summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig4
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/ata/Kconfig2
-rw-r--r--drivers/ata/ahci_imx.c638
-rw-r--r--drivers/base/Kconfig1
-rw-r--r--drivers/base/base.h13
-rw-r--r--drivers/base/core.c540
-rw-r--r--drivers/base/dd.c63
-rw-r--r--drivers/base/firmware_class.c2
-rw-r--r--drivers/base/power/domain.c41
-rw-r--r--drivers/base/power/main.c2
-rw-r--r--drivers/base/power/power.h10
-rw-r--r--drivers/base/power/runtime.c35
-rw-r--r--drivers/base/regmap/regmap-mmio.c20
-rw-r--r--drivers/block/pktcdvd.c2
-rw-r--r--drivers/char/Kconfig16
-rw-r--r--drivers/char/Makefile2
-rw-r--r--drivers/char/fsl_otp.c738
-rw-r--r--drivers/char/hw_random/Kconfig12
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/imx-rng.c440
-rw-r--r--drivers/char/imx_amp/Kconfig9
-rw-r--r--drivers/char/imx_amp/Makefile5
-rw-r--r--drivers/char/imx_amp/imx_sema4.c413
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/clk-divider.c100
-rw-r--r--drivers/clk/clk-fractional-divider.c10
-rw-r--r--drivers/clk/clk.c3
-rw-r--r--drivers/clk/imx/Makefile18
-rw-r--r--drivers/clk/imx/clk-busy.c2
-rw-r--r--drivers/clk/imx/clk-composite.c89
-rw-r--r--drivers/clk/imx/clk-divider-scu.c250
-rw-r--r--drivers/clk/imx/clk-frac-pll.c230
-rw-r--r--drivers/clk/imx/clk-gate-scu.c448
-rw-r--r--drivers/clk/imx/clk-gate2.c70
-rw-r--r--drivers/clk/imx/clk-imx6q.c543
-rw-r--r--drivers/clk/imx/clk-imx6sl.c102
-rw-r--r--drivers/clk/imx/clk-imx6sll.c380
-rw-r--r--drivers/clk/imx/clk-imx6sx.c285
-rw-r--r--drivers/clk/imx/clk-imx6ul.c113
-rw-r--r--drivers/clk/imx/clk-imx7d.c218
-rw-r--r--drivers/clk/imx/clk-imx7ulp.c322
-rw-r--r--drivers/clk/imx/clk-imx8.c68
-rw-r--r--drivers/clk/imx/clk-imx8.h130
-rw-r--r--drivers/clk/imx/clk-imx8mm.c985
-rw-r--r--drivers/clk/imx/clk-imx8mq.c909
-rw-r--r--drivers/clk/imx/clk-imx8qm.c950
-rw-r--r--drivers/clk/imx/clk-imx8qxp.c742
-rw-r--r--drivers/clk/imx/clk-intpll.c415
-rw-r--r--drivers/clk/imx/clk-mux-scu.c445
-rw-r--r--drivers/clk/imx/clk-pfd.c52
-rw-r--r--drivers/clk/imx/clk-pfdv2.c207
-rw-r--r--drivers/clk/imx/clk-pllv3.c129
-rw-r--r--drivers/clk/imx/clk-pllv4.c215
-rw-r--r--drivers/clk/imx/clk-pllv5.c199
-rw-r--r--drivers/clk/imx/clk-sccg-pll.c237
-rw-r--r--drivers/clk/imx/clk.c10
-rw-r--r--drivers/clk/imx/clk.h215
-rw-r--r--drivers/clocksource/Kconfig9
-rw-r--r--drivers/clocksource/Makefile2
-rw-r--r--drivers/clocksource/timer-imx-gpt.c3
-rw-r--r--drivers/clocksource/timer-imx-sysctr.c187
-rw-r--r--drivers/clocksource/timer-imx-tpm.c241
-rw-r--r--drivers/cpufreq/Kconfig30
-rw-r--r--drivers/cpufreq/Kconfig.arm32
-rw-r--r--drivers/cpufreq/Makefile5
-rw-r--r--drivers/cpufreq/cpufreq_governor.h8
-rw-r--r--drivers/cpufreq/cpufreq_interactive.c1365
-rw-r--r--drivers/cpufreq/imx6q-cpufreq.c231
-rw-r--r--drivers/cpufreq/imx7-cpufreq.c271
-rw-r--r--drivers/cpufreq/imx7ulp-cpufreq.c273
-rw-r--r--drivers/cpufreq/imx8-cpufreq.c294
-rw-r--r--drivers/cpufreq/imx8mq-cpufreq.c289
-rw-r--r--drivers/crypto/caam/Kconfig54
-rw-r--r--drivers/crypto/caam/Makefile5
-rw-r--r--drivers/crypto/caam/caamalg.c178
-rw-r--r--drivers/crypto/caam/caamhash.c318
-rw-r--r--drivers/crypto/caam/caampkc.c10
-rw-r--r--drivers/crypto/caam/caamrng.c57
-rw-r--r--drivers/crypto/caam/ctrl.c1157
-rw-r--r--drivers/crypto/caam/ctrl.h3
-rw-r--r--drivers/crypto/caam/desc.h32
-rw-r--r--drivers/crypto/caam/desc_constr.h36
-rw-r--r--drivers/crypto/caam/error.c14
-rw-r--r--drivers/crypto/caam/inst_rng.c380
-rw-r--r--drivers/crypto/caam/inst_rng.h17
-rw-r--r--drivers/crypto/caam/intern.h28
-rw-r--r--drivers/crypto/caam/jr.c104
-rw-r--r--drivers/crypto/caam/pdb.h18
-rw-r--r--drivers/crypto/caam/regs.h193
-rw-r--r--drivers/crypto/caam/secvio.c340
-rw-r--r--drivers/crypto/caam/secvio.h67
-rw-r--r--drivers/crypto/caam/sm.h125
-rw-r--r--drivers/crypto/caam/sm_store.c1266
-rw-r--r--drivers/crypto/caam/sm_test.c524
-rw-r--r--drivers/crypto/caam/snvsregs.h237
-rw-r--r--drivers/crypto/mxs-dcp.c152
-rw-r--r--drivers/dma/Kconfig21
-rw-r--r--drivers/dma/Makefile3
-rw-r--r--drivers/dma/fsl-edma-v3.c1083
-rw-r--r--drivers/dma/fsl-edma.c265
-rw-r--r--drivers/dma/imx-sdma.c1164
-rw-r--r--drivers/dma/mxs-dma.c126
-rw-r--r--drivers/dma/pxp/Kconfig22
-rw-r--r--drivers/dma/pxp/Makefile3
-rw-r--r--drivers/dma/pxp/pxp_device.c878
-rw-r--r--drivers/dma/pxp/pxp_dma_v2.c1865
-rw-r--r--drivers/dma/pxp/pxp_dma_v3.c8135
-rw-r--r--drivers/dma/pxp/reg_bitfields.h280
-rw-r--r--drivers/dma/pxp/regs-pxp_v2.h1152
-rw-r--r--drivers/dma/pxp/regs-pxp_v3.h26952
-rw-r--r--drivers/dma/virt-dma.c5
-rw-r--r--drivers/extcon/Kconfig9
-rw-r--r--drivers/extcon/Makefile1
-rw-r--r--drivers/extcon/extcon-ptn5150.c271
-rw-r--r--drivers/extcon/extcon-usb-gpio.c181
-rw-r--r--drivers/gpio/Kconfig15
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-74x164.c3
-rw-r--r--drivers/gpio/gpio-imx-rpmsg.c430
-rw-r--r--drivers/gpio/gpio-max732x.c5
-rw-r--r--drivers/gpio/gpio-mxc.c378
-rw-r--r--drivers/gpio/gpio-pca953x.c5
-rw-r--r--drivers/gpio/gpio-vf610.c50
-rw-r--r--drivers/gpu/Makefile2
-rw-r--r--drivers/gpu/drm/Kconfig8
-rw-r--r--drivers/gpu/drm/Makefile9
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c20
-rw-r--r--drivers/gpu/drm/arc/arcpgu_crtc.c1
-rw-r--r--drivers/gpu/drm/arm/hdlcd_crtc.c1
-rw-r--r--drivers/gpu/drm/arm/malidp_planes.c2
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.c1
-rw-r--r--drivers/gpu/drm/armada/armada_overlay.c1
-rw-r--r--drivers/gpu/drm/ast/ast_mode.c2
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c3
-rw-r--r--drivers/gpu/drm/bridge/Kconfig23
-rw-r--r--drivers/gpu/drm/bridge/Makefile3
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511.h13
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7511_drv.c137
-rw-r--r--drivers/gpu/drm/bridge/adv7511/adv7533.c38
-rw-r--r--drivers/gpu/drm/bridge/it6263.c1007
-rw-r--r--drivers/gpu/drm/bridge/nwl-dsi.c1294
-rw-r--r--drivers/gpu/drm/bridge/sec-dsim.c1842
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_mode.c2
-rw-r--r--drivers/gpu/drm/drm_atomic.c55
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c23
-rw-r--r--drivers/gpu/drm/drm_auth.c38
-rw-r--r--drivers/gpu/drm/drm_bufs.c2
-rw-r--r--drivers/gpu/drm/drm_color_mgmt.c4
-rw-r--r--drivers/gpu/drm/drm_connector.c69
-rw-r--r--drivers/gpu/drm/drm_crtc.c98
-rw-r--r--drivers/gpu/drm/drm_crtc_internal.h1
-rw-r--r--drivers/gpu/drm/drm_drv.c3
-rw-r--r--drivers/gpu/drm/drm_edid.c634
-rw-r--r--drivers/gpu/drm/drm_encoder.c7
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c6
-rw-r--r--drivers/gpu/drm/drm_fourcc.c4
-rw-r--r--drivers/gpu/drm/drm_framebuffer.c10
-rw-r--r--drivers/gpu/drm/drm_ioctl.c7
-rw-r--r--drivers/gpu/drm/drm_irq.c25
-rw-r--r--drivers/gpu/drm/drm_lease.c765
-rw-r--r--drivers/gpu/drm/drm_mode_object.c34
-rw-r--r--drivers/gpu/drm/drm_modes.c87
-rw-r--r--drivers/gpu/drm/drm_modeset_helper.c1
-rw-r--r--drivers/gpu/drm/drm_of.c31
-rw-r--r--drivers/gpu/drm/drm_plane.c186
-rw-r--r--drivers/gpu/drm/drm_prime.c12
-rw-r--r--drivers/gpu/drm/drm_probe_helper.c4
-rw-r--r--drivers/gpu/drm/drm_property.c6
-rw-r--r--drivers/gpu/drm/drm_scdc_helper.c244
-rw-r--r--drivers/gpu/drm/drm_simple_kms_helper.c3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.c2
-rw-r--r--drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c2
-rw-r--r--drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c2
-rw-r--r--drivers/gpu/drm/i915/intel_display.c7
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c2
-rw-r--r--drivers/gpu/drm/i915/intel_sprite.c6
-rw-r--r--drivers/gpu/drm/imx/Kconfig37
-rw-r--r--drivers/gpu/drm/imx/Makefile10
-rw-r--r--drivers/gpu/drm/imx/dcss/Kconfig6
-rw-r--r--drivers/gpu/drm/imx/dcss/Makefile4
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-crtc.c501
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-crtc.h12
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-kms.c135
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-kms.h21
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-plane.c701
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-plane.h28
-rw-r--r--drivers/gpu/drm/imx/dpu/Kconfig6
-rw-r--r--drivers/gpu/drm/imx/dpu/Makefile7
-rw-r--r--drivers/gpu/drm/imx/dpu/dpu-blit.c322
-rw-r--r--drivers/gpu/drm/imx/dpu/dpu-crtc.c812
-rw-r--r--drivers/gpu/drm/imx/dpu/dpu-crtc.h23
-rw-r--r--drivers/gpu/drm/imx/dpu/dpu-kms.c585
-rw-r--r--drivers/gpu/drm/imx/dpu/dpu-kms.h20
-rw-r--r--drivers/gpu/drm/imx/dpu/dpu-plane.c787
-rw-r--r--drivers/gpu/drm/imx/dpu/dpu-plane.h194
-rw-r--r--drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.c419
-rw-r--r--drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.h168
-rw-r--r--drivers/gpu/drm/imx/hdp/API_AFE_mcu2_dp.c610
-rw-r--r--drivers/gpu/drm/imx/hdp/API_AFE_mcu2_dp.h195
-rw-r--r--drivers/gpu/drm/imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.c550
-rw-r--r--drivers/gpu/drm/imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.h56
-rw-r--r--drivers/gpu/drm/imx/hdp/API_AFE_t28hpc_hdmitx.c781
-rw-r--r--drivers/gpu/drm/imx/hdp/API_AFE_t28hpc_hdmitx.h60
-rw-r--r--drivers/gpu/drm/imx/hdp/Kconfig18
-rw-r--r--drivers/gpu/drm/imx/hdp/Makefile9
-rw-r--r--drivers/gpu/drm/imx/hdp/hdmitx_firmware.h77
-rw-r--r--drivers/gpu/drm/imx/hdp/imx-arc.c103
-rw-r--r--drivers/gpu/drm/imx/hdp/imx-dp.c511
-rw-r--r--drivers/gpu/drm/imx/hdp/imx-dp.h34
-rw-r--r--drivers/gpu/drm/imx/hdp/imx-hdmi.c447
-rw-r--r--drivers/gpu/drm/imx/hdp/imx-hdmi.h33
-rw-r--r--drivers/gpu/drm/imx/hdp/imx-hdp-audio.c235
-rw-r--r--drivers/gpu/drm/imx/hdp/imx-hdp.c1455
-rw-r--r--drivers/gpu/drm/imx/hdp/imx-hdp.h251
-rw-r--r--drivers/gpu/drm/imx/hdp/mhdp_firmware.h77
-rw-r--r--drivers/gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.c108
-rw-r--r--drivers/gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.h104
-rw-r--r--drivers/gpu/drm/imx/hdp/t28hpc_hdmitx_table.c175
-rw-r--r--drivers/gpu/drm/imx/hdp/t28hpc_hdmitx_table.h129
-rw-r--r--drivers/gpu/drm/imx/imx-drm-core.c260
-rw-r--r--drivers/gpu/drm/imx/imx-drm.h10
-rw-r--r--drivers/gpu/drm/imx/imx-ldb.c936
-rw-r--r--drivers/gpu/drm/imx/ipuv3/Kconfig6
-rw-r--r--drivers/gpu/drm/imx/ipuv3/Makefile4
-rw-r--r--drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c (renamed from drivers/gpu/drm/imx/ipuv3-crtc.c)25
-rw-r--r--drivers/gpu/drm/imx/ipuv3/ipuv3-kms.c111
-rw-r--r--drivers/gpu/drm/imx/ipuv3/ipuv3-kms.h20
-rw-r--r--drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c (renamed from drivers/gpu/drm/imx/ipuv3-plane.c)4
-rw-r--r--drivers/gpu/drm/imx/ipuv3/ipuv3-plane.h (renamed from drivers/gpu/drm/imx/ipuv3-plane.h)0
-rw-r--r--drivers/gpu/drm/imx/lcdif/Kconfig8
-rw-r--r--drivers/gpu/drm/imx/lcdif/Makefile4
-rw-r--r--drivers/gpu/drm/imx/lcdif/lcdif-crtc.c399
-rw-r--r--drivers/gpu/drm/imx/lcdif/lcdif-kms.c46
-rw-r--r--drivers/gpu/drm/imx/lcdif/lcdif-kms.h21
-rw-r--r--drivers/gpu/drm/imx/lcdif/lcdif-plane.c234
-rw-r--r--drivers/gpu/drm/imx/lcdif/lcdif-plane.h37
-rw-r--r--drivers/gpu/drm/imx/nwl_dsi-imx.c1052
-rw-r--r--drivers/gpu/drm/imx/sec_mipi_dphy_ln14lpp.h227
-rw-r--r--drivers/gpu/drm/imx/sec_mipi_dsim-imx.c388
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_plane.c2
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c2
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c2
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c2
-rw-r--r--drivers/gpu/drm/mxsfb/Kconfig19
-rw-r--r--drivers/gpu/drm/mxsfb/Makefile2
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_crtc.c489
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_drv.c644
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_drv.h63
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_out.c134
-rw-r--r--drivers/gpu/drm/mxsfb/mxsfb_regs.h155
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c4
-rw-r--r--drivers/gpu/drm/omapdrm/omap_plane.c2
-rw-r--r--drivers/gpu/drm/panel/Kconfig9
-rw-r--r--drivers/gpu/drm/panel/Makefile1
-rw-r--r--drivers/gpu/drm/panel/panel-raydium-rm67191.c691
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c39
-rw-r--r--drivers/gpu/drm/radeon/r100.c2
-rw-r--r--drivers/gpu/drm/radeon/r600_cs.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c14
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_plane.c4
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_vsp.c4
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c4
-rw-r--r--drivers/gpu/drm/sti/sti_cursor.c2
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.c2
-rw-r--r--drivers/gpu/drm/sti/sti_hqvdp.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_layer.c2
-rw-r--r--drivers/gpu/drm/tegra/dc.c12
-rw-r--r--drivers/gpu/drm/tegra/drm.c2
-rw-r--r--drivers/gpu/drm/tegra/fb.c23
-rw-r--r--drivers/gpu/drm/udl/udl_connector.c2
-rw-r--r--drivers/gpu/drm/vc4/vc4_plane.c33
-rw-r--r--drivers/gpu/drm/vc4/vc4_regs.h19
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_plane.c2
-rw-r--r--drivers/gpu/drm/vivante/Makefile29
-rw-r--r--drivers/gpu/drm/vivante/vivante_drv.c131
-rw-r--r--drivers/gpu/drm/vivante/vivante_drv.h66
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c4
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c2
-rw-r--r--drivers/gpu/imx/Kconfig15
-rw-r--r--drivers/gpu/imx/Makefile8
-rw-r--r--drivers/gpu/imx/dcss/Kconfig9
-rw-r--r--drivers/gpu/imx/dcss/Makefile6
-rw-r--r--drivers/gpu/imx/dcss/dcss-blkctl.c143
-rw-r--r--drivers/gpu/imx/dcss/dcss-common.c739
-rw-r--r--drivers/gpu/imx/dcss/dcss-ctxld.c513
-rw-r--r--drivers/gpu/imx/dcss/dcss-dec400d.c320
-rw-r--r--drivers/gpu/imx/dcss/dcss-dpr.c754
-rw-r--r--drivers/gpu/imx/dcss/dcss-dtg.c496
-rw-r--r--drivers/gpu/imx/dcss/dcss-dtrc.c612
-rw-r--r--drivers/gpu/imx/dcss/dcss-hdr10-tables.h1680
-rw-r--r--drivers/gpu/imx/dcss/dcss-hdr10.c656
-rw-r--r--drivers/gpu/imx/dcss/dcss-prv.h181
-rw-r--r--drivers/gpu/imx/dcss/dcss-rdsrc.c155
-rw-r--r--drivers/gpu/imx/dcss/dcss-scaler.c994
-rw-r--r--drivers/gpu/imx/dcss/dcss-ss.c226
-rw-r--r--drivers/gpu/imx/dcss/dcss-wrscl.c189
-rw-r--r--drivers/gpu/imx/dpu-blit/Kconfig5
-rw-r--r--drivers/gpu/imx/dpu-blit/Makefile5
-rw-r--r--drivers/gpu/imx/dpu-blit/dpu-blit-registers.h283
-rw-r--r--drivers/gpu/imx/dpu-blit/dpu-blit.c442
-rw-r--r--drivers/gpu/imx/dpu-blit/dpu-blit.h46
-rw-r--r--drivers/gpu/imx/dpu/Kconfig11
-rw-r--r--drivers/gpu/imx/dpu/Makefile7
-rw-r--r--drivers/gpu/imx/dpu/dpu-common.c1809
-rw-r--r--drivers/gpu/imx/dpu/dpu-constframe.c230
-rw-r--r--drivers/gpu/imx/dpu/dpu-disengcfg.c142
-rw-r--r--drivers/gpu/imx/dpu/dpu-extdst.c503
-rw-r--r--drivers/gpu/imx/dpu/dpu-fetchdecode.c778
-rw-r--r--drivers/gpu/imx/dpu/dpu-fetcheco.c431
-rw-r--r--drivers/gpu/imx/dpu/dpu-fetchlayer.c330
-rw-r--r--drivers/gpu/imx/dpu/dpu-fetchunit.c339
-rw-r--r--drivers/gpu/imx/dpu/dpu-fetchwarp.c329
-rw-r--r--drivers/gpu/imx/dpu/dpu-framegen.c618
-rw-r--r--drivers/gpu/imx/dpu/dpu-hscaler.c392
-rw-r--r--drivers/gpu/imx/dpu/dpu-layerblend.c407
-rw-r--r--drivers/gpu/imx/dpu/dpu-prv.h428
-rw-r--r--drivers/gpu/imx/dpu/dpu-tcon.c255
-rw-r--r--drivers/gpu/imx/dpu/dpu-vscaler.c444
-rw-r--r--drivers/gpu/imx/imx8_dprc.c896
-rw-r--r--drivers/gpu/imx/imx8_prg.c443
-rw-r--r--drivers/gpu/imx/ipu-v3/Kconfig (renamed from drivers/gpu/ipu-v3/Kconfig)0
-rw-r--r--drivers/gpu/imx/ipu-v3/Makefile (renamed from drivers/gpu/ipu-v3/Makefile)0
-rw-r--r--drivers/gpu/imx/ipu-v3/ipu-common.c (renamed from drivers/gpu/ipu-v3/ipu-common.c)0
-rw-r--r--drivers/gpu/imx/ipu-v3/ipu-cpmem.c (renamed from drivers/gpu/ipu-v3/ipu-cpmem.c)0
-rw-r--r--drivers/gpu/imx/ipu-v3/ipu-csi.c (renamed from drivers/gpu/ipu-v3/ipu-csi.c)0
-rw-r--r--drivers/gpu/imx/ipu-v3/ipu-dc.c (renamed from drivers/gpu/ipu-v3/ipu-dc.c)0
-rw-r--r--drivers/gpu/imx/ipu-v3/ipu-di.c (renamed from drivers/gpu/ipu-v3/ipu-di.c)0
-rw-r--r--drivers/gpu/imx/ipu-v3/ipu-dmfc.c (renamed from drivers/gpu/ipu-v3/ipu-dmfc.c)0
-rw-r--r--drivers/gpu/imx/ipu-v3/ipu-dp.c (renamed from drivers/gpu/ipu-v3/ipu-dp.c)0
-rw-r--r--drivers/gpu/imx/ipu-v3/ipu-ic.c (renamed from drivers/gpu/ipu-v3/ipu-ic.c)0
-rw-r--r--drivers/gpu/imx/ipu-v3/ipu-image-convert.c (renamed from drivers/gpu/ipu-v3/ipu-image-convert.c)0
-rw-r--r--drivers/gpu/imx/ipu-v3/ipu-prv.h (renamed from drivers/gpu/ipu-v3/ipu-prv.h)0
-rw-r--r--drivers/gpu/imx/ipu-v3/ipu-smfc.c (renamed from drivers/gpu/ipu-v3/ipu-smfc.c)0
-rw-r--r--drivers/gpu/imx/ipu-v3/ipu-vdi.c (renamed from drivers/gpu/ipu-v3/ipu-vdi.c)0
-rw-r--r--drivers/gpu/imx/lcdif/Kconfig8
-rw-r--r--drivers/gpu/imx/lcdif/Makefile3
-rw-r--r--drivers/gpu/imx/lcdif/lcdif-common.c799
-rw-r--r--drivers/gpu/imx/lcdif/lcdif-regs.h144
-rw-r--r--drivers/hwmon/Kconfig25
-rw-r--r--drivers/hwmon/Makefile3
-rw-r--r--drivers/hwmon/mag3110.c654
-rw-r--r--drivers/hwmon/max17135-hwmon.c176
-rw-r--r--drivers/hwmon/mxc_mma8451.c599
-rw-r--r--drivers/i2c/busses/Kconfig12
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-imx-lpi2c.c740
-rw-r--r--drivers/i2c/busses/i2c-imx.c29
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca954x.c7
-rw-r--r--drivers/ide/ide-atapi.c6
-rw-r--r--drivers/ide/ide-cd.c46
-rw-r--r--drivers/ide/ide-cd.h2
-rw-r--r--drivers/ide/ide-cd_ioctl.c6
-rw-r--r--drivers/ide/ide-io.c6
-rw-r--r--drivers/ide/ide-pm.c4
-rw-r--r--drivers/iio/adc/Kconfig10
-rw-r--r--drivers/iio/adc/Makefile1
-rw-r--r--drivers/iio/adc/imx8qxp_adc.c724
-rw-r--r--drivers/iio/adc/vf610_adc.c10
-rw-r--r--drivers/input/keyboard/Kconfig26
-rw-r--r--drivers/input/keyboard/Makefile3
-rw-r--r--drivers/input/keyboard/atkbd.c3
-rw-r--r--drivers/input/keyboard/gpio_keys.c4
-rw-r--r--drivers/input/keyboard/imx_keypad.c27
-rw-r--r--drivers/input/keyboard/imx_sc_pwrkey.c173
-rw-r--r--drivers/input/keyboard/pf1550_onkey.c206
-rw-r--r--drivers/input/keyboard/rpmsg-keys.c310
-rw-r--r--drivers/input/keyboard/snvs_pwrkey.c19
-rw-r--r--drivers/input/misc/Kconfig35
-rw-r--r--drivers/input/misc/Makefile4
-rw-r--r--drivers/input/misc/fxls8471.c583
-rw-r--r--drivers/input/misc/fxls8471.h94
-rw-r--r--drivers/input/misc/fxls8471_i2c.c111
-rw-r--r--drivers/input/misc/isl29023.c1075
-rw-r--r--drivers/input/misc/mma8450.c173
-rw-r--r--drivers/input/misc/mpl3115.c356
-rw-r--r--drivers/input/misc/rpmsg_input.c528
-rw-r--r--drivers/input/touchscreen/Kconfig28
-rw-r--r--drivers/input/touchscreen/Makefile4
-rw-r--r--drivers/input/touchscreen/ads7846.c6
-rw-r--r--drivers/input/touchscreen/egalax_ts.c53
-rw-r--r--drivers/input/touchscreen/elan_ts.c472
-rw-r--r--drivers/input/touchscreen/focaltech_touch/Kconfig16
-rw-r--r--drivers/input/touchscreen/focaltech_touch/Makefile13
-rw-r--r--drivers/input/touchscreen/focaltech_touch/focaltech_common.h211
-rw-r--r--drivers/input/touchscreen/focaltech_touch/focaltech_config.h219
-rw-r--r--drivers/input/touchscreen/focaltech_touch/focaltech_core.c1439
-rw-r--r--drivers/input/touchscreen/focaltech_touch/focaltech_core.h189
-rw-r--r--drivers/input/touchscreen/focaltech_touch/focaltech_esdcheck.c473
-rw-r--r--drivers/input/touchscreen/focaltech_touch/focaltech_ex_mode.c357
-rw-r--r--drivers/input/touchscreen/focaltech_touch/focaltech_gesture.c652
-rw-r--r--drivers/input/touchscreen/focaltech_touch/focaltech_i2c.c209
-rw-r--r--drivers/input/touchscreen/focaltech_touch/focaltech_point_report_check.c151
-rw-r--r--drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c311
-rw-r--r--drivers/input/touchscreen/focaltech_touch/include/firmware/FT8716_app_sample.i0
-rw-r--r--drivers/input/touchscreen/focaltech_touch/include/firmware/lcd_cfg.i0
-rw-r--r--drivers/input/touchscreen/focaltech_touch/include/pramboot/FT8606_Pramboot_V0.7_20150507.i244
-rw-r--r--drivers/input/touchscreen/focaltech_touch/include/pramboot/FT8607_Pramboot_V0.3_20160727.i248
-rw-r--r--drivers/input/touchscreen/focaltech_touch/include/pramboot/FT8716_Pramboot_V0.5_20160723.i303
-rw-r--r--drivers/input/touchscreen/focaltech_touch/include/pramboot/FT8736_Pramboot_V0.4_20160627.i288
-rw-r--r--drivers/input/touchscreen/max11801_ts.c192
-rw-r--r--drivers/input/touchscreen/synaptics_dsx/Kconfig27
-rw-r--r--drivers/input/touchscreen/synaptics_dsx/Makefile2
-rw-r--r--drivers/input/touchscreen/synaptics_dsx/synaptics_dsx.h86
-rw-r--r--drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c3615
-rw-r--r--drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.h421
-rw-r--r--drivers/input/touchscreen/vtl/Makefile5
-rw-r--r--drivers/input/touchscreen/vtl/vtl_ts.c496
-rw-r--r--drivers/input/touchscreen/vtl/vtl_ts.h181
-rw-r--r--drivers/iommu/arm-smmu.c25
-rw-r--r--drivers/iommu/io-pgtable-arm.c3
-rw-r--r--drivers/irqchip/Kconfig12
-rw-r--r--drivers/irqchip/Makefile2
-rw-r--r--drivers/irqchip/irq-gic-v3.c21
-rw-r--r--drivers/irqchip/irq-imx-intmux.c237
-rw-r--r--drivers/irqchip/irq-imx-irqsteer.c337
-rw-r--r--drivers/md/dm-crypt.c2
-rw-r--r--drivers/md/dm-rq.c15
-rw-r--r--drivers/media/platform/Kconfig23
-rw-r--r--drivers/media/platform/Makefile6
-rw-r--r--drivers/media/platform/imx8/Kconfig55
-rw-r--r--drivers/media/platform/imx8/Makefile14
-rw-r--r--drivers/media/platform/imx8/hdmi/API_AFE_ss28fdsoi_hdmirx.c1233
-rw-r--r--drivers/media/platform/imx8/hdmi/API_AFE_ss28fdsoi_hdmirx.h142
-rw-r--r--drivers/media/platform/imx8/hdmi/Kconfig4
-rw-r--r--drivers/media/platform/imx8/hdmi/Makefile2
-rw-r--r--drivers/media/platform/imx8/hdmi/mxc-hdmi-hw.c440
-rw-r--r--drivers/media/platform/imx8/hdmi/mxc-hdmi-rx-audio.c250
-rw-r--r--drivers/media/platform/imx8/hdmi/mxc-hdmi-rx.c923
-rw-r--r--drivers/media/platform/imx8/hdmi/mxc-hdmi-rx.h139
-rw-r--r--drivers/media/platform/imx8/max9286.c2994
-rw-r--r--drivers/media/platform/imx8/mxc-isi-cap.c1669
-rw-r--r--drivers/media/platform/imx8/mxc-isi-core.c260
-rw-r--r--drivers/media/platform/imx8/mxc-isi-core.h324
-rw-r--r--drivers/media/platform/imx8/mxc-isi-hw.c599
-rw-r--r--drivers/media/platform/imx8/mxc-isi-hw.h484
-rw-r--r--drivers/media/platform/imx8/mxc-jpeg-hw.c244
-rw-r--r--drivers/media/platform/imx8/mxc-jpeg-hw.h140
-rw-r--r--drivers/media/platform/imx8/mxc-jpeg.c1358
-rw-r--r--drivers/media/platform/imx8/mxc-jpeg.h141
-rw-r--r--drivers/media/platform/imx8/mxc-media-dev.c710
-rw-r--r--drivers/media/platform/imx8/mxc-media-dev.h124
-rw-r--r--drivers/media/platform/imx8/mxc-mipi-csi2.c875
-rw-r--r--drivers/media/platform/imx8/mxc-mipi-csi2.h279
-rw-r--r--drivers/media/platform/imx8/mxc-mipi-csi2_yav.c749
-rw-r--r--drivers/media/platform/imx8/mxc-parallel-csi.c723
-rw-r--r--drivers/media/platform/imx8/mxc-parallel-csi.h170
-rw-r--r--drivers/media/platform/imx8/ov5640_mipi_v3.c1446
-rw-r--r--drivers/media/platform/imx8/ov5640_v3.c1409
-rw-r--r--drivers/media/platform/mxc/capture/Kconfig124
-rw-r--r--drivers/media/platform/mxc/capture/Makefile38
-rw-r--r--drivers/media/platform/mxc/capture/adv7180.c1380
-rw-r--r--drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c552
-rw-r--r--drivers/media/platform/mxc/capture/ipu_csi_enc.c430
-rw-r--r--drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c638
-rw-r--r--drivers/media/platform/mxc/capture/ipu_prp_enc.c597
-rw-r--r--drivers/media/platform/mxc/capture/ipu_prp_sw.h43
-rw-r--r--drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c582
-rw-r--r--drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c521
-rw-r--r--drivers/media/platform/mxc/capture/ipu_still.c268
-rw-r--r--drivers/media/platform/mxc/capture/mx6s_capture.c2007
-rw-r--r--drivers/media/platform/mxc/capture/mxc_mipi_csi.c1307
-rw-r--r--drivers/media/platform/mxc/capture/mxc_v4l2_capture.c3148
-rw-r--r--drivers/media/platform/mxc/capture/mxc_v4l2_capture.h262
-rw-r--r--drivers/media/platform/mxc/capture/mxc_vadc.c830
-rw-r--r--drivers/media/platform/mxc/capture/mxc_vadc.h239
-rw-r--r--drivers/media/platform/mxc/capture/ov5640.c1950
-rw-r--r--drivers/media/platform/mxc/capture/ov5640_mipi.c2142
-rw-r--r--drivers/media/platform/mxc/capture/ov5640_mipi_v2.c1788
-rw-r--r--drivers/media/platform/mxc/capture/ov5640_v2.c1895
-rw-r--r--drivers/media/platform/mxc/capture/ov5642.c4252
-rw-r--r--drivers/media/platform/mxc/capture/ov5647_mipi.c1721
-rw-r--r--drivers/media/platform/mxc/capture/v4l2-int-device.c165
-rw-r--r--drivers/media/platform/mxc/capture/v4l2-int-device.h309
-rw-r--r--drivers/media/platform/mxc/output/Kconfig16
-rw-r--r--drivers/media/platform/mxc/output/Makefile2
-rw-r--r--drivers/media/platform/mxc/output/mxc_pxp_v4l2.c1346
-rw-r--r--drivers/media/platform/mxc/output/mxc_pxp_v4l2.h87
-rw-r--r--drivers/media/platform/mxc/output/mxc_vout.c2331
-rw-r--r--drivers/media/radio/radio-si476x.c24
-rw-r--r--drivers/media/v4l2-core/v4l2-async.c7
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c29
-rw-r--r--drivers/media/v4l2-core/v4l2-device.c1
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c36
-rw-r--r--drivers/media/v4l2-core/videobuf-core.c7
-rw-r--r--drivers/memstick/core/ms_block.c2
-rw-r--r--drivers/memstick/core/mspro_block.c2
-rw-r--r--drivers/mfd/Kconfig37
-rw-r--r--drivers/mfd/Makefile5
-rw-r--r--drivers/mfd/bd71837.c308
-rw-r--r--drivers/mfd/max17135-core.c281
-rw-r--r--drivers/mfd/mxc-hdmi-core.c821
-rw-r--r--drivers/mfd/pf1550.c311
-rw-r--r--drivers/mfd/si476x-i2c.c23
-rw-r--r--drivers/misc/Kconfig20
-rw-r--r--drivers/misc/Makefile2
-rw-r--r--drivers/misc/eeprom/at25.c2
-rw-r--r--drivers/misc/fxas2100x.c628
-rw-r--r--drivers/misc/fxos8700.c978
-rw-r--r--drivers/misc/sram.c2
-rw-r--r--drivers/mmc/Kconfig2
-rw-r--r--drivers/mmc/Makefile1
-rw-r--r--drivers/mmc/card/Kconfig70
-rw-r--r--drivers/mmc/card/Makefile10
-rw-r--r--drivers/mmc/card/block.h1
-rw-r--r--drivers/mmc/card/queue.c557
-rw-r--r--drivers/mmc/card/queue.h83
-rw-r--r--drivers/mmc/core/Kconfig48
-rw-r--r--drivers/mmc/core/Makefile6
-rw-r--r--drivers/mmc/core/block.c (renamed from drivers/mmc/card/block.c)1225
-rw-r--r--drivers/mmc/core/block.h16
-rw-r--r--drivers/mmc/core/bus.c9
-rw-r--r--drivers/mmc/core/bus.h16
-rw-r--r--drivers/mmc/core/card.h221
-rw-r--r--drivers/mmc/core/core.c553
-rw-r--r--drivers/mmc/core/core.h47
-rw-r--r--drivers/mmc/core/debugfs.c18
-rw-r--r--drivers/mmc/core/host.c50
-rw-r--r--drivers/mmc/core/host.h49
-rw-r--r--drivers/mmc/core/mmc.c230
-rw-r--r--drivers/mmc/core/mmc_ops.c301
-rw-r--r--drivers/mmc/core/mmc_ops.h23
-rw-r--r--drivers/mmc/core/mmc_test.c (renamed from drivers/mmc/card/mmc_test.c)180
-rw-r--r--drivers/mmc/core/pwrseq.c8
-rw-r--r--drivers/mmc/core/pwrseq.h9
-rw-r--r--drivers/mmc/core/pwrseq_emmc.c2
-rw-r--r--drivers/mmc/core/pwrseq_simple.c7
-rw-r--r--drivers/mmc/core/queue.c690
-rw-r--r--drivers/mmc/core/queue.h115
-rw-r--r--drivers/mmc/core/quirks.c83
-rw-r--r--drivers/mmc/core/quirks.h148
-rw-r--r--drivers/mmc/core/sd.c30
-rw-r--r--drivers/mmc/core/sd.h5
-rw-r--r--drivers/mmc/core/sd_ops.c76
-rw-r--r--drivers/mmc/core/sd_ops.h11
-rw-r--r--drivers/mmc/core/sdio.c107
-rw-r--r--drivers/mmc/core/sdio_bus.c1
-rw-r--r--drivers/mmc/core/sdio_bus.h3
-rw-r--r--drivers/mmc/core/sdio_cis.c3
-rw-r--r--drivers/mmc/core/sdio_cis.h3
-rw-r--r--drivers/mmc/core/sdio_io.c56
-rw-r--r--drivers/mmc/core/sdio_irq.c36
-rw-r--r--drivers/mmc/core/sdio_ops.c19
-rw-r--r--drivers/mmc/core/sdio_ops.h17
-rw-r--r--drivers/mmc/core/sdio_uart.c (renamed from drivers/mmc/card/sdio_uart.c)4
-rw-r--r--drivers/mmc/core/slot-gpio.c8
-rw-r--r--drivers/mmc/core/slot-gpio.h2
-rw-r--r--drivers/mmc/host/Kconfig16
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/android-goldfish.c10
-rw-r--r--drivers/mmc/host/atmel-mci.c30
-rw-r--r--drivers/mmc/host/cqhci.c1148
-rw-r--r--drivers/mmc/host/cqhci.h240
-rw-r--r--drivers/mmc/host/davinci_mmc.c15
-rw-r--r--drivers/mmc/host/dw_mmc.c17
-rw-r--r--drivers/mmc/host/jz4740_mmc.c12
-rw-r--r--drivers/mmc/host/mmc_spi.c5
-rw-r--r--drivers/mmc/host/mmci.c30
-rw-r--r--drivers/mmc/host/mmci.h3
-rw-r--r--drivers/mmc/host/moxart-mmc.c8
-rw-r--r--drivers/mmc/host/mtk-sd.c12
-rw-r--r--drivers/mmc/host/mvsdio.c11
-rw-r--r--drivers/mmc/host/omap_hsmmc.c20
-rw-r--r--drivers/mmc/host/pxamci.c6
-rw-r--r--drivers/mmc/host/rtsx_pci_sdmmc.c5
-rw-r--r--drivers/mmc/host/rtsx_usb_sdmmc.c2
-rw-r--r--drivers/mmc/host/s3cmci.c4
-rw-r--r--drivers/mmc/host/sdhci-acpi.c12
-rw-r--r--drivers/mmc/host/sdhci-brcmstb.c3
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c435
-rw-r--r--drivers/mmc/host/sdhci-esdhc.h39
-rw-r--r--drivers/mmc/host/sdhci-of-arasan.c26
-rw-r--r--drivers/mmc/host/sdhci-of-at91.c3
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c3
-rw-r--r--drivers/mmc/host/sdhci-pci-core.c42
-rw-r--r--drivers/mmc/host/sdhci-pci.h6
-rw-r--r--drivers/mmc/host/sdhci-pltfm.c13
-rw-r--r--drivers/mmc/host/sdhci-pltfm.h2
-rw-r--r--drivers/mmc/host/sdhci-pxav3.c10
-rw-r--r--drivers/mmc/host/sdhci-s3c.c8
-rw-r--r--drivers/mmc/host/sdhci-sirf.c3
-rw-r--r--drivers/mmc/host/sdhci-spear.c3
-rw-r--r--drivers/mmc/host/sdhci-st.c6
-rw-r--r--drivers/mmc/host/sdhci.c924
-rw-r--r--drivers/mmc/host/sdhci.h73
-rw-r--r--drivers/mmc/host/sunxi-mmc.c14
-rw-r--r--drivers/mmc/host/tmio_mmc.h1
-rw-r--r--drivers/mmc/host/via-sdmmc.c1
-rw-r--r--drivers/mmc/host/wmt-sdmmc.c1
-rw-r--r--drivers/mtd/Makefile2
-rw-r--r--drivers/mtd/nand/gpmi-nand/bch-regs.h24
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-lib.c111
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c458
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.h37
-rw-r--r--drivers/mtd/spi-nor/Kconfig6
-rw-r--r--drivers/mtd/spi-nor/Makefile1
-rw-r--r--drivers/mtd/spi-nor/fsl-flexspi.c1471
-rw-r--r--drivers/mtd/spi-nor/fsl-quadspi.c329
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c104
-rw-r--r--drivers/mtd/ubi/build.c2
-rwxr-xr-xdrivers/mxc/Kconfig47
-rwxr-xr-xdrivers/mxc/Makefile15
-rw-r--r--drivers/mxc/gpu-viv/Kbuild334
-rw-r--r--drivers/mxc/gpu-viv/Kconfig11
-rw-r--r--drivers/mxc/gpu-viv/config74
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_context.c3638
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_context.h188
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware.c13717
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware.h350
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_recorder.c728
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_command_vg.c1192
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_command_vg.h353
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_vg.c2302
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_vg.h110
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.c6450
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.h2071
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_async_command.c477
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command.c3461
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command_vg.c3948
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_db.c1877
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_debug.c2865
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_event.c3070
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_heap.c892
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_interrupt_vg.c911
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_metadata.h88
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu.c2921
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu_vg.c556
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_power.c381
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_precomp.h63
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_security.c284
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_security_v1.c320
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_vg.c643
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_vg.h119
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_video_memory.c3488
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_feature_database.h68191
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal.h2827
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_base.h6003
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_driver.h1365
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_driver_vg.h300
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_drm.h199
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_dump.h123
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_eglplatform.h587
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_eglplatform_type.h324
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_engine.h2970
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_engine_vg.h1318
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_enum.h2179
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_kernel_buffer.h314
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_mem.h564
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_options.h1404
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_profiler.h1173
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_raster.h1109
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_rename.h277
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_resource.h67
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_security_interface.h184
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_statistics.h133
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_types.h1034
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_version.h69
-rw-r--r--drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_vg.h916
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_array.h119
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_dma.c594
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_dmabuf.c522
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_gfp.c1006
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_reserved_mem.c494
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_user_memory.c715
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/freescale/gc_hal_kernel_allocator_array.h130
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/freescale/gc_hal_kernel_allocator_cma.c588
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_allocator.c180
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_allocator.h558
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debug.h147
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debugfs.c964
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debugfs.h170
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c2288
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.h272
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_driver.c1297
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_drm.c813
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_iommu.c250
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.c518
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.h376
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_math.c66
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_mutex.h89
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c7838
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.h112
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_platform.h305
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_security_channel.c426
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_security_channel_emulator.c116
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_sync.c373
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_sync.h146
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/default/gc_hal_kernel_platform_default.c146
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/freescale/gc_hal_kernel_platform_imx.c1569
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/freescale/gc_hal_kernel_platform_imx.config27
-rw-r--r--drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta.c348
-rw-r--r--drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta.h373
-rw-r--r--drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_hardware.c965
-rw-r--r--drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_hardware.h139
-rw-r--r--drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_mmu.c586
-rw-r--r--drivers/mxc/gpu-viv/hal/security_v1/os/emulator/gc_hal_ta_emulator.c322
-rwxr-xr-xdrivers/mxc/hantro/Kconfig14
-rwxr-xr-xdrivers/mxc/hantro/Makefile8
-rwxr-xr-xdrivers/mxc/hantro/dwl_defs.h94
-rwxr-xr-xdrivers/mxc/hantro/hantrodec.c1918
-rwxr-xr-xdrivers/mxc/hantro_845/Kconfig14
-rwxr-xr-xdrivers/mxc/hantro_845/Makefile8
-rw-r--r--drivers/mxc/hantro_845/dwl_defs.h94
-rwxr-xr-xdrivers/mxc/hantro_845/hantrodec_845s.c2018
-rwxr-xr-xdrivers/mxc/hantro_845_h1/Kconfig14
-rwxr-xr-xdrivers/mxc/hantro_845_h1/Makefile8
-rwxr-xr-xdrivers/mxc/hantro_845_h1/hx280enc.c883
-rwxr-xr-xdrivers/mxc/hantro_845_h1/hx280enc.h79
-rw-r--r--drivers/mxc/hdmi-cec/Kconfig11
-rw-r--r--drivers/mxc/hdmi-cec/Makefile1
-rw-r--r--drivers/mxc/hdmi-cec/mxc_hdmi-cec.c665
-rw-r--r--drivers/mxc/hdmi-cec/mxc_hdmi-cec.h38
-rw-r--r--drivers/mxc/hdp-cec/Kconfig5
-rw-r--r--drivers/mxc/hdp-cec/Makefile1
-rw-r--r--drivers/mxc/hdp-cec/imx-hdp-cec.c313
-rw-r--r--drivers/mxc/hdp-cec/imx-hdp-cec.h346
-rw-r--r--drivers/mxc/hdp/API_AFE.c188
-rw-r--r--drivers/mxc/hdp/API_AFE.h111
-rw-r--r--drivers/mxc/hdp/API_Audio.c432
-rw-r--r--drivers/mxc/hdp/API_Audio.h159
-rw-r--r--drivers/mxc/hdp/API_DPTX.c936
-rw-r--r--drivers/mxc/hdp/API_DPTX.h448
-rw-r--r--drivers/mxc/hdp/API_General.c510
-rw-r--r--drivers/mxc/hdp/API_General.h248
-rw-r--r--drivers/mxc/hdp/API_HDCP.c454
-rw-r--r--drivers/mxc/hdp/API_HDCP.h263
-rw-r--r--drivers/mxc/hdp/API_HDMIRX.c236
-rw-r--r--drivers/mxc/hdp/API_HDMIRX.h135
-rw-r--r--drivers/mxc/hdp/API_HDMITX.c520
-rw-r--r--drivers/mxc/hdp/API_HDMITX.h165
-rw-r--r--drivers/mxc/hdp/API_HDMI_RX_Audio.c191
-rw-r--r--drivers/mxc/hdp/API_HDMI_RX_Audio.h80
-rw-r--r--drivers/mxc/hdp/API_Infoframe.c163
-rw-r--r--drivers/mxc/hdp/API_Infoframe.h64
-rw-r--r--drivers/mxc/hdp/Kconfig5
-rw-r--r--drivers/mxc/hdp/Makefile13
-rw-r--r--drivers/mxc/hdp/address.h109
-rw-r--r--drivers/mxc/hdp/aif_pckt2smp.h168
-rw-r--r--drivers/mxc/hdp/all.h63
-rw-r--r--drivers/mxc/hdp/apb_cfg.h185
-rw-r--r--drivers/mxc/hdp/clock_meters.h157
-rw-r--r--drivers/mxc/hdp/dptx_framer.h372
-rw-r--r--drivers/mxc/hdp/dptx_stream.h208
-rw-r--r--drivers/mxc/hdp/general_handler.h166
-rw-r--r--drivers/mxc/hdp/hdcp.h52
-rw-r--r--drivers/mxc/hdp/hdcp2.h289
-rw-r--r--drivers/mxc/hdp/hdcp_tran.h258
-rw-r--r--drivers/mxc/hdp/hdmi.h122
-rw-r--r--drivers/mxc/hdp/mailBox.h116
-rw-r--r--drivers/mxc/hdp/mhl_hdtx_top.h220
-rw-r--r--drivers/mxc/hdp/opcodes.h116
-rw-r--r--drivers/mxc/hdp/sink_aif_encoder.h367
-rw-r--r--drivers/mxc/hdp/sink_car.h168
-rw-r--r--drivers/mxc/hdp/sink_clk_meters.h241
-rw-r--r--drivers/mxc/hdp/sink_core.h117
-rw-r--r--drivers/mxc/hdp/sink_mhl_hd.h418
-rw-r--r--drivers/mxc/hdp/sink_pif.h160
-rw-r--r--drivers/mxc/hdp/sink_vif.h285
-rw-r--r--drivers/mxc/hdp/source_aif_decoder.h452
-rw-r--r--drivers/mxc/hdp/source_aif_smpl2pckt.h113
-rw-r--r--drivers/mxc/hdp/source_car.h173
-rw-r--r--drivers/mxc/hdp/source_phy.h180
-rw-r--r--drivers/mxc/hdp/source_pif.h170
-rw-r--r--drivers/mxc/hdp/source_vif.h93
-rw-r--r--drivers/mxc/hdp/util.c360
-rw-r--r--drivers/mxc/hdp/util.h394
-rw-r--r--drivers/mxc/ipu3/Kconfig21
-rw-r--r--drivers/mxc/ipu3/Makefile7
-rw-r--r--drivers/mxc/ipu3/ipu_calc_stripes_sizes.c495
-rw-r--r--drivers/mxc/ipu3/ipu_capture.c816
-rw-r--r--drivers/mxc/ipu3/ipu_common.c3494
-rw-r--r--drivers/mxc/ipu3/ipu_device.c3750
-rw-r--r--drivers/mxc/ipu3/ipu_disp.c1981
-rw-r--r--drivers/mxc/ipu3/ipu_ic.c924
-rw-r--r--drivers/mxc/ipu3/ipu_param_mem.h998
-rw-r--r--drivers/mxc/ipu3/ipu_pixel_clk.c317
-rw-r--r--drivers/mxc/ipu3/ipu_prv.h369
-rw-r--r--drivers/mxc/ipu3/ipu_regs.h702
-rw-r--r--drivers/mxc/ipu3/pre-regs.h480
-rw-r--r--drivers/mxc/ipu3/pre.c999
-rw-r--r--drivers/mxc/ipu3/prg-regs.h70
-rw-r--r--drivers/mxc/ipu3/prg.c506
-rw-r--r--drivers/mxc/ipu3/vdoa.c536
-rw-r--r--drivers/mxc/ipu3/vdoa.h62
-rw-r--r--drivers/mxc/mipi/Kconfig14
-rw-r--r--drivers/mxc/mipi/Makefile4
-rw-r--r--drivers/mxc/mipi/mxc_mipi_csi2.c540
-rw-r--r--drivers/mxc/mipi/mxc_mipi_csi2.h46
-rw-r--r--drivers/mxc/mlb/Kconfig17
-rw-r--r--drivers/mxc/mlb/Makefile5
-rwxr-xr-xdrivers/mxc/mlb/mxc_mlb.c2812
-rw-r--r--drivers/mxc/sim/Kconfig27
-rw-r--r--drivers/mxc/sim/Makefile6
-rw-r--r--drivers/mxc/sim/imx_emvsim.c1638
-rwxr-xr-xdrivers/mxc/sim/imx_sim.c1865
-rwxr-xr-xdrivers/mxc/vpu-decoder-b0/Kconfig20
-rw-r--r--drivers/mxc/vpu-decoder-b0/Makefile15
-rw-r--r--drivers/mxc/vpu-decoder-b0/insert_startcode.c546
-rw-r--r--drivers/mxc/vpu-decoder-b0/insert_startcode.h39
-rw-r--r--drivers/mxc/vpu-decoder-b0/mediasys_types.h773
-rwxr-xr-xdrivers/mxc/vpu-decoder-b0/vpu_b0.c3243
-rwxr-xr-xdrivers/mxc/vpu-decoder-b0/vpu_b0.h292
-rw-r--r--drivers/mxc/vpu-decoder-b0/vpu_rpc.c353
-rw-r--r--drivers/mxc/vpu-decoder-b0/vpu_rpc.h114
-rwxr-xr-xdrivers/mxc/vpu-encoder-b0/Kconfig20
-rw-r--r--drivers/mxc/vpu-encoder-b0/Makefile12
-rw-r--r--drivers/mxc/vpu-encoder-b0/mediasys_types.h701
-rw-r--r--drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.c2408
-rw-r--r--drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.h268
-rw-r--r--drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.c303
-rw-r--r--drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.h114
-rwxr-xr-xdrivers/mxc/vpu-malone/Kconfig20
-rwxr-xr-xdrivers/mxc/vpu-malone/Makefile197
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Control/DecKernelLibHWControl.c326
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Control/DecKernelLibHWControl.h175
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Control/DecKernelLibHWIsr.c514
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/DecKernelLib.h121
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/mvd.h157
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/mvd_reg_map.h1676
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/mvd_sif_control.h975
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/mvd_types.h132
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/DecKLib/KernelIF/DecKernelLib.c152
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/DecKLib/KernelIF/DecKernelLibCfg.h95
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/DecKLib/KernelIF/DecKernelLibPrivate.c171
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/DecKLib/KernelIF/DecKernelLibPrivate.h69
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/Incl/basetype.h343
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/Incl/mediaip_fw_defines.h249
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/Incl/mediaip_fw_types.h1991
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/Incl/pal.h337
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/Incl/status_codes.h99
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/Incl/trace_types.h261
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/PAL/Incl/pal_linux_map.h149
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/PAL/Incl/pal_types.h170
-rwxr-xr-xdrivers/mxc/vpu-malone/Malone_Firmware/PAL/pal.c780
-rwxr-xr-xdrivers/mxc/vpu-malone/VPU_debug.h95
-rwxr-xr-xdrivers/mxc/vpu-malone/VPU_regdef.h60
-rwxr-xr-xdrivers/mxc/vpu-malone/mxc_vpu-malone.c1344
-rw-r--r--drivers/mxc/vpu/Kconfig31
-rw-r--r--drivers/mxc/vpu/Makefile9
-rw-r--r--drivers/mxc/vpu/mxc_vpu.c1348
-rw-r--r--drivers/net/Kconfig4
-rw-r--r--drivers/net/Makefile2
-rw-r--r--drivers/net/can/Kconfig2
-rw-r--r--drivers/net/can/flexcan.c1019
-rw-r--r--drivers/net/ethernet/freescale/Kconfig6
-rw-r--r--drivers/net/ethernet/freescale/Makefile2
-rw-r--r--drivers/net/ethernet/freescale/fec.h65
-rw-r--r--drivers/net/ethernet/freescale/fec_fixup.c277
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c482
-rw-r--r--drivers/net/ivshmem-net.c984
-rw-r--r--drivers/net/phy/Kconfig5
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/at803x.c137
-rw-r--r--drivers/net/phy/micrel.c18
-rw-r--r--drivers/net/phy/phy_device.c54
-rw-r--r--drivers/net/phy/tja110x.c2547
-rw-r--r--drivers/net/phy/tja110x.h274
-rw-r--r--drivers/net/wireless/Kconfig2
-rw-r--r--drivers/net/wireless/Makefile2
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c60
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h9
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c4
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c3
-rw-r--r--drivers/net/wireless/bcmdhd/Kconfig60
-rw-r--r--drivers/net/wireless/bcmdhd/Makefile229
-rw-r--r--drivers/net/wireless/bcmdhd/aiutils.c1012
-rw-r--r--drivers/net/wireless/bcmdhd/bcmevent.c242
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh.c705
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh_linux.c473
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c1491
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c405
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdspi_linux.c249
-rw-r--r--drivers/net/wireless/bcmdhd/bcmspibrcm.c1814
-rw-r--r--drivers/net/wireless/bcmdhd/bcmutils.c3084
-rw-r--r--drivers/net/wireless/bcmdhd/bcmwifi_channels.c1206
-rw-r--r--drivers/net/wireless/bcmdhd/bcmwifi_channels.h495
-rw-r--r--drivers/net/wireless/bcmdhd/bcmwifi_rates.h458
-rw-r--r--drivers/net/wireless/bcmdhd/circularbuf.c326
-rw-r--r--drivers/net/wireless/bcmdhd/dhd.h931
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_bta.c337
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_bta.h39
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_bus.h158
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_cdc.c789
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_cfg80211.c301
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_cfg80211.h59
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_common.c2640
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_custom_gpio.c300
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_dbg.h123
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_ip.c965
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_ip.h71
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux.c8008
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux.h77
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux_platdev.c821
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux_sched.c48
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux_wq.c316
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux_wq.h64
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_msgbuf.c1755
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_pcie.c2566
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_pcie.h169
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_pcie_linux.c503
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_pno.c1899
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_pno.h253
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_proto.h115
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_sdio.c8343
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_wlfc.c4049
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_wlfc.h513
-rw-r--r--drivers/net/wireless/bcmdhd/dngl_stats.h43
-rw-r--r--drivers/net/wireless/bcmdhd/dngl_wlhdr.h40
-rw-r--r--drivers/net/wireless/bcmdhd/hndpmu.c282
-rw-r--r--drivers/net/wireless/bcmdhd/include/Makefile53
-rw-r--r--drivers/net/wireless/bcmdhd/include/aidmp.h387
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcm_cfg.h29
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h361
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmcdc.h132
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmdefs.h348
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmdevs.h688
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmendian.h329
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h261
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmnvram.h272
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmpcie.h129
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmpcispi.h181
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmperf.h36
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdbus.h143
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdh.h251
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h117
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdpcm.h281
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdspi.h135
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdstd.h282
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmspi.h40
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmspibrcm.h162
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsrom_fmt.h633
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsrom_tbl.h1014
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmutils.h1204
-rw-r--r--drivers/net/wireless/bcmdhd/include/brcm_nl80211.h56
-rw-r--r--drivers/net/wireless/bcmdhd/include/circularbuf.h115
-rw-r--r--drivers/net/wireless/bcmdhd/include/dbus.h582
-rw-r--r--drivers/net/wireless/bcmdhd/include/devctrl_if/wlioctl_defs.h1987
-rw-r--r--drivers/net/wireless/bcmdhd/include/dhdioctl.h135
-rw-r--r--drivers/net/wireless/bcmdhd/include/epivers.h48
-rw-r--r--drivers/net/wireless/bcmdhd/include/hndpmu.h36
-rw-r--r--drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h88
-rw-r--r--drivers/net/wireless/bcmdhd/include/hndrte_cons.h78
-rw-r--r--drivers/net/wireless/bcmdhd/include/hndsoc.h282
-rw-r--r--drivers/net/wireless/bcmdhd/include/linux_osl.h763
-rw-r--r--drivers/net/wireless/bcmdhd/include/linuxver.h754
-rw-r--r--drivers/net/wireless/bcmdhd/include/miniopt.h77
-rw-r--r--drivers/net/wireless/bcmdhd/include/msgtrace.h77
-rw-r--r--drivers/net/wireless/bcmdhd/include/osl.h142
-rw-r--r--drivers/net/wireless/bcmdhd/include/packed_section_end.h59
-rw-r--r--drivers/net/wireless/bcmdhd/include/packed_section_start.h63
-rw-r--r--drivers/net/wireless/bcmdhd/include/pcicfg.h101
-rw-r--r--drivers/net/wireless/bcmdhd/include/pcie_core.h581
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/802.11.h3803
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h45
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/802.11e.h132
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/802.1d.h50
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/802.3.h52
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bcmeth.h112
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bcmevent.h517
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bcmip.h231
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bcmipv6.h159
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bcmtcp.h90
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h441
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/eapol.h211
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/ethernet.h220
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/p2p.h608
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/sdspi.h75
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/vlan.h95
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/wpa.h175
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/wps.h379
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbchipc.h3304
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbconfig.h282
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbhnddma.h416
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbpcmcia.h113
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbsdio.h186
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h295
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbsocram.h200
-rw-r--r--drivers/net/wireless/bcmdhd/include/sdio.h619
-rw-r--r--drivers/net/wireless/bcmdhd/include/sdioh.h445
-rw-r--r--drivers/net/wireless/bcmdhd/include/sdiovar.h58
-rw-r--r--drivers/net/wireless/bcmdhd/include/siutils.h440
-rw-r--r--drivers/net/wireless/bcmdhd/include/spid.h165
-rw-r--r--drivers/net/wireless/bcmdhd/include/trxhdr.h92
-rw-r--r--drivers/net/wireless/bcmdhd/include/typedefs.h344
-rw-r--r--drivers/net/wireless/bcmdhd/include/wlfc_proto.h304
-rw-r--r--drivers/net/wireless/bcmdhd/include/wlioctl.h5008
-rw-r--r--drivers/net/wireless/bcmdhd/linux_osl.c1529
-rw-r--r--drivers/net/wireless/bcmdhd/sbutils.c1063
-rw-r--r--drivers/net/wireless/bcmdhd/siutils.c2877
-rw-r--r--drivers/net/wireless/bcmdhd/siutils_priv.h272
-rw-r--r--drivers/net/wireless/bcmdhd/uamp_api.h176
-rw-r--r--drivers/net/wireless/bcmdhd/wl_android.c2331
-rw-r--r--drivers/net/wireless/bcmdhd/wl_android.h77
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.c14425
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.h1264
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg_btcoex.c545
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.c2539
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.h414
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgvendor.c201
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgvendor.h56
-rw-r--r--drivers/net/wireless/bcmdhd/wl_dbg.h67
-rw-r--r--drivers/net/wireless/bcmdhd/wl_iw.c3689
-rw-r--r--drivers/net/wireless/bcmdhd/wl_iw.h159
-rw-r--r--drivers/net/wireless/bcmdhd/wl_linux_mon.c403
-rw-r--r--drivers/net/wireless/bcmdhd/wldev_common.c479
-rw-r--r--drivers/net/wireless/bcmdhd/wldev_common.h121
-rw-r--r--drivers/net/wireless/bcmdhd_1363/Kconfig53
-rw-r--r--drivers/net/wireless/bcmdhd_1363/Makefile315
-rw-r--r--drivers/net/wireless/bcmdhd_1363/aiutils.c1284
-rw-r--r--drivers/net/wireless/bcmdhd_1363/bcm_app_utils.c1012
-rw-r--r--drivers/net/wireless/bcmdhd_1363/bcmevent.c356
-rw-r--r--drivers/net/wireless/bcmdhd_1363/bcmsdh.c708
-rw-r--r--drivers/net/wireless/bcmdhd_1363/bcmsdh_linux.c473
-rw-r--r--drivers/net/wireless/bcmdhd_1363/bcmsdh_sdmmc.c1509
-rw-r--r--drivers/net/wireless/bcmdhd_1363/bcmsdh_sdmmc_linux.c409
-rw-r--r--drivers/net/wireless/bcmdhd_1363/bcmsdspi_linux.c252
-rw-r--r--drivers/net/wireless/bcmdhd_1363/bcmspibrcm.c1823
-rw-r--r--drivers/net/wireless/bcmdhd_1363/bcmutils.c3581
-rw-r--r--drivers/net/wireless/bcmdhd_1363/bcmwifi_channels.c1253
-rw-r--r--drivers/net/wireless/bcmdhd_1363/bcmwifi_channels.h631
-rw-r--r--drivers/net/wireless/bcmdhd_1363/bcmwifi_rates.h793
-rw-r--r--drivers/net/wireless/bcmdhd_1363/bcmxtlv.c457
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd.h1786
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_bandsteer.c595
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_bandsteer.h75
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_bta.c340
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_bta.h42
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_bus.h220
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_buzzz.h37
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_cdc.c814
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_cfg80211.c266
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_cfg80211.h54
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_cfg_vendor.c174
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_common.c4154
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_custom_gpio.c309
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_dbg.h193
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_flowring.c964
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_flowring.h235
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_ip.c1274
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_ip.h85
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_linux.c14471
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_linux.h130
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_linux_platdev.c901
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_linux_sched.c51
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_linux_wq.c320
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_linux_wq.h70
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_msgbuf.c6427
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_pcie.c6139
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_pcie.h315
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_pcie_linux.c1583
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_pno.c3892
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_pno.h498
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_proto.h169
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_rtt.c729
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_rtt.h234
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_sdio.c8445
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_wlfc.c4510
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dhd_wlfc.h554
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dngl_stats.h324
-rw-r--r--drivers/net/wireless/bcmdhd_1363/dngl_wlhdr.h43
-rw-r--r--drivers/net/wireless/bcmdhd_1363/hnd_pktpool.c1131
-rw-r--r--drivers/net/wireless/bcmdhd_1363/hnd_pktq.c886
-rw-r--r--drivers/net/wireless/bcmdhd_1363/hndpmu.c292
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/aidmp.h402
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcm_cfg.h32
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcm_mpool_pub.h364
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcm_ring.h616
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmcdc.h135
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmdefs.h382
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmdevs.h806
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmendian.h332
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmmsgbuf.h863
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmnvram.h310
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmpcie.h318
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmpcispi.h184
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmperf.h39
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmsdbus.h146
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmsdh.h255
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmsdh_sdmmc.h119
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmsdpcm.h281
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmsdspi.h138
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmsdstd.h285
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmspi.h43
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmspibrcm.h165
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmsrom_fmt.h965
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmsrom_tbl.h1400
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/bcmutils.h1304
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/brcm_nl80211.h68
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/dbus.h591
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/devctrl_if/wlioctl_defs.h2211
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/dhdioctl.h142
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/epivers.h51
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/event_log.h349
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/hnd_armtrap.h92
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/hnd_cons.h80
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/hnd_pktpool.h225
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/hnd_pktq.h214
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/hndpmu.h45
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/hndsoc.h315
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/linux_osl.h1088
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/linuxver.h774
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/miniopt.h83
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/msgtrace.h81
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/osl.h178
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/osl_decl.h37
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/osl_ext.h697
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/packed_section_end.h63
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/packed_section_start.h67
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/pcicfg.h260
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/pcie_core.h652
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/802.11.h4936
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/802.11_bta.h48
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/802.11e.h134
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/802.1d.h53
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/802.3.h55
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/bcmdhcp.h92
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/bcmeth.h116
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/bcmevent.h842
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/bcmip.h249
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/bcmipv6.h163
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/bcmtcp.h93
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/bcmudp.h61
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/bt_amp_hci.h444
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/eapol.h215
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/ethernet.h227
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/event_log_set.h46
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/event_log_tag.h206
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/p2p.h713
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/sdspi.h78
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/vlan.h98
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/wpa.h212
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/proto/wps.h389
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/rte_ioctl.h85
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/sbchipc.h3761
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/sbconfig.h285
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/sbhnddma.h420
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/sbpcmcia.h116
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/sbsdio.h189
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/sbsdpcmdev.h298
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/sbsocram.h203
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/sbsysmem.h200
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/sdio.h625
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/sdioh.h448
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/sdiovar.h61
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/siutils.h606
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/spid.h168
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/trxhdr.h95
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/typedefs.h339
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/wlfc_proto.h350
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/wlioctl.h8087
-rw-r--r--drivers/net/wireless/bcmdhd_1363/include/wlioctl_utils.h53
-rw-r--r--drivers/net/wireless/bcmdhd_1363/linux_osl.c2673
-rw-r--r--drivers/net/wireless/bcmdhd_1363/pcie_core.c115
-rw-r--r--drivers/net/wireless/bcmdhd_1363/sbutils.c1108
-rw-r--r--drivers/net/wireless/bcmdhd_1363/siutils.c3270
-rw-r--r--drivers/net/wireless/bcmdhd_1363/siutils_priv.h294
-rw-r--r--drivers/net/wireless/bcmdhd_1363/uamp_api.h181
-rw-r--r--drivers/net/wireless/bcmdhd_1363/wl_android.c3861
-rw-r--r--drivers/net/wireless/bcmdhd_1363/wl_android.h80
-rw-r--r--drivers/net/wireless/bcmdhd_1363/wl_cfg80211.c17874
-rw-r--r--drivers/net/wireless/bcmdhd_1363/wl_cfg80211.h1572
-rw-r--r--drivers/net/wireless/bcmdhd_1363/wl_cfg_btcoex.c564
-rw-r--r--drivers/net/wireless/bcmdhd_1363/wl_cfgp2p.c2614
-rw-r--r--drivers/net/wireless/bcmdhd_1363/wl_cfgp2p.h446
-rw-r--r--drivers/net/wireless/bcmdhd_1363/wl_cfgvendor.c1835
-rw-r--r--drivers/net/wireless/bcmdhd_1363/wl_cfgvendor.h286
-rw-r--r--drivers/net/wireless/bcmdhd_1363/wl_dbg.h211
-rw-r--r--drivers/net/wireless/bcmdhd_1363/wl_linux_mon.c406
-rw-r--r--drivers/net/wireless/bcmdhd_1363/wl_roam.c28
-rw-r--r--drivers/net/wireless/bcmdhd_1363/wldev_common.c456
-rw-r--r--drivers/net/wireless/bcmdhd_1363/wldev_common.h124
-rw-r--r--drivers/nvme/host/pci.c4
-rw-r--r--drivers/nvmem/Kconfig14
-rw-r--r--drivers/nvmem/Makefile2
-rw-r--r--drivers/nvmem/imx-ocotp.c30
-rw-r--r--drivers/nvmem/imx-scu-ocotp.c180
-rw-r--r--drivers/of/base.c30
-rw-r--r--drivers/of/of_reserved_mem.c43
-rw-r--r--drivers/pci/host/Kconfig25
-rw-r--r--drivers/pci/host/Makefile2
-rw-r--r--drivers/pci/host/pci-host-common.c14
-rw-r--r--drivers/pci/host/pci-host-generic.c1
-rw-r--r--drivers/pci/host/pci-imx6-ep-driver.c209
-rw-r--r--drivers/pci/host/pci-imx6.c2518
-rw-r--r--drivers/pci/host/pcie-designware.c83
-rw-r--r--drivers/pci/host/pcie-designware.h10
-rw-r--r--drivers/pci/pci.c6
-rw-r--r--drivers/pci/pcie/Kconfig8
-rw-r--r--drivers/pci/pcie/aspm.c311
-rw-r--r--drivers/perf/Kconfig3
-rw-r--r--drivers/perf/Makefile1
-rw-r--r--drivers/perf/ddr-perf.c531
-rw-r--r--drivers/phy/Kconfig25
-rw-r--r--drivers/phy/Makefile4
-rw-r--r--drivers/phy/phy-fsl-imx8mq-usb.c132
-rw-r--r--drivers/phy/phy-mixel-lvds-combo.c285
-rw-r--r--drivers/phy/phy-mixel-lvds.c309
-rw-r--r--drivers/phy/phy-mixel-mipi-dsi.c538
-rw-r--r--drivers/pinctrl/devicetree.c44
-rw-r--r--drivers/pinctrl/freescale/Kconfig65
-rw-r--r--drivers/pinctrl/freescale/Makefile8
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx.c383
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx.h110
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx6sll.c388
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx6ul.c52
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx7d.c17
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx7ulp.c449
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx8mm.c384
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx8mq.c385
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx8qm.c358
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx8qxp.c263
-rw-r--r--drivers/pinctrl/freescale/pinctrl-memmap.c234
-rw-r--r--drivers/pinctrl/freescale/pinctrl-scu.c109
-rw-r--r--drivers/pinctrl/freescale/pinctrl-vf610.c4
-rw-r--r--drivers/power/supply/Kconfig14
-rw-r--r--drivers/power/supply/Makefile2
-rw-r--r--drivers/power/supply/pf1550_charger.c656
-rw-r--r--drivers/power/supply/sabresd_battery.c1014
-rw-r--r--drivers/pwm/Kconfig11
-rw-r--r--drivers/pwm/Makefile1
-rw-r--r--drivers/pwm/pwm-fsl-ftm.c49
-rw-r--r--drivers/pwm/pwm-imx.c46
-rw-r--r--drivers/pwm/pwm-tpm.c259
-rw-r--r--drivers/regulator/Kconfig25
-rw-r--r--drivers/regulator/Makefile4
-rw-r--r--drivers/regulator/anatop-regulator.c103
-rw-r--r--drivers/regulator/bd71837-regulator.c1053
-rw-r--r--drivers/regulator/core.c3
-rw-r--r--drivers/regulator/fixed.c24
-rw-r--r--drivers/regulator/max17135-regulator.c858
-rw-r--r--drivers/regulator/pf1550-regulator-rpmsg.c512
-rw-r--r--drivers/regulator/pf1550.c390
-rw-r--r--drivers/regulator/pfuze100-regulator.c110
-rw-r--r--drivers/regulator/userspace-consumer.c53
-rw-r--r--drivers/regulator/virtual.c38
-rw-r--r--drivers/reset/Kconfig9
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/gpio-reset.c196
-rw-r--r--drivers/rpmsg/Kconfig23
-rw-r--r--drivers/rpmsg/Makefile4
-rw-r--r--drivers/rpmsg/imx_rpmsg.c613
-rw-r--r--drivers/rpmsg/imx_rpmsg_pingpong.c108
-rw-r--r--drivers/rpmsg/imx_rpmsg_tty.c253
-rw-r--r--drivers/rpmsg/rpmsg_char.c584
-rw-r--r--drivers/rpmsg/rpmsg_core.c3
-rw-r--r--drivers/rpmsg/rpmsg_internal.h15
-rw-r--r--drivers/rpmsg/virtio_rpmsg_bus.c39
-rw-r--r--drivers/rtc/Kconfig14
-rw-r--r--drivers/rtc/Makefile2
-rw-r--r--drivers/rtc/rtc-imx-rpmsg.c384
-rw-r--r--drivers/rtc/rtc-imx-sc.c219
-rw-r--r--drivers/rtc/rtc-snvs.c14
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c8
-rw-r--r--drivers/scsi/device_handler/scsi_dh_emc.c2
-rw-r--r--drivers/scsi/device_handler/scsi_dh_hp_sw.c2
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c2
-rw-r--r--drivers/scsi/osd/osd_initiator.c2
-rw-r--r--drivers/scsi/osst.c2
-rw-r--r--drivers/scsi/scsi_error.c22
-rw-r--r--drivers/scsi/scsi_lib.c75
-rw-r--r--drivers/scsi/sd.c9
-rw-r--r--drivers/scsi/st.c2
-rw-r--r--drivers/scsi/ufs/ufshcd.c6
-rw-r--r--drivers/soc/Kconfig1
-rw-r--r--drivers/soc/Makefile1
-rw-r--r--drivers/soc/imx/Kconfig50
-rw-r--r--drivers/soc/imx/Makefile6
-rw-r--r--drivers/soc/imx/busfreq-imx8mq.c661
-rw-r--r--drivers/soc/imx/gpc-psci.c425
-rw-r--r--drivers/soc/imx/mu/Makefile1
-rw-r--r--drivers/soc/imx/mu/mx8_mu.c156
-rw-r--r--drivers/soc/imx/pm-domain-imx8.h59
-rw-r--r--drivers/soc/imx/pm-domains.c638
-rw-r--r--drivers/soc/imx/sc/Makefile8
-rw-r--r--drivers/soc/imx/sc/main/ipc.c422
-rw-r--r--drivers/soc/imx/sc/main/rpc.h124
-rw-r--r--drivers/soc/imx/sc/svc/irq/rpc.h53
-rw-r--r--drivers/soc/imx/sc/svc/irq/rpc_clnt.c74
-rw-r--r--drivers/soc/imx/sc/svc/misc/rpc.h70
-rw-r--r--drivers/soc/imx/sc/svc/misc/rpc_clnt.c405
-rw-r--r--drivers/soc/imx/sc/svc/pad/rpc.h67
-rw-r--r--drivers/soc/imx/sc/svc/pad/rpc_clnt.c453
-rw-r--r--drivers/soc/imx/sc/svc/pm/rpc.h70
-rw-r--r--drivers/soc/imx/sc/svc/pm/rpc_clnt.c415
-rw-r--r--drivers/soc/imx/sc/svc/rm/rpc.h82
-rw-r--r--drivers/soc/imx/sc/svc/rm/rpc_clnt.c637
-rw-r--r--drivers/soc/imx/sc/svc/timer/rpc.h64
-rw-r--r--drivers/soc/imx/sc/svc/timer/rpc_clnt.c322
-rw-r--r--drivers/soc/imx/soc-imx8.c457
-rw-r--r--drivers/spi/Kconfig9
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/spi-fsl-lpspi.c624
-rw-r--r--drivers/spi/spi-imx.c145
-rw-r--r--drivers/spi/spi.c7
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile3
-rw-r--r--drivers/staging/android/Kconfig4
-rw-r--r--drivers/staging/android/ion/Kconfig42
-rw-r--r--drivers/staging/android/ion/Makefile5
-rw-r--r--drivers/staging/android/ion/devicetree.txt1
-rw-r--r--drivers/staging/android/ion/ion.c46
-rw-r--r--drivers/staging/android/ion/ion_dummy_driver.c10
-rw-r--r--drivers/staging/android/ion/ion_heap.c10
-rw-r--r--drivers/staging/android/ion/ion_of.c1
-rw-r--r--drivers/staging/android/ion/ion_priv.h11
-rw-r--r--drivers/staging/android/ion/ion_unmapped_heap.c236
-rw-r--r--drivers/staging/android/ion/mxc/Makefile2
-rw-r--r--drivers/staging/android/ion/mxc/mxc_ion.c532
-rw-r--r--drivers/staging/android/uapi/ion.h28
-rw-r--r--drivers/staging/android/uapi/secure_ion.h25
-rw-r--r--drivers/staging/typec/Kconfig22
-rw-r--r--drivers/staging/typec/Makefile2
-rw-r--r--drivers/staging/typec/TODO15
-rw-r--r--drivers/staging/typec/pd.h281
-rw-r--r--drivers/staging/typec/pd_bdo.h31
-rw-r--r--drivers/staging/typec/pd_vdo.h249
-rw-r--r--drivers/staging/typec/tcpci.c935
-rw-r--r--drivers/staging/typec/tcpci.h142
-rw-r--r--drivers/staging/typec/tcpm.c3637
-rw-r--r--drivers/staging/typec/tcpm.h162
-rw-r--r--drivers/tee/Kconfig19
-rw-r--r--drivers/tee/Makefile5
-rw-r--r--drivers/tee/optee/Kconfig7
-rw-r--r--drivers/tee/optee/Makefile5
-rw-r--r--drivers/tee/optee/call.c444
-rw-r--r--drivers/tee/optee/core.c619
-rw-r--r--drivers/tee/optee/optee_msg.h418
-rw-r--r--drivers/tee/optee/optee_private.h172
-rw-r--r--drivers/tee/optee/optee_smc.h450
-rw-r--r--drivers/tee/optee/rpc.c393
-rw-r--r--drivers/tee/optee/supp.c382
-rw-r--r--drivers/tee/tee_core.c1031
-rw-r--r--drivers/tee/tee_private.h129
-rw-r--r--drivers/tee/tee_shm.c476
-rw-r--r--drivers/tee/tee_shm_pool.c156
-rw-r--r--drivers/thermal/Kconfig36
-rw-r--r--drivers/thermal/Makefile4
-rw-r--r--drivers/thermal/device_cooling.c151
-rw-r--r--drivers/thermal/imx8mm_thermal.c237
-rw-r--r--drivers/thermal/imx_sc_thermal.c242
-rw-r--r--drivers/thermal/imx_thermal.c560
-rw-r--r--drivers/thermal/qoriq_thermal.c78
-rw-r--r--drivers/tty/serial/Kconfig2
-rw-r--r--drivers/tty/serial/fsl_lpuart.c1331
-rw-r--r--drivers/tty/serial/imx.c683
-rw-r--r--drivers/usb/Kconfig4
-rw-r--r--drivers/usb/Makefile3
-rw-r--r--drivers/usb/cdns3/Kconfig26
-rw-r--r--drivers/usb/cdns3/Makefile5
-rw-r--r--drivers/usb/cdns3/cdns3-nxp-reg-def.h172
-rw-r--r--drivers/usb/cdns3/core.c1014
-rw-r--r--drivers/usb/cdns3/core.h131
-rw-r--r--drivers/usb/cdns3/dev-regs-macro.h894
-rw-r--r--drivers/usb/cdns3/dev-regs-map.h126
-rw-r--r--drivers/usb/cdns3/gadget-export.h36
-rw-r--r--drivers/usb/cdns3/gadget.c2526
-rw-r--r--drivers/usb/cdns3/gadget.h225
-rw-r--r--drivers/usb/cdns3/host-export.h43
-rw-r--r--drivers/usb/cdns3/host.c259
-rw-r--r--drivers/usb/cdns3/io.h35
-rw-r--r--drivers/usb/chipidea/ci.h44
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c407
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.h45
-rw-r--r--drivers/usb/chipidea/ci_hdrc_msm.c4
-rw-r--r--drivers/usb/chipidea/core.c328
-rw-r--r--drivers/usb/chipidea/host.c335
-rw-r--r--drivers/usb/chipidea/host.h8
-rw-r--r--drivers/usb/chipidea/otg.c101
-rw-r--r--drivers/usb/chipidea/otg.h13
-rw-r--r--drivers/usb/chipidea/otg_fsm.c220
-rw-r--r--drivers/usb/chipidea/otg_fsm.h28
-rw-r--r--drivers/usb/chipidea/udc.c294
-rw-r--r--drivers/usb/chipidea/udc.h13
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c738
-rw-r--r--drivers/usb/common/usb-otg-fsm.c54
-rw-r--r--drivers/usb/core/buffer.c12
-rw-r--r--drivers/usb/core/hcd.c216
-rw-r--r--drivers/usb/core/hub.c40
-rw-r--r--drivers/usb/core/otg_whitelist.h88
-rw-r--r--drivers/usb/core/usb.c18
-rw-r--r--drivers/usb/dwc3/Kconfig1
-rw-r--r--drivers/usb/dwc3/Makefile4
-rw-r--r--drivers/usb/dwc3/core.c183
-rw-r--r--drivers/usb/dwc3/core.h36
-rw-r--r--drivers/usb/dwc3/debugfs.c14
-rw-r--r--drivers/usb/dwc3/drd.c85
-rw-r--r--drivers/usb/dwc3/dwc3-of-simple.c1
-rw-r--r--drivers/usb/dwc3/gadget.c180
-rw-r--r--drivers/usb/gadget/Kconfig6
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c63
-rw-r--r--drivers/usb/gadget/function/fsl_updater.c647
-rw-r--r--drivers/usb/gadget/function/fsl_updater.h152
-rw-r--r--drivers/usb/gadget/udc/core.c1
-rw-r--r--drivers/usb/host/ehci-hcd.c6
-rw-r--r--drivers/usb/host/ehci-hub.c141
-rw-r--r--drivers/usb/host/ehci-mem.c12
-rw-r--r--drivers/usb/host/ehci-q.c14
-rw-r--r--drivers/usb/host/xhci-dbg.c6
-rw-r--r--drivers/usb/host/xhci-hub.c162
-rw-r--r--drivers/usb/host/xhci-mem.c32
-rw-r--r--drivers/usb/host/xhci-plat.c93
-rw-r--r--drivers/usb/host/xhci-ring.c138
-rw-r--r--drivers/usb/host/xhci.c75
-rw-r--r--drivers/usb/host/xhci.h18
-rw-r--r--drivers/usb/misc/ehset.c25
-rw-r--r--drivers/usb/phy/Kconfig2
-rw-r--r--drivers/usb/phy/phy-generic.c10
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c289
-rw-r--r--drivers/usb/typec/Kconfig7
-rw-r--r--drivers/usb/typec/Makefile1
-rw-r--r--drivers/usb/typec/typec.c1310
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/backlight/gpio_backlight.c16
-rw-r--r--drivers/video/backlight/pwm_bl.c19
-rw-r--r--drivers/video/console/fbcon.c2
-rw-r--r--drivers/video/fbdev/Kconfig26
-rw-r--r--drivers/video/fbdev/Makefile1
-rw-r--r--drivers/video/fbdev/mxc/Kconfig136
-rw-r--r--drivers/video/fbdev/mxc/Makefile18
-rw-r--r--drivers/video/fbdev/mxc/adv7535.c376
-rw-r--r--drivers/video/fbdev/mxc/crtc.h57
-rw-r--r--drivers/video/fbdev/mxc/epdc_regs.h442
-rw-r--r--drivers/video/fbdev/mxc/epdc_v2_regs.h533
-rw-r--r--drivers/video/fbdev/mxc/hannstar_cabc.c82
-rw-r--r--drivers/video/fbdev/mxc/imx_dcss.c3585
-rw-r--r--drivers/video/fbdev/mxc/imx_dcss_table.h9761
-rw-r--r--drivers/video/fbdev/mxc/ldb.c910
-rw-r--r--drivers/video/fbdev/mxc/mipi_dsi.c1039
-rw-r--r--drivers/video/fbdev/mxc/mipi_dsi.h141
-rw-r--r--drivers/video/fbdev/mxc/mipi_dsi_northwest.c1543
-rw-r--r--drivers/video/fbdev/mxc/mipi_dsi_samsung.c952
-rw-r--r--drivers/video/fbdev/mxc/mxc_dcic.c592
-rw-r--r--drivers/video/fbdev/mxc/mxc_dispdrv.c148
-rw-r--r--drivers/video/fbdev/mxc/mxc_dispdrv.h52
-rw-r--r--drivers/video/fbdev/mxc/mxc_edid.c771
-rw-r--r--drivers/video/fbdev/mxc/mxc_epdc_fb.c5601
-rw-r--r--drivers/video/fbdev/mxc/mxc_epdc_v2_fb.c6833
-rw-r--r--drivers/video/fbdev/mxc/mxc_hdmi.c2980
-rw-r--r--drivers/video/fbdev/mxc/mxc_ipuv3_fb.c3673
-rw-r--r--drivers/video/fbdev/mxc/mxc_lcdif.c237
-rw-r--r--drivers/video/fbdev/mxc/mxcfb_hx8363_wvga.c220
-rw-r--r--drivers/video/fbdev/mxc/mxcfb_hx8369_wvga.c451
-rw-r--r--drivers/video/fbdev/mxc/mxcfb_otm8018b_wvga.c266
-rw-r--r--drivers/video/fbdev/mxc/mxsfb_sii902x.c558
-rw-r--r--drivers/video/fbdev/mxsfb.c1847
-rw-r--r--drivers/video/hdmi.c142
-rw-r--r--drivers/watchdog/Kconfig26
-rw-r--r--drivers/watchdog/Makefile2
-rw-r--r--drivers/watchdog/imx2_wdt.c49
-rw-r--r--drivers/watchdog/imx7ulp_wdt.c291
-rw-r--r--drivers/watchdog/imx8_wdt.c235
-rw-r--r--drivers/xen/swiotlb-xen.c28
1452 files changed, 796147 insertions, 7815 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index e1e2066cecdb..bec8debd828e 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -102,6 +102,8 @@ source "drivers/mmc/Kconfig"
source "drivers/memstick/Kconfig"
+source "drivers/mxc/Kconfig"
+
source "drivers/leds/Kconfig"
source "drivers/accessibility/Kconfig"
@@ -202,4 +204,6 @@ source "drivers/hwtracing/intel_th/Kconfig"
source "drivers/fpga/Kconfig"
+source "drivers/tee/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 7c3d58dcf6b3..beca20436217 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -125,6 +125,7 @@ obj-y += lguest/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_CPU_IDLE) += cpuidle/
obj-y += mmc/
+obj-y += mxc/
obj-$(CONFIG_MEMSTICK) += memstick/
obj-$(CONFIG_NEW_LEDS) += leds/
obj-$(CONFIG_INFINIBAND) += infiniband/
@@ -175,3 +176,4 @@ obj-$(CONFIG_STM) += hwtracing/stm/
obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_NVMEM) += nvmem/
obj-$(CONFIG_FPGA) += fpga/
+obj-$(CONFIG_TEE) += tee/
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 5d16fc4fa46c..cbdf105dfe88 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -126,7 +126,7 @@ config AHCI_ST
config AHCI_IMX
tristate "Freescale i.MX AHCI SATA support"
- depends on MFD_SYSCON && (ARCH_MXC || COMPILE_TEST)
+ depends on MFD_SYSCON && (SOC_IMX53 || SOC_IMX6Q || ARCH_FSL_IMX8QM || COMPILE_TEST)
help
This option enables support for the Freescale i.MX SoC's
onboard AHCI SATA.
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index 3f3a7db208ae..05f2fdaee9b3 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -22,6 +22,8 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/ahci_platform.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
#include <linux/of_device.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
@@ -50,11 +52,82 @@ enum {
/* Clock Reset Register */
IMX_CLOCK_RESET = 0x7f3f,
IMX_CLOCK_RESET_RESET = 1 << 0,
+ /* IMX8QM HSIO AHCI definitions */
+ IMX8QM_SATA_PHY_REG03_RX_IMPED_RATIO = 0x03,
+ IMX8QM_SATA_PHY_REG09_TX_IMPED_RATIO = 0x09,
+ IMX8QM_SATA_PHY_REG10_TX_POST_CURSOR_RATIO = 0x0a,
+ IMX8QM_SATA_PHY_GEN1_TX_POST_CURSOR_RATIO = 0x15,
+ IMX8QM_SATA_PHY_IMPED_RATIO_85OHM = 0x6c,
+ IMX8QM_SATA_PHY_REG22_TX_POST_CURSOR_RATIO = 0x16,
+ IMX8QM_SATA_PHY_GEN2_TX_POST_CURSOR_RATIO = 0x00,
+ IMX8QM_SATA_PHY_REG24_TX_AMP_RATIO_MARGIN0 = 0x18,
+ IMX8QM_SATA_PHY_TX_AMP_RATIO_MARGIN0 = 0x64,
+ IMX8QM_SATA_PHY_REG25_TX_AMP_RATIO_MARGIN1 = 0x19,
+ IMX8QM_SATA_PHY_TX_AMP_RATIO_MARGIN1 = 0x70,
+ IMX8QM_SATA_PHY_REG26_TX_AMP_RATIO_MARGIN2 = 0x1a,
+ IMX8QM_SATA_PHY_TX_AMP_RATIO_MARGIN2 = 0x69,
+ IMX8QM_SATA_PHY_REG48_PMA_STATUS = 0x30,
+ IMX8QM_SATA_PHY_REG48_PMA_RDY = BIT(7),
+ IMX8QM_SATA_PHY_REG128_UPDATE_SETTING = 0x80,
+ IMX8QM_SATA_PHY_UPDATE_SETTING = 0x01,
+ IMX8QM_LPCG_PHYX2_OFFSET = 0x00000,
+ IMX8QM_CSR_PHYX2_OFFSET = 0x90000,
+ IMX8QM_CSR_PHYX1_OFFSET = 0xa0000,
+ IMX8QM_CSR_PHYX_STTS0_OFFSET = 0x4,
+ IMX8QM_CSR_PCIEA_OFFSET = 0xb0000,
+ IMX8QM_CSR_PCIEB_OFFSET = 0xc0000,
+ IMX8QM_CSR_SATA_OFFSET = 0xd0000,
+ IMX8QM_CSR_PCIE_CTRL2_OFFSET = 0x8,
+ IMX8QM_CSR_MISC_OFFSET = 0xe0000,
+ /* IMX8QM SATA specific control registers */
+ IMX8QM_SATA_PPCFG_OFFSET = 0xa8,
+ IMX8QM_SATA_PPCFG_FORCE_PHY_RDY = BIT(20),
+ IMX8QM_SATA_PPCFG_BIST_PATTERN_MASK = 0x7 << 21,
+ IMX8QM_SATA_PPCFG_BIST_PATTERN_OFFSET = 21,
+ IMX8QM_SATA_PPCFG_BIST_PATTERN_EN = BIT(24),
+ IMX8QM_SATA_PPCFG_BIST_PATTERN_NOALIGNS = BIT(26),
+ IMX8QM_SATA_PP2CFG_OFFSET = 0xac,
+ IMX8QM_SATA_PP2CFG_COMINIT_NEGATE_MIN = 0x28 << 24,
+ IMX8QM_SATA_PP2CFG_COMINT_BURST_GAP = 0x18 << 16,
+ IMX8QM_SATA_PP2CFG_COMINT_BURST_GAP_MAX = 0x2b << 8,
+ IMX8QM_SATA_PP2CFG_COMINT_BURST_GAP_MIN = 0x1b << 0,
+ IMX8QM_SATA_PP3CFG_OFFSET = 0xb0,
+ IMX8QM_SATA_PP3CFG_COMWAKE_NEGATE_MIN = 0x0e << 24,
+ IMX8QM_SATA_PP3CFG_COMWAKE_BURST_GAP = 0x08 << 16,
+ IMX8QM_SATA_PP3CFG_COMWAKE_BURST_GAP_MAX = 0x0f << 8,
+ IMX8QM_SATA_PP3CFG_COMWAKE_BURST_GAP_MIN = 0x01 << 0,
+
+ IMX8QM_LPCG_PHYX2_PCLK0_MASK = (0x3 << 16),
+ IMX8QM_LPCG_PHYX2_PCLK1_MASK = (0x3 << 20),
+ IMX8QM_PHY_APB_RSTN_0 = BIT(0),
+ IMX8QM_PHY_MODE_SATA = BIT(19),
+ IMX8QM_PHY_MODE_MASK = (0xf << 17),
+ IMX8QM_PHY_PIPE_RSTN_0 = BIT(24),
+ IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0 = BIT(25),
+ IMX8QM_PHY_PIPE_RSTN_1 = BIT(26),
+ IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1 = BIT(27),
+ IMX8QM_STTS0_LANE0_TX_PLL_LOCK = BIT(4),
+ IMX8QM_MISC_IOB_RXENA = BIT(0),
+ IMX8QM_MISC_IOB_TXENA = BIT(1),
+ IMX8QM_MISC_PHYX1_EPCS_SEL = BIT(12),
+ IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1 = BIT(24),
+ IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0 = BIT(25),
+ IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1 = BIT(28),
+ IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0 = BIT(29),
+ IMX8QM_SATA_CTRL_RESET_N = BIT(12),
+ IMX8QM_SATA_CTRL_EPCS_PHYRESET_N = BIT(7),
+ IMX8QM_SATA_CTRL_EPCS_TXDEEMP_SEL = BIT(6),
+ IMX8QM_SATA_CTRL_EPCS_TXDEEMP = BIT(5),
+ IMX8QM_CTRL_BUTTON_RST_N = BIT(21),
+ IMX8QM_CTRL_POWER_UP_RST_N = BIT(23),
+ IMX8QM_CTRL_LTSSM_ENABLE = BIT(4),
};
enum ahci_imx_type {
AHCI_IMX53,
AHCI_IMX6Q,
+ AHCI_IMX6QP,
+ AHCI_IMX8QM,
};
struct imx_ahci_priv {
@@ -63,16 +136,30 @@ struct imx_ahci_priv {
struct clk *sata_clk;
struct clk *sata_ref_clk;
struct clk *ahb_clk;
+ struct clk *epcs_tx_clk;
+ struct clk *epcs_rx_clk;
+ struct clk *phy_apbclk;
+ struct clk *phy_pclk0;
+ struct clk *phy_pclk1;
+ void __iomem *phy_base;
+ int clkreq_gpio;
struct regmap *gpr;
bool no_device;
bool first_time;
u32 phy_params;
+ u32 imped_ratio;
};
+void *sg_io_buffer_hack;
+
static int ahci_imx_hotplug;
module_param_named(hotplug, ahci_imx_hotplug, int, 0644);
MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)");
+static int bist_enable;
+module_param_named(bist, bist_enable, int, 0644);
+MODULE_PARM_DESC(bist, "AHCI IMX bist mode enable(1 = enable)");
+
static void ahci_imx_host_stop(struct ata_host *host);
static int imx_phy_crbit_assert(void __iomem *mmio, u32 bit, bool assert)
@@ -214,6 +301,259 @@ static int imx_sata_phy_reset(struct ahci_host_priv *hpriv)
return timeout ? 0 : -ETIMEDOUT;
}
+static int imx8_sata_enable(struct ahci_host_priv *hpriv)
+{
+ u32 val, reg;
+ int i, ret;
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+ struct device *dev = &imxpriv->ahci_pdev->dev;
+
+ /* configure the hsio for sata */
+ ret = clk_prepare_enable(imxpriv->phy_pclk0);
+ if (ret < 0) {
+ dev_err(dev, "can't enable phy pclk0.\n");
+ return ret;
+ }
+ ret = clk_prepare_enable(imxpriv->phy_pclk1);
+ if (ret < 0) {
+ dev_err(dev, "can't enable phy pclk1.\n");
+ goto disable_phy_pclk0;
+ }
+ ret = clk_prepare_enable(imxpriv->epcs_tx_clk);
+ if (ret < 0) {
+ dev_err(dev, "can't enable epcs tx clk.\n");
+ goto disable_phy_pclk1;
+ }
+ ret = clk_prepare_enable(imxpriv->epcs_rx_clk);
+ if (ret < 0) {
+ dev_err(dev, "can't enable epcs rx clk.\n");
+ goto disable_epcs_tx_clk;
+ }
+ ret = clk_prepare_enable(imxpriv->phy_apbclk);
+ if (ret < 0) {
+ dev_err(dev, "can't enable phy pclk1.\n");
+ goto disable_epcs_rx_clk;
+ }
+ /* Configure PHYx2 PIPE_RSTN */
+ regmap_read(imxpriv->gpr, IMX8QM_CSR_PCIEA_OFFSET
+ + IMX8QM_CSR_PCIE_CTRL2_OFFSET, &val);
+ if ((val & IMX8QM_CTRL_LTSSM_ENABLE) == 0) {
+ /* PCIEA of HSIO is down too */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_PHYX2_OFFSET,
+ IMX8QM_PHY_PIPE_RSTN_0
+ | IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0,
+ IMX8QM_PHY_PIPE_RSTN_0
+ | IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0);
+ }
+ regmap_read(imxpriv->gpr, IMX8QM_CSR_PCIEB_OFFSET
+ + IMX8QM_CSR_PCIE_CTRL2_OFFSET, &reg);
+ if ((reg & IMX8QM_CTRL_LTSSM_ENABLE) == 0) {
+ /* PCIEB of HSIO is down */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_PHYX2_OFFSET,
+ IMX8QM_PHY_PIPE_RSTN_1
+ | IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1,
+ IMX8QM_PHY_PIPE_RSTN_1
+ | IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1);
+ }
+ if (((reg | val) & IMX8QM_CTRL_LTSSM_ENABLE) == 0) {
+ /* Both PCIA and PCIEB of HSIO is down */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_LPCG_PHYX2_OFFSET,
+ IMX8QM_LPCG_PHYX2_PCLK0_MASK
+ | IMX8QM_LPCG_PHYX2_PCLK1_MASK,
+ 0);
+ }
+
+ /* set PWR_RST and BT_RST of csr_pciea */
+ val = IMX8QM_CSR_PCIEA_OFFSET + IMX8QM_CSR_PCIE_CTRL2_OFFSET;
+ regmap_update_bits(imxpriv->gpr,
+ val,
+ IMX8QM_CTRL_BUTTON_RST_N,
+ IMX8QM_CTRL_BUTTON_RST_N);
+ regmap_update_bits(imxpriv->gpr,
+ val,
+ IMX8QM_CTRL_POWER_UP_RST_N,
+ IMX8QM_CTRL_POWER_UP_RST_N);
+
+ /* PHYX1_MODE to SATA */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_PHYX1_OFFSET,
+ IMX8QM_PHY_MODE_MASK,
+ IMX8QM_PHY_MODE_SATA);
+
+ /*
+ * bit0 rx ena 1, bit1 tx ena 0
+ * bit12 PHY_X1_EPCS_SEL 1.
+ */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_IOB_RXENA,
+ IMX8QM_MISC_IOB_RXENA);
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_IOB_TXENA,
+ 0);
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_PHYX1_EPCS_SEL,
+ IMX8QM_MISC_PHYX1_EPCS_SEL);
+ /*
+ * It is possible, for PCIe and SATA are sharing
+ * the same clock source, HPLL or external oscillator.
+ * When PCIe is in low power modes (L1.X or L2 etc),
+ * the clock source can be turned off. In this case,
+ * if this clock source is required to be toggling by
+ * SATA, then SATA functions will be abnormal.
+ */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1
+ | IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0
+ | IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1
+ | IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0,
+ IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1
+ | IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0
+ | IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1
+ | IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0);
+
+ /* clear PHY RST, then set it */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_EPCS_PHYRESET_N,
+ 0);
+
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_EPCS_PHYRESET_N,
+ IMX8QM_SATA_CTRL_EPCS_PHYRESET_N);
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_EPCS_TXDEEMP,
+ IMX8QM_SATA_CTRL_EPCS_TXDEEMP);
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_EPCS_TXDEEMP_SEL,
+ IMX8QM_SATA_CTRL_EPCS_TXDEEMP_SEL);
+
+ /* CTRL RST: SET -> delay 1 us -> CLEAR -> SET */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_RESET_N,
+ IMX8QM_SATA_CTRL_RESET_N);
+ udelay(1);
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_RESET_N,
+ 0);
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_SATA_OFFSET,
+ IMX8QM_SATA_CTRL_RESET_N,
+ IMX8QM_SATA_CTRL_RESET_N);
+
+ /* APB reset */
+ regmap_update_bits(imxpriv->gpr,
+ IMX8QM_CSR_PHYX1_OFFSET,
+ IMX8QM_PHY_APB_RSTN_0,
+ IMX8QM_PHY_APB_RSTN_0);
+
+ for (i = 0; i < 100; i++) {
+ reg = IMX8QM_CSR_PHYX1_OFFSET
+ + IMX8QM_CSR_PHYX_STTS0_OFFSET;
+ regmap_read(imxpriv->gpr, reg, &val);
+ val &= IMX8QM_STTS0_LANE0_TX_PLL_LOCK;
+ if (val == IMX8QM_STTS0_LANE0_TX_PLL_LOCK)
+ break;
+ udelay(1);
+ }
+
+ if (val != IMX8QM_STTS0_LANE0_TX_PLL_LOCK) {
+ dev_err(dev, "TX PLL of the PHY is not locked\n");
+ ret = -ENODEV;
+ } else {
+ for (i = 0; i < 1000; i++) {
+ reg = readb(imxpriv->phy_base +
+ IMX8QM_SATA_PHY_REG48_PMA_STATUS);
+ if (reg & IMX8QM_SATA_PHY_REG48_PMA_RDY)
+ break;
+ udelay(10);
+ }
+ if ((reg & IMX8QM_SATA_PHY_REG48_PMA_RDY) == 0) {
+ dev_err(dev, "Calibration is NOT finished.\n");
+ ret = -ENODEV;
+ goto err_out;
+ }
+
+ writeb(imxpriv->imped_ratio, imxpriv->phy_base
+ + IMX8QM_SATA_PHY_REG03_RX_IMPED_RATIO);
+ writeb(imxpriv->imped_ratio, imxpriv->phy_base
+ + IMX8QM_SATA_PHY_REG09_TX_IMPED_RATIO);
+ reg = readb(imxpriv->phy_base
+ + IMX8QM_SATA_PHY_REG03_RX_IMPED_RATIO);
+ if (unlikely(reg != imxpriv->imped_ratio))
+ dev_info(dev, "Can't set PHY RX impedance ratio.\n");
+ reg = readb(imxpriv->phy_base
+ + IMX8QM_SATA_PHY_REG09_TX_IMPED_RATIO);
+ if (unlikely(reg != imxpriv->imped_ratio))
+ dev_info(dev, "Can't set PHY TX impedance ratio.\n");
+
+ /* Configure the tx_amplitude to pass the tests. */
+ writeb(IMX8QM_SATA_PHY_TX_AMP_RATIO_MARGIN0, imxpriv->phy_base +
+ IMX8QM_SATA_PHY_REG24_TX_AMP_RATIO_MARGIN0);
+ writeb(IMX8QM_SATA_PHY_TX_AMP_RATIO_MARGIN1, imxpriv->phy_base +
+ IMX8QM_SATA_PHY_REG25_TX_AMP_RATIO_MARGIN1);
+ writeb(IMX8QM_SATA_PHY_TX_AMP_RATIO_MARGIN2, imxpriv->phy_base +
+ IMX8QM_SATA_PHY_REG26_TX_AMP_RATIO_MARGIN2);
+
+ /* Adjust the OOB COMINIT/COMWAKE to pass the tests. */
+ writeb(IMX8QM_SATA_PHY_GEN1_TX_POST_CURSOR_RATIO,
+ imxpriv->phy_base +
+ IMX8QM_SATA_PHY_REG10_TX_POST_CURSOR_RATIO);
+ writeb(IMX8QM_SATA_PHY_GEN2_TX_POST_CURSOR_RATIO,
+ imxpriv->phy_base +
+ IMX8QM_SATA_PHY_REG22_TX_POST_CURSOR_RATIO);
+
+ writeb(IMX8QM_SATA_PHY_UPDATE_SETTING, imxpriv->phy_base +
+ IMX8QM_SATA_PHY_REG128_UPDATE_SETTING);
+
+ reg = IMX8QM_SATA_PP2CFG_COMINIT_NEGATE_MIN |
+ IMX8QM_SATA_PP2CFG_COMINT_BURST_GAP |
+ IMX8QM_SATA_PP2CFG_COMINT_BURST_GAP_MAX |
+ IMX8QM_SATA_PP2CFG_COMINT_BURST_GAP_MIN;
+ writel(reg, hpriv->mmio + IMX8QM_SATA_PP2CFG_OFFSET);
+ reg = IMX8QM_SATA_PP3CFG_COMWAKE_NEGATE_MIN |
+ IMX8QM_SATA_PP3CFG_COMWAKE_BURST_GAP |
+ IMX8QM_SATA_PP3CFG_COMWAKE_BURST_GAP_MAX |
+ IMX8QM_SATA_PP3CFG_COMWAKE_BURST_GAP_MIN;
+ writel(reg, hpriv->mmio + IMX8QM_SATA_PP3CFG_OFFSET);
+
+ usleep_range(50, 100);
+
+ /*
+ * To reduce the power consumption, gate off
+ * the PHY clks
+ */
+ clk_disable_unprepare(imxpriv->phy_apbclk);
+ clk_disable_unprepare(imxpriv->phy_pclk1);
+ clk_disable_unprepare(imxpriv->phy_pclk0);
+ return ret;
+ }
+
+err_out:
+ clk_disable_unprepare(imxpriv->phy_apbclk);
+disable_epcs_rx_clk:
+ clk_disable_unprepare(imxpriv->epcs_rx_clk);
+disable_epcs_tx_clk:
+ clk_disable_unprepare(imxpriv->epcs_tx_clk);
+disable_phy_pclk1:
+ clk_disable_unprepare(imxpriv->phy_pclk1);
+disable_phy_pclk0:
+ clk_disable_unprepare(imxpriv->phy_pclk0);
+
+ return ret;
+}
+
static int imx_sata_enable(struct ahci_host_priv *hpriv)
{
struct imx_ahci_priv *imxpriv = hpriv->plat_data;
@@ -231,7 +571,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
if (ret < 0)
goto disable_regulator;
- if (imxpriv->type == AHCI_IMX6Q) {
+ if (imxpriv->type == AHCI_IMX6Q || imxpriv->type == AHCI_IMX6QP) {
/*
* set PHY Paremeters, two steps to configure the GPR13,
* one write for rest of parameters, mask of first write
@@ -255,12 +595,28 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
IMX6Q_GPR13_SATA_MPLL_CLK_EN);
usleep_range(100, 200);
+ }
+
+ if (imxpriv->type == AHCI_IMX6Q) {
ret = imx_sata_phy_reset(hpriv);
- if (ret) {
- dev_err(dev, "failed to reset phy: %d\n", ret);
- goto disable_clk;
- }
+ } else if (imxpriv->type == AHCI_IMX6QP) {
+ /* 6qp adds the sata reset mechanism, use it for 6qp sata */
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR5,
+ BIT(10), 0);
+
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR5,
+ BIT(11), 0);
+ udelay(50);
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR5,
+ BIT(11), BIT(11));
+ } else if (imxpriv->type == AHCI_IMX8QM) {
+ ret = imx8_sata_enable(hpriv);
+ }
+
+ if (ret) {
+ dev_err(dev, "failed to reset phy: %d\n", ret);
+ goto disable_clk;
}
usleep_range(1000, 2000);
@@ -282,12 +638,20 @@ static void imx_sata_disable(struct ahci_host_priv *hpriv)
if (imxpriv->no_device)
return;
- if (imxpriv->type == AHCI_IMX6Q) {
+ if (imxpriv->type == AHCI_IMX6QP)
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR5,
+ BIT(10), BIT(10));
+
+ if (imxpriv->type == AHCI_IMX6Q || imxpriv->type == AHCI_IMX6QP) {
regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
IMX6Q_GPR13_SATA_MPLL_CLK_EN,
!IMX6Q_GPR13_SATA_MPLL_CLK_EN);
}
+ if (imxpriv->type == AHCI_IMX8QM) {
+ clk_disable_unprepare(imxpriv->epcs_rx_clk);
+ clk_disable_unprepare(imxpriv->epcs_tx_clk);
+ }
clk_disable_unprepare(imxpriv->sata_ref_clk);
ahci_platform_disable_regulators(hpriv);
@@ -304,7 +668,8 @@ static void ahci_imx_error_handler(struct ata_port *ap)
ahci_error_handler(ap);
- if (!(imxpriv->first_time) || ahci_imx_hotplug)
+ if (!(imxpriv->first_time) || ahci_imx_hotplug
+ || (imxpriv->type == AHCI_IMX8QM))
return;
imxpriv->first_time = false;
@@ -336,7 +701,7 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
if (imxpriv->type == AHCI_IMX53)
ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline);
- else if (imxpriv->type == AHCI_IMX6Q)
+ else
ret = ahci_ops.softreset(link, class, deadline);
return ret;
@@ -359,6 +724,8 @@ static const struct ata_port_info ahci_imx_port_info = {
static const struct of_device_id imx_ahci_of_match[] = {
{ .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 },
{ .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q },
+ { .compatible = "fsl,imx6qp-ahci", .data = (void *)AHCI_IMX6QP },
+ { .compatible = "fsl,imx8qm-ahci", .data = (void *)AHCI_IMX8QM },
{},
};
MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
@@ -526,6 +893,188 @@ static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT(DRV_NAME),
};
+static int imx8_sata_probe(struct device *dev, struct imx_ahci_priv *imxpriv)
+{
+ int ret;
+ struct resource *phy_res;
+ struct platform_device *pdev = imxpriv->ahci_pdev;
+ struct device_node *np = dev->of_node;
+
+ if (of_property_read_u32(np, "fsl,phy-imp", &imxpriv->imped_ratio)) {
+ /*
+ * Regarding to the differnet Hw designs,
+ * Set the impedance ratio to 0x6c when 85OHM is used.
+ * Keep it to default value 0x80, when 100OHM is used.
+ */
+ dev_info(dev, "phy impedance ratio is not specified.\n");
+ imxpriv->imped_ratio = IMX8QM_SATA_PHY_IMPED_RATIO_85OHM;
+ }
+ phy_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
+ if (phy_res) {
+ imxpriv->phy_base = devm_ioremap(dev, phy_res->start,
+ resource_size(phy_res));
+ if (!imxpriv->phy_base) {
+ dev_err(dev, "error with ioremap\n");
+ return -ENOMEM;
+ }
+ } else {
+ dev_err(dev, "missing *phy* reg region.\n");
+ return -ENOMEM;
+ }
+ imxpriv->gpr =
+ syscon_regmap_lookup_by_phandle(np, "hsio");
+ if (IS_ERR(imxpriv->gpr)) {
+ dev_err(dev, "unable to find gpr registers\n");
+ return PTR_ERR(imxpriv->gpr);
+ }
+ imxpriv->epcs_tx_clk = devm_clk_get(dev, "epcs_tx");
+ if (IS_ERR(imxpriv->epcs_tx_clk)) {
+ dev_err(dev, "can't get sata_epcs tx clock.\n");
+ return PTR_ERR(imxpriv->epcs_tx_clk);
+ }
+
+ imxpriv->epcs_rx_clk = devm_clk_get(dev, "epcs_rx");
+ if (IS_ERR(imxpriv->epcs_rx_clk)) {
+ dev_err(dev, "can't get sata_epcs rx clock.\n");
+ return PTR_ERR(imxpriv->epcs_rx_clk);
+ }
+
+ imxpriv->phy_pclk0 = devm_clk_get(dev, "phy_pclk0");
+ if (IS_ERR(imxpriv->phy_pclk0)) {
+ dev_err(dev, "can't get sata_phy_pclk0 clock.\n");
+ return PTR_ERR(imxpriv->phy_pclk0);
+ }
+
+ imxpriv->phy_pclk1 = devm_clk_get(dev, "phy_pclk1");
+ if (IS_ERR(imxpriv->phy_pclk1)) {
+ dev_err(dev, "can't get sata_phy_pclk1 clock.\n");
+ return PTR_ERR(imxpriv->phy_pclk1);
+ }
+
+ imxpriv->phy_apbclk = devm_clk_get(dev, "phy_apbclk");
+ if (IS_ERR(imxpriv->phy_apbclk)) {
+ dev_err(dev, "can't get sata_phy_apbclk clock.\n");
+ return PTR_ERR(imxpriv->phy_apbclk);
+ }
+
+ /* Fetch GPIO, then enable the external OSC */
+ imxpriv->clkreq_gpio = of_get_named_gpio(np, "clkreq-gpio", 0);
+ if (gpio_is_valid(imxpriv->clkreq_gpio)) {
+ ret = devm_gpio_request_one(dev, imxpriv->clkreq_gpio,
+ GPIOF_OUT_INIT_LOW,
+ "SATA CLKREQ");
+ if (ret == -EBUSY) {
+ dev_info(dev, "clkreq had been initialized.\n");
+ } else if (ret) {
+ dev_err(dev, "%d unable to get clkreq.\n", ret);
+ return ret;
+ }
+ } else if (imxpriv->clkreq_gpio == -EPROBE_DEFER) {
+ return imxpriv->clkreq_gpio;
+ }
+
+ return 0;
+}
+
+static ssize_t imx_ahci_bist_pattern_info(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ u32 bist_pattern;
+ struct ahci_host_priv *hpriv = dev_get_drvdata(dev);
+
+ bist_pattern = readl(hpriv->mmio + IMX8QM_SATA_PPCFG_OFFSET);
+ bist_pattern = bist_pattern & IMX8QM_SATA_PPCFG_BIST_PATTERN_MASK;
+ bist_pattern = bist_pattern >> IMX8QM_SATA_PPCFG_BIST_PATTERN_OFFSET;
+ return sprintf(buf, "imx-ahci-bist-pattern %s%s%s%s.\n",
+ (BIT(0) << bist_pattern) & BIT(0) ? "LBP " : "",
+ (BIT(0) << bist_pattern) & BIT(1) ? "LFTP " : "",
+ (BIT(0) << bist_pattern) & BIT(2) ? "MFTP " : "",
+ (BIT(0) << bist_pattern) & BIT(3) ? "HFTP " : "");
+}
+
+static ssize_t imx_ahci_bist_pattern(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int ret;
+ u32 bist_pattern, val, timeout;
+ struct ahci_host_priv *hpriv = dev_get_drvdata(dev);
+
+ ret = sscanf(buf, "%x\n", &bist_pattern);
+ if (ret != 1)
+ return -EINVAL;
+ if ((bist_pattern > 3)) {
+ dev_err(dev, "LBP 0, LFTP 1, MFTP 2, HFTP 3.\n");
+ return -1;
+ }
+ dev_info(dev, "Try to enable %s%s%s%s pattern.\n",
+ (BIT(0) << bist_pattern) & BIT(0) ? "LBP " : "",
+ (BIT(0) << bist_pattern) & BIT(1) ? "LFTP " : "",
+ (BIT(0) << bist_pattern) & BIT(2) ? "MFTP " : "",
+ (BIT(0) << bist_pattern) & BIT(3) ? "HFTP " : "");
+
+ dev_info(dev, "Clear BIST enable.\n");
+ val = readl(hpriv->mmio + IMX8QM_SATA_PPCFG_OFFSET);
+ writel(val & (~IMX8QM_SATA_PPCFG_BIST_PATTERN_EN),
+ hpriv->mmio + IMX8QM_SATA_PPCFG_OFFSET);
+
+ /* put device into listen mode, first set PxSCTL.DET to 0 */
+ dev_info(dev, "Turn off device detection.\n");
+ val = readl(hpriv->mmio + 0x100 + PORT_SCR_CTL);
+ writel(val & ~0xf, hpriv->mmio + 0x100 + PORT_SCR_CTL);
+
+ dev_info(dev, "Force phy ready, then wait.\n");
+ val = readl(hpriv->mmio + IMX8QM_SATA_PPCFG_OFFSET);
+ writel(val | IMX8QM_SATA_PPCFG_FORCE_PHY_RDY,
+ hpriv->mmio + IMX8QM_SATA_PPCFG_OFFSET);
+
+ timeout = 1000;
+ do {
+ val = readl(hpriv->mmio + 0x100 + PORT_SCR_STAT);
+ if ((val & 0xf) > 1)
+ break;
+ mdelay(1);
+ } while (--timeout);
+ if (timeout == 0)
+ dev_info(dev, "Error, wait for phy ready timeout.\n");
+ else
+ dev_info(dev, "Get phy ready, and Gen%d mode is set.\n",
+ (val & 0xF0) >> 4);
+
+ /* clear SError */
+ dev_info(dev, "Clear error reg.\n");
+ val = readl(hpriv->mmio + 0x100 + PORT_SCR_ERR);
+ writel(val, hpriv->mmio + 0x100 + PORT_SCR_ERR);
+
+ dev_info(dev, "Select BIST pattern.\n");
+ val = readl(hpriv->mmio + IMX8QM_SATA_PPCFG_OFFSET);
+ val &= (~IMX8QM_SATA_PPCFG_BIST_PATTERN_MASK);
+ val |= (bist_pattern << IMX8QM_SATA_PPCFG_BIST_PATTERN_OFFSET);
+ writel(val, hpriv->mmio + IMX8QM_SATA_PPCFG_OFFSET);
+
+ dev_info(dev, "Set no aligns in BIST pattern.\n");
+ val = readl(hpriv->mmio + IMX8QM_SATA_PPCFG_OFFSET);
+ writel(val | IMX8QM_SATA_PPCFG_BIST_PATTERN_NOALIGNS,
+ hpriv->mmio + IMX8QM_SATA_PPCFG_OFFSET);
+
+ dev_info(dev, "BIST enable.\n");
+ val = readl(hpriv->mmio + IMX8QM_SATA_PPCFG_OFFSET);
+ writel(val | IMX8QM_SATA_PPCFG_BIST_PATTERN_EN,
+ hpriv->mmio + IMX8QM_SATA_PPCFG_OFFSET);
+
+ return count;
+}
+
+static DEVICE_ATTR(ahci_bist_pattern, 0644, imx_ahci_bist_pattern_info,
+ imx_ahci_bist_pattern);
+
+static struct attribute *imx_ahci_attrs[] = {
+ &dev_attr_ahci_bist_pattern.attr,
+ NULL
+};
+
+static struct attribute_group imx_ahci_attrgroup = {
+ .attrs = imx_ahci_attrs,
+};
static int imx_ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -560,13 +1109,7 @@ static int imx_ahci_probe(struct platform_device *pdev)
return PTR_ERR(imxpriv->sata_ref_clk);
}
- imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
- if (IS_ERR(imxpriv->ahb_clk)) {
- dev_err(dev, "can't get ahb clock.\n");
- return PTR_ERR(imxpriv->ahb_clk);
- }
-
- if (imxpriv->type == AHCI_IMX6Q) {
+ if (imxpriv->type == AHCI_IMX6Q || imxpriv->type == AHCI_IMX6QP) {
u32 reg_value;
imxpriv->gpr = syscon_regmap_lookup_by_compatible(
@@ -585,6 +1128,10 @@ static int imx_ahci_probe(struct platform_device *pdev)
IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
reg_value;
+ } else if (imxpriv->type == AHCI_IMX8QM) {
+ ret = imx8_sata_probe(dev, imxpriv);
+ if (ret)
+ return ret;
}
hpriv = ahci_platform_get_resources(pdev);
@@ -619,15 +1166,62 @@ static int imx_ahci_probe(struct platform_device *pdev)
writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL);
}
- reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
- writel(reg_val, hpriv->mmio + IMX_TIMER1MS);
+ imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
+ if (IS_ERR(imxpriv->ahb_clk)) {
+ dev_info(dev, "no ahb clock.\n");
+ } else {
+ /*
+ * AHB clock is only used to configure the vendor specified
+ * TIMER1MS register. Set it if the AHB clock is defined.
+ */
+ reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
+ writel(reg_val, hpriv->mmio + IMX_TIMER1MS);
+ }
- ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info,
- &ahci_platform_sht);
- if (ret)
- goto disable_sata;
+ /*
+ * Due to IP bug on the Synopsis 3.00 SATA version,
+ * which is present on mx6q, and not on mx53,
+ * we should use sg_tablesize = 1 for reliable operation
+ */
+ if (imxpriv->type == AHCI_IMX6Q || imxpriv->type == AHCI_IMX6QP) {
+ dma_addr_t dma;
+
+ ahci_platform_sht.sg_tablesize = 1;
+
+ sg_io_buffer_hack = dma_alloc_coherent(NULL, 0x10000,
+ &dma, GFP_KERNEL);
+ if (!sg_io_buffer_hack) {
+ ret = -ENOMEM;
+ goto disable_sata;
+ }
+ }
- return 0;
+ if (imxpriv->type == AHCI_IMX8QM && bist_enable) {
+ dev_info(dev, "AHCI SATA compliance test patterns.\n");
+ ret = clk_prepare_enable(imxpriv->phy_pclk0);
+ if (ret < 0)
+ dev_err(dev, "can't enable phy pclk0.\n");
+ ret = clk_prepare_enable(imxpriv->phy_pclk1);
+ if (ret < 0)
+ dev_err(dev, "can't enable phy pclk1.\n");
+ ret = clk_prepare_enable(imxpriv->phy_apbclk);
+ if (ret < 0)
+ dev_err(dev, "can't get sata_phy_apbclk clock.\n");
+
+ dev_set_drvdata(dev, hpriv);
+ ret = sysfs_create_group(&pdev->dev.kobj, &imx_ahci_attrgroup);
+ if (ret)
+ ret = -EINVAL;
+ dev_info(dev, "Register AHCI SATA BIST sysfile callback.\n");
+ } else {
+
+ ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info,
+ &ahci_platform_sht);
+ if (ret)
+ goto disable_sata;
+ }
+
+ return ret;
disable_sata:
imx_sata_disable(hpriv);
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 0651010bba21..4a7032cbb3c1 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -154,6 +154,7 @@ config FW_LOADER_USER_HELPER
config FW_LOADER_USER_HELPER_FALLBACK
bool "Fallback user-helper invocation for firmware loading"
depends on FW_LOADER
+ default y
select FW_LOADER_USER_HELPER
help
This option enables / disables the invocation of user-helper
diff --git a/drivers/base/base.h b/drivers/base/base.h
index e05db388bd1c..e19b1008e5fb 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -107,6 +107,9 @@ extern void bus_remove_device(struct device *dev);
extern int bus_add_driver(struct device_driver *drv);
extern void bus_remove_driver(struct device_driver *drv);
+extern void device_release_driver_internal(struct device *dev,
+ struct device_driver *drv,
+ struct device *parent);
extern void driver_detach(struct device_driver *drv);
extern int driver_probe_device(struct device_driver *drv, struct device *dev);
@@ -152,3 +155,13 @@ extern int devtmpfs_init(void);
#else
static inline int devtmpfs_init(void) { return 0; }
#endif
+
+/* Device links support */
+extern int device_links_read_lock(void);
+extern void device_links_read_unlock(int idx);
+extern int device_links_check_suppliers(struct device *dev);
+extern void device_links_driver_bound(struct device *dev);
+extern void device_links_driver_cleanup(struct device *dev);
+extern void device_links_no_driver(struct device *dev);
+extern bool device_links_busy(struct device *dev);
+extern void device_links_unbind_consumers(struct device *dev);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index f43caad30e1e..548c7412f28c 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -44,6 +44,541 @@ static int __init sysfs_deprecated_setup(char *arg)
early_param("sysfs.deprecated", sysfs_deprecated_setup);
#endif
+/* Device links support. */
+
+#ifdef CONFIG_SRCU
+static DEFINE_MUTEX(device_links_lock);
+DEFINE_STATIC_SRCU(device_links_srcu);
+
+static inline void device_links_write_lock(void)
+{
+ mutex_lock(&device_links_lock);
+}
+
+static inline void device_links_write_unlock(void)
+{
+ mutex_unlock(&device_links_lock);
+}
+
+int device_links_read_lock(void)
+{
+ return srcu_read_lock(&device_links_srcu);
+}
+
+void device_links_read_unlock(int idx)
+{
+ srcu_read_unlock(&device_links_srcu, idx);
+}
+#else /* !CONFIG_SRCU */
+static DECLARE_RWSEM(device_links_lock);
+
+static inline void device_links_write_lock(void)
+{
+ down_write(&device_links_lock);
+}
+
+static inline void device_links_write_unlock(void)
+{
+ up_write(&device_links_lock);
+}
+
+int device_links_read_lock(void)
+{
+ down_read(&device_links_lock);
+ return 0;
+}
+
+void device_links_read_unlock(int not_used)
+{
+ up_read(&device_links_lock);
+}
+#endif /* !CONFIG_SRCU */
+
+/**
+ * device_is_dependent - Check if one device depends on another one
+ * @dev: Device to check dependencies for.
+ * @target: Device to check against.
+ *
+ * Check if @target depends on @dev or any device dependent on it (its child or
+ * its consumer etc). Return 1 if that is the case or 0 otherwise.
+ */
+static int device_is_dependent(struct device *dev, void *target)
+{
+ struct device_link *link;
+ int ret;
+
+ if (WARN_ON(dev == target))
+ return 1;
+
+ ret = device_for_each_child(dev, target, device_is_dependent);
+ if (ret)
+ return ret;
+
+ list_for_each_entry(link, &dev->links.consumers, s_node) {
+ if (WARN_ON(link->consumer == target))
+ return 1;
+
+ ret = device_is_dependent(link->consumer, target);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
+static int device_reorder_to_tail(struct device *dev, void *not_used)
+{
+ struct device_link *link;
+
+ /*
+ * Devices that have not been registered yet will be put to the ends
+ * of the lists during the registration, so skip them here.
+ */
+ if (device_is_registered(dev))
+ devices_kset_move_last(dev);
+
+ if (device_pm_initialized(dev))
+ device_pm_move_last(dev);
+
+ device_for_each_child(dev, NULL, device_reorder_to_tail);
+ list_for_each_entry(link, &dev->links.consumers, s_node)
+ device_reorder_to_tail(link->consumer, NULL);
+
+ return 0;
+}
+
+/**
+ * device_link_add - Create a link between two devices.
+ * @consumer: Consumer end of the link.
+ * @supplier: Supplier end of the link.
+ * @flags: Link flags.
+ *
+ * If the DL_FLAG_AUTOREMOVE is set, the link will be removed automatically
+ * when the consumer device driver unbinds from it. The combination of both
+ * DL_FLAG_AUTOREMOVE and DL_FLAG_STATELESS set is invalid and will cause NULL
+ * to be returned.
+ *
+ * A side effect of the link creation is re-ordering of dpm_list and the
+ * devices_kset list by moving the consumer device and all devices depending
+ * on it to the ends of these lists (that does not happen to devices that have
+ * not been registered when this function is called).
+ *
+ * The supplier device is required to be registered when this function is called
+ * and NULL will be returned if that is not the case. The consumer device need
+ * not be registerd, however.
+ */
+struct device_link *device_link_add(struct device *consumer,
+ struct device *supplier, u32 flags)
+{
+ struct device_link *link;
+
+ if (!consumer || !supplier ||
+ ((flags & DL_FLAG_STATELESS) && (flags & DL_FLAG_AUTOREMOVE)))
+ return NULL;
+
+ device_links_write_lock();
+ device_pm_lock();
+
+ /*
+ * If the supplier has not been fully registered yet or there is a
+ * reverse dependency between the consumer and the supplier already in
+ * the graph, return NULL.
+ */
+ if (!device_pm_initialized(supplier)
+ || device_is_dependent(consumer, supplier)) {
+ link = NULL;
+ goto out;
+ }
+
+ list_for_each_entry(link, &supplier->links.consumers, s_node)
+ if (link->consumer == consumer)
+ goto out;
+
+ link = kmalloc(sizeof(*link), GFP_KERNEL);
+ if (!link)
+ goto out;
+
+ get_device(supplier);
+ link->supplier = supplier;
+ INIT_LIST_HEAD(&link->s_node);
+ get_device(consumer);
+ link->consumer = consumer;
+ INIT_LIST_HEAD(&link->c_node);
+ link->flags = flags;
+
+ /* Deterine the initial link state. */
+ if (flags & DL_FLAG_STATELESS) {
+ link->status = DL_STATE_NONE;
+ } else {
+ switch (supplier->links.status) {
+ case DL_DEV_DRIVER_BOUND:
+ switch (consumer->links.status) {
+ case DL_DEV_PROBING:
+ link->status = DL_STATE_CONSUMER_PROBE;
+ break;
+ case DL_DEV_DRIVER_BOUND:
+ link->status = DL_STATE_ACTIVE;
+ break;
+ default:
+ link->status = DL_STATE_AVAILABLE;
+ break;
+ }
+ break;
+ case DL_DEV_UNBINDING:
+ link->status = DL_STATE_SUPPLIER_UNBIND;
+ break;
+ default:
+ link->status = DL_STATE_DORMANT;
+ break;
+ }
+ }
+
+ /*
+ * Move the consumer and all of the devices depending on it to the end
+ * of dpm_list and the devices_kset list.
+ *
+ * It is necessary to hold dpm_list locked throughout all that or else
+ * we may end up suspending with a wrong ordering of it.
+ */
+ device_reorder_to_tail(consumer, NULL);
+
+ list_add_tail_rcu(&link->s_node, &supplier->links.consumers);
+ list_add_tail_rcu(&link->c_node, &consumer->links.suppliers);
+
+ dev_info(consumer, "Linked as a consumer to %s\n", dev_name(supplier));
+
+ out:
+ device_pm_unlock();
+ device_links_write_unlock();
+ return link;
+}
+EXPORT_SYMBOL_GPL(device_link_add);
+
+static void device_link_free(struct device_link *link)
+{
+ put_device(link->consumer);
+ put_device(link->supplier);
+ kfree(link);
+}
+
+#ifdef CONFIG_SRCU
+static void __device_link_free_srcu(struct rcu_head *rhead)
+{
+ device_link_free(container_of(rhead, struct device_link, rcu_head));
+}
+
+static void __device_link_del(struct device_link *link)
+{
+ dev_info(link->consumer, "Dropping the link to %s\n",
+ dev_name(link->supplier));
+
+ list_del_rcu(&link->s_node);
+ list_del_rcu(&link->c_node);
+ call_srcu(&device_links_srcu, &link->rcu_head, __device_link_free_srcu);
+}
+#else /* !CONFIG_SRCU */
+static void __device_link_del(struct device_link *link)
+{
+ dev_info(link->consumer, "Dropping the link to %s\n",
+ dev_name(link->supplier));
+
+ list_del(&link->s_node);
+ list_del(&link->c_node);
+ device_link_free(link);
+}
+#endif /* !CONFIG_SRCU */
+
+/**
+ * device_link_del - Delete a link between two devices.
+ * @link: Device link to delete.
+ *
+ * The caller must ensure proper synchronization of this function with runtime
+ * PM.
+ */
+void device_link_del(struct device_link *link)
+{
+ device_links_write_lock();
+ device_pm_lock();
+ __device_link_del(link);
+ device_pm_unlock();
+ device_links_write_unlock();
+}
+EXPORT_SYMBOL_GPL(device_link_del);
+
+static void device_links_missing_supplier(struct device *dev)
+{
+ struct device_link *link;
+
+ list_for_each_entry(link, &dev->links.suppliers, c_node)
+ if (link->status == DL_STATE_CONSUMER_PROBE)
+ WRITE_ONCE(link->status, DL_STATE_AVAILABLE);
+}
+
+/**
+ * device_links_check_suppliers - Check presence of supplier drivers.
+ * @dev: Consumer device.
+ *
+ * Check links from this device to any suppliers. Walk the list of the device's
+ * links to suppliers and see if all of them are available. If not, simply
+ * return -EPROBE_DEFER.
+ *
+ * We need to guarantee that the supplier will not go away after the check has
+ * been positive here. It only can go away in __device_release_driver() and
+ * that function checks the device's links to consumers. This means we need to
+ * mark the link as "consumer probe in progress" to make the supplier removal
+ * wait for us to complete (or bad things may happen).
+ *
+ * Links with the DL_FLAG_STATELESS flag set are ignored.
+ */
+int device_links_check_suppliers(struct device *dev)
+{
+ struct device_link *link;
+ int ret = 0;
+
+ device_links_write_lock();
+
+ list_for_each_entry(link, &dev->links.suppliers, c_node) {
+ if (link->flags & DL_FLAG_STATELESS)
+ continue;
+
+ if (link->status != DL_STATE_AVAILABLE) {
+ device_links_missing_supplier(dev);
+ ret = -EPROBE_DEFER;
+ break;
+ }
+ WRITE_ONCE(link->status, DL_STATE_CONSUMER_PROBE);
+ }
+ dev->links.status = DL_DEV_PROBING;
+
+ device_links_write_unlock();
+ return ret;
+}
+
+/**
+ * device_links_driver_bound - Update device links after probing its driver.
+ * @dev: Device to update the links for.
+ *
+ * The probe has been successful, so update links from this device to any
+ * consumers by changing their status to "available".
+ *
+ * Also change the status of @dev's links to suppliers to "active".
+ *
+ * Links with the DL_FLAG_STATELESS flag set are ignored.
+ */
+void device_links_driver_bound(struct device *dev)
+{
+ struct device_link *link;
+
+ device_links_write_lock();
+
+ list_for_each_entry(link, &dev->links.consumers, s_node) {
+ if (link->flags & DL_FLAG_STATELESS)
+ continue;
+
+ WARN_ON(link->status != DL_STATE_DORMANT);
+ WRITE_ONCE(link->status, DL_STATE_AVAILABLE);
+ }
+
+ list_for_each_entry(link, &dev->links.suppliers, c_node) {
+ if (link->flags & DL_FLAG_STATELESS)
+ continue;
+
+ WARN_ON(link->status != DL_STATE_CONSUMER_PROBE);
+ WRITE_ONCE(link->status, DL_STATE_ACTIVE);
+ }
+
+ dev->links.status = DL_DEV_DRIVER_BOUND;
+
+ device_links_write_unlock();
+}
+
+/**
+ * __device_links_no_driver - Update links of a device without a driver.
+ * @dev: Device without a drvier.
+ *
+ * Delete all non-persistent links from this device to any suppliers.
+ *
+ * Persistent links stay around, but their status is changed to "available",
+ * unless they already are in the "supplier unbind in progress" state in which
+ * case they need not be updated.
+ *
+ * Links with the DL_FLAG_STATELESS flag set are ignored.
+ */
+static void __device_links_no_driver(struct device *dev)
+{
+ struct device_link *link, *ln;
+
+ list_for_each_entry_safe_reverse(link, ln, &dev->links.suppliers, c_node) {
+ if (link->flags & DL_FLAG_STATELESS)
+ continue;
+
+ if (link->flags & DL_FLAG_AUTOREMOVE)
+ __device_link_del(link);
+ else if (link->status != DL_STATE_SUPPLIER_UNBIND)
+ WRITE_ONCE(link->status, DL_STATE_AVAILABLE);
+ }
+
+ dev->links.status = DL_DEV_NO_DRIVER;
+}
+
+void device_links_no_driver(struct device *dev)
+{
+ device_links_write_lock();
+ __device_links_no_driver(dev);
+ device_links_write_unlock();
+}
+
+/**
+ * device_links_driver_cleanup - Update links after driver removal.
+ * @dev: Device whose driver has just gone away.
+ *
+ * Update links to consumers for @dev by changing their status to "dormant" and
+ * invoke %__device_links_no_driver() to update links to suppliers for it as
+ * appropriate.
+ *
+ * Links with the DL_FLAG_STATELESS flag set are ignored.
+ */
+void device_links_driver_cleanup(struct device *dev)
+{
+ struct device_link *link;
+
+ device_links_write_lock();
+
+ list_for_each_entry(link, &dev->links.consumers, s_node) {
+ if (link->flags & DL_FLAG_STATELESS)
+ continue;
+
+ WARN_ON(link->flags & DL_FLAG_AUTOREMOVE);
+ WARN_ON(link->status != DL_STATE_SUPPLIER_UNBIND);
+ WRITE_ONCE(link->status, DL_STATE_DORMANT);
+ }
+
+ __device_links_no_driver(dev);
+
+ device_links_write_unlock();
+}
+
+/**
+ * device_links_busy - Check if there are any busy links to consumers.
+ * @dev: Device to check.
+ *
+ * Check each consumer of the device and return 'true' if its link's status
+ * is one of "consumer probe" or "active" (meaning that the given consumer is
+ * probing right now or its driver is present). Otherwise, change the link
+ * state to "supplier unbind" to prevent the consumer from being probed
+ * successfully going forward.
+ *
+ * Return 'false' if there are no probing or active consumers.
+ *
+ * Links with the DL_FLAG_STATELESS flag set are ignored.
+ */
+bool device_links_busy(struct device *dev)
+{
+ struct device_link *link;
+ bool ret = false;
+
+ device_links_write_lock();
+
+ list_for_each_entry(link, &dev->links.consumers, s_node) {
+ if (link->flags & DL_FLAG_STATELESS)
+ continue;
+
+ if (link->status == DL_STATE_CONSUMER_PROBE
+ || link->status == DL_STATE_ACTIVE) {
+ ret = true;
+ break;
+ }
+ WRITE_ONCE(link->status, DL_STATE_SUPPLIER_UNBIND);
+ }
+
+ dev->links.status = DL_DEV_UNBINDING;
+
+ device_links_write_unlock();
+ return ret;
+}
+
+/**
+ * device_links_unbind_consumers - Force unbind consumers of the given device.
+ * @dev: Device to unbind the consumers of.
+ *
+ * Walk the list of links to consumers for @dev and if any of them is in the
+ * "consumer probe" state, wait for all device probes in progress to complete
+ * and start over.
+ *
+ * If that's not the case, change the status of the link to "supplier unbind"
+ * and check if the link was in the "active" state. If so, force the consumer
+ * driver to unbind and start over (the consumer will not re-probe as we have
+ * changed the state of the link already).
+ *
+ * Links with the DL_FLAG_STATELESS flag set are ignored.
+ */
+void device_links_unbind_consumers(struct device *dev)
+{
+ struct device_link *link;
+
+ start:
+ device_links_write_lock();
+
+ list_for_each_entry(link, &dev->links.consumers, s_node) {
+ enum device_link_state status;
+
+ if (link->flags & DL_FLAG_STATELESS)
+ continue;
+
+ status = link->status;
+ if (status == DL_STATE_CONSUMER_PROBE) {
+ device_links_write_unlock();
+
+ wait_for_device_probe();
+ goto start;
+ }
+ WRITE_ONCE(link->status, DL_STATE_SUPPLIER_UNBIND);
+ if (status == DL_STATE_ACTIVE) {
+ struct device *consumer = link->consumer;
+
+ get_device(consumer);
+
+ device_links_write_unlock();
+
+ device_release_driver_internal(consumer, NULL,
+ consumer->parent);
+ put_device(consumer);
+ goto start;
+ }
+ }
+
+ device_links_write_unlock();
+}
+
+/**
+ * device_links_purge - Delete existing links to other devices.
+ * @dev: Target device.
+ */
+static void device_links_purge(struct device *dev)
+{
+ struct device_link *link, *ln;
+
+ /*
+ * Delete all of the remaining links from this device to any other
+ * devices (either consumers or suppliers).
+ */
+ device_links_write_lock();
+
+ list_for_each_entry_safe_reverse(link, ln, &dev->links.suppliers, c_node) {
+ WARN_ON(link->status == DL_STATE_ACTIVE);
+ __device_link_del(link);
+ }
+
+ list_for_each_entry_safe_reverse(link, ln, &dev->links.consumers, s_node) {
+ WARN_ON(link->status != DL_STATE_DORMANT &&
+ link->status != DL_STATE_NONE);
+ __device_link_del(link);
+ }
+
+ device_links_write_unlock();
+}
+
+/* Device links support end. */
+
int (*platform_notify)(struct device *dev) = NULL;
int (*platform_notify_remove)(struct device *dev) = NULL;
static struct kobject *dev_kobj;
@@ -711,6 +1246,9 @@ void device_initialize(struct device *dev)
#ifdef CONFIG_GENERIC_MSI_IRQ
INIT_LIST_HEAD(&dev->msi_list);
#endif
+ INIT_LIST_HEAD(&dev->links.consumers);
+ INIT_LIST_HEAD(&dev->links.suppliers);
+ dev->links.status = DL_DEV_NO_DRIVER;
}
EXPORT_SYMBOL_GPL(device_initialize);
@@ -1263,6 +1801,8 @@ void device_del(struct device *dev)
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_DEL_DEVICE, dev);
+
+ device_links_purge(dev);
dpm_sysfs_remove(dev);
if (parent)
klist_del(&dev->p->knode_parent);
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index ee25a69630c3..dbf92e3272f9 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -244,6 +244,7 @@ static void driver_bound(struct device *dev)
__func__, dev_name(dev));
klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
+ device_links_driver_bound(dev);
device_pm_check_callbacks(dev);
@@ -338,6 +339,10 @@ static int really_probe(struct device *dev, struct device_driver *drv)
return ret;
}
+ ret = device_links_check_suppliers(dev);
+ if (ret)
+ return ret;
+
atomic_inc(&probe_count);
pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
drv->bus->name, __func__, drv->name, dev_name(dev));
@@ -408,6 +413,7 @@ probe_failed:
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
pinctrl_bind_failed:
+ device_links_no_driver(dev);
devres_release_all(dev);
driver_sysfs_remove(dev);
dev->driver = NULL;
@@ -764,7 +770,7 @@ EXPORT_SYMBOL_GPL(driver_attach);
* __device_release_driver() must be called with @dev lock held.
* When called for a USB interface, @dev->parent lock must be held as well.
*/
-static void __device_release_driver(struct device *dev)
+static void __device_release_driver(struct device *dev, struct device *parent)
{
struct device_driver *drv;
@@ -773,6 +779,25 @@ static void __device_release_driver(struct device *dev)
if (driver_allows_async_probing(drv))
async_synchronize_full();
+ while (device_links_busy(dev)) {
+ device_unlock(dev);
+ if (parent)
+ device_unlock(parent);
+
+ device_links_unbind_consumers(dev);
+ if (parent)
+ device_lock(parent);
+
+ device_lock(dev);
+ /*
+ * A concurrent invocation of the same function might
+ * have released the driver successfully while this one
+ * was waiting, so check for that.
+ */
+ if (dev->driver != drv)
+ return;
+ }
+
pm_runtime_get_sync(dev);
driver_sysfs_remove(dev);
@@ -788,6 +813,8 @@ static void __device_release_driver(struct device *dev)
dev->bus->remove(dev);
else if (drv->remove)
drv->remove(dev);
+
+ device_links_driver_cleanup(dev);
devres_release_all(dev);
dev->driver = NULL;
dev_set_drvdata(dev, NULL);
@@ -804,12 +831,32 @@ static void __device_release_driver(struct device *dev)
}
}
+void device_release_driver_internal(struct device *dev,
+ struct device_driver *drv,
+ struct device *parent)
+{
+ if (parent)
+ device_lock(parent);
+
+ device_lock(dev);
+ if (!drv || drv == dev->driver)
+ __device_release_driver(dev, parent);
+
+ device_unlock(dev);
+ if (parent)
+ device_unlock(parent);
+}
+
/**
* device_release_driver - manually detach device from driver.
* @dev: device.
*
* Manually detach device from driver.
* When called for a USB interface, @dev->parent lock must be held.
+ *
+ * If this function is to be called with @dev->parent lock held, ensure that
+ * the device's consumers are unbound in advance or that their locks can be
+ * acquired under the @dev->parent lock.
*/
void device_release_driver(struct device *dev)
{
@@ -818,9 +865,7 @@ void device_release_driver(struct device *dev)
* within their ->remove callback for the same device, they
* will deadlock right here.
*/
- device_lock(dev);
- __device_release_driver(dev);
- device_unlock(dev);
+ device_release_driver_internal(dev, NULL, NULL);
}
EXPORT_SYMBOL_GPL(device_release_driver);
@@ -845,15 +890,7 @@ void driver_detach(struct device_driver *drv)
dev = dev_prv->device;
get_device(dev);
spin_unlock(&drv->p->klist_devices.k_lock);
-
- if (dev->parent) /* Needed for USB */
- device_lock(dev->parent);
- device_lock(dev);
- if (dev->driver == drv)
- __device_release_driver(dev);
- device_unlock(dev);
- if (dev->parent)
- device_unlock(dev->parent);
+ device_release_driver_internal(dev, drv, dev->parent);
put_device(dev);
}
}
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index a95e1e572697..9a075ff33a52 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -1173,7 +1173,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
ret = fw_get_filesystem_firmware(device, fw->priv);
if (ret) {
if (!(opt_flags & FW_OPT_NO_WARN))
- dev_warn(device,
+ dev_dbg(device,
"Direct firmware load for %s failed with error %d\n",
name, ret);
if (opt_flags & FW_OPT_USERHELPER) {
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 8c7d0f33bd53..9c3e535795a0 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -112,6 +112,9 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed)
if (!genpd->power_on)
return 0;
+ pr_debug("%s: Power-%s (idle state %d timed %s)\n", genpd->name, "on",
+ state_idx, timed ? "true" : "false");
+
if (!timed)
return genpd->power_on(genpd);
@@ -142,6 +145,9 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
if (!genpd->power_off)
return 0;
+ pr_debug("%s: Power-%s (idle state %d timed %s)\n", genpd->name, "off",
+ state_idx, timed ? "true" : "false");
+
if (!timed)
return genpd->power_off(genpd);
@@ -313,6 +319,13 @@ static int genpd_poweroff(struct generic_pm_domain *genpd, bool is_async)
if (genpd->gov && genpd->gov->power_down_ok) {
if (!genpd->gov->power_down_ok(&genpd->domain))
return -EAGAIN;
+ } else {
+ /*
+ * if no valid state idx specified by governor, we use
+ * the default state_idx 0 to enter in case the domain
+ * has multi low power states.
+ */
+ genpd->state_idx = 0;
}
if (genpd->power_off) {
@@ -321,6 +334,10 @@ static int genpd_poweroff(struct generic_pm_domain *genpd, bool is_async)
if (atomic_read(&genpd->sd_count) > 0)
return -EBUSY;
+ if (!genpd->device_count)
+ /* Choose the deepest state if no devices using this domain */
+ genpd->state_idx = genpd->state_count - 1;
+
/*
* If sd_count > 0 at this point, one of the subdomains hasn't
* managed to call genpd_poweron() for the master yet after
@@ -632,7 +649,17 @@ static void genpd_sync_poweroff(struct generic_pm_domain *genpd)
{
struct gpd_link *link;
- if (genpd->status == GPD_STATE_POWER_OFF)
+ /*
+ * Give the power domain a chance to switch to the deepest state in
+ * case it's already off but in an intermediate low power state.
+ * Due to power domain is alway off, so no need to check device wakeup
+ * here anymore
+ */
+
+ genpd->state_idx_saved = genpd->state_idx;
+
+ if (genpd->status == GPD_STATE_POWER_OFF &&
+ genpd->state_idx == (genpd->state_count - 1))
return;
if (genpd->suspended_count != genpd->device_count
@@ -643,6 +670,9 @@ static void genpd_sync_poweroff(struct generic_pm_domain *genpd)
genpd->state_idx = genpd->state_count - 1;
genpd_power_off(genpd, false);
+ if (genpd->status == GPD_STATE_POWER_OFF)
+ return;
+
genpd->status = GPD_STATE_POWER_OFF;
list_for_each_entry(link, &genpd->slave_links, slave_node) {
@@ -674,6 +704,8 @@ static void genpd_sync_poweron(struct generic_pm_domain *genpd)
genpd_power_on(genpd, false);
+ /* restore save power domain state after resume */
+ genpd->state_idx = genpd->state_idx_saved;
genpd->status = GPD_STATE_ACTIVE;
}
@@ -772,6 +804,8 @@ static int pm_genpd_suspend_noirq(struct device *dev)
if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
return 0;
+ pm_generic_suspend_noirq(dev);
+
if (genpd->dev_ops.stop && genpd->dev_ops.start) {
ret = pm_runtime_force_suspend(dev);
if (ret)
@@ -820,6 +854,8 @@ static int pm_genpd_resume_noirq(struct device *dev)
if (genpd->dev_ops.stop && genpd->dev_ops.start)
ret = pm_runtime_force_resume(dev);
+ pm_generic_resume_noirq(dev);
+
return ret;
}
@@ -1645,7 +1681,7 @@ EXPORT_SYMBOL_GPL(of_genpd_del_provider);
* Returns a valid pointer to struct generic_pm_domain on success or ERR_PTR()
* on failure.
*/
-static struct generic_pm_domain *genpd_get_from_provider(
+struct generic_pm_domain *genpd_get_from_provider(
struct of_phandle_args *genpdspec)
{
struct generic_pm_domain *genpd = ERR_PTR(-ENOENT);
@@ -1668,6 +1704,7 @@ static struct generic_pm_domain *genpd_get_from_provider(
return genpd;
}
+EXPORT_SYMBOL_GPL(genpd_get_from_provider);
/**
* of_genpd_add_device() - Add a device to an I/O PM domain
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index dfffba39f723..762c39ec7ba7 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -131,6 +131,7 @@ void device_pm_add(struct device *dev)
dev_warn(dev, "parent %s should not be sleeping\n",
dev_name(dev->parent));
list_add_tail(&dev->power.entry, &dpm_list);
+ dev->power.in_dpm_list = true;
mutex_unlock(&dpm_list_mtx);
}
@@ -145,6 +146,7 @@ void device_pm_remove(struct device *dev)
complete_all(&dev->power.completion);
mutex_lock(&dpm_list_mtx);
list_del_init(&dev->power.entry);
+ dev->power.in_dpm_list = false;
mutex_unlock(&dpm_list_mtx);
device_wakeup_disable(dev);
pm_runtime_remove(dev);
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index a84332aefc2d..a46e97e515c5 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -144,6 +144,11 @@ extern void device_pm_move_after(struct device *, struct device *);
extern void device_pm_move_last(struct device *);
extern void device_pm_check_callbacks(struct device *dev);
+static inline bool device_pm_initialized(struct device *dev)
+{
+ return dev->power.in_dpm_list;
+}
+
#else /* !CONFIG_PM_SLEEP */
static inline void device_pm_sleep_init(struct device *dev) {}
@@ -163,6 +168,11 @@ static inline void device_pm_move_last(struct device *dev) {}
static inline void device_pm_check_callbacks(struct device *dev) {}
+static inline bool device_pm_initialized(struct device *dev)
+{
+ return device_is_registered(dev);
+}
+
#endif /* !CONFIG_PM_SLEEP */
static inline void device_pm_init(struct device *dev)
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 147d2e3678aa..626c6eadec9e 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1479,6 +1479,16 @@ int pm_runtime_force_suspend(struct device *dev)
if (ret)
goto err;
+ /*
+ * Increase the runtime PM usage count for the device's parent, in case
+ * when we find the device being used when system suspend was invoked.
+ * This informs pm_runtime_force_resume() to resume the parent
+ * immediately, which is needed to be able to resume its children,
+ * when not deferring the resume to be managed via runtime PM.
+ */
+ if (dev->parent && atomic_read(&dev->power.usage_count) > 1)
+ pm_runtime_get_noresume(dev->parent);
+
pm_runtime_set_suspended(dev);
return 0;
err:
@@ -1488,16 +1498,20 @@ err:
EXPORT_SYMBOL_GPL(pm_runtime_force_suspend);
/**
- * pm_runtime_force_resume - Force a device into resume state.
+ * pm_runtime_force_resume - Force a device into resume state if needed.
* @dev: Device to resume.
*
* Prior invoking this function we expect the user to have brought the device
* into low power state by a call to pm_runtime_force_suspend(). Here we reverse
- * those actions and brings the device into full power. We update the runtime PM
- * status and re-enables runtime PM.
+ * those actions and brings the device into full power, if it is expected to be
+ * used on system resume. To distinguish that, we check whether the runtime PM
+ * usage count is greater than 1 (the PM core increases the usage count in the
+ * system PM prepare phase), as that indicates a real user (such as a subsystem,
+ * driver, userspace, etc.) is using it. If that is the case, the device is
+ * expected to be used on system resume as well, so then we resume it. In the
+ * other case, we defer the resume to be managed via runtime PM.
*
- * Typically this function may be invoked from a system resume callback to make
- * sure the device is put into full power state.
+ * Typically this function may be invoked from a system resume callback.
*/
int pm_runtime_force_resume(struct device *dev)
{
@@ -1514,6 +1528,17 @@ int pm_runtime_force_resume(struct device *dev)
if (!pm_runtime_status_suspended(dev))
goto out;
+ /*
+ * Decrease the parent's runtime PM usage count, if we increased it
+ * during system suspend in pm_runtime_force_suspend().
+ */
+ if (atomic_read(&dev->power.usage_count) > 1) {
+ if (dev->parent)
+ pm_runtime_put_noidle(dev->parent);
+ } else {
+ goto out;
+ }
+
ret = pm_runtime_set_active(dev);
if (ret)
goto out;
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index 5189fd6182f6..400a297d2490 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -305,19 +305,15 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
goto err_free;
}
- if (clk_id == NULL)
- return ctx;
-
ctx->clk = clk_get(dev, clk_id);
- if (IS_ERR(ctx->clk)) {
- ret = PTR_ERR(ctx->clk);
- goto err_free;
- }
-
- ret = clk_prepare(ctx->clk);
- if (ret < 0) {
- clk_put(ctx->clk);
- goto err_free;
+ if (!IS_ERR(ctx->clk)) {
+ ret = clk_prepare(ctx->clk);
+ if (ret < 0) {
+ clk_put(ctx->clk);
+ goto err_free;
+ }
+ } else {
+ ctx->clk = NULL;
}
return ctx;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 7e4ef0502796..ba69fc6745a4 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -721,7 +721,7 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
rq->timeout = 60*HZ;
if (cgc->quiet)
- rq->cmd_flags |= REQ_QUIET;
+ rq->rq_flags |= RQF_QUIET;
blk_execute_rq(rq->q, pd->bdev->bd_disk, rq, 0);
if (rq->errors)
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 8453a49471d7..e4866ed3c3da 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -91,6 +91,21 @@ config BFIN_OTP_WRITE_ENABLE
If unsure, say N.
+config FSL_OTP
+ tristate "Freescale On-Chip OTP Memory Support"
+ depends on HAS_IOMEM && OF
+ help
+ If you say Y here, you will get support for a character device
+ interface into the One Time Programmable memory pages that are
+ stored on the some Freescale i.MX processors. This will not get
+ you access to the secure memory pages however. You will need to
+ write your own secure code and reader for that.
+
+ To compile this driver as a module, choose M here: the module
+ will be called fsl_otp.
+
+ If unsure, it is safe to say Y.
+
config PRINTER
tristate "Parallel printer support"
depends on PARPORT
@@ -593,5 +608,6 @@ config TILE_SROM
source "drivers/char/xillybus/Kconfig"
+source "drivers/char/imx_amp/Kconfig"
endmenu
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 6e6c244a66a0..4e34c9357a88 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o
obj-$(CONFIG_IBM_BSR) += bsr.o
obj-$(CONFIG_SGI_MBCS) += mbcs.o
obj-$(CONFIG_BFIN_OTP) += bfin-otp.o
+obj-$(CONFIG_FSL_OTP) += fsl_otp.o
obj-$(CONFIG_PRINTER) += lp.o
@@ -60,3 +61,4 @@ js-rtc-y = rtc.o
obj-$(CONFIG_TILE_SROM) += tile-srom.o
obj-$(CONFIG_XILLYBUS) += xillybus/
obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o
+obj-$(CONFIG_HAVE_IMX_AMP) += imx_amp/
diff --git a/drivers/char/fsl_otp.c b/drivers/char/fsl_otp.c
new file mode 100644
index 000000000000..ebeb0fc0907d
--- /dev/null
+++ b/drivers/char/fsl_otp.c
@@ -0,0 +1,738 @@
+/*
+ * Freescale On-Chip OTP driver
+ *
+ * Copyright (C) 2010-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#define HW_OCOTP_CTRL 0x00000000
+#define HW_OCOTP_CTRL_SET 0x00000004
+#define BP_OCOTP_CTRL_WR_UNLOCK 16
+#define BM_OCOTP_CTRL_WR_UNLOCK 0xFFFF0000
+#define BM_OCOTP_CTRL_RELOAD_SHADOWS 0x00000400
+#define BM_OCOTP_CTRL_ERROR 0x00000200
+#define BM_OCOTP_CTRL_BUSY 0x00000100
+#define BP_OCOTP_CTRL_ADDR 0
+#define BM_OCOTP_CTRL_ADDR 0x0000007F
+#define BM_OCOTP_CTRL_ADDR_MX7D 0x0000000F
+#define BP_OCOTP_CTRL_ADDR_MX7ULP 0
+#define BM_OCOTP_CTRL_ADDR_MX7ULP 0x000000FF
+
+#define HW_OCOTP_TIMING 0x00000010
+#define BP_OCOTP_TIMING_STROBE_READ 16
+#define BM_OCOTP_TIMING_STROBE_READ 0x003F0000
+#define BP_OCOTP_TIMING_RELAX 12
+#define BM_OCOTP_TIMING_RELAX 0x0000F000
+#define BP_OCOTP_TIMING_STROBE_PROG 0
+#define BM_OCOTP_TIMING_STROBE_PROG 0x00000FFF
+
+#define BP_TIMING_FSOURCE 12
+#define BM_TIMING_FSOURCE 0x0007F000
+#define BV_TIMING_FSOURCE_NS 1001
+#define BP_TIMING_PROG 0
+#define BM_TIMING_PROG 0x00000FFF
+#define BV_TIMING_PROG_US 10
+
+#define HW_OCOTP_DATA 0x00000020
+
+#define HW_OCOTP_DATA0_MX7D 0x00000020
+#define HW_OCOTP_DATA1_MX7D 0x00000030
+#define HW_OCOTP_DATA2_MX7D 0x00000040
+#define HW_OCOTP_DATA3_MX7D 0x00000050
+
+#define HW_OCOTP_PDN_ULP 0x00000010
+#define HW_OCOTP_OUT_STATUS_ULP 0x00000090
+#define HW_OCOTP_OUT_STATUS_CLR_ULP 0x00000098
+
+#define BM_OUT_STATUS_DED_RELOAD_ULP (1 << 20)
+#define BM_OUT_STATUS_SEC_RELOAD_ULP (1 << 19)
+#define BM_OUT_STATUS_PROGFAIL (1 << 12)
+#define BM_OUT_STATUS_LOCKED (1 << 11)
+#define BM_OUT_STATUS_DED_ULP (1 << 10)
+
+#define HW_OCOTP_CUST_N(n) (0x00000400 + (n) * 0x10)
+#define BF(value, field) (((value) << BP_##field) & BM_##field)
+
+#define DEF_RELAX 20 /* > 16.5ns */
+
+#define BANK8(a, b, c, d, e, f, g, h) { \
+ "HW_OCOTP_"#a, "HW_OCOTP_"#b, "HW_OCOTP_"#c, "HW_OCOTP_"#d, \
+ "HW_OCOTP_"#e, "HW_OCOTP_"#f, "HW_OCOTP_"#g, "HW_OCOTP_"#h, \
+}
+
+#define BANK4(a, b, c, d) { \
+ "HW_OCOTP_"#a, "HW_OCOTP_"#b, "HW_OCOTP_"#c, "HW_OCOTP_"#d, \
+}
+
+static const char *imx6q_otp_desc[16][8] = {
+ BANK8(LOCK, CFG0, CFG1, CFG2, CFG3, CFG4, CFG5, CFG6),
+ BANK8(MEM0, MEM1, MEM2, MEM3, MEM4, ANA0, ANA1, ANA2),
+ BANK8(OTPMK0, OTPMK1, OTPMK2, OTPMK3, OTPMK4, OTPMK5, OTPMK6, OTPMK7),
+ BANK8(SRK0, SRK1, SRK2, SRK3, SRK4, SRK5, SRK6, SRK7),
+ BANK8(RESP0, HSJC_RESP1, MAC0, MAC1, HDCP_KSV0, HDCP_KSV1, GP1, GP2),
+ BANK8(DTCP_KEY0, DTCP_KEY1, DTCP_KEY2, DTCP_KEY3, DTCP_KEY4, MISC_CONF, FIELD_RETURN, SRK_REVOKE),
+ BANK8(HDCP_KEY0, HDCP_KEY1, HDCP_KEY2, HDCP_KEY3, HDCP_KEY4, HDCP_KEY5, HDCP_KEY6, HDCP_KEY7),
+ BANK8(HDCP_KEY8, HDCP_KEY9, HDCP_KEY10, HDCP_KEY11, HDCP_KEY12, HDCP_KEY13, HDCP_KEY14, HDCP_KEY15),
+ BANK8(HDCP_KEY16, HDCP_KEY17, HDCP_KEY18, HDCP_KEY19, HDCP_KEY20, HDCP_KEY21, HDCP_KEY22, HDCP_KEY23),
+ BANK8(HDCP_KEY24, HDCP_KEY25, HDCP_KEY26, HDCP_KEY27, HDCP_KEY28, HDCP_KEY29, HDCP_KEY30, HDCP_KEY31),
+ BANK8(HDCP_KEY32, HDCP_KEY33, HDCP_KEY34, HDCP_KEY35, HDCP_KEY36, HDCP_KEY37, HDCP_KEY38, HDCP_KEY39),
+ BANK8(HDCP_KEY40, HDCP_KEY41, HDCP_KEY42, HDCP_KEY43, HDCP_KEY44, HDCP_KEY45, HDCP_KEY46, HDCP_KEY47),
+ BANK8(HDCP_KEY48, HDCP_KEY49, HDCP_KEY50, HDCP_KEY51, HDCP_KEY52, HDCP_KEY53, HDCP_KEY54, HDCP_KEY55),
+ BANK8(HDCP_KEY56, HDCP_KEY57, HDCP_KEY58, HDCP_KEY59, HDCP_KEY60, HDCP_KEY61, HDCP_KEY62, HDCP_KEY63),
+ BANK8(HDCP_KEY64, HDCP_KEY65, HDCP_KEY66, HDCP_KEY67, HDCP_KEY68, HDCP_KEY69, HDCP_KEY70, HDCP_KEY71),
+ BANK8(CRC0, CRC1, CRC2, CRC3, CRC4, CRC5, CRC6, CRC7),
+};
+
+static const char *imx6sl_otp_desc[][8] = {
+ BANK8(LOCK, CFG0, CFG1, CFG2, CFG3, CFG4, CFG5, CFG6),
+ BANK8(MEM0, MEM1, MEM2, MEM3, MEM4, ANA0, ANA1, ANA2),
+ BANK8(OTPMK0, OTPMK1, OTPMK2, OTPMK3, OTPMK4, OTPMK5, OTPMK6, OTPMK7),
+ BANK8(SRK0, SRK1, SRK2, SRK3, SRK4, SRK5, SRK6, SRK7),
+ BANK8(SJC_RESP0, SJC_RESP1, MAC0, MAC1, CRC0, CRC1, GP1, GP2),
+ BANK8(SW_GP0, SW_GP1, SW_GP2, SW_GP3, SW_GP4, MISC_CONF, FIELD_RETURN, SRK_REVOKE),
+ BANK8(GP_LO0, GP_LO1, GP_LO2, GP_LO3, GP_LO4, GP_LO5, GP_LO6, GP_LO7),
+ BANK8(GP_HI0, GP_HI1, GP_HI2, GP_HI3, GP_HI4, GP_HI5, GP_HI6, GP_HI7),
+};
+
+static const char *imx6sll_otp_desc[][8] = {
+ BANK8(LOCK, CFG0, CFG1, CFG2, CFG3, CFG4, CFG5, CFG6),
+ BANK8(MEM0, MEM1, MEM2, MEM3, MEM4, ANA0, ANA1, USB),
+ BANK8(OTPMK0, OTPMK1, OTPMK2, OTPMK3, OTPMK4, OTPMK5, OTPMK6, OTPMK7),
+ BANK8(SRK0, SRK1, SRK2, SRK3, SRK4, SRK5, SRK6, SRK7),
+ BANK8(SJC_RESP0, SJC_RESP1, MAC0, MAC1, MAC2, CRC0, GP1, GP2),
+ BANK8(SW_GP0, SW_GP1, SW_GP2, SW_GP3, SW_GP4, MISC_CONF, FIELD_RETURN, SRK_REVOKE),
+ BANK8(ROM_PATCH0, ROM_PATCH1, ROM_PATCH2, ROM_PATCH3, ROM_PATCH4, ROM_PATCH5, ROM_PATCH6, ROM_PATCH7),
+ BANK8(GP30, GP31, GP32, GP33, GP40, GP41, GP42, GP43),
+};
+
+static const char *imx6ul_otp_desc[][8] = {
+ BANK8(LOCK, CFG0, CFG1, CFG2, CFG3, CFG4, CFG5, CFG6),
+ BANK8(MEM0, MEM1, MEM2, MEM3, MEM4, ANA0, ANA1, ANA2),
+ BANK8(OTPMK0, OTPMK1, OTPMK2, OTPMK3, OTPMK4, OTPMK5, OTPMK6, OTPMK7),
+ BANK8(SRK0, SRK1, SRK2, SRK3, SRK4, SRK5, SRK6, SRK7),
+ BANK8(SJC_RESP0, SJC_RESP1, MAC0, MAC1, MAC2, CRC, GP1, GP2),
+ BANK8(SW_GP0, SW_GP1, SW_GP2, SW_GP3, SW_GP4, MISC_CONF, FIELD_RETURN, SRK_REVOKE),
+ BANK8(ROM_PATCH0, ROM_PATCH1, ROM_PATCH2, ROM_PATCH3, ROM_PATCH4, ROM_PATCH5, ROM_PATCH6, ROM_PATCH7),
+ BANK8(ROM_PATCH8, ROM_PATCH9, ROM_PATCH10, ROM_PATCH11, ROM_PATCH12, ROM_PATCH13, ROM_PATCH14, ROM_PATCH15),
+ BANK8(GP30, GP31, GP32, GP33, GP34, GP35, GP36, GP37),
+ BANK8(GP38, GP39, GP310, GP311, GP312, GP313, GP314, GP315),
+ BANK8(GP40, GP41, GP42, GP43, GP44, GP45, GP46, GP47),
+ BANK8(GP48, GP49, GP410, GP411, GP412, GP413, GP414, GP415),
+ BANK8(GP50, GP51, GP52, GP53, GP54, GP55, GP56, GP57),
+ BANK8(GP58, GP59, GP510, GP511, GP512, GP513, GP514, GP515),
+ BANK8(GP60, GP61, GP62, GP63, GP64, GP65, GP66, GP67),
+ BANK8(GP70, GP71, GP72, GP73, GP80, GP81, GP82, GP83),
+};
+
+static const char *imx6ull_otp_desc[][8] = {
+ BANK8(LOCK, CFG0, CFG1, CFG2, CFG3, CFG4, CFG5, CFG6),
+ BANK8(MEM0, MEM1, MEM2, MEM3, MEM4, ANA0, ANA1, ANA2),
+ BANK8(OTPMK0, OTPMK1, OTPMK2, OTPMK3, OTPMK4, OTPMK5, OTPMK6, OTPMK7),
+ BANK8(SRK0, SRK1, SRK2, SRK3, SRK4, SRK5, SRK6, SRK7),
+ BANK8(SJC_RESP0, SJC_RESP1, MAC0, MAC1, MAC2, CRC, GP1, GP2),
+ BANK8(SW_GP0, SW_GP1, SW_GP2, SW_GP3, SW_GP4, MISC_CONF, FIELD_RETURN, SRK_REVOKE),
+ BANK8(ROM_PATCH0, ROM_PATCH1, ROM_PATCH2, ROM_PATCH3, ROM_PATCH4, ROM_PATCH5, ROM_PATCH6, ROM_PATCH7),
+ BANK8(GP30, GP31, GP32, GP33, GP40, GP41, GP42, GP43),
+};
+
+static const char *imx7d_otp_desc[][4] = {
+ BANK4(LOCK, TESTER0, TESTER1, TESTER2),
+ BANK4(TESTER3, TESTER4, TESTER5, BOOT_CFG0),
+ BANK4(BOOT_CFG1, BOOT_CFG2, BOOT_CFG3, BOOT_CFG4),
+ BANK4(MEM_TRIM0, MEM_TRIM1, ANA0, ANA1),
+ BANK4(OTPMK0, OTPMK1, OTPMK2, OTPMK3),
+ BANK4(OTPMK4, OTPMK5, OTPMK6, OTPMK7),
+ BANK4(SRK0, SRK1, SRK2, SRK3),
+ BANK4(SRK4, SRK5, SRK6, SRK7),
+ BANK4(SJC_RESP0, SJC_RESP1, USB_ID, FIELD_RETURN),
+ BANK4(MAC_ADDR0, MAC_ADDR1, MAC_ADDR2, SRK_REVOKE),
+ BANK4(MAU_KEY0, MAU_KEY1, MAU_KEY2, MAU_KEY3),
+ BANK4(MAU_KEY4, MAU_KEY5, MAU_KEY6, MAU_KEY7),
+ BANK4(ROM_PATCH0, ROM_PATCH1, ROM_PATCH2, ROM_PATCH3),
+ BANK4(ROM_PATCH4, ROM_PATCH5, ROM_PATCH6, ROM_PATCH7),
+ BANK4(GP10, GP11, GP20, GP21),
+ BANK4(CRC_GP10, CRC_GP11, CRC_GP20, CRC_GP21),
+};
+
+static const char *imx7ulp_otp_desc[][8] = {
+ BANK8(TESTER0, TESTER1, TESTER2, TESTER3, TESTER4, TESTER5, TESTER6, TESTER7),
+ BANK8(LOCK0, LOCK1, LOCK2, CFG0, CFG1, CFG2, CFG3, CFG4),
+ BANK8(BOOT0, BOOT1, BOOT2, BOOT3, BOOT4, BOOT5, BOOT6, BOOT7),
+ BANK8(MEM0, MEM1, MEM2, MEM3, ANA0, ANA1, ANA2, ANA3),
+ BANK8(OTPMK0, OTPMK1, OTPMK2, OTPMK3, OTPMK4, OTPMK5, OTPMK6, OTPMK7),
+ BANK8(A7_SRK0, A7_SRK1, A7_SRK2, A7_SRK3, A7_SRK4, A7_SRK5, A7_SRK6, A7_SRK7),
+ BANK8(M4_SRK0, M4_SRK1, M4_SRK2, M4_SRK3, M4_SRK4, M4_SRK5, M4_SRK6, M4_SRK7),
+ BANK8(SJC_RESP0, SJC_RESP1, GP0, GP1, GP2, GP3, GP4, GP5),
+ BANK8(MAU_KEY0, MAU_KEY1, MAU_KEY2, MAU_KEY3, MAU_KEY4, MAU_KEY5, MAU_KEY6, MAU_KEY7),
+ BANK8(TESTER10, TESTER11, TESTER12, TESTER13, TESTER14, TESTER15, FIELD_RETURN, SRK_REVOKE),
+ BANK8(PMU0, PMU1, PMU2, PMU3, PMU4, PMU5, PMU6, PMU7),
+ BANK8(A7_PATCH0, A7_PATCH1, A7_PATCH2, A7_PATCH3, A7_PATCH4, A7_PATCH5, A7_PATCH6, A7_PATCH7),
+ BANK8(A7_PATCH10, A7_PATCH11, A7_PATCH12, A7_PATCH13, A7_PATCH14, A7_PATCH15, A7_PATCH16, A7_PATCH17),
+ BANK8(A7_PATCH20, A7_PATCH21, A7_PATCH22, A7_PATCH23, A7_PATCH24, A7_PATCH25, A7_PATCH26, A7_PATCH27),
+ BANK8(A7_PATCH30, A7_PATCH31, A7_PATCH32, A7_PATCH33, A7_PATCH34, A7_PATCH35, A7_PATCH36, A7_PATCH37),
+ BANK8(GP10, GP11, GP12, GP13, GP14, GP15, GP16, GP17),
+ BANK8(GP20, GP21, GP22, GP23, GP24, GP25, GP26, GP27),
+ BANK8(GP30, GP31, GP32, GP33, GP34, GP35, GP36, GP37),
+ BANK8(GP40, GP41, GP42, GP43, GP44, GP45, GP46, GP47),
+ BANK8(GP50, GP51, GP52, GP53, GP54, GP55, GP56, GP57),
+ BANK8(M4_PATCH0, M4_PATCH1, M4_PATCH2, M4_PATCH3, M4_PATCH4, M4_PATCH5, M4_PATCH6, M4_PATCH7),
+ BANK8(M4_PATCH10, M4_PATCH11, M4_PATCH12, M4_PATCH13, M4_PATCH14, M4_PATCH15, M4_PATCH16, M4_PATCH17),
+ BANK8(M4_PATCH20, M4_PATCH21, M4_PATCH22, M4_PATCH23, M4_PATCH24, M4_PATCH25, M4_PATCH26, M4_PATCH27),
+ BANK8(M4_PATCH30, M4_PATCH31, M4_PATCH32, M4_PATCH33, M4_PATCH34, M4_PATCH35, M4_PATCH36, M4_PATCH37),
+ BANK8(GP60, GP61, GP62, GP63, GP64, GP65, GP66, GP67),
+ BANK8(GP70, GP71, GP72, GP73, GP74, GP75, GP76, GP77),
+ BANK8(GP80, GP81, GP82, GP83, GP84, GP85, GP86, GP87),
+ BANK8(GP90, GP91, GP92, GP93, GP94, GP95, GP96, GP97),
+ BANK8(TRIM0, TRIM1, TRIM2, TRIM3, TRIM4, TRIM5, TRIM6, TRIM7),
+ BANK8(OTFAD_KEY0, OTFAD_KEY1, OTFAD_KEY2, OTFAD_KEY3, OTFAD_CFG0, OTFAD_CFG1, OTFAD_CFG2, OTFAD_CFG3),
+ BANK8(CRC0, CRC1, CRC2, CRC3, CRC4, CRC5, CRC6, CRC7),
+};
+
+static DEFINE_MUTEX(otp_mutex);
+static void __iomem *otp_base;
+static struct clk *otp_clk;
+struct kobject *otp_kobj;
+struct kobj_attribute *otp_kattr;
+struct attribute_group *otp_attr_group;
+
+enum fsl_otp_devtype {
+ FSL_OTP_MX6Q,
+ FSL_OTP_MX6DL,
+ FSL_OTP_MX6SX,
+ FSL_OTP_MX6SL,
+ FSL_OTP_MX6SLL,
+ FSL_OTP_MX6UL,
+ FSL_OTP_MX6ULL,
+ FSL_OTP_MX7D,
+ FSL_OTP_MX7ULP,
+};
+
+struct fsl_otp_devtype_data {
+ enum fsl_otp_devtype devtype;
+ const char **bank_desc;
+ int fuse_nums;
+ void (*set_otp_timing)(void);
+};
+
+static struct fsl_otp_devtype_data *fsl_otp;
+
+/*
+ * fsl_otp_bank_physical and fsl_otp_word_physical are used to
+ * find the physical index of the word. Only used for calculating
+ * offset of the word, means only effective when reading fuse.
+ * Do not use the two functions for prog fuse. Always use the word
+ * index from fuse map to prog the fuse.
+ *
+ * Take i.MX6UL for example:
+ * there are holes between bank 5 and bank 6. The hole is 0x100 bytes.
+ * To bank 15, word 7, the word index is 15 * 8 + 7. The physical word
+ * index is 15 * 8 + 0x100 / 0x10 + 7, 0x100 contains 16 words.
+ * So use 15 * 8 + 7 to prog the fuse. And when reading, account the hole
+ * using offset 0x400 + (15 * 8 + 0x100 / 0x10 + 7) * 0x10.
+ *
+ * There is a hole in shadow registers address map of size 0x100
+ * between bank 5 and bank 6 on iMX6QP, iMX6DQ, iMX6SDL, iMX6SX and iMX6UL.
+ * Bank 5 ends at 0x6F0 and Bank 6 starts at 0x800. When reading the fuses,
+ * account for this hole in address space.
+ *
+ * Similar hole exists between bank 14 and bank 15 of size 0x80
+ * on iMX6QP, iMX6DQ, iMX6SDL, i.MX6SLL and iMX6SX.
+ * Note: iMX6SL has only 0-7 banks and there is no hole.
+ * Note: iMX6UL doesn't have this one.
+ *
+ * To i.MX6SLL, there are 9 banks. bank 7 and bank8 only contain 4 words
+ * each. Other banks contains 8 words.
+ */
+static u32 fsl_otp_bank_physical(struct fsl_otp_devtype_data *d, int bank)
+{
+ u32 phy_bank;
+
+ if ((bank == 0) || (d->devtype == FSL_OTP_MX6SL) ||
+ (d->devtype == FSL_OTP_MX7D) || (d->devtype == FSL_OTP_MX7ULP))
+ phy_bank = bank;
+ else if ((d->devtype == FSL_OTP_MX6UL) ||
+ (d->devtype == FSL_OTP_MX6ULL) ||
+ (d->devtype == FSL_OTP_MX6SLL)) {
+ if (bank >= 6)
+ phy_bank = fsl_otp_bank_physical(d, 5) + bank - 3;
+ else
+ phy_bank = bank;
+ } else {
+ if (bank >= 15)
+ phy_bank = fsl_otp_bank_physical(d, 14) + bank - 13;
+ else if (bank >= 6)
+ phy_bank = fsl_otp_bank_physical(d, 5) + bank - 3;
+ else
+ phy_bank = bank;
+ }
+
+ return phy_bank;
+}
+
+static u32 fsl_otp_word_physical(struct fsl_otp_devtype_data *d, int index)
+{
+ u32 phy_bank_off;
+ u32 word_off, bank_off;
+ u32 words_per_bank;
+
+ if (d->devtype == FSL_OTP_MX7D)
+ words_per_bank = 4;
+ else
+ words_per_bank = 8;
+
+ bank_off = index / words_per_bank;
+ word_off = index % words_per_bank;
+ phy_bank_off = fsl_otp_bank_physical(d, bank_off);
+
+ return phy_bank_off * words_per_bank + word_off;
+}
+
+static void imx6_set_otp_timing(void)
+{
+ unsigned long clk_rate = 0;
+ unsigned long strobe_read, relex, strobe_prog;
+ u32 timing = 0;
+
+ clk_rate = clk_get_rate(otp_clk);
+
+ /* do optimization for too many zeros */
+ relex = clk_rate / (1000000000 / DEF_RELAX) - 1;
+ strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1;
+ strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1;
+
+ timing = BF(relex, OCOTP_TIMING_RELAX);
+ timing |= BF(strobe_read, OCOTP_TIMING_STROBE_READ);
+ timing |= BF(strobe_prog, OCOTP_TIMING_STROBE_PROG);
+
+ __raw_writel(timing, otp_base + HW_OCOTP_TIMING);
+}
+
+static void imx7_set_otp_timing(void)
+{
+ unsigned long clk_rate;
+ u32 fsource, prog;
+ u32 timing = 0;
+ u32 reg;
+
+ clk_rate = clk_get_rate(otp_clk);
+
+ fsource = DIV_ROUND_UP((clk_rate / 1000) * BV_TIMING_FSOURCE_NS,
+ 1000000) + 1;
+ prog = DIV_ROUND_CLOSEST(clk_rate * BV_TIMING_PROG_US, 1000000) + 1;
+ timing = BF(fsource, TIMING_FSOURCE) | BF(prog, TIMING_PROG);
+ reg = __raw_readl(otp_base + HW_OCOTP_TIMING);
+ reg &= ~(BM_TIMING_FSOURCE | BM_TIMING_PROG);
+ reg |= timing;
+ __raw_writel(reg, otp_base + HW_OCOTP_TIMING);
+}
+
+static void imx7ulp_set_otp_timing(void)
+{
+ /* No need to setup timing for ULP */
+}
+
+static struct fsl_otp_devtype_data imx6q_data = {
+ .devtype = FSL_OTP_MX6Q,
+ .bank_desc = (const char **)imx6q_otp_desc,
+ .fuse_nums = 16 * 8,
+ .set_otp_timing = imx6_set_otp_timing,
+};
+
+static struct fsl_otp_devtype_data imx6sl_data = {
+ .devtype = FSL_OTP_MX6SL,
+ .bank_desc = (const char **)imx6sl_otp_desc,
+ .fuse_nums = 8 * 8,
+ .set_otp_timing = imx6_set_otp_timing,
+};
+
+static struct fsl_otp_devtype_data imx6sll_data = {
+ .devtype = FSL_OTP_MX6SLL,
+ .bank_desc = (const char **)imx6sll_otp_desc,
+ /* Bank 7 and Bank 8 are 4 words each */
+ .fuse_nums = 8 * 8,
+ .set_otp_timing = imx6_set_otp_timing,
+};
+
+static struct fsl_otp_devtype_data imx6ul_data = {
+ .devtype = FSL_OTP_MX6UL,
+ .bank_desc = (const char **)imx6ul_otp_desc,
+ .fuse_nums = 16 * 8,
+ .set_otp_timing = imx6_set_otp_timing,
+};
+
+static struct fsl_otp_devtype_data imx6ull_data = {
+ .devtype = FSL_OTP_MX6ULL,
+ .bank_desc = (const char **)imx6ull_otp_desc,
+ /* Bank 7 and Bank 8 are 4 words each */
+ .fuse_nums = 8 * 8,
+ .set_otp_timing = imx6_set_otp_timing,
+};
+
+static struct fsl_otp_devtype_data imx7d_data = {
+ .devtype = FSL_OTP_MX7D,
+ .bank_desc = (const char **)imx7d_otp_desc,
+ .fuse_nums = 16 * 4,
+ .set_otp_timing = imx7_set_otp_timing,
+};
+
+static struct fsl_otp_devtype_data imx7ulp_data = {
+ .devtype = FSL_OTP_MX7ULP,
+ .bank_desc = (const char **)imx7ulp_otp_desc,
+ .fuse_nums = 31 * 8,
+ .set_otp_timing = imx7ulp_set_otp_timing,
+};
+
+static int otp_wait_busy(u32 flags)
+{
+ int count;
+ u32 c;
+
+ for (count = 10000; count >= 0; count--) {
+ c = __raw_readl(otp_base + HW_OCOTP_CTRL);
+ if (!(c & (BM_OCOTP_CTRL_BUSY | BM_OCOTP_CTRL_ERROR | flags)))
+ break;
+ cpu_relax();
+ }
+
+ if (count < 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static ssize_t fsl_otp_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ unsigned int index = attr - otp_kattr;
+ unsigned int phy_index;
+ u32 value = 0;
+ int ret;
+
+ if (!fsl_otp)
+ return -ENODEV;
+
+ ret = clk_prepare_enable(otp_clk);
+ if (ret)
+ return -ENODEV;
+
+ mutex_lock(&otp_mutex);
+
+ phy_index = fsl_otp_word_physical(fsl_otp, index);
+ fsl_otp->set_otp_timing();
+ ret = otp_wait_busy(0);
+ if (ret)
+ goto out;
+
+ if (fsl_otp->devtype == FSL_OTP_MX7ULP) {
+ value = __raw_readl(otp_base + HW_OCOTP_OUT_STATUS_ULP);
+ if (value & BM_OUT_STATUS_DED_ULP) {
+ __raw_writel(BM_OUT_STATUS_DED_ULP, otp_base + HW_OCOTP_OUT_STATUS_CLR_ULP);
+ goto out;
+ }
+ }
+
+ value = __raw_readl(otp_base + HW_OCOTP_CUST_N(phy_index));
+
+ if (fsl_otp->devtype == FSL_OTP_MX7ULP) {
+ __raw_writel(1, otp_base + HW_OCOTP_PDN_ULP);
+ }
+
+out:
+ mutex_unlock(&otp_mutex);
+ clk_disable_unprepare(otp_clk);
+ return ret ? 0 : sprintf(buf, "0x%x\n", value);
+}
+
+static int imx6_otp_write_bits(int addr, u32 data, u32 magic)
+{
+ u32 c; /* for control register */
+
+ /* init the control register */
+ c = __raw_readl(otp_base + HW_OCOTP_CTRL);
+ c &= ~BM_OCOTP_CTRL_ADDR;
+ c |= BF(addr, OCOTP_CTRL_ADDR);
+ c |= BF(magic, OCOTP_CTRL_WR_UNLOCK);
+ __raw_writel(c, otp_base + HW_OCOTP_CTRL);
+
+ /* init the data register */
+ __raw_writel(data, otp_base + HW_OCOTP_DATA);
+ otp_wait_busy(0);
+
+ mdelay(2); /* Write Postamble */
+
+ return 0;
+}
+
+static int imx7ulp_otp_write_bits(int addr, u32 data, u32 magic)
+{
+ u32 c; /* for control register */
+
+ /* init the control register */
+ c = __raw_readl(otp_base + HW_OCOTP_CTRL);
+ c &= ~BM_OCOTP_CTRL_ADDR_MX7ULP;
+ c |= BF(addr, OCOTP_CTRL_ADDR_MX7ULP);
+ c |= BF(magic, OCOTP_CTRL_WR_UNLOCK);
+ __raw_writel(c, otp_base + HW_OCOTP_CTRL);
+
+ /* init the data register */
+ __raw_writel(data, otp_base + HW_OCOTP_DATA);
+ otp_wait_busy(0);
+
+ mdelay(2); /* Write Postamble */
+
+ return 0;
+}
+
+static int imx7_otp_write_bits(int addr, u32 data, u32 magic)
+{
+ u32 c; /* for control register */
+
+ /* init the control register */
+ c = __raw_readl(otp_base + HW_OCOTP_CTRL);
+ c &= ~BM_OCOTP_CTRL_ADDR_MX7D;
+ /* convert to bank address */
+ c |= BF((addr >> 2), OCOTP_CTRL_ADDR);
+ c |= BF(magic, OCOTP_CTRL_WR_UNLOCK);
+ __raw_writel(c, otp_base + HW_OCOTP_CTRL);
+
+ /* init the data register */
+ switch (addr & 0x3) {
+ case 0:
+ __raw_writel(0, otp_base + HW_OCOTP_DATA1_MX7D);
+ __raw_writel(0, otp_base + HW_OCOTP_DATA2_MX7D);
+ __raw_writel(0, otp_base + HW_OCOTP_DATA3_MX7D);
+ __raw_writel(data, otp_base + HW_OCOTP_DATA0_MX7D);
+ break;
+ case 1:
+ __raw_writel(data, otp_base + HW_OCOTP_DATA1_MX7D);
+ __raw_writel(0, otp_base + HW_OCOTP_DATA2_MX7D);
+ __raw_writel(0, otp_base + HW_OCOTP_DATA3_MX7D);
+ __raw_writel(0, otp_base + HW_OCOTP_DATA0_MX7D);
+ break;
+ case 2:
+ __raw_writel(0, otp_base + HW_OCOTP_DATA1_MX7D);
+ __raw_writel(data, otp_base + HW_OCOTP_DATA2_MX7D);
+ __raw_writel(0, otp_base + HW_OCOTP_DATA3_MX7D);
+ __raw_writel(0, otp_base + HW_OCOTP_DATA0_MX7D);
+ break;
+ case 3:
+ __raw_writel(0, otp_base + HW_OCOTP_DATA1_MX7D);
+ __raw_writel(0, otp_base + HW_OCOTP_DATA2_MX7D);
+ __raw_writel(data, otp_base + HW_OCOTP_DATA3_MX7D);
+ __raw_writel(0, otp_base + HW_OCOTP_DATA0_MX7D);
+ break;
+ }
+ __raw_writel(data, otp_base + HW_OCOTP_DATA);
+ otp_wait_busy(0);
+
+ mdelay(2); /* Write Postamble */
+
+ return 0;
+
+}
+
+static ssize_t fsl_otp_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned int index = attr - otp_kattr;
+ unsigned int phy_index;
+ unsigned long value;
+ unsigned long tmp;
+ int ret;
+
+ if (!fsl_otp)
+ return -ENODEV;
+
+ ret = kstrtoul(buf, 16, &value);
+ if (ret < 0)
+ return -EINVAL;
+
+ ret = clk_prepare_enable(otp_clk);
+ if (ret)
+ return -ENODEV;
+
+ mutex_lock(&otp_mutex);
+
+ phy_index = fsl_otp_word_physical(fsl_otp, index);
+ if ((fsl_otp->devtype == FSL_OTP_MX7ULP) && (phy_index > 15)) {
+ fsl_otp->set_otp_timing();
+ ret = otp_wait_busy(0);
+ if (ret)
+ goto out;
+
+ tmp = __raw_readl(otp_base + HW_OCOTP_OUT_STATUS_ULP);
+ if (tmp & BM_OUT_STATUS_DED_ULP) {
+ __raw_writel(BM_OUT_STATUS_DED_ULP, otp_base + HW_OCOTP_OUT_STATUS_CLR_ULP);
+ goto out;
+ }
+
+ tmp = __raw_readl(otp_base + HW_OCOTP_CUST_N(phy_index));
+
+ __raw_writel(1, otp_base + HW_OCOTP_PDN_ULP);
+
+ if (tmp != 0) {
+ ret = -EPERM;
+ goto out;
+ }
+ }
+
+ fsl_otp->set_otp_timing();
+ ret = otp_wait_busy(0);
+ if (ret)
+ goto out;
+
+ if (fsl_otp->devtype == FSL_OTP_MX7D)
+ imx7_otp_write_bits(index, value, 0x3e77);
+ else if (fsl_otp->devtype == FSL_OTP_MX7ULP)
+ imx7ulp_otp_write_bits(index, value, 0x3e77);
+ else
+ imx6_otp_write_bits(index, value, 0x3e77);
+
+ if (fsl_otp->devtype == FSL_OTP_MX7ULP) {
+ value = __raw_readl(otp_base + HW_OCOTP_OUT_STATUS_ULP);
+ if (value & (BM_OUT_STATUS_LOCKED | BM_OUT_STATUS_PROGFAIL))
+ printk("ulp prog fail\n");
+
+ otp_wait_busy(0);
+ }
+
+ /* Reload all the shadow registers */
+ __raw_writel(BM_OCOTP_CTRL_RELOAD_SHADOWS,
+ otp_base + HW_OCOTP_CTRL_SET);
+ udelay(1);
+ otp_wait_busy(BM_OCOTP_CTRL_RELOAD_SHADOWS);
+
+ if (fsl_otp->devtype == FSL_OTP_MX7ULP) {
+ __raw_writel(1, otp_base + HW_OCOTP_PDN_ULP);
+ }
+
+out:
+ mutex_unlock(&otp_mutex);
+ clk_disable_unprepare(otp_clk);
+ return ret ? ret : count;
+}
+
+static const struct of_device_id fsl_otp_dt_ids[] = {
+ { .compatible = "fsl,imx6q-ocotp", .data = (void *)&imx6q_data, },
+ { .compatible = "fsl,imx6sl-ocotp", .data = (void *)&imx6sl_data, },
+ { .compatible = "fsl,imx6sll-ocotp", .data = (void *)&imx6sll_data, },
+ { .compatible = "fsl,imx6ul-ocotp", .data = (void *)&imx6ul_data, },
+ { .compatible = "fsl,imx6ull-ocotp", .data = (void *)&imx6ull_data, },
+ { .compatible = "fsl,imx7d-ocotp", .data = (void *)&imx7d_data, },
+ { .compatible = "fsl,imx7ulp-ocotp", .data = (void *)&imx7ulp_data, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_otp_dt_ids);
+
+static int fsl_otp_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct attribute **attrs;
+ const char **desc;
+ int i, num;
+ int ret;
+ const struct of_device_id *of_id =
+ of_match_device(fsl_otp_dt_ids, &pdev->dev);
+
+ fsl_otp = (struct fsl_otp_devtype_data *)of_id->data;
+ if (!fsl_otp) {
+ dev_err(&pdev->dev, "No driver data provided!\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ otp_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(otp_base)) {
+ ret = PTR_ERR(otp_base);
+ dev_err(&pdev->dev, "failed to ioremap resource: %d\n", ret);
+ return ret;
+ }
+
+ otp_clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(otp_clk)) {
+ ret = PTR_ERR(otp_clk);
+ dev_err(&pdev->dev, "failed to get clock: %d\n", ret);
+ return ret;
+ }
+
+ desc = fsl_otp->bank_desc;
+ num = fsl_otp->fuse_nums;
+
+ /* The last one is NULL, which is used to detect the end */
+ attrs = devm_kzalloc(&pdev->dev, (num + 1) * sizeof(*attrs),
+ GFP_KERNEL);
+ otp_kattr = devm_kzalloc(&pdev->dev, num * sizeof(*otp_kattr),
+ GFP_KERNEL);
+ otp_attr_group = devm_kzalloc(&pdev->dev, sizeof(*otp_attr_group),
+ GFP_KERNEL);
+ if (!attrs || !otp_kattr || !otp_attr_group)
+ return -ENOMEM;
+
+ for (i = 0; i < num; i++) {
+ sysfs_attr_init(&otp_kattr[i].attr);
+ otp_kattr[i].attr.name = desc[i];
+ otp_kattr[i].attr.mode = 0600;
+ otp_kattr[i].show = fsl_otp_show;
+ otp_kattr[i].store = fsl_otp_store;
+ attrs[i] = &otp_kattr[i].attr;
+ }
+ otp_attr_group->attrs = attrs;
+
+ otp_kobj = kobject_create_and_add("fsl_otp", NULL);
+ if (!otp_kobj) {
+ dev_err(&pdev->dev, "failed to add kobject\n");
+ return -ENOMEM;
+ }
+
+ ret = sysfs_create_group(otp_kobj, otp_attr_group);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to create sysfs group: %d\n", ret);
+ kobject_put(otp_kobj);
+ return ret;
+ }
+
+ mutex_init(&otp_mutex);
+
+ return 0;
+}
+
+static int fsl_otp_remove(struct platform_device *pdev)
+{
+ sysfs_remove_group(otp_kobj, otp_attr_group);
+ kobject_put(otp_kobj);
+
+ return 0;
+}
+
+static struct platform_driver fsl_otp_driver = {
+ .driver = {
+ .name = "imx-ocotp",
+ .owner = THIS_MODULE,
+ .of_match_table = fsl_otp_dt_ids,
+ },
+ .probe = fsl_otp_probe,
+ .remove = fsl_otp_remove,
+};
+module_platform_driver(fsl_otp_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Huang Shijie <b32955@freescale.com>");
+MODULE_DESCRIPTION("Freescale i.MX OCOTP driver");
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 200dab5136a7..7969d2f36a14 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -255,6 +255,18 @@ config HW_RANDOM_MXC_RNGA
If unsure, say Y.
+config HW_RANDOM_IMX_RNG
+ tristate "Freescale RNG B/C Random Number Generator"
+ depends on HW_RANDOM && ARCH_MXC && HAVE_IMX_RNG
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator (RNGBB and RNGC) hardware found on Freescale i.MX processors.
+
+ To compile this driver as a module, choose M here: the
+ module will be called fsl-rngc.
+
+ If unsure, say Y.
+
config HW_RANDOM_NOMADIK
tristate "ST-Ericsson Nomadik Random Number Generator support"
depends on ARCH_NOMADIK
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index 5f52b1e4e7be..d9d76206788e 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o
obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
+obj-$(CONFIG_HW_RANDOM_IMX_RNG) += imx-rng.o
obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
diff --git a/drivers/char/hw_random/imx-rng.c b/drivers/char/hw_random/imx-rng.c
new file mode 100644
index 000000000000..df9c13f7d325
--- /dev/null
+++ b/drivers/char/hw_random/imx-rng.c
@@ -0,0 +1,440 @@
+/*
+ * RNG driver for Freescale RNG B/C
+ *
+ * Copyright (C) 2008-2015 Freescale Semiconductor, Inc.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
+ * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for the AMD 768 Random Number Generator (RNG)
+ * (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for Intel i810 Random Number Generator (RNG)
+ * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/interrupt.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#define MODULE_NAME "imx-rng"
+
+#define RNGC_VERSION_MAJOR3 3
+
+#define RNGC_VERSION_ID 0x0000
+#define RNGC_COMMAND 0x0004
+#define RNGC_CONTROL 0x0008
+#define RNGC_STATUS 0x000C
+#define RNGC_ERROR 0x0010
+#define RNGC_FIFO 0x0014
+#define RNGC_VERIF_CTRL 0x0020
+#define RNGC_OSC_CTRL_COUNT 0x0028
+#define RNGC_OSC_COUNT 0x002C
+#define RNGC_OSC_COUNT_STATUS 0x0030
+
+#define RNGC_VERID_ZEROS_MASK 0x0f000000
+#define RNGC_VERID_RNG_TYPE_MASK 0xf0000000
+#define RNGC_VERID_RNG_TYPE_SHIFT 28
+#define RNGC_VERID_CHIP_VERSION_MASK 0x00ff0000
+#define RNGC_VERID_CHIP_VERSION_SHIFT 16
+#define RNGC_VERID_VERSION_MAJOR_MASK 0x0000ff00
+#define RNGC_VERID_VERSION_MAJOR_SHIFT 8
+#define RNGC_VERID_VERSION_MINOR_MASK 0x000000ff
+#define RNGC_VERID_VERSION_MINOR_SHIFT 0
+
+#define RNGC_CMD_ZEROS_MASK 0xffffff8c
+#define RNGC_CMD_SW_RST 0x00000040
+#define RNGC_CMD_CLR_ERR 0x00000020
+#define RNGC_CMD_CLR_INT 0x00000010
+#define RNGC_CMD_SEED 0x00000002
+#define RNGC_CMD_SELF_TEST 0x00000001
+
+#define RNGC_CTRL_ZEROS_MASK 0xfffffc8c
+#define RNGC_CTRL_CTL_ACC 0x00000200
+#define RNGC_CTRL_VERIF_MODE 0x00000100
+#define RNGC_CTRL_MASK_ERROR 0x00000040
+
+#define RNGC_CTRL_MASK_DONE 0x00000020
+#define RNGC_CTRL_AUTO_SEED 0x00000010
+#define RNGC_CTRL_FIFO_UFLOW_MASK 0x00000003
+#define RNGC_CTRL_FIFO_UFLOW_SHIFT 0
+
+#define RNGC_CTRL_FIFO_UFLOW_ZEROS_ERROR 0
+#define RNGC_CTRL_FIFO_UFLOW_ZEROS_ERROR2 1
+#define RNGC_CTRL_FIFO_UFLOW_BUS_XFR 2
+#define RNGC_CTRL_FIFO_UFLOW_ZEROS_INTR 3
+
+#define RNGC_STATUS_ST_PF_MASK 0x00c00000
+#define RNGC_STATUS_ST_PF_SHIFT 22
+#define RNGC_STATUS_ST_PF_TRNG 0x00800000
+#define RNGC_STATUS_ST_PF_PRNG 0x00400000
+#define RNGC_STATUS_ERROR 0x00010000
+#define RNGC_STATUS_FIFO_SIZE_MASK 0x0000f000
+#define RNGC_STATUS_FIFO_SIZE_SHIFT 12
+#define RNGC_STATUS_FIFO_LEVEL_MASK 0x00000f00
+#define RNGC_STATUS_FIFO_LEVEL_SHIFT 8
+#define RNGC_STATUS_NEXT_SEED_DONE 0x00000040
+#define RNGC_STATUS_SEED_DONE 0x00000020
+#define RNGC_STATUS_ST_DONE 0x00000010
+#define RNGC_STATUS_RESEED 0x00000008
+#define RNGC_STATUS_SLEEP 0x00000004
+#define RNGC_STATUS_BUSY 0x00000002
+#define RNGC_STATUS_SEC_STATE 0x00000001
+
+#define RNGC_ERROR_STATUS_ZEROS_MASK 0xffffffc0
+#define RNGC_ERROR_STATUS_BAD_KEY 0x00000040
+#define RNGC_ERROR_STATUS_RAND_ERR 0x00000020
+#define RNGC_ERROR_STATUS_FIFO_ERR 0x00000010
+#define RNGC_ERROR_STATUS_STAT_ERR 0x00000008
+#define RNGC_ERROR_STATUS_ST_ERR 0x00000004
+#define RNGC_ERROR_STATUS_OSC_ERR 0x00000002
+#define RNGC_ERROR_STATUS_LFSR_ERR 0x00000001
+
+#define RNG_ADDR_RANGE 0x34
+
+static DECLARE_COMPLETION(rng_self_testing);
+static DECLARE_COMPLETION(rng_seed_done);
+
+static struct platform_device *imx_rng_dev;
+
+struct imx_rng_priv_data {
+ void __iomem *reg_base;
+};
+
+int irq_rng;
+
+static int imx_rng_data_present(struct hwrng *rng, int wait)
+{
+ int level;
+ struct imx_rng_priv_data *prv = (struct imx_rng_priv_data *)rng->priv;
+
+ /* how many random numbers are in FIFO? [0-16] */
+ level = (readl(prv->reg_base + RNGC_STATUS) &
+ RNGC_STATUS_FIFO_LEVEL_MASK) >> RNGC_STATUS_FIFO_LEVEL_SHIFT;
+
+ return level > 0 ? 1 : 0;
+}
+
+static int imx_rng_data_read(struct hwrng *rng, u32 *data)
+{
+ int err;
+ struct imx_rng_priv_data *prv = (struct imx_rng_priv_data *)rng->priv;
+
+ /* retrieve a random number from FIFO */
+ *data = readl(prv->reg_base + RNGC_FIFO);
+
+ /* is there some error while reading this random number? */
+ err = readl(prv->reg_base + RNGC_STATUS) & RNGC_STATUS_ERROR;
+
+ /* if error happened doesn't return random number */
+ return err ? 0 : 4;
+}
+
+static irqreturn_t imx_rng_irq(int irq, void *dev)
+{
+ int handled = 0;
+ struct imx_rng_priv_data *prv = (struct imx_rng_priv_data *)dev;
+
+ /* is the seed creation done? */
+ if (readl(prv->reg_base + RNGC_STATUS) & RNGC_STATUS_SEED_DONE) {
+ complete(&rng_seed_done);
+ writel(RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR,
+ prv->reg_base + RNGC_COMMAND);
+ handled = 1;
+ }
+
+ /* is the self test done? */
+ if (readl(prv->reg_base + RNGC_STATUS) & RNGC_STATUS_ST_DONE) {
+ complete(&rng_self_testing);
+ writel(RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR,
+ prv->reg_base + RNGC_COMMAND);
+ handled = 1;
+ }
+
+ /* is there any error? */
+ if (readl(prv->reg_base + RNGC_STATUS) & RNGC_STATUS_ERROR) {
+ /* clear interrupt */
+ writel(RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR,
+ prv->reg_base + RNGC_COMMAND);
+ handled = 1;
+ }
+
+ return handled;
+}
+
+static int imx_rng_init(struct hwrng *rng)
+{
+ int err;
+ struct imx_rng_priv_data *prv = (struct imx_rng_priv_data *)rng->priv;
+ u32 cmd, ctrl, osc;
+
+ reinit_completion(&rng_self_testing);
+ reinit_completion(&rng_seed_done);
+
+ err = readl(prv->reg_base + RNGC_STATUS) & RNGC_STATUS_ERROR;
+ if (err) {
+ /* is this a bad keys error ? */
+ if (readl(prv->reg_base + RNGC_ERROR) &
+ RNGC_ERROR_STATUS_BAD_KEY) {
+ dev_err(&imx_rng_dev->dev, "Can't start, Bad Keys.\n");
+ return -EIO;
+ }
+ }
+
+ /* mask all interrupts, will be unmasked soon */
+ ctrl = readl(prv->reg_base + RNGC_CONTROL);
+ writel(ctrl | RNGC_CTRL_MASK_DONE | RNGC_CTRL_MASK_ERROR,
+ prv->reg_base + RNGC_CONTROL);
+
+ /* verify if oscillator is working */
+ osc = readl(prv->reg_base + RNGC_ERROR);
+ if (osc & RNGC_ERROR_STATUS_OSC_ERR) {
+ dev_err(&imx_rng_dev->dev, "RNGC Oscillator is dead!\n");
+ return -EIO;
+ }
+
+ err = request_irq(irq_rng, imx_rng_irq,
+ 0, "imx-rng", (void *)rng->priv);
+ if (err) {
+ dev_err(&imx_rng_dev->dev, "Can't get interrupt working.\n");
+ return -EIO;
+ }
+
+ /* do self test, repeat until get success */
+ do {
+ /* clear error */
+ cmd = readl(prv->reg_base + RNGC_COMMAND);
+ writel(cmd | RNGC_CMD_CLR_ERR, prv->reg_base + RNGC_COMMAND);
+
+ /* unmask all interrupt */
+ ctrl = readl(prv->reg_base + RNGC_CONTROL);
+ writel(ctrl & ~(RNGC_CTRL_MASK_DONE | RNGC_CTRL_MASK_ERROR),
+ prv->reg_base + RNGC_CONTROL);
+
+ /* run self test */
+ cmd = readl(prv->reg_base + RNGC_COMMAND);
+ writel(cmd | RNGC_CMD_SELF_TEST,
+ prv->reg_base + RNGC_COMMAND);
+
+ wait_for_completion(&rng_self_testing);
+
+ } while (readl(prv->reg_base + RNGC_ERROR) &
+ RNGC_ERROR_STATUS_ST_ERR);
+
+ /* clear interrupt. Is it really necessary here? */
+ writel(RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR,
+ prv->reg_base + RNGC_COMMAND);
+
+ /* create seed, repeat while there is some statistical error */
+ do {
+ /* clear error */
+ cmd = readl(prv->reg_base + RNGC_COMMAND);
+ writel(cmd | RNGC_CMD_CLR_ERR, prv->reg_base + RNGC_COMMAND);
+
+ /* seed creation */
+ cmd = readl(prv->reg_base + RNGC_COMMAND);
+ writel(cmd | RNGC_CMD_SEED, prv->reg_base + RNGC_COMMAND);
+
+ wait_for_completion(&rng_seed_done);
+
+ } while (readl(prv->reg_base + RNGC_ERROR) &
+ RNGC_ERROR_STATUS_STAT_ERR);
+
+ err = readl(prv->reg_base + RNGC_ERROR) &
+ (RNGC_ERROR_STATUS_STAT_ERR |
+ RNGC_ERROR_STATUS_RAND_ERR |
+ RNGC_ERROR_STATUS_FIFO_ERR |
+ RNGC_ERROR_STATUS_ST_ERR |
+ RNGC_ERROR_STATUS_OSC_ERR |
+ RNGC_ERROR_STATUS_LFSR_ERR);
+
+ if (err) {
+ dev_err(&imx_rng_dev->dev, "iMX RNG appears inoperable.\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static struct hwrng imx_rng = {
+ .name = "imx-rng",
+ .init = imx_rng_init,
+ .data_present = imx_rng_data_present,
+ .data_read = imx_rng_data_read
+};
+
+static int __init imx_rng_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct clk *clk;
+ struct imx_rng_priv_data *priv;
+ int err = -ENODEV;
+
+ if (imx_rng_dev)
+ return -EBUSY;
+
+ /* Enable the clock */
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk)) {
+ dev_err(dev, "Can not get clock.\n");
+ return PTR_ERR(clk);
+ }
+ clk_enable(clk);
+
+ /* Allocate private data memory */
+ priv = kzalloc(sizeof(struct imx_rng_priv_data), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ imx_rng.priv = (unsigned long)priv;
+ dev_set_drvdata(dev, priv);
+
+ /* ioremap that register space */
+ priv->reg_base = of_iomap(np, 0);
+ if (!priv->reg_base) {
+ kfree(priv);
+ dev_err(dev, "Failed to remap register space.\n");
+ return -ENODEV;
+ }
+
+ irq_rng = platform_get_irq(pdev, 0);
+
+ err = hwrng_register(&imx_rng);
+ if (err) {
+ iounmap(priv->reg_base);
+ kfree(priv);
+ dev_err(dev, "failed to register hwrng (%d)\n", err);
+ return err;
+ }
+
+ imx_rng_dev = pdev;
+ dev_info(dev, "iMX RNG Registered.\n");
+
+ return 0;
+}
+
+static int __exit imx_rng_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct clk *clk;
+ struct imx_rng_priv_data *priv = dev_get_drvdata(dev);
+
+ /* Disable the clock */
+ clk = of_clk_get(np, 0);
+
+ if (IS_ERR(clk))
+ dev_err(dev, "Can not get clock.\n");
+ else
+ clk_disable(clk);
+
+ hwrng_unregister(&imx_rng);
+
+ iounmap(priv->reg_base);
+
+ kfree(priv);
+
+ return 0;
+}
+
+static int imx_rng_suspend(struct platform_device *pdev, pm_message_t state)
+{
+#ifdef CONFIG_PM
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct clk *clk = of_clk_get(np, 0);
+
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "Can not get rng_clk\n");
+ return PTR_ERR(clk);
+ }
+
+ clk_disable(clk);
+#endif
+
+ return 0;
+}
+
+static int imx_rng_resume(struct platform_device *pdev)
+{
+#ifdef CONFIG_PM
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct clk *clk = of_clk_get(np, 0);
+
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "Can not get rng_clk\n");
+ return PTR_ERR(clk);
+ }
+
+ clk_enable(clk);
+#endif
+
+ return 0;
+}
+
+static struct of_device_id imx_rng_dt_ids[] = {
+ { .compatible = "imx-rng",},
+ { .compatible = "fsl,imx-rng",},
+ { .compatible = "fsl,imx6sl-rng",},
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, imx_rng_dt_ids);
+
+static struct platform_driver imx_rng_driver = {
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = imx_rng_dt_ids,
+ },
+ .remove = __exit_p(imx_rng_remove),
+ .suspend = imx_rng_suspend,
+ .resume = imx_rng_resume,
+};
+
+static int __init mod_init(void)
+{
+ return platform_driver_probe(&imx_rng_driver, imx_rng_probe);
+}
+
+static void __exit mod_exit(void)
+{
+ platform_driver_unregister(&imx_rng_driver);
+}
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("H/W RNG(B/C) driver for i.MX");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/imx_amp/Kconfig b/drivers/char/imx_amp/Kconfig
new file mode 100644
index 000000000000..1f892f8daccb
--- /dev/null
+++ b/drivers/char/imx_amp/Kconfig
@@ -0,0 +1,9 @@
+#
+# imx mcc
+#
+
+config IMX_SEMA4
+ bool "IMX SEMA4 driver"
+ depends on SOC_IMX6SX
+ help
+ Support for IMX SEMA4 driver, most people should say N here.
diff --git a/drivers/char/imx_amp/Makefile b/drivers/char/imx_amp/Makefile
new file mode 100644
index 000000000000..4e7a91691b39
--- /dev/null
+++ b/drivers/char/imx_amp/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for imx mcc
+#
+#
+obj-$(CONFIG_IMX_SEMA4) += imx_sema4.o
diff --git a/drivers/char/imx_amp/imx_sema4.c b/drivers/char/imx_amp/imx_sema4.c
new file mode 100644
index 000000000000..412202f11cbb
--- /dev/null
+++ b/drivers/char/imx_amp/imx_sema4.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/imx_sema4.h>
+
+static struct imx_sema4_mutex_device *imx6_sema4;
+
+/*!
+ * \brief mutex create function.
+ *
+ * This function allocates imx_sema4_mutex structure and returns a handle
+ * to it. The mutex to be created is identified by SEMA4 device number and mutex
+ * (gate) number. The handle is used to reference the created mutex in calls to
+ * other imx_sema4_mutex API functions. This function is to be called only
+ * once for each mutex.
+ *
+ * \param[in] dev_num SEMA4 device (module) number.
+ * \param[in] mutex_num Mutex (gate) number.
+ *
+ * \return NULL (Failure.)
+ * \return imx_sema4_mutex (Success.)
+ */
+struct imx_sema4_mutex *
+imx_sema4_mutex_create(u32 dev_num, u32 mutex_num)
+{
+ struct imx_sema4_mutex *mutex_ptr = NULL;
+
+ if (mutex_num >= SEMA4_NUM_GATES || dev_num >= SEMA4_NUM_DEVICES)
+ goto out;
+
+ if (imx6_sema4->cpine_val & (1 < mutex_num)) {
+ pr_err("Error: requiring a allocated sema4.\n");
+ pr_err("mutex_num %d cpine_val 0x%08x.\n",
+ mutex_num, imx6_sema4->cpine_val);
+ }
+ mutex_ptr = kzalloc(sizeof(*mutex_ptr), GFP_KERNEL);
+ if (!mutex_ptr)
+ goto out;
+ imx6_sema4->mutex_ptr[mutex_num] = mutex_ptr;
+ imx6_sema4->alloced |= 1 < mutex_num;
+ imx6_sema4->cpine_val |= idx_sema4[mutex_num];
+ writew(imx6_sema4->cpine_val, imx6_sema4->ioaddr + SEMA4_CP0INE);
+
+ mutex_ptr->valid = CORE_MUTEX_VALID;
+ mutex_ptr->gate_num = mutex_num;
+ init_waitqueue_head(&mutex_ptr->wait_q);
+
+out:
+ return mutex_ptr;
+}
+EXPORT_SYMBOL(imx_sema4_mutex_create);
+
+/*!
+ * \brief mutex destroy function.
+ *
+ * This function destroys a mutex.
+ *
+ * \param[in] mutex_ptr Pointer to mutex structure.
+ *
+ * \return MQX_COMPONENT_DOES_NOT_EXIST (mutex component not installed.)
+ * \return MQX_INVALID_PARAMETER (Wrong input parameter.)
+ * \return COREMUTEX_OK (Success.)
+ *
+ */
+int imx_sema4_mutex_destroy(struct imx_sema4_mutex *mutex_ptr)
+{
+ u32 mutex_num;
+
+ if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID))
+ return -EINVAL;
+
+ mutex_num = mutex_ptr->gate_num;
+ if ((imx6_sema4->cpine_val & idx_sema4[mutex_num]) == 0) {
+ pr_err("Error: trying to destroy a un-allocated sema4.\n");
+ pr_err("mutex_num %d cpine_val 0x%08x.\n",
+ mutex_num, imx6_sema4->cpine_val);
+ }
+ imx6_sema4->mutex_ptr[mutex_num] = NULL;
+ imx6_sema4->alloced &= ~(1 << mutex_num);
+ imx6_sema4->cpine_val &= ~(idx_sema4[mutex_num]);
+ writew(imx6_sema4->cpine_val, imx6_sema4->ioaddr + SEMA4_CP0INE);
+
+ kfree(mutex_ptr);
+
+ return 0;
+}
+EXPORT_SYMBOL(imx_sema4_mutex_destroy);
+
+/*!
+ * \brief Lock the mutex, shouldn't be interruted by INT.
+ *
+ * This function attempts to lock a mutex. If the mutex is already locked
+ * by another task the function return -EBUSY, and tell invoker wait until
+ * it is possible to lock the mutex.
+ *
+ * \param[in] mutex_ptr Pointer to mutex structure.
+ *
+ * \return MQX_INVALID_POINTER (Wrong pointer to the mutex structure provided.)
+ * \return COREMUTEX_OK (mutex successfully locked.)
+ *
+ * \see imx_sema4_mutex_unlock
+ */
+int _imx_sema4_mutex_lock(struct imx_sema4_mutex *mutex_ptr)
+{
+ int ret = 0, i = 0;
+
+ if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID))
+ return -EINVAL;
+
+ i = mutex_ptr->gate_num;
+ mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
+ mutex_ptr->gate_val &= SEMA4_GATE_MASK;
+ /* Check to see if this core already own it */
+ if (mutex_ptr->gate_val == SEMA4_A9_LOCK) {
+ /* return -EBUSY, invoker should be in sleep, and re-lock ag */
+ pr_err("%s -> %s %d already locked, wait! num %d val %d.\n",
+ __FILE__, __func__, __LINE__,
+ i, mutex_ptr->gate_val);
+ ret = -EBUSY;
+ goto out;
+ } else {
+ /* try to lock the mutex */
+ mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
+ mutex_ptr->gate_val &= (~SEMA4_GATE_MASK);
+ mutex_ptr->gate_val |= SEMA4_A9_LOCK;
+ writeb(mutex_ptr->gate_val, imx6_sema4->ioaddr + i);
+ mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
+ mutex_ptr->gate_val &= SEMA4_GATE_MASK;
+ /* double check the mutex is locked, otherwise, return -EBUSY */
+ if (mutex_ptr->gate_val != SEMA4_A9_LOCK) {
+ pr_debug("wait-locked num %d val %d.\n",
+ i, mutex_ptr->gate_val);
+ ret = -EBUSY;
+ }
+ }
+out:
+ return ret;
+}
+
+/* !
+ * \brief Try to lock the core mutex.
+ *
+ * This function attempts to lock a mutex. If the mutex is successfully locked
+ * for the calling task, SEMA4_A9_LOCK is returned. If the mutex is already
+ * locked by another task, the function does not block but rather returns
+ * negative immediately.
+ *
+ * \param[in] mutex_ptr Pointer to core_mutex structure.
+ *
+ * \return SEMA4_A9_LOCK (mutex successfully locked.)
+ * \return negative (mutex not locked.)
+ *
+ */
+int imx_sema4_mutex_trylock(struct imx_sema4_mutex *mutex_ptr)
+{
+ int ret = 0;
+
+ ret = _imx_sema4_mutex_lock(mutex_ptr);
+ if (ret == 0)
+ return SEMA4_A9_LOCK;
+ else
+ return ret;
+}
+EXPORT_SYMBOL(imx_sema4_mutex_trylock);
+
+/*!
+ * \brief Invoke _imx_sema4_mutex_lock to lock the mutex.
+ *
+ * This function attempts to lock a mutex. If the mutex is already locked
+ * by another task the function, sleep itself and schedule out.
+ * Wait until it is possible to lock the mutex.
+ *
+ * Invoker should add its own wait queue into the wait queue header of the
+ * required semaphore, set TASK_INTERRUPTIBLE and sleep on itself by
+ * schedule() when the lock is failed. Re-try to lock the semaphore when
+ * it is woke up by the sema4 isr.
+ *
+ * \param[in] mutex_ptr Pointer to mutex structure.
+ *
+ * \return SEMA4_A9_LOCK (mutex successfully locked.)
+ *
+ * \see imx_sema4_mutex_unlock
+ */
+int imx_sema4_mutex_lock(struct imx_sema4_mutex *mutex_ptr)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&imx6_sema4->lock, flags);
+ ret = _imx_sema4_mutex_lock(mutex_ptr);
+ spin_unlock_irqrestore(&imx6_sema4->lock, flags);
+ while (-EBUSY == ret) {
+ spin_lock_irqsave(&imx6_sema4->lock, flags);
+ ret = _imx_sema4_mutex_lock(mutex_ptr);
+ spin_unlock_irqrestore(&imx6_sema4->lock, flags);
+ if (ret == 0)
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(imx_sema4_mutex_lock);
+
+/*!
+ * \brief Unlock the mutex.
+ *
+ * This function unlocks the specified mutex.
+ *
+ * \param[in] mutex_ptr Pointer to mutex structure.
+ *
+ * \return -EINVAL (Wrong pointer to the mutex structure provided.)
+ * \return -EINVAL (This mutex has not been locked by this core.)
+ * \return 0 (mutex successfully unlocked.)
+ *
+ * \see imx_sema4_mutex_lock
+ */
+int imx_sema4_mutex_unlock(struct imx_sema4_mutex *mutex_ptr)
+{
+ int ret = 0, i = 0;
+
+ if ((mutex_ptr == NULL) || (mutex_ptr->valid != CORE_MUTEX_VALID))
+ return -EINVAL;
+
+ i = mutex_ptr->gate_num;
+ mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
+ mutex_ptr->gate_val &= SEMA4_GATE_MASK;
+ /* make sure it is locked by this core */
+ if (mutex_ptr->gate_val != SEMA4_A9_LOCK) {
+ pr_err("%d Trying to unlock an unlock mutex.\n", __LINE__);
+ ret = -EINVAL;
+ goto out;
+ }
+ /* unlock it */
+ mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
+ mutex_ptr->gate_val &= (~SEMA4_GATE_MASK);
+ writeb(mutex_ptr->gate_val | SEMA4_UNLOCK, imx6_sema4->ioaddr + i);
+ mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
+ mutex_ptr->gate_val &= SEMA4_GATE_MASK;
+ /* make sure it is locked by this core */
+ if (mutex_ptr->gate_val == SEMA4_A9_LOCK)
+ pr_err("%d ERROR, failed to unlock the mutex.\n", __LINE__);
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL(imx_sema4_mutex_unlock);
+
+/*
+ * isr used by SEMA4, wake up the sleep tasks if there are the tasks waiting
+ * for locking semaphore.
+ * FIXME the bits order of the gatn, cpnie, cpnntf are not exact identified yet!
+ */
+static irqreturn_t imx_sema4_isr(int irq, void *dev_id)
+{
+ int i;
+ struct imx_sema4_mutex *mutex_ptr;
+ unsigned int mask;
+ struct imx_sema4_mutex_device *imx6_sema4 = dev_id;
+
+ imx6_sema4->cpntf_val = readw(imx6_sema4->ioaddr + SEMA4_CP0NTF);
+ for (i = 0; i < SEMA4_NUM_GATES; i++) {
+ mask = idx_sema4[i];
+ if ((imx6_sema4->cpntf_val) & mask) {
+ mutex_ptr = imx6_sema4->mutex_ptr[i];
+ /*
+ * An interrupt is pending on this mutex, the only way
+ * to clear it is to lock it (either by this core or
+ * another).
+ */
+ mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
+ mutex_ptr->gate_val &= (~SEMA4_GATE_MASK);
+ mutex_ptr->gate_val |= SEMA4_A9_LOCK;
+ writeb(mutex_ptr->gate_val, imx6_sema4->ioaddr + i);
+ mutex_ptr->gate_val = readb(imx6_sema4->ioaddr + i);
+ mutex_ptr->gate_val &= SEMA4_GATE_MASK;
+ if (mutex_ptr->gate_val == SEMA4_A9_LOCK) {
+ /*
+ * wake up the wait queue, whatever there
+ * are wait task or not.
+ * NOTE: check gate is locted or not in
+ * sema4_lock func by wait task.
+ */
+ mutex_ptr->gate_val =
+ readb(imx6_sema4->ioaddr + i);
+ mutex_ptr->gate_val &= (~SEMA4_GATE_MASK);
+ mutex_ptr->gate_val |= SEMA4_UNLOCK;
+
+ writeb(mutex_ptr->gate_val,
+ imx6_sema4->ioaddr + i);
+ wake_up(&mutex_ptr->wait_q);
+ } else {
+ pr_debug("can't lock gate%d %s retry!\n", i,
+ mutex_ptr->gate_val ?
+ "locked by m4" : "");
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static const struct of_device_id imx_sema4_dt_ids[] = {
+ { .compatible = "fsl,imx6sx-sema4", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_sema4_dt_ids);
+
+static int imx_sema4_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret;
+
+ imx6_sema4 = devm_kzalloc(&pdev->dev, sizeof(*imx6_sema4), GFP_KERNEL);
+ if (!imx6_sema4)
+ return -ENOMEM;
+
+ imx6_sema4->dev = &pdev->dev;
+ imx6_sema4->cpine_val = 0;
+ spin_lock_init(&imx6_sema4->lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (IS_ERR(res)) {
+ dev_err(&pdev->dev, "unable to get imx sema4 resource 0\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ imx6_sema4->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(imx6_sema4->ioaddr)) {
+ ret = PTR_ERR(imx6_sema4->ioaddr);
+ goto err;
+ }
+
+ imx6_sema4->irq = platform_get_irq(pdev, 0);
+ if (!imx6_sema4->irq) {
+ dev_err(&pdev->dev, "failed to get irq\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ ret = devm_request_irq(&pdev->dev, imx6_sema4->irq, imx_sema4_isr,
+ IRQF_SHARED, "imx6sx-sema4", imx6_sema4);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request imx sema4 irq\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, imx6_sema4);
+
+err:
+ return ret;
+}
+
+static int imx_sema4_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver imx_sema4_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "imx-sema4",
+ .of_match_table = imx_sema4_dt_ids,
+ },
+ .probe = imx_sema4_probe,
+ .remove = imx_sema4_remove,
+};
+
+static int __init imx_sema4_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&imx_sema4_driver);
+ if (ret)
+ pr_err("Unable to initialize sema4 driver\n");
+ else
+ pr_info("imx sema4 driver is registered.\n");
+
+ return ret;
+}
+
+static void __exit imx_sema4_exit(void)
+{
+ pr_info("imx sema4 driver is unregistered.\n");
+ platform_driver_unregister(&imx_sema4_driver);
+}
+
+module_exit(imx_sema4_exit);
+module_init(imx_sema4_init);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IMX SEMA4 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 42042c0a936c..57252488e72c 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_ARCH_BERLIN) += berlin/
obj-$(CONFIG_H8300) += h8300/
obj-$(CONFIG_ARCH_HISI) += hisilicon/
obj-$(CONFIG_ARCH_MXC) += imx/
+obj-$(CONFIG_ARCH_MXC_ARM64) += imx/
obj-$(CONFIG_MACH_INGENIC) += ingenic/
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
obj-$(CONFIG_MACH_LOONGSON32) += loongson1/
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 96386ffc8483..5012d272f8e2 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -123,6 +123,9 @@ unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
struct clk_divider *divider = to_clk_divider(hw);
unsigned int div;
+ if (flags & CLK_DIVIDER_ZERO_GATE && !val)
+ return 0;
+
div = _get_div(table, val, flags, divider->width);
if (!div) {
WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
@@ -141,8 +144,13 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
struct clk_divider *divider = to_clk_divider(hw);
unsigned int val;
- val = clk_readl(divider->reg) >> divider->shift;
- val &= div_mask(divider->width);
+ if ((divider->flags & CLK_DIVIDER_ZERO_GATE) &&
+ !clk_hw_is_enabled(hw)) {
+ val = divider->cached_val;
+ } else {
+ val = clk_readl(divider->reg) >> divider->shift;
+ val &= div_mask(divider->width);
+ }
return divider_recalc_rate(hw, parent_rate, val, divider->table,
divider->flags);
@@ -391,6 +399,12 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
value = divider_get_val(rate, parent_rate, divider->table,
divider->width, divider->flags);
+ if ((divider->flags & CLK_DIVIDER_ZERO_GATE) &&
+ !clk_hw_is_enabled(hw)) {
+ divider->cached_val = value;
+ return 0;
+ }
+
if (divider->lock)
spin_lock_irqsave(divider->lock, flags);
else
@@ -413,10 +427,85 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
return 0;
}
+static int clk_divider_enable(struct clk_hw *hw)
+{
+ struct clk_divider *divider = to_clk_divider(hw);
+ unsigned long flags = 0;
+ u32 val;
+
+ if (!(divider->flags & CLK_DIVIDER_ZERO_GATE))
+ return 0;
+
+ if (!divider->cached_val) {
+ pr_err("%s: no valid preset rate\n", clk_hw_get_name(hw));
+ return -EINVAL;
+ }
+
+ if (divider->lock)
+ spin_lock_irqsave(divider->lock, flags);
+ else
+ __acquire(divider->lock);
+
+ /* restore div val */
+ val = clk_readl(divider->reg);
+ val |= divider->cached_val << divider->shift;
+ clk_writel(val, divider->reg);
+
+ if (divider->lock)
+ spin_unlock_irqrestore(divider->lock, flags);
+ else
+ __release(divider->lock);
+
+ return 0;
+}
+
+static void clk_divider_disable(struct clk_hw *hw)
+{
+ struct clk_divider *divider = to_clk_divider(hw);
+ unsigned long flags = 0;
+ u32 val;
+
+ if (!(divider->flags & CLK_DIVIDER_ZERO_GATE))
+ return;
+
+ if (divider->lock)
+ spin_lock_irqsave(divider->lock, flags);
+ else
+ __acquire(divider->lock);
+
+ /* store the current div val */
+ val = clk_readl(divider->reg) >> divider->shift;
+ val &= div_mask(divider->width);
+ divider->cached_val = val;
+ clk_writel(0, divider->reg);
+
+ if (divider->lock)
+ spin_unlock_irqrestore(divider->lock, flags);
+ else
+ __release(divider->lock);
+}
+
+static int clk_divider_is_enabled(struct clk_hw *hw)
+{
+ struct clk_divider *divider = to_clk_divider(hw);
+ u32 val;
+
+ if (!(divider->flags & CLK_DIVIDER_ZERO_GATE))
+ return __clk_get_enable_count(hw->clk);
+
+ val = clk_readl(divider->reg) >> divider->shift;
+ val &= div_mask(divider->width);
+
+ return val ? 1 : 0;
+}
+
const struct clk_ops clk_divider_ops = {
.recalc_rate = clk_divider_recalc_rate,
.round_rate = clk_divider_round_rate,
.set_rate = clk_divider_set_rate,
+ .enable = clk_divider_enable,
+ .disable = clk_divider_disable,
+ .is_enabled = clk_divider_is_enabled,
};
EXPORT_SYMBOL_GPL(clk_divider_ops);
@@ -435,6 +524,7 @@ static struct clk_hw *_register_divider(struct device *dev, const char *name,
struct clk_divider *div;
struct clk_hw *hw;
struct clk_init_data init;
+ u32 val;
int ret;
if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
@@ -467,6 +557,12 @@ static struct clk_hw *_register_divider(struct device *dev, const char *name,
div->hw.init = &init;
div->table = table;
+ if (div->flags & CLK_DIVIDER_ZERO_GATE) {
+ val = clk_readl(reg) >> shift;
+ val &= div_mask(width);
+ div->cached_val = val;
+ }
+
/* register the clock */
hw = &div->hw;
ret = clk_hw_register(dev, hw);
diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c
index aab904618eb6..455bec58c3c9 100644
--- a/drivers/clk/clk-fractional-divider.c
+++ b/drivers/clk/clk-fractional-divider.c
@@ -40,6 +40,11 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
m = (val & fd->mmask) >> fd->mshift;
n = (val & fd->nmask) >> fd->nshift;
+ if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) {
+ m++;
+ n++;
+ }
+
if (!n || !m)
return parent_rate;
@@ -91,6 +96,11 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
&m, &n);
+ if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) {
+ m--;
+ n--;
+ }
+
if (fd->lock)
spin_lock_irqsave(fd->lock, flags);
else
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index c745dad7f85e..5da068e435d1 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1797,7 +1797,8 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
/* prevent racing with updates to the clock topology */
clk_prepare_lock();
- if (core->parent == parent)
+ if ((core->parent == parent) &&
+ !(core->flags & CLK_SET_PARENT_NOCACHE))
goto out;
/* verify ops for for multi-parent clks */
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
index 1ada68abb158..d09bcea81ed7 100644
--- a/drivers/clk/imx/Makefile
+++ b/drivers/clk/imx/Makefile
@@ -1,5 +1,4 @@
-
-obj-y += \
+obj-$(CONFIG_ARM) += \
clk.o \
clk-busy.o \
clk-cpu.o \
@@ -10,7 +9,11 @@ obj-y += \
clk-pllv1.o \
clk-pllv2.o \
clk-pllv3.o \
- clk-pfd.o
+ clk-pfd.o \
+ clk-composite.o \
+ clk-pllv4.o \
+ clk-pllv5.o \
+ clk-pfdv2.o
obj-$(CONFIG_SOC_IMX1) += clk-imx1.o
obj-$(CONFIG_SOC_IMX21) += clk-imx21.o
@@ -21,7 +24,16 @@ obj-$(CONFIG_SOC_IMX35) += clk-imx35.o
obj-$(CONFIG_SOC_IMX5) += clk-imx51-imx53.o
obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o
obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o
+obj-$(CONFIG_SOC_IMX6SLL) += clk-imx6sll.o
obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o
obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o
obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o
+obj-$(CONFIG_SOC_IMX7ULP) += clk-imx7ulp.o
obj-$(CONFIG_SOC_VF610) += clk-vf610.o
+#
+# IMX Clock specific Makefile
+#
+obj-$(CONFIG_ARCH_FSL_IMX8QM) += clk.o clk-imx8qm.o clk-imx8.o clk-divider-scu.o clk-gate-scu.o clk-mux-scu.o
+obj-$(CONFIG_ARCH_FSL_IMX8QXP) += clk.o clk-imx8qxp.o clk-imx8.o clk-divider-scu.o clk-gate-scu.o clk-mux-scu.o
+obj-$(CONFIG_ARCH_FSL_IMX8MQ) += clk.o clk-imx8mq.o clk-frac-pll.o clk-sccg-pll.o clk-gate2.o
+obj-$(CONFIG_ARCH_FSL_IMX8MM) += clk.o clk-imx8mm.o clk-intpll.o clk-gate2.o clk-cpu.o
diff --git a/drivers/clk/imx/clk-busy.c b/drivers/clk/imx/clk-busy.c
index 5cc99590f9a3..59a133d291ee 100644
--- a/drivers/clk/imx/clk-busy.c
+++ b/drivers/clk/imx/clk-busy.c
@@ -101,7 +101,7 @@ struct clk *imx_clk_busy_divider(const char *name, const char *parent_name,
init.name = name;
init.ops = &clk_busy_divider_ops;
- init.flags = CLK_SET_RATE_PARENT;
+ init.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE;
init.parent_names = &parent_name;
init.num_parents = 1;
diff --git a/drivers/clk/imx/clk-composite.c b/drivers/clk/imx/clk-composite.c
new file mode 100644
index 000000000000..c6105d586063
--- /dev/null
+++ b/drivers/clk/imx/clk-composite.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#define PCG_PCS_SHIFT 24
+#define PCG_PCS_MASK 0x7
+#define PCG_CGC_SHIFT 30
+#define PCG_FRAC_SHIFT 3
+#define PCG_FRAC_WIDTH 1
+#define PCG_FRAC_MASK BIT(3)
+#define PCG_PCD_SHIFT 0
+#define PCG_PCD_WIDTH 3
+#define PCG_PCD_MASK 0x7
+
+struct clk *imx_clk_composite(const char *name, const char **parent_names,
+ int num_parents, bool mux_present,
+ bool rate_present, bool gate_present,
+ void __iomem *reg)
+{
+ struct clk_hw *mux_hw = NULL, *fd_hw = NULL, *gate_hw = NULL;
+ struct clk_fractional_divider *fd = NULL;
+ struct clk_gate *gate = NULL;
+ struct clk_mux *mux = NULL;
+ struct clk *clk;
+
+ if (mux_present) {
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ return ERR_PTR(-ENOMEM);
+ mux_hw = &mux->hw;
+ mux->reg = reg;
+ mux->shift = PCG_PCS_SHIFT;
+ mux->mask = PCG_PCS_MASK;
+ }
+
+ if (rate_present) {
+ fd = kzalloc(sizeof(*fd), GFP_KERNEL);
+ if (!fd) {
+ kfree(mux);
+ return ERR_PTR(-ENOMEM);
+ }
+ fd_hw = &fd->hw;
+ fd->reg = reg;
+ fd->mshift = PCG_FRAC_SHIFT;
+ fd->mwidth = PCG_FRAC_WIDTH;
+ fd->mmask = PCG_FRAC_MASK;
+ fd->nshift = PCG_PCD_SHIFT;
+ fd->nwidth = PCG_PCD_WIDTH;
+ fd->nmask = PCG_PCD_MASK;
+ fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED;
+ }
+
+ if (gate_present) {
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ kfree(mux);
+ kfree(fd);
+ return ERR_PTR(-ENOMEM);
+ }
+ gate_hw = &gate->hw;
+ gate->reg = reg;
+ gate->bit_idx = PCG_CGC_SHIFT;
+ }
+
+ clk = clk_register_composite(NULL, name, parent_names, num_parents,
+ mux_hw, &clk_mux_ops, fd_hw,
+ &clk_fractional_divider_ops, gate_hw,
+ &clk_gate_ops, CLK_SET_RATE_GATE |
+ CLK_SET_PARENT_GATE);
+ if (IS_ERR(clk)) {
+ kfree(mux);
+ kfree(fd);
+ kfree(gate);
+ }
+
+ return clk;
+}
diff --git a/drivers/clk/imx/clk-divider-scu.c b/drivers/clk/imx/clk-divider-scu.c
new file mode 100644
index 000000000000..b8ad05050ec0
--- /dev/null
+++ b/drivers/clk/imx/clk-divider-scu.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <soc/imx8/sc/sci.h>
+
+#include "clk-imx8.h"
+
+struct clk_divider_scu {
+ struct clk_divider div;
+ sc_rsrc_t rsrc_id;
+ sc_pm_clk_t clk_type;
+};
+
+struct clk_divider3_scu {
+ struct clk_divider div;
+ sc_rsrc_t rsrc_id;
+ sc_ctrl_t gpr_id;
+};
+
+static inline struct clk_divider3_scu *to_clk_divider3_scu(struct clk_hw *hw)
+{
+ struct clk_divider *div = container_of(hw, struct clk_divider, hw);
+
+ return container_of(div, struct clk_divider3_scu, div);
+}
+
+static inline struct clk_divider_scu *to_clk_divider_scu(struct clk_hw *hw)
+{
+ struct clk_divider *div = container_of(hw, struct clk_divider, hw);
+
+ return container_of(div, struct clk_divider_scu, div);
+}
+
+static unsigned long clk_divider_scu_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_divider_scu *clk = to_clk_divider_scu(hw);
+ sc_err_t sci_err;
+ sc_pm_clock_rate_t rate = 0;
+
+ if (!ccm_ipc_handle)
+ return 0;
+
+ sci_err = sc_pm_get_clock_rate(ccm_ipc_handle, clk->rsrc_id,
+ clk->clk_type, &rate);
+
+ return sci_err ? 0 : rate;
+}
+
+static long clk_divider_scu_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ /* TODO */
+ *prate = rate;
+
+ return rate;
+}
+
+static int clk_divider_scu_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_divider_scu *clk = to_clk_divider_scu(hw);
+ sc_err_t sci_err;
+
+ if (!ccm_ipc_handle) {
+ return -EAGAIN;
+ }
+
+ sci_err = sc_pm_set_clock_rate(ccm_ipc_handle, clk->rsrc_id,
+ clk->clk_type, (sc_pm_clock_rate_t *)&rate);
+
+ return sci_err ? -EINVAL : 0;
+}
+
+static struct clk_ops clk_divider_scu_ops = {
+ .recalc_rate = clk_divider_scu_recalc_rate,
+ .round_rate = clk_divider_scu_round_rate,
+ .set_rate = clk_divider_scu_set_rate,
+};
+
+struct clk *imx_clk_divider_scu(const char *name,
+ sc_rsrc_t rsrc_id, sc_pm_clk_t clk_type)
+{
+ struct clk_divider_scu *div_clk;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ if (!imx8_clk_is_resource_owned(rsrc_id)) {
+ pr_debug("skip clk %s rsrc %d not owned\n", name, rsrc_id);
+ return ERR_PTR(-ENODEV);
+ }
+
+ div_clk = kzalloc(sizeof(*div_clk), GFP_KERNEL);
+ if (!div_clk)
+ return ERR_PTR(-ENOMEM);
+
+ div_clk->rsrc_id = rsrc_id;
+ div_clk->clk_type = clk_type;
+
+ init.name = name;
+ init.ops = &clk_divider_scu_ops;
+ init.flags = CLK_GET_RATE_NOCACHE;
+ init.num_parents = 0;
+ div_clk->div.hw.init = &init;
+
+ clk = clk_register(NULL, &div_clk->div.hw);
+ if (IS_ERR(clk))
+ kfree(div_clk);
+
+ return clk;
+}
+
+struct clk *imx_clk_divider2_scu(const char *name, const char *parent_name,
+ sc_rsrc_t rsrc_id, sc_pm_clk_t clk_type)
+{
+ struct clk_divider_scu *div_clk;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ if (!imx8_clk_is_resource_owned(rsrc_id)) {
+ pr_debug("skip clk %s rsrc %d not owned\n", name, rsrc_id);
+ return ERR_PTR(-ENODEV);
+ }
+
+ div_clk = kzalloc(sizeof(*div_clk), GFP_KERNEL);
+ if (!div_clk)
+ return ERR_PTR(-ENOMEM);
+
+ div_clk->rsrc_id = rsrc_id;
+ div_clk->clk_type = clk_type;
+
+ init.name = name;
+ init.ops = &clk_divider_scu_ops;
+ init.flags = CLK_GET_RATE_NOCACHE;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ init.num_parents = parent_name ? 1 : 0;
+ div_clk->div.hw.init = &init;
+
+ clk = clk_register(NULL, &div_clk->div.hw);
+ if (IS_ERR(clk))
+ kfree(div_clk);
+
+ return clk;
+}
+
+static unsigned long clk_divider3_scu_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_divider3_scu *clk = to_clk_divider3_scu(hw);
+ uint32_t val;
+ sc_err_t sci_err;
+ sc_pm_clock_rate_t rate = 0;
+
+ if (!ccm_ipc_handle)
+ return 0;
+
+ sci_err = sc_misc_get_control(ccm_ipc_handle, clk->rsrc_id,
+ clk->gpr_id, &val);
+
+ rate = (val) ? parent_rate / 2 : parent_rate;
+
+ return sci_err ? 0 : rate;
+}
+
+static long clk_divider3_scu_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ if (rate < *prate)
+ rate = *prate / 2;
+ else
+ rate = *prate;
+
+ return rate;
+}
+
+static int clk_divider3_scu_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_divider3_scu *clk = to_clk_divider3_scu(hw);
+ uint32_t val;
+ sc_err_t sci_err;
+
+ if (!ccm_ipc_handle) {
+ return -EAGAIN;
+ }
+
+ val = (rate < parent_rate) ? 1 : 0;
+ sci_err = sc_misc_set_control(ccm_ipc_handle, clk->rsrc_id,
+ clk->gpr_id, val);
+
+ return sci_err ? -EINVAL : 0;
+}
+
+static struct clk_ops clk_divider3_scu_ops = {
+ .recalc_rate = clk_divider3_scu_recalc_rate,
+ .round_rate = clk_divider3_scu_round_rate,
+ .set_rate = clk_divider3_scu_set_rate,
+};
+
+struct clk *imx_clk_divider3_scu(const char *name, const char *parent_name,
+ sc_rsrc_t rsrc_id, sc_ctrl_t gpr_id)
+{
+ struct clk_divider3_scu *div;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ if (!imx8_clk_is_resource_owned(rsrc_id)) {
+ pr_debug("skip clk %s rsrc %d not owned\n", name, rsrc_id);
+ return ERR_PTR(-ENODEV);
+ }
+
+ div = kzalloc(sizeof(struct clk_divider3_scu), GFP_KERNEL);
+ if (!div)
+ return ERR_PTR(-ENOMEM);
+
+ div->rsrc_id = rsrc_id;
+ div->gpr_id = gpr_id;
+
+ init.name = name;
+ init.ops = &clk_divider3_scu_ops;
+ init.flags = 0;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ init.num_parents = parent_name ? 1 : 0;
+
+ div->div.hw.init = &init;
+
+ clk = clk_register(NULL, &div->div.hw);
+ if (IS_ERR(clk))
+ kfree(div);
+
+ return clk;
+}
diff --git a/drivers/clk/imx/clk-frac-pll.c b/drivers/clk/imx/clk-frac-pll.c
new file mode 100644
index 000000000000..7c2614cbb8f7
--- /dev/null
+++ b/drivers/clk/imx/clk-frac-pll.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2017 NXP.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+
+#include "clk.h"
+
+#define PLL_CFG0 0x0
+#define PLL_CFG1 0x4
+
+#define PLL_LOCK_STATUS (0x1 << 31)
+#define PLL_CLKE 21
+#define PLL_PD 19
+#define PLL_BYPASS 14
+#define PLL_NEWDIV_VAL (1 << 12)
+#define PLL_NEWDIV_ACK (1 << 11)
+#define PLL_FRAC_DIV_MASK 0xffffff
+#define PLL_INT_DIV_MASK 0x7f
+#define PLL_FRAC_DENOM 0x1000000
+
+struct clk_frac_pll {
+ struct clk_hw hw;
+ void __iomem *base;
+};
+
+#define to_clk_frac_pll(_hw) container_of(_hw, struct clk_frac_pll, hw)
+
+static int clk_wait_lock(struct clk_frac_pll *pll)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(10);
+
+ /* Wait for PLL to lock */
+ do {
+ if (readl_relaxed(pll->base) & PLL_LOCK_STATUS)
+ break;
+ if (time_after(jiffies, timeout))
+ break;
+ } while (1);
+
+ return readl_relaxed(pll->base) & PLL_LOCK_STATUS ? 0 : -ETIMEDOUT;
+}
+
+static int clk_wait_ack(struct clk_frac_pll *pll)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(50);
+
+ /* return directly if the pll is in powerdown or bypass */
+ if (readl_relaxed(pll->base) & ((1 << PLL_PD) | (1 << PLL_BYPASS)))
+ return 0;
+
+ /* Wait for the pll's divfi and divff is reloaded */
+ do {
+ if (readl_relaxed(pll->base) & PLL_NEWDIV_ACK)
+ break;
+ if (time_after(jiffies, timeout))
+ break;
+ } while (1);
+
+ return readl_relaxed(pll->base) & PLL_NEWDIV_ACK ? 0 : ETIMEDOUT;
+}
+
+static int clk_pll_prepare(struct clk_hw *hw)
+{
+ struct clk_frac_pll *pll = to_clk_frac_pll(hw);
+ u32 val;
+
+ val = readl_relaxed(pll->base + PLL_CFG0);
+ val &= ~(1 << PLL_PD);
+ writel_relaxed(val, pll->base + PLL_CFG0);
+
+ return clk_wait_lock(pll);
+}
+
+static void clk_pll_unprepare(struct clk_hw *hw)
+{
+ struct clk_frac_pll *pll = to_clk_frac_pll(hw);
+ u32 val;
+
+ val = readl_relaxed(pll->base + PLL_CFG0);
+ val |= (1 << PLL_PD);
+ writel_relaxed(val, pll->base + PLL_CFG0);
+}
+
+static int clk_pll_is_prepared(struct clk_hw *hw)
+{
+ struct clk_frac_pll *pll = to_clk_frac_pll(hw);
+ u32 val;
+
+ val = readl_relaxed(pll->base + PLL_CFG0);
+ return (val & (1 << PLL_PD)) ? 0 : 1;
+}
+
+static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_frac_pll *pll = to_clk_frac_pll(hw);
+ u32 val, divff, divfi, divq;
+ u64 temp64;
+
+ val = readl_relaxed(pll->base + PLL_CFG0);
+ divq = ((val & 0x1f) + 1) * 2;
+ val = readl_relaxed(pll->base + PLL_CFG1);
+ divff = (val >> 7) & PLL_FRAC_DIV_MASK;
+ divfi = (val & PLL_INT_DIV_MASK);
+
+ temp64 = (u64)parent_rate * 8;
+ temp64 *= divff;
+ do_div(temp64, PLL_FRAC_DENOM);
+ temp64 /= divq;
+
+ return parent_rate * 8 * (divfi + 1) / divq + (unsigned long)temp64;
+}
+
+static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ u32 divff, divfi;
+ u64 temp64;
+ unsigned long parent_rate = *prate;
+
+ parent_rate *= 8;
+ rate *= 2;
+ divfi = rate / parent_rate;
+ temp64 = (u64)(rate - divfi * parent_rate);
+ temp64 *= PLL_FRAC_DENOM;
+ do_div(temp64, parent_rate);
+ divff = temp64;
+
+ temp64 = (u64)parent_rate;
+ temp64 *= divff;
+ do_div(temp64, PLL_FRAC_DENOM);
+
+ return (parent_rate * divfi + (unsigned long)temp64) / 2;
+}
+
+/*
+ * To simplify the clock calculation, we can keep the
+ * 'PLL_OUTPUT_VAL' to zero(means the PLL output
+ * will be dividered by 2. So the PLL output can use
+ * below formula:
+ * pllout = parent_rate * 8 / 2 * DIVF_VAL;
+ * where DIVF_VAL = 1 + DIVFI + DIVFF / 2^24.
+ */
+static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_frac_pll *pll = to_clk_frac_pll(hw);
+ u32 val, divfi, divff;
+ u64 temp64;
+ int ret;
+
+ parent_rate *= 8;
+ rate *= 2;
+ divfi = rate / parent_rate;
+ temp64 = (u64) (rate - divfi * parent_rate);
+ temp64 *= PLL_FRAC_DENOM;
+ do_div(temp64, parent_rate);
+ divff = temp64;
+
+ val = readl_relaxed(pll->base + PLL_CFG1);
+ val &= ~((PLL_FRAC_DIV_MASK << 7) | (PLL_INT_DIV_MASK));
+ val |= ((divff << 7) | (divfi - 1));
+ writel_relaxed(val, pll->base + PLL_CFG1);
+
+ val = readl_relaxed(pll->base + PLL_CFG0);
+ val &= ~0x1f;
+ writel_relaxed(val, pll->base + PLL_CFG0);
+
+ /* Set the NEV_DIV_VAL to reload the DIVFI and DIVFF */
+ val = readl_relaxed(pll->base + PLL_CFG0);
+ val |= PLL_NEWDIV_VAL;
+ writel_relaxed(val, pll->base + PLL_CFG0);
+
+ ret = clk_wait_ack(pll);
+
+ /* clear the NEV_DIV_VAL */
+ val = readl_relaxed(pll->base + PLL_CFG0);
+ val &= ~PLL_NEWDIV_VAL;
+ writel_relaxed(val, pll->base + PLL_CFG0);
+
+ return ret;
+}
+
+static const struct clk_ops clk_frac_pll_ops = {
+ .prepare = clk_pll_prepare,
+ .unprepare = clk_pll_unprepare,
+ .is_prepared = clk_pll_is_prepared,
+ .recalc_rate = clk_pll_recalc_rate,
+ .round_rate = clk_pll_round_rate,
+ .set_rate = clk_pll_set_rate,
+};
+
+struct clk *imx_clk_frac_pll(const char *name, const char *parent_name,
+ void __iomem *base)
+{
+ struct clk_frac_pll *pll;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ pll->base = base;
+ init.name = name;
+ init.ops = &clk_frac_pll_ops;
+ init.flags = 0;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ pll->hw.init = &init;
+
+ clk = clk_register(NULL, &pll->hw);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
diff --git a/drivers/clk/imx/clk-gate-scu.c b/drivers/clk/imx/clk-gate-scu.c
new file mode 100644
index 000000000000..abcda5f9a952
--- /dev/null
+++ b/drivers/clk/imx/clk-gate-scu.c
@@ -0,0 +1,448 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm_domain.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <soc/imx8/sc/sci.h>
+
+#include "clk-imx8.h"
+
+/*
+ * 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 CLK_GATE_SCU_HW_SW_EN (BIT(0) | BIT(1))
+#define CLK_GATE_SCU_SW_EN BIT(1)
+
+struct clk_gate_scu {
+ struct clk_hw hw;
+ void __iomem *reg;
+ u8 bit_idx;
+ bool hw_gate;
+ u8 flags;
+ spinlock_t *lock;
+ sc_rsrc_t rsrc_id;
+ sc_pm_clk_t clk_type;
+};
+
+struct clk_gate2_scu {
+ struct clk_hw hw;
+ void __iomem *reg;
+ u8 bit_idx;
+ u8 flags;
+ spinlock_t *lock;
+ char *pd_name;
+ struct generic_pm_domain *pd;
+};
+
+struct clk_gate3_scu {
+ struct clk_hw hw;
+ spinlock_t *lock;
+ sc_rsrc_t rsrc_id;
+ sc_ctrl_t gpr_id;
+ bool invert;
+};
+
+#define to_clk_gate_scu(_hw) container_of(_hw, struct clk_gate_scu, hw)
+#define to_clk_gate2_scu(_hw) container_of(_hw, struct clk_gate2_scu, hw)
+#define to_clk_gate3_scu(_hw) container_of(_hw, struct clk_gate3_scu, hw)
+
+/* Write to the LPCG bits. */
+static int clk_gate_scu_enable(struct clk_hw *hw)
+{
+ struct clk_gate_scu *gate = to_clk_gate_scu(hw);
+ u32 reg;
+
+ if (!ccm_ipc_handle)
+ return -1;
+
+ if (gate->reg) {
+ reg = readl(gate->reg);
+ if (gate->hw_gate)
+ reg |= (CLK_GATE_SCU_HW_SW_EN << gate->bit_idx);
+ else
+ reg |= (CLK_GATE_SCU_SW_EN << gate->bit_idx);
+ writel(reg, gate->reg);
+ }
+
+ return 0;
+}
+
+/* Write to the LPCG bits. */
+static void clk_gate_scu_disable(struct clk_hw *hw)
+{
+ struct clk_gate_scu *gate = to_clk_gate_scu(hw);
+ u32 reg;
+
+ if (!ccm_ipc_handle)
+ return;
+
+ if (gate->reg) {
+ reg = readl(gate->reg);
+ if (gate->hw_gate)
+ reg &= ~(CLK_GATE_SCU_HW_SW_EN << gate->bit_idx);
+ else
+ reg &= ~(CLK_GATE_SCU_SW_EN << gate->bit_idx);
+ writel(reg, gate->reg);
+ }
+}
+
+static int clk_gate_scu_prepare(struct clk_hw *hw)
+{
+ struct clk_gate_scu *gate = to_clk_gate_scu(hw);
+ sc_err_t sci_err = SC_ERR_NONE;
+
+ if (!ccm_ipc_handle)
+ return -1;
+
+ /* Enable the clock at the DSC slice level */
+ sci_err = sc_pm_clock_enable(ccm_ipc_handle, gate->rsrc_id,
+ gate->clk_type, true, gate->hw_gate);
+
+ if (sci_err != SC_ERR_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void clk_gate_scu_unprepare(struct clk_hw *hw)
+{
+ struct clk_gate_scu *gate = to_clk_gate_scu(hw);
+ sc_err_t sci_err;
+
+ if (!ccm_ipc_handle)
+ return;
+
+ sci_err = sc_pm_clock_enable(ccm_ipc_handle, gate->rsrc_id,
+ gate->clk_type, false, false);
+ if (sci_err)
+ pr_err("clk gate scu unprepare clk fail!\n");
+}
+
+static unsigned long clk_gate_scu_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_gate_scu *clk = to_clk_gate_scu(hw);
+ sc_err_t sci_err;
+ sc_pm_clock_rate_t rate = 0;
+
+ if (!ccm_ipc_handle)
+ return 0;
+
+ sci_err = sc_pm_get_clock_rate(ccm_ipc_handle, clk->rsrc_id,
+ clk->clk_type, &rate);
+
+ return sci_err ? 0 : rate;
+}
+
+static struct clk_ops clk_gate_scu_ops = {
+ .prepare = clk_gate_scu_prepare,
+ .unprepare = clk_gate_scu_unprepare,
+ .enable = clk_gate_scu_enable,
+ .disable = clk_gate_scu_disable,
+ .recalc_rate = clk_gate_scu_recalc_rate,
+};
+
+struct clk *clk_register_gate_scu(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ u8 clk_gate_scu_flags, spinlock_t *lock,
+ sc_rsrc_t rsrc_id, sc_pm_clk_t clk_type,
+ void __iomem *reg, u8 bit_idx, bool hw_gate)
+{
+ struct clk_gate_scu *gate;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ if (!imx8_clk_is_resource_owned(rsrc_id)) {
+ pr_debug("skip clk %s rsrc %d not owned\n", name, rsrc_id);
+ return ERR_PTR(-ENODEV);
+ }
+
+ gate = kzalloc(sizeof(struct clk_gate_scu), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ /* struct clk_gate_scu assignments */
+ gate->flags = clk_gate_scu_flags;
+ gate->lock = lock;
+ gate->rsrc_id = rsrc_id;
+ gate->clk_type = clk_type;
+ if (reg != NULL)
+ gate->reg = ioremap((phys_addr_t)reg, SZ_64K);
+ else
+ gate->reg = NULL;
+ gate->bit_idx = bit_idx;
+ gate->hw_gate = hw_gate;
+
+ init.name = name;
+ init.ops = &clk_gate_scu_ops;
+ init.flags = flags;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ init.num_parents = parent_name ? 1 : 0;
+
+ gate->hw.init = &init;
+
+ clk = clk_register(dev, &gate->hw);
+ if (IS_ERR(clk)) {
+ iounmap(gate->reg);
+ kfree(gate);
+ }
+
+ return clk;
+}
+
+/* Get the power domain associated with the clock from the device tree. */
+static void populate_gate_pd(struct clk_gate2_scu *clk)
+{
+ struct device_node *np;
+ struct of_phandle_args pd_args;
+
+ np = of_find_node_by_name(NULL, clk->pd_name);
+ if (np) {
+ pd_args.np = np;
+ pd_args.args_count = 0;
+ clk->pd = genpd_get_from_provider(&pd_args);
+ if (IS_ERR(clk->pd))
+ pr_warn("%s: failed to get pd\n", __func__);
+ }
+}
+
+/* Write to the LPCG bits. */
+static int clk_gate2_scu_enable(struct clk_hw *hw)
+{
+ struct clk_gate2_scu *gate = to_clk_gate2_scu(hw);
+ u32 reg;
+
+ if (!ccm_ipc_handle)
+ return -1;
+
+ if (gate->pd == NULL && gate->pd_name)
+ populate_gate_pd(gate);
+
+ if (IS_ERR_OR_NULL(gate->pd))
+ return -1;
+
+ if (gate->pd->status != GPD_STATE_ACTIVE)
+ return -1;
+
+ if (gate->reg) {
+ reg = readl(gate->reg);
+ reg |= (0x2 << gate->bit_idx);
+ writel(reg, gate->reg);
+ }
+
+ return 0;
+}
+
+/* Write to the LPCG bits. */
+static void clk_gate2_scu_disable(struct clk_hw *hw)
+{
+ struct clk_gate2_scu *gate = to_clk_gate2_scu(hw);
+ u32 reg;
+
+ if (!ccm_ipc_handle)
+ return;
+
+ if (gate->pd == NULL && gate->pd_name)
+ populate_gate_pd(gate);
+
+ if (IS_ERR_OR_NULL(gate->pd))
+ return;
+
+ if (gate->pd->status != GPD_STATE_ACTIVE)
+ return;
+
+ if (gate->reg) {
+ reg = readl(gate->reg);
+ reg &= ~(0x2 << gate->bit_idx);
+ writel(reg, gate->reg);
+ }
+}
+
+static int clk_gate2_scu_is_enabled(struct clk_hw *hw)
+{
+ struct clk_gate2_scu *gate = to_clk_gate2_scu(hw);
+ u32 val;
+
+ if (gate->pd == NULL && gate->pd_name)
+ populate_gate_pd(gate);
+
+ if (IS_ERR_OR_NULL(gate->pd))
+ return 0;
+
+ if (gate->pd->status != GPD_STATE_ACTIVE)
+ return 0;
+
+ if (gate->reg) {
+ val = readl(gate->reg);
+
+ if (((val >> gate->bit_idx) & 2) == 2)
+ return 1;
+ }
+ return 0;
+}
+
+
+static struct clk_ops clk_gate2_scu_ops = {
+ .enable = clk_gate2_scu_enable,
+ .disable = clk_gate2_scu_disable,
+ .is_enabled = clk_gate2_scu_is_enabled,
+};
+
+struct clk *clk_register_gate2_scu(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 bit_idx,
+ u8 clk_gate_flags, spinlock_t *lock, const char *pd_name)
+{
+ struct clk_gate2_scu *gate;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ gate = kzalloc(sizeof(struct clk_gate2_scu), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ /* struct clk_gate_scu assignments */
+ gate->flags = clk_gate_flags;
+ gate->lock = lock;
+ if (reg != NULL)
+ gate->reg = ioremap((phys_addr_t)reg, SZ_64K);
+ else
+ gate->reg = NULL;
+ gate->bit_idx = bit_idx;
+ gate->pd = NULL;
+ gate->pd_name = NULL;
+ if (pd_name) {
+ gate->pd_name = kzalloc(strlen(pd_name) + 1, GFP_KERNEL);
+ strcpy(gate->pd_name, pd_name);
+ }
+
+ init.name = name;
+ init.ops = &clk_gate2_scu_ops;
+ init.flags = flags;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ init.num_parents = parent_name ? 1 : 0;
+
+ gate->hw.init = &init;
+
+ clk = clk_register(dev, &gate->hw);
+ if (IS_ERR(clk)) {
+ iounmap(gate->reg);
+ kfree(gate->pd_name);
+ kfree(gate);
+ }
+
+ return clk;
+}
+
+static int clk_gate3_scu_prepare(struct clk_hw *hw)
+{
+ struct clk_gate3_scu *gate = to_clk_gate3_scu(hw);
+ uint32_t val;
+
+ if (!ccm_ipc_handle)
+ return -1;
+
+ val = (gate->invert) ? 0 : 1;
+
+ return sc_misc_set_control(ccm_ipc_handle,
+ gate->rsrc_id, gate->gpr_id, val);
+}
+
+/* Write to the LPCG bits. */
+static void clk_gate3_scu_unprepare(struct clk_hw *hw)
+{
+ struct clk_gate3_scu *gate = to_clk_gate3_scu(hw);
+ uint32_t val;
+
+ if (!ccm_ipc_handle)
+ return;
+
+ val = (gate->invert) ? 1 : 0;
+ sc_misc_set_control(ccm_ipc_handle, gate->rsrc_id, gate->gpr_id, val);
+}
+
+static int clk_gate3_scu_is_prepared(struct clk_hw *hw)
+{
+ struct clk_gate3_scu *gate = to_clk_gate3_scu(hw);
+ uint32_t val;
+
+ if (!ccm_ipc_handle)
+ return -1;
+
+ sc_misc_get_control(ccm_ipc_handle, gate->rsrc_id, gate->gpr_id, &val);
+ val &= 1;
+
+ if (gate->invert)
+ return 1 - val;
+
+ return val;
+}
+
+static struct clk_ops clk_gate3_scu_ops = {
+ .prepare = clk_gate3_scu_prepare,
+ .unprepare = clk_gate3_scu_unprepare,
+ .is_prepared = clk_gate3_scu_is_prepared,
+};
+
+struct clk *clk_register_gate3_scu(struct device *dev, const char *name,
+ const char *parent_name, spinlock_t *lock,
+ sc_rsrc_t rsrc_id, sc_ctrl_t gpr_id, bool invert_flag)
+{
+ struct clk_gate3_scu *gate;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ if (!imx8_clk_is_resource_owned(rsrc_id)) {
+ pr_debug("skip clk %s rsrc %d not owned\n", name, rsrc_id);
+ return ERR_PTR(-ENODEV);
+ }
+
+ gate = kzalloc(sizeof(struct clk_gate_scu), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ /* struct clk_gate_scu assignments */
+ gate->lock = lock;
+ gate->rsrc_id = rsrc_id;
+ gate->gpr_id = gpr_id;
+ gate->invert = invert_flag;
+
+ init.name = name;
+ init.ops = &clk_gate3_scu_ops;
+ init.flags = 0;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ init.num_parents = parent_name ? 1 : 0;
+
+ gate->hw.init = &init;
+
+ clk = clk_register(dev, &gate->hw);
+ if (IS_ERR(clk))
+ kfree(gate);
+
+ return clk;
+}
diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c
index db44a198a0d9..b9bd5938d44a 100644
--- a/drivers/clk/imx/clk-gate2.c
+++ b/drivers/clk/imx/clk-gate2.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
* Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -10,11 +11,13 @@
*/
#include <linux/clk-provider.h>
+#include <linux/imx_sema4.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/string.h>
+#include <soc/imx/src.h>
#include "clk.h"
/**
@@ -38,11 +41,56 @@ struct clk_gate2 {
};
#define to_clk_gate2(_hw) container_of(_hw, struct clk_gate2, hw)
+#define CCM_CCGR_FULL_ENABLE 0x3
+
+static void clk_gate2_do_hardware(struct clk_gate2 *gate, bool enable)
+{
+ u32 reg;
+
+ reg = readl(gate->reg);
+ if (enable)
+ reg |= CCM_CCGR_FULL_ENABLE << gate->bit_idx;
+ else
+ reg &= ~(CCM_CCGR_FULL_ENABLE << gate->bit_idx);
+ writel(reg, gate->reg);
+}
+
+static void clk_gate2_do_shared_clks(struct clk_hw *hw, bool enable)
+{
+ struct clk_gate2 *gate = to_clk_gate2(hw);
+
+ if (imx_src_is_m4_enabled() && clk_on_imx6sx()) {
+#ifdef CONFIG_SOC_IMX6SX
+ if (!amp_power_mutex || !shared_mem) {
+ if (enable)
+ clk_gate2_do_hardware(gate, enable);
+ return;
+ }
+
+ imx_sema4_mutex_lock(amp_power_mutex);
+ if (shared_mem->ca9_valid != SHARED_MEM_MAGIC_NUMBER ||
+ shared_mem->cm4_valid != SHARED_MEM_MAGIC_NUMBER) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+
+ if (!imx_update_shared_mem(hw, enable)) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+
+ clk_gate2_do_hardware(gate, enable);
+
+ imx_sema4_mutex_unlock(amp_power_mutex);
+#endif
+ } else {
+ clk_gate2_do_hardware(gate, enable);
+ }
+}
static int clk_gate2_enable(struct clk_hw *hw)
{
struct clk_gate2 *gate = to_clk_gate2(hw);
- u32 reg;
unsigned long flags = 0;
spin_lock_irqsave(gate->lock, flags);
@@ -50,11 +98,7 @@ static int clk_gate2_enable(struct clk_hw *hw)
if (gate->share_count && (*gate->share_count)++ > 0)
goto out;
- reg = readl(gate->reg);
- reg &= ~(3 << gate->bit_idx);
- reg |= gate->cgr_val << gate->bit_idx;
- writel(reg, gate->reg);
-
+ clk_gate2_do_shared_clks(hw, true);
out:
spin_unlock_irqrestore(gate->lock, flags);
@@ -64,7 +108,6 @@ out:
static void clk_gate2_disable(struct clk_hw *hw)
{
struct clk_gate2 *gate = to_clk_gate2(hw);
- u32 reg;
unsigned long flags = 0;
spin_lock_irqsave(gate->lock, flags);
@@ -76,10 +119,7 @@ static void clk_gate2_disable(struct clk_hw *hw)
goto out;
}
- reg = readl(gate->reg);
- reg &= ~(3 << gate->bit_idx);
- writel(reg, gate->reg);
-
+ clk_gate2_do_shared_clks(hw, false);
out:
spin_unlock_irqrestore(gate->lock, flags);
}
@@ -105,15 +145,11 @@ static void clk_gate2_disable_unused(struct clk_hw *hw)
{
struct clk_gate2 *gate = to_clk_gate2(hw);
unsigned long flags = 0;
- u32 reg;
spin_lock_irqsave(gate->lock, flags);
- if (!gate->share_count || *gate->share_count == 0) {
- reg = readl(gate->reg);
- reg &= ~(3 << gate->bit_idx);
- writel(reg, gate->reg);
- }
+ if (!gate->share_count || *gate->share_count == 0)
+ clk_gate2_do_shared_clks(hw, false);
spin_unlock_irqrestore(gate->lock, flags);
}
diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c
index 93a19667003d..8cde9cc32798 100644
--- a/drivers/clk/imx/clk-imx6q.c
+++ b/drivers/clk/imx/clk-imx6q.c
@@ -1,6 +1,7 @@
/*
- * Copyright 2011-2013 Freescale Semiconductor, Inc.
+ * Copyright (C) 2011-2016 Freescale Semiconductor, Inc.
* Copyright 2011 Linaro Ltd.
+ * Copyright 2017 NXP.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
@@ -31,7 +32,8 @@ static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", "dummy",
static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "pll2_bus", };
static const char *periph_sels[] = { "periph_pre", "periph_clk2", };
static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", };
-static const char *axi_sels[] = { "periph", "pll2_pfd2_396m", "periph", "pll3_pfd1_540m", };
+static const char *axi_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_540m", };
+static const char *axi_sels[] = { "periph", "axi_alt_sel", };
static const char *audio_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll3_pfd3_454m", "pll3_usb_otg", };
static const char *gpu_axi_sels[] = { "axi", "ahb", };
static const char *pre_axi_sels[] = { "axi", "ahb", };
@@ -41,15 +43,17 @@ static const char *gpu3d_core_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_p
static const char *gpu3d_shader_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll3_pfd0_720m", };
static const char *ipu_sels[] = { "mmdc_ch0_axi", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", };
static const char *ldb_di_sels[] = { "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "mmdc_ch1_axi", "pll3_usb_otg", };
+static const char *ldb_di0_div_sels[] = { "ldb_di0_div_3_5", "ldb_di0_div_7", };
+static const char *ldb_di1_div_sels[] = { "ldb_di1_div_3_5", "ldb_di1_div_7", };
static const char *ipu_di_pre_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd1_540m", };
static const char *ipu1_di0_sels[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
static const char *ipu1_di1_sels[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
static const char *ipu2_di0_sels[] = { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
static const char *ipu2_di1_sels[] = { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
-static const char *ipu1_di0_sels_2[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf", };
-static const char *ipu1_di1_sels_2[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf", };
-static const char *ipu2_di0_sels_2[] = { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf", };
-static const char *ipu2_di1_sels_2[] = { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0_podf", "ldb_di1_podf", };
+static const char *ipu1_di0_sels_2[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0_div_sel", "ldb_di1_div_sel", };
+static const char *ipu1_di1_sels_2[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0_div_sel", "ldb_di1_div_sel", };
+static const char *ipu2_di0_sels_2[] = { "ipu2_di0_pre", "dummy", "dummy", "ldb_di0_div_sel", "ldb_di1_div_sel", };
+static const char *ipu2_di1_sels_2[] = { "ipu2_di1_pre", "dummy", "dummy", "ldb_di0_div_sel", "ldb_di1_div_sel", };
static const char *hsi_tx_sels[] = { "pll3_120m", "pll2_pfd2_396m", };
static const char *pcie_axi_sels[] = { "axi", "ahb", };
static const char *ssi_sels[] = { "pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_audio_div", };
@@ -95,11 +99,14 @@ static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
static struct clk *clk[IMX6QDL_CLK_END];
static struct clk_onecell_data clk_data;
+static void __iomem *ccm_base;
static unsigned int const clks_init_on[] __initconst = {
IMX6QDL_CLK_MMDC_CH0_AXI,
IMX6QDL_CLK_ROM,
IMX6QDL_CLK_ARM,
+ IMX6QDL_CLK_OCRAM,
+ IMX6QDL_CLK_AXI,
};
static struct clk_div_table clk_enet_ref_table[] = {
@@ -156,12 +163,335 @@ static struct clk ** const uart_clks[] __initconst = {
NULL
};
+static int ldb_di_sel_by_clock_id(int clock_id)
+{
+ switch (clock_id) {
+ case IMX6QDL_CLK_PLL5_VIDEO_DIV:
+ if (clk_on_imx6q() &&
+ imx_get_soc_revision() == IMX_CHIP_REVISION_1_0)
+ return -ENOENT;
+ return 0;
+ case IMX6QDL_CLK_PLL2_PFD0_352M:
+ return 1;
+ case IMX6QDL_CLK_PLL2_PFD2_396M:
+ return 2;
+ case IMX6QDL_CLK_MMDC_CH1_AXI:
+ return 3;
+ case IMX6QDL_CLK_PLL3_USB_OTG:
+ return 4;
+ default:
+ return -ENOENT;
+ }
+}
+
+static void of_assigned_ldb_sels(struct device_node *node,
+ unsigned int *ldb_di0_sel,
+ unsigned int *ldb_di1_sel)
+{
+ struct of_phandle_args clkspec;
+ int index, rc, num_parents;
+ int parent, child, sel;
+
+ num_parents = of_count_phandle_with_args(node, "assigned-clock-parents",
+ "#clock-cells");
+ for (index = 0; index < num_parents; index++) {
+ rc = of_parse_phandle_with_args(node, "assigned-clock-parents",
+ "#clock-cells", index, &clkspec);
+ if (rc < 0) {
+ /* skip empty (null) phandles */
+ if (rc == -ENOENT)
+ continue;
+ else
+ return;
+ }
+ if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) {
+ pr_err("ccm: parent clock %d not in ccm\n", index);
+ return;
+ }
+ parent = clkspec.args[0];
+
+ rc = of_parse_phandle_with_args(node, "assigned-clocks",
+ "#clock-cells", index, &clkspec);
+ if (rc < 0)
+ return;
+ if (clkspec.np != node || clkspec.args[0] >= IMX6QDL_CLK_END) {
+ pr_err("ccm: child clock %d not in ccm\n", index);
+ return;
+ }
+ child = clkspec.args[0];
+
+ if (child != IMX6QDL_CLK_LDB_DI0_SEL &&
+ child != IMX6QDL_CLK_LDB_DI1_SEL)
+ continue;
+
+ sel = ldb_di_sel_by_clock_id(parent);
+ if (sel < 0) {
+ pr_err("ccm: invalid ldb_di%d parent clock: %d\n",
+ child == IMX6QDL_CLK_LDB_DI1_SEL, parent);
+ continue;
+ }
+
+ if (child == IMX6QDL_CLK_LDB_DI0_SEL)
+ *ldb_di0_sel = sel;
+ if (child == IMX6QDL_CLK_LDB_DI1_SEL)
+ *ldb_di1_sel = sel;
+ }
+}
+
+#define CCM_CCDR 0x04
+#define CCM_CCSR 0x0c
+#define CCM_CS2CDR 0x2c
+#define CCM_CSCDR3 0x3c
+#define CCM_CCGR0 0x68
+#define CCM_CCGR3 0x74
+
+#define ANATOP_PLL3_PFD 0xf0
+
+
+#define CCDR_MMDC_CH1_MASK BIT(16)
+#define CCSR_PLL3_SW_CLK_SEL BIT(0)
+
+#define CS2CDR_LDB_DI0_CLK_SEL_SHIFT 9
+#define CS2CDR_LDB_DI1_CLK_SEL_SHIFT 12
+
+#define OCOTP_CFG3 0x440
+#define OCOTP_CFG3_SPEED_SHIFT 16
+#define OCOTP_CFG3_SPEED_1P2GHZ 0x3
+
+static void __init imx6q_mmdc_ch1_mask_handshake(void __iomem *ccm_base)
+{
+ unsigned int reg;
+
+ reg = readl_relaxed(ccm_base + CCM_CCDR);
+ reg |= CCDR_MMDC_CH1_MASK;
+ writel_relaxed(reg, ccm_base + CCM_CCDR);
+}
+
+/*
+ * The only way to disable the MMDC_CH1 clock is to move it to pll3_sw_clk
+ * via periph2_clk2_sel and then to disable pll3_sw_clk by selecting the
+ * bypass clock source, since there is no CG bit for mmdc_ch1.
+ */
+static void mmdc_ch1_disable(void __iomem *ccm_base)
+{
+ unsigned int reg;
+
+ clk_set_parent(clk[IMX6QDL_CLK_PERIPH2_CLK2_SEL],
+ clk[IMX6QDL_CLK_PLL3_USB_OTG]);
+
+ /*
+ * Handshake with mmdc_ch1 module must be masked when changing
+ * periph2_clk_sel.
+ */
+ clk_set_parent(clk[IMX6QDL_CLK_PERIPH2], clk[IMX6QDL_CLK_PERIPH2_CLK2]);
+
+ /* Disable pll3_sw_clk by selecting the bypass clock source */
+ reg = readl_relaxed(ccm_base + CCM_CCSR);
+ reg |= CCSR_PLL3_SW_CLK_SEL;
+ writel_relaxed(reg, ccm_base + CCM_CCSR);
+}
+
+static void mmdc_ch1_reenable(void __iomem *ccm_base)
+{
+ unsigned int reg;
+
+ /* Enable pll3_sw_clk by disabling the bypass */
+ reg = readl_relaxed(ccm_base + CCM_CCSR);
+ reg &= ~CCSR_PLL3_SW_CLK_SEL;
+ writel_relaxed(reg, ccm_base + CCM_CCSR);
+
+ clk_set_parent(clk[IMX6QDL_CLK_PERIPH2], clk[IMX6QDL_CLK_PERIPH2_PRE]);
+}
+
+/*
+ * We have to follow a strict procedure when changing the LDB clock source,
+ * otherwise we risk introducing a glitch that can lock up the LDB divider.
+ * Things to keep in mind:
+ *
+ * 1. The current and new parent clock inputs to the mux must be disabled.
+ * 2. The default clock input for ldb_di0/1_clk_sel is mmdc_ch1_axi, which
+ * has no CG bit.
+ * 3. pll2_pfd2_396m can not be gated if it is used as memory clock.
+ * 4. In the RTL implementation of the LDB_DI_CLK_SEL muxes the top four
+ * options are in one mux and the PLL3 option along with three unused
+ * inputs is in a second mux. There is a third mux with two inputs used
+ * to decide between the first and second 4-port mux:
+ *
+ * pll5_video_div 0 --|\
+ * pll2_pfd0_352m 1 --| |_
+ * pll2_pfd2_396m 2 --| | `-|\
+ * mmdc_ch1_axi 3 --|/ | |
+ * | |--
+ * pll3_usb_otg 4 --|\ | |
+ * 5 --| |_,-|/
+ * 6 --| |
+ * 7 --|/
+ *
+ * The ldb_di0/1_clk_sel[1:0] bits control both 4-port muxes at the same time.
+ * The ldb_di0/1_clk_sel[2] bit controls the 2-port mux. The code below
+ * switches the parent to the bottom mux first and then manipulates the top
+ * mux to ensure that no glitch will enter the divider.
+ */
+static void init_ldb_clks(struct device_node *np, void __iomem *ccm_base)
+{
+ unsigned int reg;
+ unsigned int sel[2][4];
+ int i;
+
+ reg = readl_relaxed(ccm_base + CCM_CS2CDR);
+ sel[0][0] = (reg >> CS2CDR_LDB_DI0_CLK_SEL_SHIFT) & 7;
+ sel[1][0] = (reg >> CS2CDR_LDB_DI1_CLK_SEL_SHIFT) & 7;
+
+ sel[0][3] = sel[0][2] = sel[0][1] = sel[0][0];
+ sel[1][3] = sel[1][2] = sel[1][1] = sel[1][0];
+
+ of_assigned_ldb_sels(np, &sel[0][3], &sel[1][3]);
+
+ for (i = 0; i < 2; i++) {
+ /* Warn if a glitch might have been introduced already */
+ if (sel[i][0] != 3) {
+ pr_warn("ccm: ldb_di%d_sel already changed from reset value: %d\n",
+ i, sel[i][0]);
+ }
+
+ if (sel[i][0] == sel[i][3])
+ continue;
+
+ /* Only switch to or from pll2_pfd2_396m if it is disabled */
+ if ((sel[i][0] == 2 || sel[i][3] == 2) &&
+ (clk_get_parent(clk[IMX6QDL_CLK_PERIPH_PRE]) ==
+ clk[IMX6QDL_CLK_PLL2_PFD2_396M])) {
+ pr_err("ccm: ldb_di%d_sel: couldn't disable pll2_pfd2_396m\n",
+ i);
+ sel[i][3] = sel[i][2] = sel[i][1] = sel[i][0];
+ continue;
+ }
+
+ /* First switch to the bottom mux */
+ sel[i][1] = sel[i][0] | 4;
+
+ /* Then configure the top mux before switching back to it */
+ sel[i][2] = sel[i][3] | 4;
+
+ pr_debug("ccm: switching ldb_di%d_sel: %d->%d->%d->%d\n", i,
+ sel[i][0], sel[i][1], sel[i][2], sel[i][3]);
+ }
+
+ if (sel[0][0] == sel[0][3] && sel[1][0] == sel[1][3])
+ return;
+
+ mmdc_ch1_disable(ccm_base);
+
+ for (i = 1; i < 4; i++) {
+ reg = readl_relaxed(ccm_base + CCM_CS2CDR);
+ reg &= ~((7 << CS2CDR_LDB_DI0_CLK_SEL_SHIFT) |
+ (7 << CS2CDR_LDB_DI1_CLK_SEL_SHIFT));
+ reg |= ((sel[0][i] << CS2CDR_LDB_DI0_CLK_SEL_SHIFT) |
+ (sel[1][i] << CS2CDR_LDB_DI1_CLK_SEL_SHIFT));
+ writel_relaxed(reg, ccm_base + CCM_CS2CDR);
+ }
+
+ mmdc_ch1_reenable(ccm_base);
+}
+
+#define CCM_ANALOG_PLL_VIDEO 0xa0
+#define CCM_ANALOG_PFD_480 0xf0
+#define CCM_ANALOG_PFD_528 0x100
+
+#define PLL_ENABLE BIT(13)
+
+#define PFD0_CLKGATE BIT(7)
+#define PFD1_CLKGATE BIT(15)
+#define PFD2_CLKGATE BIT(23)
+#define PFD3_CLKGATE BIT(31)
+
+/*
+ * workaround for ERR010579, when switching the clock source of IPU clock
+ * root in CCM. even setting CCGR3[CG0]=0x0 to gate off clock before
+ * switching, IPU may hang due to no IPU clock from CCM.
+ */
+static void __init init_ipu_clk(void __iomem *anatop_base)
+{
+ u32 val, origin_podf;
+
+ /* gate off the IPU1_IPU clock */
+ val = readl_relaxed(ccm_base + CCM_CCGR3);
+ val &= ~0x3;
+ writel_relaxed(val, ccm_base + CCM_CCGR3);
+
+ /* gate off IPU DCIC1/2 clocks */
+ val = readl_relaxed(ccm_base + CCM_CCGR0);
+ val &= ~(0xf << 24);
+ writel_relaxed(val, ccm_base + CCM_CCGR0);
+
+ /* set IPU_PODF to 3'b000 */
+ val = readl_relaxed(ccm_base + CCM_CSCDR3);
+ origin_podf = val & (0x7 << 11);
+ val &= ~(0x7 << 11);
+ writel_relaxed(val, ccm_base + CCM_CSCDR3);
+
+ /* disable PLL3_PFD1 */
+ val = readl_relaxed(anatop_base + ANATOP_PLL3_PFD);
+ val &= ~(0x1 << 15);
+ writel_relaxed(val, anatop_base + ANATOP_PLL3_PFD);
+
+ /* switch IPU_SEL clock to PLL3_PFD1 */
+ val = readl_relaxed(ccm_base + CCM_CSCDR3);
+ val |= (0x3 << 9);
+ writel_relaxed(val, ccm_base + CCM_CSCDR3);
+
+ /* restore the IPU PODF*/
+ val = readl_relaxed(ccm_base + CCM_CSCDR3);
+ val |= origin_podf;
+ writel_relaxed(val, ccm_base + CCM_CSCDR3);
+
+ /* enable PLL3_PFD1 */
+ val = readl_relaxed(anatop_base + ANATOP_PLL3_PFD);
+ val |= (0x1 << 15);
+ writel_relaxed(val, anatop_base + ANATOP_PLL3_PFD);
+
+ /* enable IPU1_IPU clock */
+ val = readl_relaxed(ccm_base + CCM_CCGR3);
+ val |= 0x3;
+ writel_relaxed(val, ccm_base + CCM_CCGR3);
+
+ /* enable IPU DCIC1/2 clock */
+ val = readl_relaxed(ccm_base + CCM_CCGR0);
+ val |= (0xf << 24);
+ writel_relaxed(val, ccm_base + CCM_CCGR0);
+}
+
+static void disable_anatop_clocks(void __iomem *anatop_base)
+{
+ unsigned int reg;
+
+ /* Make sure PLL2 PFDs 0-2 are gated */
+ reg = readl_relaxed(anatop_base + CCM_ANALOG_PFD_528);
+ /* Cannot gate PFD2 if pll2_pfd2_396m is the parent of MMDC clock */
+ if (clk_get_parent(clk[IMX6QDL_CLK_PERIPH_PRE]) ==
+ clk[IMX6QDL_CLK_PLL2_PFD2_396M])
+ reg |= PFD0_CLKGATE | PFD1_CLKGATE;
+ else
+ reg |= PFD0_CLKGATE | PFD1_CLKGATE | PFD2_CLKGATE;
+ writel_relaxed(reg, anatop_base + CCM_ANALOG_PFD_528);
+
+ /* Make sure PLL3 PFDs 0-3 are gated */
+ reg = readl_relaxed(anatop_base + CCM_ANALOG_PFD_480);
+ reg |= PFD0_CLKGATE | PFD1_CLKGATE | PFD2_CLKGATE | PFD3_CLKGATE;
+ writel_relaxed(reg, anatop_base + CCM_ANALOG_PFD_480);
+
+ /* Make sure PLL5 is disabled */
+ reg = readl_relaxed(anatop_base + CCM_ANALOG_PLL_VIDEO);
+ reg &= ~PLL_ENABLE;
+ writel_relaxed(reg, anatop_base + CCM_ANALOG_PLL_VIDEO);
+}
+
static void __init imx6q_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
- void __iomem *base;
+ void __iomem *anatop_base, *base;
int i;
- int ret;
+ u32 val;
clk[IMX6QDL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
clk[IMX6QDL_CLK_CKIL] = imx_obtain_fixed_clock("ckil", 0);
@@ -172,7 +502,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_ANACLK2] = imx_obtain_fixed_clock("anaclk2", 0);
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
- base = of_iomap(np, 0);
+ anatop_base = base = of_iomap(np, 0);
WARN_ON(!base);
/* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */
@@ -193,7 +523,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
/* type name parent_name base div_mask */
clk[IMX6QDL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f);
- clk[IMX6QDL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
+ clk[IMX6QDL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_PLL2, "pll2", "osc", base + 0x30, 0x1);
clk[IMX6QDL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3);
clk[IMX6QDL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f);
clk[IMX6QDL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f);
@@ -217,7 +547,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk_set_parent(clk[IMX6QDL_PLL6_BYPASS], clk[IMX6QDL_CLK_PLL6]);
clk_set_parent(clk[IMX6QDL_PLL7_BYPASS], clk[IMX6QDL_CLK_PLL7]);
- clk[IMX6QDL_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", base + 0x00, 13);
+ clk[IMX6QDL_CLK_PLL1_SYS] = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1);
clk[IMX6QDL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
clk[IMX6QDL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
clk[IMX6QDL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
@@ -288,23 +618,25 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_fixed_factor("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1);
}
- clk[IMX6QDL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
- clk[IMX6QDL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
- clk[IMX6QDL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
- clk[IMX6QDL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
+ clk[IMX6QDL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
+ clk[IMX6QDL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 15, 1, 0, &imx_ccm_lock);
+ clk[IMX6QDL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
+ clk[IMX6QDL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
np = ccm_node;
base = of_iomap(np, 0);
+ ccm_base = base;
WARN_ON(!base);
/* name reg shift width parent_names num_parents */
clk[IMX6QDL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
- clk[IMX6QDL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
- clk[IMX6QDL_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+ clk[IMX6QDL_CLK_PLL1_SW] = imx_clk_mux_glitchless("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
+ clk[IMX6QDL_CLK_PERIPH_PRE] = imx_clk_mux_bus("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
clk[IMX6QDL_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
- clk[IMX6QDL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+ clk[IMX6QDL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux_bus("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
clk[IMX6QDL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
- clk[IMX6QDL_CLK_AXI_SEL] = imx_clk_mux("axi_sel", base + 0x14, 6, 2, axi_sels, ARRAY_SIZE(axi_sels));
+ clk[IMX6QDL_CLK_AXI_ALT_SEL] = imx_clk_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
+ clk[IMX6QDL_CLK_AXI_SEL] = imx_clk_mux_glitchless("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels));
clk[IMX6QDL_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels));
clk[IMX6QDL_CLK_ASRC_SEL] = imx_clk_mux("asrc_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
clk[IMX6QDL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
@@ -330,8 +662,27 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8, 2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
clk[IMX6QDL_CLK_IPU1_SEL] = imx_clk_mux("ipu1_sel", base + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels));
clk[IMX6QDL_CLK_IPU2_SEL] = imx_clk_mux("ipu2_sel", base + 0x3c, 14, 2, ipu_sels, ARRAY_SIZE(ipu_sels));
- clk[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
- clk[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
+
+ if (clk_on_imx6q() && imx_get_soc_revision() >= IMX_CHIP_REVISION_2_0) {
+ clk[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_mux_flags("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
+ clk[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_mux_flags("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), CLK_SET_RATE_PARENT);
+ } else {
+ disable_anatop_clocks(anatop_base);
+
+ imx6q_mmdc_ch1_mask_handshake(base);
+
+ /*
+ * The LDB_DI0/1_SEL muxes are registered read-only due to a hardware
+ * bug. Set the muxes to the requested values before registering the
+ * ldb_di_sel clocks.
+ */
+ init_ldb_clks(np, base);
+
+ clk[IMX6QDL_CLK_LDB_DI0_SEL] = imx_clk_mux_ldb("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels));
+ clk[IMX6QDL_CLK_LDB_DI1_SEL] = imx_clk_mux_ldb("ldb_di1_sel", base + 0x2c, 12, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels));
+ }
+ clk[IMX6QDL_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux_flags("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels), CLK_SET_RATE_PARENT);
+ clk[IMX6QDL_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux_flags("ldb_di1_div_sel", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels), CLK_SET_RATE_PARENT);
clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL] = imx_clk_mux_flags("ipu1_di0_pre_sel", base + 0x34, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL] = imx_clk_mux_flags("ipu1_di1_pre_sel", base + 0x34, 15, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
clk[IMX6QDL_CLK_IPU2_DI0_PRE_SEL] = imx_clk_mux_flags("ipu2_di0_pre_sel", base + 0x38, 6, 3, ipu_di_pre_sels, ARRAY_SIZE(ipu_di_pre_sels), CLK_SET_RATE_PARENT);
@@ -397,6 +748,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_divider("uart_serial_podf", "uart_sel", base + 0x24, 0, 6);
clk[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0", 2, 7);
clk[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1", 2, 7);
+ clk[IMX6QDL_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0", 1, 7);
+ clk[IMX6QDL_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "ldb_di1", 1, 7);
} else {
clk[IMX6QDL_CLK_ECSPI_ROOT] = imx_clk_divider("ecspi_root", "pll3_60m", base + 0x38, 19, 6);
clk[IMX6QDL_CLK_CAN_ROOT] = imx_clk_divider("can_root", "pll3_60m", base + 0x20, 2, 6);
@@ -404,6 +757,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_UART_SERIAL_PODF] = imx_clk_divider("uart_serial_podf", "pll3_80m", base + 0x24, 0, 6);
clk[IMX6QDL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
clk[IMX6QDL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
+ clk[IMX6QDL_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7);
+ clk[IMX6QDL_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7);
}
if (clk_on_imx6dl())
clk[IMX6QDL_CLK_MLB_PODF] = imx_clk_divider("mlb_podf", "mlb_sel", base + 0x18, 23, 3);
@@ -470,6 +825,8 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_root", base + 0x68, 16);
clk[IMX6QDL_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18);
clk[IMX6QDL_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_root", base + 0x68, 20);
+ clk[IMX6QDL_CLK_DCIC1] = imx_clk_gate2("dcic1", "ipu1_podf", base + 0x68, 24);
+ clk[IMX6QDL_CLK_DCIC2] = imx_clk_gate2("dcic2", "ipu2_podf", base + 0x68, 26);
clk[IMX6QDL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0);
clk[IMX6QDL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_root", base + 0x6c, 2);
clk[IMX6QDL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_root", base + 0x6c, 4);
@@ -487,7 +844,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24);
clk[IMX6QDL_CLK_GPU3D_CORE] = imx_clk_gate2("gpu3d_core", "gpu3d_core_podf", base + 0x6c, 26);
clk[IMX6QDL_CLK_HDMI_IAHB] = imx_clk_gate2("hdmi_iahb", "ahb", base + 0x70, 0);
- clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "mipi_core_cfg", base + 0x70, 4);
+ clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "pll3_pfd1_540m", base + 0x70, 4);
clk[IMX6QDL_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6);
clk[IMX6QDL_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8);
clk[IMX6QDL_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_per", base + 0x70, 10);
@@ -580,17 +937,27 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk_data.clk_num = ARRAY_SIZE(clk);
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+ clk_register_clkdev(clk[IMX6QDL_CLK_GPT_IPG], "ipg", "imx-gpt.0");
+ clk_register_clkdev(clk[IMX6QDL_CLK_GPT_IPG_PER], "per", "imx-gpt.0");
+ clk_register_clkdev(clk[IMX6QDL_CLK_GPT_3M], "gpt_3m", "imx-gpt.0");
clk_register_clkdev(clk[IMX6QDL_CLK_ENET_REF], "enet_ref", NULL);
- if ((imx_get_soc_revision() != IMX_CHIP_REVISION_1_0) ||
- clk_on_imx6dl()) {
- clk_set_parent(clk[IMX6QDL_CLK_LDB_DI0_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
- clk_set_parent(clk[IMX6QDL_CLK_LDB_DI1_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
- }
-
clk_set_rate(clk[IMX6QDL_CLK_PLL3_PFD1_540M], 540000000);
- if (clk_on_imx6dl())
+ if (clk_on_imx6dl()) {
+ init_ipu_clk(anatop_base);
clk_set_parent(clk[IMX6QDL_CLK_IPU1_SEL], clk[IMX6QDL_CLK_PLL3_PFD1_540M]);
+ clk_set_parent(clk[IMX6QDL_CLK_AXI_ALT_SEL], clk[IMX6QDL_CLK_PLL3_PFD1_540M]);
+ clk_set_parent(clk[IMX6QDL_CLK_AXI_SEL], clk[IMX6QDL_CLK_AXI_ALT_SEL]);
+ /* set epdc/pxp axi clock to 200Mhz */
+ clk_set_parent(clk[IMX6QDL_CLK_IPU2_SEL], clk[IMX6QDL_CLK_PLL2_PFD2_396M]);
+ clk_set_rate(clk[IMX6QDL_CLK_IPU2], 200000000);
+ } else {
+ /* set eim_slow to 132Mhz for i.MX6Q */
+ if (clk_on_imx6q())
+ clk_set_rate(clk[IMX6QDL_CLK_EIM_SLOW], 132000000);
+ clk_set_parent(clk[IMX6QDL_CLK_IPU1_SEL], clk[IMX6QDL_CLK_MMDC_CH0_AXI]);
+ clk_set_parent(clk[IMX6QDL_CLK_IPU2_SEL], clk[IMX6QDL_CLK_MMDC_CH0_AXI]);
+ }
clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI0_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
clk_set_parent(clk[IMX6QDL_CLK_IPU1_DI1_PRE_SEL], clk[IMX6QDL_CLK_PLL5_VIDEO_DIV]);
@@ -601,6 +968,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI0_SEL], clk[IMX6QDL_CLK_IPU2_DI0_PRE]);
clk_set_parent(clk[IMX6QDL_CLK_IPU2_DI1_SEL], clk[IMX6QDL_CLK_IPU2_DI1_PRE]);
+
/*
* The gpmi needs 100MHz frequency in the EDO/Sync mode,
* We can not get the 100MHz from the pll2_pfd0_352m.
@@ -608,30 +976,93 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
*/
clk_set_parent(clk[IMX6QDL_CLK_ENFC_SEL], clk[IMX6QDL_CLK_PLL2_PFD2_396M]);
- for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
- clk_prepare_enable(clk[clks_init_on[i]]);
-
- if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
- clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY1_GATE]);
- clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY2_GATE]);
+ /* gpu clock initilazation */
+ /*
+ * On mx6dl, 2d core clock sources(sel, podf) is from 3d
+ * shader core clock, but 3d shader clock multiplexer of
+ * mx6dl is different. For instance the equivalent of
+ * pll2_pfd_594M on mx6q is pll2_pfd_528M on mx6dl.
+ * Make a note here.
+ */
+ if (clk_on_imx6dl()) {
+ clk_set_parent(clk[IMX6QDL_CLK_GPU3D_SHADER_SEL], clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
+ imx_clk_set_rate(clk[IMX6QDL_CLK_GPU3D_SHADER], 528000000);
+ /* for mx6dl, change gpu3d_core parent to 594_PFD*/
+ clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL], clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
+ imx_clk_set_rate(clk[IMX6QDL_CLK_GPU3D_CORE], 528000000);
+ } else if (clk_on_imx6q()) {
+ if (imx_get_soc_revision() >= IMX_CHIP_REVISION_2_0) {
+ clk_set_parent(clk[IMX6QDL_CLK_GPU3D_SHADER_SEL], clk[IMX6QDL_CLK_PLL3_PFD0_720M]);
+ imx_clk_set_rate(clk[IMX6QDL_CLK_GPU3D_SHADER], 720000000);
+ clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL], clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
+ imx_clk_set_rate(clk[IMX6QDL_CLK_GPU3D_CORE], 594000000);
+ clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL], clk[IMX6QDL_CLK_PLL3_PFD0_720M]);
+ imx_clk_set_rate(clk[IMX6QDL_CLK_GPU2D_CORE], 720000000);
+ } else {
+ clk_set_parent(clk[IMX6QDL_CLK_GPU3D_SHADER_SEL], clk[IMX6QDL_CLK_PLL2_PFD1_594M]);
+ imx_clk_set_rate(clk[IMX6QDL_CLK_GPU3D_SHADER], 594000000);
+ clk_set_parent(clk[IMX6QDL_CLK_GPU3D_CORE_SEL], clk[IMX6QDL_CLK_MMDC_CH0_AXI]);
+ imx_clk_set_rate(clk[IMX6QDL_CLK_GPU3D_CORE], 528000000);
+ clk_set_parent(clk[IMX6QDL_CLK_GPU2D_CORE_SEL], clk[IMX6QDL_CLK_PLL3_USB_OTG]);
+ imx_clk_set_rate(clk[IMX6QDL_CLK_GPU2D_CORE], 480000000);
+ }
}
/*
* Let's initially set up CLKO with OSC24M, since this configuration
* is widely used by imx6q board designs to clock audio codec.
*/
- ret = clk_set_parent(clk[IMX6QDL_CLK_CKO2_SEL], clk[IMX6QDL_CLK_OSC]);
- if (!ret)
- ret = clk_set_parent(clk[IMX6QDL_CLK_CKO], clk[IMX6QDL_CLK_CKO2]);
- if (ret)
- pr_warn("failed to set up CLKO: %d\n", ret);
+ imx_clk_set_parent(clk[IMX6QDL_CLK_CKO2_SEL], clk[IMX6QDL_CLK_OSC]);
+ imx_clk_set_parent(clk[IMX6QDL_CLK_CKO], clk[IMX6QDL_CLK_CKO2]);
/* Audio-related clocks configuration */
clk_set_parent(clk[IMX6QDL_CLK_SPDIF_SEL], clk[IMX6QDL_CLK_PLL3_PFD3_454M]);
/* All existing boards with PCIe use LVDS1 */
- if (IS_ENABLED(CONFIG_PCI_IMX6))
+ if (IS_ENABLED(CONFIG_PCI_IMX6)) {
clk_set_parent(clk[IMX6QDL_CLK_LVDS1_SEL], clk[IMX6QDL_CLK_SATA_REF_100M]);
+ np = of_find_compatible_node(NULL, NULL, "snps,dw-pcie");
+ /* external oscillator is used or not. */
+ if (of_property_read_u32(np, "ext_osc", &val) < 0)
+ val = 0;
+ /*
+ * imx6qp sabresd revb board has the external osc used by pcie
+ * - pll6 should be set bypass mode later in driver.
+ * - lvds_clk1 should be selected as pll6 bypass src, set here.
+ */
+ if (clk_on_imx6qp() && val == 1)
+ clk_set_parent(clk[IMX6QDL_PLL6_BYPASS_SRC], clk[IMX6QDL_CLK_LVDS1_IN]);
+ }
+
+ /*
+ * Enable clocks only after both parent and rate are all initialized
+ * as needed
+ */
+ for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
+ imx_clk_prepare_enable(clk[clks_init_on[i]]);
+
+ if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
+ imx_clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY1_GATE]);
+ imx_clk_prepare_enable(clk[IMX6QDL_CLK_USBPHY2_GATE]);
+ }
+
+ /*Set enet_ref clock to 125M to supply for RGMII tx_clk */
+ clk_set_rate(clk[IMX6QDL_CLK_ENET_REF], 125000000);
+
+#ifdef CONFIG_MX6_VPU_352M
+ /*
+ * If VPU 352M is enabled, then PLL2_PDF2 need to be
+ * set to 352M, cpufreq will be disabled as VDDSOC/PU
+ * need to be at highest voltage, scaling cpu freq is
+ * not saving any power, and busfreq will be also disabled
+ * as the PLL2_PFD2 is not at default freq, in a word,
+ * all modules that sourceing clk from PLL2_PFD2 will
+ * be impacted.
+ */
+ imx_clk_set_rate(clk[IMX6QDL_CLK_PLL2_PFD2_396M], 352000000);
+ clk_set_parent(clk[IMX6QDL_CLK_VPU_AXI_SEL], clk[IMX6QDL_CLK_PLL2_PFD2_396M]);
+ pr_info("VPU 352M is enabled!\n");
+#endif
/*
* Initialize the GPU clock muxes, so that the maximum specified clock
@@ -652,5 +1083,35 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
}
imx_register_uart_clocks(uart_clks);
+
+ /*
+ * for i.MX6QP with speeding grading set to 1.2GHz,
+ * VPU should run at 396MHz.
+ */
+ if (clk_on_imx6q() && imx_get_soc_revision() >= IMX_CHIP_REVISION_2_0) {
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp");
+ WARN_ON(!np);
+
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ /*
+ * SPEED_GRADING[1:0] defines the max speed of ARM:
+ * 2b'11: 1200000000Hz;
+ * 2b'10: 996000000Hz;
+ * 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz.
+ * 2b'00: 792000000Hz;
+ * We need to set the max speed of ARM according to fuse map.
+ */
+ val = readl_relaxed(base + OCOTP_CFG3);
+ val >>= OCOTP_CFG3_SPEED_SHIFT;
+ val &= 0x3;
+ if (val == OCOTP_CFG3_SPEED_1P2GHZ) {
+ imx_clk_set_parent(clk[IMX6QDL_CLK_VPU_AXI_SEL], clk[IMX6QDL_CLK_PLL2_PFD2_396M]);
+ imx_clk_set_rate(clk[IMX6QDL_CLK_VPU_AXI_PODF], 396000000);
+ pr_info("VPU frequency set to 396MHz!\n");
+ }
+ iounmap(base);
+ }
}
CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init);
diff --git a/drivers/clk/imx/clk-imx6sl.c b/drivers/clk/imx/clk-imx6sl.c
index 5fd4ddac1bf1..bedbb7efa2d0 100644
--- a/drivers/clk/imx/clk-imx6sl.c
+++ b/drivers/clk/imx/clk-imx6sl.c
@@ -7,6 +7,7 @@
*
*/
+#include <linux/busfreq-imx.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/err.h>
@@ -18,6 +19,8 @@
#include "clk.h"
#define CCSR 0xc
+#define CCDR 0x04
+#define CCDR_CH0_HS_BYP 17
#define BM_CCSR_PLL1_SW_CLK_SEL (1 << 2)
#define CACRR 0x10
#define CDHIPR 0x48
@@ -55,7 +58,7 @@ static const char *lcdif_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_
static const char *epdc_pix_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0", "pll2_pfd1", "pll3_pfd1", };
static const char *audio_sels[] = { "pll4_audio_div", "pll3_pfd2", "pll3_pfd3", "pll3_usb_otg", };
static const char *ecspi_sels[] = { "pll3_60m", "osc", };
-static const char *uart_sels[] = { "pll3_80m", "osc", };
+static const char *uart_sels[] = { "pll3_80m", "uart_osc_4m", };
static const char *lvds_sels[] = {
"pll1_sys", "pll2_bus", "pll2_pfd0", "pll2_pfd1", "pll2_pfd2", "dummy", "pll4_audio", "pll5_video",
"dummy", "enet_ref", "dummy", "dummy", "pll3_usb_otg", "pll7_usb_host", "pll3_pfd0", "pll3_pfd1",
@@ -143,46 +146,39 @@ static int imx6sl_get_arm_divider_for_wait(void)
}
}
-static void imx6sl_enable_pll_arm(bool enable)
-{
- static u32 saved_pll_arm;
- u32 val;
-
- if (enable) {
- saved_pll_arm = val = readl_relaxed(anatop_base + PLL_ARM);
- val |= BM_PLL_ARM_ENABLE;
- val &= ~BM_PLL_ARM_POWERDOWN;
- writel_relaxed(val, anatop_base + PLL_ARM);
- while (!(__raw_readl(anatop_base + PLL_ARM) & BM_PLL_ARM_LOCK))
- ;
- } else {
- writel_relaxed(saved_pll_arm, anatop_base + PLL_ARM);
- }
-}
-
void imx6sl_set_wait_clk(bool enter)
{
static unsigned long saved_arm_div;
+ u32 val;
int arm_div_for_wait = imx6sl_get_arm_divider_for_wait();
-
- /*
- * According to hardware design, arm podf change need
- * PLL1 clock enabled.
- */
- if (arm_div_for_wait == ARM_WAIT_DIV_396M)
- imx6sl_enable_pll_arm(true);
+ int mode = get_bus_freq_mode();
if (enter) {
- saved_arm_div = readl_relaxed(ccm_base + CACRR);
- writel_relaxed(arm_div_for_wait, ccm_base + CACRR);
+ /*
+ * If in this mode, the IPG clock is at 12MHz, we can
+ * only run ARM at a max 28.8MHz, so we need to run
+ * from the 24MHz OSC, as there is no way to get
+ * 28.8MHz, when ARM is sourced from PLl1.
+ */
+ if (mode == BUS_FREQ_LOW) {
+ val = readl_relaxed(ccm_base + CCSR);
+ val |= BM_CCSR_PLL1_SW_CLK_SEL;
+ writel_relaxed(val, ccm_base + CCSR);
+ } else {
+ saved_arm_div = readl_relaxed(ccm_base + CACRR);
+ writel_relaxed(arm_div_for_wait, ccm_base + CACRR);
+ }
} else {
- writel_relaxed(saved_arm_div, ccm_base + CACRR);
+ if (mode == BUS_FREQ_LOW) {
+ val = readl_relaxed(ccm_base + CCSR);
+ val &= ~BM_CCSR_PLL1_SW_CLK_SEL;
+ writel_relaxed(val, ccm_base + CCSR);
+ } else {
+ writel_relaxed(saved_arm_div, ccm_base + CACRR);
+ }
}
while (__raw_readl(ccm_base + CDHIPR) & BM_CDHIPR_ARM_PODF_BUSY)
;
-
- if (arm_div_for_wait == ARM_WAIT_DIV_396M)
- imx6sl_enable_pll_arm(false);
}
static struct clk ** const uart_clks[] __initconst = {
@@ -195,7 +191,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
void __iomem *base;
- int i;
+ int i, reg;
int ret;
clks[IMX6SL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
@@ -227,7 +223,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
clks[IMX6SL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "osc", base + 0x20, 0x3);
clks[IMX6SL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6SL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6SL_PLL2_BYPASS] = imx_clk_mux_flags_bus("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
clks[IMX6SL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
clks[IMX6SL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
clks[IMX6SL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
@@ -243,7 +239,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
clk_set_parent(clks[IMX6SL_PLL6_BYPASS], clks[IMX6SL_CLK_PLL6]);
clk_set_parent(clks[IMX6SL_PLL7_BYPASS], clks[IMX6SL_CLK_PLL7]);
- clks[IMX6SL_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", base + 0x00, 13);
+ clks[IMX6SL_CLK_PLL1_SYS] = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1);
clks[IMX6SL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
clks[IMX6SL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
clks[IMX6SL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
@@ -271,7 +267,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
clks[IMX6SL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
clks[IMX6SL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
clks[IMX6SL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video", CLK_SET_RATE_PARENT, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
- clks[IMX6SL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
+ clks[IMX6SL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
clks[IMX6SL_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0, base + 0xe0, 0, 2, 0, clk_enet_ref_table, &imx_ccm_lock);
/* name parent_name reg idx */
@@ -288,6 +284,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
clks[IMX6SL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4);
clks[IMX6SL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
clks[IMX6SL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
+ clks[IMX6SL_CLK_UART_OSC_4M] = imx_clk_fixed_factor("uart_osc_4m", "osc", 1, 6);
np = ccm_node;
base = of_iomap(np, 0);
@@ -296,13 +293,13 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
/* name reg shift width parent_names num_parents */
clks[IMX6SL_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
- clks[IMX6SL_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
+ clks[IMX6SL_CLK_PLL1_SW] = imx_clk_mux_glitchless("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
clks[IMX6SL_CLK_OCRAM_ALT_SEL] = imx_clk_mux("ocram_alt_sel", base + 0x14, 7, 1, ocram_alt_sels, ARRAY_SIZE(ocram_alt_sels));
clks[IMX6SL_CLK_OCRAM_SEL] = imx_clk_mux("ocram_sel", base + 0x14, 6, 1, ocram_sels, ARRAY_SIZE(ocram_sels));
- clks[IMX6SL_CLK_PRE_PERIPH2_SEL] = imx_clk_mux("pre_periph2_sel", base + 0x18, 21, 2, pre_periph_sels, ARRAY_SIZE(pre_periph_sels));
- clks[IMX6SL_CLK_PRE_PERIPH_SEL] = imx_clk_mux("pre_periph_sel", base + 0x18, 18, 2, pre_periph_sels, ARRAY_SIZE(pre_periph_sels));
- clks[IMX6SL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
- clks[IMX6SL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+ clks[IMX6SL_CLK_PRE_PERIPH2_SEL] = imx_clk_mux_bus("pre_periph2_sel", base + 0x18, 21, 2, pre_periph_sels, ARRAY_SIZE(pre_periph_sels));
+ clks[IMX6SL_CLK_PRE_PERIPH_SEL] = imx_clk_mux_bus("pre_periph_sel", base + 0x18, 18, 2, pre_periph_sels, ARRAY_SIZE(pre_periph_sels));
+ clks[IMX6SL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux_bus("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+ clks[IMX6SL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux_bus("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
clks[IMX6SL_CLK_CSI_SEL] = imx_clk_mux("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels));
clks[IMX6SL_CLK_LCDIF_AXI_SEL] = imx_clk_mux("lcdif_axi_sel", base + 0x3c, 14, 2, lcdif_axi_sels, ARRAY_SIZE(lcdif_axi_sels));
clks[IMX6SL_CLK_USDHC1_SEL] = imx_clk_fixup_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels), imx_cscmr1_fixup);
@@ -317,8 +314,8 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
clks[IMX6SL_CLK_EPDC_AXI_SEL] = imx_clk_mux("epdc_axi_sel", base + 0x34, 15, 3, epdc_axi_sels, ARRAY_SIZE(epdc_axi_sels));
clks[IMX6SL_CLK_GPU2D_OVG_SEL] = imx_clk_mux("gpu2d_ovg_sel", base + 0x18, 4, 2, gpu2d_ovg_sels, ARRAY_SIZE(gpu2d_ovg_sels));
clks[IMX6SL_CLK_GPU2D_SEL] = imx_clk_mux("gpu2d_sel", base + 0x18, 8, 2, gpu2d_sels, ARRAY_SIZE(gpu2d_sels));
- clks[IMX6SL_CLK_LCDIF_PIX_SEL] = imx_clk_mux("lcdif_pix_sel", base + 0x38, 6, 3, lcdif_pix_sels, ARRAY_SIZE(lcdif_pix_sels));
- clks[IMX6SL_CLK_EPDC_PIX_SEL] = imx_clk_mux("epdc_pix_sel", base + 0x38, 15, 3, epdc_pix_sels, ARRAY_SIZE(epdc_pix_sels));
+ clks[IMX6SL_CLK_LCDIF_PIX_SEL] = imx_clk_mux_flags("lcdif_pix_sel", base + 0x38, 6, 3, lcdif_pix_sels, ARRAY_SIZE(lcdif_pix_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6SL_CLK_EPDC_PIX_SEL] = imx_clk_mux_flags("epdc_pix_sel", base + 0x38, 15, 3, epdc_pix_sels, ARRAY_SIZE(epdc_pix_sels), CLK_SET_RATE_PARENT);
clks[IMX6SL_CLK_SPDIF0_SEL] = imx_clk_mux("spdif0_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
clks[IMX6SL_CLK_SPDIF1_SEL] = imx_clk_mux("spdif1_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
clks[IMX6SL_CLK_EXTERN_AUDIO_SEL] = imx_clk_mux("extern_audio_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels));
@@ -330,7 +327,7 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
clks[IMX6SL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
/* name parent_name reg shift width */
- clks[IMX6SL_CLK_OCRAM_PODF] = imx_clk_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3);
+ clks[IMX6SL_CLK_OCRAM_PODF] = imx_clk_busy_divider("ocram_podf", "ocram_sel", base + 0x14, 16, 3, base + 0x48, 0);
clks[IMX6SL_CLK_PERIPH_CLK2_PODF] = imx_clk_divider("periph_clk2_podf", "periph_clk2_sel", base + 0x14, 27, 3);
clks[IMX6SL_CLK_PERIPH2_CLK2_PODF] = imx_clk_divider("periph2_clk2_podf", "periph2_clk2_sel", base + 0x14, 0, 3);
clks[IMX6SL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2);
@@ -420,6 +417,11 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
clk_data.clk_num = ARRAY_SIZE(clks);
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+ /* Ensure the CH0 handshake is bypassed */
+ reg = readl_relaxed(base + CCDR);
+ reg |= 1 << CCDR_CH0_HS_BYP;
+ writel_relaxed(reg, base + CCDR);
+
/* Ensure the AHB clk is at 132MHz. */
ret = clk_set_rate(clks[IMX6SL_CLK_AHB], 132000000);
if (ret)
@@ -441,6 +443,8 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
/* Audio-related clocks configuration */
clk_set_parent(clks[IMX6SL_CLK_SPDIF0_SEL], clks[IMX6SL_CLK_PLL3_PFD3]);
+ /* Initialize Video PLLs to valid frequency (650MHz). */
+ imx_clk_set_rate(clks[IMX6SL_CLK_PLL5_VIDEO_DIV], 650000000);
/* set PLL5 video as lcdif pix parent clock */
clk_set_parent(clks[IMX6SL_CLK_LCDIF_PIX_SEL],
clks[IMX6SL_CLK_PLL5_VIDEO_DIV]);
@@ -448,6 +452,18 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
clk_set_parent(clks[IMX6SL_CLK_LCDIF_AXI_SEL],
clks[IMX6SL_CLK_PLL2_PFD2]);
+ /* Configure EPDC clocks */
+ clk_set_parent(clks[IMX6SL_CLK_EPDC_PIX_SEL],
+ clks[IMX6SL_CLK_PLL5_VIDEO_DIV]);
+ clk_set_parent(clks[IMX6SL_CLK_EPDC_AXI_SEL],
+ clks[IMX6SL_CLK_PLL2_PFD2]);
+ clk_set_rate(clks[IMX6SL_CLK_EPDC_AXI], 200000000);
+
+ /* Set the UART parent if needed */
+ if (uart_from_osc)
+ imx_clk_set_parent(clks[IMX6SL_CLK_UART_SEL], clks[IMX6SL_CLK_UART_OSC_4M]);
+
imx_register_uart_clocks(uart_clks);
+
}
CLK_OF_DECLARE(imx6sl, "fsl,imx6sl-ccm", imx6sl_clocks_init);
diff --git a/drivers/clk/imx/clk-imx6sll.c b/drivers/clk/imx/clk-imx6sll.c
new file mode 100644
index 000000000000..ff6aaf4143ef
--- /dev/null
+++ b/drivers/clk/imx/clk-imx6sll.c
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <dt-bindings/clock/imx6sll-clock.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/types.h>
+
+#include "clk.h"
+
+#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16)
+#define CCDR 0x4
+
+static const char *pll_bypass_src_sels[] = { "osc", "dummy", };
+static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
+static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
+static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", };
+static const char *pll4_bypass_sels[] = { "pll4", "pll4_bypass_src", };
+static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
+static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
+static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
+static const char *step_sels[] = { "osc", "pll2_pfd2_396m", };
+static const char *pll1_sw_sels[] = { "pll1_sys", "step", };
+static const char *axi_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_540m", };
+static const char *axi_sels[] = {"periph", "axi_alt_sel", };
+static const char *periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll2_198m", };
+static const char *periph2_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", "pll4_audio_div", };
+static const char *periph_clk2_sels[] = { "pll3_usb_otg", "osc", "osc", };
+static const char *periph2_clk2_sels[] = { "pll3_usb_otg", "osc", };
+static const char *periph_sels[] = { "periph_pre", "periph_clk2", };
+static const char *periph2_sels[] = { "periph2_pre", "periph2_clk2", };
+static const char *usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
+static const char *ssi_sels[] = {"pll3_pfd2_508m", "pll3_pfd3_454m", "pll4_audio_div", "dummy",};
+static const char *spdif_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll5_video_div", "pll3_usb_otg", };
+static const char *ldb_di0_div_sels[] = { "ldb_di0_div_3_5", "ldb_di0_div_7", };
+static const char *ldb_di1_div_sels[] = { "ldb_di1_div_3_5", "ldb_di1_div_7", };
+static const char *ldb_di0_sels[] = { "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_pfd3_594m", "pll2_pfd1_594m", "pll3_pfd3_454m", };
+static const char *ldb_di1_sels[] = { "pll3_usb_otg", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll2_bus", "pll3_pfd3_454m", "pll3_pfd2_508m", };
+static const char *lcdif_pre_sels[] = { "pll2_bus", "pll3_pfd3_454m", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_540m", };
+static const char *ecspi_sels[] = { "pll3_60m", "osc", };
+static const char *uart_sels[] = { "pll3_80m", "osc", };
+static const char *perclk_sels[] = { "ipg", "osc", };
+static const char *lcdif_sels[] = { "lcdif_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
+
+static const char *epdc_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", };
+static const char *epdc_sels[] = { "epdc_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
+
+static struct clk *clks[IMX6SLL_CLK_END];
+static struct clk_onecell_data clk_data;
+
+static int const clks_init_on[] __initconst = {
+ IMX6SLL_CLK_AIPSTZ1, IMX6SLL_CLK_AIPSTZ2,
+ IMX6SLL_CLK_OCRAM, IMX6SLL_CLK_ARM, IMX6SLL_CLK_ROM,
+ IMX6SLL_CLK_MMDC_P0_FAST, IMX6SLL_CLK_MMDC_P0_IPG,
+};
+
+static struct clk_div_table post_div_table[] = {
+ { .val = 2, .div = 1, },
+ { .val = 1, .div = 2, },
+ { .val = 0, .div = 4, },
+ { }
+};
+
+static struct clk_div_table video_div_table[] = {
+ { .val = 0, .div = 1, },
+ { .val = 1, .div = 2, },
+ { .val = 2, .div = 1, },
+ { .val = 3, .div = 4, },
+ { }
+};
+
+static u32 share_count_audio;
+static u32 share_count_ssi1;
+static u32 share_count_ssi2;
+static u32 share_count_ssi3;
+
+static void __init imx6sll_clocks_init(struct device_node *ccm_node)
+{
+ struct device_node *np;
+ void __iomem *base;
+ int i;
+
+ clks[IMX6SLL_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+
+ clks[IMX6SLL_CLK_CKIL] = of_clk_get_by_name(ccm_node, "ckil");
+ clks[IMX6SLL_CLK_OSC] = of_clk_get_by_name(ccm_node, "osc");
+
+ /* ipp_di clock is external input */
+ clks[IMX6SLL_CLK_IPP_DI0] = of_clk_get_by_name(ccm_node, "ipp_di0");
+ clks[IMX6SLL_CLK_IPP_DI1] = of_clk_get_by_name(ccm_node, "ipp_di1");
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6sll-anatop");
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks[IMX6SLL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6SLL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6SLL_PLL3_BYPASS_SRC] = imx_clk_mux("pll3_bypass_src", base + 0x10, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6SLL_PLL4_BYPASS_SRC] = imx_clk_mux("pll4_bypass_src", base + 0x70, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6SLL_PLL5_BYPASS_SRC] = imx_clk_mux("pll5_bypass_src", base + 0xa0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6SLL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+ clks[IMX6SLL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
+
+ clks[IMX6SLL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
+ clks[IMX6SLL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
+ clks[IMX6SLL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3);
+ clks[IMX6SLL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
+ clks[IMX6SLL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
+ clks[IMX6SLL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
+ clks[IMX6SLL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3);
+
+ clks[IMX6SLL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6SLL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6SLL_PLL3_BYPASS] = imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6SLL_PLL4_BYPASS] = imx_clk_mux_flags("pll4_bypass", base + 0x70, 16, 1, pll4_bypass_sels, ARRAY_SIZE(pll4_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6SLL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6SLL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6SLL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
+
+ /* Do not bypass PLLs initially */
+ clk_set_parent(clks[IMX6SLL_PLL1_BYPASS], clks[IMX6SLL_CLK_PLL1]);
+ clk_set_parent(clks[IMX6SLL_PLL2_BYPASS], clks[IMX6SLL_CLK_PLL2]);
+ clk_set_parent(clks[IMX6SLL_PLL3_BYPASS], clks[IMX6SLL_CLK_PLL3]);
+ clk_set_parent(clks[IMX6SLL_PLL4_BYPASS], clks[IMX6SLL_CLK_PLL4]);
+ clk_set_parent(clks[IMX6SLL_PLL5_BYPASS], clks[IMX6SLL_CLK_PLL5]);
+ clk_set_parent(clks[IMX6SLL_PLL6_BYPASS], clks[IMX6SLL_CLK_PLL6]);
+ clk_set_parent(clks[IMX6SLL_PLL7_BYPASS], clks[IMX6SLL_CLK_PLL7]);
+
+ clks[IMX6SLL_CLK_PLL1_SYS] = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1);
+ clks[IMX6SLL_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
+ clks[IMX6SLL_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
+ clks[IMX6SLL_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
+ clks[IMX6SLL_CLK_PLL5_VIDEO] = imx_clk_gate("pll5_video", "pll5_bypass", base + 0xa0, 13);
+ clks[IMX6SLL_CLK_PLL6_ENET] = imx_clk_gate("pll6_enet", "pll6_bypass", base + 0xe0, 13);
+ clks[IMX6SLL_CLK_PLL7_USB_HOST] = imx_clk_gate("pll7_usb_host", "pll7_bypass", base + 0x20, 13);
+
+ /*
+ * Bit 20 is the reserved and read-only bit, we do this only for:
+ * - Do nothing for usbphy clk_enable/disable
+ * - Keep refcount when do usbphy clk_enable/disable, in that case,
+ * the clk framework many need to enable/disable usbphy's parent
+ */
+ clks[IMX6SLL_CLK_USBPHY1] = imx_clk_gate("usbphy1", "pll3_usb_otg", base + 0x10, 20);
+ clks[IMX6SLL_CLK_USBPHY2] = imx_clk_gate("usbphy2", "pll7_usb_host", base + 0x20, 20);
+
+ /*
+ * usbphy*_gate needs to be on after system boots up, and software
+ * never needs to control it anymore.
+ */
+ clks[IMX6SLL_CLK_USBPHY1_GATE] = imx_clk_gate("usbphy1_gate", "dummy", base + 0x10, 6);
+ clks[IMX6SLL_CLK_USBPHY2_GATE] = imx_clk_gate("usbphy2_gate", "dummy", base + 0x20, 6);
+
+ /* name parent_name reg idx */
+ clks[IMX6SLL_CLK_PLL2_PFD0] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
+ clks[IMX6SLL_CLK_PLL2_PFD1] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
+ clks[IMX6SLL_CLK_PLL2_PFD2] = imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2);
+ clks[IMX6SLL_CLK_PLL2_PFD3] = imx_clk_pfd("pll2_pfd3_594m", "pll2_bus", base + 0x100, 3);
+ clks[IMX6SLL_CLK_PLL3_PFD0] = imx_clk_pfd("pll3_pfd0_720m", "pll3_usb_otg", base + 0xf0, 0);
+ clks[IMX6SLL_CLK_PLL3_PFD1] = imx_clk_pfd("pll3_pfd1_540m", "pll3_usb_otg", base + 0xf0, 1);
+ clks[IMX6SLL_CLK_PLL3_PFD2] = imx_clk_pfd("pll3_pfd2_508m", "pll3_usb_otg", base + 0xf0, 2);
+ clks[IMX6SLL_CLK_PLL3_PFD3] = imx_clk_pfd("pll3_pfd3_454m", "pll3_usb_otg", base + 0xf0, 3);
+
+ clks[IMX6SLL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio",
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
+ clks[IMX6SLL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div",
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 15, 1, 0, &imx_ccm_lock);
+ clks[IMX6SLL_CLK_PLL5_POST_DIV] = clk_register_divider_table(NULL, "pll5_post_div", "pll5_video",
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xa0, 19, 2, 0, post_div_table, &imx_ccm_lock);
+ clks[IMX6SLL_CLK_PLL5_VIDEO_DIV] = clk_register_divider_table(NULL, "pll5_video_div", "pll5_post_div",
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x170, 30, 2, 0, video_div_table, &imx_ccm_lock);
+
+ /* name parent_name mult div */
+ clks[IMX6SLL_CLK_PLL2_198M] = imx_clk_fixed_factor("pll2_198m", "pll2_pfd2_396m", 1, 2);
+ clks[IMX6SLL_CLK_PLL3_120M] = imx_clk_fixed_factor("pll3_120m", "pll3_usb_otg", 1, 4);
+ clks[IMX6SLL_CLK_PLL3_80M] = imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6);
+ clks[IMX6SLL_CLK_PLL3_60M] = imx_clk_fixed_factor("pll3_60m", "pll3_usb_otg", 1, 8);
+ clks[IMX6SLL_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
+
+ np = ccm_node;
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks[IMX6SLL_CLK_STEP] = imx_clk_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels));
+ clks[IMX6SLL_CLK_PLL1_SW] = imx_clk_mux_glitchless("pll1_sw", base + 0x0c, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
+ clks[IMX6SLL_CLK_AXI_ALT_SEL] = imx_clk_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
+ clks[IMX6SLL_CLK_AXI_SEL] = imx_clk_mux_flags("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels), 0);
+ clks[IMX6SLL_CLK_PERIPH_PRE] = imx_clk_mux_bus("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+ clks[IMX6SLL_CLK_PERIPH2_PRE] = imx_clk_mux_bus("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
+ clks[IMX6SLL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux_bus("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+ clks[IMX6SLL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux_bus("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+ clks[IMX6SLL_CLK_USDHC2_SEL] = imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ clks[IMX6SLL_CLK_USDHC1_SEL] = imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ clks[IMX6SLL_CLK_USDHC3_SEL] = imx_clk_mux("usdhc3_sel", base + 0x1c, 18, 1, usdhc_sels, ARRAY_SIZE(usdhc_sels));
+ clks[IMX6SLL_CLK_SSI1_SEL] = imx_clk_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+ clks[IMX6SLL_CLK_SSI2_SEL] = imx_clk_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+ clks[IMX6SLL_CLK_SSI3_SEL] = imx_clk_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
+ clks[IMX6SLL_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels));
+ clks[IMX6SLL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
+ clks[IMX6SLL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
+ clks[IMX6SLL_CLK_EXTERN_AUDIO_SEL] = imx_clk_mux("extern_audio_sel", base + 0x30, 7, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
+ clks[IMX6SLL_CLK_EPDC_PRE_SEL] = imx_clk_mux("epdc_pre_sel", base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels));
+ clks[IMX6SLL_CLK_EPDC_SEL] = imx_clk_mux("epdc_sel", base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels));
+ clks[IMX6SLL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
+ clks[IMX6SLL_CLK_LCDIF_PRE_SEL] = imx_clk_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels));
+ clks[IMX6SLL_CLK_LCDIF_SEL] = imx_clk_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
+
+ clks[IMX6SLL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
+ clks[IMX6SLL_CLK_PERIPH2] = imx_clk_busy_mux("periph2", base + 0x14, 26, 1, base + 0x48, 3, periph2_sels, ARRAY_SIZE(periph2_sels));
+
+ clks[IMX6SLL_CLK_PERIPH_CLK2] = imx_clk_divider("periph_clk2", "periph_clk2_sel", base + 0x14, 27, 3);
+ clks[IMX6SLL_CLK_PERIPH2_CLK2] = imx_clk_divider("periph2_clk2", "periph2_clk2_sel", base + 0x14, 0, 3);
+ clks[IMX6SLL_CLK_IPG] = imx_clk_divider("ipg", "ahb", base + 0x14, 8, 2);
+ clks[IMX6SLL_CLK_LCDIF_PODF] = imx_clk_divider("lcdif_podf", "lcdif_pred", base + 0x18, 23, 3);
+ clks[IMX6SLL_CLK_PERCLK] = imx_clk_divider("perclk", "perclk_sel", base + 0x1c, 0, 6);
+ clks[IMX6SLL_CLK_USDHC3_PODF] = imx_clk_divider("usdhc3_podf", "usdhc3_sel", base + 0x24, 19, 3);
+ clks[IMX6SLL_CLK_USDHC2_PODF] = imx_clk_divider("usdhc2_podf", "usdhc2_sel", base + 0x24, 16, 3);
+ clks[IMX6SLL_CLK_USDHC1_PODF] = imx_clk_divider("usdhc1_podf", "usdhc1_sel", base + 0x24, 11, 3);
+ clks[IMX6SLL_CLK_UART_PODF] = imx_clk_divider("uart_podf", "uart_sel", base + 0x24, 0, 6);
+ clks[IMX6SLL_CLK_SSI3_PRED] = imx_clk_divider("ssi3_pred", "ssi3_sel", base + 0x28, 22, 3);
+ clks[IMX6SLL_CLK_SSI3_PODF] = imx_clk_divider("ssi3_podf", "ssi3_pred", base + 0x28, 16, 6);
+ clks[IMX6SLL_CLK_SSI1_PRED] = imx_clk_divider("ssi1_pred", "ssi1_sel", base + 0x28, 6, 3);
+ clks[IMX6SLL_CLK_SSI1_PODF] = imx_clk_divider("ssi1_podf", "ssi1_pred", base + 0x28, 0, 6);
+ clks[IMX6SLL_CLK_SSI2_PRED] = imx_clk_divider("ssi2_pred", "ssi2_sel", base + 0x2c, 6, 3);
+ clks[IMX6SLL_CLK_SSI2_PODF] = imx_clk_divider("ssi2_podf", "ssi2_pred", base + 0x2c, 0, 6);
+ clks[IMX6SLL_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3);
+ clks[IMX6SLL_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3);
+ clks[IMX6SLL_CLK_EXTERN_AUDIO_PRED] = imx_clk_divider("extern_audio_pred", "extern_audio_sel", base + 0x30, 12, 3);
+ clks[IMX6SLL_CLK_EXTERN_AUDIO_PODF] = imx_clk_divider("extern_audio_podf", "extern_audio_pred", base + 0x30, 9, 3);
+ clks[IMX6SLL_CLK_EPDC_PODF] = imx_clk_divider("epdc_podf", "epdc_pre_sel", base + 0x34, 12, 3);
+ clks[IMX6SLL_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6);
+ clks[IMX6SLL_CLK_LCDIF_PRED] = imx_clk_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3);
+
+ clks[IMX6SLL_CLK_ARM] = imx_clk_busy_divider("arm", "pll1_sw", base + 0x10, 0, 3, base + 0x48, 16);
+ clks[IMX6SLL_CLK_MMDC_PODF] = imx_clk_busy_divider("mmdc_podf", "periph2", base + 0x14, 3, 3, base + 0x48, 2);
+ clks[IMX6SLL_CLK_AXI_PODF] = imx_clk_busy_divider("axi", "axi_sel", base + 0x14, 16, 3, base + 0x48, 0);
+ clks[IMX6SLL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1);
+
+ clks[IMX6SLL_CLK_LDB_DI0_DIV_3_5] = imx_clk_fixed_factor("ldb_di0_div_3_5", "ldb_di0_sel", 2, 7);
+ clks[IMX6SLL_CLK_LDB_DI0_DIV_7] = imx_clk_fixed_factor("ldb_di0_div_7", "ldb_di0_sel", 1, 7);
+ clks[IMX6SLL_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
+ clks[IMX6SLL_CLK_LDB_DI1_DIV_7] = imx_clk_fixed_factor("ldb_di1_div_7", "ldb_di1_sel", 1, 7);
+
+ clks[IMX6SLL_CLK_LDB_DI0_SEL] = imx_clk_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
+ clks[IMX6SLL_CLK_LDB_DI1_SEL] = imx_clk_mux("ldb_di1_sel", base + 0x1c, 7, 3, ldb_di1_sels, ARRAY_SIZE(ldb_di1_sels));
+ clks[IMX6SLL_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux("ldb_di0_div_sel", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
+ clks[IMX6SLL_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux("ldb_di1_div_sel", base + 0x20, 10, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
+
+ /* CCGR0 */
+ clks[IMX6SLL_CLK_AIPSTZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0);
+ clks[IMX6SLL_CLK_AIPSTZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2);
+ clks[IMX6SLL_CLK_DCP] = imx_clk_gate2("dcp", "ahb", base + 0x68, 10);
+ clks[IMX6SLL_CLK_UART2_IPG] = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28);
+ clks[IMX6SLL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28);
+
+ /* CCGR1 */
+ clks[IMX6SLL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0);
+ clks[IMX6SLL_CLK_ECSPI2] = imx_clk_gate2("ecspi2", "ecspi_podf", base + 0x6c, 2);
+ clks[IMX6SLL_CLK_ECSPI3] = imx_clk_gate2("ecspi3", "ecspi_podf", base + 0x6c, 4);
+ clks[IMX6SLL_CLK_ECSPI4] = imx_clk_gate2("ecspi4", "ecspi_podf", base + 0x6c, 6);
+ clks[IMX6SLL_CLK_UART3_IPG] = imx_clk_gate2("uart3_ipg", "ipg", base + 0x6c, 10);
+ clks[IMX6SLL_CLK_UART3_SERIAL] = imx_clk_gate2("uart3_serial", "uart_podf", base + 0x6c, 10);
+ clks[IMX6SLL_CLK_EPIT1] = imx_clk_gate2("epit1", "perclk", base + 0x6c, 12);
+ clks[IMX6SLL_CLK_EPIT2] = imx_clk_gate2("epit2", "perclk", base + 0x6c, 14);
+ clks[IMX6SLL_CLK_GPT_BUS] = imx_clk_gate2("gpt1_bus", "perclk", base + 0x6c, 20);
+ clks[IMX6SLL_CLK_GPT_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22);
+ clks[IMX6SLL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24);
+ clks[IMX6SLL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serail", "uart_podf", base + 0x6c, 24);
+
+ /* CCGR2 */
+ clks[IMX6SLL_CLK_CSI] = imx_clk_gate2("csi", "axi", base + 0x70, 2);
+ clks[IMX6SLL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6);
+ clks[IMX6SLL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8);
+ clks[IMX6SLL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10);
+ clks[IMX6SLL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12);
+ clks[IMX6SLL_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "axi", base + 0x70, 28);
+ clks[IMX6SLL_CLK_PXP] = imx_clk_gate2("pxp", "axi", base + 0x70, 30);
+
+ /* CCGR3 */
+ clks[IMX6SLL_CLK_UART5_IPG] = imx_clk_gate2("uart5_ipg", "ipg", base + 0x74, 2);
+ clks[IMX6SLL_CLK_UART5_SERIAL] = imx_clk_gate2("uart5_serial", "uart_podf", base + 0x74, 2);
+ clks[IMX6SLL_CLK_EPDC_AXI] = imx_clk_gate2("epdc_aclk", "axi", base + 0x74, 4);
+ clks[IMX6SLL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_podf", base + 0x74, 4);
+ clks[IMX6SLL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10);
+ clks[IMX6SLL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16);
+ clks[IMX6SLL_CLK_MMDC_P0_FAST] = imx_clk_gate("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20);
+ clks[IMX6SLL_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24);
+ clks[IMX6SLL_CLK_OCRAM] = imx_clk_gate("ocram", "ahb", base + 0x74, 28);
+
+ /* CCGR4 */
+ clks[IMX6SLL_CLK_PWM1] = imx_clk_gate2("pwm1", "perclk", base + 0x78, 16);
+ clks[IMX6SLL_CLK_PWM2] = imx_clk_gate2("pwm2", "perclk", base + 0x78, 18);
+ clks[IMX6SLL_CLK_PWM3] = imx_clk_gate2("pwm3", "perclk", base + 0x78, 20);
+ clks[IMX6SLL_CLK_PWM4] = imx_clk_gate2("pwm4", "perclk", base + 0x78, 22);
+
+ /* CCGR5 */
+ clks[IMX6SLL_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0);
+ clks[IMX6SLL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6);
+ clks[IMX6SLL_CLK_WDOG2] = imx_clk_gate2("wdog2", "ipg", base + 0x7c, 10);
+ clks[IMX6SLL_CLK_SPBA] = imx_clk_gate2("spba", "ipg", base + 0x7c, 12);
+ clks[IMX6SLL_CLK_EXTERN_AUDIO] = imx_clk_gate2_shared("extern_audio", "extern_audio_podf", base + 0x7c, 14, &share_count_audio);
+ clks[IMX6SLL_CLK_SPDIF] = imx_clk_gate2_shared("spdif", "spdif_podf", base + 0x7c, 14, &share_count_audio);
+ clks[IMX6SLL_CLK_SPDIF_GCLK] = imx_clk_gate2_shared("spdif_gclk", "ipg", base + 0x7c, 14, &share_count_audio);
+ clks[IMX6SLL_CLK_SSI1] = imx_clk_gate2_shared("ssi1", "ssi1_podf", base + 0x7c, 18, &share_count_ssi1);
+ clks[IMX6SLL_CLK_SSI1_IPG] = imx_clk_gate2_shared("ssi1_ipg", "ipg", base + 0x7c, 18, &share_count_ssi1);
+ clks[IMX6SLL_CLK_SSI2] = imx_clk_gate2_shared("ssi2", "ssi2_podf", base + 0x7c, 20, &share_count_ssi2);
+ clks[IMX6SLL_CLK_SSI2_IPG] = imx_clk_gate2_shared("ssi2_ipg", "ipg", base + 0x7c, 20, &share_count_ssi2);
+ clks[IMX6SLL_CLK_SSI3] = imx_clk_gate2_shared("ssi3", "ssi3_podf", base + 0x7c, 22, &share_count_ssi3);
+ clks[IMX6SLL_CLK_SSI3_IPG] = imx_clk_gate2_shared("ssi3_ipg", "ipg", base + 0x7c, 22, &share_count_ssi3);
+ clks[IMX6SLL_CLK_UART1_IPG] = imx_clk_gate2("uart1_ipg", "ipg", base + 0x7c, 24);
+ clks[IMX6SLL_CLK_UART1_SERIAL] = imx_clk_gate2("uart1_serial", "uart_podf", base + 0x7c, 24);
+
+ /* CCGR6 */
+ clks[IMX6SLL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0);
+ clks[IMX6SLL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
+ clks[IMX6SLL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
+ clks[IMX6SLL_CLK_USDHC3] = imx_clk_gate2("usdhc3", "usdhc3_podf", base + 0x80, 6);
+
+ /* mask handshake of mmdc */
+ writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
+
+ for (i = 0; i < ARRAY_SIZE(clks); i++)
+ if (IS_ERR(clks[i]))
+ pr_err("i.MX6SLL clk %d: register failed with %ld\n", i, PTR_ERR(clks[i]));
+
+ clk_data.clks = clks;
+ clk_data.clk_num = ARRAY_SIZE(clks);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+
+ /* set perclk to from OSC */
+ clk_set_parent(clks[IMX6SLL_CLK_PERCLK_SEL], clks[IMX6SLL_CLK_OSC]);
+
+ /* Set the UART parent if needed */
+ if (uart_from_osc)
+ imx_clk_set_parent(clks[IMX6SLL_CLK_UART_SEL], clks[IMX6SLL_CLK_OSC]);
+ else
+ imx_clk_set_parent(clks[IMX6SLL_CLK_UART_SEL], clks[IMX6SLL_CLK_PLL3_80M]);
+
+ for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
+ clk_prepare_enable(clks[clks_init_on[i]]);
+
+ if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
+ clk_prepare_enable(clks[IMX6SLL_CLK_USBPHY1_GATE]);
+ clk_prepare_enable(clks[IMX6SLL_CLK_USBPHY2_GATE]);
+ }
+
+ /* Lower the AHB clock rate before changing the clock source. */
+ imx_clk_set_rate(clks[IMX6SLL_CLK_AHB], 99000000);
+
+ /* Change periph_pre clock to pll2_bus to adjust AXI rate to 264MHz */
+ imx_clk_set_parent(clks[IMX6SLL_CLK_PERIPH_CLK2_SEL], clks[IMX6SLL_CLK_PLL3_USB_OTG]);
+ imx_clk_set_parent(clks[IMX6SLL_CLK_PERIPH], clks[IMX6SLL_CLK_PERIPH_CLK2]);
+ imx_clk_set_parent(clks[IMX6SLL_CLK_PERIPH_PRE], clks[IMX6SLL_CLK_PLL2_BUS]);
+ imx_clk_set_parent(clks[IMX6SLL_CLK_PERIPH], clks[IMX6SLL_CLK_PERIPH_PRE]);
+
+ imx_clk_set_rate(clks[IMX6SLL_CLK_AHB], 132000000);
+
+ /* Configure EPDC clocks */
+ imx_clk_set_rate(clks[IMX6SLL_CLK_PLL3_PFD2], 320000000);
+ clk_set_parent(clks[IMX6SLL_CLK_EPDC_PRE_SEL],
+ clks[IMX6SLL_CLK_PLL3_PFD2]);
+
+}
+
+CLK_OF_DECLARE(imx6sll, "fsl,imx6sll-ccm", imx6sll_clocks_init);
+
diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c
index b5c96de41ccf..a6be682ed011 100644
--- a/drivers/clk/imx/clk-imx6sx.c
+++ b/drivers/clk/imx/clk-imx6sx.c
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
@@ -13,15 +14,19 @@
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/err.h>
+#include <linux/imx_sema4.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/types.h>
+#include <soc/imx/gpc.h>
+#include <soc/imx/src.h>
#include "clk.h"
+#define CCM_CCGR_OFFSET(index) (index * 2)
#define CCDR 0x4
#define BM_CCM_CCDR_MMDC_CH0_MASK (0x2 << 16)
@@ -80,7 +85,7 @@ static const char *lvds_sels[] = {
"arm", "pll1_sys", "dummy", "dummy", "dummy", "dummy", "dummy", "pll5_video_div",
"dummy", "dummy", "pcie_ref_125m", "dummy", "usbphy1", "usbphy2",
};
-static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", };
+static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", "lvds2_in", "dummy", };
static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };
static const char *pll2_bypass_sels[] = { "pll2", "pll2_bypass_src", };
static const char *pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", };
@@ -91,18 +96,19 @@ static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
static struct clk *clks[IMX6SX_CLK_CLK_END];
static struct clk_onecell_data clk_data;
+struct imx_sema4_mutex *amp_power_mutex;
+
+static int clks_shared[MAX_SHARED_CLK_NUMBER];
+
+struct imx_shared_mem *shared_mem;
+static unsigned int shared_mem_paddr, shared_mem_size;
static int const clks_init_on[] __initconst = {
IMX6SX_CLK_AIPS_TZ1, IMX6SX_CLK_AIPS_TZ2, IMX6SX_CLK_AIPS_TZ3,
IMX6SX_CLK_IPMUX1, IMX6SX_CLK_IPMUX2, IMX6SX_CLK_IPMUX3,
IMX6SX_CLK_WAKEUP, IMX6SX_CLK_MMDC_P0_FAST, IMX6SX_CLK_MMDC_P0_IPG,
IMX6SX_CLK_ROM, IMX6SX_CLK_ARM, IMX6SX_CLK_IPG, IMX6SX_CLK_OCRAM,
- IMX6SX_CLK_PER2_MAIN, IMX6SX_CLK_PERCLK, IMX6SX_CLK_M4,
- IMX6SX_CLK_QSPI1, IMX6SX_CLK_QSPI2, IMX6SX_CLK_UART_IPG,
- IMX6SX_CLK_UART_SERIAL, IMX6SX_CLK_I2C3, IMX6SX_CLK_ECSPI5,
- IMX6SX_CLK_CAN1_IPG, IMX6SX_CLK_CAN1_SERIAL, IMX6SX_CLK_CAN2_IPG,
- IMX6SX_CLK_CAN2_SERIAL, IMX6SX_CLK_CANFD, IMX6SX_CLK_EPIT1,
- IMX6SX_CLK_EPIT2,
+ IMX6SX_CLK_PER2_MAIN, IMX6SX_CLK_PERCLK, IMX6SX_CLK_TZASC1,
};
static struct clk_div_table clk_enet_ref_table[] = {
@@ -143,6 +149,38 @@ static struct clk ** const uart_clks[] __initconst = {
NULL
};
+/*
+ * As IMX6SX_CLK_M4_PRE_SEL is NOT a glitchless MUX, so when
+ * M4 is trying to change its clk parent, need to ask A9 to
+ * help do it, and M4 must be hold in wfi. To avoid glitch
+ * occur, need to gate M4 clk first before switching its parent.
+ */
+void imx6sx_set_m4_highfreq(bool high_freq)
+{
+ static struct clk *m4_high_freq_sel;
+
+ imx_gpc_hold_m4_in_sleep();
+
+ clk_disable_unprepare(clks[IMX6SX_CLK_M4]);
+ imx_clk_set_parent(clks[IMX6SX_CLK_M4_SEL],
+ clks[IMX6SX_CLK_LDB_DI0]);
+
+ if (high_freq) {
+ imx_clk_set_parent(clks[IMX6SX_CLK_M4_PRE_SEL],
+ m4_high_freq_sel);
+ } else {
+ m4_high_freq_sel = clk_get_parent(clks[IMX6SX_CLK_M4_PRE_SEL]);
+ imx_clk_set_parent(clks[IMX6SX_CLK_M4_PRE_SEL],
+ clks[IMX6SX_CLK_OSC]);
+ }
+
+ imx_clk_set_parent(clks[IMX6SX_CLK_M4_SEL],
+ clks[IMX6SX_CLK_M4_PRE_SEL]);
+ clk_prepare_enable(clks[IMX6SX_CLK_M4]);
+
+ imx_gpc_release_m4_in_sleep();
+}
+
static void __init imx6sx_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
@@ -160,6 +198,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
/* Clock source from external clock via CLK1 PAD */
clks[IMX6SX_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
+ clks[IMX6SX_CLK_ANACLK2] = imx_obtain_fixed_clock("anaclk2", 0);
np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-anatop");
base = of_iomap(np, 0);
@@ -175,7 +214,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
/* type name parent_name base div_mask */
clks[IMX6SX_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f);
- clks[IMX6SX_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
+ clks[IMX6SX_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_PLL2, "pll2", "osc", base + 0x30, 0x1);
clks[IMX6SX_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3);
clks[IMX6SX_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f);
clks[IMX6SX_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f);
@@ -191,15 +230,15 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clks[IMX6SX_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
/* Do not bypass PLLs initially */
- clk_set_parent(clks[IMX6SX_PLL1_BYPASS], clks[IMX6SX_CLK_PLL1]);
- clk_set_parent(clks[IMX6SX_PLL2_BYPASS], clks[IMX6SX_CLK_PLL2]);
- clk_set_parent(clks[IMX6SX_PLL3_BYPASS], clks[IMX6SX_CLK_PLL3]);
- clk_set_parent(clks[IMX6SX_PLL4_BYPASS], clks[IMX6SX_CLK_PLL4]);
- clk_set_parent(clks[IMX6SX_PLL5_BYPASS], clks[IMX6SX_CLK_PLL5]);
- clk_set_parent(clks[IMX6SX_PLL6_BYPASS], clks[IMX6SX_CLK_PLL6]);
- clk_set_parent(clks[IMX6SX_PLL7_BYPASS], clks[IMX6SX_CLK_PLL7]);
-
- clks[IMX6SX_CLK_PLL1_SYS] = imx_clk_gate("pll1_sys", "pll1_bypass", base + 0x00, 13);
+ imx_clk_set_parent(clks[IMX6SX_PLL1_BYPASS], clks[IMX6SX_CLK_PLL1]);
+ imx_clk_set_parent(clks[IMX6SX_PLL2_BYPASS], clks[IMX6SX_CLK_PLL2]);
+ imx_clk_set_parent(clks[IMX6SX_PLL3_BYPASS], clks[IMX6SX_CLK_PLL3]);
+ imx_clk_set_parent(clks[IMX6SX_PLL4_BYPASS], clks[IMX6SX_CLK_PLL4]);
+ imx_clk_set_parent(clks[IMX6SX_PLL5_BYPASS], clks[IMX6SX_CLK_PLL5]);
+ imx_clk_set_parent(clks[IMX6SX_PLL6_BYPASS], clks[IMX6SX_CLK_PLL6]);
+ imx_clk_set_parent(clks[IMX6SX_PLL7_BYPASS], clks[IMX6SX_CLK_PLL7]);
+
+ clks[IMX6SX_CLK_PLL1_SYS] = imx_clk_fixed_factor("pll1_sys", "pll1_bypass", 1, 1);
clks[IMX6SX_CLK_PLL2_BUS] = imx_clk_gate("pll2_bus", "pll2_bypass", base + 0x30, 13);
clks[IMX6SX_CLK_PLL3_USB_OTG] = imx_clk_gate("pll3_usb_otg", "pll3_bypass", base + 0x10, 13);
clks[IMX6SX_CLK_PLL4_AUDIO] = imx_clk_gate("pll4_audio", "pll4_bypass", base + 0x70, 13);
@@ -228,7 +267,9 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clks[IMX6SX_CLK_PCIE_REF_125M] = imx_clk_gate("pcie_ref_125m", "pcie_ref", base + 0xe0, 19);
clks[IMX6SX_CLK_LVDS1_OUT] = imx_clk_gate_exclusive("lvds1_out", "lvds1_sel", base + 0x160, 10, BIT(12));
+ clks[IMX6SX_CLK_LVDS2_OUT] = imx_clk_gate_exclusive("lvds2_out", "lvds2_sel", base + 0x160, 11, BIT(13));
clks[IMX6SX_CLK_LVDS1_IN] = imx_clk_gate_exclusive("lvds1_in", "anaclk1", base + 0x160, 12, BIT(10));
+ clks[IMX6SX_CLK_LVDS2_IN] = imx_clk_gate_exclusive("lvds2_in", "anaclk2", base + 0x160, 13, BIT(11));
clks[IMX6SX_CLK_ENET_REF] = clk_register_divider_table(NULL, "enet_ref", "pll6_enet", 0,
base + 0xe0, 0, 2, 0, clk_enet_ref_table,
@@ -270,6 +311,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
/* name reg shift width parent_names num_parents */
clks[IMX6SX_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+ clks[IMX6SX_CLK_LVDS2_SEL] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
np = ccm_node;
base = of_iomap(np, 0);
@@ -277,12 +319,12 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
/* name reg shift width parent_names num_parents */
clks[IMX6SX_CLK_STEP] = imx_clk_mux("step", base + 0xc, 8, 1, step_sels, ARRAY_SIZE(step_sels));
- clks[IMX6SX_CLK_PLL1_SW] = imx_clk_mux("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
+ clks[IMX6SX_CLK_PLL1_SW] = imx_clk_mux_glitchless("pll1_sw", base + 0xc, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
clks[IMX6SX_CLK_OCRAM_SEL] = imx_clk_mux("ocram_sel", base + 0x14, 6, 2, ocram_sels, ARRAY_SIZE(ocram_sels));
- clks[IMX6SX_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
- clks[IMX6SX_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
- clks[IMX6SX_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
- clks[IMX6SX_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+ clks[IMX6SX_CLK_PERIPH_PRE] = imx_clk_mux_bus("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+ clks[IMX6SX_CLK_PERIPH2_PRE] = imx_clk_mux_bus("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
+ clks[IMX6SX_CLK_PERIPH_CLK2_SEL] = imx_clk_mux_bus("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+ clks[IMX6SX_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux_bus("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
clks[IMX6SX_CLK_PCIE_AXI_SEL] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels));
clks[IMX6SX_CLK_GPU_AXI_SEL] = imx_clk_mux("gpu_axi_sel", base + 0x18, 8, 2, gpu_axi_sels, ARRAY_SIZE(gpu_axi_sels));
clks[IMX6SX_CLK_GPU_CORE_SEL] = imx_clk_mux("gpu_core_sel", base + 0x18, 4, 2, gpu_core_sels, ARRAY_SIZE(gpu_core_sels));
@@ -294,13 +336,13 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clks[IMX6SX_CLK_SSI3_SEL] = imx_clk_mux("ssi3_sel", base + 0x1c, 14, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
clks[IMX6SX_CLK_SSI2_SEL] = imx_clk_mux("ssi2_sel", base + 0x1c, 12, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
clks[IMX6SX_CLK_SSI1_SEL] = imx_clk_mux("ssi1_sel", base + 0x1c, 10, 2, ssi_sels, ARRAY_SIZE(ssi_sels));
- clks[IMX6SX_CLK_QSPI1_SEL] = imx_clk_mux_flags("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6SX_CLK_QSPI1_SEL] = imx_clk_mux("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels));
clks[IMX6SX_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels));
clks[IMX6SX_CLK_VID_SEL] = imx_clk_mux("vid_sel", base + 0x20, 21, 3, vid_sels, ARRAY_SIZE(vid_sels));
clks[IMX6SX_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", base + 0x20, 19, 2, audio_sels, ARRAY_SIZE(audio_sels));
clks[IMX6SX_CLK_CAN_SEL] = imx_clk_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels));
clks[IMX6SX_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
- clks[IMX6SX_CLK_QSPI2_SEL] = imx_clk_mux_flags("qspi2_sel", base + 0x2c, 15, 3, qspi2_sels, ARRAY_SIZE(qspi2_sels), CLK_SET_RATE_PARENT);
+ clks[IMX6SX_CLK_QSPI2_SEL] = imx_clk_mux("qspi2_sel", base + 0x2c, 15, 3, qspi2_sels, ARRAY_SIZE(qspi2_sels));
clks[IMX6SX_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, audio_sels, ARRAY_SIZE(audio_sels));
clks[IMX6SX_CLK_AUDIO_SEL] = imx_clk_mux("audio_sel", base + 0x30, 7, 2, audio_sels, ARRAY_SIZE(audio_sels));
clks[IMX6SX_CLK_ENET_PRE_SEL] = imx_clk_mux("enet_pre_sel", base + 0x34, 15, 3, enet_pre_sels, ARRAY_SIZE(enet_pre_sels));
@@ -494,79 +536,196 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clks[IMX6SX_CLK_CKO1] = imx_clk_gate("cko1", "cko1_podf", base + 0x60, 7);
clks[IMX6SX_CLK_CKO2] = imx_clk_gate("cko2", "cko2_podf", base + 0x60, 24);
+ /* get those shared clk nodes if M4 is active */
+ if (imx_src_is_m4_enabled()) {
+ u32 num;
+
+ of_property_read_u32(np, "fsl,shared-clks-number", &num);
+ if (num > MAX_SHARED_CLK_NUMBER)
+ pr_err("clk: shared clk nodes exceed the max number!\n");
+ of_property_read_u32_array(np, "fsl,shared-clks-index",
+ clks_shared, num);
+ if (of_property_read_u32(np, "fsl,shared-mem-addr",
+ &shared_mem_paddr))
+ pr_err("clk: fsl,shared-mem-addr NOT found!\n");
+ if (of_property_read_u32(np, "fsl,shared-mem-size",
+ &shared_mem_size))
+ pr_err("clk: fsl,shared-mem-size NOT found!\n");
+ }
+
/* mask handshake of mmdc */
writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
imx_check_clocks(clks, ARRAY_SIZE(clks));
+ /*
+ * QSPI2/GPMI_IO share the same clock source but with the
+ * different gate, need explicitely gate the QSPI2 & GPMI_IO
+ * during the clock init phase according to the SOC design.
+ */
+ if (!imx_src_is_m4_enabled()) {
+ writel_relaxed(readl_relaxed(base + 0x78) &
+ ~(3 << CCM_CCGR_OFFSET(5)), base + 0x78);
+ writel_relaxed(readl_relaxed(base + 0x78) &
+ ~(3 << CCM_CCGR_OFFSET(14)), base + 0x78);
+ }
+
clk_data.clks = clks;
clk_data.clk_num = ARRAY_SIZE(clks);
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
- for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
- clk_prepare_enable(clks[clks_init_on[i]]);
+ /*
+ * As some of the modules need to access ocotp in MSL,
+ * need to make sure ocotp clk(CCM_CCGR2_CG6) is enabled
+ * during MSL, as on i.MX6SX, accessing OCOTP registers
+ * needs its clk on, it will be disabled by clk late
+ * init and managed by ocotp driver.
+ */
+ writel_relaxed(readl_relaxed(base + 0x70) | 1 << 12, base + 0x70);
+
+ /* maintain M4 usecount */
+ if (imx_src_is_m4_enabled())
+ imx_clk_prepare_enable(clks[IMX6SX_CLK_M4]);
+
+ /* set perclk to from OSC */
+ imx_clk_set_parent(clks[IMX6SX_CLK_PERCLK_SEL], clks[IMX6SX_CLK_OSC]);
if (IS_ENABLED(CONFIG_USB_MXS_PHY)) {
- clk_prepare_enable(clks[IMX6SX_CLK_USBPHY1_GATE]);
- clk_prepare_enable(clks[IMX6SX_CLK_USBPHY2_GATE]);
+ imx_clk_prepare_enable(clks[IMX6SX_CLK_USBPHY1_GATE]);
+ imx_clk_prepare_enable(clks[IMX6SX_CLK_USBPHY2_GATE]);
}
/* Set the default 132MHz for EIM module */
- clk_set_parent(clks[IMX6SX_CLK_EIM_SLOW_SEL], clks[IMX6SX_CLK_PLL2_PFD2]);
- clk_set_rate(clks[IMX6SX_CLK_EIM_SLOW], 132000000);
+ imx_clk_set_parent(clks[IMX6SX_CLK_EIM_SLOW_SEL], clks[IMX6SX_CLK_PLL2_PFD2]);
+ imx_clk_set_rate(clks[IMX6SX_CLK_EIM_SLOW], 132000000);
/* set parent clock for LCDIF1 pixel clock */
- clk_set_parent(clks[IMX6SX_CLK_LCDIF1_PRE_SEL], clks[IMX6SX_CLK_PLL5_VIDEO_DIV]);
- clk_set_parent(clks[IMX6SX_CLK_LCDIF1_SEL], clks[IMX6SX_CLK_LCDIF1_PODF]);
+ imx_clk_set_parent(clks[IMX6SX_CLK_LCDIF1_PRE_SEL], clks[IMX6SX_CLK_PLL5_VIDEO_DIV]);
+ imx_clk_set_parent(clks[IMX6SX_CLK_LCDIF1_SEL], clks[IMX6SX_CLK_LCDIF1_PODF]);
+
+ /* set parent clock for LCDIF2 */
+ imx_clk_set_parent(clks[IMX6SX_CLK_LCDIF2_SEL], clks[IMX6SX_CLK_LDB_DI0]);
/* Set the parent clks of PCIe lvds1 and pcie_axi to be pcie ref, axi */
- if (clk_set_parent(clks[IMX6SX_CLK_LVDS1_SEL], clks[IMX6SX_CLK_PCIE_REF_125M]))
- pr_err("Failed to set pcie bus parent clk.\n");
- if (clk_set_parent(clks[IMX6SX_CLK_PCIE_AXI_SEL], clks[IMX6SX_CLK_AXI]))
- pr_err("Failed to set pcie parent clk.\n");
+ imx_clk_set_parent(clks[IMX6SX_CLK_LVDS1_SEL], clks[IMX6SX_CLK_PCIE_REF_125M]);
+ imx_clk_set_parent(clks[IMX6SX_CLK_PCIE_AXI_SEL], clks[IMX6SX_CLK_AXI]);
/*
* Init enet system AHB clock, set to 200MHz
* pll2_pfd2_396m-> ENET_PODF-> ENET_AHB
*/
- clk_set_parent(clks[IMX6SX_CLK_ENET_PRE_SEL], clks[IMX6SX_CLK_PLL2_PFD2]);
- clk_set_parent(clks[IMX6SX_CLK_ENET_SEL], clks[IMX6SX_CLK_ENET_PODF]);
- clk_set_rate(clks[IMX6SX_CLK_ENET_PODF], 200000000);
- clk_set_rate(clks[IMX6SX_CLK_ENET_REF], 125000000);
- clk_set_rate(clks[IMX6SX_CLK_ENET2_REF], 125000000);
+ imx_clk_set_parent(clks[IMX6SX_CLK_ENET_PRE_SEL], clks[IMX6SX_CLK_PLL2_PFD2]);
+ imx_clk_set_parent(clks[IMX6SX_CLK_ENET_SEL], clks[IMX6SX_CLK_ENET_PODF]);
+ imx_clk_set_rate(clks[IMX6SX_CLK_ENET_PODF], 200000000);
+ imx_clk_set_rate(clks[IMX6SX_CLK_ENET_REF], 125000000);
+ imx_clk_set_rate(clks[IMX6SX_CLK_ENET2_REF], 125000000);
/* Audio clocks */
- clk_set_rate(clks[IMX6SX_CLK_PLL4_AUDIO_DIV], 393216000);
+ imx_clk_set_rate(clks[IMX6SX_CLK_PLL4_AUDIO_DIV], 393216000);
- clk_set_parent(clks[IMX6SX_CLK_SPDIF_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
- clk_set_rate(clks[IMX6SX_CLK_SPDIF_PODF], 98304000);
+ imx_clk_set_parent(clks[IMX6SX_CLK_SPDIF_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
+ imx_clk_set_rate(clks[IMX6SX_CLK_SPDIF_PODF], 24576000);
- clk_set_parent(clks[IMX6SX_CLK_AUDIO_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]);
- clk_set_rate(clks[IMX6SX_CLK_AUDIO_PODF], 24000000);
+ imx_clk_set_parent(clks[IMX6SX_CLK_AUDIO_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]);
+ imx_clk_set_rate(clks[IMX6SX_CLK_AUDIO_PODF], 24000000);
- clk_set_parent(clks[IMX6SX_CLK_SSI1_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
- clk_set_parent(clks[IMX6SX_CLK_SSI2_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
- clk_set_parent(clks[IMX6SX_CLK_SSI3_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
- clk_set_rate(clks[IMX6SX_CLK_SSI1_PODF], 24576000);
- clk_set_rate(clks[IMX6SX_CLK_SSI2_PODF], 24576000);
- clk_set_rate(clks[IMX6SX_CLK_SSI3_PODF], 24576000);
+ imx_clk_set_parent(clks[IMX6SX_CLK_SSI1_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
+ imx_clk_set_parent(clks[IMX6SX_CLK_SSI2_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
+ imx_clk_set_parent(clks[IMX6SX_CLK_SSI3_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
+ imx_clk_set_rate(clks[IMX6SX_CLK_SSI1_PODF], 24576000);
+ imx_clk_set_rate(clks[IMX6SX_CLK_SSI2_PODF], 24576000);
+ imx_clk_set_rate(clks[IMX6SX_CLK_SSI3_PODF], 24576000);
- clk_set_parent(clks[IMX6SX_CLK_ESAI_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
- clk_set_rate(clks[IMX6SX_CLK_ESAI_PODF], 24576000);
+ imx_clk_set_parent(clks[IMX6SX_CLK_ESAI_SEL], clks[IMX6SX_CLK_PLL4_AUDIO_DIV]);
+ imx_clk_set_rate(clks[IMX6SX_CLK_ESAI_PODF], 24576000);
- /* Set parent clock for vadc */
- clk_set_parent(clks[IMX6SX_CLK_VID_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]);
+ /* Set the UART parent if needed. */
+ if (uart_from_osc)
+ clk_set_parent(clks[IMX6SX_CLK_UART_SEL], clks[IMX6SX_CLK_OSC]);
+ else
+ clk_set_parent(clks[IMX6SX_CLK_UART_SEL], clks[IMX6SX_CLK_PLL3_80M]);
- /* default parent of can_sel clock is invalid, manually set it here */
- clk_set_parent(clks[IMX6SX_CLK_CAN_SEL], clks[IMX6SX_CLK_PLL3_60M]);
+ /* Set parent clock for vadc */
+ imx_clk_set_parent(clks[IMX6SX_CLK_VID_SEL], clks[IMX6SX_CLK_PLL3_USB_OTG]);
/* Update gpu clock from default 528M to 720M */
- clk_set_parent(clks[IMX6SX_CLK_GPU_CORE_SEL], clks[IMX6SX_CLK_PLL3_PFD0]);
- clk_set_parent(clks[IMX6SX_CLK_GPU_AXI_SEL], clks[IMX6SX_CLK_PLL3_PFD0]);
+ imx_clk_set_parent(clks[IMX6SX_CLK_GPU_CORE_SEL], clks[IMX6SX_CLK_PLL3_PFD0]);
+ imx_clk_set_parent(clks[IMX6SX_CLK_GPU_AXI_SEL], clks[IMX6SX_CLK_PLL3_PFD0]);
- clk_set_parent(clks[IMX6SX_CLK_QSPI1_SEL], clks[IMX6SX_CLK_PLL2_BUS]);
- clk_set_parent(clks[IMX6SX_CLK_QSPI2_SEL], clks[IMX6SX_CLK_PLL2_BUS]);
+ imx_clk_set_parent(clks[IMX6SX_CLK_QSPI1_SEL], clks[IMX6SX_CLK_PLL2_BUS]);
+ imx_clk_set_parent(clks[IMX6SX_CLK_QSPI2_SEL], clks[IMX6SX_CLK_PLL2_BUS]);
+ /* Set the UART parent if needed. */
+ if (uart_from_osc)
+ imx_clk_set_parent(clks[IMX6SX_CLK_UART_SEL], clks[IMX6SX_CLK_OSC]);
+
+ if (!imx_src_is_m4_enabled())
+ /* default parent of can_sel clock is invalid, manually set it here */
+ imx_clk_set_parent(clks[IMX6SX_CLK_CAN_SEL], clks[IMX6SX_CLK_PLL3_60M]);
+
+ for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
+ imx_clk_prepare_enable(clks[clks_init_on[i]]);
imx_register_uart_clocks(uart_clks);
}
CLK_OF_DECLARE(imx6sx, "fsl,imx6sx-ccm", imx6sx_clocks_init);
+
+int imx_update_shared_mem(struct clk_hw *hw, bool enable)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(clks_shared); i++) {
+ if (shared_mem->imx_clk[i].self == hw->clk)
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(clks_shared))
+ return 1;
+
+ /* update ca9 clk status in shared memory */
+ if (enable)
+ shared_mem->imx_clk[i].ca9_enabled = 1;
+ else
+ shared_mem->imx_clk[i].ca9_enabled = 0;
+
+ if (shared_mem->imx_clk[i].cm4_enabled == 0)
+ return 1;
+
+ return 0;
+}
+
+static int __init imx_amp_power_init(void)
+{
+ int i;
+ void __iomem *shared_mem_base;
+
+ if (!(imx_src_is_m4_enabled() && clk_on_imx6sx()))
+ return 0;
+
+ amp_power_mutex = imx_sema4_mutex_create(0, MCC_POWER_SHMEM_NUMBER);
+
+ shared_mem_base = ioremap_nocache(shared_mem_paddr, shared_mem_size);
+
+ if (!amp_power_mutex) {
+ pr_err("Failed to create sema4 mutex!\n");
+ return 0;
+ }
+
+ shared_mem = (struct imx_shared_mem *)shared_mem_base;
+
+ for (i = 0; i < ARRAY_SIZE(clks_shared); i++) {
+ shared_mem->imx_clk[i].self = clks[clks_shared[i]];
+ shared_mem->imx_clk[i].ca9_enabled = 1;
+ pr_debug("%d: name %s, addr 0x%x\n", i,
+ __clk_get_name(shared_mem->imx_clk[i].self),
+ (u32)&(shared_mem->imx_clk[i]));
+ }
+ /* enable amp power management */
+ shared_mem->ca9_valid = SHARED_MEM_MAGIC_NUMBER;
+
+ pr_info("A9-M4 sema4 num %d, A9-M4 magic number 0x%x - 0x%x.\n",
+ amp_power_mutex->gate_num, shared_mem->ca9_valid,
+ shared_mem->cm4_valid);
+
+ return 0;
+}
+late_initcall(imx_amp_power_init);
diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c
index db2901646403..2b91f04b982a 100644
--- a/drivers/clk/imx/clk-imx6ul.c
+++ b/drivers/clk/imx/clk-imx6ul.c
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
@@ -65,6 +66,11 @@ static const char *lcdif_sels[] = { "lcdif_podf", "ipp_di0", "ipp_di1", "ldb_di0
static const char *csi_sels[] = { "osc", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", };
static const char *sim_sels[] = { "sim_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
+/* epdc_pre_sels, epdc_sels, esai_sels only exists on i.MX6ULL */
+static const char *epdc_pre_sels[] = { "pll2_bus", "pll3_usb_otg", "pll5_video_div", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd2_508m", };
+static const char *esai_sels[] = { "pll4_audio_div", "pll3_pfd2_508m", "pll5_video_div", "pll3_usb_otg", };
+static const char *epdc_sels[] = { "epdc_podf", "ipp_di0", "ipp_di1", "ldb_di0", "ldb_di1", };
+
static struct clk *clks[IMX6UL_CLK_END];
static struct clk_onecell_data clk_data;
@@ -102,6 +108,17 @@ static u32 share_count_audio;
static u32 share_count_sai1;
static u32 share_count_sai2;
static u32 share_count_sai3;
+static u32 share_count_esai;
+
+static inline int clk_on_imx6ul(void)
+{
+ return of_machine_is_compatible("fsl,imx6ul");
+}
+
+static inline int clk_on_imx6ull(void)
+{
+ return of_machine_is_compatible("fsl,imx6ull");
+}
static void __init imx6ul_clocks_init(struct device_node *ccm_node)
{
@@ -132,7 +149,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
clks[IMX6UL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f);
- clks[IMX6UL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
+ clks[IMX6UL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_PLL2, "pll2", "osc", base + 0x30, 0x1);
clks[IMX6UL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3);
clks[IMX6UL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f);
clks[IMX6UL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f);
@@ -146,7 +163,6 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_PLL5_BYPASS] = imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), CLK_SET_RATE_PARENT);
clks[IMX6UL_PLL6_BYPASS] = imx_clk_mux_flags("pll6_bypass", base + 0xe0, 16, 1, pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), CLK_SET_RATE_PARENT);
clks[IMX6UL_PLL7_BYPASS] = imx_clk_mux_flags("pll7_bypass", base + 0x20, 16, 1, pll7_bypass_sels, ARRAY_SIZE(pll7_bypass_sels), CLK_SET_RATE_PARENT);
- clks[IMX6UL_CLK_CSI_SEL] = imx_clk_mux_flags("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels), CLK_SET_RATE_PARENT);
/* Do not bypass PLLs initially */
clk_set_parent(clks[IMX6UL_PLL1_BYPASS], clks[IMX6UL_CLK_PLL1]);
@@ -221,13 +237,13 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CA7_SECONDARY_SEL] = imx_clk_mux("ca7_secondary_sel", base + 0xc, 3, 1, ca7_secondary_sels, ARRAY_SIZE(ca7_secondary_sels));
clks[IMX6UL_CLK_STEP] = imx_clk_mux("step", base + 0x0c, 8, 1, step_sels, ARRAY_SIZE(step_sels));
- clks[IMX6UL_CLK_PLL1_SW] = imx_clk_mux_flags("pll1_sw", base + 0x0c, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels), 0);
+ clks[IMX6UL_CLK_PLL1_SW] = imx_clk_mux_glitchless("pll1_sw", base + 0x0c, 2, 1, pll1_sw_sels, ARRAY_SIZE(pll1_sw_sels));
clks[IMX6UL_CLK_AXI_ALT_SEL] = imx_clk_mux("axi_alt_sel", base + 0x14, 7, 1, axi_alt_sels, ARRAY_SIZE(axi_alt_sels));
clks[IMX6UL_CLK_AXI_SEL] = imx_clk_mux_flags("axi_sel", base + 0x14, 6, 1, axi_sels, ARRAY_SIZE(axi_sels), 0);
- clks[IMX6UL_CLK_PERIPH_PRE] = imx_clk_mux("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
- clks[IMX6UL_CLK_PERIPH2_PRE] = imx_clk_mux("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
- clks[IMX6UL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
- clks[IMX6UL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
+ clks[IMX6UL_CLK_PERIPH_PRE] = imx_clk_mux_bus("periph_pre", base + 0x18, 18, 2, periph_pre_sels, ARRAY_SIZE(periph_pre_sels));
+ clks[IMX6UL_CLK_PERIPH2_PRE] = imx_clk_mux_bus("periph2_pre", base + 0x18, 21, 2, periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels));
+ clks[IMX6UL_CLK_PERIPH_CLK2_SEL] = imx_clk_mux_bus("periph_clk2_sel", base + 0x18, 12, 2, periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels));
+ clks[IMX6UL_CLK_PERIPH2_CLK2_SEL] = imx_clk_mux_bus("periph2_clk2_sel", base + 0x18, 20, 1, periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels));
clks[IMX6UL_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_slow_sels, ARRAY_SIZE(eim_slow_sels));
clks[IMX6UL_CLK_GPMI_SEL] = imx_clk_mux("gpmi_sel", base + 0x1c, 19, 1, gpmi_sels, ARRAY_SIZE(gpmi_sels));
clks[IMX6UL_CLK_BCH_SEL] = imx_clk_mux("bch_sel", base + 0x1c, 18, 1, bch_sels, ARRAY_SIZE(bch_sels));
@@ -239,15 +255,23 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_QSPI1_SEL] = imx_clk_mux("qspi1_sel", base + 0x1c, 7, 3, qspi1_sels, ARRAY_SIZE(qspi1_sels));
clks[IMX6UL_CLK_PERCLK_SEL] = imx_clk_mux("perclk_sel", base + 0x1c, 6, 1, perclk_sels, ARRAY_SIZE(perclk_sels));
clks[IMX6UL_CLK_CAN_SEL] = imx_clk_mux("can_sel", base + 0x20, 8, 2, can_sels, ARRAY_SIZE(can_sels));
+ if (clk_on_imx6ull())
+ clks[IMX6UL_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", base + 0x20, 19, 2, esai_sels, ARRAY_SIZE(esai_sels));
clks[IMX6UL_CLK_UART_SEL] = imx_clk_mux("uart_sel", base + 0x24, 6, 1, uart_sels, ARRAY_SIZE(uart_sels));
clks[IMX6UL_CLK_ENFC_SEL] = imx_clk_mux("enfc_sel", base + 0x2c, 15, 3, enfc_sels, ARRAY_SIZE(enfc_sels));
clks[IMX6UL_CLK_LDB_DI0_SEL] = imx_clk_mux("ldb_di0_sel", base + 0x2c, 9, 3, ldb_di0_sels, ARRAY_SIZE(ldb_di0_sels));
clks[IMX6UL_CLK_SPDIF_SEL] = imx_clk_mux("spdif_sel", base + 0x30, 20, 2, spdif_sels, ARRAY_SIZE(spdif_sels));
- clks[IMX6UL_CLK_SIM_PRE_SEL] = imx_clk_mux("sim_pre_sel", base + 0x34, 15, 3, sim_pre_sels, ARRAY_SIZE(sim_pre_sels));
- clks[IMX6UL_CLK_SIM_SEL] = imx_clk_mux("sim_sel", base + 0x34, 9, 3, sim_sels, ARRAY_SIZE(sim_sels));
+ if (clk_on_imx6ul()) {
+ clks[IMX6UL_CLK_SIM_PRE_SEL] = imx_clk_mux("sim_pre_sel", base + 0x34, 15, 3, sim_pre_sels, ARRAY_SIZE(sim_pre_sels));
+ clks[IMX6UL_CLK_SIM_SEL] = imx_clk_mux("sim_sel", base + 0x34, 9, 3, sim_sels, ARRAY_SIZE(sim_sels));
+ } else {
+ clks[IMX6UL_CLK_EPDC_PRE_SEL] = imx_clk_mux("epdc_pre_sel", base + 0x34, 15, 3, epdc_pre_sels, ARRAY_SIZE(epdc_pre_sels));
+ clks[IMX6UL_CLK_EPDC_SEL] = imx_clk_mux("epdc_sel", base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels));
+ }
clks[IMX6UL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels));
clks[IMX6UL_CLK_LCDIF_PRE_SEL] = imx_clk_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels));
clks[IMX6UL_CLK_LCDIF_SEL] = imx_clk_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels));
+ clks[IMX6UL_CLK_CSI_SEL] = imx_clk_mux_flags("csi_sel", base + 0x3c, 9, 2, csi_sels, ARRAY_SIZE(csi_sels), CLK_SET_RATE_PARENT);
clks[IMX6UL_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux("ldb_di0", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels));
clks[IMX6UL_CLK_LDB_DI1_DIV_SEL] = imx_clk_mux("ldb_di1", base + 0x20, 11, 1, ldb_di1_div_sels, ARRAY_SIZE(ldb_di1_div_sels));
@@ -277,13 +301,20 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_SAI3_PODF] = imx_clk_divider("sai3_podf", "sai3_pred", base + 0x28, 16, 6);
clks[IMX6UL_CLK_SAI1_PRED] = imx_clk_divider("sai1_pred", "sai1_sel", base + 0x28, 6, 3);
clks[IMX6UL_CLK_SAI1_PODF] = imx_clk_divider("sai1_podf", "sai1_pred", base + 0x28, 0, 6);
+ if (clk_on_imx6ull()) {
+ clks[IMX6UL_CLK_ESAI_PRED] = imx_clk_divider("esai_pred", "esai_sel", base + 0x28, 9, 3);
+ clks[IMX6UL_CLK_ESAI_PODF] = imx_clk_divider("esai_podf", "esai_pred", base + 0x28, 25, 3);
+ }
clks[IMX6UL_CLK_ENFC_PRED] = imx_clk_divider("enfc_pred", "enfc_sel", base + 0x2c, 18, 3);
clks[IMX6UL_CLK_ENFC_PODF] = imx_clk_divider("enfc_podf", "enfc_pred", base + 0x2c, 21, 6);
clks[IMX6UL_CLK_SAI2_PRED] = imx_clk_divider("sai2_pred", "sai2_sel", base + 0x2c, 6, 3);
clks[IMX6UL_CLK_SAI2_PODF] = imx_clk_divider("sai2_podf", "sai2_pred", base + 0x2c, 0, 6);
clks[IMX6UL_CLK_SPDIF_PRED] = imx_clk_divider("spdif_pred", "spdif_sel", base + 0x30, 25, 3);
clks[IMX6UL_CLK_SPDIF_PODF] = imx_clk_divider("spdif_podf", "spdif_pred", base + 0x30, 22, 3);
- clks[IMX6UL_CLK_SIM_PODF] = imx_clk_divider("sim_podf", "sim_pre_sel", base + 0x34, 12, 3);
+ if (clk_on_imx6ul())
+ clks[IMX6UL_CLK_SIM_PODF] = imx_clk_divider("sim_podf", "sim_pre_sel", base + 0x34, 12, 3);
+ else
+ clks[IMX6UL_CLK_EPDC_PODF] = imx_clk_divider("epdc_podf", "epdc_pre_sel", base + 0x34, 12, 3);
clks[IMX6UL_CLK_ECSPI_PODF] = imx_clk_divider("ecspi_podf", "ecspi_sel", base + 0x38, 19, 6);
clks[IMX6UL_CLK_LCDIF_PRED] = imx_clk_divider("lcdif_pred", "lcdif_pre_sel", base + 0x38, 12, 3);
clks[IMX6UL_CLK_CSI_PODF] = imx_clk_divider("csi_podf", "csi_sel", base + 0x3c, 11, 3);
@@ -299,9 +330,15 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_APBHDMA] = imx_clk_gate2("apbh_dma", "bch_podf", base + 0x68, 4);
clks[IMX6UL_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc);
clks[IMX6UL_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc);
- clks[IMX6UL_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8);
- clks[IMX6UL_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10);
- clks[IMX6UL_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12);
+ if (clk_on_imx6ul()) {
+ clks[IMX6UL_CLK_CAAM_MEM] = imx_clk_gate2("caam_mem", "ahb", base + 0x68, 8);
+ clks[IMX6UL_CLK_CAAM_ACLK] = imx_clk_gate2("caam_aclk", "ahb", base + 0x68, 10);
+ clks[IMX6UL_CLK_CAAM_IPG] = imx_clk_gate2("caam_ipg", "ipg", base + 0x68, 12);
+ } else {
+ clks[IMX6UL_CLK_DCP_CLK] = imx_clk_gate2("dcp", "ahb", base + 0x68, 10);
+ clks[IMX6UL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x68, 12);
+ clks[IMX6UL_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "ahb", base + 0x68, 12);
+ }
clks[IMX6UL_CLK_CAN1_IPG] = imx_clk_gate2("can1_ipg", "ipg", base + 0x68, 14);
clks[IMX6UL_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_podf", base + 0x68, 16);
clks[IMX6UL_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18);
@@ -310,7 +347,8 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_GPT2_SERIAL] = imx_clk_gate2("gpt2_serial", "perclk", base + 0x68, 26);
clks[IMX6UL_CLK_UART2_IPG] = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28);
clks[IMX6UL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28);
- clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30);
+ if (clk_on_imx6ul())
+ clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30);
/* CCGR1 */
clks[IMX6UL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0);
@@ -329,6 +367,11 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serail", "uart_podf", base + 0x6c, 24);
/* CCGR2 */
+ if (clk_on_imx6ull()) {
+ clks[IMX6UL_CLK_ESAI_EXTAL] = imx_clk_gate2_shared("esai_extal", "esai_podf", base + 0x70, 0, &share_count_esai);
+ clks[IMX6UL_CLK_ESAI_IPG] = imx_clk_gate2_shared("esai_ipg", "ahb", base + 0x70, 0, &share_count_esai);
+ clks[IMX6UL_CLK_ESAI_MEM] = imx_clk_gate2_shared("esai_mem", "ahb", base + 0x70, 0, &share_count_esai);
+ }
clks[IMX6UL_CLK_CSI] = imx_clk_gate2("csi", "csi_podf", base + 0x70, 2);
clks[IMX6UL_CLK_I2C1] = imx_clk_gate2("i2c1", "perclk", base + 0x70, 6);
clks[IMX6UL_CLK_I2C2] = imx_clk_gate2("i2c2", "perclk", base + 0x70, 8);
@@ -341,8 +384,13 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
/* CCGR3 */
clks[IMX6UL_CLK_UART5_IPG] = imx_clk_gate2("uart5_ipg", "ipg", base + 0x74, 2);
clks[IMX6UL_CLK_UART5_SERIAL] = imx_clk_gate2("uart5_serial", "uart_podf", base + 0x74, 2);
- clks[IMX6UL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x74, 4);
- clks[IMX6UL_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "ahb", base + 0x74, 4);
+ if (clk_on_imx6ul()) {
+ clks[IMX6UL_CLK_ENET] = imx_clk_gate2("enet", "ipg", base + 0x74, 4);
+ clks[IMX6UL_CLK_ENET_AHB] = imx_clk_gate2("enet_ahb", "ahb", base + 0x74, 4);
+ } else {
+ clks[IMX6UL_CLK_EPDC_ACLK] = imx_clk_gate2("epdc_aclk", "axi", base + 0x74, 4);
+ clks[IMX6UL_CLK_EPDC_PIX] = imx_clk_gate2("epdc_pix", "epdc_podf", base + 0x74, 4);
+ }
clks[IMX6UL_CLK_UART6_IPG] = imx_clk_gate2("uart6_ipg", "ipg", base + 0x74, 6);
clks[IMX6UL_CLK_UART6_SERIAL] = imx_clk_gate2("uart6_serial", "uart_podf", base + 0x74, 6);
clks[IMX6UL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10);
@@ -386,12 +434,16 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_USBOH3] = imx_clk_gate2("usboh3", "ipg", base + 0x80, 0);
clks[IMX6UL_CLK_USDHC1] = imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2);
clks[IMX6UL_CLK_USDHC2] = imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4);
- clks[IMX6UL_CLK_SIM1] = imx_clk_gate2("sim1", "sim_sel", base + 0x80, 6);
- clks[IMX6UL_CLK_SIM2] = imx_clk_gate2("sim2", "sim_sel", base + 0x80, 8);
+ if (clk_on_imx6ul()) {
+ clks[IMX6UL_CLK_SIM1] = imx_clk_gate2("sim1", "sim_sel", base + 0x80, 6);
+ clks[IMX6UL_CLK_SIM2] = imx_clk_gate2("sim2", "sim_sel", base + 0x80, 8);
+ }
clks[IMX6UL_CLK_EIM] = imx_clk_gate2("eim", "eim_slow_podf", base + 0x80, 10);
clks[IMX6UL_CLK_PWM8] = imx_clk_gate2("pwm8", "perclk", base + 0x80, 16);
clks[IMX6UL_CLK_UART8_IPG] = imx_clk_gate2("uart8_ipg", "ipg", base + 0x80, 14);
clks[IMX6UL_CLK_UART8_SERIAL] = imx_clk_gate2("uart8_serial", "uart_podf", base + 0x80, 14);
+ if (clk_on_imx6ull())
+ clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x80, 18);
clks[IMX6UL_CLK_WDOG3] = imx_clk_gate2("wdog3", "ipg", base + 0x80, 20);
clks[IMX6UL_CLK_I2C4] = imx_clk_gate2("i2c4", "perclk", base + 0x80, 24);
clks[IMX6UL_CLK_PWM5] = imx_clk_gate2("pwm5", "perclk", base + 0x80, 26);
@@ -428,9 +480,16 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
/* set perclk to from OSC */
clk_set_parent(clks[IMX6UL_CLK_PERCLK_SEL], clks[IMX6UL_CLK_OSC]);
+ /* Set the UART parent if needed */
+ if (uart_from_osc)
+ imx_clk_set_parent(clks[IMX6UL_CLK_UART_SEL], clks[IMX6UL_CLK_OSC]);
+ else
+ imx_clk_set_parent(clks[IMX6UL_CLK_UART_SEL], clks[IMX6UL_CLK_PLL3_80M]);
+
clk_set_rate(clks[IMX6UL_CLK_ENET_REF], 50000000);
clk_set_rate(clks[IMX6UL_CLK_ENET2_REF], 50000000);
clk_set_rate(clks[IMX6UL_CLK_CSI], 24000000);
+ clk_set_rate(clks[IMX6UL_CLK_PLL3_PFD2], 320000000);
/* keep all the clks on just for bringup */
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
@@ -442,9 +501,23 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
}
clk_set_parent(clks[IMX6UL_CLK_CAN_SEL], clks[IMX6UL_CLK_PLL3_60M]);
- clk_set_parent(clks[IMX6UL_CLK_SIM_PRE_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]);
+ if (clk_on_imx6ul())
+ clk_set_parent(clks[IMX6UL_CLK_SIM_PRE_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]);
+ else
+ clk_set_parent(clks[IMX6UL_CLK_EPDC_PRE_SEL], clks[IMX6UL_CLK_PLL3_PFD2]);
clk_set_parent(clks[IMX6UL_CLK_ENFC_SEL], clks[IMX6UL_CLK_PLL2_PFD2]);
+
+ /* Lower the AHB clock rate before changing the clock source. */
+ imx_clk_set_rate(clks[IMX6UL_CLK_AHB], 99000000);
+
+ /* Change periph_pre clock to pll2_bus to adjust AXI rate to 264MHz */
+ imx_clk_set_parent(clks[IMX6UL_CLK_PERIPH_CLK2_SEL], clks[IMX6UL_CLK_PLL3_USB_OTG]);
+ imx_clk_set_parent(clks[IMX6UL_CLK_PERIPH], clks[IMX6UL_CLK_PERIPH_CLK2]);
+ imx_clk_set_parent(clks[IMX6UL_CLK_PERIPH_PRE], clks[IMX6UL_CLK_PLL2_BUS]);
+ imx_clk_set_parent(clks[IMX6UL_CLK_PERIPH], clks[IMX6UL_CLK_PERIPH_PRE]);
+
+ imx_clk_set_rate(clks[IMX6UL_CLK_AHB], 132000000);
}
CLK_OF_DECLARE(imx6ul, "fsl,imx6ul-ccm", imx6ul_clocks_init);
diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c
index e7c7353a86fc..0b98e03b1741 100644
--- a/drivers/clk/imx/clk-imx7d.c
+++ b/drivers/clk/imx/clk-imx7d.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
@@ -19,12 +20,17 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/types.h>
+#include <soc/imx/src.h>
#include "clk.h"
static u32 share_count_sai1;
static u32 share_count_sai2;
static u32 share_count_sai3;
+static u32 share_count_pxp;
+static u32 share_count_enet1;
+static u32 share_count_enet2;
+static u32 share_count_nand;
static struct clk_div_table test_div_table[] = {
{ .val = 3, .div = 1, },
@@ -50,25 +56,20 @@ static const char *arm_a7_sel[] = { "osc", "pll_arm_main_clk",
static const char *arm_m4_sel[] = { "osc", "pll_sys_main_240m_clk",
"pll_enet_250m_clk", "pll_sys_pfd2_270m_clk",
- "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_main_clk",
- "pll_usb_main_clk", };
-
-static const char *arm_m0_sel[] = { "osc", "pll_sys_main_120m_clk",
- "pll_enet_125m_clk", "pll_sys_pfd2_135m_clk",
- "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_main_clk",
+ "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_post_div",
"pll_usb_main_clk", };
static const char *axi_sel[] = { "osc", "pll_sys_pfd1_332m_clk",
"pll_dram_533m_clk", "pll_enet_250m_clk", "pll_sys_pfd5_clk",
- "pll_audio_post_div", "pll_video_main_clk", "pll_sys_pfd7_clk", };
+ "pll_audio_post_div", "pll_video_post_div", "pll_sys_pfd7_clk", };
static const char *disp_axi_sel[] = { "osc", "pll_sys_pfd1_332m_clk",
"pll_dram_533m_clk", "pll_enet_250m_clk", "pll_sys_pfd6_clk",
- "pll_sys_pfd7_clk", "pll_audio_post_div", "pll_video_main_clk", };
+ "pll_sys_pfd7_clk", "pll_audio_post_div", "pll_video_post_div", };
static const char *enet_axi_sel[] = { "osc", "pll_sys_pfd2_270m_clk",
"pll_dram_533m_clk", "pll_enet_250m_clk",
- "pll_sys_main_240m_clk", "pll_audio_post_div", "pll_video_main_clk",
+ "pll_sys_main_240m_clk", "pll_audio_post_div", "pll_video_post_div",
"pll_sys_pfd4_clk", };
static const char *nand_usdhc_bus_sel[] = { "osc", "pll_sys_pfd2_270m_clk",
@@ -78,8 +79,8 @@ static const char *nand_usdhc_bus_sel[] = { "osc", "pll_sys_pfd2_270m_clk",
static const char *ahb_channel_sel[] = { "osc", "pll_sys_pfd2_270m_clk",
"pll_dram_533m_clk", "pll_sys_pfd0_392m_clk",
- "pll_enet_125m_clk", "pll_usb_main_clk", "pll_audio_post_div",
- "pll_video_main_clk", };
+ "pll_enet_250m_clk", "pll_usb_main_clk", "pll_audio_post_div",
+ "pll_video_post_div", };
static const char *dram_phym_sel[] = { "pll_dram_main_clk",
"dram_phym_alt_clk", };
@@ -90,7 +91,7 @@ static const char *dram_sel[] = { "pll_dram_main_clk",
static const char *dram_phym_alt_sel[] = { "osc", "pll_dram_533m_clk",
"pll_sys_main_clk", "pll_enet_500m_clk",
"pll_usb_main_clk", "pll_sys_pfd7_clk", "pll_audio_post_div",
- "pll_video_main_clk", };
+ "pll_video_post_div", };
static const char *dram_alt_sel[] = { "osc", "pll_dram_533m_clk",
"pll_sys_main_clk", "pll_enet_500m_clk",
@@ -112,62 +113,62 @@ static const char *pcie_phy_sel[] = { "osc", "pll_enet_100m_clk",
static const char *epdc_pixel_sel[] = { "osc", "pll_sys_pfd1_332m_clk",
"pll_dram_533m_clk", "pll_sys_main_clk", "pll_sys_pfd5_clk",
- "pll_sys_pfd6_clk", "pll_sys_pfd7_clk", "pll_video_main_clk", };
+ "pll_sys_pfd6_clk", "pll_sys_pfd7_clk", "pll_video_post_div", };
static const char *lcdif_pixel_sel[] = { "osc", "pll_sys_pfd5_clk",
"pll_dram_533m_clk", "ext_clk_3", "pll_sys_pfd4_clk",
- "pll_sys_pfd2_270m_clk", "pll_video_main_clk",
+ "pll_sys_pfd2_270m_clk", "pll_video_post_div",
"pll_usb_main_clk", };
static const char *mipi_dsi_sel[] = { "osc", "pll_sys_pfd5_clk",
"pll_sys_pfd3_clk", "pll_sys_main_clk", "pll_sys_pfd0_196m_clk",
- "pll_dram_533m_clk", "pll_video_main_clk", "pll_audio_post_div", };
+ "pll_dram_533m_clk", "pll_video_post_div", "pll_audio_post_div", };
static const char *mipi_csi_sel[] = { "osc", "pll_sys_pfd4_clk",
"pll_sys_pfd3_clk", "pll_sys_main_clk", "pll_sys_pfd0_196m_clk",
- "pll_dram_533m_clk", "pll_video_main_clk", "pll_audio_post_div", };
+ "pll_dram_533m_clk", "pll_video_post_div", "pll_audio_post_div", };
static const char *mipi_dphy_sel[] = { "osc", "pll_sys_main_120m_clk",
"pll_dram_533m_clk", "pll_sys_pfd5_clk", "ref_1m_clk", "ext_clk_2",
- "pll_video_main_clk", "ext_clk_3", };
+ "pll_video_post_div", "ext_clk_3", };
static const char *sai1_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
- "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_main_clk",
+ "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_post_div",
"pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_clk_2", };
static const char *sai2_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
- "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_main_clk",
+ "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_post_div",
"pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_clk_2", };
static const char *sai3_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
- "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_main_clk",
+ "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_post_div",
"pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_clk_3", };
static const char *spdif_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
- "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_main_clk",
+ "pll_audio_post_div", "pll_dram_533m_clk", "pll_video_post_div",
"pll_sys_pfd4_clk", "pll_enet_125m_clk", "ext_3_clk", };
static const char *enet1_ref_sel[] = { "osc", "pll_enet_125m_clk",
"pll_enet_50m_clk", "pll_enet_25m_clk",
- "pll_sys_main_120m_clk", "pll_audio_post_div", "pll_video_main_clk",
+ "pll_sys_main_120m_clk", "pll_audio_post_div", "pll_video_post_div",
"ext_clk_4", };
static const char *enet1_time_sel[] = { "osc", "pll_enet_100m_clk",
"pll_audio_post_div", "ext_clk_1", "ext_clk_2", "ext_clk_3",
- "ext_clk_4", "pll_video_main_clk", };
+ "ext_clk_4", "pll_video_post_div", };
static const char *enet2_ref_sel[] = { "osc", "pll_enet_125m_clk",
"pll_enet_50m_clk", "pll_enet_25m_clk",
- "pll_sys_main_120m_clk", "pll_audio_post_div", "pll_video_main_clk",
+ "pll_sys_main_120m_clk", "pll_audio_post_div", "pll_video_post_div",
"ext_clk_4", };
static const char *enet2_time_sel[] = { "osc", "pll_enet_100m_clk",
"pll_audio_post_div", "ext_clk_1", "ext_clk_2", "ext_clk_3",
- "ext_clk_4", "pll_video_main_clk", };
+ "ext_clk_4", "pll_video_post_div", };
static const char *enet_phy_ref_sel[] = { "osc", "pll_enet_25m_clk",
"pll_enet_50m_clk", "pll_enet_125m_clk",
- "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_main_clk",
+ "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_post_div",
"pll_sys_pfd3_clk", };
static const char *eim_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
@@ -178,7 +179,7 @@ static const char *eim_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
static const char *nand_sel[] = { "osc", "pll_sys_main_clk",
"pll_dram_533m_clk", "pll_sys_pfd0_392m_clk", "pll_sys_pfd3_clk",
"pll_enet_500m_clk", "pll_enet_250m_clk",
- "pll_video_main_clk", };
+ "pll_video_post_div", };
static const char *qspi_sel[] = { "osc", "pll_sys_pfd4_clk",
"pll_dram_533m_clk", "pll_enet_500m_clk", "pll_sys_pfd3_clk",
@@ -208,22 +209,22 @@ static const char *can2_sel[] = { "osc", "pll_sys_main_120m_clk",
static const char *i2c1_sel[] = { "osc", "pll_sys_main_120m_clk",
"pll_enet_50m_clk", "pll_dram_533m_clk",
- "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk",
+ "pll_audio_post_div", "pll_video_post_div", "pll_usb_main_clk",
"pll_sys_pfd2_135m_clk", };
static const char *i2c2_sel[] = { "osc", "pll_sys_main_120m_clk",
"pll_enet_50m_clk", "pll_dram_533m_clk",
- "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk",
+ "pll_audio_post_div", "pll_video_post_div", "pll_usb_main_clk",
"pll_sys_pfd2_135m_clk", };
static const char *i2c3_sel[] = { "osc", "pll_sys_main_120m_clk",
"pll_enet_50m_clk", "pll_dram_533m_clk",
- "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk",
+ "pll_audio_post_div", "pll_video_post_div", "pll_usb_main_clk",
"pll_sys_pfd2_135m_clk", };
static const char *i2c4_sel[] = { "osc", "pll_sys_main_120m_clk",
"pll_enet_50m_clk", "pll_dram_533m_clk",
- "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk",
+ "pll_audio_post_div", "pll_video_post_div", "pll_usb_main_clk",
"pll_sys_pfd2_135m_clk", };
static const char *uart1_sel[] = { "osc", "pll_sys_main_240m_clk",
@@ -283,27 +284,27 @@ static const char *ecspi4_sel[] = { "osc", "pll_sys_main_240m_clk",
static const char *pwm1_sel[] = { "osc", "pll_enet_100m_clk",
"pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div",
- "ext_clk_1", "ref_1m_clk", "pll_video_main_clk", };
+ "ext_clk_1", "ref_1m_clk", "pll_video_post_div", };
static const char *pwm2_sel[] = { "osc", "pll_enet_100m_clk",
"pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div",
- "ext_clk_1", "ref_1m_clk", "pll_video_main_clk", };
+ "ext_clk_1", "ref_1m_clk", "pll_video_post_div", };
static const char *pwm3_sel[] = { "osc", "pll_enet_100m_clk",
"pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div",
- "ext_clk_2", "ref_1m_clk", "pll_video_main_clk", };
+ "ext_clk_2", "ref_1m_clk", "pll_video_post_div", };
static const char *pwm4_sel[] = { "osc", "pll_enet_100m_clk",
"pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div",
- "ext_clk_2", "ref_1m_clk", "pll_video_main_clk", };
+ "ext_clk_2", "ref_1m_clk", "pll_video_post_div", };
static const char *flextimer1_sel[] = { "osc", "pll_enet_100m_clk",
"pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div",
- "ext_clk_3", "ref_1m_clk", "pll_video_main_clk", };
+ "ext_clk_3", "ref_1m_clk", "pll_video_post_div", };
static const char *flextimer2_sel[] = { "osc", "pll_enet_100m_clk",
"pll_sys_main_120m_clk", "pll_enet_40m_clk", "pll_audio_post_div",
- "ext_clk_3", "ref_1m_clk", "pll_video_main_clk", };
+ "ext_clk_3", "ref_1m_clk", "pll_video_post_div", };
static const char *sim1_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
"pll_sys_main_120m_clk", "pll_dram_533m_clk",
@@ -312,23 +313,23 @@ static const char *sim1_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
static const char *sim2_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
"pll_sys_main_120m_clk", "pll_dram_533m_clk",
- "pll_usb_main_clk", "pll_video_main_clk", "pll_enet_125m_clk",
+ "pll_usb_main_clk", "pll_video_post_div", "pll_enet_125m_clk",
"pll_sys_pfd7_clk", };
static const char *gpt1_sel[] = { "osc", "pll_enet_100m_clk",
- "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk",
+ "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_post_div",
"ref_1m_clk", "pll_audio_post_div", "ext_clk_1", };
static const char *gpt2_sel[] = { "osc", "pll_enet_100m_clk",
- "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk",
+ "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_post_div",
"ref_1m_clk", "pll_audio_post_div", "ext_clk_2", };
static const char *gpt3_sel[] = { "osc", "pll_enet_100m_clk",
- "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk",
+ "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_post_div",
"ref_1m_clk", "pll_audio_post_div", "ext_clk_3", };
static const char *gpt4_sel[] = { "osc", "pll_enet_100m_clk",
- "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_main_clk",
+ "pll_sys_pfd0_392m_clk", "pll_enet_40m_clk", "pll_video_post_div",
"ref_1m_clk", "pll_audio_post_div", "ext_clk_4", };
static const char *trace_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
@@ -343,12 +344,12 @@ static const char *wdog_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
static const char *csi_mclk_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
"pll_sys_main_120m_clk", "pll_dram_533m_clk",
- "pll_enet_125m_clk", "pll_audio_post_div", "pll_video_main_clk",
+ "pll_enet_125m_clk", "pll_audio_post_div", "pll_video_post_div",
"pll_usb_main_clk", };
static const char *audio_mclk_sel[] = { "osc", "pll_sys_pfd2_135m_clk",
"pll_sys_main_120m_clk", "pll_dram_533m_clk",
- "pll_enet_125m_clk", "pll_audio_post_div", "pll_video_main_clk",
+ "pll_enet_125m_clk", "pll_audio_post_div", "pll_video_post_div",
"pll_usb_main_clk", };
static const char *wrclk_sel[] = { "osc", "pll_enet_40m_clk",
@@ -362,13 +363,13 @@ static const char *clko1_sel[] = { "osc", "pll_sys_main_clk",
static const char *clko2_sel[] = { "osc", "pll_sys_main_240m_clk",
"pll_sys_pfd0_392m_clk", "pll_sys_pfd1_166m_clk", "pll_sys_pfd4_clk",
- "pll_audio_post_div", "pll_video_main_clk", "ckil", };
+ "pll_audio_post_div", "pll_video_post_div", "ckil", };
static const char *lvds1_sel[] = { "pll_arm_main_clk",
"pll_sys_main_clk", "pll_sys_pfd0_392m_clk", "pll_sys_pfd1_332m_clk",
"pll_sys_pfd2_270m_clk", "pll_sys_pfd3_clk", "pll_sys_pfd4_clk",
"pll_sys_pfd5_clk", "pll_sys_pfd6_clk", "pll_sys_pfd7_clk",
- "pll_audio_post_div", "pll_video_main_clk", "pll_enet_500m_clk",
+ "pll_audio_post_div", "pll_video_post_div", "pll_enet_500m_clk",
"pll_enet_250m_clk", "pll_enet_125m_clk", "pll_enet_100m_clk",
"pll_enet_50m_clk", "pll_enet_40m_clk", "pll_enet_25m_clk",
"pll_dram_main_clk", };
@@ -383,10 +384,10 @@ static const char *pll_video_bypass_sel[] = { "pll_video_main", "pll_video_main_
static int const clks_init_on[] __initconst = {
IMX7D_ARM_A7_ROOT_CLK, IMX7D_MAIN_AXI_ROOT_CLK,
- IMX7D_PLL_SYS_MAIN_480M_CLK, IMX7D_NAND_USDHC_BUS_ROOT_CLK,
+ IMX7D_PLL_SYS_MAIN_480M_CLK,
IMX7D_DRAM_PHYM_ROOT_CLK, IMX7D_DRAM_ROOT_CLK,
IMX7D_DRAM_PHYM_ALT_ROOT_CLK, IMX7D_DRAM_ALT_ROOT_CLK,
- IMX7D_AHB_CHANNEL_ROOT_CLK,
+ IMX7D_AHB_CHANNEL_ROOT_CLK, IMX7D_IPG_ROOT_CLK,
};
static struct clk_onecell_data clk_data;
@@ -424,11 +425,11 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_PLL_VIDEO_MAIN_SRC] = imx_clk_mux("pll_video_main_src", base + 0x130, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
clks[IMX7D_PLL_ARM_MAIN] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll_arm_main", "osc", base + 0x60, 0x7f);
- clks[IMX7D_PLL_DRAM_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV, "pll_dram_main", "osc", base + 0x70, 0x7f);
+ clks[IMX7D_PLL_DRAM_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV_IMX7, "pll_dram_main", "osc", base + 0x70, 0x7f);
clks[IMX7D_PLL_SYS_MAIN] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll_sys_main", "osc", base + 0xb0, 0x1);
clks[IMX7D_PLL_ENET_MAIN] = imx_clk_pllv3(IMX_PLLV3_ENET_IMX7, "pll_enet_main", "osc", base + 0xe0, 0x0);
- clks[IMX7D_PLL_AUDIO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV, "pll_audio_main", "osc", base + 0xf0, 0x7f);
- clks[IMX7D_PLL_VIDEO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV, "pll_video_main", "osc", base + 0x130, 0x7f);
+ clks[IMX7D_PLL_AUDIO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV_IMX7, "pll_audio_main", "osc", base + 0xf0, 0x7f);
+ clks[IMX7D_PLL_VIDEO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV_IMX7, "pll_video_main", "osc", base + 0x130, 0x7f);
clks[IMX7D_PLL_ARM_MAIN_BYPASS] = imx_clk_mux_flags("pll_arm_main_bypass", base + 0x60, 16, 1, pll_arm_bypass_sel, ARRAY_SIZE(pll_arm_bypass_sel), CLK_SET_RATE_PARENT);
clks[IMX7D_PLL_DRAM_MAIN_BYPASS] = imx_clk_mux_flags("pll_dram_main_bypass", base + 0x70, 16, 1, pll_dram_bypass_sel, ARRAY_SIZE(pll_dram_bypass_sel), CLK_SET_RATE_PARENT);
@@ -437,23 +438,22 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_PLL_AUDIO_MAIN_BYPASS] = imx_clk_mux_flags("pll_audio_main_bypass", base + 0xf0, 16, 1, pll_audio_bypass_sel, ARRAY_SIZE(pll_audio_bypass_sel), CLK_SET_RATE_PARENT);
clks[IMX7D_PLL_VIDEO_MAIN_BYPASS] = imx_clk_mux_flags("pll_video_main_bypass", base + 0x130, 16, 1, pll_video_bypass_sel, ARRAY_SIZE(pll_video_bypass_sel), CLK_SET_RATE_PARENT);
- clk_set_parent(clks[IMX7D_PLL_ARM_MAIN_BYPASS], clks[IMX7D_PLL_ARM_MAIN]);
- clk_set_parent(clks[IMX7D_PLL_DRAM_MAIN_BYPASS], clks[IMX7D_PLL_DRAM_MAIN]);
- clk_set_parent(clks[IMX7D_PLL_SYS_MAIN_BYPASS], clks[IMX7D_PLL_SYS_MAIN]);
- clk_set_parent(clks[IMX7D_PLL_ENET_MAIN_BYPASS], clks[IMX7D_PLL_ENET_MAIN]);
- clk_set_parent(clks[IMX7D_PLL_AUDIO_MAIN_BYPASS], clks[IMX7D_PLL_AUDIO_MAIN]);
- clk_set_parent(clks[IMX7D_PLL_VIDEO_MAIN_BYPASS], clks[IMX7D_PLL_VIDEO_MAIN]);
-
clks[IMX7D_PLL_ARM_MAIN_CLK] = imx_clk_gate("pll_arm_main_clk", "pll_arm_main_bypass", base + 0x60, 13);
- clks[IMX7D_PLL_DRAM_MAIN_CLK] = imx_clk_gate("pll_dram_main_clk", "pll_dram_main_bypass", base + 0x70, 13);
+ clks[IMX7D_PLL_DRAM_MAIN_CLK] = imx_clk_gate("pll_dram_main_clk", "pll_dram_test_div", base + 0x70, 13);
clks[IMX7D_PLL_SYS_MAIN_CLK] = imx_clk_gate("pll_sys_main_clk", "pll_sys_main_bypass", base + 0xb0, 13);
- clks[IMX7D_PLL_AUDIO_MAIN_CLK] = imx_clk_gate("pll_audio_main_clk", "pll_audio_main_bypass", base + 0xf0, 13);
- clks[IMX7D_PLL_VIDEO_MAIN_CLK] = imx_clk_gate("pll_video_main_clk", "pll_video_main_bypass", base + 0x130, 13);
+ clks[IMX7D_PLL_AUDIO_MAIN_CLK] = imx_clk_gate("pll_audio_main_clk", "pll_audio_test_div", base + 0xf0, 13);
+ clks[IMX7D_PLL_VIDEO_MAIN_CLK] = imx_clk_gate("pll_video_main_clk", "pll_video_test_div", base + 0x130, 13);
- clks[IMX7D_PLL_AUDIO_TEST_DIV] = clk_register_divider_table(NULL, "pll_audio_test_div", "pll_audio_main_clk",
+ clks[IMX7D_PLL_DRAM_TEST_DIV] = clk_register_divider_table(NULL, "pll_dram_test_div", "pll_dram_main_bypass",
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 21, 2, 0, test_div_table, &imx_ccm_lock);
+ clks[IMX7D_PLL_AUDIO_TEST_DIV] = clk_register_divider_table(NULL, "pll_audio_test_div", "pll_audio_main_bypass",
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xf0, 19, 2, 0, test_div_table, &imx_ccm_lock);
- clks[IMX7D_PLL_AUDIO_POST_DIV] = clk_register_divider_table(NULL, "pll_audio_post_div", "pll_audio_test_div",
+ clks[IMX7D_PLL_AUDIO_POST_DIV] = clk_register_divider_table(NULL, "pll_audio_post_div", "pll_audio_main_clk",
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xf0, 22, 2, 0, post_div_table, &imx_ccm_lock);
+ clks[IMX7D_PLL_VIDEO_TEST_DIV] = clk_register_divider_table(NULL, "pll_video_test_div", "pll_video_main_bypass",
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x130, 19, 2, 0, test_div_table, &imx_ccm_lock);
+ clks[IMX7D_PLL_VIDEO_POST_DIV] = clk_register_divider_table(NULL, "pll_video_post_div", "pll_video_main_clk",
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x130, 22, 2, 0, post_div_table, &imx_ccm_lock);
clks[IMX7D_PLL_SYS_PFD0_392M_CLK] = imx_clk_pfd("pll_sys_pfd0_392m_clk", "pll_sys_main_clk", base + 0xc0, 0);
clks[IMX7D_PLL_SYS_PFD1_332M_CLK] = imx_clk_pfd("pll_sys_pfd1_332m_clk", "pll_sys_main_clk", base + 0xc0, 1);
@@ -509,7 +509,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_ARM_A7_ROOT_SRC] = imx_clk_mux2("arm_a7_src", base + 0x8000, 24, 3, arm_a7_sel, ARRAY_SIZE(arm_a7_sel));
clks[IMX7D_ARM_M4_ROOT_SRC] = imx_clk_mux2("arm_m4_src", base + 0x8080, 24, 3, arm_m4_sel, ARRAY_SIZE(arm_m4_sel));
- clks[IMX7D_ARM_M0_ROOT_SRC] = imx_clk_mux2("arm_m0_src", base + 0x8100, 24, 3, arm_m0_sel, ARRAY_SIZE(arm_m0_sel));
clks[IMX7D_MAIN_AXI_ROOT_SRC] = imx_clk_mux2("axi_src", base + 0x8800, 24, 3, axi_sel, ARRAY_SIZE(axi_sel));
clks[IMX7D_DISP_AXI_ROOT_SRC] = imx_clk_mux2("disp_axi_src", base + 0x8880, 24, 3, disp_axi_sel, ARRAY_SIZE(disp_axi_sel));
clks[IMX7D_ENET_AXI_ROOT_SRC] = imx_clk_mux2("enet_axi_src", base + 0x8900, 24, 3, enet_axi_sel, ARRAY_SIZE(enet_axi_sel));
@@ -523,7 +522,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_PCIE_CTRL_ROOT_SRC] = imx_clk_mux2("pcie_ctrl_src", base + 0xa180, 24, 3, pcie_ctrl_sel, ARRAY_SIZE(pcie_ctrl_sel));
clks[IMX7D_PCIE_PHY_ROOT_SRC] = imx_clk_mux2("pcie_phy_src", base + 0xa200, 24, 3, pcie_phy_sel, ARRAY_SIZE(pcie_phy_sel));
clks[IMX7D_EPDC_PIXEL_ROOT_SRC] = imx_clk_mux2("epdc_pixel_src", base + 0xa280, 24, 3, epdc_pixel_sel, ARRAY_SIZE(epdc_pixel_sel));
- clks[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_mux2("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel));
+ clks[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_mux_flags("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel), CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
clks[IMX7D_MIPI_DSI_ROOT_SRC] = imx_clk_mux2("mipi_dsi_src", base + 0xa380, 24, 3, mipi_dsi_sel, ARRAY_SIZE(mipi_dsi_sel));
clks[IMX7D_MIPI_CSI_ROOT_SRC] = imx_clk_mux2("mipi_csi_src", base + 0xa400, 24, 3, mipi_csi_sel, ARRAY_SIZE(mipi_csi_sel));
clks[IMX7D_MIPI_DPHY_ROOT_SRC] = imx_clk_mux2("mipi_dphy_src", base + 0xa480, 24, 3, mipi_dphy_sel, ARRAY_SIZE(mipi_dphy_sel));
@@ -581,7 +580,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_ARM_A7_ROOT_CG] = imx_clk_gate3("arm_a7_cg", "arm_a7_src", base + 0x8000, 28);
clks[IMX7D_ARM_M4_ROOT_CG] = imx_clk_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28);
- clks[IMX7D_ARM_M0_ROOT_CG] = imx_clk_gate3("arm_m0_cg", "arm_m0_src", base + 0x8100, 28);
clks[IMX7D_MAIN_AXI_ROOT_CG] = imx_clk_gate3("axi_cg", "axi_src", base + 0x8800, 28);
clks[IMX7D_DISP_AXI_ROOT_CG] = imx_clk_gate3("disp_axi_cg", "disp_axi_src", base + 0x8880, 28);
clks[IMX7D_ENET_AXI_ROOT_CG] = imx_clk_gate3("enet_axi_cg", "enet_axi_src", base + 0x8900, 28);
@@ -718,14 +716,14 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_CLKO1_ROOT_PRE_DIV] = imx_clk_divider2("clko1_pre_div", "clko1_cg", base + 0xbd80, 16, 3);
clks[IMX7D_CLKO2_ROOT_PRE_DIV] = imx_clk_divider2("clko2_pre_div", "clko2_cg", base + 0xbe00, 16, 3);
- clks[IMX7D_ARM_A7_ROOT_DIV] = imx_clk_divider2("arm_a7_div", "arm_a7_cg", base + 0x8000, 0, 3);
+ clks[IMX7D_ARM_A7_ROOT_DIV] = imx_clk_divider_flags("arm_a7_div", "arm_a7_cg", base + 0x8000, 0, 3, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
clks[IMX7D_ARM_M4_ROOT_DIV] = imx_clk_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3);
- clks[IMX7D_ARM_M0_ROOT_DIV] = imx_clk_divider2("arm_m0_div", "arm_m0_cg", base + 0x8100, 0, 3);
- clks[IMX7D_MAIN_AXI_ROOT_DIV] = imx_clk_divider2("axi_post_div", "axi_pre_div", base + 0x8800, 0, 6);
+ clks[IMX7D_MAIN_AXI_ROOT_DIV] = imx_clk_divider_flags("axi_post_div", "axi_pre_div", base + 0x8800, 0, 6, CLK_OPS_PARENT_ENABLE);
clks[IMX7D_DISP_AXI_ROOT_DIV] = imx_clk_divider2("disp_axi_post_div", "disp_axi_pre_div", base + 0x8880, 0, 6);
clks[IMX7D_ENET_AXI_ROOT_DIV] = imx_clk_divider2("enet_axi_post_div", "enet_axi_pre_div", base + 0x8900, 0, 6);
- clks[IMX7D_NAND_USDHC_BUS_ROOT_DIV] = imx_clk_divider2("nand_usdhc_post_div", "nand_usdhc_pre_div", base + 0x8980, 0, 6);
- clks[IMX7D_AHB_CHANNEL_ROOT_DIV] = imx_clk_divider2("ahb_post_div", "ahb_pre_div", base + 0x9000, 0, 6);
+ clks[IMX7D_NAND_USDHC_BUS_ROOT_CLK] = imx_clk_divider2("nand_usdhc_root_clk", "nand_usdhc_pre_div", base + 0x8980, 0, 6);
+ clks[IMX7D_AHB_CHANNEL_ROOT_CLK] = imx_clk_divider_flags("ahb_root_clk", "ahb_pre_div", base + 0x9000, 0, 6, CLK_OPS_PARENT_ENABLE);
+ clks[IMX7D_IPG_ROOT_CLK] = imx_clk_divider2("ipg_root_clk", "ahb_root_clk", base + 0x9080, 0, 2);
clks[IMX7D_DRAM_ROOT_DIV] = imx_clk_divider2("dram_post_div", "dram_cg", base + 0x9880, 0, 3);
clks[IMX7D_DRAM_PHYM_ALT_ROOT_DIV] = imx_clk_divider2("dram_phym_alt_post_div", "dram_phym_alt_pre_div", base + 0xa000, 0, 3);
clks[IMX7D_DRAM_ALT_ROOT_DIV] = imx_clk_divider2("dram_alt_post_div", "dram_alt_pre_div", base + 0xa080, 0, 3);
@@ -736,7 +734,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_LCDIF_PIXEL_ROOT_DIV] = imx_clk_divider2("lcdif_pixel_post_div", "lcdif_pixel_pre_div", base + 0xa300, 0, 6);
clks[IMX7D_MIPI_DSI_ROOT_DIV] = imx_clk_divider2("mipi_dsi_post_div", "mipi_dsi_pre_div", base + 0xa380, 0, 6);
clks[IMX7D_MIPI_CSI_ROOT_DIV] = imx_clk_divider2("mipi_csi_post_div", "mipi_csi_pre_div", base + 0xa400, 0, 6);
- clks[IMX7D_MIPI_DPHY_ROOT_DIV] = imx_clk_divider2("mipi_dphy_post_div", "mipi_csi_dphy_div", base + 0xa480, 0, 6);
+ clks[IMX7D_MIPI_DPHY_ROOT_DIV] = imx_clk_divider2("mipi_dphy_post_div", "mipi_dphy_pre_div", base + 0xa480, 0, 6);
clks[IMX7D_SAI1_ROOT_DIV] = imx_clk_divider2("sai1_post_div", "sai1_pre_div", base + 0xa500, 0, 6);
clks[IMX7D_SAI2_ROOT_DIV] = imx_clk_divider2("sai2_post_div", "sai2_pre_div", base + 0xa580, 0, 6);
clks[IMX7D_SAI3_ROOT_DIV] = imx_clk_divider2("sai3_post_div", "sai3_pre_div", base + 0xa600, 0, 6);
@@ -747,7 +745,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_ENET2_TIME_ROOT_DIV] = imx_clk_divider2("enet2_time_post_div", "enet2_time_pre_div", base + 0xa880, 0, 6);
clks[IMX7D_ENET_PHY_REF_ROOT_DIV] = imx_clk_divider2("enet_phy_ref_post_div", "enet_phy_ref_pre_div", base + 0xa900, 0, 6);
clks[IMX7D_EIM_ROOT_DIV] = imx_clk_divider2("eim_post_div", "eim_pre_div", base + 0xa980, 0, 6);
- clks[IMX7D_NAND_ROOT_DIV] = imx_clk_divider2("nand_post_div", "nand_pre_div", base + 0xaa00, 0, 6);
+ clks[IMX7D_NAND_ROOT_CLK] = imx_clk_divider2("nand_root_clk", "nand_pre_div", base + 0xaa00, 0, 6);
clks[IMX7D_QSPI_ROOT_DIV] = imx_clk_divider2("qspi_post_div", "qspi_pre_div", base + 0xaa80, 0, 6);
clks[IMX7D_USDHC1_ROOT_DIV] = imx_clk_divider2("usdhc1_post_div", "usdhc1_pre_div", base + 0xab00, 0, 6);
clks[IMX7D_USDHC2_ROOT_DIV] = imx_clk_divider2("usdhc2_post_div", "usdhc2_pre_div", base + 0xab80, 0, 6);
@@ -789,21 +787,22 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_CLKO1_ROOT_DIV] = imx_clk_divider2("clko1_post_div", "clko1_pre_div", base + 0xbd80, 0, 6);
clks[IMX7D_CLKO2_ROOT_DIV] = imx_clk_divider2("clko2_post_div", "clko2_pre_div", base + 0xbe00, 0, 6);
- clks[IMX7D_ARM_A7_ROOT_CLK] = imx_clk_gate4("arm_a7_root_clk", "arm_a7_div", base + 0x4000, 0);
+ clks[IMX7D_ARM_A7_ROOT_CLK] = imx_clk_gate2_flags("arm_a7_root_clk", "arm_a7_div", base + 0x4000, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
clks[IMX7D_ARM_M4_ROOT_CLK] = imx_clk_gate4("arm_m4_root_clk", "arm_m4_div", base + 0x4010, 0);
- clks[IMX7D_ARM_M0_ROOT_CLK] = imx_clk_gate4("arm_m0_root_clk", "arm_m0_div", base + 0x4020, 0);
clks[IMX7D_MAIN_AXI_ROOT_CLK] = imx_clk_gate4("main_axi_root_clk", "axi_post_div", base + 0x4040, 0);
clks[IMX7D_DISP_AXI_ROOT_CLK] = imx_clk_gate4("disp_axi_root_clk", "disp_axi_post_div", base + 0x4050, 0);
clks[IMX7D_ENET_AXI_ROOT_CLK] = imx_clk_gate4("enet_axi_root_clk", "enet_axi_post_div", base + 0x4060, 0);
- clks[IMX7D_OCRAM_CLK] = imx_clk_gate4("ocram_clk", "axi_post_div", base + 0x4110, 0);
- clks[IMX7D_OCRAM_S_CLK] = imx_clk_gate4("ocram_s_clk", "ahb_post_div", base + 0x4120, 0);
- clks[IMX7D_NAND_USDHC_BUS_ROOT_CLK] = imx_clk_gate4("nand_usdhc_root_clk", "nand_usdhc_post_div", base + 0x4130, 0);
- clks[IMX7D_AHB_CHANNEL_ROOT_CLK] = imx_clk_gate4("ahb_root_clk", "ahb_post_div", base + 0x4200, 0);
+ clks[IMX7D_OCRAM_CLK] = imx_clk_gate4("ocram_clk", "main_axi_root_clk", base + 0x4110, 0);
+ clks[IMX7D_OCRAM_S_CLK] = imx_clk_gate4("ocram_s_clk", "ahb_root_clk", base + 0x4120, 0);
+ clks[IMX7D_CAAM_CLK] = imx_clk_gate4("caam_clk", "ipg_root_clk", base + 0x4240, 0);
clks[IMX7D_DRAM_ROOT_CLK] = imx_clk_gate4("dram_root_clk", "dram_post_div", base + 0x4130, 0);
clks[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_gate4("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0);
clks[IMX7D_DRAM_PHYM_ALT_ROOT_CLK] = imx_clk_gate4("dram_phym_alt_root_clk", "dram_phym_alt_post_div", base + 0x4130, 0);
clks[IMX7D_DRAM_ALT_ROOT_CLK] = imx_clk_gate4("dram_alt_root_clk", "dram_alt_post_div", base + 0x4130, 0);
- clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4420, 0);
+ clks[IMX7D_MU_ROOT_CLK] = imx_clk_gate4("mu_root_clk", "ipg_root_clk", base + 0x4270, 0);
+ clks[IMX7D_SEMA4_HS_ROOT_CLK] = imx_clk_gate4("sema4_hs_root_clk", "ipg_root_clk", base + 0x4280, 0);
+ clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0);
+ clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0);
clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0);
clks[IMX7D_PCIE_CTRL_ROOT_CLK] = imx_clk_gate4("pcie_ctrl_root_clk", "pcie_ctrl_post_div", base + 0x4600, 0);
clks[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_gate4("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0);
@@ -812,6 +811,10 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_MIPI_DSI_ROOT_CLK] = imx_clk_gate4("mipi_dsi_root_clk", "mipi_dsi_post_div", base + 0x4650, 0);
clks[IMX7D_MIPI_CSI_ROOT_CLK] = imx_clk_gate4("mipi_csi_root_clk", "mipi_csi_post_div", base + 0x4640, 0);
clks[IMX7D_MIPI_DPHY_ROOT_CLK] = imx_clk_gate4("mipi_dphy_root_clk", "mipi_dphy_post_div", base + 0x4660, 0);
+ clks[IMX7D_ENET1_IPG_ROOT_CLK] = imx_clk_gate2_shared2("enet1_ipg_root_clk", "enet_axi_post_div", base + 0x4700, 0, &share_count_enet1);
+ clks[IMX7D_ENET1_TIME_ROOT_CLK] = imx_clk_gate2_shared2("enet1_time_root_clk", "enet1_time_post_div", base + 0x4700, 0, &share_count_enet1);
+ clks[IMX7D_ENET2_IPG_ROOT_CLK] = imx_clk_gate2_shared2("enet2_ipg_root_clk", "enet_axi_post_div", base + 0x4710, 0, &share_count_enet2);
+ clks[IMX7D_ENET2_TIME_ROOT_CLK] = imx_clk_gate2_shared2("enet2_time_root_clk", "enet2_time_post_div", base + 0x4710, 0, &share_count_enet2);
clks[IMX7D_SAI1_ROOT_CLK] = imx_clk_gate2_shared2("sai1_root_clk", "sai1_post_div", base + 0x48c0, 0, &share_count_sai1);
clks[IMX7D_SAI1_IPG_CLK] = imx_clk_gate2_shared2("sai1_ipg_clk", "ipg_root_clk", base + 0x48c0, 0, &share_count_sai1);
clks[IMX7D_SAI2_ROOT_CLK] = imx_clk_gate2_shared2("sai2_root_clk", "sai2_post_div", base + 0x48d0, 0, &share_count_sai2);
@@ -819,13 +822,9 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_SAI3_ROOT_CLK] = imx_clk_gate2_shared2("sai3_root_clk", "sai3_post_div", base + 0x48e0, 0, &share_count_sai3);
clks[IMX7D_SAI3_IPG_CLK] = imx_clk_gate2_shared2("sai3_ipg_clk", "ipg_root_clk", base + 0x48e0, 0, &share_count_sai3);
clks[IMX7D_SPDIF_ROOT_CLK] = imx_clk_gate4("spdif_root_clk", "spdif_post_div", base + 0x44d0, 0);
- clks[IMX7D_ENET1_REF_ROOT_CLK] = imx_clk_gate4("enet1_ref_root_clk", "enet1_ref_post_div", base + 0x44e0, 0);
- clks[IMX7D_ENET1_TIME_ROOT_CLK] = imx_clk_gate4("enet1_time_root_clk", "enet1_time_post_div", base + 0x44f0, 0);
- clks[IMX7D_ENET2_REF_ROOT_CLK] = imx_clk_gate4("enet2_ref_root_clk", "enet2_ref_post_div", base + 0x4500, 0);
- clks[IMX7D_ENET2_TIME_ROOT_CLK] = imx_clk_gate4("enet2_time_root_clk", "enet2_time_post_div", base + 0x4510, 0);
- clks[IMX7D_ENET_PHY_REF_ROOT_CLK] = imx_clk_gate4("enet_phy_ref_root_clk", "enet_phy_ref_post_div", base + 0x4520, 0);
clks[IMX7D_EIM_ROOT_CLK] = imx_clk_gate4("eim_root_clk", "eim_post_div", base + 0x4160, 0);
- clks[IMX7D_NAND_ROOT_CLK] = imx_clk_gate4("nand_root_clk", "nand_post_div", base + 0x4140, 0);
+ clks[IMX7D_NAND_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_rawnand_clk", "nand_root_clk", base + 0x4140, 0, &share_count_nand);
+ clks[IMX7D_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_root_clk", base + 0x4140, 0, &share_count_nand);
clks[IMX7D_QSPI_ROOT_CLK] = imx_clk_gate4("qspi_root_clk", "qspi_post_div", base + 0x4150, 0);
clks[IMX7D_USDHC1_ROOT_CLK] = imx_clk_gate4("usdhc1_root_clk", "usdhc1_post_div", base + 0x46c0, 0);
clks[IMX7D_USDHC2_ROOT_CLK] = imx_clk_gate4("usdhc2_root_clk", "usdhc2_post_div", base + 0x46d0, 0);
@@ -867,7 +866,12 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_CSI_MCLK_ROOT_CLK] = imx_clk_gate4("csi_mclk_root_clk", "csi_mclk_post_div", base + 0x4490, 0);
clks[IMX7D_AUDIO_MCLK_ROOT_CLK] = imx_clk_gate4("audio_mclk_root_clk", "audio_mclk_post_div", base + 0x4790, 0);
clks[IMX7D_WRCLK_ROOT_CLK] = imx_clk_gate4("wrclk_root_clk", "wrclk_post_div", base + 0x47a0, 0);
+ clks[IMX7D_USB_CTRL_CLK] = imx_clk_gate4("usb_ctrl_clk", "ahb_root_clk", base + 0x4680, 0);
+ clks[IMX7D_USB_PHY1_CLK] = imx_clk_gate4("usb_phy1_clk", "pll_usb1_main_clk", base + 0x46a0, 0);
+ clks[IMX7D_USB_PHY2_CLK] = imx_clk_gate4("usb_phy2_clk", "pll_usb_main_clk", base + 0x46b0, 0);
clks[IMX7D_ADC_ROOT_CLK] = imx_clk_gate4("adc_root_clk", "ipg_root_clk", base + 0x4200, 0);
+ clks[IMX7D_PXP_IPG_CLK] = imx_clk_gate2_shared2("pxp_ipg_clk", "ipg_root_clk", base + 0x44c0, 0, &share_count_pxp);
+ clks[IMX7D_PXP_AXI_CLK] = imx_clk_gate2_shared2("pxp_axi_clk", "main_axi_root_clk", base + 0x44c0, 0, &share_count_pxp);
clks[IMX7D_GPT_3M_CLK] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
@@ -886,13 +890,47 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
clk_prepare_enable(clks[clks_init_on[i]]);
+ if (imx_src_is_m4_enabled()) {
+ imx_clk_set_parent(clks[IMX7D_ARM_M4_ROOT_SRC], clks[IMX7D_PLL_SYS_MAIN_240M_CLK]);
+ imx_clk_prepare_enable(clks[IMX7D_ARM_M4_ROOT_CLK]);
+ }
+
+ imx_clk_set_parent(clks[IMX7D_PLL_ARM_MAIN_BYPASS], clks[IMX7D_PLL_ARM_MAIN]);
+ imx_clk_set_parent(clks[IMX7D_PLL_DRAM_MAIN_BYPASS], clks[IMX7D_PLL_DRAM_MAIN]);
+ imx_clk_set_parent(clks[IMX7D_PLL_SYS_MAIN_BYPASS], clks[IMX7D_PLL_SYS_MAIN]);
+ imx_clk_set_parent(clks[IMX7D_PLL_ENET_MAIN_BYPASS], clks[IMX7D_PLL_ENET_MAIN]);
+ imx_clk_set_parent(clks[IMX7D_PLL_AUDIO_MAIN_BYPASS], clks[IMX7D_PLL_AUDIO_MAIN]);
+ imx_clk_set_parent(clks[IMX7D_PLL_VIDEO_MAIN_BYPASS], clks[IMX7D_PLL_VIDEO_MAIN]);
+
/* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */
- clk_set_parent(clks[IMX7D_GPT1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]);
+ imx_clk_set_parent(clks[IMX7D_GPT1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]);
- /* set uart module clock's parent clock source that must be great then 80MHz */
- clk_set_parent(clks[IMX7D_UART1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]);
+ /* set pcie root's parent clk source */
+ imx_clk_set_parent(clks[IMX7D_PCIE_CTRL_ROOT_SRC], clks[IMX7D_PLL_ENET_MAIN_250M_CLK]);
+ imx_clk_set_parent(clks[IMX7D_PCIE_PHY_ROOT_SRC], clks[IMX7D_PLL_ENET_MAIN_100M_CLK]);
- imx_register_uart_clocks(uart_clks);
+ /* Set clock rate for USBPHY, the USB_PLL at CCM is from USBOTG2 */
+ clks[IMX7D_USB1_MAIN_480M_CLK] = imx_clk_fixed_factor("pll_usb1_main_clk", "osc", 20, 1);
+ clks[IMX7D_USB_MAIN_480M_CLK] = imx_clk_fixed_factor("pll_usb_main_clk", "osc", 20, 1);
+ /* set parent of EPDC pixel clock */
+ imx_clk_set_parent(clks[IMX7D_EPDC_PIXEL_ROOT_SRC], clks[IMX7D_PLL_SYS_MAIN_CLK]);
+
+ /* set lcdif pixel root clock source to get the required 33Mhz clock */
+ imx_clk_set_parent(clks[IMX7D_LCDIF_PIXEL_ROOT_SRC], clks[IMX7D_PLL_VIDEO_POST_DIV]);
+
+ imx_clk_set_parent(clks[IMX7D_MIPI_CSI_ROOT_SRC], clks[IMX7D_PLL_SYS_PFD3_CLK]);
+
+ /* set parent of SIM1 root clock */
+ imx_clk_set_parent(clks[IMX7D_SIM1_ROOT_SRC], clks[IMX7D_PLL_SYS_MAIN_120M_CLK]);
+
+ imx_clk_set_parent(clks[IMX7D_UART3_ROOT_SRC], clks[IMX7D_PLL_SYS_MAIN_240M_CLK]);
+ imx_clk_set_rate(clks[IMX7D_UART3_ROOT_DIV], 80000000);
+ imx_clk_set_parent(clks[IMX7D_UART5_ROOT_SRC], clks[IMX7D_PLL_SYS_MAIN_240M_CLK]);
+ imx_clk_set_rate(clks[IMX7D_UART5_ROOT_DIV], 80000000);
+ imx_clk_set_parent(clks[IMX7D_UART6_ROOT_SRC], clks[IMX7D_PLL_SYS_MAIN_240M_CLK]);
+ imx_clk_set_rate(clks[IMX7D_UART6_ROOT_DIV], 80000000);
+
+ imx_register_uart_clocks(uart_clks);
}
CLK_OF_DECLARE(imx7d, "fsl,imx7d-ccm", imx7d_clocks_init);
diff --git a/drivers/clk/imx/clk-imx7ulp.c b/drivers/clk/imx/clk-imx7ulp.c
new file mode 100644
index 000000000000..02c369a8a674
--- /dev/null
+++ b/drivers/clk/imx/clk-imx7ulp.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <dt-bindings/clock/imx7ulp-clock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include "clk.h"
+
+static const char *pll_pre_sels[] = { "sosc", "firc", };
+static const char *spll_pfd_sels[] = { "spll_pfd0", "spll_pfd1", "spll_pfd2", "spll_pfd3", };
+static const char *spll_sels[] = { "spll", "spll_pfd_sel", };
+static const char *apll_pfd_sels[] = { "apll_pfd0", "apll_pfd1", "apll_pfd2", "apll_pfd3", };
+static const char *apll_sels[] = { "apll", "apll_pfd_sel", };
+static const char *sys_sels[] = { "dummy", "sosc", "sirc", "firc", "rosc", "apll_sel", "spll_sel", "upll", };
+static const char *arm_sels[] = { "core_div", "dummy", "dummy", "hsrun_core", };
+static const char *ddr_sels[] = { "apll_pfd_sel", "upll", };
+static const char *nic_sels[] = { "firc", "ddr_div", };
+static const char *periph_plat_sels[] = { "dummy", "nic1_bus", "nic1_div", "ddr_div", "apll_pfd2", "apll_pfd1", "apll_pfd0", "upll", };
+static const char *periph_bus_sels[] = { "dummy", "sosc_bus_clk", "dummy", "firc_bus_clk", "rosc", "nic1_bus", "nic1_div", "spll_bus_clk", };
+static struct clk *clks[IMX7ULP_CLK_END];
+static struct clk_onecell_data clk_data;
+
+static const char *cm4_pll_pre_sels[] = { "cm4_sosc", "cm4_firc", };
+static const char *cm4_spll_pfd_sels[] = { "cm4_spll_pfd0", "cm4_spll_pfd1", "cm4_spll_pfd2", "cm4_spll_pfd3", };
+static const char *cm4_spll_sels[] = { "cm4_spll_vco", "cm4_spll_pfd_sel", };
+static const char *cm4_apll_pfd_sels[] = { "cm4_apll_pfd0", "cm4_apll_pfd1", "cm4_apll_pfd2", "cm4_apll_pfd3", };
+static const char *cm4_apll_sels[] = { "cm4_apll_vco_post_div2", "cm4_apll_pfd_sel", };
+static const char *cm4_sys_sels[] = { "cm4_dummy", "cm4_sosc", "cm4_sirc", "cm4_firc", "cm4_rosc", "cm4_apll_sel", "cm4_spll_sel", "cm4_dummy", };
+static const char *cm4_periph_bus_sels[] = { "cm4_dummy", "cm4_sosc", "cm4_sirc", "cm4_firc", "cm4_rosc", "cm4_bus_div", "cm4_spll_pfd2", "cm4_apll_pfd0_pre_div", };
+static const char *scg0_clkout_sels[] = { "dummy", "cm4_sosc", "cm4_sirc", "cm4_firc", "cm4_rosc", "cm4_apll_sel", "cm4_spll_sel", "dummy"};
+
+static struct clk *clks_cm4[IMX7ULP_CM4_CLK_END];
+static struct clk_onecell_data clk_data_cm4;
+
+
+static int const clks_init_on[] __initconst = {
+ IMX7ULP_CLK_BUS_DIV,
+ IMX7ULP_CLK_ARM,
+ IMX7ULP_CLK_NIC0_DIV,
+ IMX7ULP_CLK_NIC1_DIV,
+ IMX7ULP_CLK_NIC1_BUS_DIV,
+ IMX7ULP_CLK_MMDC,
+};
+
+/* used by sosc/sirc/firc/ddr/spll/apll dividers */
+static const struct clk_div_table ulp_div_table[] = {
+ { .val = 1, .div = 1, },
+ { .val = 2, .div = 2, },
+ { .val = 3, .div = 4, },
+ { .val = 4, .div = 8, },
+ { .val = 5, .div = 16, },
+ { .val = 6, .div = 32, },
+ { .val = 7, .div = 64, },
+ { }
+};
+
+static void __init imx7ulp_clocks_init(struct device_node *scg_node)
+{
+ struct device_node *np;
+ void __iomem *base;
+ void __iomem *smc_base;
+ int i;
+
+ clks[IMX7ULP_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+
+ clks[IMX7ULP_CLK_ROSC] = of_clk_get_by_name(scg_node, "rosc");
+ clks[IMX7ULP_CLK_SOSC] = of_clk_get_by_name(scg_node, "sosc");
+ clks[IMX7ULP_CLK_SIRC] = of_clk_get_by_name(scg_node, "sirc");
+ clks[IMX7ULP_CLK_FIRC] = of_clk_get_by_name(scg_node, "firc");
+ clks[IMX7ULP_CLK_MIPI_PLL] = of_clk_get_by_name(scg_node, "mpll");
+ clks[IMX7ULP_CLK_UPLL] = of_clk_get_by_name(scg_node, "upll");
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-smc1");
+ smc_base = of_iomap(np, 0);
+ WARN_ON(!smc_base);
+
+ np = scg_node;
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks[IMX7ULP_CLK_SPLL_PRE_SEL] = imx_clk_mux("spll_pre_sel", base + 0x608, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels));
+ clks[IMX7ULP_CLK_APLL_PRE_SEL] = imx_clk_mux("apll_pre_sel", base + 0x508, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels));
+ /* name parent_name reg shift width */
+ clks[IMX7ULP_CLK_SPLL_PRE_DIV] = imx_clk_divider("spll_pre_div", "spll_pre_sel", base + 0x608, 8, 3);
+ clks[IMX7ULP_CLK_APLL_PRE_DIV] = imx_clk_divider("apll_pre_div", "apll_pre_sel", base + 0x508, 8, 3);
+ /* name parent_name base*/
+ clks[IMX7ULP_CLK_SPLL] = imx_clk_pllv4("spll", "spll_pre_div", base + 0x600);
+ clks[IMX7ULP_CLK_APLL] = imx_clk_pllv4("apll", "apll_pre_div", base + 0x500);
+
+ /* SPLL PFDs */
+ clks[IMX7ULP_CLK_SPLL_PFD0] = imx_clk_pfdv2("spll_pfd0", "spll", base + 0x60C, 0);
+ clks[IMX7ULP_CLK_SPLL_PFD1] = imx_clk_pfdv2("spll_pfd1", "spll", base + 0x60C, 1);
+ clks[IMX7ULP_CLK_SPLL_PFD2] = imx_clk_pfdv2("spll_pfd2", "spll", base + 0x60C, 2);
+ clks[IMX7ULP_CLK_SPLL_PFD3] = imx_clk_pfdv2("spll_pfd3", "spll", base + 0x60C, 3);
+ /* APLL PFDs */
+ clks[IMX7ULP_CLK_APLL_PFD0] = imx_clk_pfdv2("apll_pfd0", "apll", base + 0x50C, 0);
+ clks[IMX7ULP_CLK_APLL_PFD1] = imx_clk_pfdv2("apll_pfd1", "apll", base + 0x50C, 1);
+ clks[IMX7ULP_CLK_APLL_PFD2] = imx_clk_pfdv2("apll_pfd2", "apll", base + 0x50C, 2);
+ clks[IMX7ULP_CLK_APLL_PFD3] = imx_clk_pfdv2("apll_pfd3", "apll", base + 0x50C, 3);
+
+ clks[IMX7ULP_CLK_SPLL_PFD_SEL] = imx_clk_mux("spll_pfd_sel", base + 0x608, 14, 2, spll_pfd_sels, ARRAY_SIZE(spll_pfd_sels));
+ clks[IMX7ULP_CLK_APLL_PFD_SEL] = imx_clk_mux("apll_pfd_sel", base + 0x508, 14, 2, apll_pfd_sels, ARRAY_SIZE(apll_pfd_sels));
+
+ clks[IMX7ULP_CLK_SPLL_SEL] = imx_clk_mux("spll_sel", base + 0x608, 1, 1, spll_sels, ARRAY_SIZE(spll_sels));
+ clks[IMX7ULP_CLK_APLL_SEL] = imx_clk_mux("apll_sel", base + 0x508, 1, 1, apll_sels, ARRAY_SIZE(apll_sels));
+
+ clks[IMX7ULP_CLK_SPLL_BUS_CLK] = clk_register_divider_table(NULL, "spll_bus_clk", "spll_sel", CLK_SET_RATE_GATE, base + 0x604, 8, 3,
+ CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_ZERO_GATE, ulp_div_table, &imx_ccm_lock);
+
+ /* sys/ddr/nic select different clock source requires that clock to be enabled first */
+ clks[IMX7ULP_CLK_SYS_SEL] = imx_clk_mux2("sys_sel", base + 0x14, 24, 4, sys_sels, ARRAY_SIZE(sys_sels));
+ clks[IMX7ULP_CLK_HSRUN_SYS_SEL] = imx_clk_mux2("hsrun_sys_sel", base + 0x1c, 24, 4, sys_sels, ARRAY_SIZE(sys_sels));
+ clks[IMX7ULP_CLK_DDR_SEL] = imx_clk_mux2("ddr_sel", base + 0x30, 24, 1, ddr_sels, ARRAY_SIZE(ddr_sels));
+ clks[IMX7ULP_CLK_NIC_SEL] = imx_clk_mux2("nic_sel", base + 0x40, 28, 1, nic_sels, ARRAY_SIZE(nic_sels));
+
+ clks[IMX7ULP_CLK_CORE_DIV] = imx_clk_divider_flags("core_div", "sys_sel", base + 0x14, 16, 4, CLK_SET_RATE_PARENT);
+ clks[IMX7ULP_CLK_HSRUN_CORE] = imx_clk_divider_flags("hsrun_core", "hsrun_sys_sel", base + 0x1c, 16, 4, CLK_SET_RATE_PARENT);
+
+ clks[IMX7ULP_CLK_PLAT_DIV] = imx_clk_divider("plat_div", "core_div", base + 0x14, 12, 4);
+ /* Fake mux */
+ clks[IMX7ULP_CLK_ARM] = imx_clk_mux_glitchless("arm", smc_base + 0x10, 8, 2, arm_sels, ARRAY_SIZE(arm_sels));
+
+ clks[IMX7ULP_CLK_DDR_DIV] = clk_register_divider_table(NULL, "ddr_div", "ddr_sel", CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, base + 0x30, 0, 3,
+ CLK_DIVIDER_ZERO_GATE, ulp_div_table, &imx_ccm_lock);
+
+ clks[IMX7ULP_CLK_NIC0_DIV] = imx_clk_divider_flags("nic0_div", "nic_sel", base + 0x40, 24, 4, CLK_SET_RATE_PARENT);
+ clks[IMX7ULP_CLK_NIC1_DIV] = imx_clk_divider_flags("nic1_div", "nic0_div", base + 0x40, 16, 4, CLK_SET_RATE_PARENT);
+ clks[IMX7ULP_CLK_NIC1_BUS_DIV] = imx_clk_divider_flags("nic1_bus", "nic0_div", base + 0x40, 4, 4, CLK_SET_RATE_PARENT);
+
+ clks[IMX7ULP_CLK_GPU_DIV] = imx_clk_divider("gpu_div", "nic0_div", base + 0x40, 20, 4);
+
+ clks[IMX7ULP_CLK_SOSC_BUS_CLK] = clk_register_divider_table(NULL, "sosc_bus_clk", "sosc", 0, base + 0x104, 8, 3,
+ CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_ZERO_GATE, ulp_div_table, &imx_ccm_lock);
+ clks[IMX7ULP_CLK_FIRC_BUS_CLK] = clk_register_divider_table(NULL, "firc_bus_clk", "firc", 0, base + 0x304, 8, 3,
+ CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_ZERO_GATE, ulp_div_table, &imx_ccm_lock);
+
+ /* PCC2 */
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-pcc2");
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks[IMX7ULP_CLK_DMA1] = imx_clk_gate("dma1", "nic1_bus", base + 0x20, 30);
+ clks[IMX7ULP_CLK_RGPIO2P1] = imx_clk_gate("rgpio2p1", "nic1_bus", base + 0x3c, 30);
+ clks[IMX7ULP_CLK_DMA_MUX1] = imx_clk_gate("dma_mux1", "nic1_bus", base + 0x84, 30);
+ clks[IMX7ULP_CLK_CAAM] = imx_clk_gate("caam", "nic1_div", base + 0x90, 30);
+ clks[IMX7ULP_CLK_LPTPM4] = imx_clk_composite("lptpm4", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x94);
+ clks[IMX7ULP_CLK_LPTPM5] = imx_clk_composite("lptmp5", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x98);
+ clks[IMX7ULP_CLK_LPIT1] = imx_clk_composite("lpit1", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x9C);
+ clks[IMX7ULP_CLK_LPSPI2] = imx_clk_composite("lpspi2", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xA4);
+ clks[IMX7ULP_CLK_LPSPI3] = imx_clk_composite("lpspi3", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xA8);
+ clks[IMX7ULP_CLK_LPI2C4] = imx_clk_composite("lpi2c4", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xAC);
+ clks[IMX7ULP_CLK_LPI2C5] = imx_clk_composite("lpi2c5", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xB0);
+ clks[IMX7ULP_CLK_LPUART4] = imx_clk_composite("lpuart4", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xB4);
+ clks[IMX7ULP_CLK_LPUART5] = imx_clk_composite("lpuart5", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xB8);
+ clks[IMX7ULP_CLK_FLEXIO1] = imx_clk_composite("flexio", periph_bus_sels, ARRAY_SIZE(periph_plat_sels), true, false, true, base + 0xC4);
+ clks[IMX7ULP_CLK_USB0] = imx_clk_composite("usb0", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true, true, base + 0xCC);
+ clks[IMX7ULP_CLK_USB1] = imx_clk_composite("usb1", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true, true, base + 0xD0);
+ clks[IMX7ULP_CLK_USB_PHY] = imx_clk_gate("usb_phy", "nic1_bus", base + 0xD4, 30);
+ clks[IMX7ULP_CLK_USDHC0] = imx_clk_composite("usdhc0", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true, true, base + 0xDC);
+ clks[IMX7ULP_CLK_USDHC1] = imx_clk_composite("usdhc1", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true, true, base + 0xE0);
+ clks[IMX7ULP_CLK_WDG1] = imx_clk_composite("wdg1", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, true, true, base + 0xF4);
+ clks[IMX7ULP_CLK_WDG2] = imx_clk_composite("wdg2", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, true, true, base + 0x10C);
+
+ /* PCC3 */
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-pcc3");
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks[IMX7ULP_CLK_LPTPM6] = imx_clk_composite("lptpm6", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x84);
+ clks[IMX7ULP_CLK_LPTPM7] = imx_clk_composite("lptpm7", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x88);
+ clks[IMX7ULP_CLK_LPI2C6] = imx_clk_composite("lpi2c6", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x90);
+ clks[IMX7ULP_CLK_LPI2C7] = imx_clk_composite("lpi2c7", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x94);
+ clks[IMX7ULP_CLK_LPUART6] = imx_clk_composite("lpuart6", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x98);
+ clks[IMX7ULP_CLK_LPUART7] = imx_clk_composite("lpuart7", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x9C);
+ clks[IMX7ULP_CLK_VIU] = imx_clk_gate("viu", "nic1_div", base + 0xA0, 30);
+ clks[IMX7ULP_CLK_DSI] = imx_clk_composite("dsi", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, true, true, base + 0xA4);
+ clks[IMX7ULP_CLK_LCDIF] = imx_clk_composite("lcdif", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true, true, base + 0xA8);
+ clks[IMX7ULP_CLK_MMDC] = imx_clk_gate("mmdc", "nic1_div", base + 0xAC, 30);
+ clks[IMX7ULP_CLK_GPU3D] = imx_clk_composite("gpu3d", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, false, true, base + 0x140);
+ clks[IMX7ULP_CLK_PCTLC] = imx_clk_gate("pctlc", "nic1_bus", base + 0xb8, 30);
+ clks[IMX7ULP_CLK_PCTLD] = imx_clk_gate("pctld", "nic1_bus", base + 0xbc, 30);
+ clks[IMX7ULP_CLK_PCTLE] = imx_clk_gate("pctle", "nic1_bus", base + 0xc0, 30);
+ clks[IMX7ULP_CLK_PCTLF] = imx_clk_gate("pctlf", "nic1_bus", base + 0xc4, 30);
+ clks[IMX7ULP_CLK_GPU2D] = imx_clk_composite("gpu2d", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, false, true, base + 0x144);
+
+ imx_check_clocks(clks, ARRAY_SIZE(clks));
+
+ clk_data.clks = clks;
+ clk_data.clk_num = ARRAY_SIZE(clks);
+ of_clk_add_provider(scg_node, of_clk_src_onecell_get, &clk_data);
+
+ for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
+ imx_clk_prepare_enable(clks[clks_init_on[i]]);
+ imx_clk_set_parent(clks[IMX7ULP_CLK_GPU2D], clks[IMX7ULP_CLK_APLL_PFD2]);
+ imx_clk_set_parent(clks[IMX7ULP_CLK_GPU3D], clks[IMX7ULP_CLK_APLL_PFD2]);
+
+ imx_clk_set_rate(clks[IMX7ULP_CLK_APLL_PFD2], 400000000);
+
+ /* setting the rate for emmc/sd usage */
+ imx_clk_set_rate(clks[IMX7ULP_CLK_APLL_PFD1], 352800000);
+
+ pr_info("i.MX7ULP clock tree init done.\n");
+}
+
+CLK_OF_DECLARE(imx7ulp, "fsl,imx7ulp-scg1", imx7ulp_clocks_init);
+
+static struct clk_div_table apll_pfd0_div_table[] = {
+ { .val = 1, .div = 1, },
+ { .val = 0, .div = 2, },
+ { /* sentinel */ }
+};
+
+static u32 share_count_sai0;
+static u32 share_count_sai1;
+
+static void __init imx7ulp_cm4_clocks_init(struct device_node *scg_node)
+{
+ struct device_node *np, *np_sim;
+ void __iomem *base;
+ void __iomem *base_sim;
+
+ clks_cm4[IMX7ULP_CM4_CLK_DUMMY] = imx_clk_fixed("cm4_dummy", 0);
+
+ clks_cm4[IMX7ULP_CM4_CLK_ROSC] = of_clk_get_by_name(scg_node, "cm4_rosc");
+ clks_cm4[IMX7ULP_CM4_CLK_SOSC] = of_clk_get_by_name(scg_node, "cm4_sosc");
+ clks_cm4[IMX7ULP_CM4_CLK_SIRC] = of_clk_get_by_name(scg_node, "cm4_sirc");
+ clks_cm4[IMX7ULP_CM4_CLK_FIRC] = of_clk_get_by_name(scg_node, "cm4_firc");
+
+ np = scg_node;
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ np_sim = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-sim");
+ base_sim = of_iomap(np_sim, 0);
+ WARN_ON(!base_sim);
+
+ clks_cm4[IMX7ULP_CM4_CLK_SPLL_VCO_PRE_SEL] = imx_clk_mux("cm4_spll_vco_pre_sel", base + 0x608, 0, 1, cm4_pll_pre_sels, ARRAY_SIZE(cm4_pll_pre_sels));
+ clks_cm4[IMX7ULP_CM4_CLK_APLL_VCO_PRE_SEL] = imx_clk_mux("cm4_apll_vco_pre_sel", base + 0x508, 0, 1, cm4_pll_pre_sels, ARRAY_SIZE(cm4_pll_pre_sels));
+ /* name parent_name reg shift width */
+ clks_cm4[IMX7ULP_CM4_CLK_SPLL_VCO_PRE_DIV] = imx_clk_divider("cm4_spll_vco_pre_div", "cm4_spll_vco_pre_sel", base + 0x608, 8, 3);
+ clks_cm4[IMX7ULP_CM4_CLK_APLL_VCO_PRE_DIV] = imx_clk_divider("cm4_apll_vco_pre_div", "cm4_apll_vco_pre_sel", base + 0x508, 8, 3);
+ /* name parent_name base*/
+ clks_cm4[IMX7ULP_CM4_CLK_SPLL_VCO] = imx_clk_pllv5("cm4_spll_vco", "cm4_spll_vco_pre_div", base + 0x600);
+ clks_cm4[IMX7ULP_CM4_CLK_APLL_VCO] = imx_clk_pllv4("cm4_apll_vco", "cm4_apll_vco_pre_div", base + 0x500);
+
+ clks_cm4[IMX7ULP_CM4_CLK_APLL_VCO_POST_DIV1] = imx_clk_divider("cm4_apll_vco_post_div1", "cm4_apll_vco", base + 0x508, 24, 4);
+ clks_cm4[IMX7ULP_CM4_CLK_APLL_VCO_POST_DIV2] = imx_clk_divider("cm4_apll_vco_post_div2", "cm4_apll_vco_post_div1", base + 0x508, 28, 4);
+
+ /* SPLL PFDs */
+ clks_cm4[IMX7ULP_CM4_CLK_SPLL_PFD0] = imx_clk_pfdv2("cm4_spll_pfd0", "cm4_spll_vco", base + 0x60C, 0);
+ clks_cm4[IMX7ULP_CM4_CLK_SPLL_PFD1] = imx_clk_pfdv2("cm4_spll_pfd1", "cm4_spll_vco", base + 0x60C, 1);
+ clks_cm4[IMX7ULP_CM4_CLK_SPLL_PFD2] = imx_clk_pfdv2("cm4_spll_pfd2", "cm4_spll_vco", base + 0x60C, 2);
+ clks_cm4[IMX7ULP_CM4_CLK_SPLL_PFD3] = imx_clk_pfdv2("cm4_spll_pfd3", "cm4_spll_vco", base + 0x60C, 3);
+ /* APLL PFDs */
+ clks_cm4[IMX7ULP_CM4_CLK_APLL_PFD0] = imx_clk_pfdv2("cm4_apll_pfd0", "cm4_apll_vco", base + 0x50C, 0);
+ clks_cm4[IMX7ULP_CM4_CLK_APLL_PFD1] = imx_clk_pfdv2("cm4_apll_pfd1", "cm4_apll_vco", base + 0x50C, 1);
+ clks_cm4[IMX7ULP_CM4_CLK_APLL_PFD2] = imx_clk_pfdv2("cm4_apll_pfd2", "cm4_apll_vco", base + 0x50C, 2);
+ clks_cm4[IMX7ULP_CM4_CLK_APLL_PFD3] = imx_clk_pfdv2("cm4_apll_pfd3", "cm4_apll_vco", base + 0x50C, 3);
+
+ clks_cm4[IMX7ULP_CM4_CLK_APLL_PFD0_PRE_DIV] = clk_register_divider_table(NULL, "cm4_apll_pfd0_pre_div", "cm4_apll_pfd0", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base_sim + 0x2c, 5, 1, 0, apll_pfd0_div_table, &imx_ccm_lock);
+
+ clks_cm4[IMX7ULP_CM4_CLK_SPLL_PFD_SEL] = imx_clk_mux("cm4_spll_pfd_sel", base + 0x608, 14, 2, cm4_spll_pfd_sels, ARRAY_SIZE(cm4_spll_pfd_sels));
+ clks_cm4[IMX7ULP_CM4_CLK_APLL_PFD_SEL] = imx_clk_mux("cm4_apll_pfd_sel", base + 0x508, 14, 2, cm4_apll_pfd_sels, ARRAY_SIZE(cm4_apll_pfd_sels));
+
+ clks_cm4[IMX7ULP_CM4_CLK_SPLL_SEL] = imx_clk_mux("cm4_spll_sel", base + 0x608, 1, 1, cm4_spll_sels, ARRAY_SIZE(cm4_spll_sels));
+ clks_cm4[IMX7ULP_CM4_CLK_APLL_SEL] = imx_clk_mux("cm4_apll_sel", base + 0x508, 1, 1, cm4_apll_sels, ARRAY_SIZE(cm4_apll_sels));
+
+ clks_cm4[IMX7ULP_CM4_CLK_SYS_SEL] = imx_clk_mux("cm4_sys_sel", base + 0x14, 24, 4, cm4_sys_sels, ARRAY_SIZE(cm4_sys_sels));
+
+ clks_cm4[IMX7ULP_CM4_CLK_CORE_DIV] = imx_clk_divider("cm4_core_div", "cm4_sys_sel", base + 0x14, 16, 4);
+ clks_cm4[IMX7ULP_CM4_CLK_PLAT_DIV] = imx_clk_divider("cm4_plat_div", "cm4_core_div", base + 0x14, 12, 4);
+ clks_cm4[IMX7ULP_CM4_CLK_BUS_DIV] = imx_clk_divider("cm4_bus_div", "cm4_core_div", base + 0x14, 4, 4);
+ clks_cm4[IMX7ULP_CM4_CLK_SLOW_DIV] = imx_clk_divider("cm4_slow_div", "cm4_core_div", base + 0x14, 0, 4);
+
+ clks_cm4[IMX7ULP_CLK_SCG0_CLKOUT] = imx_clk_mux("scg0_clkout", base + 0x20, 24, 4, scg0_clkout_sels, ARRAY_SIZE(scg0_clkout_sels));
+
+ /* PCG0 */
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-pcc0");
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks_cm4[IMX7ULP_CM4_CLK_SAI0_SEL] = imx_clk_mux("cm4_sai0_sel", base + 0xDC, 24, 3, cm4_periph_bus_sels, ARRAY_SIZE(cm4_periph_bus_sels));
+ clks_cm4[IMX7ULP_CM4_CLK_SAI0_DIV] = imx_clk_divider("cm4_sai0_div", "cm4_sai0_sel", base + 0xDC, 0, 8);
+ clks_cm4[IMX7ULP_CM4_CLK_SAI0_ROOT] = imx_clk_gate2_shared("cm4_sai0_root", "cm4_sai0_div", base + 0xDC, 30, &share_count_sai0);
+ clks_cm4[IMX7ULP_CM4_CLK_SAI0_IPG] = imx_clk_gate2_shared("cm4_sai0_ipg", "cm4_bus_div", base + 0xDC, 30, &share_count_sai0);
+
+ /* PCG1 */
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx7ulp-pcc1");
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+
+ clks_cm4[IMX7ULP_CM4_CLK_SAI1_SEL] = imx_clk_mux("cm4_sai1_sel", base + 0xA8, 24, 3, cm4_periph_bus_sels, ARRAY_SIZE(cm4_periph_bus_sels));
+ clks_cm4[IMX7ULP_CM4_CLK_SAI1_DIV] = imx_clk_divider("cm4_sai1_div", "cm4_sai1_sel", base + 0xA8, 0, 8);
+ clks_cm4[IMX7ULP_CM4_CLK_SAI1_ROOT] = imx_clk_gate2_shared("cm4_sai1_root", "cm4_sai1_div", base + 0xA8, 30, &share_count_sai1);
+ clks_cm4[IMX7ULP_CM4_CLK_SAI1_IPG] = imx_clk_gate2_shared("cm4_sai1_ipg", "cm4_bus_div", base + 0xA8, 30, &share_count_sai1);
+
+ imx_check_clocks(clks_cm4, ARRAY_SIZE(clks_cm4));
+
+ clk_data_cm4.clks = clks_cm4;
+ clk_data_cm4.clk_num = ARRAY_SIZE(clks_cm4);
+ of_clk_add_provider(scg_node, of_clk_src_onecell_get, &clk_data_cm4);
+
+ imx_clk_prepare_enable(clks_cm4[IMX7ULP_CM4_CLK_SYS_SEL]);
+
+ pr_info("i.MX7ULP cm4 clock tree init.\n");
+}
+CLK_OF_DECLARE(imx7ulp_cm4, "fsl,imx7ulp-scg0", imx7ulp_cm4_clocks_init);
diff --git a/drivers/clk/imx/clk-imx8.c b/drivers/clk/imx/clk-imx8.c
new file mode 100644
index 000000000000..fb5896a09b79
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/errno.h>
+#include <soc/imx8/sc/sci.h>
+
+#include "clk-imx8.h"
+
+sc_ipc_t ccm_ipc_handle;
+
+int imx8_clk_mu_init(void)
+{
+ uint32_t mu_id;
+ sc_err_t sciErr;
+
+ printk("MU and Power domains initialized\n");
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_info("Cannot obtain MU ID\n");
+ return -EPROBE_DEFER;
+ }
+
+ sciErr = sc_ipc_open(&ccm_ipc_handle, mu_id);
+
+ if (sciErr != SC_ERR_NONE) {
+ pr_info("Cannot open MU channel to SCU\n");
+ return -EPROBE_DEFER;
+ }
+
+ return 0;
+}
+
+bool imx8_clk_is_resource_owned(sc_rsrc_t rsrc)
+{
+ /*
+ * A-core resources are special. SCFW reports they are not "owned" by
+ * current partition but linux can still adjust them for cpufreq.
+ *
+ * So force this to return false when running as a VM guest and always
+ * true otherwise.
+ */
+ if (rsrc == SC_R_A53 || rsrc == SC_R_A72 || rsrc == SC_R_A35) {
+ if (xen_domain() && !xen_initial_domain())
+ return false;
+ return true;
+ }
+
+ if (!ccm_ipc_handle) {
+ pr_warn("%s: no ipc handle!\n", __func__);
+ /* should have handled -EPROBE_DEFER from clk_mu_init earlier. */
+ return false;
+ }
+
+ return sc_rm_is_resource_owned(ccm_ipc_handle, rsrc);
+}
diff --git a/drivers/clk/imx/clk-imx8.h b/drivers/clk/imx/clk-imx8.h
new file mode 100644
index 000000000000..05552b44b507
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8.h
@@ -0,0 +1,130 @@
+#ifndef __IMX8_CLK_H
+#define __IMX8_CLK_H
+
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <soc/imx8/sc/sci.h>
+
+extern spinlock_t imx_ccm_lock;
+extern sc_ipc_t ccm_ipc_handle;
+
+int imx8_clk_mu_init(void);
+bool imx8_clk_is_resource_owned(sc_rsrc_t rsrc);
+
+struct clk *imx_clk_divider_scu(const char *name,
+ sc_rsrc_t rsrc_id, sc_pm_clk_t clk_type);
+
+struct clk *imx_clk_divider2_scu(const char *name, const char *parent_name,
+ sc_rsrc_t rsrc_id, sc_pm_clk_t clk_type);
+
+struct clk *imx_clk_divider3_scu(const char *name, const char *parent_name,
+ sc_rsrc_t rsrc_id, sc_ctrl_t gpr_id);
+
+struct clk *clk_register_gate_scu(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ u8 clk_gate_scu_flags, spinlock_t *lock,
+ sc_rsrc_t rsrc_id, sc_pm_clk_t clk_type,
+ void __iomem *reg, u8 bit_idx, bool hw_gate);
+
+struct clk *clk_register_gate2_scu(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 bit_idx,
+ u8 clk_gate_flags, spinlock_t *lock, const char *pd_name);
+
+struct clk *clk_register_mux_scu(struct device *dev, const char *name,
+ const char **parent_names, u8 num_parents, unsigned long flags,
+ void __iomem *reg, u8 shift, u8 width,
+ u8 clk_mux_flags, spinlock_t *lock,
+ const char *pd_name);
+
+struct clk *clk_register_gate3_scu(struct device *dev, const char *name,
+ const char *parent_name, spinlock_t *lock,
+ sc_rsrc_t rsrc_id, sc_ctrl_t gpr_id, bool invert_flag);
+
+struct clk *clk_register_mux_gpr_scu(struct device *dev, const char *name,
+ const char **parents, int num_parents, spinlock_t *lock,
+ sc_rsrc_t rsrc_id, sc_ctrl_t gpr_id);
+
+struct clk *clk_register_mux2_scu(struct device *dev, const char *name,
+ const char **parents, int num_parents, unsigned long flags,
+ sc_rsrc_t rsrc_id, sc_pm_clk_t clk_type);
+
+static inline struct clk *imx_clk_fixed(const char *name, int rate)
+{
+ return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
+}
+
+static inline struct clk *imx_clk_gate_scu(const char *name, const char *parent,
+ sc_rsrc_t rsrc_id, sc_pm_clk_t clk_type,
+ void __iomem *reg, u8 bit_idx, bool hw_gate)
+{
+ return clk_register_gate_scu(NULL, name, parent,
+ CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, 0,
+ &imx_ccm_lock, rsrc_id, clk_type, reg,
+ bit_idx, hw_gate);
+}
+
+static inline struct clk *imx_clk_gate2_scu(const char *name, const char *parent,
+ void __iomem *reg, u8 bit_idx, const char *pd_name)
+{
+ return clk_register_gate2_scu(NULL, name, parent, 0, reg,
+ bit_idx, 0, &imx_ccm_lock, pd_name);
+}
+
+static inline struct clk *imx_clk_gate3_scu(const char *name, const char *parent,
+ sc_rsrc_t rsrc_id, sc_ctrl_t gpr_id, bool invert_flag)
+{
+ return clk_register_gate3_scu(NULL, name, parent,
+ &imx_ccm_lock, rsrc_id, gpr_id, invert_flag);
+}
+
+static inline struct clk *imx_clk_mux_gpr_scu(const char *name, const char **parents,
+ int num_parents, sc_rsrc_t rsrc_id, sc_ctrl_t gpr_id)
+{
+ return clk_register_mux_gpr_scu(NULL, name, parents, num_parents,
+ &imx_ccm_lock, rsrc_id, gpr_id);
+}
+
+static inline struct clk *imx_clk_mux2_scu(const char *name,
+ const char **parents, int num_parents, sc_rsrc_t rsrc_id,
+ sc_pm_clk_t clk_type)
+{
+ return clk_register_mux2_scu(NULL, name, parents, num_parents,
+ CLK_SET_RATE_NO_REPARENT, rsrc_id,
+ clk_type);
+}
+
+static inline void imx_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ int ret = clk_set_rate(clk, rate);
+
+ if (ret)
+ pr_err("failed to set rate of clk %s to %ld: %d\n",
+ __clk_get_name(clk), rate, ret);
+}
+
+static inline struct clk *imx_clk_gate(const char *name, const char *parent,
+ void __iomem *reg, u8 shift)
+{
+ return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+ shift, 0, &imx_ccm_lock);
+}
+
+static inline struct clk *imx_clk_fixed_factor(const char *name,
+ const char *parent, unsigned int mult, unsigned int div)
+{
+ return clk_register_fixed_factor(NULL, name, parent,
+ CLK_SET_RATE_PARENT, mult, div);
+}
+
+static inline struct clk *imx_clk_mux_scu(const char *name, void __iomem *reg,
+ u8 shift, u8 width, const char **parents, int num_parents, const char *pd_name)
+{
+ return clk_register_mux_scu(NULL, name, parents, num_parents,
+ CLK_SET_RATE_NO_REPARENT, reg, shift,
+ width, 0, &imx_ccm_lock, pd_name);
+}
+
+
+#endif
diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c
new file mode 100644
index 000000000000..4381f57dc8a0
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8mm.c
@@ -0,0 +1,985 @@
+/*
+ * Copyright 2017-2018 NXP.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <dt-bindings/clock/imx8mm-clock.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/types.h>
+#include <soc/imx8/soc.h>
+
+#include "clk.h"
+
+static u32 share_count_sai1;
+static u32 share_count_sai2;
+static u32 share_count_sai3;
+static u32 share_count_sai4;
+static u32 share_count_sai5;
+static u32 share_count_sai6;
+static u32 share_count_dcss;
+static u32 share_count_pdm;
+
+/* IDs of PLLs available on i.MX8 Mini */
+enum {
+ ARM_PLL,
+ GPU_PLL,
+ VPU_PLL,
+ SYS_PLL1,
+ SYS_PLL2,
+ SYS_PLL3,
+ DRAM_PLL,
+ AUDIO_PLL1,
+ AUDIO_PLL2,
+ VIDEO_PLL2,
+ NR_PLLS,
+};
+
+#define PLL_1416X_RATE(_rate, _m, _p, _s) \
+ { \
+ .rate = (_rate), \
+ .mdiv = (_m), \
+ .pdiv = (_p), \
+ .sdiv = (_s), \
+ }
+
+#define PLL_1443X_RATE(_rate, _m, _p, _s, _k) \
+ { \
+ .rate = (_rate), \
+ .mdiv = (_m), \
+ .pdiv = (_p), \
+ .sdiv = (_s), \
+ .kdiv = (_k), \
+ }
+
+static const struct imx_int_pll_rate_table imx8mm_intpll_tbl[] = {
+ PLL_1416X_RATE(1800000000U, 225, 3, 0),
+ PLL_1416X_RATE(1600000000U, 200, 3, 0),
+ PLL_1416X_RATE(1200000000U, 300, 3, 1),
+ PLL_1416X_RATE(1000000000U, 250, 3, 1),
+ PLL_1416X_RATE(800000000U, 200, 3, 1),
+ PLL_1416X_RATE(750000000U, 250, 2, 2),
+ PLL_1416X_RATE(700000000U, 350, 3, 2),
+ PLL_1416X_RATE(600000000U, 300, 3, 2),
+};
+
+static const struct imx_int_pll_rate_table imx8mm_audiopll_tbl[] = {
+ PLL_1443X_RATE(786432000U, 655, 5, 2, 23593),
+ PLL_1443X_RATE(722534400U, 301, 5, 1, 3670),
+};
+
+static const struct imx_int_pll_rate_table imx8mm_videopll_tbl[] = {
+ PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
+ PLL_1443X_RATE(594000000U, 198, 2, 2, 0),
+};
+
+static const struct imx_int_pll_rate_table imx8mm_drampll_tbl[] = {
+ PLL_1443X_RATE(650000000U, 325, 3, 2, 0),
+};
+
+static struct imx_int_pll_clk imx8mm_audio_pll __initdata = {
+ .type = PLL_1443X,
+ .rate_table = imx8mm_audiopll_tbl,
+};
+
+static struct imx_int_pll_clk imx8mm_video_pll __initdata = {
+ .type = PLL_1443X,
+ .rate_table = imx8mm_videopll_tbl,
+};
+
+static struct imx_int_pll_clk imx8mm_dram_pll __initdata = {
+ .type = PLL_1443X,
+ .rate_table = imx8mm_drampll_tbl,
+};
+
+static struct imx_int_pll_clk imx8mm_arm_pll __initdata = {
+ .type = PLL_1416X,
+ .rate_table = imx8mm_intpll_tbl,
+};
+
+static struct imx_int_pll_clk imx8mm_gpu_pll __initdata = {
+ .type = PLL_1416X,
+ .rate_table = imx8mm_intpll_tbl,
+};
+
+static struct imx_int_pll_clk imx8mm_vpu_pll __initdata = {
+ .type = PLL_1416X,
+ .rate_table = imx8mm_intpll_tbl,
+};
+
+static struct imx_int_pll_clk imx8mm_sys_pll __initdata = {
+ .type = PLL_1416X,
+ .rate_table = imx8mm_intpll_tbl,
+};
+
+static const char *pll_ref_sels[] = { "osc_24m", "dummy", "dummy", "dummy", };
+static const char *audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", };
+static const char *audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", };
+static const char *video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", };
+static const char *dram_pll_bypass_sels[] = {"dram_pll", "dram_pll_ref_sel", };
+static const char *gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", };
+static const char *vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", };
+static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
+static const char *sys_pll1_bypass_sels[] = {"sys_pll1", "sys_pll1_ref_sel", };
+static const char *sys_pll2_bypass_sels[] = {"sys_pll2", "sys_pll2_ref_sel", };
+static const char *sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", };
+
+/* CCM ROOT */
+static const char *imx8mm_a53_sels[] = {"osc_24m", "arm_pll_out", "sys_pll2_500m", "sys_pll2_1000m",
+ "sys_pll1_800m", "sys_pll1_400m", "audio_pll1_out", "sys_pll3_out", };
+
+static const char *imx8mm_m4_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_250m", "sys_pll1_266m",
+ "sys_pll1_800m", "audio_pll1_out", "video_pll1_out", "sys_pll3_out", };
+
+static const char *imx8mm_vpu_sels[] = {"osc_24m", "arm_pll_out", "sys_pll2_500m", "sys_pll2_1000m",
+ "sys_pll1_800m", "sys_pll1_400m", "audio_pll1_out", "vpu_pll_out", };
+
+static const char *imx8mm_gpu3d_sels[] = {"osc_24m", "gpu_pll_out", "sys_pll1_800m", "sys_pll3_out",
+ "sys_pll2_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
+
+static const char *imx8mm_gpu2d_sels[] = {"osc_24m", "gpu_pll_out", "sys_pll1_800m", "sys_pll3_out",
+ "sys_pll2_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
+
+static const char *imx8mm_main_axi_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll1_800m", "sys_pll2_250m",
+ "sys_pll2_1000m", "audio_pll1_out", "video_pll1_out", "sys_pll1_100m",};
+
+static const char *imx8mm_enet_axi_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_250m",
+ "sys_pll2_200m", "audio_pll1_out", "video_pll1_out", "sys_pll3_out", };
+
+static const char *imx8mm_nand_usdhc_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_200m",
+ "sys_pll1_133m", "sys_pll3_out", "sys_pll2_250m", "audio_pll1_out", };
+
+static const char *imx8mm_vpu_bus_sels[] = {"osc_24m", "sys_pll1_800m", "vpu_pll_out", "audio_pll2_out",
+ "sys_pll3_out", "sys_pll2_1000m", "sys_pll2_200m", "sys_pll1_100m", };
+
+static const char *imx8mm_disp_axi_sels[] = {"osc_24m", "sys_pll2_1000m", "sys_pll1_800m", "sys_pll3_out",
+ "sys_pll1_40m", "audio_pll2_out", "clk_ext1", "clk_ext4", };
+
+static const char *imx8mm_disp_apb_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll1_800m", "sys_pll3_out",
+ "sys1_pll_40m", "audio_pll2_out", "clk_ext1", "clk_ext3", };
+
+static const char *imx8mm_disp_rtrm_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll2_200m", "sys_pll2_1000m",
+ "audio_pll1_out", "video_pll1_out", "clk_ext2", "clk_ext3", };
+
+static const char *imx8mm_usb_bus_sels[] = {"osc_24m", "sys_pll2_500m", "sys_pll1_800m", "sys_pll2_100m",
+ "sys_pll2_200m", "clk_ext2", "clk_ext4", "audio_pll2_out", };
+
+static const char *imx8mm_gpu_axi_sels[] = {"osc_24m", "sys_pll1_800m", "gpu_pll_out", "sys_pll3_out", "sys_pll2_1000m",
+ "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
+
+static const char *imx8mm_gpu_ahb_sels[] = {"osc_24m", "sys_pll1_800m", "gpu_pll_out", "sys_pll3_out", "sys_pll2_1000m",
+ "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
+
+static const char *imx8mm_noc_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll3_out", "sys_pll2_1000m", "sys_pll2_500m",
+ "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
+
+static const char *imx8mm_noc_apb_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll3_out", "sys_pll2_333m", "sys_pll2_200m",
+ "sys_pll1_800m", "audio_pll1_out", "video_pll1_out", };
+
+static const char *imx8mm_ahb_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_800m", "sys_pll1_400m",
+ "sys_pll2_125m", "sys_pll3_out", "audio_pll1_out", "video_pll1_out", };
+
+static const char *imx8mm_audio_ahb_sels[] = {"osc_24m", "sys_pll2_500m", "sys_pll1_800m", "sys_pll2_1000m",
+ "sys_pll2_166m", "sys_pll3_out", "audio_pll1_out", "video_pll1_out", };
+
+static const char *imx8mm_dram_alt_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll1_100m", "sys_pll2_500m",
+ "sys_pll2_1000m", "sys_pll3_out", "audio_pll1_out", "sys_pll1_266m", };
+
+static const char *imx8mm_dram_apb_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", "sys_pll1_160m",
+ "sys_pll1_800m", "sys_pll3_out", "sys_pll2_250m", "audio_pll2_out", };
+
+static const char *imx8mm_vpu_g1_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_800m", "sys_pll2_1000m",
+ "sys_pll1_100m", "sys_pll2_125m", "sys_pll3_out", "audio_pll1_out", };
+
+static const char *imx8mm_vpu_g2_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_800m", "sys_pll2_1000m",
+ "sys_pll1_100m", "sys_pll2_125m", "sys_pll3_out", "audio_pll1_out", };
+
+static const char *imx8mm_disp_dtrc_sels[] = {"osc_24m", "video_pll2_out", "sys_pll1_800m", "sys_pll2_1000m",
+ "sys_pll1_160m", "video_pll1_out", "sys_pll3_out", "audio_pll2_out", };
+
+static const char *imx8mm_disp_dc8000_sels[] = {"osc_24m", "video_pll2_out", "sys_pll1_800m", "sys_pll2_1000m",
+ "sys_pll1_160m", "video_pll1_out", "sys_pll3_out", "audio_pll2_out", };
+
+static const char *imx8mm_pcie1_ctrl_sels[] = {"osc_24m", "sys_pll2_250m", "sys_pll2_200m", "sys_pll1_266m",
+ "sys_pll1_800m", "sys_pll2_500m", "sys_pll2_333m", "sys_pll3_out", };
+
+static const char *imx8mm_pcie1_phy_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll2_500m", "clk_ext1", "clk_ext2",
+ "clk_ext3", "clk_ext4", "sys_pll1_400m", };
+
+static const char *imx8mm_pcie1_aux_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_50m", "sys_pll3_out",
+ "sys_pll2_100m", "sys_pll1_80m", "sys_pll1_160m", "sys_pll1_200m", };
+
+static const char *imx8mm_dc_pixel_sels[] = {"osc_24m", "video_pll1_out", "audio_pll2_out", "audio_pll1_out",
+ "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out", "clk_ext4", };
+
+static const char *imx8mm_lcdif_pixel_sels[] = {"osc_24m", "video_pll1_out", "audio_pll2_out", "audio_pll1_out",
+ "sys_pll1_800m", "sys_pll2_1000m", "sys_pll3_out", "clk_ext4", };
+
+static const char *imx8mm_sai1_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out",
+ "sys_pll1_133m", "osc_hdmi", "clk_ext1", "clk_ext2", };
+
+static const char *imx8mm_sai2_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out",
+ "sys_pll1_133m", "osc_hdmi", "clk_ext2", "clk_ext3", };
+
+static const char *imx8mm_sai3_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out",
+ "sys_pll1_133m", "osc_hdmi", "clk_ext3", "clk_ext4", };
+
+static const char *imx8mm_sai4_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out",
+ "sys_pll1_133m", "osc_hdmi", "clk_ext1", "clk_ext2", };
+
+static const char *imx8mm_sai5_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out",
+ "sys_pll1_133m", "osc_hdmi", "clk_ext2", "clk_ext3", };
+
+static const char *imx8mm_sai6_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out",
+ "sys_pll1_133m", "osc_hdmi", "clk_ext3", "clk_ext4", };
+
+static const char *imx8mm_spdif1_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out",
+ "sys_pll1_133m", "osc_hdmi", "clk_ext2", "clk_ext3", };
+
+static const char *imx8mm_spdif2_sels[] = {"osc_24m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out",
+ "sys_pll1_133m", "osc_hdmi", "clk_ext3", "clk_ext4", };
+
+static const char *imx8mm_enet_ref_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_50m", "sys_pll2_100m",
+ "sys_pll1_160m", "audio_pll1_out", "video_pll1_out", "clk_ext4", };
+
+static const char *imx8mm_enet_timer_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_out", "clk_ext1", "clk_ext2",
+ "clk_ext3", "clk_ext4", "video_pll1_out", };
+
+static const char *imx8mm_enet_phy_sels[] = {"osc_24m", "sys_pll2_50m", "sys_pll2_125m", "sys_pll2_200m",
+ "sys_pll2_500m", "video_pll1_out", "audio_pll2_out", };
+
+static const char *imx8mm_nand_sels[] = {"osc_24m", "sys_pll2_500m", "audio_pll1_out", "sys_pll1_400m",
+ "audio_pll2_out", "sys_pll3_out", "sys_pll2_250m", "video_pll1_out", };
+
+static const char *imx8mm_qspi_sels[] = {"osc_24m", "sys1_pll_400m", "sys_pll1_800m", "sys2_pll_500m",
+ "audio_pll2_out", "sys1_pll_266m", "sys3_pll2_out", "sys1_pll_100m", };
+
+static const char *imx8mm_usdhc1_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m",
+ "sys_pll3_out", "sys_pll1_266m", "audio_pll2_out", "sys_pll1_100m", };
+
+static const char *imx8mm_usdhc2_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m",
+ "sys_pll3_out", "sys_pll1_266m", "audio_pll2_out", "sys_pll1_100m", };
+
+static const char *imx8mm_i2c1_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out",
+ "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", };
+
+static const char *imx8mm_i2c2_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out",
+ "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", };
+
+static const char *imx8mm_i2c3_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out",
+ "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", };
+
+static const char *imx8mm_i2c4_sels[] = {"osc_24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out",
+ "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", };
+
+static const char *imx8mm_uart1_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m", "sys_pll2_100m",
+ "sys_pll3_out", "clk_ext2", "clk_ext4", "audio_pll2_out", };
+
+static const char *imx8mm_uart2_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m", "sys_pll2_100m",
+ "sys_pll3_out", "clk_ext2", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mm_uart3_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m", "sys_pll2_100m",
+ "sys_pll3_out", "clk_ext2", "clk_ext4", "audio_pll2_out", };
+
+static const char *imx8mm_uart4_sels[] = {"osc_24m", "sys_pll1_80m", "sys_pll2_200m", "sys_pll2_100m",
+ "sys_pll3_out", "clk_ext2", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mm_usb_core_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m", "sys_pll2_100m",
+ "sys_pll2_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mm_usb_phy_sels[] = {"osc_24m", "sys_pll1_100m", "sys_pll1_40m", "sys_pll2_100m",
+ "sys_pll2_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mm_ecspi1_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", "sys_pll1_160m",
+ "sys_pll1_800m", "sys_pll3_out", "sys_pll2_250m", "audio_pll2_out", };
+
+static const char *imx8mm_ecspi2_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", "sys_pll1_160m",
+ "sys_pll1_800m", "sys_pll3_out", "sys_pll2_250m", "audio_pll2_out", };
+
+static const char *imx8mm_pwm1_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m", "sys_pll1_40m",
+ "sys_pll3_out", "clk_ext1", "sys_pll1_80m", "video_pll1_out", };
+
+static const char *imx8mm_pwm2_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m", "sys_pll1_40m",
+ "sys_pll3_out", "clk_ext1", "sys_pll1_80m", "video_pll1_out", };
+
+static const char *imx8mm_pwm3_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m", "sys_pll1_40m",
+ "sys3_pll2_out", "clk_ext2", "sys_pll1_80m", "video_pll1_out", };
+
+static const char *imx8mm_pwm4_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_160m", "sys_pll1_40m",
+ "sys_pll3_out", "clk_ext2", "sys_pll1_80m", "video_pll1_out", };
+
+static const char *imx8mm_gpt1_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_400m", "sys_pll1_40m",
+ "video_pll1_out", "sys_pll1_800m", "audio_pll1_out", "clk_ext1" };
+
+static const char *imx8mm_wdog_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_160m", "vpu_pll_out",
+ "sys_pll2_125m", "sys_pll3_out", "sys_pll1_80m", "sys_pll2_166m", };
+
+static const char *imx8mm_wrclk_sels[] = {"osc_24m", "sys_pll1_40m", "vpu_pll_out", "sys_pll3_out", "sys_pll2_200m",
+ "sys_pll1_266m", "sys_pll2_500m", "sys_pll1_100m", };
+
+static const char *imx8mm_dsi_core_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_250m", "sys_pll1_800m",
+ "sys_pll2_1000m", "sys_pll3_out", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mm_dsi_phy_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_100m", "sys_pll1_800m",
+ "sys_pll2_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mm_dsi_dbi_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_100m", "sys_pll1_800m",
+ "sys_pll2_1000m", "sys_pll3_out", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mm_usdhc3_sels[] = {"osc_24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m",
+ "sys_pll3_out", "sys_pll1_266m", "audio_pll2_clk", "sys_pll1_100m", };
+
+static const char *imx8mm_csi1_core_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_250m", "sys_pll1_800m",
+ "sys_pll2_1000m", "sys_pll3_out", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mm_csi1_phy_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll2_100m", "sys_pll1_800m",
+ "sys_pll2_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mm_csi1_esc_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_80m", "sys_pll1_800m",
+ "sys_pll2_1000m", "sys_pll3_out", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mm_csi2_core_sels[] = {"osc_24m", "sys_pll1_266m", "sys_pll2_250m", "sys_pll1_800m",
+ "sys_pll2_1000m", "sys_pll3_out", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mm_csi2_phy_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll2_100m", "sys_pll1_800m",
+ "sys_pll2_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mm_csi2_esc_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll1_80m", "sys_pll1_800m",
+ "sys_pll2_1000m", "sys_pll3_out", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mm_pcie2_ctrl_sels[] = {"osc_24m", "sys_pll2_250m", "sys_pll2_200m", "sys_pll1_266m",
+ "sys_pll1_800m", "sys_pll2_500m", "sys_pll2_333m", "sys_pll3_out", };
+
+static const char *imx8mm_pcie2_phy_sels[] = {"osc_24m", "sys_pll2_100m", "sys_pll2_500m", "clk_ext1",
+ "clk_ext2", "clk_ext3", "clk_ext4", "sys_pll1_400m", };
+
+static const char *imx8mm_pcie2_aux_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll2_50m", "sys_pll3_out",
+ "sys_pll2_100m", "sys_pll1_80m", "sys_pll1_160m", "sys_pll1_200m", };
+
+static const char *imx8mm_ecspi3_sels[] = {"osc_24m", "sys_pll2_200m", "sys_pll1_40m", "sys_pll1_160m",
+ "sys_pll1_800m", "sys_pll3_out", "sys_pll2_250m", "audio_pll2_out", };
+
+static const char *imx8mm_pdm_sels[] = {"osc_24m", "sys_pll2_100m", "audio_pll1_out", "sys_pll1_800m",
+ "sys_pll2_1000m", "sys_pll3_out", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mm_vpu_h1_sels[] = {"osc_24m", "vpu_pll_out", "sys_pll1_800m", "sys_pll2_1000m",
+ "audio_pll2_clk", "sys_pll2_125m", "sys_pll3_clk", "audio_pll1_out", };
+
+static const char *imx8mm_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", };
+
+static struct clk *clks[IMX8MM_CLK_END];
+static struct clk_onecell_data clk_data;
+
+static int const clks_init_on[] __initconst = {
+ IMX8MM_CLK_AHB_CG, IMX8MM_CLK_DRAM_CORE,
+ IMX8MM_CLK_NOC_CG, IMX8MM_CLK_NOC_APB_CG,
+ IMX8MM_CLK_USB_BUS_CG,
+ IMX8MM_CLK_MAIN_AXI_CG, IMX8MM_CLK_AUDIO_AHB_CG,
+ IMX8MM_CLK_DRAM_APB_DIV, IMX8MM_CLK_A53_DIV,
+ IMX8MM_ARM_PLL_OUT, IMX8MM_CLK_DISP_AXI_CG,
+ IMX8MM_CLK_DISP_APB_CG,
+};
+
+static struct clk ** const uart_clks[] __initconst = {
+ &clks[IMX8MM_CLK_UART1_ROOT],
+ &clks[IMX8MM_CLK_UART2_ROOT],
+ &clks[IMX8MM_CLK_UART3_ROOT],
+ &clks[IMX8MM_CLK_UART4_ROOT],
+ NULL
+};
+
+static const char *imx8mm_clko1_sels[] = {"osc_24m", "sys_pll1_800m", "osc_27m", "sys_pll1_200m", "audio_pll2_clk",
+ "vpu_pll", "sys_pll1_80m", };
+
+static int __init imx_clk_init_on(struct device_node *np,
+ struct clk * const clks[])
+{
+ u32 *array;
+ int i, ret, elems;
+
+ elems = of_property_count_u32_elems(np, "init-on-array");
+ if (elems < 0)
+ return elems;
+ array = kcalloc(elems, sizeof(elems), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(array))
+ return PTR_ERR(array);
+
+ ret = of_property_read_u32_array(np, "init-on-array", array, elems);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < elems; i++) {
+ ret = clk_prepare_enable(clks[array[i]]);
+ if (ret)
+ pr_err("clk_prepare_enable failed %d\n", array[i]);
+ }
+
+ return 0;
+}
+
+static void __init imx8mm_clocks_init(struct device_node *ccm_node)
+{
+ struct device_node *np;
+ void __iomem *base;
+ int i;
+
+ check_m4_enabled();
+
+ clks[IMX8MM_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+ clks[IMX8MM_CLK_24M] = of_clk_get_by_name(ccm_node, "osc_24m");
+ clks[IMX8MM_CLK_32K] = of_clk_get_by_name(ccm_node, "osc_32k"); /* Check more */
+ clks[IMX8MM_CLK_EXT1] = of_clk_get_by_name(ccm_node, "clk_ext1");
+ clks[IMX8MM_CLK_EXT2] = of_clk_get_by_name(ccm_node, "clk_ext2");
+ clks[IMX8MM_CLK_EXT3] = of_clk_get_by_name(ccm_node, "clk_ext3");
+ clks[IMX8MM_CLK_EXT4] = of_clk_get_by_name(ccm_node, "clk_ext4");
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop");
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks[IMX8MM_AUDIO_PLL1_REF_SEL] = imx_clk_mux("audio_pll1_ref_sel", base + 0x0, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MM_AUDIO_PLL2_REF_SEL] = imx_clk_mux("audio_pll2_ref_sel", base + 0x14, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MM_VIDEO_PLL1_REF_SEL] = imx_clk_mux("video_pll1_ref_sel", base + 0x28, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MM_DRAM_PLL_REF_SEL] = imx_clk_mux("dram_pll_ref_sel", base + 0x50, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MM_GPU_PLL_REF_SEL] = imx_clk_mux("gpu_pll_ref_sel", base + 0x64, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MM_VPU_PLL_REF_SEL] = imx_clk_mux("vpu_pll_ref_sel", base + 0x74, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MM_ARM_PLL_REF_SEL] = imx_clk_mux("arm_pll_ref_sel", base + 0x84, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MM_SYS_PLL1_REF_SEL] = imx_clk_mux("sys_pll1_ref_sel", base + 0x94, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MM_SYS_PLL2_REF_SEL] = imx_clk_mux("sys_pll2_ref_sel", base + 0x104, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MM_SYS_PLL3_REF_SEL] = imx_clk_mux("sys_pll3_ref_sel", base + 0x114, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+
+ clks[IMX8MM_AUDIO_PLL1] = imx_clk_int_pll("audio_pll1", "audio_pll1_ref_sel", base, &imx8mm_audio_pll);
+ clks[IMX8MM_AUDIO_PLL2] = imx_clk_int_pll("audio_pll2", "audio_pll2_ref_sel", base + 0x14, &imx8mm_audio_pll);
+ clks[IMX8MM_VIDEO_PLL1] = imx_clk_int_pll("video_pll1", "video_pll1_ref_sel", base + 0x28, &imx8mm_video_pll);
+ clks[IMX8MM_DRAM_PLL] = imx_clk_int_pll("dram_pll", "dram_pll_ref_sel", base + 0x50, &imx8mm_dram_pll);
+ clks[IMX8MM_GPU_PLL] = imx_clk_int_pll("gpu_pll", "gpu_pll_ref_sel", base + 0x64, &imx8mm_gpu_pll);
+ clks[IMX8MM_VPU_PLL] = imx_clk_int_pll("vpu_pll", "vpu_pll_ref_sel", base + 0x74, &imx8mm_vpu_pll);
+ clks[IMX8MM_ARM_PLL] = imx_clk_int_pll("arm_pll", "arm_pll_ref_sel", base + 0x84, &imx8mm_arm_pll);
+ clks[IMX8MM_SYS_PLL1] = imx_clk_int_pll("sys_pll1", "sys_pll1_ref_sel", base + 0x94, &imx8mm_sys_pll);
+ clks[IMX8MM_SYS_PLL2] = imx_clk_int_pll("sys_pll2", "sys_pll2_ref_sel", base + 0x104, &imx8mm_sys_pll);
+ clks[IMX8MM_SYS_PLL3] = imx_clk_int_pll("sys_pll3", "sys_pll3_ref_sel", base + 0x114, &imx8mm_sys_pll);
+
+ /* PLL bypass out */
+ clks[IMX8MM_AUDIO_PLL1_BYPASS] = imx_clk_mux_flags("audio_pll1_bypass", base, 4, 1, audio_pll1_bypass_sels, ARRAY_SIZE(audio_pll1_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX8MM_AUDIO_PLL2_BYPASS] = imx_clk_mux_flags("audio_pll2_bypass", base + 0x14, 4, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX8MM_VIDEO_PLL1_BYPASS] = imx_clk_mux_flags("video_pll1_bypass", base + 0x28, 4, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX8MM_DRAM_PLL_BYPASS] = imx_clk_mux_flags("dram_pll_bypass", base + 0x50, 4, 1, dram_pll_bypass_sels, ARRAY_SIZE(dram_pll_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX8MM_GPU_PLL_BYPASS] = imx_clk_mux_flags("gpu_pll_bypass", base + 0x64, 4, 1, gpu_pll_bypass_sels, ARRAY_SIZE(gpu_pll_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX8MM_VPU_PLL_BYPASS] = imx_clk_mux_flags("vpu_pll_bypass", base + 0x74, 4, 1, vpu_pll_bypass_sels, ARRAY_SIZE(vpu_pll_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX8MM_ARM_PLL_BYPASS] = imx_clk_mux_flags("arm_pll_bypass", base + 0x84, 4, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX8MM_SYS_PLL1_BYPASS] = imx_clk_mux_flags("sys_pll1_bypass", base + 0x94, 4, 1, sys_pll1_bypass_sels, ARRAY_SIZE(sys_pll1_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX8MM_SYS_PLL2_BYPASS] = imx_clk_mux_flags("sys_pll2_bypass", base + 0x104, 4, 1, sys_pll2_bypass_sels, ARRAY_SIZE(sys_pll2_bypass_sels), CLK_SET_RATE_PARENT);
+ clks[IMX8MM_SYS_PLL3_BYPASS] = imx_clk_mux_flags("sys_pll3_bypass", base + 0x114, 4, 1, sys_pll3_bypass_sels, ARRAY_SIZE(sys_pll3_bypass_sels), CLK_SET_RATE_PARENT);
+
+ /* unbypass all the plls */
+ clk_set_parent(clks[IMX8MM_AUDIO_PLL1_BYPASS], clks[IMX8MM_AUDIO_PLL1]);
+ clk_set_parent(clks[IMX8MM_AUDIO_PLL2_BYPASS], clks[IMX8MM_AUDIO_PLL2]);
+ clk_set_parent(clks[IMX8MM_VIDEO_PLL1_BYPASS], clks[IMX8MM_VIDEO_PLL1]);
+ clk_set_parent(clks[IMX8MM_DRAM_PLL_BYPASS], clks[IMX8MM_DRAM_PLL]);
+ clk_set_parent(clks[IMX8MM_GPU_PLL_BYPASS], clks[IMX8MM_GPU_PLL]);
+ clk_set_parent(clks[IMX8MM_VPU_PLL_BYPASS], clks[IMX8MM_VPU_PLL]);
+ clk_set_parent(clks[IMX8MM_ARM_PLL_BYPASS], clks[IMX8MM_ARM_PLL]);
+ clk_set_parent(clks[IMX8MM_SYS_PLL1_BYPASS], clks[IMX8MM_SYS_PLL1]);
+ clk_set_parent(clks[IMX8MM_SYS_PLL2_BYPASS], clks[IMX8MM_SYS_PLL2]);
+ clk_set_parent(clks[IMX8MM_SYS_PLL3_BYPASS], clks[IMX8MM_SYS_PLL3]);
+
+ /* PLL out gate */
+ clks[IMX8MM_AUDIO_PLL1_OUT] = imx_clk_gate("audio_pll1_out", "audio_pll1_bypass", base, 13);
+ clks[IMX8MM_AUDIO_PLL2_OUT] = imx_clk_gate("audio_pll2_out", "audio_pll2_bypass", base + 0x14, 13);
+ clks[IMX8MM_VIDEO_PLL1_OUT] = imx_clk_gate("video_pll1_out", "video_pll1_bypass", base + 0x28, 13);
+ clks[IMX8MM_DRAM_PLL_OUT] = imx_clk_gate("dram_pll_out", "dram_pll_bypass", base + 0x50, 13);
+ clks[IMX8MM_GPU_PLL_OUT] = imx_clk_gate("gpu_pll_out", "gpu_pll_bypass", base + 0x64, 13);
+ clks[IMX8MM_VPU_PLL_OUT] = imx_clk_gate("vpu_pll_out", "vpu_pll_bypass", base + 0x74, 13);
+ clks[IMX8MM_ARM_PLL_OUT] = imx_clk_gate("arm_pll_out", "arm_pll_bypass", base + 0x84, 13);
+ clks[IMX8MM_SYS_PLL1_OUT] = imx_clk_gate("sys_pll1_out", "sys_pll1_bypass", base + 0x94, 13);
+ clks[IMX8MM_SYS_PLL2_OUT] = imx_clk_gate("sys_pll2_out", "sys_pll2_bypass", base + 0x104, 13);
+ clks[IMX8MM_SYS_PLL3_OUT] = imx_clk_gate("sys_pll3_out", "sys_pll3_bypass", base + 0x114, 13);
+
+ /* SYS PLL fixed output */
+ clks[IMX8MM_SYS_PLL1_40M] = imx_clk_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20);
+ clks[IMX8MM_SYS_PLL1_80M] = imx_clk_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10);
+ clks[IMX8MM_SYS_PLL1_100M] = imx_clk_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8);
+ clks[IMX8MM_SYS_PLL1_133M] = imx_clk_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6);
+ clks[IMX8MM_SYS_PLL1_160M] = imx_clk_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5);
+ clks[IMX8MM_SYS_PLL1_200M] = imx_clk_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4);
+ clks[IMX8MM_SYS_PLL1_266M] = imx_clk_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3);
+ clks[IMX8MM_SYS_PLL1_400M] = imx_clk_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2);
+ clks[IMX8MM_SYS_PLL1_800M] = imx_clk_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1);
+
+ clks[IMX8MM_SYS_PLL2_50M] = imx_clk_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20);
+ clks[IMX8MM_SYS_PLL2_100M] = imx_clk_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10);
+ clks[IMX8MM_SYS_PLL2_125M] = imx_clk_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8);
+ clks[IMX8MM_SYS_PLL2_166M] = imx_clk_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6);
+ clks[IMX8MM_SYS_PLL2_200M] = imx_clk_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5);
+ clks[IMX8MM_SYS_PLL2_250M] = imx_clk_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4);
+ clks[IMX8MM_SYS_PLL2_333M] = imx_clk_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3);
+ clks[IMX8MM_SYS_PLL2_500M] = imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2);
+ clks[IMX8MM_SYS_PLL2_1000M] = imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1);
+
+ np = ccm_node;
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ /* Core Slice */
+ clks[IMX8MM_CLK_A53_SRC] = imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mm_a53_sels, ARRAY_SIZE(imx8mm_a53_sels));
+ clks[IMX8MM_CLK_M4_SRC] = imx_clk_mux2("arm_m4_src", base + 0x8080, 24, 3, imx8mm_m4_sels, ARRAY_SIZE(imx8mm_m4_sels));
+ clks[IMX8MM_CLK_VPU_SRC] = imx_clk_mux2("vpu_src", base + 0x8100, 24, 3, imx8mm_vpu_sels, ARRAY_SIZE(imx8mm_vpu_sels));
+ clks[IMX8MM_CLK_GPU3D_SRC] = imx_clk_mux2("gpu3d_src", base + 0x8180, 24, 3, imx8mm_gpu3d_sels, ARRAY_SIZE(imx8mm_gpu3d_sels));
+ clks[IMX8MM_CLK_GPU2D_SRC] = imx_clk_mux2("gpu2d_src", base + 0x8200, 24, 3, imx8mm_gpu2d_sels, ARRAY_SIZE(imx8mm_gpu2d_sels));
+ clks[IMX8MM_CLK_A53_CG] = imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28);
+ clks[IMX8MM_CLK_M4_CG] = imx_clk_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28);
+ clks[IMX8MM_CLK_VPU_CG] = imx_clk_gate3("vpu_cg", "vpu_src", base + 0x8100, 28);
+ clks[IMX8MM_CLK_GPU3D_CG] = imx_clk_gate3("gpu3d_cg", "gpu3d_src", base + 0x8180, 28);
+ clks[IMX8MM_CLK_GPU2D_CG] = imx_clk_gate3("gpu2d_cg", "gpu2d_src", base + 0x8200, 28);
+
+ clks[IMX8MM_CLK_A53_DIV] = imx_clk_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3);
+ clks[IMX8MM_CLK_M4_DIV] = imx_clk_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3);
+ clks[IMX8MM_CLK_VPU_DIV] = imx_clk_divider2("vpu_div", "vpu_cg", base + 0x8100, 0, 3);
+ clks[IMX8MM_CLK_GPU3D_DIV] = imx_clk_divider2("gpu3d_div", "gpu3d_cg", base + 0x8180, 0, 3);
+ clks[IMX8MM_CLK_GPU2D_DIV] = imx_clk_divider2("gpu2d_div", "gpu2d_cg", base + 0x8200, 0, 3);
+
+ /* BUS */
+ clks[IMX8MM_CLK_MAIN_AXI_SRC] = imx_clk_mux2("main_axi_src", base + 0x8800, 24, 3, imx8mm_main_axi_sels, ARRAY_SIZE(imx8mm_main_axi_sels));
+ clks[IMX8MM_CLK_ENET_AXI_SRC] = imx_clk_mux2("enet_axi_src", base + 0x8880, 24, 3, imx8mm_enet_axi_sels, ARRAY_SIZE(imx8mm_enet_axi_sels));
+ clks[IMX8MM_CLK_NAND_USDHC_BUS_SRC] = imx_clk_mux2("nand_usdhc_bus_src", base + 0x8900, 24, 3, imx8mm_nand_usdhc_sels, ARRAY_SIZE(imx8mm_nand_usdhc_sels));
+ clks[IMX8MM_CLK_VPU_BUS_SRC] = imx_clk_mux2("vpu_bus_src", base + 0x8980, 24, 3, imx8mm_vpu_bus_sels, ARRAY_SIZE(imx8mm_vpu_bus_sels));
+ clks[IMX8MM_CLK_DISP_AXI_SRC] = imx_clk_mux2("disp_axi_src", base + 0x8a00, 24, 3, imx8mm_disp_axi_sels, ARRAY_SIZE(imx8mm_disp_axi_sels));
+ clks[IMX8MM_CLK_DISP_APB_SRC] = imx_clk_mux2("disp_apb_src", base + 0x8a80, 24, 3, imx8mm_disp_apb_sels, ARRAY_SIZE(imx8mm_disp_apb_sels));
+ clks[IMX8MM_CLK_DISP_RTRM_SRC] = imx_clk_mux2("disp_rtrm_src", base + 0x8b00, 24, 3, imx8mm_disp_rtrm_sels, ARRAY_SIZE(imx8mm_disp_rtrm_sels));
+ clks[IMX8MM_CLK_USB_BUS_SRC] = imx_clk_mux2("usb_bus_src", base + 0x8b80, 24, 3, imx8mm_usb_bus_sels, ARRAY_SIZE(imx8mm_usb_bus_sels));
+ clks[IMX8MM_CLK_GPU_AXI_SRC] = imx_clk_mux2("gpu_axi_src", base + 0x8c00, 24, 3, imx8mm_gpu_axi_sels, ARRAY_SIZE(imx8mm_gpu_axi_sels));
+ clks[IMX8MM_CLK_GPU_AHB_SRC] = imx_clk_mux2("gpu_ahb_src", base + 0x8c80, 24, 3, imx8mm_gpu_ahb_sels, ARRAY_SIZE(imx8mm_gpu_ahb_sels));
+ clks[IMX8MM_CLK_NOC_SRC] = imx_clk_mux2("noc_src", base + 0x8d00, 24, 3, imx8mm_noc_sels, ARRAY_SIZE(imx8mm_noc_sels));
+ clks[IMX8MM_CLK_NOC_APB_SRC] = imx_clk_mux2("noc_apb_src", base + 0x8d80, 24, 3, imx8mm_noc_apb_sels, ARRAY_SIZE(imx8mm_noc_apb_sels));
+
+ clks[IMX8MM_CLK_MAIN_AXI_CG] = imx_clk_gate3("main_axi_cg", "main_axi_src", base + 0x8800, 28);
+ clks[IMX8MM_CLK_ENET_AXI_CG] = imx_clk_gate3("enet_axi_cg", "enet_axi_src", base + 0x8880, 28);
+ clks[IMX8MM_CLK_NAND_USDHC_BUS_CG] = imx_clk_gate3("nand_usdhc_bus_cg", "nand_usdhc_bus_src", base + 0x8900, 28);
+ clks[IMX8MM_CLK_VPU_BUS_CG] = imx_clk_gate3("vpu_bus_cg", "vpu_bus_src", base + 0x8980, 28);
+ clks[IMX8MM_CLK_DISP_AXI_CG] = imx_clk_gate3("disp_axi_cg", "disp_axi_src", base + 0x8a00, 28);
+ clks[IMX8MM_CLK_DISP_APB_CG] = imx_clk_gate3("disp_apb_cg", "disp_apb_src", base + 0x8a80, 28);
+ clks[IMX8MM_CLK_DISP_RTRM_CG] = imx_clk_gate3("disp_rtrm_cg", "disp_rtrm_src", base + 0x8b00, 28);
+ clks[IMX8MM_CLK_USB_BUS_CG] = imx_clk_gate3("usb_bus_cg", "usb_bus_src", base + 0x8b80, 28);
+ clks[IMX8MM_CLK_GPU_AXI_CG] = imx_clk_gate3("gpu_axi_cg", "gpu_axi_src", base + 0x8c00, 28);
+ clks[IMX8MM_CLK_GPU_AHB_CG] = imx_clk_gate3("gpu_ahb_cg", "gpu_ahb_src", base + 0x8c80, 28);
+ clks[IMX8MM_CLK_NOC_CG] = imx_clk_gate3("noc_cg", "noc_src", base + 0x8d00, 28);
+ clks[IMX8MM_CLK_NOC_APB_CG] = imx_clk_gate3("noc_apb_cg", "noc_apb_src", base + 0x8d80, 28);
+
+ clks[IMX8MM_CLK_MAIN_AXI_PRE_DIV] = imx_clk_divider2("main_axi_pre_div", "main_axi_cg", base + 0x8800, 16, 3);
+ clks[IMX8MM_CLK_ENET_AXI_PRE_DIV] = imx_clk_divider2("enet_axi_pre_div", "enet_axi_cg", base + 0x8880, 16, 3);
+ clks[IMX8MM_CLK_NAND_USDHC_BUS_PRE_DIV] = imx_clk_divider2("nand_usdhc_bus_pre_div", "nand_usdhc_bus_cg", base + 0x8900, 16, 3);
+ clks[IMX8MM_CLK_VPU_BUS_PRE_DIV] = imx_clk_divider2("vpu_bus_pre_div", "vpu_bus_cg", base + 0x8980, 16, 3);
+ clks[IMX8MM_CLK_DISP_AXI_PRE_DIV] = imx_clk_divider2("disp_axi_pre_div", "disp_axi_cg", base + 0x8a00, 16, 3);
+ clks[IMX8MM_CLK_DISP_APB_PRE_DIV] = imx_clk_divider2("disp_apb_pre_div", "disp_apb_cg", base + 0x8a80, 16, 3);
+ clks[IMX8MM_CLK_DISP_RTRM_PRE_DIV] = imx_clk_divider2("disp_rtrm_pre_div", "disp_rtrm_cg", base + 0x8b00, 16, 3);
+ clks[IMX8MM_CLK_USB_BUS_PRE_DIV] = imx_clk_divider2("usb_bus_pre_div", "usb_bus_cg", base + 0x8b80, 16, 3);
+ clks[IMX8MM_CLK_GPU_AXI_PRE_DIV] = imx_clk_divider2("gpu_axi_pre_div", "gpu_axi_cg", base + 0x8c00, 16, 3);
+ clks[IMX8MM_CLK_GPU_AHB_PRE_DIV] = imx_clk_divider2("gpu_ahb_pre_div", "gpu_ahb_cg", base + 0x8c80, 16, 3);
+ clks[IMX8MM_CLK_NOC_PRE_DIV] = imx_clk_divider2("noc_pre_div", "noc_cg", base + 0x8d00, 16, 3);
+ clks[IMX8MM_CLK_NOC_APB_PRE_DIV] = imx_clk_divider2("noc_apb_pre_div", "noc_apb_cg", base + 0x8d80, 16, 3);
+
+ clks[IMX8MM_CLK_MAIN_AXI_DIV] = imx_clk_divider2("main_axi_div", "main_axi_pre_div", base + 0x8800, 0, 6);
+ clks[IMX8MM_CLK_ENET_AXI_DIV] = imx_clk_divider2("enet_axi_div", "enet_axi_pre_div", base + 0x8880, 0, 6);
+ clks[IMX8MM_CLK_NAND_USDHC_BUS_DIV] = imx_clk_divider2("nand_usdhc_bus_div", "nand_usdhc_bus_pre_div", base + 0x8900, 0, 6);
+ clks[IMX8MM_CLK_VPU_BUS_DIV] = imx_clk_divider2("vpu_bus_div", "vpu_bus_pre_div", base + 0x8980, 0, 6);
+ clks[IMX8MM_CLK_DISP_AXI_DIV] = imx_clk_divider2("disp_axi_div", "disp_axi_pre_div", base + 0x8a00, 0, 6);
+ clks[IMX8MM_CLK_DISP_APB_DIV] = imx_clk_divider2("disp_apb_div", "disp_apb_pre_div", base + 0x8a80, 0, 6);
+ clks[IMX8MM_CLK_DISP_RTRM_DIV] = imx_clk_divider2("disp_rtrm_div", "disp_rtrm_pre_div", base + 0x8b00, 0, 6);
+ clks[IMX8MM_CLK_USB_BUS_DIV] = imx_clk_divider2("usb_bus_div", "usb_bus_pre_div", base + 0x8b80, 0, 6);
+ clks[IMX8MM_CLK_GPU_AXI_DIV] = imx_clk_divider2("gpu_axi_div", "gpu_axi_pre_div", base + 0x8c00, 0, 6);
+ clks[IMX8MM_CLK_GPU_AHB_DIV] = imx_clk_divider2("gpu_ahb_div", "gpu_ahb_pre_div", base + 0x8c80, 0, 6);
+ clks[IMX8MM_CLK_NOC_DIV] = imx_clk_divider2("noc_div", "noc_pre_div", base + 0x8d00, 0, 6);
+ clks[IMX8MM_CLK_NOC_APB_DIV] = imx_clk_divider2("noc_apb_div", "noc_apb_pre_div", base + 0x8d80, 0, 6);
+
+ /* AHB */
+ clks[IMX8MM_CLK_AHB_SRC] = imx_clk_mux2("ahb_src", base + 0x9000, 24, 3, imx8mm_ahb_sels, ARRAY_SIZE(imx8mm_ahb_sels));
+ clks[IMX8MM_CLK_AUDIO_AHB_SRC] = imx_clk_mux2("audio_ahb_src", base + 0x9100, 24, 3, imx8mm_audio_ahb_sels, ARRAY_SIZE(imx8mm_audio_ahb_sels));
+ clks[IMX8MM_CLK_AHB_CG] = imx_clk_gate3("ahb_cg", "ahb_src", base + 0x9000, 28);
+ clks[IMX8MM_CLK_AUDIO_AHB_CG] = imx_clk_gate3("audio_ahb_cg", "audio_ahb_src", base + 0x9100, 28);
+ clks[IMX8MM_CLK_AHB_PRE_DIV] = imx_clk_divider2("ahb_pre_div", "ahb_cg", base + 0x9000, 16, 3);
+ clks[IMX8MM_CLK_AUDIO_AHB_PRE_DIV] = imx_clk_divider2("audio_ahb_pre_div", "audio_ahb_cg", base + 0x9100, 16, 3);
+ clks[IMX8MM_CLK_AHB_DIV] = imx_clk_divider_flags("ahb_div", "ahb_pre_div", base + 0x9000, 0, 6, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+ clks[IMX8MM_CLK_AUDIO_AHB_DIV] = imx_clk_divider2("audio_ahb_div", "audio_ahb_pre_div", base + 0x9100, 0, 6);
+
+ /* IPG */
+ clks[IMX8MM_CLK_IPG_ROOT] = imx_clk_divider2("ipg_root", "ahb_div", base + 0x9080, 0, 1);
+ clks[IMX8MM_CLK_IPG_AUDIO_ROOT] = imx_clk_divider2("ipg_audio_root", "audio_ahb_div", base + 0x9180, 0, 1);
+
+ /* IP */
+ clks[IMX8MM_CLK_DRAM_ALT_SRC] = imx_clk_mux2("dram_alt_src", base + 0xa000, 24, 3, imx8mm_dram_alt_sels, ARRAY_SIZE(imx8mm_dram_alt_sels));
+ clks[IMX8MM_CLK_DRAM_APB_SRC] = imx_clk_mux2("dram_apb_src", base + 0xa080, 24, 3, imx8mm_dram_apb_sels, ARRAY_SIZE(imx8mm_dram_apb_sels));
+ clks[IMX8MM_CLK_VPU_G1_SRC] = imx_clk_mux2("vpu_g1_src", base + 0xa100, 24, 3, imx8mm_vpu_g1_sels, ARRAY_SIZE(imx8mm_vpu_g1_sels));
+ clks[IMX8MM_CLK_VPU_G2_SRC] = imx_clk_mux2("vpu_g2_src", base + 0xa180, 24, 3, imx8mm_vpu_g2_sels, ARRAY_SIZE(imx8mm_vpu_g2_sels));
+ clks[IMX8MM_CLK_DISP_DTRC_SRC] = imx_clk_mux2("disp_dtrc_src", base + 0xa200, 24, 3, imx8mm_disp_dtrc_sels, ARRAY_SIZE(imx8mm_disp_dtrc_sels));
+ clks[IMX8MM_CLK_DISP_DC8000_SRC] = imx_clk_mux2("disp_dc8000_src", base + 0xa280, 24, 3, imx8mm_disp_dc8000_sels, ARRAY_SIZE(imx8mm_disp_dc8000_sels));
+ clks[IMX8MM_CLK_PCIE1_CTRL_SRC] = imx_clk_mux2("pcie1_ctrl_src", base + 0xa300, 24, 3, imx8mm_pcie1_ctrl_sels, ARRAY_SIZE(imx8mm_pcie1_ctrl_sels));
+ clks[IMX8MM_CLK_PCIE1_PHY_SRC] = imx_clk_mux2("pcie1_phy_src", base + 0xa380, 24, 3, imx8mm_pcie1_phy_sels, ARRAY_SIZE(imx8mm_pcie1_phy_sels));
+ clks[IMX8MM_CLK_PCIE1_AUX_SRC] = imx_clk_mux2("pcie1_aux_src", base + 0xa400, 24, 3, imx8mm_pcie1_aux_sels, ARRAY_SIZE(imx8mm_pcie1_aux_sels));
+ clks[IMX8MM_CLK_DC_PIXEL_SRC] = imx_clk_mux2("dc_pixel_src", base + 0xa480, 24, 3, imx8mm_dc_pixel_sels, ARRAY_SIZE(imx8mm_dc_pixel_sels));
+ clks[IMX8MM_CLK_LCDIF_PIXEL_SRC] = imx_clk_mux2("lcdif_pixel_src", base + 0xa500, 24, 3, imx8mm_lcdif_pixel_sels, ARRAY_SIZE(imx8mm_lcdif_pixel_sels));
+ clks[IMX8MM_CLK_SAI1_SRC] = imx_clk_mux2("sai1_src", base + 0xa580, 24, 3, imx8mm_sai1_sels, ARRAY_SIZE(imx8mm_sai1_sels));
+ clks[IMX8MM_CLK_SAI2_SRC] = imx_clk_mux2("sai2_src", base + 0xa600, 24, 3, imx8mm_sai2_sels, ARRAY_SIZE(imx8mm_sai2_sels));
+ clks[IMX8MM_CLK_SAI3_SRC] = imx_clk_mux2("sai3_src", base + 0xa680, 24, 3, imx8mm_sai3_sels, ARRAY_SIZE(imx8mm_sai3_sels));
+ clks[IMX8MM_CLK_SAI4_SRC] = imx_clk_mux2("sai4_src", base + 0xa700, 24, 3, imx8mm_sai4_sels, ARRAY_SIZE(imx8mm_sai4_sels));
+ clks[IMX8MM_CLK_SAI5_SRC] = imx_clk_mux2("sai5_src", base + 0xa780, 24, 3, imx8mm_sai5_sels, ARRAY_SIZE(imx8mm_sai5_sels));
+ clks[IMX8MM_CLK_SAI6_SRC] = imx_clk_mux2("sai6_src", base + 0xa800, 24, 3, imx8mm_sai6_sels, ARRAY_SIZE(imx8mm_sai6_sels));
+ clks[IMX8MM_CLK_SPDIF1_SRC] = imx_clk_mux2("spdif1_src", base + 0xa880, 24, 3, imx8mm_spdif1_sels, ARRAY_SIZE(imx8mm_spdif1_sels));
+ clks[IMX8MM_CLK_SPDIF2_SRC] = imx_clk_mux2("spdif2_src", base + 0xa900, 24, 3, imx8mm_spdif2_sels, ARRAY_SIZE(imx8mm_spdif2_sels));
+ clks[IMX8MM_CLK_ENET_REF_SRC] = imx_clk_mux2("enet_ref_src", base + 0xa980, 24, 3, imx8mm_enet_ref_sels, ARRAY_SIZE(imx8mm_enet_ref_sels));
+ clks[IMX8MM_CLK_ENET_TIMER_SRC] = imx_clk_mux2("enet_timer_src", base + 0xaa00, 24, 3, imx8mm_enet_timer_sels, ARRAY_SIZE(imx8mm_enet_timer_sels));
+ clks[IMX8MM_CLK_ENET_PHY_REF_SRC] = imx_clk_mux2("enet_phy_src", base + 0xaa80, 24, 3, imx8mm_enet_phy_sels, ARRAY_SIZE(imx8mm_enet_phy_sels));
+ clks[IMX8MM_CLK_NAND_SRC] = imx_clk_mux2("nand_src", base + 0xab00, 24, 3, imx8mm_nand_sels, ARRAY_SIZE(imx8mm_nand_sels));
+ clks[IMX8MM_CLK_QSPI_SRC] = imx_clk_mux2("qspi_src", base + 0xab80, 24, 3, imx8mm_qspi_sels, ARRAY_SIZE(imx8mm_qspi_sels));
+ clks[IMX8MM_CLK_USDHC1_SRC] = imx_clk_mux2("usdhc1_src", base + 0xac00, 24, 3, imx8mm_usdhc1_sels, ARRAY_SIZE(imx8mm_usdhc1_sels));
+ clks[IMX8MM_CLK_USDHC2_SRC] = imx_clk_mux2("usdhc2_src", base + 0xac80, 24, 3, imx8mm_usdhc2_sels, ARRAY_SIZE(imx8mm_usdhc2_sels));
+ clks[IMX8MM_CLK_I2C1_SRC] = imx_clk_mux2("i2c1_src", base + 0xad00, 24, 3, imx8mm_i2c1_sels, ARRAY_SIZE(imx8mm_i2c1_sels));
+ clks[IMX8MM_CLK_I2C2_SRC] = imx_clk_mux2("i2c2_src", base + 0xad80, 24, 3, imx8mm_i2c2_sels, ARRAY_SIZE(imx8mm_i2c2_sels));
+ clks[IMX8MM_CLK_I2C3_SRC] = imx_clk_mux2("i2c3_src", base + 0xae00, 24, 3, imx8mm_i2c3_sels, ARRAY_SIZE(imx8mm_i2c3_sels));
+ clks[IMX8MM_CLK_I2C4_SRC] = imx_clk_mux2("i2c4_src", base + 0xae80, 24, 3, imx8mm_i2c4_sels, ARRAY_SIZE(imx8mm_i2c4_sels));
+ clks[IMX8MM_CLK_UART1_SRC] = imx_clk_mux2("uart1_src", base + 0xaf00, 24, 3, imx8mm_uart1_sels, ARRAY_SIZE(imx8mm_uart1_sels));
+ clks[IMX8MM_CLK_UART2_SRC] = imx_clk_mux2("uart2_src", base + 0xaf80, 24, 3, imx8mm_uart2_sels, ARRAY_SIZE(imx8mm_uart2_sels));
+ clks[IMX8MM_CLK_UART3_SRC] = imx_clk_mux2("uart3_src", base + 0xb000, 24, 3, imx8mm_uart3_sels, ARRAY_SIZE(imx8mm_uart3_sels));
+ clks[IMX8MM_CLK_UART4_SRC] = imx_clk_mux2("uart4_src", base + 0xb080, 24, 3, imx8mm_uart4_sels, ARRAY_SIZE(imx8mm_uart4_sels));
+ clks[IMX8MM_CLK_USB_CORE_REF_SRC] = imx_clk_mux2("usb_core_ref_src", base + 0xb100, 24, 3, imx8mm_usb_core_sels, ARRAY_SIZE(imx8mm_usb_core_sels));
+ clks[IMX8MM_CLK_USB_PHY_REF_SRC] = imx_clk_mux2("usb_phy_ref_src", base + 0xb180, 24, 3, imx8mm_usb_phy_sels, ARRAY_SIZE(imx8mm_usb_phy_sels));
+ clks[IMX8MM_CLK_ECSPI1_SRC] = imx_clk_mux2("ecspi1_src", base + 0xb280, 24, 3, imx8mm_ecspi1_sels, ARRAY_SIZE(imx8mm_ecspi1_sels));
+ clks[IMX8MM_CLK_ECSPI2_SRC] = imx_clk_mux2("ecspi2_src", base + 0xb300, 24, 3, imx8mm_ecspi2_sels, ARRAY_SIZE(imx8mm_ecspi2_sels));
+ clks[IMX8MM_CLK_PWM1_SRC] = imx_clk_mux2("pwm1_src", base + 0xb380, 24, 3, imx8mm_pwm1_sels, ARRAY_SIZE(imx8mm_pwm1_sels));
+ clks[IMX8MM_CLK_PWM2_SRC] = imx_clk_mux2("pwm2_src", base + 0xb400, 24, 3, imx8mm_pwm2_sels, ARRAY_SIZE(imx8mm_pwm2_sels));
+ clks[IMX8MM_CLK_PWM3_SRC] = imx_clk_mux2("pwm3_src", base + 0xb480, 24, 3, imx8mm_pwm3_sels, ARRAY_SIZE(imx8mm_pwm3_sels));
+ clks[IMX8MM_CLK_PWM4_SRC] = imx_clk_mux2("pwm4_src", base + 0xb500, 24, 3, imx8mm_pwm4_sels, ARRAY_SIZE(imx8mm_pwm4_sels));
+ clks[IMX8MM_CLK_GPT1_SRC] = imx_clk_mux2("gpt1_src", base + 0xb580, 24, 3, imx8mm_gpt1_sels, ARRAY_SIZE(imx8mm_gpt1_sels));
+ clks[IMX8MM_CLK_WDOG_SRC] = imx_clk_mux2("wdog_src", base + 0xb900, 24, 3, imx8mm_wdog_sels, ARRAY_SIZE(imx8mm_wdog_sels));
+ clks[IMX8MM_CLK_WRCLK_SRC] = imx_clk_mux2("wrclk_src", base + 0xb980, 24, 3, imx8mm_wrclk_sels, ARRAY_SIZE(imx8mm_wrclk_sels));
+ clks[IMX8MM_CLK_CLKO1_SRC] = imx_clk_mux2("clko1_src", base + 0xba00, 24, 3, imx8mm_clko1_sels, ARRAY_SIZE(imx8mm_clko1_sels));
+ clks[IMX8MM_CLK_DSI_CORE_SRC] = imx_clk_mux2("dsi_core_src", base + 0xbb00, 24, 3, imx8mm_dsi_core_sels, ARRAY_SIZE(imx8mm_dsi_core_sels));
+ clks[IMX8MM_CLK_DSI_PHY_REF_SRC] = imx_clk_mux2("dsi_phy_ref_src", base + 0xbb80, 24, 3, imx8mm_dsi_phy_sels, ARRAY_SIZE(imx8mm_dsi_phy_sels));
+ clks[IMX8MM_CLK_DSI_DBI_SRC] = imx_clk_mux2("dsi_dbi_src", base + 0xbc00, 24, 3, imx8mm_dsi_dbi_sels, ARRAY_SIZE(imx8mm_dsi_dbi_sels));
+ clks[IMX8MM_CLK_USDHC3_SRC] = imx_clk_mux2("usdhc3_src", base + 0xbc80, 24, 3, imx8mm_usdhc3_sels, ARRAY_SIZE(imx8mm_usdhc3_sels));
+ clks[IMX8MM_CLK_CSI1_CORE_SRC] = imx_clk_mux2("csi1_core_src", base + 0xbd00, 24, 3, imx8mm_csi1_core_sels, ARRAY_SIZE(imx8mm_csi1_core_sels));
+ clks[IMX8MM_CLK_CSI1_PHY_REF_SRC] = imx_clk_mux2("csi1_phy_ref_src", base + 0xbd80, 24, 3, imx8mm_csi1_phy_sels, ARRAY_SIZE(imx8mm_csi1_phy_sels));
+ clks[IMX8MM_CLK_CSI1_ESC_SRC] = imx_clk_mux2("csi1_esc_src", base + 0xbe00, 24, 3, imx8mm_csi1_esc_sels, ARRAY_SIZE(imx8mm_csi1_esc_sels));
+ clks[IMX8MM_CLK_CSI2_CORE_SRC] = imx_clk_mux2("csi2_core_src", base + 0xbe80, 24, 3, imx8mm_csi2_core_sels, ARRAY_SIZE(imx8mm_csi2_core_sels));
+ clks[IMX8MM_CLK_CSI2_PHY_REF_SRC] = imx_clk_mux2("csi2_phy_ref_src", base + 0xbf00, 24, 3, imx8mm_csi2_phy_sels, ARRAY_SIZE(imx8mm_csi2_phy_sels));
+ clks[IMX8MM_CLK_CSI2_ESC_SRC] = imx_clk_mux2("csi2_esc_src", base + 0xbf80, 24, 3, imx8mm_csi2_esc_sels, ARRAY_SIZE(imx8mm_csi2_esc_sels));
+ clks[IMX8MM_CLK_PCIE2_CTRL_SRC] = imx_clk_mux2("pcie2_ctrl_src", base + 0xc000, 24, 3, imx8mm_pcie2_ctrl_sels, ARRAY_SIZE(imx8mm_pcie2_ctrl_sels));
+ clks[IMX8MM_CLK_PCIE2_PHY_SRC] = imx_clk_mux2("pcie2_phy_src", base + 0xc080, 24, 3, imx8mm_pcie2_phy_sels, ARRAY_SIZE(imx8mm_pcie2_phy_sels));
+ clks[IMX8MM_CLK_PCIE2_AUX_SRC] = imx_clk_mux2("pcie2_aux_src", base + 0xc100, 24, 3, imx8mm_pcie2_aux_sels, ARRAY_SIZE(imx8mm_pcie2_aux_sels));
+ clks[IMX8MM_CLK_ECSPI3_SRC] = imx_clk_mux2("ecspi3_src", base + 0xc180, 24, 3, imx8mm_ecspi3_sels, ARRAY_SIZE(imx8mm_ecspi3_sels));
+ clks[IMX8MM_CLK_PDM_SRC] = imx_clk_mux2("pdm_src", base + 0xc200, 24, 3, imx8mm_pdm_sels, ARRAY_SIZE(imx8mm_pdm_sels));
+ clks[IMX8MM_CLK_VPU_H1_SRC] = imx_clk_mux2("vpu_h1_src", base + 0xc280, 24, 3, imx8mm_vpu_h1_sels, ARRAY_SIZE(imx8mm_vpu_h1_sels));
+
+ clks[IMX8MM_CLK_DRAM_ALT_CG] = imx_clk_gate3("dram_alt_cg", "dram_alt_src", base + 0xa000, 28);
+ clks[IMX8MM_CLK_DRAM_APB_CG] = imx_clk_gate3("dram_apb_cg", "dram_apb_src", base + 0xa080, 28);
+ clks[IMX8MM_CLK_VPU_G1_CG] = imx_clk_gate3("vpu_g1_cg", "vpu_g1_src", base + 0xa100, 28);
+ clks[IMX8MM_CLK_VPU_G2_CG] = imx_clk_gate3("vpu_g2_cg", "vpu_g2_src", base + 0xa180, 28);
+ clks[IMX8MM_CLK_DISP_DTRC_CG] = imx_clk_gate3("disp_dtrc_cg", "disp_dtrc_src", base + 0xa200, 28);
+ clks[IMX8MM_CLK_DISP_DC8000_CG] = imx_clk_gate3("disp_dc8000_cg", "disp_dc8000_src", base + 0xa280, 28);
+ clks[IMX8MM_CLK_PCIE1_CTRL_CG] = imx_clk_gate3("pcie1_ctrl_cg", "pcie1_ctrl_src", base + 0xa300, 28);
+ clks[IMX8MM_CLK_PCIE1_PHY_CG] = imx_clk_gate3("pcie1_phy_cg", "pcie1_phy_src", base + 0xa380, 28);
+ clks[IMX8MM_CLK_PCIE1_AUX_CG] = imx_clk_gate3("pcie1_aux_cg", "pcie1_aux_src", base + 0xa400, 28);
+ clks[IMX8MM_CLK_DC_PIXEL_CG] = imx_clk_gate3("dc_pixel_cg", "dc_pixel_src", base + 0xa480, 28);
+ clks[IMX8MM_CLK_LCDIF_PIXEL_CG] = imx_clk_gate3("lcdif_pixel_cg", "lcdif_pixel_src", base + 0xa500, 28);
+ clks[IMX8MM_CLK_SAI1_CG] = imx_clk_gate3("sai1_cg", "sai1_src", base + 0xa580, 28);
+ clks[IMX8MM_CLK_SAI2_CG] = imx_clk_gate3("sai2_cg", "sai2_src", base + 0xa600, 28);
+ clks[IMX8MM_CLK_SAI3_CG] = imx_clk_gate3("sai3_cg", "sai3_src", base + 0xa680, 28);
+ clks[IMX8MM_CLK_SAI4_CG] = imx_clk_gate3("sai4_cg", "sai4_src", base + 0xa700, 28);
+ clks[IMX8MM_CLK_SAI5_CG] = imx_clk_gate3("sai5_cg", "sai5_src", base + 0xa780, 28);
+ clks[IMX8MM_CLK_SAI6_CG] = imx_clk_gate3("sai6_cg", "sai6_src", base + 0xa800, 28);
+ clks[IMX8MM_CLK_SPDIF1_CG] = imx_clk_gate3("spdif1_cg", "spdif1_src", base + 0xa880, 28);
+ clks[IMX8MM_CLK_SPDIF2_CG] = imx_clk_gate3("spdif2_cg", "spdif2_src", base + 0xa900, 28);
+ clks[IMX8MM_CLK_ENET_REF_CG] = imx_clk_gate3("enet_ref_cg", "enet_ref_src", base + 0xa980, 28);
+ clks[IMX8MM_CLK_ENET_TIMER_CG] = imx_clk_gate3("enet_timer_cg", "enet_timer_src", base + 0xaa00, 28);
+ clks[IMX8MM_CLK_ENET_PHY_REF_CG] = imx_clk_gate3("enet_phy_cg", "enet_phy_src", base + 0xaa80, 28);
+ clks[IMX8MM_CLK_NAND_CG] = imx_clk_gate3("nand_cg", "nand_src", base + 0xab00, 28);
+ clks[IMX8MM_CLK_QSPI_CG] = imx_clk_gate3("qspi_cg", "qspi_src", base + 0xab80, 28);
+ clks[IMX8MM_CLK_USDHC1_CG] = imx_clk_gate3("usdhc1_cg", "usdhc1_src", base + 0xac00, 28);
+ clks[IMX8MM_CLK_USDHC2_CG] = imx_clk_gate3("usdhc2_cg", "usdhc2_src", base + 0xac80, 28);
+ clks[IMX8MM_CLK_I2C1_CG] = imx_clk_gate3("i2c1_cg", "i2c1_src", base + 0xad00, 28);
+ clks[IMX8MM_CLK_I2C2_CG] = imx_clk_gate3("i2c2_cg", "i2c2_src", base + 0xad80, 28);
+ clks[IMX8MM_CLK_I2C3_CG] = imx_clk_gate3("i2c3_cg", "i2c3_src", base + 0xae00, 28);
+ clks[IMX8MM_CLK_I2C4_CG] = imx_clk_gate3("i2c4_cg", "i2c4_src", base + 0xae80, 28);
+ clks[IMX8MM_CLK_UART1_CG] = imx_clk_gate3("uart1_cg", "uart1_src", base + 0xaf00, 28);
+ clks[IMX8MM_CLK_UART2_CG] = imx_clk_gate3("uart2_cg", "uart2_src", base + 0xaf80, 28);
+ clks[IMX8MM_CLK_UART3_CG] = imx_clk_gate3("uart3_cg", "uart3_src", base + 0xb000, 28);
+ clks[IMX8MM_CLK_UART4_CG] = imx_clk_gate3("uart4_cg", "uart4_src", base + 0xb080, 28);
+ clks[IMX8MM_CLK_USB_CORE_REF_CG] = imx_clk_gate3("usb_core_ref_cg", "usb_core_ref_src", base + 0xb100, 28);
+ clks[IMX8MM_CLK_USB_PHY_REF_CG] = imx_clk_gate3("usb_phy_ref_cg", "usb_phy_ref_src", base + 0xb180, 28);
+ clks[IMX8MM_CLK_ECSPI1_CG] = imx_clk_gate3("ecspi1_cg", "ecspi1_src", base + 0xb280, 28);
+ clks[IMX8MM_CLK_ECSPI2_CG] = imx_clk_gate3("ecspi2_cg", "ecspi2_src", base + 0xb300, 28);
+ clks[IMX8MM_CLK_PWM1_CG] = imx_clk_gate3("pwm1_cg", "pwm1_src", base + 0xb380, 28);
+ clks[IMX8MM_CLK_PWM2_CG] = imx_clk_gate3("pwm2_cg", "pwm2_src", base + 0xb400, 28);
+ clks[IMX8MM_CLK_PWM3_CG] = imx_clk_gate3("pwm3_cg", "pwm3_src", base + 0xb480, 28);
+ clks[IMX8MM_CLK_PWM4_CG] = imx_clk_gate3("pwm4_cg", "pwm4_src", base + 0xb500, 28);
+ clks[IMX8MM_CLK_GPT1_CG] = imx_clk_gate3("gpt1_cg", "gpt1_src", base + 0xb580, 28);
+ clks[IMX8MM_CLK_WDOG_CG] = imx_clk_gate3("wdog_cg", "wdog_src", base + 0xb900, 28);
+ clks[IMX8MM_CLK_WRCLK_CG] = imx_clk_gate3("wrclk_cg", "wrclk_src", base + 0xb980, 28);
+ clks[IMX8MM_CLK_CLKO1_CG] = imx_clk_gate3("clko1_cg", "clko1_src", base + 0xba00, 28);
+ clks[IMX8MM_CLK_DSI_CORE_CG] = imx_clk_gate3("dsi_core_cg", "dsi_core_src", base + 0xbb00, 28);
+ clks[IMX8MM_CLK_DSI_PHY_REF_CG] = imx_clk_gate3("dsi_phy_ref_cg", "dsi_phy_ref_src", base + 0xbb80, 28);
+ clks[IMX8MM_CLK_DSI_DBI_CG] = imx_clk_gate3("dsi_dbi_cg", "dsi_dbi_src", base + 0xbc00, 28);
+ clks[IMX8MM_CLK_USDHC3_CG] = imx_clk_gate3("usdhc3_cg", "usdhc3_src", base + 0xbc80, 28);
+ clks[IMX8MM_CLK_CSI1_CORE_CG] = imx_clk_gate3("csi1_core_cg", "csi1_core_src", base + 0xbd00, 28);
+ clks[IMX8MM_CLK_CSI1_PHY_REF_CG] = imx_clk_gate3("csi1_phy_ref_cg", "csi1_phy_ref_src", base + 0xbd80, 28);
+ clks[IMX8MM_CLK_CSI1_ESC_CG] = imx_clk_gate3("csi1_esc_cg", "csi1_esc_src", base + 0xbe00, 28);
+ clks[IMX8MM_CLK_CSI2_CORE_CG] = imx_clk_gate3("csi2_core_cg", "csi2_core_src", base + 0xbe80, 28);
+ clks[IMX8MM_CLK_CSI2_PHY_REF_CG] = imx_clk_gate3("csi2_phy_ref_cg", "csi2_phy_ref_src", base + 0xbf00, 28);
+ clks[IMX8MM_CLK_CSI2_ESC_CG] = imx_clk_gate3("csi2_esc_cg", "csi2_esc_src", base + 0xbf80, 28);
+ clks[IMX8MM_CLK_PCIE2_CTRL_CG] = imx_clk_gate3("pcie2_ctrl_cg", "pcie2_ctrl_src", base + 0xc000, 28);
+ clks[IMX8MM_CLK_PCIE2_PHY_CG] = imx_clk_gate3("pcie2_phy_cg", "pcie2_phy_src", base + 0xc080, 28);
+ clks[IMX8MM_CLK_PCIE2_AUX_CG] = imx_clk_gate3("pcie2_aux_cg", "pcie2_aux_src", base + 0xc100, 28);
+ clks[IMX8MM_CLK_ECSPI3_CG] = imx_clk_gate3("ecspi3_cg", "ecspi3_src", base + 0xc180, 28);
+ clks[IMX8MM_CLK_PDM_CG] = imx_clk_gate3("pdm_cg", "pdm_src", base + 0xc200, 28);
+ clks[IMX8MM_CLK_VPU_H1_CG] = imx_clk_gate3("vpu_h1_cg", "vpu_h1_src", base + 0xc280, 28);
+
+ clks[IMX8MM_CLK_DRAM_ALT_PRE_DIV] = imx_clk_divider2("dram_alt_pre_div", "dram_alt_cg", base + 0xa000, 16, 3);
+ clks[IMX8MM_CLK_DRAM_APB_PRE_DIV] = imx_clk_divider2("dram_apb_pre_div", "dram_apb_cg", base + 0xa080, 16, 3);
+ clks[IMX8MM_CLK_VPU_G1_PRE_DIV] = imx_clk_divider2("vpu_g1_pre_div", "vpu_g1_cg", base + 0xa100, 16, 3);
+ clks[IMX8MM_CLK_VPU_G2_PRE_DIV] = imx_clk_divider2("vpu_g2_pre_div", "vpu_g2_cg", base + 0xa180, 16, 3);
+ clks[IMX8MM_CLK_DISP_DTRC_PRE_DIV] = imx_clk_divider2("disp_dtrc_pre_div", "disp_dtrc_cg", base + 0xa200, 16, 3);
+ clks[IMX8MM_CLK_DISP_DC8000_PRE_DIV] = imx_clk_divider2("disp_dc8000_pre_div", "disp_dc8000_cg", base + 0xa280, 16, 3);
+ clks[IMX8MM_CLK_PCIE1_CTRL_PRE_DIV] = imx_clk_divider2("pcie1_ctrl_pre_div", "pcie1_ctrl_cg", base + 0xa300, 16, 3);
+ clks[IMX8MM_CLK_PCIE1_PHY_PRE_DIV] = imx_clk_divider2("pcie1_phy_pre_div", "pcie1_phy_cg", base + 0xa380, 16, 3);
+ clks[IMX8MM_CLK_PCIE1_AUX_PRE_DIV] = imx_clk_divider2("pcie1_aux_pre_div", "pcie1_aux_cg", base + 0xa400, 16, 3);
+ clks[IMX8MM_CLK_DC_PIXEL_PRE_DIV] = imx_clk_divider2("dc_pixel_pre_div", "dc_pixel_cg", base + 0xa480, 16, 3);
+ clks[IMX8MM_CLK_LCDIF_PIXEL_PRE_DIV] = imx_clk_divider2("lcdif_pixel_pre_div", "lcdif_pixel_cg", base + 0xa500, 16, 3);
+ clks[IMX8MM_CLK_SAI1_PRE_DIV] = imx_clk_divider2("sai1_pre_div", "sai1_cg", base + 0xa580, 16, 3);
+ clks[IMX8MM_CLK_SAI2_PRE_DIV] = imx_clk_divider2("sai2_pre_div", "sai2_cg", base + 0xa600, 16, 3);
+ clks[IMX8MM_CLK_SAI3_PRE_DIV] = imx_clk_divider2("sai3_pre_div", "sai3_cg", base + 0xa680, 16, 3);
+ clks[IMX8MM_CLK_SAI4_PRE_DIV] = imx_clk_divider2("sai4_pre_div", "sai4_cg", base + 0xa700, 16, 3);
+ clks[IMX8MM_CLK_SAI5_PRE_DIV] = imx_clk_divider2("sai5_pre_div", "sai5_cg", base + 0xa780, 16, 3);
+ clks[IMX8MM_CLK_SAI6_PRE_DIV] = imx_clk_divider2("sai6_pre_div", "sai6_cg", base + 0xa800, 16, 3);
+ clks[IMX8MM_CLK_SPDIF1_PRE_DIV] = imx_clk_divider2("spdif1_pre_div", "spdif1_cg", base + 0xa880, 16, 3);
+ clks[IMX8MM_CLK_SPDIF2_PRE_DIV] = imx_clk_divider2("spdif2_pre_div", "spdif2_cg", base + 0xa900, 16, 3);
+ clks[IMX8MM_CLK_ENET_REF_PRE_DIV] = imx_clk_divider2("enet_ref_pre_div", "enet_ref_cg", base + 0xa980, 16, 3);
+ clks[IMX8MM_CLK_ENET_TIMER_PRE_DIV] = imx_clk_divider2("enet_timer_pre_div", "enet_timer_cg", base + 0xaa00, 16, 3);
+ clks[IMX8MM_CLK_ENET_PHY_REF_PRE_DIV] = imx_clk_divider2("enet_phy_pre_div", "enet_phy_cg", base + 0xaa80, 16, 3);
+ clks[IMX8MM_CLK_NAND_PRE_DIV] = imx_clk_divider2("nand_pre_div", "nand_cg", base + 0xab00, 16, 3);
+ clks[IMX8MM_CLK_QSPI_PRE_DIV] = imx_clk_divider2("qspi_pre_div", "qspi_cg", base + 0xab80, 16, 3);
+ clks[IMX8MM_CLK_USDHC1_PRE_DIV] = imx_clk_divider2("usdhc1_pre_div", "usdhc1_cg", base + 0xac00, 16, 3);
+ clks[IMX8MM_CLK_USDHC2_PRE_DIV] = imx_clk_divider2("usdhc2_pre_div", "usdhc2_cg", base + 0xac80, 16, 3);
+ clks[IMX8MM_CLK_I2C1_PRE_DIV] = imx_clk_divider2("i2c1_pre_div", "i2c1_cg", base + 0xad00, 16, 3);
+ clks[IMX8MM_CLK_I2C2_PRE_DIV] = imx_clk_divider2("i2c2_pre_div", "i2c2_cg", base + 0xad80, 16, 3);
+ clks[IMX8MM_CLK_I2C3_PRE_DIV] = imx_clk_divider2("i2c3_pre_div", "i2c3_cg", base + 0xae00, 16, 3);
+ clks[IMX8MM_CLK_I2C4_PRE_DIV] = imx_clk_divider2("i2c4_pre_div", "i2c4_cg", base + 0xae80, 16, 3);
+ clks[IMX8MM_CLK_UART1_PRE_DIV] = imx_clk_divider2("uart1_pre_div", "uart1_cg", base + 0xaf00, 16, 3);
+ clks[IMX8MM_CLK_UART2_PRE_DIV] = imx_clk_divider2("uart2_pre_div", "uart2_cg", base + 0xaf80, 16, 3);
+ clks[IMX8MM_CLK_UART3_PRE_DIV] = imx_clk_divider2("uart3_pre_div", "uart3_cg", base + 0xb000, 16, 3);
+ clks[IMX8MM_CLK_UART4_PRE_DIV] = imx_clk_divider2("uart4_pre_div", "uart4_cg", base + 0xb080, 16, 3);
+ clks[IMX8MM_CLK_USB_CORE_REF_PRE_DIV] = imx_clk_divider2("usb_core_ref_pre_div", "usb_core_ref_cg", base + 0xb100, 16, 3);
+ clks[IMX8MM_CLK_USB_PHY_REF_PRE_DIV] = imx_clk_divider2("usb_phy_ref_pre_div", "usb_phy_ref_cg", base + 0xb180, 16, 3);
+ clks[IMX8MM_CLK_ECSPI1_PRE_DIV] = imx_clk_divider2("ecspi1_pre_div", "ecspi1_cg", base + 0xb280, 16, 3);
+ clks[IMX8MM_CLK_ECSPI2_PRE_DIV] = imx_clk_divider2("ecspi2_pre_div", "ecspi2_cg", base + 0xb300, 16, 3);
+ clks[IMX8MM_CLK_PWM1_PRE_DIV] = imx_clk_divider2("pwm1_pre_div", "pwm1_cg", base + 0xb380, 16, 3);
+ clks[IMX8MM_CLK_PWM2_PRE_DIV] = imx_clk_divider2("pwm2_pre_div", "pwm2_cg", base + 0xb400, 16, 3);
+ clks[IMX8MM_CLK_PWM3_PRE_DIV] = imx_clk_divider2("pwm3_pre_div", "pwm3_cg", base + 0xb480, 16, 3);
+ clks[IMX8MM_CLK_PWM4_PRE_DIV] = imx_clk_divider2("pwm4_pre_div", "pwm4_cg", base + 0xb500, 16, 3);
+ clks[IMX8MM_CLK_GPT1_PRE_DIV] = imx_clk_divider2("gpt1_pre_div", "gpt1_cg", base + 0xb580, 16, 3);
+ clks[IMX8MM_CLK_WDOG_PRE_DIV] = imx_clk_divider2("wdog_pre_div", "wdog_cg", base + 0xb900, 16, 3);
+ clks[IMX8MM_CLK_WRCLK_PRE_DIV] = imx_clk_divider2("wrclk_pre_div", "wrclk_cg", base + 0xb980, 16, 3);
+ clks[IMX8MM_CLK_CLKO1_PRE_DIV] = imx_clk_divider2("clko1_pre_div", "clko1_cg", base + 0xba00, 16, 3);
+ clks[IMX8MM_CLK_DSI_CORE_PRE_DIV] = imx_clk_divider2("dsi_core_pre_div", "dsi_core_cg", base + 0xbb00, 16, 3);
+ clks[IMX8MM_CLK_DSI_PHY_REF_PRE_DIV] = imx_clk_divider2("dsi_phy_ref_pre_div", "dsi_phy_ref_cg", base + 0xbb80, 16, 3);
+ clks[IMX8MM_CLK_DSI_DBI_PRE_DIV] = imx_clk_divider2("dsi_dbi_pre_div", "dsi_dbi_cg", base + 0xbc00, 16, 3);
+ clks[IMX8MM_CLK_USDHC3_PRE_DIV] = imx_clk_divider2("usdhc3_pre_div", "usdhc3_cg", base + 0xbc80, 16, 3);
+ clks[IMX8MM_CLK_CSI1_CORE_PRE_DIV] = imx_clk_divider2("csi1_core_pre_div", "csi1_core_cg", base + 0xbd00, 16, 3);
+ clks[IMX8MM_CLK_CSI1_PHY_REF_PRE_DIV] = imx_clk_divider2("csi1_phy_ref_pre_div", "csi1_phy_ref_cg", base + 0xbd80, 16, 3);
+ clks[IMX8MM_CLK_CSI1_ESC_PRE_DIV] = imx_clk_divider2("csi1_esc_pre_div", "csi1_esc_cg", base + 0xbe00, 16, 3);
+ clks[IMX8MM_CLK_CSI2_CORE_PRE_DIV] = imx_clk_divider2("csi2_core_pre_div", "csi2_core_cg", base + 0xbe80, 16, 3);
+ clks[IMX8MM_CLK_CSI2_PHY_REF_PRE_DIV] = imx_clk_divider2("csi2_phy_ref_pre_div", "csi2_phy_ref_cg", base + 0xbf00, 16, 3);
+ clks[IMX8MM_CLK_CSI2_ESC_PRE_DIV] = imx_clk_divider2("csi2_esc_pre_div", "csi2_esc_cg", base + 0xbf80, 16, 3);
+ clks[IMX8MM_CLK_PCIE2_CTRL_PRE_DIV] = imx_clk_divider2("pcie2_ctrl_pre_div", "pcie2_ctrl_cg", base + 0xc000, 16, 3);
+ clks[IMX8MM_CLK_PCIE2_PHY_PRE_DIV] = imx_clk_divider2("pcie2_phy_pre_div", "pcie2_phy_cg", base + 0xc080, 16, 3);
+ clks[IMX8MM_CLK_PCIE2_AUX_PRE_DIV] = imx_clk_divider2("pcie2_aux_pre_div", "pcie2_aux_cg", base + 0xc100, 16, 3);
+ clks[IMX8MM_CLK_ECSPI3_PRE_DIV] = imx_clk_divider2("ecspi3_pre_div", "ecspi3_cg", base + 0xc180, 16, 3);
+ clks[IMX8MM_CLK_PDM_PRE_DIV] = imx_clk_divider2("pdm_pre_div", "pdm_cg", base + 0xc200, 16, 3);
+ clks[IMX8MM_CLK_VPU_H1_PRE_DIV] = imx_clk_divider2("vpu_h1_pre_div", "vpu_h1_cg", base + 0xc280, 16, 3);
+
+ clks[IMX8MM_CLK_DRAM_ALT_DIV] = imx_clk_divider2("dram_alt_div", "dram_alt_pre_div", base + 0xa000, 0, 6);
+ clks[IMX8MM_CLK_DRAM_APB_DIV] = imx_clk_divider2("dram_apb_div", "dram_apb_pre_div", base + 0xa080, 0, 6);
+ clks[IMX8MM_CLK_VPU_G1_DIV] = imx_clk_divider2("vpu_g1_div", "vpu_g1_pre_div", base + 0xa100, 0, 6);
+ clks[IMX8MM_CLK_VPU_G2_DIV] = imx_clk_divider2("vpu_g2_div", "vpu_g2_pre_div", base + 0xa180, 0, 6);
+ clks[IMX8MM_CLK_DISP_DTRC_DIV] = imx_clk_divider2("disp_dtrc_div", "disp_dtrc_pre_div", base + 0xa200, 0, 6);
+ clks[IMX8MM_CLK_DISP_DC8000_DIV] = imx_clk_divider2("disp_dc8000_div", "disp_dc8000_pre_div", base + 0xa280, 0, 6);
+ clks[IMX8MM_CLK_PCIE1_CTRL_DIV] = imx_clk_divider2("pcie1_ctrl_div", "pcie1_ctrl_pre_div", base + 0xa300, 0, 6);
+ clks[IMX8MM_CLK_PCIE1_PHY_DIV] = imx_clk_divider2("pcie1_phy_div", "pcie1_phy_pre_div", base + 0xa380, 0, 6);
+ clks[IMX8MM_CLK_PCIE1_AUX_DIV] = imx_clk_divider2("pcie1_aux_div", "pcie1_aux_pre_div", base + 0xa400, 0, 6);
+ clks[IMX8MM_CLK_DC_PIXEL_DIV] = imx_clk_divider2("dc_pixel_div", "dc_pixel_pre_div", base + 0xa480, 0, 6);
+ clks[IMX8MM_CLK_LCDIF_PIXEL_DIV] = imx_clk_divider2("lcdif_pixel_div", "lcdif_pixel_pre_div", base + 0xa500, 0, 6);
+ clks[IMX8MM_CLK_SAI1_DIV] = imx_clk_divider2("sai1_div", "sai1_pre_div", base + 0xa580, 0, 6);
+ clks[IMX8MM_CLK_SAI2_DIV] = imx_clk_divider2("sai2_div", "sai2_pre_div", base + 0xa600, 0, 6);
+ clks[IMX8MM_CLK_SAI3_DIV] = imx_clk_divider2("sai3_div", "sai3_pre_div", base + 0xa680, 0, 6);
+ clks[IMX8MM_CLK_SAI4_DIV] = imx_clk_divider2("sai4_div", "sai4_pre_div", base + 0xa700, 0, 6);
+ clks[IMX8MM_CLK_SAI5_DIV] = imx_clk_divider2("sai5_div", "sai5_pre_div", base + 0xa780, 0, 6);
+ clks[IMX8MM_CLK_SAI6_DIV] = imx_clk_divider2("sai6_div", "sai6_pre_div", base + 0xa800, 0, 6);
+ clks[IMX8MM_CLK_SPDIF1_DIV] = imx_clk_divider2("spdif1_div", "spdif1_pre_div", base + 0xa880, 0, 6);
+ clks[IMX8MM_CLK_SPDIF2_DIV] = imx_clk_divider2("spdif2_div", "spdif2_pre_div", base + 0xa900, 0, 6);
+ clks[IMX8MM_CLK_ENET_REF_DIV] = imx_clk_divider2("enet_ref_div", "enet_ref_pre_div", base + 0xa980, 0, 6);
+ clks[IMX8MM_CLK_ENET_TIMER_DIV] = imx_clk_divider2("enet_timer_div", "enet_timer_pre_div", base + 0xaa00, 0, 6);
+ clks[IMX8MM_CLK_ENET_PHY_REF_DIV] = imx_clk_divider2("enet_phy_div", "enet_phy_pre_div", base + 0xaa80, 0, 6);
+ clks[IMX8MM_CLK_NAND_DIV] = imx_clk_divider2("nand_div", "nand_pre_div", base + 0xab00, 0, 6);
+ clks[IMX8MM_CLK_QSPI_DIV] = imx_clk_divider2("qspi_div", "qspi_pre_div", base + 0xab80, 0, 6);
+ clks[IMX8MM_CLK_USDHC1_DIV] = imx_clk_divider2("usdhc1_div", "usdhc1_pre_div", base + 0xac00, 0, 6);
+ clks[IMX8MM_CLK_USDHC2_DIV] = imx_clk_divider2("usdhc2_div", "usdhc2_pre_div", base + 0xac80, 0, 6);
+ clks[IMX8MM_CLK_I2C1_DIV] = imx_clk_divider2("i2c1_div", "i2c1_pre_div", base + 0xad00, 0, 6);
+ clks[IMX8MM_CLK_I2C2_DIV] = imx_clk_divider2("i2c2_div", "i2c2_pre_div", base + 0xad80, 0, 6);
+ clks[IMX8MM_CLK_I2C3_DIV] = imx_clk_divider2("i2c3_div", "i2c3_pre_div", base + 0xae00, 0, 6);
+ clks[IMX8MM_CLK_I2C4_DIV] = imx_clk_divider2("i2c4_div", "i2c4_pre_div", base + 0xae80, 0, 6);
+ clks[IMX8MM_CLK_UART1_DIV] = imx_clk_divider2("uart1_div", "uart1_pre_div", base + 0xaf00, 0, 6);
+ clks[IMX8MM_CLK_UART2_DIV] = imx_clk_divider2("uart2_div", "uart2_pre_div", base + 0xaf80, 0, 6);
+ clks[IMX8MM_CLK_UART3_DIV] = imx_clk_divider2("uart3_div", "uart3_pre_div", base + 0xb000, 0, 6);
+ clks[IMX8MM_CLK_UART4_DIV] = imx_clk_divider2("uart4_div", "uart4_pre_div", base + 0xb080, 0, 6);
+ clks[IMX8MM_CLK_USB_CORE_REF_DIV] = imx_clk_divider2("usb_core_ref_div", "usb_core_ref_pre_div", base + 0xb100, 0, 6);
+ clks[IMX8MM_CLK_USB_PHY_REF_DIV] = imx_clk_divider2("usb_phy_ref_div", "usb_phy_ref_pre_div", base + 0xb180, 0, 6);
+ clks[IMX8MM_CLK_ECSPI1_DIV] = imx_clk_divider2("ecspi1_div", "ecspi1_pre_div", base + 0xb280, 0, 6);
+ clks[IMX8MM_CLK_ECSPI2_DIV] = imx_clk_divider2("ecspi2_div", "ecspi2_pre_div", base + 0xb300, 0, 6);
+ clks[IMX8MM_CLK_PWM1_DIV] = imx_clk_divider2("pwm1_div", "pwm1_pre_div", base + 0xb380, 0, 6);
+ clks[IMX8MM_CLK_PWM2_DIV] = imx_clk_divider2("pwm2_div", "pwm2_pre_div", base + 0xb400, 0, 6);
+ clks[IMX8MM_CLK_PWM3_DIV] = imx_clk_divider2("pwm3_div", "pwm3_pre_div", base + 0xb480, 0, 6);
+ clks[IMX8MM_CLK_PWM4_DIV] = imx_clk_divider2("pwm4_div", "pwm4_pre_div", base + 0xb500, 0, 6);
+ clks[IMX8MM_CLK_GPT1_DIV] = imx_clk_divider2("gpt1_div", "gpt1_pre_div", base + 0xb580, 0, 6);
+ clks[IMX8MM_CLK_WDOG_DIV] = imx_clk_divider2("wdog_div", "wdog_pre_div", base + 0xb900, 0, 6);
+ clks[IMX8MM_CLK_WRCLK_DIV] = imx_clk_divider2("wrclk_div", "wrclk_pre_div", base + 0xb980, 0, 6);
+ clks[IMX8MM_CLK_CLKO1_DIV] = imx_clk_divider2("clko1_div", "clko1_pre_div", base + 0xba00, 0, 6);
+ clks[IMX8MM_CLK_DSI_CORE_DIV] = imx_clk_divider2("dsi_core_div", "dsi_core_pre_div", base + 0xbb00, 0, 6);
+ clks[IMX8MM_CLK_DSI_PHY_REF_DIV] = imx_clk_divider2("dsi_phy_ref_div", "dsi_phy_ref_pre_div", base + 0xbb80, 0, 6);
+ clks[IMX8MM_CLK_DSI_DBI_DIV] = imx_clk_divider2("dsi_dbi_div", "dsi_dbi_pre_div", base + 0xbc00, 0, 6);
+ clks[IMX8MM_CLK_USDHC3_DIV] = imx_clk_divider2("usdhc3_div", "usdhc3_pre_div", base + 0xbc80, 0, 6);
+ clks[IMX8MM_CLK_CSI1_CORE_DIV] = imx_clk_divider2("csi1_core_div", "csi1_core_pre_div", base + 0xbd00, 0, 6);
+ clks[IMX8MM_CLK_CSI1_PHY_REF_DIV] = imx_clk_divider2("csi1_phy_ref_div", "csi1_phy_ref_pre_div", base + 0xbd80, 0, 6);
+ clks[IMX8MM_CLK_CSI1_ESC_DIV] = imx_clk_divider2("csi1_esc_div", "csi1_esc_pre_div", base + 0xbe00, 0, 6);
+ clks[IMX8MM_CLK_CSI2_CORE_DIV] = imx_clk_divider2("csi2_core_div", "csi2_core_pre_div", base + 0xbe80, 0, 6);
+ clks[IMX8MM_CLK_CSI2_PHY_REF_DIV] = imx_clk_divider2("csi2_phy_ref_div", "csi2_phy_ref_pre_div", base + 0xbf00, 0, 6);
+ clks[IMX8MM_CLK_CSI2_ESC_DIV] = imx_clk_divider2("csi2_esc_div", "csi2_esc_pre_div", base + 0xbf80, 0, 6);
+ clks[IMX8MM_CLK_PCIE2_CTRL_DIV] = imx_clk_divider2("pcie2_ctrl_div", "pcie2_ctrl_pre_div", base + 0xc000, 0, 6);
+ clks[IMX8MM_CLK_PCIE2_PHY_DIV] = imx_clk_divider2("pcie2_phy_div", "pcie2_phy_pre_div", base + 0xc080, 0, 6);
+ clks[IMX8MM_CLK_PCIE2_AUX_DIV] = imx_clk_divider2("pcie2_aux_div", "pcie2_aux_pre_div", base + 0xc100, 0, 6);
+ clks[IMX8MM_CLK_ECSPI3_DIV] = imx_clk_divider2("ecspi3_div", "ecspi3_pre_div", base + 0xc180, 0, 6);
+ clks[IMX8MM_CLK_PDM_DIV] = imx_clk_divider2("pdm_div", "pdm_pre_div", base + 0xc200, 0, 6);
+ clks[IMX8MM_CLK_VPU_H1_DIV] = imx_clk_divider2("vpu_h1_div", "vpu_h1_pre_div", base + 0xc280, 0, 6);
+
+ /* CCGR */
+ clks[IMX8MM_CLK_ECSPI1_ROOT] = imx_clk_gate4("ecspi1_root_clk", "ecspi1_div", base + 0x4070, 0);
+ clks[IMX8MM_CLK_ECSPI2_ROOT] = imx_clk_gate4("ecspi2_root_clk", "ecspi2_div", base + 0x4080, 0);
+ clks[IMX8MM_CLK_ECSPI3_ROOT] = imx_clk_gate4("ecspi3_root_clk", "ecspi3_div", base + 0x4090, 0);
+ clks[IMX8MM_CLK_ENET1_ROOT] = imx_clk_gate4("enet1_root_clk", "enet_axi_div", base + 0x40a0, 0);
+ clks[IMX8MM_CLK_GPT1_ROOT] = imx_clk_gate4("gpt1_root_clk", "gpt1_div", base + 0x4100, 0);
+ clks[IMX8MM_CLK_I2C1_ROOT] = imx_clk_gate4("i2c1_root_clk", "i2c1_div", base + 0x4170, 0);
+ clks[IMX8MM_CLK_I2C2_ROOT] = imx_clk_gate4("i2c2_root_clk", "i2c2_div", base + 0x4180, 0);
+ clks[IMX8MM_CLK_I2C3_ROOT] = imx_clk_gate4("i2c3_root_clk", "i2c3_div", base + 0x4190, 0);
+ clks[IMX8MM_CLK_I2C4_ROOT] = imx_clk_gate4("i2c4_root_clk", "i2c4_div", base + 0x41a0, 0);
+ clks[IMX8MM_CLK_MU_ROOT] = imx_clk_gate4("mu_root_clk", "ipg_root", base + 0x4210, 0);
+ clks[IMX8MM_CLK_OCOTP_ROOT] = imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0);
+ clks[IMX8MM_CLK_PCIE1_ROOT] = imx_clk_gate4("pcie1_root_clk", "pcie1_ctrl_div", base + 0x4250, 0);
+ clks[IMX8MM_CLK_PWM1_ROOT] = imx_clk_gate4("pwm1_root_clk", "pwm1_div", base + 0x4280, 0);
+ clks[IMX8MM_CLK_PWM2_ROOT] = imx_clk_gate4("pwm2_root_clk", "pwm2_div", base + 0x4290, 0);
+ clks[IMX8MM_CLK_PWM3_ROOT] = imx_clk_gate4("pwm3_root_clk", "pwm3_div", base + 0x42a0, 0);
+ clks[IMX8MM_CLK_PWM4_ROOT] = imx_clk_gate4("pwm4_root_clk", "pwm4_div", base + 0x42b0, 0);
+ clks[IMX8MM_CLK_QSPI_ROOT] = imx_clk_gate4("qspi_root_clk", "qspi_div", base + 0x42f0, 0);
+ clks[IMX8MM_CLK_NAND_ROOT] = imx_clk_gate4("nand_root_clk", "nand_div", base + 0x4300, 0);
+ clks[IMX8MM_CLK_SAI1_ROOT] = imx_clk_gate2_shared2("sai1_root_clk", "sai1_div", base + 0x4330, 0, &share_count_sai1);
+ clks[IMX8MM_CLK_SAI1_IPG] = imx_clk_gate2_shared2("sai1_ipg_clk", "ipg_audio_root", base + 0x4330, 0, &share_count_sai1);
+ clks[IMX8MM_CLK_SAI2_ROOT] = imx_clk_gate2_shared2("sai2_root_clk", "sai2_div", base + 0x4340, 0, &share_count_sai2);
+ clks[IMX8MM_CLK_SAI2_IPG] = imx_clk_gate2_shared2("sai2_ipg_clk", "ipg_audio_root", base + 0x4340, 0, &share_count_sai2);
+ clks[IMX8MM_CLK_SAI3_ROOT] = imx_clk_gate2_shared2("sai3_root_clk", "sai3_div", base + 0x4350, 0, &share_count_sai3);
+ clks[IMX8MM_CLK_SAI3_IPG] = imx_clk_gate2_shared2("sai3_ipg_clk", "ipg_audio_root", base + 0x4350, 0, &share_count_sai3);
+ clks[IMX8MM_CLK_SAI4_ROOT] = imx_clk_gate2_shared2("sai4_root_clk", "sai4_div", base + 0x4360, 0, &share_count_sai4);
+ clks[IMX8MM_CLK_SAI4_IPG] = imx_clk_gate2_shared2("sai4_ipg_clk", "ipg_audio_root", base + 0x4360, 0, &share_count_sai4);
+ clks[IMX8MM_CLK_SAI5_ROOT] = imx_clk_gate2_shared2("sai5_root_clk", "sai5_div", base + 0x4370, 0, &share_count_sai5);
+ clks[IMX8MM_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
+ clks[IMX8MM_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6_div", base + 0x4380, 0, &share_count_sai6);
+ clks[IMX8MM_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
+ clks[IMX8MM_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1_div", base + 0x4490, 0);
+ clks[IMX8MM_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2_div", base + 0x44a0, 0);
+ clks[IMX8MM_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3_div", base + 0x44b0, 0);
+ clks[IMX8MM_CLK_UART4_ROOT] = imx_clk_gate4("uart4_root_clk", "uart4_div", base + 0x44c0, 0);
+ clks[IMX8MM_CLK_USB1_CTRL_ROOT] = imx_clk_gate4("usb1_ctrl_root_clk", "usb_core_ref_div", base + 0x44d0, 0);
+ clks[IMX8MM_CLK_GPU3D_ROOT] = imx_clk_gate4("gpu3d_root_clk", "gpu3d_div", base + 0x44f0, 0);
+ clks[IMX8MM_CLK_USDHC1_ROOT] = imx_clk_gate4("usdhc1_root_clk", "usdhc1_div", base + 0x4510, 0);
+ clks[IMX8MM_CLK_USDHC2_ROOT] = imx_clk_gate4("usdhc2_root_clk", "usdhc2_div", base + 0x4520, 0);
+ clks[IMX8MM_CLK_WDOG1_ROOT] = imx_clk_gate4("wdog1_root_clk", "wdog_div", base + 0x4530, 0);
+ clks[IMX8MM_CLK_WDOG2_ROOT] = imx_clk_gate4("wdog2_root_clk", "wdog_div", base + 0x4540, 0);
+ clks[IMX8MM_CLK_WDOG3_ROOT] = imx_clk_gate4("wdog3_root_clk", "wdog_div", base + 0x4550, 0);
+ clks[IMX8MM_CLK_VPU_G1_ROOT] = imx_clk_gate4("vpu_g1_root_clk", "vpu_g1_div", base + 0x4560, 0);
+ clks[IMX8MM_CLK_GPU_BUS_ROOT] = imx_clk_gate4("gpu_root_clk", "gpu_axi_div", base + 0x4570, 0);
+ clks[IMX8MM_CLK_VPU_H1_ROOT] = imx_clk_gate4("vpu_h1_root_clk", "vpu_h1_div", base + 0x4590, 0);
+ clks[IMX8MM_CLK_VPU_G2_ROOT] = imx_clk_gate4("vpu_g2_root_clk", "vpu_g2_div", base + 0x45a0, 0);
+ clks[IMX8MM_CLK_PDM_ROOT] = imx_clk_gate2_shared2("pdm_root_clk", "pdm_div", base + 0x45b0, 0, &share_count_pdm);
+ clks[IMX8MM_CLK_PDM_IPG] = imx_clk_gate2_shared2("pdm_ipg_clk", "ipg_audio_root", base + 0x45b0, 0, &share_count_pdm);
+ clks[IMX8MM_CLK_DISP_ROOT] = imx_clk_gate2_shared2("disp_root_clk", "disp_dc8000_div", base + 0x45d0, 0, &share_count_dcss);
+ clks[IMX8MM_CLK_DISP_AXI_ROOT] = imx_clk_gate2_shared2("disp_axi_root_clk", "disp_axi_div", base + 0x45d0, 0, &share_count_dcss);
+ clks[IMX8MM_CLK_DISP_APB_ROOT] = imx_clk_gate2_shared2("disp_apb_root_clk", "disp_apb_div", base + 0x45d0, 0, &share_count_dcss);
+ clks[IMX8MM_CLK_DISP_RTRM_ROOT] = imx_clk_gate2_shared2("disp_rtrm_root_clk", "disp_rtrm_div", base + 0x45d0, 0, &share_count_dcss);
+ clks[IMX8MM_CLK_USDHC3_ROOT] = imx_clk_gate4("usdhc3_root_clk", "usdhc3_div", base + 0x45e0, 0);
+ clks[IMX8MM_CLK_TMU_ROOT] = imx_clk_gate4("tmu_root_clk", "ipg_root", base + 0x4620, 0);
+ clks[IMX8MM_CLK_VPU_DEC_ROOT] = imx_clk_gate4("vpu_dec_root_clk", "vpu_bus_div", base + 0x4630, 0);
+ clks[IMX8MM_CLK_SDMA1_ROOT] = imx_clk_gate4("sdma1_clk", "ipg_root", base + 0x43a0, 0);
+ clks[IMX8MM_CLK_SDMA2_ROOT] = imx_clk_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0);
+ clks[IMX8MM_CLK_SDMA3_ROOT] = imx_clk_gate4("sdma3_clk", "ipg_audio_root", base + 0x45f0, 0);
+ clks[IMX8MM_CLK_GPU2D_ROOT] = imx_clk_gate4("gpu2d_root_clk", "gpu2d_div", base + 0x4660, 0);
+ clks[IMX8MM_CLK_CSI1_ROOT] = imx_clk_gate4("csi1_root_clk", "csi1_core_div", base + 0x4650, 0);
+
+ clks[IMX8MM_CLK_GPT_3M] = imx_clk_fixed_factor("gpt_3m", "osc_24m", 1, 8);
+
+ clks[IMX8MM_CLK_DRAM_ALT_ROOT] = imx_clk_fixed_factor("dram_alt_root", "dram_alt_div", 1, 4);
+ clks[IMX8MM_CLK_DRAM_CORE] = imx_clk_mux2("dram_core_clk", base + 0x9800, 24, 1, imx8mm_dram_core_sels, ARRAY_SIZE(imx8mm_dram_core_sels));
+
+ clks[IMX8MM_CLK_ARM] = imx_clk_cpu("arm", "arm_a53_div",
+ clks[IMX8MM_CLK_A53_DIV],
+ clks[IMX8MM_CLK_A53_SRC],
+ clks[IMX8MM_ARM_PLL_OUT],
+ clks[IMX8MM_CLK_24M]);
+
+ for (i = 0; i < IMX8MM_CLK_END; i++)
+ if (IS_ERR(clks[i]))
+ pr_err("i.MX8mm clk %u register failed with %ld\n",
+ i, PTR_ERR(clks[i]));
+
+ clk_data.clks = clks;
+ clk_data.clk_num = ARRAY_SIZE(clks);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+
+ if (imx_clk_init_on(ccm_node, clks)) {
+ for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
+ clk_prepare_enable(clks[clks_init_on[i]]);
+ }
+
+ clk_set_parent(clks[IMX8MM_CLK_AUDIO_AHB_SRC], clks[IMX8MM_SYS_PLL1_800M]);
+ clk_set_rate(clks[IMX8MM_CLK_AUDIO_AHB_DIV], 400000000);
+ clk_set_rate(clks[IMX8MM_CLK_IPG_AUDIO_ROOT], 400000000);
+
+ /* increase NOC clock to design target */
+ clk_set_rate(clks[IMX8MM_SYS_PLL3], 750000000);
+ clk_set_rate(clks[IMX8MM_VIDEO_PLL1], 594000000);
+ clk_set_parent(clks[IMX8MM_CLK_NOC_SRC], clks[IMX8MM_SYS_PLL3_OUT]);
+ clk_set_parent(clks[IMX8MM_CLK_PCIE1_CTRL_SRC], clks[IMX8MM_SYS_PLL2_250M]);
+ clk_set_parent(clks[IMX8MM_CLK_PCIE1_PHY_SRC], clks[IMX8MM_SYS_PLL2_100M]);
+
+ clk_set_parent(clks[IMX8MM_CLK_CSI1_CORE_SRC], clks[IMX8MM_SYS_PLL2_1000M]);
+ clk_set_parent(clks[IMX8MM_CLK_CSI1_PHY_REF_SRC], clks[IMX8MM_SYS_PLL2_1000M]);
+ clk_set_parent(clks[IMX8MM_CLK_CSI1_ESC_SRC], clks[IMX8MM_SYS_PLL1_800M]);
+
+ writel_relaxed(0x2, base + 0x45d0);
+ clk_set_parent(clks[IMX8MM_CLK_DISP_AXI_SRC], clks[IMX8MM_SYS_PLL2_1000M]);
+ clk_set_rate(clks[IMX8MM_CLK_DISP_AXI_PRE_DIV], 500000000);
+ clk_set_parent(clks[IMX8MM_CLK_DISP_APB_SRC], clks[IMX8MM_SYS_PLL1_800M]);
+ clk_set_rate(clks[IMX8MM_CLK_DISP_APB_PRE_DIV], 200000000);
+
+ imx_register_uart_clocks(uart_clks);
+
+ pr_info("i.MX8MM clock driver init done\n");
+}
+
+CLK_OF_DECLARE(imx8mm, "fsl,imx8mm-ccm", imx8mm_clocks_init);
diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c
new file mode 100644
index 000000000000..9151efccf0be
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8mq.c
@@ -0,0 +1,909 @@
+/*
+ * Copyright 2017 NXP.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <dt-bindings/clock/imx8mq-clock.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/types.h>
+#include <soc/imx8/soc.h>
+
+#include "clk.h"
+
+static u32 share_count_sai1;
+static u32 share_count_sai2;
+static u32 share_count_sai3;
+static u32 share_count_sai4;
+static u32 share_count_sai5;
+static u32 share_count_sai6;
+static u32 share_count_dcss;
+static u32 share_count_nand;
+
+static struct clk *clks[IMX8MQ_CLK_END];
+
+static const char *pll_ref_sels[] = { "osc_25m", "osc_27m", "phy_27m", "dummy", };
+static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
+static const char *gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", };
+static const char *vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", };
+static const char *audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", };
+static const char *audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", };
+static const char *video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", };
+
+static const char *sys1_pll1_out_sels[] = {"sys1_pll1", "sys1_pll1_ref_sel", };
+static const char *sys2_pll1_out_sels[] = {"sys2_pll1", "sys1_pll1_ref_sel", };
+static const char *sys3_pll1_out_sels[] = {"sys3_pll1", "sys3_pll1_ref_sel", };
+static const char *dram_pll1_out_sels[] = {"dram_pll1", "dram_pll1_ref_sel", };
+static const char *video2_pll1_out_sels[] = {"video2_pll1", "video2_pll1_ref_sel", };
+
+static const char *sys1_pll2_out_sels[] = {"sys1_pll2_div", "sys1_pll1_ref_sel", };
+static const char *sys2_pll2_out_sels[] = {"sys2_pll2_div", "sys2_pll1_ref_sel", };
+static const char *sys3_pll2_out_sels[] = {"sys3_pll2_div", "sys2_pll1_ref_sel", };
+static const char *dram_pll2_out_sels[] = {"dram_pll2_div", "dram_pll1_ref_sel", };
+static const char *video2_pll2_out_sels[] = {"video2_pll2_div", "video2_pll1_ref_sel", };
+
+/* CCM ROOT */
+static const char *imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m",
+ "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "sys3_pll2_out", };
+
+static const char *imx8mq_vpu_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m",
+ "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "vpu_pll_out", };
+
+static const char *imx8mq_gpu_core_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out",
+ "sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
+
+static const char *imx8mq_gpu_shader_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out",
+ "sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
+
+static const char *imx8mq_main_axi_sels[] = {"osc_25m", "sys2_pll_333m", "sys1_pll_800m", "sys2_pll_250m",
+ "sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "sys1_pll_100m",};
+
+static const char *imx8mq_enet_axi_sels[] = {"osc_25m", "sys1_pll_266m", "sys1_pll_800m", "sys2_pll_250m",
+ "sys2_pll_200m", "audio_pll1_out", "video_pll1_out", "sys3_pll2_out", };
+
+static const char *imx8mq_nand_usdhc_sels[] = {"osc_25m", "sys1_pll_266m", "sys1_pll_800m", "sys2_pll_200m",
+ "sys1_pll_133m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll1_out", };
+
+static const char *imx8mq_vpu_bus_sels[] = {"osc_25m", "sys1_pll_800m", "vpu_pll_out", "audio_pll2_out", "sys3_pll2_out", "sys2_pll_1000m", "sys2_pll_200m", "sys1_pll_100m", };
+
+static const char *imx8mq_disp_axi_sels[] = {"osc_25m", "sys2_pll_125m", "sys1_pll_800m", "sys3_pll2_out", "sys1_pll_400m", "audio_pll2_out", "clk_ext1", "clk_ext4", };
+
+static const char *imx8mq_disp_apb_sels[] = {"osc_25m", "sys2_pll_125m", "sys1_pll_800m", "sys3_pll2_out",
+ "sys1_pll_40m", "audio_pll2_out", "clk_ext1", "clk_ext3", };
+
+static const char *imx8mq_disp_rtrm_sels[] = {"osc_25m", "sys1_pll_800m", "sys2_pll_200m", "sys1_pll_400m",
+ "audio_pll1_out", "video_pll1_out", "clk_ext2", "clk_ext3", };
+
+static const char *imx8mq_usb_bus_sels[] = {"osc_25m", "sys2_pll_500m", "sys1_pll_800m", "sys2_pll_100m",
+ "sys2_pll_200m", "clk_ext2", "clk_ext4", "audio_pll2_out", };
+
+static const char *imx8mq_gpu_axi_sels[] = {"osc_25m", "sys1_pll_800m", "gpu_pll_out", "sys3_pll2_out", "sys2_pll_1000m",
+ "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
+
+static const char *imx8mq_gpu_ahb_sels[] = {"osc_25m", "sys1_pll_800m", "gpu_pll_out", "sys3_pll2_out", "sys2_pll_1000m",
+ "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
+
+static const char *imx8mq_noc_sels[] = {"osc_25m", "sys1_pll_800m", "sys3_pll2_out", "sys2_pll_1000m", "sys2_pll_500m",
+ "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
+
+static const char *imx8mq_noc_apb_sels[] = {"osc_25m", "sys1_pll_400m", "sys3_pll2_out", "sys2_pll_333m", "sys2_pll_200m",
+ "sys1_pll_800m", "audio_pll1_out", "video_pll1_out", };
+
+static const char *imx8mq_ahb_sels[] = {"osc_25m", "sys1_pll_133m", "sys1_pll_800m", "sys1_pll_400m",
+ "sys2_pll_125m", "sys3_pll2_out", "audio_pll1_out", "video_pll1_out", };
+
+static const char *imx8mq_audio_ahb_sels[] = {"osc_25m", "sys2_pll_500m", "sys1_pll_800m", "sys2_pll_1000m",
+ "sys2_pll_166m", "sys3_pll2_out", "audio_pll1_out", "video_pll1_out", };
+
+static const char *imx8mq_dsi_ahb_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m",
+ "sys2_pll_1000m", "sys3_pll2_out", "clk_ext3", "audio_pll2_out"};
+
+static const char *imx8mq_dram_alt_sels[] = {"osc_25m", "sys1_pll_800m", "sys1_pll_100m", "sys2_pll_500m",
+ "sys2_pll_250m", "sys1_pll_400m", "audio_pll1_out", "sys1_pll_266m", };
+
+static const char *imx8mq_dram_apb_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_40m", "sys1_pll_160m",
+ "sys1_pll_800m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll2_out", };
+
+static const char *imx8mq_vpu_g1_sels[] = {"osc_25m", "vpu_pll_out", "sys1_pll_800m", "sys2_pll_1000m", "sys1_pll_100m", "sys2_pll_125m", "sys3_pll2_out", "audio_pll1_out", };
+
+static const char *imx8mq_vpu_g2_sels[] = {"osc_25m", "vpu_pll_out", "sys1_pll_800m", "sys2_pll_1000m", "sys1_pll_100m", "sys2_pll_125m", "sys3_pll2_out", "audio_pll1_out", };
+
+static const char *imx8mq_disp_dtrc_sels[] = {"osc_25m", "vpu_pll_out", "sys1_pll_800m", "sys2_pll_1000m", "sys1_pll_160m", "sys2_pll_100m", "sys3_pll2_out", "audio_pll2_out", };
+
+static const char *imx8mq_disp_dc8000_sels[] = {"osc_25m", "vpu_pll_out", "sys1_pll_800m", "sys2_pll_1000m", "sys1_pll_160m", "sys2_pll_100m", "sys3_pll2_out", "audio_pll2_out", };
+
+static const char *imx8mq_pcie1_ctrl_sels[] = {"osc_25m", "sys2_pll_250m", "sys2_pll_200m", "sys1_pll_266m",
+ "sys1_pll_800m", "sys2_pll_500m", "sys2_pll_250m", "sys3_pll2_out", };
+
+static const char *imx8mq_pcie1_phy_sels[] = {"osc_25m", "sys2_pll_100m", "sys2_pll_500m", "clk_ext1", "clk_ext2",
+ "clk_ext3", "clk_ext4", };
+
+static const char *imx8mq_pcie1_aux_sels[] = {"osc_25m", "sys2_pll_200m", "sys2_pll_500m", "sys3_pll2_out",
+ "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_160m", "sys1_pll_200m", };
+
+static const char *imx8mq_dc_pixel_sels[] = {"osc_25m", "video_pll1_out", "audio_pll2_out", "audio_pll1_out", "sys1_pll_800m", "sys2_pll_1000m", "sys3_pll2_out", "clk_ext4", };
+
+static const char *imx8mq_lcdif_pixel_sels[] = {"osc_25m", "video_pll1_out", "audio_pll2_out", "audio_pll1_out", "sys1_pll_800m", "sys2_pll_1000m", "sys3_pll2_out", "clk_ext4", };
+
+static const char *imx8mq_sai1_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext1", "clk_ext2", };
+
+static const char *imx8mq_sai2_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext2", "clk_ext3", };
+
+static const char *imx8mq_sai3_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext3", "clk_ext4", };
+
+static const char *imx8mq_sai4_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext1", "clk_ext2", };
+
+static const char *imx8mq_sai5_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext2", "clk_ext3", };
+
+static const char *imx8mq_sai6_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext3", "clk_ext4", };
+
+static const char *imx8mq_spdif1_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext2", "clk_ext3", };
+
+static const char *imx8mq_spdif2_sels[] = {"osc_25m", "audio_pll1_out", "audio_pll2_out", "video_pll1_out", "sys1_pll_133m", "osc_27m", "clk_ext3", "clk_ext4", };
+
+static const char *imx8mq_enet_ref_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_500m", "sys2_pll_100m",
+ "sys1_pll_160m", "audio_pll1_out", "video_pll1_out", "clk_ext4", };
+
+static const char *imx8mq_enet_timer_sels[] = {"osc_25m", "sys2_pll_100m", "audio_pll1_out", "clk_ext1", "clk_ext2",
+ "clk_ext3", "clk_ext4", "video_pll1_out", };
+
+static const char *imx8mq_enet_phy_sels[] = {"osc_25m", "sys2_pll_50m", "sys2_pll_125m", "sys2_pll_500m",
+ "audio_pll1_out", "video_pll1_out", "audio_pll2_out", };
+
+static const char *imx8mq_nand_sels[] = {"osc_25m", "sys2_pll_500m", "audio_pll1_out", "sys1_pll_400m",
+ "audio_pll2_out", "sys3_pll2_out", "sys2_pll_250m", "video_pll1_out", };
+
+static const char *imx8mq_qspi_sels[] = {"osc_25m", "sys1_pll_400m", "sys1_pll_800m", "sys2_pll_500m",
+ "audio_pll2_out", "sys1_pll_266m", "sys3_pll2_out", "sys1_pll_100m", };
+
+static const char *imx8mq_usdhc1_sels[] = {"osc_25m", "sys1_pll_400m", "sys1_pll_800m", "sys2_pll_500m",
+ "audio_pll2_out", "sys1_pll_266m", "sys3_pll2_out", "sys1_pll_100m", };
+
+static const char *imx8mq_usdhc2_sels[] = {"osc_25m", "sys1_pll_400m", "sys1_pll_800m", "sys2_pll_500m",
+ "audio_pll2_out", "sys1_pll_266m", "sys3_pll2_out", "sys1_pll_100m", };
+
+static const char *imx8mq_i2c1_sels[] = {"osc_25m", "sys1_pll_160m", "sys2_pll_50m", "sys3_pll2_out", "audio_pll1_out",
+ "video_pll1_out", "audio_pll2_out", "sys1_pll_133m", };
+
+static const char *imx8mq_i2c2_sels[] = {"osc_25m", "sys1_pll_160m", "sys2_pll_50m", "sys3_pll2_out", "audio_pll1_out",
+ "video_pll1_out", "audio_pll2_out", "sys1_pll_133m", };
+
+static const char *imx8mq_i2c3_sels[] = {"osc_25m", "sys1_pll_160m", "sys2_pll_50m", "sys3_pll2_out", "audio_pll1_out",
+ "video_pll1_out", "audio_pll2_out", "sys1_pll_133m", };
+
+static const char *imx8mq_i2c4_sels[] = {"osc_25m", "sys1_pll_160m", "sys2_pll_50m", "sys3_pll2_out", "audio_pll1_out",
+ "video_pll1_out", "audio_pll2_out", "sys1_pll_133m", };
+
+static const char *imx8mq_uart1_sels[] = {"osc_25m", "sys1_pll_80m", "sys2_pll_200m", "sys2_pll_100m",
+ "sys3_pll2_out", "clk_ext2", "clk_ext4", "audio_pll2_out", };
+
+static const char *imx8mq_uart2_sels[] = {"osc_25m", "sys1_pll_80m", "sys2_pll_200m", "sys2_pll_100m",
+ "sys3_pll2_out", "clk_ext2", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mq_uart3_sels[] = {"osc_25m", "sys1_pll_80m", "sys2_pll_200m", "sys2_pll_100m",
+ "sys3_pll2_out", "clk_ext2", "clk_ext4", "audio_pll2_out", };
+
+static const char *imx8mq_uart4_sels[] = {"osc_25m", "sys1_pll_80m", "sys2_pll_200m", "sys2_pll_100m",
+ "sys3_pll2_out", "clk_ext2", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mq_usb_core_sels[] = {"osc_25m", "sys1_pll_100m", "sys1_pll_40m", "sys2_pll_100m",
+ "sys2_pll_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mq_usb_phy_sels[] = {"osc_25m", "sys1_pll_100m", "sys1_pll_40m", "sys2_pll_100m",
+ "sys2_pll_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mq_ecspi1_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_40m", "sys1_pll_160m",
+ "sys1_pll_800m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll2_out", };
+
+static const char *imx8mq_ecspi2_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_40m", "sys1_pll_160m",
+ "sys1_pll_800m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll2_out", };
+
+static const char *imx8mq_pwm1_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_160m", "sys1_pll_40m",
+ "sys3_pll2_out", "clk_ext1", "sys1_pll_80m", "video_pll1_out", };
+
+static const char *imx8mq_pwm2_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_160m", "sys1_pll_40m",
+ "sys3_pll2_out", "clk_ext1", "sys1_pll_80m", "video_pll1_out", };
+
+static const char *imx8mq_pwm3_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_160m", "sys1_pll_40m",
+ "sys3_pll2_out", "clk_ext2", "sys1_pll_80m", "video_pll1_out", };
+
+static const char *imx8mq_pwm4_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_160m", "sys1_pll_40m",
+ "sys3_pll2_out", "clk_ext2", "sys1_pll_80m", "video_pll1_out", };
+
+static const char *imx8mq_gpt1_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_400m", "sys1_pll_40m",
+ "sys1_pll_80m", "audio_pll1_out", "clk_ext1", };
+
+static const char *imx8mq_wdog_sels[] = {"osc_25m", "sys1_pll_133m", "sys1_pll_160m", "vpu_pll_out",
+ "sys2_pll_125m", "sys3_pll2_out", "sys1_pll_80m", "sys2_pll_166m", };
+
+static const char *imx8mq_wrclk_sels[] = {"osc_25m", "sys1_pll_40m", "vpu_pll_out", "sys3_pll2_out", "sys2_pll_200m",
+ "sys1_pll_266m", "sys2_pll_500m", "sys1_pll_100m", };
+
+static const char *imx8mq_dsi_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m",
+ "sys2_pll_1000m", "sys3_pll2_out", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mq_dsi_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m",
+ "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mq_dsi_dbi_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_100m", "sys1_pll_800m",
+ "sys2_pll_1000m", "sys3_pll2_out", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mq_dsi_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m",
+ "sys2_pll_1000m", "sys3_pll2_out", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mq_csi1_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m",
+ "sys2_pll_1000m", "sys3_pll2_out", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mq_csi1_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m",
+ "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mq_csi1_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m",
+ "sys2_pll_1000m", "sys3_pll2_out", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mq_csi2_core_sels[] = {"osc_25m", "sys1_pll_266m", "sys2_pll_250m", "sys1_pll_800m",
+ "sys2_pll_1000m", "sys3_pll2_out", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mq_csi2_phy_sels[] = {"osc_25m", "sys2_pll_125m", "sys2_pll_100m", "sys1_pll_800m",
+ "sys2_pll_1000m", "clk_ext2", "audio_pll2_out", "video_pll1_out", };
+
+static const char *imx8mq_csi2_esc_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_800m",
+ "sys2_pll_1000m", "sys3_pll2_out", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mq_pcie2_ctrl_sels[] = {"osc_25m", "sys2_pll_250m", "sys2_pll_200m", "sys1_pll_266m",
+ "sys1_pll_800m", "sys2_pll_500m", "sys2_pll_333m", "sys3_pll2_out", };
+
+static const char *imx8mq_pcie2_phy_sels[] = {"osc_25m", "sys2_pll_100m", "sys2_pll_500m", "clk_ext1",
+ "clk_ext2", "clk_ext3", "clk_ext4", "sys1_pll_400m", };
+
+static const char *imx8mq_pcie2_aux_sels[] = {"osc_25m", "sys2_pll_200m", "sys2_pll_50m", "sys3_pll2_out",
+ "sys2_pll_100m", "sys1_pll_80m", "sys1_pll_160m", "sys1_pll_200m", };
+
+static const char *imx8mq_ecspi3_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_40m", "sys1_pll_160m",
+ "sys1_pll_800m", "sys3_pll2_out", "sys2_pll_250m", "audio_pll2_out", };
+static const char *imx8mq_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", };
+
+static const char *imx8mq_clko2_sels[] = {"osc_25m", "sys2_pll_200m", "sys1_pll_400m", "sys2_pll_166m", "audio_pll1_out",
+ "video_pll1_out", "ckil", };
+
+static int const clks_init_on[] __initconst = {
+ IMX8MQ_CLK_DRAM_CORE, IMX8MQ_CLK_AHB_CG,
+ IMX8MQ_CLK_NOC_CG, IMX8MQ_CLK_NOC_APB_CG,
+ IMX8MQ_CLK_USB_BUS_CG,
+ IMX8MQ_CLK_MAIN_AXI_CG, IMX8MQ_CLK_A53_CG,
+ IMX8MQ_CLK_TMU_ROOT,
+ IMX8MQ_CLK_DRAM_APB_DIV,
+};
+
+static struct clk ** const uart_clks[] __initconst = {
+ &clks[IMX8MQ_CLK_UART1_ROOT],
+ &clks[IMX8MQ_CLK_UART2_ROOT],
+ &clks[IMX8MQ_CLK_UART3_ROOT],
+ &clks[IMX8MQ_CLK_UART4_ROOT],
+ NULL
+};
+
+static struct clk_onecell_data clk_data;
+
+static int __init imx_clk_init_on(struct device_node *np,
+ struct clk * const clks[])
+{
+ u32 *array;
+ int i, ret, elems;
+
+ elems = of_property_count_u32_elems(np, "init-on-array");
+ if (elems < 0)
+ return elems;
+ array = kzalloc(elems * sizeof(elems), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(array))
+ return PTR_ERR(array);
+
+ ret = of_property_read_u32_array(np, "init-on-array", array, elems);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < elems; i++) {
+ ret = clk_prepare_enable(clks[array[i]]);
+ if (ret)
+ pr_err("clk_prepare_enable failed %d\n", array[i]);
+ }
+
+ return 0;
+}
+
+static void __init imx8mq_clocks_init(struct device_node *ccm_node)
+{
+ struct device_node *np;
+ void __iomem *base;
+ int i;
+
+ check_m4_enabled();
+
+ clks[IMX8MQ_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+ clks[IMX8MQ_CLK_32K] = of_clk_get_by_name(ccm_node, "ckil");
+ clks[IMX8MQ_CLK_25M] = of_clk_get_by_name(ccm_node, "osc_25m");
+ clks[IMX8MQ_CLK_27M] = of_clk_get_by_name(ccm_node, "osc_27m");
+ clks[IMX8MQ_CLK_EXT1] = of_clk_get_by_name(ccm_node, "clk_ext1");
+ clks[IMX8MQ_CLK_EXT2] = of_clk_get_by_name(ccm_node, "clk_ext2");
+ clks[IMX8MQ_CLK_EXT3] = of_clk_get_by_name(ccm_node, "clk_ext3");
+ clks[IMX8MQ_CLK_EXT4] = of_clk_get_by_name(ccm_node, "clk_ext4");
+ clks[IMX8MQ_CLK_PHY_27MHZ] = imx_clk_fixed("phy_27m", 27000000);
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-anatop");
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ clks[IMX8MQ_ARM_PLL_REF_SEL] = imx_clk_mux("arm_pll_ref_sel", base + 0x28, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MQ_GPU_PLL_REF_SEL] = imx_clk_mux("gpu_pll_ref_sel", base + 0x18, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MQ_VPU_PLL_REF_SEL] = imx_clk_mux("vpu_pll_ref_sel", base + 0x20, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MQ_AUDIO_PLL1_REF_SEL] = imx_clk_mux("audio_pll1_ref_sel", base + 0x0, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MQ_AUDIO_PLL2_REF_SEL] = imx_clk_mux("audio_pll2_ref_sel", base + 0x8, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MQ_VIDEO_PLL1_REF_SEL] = imx_clk_mux("video_pll1_ref_sel", base + 0x10, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MQ_SYS1_PLL1_REF_SEL] = imx_clk_mux("sys1_pll1_ref_sel", base + 0x30, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MQ_SYS2_PLL1_REF_SEL] = imx_clk_mux("sys2_pll1_ref_sel", base + 0x3c, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MQ_SYS3_PLL1_REF_SEL] = imx_clk_mux("sys3_pll1_ref_sel", base + 0x48, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MQ_DRAM_PLL1_REF_SEL] = imx_clk_mux("dram_pll1_ref_sel", base + 0x60, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+ clks[IMX8MQ_VIDEO2_PLL1_REF_SEL] = imx_clk_mux("video2_pll1_ref_sel", base + 0x54, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
+
+ clks[IMX8MQ_ARM_PLL_REF_DIV] = imx_clk_divider("arm_pll_ref_div", "arm_pll_ref_sel", base + 0x28, 5, 6);
+ clks[IMX8MQ_GPU_PLL_REF_DIV] = imx_clk_divider("gpu_pll_ref_div", "gpu_pll_ref_sel", base + 0x18, 5, 6);
+ clks[IMX8MQ_VPU_PLL_REF_DIV] = imx_clk_divider("vpu_pll_ref_div", "vpu_pll_ref_sel", base + 0x20, 5, 6);
+ clks[IMX8MQ_AUDIO_PLL1_REF_DIV] = imx_clk_divider("audio_pll1_ref_div", "audio_pll1_ref_sel", base + 0x0, 5, 6);
+ clks[IMX8MQ_AUDIO_PLL2_REF_DIV] = imx_clk_divider("audio_pll2_ref_div", "audio_pll2_ref_sel", base + 0x8, 5, 6);
+ clks[IMX8MQ_VIDEO_PLL1_REF_DIV] = imx_clk_divider("video_pll1_ref_div", "video_pll1_ref_sel", base + 0x10, 5, 6);
+ clks[IMX8MQ_SYS1_PLL1_REF_DIV] = imx_clk_divider("sys1_pll1_ref_div", "sys1_pll1_ref_sel", base + 0x38, 25, 3);
+ clks[IMX8MQ_SYS2_PLL1_REF_DIV] = imx_clk_divider("sys2_pll1_ref_div", "sys2_pll1_ref_sel", base + 0x44, 25, 3);
+ clks[IMX8MQ_SYS3_PLL1_REF_DIV] = imx_clk_divider("sys3_pll1_ref_div", "sys3_pll1_ref_sel", base + 0x50, 25, 3);
+ clks[IMX8MQ_DRAM_PLL1_REF_DIV] = imx_clk_divider("dram_pll1_ref_div", "dram_pll1_ref_sel", base + 0x68, 25, 3);
+ clks[IMX8MQ_VIDEO2_PLL1_REF_DIV] = imx_clk_divider("video2_pll1_ref_div", "video2_pll1_ref_sel", base + 0x5c, 25, 3);
+
+ clks[IMX8MQ_ARM_PLL] = imx_clk_frac_pll("arm_pll", "arm_pll_ref_div", base + 0x28);
+ clks[IMX8MQ_GPU_PLL] = imx_clk_frac_pll("gpu_pll", "gpu_pll_ref_div", base + 0x18);
+ clks[IMX8MQ_VPU_PLL] = imx_clk_frac_pll("vpu_pll", "vpu_pll_ref_div", base + 0x20);
+ clks[IMX8MQ_AUDIO_PLL1] = imx_clk_frac_pll("audio_pll1", "audio_pll1_ref_div", base + 0x0);
+ clks[IMX8MQ_AUDIO_PLL2] = imx_clk_frac_pll("audio_pll2", "audio_pll2_ref_div", base + 0x8);
+ clks[IMX8MQ_VIDEO_PLL1] = imx_clk_frac_pll("video_pll1", "video_pll1_ref_div", base + 0x10);
+ clks[IMX8MQ_SYS1_PLL1] = imx_clk_sccg_pll("sys1_pll1", "sys1_pll1_ref_div", base + 0x30, SCCG_PLL1);
+ clks[IMX8MQ_SYS2_PLL1] = imx_clk_sccg_pll("sys2_pll1", "sys2_pll1_ref_div", base + 0x3c, SCCG_PLL1);
+ clks[IMX8MQ_SYS3_PLL1] = imx_clk_sccg_pll("sys3_pll1", "sys3_pll1_ref_div", base + 0x48, SCCG_PLL1);
+ clks[IMX8MQ_DRAM_PLL1] = imx_clk_sccg_pll("dram_pll1", "dram_pll1_ref_div", base + 0x60, SCCG_PLL1);
+ clks[IMX8MQ_VIDEO2_PLL1] = imx_clk_sccg_pll("video2_pll1", "video2_pll1_ref_div", base + 0x54, 3);
+
+ clks[IMX8MQ_SYS1_PLL2] = imx_clk_sccg_pll("sys1_pll2", "sys1_pll1_out_div", base + 0x30, SCCG_PLL2);
+ clks[IMX8MQ_SYS2_PLL2] = imx_clk_sccg_pll("sys2_pll2", "sys2_pll1_out_div", base + 0x3c, SCCG_PLL2);
+ clks[IMX8MQ_SYS3_PLL2] = imx_clk_sccg_pll("sys3_pll2", "sys3_pll1_out_div", base + 0x48, SCCG_PLL2);
+ clks[IMX8MQ_DRAM_PLL2] = imx_clk_sccg_pll("dram_pll2", "dram_pll1_out_div", base + 0x60, SCCG_PLL2);
+ clks[IMX8MQ_VIDEO2_PLL2] = imx_clk_sccg_pll("video2_pll2", "video2_pll1_out_div", base + 0x54, SCCG_PLL2);
+
+ /* PLL divs */
+ clks[IMX8MQ_SYS1_PLL1_OUT_DIV] = imx_clk_divider("sys1_pll1_out_div", "sys1_pll1_out", base + 0x38, 19, 6);
+ clks[IMX8MQ_SYS2_PLL1_OUT_DIV] = imx_clk_divider("sys2_pll1_out_div", "sys2_pll1_out", base + 0x44, 19, 6);
+ clks[IMX8MQ_SYS3_PLL1_OUT_DIV] = imx_clk_divider("sys3_pll1_out_div", "sys3_pll1_out", base + 0x50, 19, 6);
+ clks[IMX8MQ_DRAM_PLL1_OUT_DIV] = imx_clk_divider("dram_pll1_out_div", "dram_pll1_out", base + 0x68, 19, 6);
+ clks[IMX8MQ_VIDEO2_PLL1_OUT_DIV] = imx_clk_divider("video2_pll1_out_div", "video2_pll1_out", base + 0x5c, 19, 6);
+ clks[IMX8MQ_SYS1_PLL2_DIV] = imx_clk_divider("sys1_pll2_div", "sys1_pll2", base + 0x38, 1, 6);
+ clks[IMX8MQ_SYS2_PLL2_DIV] = imx_clk_divider("sys2_pll2_div", "sys2_pll2", base + 0x44, 1, 6);
+ clks[IMX8MQ_SYS3_PLL2_DIV] = imx_clk_divider("sys3_pll2_div", "sys3_pll2", base + 0x50, 1, 6);
+ clks[IMX8MQ_DRAM_PLL2_DIV] = imx_clk_divider("dram_pll2_div", "dram_pll2", base + 0x68, 1, 6);
+ clks[IMX8MQ_VIDEO2_PLL2_DIV] = imx_clk_divider("video2_pll2_div", "video2_pll2", base + 0x5c, 1, 6);
+
+ /* PLL bypass out */
+ clks[IMX8MQ_ARM_PLL_BYPASS] = imx_clk_mux("arm_pll_bypass", base + 0x28, 14, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels));
+ clks[IMX8MQ_GPU_PLL_BYPASS] = imx_clk_mux("gpu_pll_bypass", base + 0x18, 14, 1, gpu_pll_bypass_sels, ARRAY_SIZE(gpu_pll_bypass_sels));
+ clks[IMX8MQ_VPU_PLL_BYPASS] = imx_clk_mux("vpu_pll_bypass", base + 0x20, 14, 1, vpu_pll_bypass_sels, ARRAY_SIZE(vpu_pll_bypass_sels));
+ clks[IMX8MQ_AUDIO_PLL1_BYPASS] = imx_clk_mux("audio_pll1_bypass", base + 0x0, 14, 1, audio_pll1_bypass_sels, ARRAY_SIZE(audio_pll1_bypass_sels));
+ clks[IMX8MQ_AUDIO_PLL2_BYPASS] = imx_clk_mux("audio_pll2_bypass", base + 0x8, 14, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels));
+ clks[IMX8MQ_VIDEO_PLL1_BYPASS] = imx_clk_mux("video_pll1_bypass", base + 0x10, 14, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels));
+
+ clks[IMX8MQ_SYS1_PLL1_OUT] = imx_clk_mux("sys1_pll1_out", base + 0x30, 5, 1, sys1_pll1_out_sels, ARRAY_SIZE(sys1_pll1_out_sels));
+ clks[IMX8MQ_SYS2_PLL1_OUT] = imx_clk_mux("sys2_pll1_out", base + 0x3c, 5, 1, sys2_pll1_out_sels, ARRAY_SIZE(sys2_pll1_out_sels));
+ clks[IMX8MQ_SYS3_PLL1_OUT] = imx_clk_mux("sys3_pll1_out", base + 0x48, 5, 1, sys3_pll1_out_sels, ARRAY_SIZE(sys3_pll1_out_sels));
+ clks[IMX8MQ_DRAM_PLL1_OUT] = imx_clk_mux("dram_pll1_out", base + 0x60, 5, 1, dram_pll1_out_sels, ARRAY_SIZE(dram_pll1_out_sels));
+ clks[IMX8MQ_VIDEO2_PLL1_OUT] = imx_clk_mux("video2_pll1_out", base + 0x54, 5, 1, video2_pll1_out_sels, ARRAY_SIZE(video2_pll1_out_sels));
+ clks[IMX8MQ_SYS1_PLL2_OUT] = imx_clk_mux("sys1_pll2_out", base + 0x30, 4, 1, sys1_pll2_out_sels, ARRAY_SIZE(sys1_pll2_out_sels));
+ clks[IMX8MQ_SYS2_PLL2_OUT] = imx_clk_mux("sys2_pll2_out", base + 0x3c, 4, 1, sys2_pll2_out_sels, ARRAY_SIZE(sys2_pll2_out_sels));
+ clks[IMX8MQ_SYS3_PLL2_OUT] = imx_clk_mux("sys3_pll2_out", base + 0x48, 4, 1, sys3_pll2_out_sels, ARRAY_SIZE(sys3_pll2_out_sels));
+ clks[IMX8MQ_DRAM_PLL2_OUT] = imx_clk_mux("dram_pll2_out", base + 0x60, 4, 1, dram_pll2_out_sels, ARRAY_SIZE(dram_pll2_out_sels));
+ clks[IMX8MQ_VIDEO2_PLL2_OUT] = imx_clk_mux("video2_pll2_out", base + 0x54, 4, 1, video2_pll2_out_sels, ARRAY_SIZE(video2_pll2_out_sels));
+
+ /* unbypass all the plls */
+ clk_set_parent(clks[IMX8MQ_GPU_PLL_BYPASS], clks[IMX8MQ_GPU_PLL]);
+ clk_set_parent(clks[IMX8MQ_VPU_PLL_BYPASS], clks[IMX8MQ_VPU_PLL]);
+ clk_set_parent(clks[IMX8MQ_AUDIO_PLL1_BYPASS], clks[IMX8MQ_AUDIO_PLL1]);
+ clk_set_parent(clks[IMX8MQ_AUDIO_PLL2_BYPASS], clks[IMX8MQ_AUDIO_PLL2]);
+ clk_set_parent(clks[IMX8MQ_VIDEO_PLL1_BYPASS], clks[IMX8MQ_VIDEO_PLL1]);
+ clk_set_parent(clks[IMX8MQ_SYS3_PLL1_OUT], clks[IMX8MQ_SYS3_PLL1]);
+ clk_set_parent(clks[IMX8MQ_SYS3_PLL2_OUT], clks[IMX8MQ_SYS3_PLL2_DIV]);
+
+ /* PLL OUT GATE */
+ clks[IMX8MQ_ARM_PLL_OUT] = imx_clk_gate("arm_pll_out", "arm_pll_bypass", base + 0x28, 21);
+ clks[IMX8MQ_GPU_PLL_OUT] = imx_clk_gate("gpu_pll_out", "gpu_pll_bypass", base + 0x18, 21);
+ clks[IMX8MQ_VPU_PLL_OUT] = imx_clk_gate("vpu_pll_out", "vpu_pll_bypass", base + 0x20, 21);
+ clks[IMX8MQ_AUDIO_PLL1_OUT] = imx_clk_gate("audio_pll1_out", "audio_pll1_bypass", base + 0x0, 21);
+ clks[IMX8MQ_AUDIO_PLL2_OUT] = imx_clk_gate("audio_pll2_out", "audio_pll2_bypass", base + 0x8, 21);
+ clks[IMX8MQ_VIDEO_PLL1_OUT] = imx_clk_gate("video_pll1_out", "video_pll1_bypass", base + 0x10, 21);
+ clks[IMX8MQ_SYS1_PLL_OUT] = imx_clk_gate("sys1_pll_out", "sys1_pll2_out", base + 0x30, 9);
+ clks[IMX8MQ_SYS2_PLL_OUT] = imx_clk_gate("sys2_pll_out", "sys2_pll2_out", base + 0x3c, 9);
+ clks[IMX8MQ_SYS3_PLL_OUT] = imx_clk_gate("sys3_pll_out", "sys3_pll2_out", base + 0x48, 9);
+ clks[IMX8MQ_DRAM_PLL_OUT] = imx_clk_gate("dram_pll_out", "dram_pll2_out", base + 0x60, 9);
+ clks[IMX8MQ_VIDEO2_PLL_OUT] = imx_clk_gate("video2_pll_out", "video2_pll2_out", base + 0x54, 9);
+
+ /* SYS PLL fixed output */
+ clks[IMX8MQ_SYS1_PLL_40M] = imx_clk_fixed_factor("sys1_pll_40m", "sys1_pll_out", 1, 20);
+ clks[IMX8MQ_SYS1_PLL_80M] = imx_clk_fixed_factor("sys1_pll_80m", "sys1_pll_out", 1, 10);
+ clks[IMX8MQ_SYS1_PLL_100M] = imx_clk_fixed_factor("sys1_pll_100m", "sys1_pll_out", 1, 8);
+ clks[IMX8MQ_SYS1_PLL_133M] = imx_clk_fixed_factor("sys1_pll_133m", "sys1_pll_out", 1, 6);
+ clks[IMX8MQ_SYS1_PLL_160M] = imx_clk_fixed_factor("sys1_pll_160m", "sys1_pll_out", 1, 5);
+ clks[IMX8MQ_SYS1_PLL_200M] = imx_clk_fixed_factor("sys1_pll_200m", "sys1_pll_out", 1, 4);
+ clks[IMX8MQ_SYS1_PLL_266M] = imx_clk_fixed_factor("sys1_pll_266m", "sys1_pll_out", 1, 3);
+ clks[IMX8MQ_SYS1_PLL_400M] = imx_clk_fixed_factor("sys1_pll_400m", "sys1_pll_out", 1, 2);
+ clks[IMX8MQ_SYS1_PLL_800M] = imx_clk_fixed_factor("sys1_pll_800m", "sys1_pll_out", 1, 1);
+
+ clks[IMX8MQ_SYS2_PLL_50M] = imx_clk_fixed_factor("sys2_pll_50m", "sys2_pll_out", 1, 20);
+ clks[IMX8MQ_SYS2_PLL_100M] = imx_clk_fixed_factor("sys2_pll_100m", "sys2_pll_out", 1, 10);
+ clks[IMX8MQ_SYS2_PLL_125M] = imx_clk_fixed_factor("sys2_pll_125m", "sys2_pll_out", 1, 8);
+ clks[IMX8MQ_SYS2_PLL_166M] = imx_clk_fixed_factor("sys2_pll_166m", "sys2_pll_out", 1, 6);
+ clks[IMX8MQ_SYS2_PLL_200M] = imx_clk_fixed_factor("sys2_pll_200m", "sys2_pll_out", 1, 5);
+ clks[IMX8MQ_SYS2_PLL_250M] = imx_clk_fixed_factor("sys2_pll_250m", "sys2_pll_out", 1, 4);
+ clks[IMX8MQ_SYS2_PLL_333M] = imx_clk_fixed_factor("sys2_pll_333m", "sys2_pll_out", 1, 3);
+ clks[IMX8MQ_SYS2_PLL_500M] = imx_clk_fixed_factor("sys2_pll_500m", "sys2_pll_out", 1, 2);
+ clks[IMX8MQ_SYS2_PLL_1000M] = imx_clk_fixed_factor("sys2_pll_1000m", "sys2_pll_out", 1, 1);
+
+ np = ccm_node;
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+ /* CORE */
+ clks[IMX8MQ_CLK_A53_SRC] = imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mq_a53_sels, ARRAY_SIZE(imx8mq_a53_sels));
+ clks[IMX8MQ_CLK_VPU_SRC] = imx_clk_mux2("vpu_src", base + 0x8100, 24, 3, imx8mq_vpu_sels, ARRAY_SIZE(imx8mq_vpu_sels));
+ clks[IMX8MQ_CLK_GPU_CORE_SRC] = imx_clk_mux2("gpu_core_src", base + 0x8180, 24, 3, imx8mq_gpu_core_sels, ARRAY_SIZE(imx8mq_gpu_core_sels));
+ clks[IMX8MQ_CLK_GPU_SHADER_SRC] = imx_clk_mux2("gpu_shader_src", base + 0x8200, 24, 3, imx8mq_gpu_shader_sels, ARRAY_SIZE(imx8mq_gpu_shader_sels));
+ clks[IMX8MQ_CLK_A53_CG] = imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28);
+ clks[IMX8MQ_CLK_VPU_CG] = imx_clk_gate3("vpu_cg", "vpu_src", base + 0x8100, 28);
+ clks[IMX8MQ_CLK_GPU_CORE_CG] = imx_clk_gate3("gpu_core_cg", "gpu_core_src", base + 0x8180, 28);
+ clks[IMX8MQ_CLK_GPU_SHADER_CG] = imx_clk_gate3("gpu_shader_cg", "gpu_shader_src", base + 0x8200, 28);
+
+ clks[IMX8MQ_CLK_A53_DIV] = imx_clk_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3);
+ clks[IMX8MQ_CLK_VPU_DIV] = imx_clk_divider2("vpu_div", "vpu_cg", base + 0x8100, 0, 3);
+ clks[IMX8MQ_CLK_GPU_CORE_DIV] = imx_clk_divider2("gpu_core_div", "gpu_core_cg", base + 0x8180, 0, 3);
+ clks[IMX8MQ_CLK_GPU_SHADER_DIV] = imx_clk_divider2("gpu_shader_div", "gpu_shader_cg", base + 0x8200, 0, 3);
+
+ /* BUS */
+ clks[IMX8MQ_CLK_MAIN_AXI_SRC] = imx_clk_mux2("main_axi_src", base + 0x8800, 24, 3, imx8mq_main_axi_sels, ARRAY_SIZE(imx8mq_main_axi_sels));
+ clks[IMX8MQ_CLK_ENET_AXI_SRC] = imx_clk_mux2("enet_axi_src", base + 0x8880, 24, 3, imx8mq_enet_axi_sels, ARRAY_SIZE(imx8mq_enet_axi_sels));
+ clks[IMX8MQ_CLK_NAND_USDHC_BUS_SRC] = imx_clk_mux2("nand_usdhc_bus_src", base + 0x8900, 24, 3, imx8mq_nand_usdhc_sels, ARRAY_SIZE(imx8mq_nand_usdhc_sels));
+ clks[IMX8MQ_CLK_VPU_BUS_SRC] = imx_clk_mux2("vpu_bus_src", base + 0x8980, 24, 3, imx8mq_vpu_bus_sels, ARRAY_SIZE(imx8mq_vpu_bus_sels));
+ clks[IMX8MQ_CLK_DISP_AXI_SRC] = imx_clk_mux2("disp_axi_src", base + 0x8a00, 24, 3, imx8mq_disp_axi_sels, ARRAY_SIZE(imx8mq_disp_axi_sels));
+ clks[IMX8MQ_CLK_DISP_APB_SRC] = imx_clk_mux2("disp_apb_src", base + 0x8a80, 24, 3, imx8mq_disp_apb_sels, ARRAY_SIZE(imx8mq_disp_apb_sels));
+ clks[IMX8MQ_CLK_DISP_RTRM_SRC] = imx_clk_mux2("disp_rtrm_src", base + 0x8b00, 24, 3, imx8mq_disp_rtrm_sels, ARRAY_SIZE(imx8mq_disp_rtrm_sels));
+ clks[IMX8MQ_CLK_USB_BUS_SRC] = imx_clk_mux2("usb_bus_src", base + 0x8b80, 24, 3, imx8mq_usb_bus_sels, ARRAY_SIZE(imx8mq_usb_bus_sels));
+ clks[IMX8MQ_CLK_GPU_AXI_SRC] = imx_clk_mux2("gpu_axi_src", base + 0x8c00, 24, 3, imx8mq_gpu_axi_sels, ARRAY_SIZE(imx8mq_gpu_axi_sels));
+ clks[IMX8MQ_CLK_GPU_AHB_SRC] = imx_clk_mux2("gpu_ahb_src", base + 0x8c80, 24, 3, imx8mq_gpu_ahb_sels, ARRAY_SIZE(imx8mq_gpu_ahb_sels));
+ clks[IMX8MQ_CLK_NOC_SRC] = imx_clk_mux2("noc_src", base + 0x8d00, 24, 3, imx8mq_noc_sels, ARRAY_SIZE(imx8mq_noc_sels));
+ clks[IMX8MQ_CLK_NOC_APB_SRC] = imx_clk_mux2("noc_apb_src", base + 0x8d80, 24, 3, imx8mq_noc_apb_sels, ARRAY_SIZE(imx8mq_noc_apb_sels));
+
+ clks[IMX8MQ_CLK_MAIN_AXI_CG] = imx_clk_gate3("main_axi_cg", "main_axi_src", base + 0x8800, 28);
+ clks[IMX8MQ_CLK_ENET_AXI_CG] = imx_clk_gate3("enet_axi_cg", "enet_axi_src", base + 0x8880, 28);
+ clks[IMX8MQ_CLK_NAND_USDHC_BUS_CG] = imx_clk_gate3("nand_usdhc_bus_cg", "nand_usdhc_bus_src", base + 0x8900, 28);
+ clks[IMX8MQ_CLK_VPU_BUS_CG] = imx_clk_gate3("vpu_bus_cg", "vpu_bus_src", base + 0x8980, 28);
+ clks[IMX8MQ_CLK_DISP_AXI_CG] = imx_clk_gate3("disp_axi_cg", "disp_axi_src", base + 0x8a00, 28);
+ clks[IMX8MQ_CLK_DISP_APB_CG] = imx_clk_gate3("disp_apb_cg", "disp_apb_src", base + 0x8a80, 28);
+ clks[IMX8MQ_CLK_DISP_RTRM_CG] = imx_clk_gate3("disp_rtrm_cg", "disp_rtrm_src", base + 0x8b00, 28);
+ clks[IMX8MQ_CLK_USB_BUS_CG] = imx_clk_gate3("usb_bus_cg", "usb_bus_src", base + 0x8b80, 28);
+ clks[IMX8MQ_CLK_GPU_AXI_CG] = imx_clk_gate3("gpu_axi_cg", "gpu_axi_src", base + 0x8c00, 28);
+ clks[IMX8MQ_CLK_GPU_AHB_CG] = imx_clk_gate3("gpu_ahb_cg", "gpu_ahb_src", base + 0x8c80, 28);
+ clks[IMX8MQ_CLK_NOC_CG] = imx_clk_gate3("noc_cg", "noc_src", base + 0x8d00, 28);
+ clks[IMX8MQ_CLK_NOC_APB_CG] = imx_clk_gate3("noc_apb_cg", "noc_apb_src", base + 0x8d80, 28);
+
+ clks[IMX8MQ_CLK_MAIN_AXI_PRE_DIV] = imx_clk_divider2("main_axi_pre_div", "main_axi_cg", base + 0x8800, 16, 3);
+ clks[IMX8MQ_CLK_ENET_AXI_PRE_DIV] = imx_clk_divider2("enet_axi_pre_div", "enet_axi_cg", base + 0x8880, 16, 3);
+ clks[IMX8MQ_CLK_NAND_USDHC_BUS_PRE_DIV] = imx_clk_divider2("nand_usdhc_bus_pre_div", "nand_usdhc_bus_cg", base + 0x8900, 16, 3);
+ clks[IMX8MQ_CLK_VPU_BUS_PRE_DIV] = imx_clk_divider2("vpu_bus_pre_div", "vpu_bus_cg", base + 0x8980, 16, 3);
+ clks[IMX8MQ_CLK_DISP_AXI_PRE_DIV] = imx_clk_divider2("disp_axi_pre_div", "disp_axi_cg", base + 0x8a00, 16, 3);
+ clks[IMX8MQ_CLK_DISP_APB_PRE_DIV] = imx_clk_divider2("disp_apb_pre_div", "disp_apb_cg", base + 0x8a80, 16, 3);
+ clks[IMX8MQ_CLK_DISP_RTRM_PRE_DIV] = imx_clk_divider2("disp_rtrm_pre_div", "disp_rtrm_cg", base + 0x8b00, 16, 3);
+ clks[IMX8MQ_CLK_USB_BUS_PRE_DIV] = imx_clk_divider2("usb_bus_pre_div", "usb_bus_cg", base + 0x8b80, 16, 3);
+ clks[IMX8MQ_CLK_GPU_AXI_PRE_DIV] = imx_clk_divider2("gpu_axi_pre_div", "gpu_axi_cg", base + 0x8c00, 16, 3);
+ clks[IMX8MQ_CLK_GPU_AHB_PRE_DIV] = imx_clk_divider2("gpu_ahb_pre_div", "gpu_ahb_cg", base + 0x8c80, 16, 3);
+ clks[IMX8MQ_CLK_NOC_PRE_DIV] = imx_clk_divider2("noc_pre_div", "noc_cg", base + 0x8d00, 16, 3);
+ clks[IMX8MQ_CLK_NOC_APB_PRE_DIV] = imx_clk_divider2("noc_apb_pre_div", "noc_apb_cg", base + 0x8d80, 16, 3);
+
+ clks[IMX8MQ_CLK_MAIN_AXI_DIV] = imx_clk_divider2("main_axi_div", "main_axi_pre_div", base + 0x8800, 0, 6);
+ clks[IMX8MQ_CLK_ENET_AXI_DIV] = imx_clk_divider2("enet_axi_div", "enet_axi_pre_div", base + 0x8880, 0, 6);
+ clks[IMX8MQ_CLK_NAND_USDHC_BUS_DIV] = imx_clk_divider2("nand_usdhc_bus_div", "nand_usdhc_bus_pre_div", base + 0x8900, 0, 6);
+ clks[IMX8MQ_CLK_VPU_BUS_DIV] = imx_clk_divider_flags("vpu_bus_div", "vpu_bus_pre_div", base + 0x8980, 0, 6, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+ clks[IMX8MQ_CLK_DISP_AXI_DIV] = imx_clk_divider2("disp_axi_div", "disp_axi_pre_div", base + 0x8a00, 0, 6);
+ clks[IMX8MQ_CLK_DISP_APB_DIV] = imx_clk_divider2("disp_apb_div", "disp_apb_pre_div", base + 0x8a80, 0, 6);
+ clks[IMX8MQ_CLK_DISP_RTRM_DIV] = imx_clk_divider2("disp_rtrm_div", "disp_rtrm_pre_div", base + 0x8b00, 0, 6);
+ clks[IMX8MQ_CLK_USB_BUS_DIV] = imx_clk_divider2("usb_bus_div", "usb_bus_pre_div", base + 0x8b80, 0, 6);
+ clks[IMX8MQ_CLK_GPU_AXI_DIV] = imx_clk_divider2("gpu_axi_div", "gpu_axi_pre_div", base + 0x8c00, 0, 6);
+ clks[IMX8MQ_CLK_GPU_AHB_DIV] = imx_clk_divider2("gpu_ahb_div", "gpu_ahb_pre_div", base + 0x8c80, 0, 6);
+ clks[IMX8MQ_CLK_NOC_DIV] = imx_clk_divider2("noc_div", "noc_pre_div", base + 0x8d00, 0, 6);
+ clks[IMX8MQ_CLK_NOC_APB_DIV] = imx_clk_divider2("noc_apb_div", "noc_apb_pre_div", base + 0x8d80, 0, 6);
+
+ /* AHB */
+ clks[IMX8MQ_CLK_AHB_SRC] = imx_clk_mux2("ahb_src", base + 0x9000, 24, 3, imx8mq_ahb_sels, ARRAY_SIZE(imx8mq_ahb_sels));
+ clks[IMX8MQ_CLK_AUDIO_AHB_SRC] = imx_clk_mux2("audio_ahb_src", base + 0x9100, 24, 3, imx8mq_audio_ahb_sels, ARRAY_SIZE(imx8mq_audio_ahb_sels));
+ clks[IMX8MQ_CLK_AHB_CG] = imx_clk_gate3("ahb_cg", "ahb_src", base + 0x9000, 28);
+ clks[IMX8MQ_CLK_AUDIO_AHB_CG] = imx_clk_gate3("audio_ahb_cg", "audio_ahb_src", base + 0x9100, 28);
+ clks[IMX8MQ_CLK_AHB_PRE_DIV] = imx_clk_divider2("ahb_pre_div", "ahb_cg", base + 0x9000, 16, 3);
+ clks[IMX8MQ_CLK_AUDIO_AHB_PRE_DIV] = imx_clk_divider2("audio_ahb_pre_div", "audio_ahb_cg", base + 0x9100, 16, 3);
+ clks[IMX8MQ_CLK_AHB_DIV] = imx_clk_divider_flags("ahb_div", "ahb_pre_div", base + 0x9000, 0, 6, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+ clks[IMX8MQ_CLK_AUDIO_AHB_DIV] = imx_clk_divider2("audio_ahb_div", "audio_ahb_pre_div", base + 0x9100, 0, 6);
+
+ /* IPG */
+ clks[IMX8MQ_CLK_IPG_ROOT] = imx_clk_divider2("ipg_root", "ahb_div", base + 0x9080, 0, 1);
+ clks[IMX8MQ_CLK_IPG_AUDIO_ROOT] = imx_clk_divider2("ipg_audio_root", "audio_ahb_div", base + 0x9180, 0, 1);
+
+ /* IP */
+ clks[IMX8MQ_CLK_DRAM_ALT_SRC] = imx_clk_mux2("dram_alt_src", base + 0xa000, 24, 3, imx8mq_dram_alt_sels, ARRAY_SIZE(imx8mq_dram_alt_sels));
+ clks[IMX8MQ_CLK_DRAM_CORE] = imx_clk_mux2("dram_core_clk", base + 0x9800, 24, 1, imx8mq_dram_core_sels, ARRAY_SIZE(imx8mq_dram_core_sels));
+ clks[IMX8MQ_CLK_DRAM_APB_SRC] = imx_clk_mux2("dram_apb_src", base + 0xa080, 24, 3, imx8mq_dram_apb_sels, ARRAY_SIZE(imx8mq_dram_apb_sels));
+ clks[IMX8MQ_CLK_VPU_G1_SRC] = imx_clk_mux2("vpu_g1_src", base + 0xa100, 24, 3, imx8mq_vpu_g1_sels, ARRAY_SIZE(imx8mq_vpu_g1_sels));
+ clks[IMX8MQ_CLK_VPU_G2_SRC] = imx_clk_mux2("vpu_g2_src", base + 0xa180, 24, 3, imx8mq_vpu_g2_sels, ARRAY_SIZE(imx8mq_vpu_g2_sels));
+ clks[IMX8MQ_CLK_DISP_DTRC_SRC] = imx_clk_mux2("disp_dtrc_src", base + 0xa200, 24, 3, imx8mq_disp_dtrc_sels, ARRAY_SIZE(imx8mq_disp_dtrc_sels));
+ clks[IMX8MQ_CLK_DISP_DC8000_SRC] = imx_clk_mux2("disp_dc8000_src", base + 0xa280, 24, 3, imx8mq_disp_dc8000_sels, ARRAY_SIZE(imx8mq_disp_dc8000_sels));
+ clks[IMX8MQ_CLK_PCIE1_CTRL_SRC] = imx_clk_mux2("pcie1_ctrl_src", base + 0xa300, 24, 3, imx8mq_pcie1_ctrl_sels, ARRAY_SIZE(imx8mq_pcie1_ctrl_sels));
+ clks[IMX8MQ_CLK_PCIE1_PHY_SRC] = imx_clk_mux2("pcie1_phy_src", base + 0xa380, 24, 3, imx8mq_pcie1_phy_sels, ARRAY_SIZE(imx8mq_pcie1_phy_sels));
+ clks[IMX8MQ_CLK_PCIE1_AUX_SRC] = imx_clk_mux2("pcie1_aux_src", base + 0xa400, 24, 3, imx8mq_pcie1_aux_sels, ARRAY_SIZE(imx8mq_pcie1_aux_sels));
+ clks[IMX8MQ_CLK_DC_PIXEL_SRC] = imx_clk_mux2("dc_pixel_src", base + 0xa480, 24, 3, imx8mq_dc_pixel_sels, ARRAY_SIZE(imx8mq_dc_pixel_sels));
+ clks[IMX8MQ_CLK_LCDIF_PIXEL_SRC] = imx_clk_mux2("lcdif_pixel_src", base + 0xa500, 24, 3, imx8mq_lcdif_pixel_sels, ARRAY_SIZE(imx8mq_lcdif_pixel_sels));
+ clks[IMX8MQ_CLK_SAI1_SRC] = imx_clk_mux2("sai1_src", base + 0xa580, 24, 3, imx8mq_sai1_sels, ARRAY_SIZE(imx8mq_sai1_sels));
+ clks[IMX8MQ_CLK_SAI2_SRC] = imx_clk_mux2("sai2_src", base + 0xa600, 24, 3, imx8mq_sai2_sels, ARRAY_SIZE(imx8mq_sai2_sels));
+ clks[IMX8MQ_CLK_SAI3_SRC] = imx_clk_mux2("sai3_src", base + 0xa680, 24, 3, imx8mq_sai3_sels, ARRAY_SIZE(imx8mq_sai3_sels));
+ clks[IMX8MQ_CLK_SAI4_SRC] = imx_clk_mux2("sai4_src", base + 0xa700, 24, 3, imx8mq_sai4_sels, ARRAY_SIZE(imx8mq_sai4_sels));
+ clks[IMX8MQ_CLK_SAI5_SRC] = imx_clk_mux2("sai5_src", base + 0xa780, 24, 3, imx8mq_sai5_sels, ARRAY_SIZE(imx8mq_sai5_sels));
+ clks[IMX8MQ_CLK_SAI6_SRC] = imx_clk_mux2("sai6_src", base + 0xa800, 24, 3, imx8mq_sai6_sels, ARRAY_SIZE(imx8mq_sai6_sels));
+ clks[IMX8MQ_CLK_SPDIF1_SRC] = imx_clk_mux2("spdif1_src", base + 0xa880, 24, 3, imx8mq_spdif1_sels, ARRAY_SIZE(imx8mq_spdif1_sels));
+ clks[IMX8MQ_CLK_SPDIF2_SRC] = imx_clk_mux2("spdif2_src", base + 0xa900, 24, 3, imx8mq_spdif2_sels, ARRAY_SIZE(imx8mq_spdif2_sels));
+ clks[IMX8MQ_CLK_ENET_REF_SRC] = imx_clk_mux2("enet_ref_src", base + 0xa980, 24, 3, imx8mq_enet_ref_sels, ARRAY_SIZE(imx8mq_enet_ref_sels));
+ clks[IMX8MQ_CLK_ENET_TIMER_SRC] = imx_clk_mux2("enet_timer_src", base + 0xaa00, 24, 3, imx8mq_enet_timer_sels, ARRAY_SIZE(imx8mq_enet_timer_sels));
+ clks[IMX8MQ_CLK_ENET_PHY_REF_SRC] = imx_clk_mux2("enet_phy_src", base + 0xaa80, 24, 3, imx8mq_enet_phy_sels, ARRAY_SIZE(imx8mq_enet_phy_sels));
+ clks[IMX8MQ_CLK_NAND_SRC] = imx_clk_mux2("nand_src", base + 0xab00, 24, 3, imx8mq_nand_sels, ARRAY_SIZE(imx8mq_nand_sels));
+ clks[IMX8MQ_CLK_QSPI_SRC] = imx_clk_mux2("qspi_src", base + 0xab80, 24, 3, imx8mq_qspi_sels, ARRAY_SIZE(imx8mq_qspi_sels));
+ clks[IMX8MQ_CLK_USDHC1_SRC] = imx_clk_mux2("usdhc1_src", base + 0xac00, 24, 3, imx8mq_usdhc1_sels, ARRAY_SIZE(imx8mq_usdhc1_sels));
+ clks[IMX8MQ_CLK_USDHC2_SRC] = imx_clk_mux2("usdhc2_src", base + 0xac80, 24, 3, imx8mq_usdhc2_sels, ARRAY_SIZE(imx8mq_usdhc2_sels));
+ clks[IMX8MQ_CLK_I2C1_SRC] = imx_clk_mux2("i2c1_src", base + 0xad00, 24, 3, imx8mq_i2c1_sels, ARRAY_SIZE(imx8mq_i2c1_sels));
+ clks[IMX8MQ_CLK_I2C2_SRC] = imx_clk_mux2("i2c2_src", base + 0xad80, 24, 3, imx8mq_i2c2_sels, ARRAY_SIZE(imx8mq_i2c2_sels));
+ clks[IMX8MQ_CLK_I2C3_SRC] = imx_clk_mux2("i2c3_src", base + 0xae00, 24, 3, imx8mq_i2c3_sels, ARRAY_SIZE(imx8mq_i2c3_sels));
+ clks[IMX8MQ_CLK_I2C4_SRC] = imx_clk_mux2("i2c4_src", base + 0xae80, 24, 3, imx8mq_i2c4_sels, ARRAY_SIZE(imx8mq_i2c4_sels));
+ clks[IMX8MQ_CLK_UART1_SRC] = imx_clk_mux2("uart1_src", base + 0xaf00, 24, 3, imx8mq_uart1_sels, ARRAY_SIZE(imx8mq_uart1_sels));
+ clks[IMX8MQ_CLK_UART2_SRC] = imx_clk_mux2("uart2_src", base + 0xaf80, 24, 3, imx8mq_uart2_sels, ARRAY_SIZE(imx8mq_uart2_sels));
+ clks[IMX8MQ_CLK_UART3_SRC] = imx_clk_mux2("uart3_src", base + 0xb000, 24, 3, imx8mq_uart3_sels, ARRAY_SIZE(imx8mq_uart3_sels));
+ clks[IMX8MQ_CLK_UART4_SRC] = imx_clk_mux2("uart4_src", base + 0xb080, 24, 3, imx8mq_uart4_sels, ARRAY_SIZE(imx8mq_uart4_sels));
+ clks[IMX8MQ_CLK_USB_CORE_REF_SRC] = imx_clk_mux2("usb_core_ref_src", base + 0xb100, 24, 3, imx8mq_usb_core_sels, ARRAY_SIZE(imx8mq_usb_core_sels));
+ clks[IMX8MQ_CLK_USB_PHY_REF_SRC] = imx_clk_mux2("usb_phy_ref_src", base + 0xb180, 24, 3, imx8mq_usb_phy_sels, ARRAY_SIZE(imx8mq_usb_phy_sels));
+ clks[IMX8MQ_CLK_ECSPI1_SRC] = imx_clk_mux2("ecspi1_src", base + 0xb280, 24, 3, imx8mq_ecspi1_sels, ARRAY_SIZE(imx8mq_ecspi1_sels));
+ clks[IMX8MQ_CLK_ECSPI2_SRC] = imx_clk_mux2("ecspi2_src", base + 0xb300, 24, 3, imx8mq_ecspi2_sels, ARRAY_SIZE(imx8mq_ecspi2_sels));
+ clks[IMX8MQ_CLK_PWM1_SRC] = imx_clk_mux2("pwm1_src", base + 0xb380, 24, 3, imx8mq_pwm1_sels, ARRAY_SIZE(imx8mq_pwm1_sels));
+ clks[IMX8MQ_CLK_PWM2_SRC] = imx_clk_mux2("pwm2_src", base + 0xb400, 24, 3, imx8mq_pwm2_sels, ARRAY_SIZE(imx8mq_pwm2_sels));
+ clks[IMX8MQ_CLK_PWM3_SRC] = imx_clk_mux2("pwm3_src", base + 0xb480, 24, 3, imx8mq_pwm3_sels, ARRAY_SIZE(imx8mq_pwm3_sels));
+ clks[IMX8MQ_CLK_PWM4_SRC] = imx_clk_mux2("pwm4_src", base + 0xb500, 24, 3, imx8mq_pwm4_sels, ARRAY_SIZE(imx8mq_pwm4_sels));
+ clks[IMX8MQ_CLK_GPT1_SRC] = imx_clk_mux2("gpt1_src", base + 0xb580, 24, 3, imx8mq_gpt1_sels, ARRAY_SIZE(imx8mq_gpt1_sels));
+ clks[IMX8MQ_CLK_WDOG_SRC] = imx_clk_mux2("wdog_src", base + 0xb900, 24, 3, imx8mq_wdog_sels, ARRAY_SIZE(imx8mq_wdog_sels));
+ clks[IMX8MQ_CLK_WRCLK_SRC] = imx_clk_mux2("wrclk_src", base + 0xb980, 24, 3, imx8mq_wrclk_sels, ARRAY_SIZE(imx8mq_wrclk_sels));
+ clks[IMX8MQ_CLK_CLKO2_SRC] = imx_clk_mux2("clko2_src", base + 0xba80, 24, 3, imx8mq_clko2_sels, ARRAY_SIZE(imx8mq_clko2_sels));
+ clks[IMX8MQ_CLK_DSI_CORE_SRC] = imx_clk_mux2("dsi_core_src", base + 0xbb00, 24, 3, imx8mq_dsi_core_sels, ARRAY_SIZE(imx8mq_dsi_core_sels));
+ clks[IMX8MQ_CLK_DSI_PHY_REF_SRC] = imx_clk_mux2("dsi_phy_ref_src", base + 0xbb80, 24, 3, imx8mq_dsi_phy_sels, ARRAY_SIZE(imx8mq_dsi_phy_sels));
+ clks[IMX8MQ_CLK_DSI_DBI_SRC] = imx_clk_mux2("dsi_dbi_src", base + 0xbc00, 24, 3, imx8mq_dsi_dbi_sels, ARRAY_SIZE(imx8mq_dsi_dbi_sels));
+ clks[IMX8MQ_CLK_DSI_ESC_SRC] = imx_clk_mux2("dsi_esc_src", base + 0xbc80, 24, 3, imx8mq_dsi_esc_sels, ARRAY_SIZE(imx8mq_dsi_esc_sels));
+ clks[IMX8MQ_CLK_DSI_AHB_SRC] = imx_clk_mux2("dsi_ahb_src", base + 0x9200, 24, 3, imx8mq_dsi_ahb_sels, ARRAY_SIZE(imx8mq_dsi_ahb_sels));
+ clks[IMX8MQ_CLK_CSI1_CORE_SRC] = imx_clk_mux2("csi1_core_src", base + 0xbd00, 24, 3, imx8mq_csi1_core_sels, ARRAY_SIZE(imx8mq_csi1_core_sels));
+ clks[IMX8MQ_CLK_CSI1_PHY_REF_SRC] = imx_clk_mux2("csi1_phy_ref_src", base + 0xbd80, 24, 3, imx8mq_csi1_phy_sels, ARRAY_SIZE(imx8mq_csi1_phy_sels));
+ clks[IMX8MQ_CLK_CSI1_ESC_SRC] = imx_clk_mux2("csi1_esc_src", base + 0xbe00, 24, 3, imx8mq_csi1_esc_sels, ARRAY_SIZE(imx8mq_csi1_esc_sels));
+ clks[IMX8MQ_CLK_CSI2_CORE_SRC] = imx_clk_mux2("csi2_core_src", base + 0xbe80, 24, 3, imx8mq_csi2_core_sels, ARRAY_SIZE(imx8mq_csi2_core_sels));
+ clks[IMX8MQ_CLK_CSI2_PHY_REF_SRC] = imx_clk_mux2("csi2_phy_ref_src", base + 0xbf00, 24, 3, imx8mq_csi2_phy_sels, ARRAY_SIZE(imx8mq_csi2_phy_sels));
+ clks[IMX8MQ_CLK_CSI2_ESC_SRC] = imx_clk_mux2("csi2_esc_src", base + 0xbf80, 24, 3, imx8mq_csi2_esc_sels, ARRAY_SIZE(imx8mq_csi2_esc_sels));
+ clks[IMX8MQ_CLK_PCIE2_CTRL_SRC] = imx_clk_mux2("pcie2_ctrl_src", base + 0xc000, 24, 3, imx8mq_pcie2_ctrl_sels, ARRAY_SIZE(imx8mq_pcie2_ctrl_sels));
+ clks[IMX8MQ_CLK_PCIE2_PHY_SRC] = imx_clk_mux2("pcie2_phy_src", base + 0xc080, 24, 3, imx8mq_pcie2_phy_sels, ARRAY_SIZE(imx8mq_pcie2_phy_sels));
+ clks[IMX8MQ_CLK_PCIE2_AUX_SRC] = imx_clk_mux2("pcie2_aux_src", base + 0xc100, 24, 3, imx8mq_pcie2_aux_sels, ARRAY_SIZE(imx8mq_pcie2_aux_sels));
+ clks[IMX8MQ_CLK_ECSPI3_SRC] = imx_clk_mux2("ecspi3_src", base + 0xc180, 24, 3, imx8mq_ecspi3_sels, ARRAY_SIZE(imx8mq_ecspi3_sels));
+
+ clks[IMX8MQ_CLK_DRAM_ALT_CG] = imx_clk_gate3("dram_alt_cg", "dram_alt_src", base + 0xa000, 28);
+ clks[IMX8MQ_CLK_DRAM_APB_CG] = imx_clk_gate3("dram_apb_cg", "dram_apb_src", base + 0xa080, 28);
+ clks[IMX8MQ_CLK_VPU_G1_CG] = imx_clk_gate3("vpu_g1_cg", "vpu_g1_src", base + 0xa100, 28);
+ clks[IMX8MQ_CLK_VPU_G2_CG] = imx_clk_gate3("vpu_g2_cg", "vpu_g2_src", base + 0xa180, 28);
+ clks[IMX8MQ_CLK_DISP_DTRC_CG] = imx_clk_gate3("disp_dtrc_cg", "disp_dtrc_src", base + 0xa200, 28);
+ clks[IMX8MQ_CLK_DISP_DC8000_CG] = imx_clk_gate3("disp_dc8000_cg", "disp_dc8000_src", base + 0xa280, 28);
+ clks[IMX8MQ_CLK_PCIE1_CTRL_CG] = imx_clk_gate3("pcie1_ctrl_cg", "pcie1_ctrl_src", base + 0xa300, 28);
+ clks[IMX8MQ_CLK_PCIE1_PHY_CG] = imx_clk_gate3("pcie1_phy_cg", "pcie1_phy_src", base + 0xa380, 28);
+ clks[IMX8MQ_CLK_PCIE1_AUX_CG] = imx_clk_gate3("pcie1_aux_cg", "pcie1_aux_src", base + 0xa400, 28);
+ clks[IMX8MQ_CLK_DC_PIXEL_CG] = imx_clk_gate3("dc_pixel_cg", "dc_pixel_src", base + 0xa480, 28);
+ clks[IMX8MQ_CLK_LCDIF_PIXEL_CG] = imx_clk_gate3("lcdif_pixel_cg", "lcdif_pixel_src", base + 0xa500, 28);
+ clks[IMX8MQ_CLK_SAI1_CG] = imx_clk_gate3("sai1_cg", "sai1_src", base + 0xa580, 28);
+ clks[IMX8MQ_CLK_SAI2_CG] = imx_clk_gate3("sai2_cg", "sai2_src", base + 0xa600, 28);
+ clks[IMX8MQ_CLK_SAI3_CG] = imx_clk_gate3("sai3_cg", "sai3_src", base + 0xa680, 28);
+ clks[IMX8MQ_CLK_SAI4_CG] = imx_clk_gate3("sai4_cg", "sai4_src", base + 0xa700, 28);
+ clks[IMX8MQ_CLK_SAI5_CG] = imx_clk_gate3("sai5_cg", "sai5_src", base + 0xa780, 28);
+ clks[IMX8MQ_CLK_SAI6_CG] = imx_clk_gate3("sai6_cg", "sai6_src", base + 0xa800, 28);
+ clks[IMX8MQ_CLK_SPDIF1_CG] = imx_clk_gate3("spdif1_cg", "spdif1_src", base + 0xa880, 28);
+ clks[IMX8MQ_CLK_SPDIF2_CG] = imx_clk_gate3("spdif2_cg", "spdif2_src", base + 0xa900, 28);
+ clks[IMX8MQ_CLK_ENET_REF_CG] = imx_clk_gate3("enet_ref_cg", "enet_ref_src", base + 0xa980, 28);
+ clks[IMX8MQ_CLK_ENET_TIMER_CG] = imx_clk_gate3("enet_timer_cg", "enet_timer_src", base + 0xaa00, 28);
+ clks[IMX8MQ_CLK_ENET_PHY_REF_CG] = imx_clk_gate3("enet_phy_cg", "enet_phy_src", base + 0xaa80, 28);
+ clks[IMX8MQ_CLK_NAND_CG] = imx_clk_gate3("nand_cg", "nand_src", base + 0xab00, 28);
+ clks[IMX8MQ_CLK_QSPI_CG] = imx_clk_gate3("qspi_cg", "qspi_src", base + 0xab80, 28);
+ clks[IMX8MQ_CLK_USDHC1_CG] = imx_clk_gate3("usdhc1_cg", "usdhc1_src", base + 0xac00, 28);
+ clks[IMX8MQ_CLK_USDHC2_CG] = imx_clk_gate3("usdhc2_cg", "usdhc2_src", base + 0xac80, 28);
+ clks[IMX8MQ_CLK_I2C1_CG] = imx_clk_gate3("i2c1_cg", "i2c1_src", base + 0xad00, 28);
+ clks[IMX8MQ_CLK_I2C2_CG] = imx_clk_gate3("i2c2_cg", "i2c2_src", base + 0xad80, 28);
+ clks[IMX8MQ_CLK_I2C3_CG] = imx_clk_gate3("i2c3_cg", "i2c3_src", base + 0xae00, 28);
+ clks[IMX8MQ_CLK_I2C4_CG] = imx_clk_gate3("i2c4_cg", "i2c4_src", base + 0xae80, 28);
+ clks[IMX8MQ_CLK_UART1_CG] = imx_clk_gate3("uart1_cg", "uart1_src", base + 0xaf00, 28);
+ clks[IMX8MQ_CLK_UART2_CG] = imx_clk_gate3("uart2_cg", "uart2_src", base + 0xaf80, 28);
+ clks[IMX8MQ_CLK_UART3_CG] = imx_clk_gate3("uart3_cg", "uart3_src", base + 0xb000, 28);
+ clks[IMX8MQ_CLK_UART4_CG] = imx_clk_gate3("uart4_cg", "uart4_src", base + 0xb080, 28);
+ clks[IMX8MQ_CLK_USB_CORE_REF_CG] = imx_clk_gate3("usb_core_ref_cg", "usb_core_ref_src", base + 0xb100, 28);
+ clks[IMX8MQ_CLK_USB_PHY_REF_CG] = imx_clk_gate3("usb_phy_ref_cg", "usb_phy_ref_src", base + 0xb180, 28);
+ clks[IMX8MQ_CLK_ECSPI1_CG] = imx_clk_gate3("ecspi1_cg", "ecspi1_src", base + 0xb280, 28);
+ clks[IMX8MQ_CLK_ECSPI2_CG] = imx_clk_gate3("ecspi2_cg", "ecspi2_src", base + 0xb300, 28);
+ clks[IMX8MQ_CLK_PWM1_CG] = imx_clk_gate3("pwm1_cg", "pwm1_src", base + 0xb380, 28);
+ clks[IMX8MQ_CLK_PWM2_CG] = imx_clk_gate3("pwm2_cg", "pwm2_src", base + 0xb400, 28);
+ clks[IMX8MQ_CLK_PWM3_CG] = imx_clk_gate3("pwm3_cg", "pwm3_src", base + 0xb480, 28);
+ clks[IMX8MQ_CLK_PWM4_CG] = imx_clk_gate3("pwm4_cg", "pwm4_src", base + 0xb500, 28);
+ clks[IMX8MQ_CLK_GPT1_CG] = imx_clk_gate3("gpt1_cg", "gpt1_src", base + 0xb580, 28);
+ clks[IMX8MQ_CLK_WDOG_CG] = imx_clk_gate3("wdog_cg", "wdog_src", base + 0xb900, 28);
+ clks[IMX8MQ_CLK_WRCLK_CG] = imx_clk_gate3("wrclk_cg", "wrclk_src", base + 0xb980, 28);
+ clks[IMX8MQ_CLK_CLKO2_CG] = imx_clk_gate3("clko2_cg", "clko2_src", base + 0xba80, 28);
+ clks[IMX8MQ_CLK_DSI_CORE_CG] = imx_clk_gate3("dsi_core_cg", "dsi_core_src", base + 0xbb00, 28);
+ clks[IMX8MQ_CLK_DSI_PHY_REF_CG] = imx_clk_gate3("dsi_phy_ref_cg", "dsi_phy_ref_src", base + 0xbb80, 28);
+ clks[IMX8MQ_CLK_DSI_DBI_CG] = imx_clk_gate3("dsi_dbi_cg", "dsi_dbi_src", base + 0xbc00, 28);
+ clks[IMX8MQ_CLK_DSI_ESC_CG] = imx_clk_gate3("dsi_esc_cg", "dsi_esc_src", base + 0xbc80, 28);
+ clks[IMX8MQ_CLK_DSI_AHB_CG] = imx_clk_gate3("dsi_ahb_cg", "dsi_ahb_src", base + 0x9200, 28);
+ clks[IMX8MQ_CLK_CSI1_CORE_CG] = imx_clk_gate3("csi1_core_cg", "csi1_core_src", base + 0xbd00, 28);
+ clks[IMX8MQ_CLK_CSI1_PHY_REF_CG] = imx_clk_gate3("csi1_phy_ref_cg", "csi1_phy_ref_src", base + 0xbd80, 28);
+ clks[IMX8MQ_CLK_CSI1_ESC_CG] = imx_clk_gate3("csi1_esc_cg", "csi1_esc_src", base + 0xbe00, 28);
+ clks[IMX8MQ_CLK_CSI2_CORE_CG] = imx_clk_gate3("csi2_core_cg", "csi2_core_src", base + 0xbe80, 28);
+ clks[IMX8MQ_CLK_CSI2_PHY_REF_CG] = imx_clk_gate3("csi2_phy_ref_cg", "csi2_phy_ref_src", base + 0xbf00, 28);
+ clks[IMX8MQ_CLK_CSI2_ESC_CG] = imx_clk_gate3("csi2_esc_cg", "csi2_esc_src", base + 0xbf80, 28);
+ clks[IMX8MQ_CLK_PCIE2_CTRL_CG] = imx_clk_gate3("pcie2_ctrl_cg", "pcie2_ctrl_src", base + 0xc000, 28);
+ clks[IMX8MQ_CLK_PCIE2_PHY_CG] = imx_clk_gate3("pcie2_phy_cg", "pcie2_phy_src", base + 0xc080, 28);
+ clks[IMX8MQ_CLK_PCIE2_AUX_CG] = imx_clk_gate3("pcie2_aux_cg", "pcie2_aux_src", base + 0xc100, 28);
+ clks[IMX8MQ_CLK_ECSPI3_CG] = imx_clk_gate3("ecspi3_cg", "ecspi3_src", base + 0xc180, 28);
+
+ clks[IMX8MQ_CLK_DRAM_ALT_PRE_DIV] = imx_clk_divider2("dram_alt_pre_div", "dram_alt_cg", base + 0xa000, 16, 3);
+ clks[IMX8MQ_CLK_DRAM_APB_PRE_DIV] = imx_clk_divider_flags("dram_apb_pre_div", "dram_apb_cg", base + 0xa080, 16, 3, CLK_OPS_PARENT_ENABLE);
+ clks[IMX8MQ_CLK_VPU_G1_PRE_DIV] = imx_clk_divider_flags("vpu_g1_pre_div", "vpu_g1_cg", base + 0xa100, 16, 3, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+ clks[IMX8MQ_CLK_VPU_G2_PRE_DIV] = imx_clk_divider_flags("vpu_g2_pre_div", "vpu_g2_cg", base + 0xa180, 16, 3, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+ clks[IMX8MQ_CLK_DISP_DTRC_PRE_DIV] = imx_clk_divider2("disp_dtrc_pre_div", "disp_dtrc_cg", base + 0xa200, 16, 3);
+ clks[IMX8MQ_CLK_DISP_DC8000_PRE_DIV] = imx_clk_divider2("disp_dc8000_pre_div", "disp_dc8000_cg", base + 0xa280, 16, 3);
+ clks[IMX8MQ_CLK_PCIE1_CTRL_PRE_DIV] = imx_clk_divider2("pcie1_ctrl_pre_div", "pcie1_ctrl_cg", base + 0xa300, 16, 3);
+ clks[IMX8MQ_CLK_PCIE1_PHY_PRE_DIV] = imx_clk_divider2("pcie1_phy_pre_div", "pcie1_phy_cg", base + 0xa380, 16, 3);
+ clks[IMX8MQ_CLK_PCIE1_AUX_PRE_DIV] = imx_clk_divider2("pcie1_aux_pre_div", "pcie1_aux_cg", base + 0xa400, 16, 3);
+ clks[IMX8MQ_CLK_DC_PIXEL_PRE_DIV] = imx_clk_divider2("dc_pixel_pre_div", "dc_pixel_cg", base + 0xa480, 16, 3);
+ clks[IMX8MQ_CLK_LCDIF_PIXEL_PRE_DIV] = imx_clk_divider2("lcdif_pixel_pre_div", "lcdif_pixel_cg", base + 0xa500, 16, 3);
+ clks[IMX8MQ_CLK_SAI1_PRE_DIV] = imx_clk_divider2("sai1_pre_div", "sai1_cg", base + 0xa580, 16, 3);
+ clks[IMX8MQ_CLK_SAI2_PRE_DIV] = imx_clk_divider2("sai2_pre_div", "sai2_cg", base + 0xa600, 16, 3);
+ clks[IMX8MQ_CLK_SAI3_PRE_DIV] = imx_clk_divider2("sai3_pre_div", "sai3_cg", base + 0xa680, 16, 3);
+ clks[IMX8MQ_CLK_SAI4_PRE_DIV] = imx_clk_divider2("sai4_pre_div", "sai4_cg", base + 0xa700, 16, 3);
+ clks[IMX8MQ_CLK_SAI5_PRE_DIV] = imx_clk_divider2("sai5_pre_div", "sai5_cg", base + 0xa780, 16, 3);
+ clks[IMX8MQ_CLK_SAI6_PRE_DIV] = imx_clk_divider2("sai6_pre_div", "sai6_cg", base + 0xa800, 16, 3);
+ clks[IMX8MQ_CLK_SPDIF1_PRE_DIV] = imx_clk_divider2("spdif1_pre_div", "spdif1_cg", base + 0xa880, 16, 3);
+ clks[IMX8MQ_CLK_SPDIF2_PRE_DIV] = imx_clk_divider2("spdif2_pre_div", "spdif2_cg", base + 0xa900, 16, 3);
+ clks[IMX8MQ_CLK_ENET_REF_PRE_DIV] = imx_clk_divider2("enet_ref_pre_div", "enet_ref_cg", base + 0xa980, 16, 3);
+ clks[IMX8MQ_CLK_ENET_TIMER_PRE_DIV] = imx_clk_divider2("enet_timer_pre_div", "enet_timer_cg", base + 0xaa00, 16, 3);
+ clks[IMX8MQ_CLK_ENET_PHY_REF_PRE_DIV] = imx_clk_divider2("enet_phy_pre_div", "enet_phy_cg", base + 0xaa80, 16, 3);
+ clks[IMX8MQ_CLK_NAND_PRE_DIV] = imx_clk_divider2("nand_pre_div", "nand_cg", base + 0xab00, 16, 3);
+ clks[IMX8MQ_CLK_QSPI_PRE_DIV] = imx_clk_divider2("qspi_pre_div", "qspi_cg", base + 0xab80, 16, 3);
+ clks[IMX8MQ_CLK_USDHC1_PRE_DIV] = imx_clk_divider2("usdhc1_pre_div", "usdhc1_cg", base + 0xac00, 16, 3);
+ clks[IMX8MQ_CLK_USDHC2_PRE_DIV] = imx_clk_divider2("usdhc2_pre_div", "usdhc2_cg", base + 0xac80, 16, 3);
+ clks[IMX8MQ_CLK_I2C1_PRE_DIV] = imx_clk_divider2("i2c1_pre_div", "i2c1_cg", base + 0xad00, 16, 3);
+ clks[IMX8MQ_CLK_I2C2_PRE_DIV] = imx_clk_divider2("i2c2_pre_div", "i2c2_cg", base + 0xad80, 16, 3);
+ clks[IMX8MQ_CLK_I2C3_PRE_DIV] = imx_clk_divider2("i2c3_pre_div", "i2c3_cg", base + 0xae00, 16, 3);
+ clks[IMX8MQ_CLK_I2C4_PRE_DIV] = imx_clk_divider2("i2c4_pre_div", "i2c4_cg", base + 0xae80, 16, 3);
+ clks[IMX8MQ_CLK_UART1_PRE_DIV] = imx_clk_divider2("uart1_pre_div", "uart1_cg", base + 0xaf00, 16, 3);
+ clks[IMX8MQ_CLK_UART2_PRE_DIV] = imx_clk_divider2("uart2_pre_div", "uart2_cg", base + 0xaf80, 16, 3);
+ clks[IMX8MQ_CLK_UART3_PRE_DIV] = imx_clk_divider2("uart3_pre_div", "uart3_cg", base + 0xb000, 16, 3);
+ clks[IMX8MQ_CLK_UART4_PRE_DIV] = imx_clk_divider2("uart4_pre_div", "uart4_cg", base + 0xb080, 16, 3);
+ clks[IMX8MQ_CLK_USB_CORE_REF_PRE_DIV] = imx_clk_divider2("usb_core_ref_pre_div", "usb_core_ref_cg", base + 0xb100, 16, 3);
+ clks[IMX8MQ_CLK_USB_PHY_REF_PRE_DIV] = imx_clk_divider2("usb_phy_ref_pre_div", "usb_phy_ref_cg", base + 0xb180, 16, 3);
+ clks[IMX8MQ_CLK_ECSPI1_PRE_DIV] = imx_clk_divider2("ecspi1_pre_div", "ecspi1_cg", base + 0xb280, 16, 3);
+ clks[IMX8MQ_CLK_ECSPI2_PRE_DIV] = imx_clk_divider2("ecspi2_pre_div", "ecspi2_cg", base + 0xb300, 16, 3);
+ clks[IMX8MQ_CLK_PWM1_PRE_DIV] = imx_clk_divider2("pwm1_pre_div", "pwm1_cg", base + 0xb380, 16, 3);
+ clks[IMX8MQ_CLK_PWM2_PRE_DIV] = imx_clk_divider2("pwm2_pre_div", "pwm2_cg", base + 0xb400, 16, 3);
+ clks[IMX8MQ_CLK_PWM3_PRE_DIV] = imx_clk_divider2("pwm3_pre_div", "pwm3_cg", base + 0xb480, 16, 3);
+ clks[IMX8MQ_CLK_PWM4_PRE_DIV] = imx_clk_divider2("pwm4_pre_div", "pwm4_cg", base + 0xb500, 16, 3);
+ clks[IMX8MQ_CLK_GPT1_PRE_DIV] = imx_clk_divider2("gpt1_pre_div", "gpt1_cg", base + 0xb580, 16, 3);
+ clks[IMX8MQ_CLK_WDOG_PRE_DIV] = imx_clk_divider2("wdog_pre_div", "wdog_cg", base + 0xb900, 16, 3);
+ clks[IMX8MQ_CLK_WRCLK_PRE_DIV] = imx_clk_divider2("wrclk_pre_div", "wrclk_cg", base + 0xb980, 16, 3);
+ clks[IMX8MQ_CLK_CLKO2_PRE_DIV] = imx_clk_divider2("clko2_pre_div", "clko2_cg", base + 0xba80, 16, 3);
+ clks[IMX8MQ_CLK_DSI_CORE_PRE_DIV] = imx_clk_divider2("dsi_core_pre_div", "dsi_core_cg", base + 0xbb00, 16, 3);
+ clks[IMX8MQ_CLK_DSI_PHY_REF_PRE_DIV] = imx_clk_divider2("dsi_phy_ref_pre_div", "dsi_phy_ref_cg", base + 0xbb80, 16, 3);
+ clks[IMX8MQ_CLK_DSI_DBI_PRE_DIV] = imx_clk_divider2("dsi_dbi_pre_div", "dsi_dbi_cg", base + 0xbc00, 16, 3);
+ clks[IMX8MQ_CLK_DSI_ESC_PRE_DIV] = imx_clk_divider2("dsi_esc_pre_div", "dsi_esc_cg", base + 0xbc80, 16, 3);
+ clks[IMX8MQ_CLK_DSI_AHB_PRE_DIV] = imx_clk_divider2("dsi_ahb_pre_div", "dsi_ahb_cg", base + 0x9200, 16, 3);
+ clks[IMX8MQ_CLK_CSI1_CORE_PRE_DIV] = imx_clk_divider2("csi1_core_pre_div", "csi1_core_cg", base + 0xbd00, 16, 3);
+ clks[IMX8MQ_CLK_CSI1_PHY_REF_PRE_DIV] = imx_clk_divider2("csi1_phy_ref_pre_div", "csi1_phy_ref_cg", base + 0xbd80, 16, 3);
+ clks[IMX8MQ_CLK_CSI1_ESC_PRE_DIV] = imx_clk_divider2("csi1_esc_pre_div", "csi1_esc_cg", base + 0xbe00, 16, 3);
+ clks[IMX8MQ_CLK_CSI2_CORE_PRE_DIV] = imx_clk_divider2("csi2_core_pre_div", "csi2_core_cg", base + 0xbe80, 16, 3);
+ clks[IMX8MQ_CLK_CSI2_PHY_REF_PRE_DIV] = imx_clk_divider2("csi2_phy_ref_pre_div", "csi2_phy_ref_cg", base + 0xbf00, 16, 3);
+ clks[IMX8MQ_CLK_CSI2_ESC_PRE_DIV] = imx_clk_divider2("csi2_esc_pre_div", "csi2_esc_cg", base + 0xbf80, 16, 3);
+ clks[IMX8MQ_CLK_PCIE2_CTRL_PRE_DIV] = imx_clk_divider2("pcie2_ctrl_pre_div", "pcie2_ctrl_cg", base + 0xc000, 16, 3);
+ clks[IMX8MQ_CLK_PCIE2_PHY_PRE_DIV] = imx_clk_divider2("pcie2_phy_pre_div", "pcie2_phy_cg", base + 0xc080, 16, 3);
+ clks[IMX8MQ_CLK_PCIE2_AUX_PRE_DIV] = imx_clk_divider2("pcie2_aux_pre_div", "pcie2_aux_cg", base + 0xc100, 16, 3);
+ clks[IMX8MQ_CLK_ECSPI3_PRE_DIV] = imx_clk_divider2("ecspi3_pre_div", "ecspi3_cg", base + 0xc180, 16, 3);
+
+ clks[IMX8MQ_CLK_DRAM_ALT_DIV] = imx_clk_divider2("dram_alt_div", "dram_alt_pre_div", base + 0xa000, 0, 6);
+ clks[IMX8MQ_CLK_DRAM_APB_DIV] = imx_clk_divider2("dram_apb_div", "dram_apb_pre_div", base + 0xa080, 0, 6);
+ clks[IMX8MQ_CLK_VPU_G1_DIV] = imx_clk_divider_flags("vpu_g1_div", "vpu_g1_pre_div", base + 0xa100, 0, 6, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+ clks[IMX8MQ_CLK_VPU_G2_DIV] = imx_clk_divider_flags("vpu_g2_div", "vpu_g2_pre_div", base + 0xa180, 0, 6, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+ clks[IMX8MQ_CLK_DISP_DTRC_DIV] = imx_clk_divider2("disp_dtrc_div", "disp_dtrc_pre_div", base + 0xa200, 0, 6);
+ clks[IMX8MQ_CLK_DISP_DC8000_DIV] = imx_clk_divider2("disp_dc8000_div", "disp_dc8000_pre_div", base + 0xa280, 0, 6);
+ clks[IMX8MQ_CLK_PCIE1_CTRL_DIV] = imx_clk_divider2("pcie1_ctrl_div", "pcie1_ctrl_pre_div", base + 0xa300, 0, 6);
+ clks[IMX8MQ_CLK_PCIE1_PHY_DIV] = imx_clk_divider2("pcie1_phy_div", "pcie1_phy_pre_div", base + 0xa380, 0, 6);
+ clks[IMX8MQ_CLK_PCIE1_AUX_DIV] = imx_clk_divider2("pcie1_aux_div", "pcie1_aux_pre_div", base + 0xa400, 0, 6);
+ clks[IMX8MQ_CLK_DC_PIXEL_DIV] = imx_clk_divider2("dc_pixel_div", "dc_pixel_pre_div", base + 0xa480, 0, 6);
+ clks[IMX8MQ_CLK_LCDIF_PIXEL_DIV] = imx_clk_divider2("lcdif_pixel_div", "lcdif_pixel_pre_div", base + 0xa500, 0, 6);
+ clks[IMX8MQ_CLK_SAI1_DIV] = imx_clk_divider2("sai1_div", "sai1_pre_div", base + 0xa580, 0, 6);
+ clks[IMX8MQ_CLK_SAI2_DIV] = imx_clk_divider2("sai2_div", "sai2_pre_div", base + 0xa600, 0, 6);
+ clks[IMX8MQ_CLK_SAI3_DIV] = imx_clk_divider2("sai3_div", "sai3_pre_div", base + 0xa680, 0, 6);
+ clks[IMX8MQ_CLK_SAI4_DIV] = imx_clk_divider2("sai4_div", "sai4_pre_div", base + 0xa700, 0, 6);
+ clks[IMX8MQ_CLK_SAI5_DIV] = imx_clk_divider2("sai5_div", "sai5_pre_div", base + 0xa780, 0, 6);
+ clks[IMX8MQ_CLK_SAI6_DIV] = imx_clk_divider2("sai6_div", "sai6_pre_div", base + 0xa800, 0, 6);
+ clks[IMX8MQ_CLK_SPDIF1_DIV] = imx_clk_divider2("spdif1_div", "spdif1_pre_div", base + 0xa880, 0, 6);
+ clks[IMX8MQ_CLK_SPDIF2_DIV] = imx_clk_divider2("spdif2_div", "spdif2_pre_div", base + 0xa900, 0, 6);
+ clks[IMX8MQ_CLK_ENET_REF_DIV] = imx_clk_divider2("enet_ref_div", "enet_ref_pre_div", base + 0xa980, 0, 6);
+ clks[IMX8MQ_CLK_ENET_TIMER_DIV] = imx_clk_divider2("enet_timer_div", "enet_timer_pre_div", base + 0xaa00, 0, 6);
+ clks[IMX8MQ_CLK_ENET_PHY_REF_DIV] = imx_clk_divider2("enet_phy_div", "enet_phy_pre_div", base + 0xaa80, 0, 6);
+ clks[IMX8MQ_CLK_NAND_DIV] = imx_clk_divider2("nand_div", "nand_pre_div", base + 0xab00, 0, 6);
+ clks[IMX8MQ_CLK_QSPI_DIV] = imx_clk_divider2("qspi_div", "qspi_pre_div", base + 0xab80, 0, 6);
+ clks[IMX8MQ_CLK_USDHC1_DIV] = imx_clk_divider2("usdhc1_div", "usdhc1_pre_div", base + 0xac00, 0, 6);
+ clks[IMX8MQ_CLK_USDHC2_DIV] = imx_clk_divider2("usdhc2_div", "usdhc2_pre_div", base + 0xac80, 0, 6);
+ clks[IMX8MQ_CLK_I2C1_DIV] = imx_clk_divider2("i2c1_div", "i2c1_pre_div", base + 0xad00, 0, 6);
+ clks[IMX8MQ_CLK_I2C2_DIV] = imx_clk_divider2("i2c2_div", "i2c2_pre_div", base + 0xad80, 0, 6);
+ clks[IMX8MQ_CLK_I2C3_DIV] = imx_clk_divider2("i2c3_div", "i2c3_pre_div", base + 0xae00, 0, 6);
+ clks[IMX8MQ_CLK_I2C4_DIV] = imx_clk_divider2("i2c4_div", "i2c4_pre_div", base + 0xae80, 0, 6);
+ clks[IMX8MQ_CLK_UART1_DIV] = imx_clk_divider2("uart1_div", "uart1_pre_div", base + 0xaf00, 0, 6);
+ clks[IMX8MQ_CLK_UART2_DIV] = imx_clk_divider2("uart2_div", "uart2_pre_div", base + 0xaf80, 0, 6);
+ clks[IMX8MQ_CLK_UART3_DIV] = imx_clk_divider2("uart3_div", "uart3_pre_div", base + 0xb000, 0, 6);
+ clks[IMX8MQ_CLK_UART4_DIV] = imx_clk_divider2("uart4_div", "uart4_pre_div", base + 0xb080, 0, 6);
+ clks[IMX8MQ_CLK_USB_CORE_REF_DIV] = imx_clk_divider2("usb_core_ref_div", "usb_core_ref_pre_div", base + 0xb100, 0, 6);
+ clks[IMX8MQ_CLK_USB_PHY_REF_DIV] = imx_clk_divider2("usb_phy_ref_div", "usb_phy_ref_pre_div", base + 0xb180, 0, 6);
+ clks[IMX8MQ_CLK_ECSPI1_DIV] = imx_clk_divider2("ecspi1_div", "ecspi1_pre_div", base + 0xb280, 0, 6);
+ clks[IMX8MQ_CLK_ECSPI2_DIV] = imx_clk_divider2("ecspi2_div", "ecspi2_pre_div", base + 0xb300, 0, 6);
+ clks[IMX8MQ_CLK_PWM1_DIV] = imx_clk_divider2("pwm1_div", "pwm1_pre_div", base + 0xb380, 0, 6);
+ clks[IMX8MQ_CLK_PWM2_DIV] = imx_clk_divider2("pwm2_div", "pwm2_pre_div", base + 0xb400, 0, 6);
+ clks[IMX8MQ_CLK_PWM3_DIV] = imx_clk_divider2("pwm3_div", "pwm3_pre_div", base + 0xb480, 0, 6);
+ clks[IMX8MQ_CLK_PWM4_DIV] = imx_clk_divider2("pwm4_div", "pwm4_pre_div", base + 0xb500, 0, 6);
+ clks[IMX8MQ_CLK_GPT1_DIV] = imx_clk_divider2("gpt1_div", "gpt1_pre_div", base + 0xb580, 0, 6);
+ clks[IMX8MQ_CLK_WDOG_DIV] = imx_clk_divider2("wdog_div", "wdog_pre_div", base + 0xb900, 0, 6);
+ clks[IMX8MQ_CLK_WRCLK_DIV] = imx_clk_divider2("wrclk_div", "wrclk_pre_div", base + 0xb980, 0, 6);
+ clks[IMX8MQ_CLK_CLKO2_DIV] = imx_clk_divider2("clko2_div", "clko2_pre_div", base + 0xba80, 0, 6);
+ clks[IMX8MQ_CLK_DSI_CORE_DIV] = imx_clk_divider2("dsi_core_div", "dsi_core_pre_div", base + 0xbb00, 0, 6);
+ clks[IMX8MQ_CLK_DSI_PHY_REF_DIV] = imx_clk_divider2("dsi_phy_ref_div", "dsi_phy_ref_pre_div", base + 0xbb80, 0, 6);
+ clks[IMX8MQ_CLK_DSI_DBI_DIV] = imx_clk_divider2("dsi_dbi_div", "dsi_dbi_pre_div", base + 0xbc00, 0, 6);
+ clks[IMX8MQ_CLK_DSI_ESC_DIV] = imx_clk_divider2("dsi_esc_div", "dsi_esc_pre_div", base + 0xbc80, 0, 6);
+ clks[IMX8MQ_CLK_DSI_AHB_DIV] = imx_clk_divider2("dsi_ahb_div", "dsi_ahb_pre_div", base + 0x9200, 0, 6);
+ clks[IMX8MQ_CLK_DSI_IPG_DIV] = imx_clk_divider2("dsi_ipg_div", "dsi_ahb_div", base + 0x9280, 0, 6);
+ clks[IMX8MQ_CLK_CSI1_CORE_DIV] = imx_clk_divider2("csi1_core_div", "csi1_core_pre_div", base + 0xbd00, 0, 6);
+ clks[IMX8MQ_CLK_CSI1_PHY_REF_DIV] = imx_clk_divider2("csi1_phy_ref_div", "csi1_phy_ref_pre_div", base + 0xbd80, 0, 6);
+ clks[IMX8MQ_CLK_CSI1_ESC_DIV] = imx_clk_divider2("csi1_esc_div", "csi1_esc_pre_div", base + 0xbe00, 0, 6);
+ clks[IMX8MQ_CLK_CSI2_CORE_DIV] = imx_clk_divider2("csi2_core_div", "csi2_core_pre_div", base + 0xbe80, 0, 6);
+ clks[IMX8MQ_CLK_CSI2_PHY_REF_DIV] = imx_clk_divider2("csi2_phy_ref_div", "csi2_phy_ref_pre_div", base + 0xbf00, 0, 6);
+ clks[IMX8MQ_CLK_CSI2_ESC_DIV] = imx_clk_divider2("csi2_esc_div", "csi2_esc_pre_div", base + 0xbf80, 0, 6);
+ clks[IMX8MQ_CLK_PCIE2_CTRL_DIV] = imx_clk_divider2("pcie2_ctrl_div", "pcie2_ctrl_pre_div", base + 0xc000, 0, 6);
+ clks[IMX8MQ_CLK_PCIE2_PHY_DIV] = imx_clk_divider2("pcie2_phy_div", "pcie2_phy_pre_div", base + 0xc080, 0, 6);
+ clks[IMX8MQ_CLK_PCIE2_AUX_DIV] = imx_clk_divider2("pcie2_aux_div", "pcie2_aux_pre_div", base + 0xc100, 0, 6);
+ clks[IMX8MQ_CLK_ECSPI3_DIV] = imx_clk_divider2("ecspi3_div", "ecspi3_pre_div", base + 0xc180, 0, 6);
+
+ /*FIXME, the doc is not ready now */
+ clks[IMX8MQ_CLK_ECSPI1_ROOT] = imx_clk_gate4("ecspi1_root_clk", "ecspi1_div", base + 0x4070, 0);
+ clks[IMX8MQ_CLK_ECSPI2_ROOT] = imx_clk_gate4("ecspi2_root_clk", "ecspi2_div", base + 0x4080, 0);
+ clks[IMX8MQ_CLK_ECSPI3_ROOT] = imx_clk_gate4("ecspi3_root_clk", "ecspi3_div", base + 0x4090, 0);
+ clks[IMX8MQ_CLK_ENET1_ROOT] = imx_clk_gate4("enet1_root_clk", "enet_axi_div", base + 0x40a0, 0);
+ clks[IMX8MQ_CLK_GPT1_ROOT] = imx_clk_gate4("gpt1_root_clk", "gpt1_div", base + 0x4100, 0);
+ clks[IMX8MQ_CLK_I2C1_ROOT] = imx_clk_gate4("i2c1_root_clk", "i2c1_div", base + 0x4170, 0);
+ clks[IMX8MQ_CLK_I2C2_ROOT] = imx_clk_gate4("i2c2_root_clk", "i2c2_div", base + 0x4180, 0);
+ clks[IMX8MQ_CLK_I2C3_ROOT] = imx_clk_gate4("i2c3_root_clk", "i2c3_div", base + 0x4190, 0);
+ clks[IMX8MQ_CLK_I2C4_ROOT] = imx_clk_gate4("i2c4_root_clk", "i2c4_div", base + 0x41a0, 0);
+ clks[IMX8MQ_CLK_MU_ROOT] = imx_clk_gate4("mu_root_clk", "ipg_root", base + 0x4210, 0);
+ clks[IMX8MQ_CLK_OCOTP_ROOT] = imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0);
+ clks[IMX8MQ_CLK_PCIE1_ROOT] = imx_clk_gate4("pcie1_root_clk", "pcie1_ctrl_div", base + 0x4250, 0);
+ clks[IMX8MQ_CLK_PCIE2_ROOT] = imx_clk_gate4("pcie2_root_clk", "pcie2_ctrl_div", base + 0x4640, 0);
+ clks[IMX8MQ_CLK_PWM1_ROOT] = imx_clk_gate4("pwm1_root_clk", "pwm1_div", base + 0x4280, 0);
+ clks[IMX8MQ_CLK_PWM2_ROOT] = imx_clk_gate4("pwm2_root_clk", "pwm2_div", base + 0x4290, 0);
+ clks[IMX8MQ_CLK_PWM3_ROOT] = imx_clk_gate4("pwm3_root_clk", "pwm3_div", base + 0x42a0, 0);
+ clks[IMX8MQ_CLK_PWM4_ROOT] = imx_clk_gate4("pwm4_root_clk", "pwm4_div", base + 0x42b0, 0);
+ clks[IMX8MQ_CLK_QSPI_ROOT] = imx_clk_gate4("qspi_root_clk", "qspi_div", base + 0x42f0, 0);
+ clks[IMX8MQ_CLK_RAWNAND_ROOT] = imx_clk_gate2_shared2("nand_root_clk", "nand_div", base + 0x4300, 0, &share_count_nand);
+ clks[IMX8MQ_CLK_NAND_USDHC_BUS_RAWNAND_CLK] = imx_clk_gate2_shared2("nand_usdhc_rawnand_clk", "nand_usdhc_bus_div", base + 0x4300, 0, &share_count_nand);
+ clks[IMX8MQ_CLK_SAI1_ROOT] = imx_clk_gate2_shared2("sai1_root_clk", "sai1_div", base + 0x4330, 0, &share_count_sai1);
+ clks[IMX8MQ_CLK_SAI1_IPG] = imx_clk_gate2_shared2("sai1_ipg_clk", "ipg_audio_root", base + 0x4330, 0, &share_count_sai1);
+ clks[IMX8MQ_CLK_SAI2_ROOT] = imx_clk_gate2_shared2("sai2_root_clk", "sai2_div", base + 0x4340, 0, &share_count_sai2);
+ clks[IMX8MQ_CLK_SAI2_IPG] = imx_clk_gate2_shared2("sai2_ipg_clk", "ipg_root", base + 0x4340, 0, &share_count_sai2);
+ clks[IMX8MQ_CLK_SAI3_ROOT] = imx_clk_gate2_shared2("sai3_root_clk", "sai3_div", base + 0x4350, 0, &share_count_sai3);
+ clks[IMX8MQ_CLK_SAI3_IPG] = imx_clk_gate2_shared2("sai3_ipg_clk", "ipg_root", base + 0x4350, 0, &share_count_sai3);
+ clks[IMX8MQ_CLK_SAI4_ROOT] = imx_clk_gate2_shared2("sai4_root_clk", "sai4_div", base + 0x4360, 0, &share_count_sai4);
+ clks[IMX8MQ_CLK_SAI4_IPG] = imx_clk_gate2_shared2("sai4_ipg_clk", "ipg_audio_root", base + 0x4360, 0, &share_count_sai4);
+ clks[IMX8MQ_CLK_SAI5_ROOT] = imx_clk_gate2_shared2("sai5_root_clk", "sai5_div", base + 0x4370, 0, &share_count_sai5);
+ clks[IMX8MQ_CLK_SAI5_IPG] = imx_clk_gate2_shared2("sai5_ipg_clk", "ipg_audio_root", base + 0x4370, 0, &share_count_sai5);
+ clks[IMX8MQ_CLK_SAI6_ROOT] = imx_clk_gate2_shared2("sai6_root_clk", "sai6_div", base + 0x4380, 0, &share_count_sai6);
+ clks[IMX8MQ_CLK_SAI6_IPG] = imx_clk_gate2_shared2("sai6_ipg_clk", "ipg_audio_root", base + 0x4380, 0, &share_count_sai6);
+ clks[IMX8MQ_CLK_UART1_ROOT] = imx_clk_gate4("uart1_root_clk", "uart1_div", base + 0x4490, 0);
+ clks[IMX8MQ_CLK_UART2_ROOT] = imx_clk_gate4("uart2_root_clk", "uart2_div", base + 0x44a0, 0);
+ clks[IMX8MQ_CLK_UART3_ROOT] = imx_clk_gate4("uart3_root_clk", "uart3_div", base + 0x44b0, 0);
+ clks[IMX8MQ_CLK_UART4_ROOT] = imx_clk_gate4("uart4_root_clk", "uart4_div", base + 0x44c0, 0);
+ clks[IMX8MQ_CLK_USB1_CTRL_ROOT] = imx_clk_gate4("usb1_ctrl_root_clk", "usb_core_ref_div", base + 0x44d0, 0);
+ clks[IMX8MQ_CLK_USB2_CTRL_ROOT] = imx_clk_gate4("usb2_ctrl_root_clk", "usb_core_ref_div", base + 0x44e0, 0);
+ clks[IMX8MQ_CLK_USB1_PHY_ROOT] = imx_clk_gate4("usb1_phy_root_clk", "usb_phy_ref_div", base + 0x44f0, 0);
+ clks[IMX8MQ_CLK_USB2_PHY_ROOT] = imx_clk_gate4("usb2_phy_root_clk", "usb_phy_ref_div", base + 0x4500, 0);
+ clks[IMX8MQ_CLK_USDHC1_ROOT] = imx_clk_gate4("usdhc1_root_clk", "usdhc1_div", base + 0x4510, 0);
+ clks[IMX8MQ_CLK_USDHC2_ROOT] = imx_clk_gate4("usdhc2_root_clk", "usdhc2_div", base + 0x4520, 0);
+ clks[IMX8MQ_CLK_WDOG1_ROOT] = imx_clk_gate4("wdog1_root_clk", "wdog_div", base + 0x4530, 0);
+ clks[IMX8MQ_CLK_WDOG2_ROOT] = imx_clk_gate4("wdog2_root_clk", "wdog_div", base + 0x4540, 0);
+ clks[IMX8MQ_CLK_WDOG3_ROOT] = imx_clk_gate4("wdog3_root_clk", "wdog_div", base + 0x4550, 0);
+ clks[IMX8MQ_CLK_VPU_G1_ROOT] = imx_clk_gate2_flags("vpu_g1_root_clk", "vpu_g1_div", base + 0x4560, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+ clks[IMX8MQ_CLK_GPU_ROOT] = imx_clk_gate4("gpu_root_clk", "gpu_core_div", base + 0x4570, 0);
+ clks[IMX8MQ_CLK_VPU_G2_ROOT] = imx_clk_gate2_flags("vpu_g2_root_clk", "vpu_g2_div", base + 0x45a0, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+ clks[IMX8MQ_CLK_DISP_ROOT] = imx_clk_gate2_shared2("disp_root_clk", "disp_dc8000_div", base + 0x45d0, 0, &share_count_dcss);
+ clks[IMX8MQ_CLK_DISP_AXI_ROOT] = imx_clk_gate2_shared2("disp_axi_root_clk", "disp_axi_div", base + 0x45d0, 0, &share_count_dcss);
+ clks[IMX8MQ_CLK_DISP_APB_ROOT] = imx_clk_gate2_shared2("disp_apb_root_clk", "disp_apb_div", base + 0x45d0, 0, &share_count_dcss);
+ clks[IMX8MQ_CLK_DISP_RTRM_ROOT] = imx_clk_gate2_shared2("disp_rtrm_root_clk", "disp_rtrm_div", base + 0x45d0, 0, &share_count_dcss);
+ clks[IMX8MQ_CLK_TMU_ROOT] = imx_clk_gate4("tmu_root_clk", "ipg_root", base + 0x4620, 0);
+ clks[IMX8MQ_CLK_VPU_DEC_ROOT] = imx_clk_gate2_flags("vpu_dec_root_clk", "vpu_bus_div", base + 0x4630, 0, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
+ clks[IMX8MQ_CLK_CSI1_ROOT] = imx_clk_gate4("csi1_root_clk", "csi1_core_div", base + 0x4650, 0);
+ clks[IMX8MQ_CLK_CSI2_ROOT] = imx_clk_gate4("csi2_root_clk", "csi2_core_div", base + 0x4660, 0);
+ clks[IMX8MQ_CLK_SDMA1_ROOT] = imx_clk_gate4("sdma1_clk", "ipg_root", base + 0x43a0, 0);
+ clks[IMX8MQ_CLK_SDMA2_ROOT] = imx_clk_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0);
+
+ clks[IMX8MQ_GPT_3M_CLK] = imx_clk_fixed_factor("gpt_3m", "osc_25m", 1, 8);
+ clks[IMX8MQ_CLK_DRAM_ALT_ROOT] = imx_clk_fixed_factor("dram_alt_root", "dram_alt_div", 1, 4);
+
+ for (i = 0; i < IMX8MQ_CLK_END; i++)
+ if (IS_ERR(clks[i]))
+ pr_err("i.MX8mq clk %u register failed with %ld\n",
+ i, PTR_ERR(clks[i]));
+
+ clk_data.clks = clks;
+ clk_data.clk_num = ARRAY_SIZE(clks);
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+
+ /* enable all the clocks just for bringup */
+ if (imx_clk_init_on(ccm_node, clks)) {
+ for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
+ clk_prepare_enable(clks[clks_init_on[i]]);
+ }
+
+ clk_set_parent(clks[IMX8MQ_VIDEO2_PLL1_OUT], clks[IMX8MQ_VIDEO2_PLL1]);
+ clk_set_parent(clks[IMX8MQ_VIDEO2_PLL2_OUT], clks[IMX8MQ_VIDEO2_PLL2_DIV]);
+
+ clk_set_parent(clks[IMX8MQ_CLK_AHB_SRC], clks[IMX8MQ_SYS1_PLL_133M]);
+ clk_set_parent(clks[IMX8MQ_CLK_NAND_USDHC_BUS_SRC], clks[IMX8MQ_SYS1_PLL_266M]);
+ clk_set_parent(clks[IMX8MQ_CLK_AUDIO_AHB_SRC], clks[IMX8MQ_SYS2_PLL_500M]);
+
+ /* config video_pll1 clock */
+ clk_set_parent(clks[IMX8MQ_VIDEO_PLL1_REF_SEL], clks[IMX8MQ_CLK_27M]);
+ clk_set_rate(clks[IMX8MQ_VIDEO_PLL1], 593999999);
+
+ /* increase NOC clock to achieve best DDR access performance */
+ clk_set_rate(clks[IMX8MQ_CLK_NOC_DIV], clk_get_rate(clks[IMX8MQ_SYS1_PLL_800M]));
+
+ /* set pcie root's parent clk source */
+ clk_set_parent(clks[IMX8MQ_CLK_PCIE1_CTRL_SRC], clks[IMX8MQ_SYS2_PLL_250M]);
+ clk_set_parent(clks[IMX8MQ_CLK_PCIE1_PHY_SRC], clks[IMX8MQ_SYS2_PLL_100M]);
+ clk_set_parent(clks[IMX8MQ_CLK_PCIE2_CTRL_SRC], clks[IMX8MQ_SYS2_PLL_250M]);
+ clk_set_parent(clks[IMX8MQ_CLK_PCIE2_PHY_SRC], clks[IMX8MQ_SYS2_PLL_100M]);
+
+ clk_set_parent(clks[IMX8MQ_CLK_CSI1_CORE_SRC], clks[IMX8MQ_SYS1_PLL_266M]);
+ clk_set_parent(clks[IMX8MQ_CLK_CSI1_PHY_REF_SRC], clks[IMX8MQ_SYS2_PLL_1000M]);
+ clk_set_parent(clks[IMX8MQ_CLK_CSI1_ESC_SRC], clks[IMX8MQ_SYS1_PLL_800M]);
+ clk_set_parent(clks[IMX8MQ_CLK_CSI2_CORE_SRC], clks[IMX8MQ_SYS1_PLL_266M]);
+ clk_set_parent(clks[IMX8MQ_CLK_CSI2_PHY_REF_SRC], clks[IMX8MQ_SYS2_PLL_1000M]);
+ clk_set_parent(clks[IMX8MQ_CLK_CSI2_ESC_SRC], clks[IMX8MQ_SYS1_PLL_800M]);
+
+ imx_register_uart_clocks(uart_clks);
+
+ pr_info("i.MX8MQ clock driver init done\n");
+}
+
+CLK_OF_DECLARE(imx8mq, "fsl,imx8mq-ccm", imx8mq_clocks_init);
diff --git a/drivers/clk/imx/clk-imx8qm.c b/drivers/clk/imx/clk-imx8qm.c
new file mode 100644
index 000000000000..50b20ddb3a50
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8qm.c
@@ -0,0 +1,950 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/clock/imx8qm-clock.h>
+#include <dt-bindings/soc/imx8_pd.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/types.h>
+
+#include <soc/imx8/imx8qm/lpcg.h>
+#include <soc/imx8/sc/sci.h>
+
+#include "clk-imx8.h"
+
+#define STR_VALUE(arg) #arg
+#define FUNCTION_NAME(name) STR_VALUE(name)
+
+static const char *aud_clk_sels[] = {
+ "aud_acm_aud_rec_clk0_clk",
+ "aud_acm_aud_rec_clk1_clk",
+ "mlb_clk",
+ "hdmi_rx_mclk",
+ "ext_aud_mclk0",
+ "ext_aud_mclk1",
+ "esai0_rx_clk",
+ "esai0_rx_hf_clk",
+ "esai0_tx_clk",
+ "esai0_tx_hf_clk",
+ "esai1_rx_clk",
+ "esai1_rx_hf_clk",
+ "esai1_tx_clk",
+ "esai1_tx_hf_clk",
+ "spdif0_rx",
+ "spdif1_rx",
+ "sai0_rx_bclk",
+ "sai0_tx_bclk",
+ "sai1_rx_bclk",
+ "sai1_tx_bclk",
+ "sai2_rx_bclk",
+ "sai3_rx_bclk",
+ "hdmi_rx_sai0_rx_bclk",
+};
+
+static const char *mclk_out_sels[] = {
+ "aud_acm_aud_rec_clk0_clk",
+ "aud_acm_aud_rec_clk1_clk",
+ "mlb_clk",
+ "hdmi_rx_mclk",
+ "spdif0_rx",
+ "spdif1_rx",
+ "hdmi_rx_sai0_rx_bclk",
+ "sai6_rx_bclk",
+};
+
+static const char *sai_mclk_sels[] = {
+ "aud_acm_aud_pll_clk0_clk",
+ "aud_acm_aud_pll_clk1_clk",
+ "acm_aud_clk0_clk",
+ "acm_aud_clk1_clk",
+};
+
+static const char *asrc_mux_clk_sels[] = {
+ "hdmi_rx_sai0_rx_bclk",
+ "hdmi_tx_sai0_tx_bclk",
+ "dummy",
+ "mlb_clk",
+};
+
+static const char *esai_mclk_sels[] = {
+ "aud_acm_aud_pll_clk0_clk",
+ "aud_acm_aud_pll_clk1_clk",
+ "acm_aud_clk0_clk",
+ "acm_aud_clk1_clk",
+};
+
+static const char *spdif_mclk_sels[] = {
+ "aud_acm_aud_pll_clk0_clk",
+ "aud_acm_aud_pll_clk1_clk",
+ "acm_aud_clk0_clk",
+ "acm_aud_clk1_clk",
+};
+
+static const char *mqs_mclk_sels[] = {
+ "aud_acm_aud_pll_clk0_clk",
+ "aud_acm_aud_pll_clk1_clk",
+ "acm_aud_clk0_clk",
+ "acm_aud_clk1_clk",
+};
+
+static const char *dc0_sels[] = {
+ "dummy",
+ "dummy",
+ "dc0_pll0_clk",
+ "dc0_pll1_clk",
+ "dc0_bypass0_div",
+};
+
+static const char *dc1_sels[] = {
+ "dummy",
+ "dummy",
+ "dc1_pll0_clk",
+ "dc1_pll1_clk",
+ "dc1_bypass0_div",
+};
+
+static const char *hdmi_sels[] = {
+ "dummy",
+ "hdmi_dig_pll_clk",
+ "dummy",
+ "dummy",
+ "hdmi_av_pll_clk",
+};
+
+static const char *hdmi_rx_sels[] = {
+ "dummy",
+ "hdmi_rx_dig_pll_clk",
+ "dummy",
+ "dummy",
+ "hdmi_rx_bypass_clk",
+};
+
+
+static struct clk *clks[IMX8QM_CLK_END];
+static struct clk_onecell_data clk_data;
+
+static const char *enet_sels[] = {"enet_25MHz", "enet_125MHz",};
+static const char *enet0_rmii_tx_sels[] = {"enet0_ref_div", "dummy",};
+static const char *enet1_rmii_tx_sels[] = {"enet1_ref_div", "dummy",};
+
+#define LPCG_ADDR(arg) ((void __iomem *)(base_lpcg + arg))
+
+static int imx8qm_clk_probe(struct platform_device *pdev)
+{
+ struct device_node *ccm_node = pdev->dev.of_node;
+ struct device_node *np_acm;
+ void __iomem *base_acm;
+ u64 base_lpcg = 0;
+ int i, ret;
+
+ ret = imx8_clk_mu_init();
+ if (ret)
+ return ret;
+
+ pr_info("***** imx8qm_clocks_init *****\n");
+
+ /* Parse lpcg_base_offset for virtualization cases */
+ ret = of_property_read_u64(ccm_node, "fsl,lpcg_base_offset", &base_lpcg);
+ if (ret && ret != -EINVAL) {
+ dev_err(&pdev->dev, "failed to parse fsl,lpcg_base_offset: %d\n", ret);
+ return ret;
+ }
+
+ clks[IMX8QM_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+
+ /* ARM core */
+ clks[IMX8QM_A53_DIV] = imx_clk_divider_scu("a53_div", SC_R_A53, SC_PM_CLK_CPU);
+ clks[IMX8QM_A72_DIV] = imx_clk_divider_scu("a72_div", SC_R_A72, SC_PM_CLK_CPU);
+
+ /* User Defined PLLs dividers */
+ clks[IMX8QM_AUD_PLL0_DIV] = imx_clk_divider_scu("audio_pll0_div", SC_R_AUDIO_PLL_0, SC_PM_CLK_PLL);
+ clks[IMX8QM_AUD_PLL1_DIV] = imx_clk_divider_scu("audio_pll1_div", SC_R_AUDIO_PLL_1, SC_PM_CLK_PLL);
+ clks[IMX8QM_DC0_PLL0_DIV] = imx_clk_divider_scu("dc0_pll0_div", SC_R_DC_0_PLL_0, SC_PM_CLK_PLL);
+ clks[IMX8QM_DC0_PLL1_DIV] = imx_clk_divider_scu("dc0_pll1_div", SC_R_DC_0_PLL_1, SC_PM_CLK_PLL);
+ clks[IMX8QM_DC1_PLL1_DIV] = imx_clk_divider_scu("dc1_pll0_div", SC_R_DC_1_PLL_0, SC_PM_CLK_PLL);
+ clks[IMX8QM_DC1_PLL1_DIV] = imx_clk_divider_scu("dc1_pll1_div", SC_R_DC_1_PLL_1, SC_PM_CLK_PLL);
+ clks[IMX8QM_HDMI_AV_PLL_DIV] = imx_clk_divider_scu("hdmi_av_pll_div", SC_R_HDMI_PLL_1, SC_PM_CLK_PLL);
+ clks[IMX8QM_HDMI_DIG_PLL_DIV] = imx_clk_divider_scu("hdmi_dig_pll_div", SC_R_HDMI_PLL_0, SC_PM_CLK_PLL);
+
+ /* User Defined PLLs clocks*/
+ clks[IMX8QM_AUD_PLL0] = imx_clk_gate_scu("audio_pll0_clk", "audio_pll0_div", SC_R_AUDIO_PLL_0, SC_PM_CLK_PLL, NULL, 0, 0);
+ clks[IMX8QM_AUD_PLL1] = imx_clk_gate_scu("audio_pll1_clk", "audio_pll1_div", SC_R_AUDIO_PLL_1, SC_PM_CLK_PLL, NULL, 0, 0);
+ clks[IMX8QM_DC0_PLL0_CLK] = imx_clk_gate_scu("dc0_pll0_clk", "dc0_pll0_div", SC_R_DC_0_PLL_0, SC_PM_CLK_PLL, NULL, 0, 0);
+ clks[IMX8QM_DC0_PLL1_CLK] = imx_clk_gate_scu("dc0_pll1_clk", "dc0_pll1_div", SC_R_DC_0_PLL_1, SC_PM_CLK_PLL, NULL, 0, 0);
+ clks[IMX8QM_DC1_PLL0_CLK] = imx_clk_gate_scu("dc1_pll0_clk", "dc1_pll0_div", SC_R_DC_1_PLL_0, SC_PM_CLK_PLL, NULL, 0, 0);
+ clks[IMX8QM_DC1_PLL1_CLK] = imx_clk_gate_scu("dc1_pll1_clk", "dc1_pll1_div", SC_R_DC_1_PLL_1, SC_PM_CLK_PLL, NULL, 0, 0);
+ clks[IMX8QM_HDMI_AV_PLL_CLK] = imx_clk_gate_scu("hdmi_av_pll_clk", "hdmi_av_pll_div", SC_R_HDMI_PLL_1, SC_PM_CLK_PLL, NULL, 0, 0);
+ clks[IMX8QM_HDMI_DIG_PLL_CLK] = imx_clk_gate_scu("hdmi_dig_pll_clk", "hdmi_dig_pll_div", SC_R_HDMI_PLL_0, SC_PM_CLK_PLL, NULL, 0, 0);
+
+ /* DMA SS */
+ clks[IMX8QM_UART0_DIV] = imx_clk_divider_scu("uart0_div", SC_R_UART_0, SC_PM_CLK_PER);
+ clks[IMX8QM_UART1_DIV] = imx_clk_divider_scu("uart1_div", SC_R_UART_1, SC_PM_CLK_PER);
+ clks[IMX8QM_UART2_DIV] = imx_clk_divider_scu("uart2_div", SC_R_UART_2, SC_PM_CLK_PER);
+ clks[IMX8QM_UART3_DIV] = imx_clk_divider_scu("uart3_div", SC_R_UART_3, SC_PM_CLK_PER);
+ clks[IMX8QM_UART4_DIV] = imx_clk_divider_scu("uart4_div", SC_R_UART_4, SC_PM_CLK_PER);
+ clks[IMX8QM_SPI0_DIV] = imx_clk_divider_scu("spi0_div", SC_R_SPI_0, SC_PM_CLK_PER);
+ clks[IMX8QM_SPI1_DIV] = imx_clk_divider_scu("spi1_div", SC_R_SPI_1, SC_PM_CLK_PER);
+ clks[IMX8QM_SPI2_DIV] = imx_clk_divider_scu("spi2_div", SC_R_SPI_2, SC_PM_CLK_PER);
+ clks[IMX8QM_SPI3_DIV] = imx_clk_divider_scu("spi3_div", SC_R_SPI_3, SC_PM_CLK_PER);
+ clks[IMX8QM_EMVSIM0_DIV] = imx_clk_divider_scu("emvsim0_div", SC_R_EMVSIM_0, SC_PM_CLK_PER);
+ clks[IMX8QM_EMVSIM1_DIV] = imx_clk_divider_scu("emvsim1_div", SC_R_EMVSIM_1, SC_PM_CLK_PER);
+ clks[IMX8QM_CAN0_DIV] = imx_clk_divider_scu("can0_div", SC_R_CAN_0, SC_PM_CLK_PER);
+ clks[IMX8QM_CAN1_DIV] = imx_clk_divider_scu("can1_div", SC_R_CAN_1, SC_PM_CLK_PER);
+ clks[IMX8QM_CAN2_DIV] = imx_clk_divider_scu("can2_div", SC_R_CAN_2, SC_PM_CLK_PER);
+ clks[IMX8QM_I2C0_DIV] = imx_clk_divider_scu("i2c0_div", SC_R_I2C_0, SC_PM_CLK_PER);
+ clks[IMX8QM_I2C1_DIV] = imx_clk_divider_scu("i2c1_div", SC_R_I2C_1, SC_PM_CLK_PER);
+ clks[IMX8QM_I2C2_DIV] = imx_clk_divider_scu("i2c2_div", SC_R_I2C_2, SC_PM_CLK_PER);
+ clks[IMX8QM_I2C3_DIV] = imx_clk_divider_scu("i2c3_div", SC_R_I2C_3, SC_PM_CLK_PER);
+ clks[IMX8QM_I2C4_DIV] = imx_clk_divider_scu("i2c4_div", SC_R_I2C_4, SC_PM_CLK_PER);
+ clks[IMX8QM_FTM0_DIV] = imx_clk_divider_scu("ftm0_div", SC_R_FTM_0, SC_PM_CLK_PER);
+ clks[IMX8QM_FTM1_DIV] = imx_clk_divider_scu("ftm1_div", SC_R_FTM_1, SC_PM_CLK_PER);
+ clks[IMX8QM_ADC0_DIV] = imx_clk_divider_scu("adc0_div", SC_R_ADC_0, SC_PM_CLK_PER);
+ clks[IMX8QM_ADC1_DIV] = imx_clk_divider_scu("adc1_div", SC_R_ADC_1, SC_PM_CLK_PER);
+
+ /* LSIO SS */
+ clks[IMX8QM_PWM0_DIV] = imx_clk_divider_scu("pwm_0_div", SC_R_PWM_0, SC_PM_CLK_PER);
+ clks[IMX8QM_PWM1_DIV] = imx_clk_divider_scu("pwm_1_div", SC_R_PWM_1, SC_PM_CLK_PER);
+ clks[IMX8QM_PWM2_DIV] = imx_clk_divider_scu("pwm_2_div", SC_R_PWM_2, SC_PM_CLK_PER);
+ clks[IMX8QM_PWM3_DIV] = imx_clk_divider_scu("pwm_3_div", SC_R_PWM_3, SC_PM_CLK_PER);
+ clks[IMX8QM_PWM4_DIV] = imx_clk_divider_scu("pwm_4_div", SC_R_PWM_4, SC_PM_CLK_PER);
+ clks[IMX8QM_PWM5_DIV] = imx_clk_divider_scu("pwm_5_div", SC_R_PWM_5, SC_PM_CLK_PER);
+ clks[IMX8QM_PWM6_DIV] = imx_clk_divider_scu("pwm_6_div", SC_R_PWM_6, SC_PM_CLK_PER);
+ clks[IMX8QM_PWM7_DIV] = imx_clk_divider_scu("pwm_7_div", SC_R_PWM_7, SC_PM_CLK_PER);
+ clks[IMX8QM_FSPI0_DIV] = imx_clk_divider_scu("fspi_0_div", SC_R_FSPI_0, SC_PM_CLK_PER);
+ clks[IMX8QM_FSPI1_DIV] = imx_clk_divider_scu("fspi_1_div", SC_R_FSPI_1, SC_PM_CLK_PER);
+ clks[IMX8QM_GPT0_DIV] = imx_clk_divider_scu("gpt_0_div", SC_R_GPT_0, SC_PM_CLK_PER);
+ clks[IMX8QM_GPT1_DIV] = imx_clk_divider_scu("gpt_1_div", SC_R_GPT_1, SC_PM_CLK_PER);
+ clks[IMX8QM_GPT2_DIV] = imx_clk_divider_scu("gpt_2_div", SC_R_GPT_2, SC_PM_CLK_PER);
+ clks[IMX8QM_GPT3_DIV] = imx_clk_divider_scu("gpt_3_div", SC_R_GPT_3, SC_PM_CLK_PER);
+ clks[IMX8QM_GPT4_DIV] = imx_clk_divider_scu("gpt_4_div", SC_R_GPT_4, SC_PM_CLK_PER);
+
+ /* lvds subsystem */
+ clks[IMX8QM_LVDS0_BYPASS_CLK] = imx_clk_divider_scu("lvds0_bypass_clk", SC_R_LVDS_0, SC_PM_CLK_BYPASS);
+ clks[IMX8QM_LVDS0_PIXEL_DIV] = imx_clk_divider_scu("lvds0_pixel_div", SC_R_LVDS_0, SC_PM_CLK_PER);
+ clks[IMX8QM_LVDS0_I2C0_DIV] = imx_clk_divider_scu("lvds0_i2c0_div", SC_R_LVDS_0_I2C_0, SC_PM_CLK_PER);
+ clks[IMX8QM_LVDS0_I2C1_DIV] = imx_clk_divider_scu("lvds0_i2c1_div", SC_R_LVDS_0_I2C_1, SC_PM_CLK_PER);
+ clks[IMX8QM_LVDS0_PWM0_DIV] = imx_clk_divider_scu("lvds0_pwm0_div", SC_R_LVDS_0_PWM_0, SC_PM_CLK_PER);
+ clks[IMX8QM_LVDS0_PHY_DIV] = imx_clk_divider_scu("lvds0_phy_div", SC_R_LVDS_0, SC_PM_CLK_PHY);
+ clks[IMX8QM_LVDS1_BYPASS_CLK] = imx_clk_divider_scu("lvds1_bypass_clk", SC_R_LVDS_1, SC_PM_CLK_BYPASS);
+ clks[IMX8QM_LVDS1_PIXEL_DIV] = imx_clk_divider_scu("lvds1_pixel_div", SC_R_LVDS_1, SC_PM_CLK_PER);
+ clks[IMX8QM_LVDS1_I2C0_DIV] = imx_clk_divider_scu("lvds1_i2c0_div", SC_R_LVDS_1_I2C_0, SC_PM_CLK_PER);
+ clks[IMX8QM_LVDS1_I2C1_DIV] = imx_clk_divider_scu("lvds1_i2c1_div", SC_R_LVDS_1_I2C_1, SC_PM_CLK_PER);
+ clks[IMX8QM_LVDS1_PWM0_DIV] = imx_clk_divider_scu("lvds1_pwm0_div", SC_R_LVDS_1_PWM_0, SC_PM_CLK_PER);
+ clks[IMX8QM_LVDS1_PHY_DIV] = imx_clk_divider_scu("lvds1_phy_div", SC_R_LVDS_1, SC_PM_CLK_PHY);
+
+ /* vpu/zpu subsystem */
+ clks[IMX8QM_VPU_DDR_DIV] = imx_clk_divider_scu("vpu_ddr_div", SC_R_VPU, SC_PM_CLK_SLV_BUS);
+ clks[IMX8QM_VPU_SYS_DIV] = imx_clk_divider_scu("vpu_sys_div", SC_R_VPU, SC_PM_CLK_MST_BUS);
+ clks[IMX8QM_VPU_XUVI_DIV] = imx_clk_divider_scu("vpu_xuvi_div", SC_R_VPU, SC_PM_CLK_PER);
+ clks[IMX8QM_VPU_UART_DIV] = imx_clk_divider_scu("vpu_uart_div", SC_R_VPU_UART, SC_PM_CLK_PER);
+ clks[IMX8QM_VPU_CORE_DIV] = imx_clk_divider_scu("vpu_core_div", SC_R_VPUCORE, SC_PM_CLK_PER);
+
+ /* gpu */
+ clks[IMX8QM_GPU0_CORE_DIV] = imx_clk_divider_scu("gpu_core0_div", SC_R_GPU_0_PID0, SC_PM_CLK_PER);
+ clks[IMX8QM_GPU0_SHADER_DIV] = imx_clk_divider_scu("gpu_shader0_div", SC_R_GPU_0_PID0, SC_PM_CLK_MISC);
+ clks[IMX8QM_GPU1_CORE_DIV] = imx_clk_divider_scu("gpu_core1_div", SC_R_GPU_1_PID0, SC_PM_CLK_PER);
+ clks[IMX8QM_GPU1_SHADER_DIV] = imx_clk_divider_scu("gpu_shader1_div", SC_R_GPU_1_PID0, SC_PM_CLK_MISC);
+
+ /* Connectivity */
+ clks[IMX8QM_SDHC0_DIV] = imx_clk_divider_scu("sdhc0_div", SC_R_SDHC_0, SC_PM_CLK_PER);
+ clks[IMX8QM_SDHC1_DIV] = imx_clk_divider_scu("sdhc1_div", SC_R_SDHC_1, SC_PM_CLK_PER);
+ clks[IMX8QM_SDHC2_DIV] = imx_clk_divider_scu("sdhc2_div", SC_R_SDHC_2, SC_PM_CLK_PER);
+ clks[IMX8QM_ENET0_ROOT_DIV] = imx_clk_divider_scu("enet0_root_div", SC_R_ENET_0, SC_PM_CLK_PER);
+ clks[IMX8QM_ENET0_REF_DIV] = imx_clk_divider3_scu("enet0_ref_div", "enet0_root_clk", SC_R_ENET_0, SC_C_CLKDIV);
+ clks[IMX8QM_ENET1_REF_DIV] = imx_clk_divider3_scu("enet1_ref_div", "enet1_root_clk", SC_R_ENET_1, SC_C_CLKDIV);
+ clks[IMX8QM_ENET0_BYPASS_DIV] = imx_clk_divider_scu("enet0_bypass_div", SC_R_ENET_0, SC_PM_CLK_BYPASS);
+ clks[IMX8QM_ENET0_RGMII_DIV] = imx_clk_divider_scu("enet0_rgmii_div", SC_R_ENET_0, SC_PM_CLK_MISC0);
+ clks[IMX8QM_ENET1_ROOT_DIV] = imx_clk_divider_scu("enet1_root_div", SC_R_ENET_1, SC_PM_CLK_PER);
+ clks[IMX8QM_ENET1_BYPASS_DIV] = imx_clk_divider_scu("enet1_bypass_div", SC_R_ENET_1, SC_PM_CLK_BYPASS);
+ clks[IMX8QM_ENET1_RGMII_DIV] = imx_clk_divider_scu("enet1_rgmii_div", SC_R_ENET_1, SC_PM_CLK_MISC0);
+ clks[IMX8QM_GPMI_BCH_IO_DIV] = imx_clk_divider_scu("gpmi_io_div", SC_R_NAND, SC_PM_CLK_MST_BUS);
+ clks[IMX8QM_GPMI_BCH_DIV] = imx_clk_divider_scu("gpmi_bch_div", SC_R_NAND, SC_PM_CLK_PER);
+ clks[IMX8QM_USB3_ACLK_DIV] = imx_clk_divider_scu("usb3_aclk_div", SC_R_USB_2, SC_PM_CLK_PER);
+ clks[IMX8QM_USB3_BUS_DIV] = imx_clk_divider_scu("usb3_bus_div", SC_R_USB_2, SC_PM_CLK_MST_BUS);
+ clks[IMX8QM_USB3_LPM_DIV] = imx_clk_divider_scu("usb3_lpm_div", SC_R_USB_2, SC_PM_CLK_MISC);
+
+ /* Audio */
+ clks[IMX8QM_AUD_ACM_AUD_PLL_CLK0_DIV] = imx_clk_divider2_scu("aud_acm_aud_pll_clk0_div", "audio_pll0_clk", SC_R_AUDIO_PLL_0, SC_PM_CLK_MISC0);
+ clks[IMX8QM_AUD_ACM_AUD_PLL_CLK1_DIV] = imx_clk_divider2_scu("aud_acm_aud_pll_clk1_div", "audio_pll1_clk", SC_R_AUDIO_PLL_1, SC_PM_CLK_MISC0);
+ clks[IMX8QM_AUD_ACM_AUD_REC_CLK0_DIV] = imx_clk_divider2_scu("aud_acm_aud_rec_clk0_div", "audio_pll0_clk", SC_R_AUDIO_PLL_0, SC_PM_CLK_MISC1);
+ clks[IMX8QM_AUD_ACM_AUD_REC_CLK1_DIV] = imx_clk_divider2_scu("aud_acm_aud_rec_clk1_div", "audio_pll1_clk", SC_R_AUDIO_PLL_1, SC_PM_CLK_MISC1);
+
+ /* MIPI CSI */
+ clks[IMX8QM_CSI0_I2C0_DIV] = imx_clk_divider_scu("mipi_csi0_i2c0_div", SC_R_CSI_0_I2C_0, SC_PM_CLK_PER);
+ clks[IMX8QM_CSI0_PWM0_DIV] = imx_clk_divider_scu("mipi_csi0_pwm0_div", SC_R_CSI_0_PWM_0, SC_PM_CLK_PER);
+ clks[IMX8QM_CSI0_CORE_DIV] = imx_clk_divider_scu("mipi_csi0_core_div", SC_R_CSI_0, SC_PM_CLK_PER);
+ clks[IMX8QM_CSI0_ESC_DIV] = imx_clk_divider_scu("mipi_csi0_esc_div", SC_R_CSI_0, SC_PM_CLK_MISC);
+ clks[IMX8QM_CSI1_I2C0_DIV] = imx_clk_divider_scu("mipi_csi1_i2c0_div", SC_R_CSI_1_I2C_0, SC_PM_CLK_PER);
+ clks[IMX8QM_CSI1_PWM0_DIV] = imx_clk_divider_scu("mipi_csi1_pwm0_div", SC_R_CSI_1_PWM_0, SC_PM_CLK_PER);
+ clks[IMX8QM_CSI1_CORE_DIV] = imx_clk_divider_scu("mipi_csi1_core_div", SC_R_CSI_1, SC_PM_CLK_PER);
+ clks[IMX8QM_CSI1_ESC_DIV] = imx_clk_divider_scu("mipi_csi1_esc_div", SC_R_CSI_1, SC_PM_CLK_MISC);
+
+ /* RX-HDMI */
+ clks[IMX8QM_HDMI_RX_I2S_BYPASS_CLK] = imx_clk_divider_scu("hdmi_rx_i2s_bypass_clk", SC_R_HDMI_RX_BYPASS, SC_PM_CLK_MISC0);
+ clks[IMX8QM_HDMI_RX_SPDIF_BYPASS_CLK] = imx_clk_divider_scu("hdmi_rx_spdif_bypass_clk", SC_R_HDMI_RX_BYPASS, SC_PM_CLK_MISC1);
+ clks[IMX8QM_HDMI_RX_BYPASS_CLK] = imx_clk_divider_scu("hdmi_rx_bypass_clk", SC_R_HDMI_RX_BYPASS, SC_PM_CLK_MISC2);
+ clks[IMX8QM_HDMI_RX_I2C0_DIV] = imx_clk_divider_scu("hdmi_rx_i2c0_div", SC_R_HDMI_RX_I2C_0, SC_PM_CLK_MISC2);
+ clks[IMX8QM_HDMI_RX_SPDIF_DIV] = imx_clk_divider_scu("hdmi_rx_spdif_div", SC_R_HDMI_RX, SC_PM_CLK_MISC0);
+ clks[IMX8QM_HDMI_RX_HD_REF_SEL] = imx_clk_mux2_scu("hdmi_rx_hd_ref_sel", hdmi_rx_sels, ARRAY_SIZE(hdmi_rx_sels), SC_R_HDMI_RX, SC_PM_CLK_MISC1);
+ clks[IMX8QM_HDMI_RX_HD_REF_DIV] = imx_clk_divider2_scu("hdmi_rx_hd_ref_div", "hdmi_rx_hd_ref_sel", SC_R_HDMI_RX, SC_PM_CLK_MISC1);
+ clks[IMX8QM_HDMI_RX_HD_CORE_SEL] = imx_clk_mux2_scu("hdmi_rx_hd_core_sel", hdmi_rx_sels, ARRAY_SIZE(hdmi_rx_sels), SC_R_HDMI_RX, SC_PM_CLK_MISC2);
+ clks[IMX8QM_HDMI_RX_HD_CORE_DIV] = imx_clk_divider2_scu("hdmi_rx_hd_core_div", "hdmi_rx_hd_core_sel", SC_R_HDMI_RX, SC_PM_CLK_MISC2);
+ clks[IMX8QM_HDMI_RX_PXL_SEL] = imx_clk_mux2_scu("hdmi_rx_pxl_sel", hdmi_rx_sels, ARRAY_SIZE(hdmi_rx_sels), SC_R_HDMI_RX, SC_PM_CLK_MISC3);
+ clks[IMX8QM_HDMI_RX_PXL_DIV] = imx_clk_divider2_scu("hdmi_rx_pxl_div", "hdmi_rx_pxl_sel", SC_R_HDMI_RX, SC_PM_CLK_MISC3);
+ clks[IMX8QM_HDMI_RX_I2S_DIV] = imx_clk_divider_scu("hdmi_rx_i2s_div", SC_R_HDMI_RX, SC_PM_CLK_MISC4);
+ clks[IMX8QM_HDMI_RX_PWM_DIV] = imx_clk_divider_scu("hdmi_rx_pwm_div", SC_R_HDMI_RX_PWM_0, SC_PM_CLK_MISC2);
+
+ /* DC SS */
+ clks[IMX8QM_DC0_DISP0_SEL] = imx_clk_mux2_scu("dc0_disp0_sel", dc0_sels, ARRAY_SIZE(dc0_sels), SC_R_DC_0, SC_PM_CLK_MISC0);
+ clks[IMX8QM_DC0_DISP0_DIV] = imx_clk_divider2_scu("dc0_disp0_div", "dc0_disp0_sel", SC_R_DC_0, SC_PM_CLK_MISC0);
+ clks[IMX8QM_DC0_DISP1_SEL] = imx_clk_mux2_scu("dc0_disp1_sel", dc0_sels, ARRAY_SIZE(dc0_sels), SC_R_DC_0, SC_PM_CLK_MISC1);
+ clks[IMX8QM_DC0_DISP1_DIV] = imx_clk_divider2_scu("dc0_disp1_div", "dc0_disp1_sel", SC_R_DC_0, SC_PM_CLK_MISC1);
+ clks[IMX8QM_DC0_BYPASS_0_DIV] = imx_clk_divider_scu("dc0_bypass0_div", SC_R_DC_0_VIDEO0, SC_PM_CLK_MISC);
+ clks[IMX8QM_DC0_BYPASS_1_DIV] = imx_clk_divider_scu("dc0_bypass1_div", SC_R_DC_0_VIDEO1, SC_PM_CLK_MISC);
+ clks[IMX8QM_DC1_DISP0_SEL] = imx_clk_mux2_scu("dc1_disp0_sel", dc1_sels, ARRAY_SIZE(dc1_sels), SC_R_DC_1, SC_PM_CLK_MISC0);
+ clks[IMX8QM_DC1_DISP0_DIV] = imx_clk_divider2_scu("dc1_disp0_div", "dc1_disp0_sel", SC_R_DC_1, SC_PM_CLK_MISC0);
+ clks[IMX8QM_DC1_DISP1_SEL] = imx_clk_mux2_scu("dc1_disp1_sel", dc1_sels, ARRAY_SIZE(dc1_sels), SC_R_DC_1, SC_PM_CLK_MISC1);
+ clks[IMX8QM_DC1_DISP1_DIV] = imx_clk_divider2_scu("dc1_disp1_div", "dc1_disp1_sel", SC_R_DC_1, SC_PM_CLK_MISC1);
+ clks[IMX8QM_DC1_BYPASS_0_DIV] = imx_clk_divider_scu("dc1_bypass0_div", SC_R_DC_1_VIDEO0, SC_PM_CLK_BYPASS);
+ clks[IMX8QM_DC1_BYPASS_1_DIV] = imx_clk_divider_scu("dc1_bypass1_div", SC_R_DC_1_VIDEO1, SC_PM_CLK_BYPASS);
+
+ /* HDMI SS */
+ clks[IMX8QM_HDMI_IPG_DIV] = imx_clk_divider_scu("hdmi_ipg_div", SC_R_HDMI, SC_PM_CLK_MISC);
+ clks[IMX8QM_HDMI_I2S_BYPASS_CLK] = imx_clk_divider_scu("hdmi_i2s_bypass_clk", SC_R_HDMI_I2S, SC_PM_CLK_BYPASS);
+ clks[IMX8QM_HDMI_I2C0_DIV] = imx_clk_divider_scu("hdmi_i2c0_div", SC_R_HDMI_I2C_0, SC_PM_CLK_MISC2);
+ clks[IMX8QM_HDMI_PXL_SEL] = imx_clk_mux2_scu("hdmi_pxl_sel", hdmi_sels, ARRAY_SIZE(hdmi_sels), SC_R_HDMI, SC_PM_CLK_MISC3);
+ clks[IMX8QM_HDMI_PXL_DIV] = imx_clk_divider2_scu("hdmi_pxl_div", "hdmi_pxl_sel", SC_R_HDMI, SC_PM_CLK_MISC3);
+ clks[IMX8QM_HDMI_PXL_LINK_SEL] = imx_clk_mux2_scu("hdmi_pxl_link_sel", hdmi_sels, ARRAY_SIZE(hdmi_sels), SC_R_HDMI, SC_PM_CLK_MISC1);
+ clks[IMX8QM_HDMI_PXL_LINK_DIV] = imx_clk_divider2_scu("hdmi_pxl_link_div", "hdmi_pxl_link_sel", SC_R_HDMI, SC_PM_CLK_MISC1);
+ clks[IMX8QM_HDMI_PXL_MUX_SEL] = imx_clk_mux2_scu("hdmi_pxl_mux_sel", hdmi_sels, ARRAY_SIZE(hdmi_sels), SC_R_HDMI, SC_PM_CLK_MISC0);
+ clks[IMX8QM_HDMI_PXL_MUX_DIV] = imx_clk_divider2_scu("hdmi_pxl_mux_div", "hdmi_pxl_mux_sel", SC_R_HDMI, SC_PM_CLK_MISC0);
+ clks[IMX8QM_HDMI_I2S_DIV] = imx_clk_divider_scu("hdmi_i2s_div", SC_R_HDMI_I2S, SC_PM_CLK_MISC0);
+ clks[IMX8QM_HDMI_HDP_CORE_DIV] = imx_clk_divider_scu("hdmi_core_div", SC_R_HDMI, SC_PM_CLK_MISC2);
+
+ /* MIPI -DI SS */
+ clks[IMX8QM_MIPI0_BYPASS_CLK] = imx_clk_divider_scu("mipi0_bypass_clk", SC_R_MIPI_0, SC_PM_CLK_BYPASS);
+ clks[IMX8QM_MIPI0_PWM0_DIV] = imx_clk_divider_scu("mipi0_pwm0_div", SC_R_MIPI_0_PWM_0, SC_PM_CLK_PER);
+ clks[IMX8QM_MIPI0_DSI_TX_ESC_DIV] = imx_clk_divider_scu("mipi0_dsi_tx_esc_div", SC_R_MIPI_0, SC_PM_CLK_MST_BUS);
+ clks[IMX8QM_MIPI0_DSI_RX_ESC_DIV] = imx_clk_divider_scu("mipi0_dsi_rx_esc_div", SC_R_MIPI_0, SC_PM_CLK_SLV_BUS);
+ clks[IMX8QM_MIPI0_PXL_DIV] = imx_clk_divider_scu("mipi0_pxl_div", SC_R_MIPI_0, SC_PM_CLK_PER);
+ clks[IMX8QM_MIPI1_BYPASS_CLK] = imx_clk_divider_scu("mipi1_bypass_clk", SC_R_MIPI_1, SC_PM_CLK_BYPASS);
+ clks[IMX8QM_MIPI1_PWM0_DIV] = imx_clk_divider_scu("mipi1_pwm0_div", SC_R_MIPI_1_PWM_0, SC_PM_CLK_PER);
+ clks[IMX8QM_MIPI1_DSI_TX_ESC_DIV] = imx_clk_divider_scu("mipi1_dsi_tx_esc_div", SC_R_MIPI_1, SC_PM_CLK_MST_BUS);
+ clks[IMX8QM_MIPI1_DSI_RX_ESC_DIV] = imx_clk_divider_scu("mipi1_dsi_rx_esc_div", SC_R_MIPI_1, SC_PM_CLK_SLV_BUS);
+ clks[IMX8QM_MIPI1_PXL_DIV] = imx_clk_divider_scu("mipi1_pxl_div", SC_R_MIPI_1, SC_PM_CLK_PER);
+
+ /* Fixed clocks. */
+ clks[IMX8QM_IPG_DMA_CLK_ROOT] = imx_clk_fixed("ipg_dma_clk_root", SC_120MHZ);
+ clks[IMX8QM_IPG_AUD_CLK_ROOT] = imx_clk_fixed("ipg_aud_clk_root", SC_175MHZ);
+ clks[IMX8QM_AXI_CONN_CLK_ROOT] = imx_clk_fixed("axi_conn_clk_root", SC_333MHZ);
+ clks[IMX8QM_AHB_CONN_CLK_ROOT] = imx_clk_fixed("ahb_conn_clk_root", SC_166MHZ);
+ clks[IMX8QM_IPG_CONN_CLK_ROOT] = imx_clk_fixed("ipg_conn_clk_root", SC_83MHZ);
+ clks[IMX8QM_IPG_MIPI_CSI_CLK_ROOT] = imx_clk_fixed("ipg_mipi_csi_clk_root", SC_120MHZ);
+ clks[IMX8QM_DC_AXI_EXT_CLK] = imx_clk_fixed("axi_ext_dc_clk_root", SC_800MHZ);
+ clks[IMX8QM_DC_AXI_INT_CLK] = imx_clk_fixed("axi_int_dc_clk_root", SC_400MHZ);
+ clks[IMX8QM_DC_CFG_CLK] = imx_clk_fixed("cfg_dc_clk_root", SC_100MHZ);
+ clks[IMX8QM_LVDS_IPG_CLK] = imx_clk_fixed("ipg_lvds_clk_root", SC_24MHZ);
+ clks[IMX8QM_IMG_AXI_CLK] = imx_clk_fixed("axi_img_clk_root", SC_400MHZ);
+ clks[IMX8QM_IMG_IPG_CLK] = imx_clk_fixed("ipg_img_clk_root", SC_200MHZ);
+ clks[IMX8QM_IMG_PXL_CLK] = imx_clk_fixed("pxl_img_clk_root", SC_600MHZ);
+ clks[IMX8QM_HSIO_AXI_CLK] = imx_clk_fixed("axi_hsio_clk_root", SC_400MHZ);
+ clks[IMX8QM_HSIO_PER_CLK] = imx_clk_fixed("per_hsio_clk_root", SC_133MHZ);
+ clks[IMX8QM_HDMI_RX_IPG_CLK] = imx_clk_fixed("ipg_hdmi_rx_clk_root", SC_200MHZ);
+ clks[IMX8QM_HDMI_RX_DIG_PLL_CLK] = imx_clk_fixed("hdmi_rx_dig_pll_clk", SC_800MHZ);
+ clks[IMX8QM_ENET_25MHZ_CLK] = imx_clk_fixed("enet_25MHz", SC_25MHZ);
+ clks[IMX8QM_ENET_125MHZ_CLK] = imx_clk_fixed("enet_125MHz", SC_125MHZ);
+ clks[IMX8QM_LSIO_BUS_CLK] = imx_clk_fixed("lsio_bus_clk_root", SC_100MHZ);
+ clks[IMX8QM_LSIO_MEM_CLK] = imx_clk_fixed("lsio_mem_clk_root", SC_200MHZ);
+ clks[IMX8QM_24MHZ] = imx_clk_fixed("xtal_24MHz", 24000000);
+ clks[IMX8QM_GPT_3M] = imx_clk_fixed("gpt_3m", 3000000);
+ clks[IMX8QM_32KHZ] = imx_clk_fixed("xtal_32KHz", 32768);
+ clks[IMX8QM_MIPI0_CLK_ROOT] = imx_clk_fixed("mipi0_clk_root", SC_120MHZ);
+ clks[IMX8QM_MIPI1_CLK_ROOT] = imx_clk_fixed("mipi1_clk_root", SC_120MHZ);
+
+ /* Conectivity */
+ clks[IMX8QM_SDHC0_IPG_CLK] = imx_clk_gate2_scu("sdhc0_ipg_clk", "ipg_conn_clk_root", LPCG_ADDR(USDHC_0_LPCG), 16, FUNCTION_NAME(PD_CONN_SDHC_0));
+ clks[IMX8QM_SDHC1_IPG_CLK] = imx_clk_gate2_scu("sdhc1_ipg_clk", "ipg_conn_clk_root", LPCG_ADDR(USDHC_1_LPCG), 16, FUNCTION_NAME(PD_CONN_SDHC_1));
+ clks[IMX8QM_SDHC2_IPG_CLK] = imx_clk_gate2_scu("sdhc2_ipg_clk", "ipg_conn_clk_root", LPCG_ADDR(USDHC_2_LPCG), 16, FUNCTION_NAME(PD_CONN_SDHC_2));
+ clks[IMX8QM_SDHC0_CLK] = imx_clk_gate_scu("sdhc0_clk", "sdhc0_div", SC_R_SDHC_0, SC_PM_CLK_PER, LPCG_ADDR(USDHC_0_LPCG), 0, 0);
+ clks[IMX8QM_SDHC1_CLK] = imx_clk_gate_scu("sdhc1_clk", "sdhc1_div", SC_R_SDHC_1, SC_PM_CLK_PER, LPCG_ADDR(USDHC_1_LPCG), 0, 0);
+ clks[IMX8QM_SDHC2_CLK] = imx_clk_gate_scu("sdhc2_clk", "sdhc2_div", SC_R_SDHC_2, SC_PM_CLK_PER, LPCG_ADDR(USDHC_2_LPCG), 0, 0);
+ clks[IMX8QM_ENET0_AHB_CLK] = imx_clk_gate2_scu("enet0_ahb_clk", "axi_conn_clk_root", LPCG_ADDR(ENET_0_LPCG), 8, FUNCTION_NAME(PD_CONN_ENET_0));
+ clks[IMX8QM_ENET0_IPG_S_CLK] = imx_clk_gate2_scu("enet0_ipg_s_clk", "ipg_conn_clk_root", LPCG_ADDR(ENET_0_LPCG), 20, FUNCTION_NAME(PD_CONN_ENET_0));
+ clks[IMX8QM_ENET0_IPG_CLK] = imx_clk_gate2_scu("enet0_ipg_clk", "enet0_ipg_s_clk", LPCG_ADDR(ENET_0_LPCG), 16, FUNCTION_NAME(PD_CONN_ENET_0));
+ clks[IMX8QM_ENET1_AHB_CLK] = imx_clk_gate2_scu("enet1_ahb_clk", "axi_conn_clk_root", LPCG_ADDR(ENET_1_LPCG), 8, FUNCTION_NAME(PD_CONN_ENET_1));
+ clks[IMX8QM_ENET1_IPG_S_CLK] = imx_clk_gate2_scu("enet1_ipg_s_clk", "ipg_conn_clk_root", LPCG_ADDR(ENET_1_LPCG), 20, FUNCTION_NAME(PD_CONN_ENET_1));
+ clks[IMX8QM_ENET1_IPG_CLK] = imx_clk_gate2_scu("enet1_ipg_clk", "enet1_ipg_s_clk", LPCG_ADDR(ENET_1_LPCG), 16, FUNCTION_NAME(PD_CONN_ENET_1));
+ clks[IMX8QM_ENET0_ROOT_CLK] = imx_clk_gate_scu("enet0_root_clk", "enet0_root_div", SC_R_ENET_0, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QM_ENET1_ROOT_CLK] = imx_clk_gate_scu("enet1_root_clk", "enet1_root_div", SC_R_ENET_1, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QM_ENET0_TX_CLK] = imx_clk_gate2_scu("enet0_tx_2x_clk", "enet0_root_clk", LPCG_ADDR(ENET_0_LPCG), 4, FUNCTION_NAME(PD_CONN_ENET_0));
+ clks[IMX8QM_ENET1_TX_CLK] = imx_clk_gate2_scu("enet1_tx_2x_clk", "enet1_root_clk", LPCG_ADDR(ENET_1_LPCG), 4, FUNCTION_NAME(PD_CONN_ENET_1));
+ clks[IMX8QM_ENET0_PTP_CLK] = imx_clk_gate2_scu("enet0_ptp_clk", "enet0_root_clk", LPCG_ADDR(ENET_0_LPCG), 0, FUNCTION_NAME(PD_CONN_ENET_0));
+ clks[IMX8QM_ENET1_PTP_CLK] = imx_clk_gate2_scu("enet1_ptp_clk", "enet1_root_clk", LPCG_ADDR(ENET_1_LPCG), 0, FUNCTION_NAME(PD_CONN_ENET_1));
+ clks[IMX8QM_ENET0_REF_25MHZ_125MHZ_SEL] = imx_clk_mux_gpr_scu("enet0_ref_25_125_sel", enet_sels, ARRAY_SIZE(enet_sels), SC_R_ENET_0, SC_C_SEL_125);
+ clks[IMX8QM_ENET1_REF_25MHZ_125MHZ_SEL] = imx_clk_mux_gpr_scu("enet1_ref_25_125_sel", enet_sels, ARRAY_SIZE(enet_sels), SC_R_ENET_1, SC_C_SEL_125);
+ clks[IMX8QM_ENET0_RMII_TX_SEL] = imx_clk_mux_gpr_scu("enet0_rmii_tx_sel", enet0_rmii_tx_sels, ARRAY_SIZE(enet0_rmii_tx_sels), SC_R_ENET_0, SC_C_TXCLK);
+ clks[IMX8QM_ENET1_RMII_TX_SEL] = imx_clk_mux_gpr_scu("enet1_rmii_tx_sel", enet1_rmii_tx_sels, ARRAY_SIZE(enet1_rmii_tx_sels), SC_R_ENET_1, SC_C_TXCLK);
+ clks[IMX8QM_ENET0_RGMII_TX_CLK] = imx_clk_gate2_scu("enet0_rgmii_tx_clk", "enet0_rmii_tx_sel", LPCG_ADDR(ENET_0_LPCG), 12, FUNCTION_NAME(PD_CONN_ENET_0));
+ clks[IMX8QM_ENET1_RGMII_TX_CLK] = imx_clk_gate2_scu("enet1_rgmii_tx_clk", "enet1_rmii_tx_sel", LPCG_ADDR(ENET_1_LPCG), 12, FUNCTION_NAME(PD_CONN_ENET_1));
+ clks[IMX8QM_ENET0_RMII_RX_CLK] = imx_clk_gate2_scu("enet0_rgmii_rx_clk", "enet0_rgmii_div", LPCG_ADDR(ENET_0_LPCG + 0x4), 0, FUNCTION_NAME(PD_CONN_ENET_0));
+ clks[IMX8QM_ENET1_RMII_RX_CLK] = imx_clk_gate2_scu("enet1_rgmii_rx_clk", "enet1_rgmii_div", LPCG_ADDR(ENET_1_LPCG + 0x4), 0, FUNCTION_NAME(PD_CONN_ENET_1));
+ clks[IMX8QM_ENET0_REF_25MHZ_125MHZ_CLK] = imx_clk_gate3_scu("enet0_ref_25_125_clk", "enet0_ref_25_125_sel", SC_R_ENET_0, SC_C_DISABLE_125, true);
+ clks[IMX8QM_ENET1_REF_25MHZ_125MHZ_CLK] = imx_clk_gate3_scu("enet1_ref_25_125_clk", "enet1_ref_25_125_sel", SC_R_ENET_1, SC_C_DISABLE_125, true);
+ clks[IMX8QM_ENET0_REF_50MHZ_CLK] = imx_clk_gate3_scu("enet0_ref_50_clk", NULL, SC_R_ENET_0, SC_C_DISABLE_50, true);
+ clks[IMX8QM_ENET1_REF_50MHZ_CLK] = imx_clk_gate3_scu("enet1_ref_50_clk", NULL, SC_R_ENET_1, SC_C_DISABLE_50, true);
+ clks[IMX8QM_GPMI_APB_CLK] = imx_clk_gate2_scu("gpmi_apb_clk", "axi_conn_clk_root", LPCG_ADDR(NAND_LPCG), 16, FUNCTION_NAME(PD_CONN_NAND));
+ clks[IMX8QM_GPMI_APB_BCH_CLK] = imx_clk_gate2_scu("gpmi_apb_bch_clk", "axi_conn_clk_root", LPCG_ADDR(NAND_LPCG), 20, FUNCTION_NAME(PD_CONN_NAND));
+ clks[IMX8QM_GPMI_BCH_IO_CLK] = imx_clk_gate_scu("gpmi_io_clk", "gpmi_io_div", SC_R_NAND, SC_PM_CLK_MST_BUS, LPCG_ADDR(NAND_LPCG), 4, 0);
+ clks[IMX8QM_GPMI_BCH_CLK] = imx_clk_gate_scu("gpmi_bch_clk", "gpmi_bch_div", SC_R_NAND, SC_PM_CLK_PER, LPCG_ADDR(NAND_LPCG), 0, 0);
+ clks[IMX8QM_APBHDMA_CLK] = imx_clk_gate2_scu("gpmi_clk", "axi_conn_clk_root", LPCG_ADDR(NAND_LPCG + 0x4), 16, FUNCTION_NAME(PD_CONN_NAND));
+ clks[IMX8QM_USB2_OH_AHB_CLK] = imx_clk_gate2_scu("usboh3", "ahb_conn_clk_root", LPCG_ADDR(USB_2_LPCG), 24, FUNCTION_NAME(PD_CONN_USB_0));
+ clks[IMX8QM_USB2_OH_IPG_S_CLK] = imx_clk_gate2_scu("usboh3_ipg_s", "ipg_conn_clk_root", LPCG_ADDR(USB_2_LPCG), 16, FUNCTION_NAME(PD_CONN_USB_0));
+ clks[IMX8QM_USB2_OH_IPG_S_PL301_CLK] = imx_clk_gate2_scu("usboh3_ipg_pl301_s", "ipg_conn_clk_root", LPCG_ADDR(USB_2_LPCG), 20, FUNCTION_NAME(PD_CONN_USB_0));
+ clks[IMX8QM_USB2_PHY_IPG_CLK] = imx_clk_gate2_scu("usboh3_phy_clk", "ipg_conn_clk_root", LPCG_ADDR(USB_2_LPCG), 28, FUNCTION_NAME(PD_CONN_USB_0));
+ clks[IMX8QM_USB3_IPG_CLK] = imx_clk_gate2_scu("usb3_ipg_clk", "ipg_conn_clk_root", LPCG_ADDR(USB_3_LPCG), 16, FUNCTION_NAME(PD_CONN_USB_2));
+ clks[IMX8QM_USB3_CORE_PCLK] = imx_clk_gate2_scu("usb3_core_clk", "ipg_conn_clk_root", LPCG_ADDR(USB_3_LPCG), 20, FUNCTION_NAME(PD_CONN_USB_2));
+ clks[IMX8QM_USB3_PHY_CLK] = imx_clk_gate2_scu("usb3_phy_clk", "usb3_ipg_clk", LPCG_ADDR(USB_3_LPCG), 24, FUNCTION_NAME(PD_CONN_USB_2_PHY));
+ clks[IMX8QM_USB3_ACLK] = imx_clk_gate_scu("usb3_aclk", "usb3_aclk_div", SC_R_USB_2, SC_PM_CLK_PER, LPCG_ADDR(USB_3_LPCG), 28, 0);
+ clks[IMX8QM_USB3_BUS_CLK] = imx_clk_gate_scu("usb3_bus_clk", "usb3_bus_div", SC_R_USB_2, SC_PM_CLK_MST_BUS, LPCG_ADDR(USB_3_LPCG), 0, 0);
+ clks[IMX8QM_USB3_LPM_CLK] = imx_clk_gate_scu("usb3_lpm_clk", "usb3_lpm_div", SC_R_USB_2, SC_PM_CLK_MISC, LPCG_ADDR(USB_3_LPCG), 4, 0);
+ clks[IMX8QM_EDMA_CLK] = imx_clk_gate2_scu("edma_clk", "axi_conn_clk_root", LPCG_ADDR(EDMA_LPCG), 0, FUNCTION_NAME(PD_CONN_DMA_4_CH0));
+ clks[IMX8QM_EDMA_IPG_CLK] = imx_clk_gate2_scu("edma_ipg_clk", "ipg_conn_clk_root", LPCG_ADDR(EDMA_LPCG), 16, FUNCTION_NAME(PD_CONN_DMA_4_CH0));
+ clks[IMX8QM_MLB_HCLK] = imx_clk_gate2_scu("mlb_hclk", "axi_conn_clk_root", LPCG_ADDR(MLB_LPCG), 20, FUNCTION_NAME(PD_CONN_MLB_0));
+ clks[IMX8QM_MLB_CLK] = imx_clk_gate2_scu("mlb_clk", "mlb_hclk", LPCG_ADDR(MLB_LPCG), 0, FUNCTION_NAME(PD_CONN_MLB_0));
+ clks[IMX8QM_MLB_IPG_CLK] = imx_clk_gate2_scu("mlb_ipg_clk", "ipg_conn_clk_root", LPCG_ADDR(MLB_LPCG), 16, FUNCTION_NAME(PD_CONN_MLB_0));
+
+ /* DMA */
+ clks[IMX8QM_UART0_IPG_CLK] = imx_clk_gate2_scu("uart0_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(LPUART_0_LPCG), 16, FUNCTION_NAME(PD_DMA_UART0));
+ clks[IMX8QM_UART1_IPG_CLK] = imx_clk_gate2_scu("uart1_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(LPUART_1_LPCG), 16, FUNCTION_NAME(PD_DMA_UART1));
+ clks[IMX8QM_UART2_IPG_CLK] = imx_clk_gate2_scu("uart2_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(LPUART_2_LPCG), 16, FUNCTION_NAME(PD_DMA_UART2));
+ clks[IMX8QM_UART3_IPG_CLK] = imx_clk_gate2_scu("uart3_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(LPUART_3_LPCG), 16, FUNCTION_NAME(PD_DMA_UART3));
+ clks[IMX8QM_UART4_IPG_CLK] = imx_clk_gate2_scu("uart4_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(LPUART_4_LPCG), 16, FUNCTION_NAME(PD_DMA_UART4));
+ clks[IMX8QM_UART0_CLK] = imx_clk_gate_scu("uart0_clk", "uart0_div", SC_R_UART_0, SC_PM_CLK_PER, LPCG_ADDR(LPUART_0_LPCG), 0, 0);
+ clks[IMX8QM_UART1_CLK] = imx_clk_gate_scu("uart1_clk", "uart1_div", SC_R_UART_1, SC_PM_CLK_PER, LPCG_ADDR(LPUART_1_LPCG), 0, 0);
+ clks[IMX8QM_UART2_CLK] = imx_clk_gate_scu("uart2_clk", "uart2_div", SC_R_UART_2, SC_PM_CLK_PER, LPCG_ADDR(LPUART_2_LPCG), 0, 0);
+ clks[IMX8QM_UART3_CLK] = imx_clk_gate_scu("uart3_clk", "uart3_div", SC_R_UART_3, SC_PM_CLK_PER, LPCG_ADDR(LPUART_3_LPCG), 0, 0);
+ clks[IMX8QM_UART4_CLK] = imx_clk_gate_scu("uart4_clk", "uart4_div", SC_R_UART_4, SC_PM_CLK_PER, LPCG_ADDR(LPUART_4_LPCG), 0, 0);
+ clks[IMX8QM_SPI0_IPG_CLK] = imx_clk_gate2_scu("spi0_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(LPSPI_0_LPCG), 16, FUNCTION_NAME(PD_DMA_SPI_0));
+ clks[IMX8QM_SPI1_IPG_CLK] = imx_clk_gate2_scu("spi1_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(LPSPI_1_LPCG), 16, FUNCTION_NAME(PD_DMA_SPI_1));
+ clks[IMX8QM_SPI2_IPG_CLK] = imx_clk_gate2_scu("spi2_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(LPSPI_2_LPCG), 16, FUNCTION_NAME(PD_DMA_SPI_2));
+ clks[IMX8QM_SPI3_IPG_CLK] = imx_clk_gate2_scu("spi3_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(LPSPI_3_LPCG), 16, FUNCTION_NAME(PD_DMA_SPI_3));
+ clks[IMX8QM_SPI0_CLK] = imx_clk_gate_scu("spi0_clk", "spi0_div", SC_R_SPI_0, SC_PM_CLK_PER, LPCG_ADDR(LPSPI_0_LPCG), 0, 0);
+ clks[IMX8QM_SPI1_CLK] = imx_clk_gate_scu("spi1_clk", "spi1_div", SC_R_SPI_1, SC_PM_CLK_PER, LPCG_ADDR(LPSPI_1_LPCG), 0, 0);
+ clks[IMX8QM_SPI2_CLK] = imx_clk_gate_scu("spi2_clk", "spi2_div", SC_R_SPI_2, SC_PM_CLK_PER, LPCG_ADDR(LPSPI_2_LPCG), 0, 0);
+ clks[IMX8QM_SPI3_CLK] = imx_clk_gate_scu("spi3_clk", "spi3_div", SC_R_SPI_3, SC_PM_CLK_PER, LPCG_ADDR(LPSPI_3_LPCG), 0, 0);
+ clks[IMX8QM_EMVSIM0_IPG_CLK] = imx_clk_gate2_scu("emvsim0_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(EMVSIM_0_LPCG), 16, FUNCTION_NAME(PD_DMA_EMVSIM_0));
+ clks[IMX8QM_EMVSIM1_IPG_CLK] = imx_clk_gate2_scu("emvsim1_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(EMVSIM_1_LPCG), 16, FUNCTION_NAME(PD_DMA_EMVSIM_1));
+ clks[IMX8QM_EMVSIM0_CLK] = imx_clk_gate_scu("emvsim0_clk", "emvsim0_div", SC_R_EMVSIM_0, SC_PM_CLK_PER, LPCG_ADDR(EMVSIM_0_LPCG), 0, 0);
+ clks[IMX8QM_EMVSIM1_CLK] = imx_clk_gate_scu("emvsim1_clk", "emvsim1_div", SC_R_EMVSIM_0, SC_PM_CLK_PER, LPCG_ADDR(EMVSIM_1_LPCG), 0, 0);
+ clks[IMX8QM_CAN0_IPG_CHI_CLK] = imx_clk_gate2_scu("can0_ipg_chi_clk", "ipg_dma_clk_root", LPCG_ADDR(FLEX_CAN_0_LPCG), 20, FUNCTION_NAME(PD_DMA_CAN_0));
+ clks[IMX8QM_CAN0_IPG_CLK] = imx_clk_gate2_scu("can0_ipg_clk", "can0_ipg_chi_clk", LPCG_ADDR(FLEX_CAN_0_LPCG), 16, FUNCTION_NAME(PD_DMA_CAN_0));
+ clks[IMX8QM_CAN1_IPG_CHI_CLK] = imx_clk_gate2_scu("can1_ipg_chi_clk", "ipg_dma_clk_root", LPCG_ADDR(FLEX_CAN_1_LPCG), 20, FUNCTION_NAME(PD_DMA_CAN_1));
+ clks[IMX8QM_CAN1_IPG_CLK] = imx_clk_gate2_scu("can1_ipg_clk", "can1_ipg_chi_clk", LPCG_ADDR(FLEX_CAN_1_LPCG), 16, FUNCTION_NAME(PD_DMA_CAN_1));
+ clks[IMX8QM_CAN2_IPG_CHI_CLK] = imx_clk_gate2_scu("can2_ipg_chi_clk", "ipg_dma_clk_root", LPCG_ADDR(FLEX_CAN_2_LPCG), 20, FUNCTION_NAME(PD_DMA_CAN_2));
+ clks[IMX8QM_CAN2_IPG_CLK] = imx_clk_gate2_scu("can2_ipg_clk", "can2_ipg_chi_clk", LPCG_ADDR(FLEX_CAN_2_LPCG), 16, FUNCTION_NAME(PD_DMA_CAN_2));
+ clks[IMX8QM_CAN0_CLK] = imx_clk_gate_scu("can0_clk", "can0_div", SC_R_CAN_0, SC_PM_CLK_PER, LPCG_ADDR(FLEX_CAN_0_LPCG), 0, 0);
+ clks[IMX8QM_CAN1_CLK] = imx_clk_gate_scu("can1_clk", "can1_div", SC_R_CAN_1, SC_PM_CLK_PER, LPCG_ADDR(FLEX_CAN_1_LPCG), 0, 0);
+ clks[IMX8QM_CAN2_CLK] = imx_clk_gate_scu("can2_clk", "can2_div", SC_R_CAN_2, SC_PM_CLK_PER, LPCG_ADDR(FLEX_CAN_2_LPCG), 0, 0);
+ clks[IMX8QM_I2C0_IPG_CLK] = imx_clk_gate2_scu("i2c0_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(LPI2C_0_LPCG), 16, FUNCTION_NAME(PD_DMA_I2C_0));
+ clks[IMX8QM_I2C1_IPG_CLK] = imx_clk_gate2_scu("i2c1_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(LPI2C_1_LPCG), 16, FUNCTION_NAME(PD_DMA_I2C_1));
+ clks[IMX8QM_I2C2_IPG_CLK] = imx_clk_gate2_scu("i2c2_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(LPI2C_2_LPCG), 16, FUNCTION_NAME(PD_DMA_I2C_2));
+ clks[IMX8QM_I2C3_IPG_CLK] = imx_clk_gate2_scu("i2c3_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(LPI2C_3_LPCG), 16, FUNCTION_NAME(PD_DMA_I2C_3));
+ clks[IMX8QM_I2C4_IPG_CLK] = imx_clk_gate2_scu("i2c4_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(LPI2C_4_LPCG), 16, FUNCTION_NAME(PD_DMA_I2C_4));
+ clks[IMX8QM_I2C0_CLK] = imx_clk_gate_scu("i2c0_clk", "i2c0_div", SC_R_I2C_0, SC_PM_CLK_PER, LPCG_ADDR(LPI2C_0_LPCG), 0, 0);
+ clks[IMX8QM_I2C1_CLK] = imx_clk_gate_scu("i2c1_clk", "i2c1_div", SC_R_I2C_1, SC_PM_CLK_PER, LPCG_ADDR(LPI2C_1_LPCG), 0, 0);
+ clks[IMX8QM_I2C2_CLK] = imx_clk_gate_scu("i2c2_clk", "i2c2_div", SC_R_I2C_2, SC_PM_CLK_PER, LPCG_ADDR(LPI2C_2_LPCG), 0, 0);
+ clks[IMX8QM_I2C3_CLK] = imx_clk_gate_scu("i2c3_clk", "i2c3_div", SC_R_I2C_3, SC_PM_CLK_PER, LPCG_ADDR(LPI2C_3_LPCG), 0, 0);
+ clks[IMX8QM_I2C4_CLK] = imx_clk_gate_scu("i2c4_clk", "i2c4_div", SC_R_I2C_4, SC_PM_CLK_PER, LPCG_ADDR(LPI2C_4_LPCG), 0, 0);
+ clks[IMX8QM_FTM0_IPG_CLK] = imx_clk_gate2_scu("ftm0_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(FTM_0_LPCG), 16, FUNCTION_NAME(PD_DMA_FTM_0));
+ clks[IMX8QM_FTM1_IPG_CLK] = imx_clk_gate2_scu("ftm1_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(FTM_1_LPCG), 16, FUNCTION_NAME(PD_DMA_FTM_1));
+ clks[IMX8QM_FTM0_CLK] = imx_clk_gate_scu("ftm0_clk", "ftm0_div", SC_R_FTM_0, SC_PM_CLK_PER, LPCG_ADDR(FTM_0_LPCG), 0, 0);
+ clks[IMX8QM_FTM1_CLK] = imx_clk_gate_scu("ftm1_clk", "ftm1_div", SC_R_FTM_1, SC_PM_CLK_PER, LPCG_ADDR(FTM_1_LPCG), 0, 0);
+ clks[IMX8QM_ADC0_IPG_CLK] = imx_clk_gate2_scu("adc0_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(ADC_0_LPCG), 16, FUNCTION_NAME(PD_DMA_ADC_0));
+ clks[IMX8QM_ADC1_IPG_CLK] = imx_clk_gate2_scu("adc1_ipg_clk", "ipg_dma_clk_root", LPCG_ADDR(ADC_1_LPCG), 16, FUNCTION_NAME(PD_DMA_ADC_1));
+ clks[IMX8QM_ADC0_CLK] = imx_clk_gate_scu("adc0_clk", "adc0_div", SC_R_ADC_0, SC_PM_CLK_PER, LPCG_ADDR(ADC_0_LPCG), 0, 0);
+ clks[IMX8QM_ADC1_CLK] = imx_clk_gate_scu("adc1_clk", "adc1_div", SC_R_ADC_1, SC_PM_CLK_PER, LPCG_ADDR(ADC_1_LPCG), 0, 0);
+
+ /* LSIO SS */
+ clks[IMX8QM_PWM0_IPG_S_CLK] = imx_clk_gate_scu("pwm_0_ipg_s_clk", "pwm_0_div", SC_R_PWM_0, SC_PM_CLK_PER, LPCG_ADDR(PWM_0_LPCG), 0x10, 0);
+ clks[IMX8QM_PWM0_IPG_SLV_CLK] = imx_clk_gate_scu("pwm_0_ipg_slv_clk", "pwm_0_ipg_s_clk", SC_R_PWM_0, SC_PM_CLK_PER, LPCG_ADDR(PWM_0_LPCG), 0x14, 0);
+ clks[IMX8QM_PWM0_IPG_MSTR_CLK] = imx_clk_gate2_scu("pwm_0_ipg_mstr_clk", "lsio_bus_clk_root", LPCG_ADDR(PWM_0_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_PWM_0));
+ clks[IMX8QM_PWM0_HF_CLK] = imx_clk_gate_scu("pwm_0_hf_clk", "pwm_0_ipg_slv_clk", SC_R_PWM_0, SC_PM_CLK_PER, LPCG_ADDR(PWM_0_LPCG), 4, 0);
+ clks[IMX8QM_PWM0_CLK] = imx_clk_gate_scu("pwm_0_clk", "pwm_0_ipg_slv_clk", SC_R_PWM_0, SC_PM_CLK_PER, LPCG_ADDR(PWM_0_LPCG), 0, 0);
+ clks[IMX8QM_PWM1_IPG_S_CLK] = imx_clk_gate_scu("pwm_1_ipg_s_clk", "pwm_1_div", SC_R_PWM_1, SC_PM_CLK_PER, LPCG_ADDR(PWM_1_LPCG), 0x10, 0);
+ clks[IMX8QM_PWM1_IPG_SLV_CLK] = imx_clk_gate_scu("pwm_1_ipg_slv_clk", "pwm_1_ipg_s_clk", SC_R_PWM_1, SC_PM_CLK_PER, LPCG_ADDR(PWM_1_LPCG), 0x14, 0);
+ clks[IMX8QM_PWM1_IPG_MSTR_CLK] = imx_clk_gate2_scu("pwm_1_ipg_mstr_clk", "lsio_bus_clk_root", LPCG_ADDR(PWM_1_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_PWM_1));
+ clks[IMX8QM_PWM1_HF_CLK] = imx_clk_gate_scu("pwm_1_hf_clk", "pwm_1_ipg_slv_clk", SC_R_PWM_1, SC_PM_CLK_PER, LPCG_ADDR(PWM_1_LPCG), 4, 0);
+ clks[IMX8QM_PWM1_CLK] = imx_clk_gate_scu("pwm_1_clk", "pwm_1_ipg_slv_clk", SC_R_PWM_1, SC_PM_CLK_PER, LPCG_ADDR(PWM_1_LPCG), 0, 0);
+ clks[IMX8QM_PWM2_IPG_S_CLK] = imx_clk_gate_scu("pwm_2_ipg_s_clk", "pwm_2_div", SC_R_PWM_2, SC_PM_CLK_PER, LPCG_ADDR(PWM_2_LPCG), 0x10, 0);
+ clks[IMX8QM_PWM2_IPG_SLV_CLK] = imx_clk_gate_scu("pwm_2_ipg_slv_clk", "pwm_2_ipg_s_clk", SC_R_PWM_2, SC_PM_CLK_PER, LPCG_ADDR(PWM_2_LPCG), 0x14, 0);
+ clks[IMX8QM_PWM2_IPG_MSTR_CLK] = imx_clk_gate2_scu("pwm_2_ipg_mstr_clk", "lsio_bus_clk_root", LPCG_ADDR(PWM_2_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_PWM_2));
+ clks[IMX8QM_PWM2_HF_CLK] = imx_clk_gate_scu("pwm_2_hf_clk", "pwm_2_ipg_slv_clk", SC_R_PWM_2, SC_PM_CLK_PER, LPCG_ADDR(PWM_2_LPCG), 4, 0);
+ clks[IMX8QM_PWM2_CLK] = imx_clk_gate_scu("pwm_2_clk", "pwm_2_ipg_slv_clk", SC_R_PWM_2, SC_PM_CLK_PER, LPCG_ADDR(PWM_2_LPCG), 0, 0);
+ clks[IMX8QM_PWM3_IPG_S_CLK] = imx_clk_gate_scu("pwm_3_ipg_s_clk", "pwm_3_div", SC_R_PWM_3, SC_PM_CLK_PER, LPCG_ADDR(PWM_3_LPCG), 0x10, 0);
+ clks[IMX8QM_PWM3_IPG_SLV_CLK] = imx_clk_gate_scu("pwm_3_ipg_slv_clk", "pwm_3_ipg_s_clk", SC_R_PWM_3, SC_PM_CLK_PER, LPCG_ADDR(PWM_3_LPCG), 0x14, 0);
+ clks[IMX8QM_PWM3_IPG_MSTR_CLK] = imx_clk_gate2_scu("pwm_3_ipg_mstr_clk", "lsio_bus_clk_root", LPCG_ADDR(PWM_3_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_PWM_3));
+ clks[IMX8QM_PWM3_HF_CLK] = imx_clk_gate_scu("pwm_3_hf_clk", "pwm_3_ipg_slv_clk", SC_R_PWM_3, SC_PM_CLK_PER, LPCG_ADDR(PWM_3_LPCG), 4, 0);
+ clks[IMX8QM_PWM3_CLK] = imx_clk_gate_scu("pwm_3_clk", "pwm_3_ipg_slv_clk", SC_R_PWM_3, SC_PM_CLK_PER, LPCG_ADDR(PWM_3_LPCG), 0, 0);
+ clks[IMX8QM_PWM4_IPG_S_CLK] = imx_clk_gate_scu("pwm_4_ipg_s_clk", "pwm_4_div", SC_R_PWM_4, SC_PM_CLK_PER, LPCG_ADDR(PWM_4_LPCG), 0x10, 0);
+ clks[IMX8QM_PWM4_IPG_SLV_CLK] = imx_clk_gate_scu("pwm_4_ipg_slv_clk", "pwm_4_ipg_s_clk", SC_R_PWM_4, SC_PM_CLK_PER, LPCG_ADDR(PWM_4_LPCG), 0x14, 0);
+ clks[IMX8QM_PWM4_IPG_MSTR_CLK] = imx_clk_gate2_scu("pwm_4_ipg_mstr_clk", "lsio_bus_clk_root", LPCG_ADDR(PWM_4_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_PWM_4));
+ clks[IMX8QM_PWM4_HF_CLK] = imx_clk_gate_scu("pwm_4_hf_clk", "pwm_4_ipg_slv_clk", SC_R_PWM_4, SC_PM_CLK_PER, LPCG_ADDR(PWM_4_LPCG), 4, 0);
+ clks[IMX8QM_PWM4_CLK] = imx_clk_gate_scu("pwm_4_clk", "pwm_4_ipg_slv_clk", SC_R_PWM_4, SC_PM_CLK_PER, LPCG_ADDR(PWM_4_LPCG), 0, 0);
+ clks[IMX8QM_PWM5_IPG_S_CLK] = imx_clk_gate_scu("pwm_5_ipg_s_clk", "pwm_5_div", SC_R_PWM_5, SC_PM_CLK_PER, LPCG_ADDR(PWM_5_LPCG), 0x10, 0);
+ clks[IMX8QM_PWM5_IPG_SLV_CLK] = imx_clk_gate_scu("pwm_5_ipg_slv_clk", "pwm_5_ipg_s_clk", SC_R_PWM_5, SC_PM_CLK_PER, LPCG_ADDR(PWM_5_LPCG), 0x14, 0);
+ clks[IMX8QM_PWM5_IPG_MSTR_CLK] = imx_clk_gate2_scu("pwm_5_ipg_mstr_clk", "lsio_bus_clk_root", LPCG_ADDR(PWM_5_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_PWM_5));
+ clks[IMX8QM_PWM5_HF_CLK] = imx_clk_gate_scu("pwm_5_hf_clk", "pwm_5_ipg_slv_clk", SC_R_PWM_5, SC_PM_CLK_PER, LPCG_ADDR(PWM_5_LPCG), 4, 0);
+ clks[IMX8QM_PWM5_CLK] = imx_clk_gate_scu("pwm_5_clk", "pwm_5_ipg_slv_clk", SC_R_PWM_5, SC_PM_CLK_PER, LPCG_ADDR(PWM_5_LPCG), 0, 0);
+ clks[IMX8QM_PWM6_IPG_S_CLK] = imx_clk_gate_scu("pwm_6_ipg_s_clk", "pwm_6_div", SC_R_PWM_6, SC_PM_CLK_PER, LPCG_ADDR(PWM_6_LPCG), 0x10, 0);
+ clks[IMX8QM_PWM6_IPG_SLV_CLK] = imx_clk_gate_scu("pwm_6_ipg_slv_clk", "pwm_6_ipg_s_clk", SC_R_PWM_6, SC_PM_CLK_PER, LPCG_ADDR(PWM_6_LPCG), 0x14, 0);
+ clks[IMX8QM_PWM6_IPG_MSTR_CLK] = imx_clk_gate2_scu("pwm_6_ipg_mstr_clk", "lsio_bus_clk_root", LPCG_ADDR(PWM_6_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_PWM_6));
+ clks[IMX8QM_PWM6_HF_CLK] = imx_clk_gate_scu("pwm_6_hf_clk", "pwm_6_ipg_slv_clk", SC_R_PWM_6, SC_PM_CLK_PER, LPCG_ADDR(PWM_6_LPCG), 4, 0);
+ clks[IMX8QM_PWM6_CLK] = imx_clk_gate_scu("pwm_6_clk", "pwm_6_ipg_slv_clk", SC_R_PWM_6, SC_PM_CLK_PER, LPCG_ADDR(PWM_6_LPCG), 0, 0);
+ clks[IMX8QM_PWM7_IPG_S_CLK] = imx_clk_gate_scu("pwm_7_ipg_s_clk", "pwm_7_div", SC_R_PWM_7, SC_PM_CLK_PER, LPCG_ADDR(PWM_7_LPCG), 0x10, 0);
+ clks[IMX8QM_PWM7_IPG_SLV_CLK] = imx_clk_gate_scu("pwm_7_ipg_slv_clk", "pwm_7_ipg_s_clk", SC_R_PWM_7, SC_PM_CLK_PER, LPCG_ADDR(PWM_7_LPCG), 0x14, 0);
+ clks[IMX8QM_PWM7_IPG_MSTR_CLK] = imx_clk_gate2_scu("pwm_7_ipg_mstr_clk", "lsio_bus_clk_root", LPCG_ADDR(PWM_7_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_PWM_7));
+ clks[IMX8QM_PWM7_HF_CLK] = imx_clk_gate_scu("pwm_7_hf_clk", "pwm_7_ipg_slv_clk", SC_R_PWM_7, SC_PM_CLK_PER, LPCG_ADDR(PWM_7_LPCG), 4, 0);
+ clks[IMX8QM_PWM7_CLK] = imx_clk_gate_scu("pwm_7_clk", "pwm_7_ipg_slv_clk", SC_R_PWM_7, SC_PM_CLK_PER, LPCG_ADDR(PWM_7_LPCG), 0, 0);
+ clks[IMX8QM_GPT0_IPG_S_CLK] = imx_clk_gate_scu("gpt_0_ipg_s_clk", "gpt_0_div", SC_R_GPT_0, SC_PM_CLK_PER, LPCG_ADDR(GPT_0_LPCG), 0x10, 0);
+ clks[IMX8QM_GPT0_IPG_SLV_CLK] = imx_clk_gate_scu("gpt_0_ipg_slv_clk", "gpt_0_ipg_s_clk", SC_R_GPT_0, SC_PM_CLK_PER, LPCG_ADDR(GPT_0_LPCG), 0x14, 0);
+ clks[IMX8QM_GPT0_CLK] = imx_clk_gate_scu("gpt_0_clk", "gpt_0_ipg_slv_clk", SC_R_GPT_0, SC_PM_CLK_PER, LPCG_ADDR(GPT_0_LPCG), 0, 0);
+ clks[IMX8QM_GPT0_IPG_MSTR_CLK] = imx_clk_gate2_scu("gpt_0_ipg_mstr_clk", "lsio_bus_clk_root", LPCG_ADDR(GPT_0_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_GPT_0));
+ clks[IMX8QM_GPT0_HF_CLK] = imx_clk_gate_scu("gpt_0_hf_clk", "gpt_0_ipg_slv_clk", SC_R_GPT_0, SC_PM_CLK_PER, LPCG_ADDR(GPT_0_LPCG), 4, 0);
+ clks[IMX8QM_GPT1_IPG_S_CLK] = imx_clk_gate_scu("gpt_1_ipg_s_clk", "gpt_1_div", SC_R_GPT_1, SC_PM_CLK_PER, LPCG_ADDR(GPT_1_LPCG), 0x10, 0);
+ clks[IMX8QM_GPT1_IPG_SLV_CLK] = imx_clk_gate_scu("gpt_1_ipg_slv_clk", "gpt_1_ipg_s_clk", SC_R_GPT_1, SC_PM_CLK_PER, LPCG_ADDR(GPT_1_LPCG), 0x14, 0);
+ clks[IMX8QM_GPT1_CLK] = imx_clk_gate_scu("gpt_1_clk", "gpt_1_ipg_slv_clk", SC_R_GPT_1, SC_PM_CLK_PER, LPCG_ADDR(GPT_1_LPCG), 0, 0);
+ clks[IMX8QM_GPT1_HF_CLK] = imx_clk_gate_scu("gpt_1_hf_clk", "gpt_1_ipg_slv_clk", SC_R_GPT_1, SC_PM_CLK_PER, LPCG_ADDR(GPT_1_LPCG), 4, 0);
+ clks[IMX8QM_GPT1_IPG_MSTR_CLK] = imx_clk_gate2_scu("gpt_1_ipg_mstr_clk", "lsio_bus_clk_root", LPCG_ADDR(GPT_1_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_GPT_1));
+ clks[IMX8QM_GPT2_IPG_S_CLK] = imx_clk_gate_scu("gpt_2_ipg_s_clk", "gpt_2_div", SC_R_GPT_2, SC_PM_CLK_PER, LPCG_ADDR(GPT_2_LPCG), 0x10, 0);
+ clks[IMX8QM_GPT2_IPG_SLV_CLK] = imx_clk_gate_scu("gpt_2_ipg_slv_clk", "gpt_2_ipg_s_clk", SC_R_GPT_2, SC_PM_CLK_PER, LPCG_ADDR(GPT_2_LPCG), 0x14, 0);
+ clks[IMX8QM_GPT2_CLK] = imx_clk_gate_scu("gpt_2_clk", "gpt_2_ipg_slv_clk", SC_R_GPT_2, SC_PM_CLK_PER, LPCG_ADDR(GPT_2_LPCG), 0, 0);
+ clks[IMX8QM_GPT2_HF_CLK] = imx_clk_gate_scu("gpt_2_hf_clk", "gpt_2_ipg_slv_clk", SC_R_GPT_2, SC_PM_CLK_PER, LPCG_ADDR(GPT_2_LPCG), 4, 0);
+ clks[IMX8QM_GPT2_IPG_MSTR_CLK] = imx_clk_gate2_scu("gpt_2_ipg_mstr_clk", "lsio_bus_clk_root", LPCG_ADDR(GPT_2_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_GPT_2));
+ clks[IMX8QM_GPT3_IPG_S_CLK] = imx_clk_gate_scu("gpt_3_ipg_s_clk", "gpt_3_div", SC_R_GPT_3, SC_PM_CLK_PER, LPCG_ADDR(GPT_3_LPCG), 0x10, 0);
+ clks[IMX8QM_GPT3_IPG_SLV_CLK] = imx_clk_gate_scu("gpt_3_ipg_slv_clk", "gpt_3_ipg_s_clk", SC_R_GPT_3, SC_PM_CLK_PER, LPCG_ADDR(GPT_3_LPCG), 0x14, 0);
+ clks[IMX8QM_GPT3_CLK] = imx_clk_gate_scu("gpt_3_clk", "gpt_3_ipg_slv_clk", SC_R_GPT_3, SC_PM_CLK_PER, LPCG_ADDR(GPT_3_LPCG), 0, 0);
+ clks[IMX8QM_GPT3_HF_CLK] = imx_clk_gate_scu("gpt_3_hf_clk", "gpt_3_ipg_slv_clk", SC_R_GPT_3, SC_PM_CLK_PER, LPCG_ADDR(GPT_3_LPCG), 4, 0);
+ clks[IMX8QM_GPT3_IPG_MSTR_CLK] = imx_clk_gate2_scu("gpt_3_ipg_mstr_clk", "lsio_bus_clk_root", LPCG_ADDR(GPT_3_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_GPT_3));
+ clks[IMX8QM_GPT4_IPG_S_CLK] = imx_clk_gate_scu("gpt_4_ipg_s_clk", "gpt_4_div", SC_R_GPT_4, SC_PM_CLK_PER, LPCG_ADDR(GPT_4_LPCG), 0x10, 0);
+ clks[IMX8QM_GPT4_IPG_SLV_CLK] = imx_clk_gate_scu("gpt_4_ipg_slv_clk", "gpt_4_ipg_s_clk", SC_R_GPT_4, SC_PM_CLK_PER, LPCG_ADDR(GPT_4_LPCG), 0x14, 0);
+ clks[IMX8QM_GPT4_CLK] = imx_clk_gate_scu("gpt_4_clk", "gpt_4_ipg_slv_clk", SC_R_GPT_4, SC_PM_CLK_PER, LPCG_ADDR(GPT_4_LPCG), 0, 0);
+ clks[IMX8QM_GPT4_HF_CLK] = imx_clk_gate_scu("gpt_4_hf_clk", "gpt_4_ipg_slv_clk", SC_R_GPT_4, SC_PM_CLK_PER, LPCG_ADDR(GPT_4_LPCG), 4, 0);
+ clks[IMX8QM_GPT4_IPG_MSTR_CLK] = imx_clk_gate2_scu("gpt_4_ipg_mstr_clk", "lsio_bus_clk_root", LPCG_ADDR(GPT_4_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_GPT_4));
+ clks[IMX8QM_FSPI0_HCLK] = imx_clk_gate2_scu("fspi0_hclk_clk", "lsio_mem_clk_root", LPCG_ADDR(FSPI_0_LPCG), 0x10, FUNCTION_NAME(PD_LSIO_FSPI_0));
+ clks[IMX8QM_FSPI0_IPG_S_CLK] = imx_clk_gate2_scu("fspi0_ipg_s_clk", "lsio_bus_clk_root", LPCG_ADDR(FSPI_0_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_FSPI_0));
+ clks[IMX8QM_FSPI0_IPG_CLK] = imx_clk_gate2_scu("fspi0_ipg_clk", "fspi0_ipg_s_clk", LPCG_ADDR(FSPI_0_LPCG), 0x14, FUNCTION_NAME(PD_LSIO_FSPI_0));
+ clks[IMX8QM_FSPI0_CLK] = imx_clk_gate_scu("fspi_0_clk", "fspi_0_div", SC_R_FSPI_0, SC_PM_CLK_PER, LPCG_ADDR(FSPI_0_LPCG), 0, 0);
+ clks[IMX8QM_FSPI1_HCLK] = imx_clk_gate2_scu("fspi1_hclk_clk", "lsio_mem_clk_root", LPCG_ADDR(FSPI_1_LPCG), 0x10, FUNCTION_NAME(PD_LSIO_FSPI_1));
+ clks[IMX8QM_FSPI1_IPG_S_CLK] = imx_clk_gate2_scu("fspi1_ipg_s_clk", "lsio_bus_clk_root", LPCG_ADDR(FSPI_1_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_FSPI_1));
+ clks[IMX8QM_FSPI1_IPG_CLK] = imx_clk_gate2_scu("fspi1_ipg_clk", "fspi1_ipg_s_clk", LPCG_ADDR(FSPI_1_LPCG), 0x14, FUNCTION_NAME(PD_LSIO_FSPI_1));
+ clks[IMX8QM_FSPI1_CLK] = imx_clk_gate_scu("fspi_1_clk", "fspi_1_div", SC_R_FSPI_1, SC_PM_CLK_PER, LPCG_ADDR(FSPI_1_LPCG), 0, 0);
+
+ clks[IMX8QM_LSIO_MU5A_IPG_S_CLK] = imx_clk_gate2_scu("mu5_a_ipg_s_clk", "lsio_bus_clk_root", LPCG_ADDR(MU_5A_LPCG), 0x10, FUNCTION_NAME(PD_LSIO_MU5A));
+ clks[IMX8QM_LSIO_MU5A_IPG_CLK] = imx_clk_gate2_scu("mu5_a_ipg_clk", "mu5_a_ipg_s_clk", LPCG_ADDR(MU_5A_LPCG), 0x0, FUNCTION_NAME(PD_LSIO_MU5A));
+ clks[IMX8QM_LSIO_MU6A_IPG_S_CLK] = imx_clk_gate2_scu("mu6_a_ipg_s_clk", "lsio_bus_clk_root", LPCG_ADDR(MU_6A_LPCG), 0x10, FUNCTION_NAME(PD_LSIO_MU6A));
+ clks[IMX8QM_LSIO_MU6A_IPG_CLK] = imx_clk_gate2_scu("mu6_a_ipg_clk", "mu6_a_ipg_s_clk", LPCG_ADDR(MU_6A_LPCG), 0x0, FUNCTION_NAME(PD_LSIO_MU6A));
+ /* Audio */
+ clks[IMX8QM_AUD_ACM_AUD_PLL_CLK0_CLK] = imx_clk_gate_scu("aud_acm_aud_pll_clk0_clk", "aud_acm_aud_pll_clk0_div", SC_R_AUDIO_PLL_0, SC_PM_CLK_MISC0, LPCG_ADDR(AUD_PLL_CLK0_LPCG), 0, 0);
+ clks[IMX8QM_AUD_ACM_AUD_PLL_CLK1_CLK] = imx_clk_gate_scu("aud_acm_aud_pll_clk1_clk", "aud_acm_aud_pll_clk1_div", SC_R_AUDIO_PLL_1, SC_PM_CLK_MISC0, LPCG_ADDR(AUD_PLL_CLK1_LPCG), 0, 0);
+ clks[IMX8QM_AUD_ACM_AUD_REC_CLK0_CLK] = imx_clk_gate_scu("aud_acm_aud_rec_clk0_clk", "aud_acm_aud_rec_clk0_div", SC_R_AUDIO_PLL_0, SC_PM_CLK_MISC1, LPCG_ADDR(AUD_REC_CLK0_LPCG), 0, 0);
+ clks[IMX8QM_AUD_ACM_AUD_REC_CLK1_CLK] = imx_clk_gate_scu("aud_acm_aud_rec_clk1_clk", "aud_acm_aud_rec_clk1_div", SC_R_AUDIO_PLL_1, SC_PM_CLK_MISC1, LPCG_ADDR(AUD_REC_CLK1_LPCG), 0, 0);
+
+ clks[IMX8QM_HDMI_RX_MCLK] = imx_clk_fixed("hdmi_rx_mclk", 0);
+ clks[IMX8QM_EXT_AUD_MCLK0] = imx_clk_fixed("ext_aud_mclk0", 0);
+ clks[IMX8QM_EXT_AUD_MCLK1] = imx_clk_fixed("ext_aud_mclk1", 0);
+ clks[IMX8QM_ESAI0_RX_CLK] = imx_clk_fixed("esai0_rx_clk", 0);
+ clks[IMX8QM_ESAI0_RX_HF_CLK] = imx_clk_fixed("esai0_rx_hf_clk", 0);
+ clks[IMX8QM_ESAI0_TX_CLK] = imx_clk_fixed("esai0_tx_clk", 0);
+ clks[IMX8QM_ESAI0_TX_HF_CLK] = imx_clk_fixed("esai0_tx_hf_clk", 0);
+ clks[IMX8QM_ESAI1_RX_CLK] = imx_clk_fixed("esai1_rx_clk", 0);
+ clks[IMX8QM_ESAI1_RX_HF_CLK] = imx_clk_fixed("esai1_rx_hf_clk", 0);
+ clks[IMX8QM_ESAI1_TX_CLK] = imx_clk_fixed("esai1_tx_clk", 0);
+ clks[IMX8QM_ESAI1_TX_HF_CLK] = imx_clk_fixed("esai1_tx_hf_clk", 0);
+ clks[IMX8QM_SPDIF0_RX] = imx_clk_fixed("spdif0_rx", 0);
+ clks[IMX8QM_SPDIF1_RX] = imx_clk_fixed("spdif1_rx", 0);
+ clks[IMX8QM_SAI0_RX_BCLK] = imx_clk_fixed("sai0_rx_bclk", 0);
+ clks[IMX8QM_SAI0_TX_BCLK] = imx_clk_fixed("sai0_tx_bclk", 0);
+ clks[IMX8QM_SAI1_RX_BCLK] = imx_clk_fixed("sai1_rx_bclk", 0);
+ clks[IMX8QM_SAI1_TX_BCLK] = imx_clk_fixed("sai1_tx_bclk", 0);
+ clks[IMX8QM_SAI2_RX_BCLK] = imx_clk_fixed("sai2_rx_bclk", 0);
+ clks[IMX8QM_SAI3_RX_BCLK] = imx_clk_fixed("sai3_rx_bclk", 0);
+ clks[IMX8QM_HDMI_RX_SAI0_RX_BCLK] = imx_clk_fixed("hdmi_rx_sai0_rx_bclk", 0);
+ clks[IMX8QM_SAI6_RX_BCLK] = imx_clk_fixed("sai6_rx_bclk", 0);
+ clks[IMX8QM_HDMI_TX_SAI0_TX_BCLK] = imx_clk_fixed("hdmi_tx_sai0_tx_bclk", 0);
+ clks[IMX8QM_CM40_IPG_CLK] = imx_clk_fixed("ipg_cm40_clk_root", SC_132MHZ);
+ clks[IMX8QM_CM41_IPG_CLK] = imx_clk_fixed("ipg_cm41_clk_root", SC_132MHZ);
+
+ np_acm = of_find_compatible_node(NULL, NULL, "nxp,imx8qm-acm");
+ if (np_acm) {
+ base_acm = of_iomap(np_acm, 0);
+ WARN_ON(!base_acm);
+
+ clks[IMX8QM_ACM_AUD_CLK0_SEL] = imx_clk_mux_scu("acm_aud_clk0_sel", base_acm + 0x00000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels), FUNCTION_NAME(PD_AUDIO));
+ clks[IMX8QM_ACM_AUD_CLK0_CLK] = imx_clk_gate_scu("acm_aud_clk0_clk", "acm_aud_clk0_sel", SC_R_AUDIO_CLK_0, SC_PM_CLK_SLV_BUS, NULL, 0, 0);
+
+ clks[IMX8QM_ACM_AUD_CLK1_SEL] = imx_clk_mux_scu("acm_aud_clk1_sel", base_acm + 0x10000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels), FUNCTION_NAME(PD_AUDIO));
+ clks[IMX8QM_ACM_AUD_CLK1_CLK] = imx_clk_gate_scu("acm_aud_clk1_clk", "acm_aud_clk1_sel", SC_R_AUDIO_CLK_1, SC_PM_CLK_SLV_BUS, NULL, 0, 0);
+ clks[IMX8QM_ACM_MCLKOUT0_SEL] = imx_clk_mux_scu("acm_mclkout0_sel", base_acm + 0x20000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels), FUNCTION_NAME(PD_AUDIO));
+ clks[IMX8QM_ACM_MCLKOUT1_SEL] = imx_clk_mux_scu("acm_mclkout1_sel", base_acm + 0x30000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels), FUNCTION_NAME(PD_AUDIO));
+ clks[IMX8QM_ACM_SAI0_MCLK_SEL] = imx_clk_mux_scu("acm_sai0_mclk_sel", base_acm + 0xE0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels), FUNCTION_NAME(PD_AUD_SAI_0));
+ clks[IMX8QM_ACM_SAI1_MCLK_SEL] = imx_clk_mux_scu("acm_sai1_mclk_sel", base_acm + 0xF0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels), FUNCTION_NAME(PD_AUD_SAI_1));
+ clks[IMX8QM_ACM_SAI2_MCLK_SEL] = imx_clk_mux_scu("acm_sai2_mclk_sel", base_acm + 0x100000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels), FUNCTION_NAME(PD_AUD_SAI_2));
+ clks[IMX8QM_ACM_SAI3_MCLK_SEL] = imx_clk_mux_scu("acm_sai3_mclk_sel", base_acm + 0x110000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels), FUNCTION_NAME(PD_AUD_SAI_3));
+ clks[IMX8QM_ACM_HDMI_RX_SAI0_MCLK_SEL] = imx_clk_mux_scu("acm_hdmi_rx_sai0_mclk_sel", base_acm + 0x120000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels), FUNCTION_NAME(PD_AUD_SAI_4));
+ clks[IMX8QM_ACM_HDMI_TX_SAI0_MCLK_SEL] = imx_clk_mux_scu("acm_hdmi_tx_sai0_mclk_sel", base_acm + 0x130000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels), FUNCTION_NAME(PD_AUD_SAI_5));
+ clks[IMX8QM_ACM_SAI6_MCLK_SEL] = imx_clk_mux_scu("acm_sai6_mclk_sel", base_acm + 0x140000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels), FUNCTION_NAME(PD_AUD_SAI_6));
+ clks[IMX8QM_ACM_SAI7_MCLK_SEL] = imx_clk_mux_scu("acm_sai7_mclk_sel", base_acm + 0x150000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels), FUNCTION_NAME(PD_AUD_SAI_7));
+ clks[IMX8QM_ACM_SPDIF0_TX_CLK_SEL] = imx_clk_mux_scu("acm_spdif0_mclk_sel", base_acm + 0x1A0000, 0, 2, spdif_mclk_sels, ARRAY_SIZE(spdif_mclk_sels), FUNCTION_NAME(PD_AUD_SPDIF_0));
+ clks[IMX8QM_ACM_SPDIF1_TX_CLK_SEL] = imx_clk_mux_scu("acm_spdif1_mclk_sel", base_acm + 0x1B0000, 0, 2, spdif_mclk_sels, ARRAY_SIZE(spdif_mclk_sels), FUNCTION_NAME(PD_AUD_SPDIF_1));
+ clks[IMX8QM_ACM_MQS_TX_CLK_SEL] = imx_clk_mux_scu("acm_mqs_mclk_sel", base_acm + 0x1C0000, 0, 2, mqs_mclk_sels, ARRAY_SIZE(mqs_mclk_sels), FUNCTION_NAME(PD_AUD_MQS_0));
+ clks[IMX8QM_ACM_ASRC0_MUX_CLK_SEL] = imx_clk_mux_scu("acm_asrc0_mclk_sel", base_acm + 0x40000, 0, 2, asrc_mux_clk_sels, ARRAY_SIZE(asrc_mux_clk_sels), FUNCTION_NAME(PD_AUD_ASRC_0));
+ clks[IMX8QM_ACM_ASRC1_MUX_CLK_SEL] = imx_clk_mux_scu("acm_asrc1_mclk_sel", base_acm + 0x50000, 0, 2, asrc_mux_clk_sels, ARRAY_SIZE(asrc_mux_clk_sels), FUNCTION_NAME(PD_AUD_ASRC_1));
+ clks[IMX8QM_ACM_ESAI0_MCLK_SEL] = imx_clk_mux_scu("acm_esai0_mclk_sel", base_acm + 0x60000, 0, 2, esai_mclk_sels, ARRAY_SIZE(esai_mclk_sels), FUNCTION_NAME(PD_AUD_ESAI_0));
+ clks[IMX8QM_ACM_ESAI1_MCLK_SEL] = imx_clk_mux_scu("acm_esai1_mclk_sel", base_acm + 0x70000, 0, 2, esai_mclk_sels, ARRAY_SIZE(esai_mclk_sels), FUNCTION_NAME(PD_AUD_ESAI_1));
+ } else
+ printk("clk-imx8qm: missing acm node, skipping\n");
+
+ clks[IMX8QM_AUD_AMIX_IPG] = imx_clk_gate2_scu("aud_amix_ipg_clk", "ipg_aud_clk_root", LPCG_ADDR(AUD_AMIX_LPCG), 0, FUNCTION_NAME(PD_AUD_AMIX));
+ clks[IMX8QM_AUD_ESAI_0_IPG] = imx_clk_gate2_scu("aud_esai0_ipg_clk", "ipg_aud_clk_root", LPCG_ADDR(AUD_ESAI_0_LPCG), 0, FUNCTION_NAME(PD_AUD_ESAI_0));
+ clks[IMX8QM_AUD_ESAI_1_IPG] = imx_clk_gate2_scu("aud_esai1_ipg_clk", "ipg_aud_clk_root", LPCG_ADDR(AUD_ESAI_1_LPCG), 0, FUNCTION_NAME(PD_AUD_ESAI_1));
+ clks[IMX8QM_AUD_ESAI_0_EXTAL_IPG] = imx_clk_gate2_scu("aud_esai0_extal_ipg_clk", "acm_esai0_mclk_sel", LPCG_ADDR(AUD_ESAI_0_LPCG), 16, FUNCTION_NAME(PD_AUD_ESAI_0));
+ clks[IMX8QM_AUD_ESAI_1_EXTAL_IPG] = imx_clk_gate2_scu("aud_esai1_extal_ipg_clk", "acm_esai1_mclk_sel", LPCG_ADDR(AUD_ESAI_1_LPCG), 16, FUNCTION_NAME(PD_AUD_ESAI_1));
+ clks[IMX8QM_AUD_SAI_0_IPG_S] = imx_clk_gate2_scu("aud_sai0_ipg_s_clk", "ipg_aud_clk_root", LPCG_ADDR(AUD_SAI_0_LPCG), 8, FUNCTION_NAME(PD_AUD_SAI_0));
+ clks[IMX8QM_AUD_SAI_0_IPG] = imx_clk_gate2_scu("aud_sai0_ipg_clk", "aud_sai0_ipg_s_clk", LPCG_ADDR(AUD_SAI_0_LPCG), 0, FUNCTION_NAME(PD_AUD_SAI_0));
+ clks[IMX8QM_AUD_SAI_0_MCLK] = imx_clk_gate2_scu("aud_sai0_mclk_clk", "acm_sai0_mclk_sel", LPCG_ADDR(AUD_SAI_0_LPCG), 16, FUNCTION_NAME(PD_AUD_SAI_0));
+ clks[IMX8QM_AUD_SAI_1_IPG_S] = imx_clk_gate2_scu("aud_sai1_ipg_s_clk", "ipg_aud_clk_root", LPCG_ADDR(AUD_SAI_1_LPCG), 8, FUNCTION_NAME(PD_AUD_SAI_1));
+ clks[IMX8QM_AUD_SAI_1_IPG] = imx_clk_gate2_scu("aud_sai1_ipg_clk", "aud_sai1_ipg_s_clk", LPCG_ADDR(AUD_SAI_1_LPCG), 0, FUNCTION_NAME(PD_AUD_SAI_1));
+ clks[IMX8QM_AUD_SAI_1_MCLK] = imx_clk_gate2_scu("aud_sai1_mclk_clk", "acm_sai1_mclk_sel", LPCG_ADDR(AUD_SAI_1_LPCG), 16, FUNCTION_NAME(PD_AUD_SAI_1));
+ clks[IMX8QM_AUD_SAI_2_IPG_S] = imx_clk_gate2_scu("aud_sai2_ipg_s_clk", "ipg_aud_clk_root", LPCG_ADDR(AUD_SAI_2_LPCG), 8, FUNCTION_NAME(PD_AUD_SAI_2));
+ clks[IMX8QM_AUD_SAI_2_IPG] = imx_clk_gate2_scu("aud_sai2_ipg_clk", "aud_sai2_ipg_s_clk", LPCG_ADDR(AUD_SAI_2_LPCG), 0, FUNCTION_NAME(PD_AUD_SAI_2));
+ clks[IMX8QM_AUD_SAI_2_MCLK] = imx_clk_gate2_scu("aud_sai2_mclk_clk", "acm_sai2_mclk_sel", LPCG_ADDR(AUD_SAI_2_LPCG), 16, FUNCTION_NAME(PD_AUD_SAI_2));
+ clks[IMX8QM_AUD_SAI_3_IPG_S] = imx_clk_gate2_scu("aud_sai3_ipg_s_clk", "ipg_aud_clk_root", LPCG_ADDR(AUD_SAI_3_LPCG), 8, FUNCTION_NAME(PD_AUD_SAI_3));
+ clks[IMX8QM_AUD_SAI_3_IPG] = imx_clk_gate2_scu("aud_sai3_ipg_clk", "aud_sai3_ipg_s_clk", LPCG_ADDR(AUD_SAI_3_LPCG), 0, FUNCTION_NAME(PD_AUD_SAI_3));
+ clks[IMX8QM_AUD_SAI_3_MCLK] = imx_clk_gate2_scu("aud_sai3_mclk_clk", "acm_sai3_mclk_sel", LPCG_ADDR(AUD_SAI_3_LPCG), 16, FUNCTION_NAME(PD_AUD_SAI_3));
+ clks[IMX8QM_AUD_SAI_6_IPG_S] = imx_clk_gate2_scu("aud_sai6_ipg_s_clk", "ipg_aud_clk_root", LPCG_ADDR(AUD_SAI_6_LPCG), 8, FUNCTION_NAME(PD_AUD_SAI_6));
+ clks[IMX8QM_AUD_SAI_6_IPG] = imx_clk_gate2_scu("aud_sai6_ipg_clk", "aud_sai6_ipg_s_clk", LPCG_ADDR(AUD_SAI_6_LPCG), 0, FUNCTION_NAME(PD_AUD_SAI_6));
+ clks[IMX8QM_AUD_SAI_6_MCLK] = imx_clk_gate2_scu("aud_sai6_mclk_clk", "acm_sai6_mclk_sel", LPCG_ADDR(AUD_SAI_6_LPCG), 16, FUNCTION_NAME(PD_AUD_SAI_6));
+ clks[IMX8QM_AUD_SAI_7_IPG_S] = imx_clk_gate2_scu("aud_sai7_ipg_s_clk", "ipg_aud_clk_root", LPCG_ADDR(AUD_SAI_7_LPCG), 8, FUNCTION_NAME(PD_AUD_SAI_7));
+ clks[IMX8QM_AUD_SAI_7_IPG] = imx_clk_gate2_scu("aud_sai7_ipg_clk", "aud_sai7_ipg_s_clk", LPCG_ADDR(AUD_SAI_7_LPCG), 0, FUNCTION_NAME(PD_AUD_SAI_7));
+ clks[IMX8QM_AUD_SAI_7_MCLK] = imx_clk_gate2_scu("aud_sai7_mclk_clk", "acm_sai7_mclk_sel", LPCG_ADDR(AUD_SAI_7_LPCG), 16, FUNCTION_NAME(PD_AUD_SAI_7));
+ clks[IMX8QM_AUD_SAI_HDMIRX0_IPG_S] = imx_clk_gate2_scu("aud_sai_hdmirx0_ipg_s_clk", "ipg_aud_clk_root", LPCG_ADDR(AUD_HDMI_RX_SAI_0_LPCG), 8, FUNCTION_NAME(PD_AUD_SAI_4));
+ clks[IMX8QM_AUD_SAI_HDMIRX0_IPG] = imx_clk_gate2_scu("aud_sai_hdmirx0_ipg_clk", "aud_sai_hdmirx0_ipg_s_clk", LPCG_ADDR(AUD_HDMI_RX_SAI_0_LPCG), 0, FUNCTION_NAME(PD_AUD_SAI_4));
+ clks[IMX8QM_AUD_SAI_HDMIRX0_MCLK] = imx_clk_gate2_scu("aud_sai_hdmirx0_mclk_clk", "acm_hdmi_rx_sai0_mclk_sel", LPCG_ADDR(AUD_HDMI_RX_SAI_0_LPCG), 16, FUNCTION_NAME(PD_AUD_SAI_4));
+ clks[IMX8QM_AUD_SAI_HDMITX0_IPG_S] = imx_clk_gate2_scu("aud_sai_hdmitx0_ipg_s_clk", "ipg_aud_clk_root", LPCG_ADDR(AUD_HDMI_TX_SAI_0_LPCG), 8, FUNCTION_NAME(PD_AUD_SAI_5));
+ clks[IMX8QM_AUD_SAI_HDMITX0_IPG] = imx_clk_gate2_scu("aud_sai_hdmitx0_ipg_clk", "aud_sai_hdmitx0_ipg_s_clk", LPCG_ADDR(AUD_HDMI_TX_SAI_0_LPCG), 0, FUNCTION_NAME(PD_AUD_SAI_5));
+ clks[IMX8QM_AUD_SAI_HDMITX0_MCLK] = imx_clk_gate2_scu("aud_sai_hdmitx0_mclk_clk", "acm_hdmi_tx_sai0_mclk_sel", LPCG_ADDR(AUD_HDMI_TX_SAI_0_LPCG), 16, FUNCTION_NAME(PD_AUD_SAI_5));
+ clks[IMX8QM_AUD_MQS_IPG] = imx_clk_gate2_scu("aud_mqs_ipg", "ipg_aud_clk_root", LPCG_ADDR(AUD_MQS_LPCG), 0, FUNCTION_NAME(PD_AUD_MQS_0));
+ clks[IMX8QM_AUD_MQS_HMCLK] = imx_clk_gate2_scu("aud_mqs_hm_clk", "acm_mqs_mclk_sel", LPCG_ADDR(AUD_MQS_LPCG), 16, FUNCTION_NAME(PD_AUD_MQS_0));
+ clks[IMX8QM_AUD_GPT5_IPG_S] = imx_clk_gate2_scu("aud_gpt5_ipg", "ipg_aud_clk_root", LPCG_ADDR(AUD_GPT_5_LPCG), 0, FUNCTION_NAME(PD_AUD_GPT_5));
+ clks[IMX8QM_AUD_GPT5_24M_CLK] = imx_clk_gate2_scu("aud_gpt5_24MHz", "xtal_24MHz", LPCG_ADDR(AUD_GPT_5_LPCG), 20, FUNCTION_NAME(PD_AUD_GPT_5));
+ clks[IMX8QM_AUD_GPT6_IPG_S] = imx_clk_gate2_scu("aud_gpt6_ipg", "ipg_aud_clk_root", LPCG_ADDR(AUD_GPT_6_LPCG), 0, FUNCTION_NAME(PD_AUD_GPT_6));
+ clks[IMX8QM_AUD_GPT6_24M_CLK] = imx_clk_gate2_scu("aud_gpt6_24MHz", "xtal_24MHz", LPCG_ADDR(AUD_GPT_6_LPCG), 20, FUNCTION_NAME(PD_AUD_GPT_6));
+ clks[IMX8QM_AUD_GPT7_IPG_S] = imx_clk_gate2_scu("aud_gpt7_ipg", "ipg_aud_clk_root", LPCG_ADDR(AUD_GPT_7_LPCG), 0, FUNCTION_NAME(PD_AUD_GPT_7));
+ clks[IMX8QM_AUD_GPT7_24M_CLK] = imx_clk_gate2_scu("aud_gpt7_24MHz", "xtal_24MHz", LPCG_ADDR(AUD_GPT_7_LPCG), 20, FUNCTION_NAME(PD_AUD_GPT_7));
+ clks[IMX8QM_AUD_GPT8_IPG_S] = imx_clk_gate2_scu("aud_gpt8_ipg", "ipg_aud_clk_root", LPCG_ADDR(AUD_GPT_8_LPCG), 0, FUNCTION_NAME(PD_AUD_GPT_8));
+ clks[IMX8QM_AUD_GPT8_24M_CLK] = imx_clk_gate2_scu("aud_gpt8_24MHz", "xtal_24MHz", LPCG_ADDR(AUD_GPT_8_LPCG), 20, FUNCTION_NAME(PD_AUD_GPT_8));
+ clks[IMX8QM_AUD_GPT9_IPG_S] = imx_clk_gate2_scu("aud_gpt9_ipg", "ipg_aud_clk_root", LPCG_ADDR(AUD_GPT_9_LPCG), 0, FUNCTION_NAME(PD_AUD_GPT_9));
+ clks[IMX8QM_AUD_GPT9_24M_CLK] = imx_clk_gate2_scu("aud_gpt9_24MHz", "xtal_24MHz", LPCG_ADDR(AUD_GPT_9_LPCG), 20, FUNCTION_NAME(PD_AUD_GPT_9));
+ clks[IMX8QM_AUD_GPT10_IPG_S] = imx_clk_gate2_scu("aud_gpt10_ipg", "ipg_aud_clk_root", LPCG_ADDR(AUD_GPT_10_LPCG), 0, FUNCTION_NAME(PD_AUD_GPT_9));
+ clks[IMX8QM_AUD_GPT10_24M_CLK] = imx_clk_gate2_scu("aud_gpt10_24MHz", "xtal_24MHz", LPCG_ADDR(AUD_GPT_10_LPCG), 20, FUNCTION_NAME(PD_AUD_GPT_9));
+ clks[IMX8QM_AUD_MCLKOUT0] = imx_clk_gate2_scu("aud_mclkout0", "acm_mclkout0_sel", LPCG_ADDR(AUD_MCLKOUT0_LPCG), 0, FUNCTION_NAME(PD_AUDIO));
+ clks[IMX8QM_AUD_MCLKOUT1] = imx_clk_gate2_scu("aud_mclkout1", "acm_mclkout1_sel", LPCG_ADDR(AUD_MCLKOUT1_LPCG), 0, FUNCTION_NAME(PD_AUDIO));
+ clks[IMX8QM_AUD_SPDIF_0_IPG_S] = imx_clk_gate2_scu("spdif0_ipg_s", "ipg_aud_clk_root", LPCG_ADDR(AUD_SPDIF_0_LPCG), 0, FUNCTION_NAME(PD_AUD_SPDIF_0));
+ clks[IMX8QM_AUD_SPDIF_0_GCLKW] = imx_clk_gate2_scu("spdif0_gclkw", "spdif0_ipg_s", LPCG_ADDR(AUD_SPDIF_0_LPCG), 16, FUNCTION_NAME(PD_AUD_SPDIF_0));
+ clks[IMX8QM_AUD_SPDIF_0_TX_CLK] = imx_clk_gate2_scu("spdif0_tx_clk", "acm_spdif0_mclk_sel", LPCG_ADDR(AUD_SPDIF_0_LPCG), 20, FUNCTION_NAME(PD_AUD_SPDIF_0));
+ clks[IMX8QM_AUD_SPDIF_1_IPG_S] = imx_clk_gate2_scu("spdif1_ipg_s", "ipg_aud_clk_root", LPCG_ADDR(AUD_SPDIF_1_LPCG), 0, FUNCTION_NAME(PD_AUD_SPDIF_1));
+ clks[IMX8QM_AUD_SPDIF_1_GCLKW] = imx_clk_gate2_scu("spdif1_gclkw", "spdif1_ipg_s", LPCG_ADDR(AUD_SPDIF_1_LPCG), 16, FUNCTION_NAME(PD_AUD_SPDIF_1));
+ clks[IMX8QM_AUD_SPDIF_1_TX_CLK] = imx_clk_gate2_scu("spdif1_tx_clk", "acm_spdif1_mclk_sel", LPCG_ADDR(AUD_SPDIF_1_LPCG), 20, FUNCTION_NAME(PD_AUD_SPDIF_1));
+ clks[IMX8QM_AUD_ASRC_0_IPG] = imx_clk_gate2_scu("aud_asrc0_ipg", "ipg_aud_clk_root", LPCG_ADDR(AUD_ASRC_0_LPCG), 0, FUNCTION_NAME(PD_AUD_ASRC_0));
+ clks[IMX8QM_AUD_ASRC_0_MEM] = imx_clk_gate2_scu("aud_asrc0_mem", "ipg_aud_clk_root", LPCG_ADDR(AUD_ASRC_0_LPCG), 8, FUNCTION_NAME(PD_AUD_ASRC_0));
+ clks[IMX8QM_AUD_ASRC_1_IPG] = imx_clk_gate2_scu("aud_asrc1_ipg", "ipg_aud_clk_root", LPCG_ADDR(AUD_ASRC_1_LPCG), 0, FUNCTION_NAME(PD_AUD_ASRC_1));
+ clks[IMX8QM_AUD_ASRC_1_MEM] = imx_clk_gate2_scu("aud_asrc1_mem", "ipg_aud_clk_root", LPCG_ADDR(AUD_ASRC_1_LPCG), 8, FUNCTION_NAME(PD_AUD_ASRC_1));
+ clks[IMX8QM_ACM_ASRC0_MUX_CLK_CLK] = imx_clk_gate_scu("aud_asrc0_mux_clk", "acm_asrc0_mclk_sel", SC_R_ASRC_0, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QM_ACM_ASRC1_MUX_CLK_CLK] = imx_clk_gate_scu("aud_asrc1_mux_clk", "acm_asrc1_mclk_sel", SC_R_ASRC_1, SC_PM_CLK_PER, NULL, 0, 0);
+
+ /* DSP */
+ clks[IMX8QM_AUD_DSP_ADB_ACLK] = imx_clk_gate2_scu("aud_dsp_adb_aclk", "ipg_aud_clk_root", LPCG_ADDR(AUD_DSP_LPCG), 16, FUNCTION_NAME(PD_AUD_DSP));
+ clks[IMX8QM_AUD_DSP_IPG] = imx_clk_gate2_scu("aud_dsp_ipg", "ipg_aud_clk_root", LPCG_ADDR(AUD_DSP_LPCG), 20, FUNCTION_NAME(PD_AUD_DSP));
+ clks[IMX8QM_AUD_DSP_CORE_CLK] = imx_clk_gate2_scu("aud_dsp_core_clk", "ipg_aud_clk_root", LPCG_ADDR(AUD_DSP_LPCG), 28, FUNCTION_NAME(PD_AUD_DSP));
+ clks[IMX8QM_AUD_OCRAM_IPG] = imx_clk_gate2_scu("aud_ocram_ipg", "ipg_aud_clk_root", LPCG_ADDR(AUD_OCRAM_LPCG), 16, FUNCTION_NAME(PD_AUD_OCRAM));
+
+ /* MIPI CSI */
+ clks[IMX8QM_CSI0_I2C0_IPG_CLK] = imx_clk_gate2_scu("mipi_csi0_i2c0_ipg_s", "ipg_mipi_csi_clk_root", LPCG_ADDR(MIPI_CSI_0_LPCG + 0x14), 16, FUNCTION_NAME(PD_MIPI_CSI0_I2C0));
+ clks[IMX8QM_CSI0_I2C0_CLK] = imx_clk_gate_scu("mipi_csi0_i2c0_clk", "mipi_csi0_i2c0_div", SC_R_CSI_0_I2C_0, SC_PM_CLK_PER, LPCG_ADDR(MIPI_CSI_0_LPCG + 0x14), 0, 0);
+ clks[IMX8QM_CSI0_PWM0_IPG_CLK] = imx_clk_gate2_scu("mipi_csi0_pwm0_ipg_s", "ipg_mipi_csi_clk_root", LPCG_ADDR(MIPI_CSI_0_LPCG + 0x10), 16, FUNCTION_NAME(PD_MIPI_CSI0_PWM));
+ clks[IMX8QM_CSI0_PWM0_CLK] = imx_clk_gate_scu("mipi_csi0_pwm0_clk", "mipi_csi0_pwm0_div", SC_R_CSI_0_PWM_0, SC_PM_CLK_PER, LPCG_ADDR(MIPI_CSI_0_LPCG + 0x10), 0, 0);
+ clks[IMX8QM_CSI0_CORE_CLK] = imx_clk_gate_scu("mipi_csi0_core_clk", "mipi_csi0_core_div", SC_R_CSI_0, SC_PM_CLK_PER, LPCG_ADDR(MIPI_CSI_0_LPCG + 0x18), 16, 0);
+ clks[IMX8QM_CSI0_ESC_CLK] = imx_clk_gate_scu("mipi_csi0_esc_clk", "mipi_csi0_esc_div", SC_R_CSI_0, SC_PM_CLK_MISC, LPCG_ADDR(MIPI_CSI_0_LPCG + 0x1C), 16, 0);
+ clks[IMX8QM_CSI1_I2C0_IPG_CLK] = imx_clk_gate2_scu("mipi_csi1_i2c0_ipg_s", "ipg_mipi_csi_clk_root", LPCG_ADDR(MIPI_CSI_1_LPCG + 0x14), 16, FUNCTION_NAME(PD_MIPI_CSI1_I2C0));
+ clks[IMX8QM_CSI1_I2C0_CLK] = imx_clk_gate_scu("mipi_csi1_i2c0_clk", "mipi_csi1_i2c0_div", SC_R_CSI_1_I2C_0, SC_PM_CLK_PER, LPCG_ADDR(MIPI_CSI_1_LPCG + 0x14), 0, 0);
+ clks[IMX8QM_CSI1_PWM0_IPG_CLK] = imx_clk_gate2_scu("mipi_csi1_pwm0_ipg_s", "ipg_mipi_csi_clk_root", LPCG_ADDR(MIPI_CSI_1_LPCG + 0x10), 16, FUNCTION_NAME(PD_MIPI_CSI0_PWM));
+ clks[IMX8QM_CSI1_PWM0_CLK] = imx_clk_gate_scu("mipi_csi1_pwm0_clk", "mipi_csi1_pwm0_div", SC_R_CSI_1_PWM_0, SC_PM_CLK_PER, LPCG_ADDR(MIPI_CSI_1_LPCG + 0x10), 0, 0);
+ clks[IMX8QM_CSI1_CORE_CLK] = imx_clk_gate_scu("mipi_csi1_core_clk", "mipi_csi1_core_div", SC_R_CSI_1, SC_PM_CLK_PER, LPCG_ADDR(MIPI_CSI_1_LPCG + 0x18), 16, 0);
+ clks[IMX8QM_CSI1_ESC_CLK] = imx_clk_gate_scu("mipi_csi1_esc_clk", "mipi_csi1_esc_div", SC_R_CSI_1, SC_PM_CLK_MISC, LPCG_ADDR(MIPI_CSI_1_LPCG + 0x1C), 16, 0);
+
+ /* RX-HDMI */
+ clks[IMX8QM_HDMI_RX_GPIO_IPG_S_CLK] = imx_clk_gate2_scu("hdmi_rx_gpio_ipg_s_clk", "ipg_hdmi_rx_clk_root", LPCG_ADDR(RX_HDMI_LPCG), 0, FUNCTION_NAME(PD_HDMI_RX));
+ clks[IMX8QM_HDMI_RX_PWM_IPG_S_CLK] = imx_clk_gate2_scu("hdmi_rx_pwm_ipg_s_clk", "ipg_hdmi_rx_clk_root", LPCG_ADDR(RX_HDMI_LPCG + 0x8), 0, FUNCTION_NAME(PD_HDMI_RX));
+ clks[IMX8QM_HDMI_RX_PWM_IPG_CLK] = imx_clk_gate2_scu("hdmi_rx_pwm_ipg_clk", "hdmi_rx_pwm_ipg_s_clk", LPCG_ADDR(RX_HDMI_LPCG + 0x4), 0, FUNCTION_NAME(PD_HDMI_RX));
+ clks[IMX8QM_HDMI_RX_I2C_IPG_S_CLK] = imx_clk_gate2_scu("hdmi_rx_i2c_ipg_s_clk", "ipg_hdmi_rx_clk_root", LPCG_ADDR(RX_HDMI_LPCG + 0x1C), 0, FUNCTION_NAME(PD_HDMI_RX_I2C));
+ clks[IMX8QM_HDMI_RX_I2C_IPG_CLK] = imx_clk_gate2_scu("hdmi_rx_i2c_ipg_clk", "hdmi_rx_i2c_ipg_s_clk", LPCG_ADDR(RX_HDMI_LPCG + 0x18), 0, FUNCTION_NAME(PD_HDMI_RX_I2C));
+ clks[IMX8QM_HDMI_RX_I2C_DIV_CLK] = imx_clk_gate2_scu("hdmi_rx_i2c0_div_clk", "hdmi_rx_i2c0_div", LPCG_ADDR(RX_HDMI_LPCG + 0x14), 0, FUNCTION_NAME(PD_HDMI_RX_I2C));
+ clks[IMX8QM_HDMI_RX_I2C0_CLK] = imx_clk_gate_scu("hdmi_rx_i2c0_clk", "hdmi_rx_i2c0_div_clk", SC_R_HDMI_RX_I2C_0, SC_PM_CLK_MISC2, LPCG_ADDR(RX_HDMI_LPCG + 0x10), 0, 0);
+ clks[IMX8QM_HDMI_RX_SPDIF_CLK] = imx_clk_gate_scu("hdmi_rx_spdif_clk", "hdmi_rx_spdif_bypass_clk", SC_R_HDMI_RX, SC_PM_CLK_MISC0, NULL, 0, 0);
+ clks[IMX8QM_HDMI_RX_HD_REF_CLK] = imx_clk_gate_scu("hdmi_rx_hd_ref_clk", "hdmi_rx_hd_ref_div", SC_R_HDMI_RX, SC_PM_CLK_MISC1, NULL, 0, 0);
+ clks[IMX8QM_HDMI_RX_HD_CORE_CLK] = imx_clk_gate_scu("hdmi_rx_hd_core_clk", "hdmi_rx_hd_core_div", SC_R_HDMI_RX, SC_PM_CLK_MISC2, LPCG_ADDR(RX_HDMI_LPCG + 0x28), 0, 0);
+ clks[IMX8QM_HDMI_RX_PXL_CLK] = imx_clk_gate_scu("hdmi_rx_pxl_clk", "hdmi_rx_pxl_div", SC_R_HDMI_RX, SC_PM_CLK_MISC3, LPCG_ADDR(RX_HDMI_LPCG + 0x2C), 0, 0);
+ clks[IMX8QM_HDMI_RX_I2S_CLK] = imx_clk_gate_scu("hdmi_rx_i2s_clk", "hdmi_rx_i2s_bypass_clk", SC_R_HDMI_RX, SC_PM_CLK_MISC4, NULL, 0, 0);
+ clks[IMX8QM_HDMI_RX_PWM_CLK] = imx_clk_gate_scu("hdmi_rx_pwm_clk", "hdmi_rx_pwm_div", SC_R_HDMI_RX_PWM_0, SC_PM_CLK_MISC2, LPCG_ADDR(RX_HDMI_LPCG + 0xC), 0, 0);
+ clks[IMX8QM_HDMI_RX_SINK_PCLK] = imx_clk_gate2_scu("hdmi_rx_sink_pclk", "ipg_hdmi_rx_clk_root", LPCG_ADDR(RX_HDMI_LPCG + 0x20), 0, FUNCTION_NAME(PD_HDMI_RX_BYPASS));
+ clks[IMX8QM_HDMI_RX_SINK_SCLK] = imx_clk_gate2_scu("hdmi_rx_sink_sclk", "ipg_hdmi_rx_clk_root", LPCG_ADDR(RX_HDMI_LPCG + 0x24), 0, FUNCTION_NAME(PD_HDMI_RX_BYPASS));
+ clks[IMX8QM_HDMI_RX_PXL_ENC_CLK] = imx_clk_gate2_scu("hdmi_rx_sink_enc_clk", "hdmi_rx_pxl_clk", LPCG_ADDR(RX_HDMI_LPCG + 0x30), 0, FUNCTION_NAME(PD_HDMI_RX_BYPASS));
+
+ /* MIPI-DI */
+ clks[IMX8QM_MIPI0_LIS_IPG_CLK] = imx_clk_gate2_scu("mipi0_lis_ipg_clk", "mipi0_clk_root", LPCG_ADDR(MIPI_DSI_0_LPCG + 0x0), 0, FUNCTION_NAME(PD_MIPI_0_DSI));
+ clks[IMX8QM_MIPI0_I2C0_DIV] = imx_clk_divider_scu("mipi0_i2c0_div", SC_R_MIPI_0_I2C_0, SC_PM_CLK_MISC2);
+ clks[IMX8QM_MIPI0_I2C0_CLK] = imx_clk_gate_scu("mipi0_i2c0_clk", "mipi0_i2c0_div", SC_R_MIPI_0_I2C_0, SC_PM_CLK_MISC2, LPCG_ADDR(MIPI_DSI_0_LPCG + 0x1c), 0, 0);
+ clks[IMX8QM_MIPI0_I2C0_IPG_S_CLK] = imx_clk_gate2_scu("mipi0_i2c0_ipg_s", "mipi0_clk_root", LPCG_ADDR(MIPI_DSI_0_LPCG + 0x18), 0, FUNCTION_NAME(PD_MIPI_0_DSI_I2C0));
+ clks[IMX8QM_MIPI0_I2C0_IPG_CLK] = imx_clk_gate2_scu("mipi0_i2c0_ipg", "mipi0_i2c0_ipg_s", LPCG_ADDR(MIPI_DSI_0_LPCG + 0x14), 0, FUNCTION_NAME(PD_MIPI_0_DSI_I2C0));
+ clks[IMX8QM_MIPI0_I2C1_DIV] = imx_clk_divider_scu("mipi0_i2c1_div", SC_R_MIPI_0_I2C_1, SC_PM_CLK_MISC2);
+ clks[IMX8QM_MIPI0_I2C1_CLK] = imx_clk_gate_scu("mipi0_i2c1_clk", "mipi0_i2c1_div", SC_R_MIPI_0_I2C_1, SC_PM_CLK_MISC2, LPCG_ADDR(MIPI_DSI_0_LPCG + 0x2C), 0, 0);
+ clks[IMX8QM_MIPI0_I2C1_IPG_S_CLK] = imx_clk_gate2_scu("mipi0_i2c1_ipg_s", "mipi0_clk_root", LPCG_ADDR(MIPI_DSI_0_LPCG + 0x28), 0, FUNCTION_NAME(PD_MIPI_0_DSI_I2C1));
+ clks[IMX8QM_MIPI0_I2C1_IPG_CLK] = imx_clk_gate2_scu("mipi0_i2c1_ipg", "mipi0_i2c1_ipg_s", LPCG_ADDR(MIPI_DSI_0_LPCG + 0x24), 0, FUNCTION_NAME(PD_MIPI_0_DSI_I2C1));
+ clks[IMX8QM_MIPI0_PWM0_CLK] = imx_clk_gate_scu("mipi0_pwm0_clk", "mipi0_pwm0_div", SC_R_MIPI_0_PWM_0, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QM_MIPI0_DSI_TX_ESC_CLK] = imx_clk_gate_scu("mipi0_dsi_tx_esc_clk", "mipi0_dsi_tx_esc_div", SC_R_MIPI_0, SC_PM_CLK_MST_BUS, NULL, 0, 0);
+ clks[IMX8QM_MIPI0_DSI_RX_ESC_CLK] = imx_clk_gate_scu("mipi0_dsi_rx_esc_clk", "mipi0_dsi_rx_esc_div", SC_R_MIPI_0, SC_PM_CLK_SLV_BUS, NULL, 0, 0);
+ clks[IMX8QM_MIPI0_PXL_CLK] = imx_clk_gate_scu("mipi0_pxl_clk", "mipi0_pxl_div", SC_R_MIPI_0, SC_PM_CLK_PER, NULL, 0, 0);
+
+ clks[IMX8QM_MIPI1_LIS_IPG_CLK] = imx_clk_gate2_scu("mipi1_lis_ipg_clk", "mipi1_clk_root", LPCG_ADDR(MIPI_DSI_1_LPCG + 0x0), 0, FUNCTION_NAME(PD_MIPI_1_DSI));
+
+ clks[IMX8QM_MIPI1_I2C0_DIV] = imx_clk_divider_scu("mipi1_i2c0_div", SC_R_MIPI_1_I2C_0, SC_PM_CLK_MISC2);
+ clks[IMX8QM_MIPI1_I2C0_CLK] = imx_clk_gate_scu("mipi1_i2c0_clk", "mipi1_i2c0_div", SC_R_MIPI_1_I2C_0, SC_PM_CLK_MISC2, LPCG_ADDR(MIPI_DSI_1_LPCG + 0x1c), 0, 0);
+ clks[IMX8QM_MIPI1_I2C0_IPG_S_CLK] = imx_clk_gate2_scu("mipi1_i2c0_ipg_s", "mipi1_clk_root", LPCG_ADDR(MIPI_DSI_1_LPCG + 0x18), 0, FUNCTION_NAME(PD_MIPI_1_DSI_I2C0));
+ clks[IMX8QM_MIPI1_I2C0_IPG_CLK] = imx_clk_gate2_scu("mipi1_i2c0_ipg", "mipi1_i2c0_ipg_s", LPCG_ADDR(MIPI_DSI_1_LPCG + 0x14), 0, FUNCTION_NAME(PD_MIPI_1_DSI_I2C0));
+ clks[IMX8QM_MIPI1_I2C1_DIV] = imx_clk_divider_scu("mipi1_i2c1_div", SC_R_MIPI_1_I2C_1, SC_PM_CLK_MISC2);
+ clks[IMX8QM_MIPI1_I2C1_CLK] = imx_clk_gate_scu("mipi1_i2c1_clk", "mipi1_i2c1_div", SC_R_MIPI_1_I2C_1, SC_PM_CLK_MISC2, LPCG_ADDR(MIPI_DSI_1_LPCG + 0x2C), 0, 0);
+ clks[IMX8QM_MIPI1_I2C1_IPG_S_CLK] = imx_clk_gate2_scu("mipi1_i2c1_ipg_s", "mipi1_clk_root", LPCG_ADDR(MIPI_DSI_1_LPCG + 0x28), 0, FUNCTION_NAME(PD_MIPI_1_DSI_I2C1));
+ clks[IMX8QM_MIPI1_I2C1_IPG_CLK] = imx_clk_gate2_scu("mipi1_i2c1_ipg", "mipi1_i2c1_ipg_s", LPCG_ADDR(MIPI_DSI_1_LPCG + 0x24), 0, FUNCTION_NAME(PD_MIPI_1_DSI_I2C1));
+ clks[IMX8QM_MIPI1_PWM0_CLK] = imx_clk_gate_scu("mipi1_pwm0_clk", "mipi1_pwm0_div", SC_R_MIPI_1_PWM_0, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QM_MIPI1_DSI_TX_ESC_CLK] = imx_clk_gate_scu("mipi1_dsi_tx_esc_clk", "mipi1_dsi_tx_esc_div", SC_R_MIPI_1, SC_PM_CLK_MST_BUS, NULL, 0, 0);
+ clks[IMX8QM_MIPI1_DSI_RX_ESC_CLK] = imx_clk_gate_scu("mipi1_dsi_rx_esc_clk", "mipi1_dsi_rx_esc_div", SC_R_MIPI_1, SC_PM_CLK_SLV_BUS, NULL, 0, 0);
+ clks[IMX8QM_MIPI1_PXL_CLK] = imx_clk_gate_scu("mipi1_pxl_clk", "mipi1_pxl_div", SC_R_MIPI_1, SC_PM_CLK_PER, NULL, 0, 0);
+
+ /* Display controller */
+ /* DC0 */
+ clks[IMX8QM_DC0_DISP0_CLK] = imx_clk_gate_scu("dc0_disp0_clk", "dc0_disp0_div", SC_R_DC_0, SC_PM_CLK_MISC0, LPCG_ADDR(DC_0_LPCG), 0, 0);
+ clks[IMX8QM_DC0_DISP1_CLK] = imx_clk_gate_scu("dc0_disp1_clk", "dc0_disp1_div", SC_R_DC_0, SC_PM_CLK_MISC1, LPCG_ADDR(DC_0_LPCG), 4, 0);
+ clks[IMX8QM_DC0_PRG0_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg0_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x20), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG0_APB_CLK] = imx_clk_gate2_scu("dc0_prg0_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x20), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG1_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg1_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x24), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG1_APB_CLK] = imx_clk_gate2_scu("dc0_prg1_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x24), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG2_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg2_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x28), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG2_APB_CLK] = imx_clk_gate2_scu("dc0_prg2_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x28), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG3_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg3_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x34), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG3_APB_CLK] = imx_clk_gate2_scu("dc0_prg3_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x34), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG4_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg4_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x38), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG4_APB_CLK] = imx_clk_gate2_scu("dc0_prg4_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x38), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG5_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg5_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x3c), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG5_APB_CLK] = imx_clk_gate2_scu("dc0_prg5_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x3c), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG6_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg6_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x40), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG6_APB_CLK] = imx_clk_gate2_scu("dc0_prg6_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x40), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG7_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg7_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x44), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG7_APB_CLK] = imx_clk_gate2_scu("dc0_prg7_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x44), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG8_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg8_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x48), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_PRG8_APB_CLK] = imx_clk_gate2_scu("dc0_prg8_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x48), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_DPR0_APB_CLK] = imx_clk_gate2_scu("dc0_dpr0_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x18), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_DPR0_B_CLK] = imx_clk_gate2_scu("dc0_dpr0_b_clk", "axi_ext_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x18), 20, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_DPR1_APB_CLK] = imx_clk_gate2_scu("dc0_dpr1_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x2c), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_DPR1_B_CLK] = imx_clk_gate2_scu("dc0_dpr1_b_clk", "axi_ext_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x2c), 20, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_RTRAM0_CLK] = imx_clk_gate2_scu("dc0_rtrm0_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x1C), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QM_DC0_RTRAM1_CLK] = imx_clk_gate2_scu("dc0_rtrm1_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_0_LPCG + 0x30), 0, FUNCTION_NAME(PD_DC_0));
+ /* DC1 */
+ clks[IMX8QM_DC1_DISP0_CLK] = imx_clk_gate_scu("dc1_disp0_clk", "dc1_disp0_div", SC_R_DC_1, SC_PM_CLK_MISC0, LPCG_ADDR(DC_1_LPCG), 0, 0);
+ clks[IMX8QM_DC1_DISP1_CLK] = imx_clk_gate_scu("dc1_disp1_clk", "dc1_disp1_div", SC_R_DC_1, SC_PM_CLK_MISC1, LPCG_ADDR(DC_1_LPCG), 4, 0);
+ clks[IMX8QM_DC1_PRG0_RTRAM_CLK] = imx_clk_gate2_scu("dc1_prg0_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x20), 0, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG0_APB_CLK] = imx_clk_gate2_scu("dc1_prg0_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x20), 16, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG1_RTRAM_CLK] = imx_clk_gate2_scu("dc1_prg1_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x24), 0, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG1_APB_CLK] = imx_clk_gate2_scu("dc1_prg1_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x24), 16, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG2_RTRAM_CLK] = imx_clk_gate2_scu("dc1_prg2_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x28), 0, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG2_APB_CLK] = imx_clk_gate2_scu("dc1_prg2_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x28), 16, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG3_RTRAM_CLK] = imx_clk_gate2_scu("dc1_prg3_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x34), 0, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG3_APB_CLK] = imx_clk_gate2_scu("dc1_prg3_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x34), 16, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG4_RTRAM_CLK] = imx_clk_gate2_scu("dc1_prg4_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x38), 0, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG4_APB_CLK] = imx_clk_gate2_scu("dc1_prg4_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x38), 16, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG5_RTRAM_CLK] = imx_clk_gate2_scu("dc1_prg5_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x3c), 0, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG5_APB_CLK] = imx_clk_gate2_scu("dc1_prg5_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x3c), 16, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG6_RTRAM_CLK] = imx_clk_gate2_scu("dc1_prg6_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x40), 0, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG6_APB_CLK] = imx_clk_gate2_scu("dc1_prg6_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x40), 16, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG7_RTRAM_CLK] = imx_clk_gate2_scu("dc1_prg7_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x44), 0, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG7_APB_CLK] = imx_clk_gate2_scu("dc1_prg7_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x44), 16, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG8_RTRAM_CLK] = imx_clk_gate2_scu("dc1_prg8_rtram_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x48), 0, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_PRG8_APB_CLK] = imx_clk_gate2_scu("dc1_prg8_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x48), 16, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_DPR0_APB_CLK] = imx_clk_gate2_scu("dc1_dpr0_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x18), 16, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_DPR0_B_CLK] = imx_clk_gate2_scu("dc1_dpr0_b_clk", "axi_ext_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x18), 20, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_DPR1_APB_CLK] = imx_clk_gate2_scu("dc1_dpr1_apb_clk", "cfg_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x2c), 16, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_DPR1_B_CLK] = imx_clk_gate2_scu("dc1_dpr1_b_clk", "axi_ext_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x2c), 20, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_RTRAM0_CLK] = imx_clk_gate2_scu("dc1_rtrm0_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x1C), 0, FUNCTION_NAME(PD_DC_1));
+ clks[IMX8QM_DC1_RTRAM1_CLK] = imx_clk_gate2_scu("dc1_rtrm1_clk", "axi_int_dc_clk_root", LPCG_ADDR(DC_1_LPCG + 0x30), 0, FUNCTION_NAME(PD_DC_1));
+
+ /* HDMI SS */
+ clks[IMX8QM_HDMI_IPG_CLK] = imx_clk_gate_scu("ipg_hdmi_clk_root", "hdmi_ipg_div", SC_R_HDMI, SC_PM_CLK_MISC, NULL, 0, 0);
+ clks[IMX8QM_HDMI_I2C0_CLK] = imx_clk_gate_scu("hdmi_i2c0_clk", "hdmi_i2c0_div", SC_R_HDMI_I2C_0, SC_PM_CLK_MISC2, LPCG_ADDR(DI_HDMI_LPCG), 0, 0);
+ clks[IMX8QM_HDMI_PXL_MUX_CLK] = imx_clk_gate_scu("hdmi_pxl_mux_clk", "hdmi_pxl_mux_div", SC_R_HDMI, SC_PM_CLK_MISC0, NULL, 0, 0);
+ clks[IMX8QM_HDMI_PXL_LINK_CLK] = imx_clk_gate_scu("hdmi_pxl_link_clk", "hdmi_pxl_link_div", SC_R_HDMI, SC_PM_CLK_MISC1, NULL, 0, 0);
+ clks[IMX8QM_HDMI_HDP_CORE_CLK] = imx_clk_gate_scu("hdmi_hdp_core_clk", "hdmi_core_div", SC_R_HDMI, SC_PM_CLK_MISC2, NULL, 0, 0);
+ clks[IMX8QM_HDMI_PXL_CLK] = imx_clk_gate_scu("hdmi_pxl_clk", "hdmi_pxl_div", SC_R_HDMI, SC_PM_CLK_MISC3, NULL, 0, 0);
+ clks[IMX8QM_HDMI_I2S_CLK] = imx_clk_gate_scu("hdmi_i2s_clk", "hdmi_i2s_div", SC_R_HDMI_I2S, SC_PM_CLK_MISC0, LPCG_ADDR(DI_HDMI_LPCG + 0xC), 0, 0);
+ clks[IMX8QM_HDMI_I2C_IPG_CLK] = imx_clk_gate2_scu("hdmi_i2c_ipg_clk", "ipg_hdmi_clk_root", LPCG_ADDR(DI_HDMI_LPCG), 16, FUNCTION_NAME(PD_HDMI_I2C_0));
+ clks[IMX8QM_HDMI_PWM_IPG_CLK] = imx_clk_gate2_scu("hdmi_pwm_ipg_clk", "ipg_hdmi_clk_root", LPCG_ADDR(DI_HDMI_LPCG + 0x8), 16, FUNCTION_NAME(PD_HDMI_PWM_0));
+ clks[IMX8QM_HDMI_GPIO_IPG_CLK] = imx_clk_gate2_scu("hdmi_gpio_ipg_clk", "ipg_hdmi_clk_root", LPCG_ADDR(DI_HDMI_LPCG + 0x10), 16, FUNCTION_NAME(PD_HDMI_GPIO_0));
+ clks[IMX8QM_HDMI_LIS_IPG_CLK] = imx_clk_gate2_scu("hdmi_lis_ipg_clk", "ipg_hdmi_clk_root", LPCG_ADDR(DI_HDMI_LPCG + 0x4), 16, FUNCTION_NAME(PD_HDMI));
+ clks[IMX8QM_HDMI_MSI_HCLK] = imx_clk_gate2_scu("hdmi_msi_hclk_clk", "ipg_hdmi_clk_root", LPCG_ADDR(DI_HDMI_LPCG + 0x14), 0, FUNCTION_NAME(PD_HDMI));
+ clks[IMX8QM_HDMI_PXL_LPCG_CLK] = imx_clk_gate2_scu("hdmi_pxl_lpcg_clk", "dummy", LPCG_ADDR(DI_HDMI_LPCG + 0x18), 0, FUNCTION_NAME(PD_HDMI));
+ clks[IMX8QM_HDMI_PXL_EVEN_CLK] = imx_clk_gate2_scu("hdmi_pxl_even_clk", "hdmi_pxl_lpcg_clk", NULL, 0, FUNCTION_NAME(PD_HDMI));
+ clks[IMX8QM_HDMI_HDP_CLK] = imx_clk_gate2_scu("hdmi_pxl_odd_clk", "hdmi_pxl_lpcg_clk", NULL, 0, FUNCTION_NAME(PD_HDMI));
+ clks[IMX8QM_HDMI_PXL_DBL_CLK] = imx_clk_gate2_scu("hdmi_pxl_dbl_clk", "hdmi_pxl_lpcg_clk", NULL, 0, FUNCTION_NAME(PD_HDMI));
+ clks[IMX8QM_HDMI_VIF_CLK] = imx_clk_gate2_scu("hdmi_vif_clk", "hdmi_pxl_mux_clk", LPCG_ADDR(DI_HDMI_LPCG + 0x1C), 0, FUNCTION_NAME(PD_HDMI));
+ clks[IMX8QM_HDMI_APB_CLK] = imx_clk_gate2_scu("hdmi_apb_clk", "ipg_hdmi_clk_root", LPCG_ADDR(DI_HDMI_LPCG + 0x28), 16, FUNCTION_NAME(PD_HDMI));
+ clks[IMX8QM_HDMI_APB_MUX_CSR_CLK] = imx_clk_gate2_scu("hdmi_apb_mux_csr_clk", "hdmi_apb_clk", LPCG_ADDR(DI_HDMI_LPCG + 0x20), 16, FUNCTION_NAME(PD_HDMI));
+ clks[IMX8QM_HDMI_APB_MUX_CTRL_CLK] = imx_clk_gate2_scu("hdmi_apb_mux_ctrl_clk", "hdmi_apb_clk", LPCG_ADDR(DI_HDMI_LPCG + 0x24), 16, FUNCTION_NAME(PD_HDMI));
+ clks[IMX8QM_HDMI_HDP_PHY_CLK] = imx_clk_gate2_scu("hdmi_pclk", "ipg_hdmi_clk_root", LPCG_ADDR(DI_HDMI_LPCG + 0x1C), 16, FUNCTION_NAME(PD_HDMI));
+
+ /* lvds subsystem */
+ clks[IMX8QM_LVDS0_PIXEL_CLK] = imx_clk_gate_scu("lvds0_pixel_clk", "lvds0_pixel_div", SC_R_LVDS_0, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QM_LVDS0_I2C0_CLK] = imx_clk_gate_scu("lvds0_i2c0_clk", "lvds0_i2c0_div", SC_R_LVDS_0_I2C_0, SC_PM_CLK_PER, LPCG_ADDR(DI_LVDS_0_LPCG + 0x10), 0, 0);
+ clks[IMX8QM_LVDS0_I2C1_CLK] = imx_clk_gate_scu("lvds0_i2c1_clk", "lvds0_i2c1_div", SC_R_LVDS_0_I2C_1, SC_PM_CLK_PER, LPCG_ADDR(DI_LVDS_0_LPCG + 0x14), 0, 0);
+ clks[IMX8QM_LVDS0_PWM0_CLK] = imx_clk_gate_scu("lvds0_pwm0_clk", "lvds0_pwm0_div", SC_R_LVDS_0_PWM_0, SC_PM_CLK_PER, LPCG_ADDR(DI_LVDS_0_LPCG + 0x0C), 0, 0);
+ clks[IMX8QM_LVDS0_PHY_CLK] = imx_clk_gate_scu("lvds0_phy_clk", "lvds0_phy_div", SC_R_LVDS_0, SC_PM_CLK_PHY, NULL, 0, 0);
+ clks[IMX8QM_LVDS0_I2C0_IPG_CLK] = imx_clk_gate2_scu("lvds0_i2c0_ipg_clk", "ipg_lvds_clk_root", LPCG_ADDR(DI_LVDS_0_LPCG + 0x10), 16, FUNCTION_NAME(PD_LVDS0_I2C0));
+ clks[IMX8QM_LVDS0_I2C1_IPG_CLK] = imx_clk_gate2_scu("lvds0_i2c1_ipg_clk", "ipg_lvds_clk_root", LPCG_ADDR(DI_LVDS_0_LPCG + 0x14), 16, FUNCTION_NAME(PD_LVDS0_I2C1));
+ clks[IMX8QM_LVDS0_PWM0_IPG_CLK] = imx_clk_gate2_scu("lvds0_pwm0_ipg_clk", "ipg_lvds_clk_root", LPCG_ADDR(DI_LVDS_0_LPCG + 0x0C), 16, FUNCTION_NAME(PD_LVDS0_PWM));
+ clks[IMX8QM_LVDS0_GPIO_IPG_CLK] = imx_clk_gate2_scu("lvds0_gpio_ipg_clk", "ipg_lvds_clk_root", LPCG_ADDR(DI_LVDS_0_LPCG + 0x08), 16, FUNCTION_NAME(PD_LVDS0_GPIO));
+ clks[IMX8QM_LVDS0_LIS_IPG_CLK] = imx_clk_gate2_scu("lvds0_lis_ipg_clk", "ipg_lvds_clk_root", LPCG_ADDR(DI_LVDS_0_LPCG + 0x0), 16, FUNCTION_NAME(PD_LVDS0));
+
+ clks[IMX8QM_LVDS1_PIXEL_CLK] = imx_clk_gate_scu("lvds1_pixel_clk", "lvds1_pixel_div", SC_R_LVDS_1, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QM_LVDS1_I2C0_CLK] = imx_clk_gate_scu("lvds1_i2c0_clk", "lvds1_i2c0_div", SC_R_LVDS_1_I2C_0, SC_PM_CLK_PER, LPCG_ADDR(DI_LVDS_1_LPCG + 0x10), 0, 0);
+ clks[IMX8QM_LVDS1_I2C1_CLK] = imx_clk_gate_scu("lvds1_i2c1_clk", "lvds1_i2c1_div", SC_R_LVDS_1_I2C_1, SC_PM_CLK_PER, LPCG_ADDR(DI_LVDS_1_LPCG + 0x14), 0, 0);
+ clks[IMX8QM_LVDS1_PWM0_CLK] = imx_clk_gate_scu("lvds1_pwm0_clk", "lvds1_pwm0_div", SC_R_LVDS_1_PWM_0, SC_PM_CLK_PER, LPCG_ADDR(DI_LVDS_1_LPCG + 0x0C), 0, 0);
+ clks[IMX8QM_LVDS1_PHY_CLK] = imx_clk_gate_scu("lvds1_phy_clk", "lvds1_phy_div", SC_R_LVDS_1, SC_PM_CLK_PHY, NULL, 0, 0);
+ clks[IMX8QM_LVDS1_I2C0_IPG_CLK] = imx_clk_gate2_scu("lvds1_i2c0_ipg_clk", "ipg_lvds_clk_root", LPCG_ADDR(DI_LVDS_1_LPCG + 0x10), 16, FUNCTION_NAME(PD_LVDS1_I2C0));
+ clks[IMX8QM_LVDS1_I2C1_IPG_CLK] = imx_clk_gate2_scu("lvds1_i2c1_ipg_clk", "ipg_lvds_clk_root", LPCG_ADDR(DI_LVDS_1_LPCG + 0x14), 16, FUNCTION_NAME(PD_LVDS1_I2C1));
+ clks[IMX8QM_LVDS1_PWM0_IPG_CLK] = imx_clk_gate2_scu("lvds1_pwm0_ipg_clk", "ipg_lvds_clk_root", LPCG_ADDR(DI_LVDS_1_LPCG + 0x0C), 16, FUNCTION_NAME(PD_LVDS1_PWM));
+ clks[IMX8QM_LVDS1_GPIO_IPG_CLK] = imx_clk_gate2_scu("lvds1_gpio_ipg_clk", "ipg_lvds_clk_root", LPCG_ADDR(DI_LVDS_1_LPCG + 0x08), 16, FUNCTION_NAME(PD_LVDS1_GPIO));
+ clks[IMX8QM_LVDS1_LIS_IPG_CLK] = imx_clk_gate2_scu("lvds1_lis_ipg_clk", "ipg_lvds_clk_root", LPCG_ADDR(DI_LVDS_1_LPCG + 0x0), 16, FUNCTION_NAME(PD_LVDS1));
+
+ /* vpu/zpu subsystem */
+ clks[IMX8QM_VPU_DDR_CLK] = imx_clk_gate_scu("vpu_ddr_clk", "vpu_ddr_div", SC_R_VPU, SC_PM_CLK_SLV_BUS, NULL, 0, 0);
+ clks[IMX8QM_VPU_SYS_CLK] = imx_clk_gate_scu("vpu_sys_clk", "vpu_sys_div", SC_R_VPU, SC_PM_CLK_MST_BUS, NULL, 0, 0);
+ clks[IMX8QM_VPU_XUVI_CLK] = imx_clk_gate_scu("vpu_xuvi_clk", "vpu_xuvi_div", SC_R_VPU, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QM_VPU_UART_CLK] = imx_clk_gate_scu("vpu_uart_clk", "vpu_uart_div", SC_R_VPU_UART, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QM_VPU_CORE_CLK] = imx_clk_gate_scu("vpu_core_clk", "vpu_core_div", SC_R_VPUCORE, SC_PM_CLK_PER, NULL, 0, 0);
+
+ /* gpu */
+ clks[IMX8QM_GPU0_CORE_CLK] = imx_clk_gate_scu("gpu_core0_clk", "gpu_core0_div", SC_R_GPU_0_PID0, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QM_GPU0_SHADER_CLK] = imx_clk_gate_scu("gpu_shader0_clk", "gpu_shader0_div", SC_R_GPU_0_PID0, SC_PM_CLK_MISC, NULL, 0, 0);
+ clks[IMX8QM_GPU1_CORE_CLK] = imx_clk_gate_scu("gpu_core1_clk", "gpu_core1_div", SC_R_GPU_1_PID0, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QM_GPU1_SHADER_CLK] = imx_clk_gate_scu("gpu_shader1_clk", "gpu_shader1_div", SC_R_GPU_1_PID0, SC_PM_CLK_MISC, NULL, 0, 0);
+
+ /* Imaging SS */
+ clks[IMX8QM_IMG_JPEG_ENC_IPG_CLK] = imx_clk_gate2_scu("img_jpeg_enc_ipg_clk", "ipg_img_clk_root", LPCG_ADDR(IMG_JPEG_ENC_LPCG), 16, FUNCTION_NAME(PD_IMAGING_JPEG_ENC));
+ clks[IMX8QM_IMG_JPEG_ENC_CLK] = imx_clk_gate2_scu("img_jpeg_enc_clk", "img_jpeg_enc_ipg_clk", LPCG_ADDR(IMG_JPEG_ENC_LPCG), 0, FUNCTION_NAME(PD_IMAGING_JPEG_ENC));
+ clks[IMX8QM_IMG_JPEG_DEC_IPG_CLK] = imx_clk_gate2_scu("img_jpeg_dec_ipg_clk", "ipg_img_clk_root", LPCG_ADDR(IMG_JPEG_DEC_LPCG), 16, FUNCTION_NAME(PD_IMAGING_JPEG_DEC));
+ clks[IMX8QM_IMG_JPEG_DEC_CLK] = imx_clk_gate2_scu("img_jpeg_dec_clk", "img_jpeg_dec_ipg_clk", LPCG_ADDR(IMG_JPEG_DEC_LPCG), 0, FUNCTION_NAME(PD_IMAGING_JPEG_DEC));
+ clks[IMX8QM_IMG_PXL_LINK_DC0_CLK] = imx_clk_gate2_scu("img_pxl_link_dc0_clk", "pxl_img_clk_root", LPCG_ADDR(IMG_PXL_LINK_DC0_LPCG), 0, FUNCTION_NAME(PD_IMAGING));
+ clks[IMX8QM_IMG_PXL_LINK_DC1_CLK] = imx_clk_gate2_scu("img_pxl_link_dc1_clk", "pxl_img_clk_root", LPCG_ADDR(IMG_PXL_LINK_DC1_LPCG), 0, FUNCTION_NAME(PD_IMAGING));
+ clks[IMX8QM_IMG_PXL_LINK_CSI0_CLK] = imx_clk_gate2_scu("img_pxl_link_csi0_clk", "pxl_img_clk_root", LPCG_ADDR(IMG_PXL_LINK_CSI0_LPCG), 0, FUNCTION_NAME(PD_IMAGING));
+ clks[IMX8QM_IMG_PXL_LINK_CSI1_CLK] = imx_clk_gate2_scu("img_pxl_link_csi1_clk", "pxl_img_clk_root", LPCG_ADDR(IMG_PXL_LINK_CSI1_LPCG), 0, FUNCTION_NAME(PD_IMAGING));
+ clks[IMX8QM_IMG_PXL_LINK_HDMI_IN_CLK] = imx_clk_gate2_scu("img_pxl_link_hdmi_in_clk", "pxl_img_clk_root", LPCG_ADDR(IMG_PXL_LINK_HDMI_LPCG), 0, FUNCTION_NAME(PD_IMAGING));
+ clks[IMX8QM_IMG_PDMA_0_CLK] = imx_clk_gate2_scu("img_pdma0_clk", "pxl_img_clk_root", LPCG_ADDR(IMG_PDMA_0_LPCG), 0, FUNCTION_NAME(PD_IMAGING_PDMA0));
+ clks[IMX8QM_IMG_PDMA_1_CLK] = imx_clk_gate2_scu("img_pdma1_clk", "pxl_img_clk_root", LPCG_ADDR(IMG_PDMA_1_LPCG), 0, FUNCTION_NAME(PD_IMAGING_PDMA1));
+ clks[IMX8QM_IMG_PDMA_2_CLK] = imx_clk_gate2_scu("img_pdma2_clk", "pxl_img_clk_root", LPCG_ADDR(IMG_PDMA_2_LPCG), 0, FUNCTION_NAME(PD_IMAGING_PDMA2));
+ clks[IMX8QM_IMG_PDMA_3_CLK] = imx_clk_gate2_scu("img_pdma3_clk", "pxl_img_clk_root", LPCG_ADDR(IMG_PDMA_3_LPCG), 0, FUNCTION_NAME(PD_IMAGING_PDMA3));
+ clks[IMX8QM_IMG_PDMA_4_CLK] = imx_clk_gate2_scu("img_pdma4_clk", "pxl_img_clk_root", LPCG_ADDR(IMG_PDMA_4_LPCG), 0, FUNCTION_NAME(PD_IMAGING_PDMA4));
+ clks[IMX8QM_IMG_PDMA_5_CLK] = imx_clk_gate2_scu("img_pdma5_clk", "pxl_img_clk_root", LPCG_ADDR(IMG_PDMA_5_LPCG), 0, FUNCTION_NAME(PD_IMAGING_PDMA5));
+ clks[IMX8QM_IMG_PDMA_6_CLK] = imx_clk_gate2_scu("img_pdma6_clk", "pxl_img_clk_root", LPCG_ADDR(IMG_PDMA_6_LPCG), 0, FUNCTION_NAME(PD_IMAGING_PDMA6));
+ clks[IMX8QM_IMG_PDMA_7_CLK] = imx_clk_gate2_scu("img_pdma7_clk", "pxl_img_clk_root", LPCG_ADDR(IMG_PDMA_7_LPCG), 0, FUNCTION_NAME(PD_IMAGING_PDMA7));
+
+ /* HSIO */
+ clks[IMX8QM_HSIO_PCIE_A_MSTR_AXI_CLK] = imx_clk_gate2_scu("hsio_pcieA_mstr_axi_clk", "axi_hsio_clk_root", LPCG_ADDR(HSIO_PCIE_X2_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_A));
+ clks[IMX8QM_HSIO_PCIE_A_SLV_AXI_CLK] = imx_clk_gate2_scu("hsio_pcieA_slv_axi_clk", "axi_hsio_clk_root", LPCG_ADDR(HSIO_PCIE_X2_LPCG), 20, FUNCTION_NAME(PD_HSIO_PCIE_A));
+ clks[IMX8QM_HSIO_PCIE_A_DBI_AXI_CLK] = imx_clk_gate2_scu("hsio_pcieA_dbi_axi_clk", "axi_hsio_clk_root", LPCG_ADDR(HSIO_PCIE_X2_LPCG), 24, FUNCTION_NAME(PD_HSIO_PCIE_A));
+ clks[IMX8QM_HSIO_PCIE_B_MSTR_AXI_CLK] = imx_clk_gate2_scu("hsio_pcieB_mstr_axi_clk", "axi_hsio_clk_root", LPCG_ADDR(HSIO_PCIE_X1_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_B));
+ clks[IMX8QM_HSIO_PCIE_B_SLV_AXI_CLK] = imx_clk_gate2_scu("hsio_pcieB_slv_axi_clk", "axi_hsio_clk_root", LPCG_ADDR(HSIO_PCIE_X1_LPCG), 20, FUNCTION_NAME(PD_HSIO_PCIE_B));
+ clks[IMX8QM_HSIO_PCIE_B_DBI_AXI_CLK] = imx_clk_gate2_scu("hsio_pcieB_dbi_axi_clk", "axi_hsio_clk_root", LPCG_ADDR(HSIO_PCIE_X1_LPCG), 24, FUNCTION_NAME(PD_HSIO_PCIE_B));
+ clks[IMX8QM_HSIO_PCIE_X1_PER_CLK] = imx_clk_gate2_scu("hsio_pcie_x1_per_clk", "per_hsio_clk_root", LPCG_ADDR(HSIO_PCIE_X1_CRR3_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_B));
+ clks[IMX8QM_HSIO_PCIE_X2_PER_CLK] = imx_clk_gate2_scu("hsio_pcie_x2_per_clk", "per_hsio_clk_root", LPCG_ADDR(HSIO_PCIE_X2_CRR2_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_A));
+ clks[IMX8QM_HSIO_SATA_PER_CLK] = imx_clk_gate2_scu("hsio_sata_per_clk", "per_hsio_clk_root", LPCG_ADDR(HSIO_SATA_CRR4_LPCG), 16, FUNCTION_NAME(PD_HSIO_SATA_0));
+ clks[IMX8QM_HSIO_PHY_X1_PER_CLK] = imx_clk_gate2_scu("hsio_phy_x1_per_clk", "per_hsio_clk_root", LPCG_ADDR(HSIO_PHY_X1_CRR1_LPCG), 16, FUNCTION_NAME(PD_HSIO_SATA_0));
+ clks[IMX8QM_HSIO_PHY_X2_PER_CLK] = imx_clk_gate2_scu("hsio_phy_x2_per_clk", "per_hsio_clk_root", LPCG_ADDR(HSIO_PHY_X2_CRR0_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_A));
+ clks[IMX8QM_HSIO_MISC_PER_CLK] = imx_clk_gate2_scu("hsio_misc_per_clk", "per_hsio_clk_root", LPCG_ADDR(HSIO_MISC_LPCG), 16, FUNCTION_NAME(PD_HSIO));
+ clks[IMX8QM_HSIO_PHY_X1_APB_CLK] = imx_clk_gate2_scu("hsio_phy_x1_apb_clk", "per_hsio_clk_root", LPCG_ADDR(HSIO_PHY_X1_LPCG), 16, FUNCTION_NAME(PD_HSIO_SATA_0));
+ clks[IMX8QM_HSIO_PHY_X2_APB_0_CLK] = imx_clk_gate2_scu("hsio_phy_x2_apb_0_clk", "per_hsio_clk_root", LPCG_ADDR(HSIO_PHY_X2_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_A));
+ clks[IMX8QM_HSIO_PHY_X2_APB_1_CLK] = imx_clk_gate2_scu("hsio_phy_x2_apb_1_clk", "per_hsio_clk_root", LPCG_ADDR(HSIO_PHY_X2_LPCG), 20, FUNCTION_NAME(PD_HSIO_PCIE_A));
+ clks[IMX8QM_HSIO_SATA_CLK] = imx_clk_gate2_scu("hsio_sata_clk", "axi_hsio_clk_root", LPCG_ADDR(HSIO_SATA_LPCG), 16, FUNCTION_NAME(PD_HSIO_SATA_0));
+ clks[IMX8QM_HSIO_GPIO_CLK] = imx_clk_gate2_scu("hsio_gpio_clk", "per_hsio_clk_root", LPCG_ADDR(HSIO_GPIO_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_A));
+ clks[IMX8QM_HSIO_PHY_X1_PCLK] = imx_clk_gate2_scu("hsio_phy_x1_pclk", "dummy", LPCG_ADDR(HSIO_PHY_X1_LPCG), 0, FUNCTION_NAME(PD_HSIO_SATA_0));
+ clks[IMX8QM_HSIO_PHY_X2_PCLK_0] = imx_clk_gate2_scu("hsio_phy_x2_pclk_0", "dummy", LPCG_ADDR(HSIO_PHY_X2_LPCG), 0, FUNCTION_NAME(PD_HSIO_PCIE_A));
+ clks[IMX8QM_HSIO_PHY_X2_PCLK_1] = imx_clk_gate2_scu("hsio_phy_x2_pclk_1", "dummy", LPCG_ADDR(HSIO_PHY_X2_LPCG), 4, FUNCTION_NAME(PD_HSIO_PCIE_B));
+ clks[IMX8QM_HSIO_SATA_EPCS_RX_CLK] = imx_clk_gate2_scu("hsio_sata_epcs_rx_clk", "dummy", LPCG_ADDR(HSIO_PHY_X1_LPCG), 8, FUNCTION_NAME(PD_HSIO_SATA_0));
+ clks[IMX8QM_HSIO_SATA_EPCS_TX_CLK] = imx_clk_gate2_scu("hsio_sata_epcs_tx_clk", "dummy", LPCG_ADDR(HSIO_PHY_X1_LPCG), 4, FUNCTION_NAME(PD_HSIO_SATA_0));
+
+ /* CM40 */
+ clks[IMX8QM_CM40_I2C_DIV] = imx_clk_divider_scu("cm40_i2c_div", SC_R_M4_0_I2C, SC_PM_CLK_PER);
+ clks[IMX8QM_CM40_I2C_CLK] = imx_clk_gate_scu("cm40_i2c_clk", "cm40_i2c_div", SC_R_M4_0_I2C, SC_PM_CLK_PER, (void __iomem *)(CM40_I2C_LPCG), 0, 0);
+ clks[IMX8QM_CM40_I2C_IPG_CLK] = imx_clk_gate2_scu("cm40_i2c_ipg_clk", "ipg_cm40_clk_root", (void __iomem *)(CM40_I2C_LPCG), 16, FUNCTION_NAME(PD_CM40_I2C));
+
+ /* CM41 */
+ clks[IMX8QM_CM41_I2C_DIV] = imx_clk_divider_scu("cm41_i2c_div", SC_R_M4_1_I2C, SC_PM_CLK_PER);
+ clks[IMX8QM_CM41_I2C_CLK] = imx_clk_gate_scu("cm41_i2c_clk", "cm41_i2c_div", SC_R_M4_1_I2C, SC_PM_CLK_PER, (void __iomem *)(CM41_I2C_LPCG), 0, 0);
+ clks[IMX8QM_CM41_I2C_IPG_CLK] = imx_clk_gate2_scu("cm41_i2c_ipg_clk", "ipg_cm41_clk_root", (void __iomem *)(CM41_I2C_LPCG), 16, FUNCTION_NAME(PD_CM41_I2C));
+
+ for (i = 0; i < ARRAY_SIZE(clks); i++)
+ if (IS_ERR(clks[i]) && PTR_ERR(clks[i]) != -ENODEV)
+ pr_err("i.MX8QM clk %d: register failed with %ld\n",
+ i, PTR_ERR(clks[i]));
+
+ clk_data.clks = clks;
+ clk_data.clk_num = ARRAY_SIZE(clks);
+ of_clk_add_provider(ccm_node, of_clk_src_onecell_get, &clk_data);
+
+ return 0;
+}
+
+static const struct of_device_id imx8qm_match[] = {
+ { .compatible = "fsl,imx8qm-clk", },
+ { /* sentinel value */ }
+};
+
+static struct platform_driver imx8qm_clk_driver = {
+ .driver = {
+ .name = "imx8qm-clk",
+ .of_match_table = imx8qm_match,
+ },
+ .probe = imx8qm_clk_probe,
+};
+
+static int __init imx8qm_clk_init(void)
+{
+ return platform_driver_register(&imx8qm_clk_driver);
+}
+core_initcall(imx8qm_clk_init);
diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c
new file mode 100644
index 000000000000..80d0dc6fd5b0
--- /dev/null
+++ b/drivers/clk/imx/clk-imx8qxp.c
@@ -0,0 +1,742 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/clock/imx8qxp-clock.h>
+#include <dt-bindings/soc/imx8_pd.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+
+#include <soc/imx8/imx8qxp/lpcg.h>
+#include <soc/imx8/sc/sci.h>
+#include "clk-imx8.h"
+
+#define STR_VALUE(arg) #arg
+#define FUNCTION_NAME(name) STR_VALUE(name)
+
+static const char *aud_clk_sels[] = {
+ "aud_acm_aud_rec_clk0_clk",
+ "aud_acm_aud_rec_clk1_clk",
+ "ext_aud_mclk0",
+ "ext_aud_mclk1",
+ "esai0_rx_clk",
+ "esai0_rx_hf_clk",
+ "esai0_tx_clk",
+ "esai0_tx_hf_clk",
+ "spdif0_rx",
+ "sai0_rx_bclk",
+ "sai0_tx_bclk",
+ "sai1_rx_bclk",
+ "sai1_tx_bclk",
+ "sai2_rx_bclk",
+ "sai3_rx_bclk",
+};
+
+static const char *mclk_out_sels[] = {
+ "aud_acm_aud_rec_clk0_clk",
+ "aud_acm_aud_rec_clk1_clk",
+ "dummy",
+ "dummy",
+ "spdif0_rx",
+ "dummy",
+ "dummy",
+ "sai4_rx_bclk",
+};
+
+static const char *sai_mclk_sels[] = {
+ "aud_acm_aud_pll_clk0_clk",
+ "aud_acm_aud_pll_clk1_clk",
+ "acm_aud_clk0_clk",
+ "acm_aud_clk1_clk",
+};
+
+static const char *esai_mclk_sels[] = {
+ "aud_acm_aud_pll_clk0_clk",
+ "aud_acm_aud_pll_clk1_clk",
+ "acm_aud_clk0_clk",
+ "acm_aud_clk1_clk",
+};
+
+static const char *spdif_mclk_sels[] = {
+ "aud_acm_aud_pll_clk0_clk",
+ "aud_acm_aud_pll_clk1_clk",
+ "acm_aud_clk0_clk",
+ "acm_aud_clk1_clk",
+};
+
+static const char *mqs_mclk_sels[] = {
+ "aud_acm_aud_pll_clk0_clk",
+ "aud_acm_aud_pll_clk1_clk",
+ "acm_aud_clk0_clk",
+ "acm_aud_clk1_clk",
+};
+
+static const char *mipi0_sels[] = {
+ "dummy",
+ "mipi0_pll_clk",
+ "mipi0_pll_div2_clk",
+ "dummy",
+ "mipi0_lvds_bypass_clk",
+};
+
+static const char *mipi1_sels[] = {
+ "dummy",
+ "mipi1_pll_clk",
+ "mipi1_pll_div2_clk",
+ "dummy",
+ "mipi1_lvds_bypass_clk",
+};
+
+static const char *sdhc0_sels[] = {
+ "dummy",
+ "conn_pll0_clk",
+ "conn_pll1_clk",
+ "dummy",
+ "dummy",
+};
+
+static const char *sdhc1_sels[] = {
+ "dummy",
+ "conn_pll0_clk",
+ "conn_pll1_clk",
+ "dummy",
+ "dummy",
+};
+
+static const char *sdhc2_sels[] = {
+ "dummy",
+ "conn_pll0_clk",
+ "conn_pll1_clk",
+ "dummy",
+ "dummy",
+};
+
+static const char *pll0_sels[] = {
+ "dummy",
+ "parallel_pll_clk",
+ "dummy",
+ "dummy",
+ "dummy",
+};
+
+static const char *lcd_pxl_sels[] = {
+ "dummy",
+ "dummy",
+ "dummy",
+ "dummy",
+ "lcd_pxl_bypass_div",
+};
+
+static const char *lcd_sels[] = {
+ "dummy",
+ "dummy",
+ "dummy",
+ "dummy",
+ "elcdif_pll",
+};
+
+static struct clk *clks[IMX8QXP_CLK_END];
+static struct clk_onecell_data clk_data;
+
+static const char *enet_sels[] = { "enet_25MHz", "enet_125MHz", };
+static const char *enet0_rmii_tx_sels[] = { "enet0_ref_div", "dummy", };
+static const char *enet1_rmii_tx_sels[] = { "enet1_ref_div", "dummy", };
+
+static int imx8qxp_clk_probe(struct platform_device *pdev)
+{
+ struct device_node *ccm_node = pdev->dev.of_node;
+ struct device_node *np_acm;
+ void __iomem *base_acm;
+ int i, ret;
+
+ ret = imx8_clk_mu_init();
+ if (ret)
+ return ret;
+
+ pr_info("***** imx8qxp_clocks_init *****\n");
+
+ /* Fixed clocks */
+ clks[IMX8QXP_CLK_DUMMY] = imx_clk_fixed("dummy", 0);
+ clks[IMX8QXP_24MHZ] = imx_clk_fixed("xtal_24MHz", SC_24MHZ);
+ clks[IMX8QXP_GPT_3M] = imx_clk_fixed("gpt_3m", 3000000);
+ clks[IMX8QXP_32KHZ] = imx_clk_fixed("xtal_32KHz", SC_32KHZ);
+
+ /* ARM core */
+ clks[IMX8QXP_A35_DIV] = imx_clk_divider_scu("a35_div", SC_R_A35, SC_PM_CLK_CPU);
+
+ /* User Defined PLLs dividers */
+ clks[IMX8QXP_AUD_PLL0_DIV] = imx_clk_divider_scu("audio_pll0_div", SC_R_AUDIO_PLL_0, SC_PM_CLK_PLL);
+ clks[IMX8QXP_AUD_PLL1_DIV] = imx_clk_divider_scu("audio_pll1_div", SC_R_AUDIO_PLL_1, SC_PM_CLK_PLL);
+ clks[IMX8QXP_ELCDIF_PLL_DIV] = imx_clk_divider_scu("elcdif_pll_div", SC_R_ELCDIF_PLL, SC_PM_CLK_PLL);
+
+ /* User Defined PLLs clocks */
+ clks[IMX8QXP_AUD_PLL0] = imx_clk_gate_scu("audio_pll0_clk", "audio_pll0_div", SC_R_AUDIO_PLL_0, SC_PM_CLK_PLL, NULL, 0, 0);
+ clks[IMX8QXP_AUD_PLL1] = imx_clk_gate_scu("audio_pll1_clk", "audio_pll1_div", SC_R_AUDIO_PLL_1, SC_PM_CLK_PLL, NULL, 0, 0);
+ clks[IMX8QXP_ELCDIF_PLL] = imx_clk_gate_scu("elcdif_pll", "elcdif_pll_div", SC_R_ELCDIF_PLL, SC_PM_CLK_PLL, NULL, 0, 0);
+
+ clks[IMX8QXP_IPG_DMA_CLK_ROOT] = imx_clk_fixed("ipg_dma_clk_root", SC_120MHZ);
+ clks[IMX8QXP_IPG_AUD_CLK_ROOT] = imx_clk_fixed("ipg_aud_clk_root", SC_150MHZ);
+ clks[IMX8QXP_AXI_CONN_CLK_ROOT] = imx_clk_fixed("axi_conn_clk_root", SC_333MHZ);
+ clks[IMX8QXP_AHB_CONN_CLK_ROOT] = imx_clk_fixed("ahb_conn_clk_root", SC_166MHZ);
+ clks[IMX8QXP_IPG_CONN_CLK_ROOT] = imx_clk_fixed("ipg_conn_clk_root", SC_83MHZ);
+ clks[IMX8QXP_DC_AXI_EXT_CLK] = imx_clk_fixed("axi_ext_dc_clk_root", SC_800MHZ);
+ clks[IMX8QXP_DC_AXI_INT_CLK] = imx_clk_fixed("axi_int_dc_clk_root", SC_400MHZ);
+ clks[IMX8QXP_DC_CFG_CLK] = imx_clk_fixed("cfg_dc_clk_root", SC_100MHZ);
+ clks[IMX8QXP_MIPI_IPG_CLK] = imx_clk_fixed("ipg_mipi_clk_root", SC_120MHZ);
+ clks[IMX8QXP_IMG_AXI_CLK] = imx_clk_fixed("axi_img_clk_root", SC_400MHZ);
+ clks[IMX8QXP_IMG_IPG_CLK] = imx_clk_fixed("ipg_img_clk_root", SC_200MHZ);
+ clks[IMX8QXP_IMG_PXL_CLK] = imx_clk_fixed("pxl_img_clk_root", SC_600MHZ);
+ clks[IMX8QXP_HSIO_AXI_CLK] = imx_clk_fixed("axi_hsio_clk_root", SC_400MHZ);
+ clks[IMX8QXP_HSIO_PER_CLK] = imx_clk_fixed("per_hsio_clk_root", SC_133MHZ);
+ clks[IMX8QXP_CM40_IPG_CLK] = imx_clk_fixed("ipg_cm40_clk_root", SC_132MHZ);
+ clks[IMX8QXP_MIPI0_DSI_PLL_CLK] = imx_clk_fixed("mipi0_pll_clk", SC_864MHZ);
+ clks[IMX8QXP_MIPI0_DSI_PLL_DIV2_CLK] = imx_clk_fixed("mipi0_pll_div2_clk", SC_432MHZ);
+ clks[IMX8QXP_MIPI1_DSI_PLL_CLK] = imx_clk_fixed("mipi1_pll_clk", SC_864MHZ);
+ clks[IMX8QXP_MIPI1_DSI_PLL_DIV2_CLK] = imx_clk_fixed("mipi1_pll_div2_clk", SC_432MHZ);
+ clks[IMX8QXP_CONN_PLL0_CLK] = imx_clk_fixed("conn_pll0_clk", SC_792MHZ);
+ clks[IMX8QXP_CONN_PLL1_CLK] = imx_clk_fixed("conn_pll1_clk", SC_1000MHZ);
+
+ clks[IMX8QXP_UART0_DIV] = imx_clk_divider_scu("uart0_div", SC_R_UART_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_UART0_IPG_CLK] = imx_clk_gate2_scu("uart0_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPUART_0_LPCG), 16, FUNCTION_NAME(PD_DMA_UART0));
+ clks[IMX8QXP_UART0_CLK] = imx_clk_gate_scu("uart0_clk", "uart0_div", SC_R_UART_0, SC_PM_CLK_PER, (void __iomem *)(LPUART_0_LPCG), 0, 0);
+
+ clks[IMX8QXP_GPU0_CORE_DIV] = imx_clk_divider_scu("gpu_core0_div", SC_R_GPU_0_PID0, SC_PM_CLK_PER);
+ clks[IMX8QXP_GPU0_SHADER_DIV] = imx_clk_divider_scu("gpu_shader0_div", SC_R_GPU_0_PID0, SC_PM_CLK_MISC);
+ clks[IMX8QXP_GPU0_CORE_CLK] = imx_clk_gate_scu("gpu_core0_clk", "gpu_core0_div", SC_R_GPU_0_PID0, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QXP_GPU0_SHADER_CLK] = imx_clk_gate_scu("gpu_shader0_clk", "gpu_shader0_div", SC_R_GPU_0_PID0, SC_PM_CLK_MISC, NULL, 0, 0);
+
+ /* LSIO SS */
+ clks[IMX8QXP_LSIO_MEM_CLK] = imx_clk_fixed("lsio_mem_clk_root", SC_100MHZ);
+ clks[IMX8QXP_LSIO_BUS_CLK] = imx_clk_fixed("lsio_bus_clk_root", SC_200MHZ);
+
+ clks[IMX8QXP_LSIO_PWM0_DIV] = imx_clk_divider_scu("pwm_0_div", SC_R_PWM_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_LSIO_PWM0_IPG_S_CLK] = imx_clk_gate_scu("pwm_0_ipg_s_clk", "pwm_0_div", SC_R_PWM_0, SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 0x10, 0);
+ clks[IMX8QXP_LSIO_PWM0_IPG_SLV_CLK] = imx_clk_gate_scu("pwm_0_ipg_slv_clk", "pwm_0_ipg_s_clk", SC_R_PWM_0, SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 0x14, 0);
+ clks[IMX8QXP_LSIO_PWM0_IPG_MSTR_CLK] = imx_clk_gate2_scu("pwm_0_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_0_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_PWM_0));
+ clks[IMX8QXP_LSIO_PWM0_HF_CLK] = imx_clk_gate_scu("pwm_0_hf_clk", "pwm_0_ipg_slv_clk", SC_R_PWM_0, SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 4, 0);
+ clks[IMX8QXP_LSIO_PWM0_CLK] = imx_clk_gate_scu("pwm_0_clk", "pwm_0_ipg_slv_clk", SC_R_PWM_0, SC_PM_CLK_PER, (void __iomem *)(PWM_0_LPCG), 0, 0);
+ clks[IMX8QXP_LSIO_PWM1_DIV] = imx_clk_divider_scu("pwm_1_div", SC_R_PWM_1, SC_PM_CLK_PER);
+ clks[IMX8QXP_LSIO_PWM1_IPG_S_CLK] = imx_clk_gate_scu("pwm_1_ipg_s_clk", "pwm_1_div", SC_R_PWM_1, SC_PM_CLK_PER, (void __iomem *)(PWM_1_LPCG), 0x10, 0);
+ clks[IMX8QXP_LSIO_PWM1_IPG_SLV_CLK] = imx_clk_gate_scu("pwm_1_ipg_slv_clk", "pwm_1_ipg_s_clk", SC_R_PWM_1, SC_PM_CLK_PER, (void __iomem *)(PWM_1_LPCG), 0x14, 0);
+ clks[IMX8QXP_LSIO_PWM1_IPG_MSTR_CLK] = imx_clk_gate2_scu("pwm_1_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_1_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_PWM_1));
+ clks[IMX8QXP_LSIO_PWM1_HF_CLK] = imx_clk_gate_scu("pwm_1_hf_clk", "pwm_1_ipg_slv_clk", SC_R_PWM_1, SC_PM_CLK_PER, (void __iomem *)(PWM_1_LPCG), 4, 0);
+ clks[IMX8QXP_LSIO_PWM1_CLK] = imx_clk_gate_scu("pwm_1_clk", "pwm_1_ipg_slv_clk", SC_R_PWM_1, SC_PM_CLK_PER, (void __iomem *)(PWM_1_LPCG), 0, 0);
+ clks[IMX8QXP_LSIO_PWM2_DIV] = imx_clk_divider_scu("pwm_2_div", SC_R_PWM_2, SC_PM_CLK_PER);
+ clks[IMX8QXP_LSIO_PWM2_IPG_S_CLK] = imx_clk_gate_scu("pwm_2_ipg_s_clk", "pwm_2_div", SC_R_PWM_2, SC_PM_CLK_PER, (void __iomem *)(PWM_2_LPCG), 0x10, 0);
+ clks[IMX8QXP_LSIO_PWM2_IPG_SLV_CLK] = imx_clk_gate_scu("pwm_2_ipg_slv_clk", "pwm_2_ipg_s_clk", SC_R_PWM_2, SC_PM_CLK_PER, (void __iomem *)(PWM_2_LPCG), 0x14, 0);
+ clks[IMX8QXP_LSIO_PWM2_IPG_MSTR_CLK] = imx_clk_gate2_scu("pwm_2_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_2_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_PWM_2));
+ clks[IMX8QXP_LSIO_PWM2_HF_CLK] = imx_clk_gate_scu("pwm_2_hf_clk", "pwm_2_ipg_slv_clk", SC_R_PWM_2, SC_PM_CLK_PER, (void __iomem *)(PWM_2_LPCG), 4, 0);
+ clks[IMX8QXP_LSIO_PWM2_CLK] = imx_clk_gate_scu("pwm_2_clk", "pwm_2_ipg_slv_clk", SC_R_PWM_2, SC_PM_CLK_PER, (void __iomem *)(PWM_2_LPCG), 0, 0);
+ clks[IMX8QXP_LSIO_PWM3_DIV] = imx_clk_divider_scu("pwm_3_div", SC_R_PWM_3, SC_PM_CLK_PER);
+ clks[IMX8QXP_LSIO_PWM3_IPG_S_CLK] = imx_clk_gate_scu("pwm_3_ipg_s_clk", "pwm_3_div", SC_R_PWM_3, SC_PM_CLK_PER, (void __iomem *)(PWM_3_LPCG), 0x10, 0);
+ clks[IMX8QXP_LSIO_PWM3_IPG_SLV_CLK] = imx_clk_gate_scu("pwm_3_ipg_slv_clk", "pwm_3_ipg_s_clk", SC_R_PWM_3, SC_PM_CLK_PER, (void __iomem *)(PWM_3_LPCG), 0x14, 0);
+ clks[IMX8QXP_LSIO_PWM3_IPG_MSTR_CLK] = imx_clk_gate2_scu("pwm_3_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_3_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_PWM_3));
+ clks[IMX8QXP_LSIO_PWM3_HF_CLK] = imx_clk_gate_scu("pwm_3_hf_clk", "pwm_3_ipg_slv_clk", SC_R_PWM_3, SC_PM_CLK_PER, (void __iomem *)(PWM_3_LPCG), 4, 0);
+ clks[IMX8QXP_LSIO_PWM3_CLK] = imx_clk_gate_scu("pwm_3_clk", "pwm_3_ipg_slv_clk", SC_R_PWM_3, SC_PM_CLK_PER, (void __iomem *)(PWM_3_LPCG), 0, 0);
+ clks[IMX8QXP_LSIO_PWM4_DIV] = imx_clk_divider_scu("pwm_4_div", SC_R_PWM_4, SC_PM_CLK_PER);
+ clks[IMX8QXP_LSIO_PWM4_IPG_S_CLK] = imx_clk_gate_scu("pwm_4_ipg_s_clk", "pwm_4_div", SC_R_PWM_4, SC_PM_CLK_PER, (void __iomem *)(PWM_4_LPCG), 0x10, 0);
+ clks[IMX8QXP_LSIO_PWM4_IPG_SLV_CLK] = imx_clk_gate_scu("pwm_4_ipg_slv_clk", "pwm_4_ipg_s_clk", SC_R_PWM_4, SC_PM_CLK_PER, (void __iomem *)(PWM_4_LPCG), 0x14, 0);
+ clks[IMX8QXP_LSIO_PWM4_IPG_MSTR_CLK] = imx_clk_gate2_scu("pwm_4_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_4_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_PWM_4));
+ clks[IMX8QXP_LSIO_PWM4_HF_CLK] = imx_clk_gate_scu("pwm_4_hf_clk", "pwm_4_ipg_slv_clk", SC_R_PWM_4, SC_PM_CLK_PER, (void __iomem *)(PWM_4_LPCG), 4, 0);
+ clks[IMX8QXP_LSIO_PWM4_CLK] = imx_clk_gate_scu("pwm_4_clk", "pwm_4_ipg_slv_clk", SC_R_PWM_4, SC_PM_CLK_PER, (void __iomem *)(PWM_4_LPCG), 0, 0);
+ clks[IMX8QXP_LSIO_PWM5_DIV] = imx_clk_divider_scu("pwm_5_div", SC_R_PWM_5, SC_PM_CLK_PER);
+ clks[IMX8QXP_LSIO_PWM5_IPG_S_CLK] = imx_clk_gate_scu("pwm_5_ipg_s_clk", "pwm_5_div", SC_R_PWM_5, SC_PM_CLK_PER, (void __iomem *)(PWM_5_LPCG), 0x10, 0);
+ clks[IMX8QXP_LSIO_PWM5_IPG_SLV_CLK] = imx_clk_gate_scu("pwm_5_ipg_slv_clk", "pwm_5_ipg_s_clk", SC_R_PWM_5, SC_PM_CLK_PER, (void __iomem *)(PWM_5_LPCG), 0x14, 0);
+ clks[IMX8QXP_LSIO_PWM5_IPG_MSTR_CLK] = imx_clk_gate2_scu("pwm_5_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_5_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_PWM_5));
+ clks[IMX8QXP_LSIO_PWM5_HF_CLK] = imx_clk_gate_scu("pwm_5_hf_clk", "pwm_5_ipg_slv_clk", SC_R_PWM_5, SC_PM_CLK_PER, (void __iomem *)(PWM_5_LPCG), 4, 0);
+ clks[IMX8QXP_LSIO_PWM5_CLK] = imx_clk_gate_scu("pwm_5_clk", "pwm_5_ipg_slv_clk", SC_R_PWM_5, SC_PM_CLK_PER, (void __iomem *)(PWM_5_LPCG), 0, 0);
+ clks[IMX8QXP_LSIO_PWM6_DIV] = imx_clk_divider_scu("pwm_6_div", SC_R_PWM_6, SC_PM_CLK_PER);
+ clks[IMX8QXP_LSIO_PWM6_IPG_S_CLK] = imx_clk_gate_scu("pwm_6_ipg_s_clk", "pwm_6_div", SC_R_PWM_6, SC_PM_CLK_PER, (void __iomem *)(PWM_6_LPCG), 0x10, 0);
+ clks[IMX8QXP_LSIO_PWM6_IPG_SLV_CLK] = imx_clk_gate_scu("pwm_6_ipg_slv_clk", "pwm_6_ipg_s_clk", SC_R_PWM_6, SC_PM_CLK_PER, (void __iomem *)(PWM_6_LPCG), 0x14, 0);
+ clks[IMX8QXP_LSIO_PWM6_IPG_MSTR_CLK] = imx_clk_gate2_scu("pwm_6_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_6_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_PWM_6));
+ clks[IMX8QXP_LSIO_PWM6_HF_CLK] = imx_clk_gate_scu("pwm_6_hf_clk", "pwm_6_ipg_slv_clk", SC_R_PWM_6, SC_PM_CLK_PER, (void __iomem *)(PWM_6_LPCG), 4, 0);
+ clks[IMX8QXP_LSIO_PWM6_CLK] = imx_clk_gate_scu("pwm_6_clk", "pwm_6_ipg_slv_clk", SC_R_PWM_6, SC_PM_CLK_PER, (void __iomem *)(PWM_6_LPCG), 0, 0);
+ clks[IMX8QXP_LSIO_PWM7_DIV] = imx_clk_divider_scu("pwm_7_div", SC_R_PWM_7, SC_PM_CLK_PER);
+ clks[IMX8QXP_LSIO_PWM7_IPG_S_CLK] = imx_clk_gate_scu("pwm_7_ipg_s_clk", "pwm_7_div", SC_R_PWM_7, SC_PM_CLK_PER, (void __iomem *)(PWM_7_LPCG), 0x10, 0);
+ clks[IMX8QXP_LSIO_PWM7_IPG_SLV_CLK] = imx_clk_gate_scu("pwm_7_ipg_slv_clk", "pwm_7_ipg_s_clk", SC_R_PWM_7, SC_PM_CLK_PER, (void __iomem *)(PWM_7_LPCG), 0x14, 0);
+ clks[IMX8QXP_LSIO_PWM7_IPG_MSTR_CLK] = imx_clk_gate2_scu("pwm_7_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(PWM_7_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_PWM_7));
+ clks[IMX8QXP_LSIO_PWM7_HF_CLK] = imx_clk_gate_scu("pwm_7_hf_clk", "pwm_7_ipg_slv_clk", SC_R_PWM_7, SC_PM_CLK_PER, (void __iomem *)(PWM_7_LPCG), 4, 0);
+ clks[IMX8QXP_LSIO_PWM7_CLK] = imx_clk_gate_scu("pwm_7_clk", "pwm_7_ipg_slv_clk", SC_R_PWM_7, SC_PM_CLK_PER, (void __iomem *)(PWM_7_LPCG), 0, 0);
+ clks[IMX8QXP_LSIO_GPT0_DIV] = imx_clk_divider_scu("gpt_0_div", SC_R_GPT_4, SC_PM_CLK_PER);
+ clks[IMX8QXP_LSIO_GPT0_IPG_S_CLK] = imx_clk_gate_scu("gpt_0_ipg_s_clk", "gpt_0_div", SC_R_GPT_0, SC_PM_CLK_PER, (void __iomem *)(GPT_0_LPCG), 0x10, 0);
+ clks[IMX8QXP_LSIO_GPT0_IPG_SLV_CLK] = imx_clk_gate_scu("gpt_0_ipg_slv_clk", "gpt_0_ipg_s_clk", SC_R_GPT_0, SC_PM_CLK_PER, (void __iomem *)(GPT_0_LPCG), 0x14, 0);
+ clks[IMX8QXP_LSIO_GPT0_CLK] = imx_clk_gate_scu("gpt_0_clk", "gpt_0_ipg_slv_clk", SC_R_GPT_0, SC_PM_CLK_PER, (void __iomem *)(GPT_0_LPCG), 0, 0);
+ clks[IMX8QXP_LSIO_GPT0_IPG_MSTR_CLK] = imx_clk_gate2_scu("gpt_0_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(GPT_0_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_GPT_0));
+ clks[IMX8QXP_LSIO_GPT0_HF_CLK] = imx_clk_gate_scu("gpt_0_hf_clk", "gpt_0_ipg_slv_clk", SC_R_GPT_0, SC_PM_CLK_PER, (void __iomem *)(GPT_0_LPCG), 4, 0);
+ clks[IMX8QXP_LSIO_GPT1_DIV] = imx_clk_divider_scu("gpt_1_div", SC_R_GPT_4, SC_PM_CLK_PER);
+ clks[IMX8QXP_LSIO_GPT1_IPG_S_CLK] = imx_clk_gate_scu("gpt_1_ipg_s_clk", "gpt_1_div", SC_R_GPT_1, SC_PM_CLK_PER, (void __iomem *)(GPT_1_LPCG), 0x10, 0);
+ clks[IMX8QXP_LSIO_GPT1_IPG_SLV_CLK] = imx_clk_gate_scu("gpt_1_ipg_slv_clk", "gpt_1_ipg_s_clk", SC_R_GPT_1, SC_PM_CLK_PER, (void __iomem *)(GPT_1_LPCG), 0x14, 0);
+ clks[IMX8QXP_LSIO_GPT1_CLK] = imx_clk_gate_scu("gpt_1_clk", "gpt_1_ipg_slv_clk", SC_R_GPT_1, SC_PM_CLK_PER, (void __iomem *)(GPT_1_LPCG), 0, 0);
+ clks[IMX8QXP_LSIO_GPT1_HF_CLK] = imx_clk_gate_scu("gpt_1_hf_clk", "gpt_1_ipg_slv_clk", SC_R_GPT_1, SC_PM_CLK_PER, (void __iomem *)(GPT_1_LPCG), 4, 0);
+ clks[IMX8QXP_LSIO_GPT1_IPG_MSTR_CLK] = imx_clk_gate2_scu("gpt_1_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(GPT_1_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_GPT_1));
+ clks[IMX8QXP_LSIO_GPT2_DIV] = imx_clk_divider_scu("gpt_2_div", SC_R_GPT_4, SC_PM_CLK_PER);
+ clks[IMX8QXP_LSIO_GPT2_IPG_S_CLK] = imx_clk_gate_scu("gpt_2_ipg_s_clk", "gpt_2_div", SC_R_GPT_2, SC_PM_CLK_PER, (void __iomem *)(GPT_2_LPCG), 0x10, 0);
+ clks[IMX8QXP_LSIO_GPT2_IPG_SLV_CLK] = imx_clk_gate_scu("gpt_2_ipg_slv_clk", "gpt_2_ipg_s_clk", SC_R_GPT_2, SC_PM_CLK_PER, (void __iomem *)(GPT_2_LPCG), 0x14, 0);
+ clks[IMX8QXP_LSIO_GPT2_CLK] = imx_clk_gate_scu("gpt_2_clk", "gpt_2_ipg_slv_clk", SC_R_GPT_2, SC_PM_CLK_PER, (void __iomem *)(GPT_2_LPCG), 0, 0);
+ clks[IMX8QXP_LSIO_GPT2_HF_CLK] = imx_clk_gate_scu("gpt_2_hf_clk", "gpt_2_ipg_slv_clk", SC_R_GPT_2, SC_PM_CLK_PER, (void __iomem *)(GPT_2_LPCG), 4, 0);
+ clks[IMX8QXP_LSIO_GPT2_IPG_MSTR_CLK] = imx_clk_gate2_scu("gpt_2_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(GPT_2_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_GPT_2));
+ clks[IMX8QXP_LSIO_GPT3_DIV] = imx_clk_divider_scu("gpt_3_div", SC_R_GPT_4, SC_PM_CLK_PER);
+ clks[IMX8QXP_LSIO_GPT3_IPG_S_CLK] = imx_clk_gate_scu("gpt_3_ipg_s_clk", "gpt_3_div", SC_R_GPT_3, SC_PM_CLK_PER, (void __iomem *)(GPT_3_LPCG), 0x10, 0);
+ clks[IMX8QXP_LSIO_GPT3_IPG_SLV_CLK] = imx_clk_gate_scu("gpt_3_ipg_slv_clk", "gpt_3_ipg_s_clk", SC_R_GPT_3, SC_PM_CLK_PER, (void __iomem *)(GPT_3_LPCG), 0x14, 0);
+ clks[IMX8QXP_LSIO_GPT3_CLK] = imx_clk_gate_scu("gpt_3_clk", "gpt_3_ipg_slv_clk", SC_R_GPT_3, SC_PM_CLK_PER, (void __iomem *)(GPT_3_LPCG), 0, 0);
+ clks[IMX8QXP_LSIO_GPT3_HF_CLK] = imx_clk_gate_scu("gpt_3_hf_clk", "gpt_3_ipg_slv_clk", SC_R_GPT_3, SC_PM_CLK_PER, (void __iomem *)(GPT_3_LPCG), 4, 0);
+ clks[IMX8QXP_LSIO_GPT3_IPG_MSTR_CLK] = imx_clk_gate2_scu("gpt_3_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(GPT_3_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_GPT_3));
+ clks[IMX8QXP_LSIO_GPT4_DIV] = imx_clk_divider_scu("gpt_4_div", SC_R_GPT_4, SC_PM_CLK_PER);
+ clks[IMX8QXP_LSIO_GPT4_IPG_S_CLK] = imx_clk_gate_scu("gpt_4_ipg_s_clk", "gpt_4_div", SC_R_GPT_4, SC_PM_CLK_PER, (void __iomem *)(GPT_4_LPCG), 0x10, 0);
+ clks[IMX8QXP_LSIO_GPT4_IPG_SLV_CLK] = imx_clk_gate_scu("gpt_4_ipg_slv_clk", "gpt_4_ipg_s_clk", SC_R_GPT_4, SC_PM_CLK_PER, (void __iomem *)(GPT_4_LPCG), 0x14, 0);
+ clks[IMX8QXP_LSIO_GPT4_CLK] = imx_clk_gate_scu("gpt_4_clk", "gpt_4_ipg_slv_clk", SC_R_GPT_4, SC_PM_CLK_PER, (void __iomem *)(GPT_4_LPCG), 0, 0);
+ clks[IMX8QXP_LSIO_GPT4_HF_CLK] = imx_clk_gate_scu("gpt_4_hf_clk", "gpt_4_ipg_slv_clk", SC_R_GPT_4, SC_PM_CLK_PER, (void __iomem *)(GPT_4_LPCG), 4, 0);
+ clks[IMX8QXP_LSIO_GPT4_IPG_MSTR_CLK] = imx_clk_gate2_scu("gpt_4_ipg_mstr_clk", "lsio_bus_clk_root", (void __iomem *)(GPT_4_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_GPT_4));
+ clks[IMX8QXP_LSIO_FSPI0_DIV] = imx_clk_divider_scu("fspi_0_div", SC_R_FSPI_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_LSIO_FSPI0_HCLK] = imx_clk_gate2_scu("fspi0_hclk_clk", "lsio_mem_clk_root", (void __iomem *)(FSPI_0_LPCG), 0x10, FUNCTION_NAME(PD_LSIO_FSPI_0));
+ clks[IMX8QXP_LSIO_FSPI0_IPG_S_CLK] = imx_clk_gate2_scu("fspi0_ipg_s_clk", "lsio_bus_clk_root", (void __iomem *)(FSPI_0_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_FSPI_0));
+ clks[IMX8QXP_LSIO_FSPI0_IPG_CLK] = imx_clk_gate2_scu("fspi0_ipg_clk", "fspi0_ipg_s_clk", (void __iomem *)(FSPI_0_LPCG), 0x14, FUNCTION_NAME(PD_LSIO_FSPI_0));
+ clks[IMX8QXP_LSIO_FSPI0_CLK] = imx_clk_gate_scu("fspi_0_clk", "fspi_0_div", SC_R_FSPI_0, SC_PM_CLK_PER, (void __iomem *)(FSPI_0_LPCG), 0, 0);
+ clks[IMX8QXP_LSIO_FSPI1_DIV] = imx_clk_divider_scu("fspi_1_div", SC_R_FSPI_1, SC_PM_CLK_PER);
+ clks[IMX8QXP_LSIO_FSPI1_HCLK] = imx_clk_gate2_scu("fspi1_hclk_clk", "lsio_mem_clk_root", (void __iomem *)(FSPI_1_LPCG), 0x10, FUNCTION_NAME(PD_LSIO_FSPI_1));
+ clks[IMX8QXP_LSIO_FSPI1_IPG_S_CLK] = imx_clk_gate2_scu("fspi1_ipg_s_clk", "lsio_bus_clk_root", (void __iomem *)(FSPI_1_LPCG), 0x18, FUNCTION_NAME(PD_LSIO_FSPI_1));
+ clks[IMX8QXP_LSIO_FSPI1_IPG_CLK] = imx_clk_gate2_scu("fspi1_ipg_clk", "fspi1_ipg_s_clk", (void __iomem *)(FSPI_1_LPCG), 0x14, FUNCTION_NAME(PD_LSIO_FSPI_1));
+ clks[IMX8QXP_LSIO_FSPI1_CLK] = imx_clk_gate_scu("fspi_1_clk", "fspi_1_div", SC_R_FSPI_1, SC_PM_CLK_PER, (void __iomem *)(FSPI_1_LPCG), 0, 0);
+ clks[IMX8QXP_LSIO_MU5A_IPG_S_CLK] = imx_clk_gate2_scu("mu5_a_ipg_s_clk", "lsio_bus_clk_root", (void __iomem *)(MU_5A_LPCG), 0x10, FUNCTION_NAME(PD_LSIO_MU5A));
+ clks[IMX8QXP_LSIO_MU5A_IPG_CLK] = imx_clk_gate2_scu("mu5_a_ipg_clk", "mu5_a_ipg_s_clk", (void __iomem *)(MU_5A_LPCG), 0x0, FUNCTION_NAME(PD_LSIO_MU5A));
+ /* ADMA SS */
+ clks[IMX8QXP_UART1_IPG_CLK] = imx_clk_gate2_scu("uart1_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPUART_1_LPCG), 16, FUNCTION_NAME(PD_DMA_UART1));
+ clks[IMX8QXP_UART2_IPG_CLK] = imx_clk_gate2_scu("uart2_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPUART_2_LPCG), 16, FUNCTION_NAME(PD_DMA_UART2));
+ clks[IMX8QXP_UART3_IPG_CLK] = imx_clk_gate2_scu("uart3_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPUART_3_LPCG), 16, FUNCTION_NAME(PD_DMA_UART3));
+ clks[IMX8QXP_UART1_DIV] = imx_clk_divider_scu("uart1_div", SC_R_UART_1, SC_PM_CLK_PER);
+ clks[IMX8QXP_UART2_DIV] = imx_clk_divider_scu("uart2_div", SC_R_UART_2, SC_PM_CLK_PER);
+ clks[IMX8QXP_UART3_DIV] = imx_clk_divider_scu("uart3_div", SC_R_UART_3, SC_PM_CLK_PER);
+ clks[IMX8QXP_UART1_CLK] = imx_clk_gate_scu("uart1_clk", "uart1_div", SC_R_UART_1, SC_PM_CLK_PER, (void __iomem *)(LPUART_1_LPCG), 0, 0);
+ clks[IMX8QXP_UART2_CLK] = imx_clk_gate_scu("uart2_clk", "uart2_div", SC_R_UART_2, SC_PM_CLK_PER, (void __iomem *)(LPUART_2_LPCG), 0, 0);
+ clks[IMX8QXP_UART3_CLK] = imx_clk_gate_scu("uart3_clk", "uart3_div", SC_R_UART_3, SC_PM_CLK_PER, (void __iomem *)(LPUART_3_LPCG), 0, 0);
+ clks[IMX8QXP_SPI0_IPG_CLK] = imx_clk_gate2_scu("spi0_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPSPI_0_LPCG), 16, FUNCTION_NAME(PD_DMA_SPI_0));
+ clks[IMX8QXP_SPI1_IPG_CLK] = imx_clk_gate2_scu("spi1_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPSPI_1_LPCG), 16, FUNCTION_NAME(PD_DMA_SPI_1));
+ clks[IMX8QXP_SPI2_IPG_CLK] = imx_clk_gate2_scu("spi2_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPSPI_2_LPCG), 16, FUNCTION_NAME(PD_DMA_SPI_2));
+ clks[IMX8QXP_SPI3_IPG_CLK] = imx_clk_gate2_scu("spi3_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPSPI_3_LPCG), 16, FUNCTION_NAME(PD_DMA_SPI_3));
+ clks[IMX8QXP_SPI0_DIV] = imx_clk_divider_scu("spi0_div", SC_R_SPI_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_SPI1_DIV] = imx_clk_divider_scu("spi1_div", SC_R_SPI_1, SC_PM_CLK_PER);
+ clks[IMX8QXP_SPI2_DIV] = imx_clk_divider_scu("spi2_div", SC_R_SPI_2, SC_PM_CLK_PER);
+ clks[IMX8QXP_SPI3_DIV] = imx_clk_divider_scu("spi3_div", SC_R_SPI_3, SC_PM_CLK_PER);
+ clks[IMX8QXP_SPI0_CLK] = imx_clk_gate_scu("spi0_clk", "spi0_div", SC_R_SPI_0, SC_PM_CLK_PER, (void __iomem *)(LPSPI_0_LPCG), 0, 0);
+ clks[IMX8QXP_SPI1_CLK] = imx_clk_gate_scu("spi1_clk", "spi1_div", SC_R_SPI_1, SC_PM_CLK_PER, (void __iomem *)(LPSPI_1_LPCG), 0, 0);
+ clks[IMX8QXP_SPI2_CLK] = imx_clk_gate_scu("spi2_clk", "spi2_div", SC_R_SPI_2, SC_PM_CLK_PER, (void __iomem *)(LPSPI_2_LPCG), 0, 0);
+ clks[IMX8QXP_SPI3_CLK] = imx_clk_gate_scu("spi3_clk", "spi3_div", SC_R_SPI_3, SC_PM_CLK_PER, (void __iomem *)(LPSPI_3_LPCG), 0, 0);
+ clks[IMX8QXP_CAN0_IPG_CHI_CLK] = imx_clk_gate2_scu("can0_ipg_chi_clk", "ipg_dma_clk_root", (void __iomem *)(FLEX_CAN_0_LPCG), 20, FUNCTION_NAME(PD_DMA_CAN_0));
+ clks[IMX8QXP_CAN0_IPG_CLK] = imx_clk_gate2_scu("can0_ipg_clk", "can0_ipg_chi_clk", (void __iomem *)(FLEX_CAN_0_LPCG), 16, FUNCTION_NAME(PD_DMA_CAN_0));
+ clks[IMX8QXP_CAN1_IPG_CHI_CLK] = imx_clk_gate2_scu("can1_ipg_chi_clk", "ipg_dma_clk_root", (void __iomem *)(FLEX_CAN_1_LPCG), 20, FUNCTION_NAME(PD_DMA_CAN_1));
+ clks[IMX8QXP_CAN1_IPG_CLK] = imx_clk_gate2_scu("can1_ipg_clk", "can1_ipg_chi_clk", (void __iomem *)(FLEX_CAN_1_LPCG), 16, FUNCTION_NAME(PD_DMA_CAN_1));
+ clks[IMX8QXP_CAN2_IPG_CHI_CLK] = imx_clk_gate2_scu("can2_ipg_chi_clk", "ipg_dma_clk_root", (void __iomem *)(FLEX_CAN_2_LPCG), 20, FUNCTION_NAME(PD_DMA_CAN_2));
+ clks[IMX8QXP_CAN2_IPG_CLK] = imx_clk_gate2_scu("can2_ipg_clk", "can2_ipg_chi_clk", (void __iomem *)(FLEX_CAN_2_LPCG), 16, FUNCTION_NAME(PD_DMA_CAN_2));
+ clks[IMX8QXP_CAN0_DIV] = imx_clk_divider_scu("can0_div", SC_R_CAN_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_CAN1_DIV] = imx_clk_divider_scu("can1_div", SC_R_CAN_1, SC_PM_CLK_PER);
+ clks[IMX8QXP_CAN2_DIV] = imx_clk_divider_scu("can2_div", SC_R_CAN_2, SC_PM_CLK_PER);
+ clks[IMX8QXP_CAN0_CLK] = imx_clk_gate_scu("can0_clk", "can0_div", SC_R_CAN_0, SC_PM_CLK_PER, (void __iomem *)(FLEX_CAN_0_LPCG), 0, 0);
+ clks[IMX8QXP_CAN1_CLK] = imx_clk_gate_scu("can1_clk", "can1_div", SC_R_CAN_1, SC_PM_CLK_PER, (void __iomem *)(FLEX_CAN_1_LPCG), 0, 0);
+ clks[IMX8QXP_CAN2_CLK] = imx_clk_gate_scu("can2_clk", "can2_div", SC_R_CAN_2, SC_PM_CLK_PER, (void __iomem *)(FLEX_CAN_2_LPCG), 0, 0);
+ clks[IMX8QXP_I2C0_IPG_CLK] = imx_clk_gate2_scu("i2c0_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPI2C_0_LPCG), 16, FUNCTION_NAME(PD_DMA_I2C_0));
+ clks[IMX8QXP_I2C1_IPG_CLK] = imx_clk_gate2_scu("i2c1_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPI2C_1_LPCG), 16, FUNCTION_NAME(PD_DMA_I2C_1));
+ clks[IMX8QXP_I2C2_IPG_CLK] = imx_clk_gate2_scu("i2c2_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPI2C_2_LPCG), 16, FUNCTION_NAME(PD_DMA_I2C_2));
+ clks[IMX8QXP_I2C3_IPG_CLK] = imx_clk_gate2_scu("i2c3_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LPI2C_3_LPCG), 16, FUNCTION_NAME(PD_DMA_I2C_3));
+ clks[IMX8QXP_I2C0_DIV] = imx_clk_divider_scu("i2c0_div", SC_R_I2C_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_I2C1_DIV] = imx_clk_divider_scu("i2c1_div", SC_R_I2C_1, SC_PM_CLK_PER);
+ clks[IMX8QXP_I2C2_DIV] = imx_clk_divider_scu("i2c2_div", SC_R_I2C_2, SC_PM_CLK_PER);
+ clks[IMX8QXP_I2C3_DIV] = imx_clk_divider_scu("i2c3_div", SC_R_I2C_3, SC_PM_CLK_PER);
+ clks[IMX8QXP_I2C0_CLK] = imx_clk_gate_scu("i2c0_clk", "i2c0_div", SC_R_I2C_0, SC_PM_CLK_PER, (void __iomem *)(LPI2C_0_LPCG), 0, 0);
+ clks[IMX8QXP_I2C1_CLK] = imx_clk_gate_scu("i2c1_clk", "i2c1_div", SC_R_I2C_1, SC_PM_CLK_PER, (void __iomem *)(LPI2C_1_LPCG), 0, 0);
+ clks[IMX8QXP_I2C2_CLK] = imx_clk_gate_scu("i2c2_clk", "i2c2_div", SC_R_I2C_2, SC_PM_CLK_PER, (void __iomem *)(LPI2C_2_LPCG), 0, 0);
+ clks[IMX8QXP_I2C3_CLK] = imx_clk_gate_scu("i2c3_clk", "i2c3_div", SC_R_I2C_3, SC_PM_CLK_PER, (void __iomem *)(LPI2C_3_LPCG), 0, 0);
+ clks[IMX8QXP_FTM0_IPG_CLK] = imx_clk_gate2_scu("ftm0_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(FTM_0_LPCG), 16, FUNCTION_NAME(PD_DMA_FTM_0));
+ clks[IMX8QXP_FTM1_IPG_CLK] = imx_clk_gate2_scu("ftm1_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(FTM_1_LPCG), 16, FUNCTION_NAME(PD_DMA_FTM_1));
+ clks[IMX8QXP_FTM0_DIV] = imx_clk_divider_scu("ftm0_div", SC_R_FTM_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_FTM1_DIV] = imx_clk_divider_scu("ftm1_div", SC_R_FTM_1, SC_PM_CLK_PER);
+ clks[IMX8QXP_FTM0_CLK] = imx_clk_gate_scu("ftm0_clk", "ftm0_div", SC_R_FTM_0, SC_PM_CLK_PER, (void __iomem *)(FTM_0_LPCG), 0, 0);
+ clks[IMX8QXP_FTM1_CLK] = imx_clk_gate_scu("ftm1_clk", "ftm1_div", SC_R_FTM_1, SC_PM_CLK_PER, (void __iomem *)(FTM_1_LPCG), 0, 0);
+ clks[IMX8QXP_ADC0_IPG_CLK] = imx_clk_gate2_scu("adc0_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(ADC_0_LPCG), 16, FUNCTION_NAME(PD_DMA_ADC_0));
+ clks[IMX8QXP_ADC0_DIV] = imx_clk_divider_scu("adc0_div", SC_R_ADC_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_ADC0_CLK] = imx_clk_gate_scu("adc0_clk", "adc0_div", SC_R_ADC_0, SC_PM_CLK_PER, (void __iomem *)(ADC_0_LPCG), 0, 0);
+ clks[IMX8QXP_PWM_IPG_CLK] = imx_clk_gate2_scu("pwm_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(PWM_LPCG), 16, FUNCTION_NAME(PD_DMA_PWM_0));
+ clks[IMX8QXP_PWM_DIV] = imx_clk_divider_scu("pwm_div", SC_R_LCD_0_PWM_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_PWM_CLK] = imx_clk_gate_scu("pwm_clk", "pwm_div", SC_R_LCD_0_PWM_0, SC_PM_CLK_PER, (void __iomem *)(PWM_LPCG), 0, 0);
+ clks[IMX8QXP_LCD_IPG_CLK] = imx_clk_gate2_scu("lcd_ipg_clk", "ipg_dma_clk_root", (void __iomem *)(LCD_LPCG), 16, FUNCTION_NAME(PD_DMA_LCD_0));
+
+ clks[IMX8QXP_LCD_PXL_BYPASS_DIV] = imx_clk_divider_scu("lcd_pxl_bypass_div", SC_R_LCD_0, SC_PM_CLK_BYPASS);
+ clks[IMX8QXP_LCD_PXL_SEL] = imx_clk_mux2_scu("lcd_pxl_sel", lcd_pxl_sels, ARRAY_SIZE(lcd_pxl_sels), SC_R_LCD_0, SC_PM_CLK_MISC0);
+ clks[IMX8QXP_LCD_PXL_DIV] = imx_clk_divider2_scu("lcd_pxl_div", "lcd_pxl_sel", SC_R_LCD_0, SC_PM_CLK_MISC0);
+ clks[IMX8QXP_LCD_PXL_CLK] = imx_clk_gate_scu("lcd_pxl_clk", "lcd_pxl_div", SC_R_LCD_0, SC_PM_CLK_MISC0, NULL, 0, 0);
+ clks[IMX8QXP_LCD_SEL] = imx_clk_mux2_scu("lcd_sel", lcd_sels, ARRAY_SIZE(lcd_sels), SC_R_LCD_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_LCD_DIV] = imx_clk_divider2_scu("lcd_div", "lcd_sel", SC_R_LCD_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_LCD_CLK] = imx_clk_gate_scu("lcd_clk", "lcd_div", SC_R_LCD_0, SC_PM_CLK_PER, (void __iomem *)(LCD_LPCG), 0, 0);
+
+ /* Connectivity */
+ clks[IMX8QXP_SDHC0_IPG_CLK] = imx_clk_gate2_scu("sdhc0_ipg_clk", "ipg_conn_clk_root", (void __iomem *)(USDHC_0_LPCG), 16, FUNCTION_NAME(PD_CONN_SDHC_0));
+ clks[IMX8QXP_SDHC1_IPG_CLK] = imx_clk_gate2_scu("sdhc1_ipg_clk", "ipg_conn_clk_root", (void __iomem *)(USDHC_1_LPCG), 16, FUNCTION_NAME(PD_CONN_SDHC_1));
+ clks[IMX8QXP_SDHC2_IPG_CLK] = imx_clk_gate2_scu("sdhc2_ipg_clk", "ipg_conn_clk_root", (void __iomem *)(USDHC_2_LPCG), 16, FUNCTION_NAME(PD_CONN_SDHC_2));
+ clks[IMX8QXP_SDHC0_SEL] = imx_clk_mux2_scu("sdhc0_sel", sdhc0_sels, ARRAY_SIZE(sdhc0_sels), SC_R_SDHC_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_SDHC1_SEL] = imx_clk_mux2_scu("sdhc1_sel", sdhc1_sels, ARRAY_SIZE(sdhc1_sels), SC_R_SDHC_1, SC_PM_CLK_PER);
+ clks[IMX8QXP_SDHC2_SEL] = imx_clk_mux2_scu("sdhc2_sel", sdhc2_sels, ARRAY_SIZE(sdhc2_sels), SC_R_SDHC_2, SC_PM_CLK_PER);
+ clks[IMX8QXP_SDHC0_DIV] = imx_clk_divider2_scu("sdhc0_div", "sdhc0_sel", SC_R_SDHC_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_SDHC1_DIV] = imx_clk_divider2_scu("sdhc1_div", "sdhc1_sel", SC_R_SDHC_1, SC_PM_CLK_PER);
+ clks[IMX8QXP_SDHC2_DIV] = imx_clk_divider2_scu("sdhc2_div", "sdhc2_sel", SC_R_SDHC_2, SC_PM_CLK_PER);
+ clks[IMX8QXP_SDHC0_CLK] = imx_clk_gate_scu("sdhc0_clk", "sdhc0_div", SC_R_SDHC_0, SC_PM_CLK_PER, (void __iomem *)(USDHC_0_LPCG), 0, 0);
+ clks[IMX8QXP_SDHC1_CLK] = imx_clk_gate_scu("sdhc1_clk", "sdhc1_div", SC_R_SDHC_1, SC_PM_CLK_PER, (void __iomem *)(USDHC_1_LPCG), 0, 0);
+ clks[IMX8QXP_SDHC2_CLK] = imx_clk_gate_scu("sdhc2_clk", "sdhc2_div", SC_R_SDHC_2, SC_PM_CLK_PER, (void __iomem *)(USDHC_2_LPCG), 0, 0);
+ clks[IMX8QXP_ENET0_ROOT_DIV] = imx_clk_divider_scu("enet0_root_div", SC_R_ENET_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_ENET0_REF_DIV] = imx_clk_divider3_scu("enet0_ref_div", "enet0_root_clk", SC_R_ENET_0, SC_C_CLKDIV);
+ clks[IMX8QXP_ENET1_REF_DIV] = imx_clk_divider3_scu("enet1_ref_div", "enet1_root_clk", SC_R_ENET_1, SC_C_CLKDIV);
+ clks[IMX8QXP_ENET0_BYPASS_DIV] = imx_clk_divider_scu("enet0_bypass_div", SC_R_ENET_0, SC_PM_CLK_BYPASS);
+ clks[IMX8QXP_ENET0_RGMII_DIV] = imx_clk_divider_scu("enet0_rgmii_div", SC_R_ENET_0, SC_PM_CLK_MISC0);
+ clks[IMX8QXP_ENET1_ROOT_DIV] = imx_clk_divider_scu("enet1_root_div", SC_R_ENET_1, SC_PM_CLK_PER);
+ clks[IMX8QXP_ENET1_BYPASS_DIV] = imx_clk_divider_scu("enet1_bypass_div", SC_R_ENET_1, SC_PM_CLK_BYPASS);
+ clks[IMX8QXP_ENET1_RGMII_DIV] = imx_clk_divider_scu("enet1_rgmii_div", SC_R_ENET_1, SC_PM_CLK_MISC0);
+ clks[IMX8QXP_ENET0_AHB_CLK] = imx_clk_gate2_scu("enet0_ahb_clk", "axi_conn_clk_root", (void __iomem *)(ENET_0_LPCG), 8, FUNCTION_NAME(PD_CONN_ENET_0));
+ clks[IMX8QXP_ENET0_IPG_S_CLK] = imx_clk_gate2_scu("enet0_ipg_s_clk", "ipg_conn_clk_root", (void __iomem *)(ENET_0_LPCG), 20, FUNCTION_NAME(PD_CONN_ENET_0));
+ clks[IMX8QXP_ENET0_IPG_CLK] = imx_clk_gate2_scu("enet0_ipg_clk", "enet0_ipg_s_clk", (void __iomem *)(ENET_0_LPCG), 16, FUNCTION_NAME(PD_CONN_ENET_0));
+ clks[IMX8QXP_ENET1_AHB_CLK] = imx_clk_gate2_scu("enet1_ahb_clk", "axi_conn_clk_root", (void __iomem *)(ENET_1_LPCG), 8, FUNCTION_NAME(PD_CONN_ENET_1));
+ clks[IMX8QXP_ENET1_IPG_S_CLK] = imx_clk_gate2_scu("enet1_ipg_s_clk", "ipg_conn_clk_root", (void __iomem *)(ENET_1_LPCG), 20, FUNCTION_NAME(PD_CONN_ENET_1));
+ clks[IMX8QXP_ENET1_IPG_CLK] = imx_clk_gate2_scu("enet1_ipg_clk", "enet1_ipg_s_clk", (void __iomem *)(ENET_1_LPCG), 16, FUNCTION_NAME(PD_CONN_ENET_1));
+ clks[IMX8QXP_ENET0_ROOT_CLK] = imx_clk_gate_scu("enet0_root_clk", "enet0_root_div", SC_R_ENET_0, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QXP_ENET1_ROOT_CLK] = imx_clk_gate_scu("enet1_root_clk", "enet1_root_div", SC_R_ENET_1, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QXP_ENET0_TX_CLK] = imx_clk_gate2_scu("enet0_tx_2x_clk", "enet0_root_clk", (void __iomem *)(ENET_0_LPCG), 4, FUNCTION_NAME(PD_CONN_ENET_0));
+ clks[IMX8QXP_ENET1_TX_CLK] = imx_clk_gate2_scu("enet1_tx_2x_clk", "enet1_root_clk", (void __iomem *)(ENET_1_LPCG), 4, FUNCTION_NAME(PD_CONN_ENET_1));
+ clks[IMX8QXP_ENET0_PTP_CLK] = imx_clk_gate2_scu("enet0_ptp_clk", "enet0_root_clk", (void __iomem *)(ENET_0_LPCG), 0, FUNCTION_NAME(PD_CONN_ENET_0));
+ clks[IMX8QXP_ENET1_PTP_CLK] = imx_clk_gate2_scu("enet1_ptp_clk", "enet1_root_clk", (void __iomem *)(ENET_1_LPCG), 0, FUNCTION_NAME(PD_CONN_ENET_1));
+ clks[IMX8QXP_ENET0_REF_25MHZ_125MHZ_SEL] = imx_clk_mux_gpr_scu("enet0_ref_25_125_sel", enet_sels, ARRAY_SIZE(enet_sels), SC_R_ENET_0, SC_C_SEL_125);
+ clks[IMX8QXP_ENET1_REF_25MHZ_125MHZ_SEL] = imx_clk_mux_gpr_scu("enet1_ref_25_125_sel", enet_sels, ARRAY_SIZE(enet_sels), SC_R_ENET_1, SC_C_SEL_125);
+ clks[IMX8QXP_ENET0_RMII_TX_SEL] = imx_clk_mux_gpr_scu("enet0_rmii_tx_sel", enet0_rmii_tx_sels, ARRAY_SIZE(enet0_rmii_tx_sels), SC_R_ENET_0, SC_C_TXCLK);
+ clks[IMX8QXP_ENET1_RMII_TX_SEL] = imx_clk_mux_gpr_scu("enet1_rmii_tx_sel", enet1_rmii_tx_sels, ARRAY_SIZE(enet1_rmii_tx_sels), SC_R_ENET_1, SC_C_TXCLK);
+ clks[IMX8QXP_ENET0_RGMII_TX_CLK] = imx_clk_gate2_scu("enet0_rgmii_tx_clk", "enet0_rmii_tx_sel", (void __iomem *)(ENET_0_LPCG), 12, FUNCTION_NAME(PD_CONN_ENET_0));
+ clks[IMX8QXP_ENET1_RGMII_TX_CLK] = imx_clk_gate2_scu("enet1_rgmii_tx_clk", "enet1_rmii_tx_sel", (void __iomem *)(ENET_1_LPCG), 12, FUNCTION_NAME(PD_CONN_ENET_1));
+ clks[IMX8QXP_ENET0_RMII_RX_CLK] = imx_clk_gate2_scu("enet0_rgmii_rx_clk", "enet0_rgmii_div", (void __iomem *)(ENET_0_LPCG + 0x4), 0, FUNCTION_NAME(PD_CONN_ENET_0));
+ clks[IMX8QXP_ENET1_RMII_RX_CLK] = imx_clk_gate2_scu("enet1_rgmii_rx_clk", "enet1_rgmii_div", (void __iomem *)(ENET_1_LPCG + 0x4), 0, FUNCTION_NAME(PD_CONN_ENET_1));
+ clks[IMX8QXP_ENET0_REF_25MHZ_125MHZ_CLK] = imx_clk_gate3_scu("enet0_ref_25_125_clk", "enet0_ref_25_125_sel", SC_R_ENET_0, SC_C_DISABLE_125, true);
+ clks[IMX8QXP_ENET1_REF_25MHZ_125MHZ_CLK] = imx_clk_gate3_scu("enet1_ref_25_125_clk", "enet1_ref_25_125_sel", SC_R_ENET_1, SC_C_DISABLE_125, true);
+ clks[IMX8QXP_ENET0_REF_50MHZ_CLK] = imx_clk_gate3_scu("enet0_ref_50_clk", NULL, SC_R_ENET_0, SC_C_DISABLE_50, true);
+ clks[IMX8QXP_ENET1_REF_50MHZ_CLK] = imx_clk_gate3_scu("enet1_ref_50_clk", NULL, SC_R_ENET_1, SC_C_DISABLE_50, true);
+ clks[IMX8QXP_GPMI_BCH_IO_DIV] = imx_clk_divider_scu("gpmi_io_div", SC_R_NAND, SC_PM_CLK_MST_BUS);
+ clks[IMX8QXP_GPMI_BCH_DIV] = imx_clk_divider_scu("gpmi_bch_div", SC_R_NAND, SC_PM_CLK_PER);
+ clks[IMX8QXP_GPMI_APB_CLK] = imx_clk_gate2_scu("gpmi_apb_clk", "axi_conn_clk_root", (void __iomem *)(NAND_LPCG), 16, FUNCTION_NAME(PD_CONN_NAND));
+ clks[IMX8QXP_GPMI_APB_BCH_CLK] = imx_clk_gate2_scu("gpmi_apb_bch_clk", "axi_conn_clk_root", (void __iomem *)(NAND_LPCG), 20, FUNCTION_NAME(PD_CONN_NAND));
+ clks[IMX8QXP_GPMI_BCH_IO_CLK] = imx_clk_gate_scu("gpmi_io_clk", "gpmi_io_div", SC_R_NAND, SC_PM_CLK_MST_BUS, (void __iomem *)(NAND_LPCG), 4, 0);
+ clks[IMX8QXP_GPMI_BCH_CLK] = imx_clk_gate_scu("gpmi_bch_clk", "gpmi_bch_div", SC_R_NAND, SC_PM_CLK_PER, (void __iomem *)(NAND_LPCG), 0, 0);
+ clks[IMX8QXP_APBHDMA_CLK] = imx_clk_gate2_scu("gpmi_clk", "axi_conn_clk_root", (void __iomem *)(NAND_LPCG + 0x4), 16, FUNCTION_NAME(PD_CONN_NAND));
+ clks[IMX8QXP_USB3_ACLK_DIV] = imx_clk_divider_scu("usb3_aclk_div", SC_R_USB_2, SC_PM_CLK_PER);
+ clks[IMX8QXP_USB3_BUS_DIV] = imx_clk_divider_scu("usb3_bus_div", SC_R_USB_2, SC_PM_CLK_MST_BUS);
+ clks[IMX8QXP_USB3_LPM_DIV] = imx_clk_divider_scu("usb3_lpm_div", SC_R_USB_2, SC_PM_CLK_MISC);
+ clks[IMX8QXP_USB2_OH_AHB_CLK] = imx_clk_gate2_scu("usboh3", "ahb_conn_clk_root", (void __iomem *)(USB_2_LPCG), 24, FUNCTION_NAME(PD_CONN_USB_0));
+ clks[IMX8QXP_USB2_OH_IPG_S_CLK] = imx_clk_gate2_scu("usboh3_ipg_s", "ipg_conn_clk_root", (void __iomem *)(USB_2_LPCG), 16, FUNCTION_NAME(PD_CONN_USB_0));
+ clks[IMX8QXP_USB2_OH_IPG_S_PL301_CLK] = imx_clk_gate2_scu("usboh3_ipg_pl301_s", "ipg_conn_clk_root", (void __iomem *)(USB_2_LPCG), 20, FUNCTION_NAME(PD_CONN_USB_0));
+ clks[IMX8QXP_USB2_PHY_IPG_CLK] = imx_clk_gate2_scu("usboh3_phy_clk", "ipg_conn_clk_root", (void __iomem *)(USB_2_LPCG), 28, FUNCTION_NAME(PD_CONN_USB_0));
+ clks[IMX8QXP_USB3_IPG_CLK] = imx_clk_gate2_scu("usb3_ipg_clk", "ipg_conn_clk_root", (void __iomem *)(USB_3_LPCG), 16, FUNCTION_NAME(PD_CONN_USB_2));
+ clks[IMX8QXP_USB3_CORE_PCLK] = imx_clk_gate2_scu("usb3_core_clk", "ipg_conn_clk_root", (void __iomem *)(USB_3_LPCG), 20, FUNCTION_NAME(PD_CONN_USB_2));
+ clks[IMX8QXP_USB3_PHY_CLK] = imx_clk_gate2_scu("usb3_phy_clk", "usb3_ipg_clk", (void __iomem *)(USB_3_LPCG), 24, FUNCTION_NAME(PD_CONN_USB_2_PHY));
+ clks[IMX8QXP_USB3_ACLK] = imx_clk_gate_scu("usb3_aclk", "usb3_aclk_div", SC_R_USB_2, SC_PM_CLK_PER, (void __iomem *)(USB_3_LPCG), 28, 0);
+ clks[IMX8QXP_USB3_BUS_CLK] = imx_clk_gate_scu("usb3_bus_clk", "usb3_bus_div", SC_R_USB_2, SC_PM_CLK_MST_BUS, (void __iomem *)(USB_3_LPCG), 0, 0);
+ clks[IMX8QXP_USB3_LPM_CLK] = imx_clk_gate_scu("usb3_lpm_clk", "usb3_lpm_div", SC_R_USB_2, SC_PM_CLK_MISC, (void __iomem *)(USB_3_LPCG), 4, 0);
+ clks[IMX8QXP_EDMA_CLK] = imx_clk_gate2_scu("edma_clk", "axi_conn_clk_root", (void __iomem *)(EDMA_LPCG), 0, FUNCTION_NAME(PD_CONN_DMA_4_CH0));
+ clks[IMX8QXP_EDMA_IPG_CLK] = imx_clk_gate2_scu("edma_ipg_clk", "ipg_conn_clk_root", (void __iomem *)(EDMA_LPCG), 16, FUNCTION_NAME(PD_CONN_DMA_4_CH0));
+ clks[IMX8QXP_MLB_HCLK] = imx_clk_gate2_scu("mlb_hclk", "axi_conn_clk_root", (void __iomem *)(MLB_LPCG), 20, FUNCTION_NAME(PD_CONN_MLB_0));
+ clks[IMX8QXP_MLB_CLK] = imx_clk_gate2_scu("mlb_clk", "mlb_hclk", (void __iomem *)(MLB_LPCG), 0, FUNCTION_NAME(PD_CONN_MLB_0));
+ clks[IMX8QXP_MLB_IPG_CLK] = imx_clk_gate2_scu("mlb_ipg_clk", "ipg_conn_clk_root", (void __iomem *)(MLB_LPCG), 16, FUNCTION_NAME(PD_CONN_MLB_0));
+
+ /* Display controller - DC0 SS */
+ clks[IMX8QXP_DC0_PLL0_DIV] = imx_clk_divider_scu("dc0_pll0_div", SC_R_DC_0_PLL_0, SC_PM_CLK_PLL);
+ clks[IMX8QXP_DC0_PLL1_DIV] = imx_clk_divider_scu("dc0_pll1_div", SC_R_DC_0_PLL_1, SC_PM_CLK_PLL);
+ clks[IMX8QXP_DC0_PLL0_CLK] = imx_clk_gate_scu("dc0_pll0_clk", "dc0_pll0_div", SC_R_DC_0_PLL_0, SC_PM_CLK_PLL, NULL, 0, 0);
+ clks[IMX8QXP_DC0_PLL1_CLK] = imx_clk_gate_scu("dc0_pll1_clk", "dc0_pll1_div", SC_R_DC_0_PLL_1, SC_PM_CLK_PLL, NULL, 0, 0);
+ clks[IMX8QXP_DC0_DISP0_DIV] = imx_clk_divider_scu("dc0_disp0_div", SC_R_DC_0, SC_PM_CLK_MISC0);
+ clks[IMX8QXP_DC0_DISP1_DIV] = imx_clk_divider_scu("dc0_disp1_div", SC_R_DC_0, SC_PM_CLK_MISC1);
+ clks[IMX8QXP_DC0_DISP0_CLK] = imx_clk_gate_scu("dc0_disp0_clk", "dc0_disp0_div", SC_R_DC_0, SC_PM_CLK_MISC0, (void __iomem *)(DC_0_LPCG), 0, 0);
+ clks[IMX8QXP_DC0_DISP1_CLK] = imx_clk_gate_scu("dc0_disp1_clk", "dc0_disp1_div", SC_R_DC_0, SC_PM_CLK_MISC1, (void __iomem *)(DC_0_LPCG), 4, 0);
+ clks[IMX8QXP_DC0_BYPASS_0_DIV] = imx_clk_divider_scu("dc0_bypass0_div", SC_R_DC_0_VIDEO0, SC_PM_CLK_BYPASS);
+ clks[IMX8QXP_DC0_BYPASS_1_DIV] = imx_clk_divider_scu("dc0_bypass1_div", SC_R_DC_0_VIDEO1, SC_PM_CLK_BYPASS);
+ clks[IMX8QXP_DC0_PRG0_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg0_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x20), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG0_APB_CLK] = imx_clk_gate2_scu("dc0_prg0_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x20), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG1_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg1_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x24), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG1_APB_CLK] = imx_clk_gate2_scu("dc0_prg1_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x24), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG2_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg2_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x28), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG2_APB_CLK] = imx_clk_gate2_scu("dc0_prg2_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x28), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG3_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg3_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x34), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG3_APB_CLK] = imx_clk_gate2_scu("dc0_prg3_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x34), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG4_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg4_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x38), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG4_APB_CLK] = imx_clk_gate2_scu("dc0_prg4_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x38), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG5_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg5_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x3c), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG5_APB_CLK] = imx_clk_gate2_scu("dc0_prg5_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x3c), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG6_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg6_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x40), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG6_APB_CLK] = imx_clk_gate2_scu("dc0_prg6_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x40), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG7_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg7_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x44), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG7_APB_CLK] = imx_clk_gate2_scu("dc0_prg7_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x44), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG8_RTRAM_CLK] = imx_clk_gate2_scu("dc0_prg8_rtram_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x48), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_PRG8_APB_CLK] = imx_clk_gate2_scu("dc0_prg8_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x48), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_DPR0_APB_CLK] = imx_clk_gate2_scu("dc0_dpr0_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x18), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_DPR0_B_CLK] = imx_clk_gate2_scu("dc0_dpr0_b_clk", "axi_ext_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x18), 20, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_RTRAM0_CLK] = imx_clk_gate2_scu("dc0_rtrm0_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x1C), 0, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_DPR1_APB_CLK] = imx_clk_gate2_scu("dc0_dpr1_apb_clk", "cfg_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x2C), 16, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_DPR1_B_CLK] = imx_clk_gate2_scu("dc0_dpr1_b_clk", "axi_ext_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x2C), 20, FUNCTION_NAME(PD_DC_0));
+ clks[IMX8QXP_DC0_RTRAM1_CLK] = imx_clk_gate2_scu("dc0_rtrm1_clk", "axi_int_dc_clk_root", (void __iomem *)(DC_0_LPCG + 0x30), 0, FUNCTION_NAME(PD_DC_0));
+
+ /* Display interface - MIPI-LVDS SS */
+ clks[IMX8QXP_MIPI0_BYPASS_CLK] = imx_clk_divider_scu("mipi0_bypass_clk", SC_R_MIPI_0, SC_PM_CLK_BYPASS);
+ clks[IMX8QXP_MIPI0_PIXEL_DIV] = imx_clk_divider_scu("mipi0_pixel_div", SC_R_MIPI_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_MIPI0_PIXEL_CLK] = imx_clk_gate_scu("mipi0_pixel_clk", "mipi0_pixel_div", SC_R_MIPI_0, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QXP_MIPI0_LVDS_PIXEL_DIV] = imx_clk_divider_scu("mipi0_lvds_pixel_div", SC_R_LVDS_0, SC_PM_CLK_MISC2);
+ clks[IMX8QXP_MIPI0_LVDS_PIXEL_CLK] = imx_clk_gate_scu("mipi0_lvds_pixel_clk", "mipi0_lvds_pixel_div", SC_R_LVDS_0, SC_PM_CLK_MISC2, NULL, 0, 0);
+ clks[IMX8QXP_MIPI0_LVDS_BYPASS_CLK] = imx_clk_divider_scu("mipi0_lvds_bypass_clk", SC_R_LVDS_0, SC_PM_CLK_BYPASS);
+ clks[IMX8QXP_MIPI0_LVDS_PHY_DIV] = imx_clk_divider_scu("mipi0_lvds_phy_div", SC_R_LVDS_0, SC_PM_CLK_MISC3);
+ clks[IMX8QXP_MIPI0_LVDS_PHY_CLK] = imx_clk_gate_scu("mipi0_lvds_phy_clk", "mipi0_lvds_phy_div", SC_R_LVDS_0, SC_PM_CLK_MISC3, NULL, 0, 0);
+ clks[IMX8QXP_MIPI0_DSI_TX_ESC_SEL] = imx_clk_mux2_scu("mipi0_dsi_tx_esc_sel", mipi0_sels, ARRAY_SIZE(mipi0_sels), SC_R_MIPI_0, SC_PM_CLK_MST_BUS);
+ clks[IMX8QXP_MIPI0_DSI_TX_ESC_DIV] = imx_clk_divider2_scu("mipi0_dsi_tx_esc_div", "mipi0_dsi_tx_esc_sel", SC_R_MIPI_0, SC_PM_CLK_MST_BUS);
+ clks[IMX8QXP_MIPI0_DSI_TX_ESC_CLK] = imx_clk_gate_scu("mipi0_dsi_tx_esc_clk", "mipi0_dsi_tx_esc_div", SC_R_MIPI_0, SC_PM_CLK_MST_BUS, NULL, 0, 0);
+ clks[IMX8QXP_MIPI0_DSI_RX_ESC_SEL] = imx_clk_mux2_scu("mipi0_dsi_rx_esc_sel", mipi0_sels, ARRAY_SIZE(mipi0_sels), SC_R_MIPI_0, SC_PM_CLK_SLV_BUS);
+ clks[IMX8QXP_MIPI0_DSI_RX_ESC_DIV] = imx_clk_divider2_scu("mipi0_dsi_rx_esc_div", "mipi0_dsi_rx_esc_sel", SC_R_MIPI_0, SC_PM_CLK_SLV_BUS);
+ clks[IMX8QXP_MIPI0_DSI_RX_ESC_CLK] = imx_clk_gate_scu("mipi0_dsi_rx_esc_clk", "mipi0_dsi_rx_esc_div", SC_R_MIPI_0, SC_PM_CLK_SLV_BUS, NULL, 0, 0);
+ clks[IMX8QXP_MIPI0_DSI_PHY_SEL] = imx_clk_mux2_scu("mipi0_dsi_phy_sel", mipi0_sels, ARRAY_SIZE(mipi0_sels), SC_R_MIPI_0, SC_PM_CLK_PHY);
+ clks[IMX8QXP_MIPI0_DSI_PHY_DIV] = imx_clk_divider2_scu("mipi0_dsi_phy_div", "mipi0_dsi_phy_sel", SC_R_MIPI_0, SC_PM_CLK_PHY);
+ clks[IMX8QXP_MIPI0_DSI_PHY_CLK] = imx_clk_gate_scu("mipi0_dsi_phy_clk", "mipi0_dsi_phy_div", SC_R_MIPI_0, SC_PM_CLK_PHY, NULL, 0, 0);
+ clks[IMX8QXP_MIPI0_I2C0_DIV] = imx_clk_divider_scu("mipi0_i2c0_div", SC_R_MIPI_0_I2C_0, SC_PM_CLK_MISC2);
+ clks[IMX8QXP_MIPI0_I2C1_DIV] = imx_clk_divider_scu("mipi0_i2c1_div", SC_R_MIPI_0_I2C_1, SC_PM_CLK_MISC2);
+ clks[IMX8QXP_MIPI0_I2C0_CLK] = imx_clk_gate_scu("mipi0_i2c0_clk", "mipi0_i2c0_div", SC_R_MIPI_0_I2C_0, SC_PM_CLK_MISC2, (void __iomem *)(DI_MIPI0_LPCG + 0x14), 0, 0);
+ clks[IMX8QXP_MIPI0_I2C1_CLK] = imx_clk_gate_scu("mipi0_i2c1_clk", "mipi0_i2c1_div", SC_R_MIPI_0_I2C_1, SC_PM_CLK_MISC2, (void __iomem *)(DI_MIPI0_LPCG + 0x14), 0, 0);
+ clks[IMX8QXP_MIPI0_I2C0_IPG_S_CLK] = imx_clk_gate2_scu("mipi0_i2c0_ipg_s", "ipg_mipi_clk_root", (void __iomem *)(DI_MIPI0_LPCG + 0x10), 0, FUNCTION_NAME(PD_MIPI_0_DSI_I2C0));
+ clks[IMX8QXP_MIPI0_I2C0_IPG_CLK] = imx_clk_gate2_scu("mipi0_i2c0_ipg_clk", "mipi0_i2c0_ipg_s", (void __iomem *)(DI_MIPI0_LPCG), 0, FUNCTION_NAME(PD_MIPI_0_DSI_I2C0));
+ clks[IMX8QXP_MIPI0_I2C1_IPG_S_CLK] = imx_clk_gate2_scu("mipi0_i2c1_ipg_s", "ipg_mipi_clk_root", (void __iomem *)(DI_MIPI0_LPCG + 0x14), 0, FUNCTION_NAME(PD_MIPI_0_DSI_I2C1));
+ clks[IMX8QXP_MIPI0_I2C1_IPG_CLK] = imx_clk_gate2_scu("mipi0_i2c1_ipg_clk", "mipi0_i2c1_ipg_s", (void __iomem *)(DI_MIPI0_LPCG), 0, FUNCTION_NAME(PD_MIPI_0_DSI_I2C1));
+ clks[IMX8QXP_MIPI0_PWM_IPG_S_CLK] = imx_clk_gate2_scu("mipi0_pwm_ipg_s", "ipg_mipi_clk_root", (void __iomem *)(DI_MIPI0_LPCG + 0xC), 16, FUNCTION_NAME(PD_MIPI_0_DSI_PWM0));
+ clks[IMX8QXP_MIPI0_PWM_IPG_CLK] = imx_clk_gate2_scu("mipi0_pwm_ipg_clk", "mipi0_pwm_ipg_s", (void __iomem *)(DI_MIPI0_LPCG + 0xC), 16, FUNCTION_NAME(PD_MIPI_0_DSI_PWM0));
+ clks[IMX8QXP_MIPI0_PWM_32K_CLK] = imx_clk_gate2_scu("mipi0_pwm_32K_clk", "xtal_32KHz", (void __iomem *)(DI_MIPI0_LPCG + 0xC), 0, FUNCTION_NAME(PD_MIPI_0_DSI_PWM0));
+ clks[IMX8QXP_MIPI0_PWM_DIV] = imx_clk_divider_scu("mipi0_pwm_div", SC_R_MIPI_0_PWM_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_MIPI0_PWM_CLK] = imx_clk_gate_scu("mipi0_pwm_clk", "mipi0_pwm_div", SC_R_MIPI_0_PWM_0, SC_PM_CLK_PER, (void __iomem *)(DI_MIPI0_LPCG + 0xC), 0, 0);
+ clks[IMX8QXP_MIPI0_GPIO_IPG_CLK] = imx_clk_gate2_scu("mipi0_gpio_ipg_clk", "ipg_mipi_clk_root", (void __iomem *)(DI_MIPI0_LPCG + 0x8), 0, FUNCTION_NAME(PD_MIPI_0_GPIO_0));
+ clks[IMX8QXP_MIPI0_LIS_IPG_CLK] = imx_clk_gate2_scu("mipi0_lis_ipg_clk", "ipg_mipi_clk_root", (void __iomem *)(DI_MIPI0_LPCG + 0x0), 16, FUNCTION_NAME(PD_MIPI_0_DSI));
+ clks[IMX8QXP_MIPI1_BYPASS_CLK] = imx_clk_divider_scu("mipi1_bypass_clk", SC_R_MIPI_1, SC_PM_CLK_BYPASS);
+ clks[IMX8QXP_MIPI1_PIXEL_DIV] = imx_clk_divider_scu("mipi1_pixel_div", SC_R_MIPI_1, SC_PM_CLK_PER);
+ clks[IMX8QXP_MIPI1_PIXEL_CLK] = imx_clk_gate_scu("mipi1_pixel_clk", "mipi1_pixel_div", SC_R_MIPI_1, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QXP_MIPI1_LVDS_PIXEL_DIV] = imx_clk_divider_scu("mipi1_lvds_pixel_div", SC_R_LVDS_1, SC_PM_CLK_MISC2);
+ clks[IMX8QXP_MIPI1_LVDS_PIXEL_CLK] = imx_clk_gate_scu("mipi1_lvds_pixel_clk", "mipi1_lvds_pixel_div", SC_R_LVDS_1, SC_PM_CLK_MISC2, NULL, 0, 0);
+ clks[IMX8QXP_MIPI1_LVDS_BYPASS_CLK] = imx_clk_divider_scu("mipi1_lvds_bypass_clk", SC_R_LVDS_1, SC_PM_CLK_BYPASS);
+ clks[IMX8QXP_MIPI1_LVDS_PHY_DIV] = imx_clk_divider_scu("mipi1_lvds_phy_div", SC_R_LVDS_1, SC_PM_CLK_MISC3);
+ clks[IMX8QXP_MIPI1_LVDS_PHY_CLK] = imx_clk_gate_scu("mipi1_lvds_phy_clk", "mipi1_lvds_phy_div", SC_R_LVDS_1, SC_PM_CLK_MISC3, NULL, 0, 0);
+ clks[IMX8QXP_MIPI1_DSI_TX_ESC_SEL] = imx_clk_mux2_scu("mipi1_dsi_tx_esc_sel", mipi1_sels, ARRAY_SIZE(mipi1_sels), SC_R_MIPI_1, SC_PM_CLK_MST_BUS);
+ clks[IMX8QXP_MIPI1_DSI_TX_ESC_DIV] = imx_clk_divider2_scu("mipi1_dsi_tx_esc_div", "mipi1_dsi_tx_esc_sel", SC_R_MIPI_1, SC_PM_CLK_MST_BUS);
+ clks[IMX8QXP_MIPI1_DSI_TX_ESC_CLK] = imx_clk_gate_scu("mipi1_dsi_tx_esc_clk", "mipi1_dsi_tx_esc_div", SC_R_MIPI_1, SC_PM_CLK_MST_BUS, NULL, 0, 0);
+ clks[IMX8QXP_MIPI1_DSI_RX_ESC_SEL] = imx_clk_mux2_scu("mipi1_dsi_rx_esc_sel", mipi1_sels, ARRAY_SIZE(mipi1_sels), SC_R_MIPI_1, SC_PM_CLK_SLV_BUS);
+ clks[IMX8QXP_MIPI1_DSI_RX_ESC_DIV] = imx_clk_divider2_scu("mipi1_dsi_rx_esc_div", "mipi1_dsi_rx_esc_sel", SC_R_MIPI_1, SC_PM_CLK_SLV_BUS);
+ clks[IMX8QXP_MIPI1_DSI_RX_ESC_CLK] = imx_clk_gate_scu("mipi1_dsi_rx_esc_clk", "mipi1_dsi_rx_esc_div", SC_R_MIPI_1, SC_PM_CLK_SLV_BUS, NULL, 0, 0);
+
+ clks[IMX8QXP_MIPI1_I2C0_DIV] = imx_clk_divider_scu("mipi1_i2c0_div", SC_R_MIPI_1_I2C_0, SC_PM_CLK_MISC2);
+ clks[IMX8QXP_MIPI1_I2C1_DIV] = imx_clk_divider_scu("mipi1_i2c1_div", SC_R_MIPI_1_I2C_1, SC_PM_CLK_MISC2);
+ clks[IMX8QXP_MIPI1_I2C0_CLK] = imx_clk_gate_scu("mipi1_i2c0_clk", "mipi1_i2c0_div", SC_R_MIPI_1_I2C_0, SC_PM_CLK_MISC2, (void __iomem *)(DI_MIPI1_LPCG + 0x14), 0, 0);
+ clks[IMX8QXP_MIPI1_I2C1_CLK] = imx_clk_gate_scu("mipi1_i2c1_clk", "mipi1_i2c1_div", SC_R_MIPI_1_I2C_1, SC_PM_CLK_MISC2, (void __iomem *)(DI_MIPI1_LPCG + 0x14), 0, 0);
+ clks[IMX8QXP_MIPI1_I2C0_IPG_S_CLK] = imx_clk_gate2_scu("mipi1_i2c0_ipg_s", "ipg_mipi_clk_root", (void __iomem *)(DI_MIPI1_LPCG + 0x10), 0, FUNCTION_NAME(PD_MIPI_1_DSI_I2C0));
+ clks[IMX8QXP_MIPI1_I2C0_IPG_CLK] = imx_clk_gate2_scu("mipi1_i2c0_ipg_clk", "mipi1_i2c0_ipg_s", (void __iomem *)(DI_MIPI1_LPCG), 0, FUNCTION_NAME(PD_MIPI_1_DSI_I2C0));
+ clks[IMX8QXP_MIPI1_I2C1_IPG_S_CLK] = imx_clk_gate2_scu("mipi1_i2c1_ipg_s", "ipg_mipi_clk_root", (void __iomem *)(DI_MIPI1_LPCG + 0x14), 0, FUNCTION_NAME(PD_MIPI_1_DSI_I2C1));
+ clks[IMX8QXP_MIPI1_I2C1_IPG_CLK] = imx_clk_gate2_scu("mipi1_i2c1_ipg_clk", "mipi1_i2c1_ipg_s", (void __iomem *)(DI_MIPI1_LPCG), 0, FUNCTION_NAME(PD_MIPI_1_DSI_I2C1));
+ clks[IMX8QXP_MIPI1_PWM_IPG_S_CLK] = imx_clk_gate2_scu("mipi1_pwm_ipg_s", "ipg_mipi_clk_root", (void __iomem *)(DI_MIPI1_LPCG + 0xC), 16, FUNCTION_NAME(PD_MIPI_1_DSI_PWM0));
+ clks[IMX8QXP_MIPI1_PWM_IPG_CLK] = imx_clk_gate2_scu("mipi1_pwm_ipg_clk", "mipi1_pwm_ipg_s", (void __iomem *)(DI_MIPI1_LPCG + 0xC), 16, FUNCTION_NAME(PD_MIPI_1_DSI_PWM0));
+ clks[IMX8QXP_MIPI1_PWM_32K_CLK] = imx_clk_gate2_scu("mipi1_pwm_32K_clk", "xtal_32KHz", (void __iomem *)(DI_MIPI1_LPCG + 0xC), 0, FUNCTION_NAME(PD_MIPI_1_DSI_PWM0));
+ clks[IMX8QXP_MIPI1_PWM_DIV] = imx_clk_divider_scu("mipi1_pwm_div", SC_R_MIPI_1_PWM_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_MIPI1_PWM_CLK] = imx_clk_gate_scu("mipi1_pwm_clk", "mipi1_pwm_div", SC_R_MIPI_1_PWM_0, SC_PM_CLK_PER, (void __iomem *)(DI_MIPI1_LPCG + 0xC), 0, 0);
+ clks[IMX8QXP_MIPI1_GPIO_IPG_CLK] = imx_clk_gate2_scu("mipi1_gpio_ipg_clk", "ipg_mipi_clk_root", (void __iomem *)(DI_MIPI1_LPCG + 0x8), 0, FUNCTION_NAME(PD_MIPI_1_GPIO_0));
+ clks[IMX8QXP_MIPI1_LIS_IPG_CLK] = imx_clk_gate2_scu("mipi1_lis_ipg_clk", "ipg_mipi_clk_root", (void __iomem *)(DI_MIPI1_LPCG + 0x0), 16, FUNCTION_NAME(PD_MIPI_1_DSI));
+
+ /* Imaging SS */
+ clks[IMX8QXP_IMG_JPEG_ENC_IPG_CLK] = imx_clk_gate2_scu("img_jpeg_enc_ipg_clk", "ipg_img_clk_root", (void __iomem *)(IMG_JPEG_ENC_LPCG), 16, FUNCTION_NAME(PD_IMAGING_JPEG_ENC));
+ clks[IMX8QXP_IMG_JPEG_ENC_CLK] = imx_clk_gate2_scu("img_jpeg_enc_clk", "img_jpeg_enc_ipg_clk", (void __iomem *)(IMG_JPEG_ENC_LPCG), 0, FUNCTION_NAME(PD_IMAGING_JPEG_ENC));
+ clks[IMX8QXP_IMG_JPEG_DEC_IPG_CLK] = imx_clk_gate2_scu("img_jpeg_dec_ipg_clk", "ipg_img_clk_root", (void __iomem *)(IMG_JPEG_DEC_LPCG), 16, FUNCTION_NAME(PD_IMAGING_JPEG_DEC));
+ clks[IMX8QXP_IMG_JPEG_DEC_CLK] = imx_clk_gate2_scu("img_jpeg_dec_clk", "img_jpeg_dec_ipg_clk", (void __iomem *)(IMG_JPEG_DEC_LPCG), 0, FUNCTION_NAME(PD_IMAGING_JPEG_DEC));
+ clks[IMX8QXP_IMG_PXL_LINK_DC0_CLK] = imx_clk_gate2_scu("img_pxl_link_dc0_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PXL_LINK_DC0_LPCG), 0, FUNCTION_NAME(PD_IMAGING));
+ clks[IMX8QXP_IMG_PXL_LINK_DC1_CLK] = imx_clk_gate2_scu("img_pxl_link_dc1_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PXL_LINK_DC1_LPCG), 0, FUNCTION_NAME(PD_IMAGING));
+ clks[IMX8QXP_IMG_PXL_LINK_CSI0_CLK] = imx_clk_gate2_scu("img_pxl_link_csi0_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PXL_LINK_CSI0_LPCG), 0, FUNCTION_NAME(PD_IMAGING));
+ clks[IMX8QXP_IMG_PXL_LINK_CSI1_CLK] = imx_clk_gate2_scu("img_pxl_link_csi1_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PXL_LINK_CSI1_LPCG), 0, FUNCTION_NAME(PD_IMAGING));
+ clks[IMX8QXP_IMG_PXL_LINK_HDMI_IN_CLK] = imx_clk_gate2_scu("img_pxl_link_hdmi_in_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PXL_LINK_HDMI_LPCG), 0, FUNCTION_NAME(PD_IMAGING));
+ clks[IMX8QXP_IMG_PDMA_0_CLK] = imx_clk_gate2_scu("img_pdma0_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_0_LPCG), 0, FUNCTION_NAME(PD_IMAGING_PDMA0));
+ clks[IMX8QXP_IMG_PDMA_1_CLK] = imx_clk_gate2_scu("img_pdma1_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_1_LPCG), 0, FUNCTION_NAME(PD_IMAGING_PDMA1));
+ clks[IMX8QXP_IMG_PDMA_2_CLK] = imx_clk_gate2_scu("img_pdma2_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_2_LPCG), 0, FUNCTION_NAME(PD_IMAGING_PDMA2));
+ clks[IMX8QXP_IMG_PDMA_3_CLK] = imx_clk_gate2_scu("img_pdma3_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_3_LPCG), 0, FUNCTION_NAME(PD_IMAGING_PDMA3));
+ clks[IMX8QXP_IMG_PDMA_4_CLK] = imx_clk_gate2_scu("img_pdma4_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_4_LPCG), 0, FUNCTION_NAME(PD_IMAGING_PDMA4));
+ clks[IMX8QXP_IMG_PDMA_5_CLK] = imx_clk_gate2_scu("img_pdma5_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_5_LPCG), 0, FUNCTION_NAME(PD_IMAGING_PDMA5));
+ clks[IMX8QXP_IMG_PDMA_6_CLK] = imx_clk_gate2_scu("img_pdma6_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_6_LPCG), 0, FUNCTION_NAME(PD_IMAGING_PDMA6));
+ clks[IMX8QXP_IMG_PDMA_7_CLK] = imx_clk_gate2_scu("img_pdma7_clk", "pxl_img_clk_root", (void __iomem *)(IMG_PDMA_7_LPCG), 0, FUNCTION_NAME(PD_IMAGING_PDMA7));
+
+ /* MIPI CSI SS */
+ clks[IMX8QXP_CSI0_I2C0_DIV] = imx_clk_divider_scu("mipi_csi0_i2c0_div", SC_R_CSI_0_I2C_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_CSI0_PWM0_DIV] = imx_clk_divider_scu("mipi_csi0_pwm0_div", SC_R_CSI_0_PWM_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_CSI0_CORE_DIV] = imx_clk_divider_scu("mipi_csi0_core_div", SC_R_CSI_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_CSI0_ESC_DIV] = imx_clk_divider_scu("mipi_csi0_esc_div", SC_R_CSI_0, SC_PM_CLK_MISC);
+ clks[IMX8QXP_CSI0_I2C0_IPG_CLK] = imx_clk_gate2_scu("mipi_csi0_i2c0_ipg_s", "ipg_mipi_csi_clk_root", (void __iomem *)(MIPI_CSI_0_LPCG + 0x14), 16, FUNCTION_NAME(PD_MIPI_CSI0_I2C0));
+ clks[IMX8QXP_CSI0_I2C0_CLK] = imx_clk_gate_scu("mipi_csi0_i2c0_clk", "mipi_csi0_i2c0_div", SC_R_CSI_0_I2C_0, SC_PM_CLK_PER, (void __iomem *)(MIPI_CSI_0_LPCG + 0x14), 0, 0);
+ clks[IMX8QXP_CSI0_PWM0_IPG_CLK] = imx_clk_gate2_scu("mipi_csi0_pwm0_ipg_s", "ipg_mipi_csi_clk_root", (void __iomem *)(MIPI_CSI_0_LPCG + 0x10), 16, FUNCTION_NAME(PD_MIPI_CSI0_PWM));
+ clks[IMX8QXP_CSI0_PWM0_CLK] = imx_clk_gate_scu("mipi_csi0_pwm0_clk", "mipi_csi0_pwm0_div", SC_R_CSI_0_PWM_0, SC_PM_CLK_PER, (void __iomem *)(MIPI_CSI_0_LPCG + 0x10), 0, 0);
+ clks[IMX8QXP_CSI0_CORE_CLK] = imx_clk_gate_scu("mipi_csi0_core_clk", "mipi_csi0_core_div", SC_R_CSI_0, SC_PM_CLK_PER, (void __iomem *)(MIPI_CSI_0_LPCG + 0x18), 16, 0);
+ clks[IMX8QXP_CSI0_ESC_CLK] = imx_clk_gate_scu("mipi_csi0_esc_clk", "mipi_csi0_esc_div", SC_R_CSI_0, SC_PM_CLK_MISC, (void __iomem *)(MIPI_CSI_0_LPCG + 0x1C), 16, 0);
+
+ /* Parallel CSI */
+ clks[IMX8QXP_PARALLEL_CSI_CLK_DPLL] = imx_clk_divider_scu("parallel_pll_clk", SC_R_PI_0_PLL, SC_PM_CLK_PLL);
+ clks[IMX8QXP_PARALLEL_CSI_CLK_SEL] = imx_clk_mux2_scu("pll0_sel", pll0_sels, ARRAY_SIZE(pll0_sels), SC_R_PI_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_PARALLEL_CSI_PER_CLK_DIV] = imx_clk_divider2_scu("parallel_per_clk", "pll0_sel", SC_R_PI_0, SC_PM_CLK_PER);
+ clks[IMX8QXP_PARALLEL_CSI_MCLK_DIV] = imx_clk_divider_scu("parallel_csi_mclk_div", SC_R_PI_0, SC_PM_CLK_MISC0);
+ clks[IMX8QXP_PARALLEL_CSI_PIXEL_CLK] = imx_clk_gate_scu("parallel_pixel_clk", "parallel_per_clk", SC_R_PI_0, SC_PM_CLK_PER, (void __iomem *)(PARALLEL_CSI_LPCG + 0x18), 0, 0);
+ clks[IMX8QXP_PARALLEL_CSI_IPG_CLK] = imx_clk_gate_scu("parallel_ipg_clk", "parallel_per_clk", SC_R_PI_0, SC_PM_CLK_PER, (void __iomem *)(PARALLEL_CSI_LPCG + 0x4), 16, 0);
+ clks[IMX8QXP_PARALLEL_CSI_MISC0_CLK] = imx_clk_gate_scu("parallel_csi_mclk", "parallel_csi_mclk_div", SC_R_PI_0, SC_PM_CLK_MISC0, (void __iomem *)(PARALLEL_CSI_LPCG + 0x1C), 0, 0);
+
+
+ /* HSIO SS */
+ clks[IMX8QXP_HSIO_PCIE_MSTR_AXI_CLK] = imx_clk_gate2_scu("hsio_pcie_mstr_axi_clk", "axi_hsio_clk_root", (void __iomem *)(HSIO_PCIE_X1_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_B));
+ clks[IMX8QXP_HSIO_PCIE_SLV_AXI_CLK] = imx_clk_gate2_scu("hsio_pcie_slv_axi_clk", "axi_hsio_clk_root", (void __iomem *)(HSIO_PCIE_X1_LPCG), 20, FUNCTION_NAME(PD_HSIO_PCIE_B));
+ clks[IMX8QXP_HSIO_PCIE_DBI_AXI_CLK] = imx_clk_gate2_scu("hsio_pcie_dbi_axi_clk", "axi_hsio_clk_root", (void __iomem *)(HSIO_PCIE_X1_LPCG), 24, FUNCTION_NAME(PD_HSIO_PCIE_B));
+ clks[IMX8QXP_HSIO_PCIE_X1_PER_CLK] = imx_clk_gate2_scu("hsio_pcie_x1_per_clk", "per_hsio_clk_root", (void __iomem *)(HSIO_PCIE_X1_CRR3_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_B));
+ clks[IMX8QXP_HSIO_PHY_X1_PER_CLK] = imx_clk_gate2_scu("hsio_phy_x1_per_clk", "per_hsio_clk_root", (void __iomem *)(HSIO_PHY_X1_CRR1_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_B));
+ clks[IMX8QXP_HSIO_MISC_PER_CLK] = imx_clk_gate2_scu("hsio_misc_per_clk", "per_hsio_clk_root", (void __iomem *)(HSIO_MISC_LPCG), 16, FUNCTION_NAME(PD_HSIO));
+ clks[IMX8QXP_HSIO_PHY_X1_APB_CLK] = imx_clk_gate2_scu("hsio_phy_x1_apb_clk", "per_hsio_clk_root", (void __iomem *)(HSIO_PHY_X1_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_B));
+ clks[IMX8QXP_HSIO_GPIO_CLK] = imx_clk_gate2_scu("hsio_gpio_clk", "per_hsio_clk_root", (void __iomem *)(HSIO_GPIO_LPCG), 16, FUNCTION_NAME(PD_HSIO_PCIE_B));
+ clks[IMX8QXP_HSIO_PHY_X1_PCLK] = imx_clk_gate2_scu("hsio_phy_x1_pclk", "dummy", (void __iomem *)(HSIO_PHY_X1_LPCG), 0, FUNCTION_NAME(PD_HSIO_PCIE_B));
+
+ /* CM40 */
+ clks[IMX8QXP_CM40_I2C_DIV] = imx_clk_divider_scu("cm40_i2c_div", SC_R_M4_0_I2C, SC_PM_CLK_PER);
+ clks[IMX8QXP_CM40_I2C_CLK] = imx_clk_gate_scu("cm40_i2c_clk", "cm40_i2c_div", SC_R_M4_0_I2C, SC_PM_CLK_PER, (void __iomem *)(CM40_I2C_LPCG), 0, 0);
+ clks[IMX8QXP_CM40_I2C_IPG_CLK] = imx_clk_gate2_scu("cm40_i2c_ipg_clk", "ipg_cm40_clk_root", (void __iomem *)(CM40_I2C_LPCG), 16, FUNCTION_NAME(PD_CM40_I2C));
+
+ /* Audio */
+ clks[IMX8QXP_AUD_ACM_AUD_PLL_CLK0_DIV] = imx_clk_divider2_scu("aud_acm_aud_pll_clk0_div", "audio_pll0_clk", SC_R_AUDIO_PLL_0, SC_PM_CLK_MISC0);
+ clks[IMX8QXP_AUD_ACM_AUD_PLL_CLK1_DIV] = imx_clk_divider2_scu("aud_acm_aud_pll_clk1_div", "audio_pll1_clk", SC_R_AUDIO_PLL_1, SC_PM_CLK_MISC0);
+ clks[IMX8QXP_AUD_ACM_AUD_REC_CLK0_DIV] = imx_clk_divider2_scu("aud_acm_aud_rec_clk0_div", "audio_pll0_clk", SC_R_AUDIO_PLL_0, SC_PM_CLK_MISC1);
+ clks[IMX8QXP_AUD_ACM_AUD_REC_CLK1_DIV] = imx_clk_divider2_scu("aud_acm_aud_rec_clk1_div", "audio_pll1_clk", SC_R_AUDIO_PLL_1, SC_PM_CLK_MISC1);
+ clks[IMX8QXP_AUD_ACM_AUD_PLL_CLK0_CLK] = imx_clk_gate_scu("aud_acm_aud_pll_clk0_clk", "aud_acm_aud_pll_clk0_div", SC_R_AUDIO_PLL_0, SC_PM_CLK_MISC0, (void __iomem *)(AUD_PLL_CLK0_LPCG), 0, 0);
+ clks[IMX8QXP_AUD_ACM_AUD_PLL_CLK1_CLK] = imx_clk_gate_scu("aud_acm_aud_pll_clk1_clk", "aud_acm_aud_pll_clk1_div", SC_R_AUDIO_PLL_1, SC_PM_CLK_MISC0, (void __iomem *)(AUD_PLL_CLK1_LPCG), 0, 0);
+ clks[IMX8QXP_AUD_ACM_AUD_REC_CLK0_CLK] = imx_clk_gate_scu("aud_acm_aud_rec_clk0_clk", "aud_acm_aud_rec_clk0_div", SC_R_AUDIO_PLL_0, SC_PM_CLK_MISC1, (void __iomem *)(AUD_REC_CLK0_LPCG), 0, 0);
+ clks[IMX8QXP_AUD_ACM_AUD_REC_CLK1_CLK] = imx_clk_gate_scu("aud_acm_aud_rec_clk1_clk", "aud_acm_aud_rec_clk1_div", SC_R_AUDIO_PLL_1, SC_PM_CLK_MISC1, (void __iomem *)(AUD_REC_CLK1_LPCG), 0, 0);
+
+ /* VPU */
+ clks[IMX8QXP_VPU_ENC_CLK] = imx_clk_gate_scu("vpu_enc_clk", "dummy", SC_R_VPU_ENC_0, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QXP_VPU_DEC_CLK] = imx_clk_gate_scu("vpu_dec_clk", "dummy", SC_R_VPU_DEC_0, SC_PM_CLK_PER, NULL, 0, 0);
+
+ np_acm = of_find_compatible_node(NULL, NULL, "nxp,imx8qm-acm");
+ if (np_acm) {
+ base_acm = of_iomap(np_acm, 0);
+ WARN_ON(!base_acm);
+
+ clks[IMX8QXP_EXT_AUD_MCLK0] = imx_clk_fixed("ext_aud_mclk0", 0);
+ clks[IMX8QXP_EXT_AUD_MCLK1] = imx_clk_fixed("ext_aud_mclk1", 0);
+ clks[IMX8QXP_ESAI0_RX_CLK] = imx_clk_fixed("esai0_rx_clk", 0);
+ clks[IMX8QXP_ESAI0_RX_HF_CLK] = imx_clk_fixed("esai0_rx_hf_clk", 0);
+ clks[IMX8QXP_ESAI0_TX_CLK] = imx_clk_fixed("esai0_tx_clk", 0);
+ clks[IMX8QXP_ESAI0_TX_HF_CLK] = imx_clk_fixed("esai0_tx_hf_clk", 0);
+ clks[IMX8QXP_SPDIF0_RX] = imx_clk_fixed("spdif0_rx", 0);
+ clks[IMX8QXP_SAI0_RX_BCLK] = imx_clk_fixed("sai0_rx_bclk", 0);
+ clks[IMX8QXP_SAI0_TX_BCLK] = imx_clk_fixed("sai0_tx_bclk", 0);
+ clks[IMX8QXP_SAI1_RX_BCLK] = imx_clk_fixed("sai1_rx_bclk", 0);
+ clks[IMX8QXP_SAI1_TX_BCLK] = imx_clk_fixed("sai1_tx_bclk", 0);
+ clks[IMX8QXP_SAI2_RX_BCLK] = imx_clk_fixed("sai2_rx_bclk", 0);
+ clks[IMX8QXP_SAI3_RX_BCLK] = imx_clk_fixed("sai3_rx_bclk", 0);
+ clks[IMX8QXP_SAI4_RX_BCLK] = imx_clk_fixed("sai4_rx_bclk", 0);
+
+ clks[IMX8QXP_ACM_AUD_CLK0_SEL] = imx_clk_mux_scu("acm_aud_clk0_sel", base_acm+0x000000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels), FUNCTION_NAME(PD_AUD_AUDIO_CLK_0));
+ clks[IMX8QXP_ACM_AUD_CLK0_CLK] = imx_clk_gate_scu("acm_aud_clk0_clk", "acm_aud_clk0_sel", SC_R_AUDIO_CLK_0, SC_PM_CLK_SLV_BUS, NULL, 0, 0);
+ clks[IMX8QXP_ACM_AUD_CLK1_SEL] = imx_clk_mux_scu("acm_aud_clk1_sel", base_acm+0x010000, 0, 5, aud_clk_sels, ARRAY_SIZE(aud_clk_sels), FUNCTION_NAME(PD_AUD_AUDIO_CLK_1));
+ clks[IMX8QXP_ACM_AUD_CLK1_CLK] = imx_clk_gate_scu("acm_aud_clk1_clk", "acm_aud_clk1_sel", SC_R_AUDIO_CLK_1, SC_PM_CLK_SLV_BUS, NULL, 0, 0);
+ clks[IMX8QXP_ACM_MCLKOUT0_SEL] = imx_clk_mux_scu("acm_mclkout0_sel", base_acm+0x020000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels), FUNCTION_NAME(PD_AUD_MCLK_OUT_0));
+ clks[IMX8QXP_ACM_MCLKOUT1_SEL] = imx_clk_mux_scu("acm_mclkout1_sel", base_acm+0x030000, 0, 3, mclk_out_sels, ARRAY_SIZE(mclk_out_sels), FUNCTION_NAME(PD_AUD_MCLK_OUT_1));
+ clks[IMX8QXP_ACM_ASRC0_MUX_CLK_SEL] = imx_clk_mux_scu("acm_asrc0_mclk_sel", base_acm+0x040000, 0, 2, NULL, 0, FUNCTION_NAME(PD_AUD_ASRC_0));
+ clks[IMX8QXP_ACM_ASRC0_MUX_CLK_CLK] = imx_clk_gate_scu("aud_asrc0_mux_clk", "acm_asrc0_mclk_sel", SC_R_ASRC_0, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QXP_ACM_ASRC1_MUX_CLK_SEL] = imx_clk_mux_scu("acm_asrc1_mclk_sel", base_acm+0x050000, 0, 2, NULL, 0, FUNCTION_NAME(PD_AUD_ASRC_1));
+ clks[IMX8QXP_ACM_ASRC1_MUX_CLK_CLK] = imx_clk_gate_scu("aud_asrc1_mux_clk", "acm_asrc1_mclk_sel", SC_R_ASRC_1, SC_PM_CLK_PER, NULL, 0, 0);
+ clks[IMX8QXP_ACM_ESAI0_MCLK_SEL] = imx_clk_mux_scu("acm_esai0_mclk_sel", base_acm+0x060000, 0, 2, esai_mclk_sels, ARRAY_SIZE(esai_mclk_sels), FUNCTION_NAME(PD_AUD_ESAI_0));
+ clks[IMX8QXP_ACM_SAI0_MCLK_SEL] = imx_clk_mux_scu("acm_sai0_mclk_sel", base_acm+0x0E0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels), FUNCTION_NAME(PD_AUD_SAI_0));
+ clks[IMX8QXP_ACM_SAI1_MCLK_SEL] = imx_clk_mux_scu("acm_sai1_mclk_sel", base_acm+0x0F0000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels), FUNCTION_NAME(PD_AUD_SAI_1));
+ clks[IMX8QXP_ACM_SAI2_MCLK_SEL] = imx_clk_mux_scu("acm_sai2_mclk_sel", base_acm+0x100000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels), FUNCTION_NAME(PD_AUD_SAI_2));
+ clks[IMX8QXP_ACM_SAI3_MCLK_SEL] = imx_clk_mux_scu("acm_sai3_mclk_sel", base_acm+0x110000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels), FUNCTION_NAME(PD_AUD_SAI_3));
+ clks[IMX8QXP_ACM_SAI4_MCLK_SEL] = imx_clk_mux_scu("acm_sai4_mclk_sel", base_acm+0x140000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels), FUNCTION_NAME(PD_AUD_SAI_4));
+ clks[IMX8QXP_ACM_SAI5_MCLK_SEL] = imx_clk_mux_scu("acm_sai5_mclk_sel", base_acm+0x150000, 0, 2, sai_mclk_sels, ARRAY_SIZE(sai_mclk_sels), FUNCTION_NAME(PD_AUD_SAI_5));
+ clks[IMX8QXP_ACM_SPDIF0_TX_CLK_SEL] = imx_clk_mux_scu("acm_spdif0_mclk_sel", base_acm+0x1A0000, 0, 2, spdif_mclk_sels, ARRAY_SIZE(spdif_mclk_sels), FUNCTION_NAME(PD_AUD_SPDIF_0));
+ clks[IMX8QXP_ACM_MQS_TX_CLK_SEL] = imx_clk_mux_scu("acm_mqs_mclk_sel", base_acm+0x1C0000, 0, 2, mqs_mclk_sels, ARRAY_SIZE(mqs_mclk_sels), FUNCTION_NAME(PD_AUD_MQS_0));
+
+ clks[IMX8QXP_AUD_AMIX_IPG] = imx_clk_gate2_scu("aud_amix_ipg_clk", "ipg_aud_clk_root", (void __iomem *)(AUD_AMIX_LPCG), 0, FUNCTION_NAME(PD_AUD_AMIX));
+ clks[IMX8QXP_AUD_ESAI_0_IPG] = imx_clk_gate2_scu("aud_esai0_ipg_clk", "ipg_aud_clk_root", (void __iomem *)(AUD_ESAI_0_LPCG), 16, FUNCTION_NAME(PD_AUD_ESAI_0));
+ clks[IMX8QXP_AUD_ESAI_0_EXTAL_IPG] = imx_clk_gate2_scu("aud_esai0_extal_clk", "acm_esai0_mclk_sel", (void __iomem *)(AUD_ESAI_0_LPCG), 0, FUNCTION_NAME(PD_AUD_ESAI_0));
+ clks[IMX8QXP_AUD_SAI_0_IPG] = imx_clk_gate2_scu("aud_sai0_ipg_clk", "ipg_aud_clk_root", (void __iomem *)(AUD_SAI_0_LPCG), 16, FUNCTION_NAME(PD_AUD_SAI_0));
+ clks[IMX8QXP_AUD_SAI_0_MCLK] = imx_clk_gate2_scu("aud_sai0_mclk_clk", "acm_sai0_mclk_sel", (void __iomem *)(AUD_SAI_0_LPCG), 0, FUNCTION_NAME(PD_AUD_SAI_0));
+ clks[IMX8QXP_AUD_SAI_1_IPG] = imx_clk_gate2_scu("aud_sai1_ipg_clk", "ipg_aud_clk_root", (void __iomem *)(AUD_SAI_1_LPCG), 16, FUNCTION_NAME(PD_AUD_SAI_1));
+ clks[IMX8QXP_AUD_SAI_1_MCLK] = imx_clk_gate2_scu("aud_sai1_mclk_clk", "acm_sai1_mclk_sel", (void __iomem *)(AUD_SAI_1_LPCG), 0, FUNCTION_NAME(PD_AUD_SAI_1));
+ clks[IMX8QXP_AUD_SAI_2_IPG] = imx_clk_gate2_scu("aud_sai2_ipg_clk", "ipg_aud_clk_root", (void __iomem *)(AUD_SAI_2_LPCG), 16, FUNCTION_NAME(PD_AUD_SAI_2));
+ clks[IMX8QXP_AUD_SAI_2_MCLK] = imx_clk_gate2_scu("aud_sai2_mclk_clk", "acm_sai2_mclk_sel", (void __iomem *)(AUD_SAI_2_LPCG), 0, FUNCTION_NAME(PD_AUD_SAI_2));
+ clks[IMX8QXP_AUD_SAI_3_IPG] = imx_clk_gate2_scu("aud_sai3_ipg_clk", "ipg_aud_clk_root", (void __iomem *)(AUD_SAI_3_LPCG), 16, FUNCTION_NAME(PD_AUD_SAI_3));
+ clks[IMX8QXP_AUD_SAI_3_MCLK] = imx_clk_gate2_scu("aud_sai3_mclk_clk", "acm_sai3_mclk_sel", (void __iomem *)(AUD_SAI_3_LPCG), 0, FUNCTION_NAME(PD_AUD_SAI_3));
+ clks[IMX8QXP_AUD_SAI_4_IPG] = imx_clk_gate2_scu("aud_sai4_ipg_clk", "ipg_aud_clk_root", (void __iomem *)(AUD_SAI_4_LPCG), 16, FUNCTION_NAME(PD_AUD_SAI_4));
+ clks[IMX8QXP_AUD_SAI_4_MCLK] = imx_clk_gate2_scu("aud_sai4_mclk_clk", "acm_sai4_mclk_sel", (void __iomem *)(AUD_SAI_4_LPCG), 0, FUNCTION_NAME(PD_AUD_SAI_4));
+ clks[IMX8QXP_AUD_SAI_5_IPG] = imx_clk_gate2_scu("aud_sai5_ipg_clk", "ipg_aud_clk_root", (void __iomem *)(AUD_SAI_5_LPCG), 16, FUNCTION_NAME(PD_AUD_SAI_5));
+ clks[IMX8QXP_AUD_SAI_5_MCLK] = imx_clk_gate2_scu("aud_sai5_mclk_clk", "acm_sai5_mclk_sel", (void __iomem *)(AUD_SAI_5_LPCG), 0, FUNCTION_NAME(PD_AUD_SAI_5));
+ clks[IMX8QXP_AUD_MQS_IPG] = imx_clk_gate2_scu("aud_mqs_ipg", "ipg_aud_clk_root", (void __iomem *)(AUD_MQS_LPCG), 16, FUNCTION_NAME(PD_AUD_MQS_0));
+ clks[IMX8QXP_AUD_MQS_HMCLK] = imx_clk_gate2_scu("aud_mqs_hm_clk", "acm_mqs_mclk_sel", (void __iomem *)(AUD_MQS_LPCG), 0, FUNCTION_NAME(PD_AUD_MQS_0));
+ clks[IMX8QXP_AUD_GPT5_IPG] = imx_clk_gate2_scu("aud_gpt5_ipg", "ipg_aud_clk_root", (void __iomem *)(AUD_GPT_5_LPCG), 16, FUNCTION_NAME(PD_AUD_GPT_5));
+ clks[IMX8QXP_AUD_GPT5_CLKIN] = imx_clk_gate2_scu("aud_gpt5_clkin", "ipg_aud_clk_root", (void __iomem *)(AUD_GPT_5_LPCG), 0, FUNCTION_NAME(PD_AUD_GPT_5));
+ clks[IMX8QXP_AUD_GPT6_IPG] = imx_clk_gate2_scu("aud_gpt6_ipg", "ipg_aud_clk_root", (void __iomem *)(AUD_GPT_6_LPCG), 16, FUNCTION_NAME(PD_AUD_GPT_6));
+ clks[IMX8QXP_AUD_GPT6_CLKIN] = imx_clk_gate2_scu("aud_gpt6_clkin", "ipg_aud_clk_root", (void __iomem *)(AUD_GPT_6_LPCG), 0, FUNCTION_NAME(PD_AUD_GPT_6));
+ clks[IMX8QXP_AUD_GPT7_IPG] = imx_clk_gate2_scu("aud_gpt7_ipg", "ipg_aud_clk_root", (void __iomem *)(AUD_GPT_7_LPCG), 16, FUNCTION_NAME(PD_AUD_GPT_7));
+ clks[IMX8QXP_AUD_GPT7_CLKIN] = imx_clk_gate2_scu("aud_gpt7_clkin", "ipg_aud_clk_root", (void __iomem *)(AUD_GPT_7_LPCG), 0, FUNCTION_NAME(PD_AUD_GPT_7));
+ clks[IMX8QXP_AUD_GPT8_IPG] = imx_clk_gate2_scu("aud_gpt8_ipg", "ipg_aud_clk_root", (void __iomem *)(AUD_GPT_8_LPCG), 16, FUNCTION_NAME(PD_AUD_GPT_8));
+ clks[IMX8QXP_AUD_GPT8_CLKIN] = imx_clk_gate2_scu("aud_gpt8_clkin", "ipg_aud_clk_root", (void __iomem *)(AUD_GPT_8_LPCG), 0, FUNCTION_NAME(PD_AUD_GPT_8));
+ clks[IMX8QXP_AUD_GPT9_IPG] = imx_clk_gate2_scu("aud_gpt9_ipg", "ipg_aud_clk_root", (void __iomem *)(AUD_GPT_9_LPCG), 16, FUNCTION_NAME(PD_AUD_GPT_9));
+ clks[IMX8QXP_AUD_GPT9_CLKIN] = imx_clk_gate2_scu("aud_gpt9_clkin", "ipg_aud_clk_root", (void __iomem *)(AUD_GPT_9_LPCG), 0, FUNCTION_NAME(PD_AUD_GPT_9));
+ clks[IMX8QXP_AUD_GPT10_IPG] = imx_clk_gate2_scu("aud_gpt10_ipg", "ipg_aud_clk_root", (void __iomem *)(AUD_GPT_10_LPCG), 16, FUNCTION_NAME(PD_AUD_GPT_10));
+ clks[IMX8QXP_AUD_GPT10_CLKIN] = imx_clk_gate2_scu("aud_gpt10_clkin", "ipg_aud_clk_root", (void __iomem *)(AUD_GPT_10_LPCG), 0, FUNCTION_NAME(PD_AUD_GPT_10));
+ clks[IMX8QXP_AUD_MCLKOUT0] = imx_clk_gate2_scu("aud_mclkout0", "acm_mclkout0_sel", (void __iomem *)(AUD_MCLKOUT0_LPCG), 0, FUNCTION_NAME(PD_AUD_MCLK_OUT_0));
+ clks[IMX8QXP_AUD_MCLKOUT1] = imx_clk_gate2_scu("aud_mclkout1", "acm_mclkout1_sel", (void __iomem *)(AUD_MCLKOUT1_LPCG), 0, FUNCTION_NAME(PD_AUD_MCLK_OUT_1));
+ clks[IMX8QXP_AUD_SPDIF_0_GCLKW] = imx_clk_gate2_scu("spdif0_gclkw", "ipg_aud_clk_root", (void __iomem *)(AUD_SPDIF_0_LPCG), 16, FUNCTION_NAME(PD_AUD_SPDIF_0));
+ clks[IMX8QXP_AUD_SPDIF_0_TX_CLK] = imx_clk_gate2_scu("spdif0_tx_clk", "acm_spdif0_mclk_sel", (void __iomem *)(AUD_SPDIF_0_LPCG), 0, FUNCTION_NAME(PD_AUD_SPDIF_0));
+ clks[IMX8QXP_AUD_ASRC_0_IPG] = imx_clk_gate2_scu("aud_asrc0_ipg", "ipg_aud_clk_root", (void __iomem *)(AUD_ASRC_0_LPCG), 16, FUNCTION_NAME(PD_AUD_ASRC_0));
+ clks[IMX8QXP_AUD_ASRC_1_IPG] = imx_clk_gate2_scu("aud_asrc1_ipg", "ipg_aud_clk_root", (void __iomem *)(AUD_ASRC_1_LPCG), 16, FUNCTION_NAME(PD_AUD_ASRC_1));
+ clks[IMX8QXP_AUD_DSP_ADB_ACLK] = imx_clk_gate2_scu("aud_dsp_adb_aclk", "ipg_aud_clk_root", (void __iomem *)(AUD_DSP_LPCG), 16, FUNCTION_NAME(PD_AUD_DSP));
+ clks[IMX8QXP_AUD_DSP_IPG] = imx_clk_gate2_scu("aud_dsp_ipg", "ipg_aud_clk_root", (void __iomem *)(AUD_DSP_LPCG), 20, FUNCTION_NAME(PD_AUD_DSP));
+ clks[IMX8QXP_AUD_DSP_CORE_CLK] = imx_clk_gate2_scu("aud_dsp_core_clk", "ipg_aud_clk_root", (void __iomem *)(AUD_DSP_LPCG), 28, FUNCTION_NAME(PD_AUD_DSP));
+ clks[IMX8QXP_AUD_OCRAM_IPG] = imx_clk_gate2_scu("aud_ocram_ipg", "ipg_aud_clk_root", (void __iomem *)(AUD_OCRAM_LPCG), 16, FUNCTION_NAME(PD_AUD_OCRAM));
+ };
+
+ for (i = 0; i < ARRAY_SIZE(clks); i++)
+ if (IS_ERR(clks[i]) && PTR_ERR(clks[i]) != -ENODEV)
+ pr_err("i.MX8QXP clk %d: register failed with %ld\n",
+ i, PTR_ERR(clks[i]));
+
+ clk_data.clks = clks;
+ clk_data.clk_num = ARRAY_SIZE(clks);
+ of_clk_add_provider(ccm_node, of_clk_src_onecell_get, &clk_data);
+
+ return 0;
+}
+
+static const struct of_device_id imx8qxp_match[] = {
+ { .compatible = "fsl,imx8qxp-clk", },
+ { /* sentinel value */ }
+};
+
+static struct platform_driver imx8qxp_clk_driver = {
+ .driver = {
+ .name = "imx8qxp-clk",
+ .of_match_table = imx8qxp_match,
+ },
+ .probe = imx8qxp_clk_probe,
+};
+
+static int __init imx8qxp_clk_init(void)
+{
+ return platform_driver_register(&imx8qxp_clk_driver);
+}
+core_initcall(imx8qxp_clk_init);
diff --git a/drivers/clk/imx/clk-intpll.c b/drivers/clk/imx/clk-intpll.c
new file mode 100644
index 000000000000..a783a8a67eec
--- /dev/null
+++ b/drivers/clk/imx/clk-intpll.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright 2017-2018 NXP.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+
+#include "clk.h"
+
+#define GNRL_CTL 0x0
+#define DIV_CTL 0x4
+#define LOCK_STATUS BIT(31)
+#define LOCK_SEL_MASK BIT(29)
+#define CLKE_MASK BIT(11)
+#define RST_MASK BIT(9)
+#define BYPASS_MASK BIT(4)
+#define MDIV_SHIFT 12
+#define MDIV_MASK GENMASK(21, 12)
+#define PDIV_SHIFT 4
+#define PDIV_MASK GENMASK(9, 4)
+#define SDIV_SHIFT 0
+#define SDIV_MASK GENMASK(2, 0)
+#define KDIV_SHIFT 0
+#define KDIV_MASK GENMASK(15, 0)
+
+struct clk_int_pll {
+ struct clk_hw hw;
+ void __iomem *base;
+ enum imx_int_pll_type type;
+ struct imx_int_pll_rate_table *rate_table;
+ int rate_count;
+};
+
+#define to_clk_int_pll(_hw) container_of(_hw, struct clk_int_pll, hw)
+
+static const struct imx_int_pll_rate_table *imx_get_pll_settings(
+ struct clk_int_pll *pll, unsigned long rate)
+{
+ const struct imx_int_pll_rate_table *rate_table = pll->rate_table;
+ int i;
+
+ for (i = 0; i < pll->rate_count; i++) {
+ if (rate == rate_table[i].rate)
+ return &rate_table[i];
+ }
+
+ return NULL;
+}
+
+static long clk_int_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_int_pll *pll = to_clk_int_pll(hw);
+ const struct imx_int_pll_rate_table *rate_table = pll->rate_table;
+ int i;
+
+ /* Assumming rate_table is in descending order */
+ for (i = 0; i < pll->rate_count; i++) {
+ if (rate >= rate_table[i].rate)
+ return rate_table[i].rate;
+ }
+ /* return minimum supported value */
+ return rate_table[i - 1].rate;
+}
+
+static unsigned long clk_int_pll1416x_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_int_pll *pll = to_clk_int_pll(hw);
+ u32 mdiv, pdiv, sdiv, pll_gnrl, pll_div;
+ u64 fvco = parent_rate;
+
+ pll_gnrl = readl_relaxed(pll->base);
+ pll_div = readl_relaxed(pll->base + 4);
+ mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT;
+ pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT;
+ sdiv = (pll_div & SDIV_MASK) >> SDIV_SHIFT;
+
+ fvco *= mdiv;
+ do_div(fvco, pdiv << sdiv);
+
+ return (unsigned long)fvco;
+}
+
+static unsigned long clk_int_pll1443x_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_int_pll *pll = to_clk_int_pll(hw);
+ u32 mdiv, pdiv, sdiv, pll_gnrl, pll_div_ctl0, pll_div_ctl1;
+ short int kdiv;
+ u64 fvco = parent_rate;
+
+ pll_gnrl = readl_relaxed(pll->base);
+ pll_div_ctl0 = readl_relaxed(pll->base + 4);
+ pll_div_ctl1 = readl_relaxed(pll->base + 8);
+ mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT;
+ pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT;
+ sdiv = (pll_div_ctl0 & SDIV_MASK) >> SDIV_SHIFT;
+ kdiv = pll_div_ctl1 & KDIV_MASK;
+
+ /* fvco = (m * 65536 + k) * Fin / (p * 65536) */
+ fvco *= (mdiv * 65536 + kdiv);
+ pdiv *= 65536;
+
+ do_div(fvco, pdiv << sdiv);
+
+ return (unsigned long)fvco;
+}
+
+static inline bool clk_int_pll1416x_mp_change(const struct imx_int_pll_rate_table *rate,
+ u32 pll_div)
+{
+ u32 old_mdiv, old_pdiv;
+
+ old_mdiv = (pll_div >> MDIV_SHIFT) & MDIV_MASK;
+ old_pdiv = (pll_div >> PDIV_SHIFT) & PDIV_MASK;
+
+ return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv);
+}
+
+static inline bool clk_int_pll1443x_mpk_change(const struct imx_int_pll_rate_table *rate,
+ u32 pll_div_ctl0, u32 pll_div_ctl1)
+{
+ u32 old_mdiv, old_pdiv, old_kdiv;
+
+ old_mdiv = (pll_div_ctl0 >> MDIV_SHIFT) & MDIV_MASK;
+ old_pdiv = (pll_div_ctl0 >> PDIV_SHIFT) & PDIV_MASK;
+ old_kdiv = (pll_div_ctl1 >> KDIV_SHIFT) & KDIV_MASK;
+
+ return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
+ rate->kdiv != old_kdiv);
+}
+
+static inline bool clk_int_pll1443x_mp_change(const struct imx_int_pll_rate_table *rate,
+ u32 pll_div_ctl0, u32 pll_div_ctl1)
+{
+ u32 old_mdiv, old_pdiv, old_kdiv;
+
+ old_mdiv = (pll_div_ctl0 >> MDIV_SHIFT) & MDIV_MASK;
+ old_pdiv = (pll_div_ctl0 >> PDIV_SHIFT) & PDIV_MASK;
+ old_kdiv = (pll_div_ctl1 >> KDIV_SHIFT) & KDIV_MASK;
+
+ return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
+ rate->kdiv != old_kdiv);
+}
+
+static int clk_int_pll_wait_lock(struct clk_int_pll *pll)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(10);
+
+ /* Wait for PLL to lock */
+ do {
+ if (readl_relaxed(pll->base) & LOCK_STATUS)
+ break;
+ if (time_after(jiffies, timeout))
+ break;
+ } while (1);
+
+ return readl_relaxed(pll->base) & LOCK_STATUS ? 0 : -ETIMEDOUT;
+}
+
+static int clk_int_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
+ unsigned long prate)
+{
+ struct clk_int_pll *pll = to_clk_int_pll(hw);
+ const struct imx_int_pll_rate_table *rate;
+ u32 tmp, div_val;
+ int ret;
+
+ rate = imx_get_pll_settings(pll, drate);
+ if (!rate) {
+ pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+ drate, clk_hw_get_name(hw));
+ return -EINVAL;
+ }
+
+ tmp = readl_relaxed(pll->base + 4);
+
+ if (!clk_int_pll1416x_mp_change(rate, tmp)) {
+ tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
+ tmp |= rate->sdiv << SDIV_SHIFT;
+ writel_relaxed(tmp, pll->base + 4);
+
+ return 0;
+ }
+
+ /* Bypass clock and set lock to pll output lock */
+ tmp = readl_relaxed(pll->base);
+ tmp |= LOCK_SEL_MASK;
+ writel_relaxed(tmp, pll->base);
+
+ /* Enable RST */
+ tmp &= ~RST_MASK;
+ writel_relaxed(tmp, pll->base);
+
+ div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
+ (rate->sdiv << SDIV_SHIFT);
+ writel_relaxed(div_val, pll->base + 0x4);
+
+ /*
+ * According to SPEC, t3 - t2 need to be greater than
+ * 1us and 1/FREF, respectively.
+ * FREF is FIN / Prediv, the prediv is [1, 63], so choose
+ * 3us.
+ */
+ udelay(3);
+
+ /* Disable RST */
+ tmp |= RST_MASK;
+ writel_relaxed(tmp, pll->base);
+
+ /* Wait Lock */
+ ret = clk_int_pll_wait_lock(pll);
+ if (ret)
+ return ret;
+
+ /* Bypass */
+ tmp &= ~BYPASS_MASK;
+ writel_relaxed(tmp, pll->base);
+
+ return 0;
+}
+
+static int clk_int_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
+ unsigned long prate)
+{
+ struct clk_int_pll *pll = to_clk_int_pll(hw);
+ const struct imx_int_pll_rate_table *rate;
+ u32 tmp, div_val;
+ int ret;
+
+ rate = imx_get_pll_settings(pll, drate);
+ if (!rate) {
+ pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+ drate, clk_hw_get_name(hw));
+ return -EINVAL;
+ }
+
+ tmp = readl_relaxed(pll->base + 4);
+ div_val = readl_relaxed(pll->base + 8);
+
+ if (!clk_int_pll1443x_mpk_change(rate, tmp, div_val)) {
+ tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
+ tmp |= rate->sdiv << SDIV_SHIFT;
+ writel_relaxed(tmp, pll->base + 4);
+
+ return 0;
+ }
+
+ /* Enable RST */
+ tmp = readl_relaxed(pll->base);
+ tmp &= ~RST_MASK;
+ writel_relaxed(tmp, pll->base);
+
+ div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
+ (rate->sdiv << SDIV_SHIFT);
+ writel_relaxed(div_val, pll->base + 0x4);
+ writel_relaxed(rate->kdiv << KDIV_SHIFT, pll->base + 0x8);
+
+ /*
+ * According to SPEC, t3 - t2 need to be greater than
+ * 1us and 1/FREF, respectively.
+ * FREF is FIN / Prediv, the prediv is [1, 63], so choose
+ * 3us.
+ */
+ udelay(3);
+
+ /* Disable RST */
+ tmp |= RST_MASK;
+ writel_relaxed(tmp, pll->base);
+
+ /* Wait Lock*/
+ ret = clk_int_pll_wait_lock(pll);
+ if (ret)
+ return ret;
+
+ /* Bypass */
+ tmp &= ~BYPASS_MASK;
+ writel_relaxed(tmp, pll->base);
+
+ return 0;
+}
+
+static int clk_int_pll_prepare(struct clk_hw *hw)
+{
+ struct clk_int_pll *pll = to_clk_int_pll(hw);
+ u32 val;
+
+ /*
+ * RESETB = 1 from 0, PLL starts its normal
+ * operation after lock time
+ */
+ val = readl_relaxed(pll->base + GNRL_CTL);
+ val |= RST_MASK;
+ writel_relaxed(val, pll->base + GNRL_CTL);
+
+ return clk_int_pll_wait_lock(pll);
+}
+
+static int clk_int_pll_is_prepared(struct clk_hw *hw)
+{
+ struct clk_int_pll *pll = to_clk_int_pll(hw);
+ u32 val;
+
+ val = readl_relaxed(pll->base + GNRL_CTL);
+
+ return (val & RST_MASK) ? 1 : 0;
+}
+
+static void clk_int_pll_unprepare(struct clk_hw *hw)
+{
+ struct clk_int_pll *pll = to_clk_int_pll(hw);
+ u32 val;
+
+ /*
+ * Set RST to 0, power down mode is enabled and
+ * every digital block is reset
+ */
+ val = readl_relaxed(pll->base + GNRL_CTL);
+ val &= ~RST_MASK;
+ writel_relaxed(val, pll->base + GNRL_CTL);
+}
+
+static const struct clk_ops clk_pll1416x_ops = {
+ .prepare = clk_int_pll_prepare,
+ .unprepare = clk_int_pll_unprepare,
+ .is_prepared = clk_int_pll_is_prepared,
+ .recalc_rate = clk_int_pll1416x_recalc_rate,
+ .round_rate = clk_int_pll_round_rate,
+ .set_rate = clk_int_pll1416x_set_rate,
+};
+
+static const struct clk_ops clk_pll1416x_min_ops = {
+ .recalc_rate = clk_int_pll1416x_recalc_rate,
+};
+
+static const struct clk_ops clk_pll1443x_ops = {
+ .prepare = clk_int_pll_prepare,
+ .unprepare = clk_int_pll_unprepare,
+ .is_prepared = clk_int_pll_is_prepared,
+ .recalc_rate = clk_int_pll1443x_recalc_rate,
+ .round_rate = clk_int_pll_round_rate,
+ .set_rate = clk_int_pll1443x_set_rate,
+};
+
+struct clk *imx_clk_int_pll(const char *name, const char *parent_name,
+ void __iomem *base,
+ const struct imx_int_pll_clk *pll_clk)
+{
+ struct clk_int_pll *pll;
+ struct clk *clk;
+ struct clk_init_data init;
+ int len;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.flags = pll_clk->flags;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ if (pll_clk->rate_table) {
+ for (len = 0; pll_clk->rate_table[len].rate != 0; )
+ len++;
+
+ pll->rate_count = len;
+ pll->rate_table = kmemdup(pll_clk->rate_table,
+ pll->rate_count *
+ sizeof(struct imx_int_pll_rate_table),
+ GFP_KERNEL);
+ WARN(!pll->rate_table, "%s : could not alloc rate table\n", __func__);
+ }
+
+ switch (pll_clk->type) {
+ case PLL_1416X:
+ if (!pll->rate_table)
+ init.ops = &clk_pll1416x_min_ops;
+ else
+ init.ops = &clk_pll1416x_ops;
+ break;
+ case PLL_1443X:
+ init.ops = &clk_pll1443x_ops;
+ break;
+ default:
+ pr_err("%s: Unknown pll type for pll clk %s\n",
+ __func__, name);
+ };
+
+ pll->base = base;
+ pll->hw.init = &init;
+ pll->type = pll_clk->type;
+
+ clk = clk_register(NULL, &pll->hw);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register pll %s %lu\n",
+ __func__, name, PTR_ERR(clk));
+ kfree(pll);
+ }
+
+ return clk;
+}
diff --git a/drivers/clk/imx/clk-mux-scu.c b/drivers/clk/imx/clk-mux-scu.c
new file mode 100644
index 000000000000..ac1c8bc385bd
--- /dev/null
+++ b/drivers/clk/imx/clk-mux-scu.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm_domain.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <soc/imx8/sc/sci.h>
+
+#include "clk-imx8.h"
+
+/*
+ * DOC: basic adjustable multiplexer clock that cannot gate
+ *
+ * Traits of this clock:
+ * prepare - clk_prepare only ensures that parents are prepared
+ * enable - clk_enable only ensures that parents are enabled
+ * rate - rate is only affected by parent switching. No clk_set_rate support
+ * parent - parent is adjustable through clk_set_parent
+ */
+
+struct clk_mux_scu {
+ struct clk_hw hw;
+ void __iomem *reg;
+ u32 *table;
+ u32 mask;
+ u8 shift;
+ u8 flags;
+ u32 val;
+ bool update;
+ spinlock_t *lock;
+ char *pd_name;
+ struct generic_pm_domain *pd;
+};
+
+struct clk_mux_gpr_scu {
+ struct clk_hw hw;
+ sc_rsrc_t rsrc_id;
+ sc_ctrl_t gpr_id;
+};
+
+struct clk_mux2_scu {
+ struct clk_hw hw;
+ sc_rsrc_t rsrc_id;
+ sc_pm_clk_t clk_type;
+};
+
+#define to_clk_mux_scu(_hw) container_of(_hw, struct clk_mux_scu, hw)
+#define to_clk_mux_gpr_scu(_hw) container_of(_hw, struct clk_mux_gpr_scu, hw)
+#define to_clk_mux2_scu(_hw) container_of(_hw, struct clk_mux2_scu, hw)
+
+/* Get the power domain associated with the clock from the device tree. */
+static void populate_mux_pd(struct clk_mux_scu *clk)
+{
+ struct device_node *np;
+ struct of_phandle_args pd_args;
+
+ np = of_find_node_by_name(NULL, clk->pd_name);
+ if (np) {
+ pd_args.np = np;
+ pd_args.args_count = 0;
+ clk->pd = genpd_get_from_provider(&pd_args);
+ if (IS_ERR(clk->pd))
+ pr_warn("%s: failed to get pd\n", __func__);
+ }
+}
+
+static int check_mux_pd(struct clk_mux_scu *mux)
+{
+ if (!ccm_ipc_handle)
+ return -1;
+
+ if (mux->pd == NULL && mux->pd_name)
+ populate_mux_pd(mux);
+
+ if (IS_ERR_OR_NULL(mux->pd))
+ return -1;
+
+ if (mux->pd->status != GPD_STATE_ACTIVE)
+ return -1;
+
+ return 0;
+}
+
+static u8 clk_mux_get_parent_scu(struct clk_hw *hw)
+{
+ struct clk_mux_scu *mux = to_clk_mux_scu(hw);
+ int num_parents = clk_hw_get_num_parents(hw);
+ u32 val;
+
+ /*
+ * FIXME need a mux-specific flag to determine if val is bitwise or numeric
+ * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1
+ * to 0x7 (index starts at one)
+ * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
+ * val = 0x4 really means "bit 2, index starts at bit 0"
+ */
+ val = mux->val >> mux->shift;
+ val &= mux->mask;
+
+ if (mux->table) {
+ int i;
+
+ for (i = 0; i < num_parents; i++)
+ if (mux->table[i] == val)
+ return i;
+ return -EINVAL;
+ }
+
+ if (val && (mux->flags & CLK_MUX_INDEX_BIT))
+ val = ffs(val) - 1;
+
+ if (val && (mux->flags & CLK_MUX_INDEX_ONE))
+ val--;
+
+ if (val >= num_parents)
+ return -EINVAL;
+
+ return val;
+}
+
+static int clk_mux_prepare_scu(struct clk_hw *hw)
+{
+ struct clk_mux_scu *mux = to_clk_mux_scu(hw);
+ unsigned long flags = 0;
+ int ret;
+
+ ret = check_mux_pd(mux);
+ if (ret)
+ return ret;
+
+ if (mux->lock)
+ spin_lock_irqsave(mux->lock, flags);
+
+ if (mux->update) {
+ clk_writel(mux->val, mux->reg);
+ mux->update = 0;
+ }
+
+ if (mux->lock)
+ spin_unlock_irqrestore(mux->lock, flags);
+
+ return 0;
+}
+
+static int clk_mux_set_parent_scu(struct clk_hw *hw, u8 index)
+{
+ struct clk_mux_scu *mux = to_clk_mux_scu(hw);
+ unsigned long flags = 0;
+ int ret;
+
+ ret = check_mux_pd(mux);
+
+ if (mux->table) {
+ index = mux->table[index];
+ } else {
+ if (mux->flags & CLK_MUX_INDEX_BIT)
+ index = 1 << index;
+ if (mux->flags & CLK_MUX_INDEX_ONE)
+ index++;
+ }
+
+ if (mux->lock)
+ spin_lock_irqsave(mux->lock, flags);
+
+ if (mux->flags & CLK_MUX_HIWORD_MASK) {
+ mux->val = mux->mask << (mux->shift + 16);
+ } else {
+ mux->val &= ~(mux->mask << mux->shift);
+ }
+ mux->val |= index << mux->shift;
+ mux->update = (ret != 0);
+
+ if (ret == 0)
+ clk_writel(mux->val, mux->reg);
+
+ if (mux->lock)
+ spin_unlock_irqrestore(mux->lock, flags);
+
+ return 0;
+}
+
+const struct clk_ops clk_mux_scu_ops = {
+ .prepare = clk_mux_prepare_scu,
+ .get_parent = clk_mux_get_parent_scu,
+ .set_parent = clk_mux_set_parent_scu,
+ .determine_rate = __clk_mux_determine_rate,
+};
+
+const struct clk_ops clk_mux_ro_scu_ops = {
+ .get_parent = clk_mux_get_parent_scu,
+};
+
+struct clk *clk_register_mux_table_scu(struct device *dev, const char *name,
+ const char **parent_names, u8 num_parents, unsigned long flags,
+ void __iomem *reg, u8 shift, u32 mask,
+ u8 clk_mux_flags, u32 *table, spinlock_t *lock,
+ const char *pd_name)
+{
+ struct clk_mux_scu *mux;
+ struct clk *clk;
+ struct clk_init_data init;
+ u8 width = 0;
+
+ if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
+ width = fls(mask) - ffs(mask) + 1;
+ if (width + shift > 16) {
+ pr_err("mux value exceeds LOWORD field\n");
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
+ /* allocate the mux */
+ mux = kzalloc(sizeof(struct clk_mux_scu), GFP_KERNEL);
+ if (!mux) {
+ pr_err("%s: could not allocate mux clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init.name = name;
+ if (clk_mux_flags & CLK_MUX_READ_ONLY)
+ init.ops = &clk_mux_ro_scu_ops;
+ else
+ init.ops = &clk_mux_scu_ops;
+ init.flags = flags | CLK_IS_BASIC;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+
+ /* struct clk_mux_scu assignments */
+ mux->reg = reg;
+ mux->shift = shift;
+ mux->mask = mask;
+ mux->flags = clk_mux_flags;
+ mux->lock = lock;
+ mux->table = table;
+ mux->hw.init = &init;
+ mux->pd_name = NULL;
+ if (pd_name) {
+ mux->pd_name = kzalloc(strlen(pd_name) + 1, GFP_KERNEL);
+ strcpy(mux->pd_name, pd_name);
+ }
+
+ clk = clk_register(dev, &mux->hw);
+
+ if (IS_ERR(clk)) {
+ kfree(mux->pd_name);
+ kfree(mux);
+ }
+
+ return clk;
+}
+
+struct clk *clk_register_mux_scu(struct device *dev, const char *name,
+ const char **parent_names, u8 num_parents, unsigned long flags,
+ void __iomem *reg, u8 shift, u8 width,
+ u8 clk_mux_flags, spinlock_t *lock,
+ const char *pd_name)
+{
+ u32 mask = BIT(width) - 1;
+
+ return clk_register_mux_table_scu(dev, name, parent_names, num_parents,
+ flags, reg, shift, mask, clk_mux_flags,
+ NULL, lock, pd_name);
+}
+
+void clk_unregister_mux_scu(struct clk *clk)
+{
+ struct clk_mux_scu *mux;
+ struct clk_hw *hw;
+
+ hw = __clk_get_hw(clk);
+ if (!hw)
+ return;
+
+ mux = to_clk_mux_scu(hw);
+
+ clk_unregister(clk);
+ kfree(mux);
+}
+
+static u8 clk_mux_gpr_scu_get_parent(struct clk_hw *hw)
+{
+ struct clk_mux_gpr_scu *gpr_mux = to_clk_mux_gpr_scu(hw);
+ u32 val = 0;
+
+ if (!ccm_ipc_handle)
+ return 0;
+
+ sc_misc_get_control(ccm_ipc_handle,
+ gpr_mux->rsrc_id, gpr_mux->gpr_id, &val);
+
+ return (u8)val;
+}
+
+static int clk_mux_gpr_scu_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_mux_gpr_scu *gpr_mux = to_clk_mux_gpr_scu(hw);
+
+ if (!ccm_ipc_handle)
+ return -1;
+
+ sc_misc_set_control(ccm_ipc_handle,
+ gpr_mux->rsrc_id, gpr_mux->gpr_id, index);
+
+ return 0;
+}
+
+static const struct clk_ops clk_mux_gpr_scu_ops = {
+ .get_parent = clk_mux_gpr_scu_get_parent,
+ .set_parent = clk_mux_gpr_scu_set_parent,
+};
+
+struct clk *clk_register_mux_gpr_scu(struct device *dev, const char *name,
+ const char **parents, int num_parents, spinlock_t *lock,
+ sc_rsrc_t rsrc_id, sc_ctrl_t gpr_id)
+{
+ struct clk_mux_gpr_scu *gpr_scu_mux;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ if (!imx8_clk_is_resource_owned(rsrc_id)) {
+ pr_debug("skip clk %s rsrc %d not owned\n", name, rsrc_id);
+ return ERR_PTR(-ENODEV);
+ }
+
+ if (rsrc_id >= SC_R_LAST)
+ return NULL;
+
+ if (gpr_id >= SC_C_LAST)
+ return NULL;
+
+ gpr_scu_mux = kzalloc(sizeof(struct clk_mux_gpr_scu), GFP_KERNEL);
+ if (!gpr_scu_mux)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &clk_mux_gpr_scu_ops;
+ init.parent_names = parents;
+ init.num_parents = num_parents;
+ init.flags |= CLK_SET_PARENT_NOCACHE;
+
+ gpr_scu_mux->hw.init = &init;
+ gpr_scu_mux->rsrc_id = rsrc_id;
+ gpr_scu_mux->gpr_id = gpr_id;
+
+ clk = clk_register(NULL, &gpr_scu_mux->hw);
+ if (IS_ERR(clk))
+ kfree(gpr_scu_mux);
+
+ return clk;
+}
+
+static u8 clk_mux2_scu_get_parent(struct clk_hw *hw)
+{
+ struct clk_mux2_scu *mux = to_clk_mux2_scu(hw);
+ sc_pm_clk_parent_t parent;
+ sc_err_t ret;
+
+ if (!ccm_ipc_handle)
+ return -EBUSY;
+
+ ret = sc_pm_get_clock_parent(ccm_ipc_handle, mux->rsrc_id,
+ mux->clk_type, &parent);
+ if (ret != SC_ERR_NONE)
+ return -EINVAL;
+
+ return (u8)parent;
+}
+
+static int clk_mux2_scu_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_mux2_scu *mux = to_clk_mux2_scu(hw);
+ sc_err_t ret;
+
+ if (!ccm_ipc_handle)
+ return -EBUSY;
+
+ ret = sc_pm_set_clock_parent(ccm_ipc_handle, mux->rsrc_id,
+ mux->clk_type, index);
+ if (ret != SC_ERR_NONE)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct clk_ops clk_mux2_scu_ops = {
+ .get_parent = clk_mux2_scu_get_parent,
+ .set_parent = clk_mux2_scu_set_parent,
+};
+
+
+struct clk *clk_register_mux2_scu(struct device *dev, const char *name,
+ const char **parents, int num_parents,
+ unsigned long flags, sc_rsrc_t rsrc_id,
+ sc_pm_clk_t clk_type)
+{
+ struct clk_mux2_scu *mux;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ if (!imx8_clk_is_resource_owned(rsrc_id)) {
+ pr_debug("skip clk %s rsrc %d not owned\n", name, rsrc_id);
+ return ERR_PTR(-ENODEV);
+ }
+
+ if (rsrc_id >= SC_R_LAST)
+ return ERR_PTR(-EINVAL);
+
+ mux = kzalloc(sizeof(struct clk_mux2_scu), GFP_KERNEL);
+ if (!mux)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &clk_mux2_scu_ops;
+ init.parent_names = parents;
+ init.num_parents = num_parents;
+ init.flags = flags |= CLK_SET_PARENT_NOCACHE;
+
+ mux->hw.init = &init;
+ mux->rsrc_id = rsrc_id;
+ mux->clk_type = clk_type;
+
+ clk = clk_register(NULL, &mux->hw);
+ if (IS_ERR(clk))
+ kfree(mux);
+
+ return clk;
+}
diff --git a/drivers/clk/imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c
index 04a3e78ea1bc..e29bd792522f 100644
--- a/drivers/clk/imx/clk-pfd.c
+++ b/drivers/clk/imx/clk-pfd.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012-2015 Freescale Semiconductor, Inc.
* Copyright 2012 Linaro Ltd.
*
* The code contained herein is licensed under the GNU General Public
@@ -11,11 +11,14 @@
*/
#include <linux/clk-provider.h>
+#include <linux/imx_sema4.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <soc/imx/src.h>
#include "clk.h"
+
/**
* struct clk_pfd - IMX PFD clock
* @clk_hw: clock source
@@ -38,20 +41,57 @@ struct clk_pfd {
#define CLR 0x8
#define OTG 0xc
-static int clk_pfd_enable(struct clk_hw *hw)
+static void clk_pfd_do_hardware(struct clk_pfd *pfd, bool enable)
+{
+ if (enable)
+ writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR);
+ else
+ writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET);
+}
+
+static void clk_pfd_do_shared_clks(struct clk_hw *hw, bool enable)
{
struct clk_pfd *pfd = to_clk_pfd(hw);
- writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + CLR);
+ if (imx_src_is_m4_enabled() && clk_on_imx6sx()) {
+#ifdef CONFIG_SOC_IMX6SX
+ if (!amp_power_mutex || !shared_mem) {
+ if (enable)
+ clk_pfd_do_hardware(pfd, enable);
+ return;
+ }
+
+ imx_sema4_mutex_lock(amp_power_mutex);
+ if (shared_mem->ca9_valid != SHARED_MEM_MAGIC_NUMBER ||
+ shared_mem->cm4_valid != SHARED_MEM_MAGIC_NUMBER) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+
+ if (!imx_update_shared_mem(hw, enable)) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+
+ clk_pfd_do_hardware(pfd, enable);
+
+ imx_sema4_mutex_unlock(amp_power_mutex);
+#endif
+ } else {
+ clk_pfd_do_hardware(pfd, enable);
+ }
+}
+
+static int clk_pfd_enable(struct clk_hw *hw)
+{
+ clk_pfd_do_shared_clks(hw, true);
return 0;
}
static void clk_pfd_disable(struct clk_hw *hw)
{
- struct clk_pfd *pfd = to_clk_pfd(hw);
-
- writel_relaxed(1 << ((pfd->idx + 1) * 8 - 1), pfd->reg + SET);
+ clk_pfd_do_shared_clks(hw, false);
}
static unsigned long clk_pfd_recalc_rate(struct clk_hw *hw,
diff --git a/drivers/clk/imx/clk-pfdv2.c b/drivers/clk/imx/clk-pfdv2.c
new file mode 100644
index 000000000000..b342f3c3d843
--- /dev/null
+++ b/drivers/clk/imx/clk-pfdv2.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+
+#include "clk.h"
+
+/**
+ * struct clk_pfdv2 - IMX PFD clock
+ * @clk_hw: clock source
+ * @reg: PFD register address
+ * @gate_bit: Gate bit offset
+ * @vld_bit: Valid bit offset
+ * @frac_off: PLL Fractional Divider offset
+ */
+
+struct clk_pfdv2 {
+ struct clk_hw hw;
+ void __iomem *reg;
+ u32 gate_bit;
+ u32 vld_bit;
+ u8 frac_off;
+};
+
+#define to_clk_pfdv2(_hw) container_of(_hw, struct clk_pfdv2, hw)
+
+#define CLK_PFDV2_FRAC_MASK 0x3f
+
+#define LOCK_TIMEOUT_US USEC_PER_MSEC
+
+static DEFINE_SPINLOCK(pfd_lock);
+
+static int clk_pfdv2_wait(struct clk_pfdv2 *pfd)
+{
+ u32 val;
+
+ return readl_poll_timeout(pfd->reg, val, val & pfd->vld_bit,
+ 0, LOCK_TIMEOUT_US);
+}
+
+static int clk_pfd_enable(struct clk_hw *hw)
+{
+ struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&pfd_lock, flags);
+ val = readl_relaxed(pfd->reg);
+ val &= ~pfd->gate_bit;
+ writel_relaxed(val, pfd->reg);
+ spin_unlock_irqrestore(&pfd_lock, flags);
+
+ return clk_pfdv2_wait(pfd);
+}
+
+static void clk_pfd_disable(struct clk_hw *hw)
+{
+ struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&pfd_lock, flags);
+ val = readl_relaxed(pfd->reg);
+ val |= pfd->gate_bit;
+ writel_relaxed(val, pfd->reg);
+ spin_unlock_irqrestore(&pfd_lock, flags);
+}
+
+static unsigned long clk_pfd_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
+ u64 tmp = parent_rate;
+ u8 frac;
+
+ frac = (readl_relaxed(pfd->reg) >> pfd->frac_off)
+ & CLK_PFDV2_FRAC_MASK;
+
+ if (!frac) {
+ pr_debug("clk_pfdv2: %s invalid pfd frac value 0\n",
+ clk_hw_get_name(hw));
+ return 0;
+ }
+
+ tmp *= 18;
+ do_div(tmp, frac);
+
+ return tmp;
+}
+
+static long clk_pfd_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ u64 tmp = *prate;
+ u8 frac;
+
+ tmp = tmp * 18 + rate / 2;
+ do_div(tmp, rate);
+ frac = tmp;
+ if (frac < 12)
+ frac = 12;
+ else if (frac > 35)
+ frac = 35;
+ tmp = *prate;
+ tmp *= 18;
+ do_div(tmp, frac);
+
+ return tmp;
+}
+
+static int clk_pfd_is_enabled(struct clk_hw *hw)
+{
+ struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
+
+ if (readl_relaxed(pfd->reg) & pfd->gate_bit)
+ return 0;
+
+ return 1;
+}
+
+static int clk_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
+ unsigned long flags;
+ u64 tmp = parent_rate;
+ u32 val;
+ u8 frac;
+
+ if (!rate)
+ return -EINVAL;
+
+ /* PFD can NOT change rate without gating */
+ WARN_ON(clk_pfd_is_enabled(hw));
+
+ tmp = tmp * 18 + rate / 2;
+ do_div(tmp, rate);
+ frac = tmp;
+ if (frac < 12)
+ frac = 12;
+ else if (frac > 35)
+ frac = 35;
+
+ spin_lock_irqsave(&pfd_lock, flags);
+ val = readl_relaxed(pfd->reg);
+ val &= ~(CLK_PFDV2_FRAC_MASK << pfd->frac_off);
+ val |= frac << pfd->frac_off;
+ writel_relaxed(val, pfd->reg);
+ spin_unlock_irqrestore(&pfd_lock, flags);
+
+ return 0;
+}
+
+static const struct clk_ops clk_pfdv2_ops = {
+ .enable = clk_pfd_enable,
+ .disable = clk_pfd_disable,
+ .recalc_rate = clk_pfd_recalc_rate,
+ .round_rate = clk_pfd_round_rate,
+ .set_rate = clk_pfd_set_rate,
+ .is_enabled = clk_pfd_is_enabled,
+};
+
+struct clk *imx_clk_pfdv2(const char *name, const char *parent_name,
+ void __iomem *reg, u8 idx)
+{
+ struct clk_pfdv2 *pfd;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ WARN_ON(idx > 3);
+
+ pfd = kzalloc(sizeof(*pfd), GFP_KERNEL);
+ if (!pfd)
+ return ERR_PTR(-ENOMEM);
+
+ pfd->reg = reg;
+ pfd->gate_bit = 1 << ((idx + 1) * 8 - 1);
+ pfd->vld_bit = pfd->gate_bit >> 1;
+ pfd->frac_off = idx * 8;
+
+ init.name = name;
+ init.ops = &clk_pfdv2_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+ init.flags = CLK_SET_RATE_GATE;
+
+ pfd->hw.init = &init;
+
+ clk = clk_register(NULL, &pfd->hw);
+ if (IS_ERR(clk))
+ kfree(pfd);
+
+ return clk;
+}
diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c
index 7a6acc3e4a92..d8b481936f20 100644
--- a/drivers/clk/imx/clk-pllv3.c
+++ b/drivers/clk/imx/clk-pllv3.c
@@ -11,15 +11,20 @@
*/
#include <linux/clk-provider.h>
-#include <linux/delay.h>
+#include <linux/imx_sema4.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/err.h>
+#include <soc/imx/src.h>
#include "clk.h"
-#define PLL_NUM_OFFSET 0x10
-#define PLL_DENOM_OFFSET 0x20
+#define PLL_NUM_OFFSET 0x10
+#define PLL_DENOM_OFFSET 0x20
+#define PLL_AV_IMX7_NUM_OFFSET 0x20
+#define PLL_AV_IMX7_DENOM_OFFSET 0x30
+#define PLL_PLL2_NUM_OFFSET 0x20
+#define PLL_PLL2_DENOM_OFFSET 0x30
#define BM_PLL_POWER (0x1 << 12)
#define BM_PLL_LOCK (0x1 << 31)
@@ -45,6 +50,8 @@ struct clk_pllv3 {
u32 div_mask;
u32 div_shift;
unsigned long ref_clock;
+ u32 num_offset;
+ u32 denom_offset;
};
#define to_clk_pllv3(_hw) container_of(_hw, struct clk_pllv3, hw)
@@ -64,38 +71,79 @@ static int clk_pllv3_wait_lock(struct clk_pllv3 *pll)
break;
if (time_after(jiffies, timeout))
break;
- usleep_range(50, 500);
} while (1);
return readl_relaxed(pll->base) & BM_PLL_LOCK ? 0 : -ETIMEDOUT;
}
-static int clk_pllv3_prepare(struct clk_hw *hw)
+static int clk_pllv3_do_hardware(struct clk_hw *hw, bool enable)
{
struct clk_pllv3 *pll = to_clk_pllv3(hw);
+ int ret;
u32 val;
val = readl_relaxed(pll->base);
- if (pll->powerup_set)
- val |= pll->power_bit;
- else
- val &= ~pll->power_bit;
- writel_relaxed(val, pll->base);
+ if (enable) {
+ if (pll->powerup_set)
+ val |= pll->power_bit;
+ else
+ val &= ~pll->power_bit;
+ writel_relaxed(val, pll->base);
+
+ ret = clk_pllv3_wait_lock(pll);
+ if (ret)
+ return ret;
+ } else {
+ if (pll->powerup_set)
+ val &= ~pll->power_bit;
+ else
+ val |= pll->power_bit;
+ writel_relaxed(val, pll->base);
+ }
- return clk_pllv3_wait_lock(pll);
+ return 0;
}
-static void clk_pllv3_unprepare(struct clk_hw *hw)
+static void clk_pllv3_do_shared_clks(struct clk_hw *hw, bool enable)
{
- struct clk_pllv3 *pll = to_clk_pllv3(hw);
- u32 val;
+ if (imx_src_is_m4_enabled() && clk_on_imx6sx()) {
+#ifdef CONFIG_SOC_IMX6SX
+ if (!amp_power_mutex || !shared_mem) {
+ if (enable)
+ clk_pllv3_do_hardware(hw, enable);
+ return;
+ }
+
+ imx_sema4_mutex_lock(amp_power_mutex);
+ if (shared_mem->ca9_valid != SHARED_MEM_MAGIC_NUMBER ||
+ shared_mem->cm4_valid != SHARED_MEM_MAGIC_NUMBER) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+
+ if (!imx_update_shared_mem(hw, enable)) {
+ imx_sema4_mutex_unlock(amp_power_mutex);
+ return;
+ }
+ clk_pllv3_do_hardware(hw, enable);
+
+ imx_sema4_mutex_unlock(amp_power_mutex);
+#endif
+ } else {
+ clk_pllv3_do_hardware(hw, enable);
+ }
+}
- val = readl_relaxed(pll->base);
- if (pll->powerup_set)
- val &= ~pll->power_bit;
- else
- val |= pll->power_bit;
- writel_relaxed(val, pll->base);
+static int clk_pllv3_prepare(struct clk_hw *hw)
+{
+ clk_pllv3_do_shared_clks(hw, true);
+
+ return 0;
+}
+
+static void clk_pllv3_unprepare(struct clk_hw *hw)
+{
+ clk_pllv3_do_shared_clks(hw, false);
}
static int clk_pllv3_is_prepared(struct clk_hw *hw)
@@ -215,8 +263,8 @@ static unsigned long clk_pllv3_av_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_pllv3 *pll = to_clk_pllv3(hw);
- u32 mfn = readl_relaxed(pll->base + PLL_NUM_OFFSET);
- u32 mfd = readl_relaxed(pll->base + PLL_DENOM_OFFSET);
+ u32 mfn = readl_relaxed(pll->base + pll->num_offset);
+ u32 mfd = readl_relaxed(pll->base + pll->denom_offset);
u32 div = readl_relaxed(pll->base) & pll->div_mask;
u64 temp64 = (u64)parent_rate;
@@ -277,8 +325,8 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate,
val &= ~pll->div_mask;
val |= div;
writel_relaxed(val, pll->base);
- writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET);
- writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET);
+ writel_relaxed(mfn, pll->base + pll->num_offset);
+ writel_relaxed(mfd, pll->base + pll->denom_offset);
return clk_pllv3_wait_lock(pll);
}
@@ -307,6 +355,28 @@ static const struct clk_ops clk_pllv3_enet_ops = {
.recalc_rate = clk_pllv3_enet_recalc_rate,
};
+static unsigned long clk_pllv3_pll2_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_pllv3 *pll = to_clk_pllv3(hw);
+ u32 div = (readl_relaxed(pll->base) >> pll->div_shift) & pll->div_mask;
+ u32 mfn = readl_relaxed(pll->base + pll->num_offset);
+ u32 mfd = readl_relaxed(pll->base + pll->denom_offset);
+ u64 temp64 = (u64)parent_rate;
+
+ temp64 *= mfn;
+ do_div(temp64, mfd);
+
+ return (parent_rate * ((div == 1) ? 22 : 20)) + (u32)temp64;
+}
+
+static const struct clk_ops clk_pllv3_pll2_ops = {
+ .prepare = clk_pllv3_prepare,
+ .unprepare = clk_pllv3_unprepare,
+ .is_prepared = clk_pllv3_is_prepared,
+ .recalc_rate = clk_pllv3_pll2_recalc_rate,
+};
+
struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
const char *parent_name, void __iomem *base,
u32 div_mask)
@@ -321,17 +391,28 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
return ERR_PTR(-ENOMEM);
pll->power_bit = BM_PLL_POWER;
+ pll->num_offset = PLL_NUM_OFFSET;
+ pll->denom_offset = PLL_DENOM_OFFSET;
switch (type) {
case IMX_PLLV3_SYS:
ops = &clk_pllv3_sys_ops;
break;
+ case IMX_PLLV3_PLL2:
+ pll->num_offset = PLL_PLL2_NUM_OFFSET;
+ pll->denom_offset = PLL_PLL2_DENOM_OFFSET;
+ ops = &clk_pllv3_pll2_ops;
+ break;
case IMX_PLLV3_USB_VF610:
pll->div_shift = 1;
case IMX_PLLV3_USB:
ops = &clk_pllv3_ops;
pll->powerup_set = true;
break;
+ case IMX_PLLV3_AV_IMX7:
+ pll->num_offset = PLL_AV_IMX7_NUM_OFFSET;
+ pll->denom_offset = PLL_AV_IMX7_DENOM_OFFSET;
+ /* fall through */
case IMX_PLLV3_AV:
ops = &clk_pllv3_av_ops;
break;
diff --git a/drivers/clk/imx/clk-pllv4.c b/drivers/clk/imx/clk-pllv4.c
new file mode 100644
index 000000000000..0aa1d01d7dc4
--- /dev/null
+++ b/drivers/clk/imx/clk-pllv4.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+/* PLL Control Status Register (xPLLCSR) */
+#define PLL_CSR_OFFSET 0x0
+#define PLL_VLD BIT(24)
+#define PLL_EN BIT(0)
+#define BP_PLL_MULT 16
+#define BM_PLL_MULT (0x7f << 16)
+#define PLL_CFG_OFFSET 0x08
+#define PLL_NUM_OFFSET 0x10
+#define PLL_DENOM_OFFSET 0x14
+
+struct clk_pllv4 {
+ struct clk_hw hw;
+ void __iomem *base;
+};
+
+/* Valid PLL MULT Table */
+static const int pllv4_mult_table[] = {33, 27, 22, 20, 17, 16};
+
+#define to_clk_pllv4(__hw) container_of(__hw, struct clk_pllv4, hw)
+
+#define LOCK_TIMEOUT_US USEC_PER_MSEC
+
+static inline int clk_pllv4_wait_lock(struct clk_pllv4 *pll)
+{
+ u32 csr;
+
+ return readl_poll_timeout(pll->base + PLL_CSR_OFFSET,
+ csr, csr & PLL_VLD, 0, LOCK_TIMEOUT_US);
+}
+
+
+static unsigned long clk_pllv4_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_pllv4 *pll = to_clk_pllv4(hw);
+ u32 mfn = readl_relaxed(pll->base + PLL_NUM_OFFSET);
+ u32 mfd = readl_relaxed(pll->base + PLL_DENOM_OFFSET);
+ u32 mult = (readl_relaxed(pll->base + PLL_CFG_OFFSET)
+ & BM_PLL_MULT) >> BP_PLL_MULT;
+ u64 temp64 = (u64)parent_rate;
+
+ temp64 *= mfn;
+ do_div(temp64, mfd);
+
+ return (parent_rate * mult) + (u32)temp64;
+}
+
+static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ unsigned long parent_rate = *prate;
+ unsigned long round_rate;
+ u32 mfn, mfd = 1000000;
+ bool found = false;
+ u64 temp64, i;
+
+ for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) {
+ round_rate = parent_rate * pllv4_mult_table[i];
+ if (rate >= round_rate) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_warn("%s: unable to round rate %lu prate %lu\n",
+ clk_hw_get_name(hw), rate, parent_rate);
+ return 0;
+ }
+
+ temp64 = (u64) (rate - round_rate);
+ temp64 *= mfd;
+ do_div(temp64, parent_rate);
+ mfn = temp64;
+
+ /*
+ * NOTE: The value of numerator must always be configured to be
+ * less than the value of the denominator. If we can't get a proper
+ * pair of mfn/mfd, we simply return the round_rate without using
+ * the frac part.
+ */
+ if (mfn >= mfd)
+ return round_rate;
+
+ return round_rate + parent_rate / mfd * mfn;
+}
+
+static bool clk_pllv4_is_valid_mult(unsigned int mult)
+{
+ int i;
+
+ /* check if mult is in valid MULT table */
+ for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) {
+ if (pllv4_mult_table[i] == mult)
+ return true;
+ }
+
+ return false;
+}
+
+static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_pllv4 *pll = to_clk_pllv4(hw);
+ u32 val, mult;
+ u32 mfn, mfd = 1000000;
+ u64 temp64;
+
+ mult = rate / parent_rate;
+
+ if (!clk_pllv4_is_valid_mult(mult))
+ return -EINVAL;
+
+ temp64 = (u64) (rate - mult * parent_rate);
+ temp64 *= mfd;
+ do_div(temp64, parent_rate);
+ mfn = temp64;
+
+ val = readl_relaxed(pll->base + PLL_CFG_OFFSET);
+ val &= ~BM_PLL_MULT;
+ val |= mult << BP_PLL_MULT;
+ writel_relaxed(val, pll->base + PLL_CFG_OFFSET);
+ writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET);
+ writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET);
+
+ return 0;
+}
+
+static int clk_pllv4_enable(struct clk_hw *hw)
+{
+ u32 val;
+ struct clk_pllv4 *pll = to_clk_pllv4(hw);
+
+ val = readl_relaxed(pll->base);
+ val |= PLL_EN;
+ writel_relaxed(val, pll->base);
+
+ return clk_pllv4_wait_lock(pll);
+}
+
+static void clk_pllv4_disable(struct clk_hw *hw)
+{
+ u32 val;
+ struct clk_pllv4 *pll = to_clk_pllv4(hw);
+
+ val = readl_relaxed(pll->base);
+ val &= ~PLL_EN;
+ writel_relaxed(val, pll->base);
+}
+
+static int clk_pllv4_is_enabled(struct clk_hw *hw)
+{
+ struct clk_pllv4 *pll = to_clk_pllv4(hw);
+
+ if (readl_relaxed(pll->base) & PLL_EN)
+ return 1;
+
+ return 0;
+}
+
+static const struct clk_ops clk_pllv4_ops = {
+ .recalc_rate = clk_pllv4_recalc_rate,
+ .round_rate = clk_pllv4_round_rate,
+ .set_rate = clk_pllv4_set_rate,
+ .enable = clk_pllv4_enable,
+ .disable = clk_pllv4_disable,
+ .is_enabled = clk_pllv4_is_enabled,
+};
+
+struct clk *imx_clk_pllv4(const char *name, const char *parent_name,
+ void __iomem *base)
+{
+ struct clk_pllv4 *pll;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ pll->base = base;
+ init.name = name;
+ init.ops = &clk_pllv4_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+ init.flags = CLK_SET_RATE_GATE;
+
+ pll->hw.init = &init;
+
+ clk = clk_register(NULL, &pll->hw);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
diff --git a/drivers/clk/imx/clk-pllv5.c b/drivers/clk/imx/clk-pllv5.c
new file mode 100644
index 000000000000..c45704c7942e
--- /dev/null
+++ b/drivers/clk/imx/clk-pllv5.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+#define PLL_EN BIT(0)
+#define BP_PLL_DIV 16
+#define BM_PLL_DIV (0x7 << 16)
+#define PLL_CFG_OFFSET 0x08
+
+struct clk_pllv5 {
+ struct clk_hw hw;
+ void __iomem *base;
+ u32 div_mask;
+ u32 div_shift;
+ u32 cfg_offset;
+};
+
+#define to_clk_pllv5(__hw) container_of(__hw, struct clk_pllv5, hw)
+
+static unsigned long clk_pllv5_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_pllv5 *pll = to_clk_pllv5(hw);
+ u32 val = (readl_relaxed(pll->base + pll->cfg_offset) & pll->div_mask) >> pll->div_shift;
+ u32 div;
+
+ switch (val) {
+ case 1:
+ div = 15;
+ break;
+ case 2:
+ div = 16;
+ break;
+ case 3:
+ div = 20;
+ break;
+ case 4:
+ div = 22;
+ break;
+ case 5:
+ div = 25;
+ break;
+ case 6:
+ div = 30;
+ break;
+ default:
+ div = 20;
+ break;
+ }
+
+ return parent_rate * div;
+}
+
+static long clk_pllv5_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ unsigned long parent_rate = *prate;
+ u32 div;
+
+ div = rate / parent_rate;
+
+ if (div == 15 || div == 16 ||
+ div == 20 || div == 22 ||
+ div == 25 || div == 30)
+ return parent_rate * div;
+ else
+ return parent_rate * 20;
+}
+
+static int clk_pllv5_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_pllv5 *pll = to_clk_pllv5(hw);
+ unsigned long min_rate = parent_rate * 15;
+ unsigned long max_rate = parent_rate * 30;
+ u32 val, div, reg;
+
+ if (rate < min_rate || rate > max_rate)
+ return -EINVAL;
+
+ div = rate / parent_rate;
+
+ switch (div) {
+ case 15:
+ val = 1;
+ break;
+ case 16:
+ val = 2;
+ break;
+ case 20:
+ val = 3;
+ break;
+ case 22:
+ val = 4;
+ break;
+ case 25:
+ val = 5;
+ break;
+ case 30:
+ val = 6;
+ break;
+ default:
+ val = 3;
+ break;
+ }
+
+ reg = readl_relaxed(pll->base + pll->cfg_offset);
+ reg &= ~pll->div_mask;
+ reg |= (val << pll->div_shift);
+ writel_relaxed(val, pll->base + pll->cfg_offset);
+
+ return 0;
+}
+
+static int clk_pllv5_enable(struct clk_hw *hw)
+{
+ u32 val;
+ struct clk_pllv5 *pll = to_clk_pllv5(hw);
+
+ val = readl_relaxed(pll->base);
+ val |= PLL_EN;
+ writel_relaxed(val, pll->base);
+
+ return 0;
+}
+
+static void clk_pllv5_disable(struct clk_hw *hw)
+{
+ u32 val;
+ struct clk_pllv5 *pll = to_clk_pllv5(hw);
+
+ val = readl_relaxed(pll->base);
+ val &= ~PLL_EN;
+ writel_relaxed(val, pll->base);
+}
+
+static int clk_pllv5_is_enabled(struct clk_hw *hw)
+{
+ struct clk_pllv5 *pll = to_clk_pllv5(hw);
+
+ if (readl_relaxed(pll->base) & PLL_EN)
+ return 0;
+
+ return 1;
+}
+
+static const struct clk_ops clk_pllv5_ops = {
+ .recalc_rate = clk_pllv5_recalc_rate,
+ .round_rate = clk_pllv5_round_rate,
+ .set_rate = clk_pllv5_set_rate,
+ .enable = clk_pllv5_enable,
+ .disable = clk_pllv5_disable,
+ .is_enabled = clk_pllv5_is_enabled,
+};
+
+struct clk *imx_clk_pllv5(const char *name, const char *parent_name,
+ void __iomem *base)
+{
+ struct clk_pllv5 *pll;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ pll->base = base;
+ pll->div_mask = BM_PLL_DIV;
+ pll->div_shift = BP_PLL_DIV;
+ pll->cfg_offset = PLL_CFG_OFFSET;
+
+ init.name = name;
+ init.ops = &clk_pllv5_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ pll->hw.init = &init;
+
+ clk = clk_register(NULL, &pll->hw);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+
diff --git a/drivers/clk/imx/clk-sccg-pll.c b/drivers/clk/imx/clk-sccg-pll.c
new file mode 100644
index 000000000000..eb4fcff0024b
--- /dev/null
+++ b/drivers/clk/imx/clk-sccg-pll.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2017-2018 NXP.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+/* PLL CFGs */
+#define PLL_CFG0 0x0
+#define PLL_CFG1 0x4
+#define PLL_CFG2 0x8
+
+#define PLL_DIVF1_SHIFT 13
+#define PLL_DIVF2_SHIFT 7
+#define PLL_DIVF_MASK 0x3f
+
+#define PLL_DIVR1_SHIFT 25
+#define PLL_DIVR2_SHIFT 19
+#define PLL_DIVR1_MASK 0x3
+#define PLL_DIVR2_MASK 0x3f
+#define PLL_REF_SHIFT 0
+#define PLL_REF_MASK 0x3
+#define PLL_REF_OSC_25M 0
+#define PLL_REF_OSC_27M 1
+#define PLL_REF_PHY_27M 2
+
+#define PLL_LOCK 31
+#define PLL_PD 7
+
+#define OSC_25M 25000000
+#define OSC_27M 27000000
+
+struct clk_sccg_pll {
+ struct clk_hw hw;
+ void __iomem *base;
+};
+
+#define to_clk_sccg_pll(_hw) container_of(_hw, struct clk_sccg_pll, hw)
+
+static int clk_pll1_is_prepared(struct clk_hw *hw)
+{
+ struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
+ u32 val;
+
+ val = readl_relaxed(pll->base + PLL_CFG0);
+ return (val & (1 << PLL_PD)) ? 0 : 1;
+}
+
+static unsigned long clk_pll1_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
+ u32 val, divf;
+
+ val = readl_relaxed(pll->base + PLL_CFG2);
+ divf = (val >> PLL_DIVF1_SHIFT) & PLL_DIVF_MASK;
+
+ return parent_rate * 2 * (divf + 1);
+}
+
+static long clk_pll1_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ unsigned long parent_rate = *prate;
+ u32 div;
+
+ div = rate / (parent_rate * 2);
+
+ return parent_rate * div * 2;
+}
+
+static int clk_pll1_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
+ u32 val;
+ u32 divf;
+
+ divf = rate / (parent_rate * 2);
+
+ val = readl_relaxed(pll->base + PLL_CFG2);
+ val &= ~(PLL_DIVF_MASK << PLL_DIVF1_SHIFT);
+ val |= (divf - 1) << PLL_DIVF1_SHIFT;
+ writel_relaxed(val, pll->base + PLL_CFG2);
+ /* FIXME PLL lock check */
+
+ return 0;
+}
+
+static int clk_pll1_prepare(struct clk_hw *hw)
+{
+ struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
+ u32 val;
+
+ val = readl_relaxed(pll->base);
+ val &= ~(1 << PLL_PD);
+ writel_relaxed(val, pll->base);
+
+ /* wait for PLL locked */
+
+ return 0;
+}
+
+static void clk_pll1_unprepare(struct clk_hw *hw)
+{
+ struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
+ u32 val;
+
+ val = readl_relaxed(pll->base);
+ val |= (1 << PLL_PD);
+ writel_relaxed(val, pll->base);
+}
+
+static unsigned long clk_pll2_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
+ u32 val, ref, divr1, divf1, divr2, divf2;
+ u64 temp64;
+
+ val = readl_relaxed(pll->base + PLL_CFG0);
+ switch ((val >> PLL_REF_SHIFT) & PLL_REF_MASK) {
+ case PLL_REF_OSC_25M:
+ ref = OSC_25M;
+ break;
+ case PLL_REF_OSC_27M:
+ case PLL_REF_PHY_27M:
+ ref = OSC_27M;
+ break;
+ default:
+ ref = OSC_25M;
+ break;
+ }
+
+ val = readl_relaxed(pll->base + PLL_CFG2);
+ divr1 = (val >> PLL_DIVR1_SHIFT) & PLL_DIVR1_MASK;
+ divr2 = (val >> PLL_DIVR2_SHIFT) & PLL_DIVR2_MASK;
+ divf1 = (val >> PLL_DIVF1_SHIFT) & PLL_DIVF_MASK;
+ divf2 = (val >> PLL_DIVF2_SHIFT) & PLL_DIVF_MASK;
+
+ temp64 = ref * 2;
+ temp64 *= (divf1 + 1) * (divf2 + 1);
+
+ do_div(temp64, (divr1 + 1) * (divr2 + 1));
+
+ return (unsigned long)temp64;
+}
+
+static long clk_pll2_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ u32 div;
+ unsigned long parent_rate = *prate;
+
+ /* FIXME */
+ div = rate / (parent_rate * 2);
+
+ return parent_rate * div * 2;
+}
+
+static int clk_pll2_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ u32 val;
+ u32 divf;
+ struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
+
+ divf = rate / (parent_rate * 2);
+
+ val = readl_relaxed(pll->base + PLL_CFG2);
+ val &= ~(PLL_DIVF_MASK << PLL_DIVF2_SHIFT);
+ val |= (divf - 1) << PLL_DIVF2_SHIFT;
+ writel_relaxed(val, pll->base + PLL_CFG2);
+ /* FIXME PLL lock check */
+
+ return 0;
+}
+
+static const struct clk_ops clk_sccg_pll1_ops = {
+ .is_prepared = clk_pll1_is_prepared,
+ .recalc_rate = clk_pll1_recalc_rate,
+ .round_rate = clk_pll1_round_rate,
+ .set_rate = clk_pll1_set_rate,
+};
+
+static const struct clk_ops clk_sccg_pll2_ops = {
+ .prepare = clk_pll1_prepare,
+ .unprepare = clk_pll1_unprepare,
+ .recalc_rate = clk_pll2_recalc_rate,
+ .round_rate = clk_pll2_round_rate,
+ .set_rate = clk_pll2_set_rate,
+};
+
+struct clk *imx_clk_sccg_pll(const char *name, const char *parent_name,
+ void __iomem *base, enum imx_sccg_pll_type pll_type)
+{
+ struct clk_sccg_pll *pll;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ pll->base = base;
+ init.name = name;
+ switch (pll_type) {
+ case SCCG_PLL1:
+ init.ops = &clk_sccg_pll1_ops;
+ break;
+ case SCCG_PLL2:
+ init.ops = &clk_sccg_pll2_ops;
+ break;
+ }
+
+ init.flags = CLK_SET_RATE_GATE | CLK_GET_RATE_NOCACHE;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ pll->hw.init = &init;
+
+ clk = clk_register(NULL, &pll->hw);
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c
index a634b1185be3..f76cb0b733f1 100644
--- a/drivers/clk/imx/clk.c
+++ b/drivers/clk/imx/clk.c
@@ -7,6 +7,8 @@
DEFINE_SPINLOCK(imx_ccm_lock);
+bool uart_from_osc;
+
void __init imx_check_clocks(struct clk *clks[], unsigned int count)
{
unsigned i;
@@ -111,3 +113,11 @@ static int __init imx_clk_disable_uart(void)
return 0;
}
late_initcall_sync(imx_clk_disable_uart);
+
+static int __init setup_uart_clk(char *uart_rate)
+{
+ uart_from_osc = true;
+ return 1;
+}
+__setup("uart_from_osc", setup_uart_clk);
+
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index 3799ff82a9b4..ce74c115758d 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -3,6 +3,8 @@
#include <linux/spinlock.h>
#include <linux/clk-provider.h>
+#include <linux/clk.h>
+#include <soc/imx/src.h>
extern spinlock_t imx_ccm_lock;
@@ -10,6 +12,10 @@ void imx_check_clocks(struct clk *clks[], unsigned int count);
void imx_register_uart_clocks(struct clk ** const clks[]);
extern void imx_cscmr1_fixup(u32 *val);
+extern struct imx_sema4_mutex *amp_power_mutex;
+extern struct imx_shared_mem *shared_mem;
+extern bool uart_from_osc;
+extern const struct clk_ops clk_frac_divider_ops;
enum imx_pllv1_type {
IMX_PLLV1_IMX1,
@@ -20,12 +26,43 @@ enum imx_pllv1_type {
IMX_PLLV1_IMX35,
};
+enum imx_int_pll_type {
+ PLL_1416X,
+ PLL_1443X,
+};
+
+enum imx_sccg_pll_type {
+ SCCG_PLL1,
+ SCCG_PLL2,
+};
+
+/* NOTE: Rate table should be kept sorted in descending order. */
+struct imx_int_pll_rate_table {
+ unsigned int rate;
+ unsigned int pdiv;
+ unsigned int mdiv;
+ unsigned int sdiv;
+ unsigned int kdiv;
+};
+
+struct imx_int_pll_clk {
+ enum imx_int_pll_type type;
+ const struct imx_int_pll_rate_table *rate_table;
+ int flags;
+};
+
+struct clk *imx_clk_int_pll(const char *name, const char *parent_name, void __iomem *base, const struct imx_int_pll_clk *pll_clk);
+
struct clk *imx_clk_pllv1(enum imx_pllv1_type type, const char *name,
const char *parent, void __iomem *base);
struct clk *imx_clk_pllv2(const char *name, const char *parent,
void __iomem *base);
+struct clk *imx_clk_frac_pll(const char *name, const char *parent_name, void __iomem *base);
+
+struct clk *imx_clk_sccg_pll(const char *name, const char *parent_name, void __iomem *base, enum imx_sccg_pll_type pll_type);
+
enum imx_pllv3_type {
IMX_PLLV3_GENERIC,
IMX_PLLV3_SYS,
@@ -34,11 +71,54 @@ enum imx_pllv3_type {
IMX_PLLV3_AV,
IMX_PLLV3_ENET,
IMX_PLLV3_ENET_IMX7,
+ IMX_PLLV3_AV_IMX7,
+ IMX_PLLV3_PLL2,
+};
+
+/*
+ * frac_divider, found on i.MX7ULP PCC module.
+ * the output clock of the fractional divider is:
+ * Divider output clock = Input clock * (FRAC + 1)
+ * / (DIV + 1)
+ */
+struct clk_frac_divider {
+ struct clk_hw hw;
+ void __iomem *reg;
+ u8 mshift;
+ u8 mwidth;
+ u32 mmask;
+ u8 nshift;
+ u8 nwidth;
+ u32 nmask;
+};
+
+#define MAX_SHARED_CLK_NUMBER 100
+#define SHARED_MEM_MAGIC_NUMBER 0x12345678
+#define MCC_POWER_SHMEM_NUMBER (6)
+
+struct imx_shared_clk {
+ struct clk *self;
+ struct clk *parent;
+ void *m4_clk;
+ void *m4_clk_parent;
+ u8 ca9_enabled;
+ u8 cm4_enabled;
+};
+
+struct imx_shared_mem {
+ u32 ca9_valid;
+ u32 cm4_valid;
+ struct imx_shared_clk imx_clk[MAX_SHARED_CLK_NUMBER];
};
struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
const char *parent_name, void __iomem *base, u32 div_mask);
+struct clk *imx_clk_pllv4(const char *name,
+ const char *parent_name, void __iomem *base);
+struct clk *imx_clk_pllv5(const char *name, const char *parent_name,
+ void __iomem *base);
+
struct clk *clk_register_gate2(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 bit_idx, u8 cgr_val,
@@ -51,6 +131,33 @@ struct clk * imx_obtain_fixed_clock(
struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
void __iomem *reg, u8 shift, u32 exclusive_mask);
+static inline void imx_clk_prepare_enable(struct clk *clk)
+{
+ int ret = clk_prepare_enable(clk);
+
+ if (ret)
+ pr_err("failed to prepare and enable clk %s: %d\n",
+ __clk_get_name(clk), ret);
+}
+
+static inline void imx_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ int ret = clk_set_parent(clk, parent);
+
+ if (ret)
+ pr_err("failed to set parent of clk %s to %s: %d\n",
+ __clk_get_name(clk), __clk_get_name(parent), ret);
+}
+
+static inline void imx_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ int ret = clk_set_rate(clk, rate);
+
+ if (ret)
+ pr_err("failed to set rate of clk %s to %ld: %d\n",
+ __clk_get_name(clk), rate, ret);
+}
+
struct clk *imx_clk_pfd(const char *name, const char *parent_name,
void __iomem *reg, u8 idx);
@@ -62,6 +169,9 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
u8 width, void __iomem *busy_reg, u8 busy_shift,
const char **parent_names, int num_parents);
+struct clk *imx_clk_busy_gate(const char *name, const char *parent,
+ void __iomem *reg, u8 shift);
+
struct clk *imx_clk_fixup_divider(const char *name, const char *parent,
void __iomem *reg, u8 shift, u8 width,
void (*fixup)(u32 *val));
@@ -75,6 +185,14 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate)
return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
}
+static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg,
+ u8 shift, u8 width, const char **parents, int num_parents)
+{
+ return clk_register_mux(NULL, name, parents, num_parents,
+ CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg,
+ shift, width, CLK_MUX_READ_ONLY, &imx_ccm_lock);
+}
+
static inline struct clk *imx_clk_fixed_factor(const char *name,
const char *parent, unsigned int mult, unsigned int div)
{
@@ -85,10 +203,19 @@ static inline struct clk *imx_clk_fixed_factor(const char *name,
static inline struct clk *imx_clk_divider(const char *name, const char *parent,
void __iomem *reg, u8 shift, u8 width)
{
- return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT,
+ return clk_register_divider(NULL, name, parent,
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE,
reg, shift, width, 0, &imx_ccm_lock);
}
+static inline struct clk *imx_clk_divider2(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, u8 width)
+{
+ return clk_register_divider(NULL, name, parent,
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE | CLK_OPS_PARENT_ENABLE,
+ reg, shift, width, CLK_DIVIDER_ROUND_CLOSEST, &imx_ccm_lock);
+}
+
static inline struct clk *imx_clk_divider_flags(const char *name,
const char *parent, void __iomem *reg, u8 shift, u8 width,
unsigned long flags)
@@ -97,14 +224,6 @@ static inline struct clk *imx_clk_divider_flags(const char *name,
reg, shift, width, 0, &imx_ccm_lock);
}
-static inline struct clk *imx_clk_divider2(const char *name, const char *parent,
- void __iomem *reg, u8 shift, u8 width)
-{
- return clk_register_divider(NULL, name, parent,
- CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
- reg, shift, width, 0, &imx_ccm_lock);
-}
-
static inline struct clk *imx_clk_gate(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
@@ -122,7 +241,15 @@ static inline struct clk *imx_clk_gate_dis(const char *name, const char *parent,
static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
- return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+ return clk_register_gate2(NULL, name, parent,
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, reg,
+ shift, 0x3, 0, &imx_ccm_lock, NULL);
+}
+
+static inline struct clk *imx_clk_gate2_flags(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, unsigned long flags)
+{
+ return clk_register_gate2(NULL, name, parent, flags, reg,
shift, 0x3, 0, &imx_ccm_lock, NULL);
}
@@ -130,7 +257,8 @@ static inline struct clk *imx_clk_gate2_shared(const char *name,
const char *parent, void __iomem *reg, u8 shift,
unsigned int *share_count)
{
- return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+ return clk_register_gate2(NULL, name, parent,
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, reg,
shift, 0x3, 0, &imx_ccm_lock, share_count);
}
@@ -139,8 +267,8 @@ static inline struct clk *imx_clk_gate2_shared2(const char *name,
unsigned int *share_count)
{
return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT |
- CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0,
- &imx_ccm_lock, share_count);
+ CLK_SET_RATE_GATE | CLK_OPS_PARENT_ENABLE,
+ reg, shift, 0x3, 0, &imx_ccm_lock, share_count);
}
static inline struct clk *imx_clk_gate2_cgr(const char *name,
@@ -153,7 +281,17 @@ static inline struct clk *imx_clk_gate2_cgr(const char *name,
static inline struct clk *imx_clk_gate3(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
- return clk_register_gate(NULL, name, parent,
+ /*
+ * per design team's suggestion, clk root is NOT consuming
+ * much power, and clk root enable/disable does NOT have domain
+ * control, so they suggest to leave clk root always on when
+ * M4 is enabled.
+ */
+ if (imx_src_is_m4_enabled())
+ return clk_register_fixed_factor(NULL, name, parent,
+ CLK_SET_RATE_PARENT, 1, 1);
+ else
+ return clk_register_gate(NULL, name, parent,
CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, 0, &imx_ccm_lock);
}
@@ -162,16 +300,24 @@ static inline struct clk *imx_clk_gate4(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
return clk_register_gate2(NULL, name, parent,
- CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE | CLK_OPS_PARENT_ENABLE,
reg, shift, 0x3, 0, &imx_ccm_lock, NULL);
}
+static inline struct clk *imx_clk_mux_bus(const char *name, void __iomem *reg,
+ u8 shift, u8 width, const char **parents, int num_parents)
+{
+ return clk_register_mux(NULL, name, parents, num_parents,
+ CLK_SET_RATE_NO_REPARENT,
+ reg, shift, width, 0, &imx_ccm_lock);
+}
+
static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
u8 shift, u8 width, const char **parents, int num_parents)
{
return clk_register_mux(NULL, name, parents, num_parents,
- CLK_SET_RATE_NO_REPARENT, reg, shift,
- width, 0, &imx_ccm_lock);
+ CLK_SET_RATE_NO_REPARENT | CLK_SET_PARENT_GATE,
+ reg, shift, width, 0, &imx_ccm_lock);
}
static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg,
@@ -187,12 +333,43 @@ static inline struct clk *imx_clk_mux_flags(const char *name,
int num_parents, unsigned long flags)
{
return clk_register_mux(NULL, name, parents, num_parents,
- flags | CLK_SET_RATE_NO_REPARENT, reg, shift, width, 0,
- &imx_ccm_lock);
+ flags | CLK_SET_RATE_NO_REPARENT | CLK_SET_PARENT_GATE,
+ reg, shift, width, 0, &imx_ccm_lock);
+}
+
+static inline struct clk *imx_clk_mux_flags_bus(const char *name,
+ void __iomem *reg, u8 shift, u8 width, const char **paretns,
+ int num_parents, unsigned long flags)
+{
+ return clk_register_mux(NULL, name, paretns, num_parents,
+ flags | CLK_SET_RATE_NO_REPARENT, reg, shift,
+ width, 0, &imx_ccm_lock);
+}
+
+static inline struct clk *imx_clk_mux_glitchless(const char *name,
+ void __iomem *reg, u8 shift, u8 width, const char **parents,
+ int num_parents)
+{
+ return clk_register_mux(NULL, name, parents, num_parents,
+ CLK_SET_RATE_NO_REPARENT, reg, shift,
+ width, 0, &imx_ccm_lock);
}
struct clk *imx_clk_cpu(const char *name, const char *parent_name,
struct clk *div, struct clk *mux, struct clk *pll,
struct clk *step);
+int imx_update_shared_mem(struct clk_hw *hw, bool enable);
+
+static inline int clk_on_imx6sx(void)
+{
+ return of_machine_is_compatible("fsl,imx6sx");
+}
+
+struct clk *imx_clk_composite(const char *name, const char **parent_name,
+ int num_parents, bool mux_present, bool rate_present,
+ bool gate_present, void __iomem *reg);
+
+struct clk *imx_clk_pfdv2(const char *name, const char *parent_name,
+ void __iomem *reg, u8 idx);
#endif
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index e2c6e43cf8ca..3b2555c9a6f8 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -532,6 +532,15 @@ config CLKSRC_IMX_GPT
depends on ARM && CLKDEV_LOOKUP
select CLKSRC_MMIO
+config CLKSRC_IMX_TPM
+ bool "Clocksource using i.MX TPM" if COMPILE_TEST
+ depends on ARM && CLKDEV_LOOKUP && GENERIC_CLOCKEVENTS
+ select CLKSRC_MMIO
+
+config CLKSRC_IMX_SYS_CNT
+ bool "Clocksource using i.MX system counter timer"
+ depends on ARM_ARCH_TIMER
+
config CLKSRC_ST_LPC
bool "Low power clocksource found in the LPC" if COMPILE_TEST
select CLKSRC_OF if OF
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index cf87f407f1ad..4837c88d470b 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -63,6 +63,8 @@ obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o
obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o
obj-$(CONFIG_CLKSRC_TANGO_XTAL) += tango_xtal.o
obj-$(CONFIG_CLKSRC_IMX_GPT) += timer-imx-gpt.o
+obj-$(CONFIG_CLKSRC_IMX_TPM) += timer-imx-tpm.o
+obj-$(CONFIG_CLKSRC_IMX_SYS_CNT) += timer-imx-sysctr.o
obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o
obj-$(CONFIG_H8300_TMR8) += h8300_timer8.o
obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o
diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c
index f595460bfc58..d65387218418 100644
--- a/drivers/clocksource/timer-imx-gpt.c
+++ b/drivers/clocksource/timer-imx-gpt.c
@@ -556,4 +556,7 @@ CLOCKSOURCE_OF_DECLARE(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx6sll_timer, "fsl,imx6sll-gpt", imx6dl_timer_init_dt);
CLOCKSOURCE_OF_DECLARE(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(imx6ul_timer, "fsl,imx6ul-gpt", imx6dl_timer_init_dt);
+CLOCKSOURCE_OF_DECLARE(mx7d_timer, "fsl,imx7d-gpt", imx6dl_timer_init_dt);
diff --git a/drivers/clocksource/timer-imx-sysctr.c b/drivers/clocksource/timer-imx-sysctr.c
new file mode 100644
index 000000000000..aefaba7b39ad
--- /dev/null
+++ b/drivers/clocksource/timer-imx-sysctr.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/delay.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/sched_clock.h>
+
+#define CNTCV_LO 0x8
+#define CNTCV_HI 0xc
+#define CMPCV_LO 0x20
+#define CMPCV_HI 0x24
+#define CMPCR 0x2c
+
+#define SYS_CTR_EN 0x1
+#define SYS_CTR_IRQ_MASK 0x2
+
+static void __iomem *sys_ctr_rd_base;
+static void __iomem *sys_ctr_cmp_base;
+static struct clock_event_device clockevent_sysctr;
+
+static inline void sysctr_timer_enable(bool enable)
+{
+ u32 val;
+
+ val = readl(sys_ctr_cmp_base + CMPCR);
+ val &= ~SYS_CTR_EN;
+ if (enable)
+ val |= SYS_CTR_EN;
+
+ writel(val, sys_ctr_cmp_base + CMPCR);
+}
+
+static void sysctr_irq_acknowledge(void)
+{
+ u32 val;
+
+ /* clear th enable bit(EN=0) to clear the ISTAT */
+ val = readl(sys_ctr_cmp_base + CMPCR);
+ val &= ~SYS_CTR_EN;
+ writel(val, sys_ctr_cmp_base + CMPCR);
+}
+
+static inline u64 sysctr_read_counter(void)
+{
+ u32 cnt_hi, tmp_hi, cnt_lo;
+
+ do {
+ cnt_hi = readl_relaxed(sys_ctr_rd_base + CNTCV_HI);
+ cnt_lo = readl_relaxed(sys_ctr_rd_base + CNTCV_LO);
+ tmp_hi = readl_relaxed(sys_ctr_rd_base + CNTCV_HI);
+ } while (tmp_hi != cnt_hi);
+
+ return ((u64) cnt_hi << 32) | cnt_lo;
+}
+
+static u64 notrace sysctr_read_sched_clock(void)
+{
+ return sysctr_read_counter();
+}
+
+static cycle_t sysctr_clocksourc_read(struct clocksource *cs)
+{
+ return sysctr_read_counter();
+}
+
+static int __init sysctr_clocksource_init(unsigned int rate)
+{
+ sched_clock_register(sysctr_read_sched_clock, 56, rate);
+ return clocksource_mmio_init(sys_ctr_rd_base, "imx sysctr",
+ rate, 200, 56, sysctr_clocksourc_read);
+}
+
+static int sysctr_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ u32 cmp_hi, cmp_lo;
+ u64 next;
+
+ sysctr_timer_enable(false);
+
+ next = sysctr_read_counter();
+
+ next += delta;
+
+ cmp_hi = (next >> 32) & 0x00fffff;
+ cmp_lo = next & 0xffffffff;
+
+ writel_relaxed(cmp_hi, sys_ctr_cmp_base + CMPCV_HI);
+ writel_relaxed(cmp_lo, sys_ctr_cmp_base + CMPCV_LO);
+
+ sysctr_timer_enable(true);
+
+ return 0;
+}
+
+static int sysctr_set_state_oneshot(struct clock_event_device *evt)
+{
+ /* enable timer */
+ sysctr_timer_enable(true);
+
+ return 0;
+}
+
+static int sysctr_set_state_shutdown(struct clock_event_device *evt)
+{
+ /* disable the timer */
+ sysctr_timer_enable(false);
+
+ return 0;
+}
+
+static irqreturn_t sysctr_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = &clockevent_sysctr;
+
+ sysctr_irq_acknowledge();
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static struct clock_event_device clockevent_sysctr = {
+ .name = "i.MX system counter timer",
+ .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ,
+ .set_state_oneshot = sysctr_set_state_oneshot,
+ .set_next_event = sysctr_set_next_event,
+ .set_state_shutdown = sysctr_set_state_shutdown,
+ .rating = 200,
+};
+
+static struct irqaction sysctr_timer_irq = {
+ .name = "iMX system counter timer",
+ .flags = IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = sysctr_timer_interrupt,
+ .dev_id = &clockevent_sysctr,
+};
+
+static int __init sysctr_clockevent_init(unsigned long rate, int irq)
+{
+ setup_irq(irq, &sysctr_timer_irq);
+
+ clockevent_sysctr.cpumask = cpumask_of(0);
+ clockevent_sysctr.irq = irq;
+ clockevents_config_and_register(&clockevent_sysctr,
+ rate, 0xff, 0x7fffffff);
+
+ return 0;
+}
+
+static int __init sysctr_timer_init(struct device_node *np)
+{
+ u32 rate;
+ int irq;
+
+ pr_info("system counter timer init\n");
+ sys_ctr_rd_base = of_iomap(np, 0);
+ BUG_ON(!sys_ctr_rd_base);
+
+ sys_ctr_cmp_base = of_iomap(np, 1);
+ BUG_ON(!sys_ctr_cmp_base);
+
+ /*
+ * the purpose of this driver is to provide a global timer,
+ * So only use one compare frame, request frame0's irq only.
+ */
+ irq = irq_of_parse_and_map(np, 0);
+
+ if (of_property_read_u32(np, "clock-frequency", &rate))
+ return -EINVAL;
+
+ sysctr_clocksource_init(rate);
+ sysctr_clockevent_init(rate, irq);
+
+ return 0;
+}
+CLOCKSOURCE_OF_DECLARE(imx8m, "nxp,sysctr-timer", sysctr_timer_init);
diff --git a/drivers/clocksource/timer-imx-tpm.c b/drivers/clocksource/timer-imx-tpm.c
new file mode 100644
index 000000000000..92001e5a4cef
--- /dev/null
+++ b/drivers/clocksource/timer-imx-tpm.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/sched_clock.h>
+
+#define TPM_SC 0x10
+#define TPM_SC_CMOD_INC_PER_CNT (0x1 << 3)
+#define TPM_SC_CMOD_DIV_DEFAULT 0x3
+#define TPM_CNT 0x14
+#define TPM_MOD 0x18
+#define TPM_STATUS 0x1c
+#define TPM_STATUS_CH0F BIT(0)
+#define TPM_C0SC 0x20
+#define TPM_C0SC_CHIE BIT(6)
+#define TPM_C0SC_MODE_SHIFT 2
+#define TPM_C0SC_MODE_MASK 0x3c
+#define TPM_C0SC_MODE_SW_COMPARE 0x4
+#define TPM_C0V 0x24
+
+static void __iomem *timer_base;
+static struct clock_event_device clockevent_tpm;
+
+static inline void tpm_timer_disable(void)
+{
+ unsigned int val;
+
+ /* channel disable */
+ val = readl(timer_base + TPM_C0SC);
+ val &= ~(TPM_C0SC_MODE_MASK | TPM_C0SC_CHIE);
+ writel(val, timer_base + TPM_C0SC);
+}
+
+static inline void tpm_timer_enable(void)
+{
+ unsigned int val;
+
+ /* channel enabled in sw compare mode */
+ val = readl(timer_base + TPM_C0SC);
+ val |= (TPM_C0SC_MODE_SW_COMPARE << TPM_C0SC_MODE_SHIFT) |
+ TPM_C0SC_CHIE;
+ writel(val, timer_base + TPM_C0SC);
+}
+
+static inline void tpm_irq_acknowledge(void)
+{
+ writel(TPM_STATUS_CH0F, timer_base + TPM_STATUS);
+}
+
+static struct delay_timer tpm_delay_timer;
+
+static inline unsigned long tpm_read_counter(void)
+{
+ return readl(timer_base + TPM_CNT);
+}
+
+static unsigned long tpm_read_current_timer(void)
+{
+ return tpm_read_counter();
+}
+
+static u64 notrace tpm_read_sched_clock(void)
+{
+ return tpm_read_counter();
+}
+
+static int __init tpm_clocksource_init(unsigned long rate)
+{
+ tpm_delay_timer.read_current_timer = &tpm_read_current_timer;
+ tpm_delay_timer.freq = rate;
+ register_current_timer_delay(&tpm_delay_timer);
+
+ sched_clock_register(tpm_read_sched_clock, 32, rate);
+
+ return clocksource_mmio_init(timer_base + TPM_CNT, "imx-tpm",
+ rate, 200, 32, clocksource_mmio_readl_up);
+}
+
+static int tpm_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ unsigned long next, now;
+
+ next = tpm_read_counter();
+ next += delta;
+ writel(next, timer_base + TPM_C0V);
+ now = tpm_read_counter();
+
+ /*
+ * NOTE: We observed in a very small probability, the bus fabric
+ * contention between GPU and A7 may results a few cycles delay
+ * of writing CNT registers which may cause the min_delta event got
+ * missed, so we need add a ETIME check here in case it happened.
+ */
+ return (int)(next - now) <= 0 ? -ETIME : 0;
+}
+
+static int tpm_set_state_oneshot(struct clock_event_device *evt)
+{
+ tpm_timer_enable();
+
+ return 0;
+}
+
+static int tpm_set_state_shutdown(struct clock_event_device *evt)
+{
+ tpm_timer_disable();
+
+ return 0;
+}
+
+static irqreturn_t tpm_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ tpm_irq_acknowledge();
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static struct clock_event_device clockevent_tpm = {
+ .name = "i.MX7ULP TPM Timer",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .set_state_oneshot = tpm_set_state_oneshot,
+ .set_next_event = tpm_set_next_event,
+ .set_state_shutdown = tpm_set_state_shutdown,
+ .rating = 200,
+};
+
+static int __init tpm_clockevent_init(unsigned long rate, int irq)
+{
+ int ret;
+
+ ret = request_irq(irq, tpm_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
+ "i.MX7ULP TPM Timer", &clockevent_tpm);
+
+ clockevent_tpm.cpumask = cpumask_of(0);
+ clockevent_tpm.irq = irq;
+ clockevents_config_and_register(&clockevent_tpm,
+ rate, 300, 0xfffffffe);
+
+ return ret;
+}
+
+static int __init tpm_timer_init(struct device_node *np)
+{
+ struct clk *ipg, *per;
+ int irq, ret;
+ u32 rate;
+
+ timer_base = of_iomap(np, 0);
+ if (!timer_base) {
+ pr_err("tpm: failed to get base address\n");
+ return -ENXIO;
+ }
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (!irq) {
+ pr_err("tpm: failed to get irq\n");
+ ret = -ENOENT;
+ goto err_iomap;
+ }
+
+ ipg = of_clk_get_by_name(np, "ipg");
+ per = of_clk_get_by_name(np, "per");
+ if (IS_ERR(ipg) || IS_ERR(per)) {
+ pr_err("tpm: failed to get igp or per clk\n");
+ ret = -ENODEV;
+ goto err_clk_get;
+ }
+
+ /* enable clk before accessing registers */
+ ret = clk_prepare_enable(ipg);
+ if (ret) {
+ pr_err("tpm: ipg clock enable failed (%d)\n", ret);
+ goto err_clk_get;
+ }
+
+ ret = clk_prepare_enable(per);
+ if (ret) {
+ pr_err("tpm: per clock enable failed (%d)\n", ret);
+ goto err_per_clk_enable;
+ }
+
+ /*
+ * Initialize tpm module to a known state
+ * 1) Counter disabled
+ * 2) TPM counter operates in up counting mode
+ * 3) Timer Overflow Interrupt disabled
+ * 4) Channel0 disabled
+ * 5) DMA transfers disabled
+ */
+ writel(0, timer_base + TPM_SC);
+ writel(0, timer_base + TPM_CNT);
+ writel(0, timer_base + TPM_C0SC);
+
+ /* increase per cnt, div 8 by default */
+ writel(TPM_SC_CMOD_INC_PER_CNT | TPM_SC_CMOD_DIV_DEFAULT,
+ timer_base + TPM_SC);
+
+ /* set MOD register to maximum for free running mode */
+ writel(0xffffffff, timer_base + TPM_MOD);
+
+ rate = clk_get_rate(per) >> 3;
+ ret = tpm_clocksource_init(rate);
+ if (ret)
+ goto err_per_clk_enable;
+
+ ret = tpm_clockevent_init(rate, irq);
+ if (ret)
+ goto err_per_clk_enable;
+
+ return 0;
+
+err_per_clk_enable:
+ clk_disable_unprepare(ipg);
+err_clk_get:
+ clk_put(per);
+ clk_put(ipg);
+err_iomap:
+ iounmap(timer_base);
+
+ return ret;
+}
+CLOCKSOURCE_OF_DECLARE(imx7ulp, "fsl,imx7ulp-tpm", tpm_timer_init);
+
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index cac26fb22891..a8909df6ac57 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -112,6 +112,16 @@ config CPU_FREQ_DEFAULT_GOV_SCHEDUTIL
have a look at the help section of that governor. The fallback
governor will be 'performance'.
+config CPU_FREQ_DEFAULT_GOV_INTERACTIVE
+ bool "interactive"
+ select CPU_FREQ_GOV_INTERACTIVE
+ select CPU_FREQ_GOV_PERFORMANCE
+ help
+ Use the CPUFreq governor 'interactive' as default. This allows
+ you to get a full dynamic cpu frequency capable system by simply
+ loading your cpufreq low-level hardware driver, using the
+ 'interactive' governor for latency-sensitive workloads.
+
endchoice
config CPU_FREQ_GOV_PERFORMANCE
@@ -210,6 +220,26 @@ config CPU_FREQ_GOV_SCHEDUTIL
If in doubt, say N.
+config CPU_FREQ_GOV_INTERACTIVE
+ tristate "'interactive' cpufreq policy governor"
+ depends on CPU_FREQ
+ select CPU_FREQ_GOV_ATTR_SET
+ select IRQ_WORK
+ help
+ 'interactive' - This driver adds a dynamic cpufreq policy governor
+ designed for latency-sensitive workloads.
+
+ This governor attempts to reduce the latency of clock
+ increases so that the system is more responsive to
+ interactive workloads.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cpufreq_interactive.
+
+ For details, take a look at linux/Documentation/cpu-freq.
+
+ If in doubt, say N.
+
comment "CPU frequency scaling drivers"
config CPUFREQ_DT
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index bc3917d6015a..7d6290de3af2 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -60,6 +60,38 @@ config ARM_IMX6Q_CPUFREQ
If in doubt, say N.
+config ARM_IMX7D_CPUFREQ
+ tristate "Freescale i.MX7 cpufreq support"
+ depends on ARCH_MXC
+ help
+ This adds cpufreq driver support for Freescale i.MX7 series SoCs.
+
+ If in doubt, say N.
+
+config ARM_IMX7ULP_CPUFREQ
+ tristate "NXP i.MX7ULP cpufreq support"
+ depends on ARCH_MXC
+ help
+ This adds cpufreq driver support for NXP i.MX7ULP series SoCs.
+
+ If in doubt, say N.
+
+config ARM_IMX8_CPUFREQ
+ tristate "NXP i.MX8 cpufreq support"
+ select PM_OPP
+ help
+ This adds cpufreq driver support for NXP i.MX8 series SoCs.
+
+ If in doubt, say N.
+
+config ARM_IMX8MQ_CPUFREQ
+ tristate "NXP i.MX8MQ cpufreq support"
+ select PM_OPP
+ help
+ This adds cpufreq driver support for NXP i.MX8MQ series SoCs.
+
+ If in doubt, say N.
+
config ARM_INTEGRATOR
tristate "CPUfreq driver for ARM Integrator CPUs"
depends on ARCH_INTEGRATOR
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 0a9b6a093646..1926b6a5567f 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o
obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o
obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o
obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o
+obj-$(CONFIG_CPU_FREQ_GOV_INTERACTIVE) += cpufreq_interactive.o
obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o
obj-$(CONFIG_CPU_FREQ_GOV_ATTR_SET) += cpufreq_governor_attr_set.o
@@ -56,6 +57,10 @@ obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o
obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
+obj-$(CONFIG_ARM_IMX7D_CPUFREQ) += imx7-cpufreq.o
+obj-$(CONFIG_ARM_IMX7ULP_CPUFREQ) += imx7ulp-cpufreq.o
+obj-$(CONFIG_ARM_IMX8_CPUFREQ) += imx8-cpufreq.o
+obj-$(CONFIG_ARM_IMX8MQ_CPUFREQ) += imx8mq-cpufreq.o
obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o
obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
obj-$(CONFIG_ARM_MT8173_CPUFREQ) += mt8173-cpufreq.o
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index ef1037e9c92b..3196ed9c1c0a 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -70,14 +70,6 @@ static ssize_t show_##file_name \
return sprintf(buf, "%u\n", dbs_data->file_name); \
}
-#define gov_attr_ro(_name) \
-static struct governor_attr _name = \
-__ATTR(_name, 0444, show_##_name, NULL)
-
-#define gov_attr_rw(_name) \
-static struct governor_attr _name = \
-__ATTR(_name, 0644, show_##_name, store_##_name)
-
/* Common to all CPUs of a policy */
struct policy_dbs_info {
struct cpufreq_policy *policy;
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
new file mode 100644
index 000000000000..3ff6f6a599c8
--- /dev/null
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -0,0 +1,1365 @@
+/*
+ * drivers/cpufreq/cpufreq_interactive.c
+ *
+ * Copyright (C) 2010-2016 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Author: Mike Chan (mike@android.com)
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/cpufreq.h>
+#include <linux/irq_work.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/sched/rt.h>
+#include <linux/tick.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/cpufreq_interactive.h>
+
+/* Separate instance required for each 'interactive' directory in sysfs */
+struct interactive_tunables {
+ struct gov_attr_set attr_set;
+
+ /* Hi speed to bump to from lo speed when load burst (default max) */
+ unsigned int hispeed_freq;
+
+ /* Go to hi speed when CPU load at or above this value. */
+#define DEFAULT_GO_HISPEED_LOAD 99
+ unsigned long go_hispeed_load;
+
+ /* Target load. Lower values result in higher CPU speeds. */
+ spinlock_t target_loads_lock;
+ unsigned int *target_loads;
+ int ntarget_loads;
+
+ /*
+ * The minimum amount of time to spend at a frequency before we can ramp
+ * down.
+ */
+#define DEFAULT_MIN_SAMPLE_TIME (80 * USEC_PER_MSEC)
+ unsigned long min_sample_time;
+
+ /* The sample rate of the timer used to increase frequency */
+ unsigned long sampling_rate;
+
+ /*
+ * Wait this long before raising speed above hispeed, by default a
+ * single timer interval.
+ */
+ spinlock_t above_hispeed_delay_lock;
+ unsigned int *above_hispeed_delay;
+ int nabove_hispeed_delay;
+
+ /* Non-zero means indefinite speed boost active */
+ int boost;
+ /* Duration of a boot pulse in usecs */
+ int boostpulse_duration;
+ /* End time of boost pulse in ktime converted to usecs */
+ u64 boostpulse_endtime;
+ bool boosted;
+
+ /*
+ * Max additional time to wait in idle, beyond sampling_rate, at speeds
+ * above minimum before wakeup to reduce speed, or -1 if unnecessary.
+ */
+#define DEFAULT_TIMER_SLACK (4 * DEFAULT_SAMPLING_RATE)
+ unsigned long timer_slack_delay;
+ unsigned long timer_slack;
+ bool io_is_busy;
+};
+
+/* Separate instance required for each 'struct cpufreq_policy' */
+struct interactive_policy {
+ struct cpufreq_policy *policy;
+ struct interactive_tunables *tunables;
+ struct list_head tunables_hook;
+};
+
+/* Separate instance required for each CPU */
+struct interactive_cpu {
+ struct update_util_data update_util;
+ struct interactive_policy *ipolicy;
+
+ struct irq_work irq_work;
+ u64 last_sample_time;
+ bool work_in_progress;
+
+ struct rw_semaphore enable_sem;
+ struct timer_list slack_timer;
+
+ spinlock_t load_lock; /* protects the next 4 fields */
+ u64 time_in_idle;
+ u64 time_in_idle_timestamp;
+ u64 cputime_speedadj;
+ u64 cputime_speedadj_timestamp;
+
+ spinlock_t target_freq_lock; /*protects target freq */
+ unsigned int target_freq;
+
+ unsigned int floor_freq;
+ u64 pol_floor_val_time; /* policy floor_validate_time */
+ u64 loc_floor_val_time; /* per-cpu floor_validate_time */
+ u64 pol_hispeed_val_time; /* policy hispeed_validate_time */
+ u64 loc_hispeed_val_time; /* per-cpu hispeed_validate_time */
+};
+
+static DEFINE_PER_CPU(struct interactive_cpu, interactive_cpu);
+
+/* Realtime thread handles frequency scaling */
+static struct task_struct *speedchange_task;
+static cpumask_t speedchange_cpumask;
+static spinlock_t speedchange_cpumask_lock;
+
+/* Target load. Lower values result in higher CPU speeds. */
+#define DEFAULT_TARGET_LOAD 90
+static unsigned int default_target_loads[] = {DEFAULT_TARGET_LOAD};
+
+#define DEFAULT_SAMPLING_RATE (20 * USEC_PER_MSEC)
+#define DEFAULT_ABOVE_HISPEED_DELAY DEFAULT_SAMPLING_RATE
+static unsigned int default_above_hispeed_delay[] = {
+ DEFAULT_ABOVE_HISPEED_DELAY
+};
+
+/* Iterate over interactive policies for tunables */
+#define for_each_ipolicy(__ip) \
+ list_for_each_entry(__ip, &tunables->attr_set.policy_list, tunables_hook)
+
+static struct interactive_tunables *global_tunables;
+static DEFINE_MUTEX(global_tunables_lock);
+
+static inline void update_slack_delay(struct interactive_tunables *tunables)
+{
+ tunables->timer_slack_delay = usecs_to_jiffies(tunables->timer_slack +
+ tunables->sampling_rate);
+}
+
+static bool timer_slack_required(struct interactive_cpu *icpu)
+{
+ struct interactive_policy *ipolicy = icpu->ipolicy;
+ struct interactive_tunables *tunables = ipolicy->tunables;
+
+ if (tunables->timer_slack < 0)
+ return false;
+
+ if (icpu->target_freq > ipolicy->policy->min)
+ return true;
+
+ return false;
+}
+
+static void gov_slack_timer_start(struct interactive_cpu *icpu, int cpu)
+{
+ struct interactive_tunables *tunables = icpu->ipolicy->tunables;
+
+ icpu->slack_timer.expires = jiffies + tunables->timer_slack_delay;
+ add_timer_on(&icpu->slack_timer, cpu);
+}
+
+static void gov_slack_timer_modify(struct interactive_cpu *icpu)
+{
+ struct interactive_tunables *tunables = icpu->ipolicy->tunables;
+
+ mod_timer(&icpu->slack_timer, jiffies + tunables->timer_slack_delay);
+}
+
+static void slack_timer_resched(struct interactive_cpu *icpu, int cpu,
+ bool modify)
+{
+ struct interactive_tunables *tunables = icpu->ipolicy->tunables;
+ unsigned long flags;
+
+ spin_lock_irqsave(&icpu->load_lock, flags);
+
+ icpu->time_in_idle = get_cpu_idle_time(cpu,
+ &icpu->time_in_idle_timestamp,
+ tunables->io_is_busy);
+ icpu->cputime_speedadj = 0;
+ icpu->cputime_speedadj_timestamp = icpu->time_in_idle_timestamp;
+
+ if (timer_slack_required(icpu)) {
+ if (modify)
+ gov_slack_timer_modify(icpu);
+ else
+ gov_slack_timer_start(icpu, cpu);
+ }
+
+ spin_unlock_irqrestore(&icpu->load_lock, flags);
+}
+
+static unsigned int
+freq_to_above_hispeed_delay(struct interactive_tunables *tunables,
+ unsigned int freq)
+{
+ unsigned long flags;
+ unsigned int ret;
+ int i;
+
+ spin_lock_irqsave(&tunables->above_hispeed_delay_lock, flags);
+
+ for (i = 0; i < tunables->nabove_hispeed_delay - 1 &&
+ freq >= tunables->above_hispeed_delay[i + 1]; i += 2)
+ ;
+
+ ret = tunables->above_hispeed_delay[i];
+ spin_unlock_irqrestore(&tunables->above_hispeed_delay_lock, flags);
+
+ return ret;
+}
+
+static unsigned int freq_to_targetload(struct interactive_tunables *tunables,
+ unsigned int freq)
+{
+ unsigned long flags;
+ unsigned int ret;
+ int i;
+
+ spin_lock_irqsave(&tunables->target_loads_lock, flags);
+
+ for (i = 0; i < tunables->ntarget_loads - 1 &&
+ freq >= tunables->target_loads[i + 1]; i += 2)
+ ;
+
+ ret = tunables->target_loads[i];
+ spin_unlock_irqrestore(&tunables->target_loads_lock, flags);
+ return ret;
+}
+
+/*
+ * If increasing frequencies never map to a lower target load then
+ * choose_freq() will find the minimum frequency that does not exceed its
+ * target load given the current load.
+ */
+static unsigned int choose_freq(struct interactive_cpu *icpu,
+ unsigned int loadadjfreq)
+{
+ struct cpufreq_policy *policy = icpu->ipolicy->policy;
+ struct cpufreq_frequency_table *freq_table = policy->freq_table;
+ unsigned int prevfreq, freqmin = 0, freqmax = UINT_MAX, tl;
+ unsigned int freq = policy->cur;
+ int index;
+
+ do {
+ prevfreq = freq;
+ tl = freq_to_targetload(icpu->ipolicy->tunables, freq);
+
+ /*
+ * Find the lowest frequency where the computed load is less
+ * than or equal to the target load.
+ */
+
+ index = cpufreq_frequency_table_target(policy, loadadjfreq / tl,
+ CPUFREQ_RELATION_L);
+ if (index < 0)
+ break;
+
+ freq = freq_table[index].frequency;
+
+ if (freq > prevfreq) {
+ /* The previous frequency is too low */
+ freqmin = prevfreq;
+
+ if (freq < freqmax)
+ continue;
+
+ /* Find highest frequency that is less than freqmax */
+ index = cpufreq_frequency_table_target(policy,
+ freqmax - 1, CPUFREQ_RELATION_H);
+ if (index < 0)
+ break;
+
+ freq = freq_table[index].frequency;
+
+ if (freq == freqmin) {
+ /*
+ * The first frequency below freqmax has already
+ * been found to be too low. freqmax is the
+ * lowest speed we found that is fast enough.
+ */
+ freq = freqmax;
+ break;
+ }
+ } else if (freq < prevfreq) {
+ /* The previous frequency is high enough. */
+ freqmax = prevfreq;
+
+ if (freq > freqmin)
+ continue;
+
+ /* Find lowest frequency that is higher than freqmin */
+ index = cpufreq_frequency_table_target(policy,
+ freqmin + 1, CPUFREQ_RELATION_L);
+ if (index < 0)
+ break;
+
+ freq = freq_table[index].frequency;
+
+ /*
+ * If freqmax is the first frequency above
+ * freqmin then we have already found that
+ * this speed is fast enough.
+ */
+ if (freq == freqmax)
+ break;
+ }
+
+ /* If same frequency chosen as previous then done. */
+ } while (freq != prevfreq);
+
+ return freq;
+}
+
+static u64 update_load(struct interactive_cpu *icpu, int cpu)
+{
+ struct interactive_tunables *tunables = icpu->ipolicy->tunables;
+ unsigned int delta_idle, delta_time;
+ u64 now_idle, now, active_time;
+
+ now_idle = get_cpu_idle_time(cpu, &now, tunables->io_is_busy);
+ delta_idle = (unsigned int)(now_idle - icpu->time_in_idle);
+ delta_time = (unsigned int)(now - icpu->time_in_idle_timestamp);
+
+ if (delta_time <= delta_idle)
+ active_time = 0;
+ else
+ active_time = delta_time - delta_idle;
+
+ icpu->cputime_speedadj += active_time * icpu->ipolicy->policy->cur;
+
+ icpu->time_in_idle = now_idle;
+ icpu->time_in_idle_timestamp = now;
+
+ return now;
+}
+
+/* Re-evaluate load to see if a frequency change is required or not */
+static void eval_target_freq(struct interactive_cpu *icpu)
+{
+ struct interactive_tunables *tunables = icpu->ipolicy->tunables;
+ struct cpufreq_policy *policy = icpu->ipolicy->policy;
+ struct cpufreq_frequency_table *freq_table = policy->freq_table;
+ u64 cputime_speedadj, now, max_fvtime;
+ unsigned int new_freq, loadadjfreq, index, delta_time;
+ unsigned long flags;
+ int cpu_load;
+ int cpu = smp_processor_id();
+
+ spin_lock_irqsave(&icpu->load_lock, flags);
+ now = update_load(icpu, smp_processor_id());
+ delta_time = (unsigned int)(now - icpu->cputime_speedadj_timestamp);
+ cputime_speedadj = icpu->cputime_speedadj;
+ spin_unlock_irqrestore(&icpu->load_lock, flags);
+
+ if (WARN_ON_ONCE(!delta_time))
+ return;
+
+ spin_lock_irqsave(&icpu->target_freq_lock, flags);
+ do_div(cputime_speedadj, delta_time);
+ loadadjfreq = (unsigned int)cputime_speedadj * 100;
+ cpu_load = loadadjfreq / policy->cur;
+ tunables->boosted = tunables->boost ||
+ now < tunables->boostpulse_endtime;
+
+ if (cpu_load >= tunables->go_hispeed_load || tunables->boosted) {
+ if (policy->cur < tunables->hispeed_freq) {
+ new_freq = tunables->hispeed_freq;
+ } else {
+ new_freq = choose_freq(icpu, loadadjfreq);
+
+ if (new_freq < tunables->hispeed_freq)
+ new_freq = tunables->hispeed_freq;
+ }
+ } else {
+ new_freq = choose_freq(icpu, loadadjfreq);
+ if (new_freq > tunables->hispeed_freq &&
+ policy->cur < tunables->hispeed_freq)
+ new_freq = tunables->hispeed_freq;
+ }
+
+ if (policy->cur >= tunables->hispeed_freq &&
+ new_freq > policy->cur &&
+ now - icpu->pol_hispeed_val_time < freq_to_above_hispeed_delay(tunables, policy->cur)) {
+ trace_cpufreq_interactive_notyet(cpu, cpu_load,
+ icpu->target_freq, policy->cur, new_freq);
+ goto exit;
+ }
+
+ icpu->loc_hispeed_val_time = now;
+
+ index = cpufreq_frequency_table_target(policy, new_freq,
+ CPUFREQ_RELATION_L);
+ new_freq = freq_table[index].frequency;
+
+ /*
+ * Do not scale below floor_freq unless we have been at or above the
+ * floor frequency for the minimum sample time since last validated.
+ */
+ max_fvtime = max(icpu->pol_floor_val_time, icpu->loc_floor_val_time);
+ if (new_freq < icpu->floor_freq && icpu->target_freq >= policy->cur) {
+ if (now - max_fvtime < tunables->min_sample_time) {
+ trace_cpufreq_interactive_notyet(cpu, cpu_load,
+ icpu->target_freq, policy->cur, new_freq);
+ goto exit;
+ }
+ }
+
+ /*
+ * Update the timestamp for checking whether speed has been held at
+ * or above the selected frequency for a minimum of min_sample_time,
+ * if not boosted to hispeed_freq. If boosted to hispeed_freq then we
+ * allow the speed to drop as soon as the boostpulse duration expires
+ * (or the indefinite boost is turned off).
+ */
+
+ if (!tunables->boosted || new_freq > tunables->hispeed_freq) {
+ icpu->floor_freq = new_freq;
+ if (icpu->target_freq >= policy->cur || new_freq >= policy->cur)
+ icpu->loc_floor_val_time = now;
+ }
+
+ if (icpu->target_freq == new_freq &&
+ icpu->target_freq <= policy->cur) {
+ trace_cpufreq_interactive_already(cpu, cpu_load,
+ icpu->target_freq, policy->cur, new_freq);
+ goto exit;
+ }
+
+ trace_cpufreq_interactive_target(cpu, cpu_load, icpu->target_freq,
+ policy->cur, new_freq);
+
+ icpu->target_freq = new_freq;
+ spin_unlock_irqrestore(&icpu->target_freq_lock, flags);
+
+ spin_lock_irqsave(&speedchange_cpumask_lock, flags);
+ cpumask_set_cpu(cpu, &speedchange_cpumask);
+ spin_unlock_irqrestore(&speedchange_cpumask_lock, flags);
+
+ wake_up_process(speedchange_task);
+ return;
+
+exit:
+ spin_unlock_irqrestore(&icpu->target_freq_lock, flags);
+}
+
+static void cpufreq_interactive_update(struct interactive_cpu *icpu)
+{
+ eval_target_freq(icpu);
+ slack_timer_resched(icpu, smp_processor_id(), true);
+}
+
+static void cpufreq_interactive_get_policy_info(struct cpufreq_policy *policy,
+ unsigned int *pmax_freq,
+ u64 *phvt, u64 *pfvt)
+{
+ struct interactive_cpu *icpu;
+ u64 hvt = ~0ULL, fvt = 0;
+ unsigned int max_freq = 0, i;
+
+ for_each_cpu(i, policy->cpus) {
+ icpu = &per_cpu(interactive_cpu, i);
+
+ fvt = max(fvt, icpu->loc_floor_val_time);
+ if (icpu->target_freq > max_freq) {
+ max_freq = icpu->target_freq;
+ hvt = icpu->loc_hispeed_val_time;
+ } else if (icpu->target_freq == max_freq) {
+ hvt = min(hvt, icpu->loc_hispeed_val_time);
+ }
+ }
+
+ *pmax_freq = max_freq;
+ *phvt = hvt;
+ *pfvt = fvt;
+}
+
+static void cpufreq_interactive_adjust_cpu(unsigned int cpu,
+ struct cpufreq_policy *policy)
+{
+ struct interactive_cpu *icpu;
+ u64 hvt, fvt;
+ unsigned int max_freq;
+ int i;
+
+ cpufreq_interactive_get_policy_info(policy, &max_freq, &hvt, &fvt);
+
+ for_each_cpu(i, policy->cpus) {
+ icpu = &per_cpu(interactive_cpu, i);
+ icpu->pol_floor_val_time = fvt;
+ }
+
+ if (max_freq != policy->cur) {
+ __cpufreq_driver_target(policy, max_freq, CPUFREQ_RELATION_H);
+ for_each_cpu(i, policy->cpus) {
+ icpu = &per_cpu(interactive_cpu, i);
+ icpu->pol_hispeed_val_time = hvt;
+ }
+ }
+
+ trace_cpufreq_interactive_setspeed(cpu, max_freq, policy->cur);
+}
+
+static int cpufreq_interactive_speedchange_task(void *data)
+{
+ unsigned int cpu;
+ cpumask_t tmp_mask;
+ unsigned long flags;
+
+again:
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irqsave(&speedchange_cpumask_lock, flags);
+
+ if (cpumask_empty(&speedchange_cpumask)) {
+ spin_unlock_irqrestore(&speedchange_cpumask_lock, flags);
+ schedule();
+
+ if (kthread_should_stop())
+ return 0;
+
+ spin_lock_irqsave(&speedchange_cpumask_lock, flags);
+ }
+
+ set_current_state(TASK_RUNNING);
+ tmp_mask = speedchange_cpumask;
+ cpumask_clear(&speedchange_cpumask);
+ spin_unlock_irqrestore(&speedchange_cpumask_lock, flags);
+
+ for_each_cpu(cpu, &tmp_mask) {
+ struct interactive_cpu *icpu = &per_cpu(interactive_cpu, cpu);
+ struct cpufreq_policy *policy = icpu->ipolicy->policy;
+
+ if (unlikely(!down_read_trylock(&icpu->enable_sem)))
+ continue;
+
+ if (likely(icpu->ipolicy))
+ cpufreq_interactive_adjust_cpu(cpu, policy);
+
+ up_read(&icpu->enable_sem);
+ }
+
+ goto again;
+}
+
+static void cpufreq_interactive_boost(struct interactive_tunables *tunables)
+{
+ struct interactive_policy *ipolicy;
+ struct cpufreq_policy *policy;
+ struct interactive_cpu *icpu;
+ unsigned long flags[2];
+ bool wakeup = false;
+ int i;
+
+ tunables->boosted = true;
+
+ spin_lock_irqsave(&speedchange_cpumask_lock, flags[0]);
+
+ for_each_ipolicy(ipolicy) {
+ policy = ipolicy->policy;
+
+ for_each_cpu(i, policy->cpus) {
+ icpu = &per_cpu(interactive_cpu, i);
+
+ if (!down_read_trylock(&icpu->enable_sem))
+ continue;
+
+ if (!icpu->ipolicy) {
+ up_read(&icpu->enable_sem);
+ continue;
+ }
+
+ spin_lock_irqsave(&icpu->target_freq_lock, flags[1]);
+ if (icpu->target_freq < tunables->hispeed_freq) {
+ icpu->target_freq = tunables->hispeed_freq;
+ cpumask_set_cpu(i, &speedchange_cpumask);
+ icpu->pol_hispeed_val_time = ktime_to_us(ktime_get());
+ wakeup = true;
+ }
+ spin_unlock_irqrestore(&icpu->target_freq_lock, flags[1]);
+
+ up_read(&icpu->enable_sem);
+ }
+ }
+
+ spin_unlock_irqrestore(&speedchange_cpumask_lock, flags[0]);
+
+ if (wakeup)
+ wake_up_process(speedchange_task);
+}
+
+static int cpufreq_interactive_notifier(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ struct cpufreq_freqs *freq = data;
+ struct interactive_cpu *icpu = &per_cpu(interactive_cpu, freq->cpu);
+ unsigned long flags;
+
+ if (val != CPUFREQ_POSTCHANGE)
+ return 0;
+
+ if (!down_read_trylock(&icpu->enable_sem))
+ return 0;
+
+ if (!icpu->ipolicy) {
+ up_read(&icpu->enable_sem);
+ return 0;
+ }
+
+ spin_lock_irqsave(&icpu->load_lock, flags);
+ update_load(icpu, freq->cpu);
+ spin_unlock_irqrestore(&icpu->load_lock, flags);
+
+ up_read(&icpu->enable_sem);
+
+ return 0;
+}
+
+static struct notifier_block cpufreq_notifier_block = {
+ .notifier_call = cpufreq_interactive_notifier,
+};
+
+static unsigned int *get_tokenized_data(const char *buf, int *num_tokens)
+{
+ const char *cp = buf;
+ int ntokens = 1, i = 0;
+ unsigned int *tokenized_data;
+ int err = -EINVAL;
+
+ while ((cp = strpbrk(cp + 1, " :")))
+ ntokens++;
+
+ if (!(ntokens & 0x1))
+ goto err;
+
+ tokenized_data = kcalloc(ntokens, sizeof(*tokenized_data), GFP_KERNEL);
+ if (!tokenized_data) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ cp = buf;
+ while (i < ntokens) {
+ if (kstrtouint(cp, 0, &tokenized_data[i++]) < 0)
+ goto err_kfree;
+
+ cp = strpbrk(cp, " :");
+ if (!cp)
+ break;
+ cp++;
+ }
+
+ if (i != ntokens)
+ goto err_kfree;
+
+ *num_tokens = ntokens;
+ return tokenized_data;
+
+err_kfree:
+ kfree(tokenized_data);
+err:
+ return ERR_PTR(err);
+}
+
+/* Interactive governor sysfs interface */
+static struct interactive_tunables *to_tunables(struct gov_attr_set *attr_set)
+{
+ return container_of(attr_set, struct interactive_tunables, attr_set);
+}
+
+#define show_one(file_name, type) \
+static ssize_t show_##file_name(struct gov_attr_set *attr_set, char *buf) \
+{ \
+ struct interactive_tunables *tunables = to_tunables(attr_set); \
+ return sprintf(buf, type "\n", tunables->file_name); \
+}
+
+static ssize_t show_target_loads(struct gov_attr_set *attr_set, char *buf)
+{
+ struct interactive_tunables *tunables = to_tunables(attr_set);
+ unsigned long flags;
+ ssize_t ret = 0;
+ int i;
+
+ spin_lock_irqsave(&tunables->target_loads_lock, flags);
+
+ for (i = 0; i < tunables->ntarget_loads; i++)
+ ret += sprintf(buf + ret, "%u%s", tunables->target_loads[i],
+ i & 0x1 ? ":" : " ");
+
+ sprintf(buf + ret - 1, "\n");
+ spin_unlock_irqrestore(&tunables->target_loads_lock, flags);
+
+ return ret;
+}
+
+static ssize_t store_target_loads(struct gov_attr_set *attr_set,
+ const char *buf, size_t count)
+{
+ struct interactive_tunables *tunables = to_tunables(attr_set);
+ unsigned int *new_target_loads;
+ unsigned long flags;
+ int ntokens;
+
+ new_target_loads = get_tokenized_data(buf, &ntokens);
+ if (IS_ERR(new_target_loads))
+ return PTR_ERR(new_target_loads);
+
+ spin_lock_irqsave(&tunables->target_loads_lock, flags);
+ if (tunables->target_loads != default_target_loads)
+ kfree(tunables->target_loads);
+ tunables->target_loads = new_target_loads;
+ tunables->ntarget_loads = ntokens;
+ spin_unlock_irqrestore(&tunables->target_loads_lock, flags);
+
+ return count;
+}
+
+static ssize_t show_above_hispeed_delay(struct gov_attr_set *attr_set,
+ char *buf)
+{
+ struct interactive_tunables *tunables = to_tunables(attr_set);
+ unsigned long flags;
+ ssize_t ret = 0;
+ int i;
+
+ spin_lock_irqsave(&tunables->above_hispeed_delay_lock, flags);
+
+ for (i = 0; i < tunables->nabove_hispeed_delay; i++)
+ ret += sprintf(buf + ret, "%u%s",
+ tunables->above_hispeed_delay[i],
+ i & 0x1 ? ":" : " ");
+
+ sprintf(buf + ret - 1, "\n");
+ spin_unlock_irqrestore(&tunables->above_hispeed_delay_lock, flags);
+
+ return ret;
+}
+
+static ssize_t store_above_hispeed_delay(struct gov_attr_set *attr_set,
+ const char *buf, size_t count)
+{
+ struct interactive_tunables *tunables = to_tunables(attr_set);
+ unsigned int *new_above_hispeed_delay = NULL;
+ unsigned long flags;
+ int ntokens;
+
+ new_above_hispeed_delay = get_tokenized_data(buf, &ntokens);
+ if (IS_ERR(new_above_hispeed_delay))
+ return PTR_ERR(new_above_hispeed_delay);
+
+ spin_lock_irqsave(&tunables->above_hispeed_delay_lock, flags);
+ if (tunables->above_hispeed_delay != default_above_hispeed_delay)
+ kfree(tunables->above_hispeed_delay);
+ tunables->above_hispeed_delay = new_above_hispeed_delay;
+ tunables->nabove_hispeed_delay = ntokens;
+ spin_unlock_irqrestore(&tunables->above_hispeed_delay_lock, flags);
+
+ return count;
+}
+
+static ssize_t store_hispeed_freq(struct gov_attr_set *attr_set,
+ const char *buf, size_t count)
+{
+ struct interactive_tunables *tunables = to_tunables(attr_set);
+ unsigned long int val;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ tunables->hispeed_freq = val;
+
+ return count;
+}
+
+static ssize_t store_go_hispeed_load(struct gov_attr_set *attr_set,
+ const char *buf, size_t count)
+{
+ struct interactive_tunables *tunables = to_tunables(attr_set);
+ unsigned long val;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ tunables->go_hispeed_load = val;
+
+ return count;
+}
+
+static ssize_t store_min_sample_time(struct gov_attr_set *attr_set,
+ const char *buf, size_t count)
+{
+ struct interactive_tunables *tunables = to_tunables(attr_set);
+ unsigned long val;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ tunables->min_sample_time = val;
+
+ return count;
+}
+
+static ssize_t show_timer_rate(struct gov_attr_set *attr_set, char *buf)
+{
+ struct interactive_tunables *tunables = to_tunables(attr_set);
+
+ return sprintf(buf, "%lu\n", tunables->sampling_rate);
+}
+
+static ssize_t store_timer_rate(struct gov_attr_set *attr_set, const char *buf,
+ size_t count)
+{
+ struct interactive_tunables *tunables = to_tunables(attr_set);
+ unsigned long val, val_round;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ val_round = jiffies_to_usecs(usecs_to_jiffies(val));
+ if (val != val_round)
+ pr_warn("timer_rate not aligned to jiffy. Rounded up to %lu\n",
+ val_round);
+
+ tunables->sampling_rate = val_round;
+
+ return count;
+}
+
+static ssize_t store_timer_slack(struct gov_attr_set *attr_set, const char *buf,
+ size_t count)
+{
+ struct interactive_tunables *tunables = to_tunables(attr_set);
+ unsigned long val;
+ int ret;
+
+ ret = kstrtol(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+
+ tunables->timer_slack = val;
+ update_slack_delay(tunables);
+
+ return count;
+}
+
+static ssize_t store_boost(struct gov_attr_set *attr_set, const char *buf,
+ size_t count)
+{
+ struct interactive_tunables *tunables = to_tunables(attr_set);
+ unsigned long val;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ tunables->boost = val;
+
+ if (tunables->boost) {
+ trace_cpufreq_interactive_boost("on");
+ if (!tunables->boosted)
+ cpufreq_interactive_boost(tunables);
+ } else {
+ tunables->boostpulse_endtime = ktime_to_us(ktime_get());
+ trace_cpufreq_interactive_unboost("off");
+ }
+
+ return count;
+}
+
+static ssize_t store_boostpulse(struct gov_attr_set *attr_set, const char *buf,
+ size_t count)
+{
+ struct interactive_tunables *tunables = to_tunables(attr_set);
+ unsigned long val;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ tunables->boostpulse_endtime = ktime_to_us(ktime_get()) +
+ tunables->boostpulse_duration;
+ trace_cpufreq_interactive_boost("pulse");
+ if (!tunables->boosted)
+ cpufreq_interactive_boost(tunables);
+
+ return count;
+}
+
+static ssize_t store_boostpulse_duration(struct gov_attr_set *attr_set,
+ const char *buf, size_t count)
+{
+ struct interactive_tunables *tunables = to_tunables(attr_set);
+ unsigned long val;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ tunables->boostpulse_duration = val;
+
+ return count;
+}
+
+static ssize_t store_io_is_busy(struct gov_attr_set *attr_set, const char *buf,
+ size_t count)
+{
+ struct interactive_tunables *tunables = to_tunables(attr_set);
+ unsigned long val;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ tunables->io_is_busy = val;
+
+ return count;
+}
+
+show_one(hispeed_freq, "%u");
+show_one(go_hispeed_load, "%lu");
+show_one(min_sample_time, "%lu");
+show_one(timer_slack, "%lu");
+show_one(boost, "%u");
+show_one(boostpulse_duration, "%u");
+show_one(io_is_busy, "%u");
+
+gov_attr_rw(target_loads);
+gov_attr_rw(above_hispeed_delay);
+gov_attr_rw(hispeed_freq);
+gov_attr_rw(go_hispeed_load);
+gov_attr_rw(min_sample_time);
+gov_attr_rw(timer_rate);
+gov_attr_rw(timer_slack);
+gov_attr_rw(boost);
+gov_attr_wo(boostpulse);
+gov_attr_rw(boostpulse_duration);
+gov_attr_rw(io_is_busy);
+
+static struct attribute *interactive_attributes[] = {
+ &target_loads.attr,
+ &above_hispeed_delay.attr,
+ &hispeed_freq.attr,
+ &go_hispeed_load.attr,
+ &min_sample_time.attr,
+ &timer_rate.attr,
+ &timer_slack.attr,
+ &boost.attr,
+ &boostpulse.attr,
+ &boostpulse_duration.attr,
+ &io_is_busy.attr,
+ NULL
+};
+
+static struct kobj_type interactive_tunables_ktype = {
+ .default_attrs = interactive_attributes,
+ .sysfs_ops = &governor_sysfs_ops,
+};
+
+/* Interactive Governor callbacks */
+struct interactive_governor {
+ struct cpufreq_governor gov;
+ unsigned int usage_count;
+};
+
+static struct interactive_governor interactive_gov;
+
+#define CPU_FREQ_GOV_INTERACTIVE (&interactive_gov.gov)
+
+static void irq_work(struct irq_work *irq_work)
+{
+ struct interactive_cpu *icpu = container_of(irq_work, struct
+ interactive_cpu, irq_work);
+
+ cpufreq_interactive_update(icpu);
+ icpu->work_in_progress = false;
+}
+
+static void update_util_handler(struct update_util_data *data, u64 time,
+ unsigned int flags)
+{
+ struct interactive_cpu *icpu = container_of(data,
+ struct interactive_cpu, update_util);
+ struct interactive_policy *ipolicy = icpu->ipolicy;
+ struct interactive_tunables *tunables = ipolicy->tunables;
+ u64 delta_ns;
+
+ /*
+ * The irq-work may not be allowed to be queued up right now.
+ * Possible reasons:
+ * - Work has already been queued up or is in progress.
+ * - It is too early (too little time from the previous sample).
+ */
+ if (icpu->work_in_progress)
+ return;
+
+ delta_ns = time - icpu->last_sample_time;
+ if ((s64)delta_ns < tunables->sampling_rate * NSEC_PER_USEC)
+ return;
+
+ icpu->last_sample_time = time;
+
+ icpu->work_in_progress = true;
+ irq_work_queue(&icpu->irq_work);
+}
+
+static void gov_set_update_util(struct interactive_policy *ipolicy)
+{
+ struct cpufreq_policy *policy = ipolicy->policy;
+ struct interactive_cpu *icpu;
+ int cpu;
+
+ for_each_cpu(cpu, policy->cpus) {
+ icpu = &per_cpu(interactive_cpu, cpu);
+
+ icpu->last_sample_time = 0;
+ cpufreq_add_update_util_hook(cpu, &icpu->update_util,
+ update_util_handler);
+ }
+}
+
+static inline void gov_clear_update_util(struct cpufreq_policy *policy)
+{
+ int i;
+
+ for_each_cpu(i, policy->cpus)
+ cpufreq_remove_update_util_hook(i);
+
+ synchronize_sched();
+}
+
+static void icpu_cancel_work(struct interactive_cpu *icpu)
+{
+ irq_work_sync(&icpu->irq_work);
+ icpu->work_in_progress = false;
+ del_timer_sync(&icpu->slack_timer);
+}
+
+static struct interactive_policy *
+interactive_policy_alloc(struct cpufreq_policy *policy)
+{
+ struct interactive_policy *ipolicy;
+
+ ipolicy = kzalloc(sizeof(*ipolicy), GFP_KERNEL);
+ if (!ipolicy)
+ return NULL;
+
+ ipolicy->policy = policy;
+
+ return ipolicy;
+}
+
+static void interactive_policy_free(struct interactive_policy *ipolicy)
+{
+ kfree(ipolicy);
+}
+
+static struct interactive_tunables *
+interactive_tunables_alloc(struct interactive_policy *ipolicy)
+{
+ struct interactive_tunables *tunables;
+
+ tunables = kzalloc(sizeof(*tunables), GFP_KERNEL);
+ if (!tunables)
+ return NULL;
+
+ gov_attr_set_init(&tunables->attr_set, &ipolicy->tunables_hook);
+ if (!have_governor_per_policy())
+ global_tunables = tunables;
+
+ ipolicy->tunables = tunables;
+
+ return tunables;
+}
+
+static void interactive_tunables_free(struct interactive_tunables *tunables)
+{
+ if (!have_governor_per_policy())
+ global_tunables = NULL;
+
+ kfree(tunables);
+}
+
+int cpufreq_interactive_init(struct cpufreq_policy *policy)
+{
+ struct interactive_policy *ipolicy;
+ struct interactive_tunables *tunables;
+ int ret;
+
+ /* State should be equivalent to EXIT */
+ if (policy->governor_data)
+ return -EBUSY;
+
+ ipolicy = interactive_policy_alloc(policy);
+ if (!ipolicy)
+ return -ENOMEM;
+
+ mutex_lock(&global_tunables_lock);
+
+ if (global_tunables) {
+ if (WARN_ON(have_governor_per_policy())) {
+ ret = -EINVAL;
+ goto free_int_policy;
+ }
+
+ policy->governor_data = ipolicy;
+ ipolicy->tunables = global_tunables;
+
+ gov_attr_set_get(&global_tunables->attr_set,
+ &ipolicy->tunables_hook);
+ goto out;
+ }
+
+ tunables = interactive_tunables_alloc(ipolicy);
+ if (!tunables) {
+ ret = -ENOMEM;
+ goto free_int_policy;
+ }
+
+ tunables->hispeed_freq = policy->max;
+ tunables->above_hispeed_delay = default_above_hispeed_delay;
+ tunables->nabove_hispeed_delay =
+ ARRAY_SIZE(default_above_hispeed_delay);
+ tunables->go_hispeed_load = DEFAULT_GO_HISPEED_LOAD;
+ tunables->target_loads = default_target_loads;
+ tunables->ntarget_loads = ARRAY_SIZE(default_target_loads);
+ tunables->min_sample_time = DEFAULT_MIN_SAMPLE_TIME;
+ tunables->boostpulse_duration = DEFAULT_MIN_SAMPLE_TIME;
+ tunables->sampling_rate = DEFAULT_SAMPLING_RATE;
+ tunables->timer_slack = DEFAULT_TIMER_SLACK;
+ update_slack_delay(tunables);
+
+ spin_lock_init(&tunables->target_loads_lock);
+ spin_lock_init(&tunables->above_hispeed_delay_lock);
+
+ policy->governor_data = ipolicy;
+
+ ret = kobject_init_and_add(&tunables->attr_set.kobj,
+ &interactive_tunables_ktype,
+ get_governor_parent_kobj(policy), "%s",
+ interactive_gov.gov.name);
+ if (ret)
+ goto fail;
+
+ /* One time initialization for governor */
+ if (!interactive_gov.usage_count++) {
+ cpufreq_register_notifier(&cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ }
+
+ out:
+ mutex_unlock(&global_tunables_lock);
+ return 0;
+
+ fail:
+ policy->governor_data = NULL;
+ interactive_tunables_free(tunables);
+
+ free_int_policy:
+ mutex_unlock(&global_tunables_lock);
+
+ interactive_policy_free(ipolicy);
+ pr_err("governor initialization failed (%d)\n", ret);
+
+ return ret;
+}
+
+void cpufreq_interactive_exit(struct cpufreq_policy *policy)
+{
+ struct interactive_policy *ipolicy = policy->governor_data;
+ struct interactive_tunables *tunables = ipolicy->tunables;
+ unsigned int count;
+
+ mutex_lock(&global_tunables_lock);
+
+ /* Last policy using the governor ? */
+ if (!--interactive_gov.usage_count) {
+ cpufreq_unregister_notifier(&cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ }
+
+ count = gov_attr_set_put(&tunables->attr_set, &ipolicy->tunables_hook);
+ policy->governor_data = NULL;
+ if (!count)
+ interactive_tunables_free(tunables);
+
+ mutex_unlock(&global_tunables_lock);
+
+ interactive_policy_free(ipolicy);
+}
+
+int cpufreq_interactive_start(struct cpufreq_policy *policy)
+{
+ struct interactive_policy *ipolicy = policy->governor_data;
+ struct interactive_cpu *icpu;
+ unsigned int cpu;
+
+ for_each_cpu(cpu, policy->cpus) {
+ icpu = &per_cpu(interactive_cpu, cpu);
+
+ icpu->target_freq = policy->cur;
+ icpu->floor_freq = icpu->target_freq;
+ icpu->pol_floor_val_time = ktime_to_us(ktime_get());
+ icpu->loc_floor_val_time = icpu->pol_floor_val_time;
+ icpu->pol_hispeed_val_time = icpu->pol_floor_val_time;
+ icpu->loc_hispeed_val_time = icpu->pol_floor_val_time;
+
+ down_write(&icpu->enable_sem);
+ icpu->ipolicy = ipolicy;
+ up_write(&icpu->enable_sem);
+
+ slack_timer_resched(icpu, cpu, false);
+ }
+
+ gov_set_update_util(ipolicy);
+ return 0;
+}
+
+void cpufreq_interactive_stop(struct cpufreq_policy *policy)
+{
+ struct interactive_policy *ipolicy = policy->governor_data;
+ struct interactive_cpu *icpu;
+ unsigned int cpu;
+
+ gov_clear_update_util(ipolicy->policy);
+
+ for_each_cpu(cpu, policy->cpus) {
+ icpu = &per_cpu(interactive_cpu, cpu);
+
+ icpu_cancel_work(icpu);
+
+ down_write(&icpu->enable_sem);
+ icpu->ipolicy = NULL;
+ up_write(&icpu->enable_sem);
+ }
+}
+
+void cpufreq_interactive_limits(struct cpufreq_policy *policy)
+{
+ struct interactive_cpu *icpu;
+ unsigned int cpu;
+ unsigned long flags;
+
+ cpufreq_policy_apply_limits(policy);
+
+ for_each_cpu(cpu, policy->cpus) {
+ icpu = &per_cpu(interactive_cpu, cpu);
+
+ spin_lock_irqsave(&icpu->target_freq_lock, flags);
+
+ if (policy->max < icpu->target_freq)
+ icpu->target_freq = policy->max;
+ else if (policy->min > icpu->target_freq)
+ icpu->target_freq = policy->min;
+
+ spin_unlock_irqrestore(&icpu->target_freq_lock, flags);
+ }
+}
+
+static struct interactive_governor interactive_gov = {
+ .gov = {
+ .name = "interactive",
+ .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+ .owner = THIS_MODULE,
+ .init = cpufreq_interactive_init,
+ .exit = cpufreq_interactive_exit,
+ .start = cpufreq_interactive_start,
+ .stop = cpufreq_interactive_stop,
+ .limits = cpufreq_interactive_limits,
+ }
+};
+
+static void cpufreq_interactive_nop_timer(unsigned long data)
+{
+ /*
+ * The purpose of slack-timer is to wake up the CPU from IDLE, in order
+ * to decrease its frequency if it is not set to minimum already.
+ *
+ * This is important for platforms where CPU with higher frequencies
+ * consume higher power even at IDLE.
+ */
+}
+
+static int __init cpufreq_interactive_gov_init(void)
+{
+ struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
+ struct interactive_cpu *icpu;
+ unsigned int cpu;
+
+ for_each_possible_cpu(cpu) {
+ icpu = &per_cpu(interactive_cpu, cpu);
+
+ init_irq_work(&icpu->irq_work, irq_work);
+ spin_lock_init(&icpu->load_lock);
+ spin_lock_init(&icpu->target_freq_lock);
+ init_rwsem(&icpu->enable_sem);
+
+ /* Initialize per-cpu slack-timer */
+ init_timer_pinned(&icpu->slack_timer);
+ icpu->slack_timer.function = cpufreq_interactive_nop_timer;
+ }
+
+ spin_lock_init(&speedchange_cpumask_lock);
+ speedchange_task = kthread_create(cpufreq_interactive_speedchange_task,
+ NULL, "cfinteractive");
+ if (IS_ERR(speedchange_task))
+ return PTR_ERR(speedchange_task);
+
+ sched_setscheduler_nocheck(speedchange_task, SCHED_FIFO, &param);
+ get_task_struct(speedchange_task);
+
+ /* wake up so the thread does not look hung to the freezer */
+ wake_up_process(speedchange_task);
+
+ return cpufreq_register_governor(CPU_FREQ_GOV_INTERACTIVE);
+}
+
+#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE
+struct cpufreq_governor *cpufreq_default_governor(void)
+{
+ return CPU_FREQ_GOV_INTERACTIVE;
+}
+
+fs_initcall(cpufreq_interactive_gov_init);
+#else
+module_init(cpufreq_interactive_gov_init);
+#endif
+
+static void __exit cpufreq_interactive_gov_exit(void)
+{
+ cpufreq_unregister_governor(CPU_FREQ_GOV_INTERACTIVE);
+ kthread_stop(speedchange_task);
+ put_task_struct(speedchange_task);
+}
+module_exit(cpufreq_interactive_gov_exit);
+
+MODULE_AUTHOR("Mike Chan <mike@android.com>");
+MODULE_DESCRIPTION("'cpufreq_interactive' - A dynamic cpufreq governor for Latency sensitive workloads");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index ef1fa8145419..dbcf35b456b8 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -1,28 +1,39 @@
/*
- * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ * Copyright (C) 2013-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/busfreq-imx.h>
#include <linux/clk.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/of.h>
#include <linux/pm_opp.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/suspend.h>
#define PU_SOC_VOLTAGE_NORMAL 1250000
#define PU_SOC_VOLTAGE_HIGH 1275000
+#define DC_VOLTAGE_MIN 1300000
+#define DC_VOLTAGE_MAX 1400000
#define FREQ_1P2_GHZ 1200000000
+#define FREQ_396_MHZ 396000
+#define FREQ_528_MHZ 528000
+#define FREQ_198_MHZ 198000
+#define FREQ_24_MHZ 24000
-static struct regulator *arm_reg;
+struct regulator *arm_reg;
static struct regulator *pu_reg;
-static struct regulator *soc_reg;
+struct regulator *soc_reg;
+static struct regulator *dc_reg;
static struct clk *arm_clk;
static struct clk *pll1_sys_clk;
@@ -31,6 +42,9 @@ static struct clk *step_clk;
static struct clk *pll2_pfd2_396m_clk;
/* clk used by i.MX6UL */
+static struct clk *pll1_bypass;
+static struct clk *pll1_bypass_src;
+static struct clk *pll1;
static struct clk *pll2_bus_clk;
static struct clk *secondary_sel_clk;
@@ -38,9 +52,11 @@ static struct device *cpu_dev;
static bool free_opp;
static struct cpufreq_frequency_table *freq_table;
static unsigned int transition_latency;
-
+static struct mutex set_cpufreq_lock;
static u32 *imx6_soc_volt;
static u32 soc_opp_count;
+static bool ignore_dc_reg;
+static bool low_power_run_support;
static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
{
@@ -49,15 +65,29 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
unsigned int old_freq, new_freq;
int ret;
+ mutex_lock(&set_cpufreq_lock);
+
new_freq = freq_table[index].frequency;
freq_hz = new_freq * 1000;
- old_freq = clk_get_rate(arm_clk) / 1000;
+ old_freq = policy->cur;
+
+ /*
+ * ON i.MX6ULL, the 24MHz setpoint is not seen by cpufreq
+ * so we neet to prevent the cpufreq change frequency
+ * from 24MHz to 198Mhz directly. busfreq will handle this
+ * when exit from low bus mode.
+ */
+ if (old_freq == FREQ_24_MHZ && new_freq == FREQ_198_MHZ) {
+ mutex_unlock(&set_cpufreq_lock);
+ return 0;
+ };
rcu_read_lock();
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
if (IS_ERR(opp)) {
rcu_read_unlock();
dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
+ mutex_unlock(&set_cpufreq_lock);
return PTR_ERR(opp);
}
@@ -68,6 +98,16 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
old_freq / 1000, volt_old / 1000,
new_freq / 1000, volt / 1000);
+ /*
+ * CPU freq is increasing, so need to ensure
+ * that bus frequency is increased too.
+ */
+ if (low_power_run_support) {
+ if (old_freq == freq_table[0].frequency)
+ request_bus_freq(BUS_FREQ_HIGH);
+ } else if (old_freq <= FREQ_396_MHZ && new_freq > FREQ_396_MHZ) {
+ request_bus_freq(BUS_FREQ_HIGH);
+ }
/* scaling up? scale voltage before frequency */
if (new_freq > old_freq) {
@@ -75,18 +115,21 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
ret = regulator_set_voltage_tol(pu_reg, imx6_soc_volt[index], 0);
if (ret) {
dev_err(cpu_dev, "failed to scale vddpu up: %d\n", ret);
+ mutex_unlock(&set_cpufreq_lock);
return ret;
}
}
ret = regulator_set_voltage_tol(soc_reg, imx6_soc_volt[index], 0);
if (ret) {
dev_err(cpu_dev, "failed to scale vddsoc up: %d\n", ret);
+ mutex_unlock(&set_cpufreq_lock);
return ret;
}
ret = regulator_set_voltage_tol(arm_reg, volt, 0);
if (ret) {
dev_err(cpu_dev,
"failed to scale vddarm up: %d\n", ret);
+ mutex_unlock(&set_cpufreq_lock);
return ret;
}
}
@@ -102,7 +145,8 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
* - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it
* - Disable pll2_pfd2_396m_clk
*/
- if (of_machine_is_compatible("fsl,imx6ul")) {
+ if (of_machine_is_compatible("fsl,imx6ul") ||
+ of_machine_is_compatible("fsl,imx6ull")) {
/*
* When changing pll1_sw_clk's parent to pll1_sys_clk,
* CPU may run at higher than 528MHz, this will lead to
@@ -118,12 +162,28 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
clk_set_parent(secondary_sel_clk, pll2_pfd2_396m_clk);
clk_set_parent(step_clk, secondary_sel_clk);
clk_set_parent(pll1_sw_clk, step_clk);
+ if (freq_hz > clk_get_rate(pll2_bus_clk)) {
+ clk_set_rate(pll1, new_freq * 1000);
+ clk_set_parent(pll1_sw_clk, pll1_sys_clk);
+ }
} else {
clk_set_parent(step_clk, pll2_pfd2_396m_clk);
clk_set_parent(pll1_sw_clk, step_clk);
if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
+ /* Ensure that pll1_bypass is set back to
+ * pll1. We have to do this first so that the
+ * change rate done to pll1_sys_clk done below
+ * can propagate up to pll1.
+ */
+ clk_set_parent(pll1_bypass, pll1);
clk_set_rate(pll1_sys_clk, new_freq * 1000);
clk_set_parent(pll1_sw_clk, pll1_sys_clk);
+ } else {
+ /*
+ * Need to ensure that PLL1 is bypassed and enabled
+ * before ARM-PODF is set.
+ */
+ clk_set_parent(pll1_bypass, pll1_bypass_src);
}
}
@@ -132,6 +192,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
if (ret) {
dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
regulator_set_voltage_tol(arm_reg, volt_old, 0);
+ mutex_unlock(&set_cpufreq_lock);
return ret;
}
@@ -156,14 +217,40 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
}
}
}
+ /*
+ * If CPU is dropped to the lowest level, release the need
+ * for a high bus frequency.
+ */
+ if (low_power_run_support) {
+ if (new_freq == freq_table[0].frequency)
+ release_bus_freq(BUS_FREQ_HIGH);
+ } else if (old_freq > FREQ_396_MHZ && new_freq <= FREQ_396_MHZ) {
+ release_bus_freq(BUS_FREQ_HIGH);
+ }
+ mutex_unlock(&set_cpufreq_lock);
return 0;
}
static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
{
+ int ret;
+
policy->clk = arm_clk;
- return cpufreq_generic_init(policy, freq_table, transition_latency);
+ policy->cur = clk_get_rate(arm_clk) / 1000;
+
+ ret = cpufreq_generic_init(policy, freq_table, transition_latency);
+ if (ret) {
+ dev_err(cpu_dev, "imx6 cpufreq init failed!\n");
+ return ret;
+ }
+ if (low_power_run_support && policy->cur > freq_table[0].frequency) {
+ request_bus_freq(BUS_FREQ_HIGH);
+ } else if (policy->cur > FREQ_396_MHZ) {
+ request_bus_freq(BUS_FREQ_HIGH);
+ }
+
+ return 0;
}
static struct cpufreq_driver imx6q_cpufreq_driver = {
@@ -176,15 +263,61 @@ static struct cpufreq_driver imx6q_cpufreq_driver = {
.attr = cpufreq_generic_attr,
};
+static int imx6_cpufreq_pm_notify(struct notifier_block *nb,
+ unsigned long event, void *dummy)
+{
+ struct cpufreq_policy *data = cpufreq_cpu_get(0);
+ static u32 cpufreq_policy_min_pre_suspend;
+
+ /*
+ * During suspend/resume, When cpufreq driver try to increase
+ * voltage/freq, it needs to control I2C/SPI to communicate
+ * with external PMIC to adjust voltage, but these I2C/SPI
+ * devices may be already suspended, to avoid such scenario,
+ * we just increase cpufreq to highest setpoint before suspend.
+ */
+ if (!data)
+ return NOTIFY_BAD;
+
+ switch (event) {
+ case PM_SUSPEND_PREPARE:
+ cpufreq_policy_min_pre_suspend = data->user_policy.min;
+ data->user_policy.min = data->user_policy.max;
+
+ if (!IS_ERR(dc_reg) && !ignore_dc_reg)
+ regulator_set_voltage_tol(dc_reg, DC_VOLTAGE_MAX, 0);
+ break;
+ case PM_POST_SUSPEND:
+ data->user_policy.min = cpufreq_policy_min_pre_suspend;
+
+ if (!IS_ERR(dc_reg) && !ignore_dc_reg)
+ regulator_set_voltage_tol(dc_reg, DC_VOLTAGE_MIN, 0);
+ break;
+ default:
+ break;
+ }
+
+ cpufreq_update_policy(0);
+ cpufreq_cpu_put(data);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block imx6_cpufreq_pm_notifier = {
+ .notifier_call = imx6_cpufreq_pm_notify,
+};
+
static int imx6q_cpufreq_probe(struct platform_device *pdev)
{
struct device_node *np;
struct dev_pm_opp *opp;
+ struct clk *vpu_axi_podf;
unsigned long min_volt, max_volt;
int num, ret;
const struct property *prop;
const __be32 *val;
- u32 nr, i, j;
+ u32 nr, j, i = 0;
+ u32 vpu_axi_rate = 0;
cpu_dev = get_cpu_device(0);
if (!cpu_dev) {
@@ -203,14 +336,19 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
pll1_sw_clk = clk_get(cpu_dev, "pll1_sw");
step_clk = clk_get(cpu_dev, "step");
pll2_pfd2_396m_clk = clk_get(cpu_dev, "pll2_pfd2_396m");
+ pll1 = clk_get(cpu_dev, "pll1");
+ pll1_bypass = clk_get(cpu_dev, "pll1_bypass");
+ pll1_bypass_src = clk_get(cpu_dev, "pll1_bypass_src");
if (IS_ERR(arm_clk) || IS_ERR(pll1_sys_clk) || IS_ERR(pll1_sw_clk) ||
- IS_ERR(step_clk) || IS_ERR(pll2_pfd2_396m_clk)) {
+ IS_ERR(step_clk) || IS_ERR(pll2_pfd2_396m_clk) || IS_ERR(pll1) ||
+ IS_ERR(pll1_bypass) || IS_ERR(pll1_bypass_src)) {
dev_err(cpu_dev, "failed to get clocks\n");
ret = -ENOENT;
goto put_clk;
}
- if (of_machine_is_compatible("fsl,imx6ul")) {
+ if (of_machine_is_compatible("fsl,imx6ul") ||
+ of_machine_is_compatible("fsl,imx6ull")) {
pll2_bus_clk = clk_get(cpu_dev, "pll2_bus");
secondary_sel_clk = clk_get(cpu_dev, "secondary_sel");
if (IS_ERR(pll2_bus_clk) || IS_ERR(secondary_sel_clk)) {
@@ -220,15 +358,40 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
}
}
+ vpu_axi_podf = clk_get(cpu_dev, "vpu_axi_podf");
+ if (!IS_ERR(vpu_axi_podf)) {
+ vpu_axi_rate = clk_get_rate(vpu_axi_podf);
+ clk_put(vpu_axi_podf);
+ }
+
arm_reg = regulator_get(cpu_dev, "arm");
pu_reg = regulator_get_optional(cpu_dev, "pu");
soc_reg = regulator_get(cpu_dev, "soc");
if (IS_ERR(arm_reg) || IS_ERR(soc_reg)) {
- dev_err(cpu_dev, "failed to get regulators\n");
- ret = -ENOENT;
+ ret = IS_ERR(arm_reg)?PTR_ERR(arm_reg):PTR_ERR(soc_reg);
+ if (ret == -EPROBE_DEFER)
+ dev_warn(cpu_dev, "regulators not ready, retry\n");
+ else
+ dev_err(cpu_dev, "failed to get regulators: %d\n", ret);
goto put_reg;
}
+ dc_reg = regulator_get_optional(cpu_dev, "dc");
+
+ /*
+ * soc_reg sync with arm_reg if arm shares the same regulator
+ * with soc. Otherwise, regulator common framework will refuse to update
+ * this consumer's voltage right now while another consumer voltage
+ * still keep in old one. For example, imx6sx-sdb with pfuze200 in
+ * ldo-bypass mode.
+ */
+ of_property_read_u32(np, "fsl,arm-soc-shared", &i);
+ if (i == 1)
+ soc_reg = arm_reg;
+
+ /* On i.MX6ULL, check the 24MHz low power run mode support */
+ low_power_run_support = of_property_read_bool(np, "fsl,low-power-run");
+
/*
* We expect an OPP table supplied by platform.
* Just, incase the platform did not supply the OPP
@@ -259,8 +422,17 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
goto put_reg;
}
+ /*
+ * On i.MX6UL/ULL EVK board, if the SOC is run in overide frequency,
+ * the dc_regulator voltage should not be touched.
+ */
+ if (freq_table[num - 1].frequency > FREQ_528_MHZ)
+ ignore_dc_reg = true;
+ if (!IS_ERR(dc_reg) && !ignore_dc_reg)
+ regulator_set_voltage_tol(dc_reg, DC_VOLTAGE_MIN, 0);
+
/* Make imx6_soc_volt array's size same as arm opp number */
- imx6_soc_volt = devm_kzalloc(cpu_dev, sizeof(*imx6_soc_volt) * num, GFP_KERNEL);
+ imx6_soc_volt = kzalloc(sizeof(*imx6_soc_volt) * num, GFP_KERNEL);
if (imx6_soc_volt == NULL) {
ret = -ENOMEM;
goto free_freq_table;
@@ -285,6 +457,19 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
unsigned long volt = be32_to_cpup(val++);
if (freq_table[j].frequency == freq) {
imx6_soc_volt[soc_opp_count++] = volt;
+#ifdef CONFIG_MX6_VPU_352M
+ if (freq == 792000) {
+ pr_info("increase SOC/PU voltage for VPU352MHz\n");
+ imx6_soc_volt[soc_opp_count - 1] = 1250000;
+ }
+#endif
+ if (vpu_axi_rate == 396000000) {
+ if (freq <= 996000) {
+ pr_info("increase SOC/PU voltage for VPU396MHz at %ld MHz\n",
+ freq / 1000);
+ imx6_soc_volt[soc_opp_count - 1] = 1275000;
+ }
+ }
break;
}
}
@@ -333,16 +518,22 @@ soc_opp_out:
if (ret > 0)
transition_latency += ret * 1000;
+ mutex_init(&set_cpufreq_lock);
+
ret = cpufreq_register_driver(&imx6q_cpufreq_driver);
if (ret) {
dev_err(cpu_dev, "failed register driver: %d\n", ret);
goto free_freq_table;
}
+ register_pm_notifier(&imx6_cpufreq_pm_notifier);
+
of_node_put(np);
+ dev_info(cpu_dev, "Registered imx6q-cpufreq\n");
return 0;
free_freq_table:
+ kfree(imx6_soc_volt);
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
out_free_opp:
if (free_opp)
@@ -354,6 +545,8 @@ put_reg:
regulator_put(pu_reg);
if (!IS_ERR(soc_reg))
regulator_put(soc_reg);
+ if (!IS_ERR(dc_reg))
+ regulator_put(dc_reg);
put_clk:
if (!IS_ERR(arm_clk))
clk_put(arm_clk);
@@ -365,6 +558,12 @@ put_clk:
clk_put(step_clk);
if (!IS_ERR(pll2_pfd2_396m_clk))
clk_put(pll2_pfd2_396m_clk);
+ if (!IS_ERR(pll1))
+ clk_put(pll1);
+ if (!IS_ERR(pll1_bypass))
+ clk_put(pll1_bypass);
+ if (!IS_ERR(pll1_bypass_src))
+ clk_put(pll1_bypass_src);
if (!IS_ERR(pll2_bus_clk))
clk_put(pll2_bus_clk);
if (!IS_ERR(secondary_sel_clk))
@@ -376,6 +575,7 @@ put_clk:
static int imx6q_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&imx6q_cpufreq_driver);
+ kfree(imx6_soc_volt);
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
if (free_opp)
dev_pm_opp_of_remove_table(cpu_dev);
@@ -383,10 +583,15 @@ static int imx6q_cpufreq_remove(struct platform_device *pdev)
if (!IS_ERR(pu_reg))
regulator_put(pu_reg);
regulator_put(soc_reg);
+ if (!IS_ERR(dc_reg))
+ regulator_put(dc_reg);
clk_put(arm_clk);
clk_put(pll1_sys_clk);
clk_put(pll1_sw_clk);
clk_put(step_clk);
+ clk_put(pll1);
+ clk_put(pll1_bypass);
+ clk_put(pll1_bypass_src);
clk_put(pll2_pfd2_396m_clk);
clk_put(pll2_bus_clk);
clk_put(secondary_sel_clk);
diff --git a/drivers/cpufreq/imx7-cpufreq.c b/drivers/cpufreq/imx7-cpufreq.c
new file mode 100644
index 000000000000..32f30cec04ff
--- /dev/null
+++ b/drivers/cpufreq/imx7-cpufreq.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_opp.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/suspend.h>
+static struct clk *arm_clk;
+
+static struct regulator *arm_reg;
+
+static struct device *cpu_dev;
+static struct cpufreq_frequency_table *freq_table;
+static unsigned int transition_latency;
+static struct mutex set_cpufreq_lock;
+
+static int imx7d_set_target(struct cpufreq_policy *policy, unsigned int index)
+{
+ struct dev_pm_opp *opp;
+ unsigned long freq_hz, volt, volt_old;
+ unsigned int old_freq, new_freq;
+ int ret;
+
+ mutex_lock(&set_cpufreq_lock);
+
+ new_freq = freq_table[index].frequency;
+ freq_hz = new_freq * 1000;
+ old_freq = clk_get_rate(arm_clk) / 1000;
+
+ rcu_read_lock();
+ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
+ mutex_unlock(&set_cpufreq_lock);
+ return PTR_ERR(opp);
+ }
+ volt = dev_pm_opp_get_voltage(opp);
+
+ rcu_read_unlock();
+ volt_old = regulator_get_voltage(arm_reg);
+
+ dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
+ old_freq / 1000, volt_old / 1000,
+ new_freq / 1000, volt / 1000);
+
+ /* Scaling up? scale voltage before frequency */
+ if (new_freq > old_freq) {
+ ret = regulator_set_voltage_tol(arm_reg, volt, 0);
+ if (ret) {
+ dev_err(cpu_dev, "failed to scale vddarm up: %d\n", ret);
+ mutex_unlock(&set_cpufreq_lock);
+ return ret;
+ }
+ }
+
+ /* change the cpu frequency */
+ ret = clk_set_rate(arm_clk, new_freq * 1000);
+ if (ret) {
+ dev_err(cpu_dev, " failed to set clock rate: %d\n", ret);
+ regulator_set_voltage_tol(arm_reg, volt_old, 0);
+ mutex_unlock(&set_cpufreq_lock);
+ return ret;
+ }
+
+ /* scaling down? scaling voltage after frequency */
+ if (new_freq < old_freq) {
+ ret = regulator_set_voltage_tol(arm_reg, volt, 0);
+ if (ret) {
+ dev_warn(cpu_dev, "failed to scale vddarm down: %d\n", ret);
+ ret = 0;
+ }
+ }
+
+ mutex_unlock(&set_cpufreq_lock);
+ return 0;
+}
+
+static int imx7d_cpufreq_init(struct cpufreq_policy *policy)
+{
+ int ret;
+ policy->clk = arm_clk;
+ policy->cur = clk_get_rate(arm_clk) / 1000;
+
+ ret = cpufreq_generic_init(policy, freq_table, transition_latency);
+ if (ret) {
+ dev_err(cpu_dev, "imx7d cpufreq init failed!\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct cpufreq_driver imx7d_cpufreq_driver = {
+ .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
+ .verify = cpufreq_generic_frequency_table_verify,
+ .target_index = imx7d_set_target,
+ .get = cpufreq_generic_get,
+ .init = imx7d_cpufreq_init,
+ .name = "imx7d-cpufreq",
+ .attr = cpufreq_generic_attr,
+};
+
+static int imx7_cpufreq_pm_notify(struct notifier_block *nb,
+ unsigned long event, void *dummy)
+{
+ struct cpufreq_policy *data = cpufreq_cpu_get(0);
+ static u32 cpufreq_policy_min_pre_suspend;
+
+ /*
+ * During suspend/resume, when cpufreq driver try to increase
+ * voltage/freq, it needs to control I2C/SPI to communicate
+ * with external PMIC to adjust voltage, but these I2C/SPI
+ * devices may be already suspended, to avoid such scenario,
+ * we just increase cpufreq to highest setpoint before suspend.
+ */
+ if (!data)
+ return NOTIFY_BAD;
+
+ switch (event) {
+ case PM_SUSPEND_PREPARE:
+ cpufreq_policy_min_pre_suspend = data->user_policy.min;
+ data->user_policy.min = data->user_policy.max;
+ break;
+ case PM_POST_SUSPEND:
+ data->user_policy.min = cpufreq_policy_min_pre_suspend;
+ break;
+ default:
+ break;
+ }
+
+ cpufreq_update_policy(0);
+ cpufreq_cpu_put(data);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block imx7_cpufreq_pm_notifier = {
+ .notifier_call = imx7_cpufreq_pm_notify,
+};
+
+static int imx7d_cpufreq_probe(struct platform_device *pdev)
+{
+ struct device_node *np;
+ struct dev_pm_opp *opp;
+ unsigned long min_volt, max_volt;
+ int num, ret;
+
+ cpu_dev = get_cpu_device(0);
+ if (!cpu_dev) {
+ pr_err("failed to get cpu0 device\n");
+ return -ENODEV;
+ }
+
+ np = of_node_get(cpu_dev->of_node);
+ if (!np) {
+ dev_err(cpu_dev, "failed to find the cpu0 node\n");
+ return -ENOENT;
+ }
+
+ arm_clk = devm_clk_get(cpu_dev, "arm");
+ if (IS_ERR(arm_clk)) {
+ dev_err(cpu_dev, "failed to get arm clock\n");
+ ret = PTR_ERR(arm_clk);
+ goto put_node;
+ }
+
+ arm_reg = devm_regulator_get(cpu_dev, "arm");
+ if (IS_ERR(arm_reg)) {
+ dev_err(cpu_dev, "failed to get the regulator\n");
+ ret = -ENOENT;
+ goto put_node;
+ }
+
+ /* We expect an OPP table supplied by platform.
+ * Just incase the platform did not supply the OPP
+ * table, it will try to get it.
+ */
+ num = dev_pm_opp_get_opp_count(cpu_dev);
+ if (num < 0) {
+ ret = dev_pm_opp_of_add_table(cpu_dev);
+ if (ret < 0) {
+ dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);
+ goto put_node;
+ }
+ num = dev_pm_opp_get_opp_count(cpu_dev);
+ if (num < 0) {
+ ret = num;
+ dev_err(cpu_dev, "no OPP table is found: %d\n", ret);
+ goto put_node;
+ }
+ }
+
+ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
+ if (ret) {
+ dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
+ goto put_node;
+ }
+
+ if (of_property_read_u32(np, "clock-latency", &transition_latency))
+ transition_latency = CPUFREQ_ETERNAL;
+
+ /* OPP is maintained in order of increasing frequency, and
+ * freq_table initialized from OPP is therefore sorted in the
+ * same order
+ */
+ rcu_read_lock();
+ opp = dev_pm_opp_find_freq_exact(cpu_dev,
+ freq_table[0].frequency * 1000, true);
+ min_volt = dev_pm_opp_get_voltage(opp);
+ opp = dev_pm_opp_find_freq_exact(cpu_dev,
+ freq_table[--num].frequency * 1000, true);
+ max_volt = dev_pm_opp_get_voltage(opp);
+ rcu_read_unlock();
+ ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt);
+ if (ret > 0)
+ transition_latency += ret * 1000;
+
+ mutex_init(&set_cpufreq_lock);
+
+ ret = cpufreq_register_driver(&imx7d_cpufreq_driver);
+ if (ret) {
+ dev_err(cpu_dev, "failed register driver: %d\n", ret);
+ goto free_freq_table;
+ }
+
+ register_pm_notifier(&imx7_cpufreq_pm_notifier);
+
+ of_node_put(np);
+ return 0;
+
+free_freq_table:
+ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
+put_node:
+ of_node_put(np);
+
+ return ret;
+}
+
+static int imx7d_cpufreq_remove(struct platform_device *pdev)
+{
+ cpufreq_unregister_driver(&imx7d_cpufreq_driver);
+ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
+
+ return 0;
+}
+
+static struct platform_driver imx7d_cpufreq_platdrv = {
+ .driver = {
+ .name = "imx7d-cpufreq",
+ .owner = THIS_MODULE,
+ },
+ .probe = imx7d_cpufreq_probe,
+ .remove = imx7d_cpufreq_remove,
+};
+
+module_platform_driver(imx7d_cpufreq_platdrv);
+
+MODULE_DESCRIPTION("Freescale i.MX7D cpufreq driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/imx7ulp-cpufreq.c b/drivers/cpufreq/imx7ulp-cpufreq.c
new file mode 100644
index 000000000000..e63711c3630d
--- /dev/null
+++ b/drivers/cpufreq/imx7ulp-cpufreq.c
@@ -0,0 +1,273 @@
+ /*
+ * Copyright 2017 NXP.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_opp.h>
+#include <linux/pm_qos.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/suspend.h>
+
+#define MAX_RUN_FREQ 528000
+
+static struct clk *arm_clk;
+static struct clk *core_div;
+static struct clk *sys_sel;
+static struct clk *hsrun_sys_sel;
+static struct clk *hsrun_core;
+static struct clk *spll_pfd0;
+static struct clk *spll_sel;
+static struct clk *firc_clk;
+static struct clk *spll;
+
+static struct pm_qos_request pm_qos_hsrun;
+static struct regulator *arm_reg;
+static struct device *cpu_dev;
+static struct cpufreq_frequency_table *freq_table;
+static unsigned int transition_latency;
+static struct mutex set_cpufreq_lock;
+
+static int imx7ulp_set_target(struct cpufreq_policy *policy, unsigned int index)
+{
+ struct dev_pm_opp *opp;
+ unsigned long freq_hz, volt, volt_old;
+ unsigned int old_freq, new_freq;
+ int ret;
+
+ mutex_lock(&set_cpufreq_lock);
+
+ new_freq = freq_table[index].frequency;
+ freq_hz = new_freq * 1000;
+ old_freq = clk_get_rate(arm_clk) / 1000;
+
+ rcu_read_lock();
+ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
+ mutex_unlock(&set_cpufreq_lock);
+ return PTR_ERR(opp);
+ }
+ volt = dev_pm_opp_get_voltage(opp);
+
+ rcu_read_unlock();
+ volt_old = regulator_get_voltage(arm_reg);
+
+ dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
+ old_freq / 1000, volt_old / 1000,
+ new_freq / 1000, volt / 1000);
+
+ /* Scaling up? scale voltage before frequency */
+ if (new_freq > old_freq) {
+ ret = regulator_set_voltage_tol(arm_reg, volt, 0);
+ if (ret) {
+ dev_err(cpu_dev, "failed to scale vddarm up: %d\n", ret);
+ mutex_unlock(&set_cpufreq_lock);
+ return ret;
+ }
+ }
+
+ /* before changing pll_arm rate, change the arm_src's soure
+ * to firc clk first.
+ */
+ if (new_freq > MAX_RUN_FREQ) {
+ pm_qos_add_request(&pm_qos_hsrun, PM_QOS_CPU_DMA_LATENCY, 0);
+ /* change the RUN clock to firc */
+ clk_set_parent(sys_sel, firc_clk);
+ /* change the clock rate in HSRUN */
+ clk_set_rate(spll, 480000000);
+ clk_set_rate(spll_pfd0, new_freq * 1000);
+ clk_set_parent(hsrun_sys_sel, spll_sel);
+ clk_set_parent(arm_clk, hsrun_core);
+ } else {
+ /* change the HSRUN clock to firc */
+ clk_set_parent(hsrun_sys_sel, firc_clk);
+ /* change the clock rate in RUN */
+ clk_set_rate(spll, 528000000);
+ clk_set_rate(spll_pfd0, new_freq * 1000);
+ clk_set_parent(sys_sel, spll_sel);
+ clk_set_parent(arm_clk, core_div);
+ if (old_freq > MAX_RUN_FREQ)
+ pm_qos_remove_request(&pm_qos_hsrun);
+ }
+
+ /* scaling down? scaling voltage after frequency */
+ if (new_freq < old_freq) {
+ ret = regulator_set_voltage_tol(arm_reg, volt, 0);
+ if (ret) {
+ dev_warn(cpu_dev, "failed to scale vddarm down: %d\n", ret);
+ ret = 0;
+ }
+ }
+
+ mutex_unlock(&set_cpufreq_lock);
+ return 0;
+}
+
+static int imx7ulp_cpufreq_init(struct cpufreq_policy *policy)
+{
+ int ret;
+ policy->clk = arm_clk;
+ policy->cur = clk_get_rate(arm_clk) / 1000;
+ policy->suspend_freq = freq_table[0].frequency;
+
+ ret = cpufreq_generic_init(policy, freq_table, transition_latency);
+
+ if (ret) {
+ dev_err(cpu_dev, "imx7ulp cpufreq init failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct cpufreq_driver imx7ulp_cpufreq_driver = {
+ .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
+ .verify = cpufreq_generic_frequency_table_verify,
+ .target_index = imx7ulp_set_target,
+ .get = cpufreq_generic_get,
+ .init = imx7ulp_cpufreq_init,
+ .name = "imx7ulp-cpufreq",
+ .attr = cpufreq_generic_attr,
+#ifdef CONFIG_PM
+ .suspend = cpufreq_generic_suspend,
+#endif
+};
+
+static int imx7ulp_cpufreq_probe(struct platform_device *pdev)
+{
+ struct device_node *np;
+ int ret;
+
+ cpu_dev = get_cpu_device(0);
+ if (!cpu_dev) {
+ pr_err("failed to get cpu0 device\n");
+ return -ENOENT;
+ }
+
+ np = of_node_get(cpu_dev->of_node);
+ if (!np) {
+ dev_err(cpu_dev, "failed to find the cpu0 node\n");
+ return -ENOENT;
+ }
+
+ arm_clk = clk_get(cpu_dev, "arm");
+ sys_sel = clk_get(cpu_dev, "sys_sel");
+ core_div = clk_get(cpu_dev, "core_div");
+ hsrun_sys_sel = clk_get(cpu_dev, "hsrun_sys_sel");
+ hsrun_core = clk_get(cpu_dev, "hsrun_core");
+ spll_pfd0 = clk_get(cpu_dev, "spll_pfd0");
+ spll_sel = clk_get(cpu_dev, "spll_sel");
+ firc_clk = clk_get(cpu_dev, "firc");
+ spll = clk_get(cpu_dev, "spll");
+
+ if (IS_ERR(arm_clk) || IS_ERR(sys_sel) || IS_ERR(spll_sel) ||
+ IS_ERR(spll_sel) || IS_ERR(firc_clk) || IS_ERR(hsrun_sys_sel) ||
+ IS_ERR(hsrun_core) || IS_ERR(spll)) {
+ dev_err(cpu_dev, "failed to get cpu clock\n");
+ ret = -ENOENT;
+ goto put_clk;
+ }
+
+ arm_reg = regulator_get(cpu_dev, "arm");
+ if (IS_ERR(arm_reg)) {
+ dev_err(cpu_dev, "failed to get regulator\n");
+ ret = -ENOENT;
+ goto put_reg;
+ }
+
+ ret = dev_pm_opp_of_add_table(cpu_dev);
+ if (ret < 0) {
+ dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);
+ goto put_reg;
+ }
+
+ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
+ if (ret) {
+ dev_err(cpu_dev, "failed to init cpufreq table\n");
+ goto put_reg;
+ }
+
+ if (of_property_read_u32(np, "clock-latency", &transition_latency))
+ transition_latency = CPUFREQ_ETERNAL;
+
+ mutex_init(&set_cpufreq_lock);
+ ret = cpufreq_register_driver(&imx7ulp_cpufreq_driver);
+ if (ret) {
+ dev_err(cpu_dev, "failed to register driver\n");
+ goto free_opp_table;
+ }
+
+ return 0;
+
+free_opp_table:
+ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
+put_reg:
+ regulator_put(arm_reg);
+put_clk:
+ if (!IS_ERR(arm_clk))
+ clk_put(arm_clk);
+ if (!IS_ERR(sys_sel))
+ clk_put(sys_sel);
+ if (!IS_ERR(core_div))
+ clk_put(core_div);
+ if (!IS_ERR(hsrun_sys_sel))
+ clk_put(hsrun_sys_sel);
+ if (!IS_ERR(hsrun_core))
+ clk_put(hsrun_core);
+ if (!IS_ERR(spll_pfd0))
+ clk_put(spll_pfd0);
+ if (!IS_ERR(spll_sel))
+ clk_put(spll_sel);
+ if (!IS_ERR(firc_clk))
+ clk_put(firc_clk);
+ if (!IS_ERR(spll))
+ clk_put(spll);
+
+ return ret;
+}
+
+static int imx7ulp_cpufreq_remove(struct platform_device *pdev)
+{
+ cpufreq_unregister_driver(&imx7ulp_cpufreq_driver);
+ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
+
+ regulator_put(arm_reg);
+ clk_put(arm_clk);
+ clk_put(sys_sel);
+ clk_put(core_div);
+ clk_put(hsrun_sys_sel);
+ clk_put(hsrun_core);
+ clk_put(spll_pfd0);
+ clk_put(spll_sel);
+ clk_put(firc_clk);
+ clk_put(spll);
+
+ return 0;
+}
+
+static struct platform_driver imx7ulp_cpufreq_platdrv = {
+ .driver = {
+ .name = "imx7ulp-cpufreq",
+ .owner = THIS_MODULE,
+ },
+ .probe = imx7ulp_cpufreq_probe,
+ .remove = imx7ulp_cpufreq_remove,
+};
+
+module_platform_driver(imx7ulp_cpufreq_platdrv);
+
+MODULE_DESCRIPTION("NXP i.MX7ULP cpufreq driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/cpufreq/imx8-cpufreq.c b/drivers/cpufreq/imx8-cpufreq.c
new file mode 100644
index 000000000000..e64b2b01d7ee
--- /dev/null
+++ b/drivers/cpufreq/imx8-cpufreq.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/cpu_cooling.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_opp.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/syscalls.h>
+#include <soc/imx/fsl_sip.h>
+
+#define MAX_CLUSTER_NUM 2
+
+static struct delayed_work cpufreq_governor_daemon;
+
+static DEFINE_SPINLOCK(cpufreq_psci_lock);
+
+struct imx8_cpufreq {
+ struct clk *cpu_clk;
+};
+
+struct imx8_cpufreq cluster_freq[MAX_CLUSTER_NUM];
+static struct cpufreq_frequency_table *freq_table[MAX_CLUSTER_NUM];
+static unsigned int transition_latency[MAX_CLUSTER_NUM];
+struct device *cpu_dev;
+static struct thermal_cooling_device *cdev[2];
+
+static void cpufreq_governor_daemon_handler(struct work_struct *work)
+{
+ int fd, i;
+ unsigned char cluster_governor[MAX_CLUSTER_NUM][54] = {
+ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor",
+ "",
+ };
+
+ /* generate second cluster's cpufreq governor path */
+ sprintf(cluster_governor[MAX_CLUSTER_NUM - 1],
+ "%s%d%s", "/sys/devices/system/cpu/cpu", num_online_cpus() - 1,
+ "/cpufreq/scaling_governor");
+
+ for (i = 0; i < MAX_CLUSTER_NUM; i++) {
+ fd = sys_open((const char __user __force *)cluster_governor[i],
+ O_RDWR, 0700);
+ if (fd >= 0) {
+ sys_write(fd, "schedutil", strlen("schedutil"));
+ sys_close(fd);
+ pr_info("switch cluster %d cpu-freq governor to schedutil\n",
+ i);
+ } else {
+ /* re-schedule if sys write is NOT ready */
+ schedule_delayed_work(&cpufreq_governor_daemon,
+ msecs_to_jiffies(3000));
+ break;
+ }
+ }
+}
+
+static int imx8_set_target(struct cpufreq_policy *policy, unsigned int index)
+{
+ struct arm_smccc_res res;
+ unsigned int old_freq, new_freq;
+ unsigned int cluster_id = topology_physical_package_id(policy->cpu);
+
+ new_freq = freq_table[cluster_id][index].frequency;
+ old_freq = policy->cur;
+
+ dev_dbg(cpu_dev, "%u MHz --> %u MHz\n",
+ old_freq / 1000, new_freq / 1000);
+
+ spin_lock(&cpufreq_psci_lock);
+ arm_smccc_smc(FSL_SIP_CPUFREQ, FSL_SIP_SET_CPUFREQ,
+ cluster_id, new_freq * 1000, 0, 0, 0, 0, &res);
+ spin_unlock(&cpufreq_psci_lock);
+
+ /*
+ * As we can only set CPU clock rate in ATF, clock
+ * framework does NOT know CPU clock rate is changed,
+ * so here do clk_get_rate once to update CPU clock
+ * rate, otherwise cat /sys/kernel/debug/clk/xxx/clk_rate
+ * will return incorrect rate as it does NOT do a
+ * recalculation.
+ */
+ clk_get_rate(cluster_freq[cluster_id].cpu_clk);
+
+ return 0;
+}
+
+static int imx8_cpufreq_init(struct cpufreq_policy *policy)
+{
+ int cluster_id = topology_physical_package_id(policy->cpu);
+ int ret = 0;
+
+ policy->clk = cluster_freq[cluster_id].cpu_clk;
+ policy->cur = clk_get_rate(cluster_freq[cluster_id].cpu_clk) / 1000;
+ /*
+ * The driver only supports the SMP configuartion where all processors
+ * share the clock and voltage and clock.
+ */
+ cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
+
+ ret = cpufreq_table_validate_and_show(policy, freq_table[cluster_id]);
+ if (ret) {
+ pr_err("%s: invalid frequency table: %d\n", __func__, ret);
+ return ret;
+ }
+
+ policy->cpuinfo.transition_latency = transition_latency[cluster_id];
+ policy->suspend_freq = policy->max;
+
+ pr_info("%s: cluster %d running at freq %d MHz, suspend freq %d MHz\n",
+ __func__, cluster_id, policy->cur / 1000,
+ policy->suspend_freq / 1000);
+
+ return ret;
+}
+
+static void imx8_cpufreq_ready(struct cpufreq_policy *policy)
+{
+ struct device_node *np = of_get_cpu_node(policy->cpu, NULL);
+ unsigned int cluster_id = topology_physical_package_id(policy->cpu);
+
+ if (of_find_property(np, "#cooling-cells", NULL)) {
+ cdev[cluster_id] = of_cpufreq_cooling_register(np,
+ policy->related_cpus);
+
+ if (IS_ERR(cdev[cluster_id]) && PTR_ERR(cdev[cluster_id]) != -ENOSYS) {
+ pr_err("cpu%d is not running as cooling device: %ld\n",
+ policy->cpu, PTR_ERR(cdev[cluster_id]));
+
+ cdev[cluster_id] = NULL;
+ }
+ }
+
+ of_node_put(np);
+}
+
+static struct cpufreq_driver imx8_cpufreq_driver = {
+ .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
+ .verify = cpufreq_generic_frequency_table_verify,
+ .target_index = imx8_set_target,
+ .get = cpufreq_generic_get,
+ .init = imx8_cpufreq_init,
+ .name = "imx8-cpufreq",
+ .attr = cpufreq_generic_attr,
+ .ready = imx8_cpufreq_ready,
+#ifdef CONFIG_PM
+ .suspend = cpufreq_generic_suspend,
+#endif
+};
+
+static int imx8_cpufreq_probe(struct platform_device *pdev)
+{
+ struct device_node *np;
+ int ret = 0;
+ int i, cluster_id;
+ struct device *first_cpu_dev = NULL;
+
+ cpu_dev = get_cpu_device(0);
+
+ if (!cpu_dev) {
+ pr_err("failed to get cpu device 0\n");
+ return -ENODEV;
+ }
+
+ np = of_node_get(cpu_dev->of_node);
+ if (!np) {
+ pr_warn("failed to find cpu 0 node\n");
+ return -ENODEV;
+ }
+
+ ret = dev_pm_opp_of_add_table(cpu_dev);
+ if (ret < 0) {
+ dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);
+ goto put_node;
+ }
+
+ cluster_id = topology_physical_package_id(0);
+ cluster_freq[cluster_id].cpu_clk = devm_clk_get(cpu_dev, NULL);
+ if (IS_ERR(cluster_freq[cluster_id].cpu_clk)) {
+ dev_err(cpu_dev, "failed to get cluster %d clock\n", cluster_id);
+ ret = -ENOENT;
+ goto put_node;
+ }
+
+ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table[cluster_id]);
+ if (ret) {
+ dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
+ goto out_free_opp;
+ }
+
+ if (of_property_read_u32(np, "clock-latency", &transition_latency[cluster_id]))
+ transition_latency[cluster_id] = CPUFREQ_ETERNAL;
+
+ /* init next cluster if there is */
+ for (i = 1; i < num_online_cpus(); i++) {
+ if (topology_physical_package_id(i) == topology_physical_package_id(0))
+ continue;
+
+ INIT_DELAYED_WORK(&cpufreq_governor_daemon,
+ cpufreq_governor_daemon_handler);
+ schedule_delayed_work(&cpufreq_governor_daemon,
+ msecs_to_jiffies(3000));
+ first_cpu_dev = cpu_dev;
+ cpu_dev = get_cpu_device(i);
+ if (!cpu_dev) {
+ pr_err("failed to get cpu device %d\n", i);
+ return -ENODEV;
+ }
+
+ np = of_node_get(cpu_dev->of_node);
+ if (!np) {
+ pr_warn("failed to find cpu %d node\n", i);
+ ret = -ENODEV;
+ goto put_node;
+ }
+
+ cluster_id = topology_physical_package_id(i);
+ cluster_freq[cluster_id].cpu_clk = devm_clk_get(cpu_dev, NULL);
+ if (IS_ERR(cluster_freq[cluster_id].cpu_clk)) {
+ dev_err(cpu_dev, "failed to get cluster %d clock\n", cluster_id);
+ ret = -ENOENT;
+ goto put_node;
+ }
+
+ ret = dev_pm_opp_of_add_table(cpu_dev);
+ if (ret < 0) {
+ dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);
+ goto put_node;
+ }
+
+ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table[cluster_id]);
+ if (ret) {
+ dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
+ goto out_free_opp;
+ }
+
+ if (of_property_read_u32(np, "clock-latency", &transition_latency[cluster_id]))
+ transition_latency[cluster_id] = CPUFREQ_ETERNAL;
+ break;
+ }
+
+ ret = cpufreq_register_driver(&imx8_cpufreq_driver);
+ if (ret) {
+ dev_err(cpu_dev, "failed register driver: %d\n", ret);
+ if (cluster_id > 0 && first_cpu_dev != NULL) {
+ dev_pm_opp_free_cpufreq_table(first_cpu_dev, &freq_table[0]);
+ dev_pm_opp_of_remove_table(first_cpu_dev);
+ }
+ goto free_freq_table;
+ }
+
+ of_node_put(np);
+
+ return 0;
+
+free_freq_table:
+ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster_id]);
+out_free_opp:
+ dev_pm_opp_of_remove_table(cpu_dev);
+put_node:
+ of_node_put(np);
+ return ret;
+}
+
+static int imx8_cpufreq_remove(struct platform_device *pdev)
+{
+ cpufreq_unregister_driver(&imx8_cpufreq_driver);
+
+ return 0;
+}
+
+static struct platform_driver imx8_cpufreq_platdrv = {
+ .driver = {
+ .name = "imx8-cpufreq",
+ },
+ .probe = imx8_cpufreq_probe,
+ .remove = imx8_cpufreq_remove,
+};
+module_platform_driver(imx8_cpufreq_platdrv);
+
+MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
+MODULE_DESCRIPTION("NXP i.MX8 cpufreq driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/imx8mq-cpufreq.c b/drivers/cpufreq/imx8mq-cpufreq.c
new file mode 100644
index 000000000000..95f694d34f4a
--- /dev/null
+++ b/drivers/cpufreq/imx8mq-cpufreq.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/cpu_cooling.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/pm_opp.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/suspend.h>
+
+#define DC_VOLTAGE_MIN 900000
+#define DC_VOLTAGE_MAX 1000000
+
+static struct device *cpu_dev;
+static bool free_opp;
+static struct cpufreq_frequency_table *freq_table;
+static struct mutex set_cpufreq_lock;
+static unsigned int transition_latency;
+static struct clk *a53_clk;
+static struct clk *arm_a53_src_clk;
+static struct clk *arm_pll_clk;
+static struct clk *arm_pll_out_clk;
+static struct clk *sys1_pll_800m_clk;
+struct thermal_cooling_device *cdev;
+static struct regulator *dc_reg;
+static struct regulator *arm_reg;
+
+static int imx8mq_set_target(struct cpufreq_policy *policy, unsigned int index)
+{
+ struct dev_pm_opp *opp;
+ unsigned long freq_hz, volt;
+ unsigned int old_freq, new_freq;
+ int ret;
+
+ mutex_lock(&set_cpufreq_lock);
+
+ new_freq = freq_table[index].frequency;
+ freq_hz = new_freq * 1000;
+ old_freq = policy->cur;
+
+ rcu_read_lock();
+ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
+ mutex_unlock(&set_cpufreq_lock);
+ return PTR_ERR(opp);
+ }
+ volt = dev_pm_opp_get_voltage(opp);
+ rcu_read_unlock();
+
+ dev_dbg(cpu_dev, "%u MHz --> %u MHz\n",
+ old_freq / 1000, new_freq / 1000);
+
+ if (new_freq == policy->max) {
+ if (!IS_ERR(dc_reg)) {
+ ret = regulator_set_voltage_tol(dc_reg, DC_VOLTAGE_MAX, 0);
+ if (ret) {
+ dev_err(cpu_dev, "failed to scale dc_reg up: %d\n", ret);
+ mutex_unlock(&set_cpufreq_lock);
+ return ret;
+ }
+ }
+ }
+
+ if (new_freq > old_freq) {
+ if (!IS_ERR(arm_reg)) {
+ ret = regulator_set_voltage_tol(arm_reg, volt, 0);
+ if (ret) {
+ dev_err(cpu_dev, "failed to scale arm_reg up: %d\n", ret);
+ mutex_unlock(&set_cpufreq_lock);
+ return ret;
+ }
+ }
+ }
+
+ clk_set_parent(arm_a53_src_clk, sys1_pll_800m_clk);
+ clk_set_rate(arm_pll_clk, new_freq * 1000);
+ clk_set_parent(arm_a53_src_clk, arm_pll_out_clk);
+
+ if (old_freq == policy->max) {
+ if (!IS_ERR(dc_reg)) {
+ ret = regulator_set_voltage_tol(dc_reg, DC_VOLTAGE_MIN, 0);
+ if (ret) {
+ dev_err(cpu_dev, "failed to scale dc_reg down: %d\n", ret);
+ mutex_unlock(&set_cpufreq_lock);
+ return ret;
+ }
+ }
+ }
+
+ if (new_freq < old_freq) {
+ if (!IS_ERR(arm_reg)) {
+ ret = regulator_set_voltage_tol(arm_reg, volt, 0);
+ if (ret) {
+ dev_err(cpu_dev, "failed to scale arm_reg down: %d\n", ret);
+ mutex_unlock(&set_cpufreq_lock);
+ return ret;
+ }
+ }
+ }
+
+ /* Ensure the arm clock divider is what we expect */
+ ret = clk_set_rate(a53_clk, new_freq * 1000);
+ if (ret)
+ dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
+
+ mutex_unlock(&set_cpufreq_lock);
+ return ret;
+}
+
+static void imx8mq_cpufreq_ready(struct cpufreq_policy *policy)
+{
+ struct device_node *np = of_get_cpu_node(policy->cpu, NULL);
+
+ if (of_find_property(np, "#cooling-cells", NULL)) {
+ cdev = of_cpufreq_cooling_register(np,
+ policy->related_cpus);
+
+ if (IS_ERR(cdev) && PTR_ERR(cdev) != -ENOSYS) {
+ pr_err("cpu%d is not running as cooling device: %ld\n",
+ policy->cpu, PTR_ERR(cdev));
+
+ cdev = NULL;
+ }
+ }
+
+ of_node_put(np);
+}
+
+static int imx8mq_cpufreq_init(struct cpufreq_policy *policy)
+{
+ int ret;
+
+ policy->clk = a53_clk;
+ policy->cur = clk_get_rate(a53_clk) / 1000;
+
+ ret = cpufreq_generic_init(policy, freq_table, transition_latency);
+ if (ret) {
+ dev_err(cpu_dev, "imx8mq cpufreq init failed!\n");
+ return ret;
+ }
+
+ policy->suspend_freq = policy->max;
+
+ return 0;
+}
+
+static struct cpufreq_driver imx8mq_cpufreq_driver = {
+ .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
+ .verify = cpufreq_generic_frequency_table_verify,
+ .target_index = imx8mq_set_target,
+ .get = cpufreq_generic_get,
+ .init = imx8mq_cpufreq_init,
+ .name = "imx8mq-cpufreq",
+ .ready = imx8mq_cpufreq_ready,
+ .attr = cpufreq_generic_attr,
+#ifdef CONFIG_PM
+ .suspend = cpufreq_generic_suspend,
+#endif
+};
+
+static int imx8mq_cpufreq_probe(struct platform_device *pdev)
+{
+ struct device_node *np;
+ int ret, num;
+
+ cpu_dev = get_cpu_device(0);
+ if (!cpu_dev) {
+ pr_err("failed to get cpu0 device\n");
+ return -ENODEV;
+ }
+
+ np = of_node_get(cpu_dev->of_node);
+ if (!np) {
+ dev_err(cpu_dev, "failed to find cpu0 node\n");
+ return -ENOENT;
+ }
+
+ a53_clk = clk_get(cpu_dev, "a53");
+ arm_a53_src_clk = clk_get(cpu_dev, "arm_a53_src");
+ arm_pll_clk = clk_get(cpu_dev, "arm_pll");
+ arm_pll_out_clk = clk_get(cpu_dev, "arm_pll_out");
+ sys1_pll_800m_clk = clk_get(cpu_dev, "sys1_pll_800m");
+ if (IS_ERR(a53_clk) || IS_ERR(arm_a53_src_clk)
+ || IS_ERR(arm_pll_out_clk) || IS_ERR(arm_pll_clk)
+ || IS_ERR(sys1_pll_800m_clk)) {
+ dev_err(cpu_dev, "failed to get clocks\n");
+ ret = -ENOENT;
+ goto put_clk;
+ }
+
+ dc_reg = regulator_get_optional(cpu_dev, "dc");
+ arm_reg = regulator_get_optional(cpu_dev, "arm");
+
+ /*
+ * We expect an OPP table supplied by platform.
+ * Just, incase the platform did not supply the OPP
+ * table, it will try to get it.
+ */
+ num = dev_pm_opp_get_opp_count(cpu_dev);
+ if (num < 0) {
+ ret = dev_pm_opp_of_add_table(cpu_dev);
+ if (ret < 0) {
+ dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);
+ goto put_clk;
+ }
+ }
+
+ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
+ if (ret) {
+ dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
+ goto out_free_opp;
+ }
+
+ if (of_property_read_u32(np, "clock-latency", &transition_latency))
+ transition_latency = CPUFREQ_ETERNAL;
+
+ mutex_init(&set_cpufreq_lock);
+
+ ret = cpufreq_register_driver(&imx8mq_cpufreq_driver);
+ if (ret) {
+ dev_err(cpu_dev, "failed register driver: %d\n", ret);
+ goto free_freq_table;
+ }
+
+ of_node_put(np);
+ dev_info(cpu_dev, "registered imx8mq-cpufreq\n");
+
+ return 0;
+
+free_freq_table:
+ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
+out_free_opp:
+ dev_pm_opp_of_remove_table(cpu_dev);
+put_clk:
+ if (!IS_ERR(a53_clk))
+ clk_put(a53_clk);
+ if (!IS_ERR(arm_a53_src_clk))
+ clk_put(arm_a53_src_clk);
+ if (!IS_ERR(arm_pll_clk))
+ clk_put(arm_pll_clk);
+ if (!IS_ERR(arm_pll_out_clk))
+ clk_put(arm_pll_out_clk);
+ if (!IS_ERR(sys1_pll_800m_clk))
+ clk_put(sys1_pll_800m_clk);
+ of_node_put(np);
+ return ret;
+}
+
+static int imx8mq_cpufreq_remove(struct platform_device *pdev)
+{
+ cpufreq_cooling_unregister(cdev);
+ cpufreq_unregister_driver(&imx8mq_cpufreq_driver);
+ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
+ if (free_opp)
+ dev_pm_opp_of_remove_table(cpu_dev);
+ clk_put(a53_clk);
+ clk_put(arm_a53_src_clk);
+ clk_put(arm_pll_clk);
+ clk_put(arm_pll_out_clk);
+ clk_put(sys1_pll_800m_clk);
+
+ return 0;
+}
+
+static struct platform_driver imx8mq_cpufreq_platdrv = {
+ .driver = {
+ .name = "imx8mq-cpufreq",
+ },
+ .probe = imx8mq_cpufreq_probe,
+ .remove = imx8mq_cpufreq_remove,
+};
+module_platform_driver(imx8mq_cpufreq_platdrv);
+
+MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
+MODULE_DESCRIPTION("Freescale i.MX8MQ cpufreq driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig
index 64bf3024b680..e3803d142e21 100644
--- a/drivers/crypto/caam/Kconfig
+++ b/drivers/crypto/caam/Kconfig
@@ -79,6 +79,7 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API
select CRYPTO_AEAD
select CRYPTO_AUTHENC
select CRYPTO_BLKCIPHER
+ select CRYPTO_DES
help
Selecting this will offload crypto for users of the
scatterlist crypto API (such as the linux native IPSec
@@ -125,9 +126,60 @@ config CRYPTO_DEV_FSL_CAAM_RNG_API
will be called caamrng.
config CRYPTO_DEV_FSL_CAAM_IMX
- def_bool SOC_IMX6 || SOC_IMX7D
+ def_bool SOC_IMX6 || SOC_IMX7D || HAVE_IMX8_SOC
depends on CRYPTO_DEV_FSL_CAAM
+
+config CRYPTO_DEV_FSL_CAAM_RNG_TEST
+ boolean "Test caam rng"
+ depends on CRYPTO_DEV_FSL_CAAM_RNG_API
+ default n
+ help
+ Selecting this will enable a self-test to run for the
+ caam RNG. This test is several minutes long and executes
+ just before the RNG is registered with the hw_random API.
+
+config CRYPTO_DEV_FSL_CAAM_SM
+ tristate "CAAM Secure Memory / Keystore API (EXPERIMENTAL)"
+ default n
+ help
+ Enables use of a prototype kernel-level Keystore API with CAAM
+ Secure Memory for insertion/extraction of bus-protected secrets.
+
+config CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE
+ int "Size of each keystore slot in Secure Memory"
+ depends on CRYPTO_DEV_FSL_CAAM_SM
+ range 5 9
+ default 7
+ help
+ Select size of allocation units to divide Secure Memory pages into
+ (the size of a "slot" as referenced inside the API code).
+ Established as powers of two.
+ Examples:
+ 5 => 32 bytes
+ 6 => 64 bytes
+ 7 => 128 bytes
+ 8 => 256 bytes
+ 9 => 512 bytes
+
+config CRYPTO_DEV_FSL_CAAM_SM_TEST
+ tristate "CAAM Secure Memory - Keystore Test/Example (EXPERIMENTAL)"
+ depends on CRYPTO_DEV_FSL_CAAM_SM
+ default n
+ help
+ Example thread to exercise the Keystore API and to verify that
+ stored and recovered secrets can be used for general purpose
+ encryption/decryption.
+
+config CRYPTO_DEV_FSL_CAAM_SECVIO
+ tristate "CAAM/SNVS Security Violation Handler (EXPERIMENTAL)"
+ depends on CRYPTO_DEV_FSL_CAAM
+ default n
+ help
+ Enables installation of an interrupt handler with registrable
+ handler functions which can be specified to act on the consequences
+ of a security violation.
+
config CRYPTO_DEV_FSL_CAAM_DEBUG
bool "Enable debug output in CAAM driver"
depends on CRYPTO_DEV_FSL_CAAM
diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile
index 08bf5515ae8a..f445fd483997 100644
--- a/drivers/crypto/caam/Makefile
+++ b/drivers/crypto/caam/Makefile
@@ -11,7 +11,10 @@ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caam_pkc.o
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM) += sm_store.o
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST) += sm_test.o
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO) += secvio.o
caam-objs := ctrl.o
-caam_jr-objs := jr.o key_gen.o error.o
+caam_jr-objs := jr.o key_gen.o error.o inst_rng.o
caam_pkc-y := caampkc.o pkc_desc.o
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index 0d743c634f25..3e43c8787edb 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -1,7 +1,8 @@
/*
* caam - Freescale FSL CAAM support for crypto API
*
- * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright 2008-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
*
* Based on talitos crypto API driver.
*
@@ -163,6 +164,9 @@ struct caam_aead_alg {
bool registered;
};
+static uint8_t *ecb_zero_iv;
+static dma_addr_t ecb_ziv_dma;
+
/* Set DK bit in class 1 operation if shared */
static inline void append_dec_op1(u32 *desc, u32 type)
{
@@ -1755,6 +1759,33 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
return ret;
}
+
+static int ablkcipher_des_setkey(struct crypto_ablkcipher *ablkcipher,
+ const u8 *key, unsigned int keylen)
+{
+ u32 tmp[DES_EXPKEY_WORDS];
+ u32 flags;
+ int ret;
+
+ if (keylen != DES_KEY_SIZE) {
+ crypto_ablkcipher_set_flags(ablkcipher,
+ CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+
+ ret = des_ekey(tmp, key);
+
+ flags = crypto_ablkcipher_get_flags(ablkcipher);
+ if (!ret && (flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+ crypto_ablkcipher_set_flags(ablkcipher,
+ CRYPTO_TFM_RES_WEAK_KEY);
+ return -EINVAL;
+ }
+
+ return ablkcipher_setkey(ablkcipher, key, keylen);
+}
+
+
static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
const u8 *key, unsigned int keylen)
{
@@ -2015,7 +2046,10 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
struct ablkcipher_request *req = context;
struct ablkcipher_edesc *edesc;
struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
+ struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
+ int bsize = crypto_ablkcipher_blocksize(ablkcipher);
int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+ size_t ivcopy = min_t(size_t, bsize, ivsize);
#ifdef DEBUG
dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
@@ -2047,6 +2081,12 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
kfree(edesc);
+ /* Pass IV along for cbc */
+ if ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == OP_ALG_AAI_CBC) {
+ scatterwalk_map_and_copy(req->info, req->dst,
+ req->nbytes - bsize, ivcopy, 0);
+ }
+
ablkcipher_request_complete(req, err);
}
@@ -2626,6 +2666,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
int sgc;
int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
int sec4_sg_index;
+ uint32_t c1_alg_typ = ctx->class1_alg_type;
src_nents = sg_count(req->src, req->nbytes);
@@ -2642,10 +2683,17 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
DMA_FROM_DEVICE);
}
- iv_dma = dma_map_single(jrdev, req->info, ivsize, DMA_TO_DEVICE);
- if (dma_mapping_error(jrdev, iv_dma)) {
- dev_err(jrdev, "unable to map IV\n");
- return ERR_PTR(-ENOMEM);
+ if ((!req->info && ivsize) &&
+ ((c1_alg_typ & OP_ALG_ALGSEL_MASK) == OP_ALG_ALGSEL_AES) &&
+ ((c1_alg_typ & OP_ALG_AAI_MASK) == OP_ALG_AAI_ECB)) {
+ iv_dma = ecb_ziv_dma;
+ } else {
+ iv_dma = dma_map_single(jrdev, req->info, ivsize,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(jrdev, iv_dma)) {
+ dev_err(jrdev, "unable to map IV\n");
+ return ERR_PTR(-ENOMEM);
+ }
}
/*
@@ -2956,6 +3004,22 @@ static struct caam_alg_template driver_algs[] = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
},
{
+ .name = "ecb(aes)",
+ .driver_name = "ecb-aes-caam",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ablkcipher_setkey,
+ .encrypt = ablkcipher_encrypt,
+ .decrypt = ablkcipher_decrypt,
+ .geniv = "eseqiv",
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_ECB,
+ },
+ {
.name = "cbc(des3_ede)",
.driver_name = "cbc-3des-caam",
.blocksize = DES3_EDE_BLOCK_SIZE,
@@ -2973,6 +3037,22 @@ static struct caam_alg_template driver_algs[] = {
.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
},
{
+ .name = "ecb(des3_ede)",
+ .driver_name = "ecb-des3-caam",
+ .blocksize = DES3_EDE_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ablkcipher_setkey,
+ .encrypt = ablkcipher_encrypt,
+ .decrypt = ablkcipher_decrypt,
+ .geniv = "eseqiv",
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_ECB,
+ },
+ {
.name = "cbc(des)",
.driver_name = "cbc-des-caam",
.blocksize = DES_BLOCK_SIZE,
@@ -2990,6 +3070,22 @@ static struct caam_alg_template driver_algs[] = {
.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
},
{
+ .name = "ecb(des)",
+ .driver_name = "ecb-des-caam",
+ .blocksize = DES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ablkcipher_des_setkey,
+ .encrypt = ablkcipher_encrypt,
+ .decrypt = ablkcipher_decrypt,
+ .geniv = "eseqiv",
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_ECB,
+ },
+ {
.name = "ctr(aes)",
.driver_name = "ctr-aes-caam",
.blocksize = 1,
@@ -3040,6 +3136,23 @@ static struct caam_alg_template driver_algs[] = {
},
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS,
},
+ {
+ .name = "ecb(arc4)",
+ .driver_name = "ecb-arc4-caam",
+ .blocksize = ARC4_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ablkcipher_setkey,
+ .encrypt = ablkcipher_encrypt,
+ .decrypt = ablkcipher_decrypt,
+ .geniv = "eseqiv",
+ .min_keysize = ARC4_MIN_KEY_SIZE,
+ .max_keysize = ARC4_MAX_KEY_SIZE,
+ .ivsize = ARC4_BLOCK_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_ARC4 | OP_ALG_AAI_ECB
+ },
+
};
static struct caam_aead_alg driver_aeads[] = {
@@ -4455,10 +4568,35 @@ static void caam_aead_exit(struct crypto_aead *tfm)
static void __exit caam_algapi_exit(void)
{
-
+ struct device_node *dev_node;
+ struct platform_device *pdev;
+ struct device *ctrldev;
struct caam_crypto_alg *t_alg, *n;
int i;
+ if (!ecb_zero_iv)
+ goto skip_ecb_ziv;
+
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+ if (!dev_node)
+ goto skip_ecb_ziv;
+ }
+
+ pdev = of_find_device_by_node(dev_node);
+
+ if (!pdev) {
+ of_node_put(dev_node);
+ goto skip_ecb_ziv;
+ }
+
+ ctrldev = &pdev->dev;
+
+ dma_unmap_single(ctrldev, ecb_ziv_dma, AES_BLOCK_SIZE, DMA_TO_DEVICE);
+ kfree(ecb_zero_iv);
+
+skip_ecb_ziv:
for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) {
struct caam_aead_alg *t_alg = driver_aeads + i;
@@ -4500,8 +4638,12 @@ static struct caam_crypto_alg *caam_alg_alloc(struct caam_alg_template
alg->cra_blocksize = template->blocksize;
alg->cra_alignmask = 0;
alg->cra_ctxsize = sizeof(struct caam_ctx);
- alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY |
- template->type;
+ alg->cra_flags = CRYPTO_ALG_ASYNC | template->type;
+
+#ifdef CRYPTO_ALG_KERN_DRIVER_ONLY
+ alg->cra_flags |= CRYPTO_ALG_KERN_DRIVER_ONLY;
+#endif
+
switch (template->type) {
case CRYPTO_ALG_TYPE_GIVCIPHER:
alg->cra_type = &crypto_givcipher_type;
@@ -4568,6 +4710,16 @@ static int __init caam_algapi_init(void)
if (!priv)
return -ENODEV;
+ ecb_zero_iv = kzalloc(AES_BLOCK_SIZE, GFP_KERNEL);
+ if (!ecb_zero_iv)
+ return -ENOMEM;
+
+ ecb_ziv_dma = dma_map_single(ctrldev, ecb_zero_iv, AES_BLOCK_SIZE,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ctrldev, ecb_ziv_dma)) {
+ kfree(ecb_zero_iv);
+ return -ENOMEM;
+ }
INIT_LIST_HEAD(&alg_list);
@@ -4575,8 +4727,14 @@ static int __init caam_algapi_init(void)
* Register crypto algorithms the device supports.
* First, detect presence and attributes of DES, AES, and MD blocks.
*/
- cha_vid = rd_reg32(&priv->ctrl->perfmon.cha_id_ls);
- cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls);
+ if (priv->has_seco) {
+ i = priv->first_jr_index;
+ cha_vid = rd_reg32(&priv->jr[i]->perfmon.cha_id_ls);
+ cha_inst = rd_reg32(&priv->jr[i]->perfmon.cha_num_ls);
+ } else {
+ cha_vid = rd_reg32(&priv->ctrl->perfmon.cha_id_ls);
+ cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls);
+ }
des_inst = (cha_inst & CHA_ID_LS_DES_MASK) >> CHA_ID_LS_DES_SHIFT;
aes_inst = (cha_inst & CHA_ID_LS_AES_MASK) >> CHA_ID_LS_AES_SHIFT;
md_inst = (cha_inst & CHA_ID_LS_MD_MASK) >> CHA_ID_LS_MD_SHIFT;
diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c
index 631337c2e4a7..c3987747138d 100644
--- a/drivers/crypto/caam/caamhash.c
+++ b/drivers/crypto/caam/caamhash.c
@@ -1,7 +1,7 @@
/*
* caam - Freescale FSL CAAM support for ahash functions of crypto API
*
- * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
*
* Based on caamalg.c crypto API driver.
*
@@ -62,6 +62,7 @@
#include "error.h"
#include "sg_sw_sec4.h"
#include "key_gen.h"
+#include <linux/string.h>
#define CAAM_CRA_PRIORITY 3000
@@ -115,6 +116,7 @@ struct caam_hash_ctx {
u8 key[CAAM_MAX_HASH_KEY_SIZE];
dma_addr_t key_dma;
int ctx_len;
+ unsigned int key_len;
unsigned int split_key_len;
unsigned int split_key_pad_len;
};
@@ -232,6 +234,13 @@ static inline void append_key_ahash(u32 *desc, struct caam_hash_ctx *ctx)
KEY_DEST_MDHA_SPLIT | KEY_ENC);
}
+static inline void append_key_axcbc(u32 *desc, struct caam_hash_ctx *ctx)
+{
+ append_key_as_imm(desc, ctx->key, ctx->key_len,
+ ctx->key_len, CLASS_1 |
+ KEY_DEST_CLASS_REG);
+}
+
/* Append key if it has been set */
static inline void init_sh_desc_key_ahash(u32 *desc, struct caam_hash_ctx *ctx)
{
@@ -253,6 +262,25 @@ static inline void init_sh_desc_key_ahash(u32 *desc, struct caam_hash_ctx *ctx)
append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD);
}
+static inline void init_sh_desc_key_axcbc(u32 *desc, struct caam_hash_ctx *ctx)
+{
+ u32 *key_jump_cmd;
+
+ init_sh_desc(desc, HDR_SHARE_SERIAL);
+
+ if (ctx->key_len) {
+ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
+ JUMP_COND_SHRD);
+
+ append_key_axcbc(desc, ctx);
+
+ set_jump_tgt_here(desc, key_jump_cmd);
+ }
+
+ /* Propagate errors from shared to job descriptor */
+ append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD);
+
+}
/*
* For ahash read data from seqin following state->caam_ctx,
* and write resulting class2 context to seqout, which may be state->caam_ctx
@@ -272,6 +300,20 @@ static inline void ahash_append_load_str(u32 *desc, int digestsize)
LDST_SRCDST_BYTE_CONTEXT);
}
+static inline void axcbc_append_load_str(u32 *desc, int digestsize)
+{
+ /* Calculate remaining bytes to read */
+ append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ);
+
+ /* Read remaining bytes */
+ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_LAST1 |
+ FIFOLD_TYPE_MSG | KEY_VLF);
+
+ /* Store class1 context bytes */
+ append_seq_store(desc, digestsize, LDST_CLASS_1_CCB |
+ LDST_SRCDST_BYTE_CONTEXT);
+}
+
/*
* For ahash update, final and finup, import context, read and write to seqout
*/
@@ -294,6 +336,27 @@ static inline void ahash_ctx_data_to_out(u32 *desc, u32 op, u32 state,
ahash_append_load_str(desc, digestsize);
}
+/*
+ * For ahash update, final and finup, import context, read and write to seqout
+ */
+static inline void axcbc_ctx_data_to_out(u32 *desc, u32 op, u32 state,
+ int digestsize,
+ struct caam_hash_ctx *ctx)
+{
+ init_sh_desc_key_axcbc(desc, ctx);
+
+ /* Import context from software */
+ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT |
+ LDST_CLASS_1_CCB | ctx->ctx_len);
+
+ /* Class 1 operation */
+ append_operation(desc, op | state | OP_ALG_ENCRYPT);
+
+ /*
+ * Load from buf and/or src and write to req->result or state->context
+ */
+ axcbc_append_load_str(desc, digestsize);
+}
/* For ahash firsts and digest, read and write to seqout */
static inline void ahash_data_to_out(u32 *desc, u32 op, u32 state,
int digestsize, struct caam_hash_ctx *ctx)
@@ -309,6 +372,21 @@ static inline void ahash_data_to_out(u32 *desc, u32 op, u32 state,
ahash_append_load_str(desc, digestsize);
}
+/* For ahash firsts and digest, read and write to seqout */
+static inline void axcbc_data_to_out(u32 *desc, u32 op, u32 state,
+ int digestsize, struct caam_hash_ctx *ctx)
+{
+ init_sh_desc_key_axcbc(desc, ctx);
+
+ /* Class 1 operation */
+ append_operation(desc, op | state | OP_ALG_ENCRYPT);
+
+ /*
+ * Load from buf and/or src and write to req->result or state->context
+ */
+ axcbc_append_load_str(desc, digestsize);
+}
+
static int ahash_set_sh_desc(struct crypto_ahash *ahash)
{
struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
@@ -426,6 +504,124 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
return 0;
}
+static int axcbc_set_sh_desc(struct crypto_ahash *ahash)
+{
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ int digestsize = crypto_ahash_digestsize(ahash);
+ struct device *jrdev = ctx->jrdev;
+ u32 have_key = 0;
+ u32 *desc;
+
+ /* ahash_update shared descriptor */
+ desc = ctx->sh_desc_update;
+
+ init_sh_desc(desc, HDR_SHARE_SERIAL);
+
+ /* Import context from software */
+ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT |
+ LDST_CLASS_1_CCB | ctx->ctx_len);
+
+ /* Class 1 operation */
+ append_operation(desc, ctx->alg_type | OP_ALG_AS_UPDATE |
+ OP_ALG_ENCRYPT);
+
+ /* Load data and write to result or context */
+ axcbc_append_load_str(desc, ctx->ctx_len);
+
+ ctx->sh_desc_update_dma = dma_map_single(jrdev, desc, desc_bytes(desc),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(jrdev, ctx->sh_desc_update_dma)) {
+ dev_err(jrdev, "unable to map shared descriptor\n");
+ return -ENOMEM;
+ }
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR, "ahash update shdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
+#endif
+
+ /* ahash_update_first shared descriptor */
+ desc = ctx->sh_desc_update_first;
+
+ axcbc_data_to_out(desc, have_key | ctx->alg_type, OP_ALG_AS_INIT,
+ ctx->ctx_len, ctx);
+
+ ctx->sh_desc_update_first_dma = dma_map_single(jrdev, desc,
+ desc_bytes(desc),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(jrdev, ctx->sh_desc_update_first_dma)) {
+ dev_err(jrdev, "unable to map shared descriptor\n");
+ return -ENOMEM;
+ }
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR, "ahash update first shdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
+#endif
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma,
+ desc_bytes(desc), DMA_TO_DEVICE);
+
+ /* ahash_final shared descriptor */
+ desc = ctx->sh_desc_fin;
+
+ axcbc_ctx_data_to_out(desc, have_key | ctx->alg_type,
+ OP_ALG_AS_FINALIZE, digestsize, ctx);
+
+ ctx->sh_desc_fin_dma = dma_map_single(jrdev, desc, desc_bytes(desc),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(jrdev, ctx->sh_desc_fin_dma)) {
+ dev_err(jrdev, "unable to map shared descriptor\n");
+ return -ENOMEM;
+ }
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR, "ahash final shdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc,
+ desc_bytes(desc), 1);
+#endif
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma,
+ desc_bytes(desc), DMA_TO_DEVICE);
+
+ /* ahash_finup shared descriptor */
+ desc = ctx->sh_desc_finup;
+
+ axcbc_ctx_data_to_out(desc, have_key | ctx->alg_type,
+ OP_ALG_AS_FINALIZE, digestsize, ctx);
+
+ ctx->sh_desc_finup_dma = dma_map_single(jrdev, desc, desc_bytes(desc),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(jrdev, ctx->sh_desc_finup_dma)) {
+ dev_err(jrdev, "unable to map shared descriptor\n");
+ return -ENOMEM;
+ }
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR, "ahash finup shdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc,
+ desc_bytes(desc), 1);
+#endif
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_finup_dma,
+ desc_bytes(desc), DMA_TO_DEVICE);
+
+ /* ahash_digest shared descriptor */
+ desc = ctx->sh_desc_digest;
+
+ axcbc_data_to_out(desc, have_key | ctx->alg_type, OP_ALG_AS_INITFINAL,
+ digestsize, ctx);
+
+ ctx->sh_desc_digest_dma = dma_map_single(jrdev, desc,
+ desc_bytes(desc),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(jrdev, ctx->sh_desc_digest_dma)) {
+ dev_err(jrdev, "unable to map shared descriptor\n");
+ return -ENOMEM;
+ }
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR, "ahash digest shdesc@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc,
+ desc_bytes(desc), 1);
+#endif
+ dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma,
+ desc_bytes(desc), DMA_TO_DEVICE);
+
+ return 0;
+}
static int gen_split_hash_key(struct caam_hash_ctx *ctx, const u8 *key_in,
u32 keylen)
{
@@ -582,6 +778,25 @@ static int ahash_setkey(struct crypto_ahash *ahash,
return -EINVAL;
}
+static int axcbc_setkey(struct crypto_ahash *ahash,
+ const u8 *key, unsigned int keylen)
+{
+ struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ int ret = 0;
+
+ ctx->key_len = keylen;
+ memcpy(ctx->key, key, keylen);
+
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
+ ctx->key_len, 1);
+#endif
+
+ ret = axcbc_set_sh_desc(ahash);
+
+ return ret;
+}
/*
* ahash_edesc - s/w-extended ahash descriptor
* @dst_dma: physical mapped address of req->result
@@ -604,11 +819,20 @@ static inline void ahash_unmap(struct device *dev,
struct ahash_edesc *edesc,
struct ahash_request *req, int dst_len)
{
+ struct caam_hash_state *state = ahash_request_ctx(req);
+ int len;
+
if (edesc->src_nents)
dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE);
if (edesc->dst_dma)
dma_unmap_single(dev, edesc->dst_dma, dst_len, DMA_FROM_DEVICE);
+ len = state->current_buf ? state->buflen_1 : state->buflen_0;
+ if (state->buf_dma && len) {
+ dma_unmap_single(dev, state->buf_dma, len, DMA_TO_DEVICE);
+ state->buf_dma = 0;
+ }
+
if (edesc->sec4_sg_bytes)
dma_unmap_single(dev, edesc->sec4_sg_dma,
edesc->sec4_sg_bytes, DMA_TO_DEVICE);
@@ -1232,13 +1456,16 @@ static int ahash_final_no_ctx(struct ahash_request *req)
desc = edesc->hw_desc;
- state->buf_dma = dma_map_single(jrdev, buf, buflen, DMA_TO_DEVICE);
- if (dma_mapping_error(jrdev, state->buf_dma)) {
- dev_err(jrdev, "unable to map src\n");
- goto unmap;
- }
+ if (buflen) {
+ state->buf_dma = dma_map_single(jrdev, buf, buflen,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(jrdev, state->buf_dma)) {
+ dev_err(jrdev, "unable to map src\n");
+ goto unmap;
+ }
- append_seq_in_ptr(desc, state->buf_dma, buflen, 0);
+ append_seq_in_ptr(desc, state->buf_dma, buflen, 0);
+ }
edesc->dst_dma = map_seq_out_ptr_result(desc, jrdev, req->result,
digestsize);
@@ -1826,6 +2053,29 @@ static struct caam_hash_template driver_hash[] = {
.alg_type = OP_ALG_ALGSEL_MD5,
.alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC,
},
+ {
+ .name = "xcbc(aes)",
+ .driver_name = "xcbc-aes-caam",
+ .hmac_name = "xcbc(aes)",
+ .hmac_driver_name = "xcbc-aes-caam",
+ .blocksize = XCBC_MAC_BLOCK_WORDS * 4,
+ .template_ahash = {
+ .init = ahash_init,
+ .update = ahash_update,
+ .final = ahash_final,
+ .finup = ahash_finup,
+ .digest = ahash_digest,
+ .export = ahash_export,
+ .import = ahash_import,
+ .setkey = axcbc_setkey,
+ .halg = {
+ .digestsize = XCBC_MAC_DIGEST_SIZE,
+ .statesize = sizeof(struct caam_export_state),
+ },
+ },
+ .alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XCBC_MAC,
+ .alg_op = OP_ALG_ALGSEL_AES,
+ },
};
struct caam_hash_alg {
@@ -1875,6 +2125,41 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm)
return ahash_set_sh_desc(ahash);
}
+static int caam_axcbc_cra_init(struct crypto_tfm *tfm)
+{
+ struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
+ struct crypto_alg *base = tfm->__crt_alg;
+ struct hash_alg_common *halg =
+ container_of(base, struct hash_alg_common, base);
+ struct ahash_alg *alg =
+ container_of(halg, struct ahash_alg, halg);
+ struct caam_hash_alg *caam_hash =
+ container_of(alg, struct caam_hash_alg, ahash_alg);
+ struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm);
+ int ret = 0;
+
+ /*
+ * Get a Job ring from Job Ring driver to ensure in-order
+ * crypto request processing per tfm
+ */
+ ctx->jrdev = caam_jr_alloc();
+ if (IS_ERR(ctx->jrdev)) {
+ pr_err("Job Ring Device allocation for transform failed\n");
+ return PTR_ERR(ctx->jrdev);
+ }
+
+ /* copy descriptor header template value */
+ ctx->alg_type = OP_TYPE_CLASS1_ALG | caam_hash->alg_type;
+ ctx->alg_op = OP_TYPE_CLASS1_ALG | caam_hash->alg_op;
+
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct caam_hash_state));
+
+ ret = axcbc_set_sh_desc(ahash);
+
+ return ret;
+}
+
static void caam_hash_cra_exit(struct crypto_tfm *tfm)
{
struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm);
@@ -1951,7 +2236,11 @@ caam_hash_alloc(struct caam_hash_template *template,
t_alg->ahash_alg.setkey = NULL;
}
alg->cra_module = THIS_MODULE;
- alg->cra_init = caam_hash_cra_init;
+
+ if (strstr(alg->cra_name, "xcbc") > 0)
+ alg->cra_init = caam_axcbc_cra_init;
+ else
+ alg->cra_init = caam_hash_cra_init;
alg->cra_exit = caam_hash_cra_exit;
alg->cra_ctxsize = sizeof(struct caam_hash_ctx);
alg->cra_priority = CAAM_CRA_PRIORITY;
@@ -2004,8 +2293,14 @@ static int __init caam_algapi_hash_init(void)
* Register crypto algorithms the device supports. First, identify
* presence and attributes of MD block.
*/
- cha_vid = rd_reg32(&priv->ctrl->perfmon.cha_id_ls);
- cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls);
+ if (priv->has_seco) {
+ i = priv->first_jr_index;
+ cha_vid = rd_reg32(&priv->jr[i]->perfmon.cha_id_ls);
+ cha_inst = rd_reg32(&priv->jr[i]->perfmon.cha_num_ls);
+ } else {
+ cha_vid = rd_reg32(&priv->ctrl->perfmon.cha_id_ls);
+ cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls);
+ }
/*
* Skip registration of any hashing algorithms if MD block
@@ -2046,6 +2341,9 @@ static int __init caam_algapi_hash_init(void)
} else
list_add_tail(&t_alg->entry, &hash_list);
+ if (alg->alg_op == OP_ALG_ALGSEL_AES)
+ continue;
+
/* register unkeyed version */
t_alg = caam_hash_alloc(alg, false);
if (IS_ERR(t_alg)) {
diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c
index 354a16ab5a16..4964a6416135 100644
--- a/drivers/crypto/caam/caampkc.c
+++ b/drivers/crypto/caam/caampkc.c
@@ -1,7 +1,7 @@
/*
* caam - Freescale FSL CAAM support for Public Key Cryptography
*
- * Copyright 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
*
* There is no Shared Descriptor for PKC so that the Job Descriptor must carry
* all the desired key parameters, input and output pointers.
@@ -577,7 +577,13 @@ static int __init caam_pkc_init(void)
return -ENODEV;
/* Determine public key hardware accelerator presence. */
- cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls);
+ if (priv->has_seco) {
+ int i = priv->first_jr_index;
+
+ cha_inst = rd_reg32(&priv->jr[i]->perfmon.cha_num_ls);
+ } else {
+ cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls);
+ }
pk_inst = (cha_inst & CHA_ID_LS_PK_MASK) >> CHA_ID_LS_PK_SHIFT;
/* Do not register algorithms if PKHA is not present. */
diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c
index 9b92af2c7241..d99cf124252c 100644
--- a/drivers/crypto/caam/caamrng.c
+++ b/drivers/crypto/caam/caamrng.c
@@ -256,6 +256,49 @@ static void caam_cleanup(struct hwrng *rng)
rng_unmap_ctx(rng_ctx);
}
+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST
+static inline void test_len(struct hwrng *rng, size_t len, bool wait)
+{
+ u8 *buf;
+ int real_len;
+
+ buf = kzalloc(sizeof(u8) * len, GFP_KERNEL);
+ real_len = rng->read(rng, buf, len, wait);
+ if (real_len == 0 && wait)
+ pr_err("WAITING FAILED\n");
+ pr_info("wanted %d bytes, got %d\n", len, real_len);
+ print_hex_dump(KERN_INFO, "random bytes@: ", DUMP_PREFIX_ADDRESS,
+ 16, 4, buf, real_len, 1);
+ kfree(buf);
+}
+
+static inline void test_mode_once(struct hwrng *rng, bool wait)
+{
+#define TEST_CHUNK (RN_BUF_SIZE / 4)
+
+ test_len(rng, TEST_CHUNK, wait);
+ test_len(rng, RN_BUF_SIZE * 2, wait);
+ test_len(rng, RN_BUF_SIZE * 2 - TEST_CHUNK, wait);
+}
+
+static inline void test_mode(struct hwrng *rng, bool wait)
+{
+#define TEST_PASS 1
+ int i;
+
+ for (i = 0; i < TEST_PASS; i++)
+ test_mode_once(rng, wait);
+}
+
+static void self_test(struct hwrng *rng)
+{
+ pr_info("testing without waiting\n");
+ test_mode(rng, false);
+ pr_info("testing with waiting\n");
+ test_mode(rng, true);
+}
+#endif
+
static int caam_init_buf(struct caam_rng_ctx *ctx, int buf_id)
{
struct buf_data *bd = &ctx->bufs[buf_id];
@@ -317,6 +360,7 @@ static int __init caam_rng_init(void)
struct device *ctrldev;
struct caam_drv_private *priv;
int err;
+ u32 cha_inst;
dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
if (!dev_node) {
@@ -343,7 +387,14 @@ static int __init caam_rng_init(void)
return -ENODEV;
/* Check for an instantiated RNG before registration */
- if (!(rd_reg32(&priv->ctrl->perfmon.cha_num_ls) & CHA_ID_LS_RNG_MASK))
+ if (priv->has_seco) {
+ int i = priv->first_jr_index;
+
+ cha_inst = rd_reg32(&priv->jr[i]->perfmon.cha_num_ls);
+ } else {
+ cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls);
+ }
+ if (!(cha_inst & CHA_ID_LS_RNG_MASK))
return -ENODEV;
dev = caam_jr_alloc();
@@ -360,6 +411,10 @@ static int __init caam_rng_init(void)
if (err)
goto free_rng_ctx;
+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST
+ self_test(&caam_rng);
+#endif
+
dev_info(dev, "registering rng-caam\n");
return hwrng_register(&caam_rng);
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index 2ca101ac0c17..2c618ba59bb2 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -1,12 +1,14 @@
/* * CAAM control-plane driver backend
* Controller-level driver, kernel property detection, initialization
*
- * Copyright 2008-2012 Freescale Semiconductor, Inc.
+ * Copyright 2008-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
*/
#include <linux/device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/pm_domain.h>
#include "compat.h"
#include "regs.h"
@@ -15,6 +17,7 @@
#include "desc_constr.h"
#include "error.h"
#include "ctrl.h"
+#include "sm.h"
bool caam_little_end;
EXPORT_SYMBOL(caam_little_end);
@@ -37,271 +40,6 @@ static inline struct clk *caam_drv_identify_clk(struct device *dev,
}
#endif
-/*
- * Descriptor to instantiate RNG State Handle 0 in normal mode and
- * load the JDKEK, TDKEK and TDSK registers
- */
-static void build_instantiation_desc(u32 *desc, int handle, int do_sk)
-{
- u32 *jump_cmd, op_flags;
-
- init_job_desc(desc, 0);
-
- op_flags = OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
- (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INIT;
-
- /* INIT RNG in non-test mode */
- append_operation(desc, op_flags);
-
- if (!handle && do_sk) {
- /*
- * For SH0, Secure Keys must be generated as well
- */
-
- /* wait for done */
- jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1);
- set_jump_tgt_here(desc, jump_cmd);
-
- /*
- * load 1 to clear written reg:
- * resets the done interrrupt and returns the RNG to idle.
- */
- append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW);
-
- /* Initialize State Handle */
- append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
- OP_ALG_AAI_RNG4_SK);
- }
-
- append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT);
-}
-
-/* Descriptor for deinstantiation of State Handle 0 of the RNG block. */
-static void build_deinstantiation_desc(u32 *desc, int handle)
-{
- init_job_desc(desc, 0);
-
- /* Uninstantiate State Handle 0 */
- append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
- (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INITFINAL);
-
- append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT);
-}
-
-/*
- * run_descriptor_deco0 - runs a descriptor on DECO0, under direct control of
- * the software (no JR/QI used).
- * @ctrldev - pointer to device
- * @status - descriptor status, after being run
- *
- * Return: - 0 if no error occurred
- * - -ENODEV if the DECO couldn't be acquired
- * - -EAGAIN if an error occurred while executing the descriptor
- */
-static inline int run_descriptor_deco0(struct device *ctrldev, u32 *desc,
- u32 *status)
-{
- struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
- struct caam_ctrl __iomem *ctrl = ctrlpriv->ctrl;
- struct caam_deco __iomem *deco = ctrlpriv->deco;
- unsigned int timeout = 100000;
- u32 deco_dbg_reg, flags;
- int i;
-
-
- if (ctrlpriv->virt_en == 1) {
- clrsetbits_32(&ctrl->deco_rsr, 0, DECORSR_JR0);
-
- while (!(rd_reg32(&ctrl->deco_rsr) & DECORSR_VALID) &&
- --timeout)
- cpu_relax();
-
- timeout = 100000;
- }
-
- clrsetbits_32(&ctrl->deco_rq, 0, DECORR_RQD0ENABLE);
-
- while (!(rd_reg32(&ctrl->deco_rq) & DECORR_DEN0) &&
- --timeout)
- cpu_relax();
-
- if (!timeout) {
- dev_err(ctrldev, "failed to acquire DECO 0\n");
- clrsetbits_32(&ctrl->deco_rq, DECORR_RQD0ENABLE, 0);
- return -ENODEV;
- }
-
- for (i = 0; i < desc_len(desc); i++)
- wr_reg32(&deco->descbuf[i], caam32_to_cpu(*(desc + i)));
-
- flags = DECO_JQCR_WHL;
- /*
- * If the descriptor length is longer than 4 words, then the
- * FOUR bit in JRCTRL register must be set.
- */
- if (desc_len(desc) >= 4)
- flags |= DECO_JQCR_FOUR;
-
- /* Instruct the DECO to execute it */
- clrsetbits_32(&deco->jr_ctl_hi, 0, flags);
-
- timeout = 10000000;
- do {
- deco_dbg_reg = rd_reg32(&deco->desc_dbg);
- /*
- * If an error occured in the descriptor, then
- * the DECO status field will be set to 0x0D
- */
- if ((deco_dbg_reg & DESC_DBG_DECO_STAT_MASK) ==
- DESC_DBG_DECO_STAT_HOST_ERR)
- break;
- cpu_relax();
- } while ((deco_dbg_reg & DESC_DBG_DECO_STAT_VALID) && --timeout);
-
- *status = rd_reg32(&deco->op_status_hi) &
- DECO_OP_STATUS_HI_ERR_MASK;
-
- if (ctrlpriv->virt_en == 1)
- clrsetbits_32(&ctrl->deco_rsr, DECORSR_JR0, 0);
-
- /* Mark the DECO as free */
- clrsetbits_32(&ctrl->deco_rq, DECORR_RQD0ENABLE, 0);
-
- if (!timeout)
- return -EAGAIN;
-
- return 0;
-}
-
-/*
- * instantiate_rng - builds and executes a descriptor on DECO0,
- * which initializes the RNG block.
- * @ctrldev - pointer to device
- * @state_handle_mask - bitmask containing the instantiation status
- * for the RNG4 state handles which exist in
- * the RNG4 block: 1 if it's been instantiated
- * by an external entry, 0 otherwise.
- * @gen_sk - generate data to be loaded into the JDKEK, TDKEK and TDSK;
- * Caution: this can be done only once; if the keys need to be
- * regenerated, a POR is required
- *
- * Return: - 0 if no error occurred
- * - -ENOMEM if there isn't enough memory to allocate the descriptor
- * - -ENODEV if DECO0 couldn't be acquired
- * - -EAGAIN if an error occurred when executing the descriptor
- * f.i. there was a RNG hardware error due to not "good enough"
- * entropy being aquired.
- */
-static int instantiate_rng(struct device *ctrldev, int state_handle_mask,
- int gen_sk)
-{
- struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
- struct caam_ctrl __iomem *ctrl;
- u32 *desc, status = 0, rdsta_val;
- int ret = 0, sh_idx;
-
- ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl;
- desc = kmalloc(CAAM_CMD_SZ * 7, GFP_KERNEL);
- if (!desc)
- return -ENOMEM;
-
- for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) {
- /*
- * If the corresponding bit is set, this state handle
- * was initialized by somebody else, so it's left alone.
- */
- if ((1 << sh_idx) & state_handle_mask)
- continue;
-
- /* Create the descriptor for instantiating RNG State Handle */
- build_instantiation_desc(desc, sh_idx, gen_sk);
-
- /* Try to run it through DECO0 */
- ret = run_descriptor_deco0(ctrldev, desc, &status);
-
- /*
- * If ret is not 0, or descriptor status is not 0, then
- * something went wrong. No need to try the next state
- * handle (if available), bail out here.
- * Also, if for some reason, the State Handle didn't get
- * instantiated although the descriptor has finished
- * without any error (HW optimizations for later
- * CAAM eras), then try again.
- */
- if (ret)
- break;
-
- rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK;
- if ((status && status != JRSTA_SSRC_JUMP_HALT_CC) ||
- !(rdsta_val & (1 << sh_idx))) {
- ret = -EAGAIN;
- break;
- }
-
- dev_info(ctrldev, "Instantiated RNG4 SH%d\n", sh_idx);
- /* Clear the contents before recreating the descriptor */
- memset(desc, 0x00, CAAM_CMD_SZ * 7);
- }
-
- kfree(desc);
-
- return ret;
-}
-
-/*
- * deinstantiate_rng - builds and executes a descriptor on DECO0,
- * which deinitializes the RNG block.
- * @ctrldev - pointer to device
- * @state_handle_mask - bitmask containing the instantiation status
- * for the RNG4 state handles which exist in
- * the RNG4 block: 1 if it's been instantiated
- *
- * Return: - 0 if no error occurred
- * - -ENOMEM if there isn't enough memory to allocate the descriptor
- * - -ENODEV if DECO0 couldn't be acquired
- * - -EAGAIN if an error occurred when executing the descriptor
- */
-static int deinstantiate_rng(struct device *ctrldev, int state_handle_mask)
-{
- u32 *desc, status;
- int sh_idx, ret = 0;
-
- desc = kmalloc(CAAM_CMD_SZ * 3, GFP_KERNEL);
- if (!desc)
- return -ENOMEM;
-
- for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) {
- /*
- * If the corresponding bit is set, then it means the state
- * handle was initialized by us, and thus it needs to be
- * deintialized as well
- */
- if ((1 << sh_idx) & state_handle_mask) {
- /*
- * Create the descriptor for deinstantating this state
- * handle
- */
- build_deinstantiation_desc(desc, sh_idx);
-
- /* Try to run it through DECO0 */
- ret = run_descriptor_deco0(ctrldev, desc, &status);
-
- if (ret ||
- (status && status != JRSTA_SSRC_JUMP_HALT_CC)) {
- dev_err(ctrldev,
- "Failed to deinstantiate RNG4 SH%d\n",
- sh_idx);
- break;
- }
- dev_info(ctrldev, "Deinstantiated RNG4 SH%d\n", sh_idx);
- }
- }
-
- kfree(desc);
-
- return ret;
-}
-
static int caam_remove(struct platform_device *pdev)
{
struct device *ctrldev;
@@ -319,10 +57,6 @@ static int caam_remove(struct platform_device *pdev)
of_device_unregister(ctrlpriv->jrpdev[ring]);
}
- /* De-initialize RNG state handles initialized by this driver. */
- if (ctrlpriv->rng4_sh_init)
- deinstantiate_rng(ctrldev, ctrlpriv->rng4_sh_init);
-
/* Shut down debug views */
#ifdef CONFIG_DEBUG_FS
debugfs_remove_recursive(ctrlpriv->dfs_root);
@@ -340,80 +74,123 @@ static int caam_remove(struct platform_device *pdev)
return 0;
}
-/*
- * kick_trng - sets the various parameters for enabling the initialization
- * of the RNG4 block in CAAM
- * @pdev - pointer to the platform device
- * @ent_delay - Defines the length (in system clocks) of each entropy sample.
- */
-static void kick_trng(struct platform_device *pdev, int ent_delay)
+static void detect_era(struct caam_drv_private *ctrlpriv)
{
- struct device *ctrldev = &pdev->dev;
- struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
- struct caam_ctrl __iomem *ctrl;
- struct rng4tst __iomem *r4tst;
- u32 val;
+ int ret, i;
+ u32 caam_era;
+ u32 caam_id_ms;
+ char *era_source;
+ struct device_node *caam_node;
+ struct sec_vid sec_vid;
+ static const struct {
+ u16 ip_id;
+ u8 maj_rev;
+ u8 era;
+ } caam_eras[] = {
+ {0x0A10, 1, 1},
+ {0x0A10, 2, 2},
+ {0x0A12, 1, 3},
+ {0x0A14, 1, 3},
+ {0x0A10, 3, 4},
+ {0x0A11, 1, 4},
+ {0x0A14, 2, 4},
+ {0x0A16, 1, 4},
+ {0x0A18, 1, 4},
+ {0x0A11, 2, 5},
+ {0x0A12, 2, 5},
+ {0x0A13, 1, 5},
+ {0x0A1C, 1, 5},
+ {0x0A12, 4, 6},
+ {0x0A13, 2, 6},
+ {0x0A16, 2, 6},
+ {0x0A17, 1, 6},
+ {0x0A18, 2, 6},
+ {0x0A1A, 1, 6},
+ {0x0A1C, 2, 6},
+ {0x0A14, 3, 7},
+ {0x0A10, 4, 8},
+ {0x0A11, 3, 8},
+ {0x0A11, 4, 8},
+ {0x0A12, 5, 8},
+ {0x0A16, 3, 8},
+ };
+
+ /* If the user or bootloader has set the property we'll use that */
+ caam_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ ret = of_property_read_u32(caam_node, "fsl,sec-era", &caam_era);
+ of_node_put(caam_node);
- ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl;
- r4tst = &ctrl->r4tst[0];
+ if (!ret) {
+ era_source = "device tree";
+ goto era_found;
+ }
- /* put RNG4 into program mode */
- clrsetbits_32(&r4tst->rtmctl, 0, RTMCTL_PRGM);
+ i = ctrlpriv->first_jr_index;
+ /* If ccbvid has the era, use that (era 6 and onwards) */
+ if (ctrlpriv->has_seco)
+ caam_era = rd_reg32(&ctrlpriv->jr[i]->perfmon.ccb_id);
+ else
+ caam_era = rd_reg32(&ctrlpriv->ctrl->perfmon.ccb_id);
- /*
- * Performance-wise, it does not make sense to
- * set the delay to a value that is lower
- * than the last one that worked (i.e. the state handles
- * were instantiated properly. Thus, instead of wasting
- * time trying to set the values controlling the sample
- * frequency, the function simply returns.
- */
- val = (rd_reg32(&r4tst->rtsdctl) & RTSDCTL_ENT_DLY_MASK)
- >> RTSDCTL_ENT_DLY_SHIFT;
- if (ent_delay <= val) {
- /* put RNG4 into run mode */
- clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM, 0);
- return;
+ caam_era = caam_era >> CCB_VID_ERA_SHIFT & CCB_VID_ERA_MASK;
+ if (caam_era) {
+ era_source = "CCBVID";
+ goto era_found;
}
- val = rd_reg32(&r4tst->rtsdctl);
- val = (val & ~RTSDCTL_ENT_DLY_MASK) |
- (ent_delay << RTSDCTL_ENT_DLY_SHIFT);
- wr_reg32(&r4tst->rtsdctl, val);
- /* min. freq. count, equal to 1/4 of the entropy sample length */
- wr_reg32(&r4tst->rtfrqmin, ent_delay >> 2);
- /* disable maximum frequency count */
- wr_reg32(&r4tst->rtfrqmax, RTFRQMAX_DISABLE);
- /* read the control register */
- val = rd_reg32(&r4tst->rtmctl);
- /*
- * select raw sampling in both entropy shifter
- * and statistical checker
- */
- clrsetbits_32(&val, 0, RTMCTL_SAMP_MODE_RAW_ES_SC);
- /* put RNG4 into run mode */
- clrsetbits_32(&val, RTMCTL_PRGM, 0);
- /* write back the control register */
- wr_reg32(&r4tst->rtmctl, val);
+ /* If we can match caamvid to known versions, use that */
+ if (ctrlpriv->has_seco)
+ caam_id_ms = rd_reg32(&ctrlpriv->jr[i]->perfmon.caam_id_ms);
+ else
+ caam_id_ms = rd_reg32(&ctrlpriv->ctrl->perfmon.caam_id_ms);
+ sec_vid.ip_id = caam_id_ms >> SEC_VID_IPID_SHIFT;
+ sec_vid.maj_rev = (caam_id_ms & SEC_VID_MAJ_MASK) >> SEC_VID_MAJ_SHIFT;
+
+ for (i = 0; i < ARRAY_SIZE(caam_eras); i++)
+ if (caam_eras[i].ip_id == sec_vid.ip_id &&
+ caam_eras[i].maj_rev == sec_vid.maj_rev) {
+ caam_era = caam_eras[i].era;
+ era_source = "CAAMVID";
+ goto era_found;
+ }
+
+ ctrlpriv->era = -ENOTSUPP;
+ dev_info(&ctrlpriv->pdev->dev, "ERA undetermined!.\n");
+ return;
+
+era_found:
+ ctrlpriv->era = caam_era;
+ dev_info(&ctrlpriv->pdev->dev, "ERA source: %s.\n", era_source);
}
-/**
- * caam_get_era() - Return the ERA of the SEC on SoC, based
- * on "sec-era" propery in the DTS. This property is updated by u-boot.
- **/
-int caam_get_era(void)
+static void handle_imx6_err005766(struct caam_drv_private *ctrlpriv)
{
- struct device_node *caam_node;
- int ret;
- u32 prop;
+ /*
+ * ERRATA: mx6 devices have an issue wherein AXI bus transactions
+ * may not occur in the correct order. This isn't a problem running
+ * single descriptors, but can be if running multiple concurrent
+ * descriptors. Reworking the driver to throttle to single requests
+ * is impractical, thus the workaround is to limit the AXI pipeline
+ * to a depth of 1 (from it's default of 4) to preclude this situation
+ * from occurring.
+ */
- caam_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
- ret = of_property_read_u32(caam_node, "fsl,sec-era", &prop);
- of_node_put(caam_node);
+ u32 mcr_val;
+
+ if (ctrlpriv->era != IMX_ERR005766_ERA)
+ return;
- return ret ? -ENOTSUPP : prop;
+ if (of_machine_is_compatible("fsl,imx6q") ||
+ of_machine_is_compatible("fsl,imx6dl") ||
+ of_machine_is_compatible("fsl,imx6qp")) {
+ dev_info(&ctrlpriv->pdev->dev,
+ "AXI pipeline throttling enabled.\n");
+ mcr_val = rd_reg32(&ctrlpriv->ctrl->mcr);
+ wr_reg32(&ctrlpriv->ctrl->mcr,
+ (mcr_val & ~(MCFGR_AXIPIPE_MASK)) |
+ ((1 << MCFGR_AXIPIPE_SHIFT) & MCFGR_AXIPIPE_MASK));
+ }
}
-EXPORT_SYMBOL(caam_get_era);
#ifdef CONFIG_DEBUG_FS
static int caam_debugfs_u64_get(void *data, u64 *val)
@@ -432,147 +209,185 @@ DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u32_ro, caam_debugfs_u32_get, NULL, "%llu\n");
DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u64_ro, caam_debugfs_u64_get, NULL, "%llu\n");
#endif
-/* Probe routine for CAAM top (controller) level */
-static int caam_probe(struct platform_device *pdev)
+static void init_debugfs(struct caam_drv_private *ctrlpriv)
{
- int ret, ring, rspec, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN;
- u64 caam_id;
- struct device *dev;
- struct device_node *nprop, *np;
- struct caam_ctrl __iomem *ctrl;
- struct caam_drv_private *ctrlpriv;
- struct clk *clk;
#ifdef CONFIG_DEBUG_FS
struct caam_perfmon *perfmon;
-#endif
- u32 scfgr, comp_params;
- u32 cha_vid_ls;
- int pg_size;
- int BLOCK_OFFSET = 0;
- ctrlpriv = devm_kzalloc(&pdev->dev, sizeof(*ctrlpriv), GFP_KERNEL);
- if (!ctrlpriv)
- return -ENOMEM;
+ /*
+ * FIXME: needs better naming distinction, as some amalgamation of
+ * "caam" and nprop->full_name. The OF name isn't distinctive,
+ * but does separate instances
+ */
+ perfmon = (struct caam_perfmon __force *)&ctrlpriv->ctrl->perfmon;
- dev = &pdev->dev;
- dev_set_drvdata(dev, ctrlpriv);
- ctrlpriv->pdev = pdev;
- nprop = pdev->dev.of_node;
+ ctrlpriv->dfs_root = debugfs_create_dir(dev_name(ctrlpriv->dev), NULL);
+ ctrlpriv->ctl = debugfs_create_dir("ctl", ctrlpriv->dfs_root);
+
+ /* Controller-level - performance monitor counters */
+
+ ctrlpriv->ctl_rq_dequeued =
+ debugfs_create_file("rq_dequeued",
+ 0444,
+ ctrlpriv->ctl, &perfmon->req_dequeued,
+ &caam_fops_u64_ro);
+ ctrlpriv->ctl_ob_enc_req =
+ debugfs_create_file("ob_rq_encrypted",
+ 0444,
+ ctrlpriv->ctl, &perfmon->ob_enc_req,
+ &caam_fops_u64_ro);
+ ctrlpriv->ctl_ib_dec_req =
+ debugfs_create_file("ib_rq_decrypted",
+ 0444,
+ ctrlpriv->ctl, &perfmon->ib_dec_req,
+ &caam_fops_u64_ro);
+ ctrlpriv->ctl_ob_enc_bytes =
+ debugfs_create_file("ob_bytes_encrypted",
+ 0444,
+ ctrlpriv->ctl, &perfmon->ob_enc_bytes,
+ &caam_fops_u64_ro);
+ ctrlpriv->ctl_ob_prot_bytes =
+ debugfs_create_file("ob_bytes_protected",
+ 0444,
+ ctrlpriv->ctl, &perfmon->ob_prot_bytes,
+ &caam_fops_u64_ro);
+ ctrlpriv->ctl_ib_dec_bytes =
+ debugfs_create_file("ib_bytes_decrypted",
+ 0444,
+ ctrlpriv->ctl, &perfmon->ib_dec_bytes,
+ &caam_fops_u64_ro);
+ ctrlpriv->ctl_ib_valid_bytes =
+ debugfs_create_file("ib_bytes_validated",
+ 0444,
+ ctrlpriv->ctl, &perfmon->ib_valid_bytes,
+ &caam_fops_u64_ro);
+
+ /* Controller level - global status values */
+ ctrlpriv->ctl_faultaddr =
+ debugfs_create_file("fault_addr",
+ 0444,
+ ctrlpriv->ctl, &perfmon->faultaddr,
+ &caam_fops_u32_ro);
+ ctrlpriv->ctl_faultdetail =
+ debugfs_create_file("fault_detail",
+ 0444,
+ ctrlpriv->ctl, &perfmon->faultdetail,
+ &caam_fops_u32_ro);
+ ctrlpriv->ctl_faultstatus =
+ debugfs_create_file("fault_status",
+ 0444,
+ ctrlpriv->ctl, &perfmon->status,
+ &caam_fops_u32_ro);
+
+ /* Internal covering keys (useful in non-secure mode only) */
+ ctrlpriv->ctl_kek_wrap.data = &ctrlpriv->ctrl->kek[0];
+ ctrlpriv->ctl_kek_wrap.size = KEK_KEY_SIZE * sizeof(u32);
+ ctrlpriv->ctl_kek = debugfs_create_blob("kek",
+ 0444,
+ ctrlpriv->ctl,
+ &ctrlpriv->ctl_kek_wrap);
+
+ ctrlpriv->ctl_tkek_wrap.data = &ctrlpriv->ctrl->tkek[0];
+ ctrlpriv->ctl_tkek_wrap.size = KEK_KEY_SIZE * sizeof(u32);
+ ctrlpriv->ctl_tkek = debugfs_create_blob("tkek",
+ 0444,
+ ctrlpriv->ctl,
+ &ctrlpriv->ctl_tkek_wrap);
+
+ ctrlpriv->ctl_tdsk_wrap.data = &ctrlpriv->ctrl->tdsk[0];
+ ctrlpriv->ctl_tdsk_wrap.size = KEK_KEY_SIZE * sizeof(u32);
+ ctrlpriv->ctl_tdsk = debugfs_create_blob("tdsk",
+ 0444,
+ ctrlpriv->ctl,
+ &ctrlpriv->ctl_tdsk_wrap);
+#endif
+}
+
+static int init_clocks(struct caam_drv_private *ctrlpriv)
+{
+ struct clk *clk;
+ struct device *dev = ctrlpriv->dev;
+ int ret = 0;
/* Enable clocking */
- clk = caam_drv_identify_clk(&pdev->dev, "ipg");
+ clk = caam_drv_identify_clk(dev, "ipg");
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
- dev_err(&pdev->dev,
- "can't identify CAAM ipg clk: %d\n", ret);
+ dev_err(dev, "can't identify CAAM ipg clk: %d\n", ret);
return ret;
}
ctrlpriv->caam_ipg = clk;
- clk = caam_drv_identify_clk(&pdev->dev, "mem");
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- dev_err(&pdev->dev,
- "can't identify CAAM mem clk: %d\n", ret);
+ ret = clk_prepare_enable(ctrlpriv->caam_ipg);
+ if (ret < 0) {
+ dev_err(dev, "can't enable CAAM ipg clock: %d\n", ret);
return ret;
}
- ctrlpriv->caam_mem = clk;
- clk = caam_drv_identify_clk(&pdev->dev, "aclk");
+ clk = caam_drv_identify_clk(dev, "aclk");
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
- dev_err(&pdev->dev,
- "can't identify CAAM aclk clk: %d\n", ret);
+ dev_err(dev, "can't identify CAAM aclk clk: %d\n", ret);
return ret;
}
ctrlpriv->caam_aclk = clk;
- clk = caam_drv_identify_clk(&pdev->dev, "emi_slow");
- if (IS_ERR(clk)) {
- ret = PTR_ERR(clk);
- dev_err(&pdev->dev,
- "can't identify CAAM emi_slow clk: %d\n", ret);
- return ret;
- }
- ctrlpriv->caam_emi_slow = clk;
-
- ret = clk_prepare_enable(ctrlpriv->caam_ipg);
+ ret = clk_prepare_enable(ctrlpriv->caam_aclk);
if (ret < 0) {
- dev_err(&pdev->dev, "can't enable CAAM ipg clock: %d\n", ret);
+ dev_err(dev, "can't enable CAAM aclk clock: %d\n", ret);
return ret;
}
- ret = clk_prepare_enable(ctrlpriv->caam_mem);
- if (ret < 0) {
- dev_err(&pdev->dev, "can't enable CAAM secure mem clock: %d\n",
- ret);
- goto disable_caam_ipg;
- }
+ if (!(of_find_compatible_node(NULL, NULL, "fsl,imx7d-caam"))) {
- ret = clk_prepare_enable(ctrlpriv->caam_aclk);
- if (ret < 0) {
- dev_err(&pdev->dev, "can't enable CAAM aclk clock: %d\n", ret);
- goto disable_caam_mem;
- }
+ clk = caam_drv_identify_clk(dev, "mem");
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ dev_err(dev, "can't identify CAAM mem clk: %d\n", ret);
+ return ret;
+ }
+ ctrlpriv->caam_mem = clk;
- ret = clk_prepare_enable(ctrlpriv->caam_emi_slow);
- if (ret < 0) {
- dev_err(&pdev->dev, "can't enable CAAM emi slow clock: %d\n",
- ret);
- goto disable_caam_aclk;
- }
+ ret = clk_prepare_enable(ctrlpriv->caam_mem);
+ if (ret < 0) {
+ dev_err(dev, "can't enable CAAM secure mem clock: %d\n",
+ ret);
+ return ret;
+ }
- /* Get configuration properties from device tree */
- /* First, get register page */
- ctrl = of_iomap(nprop, 0);
- if (ctrl == NULL) {
- dev_err(dev, "caam: of_iomap() failed\n");
- ret = -ENOMEM;
- goto disable_caam_emi_slow;
+ if (!(of_find_compatible_node(NULL, NULL, "fsl,imx6ul-caam"))) {
+ clk = caam_drv_identify_clk(dev, "emi_slow");
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ dev_err(dev,
+ "can't identify CAAM emi_slow clk: %d\n",
+ ret);
+ return ret;
+ }
+ ctrlpriv->caam_emi_slow = clk;
+
+ ret = clk_prepare_enable(ctrlpriv->caam_emi_slow);
+ if (ret < 0) {
+ dev_err(dev,
+ "can't enable CAAM emi slow clock: %d\n",
+ ret);
+ return ret;
+ }
+ }
}
- caam_little_end = !(bool)(rd_reg32(&ctrl->perfmon.status) &
- (CSTA_PLEND | CSTA_ALT_PLEND));
-
- /* Finding the page size for using the CTPR_MS register */
- comp_params = rd_reg32(&ctrl->perfmon.comp_parms_ms);
- pg_size = (comp_params & CTPR_MS_PG_SZ_MASK) >> CTPR_MS_PG_SZ_SHIFT;
-
- /* Allocating the BLOCK_OFFSET based on the supported page size on
- * the platform
- */
- if (pg_size == 0)
- BLOCK_OFFSET = PG_SIZE_4K;
- else
- BLOCK_OFFSET = PG_SIZE_64K;
-
- ctrlpriv->ctrl = (struct caam_ctrl __force *)ctrl;
- ctrlpriv->assure = (struct caam_assurance __force *)
- ((uint8_t *)ctrl +
- BLOCK_OFFSET * ASSURE_BLOCK_NUMBER
- );
- ctrlpriv->deco = (struct caam_deco __force *)
- ((uint8_t *)ctrl +
- BLOCK_OFFSET * DECO_BLOCK_NUMBER
- );
-
- /* Get the IRQ of the controller (for security violations only) */
- ctrlpriv->secvio_irq = irq_of_parse_and_map(nprop, 0);
-
- /*
- * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel,
- * long pointers in master configuration register
- */
- clrsetbits_32(&ctrl->mcr, MCFGR_AWCACHE_MASK | MCFGR_LONG_PTR,
- MCFGR_AWCACHE_CACH | MCFGR_AWCACHE_BUFF |
- MCFGR_WDENABLE | MCFGR_LARGE_BURST |
- (sizeof(dma_addr_t) == sizeof(u64) ? MCFGR_LONG_PTR : 0));
+ return ret;
+}
+static void check_virt(struct caam_drv_private *ctrlpriv, u32 comp_params)
+{
/*
- * Read the Compile Time paramters and SCFGR to determine
+ * Read the Compile Time parameters and SCFGR to determine
* if Virtualization is enabled for this platform
*/
- scfgr = rd_reg32(&ctrl->scfgr);
+ u32 scfgr;
+
+ scfgr = rd_reg32(&ctrlpriv->ctrl->scfgr);
ctrlpriv->virt_en = 0;
if (comp_params & CTPR_MS_VIRT_EN_INCL) {
@@ -582,43 +397,41 @@ static int caam_probe(struct platform_device *pdev)
if ((comp_params & CTPR_MS_VIRT_EN_POR) ||
(!(comp_params & CTPR_MS_VIRT_EN_POR) &&
(scfgr & SCFGR_VIRT_EN)))
- ctrlpriv->virt_en = 1;
+ ctrlpriv->virt_en = 1;
} else {
/* VIRT_EN_INCL = 0 && VIRT_EN_POR_VALUE = 1 */
if (comp_params & CTPR_MS_VIRT_EN_POR)
- ctrlpriv->virt_en = 1;
+ ctrlpriv->virt_en = 1;
}
if (ctrlpriv->virt_en == 1)
- clrsetbits_32(&ctrl->jrstart, 0, JRSTART_JR0_START |
+ clrsetbits_32(&ctrlpriv->ctrl->jrstart, 0, JRSTART_JR0_START |
JRSTART_JR1_START | JRSTART_JR2_START |
JRSTART_JR3_START);
+}
- if (sizeof(dma_addr_t) == sizeof(u64))
- if (of_device_is_compatible(nprop, "fsl,sec-v5.0"))
- dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
- else
- dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
- else
- dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+static int enable_jobrings(struct caam_drv_private *ctrlpriv, int block_offset)
+{
+ int ring, index;
+ int rspec = 0;
+ struct device_node *nprop, *np;
/*
* Detect and enable JobRs
* First, find out how many ring spec'ed, allocate references
* for all, then go probe each one.
*/
- rspec = 0;
+ nprop = ctrlpriv->pdev->dev.of_node;
+
for_each_available_child_of_node(nprop, np)
if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
of_device_is_compatible(np, "fsl,sec4.0-job-ring"))
rspec++;
- ctrlpriv->jrpdev = devm_kcalloc(&pdev->dev, rspec,
+ ctrlpriv->jrpdev = devm_kcalloc(ctrlpriv->dev, rspec,
sizeof(*ctrlpriv->jrpdev), GFP_KERNEL);
- if (ctrlpriv->jrpdev == NULL) {
- ret = -ENOMEM;
- goto iounmap_ctrl;
- }
+ if (ctrlpriv->jrpdev == NULL)
+ return -ENOMEM;
ring = 0;
ctrlpriv->total_jobrs = 0;
@@ -626,209 +439,295 @@ static int caam_probe(struct platform_device *pdev)
if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
of_device_is_compatible(np, "fsl,sec4.0-job-ring")) {
ctrlpriv->jrpdev[ring] =
- of_platform_device_create(np, NULL, dev);
+ of_platform_device_create(np, NULL,
+ ctrlpriv->dev);
if (!ctrlpriv->jrpdev[ring]) {
pr_warn("JR%d Platform device creation error\n",
ring);
continue;
}
- ctrlpriv->jr[ring] = (struct caam_job_ring __force *)
- ((uint8_t *)ctrl +
- (ring + JR_BLOCK_NUMBER) *
- BLOCK_OFFSET
- );
+ /* Power up the job ring.*/
+ genpd_dev_pm_attach(&ctrlpriv->jrpdev[ring]->dev);
+
+ if (of_property_read_u32_index(np, "reg", 0, &index)) {
+ pr_warn("%s read reg property error %d.",
+ np->full_name, index);
+ continue;
+ }
+ /* Get actual job ring index from its offset
+ * ex: CAAM JR2 offset 0x30000 index = 2
+ */
+ while (index >= 16)
+ index = index >> 4;
+ index -= 1;
+ ctrlpriv->jr[index] = (struct caam_job_ring __force *)
+ ((uint8_t *)ctrlpriv->ctrl +
+ (index + JR_BLOCK_NUMBER) *
+ block_offset);
ctrlpriv->total_jobrs++;
ring++;
- }
+ }
+ return 0;
+}
+
+static void enable_qi(struct caam_drv_private *ctrlpriv, int block_offset)
+{
/* Check to see if QI present. If so, enable */
ctrlpriv->qi_present =
- !!(rd_reg32(&ctrl->perfmon.comp_parms_ms) &
+ !!(rd_reg32(&ctrlpriv->ctrl->perfmon.comp_parms_ms) &
CTPR_MS_QI_MASK);
if (ctrlpriv->qi_present) {
ctrlpriv->qi = (struct caam_queue_if __force *)
- ((uint8_t *)ctrl +
- BLOCK_OFFSET * QI_BLOCK_NUMBER
- );
+ ((uint8_t *)ctrlpriv->ctrl +
+ block_offset * QI_BLOCK_NUMBER);
/* This is all that's required to physically enable QI */
wr_reg32(&ctrlpriv->qi->qi_control_lo, QICTL_DQEN);
}
+}
- /* If no QI and no rings specified, quit and go home */
- if ((!ctrlpriv->qi_present) && (!ctrlpriv->total_jobrs)) {
- dev_err(dev, "no queues configured, terminating\n");
- ret = -ENOMEM;
- goto caam_remove;
+static int read_first_jr_index(struct caam_drv_private *ctrlpriv)
+{
+ struct device_node *caam_node;
+ int ret;
+ u32 first_index;
+
+ caam_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ ret = of_property_read_u32(caam_node,
+ "fsl,first-jr-index", &first_index);
+ of_node_put(caam_node);
+ if (ret == 0)
+ if (first_index > 0 && first_index < 4)
+ ctrlpriv->first_jr_index = first_index;
+ return ret;
+}
+
+static int probe_w_seco(struct caam_drv_private *ctrlpriv)
+{
+ int ret = 0;
+ struct device_node *np;
+ u32 idx, status;
+
+ ctrlpriv->has_seco = true;
+ /*
+ * For imx8 page size is 64k, we can't access ctrl regs to dynamically
+ * obtain this info.
+ */
+ ret = enable_jobrings(ctrlpriv, PG_SIZE_64K);
+ if (ret)
+ return ret;
+ if (!ctrlpriv->total_jobrs) {
+ dev_err(ctrlpriv->dev, "no job rings configured!\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Read first job ring index for aliased registers
+ */
+ if (read_first_jr_index(ctrlpriv)) {
+ dev_err(ctrlpriv->dev, "missing first job ring index!\n");
+ return -ENODEV;
+ }
+ idx = ctrlpriv->first_jr_index;
+ status = rd_reg32(&ctrlpriv->jr[idx]->perfmon.status);
+ caam_little_end = !(bool)(status & (CSTA_PLEND | CSTA_ALT_PLEND));
+ ctrlpriv->assure = ((struct caam_assurance __force *)
+ ((uint8_t *)ctrlpriv->ctrl +
+ PG_SIZE_64K * ASSURE_BLOCK_NUMBER));
+ ctrlpriv->deco = ((struct caam_deco __force *)
+ ((uint8_t *)ctrlpriv->ctrl +
+ PG_SIZE_64K * DECO_BLOCK_NUMBER));
+
+ detect_era(ctrlpriv);
+
+ /* Get CAAM-SM node and of_iomap() and save */
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-sm");
+ if (!np) {
+ dev_warn(ctrlpriv->dev, "No CAAM-SM node found!\n");
+ return -ENODEV;
}
- cha_vid_ls = rd_reg32(&ctrl->perfmon.cha_id_ls);
+ ctrlpriv->sm_base = of_iomap(np, 0);
+ ctrlpriv->sm_size = 0x3fff;
+
+ /* Can't enable DECO WD and LPs those are in MCR */
/*
- * If SEC has RNG version >= 4 and RNG state handle has not been
- * already instantiated, do RNG instantiation
+ * can't check for virtualization because we need access to SCFGR for it
*/
- if ((cha_vid_ls & CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT >= 4) {
- ctrlpriv->rng4_sh_init =
- rd_reg32(&ctrl->r4tst[0].rdsta);
- /*
- * If the secure keys (TDKEK, JDKEK, TDSK), were already
- * generated, signal this to the function that is instantiating
- * the state handles. An error would occur if RNG4 attempts
- * to regenerate these keys before the next POR.
- */
- gen_sk = ctrlpriv->rng4_sh_init & RDSTA_SKVN ? 0 : 1;
- ctrlpriv->rng4_sh_init &= RDSTA_IFMASK;
- do {
- int inst_handles =
- rd_reg32(&ctrl->r4tst[0].rdsta) &
- RDSTA_IFMASK;
- /*
- * If either SH were instantiated by somebody else
- * (e.g. u-boot) then it is assumed that the entropy
- * parameters are properly set and thus the function
- * setting these (kick_trng(...)) is skipped.
- * Also, if a handle was instantiated, do not change
- * the TRNG parameters.
- */
- if (!(ctrlpriv->rng4_sh_init || inst_handles)) {
- dev_info(dev,
- "Entropy delay = %u\n",
- ent_delay);
- kick_trng(pdev, ent_delay);
- ent_delay += 400;
- }
- /*
- * if instantiate_rng(...) fails, the loop will rerun
- * and the kick_trng(...) function will modfiy the
- * upper and lower limits of the entropy sampling
- * interval, leading to a sucessful initialization of
- * the RNG.
- */
- ret = instantiate_rng(dev, inst_handles,
- gen_sk);
- if (ret == -EAGAIN)
- /*
- * if here, the loop will rerun,
- * so don't hog the CPU
- */
- cpu_relax();
- } while ((ret == -EAGAIN) && (ent_delay < RTSDCTL_ENT_DLY_MAX));
- if (ret) {
- dev_err(dev, "failed to instantiate RNG");
- goto caam_remove;
- }
- /*
- * Set handles init'ed by this module as the complement of the
- * already initialized ones
- */
- ctrlpriv->rng4_sh_init = ~ctrlpriv->rng4_sh_init & RDSTA_IFMASK;
- /* Enable RDB bit so that RNG works faster */
- clrsetbits_32(&ctrl->scfgr, 0, SCFGR_RDBENABLE);
+ /* Set DMA masks according to platform ranging */
+ if (sizeof(dma_addr_t) == sizeof(u64))
+ if (of_device_is_compatible(ctrlpriv->pdev->dev.of_node,
+ "fsl,sec-v5.0"))
+ dma_set_mask_and_coherent(ctrlpriv->dev,
+ DMA_BIT_MASK(40));
+ else
+ dma_set_mask_and_coherent(ctrlpriv->dev,
+ DMA_BIT_MASK(36));
+ else
+ dma_set_mask_and_coherent(ctrlpriv->dev, DMA_BIT_MASK(32));
+
+ /*
+ * this is where we should run the descriptor for DRNG init
+ * TRNG must be initialized by SECO
+ */
+ return ret;
+}
+
+/* Probe routine for CAAM top (controller) level */
+static int caam_probe(struct platform_device *pdev)
+{
+ int ret;
+ u64 caam_id;
+ struct device *dev;
+ struct device_node *nprop, *np;
+ struct resource res_regs;
+ struct caam_ctrl __iomem *ctrl;
+ struct caam_drv_private *ctrlpriv;
+ u32 comp_params;
+ int pg_size;
+ int block_offset = 0;
+
+ ctrlpriv = devm_kzalloc(&pdev->dev, sizeof(*ctrlpriv), GFP_KERNEL);
+ if (!ctrlpriv)
+ return -ENOMEM;
+
+ dev = &pdev->dev;
+ dev_set_drvdata(dev, ctrlpriv);
+ ctrlpriv->dev = dev;
+ ctrlpriv->pdev = pdev;
+ nprop = pdev->dev.of_node;
+
+ if (!of_machine_is_compatible("fsl,imx8mq") &&
+ !of_machine_is_compatible("fsl,imx8mm") &&
+ !of_machine_is_compatible("fsl,imx8qm") &&
+ !of_machine_is_compatible("fsl,imx8qxp")) {
+ ret = init_clocks(ctrlpriv);
+ if (ret)
+ goto disable_clocks;
}
+ /* Get configuration properties from device tree */
+ /* First, get register page */
+ ctrl = of_iomap(nprop, 0);
+ if (ctrl == NULL) {
+ dev_err(dev, "caam: of_iomap() failed\n");
+ ret = -ENOMEM;
+ goto disable_clocks;
+ }
+ ctrlpriv->ctrl = (struct caam_ctrl __force *)ctrl;
- /* NOTE: RTIC detection ought to go here, around Si time */
+ if (of_machine_is_compatible("fsl,imx8qm") ||
+ of_machine_is_compatible("fsl,imx8qxp")) {
+ ret = probe_w_seco(ctrlpriv);
+ if (ret)
+ goto iounmap_ctrl;
+ return ret;
+ }
- caam_id = (u64)rd_reg32(&ctrl->perfmon.caam_id_ms) << 32 |
- (u64)rd_reg32(&ctrl->perfmon.caam_id_ls);
+ ctrlpriv->has_seco = false;
- /* Report "alive" for developer to see */
- dev_info(dev, "device ID = 0x%016llx (Era %d)\n", caam_id,
- caam_get_era());
- dev_info(dev, "job rings = %d, qi = %d\n",
- ctrlpriv->total_jobrs, ctrlpriv->qi_present);
+ caam_little_end = !(bool)(rd_reg32(&ctrl->perfmon.status) &
+ (CSTA_PLEND | CSTA_ALT_PLEND));
+
+ /* Finding the page size for using the CTPR_MS register */
+ comp_params = rd_reg32(&ctrl->perfmon.comp_parms_ms);
+ pg_size = (comp_params & CTPR_MS_PG_SZ_MASK) >> CTPR_MS_PG_SZ_SHIFT;
+
+ /* Allocating the block_offset based on the supported page size on
+ * the platform
+ */
+ if (pg_size == 0)
+ block_offset = PG_SIZE_4K;
+ else
+ block_offset = PG_SIZE_64K;
+
+ ctrlpriv->assure = (struct caam_assurance __force *)
+ ((uint8_t *)ctrl +
+ block_offset * ASSURE_BLOCK_NUMBER);
+ ctrlpriv->deco = (struct caam_deco __force *)
+ ((uint8_t *)ctrl +
+ block_offset * DECO_BLOCK_NUMBER);
+
+ detect_era(ctrlpriv);
+
+ /* Get CAAM-SM node and of_iomap() and save */
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-sm");
+ if (!np) {
+ ret = -ENODEV;
+ goto disable_clocks;
+ }
+
+ /* Get CAAM SM registers base address from device tree */
+ ret = of_address_to_resource(np, 0, &res_regs);
+ if (ret) {
+ dev_err(dev, "failed to retrieve registers base from device tree\n");
+ ret = -ENODEV;
+ goto disable_clocks;
+ }
+
+ ctrlpriv->sm_phy = res_regs.start;
+ ctrlpriv->sm_base = devm_ioremap_resource(dev, &res_regs);
+ if (IS_ERR(ctrlpriv->sm_base)) {
+ ret = PTR_ERR(ctrlpriv->sm_base);
+ goto disable_clocks;
+ }
+
+ if (!of_machine_is_compatible("fsl,imx8mq") &&
+ !of_machine_is_compatible("fsl,imx8mm") &&
+ !of_machine_is_compatible("fsl,imx8qm") &&
+ !of_machine_is_compatible("fsl,imx8qxp"))
+ ctrlpriv->sm_size = resource_size(&res_regs);
+ else
+ ctrlpriv->sm_size = PG_SIZE_64K;
-#ifdef CONFIG_DEBUG_FS
/*
- * FIXME: needs better naming distinction, as some amalgamation of
- * "caam" and nprop->full_name. The OF name isn't distinctive,
- * but does separate instances
+ * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel,
+ * long pointers in master configuration register
*/
- perfmon = (struct caam_perfmon __force *)&ctrl->perfmon;
+ clrsetbits_32(&ctrl->mcr, MCFGR_AWCACHE_MASK | MCFGR_LONG_PTR,
+ MCFGR_AWCACHE_CACH | MCFGR_AWCACHE_BUFF |
+ MCFGR_WDENABLE | MCFGR_LARGE_BURST |
+ (sizeof(dma_addr_t) == sizeof(u64) ? MCFGR_LONG_PTR : 0));
- ctrlpriv->dfs_root = debugfs_create_dir(dev_name(dev), NULL);
- ctrlpriv->ctl = debugfs_create_dir("ctl", ctrlpriv->dfs_root);
+ handle_imx6_err005766(ctrlpriv);
- /* Controller-level - performance monitor counters */
+ check_virt(ctrlpriv, comp_params);
- ctrlpriv->ctl_rq_dequeued =
- debugfs_create_file("rq_dequeued",
- S_IRUSR | S_IRGRP | S_IROTH,
- ctrlpriv->ctl, &perfmon->req_dequeued,
- &caam_fops_u64_ro);
- ctrlpriv->ctl_ob_enc_req =
- debugfs_create_file("ob_rq_encrypted",
- S_IRUSR | S_IRGRP | S_IROTH,
- ctrlpriv->ctl, &perfmon->ob_enc_req,
- &caam_fops_u64_ro);
- ctrlpriv->ctl_ib_dec_req =
- debugfs_create_file("ib_rq_decrypted",
- S_IRUSR | S_IRGRP | S_IROTH,
- ctrlpriv->ctl, &perfmon->ib_dec_req,
- &caam_fops_u64_ro);
- ctrlpriv->ctl_ob_enc_bytes =
- debugfs_create_file("ob_bytes_encrypted",
- S_IRUSR | S_IRGRP | S_IROTH,
- ctrlpriv->ctl, &perfmon->ob_enc_bytes,
- &caam_fops_u64_ro);
- ctrlpriv->ctl_ob_prot_bytes =
- debugfs_create_file("ob_bytes_protected",
- S_IRUSR | S_IRGRP | S_IROTH,
- ctrlpriv->ctl, &perfmon->ob_prot_bytes,
- &caam_fops_u64_ro);
- ctrlpriv->ctl_ib_dec_bytes =
- debugfs_create_file("ib_bytes_decrypted",
- S_IRUSR | S_IRGRP | S_IROTH,
- ctrlpriv->ctl, &perfmon->ib_dec_bytes,
- &caam_fops_u64_ro);
- ctrlpriv->ctl_ib_valid_bytes =
- debugfs_create_file("ib_bytes_validated",
- S_IRUSR | S_IRGRP | S_IROTH,
- ctrlpriv->ctl, &perfmon->ib_valid_bytes,
- &caam_fops_u64_ro);
+ /* Set DMA masks according to platform ranging */
+ if (sizeof(dma_addr_t) == sizeof(u64))
+ if (of_device_is_compatible(nprop, "fsl,sec-v5.0"))
+ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+ else
+ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
+ else
+ dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
- /* Controller level - global status values */
- ctrlpriv->ctl_faultaddr =
- debugfs_create_file("fault_addr",
- S_IRUSR | S_IRGRP | S_IROTH,
- ctrlpriv->ctl, &perfmon->faultaddr,
- &caam_fops_u32_ro);
- ctrlpriv->ctl_faultdetail =
- debugfs_create_file("fault_detail",
- S_IRUSR | S_IRGRP | S_IROTH,
- ctrlpriv->ctl, &perfmon->faultdetail,
- &caam_fops_u32_ro);
- ctrlpriv->ctl_faultstatus =
- debugfs_create_file("fault_status",
- S_IRUSR | S_IRGRP | S_IROTH,
- ctrlpriv->ctl, &perfmon->status,
- &caam_fops_u32_ro);
+ ret = enable_jobrings(ctrlpriv, block_offset);
+ if (ret)
+ goto iounmap_ctrl;
- /* Internal covering keys (useful in non-secure mode only) */
- ctrlpriv->ctl_kek_wrap.data = &ctrlpriv->ctrl->kek[0];
- ctrlpriv->ctl_kek_wrap.size = KEK_KEY_SIZE * sizeof(u32);
- ctrlpriv->ctl_kek = debugfs_create_blob("kek",
- S_IRUSR |
- S_IRGRP | S_IROTH,
- ctrlpriv->ctl,
- &ctrlpriv->ctl_kek_wrap);
+ enable_qi(ctrlpriv, block_offset);
- ctrlpriv->ctl_tkek_wrap.data = &ctrlpriv->ctrl->tkek[0];
- ctrlpriv->ctl_tkek_wrap.size = KEK_KEY_SIZE * sizeof(u32);
- ctrlpriv->ctl_tkek = debugfs_create_blob("tkek",
- S_IRUSR |
- S_IRGRP | S_IROTH,
- ctrlpriv->ctl,
- &ctrlpriv->ctl_tkek_wrap);
+ /* If no QI and no rings specified, quit and go home */
+ if ((!ctrlpriv->qi_present) && (!ctrlpriv->total_jobrs)) {
+ dev_err(dev, "no queues configured, terminating\n");
+ ret = -ENOMEM;
+ goto caam_remove;
+ }
- ctrlpriv->ctl_tdsk_wrap.data = &ctrlpriv->ctrl->tdsk[0];
- ctrlpriv->ctl_tdsk_wrap.size = KEK_KEY_SIZE * sizeof(u32);
- ctrlpriv->ctl_tdsk = debugfs_create_blob("tdsk",
- S_IRUSR |
- S_IRGRP | S_IROTH,
- ctrlpriv->ctl,
- &ctrlpriv->ctl_tdsk_wrap);
-#endif
+ /* NOTE: RTIC detection ought to go here, around Si time */
+
+ caam_id = (u64)rd_reg32(&ctrl->perfmon.caam_id_ms) << 32 |
+ (u64)rd_reg32(&ctrl->perfmon.caam_id_ls);
+
+ dev_info(dev, "device ID = 0x%016llx (Era %d)\n"
+ "job rings = %d, qi = %d\n",
+ caam_id,
+ ctrlpriv->era,
+ ctrlpriv->total_jobrs, ctrlpriv->qi_present);
+
+ init_debugfs(ctrlpriv);
return 0;
caam_remove:
@@ -837,14 +736,16 @@ caam_remove:
iounmap_ctrl:
iounmap(ctrl);
-disable_caam_emi_slow:
- clk_disable_unprepare(ctrlpriv->caam_emi_slow);
-disable_caam_aclk:
- clk_disable_unprepare(ctrlpriv->caam_aclk);
-disable_caam_mem:
- clk_disable_unprepare(ctrlpriv->caam_mem);
-disable_caam_ipg:
- clk_disable_unprepare(ctrlpriv->caam_ipg);
+disable_clocks:
+ if (!of_machine_is_compatible("fsl,imx8mq") &&
+ !of_machine_is_compatible("fsl,imx8mm") &&
+ !of_machine_is_compatible("fsl,imx8qm") &&
+ !of_machine_is_compatible("fsl,imx8qxp")) {
+ clk_disable_unprepare(ctrlpriv->caam_emi_slow);
+ clk_disable_unprepare(ctrlpriv->caam_aclk);
+ clk_disable_unprepare(ctrlpriv->caam_mem);
+ clk_disable_unprepare(ctrlpriv->caam_ipg);
+ }
return ret;
}
diff --git a/drivers/crypto/caam/ctrl.h b/drivers/crypto/caam/ctrl.h
index cac5402a46eb..d52e8830d409 100644
--- a/drivers/crypto/caam/ctrl.h
+++ b/drivers/crypto/caam/ctrl.h
@@ -1,13 +1,12 @@
/*
* CAAM control-plane driver backend public-level include definitions
*
- * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
*/
#ifndef CTRL_H
#define CTRL_H
/* Prototypes for backend-level services exposed to APIs */
-int caam_get_era(void);
#endif /* CTRL_H */
diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h
index 513b6646bb36..62474d9c2f72 100644
--- a/drivers/crypto/caam/desc.h
+++ b/drivers/crypto/caam/desc.h
@@ -2,7 +2,7 @@
* CAAM descriptor composition header
* Definitions to support CAAM descriptor instruction generation
*
- * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2008-2015 Freescale Semiconductor, Inc.
*/
#ifndef DESC_H
@@ -400,7 +400,10 @@ struct sec4_sg_entry {
#define FIFOST_TYPE_PKHA_N (0x08 << FIFOST_TYPE_SHIFT)
#define FIFOST_TYPE_PKHA_A (0x0c << FIFOST_TYPE_SHIFT)
#define FIFOST_TYPE_PKHA_B (0x0d << FIFOST_TYPE_SHIFT)
-#define FIFOST_TYPE_AF_SBOX_JKEK (0x10 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_AF_SBOX_CCM_JKEK (0x10 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_AF_SBOX_CCM_TKEK (0x11 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_KEY_CCM_JKEK (0x14 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_KEY_CCM_TKEK (0x15 << FIFOST_TYPE_SHIFT)
#define FIFOST_TYPE_AF_SBOX_TKEK (0x21 << FIFOST_TYPE_SHIFT)
#define FIFOST_TYPE_PKHA_E_JKEK (0x22 << FIFOST_TYPE_SHIFT)
#define FIFOST_TYPE_PKHA_E_TKEK (0x23 << FIFOST_TYPE_SHIFT)
@@ -1104,6 +1107,23 @@ struct sec4_sg_entry {
#define OP_PCL_PKPROT_ECC 0x0002
#define OP_PCL_PKPROT_F2M 0x0001
+/* Blob protocol protinfo bits */
+#define OP_PCL_BLOB_TK 0x0200
+#define OP_PCL_BLOB_EKT 0x0100
+
+#define OP_PCL_BLOB_K2KR_MEM 0x0000
+#define OP_PCL_BLOB_K2KR_C1KR 0x0010
+#define OP_PCL_BLOB_K2KR_C2KR 0x0030
+#define OP_PCL_BLOB_K2KR_AFHAS 0x0050
+#define OP_PCL_BLOB_K2KR_C2KR_SPLIT 0x0070
+
+#define OP_PCL_BLOB_PTXT_SECMEM 0x0008
+#define OP_PCL_BLOB_BLACK 0x0004
+
+#define OP_PCL_BLOB_FMT_NORMAL 0x0000
+#define OP_PCL_BLOB_FMT_MSTR 0x0002
+#define OP_PCL_BLOB_FMT_TEST 0x0003
+
/* For non-protocol/alg-only op commands */
#define OP_ALG_TYPE_SHIFT 24
#define OP_ALG_TYPE_MASK (0x7 << OP_ALG_TYPE_SHIFT)
@@ -1629,4 +1649,12 @@ struct sec4_sg_entry {
/* Frame Descriptor Command for Replacement Job Descriptor */
#define FD_CMD_REPLACE_JOB_DESC 0x20000000
+#define ARC4_BLOCK_SIZE 1
+#define ARC4_MAX_KEY_SIZE 256
+#define ARC4_MIN_KEY_SIZE 1
+
+#define XCBC_MAC_DIGEST_SIZE 16
+#define XCBC_MAC_BLOCK_WORDS 16
+
+
#endif /* DESC_H */
diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h
index a8cd8a78ec1f..5d252de83d37 100644
--- a/drivers/crypto/caam/desc_constr.h
+++ b/drivers/crypto/caam/desc_constr.h
@@ -1,7 +1,8 @@
/*
* caam descriptor construction helper functions
*
- * Copyright 2008-2012 Freescale Semiconductor, Inc.
+ * Copyright 2008-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
*/
#include "desc.h"
@@ -9,7 +10,7 @@
#define IMMEDIATE (1 << 23)
#define CAAM_CMD_SZ sizeof(u32)
-#define CAAM_PTR_SZ sizeof(dma_addr_t)
+#define CAAM_PTR_SZ sizeof(caam_dma_addr_t)
#define CAAM_DESC_BYTES_MAX (CAAM_CMD_SZ * MAX_CAAM_DESCSIZE)
#define DESC_JOB_IO_LEN (CAAM_CMD_SZ * 5 + CAAM_PTR_SZ * 3)
@@ -84,9 +85,9 @@ static inline void init_job_desc_pdb(u32 *desc, u32 options, size_t pdb_bytes)
init_job_desc(desc, (((pdb_len + 1) << HDR_START_IDX_SHIFT)) | options);
}
-static inline void append_ptr(u32 *desc, dma_addr_t ptr)
+static inline void append_ptr(u32 *desc, caam_dma_addr_t ptr)
{
- dma_addr_t *offset = (dma_addr_t *)desc_end(desc);
+ caam_dma_addr_t *offset = (caam_dma_addr_t *)desc_end(desc);
*offset = cpu_to_caam_dma(ptr);
@@ -94,8 +95,8 @@ static inline void append_ptr(u32 *desc, dma_addr_t ptr)
CAAM_PTR_SZ / CAAM_CMD_SZ);
}
-static inline void init_job_desc_shared(u32 *desc, dma_addr_t ptr, int len,
- u32 options)
+static inline void init_job_desc_shared(u32 *desc, caam_dma_addr_t ptr,
+ int len, u32 options)
{
PRINT_POS;
init_job_desc(desc, HDR_SHARED | options |
@@ -149,7 +150,7 @@ static inline u32 *write_cmd(u32 *desc, u32 command)
return desc + 1;
}
-static inline void append_cmd_ptr(u32 *desc, dma_addr_t ptr, int len,
+static inline void append_cmd_ptr(u32 *desc, caam_dma_addr_t ptr, int len,
u32 command)
{
append_cmd(desc, command | len);
@@ -157,7 +158,7 @@ static inline void append_cmd_ptr(u32 *desc, dma_addr_t ptr, int len,
}
/* Write length after pointer, rather than inside command */
-static inline void append_cmd_ptr_extlen(u32 *desc, dma_addr_t ptr,
+static inline void append_cmd_ptr_extlen(u32 *desc, caam_dma_addr_t ptr,
unsigned int len, u32 command)
{
append_cmd(desc, command);
@@ -220,8 +221,8 @@ APPEND_CMD_LEN(seq_fifo_load, SEQ_FIFO_LOAD)
APPEND_CMD_LEN(seq_fifo_store, SEQ_FIFO_STORE)
#define APPEND_CMD_PTR(cmd, op) \
-static inline void append_##cmd(u32 *desc, dma_addr_t ptr, unsigned int len, \
- u32 options) \
+static inline void append_##cmd(u32 *desc, caam_dma_addr_t ptr, \
+ unsigned int len, u32 options) \
{ \
PRINT_POS; \
append_cmd_ptr(desc, ptr, len, CMD_##op | options); \
@@ -231,8 +232,8 @@ APPEND_CMD_PTR(load, LOAD)
APPEND_CMD_PTR(fifo_load, FIFO_LOAD)
APPEND_CMD_PTR(fifo_store, FIFO_STORE)
-static inline void append_store(u32 *desc, dma_addr_t ptr, unsigned int len,
- u32 options)
+static inline void append_store(u32 *desc, caam_dma_addr_t ptr,
+ unsigned int len, u32 options)
{
u32 cmd_src;
@@ -249,9 +250,10 @@ static inline void append_store(u32 *desc, dma_addr_t ptr, unsigned int len,
}
#define APPEND_SEQ_PTR_INTLEN(cmd, op) \
-static inline void append_seq_##cmd##_ptr_intlen(u32 *desc, dma_addr_t ptr, \
- unsigned int len, \
- u32 options) \
+static inline void append_seq_##cmd##_ptr_intlen(u32 *desc, \
+ caam_dma_addr_t ptr, \
+ unsigned int len, \
+ u32 options) \
{ \
PRINT_POS; \
if (options & (SQIN_RTO | SQIN_PRE)) \
@@ -273,7 +275,7 @@ APPEND_CMD_PTR_TO_IMM(load, LOAD);
APPEND_CMD_PTR_TO_IMM(fifo_load, FIFO_LOAD);
#define APPEND_CMD_PTR_EXTLEN(cmd, op) \
-static inline void append_##cmd##_extlen(u32 *desc, dma_addr_t ptr, \
+static inline void append_##cmd##_extlen(u32 *desc, caam_dma_addr_t ptr, \
unsigned int len, u32 options) \
{ \
PRINT_POS; \
@@ -287,7 +289,7 @@ APPEND_CMD_PTR_EXTLEN(seq_out_ptr, SEQ_OUT_PTR)
* the size of its type
*/
#define APPEND_CMD_PTR_LEN(cmd, op, type) \
-static inline void append_##cmd(u32 *desc, dma_addr_t ptr, \
+static inline void append_##cmd(u32 *desc, caam_dma_addr_t ptr, \
type len, u32 options) \
{ \
PRINT_POS; \
diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c
index 33e41ea83fcc..918061db4134 100644
--- a/drivers/crypto/caam/error.c
+++ b/drivers/crypto/caam/error.c
@@ -117,6 +117,20 @@ static const char * const rng_err_id_list[] = {
"Secure key generation",
};
+#define SPRINTFCAT(str, format, param, max_alloc) \
+{ \
+ char *tmp; \
+ \
+ tmp = kmalloc(sizeof(format) + max_alloc, GFP_ATOMIC); \
+ if (likely(tmp)) { \
+ sprintf(tmp, format, param); \
+ strcat(str, tmp); \
+ kfree(tmp); \
+ } else { \
+ strcat(str, "kmalloc failure in SPRINTFCAT"); \
+ } \
+}
+
static void report_ccb_status(struct device *jrdev, const u32 status,
const char *error)
{
diff --git a/drivers/crypto/caam/inst_rng.c b/drivers/crypto/caam/inst_rng.c
new file mode 100644
index 000000000000..51bedb9dbf6a
--- /dev/null
+++ b/drivers/crypto/caam/inst_rng.c
@@ -0,0 +1,380 @@
+/*
+ * CAAM RNG instantiation driver backend
+ *
+ * Copyright 2017-2018 NXP
+ */
+
+#include <linux/device.h>
+#include <linux/of_address.h>
+#include <linux/wait.h>
+#include "compat.h"
+#include "regs.h"
+#include "intern.h"
+#include "jr.h"
+#include "desc_constr.h"
+#include "error.h"
+#include "ctrl.h"
+#include "inst_rng.h"
+
+static DECLARE_WAIT_QUEUE_HEAD(wq_desc);
+static int desc_completed;
+static int desc_status;
+
+/*
+ * Descriptor to instantiate RNG State Handle 0 in normal mode and
+ * load the JDKEK, TDKEK and TDSK registers
+ */
+static void build_instantiation_desc(u32 *desc, int handle, int do_sk)
+{
+ u32 *jump_cmd, op_flags;
+
+ init_job_desc(desc, 0);
+
+ op_flags = OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
+ (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INIT;
+
+ /* INIT RNG in non-test mode */
+ append_operation(desc, op_flags);
+
+ if (!handle && do_sk) {
+ /*
+ * For SH0, Secure Keys must be generated as well
+ */
+
+ /* wait for done */
+ jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1);
+ set_jump_tgt_here(desc, jump_cmd);
+
+ /*
+ * load 1 to clear written reg:
+ * resets the done interrupt and returns the RNG to idle.
+ */
+ append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW);
+
+ /* Initialize State Handle */
+ append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
+ OP_ALG_AAI_RNG4_SK);
+ }
+
+ append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT);
+}
+
+/* Descriptor for deinstantiation of State Handle 0 of the RNG block. */
+static void build_deinstantiation_desc(u32 *desc, int handle)
+{
+ init_job_desc(desc, 0);
+
+ /* Uninstantiate State Handle 0 */
+ append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
+ (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INITFINAL);
+
+ append_jump(desc, JUMP_CLASS_CLASS1 | JUMP_TYPE_HALT);
+}
+
+void cbk_jr_rng_inst(struct device *jrdev, u32 *desc, u32 status, void *areq)
+{
+ if ((status & JRSTA_SSRC_JUMP_HALT_CC) == JRSTA_SSRC_JUMP_HALT_CC) {
+ dev_info(jrdev, "Instantiated RNG4 SH%d.\n", *((int *)areq));
+ desc_status = 0;
+ } else {
+ desc_status = -EAGAIN;
+ }
+ desc_completed = 1;
+ wake_up(&wq_desc);
+}
+
+/*
+ * run_descriptor_jr - runs a descriptor on first JR
+ * @status - descriptor status, after being run
+ *
+ * Return: - 0 if no error occurred
+ * - -ENODEV if the DECO couldn't be acquired
+ * - -EAGAIN if an error occurred while executing the descriptor
+ */
+static int run_descriptor_jr(u32 *desc, int sh_idx)
+{
+ struct device *jrdev;
+ int ret;
+
+ jrdev = caam_jr_alloc();
+ if (IS_ERR(jrdev)) {
+ pr_err("Job Ring Device allocation for transform failed\n");
+ return -ENODEV;
+ }
+ ret = caam_jr_enqueue(jrdev, desc, cbk_jr_rng_inst, &sh_idx);
+ if (ret) {
+ dev_err(jrdev, "caam_jr_enqueue() failed\n");
+ return ret;
+ }
+ /* wait for job descriptor completion */
+ wait_event(wq_desc, desc_completed != 0);
+ desc_completed = 0;
+ caam_jr_free(jrdev);
+ return desc_status;
+}
+
+/*
+ * instantiate_rng - builds and executes a descriptor on JR0,
+ * which initializes the RNG block.
+ * @state_handle_mask - bitmask containing the instantiation status
+ * for the RNG4 state handles which exist in
+ * the RNG4 block: 1 if it's been instantiated
+ * by an external entry, 0 otherwise.
+ * @gen_sk - generate data to be loaded into the JDKEK, TDKEK and TDSK;
+ * Caution: this can be done only once; if the keys need to be
+ * regenerated, a POR is required
+ *
+ * Return: - 0 if no error occurred
+ * - -ENOMEM if there isn't enough memory to allocate the descriptor
+ * - -ENODEV if DECO0 couldn't be acquired
+ * - -EAGAIN if an error occurred when executing the descriptor
+ * f.i. there was a RNG hardware error due to not "good enough"
+ * entropy being acquired.
+ */
+static int instantiate_rng(int state_handle_mask, int gen_sk)
+{
+ u32 *desc;
+ int sh_idx, ret = 0;
+
+ desc = kmalloc(CAAM_CMD_SZ * 7, GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) {
+ /*
+ * If the corresponding bit is set, this state handle
+ * was initialized by somebody else, so it's left alone.
+ */
+ if ((1 << sh_idx) & state_handle_mask)
+ continue;
+
+ /* Create the descriptor for instantiating RNG State Handle */
+ build_instantiation_desc(desc, sh_idx, gen_sk);
+
+ /* Try to run it through JR */
+ ret = run_descriptor_jr(desc, sh_idx);
+ if (ret)
+ pr_debug("Failed to run desc RNG4 SH%d status (0x%x)\n",
+ sh_idx, ret);
+ /* Clear the contents before recreating the descriptor */
+ memset(desc, 0x00, CAAM_CMD_SZ * 7);
+ }
+
+ kfree(desc);
+
+ return ret;
+}
+
+/*
+ * deinstantiate_rng - builds and executes a descriptor on JR0,
+ * which deinitializes the RNG block.
+ * @state_handle_mask - bitmask containing the instantiation status
+ * for the RNG4 state handles which exist in
+ * the RNG4 block: 1 if it's been instantiated
+ *
+ * Return: - 0 if no error occurred
+ * - -ENOMEM if there isn't enough memory to allocate the descriptor
+ * - -ENODEV if DECO0 couldn't be acquired
+ * - -EAGAIN if an error occurred when executing the descriptor
+ */
+int deinstantiate_rng(int state_handle_mask)
+{
+ u32 *desc;
+ int sh_idx, ret = 0;
+
+ desc = kmalloc(CAAM_CMD_SZ * 3, GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+
+ for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) {
+ /*
+ * If the corresponding bit is set, then it means the state
+ * handle was initialized by us, and thus it needs to be
+ * deintialized as well
+ */
+ if ((1 << sh_idx) & state_handle_mask) {
+ /*
+ * Create the descriptor for deinstantating this state
+ * handle
+ */
+ build_deinstantiation_desc(desc, sh_idx);
+
+ /* Try to run it through JR */
+ ret = run_descriptor_jr(desc, sh_idx);
+ if (ret)
+ pr_debug("Failed to run desc to deinstantiate RNG4 SH%d\n",
+ sh_idx);
+ }
+ }
+
+ kfree(desc);
+
+ return ret;
+}
+
+/*
+ * kick_trng - sets the various parameters for enabling the initialization
+ * of the RNG4 block in CAAM
+ * @ctrldev - pointer to the device
+ * @ent_delay - Defines the length (in system clocks) of each entropy sample.
+ */
+static void kick_trng(struct device *ctrldev, int ent_delay)
+{
+ struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
+ struct caam_ctrl __iomem *ctrl;
+ struct rng4tst __iomem *r4tst;
+ u32 val;
+
+ ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl;
+ r4tst = &ctrl->r4tst[0];
+
+ /* put RNG4 into program mode */
+ clrsetbits_32(&r4tst->rtmctl, 0, RTMCTL_PRGM);
+
+ /*
+ * Performance-wise, it does not make sense to
+ * set the delay to a value that is lower
+ * than the last one that worked (i.e. the state handles
+ * were instantiated properly. Thus, instead of wasting
+ * time trying to set the values controlling the sample
+ * frequency, the function simply returns.
+ */
+ val = (rd_reg32(&r4tst->rtsdctl) & RTSDCTL_ENT_DLY_MASK)
+ >> RTSDCTL_ENT_DLY_SHIFT;
+ if (ent_delay <= val) {
+ /* put RNG4 into run mode */
+ clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM, 0);
+ return;
+ }
+
+ val = rd_reg32(&r4tst->rtsdctl);
+ val = (val & ~RTSDCTL_ENT_DLY_MASK) |
+ (ent_delay << RTSDCTL_ENT_DLY_SHIFT);
+ wr_reg32(&r4tst->rtsdctl, val);
+ /* min. freq. count, equal to 1/4 of the entropy sample length */
+ wr_reg32(&r4tst->rtfrqmin, ent_delay >> 2);
+ /* max. freq. count, equal to 16 times the entropy sample length */
+ wr_reg32(&r4tst->rtfrqmax, ent_delay << 4);
+ /* read the control register */
+ val = rd_reg32(&r4tst->rtmctl);
+ /*
+ * select raw sampling in both entropy shifter
+ * and statistical checker
+ */
+ clrsetbits_32(&val, 0, RTMCTL_SAMP_MODE_RAW_ES_SC);
+ /* put RNG4 into run mode */
+ clrsetbits_32(&val, RTMCTL_PRGM, 0);
+ /* write back the control register */
+ wr_reg32(&r4tst->rtmctl, val);
+}
+
+/*
+ * inst_rng_imx - RNG instantiation function for i.MX6/7/8m platforms
+ * @pdev - pointer to the device
+ */
+int inst_rng_imx(struct platform_device *pdev)
+{
+ struct device *ctrldev, *dev;
+ struct caam_drv_private *ctrlpriv;
+ struct caam_ctrl __iomem *ctrl;
+ int ret = 0, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN;
+ u32 cha_vid_ls;
+
+ dev = &pdev->dev;
+ ctrldev = pdev->dev.parent;
+ ctrlpriv = dev_get_drvdata(ctrldev);
+ ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl;
+
+#ifndef CONFIG_ARM64
+ /*
+ * Check if the Secure Firmware is running,
+ * check only for i.MX6 and i.MX7
+ */
+ if (of_find_compatible_node(NULL, NULL, "linaro,optee-tz")) {
+ pr_info("RNG Instantation done by Secure Firmware\n");
+ return ret;
+ }
+#endif
+
+ cha_vid_ls = rd_reg32(&ctrl->perfmon.cha_id_ls);
+ /*
+ * If SEC has RNG version >= 4 and RNG state handle has not been
+ * already instantiated, do RNG instantiation
+ */
+ if ((cha_vid_ls & CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT >= 4) {
+ ctrlpriv->rng4_sh_init =
+ rd_reg32(&ctrl->r4tst[0].rdsta);
+ /*
+ * If the secure keys (TDKEK, JDKEK, TDSK), were already
+ * generated, signal this to the function that is instantiating
+ * the state handles. An error would occur if RNG4 attempts
+ * to regenerate these keys before the next POR.
+ */
+ gen_sk = ctrlpriv->rng4_sh_init & RDSTA_SKVN ? 0 : 1;
+ ctrlpriv->rng4_sh_init &= RDSTA_IFMASK;
+ do {
+ int inst_handles =
+ rd_reg32(&ctrl->r4tst[0].rdsta) &
+ RDSTA_IFMASK;
+ /*
+ * If either SH were instantiated by somebody else
+ * (e.g. u-boot) then it is assumed that the entropy
+ * parameters are properly set and thus the function
+ * setting these (kick_trng(...)) is skipped.
+ * Also, if a handle was instantiated, do not change
+ * the TRNG parameters.
+ */
+ if (!(ctrlpriv->rng4_sh_init || inst_handles)) {
+ dev_info(dev,
+ "Entropy delay = %u\n",
+ ent_delay);
+ kick_trng(ctrldev, ent_delay);
+ ent_delay += ENT_DELAY_STEP;
+ }
+ /*
+ * if instantiate_rng(...) fails, the loop will rerun
+ * and the kick_trng(...) function will modfiy the
+ * upper and lower limits of the entropy sampling
+ * interval, leading to a sucessful initialization of
+ * the RNG.
+ */
+ ret = instantiate_rng(inst_handles, gen_sk);
+ if (ret == -EAGAIN)
+ /*
+ * if here, the loop will rerun,
+ * so don't hog the CPU
+ */
+ cpu_relax();
+ } while ((ret == -EAGAIN) && (ent_delay < RTSDCTL_ENT_DLY_MAX));
+ if (ret) {
+ dev_err(dev, "failed to instantiate RNG");
+ return ret;
+ }
+ /*
+ * Set handles init'ed by this module as the complement of the
+ * already initialized ones
+ */
+ ctrlpriv->rng4_sh_init = ~ctrlpriv->rng4_sh_init & RDSTA_IFMASK;
+ /* Enable RDB bit so that RNG works faster */
+ clrsetbits_32(&ctrl->scfgr, 0, SCFGR_RDBENABLE);
+ }
+ return ret;
+}
+
+/*
+ * deinst_rng - RNG de-instantiation function
+ * @pdev - pointer to the device
+ */
+int deinst_rng(struct platform_device *pdev)
+{
+ struct device *ctrldev, *dev;
+ struct caam_drv_private *ctrlpriv;
+ int ret = 0;
+
+ dev = &pdev->dev;
+ ctrldev = pdev->dev.parent;
+ ctrlpriv = dev_get_drvdata(ctrldev);
+
+ ret = deinstantiate_rng(ctrlpriv->rng4_sh_init);
+ return ret;
+}
diff --git a/drivers/crypto/caam/inst_rng.h b/drivers/crypto/caam/inst_rng.h
new file mode 100644
index 000000000000..66f098d94920
--- /dev/null
+++ b/drivers/crypto/caam/inst_rng.h
@@ -0,0 +1,17 @@
+/*
+ * CAAM Private/internal definitions between modules
+ *
+ * Copyright 2017-2018 NXP
+ */
+
+#ifndef INST_RNG_H
+#define INST_RNG_H
+
+#include <linux/platform_device.h>
+
+#define ENT_DELAY_STEP (400)
+int inst_rng_imx(struct platform_device *pdev);
+
+int deinst_rng(struct platform_device *pdev);
+
+#endif /* INST_RNG_H */
diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h
index e2bcacc1a921..ccddfd688908 100644
--- a/drivers/crypto/caam/intern.h
+++ b/drivers/crypto/caam/intern.h
@@ -2,16 +2,21 @@
* CAAM/SEC 4.x driver backend
* Private/internal definitions between modules
*
- * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright 2008-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
*
*/
#ifndef INTERN_H
#define INTERN_H
+#include "regs.h"
/* Currently comes from Kconfig param as a ^2 (driver-required) */
#define JOBR_DEPTH (1 << CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE)
+/* Job ring count */
+#define JOBR_MAX_COUNT 4
+
/* Kconfig params for interrupt coalescing if selected (else zero) */
#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_INTC
#define JOBR_INTC JRCFG_ICEN
@@ -31,7 +36,7 @@ struct caam_jrentry_info {
void (*callbk)(struct device *dev, u32 *desc, u32 status, void *arg);
void *cbkarg; /* Argument per ring entry */
u32 *desc_addr_virt; /* Stored virt addr for postprocessing */
- dma_addr_t desc_addr_dma; /* Stored bus addr for done matching */
+ caam_dma_addr_t desc_addr_dma; /* Stored bus addr for done matching */
u32 desc_size; /* Stored size for postprocessing, header derived */
};
@@ -53,7 +58,7 @@ struct caam_drv_private_jr {
spinlock_t inplock ____cacheline_aligned; /* Input ring index lock */
int inp_ring_write_index; /* Input index "tail" */
int head; /* entinfo (s/w ring) head index */
- dma_addr_t *inpring; /* Base of input ring, alloc DMA-safe */
+ caam_dma_addr_t *inpring; /* Base of input ring, alloc DMA-safe */
spinlock_t outlock ____cacheline_aligned; /* Output ring index lock */
int out_ring_read_index; /* Output index "tail" */
int tail; /* entinfo (s/w ring) tail index */
@@ -66,15 +71,27 @@ struct caam_drv_private_jr {
struct caam_drv_private {
struct device *dev;
+ struct device *smdev;
struct platform_device **jrpdev; /* Alloc'ed array per sub-device */
struct platform_device *pdev;
+ /*
+ * ERA of the CAAM block,
+ * -ENOTSUPP if no era version was supplied or detected.
+ */
+#define IMX_ERR005766_ERA 4 /* ERA affected by i.mx AXI errata */
+ int era;
+
/* Physical-presence section */
struct caam_ctrl __iomem *ctrl; /* controller region */
struct caam_deco __iomem *deco; /* DECO/CCB views */
struct caam_assurance __iomem *assure;
struct caam_queue_if __iomem *qi; /* QI control region */
- struct caam_job_ring __iomem *jr[4]; /* JobR's register space */
+ /* JobR's register space */
+ struct caam_job_ring __iomem *jr[JOBR_MAX_COUNT];
+ dma_addr_t __iomem *sm_base; /* Secure memory storage base */
+ phys_addr_t sm_phy; /* Secure memory storage physical */
+ u32 sm_size;
/*
* Detected geometry block. Filled in from device tree if powerpc,
@@ -82,7 +99,6 @@ struct caam_drv_private {
*/
u8 total_jobrs; /* Total Job Rings in device */
u8 qi_present; /* Nonzero if QI present in device */
- int secvio_irq; /* Security violation interrupt number */
int virt_en; /* Virtualization enabled in CAAM */
#define RNG4_MAX_HANDLES 2
@@ -96,6 +112,8 @@ struct caam_drv_private {
struct clk *caam_aclk;
struct clk *caam_emi_slow;
+ bool has_seco;
+ u32 first_jr_index;
/*
* debugfs entries for developer view into driver/device
* variables at runtime.
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index 6d475a2e298c..73e5596f82bd 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -2,17 +2,18 @@
* CAAM/SEC 4.x transport/backend driver
* JobR backend functionality
*
- * Copyright 2008-2012 Freescale Semiconductor, Inc.
+ * Copyright 2008-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
*/
#include <linux/of_irq.h>
#include <linux/of_address.h>
-
#include "compat.h"
#include "regs.h"
#include "jr.h"
#include "desc.h"
#include "intern.h"
+#include "inst_rng.h"
struct jr_driver_data {
/* List of Physical JobR's with the Driver */
@@ -26,6 +27,7 @@ static int caam_reset_hw_jr(struct device *dev)
{
struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
unsigned int timeout = 100000;
+ unsigned int reg_value;
/*
* mask interrupts since we are going to poll
@@ -35,9 +37,11 @@ static int caam_reset_hw_jr(struct device *dev)
/* initiate flush (required prior to reset) */
wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET);
- while (((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) ==
- JRINT_ERR_HALT_INPROGRESS) && --timeout)
+ do {
cpu_relax();
+ reg_value = rd_reg32(&jrp->rregs->jrintstatus);
+ } while (((reg_value & JRINT_ERR_HALT_MASK) ==
+ JRINT_ERR_HALT_INPROGRESS) && --timeout);
if ((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) !=
JRINT_ERR_HALT_COMPLETE || timeout == 0) {
@@ -48,8 +52,10 @@ static int caam_reset_hw_jr(struct device *dev)
/* initiate reset */
timeout = 100000;
wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET);
- while ((rd_reg32(&jrp->rregs->jrcommand) & JRCR_RESET) && --timeout)
+ do {
cpu_relax();
+ reg_value = rd_reg32(&jrp->rregs->jrcommand);
+ } while ((reg_value & JRCR_RESET) && --timeout);
if (timeout == 0) {
dev_err(dev, "failed to reset job ring %d\n", jrp->ridx);
@@ -100,6 +106,12 @@ static int caam_jr_remove(struct platform_device *pdev)
jrpriv = dev_get_drvdata(jrdev);
/*
+ * Deinstantiate RNG by first JR
+ */
+ if (jrpriv->ridx == 0)
+ deinst_rng(pdev);
+
+ /*
* Return EBUSY if job ring already allocated.
*/
if (atomic_read(&jrpriv->tfm_count)) {
@@ -297,8 +309,7 @@ EXPORT_SYMBOL(caam_jr_free);
* caam_jr_enqueue() - Enqueue a job descriptor head. Returns 0 if OK,
* -EBUSY if the queue is full, -EIO if it cannot map the caller's
* descriptor.
- * @dev: device of the job ring to be used. This device should have
- * been assigned prior by caam_jr_register().
+ * @dev: device of the job ring to be used.
* @desc: points to a job descriptor that execute our request. All
* descriptors (and all referenced data) must be in a DMAable
* region, and all data references must be physical addresses
@@ -358,7 +369,6 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
head_entry->desc_addr_dma = desc_dma;
jrp->inpring[jrp->inp_ring_write_index] = cpu_to_caam_dma(desc_dma);
-
/*
* Guarantee that the descriptor's DMA address has been written to
* the next slot in the ring before the write index is updated, since
@@ -395,6 +405,10 @@ static int caam_jr_init(struct device *dev)
jrp = dev_get_drvdata(dev);
+ error = caam_reset_hw_jr(dev);
+ if (error)
+ goto out_kill_deq;
+
tasklet_init(&jrp->irqtask, caam_jr_dequeue, (unsigned long)dev);
/* Connect job ring interrupt handler. */
@@ -406,10 +420,6 @@ static int caam_jr_init(struct device *dev)
goto out_kill_deq;
}
- error = caam_reset_hw_jr(dev);
- if (error)
- goto out_free_irq;
-
error = -ENOMEM;
jrp->inpring = dma_alloc_coherent(dev, sizeof(*jrp->inpring) *
JOBR_DEPTH, &inpbusaddr, GFP_KERNEL);
@@ -474,7 +484,7 @@ static int caam_jr_probe(struct platform_device *pdev)
struct device *jrdev;
struct device_node *nprop;
struct caam_job_ring __iomem *ctrl;
- struct caam_drv_private_jr *jrpriv;
+ struct caam_drv_private_jr *jrpriv, *jrppriv;
static int total_jobrs;
int error;
@@ -509,6 +519,10 @@ static int caam_jr_probe(struct platform_device *pdev)
/* Identify the interrupt */
jrpriv->irq = irq_of_parse_and_map(nprop, 0);
+ if (jrpriv->irq <= 0) {
+ kfree(jrpriv);
+ return -EINVAL;
+ }
/* Now do the platform independent part */
error = caam_jr_init(jrdev); /* now turn on hardware */
@@ -516,7 +530,7 @@ static int caam_jr_probe(struct platform_device *pdev)
irq_dispose_mapping(jrpriv->irq);
iounmap(ctrl);
return error;
- }
+ }
jrpriv->dev = jrdev;
spin_lock(&driver_data.jr_alloc_lock);
@@ -525,9 +539,68 @@ static int caam_jr_probe(struct platform_device *pdev)
atomic_set(&jrpriv->tfm_count, 0);
+ device_init_wakeup(&pdev->dev, 1);
+ device_set_wakeup_enable(&pdev->dev, false);
+ /*
+ * Instantiate RNG by JR rather than DECO
+ */
+ spin_lock(&driver_data.jr_alloc_lock);
+ if (list_empty(&driver_data.jr_list)) {
+ spin_unlock(&driver_data.jr_alloc_lock);
+ dev_err(jrdev, "jr_list is empty\n");
+ return -ENODEV;
+ }
+ jrppriv = list_first_entry(&driver_data.jr_list,
+ struct caam_drv_private_jr, list_node);
+ spin_unlock(&driver_data.jr_alloc_lock);
+ /*
+ * If this is the first available JR
+ * then try to instantiate RNG
+ */
+ if (jrppriv->ridx == jrpriv->ridx) {
+ if (!of_machine_is_compatible("fsl,imx8qm") &&
+ !of_machine_is_compatible("fsl,imx8qxp"))
+ /*
+ * This call is done for legacy SOCs:
+ * i.MX6 i.MX7 and i.MX8M (mScale).
+ */
+ error = inst_rng_imx(pdev);
+ }
+ if (error != 0) {
+ spin_lock(&driver_data.jr_alloc_lock);
+ list_del(&jrpriv->list_node);
+ spin_unlock(&driver_data.jr_alloc_lock);
+ }
+ return error;
+}
+
+#ifdef CONFIG_PM
+static int caam_jr_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(jrpriv->irq);
+
+ return 0;
+}
+
+static int caam_jr_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct caam_drv_private_jr *jrpriv = platform_get_drvdata(pdev);
+
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(jrpriv->irq);
+
return 0;
}
+static SIMPLE_DEV_PM_OPS(caam_jr_pm_ops, caam_jr_suspend,
+ caam_jr_resume);
+#endif
+
static struct of_device_id caam_jr_match[] = {
{
.compatible = "fsl,sec-v4.0-job-ring",
@@ -543,6 +616,9 @@ static struct platform_driver caam_jr_driver = {
.driver = {
.name = "caam_jr",
.of_match_table = caam_jr_match,
+#ifdef CONFIG_PM
+ .pm = &caam_jr_pm_ops,
+#endif
},
.probe = caam_jr_probe,
.remove = caam_jr_remove,
diff --git a/drivers/crypto/caam/pdb.h b/drivers/crypto/caam/pdb.h
index aaa00dd1c601..63a6ae6de83a 100644
--- a/drivers/crypto/caam/pdb.h
+++ b/drivers/crypto/caam/pdb.h
@@ -2,12 +2,14 @@
* CAAM Protocol Data Block (PDB) definition header file
*
* Copyright 2008-2016 Freescale Semiconductor, Inc.
+ * Copyright 2018 NXP
*
*/
#ifndef CAAM_PDB_H
#define CAAM_PDB_H
#include "compat.h"
+#include "regs.h"
/*
* PDB- IPSec ESP Header Modification Options
@@ -502,10 +504,10 @@ struct dsa_verify_pdb {
*/
struct rsa_pub_pdb {
u32 sgf;
- dma_addr_t f_dma;
- dma_addr_t g_dma;
- dma_addr_t n_dma;
- dma_addr_t e_dma;
+ caam_dma_addr_t f_dma;
+ caam_dma_addr_t g_dma;
+ caam_dma_addr_t n_dma;
+ caam_dma_addr_t e_dma;
u32 f_len;
} __packed;
@@ -519,10 +521,10 @@ struct rsa_pub_pdb {
*/
struct rsa_priv_f1_pdb {
u32 sgf;
- dma_addr_t g_dma;
- dma_addr_t f_dma;
- dma_addr_t n_dma;
- dma_addr_t d_dma;
+ caam_dma_addr_t g_dma;
+ caam_dma_addr_t f_dma;
+ caam_dma_addr_t n_dma;
+ caam_dma_addr_t d_dma;
} __packed;
#endif
diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h
index 84d2f838a063..aa296862ce06 100644
--- a/drivers/crypto/caam/regs.h
+++ b/drivers/crypto/caam/regs.h
@@ -1,7 +1,8 @@
/*
* CAAM hardware register-level view
*
- * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright 2008-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
*/
#ifndef REGS_H
@@ -134,7 +135,7 @@ static inline void clrsetbits_32(void __iomem *reg, u32 clear, u32 set)
* base + 0x0000 : least-significant 32 bits
* base + 0x0004 : most-significant 32 bits
*/
-#ifdef CONFIG_64BIT
+#if defined(CONFIG_64BIT) && !(defined(CONFIG_HAVE_IMX8_SOC))
static inline void wr_reg64(void __iomem *reg, u64 data)
{
if (caam_little_end)
@@ -179,7 +180,7 @@ static inline u64 rd_reg64(void __iomem *reg)
}
#endif /* CONFIG_64BIT */
-#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+#if defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) && !defined(CONFIG_HAVE_IMX8_SOC)
#ifdef CONFIG_SOC_IMX7D
#define cpu_to_caam_dma(value) \
(((u64)cpu_to_caam32(lower_32_bits(value)) << 32) | \
@@ -205,11 +206,26 @@ static inline u64 rd_reg64(void __iomem *reg)
#endif
/*
+ * On i.MX8 boards the arch is arm64 but the CAAM dma address size is
+ * 32 bits on 8MQ and 36 bits on 8QM and 8QX.
+ * For 8QM and 8QM there is a configurable field PS called pointer size
+ * in the MCFGR register to switch between 32 and 64 (default 32)
+ * But this register is only accessible by the SECO and is left to its
+ * default value.
+ * Here we set the CAAM dma address size to 32 bits for all i.MX8
+ */
+#ifdef CONFIG_HAVE_IMX8_SOC
+#define caam_dma_addr_t u32
+#else
+#define caam_dma_addr_t dma_addr_t
+#endif
+
+/*
* jr_outentry
* Represents each entry in a JobR output ring
*/
struct jr_outentry {
- dma_addr_t desc;/* Pointer to completed descriptor */
+ caam_dma_addr_t desc;/* Pointer to completed descriptor */
u32 jrstatus; /* Status for completed descriptor */
} __packed;
@@ -271,12 +287,26 @@ struct jr_outentry {
#define CHA_ID_MS_JR_SHIFT 28
#define CHA_ID_MS_JR_MASK (0xfull << CHA_ID_MS_JR_SHIFT)
+/*
+ * caam_perfmon - Performance Monitor/Secure Memory Status/
+ * CAAM Global Status/Component Version IDs
+ *
+ * Spans f00-fff wherever instantiated
+ */
+
struct sec_vid {
u16 ip_id;
u8 maj_rev;
u8 min_rev;
};
+#define SEC_VID_IPID_SHIFT 16
+#define SEC_VID_MAJ_SHIFT 8
+#define SEC_VID_MAJ_MASK 0x0000FF00
+
+#define CCB_VID_ERA_SHIFT 24
+#define CCB_VID_ERA_MASK 0x000000FF
+
struct caam_perfmon {
/* Performance Monitor Registers f00-f9f */
u64 req_dequeued; /* PC_REQ_DEQ - Dequeued Requests */
@@ -299,17 +329,22 @@ struct caam_perfmon {
#define CTPR_MS_PG_SZ_SHIFT 4
u32 comp_parms_ms; /* CTPR - Compile Parameters Register */
u32 comp_parms_ls; /* CTPR - Compile Parameters Register */
- u64 rsvd1[2];
+ /* Secure Memory State Visibility */
+ u32 rsvd1;
+ u32 smstatus; /* Secure memory status */
+ u32 rsvd2;
+ u32 smpartown; /* Secure memory partition owner */
/* CAAM Global Status fc0-fdf */
u64 faultaddr; /* FAR - Fault Address */
u32 faultliodn; /* FALR - Fault Address LIODN */
u32 faultdetail; /* FADR - Fault Addr Detail */
- u32 rsvd2;
#define CSTA_PLEND BIT(10)
#define CSTA_ALT_PLEND BIT(18)
+ u32 rsvd3;
u32 status; /* CSTA - CAAM Status */
- u64 rsvd3;
+ u32 smpart; /* Secure Memory Partition Parameters */
+ u32 smvid; /* Secure Memory Version ID */
/* Component Instantiation Parameters fe0-fff */
u32 rtic_id; /* RVID - RTIC Version ID */
@@ -322,6 +357,62 @@ struct caam_perfmon {
u32 caam_id_ls; /* CAAMVID - CAAM Version ID LS */
};
+#define SMSTATUS_PART_SHIFT 28
+#define SMSTATUS_PART_MASK (0xf << SMSTATUS_PART_SHIFT)
+#define SMSTATUS_PAGE_SHIFT 16
+#define SMSTATUS_PAGE_MASK (0x7ff << SMSTATUS_PAGE_SHIFT)
+#define SMSTATUS_MID_SHIFT 8
+#define SMSTATUS_MID_MASK (0x3f << SMSTATUS_MID_SHIFT)
+#define SMSTATUS_ACCERR_SHIFT 4
+#define SMSTATUS_ACCERR_MASK (0xf << SMSTATUS_ACCERR_SHIFT)
+#define SMSTATUS_ACCERR_NONE 0
+#define SMSTATUS_ACCERR_ALLOC 1 /* Page not allocated */
+#define SMSTATUS_ACCESS_ID 2 /* Not granted by ID */
+#define SMSTATUS_ACCESS_WRITE 3 /* Writes not allowed */
+#define SMSTATUS_ACCESS_READ 4 /* Reads not allowed */
+#define SMSTATUS_ACCESS_NONKEY 6 /* Non-key reads not allowed */
+#define SMSTATUS_ACCESS_BLOB 9 /* Blob access not allowed */
+#define SMSTATUS_ACCESS_DESCB 10 /* Descriptor Blob access spans pages */
+#define SMSTATUS_ACCESS_NON_SM 11 /* Outside Secure Memory range */
+#define SMSTATUS_ACCESS_XPAGE 12 /* Access crosses pages */
+#define SMSTATUS_ACCESS_INITPG 13 /* Page still initializing */
+#define SMSTATUS_STATE_SHIFT 0
+#define SMSTATUS_STATE_MASK (0xf << SMSTATUS_STATE_SHIFT)
+#define SMSTATUS_STATE_RESET 0
+#define SMSTATUS_STATE_INIT 1
+#define SMSTATUS_STATE_NORMAL 2
+#define SMSTATUS_STATE_FAIL 3
+
+/* up to 15 rings, 2 bits shifted by ring number */
+#define SMPARTOWN_RING_SHIFT 2
+#define SMPARTOWN_RING_MASK 3
+#define SMPARTOWN_AVAILABLE 0
+#define SMPARTOWN_NOEXIST 1
+#define SMPARTOWN_UNAVAILABLE 2
+#define SMPARTOWN_OURS 3
+
+/* Maximum number of pages possible */
+#define SMPART_MAX_NUMPG_SHIFT 16
+#define SMPART_MAX_NUMPG_MASK (0x3f << SMPART_MAX_NUMPG_SHIFT)
+
+/* Maximum partition number */
+#define SMPART_MAX_PNUM_SHIFT 12
+#define SMPART_MAX_PNUM_MASK (0xf << SMPART_MAX_PNUM_SHIFT)
+
+/* Highest possible page number */
+#define SMPART_MAX_PG_SHIFT 0
+#define SMPART_MAX_PG_MASK (0x3f << SMPART_MAX_PG_SHIFT)
+
+/* Max size of a page */
+#define SMVID_PG_SIZE_SHIFT 16
+#define SMVID_PG_SIZE_MASK (0x7 << SMVID_PG_SIZE_SHIFT)
+
+/* Major/Minor Version ID */
+#define SMVID_MAJ_VERS_SHIFT 8
+#define SMVID_MAJ_VERS (0xf << SMVID_MAJ_VERS_SHIFT)
+#define SMVID_MIN_VERS_SHIFT 0
+#define SMVID_MIN_VERS (0xf << SMVID_MIN_VERS_SHIFT)
+
/* LIODN programming for DMA configuration */
#define MSTRID_LOCK_LIODN 0x80000000
#define MSTRID_LOCK_MAKETRUSTED 0x00010000 /* only for JR masterid */
@@ -523,6 +614,35 @@ struct caam_ctrl {
#define JRSTART_JR2_START 0x00000004 /* Start Job ring 2 */
#define JRSTART_JR3_START 0x00000008 /* Start Job ring 3 */
+/* Secure Memory Configuration - if you have it */
+/* Secure Memory Register Offset from JR Base Reg*/
+#define SM_V1_OFFSET 0x0f4
+#define SM_V2_OFFSET 0xa00
+
+/* Minimum SM Version ID requiring v2 SM register mapping */
+#define SMVID_V2 0x20105
+
+struct caam_secure_mem_v1 {
+ u32 sm_cmd; /* SMCJRx - Secure memory command */
+ u32 rsvd1;
+ u32 sm_status; /* SMCSJRx - Secure memory status */
+ u32 rsvd2;
+
+ u32 sm_perm; /* SMAPJRx - Secure memory access perms */
+ u32 sm_group2; /* SMAP2JRx - Secure memory access group 2 */
+ u32 sm_group1; /* SMAP1JRx - Secure memory access group 1 */
+};
+
+struct caam_secure_mem_v2 {
+ u32 sm_perm; /* SMAPJRx - Secure memory access perms */
+ u32 sm_group2; /* SMAP2JRx - Secure memory access group 2 */
+ u32 sm_group1; /* SMAP1JRx - Secure memory access group 1 */
+ u32 rsvd1[118];
+ u32 sm_cmd; /* SMCJRx - Secure memory command */
+ u32 rsvd2;
+ u32 sm_status; /* SMCSJRx - Secure memory status */
+};
+
/*
* caam_job_ring - direct job ring setup
* 1-4 possible per instantiation, base + 1000/2000/3000/4000
@@ -564,8 +684,7 @@ struct caam_job_ring {
/* Command/control */
u32 rsvd11;
u32 jrcommand; /* JRCRx - JobR command */
-
- u32 rsvd12[932];
+ u32 rsvd12[931];
/* Performance Monitor f00-fff */
struct caam_perfmon perfmon;
@@ -688,6 +807,62 @@ struct caam_job_ring {
#define JRCR_RESET 0x01
+/* secure memory command */
+#define SMC_PAGE_SHIFT 16
+#define SMC_PAGE_MASK (0xffff << SMC_PAGE_SHIFT)
+#define SMC_PART_SHIFT 8
+#define SMC_PART_MASK (0x0f << SMC_PART_SHIFT)
+#define SMC_CMD_SHIFT 0
+#define SMC_CMD_MASK (0x0f << SMC_CMD_SHIFT)
+
+#define SMC_CMD_ALLOC_PAGE 0x01 /* allocate page to this partition */
+#define SMC_CMD_DEALLOC_PAGE 0x02 /* deallocate page from partition */
+#define SMC_CMD_DEALLOC_PART 0x03 /* deallocate partition */
+#define SMC_CMD_PAGE_INQUIRY 0x05 /* find partition associate with page */
+
+/* secure memory (command) status */
+#define SMCS_PAGE_SHIFT 16
+#define SMCS_PAGE_MASK (0x0fff << SMCS_PAGE_SHIFT)
+#define SMCS_CMDERR_SHIFT 14
+#define SMCS_CMDERR_MASK (3 << SMCS_CMDERR_SHIFT)
+#define SMCS_ALCERR_SHIFT 12
+#define SMCS_ALCERR_MASK (3 << SMCS_ALCERR_SHIFT)
+#define SMCS_PGOWN_SHIFT 6
+#define SMCS_PGWON_MASK (3 << SMCS_PGOWN_SHIFT)
+#define SMCS_PART_SHIFT 0
+#define SMCS_PART_MASK (0xf << SMCS_PART_SHIFT)
+
+#define SMCS_CMDERR_NONE 0
+#define SMCS_CMDERR_INCOMP 1 /* Command not yet complete */
+#define SMCS_CMDERR_SECFAIL 2 /* Security failure occurred */
+#define SMCS_CMDERR_OVERFLOW 3 /* Command overflow */
+
+#define SMCS_ALCERR_NONE 0
+#define SMCS_ALCERR_PSPERR 1 /* Partion marked PSP (dealloc only) */
+#define SMCS_ALCERR_PAGEAVAIL 2 /* Page not available */
+#define SMCS_ALCERR_PARTOWN 3 /* Partition ownership error */
+
+#define SMCS_PGOWN_AVAIL 0 /* Page is available */
+#define SMCS_PGOWN_NOEXIST 1 /* Page initializing or nonexistent */
+#define SMCS_PGOWN_NOOWN 2 /* Page owned by another processor */
+#define SMCS_PGOWN_OWNED 3 /* Page belongs to this processor */
+
+/* secure memory access permissions */
+#define SMCS_PERM_KEYMOD_SHIFT 16
+#define SMCA_PERM_KEYMOD_MASK (0xff << SMCS_PERM_KEYMOD_SHIFT)
+#define SMCA_PERM_CSP_ZERO 0x8000 /* Zero when deallocated or released */
+#define SMCA_PERM_PSP_LOCK 0x4000 /* Part./pages can't be deallocated */
+#define SMCA_PERM_PERM_LOCK 0x2000 /* Lock permissions */
+#define SMCA_PERM_GRP_LOCK 0x1000 /* Lock access groups */
+#define SMCA_PERM_RINGID_SHIFT 10
+#define SMCA_PERM_RINGID_MASK (3 << SMCA_PERM_RINGID_SHIFT)
+#define SMCA_PERM_G2_BLOB 0x0080 /* Group 2 blob import/export */
+#define SMCA_PERM_G2_WRITE 0x0020 /* Group 2 write */
+#define SMCA_PERM_G2_READ 0x0010 /* Group 2 read */
+#define SMCA_PERM_G1_BLOB 0x0008 /* Group 1... */
+#define SMCA_PERM_G1_WRITE 0x0002
+#define SMCA_PERM_G1_READ 0x0001
+
/*
* caam_assurance - Assurance Controller View
* base + 0x6000 padded out to 0x1000
diff --git a/drivers/crypto/caam/secvio.c b/drivers/crypto/caam/secvio.c
new file mode 100644
index 000000000000..c6a29d49de68
--- /dev/null
+++ b/drivers/crypto/caam/secvio.c
@@ -0,0 +1,340 @@
+
+/*
+ * SNVS Security Violation Handler
+ * Copyright (C) 2012-2016 Freescale Semiconductor, Inc., All Rights Reserved
+ */
+
+#include "compat.h"
+#include "intern.h"
+#include "secvio.h"
+#include "regs.h"
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+/* The driver is matched with node caam_snvs to get regmap
+ * It will then retrieve interruption and tamper alarm configuration from
+ * node caam-secvio searching for the compat string "fsl,imx6q-caam-secvio"
+ */
+#define DRIVER_NAME "caam-snvs"
+
+/*
+ * These names are associated with each violation handler.
+ * The source names were taken from MX6, and are based on recommendations
+ * for most common SoCs.
+ */
+static const u8 *violation_src_name[] = {
+ "CAAM Internal Security Violation",
+ "JTAG Alarm",
+ "Watchdog",
+ "(reserved)",
+ "External Boot",
+ "External Tamper Detect",
+};
+
+/* These names help describe security monitor state for the console */
+static const u8 *snvs_ssm_state_name[] = {
+ "init",
+ "hard fail",
+ "(undef:2)",
+ "soft fail",
+ "(undef:4)",
+ "(undef:5)",
+ "(undef:6)",
+ "(undef:7)",
+ "transition",
+ "check",
+ "(undef:10)",
+ "non-secure",
+ "(undef:12)",
+ "trusted",
+ "(undef:14)",
+ "secure",
+};
+
+/* Top-level security violation interrupt */
+static irqreturn_t snvs_secvio_interrupt(int irq, void *snvsdev)
+{
+ struct device *dev = snvsdev;
+ struct snvs_secvio_drv_private *svpriv = dev_get_drvdata(dev);
+
+ clk_enable(svpriv->clk);
+ /* Check the HP secvio status register */
+ svpriv->irqcause = rd_reg32(&svpriv->svregs->hp.secvio_status) &
+ HP_SECVIOST_SECVIOMASK;
+
+ if (!svpriv->irqcause) {
+ clk_disable(svpriv->clk);
+ return IRQ_NONE;
+ }
+
+ /* Now ACK cause */
+ clrsetbits_32(&svpriv->svregs->hp.secvio_status, 0, svpriv->irqcause);
+
+ /* And run deferred service */
+ preempt_disable();
+ tasklet_schedule(&svpriv->irqtask[smp_processor_id()]);
+ preempt_enable();
+
+ clk_disable(svpriv->clk);
+
+ return IRQ_HANDLED;
+}
+
+/* Deferred service handler. Tasklet arg is simply the SNVS dev */
+static void snvs_secvio_dispatch(unsigned long indev)
+{
+ struct device *dev = (struct device *)indev;
+ struct snvs_secvio_drv_private *svpriv = dev_get_drvdata(dev);
+ unsigned long flags;
+ int i;
+
+
+ /* Look through stored causes, call each handler if exists */
+ for (i = 0; i < MAX_SECVIO_SOURCES; i++)
+ if (svpriv->irqcause & (1 << i)) {
+ spin_lock_irqsave(&svpriv->svlock, flags);
+ svpriv->intsrc[i].handler(dev, i,
+ svpriv->intsrc[i].ext);
+ spin_unlock_irqrestore(&svpriv->svlock, flags);
+ };
+
+ /* Re-enable now-serviced interrupts */
+ clrsetbits_32(&svpriv->svregs->hp.secvio_intcfg, 0, svpriv->irqcause);
+}
+
+/*
+ * Default cause handler, used in lieu of an application-defined handler.
+ * All it does at this time is print a console message. It could force a halt.
+ */
+static void snvs_secvio_default(struct device *dev, u32 cause, void *ext)
+{
+ struct snvs_secvio_drv_private *svpriv = dev_get_drvdata(dev);
+
+ dev_err(dev, "Unhandled Security Violation Interrupt %d = %s\n",
+ cause, svpriv->intsrc[cause].intname);
+}
+
+/*
+ * Install an application-defined handler for a specified cause
+ * Arguments:
+ * - dev points to SNVS-owning device
+ * - cause interrupt source cause
+ * - handler application-defined handler, gets called with dev
+ * source cause, and locally-defined handler argument
+ * - cause_description points to a string to override the default cause
+ * name, this can be used as an alternate for error
+ * messages and such. If left NULL, the default
+ * description string is used.
+ * - ext pointer to any extra data needed by the handler.
+ */
+int snvs_secvio_install_handler(struct device *dev, enum secvio_cause cause,
+ void (*handler)(struct device *dev, u32 cause,
+ void *ext),
+ u8 *cause_description, void *ext)
+{
+ unsigned long flags;
+ struct snvs_secvio_drv_private *svpriv;
+
+ svpriv = dev_get_drvdata(dev);
+
+ if ((handler == NULL) || (cause > SECVIO_CAUSE_SOURCE_5))
+ return -EINVAL;
+
+ spin_lock_irqsave(&svpriv->svlock, flags);
+ svpriv->intsrc[cause].handler = handler;
+ if (cause_description != NULL)
+ svpriv->intsrc[cause].intname = cause_description;
+ if (ext != NULL)
+ svpriv->intsrc[cause].ext = ext;
+ spin_unlock_irqrestore(&svpriv->svlock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(snvs_secvio_install_handler);
+
+/*
+ * Remove an application-defined handler for a specified cause (and, by
+ * implication, restore the "default".
+ * Arguments:
+ * - dev points to SNVS-owning device
+ * - cause interrupt source cause
+ */
+int snvs_secvio_remove_handler(struct device *dev, enum secvio_cause cause)
+{
+ unsigned long flags;
+ struct snvs_secvio_drv_private *svpriv;
+
+ svpriv = dev_get_drvdata(dev);
+
+ if (cause > SECVIO_CAUSE_SOURCE_5)
+ return -EINVAL;
+
+ spin_lock_irqsave(&svpriv->svlock, flags);
+ svpriv->intsrc[cause].intname = violation_src_name[cause];
+ svpriv->intsrc[cause].handler = snvs_secvio_default;
+ svpriv->intsrc[cause].ext = NULL;
+ spin_unlock_irqrestore(&svpriv->svlock, flags);
+ return 0;
+}
+EXPORT_SYMBOL(snvs_secvio_remove_handler);
+
+static int snvs_secvio_remove(struct platform_device *pdev)
+{
+ struct device *svdev;
+ struct snvs_secvio_drv_private *svpriv;
+ int i;
+
+ svdev = &pdev->dev;
+ svpriv = dev_get_drvdata(svdev);
+
+ clk_enable(svpriv->clk);
+ /* Set all sources to nonfatal */
+ wr_reg32(&svpriv->svregs->hp.secvio_intcfg, 0);
+
+ /* Remove tasklets and release interrupt */
+ for_each_possible_cpu(i)
+ tasklet_kill(&svpriv->irqtask[i]);
+
+ clk_disable_unprepare(svpriv->clk);
+ free_irq(svpriv->irq, svdev);
+ iounmap(svpriv->svregs);
+ kfree(svpriv);
+
+ return 0;
+}
+
+static int snvs_secvio_probe(struct platform_device *pdev)
+{
+ struct device *svdev;
+ struct snvs_secvio_drv_private *svpriv;
+ struct device_node *np, *npirq;
+ struct snvs_full __iomem *snvsregs;
+ int i, error;
+ u32 hpstate;
+ const void *jtd, *wtd, *itd, *etd;
+ u32 td_en;
+
+ svpriv = kzalloc(sizeof(struct snvs_secvio_drv_private), GFP_KERNEL);
+ if (!svpriv)
+ return -ENOMEM;
+
+ svdev = &pdev->dev;
+ dev_set_drvdata(svdev, svpriv);
+ svpriv->pdev = pdev;
+ np = pdev->dev.of_node;
+
+ npirq = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-secvio");
+ if (!npirq) {
+ dev_err(svdev, "can't find secvio node\n");
+ kfree(svpriv);
+ return -EINVAL;
+ }
+ svpriv->irq = irq_of_parse_and_map(npirq, 0);
+ if (svpriv->irq <= 0) {
+ dev_err(svdev, "can't identify secvio interrupt\n");
+ kfree(svpriv);
+ return -EINVAL;
+ }
+
+ jtd = of_get_property(npirq, "jtag-tamper", NULL);
+ wtd = of_get_property(npirq, "watchdog-tamper", NULL);
+ itd = of_get_property(npirq, "internal-boot-tamper", NULL);
+ etd = of_get_property(npirq, "external-pin-tamper", NULL);
+ if (!jtd | !wtd | !itd | !etd ) {
+ dev_err(svdev, "can't identify all tamper alarm configuration\n");
+ kfree(svpriv);
+ return -EINVAL;
+ }
+
+ /*
+ * Configure all sources according to device tree property.
+ * If the property is enabled then the source is ser as
+ * fatal violations except LP section,
+ * source #5 (typically used as an external tamper detect), and
+ * source #3 (typically unused). Whenever the transition to
+ * secure mode has occurred, these will now be "fatal" violations
+ */
+ td_en = HP_SECVIO_INTEN_SRC0;
+ if (!strcmp(jtd, "enabled"))
+ td_en |= HP_SECVIO_INTEN_SRC1;
+ if (!strcmp(wtd, "enabled"))
+ td_en |= HP_SECVIO_INTEN_SRC2;
+ if (!strcmp(itd, "enabled"))
+ td_en |= HP_SECVIO_INTEN_SRC4;
+ if (!strcmp(etd, "enabled"))
+ td_en |= HP_SECVIO_INTEN_SRC5;
+
+ snvsregs = of_iomap(np, 0);
+ if (!snvsregs) {
+ dev_err(svdev, "register mapping failed\n");
+ return -ENOMEM;
+ }
+ svpriv->svregs = (struct snvs_full __force *)snvsregs;
+
+ svpriv->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(svpriv->clk)) {
+ dev_err(&pdev->dev, "can't get snvs clock\n");
+ svpriv->clk = NULL;
+ }
+
+ /* Write the Secvio Enable Config the SVCR */
+ wr_reg32(&svpriv->svregs->hp.secvio_ctl, td_en);
+ wr_reg32(&svpriv->svregs->hp.secvio_intcfg, td_en);
+
+ /* Device data set up. Now init interrupt source descriptions */
+ for (i = 0; i < MAX_SECVIO_SOURCES; i++) {
+ svpriv->intsrc[i].intname = violation_src_name[i];
+ svpriv->intsrc[i].handler = snvs_secvio_default;
+ }
+ /* Connect main handler */
+ for_each_possible_cpu(i)
+ tasklet_init(&svpriv->irqtask[i], snvs_secvio_dispatch,
+ (unsigned long)svdev);
+
+ error = request_irq(svpriv->irq, snvs_secvio_interrupt,
+ IRQF_SHARED, DRIVER_NAME, svdev);
+ if (error) {
+ dev_err(svdev, "can't connect secvio interrupt\n");
+ irq_dispose_mapping(svpriv->irq);
+ svpriv->irq = 0;
+ iounmap(svpriv->svregs);
+ kfree(svpriv);
+ return -EINVAL;
+ }
+
+ clk_prepare_enable(svpriv->clk);
+
+ hpstate = (rd_reg32(&svpriv->svregs->hp.status) &
+ HP_STATUS_SSM_ST_MASK) >> HP_STATUS_SSM_ST_SHIFT;
+ dev_info(svdev, "violation handlers armed - %s state\n",
+ snvs_ssm_state_name[hpstate]);
+
+ clk_disable(svpriv->clk);
+
+ return 0;
+}
+
+static struct of_device_id snvs_secvio_match[] = {
+ {
+ .compatible = "fsl,imx6q-caam-snvs",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, snvs_secvio_match);
+
+static struct platform_driver snvs_secvio_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = snvs_secvio_match,
+ },
+ .probe = snvs_secvio_probe,
+ .remove = snvs_secvio_remove,
+};
+
+module_platform_driver(snvs_secvio_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("FSL SNVS Security Violation Handler");
+MODULE_AUTHOR("Freescale Semiconductor - MCU");
diff --git a/drivers/crypto/caam/secvio.h b/drivers/crypto/caam/secvio.h
new file mode 100644
index 000000000000..97eb2723f19c
--- /dev/null
+++ b/drivers/crypto/caam/secvio.h
@@ -0,0 +1,67 @@
+
+/*
+ * CAAM Security Violation Handler
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc., All Rights Reserved
+ */
+
+#ifndef SECVIO_H
+#define SECVIO_H
+
+#include "snvsregs.h"
+
+
+/*
+ * Defines the published interfaces to install/remove application-specified
+ * handlers for catching violations
+ */
+
+#define MAX_SECVIO_SOURCES 6
+
+/* these are the untranslated causes */
+enum secvio_cause {
+ SECVIO_CAUSE_SOURCE_0,
+ SECVIO_CAUSE_SOURCE_1,
+ SECVIO_CAUSE_SOURCE_2,
+ SECVIO_CAUSE_SOURCE_3,
+ SECVIO_CAUSE_SOURCE_4,
+ SECVIO_CAUSE_SOURCE_5
+};
+
+/* These are common "recommended" cause definitions for most devices */
+#define SECVIO_CAUSE_CAAM_VIOLATION SECVIO_CAUSE_SOURCE_0
+#define SECVIO_CAUSE_JTAG_ALARM SECVIO_CAUSE_SOURCE_1
+#define SECVIO_CAUSE_WATCHDOG SECVIO_CAUSE_SOURCE_2
+#define SECVIO_CAUSE_EXTERNAL_BOOT SECVIO_CAUSE_SOURCE_4
+#define SECVIO_CAUSE_TAMPER_DETECT SECVIO_CAUSE_SOURCE_5
+
+int snvs_secvio_install_handler(struct device *dev, enum secvio_cause cause,
+ void (*handler)(struct device *dev, u32 cause,
+ void *ext),
+ u8 *cause_description, void *ext);
+int snvs_secvio_remove_handler(struct device *dev, enum secvio_cause cause);
+
+/*
+ * Private data definitions for the secvio "driver"
+ */
+
+struct secvio_int_src {
+ const u8 *intname; /* Points to a descriptive name for source */
+ void *ext; /* Extended data to pass to the handler */
+ void (*handler)(struct device *dev, u32 cause, void *ext);
+};
+
+struct snvs_secvio_drv_private {
+ struct platform_device *pdev;
+ spinlock_t svlock ____cacheline_aligned;
+ struct tasklet_struct irqtask[NR_CPUS];
+ struct snvs_full __iomem *svregs; /* both HP and LP domains */
+ struct clk *clk;
+ int irq;
+ u32 irqcause; /* stashed cause of violation interrupt */
+
+ /* Registered handlers for each violation */
+ struct secvio_int_src intsrc[MAX_SECVIO_SOURCES];
+
+};
+
+#endif /* SECVIO_H */
diff --git a/drivers/crypto/caam/sm.h b/drivers/crypto/caam/sm.h
new file mode 100644
index 000000000000..65ec9d75ef56
--- /dev/null
+++ b/drivers/crypto/caam/sm.h
@@ -0,0 +1,125 @@
+
+/*
+ * CAAM Secure Memory/Keywrap API Definitions
+ * Copyright (C) 2008-2015 Freescale Semiconductor, Inc.
+ */
+
+#ifndef SM_H
+#define SM_H
+
+
+/* Storage access permissions */
+#define SM_PERM_READ 0x01
+#define SM_PERM_WRITE 0x02
+#define SM_PERM_BLOB 0x03
+
+/* Define treatment of secure memory vs. general memory blobs */
+#define SM_SECMEM 0
+#define SM_GENMEM 1
+
+/* Define treatment of red/black keys */
+#define RED_KEY 0
+#define BLACK_KEY 1
+
+/* Define key encryption/covering options */
+#define KEY_COVER_ECB 0 /* cover key in AES-ECB */
+#define KEY_COVER_CCM 1 /* cover key with AES-CCM */
+
+/*
+ * Round a key size up to an AES blocksize boundary so to allow for
+ * padding out to a full block
+ */
+#define AES_BLOCK_PAD(x) ((x % 16) ? ((x >> 4) + 1) << 4 : x)
+
+/* Define space required for BKEK + MAC tag storage in any blob */
+#define BLOB_OVERHEAD (32 + 16)
+
+/* Keystore maintenance functions */
+void sm_init_keystore(struct device *dev);
+u32 sm_detect_keystore_units(struct device *dev);
+int sm_establish_keystore(struct device *dev, u32 unit);
+void sm_release_keystore(struct device *dev, u32 unit);
+void caam_sm_shutdown(struct platform_device *pdev);
+int caam_sm_example_init(struct platform_device *pdev);
+
+/* Keystore accessor functions */
+extern int sm_keystore_slot_alloc(struct device *dev, u32 unit, u32 size,
+ u32 *slot);
+extern int sm_keystore_slot_dealloc(struct device *dev, u32 unit, u32 slot);
+extern int sm_keystore_slot_load(struct device *dev, u32 unit, u32 slot,
+ const u8 *key_data, u32 key_length);
+extern int sm_keystore_slot_read(struct device *dev, u32 unit, u32 slot,
+ u32 key_length, u8 *key_data);
+extern int sm_keystore_cover_key(struct device *dev, u32 unit, u32 slot,
+ u16 key_length, u8 keyauth);
+extern int sm_keystore_slot_export(struct device *dev, u32 unit, u32 slot,
+ u8 keycolor, u8 keyauth, u8 *outbuf,
+ u16 keylen, u8 *keymod);
+extern int sm_keystore_slot_import(struct device *dev, u32 unit, u32 slot,
+ u8 keycolor, u8 keyauth, u8 *inbuf,
+ u16 keylen, u8 *keymod);
+
+/* Prior functions from legacy API, deprecated */
+extern int sm_keystore_slot_encapsulate(struct device *dev, u32 unit,
+ u32 inslot, u32 outslot, u16 secretlen,
+ u8 *keymod, u16 keymodlen);
+extern int sm_keystore_slot_decapsulate(struct device *dev, u32 unit,
+ u32 inslot, u32 outslot, u16 secretlen,
+ u8 *keymod, u16 keymodlen);
+
+/* Data structure to hold per-slot information */
+struct keystore_data_slot_info {
+ u8 allocated; /* Track slot assignments */
+ u32 key_length; /* Size of the key */
+};
+
+/* Data structure to hold keystore information */
+struct keystore_data {
+ void *base_address; /* Virtual base of secure memory pages */
+ void *phys_address; /* Physical base of secure memory pages */
+ u32 slot_count; /* Number of slots in the keystore */
+ struct keystore_data_slot_info *slot; /* Per-slot information */
+};
+
+/* store the detected attributes of a secure memory page */
+struct sm_page_descriptor {
+ u16 phys_pagenum; /* may be discontiguous */
+ u16 own_part; /* Owning partition */
+ void *pg_base; /* Calculated virtual address */
+ void *pg_phys; /* Calculated physical address */
+ struct keystore_data *ksdata;
+};
+
+struct caam_drv_private_sm {
+ struct device *parentdev; /* this ends up as the controller */
+ struct device *smringdev; /* ring that owns this instance */
+ struct platform_device *sm_pdev; /* Secure Memory platform device */
+ spinlock_t kslock ____cacheline_aligned;
+
+ /* SM Register offset from JR base address */
+ u32 sm_reg_offset;
+
+ /* Default parameters for geometry */
+ u32 max_pages; /* maximum pages this instance can support */
+ u32 top_partition; /* highest partition number in this instance */
+ u32 top_page; /* highest page number in this instance */
+ u32 page_size; /* page size */
+ u32 slot_size; /* selected size of each storage block */
+
+ /* Partition/Page Allocation Map */
+ u32 localpages; /* Number of pages we can access */
+ struct sm_page_descriptor *pagedesc; /* Allocated per-page */
+
+ /* Installed handlers for keystore access */
+ int (*data_init)(struct device *dev, u32 unit);
+ void (*data_cleanup)(struct device *dev, u32 unit);
+ int (*slot_alloc)(struct device *dev, u32 unit, u32 size, u32 *slot);
+ int (*slot_dealloc)(struct device *dev, u32 unit, u32 slot);
+ void *(*slot_get_address)(struct device *dev, u32 unit, u32 handle);
+ void *(*slot_get_physical)(struct device *dev, u32 unit, u32 handle);
+ u32 (*slot_get_base)(struct device *dev, u32 unit, u32 handle);
+ u32 (*slot_get_offset)(struct device *dev, u32 unit, u32 handle);
+ u32 (*slot_get_slot_size)(struct device *dev, u32 unit, u32 handle);
+};
+
+#endif /* SM_H */
diff --git a/drivers/crypto/caam/sm_store.c b/drivers/crypto/caam/sm_store.c
new file mode 100644
index 000000000000..69baa8cd1d6f
--- /dev/null
+++ b/drivers/crypto/caam/sm_store.c
@@ -0,0 +1,1266 @@
+/*
+ * CAAM Secure Memory Storage Interface
+ * Copyright (C) 2008-2015 Freescale Semiconductor, Inc.
+ * Copyright 2018 NXP
+ *
+ * Loosely based on the SHW Keystore API for SCC/SCC2
+ * Experimental implementation and NOT intended for upstream use. Expect
+ * this interface to be amended significantly in the future once it becomes
+ * integrated into live applications.
+ *
+ * Known issues:
+ *
+ * - Executes one instance of an secure memory "driver". This is tied to the
+ * fact that job rings can't run as standalone instances in the present
+ * configuration.
+ *
+ * - It does not expose a userspace interface. The value of a userspace
+ * interface for access to secrets is a point for further architectural
+ * discussion.
+ *
+ * - Partition/permission management is not part of this interface. It
+ * depends on some level of "knowledge" agreed upon between bootloader,
+ * provisioning applications, and OS-hosted software (which uses this
+ * driver).
+ *
+ * - No means of identifying the location or purpose of secrets managed by
+ * this interface exists; "slot location" and format of a given secret
+ * needs to be agreed upon between bootloader, provisioner, and OS-hosted
+ * application.
+ */
+
+#include "compat.h"
+#include "regs.h"
+#include "jr.h"
+#include "desc.h"
+#include "intern.h"
+#include "error.h"
+#include "sm.h"
+#include <linux/of_address.h>
+#include <soc/imx8/soc.h>
+
+#define SECMEM_KEYMOD_LEN 8
+#define GENMEM_KEYMOD_LEN 16
+
+#ifdef SM_DEBUG_CONT
+void sm_show_page(struct device *dev, struct sm_page_descriptor *pgdesc)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ u32 i, *smdata;
+
+ dev_info(dev, "physical page %d content at 0x%08x\n",
+ pgdesc->phys_pagenum, pgdesc->pg_base);
+ smdata = pgdesc->pg_base;
+ for (i = 0; i < (smpriv->page_size / sizeof(u32)); i += 4)
+ dev_info(dev, "[0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ (u32)&smdata[i], smdata[i], smdata[i+1], smdata[i+2],
+ smdata[i+3]);
+}
+#endif
+
+#define INITIAL_DESCSZ 16 /* size of tmp buffer for descriptor const. */
+
+static __always_inline u32 sm_send_cmd(struct caam_drv_private_sm *smpriv,
+ struct caam_drv_private_jr *jrpriv,
+ u32 cmd, u32 *status)
+{
+ void __iomem *write_address;
+ void __iomem *read_address;
+
+ if (smpriv->sm_reg_offset == SM_V1_OFFSET) {
+ struct caam_secure_mem_v1 *sm_regs_v1;
+ sm_regs_v1 = (struct caam_secure_mem_v1 *)
+ ((void *)jrpriv->rregs + SM_V1_OFFSET);
+ write_address = &sm_regs_v1->sm_cmd;
+ read_address = &sm_regs_v1->sm_status;
+
+ } else if (smpriv->sm_reg_offset == SM_V2_OFFSET) {
+ struct caam_secure_mem_v2 *sm_regs_v2;
+ sm_regs_v2 = (struct caam_secure_mem_v2 *)
+ ((void *)jrpriv->rregs + SM_V2_OFFSET);
+ write_address = &sm_regs_v2->sm_cmd;
+ read_address = &sm_regs_v2->sm_status;
+
+ } else {
+ return -EINVAL;
+ }
+
+ wr_reg32(write_address, cmd);
+
+ udelay(10);
+
+ /* Read until the command has terminated and the status is correct */
+ do {
+ *status = rd_reg32(read_address);
+ } while (((*status & SMCS_CMDERR_MASK) >> SMCS_CMDERR_SHIFT)
+ == SMCS_CMDERR_INCOMP);
+
+ return 0;
+}
+/*
+ * Construct a black key conversion job descriptor
+ *
+ * This function constructs a job descriptor capable of performing
+ * a key blackening operation on a plaintext secure memory resident object.
+ *
+ * - desc pointer to a pointer to the descriptor generated by this
+ * function. Caller will be responsible to kfree() this
+ * descriptor after execution.
+ * - key physical pointer to the plaintext, which will also hold
+ * the result. Since encryption occurs in place, caller must
+ * ensure that the space is large enough to accommodate the
+ * blackened key
+ * - keysz size of the plaintext
+ * - auth if a CCM-covered key is required, use KEY_COVER_CCM, else
+ * use KEY_COVER_ECB.
+ *
+ * KEY to key1 from @key_addr LENGTH 16 BYTES;
+ * FIFO STORE from key1[ecb] TO @key_addr LENGTH 16 BYTES;
+ *
+ * Note that this variant uses the JDKEK only; it does not accommodate the
+ * trusted key encryption key at this time.
+ *
+ */
+static int blacken_key_jobdesc(u32 **desc, void *key, u16 keysz, bool auth)
+{
+ u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
+ u16 dsize, idx;
+
+ memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32));
+ idx = 1;
+
+ /* Load key to class 1 key register */
+ tmpdesc[idx++] = CMD_KEY | CLASS_1 | (keysz & KEY_LENGTH_MASK);
+ tmpdesc[idx++] = (uintptr_t)key;
+
+ /* ...and write back out via FIFO store*/
+ tmpdesc[idx] = CMD_FIFO_STORE | CLASS_1 | (keysz & KEY_LENGTH_MASK);
+
+ /* plus account for ECB/CCM option in FIFO_STORE */
+ if (auth == KEY_COVER_ECB)
+ tmpdesc[idx] |= FIFOST_TYPE_KEY_KEK;
+ else
+ tmpdesc[idx] |= FIFOST_TYPE_KEY_CCM_JKEK;
+
+ idx++;
+ tmpdesc[idx++] = (uintptr_t)key;
+
+ /* finish off the job header */
+ tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
+ dsize = idx * sizeof(u32);
+
+ /* now allocate execution buffer and coat it with executable */
+ tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA);
+ if (tdesc == NULL)
+ return 0;
+
+ memcpy(tdesc, tmpdesc, dsize);
+ *desc = tdesc;
+
+ return dsize;
+}
+
+/*
+ * Construct a blob encapsulation job descriptor
+ *
+ * This function dynamically constructs a blob encapsulation job descriptor
+ * from the following arguments:
+ *
+ * - desc pointer to a pointer to the descriptor generated by this
+ * function. Caller will be responsible to kfree() this
+ * descriptor after execution.
+ * - keymod Physical pointer to a key modifier, which must reside in a
+ * contiguous piece of memory. Modifier will be assumed to be
+ * 8 bytes long for a blob of type SM_SECMEM, or 16 bytes long
+ * for a blob of type SM_GENMEM (see blobtype argument).
+ * - secretbuf Physical pointer to a secret, normally a black or red key,
+ * possibly residing within an accessible secure memory page,
+ * of the secret to be encapsulated to an output blob.
+ * - outbuf Physical pointer to the destination buffer to receive the
+ * encapsulated output. This buffer will need to be 48 bytes
+ * larger than the input because of the added encapsulation data.
+ * The generated descriptor will account for the increase in size,
+ * but the caller must also account for this increase in the
+ * buffer allocator.
+ * - secretsz Size of input secret, in bytes. This is limited to 65536
+ * less the size of blob overhead, since the length embeds into
+ * DECO pointer in/out instructions.
+ * - keycolor Determines if the source data is covered (black key) or
+ * plaintext (red key). RED_KEY or BLACK_KEY are defined in
+ * for this purpose.
+ * - blobtype Determine if encapsulated blob should be a secure memory
+ * blob (SM_SECMEM), with partition data embedded with key
+ * material, or a general memory blob (SM_GENMEM).
+ * - auth If BLACK_KEY source is covered via AES-CCM, specify
+ * KEY_COVER_CCM, else uses AES-ECB (KEY_COVER_ECB).
+ *
+ * Upon completion, desc points to a buffer containing a CAAM job
+ * descriptor which encapsulates data into an externally-storable blob
+ * suitable for use across power cycles.
+ *
+ * This is an example of a black key encapsulation job into a general memory
+ * blob. Notice the 16-byte key modifier in the LOAD instruction. Also note
+ * the output 48 bytes longer than the input:
+ *
+ * [00] B0800008 jobhdr: stidx=0 len=8
+ * [01] 14400010 ld: ccb2-key len=16 offs=0
+ * [02] 08144891 ptr->@0x08144891
+ * [03] F800003A seqoutptr: len=58
+ * [04] 01000000 out_ptr->@0x01000000
+ * [05] F000000A seqinptr: len=10
+ * [06] 09745090 in_ptr->@0x09745090
+ * [07] 870D0004 operation: encap blob reg=memory, black, format=normal
+ *
+ * This is an example of a red key encapsulation job for storing a red key
+ * into a secure memory blob. Note the 8 byte modifier on the 12 byte offset
+ * in the LOAD instruction; this accounts for blob permission storage:
+ *
+ * [00] B0800008 jobhdr: stidx=0 len=8
+ * [01] 14400C08 ld: ccb2-key len=8 offs=12
+ * [02] 087D0784 ptr->@0x087d0784
+ * [03] F8000050 seqoutptr: len=80
+ * [04] 09251BB2 out_ptr->@0x09251bb2
+ * [05] F0000020 seqinptr: len=32
+ * [06] 40000F31 in_ptr->@0x40000f31
+ * [07] 870D0008 operation: encap blob reg=memory, red, sec_mem,
+ * format=normal
+ *
+ * Note: this function only generates 32-bit pointers at present, and should
+ * be refactored using a scheme that allows both 32 and 64 bit addressing
+ */
+
+static int blob_encap_jobdesc(u32 **desc, dma_addr_t keymod,
+ void *secretbuf, dma_addr_t outbuf,
+ u16 secretsz, u8 keycolor, u8 blobtype, u8 auth)
+{
+ u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
+ u16 dsize, idx;
+
+ memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32));
+ idx = 1;
+
+ /*
+ * Key modifier works differently for secure/general memory blobs
+ * This accounts for the permission/protection data encapsulated
+ * within the blob if a secure memory blob is requested
+ */
+ if (blobtype == SM_SECMEM)
+ tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
+ LDST_SRCDST_BYTE_KEY |
+ ((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK)
+ | (8 & LDST_LEN_MASK);
+ else /* is general memory blob */
+ tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
+ LDST_SRCDST_BYTE_KEY | (16 & LDST_LEN_MASK);
+
+ tmpdesc[idx++] = (u32)keymod;
+
+ /*
+ * Encapsulation output must include space for blob key encryption
+ * key and MAC tag
+ */
+ tmpdesc[idx++] = CMD_SEQ_OUT_PTR | (secretsz + BLOB_OVERHEAD);
+ tmpdesc[idx++] = (u32)outbuf;
+
+ /* Input data, should be somewhere in secure memory */
+ tmpdesc[idx++] = CMD_SEQ_IN_PTR | secretsz;
+ tmpdesc[idx++] = (uintptr_t)secretbuf;
+
+ /* Set blob encap, then color */
+ tmpdesc[idx] = CMD_OPERATION | OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB;
+
+ if (blobtype == SM_SECMEM)
+ tmpdesc[idx] |= OP_PCL_BLOB_PTXT_SECMEM;
+
+ if (auth == KEY_COVER_CCM)
+ tmpdesc[idx] |= OP_PCL_BLOB_EKT;
+
+ if (keycolor == BLACK_KEY)
+ tmpdesc[idx] |= OP_PCL_BLOB_BLACK;
+
+ idx++;
+ tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
+ dsize = idx * sizeof(u32);
+
+ tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA);
+ if (tdesc == NULL)
+ return 0;
+
+ memcpy(tdesc, tmpdesc, dsize);
+ *desc = tdesc;
+ return dsize;
+}
+
+/*
+ * Construct a blob decapsulation job descriptor
+ *
+ * This function dynamically constructs a blob decapsulation job descriptor
+ * from the following arguments:
+ *
+ * - desc pointer to a pointer to the descriptor generated by this
+ * function. Caller will be responsible to kfree() this
+ * descriptor after execution.
+ * - keymod Physical pointer to a key modifier, which must reside in a
+ * contiguous piece of memory. Modifier will be assumed to be
+ * 8 bytes long for a blob of type SM_SECMEM, or 16 bytes long
+ * for a blob of type SM_GENMEM (see blobtype argument).
+ * - blobbuf Physical pointer (into external memory) of the blob to
+ * be decapsulated. Blob must reside in a contiguous memory
+ * segment.
+ * - outbuf Physical pointer of the decapsulated output, possibly into
+ * a location within a secure memory page. Must be contiguous.
+ * - secretsz Size of encapsulated secret in bytes (not the size of the
+ * input blob).
+ * - keycolor Determines if decapsulated content is encrypted (BLACK_KEY)
+ * or left as plaintext (RED_KEY).
+ * - blobtype Determine if encapsulated blob should be a secure memory
+ * blob (SM_SECMEM), with partition data embedded with key
+ * material, or a general memory blob (SM_GENMEM).
+ * - auth If decapsulation path is specified by BLACK_KEY, then if
+ * AES-CCM is requested for key covering use KEY_COVER_CCM, else
+ * use AES-ECB (KEY_COVER_ECB).
+ *
+ * Upon completion, desc points to a buffer containing a CAAM job descriptor
+ * that decapsulates a key blob from external memory into a black (encrypted)
+ * key or red (plaintext) content.
+ *
+ * This is an example of a black key decapsulation job from a general memory
+ * blob. Notice the 16-byte key modifier in the LOAD instruction.
+ *
+ * [00] B0800008 jobhdr: stidx=0 len=8
+ * [01] 14400010 ld: ccb2-key len=16 offs=0
+ * [02] 08A63B7F ptr->@0x08a63b7f
+ * [03] F8000010 seqoutptr: len=16
+ * [04] 01000000 out_ptr->@0x01000000
+ * [05] F000003A seqinptr: len=58
+ * [06] 01000010 in_ptr->@0x01000010
+ * [07] 860D0004 operation: decap blob reg=memory, black, format=normal
+ *
+ * This is an example of a red key decapsulation job for restoring a red key
+ * from a secure memory blob. Note the 8 byte modifier on the 12 byte offset
+ * in the LOAD instruction:
+ *
+ * [00] B0800008 jobhdr: stidx=0 len=8
+ * [01] 14400C08 ld: ccb2-key len=8 offs=12
+ * [02] 01000000 ptr->@0x01000000
+ * [03] F8000020 seqoutptr: len=32
+ * [04] 400000E6 out_ptr->@0x400000e6
+ * [05] F0000050 seqinptr: len=80
+ * [06] 08F0C0EA in_ptr->@0x08f0c0ea
+ * [07] 860D0008 operation: decap blob reg=memory, red, sec_mem,
+ * format=normal
+ *
+ * Note: this function only generates 32-bit pointers at present, and should
+ * be refactored using a scheme that allows both 32 and 64 bit addressing
+ */
+
+static int blob_decap_jobdesc(u32 **desc, dma_addr_t keymod, dma_addr_t blobbuf,
+ u8 *outbuf, u16 secretsz, u8 keycolor,
+ u8 blobtype, u8 auth)
+{
+ u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
+ u16 dsize, idx;
+
+ memset(tmpdesc, 0, INITIAL_DESCSZ * sizeof(u32));
+ idx = 1;
+
+ /* Load key modifier */
+ if (blobtype == SM_SECMEM)
+ tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
+ LDST_SRCDST_BYTE_KEY |
+ ((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK)
+ | (8 & LDST_LEN_MASK);
+ else /* is general memory blob */
+ tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
+ LDST_SRCDST_BYTE_KEY | (16 & LDST_LEN_MASK);
+
+ tmpdesc[idx++] = (u32)keymod;
+
+ /* Compensate BKEK + MAC tag over size of encapsulated secret */
+ tmpdesc[idx++] = CMD_SEQ_IN_PTR | (secretsz + BLOB_OVERHEAD);
+ tmpdesc[idx++] = (u32)blobbuf;
+ tmpdesc[idx++] = CMD_SEQ_OUT_PTR | secretsz;
+ tmpdesc[idx++] = (uintptr_t)outbuf;
+
+ /* Decapsulate from secure memory partition to black blob */
+ tmpdesc[idx] = CMD_OPERATION | OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB;
+
+ if (blobtype == SM_SECMEM)
+ tmpdesc[idx] |= OP_PCL_BLOB_PTXT_SECMEM;
+
+ if (auth == KEY_COVER_CCM)
+ tmpdesc[idx] |= OP_PCL_BLOB_EKT;
+
+ if (keycolor == BLACK_KEY)
+ tmpdesc[idx] |= OP_PCL_BLOB_BLACK;
+
+ idx++;
+ tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
+ dsize = idx * sizeof(u32);
+
+ tdesc = kmalloc(dsize, GFP_KERNEL | GFP_DMA);
+ if (tdesc == NULL)
+ return 0;
+
+ memcpy(tdesc, tmpdesc, dsize);
+ *desc = tdesc;
+ return dsize;
+}
+
+/*
+ * Pseudo-synchronous ring access functions for carrying out key
+ * encapsulation and decapsulation
+ */
+
+struct sm_key_job_result {
+ int error;
+ struct completion completion;
+};
+
+void sm_key_job_done(struct device *dev, u32 *desc, u32 err, void *context)
+{
+ struct sm_key_job_result *res = context;
+
+ res->error = err; /* save off the error for postprocessing */
+ complete(&res->completion); /* mark us complete */
+}
+
+static int sm_key_job(struct device *ksdev, u32 *jobdesc)
+{
+ struct sm_key_job_result testres;
+ struct caam_drv_private_sm *kspriv;
+ int rtn = 0;
+
+ kspriv = dev_get_drvdata(ksdev);
+
+ init_completion(&testres.completion);
+
+ rtn = caam_jr_enqueue(kspriv->smringdev, jobdesc, sm_key_job_done,
+ &testres);
+ if (!rtn) {
+ wait_for_completion_interruptible(&testres.completion);
+ rtn = testres.error;
+ }
+ return rtn;
+}
+
+/*
+ * Following section establishes the default methods for keystore access
+ * They are NOT intended for use external to this module
+ *
+ * In the present version, these are the only means for the higher-level
+ * interface to deal with the mechanics of accessing the phyiscal keystore
+ */
+
+
+int slot_alloc(struct device *dev, u32 unit, u32 size, u32 *slot)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
+ u32 i;
+#ifdef SM_DEBUG
+ dev_info(dev, "slot_alloc(): requesting slot for %d bytes\n", size);
+#endif
+
+ if (size > smpriv->slot_size)
+ return -EKEYREJECTED;
+
+ for (i = 0; i < ksdata->slot_count; i++) {
+ if (ksdata->slot[i].allocated == 0) {
+ ksdata->slot[i].allocated = 1;
+ (*slot) = i;
+#ifdef SM_DEBUG
+ dev_info(dev, "slot_alloc(): new slot %d allocated\n",
+ *slot);
+#endif
+ return 0;
+ }
+ }
+
+ return -ENOSPC;
+}
+EXPORT_SYMBOL(slot_alloc);
+
+int slot_dealloc(struct device *dev, u32 unit, u32 slot)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
+ u8 __iomem *slotdata;
+
+#ifdef SM_DEBUG
+ dev_info(dev, "slot_dealloc(): releasing slot %d\n", slot);
+#endif
+ if (slot >= ksdata->slot_count)
+ return -EINVAL;
+ slotdata = ksdata->base_address + slot * smpriv->slot_size;
+
+ if (ksdata->slot[slot].allocated == 1) {
+ /* Forcibly overwrite the data from the keystore */
+ memset_io(ksdata->base_address + slot * smpriv->slot_size, 0,
+ smpriv->slot_size);
+
+ ksdata->slot[slot].allocated = 0;
+#ifdef SM_DEBUG
+ dev_info(dev, "slot_dealloc(): slot %d released\n", slot);
+#endif
+ return 0;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(slot_dealloc);
+
+void *slot_get_address(struct device *dev, u32 unit, u32 slot)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
+
+ if (slot >= ksdata->slot_count)
+ return NULL;
+
+#ifdef SM_DEBUG
+ dev_info(dev, "slot_get_address(): slot %d is 0x%08x\n", slot,
+ (u32)ksdata->base_address + slot * smpriv->slot_size);
+#endif
+
+ return ksdata->base_address + slot * smpriv->slot_size;
+}
+
+void *slot_get_physical(struct device *dev, u32 unit, u32 slot)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
+
+ if (slot >= ksdata->slot_count)
+ return NULL;
+
+#ifdef SM_DEBUG
+ dev_info(dev, "slot_get_physical(): slot %d is 0x%08x\n", slot,
+ (u32)ksdata->phys_address + slot * smpriv->slot_size);
+#endif
+
+ return ksdata->phys_address + slot * smpriv->slot_size;
+}
+
+u32 slot_get_base(struct device *dev, u32 unit, u32 slot)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
+
+ /*
+ * There could potentially be more than one secure partition object
+ * associated with this keystore. For now, there is just one.
+ */
+
+ (void)slot;
+
+#ifdef SM_DEBUG
+ dev_info(dev, "slot_get_base(): slot %d = 0x%08x\n",
+ slot, (u32)ksdata->base_address);
+#endif
+
+ return (uintptr_t)(ksdata->base_address);
+}
+
+u32 slot_get_offset(struct device *dev, u32 unit, u32 slot)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ struct keystore_data *ksdata = smpriv->pagedesc[unit].ksdata;
+
+ if (slot >= ksdata->slot_count)
+ return -EINVAL;
+
+#ifdef SM_DEBUG
+ dev_info(dev, "slot_get_offset(): slot %d = %d\n", slot,
+ slot * smpriv->slot_size);
+#endif
+
+ return slot * smpriv->slot_size;
+}
+
+u32 slot_get_slot_size(struct device *dev, u32 unit, u32 slot)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+
+
+#ifdef SM_DEBUG
+ dev_info(dev, "slot_get_slot_size(): slot %d = %d\n", slot,
+ smpriv->slot_size);
+#endif
+ /* All slots are the same size in the default implementation */
+ return smpriv->slot_size;
+}
+
+
+
+int kso_init_data(struct device *dev, u32 unit)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ int retval = -EINVAL;
+ struct keystore_data *keystore_data = NULL;
+ u32 slot_count;
+ u32 keystore_data_size;
+
+ /*
+ * Calculate the required size of the keystore data structure, based
+ * on the number of keys that can fit in the partition.
+ */
+ slot_count = smpriv->page_size / smpriv->slot_size;
+#ifdef SM_DEBUG
+ dev_info(dev, "kso_init_data: %d slots initializing\n", slot_count);
+#endif
+
+ keystore_data_size = sizeof(struct keystore_data) +
+ slot_count *
+ sizeof(struct keystore_data_slot_info);
+
+ keystore_data = kzalloc(keystore_data_size, GFP_KERNEL);
+
+ if (keystore_data == NULL) {
+ retval = -ENOSPC;
+ goto out;
+ }
+
+#ifdef SM_DEBUG
+ dev_info(dev, "kso_init_data: keystore data size = %d\n",
+ keystore_data_size);
+#endif
+
+ /*
+ * Place the slot information structure directly after the keystore data
+ * structure.
+ */
+ keystore_data->slot = (struct keystore_data_slot_info *)
+ (keystore_data + 1);
+ keystore_data->slot_count = slot_count;
+
+ smpriv->pagedesc[unit].ksdata = keystore_data;
+ smpriv->pagedesc[unit].ksdata->base_address =
+ smpriv->pagedesc[unit].pg_base;
+ smpriv->pagedesc[unit].ksdata->phys_address =
+ smpriv->pagedesc[unit].pg_phys;
+
+ retval = 0;
+
+out:
+ if (retval != 0)
+ if (keystore_data != NULL)
+ kfree(keystore_data);
+
+
+ return retval;
+}
+
+void kso_cleanup_data(struct device *dev, u32 unit)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ struct keystore_data *keystore_data = NULL;
+
+ if (smpriv->pagedesc[unit].ksdata != NULL)
+ keystore_data = smpriv->pagedesc[unit].ksdata;
+
+ /* Release the allocated keystore management data */
+ kfree(smpriv->pagedesc[unit].ksdata);
+
+ return;
+}
+
+
+
+/*
+ * Keystore management section
+ */
+
+void sm_init_keystore(struct device *dev)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+
+ smpriv->data_init = kso_init_data;
+ smpriv->data_cleanup = kso_cleanup_data;
+ smpriv->slot_alloc = slot_alloc;
+ smpriv->slot_dealloc = slot_dealloc;
+ smpriv->slot_get_address = slot_get_address;
+ smpriv->slot_get_physical = slot_get_physical;
+ smpriv->slot_get_base = slot_get_base;
+ smpriv->slot_get_offset = slot_get_offset;
+ smpriv->slot_get_slot_size = slot_get_slot_size;
+#ifdef SM_DEBUG
+ dev_info(dev, "sm_init_keystore(): handlers installed\n");
+#endif
+}
+EXPORT_SYMBOL(sm_init_keystore);
+
+/* Return available pages/units */
+u32 sm_detect_keystore_units(struct device *dev)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+
+ return smpriv->localpages;
+}
+EXPORT_SYMBOL(sm_detect_keystore_units);
+
+/*
+ * Do any keystore specific initializations
+ */
+int sm_establish_keystore(struct device *dev, u32 unit)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+
+#ifdef SM_DEBUG
+ dev_info(dev, "sm_establish_keystore(): unit %d initializing\n", unit);
+#endif
+
+ if (smpriv->data_init == NULL)
+ return -EINVAL;
+
+ /* Call the data_init function for any user setup */
+ return smpriv->data_init(dev, unit);
+}
+EXPORT_SYMBOL(sm_establish_keystore);
+
+void sm_release_keystore(struct device *dev, u32 unit)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+
+#ifdef SM_DEBUG
+ dev_info(dev, "sm_establish_keystore(): unit %d releasing\n", unit);
+#endif
+ if ((smpriv != NULL) && (smpriv->data_cleanup != NULL))
+ smpriv->data_cleanup(dev, unit);
+
+ return;
+}
+EXPORT_SYMBOL(sm_release_keystore);
+
+/*
+ * Subsequent interfacce (sm_keystore_*) forms the accessor interfacce to
+ * the keystore
+ */
+int sm_keystore_slot_alloc(struct device *dev, u32 unit, u32 size, u32 *slot)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ int retval = -EINVAL;
+
+ spin_lock(&smpriv->kslock);
+
+ if ((smpriv->slot_alloc == NULL) ||
+ (smpriv->pagedesc[unit].ksdata == NULL))
+ goto out;
+
+ retval = smpriv->slot_alloc(dev, unit, size, slot);
+
+out:
+ spin_unlock(&smpriv->kslock);
+ return retval;
+}
+EXPORT_SYMBOL(sm_keystore_slot_alloc);
+
+int sm_keystore_slot_dealloc(struct device *dev, u32 unit, u32 slot)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ int retval = -EINVAL;
+
+ spin_lock(&smpriv->kslock);
+
+ if ((smpriv->slot_alloc == NULL) ||
+ (smpriv->pagedesc[unit].ksdata == NULL))
+ goto out;
+
+ retval = smpriv->slot_dealloc(dev, unit, slot);
+out:
+ spin_unlock(&smpriv->kslock);
+ return retval;
+}
+EXPORT_SYMBOL(sm_keystore_slot_dealloc);
+
+int sm_keystore_slot_load(struct device *dev, u32 unit, u32 slot,
+ const u8 *key_data, u32 key_length)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ int retval = -EINVAL;
+ u32 slot_size;
+ u8 __iomem *slot_location;
+
+ spin_lock(&smpriv->kslock);
+
+ slot_size = smpriv->slot_get_slot_size(dev, unit, slot);
+
+ if (key_length > slot_size) {
+ retval = -EFBIG;
+ goto out;
+ }
+
+ slot_location = smpriv->slot_get_address(dev, unit, slot);
+
+ memcpy_toio(slot_location, key_data, key_length);
+
+ retval = 0;
+
+out:
+ spin_unlock(&smpriv->kslock);
+ return retval;
+}
+EXPORT_SYMBOL(sm_keystore_slot_load);
+
+int sm_keystore_slot_read(struct device *dev, u32 unit, u32 slot,
+ u32 key_length, u8 *key_data)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ int retval = -EINVAL;
+ u8 __iomem *slot_addr;
+ u32 slot_size;
+
+ spin_lock(&smpriv->kslock);
+
+ slot_addr = smpriv->slot_get_address(dev, unit, slot);
+ slot_size = smpriv->slot_get_slot_size(dev, unit, slot);
+
+ if (key_length > slot_size) {
+ retval = -EKEYREJECTED;
+ goto out;
+ }
+
+ memcpy_fromio(key_data, slot_addr, key_length);
+ retval = 0;
+
+out:
+ spin_unlock(&smpriv->kslock);
+ return retval;
+}
+EXPORT_SYMBOL(sm_keystore_slot_read);
+
+/*
+ * Blacken a clear key in a slot. Operates "in place".
+ * Limited to class 1 keys at the present time
+ */
+int sm_keystore_cover_key(struct device *dev, u32 unit, u32 slot,
+ u16 key_length, u8 keyauth)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ int retval = 0;
+ u8 __iomem *slotaddr;
+ void *slotphys;
+ u32 dsize, jstat;
+ u32 __iomem *coverdesc = NULL;
+
+ /* Get the address of the object in the slot */
+ slotaddr = (u8 *)smpriv->slot_get_address(dev, unit, slot);
+ slotphys = (u8 *)smpriv->slot_get_physical(dev, unit, slot);
+
+ dsize = blacken_key_jobdesc(&coverdesc, slotphys, key_length, keyauth);
+ if (!dsize)
+ return -ENOMEM;
+ jstat = sm_key_job(dev, coverdesc);
+ if (jstat)
+ retval = -EIO;
+
+ kfree(coverdesc);
+ return retval;
+}
+EXPORT_SYMBOL(sm_keystore_cover_key);
+
+/* Export a black/red key to a blob in external memory */
+int sm_keystore_slot_export(struct device *dev, u32 unit, u32 slot, u8 keycolor,
+ u8 keyauth, u8 *outbuf, u16 keylen, u8 *keymod)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ int retval = 0;
+ u8 __iomem *slotaddr, *lkeymod;
+ u8 __iomem *slotphys;
+ dma_addr_t keymod_dma, outbuf_dma;
+ u32 dsize, jstat;
+ u32 __iomem *encapdesc = NULL;
+
+ /* Get the base address(es) of the specified slot */
+ slotaddr = (u8 *)smpriv->slot_get_address(dev, unit, slot);
+ slotphys = smpriv->slot_get_physical(dev, unit, slot);
+
+ /* Build/map/flush the key modifier */
+ lkeymod = kmalloc(SECMEM_KEYMOD_LEN, GFP_KERNEL | GFP_DMA);
+ memcpy(lkeymod, keymod, SECMEM_KEYMOD_LEN);
+ keymod_dma = dma_map_single(dev, lkeymod, SECMEM_KEYMOD_LEN,
+ DMA_TO_DEVICE);
+ dma_sync_single_for_device(dev, keymod_dma, SECMEM_KEYMOD_LEN,
+ DMA_TO_DEVICE);
+
+ outbuf_dma = dma_map_single(dev, outbuf, keylen + BLOB_OVERHEAD,
+ DMA_FROM_DEVICE);
+
+ /* Build the encapsulation job descriptor */
+ dsize = blob_encap_jobdesc(&encapdesc, keymod_dma, slotphys, outbuf_dma,
+ keylen, keycolor, SM_SECMEM, keyauth);
+ if (!dsize) {
+ dev_err(dev, "can't alloc an encapsulation descriptor\n");
+ retval = -ENOMEM;
+ goto out;
+ }
+ jstat = sm_key_job(dev, encapdesc);
+ dma_sync_single_for_cpu(dev, outbuf_dma, keylen + BLOB_OVERHEAD,
+ DMA_FROM_DEVICE);
+ if (jstat)
+ retval = -EIO;
+
+out:
+ dma_unmap_single(dev, outbuf_dma, keylen + BLOB_OVERHEAD,
+ DMA_FROM_DEVICE);
+ dma_unmap_single(dev, keymod_dma, SECMEM_KEYMOD_LEN, DMA_TO_DEVICE);
+ kfree(encapdesc);
+
+ return retval;
+}
+EXPORT_SYMBOL(sm_keystore_slot_export);
+
+/* Import a black/red key from a blob residing in external memory */
+int sm_keystore_slot_import(struct device *dev, u32 unit, u32 slot, u8 keycolor,
+ u8 keyauth, u8 *inbuf, u16 keylen, u8 *keymod)
+{
+ struct caam_drv_private_sm *smpriv = dev_get_drvdata(dev);
+ int retval = 0;
+ u8 __iomem *slotaddr, *lkeymod;
+ u8 __iomem *slotphys;
+ dma_addr_t keymod_dma, inbuf_dma;
+ u32 dsize, jstat;
+ u32 __iomem *decapdesc = NULL;
+
+ /* Get the base address(es) of the specified slot */
+ slotaddr = (u8 *)smpriv->slot_get_address(dev, unit, slot);
+ slotphys = smpriv->slot_get_physical(dev, unit, slot);
+
+ /* Build/map/flush the key modifier */
+ lkeymod = kmalloc(SECMEM_KEYMOD_LEN, GFP_KERNEL | GFP_DMA);
+ memcpy(lkeymod, keymod, SECMEM_KEYMOD_LEN);
+ keymod_dma = dma_map_single(dev, lkeymod, SECMEM_KEYMOD_LEN,
+ DMA_TO_DEVICE);
+ dma_sync_single_for_device(dev, keymod_dma, SECMEM_KEYMOD_LEN,
+ DMA_TO_DEVICE);
+
+ inbuf_dma = dma_map_single(dev, inbuf, keylen + BLOB_OVERHEAD,
+ DMA_TO_DEVICE);
+ dma_sync_single_for_device(dev, inbuf_dma, keylen + BLOB_OVERHEAD,
+ DMA_TO_DEVICE);
+
+ /* Build the encapsulation job descriptor */
+ dsize = blob_decap_jobdesc(&decapdesc, keymod_dma, inbuf_dma, slotphys,
+ keylen, keycolor, SM_SECMEM, keyauth);
+ if (!dsize) {
+ dev_err(dev, "can't alloc a decapsulation descriptor\n");
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ jstat = sm_key_job(dev, decapdesc);
+
+ /*
+ * May want to expand upon error meanings a bit. Any CAAM status
+ * is reported as EIO, but we might want to look for something more
+ * meaningful for something like an ICV error on restore, otherwise
+ * the caller is left guessing.
+ */
+ if (jstat)
+ retval = -EIO;
+
+out:
+ dma_unmap_single(dev, inbuf_dma, keylen + BLOB_OVERHEAD,
+ DMA_TO_DEVICE);
+ dma_unmap_single(dev, keymod_dma, SECMEM_KEYMOD_LEN, DMA_TO_DEVICE);
+ kfree(decapdesc);
+
+ return retval;
+}
+EXPORT_SYMBOL(sm_keystore_slot_import);
+
+/*
+ * Initialization/shutdown subsystem
+ * Assumes statically-invoked startup/shutdown from the controller driver
+ * for the present time, to be reworked when a device tree becomes
+ * available. This code will not modularize in present form.
+ *
+ * Also, simply uses ring 0 for execution at the present
+ */
+
+int caam_sm_startup(struct platform_device *pdev)
+{
+ struct device *ctrldev, *smdev;
+ struct caam_drv_private *ctrlpriv;
+ struct caam_drv_private_sm *smpriv;
+ struct platform_device *jrpdev;
+ struct caam_drv_private_jr *jrpriv; /* need this for reg page */
+ struct platform_device *sm_pdev;
+ struct sm_page_descriptor *lpagedesc;
+ u32 page, pgstat, lpagect, detectedpage, smvid, smpart;
+ int ret = 0;
+
+ struct device_node *np;
+ ctrldev = &pdev->dev;
+ ctrlpriv = dev_get_drvdata(ctrldev);
+
+ /*
+ * If ctrlpriv is NULL, it's probably because the caam driver wasn't
+ * properly initialized (e.g. RNG4 init failed). Thus, bail out here.
+ */
+ if (!ctrlpriv) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ /*
+ * Set up the private block for secure memory
+ * Only one instance is possible
+ */
+ smpriv = kzalloc(sizeof(struct caam_drv_private_sm), GFP_KERNEL);
+ if (smpriv == NULL) {
+ dev_err(ctrldev, "can't alloc private mem for secure memory\n");
+ ret = -ENOMEM;
+ goto exit;
+ }
+ smpriv->parentdev = ctrldev; /* copy of parent dev is handy */
+ spin_lock_init(&smpriv->kslock);
+
+ /* Create the dev */
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-caam-sm");
+ if (np)
+ of_node_clear_flag(np, OF_POPULATED);
+ sm_pdev = of_platform_device_create(np, "caam_sm", ctrldev);
+
+ if (sm_pdev == NULL) {
+ ret = -EINVAL;
+ goto free_smpriv;
+ }
+
+ /* Save a pointer to the platform device for Secure Memory */
+ smpriv->sm_pdev = sm_pdev;
+ smdev = &sm_pdev->dev;
+ dev_set_drvdata(smdev, smpriv);
+ ctrlpriv->smdev = smdev;
+
+ /* Set the Secure Memory Register Map Version */
+ if (ctrlpriv->has_seco) {
+ int i = ctrlpriv->first_jr_index;
+
+ smvid = rd_reg32(&ctrlpriv->jr[i]->perfmon.smvid);
+ smpart = rd_reg32(&ctrlpriv->jr[i]->perfmon.smpart);
+
+ } else {
+ smvid = rd_reg32(&ctrlpriv->ctrl->perfmon.smvid);
+ smpart = rd_reg32(&ctrlpriv->ctrl->perfmon.smpart);
+
+ }
+
+ if (smvid < SMVID_V2)
+ smpriv->sm_reg_offset = SM_V1_OFFSET;
+ else
+ smpriv->sm_reg_offset = SM_V2_OFFSET;
+
+ /*
+ * Collect configuration limit data for reference
+ * This batch comes from the partition data/vid registers in perfmon
+ */
+ smpriv->max_pages = ((smpart & SMPART_MAX_NUMPG_MASK) >>
+ SMPART_MAX_NUMPG_SHIFT) + 1;
+ smpriv->top_partition = ((smpart & SMPART_MAX_PNUM_MASK) >>
+ SMPART_MAX_PNUM_SHIFT) + 1;
+ smpriv->top_page = ((smpart & SMPART_MAX_PG_MASK) >>
+ SMPART_MAX_PG_SHIFT) + 1;
+ smpriv->page_size = 1024 << ((smvid & SMVID_PG_SIZE_MASK) >>
+ SMVID_PG_SIZE_SHIFT);
+ smpriv->slot_size = 1 << CONFIG_CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE;
+
+#ifdef SM_DEBUG
+ dev_info(smdev, "max pages = %d, top partition = %d\n",
+ smpriv->max_pages, smpriv->top_partition);
+ dev_info(smdev, "top page = %d, page size = %d (total = %d)\n",
+ smpriv->top_page, smpriv->page_size,
+ smpriv->top_page * smpriv->page_size);
+ dev_info(smdev, "selected slot size = %d\n", smpriv->slot_size);
+#endif
+
+ /*
+ * Now probe for partitions/pages to which we have access. Note that
+ * these have likely been set up by a bootloader or platform
+ * provisioning application, so we have to assume that we "inherit"
+ * a configuration and work within the constraints of what it might be.
+ *
+ * Assume use of the zeroth ring in the present iteration (until
+ * we can divorce the controller and ring drivers, and then assign
+ * an SM instance to any ring instance).
+ */
+ jrpdev = ctrlpriv->jrpdev[0];
+ if (!jrpdev) {
+ dev_err(smdev, "Platform device for job ring not created\n");
+ ret = -ENODEV;
+ goto unregister_smpdev;
+ }
+
+ smpriv->smringdev = &jrpdev->dev;
+ if (!smpriv->smringdev) {
+ dev_err(smdev, "Device for job ring not created\n");
+ ret = -ENODEV;
+ goto unregister_smpdev;
+ }
+
+ jrpriv = dev_get_drvdata(smpriv->smringdev);
+ lpagect = 0;
+ pgstat = 0;
+ lpagedesc = kzalloc(sizeof(struct sm_page_descriptor)
+ * smpriv->max_pages, GFP_KERNEL);
+ if (lpagedesc == NULL) {
+ ret = -ENOMEM;
+ goto free_smpriv;
+ }
+
+ for (page = 0; page < smpriv->max_pages; page++) {
+ if (sm_send_cmd(smpriv, jrpriv,
+ ((page << SMC_PAGE_SHIFT) & SMC_PAGE_MASK) |
+ (SMC_CMD_PAGE_INQUIRY & SMC_CMD_MASK),
+ &pgstat)) {
+ ret = -EINVAL;
+ goto free_lpagedesc;
+ }
+
+ if (((pgstat & SMCS_PGWON_MASK) >> SMCS_PGOWN_SHIFT)
+ == SMCS_PGOWN_OWNED) { /* our page? */
+ lpagedesc[page].phys_pagenum =
+ (pgstat & SMCS_PAGE_MASK) >> SMCS_PAGE_SHIFT;
+ lpagedesc[page].own_part =
+ (pgstat & SMCS_PART_SHIFT) >> SMCS_PART_MASK;
+ lpagedesc[page].pg_base = (u8 *)ctrlpriv->sm_base +
+ (smpriv->page_size * page);
+ if (ctrlpriv->has_seco) {
+/* FIXME: get different addresses viewed by CPU and CAAM from
+ * platform property
+ */
+ lpagedesc[page].pg_phys = (u8 *)0x20800000 +
+ (smpriv->page_size * page);
+ } else {
+ lpagedesc[page].pg_phys =
+ (u8 *) ctrlpriv->sm_phy +
+ (smpriv->page_size * page);
+ }
+ lpagect++;
+#ifdef SM_DEBUG
+ dev_info(smdev,
+ "physical page %d, owning partition = %d\n",
+ lpagedesc[page].phys_pagenum,
+ lpagedesc[page].own_part);
+#endif
+ }
+ }
+
+ smpriv->pagedesc = kzalloc(sizeof(struct sm_page_descriptor) * lpagect,
+ GFP_KERNEL);
+ if (smpriv->pagedesc == NULL) {
+ ret = -ENOMEM;
+ goto free_lpagedesc;
+ }
+ smpriv->localpages = lpagect;
+
+ detectedpage = 0;
+ for (page = 0; page < smpriv->max_pages; page++) {
+ if (lpagedesc[page].pg_base != NULL) { /* e.g. live entry */
+ memcpy(&smpriv->pagedesc[detectedpage],
+ &lpagedesc[page],
+ sizeof(struct sm_page_descriptor));
+#ifdef SM_DEBUG_CONT
+ sm_show_page(smdev, &smpriv->pagedesc[detectedpage]);
+#endif
+ detectedpage++;
+ }
+ }
+
+ kfree(lpagedesc);
+
+ sm_init_keystore(smdev);
+
+ goto exit;
+
+free_lpagedesc:
+ kfree(lpagedesc);
+unregister_smpdev:
+ of_device_unregister(smpriv->sm_pdev);
+free_smpriv:
+ kfree(smpriv);
+
+exit:
+ return ret;
+}
+
+void caam_sm_shutdown(struct platform_device *pdev)
+{
+ struct device *ctrldev, *smdev;
+ struct caam_drv_private *priv;
+ struct caam_drv_private_sm *smpriv;
+
+ ctrldev = &pdev->dev;
+ priv = dev_get_drvdata(ctrldev);
+ smdev = priv->smdev;
+
+ /* Return if resource not initialized by startup */
+ if (smdev == NULL)
+ return;
+
+ smpriv = dev_get_drvdata(smdev);
+
+ /* Remove Secure Memory Platform Device */
+ of_device_unregister(smpriv->sm_pdev);
+
+ kfree(smpriv->pagedesc);
+ kfree(smpriv);
+}
+EXPORT_SYMBOL(caam_sm_shutdown);
+
+static void __exit caam_sm_exit(void)
+{
+ struct device_node *dev_node;
+ struct platform_device *pdev;
+
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+ if (!dev_node)
+ return;
+ }
+
+ pdev = of_find_device_by_node(dev_node);
+ if (!pdev)
+ return;
+
+ of_node_put(dev_node);
+
+ caam_sm_shutdown(pdev);
+
+ return;
+}
+
+static int __init caam_sm_init(void)
+{
+ struct device_node *dev_node;
+ struct platform_device *pdev;
+
+ /*
+ * Do of_find_compatible_node() then of_find_device_by_node()
+ * once a functional device tree is available
+ */
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+ if (!dev_node)
+ return -ENODEV;
+ }
+
+ pdev = of_find_device_by_node(dev_node);
+ if (!pdev)
+ return -ENODEV;
+
+ of_node_get(dev_node);
+
+ caam_sm_startup(pdev);
+
+ return 0;
+}
+
+module_init(caam_sm_init);
+module_exit(caam_sm_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("FSL CAAM Secure Memory / Keystore");
+MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD");
diff --git a/drivers/crypto/caam/sm_test.c b/drivers/crypto/caam/sm_test.c
new file mode 100644
index 000000000000..3c5eba4c6fbc
--- /dev/null
+++ b/drivers/crypto/caam/sm_test.c
@@ -0,0 +1,524 @@
+/*
+ * Secure Memory / Keystore Exemplification Module
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved
+ *
+ * This module has been overloaded as an example to show:
+ * - Secure memory subsystem initialization/shutdown
+ * - Allocation/deallocation of "slots" in a secure memory page
+ * - Loading and unloading of key material into slots
+ * - Covering of secure memory objects into "black keys" (ECB only at present)
+ * - Verification of key covering (by differentiation only)
+ * - Exportation of keys into secure memory blobs (with display of result)
+ * - Importation of keys from secure memory blobs (with display of result)
+ * - Verification of re-imported keys where possible.
+ *
+ * The module does not show the use of key objects as working key register
+ * source material at this time.
+ *
+ * This module can use a substantial amount of refactoring, which may occur
+ * after the API gets some mileage. Furthermore, expect this module to
+ * eventually disappear once the API is integrated into "real" software.
+ */
+
+#include "compat.h"
+#include "intern.h"
+#include "desc.h"
+#include "error.h"
+#include "jr.h"
+#include "sm.h"
+
+/* Fixed known pattern for a key modifier */
+static u8 skeymod[] = {
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
+ 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
+};
+
+/* Fixed known pattern for a key */
+static u8 clrkey[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x0f, 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
+};
+
+static void key_display(struct device *dev, u8 *label, u16 size, u8 *key)
+{
+ unsigned i;
+
+ dev_info(dev, label);
+ for (i = 0; i < size; i += 8)
+ dev_info(dev,
+ "[%04d] %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ i, key[i], key[i + 1], key[i + 2], key[i + 3],
+ key[i + 4], key[i + 5], key[i + 6], key[i + 7]);
+}
+
+int caam_sm_example_init(struct platform_device *pdev)
+{
+ struct device *ctrldev, *ksdev;
+ struct caam_drv_private *ctrlpriv;
+ struct caam_drv_private_sm *kspriv;
+ u32 unit, units;
+ int rtnval = 0;
+ u8 clrkey8[8], clrkey16[16], clrkey24[24], clrkey32[32];
+ u8 blkkey8[AES_BLOCK_PAD(8)], blkkey16[AES_BLOCK_PAD(16)];
+ u8 blkkey24[AES_BLOCK_PAD(24)], blkkey32[AES_BLOCK_PAD(32)];
+ u8 rstkey8[AES_BLOCK_PAD(8)], rstkey16[AES_BLOCK_PAD(16)];
+ u8 rstkey24[AES_BLOCK_PAD(24)], rstkey32[AES_BLOCK_PAD(32)];
+ u8 __iomem *blob8, *blob16, *blob24, *blob32;
+ u32 keyslot8, keyslot16, keyslot24, keyslot32 = 0;
+
+ blob8 = blob16 = blob24 = blob32 = NULL;
+
+ /*
+ * 3.5.x and later revs for MX6 should be able to ditch this
+ * and detect via dts property
+ */
+ ctrldev = &pdev->dev;
+ ctrlpriv = dev_get_drvdata(ctrldev);
+
+ /*
+ * If ctrlpriv is NULL, it's probably because the caam driver wasn't
+ * properly initialized (e.g. RNG4 init failed). Thus, bail out here.
+ */
+ if (!ctrlpriv)
+ return -ENODEV;
+
+ ksdev = ctrlpriv->smdev;
+ kspriv = dev_get_drvdata(ksdev);
+ if (kspriv == NULL)
+ return -ENODEV;
+
+ /* What keystores are available ? */
+ units = sm_detect_keystore_units(ksdev);
+ if (!units)
+ dev_err(ksdev, "blkkey_ex: no keystore units available\n");
+
+ /*
+ * MX6 bootloader stores some stuff in unit 0, so let's
+ * use 1 or above
+ */
+ if (units < 2) {
+ dev_err(ksdev, "blkkey_ex: insufficient keystore units\n");
+ return -ENODEV;
+ }
+ unit = 1;
+
+ dev_info(ksdev, "blkkey_ex: %d keystore units available\n", units);
+
+ /* Initialize/Establish Keystore */
+ sm_establish_keystore(ksdev, unit); /* Initalize store in #1 */
+
+ /*
+ * Now let's set up buffers for blobs in DMA-able memory. All are
+ * larger than need to be so that blob size can be seen.
+ */
+ blob8 = kzalloc(128, GFP_KERNEL | GFP_DMA);
+ blob16 = kzalloc(128, GFP_KERNEL | GFP_DMA);
+ blob24 = kzalloc(128, GFP_KERNEL | GFP_DMA);
+ blob32 = kzalloc(128, GFP_KERNEL | GFP_DMA);
+
+ if ((blob8 == NULL) || (blob16 == NULL) || (blob24 == NULL) ||
+ (blob32 == NULL)) {
+ rtnval = -ENOMEM;
+ dev_err(ksdev, "blkkey_ex: can't get blob buffers\n");
+ goto freemem;
+ }
+
+ /* Initialize clear keys with a known and recognizable pattern */
+ memcpy(clrkey8, clrkey, 8);
+ memcpy(clrkey16, clrkey, 16);
+ memcpy(clrkey24, clrkey, 24);
+ memcpy(clrkey32, clrkey, 32);
+
+ memset(blkkey8, 0, AES_BLOCK_PAD(8));
+ memset(blkkey16, 0, AES_BLOCK_PAD(16));
+ memset(blkkey24, 0, AES_BLOCK_PAD(24));
+ memset(blkkey32, 0, AES_BLOCK_PAD(32));
+
+ memset(rstkey8, 0, AES_BLOCK_PAD(8));
+ memset(rstkey16, 0, AES_BLOCK_PAD(16));
+ memset(rstkey24, 0, AES_BLOCK_PAD(24));
+ memset(rstkey32, 0, AES_BLOCK_PAD(32));
+
+ /*
+ * Allocate keyslots. Since we're going to blacken keys in-place,
+ * we want slots big enough to pad out to the next larger AES blocksize
+ * so pad them out.
+ */
+ if (sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(8), &keyslot8))
+ goto dealloc;
+
+ if (sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(16), &keyslot16))
+ goto dealloc;
+
+ if (sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(24), &keyslot24))
+ goto dealloc;
+
+ if (sm_keystore_slot_alloc(ksdev, unit, AES_BLOCK_PAD(32), &keyslot32))
+ goto dealloc;
+
+
+ /* Now load clear key data into the newly allocated slots */
+ if (sm_keystore_slot_load(ksdev, unit, keyslot8, clrkey8, 8))
+ goto dealloc;
+
+ if (sm_keystore_slot_load(ksdev, unit, keyslot16, clrkey16, 16))
+ goto dealloc;
+
+ if (sm_keystore_slot_load(ksdev, unit, keyslot24, clrkey24, 24))
+ goto dealloc;
+
+ if (sm_keystore_slot_load(ksdev, unit, keyslot32, clrkey32, 32))
+ goto dealloc;
+
+ /*
+ * All cleartext keys are loaded into slots (in an unprotected
+ * partition at this time)
+ *
+ * Cover keys in-place
+ */
+ if (sm_keystore_cover_key(ksdev, unit, keyslot8, 8, KEY_COVER_ECB)) {
+ dev_info(ksdev, "blkkey_ex: can't cover 64-bit key\n");
+ goto dealloc;
+ }
+
+ if (sm_keystore_cover_key(ksdev, unit, keyslot16, 16, KEY_COVER_ECB)) {
+ dev_info(ksdev, "blkkey_ex: can't cover 128-bit key\n");
+ goto dealloc;
+ }
+
+ if (sm_keystore_cover_key(ksdev, unit, keyslot24, 24, KEY_COVER_ECB)) {
+ dev_info(ksdev, "blkkey_ex: can't cover 192-bit key\n");
+ goto dealloc;
+ }
+
+ if (sm_keystore_cover_key(ksdev, unit, keyslot32, 32, KEY_COVER_ECB)) {
+ dev_info(ksdev, "blkkey_ex: can't cover 256-bit key\n");
+ goto dealloc;
+ }
+
+ /*
+ * Keys should be covered and appear sufficiently "random"
+ * as a result of the covering (blackening) process. Assuming
+ * non-secure mode, read them back out for examination; they should
+ * appear as random data, completely differing from the clear
+ * inputs. So, this will read them back from secure memory and
+ * compare them. If they match the clear key, then the covering
+ * operation didn't occur.
+ */
+
+ if (sm_keystore_slot_read(ksdev, unit, keyslot8, AES_BLOCK_PAD(8),
+ blkkey8)) {
+ dev_info(ksdev, "blkkey_ex: can't read 64-bit black key\n");
+ goto dealloc;
+ }
+
+ if (sm_keystore_slot_read(ksdev, unit, keyslot16, AES_BLOCK_PAD(16),
+ blkkey16)) {
+ dev_info(ksdev, "blkkey_ex: can't read 128-bit black key\n");
+ goto dealloc;
+ }
+
+ if (sm_keystore_slot_read(ksdev, unit, keyslot24, AES_BLOCK_PAD(24),
+ blkkey24)) {
+ dev_info(ksdev, "blkkey_ex: can't read 192-bit black key\n");
+ goto dealloc;
+ }
+
+ if (sm_keystore_slot_read(ksdev, unit, keyslot32, AES_BLOCK_PAD(32),
+ blkkey32)) {
+ dev_info(ksdev, "blkkey_ex: can't read 256-bit black key\n");
+ goto dealloc;
+ }
+
+
+ if (!memcmp(blkkey8, clrkey8, 8)) {
+ dev_info(ksdev, "blkkey_ex: 64-bit key cover failed\n");
+ goto dealloc;
+ }
+
+ if (!memcmp(blkkey16, clrkey16, 16)) {
+ dev_info(ksdev, "blkkey_ex: 128-bit key cover failed\n");
+ goto dealloc;
+ }
+
+ if (!memcmp(blkkey24, clrkey24, 24)) {
+ dev_info(ksdev, "blkkey_ex: 192-bit key cover failed\n");
+ goto dealloc;
+ }
+
+ if (!memcmp(blkkey32, clrkey32, 32)) {
+ dev_info(ksdev, "blkkey_ex: 256-bit key cover failed\n");
+ goto dealloc;
+ }
+
+
+ key_display(ksdev, "64-bit clear key:", 8, clrkey8);
+ key_display(ksdev, "64-bit black key:", AES_BLOCK_PAD(8), blkkey8);
+
+ key_display(ksdev, "128-bit clear key:", 16, clrkey16);
+ key_display(ksdev, "128-bit black key:", AES_BLOCK_PAD(16), blkkey16);
+
+ key_display(ksdev, "192-bit clear key:", 24, clrkey24);
+ key_display(ksdev, "192-bit black key:", AES_BLOCK_PAD(24), blkkey24);
+
+ key_display(ksdev, "256-bit clear key:", 32, clrkey32);
+ key_display(ksdev, "256-bit black key:", AES_BLOCK_PAD(32), blkkey32);
+
+ /*
+ * Now encapsulate all keys as SM blobs out to external memory
+ * Blobs will appear as random-looking blocks of data different
+ * from the original source key, and 48 bytes longer than the
+ * original key, to account for the extra data encapsulated within.
+ */
+ key_display(ksdev, "64-bit unwritten blob:", 96, blob8);
+ key_display(ksdev, "128-bit unwritten blob:", 96, blob16);
+ key_display(ksdev, "196-bit unwritten blob:", 96, blob24);
+ key_display(ksdev, "256-bit unwritten blob:", 96, blob32);
+
+ if (sm_keystore_slot_export(ksdev, unit, keyslot8, BLACK_KEY,
+ KEY_COVER_ECB, blob8, 8, skeymod)) {
+ dev_info(ksdev, "blkkey_ex: can't encapsulate 64-bit key\n");
+ goto dealloc;
+ }
+
+ if (sm_keystore_slot_export(ksdev, unit, keyslot16, BLACK_KEY,
+ KEY_COVER_ECB, blob16, 16, skeymod)) {
+ dev_info(ksdev, "blkkey_ex: can't encapsulate 128-bit key\n");
+ goto dealloc;
+ }
+
+ if (sm_keystore_slot_export(ksdev, unit, keyslot24, BLACK_KEY,
+ KEY_COVER_ECB, blob24, 24, skeymod)) {
+ dev_info(ksdev, "blkkey_ex: can't encapsulate 192-bit key\n");
+ goto dealloc;
+ }
+
+ if (sm_keystore_slot_export(ksdev, unit, keyslot32, BLACK_KEY,
+ KEY_COVER_ECB, blob32, 32, skeymod)) {
+ dev_info(ksdev, "blkkey_ex: can't encapsulate 256-bit key\n");
+ goto dealloc;
+ }
+
+ key_display(ksdev, "64-bit black key in blob:", 96, blob8);
+ key_display(ksdev, "128-bit black key in blob:", 96, blob16);
+ key_display(ksdev, "192-bit black key in blob:", 96, blob24);
+ key_display(ksdev, "256-bit black key in blob:", 96, blob32);
+
+ /*
+ * Now re-import black keys from secure-memory blobs stored
+ * in general memory from the previous operation. Since we are
+ * working with black keys, and since power has not cycled, the
+ * restored black keys should match the original blackened keys
+ * (this would not be true if the blobs were save in some non-volatile
+ * store, and power was cycled between the save and restore)
+ */
+ if (sm_keystore_slot_import(ksdev, unit, keyslot8, BLACK_KEY,
+ KEY_COVER_ECB, blob8, 8, skeymod)) {
+ dev_info(ksdev, "blkkey_ex: can't decapsulate 64-bit blob\n");
+ goto dealloc;
+ }
+
+ if (sm_keystore_slot_import(ksdev, unit, keyslot16, BLACK_KEY,
+ KEY_COVER_ECB, blob16, 16, skeymod)) {
+ dev_info(ksdev, "blkkey_ex: can't decapsulate 128-bit blob\n");
+ goto dealloc;
+ }
+
+ if (sm_keystore_slot_import(ksdev, unit, keyslot24, BLACK_KEY,
+ KEY_COVER_ECB, blob24, 24, skeymod)) {
+ dev_info(ksdev, "blkkey_ex: can't decapsulate 196-bit blob\n");
+ goto dealloc;
+ }
+
+ if (sm_keystore_slot_import(ksdev, unit, keyslot32, BLACK_KEY,
+ KEY_COVER_ECB, blob32, 32, skeymod)) {
+ dev_info(ksdev, "blkkey_ex: can't decapsulate 256-bit blob\n");
+ goto dealloc;
+ }
+
+
+ /*
+ * Blobs are now restored as black keys. Read those black keys back
+ * for a comparison with the original black key, they should match
+ */
+ if (sm_keystore_slot_read(ksdev, unit, keyslot8, AES_BLOCK_PAD(8),
+ rstkey8)) {
+ dev_info(ksdev,
+ "blkkey_ex: can't read restored 64-bit black key\n");
+ goto dealloc;
+ }
+
+ if (sm_keystore_slot_read(ksdev, unit, keyslot16, AES_BLOCK_PAD(16),
+ rstkey16)) {
+ dev_info(ksdev,
+ "blkkey_ex: can't read restored 128-bit black key\n");
+ goto dealloc;
+ }
+
+ if (sm_keystore_slot_read(ksdev, unit, keyslot24, AES_BLOCK_PAD(24),
+ rstkey24)) {
+ dev_info(ksdev,
+ "blkkey_ex: can't read restored 196-bit black key\n");
+ goto dealloc;
+ }
+
+ if (sm_keystore_slot_read(ksdev, unit, keyslot32, AES_BLOCK_PAD(32),
+ rstkey32)) {
+ dev_info(ksdev,
+ "blkkey_ex: can't read restored 256-bit black key\n");
+ goto dealloc;
+ }
+
+ key_display(ksdev, "restored 64-bit black key:", AES_BLOCK_PAD(8),
+ rstkey8);
+ key_display(ksdev, "restored 128-bit black key:", AES_BLOCK_PAD(16),
+ rstkey16);
+ key_display(ksdev, "restored 192-bit black key:", AES_BLOCK_PAD(24),
+ rstkey24);
+ key_display(ksdev, "restored 256-bit black key:", AES_BLOCK_PAD(32),
+ rstkey32);
+
+ /*
+ * Compare the restored black keys with the original blackened keys
+ * As long as we're operating within the same power cycle, a black key
+ * restored from a blob should match the original black key IF the
+ * key happens to be of a size that matches a multiple of the AES
+ * blocksize. Any key that is padded to fill the block size will not
+ * match, excepting a key that exceeds a block; only the first full
+ * blocks will match (assuming ECB).
+ *
+ * Therefore, compare the 16 and 32 bit keys, they should match.
+ * The 24 bit key can only match within the first 16 byte block.
+ */
+
+ if (memcmp(rstkey16, blkkey16, AES_BLOCK_PAD(16))) {
+ dev_info(ksdev, "blkkey_ex: 128-bit restored key mismatch\n");
+ rtnval--;
+ }
+
+ /* Only first AES block will match, remainder subject to padding */
+ if (memcmp(rstkey24, blkkey24, 16)) {
+ dev_info(ksdev, "blkkey_ex: 192-bit restored key mismatch\n");
+ rtnval--;
+ }
+
+ if (memcmp(rstkey32, blkkey32, AES_BLOCK_PAD(32))) {
+ dev_info(ksdev, "blkkey_ex: 256-bit restored key mismatch\n");
+ rtnval--;
+ }
+
+
+ /* Remove keys from keystore */
+dealloc:
+ sm_keystore_slot_dealloc(ksdev, unit, keyslot8);
+ sm_keystore_slot_dealloc(ksdev, unit, keyslot16);
+ sm_keystore_slot_dealloc(ksdev, unit, keyslot24);
+ sm_keystore_slot_dealloc(ksdev, unit, keyslot32);
+
+
+ /* Free resources */
+freemem:
+ kfree(blob8);
+ kfree(blob16);
+ kfree(blob24);
+ kfree(blob32);
+
+ /* Disconnect from keystore and leave */
+ sm_release_keystore(ksdev, unit);
+
+ return rtnval;
+}
+EXPORT_SYMBOL(caam_sm_example_init);
+
+void caam_sm_example_shutdown(void)
+{
+ /* unused in present version */
+ struct device_node *dev_node;
+ struct platform_device *pdev;
+
+ /*
+ * Do of_find_compatible_node() then of_find_device_by_node()
+ * once a functional device tree is available
+ */
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+ if (!dev_node)
+ return;
+ }
+
+ pdev = of_find_device_by_node(dev_node);
+ if (!pdev)
+ return;
+
+ of_node_get(dev_node);
+
+}
+
+static int __init caam_sm_test_init(void)
+{
+ struct device_node *dev_node;
+ struct platform_device *pdev;
+
+ /*
+ * Do of_find_compatible_node() then of_find_device_by_node()
+ * once a functional device tree is available
+ */
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+ if (!dev_node)
+ return -ENODEV;
+ }
+
+ pdev = of_find_device_by_node(dev_node);
+ if (!pdev)
+ return -ENODEV;
+
+ of_node_put(dev_node);
+
+ caam_sm_example_init(pdev);
+
+ return 0;
+}
+
+
+/* Module-based initialization needs to wait for dev tree */
+#ifdef CONFIG_OF
+module_init(caam_sm_test_init);
+module_exit(caam_sm_example_shutdown);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("FSL CAAM Black Key Usage Example");
+MODULE_AUTHOR("Freescale Semiconductor - NMSG/MAD");
+#endif
diff --git a/drivers/crypto/caam/snvsregs.h b/drivers/crypto/caam/snvsregs.h
new file mode 100644
index 000000000000..eef6b8930db5
--- /dev/null
+++ b/drivers/crypto/caam/snvsregs.h
@@ -0,0 +1,237 @@
+/*
+ * SNVS hardware register-level view
+ *
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc., All Rights Reserved
+ */
+
+#ifndef SNVSREGS_H
+#define SNVSREGS_H
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+/*
+ * SNVS High Power Domain
+ * Includes security violations, HA counter, RTC, alarm
+ */
+struct snvs_hp {
+ u32 lock; /* HPLR - HP Lock */
+ u32 cmd; /* HPCOMR - HP Command */
+ u32 ctl; /* HPCR - HP Control */
+ u32 secvio_intcfg; /* HPSICR - Security Violation Int Config */
+ u32 secvio_ctl; /* HPSVCR - Security Violation Control */
+ u32 status; /* HPSR - HP Status */
+ u32 secvio_status; /* HPSVSR - Security Violation Status */
+ u32 ha_counteriv; /* High Assurance Counter IV */
+ u32 ha_counter; /* High Assurance Counter */
+ u32 rtc_msb; /* Real Time Clock/Counter MSB */
+ u32 rtc_lsb; /* Real Time Counter LSB */
+ u32 time_alarm_msb; /* Time Alarm MSB */
+ u32 time_alarm_lsb; /* Time Alarm LSB */
+};
+
+#define HP_LOCK_HAC_LCK 0x00040000
+#define HP_LOCK_HPSICR_LCK 0x00020000
+#define HP_LOCK_HPSVCR_LCK 0x00010000
+#define HP_LOCK_MKEYSEL_LCK 0x00000200
+#define HP_LOCK_TAMPCFG_LCK 0x00000100
+#define HP_LOCK_TAMPFLT_LCK 0x00000080
+#define HP_LOCK_SECVIO_LCK 0x00000040
+#define HP_LOCK_GENP_LCK 0x00000020
+#define HP_LOCK_MONOCTR_LCK 0x00000010
+#define HP_LOCK_CALIB_LCK 0x00000008
+#define HP_LOCK_SRTC_LCK 0x00000004
+#define HP_LOCK_ZMK_RD_LCK 0x00000002
+#define HP_LOCK_ZMK_WT_LCK 0x00000001
+
+#define HP_CMD_NONPRIV_AXS 0x80000000
+#define HP_CMD_HAC_STOP 0x00080000
+#define HP_CMD_HAC_CLEAR 0x00040000
+#define HP_CMD_HAC_LOAD 0x00020000
+#define HP_CMD_HAC_CFG_EN 0x00010000
+#define HP_CMD_SNVS_MSTR_KEY 0x00002000
+#define HP_CMD_PROG_ZMK 0x00001000
+#define HP_CMD_SW_LPSV 0x00000400
+#define HP_CMD_SW_FSV 0x00000200
+#define HP_CMD_SW_SV 0x00000100
+#define HP_CMD_LP_SWR_DIS 0x00000020
+#define HP_CMD_LP_SWR 0x00000010
+#define HP_CMD_SSM_SFNS_DIS 0x00000004
+#define HP_CMD_SSM_ST_DIS 0x00000002
+#define HP_CMD_SMM_ST 0x00000001
+
+#define HP_CTL_TIME_SYNC 0x00010000
+#define HP_CTL_CAL_VAL_SHIFT 10
+#define HP_CTL_CAL_VAL_MASK (0x1f << HP_CTL_CALIB_SHIFT)
+#define HP_CTL_CALIB_EN 0x00000100
+#define HP_CTL_PI_FREQ_SHIFT 4
+#define HP_CTL_PI_FREQ_MASK (0xf << HP_CTL_PI_FREQ_SHIFT)
+#define HP_CTL_PI_EN 0x00000008
+#define HP_CTL_TIMEALARM_EN 0x00000002
+#define HP_CTL_RTC_EN 0x00000001
+
+#define HP_SECVIO_INTEN_EN 0x10000000
+#define HP_SECVIO_INTEN_SRC5 0x00000020
+#define HP_SECVIO_INTEN_SRC4 0x00000010
+#define HP_SECVIO_INTEN_SRC3 0x00000008
+#define HP_SECVIO_INTEN_SRC2 0x00000004
+#define HP_SECVIO_INTEN_SRC1 0x00000002
+#define HP_SECVIO_INTEN_SRC0 0x00000001
+#define HP_SECVIO_INTEN_ALL 0x8000003f
+
+#define HP_SECVIO_ICTL_CFG_SHIFT 30
+#define HP_SECVIO_ICTL_CFG_MASK (0x3 << HP_SECVIO_ICTL_CFG_SHIFT)
+#define HP_SECVIO_ICTL_CFG5_SHIFT 5
+#define HP_SECVIO_ICTL_CFG5_MASK (0x3 << HP_SECVIO_ICTL_CFG5_SHIFT)
+#define HP_SECVIO_ICTL_CFG_DISABLE 0
+#define HP_SECVIO_ICTL_CFG_NONFATAL 1
+#define HP_SECVIO_ICTL_CFG_FATAL 2
+#define HP_SECVIO_ICTL_CFG4_FATAL 0x00000010
+#define HP_SECVIO_ICTL_CFG3_FATAL 0x00000008
+#define HP_SECVIO_ICTL_CFG2_FATAL 0x00000004
+#define HP_SECVIO_ICTL_CFG1_FATAL 0x00000002
+#define HP_SECVIO_ICTL_CFG0_FATAL 0x00000001
+
+#define HP_STATUS_ZMK_ZERO 0x80000000
+#define HP_STATUS_OTPMK_ZERO 0x08000000
+#define HP_STATUS_OTPMK_SYN_SHIFT 16
+#define HP_STATUS_OTPMK_SYN_MASK (0x1ff << HP_STATUS_OTPMK_SYN_SHIFT)
+#define HP_STATUS_SSM_ST_SHIFT 8
+#define HP_STATUS_SSM_ST_MASK (0xf << HP_STATUS_SSM_ST_SHIFT)
+#define HP_STATUS_SSM_ST_INIT 0
+#define HP_STATUS_SSM_ST_HARDFAIL 1
+#define HP_STATUS_SSM_ST_SOFTFAIL 3
+#define HP_STATUS_SSM_ST_INITINT 8
+#define HP_STATUS_SSM_ST_CHECK 9
+#define HP_STATUS_SSM_ST_NONSECURE 11
+#define HP_STATUS_SSM_ST_TRUSTED 13
+#define HP_STATUS_SSM_ST_SECURE 15
+
+#define HP_SECVIOST_ZMK_ECC_FAIL 0x08000000 /* write to clear */
+#define HP_SECVIOST_ZMK_SYN_SHIFT 16
+#define HP_SECVIOST_ZMK_SYN_MASK (0x1ff << HP_SECVIOST_ZMK_SYN_SHIFT)
+#define HP_SECVIOST_SECVIO5 0x00000020
+#define HP_SECVIOST_SECVIO4 0x00000010
+#define HP_SECVIOST_SECVIO3 0x00000008
+#define HP_SECVIOST_SECVIO2 0x00000004
+#define HP_SECVIOST_SECVIO1 0x00000002
+#define HP_SECVIOST_SECVIO0 0x00000001
+#define HP_SECVIOST_SECVIOMASK 0x0000003f
+
+/*
+ * SNVS Low Power Domain
+ * Includes glitch detector, SRTC, alarm, monotonic counter, ZMK
+ */
+struct snvs_lp {
+ u32 lock;
+ u32 ctl;
+ u32 mstr_key_ctl; /* Master Key Control */
+ u32 secvio_ctl; /* Security Violation Control */
+ u32 tamper_filt_cfg; /* Tamper Glitch Filters Configuration */
+ u32 tamper_det_cfg; /* Tamper Detectors Configuration */
+ u32 status;
+ u32 srtc_msb; /* Secure Real Time Clock/Counter MSB */
+ u32 srtc_lsb; /* Secure Real Time Clock/Counter LSB */
+ u32 time_alarm; /* Time Alarm */
+ u32 smc_msb; /* Secure Monotonic Counter MSB */
+ u32 smc_lsb; /* Secure Monotonic Counter LSB */
+ u32 pwr_glitch_det; /* Power Glitch Detector */
+ u32 gen_purpose;
+ u32 zmk[8]; /* Zeroizable Master Key */
+};
+
+#define LP_LOCK_MKEYSEL_LCK 0x00000200
+#define LP_LOCK_TAMPDET_LCK 0x00000100
+#define LP_LOCK_TAMPFLT_LCK 0x00000080
+#define LP_LOCK_SECVIO_LCK 0x00000040
+#define LP_LOCK_GENP_LCK 0x00000020
+#define LP_LOCK_MONOCTR_LCK 0x00000010
+#define LP_LOCK_CALIB_LCK 0x00000008
+#define LP_LOCK_SRTC_LCK 0x00000004
+#define LP_LOCK_ZMK_RD_LCK 0x00000002
+#define LP_LOCK_ZMK_WT_LCK 0x00000001
+
+#define LP_CTL_CAL_VAL_SHIFT 10
+#define LP_CTL_CAL_VAL_MASK (0x1f << LP_CTL_CAL_VAL_SHIFT)
+#define LP_CTL_CALIB_EN 0x00000100
+#define LP_CTL_SRTC_INVAL_EN 0x00000010
+#define LP_CTL_WAKE_INT_EN 0x00000008
+#define LP_CTL_MONOCTR_EN 0x00000004
+#define LP_CTL_TIMEALARM_EN 0x00000002
+#define LP_CTL_SRTC_EN 0x00000001
+
+#define LP_MKEYCTL_ZMKECC_SHIFT 8
+#define LP_MKEYCTL_ZMKECC_MASK (0xff << LP_MKEYCTL_ZMKECC_SHIFT)
+#define LP_MKEYCTL_ZMKECC_EN 0x00000010
+#define LP_MKEYCTL_ZMKECC_VAL 0x00000008
+#define LP_MKEYCTL_ZMKECC_PROG 0x00000004
+#define LP_MKEYCTL_MKSEL_SHIFT 0
+#define LP_MKEYCTL_MKSEL_MASK (3 << LP_MKEYCTL_MKSEL_SHIFT)
+#define LP_MKEYCTL_MK_OTP 0
+#define LP_MKEYCTL_MK_ZMK 2
+#define LP_MKEYCTL_MK_COMB 3
+
+#define LP_SECVIO_CTL_SRC5 0x20
+#define LP_SECVIO_CTL_SRC4 0x10
+#define LP_SECVIO_CTL_SRC3 0x08
+#define LP_SECVIO_CTL_SRC2 0x04
+#define LP_SECVIO_CTL_SRC1 0x02
+#define LP_SECVIO_CTL_SRC0 0x01
+
+#define LP_TAMPFILT_EXT2_EN 0x80000000
+#define LP_TAMPFILT_EXT2_SHIFT 24
+#define LP_TAMPFILT_EXT2_MASK (0x1f << LP_TAMPFILT_EXT2_SHIFT)
+#define LP_TAMPFILT_EXT1_EN 0x00800000
+#define LP_TAMPFILT_EXT1_SHIFT 16
+#define LP_TAMPFILT_EXT1_MASK (0x1f << LP_TAMPFILT_EXT1_SHIFT)
+#define LP_TAMPFILT_WM_EN 0x00000080
+#define LP_TAMPFILT_WM_SHIFT 0
+#define LP_TAMPFILT_WM_MASK (0x1f << LP_TAMPFILT_WM_SHIFT)
+
+#define LP_TAMPDET_OSC_BPS 0x10000000
+#define LP_TAMPDET_VRC_SHIFT 24
+#define LP_TAMPDET_VRC_MASK (3 << LP_TAMPFILT_VRC_SHIFT)
+#define LP_TAMPDET_HTDC_SHIFT 20
+#define LP_TAMPDET_HTDC_MASK (3 << LP_TAMPFILT_HTDC_SHIFT)
+#define LP_TAMPDET_LTDC_SHIFT 16
+#define LP_TAMPDET_LTDC_MASK (3 << LP_TAMPFILT_LTDC_SHIFT)
+#define LP_TAMPDET_POR_OBS 0x00008000
+#define LP_TAMPDET_PFD_OBS 0x00004000
+#define LP_TAMPDET_ET2_EN 0x00000400
+#define LP_TAMPDET_ET1_EN 0x00000200
+#define LP_TAMPDET_WMT2_EN 0x00000100
+#define LP_TAMPDET_WMT1_EN 0x00000080
+#define LP_TAMPDET_VT_EN 0x00000040
+#define LP_TAMPDET_TT_EN 0x00000020
+#define LP_TAMPDET_CT_EN 0x00000010
+#define LP_TAMPDET_MCR_EN 0x00000004
+#define LP_TAMPDET_SRTCR_EN 0x00000002
+
+#define LP_STATUS_SECURE
+#define LP_STATUS_NONSECURE
+#define LP_STATUS_SCANEXIT 0x00100000 /* all write 1 clear here on */
+#define LP_STATUS_EXT_SECVIO 0x00010000
+#define LP_STATUS_ET2 0x00000400
+#define LP_STATUS_ET1 0x00000200
+#define LP_STATUS_WMT2 0x00000100
+#define LP_STATUS_WMT1 0x00000080
+#define LP_STATUS_VTD 0x00000040
+#define LP_STATUS_TTD 0x00000020
+#define LP_STATUS_CTD 0x00000010
+#define LP_STATUS_PGD 0x00000008
+#define LP_STATUS_MCR 0x00000004
+#define LP_STATUS_SRTCR 0x00000002
+#define LP_STATUS_LPTA 0x00000001
+
+/* Full SNVS register page, including version/options */
+struct snvs_full {
+ struct snvs_hp hp;
+ struct snvs_lp lp;
+ u32 rsvd[731]; /* deadspace 0x08c-0xbf7 */
+
+ /* Version / Revision / Option ID space - end of register page */
+ u32 vid; /* 0xbf8 HP Version ID (VID 1) */
+ u32 opt_rev; /* 0xbfc HP Options / Revision (VID 2) */
+};
+
+#endif /* SNVSREGS_H */
diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c
index 625ee50fd78b..093a99ce8c64 100644
--- a/drivers/crypto/mxs-dcp.c
+++ b/drivers/crypto/mxs-dcp.c
@@ -20,6 +20,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/stmp_device.h>
+#include <linux/clk.h>
#include <crypto/aes.h>
#include <crypto/sha.h>
@@ -28,9 +29,25 @@
#define DCP_MAX_CHANS 4
#define DCP_BUF_SZ PAGE_SIZE
+#define DCP_SHA_PAY_SZ 64
#define DCP_ALIGNMENT 64
+
+/*
+ * Null hashes to align with hw behavior on imx6sl and ull
+ * these are flipped for consistency with hw output
+ */
+const uint8_t sha1_null_hash[] =
+ "\x09\x07\xd8\xaf\x90\x18\x60\x95\xef\xbf"
+ "\x55\x32\x0d\x4b\x6b\x5e\xee\xa3\x39\xda";
+
+const uint8_t sha256_null_hash[] =
+ "\x55\xb8\x52\x78\x1b\x99\x95\xa4"
+ "\x4c\x93\x9b\x64\xe4\x41\xae\x27"
+ "\x24\xb9\x6f\x99\xc8\xf4\xfb\x9a"
+ "\x14\x1c\xfc\x98\x42\xc4\xb0\xe3";
+
/* DCP DMA descriptor. */
struct dcp_dma_desc {
uint32_t next_cmd_addr;
@@ -48,6 +65,7 @@ struct dcp_coherent_block {
uint8_t aes_in_buf[DCP_BUF_SZ];
uint8_t aes_out_buf[DCP_BUF_SZ];
uint8_t sha_in_buf[DCP_BUF_SZ];
+ uint8_t sha_out_buf[DCP_SHA_PAY_SZ];
uint8_t aes_key[2 * AES_KEYSIZE_128];
@@ -66,6 +84,10 @@ struct dcp {
struct mutex mutex[DCP_MAX_CHANS];
struct task_struct *thread[DCP_MAX_CHANS];
struct crypto_queue queue[DCP_MAX_CHANS];
+#ifdef CONFIG_ARM
+ struct clk *dcp_clk;
+#endif
+ int enable_sha_workaround;
};
enum dcp_chan {
@@ -99,6 +121,11 @@ struct dcp_sha_req_ctx {
unsigned int fini:1;
};
+struct dcp_export_state {
+ struct dcp_sha_req_ctx req_ctx;
+ struct dcp_async_ctx async_ctx;
+};
+
/*
* There can even be only one instance of the MXS DCP due to the
* design of Linux Crypto API.
@@ -209,6 +236,12 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,
dma_addr_t dst_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_out_buf,
DCP_BUF_SZ, DMA_FROM_DEVICE);
+ if (actx->fill % AES_BLOCK_SIZE) {
+ dev_err(sdcp->dev, "Invalid block size!\n");
+ ret = -EINVAL;
+ goto aes_done_run;
+ }
+
/* Fill in the DMA descriptor. */
desc->control0 = MXS_DCP_CONTROL0_DECR_SEMAPHORE |
MXS_DCP_CONTROL0_INTERRUPT |
@@ -238,6 +271,7 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx,
ret = mxs_dcp_start_dma(actx);
+aes_done_run:
dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128,
DMA_TO_DEVICE);
dma_unmap_single(sdcp->dev, src_phys, DCP_BUF_SZ, DMA_TO_DEVICE);
@@ -264,13 +298,15 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq)
uint8_t *out_tmp, *src_buf, *dst_buf = NULL;
uint32_t dst_off = 0;
+ uint32_t last_out_len = 0;
uint8_t *key = sdcp->coh->aes_key;
int ret = 0;
int split = 0;
- unsigned int i, len, clen, rem = 0;
+ unsigned int i, len, clen, rem = 0, tlen = 0;
int init = 0;
+ bool limit_hit = false;
actx->fill = 0;
@@ -289,6 +325,11 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq)
for_each_sg(req->src, src, nents, i) {
src_buf = sg_virt(src);
len = sg_dma_len(src);
+ tlen += len;
+ limit_hit = tlen > req->nbytes;
+
+ if (limit_hit)
+ len = req->nbytes - (tlen - len);
do {
if (actx->fill + len > out_off)
@@ -305,13 +346,15 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq)
* If we filled the buffer or this is the last SG,
* submit the buffer.
*/
- if (actx->fill == out_off || sg_is_last(src)) {
+ if (actx->fill == out_off || sg_is_last(src) ||
+ limit_hit) {
ret = mxs_dcp_run_aes(actx, req, init);
if (ret)
return ret;
init = 0;
out_tmp = out_buf;
+ last_out_len = actx->fill;
while (dst && actx->fill) {
if (!split) {
dst_buf = sg_virt(dst);
@@ -334,6 +377,13 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq)
}
}
} while (len);
+
+ if (limit_hit)
+ break;
+ }
+ if (last_out_len >= AES_BLOCK_SIZE) {
+ memcpy(req->info, out_buf+(last_out_len-AES_BLOCK_SIZE),
+ AES_BLOCK_SIZE);
}
return ret;
@@ -509,8 +559,6 @@ static int mxs_dcp_run_sha(struct ahash_request *req)
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm);
struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req);
- struct hash_alg_common *halg = crypto_hash_alg_common(tfm);
-
struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan];
dma_addr_t digest_phys = 0;
@@ -532,10 +580,24 @@ static int mxs_dcp_run_sha(struct ahash_request *req)
desc->payload = 0;
desc->status = 0;
+ /*
+ * Align driver with hw behavior when generating null hashes
+ */
+ if (rctx->init && rctx->fini && desc->size == 0 &&
+ sdcp->enable_sha_workaround) {
+ struct hash_alg_common *halg = crypto_hash_alg_common(tfm);
+ const uint8_t *sha_buf =
+ (actx->alg == MXS_DCP_CONTROL1_HASH_SELECT_SHA1) ?
+ sha1_null_hash : sha256_null_hash;
+ memcpy(sdcp->coh->sha_out_buf, sha_buf, halg->digestsize);
+ ret = 0;
+ goto done_run;
+ }
+
/* Set HASH_TERM bit for last transfer block. */
if (rctx->fini) {
- digest_phys = dma_map_single(sdcp->dev, req->result,
- halg->digestsize, DMA_FROM_DEVICE);
+ digest_phys = dma_map_single(sdcp->dev, sdcp->coh->sha_out_buf,
+ DCP_SHA_PAY_SZ, DMA_FROM_DEVICE);
desc->control0 |= MXS_DCP_CONTROL0_HASH_TERM;
desc->payload = digest_phys;
}
@@ -543,9 +605,10 @@ static int mxs_dcp_run_sha(struct ahash_request *req)
ret = mxs_dcp_start_dma(actx);
if (rctx->fini)
- dma_unmap_single(sdcp->dev, digest_phys, halg->digestsize,
+ dma_unmap_single(sdcp->dev, digest_phys, DCP_SHA_PAY_SZ,
DMA_FROM_DEVICE);
+done_run:
dma_unmap_single(sdcp->dev, buf_phys, DCP_BUF_SZ, DMA_TO_DEVICE);
return ret;
@@ -563,6 +626,7 @@ static int dcp_sha_req_to_buf(struct crypto_async_request *arq)
const int nents = sg_nents(req->src);
uint8_t *in_buf = sdcp->coh->sha_in_buf;
+ uint8_t *out_buf = sdcp->coh->sha_out_buf;
uint8_t *src_buf;
@@ -617,11 +681,9 @@ static int dcp_sha_req_to_buf(struct crypto_async_request *arq)
actx->fill = 0;
- /* For some reason, the result is flipped. */
- for (i = 0; i < halg->digestsize / 2; i++) {
- swap(req->result[i],
- req->result[halg->digestsize - i - 1]);
- }
+ /* For some reason the result is flipped */
+ for (i = 0; i < halg->digestsize; i++)
+ req->result[i] = out_buf[halg->digestsize - i - 1];
}
return 0;
@@ -748,6 +810,35 @@ static int dcp_sha_finup(struct ahash_request *req)
return dcp_sha_update_fx(req, 1);
}
+static int dcp_sha_export(struct ahash_request *req, void *out)
+{
+ struct dcp_sha_req_ctx *rctx_state = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct dcp_async_ctx *actx_state = crypto_ahash_ctx(tfm);
+ struct dcp_export_state *export = out;
+
+ memcpy(&export->req_ctx, rctx_state, sizeof(struct dcp_sha_req_ctx));
+ memcpy(&export->async_ctx, actx_state, sizeof(struct dcp_async_ctx));
+
+ return 0;
+}
+
+static int dcp_sha_import(struct ahash_request *req, const void *in)
+{
+ struct dcp_sha_req_ctx *rctx = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct dcp_async_ctx *actx = crypto_ahash_ctx(tfm);
+ const struct dcp_export_state *export = in;
+
+ memset(rctx, 0, sizeof(struct dcp_sha_req_ctx));
+ memset(actx, 0, sizeof(struct dcp_async_ctx));
+
+ memcpy(rctx, &export->req_ctx, sizeof(struct dcp_sha_req_ctx));
+ memcpy(actx, &export->async_ctx, sizeof(struct dcp_async_ctx));
+
+ return 0;
+}
+
static int dcp_sha_digest(struct ahash_request *req)
{
int ret;
@@ -829,8 +920,11 @@ static struct ahash_alg dcp_sha1_alg = {
.final = dcp_sha_final,
.finup = dcp_sha_finup,
.digest = dcp_sha_digest,
+ .export = dcp_sha_export,
+ .import = dcp_sha_import,
.halg = {
.digestsize = SHA1_DIGEST_SIZE,
+ .statesize = sizeof(struct dcp_export_state),
.base = {
.cra_name = "sha1",
.cra_driver_name = "sha1-dcp",
@@ -853,8 +947,11 @@ static struct ahash_alg dcp_sha256_alg = {
.final = dcp_sha_final,
.finup = dcp_sha_finup,
.digest = dcp_sha_digest,
+ .export = dcp_sha_export,
+ .import = dcp_sha_import,
.halg = {
.digestsize = SHA256_DIGEST_SIZE,
+ .statesize = sizeof(struct dcp_export_state),
.base = {
.cra_name = "sha256",
.cra_driver_name = "sha256-dcp",
@@ -924,6 +1021,26 @@ static int mxs_dcp_probe(struct platform_device *pdev)
if (IS_ERR(sdcp->base))
return PTR_ERR(sdcp->base);
+#ifdef CONFIG_ARM
+ sdcp->dcp_clk = devm_clk_get(dev, "dcp");
+
+ if (IS_ERR(sdcp->dcp_clk)) {
+ ret = PTR_ERR(sdcp->dcp_clk);
+ dev_err(dev, "can't identify DCP clk: %d\n", ret);
+ return -ENODEV;
+ }
+
+ ret = clk_prepare(sdcp->dcp_clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "can't prepare DCP clock: %d\n", ret);
+ return -ENODEV;
+ }
+ ret = clk_enable(sdcp->dcp_clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "can't enable DCP clock: %d\n", ret);
+ return -ENODEV;
+ }
+#endif
ret = devm_request_irq(dev, dcp_vmi_irq, mxs_dcp_irq, 0,
"dcp-vmi-irq", sdcp);
@@ -984,6 +1101,11 @@ static int mxs_dcp_probe(struct platform_device *pdev)
crypto_init_queue(&sdcp->queue[i], 50);
}
+ /*
+ * Enable driver alignment with hw behavior for sha generation
+ */
+ sdcp->enable_sha_workaround = 1;
+
/* Create the SHA and AES handler threads. */
sdcp->thread[DCP_CHAN_HASH_SHA] = kthread_run(dcp_chan_thread_sha,
NULL, "mxs_dcp_chan/sha");
@@ -1065,6 +1187,11 @@ static int mxs_dcp_remove(struct platform_device *pdev)
kthread_stop(sdcp->thread[DCP_CHAN_HASH_SHA]);
kthread_stop(sdcp->thread[DCP_CHAN_CRYPTO]);
+#ifdef CONFIG_ARM
+ /* shut clocks off before finalizing shutdown */
+ clk_disable(sdcp->dcp_clk);
+#endif
+
platform_set_drvdata(pdev, NULL);
global_sdcp = NULL;
@@ -1075,6 +1202,7 @@ static int mxs_dcp_remove(struct platform_device *pdev)
static const struct of_device_id mxs_dcp_dt_ids[] = {
{ .compatible = "fsl,imx23-dcp", .data = NULL, },
{ .compatible = "fsl,imx28-dcp", .data = NULL, },
+ { .compatible = "fsl,imx6sl-dcp", .data = NULL, },
{ /* sentinel */ }
};
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 141aefbe37ec..2e476accd3ba 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -192,6 +192,18 @@ config FSL_EDMA
multiplexing capability for DMA request sources(slot).
This module can be found on Freescale Vybrid and LS-1 SoCs.
+config FSL_EDMA_V3
+ tristate "Freescale eDMA v3 engine support"
+ depends on OF
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+ help
+ Support the Freescale eDMA v3 engine with programmable channel.
+ This driver is based on FSL_EDMA but big changes come such as
+ different interrupt for different channel, different register
+ scope for different channel.
+ This module can be found on Freescale i.MX8QM.
+
config FSL_RAID
tristate "Freescale RAID engine Support"
depends on FSL_SOC && !ASYNC_TX_ENABLE_CHANNEL_SWITCH
@@ -222,8 +234,9 @@ config IMX_DMA
config IMX_SDMA
tristate "i.MX SDMA support"
- depends on ARCH_MXC
+ depends on ARCH_MXC || ARCH_FSL_IMX8MQ
select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
help
Support the i.MX SDMA engine. This engine is integrated into
Freescale i.MX25/31/35/51/53/6 chips.
@@ -354,13 +367,15 @@ config MV_XOR_V2
config MXS_DMA
bool "MXS DMA support"
- depends on SOC_IMX23 || SOC_IMX28 || SOC_IMX6Q || SOC_IMX6UL
+ depends on ARCH_MXS || ARCH_MXC || ARCH_MXC_ARM64 || COMPILE_TEST
select STMP_DEVICE
select DMA_ENGINE
help
Support the MXS DMA engine. This engine including APBH-DMA
and APBX-DMA is integrated into Freescale
- i.MX23/28/MX6Q/MX6DL/MX6UL chips.
+ i.MX23/28/MX6Q/MX6DL/MX6UL/MX7D/MX8 chips.
+
+source "drivers/dma/pxp/Kconfig"
config MX3_IPU
bool "MX3x Image Processing Unit support"
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index e4dc9cac7ee8..421430e9b9bc 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_DW_DMAC_CORE) += dw/
obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
obj-$(CONFIG_FSL_DMA) += fsldma.o
obj-$(CONFIG_FSL_EDMA) += fsl-edma.o
+obj-$(CONFIG_FSL_EDMA_V3) += fsl-edma-v3.o
obj-$(CONFIG_FSL_RAID) += fsl_raid.o
obj-$(CONFIG_HSU_DMA) += hsu/
obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o
@@ -53,6 +54,8 @@ obj-$(CONFIG_PCH_DMA) += pch_dma.o
obj-$(CONFIG_PL330_DMA) += pl330.o
obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
obj-$(CONFIG_PXA_DMA) += pxa_dma.o
+obj-$(CONFIG_MXC_PXP_V2) += pxp/
+obj-$(CONFIG_MXC_PXP_V3) += pxp/
obj-$(CONFIG_RENESAS_DMA) += sh/
obj-$(CONFIG_SIRF_DMA) += sirf-dma.o
obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
diff --git a/drivers/dma/fsl-edma-v3.c b/drivers/dma/fsl-edma-v3.c
new file mode 100644
index 000000000000..f74f46ad3fb1
--- /dev/null
+++ b/drivers/dma/fsl-edma-v3.c
@@ -0,0 +1,1083 @@
+/*
+ * drivers/dma/fsl-edma3-v3.c
+ *
+ * Copyright 2017-2018 NXP .
+ *
+ * Driver for the Freescale eDMA engine v3. This driver based on fsl-edma3.c
+ * but changed to meet the IP change on i.MX8QM: every dma channel is specific
+ * to hardware. For example, channel 14 for LPUART1 receive request and channel
+ * 13 for transmit requesst. The eDMA block can be found on i.MX8QM
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_dma.h>
+
+#include <soc/imx/revision.h>
+#include <soc/imx8/soc.h>
+
+#include "virt-dma.h"
+
+#define EDMA_CH_CSR 0x00
+#define EDMA_CH_ES 0x04
+#define EDMA_CH_INT 0x08
+#define EDMA_CH_SBR 0x0C
+#define EDMA_CH_PRI 0x10
+#define EDMA_TCD_SADDR 0x20
+#define EDMA_TCD_SOFF 0x24
+#define EDMA_TCD_ATTR 0x26
+#define EDMA_TCD_NBYTES 0x28
+#define EDMA_TCD_SLAST 0x2C
+#define EDMA_TCD_DADDR 0x30
+#define EDMA_TCD_DOFF 0x34
+#define EDMA_TCD_CITER_ELINK 0x36
+#define EDMA_TCD_CITER 0x36
+#define EDMA_TCD_DLAST_SGA 0x38
+#define EDMA_TCD_CSR 0x3C
+#define EDMA_TCD_BITER_ELINK 0x3E
+#define EDMA_TCD_BITER 0x3E
+
+#define EDMA_CH_SBR_RD BIT(22)
+#define EDMA_CH_SBR_WR BIT(21)
+#define EDMA_CH_CSR_ERQ BIT(0)
+#define EDMA_CH_CSR_EARQ BIT(1)
+#define EDMA_CH_CSR_EEI BIT(2)
+#define EDMA_CH_CSR_DONE BIT(30)
+#define EDMA_CH_CSR_ACTIVE BIT(31)
+
+#define EDMA_TCD_ATTR_DSIZE(x) (((x) & 0x0007))
+#define EDMA_TCD_ATTR_DMOD(x) (((x) & 0x001F) << 3)
+#define EDMA_TCD_ATTR_SSIZE(x) (((x) & 0x0007) << 8)
+#define EDMA_TCD_ATTR_SMOD(x) (((x) & 0x001F) << 11)
+#define EDMA_TCD_ATTR_SSIZE_8BIT (0x0000)
+#define EDMA_TCD_ATTR_SSIZE_16BIT (0x0100)
+#define EDMA_TCD_ATTR_SSIZE_32BIT (0x0200)
+#define EDMA_TCD_ATTR_SSIZE_64BIT (0x0300)
+#define EDMA_TCD_ATTR_SSIZE_16BYTE (0x0400)
+#define EDMA_TCD_ATTR_SSIZE_32BYTE (0x0500)
+#define EDMA_TCD_ATTR_SSIZE_64BYTE (0x0600)
+#define EDMA_TCD_ATTR_DSIZE_8BIT (0x0000)
+#define EDMA_TCD_ATTR_DSIZE_16BIT (0x0001)
+#define EDMA_TCD_ATTR_DSIZE_32BIT (0x0002)
+#define EDMA_TCD_ATTR_DSIZE_64BIT (0x0003)
+#define EDMA_TCD_ATTR_DSIZE_16BYTE (0x0004)
+#define EDMA_TCD_ATTR_DSIZE_32BYTE (0x0005)
+#define EDMA_TCD_ATTR_DSIZE_64BYTE (0x0006)
+
+#define EDMA_TCD_SOFF_SOFF(x) (x)
+#define EDMA_TCD_NBYTES_NBYTES(x) (x)
+#define EDMA_TCD_NBYTES_MLOFF(x) (x << 10)
+#define EDMA_TCD_NBYTES_DMLOE (1 << 30)
+#define EDMA_TCD_NBYTES_SMLOE (1 << 31)
+#define EDMA_TCD_SLAST_SLAST(x) (x)
+#define EDMA_TCD_DADDR_DADDR(x) (x)
+#define EDMA_TCD_CITER_CITER(x) ((x) & 0x7FFF)
+#define EDMA_TCD_DOFF_DOFF(x) (x)
+#define EDMA_TCD_DLAST_SGA_DLAST_SGA(x) (x)
+#define EDMA_TCD_BITER_BITER(x) ((x) & 0x7FFF)
+
+#define EDMA_TCD_CSR_START BIT(0)
+#define EDMA_TCD_CSR_INT_MAJOR BIT(1)
+#define EDMA_TCD_CSR_INT_HALF BIT(2)
+#define EDMA_TCD_CSR_D_REQ BIT(3)
+#define EDMA_TCD_CSR_E_SG BIT(4)
+#define EDMA_TCD_CSR_E_LINK BIT(5)
+#define EDMA_TCD_CSR_ACTIVE BIT(6)
+#define EDMA_TCD_CSR_DONE BIT(7)
+
+#define FSL_EDMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
+ BIT(DMA_SLAVE_BUSWIDTH_8_BYTES) | \
+ BIT(DMA_SLAVE_BUSWIDTH_16_BYTES))
+
+#define ARGS_RX BIT(0)
+#define ARGS_REMOTE BIT(1)
+#define ARGS_DFIFO BIT(2)
+
+/* channel name template define in dts */
+#define CHAN_PREFIX "edma0-chan"
+#define CHAN_POSFIX "-tx"
+
+enum fsl_edma3_pm_state {
+ RUNNING = 0,
+ SUSPENDED,
+};
+
+struct fsl_edma3_hw_tcd {
+ __le32 saddr;
+ __le16 soff;
+ __le16 attr;
+ __le32 nbytes;
+ __le32 slast;
+ __le32 daddr;
+ __le16 doff;
+ __le16 citer;
+ __le32 dlast_sga;
+ __le16 csr;
+ __le16 biter;
+};
+
+struct fsl_edma3_sw_tcd {
+ dma_addr_t ptcd;
+ struct fsl_edma3_hw_tcd *vtcd;
+};
+
+struct fsl_edma3_slave_config {
+ enum dma_transfer_direction dir;
+ enum dma_slave_buswidth addr_width;
+ u32 dev_addr;
+ u32 dev2_addr; /* source addr for dev2dev */
+ u32 burst;
+ u32 attr;
+};
+
+struct fsl_edma3_chan {
+ struct virt_dma_chan vchan;
+ enum dma_status status;
+ enum fsl_edma3_pm_state pm_state;
+ bool idle;
+ bool used;
+ struct fsl_edma3_engine *edma3;
+ struct fsl_edma3_desc *edesc;
+ struct fsl_edma3_slave_config fsc;
+ void __iomem *membase;
+ int txirq;
+ int hw_chanid;
+ int priority;
+ int is_rxchan;
+ int is_remote;
+ int is_dfifo;
+ struct dma_pool *tcd_pool;
+ u32 chn_real_count;
+ char txirq_name[32];
+};
+
+struct fsl_edma3_desc {
+ struct virt_dma_desc vdesc;
+ struct fsl_edma3_chan *echan;
+ bool iscyclic;
+ unsigned int n_tcds;
+ struct fsl_edma3_sw_tcd tcd[];
+};
+
+struct fsl_edma3_reg_save {
+ u32 csr;
+ u32 sbr;
+};
+
+struct fsl_edma3_engine {
+ struct dma_device dma_dev;
+ struct mutex fsl_edma3_mutex;
+ u32 n_chans;
+ int errirq;
+ #define MAX_CHAN_NUM 32
+ struct fsl_edma3_reg_save edma_regs[MAX_CHAN_NUM];
+ bool swap; /* remote/local swapped on Audio edma */
+ struct fsl_edma3_chan chans[];
+};
+
+static struct fsl_edma3_chan *to_fsl_edma3_chan(struct dma_chan *chan)
+{
+ return container_of(chan, struct fsl_edma3_chan, vchan.chan);
+}
+
+static struct fsl_edma3_desc *to_fsl_edma3_desc(struct virt_dma_desc *vd)
+{
+ return container_of(vd, struct fsl_edma3_desc, vdesc);
+}
+
+static void fsl_edma3_enable_request(struct fsl_edma3_chan *fsl_chan)
+{
+ void __iomem *addr = fsl_chan->membase;
+ u32 val;
+
+ val = readl(addr + EDMA_CH_SBR);
+ /* Remote/local swapped wrongly on iMX8 QM Audio edma */
+ if (fsl_chan->edma3->swap) {
+ if (!fsl_chan->is_rxchan)
+ val |= EDMA_CH_SBR_RD;
+ else
+ val |= EDMA_CH_SBR_WR;
+ } else {
+ if (fsl_chan->is_rxchan)
+ val |= EDMA_CH_SBR_RD;
+ else
+ val |= EDMA_CH_SBR_WR;
+ }
+
+ if (fsl_chan->is_remote)
+ val &= ~(EDMA_CH_SBR_RD | EDMA_CH_SBR_WR);
+
+ writel(val, addr + EDMA_CH_SBR);
+
+ val = readl(addr + EDMA_CH_CSR);
+
+ val |= EDMA_CH_CSR_ERQ;
+ writel(val, addr + EDMA_CH_CSR);
+
+ fsl_chan->used = true;
+}
+
+static void fsl_edma3_disable_request(struct fsl_edma3_chan *fsl_chan)
+{
+ void __iomem *addr = fsl_chan->membase;
+ u32 val = readl(addr + EDMA_CH_CSR);
+
+ val &= ~EDMA_CH_CSR_ERQ;
+ writel(val, addr + EDMA_CH_CSR);
+}
+
+static unsigned int fsl_edma3_get_tcd_attr(enum dma_slave_buswidth addr_width)
+{
+ switch (addr_width) {
+ case 1:
+ return EDMA_TCD_ATTR_SSIZE_8BIT | EDMA_TCD_ATTR_DSIZE_8BIT;
+ case 2:
+ return EDMA_TCD_ATTR_SSIZE_16BIT | EDMA_TCD_ATTR_DSIZE_16BIT;
+ case 4:
+ return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
+ case 8:
+ return EDMA_TCD_ATTR_SSIZE_64BIT | EDMA_TCD_ATTR_DSIZE_64BIT;
+ case 16:
+ return EDMA_TCD_ATTR_SSIZE_16BYTE | EDMA_TCD_ATTR_DSIZE_16BYTE;
+ case 32:
+ return EDMA_TCD_ATTR_SSIZE_32BYTE | EDMA_TCD_ATTR_DSIZE_32BYTE;
+ case 64:
+ return EDMA_TCD_ATTR_SSIZE_64BYTE | EDMA_TCD_ATTR_DSIZE_64BYTE;
+ default:
+ return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
+ }
+}
+
+static void fsl_edma3_free_desc(struct virt_dma_desc *vdesc)
+{
+ struct fsl_edma3_desc *fsl_desc;
+ int i;
+
+ fsl_desc = to_fsl_edma3_desc(vdesc);
+ for (i = 0; i < fsl_desc->n_tcds; i++)
+ dma_pool_free(fsl_desc->echan->tcd_pool, fsl_desc->tcd[i].vtcd,
+ fsl_desc->tcd[i].ptcd);
+ kfree(fsl_desc);
+}
+
+static int fsl_edma3_terminate_all(struct dma_chan *chan)
+{
+ struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
+ unsigned long flags;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ fsl_edma3_disable_request(fsl_chan);
+ fsl_chan->edesc = NULL;
+ fsl_chan->idle = true;
+ fsl_chan->used = false;
+ vchan_get_all_descriptors(&fsl_chan->vchan, &head);
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+ vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
+ return 0;
+}
+
+static int fsl_edma3_pause(struct dma_chan *chan)
+{
+ struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ if (fsl_chan->edesc) {
+ fsl_edma3_disable_request(fsl_chan);
+ fsl_chan->status = DMA_PAUSED;
+ fsl_chan->idle = true;
+ }
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+ return 0;
+}
+
+static int fsl_edma3_resume(struct dma_chan *chan)
+{
+ struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ if (fsl_chan->edesc) {
+ fsl_edma3_enable_request(fsl_chan);
+ fsl_chan->status = DMA_IN_PROGRESS;
+ fsl_chan->idle = false;
+ }
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+ return 0;
+}
+
+static int fsl_edma3_slave_config(struct dma_chan *chan,
+ struct dma_slave_config *cfg)
+{
+ struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
+
+ fsl_chan->fsc.dir = cfg->direction;
+ if (cfg->direction == DMA_DEV_TO_MEM) {
+ fsl_chan->fsc.dev_addr = cfg->src_addr;
+ fsl_chan->fsc.addr_width = cfg->src_addr_width;
+ fsl_chan->fsc.burst = cfg->src_maxburst;
+ fsl_chan->fsc.attr = fsl_edma3_get_tcd_attr
+ (cfg->src_addr_width);
+ } else if (cfg->direction == DMA_MEM_TO_DEV) {
+ fsl_chan->fsc.dev_addr = cfg->dst_addr;
+ fsl_chan->fsc.addr_width = cfg->dst_addr_width;
+ fsl_chan->fsc.burst = cfg->dst_maxburst;
+ fsl_chan->fsc.attr = fsl_edma3_get_tcd_attr
+ (cfg->dst_addr_width);
+ } else if (cfg->direction == DMA_DEV_TO_DEV) {
+ fsl_chan->fsc.dev2_addr = cfg->src_addr;
+ fsl_chan->fsc.dev_addr = cfg->dst_addr;
+ fsl_chan->fsc.addr_width = cfg->dst_addr_width;
+ fsl_chan->fsc.burst = cfg->dst_maxburst;
+ fsl_chan->fsc.attr = fsl_edma3_get_tcd_attr
+ (cfg->dst_addr_width);
+ } else {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static size_t fsl_edma3_desc_residue(struct fsl_edma3_chan *fsl_chan,
+ struct virt_dma_desc *vdesc, bool in_progress)
+{
+ struct fsl_edma3_desc *edesc = fsl_chan->edesc;
+ void __iomem *addr = fsl_chan->membase;
+ enum dma_transfer_direction dir = fsl_chan->fsc.dir;
+ dma_addr_t cur_addr, dma_addr;
+ size_t len, size;
+ int i;
+
+ /* calculate the total size in this desc */
+ for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++)
+ len += le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
+ * le16_to_cpu(edesc->tcd[i].vtcd->biter);
+
+ if (!in_progress)
+ return len;
+
+ if (dir == DMA_MEM_TO_DEV)
+ cur_addr = readl(addr + EDMA_TCD_SADDR);
+ else
+ cur_addr = readl(addr + EDMA_TCD_DADDR);
+
+ /* figure out the finished and calculate the residue */
+ for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
+ size = le32_to_cpu(edesc->tcd[i].vtcd->nbytes)
+ * le16_to_cpu(edesc->tcd[i].vtcd->biter);
+ if (dir == DMA_MEM_TO_DEV)
+ dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->saddr);
+ else
+ dma_addr = le32_to_cpu(edesc->tcd[i].vtcd->daddr);
+
+ len -= size;
+ if (cur_addr >= dma_addr && cur_addr < dma_addr + size) {
+ len += dma_addr + size - cur_addr;
+ break;
+ }
+ }
+
+ return len;
+}
+
+static enum dma_status fsl_edma3_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+ struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
+ struct virt_dma_desc *vdesc;
+ enum dma_status status;
+ unsigned long flags;
+
+ status = dma_cookie_status(chan, cookie, txstate);
+ if (status == DMA_COMPLETE) {
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ txstate->residue = fsl_chan->chn_real_count;
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+ return status;
+ }
+
+ if (!txstate)
+ return fsl_chan->status;
+
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ vdesc = vchan_find_desc(&fsl_chan->vchan, cookie);
+ if (fsl_chan->edesc && cookie == fsl_chan->edesc->vdesc.tx.cookie)
+ txstate->residue = fsl_edma3_desc_residue(fsl_chan, vdesc,
+ true);
+ else if (vdesc)
+ txstate->residue = fsl_edma3_desc_residue(fsl_chan, vdesc,
+ false);
+ else
+ txstate->residue = 0;
+
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+
+ return fsl_chan->status;
+}
+
+static void fsl_edma3_set_tcd_regs(struct fsl_edma3_chan *fsl_chan,
+ struct fsl_edma3_hw_tcd *tcd)
+{
+ void __iomem *addr = fsl_chan->membase;
+ /*
+ * TCD parameters are stored in struct fsl_edma3_hw_tcd in little
+ * endian format. However, we need to load the TCD registers in
+ * big- or little-endian obeying the eDMA engine model endian.
+ */
+ writew(0, addr + EDMA_TCD_CSR);
+ writel(le32_to_cpu(tcd->saddr), addr + EDMA_TCD_SADDR);
+ writel(le32_to_cpu(tcd->daddr), addr + EDMA_TCD_DADDR);
+
+ writew(le16_to_cpu(tcd->attr), addr + EDMA_TCD_ATTR);
+ writew(le16_to_cpu(tcd->soff), addr + EDMA_TCD_SOFF);
+
+ writel(le32_to_cpu(tcd->nbytes), addr + EDMA_TCD_NBYTES);
+ writel(le32_to_cpu(tcd->slast), addr + EDMA_TCD_SLAST);
+
+ writew(le16_to_cpu(tcd->citer), addr + EDMA_TCD_CITER);
+ writew(le16_to_cpu(tcd->biter), addr + EDMA_TCD_BITER);
+ writew(le16_to_cpu(tcd->doff), addr + EDMA_TCD_DOFF);
+
+ writel(le32_to_cpu(tcd->dlast_sga), addr + EDMA_TCD_DLAST_SGA);
+
+ /* Must clear CHa_CSR[DONE] bit before enable TCDa_CSR[ESG] */
+ writel(readl(addr + EDMA_CH_CSR), addr + EDMA_CH_CSR);
+
+ writew(le16_to_cpu(tcd->csr), addr + EDMA_TCD_CSR);
+}
+
+static inline
+void fsl_edma3_fill_tcd(struct fsl_edma3_chan *fsl_chan,
+ struct fsl_edma3_hw_tcd *tcd, u32 src, u32 dst,
+ u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer,
+ u16 biter, u16 doff, u32 dlast_sga, bool major_int,
+ bool disable_req, bool enable_sg)
+{
+ u16 csr = 0;
+
+ /*
+ * eDMA hardware SGs require the TCDs to be stored in little
+ * endian format irrespective of the register endian model.
+ * So we put the value in little endian in memory, waiting
+ * for fsl_edma3_set_tcd_regs doing the swap.
+ */
+ tcd->saddr = cpu_to_le32(src);
+ tcd->daddr = cpu_to_le32(dst);
+
+ tcd->attr = cpu_to_le16(attr);
+
+ tcd->soff = cpu_to_le16(EDMA_TCD_SOFF_SOFF(soff));
+
+ if (fsl_chan->is_dfifo) {
+ /* set mloff as -8 */
+ nbytes |= EDMA_TCD_NBYTES_MLOFF(-8);
+ /* enable DMLOE/SMLOE */
+ if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
+ nbytes |= EDMA_TCD_NBYTES_DMLOE;
+ nbytes &= ~EDMA_TCD_NBYTES_SMLOE;
+ } else {
+ nbytes |= EDMA_TCD_NBYTES_SMLOE;
+ nbytes &= ~EDMA_TCD_NBYTES_DMLOE;
+ }
+ }
+
+ tcd->nbytes = cpu_to_le32(EDMA_TCD_NBYTES_NBYTES(nbytes));
+ tcd->slast = cpu_to_le32(EDMA_TCD_SLAST_SLAST(slast));
+
+ tcd->citer = cpu_to_le16(EDMA_TCD_CITER_CITER(citer));
+ tcd->doff = cpu_to_le16(EDMA_TCD_DOFF_DOFF(doff));
+
+ tcd->dlast_sga = cpu_to_le32(EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga));
+
+ tcd->biter = cpu_to_le16(EDMA_TCD_BITER_BITER(biter));
+ if (major_int)
+ csr |= EDMA_TCD_CSR_INT_MAJOR;
+
+ if (disable_req)
+ csr |= EDMA_TCD_CSR_D_REQ;
+
+ if (enable_sg)
+ csr |= EDMA_TCD_CSR_E_SG;
+
+ if (fsl_chan->is_rxchan)
+ csr |= EDMA_TCD_CSR_ACTIVE;
+
+ tcd->csr = cpu_to_le16(csr);
+}
+
+static struct fsl_edma3_desc *fsl_edma3_alloc_desc(struct fsl_edma3_chan
+ *fsl_chan, int sg_len)
+{
+ struct fsl_edma3_desc *fsl_desc;
+ int i;
+
+ fsl_desc = kzalloc(sizeof(*fsl_desc) + sizeof(struct fsl_edma3_sw_tcd)
+ * sg_len, GFP_ATOMIC);
+ if (!fsl_desc)
+ return NULL;
+
+ fsl_desc->echan = fsl_chan;
+ fsl_desc->n_tcds = sg_len;
+ for (i = 0; i < sg_len; i++) {
+ fsl_desc->tcd[i].vtcd = dma_pool_alloc(fsl_chan->tcd_pool,
+ GFP_ATOMIC, &fsl_desc->tcd[i].ptcd);
+ if (!fsl_desc->tcd[i].vtcd)
+ goto err;
+ }
+ return fsl_desc;
+
+err:
+ while (--i >= 0)
+ dma_pool_free(fsl_chan->tcd_pool, fsl_desc->tcd[i].vtcd,
+ fsl_desc->tcd[i].ptcd);
+ kfree(fsl_desc);
+ return NULL;
+}
+
+static struct dma_async_tx_descriptor *fsl_edma3_prep_dma_cyclic(
+ struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+ size_t period_len, enum dma_transfer_direction direction,
+ unsigned long flags)
+{
+ struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
+ struct fsl_edma3_desc *fsl_desc;
+ dma_addr_t dma_buf_next;
+ int sg_len, i;
+ u32 src_addr, dst_addr, last_sg, nbytes;
+ u16 soff, doff, iter;
+
+ sg_len = buf_len / period_len;
+ fsl_desc = fsl_edma3_alloc_desc(fsl_chan, sg_len);
+ if (!fsl_desc)
+ return NULL;
+ fsl_desc->iscyclic = true;
+
+ dma_buf_next = dma_addr;
+ nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
+ iter = period_len / nbytes;
+
+ for (i = 0; i < sg_len; i++) {
+ if (dma_buf_next >= dma_addr + buf_len)
+ dma_buf_next = dma_addr;
+
+ /* get next sg's physical address */
+ last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
+
+ if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
+ src_addr = dma_buf_next;
+ dst_addr = fsl_chan->fsc.dev_addr;
+ soff = fsl_chan->fsc.addr_width;
+ if (fsl_chan->is_dfifo)
+ doff = 4;
+ else
+ doff = 0;
+ } else if (fsl_chan->fsc.dir == DMA_DEV_TO_MEM) {
+ src_addr = fsl_chan->fsc.dev_addr;
+ dst_addr = dma_buf_next;
+ if (fsl_chan->is_dfifo)
+ soff = 4;
+ else
+ soff = 0;
+ doff = fsl_chan->fsc.addr_width;
+ } else {
+ /* DMA_DEV_TO_DEV */
+ src_addr = fsl_chan->fsc.dev2_addr;
+ dst_addr = fsl_chan->fsc.dev_addr;
+ soff = 0;
+ doff = 0;
+ }
+
+ fsl_edma3_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd, src_addr,
+ dst_addr, fsl_chan->fsc.attr, soff, nbytes, 0,
+ iter, iter, doff, last_sg, true, false, true);
+ dma_buf_next += period_len;
+ }
+
+ return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
+}
+
+static struct dma_async_tx_descriptor *fsl_edma3_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 fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
+ struct fsl_edma3_desc *fsl_desc;
+ struct scatterlist *sg;
+ u32 src_addr, dst_addr, last_sg, nbytes;
+ u16 soff, doff, iter;
+ int i;
+
+ if (!is_slave_direction(fsl_chan->fsc.dir))
+ return NULL;
+
+ fsl_desc = fsl_edma3_alloc_desc(fsl_chan, sg_len);
+ if (!fsl_desc)
+ return NULL;
+ fsl_desc->iscyclic = false;
+
+ nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
+ for_each_sg(sgl, sg, sg_len, i) {
+ /* get next sg's physical address */
+ last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
+
+ if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
+ src_addr = sg_dma_address(sg);
+ dst_addr = fsl_chan->fsc.dev_addr;
+ soff = fsl_chan->fsc.addr_width;
+ doff = 0;
+ } else if (fsl_chan->fsc.dir == DMA_DEV_TO_MEM) {
+ src_addr = fsl_chan->fsc.dev_addr;
+ dst_addr = sg_dma_address(sg);
+ soff = 0;
+ doff = fsl_chan->fsc.addr_width;
+ } else {
+ /* DMA_DEV_TO_DEV */
+ src_addr = fsl_chan->fsc.dev2_addr;
+ dst_addr = fsl_chan->fsc.dev_addr;
+ soff = 0;
+ doff = 0;
+ }
+
+ iter = sg_dma_len(sg) / nbytes;
+ if (i < sg_len - 1) {
+ last_sg = fsl_desc->tcd[(i + 1)].ptcd;
+ fsl_edma3_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd,
+ src_addr, dst_addr, fsl_chan->fsc.attr,
+ soff, nbytes, 0, iter, iter, doff,
+ last_sg, false, false, true);
+ } else {
+ last_sg = 0;
+ fsl_edma3_fill_tcd(fsl_chan, fsl_desc->tcd[i].vtcd,
+ src_addr, dst_addr, fsl_chan->fsc.attr,
+ soff, nbytes, 0, iter, iter, doff,
+ last_sg, true, true, false);
+ }
+ }
+
+ return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
+}
+
+static void fsl_edma3_xfer_desc(struct fsl_edma3_chan *fsl_chan)
+{
+ struct virt_dma_desc *vdesc;
+
+ vdesc = vchan_next_desc(&fsl_chan->vchan);
+ if (!vdesc)
+ return;
+ fsl_chan->edesc = to_fsl_edma3_desc(vdesc);
+ fsl_edma3_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
+ fsl_edma3_enable_request(fsl_chan);
+ fsl_chan->status = DMA_IN_PROGRESS;
+ fsl_chan->idle = false;
+}
+
+static size_t fsl_edma3_desc_residue(struct fsl_edma3_chan *fsl_chan,
+ struct virt_dma_desc *vdesc, bool in_progress);
+
+static void fsl_edma3_get_realcnt(struct fsl_edma3_chan *fsl_chan)
+{
+ fsl_chan->chn_real_count = fsl_edma3_desc_residue(fsl_chan, NULL, true);
+}
+
+static irqreturn_t fsl_edma3_tx_handler(int irq, void *dev_id)
+{
+ struct fsl_edma3_chan *fsl_chan = dev_id;
+ unsigned int intr;
+ void __iomem *base_addr;
+
+ base_addr = fsl_chan->membase;
+
+ intr = readl(base_addr + EDMA_CH_INT);
+ if (!intr)
+ return IRQ_NONE;
+
+ writel(1, base_addr + EDMA_CH_INT);
+
+ spin_lock(&fsl_chan->vchan.lock);
+
+ /* Ignore this interrupt since channel has been disabled already */
+ if (!fsl_chan->edesc)
+ goto irq_handled;
+
+ if (!fsl_chan->edesc->iscyclic) {
+ fsl_edma3_get_realcnt(fsl_chan);
+ list_del(&fsl_chan->edesc->vdesc.node);
+ vchan_cookie_complete(&fsl_chan->edesc->vdesc);
+ fsl_chan->edesc = NULL;
+ fsl_chan->status = DMA_COMPLETE;
+ fsl_chan->idle = true;
+ } else {
+ vchan_cyclic_callback(&fsl_chan->edesc->vdesc);
+ }
+
+ if (!fsl_chan->edesc)
+ fsl_edma3_xfer_desc(fsl_chan);
+irq_handled:
+ spin_unlock(&fsl_chan->vchan.lock);
+
+ return IRQ_HANDLED;
+}
+
+static void fsl_edma3_issue_pending(struct dma_chan *chan)
+{
+ struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+
+ if (unlikely(fsl_chan->pm_state != RUNNING)) {
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+ /* cannot submit due to suspend */
+ return;
+ }
+
+ if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc)
+ fsl_edma3_xfer_desc(fsl_chan);
+
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+}
+
+static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct fsl_edma3_engine *fsl_edma3 = ofdma->of_dma_data;
+ struct dma_chan *chan, *_chan;
+ struct fsl_edma3_chan *fsl_chan;
+
+ if (dma_spec->args_count != 3)
+ return NULL;
+
+ mutex_lock(&fsl_edma3->fsl_edma3_mutex);
+ list_for_each_entry_safe(chan, _chan, &fsl_edma3->dma_dev.channels,
+ device_node) {
+ if (chan->client_count)
+ continue;
+
+ fsl_chan = to_fsl_edma3_chan(chan);
+ if (fsl_chan->hw_chanid == dma_spec->args[0]) {
+ chan = dma_get_slave_channel(chan);
+ chan->device->privatecnt++;
+ fsl_chan->priority = dma_spec->args[1];
+ fsl_chan->is_rxchan = dma_spec->args[2] & ARGS_RX;
+ fsl_chan->is_remote = dma_spec->args[2] & ARGS_REMOTE;
+ fsl_chan->is_dfifo = dma_spec->args[2] & ARGS_DFIFO;
+ mutex_unlock(&fsl_edma3->fsl_edma3_mutex);
+ return chan;
+ }
+ }
+ mutex_unlock(&fsl_edma3->fsl_edma3_mutex);
+ return NULL;
+}
+
+static int fsl_edma3_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
+
+ fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
+ sizeof(struct fsl_edma3_hw_tcd),
+ 32, 0);
+ return 0;
+}
+
+static void fsl_edma3_free_chan_resources(struct dma_chan *chan)
+{
+ struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
+ unsigned long flags;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ fsl_edma3_disable_request(fsl_chan);
+ fsl_chan->edesc = NULL;
+ vchan_get_all_descriptors(&fsl_chan->vchan, &head);
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+
+ vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
+ dma_pool_destroy(fsl_chan->tcd_pool);
+ fsl_chan->tcd_pool = NULL;
+ fsl_chan->used = false;
+}
+
+static void fsl_edma3_synchronize(struct dma_chan *chan)
+{
+ struct fsl_edma3_chan *fsl_chan = to_fsl_edma3_chan(chan);
+
+ vchan_synchronize(&fsl_chan->vchan);
+}
+
+static int fsl_edma3_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct fsl_edma3_engine *fsl_edma3;
+ struct fsl_edma3_chan *fsl_chan;
+ struct resource *res;
+ int len, chans;
+ int ret, i;
+ unsigned long irqflag = 0;
+
+ ret = of_property_read_u32(np, "dma-channels", &chans);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't get dma-channels.\n");
+ return ret;
+ }
+
+ len = sizeof(*fsl_edma3) + sizeof(*fsl_chan) * chans;
+ fsl_edma3 = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
+ if (!fsl_edma3)
+ return -ENOMEM;
+
+ /* Audio edma rx/tx channel shared interrupt */
+ if (of_property_read_bool(np, "shared-interrupt"))
+ irqflag = IRQF_SHARED;
+
+ fsl_edma3->swap = false;
+ fsl_edma3->n_chans = chans;
+
+ /*
+ * FIXUP: if this is the i.MX8QM TO1.0, need set the swap.
+ * FIXME: This will be revisted to set the swap property
+ * from the device-tree node later instead of revison check,
+ * but, this will need add extra DT file, not perfect too.
+ */
+
+ if ((of_device_is_compatible(np, "fsl,imx8qm-adma")) &&
+ cpu_is_imx8qm() &&
+ imx8_get_soc_revision() == IMX_CHIP_REVISION_1_0)
+ fsl_edma3->swap = true;
+
+ INIT_LIST_HEAD(&fsl_edma3->dma_dev.channels);
+ for (i = 0; i < fsl_edma3->n_chans; i++) {
+ struct fsl_edma3_chan *fsl_chan = &fsl_edma3->chans[i];
+ const char *txirq_name = fsl_chan->txirq_name;
+ char chanid[3], id_len = 0;
+ char *p = chanid;
+ unsigned long val;
+
+ fsl_chan->edma3 = fsl_edma3;
+ fsl_chan->pm_state = RUNNING;
+ fsl_chan->idle = true;
+ /* Get per channel membase */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ fsl_chan->membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(fsl_chan->membase))
+ return PTR_ERR(fsl_chan->membase);
+
+ /* Get the hardware chanel id by the channel membase
+ * channel0:0x10000, channel1:0x20000... total 32 channels
+ */
+ fsl_chan->hw_chanid = (res->start >> 16) & 0x1f;
+
+ ret = of_property_read_string_index(np, "interrupt-names", i,
+ &txirq_name);
+ if (ret) {
+ dev_err(&pdev->dev, "read interrupt-names fail.\n");
+ return ret;
+ }
+ /* Get channel id length from dts, one-digit or double-digit */
+ id_len = strlen(txirq_name) - strlen(CHAN_PREFIX) -
+ strlen(CHAN_POSFIX);
+ if (id_len > 2) {
+ dev_err(&pdev->dev, "%s is edmaX-chanX-tx in dts?\n",
+ res->name);
+ return -EINVAL;
+ }
+ /* Grab channel id from txirq_name */
+ strncpy(p, txirq_name + strlen(CHAN_PREFIX), id_len);
+ *(p + id_len) = '\0';
+
+ /* check if the channel id match well with hw_chanid */
+ ret = kstrtoul(chanid, 0, &val);
+ if (ret || val != fsl_chan->hw_chanid) {
+ dev_err(&pdev->dev, "%s,wrong id?\n", txirq_name);
+ return -EINVAL;
+ }
+
+ /* request channel irq */
+ fsl_chan->txirq = platform_get_irq_byname(pdev, txirq_name);
+ if (fsl_chan->txirq < 0) {
+ dev_err(&pdev->dev, "Can't get %s irq.\n", txirq_name);
+ return fsl_chan->txirq;
+ }
+
+ ret = devm_request_irq(&pdev->dev, fsl_chan->txirq,
+ fsl_edma3_tx_handler, irqflag, txirq_name,
+ fsl_chan);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't register %s IRQ.\n",
+ txirq_name);
+ return ret;
+ }
+
+ fsl_chan->vchan.desc_free = fsl_edma3_free_desc;
+ vchan_init(&fsl_chan->vchan, &fsl_edma3->dma_dev);
+ fsl_chan->used = false;
+ }
+
+ mutex_init(&fsl_edma3->fsl_edma3_mutex);
+
+ dma_cap_set(DMA_PRIVATE, fsl_edma3->dma_dev.cap_mask);
+ dma_cap_set(DMA_SLAVE, fsl_edma3->dma_dev.cap_mask);
+ dma_cap_set(DMA_CYCLIC, fsl_edma3->dma_dev.cap_mask);
+
+ fsl_edma3->dma_dev.dev = &pdev->dev;
+ fsl_edma3->dma_dev.device_alloc_chan_resources
+ = fsl_edma3_alloc_chan_resources;
+ fsl_edma3->dma_dev.device_free_chan_resources
+ = fsl_edma3_free_chan_resources;
+ fsl_edma3->dma_dev.device_tx_status = fsl_edma3_tx_status;
+ fsl_edma3->dma_dev.device_prep_slave_sg = fsl_edma3_prep_slave_sg;
+ fsl_edma3->dma_dev.device_prep_dma_cyclic = fsl_edma3_prep_dma_cyclic;
+ fsl_edma3->dma_dev.device_config = fsl_edma3_slave_config;
+ fsl_edma3->dma_dev.device_pause = fsl_edma3_pause;
+ fsl_edma3->dma_dev.device_resume = fsl_edma3_resume;
+ fsl_edma3->dma_dev.device_terminate_all = fsl_edma3_terminate_all;
+ fsl_edma3->dma_dev.device_issue_pending = fsl_edma3_issue_pending;
+ fsl_edma3->dma_dev.device_synchronize = fsl_edma3_synchronize;
+
+ fsl_edma3->dma_dev.src_addr_widths = FSL_EDMA_BUSWIDTHS;
+ fsl_edma3->dma_dev.dst_addr_widths = FSL_EDMA_BUSWIDTHS;
+ fsl_edma3->dma_dev.directions = BIT(DMA_DEV_TO_MEM) |
+ BIT(DMA_MEM_TO_DEV) |
+ BIT(DMA_DEV_TO_DEV);
+
+ platform_set_drvdata(pdev, fsl_edma3);
+
+ ret = dma_async_device_register(&fsl_edma3->dma_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't register Freescale eDMA engine.\n");
+ return ret;
+ }
+
+ ret = of_dma_controller_register(np, fsl_edma3_xlate, fsl_edma3);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't register Freescale eDMA of_dma.\n");
+ dma_async_device_unregister(&fsl_edma3->dma_dev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fsl_edma3_remove(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct fsl_edma3_engine *fsl_edma3 = platform_get_drvdata(pdev);
+
+ of_dma_controller_free(np);
+ dma_async_device_unregister(&fsl_edma3->dma_dev);
+
+ return 0;
+}
+
+static int fsl_edma3_suspend_late(struct device *dev)
+{
+ struct fsl_edma3_engine *fsl_edma = dev_get_drvdata(dev);
+ struct fsl_edma3_chan *fsl_chan;
+ unsigned long flags;
+ void __iomem *addr;
+ int i;
+
+ for (i = 0; i < fsl_edma->n_chans; i++) {
+ fsl_chan = &fsl_edma->chans[i];
+ addr = fsl_chan->membase;
+
+ if (!fsl_chan->used)
+ continue;
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ fsl_edma->edma_regs[i].csr = readl(addr + EDMA_CH_CSR);
+ fsl_edma->edma_regs[i].sbr = readl(addr + EDMA_CH_SBR);
+ /* Make sure chan is idle or will force disable. */
+ if (unlikely(!fsl_chan->idle)) {
+ dev_warn(dev, "WARN: There is non-idle channel.");
+ fsl_edma3_disable_request(fsl_chan);
+ }
+ fsl_chan->pm_state = SUSPENDED;
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+ }
+
+ return 0;
+}
+
+static int fsl_edma3_resume_early(struct device *dev)
+{
+ struct fsl_edma3_engine *fsl_edma = dev_get_drvdata(dev);
+ struct fsl_edma3_chan *fsl_chan;
+ void __iomem *addr;
+ unsigned long flags;
+ int i;
+
+ for (i = 0; i < fsl_edma->n_chans; i++) {
+ fsl_chan = &fsl_edma->chans[i];
+ addr = fsl_chan->membase;
+
+ if (!fsl_chan->used)
+ continue;
+
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ writel(fsl_edma->edma_regs[i].csr, addr + EDMA_CH_CSR);
+ writel(fsl_edma->edma_regs[i].sbr, addr + EDMA_CH_SBR);
+ /* restore tcd if this channel not terminated before suspend */
+ if (fsl_chan->edesc)
+ fsl_edma3_set_tcd_regs(fsl_chan,
+ fsl_chan->edesc->tcd[0].vtcd);
+ fsl_chan->pm_state = RUNNING;
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops fsl_edma3_pm_ops = {
+ .suspend_late = fsl_edma3_suspend_late,
+ .resume_early = fsl_edma3_resume_early,
+};
+
+static const struct of_device_id fsl_edma3_dt_ids[] = {
+ { .compatible = "fsl,imx8qm-edma", },
+ { .compatible = "fsl,imx8qm-adma", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_edma3_dt_ids);
+
+static struct platform_driver fsl_edma3_driver = {
+ .driver = {
+ .name = "fsl-edma-v3",
+ .of_match_table = fsl_edma3_dt_ids,
+ .pm = &fsl_edma3_pm_ops,
+ },
+ .probe = fsl_edma3_probe,
+ .remove = fsl_edma3_remove,
+};
+
+static int __init fsl_edma3_init(void)
+{
+ return platform_driver_register(&fsl_edma3_driver);
+}
+subsys_initcall(fsl_edma3_init);
+
+static void __exit fsl_edma3_exit(void)
+{
+ platform_driver_unregister(&fsl_edma3_driver);
+}
+module_exit(fsl_edma3_exit);
+
+MODULE_ALIAS("platform:fsl-edma3");
+MODULE_DESCRIPTION("Freescale eDMA-V3 engine driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index c7568869284e..023a33168b1b 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -2,6 +2,7 @@
* drivers/dma/fsl-edma.c
*
* Copyright 2013-2014 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
*
* Driver for the Freescale eDMA engine with flexible channel multiplexing
* capability for DMA request sources. The eDMA block can be found on some
@@ -111,11 +112,18 @@
#define EDMAMUX_CHCFG_SOURCE(n) ((n) & 0x3F)
#define DMAMUX_NR 2
+#define FSL_EDMA_REG_NUM 3
+#define FSL_DMAMUX_SLOTS 32
+#define FSL_DMAMUX_REG_NUM (DMAMUX_NR * FSL_DMAMUX_SLOTS)
#define FSL_EDMA_BUSWIDTHS BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
+
+/* Controller will loss power in i.MX7ULP VLLS low power mode */
+#define FSL_EDMA_QUIRK_VLLS_MODE (1 << 0)
+
enum fsl_edma_pm_state {
RUNNING = 0,
SUSPENDED,
@@ -158,6 +166,8 @@ struct fsl_edma_chan {
struct fsl_edma_desc *edesc;
struct fsl_edma_slave_config fsc;
struct dma_pool *tcd_pool;
+ char chan_name[16];
+ u32 chn_real_count;
};
struct fsl_edma_desc {
@@ -172,15 +182,79 @@ struct fsl_edma_engine {
struct dma_device dma_dev;
void __iomem *membase;
void __iomem *muxbase[DMAMUX_NR];
+ struct clk *dmaclk;
struct clk *muxclk[DMAMUX_NR];
struct mutex fsl_edma_mutex;
u32 n_chans;
int txirq;
int errirq;
bool big_endian;
+ u32 dmamux_nr;
+ u32 version;
+ void (*mux_configure)(struct fsl_edma_chan *,
+ void __iomem *muxaddr, u32 off,
+ u32 slot, bool enable);
+ u32 edma_regs[FSL_EDMA_REG_NUM];
+ u32 dmamux_regs[FSL_DMAMUX_REG_NUM];
+ u32 quirks;
struct fsl_edma_chan chans[];
};
+static struct platform_device_id fsl_edma_devtype[] = {
+ {
+ .name = "vf610-edma",
+ .driver_data = 0,
+ }, {
+ .name = "imx7ulp-edma",
+ .driver_data = FSL_EDMA_QUIRK_VLLS_MODE,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(platform, fsl_edma_devtype);
+
+enum fsl_edma_type {
+ VF610_EDMA,
+ IMX7ULP_EDMA,
+};
+
+static const struct of_device_id fsl_edma_dt_ids[] = {
+ {
+ .compatible = "fsl,vf610-edma",
+ .data = &fsl_edma_devtype[VF610_EDMA],
+ }, {
+ .compatible = "nxp,imx7ulp-edma",
+ .data = &fsl_edma_devtype[IMX7ULP_EDMA],
+ }, { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids);
+
+void mux_configure8(struct fsl_edma_chan *fsl_chan, void __iomem *muxaddr,
+ u32 off, u32 slot, bool enable)
+{
+ u8 val8;
+
+ if (enable)
+ val8 = EDMAMUX_CHCFG_ENBL | slot;
+ else
+ val8 = EDMAMUX_CHCFG_DIS;
+
+ iowrite8(val8, muxaddr + off);
+}
+
+void mux_configure32(struct fsl_edma_chan *fsl_chan, void __iomem *muxaddr,
+ u32 off, u32 slot, bool enable)
+{
+ u32 val;
+
+ if (enable)
+ val = EDMAMUX_CHCFG_ENBL << 24 | slot;
+ else
+ val = EDMAMUX_CHCFG_DIS;
+
+ iowrite32(val, muxaddr + off * 4);
+}
+
/*
* R/W functions for big- or little-endian registers:
* The eDMA controller's endian is independent of the CPU core's endian.
@@ -257,15 +331,12 @@ static void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
void __iomem *muxaddr;
unsigned chans_per_mux, ch_off;
- chans_per_mux = fsl_chan->edma->n_chans / DMAMUX_NR;
+ chans_per_mux = fsl_chan->edma->n_chans / fsl_chan->edma->dmamux_nr;
ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux;
muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux];
slot = EDMAMUX_CHCFG_SOURCE(slot);
- if (enable)
- iowrite8(EDMAMUX_CHCFG_ENBL | slot, muxaddr + ch_off);
- else
- iowrite8(EDMAMUX_CHCFG_DIS, muxaddr + ch_off);
+ fsl_chan->edma->mux_configure(fsl_chan, muxaddr, ch_off, slot, enable);
}
static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width)
@@ -312,7 +383,7 @@ static int fsl_edma_terminate_all(struct dma_chan *chan)
return 0;
}
-static int fsl_edma_pause(struct dma_chan *chan)
+static int fsl_edma_device_pause(struct dma_chan *chan)
{
struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
unsigned long flags;
@@ -327,7 +398,7 @@ static int fsl_edma_pause(struct dma_chan *chan)
return 0;
}
-static int fsl_edma_resume(struct dma_chan *chan)
+static int fsl_edma_device_resume(struct dma_chan *chan)
{
struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
unsigned long flags;
@@ -416,8 +487,12 @@ static enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
unsigned long flags;
status = dma_cookie_status(chan, cookie, txstate);
- if (status == DMA_COMPLETE)
+ if (status == DMA_COMPLETE) {
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ txstate->residue = fsl_chan->chn_real_count;
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
return status;
+ }
if (!txstate)
return fsl_chan->status;
@@ -426,7 +501,7 @@ static enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
vdesc = vchan_find_desc(&fsl_chan->vchan, cookie);
if (fsl_chan->edesc && cookie == fsl_chan->edesc->vdesc.tx.cookie)
txstate->residue = fsl_edma_desc_residue(fsl_chan, vdesc, true);
- else if (vdesc)
+ else if (fsl_chan->edesc && vdesc)
txstate->residue = fsl_edma_desc_residue(fsl_chan, vdesc, false);
else
txstate->residue = 0;
@@ -661,6 +736,11 @@ static void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan)
fsl_chan->idle = false;
}
+static void fsl_edma_get_realcnt(struct fsl_edma_chan *fsl_chan)
+{
+ fsl_chan->chn_real_count = fsl_edma_desc_residue(fsl_chan, NULL, true);
+}
+
static irqreturn_t fsl_edma_tx_handler(int irq, void *dev_id)
{
struct fsl_edma_engine *fsl_edma = dev_id;
@@ -683,6 +763,7 @@ static irqreturn_t fsl_edma_tx_handler(int irq, void *dev_id)
spin_lock(&fsl_chan->vchan.lock);
if (!fsl_chan->edesc->iscyclic) {
+ fsl_edma_get_realcnt(fsl_chan);
list_del(&fsl_chan->edesc->vdesc.node);
vchan_cookie_complete(&fsl_chan->edesc->vdesc);
fsl_chan->edesc = NULL;
@@ -712,6 +793,7 @@ static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id)
for (ch = 0; ch < fsl_edma->n_chans; ch++) {
if (err & (0x1 << ch)) {
+ dev_err(fsl_edma->dma_dev.dev, "DMA CH%d Err!\n", ch);
fsl_edma_disable_request(&fsl_edma->chans[ch]);
edma_writeb(fsl_edma, EDMA_CERR_CERR(ch),
fsl_edma->membase + EDMA_CERR);
@@ -755,7 +837,7 @@ static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
struct fsl_edma_engine *fsl_edma = ofdma->of_dma_data;
struct dma_chan *chan, *_chan;
struct fsl_edma_chan *fsl_chan;
- unsigned long chans_per_mux = fsl_edma->n_chans / DMAMUX_NR;
+ unsigned long chans_per_mux = fsl_edma->n_chans / fsl_edma->dmamux_nr;
if (dma_spec->args_count != 2)
return NULL;
@@ -867,8 +949,58 @@ static void fsl_disable_clocks(struct fsl_edma_engine *fsl_edma, int nr_clocks)
{
int i;
- for (i = 0; i < nr_clocks; i++)
+ for (i = 0; i < fsl_edma->dmamux_nr; i++)
clk_disable_unprepare(fsl_edma->muxclk[i]);
+
+ if (fsl_edma->dmaclk)
+ clk_disable_unprepare(fsl_edma->dmaclk);
+}
+
+static int
+fsl_edma2_irq_init(struct platform_device *pdev,
+ struct fsl_edma_engine *fsl_edma)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int i, ret, irq;
+ int count = 0;
+
+ count = of_irq_count(np);
+ dev_info(&pdev->dev, "%s Found %d interrupts\r\n", __func__, count);
+ if(count < 2){
+ dev_err(&pdev->dev, "Interrupts in DTS not correct.\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < count; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0)
+ return -ENXIO;
+
+ sprintf(fsl_edma->chans[i].chan_name, "eDMA2-CH%02d", i);
+
+ /* The last IRQ is for eDMA err */
+ if (i == count - 1)
+ ret = devm_request_irq(&pdev->dev, irq,
+ fsl_edma_err_handler,
+ 0, "eDMA2-ERR", fsl_edma);
+ else
+
+ ret = devm_request_irq(&pdev->dev, irq,
+ fsl_edma_tx_handler, 0,
+ fsl_edma->chans[i].chan_name,
+ fsl_edma);
+ if(ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void fsl_edma_synchronize(struct dma_chan *chan)
+{
+ struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+
+ vchan_synchronize(&fsl_chan->vchan);
}
static int fsl_edma_probe(struct platform_device *pdev)
@@ -876,6 +1008,7 @@ static int fsl_edma_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct fsl_edma_engine *fsl_edma;
struct fsl_edma_chan *fsl_chan;
+ const struct of_device_id *of_id;
struct resource *res;
int len, chans;
int ret, i;
@@ -891,6 +1024,11 @@ static int fsl_edma_probe(struct platform_device *pdev)
if (!fsl_edma)
return -ENOMEM;
+ of_id = of_match_device(fsl_edma_dt_ids, &pdev->dev);
+ if (of_id)
+ pdev->id_entry = of_id->data;
+ fsl_edma->quirks = pdev->id_entry->driver_data;
+
fsl_edma->n_chans = chans;
mutex_init(&fsl_edma->fsl_edma_mutex);
@@ -899,7 +1037,29 @@ static int fsl_edma_probe(struct platform_device *pdev)
if (IS_ERR(fsl_edma->membase))
return PTR_ERR(fsl_edma->membase);
- for (i = 0; i < DMAMUX_NR; i++) {
+ fsl_edma->dmamux_nr = DMAMUX_NR;
+ fsl_edma->mux_configure = mux_configure8;
+ fsl_edma->version = 1;
+
+ if (of_device_is_compatible(np, "nxp,imx7ulp-edma")) {
+ fsl_edma->dmamux_nr = 1;
+ fsl_edma->mux_configure = mux_configure32;
+ fsl_edma->version = 2;
+
+ fsl_edma->dmaclk = devm_clk_get(&pdev->dev, "dma");
+ if (IS_ERR(fsl_edma->dmaclk)) {
+ dev_err(&pdev->dev, "Missing DMA block clock.\n");
+ return PTR_ERR(fsl_edma->dmaclk);
+ }
+
+ ret = clk_prepare_enable(fsl_edma->dmaclk);
+ if (ret) {
+ dev_err(&pdev->dev, "DMA clk block failed.\n");
+ return ret;
+ }
+ }
+
+ for (i = 0; i < fsl_edma->dmamux_nr; i++) {
char clkname[32];
res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i);
@@ -926,6 +1086,14 @@ static int fsl_edma_probe(struct platform_device *pdev)
}
+ edma_writel(fsl_edma, ~0, fsl_edma->membase + EDMA_INTR);
+ if (fsl_edma->version == 1)
+ ret = fsl_edma_irq_init(pdev, fsl_edma);
+ else
+ ret = fsl_edma2_irq_init(pdev, fsl_edma);
+ if (ret)
+ return ret;
+
fsl_edma->big_endian = of_property_read_bool(np, "big-endian");
INIT_LIST_HEAD(&fsl_edma->dma_dev.channels);
@@ -940,14 +1108,11 @@ static int fsl_edma_probe(struct platform_device *pdev)
vchan_init(&fsl_chan->vchan, &fsl_edma->dma_dev);
edma_writew(fsl_edma, 0x0, fsl_edma->membase + EDMA_TCD_CSR(i));
+ fsl_chan->vchan.chan.chan_id = i;
fsl_edma_chan_mux(fsl_chan, 0, false);
+ fsl_chan->vchan.chan.chan_id = 0;
}
- edma_writel(fsl_edma, ~0, fsl_edma->membase + EDMA_INTR);
- ret = fsl_edma_irq_init(pdev, fsl_edma);
- if (ret)
- return ret;
-
dma_cap_set(DMA_PRIVATE, fsl_edma->dma_dev.cap_mask);
dma_cap_set(DMA_SLAVE, fsl_edma->dma_dev.cap_mask);
dma_cap_set(DMA_CYCLIC, fsl_edma->dma_dev.cap_mask);
@@ -961,10 +1126,11 @@ static int fsl_edma_probe(struct platform_device *pdev)
fsl_edma->dma_dev.device_prep_slave_sg = fsl_edma_prep_slave_sg;
fsl_edma->dma_dev.device_prep_dma_cyclic = fsl_edma_prep_dma_cyclic;
fsl_edma->dma_dev.device_config = fsl_edma_slave_config;
- fsl_edma->dma_dev.device_pause = fsl_edma_pause;
- fsl_edma->dma_dev.device_resume = fsl_edma_resume;
+ fsl_edma->dma_dev.device_pause = fsl_edma_device_pause;
+ fsl_edma->dma_dev.device_resume = fsl_edma_device_resume;
fsl_edma->dma_dev.device_terminate_all = fsl_edma_terminate_all;
fsl_edma->dma_dev.device_issue_pending = fsl_edma_issue_pending;
+ fsl_edma->dma_dev.device_synchronize = fsl_edma_synchronize;
fsl_edma->dma_dev.src_addr_widths = FSL_EDMA_BUSWIDTHS;
fsl_edma->dma_dev.dst_addr_widths = FSL_EDMA_BUSWIDTHS;
@@ -1020,6 +1186,56 @@ static int fsl_edma_remove(struct platform_device *pdev)
return 0;
}
+static int fsl_edma_register_save(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fsl_edma_engine *fsl_edma = platform_get_drvdata(pdev);
+ int i, j;
+
+ if (!(fsl_edma->quirks & FSL_EDMA_QUIRK_VLLS_MODE))
+ return 0;
+
+ /* save regs */
+ fsl_edma->edma_regs[0] =
+ edma_readl(fsl_edma, fsl_edma->membase + EDMA_CR);
+ fsl_edma->edma_regs[1] =
+ edma_readl(fsl_edma, fsl_edma->membase + EDMA_ERQ);
+ fsl_edma->edma_regs[2] =
+ edma_readl(fsl_edma, fsl_edma->membase + EDMA_EEI);
+ for (i = 0; i < fsl_edma->dmamux_nr; i++)
+ for (j = 0; j < fsl_edma->n_chans; j++)
+ fsl_edma->dmamux_regs[i * fsl_edma->n_chans + j] =
+ edma_readl(fsl_edma,
+ fsl_edma->muxbase[i] + j * 4);
+
+ return 0;
+}
+
+static int fsl_edma_register_restore(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fsl_edma_engine *fsl_edma = platform_get_drvdata(pdev);
+ int i, j;
+
+ if (!(fsl_edma->quirks & FSL_EDMA_QUIRK_VLLS_MODE))
+ return 0;
+
+ /* restore the regs */
+ for (i = 0; i < fsl_edma->dmamux_nr; i++)
+ for (j = 0; j < fsl_edma->n_chans; j++)
+ edma_writel(fsl_edma,
+ fsl_edma->dmamux_regs[i * fsl_edma->n_chans + j],
+ fsl_edma->muxbase[i] + j * 4);
+ edma_writel(fsl_edma, fsl_edma->edma_regs[1],
+ fsl_edma->membase + EDMA_ERQ);
+ edma_writel(fsl_edma, fsl_edma->edma_regs[2],
+ fsl_edma->membase + EDMA_EEI);
+ edma_writel(fsl_edma, fsl_edma->edma_regs[0],
+ fsl_edma->membase + EDMA_CR);
+
+ return 0;
+}
+
static int fsl_edma_suspend_late(struct device *dev)
{
struct fsl_edma_engine *fsl_edma = dev_get_drvdata(dev);
@@ -1041,6 +1257,8 @@ static int fsl_edma_suspend_late(struct device *dev)
spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
}
+ fsl_edma_register_save(dev);
+
return 0;
}
@@ -1050,6 +1268,8 @@ static int fsl_edma_resume_early(struct device *dev)
struct fsl_edma_chan *fsl_chan;
int i;
+ fsl_edma_register_restore(dev);
+
for (i = 0; i < fsl_edma->n_chans; i++) {
fsl_chan = &fsl_edma->chans[i];
fsl_chan->pm_state = RUNNING;
@@ -1074,18 +1294,13 @@ static const struct dev_pm_ops fsl_edma_pm_ops = {
.resume_early = fsl_edma_resume_early,
};
-static const struct of_device_id fsl_edma_dt_ids[] = {
- { .compatible = "fsl,vf610-edma", },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids);
-
static struct platform_driver fsl_edma_driver = {
.driver = {
.name = "fsl-edma",
.of_match_table = fsl_edma_dt_ids,
.pm = &fsl_edma_pm_ops,
},
+ .id_table = fsl_edma_devtype,
.probe = fsl_edma_probe,
.remove = fsl_edma_remove,
};
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index b9c29720aeb1..77354c999c76 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -7,7 +7,8 @@
*
* Based on code from Freescale:
*
- * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2004-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2018 NXP.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
@@ -30,7 +31,9 @@
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/device.h>
+#include <linux/genalloc.h>
#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
@@ -48,6 +51,7 @@
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include "dmaengine.h"
+#include "virt-dma.h"
/* SDMA registers */
#define SDMA_H_C0PTR 0x000
@@ -79,6 +83,9 @@
#define SDMA_CHNENBL0_IMX35 0x200
#define SDMA_CHNENBL0_IMX31 0x080
#define SDMA_CHNPRI_0 0x100
+#define SDMA_DONE0_CONFIG 0x1000
+#define SDMA_DONE0_CONFIG_DONE_SEL 0x7
+#define SDMA_DONE0_CONFIG_DONE_DIS 0x6
/*
* Buffer descriptor status values.
@@ -173,11 +180,26 @@
#define SDMA_WATERMARK_LEVEL_SPDIF BIT(10)
#define SDMA_WATERMARK_LEVEL_SP BIT(11)
#define SDMA_WATERMARK_LEVEL_DP BIT(12)
+#define SDMA_WATERMARK_LEVEL_SD BIT(13)
+#define SDMA_WATERMARK_LEVEL_DD BIT(14)
#define SDMA_WATERMARK_LEVEL_HWML (0xFF << 16)
#define SDMA_WATERMARK_LEVEL_LWE BIT(28)
#define SDMA_WATERMARK_LEVEL_HWE BIT(29)
#define SDMA_WATERMARK_LEVEL_CONT BIT(31)
+#define SDMA_DMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+ BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
+
+#define SDMA_DMA_DIRECTIONS (BIT(DMA_DEV_TO_MEM) | \
+ BIT(DMA_MEM_TO_DEV) | \
+ BIT(DMA_DEV_TO_DEV))
+
+#define SDMA_WATERMARK_LEVEL_FIFOS_OFF 8
+#define SDMA_WATERMARK_LEVEL_SW_DONE BIT(23)
+#define SDMA_WATERMARK_LEVEL_SW_DONE_SEL_OFF 24
+
/*
* Mode/Count of data node descriptors - IPCv2
*/
@@ -284,9 +306,22 @@ struct sdma_context_data {
} __attribute__ ((packed));
#define NUM_BD (int)(PAGE_SIZE / sizeof(struct sdma_buffer_descriptor))
+#define SDMA_BD_MAX_CNT 0xfffc /* align with 4 bytes */
struct sdma_engine;
+struct sdma_desc {
+ struct virt_dma_desc vd;
+ struct list_head node;
+ unsigned int num_bd;
+ dma_addr_t bd_phys;
+ bool bd_iram;
+ unsigned int buf_tail;
+ unsigned int buf_ptail;
+ struct sdma_channel *sdmac;
+ struct sdma_buffer_descriptor *bd;
+};
+
/**
* struct sdma_channel - housekeeping for a SDMA channel
*
@@ -300,36 +335,40 @@ struct sdma_engine;
* @buf_tail ID of the buffer that was processed
* @buf_ptail ID of the previous buffer that was processed
* @num_bd max NUM_BD. number of descriptors currently handling
+ * @bd_iram flag indicating the memory location of buffer descriptor
*/
struct sdma_channel {
+ struct virt_dma_chan vc;
+ struct list_head pending;
struct sdma_engine *sdma;
+ struct sdma_desc *desc;
unsigned int channel;
enum dma_transfer_direction direction;
enum sdma_peripheral_type peripheral_type;
unsigned int event_id0;
unsigned int event_id1;
enum dma_slave_buswidth word_size;
- unsigned int buf_tail;
- unsigned int buf_ptail;
- unsigned int num_bd;
unsigned int period_len;
- struct sdma_buffer_descriptor *bd;
- dma_addr_t bd_phys;
unsigned int pc_from_device, pc_to_device;
unsigned int device_to_device;
+ unsigned int pc_to_pc;
unsigned long flags;
dma_addr_t per_address, per_address2;
unsigned long event_mask[2];
unsigned long watermark_level;
u32 shp_addr, per_addr;
- struct dma_chan chan;
- spinlock_t lock;
- struct dma_async_tx_descriptor desc;
enum dma_status status;
+ struct imx_dma_data data;
unsigned int chn_count;
unsigned int chn_real_count;
- struct tasklet_struct tasklet;
- struct imx_dma_data data;
+ bool context_loaded;
+ u32 bd_size_sum;
+ bool src_dualfifo;
+ bool dst_dualfifo;
+ unsigned int fifo_num;
+ bool sw_done;
+ u32 sw_done_sel;
+ struct dma_pool *bd_pool;
};
#define IMX_DMA_SG_LOOP BIT(0)
@@ -338,6 +377,14 @@ struct sdma_channel {
#define MXC_SDMA_DEFAULT_PRIORITY 1
#define MXC_SDMA_MIN_PRIORITY 1
#define MXC_SDMA_MAX_PRIORITY 7
+/*
+ * 0x78(SDMA_XTRIG_CONF2+4)~0x100(SDMA_CHNPRI_O) registers are reserved and
+ * can't be accessed. Skip these register touch in suspend/resume. Also below
+ * two macros are only used on i.mx6sx.
+ */
+#define MXC_SDMA_RESERVED_REG (SDMA_CHNPRI_0 - SDMA_XTRIG_CONF2 - 4)
+#define MXC_SDMA_SAVED_REG_NUM (((SDMA_CHNENBL0_IMX35 + 4 * 48) - \
+ MXC_SDMA_RESERVED_REG) / 4)
#define SDMA_FIRMWARE_MAGIC 0x414d4453
@@ -376,6 +423,8 @@ struct sdma_engine {
struct device_dma_parameters dma_parms;
struct sdma_channel channel[MAX_DMA_CHANNELS];
struct sdma_channel_control *channel_control;
+ u32 save_regs[MXC_SDMA_SAVED_REG_NUM];
+ const char *fw_name;
void __iomem *regs;
struct sdma_context_data *context;
dma_addr_t context_phys;
@@ -389,6 +438,15 @@ struct sdma_engine {
u32 spba_start_addr;
u32 spba_end_addr;
unsigned int irq;
+ struct gen_pool *iram_pool;
+ /* channel0 bd */
+ dma_addr_t bd0_phys;
+ bool bd0_iram;
+ struct sdma_buffer_descriptor *bd0;
+ bool suspend_off;
+ int idx;
+ /* clock ration for AHB:SDMA core. 1:1 is 1, 2:1 is 0*/
+ bool clk_ratio;
};
static struct sdma_driver_data sdma_imx31 = {
@@ -466,7 +524,6 @@ static struct sdma_script_start_addrs sdma_script_imx6q = {
.ap_2_ap_addr = 642,
.uart_2_mcu_addr = 817,
.mcu_2_app_addr = 747,
- .per_2_per_addr = 6331,
.uartsh_2_mcu_addr = 1032,
.mcu_2_shp_addr = 960,
.app_2_mcu_addr = 683,
@@ -481,6 +538,30 @@ static struct sdma_driver_data sdma_imx6q = {
.script_addrs = &sdma_script_imx6q,
};
+static struct sdma_script_start_addrs sdma_script_imx6sx = {
+ .ap_2_ap_addr = 642,
+ .uart_2_mcu_addr = 817,
+ .mcu_2_app_addr = 747,
+ .uartsh_2_mcu_addr = 1032,
+ .mcu_2_shp_addr = 960,
+ .app_2_mcu_addr = 683,
+ .shp_2_mcu_addr = 891,
+ .spdif_2_mcu_addr = 1100,
+ .mcu_2_spdif_addr = 1134,
+};
+
+static struct sdma_driver_data sdma_imx6sx = {
+ .chnenbl0 = SDMA_CHNENBL0_IMX35,
+ .num_events = 48,
+ .script_addrs = &sdma_script_imx6sx,
+};
+
+static struct sdma_driver_data sdma_imx6ul = {
+ .chnenbl0 = SDMA_CHNENBL0_IMX35,
+ .num_events = 48,
+ .script_addrs = &sdma_script_imx6sx,
+};
+
static struct sdma_script_start_addrs sdma_script_imx7d = {
.ap_2_ap_addr = 644,
.uart_2_mcu_addr = 819,
@@ -499,6 +580,12 @@ static struct sdma_driver_data sdma_imx7d = {
.script_addrs = &sdma_script_imx7d,
};
+static struct sdma_driver_data sdma_imx8m = {
+ .chnenbl0 = SDMA_CHNENBL0_IMX35,
+ .num_events = 48,
+ .script_addrs = &sdma_script_imx7d,
+};
+
static const struct platform_device_id sdma_devtypes[] = {
{
.name = "imx25-sdma",
@@ -519,15 +606,23 @@ static const struct platform_device_id sdma_devtypes[] = {
.name = "imx6q-sdma",
.driver_data = (unsigned long)&sdma_imx6q,
}, {
+ .name = "imx6sx-sdma",
+ .driver_data = (unsigned long)&sdma_imx6sx,
+ }, {
.name = "imx7d-sdma",
.driver_data = (unsigned long)&sdma_imx7d,
}, {
+ .name = "imx8mq-sdma",
+ .driver_data = (unsigned long)&sdma_imx8m,
+ }, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(platform, sdma_devtypes);
static const struct of_device_id sdma_dt_ids[] = {
+ { .compatible = "fsl,imx6ul-sdma", .data = &sdma_imx6ul, },
+ { .compatible = "fsl,imx6sx-sdma", .data = &sdma_imx6sx, },
{ .compatible = "fsl,imx6q-sdma", .data = &sdma_imx6q, },
{ .compatible = "fsl,imx53-sdma", .data = &sdma_imx53, },
{ .compatible = "fsl,imx51-sdma", .data = &sdma_imx51, },
@@ -535,15 +630,20 @@ static const struct of_device_id sdma_dt_ids[] = {
{ .compatible = "fsl,imx31-sdma", .data = &sdma_imx31, },
{ .compatible = "fsl,imx25-sdma", .data = &sdma_imx25, },
{ .compatible = "fsl,imx7d-sdma", .data = &sdma_imx7d, },
+ { .compatible = "fsl,imx8mq-sdma", .data = &sdma_imx8m, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sdma_dt_ids);
+static int sdma_dev_idx;
+
#define SDMA_H_CONFIG_DSPDMA BIT(12) /* indicates if the DSPDMA is used */
#define SDMA_H_CONFIG_RTD_PINS BIT(11) /* indicates if Real-Time Debug pins are enabled */
#define SDMA_H_CONFIG_ACR BIT(4) /* indicates if AHB freq /core freq = 2 or 1 */
#define SDMA_H_CONFIG_CSM (3) /* indicates which context switch mode is selected*/
+static void sdma_start_desc(struct sdma_channel *sdmac);
+
static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event)
{
u32 chnenbl0 = sdma->drvdata->chnenbl0;
@@ -616,23 +716,25 @@ static int sdma_run_channel0(struct sdma_engine *sdma)
static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
u32 address)
{
- struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
+ struct sdma_buffer_descriptor *bd0 = sdma->bd0;
void *buf_virt;
dma_addr_t buf_phys;
int ret;
unsigned long flags;
+ bool use_iram = true;
- buf_virt = dma_alloc_coherent(NULL,
- size,
- &buf_phys, GFP_KERNEL);
+ buf_virt = gen_pool_dma_alloc(sdma->iram_pool, size, &buf_phys);
if (!buf_virt) {
- return -ENOMEM;
+ use_iram = false;
+ buf_virt = dma_alloc_coherent(sdma->dev, size, &buf_phys, GFP_KERNEL);
+ if (!buf_virt)
+ return -ENOMEM;
}
spin_lock_irqsave(&sdma->channel_0_lock, flags);
bd0->mode.command = C0_SETPM;
- bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
+ bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD;
bd0->mode.count = size / 2;
bd0->buffer_addr = buf_phys;
bd0->ext_buffer_addr = address;
@@ -643,7 +745,10 @@ static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
- dma_free_coherent(NULL, size, buf_virt, buf_phys);
+ if (use_iram)
+ gen_pool_free(sdma->iram_pool, (unsigned long)buf_virt, size);
+ else
+ dma_free_coherent(sdma->dev, size, buf_virt, buf_phys);
return ret;
}
@@ -658,6 +763,21 @@ static void sdma_event_enable(struct sdma_channel *sdmac, unsigned int event)
val = readl_relaxed(sdma->regs + chnenbl);
__set_bit(channel, &val);
writel_relaxed(val, sdma->regs + chnenbl);
+
+ /* Set SDMA_DONEx_CONFIG is sw_done enabled */
+ if (sdmac->sw_done) {
+ u32 offset = SDMA_DONE0_CONFIG + sdmac->sw_done_sel / 4;
+ u32 done_sel = SDMA_DONE0_CONFIG_DONE_SEL +
+ ((sdmac->sw_done_sel % 4) << 3);
+ u32 sw_done_dis = SDMA_DONE0_CONFIG_DONE_DIS +
+ ((sdmac->sw_done_sel % 4) << 3);
+
+ val = readl_relaxed(sdma->regs + offset);
+ __set_bit(done_sel, &val);
+ __clear_bit(sw_done_dis, &val);
+ writel_relaxed(val, sdma->regs + offset);
+ }
+
}
static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
@@ -682,8 +802,10 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
* loop mode. Iterate over descriptors, re-setup them and
* call callback function.
*/
- while (1) {
- bd = &sdmac->bd[sdmac->buf_tail];
+ while (sdmac->desc) {
+ struct sdma_desc *desc = sdmac->desc;
+
+ bd = &desc->bd[desc->buf_tail];
if (bd->mode.status & BD_DONE)
break;
@@ -702,36 +824,35 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
sdmac->chn_real_count = bd->mode.count;
bd->mode.status |= BD_DONE;
bd->mode.count = sdmac->period_len;
- sdmac->buf_ptail = sdmac->buf_tail;
- sdmac->buf_tail = (sdmac->buf_tail + 1) % sdmac->num_bd;
-
- /*
- * The callback is called from the interrupt context in order
- * to reduce latency and to avoid the risk of altering the
- * SDMA transaction status by the time the client tasklet is
- * executed.
- */
-
- dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL);
+ desc->buf_ptail = desc->buf_tail;
+ desc->buf_tail = (desc->buf_tail + 1) % desc->num_bd;
if (error)
sdmac->status = old_status;
+ /*
+ * The callback is called from the interrupt context in order
+ * to reduce latency and to avoid the risk of altering the
+ * SDMA transaction status by the time the client tasklet is
+ * executed.
+ */
+ spin_unlock(&sdmac->vc.lock);
+ dmaengine_desc_get_callback_invoke(&desc->vd.tx, NULL);
+ spin_lock(&sdmac->vc.lock);
}
}
-static void mxc_sdma_handle_channel_normal(unsigned long data)
+static void mxc_sdma_handle_channel_normal(struct sdma_channel *data)
{
struct sdma_channel *sdmac = (struct sdma_channel *) data;
struct sdma_buffer_descriptor *bd;
int i, error = 0;
- sdmac->chn_real_count = 0;
/*
* non loop mode. Iterate over all descriptors, collect
* errors and call callback function
*/
- for (i = 0; i < sdmac->num_bd; i++) {
- bd = &sdmac->bd[i];
+ for (i = 0; i < sdmac->desc->num_bd; i++) {
+ bd = &sdmac->desc->bd[i];
if (bd->mode.status & (BD_DONE | BD_RROR))
error = -EIO;
@@ -742,10 +863,6 @@ static void mxc_sdma_handle_channel_normal(unsigned long data)
sdmac->status = DMA_ERROR;
else
sdmac->status = DMA_COMPLETE;
-
- dma_cookie_complete(&sdmac->desc);
-
- dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL);
}
static irqreturn_t sdma_int_handler(int irq, void *dev_id)
@@ -761,13 +878,26 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
while (stat) {
int channel = fls(stat) - 1;
struct sdma_channel *sdmac = &sdma->channel[channel];
-
- if (sdmac->flags & IMX_DMA_SG_LOOP)
- sdma_update_channel_loop(sdmac);
- else
- tasklet_schedule(&sdmac->tasklet);
-
+ struct sdma_desc *desc;
+
+ spin_lock(&sdmac->vc.lock);
+ desc = sdmac->desc;
+ if (desc) {
+ if (sdmac->flags & IMX_DMA_SG_LOOP) {
+ if (sdmac->peripheral_type != IMX_DMATYPE_HDMI)
+ sdma_update_channel_loop(sdmac);
+ else
+ vchan_cyclic_callback(&desc->vd);
+ } else {
+ mxc_sdma_handle_channel_normal(sdmac);
+ vchan_cookie_complete(&desc->vd);
+ if (!list_empty(&sdmac->pending))
+ list_del(&desc->node);
+ sdma_start_desc(sdmac);
+ }
+ }
__clear_bit(channel, &stat);
+ spin_unlock(&sdmac->vc.lock);
}
return IRQ_HANDLED;
@@ -785,14 +915,16 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
* These are needed once we start to support transfers between
* two peripherals or memory-to-memory transfers
*/
- int per_2_per = 0;
+ int per_2_per = 0, emi_2_emi = 0;
sdmac->pc_from_device = 0;
sdmac->pc_to_device = 0;
sdmac->device_to_device = 0;
+ sdmac->pc_to_pc = 0;
switch (peripheral_type) {
case IMX_DMATYPE_MEMORY:
+ emi_2_emi = sdma->script_addrs->ap_2_ap_addr;
break;
case IMX_DMATYPE_DSP:
emi_2_per = sdma->script_addrs->bp_2_ap_addr;
@@ -815,6 +947,9 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
emi_2_per = sdma->script_addrs->mcu_2_ata_addr;
break;
case IMX_DMATYPE_CSPI:
+ per_2_emi = sdma->script_addrs->app_2_mcu_addr;
+ emi_2_per = sdma->script_addrs->mcu_2_ecspi_addr;
+ break;
case IMX_DMATYPE_EXT:
case IMX_DMATYPE_SSI:
case IMX_DMATYPE_SAI:
@@ -858,6 +993,12 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
case IMX_DMATYPE_IPU_MEMORY:
emi_2_per = sdma->script_addrs->ext_mem_2_ipu_addr;
break;
+ case IMX_DMATYPE_HDMI:
+ emi_2_per = sdma->script_addrs->hdmi_dma_addr;
+ break;
+ case IMX_DMATYPE_MULTI_SAI:
+ per_2_emi = sdma->script_addrs->sai_2_mcu_addr;
+ emi_2_per = sdma->script_addrs->mcu_2_sai_addr;
default:
break;
}
@@ -865,6 +1006,7 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
sdmac->pc_from_device = per_2_emi;
sdmac->pc_to_device = emi_2_per;
sdmac->device_to_device = per_2_per;
+ sdmac->pc_to_pc = emi_2_emi;
}
static int sdma_load_context(struct sdma_channel *sdmac)
@@ -873,14 +1015,19 @@ static int sdma_load_context(struct sdma_channel *sdmac)
int channel = sdmac->channel;
int load_address;
struct sdma_context_data *context = sdma->context;
- struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
+ struct sdma_buffer_descriptor *bd0 = sdma->bd0;
int ret;
unsigned long flags;
+ if (sdmac->context_loaded)
+ return 0;
+
if (sdmac->direction == DMA_DEV_TO_MEM)
load_address = sdmac->pc_from_device;
else if (sdmac->direction == DMA_DEV_TO_DEV)
load_address = sdmac->device_to_device;
+ else if (sdmac->direction == DMA_MEM_TO_MEM)
+ load_address = sdmac->pc_to_pc;
else
load_address = sdmac->pc_to_device;
@@ -902,14 +1049,19 @@ static int sdma_load_context(struct sdma_channel *sdmac)
/* Send by context the event mask,base address for peripheral
* and watermark level
*/
- context->gReg[0] = sdmac->event_mask[1];
- context->gReg[1] = sdmac->event_mask[0];
- context->gReg[2] = sdmac->per_addr;
- context->gReg[6] = sdmac->shp_addr;
- context->gReg[7] = sdmac->watermark_level;
+ if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) {
+ context->gReg[4] = sdmac->per_addr;
+ context->gReg[6] = sdmac->shp_addr;
+ } else {
+ context->gReg[0] = sdmac->event_mask[1];
+ context->gReg[1] = sdmac->event_mask[0];
+ context->gReg[2] = sdmac->per_addr;
+ context->gReg[6] = sdmac->shp_addr;
+ context->gReg[7] = sdmac->watermark_level;
+ }
bd0->mode.command = C0_SETDM;
- bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
+ bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD;
bd0->mode.count = sizeof(*context) / 4;
bd0->buffer_addr = sdma->context_phys;
bd0->ext_buffer_addr = 2048 + (sizeof(*context) / 4) * channel;
@@ -917,12 +1069,39 @@ static int sdma_load_context(struct sdma_channel *sdmac)
spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
+ sdmac->context_loaded = true;
+
+ return ret;
+}
+
+static int sdma_save_restore_context(struct sdma_engine *sdma, bool save)
+{
+ struct sdma_context_data *context = sdma->context;
+ struct sdma_buffer_descriptor *bd0 = sdma->bd0;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&sdma->channel_0_lock, flags);
+
+ if (save)
+ bd0->mode.command = C0_GETDM;
+ else
+ bd0->mode.command = C0_SETDM;
+
+ bd0->mode.status = BD_DONE | BD_WRAP | BD_EXTD;
+ bd0->mode.count = MAX_DMA_CHANNELS * sizeof(*context) / 4;
+ bd0->buffer_addr = sdma->context_phys;
+ bd0->ext_buffer_addr = 2048;
+ ret = sdma_run_channel0(sdma);
+
+ spin_unlock_irqrestore(&sdma->channel_0_lock, flags);
+
return ret;
}
static struct sdma_channel *to_sdma_chan(struct dma_chan *chan)
{
- return container_of(chan, struct sdma_channel, chan);
+ return container_of(chan, struct sdma_channel, vc.chan);
}
static int sdma_disable_channel(struct dma_chan *chan)
@@ -937,21 +1116,6 @@ static int sdma_disable_channel(struct dma_chan *chan)
return 0;
}
-static int sdma_disable_channel_with_delay(struct dma_chan *chan)
-{
- sdma_disable_channel(chan);
-
- /*
- * According to NXP R&D team a delay of one BD SDMA cost time
- * (maximum is 1ms) should be added after disable of the channel
- * bit, to ensure SDMA core has really been stopped after SDMA
- * clients call .device_terminate_all.
- */
- mdelay(1);
-
- return 0;
-}
-
static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac)
{
struct sdma_engine *sdma = sdmac->sdma;
@@ -990,6 +1154,31 @@ static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac)
sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_DP;
sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_CONT;
+
+ if (sdmac->src_dualfifo)
+ sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_SD;
+ if (sdmac->dst_dualfifo)
+ sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_DD;
+}
+
+static void sdma_set_watermarklevel_for_sais(struct sdma_channel *sdmac)
+{
+ sdmac->watermark_level &= ~(0xFFF << SDMA_WATERMARK_LEVEL_FIFOS_OFF |
+ SDMA_WATERMARK_LEVEL_SW_DONE |
+ 0xf << SDMA_WATERMARK_LEVEL_SW_DONE_SEL_OFF);
+
+ if (sdmac->sw_done)
+ sdmac->watermark_level |= SDMA_WATERMARK_LEVEL_SW_DONE |
+ sdmac->sw_done_sel <<
+ SDMA_WATERMARK_LEVEL_SW_DONE_SEL_OFF;
+
+ /* For fifo_num
+ * bit 0-7 is the fifo number;
+ * bit 8-11 is the fifo offset,
+ * so here only need to shift left fifo_num 8 bit for watermake_level
+ */
+ sdmac->watermark_level |= sdmac->fifo_num<<
+ SDMA_WATERMARK_LEVEL_FIFOS_OFF;
}
static int sdma_config_channel(struct dma_chan *chan)
@@ -1004,11 +1193,9 @@ static int sdma_config_channel(struct dma_chan *chan)
sdmac->shp_addr = 0;
sdmac->per_addr = 0;
- if (sdmac->event_id0) {
- if (sdmac->event_id0 >= sdmac->sdma->drvdata->num_events)
- return -EINVAL;
- sdma_event_enable(sdmac, sdmac->event_id0);
- }
+ if (sdmac->event_id0 >= sdmac->sdma->drvdata->num_events)
+ return -EINVAL;
+ sdma_event_enable(sdmac, sdmac->event_id0);
if (sdmac->event_id1) {
if (sdmac->event_id1 >= sdmac->sdma->drvdata->num_events)
@@ -1037,8 +1224,18 @@ static int sdma_config_channel(struct dma_chan *chan)
if (sdmac->peripheral_type == IMX_DMATYPE_ASRC_SP ||
sdmac->peripheral_type == IMX_DMATYPE_ASRC)
sdma_set_watermarklevel_for_p2p(sdmac);
- } else
+ } else {
+ /* ERR008517 fixed on i.mx6ul, no workaround needed */
+ if (sdmac->peripheral_type == IMX_DMATYPE_CSPI &&
+ sdmac->direction == DMA_MEM_TO_DEV &&
+ sdmac->sdma->drvdata == &sdma_imx6ul)
+ __set_bit(31, &sdmac->watermark_level);
+ else if (sdmac->peripheral_type ==
+ IMX_DMATYPE_MULTI_SAI)
+ sdma_set_watermarklevel_for_sais(sdmac);
+
__set_bit(sdmac->event_id0, sdmac->event_mask);
+ }
/* Address */
sdmac->shp_addr = sdmac->per_address;
@@ -1047,6 +1244,8 @@ static int sdma_config_channel(struct dma_chan *chan)
sdmac->watermark_level = 0; /* FIXME: M3_BASE_ADDRESS */
}
+ sdmac->context_loaded = false;
+
ret = sdma_load_context(sdmac);
return ret;
@@ -1068,52 +1267,191 @@ static int sdma_set_channel_priority(struct sdma_channel *sdmac,
return 0;
}
-static int sdma_request_channel(struct sdma_channel *sdmac)
+static int sdma_alloc_bd(struct sdma_desc *desc)
{
- struct sdma_engine *sdma = sdmac->sdma;
- int channel = sdmac->channel;
- int ret = -EBUSY;
+ u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor);
+ int ret = -ENOMEM;
+ unsigned long flags;
- sdmac->bd = dma_zalloc_coherent(NULL, PAGE_SIZE, &sdmac->bd_phys,
- GFP_KERNEL);
- if (!sdmac->bd) {
- ret = -ENOMEM;
- goto out;
+ desc->bd_iram = true;
+ desc->bd = gen_pool_dma_alloc(desc->sdmac->sdma->iram_pool, bd_size,
+ &desc->bd_phys);
+ if (!desc->bd) {
+ desc->bd_iram = false;
+ desc->bd = dma_pool_alloc(desc->sdmac->bd_pool, GFP_ATOMIC,
+ &desc->bd_phys);
+ if (!desc->bd)
+ return ret;
+ }
+ spin_lock_irqsave(&desc->sdmac->vc.lock, flags);
+ desc->sdmac->bd_size_sum += bd_size;
+ spin_unlock_irqrestore(&desc->sdmac->vc.lock, flags);
+
+ memset(desc->bd, 0, bd_size);
+
+ return 0;
+}
+
+static void sdma_free_bd(struct sdma_desc *desc)
+{
+ u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor);
+ unsigned long flags;
+
+ if (desc->bd) {
+ if (desc->bd_iram)
+ gen_pool_free(desc->sdmac->sdma->iram_pool,
+ (unsigned long)desc->bd, bd_size);
+ else
+ dma_pool_free(desc->sdmac->bd_pool, desc->bd,
+ desc->bd_phys);
+ spin_lock_irqsave(&desc->sdmac->vc.lock, flags);
+ desc->sdmac->bd_size_sum -= bd_size;
+ spin_unlock_irqrestore(&desc->sdmac->vc.lock, flags);
+ }
+}
+
+static int sdma_request_channel0(struct sdma_engine *sdma)
+{
+ int ret = 0;
+
+ sdma->bd0_iram = true;
+ sdma->bd0 = gen_pool_dma_alloc(sdma->iram_pool, PAGE_SIZE, &sdma->bd0_phys);
+ if (!sdma->bd0) {
+ sdma->bd0_iram = false;
+ sdma->bd0 = dma_alloc_coherent(sdma->dev, PAGE_SIZE,
+ &sdma->bd0_phys, GFP_KERNEL);
+ if (!sdma->bd0) {
+ ret = -ENOMEM;
+ goto out;
+ }
}
- sdma->channel_control[channel].base_bd_ptr = sdmac->bd_phys;
- sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
+ memset(sdma->bd0, 0, PAGE_SIZE);
- sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY);
+ sdma->channel_control[0].base_bd_ptr = sdma->bd0_phys;
+ sdma->channel_control[0].current_bd_ptr = sdma->bd0_phys;
+
+ sdma_set_channel_priority(&sdma->channel[0], MXC_SDMA_DEFAULT_PRIORITY);
return 0;
out:
return ret;
}
-static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx)
+static struct sdma_desc *to_sdma_desc(struct dma_async_tx_descriptor *t)
{
+ return container_of(t, struct sdma_desc, vd.tx);
+}
+
+static void sdma_desc_free(struct virt_dma_desc *vd)
+{
+ struct sdma_desc *desc = container_of(vd, struct sdma_desc, vd);
+ if (desc) {
+ sdma_free_bd(desc);
+ kfree(desc);
+ }
+}
+
+static int sdma_channel_pause(struct dma_chan *chan)
+{
+ struct sdma_channel *sdmac = to_sdma_chan(chan);
unsigned long flags;
- struct sdma_channel *sdmac = to_sdma_chan(tx->chan);
- dma_cookie_t cookie;
- spin_lock_irqsave(&sdmac->lock, flags);
+ if (!(sdmac->flags & IMX_DMA_SG_LOOP))
+ return -EINVAL;
+
+ sdma_disable_channel(chan);
+ spin_lock_irqsave(&sdmac->vc.lock, flags);
+ sdmac->status = DMA_PAUSED;
+ spin_unlock_irqrestore(&sdmac->vc.lock, flags);
- cookie = dma_cookie_assign(tx);
+ return 0;
+}
- spin_unlock_irqrestore(&sdmac->lock, flags);
+static int sdma_channel_resume(struct dma_chan *chan)
+{
+ struct sdma_channel *sdmac = to_sdma_chan(chan);
+ struct sdma_engine *sdma = sdmac->sdma;
+ unsigned long flags;
- return cookie;
+ if (!(sdmac->flags & IMX_DMA_SG_LOOP))
+ return -EINVAL;
+
+ /*
+ * restore back context since context may loss if mega/fast OFF
+ */
+ if (sdma->suspend_off) {
+ if (sdma_load_context(sdmac)) {
+ dev_err(sdmac->sdma->dev, "context load failed.\n");
+ return -EINVAL;
+ }
+ }
+
+ sdma_enable_channel(sdmac->sdma, sdmac->channel);
+ spin_lock_irqsave(&sdmac->vc.lock, flags);
+ sdmac->status = DMA_IN_PROGRESS;
+ spin_unlock_irqrestore(&sdmac->vc.lock, flags);
+
+ return 0;
+}
+
+static int sdma_terminate_all(struct dma_chan *chan)
+{
+ struct sdma_channel *sdmac = to_sdma_chan(chan);
+ unsigned long flags;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&sdmac->vc.lock, flags);
+ vchan_get_all_descriptors(&sdmac->vc, &head);
+ while (!list_empty(&sdmac->pending)) {
+ struct sdma_desc *desc = list_first_entry(&sdmac->pending,
+ struct sdma_desc, node);
+
+ list_del(&desc->node);
+ spin_unlock_irqrestore(&sdmac->vc.lock, flags);
+ sdmac->vc.desc_free(&desc->vd);
+ spin_lock_irqsave(&sdmac->vc.lock, flags);
+ }
+ if (sdmac->desc)
+ sdmac->desc = NULL;
+ spin_unlock_irqrestore(&sdmac->vc.lock, flags);
+ vchan_dma_desc_free_list(&sdmac->vc, &head);
+ sdma_disable_channel(chan);
+ sdmac->context_loaded = false;
+
+ return 0;
}
static int sdma_alloc_chan_resources(struct dma_chan *chan)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
struct imx_dma_data *data = chan->private;
+ struct imx_dma_data default_data;
int prio, ret;
- if (!data)
- return -EINVAL;
+ ret = clk_enable(sdmac->sdma->clk_ipg);
+ if (ret)
+ return ret;
+ ret = clk_enable(sdmac->sdma->clk_ahb);
+ if (ret)
+ goto disable_clk_ipg;
+
+ /*
+ * dmatest(memcpy) will never call slave_config before prep, so we need
+ * do some job in slave_config in this case.
+ */
+ if (!data) {
+ sdmac->word_size = sdmac->sdma->dma_device.copy_align;
+ default_data.priority = 2;
+ default_data.peripheral_type = IMX_DMATYPE_MEMORY;
+ default_data.dma_request = 0;
+ default_data.dma_request2 = 0;
+ data = &default_data;
+
+ sdma_config_ownership(sdmac, false, true, false);
+ sdma_get_pc(sdmac, IMX_DMATYPE_MEMORY);
+ sdma_load_context(sdmac);
+ }
switch (data->priority) {
case DMA_PRIO_HIGH:
@@ -1131,26 +1469,23 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
sdmac->peripheral_type = data->peripheral_type;
sdmac->event_id0 = data->dma_request;
sdmac->event_id1 = data->dma_request2;
-
- ret = clk_enable(sdmac->sdma->clk_ipg);
- if (ret)
- return ret;
- ret = clk_enable(sdmac->sdma->clk_ahb);
- if (ret)
- goto disable_clk_ipg;
-
- ret = sdma_request_channel(sdmac);
- if (ret)
- goto disable_clk_ahb;
+ sdmac->src_dualfifo = data->src_dualfifo;
+ sdmac->dst_dualfifo = data->dst_dualfifo;
+ /* Get software done selector if sw_done enabled */
+ if (data->done_sel & BIT(31)) {
+ sdmac->sw_done = true;
+ sdmac->sw_done_sel = (data->done_sel >> 8) & 0xff;
+ }
ret = sdma_set_channel_priority(sdmac, prio);
if (ret)
goto disable_clk_ahb;
- dma_async_tx_descriptor_init(&sdmac->desc, chan);
- sdmac->desc.tx_submit = sdma_tx_submit;
- /* txd.flags will be overwritten in prep funcs */
- sdmac->desc.flags = DMA_CTRL_ACK;
+ sdmac->bd_size_sum = 0;
+
+ sdmac->bd_pool = dma_pool_create("bd_pool", chan->device->dev,
+ sizeof(struct sdma_buffer_descriptor),
+ 32, 0);
return 0;
@@ -1166,10 +1501,9 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
struct sdma_channel *sdmac = to_sdma_chan(chan);
struct sdma_engine *sdma = sdmac->sdma;
- sdma_disable_channel(chan);
+ sdma_terminate_all(chan);
- if (sdmac->event_id0)
- sdma_event_disable(sdmac, sdmac->event_id0);
+ sdma_event_disable(sdmac, sdmac->event_id0);
if (sdmac->event_id1)
sdma_event_disable(sdmac, sdmac->event_id1);
@@ -1178,115 +1512,242 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
sdma_set_channel_priority(sdmac, 0);
- dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys);
-
clk_disable(sdma->clk_ipg);
clk_disable(sdma->clk_ahb);
+
+ dma_pool_destroy(sdmac->bd_pool);
+ sdmac->bd_pool = NULL;
}
-static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
- struct dma_chan *chan, struct scatterlist *sgl,
- unsigned int sg_len, enum dma_transfer_direction direction,
- unsigned long flags, void *context)
+static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac,
+ enum dma_transfer_direction direction, u32 bds)
+{
+ struct sdma_desc *desc;
+ /* Now allocate and setup the descriptor. */
+ desc = kzalloc((sizeof(*desc)), GFP_ATOMIC);
+ if (!desc)
+ goto err_out;
+
+ sdmac->status = DMA_IN_PROGRESS;
+ sdmac->direction = direction;
+ sdmac->flags = 0;
+ sdmac->chn_count = 0;
+ sdmac->chn_real_count = 0;
+
+ desc->sdmac = sdmac;
+ desc->num_bd = bds;
+ INIT_LIST_HEAD(&desc->node);
+
+ if (sdma_alloc_bd(desc))
+ goto err_desc_out;
+
+ if (sdma_load_context(sdmac))
+ goto err_desc_out;
+
+ return desc;
+
+err_desc_out:
+ kfree(desc);
+err_out:
+ return NULL;
+}
+
+static int check_bd_buswidth(struct sdma_buffer_descriptor *bd,
+ struct sdma_channel *sdmac, int count,
+ dma_addr_t dma_dst, dma_addr_t dma_src)
+{
+ int ret = 0;
+
+ switch (sdmac->word_size) {
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ bd->mode.command = 0;
+ if ((count | dma_dst | dma_src) & 3)
+ ret = -EINVAL;
+ break;
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
+ bd->mode.command = 2;
+ if ((count | dma_dst | dma_src) & 1)
+ ret = -EINVAL;
+ break;
+ case DMA_SLAVE_BUSWIDTH_1_BYTE:
+ bd->mode.command = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static struct dma_async_tx_descriptor *sdma_prep_memcpy(
+ struct dma_chan *chan, dma_addr_t dma_dst,
+ dma_addr_t dma_src, size_t len, unsigned long flags)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
struct sdma_engine *sdma = sdmac->sdma;
- int ret, i, count;
int channel = sdmac->channel;
- struct scatterlist *sg;
+ size_t count;
+ int i = 0, param;
+ struct sdma_buffer_descriptor *bd;
+ struct sdma_desc *desc;
- if (sdmac->status == DMA_IN_PROGRESS)
+ if (!chan || !len)
return NULL;
- sdmac->status = DMA_IN_PROGRESS;
- sdmac->flags = 0;
+ dev_dbg(sdma->dev, "memcpy: %pad->%pad, len=%zu, channel=%d.\n",
+ &dma_src, &dma_dst, len, channel);
- sdmac->buf_tail = 0;
- sdmac->buf_ptail = 0;
- sdmac->chn_real_count = 0;
+ desc = sdma_transfer_init(sdmac, DMA_MEM_TO_MEM, len / SDMA_BD_MAX_CNT + 1);
+ if (!desc)
+ goto err_out;
- dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n",
- sg_len, channel);
+ do {
+ count = min_t(size_t, len, SDMA_BD_MAX_CNT);
+ bd = &desc->bd[i];
+ bd->buffer_addr = dma_src;
+ bd->ext_buffer_addr = dma_dst;
+ bd->mode.count = count;
+ sdmac->chn_count += count;
- sdmac->direction = direction;
- ret = sdma_load_context(sdmac);
- if (ret)
- goto err_out;
+ if (check_bd_buswidth(bd, sdmac, count, dma_dst, dma_src))
+ goto err_bd_out;
- if (sg_len > NUM_BD) {
- dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
- channel, sg_len, NUM_BD);
- ret = -EINVAL;
+ dma_src += count;
+ dma_dst += count;
+ len -= count;
+ i++;
+
+ param = BD_DONE | BD_EXTD | BD_CONT;
+ /* last bd */
+ if (!len) {
+ param |= BD_INTR;
+ param |= BD_LAST;
+ param &= ~BD_CONT;
+ }
+
+ dev_dbg(sdma->dev, "entry %d: count: %zd dma: 0x%x %s%s\n",
+ i, count, bd->buffer_addr,
+ param & BD_WRAP ? "wrap" : "",
+ param & BD_INTR ? " intr" : "");
+
+ bd->mode.status = param;
+ } while (len);
+
+ return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
+err_bd_out:
+ sdma_free_bd(desc);
+ kfree(desc);
+err_out:
+ return NULL;
+}
+
+/*
+ * Please ensure dst_nents no smaller than src_nents , also every sg_len of
+ * dst_sg node no smaller than src_sg. To simply things, please use the same
+ * size of dst_sg as src_sg.
+ */
+static struct dma_async_tx_descriptor *sdma_prep_sg(
+ struct dma_chan *chan,
+ struct scatterlist *dst_sg, unsigned int dst_nents,
+ struct scatterlist *src_sg, unsigned int src_nents,
+ enum dma_transfer_direction direction, unsigned long flags)
+{
+ struct sdma_channel *sdmac = to_sdma_chan(chan);
+ struct sdma_engine *sdma = sdmac->sdma;
+ int ret, i, count;
+ int channel = sdmac->channel;
+ struct scatterlist *sg_src = src_sg, *sg_dst = dst_sg;
+ struct sdma_desc *desc;
+
+ if (!chan)
+ return NULL;
+
+ dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n",
+ src_nents, channel);
+
+ desc = sdma_transfer_init(sdmac, direction, src_nents);
+ if (!desc)
goto err_out;
- }
- sdmac->chn_count = 0;
- for_each_sg(sgl, sg, sg_len, i) {
- struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
+ for_each_sg(src_sg, sg_src, src_nents, i) {
+ struct sdma_buffer_descriptor *bd = &desc->bd[i];
int param;
- bd->buffer_addr = sg->dma_address;
+ bd->buffer_addr = sg_src->dma_address;
+
+ if (direction == DMA_MEM_TO_MEM) {
+ BUG_ON(!sg_dst);
+ bd->ext_buffer_addr = sg_dst->dma_address;
+ }
- count = sg_dma_len(sg);
+ count = sg_dma_len(sg_src);
- if (count > 0xffff) {
+ if (count > SDMA_BD_MAX_CNT) {
dev_err(sdma->dev, "SDMA channel %d: maximum bytes for sg entry exceeded: %d > %d\n",
- channel, count, 0xffff);
+ channel, count, SDMA_BD_MAX_CNT);
ret = -EINVAL;
- goto err_out;
+ goto err_bd_out;
}
bd->mode.count = count;
sdmac->chn_count += count;
- if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) {
- ret = -EINVAL;
- goto err_out;
- }
-
- switch (sdmac->word_size) {
- case DMA_SLAVE_BUSWIDTH_4_BYTES:
- bd->mode.command = 0;
- if (count & 3 || sg->dma_address & 3)
- return NULL;
- break;
- case DMA_SLAVE_BUSWIDTH_2_BYTES:
- bd->mode.command = 2;
- if (count & 1 || sg->dma_address & 1)
- return NULL;
- break;
- case DMA_SLAVE_BUSWIDTH_1_BYTE:
- bd->mode.command = 1;
- break;
- default:
- return NULL;
- }
+ if (direction == DMA_MEM_TO_MEM)
+ ret = check_bd_buswidth(bd, sdmac, count,
+ sg_dst->dma_address,
+ sg_src->dma_address);
+ else
+ ret = check_bd_buswidth(bd, sdmac, count, 0,
+ sg_src->dma_address);
+ if (ret)
+ goto err_bd_out;
param = BD_DONE | BD_EXTD | BD_CONT;
- if (i + 1 == sg_len) {
+ if (i + 1 == src_nents) {
param |= BD_INTR;
param |= BD_LAST;
param &= ~BD_CONT;
}
- dev_dbg(sdma->dev, "entry %d: count: %d dma: %#llx %s%s\n",
- i, count, (u64)sg->dma_address,
+ dev_dbg(sdma->dev, "entry %d: count: %d dma: 0x%pad %s%s\n",
+ i, count, &sg_src->dma_address,
param & BD_WRAP ? "wrap" : "",
param & BD_INTR ? " intr" : "");
bd->mode.status = param;
+ if (direction == DMA_MEM_TO_MEM)
+ sg_dst = sg_next(sg_dst);
}
- sdmac->num_bd = sg_len;
- sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
+ return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
- return &sdmac->desc;
+err_bd_out:
+ sdma_free_bd(desc);
+ kfree(desc);
err_out:
- sdmac->status = DMA_ERROR;
+ dev_dbg(sdma->dev, "Can't get desc.\n");
return NULL;
}
+static struct dma_async_tx_descriptor *sdma_prep_memcpy_sg(
+ struct dma_chan *chan,
+ struct scatterlist *dst_sg, unsigned int dst_nents,
+ struct scatterlist *src_sg, unsigned int src_nents,
+ unsigned long flags)
+{
+ return sdma_prep_sg(chan, dst_sg, dst_nents, src_sg, src_nents,
+ DMA_MEM_TO_MEM, flags);
+}
+
+static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction direction,
+ unsigned long flags, void *context)
+{
+ return sdma_prep_sg(chan, NULL, 0, sgl, sg_len, direction, flags);
+}
+
static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
size_t period_len, enum dma_transfer_direction direction,
@@ -1294,42 +1755,42 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
struct sdma_engine *sdma = sdmac->sdma;
- int num_periods = buf_len / period_len;
int channel = sdmac->channel;
- int ret, i = 0, buf = 0;
+ int i = 0, buf = 0;
+ int num_periods = 0;
+ struct sdma_desc *desc;
dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
- if (sdmac->status == DMA_IN_PROGRESS)
- return NULL;
-
- sdmac->status = DMA_IN_PROGRESS;
+ if (sdmac->peripheral_type != IMX_DMATYPE_HDMI)
+ num_periods = buf_len / period_len;
+ /* Now allocate and setup the descriptor. */
+ desc = sdma_transfer_init(sdmac, direction, num_periods);
+ if (!desc)
+ goto err_out;
- sdmac->buf_tail = 0;
- sdmac->buf_ptail = 0;
- sdmac->chn_real_count = 0;
sdmac->period_len = period_len;
-
sdmac->flags |= IMX_DMA_SG_LOOP;
- sdmac->direction = direction;
- ret = sdma_load_context(sdmac);
- if (ret)
- goto err_out;
- if (num_periods > NUM_BD) {
- dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
- channel, num_periods, NUM_BD);
- goto err_out;
- }
+ /* for hdmi-audio without BDs */
+ if (sdmac->peripheral_type == IMX_DMATYPE_HDMI)
+ return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
- if (period_len > 0xffff) {
- dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %d > %d\n",
- channel, period_len, 0xffff);
- goto err_out;
+ desc->buf_tail = 0;
+ desc->buf_ptail = 0;
+ sdmac->chn_real_count = 0;
+
+ if (period_len > SDMA_BD_MAX_CNT) {
+ dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %zu > %d\n",
+ channel, period_len, SDMA_BD_MAX_CNT);
+ goto err_bd_out;
}
+ if (sdmac->peripheral_type == IMX_DMATYPE_UART)
+ sdmac->chn_count = period_len;
+
while (buf < buf_len) {
- struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
+ struct sdma_buffer_descriptor *bd = &desc->bd[i];
int param;
bd->buffer_addr = dma_addr;
@@ -1337,7 +1798,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
bd->mode.count = period_len;
if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES)
- goto err_out;
+ goto err_bd_out;
if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES)
bd->mode.command = 0;
else
@@ -1347,8 +1808,8 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
if (i + 1 == num_periods)
param |= BD_WRAP;
- dev_dbg(sdma->dev, "entry %d: count: %d dma: %#llx %s%s\n",
- i, period_len, (u64)dma_addr,
+ dev_dbg(sdma->dev, "entry %d: count: %zd dma: %pad %s%s\n",
+ i, period_len, &dma_addr,
param & BD_WRAP ? "wrap" : "",
param & BD_INTR ? " intr" : "");
@@ -1359,13 +1820,12 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
i++;
}
+ return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
- sdmac->num_bd = num_periods;
- sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
-
- return &sdmac->desc;
+err_bd_out:
+ sdma_free_bd(desc);
+ kfree(desc);
err_out:
- sdmac->status = DMA_ERROR;
return NULL;
}
@@ -1373,12 +1833,14 @@ static int sdma_config(struct dma_chan *chan,
struct dma_slave_config *dmaengine_cfg)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
-
+ /* clear watermark_level before setting */
+ sdmac->watermark_level = 0;
if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
sdmac->per_address = dmaengine_cfg->src_addr;
sdmac->watermark_level = dmaengine_cfg->src_maxburst *
dmaengine_cfg->src_addr_width;
sdmac->word_size = dmaengine_cfg->src_addr_width;
+ sdmac->fifo_num = dmaengine_cfg->src_fifo_num;
} else if (dmaengine_cfg->direction == DMA_DEV_TO_DEV) {
sdmac->per_address2 = dmaengine_cfg->src_addr;
sdmac->per_address = dmaengine_cfg->dst_addr;
@@ -1387,48 +1849,115 @@ static int sdma_config(struct dma_chan *chan,
sdmac->watermark_level |= (dmaengine_cfg->dst_maxburst << 16) &
SDMA_WATERMARK_LEVEL_HWML;
sdmac->word_size = dmaengine_cfg->dst_addr_width;
+ } else if (sdmac->peripheral_type == IMX_DMATYPE_HDMI) {
+ sdmac->per_address = dmaengine_cfg->dst_addr;
+ sdmac->per_address2 = dmaengine_cfg->src_addr;
+ sdmac->watermark_level = 0;
+ } else if (dmaengine_cfg->direction == DMA_MEM_TO_MEM) {
+ sdmac->word_size = dmaengine_cfg->dst_addr_width;
} else {
sdmac->per_address = dmaengine_cfg->dst_addr;
sdmac->watermark_level = dmaengine_cfg->dst_maxburst *
dmaengine_cfg->dst_addr_width;
sdmac->word_size = dmaengine_cfg->dst_addr_width;
+ sdmac->fifo_num = dmaengine_cfg->dst_fifo_num;
}
sdmac->direction = dmaengine_cfg->direction;
return sdma_config_channel(chan);
}
+static void sdma_wait_tasklet(struct dma_chan *chan)
+{
+ struct sdma_channel *sdmac = to_sdma_chan(chan);
+
+ tasklet_kill(&sdmac->vc.task);
+}
+
static enum dma_status sdma_tx_status(struct dma_chan *chan,
dma_cookie_t cookie,
struct dma_tx_state *txstate)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
u32 residue;
+ struct virt_dma_desc *vd;
+ struct sdma_desc *desc;
+ enum dma_status ret;
+ unsigned long flags;
- if (sdmac->flags & IMX_DMA_SG_LOOP)
- residue = (sdmac->num_bd - sdmac->buf_ptail) *
- sdmac->period_len - sdmac->chn_real_count;
- else
+ ret = dma_cookie_status(chan, cookie, txstate);
+ if (!txstate) {
+ return ret;
+ } else if (ret == DMA_COMPLETE) {
+ spin_lock_irqsave(&sdmac->vc.lock, flags);
+ txstate->residue = sdmac->chn_count - sdmac->chn_real_count;
+ spin_unlock_irqrestore(&sdmac->vc.lock, flags);
+ return ret;
+ }
+
+ spin_lock_irqsave(&sdmac->vc.lock, flags);
+ vd = vchan_find_desc(&sdmac->vc, cookie);
+ desc = to_sdma_desc(&vd->tx);
+ if (vd) {
+ if ((sdmac->flags & IMX_DMA_SG_LOOP)) {
+ if (sdmac->peripheral_type != IMX_DMATYPE_UART)
+ residue = (desc->num_bd - desc->buf_ptail) *
+ sdmac->period_len - sdmac->chn_real_count;
+ else
+ residue = sdmac->chn_count - sdmac->chn_real_count;
+ } else
+ residue = sdmac->chn_count;
+ } else if (sdmac->desc && sdmac->desc->vd.tx.cookie == cookie)
residue = sdmac->chn_count - sdmac->chn_real_count;
+ else
+ residue = 0;
+
+ txstate->residue = residue;
+ ret = sdmac->status;
+ spin_unlock_irqrestore(&sdmac->vc.lock, flags);
+
+ return ret;
+}
- dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
- residue);
+static void sdma_start_desc(struct sdma_channel *sdmac)
+{
+ struct virt_dma_desc *vd = vchan_next_desc(&sdmac->vc);
+ struct sdma_desc *desc;
+ struct sdma_engine *sdma = sdmac->sdma;
+ int channel = sdmac->channel;
- return sdmac->status;
+ if (!vd) {
+ sdmac->desc = NULL;
+ return;
+ }
+ sdmac->desc = desc = to_sdma_desc(&vd->tx);
+ /*
+ * Do not delete the node in desc_issued list in cyclic mode, otherwise
+ * the desc alloced will never be freed in vchan_dma_desc_free_list
+ */
+ if (!(sdmac->flags & IMX_DMA_SG_LOOP)) {
+ list_add_tail(&sdmac->desc->node, &sdmac->pending);
+ list_del(&vd->node);
+ }
+ sdma->channel_control[channel].base_bd_ptr = desc->bd_phys;
+ sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
+ sdma_enable_channel(sdma, sdmac->channel);
}
static void sdma_issue_pending(struct dma_chan *chan)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
- struct sdma_engine *sdma = sdmac->sdma;
+ unsigned long flags;
- if (sdmac->status == DMA_IN_PROGRESS)
- sdma_enable_channel(sdma, sdmac->channel);
+ spin_lock_irqsave(&sdmac->vc.lock, flags);
+ if (vchan_issue_pending(&sdmac->vc) && !sdmac->desc)
+ sdma_start_desc(sdmac);
+ spin_unlock_irqrestore(&sdmac->vc.lock, flags);
}
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2 38
#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3 41
-#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V4 42
+#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V4 44
static void sdma_add_scripts(struct sdma_engine *sdma,
const struct sdma_script_start_addrs *addr)
@@ -1588,7 +2117,7 @@ static int sdma_get_firmware(struct sdma_engine *sdma,
static int sdma_init(struct sdma_engine *sdma)
{
- int i, ret;
+ int i, ret, ccbsize;
dma_addr_t ccb_phys;
ret = clk_enable(sdma->clk_ipg);
@@ -1601,14 +2130,17 @@ static int sdma_init(struct sdma_engine *sdma)
/* Be sure SDMA has not started yet */
writel_relaxed(0, sdma->regs + SDMA_H_C0PTR);
- sdma->channel_control = dma_alloc_coherent(NULL,
- MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control) +
- sizeof(struct sdma_context_data),
- &ccb_phys, GFP_KERNEL);
+ ccbsize = MAX_DMA_CHANNELS * (sizeof(struct sdma_channel_control)
+ + sizeof(struct sdma_context_data));
+ sdma->channel_control = gen_pool_dma_alloc(sdma->iram_pool, ccbsize, &ccb_phys);
if (!sdma->channel_control) {
- ret = -ENOMEM;
- goto err_dma_alloc;
+ sdma->channel_control = dma_alloc_coherent(sdma->dev, ccbsize,
+ &ccb_phys, GFP_KERNEL);
+ if (!sdma->channel_control) {
+ ret = -ENOMEM;
+ goto err_dma_alloc;
+ }
}
sdma->context = (void *)sdma->channel_control +
@@ -1628,7 +2160,7 @@ static int sdma_init(struct sdma_engine *sdma)
for (i = 0; i < MAX_DMA_CHANNELS; i++)
writel_relaxed(0, sdma->regs + SDMA_CHNPRI_0 + i * 4);
- ret = sdma_request_channel(&sdma->channel[0]);
+ ret = sdma_request_channel0(sdma);
if (ret)
goto err_dma_alloc;
@@ -1639,7 +2171,10 @@ static int sdma_init(struct sdma_engine *sdma)
/* Set bits of CONFIG register but with static context switching */
/* FIXME: Check whether to set ACR bit depending on clock ratios */
- writel_relaxed(0, sdma->regs + SDMA_H_CONFIG);
+ if (sdma->clk_ratio)
+ writel_relaxed(SDMA_H_CONFIG_ACR, sdma->regs + SDMA_H_CONFIG);
+ else
+ writel_relaxed(0, sdma->regs + SDMA_H_CONFIG);
writel_relaxed(ccb_phys, sdma->regs + SDMA_H_C0PTR);
@@ -1666,6 +2201,10 @@ static bool sdma_filter_fn(struct dma_chan *chan, void *fn_param)
if (!imx_dma_is_general_purpose(chan))
return false;
+ /* return false if it's not the right device */
+ if ((sdmac->sdma->drvdata == &sdma_imx8m)
+ && (sdmac->sdma->idx != data->idx))
+ return false;
sdmac->data = *data;
chan->private = &sdmac->data;
@@ -1683,17 +2222,15 @@ static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec,
if (dma_spec->args_count != 3)
return NULL;
+ memset(&data, 0, sizeof(data));
+
data.dma_request = dma_spec->args[0];
data.peripheral_type = dma_spec->args[1];
- data.priority = dma_spec->args[2];
- /*
- * init dma_request2 to zero, which is not used by the dts.
- * For P2P, dma_request2 is init from dma_request_channel(),
- * chan->private will point to the imx_dma_data, and in
- * device_alloc_chan_resources(), imx_dma_data.dma_request2 will
- * be set to sdmac->event_id1.
- */
- data.dma_request2 = 0;
+ /* Get sw_done setting if sw_done enabled */
+ if (dma_spec->args[2] & BIT(31))
+ data.done_sel = dma_spec->args[2];
+ data.priority = dma_spec->args[2] & 0xff;
+ data.idx = sdma->idx;
return dma_request_channel(mask, sdma_filter_fn, &data);
}
@@ -1733,6 +2270,8 @@ static int sdma_probe(struct platform_device *pdev)
if (!sdma)
return -ENOMEM;
+ sdma->clk_ratio = of_property_read_bool(np, "fsl,ratio-1-1");
+
spin_lock_init(&sdma->channel_0_lock);
sdma->dev = &pdev->dev;
@@ -1783,6 +2322,7 @@ static int sdma_probe(struct platform_device *pdev)
dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
+ dma_cap_set(DMA_MEMCPY, sdma->dma_device.cap_mask);
INIT_LIST_HEAD(&sdma->dma_device.channels);
/* Initialize channel parameters */
@@ -1790,24 +2330,26 @@ static int sdma_probe(struct platform_device *pdev)
struct sdma_channel *sdmac = &sdma->channel[i];
sdmac->sdma = sdma;
- spin_lock_init(&sdmac->lock);
-
- sdmac->chan.device = &sdma->dma_device;
- dma_cookie_init(&sdmac->chan);
+ sdmac->context_loaded = false;
sdmac->channel = i;
+ sdmac->status = DMA_IN_PROGRESS;
+ sdmac->vc.desc_free = sdma_desc_free;
+ INIT_LIST_HEAD(&sdmac->pending);
- tasklet_init(&sdmac->tasklet, mxc_sdma_handle_channel_normal,
- (unsigned long) sdmac);
/*
* Add the channel to the DMAC list. Do not add channel 0 though
* because we need it internally in the SDMA driver. This also means
* that channel 0 in dmaengine counting matches sdma channel 1.
*/
if (i)
- list_add_tail(&sdmac->chan.device_node,
- &sdma->dma_device.channels);
+ vchan_init(&sdmac->vc, &sdma->dma_device);
}
+ if (np)
+ sdma->iram_pool = of_gen_pool_get(np, "iram", 0);
+ if (!sdma->iram_pool)
+ dev_warn(&pdev->dev, "no iram assigned, using external mem\n");
+
ret = sdma_init(sdma);
if (ret)
goto err_init;
@@ -1841,23 +2383,30 @@ static int sdma_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "failed to get firmware from device tree\n");
}
}
+ sdma->fw_name = fw_name;
sdma->dma_device.dev = &pdev->dev;
sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources;
sdma->dma_device.device_free_chan_resources = sdma_free_chan_resources;
sdma->dma_device.device_tx_status = sdma_tx_status;
+ sdma->dma_device.device_synchronize = sdma_wait_tasklet;
sdma->dma_device.device_prep_slave_sg = sdma_prep_slave_sg;
sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic;
sdma->dma_device.device_config = sdma_config;
- sdma->dma_device.device_terminate_all = sdma_disable_channel_with_delay;
- sdma->dma_device.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
- sdma->dma_device.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
- sdma->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ sdma->dma_device.device_terminate_all = sdma_terminate_all;
+ sdma->dma_device.device_pause = sdma_channel_pause;
+ sdma->dma_device.device_resume = sdma_channel_resume;
+ sdma->dma_device.src_addr_widths = SDMA_DMA_BUSWIDTHS;
+ sdma->dma_device.dst_addr_widths = SDMA_DMA_BUSWIDTHS;
+ sdma->dma_device.directions = SDMA_DMA_DIRECTIONS;
sdma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+ sdma->dma_device.device_prep_dma_memcpy = sdma_prep_memcpy;
+ sdma->dma_device.device_prep_dma_sg = sdma_prep_memcpy_sg;
sdma->dma_device.device_issue_pending = sdma_issue_pending;
sdma->dma_device.dev->dma_parms = &sdma->dma_parms;
- dma_set_max_seg_size(sdma->dma_device.dev, 65535);
+ sdma->dma_device.copy_align = 2;
+ dma_set_max_seg_size(sdma->dma_device.dev, SDMA_BD_MAX_CNT);
platform_set_drvdata(pdev, sdma);
@@ -1882,6 +2431,8 @@ static int sdma_probe(struct platform_device *pdev)
}
of_node_put(spba_bus);
}
+ /* There maybe multi sdma devices such as i.mx8mscale */
+ sdma->idx = sdma_dev_idx++;
return 0;
@@ -1910,17 +2461,124 @@ static int sdma_remove(struct platform_device *pdev)
for (i = 0; i < MAX_DMA_CHANNELS; i++) {
struct sdma_channel *sdmac = &sdma->channel[i];
- tasklet_kill(&sdmac->tasklet);
+ tasklet_kill(&sdmac->vc.task);
+ sdma_free_chan_resources(&sdmac->vc.chan);
}
platform_set_drvdata(pdev, NULL);
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int sdma_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sdma_engine *sdma = platform_get_drvdata(pdev);
+ int i, ret = 0;
+
+ sdma->suspend_off = false;
+
+ /* Do nothing if not i.MX6SX or i.MX7D*/
+ if (sdma->drvdata != &sdma_imx6sx && sdma->drvdata != &sdma_imx7d
+ && sdma->drvdata != &sdma_imx6ul)
+ return 0;
+
+ clk_enable(sdma->clk_ipg);
+ clk_enable(sdma->clk_ahb);
+
+ ret = sdma_save_restore_context(sdma, true);
+ if (ret) {
+ dev_err(sdma->dev, "save context error!\n");
+ return ret;
+ }
+ /* save regs */
+ for (i = 0; i < MXC_SDMA_SAVED_REG_NUM; i++) {
+ /*
+ * 0x78(SDMA_XTRIG_CONF2+4)~0x100(SDMA_CHNPRI_O) registers are
+ * reserved and can't be touched. Skip these regs.
+ */
+ if (i > SDMA_XTRIG_CONF2 / 4)
+ sdma->save_regs[i] = readl_relaxed(sdma->regs +
+ MXC_SDMA_RESERVED_REG
+ + 4 * i);
+ else
+ sdma->save_regs[i] = readl_relaxed(sdma->regs + 4 * i);
+ }
+
+ clk_disable(sdma->clk_ipg);
+ clk_disable(sdma->clk_ahb);
+
+ return 0;
+}
+
+static int sdma_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sdma_engine *sdma = platform_get_drvdata(pdev);
+ int i, ret;
+
+ /* Do nothing if not i.MX6SX or i.MX7D*/
+ if (sdma->drvdata != &sdma_imx6sx && sdma->drvdata != &sdma_imx7d
+ && sdma->drvdata != &sdma_imx6ul)
+ return 0;
+
+ clk_enable(sdma->clk_ipg);
+ clk_enable(sdma->clk_ahb);
+ /* Do nothing if mega/fast mix not turned off */
+ if (readl_relaxed(sdma->regs + SDMA_H_C0PTR)) {
+ clk_disable(sdma->clk_ipg);
+ clk_disable(sdma->clk_ahb);
+ return 0;
+ }
+
+ sdma->suspend_off = true;
+
+ /* restore regs and load firmware */
+ for (i = 0; i < MXC_SDMA_SAVED_REG_NUM; i++) {
+ /*
+ * 0x78(SDMA_XTRIG_CONF2+4)~0x100(SDMA_CHNPRI_O) registers are
+ * reserved and can't be touched. Skip these regs.
+ */
+ if (i > SDMA_XTRIG_CONF2 / 4)
+ writel_relaxed(sdma->save_regs[i], sdma->regs +
+ MXC_SDMA_RESERVED_REG + 4 * i);
+ else
+ writel_relaxed(sdma->save_regs[i] , sdma->regs + 4 * i);
+ }
+
+ /* prepare priority for channel0 to start */
+ sdma_set_channel_priority(&sdma->channel[0], MXC_SDMA_DEFAULT_PRIORITY);
+
+ ret = sdma_get_firmware(sdma, sdma->fw_name);
+ if (ret) {
+ dev_warn(&pdev->dev, "failed to get firware\n");
+ goto out;
+ }
+
+ ret = sdma_save_restore_context(sdma, false);
+ if (ret) {
+ dev_err(sdma->dev, "restore context error!\n");
+ goto out;
+ }
+
+ ret = 0;
+out:
+ clk_disable(sdma->clk_ipg);
+ clk_disable(sdma->clk_ahb);
+
+ return ret;
+}
+#endif
+
+static const struct dev_pm_ops sdma_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(sdma_suspend, sdma_resume)
+};
+
static struct platform_driver sdma_driver = {
.driver = {
.name = "imx-sdma",
.of_match_table = sdma_dt_ids,
+ .pm = &sdma_pm_ops,
},
.id_table = sdma_devtypes,
.remove = sdma_remove,
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index e217268c7098..1b829d59d2a1 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -1,5 +1,6 @@
/*
- * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2017 NXP
*
* Refer to drivers/dma/imx-sdma.c
*
@@ -28,8 +29,8 @@
#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <linux/list.h>
-
#include <asm/irq.h>
+#include <linux/pm_runtime.h>
#include "dmaengine.h"
@@ -42,6 +43,8 @@
#define dma_is_apbh(mxs_dma) ((mxs_dma)->type == MXS_DMA_APBH)
#define apbh_is_old(mxs_dma) ((mxs_dma)->dev_id == IMX23_DMA)
+#define MXS_DMA_RPM_TIMEOUT 50 /* ms */
+
#define HW_APBHX_CTRL0 0x000
#define BM_APBH_CTRL0_APB_BURST8_EN (1 << 29)
#define BM_APBH_CTRL0_APB_BURST_EN (1 << 28)
@@ -135,6 +138,8 @@ enum mxs_dma_devtype {
enum mxs_dma_id {
IMX23_DMA,
IMX28_DMA,
+ IMX7D_DMA,
+ IMX8QXP_DMA,
};
struct mxs_dma_engine {
@@ -142,6 +147,7 @@ struct mxs_dma_engine {
enum mxs_dma_devtype type;
void __iomem *base;
struct clk *clk;
+ struct clk *clk_io;
struct dma_device dma_device;
struct device_dma_parameters dma_parms;
struct mxs_dma_chan mxs_chans[MXS_DMA_CHANNELS];
@@ -167,6 +173,12 @@ static struct mxs_dma_type mxs_dma_types[] = {
}, {
.id = IMX28_DMA,
.type = MXS_DMA_APBX,
+ }, {
+ .id = IMX7D_DMA,
+ .type = MXS_DMA_APBH,
+ }, {
+ .id = IMX8QXP_DMA,
+ .type = MXS_DMA_APBH,
}
};
@@ -184,6 +196,12 @@ static const struct platform_device_id mxs_dma_ids[] = {
.name = "imx28-dma-apbx",
.driver_data = (kernel_ulong_t) &mxs_dma_types[3],
}, {
+ .name = "imx7d-dma-apbh",
+ .driver_data = (kernel_ulong_t) &mxs_dma_types[4],
+ }, {
+ .name = "imx8qxp-dma-apbh",
+ .driver_data = (kernel_ulong_t) &mxs_dma_types[5],
+ }, {
/* end of list */
}
};
@@ -193,6 +211,8 @@ static const struct of_device_id mxs_dma_dt_ids[] = {
{ .compatible = "fsl,imx23-dma-apbx", .data = &mxs_dma_ids[1], },
{ .compatible = "fsl,imx28-dma-apbh", .data = &mxs_dma_ids[2], },
{ .compatible = "fsl,imx28-dma-apbx", .data = &mxs_dma_ids[3], },
+ { .compatible = "fsl,imx7d-dma-apbh", .data = &mxs_dma_ids[4], },
+ { .compatible = "fsl,imx8qxp-dma-apbh", .data = &mxs_dma_ids[5], },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mxs_dma_dt_ids);
@@ -418,6 +438,7 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
{
struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+ struct device *dev = &mxs_dma->pdev->dev;
int ret;
mxs_chan->ccw = dma_zalloc_coherent(mxs_dma->dma_device.dev,
@@ -433,9 +454,11 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
if (ret)
goto err_irq;
- ret = clk_prepare_enable(mxs_dma->clk);
- if (ret)
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable clock\n");
goto err_clk;
+ }
mxs_dma_reset_chan(chan);
@@ -460,6 +483,7 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan)
{
struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+ struct device *dev = &mxs_dma->pdev->dev;
mxs_dma_disable_chan(chan);
@@ -468,7 +492,9 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan)
dma_free_coherent(mxs_dma->dma_device.dev, CCW_BLOCK_SIZE,
mxs_chan->ccw, mxs_chan->ccw_phys);
- clk_disable_unprepare(mxs_dma->clk);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
}
/*
@@ -617,7 +643,7 @@ static struct dma_async_tx_descriptor *mxs_dma_prep_dma_cyclic(
if (period_len > MAX_XFER_BYTES) {
dev_err(mxs_dma->dma_device.dev,
- "maximum period size exceeded: %d > %d\n",
+ "maximum period size exceeded: %zu > %d\n",
period_len, MAX_XFER_BYTES);
goto err_out;
}
@@ -690,17 +716,35 @@ static enum dma_status mxs_dma_tx_status(struct dma_chan *chan,
return mxs_chan->status;
}
-static int __init mxs_dma_init(struct mxs_dma_engine *mxs_dma)
+static int mxs_dma_init_rpm(struct mxs_dma_engine *mxs_dma)
+{
+ struct device *dev = &mxs_dma->pdev->dev;
+
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, MXS_DMA_RPM_TIMEOUT);
+ pm_runtime_use_autosuspend(dev);
+
+ return 0;
+}
+
+static int mxs_dma_init(struct mxs_dma_engine *mxs_dma)
{
+ struct device *dev = &mxs_dma->pdev->dev;
int ret;
- ret = clk_prepare_enable(mxs_dma->clk);
+ ret = mxs_dma_init_rpm(mxs_dma);
if (ret)
return ret;
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable clock\n");
+ return ret;
+ }
+
ret = stmp_reset_block(mxs_dma->base);
if (ret)
- goto err_out;
+ goto err_clk;
/* enable apbh burst */
if (dma_is_apbh(mxs_dma)) {
@@ -714,8 +758,10 @@ static int __init mxs_dma_init(struct mxs_dma_engine *mxs_dma)
writel(MXS_DMA_CHANNELS_MASK << MXS_DMA_CHANNELS,
mxs_dma->base + HW_APBHX_CTRL1 + STMP_OFFSET_REG_SET);
-err_out:
- clk_disable_unprepare(mxs_dma->clk);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+err_clk:
return ret;
}
@@ -731,6 +777,9 @@ static bool mxs_dma_filter_fn(struct dma_chan *chan, void *fn_param)
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
int chan_irq;
+ if (!mxs_dma)
+ return false;
+
if (mxs_dma->dma_device.dev->of_node != param->of_node)
return false;
@@ -826,12 +875,15 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
&mxs_dma->dma_device.channels);
}
+ platform_set_drvdata(pdev, mxs_dma);
+ mxs_dma->pdev = pdev;
+
ret = mxs_dma_init(mxs_dma);
if (ret)
return ret;
- mxs_dma->pdev = pdev;
mxs_dma->dma_device.dev = &pdev->dev;
+ dev_set_drvdata(&pdev->dev, mxs_dma);
/* mxs_dma gets 65535 bytes maximum sg size */
mxs_dma->dma_device.dev->dma_parms = &mxs_dma->dma_parms;
@@ -869,9 +921,59 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
return 0;
}
+static int mxs_dma_pm_suspend(struct device *dev)
+{
+ int ret;
+
+ ret = pm_runtime_force_suspend(dev);
+
+ return ret;
+}
+
+static int mxs_dma_pm_resume(struct device *dev)
+{
+ struct mxs_dma_engine *mxs_dma = dev_get_drvdata(dev);
+ int ret;
+
+ ret = mxs_dma_init(mxs_dma);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int mxs_dma_runtime_suspend(struct device *dev)
+{
+ struct mxs_dma_engine *mxs_dma = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(mxs_dma->clk);
+
+ return 0;
+}
+
+int mxs_dma_runtime_resume(struct device *dev)
+{
+ struct mxs_dma_engine *mxs_dma = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(mxs_dma->clk);
+ if (ret) {
+ dev_err(&mxs_dma->pdev->dev, "failed to enable the clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops mxs_dma_pm_ops = {
+ SET_RUNTIME_PM_OPS(mxs_dma_runtime_suspend, mxs_dma_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(mxs_dma_pm_suspend, mxs_dma_pm_resume)
+};
+
static struct platform_driver mxs_dma_driver = {
.driver = {
.name = "mxs-dma",
+ .pm = &mxs_dma_pm_ops,
.of_match_table = mxs_dma_dt_ids,
},
.id_table = mxs_dma_ids,
diff --git a/drivers/dma/pxp/Kconfig b/drivers/dma/pxp/Kconfig
new file mode 100644
index 000000000000..76717f7d78e1
--- /dev/null
+++ b/drivers/dma/pxp/Kconfig
@@ -0,0 +1,22 @@
+config MXC_PXP_V2
+ bool "MXC PxP V2 support"
+ depends on ARM
+ select DMA_ENGINE
+ help
+ Support the PxP (Pixel Pipeline) on i.MX6 DualLite and i.MX6 SoloLite.
+ If unsure, select N.
+
+config MXC_PXP_V3
+ bool "MXC PxP V3 support"
+ depends on ARM
+ select DMA_ENGINE
+ help
+ Support the PxP V3(Pixel Pipeline) on i.MX7D. The PxP V3 supports
+ more functions than PxP V2, dithering, reagl/-D and etc.
+ If unsure, select N.
+
+config MXC_PXP_CLIENT_DEVICE
+ bool "MXC PxP Client Device"
+ default y
+ depends on MXC_PXP_V2 || MXC_PXP_V3
+
diff --git a/drivers/dma/pxp/Makefile b/drivers/dma/pxp/Makefile
new file mode 100644
index 000000000000..42e4ace02fbd
--- /dev/null
+++ b/drivers/dma/pxp/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_MXC_PXP_V2) += pxp_dma_v2.o
+obj-$(CONFIG_MXC_PXP_V3) += pxp_dma_v3.o
+obj-$(CONFIG_MXC_PXP_CLIENT_DEVICE) += pxp_device.o
diff --git a/drivers/dma/pxp/pxp_device.c b/drivers/dma/pxp/pxp_device.c
new file mode 100644
index 000000000000..a4a65a45d30c
--- /dev/null
+++ b/drivers/dma/pxp/pxp_device.c
@@ -0,0 +1,878 @@
+/*
+ * Copyright (C) 2010-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/pxp_device.h>
+#include <linux/atomic.h>
+#include <linux/platform_data/dma-imx.h>
+
+#define BUFFER_HASH_ORDER 4
+
+static struct pxp_buffer_hash bufhash;
+static struct pxp_irq_info irq_info[NR_PXP_VIRT_CHANNEL];
+
+static int pxp_ht_create(struct pxp_buffer_hash *hash, int order)
+{
+ unsigned long i;
+ unsigned long table_size;
+
+ table_size = 1U << order;
+
+ hash->order = order;
+ hash->hash_table = kmalloc(sizeof(*hash->hash_table) * table_size, GFP_KERNEL);
+
+ if (!hash->hash_table) {
+ pr_err("%s: Out of memory for hash table\n", __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < table_size; i++)
+ INIT_HLIST_HEAD(&hash->hash_table[i]);
+
+ return 0;
+}
+
+static int pxp_ht_insert_item(struct pxp_buffer_hash *hash,
+ struct pxp_buf_obj *new)
+{
+ unsigned long hashkey;
+ struct hlist_head *h_list;
+
+ hashkey = hash_long(new->offset >> PAGE_SHIFT, hash->order);
+ h_list = &hash->hash_table[hashkey];
+
+ spin_lock(&hash->hash_lock);
+ hlist_add_head_rcu(&new->item, h_list);
+ spin_unlock(&hash->hash_lock);
+
+ return 0;
+}
+
+static int pxp_ht_remove_item(struct pxp_buffer_hash *hash,
+ struct pxp_buf_obj *obj)
+{
+ spin_lock(&hash->hash_lock);
+ hlist_del_init_rcu(&obj->item);
+ spin_unlock(&hash->hash_lock);
+ return 0;
+}
+
+static struct hlist_node *pxp_ht_find_key(struct pxp_buffer_hash *hash,
+ unsigned long key)
+{
+ struct pxp_buf_obj *entry;
+ struct hlist_head *h_list;
+ unsigned long hashkey;
+
+ hashkey = hash_long(key, hash->order);
+ h_list = &hash->hash_table[hashkey];
+
+ hlist_for_each_entry_rcu(entry, h_list, item) {
+ if (entry->offset >> PAGE_SHIFT == key)
+ return &entry->item;
+ }
+
+ return NULL;
+}
+
+static void pxp_ht_destroy(struct pxp_buffer_hash *hash)
+{
+ kfree(hash->hash_table);
+ hash->hash_table = NULL;
+}
+
+static int pxp_buffer_handle_create(struct pxp_file *file_priv,
+ struct pxp_buf_obj *obj,
+ uint32_t *handlep)
+{
+ int ret;
+
+ idr_preload(GFP_KERNEL);
+ spin_lock(&file_priv->buffer_lock);
+
+ ret = idr_alloc(&file_priv->buffer_idr, obj, 1, 0, GFP_NOWAIT);
+
+ spin_unlock(&file_priv->buffer_lock);
+ idr_preload_end();
+
+ if (ret < 0)
+ return ret;
+
+ *handlep = ret;
+
+ return 0;
+}
+
+static struct pxp_buf_obj *
+pxp_buffer_object_lookup(struct pxp_file *file_priv,
+ uint32_t handle)
+{
+ struct pxp_buf_obj *obj;
+
+ spin_lock(&file_priv->buffer_lock);
+
+ obj = idr_find(&file_priv->buffer_idr, handle);
+ if (!obj) {
+ spin_unlock(&file_priv->buffer_lock);
+ return NULL;
+ }
+
+ spin_unlock(&file_priv->buffer_lock);
+
+ return obj;
+}
+
+static int pxp_buffer_handle_delete(struct pxp_file *file_priv,
+ uint32_t handle)
+{
+ struct pxp_buf_obj *obj;
+
+ spin_lock(&file_priv->buffer_lock);
+
+ obj = idr_find(&file_priv->buffer_idr, handle);
+ if (!obj) {
+ spin_unlock(&file_priv->buffer_lock);
+ return -EINVAL;
+ }
+
+ idr_remove(&file_priv->buffer_idr, handle);
+ spin_unlock(&file_priv->buffer_lock);
+
+ return 0;
+}
+
+static int pxp_channel_handle_create(struct pxp_file *file_priv,
+ struct pxp_chan_obj *obj,
+ uint32_t *handlep)
+{
+ int ret;
+
+ idr_preload(GFP_KERNEL);
+ spin_lock(&file_priv->channel_lock);
+
+ ret = idr_alloc(&file_priv->channel_idr, obj, 0, 0, GFP_NOWAIT);
+
+ spin_unlock(&file_priv->channel_lock);
+ idr_preload_end();
+
+ if (ret < 0)
+ return ret;
+
+ *handlep = ret;
+
+ return 0;
+}
+
+static struct pxp_chan_obj *
+pxp_channel_object_lookup(struct pxp_file *file_priv,
+ uint32_t handle)
+{
+ struct pxp_chan_obj *obj;
+
+ spin_lock(&file_priv->channel_lock);
+
+ obj = idr_find(&file_priv->channel_idr, handle);
+ if (!obj) {
+ spin_unlock(&file_priv->channel_lock);
+ return NULL;
+ }
+
+ spin_unlock(&file_priv->channel_lock);
+
+ return obj;
+}
+
+static int pxp_channel_handle_delete(struct pxp_file *file_priv,
+ uint32_t handle)
+{
+ struct pxp_chan_obj *obj;
+
+ spin_lock(&file_priv->channel_lock);
+
+ obj = idr_find(&file_priv->channel_idr, handle);
+ if (!obj) {
+ spin_unlock(&file_priv->channel_lock);
+ return -EINVAL;
+ }
+
+ idr_remove(&file_priv->channel_idr, handle);
+ spin_unlock(&file_priv->channel_lock);
+
+ return 0;
+}
+
+static int pxp_alloc_dma_buffer(struct pxp_buf_obj *obj)
+{
+ obj->virtual = dma_alloc_coherent(NULL, PAGE_ALIGN(obj->size),
+ (dma_addr_t *) (&obj->offset),
+ GFP_DMA | GFP_KERNEL);
+ pr_debug("[ALLOC] mem alloc phys_addr = 0x%lx\n", obj->offset);
+
+ if (obj->virtual == NULL) {
+ printk(KERN_ERR "Physical memory allocation error!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void pxp_free_dma_buffer(struct pxp_buf_obj *obj)
+{
+ if (obj->virtual != NULL) {
+ dma_free_coherent(0, PAGE_ALIGN(obj->size),
+ obj->virtual, (dma_addr_t)obj->offset);
+ }
+}
+
+static int
+pxp_buffer_object_free(int id, void *ptr, void *data)
+{
+ struct pxp_file *file_priv = data;
+ struct pxp_buf_obj *obj = ptr;
+ int ret;
+
+ ret = pxp_buffer_handle_delete(file_priv, obj->handle);
+ if (ret < 0)
+ return ret;
+
+ pxp_ht_remove_item(&bufhash, obj);
+ pxp_free_dma_buffer(obj);
+ kfree(obj);
+
+ return 0;
+}
+
+static int
+pxp_channel_object_free(int id, void *ptr, void *data)
+{
+ struct pxp_file *file_priv = data;
+ struct pxp_chan_obj *obj = ptr;
+ int chan_id;
+
+ chan_id = obj->chan->chan_id;
+ wait_event(irq_info[chan_id].waitq,
+ atomic_read(&irq_info[chan_id].irq_pending) == 0);
+
+ pxp_channel_handle_delete(file_priv, obj->handle);
+ dma_release_channel(obj->chan);
+ kfree(obj);
+
+ return 0;
+}
+
+static void pxp_free_buffers(struct pxp_file *file_priv)
+{
+ idr_for_each(&file_priv->buffer_idr,
+ &pxp_buffer_object_free, file_priv);
+ idr_destroy(&file_priv->buffer_idr);
+}
+
+static void pxp_free_channels(struct pxp_file *file_priv)
+{
+ idr_for_each(&file_priv->channel_idr,
+ &pxp_channel_object_free, file_priv);
+ idr_destroy(&file_priv->channel_idr);
+}
+
+/* Callback function triggered after PxP receives an EOF interrupt */
+static void pxp_dma_done(void *arg)
+{
+ struct pxp_tx_desc *tx_desc = to_tx_desc(arg);
+ struct dma_chan *chan = tx_desc->txd.chan;
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+ int chan_id = pxp_chan->dma_chan.chan_id;
+
+ pr_debug("DMA Done ISR, chan_id %d\n", chan_id);
+
+ atomic_dec(&irq_info[chan_id].irq_pending);
+ irq_info[chan_id].hist_status = tx_desc->hist_status;
+
+ wake_up(&(irq_info[chan_id].waitq));
+}
+
+static int pxp_ioc_config_chan(struct pxp_file *priv, unsigned long arg)
+{
+ struct scatterlist *sg;
+ struct pxp_tx_desc *desc;
+ struct dma_async_tx_descriptor *txd;
+ struct pxp_config_data *pxp_conf;
+ dma_cookie_t cookie;
+ int handle, chan_id;
+ struct dma_chan *chan;
+ struct pxp_chan_obj *obj;
+ int i = 0, j = 0, k = 0, m = 0, length, ret, sg_len;
+
+ pxp_conf = kzalloc(sizeof(*pxp_conf), GFP_KERNEL);
+ if (!pxp_conf)
+ return -ENOMEM;
+
+ ret = copy_from_user(pxp_conf,
+ (struct pxp_config_data *)arg,
+ sizeof(struct pxp_config_data));
+ if (ret) {
+ kfree(pxp_conf);
+ return -EFAULT;
+ }
+
+ handle = pxp_conf->handle;
+ obj = pxp_channel_object_lookup(priv, handle);
+ if (!obj) {
+ kfree(pxp_conf);
+ return -EINVAL;
+ }
+ chan = obj->chan;
+ chan_id = chan->chan_id;
+
+ sg_len = 3;
+ if (pxp_conf->proc_data.engine_enable & PXP_ENABLE_WFE_A)
+ sg_len += 4;
+ if (pxp_conf->proc_data.engine_enable & PXP_ENABLE_WFE_B)
+ sg_len += 4;
+ if (pxp_conf->proc_data.engine_enable & PXP_ENABLE_DITHER)
+ sg_len += 4;
+
+ sg = kmalloc(sizeof(*sg) * sg_len, GFP_KERNEL);
+ if (!sg) {
+ kfree(pxp_conf);
+ return -ENOMEM;
+ }
+
+ sg_init_table(sg, sg_len);
+
+ txd = chan->device->device_prep_slave_sg(chan,
+ sg, sg_len,
+ DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT,
+ NULL);
+ if (!txd) {
+ pr_err("Error preparing a DMA transaction descriptor.\n");
+ kfree(pxp_conf);
+ kfree(sg);
+ return -EIO;
+ }
+
+ txd->callback_param = txd;
+ txd->callback = pxp_dma_done;
+
+ desc = to_tx_desc(txd);
+
+ length = desc->len;
+ for (i = 0; i < length; i++) {
+ if (i == 0) { /* S0 */
+ memcpy(&desc->proc_data,
+ &pxp_conf->proc_data,
+ sizeof(struct pxp_proc_data));
+ memcpy(&desc->layer_param.s0_param,
+ &pxp_conf->s0_param,
+ sizeof(struct pxp_layer_param));
+ desc = desc->next;
+ } else if (i == 1) { /* Output */
+ memcpy(&desc->layer_param.out_param,
+ &pxp_conf->out_param,
+ sizeof(struct pxp_layer_param));
+ desc = desc->next;
+ } else if (i == 2) {
+ /* OverLay */
+ memcpy(&desc->layer_param.ol_param,
+ &pxp_conf->ol_param,
+ sizeof(struct pxp_layer_param));
+ desc = desc->next;
+ } else if ((pxp_conf->proc_data.engine_enable & PXP_ENABLE_WFE_A) && (j < 4)) {
+ for (j = 0; j < 4; j++) {
+ if (j == 0) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->wfe_a_fetch_param[0],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_WFE_A_FETCH0;
+ } else if (j == 1) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->wfe_a_fetch_param[1],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_WFE_A_FETCH1;
+ } else if (j == 2) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->wfe_a_store_param[0],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_WFE_A_STORE0;
+ } else if (j == 3) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->wfe_a_store_param[1],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_WFE_A_STORE1;
+ }
+
+ desc = desc->next;
+ }
+
+ i += 4;
+
+ } else if ((pxp_conf->proc_data.engine_enable & PXP_ENABLE_WFE_B) && (m < 4)) {
+ for (m = 0; m < 4; m++) {
+ if (m == 0) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->wfe_b_fetch_param[0],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_WFE_B_FETCH0;
+ } else if (m == 1) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->wfe_b_fetch_param[1],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_WFE_B_FETCH1;
+ } else if (m == 2) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->wfe_b_store_param[0],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_WFE_B_STORE0;
+ } else if (m == 3) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->wfe_b_store_param[1],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_WFE_B_STORE1;
+ }
+
+ desc = desc->next;
+ }
+
+ i += 4;
+
+ } else if ((pxp_conf->proc_data.engine_enable & PXP_ENABLE_DITHER) && (k < 4)) {
+ for (k = 0; k < 4; k++) {
+ if (k == 0) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->dither_fetch_param[0],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_DITHER_FETCH0;
+ } else if (k == 1) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->dither_fetch_param[1],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_DITHER_FETCH1;
+ } else if (k == 2) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->dither_store_param[0],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_DITHER_STORE0;
+ } else if (k == 3) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->dither_store_param[1],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_DITHER_STORE1;
+ }
+
+ desc = desc->next;
+ }
+
+ i += 4;
+ }
+ }
+
+ cookie = txd->tx_submit(txd);
+ if (cookie < 0) {
+ pr_err("Error tx_submit\n");
+ kfree(pxp_conf);
+ kfree(sg);
+ return -EIO;
+ }
+
+ atomic_inc(&irq_info[chan_id].irq_pending);
+
+ kfree(pxp_conf);
+ kfree(sg);
+
+ return 0;
+}
+
+static int pxp_device_open(struct inode *inode, struct file *filp)
+{
+ struct pxp_file *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+
+ if (!priv)
+ return -ENOMEM;
+
+ filp->private_data = priv;
+ priv->filp = filp;
+
+ idr_init(&priv->buffer_idr);
+ spin_lock_init(&priv->buffer_lock);
+
+ idr_init(&priv->channel_idr);
+ spin_lock_init(&priv->channel_lock);
+
+ return 0;
+}
+
+static int pxp_device_release(struct inode *inode, struct file *filp)
+{
+ struct pxp_file *priv = filp->private_data;
+
+ if (priv) {
+ pxp_free_channels(priv);
+ pxp_free_buffers(priv);
+ kfree(priv);
+ filp->private_data = NULL;
+ }
+
+ return 0;
+}
+
+static int pxp_device_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ int request_size;
+ struct hlist_node *node;
+ struct pxp_buf_obj *obj;
+
+ request_size = vma->vm_end - vma->vm_start;
+
+ pr_debug("start=0x%x, pgoff=0x%x, size=0x%x\n",
+ (unsigned int)(vma->vm_start), (unsigned int)(vma->vm_pgoff),
+ request_size);
+
+ node = pxp_ht_find_key(&bufhash, vma->vm_pgoff);
+ if (!node)
+ return -EINVAL;
+
+ obj = list_entry(node, struct pxp_buf_obj, item);
+ if (obj->offset + (obj->size >> PAGE_SHIFT) <
+ (vma->vm_pgoff + vma_pages(vma)))
+ return -ENOMEM;
+
+ switch (obj->mem_type) {
+ case MEMORY_TYPE_UNCACHED:
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ break;
+ case MEMORY_TYPE_WC:
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ break;
+ case MEMORY_TYPE_CACHED:
+ break;
+ default:
+ pr_err("%s: invalid memory type!\n", __func__);
+ return -EINVAL;
+ }
+
+ return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ request_size, vma->vm_page_prot) ? -EAGAIN : 0;
+}
+
+static bool chan_filter(struct dma_chan *chan, void *arg)
+{
+ if (imx_dma_is_pxp(chan))
+ return true;
+ else
+ return false;
+}
+
+static long pxp_device_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ struct pxp_file *file_priv = filp->private_data;
+
+ switch (cmd) {
+ case PXP_IOC_GET_CHAN:
+ {
+ int ret;
+ struct dma_chan *chan = NULL;
+ dma_cap_mask_t mask;
+ struct pxp_chan_obj *obj = NULL;
+
+ pr_debug("drv: PXP_IOC_GET_CHAN Line %d\n", __LINE__);
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_PRIVATE, mask);
+
+ chan = dma_request_channel(mask, chan_filter, NULL);
+ if (!chan) {
+ pr_err("Unsccessfully received channel!\n");
+ return -EBUSY;
+ }
+
+ pr_debug("Successfully received channel."
+ "chan_id %d\n", chan->chan_id);
+
+ obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+ if (!obj) {
+ dma_release_channel(chan);
+ return -ENOMEM;
+ }
+ obj->chan = chan;
+
+ ret = pxp_channel_handle_create(file_priv, obj,
+ &obj->handle);
+ if (ret) {
+ dma_release_channel(chan);
+ kfree(obj);
+ return ret;
+ }
+
+ init_waitqueue_head(&(irq_info[chan->chan_id].waitq));
+ if (put_user(obj->handle, (u32 __user *) arg)) {
+ pxp_channel_handle_delete(file_priv, obj->handle);
+ dma_release_channel(chan);
+ kfree(obj);
+ return -EFAULT;
+ }
+
+ break;
+ }
+ case PXP_IOC_PUT_CHAN:
+ {
+ int handle;
+ struct pxp_chan_obj *obj;
+
+ if (get_user(handle, (u32 __user *) arg))
+ return -EFAULT;
+
+ pr_debug("%d release handle %d\n", __LINE__, handle);
+
+ obj = pxp_channel_object_lookup(file_priv, handle);
+ if (!obj)
+ return -EINVAL;
+
+ pxp_channel_handle_delete(file_priv, obj->handle);
+ dma_release_channel(obj->chan);
+ kfree(obj);
+
+ break;
+ }
+ case PXP_IOC_CONFIG_CHAN:
+ {
+ int ret;
+
+ ret = pxp_ioc_config_chan(file_priv, arg);
+ if (ret)
+ return ret;
+
+ break;
+ }
+ case PXP_IOC_START_CHAN:
+ {
+ int handle;
+ struct pxp_chan_obj *obj = NULL;
+
+ if (get_user(handle, (u32 __user *) arg))
+ return -EFAULT;
+
+ obj = pxp_channel_object_lookup(file_priv, handle);
+ if (!obj)
+ return -EINVAL;
+
+ dma_async_issue_pending(obj->chan);
+
+ break;
+ }
+ case PXP_IOC_GET_PHYMEM:
+ {
+ struct pxp_mem_desc buffer;
+ struct pxp_buf_obj *obj;
+
+ ret = copy_from_user(&buffer,
+ (struct pxp_mem_desc *)arg,
+ sizeof(struct pxp_mem_desc));
+ if (ret)
+ return -EFAULT;
+
+ pr_debug("[ALLOC] mem alloc size = 0x%x\n",
+ buffer.size);
+
+ obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+ if (!obj)
+ return -ENOMEM;
+ obj->size = buffer.size;
+ obj->mem_type = buffer.mtype;
+
+ ret = pxp_alloc_dma_buffer(obj);
+ if (ret == -1) {
+ printk(KERN_ERR
+ "Physical memory allocation error!\n");
+ kfree(obj);
+ return ret;
+ }
+
+ ret = pxp_buffer_handle_create(file_priv, obj, &obj->handle);
+ if (ret) {
+ pxp_free_dma_buffer(obj);
+ kfree(obj);
+ return ret;
+ }
+ buffer.handle = obj->handle;
+ buffer.phys_addr = obj->offset;
+
+ ret = copy_to_user((void __user *)arg, &buffer,
+ sizeof(struct pxp_mem_desc));
+ if (ret) {
+ pxp_buffer_handle_delete(file_priv, buffer.handle);
+ pxp_free_dma_buffer(obj);
+ kfree(obj);
+ return -EFAULT;
+ }
+
+ pxp_ht_insert_item(&bufhash, obj);
+
+ break;
+ }
+ case PXP_IOC_PUT_PHYMEM:
+ {
+ struct pxp_mem_desc pxp_mem;
+ struct pxp_buf_obj *obj;
+
+ ret = copy_from_user(&pxp_mem,
+ (struct pxp_mem_desc *)arg,
+ sizeof(struct pxp_mem_desc));
+ if (ret)
+ return -EACCES;
+
+ obj = pxp_buffer_object_lookup(file_priv, pxp_mem.handle);
+ if (!obj)
+ return -EINVAL;
+
+ ret = pxp_buffer_handle_delete(file_priv, obj->handle);
+ if (ret)
+ return ret;
+
+ pxp_ht_remove_item(&bufhash, obj);
+ pxp_free_dma_buffer(obj);
+ kfree(obj);
+
+ break;
+ }
+ case PXP_IOC_FLUSH_PHYMEM:
+ {
+ int ret;
+ struct pxp_mem_flush flush;
+ struct pxp_buf_obj *obj;
+
+ ret = copy_from_user(&flush,
+ (struct pxp_mem_flush *)arg,
+ sizeof(struct pxp_mem_flush));
+ if (ret)
+ return -EACCES;
+
+ obj = pxp_buffer_object_lookup(file_priv, flush.handle);
+ if (!obj)
+ return -EINVAL;
+
+ switch (flush.type) {
+ case CACHE_CLEAN:
+ dma_sync_single_for_device(NULL, obj->offset,
+ obj->size, DMA_TO_DEVICE);
+ break;
+ case CACHE_INVALIDATE:
+ dma_sync_single_for_device(NULL, obj->offset,
+ obj->size, DMA_FROM_DEVICE);
+ break;
+ case CACHE_FLUSH:
+ dma_sync_single_for_device(NULL, obj->offset,
+ obj->size, DMA_TO_DEVICE);
+ dma_sync_single_for_device(NULL, obj->offset,
+ obj->size, DMA_FROM_DEVICE);
+ break;
+ default:
+ pr_err("%s: invalid cache flush type\n", __func__);
+ return -EINVAL;
+ }
+
+ break;
+ }
+ case PXP_IOC_WAIT4CMPLT:
+ {
+ struct pxp_chan_handle chan_handle;
+ int ret, chan_id, handle;
+ struct pxp_chan_obj *obj = NULL;
+
+ ret = copy_from_user(&chan_handle,
+ (struct pxp_chan_handle *)arg,
+ sizeof(struct pxp_chan_handle));
+ if (ret)
+ return -EFAULT;
+
+ handle = chan_handle.handle;
+ obj = pxp_channel_object_lookup(file_priv, handle);
+ if (!obj)
+ return -EINVAL;
+ chan_id = obj->chan->chan_id;
+
+ ret = wait_event_interruptible
+ (irq_info[chan_id].waitq,
+ (atomic_read(&irq_info[chan_id].irq_pending) == 0));
+ if (ret < 0)
+ return -ERESTARTSYS;
+
+ chan_handle.hist_status = irq_info[chan_id].hist_status;
+ ret = copy_to_user((struct pxp_chan_handle *)arg,
+ &chan_handle,
+ sizeof(struct pxp_chan_handle));
+ if (ret)
+ return -EFAULT;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct file_operations pxp_device_fops = {
+ .open = pxp_device_open,
+ .release = pxp_device_release,
+ .unlocked_ioctl = pxp_device_ioctl,
+ .mmap = pxp_device_mmap,
+};
+
+static struct miscdevice pxp_device_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "pxp_device",
+ .fops = &pxp_device_fops,
+};
+
+int register_pxp_device(void)
+{
+ int ret;
+
+ ret = misc_register(&pxp_device_miscdev);
+ if (ret)
+ return ret;
+
+ ret = pxp_ht_create(&bufhash, BUFFER_HASH_ORDER);
+ if (ret)
+ return ret;
+ spin_lock_init(&(bufhash.hash_lock));
+
+ pr_debug("PxP_Device registered Successfully\n");
+ return 0;
+}
+
+void unregister_pxp_device(void)
+{
+ pxp_ht_destroy(&bufhash);
+ misc_deregister(&pxp_device_miscdev);
+}
diff --git a/drivers/dma/pxp/pxp_dma_v2.c b/drivers/dma/pxp/pxp_dma_v2.c
new file mode 100644
index 000000000000..8ab9e29dc896
--- /dev/null
+++ b/drivers/dma/pxp/pxp_dma_v2.c
@@ -0,0 +1,1865 @@
+/*
+ * Copyright (C) 2010-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; 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
+ *
+ */
+/*
+ * Based on STMP378X PxP driver
+ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/freezer.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/pxp_dma.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+
+#include "regs-pxp_v2.h"
+
+#define PXP_DOWNSCALE_THRESHOLD 0x4000
+
+static LIST_HEAD(head);
+static int timeout_in_ms = 600;
+static unsigned int block_size;
+static struct kmem_cache *tx_desc_cache;
+
+struct pxp_dma {
+ struct dma_device dma;
+};
+
+struct pxps {
+ struct platform_device *pdev;
+ struct clk *clk;
+ struct clk *clk_disp_axi; /* may exist on some SoC for gating */
+ void __iomem *base;
+ int irq; /* PXP IRQ to the CPU */
+
+ spinlock_t lock;
+ struct mutex clk_mutex;
+ int clk_stat;
+#define CLK_STAT_OFF 0
+#define CLK_STAT_ON 1
+ int pxp_ongoing;
+ int lut_state;
+
+ struct device *dev;
+ struct pxp_dma pxp_dma;
+ struct pxp_channel channel[NR_PXP_VIRT_CHANNEL];
+ struct work_struct work;
+
+ /* describes most recent processing configuration */
+ struct pxp_config_data pxp_conf_state;
+
+ /* to turn clock off when pxp is inactive */
+ struct timer_list clk_timer;
+
+ /* for pxp config dispatch asynchronously*/
+ struct task_struct *dispatch;
+ wait_queue_head_t thread_waitq;
+ struct completion complete;
+};
+
+#define to_pxp_dma(d) container_of(d, struct pxp_dma, dma)
+#define to_tx_desc(tx) container_of(tx, struct pxp_tx_desc, txd)
+#define to_pxp_channel(d) container_of(d, struct pxp_channel, dma_chan)
+#define to_pxp(id) container_of(id, struct pxps, pxp_dma)
+
+#define PXP_DEF_BUFS 2
+#define PXP_MIN_PIX 8
+
+/*
+ * PXP common functions
+ */
+static void dump_pxp_reg(struct pxps *pxp)
+{
+ dev_dbg(pxp->dev, "PXP_CTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CTRL));
+ dev_dbg(pxp->dev, "PXP_STAT 0x%x",
+ __raw_readl(pxp->base + HW_PXP_STAT));
+ dev_dbg(pxp->dev, "PXP_OUT_CTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_CTRL));
+ dev_dbg(pxp->dev, "PXP_OUT_BUF 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_BUF));
+ dev_dbg(pxp->dev, "PXP_OUT_BUF2 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_BUF2));
+ dev_dbg(pxp->dev, "PXP_OUT_PITCH 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_PITCH));
+ dev_dbg(pxp->dev, "PXP_OUT_LRC 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_LRC));
+ dev_dbg(pxp->dev, "PXP_OUT_PS_ULC 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_PS_ULC));
+ dev_dbg(pxp->dev, "PXP_OUT_PS_LRC 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_PS_LRC));
+ dev_dbg(pxp->dev, "PXP_OUT_AS_ULC 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_AS_ULC));
+ dev_dbg(pxp->dev, "PXP_OUT_AS_LRC 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_AS_LRC));
+ dev_dbg(pxp->dev, "PXP_PS_CTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_CTRL));
+ dev_dbg(pxp->dev, "PXP_PS_BUF 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_BUF));
+ dev_dbg(pxp->dev, "PXP_PS_UBUF 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_UBUF));
+ dev_dbg(pxp->dev, "PXP_PS_VBUF 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_VBUF));
+ dev_dbg(pxp->dev, "PXP_PS_PITCH 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_PITCH));
+ dev_dbg(pxp->dev, "PXP_PS_BACKGROUND 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_BACKGROUND));
+ dev_dbg(pxp->dev, "PXP_PS_SCALE 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_SCALE));
+ dev_dbg(pxp->dev, "PXP_PS_OFFSET 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_OFFSET));
+ dev_dbg(pxp->dev, "PXP_PS_CLRKEYLOW 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_CLRKEYLOW));
+ dev_dbg(pxp->dev, "PXP_PS_CLRKEYHIGH 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_CLRKEYHIGH));
+ dev_dbg(pxp->dev, "PXP_AS_CTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_AS_CTRL));
+ dev_dbg(pxp->dev, "PXP_AS_BUF 0x%x",
+ __raw_readl(pxp->base + HW_PXP_AS_BUF));
+ dev_dbg(pxp->dev, "PXP_AS_PITCH 0x%x",
+ __raw_readl(pxp->base + HW_PXP_AS_PITCH));
+ dev_dbg(pxp->dev, "PXP_AS_CLRKEYLOW 0x%x",
+ __raw_readl(pxp->base + HW_PXP_AS_CLRKEYLOW));
+ dev_dbg(pxp->dev, "PXP_AS_CLRKEYHIGH 0x%x",
+ __raw_readl(pxp->base + HW_PXP_AS_CLRKEYHIGH));
+ dev_dbg(pxp->dev, "PXP_CSC1_COEF0 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC1_COEF0));
+ dev_dbg(pxp->dev, "PXP_CSC1_COEF1 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC1_COEF1));
+ dev_dbg(pxp->dev, "PXP_CSC1_COEF2 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC1_COEF2));
+ dev_dbg(pxp->dev, "PXP_CSC2_CTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC2_CTRL));
+ dev_dbg(pxp->dev, "PXP_CSC2_COEF0 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC2_COEF0));
+ dev_dbg(pxp->dev, "PXP_CSC2_COEF1 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC2_COEF1));
+ dev_dbg(pxp->dev, "PXP_CSC2_COEF2 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC2_COEF2));
+ dev_dbg(pxp->dev, "PXP_CSC2_COEF3 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC2_COEF3));
+ dev_dbg(pxp->dev, "PXP_CSC2_COEF4 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC2_COEF4));
+ dev_dbg(pxp->dev, "PXP_CSC2_COEF5 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC2_COEF5));
+ dev_dbg(pxp->dev, "PXP_LUT_CTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_LUT_CTRL));
+ dev_dbg(pxp->dev, "PXP_LUT_ADDR 0x%x",
+ __raw_readl(pxp->base + HW_PXP_LUT_ADDR));
+ dev_dbg(pxp->dev, "PXP_LUT_DATA 0x%x",
+ __raw_readl(pxp->base + HW_PXP_LUT_DATA));
+ dev_dbg(pxp->dev, "PXP_LUT_EXTMEM 0x%x",
+ __raw_readl(pxp->base + HW_PXP_LUT_EXTMEM));
+ dev_dbg(pxp->dev, "PXP_CFA 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CFA));
+ dev_dbg(pxp->dev, "PXP_HIST_CTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_HIST_CTRL));
+ dev_dbg(pxp->dev, "PXP_HIST2_PARAM 0x%x",
+ __raw_readl(pxp->base + HW_PXP_HIST2_PARAM));
+ dev_dbg(pxp->dev, "PXP_HIST4_PARAM 0x%x",
+ __raw_readl(pxp->base + HW_PXP_HIST4_PARAM));
+ dev_dbg(pxp->dev, "PXP_HIST8_PARAM0 0x%x",
+ __raw_readl(pxp->base + HW_PXP_HIST8_PARAM0));
+ dev_dbg(pxp->dev, "PXP_HIST8_PARAM1 0x%x",
+ __raw_readl(pxp->base + HW_PXP_HIST8_PARAM1));
+ dev_dbg(pxp->dev, "PXP_HIST16_PARAM0 0x%x",
+ __raw_readl(pxp->base + HW_PXP_HIST16_PARAM0));
+ dev_dbg(pxp->dev, "PXP_HIST16_PARAM1 0x%x",
+ __raw_readl(pxp->base + HW_PXP_HIST16_PARAM1));
+ dev_dbg(pxp->dev, "PXP_HIST16_PARAM2 0x%x",
+ __raw_readl(pxp->base + HW_PXP_HIST16_PARAM2));
+ dev_dbg(pxp->dev, "PXP_HIST16_PARAM3 0x%x",
+ __raw_readl(pxp->base + HW_PXP_HIST16_PARAM3));
+ dev_dbg(pxp->dev, "PXP_POWER 0x%x",
+ __raw_readl(pxp->base + HW_PXP_POWER));
+ dev_dbg(pxp->dev, "PXP_NEXT 0x%x",
+ __raw_readl(pxp->base + HW_PXP_NEXT));
+ dev_dbg(pxp->dev, "PXP_DEBUGCTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_DEBUGCTRL));
+ dev_dbg(pxp->dev, "PXP_DEBUG 0x%x",
+ __raw_readl(pxp->base + HW_PXP_DEBUG));
+ dev_dbg(pxp->dev, "PXP_VERSION 0x%x",
+ __raw_readl(pxp->base + HW_PXP_VERSION));
+}
+
+static bool is_yuv(u32 pix_fmt)
+{
+ switch (pix_fmt) {
+ case PXP_PIX_FMT_YUYV:
+ case PXP_PIX_FMT_UYVY:
+ case PXP_PIX_FMT_YVYU:
+ case PXP_PIX_FMT_VYUY:
+ case PXP_PIX_FMT_Y41P:
+ case PXP_PIX_FMT_VUY444:
+ case PXP_PIX_FMT_NV12:
+ case PXP_PIX_FMT_NV21:
+ case PXP_PIX_FMT_NV16:
+ case PXP_PIX_FMT_NV61:
+ case PXP_PIX_FMT_GREY:
+ case PXP_PIX_FMT_GY04:
+ case PXP_PIX_FMT_YVU410P:
+ case PXP_PIX_FMT_YUV410P:
+ case PXP_PIX_FMT_YVU420P:
+ case PXP_PIX_FMT_YUV420P:
+ case PXP_PIX_FMT_YUV420P2:
+ case PXP_PIX_FMT_YVU422P:
+ case PXP_PIX_FMT_YUV422P:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void pxp_soft_reset(struct pxps *pxp)
+{
+ __raw_writel(BM_PXP_CTRL_SFTRST, pxp->base + HW_PXP_CTRL_CLR);
+ __raw_writel(BM_PXP_CTRL_CLKGATE, pxp->base + HW_PXP_CTRL_CLR);
+
+ __raw_writel(BM_PXP_CTRL_SFTRST, pxp->base + HW_PXP_CTRL_SET);
+ while (!(__raw_readl(pxp->base + HW_PXP_CTRL) & BM_PXP_CTRL_CLKGATE))
+ dev_dbg(pxp->dev, "%s: wait for clock gate off", __func__);
+
+ __raw_writel(BM_PXP_CTRL_SFTRST, pxp->base + HW_PXP_CTRL_CLR);
+ __raw_writel(BM_PXP_CTRL_CLKGATE, pxp->base + HW_PXP_CTRL_CLR);
+}
+
+static void pxp_set_ctrl(struct pxps *pxp)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+ u32 ctrl;
+ u32 fmt_ctrl;
+ int need_swap = 0; /* to support YUYV and YVYU formats */
+
+ /* Configure S0 input format */
+ switch (pxp_conf->s0_param.pixel_fmt) {
+ case PXP_PIX_FMT_XRGB32:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__RGB888;
+ break;
+ case PXP_PIX_FMT_RGB565:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__RGB565;
+ break;
+ case PXP_PIX_FMT_RGB555:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__RGB555;
+ break;
+ case PXP_PIX_FMT_YUV420P:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV420;
+ break;
+ case PXP_PIX_FMT_YVU420P:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV420;
+ break;
+ case PXP_PIX_FMT_GREY:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__Y8;
+ break;
+ case PXP_PIX_FMT_GY04:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__Y4;
+ break;
+ case PXP_PIX_FMT_VUY444:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV1P444;
+ break;
+ case PXP_PIX_FMT_YUV422P:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV422;
+ break;
+ case PXP_PIX_FMT_UYVY:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__UYVY1P422;
+ break;
+ case PXP_PIX_FMT_YUYV:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__UYVY1P422;
+ need_swap = 1;
+ break;
+ case PXP_PIX_FMT_VYUY:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__VYUY1P422;
+ break;
+ case PXP_PIX_FMT_YVYU:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__VYUY1P422;
+ need_swap = 1;
+ break;
+ case PXP_PIX_FMT_NV12:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV2P420;
+ break;
+ case PXP_PIX_FMT_NV21:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YVU2P420;
+ break;
+ case PXP_PIX_FMT_NV16:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV2P422;
+ break;
+ case PXP_PIX_FMT_NV61:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YVU2P422;
+ break;
+ default:
+ fmt_ctrl = 0;
+ }
+
+ ctrl = BF_PXP_PS_CTRL_FORMAT(fmt_ctrl) | BF_PXP_PS_CTRL_SWAP(need_swap);
+ __raw_writel(ctrl, pxp->base + HW_PXP_PS_CTRL_SET);
+
+ /* Configure output format based on out_channel format */
+ switch (pxp_conf->out_param.pixel_fmt) {
+ case PXP_PIX_FMT_XRGB32:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB888;
+ break;
+ case PXP_PIX_FMT_BGRA32:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__ARGB8888;
+ break;
+ case PXP_PIX_FMT_RGB24:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB888P;
+ break;
+ case PXP_PIX_FMT_RGB565:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB565;
+ break;
+ case PXP_PIX_FMT_RGB555:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB555;
+ break;
+ case PXP_PIX_FMT_GREY:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__Y8;
+ break;
+ case PXP_PIX_FMT_GY04:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__Y4;
+ break;
+ case PXP_PIX_FMT_UYVY:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__UYVY1P422;
+ break;
+ case PXP_PIX_FMT_VYUY:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__VYUY1P422;
+ break;
+ case PXP_PIX_FMT_NV12:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__YUV2P420;
+ break;
+ case PXP_PIX_FMT_NV21:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__YVU2P420;
+ break;
+ case PXP_PIX_FMT_NV16:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__YUV2P422;
+ break;
+ case PXP_PIX_FMT_NV61:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__YVU2P422;
+ break;
+ default:
+ fmt_ctrl = 0;
+ }
+
+ ctrl = BF_PXP_OUT_CTRL_FORMAT(fmt_ctrl);
+ __raw_writel(ctrl, pxp->base + HW_PXP_OUT_CTRL);
+
+ ctrl = 0;
+ if (proc_data->scaling)
+ ;
+ if (proc_data->vflip)
+ ctrl |= BM_PXP_CTRL_VFLIP;
+ if (proc_data->hflip)
+ ctrl |= BM_PXP_CTRL_HFLIP;
+ if (proc_data->rotate)
+ ctrl |= BF_PXP_CTRL_ROTATE(proc_data->rotate / 90);
+
+ /* In default, the block size is set to 8x8
+ * But block size can be set to 16x16 due to
+ * blocksize variable modification
+ */
+ ctrl |= block_size << 23;
+
+ __raw_writel(ctrl, pxp->base + HW_PXP_CTRL);
+}
+
+static int pxp_start(struct pxps *pxp)
+{
+ __raw_writel(BM_PXP_CTRL_IRQ_ENABLE, pxp->base + HW_PXP_CTRL_SET);
+ __raw_writel(BM_PXP_CTRL_ENABLE, pxp->base + HW_PXP_CTRL_SET);
+ dump_pxp_reg(pxp);
+
+ return 0;
+}
+
+static void pxp_set_outbuf(struct pxps *pxp)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_layer_param *out_params = &pxp_conf->out_param;
+ struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+
+ __raw_writel(out_params->paddr, pxp->base + HW_PXP_OUT_BUF);
+
+ if ((out_params->pixel_fmt == PXP_PIX_FMT_NV12) ||
+ (out_params->pixel_fmt == PXP_PIX_FMT_NV21) ||
+ (out_params->pixel_fmt == PXP_PIX_FMT_NV16) ||
+ (out_params->pixel_fmt == PXP_PIX_FMT_NV61)) {
+ dma_addr_t Y, U;
+
+ Y = out_params->paddr;
+ U = Y + (out_params->width * out_params->height);
+
+ __raw_writel(U, pxp->base + HW_PXP_OUT_BUF2);
+ }
+
+ if (proc_data->rotate == 90 || proc_data->rotate == 270)
+ __raw_writel(BF_PXP_OUT_LRC_X(out_params->height - 1) |
+ BF_PXP_OUT_LRC_Y(out_params->width - 1),
+ pxp->base + HW_PXP_OUT_LRC);
+ else
+ __raw_writel(BF_PXP_OUT_LRC_X(out_params->width - 1) |
+ BF_PXP_OUT_LRC_Y(out_params->height - 1),
+ pxp->base + HW_PXP_OUT_LRC);
+
+ if (out_params->pixel_fmt == PXP_PIX_FMT_RGB24) {
+ __raw_writel(out_params->stride * 3,
+ pxp->base + HW_PXP_OUT_PITCH);
+ } else if (out_params->pixel_fmt == PXP_PIX_FMT_BGRA32 ||
+ out_params->pixel_fmt == PXP_PIX_FMT_XRGB32) {
+ __raw_writel(out_params->stride << 2,
+ pxp->base + HW_PXP_OUT_PITCH);
+ } else if ((out_params->pixel_fmt == PXP_PIX_FMT_RGB565) ||
+ (out_params->pixel_fmt == PXP_PIX_FMT_RGB555)) {
+ __raw_writel(out_params->stride << 1,
+ pxp->base + HW_PXP_OUT_PITCH);
+ } else if (out_params->pixel_fmt == PXP_PIX_FMT_UYVY ||
+ (out_params->pixel_fmt == PXP_PIX_FMT_VYUY)) {
+ __raw_writel(out_params->stride << 1,
+ pxp->base + HW_PXP_OUT_PITCH);
+ } else if (out_params->pixel_fmt == PXP_PIX_FMT_GREY ||
+ out_params->pixel_fmt == PXP_PIX_FMT_NV12 ||
+ out_params->pixel_fmt == PXP_PIX_FMT_NV21 ||
+ out_params->pixel_fmt == PXP_PIX_FMT_NV16 ||
+ out_params->pixel_fmt == PXP_PIX_FMT_NV61) {
+ __raw_writel(out_params->stride,
+ pxp->base + HW_PXP_OUT_PITCH);
+ } else if (out_params->pixel_fmt == PXP_PIX_FMT_GY04) {
+ __raw_writel(out_params->stride >> 1,
+ pxp->base + HW_PXP_OUT_PITCH);
+ } else {
+ __raw_writel(0, pxp->base + HW_PXP_OUT_PITCH);
+ }
+
+ /* set global alpha if necessary */
+ if (out_params->global_alpha_enable) {
+ __raw_writel(out_params->global_alpha << 24,
+ pxp->base + HW_PXP_OUT_CTRL_SET);
+ __raw_writel(BM_PXP_OUT_CTRL_ALPHA_OUTPUT,
+ pxp->base + HW_PXP_OUT_CTRL_SET);
+ }
+}
+
+static void pxp_set_s0colorkey(struct pxps *pxp)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_layer_param *s0_params = &pxp_conf->s0_param;
+
+ /* Low and high are set equal. V4L does not allow a chromakey range */
+ if (s0_params->color_key_enable == 0 || s0_params->color_key == -1) {
+ /* disable color key */
+ __raw_writel(0xFFFFFF, pxp->base + HW_PXP_PS_CLRKEYLOW);
+ __raw_writel(0, pxp->base + HW_PXP_PS_CLRKEYHIGH);
+ } else {
+ __raw_writel(s0_params->color_key,
+ pxp->base + HW_PXP_PS_CLRKEYLOW);
+ __raw_writel(s0_params->color_key,
+ pxp->base + HW_PXP_PS_CLRKEYHIGH);
+ }
+}
+
+static void pxp_set_olcolorkey(int layer_no, struct pxps *pxp)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_layer_param *ol_params = &pxp_conf->ol_param[layer_no];
+
+ /* Low and high are set equal. V4L does not allow a chromakey range */
+ if (ol_params->color_key_enable != 0 && ol_params->color_key != -1) {
+ __raw_writel(ol_params->color_key,
+ pxp->base + HW_PXP_AS_CLRKEYLOW);
+ __raw_writel(ol_params->color_key,
+ pxp->base + HW_PXP_AS_CLRKEYHIGH);
+ } else {
+ /* disable color key */
+ __raw_writel(0xFFFFFF, pxp->base + HW_PXP_AS_CLRKEYLOW);
+ __raw_writel(0, pxp->base + HW_PXP_AS_CLRKEYHIGH);
+ }
+}
+
+static void pxp_set_oln(int layer_no, struct pxps *pxp)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_layer_param *olparams_data = &pxp_conf->ol_param[layer_no];
+ dma_addr_t phys_addr = olparams_data->paddr;
+ u32 pitch = olparams_data->stride ? olparams_data->stride :
+ olparams_data->width;
+
+ __raw_writel(phys_addr, pxp->base + HW_PXP_AS_BUF);
+
+ /* Fixme */
+ if (olparams_data->width == 0 && olparams_data->height == 0) {
+ __raw_writel(0xffffffff, pxp->base + HW_PXP_OUT_AS_ULC);
+ __raw_writel(0x0, pxp->base + HW_PXP_OUT_AS_LRC);
+ } else {
+ __raw_writel(0x0, pxp->base + HW_PXP_OUT_AS_ULC);
+ __raw_writel(BF_PXP_OUT_AS_LRC_X(olparams_data->width - 1) |
+ BF_PXP_OUT_AS_LRC_Y(olparams_data->height - 1),
+ pxp->base + HW_PXP_OUT_AS_LRC);
+ }
+
+ if ((olparams_data->pixel_fmt == PXP_PIX_FMT_BGRA32) ||
+ (olparams_data->pixel_fmt == PXP_PIX_FMT_XRGB32)) {
+ __raw_writel(pitch << 2,
+ pxp->base + HW_PXP_AS_PITCH);
+ } else if ((olparams_data->pixel_fmt == PXP_PIX_FMT_RGB565) ||
+ (olparams_data->pixel_fmt == PXP_PIX_FMT_RGB555)) {
+ __raw_writel(pitch << 1,
+ pxp->base + HW_PXP_AS_PITCH);
+ } else {
+ __raw_writel(0, pxp->base + HW_PXP_AS_PITCH);
+ }
+}
+
+static void pxp_set_olparam(int layer_no, struct pxps *pxp)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_layer_param *olparams_data = &pxp_conf->ol_param[layer_no];
+ u32 olparam;
+
+ olparam = BF_PXP_AS_CTRL_ALPHA(olparams_data->global_alpha);
+ if (olparams_data->pixel_fmt == PXP_PIX_FMT_XRGB32) {
+ olparam |=
+ BF_PXP_AS_CTRL_FORMAT(BV_PXP_AS_CTRL_FORMAT__RGB888);
+ } else if (olparams_data->pixel_fmt == PXP_PIX_FMT_BGRA32) {
+ olparam |=
+ BF_PXP_AS_CTRL_FORMAT(BV_PXP_AS_CTRL_FORMAT__ARGB8888);
+ if (!olparams_data->combine_enable) {
+ olparam |=
+ BF_PXP_AS_CTRL_ALPHA_CTRL
+ (BV_PXP_AS_CTRL_ALPHA_CTRL__ROPs);
+ olparam |= 0x3 << 16;
+ }
+ } else if (olparams_data->pixel_fmt == PXP_PIX_FMT_RGB565) {
+ olparam |=
+ BF_PXP_AS_CTRL_FORMAT(BV_PXP_AS_CTRL_FORMAT__RGB565);
+ } else if (olparams_data->pixel_fmt == PXP_PIX_FMT_RGB555) {
+ olparam |=
+ BF_PXP_AS_CTRL_FORMAT(BV_PXP_AS_CTRL_FORMAT__RGB555);
+ }
+
+ if (olparams_data->global_alpha_enable) {
+ if (olparams_data->global_override) {
+ olparam |=
+ BF_PXP_AS_CTRL_ALPHA_CTRL
+ (BV_PXP_AS_CTRL_ALPHA_CTRL__Override);
+ } else {
+ olparam |=
+ BF_PXP_AS_CTRL_ALPHA_CTRL
+ (BV_PXP_AS_CTRL_ALPHA_CTRL__Multiply);
+ }
+ if (olparams_data->alpha_invert)
+ olparam |= BM_PXP_AS_CTRL_ALPHA_INVERT;
+ }
+ if (olparams_data->color_key_enable)
+ olparam |= BM_PXP_AS_CTRL_ENABLE_COLORKEY;
+
+ __raw_writel(olparam, pxp->base + HW_PXP_AS_CTRL);
+}
+
+static void pxp_set_s0param(struct pxps *pxp)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+ struct pxp_layer_param *out_params = &pxp_conf->out_param;
+ u32 s0param_ulc, s0param_lrc;
+
+ /* contains the coordinate for the PS in the OUTPUT buffer. */
+ if ((pxp_conf->s0_param).width == 0 &&
+ (pxp_conf->s0_param).height == 0) {
+ __raw_writel(0xffffffff, pxp->base + HW_PXP_OUT_PS_ULC);
+ __raw_writel(0x0, pxp->base + HW_PXP_OUT_PS_LRC);
+ } else {
+ switch (proc_data->rotate) {
+ case 0:
+ s0param_ulc = BF_PXP_OUT_PS_ULC_X(proc_data->drect.left);
+ s0param_ulc |= BF_PXP_OUT_PS_ULC_Y(proc_data->drect.top);
+ s0param_lrc = BF_PXP_OUT_PS_LRC_X(((s0param_ulc & BM_PXP_OUT_PS_ULC_X) >> 16) + proc_data->drect.width - 1);
+ s0param_lrc |= BF_PXP_OUT_PS_LRC_Y((s0param_ulc & BM_PXP_OUT_PS_ULC_Y) + proc_data->drect.height - 1);
+ break;
+ case 90:
+ s0param_ulc = BF_PXP_OUT_PS_ULC_Y(out_params->width - (proc_data->drect.left + proc_data->drect.width));
+ s0param_ulc |= BF_PXP_OUT_PS_ULC_X(proc_data->drect.top);
+ s0param_lrc = BF_PXP_OUT_PS_LRC_X(((s0param_ulc & BM_PXP_OUT_PS_ULC_X) >> 16) + proc_data->drect.height - 1);
+ s0param_lrc |= BF_PXP_OUT_PS_LRC_Y((s0param_ulc & BM_PXP_OUT_PS_ULC_Y) + proc_data->drect.width - 1);
+ break;
+ case 180:
+ s0param_ulc = BF_PXP_OUT_PS_ULC_X(out_params->width - (proc_data->drect.left + proc_data->drect.width));
+ s0param_ulc |= BF_PXP_OUT_PS_ULC_Y(out_params->height - (proc_data->drect.top + proc_data->drect.height));
+ s0param_lrc = BF_PXP_OUT_PS_LRC_X(((s0param_ulc & BM_PXP_OUT_PS_ULC_X) >> 16) + proc_data->drect.width - 1);
+ s0param_lrc |= BF_PXP_OUT_PS_LRC_Y((s0param_ulc & BM_PXP_OUT_PS_ULC_Y) + proc_data->drect.height - 1);
+ break;
+ case 270:
+ s0param_ulc = BF_PXP_OUT_PS_ULC_X(out_params->height - (proc_data->drect.top + proc_data->drect.height));
+ s0param_ulc |= BF_PXP_OUT_PS_ULC_Y(proc_data->drect.left);
+ s0param_lrc = BF_PXP_OUT_PS_LRC_X(((s0param_ulc & BM_PXP_OUT_PS_ULC_X) >> 16) + proc_data->drect.height - 1);
+ s0param_lrc |= BF_PXP_OUT_PS_LRC_Y((s0param_ulc & BM_PXP_OUT_PS_ULC_Y) + proc_data->drect.width - 1);
+ break;
+ default:
+ return;
+ }
+ __raw_writel(s0param_ulc, pxp->base + HW_PXP_OUT_PS_ULC);
+ __raw_writel(s0param_lrc, pxp->base + HW_PXP_OUT_PS_LRC);
+ }
+
+ /* Since user apps always pass the rotated drect
+ * to this driver, we need to first swap the width
+ * and height which is used to calculate the scale
+ * factors later.
+ */
+ if (proc_data->rotate == 90 || proc_data->rotate == 270) {
+ int temp;
+ temp = proc_data->drect.width;
+ proc_data->drect.width = proc_data->drect.height;
+ proc_data->drect.height = temp;
+ }
+}
+
+/* crop behavior is re-designed in h/w. */
+static void pxp_set_s0crop(struct pxps *pxp)
+{
+ /*
+ * place-holder, it's implemented in other functions in this driver.
+ * Refer to "Clipping source images" section in RM for detail.
+ */
+}
+
+static int pxp_set_scaling(struct pxps *pxp)
+{
+ int ret = 0;
+ u32 xscale, yscale, s0scale;
+ u32 decx, decy, xdec = 0, ydec = 0;
+ struct pxp_proc_data *proc_data = &pxp->pxp_conf_state.proc_data;
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_layer_param *s0_params = &pxp_conf->s0_param;
+ struct pxp_layer_param *out_params = &pxp_conf->out_param;
+
+ proc_data->scaling = 1;
+
+ if (!proc_data->drect.width || !proc_data->drect.height) {
+ pr_err("Invalid drect width and height passed in\n");
+ return -EINVAL;
+ }
+
+ decx = proc_data->srect.width / proc_data->drect.width;
+ decy = proc_data->srect.height / proc_data->drect.height;
+ if (decx > 1) {
+ if (decx >= 2 && decx < 4) {
+ decx = 2;
+ xdec = 1;
+ } else if (decx >= 4 && decx < 8) {
+ decx = 4;
+ xdec = 2;
+ } else if (decx >= 8) {
+ decx = 8;
+ xdec = 3;
+ }
+ xscale = proc_data->srect.width * 0x1000 /
+ (proc_data->drect.width * decx);
+ } else {
+ if (!is_yuv(s0_params->pixel_fmt) ||
+ (is_yuv(s0_params->pixel_fmt) ==
+ is_yuv(out_params->pixel_fmt)) ||
+ (s0_params->pixel_fmt == PXP_PIX_FMT_GREY) ||
+ (s0_params->pixel_fmt == PXP_PIX_FMT_GY04) ||
+ (s0_params->pixel_fmt == PXP_PIX_FMT_VUY444)) {
+ if ((proc_data->srect.width > 1) &&
+ (proc_data->drect.width > 1))
+ xscale = (proc_data->srect.width - 1) * 0x1000 /
+ (proc_data->drect.width - 1);
+ else
+ xscale = proc_data->srect.width * 0x1000 /
+ proc_data->drect.width;
+ } else {
+ if ((proc_data->srect.width > 2) &&
+ (proc_data->drect.width > 1))
+ xscale = (proc_data->srect.width - 2) * 0x1000 /
+ (proc_data->drect.width - 1);
+ else
+ xscale = proc_data->srect.width * 0x1000 /
+ proc_data->drect.width;
+ }
+ }
+ if (decy > 1) {
+ if (decy >= 2 && decy < 4) {
+ decy = 2;
+ ydec = 1;
+ } else if (decy >= 4 && decy < 8) {
+ decy = 4;
+ ydec = 2;
+ } else if (decy >= 8) {
+ decy = 8;
+ ydec = 3;
+ }
+ yscale = proc_data->srect.height * 0x1000 /
+ (proc_data->drect.height * decy);
+ } else {
+ if ((proc_data->srect.height > 1) &&
+ (proc_data->drect.height > 1))
+ yscale = (proc_data->srect.height - 1) * 0x1000 /
+ (proc_data->drect.height - 1);
+ else
+ yscale = proc_data->srect.height * 0x1000 /
+ proc_data->drect.height;
+ }
+
+ __raw_writel((xdec << 10) | (ydec << 8), pxp->base + HW_PXP_PS_CTRL);
+
+ if (xscale > PXP_DOWNSCALE_THRESHOLD)
+ xscale = PXP_DOWNSCALE_THRESHOLD;
+ if (yscale > PXP_DOWNSCALE_THRESHOLD)
+ yscale = PXP_DOWNSCALE_THRESHOLD;
+ s0scale = BF_PXP_PS_SCALE_YSCALE(yscale) |
+ BF_PXP_PS_SCALE_XSCALE(xscale);
+ __raw_writel(s0scale, pxp->base + HW_PXP_PS_SCALE);
+
+ pxp_set_ctrl(pxp);
+
+ return ret;
+}
+
+static void pxp_set_bg(struct pxps *pxp)
+{
+ __raw_writel(pxp->pxp_conf_state.proc_data.bgcolor,
+ pxp->base + HW_PXP_PS_BACKGROUND);
+}
+
+static void pxp_set_lut(struct pxps *pxp)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ int lut_op = pxp_conf->proc_data.lut_transform;
+ u32 reg_val;
+ int i;
+ bool use_cmap = (lut_op & PXP_LUT_USE_CMAP) ? true : false;
+ u8 *cmap = pxp_conf->proc_data.lut_map;
+ u32 entry_src;
+ u32 pix_val;
+ u8 entry[4];
+
+ /*
+ * If LUT already configured as needed, return...
+ * Unless CMAP is needed and it has been updated.
+ */
+ if ((pxp->lut_state == lut_op) &&
+ !(use_cmap && pxp_conf->proc_data.lut_map_updated))
+ return;
+
+ if (lut_op == PXP_LUT_NONE) {
+ __raw_writel(BM_PXP_LUT_CTRL_BYPASS,
+ pxp->base + HW_PXP_LUT_CTRL);
+ } else if (((lut_op & PXP_LUT_INVERT) != 0)
+ && ((lut_op & PXP_LUT_BLACK_WHITE) != 0)) {
+ /* Fill out LUT table with inverted monochromized values */
+
+ /* clear bypass bit, set lookup mode & out mode */
+ __raw_writel(BF_PXP_LUT_CTRL_LOOKUP_MODE
+ (BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8) |
+ BF_PXP_LUT_CTRL_OUT_MODE
+ (BV_PXP_LUT_CTRL_OUT_MODE__Y8),
+ pxp->base + HW_PXP_LUT_CTRL);
+
+ /* Initialize LUT address to 0 and set NUM_BYTES to 0 */
+ __raw_writel(0, pxp->base + HW_PXP_LUT_ADDR);
+
+ /* LUT address pointer auto-increments after each data write */
+ for (pix_val = 0; pix_val < 256; pix_val += 4) {
+ for (i = 0; i < 4; i++) {
+ entry_src = use_cmap ?
+ cmap[pix_val + i] : pix_val + i;
+ entry[i] = (entry_src < 0x80) ? 0xFF : 0x00;
+ }
+ reg_val = (entry[3] << 24) | (entry[2] << 16) |
+ (entry[1] << 8) | entry[0];
+ __raw_writel(reg_val, pxp->base + HW_PXP_LUT_DATA);
+ }
+ } else if ((lut_op & PXP_LUT_INVERT) != 0) {
+ /* Fill out LUT table with 8-bit inverted values */
+
+ /* clear bypass bit, set lookup mode & out mode */
+ __raw_writel(BF_PXP_LUT_CTRL_LOOKUP_MODE
+ (BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8) |
+ BF_PXP_LUT_CTRL_OUT_MODE
+ (BV_PXP_LUT_CTRL_OUT_MODE__Y8),
+ pxp->base + HW_PXP_LUT_CTRL);
+
+ /* Initialize LUT address to 0 and set NUM_BYTES to 0 */
+ __raw_writel(0, pxp->base + HW_PXP_LUT_ADDR);
+
+ /* LUT address pointer auto-increments after each data write */
+ for (pix_val = 0; pix_val < 256; pix_val += 4) {
+ for (i = 0; i < 4; i++) {
+ entry_src = use_cmap ?
+ cmap[pix_val + i] : pix_val + i;
+ entry[i] = ~entry_src & 0xFF;
+ }
+ reg_val = (entry[3] << 24) | (entry[2] << 16) |
+ (entry[1] << 8) | entry[0];
+ __raw_writel(reg_val, pxp->base + HW_PXP_LUT_DATA);
+ }
+ } else if ((lut_op & PXP_LUT_BLACK_WHITE) != 0) {
+ /* Fill out LUT table with 8-bit monochromized values */
+
+ /* clear bypass bit, set lookup mode & out mode */
+ __raw_writel(BF_PXP_LUT_CTRL_LOOKUP_MODE
+ (BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8) |
+ BF_PXP_LUT_CTRL_OUT_MODE
+ (BV_PXP_LUT_CTRL_OUT_MODE__Y8),
+ pxp->base + HW_PXP_LUT_CTRL);
+
+ /* Initialize LUT address to 0 and set NUM_BYTES to 0 */
+ __raw_writel(0, pxp->base + HW_PXP_LUT_ADDR);
+
+ /* LUT address pointer auto-increments after each data write */
+ for (pix_val = 0; pix_val < 256; pix_val += 4) {
+ for (i = 0; i < 4; i++) {
+ entry_src = use_cmap ?
+ cmap[pix_val + i] : pix_val + i;
+ entry[i] = (entry_src < 0x80) ? 0x00 : 0xFF;
+ }
+ reg_val = (entry[3] << 24) | (entry[2] << 16) |
+ (entry[1] << 8) | entry[0];
+ __raw_writel(reg_val, pxp->base + HW_PXP_LUT_DATA);
+ }
+ } else if (use_cmap) {
+ /* Fill out LUT table using colormap values */
+
+ /* clear bypass bit, set lookup mode & out mode */
+ __raw_writel(BF_PXP_LUT_CTRL_LOOKUP_MODE
+ (BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8) |
+ BF_PXP_LUT_CTRL_OUT_MODE
+ (BV_PXP_LUT_CTRL_OUT_MODE__Y8),
+ pxp->base + HW_PXP_LUT_CTRL);
+
+ /* Initialize LUT address to 0 and set NUM_BYTES to 0 */
+ __raw_writel(0, pxp->base + HW_PXP_LUT_ADDR);
+
+ /* LUT address pointer auto-increments after each data write */
+ for (pix_val = 0; pix_val < 256; pix_val += 4) {
+ for (i = 0; i < 4; i++)
+ entry[i] = cmap[pix_val + i];
+ reg_val = (entry[3] << 24) | (entry[2] << 16) |
+ (entry[1] << 8) | entry[0];
+ __raw_writel(reg_val, pxp->base + HW_PXP_LUT_DATA);
+ }
+ }
+
+ pxp->lut_state = lut_op;
+}
+
+static void pxp_set_csc(struct pxps *pxp)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_layer_param *s0_params = &pxp_conf->s0_param;
+ struct pxp_layer_param *ol_params = &pxp_conf->ol_param[0];
+ struct pxp_layer_param *out_params = &pxp_conf->out_param;
+
+ bool input_is_YUV = is_yuv(s0_params->pixel_fmt);
+ bool output_is_YUV = is_yuv(out_params->pixel_fmt);
+
+ if (input_is_YUV && output_is_YUV) {
+ /*
+ * Input = YUV, Output = YUV
+ * No CSC unless we need to do combining
+ */
+ if (ol_params->combine_enable) {
+ /* Must convert to RGB for combining with RGB overlay */
+
+ /* CSC1 - YUV->RGB */
+ __raw_writel(0x04030000, pxp->base + HW_PXP_CSC1_COEF0);
+ __raw_writel(0x01230208, pxp->base + HW_PXP_CSC1_COEF1);
+ __raw_writel(0x076b079c, pxp->base + HW_PXP_CSC1_COEF2);
+
+ /* CSC2 - RGB->YUV */
+ __raw_writel(0x4, pxp->base + HW_PXP_CSC2_CTRL);
+ __raw_writel(0x0096004D, pxp->base + HW_PXP_CSC2_COEF0);
+ __raw_writel(0x05DA001D, pxp->base + HW_PXP_CSC2_COEF1);
+ __raw_writel(0x007005B6, pxp->base + HW_PXP_CSC2_COEF2);
+ __raw_writel(0x057C009E, pxp->base + HW_PXP_CSC2_COEF3);
+ __raw_writel(0x000005E6, pxp->base + HW_PXP_CSC2_COEF4);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_CSC2_COEF5);
+ } else {
+ /* Input & Output both YUV, so bypass both CSCs */
+
+ /* CSC1 - Bypass */
+ __raw_writel(0x40000000, pxp->base + HW_PXP_CSC1_COEF0);
+
+ /* CSC2 - Bypass */
+ __raw_writel(0x1, pxp->base + HW_PXP_CSC2_CTRL);
+ }
+ } else if (input_is_YUV && !output_is_YUV) {
+ /*
+ * Input = YUV, Output = RGB
+ * Use CSC1 to convert to RGB
+ */
+
+ /* CSC1 - YUV->RGB */
+ __raw_writel(0x84ab01f0, pxp->base + HW_PXP_CSC1_COEF0);
+ __raw_writel(0x01980204, pxp->base + HW_PXP_CSC1_COEF1);
+ __raw_writel(0x0730079c, pxp->base + HW_PXP_CSC1_COEF2);
+
+ /* CSC2 - Bypass */
+ __raw_writel(0x1, pxp->base + HW_PXP_CSC2_CTRL);
+ } else if (!input_is_YUV && output_is_YUV) {
+ /*
+ * Input = RGB, Output = YUV
+ * Use CSC2 to convert to YUV
+ */
+
+ /* CSC1 - Bypass */
+ __raw_writel(0x40000000, pxp->base + HW_PXP_CSC1_COEF0);
+
+ /* CSC2 - RGB->YUV */
+ __raw_writel(0x4, pxp->base + HW_PXP_CSC2_CTRL);
+ __raw_writel(0x0096004D, pxp->base + HW_PXP_CSC2_COEF0);
+ __raw_writel(0x05DA001D, pxp->base + HW_PXP_CSC2_COEF1);
+ __raw_writel(0x007005B6, pxp->base + HW_PXP_CSC2_COEF2);
+ __raw_writel(0x057C009E, pxp->base + HW_PXP_CSC2_COEF3);
+ __raw_writel(0x000005E6, pxp->base + HW_PXP_CSC2_COEF4);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_CSC2_COEF5);
+ } else {
+ /*
+ * Input = RGB, Output = RGB
+ * Input & Output both RGB, so bypass both CSCs
+ */
+
+ /* CSC1 - Bypass */
+ __raw_writel(0x40000000, pxp->base + HW_PXP_CSC1_COEF0);
+
+ /* CSC2 - Bypass */
+ __raw_writel(0x1, pxp->base + HW_PXP_CSC2_CTRL);
+ }
+
+ /* YCrCb colorspace */
+ /* Not sure when we use this...no YCrCb formats are defined for PxP */
+ /*
+ __raw_writel(0x84ab01f0, HW_PXP_CSCCOEFF0_ADDR);
+ __raw_writel(0x01230204, HW_PXP_CSCCOEFF1_ADDR);
+ __raw_writel(0x0730079c, HW_PXP_CSCCOEFF2_ADDR);
+ */
+
+}
+
+static void pxp_set_s0buf(struct pxps *pxp)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_layer_param *s0_params = &pxp_conf->s0_param;
+ struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+ dma_addr_t Y, U, V;
+ dma_addr_t Y1, U1, V1;
+ u32 offset, bpp = 1;
+ u32 pitch = s0_params->stride ? s0_params->stride :
+ s0_params->width;
+
+ Y = s0_params->paddr;
+
+ if ((s0_params->pixel_fmt == PXP_PIX_FMT_RGB565) ||
+ (s0_params->pixel_fmt == PXP_PIX_FMT_RGB555))
+ bpp = 2;
+ else if (s0_params->pixel_fmt == PXP_PIX_FMT_XRGB32)
+ bpp = 4;
+ offset = (proc_data->srect.top * s0_params->width +
+ proc_data->srect.left) * bpp;
+ /* clipping or cropping */
+ Y1 = Y + offset;
+ __raw_writel(Y1, pxp->base + HW_PXP_PS_BUF);
+ if ((s0_params->pixel_fmt == PXP_PIX_FMT_YUV420P) ||
+ (s0_params->pixel_fmt == PXP_PIX_FMT_YVU420P) ||
+ (s0_params->pixel_fmt == PXP_PIX_FMT_GREY) ||
+ (s0_params->pixel_fmt == PXP_PIX_FMT_YUV422P)) {
+ /* Set to 1 if YUV format is 4:2:2 rather than 4:2:0 */
+ int s = 2;
+ if (s0_params->pixel_fmt == PXP_PIX_FMT_YUV422P)
+ s = 1;
+
+ offset = proc_data->srect.top * s0_params->width / 4 +
+ proc_data->srect.left / 2;
+ U = Y + (s0_params->width * s0_params->height);
+ U1 = U + offset;
+ V = U + ((s0_params->width * s0_params->height) >> s);
+ V1 = V + offset;
+ if (s0_params->pixel_fmt == PXP_PIX_FMT_YVU420P) {
+ __raw_writel(V1, pxp->base + HW_PXP_PS_UBUF);
+ __raw_writel(U1, pxp->base + HW_PXP_PS_VBUF);
+ } else {
+ __raw_writel(U1, pxp->base + HW_PXP_PS_UBUF);
+ __raw_writel(V1, pxp->base + HW_PXP_PS_VBUF);
+ }
+ } else if ((s0_params->pixel_fmt == PXP_PIX_FMT_NV12) ||
+ (s0_params->pixel_fmt == PXP_PIX_FMT_NV21) ||
+ (s0_params->pixel_fmt == PXP_PIX_FMT_NV16) ||
+ (s0_params->pixel_fmt == PXP_PIX_FMT_NV61)) {
+ int s = 2;
+ if ((s0_params->pixel_fmt == PXP_PIX_FMT_NV16) ||
+ (s0_params->pixel_fmt == PXP_PIX_FMT_NV61))
+ s = 1;
+
+ offset = (proc_data->srect.top * s0_params->width +
+ proc_data->srect.left) / s;
+ U = Y + (s0_params->width * s0_params->height);
+ U1 = U + offset;
+
+ __raw_writel(U1, pxp->base + HW_PXP_PS_UBUF);
+ }
+
+ /* TODO: only support RGB565, Y8, Y4, YUV420 */
+ if (s0_params->pixel_fmt == PXP_PIX_FMT_GREY ||
+ s0_params->pixel_fmt == PXP_PIX_FMT_YUV420P ||
+ s0_params->pixel_fmt == PXP_PIX_FMT_YVU420P ||
+ s0_params->pixel_fmt == PXP_PIX_FMT_NV12 ||
+ s0_params->pixel_fmt == PXP_PIX_FMT_NV21 ||
+ s0_params->pixel_fmt == PXP_PIX_FMT_NV16 ||
+ s0_params->pixel_fmt == PXP_PIX_FMT_NV61 ||
+ s0_params->pixel_fmt == PXP_PIX_FMT_YUV422P) {
+ __raw_writel(pitch, pxp->base + HW_PXP_PS_PITCH);
+ }
+ else if (s0_params->pixel_fmt == PXP_PIX_FMT_GY04)
+ __raw_writel(pitch >> 1,
+ pxp->base + HW_PXP_PS_PITCH);
+ else if (s0_params->pixel_fmt == PXP_PIX_FMT_XRGB32 ||
+ s0_params->pixel_fmt == PXP_PIX_FMT_VUY444)
+ __raw_writel(pitch << 2,
+ pxp->base + HW_PXP_PS_PITCH);
+ else if (s0_params->pixel_fmt == PXP_PIX_FMT_UYVY ||
+ s0_params->pixel_fmt == PXP_PIX_FMT_YUYV ||
+ s0_params->pixel_fmt == PXP_PIX_FMT_VYUY ||
+ s0_params->pixel_fmt == PXP_PIX_FMT_YVYU)
+ __raw_writel(pitch << 1,
+ pxp->base + HW_PXP_PS_PITCH);
+ else if ((s0_params->pixel_fmt == PXP_PIX_FMT_RGB565) ||
+ (s0_params->pixel_fmt == PXP_PIX_FMT_RGB555))
+ __raw_writel(pitch << 1,
+ pxp->base + HW_PXP_PS_PITCH);
+ else
+ __raw_writel(0, pxp->base + HW_PXP_PS_PITCH);
+}
+
+/**
+ * pxp_config() - configure PxP for a processing task
+ * @pxps: PXP context.
+ * @pxp_chan: PXP channel.
+ * @return: 0 on success or negative error code on failure.
+ */
+static int pxp_config(struct pxps *pxp, struct pxp_channel *pxp_chan)
+{
+ /* Configure PxP regs */
+ pxp_set_ctrl(pxp);
+ pxp_set_s0param(pxp);
+ pxp_set_s0crop(pxp);
+ pxp_set_scaling(pxp);
+ pxp_set_s0colorkey(pxp);
+
+ pxp_set_oln(0, pxp);
+ pxp_set_olparam(0, pxp);
+ pxp_set_olcolorkey(0, pxp);
+
+ pxp_set_csc(pxp);
+ pxp_set_bg(pxp);
+ pxp_set_lut(pxp);
+
+ pxp_set_s0buf(pxp);
+ pxp_set_outbuf(pxp);
+
+ return 0;
+}
+
+static void pxp_clk_enable(struct pxps *pxp)
+{
+ mutex_lock(&pxp->clk_mutex);
+
+ if (pxp->clk_stat == CLK_STAT_ON) {
+ mutex_unlock(&pxp->clk_mutex);
+ return;
+ }
+
+ pm_runtime_get_sync(pxp->dev);
+
+ if (pxp->clk_disp_axi)
+ clk_prepare_enable(pxp->clk_disp_axi);
+ clk_prepare_enable(pxp->clk);
+ pxp->clk_stat = CLK_STAT_ON;
+
+ mutex_unlock(&pxp->clk_mutex);
+}
+
+static void pxp_clk_disable(struct pxps *pxp)
+{
+ unsigned long flags;
+
+ mutex_lock(&pxp->clk_mutex);
+
+ if (pxp->clk_stat == CLK_STAT_OFF) {
+ mutex_unlock(&pxp->clk_mutex);
+ return;
+ }
+
+ spin_lock_irqsave(&pxp->lock, flags);
+ if ((pxp->pxp_ongoing == 0) && list_empty(&head)) {
+ spin_unlock_irqrestore(&pxp->lock, flags);
+ clk_disable_unprepare(pxp->clk);
+ if (pxp->clk_disp_axi)
+ clk_disable_unprepare(pxp->clk_disp_axi);
+ pxp->clk_stat = CLK_STAT_OFF;
+ pm_runtime_put_sync_suspend(pxp->dev);
+ } else
+ spin_unlock_irqrestore(&pxp->lock, flags);
+
+ mutex_unlock(&pxp->clk_mutex);
+}
+
+static inline void clkoff_callback(struct work_struct *w)
+{
+ struct pxps *pxp = container_of(w, struct pxps, work);
+
+ pxp_clk_disable(pxp);
+}
+
+static void pxp_clkoff_timer(unsigned long arg)
+{
+ struct pxps *pxp = (struct pxps *)arg;
+
+ if ((pxp->pxp_ongoing == 0) && list_empty(&head))
+ schedule_work(&pxp->work);
+ else
+ mod_timer(&pxp->clk_timer,
+ jiffies + msecs_to_jiffies(timeout_in_ms));
+}
+
+static struct pxp_tx_desc *pxpdma_first_queued(struct pxp_channel *pxp_chan)
+{
+ return list_entry(pxp_chan->queue.next, struct pxp_tx_desc, list);
+}
+
+/* called with pxp_chan->lock held */
+static void __pxpdma_dostart(struct pxp_channel *pxp_chan)
+{
+ struct pxp_dma *pxp_dma = to_pxp_dma(pxp_chan->dma_chan.device);
+ struct pxps *pxp = to_pxp(pxp_dma);
+ struct pxp_tx_desc *desc;
+ struct pxp_tx_desc *child;
+ int i = 0;
+
+ memset(&pxp->pxp_conf_state.s0_param, 0, sizeof(struct pxp_layer_param));
+ memset(&pxp->pxp_conf_state.out_param, 0, sizeof(struct pxp_layer_param));
+ memset(pxp->pxp_conf_state.ol_param, 0, sizeof(struct pxp_layer_param) * 8);
+ memset(&pxp->pxp_conf_state.proc_data, 0, sizeof(struct pxp_proc_data));
+ /* S0 */
+ desc = list_first_entry(&head, struct pxp_tx_desc, list);
+ memcpy(&pxp->pxp_conf_state.s0_param,
+ &desc->layer_param.s0_param, sizeof(struct pxp_layer_param));
+ memcpy(&pxp->pxp_conf_state.proc_data,
+ &desc->proc_data, sizeof(struct pxp_proc_data));
+
+ /* Save PxP configuration */
+ list_for_each_entry(child, &desc->tx_list, list) {
+ if (i == 0) { /* Output */
+ memcpy(&pxp->pxp_conf_state.out_param,
+ &child->layer_param.out_param,
+ sizeof(struct pxp_layer_param));
+ } else { /* Overlay */
+ memcpy(&pxp->pxp_conf_state.ol_param[i - 1],
+ &child->layer_param.ol_param,
+ sizeof(struct pxp_layer_param));
+ }
+
+ i++;
+ }
+ pr_debug("%s:%d S0 w/h %d/%d paddr %08x\n", __func__, __LINE__,
+ pxp->pxp_conf_state.s0_param.width,
+ pxp->pxp_conf_state.s0_param.height,
+ pxp->pxp_conf_state.s0_param.paddr);
+ pr_debug("%s:%d OUT w/h %d/%d paddr %08x\n", __func__, __LINE__,
+ pxp->pxp_conf_state.out_param.width,
+ pxp->pxp_conf_state.out_param.height,
+ pxp->pxp_conf_state.out_param.paddr);
+}
+
+static void pxpdma_dostart_work(struct pxps *pxp)
+{
+ struct pxp_channel *pxp_chan = NULL;
+ unsigned long flags;
+ struct pxp_tx_desc *desc = NULL;
+
+ spin_lock_irqsave(&pxp->lock, flags);
+
+ desc = list_entry(head.next, struct pxp_tx_desc, list);
+ pxp_chan = to_pxp_channel(desc->txd.chan);
+
+ __pxpdma_dostart(pxp_chan);
+
+ /* Configure PxP */
+ pxp_config(pxp, pxp_chan);
+
+ pxp_start(pxp);
+
+ spin_unlock_irqrestore(&pxp->lock, flags);
+}
+
+static void pxpdma_dequeue(struct pxp_channel *pxp_chan, struct pxps *pxp)
+{
+ unsigned long flags;
+ struct pxp_tx_desc *desc = NULL;
+
+ do {
+ desc = pxpdma_first_queued(pxp_chan);
+ spin_lock_irqsave(&pxp->lock, flags);
+ list_move_tail(&desc->list, &head);
+ spin_unlock_irqrestore(&pxp->lock, flags);
+ } while (!list_empty(&pxp_chan->queue));
+}
+
+static dma_cookie_t pxp_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct pxp_tx_desc *desc = to_tx_desc(tx);
+ struct pxp_channel *pxp_chan = to_pxp_channel(tx->chan);
+ dma_cookie_t cookie;
+
+ dev_dbg(&pxp_chan->dma_chan.dev->device, "received TX\n");
+
+ /* pxp_chan->lock can be taken under ichan->lock, but not v.v. */
+ spin_lock(&pxp_chan->lock);
+
+ cookie = pxp_chan->dma_chan.cookie;
+
+ if (++cookie < 0)
+ cookie = 1;
+
+ /* from dmaengine.h: "last cookie value returned to client" */
+ pxp_chan->dma_chan.cookie = cookie;
+ tx->cookie = cookie;
+
+ /* Here we add the tx descriptor to our PxP task queue. */
+ list_add_tail(&desc->list, &pxp_chan->queue);
+
+ spin_unlock(&pxp_chan->lock);
+
+ dev_dbg(&pxp_chan->dma_chan.dev->device, "done TX\n");
+
+ return cookie;
+}
+
+/**
+ * pxp_init_channel() - initialize a PXP channel.
+ * @pxp_dma: PXP DMA context.
+ * @pchan: pointer to the channel object.
+ * @return 0 on success or negative error code on failure.
+ */
+static int pxp_init_channel(struct pxp_dma *pxp_dma,
+ struct pxp_channel *pxp_chan)
+{
+ int ret = 0;
+
+ /*
+ * We are using _virtual_ channel here.
+ * Each channel contains all parameters of corresponding layers
+ * for one transaction; each layer is represented as one descriptor
+ * (i.e., pxp_tx_desc) here.
+ */
+
+ INIT_LIST_HEAD(&pxp_chan->queue);
+
+ return ret;
+}
+
+static irqreturn_t pxp_irq(int irq, void *dev_id)
+{
+ struct pxps *pxp = dev_id;
+ struct pxp_channel *pxp_chan;
+ struct pxp_tx_desc *desc;
+ struct pxp_tx_desc *child, *_child;
+ dma_async_tx_callback callback;
+ void *callback_param;
+ unsigned long flags;
+ u32 hist_status;
+
+ dump_pxp_reg(pxp);
+
+ hist_status =
+ __raw_readl(pxp->base + HW_PXP_HIST_CTRL) & BM_PXP_HIST_CTRL_STATUS;
+
+ __raw_writel(BM_PXP_STAT_IRQ, pxp->base + HW_PXP_STAT_CLR);
+
+ /* set the SFTRST bit to be 1 to reset
+ * the PXP block to its default state.
+ */
+ pxp_soft_reset(pxp);
+
+ spin_lock_irqsave(&pxp->lock, flags);
+
+ if (list_empty(&head)) {
+ pxp->pxp_ongoing = 0;
+ spin_unlock_irqrestore(&pxp->lock, flags);
+ return IRQ_NONE;
+ }
+
+ /* Get descriptor and call callback */
+ desc = list_entry(head.next, struct pxp_tx_desc, list);
+ pxp_chan = to_pxp_channel(desc->txd.chan);
+
+ pxp_chan->completed = desc->txd.cookie;
+
+ callback = desc->txd.callback;
+ callback_param = desc->txd.callback_param;
+
+ /* Send histogram status back to caller */
+ desc->hist_status = hist_status;
+
+ if ((desc->txd.flags & DMA_PREP_INTERRUPT) && callback)
+ callback(callback_param);
+
+ pxp_chan->status = PXP_CHANNEL_INITIALIZED;
+
+ list_for_each_entry_safe(child, _child, &desc->tx_list, list) {
+ list_del_init(&child->list);
+ kmem_cache_free(tx_desc_cache, (void *)child);
+ }
+ list_del_init(&desc->list);
+ kmem_cache_free(tx_desc_cache, (void *)desc);
+
+ complete(&pxp->complete);
+ pxp->pxp_ongoing = 0;
+ mod_timer(&pxp->clk_timer, jiffies + msecs_to_jiffies(timeout_in_ms));
+
+ spin_unlock_irqrestore(&pxp->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+/* allocate/free dma tx descriptor dynamically*/
+static struct pxp_tx_desc *pxpdma_desc_alloc(struct pxp_channel *pxp_chan)
+{
+ struct pxp_tx_desc *desc = NULL;
+ struct dma_async_tx_descriptor *txd = NULL;
+
+ desc = kmem_cache_alloc(tx_desc_cache, GFP_KERNEL | __GFP_ZERO);
+ if (desc == NULL)
+ return NULL;
+
+ INIT_LIST_HEAD(&desc->list);
+ INIT_LIST_HEAD(&desc->tx_list);
+ txd = &desc->txd;
+ dma_async_tx_descriptor_init(txd, &pxp_chan->dma_chan);
+ txd->tx_submit = pxp_tx_submit;
+
+ return desc;
+}
+
+/* Allocate and initialise a transfer descriptor. */
+static struct dma_async_tx_descriptor *pxp_prep_slave_sg(struct dma_chan *chan,
+ struct scatterlist
+ *sgl,
+ unsigned int sg_len,
+ enum
+ dma_transfer_direction
+ direction,
+ unsigned long tx_flags,
+ void *context)
+{
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+ struct pxp_dma *pxp_dma = to_pxp_dma(chan->device);
+ struct pxps *pxp = to_pxp(pxp_dma);
+ struct pxp_tx_desc *pos = NULL, *next = NULL;
+ struct pxp_tx_desc *desc = NULL;
+ struct pxp_tx_desc *first = NULL, *prev = NULL;
+ struct scatterlist *sg;
+ dma_addr_t phys_addr;
+ int i;
+
+ if (direction != DMA_DEV_TO_MEM && direction != DMA_MEM_TO_DEV) {
+ dev_err(chan->device->dev, "Invalid DMA direction %d!\n",
+ direction);
+ return NULL;
+ }
+
+ if (unlikely(sg_len < 2))
+ return NULL;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ desc = pxpdma_desc_alloc(pxp_chan);
+ if (!desc) {
+ dev_err(chan->device->dev, "no enough memory to allocate tx descriptor\n");
+
+ if (first) {
+ list_for_each_entry_safe(pos, next, &first->tx_list, list) {
+ list_del_init(&pos->list);
+ kmem_cache_free(tx_desc_cache, (void*)pos);
+ }
+ list_del_init(&first->list);
+ kmem_cache_free(tx_desc_cache, (void*)first);
+ }
+
+ return NULL;
+ }
+
+ phys_addr = sg_dma_address(sg);
+
+ if (!first) {
+ first = desc;
+
+ desc->layer_param.s0_param.paddr = phys_addr;
+ } else {
+ list_add_tail(&desc->list, &first->tx_list);
+ prev->next = desc;
+ desc->next = NULL;
+
+ if (i == 1)
+ desc->layer_param.out_param.paddr = phys_addr;
+ else
+ desc->layer_param.ol_param.paddr = phys_addr;
+ }
+
+ prev = desc;
+ }
+
+ pxp->pxp_conf_state.layer_nr = sg_len;
+ first->txd.flags = tx_flags;
+ first->len = sg_len;
+ pr_debug("%s:%d first %p, first->len %d, flags %08x\n",
+ __func__, __LINE__, first, first->len, first->txd.flags);
+
+ return &first->txd;
+}
+
+static void pxp_issue_pending(struct dma_chan *chan)
+{
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+ struct pxp_dma *pxp_dma = to_pxp_dma(chan->device);
+ struct pxps *pxp = to_pxp(pxp_dma);
+
+ spin_lock(&pxp_chan->lock);
+
+ if (list_empty(&pxp_chan->queue)) {
+ spin_unlock(&pxp_chan->lock);
+ return;
+ }
+
+ pxpdma_dequeue(pxp_chan, pxp);
+ pxp_chan->status = PXP_CHANNEL_READY;
+
+ spin_unlock(&pxp_chan->lock);
+
+ pxp_clk_enable(pxp);
+ wake_up_interruptible(&pxp->thread_waitq);
+}
+
+static void __pxp_terminate_all(struct dma_chan *chan)
+{
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+
+ pxp_chan->status = PXP_CHANNEL_INITIALIZED;
+}
+
+static int pxp_device_terminate_all(struct dma_chan *chan)
+{
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+
+ spin_lock(&pxp_chan->lock);
+ __pxp_terminate_all(chan);
+ spin_unlock(&pxp_chan->lock);
+
+ return 0;
+}
+
+static int pxp_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+ struct pxp_dma *pxp_dma = to_pxp_dma(chan->device);
+ int ret;
+
+ /* dmaengine.c now guarantees to only offer free channels */
+ BUG_ON(chan->client_count > 1);
+ WARN_ON(pxp_chan->status != PXP_CHANNEL_FREE);
+
+ chan->cookie = 1;
+ pxp_chan->completed = -ENXIO;
+
+ pr_debug("%s dma_chan.chan_id %d\n", __func__, chan->chan_id);
+ ret = pxp_init_channel(pxp_dma, pxp_chan);
+ if (ret < 0)
+ goto err_chan;
+
+ pxp_chan->status = PXP_CHANNEL_INITIALIZED;
+
+ dev_dbg(&chan->dev->device, "Found channel 0x%x, irq %d\n",
+ chan->chan_id, pxp_chan->eof_irq);
+
+ return ret;
+
+err_chan:
+ return ret;
+}
+
+static void pxp_free_chan_resources(struct dma_chan *chan)
+{
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+
+ spin_lock(&pxp_chan->lock);
+
+ __pxp_terminate_all(chan);
+
+ pxp_chan->status = PXP_CHANNEL_FREE;
+
+ spin_unlock(&pxp_chan->lock);
+}
+
+static enum dma_status pxp_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+
+ if (cookie != chan->cookie)
+ return DMA_ERROR;
+
+ if (txstate) {
+ txstate->last = pxp_chan->completed;
+ txstate->used = chan->cookie;
+ txstate->residue = 0;
+ }
+ return DMA_COMPLETE;
+}
+
+static int pxp_dma_init(struct pxps *pxp)
+{
+ struct pxp_dma *pxp_dma = &pxp->pxp_dma;
+ struct dma_device *dma = &pxp_dma->dma;
+ int i;
+
+ dma_cap_set(DMA_SLAVE, dma->cap_mask);
+ dma_cap_set(DMA_PRIVATE, dma->cap_mask);
+
+ /* Compulsory common fields */
+ dma->dev = pxp->dev;
+ dma->device_alloc_chan_resources = pxp_alloc_chan_resources;
+ dma->device_free_chan_resources = pxp_free_chan_resources;
+ dma->device_tx_status = pxp_tx_status;
+ dma->device_issue_pending = pxp_issue_pending;
+
+ /* Compulsory for DMA_SLAVE fields */
+ dma->device_prep_slave_sg = pxp_prep_slave_sg;
+ dma->device_terminate_all = pxp_device_terminate_all;
+
+ /* Initialize PxP Channels */
+ INIT_LIST_HEAD(&dma->channels);
+ for (i = 0; i < NR_PXP_VIRT_CHANNEL; i++) {
+ struct pxp_channel *pxp_chan = pxp->channel + i;
+ struct dma_chan *dma_chan = &pxp_chan->dma_chan;
+
+ spin_lock_init(&pxp_chan->lock);
+
+ /* Only one EOF IRQ for PxP, shared by all channels */
+ pxp_chan->eof_irq = pxp->irq;
+ pxp_chan->status = PXP_CHANNEL_FREE;
+ pxp_chan->completed = -ENXIO;
+ snprintf(pxp_chan->eof_name, sizeof(pxp_chan->eof_name),
+ "PXP EOF %d", i);
+
+ dma_chan->device = &pxp_dma->dma;
+ dma_chan->cookie = 1;
+ dma_chan->chan_id = i;
+ list_add_tail(&dma_chan->device_node, &dma->channels);
+ }
+
+ return dma_async_device_register(&pxp_dma->dma);
+}
+
+static ssize_t clk_off_timeout_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", timeout_in_ms);
+}
+
+static ssize_t clk_off_timeout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int val;
+ if (sscanf(buf, "%d", &val) > 0) {
+ timeout_in_ms = val;
+ return count;
+ }
+ return -EINVAL;
+}
+
+static DEVICE_ATTR(clk_off_timeout, 0644, clk_off_timeout_show,
+ clk_off_timeout_store);
+
+static ssize_t block_size_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", block_size);
+}
+
+static ssize_t block_size_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char **last = NULL;
+
+ block_size = simple_strtoul(buf, last, 0);
+ if (block_size > 1)
+ block_size = 1;
+
+ return count;
+}
+static DEVICE_ATTR(block_size, S_IWUSR | S_IRUGO,
+ block_size_show, block_size_store);
+
+static const struct of_device_id imx_pxpdma_dt_ids[] = {
+ { .compatible = "fsl,imx6dl-pxp-dma", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_pxpdma_dt_ids);
+
+static int has_pending_task(struct pxps *pxp, struct pxp_channel *task)
+{
+ int found;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pxp->lock, flags);
+ found = !list_empty(&head);
+ spin_unlock_irqrestore(&pxp->lock, flags);
+
+ return found;
+}
+
+static int pxp_dispatch_thread(void *argv)
+{
+ struct pxps *pxp = (struct pxps *)argv;
+ struct pxp_channel *pending = NULL;
+ unsigned long flags;
+
+ set_freezable();
+
+ while (!kthread_should_stop()) {
+ int ret;
+ ret = wait_event_freezable(pxp->thread_waitq,
+ has_pending_task(pxp, pending) ||
+ kthread_should_stop());
+ if (ret < 0)
+ continue;
+
+ if (kthread_should_stop())
+ break;
+
+ spin_lock_irqsave(&pxp->lock, flags);
+ pxp->pxp_ongoing = 1;
+ spin_unlock_irqrestore(&pxp->lock, flags);
+ init_completion(&pxp->complete);
+ pxpdma_dostart_work(pxp);
+ ret = wait_for_completion_timeout(&pxp->complete, 2 * HZ);
+ if (ret == 0) {
+ printk(KERN_EMERG "%s: task is timeout\n\n", __func__);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int pxp_probe(struct platform_device *pdev)
+{
+ struct pxps *pxp;
+ struct resource *res;
+ int irq;
+ int err = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!res || irq < 0) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ pxp = devm_kzalloc(&pdev->dev, sizeof(*pxp), GFP_KERNEL);
+ if (!pxp) {
+ dev_err(&pdev->dev, "failed to allocate control object\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ pxp->dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, pxp);
+ pxp->irq = irq;
+
+ spin_lock_init(&pxp->lock);
+ mutex_init(&pxp->clk_mutex);
+
+ pxp->base = devm_ioremap_resource(&pdev->dev, res);
+ if (pxp->base == NULL) {
+ dev_err(&pdev->dev, "Couldn't ioremap regs\n");
+ err = -ENODEV;
+ goto exit;
+ }
+
+ pxp->pdev = pdev;
+
+ pxp->clk_disp_axi = devm_clk_get(&pdev->dev, "disp-axi");
+ if (IS_ERR(pxp->clk_disp_axi))
+ pxp->clk_disp_axi = NULL;
+ pxp->clk = devm_clk_get(&pdev->dev, "pxp-axi");
+
+ err = devm_request_irq(&pdev->dev, pxp->irq, pxp_irq, 0,
+ "pxp-dmaengine", pxp);
+ if (err)
+ goto exit;
+ /* Initialize DMA engine */
+ err = pxp_dma_init(pxp);
+ if (err < 0)
+ goto exit;
+
+ if (device_create_file(&pdev->dev, &dev_attr_clk_off_timeout)) {
+ dev_err(&pdev->dev,
+ "Unable to create file from clk_off_timeout\n");
+ goto exit;
+ }
+
+ device_create_file(&pdev->dev, &dev_attr_block_size);
+ pxp_clk_enable(pxp);
+ dump_pxp_reg(pxp);
+ pxp_clk_disable(pxp);
+
+ INIT_WORK(&pxp->work, clkoff_callback);
+ init_timer(&pxp->clk_timer);
+ pxp->clk_timer.function = pxp_clkoff_timer;
+ pxp->clk_timer.data = (unsigned long)pxp;
+
+ init_waitqueue_head(&pxp->thread_waitq);
+ /* allocate a kernel thread to dispatch pxp conf */
+ pxp->dispatch = kthread_run(pxp_dispatch_thread, pxp, "pxp_dispatch");
+ if (IS_ERR(pxp->dispatch)) {
+ err = PTR_ERR(pxp->dispatch);
+ goto exit;
+ }
+ tx_desc_cache = kmem_cache_create("tx_desc", sizeof(struct pxp_tx_desc),
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!tx_desc_cache) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ register_pxp_device();
+
+ pm_runtime_enable(pxp->dev);
+
+exit:
+ if (err)
+ dev_err(&pdev->dev, "Exiting (unsuccessfully) pxp_probe()\n");
+ return err;
+}
+
+static int pxp_remove(struct platform_device *pdev)
+{
+ struct pxps *pxp = platform_get_drvdata(pdev);
+
+ unregister_pxp_device();
+ kmem_cache_destroy(tx_desc_cache);
+ kthread_stop(pxp->dispatch);
+ cancel_work_sync(&pxp->work);
+ del_timer_sync(&pxp->clk_timer);
+ clk_disable_unprepare(pxp->clk);
+ if (pxp->clk_disp_axi)
+ clk_disable_unprepare(pxp->clk_disp_axi);
+ device_remove_file(&pdev->dev, &dev_attr_clk_off_timeout);
+ device_remove_file(&pdev->dev, &dev_attr_block_size);
+ dma_async_device_unregister(&(pxp->pxp_dma.dma));
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pxp_suspend(struct device *dev)
+{
+ struct pxps *pxp = dev_get_drvdata(dev);
+
+ pxp_clk_enable(pxp);
+ while (__raw_readl(pxp->base + HW_PXP_CTRL) & BM_PXP_CTRL_ENABLE)
+ ;
+
+ __raw_writel(BM_PXP_CTRL_SFTRST, pxp->base + HW_PXP_CTRL);
+ pxp_clk_disable(pxp);
+
+ return 0;
+}
+
+static int pxp_resume(struct device *dev)
+{
+ struct pxps *pxp = dev_get_drvdata(dev);
+
+ pxp_clk_enable(pxp);
+ /* Pull PxP out of reset */
+ __raw_writel(0, pxp->base + HW_PXP_CTRL);
+ pxp_clk_disable(pxp);
+
+ return 0;
+}
+#else
+#define pxp_suspend NULL
+#define pxp_resume NULL
+#endif
+
+#ifdef CONFIG_PM
+static int pxp_runtime_suspend(struct device *dev)
+{
+ dev_dbg(dev, "pxp busfreq high release.\n");
+ return 0;
+}
+
+static int pxp_runtime_resume(struct device *dev)
+{
+ dev_dbg(dev, "pxp busfreq high request.\n");
+ return 0;
+}
+#else
+#define pxp_runtime_suspend NULL
+#define pxp_runtime_resume NULL
+#endif
+
+static const struct dev_pm_ops pxp_pm_ops = {
+ SET_RUNTIME_PM_OPS(pxp_runtime_suspend, pxp_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pxp_suspend, pxp_resume)
+};
+
+static struct platform_driver pxp_driver = {
+ .driver = {
+ .name = "imx-pxp",
+ .of_match_table = of_match_ptr(imx_pxpdma_dt_ids),
+ .pm = &pxp_pm_ops,
+ },
+ .probe = pxp_probe,
+ .remove = pxp_remove,
+};
+
+module_platform_driver(pxp_driver);
+
+
+MODULE_DESCRIPTION("i.MX PxP driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/dma/pxp/pxp_dma_v3.c b/drivers/dma/pxp/pxp_dma_v3.c
new file mode 100644
index 000000000000..647fdd3e4b06
--- /dev/null
+++ b/drivers/dma/pxp/pxp_dma_v3.c
@@ -0,0 +1,8135 @@
+/*
+ * Copyright (C) 2010-2016 Freescale Semiconductor, Inc.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; 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
+ *
+ */
+/*
+ * Based on STMP378X PxP driver
+ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/freezer.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/dmaengine.h>
+#include <linux/pxp_dma.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/of.h>
+
+#include "regs-pxp_v3.h"
+#include "reg_bitfields.h"
+
+#ifdef CONFIG_MXC_FPGA_M4_TEST
+#include "cm4_image.c"
+#define FPGA_TCML_ADDR 0x0C7F8000
+#define PINCTRL 0x0C018000
+#define PIN_DOUT 0x700
+void __iomem *fpga_tcml_base;
+void __iomem *pinctrl_base;
+#endif
+
+
+#define PXP_FILL_TIMEOUT 3000
+#define busy_wait(cond) \
+ ({ \
+ unsigned long end_jiffies = jiffies + \
+ msecs_to_jiffies(PXP_FILL_TIMEOUT); \
+ bool succeeded = false; \
+ do { \
+ if (cond) { \
+ succeeded = true; \
+ break; \
+ } \
+ cpu_relax(); \
+ } while (time_after(end_jiffies, jiffies)); \
+ succeeded; \
+ })
+
+#define PXP_DOWNSCALE_THRESHOLD 0x4000
+
+#define CONFIG_FB_MXC_EINK_FPGA
+
+/* define all the pxp 2d nodes */
+#define PXP_2D_PS 0
+#define PXP_2D_AS 1
+#define PXP_2D_INPUT_FETCH0 2
+#define PXP_2D_INPUT_FETCH1 3
+#define PXP_2D_CSC1 4
+#define PXP_2D_ROTATION1 5
+#define PXP_2D_ALPHA0_S0 6
+#define PXP_2D_ALPHA0_S1 7
+#define PXP_2D_ALPHA1_S0 8
+#define PXP_2D_ALPHA1_S1 9
+#define PXP_2D_CSC2 10
+#define PXP_2D_LUT 11
+#define PXP_2D_ROTATION0 12
+#define PXP_2D_OUT 13
+#define PXP_2D_INPUT_STORE0 14
+#define PXP_2D_INPUT_STORE1 15
+#define PXP_2D_NUM 16
+
+#define PXP_2D_ALPHA0_S0_S1 0xaa
+#define PXP_2D_ALPHA1_S0_S1 0xbb
+
+#define PXP_2D_MUX_BASE 50
+#define PXP_2D_MUX_MUX0 (PXP_2D_MUX_BASE + 0)
+#define PXP_2D_MUX_MUX1 (PXP_2D_MUX_BASE + 1)
+#define PXP_2D_MUX_MUX2 (PXP_2D_MUX_BASE + 2)
+#define PXP_2D_MUX_MUX3 (PXP_2D_MUX_BASE + 3)
+#define PXP_2D_MUX_MUX4 (PXP_2D_MUX_BASE + 4)
+#define PXP_2D_MUX_MUX5 (PXP_2D_MUX_BASE + 5)
+#define PXP_2D_MUX_MUX6 (PXP_2D_MUX_BASE + 6)
+#define PXP_2D_MUX_MUX7 (PXP_2D_MUX_BASE + 7)
+#define PXP_2D_MUX_MUX8 (PXP_2D_MUX_BASE + 8)
+#define PXP_2D_MUX_MUX9 (PXP_2D_MUX_BASE + 9)
+#define PXP_2D_MUX_MUX10 (PXP_2D_MUX_BASE + 10)
+#define PXP_2D_MUX_MUX11 (PXP_2D_MUX_BASE + 11)
+#define PXP_2D_MUX_MUX12 (PXP_2D_MUX_BASE + 12)
+#define PXP_2D_MUX_MUX13 (PXP_2D_MUX_BASE + 13)
+#define PXP_2D_MUX_MUX14 (PXP_2D_MUX_BASE + 14)
+#define PXP_2D_MUX_MUX15 (PXP_2D_MUX_BASE + 15)
+
+/* define pxp 2d node types */
+#define PXP_2D_TYPE_INPUT 1
+#define PXP_2D_TYPE_ALU 2
+#define PXP_2D_TYPE_OUTPUT 3
+
+#define DISTANCE_INFINITY 0xffff
+#define NO_PATH_NODE 0xffffffff
+
+#define PXP_MAX_INPUT_NUM 2
+#define PXP_MAX_OUTPUT_NUM 2
+
+#define FETCH_NOOP 0x01
+#define FETCH_EXPAND 0x02
+#define FETCH_SHIFT 0x04
+
+#define STORE_NOOP 0x01
+#define STORE_SHIFT 0x02
+#define STORE_SHRINK 0x04
+
+#define NEED_YUV_SWAP 0x02
+
+#define IN_NEED_COMPOSITE (0x01 | IN_NEED_FMT_UNIFIED)
+#define IN_NEED_CSC (0x02 | IN_NEED_FMT_UNIFIED)
+#define IN_NEED_SCALE (0x04 | IN_NEED_FMT_UNIFIED)
+#define IN_NEED_ROTATE_FLIP (0x08 | IN_NEED_FMT_UNIFIED)
+#define IN_NEED_FMT_UNIFIED 0x10
+#define IN_NEED_SHIFT 0x20
+#define IN_NEED_LUT (0x40 | IN_NEED_UNIFIED)
+
+#define OUT_NEED_SHRINK 0x100
+#define OUT_NEED_SHIFT 0x200
+
+#define PXP_ROTATE_0 0
+#define PXP_ROTATE_90 1
+#define PXP_ROTATE_180 2
+#define PXP_ROTATE_270 3
+
+#define PXP_H_FLIP 1
+#define PXP_V_FLIP 2
+
+#define PXP_OP_TYPE_2D 0x001
+#define PXP_OP_TYPE_DITHER 0x002
+#define PXP_OP_TYPE_WFE_A 0x004
+#define PXP_OP_TYPE_WFE_B 0x008
+
+/* define store engine output mode */
+#define STORE_MODE_NORMAL 1
+#define STORE_MODE_BYPASS 2
+#define STORE_MODE_DUAL 3
+#define STORE_MODE_HANDSHAKE 4
+
+/* define fetch engine input mode */
+#define FETCH_MODE_NORMAL 1
+#define FETCH_MODE_BYPASS 2
+#define FETCH_MODE_HANDSHAKE 3
+
+#define COMMON_FMT_BPP 32
+
+#define R_COMP 0
+#define G_COMP 1
+#define B_COMP 2
+#define A_COMP 3
+
+#define Y_COMP 0
+#define U_COMP 1
+#define V_COMP 2
+#define Y1_COMP 4
+
+static LIST_HEAD(head);
+static int timeout_in_ms = 600;
+static unsigned int block_size;
+static struct kmem_cache *tx_desc_cache;
+static struct kmem_cache *edge_node_cache;
+static struct pxp_collision_info col_info;
+static dma_addr_t paddr;
+static bool v3p_flag;
+static int alpha_blending_version;
+static bool pxp_legacy;
+
+struct pxp_dma {
+ struct dma_device dma;
+};
+
+enum pxp_alpha_blending_version {
+ PXP_ALPHA_BLENDING_NONE = 0x0,
+ PXP_ALPHA_BLENDING_V1 = 0x1,
+ PXP_ALPHA_BLENDING_V2 = 0x2,
+};
+
+struct pxp_alpha_global {
+ unsigned int color_key_enable;
+ bool combine_enable;
+ bool global_alpha_enable;
+ bool global_override;
+ bool alpha_invert;
+ bool local_alpha_enable;
+ unsigned char global_alpha;
+ int comp_mask;
+};
+
+struct rectangle {
+ uint16_t x;
+ uint16_t y;
+ uint16_t width;
+ uint16_t height;
+};
+
+struct pxp_alpha_info {
+ uint8_t alpha_mode;
+ uint8_t rop_type;
+
+ struct pxp_alpha s0_alpha;
+ struct pxp_alpha s1_alpha;
+};
+
+struct pxp_op_info{
+ uint16_t op_type;
+ uint16_t rotation;
+ uint8_t flip;
+ uint8_t fill_en;
+ uint32_t fill_data;
+ uint8_t alpha_blending;
+ struct pxp_alpha_info alpha_info;
+
+ /* Dithering specific data */
+ uint32_t dither_mode;
+ uint32_t quant_bit;
+
+ /*
+ * partial:
+ * 0 - full update
+ * 1 - partial update
+ * alpha_en:
+ * 0 - upd is {Y4[3:0],4'b0000} format
+ * 1 - upd is {Y4[3:0],3'b000,alpha} format
+ * reagl_en:
+ * 0 - use normal waveform algorithm
+ * 1 - enable reagl/-d waveform algorithm
+ * detection_only:
+ * 0 - write working buffer
+ * 1 - do no write working buffer, detection only
+ * lut:
+ * valid value 0-63
+ * set to the lut used for next update
+ */
+ bool partial_update;
+ bool alpha_en;
+ bool lut_update;
+ bool reagl_en; /* enable reagl/-d */
+ bool reagl_d_en; /* enable reagl or reagl-d */
+ bool detection_only;
+ int lut;
+ uint32_t lut_status_1;
+ uint32_t lut_status_2;
+};
+
+struct pxp_pixmap {
+ uint8_t channel_id;
+ uint8_t bpp;
+ int32_t pitch;
+ uint16_t width;
+ uint16_t height;
+ struct rectangle crop;
+ uint32_t rotate;
+ uint8_t flip;
+ uint32_t format; /* fourcc pixmap format */
+ uint32_t flags;
+ bool valid;
+ dma_addr_t paddr;
+ struct pxp_alpha_global g_alpha;
+};
+
+struct pxp_task_info {
+ uint8_t input_num;
+ uint8_t output_num;
+ struct pxp_pixmap input[PXP_MAX_INPUT_NUM];
+ struct pxp_pixmap output[PXP_MAX_OUTPUT_NUM];
+ struct pxp_op_info op_info;
+ uint32_t pxp_2d_flags;
+};
+
+struct pxps {
+ struct platform_device *pdev;
+ struct clk *ipg_clk;
+ struct clk *axi_clk;
+ void __iomem *base;
+ int irq; /* PXP IRQ to the CPU */
+
+ spinlock_t lock;
+ struct mutex clk_mutex;
+ int clk_stat;
+#define CLK_STAT_OFF 0
+#define CLK_STAT_ON 1
+ int pxp_ongoing;
+ int lut_state;
+
+ struct device *dev;
+ struct pxp_dma pxp_dma;
+ struct pxp_channel channel[NR_PXP_VIRT_CHANNEL];
+ struct work_struct work;
+
+ const struct pxp_devdata *devdata;
+ struct pxp_task_info task;
+
+ /* describes most recent processing configuration */
+ struct pxp_config_data pxp_conf_state;
+
+ /* to turn clock off when pxp is inactive */
+ struct timer_list clk_timer;
+
+ /* for pxp config dispatch asynchronously*/
+ struct task_struct *dispatch;
+ wait_queue_head_t thread_waitq;
+ struct completion complete;
+};
+
+#define to_pxp_dma(d) container_of(d, struct pxp_dma, dma)
+#define to_tx_desc(tx) container_of(tx, struct pxp_tx_desc, txd)
+#define to_pxp_channel(d) container_of(d, struct pxp_channel, dma_chan)
+#define to_pxp(id) container_of(id, struct pxps, pxp_dma)
+
+#define to_pxp_task_info(op) container_of((op), struct pxp_task_info, op_info)
+#define to_pxp_from_task(task) container_of((task), struct pxps, task)
+
+#define PXP_DEF_BUFS 2
+#define PXP_MIN_PIX 8
+
+static uint8_t active_bpp(uint8_t bpp)
+{
+ switch(bpp) {
+ case 8:
+ return 0x0;
+ case 16:
+ return 0x1;
+ case 32:
+ return 0x2;
+ case 64:
+ return 0x3;
+ default:
+ return 0xff;
+ }
+}
+
+static uint8_t rotate_map(uint32_t degree)
+{
+ switch (degree) {
+ case 0:
+ return PXP_ROTATE_0;
+ case 90:
+ return PXP_ROTATE_90;
+ case 180:
+ return PXP_ROTATE_180;
+ case 270:
+ return PXP_ROTATE_270;
+ default:
+ return 0;
+ }
+}
+
+static uint8_t expand_format(uint32_t format)
+{
+ switch (format) {
+ case PXP_PIX_FMT_RGB565:
+ case PXP_PIX_FMT_BGR565:
+ return 0x0;
+ case PXP_PIX_FMT_RGB555:
+ return 0x1;
+ case PXP_PIX_FMT_YUYV:
+ case PXP_PIX_FMT_YVYU:
+ return 0x5;
+ case PXP_PIX_FMT_UYVY:
+ case PXP_PIX_FMT_VYUY:
+ return 0x6;
+ case PXP_PIX_FMT_NV16:
+ return 0x7;
+ default:
+ return 0xff;
+ }
+}
+
+struct color_component {
+ uint8_t id;
+ uint8_t offset;
+ uint8_t length;
+ uint8_t mask;
+};
+
+struct color {
+ uint32_t format;
+ struct color_component comp[4];
+};
+
+struct color rgb_colors[] = {
+ {
+ .format = PXP_PIX_FMT_RGB565,
+ .comp = {
+ { .id = B_COMP, .offset = 0, .length = 5, .mask = 0x1f, },
+ { .id = G_COMP, .offset = 5, .length = 6, .mask = 0x3f, },
+ { .id = R_COMP, .offset = 11, .length = 5, .mask = 0x1f, },
+ { .id = A_COMP, .offset = 0, .length = 0, .mask = 0x0, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_BGR565,
+ .comp = {
+ { .id = R_COMP, .offset = 0, .length = 5, .mask = 0x1f, },
+ { .id = G_COMP, .offset = 5, .length = 6, .mask = 0x3f, },
+ { .id = B_COMP, .offset = 11, .length = 6, .mask = 0x3f, },
+ { .id = A_COMP, .offset = 0, .length = 0, .mask = 0x0, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_ARGB555,
+ .comp = {
+ { .id = B_COMP, .offset = 0, .length = 5, .mask = 0x1f, },
+ { .id = G_COMP, .offset = 5, .length = 5, .mask = 0x1f, },
+ { .id = R_COMP, .offset = 10, .length = 5, .mask = 0x1f, },
+ { .id = A_COMP, .offset = 15, .length = 1, .mask = 0x1, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_XRGB555,
+ .comp = {
+ { .id = B_COMP, .offset = 0, .length = 5, .mask = 0x1f, },
+ { .id = G_COMP, .offset = 5, .length = 5, .mask = 0x1f, },
+ { .id = R_COMP, .offset = 10, .length = 5, .mask = 0x1f, },
+ { .id = A_COMP, .offset = 15, .length = 1, .mask = 0x1, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_RGB555,
+ .comp = {
+ { .id = B_COMP, .offset = 0, .length = 5, .mask = 0x1f, },
+ { .id = G_COMP, .offset = 5, .length = 5, .mask = 0x1f, },
+ { .id = R_COMP, .offset = 10, .length = 5, .mask = 0x1f, },
+ { .id = A_COMP, .offset = 15, .length = 1, .mask = 0x1, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_RGBA555,
+ .comp = {
+ { .id = A_COMP, .offset = 0, .length = 1, .mask = 0x1, },
+ { .id = B_COMP, .offset = 1, .length = 5, .mask = 0x1f, },
+ { .id = G_COMP, .offset = 6, .length = 5, .mask = 0x1f, },
+ { .id = R_COMP, .offset = 11, .length = 5, .mask = 0x1f, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_ARGB444,
+ .comp = {
+ { .id = B_COMP, .offset = 0, .length = 4, .mask = 0xf, },
+ { .id = G_COMP, .offset = 4, .length = 4, .mask = 0xf, },
+ { .id = R_COMP, .offset = 8, .length = 4, .mask = 0xf, },
+ { .id = A_COMP, .offset = 12, .length = 4, .mask = 0xf, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_XRGB444,
+ .comp = {
+ { .id = B_COMP, .offset = 0, .length = 4, .mask = 0xf, },
+ { .id = G_COMP, .offset = 4, .length = 4, .mask = 0xf, },
+ { .id = R_COMP, .offset = 8, .length = 4, .mask = 0xf, },
+ { .id = A_COMP, .offset = 12, .length = 4, .mask = 0xf, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_RGBA444,
+ .comp = {
+ { .id = A_COMP, .offset = 0, .length = 4, .mask = 0xf, },
+ { .id = B_COMP, .offset = 4, .length = 4, .mask = 0xf, },
+ { .id = G_COMP, .offset = 8, .length = 4, .mask = 0xf, },
+ { .id = R_COMP, .offset = 12, .length = 4, .mask = 0xf, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_RGB24,
+ .comp = {
+ { .id = B_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = G_COMP, .offset = 8, .length = 8, .mask = 0xff, },
+ { .id = R_COMP, .offset = 16, .length = 8, .mask = 0xff, },
+ { .id = A_COMP, .offset = 0, .length = 0, .mask = 0x0, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_BGR24,
+ .comp = {
+ { .id = R_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = G_COMP, .offset = 8, .length = 8, .mask = 0xff, },
+ { .id = B_COMP, .offset = 16, .length = 8, .mask = 0xff, },
+ { .id = A_COMP, .offset = 0, .length = 0, .mask = 0x0, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_XRGB32,
+ .comp = {
+ { .id = B_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = G_COMP, .offset = 8, .length = 8, .mask = 0xff, },
+ { .id = R_COMP, .offset = 16, .length = 8, .mask = 0xff, },
+ { .id = A_COMP, .offset = 24, .length = 8, .mask = 0xff, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_RGBX32,
+ .comp = {
+ { .id = A_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = B_COMP, .offset = 8, .length = 8, .mask = 0xff, },
+ { .id = G_COMP, .offset = 16, .length = 8, .mask = 0xff, },
+ { .id = R_COMP, .offset = 24, .length = 8, .mask = 0xff, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_XBGR32,
+ .comp = {
+ { .id = R_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = G_COMP, .offset = 8, .length = 8, .mask = 0xff, },
+ { .id = B_COMP, .offset = 16, .length = 8, .mask = 0xff, },
+ { .id = A_COMP, .offset = 24, .length = 8, .mask = 0xff, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_BGRX32,
+ .comp = {
+ { .id = A_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = R_COMP, .offset = 8, .length = 8, .mask = 0xff, },
+ { .id = G_COMP, .offset = 16, .length = 8, .mask = 0xff, },
+ { .id = B_COMP, .offset = 24, .length = 8, .mask = 0xff, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_ARGB32,
+ .comp = {
+ { .id = B_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = G_COMP, .offset = 8, .length = 8, .mask = 0xff, },
+ { .id = R_COMP, .offset = 16, .length = 8, .mask = 0xff, },
+ { .id = A_COMP, .offset = 24, .length = 8, .mask = 0xff, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_ABGR32,
+ .comp = {
+ { .id = R_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = G_COMP, .offset = 8, .length = 8, .mask = 0xff, },
+ { .id = B_COMP, .offset = 16, .length = 8, .mask = 0xff, },
+ { .id = A_COMP, .offset = 24, .length = 8, .mask = 0xff, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_RGBA32,
+ .comp = {
+ { .id = A_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = B_COMP, .offset = 8, .length = 8, .mask = 0xff, },
+ { .id = G_COMP, .offset = 16, .length = 8, .mask = 0xff, },
+ { .id = R_COMP, .offset = 24, .length = 8, .mask = 0xff, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_BGRA32,
+ .comp = {
+ { .id = A_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = R_COMP, .offset = 8, .length = 8, .mask = 0xff, },
+ { .id = G_COMP, .offset = 16, .length = 8, .mask = 0xff, },
+ { .id = B_COMP, .offset = 24, .length = 8, .mask = 0xff, },
+ },
+ },
+};
+
+/* only one plane yuv formats */
+struct color yuv_colors[] = {
+ {
+ .format = PXP_PIX_FMT_GREY,
+ .comp = {
+ { .id = Y_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = U_COMP, .offset = 8, .length = 0, .mask = 0x00, },
+ { .id = V_COMP, .offset = 16, .length = 0, .mask = 0x00, },
+ { .id = A_COMP, .offset = 24, .length = 0, .mask = 0x00, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_YUYV,
+ .comp = {
+ { .id = V_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = Y1_COMP, .offset = 8, .length = 8, .mask = 0xff, },
+ { .id = U_COMP, .offset = 16, .length = 8, .mask = 0xff, },
+ { .id = Y_COMP, .offset = 24, .length = 8, .mask = 0xff, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_UYVY,
+ .comp = {
+ { .id = Y1_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = V_COMP, .offset = 8, .length = 8, .mask = 0xff, },
+ { .id = Y_COMP, .offset = 16, .length = 8, .mask = 0xff, },
+ { .id = U_COMP, .offset = 24, .length = 8, .mask = 0xff, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_YVYU,
+ .comp = {
+ { .id = U_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = Y1_COMP, .offset = 8, .length = 8, .mask = 0xff, },
+ { .id = V_COMP, .offset = 16, .length = 8, .mask = 0xff, },
+ { .id = Y_COMP, .offset = 24, .length = 8, .mask = 0xff, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_VYUY,
+ .comp = {
+ { .id = Y1_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = U_COMP, .offset = 8, .length = 8, .mask = 0xff, },
+ { .id = Y_COMP, .offset = 16, .length = 8, .mask = 0xff, },
+ { .id = V_COMP, .offset = 24, .length = 8, .mask = 0xff, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_YUV444,
+ .comp = {
+ { .id = V_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = U_COMP, .offset = 8, .length = 8, .mask = 0xff, },
+ { .id = Y_COMP, .offset = 16, .length = 8, .mask = 0xff, },
+ { .id = A_COMP, .offset = 24, .length = 8, .mask = 0xff, },
+ },
+ }, {
+ .format = PXP_PIX_FMT_YVU444,
+ .comp = {
+ { .id = U_COMP, .offset = 0, .length = 8, .mask = 0xff, },
+ { .id = V_COMP, .offset = 8, .length = 8, .mask = 0xff, },
+ { .id = Y_COMP, .offset = 16, .length = 8, .mask = 0xff, },
+ { .id = A_COMP, .offset = 24, .length = 8, .mask = 0xff, },
+ },
+ },
+};
+
+/* 4 to 1 mux */
+struct mux {
+ uint32_t id;
+ uint8_t mux_inputs[4];
+ uint8_t mux_outputs[2];
+};
+
+/* Adjacent list structure */
+struct edge_node {
+ uint32_t adjvex;
+ uint32_t prev_vnode;
+ struct edge_node *next;
+ uint32_t mux_used;
+ struct mux_config muxes;
+};
+
+struct vetex_node {
+ uint8_t type;
+ struct edge_node *first;
+};
+
+struct path_node {
+ struct list_head node;
+ uint32_t id;
+ uint32_t distance;
+ uint32_t prev_node;
+};
+
+static struct vetex_node adj_list[PXP_2D_NUM];
+static struct path_node path_table[PXP_2D_NUM][PXP_2D_NUM];
+
+static bool adj_array_v3[PXP_2D_NUM][PXP_2D_NUM] = {
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
+ {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 0 */
+ {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1 */
+ {0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0}, /* 2 */
+ {0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1}, /* 3 */
+ {0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 4 */
+ {0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0}, /* 5 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0}, /* 6 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0}, /* 7 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0}, /* 8 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0}, /* 9 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}, /* 10 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0}, /* 11 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, /* 12 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 13 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 14 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 15 */
+};
+
+
+static struct mux muxes_v3[16] = {
+ {
+ /* mux0 */
+ .id = 0,
+ .mux_inputs = {PXP_2D_CSC1, PXP_2D_INPUT_FETCH0, PXP_2D_INPUT_FETCH1, 0xff},
+ .mux_outputs = {PXP_2D_ROTATION1, 0xff},
+ }, {
+ /* mux1 */
+ .id = 1,
+ .mux_inputs = {PXP_2D_INPUT_FETCH0, PXP_2D_ROTATION1, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_ALPHA1_S1, PXP_2D_MUX_MUX5},
+ }, {
+ /* mux2 */
+ .id = 2,
+ .mux_inputs = {PXP_2D_INPUT_FETCH1, PXP_2D_ROTATION1, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_ALPHA1_S0, 0xff},
+ }, {
+ /* mux3 */
+ .id = 3,
+ .mux_inputs = {PXP_2D_CSC1, PXP_2D_ROTATION1, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_ALPHA0_S0, 0xff},
+ }, {
+ /* mux4 is not used in ULT1 */
+ .id = 4,
+ .mux_inputs = {0xff, 0xff, 0xff, 0xff},
+ .mux_outputs = {0xff, 0xff},
+ }, {
+ /* mux5 */
+ .id = 5,
+ .mux_inputs = {PXP_2D_MUX_MUX1, PXP_2D_ALPHA1_S0_S1, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_MUX_MUX7, 0xff},
+ }, {
+ /* mux6 */
+ .id = 6,
+ .mux_inputs = {PXP_2D_ALPHA1_S0_S1, PXP_2D_ALPHA0_S0_S1, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_CSC2, 0xff},
+ }, {
+ /* mux7 */
+ .id = 7,
+ .mux_inputs = {PXP_2D_MUX_MUX5, PXP_2D_CSC2, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_MUX_MUX9, PXP_2D_MUX_MUX10},
+ }, {
+ /* mux8 */
+ .id = 8,
+ .mux_inputs = {PXP_2D_CSC2, PXP_2D_ALPHA0_S0_S1, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_MUX_MUX9, PXP_2D_MUX_MUX11},
+ }, {
+ /* mux9 */
+ .id = 9,
+ .mux_inputs = {PXP_2D_MUX_MUX7, PXP_2D_MUX_MUX8, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_LUT, 0xff},
+ }, {
+ /* mux10 */
+ .id = 10,
+ .mux_inputs = {PXP_2D_MUX_MUX7, PXP_2D_LUT, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_MUX_MUX12, PXP_2D_MUX_MUX15},
+ }, {
+ /* mux11 */
+ .id = 11,
+ .mux_inputs = {PXP_2D_LUT, PXP_2D_MUX_MUX8, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_MUX_MUX12, PXP_2D_MUX_MUX14},
+ }, {
+ /* mux12 */
+ .id = 12,
+ .mux_inputs = {PXP_2D_MUX_MUX10, PXP_2D_MUX_MUX11, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_ROTATION0, 0xff},
+ }, {
+ /* mux13 */
+ .id = 13,
+ .mux_inputs = {PXP_2D_INPUT_FETCH1, 0xff, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_INPUT_STORE1, 0xff},
+ }, {
+ /* mux14 */
+ .id = 14,
+ .mux_inputs = {PXP_2D_ROTATION0, PXP_2D_MUX_MUX11, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_OUT, 0xff},
+ }, {
+ /* mux15 */
+ .id = 15,
+ .mux_inputs = {PXP_2D_INPUT_FETCH0, PXP_2D_MUX_MUX10, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_INPUT_STORE0, 0xff},
+ },
+};
+
+static bool adj_array_v3p[PXP_2D_NUM][PXP_2D_NUM] = {
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
+ {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 0 */
+ {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, /* 1 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 2 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 3 */
+ {0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 4 */
+ {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 5 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0}, /* 6 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0}, /* 7 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 8 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 9 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, /* 10 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, /* 11 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, /* 12 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 13 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 14 */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* 15 */
+};
+
+static struct mux muxes_v3p[16] = {
+ {
+ /* mux0 */
+ .id = 0,
+ .mux_inputs = {0xff, 0xff, 0xff, 0xff},
+ .mux_outputs = {0xff, 0xff},
+ }, {
+ /* mux1 */
+ .id = 1,
+ .mux_inputs = {0xff, 0xff, 0xff, 0xff},
+ .mux_outputs = {0xff, 0xff},
+ }, {
+ /* mux2 */
+ .id = 2,
+ .mux_inputs = {0xff, 0xff, 0xff, 0xff},
+ .mux_outputs = {0xff, 0xff},
+ }, {
+ /* mux3 */
+ .id = 3,
+ .mux_inputs = {PXP_2D_CSC1, PXP_2D_ROTATION1, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_ALPHA0_S0, 0xff},
+ }, {
+ /* mux4 is not used in ULT1 */
+ .id = 4,
+ .mux_inputs = {0xff, 0xff, 0xff, 0xff},
+ .mux_outputs = {0xff, 0xff},
+ }, {
+ /* mux5 */
+ .id = 5,
+ .mux_inputs = {0xff, 0xff, 0xff, 0xff},
+ .mux_outputs = {0xff, 0xff},
+ }, {
+ /* mux6 */
+ .id = 6,
+ .mux_inputs = {0xff, 0xff, 0xff, 0xff},
+ .mux_outputs = {0xff, 0xff},
+ }, {
+ /* mux7 */
+ .id = 7,
+ .mux_inputs = {0xff, 0xff, 0xff, 0xff},
+ .mux_outputs = {0xff, 0xff},
+ }, {
+ /* mux8 */
+ .id = 8,
+ .mux_inputs = {PXP_2D_CSC2, PXP_2D_ALPHA0_S0_S1, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_MUX_MUX9, PXP_2D_MUX_MUX11},
+ }, {
+ /* mux9 */
+ .id = 9,
+ .mux_inputs = {0xff, PXP_2D_MUX_MUX8, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_LUT, 0xff},
+ }, {
+ /* mux10 */
+ .id = 10,
+ .mux_inputs = {0xff, 0xff, 0xff, 0xff},
+ .mux_outputs = {0xff, 0xff},
+ }, {
+ /* mux11 */
+ .id = 11,
+ .mux_inputs = {PXP_2D_LUT, PXP_2D_MUX_MUX8, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_MUX_MUX12, PXP_2D_ROTATION0},
+ }, {
+ /* mux12 */
+ .id = 12,
+ .mux_inputs = {PXP_2D_ROTATION0, PXP_2D_MUX_MUX11, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_MUX_MUX14, 0xff},
+ }, {
+ /* mux13 */
+ .id = 13,
+ .mux_inputs = {0xff, 0xff, 0xff, 0xff},
+ .mux_outputs = {0xff, 0xff},
+ }, {
+ /* mux14 */
+ .id = 14,
+ .mux_inputs = {0xff, PXP_2D_MUX_MUX12, 0xff, 0xff},
+ .mux_outputs = {PXP_2D_OUT, 0xff},
+ }, {
+ /* mux15 */
+ .id = 15,
+ .mux_inputs = {0xff, 0xff, 0xff, 0xff},
+ .mux_outputs = {0xff, 0xff},
+ },
+};
+
+static void __iomem *pxp_reg_base;
+
+#define pxp_writel(val, reg) writel(val, pxp_reg_base + (reg))
+
+static __attribute__((aligned (1024*4))) unsigned int active_matrix_data_8x8[64]={
+ 0x06050100, 0x04030207, 0x06050100, 0x04030207,
+ 0x00040302, 0x07060501, 0x00040302, 0x07060501,
+ 0x02070605, 0x01000403, 0x02070605, 0x01000403,
+ 0x05010004, 0x03020706, 0x05010004, 0x03020706,
+ 0x04030207, 0x06050100, 0x04030207, 0x06050100,
+ 0x07060501, 0x00040302, 0x07060501, 0x00040302,
+ 0x01000403, 0x02070605, 0x01000403, 0x02070605,
+ 0x03020706, 0x05010004, 0x03020706, 0x05010004,
+ 0x06050100, 0x04030207, 0x06050100, 0x04030207,
+ 0x00040302, 0x07060501, 0x00040302, 0x07060501,
+ 0x02070605, 0x01000403, 0x02070605, 0x01000403,
+ 0x05010004, 0x03020706, 0x05010004, 0x03020706,
+ 0x04030207, 0x06050100, 0x04030207, 0x06050100,
+ 0x07060501, 0x00040302, 0x07060501, 0x00040302,
+ 0x01000403, 0x02070605, 0x01000403, 0x02070605,
+ 0x03020706, 0x05010004, 0x03020706, 0x05010004
+ };
+
+static __attribute__((aligned (1024*4))) unsigned int bit1_dither_data_8x8[64]={
+
+ 1, 49*2, 13*2, 61*2, 4*2, 52*2, 16*2, 64*2,
+ 33*2, 17*2, 45*2, 29*2, 36*2, 20*2, 48*2, 32*2,
+ 9*2, 57*2, 5*2, 53*2, 12*2, 60*2, 8*2, 56*2,
+ 41*2, 25*2, 37*2, 21*2, 44*2, 28*2, 40*2, 24*2,
+ 3*2, 51*2, 15*2, 63*2, 2*2, 50*2, 14*2, 62*2,
+ 35*2, 19*2, 47*2, 31*2, 34*2, 18*2, 46*2, 30*2,
+ 11*2, 59*2, 7*2, 55*2, 10*2, 58*2, 6*2, 54*2,
+ 43*2, 27*2, 39*2, 23*2, 42*2, 26*2, 38*2, 22*2
+};
+
+static __attribute__((aligned (1024*4))) unsigned int bit2_dither_data_8x8[64]={
+
+ 1, 49, 13, 61, 4, 52, 16, 64,
+ 33, 17, 45, 29, 36, 20, 48, 32,
+ 9, 57, 5, 53, 12, 60, 8, 56,
+ 41, 25, 37, 21, 44, 28, 40, 24,
+ 3, 51, 15, 63, 2, 50, 14, 62,
+ 35, 19, 47, 31, 34, 18, 46, 30,
+ 11, 59, 7, 55, 10, 58, 6, 54,
+ 43, 27, 39, 23, 42, 26, 38, 22
+};
+
+static __attribute__((aligned (1024*4))) unsigned int bit4_dither_data_8x8[64]={
+
+ 1, 49/4, 13/4, 61/4, 4/4, 52/4, 16/4, 64/4,
+ 33/4, 17/4, 45/4, 29/4, 36/4, 20/4, 48/4, 32/4,
+ 9/4, 57/4, 5/4, 53/4, 12/4, 60/4, 8/4, 56/4,
+ 41/4, 25/4, 37/4, 21/4, 44/4, 28/4, 40/4, 24/4,
+ 3/4, 51/4, 15/4, 63/4, 2/4, 50/4, 14/4, 62/4,
+ 35/4, 19/4, 47/4, 31/4, 34/4, 18/4, 46/4, 30/4,
+ 11/4, 59/4, 7/4, 55/4, 10/4, 58/4, 6/4, 54/4,
+ 43/4, 27/4, 39/4, 23/4, 42/4, 26/4, 38/4, 22/4
+};
+
+static void pxp_dithering_configure(struct pxps *pxp);
+static void pxp_dithering_configure_v3p(struct pxps *pxp);
+static void pxp_dithering_process(struct pxps *pxp);
+static void pxp_wfe_a_process(struct pxps *pxp);
+static void pxp_wfe_a_process_v3p(struct pxps *pxp);
+static void pxp_wfe_a_configure(struct pxps *pxp);
+static void pxp_wfe_a_configure_v3p(struct pxps *pxp);
+static void pxp_wfe_b_process(struct pxps *pxp);
+static void pxp_wfe_b_configure(struct pxps *pxp);
+static void pxp_lut_status_set(struct pxps *pxp, unsigned int lut);
+static void pxp_lut_status_set_v3p(struct pxps *pxp, unsigned int lut);
+static void pxp_lut_status_clr(unsigned int lut);
+static void pxp_lut_status_clr_v3p(unsigned int lut);
+static void pxp_start2(struct pxps *pxp);
+static void pxp_data_path_config_v3p(struct pxps *pxp);
+static void pxp_soft_reset(struct pxps *pxp);
+static void pxp_collision_detection_disable(struct pxps *pxp);
+static void pxp_collision_detection_enable(struct pxps *pxp,
+ unsigned int width,
+ unsigned int height);
+static void pxp_luts_activate(struct pxps *pxp, u64 lut_status);
+static bool pxp_collision_status_report(struct pxps *pxp, struct pxp_collision_info *info);
+static void pxp_histogram_status_report(struct pxps *pxp, u32 *hist_status);
+static void pxp_histogram_enable(struct pxps *pxp,
+ unsigned int width,
+ unsigned int height);
+static void pxp_histogram_disable(struct pxps *pxp);
+static void pxp_lut_cleanup_multiple(struct pxps *pxp, u64 lut, bool set);
+static void pxp_lut_cleanup_multiple_v3p(struct pxps *pxp, u64 lut, bool set);
+static void pxp_luts_deactivate(struct pxps *pxp, u64 lut_status);
+static void pxp_set_colorkey(struct pxps *pxp);
+
+enum {
+ DITHER0_LUT = 0x0, /* Select the LUT memory for access */
+ DITHER0_ERR0 = 0x1, /* Select the ERR0 memory for access */
+ DITHER0_ERR1 = 0x2, /* Select the ERR1 memory for access */
+ DITHER1_LUT = 0x3, /* Select the LUT memory for access */
+ DITHER2_LUT = 0x4, /* Select the LUT memory for access */
+ ALU_A = 0x5, /* Select the ALU instr memory for access */
+ ALU_B = 0x6, /* Select the ALU instr memory for access */
+ WFE_A = 0x7, /* Select the WFE_A instr memory for access */
+ WFE_B = 0x8, /* Select the WFE_B instr memory for access */
+ RESERVED = 0x15,
+};
+
+enum pxp_devtype {
+ PXP_V3,
+ PXP_V3P, /* minor changes over V3, use WFE_B to replace WFE_A */
+};
+
+#define pxp_is_v3(pxp) (pxp->devdata->version == 30)
+#define pxp_is_v3p(pxp) (pxp->devdata->version == 31)
+
+struct pxp_devdata {
+ void (*pxp_wfe_a_configure)(struct pxps *pxp);
+ void (*pxp_wfe_a_process)(struct pxps *pxp);
+ void (*pxp_lut_status_set)(struct pxps *pxp, unsigned int lut);
+ void (*pxp_lut_status_clr)(unsigned int lut);
+ void (*pxp_dithering_configure)(struct pxps *pxp);
+ void (*pxp_lut_cleanup_multiple)(struct pxps *pxp, u64 lut, bool set);
+ void (*pxp_data_path_config)(struct pxps *pxp);
+ unsigned int version;
+};
+
+static const struct pxp_devdata pxp_devdata[] = {
+ [PXP_V3] = {
+ .pxp_wfe_a_configure = pxp_wfe_a_configure,
+ .pxp_wfe_a_process = pxp_wfe_a_process,
+ .pxp_lut_status_set = pxp_lut_status_set,
+ .pxp_lut_status_clr = pxp_lut_status_clr,
+ .pxp_lut_cleanup_multiple = pxp_lut_cleanup_multiple,
+ .pxp_dithering_configure = pxp_dithering_configure,
+ .pxp_data_path_config = NULL,
+ .version = 30,
+ },
+ [PXP_V3P] = {
+ .pxp_wfe_a_configure = pxp_wfe_a_configure_v3p,
+ .pxp_wfe_a_process = pxp_wfe_a_process_v3p,
+ .pxp_lut_status_set = pxp_lut_status_set_v3p,
+ .pxp_lut_status_clr = pxp_lut_status_clr_v3p,
+ .pxp_lut_cleanup_multiple = pxp_lut_cleanup_multiple_v3p,
+ .pxp_dithering_configure = pxp_dithering_configure_v3p,
+ .pxp_data_path_config = pxp_data_path_config_v3p,
+ .version = 31,
+ },
+};
+
+/*
+ * PXP common functions
+ */
+static void dump_pxp_reg(struct pxps *pxp)
+{
+ dev_dbg(pxp->dev, "PXP_CTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CTRL));
+ dev_dbg(pxp->dev, "PXP_STAT 0x%x",
+ __raw_readl(pxp->base + HW_PXP_STAT));
+ dev_dbg(pxp->dev, "PXP_OUT_CTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_CTRL));
+ dev_dbg(pxp->dev, "PXP_OUT_BUF 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_BUF));
+ dev_dbg(pxp->dev, "PXP_OUT_BUF2 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_BUF2));
+ dev_dbg(pxp->dev, "PXP_OUT_PITCH 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_PITCH));
+ dev_dbg(pxp->dev, "PXP_OUT_LRC 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_LRC));
+ dev_dbg(pxp->dev, "PXP_OUT_PS_ULC 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_PS_ULC));
+ dev_dbg(pxp->dev, "PXP_OUT_PS_LRC 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_PS_LRC));
+ dev_dbg(pxp->dev, "PXP_OUT_AS_ULC 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_AS_ULC));
+ dev_dbg(pxp->dev, "PXP_OUT_AS_LRC 0x%x",
+ __raw_readl(pxp->base + HW_PXP_OUT_AS_LRC));
+ dev_dbg(pxp->dev, "PXP_PS_CTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_CTRL));
+ dev_dbg(pxp->dev, "PXP_PS_BUF 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_BUF));
+ dev_dbg(pxp->dev, "PXP_PS_UBUF 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_UBUF));
+ dev_dbg(pxp->dev, "PXP_PS_VBUF 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_VBUF));
+ dev_dbg(pxp->dev, "PXP_PS_PITCH 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_PITCH));
+ dev_dbg(pxp->dev, "PXP_PS_BACKGROUND_0 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_BACKGROUND_0));
+ dev_dbg(pxp->dev, "PXP_PS_SCALE 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_SCALE));
+ dev_dbg(pxp->dev, "PXP_PS_OFFSET 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_OFFSET));
+ dev_dbg(pxp->dev, "PXP_PS_CLRKEYLOW_0 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_CLRKEYLOW_0));
+ dev_dbg(pxp->dev, "PXP_PS_CLRKEYHIGH 0x%x",
+ __raw_readl(pxp->base + HW_PXP_PS_CLRKEYHIGH_0));
+ dev_dbg(pxp->dev, "PXP_AS_CTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_AS_CTRL));
+ dev_dbg(pxp->dev, "PXP_AS_BUF 0x%x",
+ __raw_readl(pxp->base + HW_PXP_AS_BUF));
+ dev_dbg(pxp->dev, "PXP_AS_PITCH 0x%x",
+ __raw_readl(pxp->base + HW_PXP_AS_PITCH));
+ dev_dbg(pxp->dev, "PXP_AS_CLRKEYLOW 0x%x",
+ __raw_readl(pxp->base + HW_PXP_AS_CLRKEYLOW_0));
+ dev_dbg(pxp->dev, "PXP_AS_CLRKEYHIGH 0x%x",
+ __raw_readl(pxp->base + HW_PXP_AS_CLRKEYHIGH_0));
+ dev_dbg(pxp->dev, "PXP_CSC1_COEF0 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC1_COEF0));
+ dev_dbg(pxp->dev, "PXP_CSC1_COEF1 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC1_COEF1));
+ dev_dbg(pxp->dev, "PXP_CSC1_COEF2 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC1_COEF2));
+ dev_dbg(pxp->dev, "PXP_CSC2_CTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC2_CTRL));
+ dev_dbg(pxp->dev, "PXP_CSC2_COEF0 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC2_COEF0));
+ dev_dbg(pxp->dev, "PXP_CSC2_COEF1 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC2_COEF1));
+ dev_dbg(pxp->dev, "PXP_CSC2_COEF2 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC2_COEF2));
+ dev_dbg(pxp->dev, "PXP_CSC2_COEF3 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC2_COEF3));
+ dev_dbg(pxp->dev, "PXP_CSC2_COEF4 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC2_COEF4));
+ dev_dbg(pxp->dev, "PXP_CSC2_COEF5 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CSC2_COEF5));
+ dev_dbg(pxp->dev, "PXP_LUT_CTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_LUT_CTRL));
+ dev_dbg(pxp->dev, "PXP_LUT_ADDR 0x%x",
+ __raw_readl(pxp->base + HW_PXP_LUT_ADDR));
+ dev_dbg(pxp->dev, "PXP_LUT_DATA 0x%x",
+ __raw_readl(pxp->base + HW_PXP_LUT_DATA));
+ dev_dbg(pxp->dev, "PXP_LUT_EXTMEM 0x%x",
+ __raw_readl(pxp->base + HW_PXP_LUT_EXTMEM));
+ dev_dbg(pxp->dev, "PXP_CFA 0x%x",
+ __raw_readl(pxp->base + HW_PXP_CFA));
+ dev_dbg(pxp->dev, "PXP_ALPHA_A_CTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_ALPHA_A_CTRL));
+ dev_dbg(pxp->dev, "PXP_ALPHA_B_CTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_ALPHA_B_CTRL));
+ dev_dbg(pxp->dev, "PXP_POWER_REG0 0x%x",
+ __raw_readl(pxp->base + HW_PXP_POWER_REG0));
+ dev_dbg(pxp->dev, "PXP_NEXT 0x%x",
+ __raw_readl(pxp->base + HW_PXP_NEXT));
+ dev_dbg(pxp->dev, "PXP_DEBUGCTRL 0x%x",
+ __raw_readl(pxp->base + HW_PXP_DEBUGCTRL));
+ dev_dbg(pxp->dev, "PXP_DEBUG 0x%x",
+ __raw_readl(pxp->base + HW_PXP_DEBUG));
+ dev_dbg(pxp->dev, "PXP_VERSION 0x%x",
+ __raw_readl(pxp->base + HW_PXP_VERSION));
+}
+
+static void dump_pxp_reg2(struct pxps *pxp)
+{
+#ifdef DEBUG
+ int i = 0;
+
+ for (i=0; i< ((0x33C0/0x10) + 1);i++) {
+ printk("0x%08x: 0x%08x\n", 0x10*i, __raw_readl(pxp->base + 0x10*i));
+ }
+#endif
+}
+
+static void print_param(struct pxp_layer_param *p, char *s)
+{
+ pr_debug("%s: t/l/w/h/s %d/%d/%d/%d/%d, addr %x\n", s,
+ p->top, p->left, p->width, p->height, p->stride, p->paddr);
+}
+
+/* when it is, return yuv plane number */
+static uint8_t is_yuv(uint32_t format)
+{
+ switch (format) {
+ case PXP_PIX_FMT_GREY:
+ case PXP_PIX_FMT_GY04:
+ case PXP_PIX_FMT_YUYV:
+ case PXP_PIX_FMT_UYVY:
+ case PXP_PIX_FMT_YVYU:
+ case PXP_PIX_FMT_VYUY:
+ case PXP_PIX_FMT_YUV444:
+ case PXP_PIX_FMT_YVU444:
+ return 1;
+ case PXP_PIX_FMT_NV12:
+ case PXP_PIX_FMT_NV21:
+ case PXP_PIX_FMT_NV16:
+ case PXP_PIX_FMT_NV61:
+ return 2;
+ case PXP_PIX_FMT_YUV420P:
+ case PXP_PIX_FMT_YUV422P:
+ case PXP_PIX_FMT_YVU420P:
+ case PXP_PIX_FMT_YVU422P:
+ return 3;
+ default:
+ return 0;
+ }
+}
+
+static u32 get_bpp_from_fmt(u32 pix_fmt)
+{
+ unsigned int bpp = 0;
+
+ switch (pix_fmt) {
+ case PXP_PIX_FMT_GREY:
+ case PXP_PIX_FMT_NV16:
+ case PXP_PIX_FMT_NV61:
+ case PXP_PIX_FMT_NV12:
+ case PXP_PIX_FMT_NV21:
+ case PXP_PIX_FMT_YUV422P:
+ case PXP_PIX_FMT_YVU422P:
+ case PXP_PIX_FMT_YUV420P:
+ case PXP_PIX_FMT_YVU420P:
+ bpp = 8;
+ break;
+ case PXP_PIX_FMT_RGB555:
+ case PXP_PIX_FMT_ARGB555:
+ case PXP_PIX_FMT_XRGB555:
+ case PXP_PIX_FMT_RGBA555:
+ case PXP_PIX_FMT_ARGB444:
+ case PXP_PIX_FMT_XRGB444:
+ case PXP_PIX_FMT_RGBA444:
+ case PXP_PIX_FMT_RGB565:
+ case PXP_PIX_FMT_BGR565:
+ case PXP_PIX_FMT_YUYV:
+ case PXP_PIX_FMT_YVYU:
+ case PXP_PIX_FMT_UYVY:
+ case PXP_PIX_FMT_VYUY:
+ bpp = 16;
+ break;
+ case PXP_PIX_FMT_RGB24:
+ case PXP_PIX_FMT_BGR24:
+ bpp = 24;
+ break;
+ case PXP_PIX_FMT_XRGB32:
+ case PXP_PIX_FMT_RGBX32:
+ case PXP_PIX_FMT_XBGR32:
+ case PXP_PIX_FMT_BGRX32:
+ case PXP_PIX_FMT_ARGB32:
+ case PXP_PIX_FMT_RGBA32:
+ case PXP_PIX_FMT_ABGR32:
+ case PXP_PIX_FMT_BGRA32:
+ case PXP_PIX_FMT_YUV444:
+ case PXP_PIX_FMT_YVU444:
+ bpp = 32;
+ break;
+ default:
+ pr_err("%s: pix_fmt unsupport yet: 0x%x\n", __func__, pix_fmt);
+ break;
+ }
+
+ return bpp;
+}
+
+static uint32_t pxp_parse_ps_fmt(uint32_t format)
+{
+ uint32_t fmt_ctrl;
+
+ switch (format) {
+ case PXP_PIX_FMT_XRGB32:
+ case PXP_PIX_FMT_ARGB32:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__RGB888;
+ break;
+ case PXP_PIX_FMT_RGB565:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__RGB565;
+ break;
+ case PXP_PIX_FMT_RGB555:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__RGB555;
+ break;
+ case PXP_PIX_FMT_YUV420P:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV420;
+ break;
+ case PXP_PIX_FMT_YVU420P:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV420;
+ break;
+ case PXP_PIX_FMT_GREY:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__Y8;
+ break;
+ case PXP_PIX_FMT_GY04:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__Y4;
+ break;
+ case PXP_PIX_FMT_VUY444:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV1P444;
+ break;
+ case PXP_PIX_FMT_YUV422P:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV422;
+ break;
+ case PXP_PIX_FMT_UYVY:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__UYVY1P422;
+ break;
+ case PXP_PIX_FMT_YUYV:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__UYVY1P422;
+ break;
+ case PXP_PIX_FMT_VYUY:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__VYUY1P422;
+ break;
+ case PXP_PIX_FMT_YVYU:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__VYUY1P422;
+ break;
+ case PXP_PIX_FMT_NV12:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV2P420;
+ break;
+ case PXP_PIX_FMT_NV21:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YVU2P420;
+ break;
+ case PXP_PIX_FMT_NV16:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV2P422;
+ break;
+ case PXP_PIX_FMT_NV61:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YVU2P422;
+ break;
+ case PXP_PIX_FMT_RGBA32:
+ case PXP_PIX_FMT_RGBX32:
+ fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__RGBA888;
+ break;
+ default:
+ pr_debug("PS doesn't support this format\n");
+ fmt_ctrl = 0;
+ }
+
+ return fmt_ctrl;
+}
+
+static void pxp_set_colorkey(struct pxps *pxp)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_layer_param *s0_params = &pxp_conf->s0_param;
+ struct pxp_layer_param *ol_params = &pxp_conf->ol_param[0];
+
+ /* Low and high are set equal. V4L does not allow a chromakey range */
+ if (s0_params->color_key_enable == 0 || s0_params->color_key == -1) {
+ /* disable color key */
+ pxp_writel(0xFFFFFF, HW_PXP_PS_CLRKEYLOW_0);
+ pxp_writel(0, HW_PXP_PS_CLRKEYHIGH_0);
+ } else {
+ pxp_writel(s0_params->color_key, HW_PXP_PS_CLRKEYLOW_0);
+ pxp_writel(s0_params->color_key, HW_PXP_PS_CLRKEYHIGH_0);
+ }
+
+ if (ol_params->color_key_enable != 0 && ol_params->color_key != -1) {
+ pxp_writel(ol_params->color_key, HW_PXP_AS_CLRKEYLOW_0);
+ pxp_writel(ol_params->color_key, HW_PXP_AS_CLRKEYHIGH_0);
+ } else {
+ /* disable color key */
+ pxp_writel(0xFFFFFF, HW_PXP_AS_CLRKEYLOW_0);
+ pxp_writel(0, HW_PXP_AS_CLRKEYHIGH_0);
+ }
+}
+
+static uint32_t pxp_parse_as_fmt(uint32_t format)
+{
+ uint32_t fmt_ctrl;
+
+ switch (format) {
+ case PXP_PIX_FMT_BGRA32:
+ case PXP_PIX_FMT_ARGB32:
+ fmt_ctrl = BV_PXP_AS_CTRL_FORMAT__ARGB8888;
+ break;
+ case PXP_PIX_FMT_RGBA32:
+ fmt_ctrl = BV_PXP_AS_CTRL_FORMAT__RGBA8888;
+ break;
+ case PXP_PIX_FMT_XRGB32:
+ fmt_ctrl = BV_PXP_AS_CTRL_FORMAT__RGB888;
+ break;
+ case PXP_PIX_FMT_ARGB555:
+ fmt_ctrl = BV_PXP_AS_CTRL_FORMAT__ARGB1555;
+ break;
+ case PXP_PIX_FMT_ARGB444:
+ fmt_ctrl = BV_PXP_AS_CTRL_FORMAT__ARGB4444;
+ break;
+ case PXP_PIX_FMT_RGBA555:
+ fmt_ctrl = BV_PXP_AS_CTRL_FORMAT__RGBA5551;
+ break;
+ case PXP_PIX_FMT_RGBA444:
+ fmt_ctrl = BV_PXP_AS_CTRL_FORMAT__RGBA4444;
+ break;
+ case PXP_PIX_FMT_RGB555:
+ fmt_ctrl = BV_PXP_AS_CTRL_FORMAT__RGB555;
+ break;
+ case PXP_PIX_FMT_RGB444:
+ fmt_ctrl = BV_PXP_AS_CTRL_FORMAT__RGB444;
+ break;
+ case PXP_PIX_FMT_RGB565:
+ fmt_ctrl = BV_PXP_AS_CTRL_FORMAT__RGB565;
+ break;
+ default:
+ pr_debug("AS doesn't support this format\n");
+ fmt_ctrl = 0xf;
+ break;
+ }
+
+ return fmt_ctrl;
+}
+
+static uint32_t pxp_parse_out_fmt(uint32_t format)
+{
+ uint32_t fmt_ctrl;
+
+ switch (format) {
+ case PXP_PIX_FMT_BGRA32:
+ case PXP_PIX_FMT_ARGB32:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__ARGB8888;
+ break;
+ case PXP_PIX_FMT_XRGB32:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB888;
+ break;
+ case PXP_PIX_FMT_RGB24:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB888P;
+ break;
+ case PXP_PIX_FMT_RGB565:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB565;
+ break;
+ case PXP_PIX_FMT_RGB555:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB555;
+ break;
+ case PXP_PIX_FMT_GREY:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__Y8;
+ break;
+ case PXP_PIX_FMT_GY04:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__Y4;
+ break;
+ case PXP_PIX_FMT_UYVY:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__UYVY1P422;
+ break;
+ case PXP_PIX_FMT_VYUY:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__VYUY1P422;
+ break;
+ case PXP_PIX_FMT_NV12:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__YUV2P420;
+ break;
+ case PXP_PIX_FMT_NV21:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__YVU2P420;
+ break;
+ case PXP_PIX_FMT_NV16:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__YUV2P422;
+ break;
+ case PXP_PIX_FMT_NV61:
+ fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__YVU2P422;
+ break;
+ default:
+ pr_debug("OUT doesn't support this format\n");
+ fmt_ctrl = 0;
+ }
+
+ return fmt_ctrl;
+}
+
+static void set_mux(struct mux_config *path_ctrl)
+{
+ struct mux_config *mux = path_ctrl;
+
+ *(uint32_t *)path_ctrl = 0xFFFFFFFF;
+
+ mux->mux0_sel = 0;
+ mux->mux3_sel = 1;
+ mux->mux6_sel = 1;
+ mux->mux8_sel = 0;
+ mux->mux9_sel = 1;
+ mux->mux11_sel = 0;
+ mux->mux12_sel = 1;
+ mux->mux14_sel = 0;
+}
+
+static void set_mux_val(struct mux_config *muxes,
+ uint32_t mux_id,
+ uint32_t mux_val)
+{
+ BUG_ON(!muxes);
+ BUG_ON(mux_id > 15);
+
+ switch (mux_id) {
+ case 0:
+ muxes->mux0_sel = mux_val;
+ break;
+ case 1:
+ muxes->mux1_sel = mux_val;
+ break;
+ case 2:
+ muxes->mux2_sel = mux_val;
+ break;
+ case 3:
+ muxes->mux3_sel = mux_val;
+ break;
+ case 4:
+ muxes->mux4_sel = mux_val;
+ break;
+ case 5:
+ muxes->mux5_sel = mux_val;
+ break;
+ case 6:
+ muxes->mux6_sel = mux_val;
+ break;
+ case 7:
+ muxes->mux7_sel = mux_val;
+ break;
+ case 8:
+ muxes->mux8_sel = mux_val;
+ break;
+ case 9:
+ muxes->mux9_sel = mux_val;
+ break;
+ case 10:
+ muxes->mux10_sel = mux_val;
+ break;
+ case 11:
+ muxes->mux11_sel = mux_val;
+ break;
+ case 12:
+ muxes->mux12_sel = mux_val;
+ break;
+ case 13:
+ muxes->mux13_sel = mux_val;
+ break;
+ case 14:
+ muxes->mux14_sel = mux_val;
+ break;
+ case 15:
+ muxes->mux15_sel = mux_val;
+ break;
+ default:
+ break;
+ }
+}
+
+static uint32_t get_mux_val(struct mux_config *muxes,
+ uint32_t mux_id)
+{
+ BUG_ON(!muxes);
+ BUG_ON(mux_id > 15);
+
+ switch (mux_id) {
+ case 0:
+ return muxes->mux0_sel;
+ case 1:
+ return muxes->mux1_sel;
+ case 2:
+ return muxes->mux2_sel;
+ case 3:
+ return muxes->mux3_sel;
+ case 4:
+ return muxes->mux4_sel;
+ case 5:
+ return muxes->mux5_sel;
+ case 6:
+ return muxes->mux6_sel;
+ case 7:
+ return muxes->mux7_sel;
+ case 8:
+ return muxes->mux8_sel;
+ case 9:
+ return muxes->mux9_sel;
+ case 10:
+ return muxes->mux10_sel;
+ case 11:
+ return muxes->mux11_sel;
+ case 12:
+ return muxes->mux12_sel;
+ case 13:
+ return muxes->mux13_sel;
+ case 14:
+ return muxes->mux14_sel;
+ case 15:
+ return muxes->mux15_sel;
+ default:
+ return -EINVAL;
+ }
+}
+
+static uint32_t pxp_store_ctrl_config(struct pxp_pixmap *out, uint8_t mode,
+ uint8_t fill_en, uint8_t combine_2ch)
+{
+ struct store_ctrl ctrl;
+ uint8_t output_active_bpp;
+
+ memset((void*)&ctrl, 0x0, sizeof(ctrl));
+
+ if (combine_2ch) {
+ ctrl.combine_2channel = 1;
+ if (out) {
+ output_active_bpp = active_bpp(out->bpp);
+ ctrl.pack_in_sel = (output_active_bpp < 0x3) ? 1 : 0;
+ ctrl.store_memory_en = 1;
+ }
+ } else {
+ if (fill_en) {
+ ctrl.fill_data_en = 1;
+ ctrl.wr_num_bytes = 2;
+ }
+ ctrl.store_memory_en = 1;
+ }
+
+ if (out->rotate || out->flip)
+ ctrl.block_en = 1;
+
+ ctrl.ch_en = 1;
+
+ return *(uint32_t *)&ctrl;
+}
+
+static uint32_t pxp_store_size_config(struct pxp_pixmap *out)
+{
+ struct store_size size;
+
+ memset((void*)&size, 0x0, sizeof(size));
+
+ size.out_height = out->height - 1;
+ size.out_width = out->width - 1;
+
+ return *(uint32_t *)&size;
+}
+
+static uint32_t pxp_store_pitch_config(struct pxp_pixmap *out0,
+ struct pxp_pixmap *out1)
+{
+ struct store_pitch pitch;
+
+ memset((void*)&pitch, 0x0, sizeof(pitch));
+
+ pitch.ch0_out_pitch = out0->pitch;
+ pitch.ch1_out_pitch = out1 ? out1->pitch : 0;
+
+ return *(uint32_t *)&pitch;
+}
+
+static struct color *pxp_find_rgb_color(uint32_t format)
+{
+ int i;
+
+ for (i = 0; i < sizeof(rgb_colors) / sizeof(struct color); i++) {
+ if (rgb_colors[i].format == format)
+ return &rgb_colors[i];
+ }
+
+ return NULL;
+}
+
+static struct color_component *pxp_find_comp(struct color *color, uint8_t id)
+{
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (id == color->comp[i].id)
+ return &color->comp[i];
+ }
+
+ return NULL;
+}
+
+static struct color *pxp_find_yuv_color(uint32_t format)
+{
+ int i;
+
+ for (i = 0; i < sizeof(yuv_colors) / sizeof(struct color); i++) {
+ if (yuv_colors[i].format == format)
+ return &yuv_colors[i];
+ }
+
+ return NULL;
+}
+
+static uint64_t pxp_store_d_shift_calc(uint32_t in_fmt, uint32_t out_fmt,
+ struct store_d_mask *d_mask)
+{
+ int i, shift_width, shift_flag, drop = 0;
+ struct store_d_shift d_shift;
+ struct color *input_color, *output_color;
+ struct color_component *input_comp, *output_comp;
+
+ BUG_ON((in_fmt == out_fmt));
+ memset((void*)&d_shift, 0x0, sizeof(d_shift));
+ memset((void*)d_mask, 0x0, sizeof(*d_mask) * 8);
+
+ if (!is_yuv(in_fmt)) {
+ input_color = pxp_find_rgb_color(in_fmt);
+ output_color = pxp_find_rgb_color(out_fmt);
+ } else {
+ input_color = pxp_find_yuv_color(in_fmt);
+ output_color = pxp_find_yuv_color(out_fmt);
+ }
+
+ for (i = 0; i < 4; i++) {
+ input_comp = &input_color->comp[i];
+ if (!input_comp->length)
+ continue;
+
+ output_comp = pxp_find_comp(output_color, input_comp->id);
+ if (!output_comp->length)
+ continue;
+
+ /* only rgb format can drop color bits */
+ if (input_comp->length > output_comp->length) {
+ drop = input_comp->length - output_comp->length;
+ input_comp->offset += drop;
+ }
+ d_mask[i].d_mask_l = output_comp->mask << input_comp->offset;
+
+ shift_width = input_comp->offset - output_comp->offset;
+ if (shift_width > 0)
+ shift_flag = 0; /* right shift */
+ else if (shift_width < 0) {
+ shift_flag = 1; /* left shift */
+ shift_width = -shift_width;
+ } else
+ shift_width = shift_flag = 0; /* no shift require */
+
+ switch (i) {
+ case 0:
+ d_shift.d_shift_width0 = shift_width;
+ d_shift.d_shift_flag0 = shift_flag;
+ break;
+ case 1:
+ d_shift.d_shift_width1 = shift_width;
+ d_shift.d_shift_flag1 = shift_flag;
+ break;
+ case 2:
+ d_shift.d_shift_width2 = shift_width;
+ d_shift.d_shift_flag2 = shift_flag;
+ break;
+ case 3:
+ d_shift.d_shift_width3 = shift_width;
+ d_shift.d_shift_flag3 = shift_flag;
+ break;
+ default:
+ printk(KERN_ERR "unsupport d shift\n");
+ break;
+ }
+
+ input_comp->offset -= drop;
+ }
+
+ return *(uint64_t *)&d_shift;
+}
+
+static uint32_t pxp_store_shift_ctrl_config(struct pxp_pixmap *out,
+ uint8_t shift_bypass)
+{
+ struct store_shift_ctrl shift_ctrl;
+
+ memset((void*)&shift_ctrl, 0x0, sizeof(shift_ctrl));
+
+ shift_ctrl.output_active_bpp = active_bpp(out->bpp);
+ /* Not general data */
+ if (!shift_bypass) {
+ switch(out->format) {
+ case PXP_PIX_FMT_YUYV:
+ shift_bypass = 1;
+ case PXP_PIX_FMT_YVYU:
+ shift_ctrl.out_yuv422_1p_en = 1;
+ break;
+ case PXP_PIX_FMT_NV16:
+ shift_bypass = 1;
+ case PXP_PIX_FMT_NV61:
+ shift_ctrl.out_yuv422_2p_en = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ shift_ctrl.shift_bypass = shift_bypass;
+
+ return *(uint32_t *)&shift_ctrl;
+}
+
+static uint32_t pxp_fetch_ctrl_config(struct pxp_pixmap *in,
+ uint8_t mode)
+{
+ struct fetch_ctrl ctrl;
+
+ memset((void*)&ctrl, 0x0, sizeof(ctrl));
+
+ if (mode == FETCH_MODE_NORMAL)
+ ctrl.bypass_pixel_en = 0;
+
+ if (in->flip == PXP_H_FLIP)
+ ctrl.hflip = 1;
+ else if (in->flip == PXP_V_FLIP)
+ ctrl.vflip = 1;
+
+ ctrl.rotation_angle = rotate_map(in->rotate);
+
+ if (in->rotate || in->flip)
+ ctrl.block_en = 1;
+
+ ctrl.ch_en = 1;
+
+ return *(uint32_t *)&ctrl;
+}
+
+static uint32_t pxp_fetch_active_size_ulc(struct pxp_pixmap *in)
+{
+ struct fetch_active_size_ulc size_ulc;
+
+ memset((void*)&size_ulc, 0x0, sizeof(size_ulc));
+
+ size_ulc.active_size_ulc_x = 0;
+ size_ulc.active_size_ulc_y = 0;
+
+ return *(uint32_t *)&size_ulc;
+}
+
+static uint32_t pxp_fetch_active_size_lrc(struct pxp_pixmap *in)
+{
+ struct fetch_active_size_lrc size_lrc;
+
+ memset((void*)&size_lrc, 0x0, sizeof(size_lrc));
+
+ size_lrc.active_size_lrc_x = in->crop.width - 1;
+ size_lrc.active_size_lrc_y = in->crop.height - 1;
+
+ return *(uint32_t *)&size_lrc;
+}
+
+static uint32_t pxp_fetch_pitch_config(struct pxp_pixmap *in0,
+ struct pxp_pixmap *in1)
+{
+ struct fetch_pitch pitch;
+
+ memset((void*)&pitch, 0x0, sizeof(pitch));
+
+ if (in0)
+ pitch.ch0_input_pitch = in0->pitch;
+ if (in1)
+ pitch.ch1_input_pitch = in1->pitch;
+
+ return *(uint32_t *)&pitch;
+}
+
+static uint32_t pxp_fetch_shift_ctrl_config(struct pxp_pixmap *in,
+ uint8_t shift_bypass,
+ uint8_t need_expand)
+{
+ uint8_t input_expand_format;
+ struct fetch_shift_ctrl shift_ctrl;
+
+ memset((void*)&shift_ctrl, 0x0, sizeof(shift_ctrl));
+
+ shift_ctrl.input_active_bpp = active_bpp(in->bpp);
+ shift_ctrl.shift_bypass = shift_bypass;
+
+ if (in->bpp == 32)
+ need_expand = 0;
+
+ if (need_expand) {
+ input_expand_format = expand_format(in->format);
+
+ if (input_expand_format <= 0x7) {
+ shift_ctrl.expand_en = 1;
+ shift_ctrl.expand_format = input_expand_format;
+ }
+ }
+
+ return *(uint32_t *)&shift_ctrl;
+}
+
+static uint32_t pxp_fetch_shift_calc(uint32_t in_fmt, uint32_t out_fmt,
+ struct fetch_shift_width *shift_width)
+{
+ int i;
+ struct fetch_shift_offset shift_offset;
+ struct color *input_color, *output_color;
+ struct color_component *input_comp, *output_comp;
+
+ memset((void*)&shift_offset, 0x0, sizeof(shift_offset));
+ memset((void*)shift_width, 0x0, sizeof(*shift_width));
+
+ if (!is_yuv(in_fmt)) {
+ input_color = pxp_find_rgb_color(in_fmt);
+ output_color = pxp_find_rgb_color(out_fmt);
+ } else {
+ input_color = pxp_find_yuv_color(in_fmt);
+ output_color = pxp_find_yuv_color(out_fmt);
+ }
+
+ for(i = 0; i < 4; i++) {
+ output_comp = &output_color->comp[i];
+ if (!output_comp->length)
+ continue;
+
+ input_comp = pxp_find_comp(input_color, output_comp->id);
+ switch (i) {
+ case 0:
+ shift_offset.offset0 = input_comp->offset;
+ shift_width->width0 = input_comp->length;
+ break;
+ case 1:
+ shift_offset.offset1 = input_comp->offset;
+ shift_width->width1 = input_comp->length;
+ break;
+ case 2:
+ shift_offset.offset2 = input_comp->offset;
+ shift_width->width2 = input_comp->length;
+ break;
+ case 3:
+ shift_offset.offset3 = input_comp->offset;
+ shift_width->width3 = input_comp->length;
+ break;
+ }
+ }
+
+ return *(uint32_t *)&shift_offset;
+}
+
+static int pxp_start(struct pxps *pxp)
+{
+ __raw_writel(BM_PXP_CTRL_ENABLE_ROTATE1 | BM_PXP_CTRL_ENABLE |
+ BM_PXP_CTRL_ENABLE_CSC2 | BM_PXP_CTRL_ENABLE_LUT |
+ BM_PXP_CTRL_ENABLE_PS_AS_OUT | BM_PXP_CTRL_ENABLE_ROTATE0,
+ pxp->base + HW_PXP_CTRL_SET);
+ dump_pxp_reg(pxp);
+
+ return 0;
+}
+
+static bool fmt_ps_support(uint32_t format)
+{
+ switch (format) {
+ case PXP_PIX_FMT_XRGB32:
+ case PXP_PIX_FMT_ARGB32:
+ case PXP_PIX_FMT_RGB555:
+ case PXP_PIX_FMT_XRGB555:
+ case PXP_PIX_FMT_ARGB555:
+ case PXP_PIX_FMT_RGB444:
+ case PXP_PIX_FMT_XRGB444:
+ case PXP_PIX_FMT_ARGB444:
+ case PXP_PIX_FMT_RGB565:
+ case PXP_PIX_FMT_YUV444:
+ case PXP_PIX_FMT_UYVY:
+ /* need word byte swap */
+ case PXP_PIX_FMT_YUYV:
+ case PXP_PIX_FMT_VYUY:
+ /* need word byte swap */
+ case PXP_PIX_FMT_YVYU:
+ case PXP_PIX_FMT_GREY:
+ case PXP_PIX_FMT_GY04:
+ case PXP_PIX_FMT_NV16:
+ case PXP_PIX_FMT_NV12:
+ case PXP_PIX_FMT_NV61:
+ case PXP_PIX_FMT_NV21:
+ case PXP_PIX_FMT_YUV422P:
+ case PXP_PIX_FMT_YUV420P:
+ case PXP_PIX_FMT_YVU420P:
+ case PXP_PIX_FMT_RGBA32:
+ case PXP_PIX_FMT_RGBX32:
+ case PXP_PIX_FMT_RGBA555:
+ case PXP_PIX_FMT_RGBA444:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool fmt_as_support(uint32_t format)
+{
+ switch (format) {
+ case PXP_PIX_FMT_ARGB32:
+ case PXP_PIX_FMT_RGBA32:
+ case PXP_PIX_FMT_XRGB32:
+ case PXP_PIX_FMT_BGRA32:
+ case PXP_PIX_FMT_ARGB555:
+ case PXP_PIX_FMT_ARGB444:
+ case PXP_PIX_FMT_RGBA555:
+ case PXP_PIX_FMT_RGBA444:
+ case PXP_PIX_FMT_RGB555:
+ case PXP_PIX_FMT_RGB444:
+ case PXP_PIX_FMT_RGB565:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool fmt_out_support(uint32_t format)
+{
+ switch (format) {
+ case PXP_PIX_FMT_ARGB32:
+ case PXP_PIX_FMT_XRGB32:
+ case PXP_PIX_FMT_BGRA32:
+ case PXP_PIX_FMT_RGB24:
+ case PXP_PIX_FMT_ARGB555:
+ case PXP_PIX_FMT_ARGB444:
+ case PXP_PIX_FMT_RGB555:
+ case PXP_PIX_FMT_RGB444:
+ case PXP_PIX_FMT_RGB565:
+ case PXP_PIX_FMT_YUV444:
+ case PXP_PIX_FMT_UYVY:
+ case PXP_PIX_FMT_VYUY:
+ case PXP_PIX_FMT_GREY:
+ case PXP_PIX_FMT_GY04:
+ case PXP_PIX_FMT_NV16:
+ case PXP_PIX_FMT_NV12:
+ case PXP_PIX_FMT_NV61:
+ case PXP_PIX_FMT_NV21:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* common means 'ARGB32/XRGB32/YUV444' */
+static uint8_t fmt_fetch_to_common(uint32_t in)
+{
+ switch (in) {
+ case PXP_PIX_FMT_ARGB32:
+ case PXP_PIX_FMT_XRGB32:
+ case PXP_PIX_FMT_YUV444:
+ return FETCH_NOOP;
+
+ case PXP_PIX_FMT_RGB565:
+ case PXP_PIX_FMT_RGB555:
+ case PXP_PIX_FMT_ARGB555:
+ case PXP_PIX_FMT_RGB444:
+ case PXP_PIX_FMT_ARGB444:
+ case PXP_PIX_FMT_YUYV:
+ case PXP_PIX_FMT_UYVY:
+ case PXP_PIX_FMT_NV16:
+ return FETCH_EXPAND;
+
+ case PXP_PIX_FMT_RGBA32:
+ case PXP_PIX_FMT_RGBX32:
+ case PXP_PIX_FMT_BGRA32:
+ case PXP_PIX_FMT_BGRX32:
+ case PXP_PIX_FMT_ABGR32:
+ case PXP_PIX_FMT_XBGR32:
+ case PXP_PIX_FMT_YVU444:
+ return FETCH_SHIFT;
+
+ case PXP_PIX_FMT_BGR565:
+ case PXP_PIX_FMT_YVYU:
+ case PXP_PIX_FMT_VYUY:
+ return FETCH_EXPAND | FETCH_SHIFT;
+
+ default:
+ return 0;
+ }
+}
+
+static uint8_t fmt_store_from_common(uint32_t out)
+{
+ switch (out) {
+ case PXP_PIX_FMT_ARGB32:
+ case PXP_PIX_FMT_XRGB32:
+ case PXP_PIX_FMT_YUV444:
+ return STORE_NOOP;
+
+ case PXP_PIX_FMT_YUYV:
+ case PXP_PIX_FMT_NV16:
+ return STORE_SHRINK;
+
+ case PXP_PIX_FMT_RGBA32:
+ case PXP_PIX_FMT_RGBX32:
+ case PXP_PIX_FMT_BGRA32:
+ case PXP_PIX_FMT_BGRX32:
+ case PXP_PIX_FMT_ABGR32:
+ case PXP_PIX_FMT_XBGR32:
+ case PXP_PIX_FMT_YVU444:
+ case PXP_PIX_FMT_RGB565:
+ case PXP_PIX_FMT_RGB555:
+ case PXP_PIX_FMT_ARGB555:
+ case PXP_PIX_FMT_RGB444:
+ case PXP_PIX_FMT_ARGB444:
+ case PXP_PIX_FMT_GREY:
+ return STORE_SHIFT;
+
+ case PXP_PIX_FMT_YVYU:
+ case PXP_PIX_FMT_NV61:
+ return STORE_SHIFT | STORE_SHRINK;
+
+ default:
+ return 0;
+ }
+}
+
+static void filter_possible_inputs(struct pxp_pixmap *input,
+ uint32_t *possible)
+{
+ uint8_t clear = 0xff;
+ uint8_t position = 0;
+
+ do {
+ position = find_next_bit((unsigned long *)possible, 32, position);
+ if (position >= sizeof(uint32_t) * 8)
+ break;
+
+ switch (position) {
+ case PXP_2D_PS:
+ if (!fmt_ps_support(input->format))
+ clear = PXP_2D_PS;
+ break;
+ case PXP_2D_AS:
+ if (!fmt_as_support(input->format))
+ clear = PXP_2D_AS;
+ break;
+ case PXP_2D_INPUT_FETCH0:
+ case PXP_2D_INPUT_FETCH1:
+ if ((is_yuv(input->format) == 3)) {
+ clear = position;
+ break;
+ }
+ if ((input->flags & IN_NEED_FMT_UNIFIED) ||
+ is_yuv(input->format) == 2)
+ if (!fmt_fetch_to_common(input->format))
+ clear = position;
+ break;
+ default:
+ pr_err("invalid input node: %d\n", position);
+ clear = position;
+ break;
+ }
+
+ if (clear != 0xff) {
+ clear_bit(clear, (unsigned long*)possible);
+ clear = 0xff;
+ }
+
+ position++;
+ } while (1);
+}
+
+static void filter_possible_outputs(struct pxp_pixmap *output,
+ uint32_t *possible)
+{
+ uint8_t clear = 0xff;
+ uint8_t position = 0;
+
+ do {
+ position = find_next_bit((unsigned long *)possible, 32, position);
+ if (position >= sizeof(uint32_t) * 8)
+ break;
+
+ switch (position) {
+ case PXP_2D_OUT:
+ if (!fmt_out_support(output->format))
+ clear = PXP_2D_OUT;
+ break;
+ case PXP_2D_INPUT_STORE0:
+ case PXP_2D_INPUT_STORE1:
+ if (output->flags) {
+ if (!fmt_store_from_common(output->format))
+ clear = position;
+ }
+ break;
+ default:
+ pr_err("invalid output node: %d\n", position);
+ clear = position;
+ break;
+ }
+
+ if (clear != 0xff) {
+ clear_bit(clear, (unsigned long*)possible);
+ clear = 0xff;
+ }
+
+ position++;
+ } while (1);
+}
+
+static uint32_t calc_shortest_path(uint32_t *nodes_used)
+{
+ uint32_t distance = 0;
+ uint32_t from = 0, to = 0, bypass, end;
+
+ do {
+ from = find_next_bit((unsigned long *)nodes_used, 32, from);
+ if (from >= sizeof(uint32_t) * 8)
+ break;
+
+ if (to != 0) {
+ if (path_table[to][from].distance == DISTANCE_INFINITY)
+ return DISTANCE_INFINITY;
+
+ distance += path_table[to][from].distance;
+ /* backtrace */
+ end = from;
+ while (1) {
+ bypass = path_table[to][end].prev_node;
+ if (bypass == to)
+ break;
+ set_bit(bypass, (unsigned long*)nodes_used);
+ end = bypass;
+ }
+ }
+
+ to = find_next_bit((unsigned long *)nodes_used, 32, from + 1);
+ if (to >= sizeof(uint32_t) * 8)
+ break;
+
+ if (path_table[from][to].distance == DISTANCE_INFINITY)
+ return DISTANCE_INFINITY;
+
+ distance += path_table[from][to].distance;
+ /* backtrace */
+ end = to;
+ while (1) {
+ bypass = path_table[from][end].prev_node;
+ if (bypass == from)
+ break;
+ set_bit(bypass, (unsigned long*)nodes_used);
+ end = bypass;
+ }
+
+ from = to + 1;
+ } while (1);
+
+ return distance;
+}
+
+static uint32_t find_best_path(uint32_t inputs,
+ uint32_t outputs,
+ struct pxp_pixmap *in,
+ uint32_t *nodes_used)
+{
+ uint32_t outs;
+ uint32_t nodes_add, best_nodes_used = 0;
+ uint8_t in_pos = 0, out_pos = 0;
+ uint32_t nodes_in_path, best_nodes_in_path = 0;
+ uint32_t best_distance = DISTANCE_INFINITY, distance;
+
+ do {
+ outs = outputs;
+ in_pos = find_next_bit((unsigned long *)&inputs, 32, in_pos);
+ if (in_pos >= sizeof(uint32_t) * 8)
+ break;
+ nodes_add = 0;
+ set_bit(in_pos, (unsigned long *)&nodes_add);
+
+ switch (in_pos) {
+ case PXP_2D_PS:
+ if ((in->flags & IN_NEED_CSC) == IN_NEED_CSC) {
+ if (is_yuv(in->format))
+ set_bit(PXP_2D_CSC1,
+ (unsigned long *)&nodes_add);
+ else
+ set_bit(PXP_2D_CSC2,
+ (unsigned long *)&nodes_add);
+ }
+ if ((in->flags & IN_NEED_ROTATE_FLIP) == IN_NEED_ROTATE_FLIP)
+ set_bit(PXP_2D_ROTATION1,
+ (unsigned long *)&nodes_add);
+ clear_bit(PXP_2D_INPUT_STORE0, (unsigned long *)&outs);
+ break;
+ case PXP_2D_AS:
+ if ((in->flags & IN_NEED_CSC) == IN_NEED_CSC)
+ set_bit(PXP_2D_CSC2,
+ (unsigned long *)&nodes_add);
+ if ((in->flags & IN_NEED_ROTATE_FLIP) == IN_NEED_ROTATE_FLIP)
+ set_bit(PXP_2D_ROTATION0,
+ (unsigned long *)&nodes_add);
+ clear_bit(PXP_2D_INPUT_STORE0, (unsigned long *)&outs);
+ break;
+ case PXP_2D_INPUT_FETCH0:
+ case PXP_2D_INPUT_FETCH1:
+ if ((in->flags & IN_NEED_CSC) == IN_NEED_CSC)
+ set_bit(PXP_2D_CSC2,
+ (unsigned long *)&nodes_add);
+ clear_bit(PXP_2D_OUT, (unsigned long *)&outs);
+ if ((in->flags & IN_NEED_ROTATE_FLIP) == IN_NEED_ROTATE_FLIP)
+ set_bit(PXP_2D_ROTATION1,
+ (unsigned long *)&nodes_add);
+ break;
+ default:
+ /* alph0_s0/s1, alpha1_s0/s1 */
+ break;
+ }
+
+ nodes_add |= *nodes_used;
+
+ do {
+ out_pos = find_next_bit((unsigned long *)&outs, 32, out_pos);
+ if (out_pos >= sizeof(uint32_t) * 8)
+ break;
+ set_bit(out_pos, (unsigned long *)&nodes_add);
+
+ switch(out_pos) {
+ case PXP_2D_ALPHA0_S0:
+ case PXP_2D_ALPHA0_S1:
+ case PXP_2D_ALPHA1_S0:
+ case PXP_2D_ALPHA1_S1:
+ clear_bit(PXP_2D_CSC2, (unsigned long *)&nodes_add);
+ clear_bit(PXP_2D_ROTATION0, (unsigned long *)&nodes_add);
+ clear_bit(PXP_2D_LUT, (unsigned long *)&nodes_add);
+ break;
+ default:
+ break;
+ }
+
+ nodes_in_path = nodes_add;
+ distance = calc_shortest_path(&nodes_in_path);
+ if (best_distance > distance) {
+ best_distance = distance;
+ best_nodes_used = nodes_add;
+ best_nodes_in_path = nodes_in_path;
+ }
+ pr_debug("%s: out_pos = %d, nodes_in_path = 0x%x, nodes_add = 0x%x, distance = 0x%x\n",
+ __func__, out_pos, nodes_in_path, nodes_add, distance);
+
+ clear_bit(out_pos, (unsigned long *)&nodes_add);
+
+ out_pos++;
+ } while (1);
+
+ in_pos++;
+ } while (1);
+
+ *nodes_used = best_nodes_used;
+
+ return best_nodes_in_path;
+}
+
+static uint32_t ps_calc_scaling(struct pxp_pixmap *input,
+ struct pxp_pixmap *output,
+ struct ps_ctrl *ctrl)
+{
+ struct ps_scale scale;
+ uint32_t decx, decy;
+
+ memset((void*)&scale, 0x0, sizeof(scale));
+
+ if (!output->crop.width || !output->crop.height) {
+ pr_err("Invalid drect width and height passed in\n");
+ return 0;
+ }
+
+ if ((input->rotate == 90) || (input->rotate == 270))
+ swap(output->crop.width, output->crop.height);
+
+ decx = input->crop.width / output->crop.width;
+ decy = input->crop.height / output->crop.height;
+
+ if (decx > 1) {
+ if (decx >= 2 && decx < 4) {
+ decx = 2;
+ ctrl->decx = 1;
+ } else if (decx >= 4 && decx < 8) {
+ decx = 4;
+ ctrl->decx = 2;
+ } else if (decx >= 8) {
+ decx = 8;
+ ctrl->decx = 3;
+ }
+ scale.xscale = input->crop.width * 0x1000 /
+ (output->crop.width * decx);
+
+ /* A factor greater than 2 is not supported
+ * with the bilinear filter, so correct it in
+ * driver
+ */
+ if (((scale.xscale >> BP_PXP_PS_SCALE_OFFSET) & 0x3) > 2) {
+ scale.xscale &= (~(0x3 << BP_PXP_PS_SCALE_OFFSET));
+ scale.xscale |= (0x2 << BP_PXP_PS_SCALE_OFFSET);
+ pr_warn("%s: scale.xscale is larger than 2, forcing to 2"
+ "input w/h=(%d,%d), output w/h=(%d, %d)\n",
+ __func__, input->crop.width, input->crop.height,
+ output->crop.width, output->crop.height);
+ }
+ } else {
+ if (!is_yuv(input->format) ||
+ (is_yuv(input->format) == is_yuv(output->format)) ||
+ (input->format == PXP_PIX_FMT_GREY) ||
+ (input->format == PXP_PIX_FMT_GY04) ||
+ (input->format == PXP_PIX_FMT_VUY444)) {
+ if ((input->crop.width > 1) &&
+ (output->crop.width > 1))
+ scale.xscale = (input->crop.width - 1) * 0x1000 /
+ (output->crop.width - 1);
+ else
+ scale.xscale = input->crop.width * 0x1000 /
+ output->crop.width;
+ } else {
+ if ((input->crop.width > 2) &&
+ (output->crop.width > 1))
+ scale.xscale = (input->crop.width - 2) * 0x1000 /
+ (output->crop.width - 1);
+ else
+ scale.xscale = input->crop.width * 0x1000 /
+ output->crop.width;
+ }
+ }
+
+ if (decy > 1) {
+ if (decy >= 2 && decy < 4) {
+ decy = 2;
+ ctrl->decy = 1;
+ } else if (decy >= 4 && decy < 8) {
+ decy = 4;
+ ctrl->decy = 2;
+ } else if (decy >= 8) {
+ decy = 8;
+ ctrl->decy = 3;
+ }
+ scale.yscale = input->crop.height * 0x1000 /
+ (output->crop.height * decy);
+
+ /* A factor greater than 2 is not supported
+ * with the bilinear filter, so correct it in
+ * driver
+ */
+ if (((scale.yscale >> BP_PXP_PS_SCALE_OFFSET) & 0x3) > 2) {
+ scale.yscale &= (~(0x3 << BP_PXP_PS_SCALE_OFFSET));
+ scale.yscale |= (0x2 << BP_PXP_PS_SCALE_OFFSET);
+ pr_warn("%s: scale.yscale is larger than 2, forcing to 2"
+ "input w/h=(%d,%d), output w/h=(%d, %d)\n",
+ __func__, input->crop.width, input->crop.height,
+ output->crop.width, output->crop.height);
+ }
+ } else {
+ if ((input->crop.height > 1) && (output->crop.height > 1))
+ scale.yscale = (input->crop.height - 1) * 0x1000 /
+ (output->crop.height - 1);
+ else
+ scale.yscale = input->crop.height * 0x1000 /
+ output->crop.height;
+ }
+
+ return *(uint32_t *)&scale;
+}
+
+static int pxp_ps_config(struct pxp_pixmap *input,
+ struct pxp_pixmap *output)
+{
+ uint32_t offset, U, V;
+ struct ps_ctrl ctrl;
+ struct coordinate out_ps_ulc, out_ps_lrc;
+
+ memset((void*)&ctrl, 0x0, sizeof(ctrl));
+
+ ctrl.format = pxp_parse_ps_fmt(input->format);
+
+ switch (output->rotate) {
+ case 0:
+ out_ps_ulc.x = output->crop.x;
+ out_ps_ulc.y = output->crop.y;
+ out_ps_lrc.x = out_ps_ulc.x + output->crop.width - 1;
+ out_ps_lrc.y = out_ps_ulc.y + output->crop.height - 1;
+ break;
+ case 90:
+ out_ps_ulc.x = output->crop.y;
+ out_ps_ulc.y = output->width - (output->crop.x + output->crop.width);
+ out_ps_lrc.x = out_ps_ulc.x + output->crop.height - 1;
+ out_ps_lrc.y = out_ps_ulc.y + output->crop.width - 1;
+ break;
+ case 180:
+ out_ps_ulc.x = output->width - (output->crop.x + output->crop.width);
+ out_ps_ulc.y = output->height - (output->crop.y + output->crop.height);
+ out_ps_lrc.x = out_ps_ulc.x + output->crop.width - 1;
+ out_ps_lrc.y = out_ps_ulc.y + output->crop.height - 1;
+ break;
+ case 270:
+ out_ps_ulc.x = output->height - (output->crop.y + output->crop.height);
+ out_ps_ulc.y = output->crop.x;
+ out_ps_lrc.x = out_ps_ulc.x + output->crop.height - 1;
+ out_ps_lrc.y = out_ps_ulc.y + output->crop.width - 1;
+ break;
+ default:
+ pr_err("PxP only support rotate 0 90 180 270\n");
+ return -EINVAL;
+ break;
+ }
+
+ if ((input->format == PXP_PIX_FMT_YUYV) ||
+ (input->format == PXP_PIX_FMT_YVYU))
+ ctrl.wb_swap = 1;
+
+ pxp_writel(ps_calc_scaling(input, output, &ctrl),
+ HW_PXP_PS_SCALE);
+ pxp_writel(*(uint32_t *)&ctrl, HW_PXP_PS_CTRL);
+
+ offset = input->crop.y * input->pitch +
+ input->crop.x * (input->bpp >> 3);
+ pxp_writel(input->paddr + offset, HW_PXP_PS_BUF);
+
+ switch (is_yuv(input->format)) {
+ case 0: /* RGB */
+ case 1: /* 1 Plane YUV */
+ break;
+ case 2: /* NV16,NV61,NV12,NV21 */
+ if ((input->format == PXP_PIX_FMT_NV16) ||
+ (input->format == PXP_PIX_FMT_NV61)) {
+ U = input->paddr + input->width * input->height;
+ pxp_writel(U + offset, HW_PXP_PS_UBUF);
+ }
+ else {
+ U = input->paddr + input->width * input->height;
+ pxp_writel(U + (offset >> 1), HW_PXP_PS_UBUF);
+ }
+ break;
+ case 3: /* YUV422P, YUV420P */
+ if (input->format == PXP_PIX_FMT_YUV422P) {
+ U = input->paddr + input->width * input->height;
+ pxp_writel(U + (offset >> 1), HW_PXP_PS_UBUF);
+ V = U + (input->width * input->height >> 1);
+ pxp_writel(V + (offset >> 1), HW_PXP_PS_VBUF);
+ } else if (input->format == PXP_PIX_FMT_YUV420P) {
+ U = input->paddr + input->width * input->height;
+ pxp_writel(U + (offset >> 2), HW_PXP_PS_UBUF);
+ V = U + (input->width * input->height >> 2);
+ pxp_writel(V + (offset >> 2), HW_PXP_PS_VBUF);
+ } else if (input->format == PXP_PIX_FMT_YVU420P) {
+ U = input->paddr + input->width * input->height;
+ V = U + (input->width * input->height >> 2);
+ pxp_writel(U + (offset >> 2), HW_PXP_PS_VBUF);
+ pxp_writel(V + (offset >> 2), HW_PXP_PS_UBUF);
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ pxp_writel(input->pitch, HW_PXP_PS_PITCH);
+ pxp_writel(*(uint32_t *)&out_ps_ulc, HW_PXP_OUT_PS_ULC);
+ pxp_writel(*(uint32_t *)&out_ps_lrc, HW_PXP_OUT_PS_LRC);
+
+ pxp_writel(BF_PXP_CTRL_ENABLE_PS_AS_OUT(1) |
+ BF_PXP_CTRL_IRQ_ENABLE(1),
+ HW_PXP_CTRL_SET);
+
+ return 0;
+}
+
+static int pxp_as_config(struct pxp_pixmap *input,
+ struct pxp_pixmap *output)
+{
+ uint32_t offset;
+ struct as_ctrl ctrl;
+ struct coordinate out_as_ulc, out_as_lrc;
+
+ memset((void*)&ctrl, 0x0, sizeof(ctrl));
+
+ ctrl.format = pxp_parse_as_fmt(input->format);
+
+ if (alpha_blending_version == PXP_ALPHA_BLENDING_V1) {
+ if (input->format == PXP_PIX_FMT_BGRA32) {
+ if (!input->g_alpha.combine_enable) {
+ ctrl.alpha_ctrl = BV_PXP_AS_CTRL_ALPHA_CTRL__ROPs;
+ ctrl.rop = 0x3;
+ }
+ }
+
+ if (input->g_alpha.global_alpha_enable) {
+ if (input->g_alpha.global_override)
+ ctrl.alpha_ctrl = BV_PXP_AS_CTRL_ALPHA_CTRL__Override;
+ else
+ ctrl.alpha_ctrl = BV_PXP_AS_CTRL_ALPHA_CTRL__Multiply;
+
+ if (input->g_alpha.alpha_invert)
+ ctrl.alpha0_invert = 0x1;
+ }
+
+ if (input->g_alpha.color_key_enable) {
+ ctrl.enable_colorkey = 1;
+ }
+
+ ctrl.alpha = input->g_alpha.global_alpha;
+ }
+
+ out_as_ulc.x = out_as_ulc.y = 0;
+ if (input->g_alpha.combine_enable) {
+ out_as_lrc.x = input->width - 1;
+ out_as_lrc.y = input->height - 1;
+ } else {
+ out_as_lrc.x = output->crop.width - 1;
+ out_as_lrc.y = output->crop.height - 1;
+ }
+
+ offset = input->crop.y * input->pitch +
+ input->crop.x * (input->bpp >> 3);
+ pxp_writel(input->paddr + offset, HW_PXP_AS_BUF);
+
+ pxp_writel(input->pitch, HW_PXP_AS_PITCH);
+ pxp_writel(*(uint32_t *)&out_as_ulc, HW_PXP_OUT_AS_ULC);
+ pxp_writel(*(uint32_t *)&out_as_lrc, HW_PXP_OUT_AS_LRC);
+
+ pxp_writel(*(uint32_t *)&ctrl, HW_PXP_AS_CTRL);
+ pxp_writel(BF_PXP_CTRL_ENABLE_PS_AS_OUT(1) |
+ BF_PXP_CTRL_IRQ_ENABLE(1),
+ HW_PXP_CTRL_SET);
+
+ return 0;
+}
+
+static uint32_t pxp_fetch_size_config(struct pxp_pixmap *input)
+{
+ struct fetch_size total_size;
+
+ memset((void*)&total_size, 0x0, sizeof(total_size));
+
+ total_size.input_total_width = input->width - 1;
+ total_size.input_total_height = input->height - 1;
+
+ return *(uint32_t *)&total_size;
+}
+
+static int pxp_fetch_config(struct pxp_pixmap *input,
+ uint32_t fetch_index)
+{
+ uint8_t shift_bypass = 1, expand_en = 0;
+ uint32_t flags, pitch = 0, offset, UV = 0;
+ uint32_t in_fmt, out_fmt;
+ uint32_t size_ulc, size_lrc;
+ uint32_t fetch_ctrl, total_size;
+ uint32_t shift_ctrl, shift_offset = 0;
+ struct fetch_shift_width shift_width;
+
+ memset((unsigned int *)&shift_width, 0x0, sizeof(shift_width));
+ fetch_ctrl = pxp_fetch_ctrl_config(input, FETCH_MODE_NORMAL);
+ size_ulc = pxp_fetch_active_size_ulc(input);
+ size_lrc = pxp_fetch_active_size_lrc(input);
+ total_size = pxp_fetch_size_config(input);
+
+ if (input->flags) {
+ flags = fmt_fetch_to_common(input->format);
+ shift_bypass = (flags & FETCH_SHIFT) ? 0 : 1;
+ expand_en = (flags & FETCH_EXPAND) ? 1 : 0;
+
+ if (!shift_bypass) {
+ if (expand_en) {
+ if (is_yuv(input->format)) {
+ in_fmt = PXP_PIX_FMT_YVU444;
+ out_fmt = PXP_PIX_FMT_YUV444;
+ } else {
+ in_fmt = PXP_PIX_FMT_ABGR32;
+ out_fmt = PXP_PIX_FMT_ARGB32;
+ }
+ } else {
+ in_fmt = input->format;
+ out_fmt = is_yuv(input->format) ?
+ PXP_PIX_FMT_YUV444 :
+ PXP_PIX_FMT_ARGB32;
+ }
+
+ shift_offset = pxp_fetch_shift_calc(in_fmt, out_fmt,
+ &shift_width);
+ }
+ }
+ shift_ctrl = pxp_fetch_shift_ctrl_config(input, shift_bypass, expand_en);
+
+ offset = input->crop.y * input->pitch +
+ input->crop.x * (input->bpp >> 3);
+ if (is_yuv(input->format) == 2)
+ UV = input->paddr + input->width * input->height;
+
+ switch (fetch_index) {
+ case PXP_2D_INPUT_FETCH0:
+ pitch = __raw_readl(pxp_reg_base + HW_PXP_INPUT_FETCH_PITCH);
+ pitch |= pxp_fetch_pitch_config(input, NULL);
+ pxp_writel(fetch_ctrl, HW_PXP_INPUT_FETCH_CTRL_CH0);
+ pxp_writel(size_ulc, HW_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH0);
+ pxp_writel(size_lrc, HW_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH0);
+ pxp_writel(total_size, HW_PXP_INPUT_FETCH_SIZE_CH0);
+ pxp_writel(shift_ctrl, HW_PXP_INPUT_FETCH_SHIFT_CTRL_CH0);
+ pxp_writel(input->paddr + offset, HW_PXP_INPUT_FETCH_ADDR_0_CH0);
+ if (UV)
+ pxp_writel(UV + offset, HW_PXP_INPUT_FETCH_ADDR_1_CH0);
+ pxp_writel(shift_ctrl, HW_PXP_INPUT_FETCH_SHIFT_CTRL_CH0);
+ if (shift_offset)
+ pxp_writel(*(uint32_t *)&shift_offset, HW_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0);
+ pxp_writel(*(uint32_t *)&shift_width, HW_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0);
+ break;
+ case PXP_2D_INPUT_FETCH1:
+ pitch = __raw_readl(pxp_reg_base + HW_PXP_INPUT_FETCH_PITCH);
+ pitch |= pxp_fetch_pitch_config(NULL, input);
+ pxp_writel(fetch_ctrl, HW_PXP_INPUT_FETCH_CTRL_CH1);
+ pxp_writel(size_ulc, HW_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH1);
+ pxp_writel(size_lrc, HW_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH1);
+ pxp_writel(total_size, HW_PXP_INPUT_FETCH_SIZE_CH1);
+ pxp_writel(shift_ctrl, HW_PXP_INPUT_FETCH_SHIFT_CTRL_CH1);
+ pxp_writel(input->paddr + offset, HW_PXP_INPUT_FETCH_ADDR_0_CH1);
+ if (UV)
+ pxp_writel(UV + offset, HW_PXP_INPUT_FETCH_ADDR_1_CH1);
+ pxp_writel(shift_ctrl, HW_PXP_INPUT_FETCH_SHIFT_CTRL_CH1);
+ if (shift_offset)
+ pxp_writel(*(uint32_t *)&shift_offset, HW_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1);
+ pxp_writel(*(uint32_t *)&shift_width, HW_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1);
+ break;
+ default:
+ break;
+ }
+
+ pxp_writel(pitch, HW_PXP_INPUT_FETCH_PITCH);
+ pxp_writel(BF_PXP_CTRL_ENABLE_INPUT_FETCH_STORE(1), HW_PXP_CTRL_SET);
+
+ return 0;
+}
+
+static int pxp_csc1_config(struct pxp_pixmap *input,
+ bool is_ycbcr)
+{
+ BUG_ON(!is_yuv(input->format));
+
+ if (!is_ycbcr) {
+ /* YUV -> RGB */
+ pxp_writel(0x04030000, HW_PXP_CSC1_COEF0);
+ pxp_writel(0x01230208, HW_PXP_CSC1_COEF1);
+ pxp_writel(0x076b079c, HW_PXP_CSC1_COEF2);
+
+ return 0;
+ }
+
+ /* YCbCr -> RGB */
+ pxp_writel(0x84ab01f0, HW_PXP_CSC1_COEF0);
+ pxp_writel(0x01980204, HW_PXP_CSC1_COEF1);
+ pxp_writel(0x0730079c, HW_PXP_CSC1_COEF2);
+
+ return 0;
+}
+
+static int pxp_rotation1_config(struct pxp_pixmap *input)
+{
+ uint8_t rotate;
+
+ if (input->flip == PXP_H_FLIP)
+ pxp_writel(BF_PXP_CTRL_HFLIP1(1), HW_PXP_CTRL_SET);
+ else if (input->flip == PXP_V_FLIP)
+ pxp_writel(BF_PXP_CTRL_VFLIP1(1), HW_PXP_CTRL_SET);
+
+ rotate = rotate_map(input->rotate);
+ pxp_writel(BF_PXP_CTRL_ROTATE1(rotate), HW_PXP_CTRL_SET);
+
+ pxp_writel(BF_PXP_CTRL_ENABLE_ROTATE1(1), HW_PXP_CTRL_SET);
+
+ return 0;
+}
+
+static int pxp_rotation0_config(struct pxp_pixmap *input)
+{
+ uint8_t rotate;
+
+ if (input->flip == PXP_H_FLIP)
+ pxp_writel(BF_PXP_CTRL_HFLIP0(1), HW_PXP_CTRL_SET);
+ else if (input->flip == PXP_V_FLIP)
+ pxp_writel(BF_PXP_CTRL_VFLIP0(1), HW_PXP_CTRL_SET);
+
+ rotate = rotate_map(input->rotate);
+ pxp_writel(BF_PXP_CTRL_ROTATE0(rotate), HW_PXP_CTRL_SET);
+
+ pxp_writel(BF_PXP_CTRL_ENABLE_ROTATE0(1), HW_PXP_CTRL_SET);
+
+ return 0;
+}
+
+static int pxp_csc2_config(struct pxp_pixmap *output)
+{
+ if (is_yuv(output->format)) {
+ /* RGB -> YUV */
+ pxp_writel(0x4, HW_PXP_CSC2_CTRL);
+ pxp_writel(0x0096004D, HW_PXP_CSC2_COEF0);
+ pxp_writel(0x05DA001D, HW_PXP_CSC2_COEF1);
+ pxp_writel(0x007005B6, HW_PXP_CSC2_COEF2);
+ pxp_writel(0x057C009E, HW_PXP_CSC2_COEF3);
+ pxp_writel(0x000005E6, HW_PXP_CSC2_COEF4);
+ pxp_writel(0x00000000, HW_PXP_CSC2_COEF5);
+ }
+
+ pxp_writel(BF_PXP_CTRL_ENABLE_CSC2(1), HW_PXP_CTRL_SET);
+
+ return 0;
+}
+
+static int pxp_out_config(struct pxp_pixmap *output)
+{
+ uint32_t offset, UV;
+ struct out_ctrl ctrl;
+ struct coordinate out_lrc;
+
+ memset((void*)&ctrl, 0x0, sizeof(ctrl));
+
+ ctrl.format = pxp_parse_out_fmt(output->format);
+ offset = output->crop.y * output->pitch +
+ output->crop.x * (output->bpp >> 3);
+
+ pxp_writel(*(uint32_t *)&ctrl, HW_PXP_OUT_CTRL);
+
+ pxp_writel(output->paddr, HW_PXP_OUT_BUF);
+ if (is_yuv(output->format) == 2) {
+ UV = output->paddr + output->width * output->height;
+ if ((output->format == PXP_PIX_FMT_NV16) ||
+ (output->format == PXP_PIX_FMT_NV61))
+ pxp_writel(UV + offset, HW_PXP_OUT_BUF2);
+ else
+ pxp_writel(UV + (offset >> 1), HW_PXP_OUT_BUF2);
+ }
+
+ if (output->rotate == 90 || output->rotate == 270) {
+ out_lrc.y = output->width - 1;
+ out_lrc.x = output->height - 1;
+ } else {
+ out_lrc.x = output->width - 1;
+ out_lrc.y = output->height - 1;
+ }
+
+ pxp_writel(*(uint32_t *)&out_lrc, HW_PXP_OUT_LRC);
+
+ pxp_writel(output->pitch, HW_PXP_OUT_PITCH);
+
+ /* set global alpha if necessary */
+ if (output->g_alpha.global_alpha_enable) {
+ pxp_writel(output->g_alpha.global_alpha << 24, HW_PXP_OUT_CTRL_SET);
+ pxp_writel(BM_PXP_OUT_CTRL_ALPHA_OUTPUT, HW_PXP_OUT_CTRL_SET);
+ }
+
+ pxp_writel(BF_PXP_CTRL_ENABLE_PS_AS_OUT(1) |
+ BF_PXP_CTRL_IRQ_ENABLE(1),
+ HW_PXP_CTRL_SET);
+
+ return 0;
+}
+
+static int pxp_store_config(struct pxp_pixmap *output,
+ struct pxp_op_info *op)
+{
+ uint8_t combine_2ch, flags;
+ uint32_t in_fmt, out_fmt, offset, UV = 0;
+ uint64_t d_shift = 0;
+ struct store_d_mask d_mask[8];
+ uint32_t store_ctrl, store_size, store_pitch, shift_ctrl;
+
+ memset((void*)d_mask, 0x0, sizeof(*d_mask) * 8);
+ combine_2ch = (output->bpp == 64) ? 1 : 0;
+ store_ctrl = pxp_store_ctrl_config(output, STORE_MODE_NORMAL,
+ op->fill_en, combine_2ch);
+ store_size = pxp_store_size_config(output);
+ store_pitch = pxp_store_pitch_config(output, NULL);
+
+ pxp_writel(store_ctrl, HW_PXP_INPUT_STORE_CTRL_CH0);
+
+ if (output->flags) {
+ flags = fmt_store_from_common(output->format);
+ if (flags == STORE_NOOP)
+ shift_ctrl = pxp_store_shift_ctrl_config(output, 1);
+ else if (flags & STORE_SHIFT) {
+ in_fmt = is_yuv(output->format) ? PXP_PIX_FMT_YUV444 :
+ PXP_PIX_FMT_ARGB32;
+ out_fmt = (flags & STORE_SHRINK) ? PXP_PIX_FMT_YVU444 :
+ output->format;
+ d_shift = pxp_store_d_shift_calc(in_fmt, out_fmt, d_mask);
+ shift_ctrl = pxp_store_shift_ctrl_config(output, 0);
+ } else
+ shift_ctrl = pxp_store_shift_ctrl_config(output, 0);
+
+ if (flags & STORE_SHIFT) {
+ pxp_writel((uint32_t)d_shift, HW_PXP_INPUT_STORE_D_SHIFT_L_CH0);
+ /* TODO use only 4 masks */
+ pxp_writel(d_mask[0].d_mask_l, HW_PXP_INPUT_STORE_D_MASK0_L_CH0);
+ pxp_writel(d_mask[0].d_mask_h, HW_PXP_INPUT_STORE_D_MASK0_H_CH0);
+ pxp_writel(d_mask[1].d_mask_l, HW_PXP_INPUT_STORE_D_MASK1_L_CH0);
+ pxp_writel(d_mask[1].d_mask_h, HW_PXP_INPUT_STORE_D_MASK1_H_CH0);
+ pxp_writel(d_mask[2].d_mask_l, HW_PXP_INPUT_STORE_D_MASK2_L_CH0);
+ pxp_writel(d_mask[2].d_mask_h, HW_PXP_INPUT_STORE_D_MASK2_H_CH0);
+ pxp_writel(d_mask[3].d_mask_l, HW_PXP_INPUT_STORE_D_MASK3_L_CH0);
+ pxp_writel(d_mask[3].d_mask_h, HW_PXP_INPUT_STORE_D_MASK3_H_CH0);
+ }
+ } else
+ shift_ctrl = pxp_store_shift_ctrl_config(output, 1);
+
+ pxp_writel(shift_ctrl, HW_PXP_INPUT_STORE_SHIFT_CTRL_CH0);
+ pxp_writel(store_size, HW_PXP_INPUT_STORE_SIZE_CH0);
+ pxp_writel(store_pitch, HW_PXP_INPUT_STORE_PITCH);
+ if (op->fill_en) {
+ uint32_t lrc;
+
+ lrc = (output->width - 1) | ((output->height - 1) << 16);
+ pxp_writel(op->fill_data, HW_PXP_INPUT_STORE_FILL_DATA_CH0);
+
+ pxp_writel(0x1, HW_PXP_INPUT_FETCH_CTRL_CH0);
+ pxp_writel(0, HW_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH0);
+ pxp_writel(lrc, HW_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH0);
+ }
+
+ offset = output->crop.y * output->pitch +
+ output->crop.x * (output->bpp >> 3);
+ if (is_yuv(output->format == 2)) {
+ UV = output->paddr + output->width * output->height;
+ pxp_writel(UV + offset, HW_PXP_INPUT_STORE_ADDR_1_CH0);
+ }
+ pxp_writel(output->paddr + offset, HW_PXP_INPUT_STORE_ADDR_0_CH0);
+
+ pxp_writel(BF_PXP_CTRL_ENABLE_INPUT_FETCH_STORE(1), HW_PXP_CTRL_SET);
+
+ return 0;
+}
+
+static int pxp_alpha_config(struct pxp_op_info *op,
+ uint8_t alpha_node)
+{
+ uint32_t as_ctrl;
+ struct pxp_alpha_ctrl alpha_ctrl;
+ struct pxp_alpha_info *alpha = &op->alpha_info;
+ struct pxp_alpha *s0_alpha, *s1_alpha;
+
+ memset((void*)&alpha_ctrl, 0x0, sizeof(alpha_ctrl));
+
+ if (alpha_blending_version != PXP_ALPHA_BLENDING_V1) {
+ if (alpha->alpha_mode == ALPHA_MODE_ROP) {
+ switch (alpha_node) {
+ case PXP_2D_ALPHA0_S0:
+ as_ctrl = __raw_readl(pxp_reg_base + HW_PXP_AS_CTRL);
+ as_ctrl |= BF_PXP_AS_CTRL_ALPHA_CTRL(BV_PXP_AS_CTRL_ALPHA_CTRL__ROPs);
+ as_ctrl |= BF_PXP_AS_CTRL_ROP(alpha->rop_type);
+ pxp_writel(as_ctrl, HW_PXP_AS_CTRL);
+ break;
+ case PXP_2D_ALPHA1_S0:
+ pxp_writel(BM_PXP_ALPHA_B_CTRL_1_ROP_ENABLE |
+ BF_PXP_ALPHA_B_CTRL_1_ROP(alpha->rop_type),
+ HW_PXP_ALPHA_B_CTRL_1);
+ pxp_writel(BF_PXP_CTRL_ENABLE_ALPHA_B(1), HW_PXP_CTRL_SET);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+ }
+
+ s0_alpha = &alpha->s0_alpha;
+ s1_alpha = &alpha->s1_alpha;
+
+ alpha_ctrl.poter_duff_enable = 1;
+
+ alpha_ctrl.s0_s1_factor_mode = s1_alpha->factor_mode;
+ alpha_ctrl.s0_global_alpha_mode = s0_alpha->global_alpha_mode;
+ alpha_ctrl.s0_alpha_mode = s0_alpha->alpha_mode;
+ alpha_ctrl.s0_color_mode = s0_alpha->color_mode;
+
+ alpha_ctrl.s1_s0_factor_mode = s0_alpha->factor_mode;
+ alpha_ctrl.s1_global_alpha_mode = s1_alpha->global_alpha_mode;
+ alpha_ctrl.s1_alpha_mode = s1_alpha->alpha_mode;
+ alpha_ctrl.s1_color_mode = s1_alpha->color_mode;
+
+ alpha_ctrl.s0_global_alpha = s0_alpha->global_alpha_value;
+ alpha_ctrl.s1_global_alpha = s1_alpha->global_alpha_value;
+
+ switch (alpha_node) {
+ case PXP_2D_ALPHA0_S0:
+ pxp_writel(*(uint32_t *)&alpha_ctrl, HW_PXP_ALPHA_A_CTRL);
+ break;
+ case PXP_2D_ALPHA1_S0:
+ pxp_writel(*(uint32_t *)&alpha_ctrl, HW_PXP_ALPHA_B_CTRL);
+ pxp_writel(BF_PXP_CTRL_ENABLE_ALPHA_B(1), HW_PXP_CTRL_SET);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void pxp_lut_config(struct pxp_op_info *op)
+{
+ struct pxp_task_info *task = to_pxp_task_info(op);
+ struct pxps *pxp = to_pxp_from_task(task);
+ struct pxp_proc_data *proc_data = &pxp->pxp_conf_state.proc_data;
+ int lut_op = proc_data->lut_transform;
+ u32 reg_val;
+ int i;
+ bool use_cmap = (lut_op & PXP_LUT_USE_CMAP) ? true : false;
+ u8 *cmap = proc_data->lut_map;
+ u32 entry_src;
+ u32 pix_val;
+ u8 entry[4];
+
+ /*
+ * If LUT already configured as needed, return...
+ * Unless CMAP is needed and it has been updated.
+ */
+ if ((pxp->lut_state == lut_op) &&
+ !(use_cmap && proc_data->lut_map_updated))
+ return;
+
+ if (lut_op == PXP_LUT_NONE) {
+ __raw_writel(BM_PXP_LUT_CTRL_BYPASS,
+ pxp->base + HW_PXP_LUT_CTRL);
+ } else if (((lut_op & PXP_LUT_INVERT) != 0)
+ && ((lut_op & PXP_LUT_BLACK_WHITE) != 0)) {
+ /* Fill out LUT table with inverted monochromized values */
+
+ /* clear bypass bit, set lookup mode & out mode */
+ __raw_writel(BF_PXP_LUT_CTRL_LOOKUP_MODE
+ (BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8) |
+ BF_PXP_LUT_CTRL_OUT_MODE
+ (BV_PXP_LUT_CTRL_OUT_MODE__Y8),
+ pxp->base + HW_PXP_LUT_CTRL);
+
+ /* Initialize LUT address to 0 and set NUM_BYTES to 0 */
+ __raw_writel(0, pxp->base + HW_PXP_LUT_ADDR);
+
+ /* LUT address pointer auto-increments after each data write */
+ for (pix_val = 0; pix_val < 256; pix_val += 4) {
+ for (i = 0; i < 4; i++) {
+ entry_src = use_cmap ?
+ cmap[pix_val + i] : pix_val + i;
+ entry[i] = (entry_src < 0x80) ? 0xFF : 0x00;
+ }
+ reg_val = (entry[3] << 24) | (entry[2] << 16) |
+ (entry[1] << 8) | entry[0];
+ __raw_writel(reg_val, pxp->base + HW_PXP_LUT_DATA);
+ }
+ } else if ((lut_op & PXP_LUT_INVERT) != 0) {
+ /* Fill out LUT table with 8-bit inverted values */
+
+ /* clear bypass bit, set lookup mode & out mode */
+ __raw_writel(BF_PXP_LUT_CTRL_LOOKUP_MODE
+ (BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8) |
+ BF_PXP_LUT_CTRL_OUT_MODE
+ (BV_PXP_LUT_CTRL_OUT_MODE__Y8),
+ pxp->base + HW_PXP_LUT_CTRL);
+
+ /* Initialize LUT address to 0 and set NUM_BYTES to 0 */
+ __raw_writel(0, pxp->base + HW_PXP_LUT_ADDR);
+
+ /* LUT address pointer auto-increments after each data write */
+ for (pix_val = 0; pix_val < 256; pix_val += 4) {
+ for (i = 0; i < 4; i++) {
+ entry_src = use_cmap ?
+ cmap[pix_val + i] : pix_val + i;
+ entry[i] = ~entry_src & 0xFF;
+ }
+ reg_val = (entry[3] << 24) | (entry[2] << 16) |
+ (entry[1] << 8) | entry[0];
+ __raw_writel(reg_val, pxp->base + HW_PXP_LUT_DATA);
+ }
+ } else if ((lut_op & PXP_LUT_BLACK_WHITE) != 0) {
+ /* Fill out LUT table with 8-bit monochromized values */
+
+ /* clear bypass bit, set lookup mode & out mode */
+ __raw_writel(BF_PXP_LUT_CTRL_LOOKUP_MODE
+ (BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8) |
+ BF_PXP_LUT_CTRL_OUT_MODE
+ (BV_PXP_LUT_CTRL_OUT_MODE__Y8),
+ pxp->base + HW_PXP_LUT_CTRL);
+
+ /* Initialize LUT address to 0 and set NUM_BYTES to 0 */
+ __raw_writel(0, pxp->base + HW_PXP_LUT_ADDR);
+
+ /* LUT address pointer auto-increments after each data write */
+ for (pix_val = 0; pix_val < 256; pix_val += 4) {
+ for (i = 0; i < 4; i++) {
+ entry_src = use_cmap ?
+ cmap[pix_val + i] : pix_val + i;
+ entry[i] = (entry_src < 0x80) ? 0x00 : 0xFF;
+ }
+ reg_val = (entry[3] << 24) | (entry[2] << 16) |
+ (entry[1] << 8) | entry[0];
+ __raw_writel(reg_val, pxp->base + HW_PXP_LUT_DATA);
+ }
+ } else if (use_cmap) {
+ /* Fill out LUT table using colormap values */
+
+ /* clear bypass bit, set lookup mode & out mode */
+ __raw_writel(BF_PXP_LUT_CTRL_LOOKUP_MODE
+ (BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8) |
+ BF_PXP_LUT_CTRL_OUT_MODE
+ (BV_PXP_LUT_CTRL_OUT_MODE__Y8),
+ pxp->base + HW_PXP_LUT_CTRL);
+
+ /* Initialize LUT address to 0 and set NUM_BYTES to 0 */
+ __raw_writel(0, pxp->base + HW_PXP_LUT_ADDR);
+
+ /* LUT address pointer auto-increments after each data write */
+ for (pix_val = 0; pix_val < 256; pix_val += 4) {
+ for (i = 0; i < 4; i++)
+ entry[i] = cmap[pix_val + i];
+ reg_val = (entry[3] << 24) | (entry[2] << 16) |
+ (entry[1] << 8) | entry[0];
+ __raw_writel(reg_val, pxp->base + HW_PXP_LUT_DATA);
+ }
+ }
+
+ pxp_writel(BM_PXP_CTRL_ENABLE_ROTATE1 | BM_PXP_CTRL_ENABLE_ROTATE0 |
+ BM_PXP_CTRL_ENABLE_CSC2 | BM_PXP_CTRL_ENABLE_LUT,
+ HW_PXP_CTRL_SET);
+
+ pxp->lut_state = lut_op;
+}
+
+static int pxp_2d_task_config(struct pxp_pixmap *input,
+ struct pxp_pixmap *output,
+ struct pxp_op_info *op,
+ uint32_t nodes_used)
+{
+ uint8_t position = 0;
+
+ do {
+ position = find_next_bit((unsigned long *)&nodes_used, 32, position);
+ if (position >= sizeof(uint32_t) * 8)
+ break;
+
+ switch (position) {
+ case PXP_2D_PS:
+ pxp_ps_config(input, output);
+ break;
+ case PXP_2D_AS:
+ pxp_as_config(input, output);
+ break;
+ case PXP_2D_INPUT_FETCH0:
+ case PXP_2D_INPUT_FETCH1:
+ pxp_fetch_config(input, position);
+ break;
+ case PXP_2D_CSC1:
+ pxp_csc1_config(input, true);
+ break;
+ case PXP_2D_ROTATION1:
+ pxp_rotation1_config(input);
+ break;
+ case PXP_2D_ALPHA0_S0:
+ case PXP_2D_ALPHA1_S0:
+ pxp_alpha_config(op, position);
+ break;
+ case PXP_2D_ALPHA0_S1:
+ case PXP_2D_ALPHA1_S1:
+ break;
+ case PXP_2D_CSC2:
+ pxp_csc2_config(output);
+ break;
+ case PXP_2D_LUT:
+ pxp_lut_config(op);
+ break;
+ case PXP_2D_ROTATION0:
+ pxp_rotation0_config(input);
+ break;
+ case PXP_2D_OUT:
+ pxp_out_config(output);
+ break;
+ case PXP_2D_INPUT_STORE0:
+ case PXP_2D_INPUT_STORE1:
+ pxp_store_config(output, op);
+ break;
+ default:
+ break;
+ }
+
+ position++;
+ } while (1);
+
+ return 0;
+}
+
+static void mux_config_helper(struct mux_config *path_ctrl,
+ struct edge_node *enode)
+{
+ uint32_t mux_val, mux_pos = 0;
+
+ if (enode->mux_used) {
+ do {
+ mux_pos = find_next_bit((unsigned long *)&enode->mux_used,
+ 32, mux_pos);
+ if (mux_pos >= 16)
+ break;
+
+ mux_val = get_mux_val(&enode->muxes, mux_pos);
+ pr_debug("%s: mux_pos = %d, mux_val = %d\n",
+ __func__, mux_pos, mux_val);
+ set_mux_val(path_ctrl, mux_pos, mux_val);
+
+ mux_pos++;
+ } while (1);
+ }
+}
+
+static void pxp_2d_calc_mux(uint32_t nodes, struct mux_config *path_ctrl)
+{
+ struct edge_node *enode;
+ uint8_t from = 0, to = 0;
+
+ do {
+ from = find_next_bit((unsigned long *)&nodes, 32, from);
+ if (from >= sizeof(uint32_t) * 8)
+ break;
+
+ if (to != 0) {
+ enode = adj_list[to].first;
+ while (enode) {
+ if (enode->adjvex == from) {
+ mux_config_helper(path_ctrl, enode);
+ break;
+ }
+ enode = enode->next;
+ }
+ }
+
+ to = find_next_bit((unsigned long *)&nodes, 32, from + 1);
+ if (to >= sizeof(uint32_t) * 8)
+ break;
+
+ enode = adj_list[from].first;
+ while (enode) {
+ if (enode->adjvex == to) {
+ mux_config_helper(path_ctrl, enode);
+ break;
+ }
+ enode = enode->next;
+ }
+
+ from = to + 1;
+ } while (1);
+}
+
+static int pxp_2d_op_handler(struct pxps *pxp)
+{
+ struct mux_config path_ctrl0;
+ struct pxp_proc_data *proc_data = &pxp->pxp_conf_state.proc_data;
+ struct pxp_task_info *task = &pxp->task;
+ struct pxp_op_info *op = &task->op_info;
+ struct pxp_pixmap *input, *output, *input_s0, *input_s1;
+ uint32_t possible_inputs, possible_outputs;
+ uint32_t possible_inputs_s0, possible_inputs_s1;
+ uint32_t inputs_filter_s0, inputs_filter_s1;
+ uint32_t nodes_used = 0, nodes_in_path;
+ uint32_t partial_nodes_used = 0;
+ uint32_t nodes_used_s0 = 0, nodes_used_s1 = 0;
+ uint32_t nodes_in_path_s0, nodes_in_path_s1;
+ uint32_t val;
+
+ output = &task->output[0];
+ if (!output->pitch)
+ return -EINVAL;
+
+ *(unsigned int*)&path_ctrl0 = 0xffffffff;
+
+reparse:
+ switch (task->input_num) {
+ case 0:
+ /* Fill operation: use input store engine */
+ if (is_yuv(output->format) > 1)
+ return -EINVAL;
+
+ if (output->bpp > 32)
+ return -EINVAL;
+
+ nodes_used = 1 << PXP_2D_INPUT_STORE0;
+ pxp_2d_task_config(NULL, output, op, nodes_used);
+ break;
+ case 1:
+ /* No Composite */
+ possible_inputs = (1 << PXP_2D_PS) |
+ (1 << PXP_2D_AS) |
+ (1 << PXP_2D_INPUT_FETCH0);
+ possible_outputs = (1 << PXP_2D_OUT) |
+ (1 << PXP_2D_INPUT_STORE0);
+
+ input = &task->input[0];
+ if (!input->pitch)
+ return -EINVAL;
+
+ if (input->rotate || input->flip) {
+ input->flags |= IN_NEED_ROTATE_FLIP;
+ output->rotate = input->rotate;
+ output->flip = input->flip;
+ }
+
+ if (!is_yuv(input->format) != !is_yuv(output->format))
+ input->flags |= IN_NEED_CSC;
+ else if (input->format != output->format)
+ input->flags |= IN_NEED_FMT_UNIFIED;
+
+ if ((input->rotate == 90) || (input->rotate == 270)) {
+ if ((input->crop.width != output->crop.height) ||
+ (input->crop.height != output->crop.width))
+ input->flags |= IN_NEED_SCALE;
+ } else {
+ if ((input->crop.width != output->crop.width) ||
+ (input->crop.height != output->crop.height))
+ input->flags |= IN_NEED_SCALE;
+ }
+
+ if (input->flags) {
+ /* only ps has scaling function */
+ if ((input->flags & IN_NEED_SCALE) == IN_NEED_SCALE)
+ possible_inputs = 1 << PXP_2D_PS;
+ output->flags |= (output->bpp < 32) ? OUT_NEED_SHRINK :
+ OUT_NEED_SHIFT;
+ }
+
+ filter_possible_inputs(input, &possible_inputs);
+ filter_possible_outputs(output, &possible_outputs);
+
+ if (!possible_inputs || !possible_outputs) {
+ dev_err(&pxp->pdev->dev, "unsupport 2d operation\n");
+ return -EINVAL;
+ }
+
+ if (proc_data->lut_transform)
+ nodes_used |= (1 << PXP_2D_LUT);
+
+ nodes_in_path = find_best_path(possible_inputs,
+ possible_outputs,
+ input, &nodes_used);
+
+ if (nodes_in_path & (1 << PXP_2D_ROTATION1)) {
+ clear_bit(PXP_2D_ROTATION1, (unsigned long *)&nodes_in_path);
+ set_bit(PXP_2D_ROTATION0, (unsigned long *)&nodes_in_path);
+ }
+
+ if (nodes_used & (1 << PXP_2D_ROTATION1)) {
+ clear_bit(PXP_2D_ROTATION1, (unsigned long *)&nodes_used);
+ set_bit(PXP_2D_ROTATION0, (unsigned long *)&nodes_used);
+ }
+
+ pr_debug("%s: nodes_in_path = 0x%x, nodes_used = 0x%x\n",
+ __func__, nodes_in_path, nodes_used);
+ if (!nodes_used) {
+ dev_err(&pxp->pdev->dev, "unsupport 2d operation\n");
+ return -EINVAL;
+ }
+
+ /* If use input fetch0, should use
+ * alpha b instead of alpha a */
+ if (nodes_in_path & (1 << PXP_2D_ALPHA0_S0)) {
+ if (nodes_in_path & (1 << PXP_2D_INPUT_FETCH0)) {
+ clear_bit(PXP_2D_ALPHA0_S0,
+ (unsigned long *)&nodes_in_path);
+ set_bit(PXP_2D_ALPHA1_S1,
+ (unsigned long *)&nodes_in_path);
+ }
+ }
+
+ /* In this case input read in
+ * by input fetch engine
+ */
+ if ((nodes_in_path & (1 << PXP_2D_ALPHA1_S1)) ||
+ (nodes_in_path & (1 << PXP_2D_ALPHA1_S0))) {
+ memcpy(&task->input[1], input, sizeof(*input));
+ if (input->rotate == 90 || input->rotate == 270) {
+ uint32_t temp;
+
+ input = &task->input[1];
+ input->rotate = 0;
+ input->flags = 0;
+ temp = input->width;
+ input->width = input->height;
+ input->height = temp;
+ input->pitch = input->width * (input->bpp >> 3);
+ temp = input->crop.width;
+ input->crop.width = input->crop.height;
+ input->crop.height = temp;
+ }
+
+ op->alpha_info.alpha_mode = ALPHA_MODE_ROP;
+ /* s0 AND s1 */
+ op->alpha_info.rop_type = 0x0;
+ task->input_num = 2;
+ goto reparse;
+ }
+
+ pxp_2d_calc_mux(nodes_in_path, &path_ctrl0);
+ pr_debug("%s: path_ctrl0 = 0x%x\n",
+ __func__, *(uint32_t *)&path_ctrl0);
+ pxp_2d_task_config(input, output, op, nodes_used);
+
+ if (is_yuv(input->format) && is_yuv(output->format)) {
+ val = readl(pxp_reg_base + HW_PXP_CSC1_COEF0);
+ val |= (BF_PXP_CSC1_COEF0_YCBCR_MODE(1) |
+ BF_PXP_CSC1_COEF0_BYPASS(1));
+ pxp_writel(val, HW_PXP_CSC1_COEF0);
+ }
+ break;
+ case 2:
+ /* Composite */
+ input_s0 = &task->input[0];
+ input_s1 = &task->input[1];
+ if (!input_s0->pitch || !input_s1->pitch)
+ return -EINVAL;
+
+ possible_inputs_s0 = (1 << PXP_2D_PS) |
+ (1 << PXP_2D_INPUT_FETCH0) |
+ (1 << PXP_2D_INPUT_FETCH1);
+ possible_inputs_s1 = (1 << PXP_2D_AS) |
+ (1 << PXP_2D_INPUT_FETCH0);
+ possible_outputs = (1 << PXP_2D_OUT) |
+ (1 << PXP_2D_INPUT_STORE0);
+
+ if (input_s0->rotate || input_s0->flip) {
+ input_s0->flags |= IN_NEED_ROTATE_FLIP;
+ output->rotate = input_s0->rotate;
+ output->flip = input_s0->flip;
+ }
+ if (input_s1->rotate || input_s1->flip) {
+ input_s1->flags |= IN_NEED_ROTATE_FLIP;
+ clear_bit(PXP_2D_AS,
+ (unsigned long *)&possible_inputs_s1);
+ }
+
+ if (is_yuv(input_s0->format) && is_yuv(input_s1->format))
+ return -EINVAL;
+
+ if (is_yuv(input_s0->format)){
+ /* need do yuv -> rgb conversion by csc1 */
+ possible_inputs_s0 = 1 << PXP_2D_PS;
+ input_s0->flags |= IN_NEED_CSC;
+ } else if (is_yuv(input_s1->format)) {
+ possible_inputs_s1 = 1 << PXP_2D_PS;
+ input_s1->flags |= IN_NEED_CSC;
+ }
+
+ filter_possible_inputs(input_s0, &possible_inputs_s0);
+ filter_possible_inputs(input_s1, &possible_inputs_s1);
+
+ if (!possible_inputs_s0 || !possible_inputs_s0)
+ return -EINVAL;
+
+ filter_possible_outputs(output, &possible_outputs);
+ if (!possible_outputs)
+ return -EINVAL;
+
+ pr_debug("%s: poss_s0 = 0x%x, poss_s1 = 0x%x, poss_out = 0x%x\n",
+ __func__, possible_inputs_s0, possible_inputs_s1, possible_outputs);
+
+ inputs_filter_s0 = possible_inputs_s0;
+ inputs_filter_s1 = possible_inputs_s1;
+
+ /* Using alpha0, possible cases:
+ * 1. PS --> S0, AS --> S1;
+ */
+ if (possible_inputs_s1 & (1 << PXP_2D_AS)) {
+ clear_bit(PXP_2D_INPUT_FETCH0,
+ (unsigned long *)&possible_inputs_s0);
+ clear_bit(PXP_2D_INPUT_FETCH1,
+ (unsigned long *)&possible_inputs_s0);
+ clear_bit(PXP_2D_INPUT_STORE0,
+ (unsigned long *)&possible_outputs);
+
+ if (!possible_inputs_s0 || !possible_outputs)
+ goto alpha1;
+
+ nodes_in_path_s0 = find_best_path(possible_inputs_s0,
+ 1 << PXP_2D_ALPHA0_S0,
+ input_s0,
+ &partial_nodes_used);
+ if (!nodes_in_path_s0)
+ goto alpha1;
+
+ nodes_used_s0 |= partial_nodes_used;
+ partial_nodes_used = 0;
+
+ if (is_yuv(output->format))
+ set_bit(PXP_2D_CSC2,
+ (unsigned long *)&partial_nodes_used);
+ if (output->rotate || output->flip)
+ set_bit(PXP_2D_ROTATION0,
+ (unsigned long *)&partial_nodes_used);
+
+ nodes_in_path_s0 |= find_best_path(1 << PXP_2D_ALPHA0_S0,
+ possible_outputs,
+ input_s0,
+ &partial_nodes_used);
+ if (!(nodes_in_path_s0 & possible_outputs))
+ goto alpha1;
+ nodes_used_s0 |= partial_nodes_used;
+
+ possible_inputs_s1 = (1 << PXP_2D_AS);
+ nodes_in_path_s1 = find_best_path(possible_inputs_s1,
+ 1 << PXP_2D_ALPHA0_S1,
+ input_s1,
+ &nodes_used_s1);
+ if (!nodes_in_path_s1)
+ goto alpha1;
+
+ goto config;
+ }
+alpha1:
+ partial_nodes_used = 0;
+ possible_inputs_s0 = inputs_filter_s0;
+ possible_inputs_s1 = inputs_filter_s1;
+
+ /* Using alpha1, possible cases:
+ * 1. FETCH1 --> S0, FETCH0 --> S1;
+ */
+ clear_bit(PXP_2D_PS,
+ (unsigned long *)&possible_inputs_s0);
+ clear_bit(PXP_2D_INPUT_FETCH0,
+ (unsigned long *)&possible_inputs_s0);
+ clear_bit(PXP_2D_OUT,
+ (unsigned long *)&possible_outputs);
+
+ if (!possible_inputs_s0 || !possible_outputs)
+ return -EINVAL;
+
+ nodes_in_path_s0 = find_best_path(possible_inputs_s0,
+ 1 << PXP_2D_ALPHA1_S0,
+ input_s0,
+ &partial_nodes_used);
+ pr_debug("%s: nodes_in_path_s0 = 0x%x\n", __func__, nodes_in_path_s0);
+ BUG_ON(!nodes_in_path_s0);
+
+ nodes_used_s0 |= partial_nodes_used;
+ if ((nodes_used_s0 & (1 << PXP_2D_INPUT_FETCH0)) ||
+ (nodes_used_s0 & (1 << PXP_2D_INPUT_FETCH1)))
+ clear_bit(PXP_2D_OUT, (unsigned long *)&possible_outputs);
+ else
+ clear_bit(PXP_2D_INPUT_STORE0,
+ (unsigned long *)&possible_outputs);
+ partial_nodes_used = 0;
+
+ if (is_yuv(output->format))
+ set_bit(PXP_2D_CSC2,
+ (unsigned long *)&partial_nodes_used);
+ if (output->rotate || output->flip)
+ set_bit(PXP_2D_ROTATION0,
+ (unsigned long *)&partial_nodes_used);
+
+ nodes_in_path_s0 |= find_best_path(1 << PXP_2D_ALPHA1_S0,
+ possible_outputs,
+ input_s0,
+ &partial_nodes_used);
+ BUG_ON(!(nodes_in_path_s0 & possible_outputs));
+ nodes_used_s0 |= partial_nodes_used;
+ pr_debug("%s: nodes_in_path_s0 = 0x%x, nodes_used_s0 = 0x%x\n",
+ __func__, nodes_in_path_s0, nodes_used_s0);
+
+ clear_bit(PXP_2D_AS,
+ (unsigned long *)&possible_inputs_s1);
+ BUG_ON(!possible_inputs_s1);
+
+ nodes_in_path_s1 = find_best_path(possible_inputs_s1,
+ 1 << PXP_2D_ALPHA1_S1,
+ input_s1,
+ &nodes_used_s1);
+ pr_debug("%s: poss_s1 = 0x%x, nodes_used_s1 = 0x%x\n",
+ __func__, possible_inputs_s1, nodes_used_s1);
+ BUG_ON(!nodes_in_path_s1);
+ /* To workaround an IC bug */
+ path_ctrl0.mux4_sel = 0x0;
+config:
+ if (nodes_in_path_s0 & (1 << PXP_2D_ROTATION1)) {
+ clear_bit(PXP_2D_ROTATION1, (unsigned long *)&nodes_in_path_s0);
+ set_bit(PXP_2D_ROTATION0, (unsigned long *)&nodes_in_path_s0);
+ }
+
+ pr_debug("%s: nodes_in_path_s0 = 0x%x, nodes_used_s0 = 0x%x, nodes_in_path_s1 = 0x%x, nodes_used_s1 = 0x%x\n",
+ __func__, nodes_in_path_s0, nodes_used_s0, nodes_in_path_s1, nodes_used_s1);
+ pxp_2d_calc_mux(nodes_in_path_s0, &path_ctrl0);
+ pxp_2d_calc_mux(nodes_in_path_s1, &path_ctrl0);
+
+ pr_debug("%s: s0 paddr = 0x%x, s1 paddr = 0x%x, out paddr = 0x%x\n",
+ __func__, input_s0->paddr, input_s1->paddr, output->paddr);
+
+ if (nodes_used_s0 & (1 << PXP_2D_ROTATION1)) {
+ clear_bit(PXP_2D_ROTATION1, (unsigned long *)&nodes_used_s0);
+ set_bit(PXP_2D_ROTATION0, (unsigned long *)&nodes_used_s0);
+ }
+
+ pxp_2d_task_config(input_s0, output, op, nodes_used_s0);
+ pxp_2d_task_config(input_s1, output, op, nodes_used_s1);
+ break;
+ default:
+ break;
+ }
+
+ __raw_writel(proc_data->bgcolor,
+ pxp->base + HW_PXP_PS_BACKGROUND_0);
+ pxp_set_colorkey(pxp);
+
+ if (proc_data->lut_transform && pxp_is_v3(pxp))
+ set_mux(&path_ctrl0);
+
+ pr_debug("%s: path_ctrl0 = 0x%x\n",
+ __func__, *(uint32_t *)&path_ctrl0);
+ pxp_writel(*(uint32_t *)&path_ctrl0, HW_PXP_DATA_PATH_CTRL0);
+
+ return 0;
+}
+
+/**
+ * pxp_config() - configure PxP for a processing task
+ * @pxps: PXP context.
+ * @pxp_chan: PXP channel.
+ * @return: 0 on success or negative error code on failure.
+ */
+static int pxp_config(struct pxps *pxp, struct pxp_channel *pxp_chan)
+{
+ int ret = 0;
+ struct pxp_task_info *task = &pxp->task;
+ struct pxp_op_info *op = &task->op_info;
+ struct pxp_config_data *pxp_conf_data = &pxp->pxp_conf_state;
+ struct pxp_proc_data *proc_data = &pxp_conf_data->proc_data;
+
+ switch (op->op_type) {
+ case PXP_OP_TYPE_2D:
+ pxp_writel(0xffffffff, HW_PXP_OUT_AS_ULC);
+ pxp_writel(0x0, HW_PXP_OUT_AS_LRC);
+ pxp_writel(0xffffffff, HW_PXP_OUT_PS_ULC);
+ pxp_writel(0x0, HW_PXP_OUT_PS_LRC);
+ pxp_writel(0x0, HW_PXP_INPUT_FETCH_PITCH);
+ pxp_writel(0x40000000, HW_PXP_CSC1_COEF0);
+ ret = pxp_2d_op_handler(pxp);
+ break;
+ case PXP_OP_TYPE_DITHER:
+ pxp_dithering_process(pxp);
+ if (pxp_is_v3p(pxp)) {
+ __raw_writel(
+ BM_PXP_CTRL_ENABLE |
+ BM_PXP_CTRL_ENABLE_DITHER |
+ BM_PXP_CTRL_ENABLE_CSC2 |
+ BM_PXP_CTRL_ENABLE_LUT |
+ BM_PXP_CTRL_ENABLE_ROTATE0 |
+ BM_PXP_CTRL_ENABLE_PS_AS_OUT,
+ pxp->base + HW_PXP_CTRL_SET);
+ return 0;
+ }
+ break;
+ case PXP_OP_TYPE_WFE_A:
+ pxp_luts_deactivate(pxp, proc_data->lut_sels);
+
+ if (proc_data->lut_cleanup == 0) {
+ /* We should enable histogram in standard mode
+ * in wfe_a processing for waveform mode selection
+ */
+ pxp_histogram_enable(pxp, pxp_conf_data->wfe_a_fetch_param[0].width,
+ pxp_conf_data->wfe_a_fetch_param[0].height);
+
+ pxp_luts_activate(pxp, (u64)proc_data->lut_status_1 |
+ ((u64)proc_data->lut_status_2 << 32));
+
+ /* collision detection should be always enable in standard mode */
+ pxp_collision_detection_enable(pxp, pxp_conf_data->wfe_a_fetch_param[0].width,
+ pxp_conf_data->wfe_a_fetch_param[0].height);
+ }
+
+ if (pxp->devdata && pxp->devdata->pxp_wfe_a_configure)
+ pxp->devdata->pxp_wfe_a_configure(pxp);
+ if (pxp->devdata && pxp->devdata->pxp_wfe_a_process)
+ pxp->devdata->pxp_wfe_a_process(pxp);
+ break;
+ case PXP_OP_TYPE_WFE_B:
+ pxp_wfe_b_configure(pxp);
+ pxp_wfe_b_process(pxp);
+ break;
+ default:
+ /* Unsupport */
+ ret = -EINVAL;
+ pr_err("Invalid pxp operation type passed\n");
+ break;
+ }
+
+ return ret;
+}
+
+static void pxp_clk_enable(struct pxps *pxp)
+{
+ mutex_lock(&pxp->clk_mutex);
+
+ if (pxp->clk_stat == CLK_STAT_ON) {
+ mutex_unlock(&pxp->clk_mutex);
+ return;
+ }
+
+ pm_runtime_get_sync(pxp->dev);
+
+ clk_prepare_enable(pxp->ipg_clk);
+ clk_prepare_enable(pxp->axi_clk);
+ pxp->clk_stat = CLK_STAT_ON;
+
+ mutex_unlock(&pxp->clk_mutex);
+}
+
+static void pxp_clk_disable(struct pxps *pxp)
+{
+ unsigned long flags;
+
+ mutex_lock(&pxp->clk_mutex);
+
+ if (pxp->clk_stat == CLK_STAT_OFF) {
+ mutex_unlock(&pxp->clk_mutex);
+ return;
+ }
+
+ spin_lock_irqsave(&pxp->lock, flags);
+ if ((pxp->pxp_ongoing == 0) && list_empty(&head)) {
+ spin_unlock_irqrestore(&pxp->lock, flags);
+ clk_disable_unprepare(pxp->ipg_clk);
+ clk_disable_unprepare(pxp->axi_clk);
+ pxp->clk_stat = CLK_STAT_OFF;
+ } else
+ spin_unlock_irqrestore(&pxp->lock, flags);
+
+ pm_runtime_put_sync_suspend(pxp->dev);
+
+ mutex_unlock(&pxp->clk_mutex);
+}
+
+static inline void clkoff_callback(struct work_struct *w)
+{
+ struct pxps *pxp = container_of(w, struct pxps, work);
+
+ pxp_clk_disable(pxp);
+}
+
+static void pxp_clkoff_timer(unsigned long arg)
+{
+ struct pxps *pxp = (struct pxps *)arg;
+
+ if ((pxp->pxp_ongoing == 0) && list_empty(&head))
+ schedule_work(&pxp->work);
+ else
+ mod_timer(&pxp->clk_timer,
+ jiffies + msecs_to_jiffies(timeout_in_ms));
+}
+
+static struct pxp_tx_desc *pxpdma_first_queued(struct pxp_channel *pxp_chan)
+{
+ return list_entry(pxp_chan->queue.next, struct pxp_tx_desc, list);
+}
+
+static int convert_param_to_pixmap(struct pxp_pixmap *pixmap,
+ struct pxp_layer_param *param)
+{
+ if (!param->width || !param->height)
+ return -EINVAL;
+
+ pixmap->width = param->width;
+ pixmap->height = param->height;
+ pixmap->format = param->pixel_fmt;
+ pixmap->paddr = param->paddr;
+ pixmap->bpp = get_bpp_from_fmt(pixmap->format);
+
+ if (pxp_legacy) {
+ pixmap->pitch = (param->stride) ? (param->stride * pixmap->bpp >> 3) :
+ (param->width * pixmap->bpp >> 3);
+ } else {
+ if (!param->stride || (param->stride == param->width))
+ pixmap->pitch = param->width * pixmap->bpp >> 3;
+ else
+ pixmap->pitch = param->stride;
+ }
+
+ pixmap->crop.x = param->crop.left;
+ pixmap->crop.y = param->crop.top;
+ pixmap->crop.width = param->crop.width;
+ pixmap->crop.height = param->crop.height;
+
+ pixmap->g_alpha.color_key_enable = param->color_key_enable;
+ pixmap->g_alpha.combine_enable = param->combine_enable;
+ pixmap->g_alpha.global_alpha_enable = param->global_alpha_enable;
+ pixmap->g_alpha.global_override = param->global_override;
+ pixmap->g_alpha.global_alpha = param->global_alpha;
+ pixmap->g_alpha.alpha_invert = param->alpha_invert;
+ pixmap->g_alpha.local_alpha_enable = param->local_alpha_enable;
+ pixmap->g_alpha.comp_mask = param->comp_mask;
+
+ return 0;
+}
+
+/* called with pxp_chan->lock held */
+static void __pxpdma_dostart(struct pxp_channel *pxp_chan)
+{
+ struct pxp_dma *pxp_dma = to_pxp_dma(pxp_chan->dma_chan.device);
+ struct pxps *pxp = to_pxp(pxp_dma);
+ struct pxp_config_data *config_data = &pxp->pxp_conf_state;
+ struct pxp_proc_data *proc_data = &config_data->proc_data;
+ struct pxp_tx_desc *desc;
+ struct pxp_tx_desc *child;
+ struct pxp_task_info *task = &pxp->task;
+ struct pxp_op_info *op = &task->op_info;
+ struct pxp_alpha_info *alpha = &op->alpha_info;
+ struct pxp_layer_param *param = NULL;
+ struct pxp_pixmap *input, *output;
+ int i = 0, ret;
+ bool combine_enable = false;
+
+ memset(&pxp->pxp_conf_state.s0_param, 0, sizeof(struct pxp_layer_param));
+ memset(&pxp->pxp_conf_state.out_param, 0, sizeof(struct pxp_layer_param));
+ memset(pxp->pxp_conf_state.ol_param, 0, sizeof(struct pxp_layer_param));
+ memset(&pxp->pxp_conf_state.proc_data, 0, sizeof(struct pxp_proc_data));
+
+ memset(task, 0, sizeof(*task));
+ /* S0 */
+ desc = list_first_entry(&head, struct pxp_tx_desc, list);
+ memcpy(&pxp->pxp_conf_state.s0_param,
+ &desc->layer_param.s0_param, sizeof(struct pxp_layer_param));
+ memcpy(&pxp->pxp_conf_state.proc_data,
+ &desc->proc_data, sizeof(struct pxp_proc_data));
+
+ if (proc_data->combine_enable)
+ alpha_blending_version = PXP_ALPHA_BLENDING_V2;
+ else
+ alpha_blending_version = PXP_ALPHA_BLENDING_NONE;
+
+ pxp_legacy = (proc_data->pxp_legacy) ? true : false;
+
+ /* Save PxP configuration */
+ list_for_each_entry(child, &desc->tx_list, list) {
+ if (i == 0) { /* Output */
+ memcpy(&pxp->pxp_conf_state.out_param,
+ &child->layer_param.out_param,
+ sizeof(struct pxp_layer_param));
+ } else if (i == 1) { /* Overlay */
+ memcpy(&pxp->pxp_conf_state.ol_param[i - 1],
+ &child->layer_param.ol_param,
+ sizeof(struct pxp_layer_param));
+ if (pxp->pxp_conf_state.ol_param[i - 1].width != 0 &&
+ pxp->pxp_conf_state.ol_param[i - 1].height != 0) {
+ if (pxp->pxp_conf_state.ol_param[i - 1].combine_enable)
+ alpha_blending_version = PXP_ALPHA_BLENDING_V1;
+ }
+ }
+
+ if (proc_data->engine_enable & PXP_ENABLE_DITHER) {
+ if (child->layer_param.processing_param.flag & PXP_BUF_FLAG_DITHER_FETCH0)
+ memcpy(&pxp->pxp_conf_state.dither_fetch_param[0],
+ &child->layer_param.processing_param,
+ sizeof(struct pxp_layer_param));
+ if (child->layer_param.processing_param.flag & PXP_BUF_FLAG_DITHER_FETCH1)
+ memcpy(&pxp->pxp_conf_state.dither_fetch_param[1],
+ &child->layer_param.processing_param,
+ sizeof(struct pxp_layer_param));
+ if (child->layer_param.processing_param.flag & PXP_BUF_FLAG_DITHER_STORE0)
+ memcpy(&pxp->pxp_conf_state.dither_store_param[0],
+ &child->layer_param.processing_param,
+ sizeof(struct pxp_layer_param));
+ if (child->layer_param.processing_param.flag & PXP_BUF_FLAG_DITHER_STORE1)
+ memcpy(&pxp->pxp_conf_state.dither_store_param[1],
+ &child->layer_param.processing_param,
+ sizeof(struct pxp_layer_param));
+ op->op_type = PXP_OP_TYPE_DITHER;
+ }
+
+ if (proc_data->engine_enable & PXP_ENABLE_WFE_A) {
+ if (child->layer_param.processing_param.flag & PXP_BUF_FLAG_WFE_A_FETCH0)
+ memcpy(&pxp->pxp_conf_state.wfe_a_fetch_param[0],
+ &child->layer_param.processing_param,
+ sizeof(struct pxp_layer_param));
+ if (child->layer_param.processing_param.flag & PXP_BUF_FLAG_WFE_A_FETCH1)
+ memcpy(&pxp->pxp_conf_state.wfe_a_fetch_param[1],
+ &child->layer_param.processing_param,
+ sizeof(struct pxp_layer_param));
+ if (child->layer_param.processing_param.flag & PXP_BUF_FLAG_WFE_A_STORE0)
+ memcpy(&pxp->pxp_conf_state.wfe_a_store_param[0],
+ &child->layer_param.processing_param,
+ sizeof(struct pxp_layer_param));
+ if (child->layer_param.processing_param.flag & PXP_BUF_FLAG_WFE_A_STORE1)
+ memcpy(&pxp->pxp_conf_state.wfe_a_store_param[1],
+ &child->layer_param.processing_param,
+ sizeof(struct pxp_layer_param));
+ op->op_type = PXP_OP_TYPE_WFE_A;
+ }
+
+ if (proc_data->engine_enable & PXP_ENABLE_WFE_B) {
+ if (child->layer_param.processing_param.flag & PXP_BUF_FLAG_WFE_B_FETCH0)
+ memcpy(&pxp->pxp_conf_state.wfe_b_fetch_param[0],
+ &child->layer_param.processing_param,
+ sizeof(struct pxp_layer_param));
+ if (child->layer_param.processing_param.flag & PXP_BUF_FLAG_WFE_B_FETCH1)
+ memcpy(&pxp->pxp_conf_state.wfe_b_fetch_param[1],
+ &child->layer_param.processing_param,
+ sizeof(struct pxp_layer_param));
+ if (child->layer_param.processing_param.flag & PXP_BUF_FLAG_WFE_B_STORE0)
+ memcpy(&pxp->pxp_conf_state.wfe_b_store_param[0],
+ &child->layer_param.processing_param,
+ sizeof(struct pxp_layer_param));
+ if (child->layer_param.processing_param.flag & PXP_BUF_FLAG_WFE_B_STORE1)
+ memcpy(&pxp->pxp_conf_state.wfe_b_store_param[1],
+ &child->layer_param.processing_param,
+ sizeof(struct pxp_layer_param));
+ op->op_type = PXP_OP_TYPE_WFE_B;
+ }
+
+ i++;
+ }
+
+ if (!op->op_type) {
+ op->op_type = PXP_OP_TYPE_2D;
+
+ if ((alpha_blending_version == PXP_ALPHA_BLENDING_V1) ||
+ (alpha_blending_version == PXP_ALPHA_BLENDING_V2))
+ combine_enable = true;
+
+ if (combine_enable)
+ task->input_num = 2;
+ else if (proc_data->fill_en)
+ task->input_num = 0;
+ else
+ task->input_num = 1;
+
+ output = &task->output[0];
+ switch (task->input_num) {
+ case 0:
+ op->fill_en = 1;
+ op->fill_data = proc_data->bgcolor;
+ break;
+ case 1:
+ param = &pxp->pxp_conf_state.s0_param;
+ input = &task->input[0];
+
+ ret = convert_param_to_pixmap(input, param);
+ if (ret < 0) {
+ param = &pxp->pxp_conf_state.ol_param[0];
+ ret = convert_param_to_pixmap(input, param);
+ BUG_ON(ret < 0);
+ } else {
+ input->crop.x = proc_data->srect.left;
+ input->crop.y = proc_data->srect.top;
+ input->crop.width = proc_data->srect.width;
+ input->crop.height = proc_data->srect.height;
+ }
+
+ input->rotate = proc_data->rotate;
+ input->flip = (proc_data->hflip) ? PXP_H_FLIP :
+ (proc_data->vflip) ? PXP_V_FLIP : 0;
+ break;
+ case 2:
+ /* s0 */
+ param = &pxp->pxp_conf_state.s0_param;
+ input = &task->input[0];
+
+ ret = convert_param_to_pixmap(input, param);
+ BUG_ON(ret < 0);
+ input->crop.x = proc_data->srect.left;
+ input->crop.y = proc_data->srect.top;
+ input->crop.width = proc_data->srect.width;
+ input->crop.height = proc_data->srect.height;
+ alpha->s0_alpha = param->alpha;
+
+ input->rotate = proc_data->rotate;
+ input->flip = (proc_data->hflip) ? PXP_H_FLIP :
+ (proc_data->vflip) ? PXP_V_FLIP : 0;
+
+ /* overlay */
+ param = &pxp->pxp_conf_state.ol_param[0];
+ input = &task->input[1];
+
+ ret = convert_param_to_pixmap(input, param);
+ BUG_ON(ret < 0);
+ alpha->s1_alpha = param->alpha;
+ alpha->alpha_mode = proc_data->alpha_mode;
+ break;
+ }
+
+ param = &pxp->pxp_conf_state.out_param;
+ ret = convert_param_to_pixmap(output, param);
+ BUG_ON(ret < 0);
+
+ output->crop.x = proc_data->drect.left;
+ output->crop.y = proc_data->drect.top;
+ output->crop.width = proc_data->drect.width;
+ output->crop.height = proc_data->drect.height;
+ }
+
+ pr_debug("%s:%d S0 w/h %d/%d paddr %08x\n", __func__, __LINE__,
+ pxp->pxp_conf_state.s0_param.width,
+ pxp->pxp_conf_state.s0_param.height,
+ pxp->pxp_conf_state.s0_param.paddr);
+ pr_debug("%s:%d S0 crop (top, left)=(%d, %d), (width, height)=(%d, %d)\n",
+ __func__, __LINE__,
+ pxp->pxp_conf_state.s0_param.crop.top,
+ pxp->pxp_conf_state.s0_param.crop.left,
+ pxp->pxp_conf_state.s0_param.crop.width,
+ pxp->pxp_conf_state.s0_param.crop.height);
+ pr_debug("%s:%d OUT w/h %d/%d paddr %08x\n", __func__, __LINE__,
+ pxp->pxp_conf_state.out_param.width,
+ pxp->pxp_conf_state.out_param.height,
+ pxp->pxp_conf_state.out_param.paddr);
+}
+
+static int pxpdma_dostart_work(struct pxps *pxp)
+{
+ int ret;
+ struct pxp_channel *pxp_chan = NULL;
+ unsigned long flags;
+ dma_async_tx_callback callback;
+ void *callback_param;
+ struct pxp_tx_desc *desc = NULL;
+ struct pxp_tx_desc *child, *_child;
+ struct pxp_config_data *config_data = &pxp->pxp_conf_state;
+ struct pxp_proc_data *proc_data = &config_data->proc_data;
+
+ spin_lock_irqsave(&pxp->lock, flags);
+
+ desc = list_entry(head.next, struct pxp_tx_desc, list);
+ pxp_chan = to_pxp_channel(desc->txd.chan);
+
+ __pxpdma_dostart(pxp_chan);
+
+ /* Configure PxP */
+ ret = pxp_config(pxp, pxp_chan);
+ if (ret) {
+ callback = desc->txd.callback;
+ callback_param = desc->txd.callback_param;
+
+ callback(callback_param);
+
+ /* Unsupport operation */
+ list_for_each_entry_safe(child, _child, &desc->tx_list, list) {
+ list_del_init(&child->list);
+ kmem_cache_free(tx_desc_cache, (void *)child);
+ }
+ list_del_init(&desc->list);
+ kmem_cache_free(tx_desc_cache, (void *)desc);
+
+ spin_unlock_irqrestore(&pxp->lock, flags);
+ return -EINVAL;
+ }
+
+ if (proc_data->working_mode & PXP_MODE_STANDARD) {
+ if(!pxp_is_v3p(pxp) || !(proc_data->engine_enable & PXP_ENABLE_DITHER))
+ pxp_start2(pxp);
+ } else
+ pxp_start(pxp);
+
+ spin_unlock_irqrestore(&pxp->lock, flags);
+
+ return 0;
+}
+
+static void pxpdma_dequeue(struct pxp_channel *pxp_chan, struct pxps *pxp)
+{
+ unsigned long flags;
+ struct pxp_tx_desc *desc = NULL;
+
+ do {
+ desc = pxpdma_first_queued(pxp_chan);
+ spin_lock_irqsave(&pxp->lock, flags);
+ list_move_tail(&desc->list, &head);
+ spin_unlock_irqrestore(&pxp->lock, flags);
+ } while (!list_empty(&pxp_chan->queue));
+}
+
+static dma_cookie_t pxp_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct pxp_tx_desc *desc = to_tx_desc(tx);
+ struct pxp_channel *pxp_chan = to_pxp_channel(tx->chan);
+ dma_cookie_t cookie;
+
+ dev_dbg(&pxp_chan->dma_chan.dev->device, "received TX\n");
+
+ /* pxp_chan->lock can be taken under ichan->lock, but not v.v. */
+ spin_lock(&pxp_chan->lock);
+
+ cookie = pxp_chan->dma_chan.cookie;
+
+ if (++cookie < 0)
+ cookie = 1;
+
+ /* from dmaengine.h: "last cookie value returned to client" */
+ pxp_chan->dma_chan.cookie = cookie;
+ tx->cookie = cookie;
+
+ /* Here we add the tx descriptor to our PxP task queue. */
+ list_add_tail(&desc->list, &pxp_chan->queue);
+
+ spin_unlock(&pxp_chan->lock);
+
+ dev_dbg(&pxp_chan->dma_chan.dev->device, "done TX\n");
+
+ return cookie;
+}
+
+/**
+ * pxp_init_channel() - initialize a PXP channel.
+ * @pxp_dma: PXP DMA context.
+ * @pchan: pointer to the channel object.
+ * @return 0 on success or negative error code on failure.
+ */
+static int pxp_init_channel(struct pxp_dma *pxp_dma,
+ struct pxp_channel *pxp_chan)
+{
+ int ret = 0;
+
+ /*
+ * We are using _virtual_ channel here.
+ * Each channel contains all parameters of corresponding layers
+ * for one transaction; each layer is represented as one descriptor
+ * (i.e., pxp_tx_desc) here.
+ */
+
+ INIT_LIST_HEAD(&pxp_chan->queue);
+
+ return ret;
+}
+
+static irqreturn_t pxp_irq(int irq, void *dev_id)
+{
+ struct pxps *pxp = dev_id;
+ struct pxp_channel *pxp_chan;
+ struct pxp_tx_desc *desc;
+ struct pxp_tx_desc *child, *_child;
+ dma_async_tx_callback callback;
+ void *callback_param;
+ unsigned long flags;
+ u32 hist_status;
+ int pxp_irq_status = 0;
+
+ dump_pxp_reg(pxp);
+
+ if (__raw_readl(pxp->base + HW_PXP_STAT) & BM_PXP_STAT_IRQ0)
+ __raw_writel(BM_PXP_STAT_IRQ0, pxp->base + HW_PXP_STAT_CLR);
+ else {
+ int irq_clr = 0;
+
+ pxp_irq_status = __raw_readl(pxp->base + HW_PXP_IRQ);
+ BUG_ON(!pxp_irq_status);
+
+ if (pxp_irq_status & BM_PXP_IRQ_FIRST_CH0_PREFETCH_IRQ)
+ irq_clr |= BM_PXP_IRQ_FIRST_CH0_PREFETCH_IRQ;
+ if (pxp_irq_status & BM_PXP_IRQ_FIRST_CH1_PREFETCH_IRQ)
+ irq_clr |= BM_PXP_IRQ_FIRST_CH1_PREFETCH_IRQ;
+ if (pxp_irq_status & BM_PXP_IRQ_FIRST_CH0_STORE_IRQ)
+ irq_clr |= BM_PXP_IRQ_FIRST_CH0_STORE_IRQ;
+ if (pxp_irq_status & BM_PXP_IRQ_FIRST_CH1_STORE_IRQ)
+ irq_clr |= BM_PXP_IRQ_FIRST_CH1_STORE_IRQ;
+ if (pxp_irq_status & BM_PXP_IRQ_FIRST_STORE_IRQ)
+ irq_clr |= BM_PXP_IRQ_FIRST_STORE_IRQ;
+
+ if (pxp_irq_status & BM_PXP_IRQ_WFE_B_STORE_IRQ)
+ irq_clr |= BM_PXP_IRQ_WFE_B_STORE_IRQ;
+ if (pxp_irq_status & BM_PXP_IRQ_WFE_A_STORE_IRQ)
+ irq_clr |= BM_PXP_IRQ_WFE_A_STORE_IRQ;
+ if (pxp_irq_status & BM_PXP_IRQ_DITHER_STORE_IRQ)
+ irq_clr |= BM_PXP_IRQ_DITHER_STORE_IRQ;
+
+ if (pxp_irq_status & BM_PXP_IRQ_WFE_A_CH0_STORE_IRQ)
+ irq_clr |= BM_PXP_IRQ_WFE_A_CH0_STORE_IRQ;
+ if (pxp_irq_status & BM_PXP_IRQ_WFE_A_CH1_STORE_IRQ)
+ irq_clr |= BM_PXP_IRQ_WFE_A_CH1_STORE_IRQ;
+
+ if (pxp_irq_status & BM_PXP_IRQ_WFE_B_CH0_STORE_IRQ)
+ irq_clr |= BM_PXP_IRQ_WFE_B_CH0_STORE_IRQ;
+ if (pxp_irq_status & BM_PXP_IRQ_WFE_B_CH1_STORE_IRQ)
+ irq_clr |= BM_PXP_IRQ_WFE_B_CH1_STORE_IRQ;
+
+ if (pxp_irq_status & BM_PXP_IRQ_DITHER_CH0_PREFETCH_IRQ)
+ irq_clr |= BM_PXP_IRQ_DITHER_CH0_PREFETCH_IRQ;
+ if (pxp_irq_status & BM_PXP_IRQ_DITHER_CH1_PREFETCH_IRQ)
+ irq_clr |= BM_PXP_IRQ_DITHER_CH1_PREFETCH_IRQ;
+ if (pxp_irq_status & BM_PXP_IRQ_DITHER_CH0_STORE_IRQ)
+ irq_clr |= BM_PXP_IRQ_DITHER_CH0_STORE_IRQ;
+ if (pxp_irq_status & BM_PXP_IRQ_DITHER_CH1_STORE_IRQ)
+ irq_clr |= BM_PXP_IRQ_DITHER_CH1_STORE_IRQ;
+ /*XXX other irqs status clear should be added below */
+
+ __raw_writel(irq_clr, pxp->base + HW_PXP_IRQ_CLR);
+
+ pxp_writel(BM_PXP_CTRL_ENABLE, HW_PXP_CTRL_CLR);
+ }
+ pxp_collision_status_report(pxp, &col_info);
+ pxp_histogram_status_report(pxp, &hist_status);
+ /*XXX before a new update operation, we should
+ * always clear all the collision information
+ */
+ pxp_collision_detection_disable(pxp);
+ pxp_histogram_disable(pxp);
+
+ pxp_writel(0x0, HW_PXP_CTRL);
+ pxp_soft_reset(pxp);
+ if (pxp->devdata && pxp->devdata->pxp_data_path_config)
+ pxp->devdata->pxp_data_path_config(pxp);
+ __raw_writel(0xffff, pxp->base + HW_PXP_IRQ_MASK);
+
+ spin_lock_irqsave(&pxp->lock, flags);
+ if (list_empty(&head)) {
+ pxp->pxp_ongoing = 0;
+ spin_unlock_irqrestore(&pxp->lock, flags);
+ return IRQ_NONE;
+ }
+
+ /* Get descriptor and call callback */
+ desc = list_entry(head.next, struct pxp_tx_desc, list);
+ pxp_chan = to_pxp_channel(desc->txd.chan);
+
+ pxp_chan->completed = desc->txd.cookie;
+
+ callback = desc->txd.callback;
+ callback_param = desc->txd.callback_param;
+
+ /* Send histogram status back to caller */
+ desc->hist_status = hist_status;
+
+ if ((desc->txd.flags & DMA_PREP_INTERRUPT) && callback)
+ callback(callback_param);
+
+ pxp_chan->status = PXP_CHANNEL_INITIALIZED;
+
+ list_for_each_entry_safe(child, _child, &desc->tx_list, list) {
+ list_del_init(&child->list);
+ kmem_cache_free(tx_desc_cache, (void *)child);
+ }
+ list_del_init(&desc->list);
+ kmem_cache_free(tx_desc_cache, (void *)desc);
+
+ complete(&pxp->complete);
+ pxp->pxp_ongoing = 0;
+ mod_timer(&pxp->clk_timer, jiffies + msecs_to_jiffies(timeout_in_ms));
+
+ spin_unlock_irqrestore(&pxp->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+/* allocate/free dma tx descriptor dynamically*/
+static struct pxp_tx_desc *pxpdma_desc_alloc(struct pxp_channel *pxp_chan)
+{
+ struct pxp_tx_desc *desc = NULL;
+ struct dma_async_tx_descriptor *txd = NULL;
+
+ desc = kmem_cache_alloc(tx_desc_cache, GFP_KERNEL | __GFP_ZERO);
+ if (desc == NULL)
+ return NULL;
+
+ INIT_LIST_HEAD(&desc->list);
+ INIT_LIST_HEAD(&desc->tx_list);
+ txd = &desc->txd;
+ dma_async_tx_descriptor_init(txd, &pxp_chan->dma_chan);
+ txd->tx_submit = pxp_tx_submit;
+
+ return desc;
+}
+
+
+/* Allocate and initialise a transfer descriptor. */
+static struct dma_async_tx_descriptor *pxp_prep_slave_sg(struct dma_chan *chan,
+ struct scatterlist
+ *sgl,
+ unsigned int sg_len,
+ enum
+ dma_transfer_direction
+ direction,
+ unsigned long tx_flags,
+ void *context)
+{
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+ struct pxp_dma *pxp_dma = to_pxp_dma(chan->device);
+ struct pxps *pxp = to_pxp(pxp_dma);
+ struct pxp_tx_desc *pos = NULL, *next = NULL;
+ struct pxp_tx_desc *desc = NULL;
+ struct pxp_tx_desc *first = NULL, *prev = NULL;
+ struct scatterlist *sg;
+ dma_addr_t phys_addr;
+ int i;
+
+ if (direction != DMA_DEV_TO_MEM && direction != DMA_MEM_TO_DEV) {
+ dev_err(chan->device->dev, "Invalid DMA direction %d!\n",
+ direction);
+ return NULL;
+ }
+
+ if (unlikely(sg_len < 2))
+ return NULL;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ desc = pxpdma_desc_alloc(pxp_chan);
+ if (!desc) {
+ dev_err(chan->device->dev, "no enough memory to allocate tx descriptor\n");
+
+ if (first) {
+ list_for_each_entry_safe(pos, next, &first->tx_list, list) {
+ list_del_init(&pos->list);
+ kmem_cache_free(tx_desc_cache, (void*)pos);
+ }
+ list_del_init(&first->list);
+ kmem_cache_free(tx_desc_cache, (void*)first);
+ }
+
+ return NULL;
+ }
+
+ phys_addr = sg_dma_address(sg);
+
+ if (!first) {
+ first = desc;
+
+ desc->layer_param.s0_param.paddr = phys_addr;
+ } else {
+ list_add_tail(&desc->list, &first->tx_list);
+ prev->next = desc;
+ desc->next = NULL;
+
+ if (i == 1)
+ desc->layer_param.out_param.paddr = phys_addr;
+ else
+ desc->layer_param.ol_param.paddr = phys_addr;
+ }
+
+ prev = desc;
+ }
+
+ pxp->pxp_conf_state.layer_nr = sg_len;
+ first->txd.flags = tx_flags;
+ first->len = sg_len;
+ pr_debug("%s:%d first %p, first->len %d, flags %08x\n",
+ __func__, __LINE__, first, first->len, first->txd.flags);
+
+ return &first->txd;
+}
+
+static void pxp_issue_pending(struct dma_chan *chan)
+{
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+ struct pxp_dma *pxp_dma = to_pxp_dma(chan->device);
+ struct pxps *pxp = to_pxp(pxp_dma);
+
+ spin_lock(&pxp_chan->lock);
+
+ if (list_empty(&pxp_chan->queue)) {
+ spin_unlock(&pxp_chan->lock);
+ return;
+ }
+
+ pxpdma_dequeue(pxp_chan, pxp);
+ pxp_chan->status = PXP_CHANNEL_READY;
+
+ spin_unlock(&pxp_chan->lock);
+
+ pxp_clk_enable(pxp);
+ wake_up_interruptible(&pxp->thread_waitq);
+}
+
+static void __pxp_terminate_all(struct dma_chan *chan)
+{
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+ pxp_chan->status = PXP_CHANNEL_INITIALIZED;
+}
+
+static int pxp_device_terminate_all(struct dma_chan *chan)
+{
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+
+ spin_lock(&pxp_chan->lock);
+ __pxp_terminate_all(chan);
+ spin_unlock(&pxp_chan->lock);
+
+ return 0;
+}
+
+static int pxp_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+ struct pxp_dma *pxp_dma = to_pxp_dma(chan->device);
+ int ret;
+
+ /* dmaengine.c now guarantees to only offer free channels */
+ BUG_ON(chan->client_count > 1);
+ WARN_ON(pxp_chan->status != PXP_CHANNEL_FREE);
+
+ chan->cookie = 1;
+ pxp_chan->completed = -ENXIO;
+
+ pr_debug("%s dma_chan.chan_id %d\n", __func__, chan->chan_id);
+ ret = pxp_init_channel(pxp_dma, pxp_chan);
+ if (ret < 0)
+ goto err_chan;
+
+ pxp_chan->status = PXP_CHANNEL_INITIALIZED;
+
+ dev_dbg(&chan->dev->device, "Found channel 0x%x, irq %d\n",
+ chan->chan_id, pxp_chan->eof_irq);
+
+ return ret;
+
+err_chan:
+ return ret;
+}
+
+static void pxp_free_chan_resources(struct dma_chan *chan)
+{
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+
+ spin_lock(&pxp_chan->lock);
+
+ __pxp_terminate_all(chan);
+
+ pxp_chan->status = PXP_CHANNEL_FREE;
+
+ spin_unlock(&pxp_chan->lock);
+}
+
+static enum dma_status pxp_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+
+ if (cookie != chan->cookie)
+ return DMA_ERROR;
+
+ if (txstate) {
+ txstate->last = pxp_chan->completed;
+ txstate->used = chan->cookie;
+ txstate->residue = 0;
+ }
+ return DMA_COMPLETE;
+}
+
+static void pxp_data_path_config_v3p(struct pxps *pxp)
+{
+ u32 val = 0;
+
+ __raw_writel(
+ BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(1)|
+ BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(1)|
+ BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(0)|
+ BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(0),
+ pxp->base + HW_PXP_DATA_PATH_CTRL0);
+
+ /*
+ * MUX17: HIST_B as histogram: 0: output buffer, 1: wfe_store
+ * MUX16: HIST_A as collision: 0: output buffer, 1: wfe_store
+ */
+ if (pxp_is_v3(pxp))
+ val = BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(1)|
+ BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(0);
+ else if (pxp_is_v3p(pxp))
+ val = BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(1)|
+ BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(1);
+ __raw_writel(val, pxp->base + HW_PXP_DATA_PATH_CTRL1);
+}
+
+static void pxp_soft_reset(struct pxps *pxp)
+{
+ __raw_writel(BM_PXP_CTRL_SFTRST, pxp->base + HW_PXP_CTRL_CLR);
+ __raw_writel(BM_PXP_CTRL_CLKGATE, pxp->base + HW_PXP_CTRL_CLR);
+
+ __raw_writel(BM_PXP_CTRL_SFTRST, pxp->base + HW_PXP_CTRL_SET);
+ while (!(__raw_readl(pxp->base + HW_PXP_CTRL) & BM_PXP_CTRL_CLKGATE))
+ dev_dbg(pxp->dev, "%s: wait for clock gate off", __func__);
+
+ __raw_writel(BM_PXP_CTRL_SFTRST, pxp->base + HW_PXP_CTRL_CLR);
+ __raw_writel(BM_PXP_CTRL_CLKGATE, pxp->base + HW_PXP_CTRL_CLR);
+}
+
+static void pxp_sram_init(struct pxps *pxp, u32 select,
+ u32 buffer_addr, u32 length)
+{
+ u32 i;
+
+ __raw_writel(
+ BF_PXP_INIT_MEM_CTRL_ADDR(0) |
+ BF_PXP_INIT_MEM_CTRL_SELECT(select) |
+ BF_PXP_INIT_MEM_CTRL_START(1),
+ pxp->base + HW_PXP_INIT_MEM_CTRL);
+
+ if ((select == WFE_A) || (select == WFE_B)) {
+ for (i = 0; i < length / 2; i++) {
+ __raw_writel(*(((u32*)buffer_addr) + 2 * i + 1),
+ pxp->base + HW_PXP_INIT_MEM_DATA_HIGH);
+
+ __raw_writel(*(((u32*)buffer_addr) + 2 * i),
+ pxp->base + HW_PXP_INIT_MEM_DATA);
+ }
+ } else {
+ for (i = 0; i < length; i++) {
+ __raw_writel(*(((u32*) buffer_addr) + i),
+ pxp->base + HW_PXP_INIT_MEM_DATA);
+ }
+ }
+
+ __raw_writel(
+ BF_PXP_INIT_MEM_CTRL_ADDR(0) |
+ BF_PXP_INIT_MEM_CTRL_SELECT(select) |
+ BF_PXP_INIT_MEM_CTRL_START(0),
+ pxp->base + HW_PXP_INIT_MEM_CTRL);
+}
+
+/*
+ * wfe a configuration
+ * configure wfe a engine for waveform processing
+ * including its fetch and store module
+ */
+static void pxp_wfe_a_configure(struct pxps *pxp)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+
+ /* FETCH */
+ __raw_writel(
+ BF_PXP_WFA_FETCH_CTRL_BF1_EN(1) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_HSK_MODE(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_BYTES_PP(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_LINE_MODE(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_SRAM_IF(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_BURST_LEN(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_BYPASS_MODE(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_EN(1) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_HSK_MODE(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_BYTES_PP(1) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_LINE_MODE(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_SRAM_IF(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_BURST_LEN(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_BYPASS_MODE(0),
+ pxp->base + HW_PXP_WFA_FETCH_CTRL);
+
+ __raw_writel(
+ BF_PXP_WFA_ARRAY_PIXEL0_MASK_SIGN_Y(0) |
+ BF_PXP_WFA_ARRAY_PIXEL0_MASK_OFFSET_Y(0) |
+ BF_PXP_WFA_ARRAY_PIXEL0_MASK_SIGN_X(0) |
+ BF_PXP_WFA_ARRAY_PIXEL0_MASK_OFFSET_X(0) |
+ BF_PXP_WFA_ARRAY_PIXEL0_MASK_BUF_SEL(1) |
+ BF_PXP_WFA_ARRAY_PIXEL0_MASK_H_OFS(0) |
+ BF_PXP_WFA_ARRAY_PIXEL0_MASK_L_OFS(3),
+ pxp->base + HW_PXP_WFA_ARRAY_PIXEL0_MASK);
+
+ __raw_writel(
+ BF_PXP_WFA_ARRAY_PIXEL1_MASK_SIGN_Y(0) |
+ BF_PXP_WFA_ARRAY_PIXEL1_MASK_OFFSET_Y(0) |
+ BF_PXP_WFA_ARRAY_PIXEL1_MASK_SIGN_X(0) |
+ BF_PXP_WFA_ARRAY_PIXEL1_MASK_OFFSET_X(0) |
+ BF_PXP_WFA_ARRAY_PIXEL1_MASK_BUF_SEL(1) |
+ BF_PXP_WFA_ARRAY_PIXEL1_MASK_H_OFS(4) |
+ BF_PXP_WFA_ARRAY_PIXEL1_MASK_L_OFS(7),
+ pxp->base + HW_PXP_WFA_ARRAY_PIXEL1_MASK);
+
+ __raw_writel(
+ BF_PXP_WFA_ARRAY_PIXEL3_MASK_SIGN_Y(0) |
+ BF_PXP_WFA_ARRAY_PIXEL3_MASK_OFFSET_Y(0) |
+ BF_PXP_WFA_ARRAY_PIXEL3_MASK_SIGN_X(0) |
+ BF_PXP_WFA_ARRAY_PIXEL3_MASK_OFFSET_X(0) |
+ BF_PXP_WFA_ARRAY_PIXEL3_MASK_BUF_SEL(1) |
+ BF_PXP_WFA_ARRAY_PIXEL3_MASK_H_OFS(8) |
+ BF_PXP_WFA_ARRAY_PIXEL3_MASK_L_OFS(9),
+ pxp->base + HW_PXP_WFA_ARRAY_PIXEL2_MASK);
+
+ __raw_writel(
+ BF_PXP_WFA_ARRAY_PIXEL4_MASK_SIGN_Y(0) |
+ BF_PXP_WFA_ARRAY_PIXEL4_MASK_OFFSET_Y(0) |
+ BF_PXP_WFA_ARRAY_PIXEL4_MASK_SIGN_X(0) |
+ BF_PXP_WFA_ARRAY_PIXEL4_MASK_OFFSET_X(0) |
+ BF_PXP_WFA_ARRAY_PIXEL4_MASK_BUF_SEL(1) |
+ BF_PXP_WFA_ARRAY_PIXEL4_MASK_H_OFS(10) |
+ BF_PXP_WFA_ARRAY_PIXEL4_MASK_L_OFS(15),
+ pxp->base + HW_PXP_WFA_ARRAY_PIXEL3_MASK);
+
+ __raw_writel(
+ BF_PXP_WFA_ARRAY_PIXEL2_MASK_SIGN_Y(0) |
+ BF_PXP_WFA_ARRAY_PIXEL2_MASK_OFFSET_Y(0) |
+ BF_PXP_WFA_ARRAY_PIXEL2_MASK_SIGN_X(0) |
+ BF_PXP_WFA_ARRAY_PIXEL2_MASK_OFFSET_X(0) |
+ BF_PXP_WFA_ARRAY_PIXEL2_MASK_BUF_SEL(0) |
+ BF_PXP_WFA_ARRAY_PIXEL2_MASK_H_OFS(4) |
+ BF_PXP_WFA_ARRAY_PIXEL2_MASK_L_OFS(7),
+ pxp->base + HW_PXP_WFA_ARRAY_PIXEL4_MASK);
+
+ __raw_writel(1, pxp->base + HW_PXP_WFA_ARRAY_REG2);
+
+ /* STORE */
+ __raw_writel(
+ BF_PXP_WFE_A_STORE_CTRL_CH0_CH_EN(1)|
+ BF_PXP_WFE_A_STORE_CTRL_CH0_BLOCK_EN(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH0_BLOCK_16(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH0_HANDSHAKE_EN(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH0_ARRAY_EN(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH0_ARRAY_LINE_NUM(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH0_STORE_BYPASS_EN(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH0_STORE_MEMORY_EN(1)|
+ BF_PXP_WFE_A_STORE_CTRL_CH0_PACK_IN_SEL(1)|
+ BF_PXP_WFE_A_STORE_CTRL_CH0_FILL_DATA_EN(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH0_WR_NUM_BYTES(8)|
+ BF_PXP_WFE_A_STORE_CTRL_CH0_COMBINE_2CHANNEL(1) |
+ BF_PXP_WFE_A_STORE_CTRL_CH0_ARBIT_EN(0),
+ pxp->base + HW_PXP_WFE_A_STORE_CTRL_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_A_STORE_CTRL_CH1_CH_EN(1)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_BLOCK_EN(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_BLOCK_16(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_HANDSHAKE_EN(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_EN(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_LINE_NUM(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_STORE_BYPASS_EN(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_STORE_MEMORY_EN(1)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_PACK_IN_SEL(1)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_WR_NUM_BYTES(16),
+ pxp->base + HW_PXP_WFE_A_STORE_CTRL_CH1);
+
+ __raw_writel(
+ BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP(0)|
+ BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN(0)|
+ BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN(0)|
+ BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS(0),
+ pxp->base + HW_PXP_WFE_A_STORE_SHIFT_CTRL_CH0);
+
+
+ __raw_writel(
+ BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP(1)|
+ BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN(0)|
+ BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN(0),
+ pxp->base + HW_PXP_WFE_A_STORE_SHIFT_CTRL_CH1);
+
+ __raw_writel(BF_PXP_WFE_A_STORE_FILL_DATA_CH0_FILL_DATA_CH0(0),
+ pxp->base + HW_PXP_WFE_A_STORE_FILL_DATA_CH0);
+
+ __raw_writel(BF_PXP_WFE_A_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0(0x0),
+ pxp->base + HW_PXP_WFE_A_STORE_D_MASK0_H_CH0);
+
+ __raw_writel(BF_PXP_WFE_A_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0(0xf), /* fetch CP */
+ pxp->base + HW_PXP_WFE_A_STORE_D_MASK0_L_CH0);
+
+ __raw_writel(BF_PXP_WFE_A_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0(0x0),
+ pxp->base + HW_PXP_WFE_A_STORE_D_MASK1_H_CH0);
+
+ __raw_writel(BF_PXP_WFE_A_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0(0xf00), /* fetch NP */
+ pxp->base + HW_PXP_WFE_A_STORE_D_MASK1_L_CH0);
+
+ __raw_writel(BF_PXP_WFE_A_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0(0x0),
+ pxp->base + HW_PXP_WFE_A_STORE_D_MASK2_H_CH0);
+
+ __raw_writel(BF_PXP_WFE_A_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0(0x00000),
+ pxp->base + HW_PXP_WFE_A_STORE_D_MASK2_L_CH0);
+
+ __raw_writel(BF_PXP_WFE_A_STORE_D_MASK3_H_CH0_D_MASK3_H_CH0(0x0),
+ pxp->base + HW_PXP_WFE_A_STORE_D_MASK3_H_CH0);
+
+ __raw_writel(BF_PXP_WFE_A_STORE_D_MASK3_L_CH0_D_MASK3_L_CH0(0x3f000000), /* fetch LUT */
+ pxp->base + HW_PXP_WFE_A_STORE_D_MASK3_L_CH0);
+
+ __raw_writel(BF_PXP_WFE_A_STORE_D_MASK4_H_CH0_D_MASK4_H_CH0(0xf),
+ pxp->base + HW_PXP_WFE_A_STORE_D_MASK4_H_CH0);
+
+ __raw_writel(BF_PXP_WFE_A_STORE_D_MASK4_L_CH0_D_MASK4_L_CH0(0x0), /* fetch Y4 */
+ pxp->base + HW_PXP_WFE_A_STORE_D_MASK4_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0(32) |
+ BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0(1) |
+ BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1(28)|
+ BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1(1) |
+ BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2(24)|
+ BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2(1)|
+ BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3(18)|
+ BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3(1),
+ pxp->base + HW_PXP_WFE_A_STORE_D_SHIFT_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4(28) |
+ BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG4(0) |
+ BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5(0)|
+ BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG5(0) |
+ BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6(0)|
+ BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG6(0) |
+ BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7(0),
+ pxp->base + HW_PXP_WFE_A_STORE_D_SHIFT_H_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0(1)|
+ BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0(1)|
+ BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1(1)|
+ BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1(0)|
+ BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2(32+6)|
+ BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2(1)|
+ BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3(32+6)|
+ BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3(1),
+ pxp->base + HW_PXP_WFE_A_STORE_F_SHIFT_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK4(0)|
+ BF_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK5(0)|
+ BF_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK6(0)|
+ BF_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK7(0),
+ pxp->base + HW_PXP_WFE_A_STORE_F_MASK_H_CH0);
+
+
+ __raw_writel(
+ BF_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK0(0x1) |
+ BF_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK1(0x2) |
+ BF_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK2(0x4) |
+ BF_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK3(0x8),
+ pxp->base + HW_PXP_WFE_A_STORE_F_MASK_L_CH0);
+
+ /* ALU */
+ __raw_writel(BF_PXP_ALU_A_INST_ENTRY_ENTRY_ADDR(0),
+ pxp->base + HW_PXP_ALU_A_INST_ENTRY);
+
+ __raw_writel(BF_PXP_ALU_A_PARAM_PARAM0(0) |
+ BF_PXP_ALU_A_PARAM_PARAM1(0),
+ pxp->base + HW_PXP_ALU_A_PARAM);
+
+ __raw_writel(BF_PXP_ALU_A_CONFIG_BUF_ADDR(0),
+ pxp->base + HW_PXP_ALU_A_CONFIG);
+
+ __raw_writel(BF_PXP_ALU_A_LUT_CONFIG_MODE(0) |
+ BF_PXP_ALU_A_LUT_CONFIG_EN(0),
+ pxp->base + HW_PXP_ALU_A_LUT_CONFIG);
+
+ __raw_writel(BF_PXP_ALU_A_LUT_DATA0_LUT_DATA_L(0),
+ pxp->base + HW_PXP_ALU_A_LUT_DATA0);
+
+ __raw_writel(BF_PXP_ALU_A_LUT_DATA1_LUT_DATA_H(0),
+ pxp->base + HW_PXP_ALU_A_LUT_DATA1);
+
+ __raw_writel(BF_PXP_ALU_A_CTRL_BYPASS (1) |
+ BF_PXP_ALU_A_CTRL_ENABLE (1) |
+ BF_PXP_ALU_A_CTRL_START (0) |
+ BF_PXP_ALU_A_CTRL_SW_RESET (0),
+ pxp->base + HW_PXP_ALU_A_CTRL);
+
+ /* WFE A */
+ __raw_writel(0x3F3F0303, pxp->base + HW_PXP_WFE_A_STAGE1_MUX0);
+ __raw_writel(0x0C00000C, pxp->base + HW_PXP_WFE_A_STAGE1_MUX1);
+ __raw_writel(0x01040000, pxp->base + HW_PXP_WFE_A_STAGE1_MUX2);
+ __raw_writel(0x0A0A0904, pxp->base + HW_PXP_WFE_A_STAGE1_MUX3);
+ __raw_writel(0x00000B0B, pxp->base + HW_PXP_WFE_A_STAGE1_MUX4);
+
+ __raw_writel(0x1800280E, pxp->base + HW_PXP_WFE_A_STAGE2_MUX0);
+ __raw_writel(0x00280E01, pxp->base + HW_PXP_WFE_A_STAGE2_MUX1);
+ __raw_writel(0x280E0118, pxp->base + HW_PXP_WFE_A_STAGE2_MUX2);
+ __raw_writel(0x00011800, pxp->base + HW_PXP_WFE_A_STAGE2_MUX3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STAGE2_MUX4);
+ __raw_writel(0x1800280E, pxp->base + HW_PXP_WFE_A_STAGE2_MUX5);
+ __raw_writel(0x00280E01, pxp->base + HW_PXP_WFE_A_STAGE2_MUX6);
+ __raw_writel(0x1A0E0118, pxp->base + HW_PXP_WFE_A_STAGE2_MUX7);
+ __raw_writel(0x1B012911, pxp->base + HW_PXP_WFE_A_STAGE2_MUX8);
+ __raw_writel(0x00002911, pxp->base + HW_PXP_WFE_A_STAGE2_MUX9);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STAGE2_MUX10);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STAGE2_MUX11);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STAGE2_MUX12);
+
+ __raw_writel(0x07060504, pxp->base + HW_PXP_WFE_A_STAGE3_MUX0);
+ __raw_writel(0x3F3F3F08, pxp->base + HW_PXP_WFE_A_STAGE3_MUX1);
+ __raw_writel(0x03020100, pxp->base + HW_PXP_WFE_A_STAGE3_MUX2);
+ __raw_writel(0x3F3F3F3F, pxp->base + HW_PXP_WFE_A_STAGE3_MUX3);
+
+ __raw_writel(0x001F1F1F, pxp->base + HW_PXP_WFE_A_STAGE2_5X6_MASKS_0);
+ __raw_writel(0x3f030100, pxp->base + HW_PXP_WFE_A_STAGE2_5X6_ADDR_0);
+
+ __raw_writel(0x00000700, pxp->base + HW_PXP_WFE_A_STG2_5X1_OUT0);
+ __raw_writel(0x00007000, pxp->base + HW_PXP_WFE_A_STG2_5X1_OUT1);
+ __raw_writel(0x0000A000, pxp->base + HW_PXP_WFE_A_STG2_5X1_OUT2);
+ __raw_writel(0x000000C0, pxp->base + HW_PXP_WFE_A_STG2_5X1_OUT3);
+ __raw_writel(0x071F1F1F, pxp->base + HW_PXP_WFE_A_STG2_5X1_MASKS);
+
+ __raw_writel(0xFFFFFFFF, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT0_2);
+ __raw_writel(0xFFFFFFFF, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT0_3);
+ __raw_writel(0xFFFFFFFF, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT0_4);
+ __raw_writel(0xFFFFFFFF, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT0_5);
+ __raw_writel(0xFFFFFFFF, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT0_6);
+ __raw_writel(0xFFFFFFFF, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT0_7);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT1_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT1_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT1_2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT1_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT1_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT1_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT1_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT1_7);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT2_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT2_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT2_2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT2_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT2_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT2_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT2_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT2_7);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT3_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT3_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT3_2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT3_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT3_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT3_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT3_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT3_7);
+
+ __raw_writel(0x04040404, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT0_0);
+ __raw_writel(0x04040404, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT0_1);
+ __raw_writel(0x04050505, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT0_2);
+ __raw_writel(0x04040404, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT0_3);
+ __raw_writel(0x04040404, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT0_4);
+ __raw_writel(0x04040404, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT0_5);
+ __raw_writel(0x04040404, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT0_6);
+ __raw_writel(0x04040404, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT0_7);
+
+ __raw_writel(0x05050505, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT1_0);
+ __raw_writel(0x05050505, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT1_1);
+ __raw_writel(0x05080808, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT1_2);
+ __raw_writel(0x05050505, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT1_3);
+ __raw_writel(0x05050505, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT1_4);
+ __raw_writel(0x05050505, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT1_5);
+ __raw_writel(0x05050505, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT1_6);
+ __raw_writel(0x05050505, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT1_7);
+
+ __raw_writel(0x07070707, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT2_0);
+ __raw_writel(0x07070707, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT2_1);
+ __raw_writel(0x070C0C0C, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT2_2);
+ __raw_writel(0x07070707, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT2_3);
+ __raw_writel(0X0F0F0F0F, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT2_4);
+ __raw_writel(0X0F0F0F0F, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT2_5);
+ __raw_writel(0X0F0F0F0F, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT2_6);
+ __raw_writel(0X0F0F0F0F, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT2_7);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT3_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT3_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT3_2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT3_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT3_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT3_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT3_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG2_5X6_OUT3_7);
+
+ if (pxp->devdata && pxp->devdata->pxp_lut_cleanup_multiple)
+ pxp->devdata->pxp_lut_cleanup_multiple(pxp,
+ proc_data->lut_sels, 1);
+}
+
+static void pxp_wfe_a_configure_v3p(struct pxps *pxp)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+
+ /* FETCH */
+ __raw_writel(
+ BF_PXP_WFB_FETCH_CTRL_BF1_EN(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_HSK_MODE(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BYTES_PP(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_LINE_MODE(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_SRAM_IF(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BURST_LEN(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BYPASS_MODE(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_EN(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_HSK_MODE(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BYTES_PP(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_LINE_MODE(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_SRAM_IF(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BURST_LEN(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BYPASS_MODE(0),
+ pxp->base + HW_PXP_WFB_FETCH_CTRL);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_PIXEL0_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL0_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL0_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL0_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL0_MASK_BUF_SEL(1) |
+ BF_PXP_WFB_ARRAY_PIXEL0_MASK_H_OFS(0) |
+ BF_PXP_WFB_ARRAY_PIXEL0_MASK_L_OFS(3),
+ pxp->base + HW_PXP_WFB_ARRAY_PIXEL0_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_PIXEL1_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL1_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL1_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL1_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL1_MASK_BUF_SEL(1) |
+ BF_PXP_WFB_ARRAY_PIXEL1_MASK_H_OFS(4) |
+ BF_PXP_WFB_ARRAY_PIXEL1_MASK_L_OFS(7),
+ pxp->base + HW_PXP_WFB_ARRAY_PIXEL1_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_PIXEL2_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL2_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL2_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL2_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL2_MASK_BUF_SEL(1) |
+ BF_PXP_WFB_ARRAY_PIXEL2_MASK_H_OFS(8) |
+ BF_PXP_WFB_ARRAY_PIXEL2_MASK_L_OFS(9),
+ pxp->base + HW_PXP_WFB_ARRAY_PIXEL2_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_PIXEL3_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL3_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL3_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL3_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL3_MASK_BUF_SEL(1) |
+ BF_PXP_WFB_ARRAY_PIXEL3_MASK_H_OFS(10) |
+ BF_PXP_WFB_ARRAY_PIXEL3_MASK_L_OFS(15),
+ pxp->base + HW_PXP_WFB_ARRAY_PIXEL3_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_PIXEL4_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL4_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL4_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL4_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL4_MASK_BUF_SEL(0) |
+ BF_PXP_WFB_ARRAY_PIXEL4_MASK_H_OFS(4) |
+ BF_PXP_WFB_ARRAY_PIXEL4_MASK_L_OFS(7),
+ pxp->base + HW_PXP_WFB_ARRAY_PIXEL4_MASK);
+
+ __raw_writel(1, pxp->base + HW_PXP_WFB_ARRAY_REG2);
+
+ /* STORE */
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_CTRL_CH0_CH_EN(1)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_BLOCK_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_BLOCK_16(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_HANDSHAKE_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_LINE_NUM(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_STORE_BYPASS_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_STORE_MEMORY_EN(1)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_PACK_IN_SEL(1)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_FILL_DATA_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_WR_NUM_BYTES(8)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_COMBINE_2CHANNEL(1) |
+ BF_PXP_WFE_B_STORE_CTRL_CH0_ARBIT_EN(0),
+ pxp->base + HW_PXP_WFE_B_STORE_CTRL_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_CTRL_CH1_CH_EN(1)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_BLOCK_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_BLOCK_16(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_HANDSHAKE_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_LINE_NUM(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_STORE_BYPASS_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_STORE_MEMORY_EN(1)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_PACK_IN_SEL(1)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_WR_NUM_BYTES(16),
+ pxp->base + HW_PXP_WFE_B_STORE_CTRL_CH1);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP(0)|
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN(0)|
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN(0)|
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS(0),
+ pxp->base + HW_PXP_WFE_B_STORE_SHIFT_CTRL_CH0);
+
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP(1)|
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN(0)|
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN(0),
+ pxp->base + HW_PXP_WFE_B_STORE_SHIFT_CTRL_CH1);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_FILL_DATA_CH0_FILL_DATA_CH0(0),
+ pxp->base + HW_PXP_WFE_B_STORE_FILL_DATA_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0(0x0),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK0_H_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0(0xf), /* fetch CP */
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK0_L_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0(0x0),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK1_H_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0(0xf00), /* fetch NP */
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK1_L_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0(0x0),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK2_H_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0(0x00000),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK2_L_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_D_MASK3_H_CH0_D_MASK3_H_CH0(0x0),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK3_H_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_D_MASK3_L_CH0_D_MASK3_L_CH0(0x3f000000), /* fetch LUT */
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK3_L_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_D_MASK4_H_CH0_D_MASK4_H_CH0(0xf),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK4_H_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_D_MASK4_L_CH0_D_MASK4_L_CH0(0x0), /* fetch Y4 */
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK4_L_CH0);
+
+ __raw_writel(0x0, pxp->base + HW_PXP_WFE_B_STORE_D_MASK5_H_CH0);
+ __raw_writel(0x0, pxp->base + HW_PXP_WFE_B_STORE_D_MASK5_L_CH0);
+ __raw_writel(0x0, pxp->base + HW_PXP_WFE_B_STORE_D_MASK6_H_CH0);
+ __raw_writel(0x0, pxp->base + HW_PXP_WFE_B_STORE_D_MASK6_L_CH0);
+ __raw_writel(0x0, pxp->base + HW_PXP_WFE_B_STORE_D_MASK7_H_CH0);
+ __raw_writel(0x0, pxp->base + HW_PXP_WFE_B_STORE_D_MASK7_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0(32) |
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0(1) |
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1(28)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1(1) |
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2(24)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2(1)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3(18)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3(1),
+ pxp->base + HW_PXP_WFE_B_STORE_D_SHIFT_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4(28) |
+ BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG4(0) |
+ BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5(0)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG5(0) |
+ BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6(0)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG6(0) |
+ BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7(0),
+ pxp->base + HW_PXP_WFE_B_STORE_D_SHIFT_H_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0(1)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0(1)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1(1)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2(32+6)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2(1)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3(32+6)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3(1),
+ pxp->base + HW_PXP_WFE_B_STORE_F_SHIFT_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG4(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG5(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG6(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG7(0),
+ pxp->base + HW_PXP_WFE_B_STORE_F_SHIFT_H_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK0(0x1) |
+ BF_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK1(0x2) |
+ BF_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK2(0x4) |
+ BF_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK3(0x8),
+ pxp->base + HW_PXP_WFE_B_STORE_F_MASK_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK4(0x0)|
+ BF_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK5(0x0)|
+ BF_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK6(0x0)|
+ BF_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK7(0x0),
+ pxp->base + HW_PXP_WFE_B_STORE_F_MASK_H_CH0);
+
+
+ /* ALU */
+ __raw_writel(BF_PXP_ALU_B_INST_ENTRY_ENTRY_ADDR(0),
+ pxp->base + HW_PXP_ALU_B_INST_ENTRY);
+
+ __raw_writel(BF_PXP_ALU_B_PARAM_PARAM0(0) |
+ BF_PXP_ALU_B_PARAM_PARAM1(0),
+ pxp->base + HW_PXP_ALU_B_PARAM);
+
+ __raw_writel(BF_PXP_ALU_B_CONFIG_BUF_ADDR(0),
+ pxp->base + HW_PXP_ALU_B_CONFIG);
+
+ __raw_writel(BF_PXP_ALU_B_LUT_CONFIG_MODE(0) |
+ BF_PXP_ALU_B_LUT_CONFIG_EN(0),
+ pxp->base + HW_PXP_ALU_B_LUT_CONFIG);
+
+ __raw_writel(BF_PXP_ALU_B_LUT_DATA0_LUT_DATA_L(0),
+ pxp->base + HW_PXP_ALU_B_LUT_DATA0);
+
+ __raw_writel(BF_PXP_ALU_B_LUT_DATA1_LUT_DATA_H(0),
+ pxp->base + HW_PXP_ALU_B_LUT_DATA1);
+
+ __raw_writel(BF_PXP_ALU_B_CTRL_BYPASS (1) |
+ BF_PXP_ALU_B_CTRL_ENABLE (1) |
+ BF_PXP_ALU_B_CTRL_START (0) |
+ BF_PXP_ALU_B_CTRL_SW_RESET (0),
+ pxp->base + HW_PXP_ALU_B_CTRL);
+
+ /* WFE A */
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE1_MUX0);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE1_MUX1);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE1_MUX2);
+ __raw_writel(0x03000000, pxp->base + HW_PXP_WFE_B_STAGE1_MUX3);
+ __raw_writel(0x00000003, pxp->base + HW_PXP_WFE_B_STAGE1_MUX4);
+ __raw_writel(0x04000000, pxp->base + HW_PXP_WFE_B_STAGE1_MUX5);
+ __raw_writel(0x0A090401, pxp->base + HW_PXP_WFE_B_STAGE1_MUX6);
+ __raw_writel(0x000B0B0A, pxp->base + HW_PXP_WFE_B_STAGE1_MUX7);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE1_MUX8);
+
+ __raw_writel(0x1901290C, pxp->base + HW_PXP_WFE_B_STAGE2_MUX0);
+ __raw_writel(0x01290C02, pxp->base + HW_PXP_WFE_B_STAGE2_MUX1);
+ __raw_writel(0x290C0219, pxp->base + HW_PXP_WFE_B_STAGE2_MUX2);
+ __raw_writel(0x00021901, pxp->base + HW_PXP_WFE_B_STAGE2_MUX3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STAGE2_MUX4);
+ __raw_writel(0x1901290C, pxp->base + HW_PXP_WFE_B_STAGE2_MUX5);
+ __raw_writel(0x01290C02, pxp->base + HW_PXP_WFE_B_STAGE2_MUX6);
+ __raw_writel(0x1B0C0219, pxp->base + HW_PXP_WFE_B_STAGE2_MUX7);
+ __raw_writel(0x1C022A0F, pxp->base + HW_PXP_WFE_B_STAGE2_MUX8);
+ __raw_writel(0x02002A0F, pxp->base + HW_PXP_WFE_B_STAGE2_MUX9);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STAGE2_MUX10);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STAGE2_MUX11);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STAGE2_MUX12);
+
+ __raw_writel(0x2a123a1d, pxp->base + HW_PXP_WFE_B_STAGE3_MUX0);
+ __raw_writel(0x00000013, pxp->base + HW_PXP_WFE_B_STAGE3_MUX1);
+ __raw_writel(0x2a123a1d, pxp->base + HW_PXP_WFE_B_STAGE3_MUX2);
+ __raw_writel(0x00000013, pxp->base + HW_PXP_WFE_B_STAGE3_MUX3);
+ __raw_writel(0x3b202c1d, pxp->base + HW_PXP_WFE_B_STAGE3_MUX4);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE3_MUX5);
+ __raw_writel(0x003b202d, pxp->base + HW_PXP_WFE_B_STAGE3_MUX6);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE3_MUX7);
+ __raw_writel(0x07060504, pxp->base + HW_PXP_WFE_B_STAGE3_MUX8);
+ __raw_writel(0x00000008, pxp->base + HW_PXP_WFE_B_STAGE3_MUX9);
+ __raw_writel(0x03020100, pxp->base + HW_PXP_WFE_B_STAGE3_MUX10);
+
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT0_0);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT0_1);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT0_2);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT0_3);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT0_4);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT0_5);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT0_6);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT0_7);
+
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT1_0);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT1_1);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT1_2);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT1_3);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT1_4);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT1_5);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT1_6);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT1_7);
+
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE1_5X8_MASKS_0);
+
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X1_OUT0);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X1_MASKS);
+
+ __raw_writel(0xFFFFFFFF, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT0_2);
+ __raw_writel(0xFFFFFFFF, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT0_3);
+ __raw_writel(0xFFFFFFFF, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT0_4);
+ __raw_writel(0xFFFFFFFF, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT0_5);
+ __raw_writel(0xFFFFFFFF, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT0_6);
+ __raw_writel(0xFFFFFFFF, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT0_7);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_7);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT2_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT2_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT2_2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT2_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT2_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT2_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT2_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT2_7);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT3_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT3_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT3_2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT3_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT3_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT3_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT3_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT3_7);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT4_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT4_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT4_2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT4_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT4_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT4_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT4_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT4_7);
+
+ __raw_writel(0x00000700, pxp->base + HW_PXP_WFE_B_STG2_5X1_OUT0);
+ __raw_writel(0x00007000, pxp->base + HW_PXP_WFE_B_STG2_5X1_OUT1);
+ __raw_writel(0x0000A000, pxp->base + HW_PXP_WFE_B_STG2_5X1_OUT2);
+ __raw_writel(0x000000C0, pxp->base + HW_PXP_WFE_B_STG2_5X1_OUT3);
+ __raw_writel(0x070F1F1F, pxp->base + HW_PXP_WFE_B_STG2_5X1_MASKS);
+
+ __raw_writel(0x001F1F1F, pxp->base + HW_PXP_WFE_B_STAGE2_5X6_MASKS_0);
+ __raw_writel(0x3f232120, pxp->base + HW_PXP_WFE_B_STAGE2_5X6_ADDR_0);
+
+ __raw_writel(0x04040404, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT0_0);
+ __raw_writel(0x04040404, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT0_1);
+ __raw_writel(0x04050505, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT0_2);
+ __raw_writel(0x04040404, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT0_3);
+ __raw_writel(0x04040404, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT0_4);
+ __raw_writel(0x04040404, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT0_5);
+ __raw_writel(0x04040404, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT0_6);
+ __raw_writel(0x04040404, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT0_7);
+
+ __raw_writel(0x05050505, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT1_0);
+ __raw_writel(0x05050505, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT1_1);
+ __raw_writel(0x05080808, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT1_2);
+ __raw_writel(0x05050505, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT1_3);
+ __raw_writel(0x05050505, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT1_4);
+ __raw_writel(0x05050505, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT1_5);
+ __raw_writel(0x05050505, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT1_6);
+ __raw_writel(0x05050505, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT1_7);
+
+ __raw_writel(0x07070707, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT2_0);
+ __raw_writel(0x07070707, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT2_1);
+ __raw_writel(0x070C0C0C, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT2_2);
+ __raw_writel(0x07070707, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT2_3);
+ __raw_writel(0x0F0F0F0F, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT2_4);
+ __raw_writel(0x0F0F0F0F, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT2_5);
+ __raw_writel(0x0F0F0F0F, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT2_6);
+ __raw_writel(0x0F0F0F0F, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT2_7);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT3_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT3_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT3_2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT3_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT3_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT3_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT3_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT3_7);
+
+ __raw_writel(0x070F1F1F, pxp->base + HW_PXP_WFE_B_STG3_F8X1_MASKS);
+
+ __raw_writel(0x00000700, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT0_0);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT0_1);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT0_2);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT0_3);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT0_4);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT0_5);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT0_6);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT0_7);
+
+ __raw_writel(0x00007000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT1_0);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT1_1);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT1_2);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT1_3);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT1_4);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT1_5);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT1_6);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT1_7);
+
+ __raw_writel(0x0000A000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT2_0);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT2_1);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT2_2);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT2_3);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT2_4);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT2_5);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT2_6);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT2_7);
+
+ __raw_writel(0x000000C0, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT3_0);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT3_1);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT3_2);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT3_3);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT3_4);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT3_5);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT3_6);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT3_7);
+
+ if (pxp->devdata && pxp->devdata->pxp_lut_cleanup_multiple)
+ pxp->devdata->pxp_lut_cleanup_multiple(pxp,
+ proc_data->lut_sels, 1);
+}
+
+/*
+ * wfe a processing
+ * use wfe a to process an update
+ * x,y,width,height:
+ * coordinate and size of the update region
+ * wb:
+ * working buffer, 16bpp
+ * upd:
+ * update buffer, in Y4 with or without alpha, 8bpp
+ * twb:
+ * temp working buffer, 16bpp
+ * only used when reagl_en is 1
+ * y4c:
+ * y4c buffer, {Y4[3:0],3'b000,collision}, 8bpp
+ * lut:
+ * valid value 0-63
+ * set to the lut used for next update
+ * partial:
+ * 0 - full update
+ * 1 - partial update
+ * reagl_en:
+ * 0 - use normal waveform algorithm
+ * 1 - enable reagl/-d waveform algorithm
+ * detection_only:
+ * 0 - write working buffer
+ * 1 - do no write working buffer, detection only
+ * alpha_en:
+ * 0 - upd is {Y4[3:0],4'b0000} format
+ * 1 - upd is {Y4[3:0],3'b000,alpha} format
+ */
+static void pxp_wfe_a_process(struct pxps *pxp)
+{
+ struct pxp_config_data *config_data = &pxp->pxp_conf_state;
+ struct pxp_proc_data *proc_data = &config_data->proc_data;
+ struct pxp_layer_param *fetch_ch0 = &config_data->wfe_a_fetch_param[0];
+ struct pxp_layer_param *fetch_ch1 = &config_data->wfe_a_fetch_param[1];
+ struct pxp_layer_param *store_ch0 = &config_data->wfe_a_store_param[0];
+ struct pxp_layer_param *store_ch1 = &config_data->wfe_a_store_param[1];
+ int v;
+
+ if (fetch_ch0->width != fetch_ch1->width ||
+ fetch_ch0->height != fetch_ch1->height) {
+ dev_err(pxp->dev, "width/height should be same for two fetch "
+ "channels\n");
+ }
+
+ print_param(fetch_ch0, "wfe_a fetch_ch0");
+ print_param(fetch_ch1, "wfe_a fetch_ch1");
+ print_param(store_ch0, "wfe_a store_ch0");
+ print_param(store_ch1, "wfe_a store_ch1");
+
+ /* Fetch */
+ __raw_writel(fetch_ch0->paddr, pxp->base + HW_PXP_WFA_FETCH_BUF1_ADDR);
+
+ __raw_writel(BF_PXP_WFA_FETCH_BUF1_CORD_YCORD(fetch_ch0->top) |
+ BF_PXP_WFA_FETCH_BUF1_CORD_XCORD(fetch_ch0->left),
+ pxp->base + HW_PXP_WFA_FETCH_BUF1_CORD);
+
+ __raw_writel(fetch_ch0->stride, pxp->base + HW_PXP_WFA_FETCH_BUF1_PITCH);
+
+ __raw_writel(BF_PXP_WFA_FETCH_BUF1_SIZE_BUF_HEIGHT(fetch_ch0->height - 1) |
+ BF_PXP_WFA_FETCH_BUF1_SIZE_BUF_WIDTH(fetch_ch0->width - 1),
+ pxp->base + HW_PXP_WFA_FETCH_BUF1_SIZE);
+
+ __raw_writel(fetch_ch1->paddr, pxp->base + HW_PXP_WFA_FETCH_BUF2_ADDR);
+
+ __raw_writel(BF_PXP_WFA_FETCH_BUF2_CORD_YCORD(fetch_ch1->top) |
+ BF_PXP_WFA_FETCH_BUF2_CORD_XCORD(fetch_ch1->left),
+ pxp->base + HW_PXP_WFA_FETCH_BUF2_CORD);
+
+ __raw_writel(fetch_ch1->stride * 2, pxp->base + HW_PXP_WFA_FETCH_BUF2_PITCH);
+
+ __raw_writel(BF_PXP_WFA_FETCH_BUF2_SIZE_BUF_HEIGHT(fetch_ch1->height - 1) |
+ BF_PXP_WFA_FETCH_BUF2_SIZE_BUF_WIDTH(fetch_ch1->width - 1),
+ pxp->base + HW_PXP_WFA_FETCH_BUF2_SIZE);
+
+ /* Store */
+ __raw_writel(BF_PXP_WFE_A_STORE_SIZE_CH0_OUT_WIDTH(store_ch0->width - 1) |
+ BF_PXP_WFE_A_STORE_SIZE_CH0_OUT_HEIGHT(store_ch0->height - 1),
+ pxp->base + HW_PXP_WFE_A_STORE_SIZE_CH0);
+
+
+ __raw_writel(BF_PXP_WFE_A_STORE_SIZE_CH1_OUT_WIDTH(store_ch1->width - 1) |
+ BF_PXP_WFE_A_STORE_SIZE_CH1_OUT_HEIGHT(store_ch1->height - 1),
+ pxp->base + HW_PXP_WFE_A_STORE_SIZE_CH1);
+
+ __raw_writel(BF_PXP_WFE_A_STORE_PITCH_CH0_OUT_PITCH(store_ch0->stride) |
+ BF_PXP_WFE_A_STORE_PITCH_CH1_OUT_PITCH(store_ch1->stride * 2),
+ pxp->base + HW_PXP_WFE_A_STORE_PITCH);
+
+ __raw_writel(BF_PXP_WFE_A_STORE_ADDR_0_CH0_OUT_BASE_ADDR0(store_ch0->paddr),
+ pxp->base + HW_PXP_WFE_A_STORE_ADDR_0_CH0);
+ __raw_writel(BF_PXP_WFE_A_STORE_ADDR_1_CH0_OUT_BASE_ADDR1(0),
+ pxp->base + HW_PXP_WFE_A_STORE_ADDR_1_CH0);
+
+ __raw_writel(BF_PXP_WFE_A_STORE_ADDR_0_CH1_OUT_BASE_ADDR0(
+ store_ch1->paddr + (store_ch1->left + store_ch1->top *
+ store_ch1->stride) * 2),
+ pxp->base + HW_PXP_WFE_A_STORE_ADDR_0_CH1);
+
+ __raw_writel(BF_PXP_WFE_A_STORE_ADDR_1_CH1_OUT_BASE_ADDR1(0),
+ pxp->base + HW_PXP_WFE_A_STORE_ADDR_1_CH1);
+
+ /* ALU */
+ __raw_writel(BF_PXP_ALU_A_BUF_SIZE_BUF_WIDTH(fetch_ch0->width) |
+ BF_PXP_ALU_A_BUF_SIZE_BUF_HEIGHT(fetch_ch0->height),
+ pxp->base + HW_PXP_ALU_A_BUF_SIZE);
+
+ /* WFE */
+ __raw_writel(BF_PXP_WFE_A_DIMENSIONS_WIDTH(fetch_ch0->width) |
+ BF_PXP_WFE_A_DIMENSIONS_HEIGHT(fetch_ch0->height),
+ pxp->base + HW_PXP_WFE_A_DIMENSIONS);
+
+ /* Here it should be fetch_ch1 */
+ __raw_writel(BF_PXP_WFE_A_OFFSET_X_OFFSET(fetch_ch1->left) |
+ BF_PXP_WFE_A_OFFSET_Y_OFFSET(fetch_ch1->top),
+ pxp->base + HW_PXP_WFE_A_OFFSET);
+
+ __raw_writel((proc_data->lut & 0x000000FF) | 0x00000F00,
+ pxp->base + HW_PXP_WFE_A_SW_DATA_REGS);
+ __raw_writel((proc_data->partial_update | (proc_data->reagl_en << 1)),
+ pxp->base + HW_PXP_WFE_A_SW_FLAG_REGS);
+
+ __raw_writel(
+ BF_PXP_WFE_A_CTRL_ENABLE(1) |
+ BF_PXP_WFE_A_CTRL_SW_RESET(1),
+ pxp->base + HW_PXP_WFE_A_CTRL);
+
+ if (proc_data->alpha_en) {
+ __raw_writel(BF_PXP_WFA_ARRAY_FLAG0_MASK_SIGN_Y(0) |
+ BF_PXP_WFA_ARRAY_FLAG0_MASK_OFFSET_Y(0) |
+ BF_PXP_WFA_ARRAY_FLAG0_MASK_SIGN_X(0) |
+ BF_PXP_WFA_ARRAY_FLAG0_MASK_OFFSET_X(0) |
+ BF_PXP_WFA_ARRAY_FLAG0_MASK_BUF_SEL(0) |
+ BF_PXP_WFA_ARRAY_FLAG0_MASK_H_OFS(0) |
+ BF_PXP_WFA_ARRAY_FLAG0_MASK_L_OFS(0),
+ pxp->base + HW_PXP_WFA_ARRAY_FLAG0_MASK);
+ } else {
+ __raw_writel(BF_PXP_WFA_ARRAY_FLAG0_MASK_SIGN_Y(0) |
+ BF_PXP_WFA_ARRAY_FLAG0_MASK_OFFSET_Y(0) |
+ BF_PXP_WFA_ARRAY_FLAG0_MASK_SIGN_X(0) |
+ BF_PXP_WFA_ARRAY_FLAG0_MASK_OFFSET_X(0) |
+ BF_PXP_WFA_ARRAY_FLAG0_MASK_BUF_SEL(2) |
+ BF_PXP_WFA_ARRAY_FLAG0_MASK_H_OFS(0) |
+ BF_PXP_WFA_ARRAY_FLAG0_MASK_L_OFS(0),
+ pxp->base + HW_PXP_WFA_ARRAY_FLAG0_MASK);
+ }
+
+ /* disable CH1 when only doing detection */
+ v = __raw_readl(pxp->base + HW_PXP_WFE_A_STORE_CTRL_CH1);
+ if (proc_data->detection_only) {
+ v &= ~BF_PXP_WFE_A_STORE_CTRL_CH1_CH_EN(1);
+ printk(KERN_EMERG "%s: detection only happens\n", __func__);
+ } else
+ v |= BF_PXP_WFE_A_STORE_CTRL_CH1_CH_EN(1);
+ __raw_writel(v, pxp->base + HW_PXP_WFE_A_STORE_CTRL_CH1);
+}
+
+static void pxp_wfe_a_process_v3p(struct pxps *pxp)
+{
+ struct pxp_config_data *config_data = &pxp->pxp_conf_state;
+ struct pxp_proc_data *proc_data = &config_data->proc_data;
+ struct pxp_layer_param *fetch_ch0 = &config_data->wfe_a_fetch_param[0];
+ struct pxp_layer_param *fetch_ch1 = &config_data->wfe_a_fetch_param[1];
+ struct pxp_layer_param *store_ch0 = &config_data->wfe_a_store_param[0];
+ struct pxp_layer_param *store_ch1 = &config_data->wfe_a_store_param[1];
+ int v;
+
+ if (fetch_ch0->width != fetch_ch1->width ||
+ fetch_ch0->height != fetch_ch1->height) {
+ dev_err(pxp->dev, "width/height should be same for two fetch "
+ "channels\n");
+ }
+
+ print_param(fetch_ch0, "wfe_a fetch_ch0");
+ print_param(fetch_ch1, "wfe_a fetch_ch1");
+ print_param(store_ch0, "wfe_a store_ch0");
+ print_param(store_ch1, "wfe_a store_ch1");
+
+ /* Fetch */
+ __raw_writel(fetch_ch0->paddr, pxp->base + HW_PXP_WFB_FETCH_BUF1_ADDR);
+
+ __raw_writel(BF_PXP_WFB_FETCH_BUF1_CORD_YCORD(fetch_ch0->top) |
+ BF_PXP_WFB_FETCH_BUF1_CORD_XCORD(fetch_ch0->left),
+ pxp->base + HW_PXP_WFB_FETCH_BUF1_CORD);
+
+ __raw_writel(fetch_ch0->stride, pxp->base + HW_PXP_WFB_FETCH_BUF1_PITCH);
+
+ __raw_writel(BF_PXP_WFB_FETCH_BUF1_SIZE_BUF_HEIGHT(fetch_ch0->height - 1) |
+ BF_PXP_WFB_FETCH_BUF1_SIZE_BUF_WIDTH(fetch_ch0->width - 1),
+ pxp->base + HW_PXP_WFB_FETCH_BUF1_SIZE);
+
+ __raw_writel(fetch_ch1->paddr, pxp->base + HW_PXP_WFB_FETCH_BUF2_ADDR);
+
+ __raw_writel(BF_PXP_WFB_FETCH_BUF2_CORD_YCORD(fetch_ch1->top) |
+ BF_PXP_WFB_FETCH_BUF2_CORD_XCORD(fetch_ch1->left),
+ pxp->base + HW_PXP_WFB_FETCH_BUF2_CORD);
+
+ __raw_writel(fetch_ch1->stride * 2, pxp->base + HW_PXP_WFB_FETCH_BUF2_PITCH);
+
+ __raw_writel(BF_PXP_WFB_FETCH_BUF2_SIZE_BUF_HEIGHT(fetch_ch1->height - 1) |
+ BF_PXP_WFB_FETCH_BUF2_SIZE_BUF_WIDTH(fetch_ch1->width - 1),
+ pxp->base + HW_PXP_WFB_FETCH_BUF2_SIZE);
+
+ /* Store */
+ __raw_writel(BF_PXP_WFE_B_STORE_SIZE_CH0_OUT_WIDTH(store_ch0->width - 1) |
+ BF_PXP_WFE_B_STORE_SIZE_CH0_OUT_HEIGHT(store_ch0->height - 1),
+ pxp->base + HW_PXP_WFE_B_STORE_SIZE_CH0);
+
+
+ __raw_writel(BF_PXP_WFE_B_STORE_SIZE_CH1_OUT_WIDTH(store_ch1->width - 1) |
+ BF_PXP_WFE_B_STORE_SIZE_CH1_OUT_HEIGHT(store_ch1->height - 1),
+ pxp->base + HW_PXP_WFE_B_STORE_SIZE_CH1);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_PITCH_CH0_OUT_PITCH(store_ch0->stride) |
+ BF_PXP_WFE_B_STORE_PITCH_CH1_OUT_PITCH(store_ch1->stride * 2),
+ pxp->base + HW_PXP_WFE_B_STORE_PITCH);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_ADDR_0_CH0_OUT_BASE_ADDR0(store_ch0->paddr),
+ pxp->base + HW_PXP_WFE_B_STORE_ADDR_0_CH0);
+ __raw_writel(BF_PXP_WFE_B_STORE_ADDR_1_CH0_OUT_BASE_ADDR1(0),
+ pxp->base + HW_PXP_WFE_B_STORE_ADDR_1_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_ADDR_0_CH1_OUT_BASE_ADDR0(
+ store_ch1->paddr + (store_ch1->left + store_ch1->top *
+ store_ch1->stride) * 2),
+ pxp->base + HW_PXP_WFE_B_STORE_ADDR_0_CH1);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_ADDR_1_CH1_OUT_BASE_ADDR1(0),
+ pxp->base + HW_PXP_WFE_B_STORE_ADDR_1_CH1);
+
+ /* ALU */
+ __raw_writel(BF_PXP_ALU_B_BUF_SIZE_BUF_WIDTH(fetch_ch0->width) |
+ BF_PXP_ALU_B_BUF_SIZE_BUF_HEIGHT(fetch_ch0->height),
+ pxp->base + HW_PXP_ALU_B_BUF_SIZE);
+
+ /* WFE */
+ __raw_writel(BF_PXP_WFE_B_DIMENSIONS_WIDTH(fetch_ch0->width) |
+ BF_PXP_WFE_B_DIMENSIONS_HEIGHT(fetch_ch0->height),
+ pxp->base + HW_PXP_WFE_B_DIMENSIONS);
+
+ /* Here it should be fetch_ch1 */
+ __raw_writel(BF_PXP_WFE_B_OFFSET_X_OFFSET(fetch_ch1->left) |
+ BF_PXP_WFE_B_OFFSET_Y_OFFSET(fetch_ch1->top),
+ pxp->base + HW_PXP_WFE_B_OFFSET);
+
+ __raw_writel((proc_data->lut & 0x000000FF) | 0x00000F00,
+ pxp->base + HW_PXP_WFE_B_SW_DATA_REGS);
+ __raw_writel((proc_data->partial_update | (proc_data->reagl_en << 1)),
+ pxp->base + HW_PXP_WFE_B_SW_FLAG_REGS);
+
+ __raw_writel(
+ BF_PXP_WFE_B_CTRL_ENABLE(1) |
+ BF_PXP_WFE_B_CTRL_SW_RESET(1),
+ pxp->base + HW_PXP_WFE_B_CTRL);
+
+ if (proc_data->alpha_en) {
+ __raw_writel(BF_PXP_WFB_ARRAY_FLAG0_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_BUF_SEL(0) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_H_OFS(0) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_L_OFS(0),
+ pxp->base + HW_PXP_WFB_ARRAY_FLAG0_MASK);
+ } else {
+ __raw_writel(BF_PXP_WFB_ARRAY_FLAG0_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_BUF_SEL(2) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_H_OFS(0) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_L_OFS(0),
+ pxp->base + HW_PXP_WFB_ARRAY_FLAG0_MASK);
+ }
+
+ /* disable CH1 when only doing detection */
+ v = __raw_readl(pxp->base + HW_PXP_WFE_B_STORE_CTRL_CH1);
+ if (proc_data->detection_only) {
+ v &= ~BF_PXP_WFE_B_STORE_CTRL_CH1_CH_EN(1);
+ printk(KERN_EMERG "%s: detection only happens\n", __func__);
+ } else
+ v |= BF_PXP_WFE_B_STORE_CTRL_CH1_CH_EN(1);
+ __raw_writel(v, pxp->base + HW_PXP_WFE_B_STORE_CTRL_CH1);
+}
+
+/*
+ * wfe b configuration
+ *
+ * configure wfe b engnine for reagl/-d waveform processing
+ */
+static void pxp_wfe_b_configure(struct pxps *pxp)
+{
+ /* Fetch */
+ __raw_writel(
+ BF_PXP_WFB_FETCH_CTRL_BF1_EN(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_HSK_MODE(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BYTES_PP(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_LINE_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_SRAM_IF(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BURST_LEN(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BYPASS_MODE(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BORDER_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_EN(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_HSK_MODE(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BYTES_PP(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_LINE_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_SRAM_IF(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BURST_LEN(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BORDER_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BYPASS_MODE(0),
+ pxp->base + HW_PXP_WFB_FETCH_CTRL);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_PIXEL0_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL0_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL0_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL0_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL0_MASK_BUF_SEL(1) |
+ BF_PXP_WFB_ARRAY_PIXEL0_MASK_H_OFS(0) |
+ BF_PXP_WFB_ARRAY_PIXEL0_MASK_L_OFS(7),
+ pxp->base + HW_PXP_WFB_ARRAY_PIXEL0_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_PIXEL1_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL1_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL1_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL1_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL1_MASK_BUF_SEL(1) |
+ BF_PXP_WFB_ARRAY_PIXEL1_MASK_H_OFS(10) |
+ BF_PXP_WFB_ARRAY_PIXEL1_MASK_L_OFS(15),
+ pxp->base + HW_PXP_WFB_ARRAY_PIXEL1_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_PIXEL2_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL2_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL2_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL2_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL2_MASK_BUF_SEL(0) |
+ BF_PXP_WFB_ARRAY_PIXEL2_MASK_H_OFS(2) |
+ BF_PXP_WFB_ARRAY_PIXEL2_MASK_L_OFS(7),
+ pxp->base + HW_PXP_WFB_ARRAY_PIXEL2_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_PIXEL3_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL3_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL3_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL3_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL3_MASK_BUF_SEL(0) |
+ BF_PXP_WFB_ARRAY_PIXEL3_MASK_H_OFS(0) |
+ BF_PXP_WFB_ARRAY_PIXEL3_MASK_L_OFS(7),
+ pxp->base + HW_PXP_WFB_ARRAY_PIXEL3_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_PIXEL4_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL4_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL4_MASK_SIGN_X(1) |
+ BF_PXP_WFB_ARRAY_PIXEL4_MASK_OFFSET_X(1) |
+ BF_PXP_WFB_ARRAY_PIXEL4_MASK_BUF_SEL(0) |
+ BF_PXP_WFB_ARRAY_PIXEL4_MASK_H_OFS(0) |
+ BF_PXP_WFB_ARRAY_PIXEL4_MASK_L_OFS(7),
+ pxp->base + HW_PXP_WFB_ARRAY_PIXEL4_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_PIXEL5_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL5_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL5_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL5_MASK_OFFSET_X(1) |
+ BF_PXP_WFB_ARRAY_PIXEL5_MASK_BUF_SEL(0) |
+ BF_PXP_WFB_ARRAY_PIXEL5_MASK_H_OFS(0) |
+ BF_PXP_WFB_ARRAY_PIXEL5_MASK_L_OFS(7),
+ pxp->base + HW_PXP_WFB_ARRAY_PIXEL5_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_PIXEL6_MASK_SIGN_Y(1) |
+ BF_PXP_WFB_ARRAY_PIXEL6_MASK_OFFSET_Y(1) |
+ BF_PXP_WFB_ARRAY_PIXEL6_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL6_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL6_MASK_BUF_SEL(0) |
+ BF_PXP_WFB_ARRAY_PIXEL6_MASK_H_OFS(0) |
+ BF_PXP_WFB_ARRAY_PIXEL6_MASK_L_OFS(7),
+ pxp->base + HW_PXP_WFB_ARRAY_PIXEL6_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_PIXEL7_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_PIXEL7_MASK_OFFSET_Y(1) |
+ BF_PXP_WFB_ARRAY_PIXEL7_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL7_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_PIXEL7_MASK_BUF_SEL(0) |
+ BF_PXP_WFB_ARRAY_PIXEL7_MASK_H_OFS(0) |
+ BF_PXP_WFB_ARRAY_PIXEL7_MASK_L_OFS(7),
+ pxp->base + HW_PXP_WFB_ARRAY_PIXEL7_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_BUF_SEL(1) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_H_OFS(8) |
+ BF_PXP_WFB_ARRAY_FLAG0_MASK_L_OFS(8),
+ pxp->base + HW_PXP_WFB_ARRAY_FLAG0_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_FLAG1_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG1_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG1_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG1_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG1_MASK_BUF_SEL(1) |
+ BF_PXP_WFB_ARRAY_FLAG1_MASK_H_OFS(9) |
+ BF_PXP_WFB_ARRAY_FLAG1_MASK_L_OFS(9),
+ pxp->base + HW_PXP_WFB_ARRAY_FLAG1_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_FLAG2_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG2_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG2_MASK_SIGN_X(1) |
+ BF_PXP_WFB_ARRAY_FLAG2_MASK_OFFSET_X(1) |
+ BF_PXP_WFB_ARRAY_FLAG2_MASK_BUF_SEL(1) |
+ BF_PXP_WFB_ARRAY_FLAG2_MASK_H_OFS(8) |
+ BF_PXP_WFB_ARRAY_FLAG2_MASK_L_OFS(8),
+ pxp->base + HW_PXP_WFB_ARRAY_FLAG2_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_FLAG3_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG3_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG3_MASK_SIGN_X(1) |
+ BF_PXP_WFB_ARRAY_FLAG3_MASK_OFFSET_X(1) |
+ BF_PXP_WFB_ARRAY_FLAG3_MASK_BUF_SEL(1) |
+ BF_PXP_WFB_ARRAY_FLAG3_MASK_H_OFS(9) |
+ BF_PXP_WFB_ARRAY_FLAG3_MASK_L_OFS(9),
+ pxp->base + HW_PXP_WFB_ARRAY_FLAG3_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_FLAG4_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG4_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG4_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG4_MASK_OFFSET_X(1) |
+ BF_PXP_WFB_ARRAY_FLAG4_MASK_BUF_SEL(1) |
+ BF_PXP_WFB_ARRAY_FLAG4_MASK_H_OFS(8) |
+ BF_PXP_WFB_ARRAY_FLAG4_MASK_L_OFS(8),
+ pxp->base + HW_PXP_WFB_ARRAY_FLAG4_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_FLAG5_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG5_MASK_OFFSET_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG5_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG5_MASK_OFFSET_X(1) |
+ BF_PXP_WFB_ARRAY_FLAG5_MASK_BUF_SEL(1) |
+ BF_PXP_WFB_ARRAY_FLAG5_MASK_H_OFS(9) |
+ BF_PXP_WFB_ARRAY_FLAG5_MASK_L_OFS(9),
+ pxp->base + HW_PXP_WFB_ARRAY_FLAG5_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_FLAG6_MASK_SIGN_Y(1) |
+ BF_PXP_WFB_ARRAY_FLAG6_MASK_OFFSET_Y(1) |
+ BF_PXP_WFB_ARRAY_FLAG6_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG6_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG6_MASK_BUF_SEL(1) |
+ BF_PXP_WFB_ARRAY_FLAG6_MASK_H_OFS(8) |
+ BF_PXP_WFB_ARRAY_FLAG6_MASK_L_OFS(8),
+ pxp->base + HW_PXP_WFB_ARRAY_FLAG6_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_FLAG7_MASK_SIGN_Y(1) |
+ BF_PXP_WFB_ARRAY_FLAG7_MASK_OFFSET_Y(1) |
+ BF_PXP_WFB_ARRAY_FLAG7_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG7_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG7_MASK_BUF_SEL(1) |
+ BF_PXP_WFB_ARRAY_FLAG7_MASK_H_OFS(9) |
+ BF_PXP_WFB_ARRAY_FLAG7_MASK_L_OFS(9),
+ pxp->base + HW_PXP_WFB_ARRAY_FLAG7_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_FLAG8_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG8_MASK_OFFSET_Y(1) |
+ BF_PXP_WFB_ARRAY_FLAG8_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG8_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG8_MASK_BUF_SEL(1) |
+ BF_PXP_WFB_ARRAY_FLAG8_MASK_H_OFS(8) |
+ BF_PXP_WFB_ARRAY_FLAG8_MASK_L_OFS(8),
+ pxp->base + HW_PXP_WFB_ARRAY_FLAG8_MASK);
+
+ __raw_writel(
+ BF_PXP_WFB_ARRAY_FLAG9_MASK_SIGN_Y(0) |
+ BF_PXP_WFB_ARRAY_FLAG9_MASK_OFFSET_Y(1) |
+ BF_PXP_WFB_ARRAY_FLAG9_MASK_SIGN_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG9_MASK_OFFSET_X(0) |
+ BF_PXP_WFB_ARRAY_FLAG9_MASK_BUF_SEL(1) |
+ BF_PXP_WFB_ARRAY_FLAG9_MASK_H_OFS(9) |
+ BF_PXP_WFB_ARRAY_FLAG9_MASK_L_OFS(9),
+ pxp->base + HW_PXP_WFB_ARRAY_FLAG9_MASK);
+
+ pxp_sram_init(pxp, WFE_B, (u32)active_matrix_data_8x8, 64);
+
+ /* Store */
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_CTRL_CH0_CH_EN(1)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_BLOCK_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_BLOCK_16(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_HANDSHAKE_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_LINE_NUM(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_STORE_BYPASS_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_STORE_MEMORY_EN(1)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_PACK_IN_SEL(1)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_FILL_DATA_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_WR_NUM_BYTES(32)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_COMBINE_2CHANNEL(1) |
+ BF_PXP_WFE_B_STORE_CTRL_CH0_ARBIT_EN(0),
+ pxp->base + HW_PXP_WFE_B_STORE_CTRL_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_CTRL_CH1_CH_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_BLOCK_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_BLOCK_16(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_HANDSHAKE_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_LINE_NUM(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_STORE_BYPASS_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_STORE_MEMORY_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_PACK_IN_SEL(1)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_WR_NUM_BYTES(32),
+ pxp->base + HW_PXP_WFE_B_STORE_CTRL_CH1);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP(1)|
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN(0)|
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN(0)|
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS(0),
+ pxp->base + HW_PXP_WFE_B_STORE_SHIFT_CTRL_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP(1)|
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN(0)|
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN(0)|
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS(0),
+ pxp->base + HW_PXP_WFE_B_STORE_SHIFT_CTRL_CH1);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_ADDR_1_CH0_OUT_BASE_ADDR1(0),
+ pxp->base + HW_PXP_WFE_B_STORE_ADDR_1_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_ADDR_0_CH1_OUT_BASE_ADDR0(0),
+ pxp->base + HW_PXP_WFE_B_STORE_ADDR_0_CH1);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_ADDR_1_CH1_OUT_BASE_ADDR1(0),
+ pxp->base + HW_PXP_WFE_B_STORE_ADDR_1_CH1);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_FILL_DATA_CH0_FILL_DATA_CH0(0),
+ pxp->base + HW_PXP_WFE_B_STORE_FILL_DATA_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0(0x00000000),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK0_H_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0(0xff),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK0_L_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0(0x0),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK1_H_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0(0x3f00),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK1_L_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0(0x0),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK2_H_CH0);
+
+ __raw_writel(BF_PXP_WFE_B_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0(0x0),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK2_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4(0) |
+ BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG4(0) |
+ BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5(0)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG5(0) |
+ BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6(0)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG6(0)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7(0)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG7(0),
+ pxp->base + HW_PXP_WFE_B_STORE_D_SHIFT_H_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0(0) |
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0(0) |
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1(2)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1(1) |
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2(6)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2(0)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3(0)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3(0),
+ pxp->base + HW_PXP_WFE_B_STORE_D_SHIFT_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0(8)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0(1)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3(0),
+ pxp->base + HW_PXP_WFE_B_STORE_F_SHIFT_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK4(0)|
+ BF_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK5(0)|
+ BF_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK6(0)|
+ BF_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK7(0),
+ pxp->base + HW_PXP_WFE_B_STORE_F_MASK_H_CH0);
+
+ /* ALU */
+ __raw_writel(BF_PXP_ALU_B_INST_ENTRY_ENTRY_ADDR(0),
+ pxp->base + HW_PXP_ALU_B_INST_ENTRY);
+
+ __raw_writel(BF_PXP_ALU_B_PARAM_PARAM0(0) |
+ BF_PXP_ALU_B_PARAM_PARAM1(0),
+ pxp->base + HW_PXP_ALU_B_PARAM);
+
+ __raw_writel(BF_PXP_ALU_B_CONFIG_BUF_ADDR(0),
+ pxp->base + HW_PXP_ALU_B_CONFIG);
+
+ __raw_writel(BF_PXP_ALU_B_LUT_CONFIG_MODE(0) |
+ BF_PXP_ALU_B_LUT_CONFIG_EN(0),
+ pxp->base + HW_PXP_ALU_B_LUT_CONFIG);
+
+ __raw_writel(BF_PXP_ALU_B_LUT_DATA0_LUT_DATA_L(0),
+ pxp->base + HW_PXP_ALU_B_LUT_DATA0);
+
+ __raw_writel(BF_PXP_ALU_B_LUT_DATA1_LUT_DATA_H(0),
+ pxp->base + HW_PXP_ALU_B_LUT_DATA1);
+
+ __raw_writel(
+ BF_PXP_ALU_B_CTRL_BYPASS (1) |
+ BF_PXP_ALU_B_CTRL_ENABLE (1) |
+ BF_PXP_ALU_B_CTRL_START (0) |
+ BF_PXP_ALU_B_CTRL_SW_RESET (0),
+ pxp->base + HW_PXP_ALU_B_CTRL);
+
+ /* WFE */
+ __raw_writel(0x00000402, pxp->base + HW_PXP_WFE_B_SW_DATA_REGS);
+
+ __raw_writel(0x02040608, pxp->base + HW_PXP_WFE_B_STAGE1_MUX0);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE1_MUX1);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE1_MUX2);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE1_MUX3);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE1_MUX4);
+ __raw_writel(0x03000000, pxp->base + HW_PXP_WFE_B_STAGE1_MUX5);
+ __raw_writel(0x050A040A, pxp->base + HW_PXP_WFE_B_STAGE1_MUX6);
+ __raw_writel(0x070A060A, pxp->base + HW_PXP_WFE_B_STAGE1_MUX7);
+ __raw_writel(0x0000000A, pxp->base + HW_PXP_WFE_B_STAGE1_MUX8);
+
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE2_MUX0);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE2_MUX1);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE2_MUX2);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE2_MUX3);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE2_MUX4);
+ __raw_writel(0x1C1E2022, pxp->base + HW_PXP_WFE_B_STAGE2_MUX5);
+ __raw_writel(0x1215181A, pxp->base + HW_PXP_WFE_B_STAGE2_MUX6);
+ __raw_writel(0x00000C0F, pxp->base + HW_PXP_WFE_B_STAGE2_MUX7);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE2_MUX8);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE2_MUX9);
+ __raw_writel(0x01000000, pxp->base + HW_PXP_WFE_B_STAGE2_MUX10);
+ __raw_writel(0x000C010B, pxp->base + HW_PXP_WFE_B_STAGE2_MUX11);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE2_MUX12);
+
+ __raw_writel(0x09000C01, pxp->base + HW_PXP_WFE_B_STAGE3_MUX0);
+ __raw_writel(0x003A2A1D, pxp->base + HW_PXP_WFE_B_STAGE3_MUX1);
+ __raw_writel(0x09000C01, pxp->base + HW_PXP_WFE_B_STAGE3_MUX2);
+ __raw_writel(0x003A2A1D, pxp->base + HW_PXP_WFE_B_STAGE3_MUX3);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE3_MUX4);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE3_MUX5);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE3_MUX6);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STAGE3_MUX7);
+ __raw_writel(0x07060504, pxp->base + HW_PXP_WFE_B_STAGE3_MUX8);
+ __raw_writel(0x00000008, pxp->base + HW_PXP_WFE_B_STAGE3_MUX9);
+ __raw_writel(0x00001211, pxp->base + HW_PXP_WFE_B_STAGE3_MUX10);
+
+ __raw_writel(0x02010100, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT0_0);
+ __raw_writel(0x03020201, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT0_1);
+ __raw_writel(0x03020201, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT0_2);
+ __raw_writel(0x04030302, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT0_3);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT0_4);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT0_5);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT0_6);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT0_7);
+
+ __raw_writel(0x02010100, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT1_0);
+ __raw_writel(0x03020201, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT1_1);
+ __raw_writel(0x03020201, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT1_2);
+ __raw_writel(0x04030302, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT1_3);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT1_4);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT1_5);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT1_6);
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X8_OUT1_7);
+
+ __raw_writel(0x0000000F, pxp->base + HW_PXP_WFE_B_STAGE1_5X8_MASKS_0);
+
+ __raw_writel(0x00000000, pxp->base + HW_PXP_WFE_B_STG1_5X1_OUT0);
+ __raw_writel(0x0000000F, pxp->base + HW_PXP_WFE_B_STG1_5X1_MASKS);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT0_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT0_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT0_2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT0_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT0_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT0_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT0_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT0_7);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_7);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT2_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT2_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT2_2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT2_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT2_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT2_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT2_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT2_7);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT3_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT3_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT3_2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT3_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT3_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT3_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT3_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT3_7);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT4_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT4_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT4_2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT4_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT4_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT4_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT4_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT4_7);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STAGE2_5X6_MASKS_0);
+ __raw_writel(0x3F3F3F3F, pxp->base + HW_PXP_WFE_B_STAGE2_5X6_ADDR_0);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT0_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT0_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT0_2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT0_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT0_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT0_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT0_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT0_7);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT1_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT1_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT1_2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT1_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT1_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT1_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT1_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X6_OUT1_7);
+
+ __raw_writel(0x00008000, pxp->base + HW_PXP_WFE_B_STG2_5X1_OUT0);
+ __raw_writel(0x0000FFFE, pxp->base + HW_PXP_WFE_B_STG2_5X1_OUT1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X1_OUT2);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG2_5X1_OUT3);
+ __raw_writel(0x00000F0F, pxp->base + HW_PXP_WFE_B_STG2_5X1_MASKS);
+
+ __raw_writel(0x00007F7F, pxp->base + HW_PXP_WFE_B_STG3_F8X1_MASKS);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT0_0);
+ __raw_writel(0x00FF00FF, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT0_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT0_2);
+ __raw_writel(0x000000FF, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT0_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT0_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT0_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT0_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT0_7);
+
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT1_0);
+ __raw_writel(0xFF3FFF3F, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT1_1);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT1_2);
+ __raw_writel(0xFFFFFF1F, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT1_3);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT1_4);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT1_5);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT1_6);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG3_F8X1_OUT1_7);
+
+ __raw_writel(
+ BF_PXP_WFE_B_CTRL_ENABLE(1) |
+ BF_PXP_WFE_B_CTRL_SW_RESET(1),
+ pxp->base + HW_PXP_WFE_B_CTRL);
+}
+
+/* wfe b processing
+ * use wfe b to process an update
+ * call this function only after pxp_wfe_a_processing
+ * x,y,width,height:
+ * coordinate and size of the update region
+ * twb:
+ * temp working buffer, 16bpp
+ * only used when reagl_en is 1
+ * wb:
+ * working buffer, 16bpp
+ * lut:
+ * lut buffer, 8bpp
+ * lut_update:
+ * 0 - wfe_b is used for reagl/reagl-d operation
+ * 1 - wfe_b is used for lut update operation
+ * reagl_d_en:
+ * 0 - use reagl waveform algorithm
+ * 1 - use reagl/-d waveform algorithm
+ */
+static void pxp_wfe_b_process(struct pxps *pxp)
+{
+ struct pxp_config_data *config_data = &pxp->pxp_conf_state;
+ struct pxp_proc_data *proc_data = &config_data->proc_data;
+ struct pxp_layer_param *fetch_ch0 = &config_data->wfe_b_fetch_param[0];
+ struct pxp_layer_param *fetch_ch1 = &config_data->wfe_b_fetch_param[1];
+ struct pxp_layer_param *store_ch0 = &config_data->wfe_b_store_param[0];
+ struct pxp_layer_param *store_ch1 = &config_data->wfe_b_store_param[1];
+ static int comp_mask;
+ /* Fetch */
+
+ print_param(fetch_ch0, "wfe_b fetch_ch0");
+ print_param(fetch_ch1, "wfe_b fetch_ch1");
+ print_param(store_ch0, "wfe_b store_ch0");
+ print_param(store_ch1, "wfe_b store_ch1");
+
+ __raw_writel(fetch_ch0->paddr, pxp->base + HW_PXP_WFB_FETCH_BUF1_ADDR);
+
+ __raw_writel(
+ BF_PXP_WFB_FETCH_BUF1_CORD_YCORD(fetch_ch0->top) |
+ BF_PXP_WFB_FETCH_BUF1_CORD_XCORD(fetch_ch0->left),
+ pxp->base + HW_PXP_WFB_FETCH_BUF1_CORD);
+
+ __raw_writel(fetch_ch0->stride,
+ pxp->base + HW_PXP_WFB_FETCH_BUF1_PITCH);
+
+ __raw_writel(
+ BF_PXP_WFB_FETCH_BUF1_SIZE_BUF_HEIGHT(fetch_ch0->height-1) |
+ BF_PXP_WFB_FETCH_BUF1_SIZE_BUF_WIDTH(fetch_ch0->width-1),
+ pxp->base + HW_PXP_WFB_FETCH_BUF1_SIZE);
+
+ __raw_writel(fetch_ch1->paddr, pxp->base + HW_PXP_WFB_FETCH_BUF2_ADDR);
+
+ __raw_writel(fetch_ch1->stride * 2,
+ pxp->base + HW_PXP_WFB_FETCH_BUF2_PITCH);
+
+ __raw_writel(
+ BF_PXP_WFB_FETCH_BUF2_CORD_YCORD(fetch_ch1->top) |
+ BF_PXP_WFB_FETCH_BUF2_CORD_XCORD(fetch_ch1->left),
+ pxp->base + HW_PXP_WFB_FETCH_BUF2_CORD);
+
+ __raw_writel(
+ BF_PXP_WFB_FETCH_BUF2_SIZE_BUF_HEIGHT(fetch_ch1->height-1) |
+ BF_PXP_WFB_FETCH_BUF2_SIZE_BUF_WIDTH(fetch_ch1->width-1),
+ pxp->base + HW_PXP_WFB_FETCH_BUF2_SIZE);
+
+ if (!proc_data->lut_update) {
+ __raw_writel(
+ BF_PXP_WFB_FETCH_CTRL_BF1_EN(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_HSK_MODE(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BYTES_PP(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_LINE_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_SRAM_IF(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BURST_LEN(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BYPASS_MODE(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BORDER_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_EN(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_HSK_MODE(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BYTES_PP(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_LINE_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_SRAM_IF(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BURST_LEN(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BORDER_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BYPASS_MODE(0),
+ pxp->base + HW_PXP_WFB_FETCH_CTRL);
+ } else {
+ __raw_writel(
+ BF_PXP_WFB_FETCH_CTRL_BF1_EN(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_HSK_MODE(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BYTES_PP(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_LINE_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_SRAM_IF(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BURST_LEN(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BORDER_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BYPASS_MODE(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_EN(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_HSK_MODE(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BYTES_PP(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_LINE_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_SRAM_IF(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BURST_LEN(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BORDER_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BYPASS_MODE(0),
+ pxp->base + HW_PXP_WFB_FETCH_CTRL);
+ }
+
+#ifdef CONFIG_REAGLD_ALGO_CHECK
+ __raw_writel(
+ (__raw_readl(pxp->base + HW_PXP_WFE_B_SW_DATA_REGS) & 0x0000FFFF) | ((fetch_ch0->comp_mask&0x000000FF)<<16),
+ pxp->base + HW_PXP_WFE_B_SW_DATA_REGS);
+#else
+ __raw_writel(
+ (__raw_readl(pxp->base + HW_PXP_WFE_B_SW_DATA_REGS) & 0x0000FFFF) | ((comp_mask&0x000000FF)<<16),
+ pxp->base + HW_PXP_WFE_B_SW_DATA_REGS);
+
+ /* comp_mask only need to be updated upon REAGL-D, 0,1,...7, 0,1,... */
+ if (proc_data->reagl_d_en) {
+ comp_mask++;
+ if (comp_mask>7)
+ comp_mask = 0;
+ }
+#endif
+
+ /* Store */
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_SIZE_CH0_OUT_WIDTH(store_ch0->width-1)|
+ BF_PXP_WFE_B_STORE_SIZE_CH0_OUT_HEIGHT(store_ch0->height-1),
+ pxp->base + HW_PXP_WFE_B_STORE_SIZE_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_SIZE_CH1_OUT_WIDTH(store_ch1->width-1)|
+ BF_PXP_WFE_B_STORE_SIZE_CH1_OUT_HEIGHT(store_ch1->height-1),
+ pxp->base + HW_PXP_WFE_B_STORE_SIZE_CH1);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_PITCH_CH0_OUT_PITCH(store_ch0->stride * 2)|
+ BF_PXP_WFE_B_STORE_PITCH_CH1_OUT_PITCH(store_ch1->stride * 2),
+ pxp->base + HW_PXP_WFE_B_STORE_PITCH);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_ADDR_0_CH0_OUT_BASE_ADDR0(store_ch0->paddr
+ + (store_ch0->left + store_ch0->top * store_ch0->stride) * 2),
+ pxp->base + HW_PXP_WFE_B_STORE_ADDR_0_CH0);
+
+ if (proc_data->lut_update) {
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0(0x0),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK1_H_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0(0x0),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK1_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0(0x0),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK2_H_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0(0x3f0000),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK2_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK0(0x30)|
+ BF_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK1(0)|
+ BF_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK2(0)|
+ BF_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK3(0),
+ pxp->base + HW_PXP_WFE_B_STORE_F_MASK_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0(4)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0(1)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3(0),
+ pxp->base + HW_PXP_WFE_B_STORE_F_SHIFT_L_CH0);
+ } else {
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0(0x0),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK1_H_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0(0x3f00),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK1_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0(0x0),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK2_H_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0(0x0),
+ pxp->base + HW_PXP_WFE_B_STORE_D_MASK2_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK0(3)|
+ BF_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK1(0)|
+ BF_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK2(0)|
+ BF_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK3(0),
+ pxp->base + HW_PXP_WFE_B_STORE_F_MASK_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0(8)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0(1)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3(0)|
+ BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3(0),
+ pxp->base + HW_PXP_WFE_B_STORE_F_SHIFT_L_CH0);
+ }
+
+ /* ALU */
+ __raw_writel(
+ BF_PXP_ALU_B_BUF_SIZE_BUF_WIDTH(fetch_ch0->width) |
+ BF_PXP_ALU_B_BUF_SIZE_BUF_HEIGHT(fetch_ch0->height),
+ pxp->base + HW_PXP_ALU_B_BUF_SIZE);
+
+ /* WFE */
+ __raw_writel(
+ BF_PXP_WFE_B_DIMENSIONS_WIDTH(fetch_ch0->width) |
+ BF_PXP_WFE_B_DIMENSIONS_HEIGHT(fetch_ch0->height),
+ pxp->base + HW_PXP_WFE_B_DIMENSIONS);
+
+ __raw_writel( /*TODO check*/
+ BF_PXP_WFE_B_OFFSET_X_OFFSET(fetch_ch0->left) |
+ BF_PXP_WFE_B_OFFSET_Y_OFFSET(fetch_ch0->top),
+ pxp->base + HW_PXP_WFE_B_OFFSET);
+
+ __raw_writel(proc_data->reagl_d_en, pxp->base + HW_PXP_WFE_B_SW_FLAG_REGS);
+}
+
+void pxp_fill(
+ u32 bpp,
+ u32 value,
+ u32 width,
+ u32 height,
+ u32 output_buffer,
+ u32 output_pitch)
+{
+ u32 active_bpp;
+ u32 pitch;
+
+ if (bpp == 8) {
+ active_bpp = 0;
+ pitch = output_pitch;
+ } else if(bpp == 16) {
+ active_bpp = 1;
+ pitch = output_pitch * 2;
+ } else {
+ active_bpp = 2;
+ pitch = output_pitch * 4;
+ }
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_CTRL_CH0_CH_EN(1)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_BLOCK_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_BLOCK_16(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_HANDSHAKE_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_LINE_NUM(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_STORE_BYPASS_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_STORE_MEMORY_EN(1)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_PACK_IN_SEL(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_FILL_DATA_EN(1)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_WR_NUM_BYTES(32)|
+ BF_PXP_WFE_B_STORE_CTRL_CH0_COMBINE_2CHANNEL(0) |
+ BF_PXP_WFE_B_STORE_CTRL_CH0_ARBIT_EN(0),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_CTRL_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_CTRL_CH1_CH_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_BLOCK_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_BLOCK_16(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_HANDSHAKE_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_LINE_NUM(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_STORE_BYPASS_EN(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_STORE_MEMORY_EN(1)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_PACK_IN_SEL(0)|
+ BF_PXP_WFE_B_STORE_CTRL_CH1_WR_NUM_BYTES(16),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_CTRL_CH1);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_SIZE_CH0_OUT_WIDTH(width-1)|
+ BF_PXP_WFE_B_STORE_SIZE_CH0_OUT_HEIGHT(height-1),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_SIZE_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_SIZE_CH1_OUT_WIDTH(width-1)|
+ BF_PXP_WFE_B_STORE_SIZE_CH1_OUT_HEIGHT(height-1),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_SIZE_CH1);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_PITCH_CH0_OUT_PITCH(pitch)|
+ BF_PXP_WFE_B_STORE_PITCH_CH1_OUT_PITCH(pitch),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_PITCH);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP(active_bpp)|
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN(0)|
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN(0)|
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS(1),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_SHIFT_CTRL_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP(active_bpp)|
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN(0)|
+ BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN(0),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_SHIFT_CTRL_CH1);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_ADDR_0_CH0_OUT_BASE_ADDR0(output_buffer),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_ADDR_0_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_ADDR_1_CH0_OUT_BASE_ADDR1(0),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_ADDR_1_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_ADDR_0_CH1_OUT_BASE_ADDR0(output_buffer),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_ADDR_0_CH1);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_ADDR_1_CH1_OUT_BASE_ADDR1(0),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_ADDR_1_CH1);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_FILL_DATA_CH0_FILL_DATA_CH0(value),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_FILL_DATA_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0(0x00000000),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_D_MASK0_H_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0(0x000000ff),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_D_MASK0_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0(0x00000000),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_D_MASK1_H_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0(0x000000ff),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_D_MASK1_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0(0x00000000),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_D_MASK2_H_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0(0x000000ff),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_D_MASK2_L_CH0);
+
+ __raw_writel(
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0(0) |
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0(0) |
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1(32)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1(1) |
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2(40)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2(1)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3(0)|
+ BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3(0),
+ pxp_reg_base + HW_PXP_WFE_B_STORE_D_SHIFT_L_CH0);
+
+ __raw_writel(
+ BF_PXP_CTRL2_ENABLE (1) |
+ BF_PXP_CTRL2_ROTATE0 (0) |
+ BF_PXP_CTRL2_HFLIP0 (0) |
+ BF_PXP_CTRL2_VFLIP0 (0) |
+ BF_PXP_CTRL2_ROTATE1 (0) |
+ BF_PXP_CTRL2_HFLIP1 (0) |
+ BF_PXP_CTRL2_VFLIP1 (0) |
+ BF_PXP_CTRL2_ENABLE_DITHER (0) |
+ BF_PXP_CTRL2_ENABLE_WFE_A (0) |
+ BF_PXP_CTRL2_ENABLE_WFE_B (1) |
+ BF_PXP_CTRL2_ENABLE_INPUT_FETCH_STORE (0) |
+ BF_PXP_CTRL2_ENABLE_ALPHA_B (0) |
+ BF_PXP_CTRL2_BLOCK_SIZE (0) |
+ BF_PXP_CTRL2_ENABLE_CSC2 (0) |
+ BF_PXP_CTRL2_ENABLE_LUT (0) |
+ BF_PXP_CTRL2_ENABLE_ROTATE0 (0) |
+ BF_PXP_CTRL2_ENABLE_ROTATE1 (0),
+ pxp_reg_base + HW_PXP_CTRL2);
+
+ if (busy_wait(BM_PXP_IRQ_WFE_B_CH0_STORE_IRQ &
+ __raw_readl(pxp_reg_base + HW_PXP_IRQ)) == false)
+ printk("%s: wait for completion timeout\n", __func__);
+}
+EXPORT_SYMBOL(pxp_fill);
+
+static void pxp_lut_cleanup_multiple(struct pxps *pxp, u64 lut, bool set)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+
+ if (proc_data->lut_cleanup == 1) {
+ if (set) {
+ __raw_writel((u32)lut, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT1_0 + 0x4);
+ __raw_writel((u32)(lut>>32), pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT1_1 + 0x4);
+ } else {
+ pxp_luts_deactivate(pxp, lut);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT1_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT1_1);
+ }
+ }
+}
+
+static void pxp_lut_cleanup_multiple_v3p(struct pxps *pxp, u64 lut, bool set)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+
+ if (proc_data->lut_cleanup == 1) {
+ if (set) {
+ __raw_writel((u32)lut, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_0 + 0x4);
+ __raw_writel((u32)(lut>>32), pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_1 + 0x4);
+ } else {
+ pxp_luts_deactivate(pxp, lut);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_0);
+ __raw_writel(0, pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT1_1);
+ }
+ }
+}
+
+#ifdef CONFIG_MXC_FPGA_M4_TEST
+void m4_process(void)
+{
+ __raw_writel(0x7, pinctrl_base + PIN_DOUT); /* M4 Start */
+
+ while (!(__raw_readl(pxp_reg_base + HW_PXP_HANDSHAKE_CPU_STORE) & BM_PXP_HANDSHAKE_CPU_STORE_SW0_B0_READY));
+
+ __raw_writel(0x3, pinctrl_base + PIN_DOUT); /* M4 Stop */
+
+
+}
+#else
+void m4_process(void) {}
+#endif
+EXPORT_SYMBOL(m4_process);
+
+static void pxp_lut_status_set(struct pxps *pxp, unsigned int lut)
+{
+ if(lut<32)
+ __raw_writel(
+ __raw_readl(pxp_reg_base + HW_PXP_WFE_A_STG1_8X1_OUT0_0) | (1 << lut),
+ pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT0_0);
+ else {
+ lut = lut -32;
+ __raw_writel(
+ __raw_readl(pxp_reg_base + HW_PXP_WFE_A_STG1_8X1_OUT0_1) | (1 << lut),
+ pxp->base + HW_PXP_WFE_A_STG1_8X1_OUT0_1);
+ }
+}
+
+static void pxp_lut_status_set_v3p(struct pxps *pxp, unsigned int lut)
+{
+ if(lut<32)
+ __raw_writel(
+ __raw_readl(pxp_reg_base + HW_PXP_WFE_B_STG1_8X1_OUT0_0) | (1 << lut),
+ pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT0_0);
+ else {
+ lut = lut -32;
+ __raw_writel(
+ __raw_readl(pxp_reg_base + HW_PXP_WFE_B_STG1_8X1_OUT0_1) | (1 << lut),
+ pxp->base + HW_PXP_WFE_B_STG1_8X1_OUT0_1);
+ }
+}
+
+static void pxp_luts_activate(struct pxps *pxp, u64 lut_status)
+{
+ int i = 0;
+
+ if (!lut_status)
+ return;
+
+ for (i = 0; i < 64; i++) {
+ if (lut_status & (1ULL << i))
+ if (pxp->devdata && pxp->devdata->pxp_lut_status_set)
+ pxp->devdata->pxp_lut_status_set(pxp, i);
+ }
+}
+
+static void pxp_lut_status_clr(unsigned int lut)
+{
+ if(lut<32)
+ __raw_writel(
+ __raw_readl(pxp_reg_base + HW_PXP_WFE_A_STG1_8X1_OUT0_0) & (~(1 << lut)),
+ pxp_reg_base + HW_PXP_WFE_A_STG1_8X1_OUT0_0);
+ else
+ {
+ lut = lut -32;
+ __raw_writel(
+ __raw_readl(pxp_reg_base + HW_PXP_WFE_A_STG1_8X1_OUT0_1) & (~(1 << lut)),
+ pxp_reg_base + HW_PXP_WFE_A_STG1_8X1_OUT0_1);
+ }
+}
+
+static void pxp_lut_status_clr_v3p(unsigned int lut)
+{
+ if(lut<32)
+ __raw_writel(
+ __raw_readl(pxp_reg_base + HW_PXP_WFE_B_STG1_8X1_OUT0_0) & (~(1 << lut)),
+ pxp_reg_base + HW_PXP_WFE_B_STG1_8X1_OUT0_0);
+ else
+ {
+ lut = lut -32;
+ __raw_writel(
+ __raw_readl(pxp_reg_base + HW_PXP_WFE_B_STG1_8X1_OUT0_1) & (~(1 << lut)),
+ pxp_reg_base + HW_PXP_WFE_B_STG1_8X1_OUT0_1);
+ }
+}
+
+/* this function should be called in the epdc
+ * driver explicitly when some epdc lut becomes
+ * idle. So it should be exported.
+ */
+static void pxp_luts_deactivate(struct pxps *pxp, u64 lut_status)
+{
+ int i = 0;
+
+ if (!lut_status)
+ return;
+
+ for (i = 0; i < 64; i++) {
+ if (lut_status & (1ULL << i))
+ if (pxp->devdata && pxp->devdata->pxp_lut_status_clr)
+ pxp->devdata->pxp_lut_status_clr(i);
+ }
+}
+
+/* use histogram_B engine to calculate histogram status */
+static void pxp_histogram_enable(struct pxps *pxp,
+ unsigned int width,
+ unsigned int height)
+{
+ __raw_writel(
+ BF_PXP_HIST_B_BUF_SIZE_HEIGHT(height)|
+ BF_PXP_HIST_B_BUF_SIZE_WIDTH(width),
+ pxp->base + HW_PXP_HIST_B_BUF_SIZE);
+
+ __raw_writel(
+ BF_PXP_HIST_B_MASK_MASK_EN(1)|
+ BF_PXP_HIST_B_MASK_MASK_MODE(0)|
+ BF_PXP_HIST_B_MASK_MASK_OFFSET(64)|
+ BF_PXP_HIST_B_MASK_MASK_WIDTH(0)|
+ BF_PXP_HIST_B_MASK_MASK_VALUE0(1) |
+ BF_PXP_HIST_B_MASK_MASK_VALUE1(0),
+ pxp->base + HW_PXP_HIST_B_MASK);
+
+ __raw_writel(
+ BF_PXP_HIST_B_CTRL_PIXEL_WIDTH(3)|
+ BF_PXP_HIST_B_CTRL_PIXEL_OFFSET(8)|
+ BF_PXP_HIST_B_CTRL_CLEAR(0)|
+ BF_PXP_HIST_B_CTRL_ENABLE(1),
+ pxp->base + HW_PXP_HIST_B_CTRL);
+}
+
+static void pxp_histogram_status_report(struct pxps *pxp, u32 *hist_status)
+{
+ BUG_ON(!hist_status);
+
+ *hist_status = (__raw_readl(pxp->base + HW_PXP_HIST_B_CTRL) & BM_PXP_HIST_B_CTRL_STATUS)
+ >> BP_PXP_HIST_B_CTRL_STATUS;
+ dev_dbg(pxp->dev, "%d pixels are used to calculate histogram status %d\n",
+ __raw_readl(pxp->base + HW_PXP_HIST_B_TOTAL_PIXEL), *hist_status);
+}
+
+static void pxp_histogram_disable(struct pxps *pxp)
+{
+ __raw_writel(
+ BF_PXP_HIST_B_CTRL_PIXEL_WIDTH(3)|
+ BF_PXP_HIST_B_CTRL_PIXEL_OFFSET(4)|
+ BF_PXP_HIST_B_CTRL_CLEAR(1)|
+ BF_PXP_HIST_B_CTRL_ENABLE(0),
+ pxp->base + HW_PXP_HIST_B_CTRL);
+}
+
+/* the collision detection function will be
+ * called by epdc driver when required
+ */
+static void pxp_collision_detection_enable(struct pxps *pxp,
+ unsigned int width,
+ unsigned int height)
+{
+ __raw_writel(
+ BF_PXP_HIST_A_BUF_SIZE_HEIGHT(height)|
+ BF_PXP_HIST_A_BUF_SIZE_WIDTH(width),
+ pxp_reg_base + HW_PXP_HIST_A_BUF_SIZE);
+
+ __raw_writel(
+ BF_PXP_HIST_A_MASK_MASK_EN(1)|
+ BF_PXP_HIST_A_MASK_MASK_MODE(0)|
+ BF_PXP_HIST_A_MASK_MASK_OFFSET(65)|
+ BF_PXP_HIST_A_MASK_MASK_WIDTH(0)|
+ BF_PXP_HIST_A_MASK_MASK_VALUE0(1) |
+ BF_PXP_HIST_A_MASK_MASK_VALUE1(0),
+ pxp_reg_base + HW_PXP_HIST_A_MASK);
+
+ __raw_writel(
+ BF_PXP_HIST_A_CTRL_PIXEL_WIDTH(6)|
+ BF_PXP_HIST_A_CTRL_PIXEL_OFFSET(24)|
+ BF_PXP_HIST_A_CTRL_CLEAR(0)|
+ BF_PXP_HIST_A_CTRL_ENABLE(1),
+ pxp_reg_base + HW_PXP_HIST_A_CTRL);
+}
+
+static void pxp_collision_detection_disable(struct pxps *pxp)
+{
+ __raw_writel(
+ BF_PXP_HIST_A_CTRL_PIXEL_WIDTH(6)|
+ BF_PXP_HIST_A_CTRL_PIXEL_OFFSET(24)|
+ BF_PXP_HIST_A_CTRL_CLEAR(1)|
+ BF_PXP_HIST_A_CTRL_ENABLE(0),
+ pxp_reg_base + HW_PXP_HIST_A_CTRL);
+}
+
+/* this function can be called in the epdc callback
+ * function in the pxp_irq() to let the epdc know
+ * the collision information for the previous working
+ * buffer update.
+ */
+static bool pxp_collision_status_report(struct pxps *pxp, struct pxp_collision_info *info)
+{
+ unsigned int count;
+
+ BUG_ON(!info);
+ memset(info, 0x0, sizeof(*info));
+
+ info->pixel_cnt = count = __raw_readl(pxp->base + HW_PXP_HIST_A_TOTAL_PIXEL);
+ if (!count)
+ return false;
+
+ dev_dbg(pxp->dev, "%s: pixel_cnt = %d\n", __func__, info->pixel_cnt);
+ info->rect_min_x = __raw_readl(pxp->base + HW_PXP_HIST_A_ACTIVE_AREA_X) & 0xffff;
+ dev_dbg(pxp->dev, "%s: rect_min_x = %d\n", __func__, info->rect_min_x);
+ info->rect_max_x = (__raw_readl(pxp->base + HW_PXP_HIST_A_ACTIVE_AREA_X) >> 16) & 0xffff;
+ dev_dbg(pxp->dev, "%s: rect_max_x = %d\n", __func__, info->rect_max_x);
+ info->rect_min_y = __raw_readl(pxp->base + HW_PXP_HIST_A_ACTIVE_AREA_Y) & 0xffff;
+ dev_dbg(pxp->dev, "%s: rect_min_y = %d\n", __func__, info->rect_min_y);
+ info->rect_max_y = (__raw_readl(pxp->base + HW_PXP_HIST_A_ACTIVE_AREA_Y) >> 16) & 0xffff;
+ dev_dbg(pxp->dev, "%s: rect_max_y = %d\n", __func__, info->rect_max_y);
+
+ info->victim_luts[0] = __raw_readl(pxp->base + HW_PXP_HIST_A_RAW_STAT0);
+ dev_dbg(pxp->dev, "%s: victim_luts[0] = 0x%x\n", __func__, info->victim_luts[0]);
+ info->victim_luts[1] = __raw_readl(pxp->base + HW_PXP_HIST_A_RAW_STAT1);
+ dev_dbg(pxp->dev, "%s: victim_luts[1] = 0x%x\n", __func__, info->victim_luts[1]);
+
+ return true;
+}
+
+void pxp_get_collision_info(struct pxp_collision_info *info)
+{
+ BUG_ON(!info);
+
+ memcpy(info, &col_info, sizeof(struct pxp_collision_info));
+}
+EXPORT_SYMBOL(pxp_get_collision_info);
+
+static void dither_prefetch_config(struct pxps *pxp)
+{
+ struct pxp_config_data *config_data = &pxp->pxp_conf_state;
+ struct pxp_layer_param *fetch_ch0 = &config_data->dither_fetch_param[0];
+ struct pxp_layer_param *fetch_ch1 = &config_data->dither_fetch_param[1];
+
+ print_param(fetch_ch0, "dither fetch_ch0");
+ print_param(fetch_ch1, "dither fetch_ch1");
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_CTRL_CH0_CH_EN(1) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_BLOCK_EN(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_BLOCK_16(0)|
+ BF_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_EN(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_BYPASS_PIXEL_EN(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_HIGH_BYTE(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_HFLIP(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_VFLIP(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_ROTATION_ANGLE(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_RD_NUM_BYTES(32) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_ARBIT_EN(0),
+ pxp->base + HW_PXP_DITHER_FETCH_CTRL_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_CTRL_CH1_CH_EN(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH1_BLOCK_EN(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH1_BLOCK_16(0)|
+ BF_PXP_DITHER_FETCH_CTRL_CH1_HANDSHAKE_EN(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH1_BYPASS_PIXEL_EN(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH1_HFLIP(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH1_VFLIP(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH1_ROTATION_ANGLE(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH1_RD_NUM_BYTES(2) |
+ BF_PXP_DITHER_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM(0),
+ pxp->base + HW_PXP_DITHER_FETCH_CTRL_CH1);
+
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_X(0) |
+ BF_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_Y(0),
+ pxp->base + HW_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH0);
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_X(fetch_ch0->width - 1) |
+ BF_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_Y(fetch_ch0->height - 1),
+ pxp->base + HW_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_X(0) |
+ BF_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_Y(0),
+ pxp->base + HW_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH1);
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_X(fetch_ch1->width - 1) |
+ BF_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_Y(fetch_ch1->height - 1),
+ pxp->base + HW_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH1);
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_SIZE_CH0_INPUT_TOTAL_WIDTH(fetch_ch0->width - 1) |
+ BF_PXP_DITHER_FETCH_SIZE_CH0_INPUT_TOTAL_HEIGHT(fetch_ch0->height - 1),
+ pxp->base + HW_PXP_DITHER_FETCH_SIZE_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_SIZE_CH1_INPUT_TOTAL_WIDTH(fetch_ch1->width - 1) |
+ BF_PXP_DITHER_FETCH_SIZE_CH1_INPUT_TOTAL_HEIGHT(fetch_ch1->height - 1),
+ pxp->base + HW_PXP_DITHER_FETCH_SIZE_CH1);
+
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_PITCH_CH0_INPUT_PITCH(fetch_ch0->stride) |
+ BF_PXP_DITHER_FETCH_PITCH_CH1_INPUT_PITCH(fetch_ch1->stride),
+ pxp->base + HW_PXP_DITHER_FETCH_PITCH);
+
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP(0) |
+ BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT(0) |
+ BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_EN(0) |
+ BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_SHIFT_BYPASS(1),
+ pxp->base + HW_PXP_DITHER_FETCH_SHIFT_CTRL_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP(0) |
+ BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT(0) |
+ BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_EN(0) |
+ BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_SHIFT_BYPASS(1),
+ pxp->base + HW_PXP_DITHER_FETCH_SHIFT_CTRL_CH1);
+
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET0(0) |
+ BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET1(0) |
+ BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET2(0) |
+ BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET3(0),
+ pxp->base + HW_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET0(0) |
+ BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET1(0) |
+ BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET2(0) |
+ BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET3(0),
+ pxp->base + HW_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1);
+
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH0(7) |
+ BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH1(7) |
+ BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH2(7) |
+ BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH3(7),
+ pxp->base + HW_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH0(7) |
+ BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH1(7) |
+ BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH2(7) |
+ BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH3(7),
+ pxp->base + HW_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1);
+
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_ADDR_0_CH0_INPUT_BASE_ADDR0(fetch_ch0->paddr),
+ pxp->base + HW_PXP_DITHER_FETCH_ADDR_0_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_ADDR_1_CH0_INPUT_BASE_ADDR1(0),
+ pxp->base + HW_PXP_DITHER_FETCH_ADDR_1_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_ADDR_0_CH1_INPUT_BASE_ADDR0(fetch_ch1->paddr),
+ pxp->base + HW_PXP_DITHER_FETCH_ADDR_0_CH1);
+
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_ADDR_1_CH1_INPUT_BASE_ADDR1(0),
+ pxp->base + HW_PXP_DITHER_FETCH_ADDR_1_CH1);
+}
+
+static void dither_store_config(struct pxps *pxp)
+{
+ struct pxp_config_data *config_data = &pxp->pxp_conf_state;
+ struct pxp_layer_param *store_ch0 = &config_data->dither_store_param[0];
+ struct pxp_layer_param *store_ch1 = &config_data->dither_store_param[1];
+
+ print_param(store_ch0, "dither store_ch0");
+ print_param(store_ch1, "dither store_ch1");
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_CTRL_CH0_CH_EN(1)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_BLOCK_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_BLOCK_16(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_HANDSHAKE_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_ARRAY_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_ARRAY_LINE_NUM(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_STORE_BYPASS_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_STORE_MEMORY_EN(1)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_PACK_IN_SEL(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_FILL_DATA_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_WR_NUM_BYTES(32)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_COMBINE_2CHANNEL(0) |
+ BF_PXP_DITHER_STORE_CTRL_CH0_ARBIT_EN(0),
+ pxp->base + HW_PXP_DITHER_STORE_CTRL_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_CTRL_CH1_CH_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH1_BLOCK_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH1_BLOCK_16(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH1_HANDSHAKE_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH1_ARRAY_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH1_ARRAY_LINE_NUM(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH1_STORE_BYPASS_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH1_STORE_MEMORY_EN(1)|
+ BF_PXP_DITHER_STORE_CTRL_CH1_PACK_IN_SEL(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH1_WR_NUM_BYTES(32),
+ pxp->base + HW_PXP_DITHER_STORE_CTRL_CH1);
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_SIZE_CH0_OUT_WIDTH(store_ch0->width - 1) |
+ BF_PXP_DITHER_STORE_SIZE_CH0_OUT_HEIGHT(store_ch0->height - 1),
+ pxp->base + HW_PXP_DITHER_STORE_SIZE_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_SIZE_CH1_OUT_WIDTH(store_ch1->width - 1) |
+ BF_PXP_DITHER_STORE_SIZE_CH1_OUT_HEIGHT(store_ch1->height - 1),
+ pxp->base + HW_PXP_DITHER_STORE_SIZE_CH1);
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_PITCH_CH0_OUT_PITCH(store_ch0->stride) |
+ BF_PXP_DITHER_STORE_PITCH_CH1_OUT_PITCH(store_ch1->stride),
+ pxp->base + HW_PXP_DITHER_STORE_PITCH);
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP(0)|
+ BF_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN(0)|
+ BF_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN(0)|
+ BF_PXP_DITHER_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS(1),
+ pxp->base + HW_PXP_DITHER_STORE_SHIFT_CTRL_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP(0)|
+ BF_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN(0)|
+ BF_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN(0),
+ pxp->base + HW_PXP_DITHER_STORE_SHIFT_CTRL_CH1);
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_ADDR_0_CH0_OUT_BASE_ADDR0(store_ch0->paddr),
+ pxp->base + HW_PXP_DITHER_STORE_ADDR_0_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_ADDR_1_CH0_OUT_BASE_ADDR1(0),
+ pxp->base + HW_PXP_DITHER_STORE_ADDR_1_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_ADDR_0_CH1_OUT_BASE_ADDR0(store_ch1->paddr),
+ pxp->base + HW_PXP_DITHER_STORE_ADDR_0_CH1);
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_ADDR_1_CH1_OUT_BASE_ADDR1(0),
+ pxp->base + HW_PXP_DITHER_STORE_ADDR_1_CH1);
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_FILL_DATA_CH0_FILL_DATA_CH0(0),
+ pxp->base + HW_PXP_DITHER_STORE_FILL_DATA_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0(0xffffff),
+ pxp->base + HW_PXP_DITHER_STORE_D_MASK0_H_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0(0x0),
+ pxp->base + HW_PXP_DITHER_STORE_D_MASK0_L_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0(0x0),
+ pxp->base + HW_PXP_DITHER_STORE_D_MASK1_H_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0(0xff),
+ pxp->base + HW_PXP_DITHER_STORE_D_MASK1_L_CH0);
+
+ __raw_writel(
+ BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0(32) |
+ BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0(0) |
+ BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1(32)|
+ BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1(1) |
+ BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2(0)|
+ BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2(0)|
+ BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3(0)|
+ BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3(0),
+ pxp->base + HW_PXP_DITHER_STORE_D_SHIFT_L_CH0);
+}
+
+static void pxp_set_final_lut_data(struct pxps *pxp)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+
+ if(proc_data->quant_bit < 2) {
+ pxp_sram_init(pxp, DITHER0_LUT, (u32)bit1_dither_data_8x8, 64);
+
+ __raw_writel(
+ BF_PXP_DITHER_FINAL_LUT_DATA0_DATA0(0x0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA0_DATA1(0x0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA0_DATA2(0x0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA0_DATA3(0x0),
+ pxp->base + HW_PXP_DITHER_FINAL_LUT_DATA0);
+
+ __raw_writel(
+ BF_PXP_DITHER_FINAL_LUT_DATA1_DATA4(0x0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA1_DATA5(0x0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA1_DATA6(0x0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA1_DATA7(0x0),
+ pxp->base + HW_PXP_DITHER_FINAL_LUT_DATA1);
+
+ __raw_writel(
+ BF_PXP_DITHER_FINAL_LUT_DATA2_DATA8(0xf0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA2_DATA9(0xf0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA2_DATA10(0xf0)|
+ BF_PXP_DITHER_FINAL_LUT_DATA2_DATA11(0xf0),
+ pxp->base + HW_PXP_DITHER_FINAL_LUT_DATA2);
+
+ __raw_writel(
+ BF_PXP_DITHER_FINAL_LUT_DATA3_DATA12(0xf0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA3_DATA13(0xf0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA3_DATA14(0xf0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA3_DATA15(0xf0),
+ pxp->base + HW_PXP_DITHER_FINAL_LUT_DATA3);
+ } else if(proc_data->quant_bit < 4) {
+ pxp_sram_init(pxp, DITHER0_LUT, (u32)bit2_dither_data_8x8, 64);
+
+ __raw_writel(
+ BF_PXP_DITHER_FINAL_LUT_DATA0_DATA0(0x0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA0_DATA1(0x0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA0_DATA2(0x0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA0_DATA3(0x0),
+ pxp->base + HW_PXP_DITHER_FINAL_LUT_DATA0);
+
+ __raw_writel(
+ BF_PXP_DITHER_FINAL_LUT_DATA1_DATA4(0x50) |
+ BF_PXP_DITHER_FINAL_LUT_DATA1_DATA5(0x50) |
+ BF_PXP_DITHER_FINAL_LUT_DATA1_DATA6(0x50) |
+ BF_PXP_DITHER_FINAL_LUT_DATA1_DATA7(0x50),
+ pxp->base + HW_PXP_DITHER_FINAL_LUT_DATA1);
+
+ __raw_writel(
+ BF_PXP_DITHER_FINAL_LUT_DATA2_DATA8(0xa0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA2_DATA9(0xa0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA2_DATA10(0xa0)|
+ BF_PXP_DITHER_FINAL_LUT_DATA2_DATA11(0xa0),
+ pxp->base + HW_PXP_DITHER_FINAL_LUT_DATA2);
+
+ __raw_writel(
+ BF_PXP_DITHER_FINAL_LUT_DATA3_DATA12(0xf0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA3_DATA13(0xf0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA3_DATA14(0xf0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA3_DATA15(0xf0),
+ pxp->base + HW_PXP_DITHER_FINAL_LUT_DATA3);
+ } else {
+ pxp_sram_init(pxp, DITHER0_LUT, (u32)bit4_dither_data_8x8, 64);
+
+ __raw_writel(
+ BF_PXP_DITHER_FINAL_LUT_DATA0_DATA0(0x0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA0_DATA1(0x10) |
+ BF_PXP_DITHER_FINAL_LUT_DATA0_DATA2(0x20) |
+ BF_PXP_DITHER_FINAL_LUT_DATA0_DATA3(0x30),
+ pxp->base + HW_PXP_DITHER_FINAL_LUT_DATA0);
+
+ __raw_writel(
+ BF_PXP_DITHER_FINAL_LUT_DATA1_DATA4(0x40) |
+ BF_PXP_DITHER_FINAL_LUT_DATA1_DATA5(0x50) |
+ BF_PXP_DITHER_FINAL_LUT_DATA1_DATA6(0x60) |
+ BF_PXP_DITHER_FINAL_LUT_DATA1_DATA7(0x70),
+ pxp->base + HW_PXP_DITHER_FINAL_LUT_DATA1);
+
+ __raw_writel(
+ BF_PXP_DITHER_FINAL_LUT_DATA2_DATA8(0x80) |
+ BF_PXP_DITHER_FINAL_LUT_DATA2_DATA9(0x90) |
+ BF_PXP_DITHER_FINAL_LUT_DATA2_DATA10(0xa0)|
+ BF_PXP_DITHER_FINAL_LUT_DATA2_DATA11(0xb0),
+ pxp->base + HW_PXP_DITHER_FINAL_LUT_DATA2);
+
+ __raw_writel(
+ BF_PXP_DITHER_FINAL_LUT_DATA3_DATA12(0xc0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA3_DATA13(0xd0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA3_DATA14(0xe0) |
+ BF_PXP_DITHER_FINAL_LUT_DATA3_DATA15(0xf0),
+ pxp->base + HW_PXP_DITHER_FINAL_LUT_DATA3);
+ }
+}
+
+static void pxp_dithering_process(struct pxps *pxp)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+ u32 val = 0;
+
+ if (pxp->devdata && pxp->devdata->pxp_dithering_configure)
+ pxp->devdata->pxp_dithering_configure(pxp);
+
+ if (pxp_is_v3(pxp))
+ val = BF_PXP_DITHER_CTRL_ENABLE0 (1) |
+ BF_PXP_DITHER_CTRL_ENABLE1 (0) |
+ BF_PXP_DITHER_CTRL_ENABLE2 (0) |
+ BF_PXP_DITHER_CTRL_DITHER_MODE2 (0) |
+ BF_PXP_DITHER_CTRL_DITHER_MODE1 (0) |
+ BF_PXP_DITHER_CTRL_DITHER_MODE0(proc_data->dither_mode) |
+ BF_PXP_DITHER_CTRL_LUT_MODE (0) |
+ BF_PXP_DITHER_CTRL_IDX_MATRIX0_SIZE (1) |
+ BF_PXP_DITHER_CTRL_IDX_MATRIX1_SIZE (0) |
+ BF_PXP_DITHER_CTRL_IDX_MATRIX2_SIZE (0) |
+ BF_PXP_DITHER_CTRL_BUSY2 (0) |
+ BF_PXP_DITHER_CTRL_BUSY1 (0) |
+ BF_PXP_DITHER_CTRL_BUSY0 (0);
+ else if (pxp_is_v3p(pxp)) {
+ if (proc_data->dither_mode != 0 &&
+ proc_data->dither_mode != 3) {
+ dev_err(pxp->dev, "Not supported dithering mode. "
+ "Forced to be Orderred mode!\n");
+ proc_data->dither_mode = 3;
+ }
+
+ val = BF_PXP_DITHER_CTRL_ENABLE0 (1) |
+ BF_PXP_DITHER_CTRL_ENABLE1 (1) |
+ BF_PXP_DITHER_CTRL_ENABLE2 (1) |
+ BF_PXP_DITHER_CTRL_DITHER_MODE2(proc_data->dither_mode) |
+ BF_PXP_DITHER_CTRL_DITHER_MODE1(proc_data->dither_mode) |
+ BF_PXP_DITHER_CTRL_DITHER_MODE0(proc_data->dither_mode) |
+ BF_PXP_DITHER_CTRL_LUT_MODE (0) |
+ BF_PXP_DITHER_CTRL_IDX_MATRIX0_SIZE (1) |
+ BF_PXP_DITHER_CTRL_IDX_MATRIX1_SIZE (1) |
+ BF_PXP_DITHER_CTRL_IDX_MATRIX2_SIZE (1) |
+ BF_PXP_DITHER_CTRL_FINAL_LUT_ENABLE (0) |
+ BF_PXP_DITHER_CTRL_BUSY2 (0) |
+ BF_PXP_DITHER_CTRL_BUSY1 (0) |
+ BF_PXP_DITHER_CTRL_BUSY0 (0);
+ }
+ __raw_writel(val, pxp->base + HW_PXP_DITHER_CTRL);
+
+ switch(proc_data->dither_mode) {
+ case PXP_DITHER_PASS_THROUGH:
+ /* no more settings required */
+ break;
+ case PXP_DITHER_FLOYD:
+ case PXP_DITHER_ATKINSON:
+ case PXP_DITHER_ORDERED:
+ if(!proc_data->quant_bit || proc_data->quant_bit > 7) {
+ dev_err(pxp->dev, "unsupported quantization bit number!\n");
+ return;
+ }
+ __raw_writel(
+ BF_PXP_DITHER_CTRL_FINAL_LUT_ENABLE(1) |
+ BF_PXP_DITHER_CTRL_NUM_QUANT_BIT(proc_data->quant_bit),
+ pxp->base + HW_PXP_DITHER_CTRL_SET);
+ pxp_set_final_lut_data(pxp);
+
+ break;
+ case PXP_DITHER_QUANT_ONLY:
+ if(!proc_data->quant_bit || proc_data->quant_bit > 7) {
+ dev_err(pxp->dev, "unsupported quantization bit number!\n");
+ return;
+ }
+ __raw_writel(
+ BF_PXP_DITHER_CTRL_NUM_QUANT_BIT(proc_data->quant_bit),
+ pxp->base + HW_PXP_DITHER_CTRL_SET);
+ break;
+ default:
+ /* unknown mode */
+ dev_err(pxp->dev, "unknown dithering mode passed!\n");
+ __raw_writel(0x0, pxp->base + HW_PXP_DITHER_CTRL);
+ return;
+ }
+}
+
+static void pxp_dithering_configure(struct pxps *pxp)
+{
+ dither_prefetch_config(pxp);
+ dither_store_config(pxp);
+}
+
+static void pxp_dithering_configure_v3p(struct pxps *pxp)
+{
+ struct pxp_config_data *config_data = &pxp->pxp_conf_state;
+ struct pxp_layer_param *fetch_ch0 = &config_data->dither_fetch_param[0];
+ struct pxp_layer_param *store_ch0 = &config_data->dither_store_param[0];
+
+ __raw_writel(BF_PXP_CTRL_BLOCK_SIZE(BV_PXP_CTRL_BLOCK_SIZE__8X8) |
+ BF_PXP_CTRL_ROTATE0(BV_PXP_CTRL_ROTATE0__ROT_0) |
+ BM_PXP_CTRL_IRQ_ENABLE,
+ pxp->base + HW_PXP_CTRL);
+
+ __raw_writel(BF_PXP_PS_CTRL_DECX(BV_PXP_PS_CTRL_DECX__DISABLE) |
+ BF_PXP_PS_CTRL_DECY(BV_PXP_PS_CTRL_DECY__DISABLE) |
+ BF_PXP_PS_CTRL_FORMAT(BV_PXP_PS_CTRL_FORMAT__Y8),
+ pxp->base + HW_PXP_PS_CTRL);
+
+ __raw_writel(BF_PXP_OUT_CTRL_FORMAT(BV_PXP_OUT_CTRL_FORMAT__Y8),
+ pxp->base + HW_PXP_OUT_CTRL);
+
+ __raw_writel(BF_PXP_PS_SCALE_YSCALE(4096) |
+ BF_PXP_PS_SCALE_XSCALE(4096),
+ pxp->base + HW_PXP_PS_SCALE);
+
+ __raw_writel(store_ch0->paddr, pxp->base + HW_PXP_OUT_BUF);
+
+ __raw_writel(store_ch0->stride, pxp->base + HW_PXP_OUT_PITCH);
+
+ __raw_writel(BF_PXP_OUT_LRC_X(store_ch0->width - 1) |
+ BF_PXP_OUT_LRC_Y(store_ch0->height - 1),
+ pxp->base + HW_PXP_OUT_LRC);
+
+ __raw_writel(BF_PXP_OUT_AS_ULC_X(1) |
+ BF_PXP_OUT_AS_ULC_Y(1),
+ pxp->base + HW_PXP_OUT_AS_ULC);
+
+ __raw_writel(BF_PXP_OUT_AS_LRC_X(0) |
+ BF_PXP_OUT_AS_LRC_Y(0),
+ pxp->base + HW_PXP_OUT_AS_LRC);
+
+ __raw_writel(BF_PXP_OUT_PS_ULC_X(0) |
+ BF_PXP_OUT_PS_ULC_Y(0),
+ pxp->base + HW_PXP_OUT_PS_ULC);
+
+ __raw_writel(BF_PXP_OUT_PS_LRC_X(fetch_ch0->width - 1) |
+ BF_PXP_OUT_PS_LRC_Y(fetch_ch0->height - 1),
+ pxp->base + HW_PXP_OUT_PS_LRC);
+
+ __raw_writel(fetch_ch0->paddr, pxp->base + HW_PXP_PS_BUF);
+
+ __raw_writel(fetch_ch0->stride, pxp->base + HW_PXP_PS_PITCH);
+
+ __raw_writel(0x40000000, pxp->base + HW_PXP_CSC1_COEF0);
+
+ __raw_writel(BF_PXP_DITHER_STORE_SIZE_CH0_OUT_WIDTH(store_ch0->width-1)|
+ BF_PXP_DITHER_STORE_SIZE_CH0_OUT_HEIGHT(store_ch0->height-1),
+ pxp->base + HW_PXP_DITHER_STORE_SIZE_CH0);
+
+ __raw_writel(BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(1),
+ pxp->base + HW_PXP_DATA_PATH_CTRL0_CLR);
+}
+
+static void pxp_start2(struct pxps *pxp)
+{
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf_state;
+ struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+ int dither_wfe_a_handshake = 0;
+ int wfe_a_b_handshake = 0;
+ int count = 0;
+
+ int wfe_a_enable = ((proc_data->engine_enable & PXP_ENABLE_WFE_A) == PXP_ENABLE_WFE_A);
+ int wfe_b_enable = ((proc_data->engine_enable & PXP_ENABLE_WFE_B) == PXP_ENABLE_WFE_B);
+ int dither_enable = ((proc_data->engine_enable & PXP_ENABLE_DITHER) == PXP_ENABLE_DITHER);
+ int handshake = ((proc_data->engine_enable & PXP_ENABLE_HANDSHAKE) == PXP_ENABLE_HANDSHAKE);
+ int dither_bypass = ((proc_data->engine_enable & PXP_ENABLE_DITHER_BYPASS) == PXP_ENABLE_DITHER_BYPASS);
+ u32 val = 0;
+
+ if (dither_enable)
+ count++;
+ if (wfe_a_enable)
+ count++;
+ if (wfe_b_enable)
+ count++;
+
+ if (count == 0)
+ return;
+ if (handshake && (count == 1)) {
+ dev_warn(pxp->dev, "Warning: Can not use handshake mode when "
+ "only one sub-block is enabled!\n");
+ handshake = 0;
+ }
+
+ if (handshake && wfe_b_enable && (wfe_a_enable == 0)) {
+ dev_err(pxp->dev, "WFE_B only works when WFE_A is enabled!\n");
+ return;
+ }
+
+ if (handshake && dither_enable && wfe_a_enable)
+ dither_wfe_a_handshake = 1;
+ if (handshake && wfe_a_enable && wfe_b_enable)
+ wfe_a_b_handshake = 1;
+
+ dev_dbg(pxp->dev, "handshake %d, dither_wfe_a_handshake %d, "
+ "wfe_a_b_handshake %d, dither_bypass %d\n",
+ handshake,
+ dither_wfe_a_handshake,
+ wfe_a_b_handshake,
+ dither_bypass);
+
+ if (handshake) {
+ /* for handshake, we only enable the last completion INT */
+ if (wfe_b_enable)
+ __raw_writel(0x8000, pxp->base + HW_PXP_IRQ_MASK);
+ else if (wfe_a_enable)
+ __raw_writel(0x4000, pxp->base + HW_PXP_IRQ_MASK);
+
+ /* Dither fetch */
+ __raw_writel(
+ BF_PXP_DITHER_FETCH_CTRL_CH0_CH_EN(1) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_BLOCK_EN(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_BLOCK_16(0)|
+ BF_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_EN(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_BYPASS_PIXEL_EN(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_HIGH_BYTE(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_HFLIP(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_VFLIP(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_ROTATION_ANGLE(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_RD_NUM_BYTES(32) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM(0) |
+ BF_PXP_DITHER_FETCH_CTRL_CH0_ARBIT_EN(0),
+ pxp->base + HW_PXP_DITHER_FETCH_CTRL_CH0);
+
+ if (dither_bypass) {
+ /* Dither store */
+ __raw_writel(
+ BF_PXP_DITHER_STORE_CTRL_CH0_CH_EN(1)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_BLOCK_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_BLOCK_16(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_HANDSHAKE_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_ARRAY_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_ARRAY_LINE_NUM(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_STORE_BYPASS_EN(1)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_STORE_MEMORY_EN(1)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_PACK_IN_SEL(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_FILL_DATA_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_WR_NUM_BYTES(32)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_COMBINE_2CHANNEL(0) |
+ BF_PXP_DITHER_STORE_CTRL_CH0_ARBIT_EN(0),
+ pxp->base + HW_PXP_DITHER_STORE_CTRL_CH0);
+
+ /* WFE_A fetch */
+ __raw_writel(
+ BF_PXP_WFA_FETCH_CTRL_BF1_EN(1) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_HSK_MODE(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_BYTES_PP(2) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_LINE_MODE(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_SRAM_IF(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_BURST_LEN(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_BYPASS_MODE(1) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_EN(1) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_HSK_MODE(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_BYTES_PP(1) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_LINE_MODE(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_SRAM_IF(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_BURST_LEN(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_BYPASS_MODE(0),
+ pxp->base + HW_PXP_WFA_FETCH_CTRL);
+
+ } else if (dither_wfe_a_handshake) {
+ /* Dither store */
+ __raw_writel(
+ BF_PXP_DITHER_STORE_CTRL_CH0_CH_EN(1)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_BLOCK_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_BLOCK_16(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_HANDSHAKE_EN(1)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_ARRAY_EN(1)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_ARRAY_LINE_NUM(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_STORE_BYPASS_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_STORE_MEMORY_EN(1)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_PACK_IN_SEL(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_FILL_DATA_EN(0)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_WR_NUM_BYTES(32)|
+ BF_PXP_DITHER_STORE_CTRL_CH0_COMBINE_2CHANNEL(0) |
+ BF_PXP_DITHER_STORE_CTRL_CH0_ARBIT_EN(0),
+ pxp->base + HW_PXP_DITHER_STORE_CTRL_CH0);
+
+ /* WFE_A fetch */
+ __raw_writel(
+ BF_PXP_WFA_FETCH_CTRL_BF1_EN(1) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_HSK_MODE(1) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_BYTES_PP(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_LINE_MODE(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_SRAM_IF(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_BURST_LEN(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF1_BYPASS_MODE(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_EN(1) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_HSK_MODE(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_BYTES_PP(1) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_LINE_MODE(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_SRAM_IF(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_BURST_LEN(0) |
+ BF_PXP_WFA_FETCH_CTRL_BF2_BYPASS_MODE(0),
+ pxp->base + HW_PXP_WFA_FETCH_CTRL);
+ }
+
+ if (wfe_a_b_handshake) {
+ /* WFE_A Store */
+ __raw_writel(
+ BF_PXP_WFE_A_STORE_CTRL_CH1_CH_EN(1)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_BLOCK_EN(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_BLOCK_16(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_HANDSHAKE_EN(1)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_EN(1)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_LINE_NUM(1)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_STORE_BYPASS_EN(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_STORE_MEMORY_EN(1)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_PACK_IN_SEL(1)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_WR_NUM_BYTES(16),
+ pxp->base + HW_PXP_WFE_A_STORE_CTRL_CH1);
+
+ /* WFE_B fetch */
+ __raw_writel(
+ BF_PXP_WFB_FETCH_CTRL_BF1_EN(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_HSK_MODE(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BYTES_PP(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_LINE_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_SRAM_IF(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BURST_LEN(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BORDER_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF1_BYPASS_MODE(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_EN(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_HSK_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BYTES_PP(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_LINE_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_SRAM_IF(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BURST_LEN(0) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BORDER_MODE(1) |
+ BF_PXP_WFB_FETCH_CTRL_BF2_BYPASS_MODE(0),
+ pxp->base + HW_PXP_WFB_FETCH_CTRL);
+ } else {
+ /* WFE_A Store */
+ __raw_writel(
+ BF_PXP_WFE_A_STORE_CTRL_CH1_CH_EN(1)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_BLOCK_EN(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_BLOCK_16(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_HANDSHAKE_EN(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_EN(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_LINE_NUM(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_STORE_BYPASS_EN(0)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_STORE_MEMORY_EN(1)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_PACK_IN_SEL(1)|
+ BF_PXP_WFE_A_STORE_CTRL_CH1_WR_NUM_BYTES(16),
+ pxp->base + HW_PXP_WFE_A_STORE_CTRL_CH1);
+ }
+
+ if (pxp_is_v3(pxp))
+ val = BF_PXP_CTRL_ENABLE_WFE_A(wfe_a_enable) |
+ BF_PXP_CTRL_ENABLE_WFE_B(wfe_b_enable);
+ else if (pxp_is_v3p(pxp))
+ val = BF_PXP_CTRL_ENABLE_WFE_B(wfe_a_enable |
+ wfe_b_enable);
+
+ /* trigger operation */
+ __raw_writel(
+ BF_PXP_CTRL_ENABLE(1) |
+ BF_PXP_CTRL_IRQ_ENABLE(0) |
+ BF_PXP_CTRL_NEXT_IRQ_ENABLE(0) |
+ BF_PXP_CTRL_LUT_DMA_IRQ_ENABLE(0) |
+ BF_PXP_CTRL_ENABLE_LCD0_HANDSHAKE(1) |
+ BF_PXP_CTRL_HANDSHAKE_ABORT_SKIP(1) |
+ BF_PXP_CTRL_ROTATE0(0) |
+ BF_PXP_CTRL_HFLIP0(0) |
+ BF_PXP_CTRL_VFLIP0(0) |
+ BF_PXP_CTRL_ROTATE1(0) |
+ BF_PXP_CTRL_HFLIP1(0) |
+ BF_PXP_CTRL_VFLIP1(0) |
+ BF_PXP_CTRL_ENABLE_PS_AS_OUT(0) |
+ BF_PXP_CTRL_ENABLE_DITHER(dither_enable) |
+ BF_PXP_CTRL_ENABLE_INPUT_FETCH_STORE(0) |
+ BF_PXP_CTRL_ENABLE_ALPHA_B(0) |
+ BF_PXP_CTRL_BLOCK_SIZE(1) |
+ BF_PXP_CTRL_ENABLE_CSC2(0) |
+ BF_PXP_CTRL_ENABLE_LUT(1) |
+ BF_PXP_CTRL_ENABLE_ROTATE0(0) |
+ BF_PXP_CTRL_ENABLE_ROTATE1(0) |
+ BF_PXP_CTRL_EN_REPEAT(0) |
+ val,
+ pxp->base + HW_PXP_CTRL);
+
+ return;
+ }
+
+ if (pxp_is_v3(pxp))
+ val = BF_PXP_CTRL_ENABLE_WFE_A(wfe_a_enable) |
+ BF_PXP_CTRL_ENABLE_WFE_B(wfe_b_enable) |
+ BF_PXP_CTRL_ENABLE_INPUT_FETCH_STORE(0) |
+ BF_PXP_CTRL_ENABLE_ALPHA_B(0);
+ else if (pxp_is_v3p(pxp))
+ val = BF_PXP_CTRL_ENABLE_WFE_B(wfe_a_enable |
+ wfe_b_enable);
+
+ __raw_writel(
+ BF_PXP_CTRL_ENABLE(1) |
+ BF_PXP_CTRL_IRQ_ENABLE(0) |
+ BF_PXP_CTRL_NEXT_IRQ_ENABLE(0) |
+ BF_PXP_CTRL_LUT_DMA_IRQ_ENABLE(0) |
+ BF_PXP_CTRL_ENABLE_LCD0_HANDSHAKE(0) |
+ BF_PXP_CTRL_ROTATE0(0) |
+ BF_PXP_CTRL_HFLIP0(0) |
+ BF_PXP_CTRL_VFLIP0(0) |
+ BF_PXP_CTRL_ROTATE1(0) |
+ BF_PXP_CTRL_HFLIP1(0) |
+ BF_PXP_CTRL_VFLIP1(0) |
+ BF_PXP_CTRL_ENABLE_PS_AS_OUT(0) |
+ BF_PXP_CTRL_ENABLE_DITHER(dither_enable) |
+ BF_PXP_CTRL_BLOCK_SIZE(0) |
+ BF_PXP_CTRL_ENABLE_CSC2(0) |
+ BF_PXP_CTRL_ENABLE_LUT(0) |
+ BF_PXP_CTRL_ENABLE_ROTATE0(0) |
+ BF_PXP_CTRL_ENABLE_ROTATE1(0) |
+ BF_PXP_CTRL_EN_REPEAT(0) |
+ val,
+ pxp->base + HW_PXP_CTRL);
+
+ if (pxp_is_v3(pxp))
+ val = BF_PXP_CTRL2_ENABLE_WFE_A (0) |
+ BF_PXP_CTRL2_ENABLE_WFE_B (0) |
+ BF_PXP_CTRL2_ENABLE_INPUT_FETCH_STORE (0) |
+ BF_PXP_CTRL2_ENABLE_ALPHA_B (0);
+ else if (pxp_is_v3p(pxp))
+ val = BF_PXP_CTRL2_ENABLE_WFE_B(0);
+
+ __raw_writel(
+ BF_PXP_CTRL2_ENABLE (0) |
+ BF_PXP_CTRL2_ROTATE0 (0) |
+ BF_PXP_CTRL2_HFLIP0 (0) |
+ BF_PXP_CTRL2_VFLIP0 (0) |
+ BF_PXP_CTRL2_ROTATE1 (0) |
+ BF_PXP_CTRL2_HFLIP1 (0) |
+ BF_PXP_CTRL2_VFLIP1 (0) |
+ BF_PXP_CTRL2_ENABLE_DITHER (0) |
+ BF_PXP_CTRL2_BLOCK_SIZE (0) |
+ BF_PXP_CTRL2_ENABLE_CSC2 (0) |
+ BF_PXP_CTRL2_ENABLE_LUT (0) |
+ BF_PXP_CTRL2_ENABLE_ROTATE0 (0) |
+ BF_PXP_CTRL2_ENABLE_ROTATE1 (0),
+ pxp->base + HW_PXP_CTRL2);
+
+ dump_pxp_reg2(pxp);
+}
+
+static int pxp_dma_init(struct pxps *pxp)
+{
+ struct pxp_dma *pxp_dma = &pxp->pxp_dma;
+ struct dma_device *dma = &pxp_dma->dma;
+ int i;
+
+ dma_cap_set(DMA_SLAVE, dma->cap_mask);
+ dma_cap_set(DMA_PRIVATE, dma->cap_mask);
+
+ /* Compulsory common fields */
+ dma->dev = pxp->dev;
+ dma->device_alloc_chan_resources = pxp_alloc_chan_resources;
+ dma->device_free_chan_resources = pxp_free_chan_resources;
+ dma->device_tx_status = pxp_tx_status;
+ dma->device_issue_pending = pxp_issue_pending;
+
+ /* Compulsory for DMA_SLAVE fields */
+ dma->device_prep_slave_sg = pxp_prep_slave_sg;
+ dma->device_terminate_all = pxp_device_terminate_all;
+
+ /* Initialize PxP Channels */
+ INIT_LIST_HEAD(&dma->channels);
+ for (i = 0; i < NR_PXP_VIRT_CHANNEL; i++) {
+ struct pxp_channel *pxp_chan = pxp->channel + i;
+ struct dma_chan *dma_chan = &pxp_chan->dma_chan;
+
+ spin_lock_init(&pxp_chan->lock);
+
+ /* Only one EOF IRQ for PxP, shared by all channels */
+ pxp_chan->eof_irq = pxp->irq;
+ pxp_chan->status = PXP_CHANNEL_FREE;
+ pxp_chan->completed = -ENXIO;
+ snprintf(pxp_chan->eof_name, sizeof(pxp_chan->eof_name),
+ "PXP EOF %d", i);
+
+ dma_chan->device = &pxp_dma->dma;
+ dma_chan->cookie = 1;
+ dma_chan->chan_id = i;
+ list_add_tail(&dma_chan->device_node, &dma->channels);
+ }
+
+ return dma_async_device_register(&pxp_dma->dma);
+}
+
+static ssize_t clk_off_timeout_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", timeout_in_ms);
+}
+
+static ssize_t clk_off_timeout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int val;
+ if (sscanf(buf, "%d", &val) > 0) {
+ timeout_in_ms = val;
+ return count;
+ }
+ return -EINVAL;
+}
+
+static DEVICE_ATTR(clk_off_timeout, 0644, clk_off_timeout_show,
+ clk_off_timeout_store);
+
+static ssize_t block_size_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", block_size);
+}
+
+static ssize_t block_size_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char **last = NULL;
+
+ block_size = simple_strtoul(buf, last, 0);
+ if (block_size > 1)
+ block_size = 1;
+
+ return count;
+}
+static DEVICE_ATTR(block_size, S_IWUSR | S_IRUGO,
+ block_size_show, block_size_store);
+
+static struct platform_device_id imx_pxpdma_devtype[] = {
+ {
+ .name = "imx7d-pxp-dma",
+ .driver_data = PXP_V3,
+ }, {
+ .name = "imx6ull-pxp-dma",
+ .driver_data = PXP_V3P,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(platform, imx_pxpdma_devtype);
+
+static const struct of_device_id imx_pxpdma_dt_ids[] = {
+ { .compatible = "fsl,imx7d-pxp-dma", .data = &imx_pxpdma_devtype[0], },
+ { .compatible = "fsl,imx6ull-pxp-dma", .data = &imx_pxpdma_devtype[1], },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_pxpdma_dt_ids);
+
+static int has_pending_task(struct pxps *pxp, struct pxp_channel *task)
+{
+ int found;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pxp->lock, flags);
+ found = !list_empty(&head);
+ spin_unlock_irqrestore(&pxp->lock, flags);
+
+ return found;
+}
+
+static int pxp_dispatch_thread(void *argv)
+{
+ struct pxps *pxp = (struct pxps *)argv;
+ struct pxp_channel *pending = NULL;
+ unsigned long flags;
+
+ set_freezable();
+
+ while (!kthread_should_stop()) {
+ int ret;
+ ret = wait_event_freezable(pxp->thread_waitq,
+ has_pending_task(pxp, pending) ||
+ kthread_should_stop());
+ if (ret < 0)
+ continue;
+
+ if (kthread_should_stop())
+ break;
+
+ spin_lock_irqsave(&pxp->lock, flags);
+ pxp->pxp_ongoing = 1;
+ spin_unlock_irqrestore(&pxp->lock, flags);
+ init_completion(&pxp->complete);
+ ret = pxpdma_dostart_work(pxp);
+ if (ret) {
+ pxp->pxp_ongoing = 0;
+ continue;
+ }
+ ret = wait_for_completion_timeout(&pxp->complete, 2 * HZ);
+ if (ret == 0) {
+ printk(KERN_EMERG "%s: task is timeout\n\n", __func__);
+ break;
+ }
+ if (pxp->devdata && pxp->devdata->pxp_lut_cleanup_multiple)
+ pxp->devdata->pxp_lut_cleanup_multiple(pxp, 0, 0);
+ }
+
+ return 0;
+}
+
+static int pxp_init_interrupt(struct platform_device *pdev)
+{
+ int legacy_irq, std_irq, err;
+ struct pxps *pxp = platform_get_drvdata(pdev);
+
+ legacy_irq = platform_get_irq(pdev, 0);
+ if (legacy_irq < 0) {
+ dev_err(&pdev->dev, "failed to get pxp legacy irq: %d\n",
+ legacy_irq);
+ return legacy_irq;
+ }
+
+ std_irq = platform_get_irq(pdev, 1);
+ if (std_irq < 0) {
+ dev_err(&pdev->dev, "failed to get pxp standard irq: %d\n",
+ std_irq);
+ return std_irq;
+ }
+
+ err = devm_request_irq(&pdev->dev, legacy_irq, pxp_irq, 0,
+ "pxp-dmaengine-legacy", pxp);
+ if (err) {
+ dev_err(&pdev->dev, "Request pxp legacy irq failed: %d\n", err);
+ return err;
+ }
+
+ err = devm_request_irq(&pdev->dev, std_irq, pxp_irq, 0,
+ "pxp-dmaengine-std", pxp);
+ if (err) {
+ dev_err(&pdev->dev, "Request pxp standard irq failed: %d\n", err);
+ return err;
+ }
+
+ pxp->irq = legacy_irq;
+
+ /* enable all the possible irq raised by PXP */
+ __raw_writel(0xffff, pxp->base + HW_PXP_IRQ_MASK);
+
+ return 0;
+}
+
+static int pxp_create_attrs(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ if ((ret = device_create_file(&pdev->dev, &dev_attr_clk_off_timeout))) {
+ dev_err(&pdev->dev,
+ "Unable to create file from clk_off_timeout\n");
+ return ret;
+ }
+
+ if ((ret = device_create_file(&pdev->dev, &dev_attr_block_size))) {
+ device_remove_file(&pdev->dev, &dev_attr_clk_off_timeout);
+
+ dev_err(&pdev->dev,
+ "Unable to create file from block_size\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void pxp_remove_attrs(struct platform_device *pdev)
+{
+ device_remove_file(&pdev->dev, &dev_attr_clk_off_timeout);
+ device_remove_file(&pdev->dev, &dev_attr_block_size);
+}
+
+static void pxp_init_timer(struct pxps *pxp)
+{
+ INIT_WORK(&pxp->work, clkoff_callback);
+
+ init_timer(&pxp->clk_timer);
+ pxp->clk_timer.function = pxp_clkoff_timer;
+ pxp->clk_timer.data = (unsigned long)pxp;
+}
+
+static bool is_mux_node(uint32_t node_id)
+{
+ if ((node_id < PXP_2D_MUX_MUX0) ||
+ (node_id > PXP_2D_MUX_MUX15))
+ return false;
+
+ return true;
+}
+
+static bool search_mux_chain(uint32_t mux_id,
+ struct edge_node *enode)
+{
+ bool found = false;
+ uint32_t i, j, next_mux = 0;
+ uint32_t output;
+ struct mux *muxes;
+
+ muxes = (v3p_flag) ? muxes_v3p : muxes_v3;
+
+ for (i = 0; i < 2; i++) {
+ output = muxes[mux_id].mux_outputs[i];
+ if (output == 0xff)
+ break;
+
+ if ((output == enode->adjvex)) {
+ /* found */
+ found = true;
+ break;
+ } else if (is_mux_node(output)) {
+ next_mux = output - PXP_2D_MUX_BASE;
+ found = search_mux_chain(next_mux, enode);
+
+ if (found) {
+ for (j = 0; j < 4; j++) {
+ if (muxes[next_mux].mux_inputs[j] ==
+ (mux_id + PXP_2D_MUX_BASE))
+ break;
+ }
+
+ set_bit(next_mux, (unsigned long *)&enode->mux_used);
+ set_mux_val(&enode->muxes, next_mux, j);
+ break;
+ }
+ }
+ }
+
+ return found;
+}
+
+static void enode_mux_config(unsigned int vnode_id,
+ struct edge_node *enode)
+{
+ uint32_t i, j;
+ bool via_mux = false, need_search = false;
+ struct mux *muxes;
+
+ BUG_ON(vnode_id >= PXP_2D_NUM);
+ BUG_ON(enode->adjvex >= PXP_2D_NUM);
+
+ muxes = (v3p_flag) ? muxes_v3p : muxes_v3;
+
+ for (i = 0; i < 16; i++) {
+ for (j = 0; j < 4; j++) {
+ if (muxes[i].mux_inputs[j] == 0xff)
+ break;
+
+ if (muxes[i].mux_inputs[j] == vnode_id)
+ need_search = true;
+ else if (muxes[i].mux_inputs[j] == PXP_2D_ALPHA0_S0_S1) {
+ if ((vnode_id == PXP_2D_ALPHA0_S0) ||
+ (vnode_id == PXP_2D_ALPHA0_S1))
+ need_search = true;
+ } else if (muxes[i].mux_inputs[j] == PXP_2D_ALPHA1_S0_S1) {
+ if ((vnode_id == PXP_2D_ALPHA1_S0) ||
+ (vnode_id == PXP_2D_ALPHA1_S1))
+ need_search = true;
+ }
+
+ if (need_search) {
+ via_mux = search_mux_chain(i, enode);
+ need_search = false;
+ break;
+ }
+ }
+
+ if (via_mux) {
+ set_bit(i, (unsigned long *)&enode->mux_used);
+ set_mux_val(&enode->muxes, i, j);
+ break;
+ }
+ }
+}
+
+static int pxp_create_initial_graph(struct platform_device *pdev)
+{
+ int i, j, first;
+ static bool (*adj_array)[PXP_2D_NUM];
+ struct edge_node *enode, *curr = NULL;
+
+ adj_array = (v3p_flag) ? adj_array_v3p : adj_array_v3;
+
+ for (i = 0; i < PXP_2D_NUM; i++) {
+ switch (i) {
+ case PXP_2D_PS:
+ case PXP_2D_AS:
+ case PXP_2D_INPUT_FETCH0:
+ case PXP_2D_INPUT_FETCH1:
+ adj_list[i].type = PXP_2D_TYPE_INPUT;
+ break;
+ case PXP_2D_OUT:
+ case PXP_2D_INPUT_STORE0:
+ case PXP_2D_INPUT_STORE1:
+ adj_list[i].type = PXP_2D_TYPE_OUTPUT;
+ break;
+ default:
+ adj_list[i].type = PXP_2D_TYPE_ALU;
+ break;
+ }
+
+ first = -1;
+
+ for (j = 0; j < PXP_2D_NUM; j++) {
+ if (adj_array[i][j]) {
+ enode = kmem_cache_alloc(edge_node_cache,
+ GFP_KERNEL | __GFP_ZERO);
+ if (!enode) {
+ dev_err(&pdev->dev, "allocate edge node failed\n");
+ return -ENOMEM;
+ }
+ enode->adjvex = j;
+ enode->prev_vnode = i;
+
+ if (unlikely(first == -1)) {
+ first = j;
+ adj_list[i].first = enode;
+ } else
+ curr->next = enode;
+
+ curr = enode;
+ enode_mux_config(i, enode);
+ dev_dbg(&pdev->dev, "(%d -> %d): mux_used 0x%x, mux_config 0x%x\n\n",
+ i, j, enode->mux_used, *(unsigned int*)&enode->muxes);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Calculate the shortest paths start via
+ * 'from' node to other nodes
+ */
+static void pxp_find_shortest_path(unsigned int from)
+{
+ int i;
+ struct edge_node *enode;
+ struct path_node *pnode, *adjnode;
+ struct list_head queue;
+
+ INIT_LIST_HEAD(&queue);
+ list_add_tail(&path_table[from][from].node, &queue);
+
+ while(!list_empty(&queue)) {
+ pnode = list_entry(queue.next, struct path_node, node);
+ enode = adj_list[pnode->id].first;
+ while (enode) {
+ adjnode = &path_table[from][enode->adjvex];
+
+ if (adjnode->distance == DISTANCE_INFINITY) {
+ adjnode->distance = pnode->distance + 1;
+ adjnode->prev_node = pnode->id;
+ list_add_tail(&adjnode->node, &queue);
+ }
+
+ enode = enode->next;
+ }
+ list_del_init(&pnode->node);
+ }
+
+ for (i = 0; i < PXP_2D_NUM; i++)
+ pr_debug("From %u: to %d (id = %d, distance = 0x%x, prev_node = %d\n",
+ from, i, path_table[from][i].id, path_table[from][i].distance,
+ path_table[from][i].prev_node);
+}
+
+static int pxp_gen_shortest_paths(struct platform_device *pdev)
+{
+ int i, j;
+
+ for (i = 0; i < PXP_2D_NUM; i++) {
+ for (j = 0; j < PXP_2D_NUM; j++) {
+ path_table[i][j].id = j;
+ path_table[i][j].distance = DISTANCE_INFINITY;
+ path_table[i][j].prev_node = NO_PATH_NODE;
+ INIT_LIST_HEAD(&path_table[i][j].node);
+ }
+
+ path_table[i][i].distance = 0;
+
+ pxp_find_shortest_path(i);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_MXC_FPGA_M4_TEST
+static void pxp_config_m4(struct platform_device *pdev)
+{
+ fpga_tcml_base = ioremap(FPGA_TCML_ADDR, SZ_32K);
+ if (fpga_tcml_base == NULL) {
+ dev_err(&pdev->dev,
+ "get fpga_tcml_base error.\n");
+ goto exit;
+ }
+ pinctrl_base = ioremap(PINCTRL, SZ_4K);
+ if (pinctrl_base == NULL) {
+ dev_err(&pdev->dev,
+ "get fpga_tcml_base error.\n");
+ goto exit;
+ }
+
+ __raw_writel(0xC0000000, pinctrl_base + 0x08);
+ __raw_writel(0x3, pinctrl_base + PIN_DOUT);
+ int i;
+ for (i = 0; i < 1024 * 32 / 4; i++) {
+ *(((unsigned int *)(fpga_tcml_base)) + i) = cm4_image[i];
+ }
+}
+#endif
+
+static int pxp_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id =
+ of_match_device(imx_pxpdma_dt_ids, &pdev->dev);
+ struct pxps *pxp;
+ struct resource *res;
+ int err = 0;
+
+ if (of_id)
+ pdev->id_entry = of_id->data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ pxp = devm_kzalloc(&pdev->dev, sizeof(*pxp), GFP_KERNEL);
+ if (!pxp) {
+ dev_err(&pdev->dev, "failed to allocate control object\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ pxp->dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, pxp);
+
+ spin_lock_init(&pxp->lock);
+ mutex_init(&pxp->clk_mutex);
+
+ pxp->base = devm_ioremap_resource(&pdev->dev, res);
+ if (pxp->base == NULL) {
+ dev_err(&pdev->dev, "Couldn't ioremap regs\n");
+ err = -ENODEV;
+ goto exit;
+ }
+ pxp_reg_base = pxp->base;
+
+ pxp->pdev = pdev;
+ pxp->devdata = &pxp_devdata[pdev->id_entry->driver_data];
+
+ v3p_flag = (pxp_is_v3p(pxp)) ? true : false;
+
+ pxp->ipg_clk = devm_clk_get(&pdev->dev, "pxp_ipg");
+ pxp->axi_clk = devm_clk_get(&pdev->dev, "pxp_axi");
+
+ if (IS_ERR(pxp->ipg_clk) || IS_ERR(pxp->axi_clk)) {
+ dev_err(&pdev->dev, "pxp clocks invalid\n");
+ err = -EINVAL;
+ goto exit;
+ }
+
+ pxp_soft_reset(pxp);
+ pxp_writel(0x0, HW_PXP_CTRL);
+ /* Initialize DMA engine */
+ err = pxp_dma_init(pxp);
+ if (err < 0)
+ goto exit;
+
+ pxp_clk_enable(pxp);
+ pxp_soft_reset(pxp);
+
+ /* Initialize PXP Interrupt */
+ err = pxp_init_interrupt(pdev);
+ if (err < 0)
+ goto exit;
+
+ if (pxp->devdata && pxp->devdata->pxp_data_path_config)
+ pxp->devdata->pxp_data_path_config(pxp);
+
+ dump_pxp_reg(pxp);
+ pxp_clk_disable(pxp);
+
+ pxp_init_timer(pxp);
+
+ init_waitqueue_head(&pxp->thread_waitq);
+ /* allocate a kernel thread to dispatch pxp conf */
+ pxp->dispatch = kthread_run(pxp_dispatch_thread, pxp, "pxp_dispatch");
+ if (IS_ERR(pxp->dispatch)) {
+ err = PTR_ERR(pxp->dispatch);
+ goto exit;
+ }
+ tx_desc_cache = kmem_cache_create("tx_desc", sizeof(struct pxp_tx_desc),
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!tx_desc_cache) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ edge_node_cache = kmem_cache_create("edge_node", sizeof(struct edge_node),
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!edge_node_cache) {
+ err = -ENOMEM;
+ kmem_cache_destroy(tx_desc_cache);
+ goto exit;
+ }
+
+ err = pxp_create_attrs(pdev);
+ if (err) {
+ kmem_cache_destroy(tx_desc_cache);
+ kmem_cache_destroy(edge_node_cache);
+ goto exit;
+ }
+
+ if ((err = pxp_create_initial_graph(pdev))) {
+ kmem_cache_destroy(tx_desc_cache);
+ kmem_cache_destroy(edge_node_cache);
+ goto exit;
+ }
+
+ pxp_gen_shortest_paths(pdev);
+
+#ifdef CONFIG_MXC_FPGA_M4_TEST
+ pxp_config_m4(pdev);
+#endif
+ register_pxp_device();
+ pm_runtime_enable(pxp->dev);
+
+ dma_alloc_coherent(NULL, PAGE_ALIGN(1920 * 1088 * 4),
+ &paddr, GFP_KERNEL);
+
+exit:
+ if (err)
+ dev_err(&pdev->dev, "Exiting (unsuccessfully) pxp_probe()\n");
+ return err;
+}
+
+static int pxp_remove(struct platform_device *pdev)
+{
+ struct pxps *pxp = platform_get_drvdata(pdev);
+
+ unregister_pxp_device();
+ kmem_cache_destroy(tx_desc_cache);
+ kmem_cache_destroy(edge_node_cache);
+ kthread_stop(pxp->dispatch);
+ cancel_work_sync(&pxp->work);
+ del_timer_sync(&pxp->clk_timer);
+ clk_disable_unprepare(pxp->ipg_clk);
+ clk_disable_unprepare(pxp->axi_clk);
+ pxp_remove_attrs(pdev);
+ dma_async_device_unregister(&(pxp->pxp_dma.dma));
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pxp_suspend(struct device *dev)
+{
+ struct pxps *pxp = dev_get_drvdata(dev);
+
+ pxp_clk_enable(pxp);
+ while (__raw_readl(pxp->base + HW_PXP_CTRL) & BM_PXP_CTRL_ENABLE)
+ ;
+
+ __raw_writel(BM_PXP_CTRL_SFTRST, pxp->base + HW_PXP_CTRL);
+ pxp_clk_disable(pxp);
+
+ return 0;
+}
+
+static int pxp_resume(struct device *dev)
+{
+ struct pxps *pxp = dev_get_drvdata(dev);
+
+ pxp_clk_enable(pxp);
+ /* Pull PxP out of reset */
+ pxp_soft_reset(pxp);
+ if (pxp->devdata && pxp->devdata->pxp_data_path_config)
+ pxp->devdata->pxp_data_path_config(pxp);
+ /* enable all the possible irq raised by PXP */
+ __raw_writel(0xffff, pxp->base + HW_PXP_IRQ_MASK);
+ pxp_clk_disable(pxp);
+
+ return 0;
+}
+#else
+#define pxp_suspend NULL
+#define pxp_resume NULL
+#endif
+
+#ifdef CONFIG_PM
+static int pxp_runtime_suspend(struct device *dev)
+{
+ dev_dbg(dev, "pxp busfreq high release.\n");
+
+ return 0;
+}
+
+static int pxp_runtime_resume(struct device *dev)
+{
+ dev_dbg(dev, "pxp busfreq high request.\n");
+
+ return 0;
+}
+#else
+#define pxp_runtime_suspend NULL
+#define pxp_runtime_resume NULL
+#endif
+
+static const struct dev_pm_ops pxp_pm_ops = {
+ SET_RUNTIME_PM_OPS(pxp_runtime_suspend, pxp_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pxp_suspend, pxp_resume)
+};
+
+static struct platform_driver pxp_driver = {
+ .driver = {
+ .name = "imx-pxp-v3",
+ .of_match_table = of_match_ptr(imx_pxpdma_dt_ids),
+ .pm = &pxp_pm_ops,
+ },
+ .probe = pxp_probe,
+ .remove = pxp_remove,
+};
+
+static int __init pxp_init(void)
+{
+ return platform_driver_register(&pxp_driver);
+}
+late_initcall(pxp_init);
+
+static void __exit pxp_exit(void)
+{
+ platform_driver_unregister(&pxp_driver);
+}
+module_exit(pxp_exit);
+
+
+MODULE_DESCRIPTION("i.MX PxP driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/dma/pxp/reg_bitfields.h b/drivers/dma/pxp/reg_bitfields.h
new file mode 100644
index 000000000000..95b5c83b4b15
--- /dev/null
+++ b/drivers/dma/pxp/reg_bitfields.h
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2010-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; 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 _REG_BITFIELDS_H
+#define _REG_BITFIELDS_H
+struct mux_config {
+ uint32_t mux0_sel : 2;
+ uint32_t mux1_sel : 2;
+ uint32_t mux2_sel : 2;
+ uint32_t mux3_sel : 2;
+ uint32_t mux4_sel : 2;
+ uint32_t mux5_sel : 2;
+ uint32_t mux6_sel : 2;
+ uint32_t mux7_sel : 2;
+ uint32_t mux8_sel : 2;
+ uint32_t mux9_sel : 2;
+ uint32_t mux10_sel : 2;
+ uint32_t mux11_sel : 2;
+ uint32_t mux12_sel : 2;
+ uint32_t mux13_sel : 2;
+ uint32_t mux14_sel : 2;
+ uint32_t mux15_sel : 2;
+};
+
+/* legacy engine registers */
+struct ps_ctrl {
+ uint32_t format : 6;
+ uint32_t wb_swap : 1;
+ uint32_t rsvd0 : 1;
+ uint32_t decy : 2;
+ uint32_t decx : 2;
+ uint32_t rsvd1 : 20;
+};
+
+struct ps_scale {
+ uint32_t xscale : 15;
+ uint32_t rsvd1 : 1;
+ uint32_t yscale : 15;
+ uint32_t rsvd2 : 1;
+};
+
+struct ps_offset {
+ uint32_t xoffset : 12;
+ uint32_t rsvd1 : 4;
+ uint32_t yoffset : 12;
+ uint32_t rsvd2 : 4;
+};
+
+struct as_ctrl {
+ uint32_t rsvd0 : 1;
+ uint32_t alpha_ctrl : 2;
+ uint32_t enable_colorkey : 1;
+ uint32_t format : 4;
+ uint32_t alpha : 8;
+ uint32_t rop : 4;
+ uint32_t alpha0_invert : 1;
+ uint32_t alpha1_invert : 1;
+ uint32_t rsvd1 : 10;
+};
+
+struct out_ctrl {
+ uint32_t format : 5;
+ uint32_t rsvd0 : 3;
+ uint32_t interlaced_output : 2;
+ uint32_t rsvd1 : 13;
+ uint32_t alpha_output : 1;
+ uint32_t alpha : 8;
+};
+
+struct coordinate {
+ uint32_t y : 14;
+ uint32_t rsvd0 : 2;
+ uint32_t x : 14;
+ uint32_t rsvd1 : 2;
+};
+
+struct pxp_alpha_ctrl {
+ uint32_t poter_duff_enable : 1;
+ uint32_t s0_s1_factor_mode : 2;
+ uint32_t s0_global_alpha_mode : 2;
+ uint32_t s0_alpha_mode : 1;
+ uint32_t s0_color_mode : 1;
+ uint32_t rsvd1 : 1;
+ uint32_t s1_s0_factor_mode : 2;
+ uint32_t s1_global_alpha_mode : 2;
+ uint32_t s1_alpha_mode : 1;
+ uint32_t s1_color_mode : 1;
+ uint32_t rsvd0 : 2;
+ uint32_t s0_global_alpha : 8;
+ uint32_t s1_global_alpha : 8;
+};
+
+/* store engine registers */
+struct store_ctrl {
+ uint32_t ch_en : 1;
+ uint32_t block_en : 1;
+ uint32_t block_16 : 1;
+ uint32_t handshake_en : 1;
+ uint32_t array_en : 1;
+ uint32_t array_line_num : 2;
+ uint32_t rsvd3 : 1;
+ uint32_t store_bypass_en : 1;
+ uint32_t store_memory_en : 1;
+ uint32_t pack_in_sel : 1;
+ uint32_t fill_data_en : 1;
+ uint32_t rsvd2 : 4;
+ uint32_t wr_num_bytes : 2;
+ uint32_t rsvd1 : 6;
+ uint32_t combine_2channel : 1;
+ uint32_t rsvd0 : 6;
+ uint32_t arbit_en : 1;
+};
+
+struct store_size {
+ uint32_t out_width : 16;
+ uint32_t out_height : 16;
+};
+
+struct store_pitch {
+ uint32_t ch0_out_pitch : 16;
+ uint32_t ch1_out_pitch : 16;
+};
+
+struct store_shift_ctrl {
+ uint32_t rsvd2 : 2;
+ uint32_t output_active_bpp : 2;
+ uint32_t out_yuv422_1p_en : 1;
+ uint32_t out_yuv422_2p_en : 1;
+ uint32_t rsvd1 : 1;
+ uint32_t shift_bypass : 1;
+ uint32_t rsvd0 : 24;
+};
+
+struct store_d_shift {
+ uint64_t d_shift_width0 : 6;
+ uint64_t rsvd3 : 1;
+ uint64_t d_shift_flag0 : 1;
+ uint64_t d_shift_width1 : 6;
+ uint64_t rsvd2 : 1;
+ uint64_t d_shift_flag1 : 1;
+ uint64_t d_shift_width2 : 6;
+ uint64_t rsvd1 : 1;
+ uint64_t d_shift_flag2 : 1;
+ uint64_t d_shift_width3 : 6;
+ uint64_t rsvd0 : 1;
+ uint64_t d_shift_flag3 : 1;
+
+ uint64_t d_shift_width4 : 6;
+ uint64_t rsvd7 : 1;
+ uint64_t d_shift_flag4 : 1;
+ uint64_t d_shift_width5 : 6;
+ uint64_t rsvd6 : 1;
+ uint64_t d_shift_flag5 : 1;
+ uint64_t d_shift_width6 : 6;
+ uint64_t rsvd5 : 1;
+ uint64_t d_shift_flag6 : 1;
+ uint64_t d_shift_width7 : 6;
+ uint64_t rsvd4 : 1;
+ uint64_t d_shift_flag7 : 1;
+};
+
+struct store_f_shift {
+ uint64_t f_shift_width0 : 6;
+ uint64_t rsvd3 : 1;
+ uint64_t f_shift_flag0 : 1;
+ uint64_t f_shift_width1 : 6;
+ uint64_t rsvd2 : 1;
+ uint64_t f_shift_flag1 : 1;
+ uint64_t f_shift_width2 : 6;
+ uint64_t rsvd1 : 1;
+ uint64_t f_shift_flag2 : 1;
+ uint64_t f_shift_width3 : 6;
+ uint64_t rsvd0 : 1;
+ uint64_t f_shift_flag3 : 1;
+
+ uint64_t f_shift_width4 : 6;
+ uint64_t rsvd7 : 1;
+ uint64_t f_shift_flag4 : 1;
+ uint64_t f_shift_width5 : 6;
+ uint64_t rsvd6 : 1;
+ uint64_t f_shift_flag5 : 1;
+ uint64_t f_shift_width6 : 6;
+ uint64_t rsvd5 : 1;
+ uint64_t f_shift_flag6 : 1;
+ uint64_t f_shift_width7 : 6;
+ uint64_t rsvd4 : 1;
+ uint64_t f_shift_flag7 : 1;
+};
+
+struct store_d_mask {
+ uint64_t d_mask_l : 32;
+ uint64_t d_mask_h : 32;
+};
+
+/* fetch engine registers */
+struct fetch_ctrl {
+ uint32_t ch_en : 1;
+ uint32_t block_en : 1;
+ uint32_t block_16 : 1;
+ uint32_t handshake_en : 1;
+ uint32_t bypass_pixel_en : 1;
+ uint32_t high_byte : 1;
+ uint32_t rsvd4 : 3;
+ uint32_t hflip : 1;
+ uint32_t vflip : 1;
+ uint32_t rsvd3 : 1;
+ uint32_t rotation_angle : 2;
+ uint32_t rsvd2 : 2;
+ uint32_t rd_num_bytes : 2;
+ uint32_t rsvd1 : 6;
+ uint32_t handshake_scan_line_num : 2;
+ uint32_t rsvd0 : 5;
+ uint32_t arbit_en : 1;
+};
+
+struct fetch_active_size_ulc {
+ uint32_t active_size_ulc_x : 16;
+ uint32_t active_size_ulc_y : 16;
+};
+
+struct fetch_active_size_lrc {
+ uint32_t active_size_lrc_x : 16;
+ uint32_t active_size_lrc_y : 16;
+};
+
+struct fetch_size {
+ uint32_t input_total_width : 16;
+ uint32_t input_total_height : 16;
+};
+
+struct fetch_pitch {
+ uint32_t ch0_input_pitch : 16;
+ uint32_t ch1_input_pitch : 16;
+};
+
+struct fetch_shift_ctrl {
+ uint32_t input_active_bpp : 2;
+ uint32_t rsvd1 : 6;
+ uint32_t expand_format : 3;
+ uint32_t expand_en : 1;
+ uint32_t shift_bypass : 1;
+ uint32_t rsvd0 : 19;
+};
+
+struct fetch_shift_offset {
+ uint32_t offset0 : 5;
+ uint32_t rsvd3 : 3;
+ uint32_t offset1 : 5;
+ uint32_t rsvd2 : 3;
+ uint32_t offset2 : 5;
+ uint32_t rsvd1 : 3;
+ uint32_t offset3 : 5;
+ uint32_t rsvd0 : 3;
+};
+
+struct fetch_shift_width {
+ uint32_t width0 : 4;
+ uint32_t width1 : 4;
+ uint32_t width2 : 4;
+ uint32_t width3 : 4;
+ uint32_t rsvd0 : 16;
+};
+#endif
diff --git a/drivers/dma/pxp/regs-pxp_v2.h b/drivers/dma/pxp/regs-pxp_v2.h
new file mode 100644
index 000000000000..8b20ddef3954
--- /dev/null
+++ b/drivers/dma/pxp/regs-pxp_v2.h
@@ -0,0 +1,1152 @@
+/*
+ * Freescale PXP Register Definitions
+ *
+ * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This file is created by xml file. Don't Edit it.
+ *
+ * Xml Revision: 1.29
+ * Template revision: 1.3
+ */
+
+#ifndef __ARCH_ARM___PXP_H
+#define __ARCH_ARM___PXP_H
+
+#define HW_PXP_CTRL (0x00000000)
+#define HW_PXP_CTRL_SET (0x00000004)
+#define HW_PXP_CTRL_CLR (0x00000008)
+#define HW_PXP_CTRL_TOG (0x0000000c)
+
+#define BM_PXP_CTRL_SFTRST 0x80000000
+#define BM_PXP_CTRL_CLKGATE 0x40000000
+#define BM_PXP_CTRL_RSVD4 0x20000000
+#define BM_PXP_CTRL_EN_REPEAT 0x10000000
+#define BP_PXP_CTRL_RSVD3 26
+#define BM_PXP_CTRL_RSVD3 0x0C000000
+#define BF_PXP_CTRL_RSVD3(v) \
+ (((v) << 26) & BM_PXP_CTRL_RSVD3)
+#define BP_PXP_CTRL_INTERLACED_INPUT 24
+#define BM_PXP_CTRL_INTERLACED_INPUT 0x03000000
+#define BF_PXP_CTRL_INTERLACED_INPUT(v) \
+ (((v) << 24) & BM_PXP_CTRL_INTERLACED_INPUT)
+#define BV_PXP_CTRL_INTERLACED_INPUT__PROGRESSIVE 0x0
+#define BV_PXP_CTRL_INTERLACED_INPUT__FIELD0 0x2
+#define BV_PXP_CTRL_INTERLACED_INPUT__FIELD1 0x3
+#define BM_PXP_CTRL_BLOCK_SIZE 0x00800000
+#define BV_PXP_CTRL_BLOCK_SIZE__8X8 0x0
+#define BV_PXP_CTRL_BLOCK_SIZE__16X16 0x1
+#define BM_PXP_CTRL_ROT_POS 0x00400000
+#define BM_PXP_CTRL_IN_PLACE 0x00200000
+#define BP_PXP_CTRL_RSVD1 12
+#define BM_PXP_CTRL_RSVD1 0x001FF000
+#define BF_PXP_CTRL_RSVD1(v) \
+ (((v) << 12) & BM_PXP_CTRL_RSVD1)
+#define BM_PXP_CTRL_VFLIP 0x00000800
+#define BM_PXP_CTRL_HFLIP 0x00000400
+#define BP_PXP_CTRL_ROTATE 8
+#define BM_PXP_CTRL_ROTATE 0x00000300
+#define BF_PXP_CTRL_ROTATE(v) \
+ (((v) << 8) & BM_PXP_CTRL_ROTATE)
+#define BV_PXP_CTRL_ROTATE__ROT_0 0x0
+#define BV_PXP_CTRL_ROTATE__ROT_90 0x1
+#define BV_PXP_CTRL_ROTATE__ROT_180 0x2
+#define BV_PXP_CTRL_ROTATE__ROT_270 0x3
+#define BP_PXP_CTRL_RSVD0 5
+#define BM_PXP_CTRL_RSVD0 0x000000E0
+#define BF_PXP_CTRL_RSVD0(v) \
+ (((v) << 5) & BM_PXP_CTRL_RSVD0)
+#define BM_PXP_CTRL_ENABLE_LCD_HANDSHAKE 0x00000010
+#define BM_PXP_CTRL_LUT_DMA_IRQ_ENABLE 0x00000008
+#define BM_PXP_CTRL_NEXT_IRQ_ENABLE 0x00000004
+#define BM_PXP_CTRL_IRQ_ENABLE 0x00000002
+#define BM_PXP_CTRL_ENABLE 0x00000001
+
+#define HW_PXP_STAT (0x00000010)
+#define HW_PXP_STAT_SET (0x00000014)
+#define HW_PXP_STAT_CLR (0x00000018)
+#define HW_PXP_STAT_TOG (0x0000001c)
+
+#define BP_PXP_STAT_BLOCKX 24
+#define BM_PXP_STAT_BLOCKX 0xFF000000
+#define BF_PXP_STAT_BLOCKX(v) \
+ (((v) << 24) & BM_PXP_STAT_BLOCKX)
+#define BP_PXP_STAT_BLOCKY 16
+#define BM_PXP_STAT_BLOCKY 0x00FF0000
+#define BF_PXP_STAT_BLOCKY(v) \
+ (((v) << 16) & BM_PXP_STAT_BLOCKY)
+#define BP_PXP_STAT_RSVD2 9
+#define BM_PXP_STAT_RSVD2 0x0000FE00
+#define BF_PXP_STAT_RSVD2(v) \
+ (((v) << 9) & BM_PXP_STAT_RSVD2)
+#define BM_PXP_STAT_LUT_DMA_LOAD_DONE_IRQ 0x00000100
+#define BP_PXP_STAT_AXI_ERROR_ID 4
+#define BM_PXP_STAT_AXI_ERROR_ID 0x000000F0
+#define BF_PXP_STAT_AXI_ERROR_ID(v) \
+ (((v) << 4) & BM_PXP_STAT_AXI_ERROR_ID)
+#define BM_PXP_STAT_NEXT_IRQ 0x00000008
+#define BM_PXP_STAT_AXI_READ_ERROR 0x00000004
+#define BM_PXP_STAT_AXI_WRITE_ERROR 0x00000002
+#define BM_PXP_STAT_IRQ 0x00000001
+
+#define HW_PXP_OUT_CTRL (0x00000020)
+#define HW_PXP_OUT_CTRL_SET (0x00000024)
+#define HW_PXP_OUT_CTRL_CLR (0x00000028)
+#define HW_PXP_OUT_CTRL_TOG (0x0000002c)
+
+#define BP_PXP_OUT_CTRL_ALPHA 24
+#define BM_PXP_OUT_CTRL_ALPHA 0xFF000000
+#define BF_PXP_OUT_CTRL_ALPHA(v) \
+ (((v) << 24) & BM_PXP_OUT_CTRL_ALPHA)
+#define BM_PXP_OUT_CTRL_ALPHA_OUTPUT 0x00800000
+#define BP_PXP_OUT_CTRL_RSVD1 10
+#define BM_PXP_OUT_CTRL_RSVD1 0x007FFC00
+#define BF_PXP_OUT_CTRL_RSVD1(v) \
+ (((v) << 10) & BM_PXP_OUT_CTRL_RSVD1)
+#define BP_PXP_OUT_CTRL_INTERLACED_OUTPUT 8
+#define BM_PXP_OUT_CTRL_INTERLACED_OUTPUT 0x00000300
+#define BF_PXP_OUT_CTRL_INTERLACED_OUTPUT(v) \
+ (((v) << 8) & BM_PXP_OUT_CTRL_INTERLACED_OUTPUT)
+#define BV_PXP_OUT_CTRL_INTERLACED_OUTPUT__PROGRESSIVE 0x0
+#define BV_PXP_OUT_CTRL_INTERLACED_OUTPUT__FIELD0 0x1
+#define BV_PXP_OUT_CTRL_INTERLACED_OUTPUT__FIELD1 0x2
+#define BV_PXP_OUT_CTRL_INTERLACED_OUTPUT__INTERLACED 0x3
+#define BP_PXP_OUT_CTRL_RSVD0 5
+#define BM_PXP_OUT_CTRL_RSVD0 0x000000E0
+#define BF_PXP_OUT_CTRL_RSVD0(v) \
+ (((v) << 5) & BM_PXP_OUT_CTRL_RSVD0)
+#define BP_PXP_OUT_CTRL_FORMAT 0
+#define BM_PXP_OUT_CTRL_FORMAT 0x0000001F
+#define BF_PXP_OUT_CTRL_FORMAT(v) \
+ (((v) << 0) & BM_PXP_OUT_CTRL_FORMAT)
+#define BV_PXP_OUT_CTRL_FORMAT__ARGB8888 0x0
+#define BV_PXP_OUT_CTRL_FORMAT__RGB888 0x4
+#define BV_PXP_OUT_CTRL_FORMAT__RGB888P 0x5
+#define BV_PXP_OUT_CTRL_FORMAT__ARGB1555 0x8
+#define BV_PXP_OUT_CTRL_FORMAT__ARGB4444 0x9
+#define BV_PXP_OUT_CTRL_FORMAT__RGB555 0xC
+#define BV_PXP_OUT_CTRL_FORMAT__RGB444 0xD
+#define BV_PXP_OUT_CTRL_FORMAT__RGB565 0xE
+#define BV_PXP_OUT_CTRL_FORMAT__YUV1P444 0x10
+#define BV_PXP_OUT_CTRL_FORMAT__UYVY1P422 0x12
+#define BV_PXP_OUT_CTRL_FORMAT__VYUY1P422 0x13
+#define BV_PXP_OUT_CTRL_FORMAT__Y8 0x14
+#define BV_PXP_OUT_CTRL_FORMAT__Y4 0x15
+#define BV_PXP_OUT_CTRL_FORMAT__YUV2P422 0x18
+#define BV_PXP_OUT_CTRL_FORMAT__YUV2P420 0x19
+#define BV_PXP_OUT_CTRL_FORMAT__YVU2P422 0x1A
+#define BV_PXP_OUT_CTRL_FORMAT__YVU2P420 0x1B
+
+#define HW_PXP_OUT_BUF (0x00000030)
+
+#define BP_PXP_OUT_BUF_ADDR 0
+#define BM_PXP_OUT_BUF_ADDR 0xFFFFFFFF
+#define BF_PXP_OUT_BUF_ADDR(v) (v)
+
+#define HW_PXP_OUT_BUF2 (0x00000040)
+
+#define BP_PXP_OUT_BUF2_ADDR 0
+#define BM_PXP_OUT_BUF2_ADDR 0xFFFFFFFF
+#define BF_PXP_OUT_BUF2_ADDR(v) (v)
+
+#define HW_PXP_OUT_PITCH (0x00000050)
+
+#define BP_PXP_OUT_PITCH_RSVD 16
+#define BM_PXP_OUT_PITCH_RSVD 0xFFFF0000
+#define BF_PXP_OUT_PITCH_RSVD(v) \
+ (((v) << 16) & BM_PXP_OUT_PITCH_RSVD)
+#define BP_PXP_OUT_PITCH_PITCH 0
+#define BM_PXP_OUT_PITCH_PITCH 0x0000FFFF
+#define BF_PXP_OUT_PITCH_PITCH(v) \
+ (((v) << 0) & BM_PXP_OUT_PITCH_PITCH)
+
+#define HW_PXP_OUT_LRC (0x00000060)
+
+#define BP_PXP_OUT_LRC_RSVD1 30
+#define BM_PXP_OUT_LRC_RSVD1 0xC0000000
+#define BF_PXP_OUT_LRC_RSVD1(v) \
+ (((v) << 30) & BM_PXP_OUT_LRC_RSVD1)
+#define BP_PXP_OUT_LRC_X 16
+#define BM_PXP_OUT_LRC_X 0x3FFF0000
+#define BF_PXP_OUT_LRC_X(v) \
+ (((v) << 16) & BM_PXP_OUT_LRC_X)
+#define BP_PXP_OUT_LRC_RSVD0 14
+#define BM_PXP_OUT_LRC_RSVD0 0x0000C000
+#define BF_PXP_OUT_LRC_RSVD0(v) \
+ (((v) << 14) & BM_PXP_OUT_LRC_RSVD0)
+#define BP_PXP_OUT_LRC_Y 0
+#define BM_PXP_OUT_LRC_Y 0x00003FFF
+#define BF_PXP_OUT_LRC_Y(v) \
+ (((v) << 0) & BM_PXP_OUT_LRC_Y)
+
+#define HW_PXP_OUT_PS_ULC (0x00000070)
+
+#define BP_PXP_OUT_PS_ULC_RSVD1 30
+#define BM_PXP_OUT_PS_ULC_RSVD1 0xC0000000
+#define BF_PXP_OUT_PS_ULC_RSVD1(v) \
+ (((v) << 30) & BM_PXP_OUT_PS_ULC_RSVD1)
+#define BP_PXP_OUT_PS_ULC_X 16
+#define BM_PXP_OUT_PS_ULC_X 0x3FFF0000
+#define BF_PXP_OUT_PS_ULC_X(v) \
+ (((v) << 16) & BM_PXP_OUT_PS_ULC_X)
+#define BP_PXP_OUT_PS_ULC_RSVD0 14
+#define BM_PXP_OUT_PS_ULC_RSVD0 0x0000C000
+#define BF_PXP_OUT_PS_ULC_RSVD0(v) \
+ (((v) << 14) & BM_PXP_OUT_PS_ULC_RSVD0)
+#define BP_PXP_OUT_PS_ULC_Y 0
+#define BM_PXP_OUT_PS_ULC_Y 0x00003FFF
+#define BF_PXP_OUT_PS_ULC_Y(v) \
+ (((v) << 0) & BM_PXP_OUT_PS_ULC_Y)
+
+#define HW_PXP_OUT_PS_LRC (0x00000080)
+
+#define BP_PXP_OUT_PS_LRC_RSVD1 30
+#define BM_PXP_OUT_PS_LRC_RSVD1 0xC0000000
+#define BF_PXP_OUT_PS_LRC_RSVD1(v) \
+ (((v) << 30) & BM_PXP_OUT_PS_LRC_RSVD1)
+#define BP_PXP_OUT_PS_LRC_X 16
+#define BM_PXP_OUT_PS_LRC_X 0x3FFF0000
+#define BF_PXP_OUT_PS_LRC_X(v) \
+ (((v) << 16) & BM_PXP_OUT_PS_LRC_X)
+#define BP_PXP_OUT_PS_LRC_RSVD0 14
+#define BM_PXP_OUT_PS_LRC_RSVD0 0x0000C000
+#define BF_PXP_OUT_PS_LRC_RSVD0(v) \
+ (((v) << 14) & BM_PXP_OUT_PS_LRC_RSVD0)
+#define BP_PXP_OUT_PS_LRC_Y 0
+#define BM_PXP_OUT_PS_LRC_Y 0x00003FFF
+#define BF_PXP_OUT_PS_LRC_Y(v) \
+ (((v) << 0) & BM_PXP_OUT_PS_LRC_Y)
+
+#define HW_PXP_OUT_AS_ULC (0x00000090)
+
+#define BP_PXP_OUT_AS_ULC_RSVD1 30
+#define BM_PXP_OUT_AS_ULC_RSVD1 0xC0000000
+#define BF_PXP_OUT_AS_ULC_RSVD1(v) \
+ (((v) << 30) & BM_PXP_OUT_AS_ULC_RSVD1)
+#define BP_PXP_OUT_AS_ULC_X 16
+#define BM_PXP_OUT_AS_ULC_X 0x3FFF0000
+#define BF_PXP_OUT_AS_ULC_X(v) \
+ (((v) << 16) & BM_PXP_OUT_AS_ULC_X)
+#define BP_PXP_OUT_AS_ULC_RSVD0 14
+#define BM_PXP_OUT_AS_ULC_RSVD0 0x0000C000
+#define BF_PXP_OUT_AS_ULC_RSVD0(v) \
+ (((v) << 14) & BM_PXP_OUT_AS_ULC_RSVD0)
+#define BP_PXP_OUT_AS_ULC_Y 0
+#define BM_PXP_OUT_AS_ULC_Y 0x00003FFF
+#define BF_PXP_OUT_AS_ULC_Y(v) \
+ (((v) << 0) & BM_PXP_OUT_AS_ULC_Y)
+
+#define HW_PXP_OUT_AS_LRC (0x000000a0)
+
+#define BP_PXP_OUT_AS_LRC_RSVD1 30
+#define BM_PXP_OUT_AS_LRC_RSVD1 0xC0000000
+#define BF_PXP_OUT_AS_LRC_RSVD1(v) \
+ (((v) << 30) & BM_PXP_OUT_AS_LRC_RSVD1)
+#define BP_PXP_OUT_AS_LRC_X 16
+#define BM_PXP_OUT_AS_LRC_X 0x3FFF0000
+#define BF_PXP_OUT_AS_LRC_X(v) \
+ (((v) << 16) & BM_PXP_OUT_AS_LRC_X)
+#define BP_PXP_OUT_AS_LRC_RSVD0 14
+#define BM_PXP_OUT_AS_LRC_RSVD0 0x0000C000
+#define BF_PXP_OUT_AS_LRC_RSVD0(v) \
+ (((v) << 14) & BM_PXP_OUT_AS_LRC_RSVD0)
+#define BP_PXP_OUT_AS_LRC_Y 0
+#define BM_PXP_OUT_AS_LRC_Y 0x00003FFF
+#define BF_PXP_OUT_AS_LRC_Y(v) \
+ (((v) << 0) & BM_PXP_OUT_AS_LRC_Y)
+
+#define HW_PXP_PS_CTRL (0x000000b0)
+#define HW_PXP_PS_CTRL_SET (0x000000b4)
+#define HW_PXP_PS_CTRL_CLR (0x000000b8)
+#define HW_PXP_PS_CTRL_TOG (0x000000bc)
+
+#define BP_PXP_PS_CTRL_RSVD1 12
+#define BM_PXP_PS_CTRL_RSVD1 0xFFFFF000
+#define BF_PXP_PS_CTRL_RSVD1(v) \
+ (((v) << 12) & BM_PXP_PS_CTRL_RSVD1)
+#define BP_PXP_PS_CTRL_DECX 10
+#define BM_PXP_PS_CTRL_DECX 0x00000C00
+#define BF_PXP_PS_CTRL_DECX(v) \
+ (((v) << 10) & BM_PXP_PS_CTRL_DECX)
+#define BV_PXP_PS_CTRL_DECX__DISABLE 0x0
+#define BV_PXP_PS_CTRL_DECX__DECX2 0x1
+#define BV_PXP_PS_CTRL_DECX__DECX4 0x2
+#define BV_PXP_PS_CTRL_DECX__DECX8 0x3
+#define BP_PXP_PS_CTRL_DECY 8
+#define BM_PXP_PS_CTRL_DECY 0x00000300
+#define BF_PXP_PS_CTRL_DECY(v) \
+ (((v) << 8) & BM_PXP_PS_CTRL_DECY)
+#define BV_PXP_PS_CTRL_DECY__DISABLE 0x0
+#define BV_PXP_PS_CTRL_DECY__DECY2 0x1
+#define BV_PXP_PS_CTRL_DECY__DECY4 0x2
+#define BV_PXP_PS_CTRL_DECY__DECY8 0x3
+#define BP_PXP_PS_CTRL_SWAP 5
+#define BM_PXP_PS_CTRL_SWAP 0x000000E0
+#define BF_PXP_PS_CTRL_SWAP(v) \
+ (((v) << 5) & BM_PXP_PS_CTRL_SWAP)
+#define BP_PXP_PS_CTRL_FORMAT 0
+#define BM_PXP_PS_CTRL_FORMAT 0x0000001F
+#define BF_PXP_PS_CTRL_FORMAT(v) \
+ (((v) << 0) & BM_PXP_PS_CTRL_FORMAT)
+#define BV_PXP_PS_CTRL_FORMAT__RGB888 0x4
+#define BV_PXP_PS_CTRL_FORMAT__RGB555 0xC
+#define BV_PXP_PS_CTRL_FORMAT__RGB444 0xD
+#define BV_PXP_PS_CTRL_FORMAT__RGB565 0xE
+#define BV_PXP_PS_CTRL_FORMAT__YUV1P444 0x10
+#define BV_PXP_PS_CTRL_FORMAT__UYVY1P422 0x12
+#define BV_PXP_PS_CTRL_FORMAT__VYUY1P422 0x13
+#define BV_PXP_PS_CTRL_FORMAT__Y8 0x14
+#define BV_PXP_PS_CTRL_FORMAT__Y4 0x15
+#define BV_PXP_PS_CTRL_FORMAT__YUV2P422 0x18
+#define BV_PXP_PS_CTRL_FORMAT__YUV2P420 0x19
+#define BV_PXP_PS_CTRL_FORMAT__YVU2P422 0x1A
+#define BV_PXP_PS_CTRL_FORMAT__YVU2P420 0x1B
+#define BV_PXP_PS_CTRL_FORMAT__YUV422 0x1E
+#define BV_PXP_PS_CTRL_FORMAT__YUV420 0x1F
+
+#define HW_PXP_PS_BUF (0x000000c0)
+
+#define BP_PXP_PS_BUF_ADDR 0
+#define BM_PXP_PS_BUF_ADDR 0xFFFFFFFF
+#define BF_PXP_PS_BUF_ADDR(v) (v)
+
+#define HW_PXP_PS_UBUF (0x000000d0)
+
+#define BP_PXP_PS_UBUF_ADDR 0
+#define BM_PXP_PS_UBUF_ADDR 0xFFFFFFFF
+#define BF_PXP_PS_UBUF_ADDR(v) (v)
+
+#define HW_PXP_PS_VBUF (0x000000e0)
+
+#define BP_PXP_PS_VBUF_ADDR 0
+#define BM_PXP_PS_VBUF_ADDR 0xFFFFFFFF
+#define BF_PXP_PS_VBUF_ADDR(v) (v)
+
+#define HW_PXP_PS_PITCH (0x000000f0)
+
+#define BP_PXP_PS_PITCH_RSVD 16
+#define BM_PXP_PS_PITCH_RSVD 0xFFFF0000
+#define BF_PXP_PS_PITCH_RSVD(v) \
+ (((v) << 16) & BM_PXP_PS_PITCH_RSVD)
+#define BP_PXP_PS_PITCH_PITCH 0
+#define BM_PXP_PS_PITCH_PITCH 0x0000FFFF
+#define BF_PXP_PS_PITCH_PITCH(v) \
+ (((v) << 0) & BM_PXP_PS_PITCH_PITCH)
+
+#define HW_PXP_PS_BACKGROUND (0x00000100)
+
+#define BP_PXP_PS_BACKGROUND_RSVD 24
+#define BM_PXP_PS_BACKGROUND_RSVD 0xFF000000
+#define BF_PXP_PS_BACKGROUND_RSVD(v) \
+ (((v) << 24) & BM_PXP_PS_BACKGROUND_RSVD)
+#define BP_PXP_PS_BACKGROUND_COLOR 0
+#define BM_PXP_PS_BACKGROUND_COLOR 0x00FFFFFF
+#define BF_PXP_PS_BACKGROUND_COLOR(v) \
+ (((v) << 0) & BM_PXP_PS_BACKGROUND_COLOR)
+
+#define HW_PXP_PS_SCALE (0x00000110)
+
+#define BM_PXP_PS_SCALE_RSVD2 0x80000000
+#define BP_PXP_PS_SCALE_YSCALE 16
+#define BM_PXP_PS_SCALE_YSCALE 0x7FFF0000
+#define BF_PXP_PS_SCALE_YSCALE(v) \
+ (((v) << 16) & BM_PXP_PS_SCALE_YSCALE)
+#define BM_PXP_PS_SCALE_RSVD1 0x00008000
+#define BP_PXP_PS_SCALE_XSCALE 0
+#define BM_PXP_PS_SCALE_XSCALE 0x00007FFF
+#define BF_PXP_PS_SCALE_XSCALE(v) \
+ (((v) << 0) & BM_PXP_PS_SCALE_XSCALE)
+
+#define HW_PXP_PS_OFFSET (0x00000120)
+
+#define BP_PXP_PS_OFFSET_RSVD2 28
+#define BM_PXP_PS_OFFSET_RSVD2 0xF0000000
+#define BF_PXP_PS_OFFSET_RSVD2(v) \
+ (((v) << 28) & BM_PXP_PS_OFFSET_RSVD2)
+#define BP_PXP_PS_OFFSET_YOFFSET 16
+#define BM_PXP_PS_OFFSET_YOFFSET 0x0FFF0000
+#define BF_PXP_PS_OFFSET_YOFFSET(v) \
+ (((v) << 16) & BM_PXP_PS_OFFSET_YOFFSET)
+#define BP_PXP_PS_OFFSET_RSVD1 12
+#define BM_PXP_PS_OFFSET_RSVD1 0x0000F000
+#define BF_PXP_PS_OFFSET_RSVD1(v) \
+ (((v) << 12) & BM_PXP_PS_OFFSET_RSVD1)
+#define BP_PXP_PS_OFFSET_XOFFSET 0
+#define BM_PXP_PS_OFFSET_XOFFSET 0x00000FFF
+#define BF_PXP_PS_OFFSET_XOFFSET(v) \
+ (((v) << 0) & BM_PXP_PS_OFFSET_XOFFSET)
+
+#define HW_PXP_PS_CLRKEYLOW (0x00000130)
+
+#define BP_PXP_PS_CLRKEYLOW_RSVD1 24
+#define BM_PXP_PS_CLRKEYLOW_RSVD1 0xFF000000
+#define BF_PXP_PS_CLRKEYLOW_RSVD1(v) \
+ (((v) << 24) & BM_PXP_PS_CLRKEYLOW_RSVD1)
+#define BP_PXP_PS_CLRKEYLOW_PIXEL 0
+#define BM_PXP_PS_CLRKEYLOW_PIXEL 0x00FFFFFF
+#define BF_PXP_PS_CLRKEYLOW_PIXEL(v) \
+ (((v) << 0) & BM_PXP_PS_CLRKEYLOW_PIXEL)
+
+#define HW_PXP_PS_CLRKEYHIGH (0x00000140)
+
+#define BP_PXP_PS_CLRKEYHIGH_RSVD1 24
+#define BM_PXP_PS_CLRKEYHIGH_RSVD1 0xFF000000
+#define BF_PXP_PS_CLRKEYHIGH_RSVD1(v) \
+ (((v) << 24) & BM_PXP_PS_CLRKEYHIGH_RSVD1)
+#define BP_PXP_PS_CLRKEYHIGH_PIXEL 0
+#define BM_PXP_PS_CLRKEYHIGH_PIXEL 0x00FFFFFF
+#define BF_PXP_PS_CLRKEYHIGH_PIXEL(v) \
+ (((v) << 0) & BM_PXP_PS_CLRKEYHIGH_PIXEL)
+
+#define HW_PXP_AS_CTRL (0x00000150)
+
+#define BP_PXP_AS_CTRL_RSVD1 21
+#define BM_PXP_AS_CTRL_RSVD1 0xFFE00000
+#define BF_PXP_AS_CTRL_RSVD1(v) \
+ (((v) << 21) & BM_PXP_AS_CTRL_RSVD1)
+#define BM_PXP_AS_CTRL_ALPHA_INVERT 0x00100000
+#define BP_PXP_AS_CTRL_ROP 16
+#define BM_PXP_AS_CTRL_ROP 0x000F0000
+#define BF_PXP_AS_CTRL_ROP(v) \
+ (((v) << 16) & BM_PXP_AS_CTRL_ROP)
+#define BV_PXP_AS_CTRL_ROP__MASKAS 0x0
+#define BV_PXP_AS_CTRL_ROP__MASKNOTAS 0x1
+#define BV_PXP_AS_CTRL_ROP__MASKASNOT 0x2
+#define BV_PXP_AS_CTRL_ROP__MERGEAS 0x3
+#define BV_PXP_AS_CTRL_ROP__MERGENOTAS 0x4
+#define BV_PXP_AS_CTRL_ROP__MERGEASNOT 0x5
+#define BV_PXP_AS_CTRL_ROP__NOTCOPYAS 0x6
+#define BV_PXP_AS_CTRL_ROP__NOT 0x7
+#define BV_PXP_AS_CTRL_ROP__NOTMASKAS 0x8
+#define BV_PXP_AS_CTRL_ROP__NOTMERGEAS 0x9
+#define BV_PXP_AS_CTRL_ROP__XORAS 0xA
+#define BV_PXP_AS_CTRL_ROP__NOTXORAS 0xB
+#define BP_PXP_AS_CTRL_ALPHA 8
+#define BM_PXP_AS_CTRL_ALPHA 0x0000FF00
+#define BF_PXP_AS_CTRL_ALPHA(v) \
+ (((v) << 8) & BM_PXP_AS_CTRL_ALPHA)
+#define BP_PXP_AS_CTRL_FORMAT 4
+#define BM_PXP_AS_CTRL_FORMAT 0x000000F0
+#define BF_PXP_AS_CTRL_FORMAT(v) \
+ (((v) << 4) & BM_PXP_AS_CTRL_FORMAT)
+#define BV_PXP_AS_CTRL_FORMAT__ARGB8888 0x0
+#define BV_PXP_AS_CTRL_FORMAT__RGB888 0x4
+#define BV_PXP_AS_CTRL_FORMAT__ARGB1555 0x8
+#define BV_PXP_AS_CTRL_FORMAT__ARGB4444 0x9
+#define BV_PXP_AS_CTRL_FORMAT__RGB555 0xC
+#define BV_PXP_AS_CTRL_FORMAT__RGB444 0xD
+#define BV_PXP_AS_CTRL_FORMAT__RGB565 0xE
+#define BM_PXP_AS_CTRL_ENABLE_COLORKEY 0x00000008
+#define BP_PXP_AS_CTRL_ALPHA_CTRL 1
+#define BM_PXP_AS_CTRL_ALPHA_CTRL 0x00000006
+#define BF_PXP_AS_CTRL_ALPHA_CTRL(v) \
+ (((v) << 1) & BM_PXP_AS_CTRL_ALPHA_CTRL)
+#define BV_PXP_AS_CTRL_ALPHA_CTRL__Embedded 0x0
+#define BV_PXP_AS_CTRL_ALPHA_CTRL__Override 0x1
+#define BV_PXP_AS_CTRL_ALPHA_CTRL__Multiply 0x2
+#define BV_PXP_AS_CTRL_ALPHA_CTRL__ROPs 0x3
+#define BM_PXP_AS_CTRL_RSVD0 0x00000001
+
+#define HW_PXP_AS_BUF (0x00000160)
+
+#define BP_PXP_AS_BUF_ADDR 0
+#define BM_PXP_AS_BUF_ADDR 0xFFFFFFFF
+#define BF_PXP_AS_BUF_ADDR(v) (v)
+
+#define HW_PXP_AS_PITCH (0x00000170)
+
+#define BP_PXP_AS_PITCH_RSVD 16
+#define BM_PXP_AS_PITCH_RSVD 0xFFFF0000
+#define BF_PXP_AS_PITCH_RSVD(v) \
+ (((v) << 16) & BM_PXP_AS_PITCH_RSVD)
+#define BP_PXP_AS_PITCH_PITCH 0
+#define BM_PXP_AS_PITCH_PITCH 0x0000FFFF
+#define BF_PXP_AS_PITCH_PITCH(v) \
+ (((v) << 0) & BM_PXP_AS_PITCH_PITCH)
+
+#define HW_PXP_AS_CLRKEYLOW (0x00000180)
+
+#define BP_PXP_AS_CLRKEYLOW_RSVD1 24
+#define BM_PXP_AS_CLRKEYLOW_RSVD1 0xFF000000
+#define BF_PXP_AS_CLRKEYLOW_RSVD1(v) \
+ (((v) << 24) & BM_PXP_AS_CLRKEYLOW_RSVD1)
+#define BP_PXP_AS_CLRKEYLOW_PIXEL 0
+#define BM_PXP_AS_CLRKEYLOW_PIXEL 0x00FFFFFF
+#define BF_PXP_AS_CLRKEYLOW_PIXEL(v) \
+ (((v) << 0) & BM_PXP_AS_CLRKEYLOW_PIXEL)
+
+#define HW_PXP_AS_CLRKEYHIGH (0x00000190)
+
+#define BP_PXP_AS_CLRKEYHIGH_RSVD1 24
+#define BM_PXP_AS_CLRKEYHIGH_RSVD1 0xFF000000
+#define BF_PXP_AS_CLRKEYHIGH_RSVD1(v) \
+ (((v) << 24) & BM_PXP_AS_CLRKEYHIGH_RSVD1)
+#define BP_PXP_AS_CLRKEYHIGH_PIXEL 0
+#define BM_PXP_AS_CLRKEYHIGH_PIXEL 0x00FFFFFF
+#define BF_PXP_AS_CLRKEYHIGH_PIXEL(v) \
+ (((v) << 0) & BM_PXP_AS_CLRKEYHIGH_PIXEL)
+
+#define HW_PXP_CSC1_COEF0 (0x000001a0)
+
+#define BM_PXP_CSC1_COEF0_YCBCR_MODE 0x80000000
+#define BM_PXP_CSC1_COEF0_BYPASS 0x40000000
+#define BM_PXP_CSC1_COEF0_RSVD1 0x20000000
+#define BP_PXP_CSC1_COEF0_C0 18
+#define BM_PXP_CSC1_COEF0_C0 0x1FFC0000
+#define BF_PXP_CSC1_COEF0_C0(v) \
+ (((v) << 18) & BM_PXP_CSC1_COEF0_C0)
+#define BP_PXP_CSC1_COEF0_UV_OFFSET 9
+#define BM_PXP_CSC1_COEF0_UV_OFFSET 0x0003FE00
+#define BF_PXP_CSC1_COEF0_UV_OFFSET(v) \
+ (((v) << 9) & BM_PXP_CSC1_COEF0_UV_OFFSET)
+#define BP_PXP_CSC1_COEF0_Y_OFFSET 0
+#define BM_PXP_CSC1_COEF0_Y_OFFSET 0x000001FF
+#define BF_PXP_CSC1_COEF0_Y_OFFSET(v) \
+ (((v) << 0) & BM_PXP_CSC1_COEF0_Y_OFFSET)
+
+#define HW_PXP_CSC1_COEF1 (0x000001b0)
+
+#define BP_PXP_CSC1_COEF1_RSVD1 27
+#define BM_PXP_CSC1_COEF1_RSVD1 0xF8000000
+#define BF_PXP_CSC1_COEF1_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC1_COEF1_RSVD1)
+#define BP_PXP_CSC1_COEF1_C1 16
+#define BM_PXP_CSC1_COEF1_C1 0x07FF0000
+#define BF_PXP_CSC1_COEF1_C1(v) \
+ (((v) << 16) & BM_PXP_CSC1_COEF1_C1)
+#define BP_PXP_CSC1_COEF1_RSVD0 11
+#define BM_PXP_CSC1_COEF1_RSVD0 0x0000F800
+#define BF_PXP_CSC1_COEF1_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC1_COEF1_RSVD0)
+#define BP_PXP_CSC1_COEF1_C4 0
+#define BM_PXP_CSC1_COEF1_C4 0x000007FF
+#define BF_PXP_CSC1_COEF1_C4(v) \
+ (((v) << 0) & BM_PXP_CSC1_COEF1_C4)
+
+#define HW_PXP_CSC1_COEF2 (0x000001c0)
+
+#define BP_PXP_CSC1_COEF2_RSVD1 27
+#define BM_PXP_CSC1_COEF2_RSVD1 0xF8000000
+#define BF_PXP_CSC1_COEF2_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC1_COEF2_RSVD1)
+#define BP_PXP_CSC1_COEF2_C2 16
+#define BM_PXP_CSC1_COEF2_C2 0x07FF0000
+#define BF_PXP_CSC1_COEF2_C2(v) \
+ (((v) << 16) & BM_PXP_CSC1_COEF2_C2)
+#define BP_PXP_CSC1_COEF2_RSVD0 11
+#define BM_PXP_CSC1_COEF2_RSVD0 0x0000F800
+#define BF_PXP_CSC1_COEF2_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC1_COEF2_RSVD0)
+#define BP_PXP_CSC1_COEF2_C3 0
+#define BM_PXP_CSC1_COEF2_C3 0x000007FF
+#define BF_PXP_CSC1_COEF2_C3(v) \
+ (((v) << 0) & BM_PXP_CSC1_COEF2_C3)
+
+#define HW_PXP_CSC2_CTRL (0x000001d0)
+
+#define BP_PXP_CSC2_CTRL_RSVD 3
+#define BM_PXP_CSC2_CTRL_RSVD 0xFFFFFFF8
+#define BF_PXP_CSC2_CTRL_RSVD(v) \
+ (((v) << 3) & BM_PXP_CSC2_CTRL_RSVD)
+#define BP_PXP_CSC2_CTRL_CSC_MODE 1
+#define BM_PXP_CSC2_CTRL_CSC_MODE 0x00000006
+#define BF_PXP_CSC2_CTRL_CSC_MODE(v) \
+ (((v) << 1) & BM_PXP_CSC2_CTRL_CSC_MODE)
+#define BV_PXP_CSC2_CTRL_CSC_MODE__YUV2RGB 0x0
+#define BV_PXP_CSC2_CTRL_CSC_MODE__YCbCr2RGB 0x1
+#define BV_PXP_CSC2_CTRL_CSC_MODE__RGB2YUV 0x2
+#define BV_PXP_CSC2_CTRL_CSC_MODE__RGB2YCbCr 0x3
+#define BM_PXP_CSC2_CTRL_BYPASS 0x00000001
+
+#define HW_PXP_CSC2_COEF0 (0x000001e0)
+
+#define BP_PXP_CSC2_COEF0_RSVD1 27
+#define BM_PXP_CSC2_COEF0_RSVD1 0xF8000000
+#define BF_PXP_CSC2_COEF0_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC2_COEF0_RSVD1)
+#define BP_PXP_CSC2_COEF0_A2 16
+#define BM_PXP_CSC2_COEF0_A2 0x07FF0000
+#define BF_PXP_CSC2_COEF0_A2(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF0_A2)
+#define BP_PXP_CSC2_COEF0_RSVD0 11
+#define BM_PXP_CSC2_COEF0_RSVD0 0x0000F800
+#define BF_PXP_CSC2_COEF0_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC2_COEF0_RSVD0)
+#define BP_PXP_CSC2_COEF0_A1 0
+#define BM_PXP_CSC2_COEF0_A1 0x000007FF
+#define BF_PXP_CSC2_COEF0_A1(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF0_A1)
+
+#define HW_PXP_CSC2_COEF1 (0x000001f0)
+
+#define BP_PXP_CSC2_COEF1_RSVD1 27
+#define BM_PXP_CSC2_COEF1_RSVD1 0xF8000000
+#define BF_PXP_CSC2_COEF1_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC2_COEF1_RSVD1)
+#define BP_PXP_CSC2_COEF1_B1 16
+#define BM_PXP_CSC2_COEF1_B1 0x07FF0000
+#define BF_PXP_CSC2_COEF1_B1(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF1_B1)
+#define BP_PXP_CSC2_COEF1_RSVD0 11
+#define BM_PXP_CSC2_COEF1_RSVD0 0x0000F800
+#define BF_PXP_CSC2_COEF1_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC2_COEF1_RSVD0)
+#define BP_PXP_CSC2_COEF1_A3 0
+#define BM_PXP_CSC2_COEF1_A3 0x000007FF
+#define BF_PXP_CSC2_COEF1_A3(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF1_A3)
+
+#define HW_PXP_CSC2_COEF2 (0x00000200)
+
+#define BP_PXP_CSC2_COEF2_RSVD1 27
+#define BM_PXP_CSC2_COEF2_RSVD1 0xF8000000
+#define BF_PXP_CSC2_COEF2_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC2_COEF2_RSVD1)
+#define BP_PXP_CSC2_COEF2_B3 16
+#define BM_PXP_CSC2_COEF2_B3 0x07FF0000
+#define BF_PXP_CSC2_COEF2_B3(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF2_B3)
+#define BP_PXP_CSC2_COEF2_RSVD0 11
+#define BM_PXP_CSC2_COEF2_RSVD0 0x0000F800
+#define BF_PXP_CSC2_COEF2_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC2_COEF2_RSVD0)
+#define BP_PXP_CSC2_COEF2_B2 0
+#define BM_PXP_CSC2_COEF2_B2 0x000007FF
+#define BF_PXP_CSC2_COEF2_B2(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF2_B2)
+
+#define HW_PXP_CSC2_COEF3 (0x00000210)
+
+#define BP_PXP_CSC2_COEF3_RSVD1 27
+#define BM_PXP_CSC2_COEF3_RSVD1 0xF8000000
+#define BF_PXP_CSC2_COEF3_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC2_COEF3_RSVD1)
+#define BP_PXP_CSC2_COEF3_C2 16
+#define BM_PXP_CSC2_COEF3_C2 0x07FF0000
+#define BF_PXP_CSC2_COEF3_C2(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF3_C2)
+#define BP_PXP_CSC2_COEF3_RSVD0 11
+#define BM_PXP_CSC2_COEF3_RSVD0 0x0000F800
+#define BF_PXP_CSC2_COEF3_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC2_COEF3_RSVD0)
+#define BP_PXP_CSC2_COEF3_C1 0
+#define BM_PXP_CSC2_COEF3_C1 0x000007FF
+#define BF_PXP_CSC2_COEF3_C1(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF3_C1)
+
+#define HW_PXP_CSC2_COEF4 (0x00000220)
+
+#define BP_PXP_CSC2_COEF4_RSVD1 25
+#define BM_PXP_CSC2_COEF4_RSVD1 0xFE000000
+#define BF_PXP_CSC2_COEF4_RSVD1(v) \
+ (((v) << 25) & BM_PXP_CSC2_COEF4_RSVD1)
+#define BP_PXP_CSC2_COEF4_D1 16
+#define BM_PXP_CSC2_COEF4_D1 0x01FF0000
+#define BF_PXP_CSC2_COEF4_D1(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF4_D1)
+#define BP_PXP_CSC2_COEF4_RSVD0 11
+#define BM_PXP_CSC2_COEF4_RSVD0 0x0000F800
+#define BF_PXP_CSC2_COEF4_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC2_COEF4_RSVD0)
+#define BP_PXP_CSC2_COEF4_C3 0
+#define BM_PXP_CSC2_COEF4_C3 0x000007FF
+#define BF_PXP_CSC2_COEF4_C3(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF4_C3)
+
+#define HW_PXP_CSC2_COEF5 (0x00000230)
+
+#define BP_PXP_CSC2_COEF5_RSVD1 25
+#define BM_PXP_CSC2_COEF5_RSVD1 0xFE000000
+#define BF_PXP_CSC2_COEF5_RSVD1(v) \
+ (((v) << 25) & BM_PXP_CSC2_COEF5_RSVD1)
+#define BP_PXP_CSC2_COEF5_D3 16
+#define BM_PXP_CSC2_COEF5_D3 0x01FF0000
+#define BF_PXP_CSC2_COEF5_D3(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF5_D3)
+#define BP_PXP_CSC2_COEF5_RSVD0 9
+#define BM_PXP_CSC2_COEF5_RSVD0 0x0000FE00
+#define BF_PXP_CSC2_COEF5_RSVD0(v) \
+ (((v) << 9) & BM_PXP_CSC2_COEF5_RSVD0)
+#define BP_PXP_CSC2_COEF5_D2 0
+#define BM_PXP_CSC2_COEF5_D2 0x000001FF
+#define BF_PXP_CSC2_COEF5_D2(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF5_D2)
+
+#define HW_PXP_LUT_CTRL (0x00000240)
+
+#define BM_PXP_LUT_CTRL_BYPASS 0x80000000
+#define BP_PXP_LUT_CTRL_RSVD3 26
+#define BM_PXP_LUT_CTRL_RSVD3 0x7C000000
+#define BF_PXP_LUT_CTRL_RSVD3(v) \
+ (((v) << 26) & BM_PXP_LUT_CTRL_RSVD3)
+#define BP_PXP_LUT_CTRL_LOOKUP_MODE 24
+#define BM_PXP_LUT_CTRL_LOOKUP_MODE 0x03000000
+#define BF_PXP_LUT_CTRL_LOOKUP_MODE(v) \
+ (((v) << 24) & BM_PXP_LUT_CTRL_LOOKUP_MODE)
+#define BV_PXP_LUT_CTRL_LOOKUP_MODE__CACHE_RGB565 0x0
+#define BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8 0x1
+#define BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_RGB444 0x2
+#define BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_RGB454 0x3
+#define BP_PXP_LUT_CTRL_RSVD2 18
+#define BM_PXP_LUT_CTRL_RSVD2 0x00FC0000
+#define BF_PXP_LUT_CTRL_RSVD2(v) \
+ (((v) << 18) & BM_PXP_LUT_CTRL_RSVD2)
+#define BP_PXP_LUT_CTRL_OUT_MODE 16
+#define BM_PXP_LUT_CTRL_OUT_MODE 0x00030000
+#define BF_PXP_LUT_CTRL_OUT_MODE(v) \
+ (((v) << 16) & BM_PXP_LUT_CTRL_OUT_MODE)
+#define BV_PXP_LUT_CTRL_OUT_MODE__RESERVED 0x0
+#define BV_PXP_LUT_CTRL_OUT_MODE__Y8 0x1
+#define BV_PXP_LUT_CTRL_OUT_MODE__RGBW4444CFA 0x2
+#define BV_PXP_LUT_CTRL_OUT_MODE__RGB888 0x3
+#define BP_PXP_LUT_CTRL_RSVD1 11
+#define BM_PXP_LUT_CTRL_RSVD1 0x0000F800
+#define BF_PXP_LUT_CTRL_RSVD1(v) \
+ (((v) << 11) & BM_PXP_LUT_CTRL_RSVD1)
+#define BM_PXP_LUT_CTRL_SEL_8KB 0x00000400
+#define BM_PXP_LUT_CTRL_LRU_UPD 0x00000200
+#define BM_PXP_LUT_CTRL_INVALID 0x00000100
+#define BP_PXP_LUT_CTRL_RSVD0 1
+#define BM_PXP_LUT_CTRL_RSVD0 0x000000FE
+#define BF_PXP_LUT_CTRL_RSVD0(v) \
+ (((v) << 1) & BM_PXP_LUT_CTRL_RSVD0)
+#define BM_PXP_LUT_CTRL_DMA_START 0x00000001
+
+#define HW_PXP_LUT_ADDR (0x00000250)
+
+#define BM_PXP_LUT_ADDR_RSVD2 0x80000000
+#define BP_PXP_LUT_ADDR_NUM_BYTES 16
+#define BM_PXP_LUT_ADDR_NUM_BYTES 0x7FFF0000
+#define BF_PXP_LUT_ADDR_NUM_BYTES(v) \
+ (((v) << 16) & BM_PXP_LUT_ADDR_NUM_BYTES)
+#define BP_PXP_LUT_ADDR_RSVD1 14
+#define BM_PXP_LUT_ADDR_RSVD1 0x0000C000
+#define BF_PXP_LUT_ADDR_RSVD1(v) \
+ (((v) << 14) & BM_PXP_LUT_ADDR_RSVD1)
+#define BP_PXP_LUT_ADDR_ADDR 0
+#define BM_PXP_LUT_ADDR_ADDR 0x00003FFF
+#define BF_PXP_LUT_ADDR_ADDR(v) \
+ (((v) << 0) & BM_PXP_LUT_ADDR_ADDR)
+
+#define HW_PXP_LUT_DATA (0x00000260)
+
+#define BP_PXP_LUT_DATA_DATA 0
+#define BM_PXP_LUT_DATA_DATA 0xFFFFFFFF
+#define BF_PXP_LUT_DATA_DATA(v) (v)
+
+#define HW_PXP_LUT_EXTMEM (0x00000270)
+
+#define BP_PXP_LUT_EXTMEM_ADDR 0
+#define BM_PXP_LUT_EXTMEM_ADDR 0xFFFFFFFF
+#define BF_PXP_LUT_EXTMEM_ADDR(v) (v)
+
+#define HW_PXP_CFA (0x00000280)
+
+#define BP_PXP_CFA_DATA 0
+#define BM_PXP_CFA_DATA 0xFFFFFFFF
+#define BF_PXP_CFA_DATA(v) (v)
+
+#define HW_PXP_HIST_CTRL (0x00000290)
+
+#define BP_PXP_HIST_CTRL_RSVD 6
+#define BM_PXP_HIST_CTRL_RSVD 0xFFFFFFC0
+#define BF_PXP_HIST_CTRL_RSVD(v) \
+ (((v) << 6) & BM_PXP_HIST_CTRL_RSVD)
+#define BP_PXP_HIST_CTRL_PANEL_MODE 4
+#define BM_PXP_HIST_CTRL_PANEL_MODE 0x00000030
+#define BF_PXP_HIST_CTRL_PANEL_MODE(v) \
+ (((v) << 4) & BM_PXP_HIST_CTRL_PANEL_MODE)
+#define BV_PXP_HIST_CTRL_PANEL_MODE__GRAY4 0x0
+#define BV_PXP_HIST_CTRL_PANEL_MODE__GRAY8 0x1
+#define BV_PXP_HIST_CTRL_PANEL_MODE__GRAY16 0x2
+#define BV_PXP_HIST_CTRL_PANEL_MODE__GRAY32 0x3
+#define BP_PXP_HIST_CTRL_STATUS 0
+#define BM_PXP_HIST_CTRL_STATUS 0x0000000F
+#define BF_PXP_HIST_CTRL_STATUS(v) \
+ (((v) << 0) & BM_PXP_HIST_CTRL_STATUS)
+
+#define HW_PXP_HIST2_PARAM (0x000002a0)
+
+#define BP_PXP_HIST2_PARAM_RSVD 16
+#define BM_PXP_HIST2_PARAM_RSVD 0xFFFF0000
+#define BF_PXP_HIST2_PARAM_RSVD(v) \
+ (((v) << 16) & BM_PXP_HIST2_PARAM_RSVD)
+#define BP_PXP_HIST2_PARAM_RSVD1 13
+#define BM_PXP_HIST2_PARAM_RSVD1 0x0000E000
+#define BF_PXP_HIST2_PARAM_RSVD1(v) \
+ (((v) << 13) & BM_PXP_HIST2_PARAM_RSVD1)
+#define BP_PXP_HIST2_PARAM_VALUE1 8
+#define BM_PXP_HIST2_PARAM_VALUE1 0x00001F00
+#define BF_PXP_HIST2_PARAM_VALUE1(v) \
+ (((v) << 8) & BM_PXP_HIST2_PARAM_VALUE1)
+#define BP_PXP_HIST2_PARAM_RSVD0 5
+#define BM_PXP_HIST2_PARAM_RSVD0 0x000000E0
+#define BF_PXP_HIST2_PARAM_RSVD0(v) \
+ (((v) << 5) & BM_PXP_HIST2_PARAM_RSVD0)
+#define BP_PXP_HIST2_PARAM_VALUE0 0
+#define BM_PXP_HIST2_PARAM_VALUE0 0x0000001F
+#define BF_PXP_HIST2_PARAM_VALUE0(v) \
+ (((v) << 0) & BM_PXP_HIST2_PARAM_VALUE0)
+
+#define HW_PXP_HIST4_PARAM (0x000002b0)
+
+#define BP_PXP_HIST4_PARAM_RSVD3 29
+#define BM_PXP_HIST4_PARAM_RSVD3 0xE0000000
+#define BF_PXP_HIST4_PARAM_RSVD3(v) \
+ (((v) << 29) & BM_PXP_HIST4_PARAM_RSVD3)
+#define BP_PXP_HIST4_PARAM_VALUE3 24
+#define BM_PXP_HIST4_PARAM_VALUE3 0x1F000000
+#define BF_PXP_HIST4_PARAM_VALUE3(v) \
+ (((v) << 24) & BM_PXP_HIST4_PARAM_VALUE3)
+#define BP_PXP_HIST4_PARAM_RSVD2 21
+#define BM_PXP_HIST4_PARAM_RSVD2 0x00E00000
+#define BF_PXP_HIST4_PARAM_RSVD2(v) \
+ (((v) << 21) & BM_PXP_HIST4_PARAM_RSVD2)
+#define BP_PXP_HIST4_PARAM_VALUE2 16
+#define BM_PXP_HIST4_PARAM_VALUE2 0x001F0000
+#define BF_PXP_HIST4_PARAM_VALUE2(v) \
+ (((v) << 16) & BM_PXP_HIST4_PARAM_VALUE2)
+#define BP_PXP_HIST4_PARAM_RSVD1 13
+#define BM_PXP_HIST4_PARAM_RSVD1 0x0000E000
+#define BF_PXP_HIST4_PARAM_RSVD1(v) \
+ (((v) << 13) & BM_PXP_HIST4_PARAM_RSVD1)
+#define BP_PXP_HIST4_PARAM_VALUE1 8
+#define BM_PXP_HIST4_PARAM_VALUE1 0x00001F00
+#define BF_PXP_HIST4_PARAM_VALUE1(v) \
+ (((v) << 8) & BM_PXP_HIST4_PARAM_VALUE1)
+#define BP_PXP_HIST4_PARAM_RSVD0 5
+#define BM_PXP_HIST4_PARAM_RSVD0 0x000000E0
+#define BF_PXP_HIST4_PARAM_RSVD0(v) \
+ (((v) << 5) & BM_PXP_HIST4_PARAM_RSVD0)
+#define BP_PXP_HIST4_PARAM_VALUE0 0
+#define BM_PXP_HIST4_PARAM_VALUE0 0x0000001F
+#define BF_PXP_HIST4_PARAM_VALUE0(v) \
+ (((v) << 0) & BM_PXP_HIST4_PARAM_VALUE0)
+
+#define HW_PXP_HIST8_PARAM0 (0x000002c0)
+
+#define BP_PXP_HIST8_PARAM0_RSVD3 29
+#define BM_PXP_HIST8_PARAM0_RSVD3 0xE0000000
+#define BF_PXP_HIST8_PARAM0_RSVD3(v) \
+ (((v) << 29) & BM_PXP_HIST8_PARAM0_RSVD3)
+#define BP_PXP_HIST8_PARAM0_VALUE3 24
+#define BM_PXP_HIST8_PARAM0_VALUE3 0x1F000000
+#define BF_PXP_HIST8_PARAM0_VALUE3(v) \
+ (((v) << 24) & BM_PXP_HIST8_PARAM0_VALUE3)
+#define BP_PXP_HIST8_PARAM0_RSVD2 21
+#define BM_PXP_HIST8_PARAM0_RSVD2 0x00E00000
+#define BF_PXP_HIST8_PARAM0_RSVD2(v) \
+ (((v) << 21) & BM_PXP_HIST8_PARAM0_RSVD2)
+#define BP_PXP_HIST8_PARAM0_VALUE2 16
+#define BM_PXP_HIST8_PARAM0_VALUE2 0x001F0000
+#define BF_PXP_HIST8_PARAM0_VALUE2(v) \
+ (((v) << 16) & BM_PXP_HIST8_PARAM0_VALUE2)
+#define BP_PXP_HIST8_PARAM0_RSVD1 13
+#define BM_PXP_HIST8_PARAM0_RSVD1 0x0000E000
+#define BF_PXP_HIST8_PARAM0_RSVD1(v) \
+ (((v) << 13) & BM_PXP_HIST8_PARAM0_RSVD1)
+#define BP_PXP_HIST8_PARAM0_VALUE1 8
+#define BM_PXP_HIST8_PARAM0_VALUE1 0x00001F00
+#define BF_PXP_HIST8_PARAM0_VALUE1(v) \
+ (((v) << 8) & BM_PXP_HIST8_PARAM0_VALUE1)
+#define BP_PXP_HIST8_PARAM0_RSVD0 5
+#define BM_PXP_HIST8_PARAM0_RSVD0 0x000000E0
+#define BF_PXP_HIST8_PARAM0_RSVD0(v) \
+ (((v) << 5) & BM_PXP_HIST8_PARAM0_RSVD0)
+#define BP_PXP_HIST8_PARAM0_VALUE0 0
+#define BM_PXP_HIST8_PARAM0_VALUE0 0x0000001F
+#define BF_PXP_HIST8_PARAM0_VALUE0(v) \
+ (((v) << 0) & BM_PXP_HIST8_PARAM0_VALUE0)
+
+#define HW_PXP_HIST8_PARAM1 (0x000002d0)
+
+#define BP_PXP_HIST8_PARAM1_RSVD7 29
+#define BM_PXP_HIST8_PARAM1_RSVD7 0xE0000000
+#define BF_PXP_HIST8_PARAM1_RSVD7(v) \
+ (((v) << 29) & BM_PXP_HIST8_PARAM1_RSVD7)
+#define BP_PXP_HIST8_PARAM1_VALUE7 24
+#define BM_PXP_HIST8_PARAM1_VALUE7 0x1F000000
+#define BF_PXP_HIST8_PARAM1_VALUE7(v) \
+ (((v) << 24) & BM_PXP_HIST8_PARAM1_VALUE7)
+#define BP_PXP_HIST8_PARAM1_RSVD6 21
+#define BM_PXP_HIST8_PARAM1_RSVD6 0x00E00000
+#define BF_PXP_HIST8_PARAM1_RSVD6(v) \
+ (((v) << 21) & BM_PXP_HIST8_PARAM1_RSVD6)
+#define BP_PXP_HIST8_PARAM1_VALUE6 16
+#define BM_PXP_HIST8_PARAM1_VALUE6 0x001F0000
+#define BF_PXP_HIST8_PARAM1_VALUE6(v) \
+ (((v) << 16) & BM_PXP_HIST8_PARAM1_VALUE6)
+#define BP_PXP_HIST8_PARAM1_RSVD5 13
+#define BM_PXP_HIST8_PARAM1_RSVD5 0x0000E000
+#define BF_PXP_HIST8_PARAM1_RSVD5(v) \
+ (((v) << 13) & BM_PXP_HIST8_PARAM1_RSVD5)
+#define BP_PXP_HIST8_PARAM1_VALUE5 8
+#define BM_PXP_HIST8_PARAM1_VALUE5 0x00001F00
+#define BF_PXP_HIST8_PARAM1_VALUE5(v) \
+ (((v) << 8) & BM_PXP_HIST8_PARAM1_VALUE5)
+#define BP_PXP_HIST8_PARAM1_RSVD4 5
+#define BM_PXP_HIST8_PARAM1_RSVD4 0x000000E0
+#define BF_PXP_HIST8_PARAM1_RSVD4(v) \
+ (((v) << 5) & BM_PXP_HIST8_PARAM1_RSVD4)
+#define BP_PXP_HIST8_PARAM1_VALUE4 0
+#define BM_PXP_HIST8_PARAM1_VALUE4 0x0000001F
+#define BF_PXP_HIST8_PARAM1_VALUE4(v) \
+ (((v) << 0) & BM_PXP_HIST8_PARAM1_VALUE4)
+
+#define HW_PXP_HIST16_PARAM0 (0x000002e0)
+
+#define BP_PXP_HIST16_PARAM0_RSVD3 29
+#define BM_PXP_HIST16_PARAM0_RSVD3 0xE0000000
+#define BF_PXP_HIST16_PARAM0_RSVD3(v) \
+ (((v) << 29) & BM_PXP_HIST16_PARAM0_RSVD3)
+#define BP_PXP_HIST16_PARAM0_VALUE3 24
+#define BM_PXP_HIST16_PARAM0_VALUE3 0x1F000000
+#define BF_PXP_HIST16_PARAM0_VALUE3(v) \
+ (((v) << 24) & BM_PXP_HIST16_PARAM0_VALUE3)
+#define BP_PXP_HIST16_PARAM0_RSVD2 21
+#define BM_PXP_HIST16_PARAM0_RSVD2 0x00E00000
+#define BF_PXP_HIST16_PARAM0_RSVD2(v) \
+ (((v) << 21) & BM_PXP_HIST16_PARAM0_RSVD2)
+#define BP_PXP_HIST16_PARAM0_VALUE2 16
+#define BM_PXP_HIST16_PARAM0_VALUE2 0x001F0000
+#define BF_PXP_HIST16_PARAM0_VALUE2(v) \
+ (((v) << 16) & BM_PXP_HIST16_PARAM0_VALUE2)
+#define BP_PXP_HIST16_PARAM0_RSVD1 13
+#define BM_PXP_HIST16_PARAM0_RSVD1 0x0000E000
+#define BF_PXP_HIST16_PARAM0_RSVD1(v) \
+ (((v) << 13) & BM_PXP_HIST16_PARAM0_RSVD1)
+#define BP_PXP_HIST16_PARAM0_VALUE1 8
+#define BM_PXP_HIST16_PARAM0_VALUE1 0x00001F00
+#define BF_PXP_HIST16_PARAM0_VALUE1(v) \
+ (((v) << 8) & BM_PXP_HIST16_PARAM0_VALUE1)
+#define BP_PXP_HIST16_PARAM0_RSVD0 5
+#define BM_PXP_HIST16_PARAM0_RSVD0 0x000000E0
+#define BF_PXP_HIST16_PARAM0_RSVD0(v) \
+ (((v) << 5) & BM_PXP_HIST16_PARAM0_RSVD0)
+#define BP_PXP_HIST16_PARAM0_VALUE0 0
+#define BM_PXP_HIST16_PARAM0_VALUE0 0x0000001F
+#define BF_PXP_HIST16_PARAM0_VALUE0(v) \
+ (((v) << 0) & BM_PXP_HIST16_PARAM0_VALUE0)
+
+#define HW_PXP_HIST16_PARAM1 (0x000002f0)
+
+#define BP_PXP_HIST16_PARAM1_RSVD7 29
+#define BM_PXP_HIST16_PARAM1_RSVD7 0xE0000000
+#define BF_PXP_HIST16_PARAM1_RSVD7(v) \
+ (((v) << 29) & BM_PXP_HIST16_PARAM1_RSVD7)
+#define BP_PXP_HIST16_PARAM1_VALUE7 24
+#define BM_PXP_HIST16_PARAM1_VALUE7 0x1F000000
+#define BF_PXP_HIST16_PARAM1_VALUE7(v) \
+ (((v) << 24) & BM_PXP_HIST16_PARAM1_VALUE7)
+#define BP_PXP_HIST16_PARAM1_RSVD6 21
+#define BM_PXP_HIST16_PARAM1_RSVD6 0x00E00000
+#define BF_PXP_HIST16_PARAM1_RSVD6(v) \
+ (((v) << 21) & BM_PXP_HIST16_PARAM1_RSVD6)
+#define BP_PXP_HIST16_PARAM1_VALUE6 16
+#define BM_PXP_HIST16_PARAM1_VALUE6 0x001F0000
+#define BF_PXP_HIST16_PARAM1_VALUE6(v) \
+ (((v) << 16) & BM_PXP_HIST16_PARAM1_VALUE6)
+#define BP_PXP_HIST16_PARAM1_RSVD5 13
+#define BM_PXP_HIST16_PARAM1_RSVD5 0x0000E000
+#define BF_PXP_HIST16_PARAM1_RSVD5(v) \
+ (((v) << 13) & BM_PXP_HIST16_PARAM1_RSVD5)
+#define BP_PXP_HIST16_PARAM1_VALUE5 8
+#define BM_PXP_HIST16_PARAM1_VALUE5 0x00001F00
+#define BF_PXP_HIST16_PARAM1_VALUE5(v) \
+ (((v) << 8) & BM_PXP_HIST16_PARAM1_VALUE5)
+#define BP_PXP_HIST16_PARAM1_RSVD4 5
+#define BM_PXP_HIST16_PARAM1_RSVD4 0x000000E0
+#define BF_PXP_HIST16_PARAM1_RSVD4(v) \
+ (((v) << 5) & BM_PXP_HIST16_PARAM1_RSVD4)
+#define BP_PXP_HIST16_PARAM1_VALUE4 0
+#define BM_PXP_HIST16_PARAM1_VALUE4 0x0000001F
+#define BF_PXP_HIST16_PARAM1_VALUE4(v) \
+ (((v) << 0) & BM_PXP_HIST16_PARAM1_VALUE4)
+
+#define HW_PXP_HIST16_PARAM2 (0x00000300)
+
+#define BP_PXP_HIST16_PARAM2_RSVD11 29
+#define BM_PXP_HIST16_PARAM2_RSVD11 0xE0000000
+#define BF_PXP_HIST16_PARAM2_RSVD11(v) \
+ (((v) << 29) & BM_PXP_HIST16_PARAM2_RSVD11)
+#define BP_PXP_HIST16_PARAM2_VALUE11 24
+#define BM_PXP_HIST16_PARAM2_VALUE11 0x1F000000
+#define BF_PXP_HIST16_PARAM2_VALUE11(v) \
+ (((v) << 24) & BM_PXP_HIST16_PARAM2_VALUE11)
+#define BP_PXP_HIST16_PARAM2_RSVD10 21
+#define BM_PXP_HIST16_PARAM2_RSVD10 0x00E00000
+#define BF_PXP_HIST16_PARAM2_RSVD10(v) \
+ (((v) << 21) & BM_PXP_HIST16_PARAM2_RSVD10)
+#define BP_PXP_HIST16_PARAM2_VALUE10 16
+#define BM_PXP_HIST16_PARAM2_VALUE10 0x001F0000
+#define BF_PXP_HIST16_PARAM2_VALUE10(v) \
+ (((v) << 16) & BM_PXP_HIST16_PARAM2_VALUE10)
+#define BP_PXP_HIST16_PARAM2_RSVD9 13
+#define BM_PXP_HIST16_PARAM2_RSVD9 0x0000E000
+#define BF_PXP_HIST16_PARAM2_RSVD9(v) \
+ (((v) << 13) & BM_PXP_HIST16_PARAM2_RSVD9)
+#define BP_PXP_HIST16_PARAM2_VALUE9 8
+#define BM_PXP_HIST16_PARAM2_VALUE9 0x00001F00
+#define BF_PXP_HIST16_PARAM2_VALUE9(v) \
+ (((v) << 8) & BM_PXP_HIST16_PARAM2_VALUE9)
+#define BP_PXP_HIST16_PARAM2_RSVD8 5
+#define BM_PXP_HIST16_PARAM2_RSVD8 0x000000E0
+#define BF_PXP_HIST16_PARAM2_RSVD8(v) \
+ (((v) << 5) & BM_PXP_HIST16_PARAM2_RSVD8)
+#define BP_PXP_HIST16_PARAM2_VALUE8 0
+#define BM_PXP_HIST16_PARAM2_VALUE8 0x0000001F
+#define BF_PXP_HIST16_PARAM2_VALUE8(v) \
+ (((v) << 0) & BM_PXP_HIST16_PARAM2_VALUE8)
+
+#define HW_PXP_HIST16_PARAM3 (0x00000310)
+
+#define BP_PXP_HIST16_PARAM3_RSVD15 29
+#define BM_PXP_HIST16_PARAM3_RSVD15 0xE0000000
+#define BF_PXP_HIST16_PARAM3_RSVD15(v) \
+ (((v) << 29) & BM_PXP_HIST16_PARAM3_RSVD15)
+#define BP_PXP_HIST16_PARAM3_VALUE15 24
+#define BM_PXP_HIST16_PARAM3_VALUE15 0x1F000000
+#define BF_PXP_HIST16_PARAM3_VALUE15(v) \
+ (((v) << 24) & BM_PXP_HIST16_PARAM3_VALUE15)
+#define BP_PXP_HIST16_PARAM3_RSVD14 21
+#define BM_PXP_HIST16_PARAM3_RSVD14 0x00E00000
+#define BF_PXP_HIST16_PARAM3_RSVD14(v) \
+ (((v) << 21) & BM_PXP_HIST16_PARAM3_RSVD14)
+#define BP_PXP_HIST16_PARAM3_VALUE14 16
+#define BM_PXP_HIST16_PARAM3_VALUE14 0x001F0000
+#define BF_PXP_HIST16_PARAM3_VALUE14(v) \
+ (((v) << 16) & BM_PXP_HIST16_PARAM3_VALUE14)
+#define BP_PXP_HIST16_PARAM3_RSVD13 13
+#define BM_PXP_HIST16_PARAM3_RSVD13 0x0000E000
+#define BF_PXP_HIST16_PARAM3_RSVD13(v) \
+ (((v) << 13) & BM_PXP_HIST16_PARAM3_RSVD13)
+#define BP_PXP_HIST16_PARAM3_VALUE13 8
+#define BM_PXP_HIST16_PARAM3_VALUE13 0x00001F00
+#define BF_PXP_HIST16_PARAM3_VALUE13(v) \
+ (((v) << 8) & BM_PXP_HIST16_PARAM3_VALUE13)
+#define BP_PXP_HIST16_PARAM3_RSVD12 5
+#define BM_PXP_HIST16_PARAM3_RSVD12 0x000000E0
+#define BF_PXP_HIST16_PARAM3_RSVD12(v) \
+ (((v) << 5) & BM_PXP_HIST16_PARAM3_RSVD12)
+#define BP_PXP_HIST16_PARAM3_VALUE12 0
+#define BM_PXP_HIST16_PARAM3_VALUE12 0x0000001F
+#define BF_PXP_HIST16_PARAM3_VALUE12(v) \
+ (((v) << 0) & BM_PXP_HIST16_PARAM3_VALUE12)
+
+#define HW_PXP_POWER (0x00000320)
+
+#define BP_PXP_POWER_CTRL 12
+#define BM_PXP_POWER_CTRL 0xFFFFF000
+#define BF_PXP_POWER_CTRL(v) \
+ (((v) << 12) & BM_PXP_POWER_CTRL)
+#define BP_PXP_POWER_ROT_MEM_LP_STATE 9
+#define BM_PXP_POWER_ROT_MEM_LP_STATE 0x00000E00
+#define BF_PXP_POWER_ROT_MEM_LP_STATE(v) \
+ (((v) << 9) & BM_PXP_POWER_ROT_MEM_LP_STATE)
+#define BV_PXP_POWER_ROT_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_ROT_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_ROT_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_ROT_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_LUT_LP_STATE_WAY1_BANKN 6
+#define BM_PXP_POWER_LUT_LP_STATE_WAY1_BANKN 0x000001C0
+#define BF_PXP_POWER_LUT_LP_STATE_WAY1_BANKN(v) \
+ (((v) << 6) & BM_PXP_POWER_LUT_LP_STATE_WAY1_BANKN)
+#define BV_PXP_POWER_LUT_LP_STATE_WAY1_BANKN__NONE 0x0
+#define BV_PXP_POWER_LUT_LP_STATE_WAY1_BANKN__LS 0x1
+#define BV_PXP_POWER_LUT_LP_STATE_WAY1_BANKN__DS 0x2
+#define BV_PXP_POWER_LUT_LP_STATE_WAY1_BANKN__SD 0x4
+#define BP_PXP_POWER_LUT_LP_STATE_WAY0_BANKN 3
+#define BM_PXP_POWER_LUT_LP_STATE_WAY0_BANKN 0x00000038
+#define BF_PXP_POWER_LUT_LP_STATE_WAY0_BANKN(v) \
+ (((v) << 3) & BM_PXP_POWER_LUT_LP_STATE_WAY0_BANKN)
+#define BV_PXP_POWER_LUT_LP_STATE_WAY0_BANKN__NONE 0x0
+#define BV_PXP_POWER_LUT_LP_STATE_WAY0_BANKN__LS 0x1
+#define BV_PXP_POWER_LUT_LP_STATE_WAY0_BANKN__DS 0x2
+#define BV_PXP_POWER_LUT_LP_STATE_WAY0_BANKN__SD 0x4
+#define BP_PXP_POWER_LUT_LP_STATE_WAY0_BANK0 0
+#define BM_PXP_POWER_LUT_LP_STATE_WAY0_BANK0 0x00000007
+#define BF_PXP_POWER_LUT_LP_STATE_WAY0_BANK0(v) \
+ (((v) << 0) & BM_PXP_POWER_LUT_LP_STATE_WAY0_BANK0)
+#define BV_PXP_POWER_LUT_LP_STATE_WAY0_BANK0__NONE 0x0
+#define BV_PXP_POWER_LUT_LP_STATE_WAY0_BANK0__LS 0x1
+#define BV_PXP_POWER_LUT_LP_STATE_WAY0_BANK0__DS 0x2
+#define BV_PXP_POWER_LUT_LP_STATE_WAY0_BANK0__SD 0x4
+
+#define HW_PXP_NEXT (0x00000400)
+
+#define BP_PXP_NEXT_POINTER 2
+#define BM_PXP_NEXT_POINTER 0xFFFFFFFC
+#define BF_PXP_NEXT_POINTER(v) \
+ (((v) << 2) & BM_PXP_NEXT_POINTER)
+#define BM_PXP_NEXT_RSVD 0x00000002
+#define BM_PXP_NEXT_ENABLED 0x00000001
+
+#define HW_PXP_DEBUGCTRL (0x00000410)
+
+#define BP_PXP_DEBUGCTRL_RSVD 12
+#define BM_PXP_DEBUGCTRL_RSVD 0xFFFFF000
+#define BF_PXP_DEBUGCTRL_RSVD(v) \
+ (((v) << 12) & BM_PXP_DEBUGCTRL_RSVD)
+#define BP_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT 8
+#define BM_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT 0x00000F00
+#define BF_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT(v) \
+ (((v) << 8) & BM_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT)
+#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__NONE 0x0
+#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__MISS_CNT 0x1
+#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__HIT_CNT 0x2
+#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__LAT_CNT 0x4
+#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__MAX_LAT 0x8
+#define BP_PXP_DEBUGCTRL_SELECT 0
+#define BM_PXP_DEBUGCTRL_SELECT 0x000000FF
+#define BF_PXP_DEBUGCTRL_SELECT(v) \
+ (((v) << 0) & BM_PXP_DEBUGCTRL_SELECT)
+#define BV_PXP_DEBUGCTRL_SELECT__NONE 0x0
+#define BV_PXP_DEBUGCTRL_SELECT__CTRL 0x1
+#define BV_PXP_DEBUGCTRL_SELECT__PSBUF 0x2
+#define BV_PXP_DEBUGCTRL_SELECT__PSBAX 0x3
+#define BV_PXP_DEBUGCTRL_SELECT__PSBAY 0x4
+#define BV_PXP_DEBUGCTRL_SELECT__ASBUF 0x5
+#define BV_PXP_DEBUGCTRL_SELECT__ROTATION 0x6
+#define BV_PXP_DEBUGCTRL_SELECT__OUTBUF0 0x7
+#define BV_PXP_DEBUGCTRL_SELECT__OUTBUF1 0x8
+#define BV_PXP_DEBUGCTRL_SELECT__OUTBUF2 0x9
+#define BV_PXP_DEBUGCTRL_SELECT__LUT_STAT 0x10
+#define BV_PXP_DEBUGCTRL_SELECT__LUT_MISS 0x11
+#define BV_PXP_DEBUGCTRL_SELECT__LUT_HIT 0x12
+#define BV_PXP_DEBUGCTRL_SELECT__LUT_LAT 0x13
+#define BV_PXP_DEBUGCTRL_SELECT__LUT_MAX_LAT 0x14
+
+#define HW_PXP_DEBUG (0x00000420)
+
+#define BP_PXP_DEBUG_DATA 0
+#define BM_PXP_DEBUG_DATA 0xFFFFFFFF
+#define BF_PXP_DEBUG_DATA(v) (v)
+
+#define HW_PXP_VERSION (0x00000430)
+
+#define BP_PXP_VERSION_MAJOR 24
+#define BM_PXP_VERSION_MAJOR 0xFF000000
+#define BF_PXP_VERSION_MAJOR(v) \
+ (((v) << 24) & BM_PXP_VERSION_MAJOR)
+#define BP_PXP_VERSION_MINOR 16
+#define BM_PXP_VERSION_MINOR 0x00FF0000
+#define BF_PXP_VERSION_MINOR(v) \
+ (((v) << 16) & BM_PXP_VERSION_MINOR)
+#define BP_PXP_VERSION_STEP 0
+#define BM_PXP_VERSION_STEP 0x0000FFFF
+#define BF_PXP_VERSION_STEP(v) \
+ (((v) << 0) & BM_PXP_VERSION_STEP)
+#endif /* __ARCH_ARM___PXP_H */
diff --git a/drivers/dma/pxp/regs-pxp_v3.h b/drivers/dma/pxp/regs-pxp_v3.h
new file mode 100644
index 000000000000..80e310bb5ca7
--- /dev/null
+++ b/drivers/dma/pxp/regs-pxp_v3.h
@@ -0,0 +1,26952 @@
+/*
+ * Freescale PXP Register Definitions
+ *
+ * Copyright 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This file is created by xml file. Don't Edit it.
+ *
+ * Xml Revision: 1.77
+ * Template revision: 1.3
+ */
+
+#ifndef __ARCH_ARM___PXP_H
+#define __ARCH_ARM___PXP_H
+
+
+#define HW_PXP_CTRL (0x00000000)
+#define HW_PXP_CTRL_SET (0x00000004)
+#define HW_PXP_CTRL_CLR (0x00000008)
+#define HW_PXP_CTRL_TOG (0x0000000c)
+
+#define BM_PXP_CTRL_SFTRST 0x80000000
+#define BF_PXP_CTRL_SFTRST(v) \
+ (((v) << 31) & BM_PXP_CTRL_SFTRST)
+#define BM_PXP_CTRL_CLKGATE 0x40000000
+#define BF_PXP_CTRL_CLKGATE(v) \
+ (((v) << 30) & BM_PXP_CTRL_CLKGATE)
+#define BM_PXP_CTRL_RSVD4 0x20000000
+#define BF_PXP_CTRL_RSVD4(v) \
+ (((v) << 29) & BM_PXP_CTRL_RSVD4)
+#define BM_PXP_CTRL_EN_REPEAT 0x10000000
+#define BF_PXP_CTRL_EN_REPEAT(v) \
+ (((v) << 28) & BM_PXP_CTRL_EN_REPEAT)
+#define BM_PXP_CTRL_ENABLE_ROTATE1 0x08000000
+#define BF_PXP_CTRL_ENABLE_ROTATE1(v) \
+ (((v) << 27) & BM_PXP_CTRL_ENABLE_ROTATE1)
+#define BM_PXP_CTRL_ENABLE_ROTATE0 0x04000000
+#define BF_PXP_CTRL_ENABLE_ROTATE0(v) \
+ (((v) << 26) & BM_PXP_CTRL_ENABLE_ROTATE0)
+#define BM_PXP_CTRL_ENABLE_LUT 0x02000000
+#define BF_PXP_CTRL_ENABLE_LUT(v) \
+ (((v) << 25) & BM_PXP_CTRL_ENABLE_LUT)
+#define BM_PXP_CTRL_ENABLE_CSC2 0x01000000
+#define BF_PXP_CTRL_ENABLE_CSC2(v) \
+ (((v) << 24) & BM_PXP_CTRL_ENABLE_CSC2)
+#define BM_PXP_CTRL_BLOCK_SIZE 0x00800000
+#define BF_PXP_CTRL_BLOCK_SIZE(v) \
+ (((v) << 23) & BM_PXP_CTRL_BLOCK_SIZE)
+#define BV_PXP_CTRL_BLOCK_SIZE__8X8 0x0
+#define BV_PXP_CTRL_BLOCK_SIZE__16X16 0x1
+#define BM_PXP_CTRL_RSVD1 0x00400000
+#define BF_PXP_CTRL_RSVD1(v) \
+ (((v) << 22) & BM_PXP_CTRL_RSVD1)
+#define BM_PXP_CTRL_ENABLE_ALPHA_B 0x00200000
+#define BF_PXP_CTRL_ENABLE_ALPHA_B(v) \
+ (((v) << 21) & BM_PXP_CTRL_ENABLE_ALPHA_B)
+#define BM_PXP_CTRL_ENABLE_INPUT_FETCH_STORE 0x00100000
+#define BF_PXP_CTRL_ENABLE_INPUT_FETCH_STORE(v) \
+ (((v) << 20) & BM_PXP_CTRL_ENABLE_INPUT_FETCH_STORE)
+#define BM_PXP_CTRL_ENABLE_WFE_B 0x00080000
+#define BF_PXP_CTRL_ENABLE_WFE_B(v) \
+ (((v) << 19) & BM_PXP_CTRL_ENABLE_WFE_B)
+#define BM_PXP_CTRL_ENABLE_WFE_A 0x00040000
+#define BF_PXP_CTRL_ENABLE_WFE_A(v) \
+ (((v) << 18) & BM_PXP_CTRL_ENABLE_WFE_A)
+#define BM_PXP_CTRL_ENABLE_DITHER 0x00020000
+#define BF_PXP_CTRL_ENABLE_DITHER(v) \
+ (((v) << 17) & BM_PXP_CTRL_ENABLE_DITHER)
+#define BM_PXP_CTRL_ENABLE_PS_AS_OUT 0x00010000
+#define BF_PXP_CTRL_ENABLE_PS_AS_OUT(v) \
+ (((v) << 16) & BM_PXP_CTRL_ENABLE_PS_AS_OUT)
+#define BM_PXP_CTRL_VFLIP1 0x00008000
+#define BF_PXP_CTRL_VFLIP1(v) \
+ (((v) << 15) & BM_PXP_CTRL_VFLIP1)
+#define BM_PXP_CTRL_HFLIP1 0x00004000
+#define BF_PXP_CTRL_HFLIP1(v) \
+ (((v) << 14) & BM_PXP_CTRL_HFLIP1)
+#define BP_PXP_CTRL_ROTATE1 12
+#define BM_PXP_CTRL_ROTATE1 0x00003000
+#define BF_PXP_CTRL_ROTATE1(v) \
+ (((v) << 12) & BM_PXP_CTRL_ROTATE1)
+#define BV_PXP_CTRL_ROTATE1__ROT_0 0x0
+#define BV_PXP_CTRL_ROTATE1__ROT_90 0x1
+#define BV_PXP_CTRL_ROTATE1__ROT_180 0x2
+#define BV_PXP_CTRL_ROTATE1__ROT_270 0x3
+#define BM_PXP_CTRL_VFLIP0 0x00000800
+#define BF_PXP_CTRL_VFLIP0(v) \
+ (((v) << 11) & BM_PXP_CTRL_VFLIP0)
+#define BM_PXP_CTRL_HFLIP0 0x00000400
+#define BF_PXP_CTRL_HFLIP0(v) \
+ (((v) << 10) & BM_PXP_CTRL_HFLIP0)
+#define BP_PXP_CTRL_ROTATE0 8
+#define BM_PXP_CTRL_ROTATE0 0x00000300
+#define BF_PXP_CTRL_ROTATE0(v) \
+ (((v) << 8) & BM_PXP_CTRL_ROTATE0)
+#define BV_PXP_CTRL_ROTATE0__ROT_0 0x0
+#define BV_PXP_CTRL_ROTATE0__ROT_90 0x1
+#define BV_PXP_CTRL_ROTATE0__ROT_180 0x2
+#define BV_PXP_CTRL_ROTATE0__ROT_270 0x3
+#define BP_PXP_CTRL_RSVD0 6
+#define BM_PXP_CTRL_RSVD0 0x000000C0
+#define BF_PXP_CTRL_RSVD0(v) \
+ (((v) << 6) & BM_PXP_CTRL_RSVD0)
+#define BM_PXP_CTRL_HANDSHAKE_ABORT_SKIP 0x00000020
+#define BF_PXP_CTRL_HANDSHAKE_ABORT_SKIP(v) \
+ (((v) << 5) & BM_PXP_CTRL_HANDSHAKE_ABORT_SKIP)
+#define BM_PXP_CTRL_ENABLE_LCD0_HANDSHAKE 0x00000010
+#define BF_PXP_CTRL_ENABLE_LCD0_HANDSHAKE(v) \
+ (((v) << 4) & BM_PXP_CTRL_ENABLE_LCD0_HANDSHAKE)
+#define BM_PXP_CTRL_LUT_DMA_IRQ_ENABLE 0x00000008
+#define BF_PXP_CTRL_LUT_DMA_IRQ_ENABLE(v) \
+ (((v) << 3) & BM_PXP_CTRL_LUT_DMA_IRQ_ENABLE)
+#define BM_PXP_CTRL_NEXT_IRQ_ENABLE 0x00000004
+#define BF_PXP_CTRL_NEXT_IRQ_ENABLE(v) \
+ (((v) << 2) & BM_PXP_CTRL_NEXT_IRQ_ENABLE)
+#define BM_PXP_CTRL_IRQ_ENABLE 0x00000002
+#define BF_PXP_CTRL_IRQ_ENABLE(v) \
+ (((v) << 1) & BM_PXP_CTRL_IRQ_ENABLE)
+#define BM_PXP_CTRL_ENABLE 0x00000001
+#define BF_PXP_CTRL_ENABLE(v) \
+ (((v) << 0) & BM_PXP_CTRL_ENABLE)
+
+#define HW_PXP_STAT (0x00000010)
+#define HW_PXP_STAT_SET (0x00000014)
+#define HW_PXP_STAT_CLR (0x00000018)
+#define HW_PXP_STAT_TOG (0x0000001c)
+
+#define BP_PXP_STAT_BLOCKX 24
+#define BM_PXP_STAT_BLOCKX 0xFF000000
+#define BF_PXP_STAT_BLOCKX(v) \
+ (((v) << 24) & BM_PXP_STAT_BLOCKX)
+#define BP_PXP_STAT_BLOCKY 16
+#define BM_PXP_STAT_BLOCKY 0x00FF0000
+#define BF_PXP_STAT_BLOCKY(v) \
+ (((v) << 16) & BM_PXP_STAT_BLOCKY)
+#define BP_PXP_STAT_AXI_ERROR_ID_1 12
+#define BM_PXP_STAT_AXI_ERROR_ID_1 0x0000F000
+#define BF_PXP_STAT_AXI_ERROR_ID_1(v) \
+ (((v) << 12) & BM_PXP_STAT_AXI_ERROR_ID_1)
+#define BM_PXP_STAT_RSVD2 0x00000800
+#define BF_PXP_STAT_RSVD2(v) \
+ (((v) << 11) & BM_PXP_STAT_RSVD2)
+#define BM_PXP_STAT_AXI_READ_ERROR_1 0x00000400
+#define BF_PXP_STAT_AXI_READ_ERROR_1(v) \
+ (((v) << 10) & BM_PXP_STAT_AXI_READ_ERROR_1)
+#define BM_PXP_STAT_AXI_WRITE_ERROR_1 0x00000200
+#define BF_PXP_STAT_AXI_WRITE_ERROR_1(v) \
+ (((v) << 9) & BM_PXP_STAT_AXI_WRITE_ERROR_1)
+#define BM_PXP_STAT_LUT_DMA_LOAD_DONE_IRQ 0x00000100
+#define BF_PXP_STAT_LUT_DMA_LOAD_DONE_IRQ(v) \
+ (((v) << 8) & BM_PXP_STAT_LUT_DMA_LOAD_DONE_IRQ)
+#define BP_PXP_STAT_AXI_ERROR_ID_0 4
+#define BM_PXP_STAT_AXI_ERROR_ID_0 0x000000F0
+#define BF_PXP_STAT_AXI_ERROR_ID_0(v) \
+ (((v) << 4) & BM_PXP_STAT_AXI_ERROR_ID_0)
+#define BM_PXP_STAT_NEXT_IRQ 0x00000008
+#define BF_PXP_STAT_NEXT_IRQ(v) \
+ (((v) << 3) & BM_PXP_STAT_NEXT_IRQ)
+#define BM_PXP_STAT_AXI_READ_ERROR_0 0x00000004
+#define BF_PXP_STAT_AXI_READ_ERROR_0(v) \
+ (((v) << 2) & BM_PXP_STAT_AXI_READ_ERROR_0)
+#define BM_PXP_STAT_AXI_WRITE_ERROR_0 0x00000002
+#define BF_PXP_STAT_AXI_WRITE_ERROR_0(v) \
+ (((v) << 1) & BM_PXP_STAT_AXI_WRITE_ERROR_0)
+#define BM_PXP_STAT_IRQ0 0x00000001
+#define BF_PXP_STAT_IRQ0(v) \
+ (((v) << 0) & BM_PXP_STAT_IRQ0)
+
+#define HW_PXP_OUT_CTRL (0x00000020)
+#define HW_PXP_OUT_CTRL_SET (0x00000024)
+#define HW_PXP_OUT_CTRL_CLR (0x00000028)
+#define HW_PXP_OUT_CTRL_TOG (0x0000002c)
+
+#define BP_PXP_OUT_CTRL_ALPHA 24
+#define BM_PXP_OUT_CTRL_ALPHA 0xFF000000
+#define BF_PXP_OUT_CTRL_ALPHA(v) \
+ (((v) << 24) & BM_PXP_OUT_CTRL_ALPHA)
+#define BM_PXP_OUT_CTRL_ALPHA_OUTPUT 0x00800000
+#define BF_PXP_OUT_CTRL_ALPHA_OUTPUT(v) \
+ (((v) << 23) & BM_PXP_OUT_CTRL_ALPHA_OUTPUT)
+#define BP_PXP_OUT_CTRL_RSVD1 10
+#define BM_PXP_OUT_CTRL_RSVD1 0x007FFC00
+#define BF_PXP_OUT_CTRL_RSVD1(v) \
+ (((v) << 10) & BM_PXP_OUT_CTRL_RSVD1)
+#define BP_PXP_OUT_CTRL_INTERLACED_OUTPUT 8
+#define BM_PXP_OUT_CTRL_INTERLACED_OUTPUT 0x00000300
+#define BF_PXP_OUT_CTRL_INTERLACED_OUTPUT(v) \
+ (((v) << 8) & BM_PXP_OUT_CTRL_INTERLACED_OUTPUT)
+#define BV_PXP_OUT_CTRL_INTERLACED_OUTPUT__PROGRESSIVE 0x0
+#define BV_PXP_OUT_CTRL_INTERLACED_OUTPUT__FIELD0 0x1
+#define BV_PXP_OUT_CTRL_INTERLACED_OUTPUT__FIELD1 0x2
+#define BV_PXP_OUT_CTRL_INTERLACED_OUTPUT__INTERLACED 0x3
+#define BP_PXP_OUT_CTRL_RSVD0 5
+#define BM_PXP_OUT_CTRL_RSVD0 0x000000E0
+#define BF_PXP_OUT_CTRL_RSVD0(v) \
+ (((v) << 5) & BM_PXP_OUT_CTRL_RSVD0)
+#define BP_PXP_OUT_CTRL_FORMAT 0
+#define BM_PXP_OUT_CTRL_FORMAT 0x0000001F
+#define BF_PXP_OUT_CTRL_FORMAT(v) \
+ (((v) << 0) & BM_PXP_OUT_CTRL_FORMAT)
+#define BV_PXP_OUT_CTRL_FORMAT__ARGB8888 0x0
+#define BV_PXP_OUT_CTRL_FORMAT__RGB888 0x4
+#define BV_PXP_OUT_CTRL_FORMAT__RGB888P 0x5
+#define BV_PXP_OUT_CTRL_FORMAT__ARGB1555 0x8
+#define BV_PXP_OUT_CTRL_FORMAT__ARGB4444 0x9
+#define BV_PXP_OUT_CTRL_FORMAT__RGB555 0xC
+#define BV_PXP_OUT_CTRL_FORMAT__RGB444 0xD
+#define BV_PXP_OUT_CTRL_FORMAT__RGB565 0xE
+#define BV_PXP_OUT_CTRL_FORMAT__YUV1P444 0x10
+#define BV_PXP_OUT_CTRL_FORMAT__UYVY1P422 0x12
+#define BV_PXP_OUT_CTRL_FORMAT__VYUY1P422 0x13
+#define BV_PXP_OUT_CTRL_FORMAT__Y8 0x14
+#define BV_PXP_OUT_CTRL_FORMAT__Y4 0x15
+#define BV_PXP_OUT_CTRL_FORMAT__YUV2P422 0x18
+#define BV_PXP_OUT_CTRL_FORMAT__YUV2P420 0x19
+#define BV_PXP_OUT_CTRL_FORMAT__YVU2P422 0x1A
+#define BV_PXP_OUT_CTRL_FORMAT__YVU2P420 0x1B
+
+#define HW_PXP_OUT_BUF (0x00000030)
+
+#define BP_PXP_OUT_BUF_ADDR 0
+#define BM_PXP_OUT_BUF_ADDR 0xFFFFFFFF
+#define BF_PXP_OUT_BUF_ADDR(v) (v)
+
+#define HW_PXP_OUT_BUF2 (0x00000040)
+
+#define BP_PXP_OUT_BUF2_ADDR 0
+#define BM_PXP_OUT_BUF2_ADDR 0xFFFFFFFF
+#define BF_PXP_OUT_BUF2_ADDR(v) (v)
+
+#define HW_PXP_OUT_PITCH (0x00000050)
+
+#define BP_PXP_OUT_PITCH_RSVD 16
+#define BM_PXP_OUT_PITCH_RSVD 0xFFFF0000
+#define BF_PXP_OUT_PITCH_RSVD(v) \
+ (((v) << 16) & BM_PXP_OUT_PITCH_RSVD)
+#define BP_PXP_OUT_PITCH_PITCH 0
+#define BM_PXP_OUT_PITCH_PITCH 0x0000FFFF
+#define BF_PXP_OUT_PITCH_PITCH(v) \
+ (((v) << 0) & BM_PXP_OUT_PITCH_PITCH)
+
+#define HW_PXP_OUT_LRC (0x00000060)
+
+#define BP_PXP_OUT_LRC_RSVD1 30
+#define BM_PXP_OUT_LRC_RSVD1 0xC0000000
+#define BF_PXP_OUT_LRC_RSVD1(v) \
+ (((v) << 30) & BM_PXP_OUT_LRC_RSVD1)
+#define BP_PXP_OUT_LRC_X 16
+#define BM_PXP_OUT_LRC_X 0x3FFF0000
+#define BF_PXP_OUT_LRC_X(v) \
+ (((v) << 16) & BM_PXP_OUT_LRC_X)
+#define BP_PXP_OUT_LRC_RSVD0 14
+#define BM_PXP_OUT_LRC_RSVD0 0x0000C000
+#define BF_PXP_OUT_LRC_RSVD0(v) \
+ (((v) << 14) & BM_PXP_OUT_LRC_RSVD0)
+#define BP_PXP_OUT_LRC_Y 0
+#define BM_PXP_OUT_LRC_Y 0x00003FFF
+#define BF_PXP_OUT_LRC_Y(v) \
+ (((v) << 0) & BM_PXP_OUT_LRC_Y)
+
+#define HW_PXP_OUT_PS_ULC (0x00000070)
+
+#define BP_PXP_OUT_PS_ULC_RSVD1 30
+#define BM_PXP_OUT_PS_ULC_RSVD1 0xC0000000
+#define BF_PXP_OUT_PS_ULC_RSVD1(v) \
+ (((v) << 30) & BM_PXP_OUT_PS_ULC_RSVD1)
+#define BP_PXP_OUT_PS_ULC_X 16
+#define BM_PXP_OUT_PS_ULC_X 0x3FFF0000
+#define BF_PXP_OUT_PS_ULC_X(v) \
+ (((v) << 16) & BM_PXP_OUT_PS_ULC_X)
+#define BP_PXP_OUT_PS_ULC_RSVD0 14
+#define BM_PXP_OUT_PS_ULC_RSVD0 0x0000C000
+#define BF_PXP_OUT_PS_ULC_RSVD0(v) \
+ (((v) << 14) & BM_PXP_OUT_PS_ULC_RSVD0)
+#define BP_PXP_OUT_PS_ULC_Y 0
+#define BM_PXP_OUT_PS_ULC_Y 0x00003FFF
+#define BF_PXP_OUT_PS_ULC_Y(v) \
+ (((v) << 0) & BM_PXP_OUT_PS_ULC_Y)
+
+#define HW_PXP_OUT_PS_LRC (0x00000080)
+
+#define BP_PXP_OUT_PS_LRC_RSVD1 30
+#define BM_PXP_OUT_PS_LRC_RSVD1 0xC0000000
+#define BF_PXP_OUT_PS_LRC_RSVD1(v) \
+ (((v) << 30) & BM_PXP_OUT_PS_LRC_RSVD1)
+#define BP_PXP_OUT_PS_LRC_X 16
+#define BM_PXP_OUT_PS_LRC_X 0x3FFF0000
+#define BF_PXP_OUT_PS_LRC_X(v) \
+ (((v) << 16) & BM_PXP_OUT_PS_LRC_X)
+#define BP_PXP_OUT_PS_LRC_RSVD0 14
+#define BM_PXP_OUT_PS_LRC_RSVD0 0x0000C000
+#define BF_PXP_OUT_PS_LRC_RSVD0(v) \
+ (((v) << 14) & BM_PXP_OUT_PS_LRC_RSVD0)
+#define BP_PXP_OUT_PS_LRC_Y 0
+#define BM_PXP_OUT_PS_LRC_Y 0x00003FFF
+#define BF_PXP_OUT_PS_LRC_Y(v) \
+ (((v) << 0) & BM_PXP_OUT_PS_LRC_Y)
+
+#define HW_PXP_OUT_AS_ULC (0x00000090)
+
+#define BP_PXP_OUT_AS_ULC_RSVD1 30
+#define BM_PXP_OUT_AS_ULC_RSVD1 0xC0000000
+#define BF_PXP_OUT_AS_ULC_RSVD1(v) \
+ (((v) << 30) & BM_PXP_OUT_AS_ULC_RSVD1)
+#define BP_PXP_OUT_AS_ULC_X 16
+#define BM_PXP_OUT_AS_ULC_X 0x3FFF0000
+#define BF_PXP_OUT_AS_ULC_X(v) \
+ (((v) << 16) & BM_PXP_OUT_AS_ULC_X)
+#define BP_PXP_OUT_AS_ULC_RSVD0 14
+#define BM_PXP_OUT_AS_ULC_RSVD0 0x0000C000
+#define BF_PXP_OUT_AS_ULC_RSVD0(v) \
+ (((v) << 14) & BM_PXP_OUT_AS_ULC_RSVD0)
+#define BP_PXP_OUT_AS_ULC_Y 0
+#define BM_PXP_OUT_AS_ULC_Y 0x00003FFF
+#define BF_PXP_OUT_AS_ULC_Y(v) \
+ (((v) << 0) & BM_PXP_OUT_AS_ULC_Y)
+
+#define HW_PXP_OUT_AS_LRC (0x000000a0)
+
+#define BP_PXP_OUT_AS_LRC_RSVD1 30
+#define BM_PXP_OUT_AS_LRC_RSVD1 0xC0000000
+#define BF_PXP_OUT_AS_LRC_RSVD1(v) \
+ (((v) << 30) & BM_PXP_OUT_AS_LRC_RSVD1)
+#define BP_PXP_OUT_AS_LRC_X 16
+#define BM_PXP_OUT_AS_LRC_X 0x3FFF0000
+#define BF_PXP_OUT_AS_LRC_X(v) \
+ (((v) << 16) & BM_PXP_OUT_AS_LRC_X)
+#define BP_PXP_OUT_AS_LRC_RSVD0 14
+#define BM_PXP_OUT_AS_LRC_RSVD0 0x0000C000
+#define BF_PXP_OUT_AS_LRC_RSVD0(v) \
+ (((v) << 14) & BM_PXP_OUT_AS_LRC_RSVD0)
+#define BP_PXP_OUT_AS_LRC_Y 0
+#define BM_PXP_OUT_AS_LRC_Y 0x00003FFF
+#define BF_PXP_OUT_AS_LRC_Y(v) \
+ (((v) << 0) & BM_PXP_OUT_AS_LRC_Y)
+
+#define HW_PXP_PS_CTRL (0x000000b0)
+#define HW_PXP_PS_CTRL_SET (0x000000b4)
+#define HW_PXP_PS_CTRL_CLR (0x000000b8)
+#define HW_PXP_PS_CTRL_TOG (0x000000bc)
+
+#define BP_PXP_PS_CTRL_RSVD1 12
+#define BM_PXP_PS_CTRL_RSVD1 0xFFFFF000
+#define BF_PXP_PS_CTRL_RSVD1(v) \
+ (((v) << 12) & BM_PXP_PS_CTRL_RSVD1)
+#define BP_PXP_PS_CTRL_DECX 10
+#define BM_PXP_PS_CTRL_DECX 0x00000C00
+#define BF_PXP_PS_CTRL_DECX(v) \
+ (((v) << 10) & BM_PXP_PS_CTRL_DECX)
+#define BV_PXP_PS_CTRL_DECX__DISABLE 0x0
+#define BV_PXP_PS_CTRL_DECX__DECX2 0x1
+#define BV_PXP_PS_CTRL_DECX__DECX4 0x2
+#define BV_PXP_PS_CTRL_DECX__DECX8 0x3
+#define BP_PXP_PS_CTRL_DECY 8
+#define BM_PXP_PS_CTRL_DECY 0x00000300
+#define BF_PXP_PS_CTRL_DECY(v) \
+ (((v) << 8) & BM_PXP_PS_CTRL_DECY)
+#define BV_PXP_PS_CTRL_DECY__DISABLE 0x0
+#define BV_PXP_PS_CTRL_DECY__DECY2 0x1
+#define BV_PXP_PS_CTRL_DECY__DECY4 0x2
+#define BV_PXP_PS_CTRL_DECY__DECY8 0x3
+#define BM_PXP_PS_CTRL_RSVD0 0x00000080
+#define BF_PXP_PS_CTRL_RSVD0(v) \
+ (((v) << 7) & BM_PXP_PS_CTRL_RSVD0)
+#define BM_PXP_PS_CTRL_WB_SWAP 0x00000040
+#define BF_PXP_PS_CTRL_WB_SWAP(v) \
+ (((v) << 6) & BM_PXP_PS_CTRL_WB_SWAP)
+#define BP_PXP_PS_CTRL_FORMAT 0
+#define BM_PXP_PS_CTRL_FORMAT 0x0000003F
+#define BF_PXP_PS_CTRL_FORMAT(v) \
+ (((v) << 0) & BM_PXP_PS_CTRL_FORMAT)
+#define BV_PXP_PS_CTRL_FORMAT__RGB888 0x4
+#define BV_PXP_PS_CTRL_FORMAT__RGB555 0xC
+#define BV_PXP_PS_CTRL_FORMAT__RGB444 0xD
+#define BV_PXP_PS_CTRL_FORMAT__RGB565 0xE
+#define BV_PXP_PS_CTRL_FORMAT__YUV1P444 0x10
+#define BV_PXP_PS_CTRL_FORMAT__UYVY1P422 0x12
+#define BV_PXP_PS_CTRL_FORMAT__VYUY1P422 0x13
+#define BV_PXP_PS_CTRL_FORMAT__Y8 0x14
+#define BV_PXP_PS_CTRL_FORMAT__Y4 0x15
+#define BV_PXP_PS_CTRL_FORMAT__YUV2P422 0x18
+#define BV_PXP_PS_CTRL_FORMAT__YUV2P420 0x19
+#define BV_PXP_PS_CTRL_FORMAT__YVU2P422 0x1A
+#define BV_PXP_PS_CTRL_FORMAT__YVU2P420 0x1B
+#define BV_PXP_PS_CTRL_FORMAT__YUV422 0x1E
+#define BV_PXP_PS_CTRL_FORMAT__YUV420 0x1F
+#define BV_PXP_PS_CTRL_FORMAT__RGBA888 0x24
+
+#define HW_PXP_PS_BUF (0x000000c0)
+
+#define BP_PXP_PS_BUF_ADDR 0
+#define BM_PXP_PS_BUF_ADDR 0xFFFFFFFF
+#define BF_PXP_PS_BUF_ADDR(v) (v)
+
+#define HW_PXP_PS_UBUF (0x000000d0)
+
+#define BP_PXP_PS_UBUF_ADDR 0
+#define BM_PXP_PS_UBUF_ADDR 0xFFFFFFFF
+#define BF_PXP_PS_UBUF_ADDR(v) (v)
+
+#define HW_PXP_PS_VBUF (0x000000e0)
+
+#define BP_PXP_PS_VBUF_ADDR 0
+#define BM_PXP_PS_VBUF_ADDR 0xFFFFFFFF
+#define BF_PXP_PS_VBUF_ADDR(v) (v)
+
+#define HW_PXP_PS_PITCH (0x000000f0)
+
+#define BP_PXP_PS_PITCH_RSVD 16
+#define BM_PXP_PS_PITCH_RSVD 0xFFFF0000
+#define BF_PXP_PS_PITCH_RSVD(v) \
+ (((v) << 16) & BM_PXP_PS_PITCH_RSVD)
+#define BP_PXP_PS_PITCH_PITCH 0
+#define BM_PXP_PS_PITCH_PITCH 0x0000FFFF
+#define BF_PXP_PS_PITCH_PITCH(v) \
+ (((v) << 0) & BM_PXP_PS_PITCH_PITCH)
+
+#define HW_PXP_PS_BACKGROUND_0 (0x00000100)
+
+#define BP_PXP_PS_BACKGROUND_0_RSVD 24
+#define BM_PXP_PS_BACKGROUND_0_RSVD 0xFF000000
+#define BF_PXP_PS_BACKGROUND_0_RSVD(v) \
+ (((v) << 24) & BM_PXP_PS_BACKGROUND_0_RSVD)
+#define BP_PXP_PS_BACKGROUND_0_COLOR 0
+#define BM_PXP_PS_BACKGROUND_0_COLOR 0x00FFFFFF
+#define BF_PXP_PS_BACKGROUND_0_COLOR(v) \
+ (((v) << 0) & BM_PXP_PS_BACKGROUND_0_COLOR)
+
+#define HW_PXP_PS_SCALE (0x00000110)
+
+#define BM_PXP_PS_SCALE_RSVD2 0x80000000
+#define BF_PXP_PS_SCALE_RSVD2(v) \
+ (((v) << 31) & BM_PXP_PS_SCALE_RSVD2)
+#define BP_PXP_PS_SCALE_YSCALE 16
+#define BM_PXP_PS_SCALE_YSCALE 0x7FFF0000
+#define BF_PXP_PS_SCALE_YSCALE(v) \
+ (((v) << 16) & BM_PXP_PS_SCALE_YSCALE)
+#define BM_PXP_PS_SCALE_RSVD1 0x00008000
+#define BF_PXP_PS_SCALE_RSVD1(v) \
+ (((v) << 15) & BM_PXP_PS_SCALE_RSVD1)
+#define BP_PXP_PS_SCALE_XSCALE 0
+#define BM_PXP_PS_SCALE_XSCALE 0x00007FFF
+#define BF_PXP_PS_SCALE_XSCALE(v) \
+ (((v) << 0) & BM_PXP_PS_SCALE_XSCALE)
+
+#define BP_PXP_PS_SCALE_OFFSET 12
+
+#define HW_PXP_PS_OFFSET (0x00000120)
+
+#define BP_PXP_PS_OFFSET_RSVD2 28
+#define BM_PXP_PS_OFFSET_RSVD2 0xF0000000
+#define BF_PXP_PS_OFFSET_RSVD2(v) \
+ (((v) << 28) & BM_PXP_PS_OFFSET_RSVD2)
+#define BP_PXP_PS_OFFSET_YOFFSET 16
+#define BM_PXP_PS_OFFSET_YOFFSET 0x0FFF0000
+#define BF_PXP_PS_OFFSET_YOFFSET(v) \
+ (((v) << 16) & BM_PXP_PS_OFFSET_YOFFSET)
+#define BP_PXP_PS_OFFSET_RSVD1 12
+#define BM_PXP_PS_OFFSET_RSVD1 0x0000F000
+#define BF_PXP_PS_OFFSET_RSVD1(v) \
+ (((v) << 12) & BM_PXP_PS_OFFSET_RSVD1)
+#define BP_PXP_PS_OFFSET_XOFFSET 0
+#define BM_PXP_PS_OFFSET_XOFFSET 0x00000FFF
+#define BF_PXP_PS_OFFSET_XOFFSET(v) \
+ (((v) << 0) & BM_PXP_PS_OFFSET_XOFFSET)
+
+#define HW_PXP_PS_CLRKEYLOW_0 (0x00000130)
+
+#define BP_PXP_PS_CLRKEYLOW_0_RSVD1 24
+#define BM_PXP_PS_CLRKEYLOW_0_RSVD1 0xFF000000
+#define BF_PXP_PS_CLRKEYLOW_0_RSVD1(v) \
+ (((v) << 24) & BM_PXP_PS_CLRKEYLOW_0_RSVD1)
+#define BP_PXP_PS_CLRKEYLOW_0_PIXEL 0
+#define BM_PXP_PS_CLRKEYLOW_0_PIXEL 0x00FFFFFF
+#define BF_PXP_PS_CLRKEYLOW_0_PIXEL(v) \
+ (((v) << 0) & BM_PXP_PS_CLRKEYLOW_0_PIXEL)
+
+#define HW_PXP_PS_CLRKEYHIGH_0 (0x00000140)
+
+#define BP_PXP_PS_CLRKEYHIGH_0_RSVD1 24
+#define BM_PXP_PS_CLRKEYHIGH_0_RSVD1 0xFF000000
+#define BF_PXP_PS_CLRKEYHIGH_0_RSVD1(v) \
+ (((v) << 24) & BM_PXP_PS_CLRKEYHIGH_0_RSVD1)
+#define BP_PXP_PS_CLRKEYHIGH_0_PIXEL 0
+#define BM_PXP_PS_CLRKEYHIGH_0_PIXEL 0x00FFFFFF
+#define BF_PXP_PS_CLRKEYHIGH_0_PIXEL(v) \
+ (((v) << 0) & BM_PXP_PS_CLRKEYHIGH_0_PIXEL)
+
+#define HW_PXP_AS_CTRL (0x00000150)
+
+#define BP_PXP_AS_CTRL_RSVD1 22
+#define BM_PXP_AS_CTRL_RSVD1 0xFFC00000
+#define BF_PXP_AS_CTRL_RSVD1(v) \
+ (((v) << 22) & BM_PXP_AS_CTRL_RSVD1)
+#define BM_PXP_AS_CTRL_ALPHA1_INVERT 0x00200000
+#define BF_PXP_AS_CTRL_ALPHA1_INVERT(v) \
+ (((v) << 21) & BM_PXP_AS_CTRL_ALPHA1_INVERT)
+#define BM_PXP_AS_CTRL_ALPHA0_INVERT 0x00100000
+#define BF_PXP_AS_CTRL_ALPHA0_INVERT(v) \
+ (((v) << 20) & BM_PXP_AS_CTRL_ALPHA0_INVERT)
+#define BP_PXP_AS_CTRL_ROP 16
+#define BM_PXP_AS_CTRL_ROP 0x000F0000
+#define BF_PXP_AS_CTRL_ROP(v) \
+ (((v) << 16) & BM_PXP_AS_CTRL_ROP)
+#define BV_PXP_AS_CTRL_ROP__MASKAS 0x0
+#define BV_PXP_AS_CTRL_ROP__MASKNOTAS 0x1
+#define BV_PXP_AS_CTRL_ROP__MASKASNOT 0x2
+#define BV_PXP_AS_CTRL_ROP__MERGEAS 0x3
+#define BV_PXP_AS_CTRL_ROP__MERGENOTAS 0x4
+#define BV_PXP_AS_CTRL_ROP__MERGEASNOT 0x5
+#define BV_PXP_AS_CTRL_ROP__NOTCOPYAS 0x6
+#define BV_PXP_AS_CTRL_ROP__NOT 0x7
+#define BV_PXP_AS_CTRL_ROP__NOTMASKAS 0x8
+#define BV_PXP_AS_CTRL_ROP__NOTMERGEAS 0x9
+#define BV_PXP_AS_CTRL_ROP__XORAS 0xA
+#define BV_PXP_AS_CTRL_ROP__NOTXORAS 0xB
+#define BP_PXP_AS_CTRL_ALPHA 8
+#define BM_PXP_AS_CTRL_ALPHA 0x0000FF00
+#define BF_PXP_AS_CTRL_ALPHA(v) \
+ (((v) << 8) & BM_PXP_AS_CTRL_ALPHA)
+#define BP_PXP_AS_CTRL_FORMAT 4
+#define BM_PXP_AS_CTRL_FORMAT 0x000000F0
+#define BF_PXP_AS_CTRL_FORMAT(v) \
+ (((v) << 4) & BM_PXP_AS_CTRL_FORMAT)
+#define BV_PXP_AS_CTRL_FORMAT__ARGB8888 0x0
+#define BV_PXP_AS_CTRL_FORMAT__RGBA8888 0x1
+#define BV_PXP_AS_CTRL_FORMAT__RGB888 0x4
+#define BV_PXP_AS_CTRL_FORMAT__ARGB1555 0x8
+#define BV_PXP_AS_CTRL_FORMAT__ARGB4444 0x9
+#define BV_PXP_AS_CTRL_FORMAT__RGBA5551 0xA
+#define BV_PXP_AS_CTRL_FORMAT__RGBA4444 0xB
+#define BV_PXP_AS_CTRL_FORMAT__RGB555 0xC
+#define BV_PXP_AS_CTRL_FORMAT__RGB444 0xD
+#define BV_PXP_AS_CTRL_FORMAT__RGB565 0xE
+#define BM_PXP_AS_CTRL_ENABLE_COLORKEY 0x00000008
+#define BF_PXP_AS_CTRL_ENABLE_COLORKEY(v) \
+ (((v) << 3) & BM_PXP_AS_CTRL_ENABLE_COLORKEY)
+#define BP_PXP_AS_CTRL_ALPHA_CTRL 1
+#define BM_PXP_AS_CTRL_ALPHA_CTRL 0x00000006
+#define BF_PXP_AS_CTRL_ALPHA_CTRL(v) \
+ (((v) << 1) & BM_PXP_AS_CTRL_ALPHA_CTRL)
+#define BV_PXP_AS_CTRL_ALPHA_CTRL__Embedded 0x0
+#define BV_PXP_AS_CTRL_ALPHA_CTRL__Override 0x1
+#define BV_PXP_AS_CTRL_ALPHA_CTRL__Multiply 0x2
+#define BV_PXP_AS_CTRL_ALPHA_CTRL__ROPs 0x3
+#define BM_PXP_AS_CTRL_RSVD0 0x00000001
+#define BF_PXP_AS_CTRL_RSVD0(v) \
+ (((v) << 0) & BM_PXP_AS_CTRL_RSVD0)
+
+#define HW_PXP_AS_BUF (0x00000160)
+
+#define BP_PXP_AS_BUF_ADDR 0
+#define BM_PXP_AS_BUF_ADDR 0xFFFFFFFF
+#define BF_PXP_AS_BUF_ADDR(v) (v)
+
+#define HW_PXP_AS_PITCH (0x00000170)
+
+#define BP_PXP_AS_PITCH_RSVD 16
+#define BM_PXP_AS_PITCH_RSVD 0xFFFF0000
+#define BF_PXP_AS_PITCH_RSVD(v) \
+ (((v) << 16) & BM_PXP_AS_PITCH_RSVD)
+#define BP_PXP_AS_PITCH_PITCH 0
+#define BM_PXP_AS_PITCH_PITCH 0x0000FFFF
+#define BF_PXP_AS_PITCH_PITCH(v) \
+ (((v) << 0) & BM_PXP_AS_PITCH_PITCH)
+
+#define HW_PXP_AS_CLRKEYLOW_0 (0x00000180)
+
+#define BP_PXP_AS_CLRKEYLOW_0_RSVD1 24
+#define BM_PXP_AS_CLRKEYLOW_0_RSVD1 0xFF000000
+#define BF_PXP_AS_CLRKEYLOW_0_RSVD1(v) \
+ (((v) << 24) & BM_PXP_AS_CLRKEYLOW_0_RSVD1)
+#define BP_PXP_AS_CLRKEYLOW_0_PIXEL 0
+#define BM_PXP_AS_CLRKEYLOW_0_PIXEL 0x00FFFFFF
+#define BF_PXP_AS_CLRKEYLOW_0_PIXEL(v) \
+ (((v) << 0) & BM_PXP_AS_CLRKEYLOW_0_PIXEL)
+
+#define HW_PXP_AS_CLRKEYHIGH_0 (0x00000190)
+
+#define BP_PXP_AS_CLRKEYHIGH_0_RSVD1 24
+#define BM_PXP_AS_CLRKEYHIGH_0_RSVD1 0xFF000000
+#define BF_PXP_AS_CLRKEYHIGH_0_RSVD1(v) \
+ (((v) << 24) & BM_PXP_AS_CLRKEYHIGH_0_RSVD1)
+#define BP_PXP_AS_CLRKEYHIGH_0_PIXEL 0
+#define BM_PXP_AS_CLRKEYHIGH_0_PIXEL 0x00FFFFFF
+#define BF_PXP_AS_CLRKEYHIGH_0_PIXEL(v) \
+ (((v) << 0) & BM_PXP_AS_CLRKEYHIGH_0_PIXEL)
+
+#define HW_PXP_CSC1_COEF0 (0x000001a0)
+
+#define BM_PXP_CSC1_COEF0_YCBCR_MODE 0x80000000
+#define BF_PXP_CSC1_COEF0_YCBCR_MODE(v) \
+ (((v) << 31) & BM_PXP_CSC1_COEF0_YCBCR_MODE)
+#define BM_PXP_CSC1_COEF0_BYPASS 0x40000000
+#define BF_PXP_CSC1_COEF0_BYPASS(v) \
+ (((v) << 30) & BM_PXP_CSC1_COEF0_BYPASS)
+#define BM_PXP_CSC1_COEF0_RSVD1 0x20000000
+#define BF_PXP_CSC1_COEF0_RSVD1(v) \
+ (((v) << 29) & BM_PXP_CSC1_COEF0_RSVD1)
+#define BP_PXP_CSC1_COEF0_C0 18
+#define BM_PXP_CSC1_COEF0_C0 0x1FFC0000
+#define BF_PXP_CSC1_COEF0_C0(v) \
+ (((v) << 18) & BM_PXP_CSC1_COEF0_C0)
+#define BP_PXP_CSC1_COEF0_UV_OFFSET 9
+#define BM_PXP_CSC1_COEF0_UV_OFFSET 0x0003FE00
+#define BF_PXP_CSC1_COEF0_UV_OFFSET(v) \
+ (((v) << 9) & BM_PXP_CSC1_COEF0_UV_OFFSET)
+#define BP_PXP_CSC1_COEF0_Y_OFFSET 0
+#define BM_PXP_CSC1_COEF0_Y_OFFSET 0x000001FF
+#define BF_PXP_CSC1_COEF0_Y_OFFSET(v) \
+ (((v) << 0) & BM_PXP_CSC1_COEF0_Y_OFFSET)
+
+#define HW_PXP_CSC1_COEF1 (0x000001b0)
+
+#define BP_PXP_CSC1_COEF1_RSVD1 27
+#define BM_PXP_CSC1_COEF1_RSVD1 0xF8000000
+#define BF_PXP_CSC1_COEF1_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC1_COEF1_RSVD1)
+#define BP_PXP_CSC1_COEF1_C1 16
+#define BM_PXP_CSC1_COEF1_C1 0x07FF0000
+#define BF_PXP_CSC1_COEF1_C1(v) \
+ (((v) << 16) & BM_PXP_CSC1_COEF1_C1)
+#define BP_PXP_CSC1_COEF1_RSVD0 11
+#define BM_PXP_CSC1_COEF1_RSVD0 0x0000F800
+#define BF_PXP_CSC1_COEF1_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC1_COEF1_RSVD0)
+#define BP_PXP_CSC1_COEF1_C4 0
+#define BM_PXP_CSC1_COEF1_C4 0x000007FF
+#define BF_PXP_CSC1_COEF1_C4(v) \
+ (((v) << 0) & BM_PXP_CSC1_COEF1_C4)
+
+#define HW_PXP_CSC1_COEF2 (0x000001c0)
+
+#define BP_PXP_CSC1_COEF2_RSVD1 27
+#define BM_PXP_CSC1_COEF2_RSVD1 0xF8000000
+#define BF_PXP_CSC1_COEF2_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC1_COEF2_RSVD1)
+#define BP_PXP_CSC1_COEF2_C2 16
+#define BM_PXP_CSC1_COEF2_C2 0x07FF0000
+#define BF_PXP_CSC1_COEF2_C2(v) \
+ (((v) << 16) & BM_PXP_CSC1_COEF2_C2)
+#define BP_PXP_CSC1_COEF2_RSVD0 11
+#define BM_PXP_CSC1_COEF2_RSVD0 0x0000F800
+#define BF_PXP_CSC1_COEF2_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC1_COEF2_RSVD0)
+#define BP_PXP_CSC1_COEF2_C3 0
+#define BM_PXP_CSC1_COEF2_C3 0x000007FF
+#define BF_PXP_CSC1_COEF2_C3(v) \
+ (((v) << 0) & BM_PXP_CSC1_COEF2_C3)
+
+#define HW_PXP_CSC2_CTRL (0x000001d0)
+
+#define BP_PXP_CSC2_CTRL_RSVD 3
+#define BM_PXP_CSC2_CTRL_RSVD 0xFFFFFFF8
+#define BF_PXP_CSC2_CTRL_RSVD(v) \
+ (((v) << 3) & BM_PXP_CSC2_CTRL_RSVD)
+#define BP_PXP_CSC2_CTRL_CSC_MODE 1
+#define BM_PXP_CSC2_CTRL_CSC_MODE 0x00000006
+#define BF_PXP_CSC2_CTRL_CSC_MODE(v) \
+ (((v) << 1) & BM_PXP_CSC2_CTRL_CSC_MODE)
+#define BV_PXP_CSC2_CTRL_CSC_MODE__YUV2RGB 0x0
+#define BV_PXP_CSC2_CTRL_CSC_MODE__YCbCr2RGB 0x1
+#define BV_PXP_CSC2_CTRL_CSC_MODE__RGB2YUV 0x2
+#define BV_PXP_CSC2_CTRL_CSC_MODE__RGB2YCbCr 0x3
+#define BM_PXP_CSC2_CTRL_BYPASS 0x00000001
+#define BF_PXP_CSC2_CTRL_BYPASS(v) \
+ (((v) << 0) & BM_PXP_CSC2_CTRL_BYPASS)
+
+#define HW_PXP_CSC2_COEF0 (0x000001e0)
+
+#define BP_PXP_CSC2_COEF0_RSVD1 27
+#define BM_PXP_CSC2_COEF0_RSVD1 0xF8000000
+#define BF_PXP_CSC2_COEF0_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC2_COEF0_RSVD1)
+#define BP_PXP_CSC2_COEF0_A2 16
+#define BM_PXP_CSC2_COEF0_A2 0x07FF0000
+#define BF_PXP_CSC2_COEF0_A2(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF0_A2)
+#define BP_PXP_CSC2_COEF0_RSVD0 11
+#define BM_PXP_CSC2_COEF0_RSVD0 0x0000F800
+#define BF_PXP_CSC2_COEF0_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC2_COEF0_RSVD0)
+#define BP_PXP_CSC2_COEF0_A1 0
+#define BM_PXP_CSC2_COEF0_A1 0x000007FF
+#define BF_PXP_CSC2_COEF0_A1(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF0_A1)
+
+#define HW_PXP_CSC2_COEF1 (0x000001f0)
+
+#define BP_PXP_CSC2_COEF1_RSVD1 27
+#define BM_PXP_CSC2_COEF1_RSVD1 0xF8000000
+#define BF_PXP_CSC2_COEF1_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC2_COEF1_RSVD1)
+#define BP_PXP_CSC2_COEF1_B1 16
+#define BM_PXP_CSC2_COEF1_B1 0x07FF0000
+#define BF_PXP_CSC2_COEF1_B1(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF1_B1)
+#define BP_PXP_CSC2_COEF1_RSVD0 11
+#define BM_PXP_CSC2_COEF1_RSVD0 0x0000F800
+#define BF_PXP_CSC2_COEF1_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC2_COEF1_RSVD0)
+#define BP_PXP_CSC2_COEF1_A3 0
+#define BM_PXP_CSC2_COEF1_A3 0x000007FF
+#define BF_PXP_CSC2_COEF1_A3(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF1_A3)
+
+#define HW_PXP_CSC2_COEF2 (0x00000200)
+
+#define BP_PXP_CSC2_COEF2_RSVD1 27
+#define BM_PXP_CSC2_COEF2_RSVD1 0xF8000000
+#define BF_PXP_CSC2_COEF2_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC2_COEF2_RSVD1)
+#define BP_PXP_CSC2_COEF2_B3 16
+#define BM_PXP_CSC2_COEF2_B3 0x07FF0000
+#define BF_PXP_CSC2_COEF2_B3(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF2_B3)
+#define BP_PXP_CSC2_COEF2_RSVD0 11
+#define BM_PXP_CSC2_COEF2_RSVD0 0x0000F800
+#define BF_PXP_CSC2_COEF2_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC2_COEF2_RSVD0)
+#define BP_PXP_CSC2_COEF2_B2 0
+#define BM_PXP_CSC2_COEF2_B2 0x000007FF
+#define BF_PXP_CSC2_COEF2_B2(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF2_B2)
+
+#define HW_PXP_CSC2_COEF3 (0x00000210)
+
+#define BP_PXP_CSC2_COEF3_RSVD1 27
+#define BM_PXP_CSC2_COEF3_RSVD1 0xF8000000
+#define BF_PXP_CSC2_COEF3_RSVD1(v) \
+ (((v) << 27) & BM_PXP_CSC2_COEF3_RSVD1)
+#define BP_PXP_CSC2_COEF3_C2 16
+#define BM_PXP_CSC2_COEF3_C2 0x07FF0000
+#define BF_PXP_CSC2_COEF3_C2(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF3_C2)
+#define BP_PXP_CSC2_COEF3_RSVD0 11
+#define BM_PXP_CSC2_COEF3_RSVD0 0x0000F800
+#define BF_PXP_CSC2_COEF3_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC2_COEF3_RSVD0)
+#define BP_PXP_CSC2_COEF3_C1 0
+#define BM_PXP_CSC2_COEF3_C1 0x000007FF
+#define BF_PXP_CSC2_COEF3_C1(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF3_C1)
+
+#define HW_PXP_CSC2_COEF4 (0x00000220)
+
+#define BP_PXP_CSC2_COEF4_RSVD1 25
+#define BM_PXP_CSC2_COEF4_RSVD1 0xFE000000
+#define BF_PXP_CSC2_COEF4_RSVD1(v) \
+ (((v) << 25) & BM_PXP_CSC2_COEF4_RSVD1)
+#define BP_PXP_CSC2_COEF4_D1 16
+#define BM_PXP_CSC2_COEF4_D1 0x01FF0000
+#define BF_PXP_CSC2_COEF4_D1(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF4_D1)
+#define BP_PXP_CSC2_COEF4_RSVD0 11
+#define BM_PXP_CSC2_COEF4_RSVD0 0x0000F800
+#define BF_PXP_CSC2_COEF4_RSVD0(v) \
+ (((v) << 11) & BM_PXP_CSC2_COEF4_RSVD0)
+#define BP_PXP_CSC2_COEF4_C3 0
+#define BM_PXP_CSC2_COEF4_C3 0x000007FF
+#define BF_PXP_CSC2_COEF4_C3(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF4_C3)
+
+#define HW_PXP_CSC2_COEF5 (0x00000230)
+
+#define BP_PXP_CSC2_COEF5_RSVD1 25
+#define BM_PXP_CSC2_COEF5_RSVD1 0xFE000000
+#define BF_PXP_CSC2_COEF5_RSVD1(v) \
+ (((v) << 25) & BM_PXP_CSC2_COEF5_RSVD1)
+#define BP_PXP_CSC2_COEF5_D3 16
+#define BM_PXP_CSC2_COEF5_D3 0x01FF0000
+#define BF_PXP_CSC2_COEF5_D3(v) \
+ (((v) << 16) & BM_PXP_CSC2_COEF5_D3)
+#define BP_PXP_CSC2_COEF5_RSVD0 9
+#define BM_PXP_CSC2_COEF5_RSVD0 0x0000FE00
+#define BF_PXP_CSC2_COEF5_RSVD0(v) \
+ (((v) << 9) & BM_PXP_CSC2_COEF5_RSVD0)
+#define BP_PXP_CSC2_COEF5_D2 0
+#define BM_PXP_CSC2_COEF5_D2 0x000001FF
+#define BF_PXP_CSC2_COEF5_D2(v) \
+ (((v) << 0) & BM_PXP_CSC2_COEF5_D2)
+
+#define HW_PXP_LUT_CTRL (0x00000240)
+
+#define BM_PXP_LUT_CTRL_BYPASS 0x80000000
+#define BF_PXP_LUT_CTRL_BYPASS(v) \
+ (((v) << 31) & BM_PXP_LUT_CTRL_BYPASS)
+#define BP_PXP_LUT_CTRL_RSVD3 26
+#define BM_PXP_LUT_CTRL_RSVD3 0x7C000000
+#define BF_PXP_LUT_CTRL_RSVD3(v) \
+ (((v) << 26) & BM_PXP_LUT_CTRL_RSVD3)
+#define BP_PXP_LUT_CTRL_LOOKUP_MODE 24
+#define BM_PXP_LUT_CTRL_LOOKUP_MODE 0x03000000
+#define BF_PXP_LUT_CTRL_LOOKUP_MODE(v) \
+ (((v) << 24) & BM_PXP_LUT_CTRL_LOOKUP_MODE)
+#define BV_PXP_LUT_CTRL_LOOKUP_MODE__CACHE_RGB565 0x0
+#define BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_Y8 0x1
+#define BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_RGB444 0x2
+#define BV_PXP_LUT_CTRL_LOOKUP_MODE__DIRECT_RGB454 0x3
+#define BP_PXP_LUT_CTRL_RSVD2 18
+#define BM_PXP_LUT_CTRL_RSVD2 0x00FC0000
+#define BF_PXP_LUT_CTRL_RSVD2(v) \
+ (((v) << 18) & BM_PXP_LUT_CTRL_RSVD2)
+#define BP_PXP_LUT_CTRL_OUT_MODE 16
+#define BM_PXP_LUT_CTRL_OUT_MODE 0x00030000
+#define BF_PXP_LUT_CTRL_OUT_MODE(v) \
+ (((v) << 16) & BM_PXP_LUT_CTRL_OUT_MODE)
+#define BV_PXP_LUT_CTRL_OUT_MODE__RESERVED 0x0
+#define BV_PXP_LUT_CTRL_OUT_MODE__Y8 0x1
+#define BV_PXP_LUT_CTRL_OUT_MODE__RGBW4444CFA 0x2
+#define BV_PXP_LUT_CTRL_OUT_MODE__RGB888 0x3
+#define BP_PXP_LUT_CTRL_RSVD1 11
+#define BM_PXP_LUT_CTRL_RSVD1 0x0000F800
+#define BF_PXP_LUT_CTRL_RSVD1(v) \
+ (((v) << 11) & BM_PXP_LUT_CTRL_RSVD1)
+#define BM_PXP_LUT_CTRL_SEL_8KB 0x00000400
+#define BF_PXP_LUT_CTRL_SEL_8KB(v) \
+ (((v) << 10) & BM_PXP_LUT_CTRL_SEL_8KB)
+#define BM_PXP_LUT_CTRL_LRU_UPD 0x00000200
+#define BF_PXP_LUT_CTRL_LRU_UPD(v) \
+ (((v) << 9) & BM_PXP_LUT_CTRL_LRU_UPD)
+#define BM_PXP_LUT_CTRL_INVALID 0x00000100
+#define BF_PXP_LUT_CTRL_INVALID(v) \
+ (((v) << 8) & BM_PXP_LUT_CTRL_INVALID)
+#define BP_PXP_LUT_CTRL_RSVD0 1
+#define BM_PXP_LUT_CTRL_RSVD0 0x000000FE
+#define BF_PXP_LUT_CTRL_RSVD0(v) \
+ (((v) << 1) & BM_PXP_LUT_CTRL_RSVD0)
+#define BM_PXP_LUT_CTRL_DMA_START 0x00000001
+#define BF_PXP_LUT_CTRL_DMA_START(v) \
+ (((v) << 0) & BM_PXP_LUT_CTRL_DMA_START)
+
+#define HW_PXP_LUT_ADDR (0x00000250)
+
+#define BM_PXP_LUT_ADDR_RSVD2 0x80000000
+#define BF_PXP_LUT_ADDR_RSVD2(v) \
+ (((v) << 31) & BM_PXP_LUT_ADDR_RSVD2)
+#define BP_PXP_LUT_ADDR_NUM_BYTES 16
+#define BM_PXP_LUT_ADDR_NUM_BYTES 0x7FFF0000
+#define BF_PXP_LUT_ADDR_NUM_BYTES(v) \
+ (((v) << 16) & BM_PXP_LUT_ADDR_NUM_BYTES)
+#define BP_PXP_LUT_ADDR_RSVD1 14
+#define BM_PXP_LUT_ADDR_RSVD1 0x0000C000
+#define BF_PXP_LUT_ADDR_RSVD1(v) \
+ (((v) << 14) & BM_PXP_LUT_ADDR_RSVD1)
+#define BP_PXP_LUT_ADDR_ADDR 0
+#define BM_PXP_LUT_ADDR_ADDR 0x00003FFF
+#define BF_PXP_LUT_ADDR_ADDR(v) \
+ (((v) << 0) & BM_PXP_LUT_ADDR_ADDR)
+
+#define HW_PXP_LUT_DATA (0x00000260)
+
+#define BP_PXP_LUT_DATA_DATA 0
+#define BM_PXP_LUT_DATA_DATA 0xFFFFFFFF
+#define BF_PXP_LUT_DATA_DATA(v) (v)
+
+#define HW_PXP_LUT_EXTMEM (0x00000270)
+
+#define BP_PXP_LUT_EXTMEM_ADDR 0
+#define BM_PXP_LUT_EXTMEM_ADDR 0xFFFFFFFF
+#define BF_PXP_LUT_EXTMEM_ADDR(v) (v)
+
+#define HW_PXP_CFA (0x00000280)
+
+#define BP_PXP_CFA_DATA 0
+#define BM_PXP_CFA_DATA 0xFFFFFFFF
+#define BF_PXP_CFA_DATA(v) (v)
+
+#define HW_PXP_ALPHA_A_CTRL (0x00000290)
+
+#define BP_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA 24
+#define BM_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA 0xFF000000
+#define BF_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA(v) \
+ (((v) << 24) & BM_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA)
+#define BP_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA 16
+#define BM_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA 0x00FF0000
+#define BF_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA(v) \
+ (((v) << 16) & BM_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA)
+#define BP_PXP_ALPHA_A_CTRL_RSVD0 14
+#define BM_PXP_ALPHA_A_CTRL_RSVD0 0x0000C000
+#define BF_PXP_ALPHA_A_CTRL_RSVD0(v) \
+ (((v) << 14) & BM_PXP_ALPHA_A_CTRL_RSVD0)
+#define BM_PXP_ALPHA_A_CTRL_S1_COLOR_MODE 0x00002000
+#define BF_PXP_ALPHA_A_CTRL_S1_COLOR_MODE(v) \
+ (((v) << 13) & BM_PXP_ALPHA_A_CTRL_S1_COLOR_MODE)
+#define BV_PXP_ALPHA_A_CTRL_S1_COLOR_MODE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_S1_COLOR_MODE__1 0x1
+#define BM_PXP_ALPHA_A_CTRL_S1_ALPHA_MODE 0x00001000
+#define BF_PXP_ALPHA_A_CTRL_S1_ALPHA_MODE(v) \
+ (((v) << 12) & BM_PXP_ALPHA_A_CTRL_S1_ALPHA_MODE)
+#define BV_PXP_ALPHA_A_CTRL_S1_ALPHA_MODE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_S1_ALPHA_MODE__1 0x1
+#define BP_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE 10
+#define BM_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE 0x00000C00
+#define BF_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE(v) \
+ (((v) << 10) & BM_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE)
+#define BV_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE__1 0x0
+#define BV_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE__2 0x0
+#define BV_PXP_ALPHA_A_CTRL_S1_GLOBAL_ALPHA_MODE__3 0x0
+#define BP_PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE 8
+#define BM_PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE 0x00000300
+#define BF_PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE(v) \
+ (((v) << 8) & BM_PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE)
+#define BV_PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE__1 0x1
+#define BV_PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE__2 0x2
+#define BV_PXP_ALPHA_A_CTRL_S1_S0_FACTOR_MODE__3 0x3
+#define BM_PXP_ALPHA_A_CTRL_RSVD1 0x00000080
+#define BF_PXP_ALPHA_A_CTRL_RSVD1(v) \
+ (((v) << 7) & BM_PXP_ALPHA_A_CTRL_RSVD1)
+#define BM_PXP_ALPHA_A_CTRL_S0_COLOR_MODE 0x00000040
+#define BF_PXP_ALPHA_A_CTRL_S0_COLOR_MODE(v) \
+ (((v) << 6) & BM_PXP_ALPHA_A_CTRL_S0_COLOR_MODE)
+#define BV_PXP_ALPHA_A_CTRL_S0_COLOR_MODE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_S0_COLOR_MODE__1 0x1
+#define BM_PXP_ALPHA_A_CTRL_S0_ALPHA_MODE 0x00000020
+#define BF_PXP_ALPHA_A_CTRL_S0_ALPHA_MODE(v) \
+ (((v) << 5) & BM_PXP_ALPHA_A_CTRL_S0_ALPHA_MODE)
+#define BV_PXP_ALPHA_A_CTRL_S0_ALPHA_MODE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_S0_ALPHA_MODE__1 0x1
+#define BP_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE 3
+#define BM_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE 0x00000018
+#define BF_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE(v) \
+ (((v) << 3) & BM_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE)
+#define BV_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE__1 0x1
+#define BV_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE__2 0x2
+#define BV_PXP_ALPHA_A_CTRL_S0_GLOBAL_ALPHA_MODE__3 0x3
+#define BP_PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE 1
+#define BM_PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE 0x00000006
+#define BF_PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE(v) \
+ (((v) << 1) & BM_PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE)
+#define BV_PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE__1 0x1
+#define BV_PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE__2 0x2
+#define BV_PXP_ALPHA_A_CTRL_S0_S1_FACTOR_MODE__3 0x3
+#define BM_PXP_ALPHA_A_CTRL_POTER_DUFF_ENABLE 0x00000001
+#define BF_PXP_ALPHA_A_CTRL_POTER_DUFF_ENABLE(v) \
+ (((v) << 0) & BM_PXP_ALPHA_A_CTRL_POTER_DUFF_ENABLE)
+#define BV_PXP_ALPHA_A_CTRL_POTER_DUFF_ENABLE__0 0x0
+#define BV_PXP_ALPHA_A_CTRL_POTER_DUFF_ENABLE__1 0x1
+
+#define HW_PXP_ALPHA_B_CTRL (0x000002a0)
+
+#define BP_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA 24
+#define BM_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA 0xFF000000
+#define BF_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA(v) \
+ (((v) << 24) & BM_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA)
+#define BP_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA 16
+#define BM_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA 0x00FF0000
+#define BF_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA(v) \
+ (((v) << 16) & BM_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA)
+#define BP_PXP_ALPHA_B_CTRL_RSVD0 14
+#define BM_PXP_ALPHA_B_CTRL_RSVD0 0x0000C000
+#define BF_PXP_ALPHA_B_CTRL_RSVD0(v) \
+ (((v) << 14) & BM_PXP_ALPHA_B_CTRL_RSVD0)
+#define BM_PXP_ALPHA_B_CTRL_S1_COLOR_MODE 0x00002000
+#define BF_PXP_ALPHA_B_CTRL_S1_COLOR_MODE(v) \
+ (((v) << 13) & BM_PXP_ALPHA_B_CTRL_S1_COLOR_MODE)
+#define BV_PXP_ALPHA_B_CTRL_S1_COLOR_MODE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_S1_COLOR_MODE__1 0x1
+#define BM_PXP_ALPHA_B_CTRL_S1_ALPHA_MODE 0x00001000
+#define BF_PXP_ALPHA_B_CTRL_S1_ALPHA_MODE(v) \
+ (((v) << 12) & BM_PXP_ALPHA_B_CTRL_S1_ALPHA_MODE)
+#define BV_PXP_ALPHA_B_CTRL_S1_ALPHA_MODE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_S1_ALPHA_MODE__1 0x1
+#define BP_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA_MODE 10
+#define BM_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA_MODE 0x00000C00
+#define BF_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA_MODE(v) \
+ (((v) << 10) & BM_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA_MODE)
+#define BV_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA_MODE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA_MODE__1 0x1
+#define BV_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA_MODE__2 0x2
+#define BV_PXP_ALPHA_B_CTRL_S1_GLOBAL_ALPHA_MODE__3 0x3
+#define BP_PXP_ALPHA_B_CTRL_S1_S0_FACTOR_MODE 8
+#define BM_PXP_ALPHA_B_CTRL_S1_S0_FACTOR_MODE 0x00000300
+#define BF_PXP_ALPHA_B_CTRL_S1_S0_FACTOR_MODE(v) \
+ (((v) << 8) & BM_PXP_ALPHA_B_CTRL_S1_S0_FACTOR_MODE)
+#define BV_PXP_ALPHA_B_CTRL_S1_S0_FACTOR_MODE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_S1_S0_FACTOR_MODE__1 0x1
+#define BV_PXP_ALPHA_B_CTRL_S1_S0_FACTOR_MODE__2 0x2
+#define BV_PXP_ALPHA_B_CTRL_S1_S0_FACTOR_MODE__3 0x3
+#define BM_PXP_ALPHA_B_CTRL_RSVD1 0x00000080
+#define BF_PXP_ALPHA_B_CTRL_RSVD1(v) \
+ (((v) << 7) & BM_PXP_ALPHA_B_CTRL_RSVD1)
+#define BM_PXP_ALPHA_B_CTRL_S0_COLOR_MODE 0x00000040
+#define BF_PXP_ALPHA_B_CTRL_S0_COLOR_MODE(v) \
+ (((v) << 6) & BM_PXP_ALPHA_B_CTRL_S0_COLOR_MODE)
+#define BV_PXP_ALPHA_B_CTRL_S0_COLOR_MODE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_S0_COLOR_MODE__1 0x1
+#define BM_PXP_ALPHA_B_CTRL_S0_ALPHA_MODE 0x00000020
+#define BF_PXP_ALPHA_B_CTRL_S0_ALPHA_MODE(v) \
+ (((v) << 5) & BM_PXP_ALPHA_B_CTRL_S0_ALPHA_MODE)
+#define BV_PXP_ALPHA_B_CTRL_S0_ALPHA_MODE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_S0_ALPHA_MODE__1 0x1
+#define BP_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA_MODE 3
+#define BM_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA_MODE 0x00000018
+#define BF_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA_MODE(v) \
+ (((v) << 3) & BM_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA_MODE)
+#define BV_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA_MODE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA_MODE__1 0x1
+#define BV_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA_MODE__2 0x2
+#define BV_PXP_ALPHA_B_CTRL_S0_GLOBAL_ALPHA_MODE__3 0x3
+#define BP_PXP_ALPHA_B_CTRL_S0_S1_FACTOR_MODE 1
+#define BM_PXP_ALPHA_B_CTRL_S0_S1_FACTOR_MODE 0x00000006
+#define BF_PXP_ALPHA_B_CTRL_S0_S1_FACTOR_MODE(v) \
+ (((v) << 1) & BM_PXP_ALPHA_B_CTRL_S0_S1_FACTOR_MODE)
+#define BV_PXP_ALPHA_B_CTRL_S0_S1_FACTOR_MODE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_S0_S1_FACTOR_MODE__1 0x1
+#define BV_PXP_ALPHA_B_CTRL_S0_S1_FACTOR_MODE__2 0x2
+#define BV_PXP_ALPHA_B_CTRL_S0_S1_FACTOR_MODE__3 0x3
+#define BM_PXP_ALPHA_B_CTRL_POTER_DUFF_ENABLE 0x00000001
+#define BF_PXP_ALPHA_B_CTRL_POTER_DUFF_ENABLE(v) \
+ (((v) << 0) & BM_PXP_ALPHA_B_CTRL_POTER_DUFF_ENABLE)
+#define BV_PXP_ALPHA_B_CTRL_POTER_DUFF_ENABLE__0 0x0
+#define BV_PXP_ALPHA_B_CTRL_POTER_DUFF_ENABLE__1 0x1
+
+#define HW_PXP_ALPHA_B_CTRL_1 (0x000002b0)
+
+#define BP_PXP_ALPHA_B_CTRL_1_RSVD0 8
+#define BM_PXP_ALPHA_B_CTRL_1_RSVD0 0xFFFFFF00
+#define BF_PXP_ALPHA_B_CTRL_1_RSVD0(v) \
+ (((v) << 8) & BM_PXP_ALPHA_B_CTRL_1_RSVD0)
+#define BP_PXP_ALPHA_B_CTRL_1_ROP 4
+#define BM_PXP_ALPHA_B_CTRL_1_ROP 0x000000F0
+#define BF_PXP_ALPHA_B_CTRL_1_ROP(v) \
+ (((v) << 4) & BM_PXP_ALPHA_B_CTRL_1_ROP)
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__MASKAS 0x0
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__MASKNOTAS 0x1
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__MASKASNOT 0x2
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__MERGEAS 0x3
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__MERGENOTAS 0x4
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__MERGEASNOT 0x5
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__NOTCOPYAS 0x6
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__NOT 0x7
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__NOTMASKAS 0x8
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__NOTMERGEAS 0x9
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__XORAS 0xA
+#define BV_PXP_ALPHA_B_CTRL_1_ROP__NOTXORAS 0xB
+#define BP_PXP_ALPHA_B_CTRL_1_RSVD1 2
+#define BM_PXP_ALPHA_B_CTRL_1_RSVD1 0x0000000C
+#define BF_PXP_ALPHA_B_CTRL_1_RSVD1(v) \
+ (((v) << 2) & BM_PXP_ALPHA_B_CTRL_1_RSVD1)
+#define BM_PXP_ALPHA_B_CTRL_1_OL_CLRKEY_ENABLE 0x00000002
+#define BF_PXP_ALPHA_B_CTRL_1_OL_CLRKEY_ENABLE(v) \
+ (((v) << 1) & BM_PXP_ALPHA_B_CTRL_1_OL_CLRKEY_ENABLE)
+#define BM_PXP_ALPHA_B_CTRL_1_ROP_ENABLE 0x00000001
+#define BF_PXP_ALPHA_B_CTRL_1_ROP_ENABLE(v) \
+ (((v) << 0) & BM_PXP_ALPHA_B_CTRL_1_ROP_ENABLE)
+
+#define HW_PXP_PS_BACKGROUND_1 (0x000002c0)
+
+#define BP_PXP_PS_BACKGROUND_1_RSVD 24
+#define BM_PXP_PS_BACKGROUND_1_RSVD 0xFF000000
+#define BF_PXP_PS_BACKGROUND_1_RSVD(v) \
+ (((v) << 24) & BM_PXP_PS_BACKGROUND_1_RSVD)
+#define BP_PXP_PS_BACKGROUND_1_COLOR 0
+#define BM_PXP_PS_BACKGROUND_1_COLOR 0x00FFFFFF
+#define BF_PXP_PS_BACKGROUND_1_COLOR(v) \
+ (((v) << 0) & BM_PXP_PS_BACKGROUND_1_COLOR)
+
+#define HW_PXP_PS_CLRKEYLOW_1 (0x000002d0)
+
+#define BP_PXP_PS_CLRKEYLOW_1_RSVD1 24
+#define BM_PXP_PS_CLRKEYLOW_1_RSVD1 0xFF000000
+#define BF_PXP_PS_CLRKEYLOW_1_RSVD1(v) \
+ (((v) << 24) & BM_PXP_PS_CLRKEYLOW_1_RSVD1)
+#define BP_PXP_PS_CLRKEYLOW_1_PIXEL 0
+#define BM_PXP_PS_CLRKEYLOW_1_PIXEL 0x00FFFFFF
+#define BF_PXP_PS_CLRKEYLOW_1_PIXEL(v) \
+ (((v) << 0) & BM_PXP_PS_CLRKEYLOW_1_PIXEL)
+
+#define HW_PXP_PS_CLRKEYHIGH_1 (0x000002e0)
+
+#define BP_PXP_PS_CLRKEYHIGH_1_RSVD1 24
+#define BM_PXP_PS_CLRKEYHIGH_1_RSVD1 0xFF000000
+#define BF_PXP_PS_CLRKEYHIGH_1_RSVD1(v) \
+ (((v) << 24) & BM_PXP_PS_CLRKEYHIGH_1_RSVD1)
+#define BP_PXP_PS_CLRKEYHIGH_1_PIXEL 0
+#define BM_PXP_PS_CLRKEYHIGH_1_PIXEL 0x00FFFFFF
+#define BF_PXP_PS_CLRKEYHIGH_1_PIXEL(v) \
+ (((v) << 0) & BM_PXP_PS_CLRKEYHIGH_1_PIXEL)
+
+#define HW_PXP_AS_CLRKEYLOW_1 (0x000002f0)
+
+#define BP_PXP_AS_CLRKEYLOW_1_RSVD1 24
+#define BM_PXP_AS_CLRKEYLOW_1_RSVD1 0xFF000000
+#define BF_PXP_AS_CLRKEYLOW_1_RSVD1(v) \
+ (((v) << 24) & BM_PXP_AS_CLRKEYLOW_1_RSVD1)
+#define BP_PXP_AS_CLRKEYLOW_1_PIXEL 0
+#define BM_PXP_AS_CLRKEYLOW_1_PIXEL 0x00FFFFFF
+#define BF_PXP_AS_CLRKEYLOW_1_PIXEL(v) \
+ (((v) << 0) & BM_PXP_AS_CLRKEYLOW_1_PIXEL)
+
+#define HW_PXP_AS_CLRKEYHIGH_1 (0x00000300)
+
+#define BP_PXP_AS_CLRKEYHIGH_1_RSVD1 24
+#define BM_PXP_AS_CLRKEYHIGH_1_RSVD1 0xFF000000
+#define BF_PXP_AS_CLRKEYHIGH_1_RSVD1(v) \
+ (((v) << 24) & BM_PXP_AS_CLRKEYHIGH_1_RSVD1)
+#define BP_PXP_AS_CLRKEYHIGH_1_PIXEL 0
+#define BM_PXP_AS_CLRKEYHIGH_1_PIXEL 0x00FFFFFF
+#define BF_PXP_AS_CLRKEYHIGH_1_PIXEL(v) \
+ (((v) << 0) & BM_PXP_AS_CLRKEYHIGH_1_PIXEL)
+
+#define HW_PXP_CTRL2 (0x00000310)
+#define HW_PXP_CTRL2_SET (0x00000314)
+#define HW_PXP_CTRL2_CLR (0x00000318)
+#define HW_PXP_CTRL2_TOG (0x0000031c)
+
+#define BP_PXP_CTRL2_RSVD3 28
+#define BM_PXP_CTRL2_RSVD3 0xF0000000
+#define BF_PXP_CTRL2_RSVD3(v) \
+ (((v) << 28) & BM_PXP_CTRL2_RSVD3)
+#define BM_PXP_CTRL2_ENABLE_ROTATE1 0x08000000
+#define BF_PXP_CTRL2_ENABLE_ROTATE1(v) \
+ (((v) << 27) & BM_PXP_CTRL2_ENABLE_ROTATE1)
+#define BM_PXP_CTRL2_ENABLE_ROTATE0 0x04000000
+#define BF_PXP_CTRL2_ENABLE_ROTATE0(v) \
+ (((v) << 26) & BM_PXP_CTRL2_ENABLE_ROTATE0)
+#define BM_PXP_CTRL2_ENABLE_LUT 0x02000000
+#define BF_PXP_CTRL2_ENABLE_LUT(v) \
+ (((v) << 25) & BM_PXP_CTRL2_ENABLE_LUT)
+#define BM_PXP_CTRL2_ENABLE_CSC2 0x01000000
+#define BF_PXP_CTRL2_ENABLE_CSC2(v) \
+ (((v) << 24) & BM_PXP_CTRL2_ENABLE_CSC2)
+#define BM_PXP_CTRL2_BLOCK_SIZE 0x00800000
+#define BF_PXP_CTRL2_BLOCK_SIZE(v) \
+ (((v) << 23) & BM_PXP_CTRL2_BLOCK_SIZE)
+#define BV_PXP_CTRL2_BLOCK_SIZE__8X8 0x0
+#define BV_PXP_CTRL2_BLOCK_SIZE__16X16 0x1
+#define BM_PXP_CTRL2_RSVD2 0x00400000
+#define BF_PXP_CTRL2_RSVD2(v) \
+ (((v) << 22) & BM_PXP_CTRL2_RSVD2)
+#define BM_PXP_CTRL2_ENABLE_ALPHA_B 0x00200000
+#define BF_PXP_CTRL2_ENABLE_ALPHA_B(v) \
+ (((v) << 21) & BM_PXP_CTRL2_ENABLE_ALPHA_B)
+#define BM_PXP_CTRL2_ENABLE_INPUT_FETCH_STORE 0x00100000
+#define BF_PXP_CTRL2_ENABLE_INPUT_FETCH_STORE(v) \
+ (((v) << 20) & BM_PXP_CTRL2_ENABLE_INPUT_FETCH_STORE)
+#define BM_PXP_CTRL2_ENABLE_WFE_B 0x00080000
+#define BF_PXP_CTRL2_ENABLE_WFE_B(v) \
+ (((v) << 19) & BM_PXP_CTRL2_ENABLE_WFE_B)
+#define BM_PXP_CTRL2_ENABLE_WFE_A 0x00040000
+#define BF_PXP_CTRL2_ENABLE_WFE_A(v) \
+ (((v) << 18) & BM_PXP_CTRL2_ENABLE_WFE_A)
+#define BM_PXP_CTRL2_ENABLE_DITHER 0x00020000
+#define BF_PXP_CTRL2_ENABLE_DITHER(v) \
+ (((v) << 17) & BM_PXP_CTRL2_ENABLE_DITHER)
+#define BM_PXP_CTRL2_RSVD1 0x00010000
+#define BF_PXP_CTRL2_RSVD1(v) \
+ (((v) << 16) & BM_PXP_CTRL2_RSVD1)
+#define BM_PXP_CTRL2_VFLIP1 0x00008000
+#define BF_PXP_CTRL2_VFLIP1(v) \
+ (((v) << 15) & BM_PXP_CTRL2_VFLIP1)
+#define BM_PXP_CTRL2_HFLIP1 0x00004000
+#define BF_PXP_CTRL2_HFLIP1(v) \
+ (((v) << 14) & BM_PXP_CTRL2_HFLIP1)
+#define BP_PXP_CTRL2_ROTATE1 12
+#define BM_PXP_CTRL2_ROTATE1 0x00003000
+#define BF_PXP_CTRL2_ROTATE1(v) \
+ (((v) << 12) & BM_PXP_CTRL2_ROTATE1)
+#define BV_PXP_CTRL2_ROTATE1__ROT_0 0x0
+#define BV_PXP_CTRL2_ROTATE1__ROT_90 0x1
+#define BV_PXP_CTRL2_ROTATE1__ROT_180 0x2
+#define BV_PXP_CTRL2_ROTATE1__ROT_270 0x3
+#define BM_PXP_CTRL2_VFLIP0 0x00000800
+#define BF_PXP_CTRL2_VFLIP0(v) \
+ (((v) << 11) & BM_PXP_CTRL2_VFLIP0)
+#define BM_PXP_CTRL2_HFLIP0 0x00000400
+#define BF_PXP_CTRL2_HFLIP0(v) \
+ (((v) << 10) & BM_PXP_CTRL2_HFLIP0)
+#define BP_PXP_CTRL2_ROTATE0 8
+#define BM_PXP_CTRL2_ROTATE0 0x00000300
+#define BF_PXP_CTRL2_ROTATE0(v) \
+ (((v) << 8) & BM_PXP_CTRL2_ROTATE0)
+#define BV_PXP_CTRL2_ROTATE0__ROT_0 0x0
+#define BV_PXP_CTRL2_ROTATE0__ROT_90 0x1
+#define BV_PXP_CTRL2_ROTATE0__ROT_180 0x2
+#define BV_PXP_CTRL2_ROTATE0__ROT_270 0x3
+#define BP_PXP_CTRL2_RSVD0 1
+#define BM_PXP_CTRL2_RSVD0 0x000000FE
+#define BF_PXP_CTRL2_RSVD0(v) \
+ (((v) << 1) & BM_PXP_CTRL2_RSVD0)
+#define BM_PXP_CTRL2_ENABLE 0x00000001
+#define BF_PXP_CTRL2_ENABLE(v) \
+ (((v) << 0) & BM_PXP_CTRL2_ENABLE)
+
+#define HW_PXP_POWER_REG0 (0x00000320)
+
+#define BP_PXP_POWER_REG0_CTRL 12
+#define BM_PXP_POWER_REG0_CTRL 0xFFFFF000
+#define BF_PXP_POWER_REG0_CTRL(v) \
+ (((v) << 12) & BM_PXP_POWER_REG0_CTRL)
+#define BP_PXP_POWER_REG0_ROT0_MEM_LP_STATE 9
+#define BM_PXP_POWER_REG0_ROT0_MEM_LP_STATE 0x00000E00
+#define BF_PXP_POWER_REG0_ROT0_MEM_LP_STATE(v) \
+ (((v) << 9) & BM_PXP_POWER_REG0_ROT0_MEM_LP_STATE)
+#define BV_PXP_POWER_REG0_ROT0_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG0_ROT0_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG0_ROT0_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG0_ROT0_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_REG0_LUT_LP_STATE_WAY1_BANKN 6
+#define BM_PXP_POWER_REG0_LUT_LP_STATE_WAY1_BANKN 0x000001C0
+#define BF_PXP_POWER_REG0_LUT_LP_STATE_WAY1_BANKN(v) \
+ (((v) << 6) & BM_PXP_POWER_REG0_LUT_LP_STATE_WAY1_BANKN)
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY1_BANKN__NONE 0x0
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY1_BANKN__LS 0x1
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY1_BANKN__DS 0x2
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY1_BANKN__SD 0x4
+#define BP_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANKN 3
+#define BM_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANKN 0x00000038
+#define BF_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANKN(v) \
+ (((v) << 3) & BM_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANKN)
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANKN__NONE 0x0
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANKN__LS 0x1
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANKN__DS 0x2
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANKN__SD 0x4
+#define BP_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANK0 0
+#define BM_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANK0 0x00000007
+#define BF_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANK0(v) \
+ (((v) << 0) & BM_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANK0)
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANK0__NONE 0x0
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANK0__LS 0x1
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANK0__DS 0x2
+#define BV_PXP_POWER_REG0_LUT_LP_STATE_WAY0_BANK0__SD 0x4
+
+#define HW_PXP_POWER_REG1 (0x00000330)
+
+#define BP_PXP_POWER_REG1_RSVD0 24
+#define BM_PXP_POWER_REG1_RSVD0 0xFF000000
+#define BF_PXP_POWER_REG1_RSVD0(v) \
+ (((v) << 24) & BM_PXP_POWER_REG1_RSVD0)
+#define BP_PXP_POWER_REG1_ALU_B_MEM_LP_STATE 21
+#define BM_PXP_POWER_REG1_ALU_B_MEM_LP_STATE 0x00E00000
+#define BF_PXP_POWER_REG1_ALU_B_MEM_LP_STATE(v) \
+ (((v) << 21) & BM_PXP_POWER_REG1_ALU_B_MEM_LP_STATE)
+#define BV_PXP_POWER_REG1_ALU_B_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG1_ALU_B_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG1_ALU_B_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG1_ALU_B_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_REG1_ALU_A_MEM_LP_STATE 18
+#define BM_PXP_POWER_REG1_ALU_A_MEM_LP_STATE 0x001C0000
+#define BF_PXP_POWER_REG1_ALU_A_MEM_LP_STATE(v) \
+ (((v) << 18) & BM_PXP_POWER_REG1_ALU_A_MEM_LP_STATE)
+#define BV_PXP_POWER_REG1_ALU_A_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG1_ALU_A_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG1_ALU_A_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG1_ALU_A_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_REG1_DITH2_LUT_MEM_LP_STATE 15
+#define BM_PXP_POWER_REG1_DITH2_LUT_MEM_LP_STATE 0x00038000
+#define BF_PXP_POWER_REG1_DITH2_LUT_MEM_LP_STATE(v) \
+ (((v) << 15) & BM_PXP_POWER_REG1_DITH2_LUT_MEM_LP_STATE)
+#define BV_PXP_POWER_REG1_DITH2_LUT_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG1_DITH2_LUT_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG1_DITH2_LUT_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG1_DITH2_LUT_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_REG1_DITH1_LUT_MEM_LP_STATE 12
+#define BM_PXP_POWER_REG1_DITH1_LUT_MEM_LP_STATE 0x00007000
+#define BF_PXP_POWER_REG1_DITH1_LUT_MEM_LP_STATE(v) \
+ (((v) << 12) & BM_PXP_POWER_REG1_DITH1_LUT_MEM_LP_STATE)
+#define BV_PXP_POWER_REG1_DITH1_LUT_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG1_DITH1_LUT_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG1_DITH1_LUT_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG1_DITH1_LUT_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_REG1_DITH0_ERR1_MEM_LP_STATE 9
+#define BM_PXP_POWER_REG1_DITH0_ERR1_MEM_LP_STATE 0x00000E00
+#define BF_PXP_POWER_REG1_DITH0_ERR1_MEM_LP_STATE(v) \
+ (((v) << 9) & BM_PXP_POWER_REG1_DITH0_ERR1_MEM_LP_STATE)
+#define BV_PXP_POWER_REG1_DITH0_ERR1_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG1_DITH0_ERR1_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG1_DITH0_ERR1_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG1_DITH0_ERR1_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_REG1_DITH0_ERR0_MEM_LP_STATE 6
+#define BM_PXP_POWER_REG1_DITH0_ERR0_MEM_LP_STATE 0x000001C0
+#define BF_PXP_POWER_REG1_DITH0_ERR0_MEM_LP_STATE(v) \
+ (((v) << 6) & BM_PXP_POWER_REG1_DITH0_ERR0_MEM_LP_STATE)
+#define BV_PXP_POWER_REG1_DITH0_ERR0_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG1_DITH0_ERR0_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG1_DITH0_ERR0_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG1_DITH0_ERR0_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_REG1_DITH0_LUT_MEM_LP_STATE 3
+#define BM_PXP_POWER_REG1_DITH0_LUT_MEM_LP_STATE 0x00000038
+#define BF_PXP_POWER_REG1_DITH0_LUT_MEM_LP_STATE(v) \
+ (((v) << 3) & BM_PXP_POWER_REG1_DITH0_LUT_MEM_LP_STATE)
+#define BV_PXP_POWER_REG1_DITH0_LUT_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG1_DITH0_LUT_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG1_DITH0_LUT_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG1_DITH0_LUT_MEM_LP_STATE__SD 0x4
+#define BP_PXP_POWER_REG1_ROT1_MEM_LP_STATE 0
+#define BM_PXP_POWER_REG1_ROT1_MEM_LP_STATE 0x00000007
+#define BF_PXP_POWER_REG1_ROT1_MEM_LP_STATE(v) \
+ (((v) << 0) & BM_PXP_POWER_REG1_ROT1_MEM_LP_STATE)
+#define BV_PXP_POWER_REG1_ROT1_MEM_LP_STATE__NONE 0x0
+#define BV_PXP_POWER_REG1_ROT1_MEM_LP_STATE__LS 0x1
+#define BV_PXP_POWER_REG1_ROT1_MEM_LP_STATE__DS 0x2
+#define BV_PXP_POWER_REG1_ROT1_MEM_LP_STATE__SD 0x4
+
+#define HW_PXP_DATA_PATH_CTRL0 (0x00000340)
+#define HW_PXP_DATA_PATH_CTRL0_SET (0x00000344)
+#define HW_PXP_DATA_PATH_CTRL0_CLR (0x00000348)
+#define HW_PXP_DATA_PATH_CTRL0_TOG (0x0000034c)
+
+#define BP_PXP_DATA_PATH_CTRL0_MUX15_SEL 30
+#define BM_PXP_DATA_PATH_CTRL0_MUX15_SEL 0xC0000000
+#define BF_PXP_DATA_PATH_CTRL0_MUX15_SEL(v) \
+ (((v) << 30) & BM_PXP_DATA_PATH_CTRL0_MUX15_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX15_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX15_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX15_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX15_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX14_SEL 28
+#define BM_PXP_DATA_PATH_CTRL0_MUX14_SEL 0x30000000
+#define BF_PXP_DATA_PATH_CTRL0_MUX14_SEL(v) \
+ (((v) << 28) & BM_PXP_DATA_PATH_CTRL0_MUX14_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX14_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX14_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX14_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX14_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX13_SEL 26
+#define BM_PXP_DATA_PATH_CTRL0_MUX13_SEL 0x0C000000
+#define BF_PXP_DATA_PATH_CTRL0_MUX13_SEL(v) \
+ (((v) << 26) & BM_PXP_DATA_PATH_CTRL0_MUX13_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX13_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX13_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX13_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX13_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX12_SEL 24
+#define BM_PXP_DATA_PATH_CTRL0_MUX12_SEL 0x03000000
+#define BF_PXP_DATA_PATH_CTRL0_MUX12_SEL(v) \
+ (((v) << 24) & BM_PXP_DATA_PATH_CTRL0_MUX12_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX12_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX12_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX12_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX12_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX11_SEL 22
+#define BM_PXP_DATA_PATH_CTRL0_MUX11_SEL 0x00C00000
+#define BF_PXP_DATA_PATH_CTRL0_MUX11_SEL(v) \
+ (((v) << 22) & BM_PXP_DATA_PATH_CTRL0_MUX11_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX11_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX11_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX11_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX11_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX10_SEL 20
+#define BM_PXP_DATA_PATH_CTRL0_MUX10_SEL 0x00300000
+#define BF_PXP_DATA_PATH_CTRL0_MUX10_SEL(v) \
+ (((v) << 20) & BM_PXP_DATA_PATH_CTRL0_MUX10_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX10_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX10_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX10_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX10_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX9_SEL 18
+#define BM_PXP_DATA_PATH_CTRL0_MUX9_SEL 0x000C0000
+#define BF_PXP_DATA_PATH_CTRL0_MUX9_SEL(v) \
+ (((v) << 18) & BM_PXP_DATA_PATH_CTRL0_MUX9_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX9_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX9_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX9_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX9_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX8_SEL 16
+#define BM_PXP_DATA_PATH_CTRL0_MUX8_SEL 0x00030000
+#define BF_PXP_DATA_PATH_CTRL0_MUX8_SEL(v) \
+ (((v) << 16) & BM_PXP_DATA_PATH_CTRL0_MUX8_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX8_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX8_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX8_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX8_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX7_SEL 14
+#define BM_PXP_DATA_PATH_CTRL0_MUX7_SEL 0x0000C000
+#define BF_PXP_DATA_PATH_CTRL0_MUX7_SEL(v) \
+ (((v) << 14) & BM_PXP_DATA_PATH_CTRL0_MUX7_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX7_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX7_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX7_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX7_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX6_SEL 12
+#define BM_PXP_DATA_PATH_CTRL0_MUX6_SEL 0x00003000
+#define BF_PXP_DATA_PATH_CTRL0_MUX6_SEL(v) \
+ (((v) << 12) & BM_PXP_DATA_PATH_CTRL0_MUX6_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX6_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX6_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX6_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX6_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX5_SEL 10
+#define BM_PXP_DATA_PATH_CTRL0_MUX5_SEL 0x00000C00
+#define BF_PXP_DATA_PATH_CTRL0_MUX5_SEL(v) \
+ (((v) << 10) & BM_PXP_DATA_PATH_CTRL0_MUX5_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX5_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX5_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX5_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX5_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX4_SEL 8
+#define BM_PXP_DATA_PATH_CTRL0_MUX4_SEL 0x00000300
+#define BF_PXP_DATA_PATH_CTRL0_MUX4_SEL(v) \
+ (((v) << 8) & BM_PXP_DATA_PATH_CTRL0_MUX4_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX4_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX4_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX4_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX4_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX3_SEL 6
+#define BM_PXP_DATA_PATH_CTRL0_MUX3_SEL 0x000000C0
+#define BF_PXP_DATA_PATH_CTRL0_MUX3_SEL(v) \
+ (((v) << 6) & BM_PXP_DATA_PATH_CTRL0_MUX3_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX3_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX3_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX3_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX3_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX2_SEL 4
+#define BM_PXP_DATA_PATH_CTRL0_MUX2_SEL 0x00000030
+#define BF_PXP_DATA_PATH_CTRL0_MUX2_SEL(v) \
+ (((v) << 4) & BM_PXP_DATA_PATH_CTRL0_MUX2_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX2_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX2_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX2_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX2_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX1_SEL 2
+#define BM_PXP_DATA_PATH_CTRL0_MUX1_SEL 0x0000000C
+#define BF_PXP_DATA_PATH_CTRL0_MUX1_SEL(v) \
+ (((v) << 2) & BM_PXP_DATA_PATH_CTRL0_MUX1_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX1_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX1_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX1_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX1_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL0_MUX0_SEL 0
+#define BM_PXP_DATA_PATH_CTRL0_MUX0_SEL 0x00000003
+#define BF_PXP_DATA_PATH_CTRL0_MUX0_SEL(v) \
+ (((v) << 0) & BM_PXP_DATA_PATH_CTRL0_MUX0_SEL)
+#define BV_PXP_DATA_PATH_CTRL0_MUX0_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL0_MUX0_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL0_MUX0_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL0_MUX0_SEL__3 0x3
+
+#define HW_PXP_DATA_PATH_CTRL1 (0x00000350)
+#define HW_PXP_DATA_PATH_CTRL1_SET (0x00000354)
+#define HW_PXP_DATA_PATH_CTRL1_CLR (0x00000358)
+#define HW_PXP_DATA_PATH_CTRL1_TOG (0x0000035c)
+
+#define BP_PXP_DATA_PATH_CTRL1_RSVD0 4
+#define BM_PXP_DATA_PATH_CTRL1_RSVD0 0xFFFFFFF0
+#define BF_PXP_DATA_PATH_CTRL1_RSVD0(v) \
+ (((v) << 4) & BM_PXP_DATA_PATH_CTRL1_RSVD0)
+#define BP_PXP_DATA_PATH_CTRL1_MUX17_SEL 2
+#define BM_PXP_DATA_PATH_CTRL1_MUX17_SEL 0x0000000C
+#define BF_PXP_DATA_PATH_CTRL1_MUX17_SEL(v) \
+ (((v) << 2) & BM_PXP_DATA_PATH_CTRL1_MUX17_SEL)
+#define BV_PXP_DATA_PATH_CTRL1_MUX17_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL1_MUX17_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL1_MUX17_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL1_MUX17_SEL__3 0x3
+#define BP_PXP_DATA_PATH_CTRL1_MUX16_SEL 0
+#define BM_PXP_DATA_PATH_CTRL1_MUX16_SEL 0x00000003
+#define BF_PXP_DATA_PATH_CTRL1_MUX16_SEL(v) \
+ (((v) << 0) & BM_PXP_DATA_PATH_CTRL1_MUX16_SEL)
+#define BV_PXP_DATA_PATH_CTRL1_MUX16_SEL__0 0x0
+#define BV_PXP_DATA_PATH_CTRL1_MUX16_SEL__1 0x1
+#define BV_PXP_DATA_PATH_CTRL1_MUX16_SEL__2 0x2
+#define BV_PXP_DATA_PATH_CTRL1_MUX16_SEL__3 0x3
+
+#define HW_PXP_INIT_MEM_CTRL (0x00000360)
+#define HW_PXP_INIT_MEM_CTRL_SET (0x00000364)
+#define HW_PXP_INIT_MEM_CTRL_CLR (0x00000368)
+#define HW_PXP_INIT_MEM_CTRL_TOG (0x0000036c)
+
+#define BM_PXP_INIT_MEM_CTRL_START 0x80000000
+#define BF_PXP_INIT_MEM_CTRL_START(v) \
+ (((v) << 31) & BM_PXP_INIT_MEM_CTRL_START)
+#define BP_PXP_INIT_MEM_CTRL_SELECT 27
+#define BM_PXP_INIT_MEM_CTRL_SELECT 0x78000000
+#define BF_PXP_INIT_MEM_CTRL_SELECT(v) \
+ (((v) << 27) & BM_PXP_INIT_MEM_CTRL_SELECT)
+#define BV_PXP_INIT_MEM_CTRL_SELECT__DITHER0_LUT 0x0
+#define BV_PXP_INIT_MEM_CTRL_SELECT__DITHER0_ERR0 0x1
+#define BV_PXP_INIT_MEM_CTRL_SELECT__DITHER0_ERR1 0x2
+#define BV_PXP_INIT_MEM_CTRL_SELECT__DITHER1_LUT 0x3
+#define BV_PXP_INIT_MEM_CTRL_SELECT__DITHER2_LUT 0x4
+#define BV_PXP_INIT_MEM_CTRL_SELECT__ALU_A 0x5
+#define BV_PXP_INIT_MEM_CTRL_SELECT__ALU_B 0x6
+#define BV_PXP_INIT_MEM_CTRL_SELECT__WFE_A_FETCH 0x7
+#define BV_PXP_INIT_MEM_CTRL_SELECT__WFE_B_FETCH 0x8
+#define BV_PXP_INIT_MEM_CTRL_SELECT__RESERVED 0x15
+#define BP_PXP_INIT_MEM_CTRL_RSVD0 16
+#define BM_PXP_INIT_MEM_CTRL_RSVD0 0x07FF0000
+#define BF_PXP_INIT_MEM_CTRL_RSVD0(v) \
+ (((v) << 16) & BM_PXP_INIT_MEM_CTRL_RSVD0)
+#define BP_PXP_INIT_MEM_CTRL_ADDR 0
+#define BM_PXP_INIT_MEM_CTRL_ADDR 0x0000FFFF
+#define BF_PXP_INIT_MEM_CTRL_ADDR(v) \
+ (((v) << 0) & BM_PXP_INIT_MEM_CTRL_ADDR)
+
+#define HW_PXP_INIT_MEM_DATA (0x00000370)
+
+#define BP_PXP_INIT_MEM_DATA_DATA 0
+#define BM_PXP_INIT_MEM_DATA_DATA 0xFFFFFFFF
+#define BF_PXP_INIT_MEM_DATA_DATA(v) (v)
+
+#define HW_PXP_INIT_MEM_DATA_HIGH (0x00000380)
+
+#define BP_PXP_INIT_MEM_DATA_HIGH_DATA 0
+#define BM_PXP_INIT_MEM_DATA_HIGH_DATA 0xFFFFFFFF
+#define BF_PXP_INIT_MEM_DATA_HIGH_DATA(v) (v)
+
+#define HW_PXP_IRQ_MASK (0x00000390)
+#define HW_PXP_IRQ_MASK_SET (0x00000394)
+#define HW_PXP_IRQ_MASK_CLR (0x00000398)
+#define HW_PXP_IRQ_MASK_TOG (0x0000039c)
+
+#define BM_PXP_IRQ_MASK_COMPRESS_DONE_IRQ_EN 0x80000000
+#define BF_PXP_IRQ_MASK_COMPRESS_DONE_IRQ_EN(v) \
+ (((v) << 31) & BM_PXP_IRQ_MASK_COMPRESS_DONE_IRQ_EN)
+#define BP_PXP_IRQ_MASK_RSVD1 16
+#define BM_PXP_IRQ_MASK_RSVD1 0x7FFF0000
+#define BF_PXP_IRQ_MASK_RSVD1(v) \
+ (((v) << 16) & BM_PXP_IRQ_MASK_RSVD1)
+#define BM_PXP_IRQ_MASK_WFE_B_STORE_IRQ_EN 0x00008000
+#define BF_PXP_IRQ_MASK_WFE_B_STORE_IRQ_EN(v) \
+ (((v) << 15) & BM_PXP_IRQ_MASK_WFE_B_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_WFE_A_STORE_IRQ_EN 0x00004000
+#define BF_PXP_IRQ_MASK_WFE_A_STORE_IRQ_EN(v) \
+ (((v) << 14) & BM_PXP_IRQ_MASK_WFE_A_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_DITHER_STORE_IRQ_EN 0x00002000
+#define BF_PXP_IRQ_MASK_DITHER_STORE_IRQ_EN(v) \
+ (((v) << 13) & BM_PXP_IRQ_MASK_DITHER_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_FIRST_STORE_IRQ_EN 0x00001000
+#define BF_PXP_IRQ_MASK_FIRST_STORE_IRQ_EN(v) \
+ (((v) << 12) & BM_PXP_IRQ_MASK_FIRST_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_WFE_B_CH1_STORE_IRQ_EN 0x00000800
+#define BF_PXP_IRQ_MASK_WFE_B_CH1_STORE_IRQ_EN(v) \
+ (((v) << 11) & BM_PXP_IRQ_MASK_WFE_B_CH1_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_WFE_B_CH0_STORE_IRQ_EN 0x00000400
+#define BF_PXP_IRQ_MASK_WFE_B_CH0_STORE_IRQ_EN(v) \
+ (((v) << 10) & BM_PXP_IRQ_MASK_WFE_B_CH0_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_WFE_A_CH1_STORE_IRQ_EN 0x00000200
+#define BF_PXP_IRQ_MASK_WFE_A_CH1_STORE_IRQ_EN(v) \
+ (((v) << 9) & BM_PXP_IRQ_MASK_WFE_A_CH1_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_WFE_A_CH0_STORE_IRQ_EN 0x00000100
+#define BF_PXP_IRQ_MASK_WFE_A_CH0_STORE_IRQ_EN(v) \
+ (((v) << 8) & BM_PXP_IRQ_MASK_WFE_A_CH0_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_DITHER_CH1_STORE_IRQ_EN 0x00000080
+#define BF_PXP_IRQ_MASK_DITHER_CH1_STORE_IRQ_EN(v) \
+ (((v) << 7) & BM_PXP_IRQ_MASK_DITHER_CH1_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_DITHER_CH0_STORE_IRQ_EN 0x00000040
+#define BF_PXP_IRQ_MASK_DITHER_CH0_STORE_IRQ_EN(v) \
+ (((v) << 6) & BM_PXP_IRQ_MASK_DITHER_CH0_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_DITHER_CH1_PREFETCH_IRQ_EN 0x00000020
+#define BF_PXP_IRQ_MASK_DITHER_CH1_PREFETCH_IRQ_EN(v) \
+ (((v) << 5) & BM_PXP_IRQ_MASK_DITHER_CH1_PREFETCH_IRQ_EN)
+#define BM_PXP_IRQ_MASK_DITHER_CH0_PREFETCH_IRQ_EN 0x00000010
+#define BF_PXP_IRQ_MASK_DITHER_CH0_PREFETCH_IRQ_EN(v) \
+ (((v) << 4) & BM_PXP_IRQ_MASK_DITHER_CH0_PREFETCH_IRQ_EN)
+#define BM_PXP_IRQ_MASK_FIRST_CH1_STORE_IRQ_EN 0x00000008
+#define BF_PXP_IRQ_MASK_FIRST_CH1_STORE_IRQ_EN(v) \
+ (((v) << 3) & BM_PXP_IRQ_MASK_FIRST_CH1_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_FIRST_CH0_STORE_IRQ_EN 0x00000004
+#define BF_PXP_IRQ_MASK_FIRST_CH0_STORE_IRQ_EN(v) \
+ (((v) << 2) & BM_PXP_IRQ_MASK_FIRST_CH0_STORE_IRQ_EN)
+#define BM_PXP_IRQ_MASK_FIRST_CH1_PREFETCH_IRQ_EN 0x00000002
+#define BF_PXP_IRQ_MASK_FIRST_CH1_PREFETCH_IRQ_EN(v) \
+ (((v) << 1) & BM_PXP_IRQ_MASK_FIRST_CH1_PREFETCH_IRQ_EN)
+#define BM_PXP_IRQ_MASK_FIRST_CH0_PREFETCH_IRQ_EN 0x00000001
+#define BF_PXP_IRQ_MASK_FIRST_CH0_PREFETCH_IRQ_EN(v) \
+ (((v) << 0) & BM_PXP_IRQ_MASK_FIRST_CH0_PREFETCH_IRQ_EN)
+
+#define HW_PXP_IRQ (0x000003a0)
+#define HW_PXP_IRQ_SET (0x000003a4)
+#define HW_PXP_IRQ_CLR (0x000003a8)
+#define HW_PXP_IRQ_TOG (0x000003ac)
+
+#define BM_PXP_IRQ_COMPRESS_DONE_IRQ 0x80000000
+#define BF_PXP_IRQ_COMPRESS_DONE_IRQ(v) \
+ (((v) << 31) & BM_PXP_IRQ_COMPRESS_DONE_IRQ)
+#define BP_PXP_IRQ_RSVD1 16
+#define BM_PXP_IRQ_RSVD1 0x7FFF0000
+#define BF_PXP_IRQ_RSVD1(v) \
+ (((v) << 16) & BM_PXP_IRQ_RSVD1)
+#define BM_PXP_IRQ_WFE_B_STORE_IRQ 0x00008000
+#define BF_PXP_IRQ_WFE_B_STORE_IRQ(v) \
+ (((v) << 15) & BM_PXP_IRQ_WFE_B_STORE_IRQ)
+#define BM_PXP_IRQ_WFE_A_STORE_IRQ 0x00004000
+#define BF_PXP_IRQ_WFE_A_STORE_IRQ(v) \
+ (((v) << 14) & BM_PXP_IRQ_WFE_A_STORE_IRQ)
+#define BM_PXP_IRQ_DITHER_STORE_IRQ 0x00002000
+#define BF_PXP_IRQ_DITHER_STORE_IRQ(v) \
+ (((v) << 13) & BM_PXP_IRQ_DITHER_STORE_IRQ)
+#define BM_PXP_IRQ_FIRST_STORE_IRQ 0x00001000
+#define BF_PXP_IRQ_FIRST_STORE_IRQ(v) \
+ (((v) << 12) & BM_PXP_IRQ_FIRST_STORE_IRQ)
+#define BM_PXP_IRQ_WFE_B_CH1_STORE_IRQ 0x00000800
+#define BF_PXP_IRQ_WFE_B_CH1_STORE_IRQ(v) \
+ (((v) << 11) & BM_PXP_IRQ_WFE_B_CH1_STORE_IRQ)
+#define BM_PXP_IRQ_WFE_B_CH0_STORE_IRQ 0x00000400
+#define BF_PXP_IRQ_WFE_B_CH0_STORE_IRQ(v) \
+ (((v) << 10) & BM_PXP_IRQ_WFE_B_CH0_STORE_IRQ)
+#define BM_PXP_IRQ_WFE_A_CH1_STORE_IRQ 0x00000200
+#define BF_PXP_IRQ_WFE_A_CH1_STORE_IRQ(v) \
+ (((v) << 9) & BM_PXP_IRQ_WFE_A_CH1_STORE_IRQ)
+#define BM_PXP_IRQ_WFE_A_CH0_STORE_IRQ 0x00000100
+#define BF_PXP_IRQ_WFE_A_CH0_STORE_IRQ(v) \
+ (((v) << 8) & BM_PXP_IRQ_WFE_A_CH0_STORE_IRQ)
+#define BM_PXP_IRQ_DITHER_CH1_STORE_IRQ 0x00000080
+#define BF_PXP_IRQ_DITHER_CH1_STORE_IRQ(v) \
+ (((v) << 7) & BM_PXP_IRQ_DITHER_CH1_STORE_IRQ)
+#define BM_PXP_IRQ_DITHER_CH0_STORE_IRQ 0x00000040
+#define BF_PXP_IRQ_DITHER_CH0_STORE_IRQ(v) \
+ (((v) << 6) & BM_PXP_IRQ_DITHER_CH0_STORE_IRQ)
+#define BM_PXP_IRQ_DITHER_CH1_PREFETCH_IRQ 0x00000020
+#define BF_PXP_IRQ_DITHER_CH1_PREFETCH_IRQ(v) \
+ (((v) << 5) & BM_PXP_IRQ_DITHER_CH1_PREFETCH_IRQ)
+#define BM_PXP_IRQ_DITHER_CH0_PREFETCH_IRQ 0x00000010
+#define BF_PXP_IRQ_DITHER_CH0_PREFETCH_IRQ(v) \
+ (((v) << 4) & BM_PXP_IRQ_DITHER_CH0_PREFETCH_IRQ)
+#define BM_PXP_IRQ_FIRST_CH1_STORE_IRQ 0x00000008
+#define BF_PXP_IRQ_FIRST_CH1_STORE_IRQ(v) \
+ (((v) << 3) & BM_PXP_IRQ_FIRST_CH1_STORE_IRQ)
+#define BM_PXP_IRQ_FIRST_CH0_STORE_IRQ 0x00000004
+#define BF_PXP_IRQ_FIRST_CH0_STORE_IRQ(v) \
+ (((v) << 2) & BM_PXP_IRQ_FIRST_CH0_STORE_IRQ)
+#define BM_PXP_IRQ_FIRST_CH1_PREFETCH_IRQ 0x00000002
+#define BF_PXP_IRQ_FIRST_CH1_PREFETCH_IRQ(v) \
+ (((v) << 1) & BM_PXP_IRQ_FIRST_CH1_PREFETCH_IRQ)
+#define BM_PXP_IRQ_FIRST_CH0_PREFETCH_IRQ 0x00000001
+#define BF_PXP_IRQ_FIRST_CH0_PREFETCH_IRQ(v) \
+ (((v) << 0) & BM_PXP_IRQ_FIRST_CH0_PREFETCH_IRQ)
+
+#define HW_PXP_NEXT (0x00000400)
+
+#define BP_PXP_NEXT_POINTER 2
+#define BM_PXP_NEXT_POINTER 0xFFFFFFFC
+#define BF_PXP_NEXT_POINTER(v) \
+ (((v) << 2) & BM_PXP_NEXT_POINTER)
+#define BM_PXP_NEXT_RSVD 0x00000002
+#define BF_PXP_NEXT_RSVD(v) \
+ (((v) << 1) & BM_PXP_NEXT_RSVD)
+#define BM_PXP_NEXT_ENABLED 0x00000001
+#define BF_PXP_NEXT_ENABLED(v) \
+ (((v) << 0) & BM_PXP_NEXT_ENABLED)
+
+#define HW_PXP_DEBUGCTRL (0x00000410)
+
+#define BP_PXP_DEBUGCTRL_RSVD 12
+#define BM_PXP_DEBUGCTRL_RSVD 0xFFFFF000
+#define BF_PXP_DEBUGCTRL_RSVD(v) \
+ (((v) << 12) & BM_PXP_DEBUGCTRL_RSVD)
+#define BP_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT 8
+#define BM_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT 0x00000F00
+#define BF_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT(v) \
+ (((v) << 8) & BM_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT)
+#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__NONE 0x0
+#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__MISS_CNT 0x1
+#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__HIT_CNT 0x2
+#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__LAT_CNT 0x4
+#define BV_PXP_DEBUGCTRL_LUT_CLR_STAT_CNT__MAX_LAT 0x8
+#define BP_PXP_DEBUGCTRL_SELECT 0
+#define BM_PXP_DEBUGCTRL_SELECT 0x000000FF
+#define BF_PXP_DEBUGCTRL_SELECT(v) \
+ (((v) << 0) & BM_PXP_DEBUGCTRL_SELECT)
+#define BV_PXP_DEBUGCTRL_SELECT__NONE 0x0
+#define BV_PXP_DEBUGCTRL_SELECT__CTRL 0x1
+#define BV_PXP_DEBUGCTRL_SELECT__PSBUF 0x2
+#define BV_PXP_DEBUGCTRL_SELECT__PSBAX 0x3
+#define BV_PXP_DEBUGCTRL_SELECT__PSBAY 0x4
+#define BV_PXP_DEBUGCTRL_SELECT__ASBUF 0x5
+#define BV_PXP_DEBUGCTRL_SELECT__ROTATION 0x6
+#define BV_PXP_DEBUGCTRL_SELECT__OUTBUF0 0x7
+#define BV_PXP_DEBUGCTRL_SELECT__OUTBUF1 0x8
+#define BV_PXP_DEBUGCTRL_SELECT__OUTBUF2 0x9
+#define BV_PXP_DEBUGCTRL_SELECT__LUT_STAT 0x10
+#define BV_PXP_DEBUGCTRL_SELECT__LUT_MISS 0x11
+#define BV_PXP_DEBUGCTRL_SELECT__LUT_HIT 0x12
+#define BV_PXP_DEBUGCTRL_SELECT__LUT_LAT 0x13
+#define BV_PXP_DEBUGCTRL_SELECT__LUT_MAX_LAT 0x14
+
+#define HW_PXP_DEBUG (0x00000420)
+
+#define BP_PXP_DEBUG_DATA 0
+#define BM_PXP_DEBUG_DATA 0xFFFFFFFF
+#define BF_PXP_DEBUG_DATA(v) (v)
+
+#define HW_PXP_VERSION (0x00000430)
+
+#define BP_PXP_VERSION_MAJOR 24
+#define BM_PXP_VERSION_MAJOR 0xFF000000
+#define BF_PXP_VERSION_MAJOR(v) \
+ (((v) << 24) & BM_PXP_VERSION_MAJOR)
+#define BP_PXP_VERSION_MINOR 16
+#define BM_PXP_VERSION_MINOR 0x00FF0000
+#define BF_PXP_VERSION_MINOR(v) \
+ (((v) << 16) & BM_PXP_VERSION_MINOR)
+#define BP_PXP_VERSION_STEP 0
+#define BM_PXP_VERSION_STEP 0x0000FFFF
+#define BF_PXP_VERSION_STEP(v) \
+ (((v) << 0) & BM_PXP_VERSION_STEP)
+
+#define HW_PXP_INPUT_FETCH_CTRL_CH0 (0x00000450)
+#define HW_PXP_INPUT_FETCH_CTRL_CH0_SET (0x00000454)
+#define HW_PXP_INPUT_FETCH_CTRL_CH0_CLR (0x00000458)
+#define HW_PXP_INPUT_FETCH_CTRL_CH0_TOG (0x0000045c)
+
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_ARBIT_EN 0x80000000
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_ARBIT_EN(v) \
+ (((v) << 31) & BM_PXP_INPUT_FETCH_CTRL_CH0_ARBIT_EN)
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_ARBIT_EN__0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_ARBIT_EN__1 0x1
+#define BP_PXP_INPUT_FETCH_CTRL_CH0_RSVD0 26
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_RSVD0 0x7C000000
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_RSVD0(v) \
+ (((v) << 26) & BM_PXP_INPUT_FETCH_CTRL_CH0_RSVD0)
+#define BP_PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM 24
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM 0x03000000
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM(v) \
+ (((v) << 24) & BM_PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM)
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM__0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM__1 0x1
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM__2 0x2
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM__3 0x3
+#define BP_PXP_INPUT_FETCH_CTRL_CH0_RSVD1 18
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_RSVD1 0x00FC0000
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_RSVD1(v) \
+ (((v) << 18) & BM_PXP_INPUT_FETCH_CTRL_CH0_RSVD1)
+#define BP_PXP_INPUT_FETCH_CTRL_CH0_RD_NUM_BYTES 16
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_RD_NUM_BYTES 0x00030000
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_RD_NUM_BYTES(v) \
+ (((v) << 16) & BM_PXP_INPUT_FETCH_CTRL_CH0_RD_NUM_BYTES)
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_RD_NUM_BYTES__8_bytes 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_RD_NUM_BYTES__16_bytes 0x1
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_RD_NUM_BYTES__32_bytes 0x2
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_RD_NUM_BYTES__64_bytes 0x3
+#define BP_PXP_INPUT_FETCH_CTRL_CH0_RSVD2 14
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_RSVD2 0x0000C000
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_INPUT_FETCH_CTRL_CH0_RSVD2)
+#define BP_PXP_INPUT_FETCH_CTRL_CH0_ROTATION_ANGLE 12
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_ROTATION_ANGLE 0x00003000
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_ROTATION_ANGLE(v) \
+ (((v) << 12) & BM_PXP_INPUT_FETCH_CTRL_CH0_ROTATION_ANGLE)
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_ROTATION_ANGLE__ROT_0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_ROTATION_ANGLE__ROT_90 0x1
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_ROTATION_ANGLE__ROT_180 0x2
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_ROTATION_ANGLE__ROT_270 0x3
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_RSVD3 0x00000800
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_RSVD3(v) \
+ (((v) << 11) & BM_PXP_INPUT_FETCH_CTRL_CH0_RSVD3)
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_VFLIP 0x00000400
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_VFLIP(v) \
+ (((v) << 10) & BM_PXP_INPUT_FETCH_CTRL_CH0_VFLIP)
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_VFLIP__0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_VFLIP__1 0x1
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_HFLIP 0x00000200
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_HFLIP(v) \
+ (((v) << 9) & BM_PXP_INPUT_FETCH_CTRL_CH0_HFLIP)
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_HFLIP__0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_HFLIP__1 0x1
+#define BP_PXP_INPUT_FETCH_CTRL_CH0_RSVD4 6
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_RSVD4 0x000001C0
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_RSVD4(v) \
+ (((v) << 6) & BM_PXP_INPUT_FETCH_CTRL_CH0_RSVD4)
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_HIGH_BYTE 0x00000020
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_HIGH_BYTE(v) \
+ (((v) << 5) & BM_PXP_INPUT_FETCH_CTRL_CH0_HIGH_BYTE)
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_HIGH_BYTE__0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_HIGH_BYTE__1 0x1
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_BYPASS_PIXEL_EN 0x00000010
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_BYPASS_PIXEL_EN(v) \
+ (((v) << 4) & BM_PXP_INPUT_FETCH_CTRL_CH0_BYPASS_PIXEL_EN)
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_BYPASS_PIXEL_EN__0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_BYPASS_PIXEL_EN__1 0x1
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_EN 0x00000008
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_EN(v) \
+ (((v) << 3) & BM_PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_EN)
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_EN__0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_HANDSHAKE_EN__1 0x1
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_BLOCK_16 0x00000004
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_BLOCK_16(v) \
+ (((v) << 2) & BM_PXP_INPUT_FETCH_CTRL_CH0_BLOCK_16)
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_BLOCK_16__8x8 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_BLOCK_16__16x16 0x1
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_BLOCK_EN 0x00000002
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_BLOCK_EN(v) \
+ (((v) << 1) & BM_PXP_INPUT_FETCH_CTRL_CH0_BLOCK_EN)
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_BLOCK_EN__0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_BLOCK_EN__1 0x1
+#define BM_PXP_INPUT_FETCH_CTRL_CH0_CH_EN 0x00000001
+#define BF_PXP_INPUT_FETCH_CTRL_CH0_CH_EN(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_CTRL_CH0_CH_EN)
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_CH_EN__0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH0_CH_EN__1 0x1
+
+#define HW_PXP_INPUT_FETCH_CTRL_CH1 (0x00000460)
+#define HW_PXP_INPUT_FETCH_CTRL_CH1_SET (0x00000464)
+#define HW_PXP_INPUT_FETCH_CTRL_CH1_CLR (0x00000468)
+#define HW_PXP_INPUT_FETCH_CTRL_CH1_TOG (0x0000046c)
+
+#define BP_PXP_INPUT_FETCH_CTRL_CH1_RSVD0 26
+#define BM_PXP_INPUT_FETCH_CTRL_CH1_RSVD0 0xFC000000
+#define BF_PXP_INPUT_FETCH_CTRL_CH1_RSVD0(v) \
+ (((v) << 26) & BM_PXP_INPUT_FETCH_CTRL_CH1_RSVD0)
+#define BP_PXP_INPUT_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM 24
+#define BM_PXP_INPUT_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM 0x03000000
+#define BF_PXP_INPUT_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM(v) \
+ (((v) << 24) & BM_PXP_INPUT_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM)
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM__0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM__1 0x1
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM__2 0x2
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM__3 0x3
+#define BP_PXP_INPUT_FETCH_CTRL_CH1_RSVD1 18
+#define BM_PXP_INPUT_FETCH_CTRL_CH1_RSVD1 0x00FC0000
+#define BF_PXP_INPUT_FETCH_CTRL_CH1_RSVD1(v) \
+ (((v) << 18) & BM_PXP_INPUT_FETCH_CTRL_CH1_RSVD1)
+#define BP_PXP_INPUT_FETCH_CTRL_CH1_RD_NUM_BYTES 16
+#define BM_PXP_INPUT_FETCH_CTRL_CH1_RD_NUM_BYTES 0x00030000
+#define BF_PXP_INPUT_FETCH_CTRL_CH1_RD_NUM_BYTES(v) \
+ (((v) << 16) & BM_PXP_INPUT_FETCH_CTRL_CH1_RD_NUM_BYTES)
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_RD_NUM_BYTES__8_bytes 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_RD_NUM_BYTES__16_bytes 0x1
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_RD_NUM_BYTES__32_bytes 0x2
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_RD_NUM_BYTES__64_bytes 0x3
+#define BP_PXP_INPUT_FETCH_CTRL_CH1_RSVD2 14
+#define BM_PXP_INPUT_FETCH_CTRL_CH1_RSVD2 0x0000C000
+#define BF_PXP_INPUT_FETCH_CTRL_CH1_RSVD2(v) \
+ (((v) << 14) & BM_PXP_INPUT_FETCH_CTRL_CH1_RSVD2)
+#define BP_PXP_INPUT_FETCH_CTRL_CH1_ROTATION_ANGLE 12
+#define BM_PXP_INPUT_FETCH_CTRL_CH1_ROTATION_ANGLE 0x00003000
+#define BF_PXP_INPUT_FETCH_CTRL_CH1_ROTATION_ANGLE(v) \
+ (((v) << 12) & BM_PXP_INPUT_FETCH_CTRL_CH1_ROTATION_ANGLE)
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_ROTATION_ANGLE__ROT_0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_ROTATION_ANGLE__ROT_90 0x1
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_ROTATION_ANGLE__ROT_180 0x2
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_ROTATION_ANGLE__ROT_270 0x3
+#define BM_PXP_INPUT_FETCH_CTRL_CH1_RSVD3 0x00000800
+#define BF_PXP_INPUT_FETCH_CTRL_CH1_RSVD3(v) \
+ (((v) << 11) & BM_PXP_INPUT_FETCH_CTRL_CH1_RSVD3)
+#define BM_PXP_INPUT_FETCH_CTRL_CH1_VFLIP 0x00000400
+#define BF_PXP_INPUT_FETCH_CTRL_CH1_VFLIP(v) \
+ (((v) << 10) & BM_PXP_INPUT_FETCH_CTRL_CH1_VFLIP)
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_VFLIP__0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_VFLIP__1 0x1
+#define BM_PXP_INPUT_FETCH_CTRL_CH1_HFLIP 0x00000200
+#define BF_PXP_INPUT_FETCH_CTRL_CH1_HFLIP(v) \
+ (((v) << 9) & BM_PXP_INPUT_FETCH_CTRL_CH1_HFLIP)
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_HFLIP__0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_HFLIP__1 0x1
+#define BP_PXP_INPUT_FETCH_CTRL_CH1_RSVD4 5
+#define BM_PXP_INPUT_FETCH_CTRL_CH1_RSVD4 0x000001E0
+#define BF_PXP_INPUT_FETCH_CTRL_CH1_RSVD4(v) \
+ (((v) << 5) & BM_PXP_INPUT_FETCH_CTRL_CH1_RSVD4)
+#define BM_PXP_INPUT_FETCH_CTRL_CH1_BYPASS_PIXEL_EN 0x00000010
+#define BF_PXP_INPUT_FETCH_CTRL_CH1_BYPASS_PIXEL_EN(v) \
+ (((v) << 4) & BM_PXP_INPUT_FETCH_CTRL_CH1_BYPASS_PIXEL_EN)
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_BYPASS_PIXEL_EN__0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_BYPASS_PIXEL_EN__1 0x1
+#define BM_PXP_INPUT_FETCH_CTRL_CH1_HANDSHAKE_EN 0x00000008
+#define BF_PXP_INPUT_FETCH_CTRL_CH1_HANDSHAKE_EN(v) \
+ (((v) << 3) & BM_PXP_INPUT_FETCH_CTRL_CH1_HANDSHAKE_EN)
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_HANDSHAKE_EN__0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_HANDSHAKE_EN__1 0x1
+#define BM_PXP_INPUT_FETCH_CTRL_CH1_BLOCK_16 0x00000004
+#define BF_PXP_INPUT_FETCH_CTRL_CH1_BLOCK_16(v) \
+ (((v) << 2) & BM_PXP_INPUT_FETCH_CTRL_CH1_BLOCK_16)
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_BLOCK_16__8x8 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_BLOCK_16__16x16 0x1
+#define BM_PXP_INPUT_FETCH_CTRL_CH1_BLOCK_EN 0x00000002
+#define BF_PXP_INPUT_FETCH_CTRL_CH1_BLOCK_EN(v) \
+ (((v) << 1) & BM_PXP_INPUT_FETCH_CTRL_CH1_BLOCK_EN)
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_BLOCK_EN__0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_BLOCK_EN__1 0x1
+#define BM_PXP_INPUT_FETCH_CTRL_CH1_CH_EN 0x00000001
+#define BF_PXP_INPUT_FETCH_CTRL_CH1_CH_EN(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_CTRL_CH1_CH_EN)
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_CH_EN__0 0x0
+#define BV_PXP_INPUT_FETCH_CTRL_CH1_CH_EN__1 0x1
+
+#define HW_PXP_INPUT_FETCH_STATUS_CH0 (0x00000470)
+
+#define BP_PXP_INPUT_FETCH_STATUS_CH0_PREFETCH_BLOCK_Y 16
+#define BM_PXP_INPUT_FETCH_STATUS_CH0_PREFETCH_BLOCK_Y 0xFFFF0000
+#define BF_PXP_INPUT_FETCH_STATUS_CH0_PREFETCH_BLOCK_Y(v) \
+ (((v) << 16) & BM_PXP_INPUT_FETCH_STATUS_CH0_PREFETCH_BLOCK_Y)
+#define BP_PXP_INPUT_FETCH_STATUS_CH0_PREFETCH_BLOCK_X 0
+#define BM_PXP_INPUT_FETCH_STATUS_CH0_PREFETCH_BLOCK_X 0x0000FFFF
+#define BF_PXP_INPUT_FETCH_STATUS_CH0_PREFETCH_BLOCK_X(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_STATUS_CH0_PREFETCH_BLOCK_X)
+
+#define HW_PXP_INPUT_FETCH_STATUS_CH1 (0x00000480)
+
+#define BP_PXP_INPUT_FETCH_STATUS_CH1_PREFETCH_BLOCK_Y 16
+#define BM_PXP_INPUT_FETCH_STATUS_CH1_PREFETCH_BLOCK_Y 0xFFFF0000
+#define BF_PXP_INPUT_FETCH_STATUS_CH1_PREFETCH_BLOCK_Y(v) \
+ (((v) << 16) & BM_PXP_INPUT_FETCH_STATUS_CH1_PREFETCH_BLOCK_Y)
+#define BP_PXP_INPUT_FETCH_STATUS_CH1_PREFETCH_BLOCK_X 0
+#define BM_PXP_INPUT_FETCH_STATUS_CH1_PREFETCH_BLOCK_X 0x0000FFFF
+#define BF_PXP_INPUT_FETCH_STATUS_CH1_PREFETCH_BLOCK_X(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_STATUS_CH1_PREFETCH_BLOCK_X)
+
+#define HW_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH0 (0x00000490)
+
+#define BP_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_Y 16
+#define BM_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_Y 0xFFFF0000
+#define BF_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_Y(v) \
+ (((v) << 16) & BM_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_Y)
+#define BP_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_X 0
+#define BM_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_X 0x0000FFFF
+#define BF_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_X(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_X)
+
+#define HW_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH0 (0x000004a0)
+
+#define BP_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_Y 16
+#define BM_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_Y 0xFFFF0000
+#define BF_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_Y(v) \
+ (((v) << 16) & BM_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_Y)
+#define BP_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_X 0
+#define BM_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_X 0x0000FFFF
+#define BF_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_X(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_X)
+
+#define HW_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH1 (0x000004b0)
+
+#define BP_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_Y 16
+#define BM_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_Y 0xFFFF0000
+#define BF_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_Y(v) \
+ (((v) << 16) & BM_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_Y)
+#define BP_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_X 0
+#define BM_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_X 0x0000FFFF
+#define BF_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_X(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_X)
+
+#define HW_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH1 (0x000004c0)
+
+#define BP_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_Y 16
+#define BM_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_Y 0xFFFF0000
+#define BF_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_Y(v) \
+ (((v) << 16) & BM_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_Y)
+#define BP_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_X 0
+#define BM_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_X 0x0000FFFF
+#define BF_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_X(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_X)
+
+#define HW_PXP_INPUT_FETCH_SIZE_CH0 (0x000004d0)
+
+#define BP_PXP_INPUT_FETCH_SIZE_CH0_INPUT_TOTAL_HEIGHT 16
+#define BM_PXP_INPUT_FETCH_SIZE_CH0_INPUT_TOTAL_HEIGHT 0xFFFF0000
+#define BF_PXP_INPUT_FETCH_SIZE_CH0_INPUT_TOTAL_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_INPUT_FETCH_SIZE_CH0_INPUT_TOTAL_HEIGHT)
+#define BP_PXP_INPUT_FETCH_SIZE_CH0_INPUT_TOTAL_WIDTH 0
+#define BM_PXP_INPUT_FETCH_SIZE_CH0_INPUT_TOTAL_WIDTH 0x0000FFFF
+#define BF_PXP_INPUT_FETCH_SIZE_CH0_INPUT_TOTAL_WIDTH(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_SIZE_CH0_INPUT_TOTAL_WIDTH)
+
+#define HW_PXP_INPUT_FETCH_SIZE_CH1 (0x000004e0)
+
+#define BP_PXP_INPUT_FETCH_SIZE_CH1_INPUT_TOTAL_HEIGHT 16
+#define BM_PXP_INPUT_FETCH_SIZE_CH1_INPUT_TOTAL_HEIGHT 0xFFFF0000
+#define BF_PXP_INPUT_FETCH_SIZE_CH1_INPUT_TOTAL_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_INPUT_FETCH_SIZE_CH1_INPUT_TOTAL_HEIGHT)
+#define BP_PXP_INPUT_FETCH_SIZE_CH1_INPUT_TOTAL_WIDTH 0
+#define BM_PXP_INPUT_FETCH_SIZE_CH1_INPUT_TOTAL_WIDTH 0x0000FFFF
+#define BF_PXP_INPUT_FETCH_SIZE_CH1_INPUT_TOTAL_WIDTH(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_SIZE_CH1_INPUT_TOTAL_WIDTH)
+
+#define HW_PXP_INPUT_FETCH_BACKGROUND_COLOR_CH0 (0x000004f0)
+
+#define BP_PXP_INPUT_FETCH_BACKGROUND_COLOR_CH0_BACKGROUND_COLOR 0
+#define BM_PXP_INPUT_FETCH_BACKGROUND_COLOR_CH0_BACKGROUND_COLOR 0xFFFFFFFF
+#define BF_PXP_INPUT_FETCH_BACKGROUND_COLOR_CH0_BACKGROUND_COLOR(v) (v)
+
+#define HW_PXP_INPUT_FETCH_BACKGROUND_COLOR_CH1 (0x00000500)
+
+#define BP_PXP_INPUT_FETCH_BACKGROUND_COLOR_CH1_BACKGROUND_COLOR 0
+#define BM_PXP_INPUT_FETCH_BACKGROUND_COLOR_CH1_BACKGROUND_COLOR 0xFFFFFFFF
+#define BF_PXP_INPUT_FETCH_BACKGROUND_COLOR_CH1_BACKGROUND_COLOR(v) (v)
+
+#define HW_PXP_INPUT_FETCH_PITCH (0x00000510)
+
+#define BP_PXP_INPUT_FETCH_PITCH_CH1_INPUT_PITCH 16
+#define BM_PXP_INPUT_FETCH_PITCH_CH1_INPUT_PITCH 0xFFFF0000
+#define BF_PXP_INPUT_FETCH_PITCH_CH1_INPUT_PITCH(v) \
+ (((v) << 16) & BM_PXP_INPUT_FETCH_PITCH_CH1_INPUT_PITCH)
+#define BP_PXP_INPUT_FETCH_PITCH_CH0_INPUT_PITCH 0
+#define BM_PXP_INPUT_FETCH_PITCH_CH0_INPUT_PITCH 0x0000FFFF
+#define BF_PXP_INPUT_FETCH_PITCH_CH0_INPUT_PITCH(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_PITCH_CH0_INPUT_PITCH)
+
+#define HW_PXP_INPUT_FETCH_SHIFT_CTRL_CH0 (0x00000520)
+#define HW_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_SET (0x00000524)
+#define HW_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_CLR (0x00000528)
+#define HW_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_TOG (0x0000052c)
+
+#define BP_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_RSVD0 13
+#define BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_RSVD0 0xFFFFE000
+#define BF_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_RSVD0(v) \
+ (((v) << 13) & BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_RSVD0)
+#define BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_SHIFT_BYPASS 0x00001000
+#define BF_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_SHIFT_BYPASS(v) \
+ (((v) << 12) & BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_SHIFT_BYPASS)
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_SHIFT_BYPASS__0 0x0
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_SHIFT_BYPASS__1 0x1
+#define BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_EN 0x00000800
+#define BF_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_EN(v) \
+ (((v) << 11) & BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_EN)
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_EN__0 0x0
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_EN__1 0x1
+#define BP_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT 8
+#define BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT 0x00000700
+#define BF_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT(v) \
+ (((v) << 8) & BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT)
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT__0 0x0
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT__1 0x1
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT__2 0x2
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT__3 0x3
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT__4 0x4
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT__5 0x5
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT__6 0x6
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT__7 0x7
+#define BP_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_RSVD1 2
+#define BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_RSVD1 0x000000FC
+#define BF_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_RSVD1(v) \
+ (((v) << 2) & BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_RSVD1)
+#define BP_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP 0
+#define BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP 0x00000003
+#define BF_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP)
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP__0 0x0
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP__1 0x1
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP__2 0x2
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP__3 0x3
+
+#define HW_PXP_INPUT_FETCH_SHIFT_CTRL_CH1 (0x00000530)
+#define HW_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_SET (0x00000534)
+#define HW_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_CLR (0x00000538)
+#define HW_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_TOG (0x0000053c)
+
+#define BP_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_RSVD0 13
+#define BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_RSVD0 0xFFFFE000
+#define BF_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_RSVD0(v) \
+ (((v) << 13) & BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_RSVD0)
+#define BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_SHIFT_BYPASS 0x00001000
+#define BF_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_SHIFT_BYPASS(v) \
+ (((v) << 12) & BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_SHIFT_BYPASS)
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_SHIFT_BYPASS__0 0x0
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_SHIFT_BYPASS__1 0x1
+#define BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_EN 0x00000800
+#define BF_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_EN(v) \
+ (((v) << 11) & BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_EN)
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_EN__0 0x0
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_EN__1 0x1
+#define BP_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT 8
+#define BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT 0x00000700
+#define BF_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT(v) \
+ (((v) << 8) & BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT)
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT__0 0x0
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT__1 0x1
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT__2 0x2
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT__3 0x3
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT__4 0x4
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT__5 0x5
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT__6 0x6
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT__7 0x7
+#define BP_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_RSVD1 2
+#define BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_RSVD1 0x000000FC
+#define BF_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_RSVD1(v) \
+ (((v) << 2) & BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_RSVD1)
+#define BP_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP 0
+#define BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP 0x00000003
+#define BF_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP)
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP__0 0x0
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP__1 0x1
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP__2 0x2
+#define BV_PXP_INPUT_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP__3 0x3
+
+#define HW_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0 (0x00000540)
+#define HW_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_SET (0x00000544)
+#define HW_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_CLR (0x00000548)
+#define HW_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_TOG (0x0000054c)
+
+#define BP_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_RSVD0 29
+#define BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_RSVD0 0xE0000000
+#define BF_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_RSVD0(v) \
+ (((v) << 29) & BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_RSVD0)
+#define BP_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_OFFSET3 24
+#define BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_OFFSET3 0x1F000000
+#define BF_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_OFFSET3(v) \
+ (((v) << 24) & BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_OFFSET3)
+#define BP_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_RSVD1 21
+#define BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_RSVD1 0x00E00000
+#define BF_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_RSVD1(v) \
+ (((v) << 21) & BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_RSVD1)
+#define BP_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_OFFSET2 16
+#define BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_OFFSET2 0x001F0000
+#define BF_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_OFFSET2(v) \
+ (((v) << 16) & BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_OFFSET2)
+#define BP_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_RSVD2 13
+#define BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_RSVD2 0x0000E000
+#define BF_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_RSVD2(v) \
+ (((v) << 13) & BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_RSVD2)
+#define BP_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_OFFSET1 8
+#define BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_OFFSET1 0x00001F00
+#define BF_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_OFFSET1(v) \
+ (((v) << 8) & BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_OFFSET1)
+#define BP_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_RSVD3 5
+#define BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_RSVD3 0x000000E0
+#define BF_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_RSVD3(v) \
+ (((v) << 5) & BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_RSVD3)
+#define BP_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_OFFSET0 0
+#define BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_OFFSET0 0x0000001F
+#define BF_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_OFFSET0(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH0_OFFSET0)
+
+#define HW_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1 (0x00000550)
+#define HW_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_SET (0x00000554)
+#define HW_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_CLR (0x00000558)
+#define HW_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_TOG (0x0000055c)
+
+#define BP_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_RSVD0 29
+#define BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_RSVD0 0xE0000000
+#define BF_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_RSVD0(v) \
+ (((v) << 29) & BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_RSVD0)
+#define BP_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_OFFSET3 24
+#define BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_OFFSET3 0x1F000000
+#define BF_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_OFFSET3(v) \
+ (((v) << 24) & BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_OFFSET3)
+#define BP_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_RSVD1 21
+#define BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_RSVD1 0x00E00000
+#define BF_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_RSVD1(v) \
+ (((v) << 21) & BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_RSVD1)
+#define BP_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_OFFSET2 16
+#define BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_OFFSET2 0x001F0000
+#define BF_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_OFFSET2(v) \
+ (((v) << 16) & BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_OFFSET2)
+#define BP_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_RSVD2 13
+#define BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_RSVD2 0x0000E000
+#define BF_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_RSVD2(v) \
+ (((v) << 13) & BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_RSVD2)
+#define BP_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_OFFSET1 8
+#define BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_OFFSET1 0x00001F00
+#define BF_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_OFFSET1(v) \
+ (((v) << 8) & BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_OFFSET1)
+#define BP_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_RSVD3 5
+#define BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_RSVD3 0x000000E0
+#define BF_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_RSVD3(v) \
+ (((v) << 5) & BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_RSVD3)
+#define BP_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_OFFSET0 0
+#define BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_OFFSET0 0x0000001F
+#define BF_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_OFFSET0(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_SHIFT_OFFSET_CH1_OFFSET0)
+
+#define HW_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0 (0x00000560)
+#define HW_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_SET (0x00000564)
+#define HW_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_CLR (0x00000568)
+#define HW_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_TOG (0x0000056c)
+
+#define BP_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_RSVD0 16
+#define BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_RSVD0 0xFFFF0000
+#define BF_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_RSVD0(v) \
+ (((v) << 16) & BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_RSVD0)
+#define BP_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_WIDTH3 12
+#define BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_WIDTH3 0x0000F000
+#define BF_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_WIDTH3(v) \
+ (((v) << 12) & BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_WIDTH3)
+#define BP_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_WIDTH2 8
+#define BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_WIDTH2 0x00000F00
+#define BF_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_WIDTH2(v) \
+ (((v) << 8) & BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_WIDTH2)
+#define BP_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_WIDTH1 4
+#define BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_WIDTH1 0x000000F0
+#define BF_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_WIDTH1(v) \
+ (((v) << 4) & BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_WIDTH1)
+#define BP_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_WIDTH0 0
+#define BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_WIDTH0 0x0000000F
+#define BF_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_WIDTH0(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH0_WIDTH0)
+
+#define HW_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1 (0x00000570)
+#define HW_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_SET (0x00000574)
+#define HW_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_CLR (0x00000578)
+#define HW_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_TOG (0x0000057c)
+
+#define BP_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_RSVD0 16
+#define BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_RSVD0 0xFFFF0000
+#define BF_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_RSVD0(v) \
+ (((v) << 16) & BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_RSVD0)
+#define BP_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_WIDTH3 12
+#define BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_WIDTH3 0x0000F000
+#define BF_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_WIDTH3(v) \
+ (((v) << 12) & BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_WIDTH3)
+#define BP_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_WIDTH2 8
+#define BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_WIDTH2 0x00000F00
+#define BF_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_WIDTH2(v) \
+ (((v) << 8) & BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_WIDTH2)
+#define BP_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_WIDTH1 4
+#define BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_WIDTH1 0x000000F0
+#define BF_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_WIDTH1(v) \
+ (((v) << 4) & BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_WIDTH1)
+#define BP_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_WIDTH0 0
+#define BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_WIDTH0 0x0000000F
+#define BF_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_WIDTH0(v) \
+ (((v) << 0) & BM_PXP_INPUT_FETCH_SHIFT_WIDTH_CH1_WIDTH0)
+
+#define HW_PXP_INPUT_FETCH_ADDR_0_CH0 (0x00000580)
+
+#define BP_PXP_INPUT_FETCH_ADDR_0_CH0_INPUT_BASE_ADDR0 0
+#define BM_PXP_INPUT_FETCH_ADDR_0_CH0_INPUT_BASE_ADDR0 0xFFFFFFFF
+#define BF_PXP_INPUT_FETCH_ADDR_0_CH0_INPUT_BASE_ADDR0(v) (v)
+
+#define HW_PXP_INPUT_FETCH_ADDR_1_CH0 (0x00000590)
+
+#define BP_PXP_INPUT_FETCH_ADDR_1_CH0_INPUT_BASE_ADDR1 0
+#define BM_PXP_INPUT_FETCH_ADDR_1_CH0_INPUT_BASE_ADDR1 0xFFFFFFFF
+#define BF_PXP_INPUT_FETCH_ADDR_1_CH0_INPUT_BASE_ADDR1(v) (v)
+
+#define HW_PXP_INPUT_FETCH_ADDR_0_CH1 (0x000005a0)
+
+#define BP_PXP_INPUT_FETCH_ADDR_0_CH1_INPUT_BASE_ADDR0 0
+#define BM_PXP_INPUT_FETCH_ADDR_0_CH1_INPUT_BASE_ADDR0 0xFFFFFFFF
+#define BF_PXP_INPUT_FETCH_ADDR_0_CH1_INPUT_BASE_ADDR0(v) (v)
+
+#define HW_PXP_INPUT_FETCH_ADDR_1_CH1 (0x000005b0)
+
+#define BP_PXP_INPUT_FETCH_ADDR_1_CH1_INPUT_BASE_ADDR1 0
+#define BM_PXP_INPUT_FETCH_ADDR_1_CH1_INPUT_BASE_ADDR1 0xFFFFFFFF
+#define BF_PXP_INPUT_FETCH_ADDR_1_CH1_INPUT_BASE_ADDR1(v) (v)
+
+#define HW_PXP_INPUT_STORE_CTRL_CH0 (0x000005c0)
+#define HW_PXP_INPUT_STORE_CTRL_CH0_SET (0x000005c4)
+#define HW_PXP_INPUT_STORE_CTRL_CH0_CLR (0x000005c8)
+#define HW_PXP_INPUT_STORE_CTRL_CH0_TOG (0x000005cc)
+
+#define BM_PXP_INPUT_STORE_CTRL_CH0_ARBIT_EN 0x80000000
+#define BF_PXP_INPUT_STORE_CTRL_CH0_ARBIT_EN(v) \
+ (((v) << 31) & BM_PXP_INPUT_STORE_CTRL_CH0_ARBIT_EN)
+#define BV_PXP_INPUT_STORE_CTRL_CH0_ARBIT_EN__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH0_ARBIT_EN__1 0x1
+#define BP_PXP_INPUT_STORE_CTRL_CH0_RSVD0 25
+#define BM_PXP_INPUT_STORE_CTRL_CH0_RSVD0 0x7E000000
+#define BF_PXP_INPUT_STORE_CTRL_CH0_RSVD0(v) \
+ (((v) << 25) & BM_PXP_INPUT_STORE_CTRL_CH0_RSVD0)
+#define BM_PXP_INPUT_STORE_CTRL_CH0_COMBINE_2CHANNEL 0x01000000
+#define BF_PXP_INPUT_STORE_CTRL_CH0_COMBINE_2CHANNEL(v) \
+ (((v) << 24) & BM_PXP_INPUT_STORE_CTRL_CH0_COMBINE_2CHANNEL)
+#define BV_PXP_INPUT_STORE_CTRL_CH0_COMBINE_2CHANNEL__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH0_COMBINE_2CHANNEL__1 0x1
+#define BP_PXP_INPUT_STORE_CTRL_CH0_RSVD1 18
+#define BM_PXP_INPUT_STORE_CTRL_CH0_RSVD1 0x00FC0000
+#define BF_PXP_INPUT_STORE_CTRL_CH0_RSVD1(v) \
+ (((v) << 18) & BM_PXP_INPUT_STORE_CTRL_CH0_RSVD1)
+#define BP_PXP_INPUT_STORE_CTRL_CH0_WR_NUM_BYTES 16
+#define BM_PXP_INPUT_STORE_CTRL_CH0_WR_NUM_BYTES 0x00030000
+#define BF_PXP_INPUT_STORE_CTRL_CH0_WR_NUM_BYTES(v) \
+ (((v) << 16) & BM_PXP_INPUT_STORE_CTRL_CH0_WR_NUM_BYTES)
+#define BV_PXP_INPUT_STORE_CTRL_CH0_WR_NUM_BYTES__8_bytes 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH0_WR_NUM_BYTES__16_bytes 0x1
+#define BV_PXP_INPUT_STORE_CTRL_CH0_WR_NUM_BYTES__32_bytes 0x2
+#define BV_PXP_INPUT_STORE_CTRL_CH0_WR_NUM_BYTES__64_bytes 0x3
+#define BP_PXP_INPUT_STORE_CTRL_CH0_RSVD2 12
+#define BM_PXP_INPUT_STORE_CTRL_CH0_RSVD2 0x0000F000
+#define BF_PXP_INPUT_STORE_CTRL_CH0_RSVD2(v) \
+ (((v) << 12) & BM_PXP_INPUT_STORE_CTRL_CH0_RSVD2)
+#define BM_PXP_INPUT_STORE_CTRL_CH0_FILL_DATA_EN 0x00000800
+#define BF_PXP_INPUT_STORE_CTRL_CH0_FILL_DATA_EN(v) \
+ (((v) << 11) & BM_PXP_INPUT_STORE_CTRL_CH0_FILL_DATA_EN)
+#define BV_PXP_INPUT_STORE_CTRL_CH0_FILL_DATA_EN__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH0_FILL_DATA_EN__1 0x1
+#define BM_PXP_INPUT_STORE_CTRL_CH0_PACK_IN_SEL 0x00000400
+#define BF_PXP_INPUT_STORE_CTRL_CH0_PACK_IN_SEL(v) \
+ (((v) << 10) & BM_PXP_INPUT_STORE_CTRL_CH0_PACK_IN_SEL)
+#define BV_PXP_INPUT_STORE_CTRL_CH0_PACK_IN_SEL__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH0_PACK_IN_SEL__1 0x1
+#define BM_PXP_INPUT_STORE_CTRL_CH0_STORE_MEMORY_EN 0x00000200
+#define BF_PXP_INPUT_STORE_CTRL_CH0_STORE_MEMORY_EN(v) \
+ (((v) << 9) & BM_PXP_INPUT_STORE_CTRL_CH0_STORE_MEMORY_EN)
+#define BV_PXP_INPUT_STORE_CTRL_CH0_STORE_MEMORY_EN__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH0_STORE_MEMORY_EN__1 0x1
+#define BM_PXP_INPUT_STORE_CTRL_CH0_STORE_BYPASS_EN 0x00000100
+#define BF_PXP_INPUT_STORE_CTRL_CH0_STORE_BYPASS_EN(v) \
+ (((v) << 8) & BM_PXP_INPUT_STORE_CTRL_CH0_STORE_BYPASS_EN)
+#define BV_PXP_INPUT_STORE_CTRL_CH0_STORE_BYPASS_EN__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH0_STORE_BYPASS_EN__1 0x1
+#define BM_PXP_INPUT_STORE_CTRL_CH0_RSVD3 0x00000080
+#define BF_PXP_INPUT_STORE_CTRL_CH0_RSVD3(v) \
+ (((v) << 7) & BM_PXP_INPUT_STORE_CTRL_CH0_RSVD3)
+#define BP_PXP_INPUT_STORE_CTRL_CH0_ARRAY_LINE_NUM 5
+#define BM_PXP_INPUT_STORE_CTRL_CH0_ARRAY_LINE_NUM 0x00000060
+#define BF_PXP_INPUT_STORE_CTRL_CH0_ARRAY_LINE_NUM(v) \
+ (((v) << 5) & BM_PXP_INPUT_STORE_CTRL_CH0_ARRAY_LINE_NUM)
+#define BV_PXP_INPUT_STORE_CTRL_CH0_ARRAY_LINE_NUM__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH0_ARRAY_LINE_NUM__1 0x1
+#define BV_PXP_INPUT_STORE_CTRL_CH0_ARRAY_LINE_NUM__2 0x2
+#define BV_PXP_INPUT_STORE_CTRL_CH0_ARRAY_LINE_NUM__3 0x3
+#define BM_PXP_INPUT_STORE_CTRL_CH0_ARRAY_EN 0x00000010
+#define BF_PXP_INPUT_STORE_CTRL_CH0_ARRAY_EN(v) \
+ (((v) << 4) & BM_PXP_INPUT_STORE_CTRL_CH0_ARRAY_EN)
+#define BV_PXP_INPUT_STORE_CTRL_CH0_ARRAY_EN__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH0_ARRAY_EN__1 0x1
+#define BM_PXP_INPUT_STORE_CTRL_CH0_HANDSHAKE_EN 0x00000008
+#define BF_PXP_INPUT_STORE_CTRL_CH0_HANDSHAKE_EN(v) \
+ (((v) << 3) & BM_PXP_INPUT_STORE_CTRL_CH0_HANDSHAKE_EN)
+#define BV_PXP_INPUT_STORE_CTRL_CH0_HANDSHAKE_EN__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH0_HANDSHAKE_EN__1 0x1
+#define BM_PXP_INPUT_STORE_CTRL_CH0_BLOCK_16 0x00000004
+#define BF_PXP_INPUT_STORE_CTRL_CH0_BLOCK_16(v) \
+ (((v) << 2) & BM_PXP_INPUT_STORE_CTRL_CH0_BLOCK_16)
+#define BV_PXP_INPUT_STORE_CTRL_CH0_BLOCK_16__8x8 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH0_BLOCK_16__16x16 0x1
+#define BM_PXP_INPUT_STORE_CTRL_CH0_BLOCK_EN 0x00000002
+#define BF_PXP_INPUT_STORE_CTRL_CH0_BLOCK_EN(v) \
+ (((v) << 1) & BM_PXP_INPUT_STORE_CTRL_CH0_BLOCK_EN)
+#define BV_PXP_INPUT_STORE_CTRL_CH0_BLOCK_EN__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH0_BLOCK_EN__1 0x1
+#define BM_PXP_INPUT_STORE_CTRL_CH0_CH_EN 0x00000001
+#define BF_PXP_INPUT_STORE_CTRL_CH0_CH_EN(v) \
+ (((v) << 0) & BM_PXP_INPUT_STORE_CTRL_CH0_CH_EN)
+#define BV_PXP_INPUT_STORE_CTRL_CH0_CH_EN__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH0_CH_EN__1 0x1
+
+#define HW_PXP_INPUT_STORE_CTRL_CH1 (0x000005d0)
+#define HW_PXP_INPUT_STORE_CTRL_CH1_SET (0x000005d4)
+#define HW_PXP_INPUT_STORE_CTRL_CH1_CLR (0x000005d8)
+#define HW_PXP_INPUT_STORE_CTRL_CH1_TOG (0x000005dc)
+
+#define BP_PXP_INPUT_STORE_CTRL_CH1_RSVD0 18
+#define BM_PXP_INPUT_STORE_CTRL_CH1_RSVD0 0xFFFC0000
+#define BF_PXP_INPUT_STORE_CTRL_CH1_RSVD0(v) \
+ (((v) << 18) & BM_PXP_INPUT_STORE_CTRL_CH1_RSVD0)
+#define BP_PXP_INPUT_STORE_CTRL_CH1_WR_NUM_BYTES 16
+#define BM_PXP_INPUT_STORE_CTRL_CH1_WR_NUM_BYTES 0x00030000
+#define BF_PXP_INPUT_STORE_CTRL_CH1_WR_NUM_BYTES(v) \
+ (((v) << 16) & BM_PXP_INPUT_STORE_CTRL_CH1_WR_NUM_BYTES)
+#define BV_PXP_INPUT_STORE_CTRL_CH1_WR_NUM_BYTES__8_bytes 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH1_WR_NUM_BYTES__16_bytes 0x1
+#define BV_PXP_INPUT_STORE_CTRL_CH1_WR_NUM_BYTES__32_bytes 0x2
+#define BV_PXP_INPUT_STORE_CTRL_CH1_WR_NUM_BYTES__64_bytes 0x3
+#define BP_PXP_INPUT_STORE_CTRL_CH1_RSVD1 11
+#define BM_PXP_INPUT_STORE_CTRL_CH1_RSVD1 0x0000F800
+#define BF_PXP_INPUT_STORE_CTRL_CH1_RSVD1(v) \
+ (((v) << 11) & BM_PXP_INPUT_STORE_CTRL_CH1_RSVD1)
+#define BM_PXP_INPUT_STORE_CTRL_CH1_PACK_IN_SEL 0x00000400
+#define BF_PXP_INPUT_STORE_CTRL_CH1_PACK_IN_SEL(v) \
+ (((v) << 10) & BM_PXP_INPUT_STORE_CTRL_CH1_PACK_IN_SEL)
+#define BV_PXP_INPUT_STORE_CTRL_CH1_PACK_IN_SEL__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH1_PACK_IN_SEL__1 0x1
+#define BM_PXP_INPUT_STORE_CTRL_CH1_STORE_MEMORY_EN 0x00000200
+#define BF_PXP_INPUT_STORE_CTRL_CH1_STORE_MEMORY_EN(v) \
+ (((v) << 9) & BM_PXP_INPUT_STORE_CTRL_CH1_STORE_MEMORY_EN)
+#define BV_PXP_INPUT_STORE_CTRL_CH1_STORE_MEMORY_EN__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH1_STORE_MEMORY_EN__1 0x1
+#define BM_PXP_INPUT_STORE_CTRL_CH1_STORE_BYPASS_EN 0x00000100
+#define BF_PXP_INPUT_STORE_CTRL_CH1_STORE_BYPASS_EN(v) \
+ (((v) << 8) & BM_PXP_INPUT_STORE_CTRL_CH1_STORE_BYPASS_EN)
+#define BV_PXP_INPUT_STORE_CTRL_CH1_STORE_BYPASS_EN__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH1_STORE_BYPASS_EN__1 0x1
+#define BM_PXP_INPUT_STORE_CTRL_CH1_RSVD3 0x00000080
+#define BF_PXP_INPUT_STORE_CTRL_CH1_RSVD3(v) \
+ (((v) << 7) & BM_PXP_INPUT_STORE_CTRL_CH1_RSVD3)
+#define BP_PXP_INPUT_STORE_CTRL_CH1_ARRAY_LINE_NUM 5
+#define BM_PXP_INPUT_STORE_CTRL_CH1_ARRAY_LINE_NUM 0x00000060
+#define BF_PXP_INPUT_STORE_CTRL_CH1_ARRAY_LINE_NUM(v) \
+ (((v) << 5) & BM_PXP_INPUT_STORE_CTRL_CH1_ARRAY_LINE_NUM)
+#define BV_PXP_INPUT_STORE_CTRL_CH1_ARRAY_LINE_NUM__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH1_ARRAY_LINE_NUM__1 0x1
+#define BV_PXP_INPUT_STORE_CTRL_CH1_ARRAY_LINE_NUM__2 0x2
+#define BV_PXP_INPUT_STORE_CTRL_CH1_ARRAY_LINE_NUM__3 0x3
+#define BM_PXP_INPUT_STORE_CTRL_CH1_ARRAY_EN 0x00000010
+#define BF_PXP_INPUT_STORE_CTRL_CH1_ARRAY_EN(v) \
+ (((v) << 4) & BM_PXP_INPUT_STORE_CTRL_CH1_ARRAY_EN)
+#define BV_PXP_INPUT_STORE_CTRL_CH1_ARRAY_EN__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH1_ARRAY_EN__1 0x1
+#define BM_PXP_INPUT_STORE_CTRL_CH1_HANDSHAKE_EN 0x00000008
+#define BF_PXP_INPUT_STORE_CTRL_CH1_HANDSHAKE_EN(v) \
+ (((v) << 3) & BM_PXP_INPUT_STORE_CTRL_CH1_HANDSHAKE_EN)
+#define BV_PXP_INPUT_STORE_CTRL_CH1_HANDSHAKE_EN__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH1_HANDSHAKE_EN__1 0x1
+#define BM_PXP_INPUT_STORE_CTRL_CH1_BLOCK_16 0x00000004
+#define BF_PXP_INPUT_STORE_CTRL_CH1_BLOCK_16(v) \
+ (((v) << 2) & BM_PXP_INPUT_STORE_CTRL_CH1_BLOCK_16)
+#define BV_PXP_INPUT_STORE_CTRL_CH1_BLOCK_16__8x8 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH1_BLOCK_16__16x16 0x1
+#define BM_PXP_INPUT_STORE_CTRL_CH1_BLOCK_EN 0x00000002
+#define BF_PXP_INPUT_STORE_CTRL_CH1_BLOCK_EN(v) \
+ (((v) << 1) & BM_PXP_INPUT_STORE_CTRL_CH1_BLOCK_EN)
+#define BV_PXP_INPUT_STORE_CTRL_CH1_BLOCK_EN__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH1_BLOCK_EN__1 0x1
+#define BM_PXP_INPUT_STORE_CTRL_CH1_CH_EN 0x00000001
+#define BF_PXP_INPUT_STORE_CTRL_CH1_CH_EN(v) \
+ (((v) << 0) & BM_PXP_INPUT_STORE_CTRL_CH1_CH_EN)
+#define BV_PXP_INPUT_STORE_CTRL_CH1_CH_EN__0 0x0
+#define BV_PXP_INPUT_STORE_CTRL_CH1_CH_EN__1 0x1
+
+#define HW_PXP_INPUT_STORE_STATUS_CH0 (0x000005e0)
+
+#define BP_PXP_INPUT_STORE_STATUS_CH0_STORE_BLOCK_Y 16
+#define BM_PXP_INPUT_STORE_STATUS_CH0_STORE_BLOCK_Y 0xFFFF0000
+#define BF_PXP_INPUT_STORE_STATUS_CH0_STORE_BLOCK_Y(v) \
+ (((v) << 16) & BM_PXP_INPUT_STORE_STATUS_CH0_STORE_BLOCK_Y)
+#define BP_PXP_INPUT_STORE_STATUS_CH0_STORE_BLOCK_X 0
+#define BM_PXP_INPUT_STORE_STATUS_CH0_STORE_BLOCK_X 0x0000FFFF
+#define BF_PXP_INPUT_STORE_STATUS_CH0_STORE_BLOCK_X(v) \
+ (((v) << 0) & BM_PXP_INPUT_STORE_STATUS_CH0_STORE_BLOCK_X)
+
+#define HW_PXP_INPUT_STORE_STATUS_CH1 (0x000005f0)
+
+#define BP_PXP_INPUT_STORE_STATUS_CH1_STORE_BLOCK_Y 16
+#define BM_PXP_INPUT_STORE_STATUS_CH1_STORE_BLOCK_Y 0xFFFF0000
+#define BF_PXP_INPUT_STORE_STATUS_CH1_STORE_BLOCK_Y(v) \
+ (((v) << 16) & BM_PXP_INPUT_STORE_STATUS_CH1_STORE_BLOCK_Y)
+#define BP_PXP_INPUT_STORE_STATUS_CH1_STORE_BLOCK_X 0
+#define BM_PXP_INPUT_STORE_STATUS_CH1_STORE_BLOCK_X 0x0000FFFF
+#define BF_PXP_INPUT_STORE_STATUS_CH1_STORE_BLOCK_X(v) \
+ (((v) << 0) & BM_PXP_INPUT_STORE_STATUS_CH1_STORE_BLOCK_X)
+
+#define HW_PXP_INPUT_STORE_SIZE_CH0 (0x00000600)
+
+#define BP_PXP_INPUT_STORE_SIZE_CH0_OUT_HEIGHT 16
+#define BM_PXP_INPUT_STORE_SIZE_CH0_OUT_HEIGHT 0xFFFF0000
+#define BF_PXP_INPUT_STORE_SIZE_CH0_OUT_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_INPUT_STORE_SIZE_CH0_OUT_HEIGHT)
+#define BP_PXP_INPUT_STORE_SIZE_CH0_OUT_WIDTH 0
+#define BM_PXP_INPUT_STORE_SIZE_CH0_OUT_WIDTH 0x0000FFFF
+#define BF_PXP_INPUT_STORE_SIZE_CH0_OUT_WIDTH(v) \
+ (((v) << 0) & BM_PXP_INPUT_STORE_SIZE_CH0_OUT_WIDTH)
+
+#define HW_PXP_INPUT_STORE_SIZE_CH1 (0x00000610)
+
+#define BP_PXP_INPUT_STORE_SIZE_CH1_OUT_HEIGHT 16
+#define BM_PXP_INPUT_STORE_SIZE_CH1_OUT_HEIGHT 0xFFFF0000
+#define BF_PXP_INPUT_STORE_SIZE_CH1_OUT_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_INPUT_STORE_SIZE_CH1_OUT_HEIGHT)
+#define BP_PXP_INPUT_STORE_SIZE_CH1_OUT_WIDTH 0
+#define BM_PXP_INPUT_STORE_SIZE_CH1_OUT_WIDTH 0x0000FFFF
+#define BF_PXP_INPUT_STORE_SIZE_CH1_OUT_WIDTH(v) \
+ (((v) << 0) & BM_PXP_INPUT_STORE_SIZE_CH1_OUT_WIDTH)
+
+#define HW_PXP_INPUT_STORE_PITCH (0x00000620)
+
+#define BP_PXP_INPUT_STORE_PITCH_CH1_OUT_PITCH 16
+#define BM_PXP_INPUT_STORE_PITCH_CH1_OUT_PITCH 0xFFFF0000
+#define BF_PXP_INPUT_STORE_PITCH_CH1_OUT_PITCH(v) \
+ (((v) << 16) & BM_PXP_INPUT_STORE_PITCH_CH1_OUT_PITCH)
+#define BP_PXP_INPUT_STORE_PITCH_CH0_OUT_PITCH 0
+#define BM_PXP_INPUT_STORE_PITCH_CH0_OUT_PITCH 0x0000FFFF
+#define BF_PXP_INPUT_STORE_PITCH_CH0_OUT_PITCH(v) \
+ (((v) << 0) & BM_PXP_INPUT_STORE_PITCH_CH0_OUT_PITCH)
+
+#define HW_PXP_INPUT_STORE_SHIFT_CTRL_CH0 (0x00000630)
+#define HW_PXP_INPUT_STORE_SHIFT_CTRL_CH0_SET (0x00000634)
+#define HW_PXP_INPUT_STORE_SHIFT_CTRL_CH0_CLR (0x00000638)
+#define HW_PXP_INPUT_STORE_SHIFT_CTRL_CH0_TOG (0x0000063c)
+
+#define BP_PXP_INPUT_STORE_SHIFT_CTRL_CH0_RSVD0 8
+#define BM_PXP_INPUT_STORE_SHIFT_CTRL_CH0_RSVD0 0xFFFFFF00
+#define BF_PXP_INPUT_STORE_SHIFT_CTRL_CH0_RSVD0(v) \
+ (((v) << 8) & BM_PXP_INPUT_STORE_SHIFT_CTRL_CH0_RSVD0)
+#define BM_PXP_INPUT_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS 0x00000080
+#define BF_PXP_INPUT_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS(v) \
+ (((v) << 7) & BM_PXP_INPUT_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS)
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS__0 0x0
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS__1 0x1
+#define BM_PXP_INPUT_STORE_SHIFT_CTRL_CH0_RSVD1 0x00000040
+#define BF_PXP_INPUT_STORE_SHIFT_CTRL_CH0_RSVD1(v) \
+ (((v) << 6) & BM_PXP_INPUT_STORE_SHIFT_CTRL_CH0_RSVD1)
+#define BM_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN 0x00000020
+#define BF_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN(v) \
+ (((v) << 5) & BM_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN)
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN__0 0x0
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN__1 0x1
+#define BM_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN 0x00000010
+#define BF_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN(v) \
+ (((v) << 4) & BM_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN)
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN__0 0x0
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN__1 0x1
+#define BP_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP 2
+#define BM_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP 0x0000000C
+#define BF_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP(v) \
+ (((v) << 2) & BM_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP)
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP__0 0x0
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP__1 0x1
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP__2 0x2
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP__3 0x3
+#define BP_PXP_INPUT_STORE_SHIFT_CTRL_CH0_RSVD2 0
+#define BM_PXP_INPUT_STORE_SHIFT_CTRL_CH0_RSVD2 0x00000003
+#define BF_PXP_INPUT_STORE_SHIFT_CTRL_CH0_RSVD2(v) \
+ (((v) << 0) & BM_PXP_INPUT_STORE_SHIFT_CTRL_CH0_RSVD2)
+
+#define HW_PXP_INPUT_STORE_SHIFT_CTRL_CH1 (0x00000640)
+#define HW_PXP_INPUT_STORE_SHIFT_CTRL_CH1_SET (0x00000644)
+#define HW_PXP_INPUT_STORE_SHIFT_CTRL_CH1_CLR (0x00000648)
+#define HW_PXP_INPUT_STORE_SHIFT_CTRL_CH1_TOG (0x0000064c)
+
+#define BP_PXP_INPUT_STORE_SHIFT_CTRL_CH1_RSVD0 6
+#define BM_PXP_INPUT_STORE_SHIFT_CTRL_CH1_RSVD0 0xFFFFFFC0
+#define BF_PXP_INPUT_STORE_SHIFT_CTRL_CH1_RSVD0(v) \
+ (((v) << 6) & BM_PXP_INPUT_STORE_SHIFT_CTRL_CH1_RSVD0)
+#define BM_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN 0x00000020
+#define BF_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN(v) \
+ (((v) << 5) & BM_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN)
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN__0 0x0
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN__1 0x1
+#define BM_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN 0x00000010
+#define BF_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN(v) \
+ (((v) << 4) & BM_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN)
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN__0 0x0
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN__1 0x1
+#define BP_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP 2
+#define BM_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP 0x0000000C
+#define BF_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP(v) \
+ (((v) << 2) & BM_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP)
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP__0 0x0
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP__1 0x1
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP__2 0x2
+#define BV_PXP_INPUT_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP__3 0x3
+#define BP_PXP_INPUT_STORE_SHIFT_CTRL_CH1_RSVD2 0
+#define BM_PXP_INPUT_STORE_SHIFT_CTRL_CH1_RSVD2 0x00000003
+#define BF_PXP_INPUT_STORE_SHIFT_CTRL_CH1_RSVD2(v) \
+ (((v) << 0) & BM_PXP_INPUT_STORE_SHIFT_CTRL_CH1_RSVD2)
+
+#define HW_PXP_INPUT_STORE_ADDR_0_CH0 (0x00000690)
+
+#define BP_PXP_INPUT_STORE_ADDR_0_CH0_OUT_BASE_ADDR0 0
+#define BM_PXP_INPUT_STORE_ADDR_0_CH0_OUT_BASE_ADDR0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_ADDR_0_CH0_OUT_BASE_ADDR0(v) (v)
+
+#define HW_PXP_INPUT_STORE_ADDR_1_CH0 (0x000006a0)
+
+#define BP_PXP_INPUT_STORE_ADDR_1_CH0_OUT_BASE_ADDR1 0
+#define BM_PXP_INPUT_STORE_ADDR_1_CH0_OUT_BASE_ADDR1 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_ADDR_1_CH0_OUT_BASE_ADDR1(v) (v)
+
+#define HW_PXP_INPUT_STORE_FILL_DATA_CH0 (0x000006b0)
+
+#define BP_PXP_INPUT_STORE_FILL_DATA_CH0_FILL_DATA_CH0 0
+#define BM_PXP_INPUT_STORE_FILL_DATA_CH0_FILL_DATA_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_FILL_DATA_CH0_FILL_DATA_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_ADDR_0_CH1 (0x000006c0)
+
+#define BP_PXP_INPUT_STORE_ADDR_0_CH1_OUT_BASE_ADDR0 0
+#define BM_PXP_INPUT_STORE_ADDR_0_CH1_OUT_BASE_ADDR0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_ADDR_0_CH1_OUT_BASE_ADDR0(v) (v)
+
+#define HW_PXP_INPUT_STORE_ADDR_1_CH1 (0x000006d0)
+
+#define BP_PXP_INPUT_STORE_ADDR_1_CH1_OUT_BASE_ADDR1 0
+#define BM_PXP_INPUT_STORE_ADDR_1_CH1_OUT_BASE_ADDR1 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_ADDR_1_CH1_OUT_BASE_ADDR1(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_MASK0_H_CH0 (0x000006e0)
+
+#define BP_PXP_INPUT_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0 0
+#define BM_PXP_INPUT_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_MASK0_L_CH0 (0x000006f0)
+
+#define BP_PXP_INPUT_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0 0
+#define BM_PXP_INPUT_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_MASK1_H_CH0 (0x00000700)
+
+#define BP_PXP_INPUT_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0 0
+#define BM_PXP_INPUT_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_MASK1_L_CH0 (0x00000710)
+
+#define BP_PXP_INPUT_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0 0
+#define BM_PXP_INPUT_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_MASK2_H_CH0 (0x00000720)
+
+#define BP_PXP_INPUT_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0 0
+#define BM_PXP_INPUT_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_MASK2_L_CH0 (0x00000730)
+
+#define BP_PXP_INPUT_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0 0
+#define BM_PXP_INPUT_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_MASK3_H_CH0 (0x00000740)
+
+#define BP_PXP_INPUT_STORE_D_MASK3_H_CH0_D_MASK3_H_CH0 0
+#define BM_PXP_INPUT_STORE_D_MASK3_H_CH0_D_MASK3_H_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_D_MASK3_H_CH0_D_MASK3_H_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_MASK3_L_CH0 (0x00000750)
+
+#define BP_PXP_INPUT_STORE_D_MASK3_L_CH0_D_MASK3_L_CH0 0
+#define BM_PXP_INPUT_STORE_D_MASK3_L_CH0_D_MASK3_L_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_D_MASK3_L_CH0_D_MASK3_L_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_MASK4_H_CH0 (0x00000760)
+
+#define BP_PXP_INPUT_STORE_D_MASK4_H_CH0_D_MASK4_H_CH0 0
+#define BM_PXP_INPUT_STORE_D_MASK4_H_CH0_D_MASK4_H_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_D_MASK4_H_CH0_D_MASK4_H_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_MASK4_L_CH0 (0x00000770)
+
+#define BP_PXP_INPUT_STORE_D_MASK4_L_CH0_D_MASK4_L_CH0 0
+#define BM_PXP_INPUT_STORE_D_MASK4_L_CH0_D_MASK4_L_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_D_MASK4_L_CH0_D_MASK4_L_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_MASK5_H_CH0 (0x00000780)
+
+#define BP_PXP_INPUT_STORE_D_MASK5_H_CH0_D_MASK5_H_CH0 0
+#define BM_PXP_INPUT_STORE_D_MASK5_H_CH0_D_MASK5_H_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_D_MASK5_H_CH0_D_MASK5_H_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_MASK5_L_CH0 (0x00000790)
+
+#define BP_PXP_INPUT_STORE_D_MASK5_L_CH0_D_MASK5_L_CH0 0
+#define BM_PXP_INPUT_STORE_D_MASK5_L_CH0_D_MASK5_L_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_D_MASK5_L_CH0_D_MASK5_L_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_MASK6_H_CH0 (0x000007a0)
+
+#define BP_PXP_INPUT_STORE_D_MASK6_H_CH0_D_MASK6_H_CH0 0
+#define BM_PXP_INPUT_STORE_D_MASK6_H_CH0_D_MASK6_H_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_D_MASK6_H_CH0_D_MASK6_H_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_MASK6_L_CH0 (0x000007b0)
+
+#define BP_PXP_INPUT_STORE_D_MASK6_L_CH0_D_MASK6_L_CH0 0
+#define BM_PXP_INPUT_STORE_D_MASK6_L_CH0_D_MASK6_L_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_D_MASK6_L_CH0_D_MASK6_L_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_MASK7_H_CH0 (0x000007c0)
+
+#define BP_PXP_INPUT_STORE_D_MASK7_H_CH0_D_MASK7_H_CH0 0
+#define BM_PXP_INPUT_STORE_D_MASK7_H_CH0_D_MASK7_H_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_D_MASK7_H_CH0_D_MASK7_H_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_MASK7_L_CH0 (0x000007e0)
+
+#define BP_PXP_INPUT_STORE_D_MASK7_L_CH0_D_MASK7_L_CH0 0
+#define BM_PXP_INPUT_STORE_D_MASK7_L_CH0_D_MASK7_L_CH0 0xFFFFFFFF
+#define BF_PXP_INPUT_STORE_D_MASK7_L_CH0_D_MASK7_L_CH0(v) (v)
+
+#define HW_PXP_INPUT_STORE_D_SHIFT_L_CH0 (0x000007f0)
+
+#define BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3 0x80000000
+#define BF_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3(v) \
+ (((v) << 31) & BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3)
+#define BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_RSVD0 0x40000000
+#define BF_PXP_INPUT_STORE_D_SHIFT_L_CH0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_RSVD0)
+#define BP_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3 24
+#define BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3 0x3F000000
+#define BF_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3(v) \
+ (((v) << 24) & BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3)
+#define BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2 0x00800000
+#define BF_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2(v) \
+ (((v) << 23) & BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2)
+#define BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_RSVD1 0x00400000
+#define BF_PXP_INPUT_STORE_D_SHIFT_L_CH0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_RSVD1)
+#define BP_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2 16
+#define BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2 0x003F0000
+#define BF_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2(v) \
+ (((v) << 16) & BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2)
+#define BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1 0x00008000
+#define BF_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1(v) \
+ (((v) << 15) & BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1)
+#define BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_RSVD2 0x00004000
+#define BF_PXP_INPUT_STORE_D_SHIFT_L_CH0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_RSVD2)
+#define BP_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1 8
+#define BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1 0x00003F00
+#define BF_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1(v) \
+ (((v) << 8) & BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1)
+#define BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0 0x00000080
+#define BF_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0(v) \
+ (((v) << 7) & BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0)
+#define BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_RSVD3 0x00000040
+#define BF_PXP_INPUT_STORE_D_SHIFT_L_CH0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_RSVD3)
+#define BP_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0 0
+#define BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0 0x0000003F
+#define BF_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0(v) \
+ (((v) << 0) & BM_PXP_INPUT_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0)
+
+#define HW_PXP_INPUT_STORE_D_SHIFT_H_CH0 (0x00000800)
+
+#define BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG7 0x80000000
+#define BF_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG7(v) \
+ (((v) << 31) & BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG7)
+#define BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_RSVD0 0x40000000
+#define BF_PXP_INPUT_STORE_D_SHIFT_H_CH0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_RSVD0)
+#define BP_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7 24
+#define BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7 0x3F000000
+#define BF_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7(v) \
+ (((v) << 24) & BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7)
+#define BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG6 0x00800000
+#define BF_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG6(v) \
+ (((v) << 23) & BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG6)
+#define BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_RSVD1 0x00400000
+#define BF_PXP_INPUT_STORE_D_SHIFT_H_CH0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_RSVD1)
+#define BP_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6 16
+#define BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6 0x003F0000
+#define BF_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6(v) \
+ (((v) << 16) & BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6)
+#define BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG5 0x00008000
+#define BF_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG5(v) \
+ (((v) << 15) & BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG5)
+#define BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_RSVD2 0x00004000
+#define BF_PXP_INPUT_STORE_D_SHIFT_H_CH0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_RSVD2)
+#define BP_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5 8
+#define BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5 0x00003F00
+#define BF_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5(v) \
+ (((v) << 8) & BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5)
+#define BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG4 0x00000080
+#define BF_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG4(v) \
+ (((v) << 7) & BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG4)
+#define BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_RSVD3 0x00000040
+#define BF_PXP_INPUT_STORE_D_SHIFT_H_CH0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_RSVD3)
+#define BP_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4 0
+#define BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4 0x0000003F
+#define BF_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4(v) \
+ (((v) << 0) & BM_PXP_INPUT_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4)
+
+#define HW_PXP_INPUT_STORE_F_SHIFT_L_CH0 (0x00000810)
+
+#define BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_RSVD0 0x80000000
+#define BF_PXP_INPUT_STORE_F_SHIFT_L_CH0_RSVD0(v) \
+ (((v) << 31) & BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_RSVD0)
+#define BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3 0x40000000
+#define BF_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3(v) \
+ (((v) << 30) & BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3)
+#define BP_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3 24
+#define BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3 0x3F000000
+#define BF_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3(v) \
+ (((v) << 24) & BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3)
+#define BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_RSVD1 0x00800000
+#define BF_PXP_INPUT_STORE_F_SHIFT_L_CH0_RSVD1(v) \
+ (((v) << 23) & BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_RSVD1)
+#define BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2 0x00400000
+#define BF_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2(v) \
+ (((v) << 22) & BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2)
+#define BP_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2 16
+#define BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2 0x003F0000
+#define BF_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2(v) \
+ (((v) << 16) & BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2)
+#define BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_RSVD2 0x00008000
+#define BF_PXP_INPUT_STORE_F_SHIFT_L_CH0_RSVD2(v) \
+ (((v) << 15) & BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_RSVD2)
+#define BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1 0x00004000
+#define BF_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1(v) \
+ (((v) << 14) & BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1)
+#define BP_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1 8
+#define BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1 0x00003F00
+#define BF_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1(v) \
+ (((v) << 8) & BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1)
+#define BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_RSVD3 0x00000080
+#define BF_PXP_INPUT_STORE_F_SHIFT_L_CH0_RSVD3(v) \
+ (((v) << 7) & BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_RSVD3)
+#define BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0 0x00000040
+#define BF_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0(v) \
+ (((v) << 6) & BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0)
+#define BP_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0 0
+#define BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0 0x0000003F
+#define BF_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0(v) \
+ (((v) << 0) & BM_PXP_INPUT_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0)
+
+#define HW_PXP_INPUT_STORE_F_SHIFT_H_CH0 (0x00000820)
+
+#define BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_RSVD0 0x80000000
+#define BF_PXP_INPUT_STORE_F_SHIFT_H_CH0_RSVD0(v) \
+ (((v) << 31) & BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_RSVD0)
+#define BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG7 0x40000000
+#define BF_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG7(v) \
+ (((v) << 30) & BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG7)
+#define BP_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7 24
+#define BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7 0x3F000000
+#define BF_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7(v) \
+ (((v) << 24) & BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7)
+#define BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_RSVD1 0x00800000
+#define BF_PXP_INPUT_STORE_F_SHIFT_H_CH0_RSVD1(v) \
+ (((v) << 23) & BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_RSVD1)
+#define BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG6 0x00400000
+#define BF_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG6(v) \
+ (((v) << 22) & BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG6)
+#define BP_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6 16
+#define BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6 0x003F0000
+#define BF_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6(v) \
+ (((v) << 16) & BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6)
+#define BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_RSVD2 0x00008000
+#define BF_PXP_INPUT_STORE_F_SHIFT_H_CH0_RSVD2(v) \
+ (((v) << 15) & BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_RSVD2)
+#define BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG5 0x00004000
+#define BF_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG5(v) \
+ (((v) << 14) & BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG5)
+#define BP_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5 8
+#define BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5 0x00003F00
+#define BF_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5(v) \
+ (((v) << 8) & BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5)
+#define BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_RSVD3 0x00000080
+#define BF_PXP_INPUT_STORE_F_SHIFT_H_CH0_RSVD3(v) \
+ (((v) << 7) & BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_RSVD3)
+#define BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG4 0x00000040
+#define BF_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG4(v) \
+ (((v) << 6) & BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG4)
+#define BP_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4 0
+#define BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4 0x0000003F
+#define BF_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4(v) \
+ (((v) << 0) & BM_PXP_INPUT_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4)
+
+#define HW_PXP_INPUT_STORE_F_MASK_L_CH0 (0x00000830)
+
+#define BP_PXP_INPUT_STORE_F_MASK_L_CH0_F_MASK3 24
+#define BM_PXP_INPUT_STORE_F_MASK_L_CH0_F_MASK3 0xFF000000
+#define BF_PXP_INPUT_STORE_F_MASK_L_CH0_F_MASK3(v) \
+ (((v) << 24) & BM_PXP_INPUT_STORE_F_MASK_L_CH0_F_MASK3)
+#define BP_PXP_INPUT_STORE_F_MASK_L_CH0_F_MASK2 16
+#define BM_PXP_INPUT_STORE_F_MASK_L_CH0_F_MASK2 0x00FF0000
+#define BF_PXP_INPUT_STORE_F_MASK_L_CH0_F_MASK2(v) \
+ (((v) << 16) & BM_PXP_INPUT_STORE_F_MASK_L_CH0_F_MASK2)
+#define BP_PXP_INPUT_STORE_F_MASK_L_CH0_F_MASK1 8
+#define BM_PXP_INPUT_STORE_F_MASK_L_CH0_F_MASK1 0x0000FF00
+#define BF_PXP_INPUT_STORE_F_MASK_L_CH0_F_MASK1(v) \
+ (((v) << 8) & BM_PXP_INPUT_STORE_F_MASK_L_CH0_F_MASK1)
+#define BP_PXP_INPUT_STORE_F_MASK_L_CH0_F_MASK0 0
+#define BM_PXP_INPUT_STORE_F_MASK_L_CH0_F_MASK0 0x000000FF
+#define BF_PXP_INPUT_STORE_F_MASK_L_CH0_F_MASK0(v) \
+ (((v) << 0) & BM_PXP_INPUT_STORE_F_MASK_L_CH0_F_MASK0)
+
+#define HW_PXP_INPUT_STORE_F_MASK_H_CH0 (0x00000840)
+
+#define BP_PXP_INPUT_STORE_F_MASK_H_CH0_F_MASK7 24
+#define BM_PXP_INPUT_STORE_F_MASK_H_CH0_F_MASK7 0xFF000000
+#define BF_PXP_INPUT_STORE_F_MASK_H_CH0_F_MASK7(v) \
+ (((v) << 24) & BM_PXP_INPUT_STORE_F_MASK_H_CH0_F_MASK7)
+#define BP_PXP_INPUT_STORE_F_MASK_H_CH0_F_MASK6 16
+#define BM_PXP_INPUT_STORE_F_MASK_H_CH0_F_MASK6 0x00FF0000
+#define BF_PXP_INPUT_STORE_F_MASK_H_CH0_F_MASK6(v) \
+ (((v) << 16) & BM_PXP_INPUT_STORE_F_MASK_H_CH0_F_MASK6)
+#define BP_PXP_INPUT_STORE_F_MASK_H_CH0_F_MASK5 8
+#define BM_PXP_INPUT_STORE_F_MASK_H_CH0_F_MASK5 0x0000FF00
+#define BF_PXP_INPUT_STORE_F_MASK_H_CH0_F_MASK5(v) \
+ (((v) << 8) & BM_PXP_INPUT_STORE_F_MASK_H_CH0_F_MASK5)
+#define BP_PXP_INPUT_STORE_F_MASK_H_CH0_F_MASK4 0
+#define BM_PXP_INPUT_STORE_F_MASK_H_CH0_F_MASK4 0x000000FF
+#define BF_PXP_INPUT_STORE_F_MASK_H_CH0_F_MASK4(v) \
+ (((v) << 0) & BM_PXP_INPUT_STORE_F_MASK_H_CH0_F_MASK4)
+
+#define HW_PXP_DITHER_FETCH_CTRL_CH0 (0x00000850)
+#define HW_PXP_DITHER_FETCH_CTRL_CH0_SET (0x00000854)
+#define HW_PXP_DITHER_FETCH_CTRL_CH0_CLR (0x00000858)
+#define HW_PXP_DITHER_FETCH_CTRL_CH0_TOG (0x0000085c)
+
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_ARBIT_EN 0x80000000
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_ARBIT_EN(v) \
+ (((v) << 31) & BM_PXP_DITHER_FETCH_CTRL_CH0_ARBIT_EN)
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_ARBIT_EN__0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_ARBIT_EN__1 0x1
+#define BP_PXP_DITHER_FETCH_CTRL_CH0_RSVD0 26
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_RSVD0 0x7C000000
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_RSVD0(v) \
+ (((v) << 26) & BM_PXP_DITHER_FETCH_CTRL_CH0_RSVD0)
+#define BP_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM 24
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM 0x03000000
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM(v) \
+ (((v) << 24) & BM_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM)
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM__0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM__1 0x1
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM__2 0x2
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_SCAN_LINE_NUM__3 0x3
+#define BP_PXP_DITHER_FETCH_CTRL_CH0_RSVD1 18
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_RSVD1 0x00FC0000
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_RSVD1(v) \
+ (((v) << 18) & BM_PXP_DITHER_FETCH_CTRL_CH0_RSVD1)
+#define BP_PXP_DITHER_FETCH_CTRL_CH0_RD_NUM_BYTES 16
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_RD_NUM_BYTES 0x00030000
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_RD_NUM_BYTES(v) \
+ (((v) << 16) & BM_PXP_DITHER_FETCH_CTRL_CH0_RD_NUM_BYTES)
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_RD_NUM_BYTES__8_bytes 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_RD_NUM_BYTES__16_bytes 0x1
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_RD_NUM_BYTES__32_bytes 0x2
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_RD_NUM_BYTES__64_bytes 0x3
+#define BP_PXP_DITHER_FETCH_CTRL_CH0_RSVD2 14
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_RSVD2 0x0000C000
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_DITHER_FETCH_CTRL_CH0_RSVD2)
+#define BP_PXP_DITHER_FETCH_CTRL_CH0_ROTATION_ANGLE 12
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_ROTATION_ANGLE 0x00003000
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_ROTATION_ANGLE(v) \
+ (((v) << 12) & BM_PXP_DITHER_FETCH_CTRL_CH0_ROTATION_ANGLE)
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_ROTATION_ANGLE__ROT_0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_ROTATION_ANGLE__ROT_90 0x1
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_ROTATION_ANGLE__ROT_180 0x2
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_ROTATION_ANGLE__ROT_270 0x3
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_RSVD3 0x00000800
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_RSVD3(v) \
+ (((v) << 11) & BM_PXP_DITHER_FETCH_CTRL_CH0_RSVD3)
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_VFLIP 0x00000400
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_VFLIP(v) \
+ (((v) << 10) & BM_PXP_DITHER_FETCH_CTRL_CH0_VFLIP)
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_VFLIP__0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_VFLIP__1 0x1
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_HFLIP 0x00000200
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_HFLIP(v) \
+ (((v) << 9) & BM_PXP_DITHER_FETCH_CTRL_CH0_HFLIP)
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_HFLIP__0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_HFLIP__1 0x1
+#define BP_PXP_DITHER_FETCH_CTRL_CH0_RSVD4 6
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_RSVD4 0x000001C0
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_RSVD4(v) \
+ (((v) << 6) & BM_PXP_DITHER_FETCH_CTRL_CH0_RSVD4)
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_HIGH_BYTE 0x00000020
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_HIGH_BYTE(v) \
+ (((v) << 5) & BM_PXP_DITHER_FETCH_CTRL_CH0_HIGH_BYTE)
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_HIGH_BYTE__0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_HIGH_BYTE__1 0x1
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_BYPASS_PIXEL_EN 0x00000010
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_BYPASS_PIXEL_EN(v) \
+ (((v) << 4) & BM_PXP_DITHER_FETCH_CTRL_CH0_BYPASS_PIXEL_EN)
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_BYPASS_PIXEL_EN__0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_BYPASS_PIXEL_EN__1 0x1
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_EN 0x00000008
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_EN(v) \
+ (((v) << 3) & BM_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_EN)
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_EN__0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_HANDSHAKE_EN__1 0x1
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_BLOCK_16 0x00000004
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_BLOCK_16(v) \
+ (((v) << 2) & BM_PXP_DITHER_FETCH_CTRL_CH0_BLOCK_16)
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_BLOCK_16__8x8 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_BLOCK_16__16x16 0x1
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_BLOCK_EN 0x00000002
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_BLOCK_EN(v) \
+ (((v) << 1) & BM_PXP_DITHER_FETCH_CTRL_CH0_BLOCK_EN)
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_BLOCK_EN__0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_BLOCK_EN__1 0x1
+#define BM_PXP_DITHER_FETCH_CTRL_CH0_CH_EN 0x00000001
+#define BF_PXP_DITHER_FETCH_CTRL_CH0_CH_EN(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_CTRL_CH0_CH_EN)
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_CH_EN__0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH0_CH_EN__1 0x1
+
+#define HW_PXP_DITHER_FETCH_CTRL_CH1 (0x00000860)
+#define HW_PXP_DITHER_FETCH_CTRL_CH1_SET (0x00000864)
+#define HW_PXP_DITHER_FETCH_CTRL_CH1_CLR (0x00000868)
+#define HW_PXP_DITHER_FETCH_CTRL_CH1_TOG (0x0000086c)
+
+#define BP_PXP_DITHER_FETCH_CTRL_CH1_RSVD0 26
+#define BM_PXP_DITHER_FETCH_CTRL_CH1_RSVD0 0xFC000000
+#define BF_PXP_DITHER_FETCH_CTRL_CH1_RSVD0(v) \
+ (((v) << 26) & BM_PXP_DITHER_FETCH_CTRL_CH1_RSVD0)
+#define BP_PXP_DITHER_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM 24
+#define BM_PXP_DITHER_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM 0x03000000
+#define BF_PXP_DITHER_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM(v) \
+ (((v) << 24) & BM_PXP_DITHER_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM)
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM__0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM__1 0x1
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM__2 0x2
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_HANDSHAKE_SCAN_LINE_NUM__3 0x3
+#define BP_PXP_DITHER_FETCH_CTRL_CH1_RSVD1 18
+#define BM_PXP_DITHER_FETCH_CTRL_CH1_RSVD1 0x00FC0000
+#define BF_PXP_DITHER_FETCH_CTRL_CH1_RSVD1(v) \
+ (((v) << 18) & BM_PXP_DITHER_FETCH_CTRL_CH1_RSVD1)
+#define BP_PXP_DITHER_FETCH_CTRL_CH1_RD_NUM_BYTES 16
+#define BM_PXP_DITHER_FETCH_CTRL_CH1_RD_NUM_BYTES 0x00030000
+#define BF_PXP_DITHER_FETCH_CTRL_CH1_RD_NUM_BYTES(v) \
+ (((v) << 16) & BM_PXP_DITHER_FETCH_CTRL_CH1_RD_NUM_BYTES)
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_RD_NUM_BYTES__8_bytes 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_RD_NUM_BYTES__16_bytes 0x1
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_RD_NUM_BYTES__32_bytes 0x2
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_RD_NUM_BYTES__64_bytes 0x3
+#define BP_PXP_DITHER_FETCH_CTRL_CH1_RSVD2 14
+#define BM_PXP_DITHER_FETCH_CTRL_CH1_RSVD2 0x0000C000
+#define BF_PXP_DITHER_FETCH_CTRL_CH1_RSVD2(v) \
+ (((v) << 14) & BM_PXP_DITHER_FETCH_CTRL_CH1_RSVD2)
+#define BP_PXP_DITHER_FETCH_CTRL_CH1_ROTATION_ANGLE 12
+#define BM_PXP_DITHER_FETCH_CTRL_CH1_ROTATION_ANGLE 0x00003000
+#define BF_PXP_DITHER_FETCH_CTRL_CH1_ROTATION_ANGLE(v) \
+ (((v) << 12) & BM_PXP_DITHER_FETCH_CTRL_CH1_ROTATION_ANGLE)
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_ROTATION_ANGLE__ROT_0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_ROTATION_ANGLE__ROT_90 0x1
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_ROTATION_ANGLE__ROT_180 0x2
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_ROTATION_ANGLE__ROT_270 0x3
+#define BM_PXP_DITHER_FETCH_CTRL_CH1_RSVD3 0x00000800
+#define BF_PXP_DITHER_FETCH_CTRL_CH1_RSVD3(v) \
+ (((v) << 11) & BM_PXP_DITHER_FETCH_CTRL_CH1_RSVD3)
+#define BM_PXP_DITHER_FETCH_CTRL_CH1_VFLIP 0x00000400
+#define BF_PXP_DITHER_FETCH_CTRL_CH1_VFLIP(v) \
+ (((v) << 10) & BM_PXP_DITHER_FETCH_CTRL_CH1_VFLIP)
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_VFLIP__0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_VFLIP__1 0x1
+#define BM_PXP_DITHER_FETCH_CTRL_CH1_HFLIP 0x00000200
+#define BF_PXP_DITHER_FETCH_CTRL_CH1_HFLIP(v) \
+ (((v) << 9) & BM_PXP_DITHER_FETCH_CTRL_CH1_HFLIP)
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_HFLIP__0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_HFLIP__1 0x1
+#define BP_PXP_DITHER_FETCH_CTRL_CH1_RSVD4 5
+#define BM_PXP_DITHER_FETCH_CTRL_CH1_RSVD4 0x000001E0
+#define BF_PXP_DITHER_FETCH_CTRL_CH1_RSVD4(v) \
+ (((v) << 5) & BM_PXP_DITHER_FETCH_CTRL_CH1_RSVD4)
+#define BM_PXP_DITHER_FETCH_CTRL_CH1_BYPASS_PIXEL_EN 0x00000010
+#define BF_PXP_DITHER_FETCH_CTRL_CH1_BYPASS_PIXEL_EN(v) \
+ (((v) << 4) & BM_PXP_DITHER_FETCH_CTRL_CH1_BYPASS_PIXEL_EN)
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_BYPASS_PIXEL_EN__0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_BYPASS_PIXEL_EN__1 0x1
+#define BM_PXP_DITHER_FETCH_CTRL_CH1_HANDSHAKE_EN 0x00000008
+#define BF_PXP_DITHER_FETCH_CTRL_CH1_HANDSHAKE_EN(v) \
+ (((v) << 3) & BM_PXP_DITHER_FETCH_CTRL_CH1_HANDSHAKE_EN)
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_HANDSHAKE_EN__0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_HANDSHAKE_EN__1 0x1
+#define BM_PXP_DITHER_FETCH_CTRL_CH1_BLOCK_16 0x00000004
+#define BF_PXP_DITHER_FETCH_CTRL_CH1_BLOCK_16(v) \
+ (((v) << 2) & BM_PXP_DITHER_FETCH_CTRL_CH1_BLOCK_16)
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_BLOCK_16__8x8 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_BLOCK_16__16x16 0x1
+#define BM_PXP_DITHER_FETCH_CTRL_CH1_BLOCK_EN 0x00000002
+#define BF_PXP_DITHER_FETCH_CTRL_CH1_BLOCK_EN(v) \
+ (((v) << 1) & BM_PXP_DITHER_FETCH_CTRL_CH1_BLOCK_EN)
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_BLOCK_EN__0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_BLOCK_EN__1 0x1
+#define BM_PXP_DITHER_FETCH_CTRL_CH1_CH_EN 0x00000001
+#define BF_PXP_DITHER_FETCH_CTRL_CH1_CH_EN(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_CTRL_CH1_CH_EN)
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_CH_EN__0 0x0
+#define BV_PXP_DITHER_FETCH_CTRL_CH1_CH_EN__1 0x1
+
+#define HW_PXP_DITHER_FETCH_STATUS_CH0 (0x00000870)
+
+#define BP_PXP_DITHER_FETCH_STATUS_CH0_PREFETCH_BLOCK_Y 16
+#define BM_PXP_DITHER_FETCH_STATUS_CH0_PREFETCH_BLOCK_Y 0xFFFF0000
+#define BF_PXP_DITHER_FETCH_STATUS_CH0_PREFETCH_BLOCK_Y(v) \
+ (((v) << 16) & BM_PXP_DITHER_FETCH_STATUS_CH0_PREFETCH_BLOCK_Y)
+#define BP_PXP_DITHER_FETCH_STATUS_CH0_PREFETCH_BLOCK_X 0
+#define BM_PXP_DITHER_FETCH_STATUS_CH0_PREFETCH_BLOCK_X 0x0000FFFF
+#define BF_PXP_DITHER_FETCH_STATUS_CH0_PREFETCH_BLOCK_X(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_STATUS_CH0_PREFETCH_BLOCK_X)
+
+#define HW_PXP_DITHER_FETCH_STATUS_CH1 (0x00000880)
+
+#define BP_PXP_DITHER_FETCH_STATUS_CH1_PREFETCH_BLOCK_Y 16
+#define BM_PXP_DITHER_FETCH_STATUS_CH1_PREFETCH_BLOCK_Y 0xFFFF0000
+#define BF_PXP_DITHER_FETCH_STATUS_CH1_PREFETCH_BLOCK_Y(v) \
+ (((v) << 16) & BM_PXP_DITHER_FETCH_STATUS_CH1_PREFETCH_BLOCK_Y)
+#define BP_PXP_DITHER_FETCH_STATUS_CH1_PREFETCH_BLOCK_X 0
+#define BM_PXP_DITHER_FETCH_STATUS_CH1_PREFETCH_BLOCK_X 0x0000FFFF
+#define BF_PXP_DITHER_FETCH_STATUS_CH1_PREFETCH_BLOCK_X(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_STATUS_CH1_PREFETCH_BLOCK_X)
+
+#define HW_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH0 (0x00000890)
+
+#define BP_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_Y 16
+#define BM_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_Y 0xFFFF0000
+#define BF_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_Y(v) \
+ (((v) << 16) & BM_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_Y)
+#define BP_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_X 0
+#define BM_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_X 0x0000FFFF
+#define BF_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_X(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH0_ACTIVE_SIZE_ULC_X)
+
+#define HW_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH0 (0x000008a0)
+
+#define BP_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_Y 16
+#define BM_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_Y 0xFFFF0000
+#define BF_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_Y(v) \
+ (((v) << 16) & BM_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_Y)
+#define BP_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_X 0
+#define BM_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_X 0x0000FFFF
+#define BF_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_X(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH0_ACTIVE_SIZE_LRC_X)
+
+#define HW_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH1 (0x000008b0)
+
+#define BP_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_Y 16
+#define BM_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_Y 0xFFFF0000
+#define BF_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_Y(v) \
+ (((v) << 16) & BM_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_Y)
+#define BP_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_X 0
+#define BM_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_X 0x0000FFFF
+#define BF_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_X(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_ACTIVE_SIZE_ULC_CH1_ACTIVE_SIZE_ULC_X)
+
+#define HW_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH1 (0x000008c0)
+
+#define BP_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_Y 16
+#define BM_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_Y 0xFFFF0000
+#define BF_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_Y(v) \
+ (((v) << 16) & BM_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_Y)
+#define BP_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_X 0
+#define BM_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_X 0x0000FFFF
+#define BF_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_X(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_ACTIVE_SIZE_LRC_CH1_ACTIVE_SIZE_LRC_X)
+
+#define HW_PXP_DITHER_FETCH_SIZE_CH0 (0x000008d0)
+
+#define BP_PXP_DITHER_FETCH_SIZE_CH0_INPUT_TOTAL_HEIGHT 16
+#define BM_PXP_DITHER_FETCH_SIZE_CH0_INPUT_TOTAL_HEIGHT 0xFFFF0000
+#define BF_PXP_DITHER_FETCH_SIZE_CH0_INPUT_TOTAL_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_DITHER_FETCH_SIZE_CH0_INPUT_TOTAL_HEIGHT)
+#define BP_PXP_DITHER_FETCH_SIZE_CH0_INPUT_TOTAL_WIDTH 0
+#define BM_PXP_DITHER_FETCH_SIZE_CH0_INPUT_TOTAL_WIDTH 0x0000FFFF
+#define BF_PXP_DITHER_FETCH_SIZE_CH0_INPUT_TOTAL_WIDTH(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_SIZE_CH0_INPUT_TOTAL_WIDTH)
+
+#define HW_PXP_DITHER_FETCH_SIZE_CH1 (0x000008e0)
+
+#define BP_PXP_DITHER_FETCH_SIZE_CH1_INPUT_TOTAL_HEIGHT 16
+#define BM_PXP_DITHER_FETCH_SIZE_CH1_INPUT_TOTAL_HEIGHT 0xFFFF0000
+#define BF_PXP_DITHER_FETCH_SIZE_CH1_INPUT_TOTAL_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_DITHER_FETCH_SIZE_CH1_INPUT_TOTAL_HEIGHT)
+#define BP_PXP_DITHER_FETCH_SIZE_CH1_INPUT_TOTAL_WIDTH 0
+#define BM_PXP_DITHER_FETCH_SIZE_CH1_INPUT_TOTAL_WIDTH 0x0000FFFF
+#define BF_PXP_DITHER_FETCH_SIZE_CH1_INPUT_TOTAL_WIDTH(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_SIZE_CH1_INPUT_TOTAL_WIDTH)
+
+#define HW_PXP_DITHER_FETCH_BACKGROUND_COLOR_CH0 (0x000008f0)
+
+#define BP_PXP_DITHER_FETCH_BACKGROUND_COLOR_CH0_BACKGROUND_COLOR 0
+#define BM_PXP_DITHER_FETCH_BACKGROUND_COLOR_CH0_BACKGROUND_COLOR 0xFFFFFFFF
+#define BF_PXP_DITHER_FETCH_BACKGROUND_COLOR_CH0_BACKGROUND_COLOR(v) (v)
+
+#define HW_PXP_DITHER_FETCH_BACKGROUND_COLOR_CH1 (0x00000900)
+
+#define BP_PXP_DITHER_FETCH_BACKGROUND_COLOR_CH1_BACKGROUND_COLOR 0
+#define BM_PXP_DITHER_FETCH_BACKGROUND_COLOR_CH1_BACKGROUND_COLOR 0xFFFFFFFF
+#define BF_PXP_DITHER_FETCH_BACKGROUND_COLOR_CH1_BACKGROUND_COLOR(v) (v)
+
+#define HW_PXP_DITHER_FETCH_PITCH (0x00000910)
+
+#define BP_PXP_DITHER_FETCH_PITCH_CH1_INPUT_PITCH 16
+#define BM_PXP_DITHER_FETCH_PITCH_CH1_INPUT_PITCH 0xFFFF0000
+#define BF_PXP_DITHER_FETCH_PITCH_CH1_INPUT_PITCH(v) \
+ (((v) << 16) & BM_PXP_DITHER_FETCH_PITCH_CH1_INPUT_PITCH)
+#define BP_PXP_DITHER_FETCH_PITCH_CH0_INPUT_PITCH 0
+#define BM_PXP_DITHER_FETCH_PITCH_CH0_INPUT_PITCH 0x0000FFFF
+#define BF_PXP_DITHER_FETCH_PITCH_CH0_INPUT_PITCH(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_PITCH_CH0_INPUT_PITCH)
+
+#define HW_PXP_DITHER_FETCH_SHIFT_CTRL_CH0 (0x00000920)
+#define HW_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_SET (0x00000924)
+#define HW_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_CLR (0x00000928)
+#define HW_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_TOG (0x0000092c)
+
+#define BP_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_RSVD0 13
+#define BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_RSVD0 0xFFFFE000
+#define BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_RSVD0(v) \
+ (((v) << 13) & BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_RSVD0)
+#define BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_SHIFT_BYPASS 0x00001000
+#define BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_SHIFT_BYPASS(v) \
+ (((v) << 12) & BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_SHIFT_BYPASS)
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_SHIFT_BYPASS__0 0x0
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_SHIFT_BYPASS__1 0x1
+#define BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_EN 0x00000800
+#define BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_EN(v) \
+ (((v) << 11) & BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_EN)
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_EN__0 0x0
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_EN__1 0x1
+#define BP_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT 8
+#define BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT 0x00000700
+#define BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT(v) \
+ (((v) << 8) & BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT)
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT__0 0x0
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT__1 0x1
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT__2 0x2
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT__3 0x3
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT__4 0x4
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT__5 0x5
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT__6 0x6
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_EXPAND_FORMAT__7 0x7
+#define BP_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_RSVD1 2
+#define BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_RSVD1 0x000000FC
+#define BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_RSVD1(v) \
+ (((v) << 2) & BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_RSVD1)
+#define BP_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP 0
+#define BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP 0x00000003
+#define BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP)
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP__0 0x0
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP__1 0x1
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP__2 0x2
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH0_INPUT_ACTIVE_BPP__3 0x3
+
+#define HW_PXP_DITHER_FETCH_SHIFT_CTRL_CH1 (0x00000930)
+#define HW_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_SET (0x00000934)
+#define HW_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_CLR (0x00000938)
+#define HW_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_TOG (0x0000093c)
+
+#define BP_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_RSVD0 13
+#define BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_RSVD0 0xFFFFE000
+#define BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_RSVD0(v) \
+ (((v) << 13) & BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_RSVD0)
+#define BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_SHIFT_BYPASS 0x00001000
+#define BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_SHIFT_BYPASS(v) \
+ (((v) << 12) & BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_SHIFT_BYPASS)
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_SHIFT_BYPASS__0 0x0
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_SHIFT_BYPASS__1 0x1
+#define BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_EN 0x00000800
+#define BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_EN(v) \
+ (((v) << 11) & BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_EN)
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_EN__0 0x0
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_EN__1 0x1
+#define BP_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT 8
+#define BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT 0x00000700
+#define BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT(v) \
+ (((v) << 8) & BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT)
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT__0 0x0
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT__1 0x1
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT__2 0x2
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT__3 0x3
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT__4 0x4
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT__5 0x5
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT__6 0x6
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_EXPAND_FORMAT__7 0x7
+#define BP_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_RSVD1 2
+#define BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_RSVD1 0x000000FC
+#define BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_RSVD1(v) \
+ (((v) << 2) & BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_RSVD1)
+#define BP_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP 0
+#define BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP 0x00000003
+#define BF_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP)
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP__0 0x0
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP__1 0x1
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP__2 0x2
+#define BV_PXP_DITHER_FETCH_SHIFT_CTRL_CH1_INPUT_ACTIVE_BPP__3 0x3
+
+#define HW_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0 (0x00000940)
+#define HW_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_SET (0x00000944)
+#define HW_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_CLR (0x00000948)
+#define HW_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_TOG (0x0000094c)
+
+#define BP_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_RSVD0 29
+#define BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_RSVD0 0xE0000000
+#define BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_RSVD0(v) \
+ (((v) << 29) & BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_RSVD0)
+#define BP_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET3 24
+#define BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET3 0x1F000000
+#define BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET3(v) \
+ (((v) << 24) & BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET3)
+#define BP_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_RSVD1 21
+#define BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_RSVD1 0x00E00000
+#define BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_RSVD1(v) \
+ (((v) << 21) & BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_RSVD1)
+#define BP_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET2 16
+#define BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET2 0x001F0000
+#define BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET2(v) \
+ (((v) << 16) & BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET2)
+#define BP_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_RSVD2 13
+#define BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_RSVD2 0x0000E000
+#define BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_RSVD2(v) \
+ (((v) << 13) & BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_RSVD2)
+#define BP_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET1 8
+#define BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET1 0x00001F00
+#define BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET1(v) \
+ (((v) << 8) & BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET1)
+#define BP_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_RSVD3 5
+#define BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_RSVD3 0x000000E0
+#define BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_RSVD3(v) \
+ (((v) << 5) & BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_RSVD3)
+#define BP_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET0 0
+#define BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET0 0x0000001F
+#define BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET0(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH0_OFFSET0)
+
+#define HW_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1 (0x00000950)
+#define HW_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_SET (0x00000954)
+#define HW_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_CLR (0x00000958)
+#define HW_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_TOG (0x0000095c)
+
+#define BP_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_RSVD0 29
+#define BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_RSVD0 0xE0000000
+#define BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_RSVD0(v) \
+ (((v) << 29) & BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_RSVD0)
+#define BP_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET3 24
+#define BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET3 0x1F000000
+#define BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET3(v) \
+ (((v) << 24) & BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET3)
+#define BP_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_RSVD1 21
+#define BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_RSVD1 0x00E00000
+#define BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_RSVD1(v) \
+ (((v) << 21) & BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_RSVD1)
+#define BP_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET2 16
+#define BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET2 0x001F0000
+#define BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET2(v) \
+ (((v) << 16) & BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET2)
+#define BP_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_RSVD2 13
+#define BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_RSVD2 0x0000E000
+#define BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_RSVD2(v) \
+ (((v) << 13) & BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_RSVD2)
+#define BP_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET1 8
+#define BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET1 0x00001F00
+#define BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET1(v) \
+ (((v) << 8) & BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET1)
+#define BP_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_RSVD3 5
+#define BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_RSVD3 0x000000E0
+#define BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_RSVD3(v) \
+ (((v) << 5) & BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_RSVD3)
+#define BP_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET0 0
+#define BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET0 0x0000001F
+#define BF_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET0(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_SHIFT_OFFSET_CH1_OFFSET0)
+
+#define HW_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0 (0x00000960)
+#define HW_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_SET (0x00000964)
+#define HW_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_CLR (0x00000968)
+#define HW_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_TOG (0x0000096c)
+
+#define BP_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_RSVD0 16
+#define BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_RSVD0 0xFFFF0000
+#define BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_RSVD0(v) \
+ (((v) << 16) & BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_RSVD0)
+#define BP_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH3 12
+#define BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH3 0x0000F000
+#define BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH3(v) \
+ (((v) << 12) & BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH3)
+#define BP_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH2 8
+#define BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH2 0x00000F00
+#define BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH2(v) \
+ (((v) << 8) & BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH2)
+#define BP_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH1 4
+#define BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH1 0x000000F0
+#define BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH1(v) \
+ (((v) << 4) & BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH1)
+#define BP_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH0 0
+#define BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH0 0x0000000F
+#define BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH0(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH0_WIDTH0)
+
+#define HW_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1 (0x00000970)
+#define HW_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_SET (0x00000974)
+#define HW_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_CLR (0x00000978)
+#define HW_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_TOG (0x0000097c)
+
+#define BP_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_RSVD0 16
+#define BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_RSVD0 0xFFFF0000
+#define BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_RSVD0(v) \
+ (((v) << 16) & BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_RSVD0)
+#define BP_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH3 12
+#define BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH3 0x0000F000
+#define BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH3(v) \
+ (((v) << 12) & BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH3)
+#define BP_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH2 8
+#define BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH2 0x00000F00
+#define BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH2(v) \
+ (((v) << 8) & BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH2)
+#define BP_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH1 4
+#define BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH1 0x000000F0
+#define BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH1(v) \
+ (((v) << 4) & BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH1)
+#define BP_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH0 0
+#define BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH0 0x0000000F
+#define BF_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH0(v) \
+ (((v) << 0) & BM_PXP_DITHER_FETCH_SHIFT_WIDTH_CH1_WIDTH0)
+
+#define HW_PXP_DITHER_FETCH_ADDR_0_CH0 (0x00000980)
+
+#define BP_PXP_DITHER_FETCH_ADDR_0_CH0_INPUT_BASE_ADDR0 0
+#define BM_PXP_DITHER_FETCH_ADDR_0_CH0_INPUT_BASE_ADDR0 0xFFFFFFFF
+#define BF_PXP_DITHER_FETCH_ADDR_0_CH0_INPUT_BASE_ADDR0(v) (v)
+
+#define HW_PXP_DITHER_FETCH_ADDR_1_CH0 (0x00000990)
+
+#define BP_PXP_DITHER_FETCH_ADDR_1_CH0_INPUT_BASE_ADDR1 0
+#define BM_PXP_DITHER_FETCH_ADDR_1_CH0_INPUT_BASE_ADDR1 0xFFFFFFFF
+#define BF_PXP_DITHER_FETCH_ADDR_1_CH0_INPUT_BASE_ADDR1(v) (v)
+
+#define HW_PXP_DITHER_FETCH_ADDR_0_CH1 (0x000009a0)
+
+#define BP_PXP_DITHER_FETCH_ADDR_0_CH1_INPUT_BASE_ADDR0 0
+#define BM_PXP_DITHER_FETCH_ADDR_0_CH1_INPUT_BASE_ADDR0 0xFFFFFFFF
+#define BF_PXP_DITHER_FETCH_ADDR_0_CH1_INPUT_BASE_ADDR0(v) (v)
+
+#define HW_PXP_DITHER_FETCH_ADDR_1_CH1 (0x000009b0)
+
+#define BP_PXP_DITHER_FETCH_ADDR_1_CH1_INPUT_BASE_ADDR1 0
+#define BM_PXP_DITHER_FETCH_ADDR_1_CH1_INPUT_BASE_ADDR1 0xFFFFFFFF
+#define BF_PXP_DITHER_FETCH_ADDR_1_CH1_INPUT_BASE_ADDR1(v) (v)
+
+#define HW_PXP_DITHER_STORE_CTRL_CH0 (0x000009c0)
+#define HW_PXP_DITHER_STORE_CTRL_CH0_SET (0x000009c4)
+#define HW_PXP_DITHER_STORE_CTRL_CH0_CLR (0x000009c8)
+#define HW_PXP_DITHER_STORE_CTRL_CH0_TOG (0x000009cc)
+
+#define BM_PXP_DITHER_STORE_CTRL_CH0_ARBIT_EN 0x80000000
+#define BF_PXP_DITHER_STORE_CTRL_CH0_ARBIT_EN(v) \
+ (((v) << 31) & BM_PXP_DITHER_STORE_CTRL_CH0_ARBIT_EN)
+#define BV_PXP_DITHER_STORE_CTRL_CH0_ARBIT_EN__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH0_ARBIT_EN__1 0x1
+#define BP_PXP_DITHER_STORE_CTRL_CH0_RSVD0 25
+#define BM_PXP_DITHER_STORE_CTRL_CH0_RSVD0 0x7E000000
+#define BF_PXP_DITHER_STORE_CTRL_CH0_RSVD0(v) \
+ (((v) << 25) & BM_PXP_DITHER_STORE_CTRL_CH0_RSVD0)
+#define BM_PXP_DITHER_STORE_CTRL_CH0_COMBINE_2CHANNEL 0x01000000
+#define BF_PXP_DITHER_STORE_CTRL_CH0_COMBINE_2CHANNEL(v) \
+ (((v) << 24) & BM_PXP_DITHER_STORE_CTRL_CH0_COMBINE_2CHANNEL)
+#define BV_PXP_DITHER_STORE_CTRL_CH0_COMBINE_2CHANNEL__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH0_COMBINE_2CHANNEL__1 0x1
+#define BP_PXP_DITHER_STORE_CTRL_CH0_RSVD1 18
+#define BM_PXP_DITHER_STORE_CTRL_CH0_RSVD1 0x00FC0000
+#define BF_PXP_DITHER_STORE_CTRL_CH0_RSVD1(v) \
+ (((v) << 18) & BM_PXP_DITHER_STORE_CTRL_CH0_RSVD1)
+#define BP_PXP_DITHER_STORE_CTRL_CH0_WR_NUM_BYTES 16
+#define BM_PXP_DITHER_STORE_CTRL_CH0_WR_NUM_BYTES 0x00030000
+#define BF_PXP_DITHER_STORE_CTRL_CH0_WR_NUM_BYTES(v) \
+ (((v) << 16) & BM_PXP_DITHER_STORE_CTRL_CH0_WR_NUM_BYTES)
+#define BV_PXP_DITHER_STORE_CTRL_CH0_WR_NUM_BYTES__8_bytes 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH0_WR_NUM_BYTES__16_bytes 0x1
+#define BV_PXP_DITHER_STORE_CTRL_CH0_WR_NUM_BYTES__32_bytes 0x2
+#define BV_PXP_DITHER_STORE_CTRL_CH0_WR_NUM_BYTES__64_bytes 0x3
+#define BP_PXP_DITHER_STORE_CTRL_CH0_RSVD2 12
+#define BM_PXP_DITHER_STORE_CTRL_CH0_RSVD2 0x0000F000
+#define BF_PXP_DITHER_STORE_CTRL_CH0_RSVD2(v) \
+ (((v) << 12) & BM_PXP_DITHER_STORE_CTRL_CH0_RSVD2)
+#define BM_PXP_DITHER_STORE_CTRL_CH0_FILL_DATA_EN 0x00000800
+#define BF_PXP_DITHER_STORE_CTRL_CH0_FILL_DATA_EN(v) \
+ (((v) << 11) & BM_PXP_DITHER_STORE_CTRL_CH0_FILL_DATA_EN)
+#define BV_PXP_DITHER_STORE_CTRL_CH0_FILL_DATA_EN__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH0_FILL_DATA_EN__1 0x1
+#define BM_PXP_DITHER_STORE_CTRL_CH0_PACK_IN_SEL 0x00000400
+#define BF_PXP_DITHER_STORE_CTRL_CH0_PACK_IN_SEL(v) \
+ (((v) << 10) & BM_PXP_DITHER_STORE_CTRL_CH0_PACK_IN_SEL)
+#define BV_PXP_DITHER_STORE_CTRL_CH0_PACK_IN_SEL__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH0_PACK_IN_SEL__1 0x1
+#define BM_PXP_DITHER_STORE_CTRL_CH0_STORE_MEMORY_EN 0x00000200
+#define BF_PXP_DITHER_STORE_CTRL_CH0_STORE_MEMORY_EN(v) \
+ (((v) << 9) & BM_PXP_DITHER_STORE_CTRL_CH0_STORE_MEMORY_EN)
+#define BV_PXP_DITHER_STORE_CTRL_CH0_STORE_MEMORY_EN__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH0_STORE_MEMORY_EN__1 0x1
+#define BM_PXP_DITHER_STORE_CTRL_CH0_STORE_BYPASS_EN 0x00000100
+#define BF_PXP_DITHER_STORE_CTRL_CH0_STORE_BYPASS_EN(v) \
+ (((v) << 8) & BM_PXP_DITHER_STORE_CTRL_CH0_STORE_BYPASS_EN)
+#define BV_PXP_DITHER_STORE_CTRL_CH0_STORE_BYPASS_EN__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH0_STORE_BYPASS_EN__1 0x1
+#define BM_PXP_DITHER_STORE_CTRL_CH0_RSVD3 0x00000080
+#define BF_PXP_DITHER_STORE_CTRL_CH0_RSVD3(v) \
+ (((v) << 7) & BM_PXP_DITHER_STORE_CTRL_CH0_RSVD3)
+#define BP_PXP_DITHER_STORE_CTRL_CH0_ARRAY_LINE_NUM 5
+#define BM_PXP_DITHER_STORE_CTRL_CH0_ARRAY_LINE_NUM 0x00000060
+#define BF_PXP_DITHER_STORE_CTRL_CH0_ARRAY_LINE_NUM(v) \
+ (((v) << 5) & BM_PXP_DITHER_STORE_CTRL_CH0_ARRAY_LINE_NUM)
+#define BV_PXP_DITHER_STORE_CTRL_CH0_ARRAY_LINE_NUM__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH0_ARRAY_LINE_NUM__1 0x1
+#define BV_PXP_DITHER_STORE_CTRL_CH0_ARRAY_LINE_NUM__2 0x2
+#define BV_PXP_DITHER_STORE_CTRL_CH0_ARRAY_LINE_NUM__3 0x3
+#define BM_PXP_DITHER_STORE_CTRL_CH0_ARRAY_EN 0x00000010
+#define BF_PXP_DITHER_STORE_CTRL_CH0_ARRAY_EN(v) \
+ (((v) << 4) & BM_PXP_DITHER_STORE_CTRL_CH0_ARRAY_EN)
+#define BV_PXP_DITHER_STORE_CTRL_CH0_ARRAY_EN__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH0_ARRAY_EN__1 0x1
+#define BM_PXP_DITHER_STORE_CTRL_CH0_HANDSHAKE_EN 0x00000008
+#define BF_PXP_DITHER_STORE_CTRL_CH0_HANDSHAKE_EN(v) \
+ (((v) << 3) & BM_PXP_DITHER_STORE_CTRL_CH0_HANDSHAKE_EN)
+#define BV_PXP_DITHER_STORE_CTRL_CH0_HANDSHAKE_EN__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH0_HANDSHAKE_EN__1 0x1
+#define BM_PXP_DITHER_STORE_CTRL_CH0_BLOCK_16 0x00000004
+#define BF_PXP_DITHER_STORE_CTRL_CH0_BLOCK_16(v) \
+ (((v) << 2) & BM_PXP_DITHER_STORE_CTRL_CH0_BLOCK_16)
+#define BV_PXP_DITHER_STORE_CTRL_CH0_BLOCK_16__8x8 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH0_BLOCK_16__16x16 0x1
+#define BM_PXP_DITHER_STORE_CTRL_CH0_BLOCK_EN 0x00000002
+#define BF_PXP_DITHER_STORE_CTRL_CH0_BLOCK_EN(v) \
+ (((v) << 1) & BM_PXP_DITHER_STORE_CTRL_CH0_BLOCK_EN)
+#define BV_PXP_DITHER_STORE_CTRL_CH0_BLOCK_EN__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH0_BLOCK_EN__1 0x1
+#define BM_PXP_DITHER_STORE_CTRL_CH0_CH_EN 0x00000001
+#define BF_PXP_DITHER_STORE_CTRL_CH0_CH_EN(v) \
+ (((v) << 0) & BM_PXP_DITHER_STORE_CTRL_CH0_CH_EN)
+#define BV_PXP_DITHER_STORE_CTRL_CH0_CH_EN__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH0_CH_EN__1 0x1
+
+#define HW_PXP_DITHER_STORE_CTRL_CH1 (0x000009d0)
+#define HW_PXP_DITHER_STORE_CTRL_CH1_SET (0x000009d4)
+#define HW_PXP_DITHER_STORE_CTRL_CH1_CLR (0x000009d8)
+#define HW_PXP_DITHER_STORE_CTRL_CH1_TOG (0x000009dc)
+
+#define BP_PXP_DITHER_STORE_CTRL_CH1_RSVD0 18
+#define BM_PXP_DITHER_STORE_CTRL_CH1_RSVD0 0xFFFC0000
+#define BF_PXP_DITHER_STORE_CTRL_CH1_RSVD0(v) \
+ (((v) << 18) & BM_PXP_DITHER_STORE_CTRL_CH1_RSVD0)
+#define BP_PXP_DITHER_STORE_CTRL_CH1_WR_NUM_BYTES 16
+#define BM_PXP_DITHER_STORE_CTRL_CH1_WR_NUM_BYTES 0x00030000
+#define BF_PXP_DITHER_STORE_CTRL_CH1_WR_NUM_BYTES(v) \
+ (((v) << 16) & BM_PXP_DITHER_STORE_CTRL_CH1_WR_NUM_BYTES)
+#define BV_PXP_DITHER_STORE_CTRL_CH1_WR_NUM_BYTES__8_bytes 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH1_WR_NUM_BYTES__16_bytes 0x1
+#define BV_PXP_DITHER_STORE_CTRL_CH1_WR_NUM_BYTES__32_bytes 0x2
+#define BV_PXP_DITHER_STORE_CTRL_CH1_WR_NUM_BYTES__64_bytes 0x3
+#define BP_PXP_DITHER_STORE_CTRL_CH1_RSVD1 11
+#define BM_PXP_DITHER_STORE_CTRL_CH1_RSVD1 0x0000F800
+#define BF_PXP_DITHER_STORE_CTRL_CH1_RSVD1(v) \
+ (((v) << 11) & BM_PXP_DITHER_STORE_CTRL_CH1_RSVD1)
+#define BM_PXP_DITHER_STORE_CTRL_CH1_PACK_IN_SEL 0x00000400
+#define BF_PXP_DITHER_STORE_CTRL_CH1_PACK_IN_SEL(v) \
+ (((v) << 10) & BM_PXP_DITHER_STORE_CTRL_CH1_PACK_IN_SEL)
+#define BV_PXP_DITHER_STORE_CTRL_CH1_PACK_IN_SEL__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH1_PACK_IN_SEL__1 0x1
+#define BM_PXP_DITHER_STORE_CTRL_CH1_STORE_MEMORY_EN 0x00000200
+#define BF_PXP_DITHER_STORE_CTRL_CH1_STORE_MEMORY_EN(v) \
+ (((v) << 9) & BM_PXP_DITHER_STORE_CTRL_CH1_STORE_MEMORY_EN)
+#define BV_PXP_DITHER_STORE_CTRL_CH1_STORE_MEMORY_EN__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH1_STORE_MEMORY_EN__1 0x1
+#define BM_PXP_DITHER_STORE_CTRL_CH1_STORE_BYPASS_EN 0x00000100
+#define BF_PXP_DITHER_STORE_CTRL_CH1_STORE_BYPASS_EN(v) \
+ (((v) << 8) & BM_PXP_DITHER_STORE_CTRL_CH1_STORE_BYPASS_EN)
+#define BV_PXP_DITHER_STORE_CTRL_CH1_STORE_BYPASS_EN__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH1_STORE_BYPASS_EN__1 0x1
+#define BM_PXP_DITHER_STORE_CTRL_CH1_RSVD3 0x00000080
+#define BF_PXP_DITHER_STORE_CTRL_CH1_RSVD3(v) \
+ (((v) << 7) & BM_PXP_DITHER_STORE_CTRL_CH1_RSVD3)
+#define BP_PXP_DITHER_STORE_CTRL_CH1_ARRAY_LINE_NUM 5
+#define BM_PXP_DITHER_STORE_CTRL_CH1_ARRAY_LINE_NUM 0x00000060
+#define BF_PXP_DITHER_STORE_CTRL_CH1_ARRAY_LINE_NUM(v) \
+ (((v) << 5) & BM_PXP_DITHER_STORE_CTRL_CH1_ARRAY_LINE_NUM)
+#define BV_PXP_DITHER_STORE_CTRL_CH1_ARRAY_LINE_NUM__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH1_ARRAY_LINE_NUM__1 0x1
+#define BV_PXP_DITHER_STORE_CTRL_CH1_ARRAY_LINE_NUM__2 0x2
+#define BV_PXP_DITHER_STORE_CTRL_CH1_ARRAY_LINE_NUM__3 0x3
+#define BM_PXP_DITHER_STORE_CTRL_CH1_ARRAY_EN 0x00000010
+#define BF_PXP_DITHER_STORE_CTRL_CH1_ARRAY_EN(v) \
+ (((v) << 4) & BM_PXP_DITHER_STORE_CTRL_CH1_ARRAY_EN)
+#define BV_PXP_DITHER_STORE_CTRL_CH1_ARRAY_EN__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH1_ARRAY_EN__1 0x1
+#define BM_PXP_DITHER_STORE_CTRL_CH1_HANDSHAKE_EN 0x00000008
+#define BF_PXP_DITHER_STORE_CTRL_CH1_HANDSHAKE_EN(v) \
+ (((v) << 3) & BM_PXP_DITHER_STORE_CTRL_CH1_HANDSHAKE_EN)
+#define BV_PXP_DITHER_STORE_CTRL_CH1_HANDSHAKE_EN__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH1_HANDSHAKE_EN__1 0x1
+#define BM_PXP_DITHER_STORE_CTRL_CH1_BLOCK_16 0x00000004
+#define BF_PXP_DITHER_STORE_CTRL_CH1_BLOCK_16(v) \
+ (((v) << 2) & BM_PXP_DITHER_STORE_CTRL_CH1_BLOCK_16)
+#define BV_PXP_DITHER_STORE_CTRL_CH1_BLOCK_16__8x8 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH1_BLOCK_16__16x16 0x1
+#define BM_PXP_DITHER_STORE_CTRL_CH1_BLOCK_EN 0x00000002
+#define BF_PXP_DITHER_STORE_CTRL_CH1_BLOCK_EN(v) \
+ (((v) << 1) & BM_PXP_DITHER_STORE_CTRL_CH1_BLOCK_EN)
+#define BV_PXP_DITHER_STORE_CTRL_CH1_BLOCK_EN__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH1_BLOCK_EN__1 0x1
+#define BM_PXP_DITHER_STORE_CTRL_CH1_CH_EN 0x00000001
+#define BF_PXP_DITHER_STORE_CTRL_CH1_CH_EN(v) \
+ (((v) << 0) & BM_PXP_DITHER_STORE_CTRL_CH1_CH_EN)
+#define BV_PXP_DITHER_STORE_CTRL_CH1_CH_EN__0 0x0
+#define BV_PXP_DITHER_STORE_CTRL_CH1_CH_EN__1 0x1
+
+#define HW_PXP_DITHER_STORE_STATUS_CH0 (0x000009e0)
+
+#define BP_PXP_DITHER_STORE_STATUS_CH0_STORE_BLOCK_Y 16
+#define BM_PXP_DITHER_STORE_STATUS_CH0_STORE_BLOCK_Y 0xFFFF0000
+#define BF_PXP_DITHER_STORE_STATUS_CH0_STORE_BLOCK_Y(v) \
+ (((v) << 16) & BM_PXP_DITHER_STORE_STATUS_CH0_STORE_BLOCK_Y)
+#define BP_PXP_DITHER_STORE_STATUS_CH0_STORE_BLOCK_X 0
+#define BM_PXP_DITHER_STORE_STATUS_CH0_STORE_BLOCK_X 0x0000FFFF
+#define BF_PXP_DITHER_STORE_STATUS_CH0_STORE_BLOCK_X(v) \
+ (((v) << 0) & BM_PXP_DITHER_STORE_STATUS_CH0_STORE_BLOCK_X)
+
+#define HW_PXP_DITHER_STORE_STATUS_CH1 (0x000009f0)
+
+#define BP_PXP_DITHER_STORE_STATUS_CH1_STORE_BLOCK_Y 16
+#define BM_PXP_DITHER_STORE_STATUS_CH1_STORE_BLOCK_Y 0xFFFF0000
+#define BF_PXP_DITHER_STORE_STATUS_CH1_STORE_BLOCK_Y(v) \
+ (((v) << 16) & BM_PXP_DITHER_STORE_STATUS_CH1_STORE_BLOCK_Y)
+#define BP_PXP_DITHER_STORE_STATUS_CH1_STORE_BLOCK_X 0
+#define BM_PXP_DITHER_STORE_STATUS_CH1_STORE_BLOCK_X 0x0000FFFF
+#define BF_PXP_DITHER_STORE_STATUS_CH1_STORE_BLOCK_X(v) \
+ (((v) << 0) & BM_PXP_DITHER_STORE_STATUS_CH1_STORE_BLOCK_X)
+
+#define HW_PXP_DITHER_STORE_SIZE_CH0 (0x00000a00)
+
+#define BP_PXP_DITHER_STORE_SIZE_CH0_OUT_HEIGHT 16
+#define BM_PXP_DITHER_STORE_SIZE_CH0_OUT_HEIGHT 0xFFFF0000
+#define BF_PXP_DITHER_STORE_SIZE_CH0_OUT_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_DITHER_STORE_SIZE_CH0_OUT_HEIGHT)
+#define BP_PXP_DITHER_STORE_SIZE_CH0_OUT_WIDTH 0
+#define BM_PXP_DITHER_STORE_SIZE_CH0_OUT_WIDTH 0x0000FFFF
+#define BF_PXP_DITHER_STORE_SIZE_CH0_OUT_WIDTH(v) \
+ (((v) << 0) & BM_PXP_DITHER_STORE_SIZE_CH0_OUT_WIDTH)
+
+#define HW_PXP_DITHER_STORE_SIZE_CH1 (0x00000a10)
+
+#define BP_PXP_DITHER_STORE_SIZE_CH1_OUT_HEIGHT 16
+#define BM_PXP_DITHER_STORE_SIZE_CH1_OUT_HEIGHT 0xFFFF0000
+#define BF_PXP_DITHER_STORE_SIZE_CH1_OUT_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_DITHER_STORE_SIZE_CH1_OUT_HEIGHT)
+#define BP_PXP_DITHER_STORE_SIZE_CH1_OUT_WIDTH 0
+#define BM_PXP_DITHER_STORE_SIZE_CH1_OUT_WIDTH 0x0000FFFF
+#define BF_PXP_DITHER_STORE_SIZE_CH1_OUT_WIDTH(v) \
+ (((v) << 0) & BM_PXP_DITHER_STORE_SIZE_CH1_OUT_WIDTH)
+
+#define HW_PXP_DITHER_STORE_PITCH (0x00000a20)
+
+#define BP_PXP_DITHER_STORE_PITCH_CH1_OUT_PITCH 16
+#define BM_PXP_DITHER_STORE_PITCH_CH1_OUT_PITCH 0xFFFF0000
+#define BF_PXP_DITHER_STORE_PITCH_CH1_OUT_PITCH(v) \
+ (((v) << 16) & BM_PXP_DITHER_STORE_PITCH_CH1_OUT_PITCH)
+#define BP_PXP_DITHER_STORE_PITCH_CH0_OUT_PITCH 0
+#define BM_PXP_DITHER_STORE_PITCH_CH0_OUT_PITCH 0x0000FFFF
+#define BF_PXP_DITHER_STORE_PITCH_CH0_OUT_PITCH(v) \
+ (((v) << 0) & BM_PXP_DITHER_STORE_PITCH_CH0_OUT_PITCH)
+
+#define HW_PXP_DITHER_STORE_SHIFT_CTRL_CH0 (0x00000a30)
+#define HW_PXP_DITHER_STORE_SHIFT_CTRL_CH0_SET (0x00000a34)
+#define HW_PXP_DITHER_STORE_SHIFT_CTRL_CH0_CLR (0x00000a38)
+#define HW_PXP_DITHER_STORE_SHIFT_CTRL_CH0_TOG (0x00000a3c)
+
+#define BP_PXP_DITHER_STORE_SHIFT_CTRL_CH0_RSVD0 8
+#define BM_PXP_DITHER_STORE_SHIFT_CTRL_CH0_RSVD0 0xFFFFFF00
+#define BF_PXP_DITHER_STORE_SHIFT_CTRL_CH0_RSVD0(v) \
+ (((v) << 8) & BM_PXP_DITHER_STORE_SHIFT_CTRL_CH0_RSVD0)
+#define BM_PXP_DITHER_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS 0x00000080
+#define BF_PXP_DITHER_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS(v) \
+ (((v) << 7) & BM_PXP_DITHER_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS)
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS__0 0x0
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS__1 0x1
+#define BM_PXP_DITHER_STORE_SHIFT_CTRL_CH0_RSVD1 0x00000040
+#define BF_PXP_DITHER_STORE_SHIFT_CTRL_CH0_RSVD1(v) \
+ (((v) << 6) & BM_PXP_DITHER_STORE_SHIFT_CTRL_CH0_RSVD1)
+#define BM_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN 0x00000020
+#define BF_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN(v) \
+ (((v) << 5) & BM_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN)
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN__0 0x0
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN__1 0x1
+#define BM_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN 0x00000010
+#define BF_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN(v) \
+ (((v) << 4) & BM_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN)
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN__0 0x0
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN__1 0x1
+#define BP_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP 2
+#define BM_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP 0x0000000C
+#define BF_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP(v) \
+ (((v) << 2) & BM_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP)
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP__0 0x0
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP__1 0x1
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP__2 0x2
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP__3 0x3
+#define BP_PXP_DITHER_STORE_SHIFT_CTRL_CH0_RSVD2 0
+#define BM_PXP_DITHER_STORE_SHIFT_CTRL_CH0_RSVD2 0x00000003
+#define BF_PXP_DITHER_STORE_SHIFT_CTRL_CH0_RSVD2(v) \
+ (((v) << 0) & BM_PXP_DITHER_STORE_SHIFT_CTRL_CH0_RSVD2)
+
+#define HW_PXP_DITHER_STORE_SHIFT_CTRL_CH1 (0x00000a40)
+#define HW_PXP_DITHER_STORE_SHIFT_CTRL_CH1_SET (0x00000a44)
+#define HW_PXP_DITHER_STORE_SHIFT_CTRL_CH1_CLR (0x00000a48)
+#define HW_PXP_DITHER_STORE_SHIFT_CTRL_CH1_TOG (0x00000a4c)
+
+#define BP_PXP_DITHER_STORE_SHIFT_CTRL_CH1_RSVD0 6
+#define BM_PXP_DITHER_STORE_SHIFT_CTRL_CH1_RSVD0 0xFFFFFFC0
+#define BF_PXP_DITHER_STORE_SHIFT_CTRL_CH1_RSVD0(v) \
+ (((v) << 6) & BM_PXP_DITHER_STORE_SHIFT_CTRL_CH1_RSVD0)
+#define BM_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN 0x00000020
+#define BF_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN(v) \
+ (((v) << 5) & BM_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN)
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN__0 0x0
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN__1 0x1
+#define BM_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN 0x00000010
+#define BF_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN(v) \
+ (((v) << 4) & BM_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN)
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN__0 0x0
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN__1 0x1
+#define BP_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP 2
+#define BM_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP 0x0000000C
+#define BF_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP(v) \
+ (((v) << 2) & BM_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP)
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP__0 0x0
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP__1 0x1
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP__2 0x2
+#define BV_PXP_DITHER_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP__3 0x3
+#define BP_PXP_DITHER_STORE_SHIFT_CTRL_CH1_RSVD2 0
+#define BM_PXP_DITHER_STORE_SHIFT_CTRL_CH1_RSVD2 0x00000003
+#define BF_PXP_DITHER_STORE_SHIFT_CTRL_CH1_RSVD2(v) \
+ (((v) << 0) & BM_PXP_DITHER_STORE_SHIFT_CTRL_CH1_RSVD2)
+
+#define HW_PXP_DITHER_STORE_ADDR_0_CH0 (0x00000a90)
+
+#define BP_PXP_DITHER_STORE_ADDR_0_CH0_OUT_BASE_ADDR0 0
+#define BM_PXP_DITHER_STORE_ADDR_0_CH0_OUT_BASE_ADDR0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_ADDR_0_CH0_OUT_BASE_ADDR0(v) (v)
+
+#define HW_PXP_DITHER_STORE_ADDR_1_CH0 (0x00000aa0)
+
+#define BP_PXP_DITHER_STORE_ADDR_1_CH0_OUT_BASE_ADDR1 0
+#define BM_PXP_DITHER_STORE_ADDR_1_CH0_OUT_BASE_ADDR1 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_ADDR_1_CH0_OUT_BASE_ADDR1(v) (v)
+
+#define HW_PXP_DITHER_STORE_FILL_DATA_CH0 (0x00000ab0)
+
+#define BP_PXP_DITHER_STORE_FILL_DATA_CH0_FILL_DATA_CH0 0
+#define BM_PXP_DITHER_STORE_FILL_DATA_CH0_FILL_DATA_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_FILL_DATA_CH0_FILL_DATA_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_ADDR_0_CH1 (0x00000ac0)
+
+#define BP_PXP_DITHER_STORE_ADDR_0_CH1_OUT_BASE_ADDR0 0
+#define BM_PXP_DITHER_STORE_ADDR_0_CH1_OUT_BASE_ADDR0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_ADDR_0_CH1_OUT_BASE_ADDR0(v) (v)
+
+#define HW_PXP_DITHER_STORE_ADDR_1_CH1 (0x00000ad0)
+
+#define BP_PXP_DITHER_STORE_ADDR_1_CH1_OUT_BASE_ADDR1 0
+#define BM_PXP_DITHER_STORE_ADDR_1_CH1_OUT_BASE_ADDR1 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_ADDR_1_CH1_OUT_BASE_ADDR1(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_MASK0_H_CH0 (0x00000ae0)
+
+#define BP_PXP_DITHER_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0 0
+#define BM_PXP_DITHER_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_MASK0_L_CH0 (0x00000af0)
+
+#define BP_PXP_DITHER_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0 0
+#define BM_PXP_DITHER_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_MASK1_H_CH0 (0x00000b00)
+
+#define BP_PXP_DITHER_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0 0
+#define BM_PXP_DITHER_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_MASK1_L_CH0 (0x00000b10)
+
+#define BP_PXP_DITHER_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0 0
+#define BM_PXP_DITHER_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_MASK2_H_CH0 (0x00000b20)
+
+#define BP_PXP_DITHER_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0 0
+#define BM_PXP_DITHER_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_MASK2_L_CH0 (0x00000b30)
+
+#define BP_PXP_DITHER_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0 0
+#define BM_PXP_DITHER_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_MASK3_H_CH0 (0x00000b40)
+
+#define BP_PXP_DITHER_STORE_D_MASK3_H_CH0_D_MASK3_H_CH0 0
+#define BM_PXP_DITHER_STORE_D_MASK3_H_CH0_D_MASK3_H_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_D_MASK3_H_CH0_D_MASK3_H_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_MASK3_L_CH0 (0x00000b50)
+
+#define BP_PXP_DITHER_STORE_D_MASK3_L_CH0_D_MASK3_L_CH0 0
+#define BM_PXP_DITHER_STORE_D_MASK3_L_CH0_D_MASK3_L_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_D_MASK3_L_CH0_D_MASK3_L_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_MASK4_H_CH0 (0x00000b60)
+
+#define BP_PXP_DITHER_STORE_D_MASK4_H_CH0_D_MASK4_H_CH0 0
+#define BM_PXP_DITHER_STORE_D_MASK4_H_CH0_D_MASK4_H_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_D_MASK4_H_CH0_D_MASK4_H_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_MASK4_L_CH0 (0x00000b70)
+
+#define BP_PXP_DITHER_STORE_D_MASK4_L_CH0_D_MASK4_L_CH0 0
+#define BM_PXP_DITHER_STORE_D_MASK4_L_CH0_D_MASK4_L_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_D_MASK4_L_CH0_D_MASK4_L_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_MASK5_H_CH0 (0x00000b80)
+
+#define BP_PXP_DITHER_STORE_D_MASK5_H_CH0_D_MASK5_H_CH0 0
+#define BM_PXP_DITHER_STORE_D_MASK5_H_CH0_D_MASK5_H_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_D_MASK5_H_CH0_D_MASK5_H_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_MASK5_L_CH0 (0x00000b90)
+
+#define BP_PXP_DITHER_STORE_D_MASK5_L_CH0_D_MASK5_L_CH0 0
+#define BM_PXP_DITHER_STORE_D_MASK5_L_CH0_D_MASK5_L_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_D_MASK5_L_CH0_D_MASK5_L_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_MASK6_H_CH0 (0x00000ba0)
+
+#define BP_PXP_DITHER_STORE_D_MASK6_H_CH0_D_MASK6_H_CH0 0
+#define BM_PXP_DITHER_STORE_D_MASK6_H_CH0_D_MASK6_H_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_D_MASK6_H_CH0_D_MASK6_H_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_MASK6_L_CH0 (0x00000bb0)
+
+#define BP_PXP_DITHER_STORE_D_MASK6_L_CH0_D_MASK6_L_CH0 0
+#define BM_PXP_DITHER_STORE_D_MASK6_L_CH0_D_MASK6_L_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_D_MASK6_L_CH0_D_MASK6_L_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_MASK7_H_CH0 (0x00000bc0)
+
+#define BP_PXP_DITHER_STORE_D_MASK7_H_CH0_D_MASK7_H_CH0 0
+#define BM_PXP_DITHER_STORE_D_MASK7_H_CH0_D_MASK7_H_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_D_MASK7_H_CH0_D_MASK7_H_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_MASK7_L_CH0 (0x00000bd0)
+
+#define BP_PXP_DITHER_STORE_D_MASK7_L_CH0_D_MASK7_L_CH0 0
+#define BM_PXP_DITHER_STORE_D_MASK7_L_CH0_D_MASK7_L_CH0 0xFFFFFFFF
+#define BF_PXP_DITHER_STORE_D_MASK7_L_CH0_D_MASK7_L_CH0(v) (v)
+
+#define HW_PXP_DITHER_STORE_D_SHIFT_L_CH0 (0x00000be0)
+
+#define BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3 0x80000000
+#define BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3(v) \
+ (((v) << 31) & BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3)
+#define BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_RSVD0 0x40000000
+#define BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_RSVD0)
+#define BP_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3 24
+#define BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3 0x3F000000
+#define BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3(v) \
+ (((v) << 24) & BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3)
+#define BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2 0x00800000
+#define BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2(v) \
+ (((v) << 23) & BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2)
+#define BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_RSVD1 0x00400000
+#define BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_RSVD1)
+#define BP_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2 16
+#define BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2 0x003F0000
+#define BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2(v) \
+ (((v) << 16) & BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2)
+#define BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1 0x00008000
+#define BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1(v) \
+ (((v) << 15) & BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1)
+#define BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_RSVD2 0x00004000
+#define BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_RSVD2)
+#define BP_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1 8
+#define BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1 0x00003F00
+#define BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1(v) \
+ (((v) << 8) & BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1)
+#define BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0 0x00000080
+#define BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0(v) \
+ (((v) << 7) & BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0)
+#define BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_RSVD3 0x00000040
+#define BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_RSVD3)
+#define BP_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0 0
+#define BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0 0x0000003F
+#define BF_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0(v) \
+ (((v) << 0) & BM_PXP_DITHER_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0)
+
+#define HW_PXP_DITHER_STORE_D_SHIFT_H_CH0 (0x00000bf0)
+
+#define BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG7 0x80000000
+#define BF_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG7(v) \
+ (((v) << 31) & BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG7)
+#define BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_RSVD0 0x40000000
+#define BF_PXP_DITHER_STORE_D_SHIFT_H_CH0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_RSVD0)
+#define BP_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7 24
+#define BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7 0x3F000000
+#define BF_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7(v) \
+ (((v) << 24) & BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7)
+#define BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG6 0x00800000
+#define BF_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG6(v) \
+ (((v) << 23) & BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG6)
+#define BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_RSVD1 0x00400000
+#define BF_PXP_DITHER_STORE_D_SHIFT_H_CH0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_RSVD1)
+#define BP_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6 16
+#define BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6 0x003F0000
+#define BF_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6(v) \
+ (((v) << 16) & BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6)
+#define BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG5 0x00008000
+#define BF_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG5(v) \
+ (((v) << 15) & BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG5)
+#define BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_RSVD2 0x00004000
+#define BF_PXP_DITHER_STORE_D_SHIFT_H_CH0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_RSVD2)
+#define BP_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5 8
+#define BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5 0x00003F00
+#define BF_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5(v) \
+ (((v) << 8) & BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5)
+#define BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG4 0x00000080
+#define BF_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG4(v) \
+ (((v) << 7) & BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG4)
+#define BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_RSVD3 0x00000040
+#define BF_PXP_DITHER_STORE_D_SHIFT_H_CH0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_RSVD3)
+#define BP_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4 0
+#define BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4 0x0000003F
+#define BF_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4(v) \
+ (((v) << 0) & BM_PXP_DITHER_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4)
+
+#define HW_PXP_DITHER_STORE_F_SHIFT_L_CH0 (0x00000c00)
+
+#define BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_RSVD0 0x80000000
+#define BF_PXP_DITHER_STORE_F_SHIFT_L_CH0_RSVD0(v) \
+ (((v) << 31) & BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_RSVD0)
+#define BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3 0x40000000
+#define BF_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3(v) \
+ (((v) << 30) & BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3)
+#define BP_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3 24
+#define BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3 0x3F000000
+#define BF_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3(v) \
+ (((v) << 24) & BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3)
+#define BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_RSVD1 0x00800000
+#define BF_PXP_DITHER_STORE_F_SHIFT_L_CH0_RSVD1(v) \
+ (((v) << 23) & BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_RSVD1)
+#define BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2 0x00400000
+#define BF_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2(v) \
+ (((v) << 22) & BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2)
+#define BP_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2 16
+#define BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2 0x003F0000
+#define BF_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2(v) \
+ (((v) << 16) & BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2)
+#define BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_RSVD2 0x00008000
+#define BF_PXP_DITHER_STORE_F_SHIFT_L_CH0_RSVD2(v) \
+ (((v) << 15) & BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_RSVD2)
+#define BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1 0x00004000
+#define BF_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1(v) \
+ (((v) << 14) & BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1)
+#define BP_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1 8
+#define BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1 0x00003F00
+#define BF_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1(v) \
+ (((v) << 8) & BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1)
+#define BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_RSVD3 0x00000080
+#define BF_PXP_DITHER_STORE_F_SHIFT_L_CH0_RSVD3(v) \
+ (((v) << 7) & BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_RSVD3)
+#define BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0 0x00000040
+#define BF_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0(v) \
+ (((v) << 6) & BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0)
+#define BP_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0 0
+#define BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0 0x0000003F
+#define BF_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0(v) \
+ (((v) << 0) & BM_PXP_DITHER_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0)
+
+#define HW_PXP_DITHER_STORE_F_SHIFT_H_CH0 (0x00000c10)
+
+#define BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_RSVD0 0x80000000
+#define BF_PXP_DITHER_STORE_F_SHIFT_H_CH0_RSVD0(v) \
+ (((v) << 31) & BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_RSVD0)
+#define BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG7 0x40000000
+#define BF_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG7(v) \
+ (((v) << 30) & BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG7)
+#define BP_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7 24
+#define BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7 0x3F000000
+#define BF_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7(v) \
+ (((v) << 24) & BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7)
+#define BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_RSVD1 0x00800000
+#define BF_PXP_DITHER_STORE_F_SHIFT_H_CH0_RSVD1(v) \
+ (((v) << 23) & BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_RSVD1)
+#define BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG6 0x00400000
+#define BF_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG6(v) \
+ (((v) << 22) & BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG6)
+#define BP_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6 16
+#define BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6 0x003F0000
+#define BF_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6(v) \
+ (((v) << 16) & BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6)
+#define BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_RSVD2 0x00008000
+#define BF_PXP_DITHER_STORE_F_SHIFT_H_CH0_RSVD2(v) \
+ (((v) << 15) & BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_RSVD2)
+#define BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG5 0x00004000
+#define BF_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG5(v) \
+ (((v) << 14) & BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG5)
+#define BP_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5 8
+#define BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5 0x00003F00
+#define BF_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5(v) \
+ (((v) << 8) & BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5)
+#define BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_RSVD3 0x00000080
+#define BF_PXP_DITHER_STORE_F_SHIFT_H_CH0_RSVD3(v) \
+ (((v) << 7) & BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_RSVD3)
+#define BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG4 0x00000040
+#define BF_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG4(v) \
+ (((v) << 6) & BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG4)
+#define BP_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4 0
+#define BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4 0x0000003F
+#define BF_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4(v) \
+ (((v) << 0) & BM_PXP_DITHER_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4)
+
+#define HW_PXP_DITHER_STORE_F_MASK_L_CH0 (0x00000c20)
+
+#define BP_PXP_DITHER_STORE_F_MASK_L_CH0_F_MASK3 24
+#define BM_PXP_DITHER_STORE_F_MASK_L_CH0_F_MASK3 0xFF000000
+#define BF_PXP_DITHER_STORE_F_MASK_L_CH0_F_MASK3(v) \
+ (((v) << 24) & BM_PXP_DITHER_STORE_F_MASK_L_CH0_F_MASK3)
+#define BP_PXP_DITHER_STORE_F_MASK_L_CH0_F_MASK2 16
+#define BM_PXP_DITHER_STORE_F_MASK_L_CH0_F_MASK2 0x00FF0000
+#define BF_PXP_DITHER_STORE_F_MASK_L_CH0_F_MASK2(v) \
+ (((v) << 16) & BM_PXP_DITHER_STORE_F_MASK_L_CH0_F_MASK2)
+#define BP_PXP_DITHER_STORE_F_MASK_L_CH0_F_MASK1 8
+#define BM_PXP_DITHER_STORE_F_MASK_L_CH0_F_MASK1 0x0000FF00
+#define BF_PXP_DITHER_STORE_F_MASK_L_CH0_F_MASK1(v) \
+ (((v) << 8) & BM_PXP_DITHER_STORE_F_MASK_L_CH0_F_MASK1)
+#define BP_PXP_DITHER_STORE_F_MASK_L_CH0_F_MASK0 0
+#define BM_PXP_DITHER_STORE_F_MASK_L_CH0_F_MASK0 0x000000FF
+#define BF_PXP_DITHER_STORE_F_MASK_L_CH0_F_MASK0(v) \
+ (((v) << 0) & BM_PXP_DITHER_STORE_F_MASK_L_CH0_F_MASK0)
+
+#define HW_PXP_DITHER_STORE_F_MASK_H_CH0 (0x00000c30)
+
+#define BP_PXP_DITHER_STORE_F_MASK_H_CH0_F_MASK7 24
+#define BM_PXP_DITHER_STORE_F_MASK_H_CH0_F_MASK7 0xFF000000
+#define BF_PXP_DITHER_STORE_F_MASK_H_CH0_F_MASK7(v) \
+ (((v) << 24) & BM_PXP_DITHER_STORE_F_MASK_H_CH0_F_MASK7)
+#define BP_PXP_DITHER_STORE_F_MASK_H_CH0_F_MASK6 16
+#define BM_PXP_DITHER_STORE_F_MASK_H_CH0_F_MASK6 0x00FF0000
+#define BF_PXP_DITHER_STORE_F_MASK_H_CH0_F_MASK6(v) \
+ (((v) << 16) & BM_PXP_DITHER_STORE_F_MASK_H_CH0_F_MASK6)
+#define BP_PXP_DITHER_STORE_F_MASK_H_CH0_F_MASK5 8
+#define BM_PXP_DITHER_STORE_F_MASK_H_CH0_F_MASK5 0x0000FF00
+#define BF_PXP_DITHER_STORE_F_MASK_H_CH0_F_MASK5(v) \
+ (((v) << 8) & BM_PXP_DITHER_STORE_F_MASK_H_CH0_F_MASK5)
+#define BP_PXP_DITHER_STORE_F_MASK_H_CH0_F_MASK4 0
+#define BM_PXP_DITHER_STORE_F_MASK_H_CH0_F_MASK4 0x000000FF
+#define BF_PXP_DITHER_STORE_F_MASK_H_CH0_F_MASK4(v) \
+ (((v) << 0) & BM_PXP_DITHER_STORE_F_MASK_H_CH0_F_MASK4)
+
+#define HW_PXP_WFA_FETCH_CTRL (0x00000c40)
+#define HW_PXP_WFA_FETCH_CTRL_SET (0x00000c44)
+#define HW_PXP_WFA_FETCH_CTRL_CLR (0x00000c48)
+#define HW_PXP_WFA_FETCH_CTRL_TOG (0x00000c4c)
+
+#define BM_PXP_WFA_FETCH_CTRL_BUF2_DONE_IRQ_EN 0x80000000
+#define BF_PXP_WFA_FETCH_CTRL_BUF2_DONE_IRQ_EN(v) \
+ (((v) << 31) & BM_PXP_WFA_FETCH_CTRL_BUF2_DONE_IRQ_EN)
+#define BM_PXP_WFA_FETCH_CTRL_BUF1_DONE_IRQ_EN 0x40000000
+#define BF_PXP_WFA_FETCH_CTRL_BUF1_DONE_IRQ_EN(v) \
+ (((v) << 30) & BM_PXP_WFA_FETCH_CTRL_BUF1_DONE_IRQ_EN)
+#define BM_PXP_WFA_FETCH_CTRL_BUF2_DONE_IRQ 0x20000000
+#define BF_PXP_WFA_FETCH_CTRL_BUF2_DONE_IRQ(v) \
+ (((v) << 29) & BM_PXP_WFA_FETCH_CTRL_BUF2_DONE_IRQ)
+#define BM_PXP_WFA_FETCH_CTRL_BUF1_DONE_IRQ 0x10000000
+#define BF_PXP_WFA_FETCH_CTRL_BUF1_DONE_IRQ(v) \
+ (((v) << 28) & BM_PXP_WFA_FETCH_CTRL_BUF1_DONE_IRQ)
+#define BP_PXP_WFA_FETCH_CTRL_RSVD0 24
+#define BM_PXP_WFA_FETCH_CTRL_RSVD0 0x0F000000
+#define BF_PXP_WFA_FETCH_CTRL_RSVD0(v) \
+ (((v) << 24) & BM_PXP_WFA_FETCH_CTRL_RSVD0)
+#define BP_PXP_WFA_FETCH_CTRL_BF2_LINE_MODE 22
+#define BM_PXP_WFA_FETCH_CTRL_BF2_LINE_MODE 0x00C00000
+#define BF_PXP_WFA_FETCH_CTRL_BF2_LINE_MODE(v) \
+ (((v) << 22) & BM_PXP_WFA_FETCH_CTRL_BF2_LINE_MODE)
+#define BV_PXP_WFA_FETCH_CTRL_BF2_LINE_MODE__0 0x0
+#define BV_PXP_WFA_FETCH_CTRL_BF2_LINE_MODE__1 0x1
+#define BV_PXP_WFA_FETCH_CTRL_BF2_LINE_MODE__2 0x2
+#define BV_PXP_WFA_FETCH_CTRL_BF2_LINE_MODE__3 0x3
+#define BP_PXP_WFA_FETCH_CTRL_BF2_BYTES_PP 20
+#define BM_PXP_WFA_FETCH_CTRL_BF2_BYTES_PP 0x00300000
+#define BF_PXP_WFA_FETCH_CTRL_BF2_BYTES_PP(v) \
+ (((v) << 20) & BM_PXP_WFA_FETCH_CTRL_BF2_BYTES_PP)
+#define BP_PXP_WFA_FETCH_CTRL_BF1_LINE_MODE 18
+#define BM_PXP_WFA_FETCH_CTRL_BF1_LINE_MODE 0x000C0000
+#define BF_PXP_WFA_FETCH_CTRL_BF1_LINE_MODE(v) \
+ (((v) << 18) & BM_PXP_WFA_FETCH_CTRL_BF1_LINE_MODE)
+#define BV_PXP_WFA_FETCH_CTRL_BF1_LINE_MODE__0 0x0
+#define BV_PXP_WFA_FETCH_CTRL_BF1_LINE_MODE__1 0x1
+#define BV_PXP_WFA_FETCH_CTRL_BF1_LINE_MODE__2 0x2
+#define BV_PXP_WFA_FETCH_CTRL_BF1_LINE_MODE__3 0x3
+#define BP_PXP_WFA_FETCH_CTRL_BF1_BYTES_PP 16
+#define BM_PXP_WFA_FETCH_CTRL_BF1_BYTES_PP 0x00030000
+#define BF_PXP_WFA_FETCH_CTRL_BF1_BYTES_PP(v) \
+ (((v) << 16) & BM_PXP_WFA_FETCH_CTRL_BF1_BYTES_PP)
+#define BP_PXP_WFA_FETCH_CTRL_RSVD1 14
+#define BM_PXP_WFA_FETCH_CTRL_RSVD1 0x0000C000
+#define BF_PXP_WFA_FETCH_CTRL_RSVD1(v) \
+ (((v) << 14) & BM_PXP_WFA_FETCH_CTRL_RSVD1)
+#define BM_PXP_WFA_FETCH_CTRL_BF2_BORDER_MODE 0x00002000
+#define BF_PXP_WFA_FETCH_CTRL_BF2_BORDER_MODE(v) \
+ (((v) << 13) & BM_PXP_WFA_FETCH_CTRL_BF2_BORDER_MODE)
+#define BV_PXP_WFA_FETCH_CTRL_BF2_BORDER_MODE__0 0x0
+#define BV_PXP_WFA_FETCH_CTRL_BF2_BORDER_MODE__1 0x1
+#define BM_PXP_WFA_FETCH_CTRL_BF2_BURST_LEN 0x00001000
+#define BF_PXP_WFA_FETCH_CTRL_BF2_BURST_LEN(v) \
+ (((v) << 12) & BM_PXP_WFA_FETCH_CTRL_BF2_BURST_LEN)
+#define BV_PXP_WFA_FETCH_CTRL_BF2_BURST_LEN__0 0x0
+#define BV_PXP_WFA_FETCH_CTRL_BF2_BURST_LEN__1 0x1
+#define BM_PXP_WFA_FETCH_CTRL_BF2_BYPASS_MODE 0x00000800
+#define BF_PXP_WFA_FETCH_CTRL_BF2_BYPASS_MODE(v) \
+ (((v) << 11) & BM_PXP_WFA_FETCH_CTRL_BF2_BYPASS_MODE)
+#define BV_PXP_WFA_FETCH_CTRL_BF2_BYPASS_MODE__0 0x0
+#define BV_PXP_WFA_FETCH_CTRL_BF2_BYPASS_MODE__1 0x1
+#define BM_PXP_WFA_FETCH_CTRL_BF2_HSK_MODE 0x00000400
+#define BF_PXP_WFA_FETCH_CTRL_BF2_HSK_MODE(v) \
+ (((v) << 10) & BM_PXP_WFA_FETCH_CTRL_BF2_HSK_MODE)
+#define BV_PXP_WFA_FETCH_CTRL_BF2_HSK_MODE__0 0x0
+#define BV_PXP_WFA_FETCH_CTRL_BF2_HSK_MODE__1 0x1
+#define BM_PXP_WFA_FETCH_CTRL_BF2_SRAM_IF 0x00000200
+#define BF_PXP_WFA_FETCH_CTRL_BF2_SRAM_IF(v) \
+ (((v) << 9) & BM_PXP_WFA_FETCH_CTRL_BF2_SRAM_IF)
+#define BV_PXP_WFA_FETCH_CTRL_BF2_SRAM_IF__0 0x0
+#define BV_PXP_WFA_FETCH_CTRL_BF2_SRAM_IF__1 0x1
+#define BM_PXP_WFA_FETCH_CTRL_BF2_EN 0x00000100
+#define BF_PXP_WFA_FETCH_CTRL_BF2_EN(v) \
+ (((v) << 8) & BM_PXP_WFA_FETCH_CTRL_BF2_EN)
+#define BV_PXP_WFA_FETCH_CTRL_BF2_EN__0 0x0
+#define BV_PXP_WFA_FETCH_CTRL_BF2_EN__1 0x1
+#define BP_PXP_WFA_FETCH_CTRL_RSVD2 6
+#define BM_PXP_WFA_FETCH_CTRL_RSVD2 0x000000C0
+#define BF_PXP_WFA_FETCH_CTRL_RSVD2(v) \
+ (((v) << 6) & BM_PXP_WFA_FETCH_CTRL_RSVD2)
+#define BM_PXP_WFA_FETCH_CTRL_BF1_BORDER_MODE 0x00000020
+#define BF_PXP_WFA_FETCH_CTRL_BF1_BORDER_MODE(v) \
+ (((v) << 5) & BM_PXP_WFA_FETCH_CTRL_BF1_BORDER_MODE)
+#define BV_PXP_WFA_FETCH_CTRL_BF1_BORDER_MODE__0 0x0
+#define BV_PXP_WFA_FETCH_CTRL_BF1_BORDER_MODE__1 0x1
+#define BM_PXP_WFA_FETCH_CTRL_BF1_BURST_LEN 0x00000010
+#define BF_PXP_WFA_FETCH_CTRL_BF1_BURST_LEN(v) \
+ (((v) << 4) & BM_PXP_WFA_FETCH_CTRL_BF1_BURST_LEN)
+#define BV_PXP_WFA_FETCH_CTRL_BF1_BURST_LEN__0 0x0
+#define BV_PXP_WFA_FETCH_CTRL_BF1_BURST_LEN__1 0x1
+#define BM_PXP_WFA_FETCH_CTRL_BF1_BYPASS_MODE 0x00000008
+#define BF_PXP_WFA_FETCH_CTRL_BF1_BYPASS_MODE(v) \
+ (((v) << 3) & BM_PXP_WFA_FETCH_CTRL_BF1_BYPASS_MODE)
+#define BV_PXP_WFA_FETCH_CTRL_BF1_BYPASS_MODE__0 0x0
+#define BV_PXP_WFA_FETCH_CTRL_BF1_BYPASS_MODE__1 0x1
+#define BM_PXP_WFA_FETCH_CTRL_BF1_HSK_MODE 0x00000004
+#define BF_PXP_WFA_FETCH_CTRL_BF1_HSK_MODE(v) \
+ (((v) << 2) & BM_PXP_WFA_FETCH_CTRL_BF1_HSK_MODE)
+#define BV_PXP_WFA_FETCH_CTRL_BF1_HSK_MODE__0 0x0
+#define BV_PXP_WFA_FETCH_CTRL_BF1_HSK_MODE__1 0x1
+#define BM_PXP_WFA_FETCH_CTRL_BF1_SRAM_IF 0x00000002
+#define BF_PXP_WFA_FETCH_CTRL_BF1_SRAM_IF(v) \
+ (((v) << 1) & BM_PXP_WFA_FETCH_CTRL_BF1_SRAM_IF)
+#define BV_PXP_WFA_FETCH_CTRL_BF1_SRAM_IF__0 0x0
+#define BV_PXP_WFA_FETCH_CTRL_BF1_SRAM_IF__1 0x1
+#define BM_PXP_WFA_FETCH_CTRL_BF1_EN 0x00000001
+#define BF_PXP_WFA_FETCH_CTRL_BF1_EN(v) \
+ (((v) << 0) & BM_PXP_WFA_FETCH_CTRL_BF1_EN)
+#define BV_PXP_WFA_FETCH_CTRL_BF1_EN__0 0x0
+#define BV_PXP_WFA_FETCH_CTRL_BF1_EN__1 0x1
+
+#define HW_PXP_WFA_FETCH_BUF1_ADDR (0x00000c50)
+
+#define BP_PXP_WFA_FETCH_BUF1_ADDR_BUF_ADDR 0
+#define BM_PXP_WFA_FETCH_BUF1_ADDR_BUF_ADDR 0xFFFFFFFF
+#define BF_PXP_WFA_FETCH_BUF1_ADDR_BUF_ADDR(v) (v)
+
+#define HW_PXP_WFA_FETCH_BUF1_PITCH (0x00000c60)
+
+#define BP_PXP_WFA_FETCH_BUF1_PITCH_RSVD 16
+#define BM_PXP_WFA_FETCH_BUF1_PITCH_RSVD 0xFFFF0000
+#define BF_PXP_WFA_FETCH_BUF1_PITCH_RSVD(v) \
+ (((v) << 16) & BM_PXP_WFA_FETCH_BUF1_PITCH_RSVD)
+#define BP_PXP_WFA_FETCH_BUF1_PITCH_PITCH 0
+#define BM_PXP_WFA_FETCH_BUF1_PITCH_PITCH 0x0000FFFF
+#define BF_PXP_WFA_FETCH_BUF1_PITCH_PITCH(v) \
+ (((v) << 0) & BM_PXP_WFA_FETCH_BUF1_PITCH_PITCH)
+
+#define HW_PXP_WFA_FETCH_BUF1_SIZE (0x00000c70)
+
+#define BP_PXP_WFA_FETCH_BUF1_SIZE_RSVD0 30
+#define BM_PXP_WFA_FETCH_BUF1_SIZE_RSVD0 0xC0000000
+#define BF_PXP_WFA_FETCH_BUF1_SIZE_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_FETCH_BUF1_SIZE_RSVD0)
+#define BP_PXP_WFA_FETCH_BUF1_SIZE_BUF_HEIGHT 16
+#define BM_PXP_WFA_FETCH_BUF1_SIZE_BUF_HEIGHT 0x3FFF0000
+#define BF_PXP_WFA_FETCH_BUF1_SIZE_BUF_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_WFA_FETCH_BUF1_SIZE_BUF_HEIGHT)
+#define BP_PXP_WFA_FETCH_BUF1_SIZE_RSVD1 14
+#define BM_PXP_WFA_FETCH_BUF1_SIZE_RSVD1 0x0000C000
+#define BF_PXP_WFA_FETCH_BUF1_SIZE_RSVD1(v) \
+ (((v) << 14) & BM_PXP_WFA_FETCH_BUF1_SIZE_RSVD1)
+#define BP_PXP_WFA_FETCH_BUF1_SIZE_BUF_WIDTH 0
+#define BM_PXP_WFA_FETCH_BUF1_SIZE_BUF_WIDTH 0x00003FFF
+#define BF_PXP_WFA_FETCH_BUF1_SIZE_BUF_WIDTH(v) \
+ (((v) << 0) & BM_PXP_WFA_FETCH_BUF1_SIZE_BUF_WIDTH)
+
+#define HW_PXP_WFA_FETCH_BUF2_ADDR (0x00000c80)
+
+#define BP_PXP_WFA_FETCH_BUF2_ADDR_BUF_ADDR 0
+#define BM_PXP_WFA_FETCH_BUF2_ADDR_BUF_ADDR 0xFFFFFFFF
+#define BF_PXP_WFA_FETCH_BUF2_ADDR_BUF_ADDR(v) (v)
+
+#define HW_PXP_WFA_FETCH_BUF2_PITCH (0x00000c90)
+
+#define BP_PXP_WFA_FETCH_BUF2_PITCH_RSVD 16
+#define BM_PXP_WFA_FETCH_BUF2_PITCH_RSVD 0xFFFF0000
+#define BF_PXP_WFA_FETCH_BUF2_PITCH_RSVD(v) \
+ (((v) << 16) & BM_PXP_WFA_FETCH_BUF2_PITCH_RSVD)
+#define BP_PXP_WFA_FETCH_BUF2_PITCH_PITCH 0
+#define BM_PXP_WFA_FETCH_BUF2_PITCH_PITCH 0x0000FFFF
+#define BF_PXP_WFA_FETCH_BUF2_PITCH_PITCH(v) \
+ (((v) << 0) & BM_PXP_WFA_FETCH_BUF2_PITCH_PITCH)
+
+#define HW_PXP_WFA_FETCH_BUF2_SIZE (0x00000ca0)
+
+#define BP_PXP_WFA_FETCH_BUF2_SIZE_RSVD0 30
+#define BM_PXP_WFA_FETCH_BUF2_SIZE_RSVD0 0xC0000000
+#define BF_PXP_WFA_FETCH_BUF2_SIZE_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_FETCH_BUF2_SIZE_RSVD0)
+#define BP_PXP_WFA_FETCH_BUF2_SIZE_BUF_HEIGHT 16
+#define BM_PXP_WFA_FETCH_BUF2_SIZE_BUF_HEIGHT 0x3FFF0000
+#define BF_PXP_WFA_FETCH_BUF2_SIZE_BUF_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_WFA_FETCH_BUF2_SIZE_BUF_HEIGHT)
+#define BP_PXP_WFA_FETCH_BUF2_SIZE_RSVD1 14
+#define BM_PXP_WFA_FETCH_BUF2_SIZE_RSVD1 0x0000C000
+#define BF_PXP_WFA_FETCH_BUF2_SIZE_RSVD1(v) \
+ (((v) << 14) & BM_PXP_WFA_FETCH_BUF2_SIZE_RSVD1)
+#define BP_PXP_WFA_FETCH_BUF2_SIZE_BUF_WIDTH 0
+#define BM_PXP_WFA_FETCH_BUF2_SIZE_BUF_WIDTH 0x00003FFF
+#define BF_PXP_WFA_FETCH_BUF2_SIZE_BUF_WIDTH(v) \
+ (((v) << 0) & BM_PXP_WFA_FETCH_BUF2_SIZE_BUF_WIDTH)
+
+#define HW_PXP_WFA_ARRAY_PIXEL0_MASK (0x00000cb0)
+
+#define BP_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_PIXEL0_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_PIXEL0_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_PIXEL0_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_PIXEL0_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_PIXEL0_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL0_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_PIXEL0_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_PIXEL0_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_PIXEL0_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_PIXEL0_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_PIXEL0_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL0_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_PIXEL0_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_PIXEL0_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_PIXEL0_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_PIXEL0_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL0_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_PIXEL0_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_PIXEL0_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_PIXEL0_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_PIXEL0_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_PIXEL0_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_PIXEL0_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_PIXEL0_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_PIXEL0_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_PIXEL0_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_PIXEL0_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_PIXEL0_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_PIXEL0_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_PIXEL0_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_PIXEL0_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_PIXEL0_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_PIXEL0_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_PIXEL0_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_PIXEL1_MASK (0x00000cc0)
+
+#define BP_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_PIXEL1_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_PIXEL1_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_PIXEL1_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_PIXEL1_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_PIXEL1_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL1_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_PIXEL1_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_PIXEL1_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_PIXEL1_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_PIXEL1_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_PIXEL1_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL1_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_PIXEL1_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_PIXEL1_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_PIXEL1_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_PIXEL1_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL1_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_PIXEL1_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_PIXEL1_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_PIXEL1_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_PIXEL1_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_PIXEL1_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_PIXEL1_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_PIXEL1_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_PIXEL1_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_PIXEL1_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_PIXEL1_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_PIXEL1_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_PIXEL1_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_PIXEL1_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_PIXEL1_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_PIXEL1_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_PIXEL1_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_PIXEL1_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_PIXEL2_MASK (0x00000cd0)
+
+#define BP_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_PIXEL2_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_PIXEL2_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_PIXEL2_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_PIXEL2_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_PIXEL2_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL2_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_PIXEL2_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_PIXEL2_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_PIXEL2_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_PIXEL2_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_PIXEL2_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL2_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_PIXEL2_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_PIXEL2_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_PIXEL2_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_PIXEL2_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL2_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_PIXEL2_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_PIXEL2_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_PIXEL2_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_PIXEL2_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_PIXEL2_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_PIXEL2_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_PIXEL2_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_PIXEL2_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_PIXEL2_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_PIXEL2_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_PIXEL2_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_PIXEL2_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_PIXEL2_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_PIXEL2_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_PIXEL2_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_PIXEL2_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_PIXEL2_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_PIXEL3_MASK (0x00000ce0)
+
+#define BP_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_PIXEL3_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_PIXEL3_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_PIXEL3_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_PIXEL3_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_PIXEL3_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL3_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_PIXEL3_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_PIXEL3_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_PIXEL3_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_PIXEL3_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_PIXEL3_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL3_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_PIXEL3_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_PIXEL3_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_PIXEL3_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_PIXEL3_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL3_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_PIXEL3_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_PIXEL3_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_PIXEL3_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_PIXEL3_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_PIXEL3_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_PIXEL3_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_PIXEL3_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_PIXEL3_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_PIXEL3_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_PIXEL3_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_PIXEL3_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_PIXEL3_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_PIXEL3_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_PIXEL3_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_PIXEL3_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_PIXEL3_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_PIXEL3_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_PIXEL4_MASK (0x00000cf0)
+
+#define BP_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_PIXEL4_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_PIXEL4_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_PIXEL4_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_PIXEL4_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_PIXEL4_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL4_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_PIXEL4_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_PIXEL4_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_PIXEL4_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_PIXEL4_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_PIXEL4_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL4_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_PIXEL4_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_PIXEL4_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_PIXEL4_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_PIXEL4_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL4_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_PIXEL4_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_PIXEL4_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_PIXEL4_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_PIXEL4_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_PIXEL4_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_PIXEL4_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_PIXEL4_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_PIXEL4_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_PIXEL4_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_PIXEL4_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_PIXEL4_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_PIXEL4_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_PIXEL4_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_PIXEL4_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_PIXEL4_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_PIXEL4_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_PIXEL4_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_PIXEL5_MASK (0x00000d00)
+
+#define BP_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_PIXEL5_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_PIXEL5_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_PIXEL5_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_PIXEL5_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_PIXEL5_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL5_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_PIXEL5_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_PIXEL5_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_PIXEL5_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_PIXEL5_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_PIXEL5_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL5_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_PIXEL5_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_PIXEL5_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_PIXEL5_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_PIXEL5_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL5_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_PIXEL5_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_PIXEL5_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_PIXEL5_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_PIXEL5_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_PIXEL5_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_PIXEL5_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_PIXEL5_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_PIXEL5_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_PIXEL5_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_PIXEL5_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_PIXEL5_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_PIXEL5_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_PIXEL5_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_PIXEL5_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_PIXEL5_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_PIXEL5_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_PIXEL5_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_PIXEL6_MASK (0x00000d10)
+
+#define BP_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_PIXEL6_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_PIXEL6_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_PIXEL6_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_PIXEL6_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_PIXEL6_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL6_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_PIXEL6_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_PIXEL6_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_PIXEL6_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_PIXEL6_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_PIXEL6_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL6_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_PIXEL6_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_PIXEL6_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_PIXEL6_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_PIXEL6_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL6_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_PIXEL6_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_PIXEL6_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_PIXEL6_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_PIXEL6_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_PIXEL6_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_PIXEL6_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_PIXEL6_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_PIXEL6_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_PIXEL6_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_PIXEL6_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_PIXEL6_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_PIXEL6_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_PIXEL6_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_PIXEL6_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_PIXEL6_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_PIXEL6_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_PIXEL6_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_PIXEL7_MASK (0x00000d20)
+
+#define BP_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_PIXEL7_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_PIXEL7_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_PIXEL7_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_PIXEL7_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_PIXEL7_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL7_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_PIXEL7_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_PIXEL7_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_PIXEL7_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_PIXEL7_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_PIXEL7_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL7_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_PIXEL7_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_PIXEL7_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_PIXEL7_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_PIXEL7_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_PIXEL7_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_PIXEL7_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_PIXEL7_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_PIXEL7_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_PIXEL7_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_PIXEL7_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_PIXEL7_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_PIXEL7_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_PIXEL7_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_PIXEL7_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_PIXEL7_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_PIXEL7_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_PIXEL7_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_PIXEL7_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_PIXEL7_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_PIXEL7_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_PIXEL7_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_PIXEL7_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_FLAG0_MASK (0x00000d30)
+
+#define BP_PXP_WFA_ARRAY_FLAG0_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_FLAG0_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_FLAG0_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_FLAG0_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_FLAG0_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_FLAG0_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_FLAG0_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_FLAG0_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_FLAG0_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG0_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_FLAG0_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_FLAG0_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_FLAG0_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_FLAG0_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_FLAG0_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_FLAG0_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_FLAG0_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_FLAG0_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_FLAG0_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG0_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_FLAG0_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_FLAG0_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_FLAG0_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_FLAG0_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG0_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_FLAG0_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_FLAG0_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_FLAG0_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_FLAG0_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_FLAG0_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_FLAG0_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_FLAG0_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_FLAG0_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_FLAG0_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_FLAG0_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_FLAG0_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_FLAG0_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_FLAG0_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_FLAG0_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_FLAG0_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_FLAG0_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_FLAG0_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_FLAG0_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_FLAG0_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_FLAG0_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_FLAG0_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_FLAG0_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_FLAG0_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_FLAG0_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_FLAG0_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_FLAG0_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_FLAG0_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_FLAG0_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_FLAG0_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_FLAG0_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_FLAG0_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_FLAG0_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_FLAG1_MASK (0x00000d40)
+
+#define BP_PXP_WFA_ARRAY_FLAG1_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_FLAG1_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_FLAG1_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_FLAG1_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_FLAG1_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_FLAG1_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_FLAG1_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_FLAG1_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_FLAG1_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG1_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_FLAG1_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_FLAG1_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_FLAG1_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_FLAG1_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_FLAG1_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_FLAG1_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_FLAG1_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_FLAG1_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_FLAG1_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG1_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_FLAG1_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_FLAG1_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_FLAG1_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_FLAG1_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG1_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_FLAG1_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_FLAG1_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_FLAG1_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_FLAG1_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_FLAG1_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_FLAG1_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_FLAG1_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_FLAG1_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_FLAG1_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_FLAG1_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_FLAG1_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_FLAG1_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_FLAG1_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_FLAG1_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_FLAG1_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_FLAG1_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_FLAG1_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_FLAG1_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_FLAG1_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_FLAG1_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_FLAG1_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_FLAG1_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_FLAG1_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_FLAG1_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_FLAG1_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_FLAG1_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_FLAG1_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_FLAG1_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_FLAG1_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_FLAG1_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_FLAG1_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_FLAG1_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_FLAG2_MASK (0x00000d50)
+
+#define BP_PXP_WFA_ARRAY_FLAG2_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_FLAG2_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_FLAG2_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_FLAG2_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_FLAG2_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_FLAG2_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_FLAG2_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_FLAG2_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_FLAG2_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG2_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_FLAG2_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_FLAG2_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_FLAG2_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_FLAG2_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_FLAG2_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_FLAG2_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_FLAG2_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_FLAG2_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_FLAG2_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG2_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_FLAG2_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_FLAG2_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_FLAG2_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_FLAG2_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG2_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_FLAG2_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_FLAG2_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_FLAG2_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_FLAG2_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_FLAG2_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_FLAG2_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_FLAG2_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_FLAG2_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_FLAG2_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_FLAG2_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_FLAG2_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_FLAG2_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_FLAG2_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_FLAG2_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_FLAG2_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_FLAG2_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_FLAG2_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_FLAG2_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_FLAG2_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_FLAG2_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_FLAG2_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_FLAG2_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_FLAG2_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_FLAG2_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_FLAG2_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_FLAG2_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_FLAG2_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_FLAG2_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_FLAG2_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_FLAG2_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_FLAG2_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_FLAG2_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_FLAG3_MASK (0x00000d60)
+
+#define BP_PXP_WFA_ARRAY_FLAG3_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_FLAG3_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_FLAG3_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_FLAG3_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_FLAG3_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_FLAG3_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_FLAG3_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_FLAG3_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_FLAG3_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG3_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_FLAG3_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_FLAG3_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_FLAG3_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_FLAG3_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_FLAG3_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_FLAG3_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_FLAG3_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_FLAG3_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_FLAG3_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG3_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_FLAG3_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_FLAG3_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_FLAG3_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_FLAG3_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG3_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_FLAG3_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_FLAG3_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_FLAG3_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_FLAG3_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_FLAG3_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_FLAG3_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_FLAG3_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_FLAG3_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_FLAG3_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_FLAG3_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_FLAG3_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_FLAG3_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_FLAG3_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_FLAG3_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_FLAG3_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_FLAG3_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_FLAG3_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_FLAG3_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_FLAG3_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_FLAG3_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_FLAG3_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_FLAG3_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_FLAG3_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_FLAG3_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_FLAG3_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_FLAG3_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_FLAG3_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_FLAG3_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_FLAG3_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_FLAG3_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_FLAG3_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_FLAG3_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_FLAG4_MASK (0x00000d70)
+
+#define BP_PXP_WFA_ARRAY_FLAG4_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_FLAG4_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_FLAG4_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_FLAG4_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_FLAG4_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_FLAG4_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_FLAG4_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_FLAG4_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_FLAG4_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG4_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_FLAG4_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_FLAG4_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_FLAG4_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_FLAG4_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_FLAG4_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_FLAG4_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_FLAG4_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_FLAG4_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_FLAG4_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG4_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_FLAG4_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_FLAG4_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_FLAG4_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_FLAG4_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG4_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_FLAG4_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_FLAG4_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_FLAG4_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_FLAG4_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_FLAG4_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_FLAG4_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_FLAG4_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_FLAG4_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_FLAG4_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_FLAG4_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_FLAG4_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_FLAG4_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_FLAG4_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_FLAG4_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_FLAG4_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_FLAG4_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_FLAG4_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_FLAG4_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_FLAG4_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_FLAG4_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_FLAG4_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_FLAG4_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_FLAG4_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_FLAG4_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_FLAG4_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_FLAG4_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_FLAG4_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_FLAG4_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_FLAG4_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_FLAG4_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_FLAG4_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_FLAG4_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_FLAG5_MASK (0x00000d80)
+
+#define BP_PXP_WFA_ARRAY_FLAG5_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_FLAG5_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_FLAG5_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_FLAG5_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_FLAG5_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_FLAG5_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_FLAG5_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_FLAG5_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_FLAG5_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG5_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_FLAG5_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_FLAG5_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_FLAG5_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_FLAG5_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_FLAG5_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_FLAG5_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_FLAG5_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_FLAG5_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_FLAG5_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG5_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_FLAG5_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_FLAG5_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_FLAG5_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_FLAG5_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG5_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_FLAG5_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_FLAG5_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_FLAG5_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_FLAG5_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_FLAG5_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_FLAG5_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_FLAG5_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_FLAG5_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_FLAG5_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_FLAG5_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_FLAG5_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_FLAG5_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_FLAG5_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_FLAG5_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_FLAG5_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_FLAG5_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_FLAG5_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_FLAG5_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_FLAG5_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_FLAG5_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_FLAG5_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_FLAG5_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_FLAG5_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_FLAG5_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_FLAG5_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_FLAG5_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_FLAG5_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_FLAG5_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_FLAG5_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_FLAG5_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_FLAG5_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_FLAG5_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_FLAG6_MASK (0x00000d90)
+
+#define BP_PXP_WFA_ARRAY_FLAG6_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_FLAG6_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_FLAG6_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_FLAG6_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_FLAG6_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_FLAG6_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_FLAG6_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_FLAG6_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_FLAG6_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG6_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_FLAG6_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_FLAG6_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_FLAG6_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_FLAG6_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_FLAG6_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_FLAG6_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_FLAG6_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_FLAG6_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_FLAG6_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG6_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_FLAG6_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_FLAG6_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_FLAG6_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_FLAG6_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG6_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_FLAG6_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_FLAG6_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_FLAG6_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_FLAG6_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_FLAG6_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_FLAG6_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_FLAG6_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_FLAG6_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_FLAG6_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_FLAG6_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_FLAG6_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_FLAG6_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_FLAG6_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_FLAG6_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_FLAG6_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_FLAG6_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_FLAG6_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_FLAG6_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_FLAG6_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_FLAG6_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_FLAG6_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_FLAG6_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_FLAG6_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_FLAG6_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_FLAG6_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_FLAG6_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_FLAG6_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_FLAG6_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_FLAG6_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_FLAG6_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_FLAG6_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_FLAG6_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_FLAG7_MASK (0x00000da0)
+
+#define BP_PXP_WFA_ARRAY_FLAG7_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_FLAG7_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_FLAG7_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_FLAG7_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_FLAG7_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_FLAG7_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_FLAG7_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_FLAG7_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_FLAG7_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG7_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_FLAG7_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_FLAG7_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_FLAG7_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_FLAG7_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_FLAG7_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_FLAG7_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_FLAG7_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_FLAG7_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_FLAG7_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG7_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_FLAG7_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_FLAG7_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_FLAG7_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_FLAG7_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG7_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_FLAG7_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_FLAG7_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_FLAG7_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_FLAG7_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_FLAG7_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_FLAG7_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_FLAG7_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_FLAG7_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_FLAG7_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_FLAG7_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_FLAG7_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_FLAG7_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_FLAG7_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_FLAG7_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_FLAG7_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_FLAG7_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_FLAG7_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_FLAG7_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_FLAG7_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_FLAG7_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_FLAG7_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_FLAG7_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_FLAG7_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_FLAG7_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_FLAG7_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_FLAG7_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_FLAG7_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_FLAG7_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_FLAG7_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_FLAG7_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_FLAG7_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_FLAG7_MASK_L_OFS)
+
+#define HW_PXP_WFA_FETCH_BUF1_CORD (0x00000db0)
+
+#define BP_PXP_WFA_FETCH_BUF1_CORD_RSVD0 30
+#define BM_PXP_WFA_FETCH_BUF1_CORD_RSVD0 0xC0000000
+#define BF_PXP_WFA_FETCH_BUF1_CORD_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_FETCH_BUF1_CORD_RSVD0)
+#define BP_PXP_WFA_FETCH_BUF1_CORD_YCORD 16
+#define BM_PXP_WFA_FETCH_BUF1_CORD_YCORD 0x3FFF0000
+#define BF_PXP_WFA_FETCH_BUF1_CORD_YCORD(v) \
+ (((v) << 16) & BM_PXP_WFA_FETCH_BUF1_CORD_YCORD)
+#define BP_PXP_WFA_FETCH_BUF1_CORD_RSVD1 14
+#define BM_PXP_WFA_FETCH_BUF1_CORD_RSVD1 0x0000C000
+#define BF_PXP_WFA_FETCH_BUF1_CORD_RSVD1(v) \
+ (((v) << 14) & BM_PXP_WFA_FETCH_BUF1_CORD_RSVD1)
+#define BP_PXP_WFA_FETCH_BUF1_CORD_XCORD 0
+#define BM_PXP_WFA_FETCH_BUF1_CORD_XCORD 0x00003FFF
+#define BF_PXP_WFA_FETCH_BUF1_CORD_XCORD(v) \
+ (((v) << 0) & BM_PXP_WFA_FETCH_BUF1_CORD_XCORD)
+
+#define HW_PXP_WFA_FETCH_BUF2_CORD (0x00000dc0)
+
+#define BP_PXP_WFA_FETCH_BUF2_CORD_RSVD0 30
+#define BM_PXP_WFA_FETCH_BUF2_CORD_RSVD0 0xC0000000
+#define BF_PXP_WFA_FETCH_BUF2_CORD_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_FETCH_BUF2_CORD_RSVD0)
+#define BP_PXP_WFA_FETCH_BUF2_CORD_YCORD 16
+#define BM_PXP_WFA_FETCH_BUF2_CORD_YCORD 0x3FFF0000
+#define BF_PXP_WFA_FETCH_BUF2_CORD_YCORD(v) \
+ (((v) << 16) & BM_PXP_WFA_FETCH_BUF2_CORD_YCORD)
+#define BP_PXP_WFA_FETCH_BUF2_CORD_RSVD1 14
+#define BM_PXP_WFA_FETCH_BUF2_CORD_RSVD1 0x0000C000
+#define BF_PXP_WFA_FETCH_BUF2_CORD_RSVD1(v) \
+ (((v) << 14) & BM_PXP_WFA_FETCH_BUF2_CORD_RSVD1)
+#define BP_PXP_WFA_FETCH_BUF2_CORD_XCORD 0
+#define BM_PXP_WFA_FETCH_BUF2_CORD_XCORD 0x00003FFF
+#define BF_PXP_WFA_FETCH_BUF2_CORD_XCORD(v) \
+ (((v) << 0) & BM_PXP_WFA_FETCH_BUF2_CORD_XCORD)
+
+#define HW_PXP_WFA_ARRAY_FLAG8_MASK (0x00000dd0)
+
+#define BP_PXP_WFA_ARRAY_FLAG8_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_FLAG8_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_FLAG8_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_FLAG8_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_FLAG8_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_FLAG8_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_FLAG8_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_FLAG8_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_FLAG8_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG8_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_FLAG8_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_FLAG8_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_FLAG8_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_FLAG8_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_FLAG8_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_FLAG8_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_FLAG8_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_FLAG8_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_FLAG8_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG8_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_FLAG8_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_FLAG8_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_FLAG8_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_FLAG8_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG8_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_FLAG8_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_FLAG8_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_FLAG8_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_FLAG8_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_FLAG8_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_FLAG8_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_FLAG8_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_FLAG8_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_FLAG8_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_FLAG8_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_FLAG8_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_FLAG8_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_FLAG8_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_FLAG8_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_FLAG8_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_FLAG8_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_FLAG8_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_FLAG8_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_FLAG8_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_FLAG8_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_FLAG8_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_FLAG8_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_FLAG8_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_FLAG8_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_FLAG8_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_FLAG8_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_FLAG8_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_FLAG8_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_FLAG8_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_FLAG8_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_FLAG8_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_FLAG8_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_FLAG9_MASK (0x00000de0)
+
+#define BP_PXP_WFA_ARRAY_FLAG9_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_FLAG9_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_FLAG9_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_FLAG9_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_FLAG9_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_FLAG9_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_FLAG9_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_FLAG9_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_FLAG9_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG9_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_FLAG9_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_FLAG9_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_FLAG9_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_FLAG9_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_FLAG9_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_FLAG9_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_FLAG9_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_FLAG9_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_FLAG9_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG9_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_FLAG9_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_FLAG9_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_FLAG9_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_FLAG9_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG9_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_FLAG9_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_FLAG9_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_FLAG9_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_FLAG9_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_FLAG9_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_FLAG9_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_FLAG9_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_FLAG9_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_FLAG9_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_FLAG9_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_FLAG9_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_FLAG9_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_FLAG9_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_FLAG9_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_FLAG9_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_FLAG9_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_FLAG9_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_FLAG9_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_FLAG9_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_FLAG9_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_FLAG9_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_FLAG9_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_FLAG9_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_FLAG9_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_FLAG9_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_FLAG9_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_FLAG9_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_FLAG9_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_FLAG9_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_FLAG9_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_FLAG9_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_FLAG9_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_FLAG10_MASK (0x00000df0)
+
+#define BP_PXP_WFA_ARRAY_FLAG10_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_FLAG10_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_FLAG10_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_FLAG10_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_FLAG10_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_FLAG10_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_FLAG10_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_FLAG10_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_FLAG10_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG10_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_FLAG10_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_FLAG10_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_FLAG10_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_FLAG10_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_FLAG10_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_FLAG10_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_FLAG10_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_FLAG10_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_FLAG10_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG10_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_FLAG10_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_FLAG10_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_FLAG10_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_FLAG10_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG10_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_FLAG10_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_FLAG10_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_FLAG10_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_FLAG10_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_FLAG10_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_FLAG10_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_FLAG10_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_FLAG10_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_FLAG10_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_FLAG10_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_FLAG10_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_FLAG10_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_FLAG10_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_FLAG10_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_FLAG10_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_FLAG10_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_FLAG10_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_FLAG10_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_FLAG10_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_FLAG10_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_FLAG10_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_FLAG10_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_FLAG10_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_FLAG10_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_FLAG10_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_FLAG10_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_FLAG10_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_FLAG10_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_FLAG10_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_FLAG10_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_FLAG10_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_FLAG10_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_FLAG11_MASK (0x00000e00)
+
+#define BP_PXP_WFA_ARRAY_FLAG11_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_FLAG11_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_FLAG11_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_FLAG11_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_FLAG11_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_FLAG11_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_FLAG11_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_FLAG11_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_FLAG11_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG11_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_FLAG11_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_FLAG11_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_FLAG11_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_FLAG11_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_FLAG11_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_FLAG11_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_FLAG11_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_FLAG11_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_FLAG11_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG11_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_FLAG11_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_FLAG11_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_FLAG11_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_FLAG11_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG11_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_FLAG11_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_FLAG11_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_FLAG11_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_FLAG11_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_FLAG11_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_FLAG11_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_FLAG11_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_FLAG11_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_FLAG11_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_FLAG11_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_FLAG11_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_FLAG11_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_FLAG11_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_FLAG11_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_FLAG11_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_FLAG11_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_FLAG11_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_FLAG11_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_FLAG11_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_FLAG11_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_FLAG11_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_FLAG11_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_FLAG11_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_FLAG11_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_FLAG11_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_FLAG11_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_FLAG11_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_FLAG11_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_FLAG11_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_FLAG11_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_FLAG11_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_FLAG11_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_FLAG12_MASK (0x00000e10)
+
+#define BP_PXP_WFA_ARRAY_FLAG12_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_FLAG12_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_FLAG12_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_FLAG12_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_FLAG12_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_FLAG12_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_FLAG12_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_FLAG12_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_FLAG12_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG12_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_FLAG12_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_FLAG12_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_FLAG12_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_FLAG12_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_FLAG12_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_FLAG12_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_FLAG12_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_FLAG12_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_FLAG12_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG12_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_FLAG12_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_FLAG12_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_FLAG12_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_FLAG12_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG12_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_FLAG12_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_FLAG12_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_FLAG12_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_FLAG12_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_FLAG12_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_FLAG12_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_FLAG12_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_FLAG12_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_FLAG12_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_FLAG12_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_FLAG12_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_FLAG12_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_FLAG12_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_FLAG12_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_FLAG12_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_FLAG12_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_FLAG12_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_FLAG12_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_FLAG12_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_FLAG12_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_FLAG12_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_FLAG12_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_FLAG12_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_FLAG12_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_FLAG12_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_FLAG12_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_FLAG12_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_FLAG12_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_FLAG12_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_FLAG12_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_FLAG12_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_FLAG12_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_FLAG13_MASK (0x00000e20)
+
+#define BP_PXP_WFA_ARRAY_FLAG13_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_FLAG13_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_FLAG13_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_FLAG13_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_FLAG13_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_FLAG13_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_FLAG13_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_FLAG13_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_FLAG13_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG13_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_FLAG13_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_FLAG13_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_FLAG13_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_FLAG13_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_FLAG13_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_FLAG13_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_FLAG13_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_FLAG13_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_FLAG13_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG13_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_FLAG13_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_FLAG13_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_FLAG13_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_FLAG13_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG13_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_FLAG13_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_FLAG13_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_FLAG13_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_FLAG13_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_FLAG13_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_FLAG13_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_FLAG13_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_FLAG13_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_FLAG13_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_FLAG13_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_FLAG13_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_FLAG13_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_FLAG13_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_FLAG13_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_FLAG13_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_FLAG13_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_FLAG13_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_FLAG13_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_FLAG13_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_FLAG13_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_FLAG13_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_FLAG13_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_FLAG13_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_FLAG13_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_FLAG13_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_FLAG13_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_FLAG13_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_FLAG13_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_FLAG13_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_FLAG13_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_FLAG13_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_FLAG13_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_FLAG14_MASK (0x00000e30)
+
+#define BP_PXP_WFA_ARRAY_FLAG14_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_FLAG14_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_FLAG14_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_FLAG14_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_FLAG14_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_FLAG14_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_FLAG14_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_FLAG14_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_FLAG14_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG14_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_FLAG14_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_FLAG14_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_FLAG14_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_FLAG14_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_FLAG14_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_FLAG14_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_FLAG14_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_FLAG14_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_FLAG14_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG14_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_FLAG14_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_FLAG14_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_FLAG14_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_FLAG14_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG14_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_FLAG14_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_FLAG14_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_FLAG14_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_FLAG14_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_FLAG14_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_FLAG14_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_FLAG14_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_FLAG14_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_FLAG14_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_FLAG14_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_FLAG14_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_FLAG14_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_FLAG14_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_FLAG14_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_FLAG14_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_FLAG14_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_FLAG14_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_FLAG14_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_FLAG14_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_FLAG14_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_FLAG14_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_FLAG14_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_FLAG14_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_FLAG14_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_FLAG14_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_FLAG14_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_FLAG14_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_FLAG14_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_FLAG14_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_FLAG14_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_FLAG14_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_FLAG14_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_FLAG15_MASK (0x00000e40)
+
+#define BP_PXP_WFA_ARRAY_FLAG15_MASK_RSVD0 30
+#define BM_PXP_WFA_ARRAY_FLAG15_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFA_ARRAY_FLAG15_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFA_ARRAY_FLAG15_MASK_RSVD0)
+#define BP_PXP_WFA_ARRAY_FLAG15_MASK_BUF_SEL 28
+#define BM_PXP_WFA_ARRAY_FLAG15_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFA_ARRAY_FLAG15_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFA_ARRAY_FLAG15_MASK_BUF_SEL)
+#define BV_PXP_WFA_ARRAY_FLAG15_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG15_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFA_ARRAY_FLAG15_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFA_ARRAY_FLAG15_MASK_RSVD1 26
+#define BM_PXP_WFA_ARRAY_FLAG15_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFA_ARRAY_FLAG15_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFA_ARRAY_FLAG15_MASK_RSVD1)
+#define BM_PXP_WFA_ARRAY_FLAG15_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFA_ARRAY_FLAG15_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFA_ARRAY_FLAG15_MASK_SIGN_Y)
+#define BV_PXP_WFA_ARRAY_FLAG15_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG15_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFA_ARRAY_FLAG15_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFA_ARRAY_FLAG15_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_FLAG15_MASK_SIGN_X)
+#define BV_PXP_WFA_ARRAY_FLAG15_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFA_ARRAY_FLAG15_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFA_ARRAY_FLAG15_MASK_RSVD2 22
+#define BM_PXP_WFA_ARRAY_FLAG15_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFA_ARRAY_FLAG15_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFA_ARRAY_FLAG15_MASK_RSVD2)
+#define BP_PXP_WFA_ARRAY_FLAG15_MASK_OFFSET_Y 20
+#define BM_PXP_WFA_ARRAY_FLAG15_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFA_ARRAY_FLAG15_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFA_ARRAY_FLAG15_MASK_OFFSET_Y)
+#define BP_PXP_WFA_ARRAY_FLAG15_MASK_RSVD3 18
+#define BM_PXP_WFA_ARRAY_FLAG15_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFA_ARRAY_FLAG15_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFA_ARRAY_FLAG15_MASK_RSVD3)
+#define BP_PXP_WFA_ARRAY_FLAG15_MASK_OFFSET_X 16
+#define BM_PXP_WFA_ARRAY_FLAG15_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFA_ARRAY_FLAG15_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_FLAG15_MASK_OFFSET_X)
+#define BP_PXP_WFA_ARRAY_FLAG15_MASK_RSVD4 13
+#define BM_PXP_WFA_ARRAY_FLAG15_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFA_ARRAY_FLAG15_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_FLAG15_MASK_RSVD4)
+#define BP_PXP_WFA_ARRAY_FLAG15_MASK_H_OFS 8
+#define BM_PXP_WFA_ARRAY_FLAG15_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFA_ARRAY_FLAG15_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_FLAG15_MASK_H_OFS)
+#define BP_PXP_WFA_ARRAY_FLAG15_MASK_RSVD5 5
+#define BM_PXP_WFA_ARRAY_FLAG15_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFA_ARRAY_FLAG15_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_FLAG15_MASK_RSVD5)
+#define BP_PXP_WFA_ARRAY_FLAG15_MASK_L_OFS 0
+#define BM_PXP_WFA_ARRAY_FLAG15_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFA_ARRAY_FLAG15_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_FLAG15_MASK_L_OFS)
+
+#define HW_PXP_WFA_ARRAY_REG0 (0x00000e50)
+
+#define BP_PXP_WFA_ARRAY_REG0_SW_PIXLE3 24
+#define BM_PXP_WFA_ARRAY_REG0_SW_PIXLE3 0xFF000000
+#define BF_PXP_WFA_ARRAY_REG0_SW_PIXLE3(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_REG0_SW_PIXLE3)
+#define BP_PXP_WFA_ARRAY_REG0_SW_PIXLE2 16
+#define BM_PXP_WFA_ARRAY_REG0_SW_PIXLE2 0x00FF0000
+#define BF_PXP_WFA_ARRAY_REG0_SW_PIXLE2(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_REG0_SW_PIXLE2)
+#define BP_PXP_WFA_ARRAY_REG0_SW_PIXLE1 8
+#define BM_PXP_WFA_ARRAY_REG0_SW_PIXLE1 0x0000FF00
+#define BF_PXP_WFA_ARRAY_REG0_SW_PIXLE1(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_REG0_SW_PIXLE1)
+#define BP_PXP_WFA_ARRAY_REG0_SW_PIXLE0 0
+#define BM_PXP_WFA_ARRAY_REG0_SW_PIXLE0 0x000000FF
+#define BF_PXP_WFA_ARRAY_REG0_SW_PIXLE0(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_REG0_SW_PIXLE0)
+
+#define HW_PXP_WFA_ARRAY_REG1 (0x00000e60)
+
+#define BP_PXP_WFA_ARRAY_REG1_SW_PIXLE7 24
+#define BM_PXP_WFA_ARRAY_REG1_SW_PIXLE7 0xFF000000
+#define BF_PXP_WFA_ARRAY_REG1_SW_PIXLE7(v) \
+ (((v) << 24) & BM_PXP_WFA_ARRAY_REG1_SW_PIXLE7)
+#define BP_PXP_WFA_ARRAY_REG1_SW_PIXLE6 16
+#define BM_PXP_WFA_ARRAY_REG1_SW_PIXLE6 0x00FF0000
+#define BF_PXP_WFA_ARRAY_REG1_SW_PIXLE6(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_REG1_SW_PIXLE6)
+#define BP_PXP_WFA_ARRAY_REG1_SW_PIXLE5 8
+#define BM_PXP_WFA_ARRAY_REG1_SW_PIXLE5 0x0000FF00
+#define BF_PXP_WFA_ARRAY_REG1_SW_PIXLE5(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_REG1_SW_PIXLE5)
+#define BP_PXP_WFA_ARRAY_REG1_SW_PIXLE4 0
+#define BM_PXP_WFA_ARRAY_REG1_SW_PIXLE4 0x000000FF
+#define BF_PXP_WFA_ARRAY_REG1_SW_PIXLE4(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_REG1_SW_PIXLE4)
+
+#define HW_PXP_WFA_ARRAY_REG2 (0x00000e70)
+
+#define BP_PXP_WFA_ARRAY_REG2_RSVD0 16
+#define BM_PXP_WFA_ARRAY_REG2_RSVD0 0xFFFF0000
+#define BF_PXP_WFA_ARRAY_REG2_RSVD0(v) \
+ (((v) << 16) & BM_PXP_WFA_ARRAY_REG2_RSVD0)
+#define BM_PXP_WFA_ARRAY_REG2_SW_FLAG15 0x00008000
+#define BF_PXP_WFA_ARRAY_REG2_SW_FLAG15(v) \
+ (((v) << 15) & BM_PXP_WFA_ARRAY_REG2_SW_FLAG15)
+#define BM_PXP_WFA_ARRAY_REG2_SW_FLAG14 0x00004000
+#define BF_PXP_WFA_ARRAY_REG2_SW_FLAG14(v) \
+ (((v) << 14) & BM_PXP_WFA_ARRAY_REG2_SW_FLAG14)
+#define BM_PXP_WFA_ARRAY_REG2_SW_FLAG13 0x00002000
+#define BF_PXP_WFA_ARRAY_REG2_SW_FLAG13(v) \
+ (((v) << 13) & BM_PXP_WFA_ARRAY_REG2_SW_FLAG13)
+#define BM_PXP_WFA_ARRAY_REG2_SW_FLAG12 0x00001000
+#define BF_PXP_WFA_ARRAY_REG2_SW_FLAG12(v) \
+ (((v) << 12) & BM_PXP_WFA_ARRAY_REG2_SW_FLAG12)
+#define BM_PXP_WFA_ARRAY_REG2_SW_FLAG11 0x00000800
+#define BF_PXP_WFA_ARRAY_REG2_SW_FLAG11(v) \
+ (((v) << 11) & BM_PXP_WFA_ARRAY_REG2_SW_FLAG11)
+#define BM_PXP_WFA_ARRAY_REG2_SW_FLAG10 0x00000400
+#define BF_PXP_WFA_ARRAY_REG2_SW_FLAG10(v) \
+ (((v) << 10) & BM_PXP_WFA_ARRAY_REG2_SW_FLAG10)
+#define BM_PXP_WFA_ARRAY_REG2_SW_FLAG9 0x00000200
+#define BF_PXP_WFA_ARRAY_REG2_SW_FLAG9(v) \
+ (((v) << 9) & BM_PXP_WFA_ARRAY_REG2_SW_FLAG9)
+#define BM_PXP_WFA_ARRAY_REG2_SW_FLAG8 0x00000100
+#define BF_PXP_WFA_ARRAY_REG2_SW_FLAG8(v) \
+ (((v) << 8) & BM_PXP_WFA_ARRAY_REG2_SW_FLAG8)
+#define BM_PXP_WFA_ARRAY_REG2_SW_FLAG7 0x00000080
+#define BF_PXP_WFA_ARRAY_REG2_SW_FLAG7(v) \
+ (((v) << 7) & BM_PXP_WFA_ARRAY_REG2_SW_FLAG7)
+#define BM_PXP_WFA_ARRAY_REG2_SW_FLAG6 0x00000040
+#define BF_PXP_WFA_ARRAY_REG2_SW_FLAG6(v) \
+ (((v) << 6) & BM_PXP_WFA_ARRAY_REG2_SW_FLAG6)
+#define BM_PXP_WFA_ARRAY_REG2_SW_FLAG5 0x00000020
+#define BF_PXP_WFA_ARRAY_REG2_SW_FLAG5(v) \
+ (((v) << 5) & BM_PXP_WFA_ARRAY_REG2_SW_FLAG5)
+#define BM_PXP_WFA_ARRAY_REG2_SW_FLAG4 0x00000010
+#define BF_PXP_WFA_ARRAY_REG2_SW_FLAG4(v) \
+ (((v) << 4) & BM_PXP_WFA_ARRAY_REG2_SW_FLAG4)
+#define BM_PXP_WFA_ARRAY_REG2_SW_FLAG3 0x00000008
+#define BF_PXP_WFA_ARRAY_REG2_SW_FLAG3(v) \
+ (((v) << 3) & BM_PXP_WFA_ARRAY_REG2_SW_FLAG3)
+#define BM_PXP_WFA_ARRAY_REG2_SW_FLAG2 0x00000004
+#define BF_PXP_WFA_ARRAY_REG2_SW_FLAG2(v) \
+ (((v) << 2) & BM_PXP_WFA_ARRAY_REG2_SW_FLAG2)
+#define BM_PXP_WFA_ARRAY_REG2_SW_FLAG1 0x00000002
+#define BF_PXP_WFA_ARRAY_REG2_SW_FLAG1(v) \
+ (((v) << 1) & BM_PXP_WFA_ARRAY_REG2_SW_FLAG1)
+#define BM_PXP_WFA_ARRAY_REG2_SW_FLAG0 0x00000001
+#define BF_PXP_WFA_ARRAY_REG2_SW_FLAG0(v) \
+ (((v) << 0) & BM_PXP_WFA_ARRAY_REG2_SW_FLAG0)
+
+#define HW_PXP_WFE_A_STORE_CTRL_CH0 (0x00000e80)
+#define HW_PXP_WFE_A_STORE_CTRL_CH0_SET (0x00000e84)
+#define HW_PXP_WFE_A_STORE_CTRL_CH0_CLR (0x00000e88)
+#define HW_PXP_WFE_A_STORE_CTRL_CH0_TOG (0x00000e8c)
+
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_ARBIT_EN 0x80000000
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_ARBIT_EN(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STORE_CTRL_CH0_ARBIT_EN)
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_ARBIT_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_ARBIT_EN__1 0x1
+#define BP_PXP_WFE_A_STORE_CTRL_CH0_RSVD0 25
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_RSVD0 0x7E000000
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_RSVD0(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STORE_CTRL_CH0_RSVD0)
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_COMBINE_2CHANNEL 0x01000000
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_COMBINE_2CHANNEL(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STORE_CTRL_CH0_COMBINE_2CHANNEL)
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_COMBINE_2CHANNEL__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_COMBINE_2CHANNEL__1 0x1
+#define BP_PXP_WFE_A_STORE_CTRL_CH0_RSVD1 18
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_RSVD1 0x00FC0000
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_RSVD1(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STORE_CTRL_CH0_RSVD1)
+#define BP_PXP_WFE_A_STORE_CTRL_CH0_WR_NUM_BYTES 16
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_WR_NUM_BYTES 0x00030000
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_WR_NUM_BYTES(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STORE_CTRL_CH0_WR_NUM_BYTES)
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_WR_NUM_BYTES__8_bytes 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_WR_NUM_BYTES__16_bytes 0x1
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_WR_NUM_BYTES__32_bytes 0x2
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_WR_NUM_BYTES__64_bytes 0x3
+#define BP_PXP_WFE_A_STORE_CTRL_CH0_RSVD2 12
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_RSVD2 0x0000F000
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_RSVD2(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STORE_CTRL_CH0_RSVD2)
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_FILL_DATA_EN 0x00000800
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_FILL_DATA_EN(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STORE_CTRL_CH0_FILL_DATA_EN)
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_FILL_DATA_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_FILL_DATA_EN__1 0x1
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_PACK_IN_SEL 0x00000400
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_PACK_IN_SEL(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STORE_CTRL_CH0_PACK_IN_SEL)
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_PACK_IN_SEL__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_PACK_IN_SEL__1 0x1
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_STORE_MEMORY_EN 0x00000200
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_STORE_MEMORY_EN(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STORE_CTRL_CH0_STORE_MEMORY_EN)
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_STORE_MEMORY_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_STORE_MEMORY_EN__1 0x1
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_STORE_BYPASS_EN 0x00000100
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_STORE_BYPASS_EN(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STORE_CTRL_CH0_STORE_BYPASS_EN)
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_STORE_BYPASS_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_STORE_BYPASS_EN__1 0x1
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_RSVD3 0x00000080
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_RSVD3(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STORE_CTRL_CH0_RSVD3)
+#define BP_PXP_WFE_A_STORE_CTRL_CH0_ARRAY_LINE_NUM 5
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_ARRAY_LINE_NUM 0x00000060
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_ARRAY_LINE_NUM(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STORE_CTRL_CH0_ARRAY_LINE_NUM)
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_ARRAY_LINE_NUM__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_ARRAY_LINE_NUM__1 0x1
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_ARRAY_LINE_NUM__2 0x2
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_ARRAY_LINE_NUM__3 0x3
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_ARRAY_EN 0x00000010
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_ARRAY_EN(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STORE_CTRL_CH0_ARRAY_EN)
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_ARRAY_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_ARRAY_EN__1 0x1
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_HANDSHAKE_EN 0x00000008
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_HANDSHAKE_EN(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STORE_CTRL_CH0_HANDSHAKE_EN)
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_HANDSHAKE_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_HANDSHAKE_EN__1 0x1
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_BLOCK_16 0x00000004
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_BLOCK_16(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STORE_CTRL_CH0_BLOCK_16)
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_BLOCK_16__8x8 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_BLOCK_16__16x16 0x1
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_BLOCK_EN 0x00000002
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_BLOCK_EN(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STORE_CTRL_CH0_BLOCK_EN)
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_BLOCK_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_BLOCK_EN__1 0x1
+#define BM_PXP_WFE_A_STORE_CTRL_CH0_CH_EN 0x00000001
+#define BF_PXP_WFE_A_STORE_CTRL_CH0_CH_EN(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STORE_CTRL_CH0_CH_EN)
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_CH_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH0_CH_EN__1 0x1
+
+#define HW_PXP_WFE_A_STORE_CTRL_CH1 (0x00000e90)
+#define HW_PXP_WFE_A_STORE_CTRL_CH1_SET (0x00000e94)
+#define HW_PXP_WFE_A_STORE_CTRL_CH1_CLR (0x00000e98)
+#define HW_PXP_WFE_A_STORE_CTRL_CH1_TOG (0x00000e9c)
+
+#define BP_PXP_WFE_A_STORE_CTRL_CH1_RSVD0 18
+#define BM_PXP_WFE_A_STORE_CTRL_CH1_RSVD0 0xFFFC0000
+#define BF_PXP_WFE_A_STORE_CTRL_CH1_RSVD0(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STORE_CTRL_CH1_RSVD0)
+#define BP_PXP_WFE_A_STORE_CTRL_CH1_WR_NUM_BYTES 16
+#define BM_PXP_WFE_A_STORE_CTRL_CH1_WR_NUM_BYTES 0x00030000
+#define BF_PXP_WFE_A_STORE_CTRL_CH1_WR_NUM_BYTES(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STORE_CTRL_CH1_WR_NUM_BYTES)
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_WR_NUM_BYTES__8_bytes 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_WR_NUM_BYTES__16_bytes 0x1
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_WR_NUM_BYTES__32_bytes 0x2
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_WR_NUM_BYTES__64_bytes 0x3
+#define BP_PXP_WFE_A_STORE_CTRL_CH1_RSVD1 11
+#define BM_PXP_WFE_A_STORE_CTRL_CH1_RSVD1 0x0000F800
+#define BF_PXP_WFE_A_STORE_CTRL_CH1_RSVD1(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STORE_CTRL_CH1_RSVD1)
+#define BM_PXP_WFE_A_STORE_CTRL_CH1_PACK_IN_SEL 0x00000400
+#define BF_PXP_WFE_A_STORE_CTRL_CH1_PACK_IN_SEL(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STORE_CTRL_CH1_PACK_IN_SEL)
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_PACK_IN_SEL__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_PACK_IN_SEL__1 0x1
+#define BM_PXP_WFE_A_STORE_CTRL_CH1_STORE_MEMORY_EN 0x00000200
+#define BF_PXP_WFE_A_STORE_CTRL_CH1_STORE_MEMORY_EN(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STORE_CTRL_CH1_STORE_MEMORY_EN)
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_STORE_MEMORY_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_STORE_MEMORY_EN__1 0x1
+#define BM_PXP_WFE_A_STORE_CTRL_CH1_STORE_BYPASS_EN 0x00000100
+#define BF_PXP_WFE_A_STORE_CTRL_CH1_STORE_BYPASS_EN(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STORE_CTRL_CH1_STORE_BYPASS_EN)
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_STORE_BYPASS_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_STORE_BYPASS_EN__1 0x1
+#define BM_PXP_WFE_A_STORE_CTRL_CH1_RSVD3 0x00000080
+#define BF_PXP_WFE_A_STORE_CTRL_CH1_RSVD3(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STORE_CTRL_CH1_RSVD3)
+#define BP_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_LINE_NUM 5
+#define BM_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_LINE_NUM 0x00000060
+#define BF_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_LINE_NUM(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_LINE_NUM)
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_LINE_NUM__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_LINE_NUM__1 0x1
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_LINE_NUM__2 0x2
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_LINE_NUM__3 0x3
+#define BM_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_EN 0x00000010
+#define BF_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_EN(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_EN)
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_ARRAY_EN__1 0x1
+#define BM_PXP_WFE_A_STORE_CTRL_CH1_HANDSHAKE_EN 0x00000008
+#define BF_PXP_WFE_A_STORE_CTRL_CH1_HANDSHAKE_EN(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STORE_CTRL_CH1_HANDSHAKE_EN)
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_HANDSHAKE_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_HANDSHAKE_EN__1 0x1
+#define BM_PXP_WFE_A_STORE_CTRL_CH1_BLOCK_16 0x00000004
+#define BF_PXP_WFE_A_STORE_CTRL_CH1_BLOCK_16(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STORE_CTRL_CH1_BLOCK_16)
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_BLOCK_16__8x8 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_BLOCK_16__16x16 0x1
+#define BM_PXP_WFE_A_STORE_CTRL_CH1_BLOCK_EN 0x00000002
+#define BF_PXP_WFE_A_STORE_CTRL_CH1_BLOCK_EN(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STORE_CTRL_CH1_BLOCK_EN)
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_BLOCK_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_BLOCK_EN__1 0x1
+#define BM_PXP_WFE_A_STORE_CTRL_CH1_CH_EN 0x00000001
+#define BF_PXP_WFE_A_STORE_CTRL_CH1_CH_EN(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STORE_CTRL_CH1_CH_EN)
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_CH_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_CTRL_CH1_CH_EN__1 0x1
+
+#define HW_PXP_WFE_A_STORE_STATUS_CH0 (0x00000ea0)
+
+#define BP_PXP_WFE_A_STORE_STATUS_CH0_STORE_BLOCK_Y 16
+#define BM_PXP_WFE_A_STORE_STATUS_CH0_STORE_BLOCK_Y 0xFFFF0000
+#define BF_PXP_WFE_A_STORE_STATUS_CH0_STORE_BLOCK_Y(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STORE_STATUS_CH0_STORE_BLOCK_Y)
+#define BP_PXP_WFE_A_STORE_STATUS_CH0_STORE_BLOCK_X 0
+#define BM_PXP_WFE_A_STORE_STATUS_CH0_STORE_BLOCK_X 0x0000FFFF
+#define BF_PXP_WFE_A_STORE_STATUS_CH0_STORE_BLOCK_X(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STORE_STATUS_CH0_STORE_BLOCK_X)
+
+#define HW_PXP_WFE_A_STORE_STATUS_CH1 (0x00000eb0)
+
+#define BP_PXP_WFE_A_STORE_STATUS_CH1_STORE_BLOCK_Y 16
+#define BM_PXP_WFE_A_STORE_STATUS_CH1_STORE_BLOCK_Y 0xFFFF0000
+#define BF_PXP_WFE_A_STORE_STATUS_CH1_STORE_BLOCK_Y(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STORE_STATUS_CH1_STORE_BLOCK_Y)
+#define BP_PXP_WFE_A_STORE_STATUS_CH1_STORE_BLOCK_X 0
+#define BM_PXP_WFE_A_STORE_STATUS_CH1_STORE_BLOCK_X 0x0000FFFF
+#define BF_PXP_WFE_A_STORE_STATUS_CH1_STORE_BLOCK_X(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STORE_STATUS_CH1_STORE_BLOCK_X)
+
+#define HW_PXP_WFE_A_STORE_SIZE_CH0 (0x00000ec0)
+
+#define BP_PXP_WFE_A_STORE_SIZE_CH0_OUT_HEIGHT 16
+#define BM_PXP_WFE_A_STORE_SIZE_CH0_OUT_HEIGHT 0xFFFF0000
+#define BF_PXP_WFE_A_STORE_SIZE_CH0_OUT_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STORE_SIZE_CH0_OUT_HEIGHT)
+#define BP_PXP_WFE_A_STORE_SIZE_CH0_OUT_WIDTH 0
+#define BM_PXP_WFE_A_STORE_SIZE_CH0_OUT_WIDTH 0x0000FFFF
+#define BF_PXP_WFE_A_STORE_SIZE_CH0_OUT_WIDTH(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STORE_SIZE_CH0_OUT_WIDTH)
+
+#define HW_PXP_WFE_A_STORE_SIZE_CH1 (0x00000ed0)
+
+#define BP_PXP_WFE_A_STORE_SIZE_CH1_OUT_HEIGHT 16
+#define BM_PXP_WFE_A_STORE_SIZE_CH1_OUT_HEIGHT 0xFFFF0000
+#define BF_PXP_WFE_A_STORE_SIZE_CH1_OUT_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STORE_SIZE_CH1_OUT_HEIGHT)
+#define BP_PXP_WFE_A_STORE_SIZE_CH1_OUT_WIDTH 0
+#define BM_PXP_WFE_A_STORE_SIZE_CH1_OUT_WIDTH 0x0000FFFF
+#define BF_PXP_WFE_A_STORE_SIZE_CH1_OUT_WIDTH(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STORE_SIZE_CH1_OUT_WIDTH)
+
+#define HW_PXP_WFE_A_STORE_PITCH (0x00000ee0)
+
+#define BP_PXP_WFE_A_STORE_PITCH_CH1_OUT_PITCH 16
+#define BM_PXP_WFE_A_STORE_PITCH_CH1_OUT_PITCH 0xFFFF0000
+#define BF_PXP_WFE_A_STORE_PITCH_CH1_OUT_PITCH(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STORE_PITCH_CH1_OUT_PITCH)
+#define BP_PXP_WFE_A_STORE_PITCH_CH0_OUT_PITCH 0
+#define BM_PXP_WFE_A_STORE_PITCH_CH0_OUT_PITCH 0x0000FFFF
+#define BF_PXP_WFE_A_STORE_PITCH_CH0_OUT_PITCH(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STORE_PITCH_CH0_OUT_PITCH)
+
+#define HW_PXP_WFE_A_STORE_SHIFT_CTRL_CH0 (0x00000ef0)
+#define HW_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_SET (0x00000ef4)
+#define HW_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_CLR (0x00000ef8)
+#define HW_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_TOG (0x00000efc)
+
+#define BP_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_RSVD0 8
+#define BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_RSVD0 0xFFFFFF00
+#define BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_RSVD0(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_RSVD0)
+#define BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS 0x00000080
+#define BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS)
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS__0 0x0
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS__1 0x1
+#define BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_RSVD1 0x00000040
+#define BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_RSVD1(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_RSVD1)
+#define BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN 0x00000020
+#define BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN)
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN__1 0x1
+#define BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN 0x00000010
+#define BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN)
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN__1 0x1
+#define BP_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP 2
+#define BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP 0x0000000C
+#define BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP)
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP__0 0x0
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP__1 0x1
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP__2 0x2
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP__3 0x3
+#define BP_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_RSVD2 0
+#define BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_RSVD2 0x00000003
+#define BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_RSVD2(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH0_RSVD2)
+
+#define HW_PXP_WFE_A_STORE_SHIFT_CTRL_CH1 (0x00000f00)
+#define HW_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_SET (0x00000f04)
+#define HW_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_CLR (0x00000f08)
+#define HW_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_TOG (0x00000f0c)
+
+#define BP_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_RSVD0 6
+#define BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_RSVD0 0xFFFFFFC0
+#define BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_RSVD0(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_RSVD0)
+#define BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN 0x00000020
+#define BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN)
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN__1 0x1
+#define BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN 0x00000010
+#define BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN)
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN__0 0x0
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN__1 0x1
+#define BP_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP 2
+#define BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP 0x0000000C
+#define BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP)
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP__0 0x0
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP__1 0x1
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP__2 0x2
+#define BV_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP__3 0x3
+#define BP_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_RSVD2 0
+#define BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_RSVD2 0x00000003
+#define BF_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_RSVD2(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STORE_SHIFT_CTRL_CH1_RSVD2)
+
+#define HW_PXP_WFE_A_STORE_ADDR_0_CH0 (0x00000f50)
+
+#define BP_PXP_WFE_A_STORE_ADDR_0_CH0_OUT_BASE_ADDR0 0
+#define BM_PXP_WFE_A_STORE_ADDR_0_CH0_OUT_BASE_ADDR0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_ADDR_0_CH0_OUT_BASE_ADDR0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_ADDR_1_CH0 (0x00000f60)
+
+#define BP_PXP_WFE_A_STORE_ADDR_1_CH0_OUT_BASE_ADDR1 0
+#define BM_PXP_WFE_A_STORE_ADDR_1_CH0_OUT_BASE_ADDR1 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_ADDR_1_CH0_OUT_BASE_ADDR1(v) (v)
+
+#define HW_PXP_WFE_A_STORE_FILL_DATA_CH0 (0x00000f70)
+
+#define BP_PXP_WFE_A_STORE_FILL_DATA_CH0_FILL_DATA_CH0 0
+#define BM_PXP_WFE_A_STORE_FILL_DATA_CH0_FILL_DATA_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_FILL_DATA_CH0_FILL_DATA_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_ADDR_0_CH1 (0x00000f80)
+
+#define BP_PXP_WFE_A_STORE_ADDR_0_CH1_OUT_BASE_ADDR0 0
+#define BM_PXP_WFE_A_STORE_ADDR_0_CH1_OUT_BASE_ADDR0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_ADDR_0_CH1_OUT_BASE_ADDR0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_ADDR_1_CH1 (0x00000f90)
+
+#define BP_PXP_WFE_A_STORE_ADDR_1_CH1_OUT_BASE_ADDR1 0
+#define BM_PXP_WFE_A_STORE_ADDR_1_CH1_OUT_BASE_ADDR1 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_ADDR_1_CH1_OUT_BASE_ADDR1(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_MASK0_H_CH0 (0x00000fa0)
+
+#define BP_PXP_WFE_A_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0 0
+#define BM_PXP_WFE_A_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_MASK0_L_CH0 (0x00000fb0)
+
+#define BP_PXP_WFE_A_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0 0
+#define BM_PXP_WFE_A_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_MASK1_H_CH0 (0x00000fc0)
+
+#define BP_PXP_WFE_A_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0 0
+#define BM_PXP_WFE_A_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_MASK1_L_CH0 (0x00000fd0)
+
+#define BP_PXP_WFE_A_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0 0
+#define BM_PXP_WFE_A_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_MASK2_H_CH0 (0x00000fe0)
+
+#define BP_PXP_WFE_A_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0 0
+#define BM_PXP_WFE_A_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_MASK2_L_CH0 (0x00000ff0)
+
+#define BP_PXP_WFE_A_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0 0
+#define BM_PXP_WFE_A_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_MASK3_H_CH0 (0x00001000)
+
+#define BP_PXP_WFE_A_STORE_D_MASK3_H_CH0_D_MASK3_H_CH0 0
+#define BM_PXP_WFE_A_STORE_D_MASK3_H_CH0_D_MASK3_H_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_D_MASK3_H_CH0_D_MASK3_H_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_MASK3_L_CH0 (0x00001010)
+
+#define BP_PXP_WFE_A_STORE_D_MASK3_L_CH0_D_MASK3_L_CH0 0
+#define BM_PXP_WFE_A_STORE_D_MASK3_L_CH0_D_MASK3_L_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_D_MASK3_L_CH0_D_MASK3_L_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_MASK4_H_CH0 (0x00001020)
+
+#define BP_PXP_WFE_A_STORE_D_MASK4_H_CH0_D_MASK4_H_CH0 0
+#define BM_PXP_WFE_A_STORE_D_MASK4_H_CH0_D_MASK4_H_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_D_MASK4_H_CH0_D_MASK4_H_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_MASK4_L_CH0 (0x00001030)
+
+#define BP_PXP_WFE_A_STORE_D_MASK4_L_CH0_D_MASK4_L_CH0 0
+#define BM_PXP_WFE_A_STORE_D_MASK4_L_CH0_D_MASK4_L_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_D_MASK4_L_CH0_D_MASK4_L_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_MASK5_H_CH0 (0x00001040)
+
+#define BP_PXP_WFE_A_STORE_D_MASK5_H_CH0_D_MASK5_H_CH0 0
+#define BM_PXP_WFE_A_STORE_D_MASK5_H_CH0_D_MASK5_H_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_D_MASK5_H_CH0_D_MASK5_H_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_MASK5_L_CH0 (0x00001050)
+
+#define BP_PXP_WFE_A_STORE_D_MASK5_L_CH0_D_MASK5_L_CH0 0
+#define BM_PXP_WFE_A_STORE_D_MASK5_L_CH0_D_MASK5_L_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_D_MASK5_L_CH0_D_MASK5_L_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_MASK6_H_CH0 (0x00001060)
+
+#define BP_PXP_WFE_A_STORE_D_MASK6_H_CH0_D_MASK6_H_CH0 0
+#define BM_PXP_WFE_A_STORE_D_MASK6_H_CH0_D_MASK6_H_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_D_MASK6_H_CH0_D_MASK6_H_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_MASK6_L_CH0 (0x00001070)
+
+#define BP_PXP_WFE_A_STORE_D_MASK6_L_CH0_D_MASK6_L_CH0 0
+#define BM_PXP_WFE_A_STORE_D_MASK6_L_CH0_D_MASK6_L_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_D_MASK6_L_CH0_D_MASK6_L_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_MASK7_H_CH0 (0x00001080)
+
+#define BP_PXP_WFE_A_STORE_D_MASK7_H_CH0_D_MASK7_H_CH0 0
+#define BM_PXP_WFE_A_STORE_D_MASK7_H_CH0_D_MASK7_H_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_D_MASK7_H_CH0_D_MASK7_H_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_MASK7_L_CH0 (0x00001090)
+
+#define BP_PXP_WFE_A_STORE_D_MASK7_L_CH0_D_MASK7_L_CH0 0
+#define BM_PXP_WFE_A_STORE_D_MASK7_L_CH0_D_MASK7_L_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_A_STORE_D_MASK7_L_CH0_D_MASK7_L_CH0(v) (v)
+
+#define HW_PXP_WFE_A_STORE_D_SHIFT_L_CH0 (0x000010a0)
+
+#define BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3 0x80000000
+#define BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3)
+#define BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_RSVD0 0x40000000
+#define BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_RSVD0)
+#define BP_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3 24
+#define BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3 0x3F000000
+#define BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3)
+#define BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2 0x00800000
+#define BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2)
+#define BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_RSVD1 0x00400000
+#define BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_RSVD1)
+#define BP_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2 16
+#define BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2 0x003F0000
+#define BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2)
+#define BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1 0x00008000
+#define BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1)
+#define BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_RSVD2 0x00004000
+#define BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_RSVD2)
+#define BP_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1 8
+#define BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1 0x00003F00
+#define BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1)
+#define BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0 0x00000080
+#define BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0)
+#define BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_RSVD3 0x00000040
+#define BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_RSVD3)
+#define BP_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0 0
+#define BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0 0x0000003F
+#define BF_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0)
+
+#define HW_PXP_WFE_A_STORE_D_SHIFT_H_CH0 (0x000010b0)
+
+#define BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG7 0x80000000
+#define BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG7(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG7)
+#define BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_RSVD0 0x40000000
+#define BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_RSVD0)
+#define BP_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7 24
+#define BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7 0x3F000000
+#define BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7)
+#define BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG6 0x00800000
+#define BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG6(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG6)
+#define BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_RSVD1 0x00400000
+#define BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_RSVD1)
+#define BP_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6 16
+#define BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6 0x003F0000
+#define BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6)
+#define BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG5 0x00008000
+#define BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG5(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG5)
+#define BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_RSVD2 0x00004000
+#define BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_RSVD2)
+#define BP_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5 8
+#define BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5 0x00003F00
+#define BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5)
+#define BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG4 0x00000080
+#define BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG4(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG4)
+#define BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_RSVD3 0x00000040
+#define BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_RSVD3)
+#define BP_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4 0
+#define BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4 0x0000003F
+#define BF_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4)
+
+#define HW_PXP_WFE_A_STORE_F_SHIFT_L_CH0 (0x000010c0)
+
+#define BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_RSVD0 0x80000000
+#define BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_RSVD0(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_RSVD0)
+#define BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3 0x40000000
+#define BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3)
+#define BP_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3 24
+#define BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3 0x3F000000
+#define BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3)
+#define BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_RSVD1 0x00800000
+#define BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_RSVD1(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_RSVD1)
+#define BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2 0x00400000
+#define BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2)
+#define BP_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2 16
+#define BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2 0x003F0000
+#define BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2)
+#define BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_RSVD2 0x00008000
+#define BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_RSVD2(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_RSVD2)
+#define BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1 0x00004000
+#define BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1)
+#define BP_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1 8
+#define BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1 0x00003F00
+#define BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1)
+#define BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_RSVD3 0x00000080
+#define BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_RSVD3(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_RSVD3)
+#define BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0 0x00000040
+#define BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0)
+#define BP_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0 0
+#define BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0 0x0000003F
+#define BF_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0)
+
+#define HW_PXP_WFE_A_STORE_F_SHIFT_H_CH0 (0x000010d0)
+
+#define BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_RSVD0 0x80000000
+#define BF_PXP_WFE_A_STORE_F_SHIFT_H_CH0_RSVD0(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_RSVD0)
+#define BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG7 0x40000000
+#define BF_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG7(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG7)
+#define BP_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7 24
+#define BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7 0x3F000000
+#define BF_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7)
+#define BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_RSVD1 0x00800000
+#define BF_PXP_WFE_A_STORE_F_SHIFT_H_CH0_RSVD1(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_RSVD1)
+#define BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG6 0x00400000
+#define BF_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG6(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG6)
+#define BP_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6 16
+#define BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6 0x003F0000
+#define BF_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6)
+#define BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_RSVD2 0x00008000
+#define BF_PXP_WFE_A_STORE_F_SHIFT_H_CH0_RSVD2(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_RSVD2)
+#define BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG5 0x00004000
+#define BF_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG5(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG5)
+#define BP_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5 8
+#define BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5 0x00003F00
+#define BF_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5)
+#define BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_RSVD3 0x00000080
+#define BF_PXP_WFE_A_STORE_F_SHIFT_H_CH0_RSVD3(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_RSVD3)
+#define BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG4 0x00000040
+#define BF_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG4(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG4)
+#define BP_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4 0
+#define BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4 0x0000003F
+#define BF_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4)
+
+#define HW_PXP_WFE_A_STORE_F_MASK_L_CH0 (0x000010e0)
+
+#define BP_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK3 24
+#define BM_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK3 0xFF000000
+#define BF_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK3(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK3)
+#define BP_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK2 16
+#define BM_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK2 0x00FF0000
+#define BF_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK2(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK2)
+#define BP_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK1 8
+#define BM_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK1 0x0000FF00
+#define BF_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK1(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK1)
+#define BP_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK0 0
+#define BM_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK0 0x000000FF
+#define BF_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STORE_F_MASK_L_CH0_F_MASK0)
+
+#define HW_PXP_WFE_A_STORE_F_MASK_H_CH0 (0x000010f0)
+
+#define BP_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK7 24
+#define BM_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK7 0xFF000000
+#define BF_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK7(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK7)
+#define BP_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK6 16
+#define BM_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK6 0x00FF0000
+#define BF_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK6(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK6)
+#define BP_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK5 8
+#define BM_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK5 0x0000FF00
+#define BF_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK5(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK5)
+#define BP_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK4 0
+#define BM_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK4 0x000000FF
+#define BF_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK4(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STORE_F_MASK_H_CH0_F_MASK4)
+
+#define HW_PXP_WFB_FETCH_CTRL (0x00001100)
+#define HW_PXP_WFB_FETCH_CTRL_SET (0x00001104)
+#define HW_PXP_WFB_FETCH_CTRL_CLR (0x00001108)
+#define HW_PXP_WFB_FETCH_CTRL_TOG (0x0000110c)
+
+#define BM_PXP_WFB_FETCH_CTRL_BUF2_DONE_IRQ_EN 0x80000000
+#define BF_PXP_WFB_FETCH_CTRL_BUF2_DONE_IRQ_EN(v) \
+ (((v) << 31) & BM_PXP_WFB_FETCH_CTRL_BUF2_DONE_IRQ_EN)
+#define BM_PXP_WFB_FETCH_CTRL_BUF1_DONE_IRQ_EN 0x40000000
+#define BF_PXP_WFB_FETCH_CTRL_BUF1_DONE_IRQ_EN(v) \
+ (((v) << 30) & BM_PXP_WFB_FETCH_CTRL_BUF1_DONE_IRQ_EN)
+#define BM_PXP_WFB_FETCH_CTRL_BUF2_DONE_IRQ 0x20000000
+#define BF_PXP_WFB_FETCH_CTRL_BUF2_DONE_IRQ(v) \
+ (((v) << 29) & BM_PXP_WFB_FETCH_CTRL_BUF2_DONE_IRQ)
+#define BM_PXP_WFB_FETCH_CTRL_BUF1_DONE_IRQ 0x10000000
+#define BF_PXP_WFB_FETCH_CTRL_BUF1_DONE_IRQ(v) \
+ (((v) << 28) & BM_PXP_WFB_FETCH_CTRL_BUF1_DONE_IRQ)
+#define BP_PXP_WFB_FETCH_CTRL_RSVD0 24
+#define BM_PXP_WFB_FETCH_CTRL_RSVD0 0x0F000000
+#define BF_PXP_WFB_FETCH_CTRL_RSVD0(v) \
+ (((v) << 24) & BM_PXP_WFB_FETCH_CTRL_RSVD0)
+#define BP_PXP_WFB_FETCH_CTRL_BF2_LINE_MODE 22
+#define BM_PXP_WFB_FETCH_CTRL_BF2_LINE_MODE 0x00C00000
+#define BF_PXP_WFB_FETCH_CTRL_BF2_LINE_MODE(v) \
+ (((v) << 22) & BM_PXP_WFB_FETCH_CTRL_BF2_LINE_MODE)
+#define BV_PXP_WFB_FETCH_CTRL_BF2_LINE_MODE__0 0x0
+#define BV_PXP_WFB_FETCH_CTRL_BF2_LINE_MODE__1 0x1
+#define BV_PXP_WFB_FETCH_CTRL_BF2_LINE_MODE__2 0x2
+#define BV_PXP_WFB_FETCH_CTRL_BF2_LINE_MODE__3 0x3
+#define BP_PXP_WFB_FETCH_CTRL_BF2_BYTES_PP 20
+#define BM_PXP_WFB_FETCH_CTRL_BF2_BYTES_PP 0x00300000
+#define BF_PXP_WFB_FETCH_CTRL_BF2_BYTES_PP(v) \
+ (((v) << 20) & BM_PXP_WFB_FETCH_CTRL_BF2_BYTES_PP)
+#define BP_PXP_WFB_FETCH_CTRL_BF1_LINE_MODE 18
+#define BM_PXP_WFB_FETCH_CTRL_BF1_LINE_MODE 0x000C0000
+#define BF_PXP_WFB_FETCH_CTRL_BF1_LINE_MODE(v) \
+ (((v) << 18) & BM_PXP_WFB_FETCH_CTRL_BF1_LINE_MODE)
+#define BV_PXP_WFB_FETCH_CTRL_BF1_LINE_MODE__0 0x0
+#define BV_PXP_WFB_FETCH_CTRL_BF1_LINE_MODE__1 0x1
+#define BV_PXP_WFB_FETCH_CTRL_BF1_LINE_MODE__2 0x2
+#define BV_PXP_WFB_FETCH_CTRL_BF1_LINE_MODE__3 0x3
+#define BP_PXP_WFB_FETCH_CTRL_BF1_BYTES_PP 16
+#define BM_PXP_WFB_FETCH_CTRL_BF1_BYTES_PP 0x00030000
+#define BF_PXP_WFB_FETCH_CTRL_BF1_BYTES_PP(v) \
+ (((v) << 16) & BM_PXP_WFB_FETCH_CTRL_BF1_BYTES_PP)
+#define BP_PXP_WFB_FETCH_CTRL_RSVD1 14
+#define BM_PXP_WFB_FETCH_CTRL_RSVD1 0x0000C000
+#define BF_PXP_WFB_FETCH_CTRL_RSVD1(v) \
+ (((v) << 14) & BM_PXP_WFB_FETCH_CTRL_RSVD1)
+#define BM_PXP_WFB_FETCH_CTRL_BF2_BORDER_MODE 0x00002000
+#define BF_PXP_WFB_FETCH_CTRL_BF2_BORDER_MODE(v) \
+ (((v) << 13) & BM_PXP_WFB_FETCH_CTRL_BF2_BORDER_MODE)
+#define BV_PXP_WFB_FETCH_CTRL_BF2_BORDER_MODE__0 0x0
+#define BV_PXP_WFB_FETCH_CTRL_BF2_BORDER_MODE__1 0x1
+#define BM_PXP_WFB_FETCH_CTRL_BF2_BURST_LEN 0x00001000
+#define BF_PXP_WFB_FETCH_CTRL_BF2_BURST_LEN(v) \
+ (((v) << 12) & BM_PXP_WFB_FETCH_CTRL_BF2_BURST_LEN)
+#define BV_PXP_WFB_FETCH_CTRL_BF2_BURST_LEN__0 0x0
+#define BV_PXP_WFB_FETCH_CTRL_BF2_BURST_LEN__1 0x1
+#define BM_PXP_WFB_FETCH_CTRL_BF2_BYPASS_MODE 0x00000800
+#define BF_PXP_WFB_FETCH_CTRL_BF2_BYPASS_MODE(v) \
+ (((v) << 11) & BM_PXP_WFB_FETCH_CTRL_BF2_BYPASS_MODE)
+#define BV_PXP_WFB_FETCH_CTRL_BF2_BYPASS_MODE__0 0x0
+#define BV_PXP_WFB_FETCH_CTRL_BF2_BYPASS_MODE__1 0x1
+#define BM_PXP_WFB_FETCH_CTRL_BF2_HSK_MODE 0x00000400
+#define BF_PXP_WFB_FETCH_CTRL_BF2_HSK_MODE(v) \
+ (((v) << 10) & BM_PXP_WFB_FETCH_CTRL_BF2_HSK_MODE)
+#define BV_PXP_WFB_FETCH_CTRL_BF2_HSK_MODE__0 0x0
+#define BV_PXP_WFB_FETCH_CTRL_BF2_HSK_MODE__1 0x1
+#define BM_PXP_WFB_FETCH_CTRL_BF2_SRAM_IF 0x00000200
+#define BF_PXP_WFB_FETCH_CTRL_BF2_SRAM_IF(v) \
+ (((v) << 9) & BM_PXP_WFB_FETCH_CTRL_BF2_SRAM_IF)
+#define BV_PXP_WFB_FETCH_CTRL_BF2_SRAM_IF__0 0x0
+#define BV_PXP_WFB_FETCH_CTRL_BF2_SRAM_IF__1 0x1
+#define BM_PXP_WFB_FETCH_CTRL_BF2_EN 0x00000100
+#define BF_PXP_WFB_FETCH_CTRL_BF2_EN(v) \
+ (((v) << 8) & BM_PXP_WFB_FETCH_CTRL_BF2_EN)
+#define BV_PXP_WFB_FETCH_CTRL_BF2_EN__0 0x0
+#define BV_PXP_WFB_FETCH_CTRL_BF2_EN__1 0x1
+#define BP_PXP_WFB_FETCH_CTRL_RSVD2 6
+#define BM_PXP_WFB_FETCH_CTRL_RSVD2 0x000000C0
+#define BF_PXP_WFB_FETCH_CTRL_RSVD2(v) \
+ (((v) << 6) & BM_PXP_WFB_FETCH_CTRL_RSVD2)
+#define BM_PXP_WFB_FETCH_CTRL_BF1_BORDER_MODE 0x00000020
+#define BF_PXP_WFB_FETCH_CTRL_BF1_BORDER_MODE(v) \
+ (((v) << 5) & BM_PXP_WFB_FETCH_CTRL_BF1_BORDER_MODE)
+#define BV_PXP_WFB_FETCH_CTRL_BF1_BORDER_MODE__0 0x0
+#define BV_PXP_WFB_FETCH_CTRL_BF1_BORDER_MODE__1 0x1
+#define BM_PXP_WFB_FETCH_CTRL_BF1_BURST_LEN 0x00000010
+#define BF_PXP_WFB_FETCH_CTRL_BF1_BURST_LEN(v) \
+ (((v) << 4) & BM_PXP_WFB_FETCH_CTRL_BF1_BURST_LEN)
+#define BV_PXP_WFB_FETCH_CTRL_BF1_BURST_LEN__0 0x0
+#define BV_PXP_WFB_FETCH_CTRL_BF1_BURST_LEN__1 0x1
+#define BM_PXP_WFB_FETCH_CTRL_BF1_BYPASS_MODE 0x00000008
+#define BF_PXP_WFB_FETCH_CTRL_BF1_BYPASS_MODE(v) \
+ (((v) << 3) & BM_PXP_WFB_FETCH_CTRL_BF1_BYPASS_MODE)
+#define BV_PXP_WFB_FETCH_CTRL_BF1_BYPASS_MODE__0 0x0
+#define BV_PXP_WFB_FETCH_CTRL_BF1_BYPASS_MODE__1 0x1
+#define BM_PXP_WFB_FETCH_CTRL_BF1_HSK_MODE 0x00000004
+#define BF_PXP_WFB_FETCH_CTRL_BF1_HSK_MODE(v) \
+ (((v) << 2) & BM_PXP_WFB_FETCH_CTRL_BF1_HSK_MODE)
+#define BV_PXP_WFB_FETCH_CTRL_BF1_HSK_MODE__0 0x0
+#define BV_PXP_WFB_FETCH_CTRL_BF1_HSK_MODE__1 0x1
+#define BM_PXP_WFB_FETCH_CTRL_BF1_SRAM_IF 0x00000002
+#define BF_PXP_WFB_FETCH_CTRL_BF1_SRAM_IF(v) \
+ (((v) << 1) & BM_PXP_WFB_FETCH_CTRL_BF1_SRAM_IF)
+#define BV_PXP_WFB_FETCH_CTRL_BF1_SRAM_IF__0 0x0
+#define BV_PXP_WFB_FETCH_CTRL_BF1_SRAM_IF__1 0x1
+#define BM_PXP_WFB_FETCH_CTRL_BF1_EN 0x00000001
+#define BF_PXP_WFB_FETCH_CTRL_BF1_EN(v) \
+ (((v) << 0) & BM_PXP_WFB_FETCH_CTRL_BF1_EN)
+#define BV_PXP_WFB_FETCH_CTRL_BF1_EN__0 0x0
+#define BV_PXP_WFB_FETCH_CTRL_BF1_EN__1 0x1
+
+#define HW_PXP_WFB_FETCH_BUF1_ADDR (0x00001110)
+
+#define BP_PXP_WFB_FETCH_BUF1_ADDR_BUF_ADDR 0
+#define BM_PXP_WFB_FETCH_BUF1_ADDR_BUF_ADDR 0xFFFFFFFF
+#define BF_PXP_WFB_FETCH_BUF1_ADDR_BUF_ADDR(v) (v)
+
+#define HW_PXP_WFB_FETCH_BUF1_PITCH (0x00001120)
+
+#define BP_PXP_WFB_FETCH_BUF1_PITCH_RSVD 16
+#define BM_PXP_WFB_FETCH_BUF1_PITCH_RSVD 0xFFFF0000
+#define BF_PXP_WFB_FETCH_BUF1_PITCH_RSVD(v) \
+ (((v) << 16) & BM_PXP_WFB_FETCH_BUF1_PITCH_RSVD)
+#define BP_PXP_WFB_FETCH_BUF1_PITCH_PITCH 0
+#define BM_PXP_WFB_FETCH_BUF1_PITCH_PITCH 0x0000FFFF
+#define BF_PXP_WFB_FETCH_BUF1_PITCH_PITCH(v) \
+ (((v) << 0) & BM_PXP_WFB_FETCH_BUF1_PITCH_PITCH)
+
+#define HW_PXP_WFB_FETCH_BUF1_SIZE (0x00001130)
+
+#define BP_PXP_WFB_FETCH_BUF1_SIZE_BUF_HEIGHT 16
+#define BM_PXP_WFB_FETCH_BUF1_SIZE_BUF_HEIGHT 0xFFFF0000
+#define BF_PXP_WFB_FETCH_BUF1_SIZE_BUF_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_WFB_FETCH_BUF1_SIZE_BUF_HEIGHT)
+#define BP_PXP_WFB_FETCH_BUF1_SIZE_BUF_WIDTH 0
+#define BM_PXP_WFB_FETCH_BUF1_SIZE_BUF_WIDTH 0x0000FFFF
+#define BF_PXP_WFB_FETCH_BUF1_SIZE_BUF_WIDTH(v) \
+ (((v) << 0) & BM_PXP_WFB_FETCH_BUF1_SIZE_BUF_WIDTH)
+
+#define HW_PXP_WFB_FETCH_BUF2_ADDR (0x00001140)
+
+#define BP_PXP_WFB_FETCH_BUF2_ADDR_BUF_ADDR 0
+#define BM_PXP_WFB_FETCH_BUF2_ADDR_BUF_ADDR 0xFFFFFFFF
+#define BF_PXP_WFB_FETCH_BUF2_ADDR_BUF_ADDR(v) (v)
+
+#define HW_PXP_WFB_FETCH_BUF2_PITCH (0x00001150)
+
+#define BP_PXP_WFB_FETCH_BUF2_PITCH_RSVD 16
+#define BM_PXP_WFB_FETCH_BUF2_PITCH_RSVD 0xFFFF0000
+#define BF_PXP_WFB_FETCH_BUF2_PITCH_RSVD(v) \
+ (((v) << 16) & BM_PXP_WFB_FETCH_BUF2_PITCH_RSVD)
+#define BP_PXP_WFB_FETCH_BUF2_PITCH_PITCH 0
+#define BM_PXP_WFB_FETCH_BUF2_PITCH_PITCH 0x0000FFFF
+#define BF_PXP_WFB_FETCH_BUF2_PITCH_PITCH(v) \
+ (((v) << 0) & BM_PXP_WFB_FETCH_BUF2_PITCH_PITCH)
+
+#define HW_PXP_WFB_FETCH_BUF2_SIZE (0x00001160)
+
+#define BP_PXP_WFB_FETCH_BUF2_SIZE_BUF_HEIGHT 16
+#define BM_PXP_WFB_FETCH_BUF2_SIZE_BUF_HEIGHT 0xFFFF0000
+#define BF_PXP_WFB_FETCH_BUF2_SIZE_BUF_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_WFB_FETCH_BUF2_SIZE_BUF_HEIGHT)
+#define BP_PXP_WFB_FETCH_BUF2_SIZE_BUF_WIDTH 0
+#define BM_PXP_WFB_FETCH_BUF2_SIZE_BUF_WIDTH 0x0000FFFF
+#define BF_PXP_WFB_FETCH_BUF2_SIZE_BUF_WIDTH(v) \
+ (((v) << 0) & BM_PXP_WFB_FETCH_BUF2_SIZE_BUF_WIDTH)
+
+#define HW_PXP_WFB_ARRAY_PIXEL0_MASK (0x00001170)
+
+#define BP_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_PIXEL0_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_PIXEL0_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_PIXEL0_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_PIXEL0_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_PIXEL0_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL0_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_PIXEL0_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_PIXEL0_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_PIXEL0_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_PIXEL0_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_PIXEL0_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL0_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_PIXEL0_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_PIXEL0_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_PIXEL0_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_PIXEL0_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL0_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_PIXEL0_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_PIXEL0_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_PIXEL0_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_PIXEL0_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_PIXEL0_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_PIXEL0_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_PIXEL0_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_PIXEL0_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_PIXEL0_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_PIXEL0_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_PIXEL0_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_PIXEL0_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_PIXEL0_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_PIXEL0_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_PIXEL0_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_PIXEL0_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_PIXEL0_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_PIXEL1_MASK (0x00001180)
+
+#define BP_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_PIXEL1_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_PIXEL1_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_PIXEL1_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_PIXEL1_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_PIXEL1_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL1_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_PIXEL1_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_PIXEL1_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_PIXEL1_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_PIXEL1_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_PIXEL1_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL1_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_PIXEL1_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_PIXEL1_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_PIXEL1_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_PIXEL1_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL1_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_PIXEL1_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_PIXEL1_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_PIXEL1_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_PIXEL1_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_PIXEL1_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_PIXEL1_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_PIXEL1_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_PIXEL1_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_PIXEL1_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_PIXEL1_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_PIXEL1_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_PIXEL1_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_PIXEL1_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_PIXEL1_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_PIXEL1_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_PIXEL1_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_PIXEL1_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_PIXEL2_MASK (0x00001190)
+
+#define BP_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_PIXEL2_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_PIXEL2_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_PIXEL2_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_PIXEL2_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_PIXEL2_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL2_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_PIXEL2_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_PIXEL2_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_PIXEL2_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_PIXEL2_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_PIXEL2_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL2_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_PIXEL2_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_PIXEL2_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_PIXEL2_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_PIXEL2_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL2_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_PIXEL2_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_PIXEL2_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_PIXEL2_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_PIXEL2_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_PIXEL2_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_PIXEL2_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_PIXEL2_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_PIXEL2_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_PIXEL2_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_PIXEL2_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_PIXEL2_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_PIXEL2_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_PIXEL2_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_PIXEL2_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_PIXEL2_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_PIXEL2_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_PIXEL2_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_PIXEL3_MASK (0x000011a0)
+
+#define BP_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_PIXEL3_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_PIXEL3_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_PIXEL3_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_PIXEL3_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_PIXEL3_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL3_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_PIXEL3_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_PIXEL3_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_PIXEL3_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_PIXEL3_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_PIXEL3_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL3_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_PIXEL3_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_PIXEL3_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_PIXEL3_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_PIXEL3_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL3_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_PIXEL3_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_PIXEL3_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_PIXEL3_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_PIXEL3_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_PIXEL3_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_PIXEL3_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_PIXEL3_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_PIXEL3_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_PIXEL3_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_PIXEL3_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_PIXEL3_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_PIXEL3_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_PIXEL3_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_PIXEL3_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_PIXEL3_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_PIXEL3_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_PIXEL3_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_PIXEL4_MASK (0x000011b0)
+
+#define BP_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_PIXEL4_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_PIXEL4_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_PIXEL4_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_PIXEL4_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_PIXEL4_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL4_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_PIXEL4_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_PIXEL4_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_PIXEL4_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_PIXEL4_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_PIXEL4_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL4_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_PIXEL4_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_PIXEL4_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_PIXEL4_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_PIXEL4_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL4_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_PIXEL4_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_PIXEL4_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_PIXEL4_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_PIXEL4_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_PIXEL4_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_PIXEL4_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_PIXEL4_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_PIXEL4_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_PIXEL4_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_PIXEL4_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_PIXEL4_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_PIXEL4_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_PIXEL4_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_PIXEL4_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_PIXEL4_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_PIXEL4_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_PIXEL4_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_PIXEL5_MASK (0x000011c0)
+
+#define BP_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_PIXEL5_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_PIXEL5_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_PIXEL5_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_PIXEL5_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_PIXEL5_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL5_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_PIXEL5_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_PIXEL5_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_PIXEL5_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_PIXEL5_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_PIXEL5_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL5_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_PIXEL5_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_PIXEL5_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_PIXEL5_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_PIXEL5_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL5_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_PIXEL5_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_PIXEL5_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_PIXEL5_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_PIXEL5_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_PIXEL5_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_PIXEL5_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_PIXEL5_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_PIXEL5_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_PIXEL5_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_PIXEL5_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_PIXEL5_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_PIXEL5_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_PIXEL5_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_PIXEL5_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_PIXEL5_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_PIXEL5_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_PIXEL5_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_PIXEL6_MASK (0x000011d0)
+
+#define BP_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_PIXEL6_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_PIXEL6_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_PIXEL6_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_PIXEL6_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_PIXEL6_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL6_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_PIXEL6_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_PIXEL6_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_PIXEL6_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_PIXEL6_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_PIXEL6_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL6_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_PIXEL6_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_PIXEL6_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_PIXEL6_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_PIXEL6_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL6_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_PIXEL6_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_PIXEL6_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_PIXEL6_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_PIXEL6_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_PIXEL6_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_PIXEL6_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_PIXEL6_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_PIXEL6_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_PIXEL6_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_PIXEL6_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_PIXEL6_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_PIXEL6_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_PIXEL6_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_PIXEL6_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_PIXEL6_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_PIXEL6_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_PIXEL6_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_PIXEL7_MASK (0x000011e0)
+
+#define BP_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_PIXEL7_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_PIXEL7_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_PIXEL7_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_PIXEL7_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_PIXEL7_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL7_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_PIXEL7_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_PIXEL7_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_PIXEL7_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_PIXEL7_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_PIXEL7_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL7_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_PIXEL7_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_PIXEL7_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_PIXEL7_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_PIXEL7_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_PIXEL7_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_PIXEL7_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_PIXEL7_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_PIXEL7_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_PIXEL7_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_PIXEL7_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_PIXEL7_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_PIXEL7_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_PIXEL7_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_PIXEL7_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_PIXEL7_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_PIXEL7_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_PIXEL7_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_PIXEL7_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_PIXEL7_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_PIXEL7_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_PIXEL7_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_PIXEL7_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_FLAG0_MASK (0x000011f0)
+
+#define BP_PXP_WFB_ARRAY_FLAG0_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_FLAG0_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_FLAG0_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_FLAG0_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_FLAG0_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_FLAG0_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_FLAG0_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_FLAG0_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_FLAG0_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG0_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_FLAG0_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_FLAG0_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_FLAG0_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_FLAG0_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_FLAG0_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_FLAG0_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_FLAG0_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_FLAG0_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_FLAG0_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG0_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_FLAG0_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_FLAG0_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_FLAG0_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_FLAG0_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG0_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_FLAG0_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_FLAG0_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_FLAG0_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_FLAG0_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_FLAG0_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_FLAG0_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_FLAG0_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_FLAG0_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_FLAG0_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_FLAG0_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_FLAG0_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_FLAG0_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_FLAG0_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_FLAG0_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_FLAG0_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_FLAG0_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_FLAG0_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_FLAG0_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_FLAG0_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_FLAG0_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_FLAG0_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_FLAG0_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_FLAG0_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_FLAG0_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_FLAG0_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_FLAG0_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_FLAG0_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_FLAG0_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_FLAG0_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_FLAG0_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_FLAG0_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_FLAG0_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_FLAG1_MASK (0x00001200)
+
+#define BP_PXP_WFB_ARRAY_FLAG1_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_FLAG1_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_FLAG1_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_FLAG1_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_FLAG1_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_FLAG1_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_FLAG1_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_FLAG1_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_FLAG1_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG1_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_FLAG1_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_FLAG1_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_FLAG1_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_FLAG1_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_FLAG1_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_FLAG1_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_FLAG1_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_FLAG1_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_FLAG1_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG1_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_FLAG1_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_FLAG1_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_FLAG1_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_FLAG1_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG1_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_FLAG1_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_FLAG1_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_FLAG1_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_FLAG1_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_FLAG1_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_FLAG1_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_FLAG1_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_FLAG1_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_FLAG1_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_FLAG1_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_FLAG1_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_FLAG1_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_FLAG1_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_FLAG1_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_FLAG1_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_FLAG1_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_FLAG1_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_FLAG1_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_FLAG1_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_FLAG1_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_FLAG1_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_FLAG1_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_FLAG1_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_FLAG1_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_FLAG1_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_FLAG1_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_FLAG1_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_FLAG1_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_FLAG1_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_FLAG1_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_FLAG1_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_FLAG1_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_FLAG2_MASK (0x00001210)
+
+#define BP_PXP_WFB_ARRAY_FLAG2_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_FLAG2_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_FLAG2_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_FLAG2_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_FLAG2_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_FLAG2_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_FLAG2_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_FLAG2_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_FLAG2_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG2_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_FLAG2_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_FLAG2_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_FLAG2_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_FLAG2_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_FLAG2_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_FLAG2_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_FLAG2_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_FLAG2_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_FLAG2_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG2_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_FLAG2_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_FLAG2_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_FLAG2_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_FLAG2_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG2_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_FLAG2_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_FLAG2_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_FLAG2_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_FLAG2_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_FLAG2_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_FLAG2_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_FLAG2_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_FLAG2_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_FLAG2_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_FLAG2_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_FLAG2_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_FLAG2_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_FLAG2_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_FLAG2_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_FLAG2_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_FLAG2_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_FLAG2_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_FLAG2_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_FLAG2_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_FLAG2_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_FLAG2_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_FLAG2_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_FLAG2_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_FLAG2_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_FLAG2_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_FLAG2_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_FLAG2_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_FLAG2_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_FLAG2_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_FLAG2_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_FLAG2_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_FLAG2_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_FLAG3_MASK (0x00001220)
+
+#define BP_PXP_WFB_ARRAY_FLAG3_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_FLAG3_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_FLAG3_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_FLAG3_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_FLAG3_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_FLAG3_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_FLAG3_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_FLAG3_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_FLAG3_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG3_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_FLAG3_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_FLAG3_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_FLAG3_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_FLAG3_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_FLAG3_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_FLAG3_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_FLAG3_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_FLAG3_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_FLAG3_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG3_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_FLAG3_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_FLAG3_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_FLAG3_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_FLAG3_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG3_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_FLAG3_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_FLAG3_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_FLAG3_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_FLAG3_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_FLAG3_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_FLAG3_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_FLAG3_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_FLAG3_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_FLAG3_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_FLAG3_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_FLAG3_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_FLAG3_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_FLAG3_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_FLAG3_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_FLAG3_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_FLAG3_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_FLAG3_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_FLAG3_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_FLAG3_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_FLAG3_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_FLAG3_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_FLAG3_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_FLAG3_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_FLAG3_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_FLAG3_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_FLAG3_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_FLAG3_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_FLAG3_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_FLAG3_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_FLAG3_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_FLAG3_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_FLAG3_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_FLAG4_MASK (0x00001230)
+
+#define BP_PXP_WFB_ARRAY_FLAG4_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_FLAG4_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_FLAG4_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_FLAG4_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_FLAG4_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_FLAG4_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_FLAG4_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_FLAG4_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_FLAG4_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG4_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_FLAG4_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_FLAG4_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_FLAG4_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_FLAG4_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_FLAG4_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_FLAG4_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_FLAG4_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_FLAG4_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_FLAG4_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG4_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_FLAG4_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_FLAG4_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_FLAG4_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_FLAG4_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG4_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_FLAG4_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_FLAG4_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_FLAG4_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_FLAG4_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_FLAG4_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_FLAG4_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_FLAG4_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_FLAG4_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_FLAG4_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_FLAG4_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_FLAG4_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_FLAG4_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_FLAG4_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_FLAG4_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_FLAG4_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_FLAG4_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_FLAG4_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_FLAG4_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_FLAG4_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_FLAG4_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_FLAG4_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_FLAG4_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_FLAG4_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_FLAG4_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_FLAG4_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_FLAG4_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_FLAG4_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_FLAG4_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_FLAG4_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_FLAG4_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_FLAG4_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_FLAG4_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_FLAG5_MASK (0x00001240)
+
+#define BP_PXP_WFB_ARRAY_FLAG5_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_FLAG5_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_FLAG5_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_FLAG5_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_FLAG5_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_FLAG5_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_FLAG5_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_FLAG5_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_FLAG5_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG5_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_FLAG5_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_FLAG5_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_FLAG5_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_FLAG5_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_FLAG5_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_FLAG5_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_FLAG5_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_FLAG5_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_FLAG5_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG5_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_FLAG5_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_FLAG5_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_FLAG5_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_FLAG5_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG5_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_FLAG5_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_FLAG5_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_FLAG5_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_FLAG5_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_FLAG5_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_FLAG5_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_FLAG5_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_FLAG5_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_FLAG5_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_FLAG5_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_FLAG5_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_FLAG5_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_FLAG5_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_FLAG5_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_FLAG5_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_FLAG5_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_FLAG5_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_FLAG5_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_FLAG5_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_FLAG5_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_FLAG5_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_FLAG5_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_FLAG5_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_FLAG5_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_FLAG5_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_FLAG5_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_FLAG5_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_FLAG5_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_FLAG5_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_FLAG5_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_FLAG5_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_FLAG5_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_FLAG6_MASK (0x00001250)
+
+#define BP_PXP_WFB_ARRAY_FLAG6_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_FLAG6_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_FLAG6_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_FLAG6_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_FLAG6_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_FLAG6_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_FLAG6_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_FLAG6_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_FLAG6_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG6_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_FLAG6_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_FLAG6_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_FLAG6_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_FLAG6_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_FLAG6_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_FLAG6_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_FLAG6_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_FLAG6_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_FLAG6_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG6_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_FLAG6_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_FLAG6_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_FLAG6_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_FLAG6_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG6_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_FLAG6_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_FLAG6_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_FLAG6_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_FLAG6_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_FLAG6_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_FLAG6_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_FLAG6_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_FLAG6_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_FLAG6_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_FLAG6_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_FLAG6_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_FLAG6_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_FLAG6_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_FLAG6_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_FLAG6_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_FLAG6_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_FLAG6_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_FLAG6_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_FLAG6_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_FLAG6_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_FLAG6_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_FLAG6_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_FLAG6_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_FLAG6_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_FLAG6_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_FLAG6_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_FLAG6_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_FLAG6_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_FLAG6_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_FLAG6_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_FLAG6_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_FLAG6_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_FLAG7_MASK (0x00001260)
+
+#define BP_PXP_WFB_ARRAY_FLAG7_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_FLAG7_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_FLAG7_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_FLAG7_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_FLAG7_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_FLAG7_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_FLAG7_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_FLAG7_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_FLAG7_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG7_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_FLAG7_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_FLAG7_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_FLAG7_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_FLAG7_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_FLAG7_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_FLAG7_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_FLAG7_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_FLAG7_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_FLAG7_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG7_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_FLAG7_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_FLAG7_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_FLAG7_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_FLAG7_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG7_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_FLAG7_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_FLAG7_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_FLAG7_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_FLAG7_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_FLAG7_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_FLAG7_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_FLAG7_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_FLAG7_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_FLAG7_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_FLAG7_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_FLAG7_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_FLAG7_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_FLAG7_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_FLAG7_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_FLAG7_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_FLAG7_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_FLAG7_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_FLAG7_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_FLAG7_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_FLAG7_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_FLAG7_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_FLAG7_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_FLAG7_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_FLAG7_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_FLAG7_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_FLAG7_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_FLAG7_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_FLAG7_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_FLAG7_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_FLAG7_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_FLAG7_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_FLAG7_MASK_L_OFS)
+
+#define HW_PXP_WFB_FETCH_BUF1_CORD (0x00001270)
+
+#define BP_PXP_WFB_FETCH_BUF1_CORD_RSVD0 30
+#define BM_PXP_WFB_FETCH_BUF1_CORD_RSVD0 0xC0000000
+#define BF_PXP_WFB_FETCH_BUF1_CORD_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_FETCH_BUF1_CORD_RSVD0)
+#define BP_PXP_WFB_FETCH_BUF1_CORD_YCORD 16
+#define BM_PXP_WFB_FETCH_BUF1_CORD_YCORD 0x3FFF0000
+#define BF_PXP_WFB_FETCH_BUF1_CORD_YCORD(v) \
+ (((v) << 16) & BM_PXP_WFB_FETCH_BUF1_CORD_YCORD)
+#define BP_PXP_WFB_FETCH_BUF1_CORD_RSVD1 14
+#define BM_PXP_WFB_FETCH_BUF1_CORD_RSVD1 0x0000C000
+#define BF_PXP_WFB_FETCH_BUF1_CORD_RSVD1(v) \
+ (((v) << 14) & BM_PXP_WFB_FETCH_BUF1_CORD_RSVD1)
+#define BP_PXP_WFB_FETCH_BUF1_CORD_XCORD 0
+#define BM_PXP_WFB_FETCH_BUF1_CORD_XCORD 0x00003FFF
+#define BF_PXP_WFB_FETCH_BUF1_CORD_XCORD(v) \
+ (((v) << 0) & BM_PXP_WFB_FETCH_BUF1_CORD_XCORD)
+
+#define HW_PXP_WFB_FETCH_BUF2_CORD (0x00001280)
+
+#define BP_PXP_WFB_FETCH_BUF2_CORD_RSVD0 30
+#define BM_PXP_WFB_FETCH_BUF2_CORD_RSVD0 0xC0000000
+#define BF_PXP_WFB_FETCH_BUF2_CORD_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_FETCH_BUF2_CORD_RSVD0)
+#define BP_PXP_WFB_FETCH_BUF2_CORD_YCORD 16
+#define BM_PXP_WFB_FETCH_BUF2_CORD_YCORD 0x3FFF0000
+#define BF_PXP_WFB_FETCH_BUF2_CORD_YCORD(v) \
+ (((v) << 16) & BM_PXP_WFB_FETCH_BUF2_CORD_YCORD)
+#define BP_PXP_WFB_FETCH_BUF2_CORD_RSVD1 14
+#define BM_PXP_WFB_FETCH_BUF2_CORD_RSVD1 0x0000C000
+#define BF_PXP_WFB_FETCH_BUF2_CORD_RSVD1(v) \
+ (((v) << 14) & BM_PXP_WFB_FETCH_BUF2_CORD_RSVD1)
+#define BP_PXP_WFB_FETCH_BUF2_CORD_XCORD 0
+#define BM_PXP_WFB_FETCH_BUF2_CORD_XCORD 0x00003FFF
+#define BF_PXP_WFB_FETCH_BUF2_CORD_XCORD(v) \
+ (((v) << 0) & BM_PXP_WFB_FETCH_BUF2_CORD_XCORD)
+
+#define HW_PXP_WFB_ARRAY_FLAG8_MASK (0x00001290)
+
+#define BP_PXP_WFB_ARRAY_FLAG8_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_FLAG8_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_FLAG8_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_FLAG8_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_FLAG8_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_FLAG8_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_FLAG8_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_FLAG8_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_FLAG8_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG8_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_FLAG8_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_FLAG8_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_FLAG8_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_FLAG8_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_FLAG8_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_FLAG8_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_FLAG8_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_FLAG8_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_FLAG8_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG8_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_FLAG8_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_FLAG8_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_FLAG8_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_FLAG8_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG8_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_FLAG8_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_FLAG8_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_FLAG8_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_FLAG8_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_FLAG8_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_FLAG8_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_FLAG8_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_FLAG8_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_FLAG8_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_FLAG8_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_FLAG8_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_FLAG8_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_FLAG8_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_FLAG8_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_FLAG8_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_FLAG8_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_FLAG8_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_FLAG8_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_FLAG8_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_FLAG8_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_FLAG8_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_FLAG8_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_FLAG8_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_FLAG8_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_FLAG8_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_FLAG8_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_FLAG8_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_FLAG8_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_FLAG8_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_FLAG8_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_FLAG8_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_FLAG8_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_FLAG9_MASK (0x000012a0)
+
+#define BP_PXP_WFB_ARRAY_FLAG9_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_FLAG9_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_FLAG9_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_FLAG9_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_FLAG9_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_FLAG9_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_FLAG9_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_FLAG9_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_FLAG9_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG9_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_FLAG9_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_FLAG9_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_FLAG9_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_FLAG9_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_FLAG9_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_FLAG9_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_FLAG9_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_FLAG9_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_FLAG9_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG9_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_FLAG9_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_FLAG9_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_FLAG9_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_FLAG9_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG9_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_FLAG9_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_FLAG9_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_FLAG9_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_FLAG9_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_FLAG9_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_FLAG9_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_FLAG9_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_FLAG9_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_FLAG9_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_FLAG9_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_FLAG9_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_FLAG9_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_FLAG9_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_FLAG9_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_FLAG9_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_FLAG9_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_FLAG9_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_FLAG9_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_FLAG9_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_FLAG9_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_FLAG9_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_FLAG9_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_FLAG9_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_FLAG9_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_FLAG9_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_FLAG9_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_FLAG9_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_FLAG9_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_FLAG9_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_FLAG9_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_FLAG9_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_FLAG9_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_FLAG10_MASK (0x000012b0)
+
+#define BP_PXP_WFB_ARRAY_FLAG10_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_FLAG10_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_FLAG10_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_FLAG10_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_FLAG10_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_FLAG10_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_FLAG10_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_FLAG10_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_FLAG10_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG10_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_FLAG10_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_FLAG10_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_FLAG10_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_FLAG10_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_FLAG10_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_FLAG10_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_FLAG10_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_FLAG10_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_FLAG10_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG10_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_FLAG10_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_FLAG10_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_FLAG10_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_FLAG10_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG10_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_FLAG10_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_FLAG10_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_FLAG10_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_FLAG10_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_FLAG10_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_FLAG10_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_FLAG10_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_FLAG10_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_FLAG10_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_FLAG10_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_FLAG10_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_FLAG10_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_FLAG10_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_FLAG10_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_FLAG10_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_FLAG10_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_FLAG10_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_FLAG10_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_FLAG10_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_FLAG10_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_FLAG10_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_FLAG10_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_FLAG10_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_FLAG10_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_FLAG10_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_FLAG10_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_FLAG10_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_FLAG10_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_FLAG10_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_FLAG10_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_FLAG10_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_FLAG10_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_FLAG11_MASK (0x000012c0)
+
+#define BP_PXP_WFB_ARRAY_FLAG11_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_FLAG11_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_FLAG11_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_FLAG11_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_FLAG11_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_FLAG11_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_FLAG11_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_FLAG11_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_FLAG11_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG11_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_FLAG11_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_FLAG11_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_FLAG11_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_FLAG11_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_FLAG11_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_FLAG11_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_FLAG11_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_FLAG11_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_FLAG11_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG11_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_FLAG11_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_FLAG11_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_FLAG11_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_FLAG11_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG11_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_FLAG11_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_FLAG11_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_FLAG11_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_FLAG11_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_FLAG11_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_FLAG11_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_FLAG11_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_FLAG11_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_FLAG11_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_FLAG11_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_FLAG11_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_FLAG11_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_FLAG11_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_FLAG11_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_FLAG11_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_FLAG11_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_FLAG11_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_FLAG11_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_FLAG11_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_FLAG11_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_FLAG11_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_FLAG11_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_FLAG11_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_FLAG11_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_FLAG11_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_FLAG11_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_FLAG11_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_FLAG11_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_FLAG11_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_FLAG11_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_FLAG11_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_FLAG11_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_FLAG12_MASK (0x000012d0)
+
+#define BP_PXP_WFB_ARRAY_FLAG12_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_FLAG12_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_FLAG12_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_FLAG12_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_FLAG12_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_FLAG12_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_FLAG12_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_FLAG12_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_FLAG12_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG12_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_FLAG12_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_FLAG12_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_FLAG12_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_FLAG12_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_FLAG12_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_FLAG12_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_FLAG12_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_FLAG12_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_FLAG12_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG12_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_FLAG12_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_FLAG12_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_FLAG12_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_FLAG12_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG12_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_FLAG12_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_FLAG12_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_FLAG12_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_FLAG12_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_FLAG12_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_FLAG12_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_FLAG12_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_FLAG12_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_FLAG12_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_FLAG12_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_FLAG12_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_FLAG12_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_FLAG12_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_FLAG12_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_FLAG12_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_FLAG12_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_FLAG12_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_FLAG12_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_FLAG12_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_FLAG12_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_FLAG12_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_FLAG12_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_FLAG12_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_FLAG12_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_FLAG12_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_FLAG12_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_FLAG12_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_FLAG12_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_FLAG12_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_FLAG12_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_FLAG12_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_FLAG12_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_FLAG13_MASK (0x000012e0)
+
+#define BP_PXP_WFB_ARRAY_FLAG13_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_FLAG13_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_FLAG13_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_FLAG13_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_FLAG13_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_FLAG13_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_FLAG13_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_FLAG13_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_FLAG13_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG13_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_FLAG13_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_FLAG13_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_FLAG13_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_FLAG13_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_FLAG13_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_FLAG13_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_FLAG13_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_FLAG13_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_FLAG13_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG13_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_FLAG13_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_FLAG13_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_FLAG13_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_FLAG13_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG13_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_FLAG13_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_FLAG13_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_FLAG13_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_FLAG13_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_FLAG13_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_FLAG13_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_FLAG13_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_FLAG13_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_FLAG13_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_FLAG13_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_FLAG13_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_FLAG13_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_FLAG13_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_FLAG13_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_FLAG13_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_FLAG13_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_FLAG13_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_FLAG13_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_FLAG13_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_FLAG13_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_FLAG13_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_FLAG13_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_FLAG13_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_FLAG13_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_FLAG13_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_FLAG13_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_FLAG13_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_FLAG13_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_FLAG13_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_FLAG13_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_FLAG13_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_FLAG13_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_FLAG14_MASK (0x000012f0)
+
+#define BP_PXP_WFB_ARRAY_FLAG14_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_FLAG14_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_FLAG14_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_FLAG14_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_FLAG14_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_FLAG14_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_FLAG14_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_FLAG14_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_FLAG14_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG14_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_FLAG14_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_FLAG14_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_FLAG14_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_FLAG14_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_FLAG14_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_FLAG14_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_FLAG14_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_FLAG14_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_FLAG14_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG14_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_FLAG14_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_FLAG14_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_FLAG14_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_FLAG14_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG14_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_FLAG14_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_FLAG14_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_FLAG14_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_FLAG14_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_FLAG14_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_FLAG14_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_FLAG14_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_FLAG14_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_FLAG14_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_FLAG14_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_FLAG14_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_FLAG14_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_FLAG14_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_FLAG14_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_FLAG14_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_FLAG14_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_FLAG14_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_FLAG14_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_FLAG14_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_FLAG14_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_FLAG14_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_FLAG14_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_FLAG14_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_FLAG14_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_FLAG14_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_FLAG14_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_FLAG14_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_FLAG14_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_FLAG14_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_FLAG14_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_FLAG14_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_FLAG14_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_FLAG15_MASK (0x00001300)
+
+#define BP_PXP_WFB_ARRAY_FLAG15_MASK_RSVD0 30
+#define BM_PXP_WFB_ARRAY_FLAG15_MASK_RSVD0 0xC0000000
+#define BF_PXP_WFB_ARRAY_FLAG15_MASK_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFB_ARRAY_FLAG15_MASK_RSVD0)
+#define BP_PXP_WFB_ARRAY_FLAG15_MASK_BUF_SEL 28
+#define BM_PXP_WFB_ARRAY_FLAG15_MASK_BUF_SEL 0x30000000
+#define BF_PXP_WFB_ARRAY_FLAG15_MASK_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_WFB_ARRAY_FLAG15_MASK_BUF_SEL)
+#define BV_PXP_WFB_ARRAY_FLAG15_MASK_BUF_SEL__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG15_MASK_BUF_SEL__1 0x1
+#define BV_PXP_WFB_ARRAY_FLAG15_MASK_BUF_SEL__2 0x2
+#define BP_PXP_WFB_ARRAY_FLAG15_MASK_RSVD1 26
+#define BM_PXP_WFB_ARRAY_FLAG15_MASK_RSVD1 0x0C000000
+#define BF_PXP_WFB_ARRAY_FLAG15_MASK_RSVD1(v) \
+ (((v) << 26) & BM_PXP_WFB_ARRAY_FLAG15_MASK_RSVD1)
+#define BM_PXP_WFB_ARRAY_FLAG15_MASK_SIGN_Y 0x02000000
+#define BF_PXP_WFB_ARRAY_FLAG15_MASK_SIGN_Y(v) \
+ (((v) << 25) & BM_PXP_WFB_ARRAY_FLAG15_MASK_SIGN_Y)
+#define BV_PXP_WFB_ARRAY_FLAG15_MASK_SIGN_Y__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG15_MASK_SIGN_Y__1 0x1
+#define BM_PXP_WFB_ARRAY_FLAG15_MASK_SIGN_X 0x01000000
+#define BF_PXP_WFB_ARRAY_FLAG15_MASK_SIGN_X(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_FLAG15_MASK_SIGN_X)
+#define BV_PXP_WFB_ARRAY_FLAG15_MASK_SIGN_X__0 0x0
+#define BV_PXP_WFB_ARRAY_FLAG15_MASK_SIGN_X__1 0x1
+#define BP_PXP_WFB_ARRAY_FLAG15_MASK_RSVD2 22
+#define BM_PXP_WFB_ARRAY_FLAG15_MASK_RSVD2 0x00C00000
+#define BF_PXP_WFB_ARRAY_FLAG15_MASK_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFB_ARRAY_FLAG15_MASK_RSVD2)
+#define BP_PXP_WFB_ARRAY_FLAG15_MASK_OFFSET_Y 20
+#define BM_PXP_WFB_ARRAY_FLAG15_MASK_OFFSET_Y 0x00300000
+#define BF_PXP_WFB_ARRAY_FLAG15_MASK_OFFSET_Y(v) \
+ (((v) << 20) & BM_PXP_WFB_ARRAY_FLAG15_MASK_OFFSET_Y)
+#define BP_PXP_WFB_ARRAY_FLAG15_MASK_RSVD3 18
+#define BM_PXP_WFB_ARRAY_FLAG15_MASK_RSVD3 0x000C0000
+#define BF_PXP_WFB_ARRAY_FLAG15_MASK_RSVD3(v) \
+ (((v) << 18) & BM_PXP_WFB_ARRAY_FLAG15_MASK_RSVD3)
+#define BP_PXP_WFB_ARRAY_FLAG15_MASK_OFFSET_X 16
+#define BM_PXP_WFB_ARRAY_FLAG15_MASK_OFFSET_X 0x00030000
+#define BF_PXP_WFB_ARRAY_FLAG15_MASK_OFFSET_X(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_FLAG15_MASK_OFFSET_X)
+#define BP_PXP_WFB_ARRAY_FLAG15_MASK_RSVD4 13
+#define BM_PXP_WFB_ARRAY_FLAG15_MASK_RSVD4 0x0000E000
+#define BF_PXP_WFB_ARRAY_FLAG15_MASK_RSVD4(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_FLAG15_MASK_RSVD4)
+#define BP_PXP_WFB_ARRAY_FLAG15_MASK_H_OFS 8
+#define BM_PXP_WFB_ARRAY_FLAG15_MASK_H_OFS 0x00001F00
+#define BF_PXP_WFB_ARRAY_FLAG15_MASK_H_OFS(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_FLAG15_MASK_H_OFS)
+#define BP_PXP_WFB_ARRAY_FLAG15_MASK_RSVD5 5
+#define BM_PXP_WFB_ARRAY_FLAG15_MASK_RSVD5 0x000000E0
+#define BF_PXP_WFB_ARRAY_FLAG15_MASK_RSVD5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_FLAG15_MASK_RSVD5)
+#define BP_PXP_WFB_ARRAY_FLAG15_MASK_L_OFS 0
+#define BM_PXP_WFB_ARRAY_FLAG15_MASK_L_OFS 0x0000001F
+#define BF_PXP_WFB_ARRAY_FLAG15_MASK_L_OFS(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_FLAG15_MASK_L_OFS)
+
+#define HW_PXP_WFB_ARRAY_REG0 (0x00001310)
+
+#define BP_PXP_WFB_ARRAY_REG0_SW_PIXLE3 24
+#define BM_PXP_WFB_ARRAY_REG0_SW_PIXLE3 0xFF000000
+#define BF_PXP_WFB_ARRAY_REG0_SW_PIXLE3(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_REG0_SW_PIXLE3)
+#define BP_PXP_WFB_ARRAY_REG0_SW_PIXLE2 16
+#define BM_PXP_WFB_ARRAY_REG0_SW_PIXLE2 0x00FF0000
+#define BF_PXP_WFB_ARRAY_REG0_SW_PIXLE2(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_REG0_SW_PIXLE2)
+#define BP_PXP_WFB_ARRAY_REG0_SW_PIXLE1 8
+#define BM_PXP_WFB_ARRAY_REG0_SW_PIXLE1 0x0000FF00
+#define BF_PXP_WFB_ARRAY_REG0_SW_PIXLE1(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_REG0_SW_PIXLE1)
+#define BP_PXP_WFB_ARRAY_REG0_SW_PIXLE0 0
+#define BM_PXP_WFB_ARRAY_REG0_SW_PIXLE0 0x000000FF
+#define BF_PXP_WFB_ARRAY_REG0_SW_PIXLE0(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_REG0_SW_PIXLE0)
+
+#define HW_PXP_WFB_ARRAY_REG1 (0x00001320)
+
+#define BP_PXP_WFB_ARRAY_REG1_SW_PIXLE7 24
+#define BM_PXP_WFB_ARRAY_REG1_SW_PIXLE7 0xFF000000
+#define BF_PXP_WFB_ARRAY_REG1_SW_PIXLE7(v) \
+ (((v) << 24) & BM_PXP_WFB_ARRAY_REG1_SW_PIXLE7)
+#define BP_PXP_WFB_ARRAY_REG1_SW_PIXLE6 16
+#define BM_PXP_WFB_ARRAY_REG1_SW_PIXLE6 0x00FF0000
+#define BF_PXP_WFB_ARRAY_REG1_SW_PIXLE6(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_REG1_SW_PIXLE6)
+#define BP_PXP_WFB_ARRAY_REG1_SW_PIXLE5 8
+#define BM_PXP_WFB_ARRAY_REG1_SW_PIXLE5 0x0000FF00
+#define BF_PXP_WFB_ARRAY_REG1_SW_PIXLE5(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_REG1_SW_PIXLE5)
+#define BP_PXP_WFB_ARRAY_REG1_SW_PIXLE4 0
+#define BM_PXP_WFB_ARRAY_REG1_SW_PIXLE4 0x000000FF
+#define BF_PXP_WFB_ARRAY_REG1_SW_PIXLE4(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_REG1_SW_PIXLE4)
+
+#define HW_PXP_WFB_ARRAY_REG2 (0x00001330)
+
+#define BP_PXP_WFB_ARRAY_REG2_RSVD0 16
+#define BM_PXP_WFB_ARRAY_REG2_RSVD0 0xFFFF0000
+#define BF_PXP_WFB_ARRAY_REG2_RSVD0(v) \
+ (((v) << 16) & BM_PXP_WFB_ARRAY_REG2_RSVD0)
+#define BM_PXP_WFB_ARRAY_REG2_SW_FLAG15 0x00008000
+#define BF_PXP_WFB_ARRAY_REG2_SW_FLAG15(v) \
+ (((v) << 15) & BM_PXP_WFB_ARRAY_REG2_SW_FLAG15)
+#define BM_PXP_WFB_ARRAY_REG2_SW_FLAG14 0x00004000
+#define BF_PXP_WFB_ARRAY_REG2_SW_FLAG14(v) \
+ (((v) << 14) & BM_PXP_WFB_ARRAY_REG2_SW_FLAG14)
+#define BM_PXP_WFB_ARRAY_REG2_SW_FLAG13 0x00002000
+#define BF_PXP_WFB_ARRAY_REG2_SW_FLAG13(v) \
+ (((v) << 13) & BM_PXP_WFB_ARRAY_REG2_SW_FLAG13)
+#define BM_PXP_WFB_ARRAY_REG2_SW_FLAG12 0x00001000
+#define BF_PXP_WFB_ARRAY_REG2_SW_FLAG12(v) \
+ (((v) << 12) & BM_PXP_WFB_ARRAY_REG2_SW_FLAG12)
+#define BM_PXP_WFB_ARRAY_REG2_SW_FLAG11 0x00000800
+#define BF_PXP_WFB_ARRAY_REG2_SW_FLAG11(v) \
+ (((v) << 11) & BM_PXP_WFB_ARRAY_REG2_SW_FLAG11)
+#define BM_PXP_WFB_ARRAY_REG2_SW_FLAG10 0x00000400
+#define BF_PXP_WFB_ARRAY_REG2_SW_FLAG10(v) \
+ (((v) << 10) & BM_PXP_WFB_ARRAY_REG2_SW_FLAG10)
+#define BM_PXP_WFB_ARRAY_REG2_SW_FLAG9 0x00000200
+#define BF_PXP_WFB_ARRAY_REG2_SW_FLAG9(v) \
+ (((v) << 9) & BM_PXP_WFB_ARRAY_REG2_SW_FLAG9)
+#define BM_PXP_WFB_ARRAY_REG2_SW_FLAG8 0x00000100
+#define BF_PXP_WFB_ARRAY_REG2_SW_FLAG8(v) \
+ (((v) << 8) & BM_PXP_WFB_ARRAY_REG2_SW_FLAG8)
+#define BM_PXP_WFB_ARRAY_REG2_SW_FLAG7 0x00000080
+#define BF_PXP_WFB_ARRAY_REG2_SW_FLAG7(v) \
+ (((v) << 7) & BM_PXP_WFB_ARRAY_REG2_SW_FLAG7)
+#define BM_PXP_WFB_ARRAY_REG2_SW_FLAG6 0x00000040
+#define BF_PXP_WFB_ARRAY_REG2_SW_FLAG6(v) \
+ (((v) << 6) & BM_PXP_WFB_ARRAY_REG2_SW_FLAG6)
+#define BM_PXP_WFB_ARRAY_REG2_SW_FLAG5 0x00000020
+#define BF_PXP_WFB_ARRAY_REG2_SW_FLAG5(v) \
+ (((v) << 5) & BM_PXP_WFB_ARRAY_REG2_SW_FLAG5)
+#define BM_PXP_WFB_ARRAY_REG2_SW_FLAG4 0x00000010
+#define BF_PXP_WFB_ARRAY_REG2_SW_FLAG4(v) \
+ (((v) << 4) & BM_PXP_WFB_ARRAY_REG2_SW_FLAG4)
+#define BM_PXP_WFB_ARRAY_REG2_SW_FLAG3 0x00000008
+#define BF_PXP_WFB_ARRAY_REG2_SW_FLAG3(v) \
+ (((v) << 3) & BM_PXP_WFB_ARRAY_REG2_SW_FLAG3)
+#define BM_PXP_WFB_ARRAY_REG2_SW_FLAG2 0x00000004
+#define BF_PXP_WFB_ARRAY_REG2_SW_FLAG2(v) \
+ (((v) << 2) & BM_PXP_WFB_ARRAY_REG2_SW_FLAG2)
+#define BM_PXP_WFB_ARRAY_REG2_SW_FLAG1 0x00000002
+#define BF_PXP_WFB_ARRAY_REG2_SW_FLAG1(v) \
+ (((v) << 1) & BM_PXP_WFB_ARRAY_REG2_SW_FLAG1)
+#define BM_PXP_WFB_ARRAY_REG2_SW_FLAG0 0x00000001
+#define BF_PXP_WFB_ARRAY_REG2_SW_FLAG0(v) \
+ (((v) << 0) & BM_PXP_WFB_ARRAY_REG2_SW_FLAG0)
+
+#define HW_PXP_WFE_B_STORE_CTRL_CH0 (0x00001340)
+#define HW_PXP_WFE_B_STORE_CTRL_CH0_SET (0x00001344)
+#define HW_PXP_WFE_B_STORE_CTRL_CH0_CLR (0x00001348)
+#define HW_PXP_WFE_B_STORE_CTRL_CH0_TOG (0x0000134c)
+
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_ARBIT_EN 0x80000000
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_ARBIT_EN(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STORE_CTRL_CH0_ARBIT_EN)
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_ARBIT_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_ARBIT_EN__1 0x1
+#define BP_PXP_WFE_B_STORE_CTRL_CH0_RSVD0 25
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_RSVD0 0x7E000000
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_RSVD0(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STORE_CTRL_CH0_RSVD0)
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_COMBINE_2CHANNEL 0x01000000
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_COMBINE_2CHANNEL(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STORE_CTRL_CH0_COMBINE_2CHANNEL)
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_COMBINE_2CHANNEL__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_COMBINE_2CHANNEL__1 0x1
+#define BP_PXP_WFE_B_STORE_CTRL_CH0_RSVD1 18
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_RSVD1 0x00FC0000
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_RSVD1(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STORE_CTRL_CH0_RSVD1)
+#define BP_PXP_WFE_B_STORE_CTRL_CH0_WR_NUM_BYTES 16
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_WR_NUM_BYTES 0x00030000
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_WR_NUM_BYTES(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STORE_CTRL_CH0_WR_NUM_BYTES)
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_WR_NUM_BYTES__8_bytes 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_WR_NUM_BYTES__16_bytes 0x1
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_WR_NUM_BYTES__32_bytes 0x2
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_WR_NUM_BYTES__64_bytes 0x3
+#define BP_PXP_WFE_B_STORE_CTRL_CH0_RSVD2 12
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_RSVD2 0x0000F000
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_RSVD2(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STORE_CTRL_CH0_RSVD2)
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_FILL_DATA_EN 0x00000800
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_FILL_DATA_EN(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STORE_CTRL_CH0_FILL_DATA_EN)
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_FILL_DATA_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_FILL_DATA_EN__1 0x1
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_PACK_IN_SEL 0x00000400
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_PACK_IN_SEL(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STORE_CTRL_CH0_PACK_IN_SEL)
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_PACK_IN_SEL__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_PACK_IN_SEL__1 0x1
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_STORE_MEMORY_EN 0x00000200
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_STORE_MEMORY_EN(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STORE_CTRL_CH0_STORE_MEMORY_EN)
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_STORE_MEMORY_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_STORE_MEMORY_EN__1 0x1
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_STORE_BYPASS_EN 0x00000100
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_STORE_BYPASS_EN(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STORE_CTRL_CH0_STORE_BYPASS_EN)
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_STORE_BYPASS_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_STORE_BYPASS_EN__1 0x1
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_RSVD3 0x00000080
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_RSVD3(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STORE_CTRL_CH0_RSVD3)
+#define BP_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_LINE_NUM 5
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_LINE_NUM 0x00000060
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_LINE_NUM(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_LINE_NUM)
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_LINE_NUM__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_LINE_NUM__1 0x1
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_LINE_NUM__2 0x2
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_LINE_NUM__3 0x3
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_EN 0x00000010
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_EN(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_EN)
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_ARRAY_EN__1 0x1
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_HANDSHAKE_EN 0x00000008
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_HANDSHAKE_EN(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STORE_CTRL_CH0_HANDSHAKE_EN)
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_HANDSHAKE_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_HANDSHAKE_EN__1 0x1
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_BLOCK_16 0x00000004
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_BLOCK_16(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STORE_CTRL_CH0_BLOCK_16)
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_BLOCK_16__8x8 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_BLOCK_16__16x16 0x1
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_BLOCK_EN 0x00000002
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_BLOCK_EN(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STORE_CTRL_CH0_BLOCK_EN)
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_BLOCK_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_BLOCK_EN__1 0x1
+#define BM_PXP_WFE_B_STORE_CTRL_CH0_CH_EN 0x00000001
+#define BF_PXP_WFE_B_STORE_CTRL_CH0_CH_EN(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STORE_CTRL_CH0_CH_EN)
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_CH_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH0_CH_EN__1 0x1
+
+#define HW_PXP_WFE_B_STORE_CTRL_CH1 (0x00001350)
+#define HW_PXP_WFE_B_STORE_CTRL_CH1_SET (0x00001354)
+#define HW_PXP_WFE_B_STORE_CTRL_CH1_CLR (0x00001358)
+#define HW_PXP_WFE_B_STORE_CTRL_CH1_TOG (0x0000135c)
+
+#define BP_PXP_WFE_B_STORE_CTRL_CH1_RSVD0 18
+#define BM_PXP_WFE_B_STORE_CTRL_CH1_RSVD0 0xFFFC0000
+#define BF_PXP_WFE_B_STORE_CTRL_CH1_RSVD0(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STORE_CTRL_CH1_RSVD0)
+#define BP_PXP_WFE_B_STORE_CTRL_CH1_WR_NUM_BYTES 16
+#define BM_PXP_WFE_B_STORE_CTRL_CH1_WR_NUM_BYTES 0x00030000
+#define BF_PXP_WFE_B_STORE_CTRL_CH1_WR_NUM_BYTES(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STORE_CTRL_CH1_WR_NUM_BYTES)
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_WR_NUM_BYTES__8_bytes 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_WR_NUM_BYTES__16_bytes 0x1
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_WR_NUM_BYTES__32_bytes 0x2
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_WR_NUM_BYTES__64_bytes 0x3
+#define BP_PXP_WFE_B_STORE_CTRL_CH1_RSVD1 11
+#define BM_PXP_WFE_B_STORE_CTRL_CH1_RSVD1 0x0000F800
+#define BF_PXP_WFE_B_STORE_CTRL_CH1_RSVD1(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STORE_CTRL_CH1_RSVD1)
+#define BM_PXP_WFE_B_STORE_CTRL_CH1_PACK_IN_SEL 0x00000400
+#define BF_PXP_WFE_B_STORE_CTRL_CH1_PACK_IN_SEL(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STORE_CTRL_CH1_PACK_IN_SEL)
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_PACK_IN_SEL__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_PACK_IN_SEL__1 0x1
+#define BM_PXP_WFE_B_STORE_CTRL_CH1_STORE_MEMORY_EN 0x00000200
+#define BF_PXP_WFE_B_STORE_CTRL_CH1_STORE_MEMORY_EN(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STORE_CTRL_CH1_STORE_MEMORY_EN)
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_STORE_MEMORY_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_STORE_MEMORY_EN__1 0x1
+#define BM_PXP_WFE_B_STORE_CTRL_CH1_STORE_BYPASS_EN 0x00000100
+#define BF_PXP_WFE_B_STORE_CTRL_CH1_STORE_BYPASS_EN(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STORE_CTRL_CH1_STORE_BYPASS_EN)
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_STORE_BYPASS_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_STORE_BYPASS_EN__1 0x1
+#define BM_PXP_WFE_B_STORE_CTRL_CH1_RSVD3 0x00000080
+#define BF_PXP_WFE_B_STORE_CTRL_CH1_RSVD3(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STORE_CTRL_CH1_RSVD3)
+#define BP_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_LINE_NUM 5
+#define BM_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_LINE_NUM 0x00000060
+#define BF_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_LINE_NUM(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_LINE_NUM)
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_LINE_NUM__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_LINE_NUM__1 0x1
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_LINE_NUM__2 0x2
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_LINE_NUM__3 0x3
+#define BM_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_EN 0x00000010
+#define BF_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_EN(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_EN)
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_ARRAY_EN__1 0x1
+#define BM_PXP_WFE_B_STORE_CTRL_CH1_HANDSHAKE_EN 0x00000008
+#define BF_PXP_WFE_B_STORE_CTRL_CH1_HANDSHAKE_EN(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STORE_CTRL_CH1_HANDSHAKE_EN)
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_HANDSHAKE_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_HANDSHAKE_EN__1 0x1
+#define BM_PXP_WFE_B_STORE_CTRL_CH1_BLOCK_16 0x00000004
+#define BF_PXP_WFE_B_STORE_CTRL_CH1_BLOCK_16(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STORE_CTRL_CH1_BLOCK_16)
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_BLOCK_16__8x8 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_BLOCK_16__16x16 0x1
+#define BM_PXP_WFE_B_STORE_CTRL_CH1_BLOCK_EN 0x00000002
+#define BF_PXP_WFE_B_STORE_CTRL_CH1_BLOCK_EN(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STORE_CTRL_CH1_BLOCK_EN)
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_BLOCK_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_BLOCK_EN__1 0x1
+#define BM_PXP_WFE_B_STORE_CTRL_CH1_CH_EN 0x00000001
+#define BF_PXP_WFE_B_STORE_CTRL_CH1_CH_EN(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STORE_CTRL_CH1_CH_EN)
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_CH_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_CTRL_CH1_CH_EN__1 0x1
+
+#define HW_PXP_WFE_B_STORE_STATUS_CH0 (0x00001360)
+
+#define BP_PXP_WFE_B_STORE_STATUS_CH0_STORE_BLOCK_Y 16
+#define BM_PXP_WFE_B_STORE_STATUS_CH0_STORE_BLOCK_Y 0xFFFF0000
+#define BF_PXP_WFE_B_STORE_STATUS_CH0_STORE_BLOCK_Y(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STORE_STATUS_CH0_STORE_BLOCK_Y)
+#define BP_PXP_WFE_B_STORE_STATUS_CH0_STORE_BLOCK_X 0
+#define BM_PXP_WFE_B_STORE_STATUS_CH0_STORE_BLOCK_X 0x0000FFFF
+#define BF_PXP_WFE_B_STORE_STATUS_CH0_STORE_BLOCK_X(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STORE_STATUS_CH0_STORE_BLOCK_X)
+
+#define HW_PXP_WFE_B_STORE_STATUS_CH1 (0x00001370)
+
+#define BP_PXP_WFE_B_STORE_STATUS_CH1_STORE_BLOCK_Y 16
+#define BM_PXP_WFE_B_STORE_STATUS_CH1_STORE_BLOCK_Y 0xFFFF0000
+#define BF_PXP_WFE_B_STORE_STATUS_CH1_STORE_BLOCK_Y(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STORE_STATUS_CH1_STORE_BLOCK_Y)
+#define BP_PXP_WFE_B_STORE_STATUS_CH1_STORE_BLOCK_X 0
+#define BM_PXP_WFE_B_STORE_STATUS_CH1_STORE_BLOCK_X 0x0000FFFF
+#define BF_PXP_WFE_B_STORE_STATUS_CH1_STORE_BLOCK_X(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STORE_STATUS_CH1_STORE_BLOCK_X)
+
+#define HW_PXP_WFE_B_STORE_SIZE_CH0 (0x00001380)
+
+#define BP_PXP_WFE_B_STORE_SIZE_CH0_OUT_HEIGHT 16
+#define BM_PXP_WFE_B_STORE_SIZE_CH0_OUT_HEIGHT 0xFFFF0000
+#define BF_PXP_WFE_B_STORE_SIZE_CH0_OUT_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STORE_SIZE_CH0_OUT_HEIGHT)
+#define BP_PXP_WFE_B_STORE_SIZE_CH0_OUT_WIDTH 0
+#define BM_PXP_WFE_B_STORE_SIZE_CH0_OUT_WIDTH 0x0000FFFF
+#define BF_PXP_WFE_B_STORE_SIZE_CH0_OUT_WIDTH(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STORE_SIZE_CH0_OUT_WIDTH)
+
+#define HW_PXP_WFE_B_STORE_SIZE_CH1 (0x00001390)
+
+#define BP_PXP_WFE_B_STORE_SIZE_CH1_OUT_HEIGHT 16
+#define BM_PXP_WFE_B_STORE_SIZE_CH1_OUT_HEIGHT 0xFFFF0000
+#define BF_PXP_WFE_B_STORE_SIZE_CH1_OUT_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STORE_SIZE_CH1_OUT_HEIGHT)
+#define BP_PXP_WFE_B_STORE_SIZE_CH1_OUT_WIDTH 0
+#define BM_PXP_WFE_B_STORE_SIZE_CH1_OUT_WIDTH 0x0000FFFF
+#define BF_PXP_WFE_B_STORE_SIZE_CH1_OUT_WIDTH(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STORE_SIZE_CH1_OUT_WIDTH)
+
+#define HW_PXP_WFE_B_STORE_PITCH (0x000013a0)
+
+#define BP_PXP_WFE_B_STORE_PITCH_CH1_OUT_PITCH 16
+#define BM_PXP_WFE_B_STORE_PITCH_CH1_OUT_PITCH 0xFFFF0000
+#define BF_PXP_WFE_B_STORE_PITCH_CH1_OUT_PITCH(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STORE_PITCH_CH1_OUT_PITCH)
+#define BP_PXP_WFE_B_STORE_PITCH_CH0_OUT_PITCH 0
+#define BM_PXP_WFE_B_STORE_PITCH_CH0_OUT_PITCH 0x0000FFFF
+#define BF_PXP_WFE_B_STORE_PITCH_CH0_OUT_PITCH(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STORE_PITCH_CH0_OUT_PITCH)
+
+#define HW_PXP_WFE_B_STORE_SHIFT_CTRL_CH0 (0x000013b0)
+#define HW_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_SET (0x000013b4)
+#define HW_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_CLR (0x000013b8)
+#define HW_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_TOG (0x000013bc)
+
+#define BP_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_RSVD0 8
+#define BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_RSVD0 0xFFFFFF00
+#define BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_RSVD0(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_RSVD0)
+#define BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS 0x00000080
+#define BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS)
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS__0 0x0
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_SHIFT_BYPASS__1 0x1
+#define BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_RSVD1 0x00000040
+#define BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_RSVD1(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_RSVD1)
+#define BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN 0x00000020
+#define BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN)
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_2P_EN__1 0x1
+#define BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN 0x00000010
+#define BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN)
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUT_YUV422_1P_EN__1 0x1
+#define BP_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP 2
+#define BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP 0x0000000C
+#define BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP)
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP__0 0x0
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP__1 0x1
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP__2 0x2
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_OUTPUT_ACTIVE_BPP__3 0x3
+#define BP_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_RSVD2 0
+#define BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_RSVD2 0x00000003
+#define BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_RSVD2(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH0_RSVD2)
+
+#define HW_PXP_WFE_B_STORE_SHIFT_CTRL_CH1 (0x000013c0)
+#define HW_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_SET (0x000013c4)
+#define HW_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_CLR (0x000013c8)
+#define HW_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_TOG (0x000013cc)
+
+#define BP_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_RSVD0 6
+#define BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_RSVD0 0xFFFFFFC0
+#define BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_RSVD0(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_RSVD0)
+#define BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN 0x00000020
+#define BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN)
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUT_YUV422_2P_EN__1 0x1
+#define BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN 0x00000010
+#define BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN)
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN__0 0x0
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUT_YUV422_1P_EN__1 0x1
+#define BP_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP 2
+#define BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP 0x0000000C
+#define BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP)
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP__0 0x0
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP__1 0x1
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP__2 0x2
+#define BV_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_OUTPUT_ACTIVE_BPP__3 0x3
+#define BP_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_RSVD2 0
+#define BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_RSVD2 0x00000003
+#define BF_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_RSVD2(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STORE_SHIFT_CTRL_CH1_RSVD2)
+
+#define HW_PXP_WFE_B_STORE_ADDR_0_CH0 (0x00001410)
+
+#define BP_PXP_WFE_B_STORE_ADDR_0_CH0_OUT_BASE_ADDR0 0
+#define BM_PXP_WFE_B_STORE_ADDR_0_CH0_OUT_BASE_ADDR0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_ADDR_0_CH0_OUT_BASE_ADDR0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_ADDR_1_CH0 (0x00001420)
+
+#define BP_PXP_WFE_B_STORE_ADDR_1_CH0_OUT_BASE_ADDR1 0
+#define BM_PXP_WFE_B_STORE_ADDR_1_CH0_OUT_BASE_ADDR1 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_ADDR_1_CH0_OUT_BASE_ADDR1(v) (v)
+
+#define HW_PXP_WFE_B_STORE_FILL_DATA_CH0 (0x00001430)
+
+#define BP_PXP_WFE_B_STORE_FILL_DATA_CH0_FILL_DATA_CH0 0
+#define BM_PXP_WFE_B_STORE_FILL_DATA_CH0_FILL_DATA_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_FILL_DATA_CH0_FILL_DATA_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_ADDR_0_CH1 (0x00001440)
+
+#define BP_PXP_WFE_B_STORE_ADDR_0_CH1_OUT_BASE_ADDR0 0
+#define BM_PXP_WFE_B_STORE_ADDR_0_CH1_OUT_BASE_ADDR0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_ADDR_0_CH1_OUT_BASE_ADDR0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_ADDR_1_CH1 (0x00001450)
+
+#define BP_PXP_WFE_B_STORE_ADDR_1_CH1_OUT_BASE_ADDR1 0
+#define BM_PXP_WFE_B_STORE_ADDR_1_CH1_OUT_BASE_ADDR1 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_ADDR_1_CH1_OUT_BASE_ADDR1(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_MASK0_H_CH0 (0x00001460)
+
+#define BP_PXP_WFE_B_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0 0
+#define BM_PXP_WFE_B_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_D_MASK0_H_CH0_D_MASK0_H_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_MASK0_L_CH0 (0x00001470)
+
+#define BP_PXP_WFE_B_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0 0
+#define BM_PXP_WFE_B_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_D_MASK0_L_CH0_D_MASK0_L_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_MASK1_H_CH0 (0x00001480)
+
+#define BP_PXP_WFE_B_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0 0
+#define BM_PXP_WFE_B_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_D_MASK1_H_CH0_D_MASK1_H_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_MASK1_L_CH0 (0x00001490)
+
+#define BP_PXP_WFE_B_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0 0
+#define BM_PXP_WFE_B_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_D_MASK1_L_CH0_D_MASK1_L_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_MASK2_H_CH0 (0x000014a0)
+
+#define BP_PXP_WFE_B_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0 0
+#define BM_PXP_WFE_B_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_D_MASK2_H_CH0_D_MASK2_H_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_MASK2_L_CH0 (0x000014b0)
+
+#define BP_PXP_WFE_B_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0 0
+#define BM_PXP_WFE_B_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_D_MASK2_L_CH0_D_MASK2_L_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_MASK3_H_CH0 (0x000014c0)
+
+#define BP_PXP_WFE_B_STORE_D_MASK3_H_CH0_D_MASK3_H_CH0 0
+#define BM_PXP_WFE_B_STORE_D_MASK3_H_CH0_D_MASK3_H_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_D_MASK3_H_CH0_D_MASK3_H_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_MASK3_L_CH0 (0x000014d0)
+
+#define BP_PXP_WFE_B_STORE_D_MASK3_L_CH0_D_MASK3_L_CH0 0
+#define BM_PXP_WFE_B_STORE_D_MASK3_L_CH0_D_MASK3_L_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_D_MASK3_L_CH0_D_MASK3_L_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_MASK4_H_CH0 (0x000014e0)
+
+#define BP_PXP_WFE_B_STORE_D_MASK4_H_CH0_D_MASK4_H_CH0 0
+#define BM_PXP_WFE_B_STORE_D_MASK4_H_CH0_D_MASK4_H_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_D_MASK4_H_CH0_D_MASK4_H_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_MASK4_L_CH0 (0x000014f0)
+
+#define BP_PXP_WFE_B_STORE_D_MASK4_L_CH0_D_MASK4_L_CH0 0
+#define BM_PXP_WFE_B_STORE_D_MASK4_L_CH0_D_MASK4_L_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_D_MASK4_L_CH0_D_MASK4_L_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_MASK5_H_CH0 (0x00001500)
+
+#define BP_PXP_WFE_B_STORE_D_MASK5_H_CH0_D_MASK5_H_CH0 0
+#define BM_PXP_WFE_B_STORE_D_MASK5_H_CH0_D_MASK5_H_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_D_MASK5_H_CH0_D_MASK5_H_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_MASK5_L_CH0 (0x00001510)
+
+#define BP_PXP_WFE_B_STORE_D_MASK5_L_CH0_D_MASK5_L_CH0 0
+#define BM_PXP_WFE_B_STORE_D_MASK5_L_CH0_D_MASK5_L_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_D_MASK5_L_CH0_D_MASK5_L_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_MASK6_H_CH0 (0x00001520)
+
+#define BP_PXP_WFE_B_STORE_D_MASK6_H_CH0_D_MASK6_H_CH0 0
+#define BM_PXP_WFE_B_STORE_D_MASK6_H_CH0_D_MASK6_H_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_D_MASK6_H_CH0_D_MASK6_H_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_MASK6_L_CH0 (0x00001530)
+
+#define BP_PXP_WFE_B_STORE_D_MASK6_L_CH0_D_MASK6_L_CH0 0
+#define BM_PXP_WFE_B_STORE_D_MASK6_L_CH0_D_MASK6_L_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_D_MASK6_L_CH0_D_MASK6_L_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_MASK7_H_CH0 (0x00001540)
+
+#define BP_PXP_WFE_B_STORE_D_MASK7_H_CH0_D_MASK7_H_CH0 0
+#define BM_PXP_WFE_B_STORE_D_MASK7_H_CH0_D_MASK7_H_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_D_MASK7_H_CH0_D_MASK7_H_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_MASK7_L_CH0 (0x00001550)
+
+#define BP_PXP_WFE_B_STORE_D_MASK7_L_CH0_D_MASK7_L_CH0 0
+#define BM_PXP_WFE_B_STORE_D_MASK7_L_CH0_D_MASK7_L_CH0 0xFFFFFFFF
+#define BF_PXP_WFE_B_STORE_D_MASK7_L_CH0_D_MASK7_L_CH0(v) (v)
+
+#define HW_PXP_WFE_B_STORE_D_SHIFT_L_CH0 (0x00001560)
+
+#define BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3 0x80000000
+#define BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG3)
+#define BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_RSVD0 0x40000000
+#define BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_RSVD0)
+#define BP_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3 24
+#define BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3 0x3F000000
+#define BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH3)
+#define BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2 0x00800000
+#define BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG2)
+#define BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_RSVD1 0x00400000
+#define BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_RSVD1)
+#define BP_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2 16
+#define BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2 0x003F0000
+#define BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH2)
+#define BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1 0x00008000
+#define BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG1)
+#define BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_RSVD2 0x00004000
+#define BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_RSVD2)
+#define BP_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1 8
+#define BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1 0x00003F00
+#define BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH1)
+#define BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0 0x00000080
+#define BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_FLAG0)
+#define BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_RSVD3 0x00000040
+#define BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_RSVD3)
+#define BP_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0 0
+#define BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0 0x0000003F
+#define BF_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STORE_D_SHIFT_L_CH0_D_SHIFT_WIDTH0)
+
+#define HW_PXP_WFE_B_STORE_D_SHIFT_H_CH0 (0x00001570)
+
+#define BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG7 0x80000000
+#define BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG7(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG7)
+#define BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_RSVD0 0x40000000
+#define BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_RSVD0)
+#define BP_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7 24
+#define BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7 0x3F000000
+#define BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH7)
+#define BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG6 0x00800000
+#define BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG6(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG6)
+#define BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_RSVD1 0x00400000
+#define BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_RSVD1)
+#define BP_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6 16
+#define BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6 0x003F0000
+#define BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH6)
+#define BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG5 0x00008000
+#define BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG5(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG5)
+#define BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_RSVD2 0x00004000
+#define BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_RSVD2)
+#define BP_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5 8
+#define BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5 0x00003F00
+#define BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH5)
+#define BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG4 0x00000080
+#define BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG4(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_FLAG4)
+#define BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_RSVD3 0x00000040
+#define BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_RSVD3)
+#define BP_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4 0
+#define BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4 0x0000003F
+#define BF_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STORE_D_SHIFT_H_CH0_D_SHIFT_WIDTH4)
+
+#define HW_PXP_WFE_B_STORE_F_SHIFT_L_CH0 (0x00001580)
+
+#define BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_RSVD0 0x80000000
+#define BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_RSVD0(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_RSVD0)
+#define BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3 0x40000000
+#define BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG3)
+#define BP_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3 24
+#define BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3 0x3F000000
+#define BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH3)
+#define BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_RSVD1 0x00800000
+#define BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_RSVD1(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_RSVD1)
+#define BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2 0x00400000
+#define BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG2)
+#define BP_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2 16
+#define BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2 0x003F0000
+#define BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH2)
+#define BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_RSVD2 0x00008000
+#define BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_RSVD2(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_RSVD2)
+#define BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1 0x00004000
+#define BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG1)
+#define BP_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1 8
+#define BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1 0x00003F00
+#define BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH1)
+#define BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_RSVD3 0x00000080
+#define BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_RSVD3(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_RSVD3)
+#define BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0 0x00000040
+#define BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_FLAG0)
+#define BP_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0 0
+#define BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0 0x0000003F
+#define BF_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STORE_F_SHIFT_L_CH0_F_SHIFT_WIDTH0)
+
+#define HW_PXP_WFE_B_STORE_F_SHIFT_H_CH0 (0x00001590)
+
+#define BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_RSVD0 0x80000000
+#define BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_RSVD0(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_RSVD0)
+#define BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG7 0x40000000
+#define BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG7(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG7)
+#define BP_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7 24
+#define BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7 0x3F000000
+#define BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH7)
+#define BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_RSVD1 0x00800000
+#define BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_RSVD1(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_RSVD1)
+#define BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG6 0x00400000
+#define BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG6(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG6)
+#define BP_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6 16
+#define BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6 0x003F0000
+#define BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH6)
+#define BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_RSVD2 0x00008000
+#define BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_RSVD2(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_RSVD2)
+#define BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG5 0x00004000
+#define BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG5(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG5)
+#define BP_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5 8
+#define BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5 0x00003F00
+#define BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH5)
+#define BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_RSVD3 0x00000080
+#define BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_RSVD3(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_RSVD3)
+#define BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG4 0x00000040
+#define BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG4(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_FLAG4)
+#define BP_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4 0
+#define BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4 0x0000003F
+#define BF_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STORE_F_SHIFT_H_CH0_F_SHIFT_WIDTH4)
+
+#define HW_PXP_WFE_B_STORE_F_MASK_L_CH0 (0x000015a0)
+
+#define BP_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK3 24
+#define BM_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK3 0xFF000000
+#define BF_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK3)
+#define BP_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK2 16
+#define BM_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK2 0x00FF0000
+#define BF_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK2)
+#define BP_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK1 8
+#define BM_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK1 0x0000FF00
+#define BF_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK1)
+#define BP_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK0 0
+#define BM_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK0 0x000000FF
+#define BF_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STORE_F_MASK_L_CH0_F_MASK0)
+
+#define HW_PXP_WFE_B_STORE_F_MASK_H_CH0 (0x000015b0)
+
+#define BP_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK7 24
+#define BM_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK7 0xFF000000
+#define BF_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK7(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK7)
+#define BP_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK6 16
+#define BM_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK6 0x00FF0000
+#define BF_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK6(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK6)
+#define BP_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK5 8
+#define BM_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK5 0x0000FF00
+#define BF_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK5(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK5)
+#define BP_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK4 0
+#define BM_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK4 0x000000FF
+#define BF_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK4(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STORE_F_MASK_H_CH0_F_MASK4)
+
+#define HW_PXP_FETCH_WFE_A_DEBUG (0x000015c0)
+
+#define BP_PXP_FETCH_WFE_A_DEBUG_RSVD 29
+#define BM_PXP_FETCH_WFE_A_DEBUG_RSVD 0xE0000000
+#define BF_PXP_FETCH_WFE_A_DEBUG_RSVD(v) \
+ (((v) << 29) & BM_PXP_FETCH_WFE_A_DEBUG_RSVD)
+#define BM_PXP_FETCH_WFE_A_DEBUG_BUF_SEL 0x10000000
+#define BF_PXP_FETCH_WFE_A_DEBUG_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_FETCH_WFE_A_DEBUG_BUF_SEL)
+#define BV_PXP_FETCH_WFE_A_DEBUG_BUF_SEL__BF0 0x0
+#define BV_PXP_FETCH_WFE_A_DEBUG_BUF_SEL__BF1 0x1
+#define BP_PXP_FETCH_WFE_A_DEBUG_ITEM_SEL 24
+#define BM_PXP_FETCH_WFE_A_DEBUG_ITEM_SEL 0x0F000000
+#define BF_PXP_FETCH_WFE_A_DEBUG_ITEM_SEL(v) \
+ (((v) << 24) & BM_PXP_FETCH_WFE_A_DEBUG_ITEM_SEL)
+#define BP_PXP_FETCH_WFE_A_DEBUG_DEBUG_VALUE 0
+#define BM_PXP_FETCH_WFE_A_DEBUG_DEBUG_VALUE 0x00FFFFFF
+#define BF_PXP_FETCH_WFE_A_DEBUG_DEBUG_VALUE(v) \
+ (((v) << 0) & BM_PXP_FETCH_WFE_A_DEBUG_DEBUG_VALUE)
+
+#define HW_PXP_FETCH_WFE_B_DEBUG (0x000015d0)
+
+#define BP_PXP_FETCH_WFE_B_DEBUG_RSVD 29
+#define BM_PXP_FETCH_WFE_B_DEBUG_RSVD 0xE0000000
+#define BF_PXP_FETCH_WFE_B_DEBUG_RSVD(v) \
+ (((v) << 29) & BM_PXP_FETCH_WFE_B_DEBUG_RSVD)
+#define BM_PXP_FETCH_WFE_B_DEBUG_BUF_SEL 0x10000000
+#define BF_PXP_FETCH_WFE_B_DEBUG_BUF_SEL(v) \
+ (((v) << 28) & BM_PXP_FETCH_WFE_B_DEBUG_BUF_SEL)
+#define BV_PXP_FETCH_WFE_B_DEBUG_BUF_SEL__BF0 0x0
+#define BV_PXP_FETCH_WFE_B_DEBUG_BUF_SEL__BF1 0x1
+#define BP_PXP_FETCH_WFE_B_DEBUG_ITEM_SEL 24
+#define BM_PXP_FETCH_WFE_B_DEBUG_ITEM_SEL 0x0F000000
+#define BF_PXP_FETCH_WFE_B_DEBUG_ITEM_SEL(v) \
+ (((v) << 24) & BM_PXP_FETCH_WFE_B_DEBUG_ITEM_SEL)
+#define BP_PXP_FETCH_WFE_B_DEBUG_DEBUG_VALUE 0
+#define BM_PXP_FETCH_WFE_B_DEBUG_DEBUG_VALUE 0x00FFFFFF
+#define BF_PXP_FETCH_WFE_B_DEBUG_DEBUG_VALUE(v) \
+ (((v) << 0) & BM_PXP_FETCH_WFE_B_DEBUG_DEBUG_VALUE)
+
+#define HW_PXP_DITHER_CTRL (0x00001670)
+#define HW_PXP_DITHER_CTRL_SET (0x00001674)
+#define HW_PXP_DITHER_CTRL_CLR (0x00001678)
+#define HW_PXP_DITHER_CTRL_TOG (0x0000167c)
+
+#define BM_PXP_DITHER_CTRL_BUSY0 0x80000000
+#define BF_PXP_DITHER_CTRL_BUSY0(v) \
+ (((v) << 31) & BM_PXP_DITHER_CTRL_BUSY0)
+#define BM_PXP_DITHER_CTRL_BUSY1 0x40000000
+#define BF_PXP_DITHER_CTRL_BUSY1(v) \
+ (((v) << 30) & BM_PXP_DITHER_CTRL_BUSY1)
+#define BM_PXP_DITHER_CTRL_BUSY2 0x20000000
+#define BF_PXP_DITHER_CTRL_BUSY2(v) \
+ (((v) << 29) & BM_PXP_DITHER_CTRL_BUSY2)
+#define BP_PXP_DITHER_CTRL_RSVD0 25
+#define BM_PXP_DITHER_CTRL_RSVD0 0x1E000000
+#define BF_PXP_DITHER_CTRL_RSVD0(v) \
+ (((v) << 25) & BM_PXP_DITHER_CTRL_RSVD0)
+#define BM_PXP_DITHER_CTRL_ORDERED_ROUND_MODE 0x01000000
+#define BF_PXP_DITHER_CTRL_ORDERED_ROUND_MODE(v) \
+ (((v) << 24) & BM_PXP_DITHER_CTRL_ORDERED_ROUND_MODE)
+#define BV_PXP_DITHER_CTRL_ORDERED_ROUND_MODE__0 0x0
+#define BV_PXP_DITHER_CTRL_ORDERED_ROUND_MODE__1 0x1
+#define BM_PXP_DITHER_CTRL_FINAL_LUT_ENABLE 0x00800000
+#define BF_PXP_DITHER_CTRL_FINAL_LUT_ENABLE(v) \
+ (((v) << 23) & BM_PXP_DITHER_CTRL_FINAL_LUT_ENABLE)
+#define BV_PXP_DITHER_CTRL_FINAL_LUT_ENABLE__Disabled 0x0
+#define BV_PXP_DITHER_CTRL_FINAL_LUT_ENABLE__Enabled 0x1
+#define BP_PXP_DITHER_CTRL_IDX_MATRIX2_SIZE 21
+#define BM_PXP_DITHER_CTRL_IDX_MATRIX2_SIZE 0x00600000
+#define BF_PXP_DITHER_CTRL_IDX_MATRIX2_SIZE(v) \
+ (((v) << 21) & BM_PXP_DITHER_CTRL_IDX_MATRIX2_SIZE)
+#define BV_PXP_DITHER_CTRL_IDX_MATRIX2_SIZE__0 0x0
+#define BV_PXP_DITHER_CTRL_IDX_MATRIX2_SIZE__1 0x1
+#define BV_PXP_DITHER_CTRL_IDX_MATRIX2_SIZE__2 0x2
+#define BV_PXP_DITHER_CTRL_IDX_MATRIX2_SIZE__3 0x3
+#define BP_PXP_DITHER_CTRL_IDX_MATRIX1_SIZE 19
+#define BM_PXP_DITHER_CTRL_IDX_MATRIX1_SIZE 0x00180000
+#define BF_PXP_DITHER_CTRL_IDX_MATRIX1_SIZE(v) \
+ (((v) << 19) & BM_PXP_DITHER_CTRL_IDX_MATRIX1_SIZE)
+#define BV_PXP_DITHER_CTRL_IDX_MATRIX1_SIZE__0 0x0
+#define BV_PXP_DITHER_CTRL_IDX_MATRIX1_SIZE__1 0x1
+#define BV_PXP_DITHER_CTRL_IDX_MATRIX1_SIZE__2 0x2
+#define BV_PXP_DITHER_CTRL_IDX_MATRIX1_SIZE__3 0x3
+#define BP_PXP_DITHER_CTRL_IDX_MATRIX0_SIZE 17
+#define BM_PXP_DITHER_CTRL_IDX_MATRIX0_SIZE 0x00060000
+#define BF_PXP_DITHER_CTRL_IDX_MATRIX0_SIZE(v) \
+ (((v) << 17) & BM_PXP_DITHER_CTRL_IDX_MATRIX0_SIZE)
+#define BV_PXP_DITHER_CTRL_IDX_MATRIX0_SIZE__0 0x0
+#define BV_PXP_DITHER_CTRL_IDX_MATRIX0_SIZE__1 0x1
+#define BV_PXP_DITHER_CTRL_IDX_MATRIX0_SIZE__2 0x2
+#define BV_PXP_DITHER_CTRL_IDX_MATRIX0_SIZE__3 0x3
+#define BP_PXP_DITHER_CTRL_LUT_MODE 15
+#define BM_PXP_DITHER_CTRL_LUT_MODE 0x00018000
+#define BF_PXP_DITHER_CTRL_LUT_MODE(v) \
+ (((v) << 15) & BM_PXP_DITHER_CTRL_LUT_MODE)
+#define BV_PXP_DITHER_CTRL_LUT_MODE__0 0x0
+#define BV_PXP_DITHER_CTRL_LUT_MODE__1 0x1
+#define BV_PXP_DITHER_CTRL_LUT_MODE__2 0x2
+#define BV_PXP_DITHER_CTRL_LUT_MODE__3 0x3
+#define BP_PXP_DITHER_CTRL_NUM_QUANT_BIT 12
+#define BM_PXP_DITHER_CTRL_NUM_QUANT_BIT 0x00007000
+#define BF_PXP_DITHER_CTRL_NUM_QUANT_BIT(v) \
+ (((v) << 12) & BM_PXP_DITHER_CTRL_NUM_QUANT_BIT)
+#define BV_PXP_DITHER_CTRL_NUM_QUANT_BIT__0 0x0
+#define BV_PXP_DITHER_CTRL_NUM_QUANT_BIT__1 0x1
+#define BV_PXP_DITHER_CTRL_NUM_QUANT_BIT__2 0x2
+#define BV_PXP_DITHER_CTRL_NUM_QUANT_BIT__3 0x3
+#define BV_PXP_DITHER_CTRL_NUM_QUANT_BIT__4 0x4
+#define BV_PXP_DITHER_CTRL_NUM_QUANT_BIT__5 0x5
+#define BV_PXP_DITHER_CTRL_NUM_QUANT_BIT__6 0x6
+#define BV_PXP_DITHER_CTRL_NUM_QUANT_BIT__7 0x7
+#define BP_PXP_DITHER_CTRL_DITHER_MODE2 9
+#define BM_PXP_DITHER_CTRL_DITHER_MODE2 0x00000E00
+#define BF_PXP_DITHER_CTRL_DITHER_MODE2(v) \
+ (((v) << 9) & BM_PXP_DITHER_CTRL_DITHER_MODE2)
+#define BV_PXP_DITHER_CTRL_DITHER_MODE2__0 0x0
+#define BV_PXP_DITHER_CTRL_DITHER_MODE2__1 0x1
+#define BV_PXP_DITHER_CTRL_DITHER_MODE2__2 0x2
+#define BV_PXP_DITHER_CTRL_DITHER_MODE2__3 0x3
+#define BV_PXP_DITHER_CTRL_DITHER_MODE2__4 0x4
+#define BV_PXP_DITHER_CTRL_DITHER_MODE2__5 0x5
+#define BV_PXP_DITHER_CTRL_DITHER_MODE2__6 0x6
+#define BV_PXP_DITHER_CTRL_DITHER_MODE2__7 0x7
+#define BP_PXP_DITHER_CTRL_DITHER_MODE1 6
+#define BM_PXP_DITHER_CTRL_DITHER_MODE1 0x000001C0
+#define BF_PXP_DITHER_CTRL_DITHER_MODE1(v) \
+ (((v) << 6) & BM_PXP_DITHER_CTRL_DITHER_MODE1)
+#define BV_PXP_DITHER_CTRL_DITHER_MODE1__0 0x0
+#define BV_PXP_DITHER_CTRL_DITHER_MODE1__1 0x1
+#define BV_PXP_DITHER_CTRL_DITHER_MODE1__2 0x2
+#define BV_PXP_DITHER_CTRL_DITHER_MODE1__3 0x3
+#define BV_PXP_DITHER_CTRL_DITHER_MODE1__4 0x4
+#define BV_PXP_DITHER_CTRL_DITHER_MODE1__5 0x5
+#define BV_PXP_DITHER_CTRL_DITHER_MODE1__6 0x6
+#define BV_PXP_DITHER_CTRL_DITHER_MODE1__7 0x7
+#define BP_PXP_DITHER_CTRL_DITHER_MODE0 3
+#define BM_PXP_DITHER_CTRL_DITHER_MODE0 0x00000038
+#define BF_PXP_DITHER_CTRL_DITHER_MODE0(v) \
+ (((v) << 3) & BM_PXP_DITHER_CTRL_DITHER_MODE0)
+#define BV_PXP_DITHER_CTRL_DITHER_MODE0__0 0x0
+#define BV_PXP_DITHER_CTRL_DITHER_MODE0__1 0x1
+#define BV_PXP_DITHER_CTRL_DITHER_MODE0__2 0x2
+#define BV_PXP_DITHER_CTRL_DITHER_MODE0__3 0x3
+#define BV_PXP_DITHER_CTRL_DITHER_MODE0__4 0x4
+#define BV_PXP_DITHER_CTRL_DITHER_MODE0__5 0x5
+#define BV_PXP_DITHER_CTRL_DITHER_MODE0__6 0x6
+#define BV_PXP_DITHER_CTRL_DITHER_MODE0__7 0x7
+#define BM_PXP_DITHER_CTRL_ENABLE2 0x00000004
+#define BF_PXP_DITHER_CTRL_ENABLE2(v) \
+ (((v) << 2) & BM_PXP_DITHER_CTRL_ENABLE2)
+#define BV_PXP_DITHER_CTRL_ENABLE2__Disabled 0x0
+#define BV_PXP_DITHER_CTRL_ENABLE2__Enabled 0x1
+#define BM_PXP_DITHER_CTRL_ENABLE1 0x00000002
+#define BF_PXP_DITHER_CTRL_ENABLE1(v) \
+ (((v) << 1) & BM_PXP_DITHER_CTRL_ENABLE1)
+#define BV_PXP_DITHER_CTRL_ENABLE1__Disabled 0x0
+#define BV_PXP_DITHER_CTRL_ENABLE1__Enabled 0x1
+#define BM_PXP_DITHER_CTRL_ENABLE0 0x00000001
+#define BF_PXP_DITHER_CTRL_ENABLE0(v) \
+ (((v) << 0) & BM_PXP_DITHER_CTRL_ENABLE0)
+#define BV_PXP_DITHER_CTRL_ENABLE0__Disabled 0x0
+#define BV_PXP_DITHER_CTRL_ENABLE0__Enabled 0x1
+
+#define HW_PXP_DITHER_FINAL_LUT_DATA0 (0x00001680)
+#define HW_PXP_DITHER_FINAL_LUT_DATA0_SET (0x00001684)
+#define HW_PXP_DITHER_FINAL_LUT_DATA0_CLR (0x00001688)
+#define HW_PXP_DITHER_FINAL_LUT_DATA0_TOG (0x0000168c)
+
+#define BP_PXP_DITHER_FINAL_LUT_DATA0_DATA3 24
+#define BM_PXP_DITHER_FINAL_LUT_DATA0_DATA3 0xFF000000
+#define BF_PXP_DITHER_FINAL_LUT_DATA0_DATA3(v) \
+ (((v) << 24) & BM_PXP_DITHER_FINAL_LUT_DATA0_DATA3)
+#define BP_PXP_DITHER_FINAL_LUT_DATA0_DATA2 16
+#define BM_PXP_DITHER_FINAL_LUT_DATA0_DATA2 0x00FF0000
+#define BF_PXP_DITHER_FINAL_LUT_DATA0_DATA2(v) \
+ (((v) << 16) & BM_PXP_DITHER_FINAL_LUT_DATA0_DATA2)
+#define BP_PXP_DITHER_FINAL_LUT_DATA0_DATA1 8
+#define BM_PXP_DITHER_FINAL_LUT_DATA0_DATA1 0x0000FF00
+#define BF_PXP_DITHER_FINAL_LUT_DATA0_DATA1(v) \
+ (((v) << 8) & BM_PXP_DITHER_FINAL_LUT_DATA0_DATA1)
+#define BP_PXP_DITHER_FINAL_LUT_DATA0_DATA0 0
+#define BM_PXP_DITHER_FINAL_LUT_DATA0_DATA0 0x000000FF
+#define BF_PXP_DITHER_FINAL_LUT_DATA0_DATA0(v) \
+ (((v) << 0) & BM_PXP_DITHER_FINAL_LUT_DATA0_DATA0)
+
+#define HW_PXP_DITHER_FINAL_LUT_DATA1 (0x00001690)
+#define HW_PXP_DITHER_FINAL_LUT_DATA1_SET (0x00001694)
+#define HW_PXP_DITHER_FINAL_LUT_DATA1_CLR (0x00001698)
+#define HW_PXP_DITHER_FINAL_LUT_DATA1_TOG (0x0000169c)
+
+#define BP_PXP_DITHER_FINAL_LUT_DATA1_DATA7 24
+#define BM_PXP_DITHER_FINAL_LUT_DATA1_DATA7 0xFF000000
+#define BF_PXP_DITHER_FINAL_LUT_DATA1_DATA7(v) \
+ (((v) << 24) & BM_PXP_DITHER_FINAL_LUT_DATA1_DATA7)
+#define BP_PXP_DITHER_FINAL_LUT_DATA1_DATA6 16
+#define BM_PXP_DITHER_FINAL_LUT_DATA1_DATA6 0x00FF0000
+#define BF_PXP_DITHER_FINAL_LUT_DATA1_DATA6(v) \
+ (((v) << 16) & BM_PXP_DITHER_FINAL_LUT_DATA1_DATA6)
+#define BP_PXP_DITHER_FINAL_LUT_DATA1_DATA5 8
+#define BM_PXP_DITHER_FINAL_LUT_DATA1_DATA5 0x0000FF00
+#define BF_PXP_DITHER_FINAL_LUT_DATA1_DATA5(v) \
+ (((v) << 8) & BM_PXP_DITHER_FINAL_LUT_DATA1_DATA5)
+#define BP_PXP_DITHER_FINAL_LUT_DATA1_DATA4 0
+#define BM_PXP_DITHER_FINAL_LUT_DATA1_DATA4 0x000000FF
+#define BF_PXP_DITHER_FINAL_LUT_DATA1_DATA4(v) \
+ (((v) << 0) & BM_PXP_DITHER_FINAL_LUT_DATA1_DATA4)
+
+#define HW_PXP_DITHER_FINAL_LUT_DATA2 (0x000016a0)
+#define HW_PXP_DITHER_FINAL_LUT_DATA2_SET (0x000016a4)
+#define HW_PXP_DITHER_FINAL_LUT_DATA2_CLR (0x000016a8)
+#define HW_PXP_DITHER_FINAL_LUT_DATA2_TOG (0x000016ac)
+
+#define BP_PXP_DITHER_FINAL_LUT_DATA2_DATA11 24
+#define BM_PXP_DITHER_FINAL_LUT_DATA2_DATA11 0xFF000000
+#define BF_PXP_DITHER_FINAL_LUT_DATA2_DATA11(v) \
+ (((v) << 24) & BM_PXP_DITHER_FINAL_LUT_DATA2_DATA11)
+#define BP_PXP_DITHER_FINAL_LUT_DATA2_DATA10 16
+#define BM_PXP_DITHER_FINAL_LUT_DATA2_DATA10 0x00FF0000
+#define BF_PXP_DITHER_FINAL_LUT_DATA2_DATA10(v) \
+ (((v) << 16) & BM_PXP_DITHER_FINAL_LUT_DATA2_DATA10)
+#define BP_PXP_DITHER_FINAL_LUT_DATA2_DATA9 8
+#define BM_PXP_DITHER_FINAL_LUT_DATA2_DATA9 0x0000FF00
+#define BF_PXP_DITHER_FINAL_LUT_DATA2_DATA9(v) \
+ (((v) << 8) & BM_PXP_DITHER_FINAL_LUT_DATA2_DATA9)
+#define BP_PXP_DITHER_FINAL_LUT_DATA2_DATA8 0
+#define BM_PXP_DITHER_FINAL_LUT_DATA2_DATA8 0x000000FF
+#define BF_PXP_DITHER_FINAL_LUT_DATA2_DATA8(v) \
+ (((v) << 0) & BM_PXP_DITHER_FINAL_LUT_DATA2_DATA8)
+
+#define HW_PXP_DITHER_FINAL_LUT_DATA3 (0x000016b0)
+#define HW_PXP_DITHER_FINAL_LUT_DATA3_SET (0x000016b4)
+#define HW_PXP_DITHER_FINAL_LUT_DATA3_CLR (0x000016b8)
+#define HW_PXP_DITHER_FINAL_LUT_DATA3_TOG (0x000016bc)
+
+#define BP_PXP_DITHER_FINAL_LUT_DATA3_DATA15 24
+#define BM_PXP_DITHER_FINAL_LUT_DATA3_DATA15 0xFF000000
+#define BF_PXP_DITHER_FINAL_LUT_DATA3_DATA15(v) \
+ (((v) << 24) & BM_PXP_DITHER_FINAL_LUT_DATA3_DATA15)
+#define BP_PXP_DITHER_FINAL_LUT_DATA3_DATA14 16
+#define BM_PXP_DITHER_FINAL_LUT_DATA3_DATA14 0x00FF0000
+#define BF_PXP_DITHER_FINAL_LUT_DATA3_DATA14(v) \
+ (((v) << 16) & BM_PXP_DITHER_FINAL_LUT_DATA3_DATA14)
+#define BP_PXP_DITHER_FINAL_LUT_DATA3_DATA13 8
+#define BM_PXP_DITHER_FINAL_LUT_DATA3_DATA13 0x0000FF00
+#define BF_PXP_DITHER_FINAL_LUT_DATA3_DATA13(v) \
+ (((v) << 8) & BM_PXP_DITHER_FINAL_LUT_DATA3_DATA13)
+#define BP_PXP_DITHER_FINAL_LUT_DATA3_DATA12 0
+#define BM_PXP_DITHER_FINAL_LUT_DATA3_DATA12 0x000000FF
+#define BF_PXP_DITHER_FINAL_LUT_DATA3_DATA12(v) \
+ (((v) << 0) & BM_PXP_DITHER_FINAL_LUT_DATA3_DATA12)
+
+#define HW_PXP_WFE_A_CTRL (0x000016c0)
+#define HW_PXP_WFE_A_CTRL_SET (0x000016c4)
+#define HW_PXP_WFE_A_CTRL_CLR (0x000016c8)
+#define HW_PXP_WFE_A_CTRL_TOG (0x000016cc)
+
+#define BM_PXP_WFE_A_CTRL_DONE 0x80000000
+#define BF_PXP_WFE_A_CTRL_DONE(v) \
+ (((v) << 31) & BM_PXP_WFE_A_CTRL_DONE)
+#define BP_PXP_WFE_A_CTRL_RSVD0 3
+#define BM_PXP_WFE_A_CTRL_RSVD0 0x7FFFFFF8
+#define BF_PXP_WFE_A_CTRL_RSVD0(v) \
+ (((v) << 3) & BM_PXP_WFE_A_CTRL_RSVD0)
+#define BM_PXP_WFE_A_CTRL_SW_RESET 0x00000004
+#define BF_PXP_WFE_A_CTRL_SW_RESET(v) \
+ (((v) << 2) & BM_PXP_WFE_A_CTRL_SW_RESET)
+#define BM_PXP_WFE_A_CTRL_RSVD1 0x00000002
+#define BF_PXP_WFE_A_CTRL_RSVD1(v) \
+ (((v) << 1) & BM_PXP_WFE_A_CTRL_RSVD1)
+#define BM_PXP_WFE_A_CTRL_ENABLE 0x00000001
+#define BF_PXP_WFE_A_CTRL_ENABLE(v) \
+ (((v) << 0) & BM_PXP_WFE_A_CTRL_ENABLE)
+#define BV_PXP_WFE_A_CTRL_ENABLE__0 0x0
+#define BV_PXP_WFE_A_CTRL_ENABLE__1 0x1
+
+#define HW_PXP_WFE_A_DIMENSIONS (0x000016d0)
+
+#define BP_PXP_WFE_A_DIMENSIONS_RSVD0 28
+#define BM_PXP_WFE_A_DIMENSIONS_RSVD0 0xF0000000
+#define BF_PXP_WFE_A_DIMENSIONS_RSVD0(v) \
+ (((v) << 28) & BM_PXP_WFE_A_DIMENSIONS_RSVD0)
+#define BP_PXP_WFE_A_DIMENSIONS_HEIGHT 16
+#define BM_PXP_WFE_A_DIMENSIONS_HEIGHT 0x0FFF0000
+#define BF_PXP_WFE_A_DIMENSIONS_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_WFE_A_DIMENSIONS_HEIGHT)
+#define BP_PXP_WFE_A_DIMENSIONS_RSVD1 12
+#define BM_PXP_WFE_A_DIMENSIONS_RSVD1 0x0000F000
+#define BF_PXP_WFE_A_DIMENSIONS_RSVD1(v) \
+ (((v) << 12) & BM_PXP_WFE_A_DIMENSIONS_RSVD1)
+#define BP_PXP_WFE_A_DIMENSIONS_WIDTH 0
+#define BM_PXP_WFE_A_DIMENSIONS_WIDTH 0x00000FFF
+#define BF_PXP_WFE_A_DIMENSIONS_WIDTH(v) \
+ (((v) << 0) & BM_PXP_WFE_A_DIMENSIONS_WIDTH)
+
+#define HW_PXP_WFE_A_OFFSET (0x000016e0)
+
+#define BP_PXP_WFE_A_OFFSET_RSVD0 28
+#define BM_PXP_WFE_A_OFFSET_RSVD0 0xF0000000
+#define BF_PXP_WFE_A_OFFSET_RSVD0(v) \
+ (((v) << 28) & BM_PXP_WFE_A_OFFSET_RSVD0)
+#define BP_PXP_WFE_A_OFFSET_Y_OFFSET 16
+#define BM_PXP_WFE_A_OFFSET_Y_OFFSET 0x0FFF0000
+#define BF_PXP_WFE_A_OFFSET_Y_OFFSET(v) \
+ (((v) << 16) & BM_PXP_WFE_A_OFFSET_Y_OFFSET)
+#define BP_PXP_WFE_A_OFFSET_RSVD1 12
+#define BM_PXP_WFE_A_OFFSET_RSVD1 0x0000F000
+#define BF_PXP_WFE_A_OFFSET_RSVD1(v) \
+ (((v) << 12) & BM_PXP_WFE_A_OFFSET_RSVD1)
+#define BP_PXP_WFE_A_OFFSET_X_OFFSET 0
+#define BM_PXP_WFE_A_OFFSET_X_OFFSET 0x00000FFF
+#define BF_PXP_WFE_A_OFFSET_X_OFFSET(v) \
+ (((v) << 0) & BM_PXP_WFE_A_OFFSET_X_OFFSET)
+
+#define HW_PXP_WFE_A_SW_DATA_REGS (0x000016f0)
+
+#define BP_PXP_WFE_A_SW_DATA_REGS_VAL3 24
+#define BM_PXP_WFE_A_SW_DATA_REGS_VAL3 0xFF000000
+#define BF_PXP_WFE_A_SW_DATA_REGS_VAL3(v) \
+ (((v) << 24) & BM_PXP_WFE_A_SW_DATA_REGS_VAL3)
+#define BP_PXP_WFE_A_SW_DATA_REGS_VAL2 16
+#define BM_PXP_WFE_A_SW_DATA_REGS_VAL2 0x00FF0000
+#define BF_PXP_WFE_A_SW_DATA_REGS_VAL2(v) \
+ (((v) << 16) & BM_PXP_WFE_A_SW_DATA_REGS_VAL2)
+#define BP_PXP_WFE_A_SW_DATA_REGS_VAL1 8
+#define BM_PXP_WFE_A_SW_DATA_REGS_VAL1 0x0000FF00
+#define BF_PXP_WFE_A_SW_DATA_REGS_VAL1(v) \
+ (((v) << 8) & BM_PXP_WFE_A_SW_DATA_REGS_VAL1)
+#define BP_PXP_WFE_A_SW_DATA_REGS_VAL0 0
+#define BM_PXP_WFE_A_SW_DATA_REGS_VAL0 0x000000FF
+#define BF_PXP_WFE_A_SW_DATA_REGS_VAL0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_SW_DATA_REGS_VAL0)
+
+#define HW_PXP_WFE_A_SW_FLAG_REGS (0x00001700)
+
+#define BP_PXP_WFE_A_SW_FLAG_REGS_RSVD 4
+#define BM_PXP_WFE_A_SW_FLAG_REGS_RSVD 0xFFFFFFF0
+#define BF_PXP_WFE_A_SW_FLAG_REGS_RSVD(v) \
+ (((v) << 4) & BM_PXP_WFE_A_SW_FLAG_REGS_RSVD)
+#define BM_PXP_WFE_A_SW_FLAG_REGS_VAL3 0x00000008
+#define BF_PXP_WFE_A_SW_FLAG_REGS_VAL3(v) \
+ (((v) << 3) & BM_PXP_WFE_A_SW_FLAG_REGS_VAL3)
+#define BM_PXP_WFE_A_SW_FLAG_REGS_VAL2 0x00000004
+#define BF_PXP_WFE_A_SW_FLAG_REGS_VAL2(v) \
+ (((v) << 2) & BM_PXP_WFE_A_SW_FLAG_REGS_VAL2)
+#define BM_PXP_WFE_A_SW_FLAG_REGS_VAL1 0x00000002
+#define BF_PXP_WFE_A_SW_FLAG_REGS_VAL1(v) \
+ (((v) << 1) & BM_PXP_WFE_A_SW_FLAG_REGS_VAL1)
+#define BM_PXP_WFE_A_SW_FLAG_REGS_VAL0 0x00000001
+#define BF_PXP_WFE_A_SW_FLAG_REGS_VAL0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_SW_FLAG_REGS_VAL0)
+
+#define HW_PXP_WFE_A_STAGE1_MUX0 (0x00001710)
+#define HW_PXP_WFE_A_STAGE1_MUX0_SET (0x00001714)
+#define HW_PXP_WFE_A_STAGE1_MUX0_CLR (0x00001718)
+#define HW_PXP_WFE_A_STAGE1_MUX0_TOG (0x0000171c)
+
+#define BP_PXP_WFE_A_STAGE1_MUX0_RSVD0 30
+#define BM_PXP_WFE_A_STAGE1_MUX0_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE1_MUX0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE1_MUX0_RSVD0)
+#define BP_PXP_WFE_A_STAGE1_MUX0_MUX3 24
+#define BM_PXP_WFE_A_STAGE1_MUX0_MUX3 0x3F000000
+#define BF_PXP_WFE_A_STAGE1_MUX0_MUX3(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE1_MUX0_MUX3)
+#define BP_PXP_WFE_A_STAGE1_MUX0_RSVD1 22
+#define BM_PXP_WFE_A_STAGE1_MUX0_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE1_MUX0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE1_MUX0_RSVD1)
+#define BP_PXP_WFE_A_STAGE1_MUX0_MUX2 16
+#define BM_PXP_WFE_A_STAGE1_MUX0_MUX2 0x003F0000
+#define BF_PXP_WFE_A_STAGE1_MUX0_MUX2(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE1_MUX0_MUX2)
+#define BP_PXP_WFE_A_STAGE1_MUX0_RSVD2 14
+#define BM_PXP_WFE_A_STAGE1_MUX0_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE1_MUX0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE1_MUX0_RSVD2)
+#define BP_PXP_WFE_A_STAGE1_MUX0_MUX1 8
+#define BM_PXP_WFE_A_STAGE1_MUX0_MUX1 0x00003F00
+#define BF_PXP_WFE_A_STAGE1_MUX0_MUX1(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE1_MUX0_MUX1)
+#define BP_PXP_WFE_A_STAGE1_MUX0_RSVD3 6
+#define BM_PXP_WFE_A_STAGE1_MUX0_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE1_MUX0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE1_MUX0_RSVD3)
+#define BP_PXP_WFE_A_STAGE1_MUX0_MUX0 0
+#define BM_PXP_WFE_A_STAGE1_MUX0_MUX0 0x0000003F
+#define BF_PXP_WFE_A_STAGE1_MUX0_MUX0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE1_MUX0_MUX0)
+
+#define HW_PXP_WFE_A_STAGE1_MUX1 (0x00001720)
+#define HW_PXP_WFE_A_STAGE1_MUX1_SET (0x00001724)
+#define HW_PXP_WFE_A_STAGE1_MUX1_CLR (0x00001728)
+#define HW_PXP_WFE_A_STAGE1_MUX1_TOG (0x0000172c)
+
+#define BP_PXP_WFE_A_STAGE1_MUX1_RSVD0 30
+#define BM_PXP_WFE_A_STAGE1_MUX1_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE1_MUX1_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE1_MUX1_RSVD0)
+#define BP_PXP_WFE_A_STAGE1_MUX1_MUX7 24
+#define BM_PXP_WFE_A_STAGE1_MUX1_MUX7 0x3F000000
+#define BF_PXP_WFE_A_STAGE1_MUX1_MUX7(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE1_MUX1_MUX7)
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX7__INC 0x0
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX7__DEC 0x1
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX7__ADD 0x2
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX7__MINUS 0x3
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX7__AND 0x4
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX7__OR 0x5
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX7__XOR 0x6
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX7__SHIFTLEFT 0x7
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX7__SHIFTRIGHT 0x8
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX7__BIT_AND 0x9
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX7__BIT_OR 0xa
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX7__BIT_CMP 0xb
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX7__NOP 0xc
+#define BP_PXP_WFE_A_STAGE1_MUX1_RSVD1 22
+#define BM_PXP_WFE_A_STAGE1_MUX1_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE1_MUX1_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE1_MUX1_RSVD1)
+#define BP_PXP_WFE_A_STAGE1_MUX1_MUX6 16
+#define BM_PXP_WFE_A_STAGE1_MUX1_MUX6 0x003F0000
+#define BF_PXP_WFE_A_STAGE1_MUX1_MUX6(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE1_MUX1_MUX6)
+#define BP_PXP_WFE_A_STAGE1_MUX1_RSVD2 14
+#define BM_PXP_WFE_A_STAGE1_MUX1_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE1_MUX1_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE1_MUX1_RSVD2)
+#define BP_PXP_WFE_A_STAGE1_MUX1_MUX5 8
+#define BM_PXP_WFE_A_STAGE1_MUX1_MUX5 0x00003F00
+#define BF_PXP_WFE_A_STAGE1_MUX1_MUX5(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE1_MUX1_MUX5)
+#define BP_PXP_WFE_A_STAGE1_MUX1_RSVD3 6
+#define BM_PXP_WFE_A_STAGE1_MUX1_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE1_MUX1_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE1_MUX1_RSVD3)
+#define BP_PXP_WFE_A_STAGE1_MUX1_MUX4 0
+#define BM_PXP_WFE_A_STAGE1_MUX1_MUX4 0x0000003F
+#define BF_PXP_WFE_A_STAGE1_MUX1_MUX4(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE1_MUX1_MUX4)
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX4__INC 0x0
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX4__DEC 0x1
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX4__ADD 0x2
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX4__MINUS 0x3
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX4__AND 0x4
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX4__OR 0x5
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX4__XOR 0x6
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX4__SHIFTLEFT 0x7
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX4__SHIFTRIGHT 0x8
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX4__BIT_AND 0x9
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX4__BIT_OR 0xa
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX4__BIT_CMP 0xb
+#define BV_PXP_WFE_A_STAGE1_MUX1_MUX4__NOP 0xc
+
+#define HW_PXP_WFE_A_STAGE1_MUX2 (0x00001730)
+#define HW_PXP_WFE_A_STAGE1_MUX2_SET (0x00001734)
+#define HW_PXP_WFE_A_STAGE1_MUX2_CLR (0x00001738)
+#define HW_PXP_WFE_A_STAGE1_MUX2_TOG (0x0000173c)
+
+#define BP_PXP_WFE_A_STAGE1_MUX2_RSVD0 30
+#define BM_PXP_WFE_A_STAGE1_MUX2_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE1_MUX2_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE1_MUX2_RSVD0)
+#define BP_PXP_WFE_A_STAGE1_MUX2_MUX11 24
+#define BM_PXP_WFE_A_STAGE1_MUX2_MUX11 0x3F000000
+#define BF_PXP_WFE_A_STAGE1_MUX2_MUX11(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE1_MUX2_MUX11)
+#define BP_PXP_WFE_A_STAGE1_MUX2_RSVD1 22
+#define BM_PXP_WFE_A_STAGE1_MUX2_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE1_MUX2_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE1_MUX2_RSVD1)
+#define BP_PXP_WFE_A_STAGE1_MUX2_MUX10 16
+#define BM_PXP_WFE_A_STAGE1_MUX2_MUX10 0x003F0000
+#define BF_PXP_WFE_A_STAGE1_MUX2_MUX10(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE1_MUX2_MUX10)
+#define BP_PXP_WFE_A_STAGE1_MUX2_RSVD2 14
+#define BM_PXP_WFE_A_STAGE1_MUX2_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE1_MUX2_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE1_MUX2_RSVD2)
+#define BP_PXP_WFE_A_STAGE1_MUX2_MUX9 8
+#define BM_PXP_WFE_A_STAGE1_MUX2_MUX9 0x00003F00
+#define BF_PXP_WFE_A_STAGE1_MUX2_MUX9(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE1_MUX2_MUX9)
+#define BP_PXP_WFE_A_STAGE1_MUX2_RSVD3 6
+#define BM_PXP_WFE_A_STAGE1_MUX2_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE1_MUX2_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE1_MUX2_RSVD3)
+#define BP_PXP_WFE_A_STAGE1_MUX2_MUX8 0
+#define BM_PXP_WFE_A_STAGE1_MUX2_MUX8 0x0000003F
+#define BF_PXP_WFE_A_STAGE1_MUX2_MUX8(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE1_MUX2_MUX8)
+
+#define HW_PXP_WFE_A_STAGE1_MUX3 (0x00001740)
+#define HW_PXP_WFE_A_STAGE1_MUX3_SET (0x00001744)
+#define HW_PXP_WFE_A_STAGE1_MUX3_CLR (0x00001748)
+#define HW_PXP_WFE_A_STAGE1_MUX3_TOG (0x0000174c)
+
+#define BP_PXP_WFE_A_STAGE1_MUX3_RSVD0 30
+#define BM_PXP_WFE_A_STAGE1_MUX3_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE1_MUX3_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE1_MUX3_RSVD0)
+#define BP_PXP_WFE_A_STAGE1_MUX3_MUX15 24
+#define BM_PXP_WFE_A_STAGE1_MUX3_MUX15 0x3F000000
+#define BF_PXP_WFE_A_STAGE1_MUX3_MUX15(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE1_MUX3_MUX15)
+#define BP_PXP_WFE_A_STAGE1_MUX3_RSVD1 22
+#define BM_PXP_WFE_A_STAGE1_MUX3_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE1_MUX3_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE1_MUX3_RSVD1)
+#define BP_PXP_WFE_A_STAGE1_MUX3_MUX14 16
+#define BM_PXP_WFE_A_STAGE1_MUX3_MUX14 0x003F0000
+#define BF_PXP_WFE_A_STAGE1_MUX3_MUX14(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE1_MUX3_MUX14)
+#define BP_PXP_WFE_A_STAGE1_MUX3_RSVD2 14
+#define BM_PXP_WFE_A_STAGE1_MUX3_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE1_MUX3_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE1_MUX3_RSVD2)
+#define BP_PXP_WFE_A_STAGE1_MUX3_MUX13 8
+#define BM_PXP_WFE_A_STAGE1_MUX3_MUX13 0x00003F00
+#define BF_PXP_WFE_A_STAGE1_MUX3_MUX13(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE1_MUX3_MUX13)
+#define BP_PXP_WFE_A_STAGE1_MUX3_RSVD3 6
+#define BM_PXP_WFE_A_STAGE1_MUX3_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE1_MUX3_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE1_MUX3_RSVD3)
+#define BP_PXP_WFE_A_STAGE1_MUX3_MUX12 0
+#define BM_PXP_WFE_A_STAGE1_MUX3_MUX12 0x0000003F
+#define BF_PXP_WFE_A_STAGE1_MUX3_MUX12(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE1_MUX3_MUX12)
+
+#define HW_PXP_WFE_A_STAGE1_MUX4 (0x00001750)
+#define HW_PXP_WFE_A_STAGE1_MUX4_SET (0x00001754)
+#define HW_PXP_WFE_A_STAGE1_MUX4_CLR (0x00001758)
+#define HW_PXP_WFE_A_STAGE1_MUX4_TOG (0x0000175c)
+
+#define BP_PXP_WFE_A_STAGE1_MUX4_RSVD0 24
+#define BM_PXP_WFE_A_STAGE1_MUX4_RSVD0 0xFF000000
+#define BF_PXP_WFE_A_STAGE1_MUX4_RSVD0(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE1_MUX4_RSVD0)
+#define BP_PXP_WFE_A_STAGE1_MUX4_RSVD1 16
+#define BM_PXP_WFE_A_STAGE1_MUX4_RSVD1 0x00FF0000
+#define BF_PXP_WFE_A_STAGE1_MUX4_RSVD1(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE1_MUX4_RSVD1)
+#define BP_PXP_WFE_A_STAGE1_MUX4_RSVD2 14
+#define BM_PXP_WFE_A_STAGE1_MUX4_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE1_MUX4_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE1_MUX4_RSVD2)
+#define BP_PXP_WFE_A_STAGE1_MUX4_MUX17 8
+#define BM_PXP_WFE_A_STAGE1_MUX4_MUX17 0x00003F00
+#define BF_PXP_WFE_A_STAGE1_MUX4_MUX17(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE1_MUX4_MUX17)
+#define BP_PXP_WFE_A_STAGE1_MUX4_RSVD3 6
+#define BM_PXP_WFE_A_STAGE1_MUX4_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE1_MUX4_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE1_MUX4_RSVD3)
+#define BP_PXP_WFE_A_STAGE1_MUX4_MUX16 0
+#define BM_PXP_WFE_A_STAGE1_MUX4_MUX16 0x0000003F
+#define BF_PXP_WFE_A_STAGE1_MUX4_MUX16(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE1_MUX4_MUX16)
+
+#define HW_PXP_WFE_A_STAGE2_MUX0 (0x00001760)
+#define HW_PXP_WFE_A_STAGE2_MUX0_SET (0x00001764)
+#define HW_PXP_WFE_A_STAGE2_MUX0_CLR (0x00001768)
+#define HW_PXP_WFE_A_STAGE2_MUX0_TOG (0x0000176c)
+
+#define BP_PXP_WFE_A_STAGE2_MUX0_RSVD0 30
+#define BM_PXP_WFE_A_STAGE2_MUX0_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE2_MUX0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE2_MUX0_RSVD0)
+#define BP_PXP_WFE_A_STAGE2_MUX0_MUX3 24
+#define BM_PXP_WFE_A_STAGE2_MUX0_MUX3 0x3F000000
+#define BF_PXP_WFE_A_STAGE2_MUX0_MUX3(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE2_MUX0_MUX3)
+#define BP_PXP_WFE_A_STAGE2_MUX0_RSVD1 22
+#define BM_PXP_WFE_A_STAGE2_MUX0_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE2_MUX0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE2_MUX0_RSVD1)
+#define BP_PXP_WFE_A_STAGE2_MUX0_MUX2 16
+#define BM_PXP_WFE_A_STAGE2_MUX0_MUX2 0x003F0000
+#define BF_PXP_WFE_A_STAGE2_MUX0_MUX2(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE2_MUX0_MUX2)
+#define BP_PXP_WFE_A_STAGE2_MUX0_RSVD2 14
+#define BM_PXP_WFE_A_STAGE2_MUX0_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE2_MUX0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE2_MUX0_RSVD2)
+#define BP_PXP_WFE_A_STAGE2_MUX0_MUX1 8
+#define BM_PXP_WFE_A_STAGE2_MUX0_MUX1 0x00003F00
+#define BF_PXP_WFE_A_STAGE2_MUX0_MUX1(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE2_MUX0_MUX1)
+#define BP_PXP_WFE_A_STAGE2_MUX0_RSVD3 6
+#define BM_PXP_WFE_A_STAGE2_MUX0_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE2_MUX0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE2_MUX0_RSVD3)
+#define BP_PXP_WFE_A_STAGE2_MUX0_MUX0 0
+#define BM_PXP_WFE_A_STAGE2_MUX0_MUX0 0x0000003F
+#define BF_PXP_WFE_A_STAGE2_MUX0_MUX0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE2_MUX0_MUX0)
+
+#define HW_PXP_WFE_A_STAGE2_MUX1 (0x00001770)
+#define HW_PXP_WFE_A_STAGE2_MUX1_SET (0x00001774)
+#define HW_PXP_WFE_A_STAGE2_MUX1_CLR (0x00001778)
+#define HW_PXP_WFE_A_STAGE2_MUX1_TOG (0x0000177c)
+
+#define BP_PXP_WFE_A_STAGE2_MUX1_RSVD0 30
+#define BM_PXP_WFE_A_STAGE2_MUX1_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE2_MUX1_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE2_MUX1_RSVD0)
+#define BP_PXP_WFE_A_STAGE2_MUX1_MUX7 24
+#define BM_PXP_WFE_A_STAGE2_MUX1_MUX7 0x3F000000
+#define BF_PXP_WFE_A_STAGE2_MUX1_MUX7(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE2_MUX1_MUX7)
+#define BP_PXP_WFE_A_STAGE2_MUX1_RSVD1 22
+#define BM_PXP_WFE_A_STAGE2_MUX1_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE2_MUX1_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE2_MUX1_RSVD1)
+#define BP_PXP_WFE_A_STAGE2_MUX1_MUX6 16
+#define BM_PXP_WFE_A_STAGE2_MUX1_MUX6 0x003F0000
+#define BF_PXP_WFE_A_STAGE2_MUX1_MUX6(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE2_MUX1_MUX6)
+#define BP_PXP_WFE_A_STAGE2_MUX1_RSVD2 14
+#define BM_PXP_WFE_A_STAGE2_MUX1_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE2_MUX1_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE2_MUX1_RSVD2)
+#define BP_PXP_WFE_A_STAGE2_MUX1_MUX5 8
+#define BM_PXP_WFE_A_STAGE2_MUX1_MUX5 0x00003F00
+#define BF_PXP_WFE_A_STAGE2_MUX1_MUX5(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE2_MUX1_MUX5)
+#define BP_PXP_WFE_A_STAGE2_MUX1_RSVD3 6
+#define BM_PXP_WFE_A_STAGE2_MUX1_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE2_MUX1_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE2_MUX1_RSVD3)
+#define BP_PXP_WFE_A_STAGE2_MUX1_MUX4 0
+#define BM_PXP_WFE_A_STAGE2_MUX1_MUX4 0x0000003F
+#define BF_PXP_WFE_A_STAGE2_MUX1_MUX4(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE2_MUX1_MUX4)
+
+#define HW_PXP_WFE_A_STAGE2_MUX2 (0x00001780)
+#define HW_PXP_WFE_A_STAGE2_MUX2_SET (0x00001784)
+#define HW_PXP_WFE_A_STAGE2_MUX2_CLR (0x00001788)
+#define HW_PXP_WFE_A_STAGE2_MUX2_TOG (0x0000178c)
+
+#define BP_PXP_WFE_A_STAGE2_MUX2_RSVD0 30
+#define BM_PXP_WFE_A_STAGE2_MUX2_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE2_MUX2_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE2_MUX2_RSVD0)
+#define BP_PXP_WFE_A_STAGE2_MUX2_MUX11 24
+#define BM_PXP_WFE_A_STAGE2_MUX2_MUX11 0x3F000000
+#define BF_PXP_WFE_A_STAGE2_MUX2_MUX11(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE2_MUX2_MUX11)
+#define BP_PXP_WFE_A_STAGE2_MUX2_RSVD1 22
+#define BM_PXP_WFE_A_STAGE2_MUX2_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE2_MUX2_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE2_MUX2_RSVD1)
+#define BP_PXP_WFE_A_STAGE2_MUX2_MUX10 16
+#define BM_PXP_WFE_A_STAGE2_MUX2_MUX10 0x003F0000
+#define BF_PXP_WFE_A_STAGE2_MUX2_MUX10(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE2_MUX2_MUX10)
+#define BP_PXP_WFE_A_STAGE2_MUX2_RSVD2 14
+#define BM_PXP_WFE_A_STAGE2_MUX2_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE2_MUX2_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE2_MUX2_RSVD2)
+#define BP_PXP_WFE_A_STAGE2_MUX2_MUX9 8
+#define BM_PXP_WFE_A_STAGE2_MUX2_MUX9 0x00003F00
+#define BF_PXP_WFE_A_STAGE2_MUX2_MUX9(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE2_MUX2_MUX9)
+#define BP_PXP_WFE_A_STAGE2_MUX2_RSVD3 6
+#define BM_PXP_WFE_A_STAGE2_MUX2_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE2_MUX2_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE2_MUX2_RSVD3)
+#define BP_PXP_WFE_A_STAGE2_MUX2_MUX8 0
+#define BM_PXP_WFE_A_STAGE2_MUX2_MUX8 0x0000003F
+#define BF_PXP_WFE_A_STAGE2_MUX2_MUX8(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE2_MUX2_MUX8)
+
+#define HW_PXP_WFE_A_STAGE2_MUX3 (0x00001790)
+#define HW_PXP_WFE_A_STAGE2_MUX3_SET (0x00001794)
+#define HW_PXP_WFE_A_STAGE2_MUX3_CLR (0x00001798)
+#define HW_PXP_WFE_A_STAGE2_MUX3_TOG (0x0000179c)
+
+#define BP_PXP_WFE_A_STAGE2_MUX3_RSVD0 30
+#define BM_PXP_WFE_A_STAGE2_MUX3_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE2_MUX3_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE2_MUX3_RSVD0)
+#define BP_PXP_WFE_A_STAGE2_MUX3_MUX15 24
+#define BM_PXP_WFE_A_STAGE2_MUX3_MUX15 0x3F000000
+#define BF_PXP_WFE_A_STAGE2_MUX3_MUX15(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE2_MUX3_MUX15)
+#define BP_PXP_WFE_A_STAGE2_MUX3_RSVD1 22
+#define BM_PXP_WFE_A_STAGE2_MUX3_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE2_MUX3_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE2_MUX3_RSVD1)
+#define BP_PXP_WFE_A_STAGE2_MUX3_MUX14 16
+#define BM_PXP_WFE_A_STAGE2_MUX3_MUX14 0x003F0000
+#define BF_PXP_WFE_A_STAGE2_MUX3_MUX14(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE2_MUX3_MUX14)
+#define BP_PXP_WFE_A_STAGE2_MUX3_RSVD2 14
+#define BM_PXP_WFE_A_STAGE2_MUX3_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE2_MUX3_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE2_MUX3_RSVD2)
+#define BP_PXP_WFE_A_STAGE2_MUX3_MUX13 8
+#define BM_PXP_WFE_A_STAGE2_MUX3_MUX13 0x00003F00
+#define BF_PXP_WFE_A_STAGE2_MUX3_MUX13(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE2_MUX3_MUX13)
+#define BP_PXP_WFE_A_STAGE2_MUX3_RSVD3 6
+#define BM_PXP_WFE_A_STAGE2_MUX3_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE2_MUX3_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE2_MUX3_RSVD3)
+#define BP_PXP_WFE_A_STAGE2_MUX3_MUX12 0
+#define BM_PXP_WFE_A_STAGE2_MUX3_MUX12 0x0000003F
+#define BF_PXP_WFE_A_STAGE2_MUX3_MUX12(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE2_MUX3_MUX12)
+
+#define HW_PXP_WFE_A_STAGE2_MUX4 (0x000017a0)
+#define HW_PXP_WFE_A_STAGE2_MUX4_SET (0x000017a4)
+#define HW_PXP_WFE_A_STAGE2_MUX4_CLR (0x000017a8)
+#define HW_PXP_WFE_A_STAGE2_MUX4_TOG (0x000017ac)
+
+#define BP_PXP_WFE_A_STAGE2_MUX4_RSVD0 30
+#define BM_PXP_WFE_A_STAGE2_MUX4_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE2_MUX4_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE2_MUX4_RSVD0)
+#define BP_PXP_WFE_A_STAGE2_MUX4_MUX19 24
+#define BM_PXP_WFE_A_STAGE2_MUX4_MUX19 0x3F000000
+#define BF_PXP_WFE_A_STAGE2_MUX4_MUX19(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE2_MUX4_MUX19)
+#define BP_PXP_WFE_A_STAGE2_MUX4_RSVD1 22
+#define BM_PXP_WFE_A_STAGE2_MUX4_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE2_MUX4_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE2_MUX4_RSVD1)
+#define BP_PXP_WFE_A_STAGE2_MUX4_MUX18 16
+#define BM_PXP_WFE_A_STAGE2_MUX4_MUX18 0x003F0000
+#define BF_PXP_WFE_A_STAGE2_MUX4_MUX18(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE2_MUX4_MUX18)
+#define BP_PXP_WFE_A_STAGE2_MUX4_RSVD2 14
+#define BM_PXP_WFE_A_STAGE2_MUX4_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE2_MUX4_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE2_MUX4_RSVD2)
+#define BP_PXP_WFE_A_STAGE2_MUX4_MUX17 8
+#define BM_PXP_WFE_A_STAGE2_MUX4_MUX17 0x00003F00
+#define BF_PXP_WFE_A_STAGE2_MUX4_MUX17(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE2_MUX4_MUX17)
+#define BP_PXP_WFE_A_STAGE2_MUX4_RSVD3 6
+#define BM_PXP_WFE_A_STAGE2_MUX4_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE2_MUX4_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE2_MUX4_RSVD3)
+#define BP_PXP_WFE_A_STAGE2_MUX4_MUX16 0
+#define BM_PXP_WFE_A_STAGE2_MUX4_MUX16 0x0000003F
+#define BF_PXP_WFE_A_STAGE2_MUX4_MUX16(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE2_MUX4_MUX16)
+
+#define HW_PXP_WFE_A_STAGE2_MUX5 (0x000017b0)
+#define HW_PXP_WFE_A_STAGE2_MUX5_SET (0x000017b4)
+#define HW_PXP_WFE_A_STAGE2_MUX5_CLR (0x000017b8)
+#define HW_PXP_WFE_A_STAGE2_MUX5_TOG (0x000017bc)
+
+#define BP_PXP_WFE_A_STAGE2_MUX5_RSVD0 30
+#define BM_PXP_WFE_A_STAGE2_MUX5_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE2_MUX5_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE2_MUX5_RSVD0)
+#define BP_PXP_WFE_A_STAGE2_MUX5_MUX23 24
+#define BM_PXP_WFE_A_STAGE2_MUX5_MUX23 0x3F000000
+#define BF_PXP_WFE_A_STAGE2_MUX5_MUX23(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE2_MUX5_MUX23)
+#define BP_PXP_WFE_A_STAGE2_MUX5_RSVD1 22
+#define BM_PXP_WFE_A_STAGE2_MUX5_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE2_MUX5_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE2_MUX5_RSVD1)
+#define BP_PXP_WFE_A_STAGE2_MUX5_MUX22 16
+#define BM_PXP_WFE_A_STAGE2_MUX5_MUX22 0x003F0000
+#define BF_PXP_WFE_A_STAGE2_MUX5_MUX22(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE2_MUX5_MUX22)
+#define BP_PXP_WFE_A_STAGE2_MUX5_RSVD2 14
+#define BM_PXP_WFE_A_STAGE2_MUX5_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE2_MUX5_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE2_MUX5_RSVD2)
+#define BP_PXP_WFE_A_STAGE2_MUX5_MUX21 8
+#define BM_PXP_WFE_A_STAGE2_MUX5_MUX21 0x00003F00
+#define BF_PXP_WFE_A_STAGE2_MUX5_MUX21(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE2_MUX5_MUX21)
+#define BP_PXP_WFE_A_STAGE2_MUX5_RSVD3 6
+#define BM_PXP_WFE_A_STAGE2_MUX5_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE2_MUX5_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE2_MUX5_RSVD3)
+#define BP_PXP_WFE_A_STAGE2_MUX5_MUX20 0
+#define BM_PXP_WFE_A_STAGE2_MUX5_MUX20 0x0000003F
+#define BF_PXP_WFE_A_STAGE2_MUX5_MUX20(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE2_MUX5_MUX20)
+
+#define HW_PXP_WFE_A_STAGE2_MUX6 (0x000017c0)
+#define HW_PXP_WFE_A_STAGE2_MUX6_SET (0x000017c4)
+#define HW_PXP_WFE_A_STAGE2_MUX6_CLR (0x000017c8)
+#define HW_PXP_WFE_A_STAGE2_MUX6_TOG (0x000017cc)
+
+#define BP_PXP_WFE_A_STAGE2_MUX6_RSVD0 30
+#define BM_PXP_WFE_A_STAGE2_MUX6_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE2_MUX6_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE2_MUX6_RSVD0)
+#define BP_PXP_WFE_A_STAGE2_MUX6_MUX27 24
+#define BM_PXP_WFE_A_STAGE2_MUX6_MUX27 0x3F000000
+#define BF_PXP_WFE_A_STAGE2_MUX6_MUX27(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE2_MUX6_MUX27)
+#define BP_PXP_WFE_A_STAGE2_MUX6_RSVD1 22
+#define BM_PXP_WFE_A_STAGE2_MUX6_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE2_MUX6_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE2_MUX6_RSVD1)
+#define BP_PXP_WFE_A_STAGE2_MUX6_MUX26 16
+#define BM_PXP_WFE_A_STAGE2_MUX6_MUX26 0x003F0000
+#define BF_PXP_WFE_A_STAGE2_MUX6_MUX26(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE2_MUX6_MUX26)
+#define BP_PXP_WFE_A_STAGE2_MUX6_RSVD2 14
+#define BM_PXP_WFE_A_STAGE2_MUX6_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE2_MUX6_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE2_MUX6_RSVD2)
+#define BP_PXP_WFE_A_STAGE2_MUX6_MUX25 8
+#define BM_PXP_WFE_A_STAGE2_MUX6_MUX25 0x00003F00
+#define BF_PXP_WFE_A_STAGE2_MUX6_MUX25(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE2_MUX6_MUX25)
+#define BP_PXP_WFE_A_STAGE2_MUX6_RSVD3 6
+#define BM_PXP_WFE_A_STAGE2_MUX6_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE2_MUX6_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE2_MUX6_RSVD3)
+#define BP_PXP_WFE_A_STAGE2_MUX6_MUX24 0
+#define BM_PXP_WFE_A_STAGE2_MUX6_MUX24 0x0000003F
+#define BF_PXP_WFE_A_STAGE2_MUX6_MUX24(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE2_MUX6_MUX24)
+
+#define HW_PXP_WFE_A_STAGE2_MUX7 (0x000017d0)
+#define HW_PXP_WFE_A_STAGE2_MUX7_SET (0x000017d4)
+#define HW_PXP_WFE_A_STAGE2_MUX7_CLR (0x000017d8)
+#define HW_PXP_WFE_A_STAGE2_MUX7_TOG (0x000017dc)
+
+#define BP_PXP_WFE_A_STAGE2_MUX7_RSVD0 30
+#define BM_PXP_WFE_A_STAGE2_MUX7_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE2_MUX7_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE2_MUX7_RSVD0)
+#define BP_PXP_WFE_A_STAGE2_MUX7_MUX31 24
+#define BM_PXP_WFE_A_STAGE2_MUX7_MUX31 0x3F000000
+#define BF_PXP_WFE_A_STAGE2_MUX7_MUX31(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE2_MUX7_MUX31)
+#define BP_PXP_WFE_A_STAGE2_MUX7_RSVD1 22
+#define BM_PXP_WFE_A_STAGE2_MUX7_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE2_MUX7_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE2_MUX7_RSVD1)
+#define BP_PXP_WFE_A_STAGE2_MUX7_MUX30 16
+#define BM_PXP_WFE_A_STAGE2_MUX7_MUX30 0x003F0000
+#define BF_PXP_WFE_A_STAGE2_MUX7_MUX30(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE2_MUX7_MUX30)
+#define BP_PXP_WFE_A_STAGE2_MUX7_RSVD2 14
+#define BM_PXP_WFE_A_STAGE2_MUX7_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE2_MUX7_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE2_MUX7_RSVD2)
+#define BP_PXP_WFE_A_STAGE2_MUX7_MUX29 8
+#define BM_PXP_WFE_A_STAGE2_MUX7_MUX29 0x00003F00
+#define BF_PXP_WFE_A_STAGE2_MUX7_MUX29(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE2_MUX7_MUX29)
+#define BP_PXP_WFE_A_STAGE2_MUX7_RSVD3 6
+#define BM_PXP_WFE_A_STAGE2_MUX7_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE2_MUX7_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE2_MUX7_RSVD3)
+#define BP_PXP_WFE_A_STAGE2_MUX7_MUX28 0
+#define BM_PXP_WFE_A_STAGE2_MUX7_MUX28 0x0000003F
+#define BF_PXP_WFE_A_STAGE2_MUX7_MUX28(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE2_MUX7_MUX28)
+
+#define HW_PXP_WFE_A_STAGE2_MUX8 (0x000017e0)
+#define HW_PXP_WFE_A_STAGE2_MUX8_SET (0x000017e4)
+#define HW_PXP_WFE_A_STAGE2_MUX8_CLR (0x000017e8)
+#define HW_PXP_WFE_A_STAGE2_MUX8_TOG (0x000017ec)
+
+#define BP_PXP_WFE_A_STAGE2_MUX8_RSVD0 30
+#define BM_PXP_WFE_A_STAGE2_MUX8_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE2_MUX8_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE2_MUX8_RSVD0)
+#define BP_PXP_WFE_A_STAGE2_MUX8_MUX35 24
+#define BM_PXP_WFE_A_STAGE2_MUX8_MUX35 0x3F000000
+#define BF_PXP_WFE_A_STAGE2_MUX8_MUX35(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE2_MUX8_MUX35)
+#define BP_PXP_WFE_A_STAGE2_MUX8_RSVD1 22
+#define BM_PXP_WFE_A_STAGE2_MUX8_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE2_MUX8_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE2_MUX8_RSVD1)
+#define BP_PXP_WFE_A_STAGE2_MUX8_MUX34 16
+#define BM_PXP_WFE_A_STAGE2_MUX8_MUX34 0x003F0000
+#define BF_PXP_WFE_A_STAGE2_MUX8_MUX34(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE2_MUX8_MUX34)
+#define BP_PXP_WFE_A_STAGE2_MUX8_RSVD2 14
+#define BM_PXP_WFE_A_STAGE2_MUX8_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE2_MUX8_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE2_MUX8_RSVD2)
+#define BP_PXP_WFE_A_STAGE2_MUX8_MUX33 8
+#define BM_PXP_WFE_A_STAGE2_MUX8_MUX33 0x00003F00
+#define BF_PXP_WFE_A_STAGE2_MUX8_MUX33(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE2_MUX8_MUX33)
+#define BP_PXP_WFE_A_STAGE2_MUX8_RSVD3 6
+#define BM_PXP_WFE_A_STAGE2_MUX8_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE2_MUX8_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE2_MUX8_RSVD3)
+#define BP_PXP_WFE_A_STAGE2_MUX8_MUX32 0
+#define BM_PXP_WFE_A_STAGE2_MUX8_MUX32 0x0000003F
+#define BF_PXP_WFE_A_STAGE2_MUX8_MUX32(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE2_MUX8_MUX32)
+
+#define HW_PXP_WFE_A_STAGE2_MUX9 (0x000017f0)
+#define HW_PXP_WFE_A_STAGE2_MUX9_SET (0x000017f4)
+#define HW_PXP_WFE_A_STAGE2_MUX9_CLR (0x000017f8)
+#define HW_PXP_WFE_A_STAGE2_MUX9_TOG (0x000017fc)
+
+#define BP_PXP_WFE_A_STAGE2_MUX9_RSVD0 30
+#define BM_PXP_WFE_A_STAGE2_MUX9_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE2_MUX9_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE2_MUX9_RSVD0)
+#define BP_PXP_WFE_A_STAGE2_MUX9_MUX39 24
+#define BM_PXP_WFE_A_STAGE2_MUX9_MUX39 0x3F000000
+#define BF_PXP_WFE_A_STAGE2_MUX9_MUX39(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE2_MUX9_MUX39)
+#define BP_PXP_WFE_A_STAGE2_MUX9_RSVD1 22
+#define BM_PXP_WFE_A_STAGE2_MUX9_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE2_MUX9_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE2_MUX9_RSVD1)
+#define BP_PXP_WFE_A_STAGE2_MUX9_MUX38 16
+#define BM_PXP_WFE_A_STAGE2_MUX9_MUX38 0x003F0000
+#define BF_PXP_WFE_A_STAGE2_MUX9_MUX38(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE2_MUX9_MUX38)
+#define BP_PXP_WFE_A_STAGE2_MUX9_RSVD2 14
+#define BM_PXP_WFE_A_STAGE2_MUX9_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE2_MUX9_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE2_MUX9_RSVD2)
+#define BP_PXP_WFE_A_STAGE2_MUX9_MUX37 8
+#define BM_PXP_WFE_A_STAGE2_MUX9_MUX37 0x00003F00
+#define BF_PXP_WFE_A_STAGE2_MUX9_MUX37(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE2_MUX9_MUX37)
+#define BP_PXP_WFE_A_STAGE2_MUX9_RSVD3 6
+#define BM_PXP_WFE_A_STAGE2_MUX9_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE2_MUX9_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE2_MUX9_RSVD3)
+#define BP_PXP_WFE_A_STAGE2_MUX9_MUX36 0
+#define BM_PXP_WFE_A_STAGE2_MUX9_MUX36 0x0000003F
+#define BF_PXP_WFE_A_STAGE2_MUX9_MUX36(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE2_MUX9_MUX36)
+
+#define HW_PXP_WFE_A_STAGE2_MUX10 (0x00001800)
+#define HW_PXP_WFE_A_STAGE2_MUX10_SET (0x00001804)
+#define HW_PXP_WFE_A_STAGE2_MUX10_CLR (0x00001808)
+#define HW_PXP_WFE_A_STAGE2_MUX10_TOG (0x0000180c)
+
+#define BP_PXP_WFE_A_STAGE2_MUX10_RSVD0 30
+#define BM_PXP_WFE_A_STAGE2_MUX10_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE2_MUX10_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE2_MUX10_RSVD0)
+#define BP_PXP_WFE_A_STAGE2_MUX10_MUX43 24
+#define BM_PXP_WFE_A_STAGE2_MUX10_MUX43 0x3F000000
+#define BF_PXP_WFE_A_STAGE2_MUX10_MUX43(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE2_MUX10_MUX43)
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX43__INC 0x0
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX43__DEC 0x1
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX43__ADD 0x2
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX43__MINUS 0x3
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX43__AND 0x4
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX43__OR 0x5
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX43__XOR 0x6
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX43__SHIFTLEFT 0x7
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX43__SHIFTRIGHT 0x8
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX43__BIT_AND 0x9
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX43__BIT_OR 0xa
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX43__BIT_CMP 0xb
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX43__NOP 0xc
+#define BP_PXP_WFE_A_STAGE2_MUX10_RSVD1 22
+#define BM_PXP_WFE_A_STAGE2_MUX10_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE2_MUX10_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE2_MUX10_RSVD1)
+#define BP_PXP_WFE_A_STAGE2_MUX10_MUX42 16
+#define BM_PXP_WFE_A_STAGE2_MUX10_MUX42 0x003F0000
+#define BF_PXP_WFE_A_STAGE2_MUX10_MUX42(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE2_MUX10_MUX42)
+#define BP_PXP_WFE_A_STAGE2_MUX10_RSVD2 14
+#define BM_PXP_WFE_A_STAGE2_MUX10_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE2_MUX10_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE2_MUX10_RSVD2)
+#define BP_PXP_WFE_A_STAGE2_MUX10_MUX41 8
+#define BM_PXP_WFE_A_STAGE2_MUX10_MUX41 0x00003F00
+#define BF_PXP_WFE_A_STAGE2_MUX10_MUX41(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE2_MUX10_MUX41)
+#define BP_PXP_WFE_A_STAGE2_MUX10_RSVD3 6
+#define BM_PXP_WFE_A_STAGE2_MUX10_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE2_MUX10_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE2_MUX10_RSVD3)
+#define BP_PXP_WFE_A_STAGE2_MUX10_MUX40 0
+#define BM_PXP_WFE_A_STAGE2_MUX10_MUX40 0x0000003F
+#define BF_PXP_WFE_A_STAGE2_MUX10_MUX40(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE2_MUX10_MUX40)
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX40__INC 0x0
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX40__DEC 0x1
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX40__ADD 0x2
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX40__MINUS 0x3
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX40__AND 0x4
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX40__OR 0x5
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX40__XOR 0x6
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX40__SHIFTLEFT 0x7
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX40__SHIFTRIGHT 0x8
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX40__BIT_AND 0x9
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX40__BIT_OR 0xa
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX40__BIT_CMP 0xb
+#define BV_PXP_WFE_A_STAGE2_MUX10_MUX40__NOP 0xc
+
+#define HW_PXP_WFE_A_STAGE2_MUX11 (0x00001810)
+#define HW_PXP_WFE_A_STAGE2_MUX11_SET (0x00001814)
+#define HW_PXP_WFE_A_STAGE2_MUX11_CLR (0x00001818)
+#define HW_PXP_WFE_A_STAGE2_MUX11_TOG (0x0000181c)
+
+#define BP_PXP_WFE_A_STAGE2_MUX11_RSVD0 30
+#define BM_PXP_WFE_A_STAGE2_MUX11_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE2_MUX11_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE2_MUX11_RSVD0)
+#define BP_PXP_WFE_A_STAGE2_MUX11_MUX47 24
+#define BM_PXP_WFE_A_STAGE2_MUX11_MUX47 0x3F000000
+#define BF_PXP_WFE_A_STAGE2_MUX11_MUX47(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE2_MUX11_MUX47)
+#define BP_PXP_WFE_A_STAGE2_MUX11_RSVD1 22
+#define BM_PXP_WFE_A_STAGE2_MUX11_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE2_MUX11_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE2_MUX11_RSVD1)
+#define BP_PXP_WFE_A_STAGE2_MUX11_MUX46 16
+#define BM_PXP_WFE_A_STAGE2_MUX11_MUX46 0x003F0000
+#define BF_PXP_WFE_A_STAGE2_MUX11_MUX46(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE2_MUX11_MUX46)
+#define BP_PXP_WFE_A_STAGE2_MUX11_RSVD2 14
+#define BM_PXP_WFE_A_STAGE2_MUX11_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE2_MUX11_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE2_MUX11_RSVD2)
+#define BP_PXP_WFE_A_STAGE2_MUX11_MUX45 8
+#define BM_PXP_WFE_A_STAGE2_MUX11_MUX45 0x00003F00
+#define BF_PXP_WFE_A_STAGE2_MUX11_MUX45(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE2_MUX11_MUX45)
+#define BP_PXP_WFE_A_STAGE2_MUX11_RSVD3 6
+#define BM_PXP_WFE_A_STAGE2_MUX11_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE2_MUX11_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE2_MUX11_RSVD3)
+#define BP_PXP_WFE_A_STAGE2_MUX11_MUX44 0
+#define BM_PXP_WFE_A_STAGE2_MUX11_MUX44 0x0000003F
+#define BF_PXP_WFE_A_STAGE2_MUX11_MUX44(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE2_MUX11_MUX44)
+
+#define HW_PXP_WFE_A_STAGE2_MUX12 (0x00001820)
+#define HW_PXP_WFE_A_STAGE2_MUX12_SET (0x00001824)
+#define HW_PXP_WFE_A_STAGE2_MUX12_CLR (0x00001828)
+#define HW_PXP_WFE_A_STAGE2_MUX12_TOG (0x0000182c)
+
+#define BP_PXP_WFE_A_STAGE2_MUX12_RSVD0 14
+#define BM_PXP_WFE_A_STAGE2_MUX12_RSVD0 0xFFFFC000
+#define BF_PXP_WFE_A_STAGE2_MUX12_RSVD0(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE2_MUX12_RSVD0)
+#define BP_PXP_WFE_A_STAGE2_MUX12_MUX49 8
+#define BM_PXP_WFE_A_STAGE2_MUX12_MUX49 0x00003F00
+#define BF_PXP_WFE_A_STAGE2_MUX12_MUX49(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE2_MUX12_MUX49)
+#define BP_PXP_WFE_A_STAGE2_MUX12_RSVD3 6
+#define BM_PXP_WFE_A_STAGE2_MUX12_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE2_MUX12_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE2_MUX12_RSVD3)
+#define BP_PXP_WFE_A_STAGE2_MUX12_MUX48 0
+#define BM_PXP_WFE_A_STAGE2_MUX12_MUX48 0x0000003F
+#define BF_PXP_WFE_A_STAGE2_MUX12_MUX48(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE2_MUX12_MUX48)
+
+#define HW_PXP_WFE_A_STAGE3_MUX0 (0x00001830)
+#define HW_PXP_WFE_A_STAGE3_MUX0_SET (0x00001834)
+#define HW_PXP_WFE_A_STAGE3_MUX0_CLR (0x00001838)
+#define HW_PXP_WFE_A_STAGE3_MUX0_TOG (0x0000183c)
+
+#define BP_PXP_WFE_A_STAGE3_MUX0_RSVD0 30
+#define BM_PXP_WFE_A_STAGE3_MUX0_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE3_MUX0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE3_MUX0_RSVD0)
+#define BP_PXP_WFE_A_STAGE3_MUX0_MUX3 24
+#define BM_PXP_WFE_A_STAGE3_MUX0_MUX3 0x3F000000
+#define BF_PXP_WFE_A_STAGE3_MUX0_MUX3(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE3_MUX0_MUX3)
+#define BP_PXP_WFE_A_STAGE3_MUX0_RSVD1 22
+#define BM_PXP_WFE_A_STAGE3_MUX0_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE3_MUX0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE3_MUX0_RSVD1)
+#define BP_PXP_WFE_A_STAGE3_MUX0_MUX2 16
+#define BM_PXP_WFE_A_STAGE3_MUX0_MUX2 0x003F0000
+#define BF_PXP_WFE_A_STAGE3_MUX0_MUX2(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE3_MUX0_MUX2)
+#define BP_PXP_WFE_A_STAGE3_MUX0_RSVD2 14
+#define BM_PXP_WFE_A_STAGE3_MUX0_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE3_MUX0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE3_MUX0_RSVD2)
+#define BP_PXP_WFE_A_STAGE3_MUX0_MUX1 8
+#define BM_PXP_WFE_A_STAGE3_MUX0_MUX1 0x00003F00
+#define BF_PXP_WFE_A_STAGE3_MUX0_MUX1(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE3_MUX0_MUX1)
+#define BP_PXP_WFE_A_STAGE3_MUX0_RSVD3 6
+#define BM_PXP_WFE_A_STAGE3_MUX0_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE3_MUX0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE3_MUX0_RSVD3)
+#define BP_PXP_WFE_A_STAGE3_MUX0_MUX0 0
+#define BM_PXP_WFE_A_STAGE3_MUX0_MUX0 0x0000003F
+#define BF_PXP_WFE_A_STAGE3_MUX0_MUX0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE3_MUX0_MUX0)
+
+#define HW_PXP_WFE_A_STAGE3_MUX1 (0x00001840)
+#define HW_PXP_WFE_A_STAGE3_MUX1_SET (0x00001844)
+#define HW_PXP_WFE_A_STAGE3_MUX1_CLR (0x00001848)
+#define HW_PXP_WFE_A_STAGE3_MUX1_TOG (0x0000184c)
+
+#define BP_PXP_WFE_A_STAGE3_MUX1_RSVD0 30
+#define BM_PXP_WFE_A_STAGE3_MUX1_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE3_MUX1_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE3_MUX1_RSVD0)
+#define BP_PXP_WFE_A_STAGE3_MUX1_MUX7 24
+#define BM_PXP_WFE_A_STAGE3_MUX1_MUX7 0x3F000000
+#define BF_PXP_WFE_A_STAGE3_MUX1_MUX7(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE3_MUX1_MUX7)
+#define BP_PXP_WFE_A_STAGE3_MUX1_RSVD1 22
+#define BM_PXP_WFE_A_STAGE3_MUX1_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE3_MUX1_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE3_MUX1_RSVD1)
+#define BP_PXP_WFE_A_STAGE3_MUX1_MUX6 16
+#define BM_PXP_WFE_A_STAGE3_MUX1_MUX6 0x003F0000
+#define BF_PXP_WFE_A_STAGE3_MUX1_MUX6(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE3_MUX1_MUX6)
+#define BP_PXP_WFE_A_STAGE3_MUX1_RSVD2 14
+#define BM_PXP_WFE_A_STAGE3_MUX1_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE3_MUX1_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE3_MUX1_RSVD2)
+#define BP_PXP_WFE_A_STAGE3_MUX1_MUX5 8
+#define BM_PXP_WFE_A_STAGE3_MUX1_MUX5 0x00003F00
+#define BF_PXP_WFE_A_STAGE3_MUX1_MUX5(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE3_MUX1_MUX5)
+#define BP_PXP_WFE_A_STAGE3_MUX1_RSVD3 6
+#define BM_PXP_WFE_A_STAGE3_MUX1_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE3_MUX1_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE3_MUX1_RSVD3)
+#define BP_PXP_WFE_A_STAGE3_MUX1_MUX4 0
+#define BM_PXP_WFE_A_STAGE3_MUX1_MUX4 0x0000003F
+#define BF_PXP_WFE_A_STAGE3_MUX1_MUX4(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE3_MUX1_MUX4)
+
+#define HW_PXP_WFE_A_STAGE3_MUX2 (0x00001850)
+#define HW_PXP_WFE_A_STAGE3_MUX2_SET (0x00001854)
+#define HW_PXP_WFE_A_STAGE3_MUX2_CLR (0x00001858)
+#define HW_PXP_WFE_A_STAGE3_MUX2_TOG (0x0000185c)
+
+#define BP_PXP_WFE_A_STAGE3_MUX2_RSVD0 30
+#define BM_PXP_WFE_A_STAGE3_MUX2_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE3_MUX2_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE3_MUX2_RSVD0)
+#define BP_PXP_WFE_A_STAGE3_MUX2_MUX11 24
+#define BM_PXP_WFE_A_STAGE3_MUX2_MUX11 0x3F000000
+#define BF_PXP_WFE_A_STAGE3_MUX2_MUX11(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE3_MUX2_MUX11)
+#define BP_PXP_WFE_A_STAGE3_MUX2_RSVD1 22
+#define BM_PXP_WFE_A_STAGE3_MUX2_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE3_MUX2_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE3_MUX2_RSVD1)
+#define BP_PXP_WFE_A_STAGE3_MUX2_MUX10 16
+#define BM_PXP_WFE_A_STAGE3_MUX2_MUX10 0x003F0000
+#define BF_PXP_WFE_A_STAGE3_MUX2_MUX10(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE3_MUX2_MUX10)
+#define BP_PXP_WFE_A_STAGE3_MUX2_RSVD2 14
+#define BM_PXP_WFE_A_STAGE3_MUX2_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE3_MUX2_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE3_MUX2_RSVD2)
+#define BP_PXP_WFE_A_STAGE3_MUX2_MUX9 8
+#define BM_PXP_WFE_A_STAGE3_MUX2_MUX9 0x00003F00
+#define BF_PXP_WFE_A_STAGE3_MUX2_MUX9(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE3_MUX2_MUX9)
+#define BP_PXP_WFE_A_STAGE3_MUX2_RSVD3 6
+#define BM_PXP_WFE_A_STAGE3_MUX2_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE3_MUX2_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE3_MUX2_RSVD3)
+#define BP_PXP_WFE_A_STAGE3_MUX2_MUX8 0
+#define BM_PXP_WFE_A_STAGE3_MUX2_MUX8 0x0000003F
+#define BF_PXP_WFE_A_STAGE3_MUX2_MUX8(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE3_MUX2_MUX8)
+
+#define HW_PXP_WFE_A_STAGE3_MUX3 (0x00001860)
+#define HW_PXP_WFE_A_STAGE3_MUX3_SET (0x00001864)
+#define HW_PXP_WFE_A_STAGE3_MUX3_CLR (0x00001868)
+#define HW_PXP_WFE_A_STAGE3_MUX3_TOG (0x0000186c)
+
+#define BP_PXP_WFE_A_STAGE3_MUX3_RSVD0 30
+#define BM_PXP_WFE_A_STAGE3_MUX3_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE3_MUX3_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE3_MUX3_RSVD0)
+#define BP_PXP_WFE_A_STAGE3_MUX3_MUX15 24
+#define BM_PXP_WFE_A_STAGE3_MUX3_MUX15 0x3F000000
+#define BF_PXP_WFE_A_STAGE3_MUX3_MUX15(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE3_MUX3_MUX15)
+#define BP_PXP_WFE_A_STAGE3_MUX3_RSVD1 22
+#define BM_PXP_WFE_A_STAGE3_MUX3_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE3_MUX3_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE3_MUX3_RSVD1)
+#define BP_PXP_WFE_A_STAGE3_MUX3_MUX14 16
+#define BM_PXP_WFE_A_STAGE3_MUX3_MUX14 0x003F0000
+#define BF_PXP_WFE_A_STAGE3_MUX3_MUX14(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE3_MUX3_MUX14)
+#define BP_PXP_WFE_A_STAGE3_MUX3_RSVD2 14
+#define BM_PXP_WFE_A_STAGE3_MUX3_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE3_MUX3_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE3_MUX3_RSVD2)
+#define BP_PXP_WFE_A_STAGE3_MUX3_MUX13 8
+#define BM_PXP_WFE_A_STAGE3_MUX3_MUX13 0x00003F00
+#define BF_PXP_WFE_A_STAGE3_MUX3_MUX13(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE3_MUX3_MUX13)
+#define BP_PXP_WFE_A_STAGE3_MUX3_RSVD3 6
+#define BM_PXP_WFE_A_STAGE3_MUX3_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE3_MUX3_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE3_MUX3_RSVD3)
+#define BP_PXP_WFE_A_STAGE3_MUX3_MUX12 0
+#define BM_PXP_WFE_A_STAGE3_MUX3_MUX12 0x0000003F
+#define BF_PXP_WFE_A_STAGE3_MUX3_MUX12(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE3_MUX3_MUX12)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT0_0 (0x00001870)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT31 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT31)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT30 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT30)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT29 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT29)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT28 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT28)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT27 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT27)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT26 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT26)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT25 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT25)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT24 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT24)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT23 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT23)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT22 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT22)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT21 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT21)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT20 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT20)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT19 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT19)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT18 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT18)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT17 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT17)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT16 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT16)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT15 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT15)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT14 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT14)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT13 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT13)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT12 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT12)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT11 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT11)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT10 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT10)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT9 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT9)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT8 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT8)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT7 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT7)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT6 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT6)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT5 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT5)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT4 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT4)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT3 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT3)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT2 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT2)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT1 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT1)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT0 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT0_0_LUTOUT0)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT0_1 (0x00001880)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT63 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT63(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT63)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT62 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT62(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT62)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT61 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT61(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT61)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT60 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT60(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT60)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT59 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT59(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT59)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT58 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT58(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT58)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT57 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT57(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT57)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT56 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT56(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT56)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT55 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT55(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT55)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT54 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT54(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT54)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT53 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT53(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT53)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT52 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT52(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT52)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT51 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT51(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT51)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT50 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT50(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT50)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT49 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT49(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT49)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT48 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT48(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT48)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT47 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT47(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT47)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT46 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT46(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT46)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT45 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT45(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT45)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT44 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT44(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT44)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT43 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT43(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT43)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT42 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT42(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT42)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT41 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT41(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT41)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT40 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT40(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT40)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT39 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT39(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT39)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT38 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT38(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT38)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT37 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT37(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT37)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT36 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT36(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT36)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT35 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT35(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT35)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT34 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT34(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT34)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT33 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT33(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT33)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT32 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT32(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT0_1_LUTOUT32)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT0_2 (0x00001890)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT95 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT95(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT95)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT94 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT94(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT94)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT93 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT93(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT93)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT92 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT92(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT92)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT91 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT91(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT91)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT90 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT90(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT90)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT89 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT89(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT89)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT88 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT88(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT88)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT87 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT87(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT87)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT86 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT86(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT86)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT85 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT85(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT85)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT84 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT84(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT84)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT83 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT83(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT83)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT82 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT82(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT82)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT81 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT81(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT81)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT80 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT80(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT80)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT79 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT79(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT79)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT78 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT78(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT78)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT77 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT77(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT77)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT76 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT76(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT76)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT75 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT75(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT75)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT74 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT74(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT74)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT73 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT73(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT73)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT72 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT72(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT72)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT71 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT71(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT71)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT70 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT70(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT70)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT69 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT69(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT69)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT68 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT68(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT68)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT67 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT67(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT67)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT66 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT66(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT66)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT65 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT65(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT65)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT64 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT64(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT0_2_LUTOUT64)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT0_3 (0x000018a0)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT127 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT127(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT127)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT126 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT126(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT126)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT125 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT125(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT125)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT124 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT124(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT124)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT123 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT123(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT123)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT122 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT122(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT122)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT121 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT121(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT121)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT120 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT120(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT120)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT119 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT119(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT119)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT118 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT118(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT118)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT117 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT117(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT117)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT116 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT116(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT116)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT115 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT115(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT115)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT114 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT114(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT114)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT113 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT113(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT113)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT112 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT112(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT112)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT111 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT111(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT111)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT110 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT110(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT110)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT109 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT109(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT109)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT108 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT108(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT108)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT107 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT107(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT107)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT106 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT106(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT106)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT105 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT105(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT105)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT104 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT104(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT104)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT103 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT103(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT103)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT102 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT102(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT102)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT101 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT101(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT101)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT100 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT100(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT100)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT99 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT99(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT99)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT98 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT98(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT98)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT97 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT97(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT97)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT96 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT96(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT0_3_LUTOUT96)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT0_4 (0x000018b0)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT159 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT159(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT159)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT158 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT158(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT158)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT157 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT157(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT157)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT156 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT156(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT156)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT155 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT155(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT155)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT154 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT154(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT154)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT153 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT153(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT153)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT152 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT152(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT152)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT151 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT151(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT151)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT150 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT150(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT150)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT149 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT149(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT149)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT148 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT148(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT148)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT147 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT147(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT147)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT146 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT146(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT146)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT145 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT145(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT145)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT144 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT144(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT144)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT143 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT143(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT143)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT142 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT142(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT142)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT141 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT141(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT141)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT140 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT140(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT140)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT139 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT139(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT139)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT138 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT138(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT138)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT137 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT137(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT137)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT136 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT136(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT136)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT135 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT135(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT135)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT134 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT134(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT134)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT133 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT133(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT133)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT132 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT132(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT132)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT131 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT131(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT131)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT130 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT130(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT130)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT129 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT129(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT129)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT128 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT128(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT0_4_LUTOUT128)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT0_5 (0x000018c0)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT191 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT191(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT191)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT190 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT190(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT190)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT189 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT189(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT189)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT188 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT188(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT188)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT187 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT187(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT187)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT186 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT186(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT186)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT185 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT185(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT185)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT184 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT184(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT184)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT183 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT183(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT183)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT182 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT182(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT182)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT181 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT181(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT181)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT180 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT180(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT180)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT179 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT179(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT179)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT178 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT178(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT178)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT177 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT177(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT177)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT176 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT176(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT176)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT175 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT175(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT175)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT174 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT174(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT174)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT173 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT173(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT173)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT172 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT172(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT172)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT171 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT171(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT171)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT170 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT170(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT170)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT169 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT169(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT169)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT168 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT168(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT168)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT167 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT167(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT167)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT166 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT166(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT166)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT165 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT165(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT165)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT164 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT164(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT164)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT163 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT163(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT163)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT162 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT162(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT162)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT161 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT161(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT161)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT160 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT160(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT0_5_LUTOUT160)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT0_6 (0x000018d0)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT223 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT223(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT223)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT222 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT222(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT222)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT221 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT221(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT221)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT220 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT220(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT220)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT219 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT219(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT219)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT218 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT218(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT218)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT217 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT217(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT217)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT216 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT216(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT216)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT215 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT215(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT215)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT214 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT214(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT214)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT213 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT213(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT213)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT212 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT212(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT212)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT211 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT211(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT211)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT210 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT210(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT210)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT209 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT209(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT209)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT208 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT208(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT208)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT207 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT207(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT207)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT206 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT206(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT206)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT205 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT205(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT205)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT204 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT204(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT204)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT203 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT203(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT203)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT202 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT202(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT202)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT201 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT201(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT201)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT200 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT200(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT200)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT199 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT199(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT199)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT198 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT198(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT198)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT197 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT197(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT197)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT196 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT196(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT196)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT195 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT195(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT195)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT194 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT194(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT194)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT193 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT193(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT193)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT192 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT192(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT0_6_LUTOUT192)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT0_7 (0x000018e0)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT255 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT255(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT255)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT254 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT254(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT254)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT253 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT253(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT253)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT252 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT252(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT252)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT251 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT251(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT251)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT250 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT250(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT250)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT249 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT249(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT249)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT248 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT248(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT248)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT247 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT247(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT247)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT246 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT246(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT246)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT245 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT245(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT245)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT244 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT244(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT244)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT243 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT243(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT243)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT242 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT242(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT242)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT241 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT241(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT241)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT240 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT240(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT240)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT239 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT239(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT239)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT238 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT238(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT238)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT237 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT237(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT237)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT236 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT236(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT236)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT235 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT235(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT235)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT234 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT234(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT234)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT233 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT233(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT233)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT232 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT232(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT232)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT231 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT231(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT231)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT230 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT230(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT230)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT229 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT229(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT229)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT228 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT228(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT228)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT227 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT227(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT227)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT226 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT226(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT226)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT225 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT225(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT225)
+#define BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT224 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT224(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT0_7_LUTOUT224)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT1_0 (0x000018f0)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT31 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT31)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT30 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT30)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT29 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT29)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT28 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT28)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT27 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT27)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT26 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT26)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT25 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT25)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT24 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT24)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT23 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT23)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT22 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT22)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT21 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT21)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT20 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT20)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT19 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT19)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT18 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT18)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT17 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT17)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT16 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT16)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT15 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT15)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT14 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT14)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT13 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT13)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT12 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT12)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT11 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT11)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT10 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT10)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT9 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT9)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT8 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT8)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT7 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT7)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT6 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT6)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT5 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT5)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT4 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT4)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT3 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT3)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT2 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT2)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT1 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT1)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT0 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT1_0_LUTOUT0)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT1_1 (0x00001900)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT63 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT63(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT63)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT62 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT62(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT62)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT61 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT61(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT61)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT60 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT60(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT60)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT59 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT59(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT59)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT58 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT58(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT58)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT57 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT57(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT57)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT56 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT56(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT56)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT55 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT55(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT55)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT54 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT54(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT54)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT53 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT53(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT53)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT52 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT52(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT52)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT51 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT51(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT51)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT50 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT50(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT50)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT49 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT49(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT49)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT48 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT48(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT48)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT47 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT47(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT47)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT46 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT46(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT46)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT45 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT45(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT45)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT44 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT44(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT44)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT43 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT43(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT43)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT42 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT42(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT42)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT41 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT41(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT41)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT40 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT40(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT40)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT39 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT39(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT39)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT38 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT38(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT38)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT37 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT37(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT37)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT36 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT36(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT36)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT35 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT35(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT35)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT34 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT34(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT34)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT33 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT33(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT33)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT32 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT32(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT1_1_LUTOUT32)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT1_2 (0x00001910)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT95 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT95(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT95)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT94 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT94(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT94)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT93 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT93(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT93)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT92 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT92(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT92)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT91 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT91(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT91)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT90 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT90(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT90)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT89 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT89(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT89)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT88 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT88(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT88)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT87 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT87(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT87)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT86 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT86(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT86)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT85 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT85(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT85)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT84 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT84(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT84)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT83 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT83(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT83)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT82 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT82(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT82)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT81 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT81(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT81)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT80 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT80(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT80)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT79 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT79(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT79)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT78 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT78(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT78)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT77 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT77(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT77)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT76 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT76(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT76)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT75 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT75(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT75)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT74 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT74(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT74)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT73 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT73(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT73)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT72 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT72(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT72)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT71 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT71(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT71)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT70 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT70(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT70)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT69 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT69(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT69)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT68 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT68(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT68)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT67 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT67(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT67)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT66 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT66(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT66)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT65 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT65(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT65)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT64 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT64(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT1_2_LUTOUT64)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT1_3 (0x00001920)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT127 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT127(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT127)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT126 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT126(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT126)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT125 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT125(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT125)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT124 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT124(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT124)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT123 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT123(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT123)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT122 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT122(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT122)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT121 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT121(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT121)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT120 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT120(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT120)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT119 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT119(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT119)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT118 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT118(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT118)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT117 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT117(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT117)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT116 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT116(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT116)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT115 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT115(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT115)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT114 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT114(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT114)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT113 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT113(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT113)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT112 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT112(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT112)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT111 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT111(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT111)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT110 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT110(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT110)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT109 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT109(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT109)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT108 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT108(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT108)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT107 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT107(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT107)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT106 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT106(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT106)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT105 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT105(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT105)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT104 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT104(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT104)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT103 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT103(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT103)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT102 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT102(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT102)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT101 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT101(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT101)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT100 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT100(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT100)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT99 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT99(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT99)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT98 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT98(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT98)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT97 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT97(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT97)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT96 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT96(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT1_3_LUTOUT96)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT1_4 (0x00001930)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT159 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT159(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT159)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT158 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT158(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT158)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT157 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT157(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT157)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT156 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT156(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT156)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT155 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT155(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT155)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT154 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT154(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT154)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT153 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT153(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT153)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT152 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT152(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT152)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT151 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT151(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT151)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT150 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT150(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT150)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT149 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT149(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT149)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT148 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT148(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT148)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT147 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT147(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT147)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT146 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT146(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT146)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT145 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT145(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT145)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT144 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT144(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT144)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT143 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT143(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT143)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT142 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT142(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT142)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT141 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT141(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT141)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT140 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT140(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT140)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT139 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT139(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT139)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT138 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT138(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT138)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT137 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT137(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT137)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT136 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT136(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT136)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT135 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT135(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT135)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT134 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT134(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT134)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT133 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT133(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT133)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT132 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT132(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT132)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT131 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT131(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT131)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT130 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT130(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT130)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT129 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT129(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT129)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT128 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT128(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT1_4_LUTOUT128)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT1_5 (0x00001940)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT191 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT191(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT191)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT190 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT190(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT190)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT189 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT189(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT189)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT188 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT188(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT188)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT187 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT187(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT187)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT186 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT186(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT186)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT185 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT185(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT185)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT184 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT184(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT184)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT183 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT183(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT183)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT182 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT182(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT182)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT181 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT181(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT181)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT180 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT180(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT180)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT179 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT179(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT179)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT178 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT178(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT178)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT177 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT177(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT177)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT176 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT176(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT176)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT175 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT175(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT175)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT174 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT174(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT174)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT173 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT173(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT173)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT172 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT172(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT172)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT171 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT171(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT171)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT170 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT170(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT170)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT169 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT169(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT169)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT168 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT168(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT168)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT167 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT167(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT167)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT166 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT166(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT166)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT165 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT165(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT165)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT164 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT164(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT164)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT163 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT163(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT163)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT162 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT162(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT162)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT161 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT161(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT161)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT160 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT160(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT1_5_LUTOUT160)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT1_6 (0x00001950)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT223 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT223(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT223)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT222 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT222(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT222)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT221 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT221(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT221)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT220 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT220(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT220)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT219 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT219(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT219)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT218 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT218(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT218)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT217 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT217(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT217)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT216 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT216(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT216)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT215 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT215(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT215)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT214 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT214(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT214)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT213 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT213(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT213)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT212 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT212(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT212)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT211 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT211(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT211)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT210 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT210(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT210)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT209 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT209(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT209)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT208 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT208(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT208)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT207 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT207(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT207)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT206 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT206(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT206)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT205 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT205(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT205)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT204 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT204(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT204)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT203 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT203(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT203)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT202 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT202(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT202)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT201 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT201(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT201)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT200 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT200(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT200)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT199 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT199(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT199)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT198 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT198(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT198)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT197 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT197(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT197)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT196 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT196(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT196)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT195 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT195(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT195)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT194 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT194(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT194)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT193 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT193(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT193)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT192 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT192(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT1_6_LUTOUT192)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT1_7 (0x00001960)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT255 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT255(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT255)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT254 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT254(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT254)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT253 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT253(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT253)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT252 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT252(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT252)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT251 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT251(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT251)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT250 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT250(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT250)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT249 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT249(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT249)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT248 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT248(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT248)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT247 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT247(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT247)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT246 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT246(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT246)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT245 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT245(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT245)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT244 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT244(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT244)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT243 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT243(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT243)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT242 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT242(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT242)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT241 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT241(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT241)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT240 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT240(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT240)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT239 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT239(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT239)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT238 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT238(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT238)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT237 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT237(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT237)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT236 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT236(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT236)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT235 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT235(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT235)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT234 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT234(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT234)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT233 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT233(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT233)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT232 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT232(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT232)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT231 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT231(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT231)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT230 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT230(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT230)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT229 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT229(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT229)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT228 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT228(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT228)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT227 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT227(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT227)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT226 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT226(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT226)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT225 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT225(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT225)
+#define BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT224 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT224(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT1_7_LUTOUT224)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT2_0 (0x00001970)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT31 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT31)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT30 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT30)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT29 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT29)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT28 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT28)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT27 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT27)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT26 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT26)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT25 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT25)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT24 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT24)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT23 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT23)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT22 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT22)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT21 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT21)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT20 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT20)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT19 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT19)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT18 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT18)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT17 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT17)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT16 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT16)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT15 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT15)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT14 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT14)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT13 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT13)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT12 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT12)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT11 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT11)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT10 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT10)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT9 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT9)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT8 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT8)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT7 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT7)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT6 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT6)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT5 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT5)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT4 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT4)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT3 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT3)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT2 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT2)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT1 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT1)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT0 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT2_0_LUTOUT0)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT2_1 (0x00001980)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT63 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT63(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT63)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT62 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT62(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT62)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT61 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT61(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT61)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT60 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT60(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT60)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT59 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT59(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT59)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT58 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT58(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT58)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT57 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT57(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT57)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT56 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT56(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT56)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT55 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT55(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT55)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT54 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT54(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT54)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT53 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT53(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT53)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT52 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT52(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT52)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT51 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT51(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT51)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT50 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT50(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT50)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT49 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT49(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT49)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT48 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT48(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT48)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT47 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT47(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT47)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT46 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT46(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT46)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT45 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT45(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT45)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT44 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT44(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT44)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT43 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT43(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT43)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT42 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT42(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT42)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT41 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT41(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT41)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT40 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT40(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT40)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT39 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT39(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT39)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT38 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT38(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT38)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT37 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT37(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT37)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT36 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT36(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT36)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT35 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT35(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT35)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT34 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT34(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT34)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT33 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT33(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT33)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT32 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT32(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT2_1_LUTOUT32)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT2_2 (0x00001990)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT95 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT95(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT95)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT94 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT94(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT94)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT93 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT93(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT93)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT92 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT92(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT92)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT91 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT91(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT91)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT90 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT90(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT90)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT89 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT89(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT89)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT88 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT88(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT88)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT87 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT87(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT87)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT86 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT86(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT86)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT85 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT85(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT85)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT84 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT84(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT84)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT83 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT83(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT83)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT82 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT82(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT82)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT81 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT81(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT81)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT80 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT80(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT80)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT79 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT79(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT79)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT78 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT78(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT78)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT77 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT77(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT77)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT76 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT76(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT76)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT75 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT75(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT75)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT74 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT74(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT74)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT73 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT73(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT73)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT72 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT72(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT72)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT71 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT71(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT71)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT70 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT70(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT70)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT69 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT69(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT69)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT68 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT68(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT68)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT67 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT67(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT67)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT66 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT66(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT66)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT65 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT65(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT65)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT64 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT64(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT2_2_LUTOUT64)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT2_3 (0x000019a0)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT127 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT127(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT127)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT126 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT126(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT126)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT125 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT125(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT125)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT124 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT124(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT124)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT123 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT123(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT123)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT122 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT122(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT122)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT121 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT121(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT121)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT120 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT120(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT120)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT119 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT119(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT119)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT118 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT118(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT118)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT117 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT117(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT117)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT116 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT116(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT116)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT115 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT115(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT115)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT114 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT114(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT114)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT113 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT113(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT113)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT112 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT112(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT112)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT111 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT111(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT111)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT110 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT110(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT110)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT109 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT109(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT109)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT108 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT108(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT108)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT107 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT107(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT107)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT106 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT106(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT106)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT105 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT105(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT105)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT104 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT104(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT104)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT103 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT103(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT103)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT102 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT102(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT102)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT101 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT101(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT101)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT100 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT100(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT100)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT99 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT99(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT99)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT98 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT98(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT98)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT97 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT97(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT97)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT96 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT96(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT2_3_LUTOUT96)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT2_4 (0x000019b0)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT159 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT159(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT159)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT158 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT158(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT158)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT157 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT157(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT157)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT156 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT156(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT156)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT155 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT155(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT155)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT154 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT154(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT154)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT153 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT153(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT153)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT152 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT152(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT152)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT151 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT151(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT151)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT150 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT150(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT150)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT149 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT149(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT149)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT148 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT148(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT148)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT147 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT147(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT147)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT146 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT146(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT146)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT145 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT145(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT145)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT144 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT144(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT144)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT143 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT143(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT143)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT142 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT142(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT142)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT141 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT141(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT141)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT140 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT140(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT140)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT139 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT139(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT139)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT138 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT138(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT138)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT137 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT137(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT137)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT136 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT136(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT136)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT135 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT135(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT135)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT134 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT134(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT134)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT133 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT133(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT133)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT132 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT132(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT132)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT131 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT131(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT131)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT130 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT130(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT130)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT129 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT129(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT129)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT128 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT128(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT2_4_LUTOUT128)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT2_5 (0x000019c0)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT191 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT191(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT191)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT190 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT190(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT190)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT189 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT189(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT189)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT188 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT188(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT188)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT187 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT187(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT187)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT186 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT186(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT186)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT185 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT185(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT185)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT184 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT184(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT184)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT183 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT183(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT183)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT182 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT182(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT182)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT181 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT181(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT181)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT180 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT180(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT180)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT179 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT179(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT179)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT178 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT178(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT178)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT177 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT177(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT177)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT176 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT176(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT176)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT175 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT175(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT175)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT174 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT174(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT174)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT173 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT173(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT173)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT172 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT172(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT172)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT171 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT171(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT171)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT170 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT170(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT170)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT169 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT169(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT169)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT168 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT168(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT168)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT167 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT167(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT167)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT166 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT166(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT166)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT165 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT165(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT165)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT164 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT164(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT164)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT163 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT163(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT163)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT162 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT162(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT162)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT161 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT161(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT161)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT160 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT160(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT2_5_LUTOUT160)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT2_6 (0x000019d0)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT223 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT223(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT223)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT222 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT222(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT222)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT221 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT221(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT221)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT220 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT220(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT220)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT219 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT219(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT219)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT218 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT218(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT218)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT217 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT217(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT217)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT216 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT216(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT216)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT215 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT215(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT215)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT214 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT214(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT214)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT213 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT213(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT213)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT212 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT212(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT212)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT211 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT211(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT211)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT210 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT210(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT210)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT209 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT209(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT209)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT208 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT208(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT208)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT207 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT207(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT207)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT206 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT206(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT206)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT205 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT205(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT205)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT204 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT204(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT204)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT203 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT203(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT203)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT202 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT202(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT202)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT201 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT201(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT201)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT200 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT200(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT200)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT199 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT199(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT199)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT198 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT198(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT198)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT197 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT197(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT197)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT196 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT196(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT196)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT195 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT195(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT195)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT194 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT194(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT194)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT193 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT193(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT193)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT192 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT192(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT2_6_LUTOUT192)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT2_7 (0x000019e0)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT255 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT255(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT255)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT254 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT254(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT254)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT253 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT253(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT253)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT252 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT252(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT252)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT251 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT251(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT251)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT250 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT250(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT250)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT249 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT249(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT249)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT248 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT248(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT248)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT247 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT247(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT247)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT246 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT246(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT246)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT245 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT245(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT245)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT244 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT244(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT244)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT243 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT243(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT243)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT242 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT242(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT242)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT241 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT241(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT241)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT240 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT240(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT240)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT239 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT239(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT239)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT238 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT238(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT238)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT237 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT237(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT237)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT236 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT236(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT236)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT235 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT235(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT235)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT234 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT234(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT234)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT233 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT233(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT233)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT232 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT232(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT232)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT231 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT231(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT231)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT230 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT230(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT230)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT229 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT229(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT229)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT228 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT228(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT228)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT227 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT227(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT227)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT226 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT226(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT226)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT225 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT225(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT225)
+#define BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT224 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT224(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT2_7_LUTOUT224)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT3_0 (0x000019f0)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT31 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT31)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT30 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT30)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT29 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT29)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT28 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT28)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT27 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT27)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT26 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT26)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT25 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT25)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT24 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT24)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT23 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT23)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT22 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT22)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT21 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT21)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT20 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT20)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT19 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT19)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT18 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT18)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT17 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT17)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT16 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT16)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT15 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT15)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT14 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT14)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT13 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT13)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT12 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT12)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT11 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT11)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT10 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT10)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT9 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT9)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT8 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT8)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT7 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT7)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT6 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT6)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT5 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT5)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT4 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT4)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT3 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT3)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT2 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT2)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT1 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT1)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT0 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT3_0_LUTOUT0)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT3_1 (0x00001a00)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT63 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT63(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT63)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT62 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT62(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT62)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT61 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT61(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT61)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT60 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT60(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT60)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT59 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT59(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT59)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT58 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT58(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT58)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT57 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT57(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT57)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT56 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT56(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT56)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT55 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT55(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT55)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT54 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT54(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT54)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT53 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT53(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT53)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT52 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT52(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT52)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT51 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT51(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT51)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT50 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT50(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT50)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT49 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT49(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT49)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT48 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT48(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT48)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT47 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT47(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT47)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT46 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT46(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT46)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT45 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT45(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT45)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT44 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT44(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT44)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT43 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT43(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT43)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT42 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT42(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT42)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT41 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT41(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT41)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT40 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT40(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT40)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT39 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT39(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT39)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT38 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT38(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT38)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT37 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT37(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT37)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT36 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT36(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT36)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT35 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT35(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT35)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT34 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT34(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT34)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT33 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT33(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT33)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT32 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT32(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT3_1_LUTOUT32)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT3_2 (0x00001a10)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT95 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT95(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT95)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT94 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT94(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT94)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT93 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT93(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT93)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT92 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT92(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT92)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT91 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT91(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT91)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT90 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT90(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT90)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT89 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT89(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT89)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT88 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT88(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT88)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT87 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT87(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT87)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT86 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT86(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT86)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT85 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT85(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT85)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT84 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT84(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT84)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT83 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT83(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT83)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT82 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT82(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT82)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT81 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT81(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT81)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT80 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT80(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT80)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT79 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT79(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT79)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT78 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT78(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT78)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT77 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT77(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT77)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT76 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT76(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT76)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT75 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT75(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT75)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT74 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT74(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT74)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT73 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT73(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT73)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT72 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT72(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT72)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT71 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT71(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT71)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT70 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT70(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT70)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT69 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT69(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT69)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT68 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT68(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT68)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT67 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT67(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT67)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT66 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT66(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT66)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT65 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT65(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT65)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT64 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT64(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT3_2_LUTOUT64)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT3_3 (0x00001a20)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT127 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT127(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT127)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT126 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT126(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT126)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT125 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT125(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT125)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT124 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT124(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT124)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT123 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT123(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT123)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT122 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT122(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT122)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT121 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT121(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT121)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT120 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT120(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT120)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT119 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT119(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT119)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT118 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT118(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT118)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT117 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT117(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT117)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT116 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT116(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT116)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT115 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT115(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT115)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT114 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT114(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT114)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT113 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT113(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT113)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT112 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT112(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT112)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT111 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT111(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT111)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT110 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT110(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT110)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT109 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT109(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT109)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT108 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT108(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT108)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT107 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT107(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT107)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT106 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT106(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT106)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT105 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT105(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT105)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT104 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT104(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT104)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT103 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT103(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT103)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT102 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT102(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT102)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT101 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT101(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT101)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT100 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT100(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT100)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT99 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT99(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT99)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT98 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT98(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT98)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT97 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT97(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT97)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT96 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT96(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT3_3_LUTOUT96)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT3_4 (0x00001a30)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT159 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT159(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT159)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT158 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT158(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT158)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT157 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT157(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT157)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT156 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT156(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT156)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT155 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT155(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT155)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT154 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT154(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT154)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT153 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT153(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT153)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT152 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT152(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT152)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT151 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT151(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT151)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT150 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT150(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT150)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT149 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT149(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT149)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT148 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT148(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT148)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT147 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT147(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT147)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT146 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT146(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT146)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT145 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT145(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT145)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT144 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT144(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT144)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT143 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT143(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT143)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT142 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT142(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT142)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT141 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT141(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT141)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT140 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT140(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT140)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT139 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT139(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT139)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT138 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT138(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT138)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT137 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT137(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT137)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT136 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT136(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT136)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT135 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT135(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT135)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT134 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT134(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT134)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT133 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT133(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT133)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT132 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT132(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT132)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT131 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT131(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT131)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT130 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT130(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT130)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT129 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT129(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT129)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT128 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT128(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT3_4_LUTOUT128)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT3_5 (0x00001a40)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT191 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT191(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT191)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT190 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT190(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT190)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT189 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT189(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT189)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT188 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT188(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT188)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT187 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT187(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT187)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT186 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT186(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT186)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT185 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT185(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT185)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT184 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT184(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT184)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT183 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT183(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT183)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT182 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT182(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT182)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT181 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT181(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT181)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT180 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT180(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT180)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT179 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT179(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT179)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT178 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT178(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT178)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT177 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT177(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT177)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT176 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT176(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT176)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT175 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT175(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT175)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT174 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT174(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT174)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT173 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT173(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT173)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT172 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT172(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT172)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT171 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT171(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT171)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT170 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT170(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT170)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT169 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT169(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT169)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT168 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT168(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT168)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT167 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT167(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT167)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT166 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT166(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT166)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT165 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT165(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT165)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT164 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT164(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT164)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT163 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT163(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT163)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT162 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT162(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT162)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT161 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT161(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT161)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT160 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT160(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT3_5_LUTOUT160)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT3_6 (0x00001a50)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT223 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT223(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT223)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT222 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT222(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT222)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT221 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT221(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT221)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT220 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT220(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT220)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT219 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT219(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT219)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT218 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT218(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT218)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT217 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT217(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT217)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT216 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT216(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT216)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT215 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT215(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT215)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT214 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT214(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT214)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT213 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT213(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT213)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT212 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT212(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT212)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT211 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT211(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT211)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT210 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT210(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT210)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT209 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT209(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT209)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT208 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT208(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT208)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT207 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT207(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT207)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT206 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT206(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT206)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT205 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT205(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT205)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT204 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT204(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT204)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT203 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT203(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT203)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT202 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT202(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT202)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT201 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT201(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT201)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT200 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT200(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT200)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT199 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT199(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT199)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT198 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT198(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT198)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT197 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT197(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT197)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT196 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT196(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT196)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT195 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT195(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT195)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT194 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT194(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT194)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT193 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT193(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT193)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT192 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT192(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT3_6_LUTOUT192)
+
+#define HW_PXP_WFE_A_STG1_8X1_OUT3_7 (0x00001a60)
+
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT255 0x80000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT255(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT255)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT254 0x40000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT254(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT254)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT253 0x20000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT253(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT253)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT252 0x10000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT252(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT252)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT251 0x08000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT251(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT251)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT250 0x04000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT250(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT250)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT249 0x02000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT249(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT249)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT248 0x01000000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT248(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT248)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT247 0x00800000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT247(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT247)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT246 0x00400000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT246(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT246)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT245 0x00200000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT245(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT245)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT244 0x00100000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT244(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT244)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT243 0x00080000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT243(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT243)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT242 0x00040000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT242(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT242)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT241 0x00020000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT241(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT241)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT240 0x00010000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT240(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT240)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT239 0x00008000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT239(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT239)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT238 0x00004000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT238(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT238)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT237 0x00002000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT237(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT237)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT236 0x00001000
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT236(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT236)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT235 0x00000800
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT235(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT235)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT234 0x00000400
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT234(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT234)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT233 0x00000200
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT233(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT233)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT232 0x00000100
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT232(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT232)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT231 0x00000080
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT231(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT231)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT230 0x00000040
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT230(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT230)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT229 0x00000020
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT229(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT229)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT228 0x00000010
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT228(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT228)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT227 0x00000008
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT227(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT227)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT226 0x00000004
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT226(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT226)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT225 0x00000002
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT225(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT225)
+#define BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT224 0x00000001
+#define BF_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT224(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG1_8X1_OUT3_7_LUTOUT224)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT0_0 (0x00001a70)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_0_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_0_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT0_0_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_0_LUTOUT3 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_0_LUTOUT3 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_0_LUTOUT3(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT0_0_LUTOUT3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_0_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_0_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT0_0_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_0_LUTOUT2 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_0_LUTOUT2 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_0_LUTOUT2(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT0_0_LUTOUT2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_0_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_0_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT0_0_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_0_LUTOUT1 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_0_LUTOUT1 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_0_LUTOUT1(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT0_0_LUTOUT1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_0_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_0_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT0_0_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_0_LUTOUT0 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_0_LUTOUT0 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT0_0_LUTOUT0)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT0_1 (0x00001a80)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_1_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_1_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_1_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT0_1_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_1_LUTOUT7 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_1_LUTOUT7 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_1_LUTOUT7(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT0_1_LUTOUT7)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_1_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_1_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_1_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT0_1_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_1_LUTOUT6 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_1_LUTOUT6 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_1_LUTOUT6(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT0_1_LUTOUT6)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_1_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_1_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_1_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT0_1_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_1_LUTOUT5 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_1_LUTOUT5 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_1_LUTOUT5(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT0_1_LUTOUT5)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_1_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_1_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_1_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT0_1_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_1_LUTOUT4 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_1_LUTOUT4 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_1_LUTOUT4(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT0_1_LUTOUT4)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT0_2 (0x00001a90)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_2_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_2_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_2_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT0_2_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_2_LUTOUT11 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_2_LUTOUT11 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_2_LUTOUT11(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT0_2_LUTOUT11)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_2_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_2_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_2_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT0_2_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_2_LUTOUT10 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_2_LUTOUT10 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_2_LUTOUT10(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT0_2_LUTOUT10)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_2_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_2_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_2_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT0_2_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_2_LUTOUT9 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_2_LUTOUT9 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_2_LUTOUT9(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT0_2_LUTOUT9)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_2_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_2_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_2_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT0_2_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_2_LUTOUT8 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_2_LUTOUT8 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_2_LUTOUT8(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT0_2_LUTOUT8)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT0_3 (0x00001aa0)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_3_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_3_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_3_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT0_3_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_3_LUTOUT15 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_3_LUTOUT15 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_3_LUTOUT15(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT0_3_LUTOUT15)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_3_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_3_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_3_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT0_3_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_3_LUTOUT14 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_3_LUTOUT14 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_3_LUTOUT14(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT0_3_LUTOUT14)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_3_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_3_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_3_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT0_3_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_3_LUTOUT13 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_3_LUTOUT13 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_3_LUTOUT13(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT0_3_LUTOUT13)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_3_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_3_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_3_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT0_3_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_3_LUTOUT12 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_3_LUTOUT12 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_3_LUTOUT12(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT0_3_LUTOUT12)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT0_4 (0x00001ab0)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_4_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_4_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_4_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT0_4_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_4_LUTOUT19 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_4_LUTOUT19 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_4_LUTOUT19(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT0_4_LUTOUT19)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_4_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_4_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_4_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT0_4_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_4_LUTOUT18 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_4_LUTOUT18 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_4_LUTOUT18(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT0_4_LUTOUT18)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_4_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_4_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_4_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT0_4_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_4_LUTOUT17 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_4_LUTOUT17 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_4_LUTOUT17(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT0_4_LUTOUT17)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_4_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_4_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_4_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT0_4_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_4_LUTOUT16 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_4_LUTOUT16 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_4_LUTOUT16(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT0_4_LUTOUT16)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT0_5 (0x00001ac0)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_5_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_5_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_5_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT0_5_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_5_LUTOUT23 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_5_LUTOUT23 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_5_LUTOUT23(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT0_5_LUTOUT23)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_5_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_5_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_5_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT0_5_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_5_LUTOUT22 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_5_LUTOUT22 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_5_LUTOUT22(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT0_5_LUTOUT22)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_5_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_5_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_5_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT0_5_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_5_LUTOUT21 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_5_LUTOUT21 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_5_LUTOUT21(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT0_5_LUTOUT21)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_5_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_5_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_5_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT0_5_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_5_LUTOUT20 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_5_LUTOUT20 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_5_LUTOUT20(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT0_5_LUTOUT20)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT0_6 (0x00001ad0)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_6_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_6_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_6_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT0_6_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_6_LUTOUT27 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_6_LUTOUT27 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_6_LUTOUT27(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT0_6_LUTOUT27)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_6_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_6_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_6_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT0_6_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_6_LUTOUT26 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_6_LUTOUT26 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_6_LUTOUT26(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT0_6_LUTOUT26)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_6_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_6_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_6_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT0_6_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_6_LUTOUT25 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_6_LUTOUT25 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_6_LUTOUT25(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT0_6_LUTOUT25)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_6_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_6_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_6_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT0_6_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_6_LUTOUT24 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_6_LUTOUT24 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_6_LUTOUT24(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT0_6_LUTOUT24)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT0_7 (0x00001ae0)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_7_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_7_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_7_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT0_7_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_7_LUTOUT31 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_7_LUTOUT31 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_7_LUTOUT31(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT0_7_LUTOUT31)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_7_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_7_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_7_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT0_7_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_7_LUTOUT30 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_7_LUTOUT30 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_7_LUTOUT30(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT0_7_LUTOUT30)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_7_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_7_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_7_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT0_7_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_7_LUTOUT29 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_7_LUTOUT29 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_7_LUTOUT29(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT0_7_LUTOUT29)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_7_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_7_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_7_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT0_7_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT0_7_LUTOUT28 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT0_7_LUTOUT28 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT0_7_LUTOUT28(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT0_7_LUTOUT28)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT1_0 (0x00001af0)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_0_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_0_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT1_0_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_0_LUTOUT3 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_0_LUTOUT3 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_0_LUTOUT3(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT1_0_LUTOUT3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_0_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_0_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT1_0_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_0_LUTOUT2 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_0_LUTOUT2 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_0_LUTOUT2(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT1_0_LUTOUT2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_0_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_0_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT1_0_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_0_LUTOUT1 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_0_LUTOUT1 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_0_LUTOUT1(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT1_0_LUTOUT1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_0_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_0_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT1_0_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_0_LUTOUT0 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_0_LUTOUT0 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT1_0_LUTOUT0)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT1_1 (0x00001b00)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_1_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_1_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_1_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT1_1_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_1_LUTOUT7 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_1_LUTOUT7 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_1_LUTOUT7(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT1_1_LUTOUT7)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_1_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_1_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_1_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT1_1_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_1_LUTOUT6 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_1_LUTOUT6 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_1_LUTOUT6(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT1_1_LUTOUT6)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_1_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_1_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_1_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT1_1_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_1_LUTOUT5 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_1_LUTOUT5 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_1_LUTOUT5(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT1_1_LUTOUT5)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_1_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_1_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_1_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT1_1_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_1_LUTOUT4 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_1_LUTOUT4 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_1_LUTOUT4(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT1_1_LUTOUT4)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT1_2 (0x00001b10)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_2_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_2_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_2_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT1_2_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_2_LUTOUT11 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_2_LUTOUT11 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_2_LUTOUT11(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT1_2_LUTOUT11)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_2_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_2_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_2_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT1_2_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_2_LUTOUT10 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_2_LUTOUT10 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_2_LUTOUT10(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT1_2_LUTOUT10)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_2_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_2_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_2_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT1_2_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_2_LUTOUT9 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_2_LUTOUT9 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_2_LUTOUT9(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT1_2_LUTOUT9)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_2_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_2_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_2_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT1_2_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_2_LUTOUT8 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_2_LUTOUT8 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_2_LUTOUT8(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT1_2_LUTOUT8)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT1_3 (0x00001b20)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_3_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_3_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_3_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT1_3_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_3_LUTOUT15 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_3_LUTOUT15 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_3_LUTOUT15(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT1_3_LUTOUT15)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_3_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_3_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_3_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT1_3_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_3_LUTOUT14 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_3_LUTOUT14 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_3_LUTOUT14(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT1_3_LUTOUT14)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_3_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_3_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_3_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT1_3_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_3_LUTOUT13 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_3_LUTOUT13 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_3_LUTOUT13(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT1_3_LUTOUT13)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_3_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_3_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_3_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT1_3_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_3_LUTOUT12 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_3_LUTOUT12 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_3_LUTOUT12(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT1_3_LUTOUT12)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT1_4 (0x00001b30)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_4_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_4_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_4_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT1_4_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_4_LUTOUT19 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_4_LUTOUT19 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_4_LUTOUT19(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT1_4_LUTOUT19)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_4_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_4_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_4_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT1_4_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_4_LUTOUT18 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_4_LUTOUT18 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_4_LUTOUT18(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT1_4_LUTOUT18)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_4_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_4_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_4_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT1_4_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_4_LUTOUT17 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_4_LUTOUT17 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_4_LUTOUT17(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT1_4_LUTOUT17)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_4_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_4_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_4_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT1_4_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_4_LUTOUT16 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_4_LUTOUT16 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_4_LUTOUT16(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT1_4_LUTOUT16)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT1_5 (0x00001b40)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_5_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_5_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_5_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT1_5_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_5_LUTOUT23 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_5_LUTOUT23 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_5_LUTOUT23(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT1_5_LUTOUT23)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_5_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_5_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_5_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT1_5_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_5_LUTOUT22 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_5_LUTOUT22 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_5_LUTOUT22(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT1_5_LUTOUT22)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_5_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_5_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_5_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT1_5_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_5_LUTOUT21 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_5_LUTOUT21 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_5_LUTOUT21(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT1_5_LUTOUT21)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_5_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_5_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_5_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT1_5_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_5_LUTOUT20 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_5_LUTOUT20 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_5_LUTOUT20(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT1_5_LUTOUT20)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT1_6 (0x00001b50)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_6_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_6_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_6_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT1_6_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_6_LUTOUT27 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_6_LUTOUT27 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_6_LUTOUT27(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT1_6_LUTOUT27)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_6_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_6_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_6_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT1_6_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_6_LUTOUT26 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_6_LUTOUT26 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_6_LUTOUT26(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT1_6_LUTOUT26)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_6_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_6_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_6_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT1_6_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_6_LUTOUT25 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_6_LUTOUT25 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_6_LUTOUT25(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT1_6_LUTOUT25)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_6_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_6_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_6_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT1_6_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_6_LUTOUT24 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_6_LUTOUT24 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_6_LUTOUT24(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT1_6_LUTOUT24)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT1_7 (0x00001b60)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_7_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_7_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_7_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT1_7_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_7_LUTOUT31 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_7_LUTOUT31 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_7_LUTOUT31(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT1_7_LUTOUT31)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_7_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_7_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_7_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT1_7_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_7_LUTOUT30 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_7_LUTOUT30 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_7_LUTOUT30(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT1_7_LUTOUT30)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_7_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_7_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_7_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT1_7_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_7_LUTOUT29 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_7_LUTOUT29 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_7_LUTOUT29(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT1_7_LUTOUT29)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_7_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_7_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_7_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT1_7_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT1_7_LUTOUT28 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT1_7_LUTOUT28 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT1_7_LUTOUT28(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT1_7_LUTOUT28)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT2_0 (0x00001b70)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_0_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_0_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT2_0_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_0_LUTOUT3 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_0_LUTOUT3 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_0_LUTOUT3(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT2_0_LUTOUT3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_0_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_0_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT2_0_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_0_LUTOUT2 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_0_LUTOUT2 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_0_LUTOUT2(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT2_0_LUTOUT2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_0_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_0_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT2_0_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_0_LUTOUT1 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_0_LUTOUT1 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_0_LUTOUT1(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT2_0_LUTOUT1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_0_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_0_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT2_0_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_0_LUTOUT0 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_0_LUTOUT0 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT2_0_LUTOUT0)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT2_1 (0x00001b80)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_1_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_1_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_1_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT2_1_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_1_LUTOUT7 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_1_LUTOUT7 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_1_LUTOUT7(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT2_1_LUTOUT7)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_1_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_1_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_1_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT2_1_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_1_LUTOUT6 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_1_LUTOUT6 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_1_LUTOUT6(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT2_1_LUTOUT6)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_1_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_1_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_1_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT2_1_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_1_LUTOUT5 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_1_LUTOUT5 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_1_LUTOUT5(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT2_1_LUTOUT5)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_1_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_1_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_1_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT2_1_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_1_LUTOUT4 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_1_LUTOUT4 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_1_LUTOUT4(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT2_1_LUTOUT4)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT2_2 (0x00001b90)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_2_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_2_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_2_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT2_2_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_2_LUTOUT11 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_2_LUTOUT11 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_2_LUTOUT11(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT2_2_LUTOUT11)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_2_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_2_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_2_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT2_2_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_2_LUTOUT10 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_2_LUTOUT10 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_2_LUTOUT10(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT2_2_LUTOUT10)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_2_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_2_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_2_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT2_2_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_2_LUTOUT9 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_2_LUTOUT9 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_2_LUTOUT9(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT2_2_LUTOUT9)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_2_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_2_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_2_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT2_2_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_2_LUTOUT8 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_2_LUTOUT8 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_2_LUTOUT8(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT2_2_LUTOUT8)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT2_3 (0x00001ba0)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_3_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_3_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_3_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT2_3_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_3_LUTOUT15 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_3_LUTOUT15 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_3_LUTOUT15(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT2_3_LUTOUT15)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_3_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_3_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_3_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT2_3_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_3_LUTOUT14 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_3_LUTOUT14 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_3_LUTOUT14(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT2_3_LUTOUT14)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_3_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_3_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_3_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT2_3_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_3_LUTOUT13 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_3_LUTOUT13 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_3_LUTOUT13(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT2_3_LUTOUT13)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_3_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_3_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_3_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT2_3_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_3_LUTOUT12 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_3_LUTOUT12 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_3_LUTOUT12(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT2_3_LUTOUT12)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT2_4 (0x00001bb0)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_4_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_4_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_4_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT2_4_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_4_LUTOUT19 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_4_LUTOUT19 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_4_LUTOUT19(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT2_4_LUTOUT19)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_4_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_4_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_4_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT2_4_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_4_LUTOUT18 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_4_LUTOUT18 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_4_LUTOUT18(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT2_4_LUTOUT18)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_4_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_4_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_4_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT2_4_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_4_LUTOUT17 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_4_LUTOUT17 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_4_LUTOUT17(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT2_4_LUTOUT17)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_4_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_4_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_4_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT2_4_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_4_LUTOUT16 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_4_LUTOUT16 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_4_LUTOUT16(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT2_4_LUTOUT16)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT2_5 (0x00001bc0)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_5_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_5_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_5_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT2_5_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_5_LUTOUT23 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_5_LUTOUT23 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_5_LUTOUT23(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT2_5_LUTOUT23)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_5_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_5_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_5_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT2_5_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_5_LUTOUT22 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_5_LUTOUT22 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_5_LUTOUT22(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT2_5_LUTOUT22)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_5_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_5_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_5_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT2_5_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_5_LUTOUT21 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_5_LUTOUT21 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_5_LUTOUT21(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT2_5_LUTOUT21)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_5_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_5_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_5_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT2_5_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_5_LUTOUT20 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_5_LUTOUT20 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_5_LUTOUT20(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT2_5_LUTOUT20)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT2_6 (0x00001bd0)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_6_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_6_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_6_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT2_6_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_6_LUTOUT27 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_6_LUTOUT27 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_6_LUTOUT27(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT2_6_LUTOUT27)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_6_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_6_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_6_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT2_6_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_6_LUTOUT26 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_6_LUTOUT26 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_6_LUTOUT26(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT2_6_LUTOUT26)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_6_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_6_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_6_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT2_6_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_6_LUTOUT25 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_6_LUTOUT25 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_6_LUTOUT25(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT2_6_LUTOUT25)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_6_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_6_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_6_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT2_6_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_6_LUTOUT24 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_6_LUTOUT24 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_6_LUTOUT24(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT2_6_LUTOUT24)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT2_7 (0x00001be0)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_7_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_7_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_7_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT2_7_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_7_LUTOUT31 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_7_LUTOUT31 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_7_LUTOUT31(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT2_7_LUTOUT31)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_7_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_7_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_7_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT2_7_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_7_LUTOUT30 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_7_LUTOUT30 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_7_LUTOUT30(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT2_7_LUTOUT30)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_7_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_7_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_7_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT2_7_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_7_LUTOUT29 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_7_LUTOUT29 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_7_LUTOUT29(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT2_7_LUTOUT29)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_7_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_7_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_7_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT2_7_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT2_7_LUTOUT28 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT2_7_LUTOUT28 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT2_7_LUTOUT28(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT2_7_LUTOUT28)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT3_0 (0x00001bf0)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_0_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_0_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT3_0_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_0_LUTOUT3 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_0_LUTOUT3 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_0_LUTOUT3(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT3_0_LUTOUT3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_0_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_0_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT3_0_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_0_LUTOUT2 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_0_LUTOUT2 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_0_LUTOUT2(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT3_0_LUTOUT2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_0_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_0_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT3_0_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_0_LUTOUT1 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_0_LUTOUT1 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_0_LUTOUT1(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT3_0_LUTOUT1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_0_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_0_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT3_0_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_0_LUTOUT0 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_0_LUTOUT0 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT3_0_LUTOUT0)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT3_1 (0x00001c00)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_1_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_1_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_1_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT3_1_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_1_LUTOUT7 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_1_LUTOUT7 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_1_LUTOUT7(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT3_1_LUTOUT7)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_1_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_1_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_1_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT3_1_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_1_LUTOUT6 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_1_LUTOUT6 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_1_LUTOUT6(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT3_1_LUTOUT6)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_1_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_1_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_1_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT3_1_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_1_LUTOUT5 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_1_LUTOUT5 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_1_LUTOUT5(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT3_1_LUTOUT5)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_1_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_1_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_1_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT3_1_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_1_LUTOUT4 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_1_LUTOUT4 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_1_LUTOUT4(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT3_1_LUTOUT4)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT3_2 (0x00001c10)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_2_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_2_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_2_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT3_2_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_2_LUTOUT11 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_2_LUTOUT11 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_2_LUTOUT11(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT3_2_LUTOUT11)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_2_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_2_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_2_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT3_2_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_2_LUTOUT10 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_2_LUTOUT10 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_2_LUTOUT10(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT3_2_LUTOUT10)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_2_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_2_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_2_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT3_2_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_2_LUTOUT9 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_2_LUTOUT9 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_2_LUTOUT9(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT3_2_LUTOUT9)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_2_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_2_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_2_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT3_2_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_2_LUTOUT8 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_2_LUTOUT8 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_2_LUTOUT8(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT3_2_LUTOUT8)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT3_3 (0x00001c20)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_3_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_3_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_3_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT3_3_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_3_LUTOUT15 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_3_LUTOUT15 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_3_LUTOUT15(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT3_3_LUTOUT15)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_3_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_3_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_3_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT3_3_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_3_LUTOUT14 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_3_LUTOUT14 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_3_LUTOUT14(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT3_3_LUTOUT14)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_3_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_3_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_3_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT3_3_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_3_LUTOUT13 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_3_LUTOUT13 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_3_LUTOUT13(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT3_3_LUTOUT13)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_3_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_3_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_3_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT3_3_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_3_LUTOUT12 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_3_LUTOUT12 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_3_LUTOUT12(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT3_3_LUTOUT12)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT3_4 (0x00001c30)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_4_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_4_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_4_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT3_4_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_4_LUTOUT19 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_4_LUTOUT19 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_4_LUTOUT19(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT3_4_LUTOUT19)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_4_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_4_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_4_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT3_4_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_4_LUTOUT18 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_4_LUTOUT18 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_4_LUTOUT18(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT3_4_LUTOUT18)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_4_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_4_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_4_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT3_4_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_4_LUTOUT17 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_4_LUTOUT17 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_4_LUTOUT17(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT3_4_LUTOUT17)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_4_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_4_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_4_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT3_4_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_4_LUTOUT16 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_4_LUTOUT16 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_4_LUTOUT16(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT3_4_LUTOUT16)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT3_5 (0x00001c40)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_5_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_5_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_5_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT3_5_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_5_LUTOUT23 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_5_LUTOUT23 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_5_LUTOUT23(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT3_5_LUTOUT23)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_5_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_5_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_5_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT3_5_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_5_LUTOUT22 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_5_LUTOUT22 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_5_LUTOUT22(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT3_5_LUTOUT22)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_5_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_5_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_5_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT3_5_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_5_LUTOUT21 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_5_LUTOUT21 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_5_LUTOUT21(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT3_5_LUTOUT21)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_5_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_5_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_5_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT3_5_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_5_LUTOUT20 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_5_LUTOUT20 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_5_LUTOUT20(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT3_5_LUTOUT20)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT3_6 (0x00001c50)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_6_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_6_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_6_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT3_6_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_6_LUTOUT27 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_6_LUTOUT27 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_6_LUTOUT27(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT3_6_LUTOUT27)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_6_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_6_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_6_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT3_6_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_6_LUTOUT26 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_6_LUTOUT26 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_6_LUTOUT26(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT3_6_LUTOUT26)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_6_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_6_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_6_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT3_6_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_6_LUTOUT25 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_6_LUTOUT25 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_6_LUTOUT25(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT3_6_LUTOUT25)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_6_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_6_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_6_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT3_6_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_6_LUTOUT24 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_6_LUTOUT24 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_6_LUTOUT24(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT3_6_LUTOUT24)
+
+#define HW_PXP_WFE_A_STG2_5X6_OUT3_7 (0x00001c60)
+
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_7_RSVD0 30
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_7_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_7_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X6_OUT3_7_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_7_LUTOUT31 24
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_7_LUTOUT31 0x3F000000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_7_LUTOUT31(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X6_OUT3_7_LUTOUT31)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_7_RSVD1 22
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_7_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_7_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X6_OUT3_7_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_7_LUTOUT30 16
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_7_LUTOUT30 0x003F0000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_7_LUTOUT30(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X6_OUT3_7_LUTOUT30)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_7_RSVD2 14
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_7_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_7_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X6_OUT3_7_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_7_LUTOUT29 8
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_7_LUTOUT29 0x00003F00
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_7_LUTOUT29(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X6_OUT3_7_LUTOUT29)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_7_RSVD3 6
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_7_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_7_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X6_OUT3_7_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X6_OUT3_7_LUTOUT28 0
+#define BM_PXP_WFE_A_STG2_5X6_OUT3_7_LUTOUT28 0x0000003F
+#define BF_PXP_WFE_A_STG2_5X6_OUT3_7_LUTOUT28(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X6_OUT3_7_LUTOUT28)
+
+#define HW_PXP_WFE_A_STAGE2_5X6_MASKS_0 (0x00001c70)
+
+#define BP_PXP_WFE_A_STAGE2_5X6_MASKS_0_RSVD0 29
+#define BM_PXP_WFE_A_STAGE2_5X6_MASKS_0_RSVD0 0xE0000000
+#define BF_PXP_WFE_A_STAGE2_5X6_MASKS_0_RSVD0(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STAGE2_5X6_MASKS_0_RSVD0)
+#define BP_PXP_WFE_A_STAGE2_5X6_MASKS_0_MASK3 24
+#define BM_PXP_WFE_A_STAGE2_5X6_MASKS_0_MASK3 0x1F000000
+#define BF_PXP_WFE_A_STAGE2_5X6_MASKS_0_MASK3(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE2_5X6_MASKS_0_MASK3)
+#define BP_PXP_WFE_A_STAGE2_5X6_MASKS_0_RSVD1 21
+#define BM_PXP_WFE_A_STAGE2_5X6_MASKS_0_RSVD1 0x00E00000
+#define BF_PXP_WFE_A_STAGE2_5X6_MASKS_0_RSVD1(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STAGE2_5X6_MASKS_0_RSVD1)
+#define BP_PXP_WFE_A_STAGE2_5X6_MASKS_0_MASK2 16
+#define BM_PXP_WFE_A_STAGE2_5X6_MASKS_0_MASK2 0x001F0000
+#define BF_PXP_WFE_A_STAGE2_5X6_MASKS_0_MASK2(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE2_5X6_MASKS_0_MASK2)
+#define BP_PXP_WFE_A_STAGE2_5X6_MASKS_0_RSVD2 13
+#define BM_PXP_WFE_A_STAGE2_5X6_MASKS_0_RSVD2 0x0000E000
+#define BF_PXP_WFE_A_STAGE2_5X6_MASKS_0_RSVD2(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STAGE2_5X6_MASKS_0_RSVD2)
+#define BP_PXP_WFE_A_STAGE2_5X6_MASKS_0_MASK1 8
+#define BM_PXP_WFE_A_STAGE2_5X6_MASKS_0_MASK1 0x00001F00
+#define BF_PXP_WFE_A_STAGE2_5X6_MASKS_0_MASK1(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE2_5X6_MASKS_0_MASK1)
+#define BP_PXP_WFE_A_STAGE2_5X6_MASKS_0_RSVD3 5
+#define BM_PXP_WFE_A_STAGE2_5X6_MASKS_0_RSVD3 0x000000E0
+#define BF_PXP_WFE_A_STAGE2_5X6_MASKS_0_RSVD3(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STAGE2_5X6_MASKS_0_RSVD3)
+#define BP_PXP_WFE_A_STAGE2_5X6_MASKS_0_MASK0 0
+#define BM_PXP_WFE_A_STAGE2_5X6_MASKS_0_MASK0 0x0000001F
+#define BF_PXP_WFE_A_STAGE2_5X6_MASKS_0_MASK0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE2_5X6_MASKS_0_MASK0)
+
+#define HW_PXP_WFE_A_STAGE2_5X6_ADDR_0 (0x00001c80)
+
+#define BP_PXP_WFE_A_STAGE2_5X6_ADDR_0_RSVD0 30
+#define BM_PXP_WFE_A_STAGE2_5X6_ADDR_0_RSVD0 0xC0000000
+#define BF_PXP_WFE_A_STAGE2_5X6_ADDR_0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STAGE2_5X6_ADDR_0_RSVD0)
+#define BP_PXP_WFE_A_STAGE2_5X6_ADDR_0_MUXADDR3 24
+#define BM_PXP_WFE_A_STAGE2_5X6_ADDR_0_MUXADDR3 0x3F000000
+#define BF_PXP_WFE_A_STAGE2_5X6_ADDR_0_MUXADDR3(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STAGE2_5X6_ADDR_0_MUXADDR3)
+#define BP_PXP_WFE_A_STAGE2_5X6_ADDR_0_RSVD1 22
+#define BM_PXP_WFE_A_STAGE2_5X6_ADDR_0_RSVD1 0x00C00000
+#define BF_PXP_WFE_A_STAGE2_5X6_ADDR_0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STAGE2_5X6_ADDR_0_RSVD1)
+#define BP_PXP_WFE_A_STAGE2_5X6_ADDR_0_MUXADDR2 16
+#define BM_PXP_WFE_A_STAGE2_5X6_ADDR_0_MUXADDR2 0x003F0000
+#define BF_PXP_WFE_A_STAGE2_5X6_ADDR_0_MUXADDR2(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STAGE2_5X6_ADDR_0_MUXADDR2)
+#define BP_PXP_WFE_A_STAGE2_5X6_ADDR_0_RSVD2 14
+#define BM_PXP_WFE_A_STAGE2_5X6_ADDR_0_RSVD2 0x0000C000
+#define BF_PXP_WFE_A_STAGE2_5X6_ADDR_0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STAGE2_5X6_ADDR_0_RSVD2)
+#define BP_PXP_WFE_A_STAGE2_5X6_ADDR_0_MUXADDR1 8
+#define BM_PXP_WFE_A_STAGE2_5X6_ADDR_0_MUXADDR1 0x00003F00
+#define BF_PXP_WFE_A_STAGE2_5X6_ADDR_0_MUXADDR1(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STAGE2_5X6_ADDR_0_MUXADDR1)
+#define BP_PXP_WFE_A_STAGE2_5X6_ADDR_0_RSVD3 6
+#define BM_PXP_WFE_A_STAGE2_5X6_ADDR_0_RSVD3 0x000000C0
+#define BF_PXP_WFE_A_STAGE2_5X6_ADDR_0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STAGE2_5X6_ADDR_0_RSVD3)
+#define BP_PXP_WFE_A_STAGE2_5X6_ADDR_0_MUXADDR0 0
+#define BM_PXP_WFE_A_STAGE2_5X6_ADDR_0_MUXADDR0 0x0000003F
+#define BF_PXP_WFE_A_STAGE2_5X6_ADDR_0_MUXADDR0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STAGE2_5X6_ADDR_0_MUXADDR0)
+
+#define HW_PXP_WFE_A_STG2_5X1_OUT0 (0x00001c90)
+
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT31 0x80000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT31)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT30 0x40000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT30)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT29 0x20000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT29)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT28 0x10000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT28)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT27 0x08000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT27)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT26 0x04000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT26)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT25 0x02000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT25)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT24 0x01000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT24)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT23 0x00800000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT23)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT22 0x00400000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT22)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT21 0x00200000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT21)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT20 0x00100000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT20)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT19 0x00080000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT19)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT18 0x00040000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT18)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT17 0x00020000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT17)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT16 0x00010000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT16)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT15 0x00008000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT15)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT14 0x00004000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT14)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT13 0x00002000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT13)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT12 0x00001000
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT12)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT11 0x00000800
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT11)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT10 0x00000400
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT10)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT9 0x00000200
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT9)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT8 0x00000100
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT8)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT7 0x00000080
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT7)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT6 0x00000040
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT6)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT5 0x00000020
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT5)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT4 0x00000010
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT4)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT3 0x00000008
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT3)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT2 0x00000004
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT2)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT1 0x00000002
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT1)
+#define BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT0 0x00000001
+#define BF_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X1_OUT0_LUTOUT0)
+
+#define HW_PXP_WFE_A_STG2_5X1_OUT1 (0x00001ca0)
+
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT31 0x80000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT31)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT30 0x40000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT30)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT29 0x20000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT29)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT28 0x10000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT28)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT27 0x08000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT27)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT26 0x04000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT26)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT25 0x02000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT25)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT24 0x01000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT24)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT23 0x00800000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT23)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT22 0x00400000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT22)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT21 0x00200000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT21)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT20 0x00100000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT20)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT19 0x00080000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT19)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT18 0x00040000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT18)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT17 0x00020000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT17)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT16 0x00010000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT16)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT15 0x00008000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT15)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT14 0x00004000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT14)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT13 0x00002000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT13)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT12 0x00001000
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT12)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT11 0x00000800
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT11)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT10 0x00000400
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT10)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT9 0x00000200
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT9)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT8 0x00000100
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT8)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT7 0x00000080
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT7)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT6 0x00000040
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT6)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT5 0x00000020
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT5)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT4 0x00000010
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT4)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT3 0x00000008
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT3)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT2 0x00000004
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT2)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT1 0x00000002
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT1)
+#define BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT0 0x00000001
+#define BF_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X1_OUT1_LUTOUT0)
+
+#define HW_PXP_WFE_A_STG2_5X1_OUT2 (0x00001cb0)
+
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT31 0x80000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT31)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT30 0x40000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT30)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT29 0x20000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT29)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT28 0x10000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT28)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT27 0x08000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT27)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT26 0x04000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT26)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT25 0x02000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT25)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT24 0x01000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT24)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT23 0x00800000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT23)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT22 0x00400000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT22)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT21 0x00200000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT21)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT20 0x00100000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT20)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT19 0x00080000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT19)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT18 0x00040000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT18)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT17 0x00020000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT17)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT16 0x00010000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT16)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT15 0x00008000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT15)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT14 0x00004000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT14)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT13 0x00002000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT13)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT12 0x00001000
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT12)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT11 0x00000800
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT11)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT10 0x00000400
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT10)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT9 0x00000200
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT9)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT8 0x00000100
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT8)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT7 0x00000080
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT7)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT6 0x00000040
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT6)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT5 0x00000020
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT5)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT4 0x00000010
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT4)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT3 0x00000008
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT3)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT2 0x00000004
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT2)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT1 0x00000002
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT1)
+#define BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT0 0x00000001
+#define BF_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X1_OUT2_LUTOUT0)
+
+#define HW_PXP_WFE_A_STG2_5X1_OUT3 (0x00001cc0)
+
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT31 0x80000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT31)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT30 0x40000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT30)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT29 0x20000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT29)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT28 0x10000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT28)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT27 0x08000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT27)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT26 0x04000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT26)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT25 0x02000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT25)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT24 0x01000000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT24)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT23 0x00800000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT23)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT22 0x00400000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT22)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT21 0x00200000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT21)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT20 0x00100000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT20)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT19 0x00080000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT19)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT18 0x00040000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT18)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT17 0x00020000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT17)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT16 0x00010000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT16)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT15 0x00008000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT15)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT14 0x00004000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT14)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT13 0x00002000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT13)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT12 0x00001000
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT12)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT11 0x00000800
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT11)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT10 0x00000400
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT10)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT9 0x00000200
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT9)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT8 0x00000100
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT8)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT7 0x00000080
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT7)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT6 0x00000040
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT6)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT5 0x00000020
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT5)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT4 0x00000010
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT4)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT3 0x00000008
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT3)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT2 0x00000004
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT2)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT1 0x00000002
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT1)
+#define BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT0 0x00000001
+#define BF_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X1_OUT3_LUTOUT0)
+
+#define HW_PXP_WFE_A_STG2_5X1_MASKS (0x00001cd0)
+
+#define BP_PXP_WFE_A_STG2_5X1_MASKS_RSVD3 29
+#define BM_PXP_WFE_A_STG2_5X1_MASKS_RSVD3 0xE0000000
+#define BF_PXP_WFE_A_STG2_5X1_MASKS_RSVD3(v) \
+ (((v) << 29) & BM_PXP_WFE_A_STG2_5X1_MASKS_RSVD3)
+#define BP_PXP_WFE_A_STG2_5X1_MASKS_MASK3 24
+#define BM_PXP_WFE_A_STG2_5X1_MASKS_MASK3 0x1F000000
+#define BF_PXP_WFE_A_STG2_5X1_MASKS_MASK3(v) \
+ (((v) << 24) & BM_PXP_WFE_A_STG2_5X1_MASKS_MASK3)
+#define BP_PXP_WFE_A_STG2_5X1_MASKS_RSVD2 21
+#define BM_PXP_WFE_A_STG2_5X1_MASKS_RSVD2 0x00E00000
+#define BF_PXP_WFE_A_STG2_5X1_MASKS_RSVD2(v) \
+ (((v) << 21) & BM_PXP_WFE_A_STG2_5X1_MASKS_RSVD2)
+#define BP_PXP_WFE_A_STG2_5X1_MASKS_MASK2 16
+#define BM_PXP_WFE_A_STG2_5X1_MASKS_MASK2 0x001F0000
+#define BF_PXP_WFE_A_STG2_5X1_MASKS_MASK2(v) \
+ (((v) << 16) & BM_PXP_WFE_A_STG2_5X1_MASKS_MASK2)
+#define BP_PXP_WFE_A_STG2_5X1_MASKS_RSVD1 13
+#define BM_PXP_WFE_A_STG2_5X1_MASKS_RSVD1 0x0000E000
+#define BF_PXP_WFE_A_STG2_5X1_MASKS_RSVD1(v) \
+ (((v) << 13) & BM_PXP_WFE_A_STG2_5X1_MASKS_RSVD1)
+#define BP_PXP_WFE_A_STG2_5X1_MASKS_MASK1 8
+#define BM_PXP_WFE_A_STG2_5X1_MASKS_MASK1 0x00001F00
+#define BF_PXP_WFE_A_STG2_5X1_MASKS_MASK1(v) \
+ (((v) << 8) & BM_PXP_WFE_A_STG2_5X1_MASKS_MASK1)
+#define BP_PXP_WFE_A_STG2_5X1_MASKS_RSVD0 5
+#define BM_PXP_WFE_A_STG2_5X1_MASKS_RSVD0 0x000000E0
+#define BF_PXP_WFE_A_STG2_5X1_MASKS_RSVD0(v) \
+ (((v) << 5) & BM_PXP_WFE_A_STG2_5X1_MASKS_RSVD0)
+#define BP_PXP_WFE_A_STG2_5X1_MASKS_MASK0 0
+#define BM_PXP_WFE_A_STG2_5X1_MASKS_MASK0 0x0000001F
+#define BF_PXP_WFE_A_STG2_5X1_MASKS_MASK0(v) \
+ (((v) << 0) & BM_PXP_WFE_A_STG2_5X1_MASKS_MASK0)
+
+#define HW_PXP_WFE_B_CTRL (0x00001d00)
+#define HW_PXP_WFE_B_CTRL_SET (0x00001d04)
+#define HW_PXP_WFE_B_CTRL_CLR (0x00001d08)
+#define HW_PXP_WFE_B_CTRL_TOG (0x00001d0c)
+
+#define BM_PXP_WFE_B_CTRL_DONE 0x80000000
+#define BF_PXP_WFE_B_CTRL_DONE(v) \
+ (((v) << 31) & BM_PXP_WFE_B_CTRL_DONE)
+#define BP_PXP_WFE_B_CTRL_RSVD0 3
+#define BM_PXP_WFE_B_CTRL_RSVD0 0x7FFFFFF8
+#define BF_PXP_WFE_B_CTRL_RSVD0(v) \
+ (((v) << 3) & BM_PXP_WFE_B_CTRL_RSVD0)
+#define BM_PXP_WFE_B_CTRL_SW_RESET 0x00000004
+#define BF_PXP_WFE_B_CTRL_SW_RESET(v) \
+ (((v) << 2) & BM_PXP_WFE_B_CTRL_SW_RESET)
+#define BM_PXP_WFE_B_CTRL_RSVD1 0x00000002
+#define BF_PXP_WFE_B_CTRL_RSVD1(v) \
+ (((v) << 1) & BM_PXP_WFE_B_CTRL_RSVD1)
+#define BM_PXP_WFE_B_CTRL_ENABLE 0x00000001
+#define BF_PXP_WFE_B_CTRL_ENABLE(v) \
+ (((v) << 0) & BM_PXP_WFE_B_CTRL_ENABLE)
+#define BV_PXP_WFE_B_CTRL_ENABLE__0 0x0
+#define BV_PXP_WFE_B_CTRL_ENABLE__1 0x1
+
+#define HW_PXP_WFE_B_DIMENSIONS (0x00001d10)
+
+#define BP_PXP_WFE_B_DIMENSIONS_RSVD0 28
+#define BM_PXP_WFE_B_DIMENSIONS_RSVD0 0xF0000000
+#define BF_PXP_WFE_B_DIMENSIONS_RSVD0(v) \
+ (((v) << 28) & BM_PXP_WFE_B_DIMENSIONS_RSVD0)
+#define BP_PXP_WFE_B_DIMENSIONS_HEIGHT 16
+#define BM_PXP_WFE_B_DIMENSIONS_HEIGHT 0x0FFF0000
+#define BF_PXP_WFE_B_DIMENSIONS_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_WFE_B_DIMENSIONS_HEIGHT)
+#define BP_PXP_WFE_B_DIMENSIONS_RSVD1 12
+#define BM_PXP_WFE_B_DIMENSIONS_RSVD1 0x0000F000
+#define BF_PXP_WFE_B_DIMENSIONS_RSVD1(v) \
+ (((v) << 12) & BM_PXP_WFE_B_DIMENSIONS_RSVD1)
+#define BP_PXP_WFE_B_DIMENSIONS_WIDTH 0
+#define BM_PXP_WFE_B_DIMENSIONS_WIDTH 0x00000FFF
+#define BF_PXP_WFE_B_DIMENSIONS_WIDTH(v) \
+ (((v) << 0) & BM_PXP_WFE_B_DIMENSIONS_WIDTH)
+
+#define HW_PXP_WFE_B_OFFSET (0x00001d20)
+
+#define BP_PXP_WFE_B_OFFSET_RSVD0 28
+#define BM_PXP_WFE_B_OFFSET_RSVD0 0xF0000000
+#define BF_PXP_WFE_B_OFFSET_RSVD0(v) \
+ (((v) << 28) & BM_PXP_WFE_B_OFFSET_RSVD0)
+#define BP_PXP_WFE_B_OFFSET_Y_OFFSET 16
+#define BM_PXP_WFE_B_OFFSET_Y_OFFSET 0x0FFF0000
+#define BF_PXP_WFE_B_OFFSET_Y_OFFSET(v) \
+ (((v) << 16) & BM_PXP_WFE_B_OFFSET_Y_OFFSET)
+#define BP_PXP_WFE_B_OFFSET_RSVD1 12
+#define BM_PXP_WFE_B_OFFSET_RSVD1 0x0000F000
+#define BF_PXP_WFE_B_OFFSET_RSVD1(v) \
+ (((v) << 12) & BM_PXP_WFE_B_OFFSET_RSVD1)
+#define BP_PXP_WFE_B_OFFSET_X_OFFSET 0
+#define BM_PXP_WFE_B_OFFSET_X_OFFSET 0x00000FFF
+#define BF_PXP_WFE_B_OFFSET_X_OFFSET(v) \
+ (((v) << 0) & BM_PXP_WFE_B_OFFSET_X_OFFSET)
+
+#define HW_PXP_WFE_B_SW_DATA_REGS (0x00001d30)
+
+#define BP_PXP_WFE_B_SW_DATA_REGS_VAL3 24
+#define BM_PXP_WFE_B_SW_DATA_REGS_VAL3 0xFF000000
+#define BF_PXP_WFE_B_SW_DATA_REGS_VAL3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_SW_DATA_REGS_VAL3)
+#define BP_PXP_WFE_B_SW_DATA_REGS_VAL2 16
+#define BM_PXP_WFE_B_SW_DATA_REGS_VAL2 0x00FF0000
+#define BF_PXP_WFE_B_SW_DATA_REGS_VAL2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_SW_DATA_REGS_VAL2)
+#define BP_PXP_WFE_B_SW_DATA_REGS_VAL1 8
+#define BM_PXP_WFE_B_SW_DATA_REGS_VAL1 0x0000FF00
+#define BF_PXP_WFE_B_SW_DATA_REGS_VAL1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_SW_DATA_REGS_VAL1)
+#define BP_PXP_WFE_B_SW_DATA_REGS_VAL0 0
+#define BM_PXP_WFE_B_SW_DATA_REGS_VAL0 0x000000FF
+#define BF_PXP_WFE_B_SW_DATA_REGS_VAL0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_SW_DATA_REGS_VAL0)
+
+#define HW_PXP_WFE_B_SW_FLAG_REGS (0x00001d40)
+
+#define BP_PXP_WFE_B_SW_FLAG_REGS_RSVD 4
+#define BM_PXP_WFE_B_SW_FLAG_REGS_RSVD 0xFFFFFFF0
+#define BF_PXP_WFE_B_SW_FLAG_REGS_RSVD(v) \
+ (((v) << 4) & BM_PXP_WFE_B_SW_FLAG_REGS_RSVD)
+#define BM_PXP_WFE_B_SW_FLAG_REGS_VAL3 0x00000008
+#define BF_PXP_WFE_B_SW_FLAG_REGS_VAL3(v) \
+ (((v) << 3) & BM_PXP_WFE_B_SW_FLAG_REGS_VAL3)
+#define BM_PXP_WFE_B_SW_FLAG_REGS_VAL2 0x00000004
+#define BF_PXP_WFE_B_SW_FLAG_REGS_VAL2(v) \
+ (((v) << 2) & BM_PXP_WFE_B_SW_FLAG_REGS_VAL2)
+#define BM_PXP_WFE_B_SW_FLAG_REGS_VAL1 0x00000002
+#define BF_PXP_WFE_B_SW_FLAG_REGS_VAL1(v) \
+ (((v) << 1) & BM_PXP_WFE_B_SW_FLAG_REGS_VAL1)
+#define BM_PXP_WFE_B_SW_FLAG_REGS_VAL0 0x00000001
+#define BF_PXP_WFE_B_SW_FLAG_REGS_VAL0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_SW_FLAG_REGS_VAL0)
+
+#define HW_PXP_WFE_B_STAGE1_MUX0 (0x00001d50)
+#define HW_PXP_WFE_B_STAGE1_MUX0_SET (0x00001d54)
+#define HW_PXP_WFE_B_STAGE1_MUX0_CLR (0x00001d58)
+#define HW_PXP_WFE_B_STAGE1_MUX0_TOG (0x00001d5c)
+
+#define BP_PXP_WFE_B_STAGE1_MUX0_RSVD0 30
+#define BM_PXP_WFE_B_STAGE1_MUX0_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE1_MUX0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE1_MUX0_RSVD0)
+#define BP_PXP_WFE_B_STAGE1_MUX0_MUX3 24
+#define BM_PXP_WFE_B_STAGE1_MUX0_MUX3 0x3F000000
+#define BF_PXP_WFE_B_STAGE1_MUX0_MUX3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE1_MUX0_MUX3)
+#define BP_PXP_WFE_B_STAGE1_MUX0_RSVD1 22
+#define BM_PXP_WFE_B_STAGE1_MUX0_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE1_MUX0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE1_MUX0_RSVD1)
+#define BP_PXP_WFE_B_STAGE1_MUX0_MUX2 16
+#define BM_PXP_WFE_B_STAGE1_MUX0_MUX2 0x003F0000
+#define BF_PXP_WFE_B_STAGE1_MUX0_MUX2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE1_MUX0_MUX2)
+#define BP_PXP_WFE_B_STAGE1_MUX0_RSVD2 14
+#define BM_PXP_WFE_B_STAGE1_MUX0_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE1_MUX0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE1_MUX0_RSVD2)
+#define BP_PXP_WFE_B_STAGE1_MUX0_MUX1 8
+#define BM_PXP_WFE_B_STAGE1_MUX0_MUX1 0x00003F00
+#define BF_PXP_WFE_B_STAGE1_MUX0_MUX1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE1_MUX0_MUX1)
+#define BP_PXP_WFE_B_STAGE1_MUX0_RSVD3 6
+#define BM_PXP_WFE_B_STAGE1_MUX0_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE1_MUX0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE1_MUX0_RSVD3)
+#define BP_PXP_WFE_B_STAGE1_MUX0_MUX0 0
+#define BM_PXP_WFE_B_STAGE1_MUX0_MUX0 0x0000003F
+#define BF_PXP_WFE_B_STAGE1_MUX0_MUX0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE1_MUX0_MUX0)
+
+#define HW_PXP_WFE_B_STAGE1_MUX1 (0x00001d60)
+#define HW_PXP_WFE_B_STAGE1_MUX1_SET (0x00001d64)
+#define HW_PXP_WFE_B_STAGE1_MUX1_CLR (0x00001d68)
+#define HW_PXP_WFE_B_STAGE1_MUX1_TOG (0x00001d6c)
+
+#define BP_PXP_WFE_B_STAGE1_MUX1_RSVD0 30
+#define BM_PXP_WFE_B_STAGE1_MUX1_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE1_MUX1_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE1_MUX1_RSVD0)
+#define BP_PXP_WFE_B_STAGE1_MUX1_MUX7 24
+#define BM_PXP_WFE_B_STAGE1_MUX1_MUX7 0x3F000000
+#define BF_PXP_WFE_B_STAGE1_MUX1_MUX7(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE1_MUX1_MUX7)
+#define BP_PXP_WFE_B_STAGE1_MUX1_RSVD1 22
+#define BM_PXP_WFE_B_STAGE1_MUX1_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE1_MUX1_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE1_MUX1_RSVD1)
+#define BP_PXP_WFE_B_STAGE1_MUX1_MUX6 16
+#define BM_PXP_WFE_B_STAGE1_MUX1_MUX6 0x003F0000
+#define BF_PXP_WFE_B_STAGE1_MUX1_MUX6(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE1_MUX1_MUX6)
+#define BP_PXP_WFE_B_STAGE1_MUX1_RSVD2 14
+#define BM_PXP_WFE_B_STAGE1_MUX1_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE1_MUX1_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE1_MUX1_RSVD2)
+#define BP_PXP_WFE_B_STAGE1_MUX1_MUX5 8
+#define BM_PXP_WFE_B_STAGE1_MUX1_MUX5 0x00003F00
+#define BF_PXP_WFE_B_STAGE1_MUX1_MUX5(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE1_MUX1_MUX5)
+#define BP_PXP_WFE_B_STAGE1_MUX1_RSVD3 6
+#define BM_PXP_WFE_B_STAGE1_MUX1_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE1_MUX1_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE1_MUX1_RSVD3)
+#define BP_PXP_WFE_B_STAGE1_MUX1_MUX4 0
+#define BM_PXP_WFE_B_STAGE1_MUX1_MUX4 0x0000003F
+#define BF_PXP_WFE_B_STAGE1_MUX1_MUX4(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE1_MUX1_MUX4)
+
+#define HW_PXP_WFE_B_STAGE1_MUX2 (0x00001d70)
+#define HW_PXP_WFE_B_STAGE1_MUX2_SET (0x00001d74)
+#define HW_PXP_WFE_B_STAGE1_MUX2_CLR (0x00001d78)
+#define HW_PXP_WFE_B_STAGE1_MUX2_TOG (0x00001d7c)
+
+#define BP_PXP_WFE_B_STAGE1_MUX2_RSVD0 30
+#define BM_PXP_WFE_B_STAGE1_MUX2_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE1_MUX2_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE1_MUX2_RSVD0)
+#define BP_PXP_WFE_B_STAGE1_MUX2_MUX11 24
+#define BM_PXP_WFE_B_STAGE1_MUX2_MUX11 0x3F000000
+#define BF_PXP_WFE_B_STAGE1_MUX2_MUX11(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE1_MUX2_MUX11)
+#define BP_PXP_WFE_B_STAGE1_MUX2_RSVD1 22
+#define BM_PXP_WFE_B_STAGE1_MUX2_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE1_MUX2_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE1_MUX2_RSVD1)
+#define BP_PXP_WFE_B_STAGE1_MUX2_MUX10 16
+#define BM_PXP_WFE_B_STAGE1_MUX2_MUX10 0x003F0000
+#define BF_PXP_WFE_B_STAGE1_MUX2_MUX10(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE1_MUX2_MUX10)
+#define BP_PXP_WFE_B_STAGE1_MUX2_RSVD2 14
+#define BM_PXP_WFE_B_STAGE1_MUX2_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE1_MUX2_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE1_MUX2_RSVD2)
+#define BP_PXP_WFE_B_STAGE1_MUX2_MUX9 8
+#define BM_PXP_WFE_B_STAGE1_MUX2_MUX9 0x00003F00
+#define BF_PXP_WFE_B_STAGE1_MUX2_MUX9(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE1_MUX2_MUX9)
+#define BP_PXP_WFE_B_STAGE1_MUX2_RSVD3 6
+#define BM_PXP_WFE_B_STAGE1_MUX2_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE1_MUX2_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE1_MUX2_RSVD3)
+#define BP_PXP_WFE_B_STAGE1_MUX2_MUX8 0
+#define BM_PXP_WFE_B_STAGE1_MUX2_MUX8 0x0000003F
+#define BF_PXP_WFE_B_STAGE1_MUX2_MUX8(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE1_MUX2_MUX8)
+
+#define HW_PXP_WFE_B_STAGE1_MUX3 (0x00001d80)
+#define HW_PXP_WFE_B_STAGE1_MUX3_SET (0x00001d84)
+#define HW_PXP_WFE_B_STAGE1_MUX3_CLR (0x00001d88)
+#define HW_PXP_WFE_B_STAGE1_MUX3_TOG (0x00001d8c)
+
+#define BP_PXP_WFE_B_STAGE1_MUX3_RSVD0 30
+#define BM_PXP_WFE_B_STAGE1_MUX3_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE1_MUX3_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE1_MUX3_RSVD0)
+#define BP_PXP_WFE_B_STAGE1_MUX3_MUX15 24
+#define BM_PXP_WFE_B_STAGE1_MUX3_MUX15 0x3F000000
+#define BF_PXP_WFE_B_STAGE1_MUX3_MUX15(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE1_MUX3_MUX15)
+#define BP_PXP_WFE_B_STAGE1_MUX3_RSVD1 22
+#define BM_PXP_WFE_B_STAGE1_MUX3_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE1_MUX3_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE1_MUX3_RSVD1)
+#define BP_PXP_WFE_B_STAGE1_MUX3_MUX14 16
+#define BM_PXP_WFE_B_STAGE1_MUX3_MUX14 0x003F0000
+#define BF_PXP_WFE_B_STAGE1_MUX3_MUX14(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE1_MUX3_MUX14)
+#define BP_PXP_WFE_B_STAGE1_MUX3_RSVD2 14
+#define BM_PXP_WFE_B_STAGE1_MUX3_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE1_MUX3_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE1_MUX3_RSVD2)
+#define BP_PXP_WFE_B_STAGE1_MUX3_MUX13 8
+#define BM_PXP_WFE_B_STAGE1_MUX3_MUX13 0x00003F00
+#define BF_PXP_WFE_B_STAGE1_MUX3_MUX13(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE1_MUX3_MUX13)
+#define BP_PXP_WFE_B_STAGE1_MUX3_RSVD3 6
+#define BM_PXP_WFE_B_STAGE1_MUX3_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE1_MUX3_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE1_MUX3_RSVD3)
+#define BP_PXP_WFE_B_STAGE1_MUX3_MUX12 0
+#define BM_PXP_WFE_B_STAGE1_MUX3_MUX12 0x0000003F
+#define BF_PXP_WFE_B_STAGE1_MUX3_MUX12(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE1_MUX3_MUX12)
+
+#define HW_PXP_WFE_B_STAGE1_MUX4 (0x00001d90)
+#define HW_PXP_WFE_B_STAGE1_MUX4_SET (0x00001d94)
+#define HW_PXP_WFE_B_STAGE1_MUX4_CLR (0x00001d98)
+#define HW_PXP_WFE_B_STAGE1_MUX4_TOG (0x00001d9c)
+
+#define BP_PXP_WFE_B_STAGE1_MUX4_RSVD0 30
+#define BM_PXP_WFE_B_STAGE1_MUX4_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE1_MUX4_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE1_MUX4_RSVD0)
+#define BP_PXP_WFE_B_STAGE1_MUX4_MUX19 24
+#define BM_PXP_WFE_B_STAGE1_MUX4_MUX19 0x3F000000
+#define BF_PXP_WFE_B_STAGE1_MUX4_MUX19(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE1_MUX4_MUX19)
+#define BP_PXP_WFE_B_STAGE1_MUX4_RSVD1 22
+#define BM_PXP_WFE_B_STAGE1_MUX4_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE1_MUX4_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE1_MUX4_RSVD1)
+#define BP_PXP_WFE_B_STAGE1_MUX4_MUX18 16
+#define BM_PXP_WFE_B_STAGE1_MUX4_MUX18 0x003F0000
+#define BF_PXP_WFE_B_STAGE1_MUX4_MUX18(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE1_MUX4_MUX18)
+#define BP_PXP_WFE_B_STAGE1_MUX4_RSVD2 14
+#define BM_PXP_WFE_B_STAGE1_MUX4_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE1_MUX4_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE1_MUX4_RSVD2)
+#define BP_PXP_WFE_B_STAGE1_MUX4_MUX17 8
+#define BM_PXP_WFE_B_STAGE1_MUX4_MUX17 0x00003F00
+#define BF_PXP_WFE_B_STAGE1_MUX4_MUX17(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE1_MUX4_MUX17)
+#define BP_PXP_WFE_B_STAGE1_MUX4_RSVD3 6
+#define BM_PXP_WFE_B_STAGE1_MUX4_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE1_MUX4_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE1_MUX4_RSVD3)
+#define BP_PXP_WFE_B_STAGE1_MUX4_MUX16 0
+#define BM_PXP_WFE_B_STAGE1_MUX4_MUX16 0x0000003F
+#define BF_PXP_WFE_B_STAGE1_MUX4_MUX16(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE1_MUX4_MUX16)
+
+#define HW_PXP_WFE_B_STAGE1_MUX5 (0x00001da0)
+#define HW_PXP_WFE_B_STAGE1_MUX5_SET (0x00001da4)
+#define HW_PXP_WFE_B_STAGE1_MUX5_CLR (0x00001da8)
+#define HW_PXP_WFE_B_STAGE1_MUX5_TOG (0x00001dac)
+
+#define BP_PXP_WFE_B_STAGE1_MUX5_RSVD0 30
+#define BM_PXP_WFE_B_STAGE1_MUX5_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE1_MUX5_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE1_MUX5_RSVD0)
+#define BP_PXP_WFE_B_STAGE1_MUX5_MUX23 24
+#define BM_PXP_WFE_B_STAGE1_MUX5_MUX23 0x3F000000
+#define BF_PXP_WFE_B_STAGE1_MUX5_MUX23(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE1_MUX5_MUX23)
+#define BP_PXP_WFE_B_STAGE1_MUX5_RSVD1 22
+#define BM_PXP_WFE_B_STAGE1_MUX5_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE1_MUX5_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE1_MUX5_RSVD1)
+#define BP_PXP_WFE_B_STAGE1_MUX5_MUX22 16
+#define BM_PXP_WFE_B_STAGE1_MUX5_MUX22 0x003F0000
+#define BF_PXP_WFE_B_STAGE1_MUX5_MUX22(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE1_MUX5_MUX22)
+#define BP_PXP_WFE_B_STAGE1_MUX5_RSVD2 14
+#define BM_PXP_WFE_B_STAGE1_MUX5_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE1_MUX5_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE1_MUX5_RSVD2)
+#define BP_PXP_WFE_B_STAGE1_MUX5_MUX21 8
+#define BM_PXP_WFE_B_STAGE1_MUX5_MUX21 0x00003F00
+#define BF_PXP_WFE_B_STAGE1_MUX5_MUX21(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE1_MUX5_MUX21)
+#define BP_PXP_WFE_B_STAGE1_MUX5_RSVD3 6
+#define BM_PXP_WFE_B_STAGE1_MUX5_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE1_MUX5_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE1_MUX5_RSVD3)
+#define BP_PXP_WFE_B_STAGE1_MUX5_MUX20 0
+#define BM_PXP_WFE_B_STAGE1_MUX5_MUX20 0x0000003F
+#define BF_PXP_WFE_B_STAGE1_MUX5_MUX20(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE1_MUX5_MUX20)
+#define BV_PXP_WFE_B_STAGE1_MUX5_MUX20__INC 0x0
+#define BV_PXP_WFE_B_STAGE1_MUX5_MUX20__DEC 0x1
+#define BV_PXP_WFE_B_STAGE1_MUX5_MUX20__ADD 0x2
+#define BV_PXP_WFE_B_STAGE1_MUX5_MUX20__MINUS 0x3
+#define BV_PXP_WFE_B_STAGE1_MUX5_MUX20__AND 0x4
+#define BV_PXP_WFE_B_STAGE1_MUX5_MUX20__OR 0x5
+#define BV_PXP_WFE_B_STAGE1_MUX5_MUX20__XOR 0x6
+#define BV_PXP_WFE_B_STAGE1_MUX5_MUX20__SHIFTLEFT 0x7
+#define BV_PXP_WFE_B_STAGE1_MUX5_MUX20__SHIFTRIGHT 0x8
+#define BV_PXP_WFE_B_STAGE1_MUX5_MUX20__BIT_AND 0x9
+#define BV_PXP_WFE_B_STAGE1_MUX5_MUX20__BIT_OR 0xa
+#define BV_PXP_WFE_B_STAGE1_MUX5_MUX20__BIT_CMP 0xb
+#define BV_PXP_WFE_B_STAGE1_MUX5_MUX20__NOP 0xc
+
+#define HW_PXP_WFE_B_STAGE1_MUX6 (0x00001db0)
+#define HW_PXP_WFE_B_STAGE1_MUX6_SET (0x00001db4)
+#define HW_PXP_WFE_B_STAGE1_MUX6_CLR (0x00001db8)
+#define HW_PXP_WFE_B_STAGE1_MUX6_TOG (0x00001dbc)
+
+#define BP_PXP_WFE_B_STAGE1_MUX6_RSVD0 30
+#define BM_PXP_WFE_B_STAGE1_MUX6_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE1_MUX6_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE1_MUX6_RSVD0)
+#define BP_PXP_WFE_B_STAGE1_MUX6_MUX27 24
+#define BM_PXP_WFE_B_STAGE1_MUX6_MUX27 0x3F000000
+#define BF_PXP_WFE_B_STAGE1_MUX6_MUX27(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE1_MUX6_MUX27)
+#define BP_PXP_WFE_B_STAGE1_MUX6_RSVD1 22
+#define BM_PXP_WFE_B_STAGE1_MUX6_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE1_MUX6_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE1_MUX6_RSVD1)
+#define BP_PXP_WFE_B_STAGE1_MUX6_MUX26 16
+#define BM_PXP_WFE_B_STAGE1_MUX6_MUX26 0x003F0000
+#define BF_PXP_WFE_B_STAGE1_MUX6_MUX26(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE1_MUX6_MUX26)
+#define BP_PXP_WFE_B_STAGE1_MUX6_RSVD2 14
+#define BM_PXP_WFE_B_STAGE1_MUX6_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE1_MUX6_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE1_MUX6_RSVD2)
+#define BP_PXP_WFE_B_STAGE1_MUX6_MUX25 8
+#define BM_PXP_WFE_B_STAGE1_MUX6_MUX25 0x00003F00
+#define BF_PXP_WFE_B_STAGE1_MUX6_MUX25(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE1_MUX6_MUX25)
+#define BP_PXP_WFE_B_STAGE1_MUX6_RSVD3 6
+#define BM_PXP_WFE_B_STAGE1_MUX6_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE1_MUX6_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE1_MUX6_RSVD3)
+#define BP_PXP_WFE_B_STAGE1_MUX6_MUX24 0
+#define BM_PXP_WFE_B_STAGE1_MUX6_MUX24 0x0000003F
+#define BF_PXP_WFE_B_STAGE1_MUX6_MUX24(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE1_MUX6_MUX24)
+
+#define HW_PXP_WFE_B_STAGE1_MUX7 (0x00001dc0)
+#define HW_PXP_WFE_B_STAGE1_MUX7_SET (0x00001dc4)
+#define HW_PXP_WFE_B_STAGE1_MUX7_CLR (0x00001dc8)
+#define HW_PXP_WFE_B_STAGE1_MUX7_TOG (0x00001dcc)
+
+#define BP_PXP_WFE_B_STAGE1_MUX7_RSVD0 30
+#define BM_PXP_WFE_B_STAGE1_MUX7_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE1_MUX7_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE1_MUX7_RSVD0)
+#define BP_PXP_WFE_B_STAGE1_MUX7_MUX31 24
+#define BM_PXP_WFE_B_STAGE1_MUX7_MUX31 0x3F000000
+#define BF_PXP_WFE_B_STAGE1_MUX7_MUX31(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE1_MUX7_MUX31)
+#define BP_PXP_WFE_B_STAGE1_MUX7_RSVD1 22
+#define BM_PXP_WFE_B_STAGE1_MUX7_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE1_MUX7_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE1_MUX7_RSVD1)
+#define BP_PXP_WFE_B_STAGE1_MUX7_MUX30 16
+#define BM_PXP_WFE_B_STAGE1_MUX7_MUX30 0x003F0000
+#define BF_PXP_WFE_B_STAGE1_MUX7_MUX30(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE1_MUX7_MUX30)
+#define BP_PXP_WFE_B_STAGE1_MUX7_RSVD2 14
+#define BM_PXP_WFE_B_STAGE1_MUX7_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE1_MUX7_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE1_MUX7_RSVD2)
+#define BP_PXP_WFE_B_STAGE1_MUX7_MUX29 8
+#define BM_PXP_WFE_B_STAGE1_MUX7_MUX29 0x00003F00
+#define BF_PXP_WFE_B_STAGE1_MUX7_MUX29(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE1_MUX7_MUX29)
+#define BP_PXP_WFE_B_STAGE1_MUX7_RSVD3 6
+#define BM_PXP_WFE_B_STAGE1_MUX7_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE1_MUX7_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE1_MUX7_RSVD3)
+#define BP_PXP_WFE_B_STAGE1_MUX7_MUX28 0
+#define BM_PXP_WFE_B_STAGE1_MUX7_MUX28 0x0000003F
+#define BF_PXP_WFE_B_STAGE1_MUX7_MUX28(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE1_MUX7_MUX28)
+
+#define HW_PXP_WFE_B_STAGE1_MUX8 (0x00001dd0)
+#define HW_PXP_WFE_B_STAGE1_MUX8_SET (0x00001dd4)
+#define HW_PXP_WFE_B_STAGE1_MUX8_CLR (0x00001dd8)
+#define HW_PXP_WFE_B_STAGE1_MUX8_TOG (0x00001ddc)
+
+#define BP_PXP_WFE_B_STAGE1_MUX8_RSVD0 6
+#define BM_PXP_WFE_B_STAGE1_MUX8_RSVD0 0xFFFFFFC0
+#define BF_PXP_WFE_B_STAGE1_MUX8_RSVD0(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE1_MUX8_RSVD0)
+#define BP_PXP_WFE_B_STAGE1_MUX8_MUX32 0
+#define BM_PXP_WFE_B_STAGE1_MUX8_MUX32 0x0000003F
+#define BF_PXP_WFE_B_STAGE1_MUX8_MUX32(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE1_MUX8_MUX32)
+
+#define HW_PXP_WFE_B_STAGE2_MUX0 (0x00001de0)
+#define HW_PXP_WFE_B_STAGE2_MUX0_SET (0x00001de4)
+#define HW_PXP_WFE_B_STAGE2_MUX0_CLR (0x00001de8)
+#define HW_PXP_WFE_B_STAGE2_MUX0_TOG (0x00001dec)
+
+#define BP_PXP_WFE_B_STAGE2_MUX0_RSVD0 30
+#define BM_PXP_WFE_B_STAGE2_MUX0_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE2_MUX0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE2_MUX0_RSVD0)
+#define BP_PXP_WFE_B_STAGE2_MUX0_MUX3 24
+#define BM_PXP_WFE_B_STAGE2_MUX0_MUX3 0x3F000000
+#define BF_PXP_WFE_B_STAGE2_MUX0_MUX3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE2_MUX0_MUX3)
+#define BP_PXP_WFE_B_STAGE2_MUX0_RSVD1 22
+#define BM_PXP_WFE_B_STAGE2_MUX0_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE2_MUX0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE2_MUX0_RSVD1)
+#define BP_PXP_WFE_B_STAGE2_MUX0_MUX2 16
+#define BM_PXP_WFE_B_STAGE2_MUX0_MUX2 0x003F0000
+#define BF_PXP_WFE_B_STAGE2_MUX0_MUX2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE2_MUX0_MUX2)
+#define BP_PXP_WFE_B_STAGE2_MUX0_RSVD2 14
+#define BM_PXP_WFE_B_STAGE2_MUX0_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE2_MUX0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE2_MUX0_RSVD2)
+#define BP_PXP_WFE_B_STAGE2_MUX0_MUX1 8
+#define BM_PXP_WFE_B_STAGE2_MUX0_MUX1 0x00003F00
+#define BF_PXP_WFE_B_STAGE2_MUX0_MUX1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE2_MUX0_MUX1)
+#define BP_PXP_WFE_B_STAGE2_MUX0_RSVD3 6
+#define BM_PXP_WFE_B_STAGE2_MUX0_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE2_MUX0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE2_MUX0_RSVD3)
+#define BP_PXP_WFE_B_STAGE2_MUX0_MUX0 0
+#define BM_PXP_WFE_B_STAGE2_MUX0_MUX0 0x0000003F
+#define BF_PXP_WFE_B_STAGE2_MUX0_MUX0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE2_MUX0_MUX0)
+
+#define HW_PXP_WFE_B_STAGE2_MUX1 (0x00001df0)
+#define HW_PXP_WFE_B_STAGE2_MUX1_SET (0x00001df4)
+#define HW_PXP_WFE_B_STAGE2_MUX1_CLR (0x00001df8)
+#define HW_PXP_WFE_B_STAGE2_MUX1_TOG (0x00001dfc)
+
+#define BP_PXP_WFE_B_STAGE2_MUX1_RSVD0 30
+#define BM_PXP_WFE_B_STAGE2_MUX1_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE2_MUX1_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE2_MUX1_RSVD0)
+#define BP_PXP_WFE_B_STAGE2_MUX1_MUX7 24
+#define BM_PXP_WFE_B_STAGE2_MUX1_MUX7 0x3F000000
+#define BF_PXP_WFE_B_STAGE2_MUX1_MUX7(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE2_MUX1_MUX7)
+#define BP_PXP_WFE_B_STAGE2_MUX1_RSVD1 22
+#define BM_PXP_WFE_B_STAGE2_MUX1_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE2_MUX1_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE2_MUX1_RSVD1)
+#define BP_PXP_WFE_B_STAGE2_MUX1_MUX6 16
+#define BM_PXP_WFE_B_STAGE2_MUX1_MUX6 0x003F0000
+#define BF_PXP_WFE_B_STAGE2_MUX1_MUX6(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE2_MUX1_MUX6)
+#define BP_PXP_WFE_B_STAGE2_MUX1_RSVD2 14
+#define BM_PXP_WFE_B_STAGE2_MUX1_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE2_MUX1_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE2_MUX1_RSVD2)
+#define BP_PXP_WFE_B_STAGE2_MUX1_MUX5 8
+#define BM_PXP_WFE_B_STAGE2_MUX1_MUX5 0x00003F00
+#define BF_PXP_WFE_B_STAGE2_MUX1_MUX5(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE2_MUX1_MUX5)
+#define BP_PXP_WFE_B_STAGE2_MUX1_RSVD3 6
+#define BM_PXP_WFE_B_STAGE2_MUX1_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE2_MUX1_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE2_MUX1_RSVD3)
+#define BP_PXP_WFE_B_STAGE2_MUX1_MUX4 0
+#define BM_PXP_WFE_B_STAGE2_MUX1_MUX4 0x0000003F
+#define BF_PXP_WFE_B_STAGE2_MUX1_MUX4(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE2_MUX1_MUX4)
+
+#define HW_PXP_WFE_B_STAGE2_MUX2 (0x00001e00)
+#define HW_PXP_WFE_B_STAGE2_MUX2_SET (0x00001e04)
+#define HW_PXP_WFE_B_STAGE2_MUX2_CLR (0x00001e08)
+#define HW_PXP_WFE_B_STAGE2_MUX2_TOG (0x00001e0c)
+
+#define BP_PXP_WFE_B_STAGE2_MUX2_RSVD0 30
+#define BM_PXP_WFE_B_STAGE2_MUX2_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE2_MUX2_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE2_MUX2_RSVD0)
+#define BP_PXP_WFE_B_STAGE2_MUX2_MUX11 24
+#define BM_PXP_WFE_B_STAGE2_MUX2_MUX11 0x3F000000
+#define BF_PXP_WFE_B_STAGE2_MUX2_MUX11(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE2_MUX2_MUX11)
+#define BP_PXP_WFE_B_STAGE2_MUX2_RSVD1 22
+#define BM_PXP_WFE_B_STAGE2_MUX2_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE2_MUX2_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE2_MUX2_RSVD1)
+#define BP_PXP_WFE_B_STAGE2_MUX2_MUX10 16
+#define BM_PXP_WFE_B_STAGE2_MUX2_MUX10 0x003F0000
+#define BF_PXP_WFE_B_STAGE2_MUX2_MUX10(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE2_MUX2_MUX10)
+#define BP_PXP_WFE_B_STAGE2_MUX2_RSVD2 14
+#define BM_PXP_WFE_B_STAGE2_MUX2_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE2_MUX2_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE2_MUX2_RSVD2)
+#define BP_PXP_WFE_B_STAGE2_MUX2_MUX9 8
+#define BM_PXP_WFE_B_STAGE2_MUX2_MUX9 0x00003F00
+#define BF_PXP_WFE_B_STAGE2_MUX2_MUX9(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE2_MUX2_MUX9)
+#define BP_PXP_WFE_B_STAGE2_MUX2_RSVD3 6
+#define BM_PXP_WFE_B_STAGE2_MUX2_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE2_MUX2_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE2_MUX2_RSVD3)
+#define BP_PXP_WFE_B_STAGE2_MUX2_MUX8 0
+#define BM_PXP_WFE_B_STAGE2_MUX2_MUX8 0x0000003F
+#define BF_PXP_WFE_B_STAGE2_MUX2_MUX8(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE2_MUX2_MUX8)
+
+#define HW_PXP_WFE_B_STAGE2_MUX3 (0x00001e10)
+#define HW_PXP_WFE_B_STAGE2_MUX3_SET (0x00001e14)
+#define HW_PXP_WFE_B_STAGE2_MUX3_CLR (0x00001e18)
+#define HW_PXP_WFE_B_STAGE2_MUX3_TOG (0x00001e1c)
+
+#define BP_PXP_WFE_B_STAGE2_MUX3_RSVD0 30
+#define BM_PXP_WFE_B_STAGE2_MUX3_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE2_MUX3_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE2_MUX3_RSVD0)
+#define BP_PXP_WFE_B_STAGE2_MUX3_MUX15 24
+#define BM_PXP_WFE_B_STAGE2_MUX3_MUX15 0x3F000000
+#define BF_PXP_WFE_B_STAGE2_MUX3_MUX15(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE2_MUX3_MUX15)
+#define BP_PXP_WFE_B_STAGE2_MUX3_RSVD1 22
+#define BM_PXP_WFE_B_STAGE2_MUX3_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE2_MUX3_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE2_MUX3_RSVD1)
+#define BP_PXP_WFE_B_STAGE2_MUX3_MUX14 16
+#define BM_PXP_WFE_B_STAGE2_MUX3_MUX14 0x003F0000
+#define BF_PXP_WFE_B_STAGE2_MUX3_MUX14(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE2_MUX3_MUX14)
+#define BP_PXP_WFE_B_STAGE2_MUX3_RSVD2 14
+#define BM_PXP_WFE_B_STAGE2_MUX3_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE2_MUX3_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE2_MUX3_RSVD2)
+#define BP_PXP_WFE_B_STAGE2_MUX3_MUX13 8
+#define BM_PXP_WFE_B_STAGE2_MUX3_MUX13 0x00003F00
+#define BF_PXP_WFE_B_STAGE2_MUX3_MUX13(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE2_MUX3_MUX13)
+#define BP_PXP_WFE_B_STAGE2_MUX3_RSVD3 6
+#define BM_PXP_WFE_B_STAGE2_MUX3_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE2_MUX3_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE2_MUX3_RSVD3)
+#define BP_PXP_WFE_B_STAGE2_MUX3_MUX12 0
+#define BM_PXP_WFE_B_STAGE2_MUX3_MUX12 0x0000003F
+#define BF_PXP_WFE_B_STAGE2_MUX3_MUX12(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE2_MUX3_MUX12)
+
+#define HW_PXP_WFE_B_STAGE2_MUX4 (0x00001e20)
+#define HW_PXP_WFE_B_STAGE2_MUX4_SET (0x00001e24)
+#define HW_PXP_WFE_B_STAGE2_MUX4_CLR (0x00001e28)
+#define HW_PXP_WFE_B_STAGE2_MUX4_TOG (0x00001e2c)
+
+#define BP_PXP_WFE_B_STAGE2_MUX4_RSVD0 30
+#define BM_PXP_WFE_B_STAGE2_MUX4_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE2_MUX4_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE2_MUX4_RSVD0)
+#define BP_PXP_WFE_B_STAGE2_MUX4_MUX19 24
+#define BM_PXP_WFE_B_STAGE2_MUX4_MUX19 0x3F000000
+#define BF_PXP_WFE_B_STAGE2_MUX4_MUX19(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE2_MUX4_MUX19)
+#define BP_PXP_WFE_B_STAGE2_MUX4_RSVD1 22
+#define BM_PXP_WFE_B_STAGE2_MUX4_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE2_MUX4_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE2_MUX4_RSVD1)
+#define BP_PXP_WFE_B_STAGE2_MUX4_MUX18 16
+#define BM_PXP_WFE_B_STAGE2_MUX4_MUX18 0x003F0000
+#define BF_PXP_WFE_B_STAGE2_MUX4_MUX18(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE2_MUX4_MUX18)
+#define BP_PXP_WFE_B_STAGE2_MUX4_RSVD2 14
+#define BM_PXP_WFE_B_STAGE2_MUX4_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE2_MUX4_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE2_MUX4_RSVD2)
+#define BP_PXP_WFE_B_STAGE2_MUX4_MUX17 8
+#define BM_PXP_WFE_B_STAGE2_MUX4_MUX17 0x00003F00
+#define BF_PXP_WFE_B_STAGE2_MUX4_MUX17(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE2_MUX4_MUX17)
+#define BP_PXP_WFE_B_STAGE2_MUX4_RSVD3 6
+#define BM_PXP_WFE_B_STAGE2_MUX4_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE2_MUX4_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE2_MUX4_RSVD3)
+#define BP_PXP_WFE_B_STAGE2_MUX4_MUX16 0
+#define BM_PXP_WFE_B_STAGE2_MUX4_MUX16 0x0000003F
+#define BF_PXP_WFE_B_STAGE2_MUX4_MUX16(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE2_MUX4_MUX16)
+
+#define HW_PXP_WFE_B_STAGE2_MUX5 (0x00001e30)
+#define HW_PXP_WFE_B_STAGE2_MUX5_SET (0x00001e34)
+#define HW_PXP_WFE_B_STAGE2_MUX5_CLR (0x00001e38)
+#define HW_PXP_WFE_B_STAGE2_MUX5_TOG (0x00001e3c)
+
+#define BP_PXP_WFE_B_STAGE2_MUX5_RSVD0 30
+#define BM_PXP_WFE_B_STAGE2_MUX5_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE2_MUX5_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE2_MUX5_RSVD0)
+#define BP_PXP_WFE_B_STAGE2_MUX5_MUX23 24
+#define BM_PXP_WFE_B_STAGE2_MUX5_MUX23 0x3F000000
+#define BF_PXP_WFE_B_STAGE2_MUX5_MUX23(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE2_MUX5_MUX23)
+#define BP_PXP_WFE_B_STAGE2_MUX5_RSVD1 22
+#define BM_PXP_WFE_B_STAGE2_MUX5_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE2_MUX5_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE2_MUX5_RSVD1)
+#define BP_PXP_WFE_B_STAGE2_MUX5_MUX22 16
+#define BM_PXP_WFE_B_STAGE2_MUX5_MUX22 0x003F0000
+#define BF_PXP_WFE_B_STAGE2_MUX5_MUX22(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE2_MUX5_MUX22)
+#define BP_PXP_WFE_B_STAGE2_MUX5_RSVD2 14
+#define BM_PXP_WFE_B_STAGE2_MUX5_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE2_MUX5_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE2_MUX5_RSVD2)
+#define BP_PXP_WFE_B_STAGE2_MUX5_MUX21 8
+#define BM_PXP_WFE_B_STAGE2_MUX5_MUX21 0x00003F00
+#define BF_PXP_WFE_B_STAGE2_MUX5_MUX21(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE2_MUX5_MUX21)
+#define BP_PXP_WFE_B_STAGE2_MUX5_RSVD3 6
+#define BM_PXP_WFE_B_STAGE2_MUX5_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE2_MUX5_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE2_MUX5_RSVD3)
+#define BP_PXP_WFE_B_STAGE2_MUX5_MUX20 0
+#define BM_PXP_WFE_B_STAGE2_MUX5_MUX20 0x0000003F
+#define BF_PXP_WFE_B_STAGE2_MUX5_MUX20(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE2_MUX5_MUX20)
+
+#define HW_PXP_WFE_B_STAGE2_MUX6 (0x00001e40)
+#define HW_PXP_WFE_B_STAGE2_MUX6_SET (0x00001e44)
+#define HW_PXP_WFE_B_STAGE2_MUX6_CLR (0x00001e48)
+#define HW_PXP_WFE_B_STAGE2_MUX6_TOG (0x00001e4c)
+
+#define BP_PXP_WFE_B_STAGE2_MUX6_RSVD0 30
+#define BM_PXP_WFE_B_STAGE2_MUX6_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE2_MUX6_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE2_MUX6_RSVD0)
+#define BP_PXP_WFE_B_STAGE2_MUX6_MUX27 24
+#define BM_PXP_WFE_B_STAGE2_MUX6_MUX27 0x3F000000
+#define BF_PXP_WFE_B_STAGE2_MUX6_MUX27(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE2_MUX6_MUX27)
+#define BP_PXP_WFE_B_STAGE2_MUX6_RSVD1 22
+#define BM_PXP_WFE_B_STAGE2_MUX6_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE2_MUX6_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE2_MUX6_RSVD1)
+#define BP_PXP_WFE_B_STAGE2_MUX6_MUX26 16
+#define BM_PXP_WFE_B_STAGE2_MUX6_MUX26 0x003F0000
+#define BF_PXP_WFE_B_STAGE2_MUX6_MUX26(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE2_MUX6_MUX26)
+#define BP_PXP_WFE_B_STAGE2_MUX6_RSVD2 14
+#define BM_PXP_WFE_B_STAGE2_MUX6_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE2_MUX6_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE2_MUX6_RSVD2)
+#define BP_PXP_WFE_B_STAGE2_MUX6_MUX25 8
+#define BM_PXP_WFE_B_STAGE2_MUX6_MUX25 0x00003F00
+#define BF_PXP_WFE_B_STAGE2_MUX6_MUX25(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE2_MUX6_MUX25)
+#define BP_PXP_WFE_B_STAGE2_MUX6_RSVD3 6
+#define BM_PXP_WFE_B_STAGE2_MUX6_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE2_MUX6_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE2_MUX6_RSVD3)
+#define BP_PXP_WFE_B_STAGE2_MUX6_MUX24 0
+#define BM_PXP_WFE_B_STAGE2_MUX6_MUX24 0x0000003F
+#define BF_PXP_WFE_B_STAGE2_MUX6_MUX24(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE2_MUX6_MUX24)
+
+#define HW_PXP_WFE_B_STAGE2_MUX7 (0x00001e50)
+#define HW_PXP_WFE_B_STAGE2_MUX7_SET (0x00001e54)
+#define HW_PXP_WFE_B_STAGE2_MUX7_CLR (0x00001e58)
+#define HW_PXP_WFE_B_STAGE2_MUX7_TOG (0x00001e5c)
+
+#define BP_PXP_WFE_B_STAGE2_MUX7_RSVD0 30
+#define BM_PXP_WFE_B_STAGE2_MUX7_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE2_MUX7_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE2_MUX7_RSVD0)
+#define BP_PXP_WFE_B_STAGE2_MUX7_MUX31 24
+#define BM_PXP_WFE_B_STAGE2_MUX7_MUX31 0x3F000000
+#define BF_PXP_WFE_B_STAGE2_MUX7_MUX31(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE2_MUX7_MUX31)
+#define BP_PXP_WFE_B_STAGE2_MUX7_RSVD1 22
+#define BM_PXP_WFE_B_STAGE2_MUX7_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE2_MUX7_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE2_MUX7_RSVD1)
+#define BP_PXP_WFE_B_STAGE2_MUX7_MUX30 16
+#define BM_PXP_WFE_B_STAGE2_MUX7_MUX30 0x003F0000
+#define BF_PXP_WFE_B_STAGE2_MUX7_MUX30(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE2_MUX7_MUX30)
+#define BP_PXP_WFE_B_STAGE2_MUX7_RSVD2 14
+#define BM_PXP_WFE_B_STAGE2_MUX7_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE2_MUX7_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE2_MUX7_RSVD2)
+#define BP_PXP_WFE_B_STAGE2_MUX7_MUX29 8
+#define BM_PXP_WFE_B_STAGE2_MUX7_MUX29 0x00003F00
+#define BF_PXP_WFE_B_STAGE2_MUX7_MUX29(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE2_MUX7_MUX29)
+#define BP_PXP_WFE_B_STAGE2_MUX7_RSVD3 6
+#define BM_PXP_WFE_B_STAGE2_MUX7_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE2_MUX7_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE2_MUX7_RSVD3)
+#define BP_PXP_WFE_B_STAGE2_MUX7_MUX28 0
+#define BM_PXP_WFE_B_STAGE2_MUX7_MUX28 0x0000003F
+#define BF_PXP_WFE_B_STAGE2_MUX7_MUX28(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE2_MUX7_MUX28)
+
+#define HW_PXP_WFE_B_STAGE2_MUX8 (0x00001e60)
+#define HW_PXP_WFE_B_STAGE2_MUX8_SET (0x00001e64)
+#define HW_PXP_WFE_B_STAGE2_MUX8_CLR (0x00001e68)
+#define HW_PXP_WFE_B_STAGE2_MUX8_TOG (0x00001e6c)
+
+#define BP_PXP_WFE_B_STAGE2_MUX8_RSVD0 30
+#define BM_PXP_WFE_B_STAGE2_MUX8_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE2_MUX8_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE2_MUX8_RSVD0)
+#define BP_PXP_WFE_B_STAGE2_MUX8_MUX35 24
+#define BM_PXP_WFE_B_STAGE2_MUX8_MUX35 0x3F000000
+#define BF_PXP_WFE_B_STAGE2_MUX8_MUX35(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE2_MUX8_MUX35)
+#define BP_PXP_WFE_B_STAGE2_MUX8_RSVD1 22
+#define BM_PXP_WFE_B_STAGE2_MUX8_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE2_MUX8_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE2_MUX8_RSVD1)
+#define BP_PXP_WFE_B_STAGE2_MUX8_MUX34 16
+#define BM_PXP_WFE_B_STAGE2_MUX8_MUX34 0x003F0000
+#define BF_PXP_WFE_B_STAGE2_MUX8_MUX34(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE2_MUX8_MUX34)
+#define BP_PXP_WFE_B_STAGE2_MUX8_RSVD2 14
+#define BM_PXP_WFE_B_STAGE2_MUX8_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE2_MUX8_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE2_MUX8_RSVD2)
+#define BP_PXP_WFE_B_STAGE2_MUX8_MUX33 8
+#define BM_PXP_WFE_B_STAGE2_MUX8_MUX33 0x00003F00
+#define BF_PXP_WFE_B_STAGE2_MUX8_MUX33(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE2_MUX8_MUX33)
+#define BP_PXP_WFE_B_STAGE2_MUX8_RSVD3 6
+#define BM_PXP_WFE_B_STAGE2_MUX8_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE2_MUX8_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE2_MUX8_RSVD3)
+#define BP_PXP_WFE_B_STAGE2_MUX8_MUX32 0
+#define BM_PXP_WFE_B_STAGE2_MUX8_MUX32 0x0000003F
+#define BF_PXP_WFE_B_STAGE2_MUX8_MUX32(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE2_MUX8_MUX32)
+
+#define HW_PXP_WFE_B_STAGE2_MUX9 (0x00001e70)
+#define HW_PXP_WFE_B_STAGE2_MUX9_SET (0x00001e74)
+#define HW_PXP_WFE_B_STAGE2_MUX9_CLR (0x00001e78)
+#define HW_PXP_WFE_B_STAGE2_MUX9_TOG (0x00001e7c)
+
+#define BP_PXP_WFE_B_STAGE2_MUX9_RSVD0 30
+#define BM_PXP_WFE_B_STAGE2_MUX9_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE2_MUX9_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE2_MUX9_RSVD0)
+#define BP_PXP_WFE_B_STAGE2_MUX9_MUX39 24
+#define BM_PXP_WFE_B_STAGE2_MUX9_MUX39 0x3F000000
+#define BF_PXP_WFE_B_STAGE2_MUX9_MUX39(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE2_MUX9_MUX39)
+#define BP_PXP_WFE_B_STAGE2_MUX9_RSVD1 22
+#define BM_PXP_WFE_B_STAGE2_MUX9_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE2_MUX9_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE2_MUX9_RSVD1)
+#define BP_PXP_WFE_B_STAGE2_MUX9_MUX38 16
+#define BM_PXP_WFE_B_STAGE2_MUX9_MUX38 0x003F0000
+#define BF_PXP_WFE_B_STAGE2_MUX9_MUX38(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE2_MUX9_MUX38)
+#define BP_PXP_WFE_B_STAGE2_MUX9_RSVD2 14
+#define BM_PXP_WFE_B_STAGE2_MUX9_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE2_MUX9_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE2_MUX9_RSVD2)
+#define BP_PXP_WFE_B_STAGE2_MUX9_MUX37 8
+#define BM_PXP_WFE_B_STAGE2_MUX9_MUX37 0x00003F00
+#define BF_PXP_WFE_B_STAGE2_MUX9_MUX37(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE2_MUX9_MUX37)
+#define BP_PXP_WFE_B_STAGE2_MUX9_RSVD3 6
+#define BM_PXP_WFE_B_STAGE2_MUX9_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE2_MUX9_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE2_MUX9_RSVD3)
+#define BP_PXP_WFE_B_STAGE2_MUX9_MUX36 0
+#define BM_PXP_WFE_B_STAGE2_MUX9_MUX36 0x0000003F
+#define BF_PXP_WFE_B_STAGE2_MUX9_MUX36(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE2_MUX9_MUX36)
+
+#define HW_PXP_WFE_B_STAGE2_MUX10 (0x00001e80)
+#define HW_PXP_WFE_B_STAGE2_MUX10_SET (0x00001e84)
+#define HW_PXP_WFE_B_STAGE2_MUX10_CLR (0x00001e88)
+#define HW_PXP_WFE_B_STAGE2_MUX10_TOG (0x00001e8c)
+
+#define BP_PXP_WFE_B_STAGE2_MUX10_RSVD0 30
+#define BM_PXP_WFE_B_STAGE2_MUX10_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE2_MUX10_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE2_MUX10_RSVD0)
+#define BP_PXP_WFE_B_STAGE2_MUX10_MUX43 24
+#define BM_PXP_WFE_B_STAGE2_MUX10_MUX43 0x3F000000
+#define BF_PXP_WFE_B_STAGE2_MUX10_MUX43(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE2_MUX10_MUX43)
+#define BP_PXP_WFE_B_STAGE2_MUX10_RSVD1 22
+#define BM_PXP_WFE_B_STAGE2_MUX10_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE2_MUX10_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE2_MUX10_RSVD1)
+#define BP_PXP_WFE_B_STAGE2_MUX10_MUX42 16
+#define BM_PXP_WFE_B_STAGE2_MUX10_MUX42 0x003F0000
+#define BF_PXP_WFE_B_STAGE2_MUX10_MUX42(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE2_MUX10_MUX42)
+#define BP_PXP_WFE_B_STAGE2_MUX10_RSVD2 14
+#define BM_PXP_WFE_B_STAGE2_MUX10_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE2_MUX10_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE2_MUX10_RSVD2)
+#define BP_PXP_WFE_B_STAGE2_MUX10_MUX41 8
+#define BM_PXP_WFE_B_STAGE2_MUX10_MUX41 0x00003F00
+#define BF_PXP_WFE_B_STAGE2_MUX10_MUX41(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE2_MUX10_MUX41)
+#define BP_PXP_WFE_B_STAGE2_MUX10_RSVD3 6
+#define BM_PXP_WFE_B_STAGE2_MUX10_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE2_MUX10_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE2_MUX10_RSVD3)
+#define BP_PXP_WFE_B_STAGE2_MUX10_MUX40 0
+#define BM_PXP_WFE_B_STAGE2_MUX10_MUX40 0x0000003F
+#define BF_PXP_WFE_B_STAGE2_MUX10_MUX40(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE2_MUX10_MUX40)
+#define BV_PXP_WFE_B_STAGE2_MUX10_MUX40__INC 0x0
+#define BV_PXP_WFE_B_STAGE2_MUX10_MUX40__DEC 0x1
+#define BV_PXP_WFE_B_STAGE2_MUX10_MUX40__ADD 0x2
+#define BV_PXP_WFE_B_STAGE2_MUX10_MUX40__MINUS 0x3
+#define BV_PXP_WFE_B_STAGE2_MUX10_MUX40__AND 0x4
+#define BV_PXP_WFE_B_STAGE2_MUX10_MUX40__OR 0x5
+#define BV_PXP_WFE_B_STAGE2_MUX10_MUX40__XOR 0x6
+#define BV_PXP_WFE_B_STAGE2_MUX10_MUX40__SHIFTLEFT 0x7
+#define BV_PXP_WFE_B_STAGE2_MUX10_MUX40__SHIFTRIGHT 0x8
+#define BV_PXP_WFE_B_STAGE2_MUX10_MUX40__BIT_AND 0x9
+#define BV_PXP_WFE_B_STAGE2_MUX10_MUX40__BIT_OR 0xa
+#define BV_PXP_WFE_B_STAGE2_MUX10_MUX40__BIT_CMP 0xb
+#define BV_PXP_WFE_B_STAGE2_MUX10_MUX40__NOP 0xc
+
+#define HW_PXP_WFE_B_STAGE2_MUX11 (0x00001e90)
+#define HW_PXP_WFE_B_STAGE2_MUX11_SET (0x00001e94)
+#define HW_PXP_WFE_B_STAGE2_MUX11_CLR (0x00001e98)
+#define HW_PXP_WFE_B_STAGE2_MUX11_TOG (0x00001e9c)
+
+#define BP_PXP_WFE_B_STAGE2_MUX11_RSVD0 30
+#define BM_PXP_WFE_B_STAGE2_MUX11_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE2_MUX11_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE2_MUX11_RSVD0)
+#define BP_PXP_WFE_B_STAGE2_MUX11_MUX47 24
+#define BM_PXP_WFE_B_STAGE2_MUX11_MUX47 0x3F000000
+#define BF_PXP_WFE_B_STAGE2_MUX11_MUX47(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE2_MUX11_MUX47)
+#define BP_PXP_WFE_B_STAGE2_MUX11_RSVD1 22
+#define BM_PXP_WFE_B_STAGE2_MUX11_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE2_MUX11_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE2_MUX11_RSVD1)
+#define BP_PXP_WFE_B_STAGE2_MUX11_MUX46 16
+#define BM_PXP_WFE_B_STAGE2_MUX11_MUX46 0x003F0000
+#define BF_PXP_WFE_B_STAGE2_MUX11_MUX46(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE2_MUX11_MUX46)
+#define BP_PXP_WFE_B_STAGE2_MUX11_RSVD2 14
+#define BM_PXP_WFE_B_STAGE2_MUX11_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE2_MUX11_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE2_MUX11_RSVD2)
+#define BP_PXP_WFE_B_STAGE2_MUX11_MUX45 8
+#define BM_PXP_WFE_B_STAGE2_MUX11_MUX45 0x00003F00
+#define BF_PXP_WFE_B_STAGE2_MUX11_MUX45(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE2_MUX11_MUX45)
+#define BP_PXP_WFE_B_STAGE2_MUX11_RSVD3 6
+#define BM_PXP_WFE_B_STAGE2_MUX11_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE2_MUX11_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE2_MUX11_RSVD3)
+#define BP_PXP_WFE_B_STAGE2_MUX11_MUX44 0
+#define BM_PXP_WFE_B_STAGE2_MUX11_MUX44 0x0000003F
+#define BF_PXP_WFE_B_STAGE2_MUX11_MUX44(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE2_MUX11_MUX44)
+
+#define HW_PXP_WFE_B_STAGE2_MUX12 (0x00001ea0)
+#define HW_PXP_WFE_B_STAGE2_MUX12_SET (0x00001ea4)
+#define HW_PXP_WFE_B_STAGE2_MUX12_CLR (0x00001ea8)
+#define HW_PXP_WFE_B_STAGE2_MUX12_TOG (0x00001eac)
+
+#define BP_PXP_WFE_B_STAGE2_MUX12_RSVD0 6
+#define BM_PXP_WFE_B_STAGE2_MUX12_RSVD0 0xFFFFFFC0
+#define BF_PXP_WFE_B_STAGE2_MUX12_RSVD0(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE2_MUX12_RSVD0)
+#define BP_PXP_WFE_B_STAGE2_MUX12_MUX48 0
+#define BM_PXP_WFE_B_STAGE2_MUX12_MUX48 0x0000003F
+#define BF_PXP_WFE_B_STAGE2_MUX12_MUX48(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE2_MUX12_MUX48)
+
+#define HW_PXP_WFE_B_STAGE3_MUX0 (0x00001eb0)
+#define HW_PXP_WFE_B_STAGE3_MUX0_SET (0x00001eb4)
+#define HW_PXP_WFE_B_STAGE3_MUX0_CLR (0x00001eb8)
+#define HW_PXP_WFE_B_STAGE3_MUX0_TOG (0x00001ebc)
+
+#define BP_PXP_WFE_B_STAGE3_MUX0_RSVD0 30
+#define BM_PXP_WFE_B_STAGE3_MUX0_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE3_MUX0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE3_MUX0_RSVD0)
+#define BP_PXP_WFE_B_STAGE3_MUX0_MUX3 24
+#define BM_PXP_WFE_B_STAGE3_MUX0_MUX3 0x3F000000
+#define BF_PXP_WFE_B_STAGE3_MUX0_MUX3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE3_MUX0_MUX3)
+#define BP_PXP_WFE_B_STAGE3_MUX0_RSVD1 22
+#define BM_PXP_WFE_B_STAGE3_MUX0_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE3_MUX0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE3_MUX0_RSVD1)
+#define BP_PXP_WFE_B_STAGE3_MUX0_MUX2 16
+#define BM_PXP_WFE_B_STAGE3_MUX0_MUX2 0x003F0000
+#define BF_PXP_WFE_B_STAGE3_MUX0_MUX2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE3_MUX0_MUX2)
+#define BP_PXP_WFE_B_STAGE3_MUX0_RSVD2 14
+#define BM_PXP_WFE_B_STAGE3_MUX0_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE3_MUX0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE3_MUX0_RSVD2)
+#define BP_PXP_WFE_B_STAGE3_MUX0_MUX1 8
+#define BM_PXP_WFE_B_STAGE3_MUX0_MUX1 0x00003F00
+#define BF_PXP_WFE_B_STAGE3_MUX0_MUX1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE3_MUX0_MUX1)
+#define BP_PXP_WFE_B_STAGE3_MUX0_RSVD3 6
+#define BM_PXP_WFE_B_STAGE3_MUX0_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE3_MUX0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE3_MUX0_RSVD3)
+#define BP_PXP_WFE_B_STAGE3_MUX0_MUX0 0
+#define BM_PXP_WFE_B_STAGE3_MUX0_MUX0 0x0000003F
+#define BF_PXP_WFE_B_STAGE3_MUX0_MUX0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE3_MUX0_MUX0)
+
+#define HW_PXP_WFE_B_STAGE3_MUX1 (0x00001ec0)
+#define HW_PXP_WFE_B_STAGE3_MUX1_SET (0x00001ec4)
+#define HW_PXP_WFE_B_STAGE3_MUX1_CLR (0x00001ec8)
+#define HW_PXP_WFE_B_STAGE3_MUX1_TOG (0x00001ecc)
+
+#define BP_PXP_WFE_B_STAGE3_MUX1_RSVD0 30
+#define BM_PXP_WFE_B_STAGE3_MUX1_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE3_MUX1_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE3_MUX1_RSVD0)
+#define BP_PXP_WFE_B_STAGE3_MUX1_MUX7 24
+#define BM_PXP_WFE_B_STAGE3_MUX1_MUX7 0x3F000000
+#define BF_PXP_WFE_B_STAGE3_MUX1_MUX7(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE3_MUX1_MUX7)
+#define BP_PXP_WFE_B_STAGE3_MUX1_RSVD1 22
+#define BM_PXP_WFE_B_STAGE3_MUX1_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE3_MUX1_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE3_MUX1_RSVD1)
+#define BP_PXP_WFE_B_STAGE3_MUX1_MUX6 16
+#define BM_PXP_WFE_B_STAGE3_MUX1_MUX6 0x003F0000
+#define BF_PXP_WFE_B_STAGE3_MUX1_MUX6(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE3_MUX1_MUX6)
+#define BP_PXP_WFE_B_STAGE3_MUX1_RSVD2 14
+#define BM_PXP_WFE_B_STAGE3_MUX1_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE3_MUX1_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE3_MUX1_RSVD2)
+#define BP_PXP_WFE_B_STAGE3_MUX1_MUX5 8
+#define BM_PXP_WFE_B_STAGE3_MUX1_MUX5 0x00003F00
+#define BF_PXP_WFE_B_STAGE3_MUX1_MUX5(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE3_MUX1_MUX5)
+#define BP_PXP_WFE_B_STAGE3_MUX1_RSVD3 6
+#define BM_PXP_WFE_B_STAGE3_MUX1_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE3_MUX1_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE3_MUX1_RSVD3)
+#define BP_PXP_WFE_B_STAGE3_MUX1_MUX4 0
+#define BM_PXP_WFE_B_STAGE3_MUX1_MUX4 0x0000003F
+#define BF_PXP_WFE_B_STAGE3_MUX1_MUX4(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE3_MUX1_MUX4)
+
+#define HW_PXP_WFE_B_STAGE3_MUX2 (0x00001ed0)
+#define HW_PXP_WFE_B_STAGE3_MUX2_SET (0x00001ed4)
+#define HW_PXP_WFE_B_STAGE3_MUX2_CLR (0x00001ed8)
+#define HW_PXP_WFE_B_STAGE3_MUX2_TOG (0x00001edc)
+
+#define BP_PXP_WFE_B_STAGE3_MUX2_RSVD0 30
+#define BM_PXP_WFE_B_STAGE3_MUX2_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE3_MUX2_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE3_MUX2_RSVD0)
+#define BP_PXP_WFE_B_STAGE3_MUX2_MUX11 24
+#define BM_PXP_WFE_B_STAGE3_MUX2_MUX11 0x3F000000
+#define BF_PXP_WFE_B_STAGE3_MUX2_MUX11(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE3_MUX2_MUX11)
+#define BP_PXP_WFE_B_STAGE3_MUX2_RSVD1 22
+#define BM_PXP_WFE_B_STAGE3_MUX2_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE3_MUX2_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE3_MUX2_RSVD1)
+#define BP_PXP_WFE_B_STAGE3_MUX2_MUX10 16
+#define BM_PXP_WFE_B_STAGE3_MUX2_MUX10 0x003F0000
+#define BF_PXP_WFE_B_STAGE3_MUX2_MUX10(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE3_MUX2_MUX10)
+#define BP_PXP_WFE_B_STAGE3_MUX2_RSVD2 14
+#define BM_PXP_WFE_B_STAGE3_MUX2_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE3_MUX2_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE3_MUX2_RSVD2)
+#define BP_PXP_WFE_B_STAGE3_MUX2_MUX9 8
+#define BM_PXP_WFE_B_STAGE3_MUX2_MUX9 0x00003F00
+#define BF_PXP_WFE_B_STAGE3_MUX2_MUX9(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE3_MUX2_MUX9)
+#define BP_PXP_WFE_B_STAGE3_MUX2_RSVD3 6
+#define BM_PXP_WFE_B_STAGE3_MUX2_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE3_MUX2_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE3_MUX2_RSVD3)
+#define BP_PXP_WFE_B_STAGE3_MUX2_MUX8 0
+#define BM_PXP_WFE_B_STAGE3_MUX2_MUX8 0x0000003F
+#define BF_PXP_WFE_B_STAGE3_MUX2_MUX8(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE3_MUX2_MUX8)
+
+#define HW_PXP_WFE_B_STAGE3_MUX3 (0x00001ee0)
+#define HW_PXP_WFE_B_STAGE3_MUX3_SET (0x00001ee4)
+#define HW_PXP_WFE_B_STAGE3_MUX3_CLR (0x00001ee8)
+#define HW_PXP_WFE_B_STAGE3_MUX3_TOG (0x00001eec)
+
+#define BP_PXP_WFE_B_STAGE3_MUX3_RSVD0 30
+#define BM_PXP_WFE_B_STAGE3_MUX3_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE3_MUX3_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE3_MUX3_RSVD0)
+#define BP_PXP_WFE_B_STAGE3_MUX3_MUX15 24
+#define BM_PXP_WFE_B_STAGE3_MUX3_MUX15 0x3F000000
+#define BF_PXP_WFE_B_STAGE3_MUX3_MUX15(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE3_MUX3_MUX15)
+#define BP_PXP_WFE_B_STAGE3_MUX3_RSVD1 22
+#define BM_PXP_WFE_B_STAGE3_MUX3_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE3_MUX3_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE3_MUX3_RSVD1)
+#define BP_PXP_WFE_B_STAGE3_MUX3_MUX14 16
+#define BM_PXP_WFE_B_STAGE3_MUX3_MUX14 0x003F0000
+#define BF_PXP_WFE_B_STAGE3_MUX3_MUX14(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE3_MUX3_MUX14)
+#define BP_PXP_WFE_B_STAGE3_MUX3_RSVD2 14
+#define BM_PXP_WFE_B_STAGE3_MUX3_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE3_MUX3_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE3_MUX3_RSVD2)
+#define BP_PXP_WFE_B_STAGE3_MUX3_MUX13 8
+#define BM_PXP_WFE_B_STAGE3_MUX3_MUX13 0x00003F00
+#define BF_PXP_WFE_B_STAGE3_MUX3_MUX13(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE3_MUX3_MUX13)
+#define BP_PXP_WFE_B_STAGE3_MUX3_RSVD3 6
+#define BM_PXP_WFE_B_STAGE3_MUX3_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE3_MUX3_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE3_MUX3_RSVD3)
+#define BP_PXP_WFE_B_STAGE3_MUX3_MUX12 0
+#define BM_PXP_WFE_B_STAGE3_MUX3_MUX12 0x0000003F
+#define BF_PXP_WFE_B_STAGE3_MUX3_MUX12(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE3_MUX3_MUX12)
+
+#define HW_PXP_WFE_B_STAGE3_MUX4 (0x00001ef0)
+#define HW_PXP_WFE_B_STAGE3_MUX4_SET (0x00001ef4)
+#define HW_PXP_WFE_B_STAGE3_MUX4_CLR (0x00001ef8)
+#define HW_PXP_WFE_B_STAGE3_MUX4_TOG (0x00001efc)
+
+#define BP_PXP_WFE_B_STAGE3_MUX4_RSVD0 30
+#define BM_PXP_WFE_B_STAGE3_MUX4_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE3_MUX4_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE3_MUX4_RSVD0)
+#define BP_PXP_WFE_B_STAGE3_MUX4_MUX19 24
+#define BM_PXP_WFE_B_STAGE3_MUX4_MUX19 0x3F000000
+#define BF_PXP_WFE_B_STAGE3_MUX4_MUX19(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE3_MUX4_MUX19)
+#define BP_PXP_WFE_B_STAGE3_MUX4_RSVD1 22
+#define BM_PXP_WFE_B_STAGE3_MUX4_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE3_MUX4_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE3_MUX4_RSVD1)
+#define BP_PXP_WFE_B_STAGE3_MUX4_MUX18 16
+#define BM_PXP_WFE_B_STAGE3_MUX4_MUX18 0x003F0000
+#define BF_PXP_WFE_B_STAGE3_MUX4_MUX18(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE3_MUX4_MUX18)
+#define BP_PXP_WFE_B_STAGE3_MUX4_RSVD2 14
+#define BM_PXP_WFE_B_STAGE3_MUX4_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE3_MUX4_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE3_MUX4_RSVD2)
+#define BP_PXP_WFE_B_STAGE3_MUX4_MUX17 8
+#define BM_PXP_WFE_B_STAGE3_MUX4_MUX17 0x00003F00
+#define BF_PXP_WFE_B_STAGE3_MUX4_MUX17(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE3_MUX4_MUX17)
+#define BP_PXP_WFE_B_STAGE3_MUX4_RSVD3 6
+#define BM_PXP_WFE_B_STAGE3_MUX4_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE3_MUX4_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE3_MUX4_RSVD3)
+#define BP_PXP_WFE_B_STAGE3_MUX4_MUX16 0
+#define BM_PXP_WFE_B_STAGE3_MUX4_MUX16 0x0000003F
+#define BF_PXP_WFE_B_STAGE3_MUX4_MUX16(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE3_MUX4_MUX16)
+
+#define HW_PXP_WFE_B_STAGE3_MUX5 (0x00001f00)
+#define HW_PXP_WFE_B_STAGE3_MUX5_SET (0x00001f04)
+#define HW_PXP_WFE_B_STAGE3_MUX5_CLR (0x00001f08)
+#define HW_PXP_WFE_B_STAGE3_MUX5_TOG (0x00001f0c)
+
+#define BP_PXP_WFE_B_STAGE3_MUX5_RSVD0 30
+#define BM_PXP_WFE_B_STAGE3_MUX5_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE3_MUX5_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE3_MUX5_RSVD0)
+#define BP_PXP_WFE_B_STAGE3_MUX5_MUX23 24
+#define BM_PXP_WFE_B_STAGE3_MUX5_MUX23 0x3F000000
+#define BF_PXP_WFE_B_STAGE3_MUX5_MUX23(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE3_MUX5_MUX23)
+#define BP_PXP_WFE_B_STAGE3_MUX5_RSVD1 22
+#define BM_PXP_WFE_B_STAGE3_MUX5_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE3_MUX5_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE3_MUX5_RSVD1)
+#define BP_PXP_WFE_B_STAGE3_MUX5_MUX22 16
+#define BM_PXP_WFE_B_STAGE3_MUX5_MUX22 0x003F0000
+#define BF_PXP_WFE_B_STAGE3_MUX5_MUX22(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE3_MUX5_MUX22)
+#define BP_PXP_WFE_B_STAGE3_MUX5_RSVD2 14
+#define BM_PXP_WFE_B_STAGE3_MUX5_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE3_MUX5_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE3_MUX5_RSVD2)
+#define BP_PXP_WFE_B_STAGE3_MUX5_MUX21 8
+#define BM_PXP_WFE_B_STAGE3_MUX5_MUX21 0x00003F00
+#define BF_PXP_WFE_B_STAGE3_MUX5_MUX21(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE3_MUX5_MUX21)
+#define BP_PXP_WFE_B_STAGE3_MUX5_RSVD3 6
+#define BM_PXP_WFE_B_STAGE3_MUX5_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE3_MUX5_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE3_MUX5_RSVD3)
+#define BP_PXP_WFE_B_STAGE3_MUX5_MUX20 0
+#define BM_PXP_WFE_B_STAGE3_MUX5_MUX20 0x0000003F
+#define BF_PXP_WFE_B_STAGE3_MUX5_MUX20(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE3_MUX5_MUX20)
+
+#define HW_PXP_WFE_B_STAGE3_MUX6 (0x00001f10)
+#define HW_PXP_WFE_B_STAGE3_MUX6_SET (0x00001f14)
+#define HW_PXP_WFE_B_STAGE3_MUX6_CLR (0x00001f18)
+#define HW_PXP_WFE_B_STAGE3_MUX6_TOG (0x00001f1c)
+
+#define BP_PXP_WFE_B_STAGE3_MUX6_RSVD0 30
+#define BM_PXP_WFE_B_STAGE3_MUX6_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE3_MUX6_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE3_MUX6_RSVD0)
+#define BP_PXP_WFE_B_STAGE3_MUX6_MUX27 24
+#define BM_PXP_WFE_B_STAGE3_MUX6_MUX27 0x3F000000
+#define BF_PXP_WFE_B_STAGE3_MUX6_MUX27(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE3_MUX6_MUX27)
+#define BP_PXP_WFE_B_STAGE3_MUX6_RSVD1 22
+#define BM_PXP_WFE_B_STAGE3_MUX6_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE3_MUX6_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE3_MUX6_RSVD1)
+#define BP_PXP_WFE_B_STAGE3_MUX6_MUX26 16
+#define BM_PXP_WFE_B_STAGE3_MUX6_MUX26 0x003F0000
+#define BF_PXP_WFE_B_STAGE3_MUX6_MUX26(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE3_MUX6_MUX26)
+#define BP_PXP_WFE_B_STAGE3_MUX6_RSVD2 14
+#define BM_PXP_WFE_B_STAGE3_MUX6_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE3_MUX6_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE3_MUX6_RSVD2)
+#define BP_PXP_WFE_B_STAGE3_MUX6_MUX25 8
+#define BM_PXP_WFE_B_STAGE3_MUX6_MUX25 0x00003F00
+#define BF_PXP_WFE_B_STAGE3_MUX6_MUX25(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE3_MUX6_MUX25)
+#define BP_PXP_WFE_B_STAGE3_MUX6_RSVD3 6
+#define BM_PXP_WFE_B_STAGE3_MUX6_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE3_MUX6_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE3_MUX6_RSVD3)
+#define BP_PXP_WFE_B_STAGE3_MUX6_MUX24 0
+#define BM_PXP_WFE_B_STAGE3_MUX6_MUX24 0x0000003F
+#define BF_PXP_WFE_B_STAGE3_MUX6_MUX24(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE3_MUX6_MUX24)
+
+#define HW_PXP_WFE_B_STAGE3_MUX7 (0x00001f20)
+#define HW_PXP_WFE_B_STAGE3_MUX7_SET (0x00001f24)
+#define HW_PXP_WFE_B_STAGE3_MUX7_CLR (0x00001f28)
+#define HW_PXP_WFE_B_STAGE3_MUX7_TOG (0x00001f2c)
+
+#define BP_PXP_WFE_B_STAGE3_MUX7_RSVD0 30
+#define BM_PXP_WFE_B_STAGE3_MUX7_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE3_MUX7_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE3_MUX7_RSVD0)
+#define BP_PXP_WFE_B_STAGE3_MUX7_MUX31 24
+#define BM_PXP_WFE_B_STAGE3_MUX7_MUX31 0x3F000000
+#define BF_PXP_WFE_B_STAGE3_MUX7_MUX31(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE3_MUX7_MUX31)
+#define BP_PXP_WFE_B_STAGE3_MUX7_RSVD1 22
+#define BM_PXP_WFE_B_STAGE3_MUX7_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE3_MUX7_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE3_MUX7_RSVD1)
+#define BP_PXP_WFE_B_STAGE3_MUX7_MUX30 16
+#define BM_PXP_WFE_B_STAGE3_MUX7_MUX30 0x003F0000
+#define BF_PXP_WFE_B_STAGE3_MUX7_MUX30(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE3_MUX7_MUX30)
+#define BP_PXP_WFE_B_STAGE3_MUX7_RSVD2 14
+#define BM_PXP_WFE_B_STAGE3_MUX7_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE3_MUX7_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE3_MUX7_RSVD2)
+#define BP_PXP_WFE_B_STAGE3_MUX7_MUX29 8
+#define BM_PXP_WFE_B_STAGE3_MUX7_MUX29 0x00003F00
+#define BF_PXP_WFE_B_STAGE3_MUX7_MUX29(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE3_MUX7_MUX29)
+#define BP_PXP_WFE_B_STAGE3_MUX7_RSVD3 6
+#define BM_PXP_WFE_B_STAGE3_MUX7_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE3_MUX7_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE3_MUX7_RSVD3)
+#define BP_PXP_WFE_B_STAGE3_MUX7_MUX28 0
+#define BM_PXP_WFE_B_STAGE3_MUX7_MUX28 0x0000003F
+#define BF_PXP_WFE_B_STAGE3_MUX7_MUX28(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE3_MUX7_MUX28)
+
+#define HW_PXP_WFE_B_STAGE3_MUX8 (0x00001f30)
+#define HW_PXP_WFE_B_STAGE3_MUX8_SET (0x00001f34)
+#define HW_PXP_WFE_B_STAGE3_MUX8_CLR (0x00001f38)
+#define HW_PXP_WFE_B_STAGE3_MUX8_TOG (0x00001f3c)
+
+#define BP_PXP_WFE_B_STAGE3_MUX8_RSVD0 30
+#define BM_PXP_WFE_B_STAGE3_MUX8_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE3_MUX8_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE3_MUX8_RSVD0)
+#define BP_PXP_WFE_B_STAGE3_MUX8_MUX35 24
+#define BM_PXP_WFE_B_STAGE3_MUX8_MUX35 0x3F000000
+#define BF_PXP_WFE_B_STAGE3_MUX8_MUX35(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE3_MUX8_MUX35)
+#define BP_PXP_WFE_B_STAGE3_MUX8_RSVD1 22
+#define BM_PXP_WFE_B_STAGE3_MUX8_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE3_MUX8_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE3_MUX8_RSVD1)
+#define BP_PXP_WFE_B_STAGE3_MUX8_MUX34 16
+#define BM_PXP_WFE_B_STAGE3_MUX8_MUX34 0x003F0000
+#define BF_PXP_WFE_B_STAGE3_MUX8_MUX34(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE3_MUX8_MUX34)
+#define BP_PXP_WFE_B_STAGE3_MUX8_RSVD2 14
+#define BM_PXP_WFE_B_STAGE3_MUX8_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE3_MUX8_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE3_MUX8_RSVD2)
+#define BP_PXP_WFE_B_STAGE3_MUX8_MUX33 8
+#define BM_PXP_WFE_B_STAGE3_MUX8_MUX33 0x00003F00
+#define BF_PXP_WFE_B_STAGE3_MUX8_MUX33(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE3_MUX8_MUX33)
+#define BP_PXP_WFE_B_STAGE3_MUX8_RSVD3 6
+#define BM_PXP_WFE_B_STAGE3_MUX8_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE3_MUX8_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE3_MUX8_RSVD3)
+#define BP_PXP_WFE_B_STAGE3_MUX8_MUX32 0
+#define BM_PXP_WFE_B_STAGE3_MUX8_MUX32 0x0000003F
+#define BF_PXP_WFE_B_STAGE3_MUX8_MUX32(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE3_MUX8_MUX32)
+
+#define HW_PXP_WFE_B_STAGE3_MUX9 (0x00001f40)
+#define HW_PXP_WFE_B_STAGE3_MUX9_SET (0x00001f44)
+#define HW_PXP_WFE_B_STAGE3_MUX9_CLR (0x00001f48)
+#define HW_PXP_WFE_B_STAGE3_MUX9_TOG (0x00001f4c)
+
+#define BP_PXP_WFE_B_STAGE3_MUX9_RSVD0 30
+#define BM_PXP_WFE_B_STAGE3_MUX9_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE3_MUX9_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE3_MUX9_RSVD0)
+#define BP_PXP_WFE_B_STAGE3_MUX9_MUX39 24
+#define BM_PXP_WFE_B_STAGE3_MUX9_MUX39 0x3F000000
+#define BF_PXP_WFE_B_STAGE3_MUX9_MUX39(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE3_MUX9_MUX39)
+#define BP_PXP_WFE_B_STAGE3_MUX9_RSVD1 22
+#define BM_PXP_WFE_B_STAGE3_MUX9_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE3_MUX9_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE3_MUX9_RSVD1)
+#define BP_PXP_WFE_B_STAGE3_MUX9_MUX38 16
+#define BM_PXP_WFE_B_STAGE3_MUX9_MUX38 0x003F0000
+#define BF_PXP_WFE_B_STAGE3_MUX9_MUX38(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE3_MUX9_MUX38)
+#define BP_PXP_WFE_B_STAGE3_MUX9_RSVD2 14
+#define BM_PXP_WFE_B_STAGE3_MUX9_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE3_MUX9_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE3_MUX9_RSVD2)
+#define BP_PXP_WFE_B_STAGE3_MUX9_MUX37 8
+#define BM_PXP_WFE_B_STAGE3_MUX9_MUX37 0x00003F00
+#define BF_PXP_WFE_B_STAGE3_MUX9_MUX37(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE3_MUX9_MUX37)
+#define BP_PXP_WFE_B_STAGE3_MUX9_RSVD3 6
+#define BM_PXP_WFE_B_STAGE3_MUX9_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE3_MUX9_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE3_MUX9_RSVD3)
+#define BP_PXP_WFE_B_STAGE3_MUX9_MUX36 0
+#define BM_PXP_WFE_B_STAGE3_MUX9_MUX36 0x0000003F
+#define BF_PXP_WFE_B_STAGE3_MUX9_MUX36(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE3_MUX9_MUX36)
+
+#define HW_PXP_WFE_B_STAGE3_MUX10 (0x00001f50)
+#define HW_PXP_WFE_B_STAGE3_MUX10_SET (0x00001f54)
+#define HW_PXP_WFE_B_STAGE3_MUX10_CLR (0x00001f58)
+#define HW_PXP_WFE_B_STAGE3_MUX10_TOG (0x00001f5c)
+
+#define BP_PXP_WFE_B_STAGE3_MUX10_RSVD0 30
+#define BM_PXP_WFE_B_STAGE3_MUX10_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STAGE3_MUX10_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE3_MUX10_RSVD0)
+#define BP_PXP_WFE_B_STAGE3_MUX10_MUX43 24
+#define BM_PXP_WFE_B_STAGE3_MUX10_MUX43 0x3F000000
+#define BF_PXP_WFE_B_STAGE3_MUX10_MUX43(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE3_MUX10_MUX43)
+#define BP_PXP_WFE_B_STAGE3_MUX10_RSVD1 22
+#define BM_PXP_WFE_B_STAGE3_MUX10_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STAGE3_MUX10_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE3_MUX10_RSVD1)
+#define BP_PXP_WFE_B_STAGE3_MUX10_MUX42 16
+#define BM_PXP_WFE_B_STAGE3_MUX10_MUX42 0x003F0000
+#define BF_PXP_WFE_B_STAGE3_MUX10_MUX42(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE3_MUX10_MUX42)
+#define BP_PXP_WFE_B_STAGE3_MUX10_RSVD2 14
+#define BM_PXP_WFE_B_STAGE3_MUX10_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STAGE3_MUX10_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE3_MUX10_RSVD2)
+#define BP_PXP_WFE_B_STAGE3_MUX10_MUX41 8
+#define BM_PXP_WFE_B_STAGE3_MUX10_MUX41 0x00003F00
+#define BF_PXP_WFE_B_STAGE3_MUX10_MUX41(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE3_MUX10_MUX41)
+#define BP_PXP_WFE_B_STAGE3_MUX10_RSVD3 6
+#define BM_PXP_WFE_B_STAGE3_MUX10_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STAGE3_MUX10_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE3_MUX10_RSVD3)
+#define BP_PXP_WFE_B_STAGE3_MUX10_MUX40 0
+#define BM_PXP_WFE_B_STAGE3_MUX10_MUX40 0x0000003F
+#define BF_PXP_WFE_B_STAGE3_MUX10_MUX40(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE3_MUX10_MUX40)
+
+#define HW_PXP_WFE_B_STG1_5X8_OUT0_0 (0x00001f60)
+
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_0_LUTOUT3 24
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_0_LUTOUT3 0xFF000000
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_0_LUTOUT3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X8_OUT0_0_LUTOUT3)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_0_LUTOUT2 16
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_0_LUTOUT2 0x00FF0000
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_0_LUTOUT2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X8_OUT0_0_LUTOUT2)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_0_LUTOUT1 8
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_0_LUTOUT1 0x0000FF00
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_0_LUTOUT1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X8_OUT0_0_LUTOUT1)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_0_LUTOUT0 0
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_0_LUTOUT0 0x000000FF
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X8_OUT0_0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG1_5X8_OUT0_1 (0x00001f70)
+
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_1_LUTOUT7 24
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_1_LUTOUT7 0xFF000000
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_1_LUTOUT7(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X8_OUT0_1_LUTOUT7)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_1_LUTOUT6 16
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_1_LUTOUT6 0x00FF0000
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_1_LUTOUT6(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X8_OUT0_1_LUTOUT6)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_1_LUTOUT5 8
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_1_LUTOUT5 0x0000FF00
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_1_LUTOUT5(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X8_OUT0_1_LUTOUT5)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_1_LUTOUT4 0
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_1_LUTOUT4 0x000000FF
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_1_LUTOUT4(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X8_OUT0_1_LUTOUT4)
+
+#define HW_PXP_WFE_B_STG1_5X8_OUT0_2 (0x00001f80)
+
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_2_LUTOUT11 24
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_2_LUTOUT11 0xFF000000
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_2_LUTOUT11(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X8_OUT0_2_LUTOUT11)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_2_LUTOUT10 16
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_2_LUTOUT10 0x00FF0000
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_2_LUTOUT10(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X8_OUT0_2_LUTOUT10)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_2_LUTOUT9 8
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_2_LUTOUT9 0x0000FF00
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_2_LUTOUT9(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X8_OUT0_2_LUTOUT9)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_2_LUTOUT8 0
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_2_LUTOUT8 0x000000FF
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_2_LUTOUT8(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X8_OUT0_2_LUTOUT8)
+
+#define HW_PXP_WFE_B_STG1_5X8_OUT0_3 (0x00001f90)
+
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_3_LUTOUT15 24
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_3_LUTOUT15 0xFF000000
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_3_LUTOUT15(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X8_OUT0_3_LUTOUT15)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_3_LUTOUT14 16
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_3_LUTOUT14 0x00FF0000
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_3_LUTOUT14(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X8_OUT0_3_LUTOUT14)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_3_LUTOUT13 8
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_3_LUTOUT13 0x0000FF00
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_3_LUTOUT13(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X8_OUT0_3_LUTOUT13)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_3_LUTOUT12 0
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_3_LUTOUT12 0x000000FF
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_3_LUTOUT12(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X8_OUT0_3_LUTOUT12)
+
+#define HW_PXP_WFE_B_STG1_5X8_OUT0_4 (0x00001fa0)
+
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_4_LUTOUT19 24
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_4_LUTOUT19 0xFF000000
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_4_LUTOUT19(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X8_OUT0_4_LUTOUT19)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_4_LUTOUT18 16
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_4_LUTOUT18 0x00FF0000
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_4_LUTOUT18(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X8_OUT0_4_LUTOUT18)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_4_LUTOUT17 8
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_4_LUTOUT17 0x0000FF00
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_4_LUTOUT17(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X8_OUT0_4_LUTOUT17)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_4_LUTOUT16 0
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_4_LUTOUT16 0x000000FF
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_4_LUTOUT16(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X8_OUT0_4_LUTOUT16)
+
+#define HW_PXP_WFE_B_STG1_5X8_OUT0_5 (0x00001fb0)
+
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_5_LUTOUT23 24
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_5_LUTOUT23 0xFF000000
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_5_LUTOUT23(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X8_OUT0_5_LUTOUT23)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_5_LUTOUT22 16
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_5_LUTOUT22 0x00FF0000
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_5_LUTOUT22(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X8_OUT0_5_LUTOUT22)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_5_LUTOUT21 8
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_5_LUTOUT21 0x0000FF00
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_5_LUTOUT21(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X8_OUT0_5_LUTOUT21)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_5_LUTOUT20 0
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_5_LUTOUT20 0x000000FF
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_5_LUTOUT20(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X8_OUT0_5_LUTOUT20)
+
+#define HW_PXP_WFE_B_STG1_5X8_OUT0_6 (0x00001fc0)
+
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_6_LUTOUT27 24
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_6_LUTOUT27 0xFF000000
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_6_LUTOUT27(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X8_OUT0_6_LUTOUT27)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_6_LUTOUT26 16
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_6_LUTOUT26 0x00FF0000
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_6_LUTOUT26(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X8_OUT0_6_LUTOUT26)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_6_LUTOUT25 8
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_6_LUTOUT25 0x0000FF00
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_6_LUTOUT25(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X8_OUT0_6_LUTOUT25)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_6_LUTOUT24 0
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_6_LUTOUT24 0x000000FF
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_6_LUTOUT24(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X8_OUT0_6_LUTOUT24)
+
+#define HW_PXP_WFE_B_STG1_5X8_OUT0_7 (0x00001fd0)
+
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_7_LUTOUT31 24
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_7_LUTOUT31 0xFF000000
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_7_LUTOUT31(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X8_OUT0_7_LUTOUT31)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_7_LUTOUT30 16
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_7_LUTOUT30 0x00FF0000
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_7_LUTOUT30(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X8_OUT0_7_LUTOUT30)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_7_LUTOUT29 8
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_7_LUTOUT29 0x0000FF00
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_7_LUTOUT29(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X8_OUT0_7_LUTOUT29)
+#define BP_PXP_WFE_B_STG1_5X8_OUT0_7_LUTOUT28 0
+#define BM_PXP_WFE_B_STG1_5X8_OUT0_7_LUTOUT28 0x000000FF
+#define BF_PXP_WFE_B_STG1_5X8_OUT0_7_LUTOUT28(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X8_OUT0_7_LUTOUT28)
+
+#define HW_PXP_WFE_B_STG1_5X8_OUT1_0 (0x00001fe0)
+
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_0_LUTOUT3 24
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_0_LUTOUT3 0xFF000000
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_0_LUTOUT3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X8_OUT1_0_LUTOUT3)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_0_LUTOUT2 16
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_0_LUTOUT2 0x00FF0000
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_0_LUTOUT2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X8_OUT1_0_LUTOUT2)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_0_LUTOUT1 8
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_0_LUTOUT1 0x0000FF00
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_0_LUTOUT1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X8_OUT1_0_LUTOUT1)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_0_LUTOUT0 0
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_0_LUTOUT0 0x000000FF
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X8_OUT1_0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG1_5X8_OUT1_1 (0x00001ff0)
+
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_1_LUTOUT7 24
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_1_LUTOUT7 0xFF000000
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_1_LUTOUT7(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X8_OUT1_1_LUTOUT7)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_1_LUTOUT6 16
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_1_LUTOUT6 0x00FF0000
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_1_LUTOUT6(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X8_OUT1_1_LUTOUT6)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_1_LUTOUT5 8
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_1_LUTOUT5 0x0000FF00
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_1_LUTOUT5(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X8_OUT1_1_LUTOUT5)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_1_LUTOUT4 0
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_1_LUTOUT4 0x000000FF
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_1_LUTOUT4(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X8_OUT1_1_LUTOUT4)
+
+#define HW_PXP_WFE_B_STG1_5X8_OUT1_2 (0x00002000)
+
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_2_LUTOUT11 24
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_2_LUTOUT11 0xFF000000
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_2_LUTOUT11(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X8_OUT1_2_LUTOUT11)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_2_LUTOUT10 16
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_2_LUTOUT10 0x00FF0000
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_2_LUTOUT10(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X8_OUT1_2_LUTOUT10)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_2_LUTOUT9 8
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_2_LUTOUT9 0x0000FF00
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_2_LUTOUT9(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X8_OUT1_2_LUTOUT9)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_2_LUTOUT8 0
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_2_LUTOUT8 0x000000FF
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_2_LUTOUT8(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X8_OUT1_2_LUTOUT8)
+
+#define HW_PXP_WFE_B_STG1_5X8_OUT1_3 (0x00002010)
+
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_3_LUTOUT15 24
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_3_LUTOUT15 0xFF000000
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_3_LUTOUT15(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X8_OUT1_3_LUTOUT15)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_3_LUTOUT14 16
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_3_LUTOUT14 0x00FF0000
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_3_LUTOUT14(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X8_OUT1_3_LUTOUT14)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_3_LUTOUT13 8
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_3_LUTOUT13 0x0000FF00
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_3_LUTOUT13(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X8_OUT1_3_LUTOUT13)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_3_LUTOUT12 0
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_3_LUTOUT12 0x000000FF
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_3_LUTOUT12(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X8_OUT1_3_LUTOUT12)
+
+#define HW_PXP_WFE_B_STG1_5X8_OUT1_4 (0x00002020)
+
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_4_LUTOUT19 24
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_4_LUTOUT19 0xFF000000
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_4_LUTOUT19(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X8_OUT1_4_LUTOUT19)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_4_LUTOUT18 16
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_4_LUTOUT18 0x00FF0000
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_4_LUTOUT18(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X8_OUT1_4_LUTOUT18)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_4_LUTOUT17 8
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_4_LUTOUT17 0x0000FF00
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_4_LUTOUT17(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X8_OUT1_4_LUTOUT17)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_4_LUTOUT16 0
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_4_LUTOUT16 0x000000FF
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_4_LUTOUT16(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X8_OUT1_4_LUTOUT16)
+
+#define HW_PXP_WFE_B_STG1_5X8_OUT1_5 (0x00002030)
+
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_5_LUTOUT23 24
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_5_LUTOUT23 0xFF000000
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_5_LUTOUT23(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X8_OUT1_5_LUTOUT23)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_5_LUTOUT22 16
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_5_LUTOUT22 0x00FF0000
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_5_LUTOUT22(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X8_OUT1_5_LUTOUT22)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_5_LUTOUT21 8
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_5_LUTOUT21 0x0000FF00
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_5_LUTOUT21(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X8_OUT1_5_LUTOUT21)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_5_LUTOUT20 0
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_5_LUTOUT20 0x000000FF
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_5_LUTOUT20(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X8_OUT1_5_LUTOUT20)
+
+#define HW_PXP_WFE_B_STG1_5X8_OUT1_6 (0x00002040)
+
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_6_LUTOUT27 24
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_6_LUTOUT27 0xFF000000
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_6_LUTOUT27(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X8_OUT1_6_LUTOUT27)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_6_LUTOUT26 16
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_6_LUTOUT26 0x00FF0000
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_6_LUTOUT26(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X8_OUT1_6_LUTOUT26)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_6_LUTOUT25 8
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_6_LUTOUT25 0x0000FF00
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_6_LUTOUT25(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X8_OUT1_6_LUTOUT25)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_6_LUTOUT24 0
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_6_LUTOUT24 0x000000FF
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_6_LUTOUT24(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X8_OUT1_6_LUTOUT24)
+
+#define HW_PXP_WFE_B_STG1_5X8_OUT1_7 (0x00002050)
+
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_7_LUTOUT31 24
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_7_LUTOUT31 0xFF000000
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_7_LUTOUT31(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X8_OUT1_7_LUTOUT31)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_7_LUTOUT30 16
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_7_LUTOUT30 0x00FF0000
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_7_LUTOUT30(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X8_OUT1_7_LUTOUT30)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_7_LUTOUT29 8
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_7_LUTOUT29 0x0000FF00
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_7_LUTOUT29(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X8_OUT1_7_LUTOUT29)
+#define BP_PXP_WFE_B_STG1_5X8_OUT1_7_LUTOUT28 0
+#define BM_PXP_WFE_B_STG1_5X8_OUT1_7_LUTOUT28 0x000000FF
+#define BF_PXP_WFE_B_STG1_5X8_OUT1_7_LUTOUT28(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X8_OUT1_7_LUTOUT28)
+
+#define HW_PXP_WFE_B_STAGE1_5X8_MASKS_0 (0x00002060)
+
+#define BP_PXP_WFE_B_STAGE1_5X8_MASKS_0_RSVD2 13
+#define BM_PXP_WFE_B_STAGE1_5X8_MASKS_0_RSVD2 0xFFFFE000
+#define BF_PXP_WFE_B_STAGE1_5X8_MASKS_0_RSVD2(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STAGE1_5X8_MASKS_0_RSVD2)
+#define BP_PXP_WFE_B_STAGE1_5X8_MASKS_0_MASK1 8
+#define BM_PXP_WFE_B_STAGE1_5X8_MASKS_0_MASK1 0x00001F00
+#define BF_PXP_WFE_B_STAGE1_5X8_MASKS_0_MASK1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE1_5X8_MASKS_0_MASK1)
+#define BP_PXP_WFE_B_STAGE1_5X8_MASKS_0_RSVD3 5
+#define BM_PXP_WFE_B_STAGE1_5X8_MASKS_0_RSVD3 0x000000E0
+#define BF_PXP_WFE_B_STAGE1_5X8_MASKS_0_RSVD3(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STAGE1_5X8_MASKS_0_RSVD3)
+#define BP_PXP_WFE_B_STAGE1_5X8_MASKS_0_MASK0 0
+#define BM_PXP_WFE_B_STAGE1_5X8_MASKS_0_MASK0 0x0000001F
+#define BF_PXP_WFE_B_STAGE1_5X8_MASKS_0_MASK0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE1_5X8_MASKS_0_MASK0)
+
+#define HW_PXP_WFE_B_STG1_5X1_OUT0 (0x00002070)
+
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT31 0x80000000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT31)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT30 0x40000000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT30)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT29 0x20000000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT29)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT28 0x10000000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT28)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT27 0x08000000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT27)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT26 0x04000000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT26)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT25 0x02000000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT25)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT24 0x01000000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT24)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT23 0x00800000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT23)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT22 0x00400000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT22)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT21 0x00200000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT21)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT20 0x00100000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT20)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT19 0x00080000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT19)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT18 0x00040000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT18)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT17 0x00020000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT17)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT16 0x00010000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT16)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT15 0x00008000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT15)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT14 0x00004000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT14)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT13 0x00002000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT13)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT12 0x00001000
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT12)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT11 0x00000800
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT11)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT10 0x00000400
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT10)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT9 0x00000200
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT9)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT8 0x00000100
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT8)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT7 0x00000080
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT7)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT6 0x00000040
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT6)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT5 0x00000020
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT5)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT4 0x00000010
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT4)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT3 0x00000008
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT3)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT2 0x00000004
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT2)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT1 0x00000002
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT1)
+#define BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT0 0x00000001
+#define BF_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X1_OUT0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG1_5X1_MASKS (0x00002080)
+
+#define BP_PXP_WFE_B_STG1_5X1_MASKS_RSVD0 5
+#define BM_PXP_WFE_B_STG1_5X1_MASKS_RSVD0 0xFFFFFFE0
+#define BF_PXP_WFE_B_STG1_5X1_MASKS_RSVD0(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_5X1_MASKS_RSVD0)
+#define BP_PXP_WFE_B_STG1_5X1_MASKS_MASK0 0
+#define BM_PXP_WFE_B_STG1_5X1_MASKS_MASK0 0x0000001F
+#define BF_PXP_WFE_B_STG1_5X1_MASKS_MASK0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_5X1_MASKS_MASK0)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT0_0 (0x00002090)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT31 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT31)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT30 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT30)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT29 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT29)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT28 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT28)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT27 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT27)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT26 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT26)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT25 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT25)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT24 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT24)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT23 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT23)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT22 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT22)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT21 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT21)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT20 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT20)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT19 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT19)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT18 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT18)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT17 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT17)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT16 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT16)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT15 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT15)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT14 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT14)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT13 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT13)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT12 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT12)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT11 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT11)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT10 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT10)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT9 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT9)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT8 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT8)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT7 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT7)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT6 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT6)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT5 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT5)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT4 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT4)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT3 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT3)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT2 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT2)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT1 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT1)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT0 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT0_0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT0_1 (0x000020a0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT63 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT63(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT63)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT62 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT62(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT62)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT61 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT61(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT61)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT60 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT60(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT60)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT59 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT59(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT59)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT58 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT58(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT58)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT57 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT57(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT57)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT56 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT56(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT56)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT55 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT55(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT55)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT54 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT54(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT54)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT53 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT53(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT53)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT52 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT52(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT52)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT51 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT51(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT51)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT50 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT50(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT50)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT49 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT49(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT49)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT48 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT48(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT48)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT47 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT47(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT47)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT46 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT46(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT46)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT45 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT45(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT45)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT44 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT44(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT44)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT43 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT43(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT43)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT42 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT42(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT42)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT41 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT41(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT41)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT40 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT40(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT40)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT39 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT39(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT39)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT38 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT38(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT38)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT37 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT37(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT37)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT36 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT36(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT36)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT35 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT35(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT35)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT34 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT34(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT34)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT33 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT33(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT33)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT32 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT32(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT0_1_LUTOUT32)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT0_2 (0x000020b0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT95 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT95(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT95)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT94 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT94(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT94)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT93 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT93(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT93)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT92 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT92(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT92)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT91 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT91(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT91)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT90 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT90(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT90)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT89 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT89(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT89)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT88 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT88(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT88)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT87 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT87(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT87)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT86 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT86(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT86)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT85 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT85(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT85)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT84 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT84(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT84)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT83 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT83(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT83)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT82 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT82(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT82)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT81 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT81(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT81)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT80 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT80(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT80)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT79 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT79(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT79)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT78 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT78(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT78)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT77 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT77(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT77)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT76 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT76(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT76)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT75 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT75(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT75)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT74 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT74(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT74)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT73 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT73(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT73)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT72 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT72(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT72)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT71 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT71(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT71)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT70 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT70(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT70)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT69 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT69(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT69)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT68 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT68(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT68)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT67 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT67(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT67)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT66 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT66(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT66)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT65 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT65(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT65)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT64 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT64(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT0_2_LUTOUT64)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT0_3 (0x000020c0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT127 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT127(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT127)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT126 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT126(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT126)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT125 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT125(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT125)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT124 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT124(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT124)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT123 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT123(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT123)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT122 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT122(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT122)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT121 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT121(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT121)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT120 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT120(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT120)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT119 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT119(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT119)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT118 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT118(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT118)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT117 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT117(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT117)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT116 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT116(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT116)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT115 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT115(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT115)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT114 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT114(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT114)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT113 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT113(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT113)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT112 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT112(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT112)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT111 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT111(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT111)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT110 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT110(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT110)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT109 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT109(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT109)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT108 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT108(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT108)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT107 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT107(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT107)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT106 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT106(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT106)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT105 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT105(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT105)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT104 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT104(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT104)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT103 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT103(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT103)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT102 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT102(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT102)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT101 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT101(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT101)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT100 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT100(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT100)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT99 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT99(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT99)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT98 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT98(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT98)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT97 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT97(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT97)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT96 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT96(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT0_3_LUTOUT96)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT0_4 (0x000020d0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT159 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT159(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT159)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT158 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT158(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT158)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT157 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT157(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT157)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT156 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT156(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT156)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT155 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT155(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT155)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT154 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT154(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT154)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT153 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT153(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT153)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT152 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT152(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT152)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT151 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT151(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT151)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT150 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT150(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT150)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT149 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT149(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT149)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT148 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT148(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT148)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT147 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT147(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT147)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT146 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT146(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT146)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT145 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT145(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT145)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT144 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT144(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT144)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT143 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT143(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT143)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT142 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT142(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT142)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT141 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT141(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT141)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT140 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT140(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT140)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT139 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT139(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT139)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT138 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT138(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT138)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT137 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT137(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT137)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT136 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT136(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT136)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT135 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT135(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT135)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT134 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT134(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT134)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT133 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT133(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT133)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT132 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT132(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT132)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT131 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT131(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT131)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT130 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT130(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT130)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT129 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT129(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT129)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT128 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT128(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT0_4_LUTOUT128)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT0_5 (0x000020e0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT191 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT191(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT191)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT190 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT190(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT190)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT189 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT189(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT189)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT188 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT188(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT188)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT187 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT187(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT187)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT186 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT186(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT186)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT185 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT185(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT185)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT184 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT184(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT184)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT183 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT183(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT183)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT182 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT182(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT182)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT181 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT181(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT181)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT180 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT180(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT180)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT179 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT179(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT179)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT178 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT178(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT178)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT177 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT177(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT177)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT176 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT176(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT176)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT175 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT175(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT175)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT174 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT174(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT174)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT173 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT173(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT173)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT172 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT172(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT172)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT171 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT171(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT171)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT170 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT170(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT170)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT169 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT169(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT169)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT168 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT168(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT168)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT167 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT167(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT167)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT166 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT166(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT166)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT165 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT165(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT165)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT164 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT164(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT164)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT163 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT163(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT163)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT162 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT162(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT162)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT161 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT161(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT161)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT160 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT160(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT0_5_LUTOUT160)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT0_6 (0x000020f0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT223 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT223(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT223)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT222 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT222(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT222)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT221 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT221(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT221)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT220 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT220(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT220)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT219 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT219(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT219)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT218 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT218(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT218)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT217 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT217(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT217)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT216 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT216(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT216)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT215 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT215(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT215)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT214 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT214(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT214)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT213 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT213(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT213)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT212 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT212(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT212)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT211 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT211(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT211)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT210 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT210(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT210)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT209 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT209(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT209)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT208 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT208(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT208)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT207 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT207(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT207)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT206 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT206(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT206)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT205 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT205(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT205)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT204 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT204(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT204)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT203 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT203(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT203)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT202 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT202(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT202)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT201 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT201(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT201)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT200 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT200(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT200)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT199 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT199(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT199)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT198 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT198(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT198)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT197 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT197(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT197)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT196 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT196(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT196)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT195 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT195(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT195)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT194 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT194(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT194)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT193 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT193(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT193)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT192 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT192(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT0_6_LUTOUT192)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT0_7 (0x00002100)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT255 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT255(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT255)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT254 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT254(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT254)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT253 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT253(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT253)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT252 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT252(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT252)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT251 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT251(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT251)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT250 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT250(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT250)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT249 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT249(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT249)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT248 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT248(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT248)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT247 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT247(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT247)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT246 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT246(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT246)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT245 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT245(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT245)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT244 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT244(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT244)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT243 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT243(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT243)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT242 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT242(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT242)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT241 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT241(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT241)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT240 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT240(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT240)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT239 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT239(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT239)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT238 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT238(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT238)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT237 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT237(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT237)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT236 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT236(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT236)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT235 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT235(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT235)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT234 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT234(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT234)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT233 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT233(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT233)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT232 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT232(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT232)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT231 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT231(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT231)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT230 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT230(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT230)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT229 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT229(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT229)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT228 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT228(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT228)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT227 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT227(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT227)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT226 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT226(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT226)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT225 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT225(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT225)
+#define BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT224 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT224(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT0_7_LUTOUT224)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT1_0 (0x00002110)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT31 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT31)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT30 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT30)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT29 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT29)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT28 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT28)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT27 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT27)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT26 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT26)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT25 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT25)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT24 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT24)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT23 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT23)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT22 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT22)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT21 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT21)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT20 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT20)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT19 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT19)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT18 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT18)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT17 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT17)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT16 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT16)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT15 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT15)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT14 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT14)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT13 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT13)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT12 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT12)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT11 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT11)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT10 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT10)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT9 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT9)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT8 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT8)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT7 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT7)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT6 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT6)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT5 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT5)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT4 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT4)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT3 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT3)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT2 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT2)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT1 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT1)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT0 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT1_0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT1_1 (0x00002120)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT63 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT63(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT63)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT62 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT62(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT62)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT61 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT61(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT61)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT60 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT60(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT60)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT59 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT59(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT59)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT58 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT58(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT58)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT57 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT57(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT57)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT56 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT56(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT56)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT55 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT55(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT55)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT54 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT54(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT54)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT53 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT53(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT53)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT52 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT52(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT52)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT51 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT51(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT51)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT50 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT50(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT50)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT49 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT49(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT49)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT48 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT48(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT48)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT47 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT47(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT47)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT46 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT46(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT46)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT45 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT45(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT45)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT44 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT44(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT44)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT43 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT43(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT43)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT42 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT42(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT42)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT41 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT41(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT41)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT40 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT40(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT40)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT39 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT39(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT39)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT38 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT38(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT38)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT37 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT37(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT37)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT36 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT36(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT36)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT35 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT35(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT35)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT34 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT34(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT34)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT33 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT33(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT33)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT32 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT32(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT1_1_LUTOUT32)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT1_2 (0x00002130)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT95 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT95(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT95)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT94 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT94(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT94)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT93 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT93(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT93)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT92 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT92(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT92)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT91 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT91(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT91)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT90 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT90(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT90)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT89 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT89(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT89)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT88 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT88(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT88)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT87 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT87(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT87)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT86 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT86(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT86)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT85 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT85(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT85)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT84 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT84(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT84)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT83 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT83(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT83)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT82 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT82(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT82)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT81 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT81(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT81)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT80 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT80(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT80)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT79 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT79(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT79)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT78 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT78(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT78)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT77 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT77(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT77)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT76 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT76(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT76)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT75 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT75(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT75)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT74 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT74(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT74)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT73 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT73(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT73)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT72 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT72(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT72)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT71 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT71(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT71)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT70 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT70(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT70)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT69 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT69(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT69)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT68 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT68(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT68)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT67 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT67(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT67)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT66 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT66(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT66)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT65 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT65(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT65)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT64 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT64(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT1_2_LUTOUT64)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT1_3 (0x00002140)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT127 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT127(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT127)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT126 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT126(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT126)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT125 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT125(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT125)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT124 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT124(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT124)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT123 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT123(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT123)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT122 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT122(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT122)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT121 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT121(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT121)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT120 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT120(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT120)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT119 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT119(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT119)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT118 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT118(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT118)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT117 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT117(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT117)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT116 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT116(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT116)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT115 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT115(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT115)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT114 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT114(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT114)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT113 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT113(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT113)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT112 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT112(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT112)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT111 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT111(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT111)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT110 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT110(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT110)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT109 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT109(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT109)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT108 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT108(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT108)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT107 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT107(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT107)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT106 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT106(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT106)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT105 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT105(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT105)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT104 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT104(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT104)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT103 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT103(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT103)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT102 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT102(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT102)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT101 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT101(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT101)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT100 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT100(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT100)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT99 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT99(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT99)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT98 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT98(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT98)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT97 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT97(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT97)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT96 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT96(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT1_3_LUTOUT96)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT1_4 (0x00002150)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT159 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT159(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT159)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT158 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT158(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT158)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT157 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT157(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT157)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT156 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT156(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT156)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT155 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT155(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT155)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT154 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT154(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT154)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT153 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT153(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT153)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT152 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT152(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT152)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT151 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT151(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT151)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT150 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT150(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT150)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT149 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT149(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT149)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT148 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT148(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT148)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT147 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT147(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT147)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT146 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT146(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT146)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT145 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT145(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT145)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT144 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT144(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT144)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT143 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT143(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT143)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT142 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT142(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT142)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT141 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT141(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT141)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT140 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT140(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT140)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT139 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT139(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT139)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT138 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT138(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT138)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT137 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT137(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT137)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT136 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT136(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT136)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT135 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT135(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT135)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT134 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT134(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT134)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT133 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT133(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT133)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT132 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT132(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT132)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT131 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT131(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT131)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT130 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT130(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT130)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT129 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT129(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT129)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT128 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT128(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT1_4_LUTOUT128)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT1_5 (0x00002160)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT191 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT191(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT191)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT190 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT190(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT190)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT189 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT189(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT189)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT188 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT188(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT188)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT187 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT187(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT187)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT186 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT186(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT186)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT185 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT185(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT185)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT184 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT184(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT184)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT183 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT183(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT183)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT182 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT182(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT182)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT181 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT181(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT181)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT180 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT180(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT180)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT179 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT179(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT179)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT178 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT178(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT178)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT177 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT177(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT177)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT176 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT176(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT176)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT175 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT175(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT175)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT174 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT174(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT174)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT173 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT173(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT173)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT172 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT172(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT172)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT171 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT171(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT171)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT170 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT170(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT170)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT169 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT169(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT169)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT168 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT168(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT168)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT167 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT167(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT167)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT166 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT166(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT166)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT165 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT165(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT165)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT164 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT164(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT164)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT163 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT163(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT163)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT162 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT162(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT162)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT161 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT161(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT161)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT160 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT160(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT1_5_LUTOUT160)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT1_6 (0x00002170)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT223 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT223(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT223)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT222 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT222(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT222)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT221 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT221(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT221)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT220 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT220(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT220)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT219 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT219(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT219)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT218 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT218(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT218)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT217 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT217(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT217)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT216 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT216(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT216)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT215 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT215(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT215)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT214 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT214(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT214)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT213 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT213(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT213)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT212 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT212(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT212)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT211 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT211(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT211)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT210 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT210(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT210)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT209 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT209(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT209)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT208 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT208(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT208)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT207 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT207(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT207)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT206 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT206(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT206)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT205 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT205(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT205)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT204 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT204(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT204)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT203 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT203(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT203)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT202 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT202(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT202)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT201 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT201(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT201)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT200 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT200(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT200)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT199 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT199(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT199)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT198 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT198(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT198)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT197 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT197(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT197)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT196 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT196(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT196)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT195 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT195(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT195)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT194 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT194(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT194)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT193 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT193(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT193)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT192 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT192(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT1_6_LUTOUT192)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT1_7 (0x00002180)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT255 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT255(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT255)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT254 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT254(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT254)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT253 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT253(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT253)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT252 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT252(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT252)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT251 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT251(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT251)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT250 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT250(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT250)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT249 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT249(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT249)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT248 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT248(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT248)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT247 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT247(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT247)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT246 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT246(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT246)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT245 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT245(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT245)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT244 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT244(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT244)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT243 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT243(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT243)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT242 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT242(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT242)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT241 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT241(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT241)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT240 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT240(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT240)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT239 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT239(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT239)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT238 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT238(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT238)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT237 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT237(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT237)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT236 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT236(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT236)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT235 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT235(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT235)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT234 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT234(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT234)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT233 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT233(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT233)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT232 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT232(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT232)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT231 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT231(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT231)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT230 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT230(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT230)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT229 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT229(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT229)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT228 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT228(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT228)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT227 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT227(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT227)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT226 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT226(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT226)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT225 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT225(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT225)
+#define BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT224 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT224(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT1_7_LUTOUT224)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT2_0 (0x00002190)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT31 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT31)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT30 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT30)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT29 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT29)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT28 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT28)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT27 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT27)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT26 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT26)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT25 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT25)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT24 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT24)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT23 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT23)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT22 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT22)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT21 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT21)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT20 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT20)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT19 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT19)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT18 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT18)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT17 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT17)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT16 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT16)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT15 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT15)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT14 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT14)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT13 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT13)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT12 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT12)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT11 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT11)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT10 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT10)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT9 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT9)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT8 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT8)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT7 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT7)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT6 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT6)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT5 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT5)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT4 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT4)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT3 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT3)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT2 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT2)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT1 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT1)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT0 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT2_0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT2_1 (0x000021a0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT63 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT63(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT63)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT62 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT62(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT62)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT61 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT61(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT61)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT60 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT60(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT60)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT59 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT59(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT59)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT58 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT58(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT58)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT57 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT57(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT57)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT56 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT56(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT56)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT55 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT55(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT55)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT54 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT54(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT54)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT53 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT53(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT53)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT52 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT52(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT52)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT51 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT51(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT51)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT50 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT50(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT50)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT49 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT49(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT49)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT48 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT48(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT48)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT47 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT47(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT47)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT46 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT46(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT46)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT45 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT45(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT45)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT44 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT44(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT44)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT43 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT43(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT43)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT42 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT42(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT42)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT41 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT41(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT41)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT40 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT40(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT40)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT39 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT39(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT39)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT38 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT38(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT38)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT37 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT37(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT37)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT36 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT36(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT36)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT35 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT35(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT35)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT34 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT34(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT34)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT33 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT33(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT33)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT32 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT32(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT2_1_LUTOUT32)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT2_2 (0x000021b0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT95 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT95(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT95)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT94 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT94(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT94)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT93 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT93(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT93)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT92 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT92(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT92)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT91 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT91(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT91)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT90 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT90(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT90)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT89 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT89(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT89)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT88 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT88(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT88)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT87 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT87(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT87)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT86 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT86(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT86)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT85 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT85(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT85)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT84 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT84(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT84)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT83 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT83(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT83)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT82 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT82(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT82)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT81 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT81(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT81)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT80 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT80(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT80)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT79 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT79(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT79)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT78 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT78(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT78)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT77 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT77(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT77)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT76 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT76(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT76)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT75 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT75(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT75)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT74 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT74(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT74)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT73 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT73(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT73)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT72 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT72(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT72)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT71 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT71(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT71)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT70 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT70(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT70)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT69 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT69(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT69)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT68 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT68(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT68)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT67 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT67(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT67)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT66 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT66(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT66)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT65 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT65(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT65)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT64 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT64(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT2_2_LUTOUT64)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT2_3 (0x000021c0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT127 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT127(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT127)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT126 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT126(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT126)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT125 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT125(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT125)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT124 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT124(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT124)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT123 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT123(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT123)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT122 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT122(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT122)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT121 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT121(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT121)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT120 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT120(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT120)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT119 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT119(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT119)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT118 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT118(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT118)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT117 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT117(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT117)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT116 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT116(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT116)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT115 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT115(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT115)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT114 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT114(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT114)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT113 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT113(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT113)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT112 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT112(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT112)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT111 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT111(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT111)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT110 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT110(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT110)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT109 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT109(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT109)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT108 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT108(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT108)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT107 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT107(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT107)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT106 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT106(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT106)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT105 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT105(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT105)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT104 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT104(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT104)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT103 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT103(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT103)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT102 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT102(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT102)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT101 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT101(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT101)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT100 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT100(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT100)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT99 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT99(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT99)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT98 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT98(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT98)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT97 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT97(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT97)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT96 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT96(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT2_3_LUTOUT96)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT2_4 (0x000021d0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT159 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT159(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT159)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT158 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT158(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT158)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT157 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT157(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT157)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT156 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT156(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT156)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT155 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT155(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT155)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT154 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT154(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT154)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT153 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT153(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT153)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT152 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT152(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT152)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT151 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT151(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT151)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT150 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT150(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT150)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT149 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT149(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT149)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT148 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT148(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT148)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT147 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT147(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT147)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT146 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT146(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT146)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT145 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT145(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT145)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT144 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT144(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT144)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT143 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT143(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT143)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT142 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT142(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT142)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT141 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT141(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT141)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT140 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT140(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT140)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT139 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT139(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT139)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT138 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT138(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT138)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT137 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT137(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT137)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT136 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT136(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT136)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT135 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT135(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT135)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT134 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT134(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT134)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT133 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT133(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT133)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT132 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT132(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT132)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT131 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT131(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT131)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT130 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT130(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT130)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT129 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT129(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT129)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT128 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT128(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT2_4_LUTOUT128)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT2_5 (0x000021e0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT191 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT191(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT191)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT190 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT190(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT190)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT189 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT189(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT189)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT188 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT188(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT188)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT187 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT187(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT187)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT186 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT186(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT186)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT185 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT185(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT185)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT184 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT184(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT184)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT183 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT183(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT183)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT182 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT182(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT182)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT181 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT181(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT181)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT180 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT180(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT180)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT179 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT179(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT179)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT178 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT178(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT178)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT177 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT177(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT177)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT176 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT176(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT176)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT175 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT175(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT175)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT174 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT174(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT174)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT173 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT173(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT173)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT172 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT172(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT172)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT171 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT171(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT171)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT170 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT170(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT170)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT169 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT169(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT169)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT168 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT168(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT168)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT167 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT167(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT167)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT166 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT166(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT166)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT165 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT165(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT165)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT164 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT164(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT164)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT163 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT163(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT163)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT162 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT162(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT162)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT161 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT161(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT161)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT160 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT160(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT2_5_LUTOUT160)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT2_6 (0x000021f0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT223 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT223(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT223)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT222 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT222(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT222)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT221 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT221(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT221)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT220 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT220(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT220)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT219 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT219(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT219)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT218 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT218(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT218)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT217 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT217(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT217)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT216 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT216(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT216)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT215 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT215(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT215)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT214 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT214(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT214)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT213 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT213(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT213)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT212 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT212(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT212)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT211 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT211(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT211)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT210 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT210(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT210)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT209 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT209(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT209)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT208 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT208(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT208)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT207 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT207(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT207)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT206 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT206(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT206)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT205 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT205(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT205)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT204 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT204(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT204)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT203 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT203(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT203)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT202 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT202(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT202)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT201 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT201(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT201)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT200 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT200(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT200)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT199 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT199(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT199)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT198 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT198(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT198)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT197 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT197(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT197)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT196 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT196(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT196)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT195 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT195(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT195)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT194 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT194(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT194)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT193 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT193(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT193)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT192 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT192(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT2_6_LUTOUT192)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT2_7 (0x00002200)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT255 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT255(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT255)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT254 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT254(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT254)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT253 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT253(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT253)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT252 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT252(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT252)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT251 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT251(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT251)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT250 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT250(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT250)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT249 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT249(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT249)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT248 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT248(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT248)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT247 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT247(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT247)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT246 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT246(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT246)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT245 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT245(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT245)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT244 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT244(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT244)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT243 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT243(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT243)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT242 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT242(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT242)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT241 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT241(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT241)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT240 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT240(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT240)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT239 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT239(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT239)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT238 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT238(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT238)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT237 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT237(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT237)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT236 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT236(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT236)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT235 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT235(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT235)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT234 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT234(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT234)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT233 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT233(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT233)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT232 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT232(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT232)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT231 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT231(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT231)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT230 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT230(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT230)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT229 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT229(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT229)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT228 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT228(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT228)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT227 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT227(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT227)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT226 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT226(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT226)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT225 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT225(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT225)
+#define BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT224 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT224(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT2_7_LUTOUT224)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT3_0 (0x00002210)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT31 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT31)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT30 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT30)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT29 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT29)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT28 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT28)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT27 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT27)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT26 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT26)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT25 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT25)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT24 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT24)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT23 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT23)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT22 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT22)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT21 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT21)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT20 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT20)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT19 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT19)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT18 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT18)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT17 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT17)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT16 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT16)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT15 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT15)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT14 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT14)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT13 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT13)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT12 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT12)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT11 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT11)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT10 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT10)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT9 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT9)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT8 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT8)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT7 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT7)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT6 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT6)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT5 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT5)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT4 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT4)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT3 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT3)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT2 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT2)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT1 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT1)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT0 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT3_0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT3_1 (0x00002220)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT63 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT63(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT63)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT62 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT62(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT62)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT61 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT61(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT61)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT60 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT60(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT60)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT59 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT59(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT59)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT58 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT58(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT58)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT57 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT57(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT57)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT56 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT56(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT56)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT55 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT55(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT55)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT54 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT54(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT54)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT53 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT53(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT53)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT52 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT52(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT52)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT51 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT51(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT51)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT50 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT50(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT50)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT49 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT49(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT49)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT48 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT48(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT48)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT47 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT47(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT47)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT46 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT46(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT46)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT45 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT45(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT45)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT44 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT44(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT44)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT43 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT43(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT43)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT42 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT42(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT42)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT41 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT41(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT41)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT40 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT40(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT40)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT39 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT39(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT39)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT38 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT38(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT38)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT37 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT37(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT37)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT36 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT36(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT36)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT35 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT35(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT35)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT34 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT34(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT34)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT33 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT33(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT33)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT32 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT32(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT3_1_LUTOUT32)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT3_2 (0x00002230)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT95 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT95(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT95)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT94 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT94(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT94)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT93 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT93(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT93)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT92 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT92(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT92)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT91 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT91(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT91)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT90 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT90(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT90)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT89 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT89(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT89)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT88 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT88(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT88)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT87 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT87(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT87)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT86 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT86(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT86)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT85 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT85(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT85)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT84 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT84(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT84)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT83 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT83(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT83)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT82 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT82(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT82)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT81 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT81(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT81)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT80 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT80(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT80)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT79 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT79(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT79)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT78 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT78(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT78)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT77 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT77(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT77)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT76 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT76(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT76)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT75 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT75(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT75)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT74 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT74(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT74)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT73 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT73(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT73)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT72 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT72(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT72)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT71 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT71(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT71)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT70 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT70(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT70)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT69 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT69(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT69)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT68 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT68(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT68)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT67 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT67(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT67)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT66 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT66(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT66)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT65 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT65(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT65)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT64 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT64(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT3_2_LUTOUT64)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT3_3 (0x00002240)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT127 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT127(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT127)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT126 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT126(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT126)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT125 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT125(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT125)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT124 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT124(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT124)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT123 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT123(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT123)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT122 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT122(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT122)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT121 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT121(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT121)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT120 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT120(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT120)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT119 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT119(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT119)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT118 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT118(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT118)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT117 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT117(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT117)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT116 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT116(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT116)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT115 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT115(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT115)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT114 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT114(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT114)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT113 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT113(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT113)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT112 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT112(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT112)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT111 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT111(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT111)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT110 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT110(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT110)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT109 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT109(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT109)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT108 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT108(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT108)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT107 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT107(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT107)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT106 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT106(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT106)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT105 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT105(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT105)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT104 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT104(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT104)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT103 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT103(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT103)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT102 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT102(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT102)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT101 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT101(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT101)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT100 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT100(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT100)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT99 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT99(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT99)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT98 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT98(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT98)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT97 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT97(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT97)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT96 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT96(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT3_3_LUTOUT96)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT3_4 (0x00002250)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT159 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT159(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT159)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT158 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT158(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT158)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT157 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT157(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT157)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT156 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT156(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT156)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT155 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT155(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT155)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT154 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT154(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT154)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT153 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT153(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT153)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT152 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT152(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT152)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT151 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT151(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT151)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT150 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT150(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT150)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT149 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT149(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT149)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT148 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT148(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT148)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT147 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT147(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT147)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT146 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT146(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT146)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT145 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT145(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT145)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT144 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT144(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT144)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT143 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT143(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT143)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT142 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT142(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT142)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT141 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT141(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT141)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT140 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT140(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT140)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT139 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT139(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT139)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT138 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT138(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT138)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT137 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT137(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT137)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT136 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT136(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT136)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT135 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT135(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT135)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT134 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT134(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT134)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT133 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT133(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT133)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT132 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT132(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT132)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT131 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT131(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT131)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT130 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT130(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT130)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT129 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT129(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT129)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT128 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT128(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT3_4_LUTOUT128)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT3_5 (0x00002260)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT191 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT191(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT191)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT190 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT190(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT190)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT189 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT189(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT189)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT188 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT188(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT188)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT187 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT187(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT187)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT186 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT186(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT186)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT185 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT185(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT185)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT184 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT184(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT184)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT183 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT183(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT183)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT182 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT182(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT182)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT181 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT181(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT181)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT180 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT180(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT180)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT179 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT179(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT179)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT178 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT178(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT178)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT177 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT177(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT177)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT176 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT176(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT176)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT175 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT175(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT175)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT174 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT174(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT174)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT173 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT173(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT173)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT172 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT172(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT172)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT171 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT171(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT171)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT170 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT170(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT170)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT169 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT169(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT169)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT168 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT168(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT168)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT167 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT167(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT167)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT166 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT166(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT166)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT165 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT165(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT165)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT164 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT164(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT164)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT163 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT163(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT163)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT162 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT162(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT162)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT161 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT161(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT161)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT160 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT160(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT3_5_LUTOUT160)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT3_6 (0x00002270)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT223 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT223(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT223)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT222 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT222(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT222)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT221 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT221(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT221)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT220 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT220(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT220)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT219 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT219(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT219)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT218 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT218(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT218)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT217 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT217(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT217)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT216 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT216(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT216)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT215 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT215(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT215)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT214 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT214(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT214)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT213 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT213(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT213)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT212 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT212(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT212)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT211 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT211(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT211)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT210 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT210(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT210)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT209 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT209(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT209)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT208 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT208(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT208)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT207 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT207(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT207)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT206 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT206(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT206)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT205 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT205(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT205)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT204 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT204(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT204)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT203 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT203(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT203)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT202 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT202(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT202)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT201 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT201(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT201)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT200 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT200(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT200)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT199 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT199(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT199)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT198 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT198(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT198)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT197 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT197(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT197)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT196 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT196(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT196)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT195 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT195(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT195)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT194 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT194(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT194)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT193 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT193(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT193)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT192 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT192(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT3_6_LUTOUT192)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT3_7 (0x00002280)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT255 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT255(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT255)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT254 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT254(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT254)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT253 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT253(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT253)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT252 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT252(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT252)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT251 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT251(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT251)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT250 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT250(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT250)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT249 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT249(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT249)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT248 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT248(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT248)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT247 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT247(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT247)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT246 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT246(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT246)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT245 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT245(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT245)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT244 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT244(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT244)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT243 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT243(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT243)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT242 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT242(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT242)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT241 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT241(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT241)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT240 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT240(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT240)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT239 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT239(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT239)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT238 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT238(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT238)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT237 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT237(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT237)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT236 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT236(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT236)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT235 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT235(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT235)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT234 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT234(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT234)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT233 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT233(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT233)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT232 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT232(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT232)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT231 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT231(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT231)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT230 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT230(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT230)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT229 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT229(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT229)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT228 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT228(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT228)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT227 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT227(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT227)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT226 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT226(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT226)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT225 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT225(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT225)
+#define BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT224 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT224(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT3_7_LUTOUT224)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT4_0 (0x00002290)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT31 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT31)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT30 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT30)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT29 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT29)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT28 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT28)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT27 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT27)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT26 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT26)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT25 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT25)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT24 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT24)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT23 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT23)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT22 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT22)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT21 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT21)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT20 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT20)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT19 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT19)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT18 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT18)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT17 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT17)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT16 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT16)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT15 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT15)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT14 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT14)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT13 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT13)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT12 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT12)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT11 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT11)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT10 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT10)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT9 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT9)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT8 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT8)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT7 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT7)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT6 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT6)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT5 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT5)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT4 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT4)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT3 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT3)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT2 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT2)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT1 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT1)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT0 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT4_0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT4_1 (0x000022a0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT63 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT63(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT63)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT62 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT62(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT62)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT61 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT61(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT61)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT60 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT60(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT60)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT59 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT59(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT59)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT58 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT58(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT58)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT57 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT57(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT57)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT56 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT56(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT56)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT55 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT55(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT55)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT54 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT54(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT54)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT53 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT53(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT53)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT52 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT52(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT52)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT51 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT51(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT51)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT50 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT50(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT50)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT49 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT49(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT49)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT48 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT48(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT48)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT47 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT47(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT47)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT46 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT46(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT46)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT45 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT45(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT45)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT44 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT44(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT44)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT43 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT43(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT43)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT42 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT42(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT42)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT41 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT41(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT41)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT40 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT40(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT40)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT39 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT39(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT39)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT38 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT38(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT38)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT37 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT37(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT37)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT36 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT36(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT36)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT35 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT35(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT35)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT34 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT34(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT34)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT33 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT33(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT33)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT32 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT32(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT4_1_LUTOUT32)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT4_2 (0x000022b0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT95 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT95(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT95)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT94 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT94(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT94)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT93 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT93(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT93)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT92 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT92(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT92)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT91 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT91(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT91)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT90 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT90(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT90)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT89 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT89(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT89)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT88 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT88(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT88)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT87 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT87(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT87)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT86 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT86(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT86)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT85 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT85(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT85)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT84 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT84(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT84)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT83 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT83(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT83)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT82 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT82(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT82)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT81 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT81(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT81)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT80 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT80(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT80)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT79 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT79(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT79)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT78 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT78(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT78)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT77 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT77(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT77)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT76 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT76(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT76)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT75 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT75(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT75)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT74 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT74(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT74)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT73 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT73(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT73)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT72 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT72(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT72)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT71 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT71(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT71)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT70 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT70(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT70)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT69 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT69(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT69)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT68 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT68(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT68)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT67 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT67(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT67)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT66 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT66(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT66)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT65 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT65(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT65)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT64 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT64(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT4_2_LUTOUT64)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT4_3 (0x000022c0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT127 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT127(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT127)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT126 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT126(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT126)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT125 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT125(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT125)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT124 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT124(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT124)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT123 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT123(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT123)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT122 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT122(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT122)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT121 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT121(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT121)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT120 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT120(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT120)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT119 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT119(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT119)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT118 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT118(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT118)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT117 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT117(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT117)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT116 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT116(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT116)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT115 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT115(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT115)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT114 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT114(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT114)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT113 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT113(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT113)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT112 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT112(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT112)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT111 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT111(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT111)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT110 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT110(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT110)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT109 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT109(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT109)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT108 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT108(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT108)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT107 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT107(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT107)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT106 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT106(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT106)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT105 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT105(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT105)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT104 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT104(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT104)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT103 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT103(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT103)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT102 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT102(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT102)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT101 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT101(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT101)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT100 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT100(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT100)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT99 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT99(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT99)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT98 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT98(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT98)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT97 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT97(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT97)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT96 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT96(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT4_3_LUTOUT96)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT4_4 (0x000022d0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT159 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT159(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT159)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT158 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT158(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT158)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT157 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT157(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT157)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT156 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT156(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT156)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT155 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT155(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT155)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT154 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT154(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT154)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT153 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT153(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT153)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT152 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT152(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT152)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT151 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT151(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT151)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT150 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT150(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT150)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT149 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT149(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT149)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT148 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT148(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT148)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT147 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT147(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT147)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT146 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT146(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT146)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT145 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT145(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT145)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT144 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT144(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT144)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT143 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT143(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT143)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT142 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT142(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT142)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT141 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT141(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT141)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT140 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT140(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT140)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT139 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT139(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT139)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT138 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT138(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT138)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT137 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT137(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT137)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT136 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT136(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT136)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT135 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT135(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT135)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT134 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT134(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT134)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT133 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT133(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT133)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT132 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT132(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT132)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT131 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT131(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT131)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT130 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT130(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT130)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT129 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT129(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT129)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT128 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT128(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT4_4_LUTOUT128)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT4_5 (0x000022e0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT191 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT191(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT191)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT190 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT190(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT190)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT189 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT189(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT189)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT188 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT188(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT188)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT187 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT187(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT187)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT186 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT186(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT186)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT185 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT185(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT185)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT184 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT184(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT184)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT183 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT183(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT183)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT182 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT182(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT182)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT181 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT181(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT181)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT180 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT180(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT180)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT179 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT179(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT179)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT178 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT178(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT178)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT177 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT177(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT177)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT176 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT176(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT176)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT175 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT175(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT175)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT174 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT174(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT174)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT173 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT173(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT173)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT172 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT172(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT172)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT171 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT171(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT171)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT170 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT170(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT170)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT169 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT169(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT169)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT168 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT168(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT168)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT167 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT167(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT167)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT166 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT166(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT166)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT165 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT165(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT165)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT164 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT164(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT164)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT163 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT163(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT163)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT162 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT162(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT162)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT161 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT161(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT161)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT160 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT160(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT4_5_LUTOUT160)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT4_6 (0x000022f0)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT223 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT223(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT223)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT222 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT222(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT222)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT221 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT221(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT221)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT220 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT220(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT220)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT219 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT219(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT219)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT218 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT218(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT218)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT217 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT217(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT217)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT216 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT216(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT216)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT215 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT215(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT215)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT214 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT214(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT214)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT213 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT213(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT213)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT212 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT212(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT212)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT211 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT211(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT211)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT210 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT210(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT210)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT209 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT209(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT209)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT208 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT208(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT208)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT207 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT207(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT207)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT206 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT206(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT206)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT205 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT205(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT205)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT204 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT204(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT204)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT203 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT203(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT203)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT202 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT202(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT202)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT201 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT201(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT201)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT200 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT200(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT200)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT199 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT199(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT199)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT198 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT198(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT198)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT197 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT197(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT197)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT196 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT196(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT196)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT195 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT195(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT195)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT194 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT194(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT194)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT193 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT193(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT193)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT192 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT192(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT4_6_LUTOUT192)
+
+#define HW_PXP_WFE_B_STG1_8X1_OUT4_7 (0x00002300)
+
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT255 0x80000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT255(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT255)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT254 0x40000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT254(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT254)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT253 0x20000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT253(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT253)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT252 0x10000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT252(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT252)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT251 0x08000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT251(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT251)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT250 0x04000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT250(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT250)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT249 0x02000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT249(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT249)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT248 0x01000000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT248(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT248)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT247 0x00800000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT247(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT247)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT246 0x00400000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT246(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT246)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT245 0x00200000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT245(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT245)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT244 0x00100000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT244(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT244)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT243 0x00080000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT243(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT243)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT242 0x00040000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT242(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT242)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT241 0x00020000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT241(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT241)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT240 0x00010000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT240(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT240)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT239 0x00008000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT239(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT239)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT238 0x00004000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT238(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT238)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT237 0x00002000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT237(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT237)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT236 0x00001000
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT236(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT236)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT235 0x00000800
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT235(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT235)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT234 0x00000400
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT234(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT234)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT233 0x00000200
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT233(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT233)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT232 0x00000100
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT232(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT232)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT231 0x00000080
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT231(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT231)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT230 0x00000040
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT230(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT230)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT229 0x00000020
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT229(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT229)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT228 0x00000010
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT228(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT228)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT227 0x00000008
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT227(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT227)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT226 0x00000004
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT226(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT226)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT225 0x00000002
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT225(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT225)
+#define BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT224 0x00000001
+#define BF_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT224(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG1_8X1_OUT4_7_LUTOUT224)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT0_0 (0x00002310)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_0_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_0_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT0_0_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_0_LUTOUT3 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_0_LUTOUT3 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_0_LUTOUT3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT0_0_LUTOUT3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_0_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_0_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT0_0_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_0_LUTOUT2 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_0_LUTOUT2 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_0_LUTOUT2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT0_0_LUTOUT2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_0_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_0_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT0_0_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_0_LUTOUT1 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_0_LUTOUT1 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_0_LUTOUT1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT0_0_LUTOUT1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_0_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_0_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT0_0_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_0_LUTOUT0 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_0_LUTOUT0 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT0_0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT0_1 (0x00002320)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_1_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_1_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_1_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT0_1_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_1_LUTOUT7 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_1_LUTOUT7 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_1_LUTOUT7(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT0_1_LUTOUT7)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_1_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_1_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_1_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT0_1_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_1_LUTOUT6 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_1_LUTOUT6 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_1_LUTOUT6(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT0_1_LUTOUT6)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_1_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_1_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_1_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT0_1_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_1_LUTOUT5 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_1_LUTOUT5 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_1_LUTOUT5(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT0_1_LUTOUT5)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_1_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_1_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_1_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT0_1_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_1_LUTOUT4 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_1_LUTOUT4 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_1_LUTOUT4(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT0_1_LUTOUT4)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT0_2 (0x00002330)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_2_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_2_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_2_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT0_2_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_2_LUTOUT11 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_2_LUTOUT11 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_2_LUTOUT11(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT0_2_LUTOUT11)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_2_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_2_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_2_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT0_2_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_2_LUTOUT10 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_2_LUTOUT10 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_2_LUTOUT10(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT0_2_LUTOUT10)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_2_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_2_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_2_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT0_2_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_2_LUTOUT9 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_2_LUTOUT9 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_2_LUTOUT9(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT0_2_LUTOUT9)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_2_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_2_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_2_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT0_2_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_2_LUTOUT8 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_2_LUTOUT8 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_2_LUTOUT8(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT0_2_LUTOUT8)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT0_3 (0x00002340)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_3_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_3_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_3_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT0_3_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_3_LUTOUT15 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_3_LUTOUT15 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_3_LUTOUT15(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT0_3_LUTOUT15)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_3_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_3_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_3_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT0_3_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_3_LUTOUT14 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_3_LUTOUT14 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_3_LUTOUT14(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT0_3_LUTOUT14)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_3_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_3_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_3_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT0_3_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_3_LUTOUT13 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_3_LUTOUT13 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_3_LUTOUT13(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT0_3_LUTOUT13)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_3_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_3_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_3_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT0_3_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_3_LUTOUT12 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_3_LUTOUT12 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_3_LUTOUT12(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT0_3_LUTOUT12)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT0_4 (0x00002350)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_4_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_4_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_4_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT0_4_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_4_LUTOUT19 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_4_LUTOUT19 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_4_LUTOUT19(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT0_4_LUTOUT19)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_4_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_4_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_4_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT0_4_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_4_LUTOUT18 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_4_LUTOUT18 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_4_LUTOUT18(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT0_4_LUTOUT18)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_4_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_4_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_4_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT0_4_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_4_LUTOUT17 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_4_LUTOUT17 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_4_LUTOUT17(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT0_4_LUTOUT17)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_4_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_4_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_4_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT0_4_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_4_LUTOUT16 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_4_LUTOUT16 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_4_LUTOUT16(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT0_4_LUTOUT16)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT0_5 (0x00002360)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_5_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_5_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_5_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT0_5_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_5_LUTOUT23 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_5_LUTOUT23 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_5_LUTOUT23(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT0_5_LUTOUT23)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_5_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_5_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_5_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT0_5_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_5_LUTOUT22 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_5_LUTOUT22 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_5_LUTOUT22(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT0_5_LUTOUT22)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_5_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_5_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_5_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT0_5_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_5_LUTOUT21 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_5_LUTOUT21 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_5_LUTOUT21(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT0_5_LUTOUT21)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_5_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_5_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_5_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT0_5_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_5_LUTOUT20 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_5_LUTOUT20 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_5_LUTOUT20(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT0_5_LUTOUT20)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT0_6 (0x00002370)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_6_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_6_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_6_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT0_6_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_6_LUTOUT27 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_6_LUTOUT27 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_6_LUTOUT27(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT0_6_LUTOUT27)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_6_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_6_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_6_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT0_6_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_6_LUTOUT26 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_6_LUTOUT26 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_6_LUTOUT26(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT0_6_LUTOUT26)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_6_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_6_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_6_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT0_6_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_6_LUTOUT25 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_6_LUTOUT25 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_6_LUTOUT25(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT0_6_LUTOUT25)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_6_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_6_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_6_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT0_6_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_6_LUTOUT24 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_6_LUTOUT24 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_6_LUTOUT24(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT0_6_LUTOUT24)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT0_7 (0x00002380)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_7_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_7_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_7_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT0_7_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_7_LUTOUT31 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_7_LUTOUT31 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_7_LUTOUT31(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT0_7_LUTOUT31)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_7_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_7_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_7_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT0_7_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_7_LUTOUT30 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_7_LUTOUT30 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_7_LUTOUT30(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT0_7_LUTOUT30)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_7_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_7_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_7_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT0_7_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_7_LUTOUT29 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_7_LUTOUT29 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_7_LUTOUT29(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT0_7_LUTOUT29)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_7_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_7_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_7_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT0_7_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT0_7_LUTOUT28 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT0_7_LUTOUT28 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT0_7_LUTOUT28(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT0_7_LUTOUT28)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT1_0 (0x00002390)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_0_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_0_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT1_0_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_0_LUTOUT3 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_0_LUTOUT3 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_0_LUTOUT3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT1_0_LUTOUT3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_0_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_0_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT1_0_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_0_LUTOUT2 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_0_LUTOUT2 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_0_LUTOUT2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT1_0_LUTOUT2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_0_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_0_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT1_0_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_0_LUTOUT1 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_0_LUTOUT1 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_0_LUTOUT1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT1_0_LUTOUT1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_0_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_0_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT1_0_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_0_LUTOUT0 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_0_LUTOUT0 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT1_0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT1_1 (0x000023a0)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_1_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_1_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_1_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT1_1_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_1_LUTOUT7 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_1_LUTOUT7 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_1_LUTOUT7(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT1_1_LUTOUT7)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_1_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_1_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_1_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT1_1_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_1_LUTOUT6 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_1_LUTOUT6 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_1_LUTOUT6(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT1_1_LUTOUT6)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_1_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_1_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_1_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT1_1_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_1_LUTOUT5 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_1_LUTOUT5 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_1_LUTOUT5(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT1_1_LUTOUT5)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_1_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_1_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_1_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT1_1_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_1_LUTOUT4 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_1_LUTOUT4 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_1_LUTOUT4(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT1_1_LUTOUT4)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT1_2 (0x000023b0)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_2_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_2_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_2_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT1_2_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_2_LUTOUT11 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_2_LUTOUT11 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_2_LUTOUT11(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT1_2_LUTOUT11)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_2_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_2_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_2_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT1_2_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_2_LUTOUT10 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_2_LUTOUT10 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_2_LUTOUT10(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT1_2_LUTOUT10)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_2_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_2_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_2_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT1_2_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_2_LUTOUT9 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_2_LUTOUT9 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_2_LUTOUT9(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT1_2_LUTOUT9)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_2_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_2_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_2_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT1_2_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_2_LUTOUT8 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_2_LUTOUT8 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_2_LUTOUT8(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT1_2_LUTOUT8)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT1_3 (0x000023c0)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_3_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_3_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_3_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT1_3_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_3_LUTOUT15 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_3_LUTOUT15 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_3_LUTOUT15(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT1_3_LUTOUT15)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_3_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_3_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_3_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT1_3_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_3_LUTOUT14 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_3_LUTOUT14 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_3_LUTOUT14(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT1_3_LUTOUT14)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_3_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_3_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_3_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT1_3_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_3_LUTOUT13 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_3_LUTOUT13 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_3_LUTOUT13(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT1_3_LUTOUT13)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_3_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_3_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_3_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT1_3_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_3_LUTOUT12 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_3_LUTOUT12 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_3_LUTOUT12(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT1_3_LUTOUT12)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT1_4 (0x000023d0)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_4_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_4_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_4_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT1_4_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_4_LUTOUT19 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_4_LUTOUT19 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_4_LUTOUT19(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT1_4_LUTOUT19)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_4_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_4_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_4_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT1_4_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_4_LUTOUT18 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_4_LUTOUT18 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_4_LUTOUT18(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT1_4_LUTOUT18)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_4_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_4_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_4_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT1_4_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_4_LUTOUT17 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_4_LUTOUT17 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_4_LUTOUT17(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT1_4_LUTOUT17)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_4_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_4_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_4_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT1_4_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_4_LUTOUT16 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_4_LUTOUT16 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_4_LUTOUT16(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT1_4_LUTOUT16)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT1_5 (0x000023e0)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_5_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_5_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_5_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT1_5_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_5_LUTOUT23 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_5_LUTOUT23 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_5_LUTOUT23(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT1_5_LUTOUT23)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_5_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_5_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_5_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT1_5_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_5_LUTOUT22 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_5_LUTOUT22 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_5_LUTOUT22(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT1_5_LUTOUT22)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_5_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_5_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_5_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT1_5_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_5_LUTOUT21 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_5_LUTOUT21 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_5_LUTOUT21(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT1_5_LUTOUT21)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_5_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_5_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_5_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT1_5_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_5_LUTOUT20 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_5_LUTOUT20 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_5_LUTOUT20(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT1_5_LUTOUT20)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT1_6 (0x000023f0)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_6_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_6_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_6_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT1_6_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_6_LUTOUT27 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_6_LUTOUT27 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_6_LUTOUT27(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT1_6_LUTOUT27)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_6_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_6_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_6_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT1_6_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_6_LUTOUT26 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_6_LUTOUT26 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_6_LUTOUT26(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT1_6_LUTOUT26)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_6_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_6_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_6_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT1_6_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_6_LUTOUT25 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_6_LUTOUT25 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_6_LUTOUT25(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT1_6_LUTOUT25)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_6_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_6_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_6_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT1_6_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_6_LUTOUT24 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_6_LUTOUT24 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_6_LUTOUT24(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT1_6_LUTOUT24)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT1_7 (0x00002400)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_7_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_7_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_7_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT1_7_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_7_LUTOUT31 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_7_LUTOUT31 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_7_LUTOUT31(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT1_7_LUTOUT31)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_7_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_7_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_7_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT1_7_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_7_LUTOUT30 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_7_LUTOUT30 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_7_LUTOUT30(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT1_7_LUTOUT30)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_7_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_7_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_7_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT1_7_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_7_LUTOUT29 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_7_LUTOUT29 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_7_LUTOUT29(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT1_7_LUTOUT29)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_7_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_7_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_7_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT1_7_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT1_7_LUTOUT28 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT1_7_LUTOUT28 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT1_7_LUTOUT28(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT1_7_LUTOUT28)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT2_0 (0x00002410)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_0_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_0_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT2_0_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_0_LUTOUT3 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_0_LUTOUT3 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_0_LUTOUT3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT2_0_LUTOUT3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_0_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_0_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT2_0_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_0_LUTOUT2 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_0_LUTOUT2 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_0_LUTOUT2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT2_0_LUTOUT2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_0_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_0_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT2_0_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_0_LUTOUT1 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_0_LUTOUT1 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_0_LUTOUT1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT2_0_LUTOUT1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_0_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_0_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT2_0_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_0_LUTOUT0 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_0_LUTOUT0 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT2_0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT2_1 (0x00002420)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_1_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_1_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_1_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT2_1_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_1_LUTOUT7 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_1_LUTOUT7 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_1_LUTOUT7(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT2_1_LUTOUT7)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_1_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_1_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_1_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT2_1_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_1_LUTOUT6 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_1_LUTOUT6 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_1_LUTOUT6(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT2_1_LUTOUT6)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_1_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_1_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_1_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT2_1_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_1_LUTOUT5 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_1_LUTOUT5 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_1_LUTOUT5(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT2_1_LUTOUT5)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_1_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_1_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_1_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT2_1_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_1_LUTOUT4 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_1_LUTOUT4 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_1_LUTOUT4(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT2_1_LUTOUT4)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT2_2 (0x00002430)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_2_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_2_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_2_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT2_2_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_2_LUTOUT11 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_2_LUTOUT11 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_2_LUTOUT11(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT2_2_LUTOUT11)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_2_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_2_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_2_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT2_2_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_2_LUTOUT10 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_2_LUTOUT10 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_2_LUTOUT10(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT2_2_LUTOUT10)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_2_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_2_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_2_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT2_2_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_2_LUTOUT9 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_2_LUTOUT9 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_2_LUTOUT9(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT2_2_LUTOUT9)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_2_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_2_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_2_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT2_2_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_2_LUTOUT8 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_2_LUTOUT8 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_2_LUTOUT8(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT2_2_LUTOUT8)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT2_3 (0x00002440)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_3_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_3_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_3_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT2_3_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_3_LUTOUT15 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_3_LUTOUT15 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_3_LUTOUT15(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT2_3_LUTOUT15)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_3_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_3_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_3_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT2_3_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_3_LUTOUT14 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_3_LUTOUT14 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_3_LUTOUT14(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT2_3_LUTOUT14)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_3_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_3_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_3_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT2_3_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_3_LUTOUT13 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_3_LUTOUT13 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_3_LUTOUT13(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT2_3_LUTOUT13)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_3_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_3_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_3_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT2_3_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_3_LUTOUT12 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_3_LUTOUT12 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_3_LUTOUT12(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT2_3_LUTOUT12)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT2_4 (0x00002450)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_4_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_4_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_4_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT2_4_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_4_LUTOUT19 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_4_LUTOUT19 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_4_LUTOUT19(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT2_4_LUTOUT19)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_4_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_4_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_4_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT2_4_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_4_LUTOUT18 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_4_LUTOUT18 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_4_LUTOUT18(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT2_4_LUTOUT18)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_4_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_4_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_4_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT2_4_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_4_LUTOUT17 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_4_LUTOUT17 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_4_LUTOUT17(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT2_4_LUTOUT17)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_4_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_4_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_4_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT2_4_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_4_LUTOUT16 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_4_LUTOUT16 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_4_LUTOUT16(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT2_4_LUTOUT16)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT2_5 (0x00002460)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_5_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_5_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_5_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT2_5_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_5_LUTOUT23 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_5_LUTOUT23 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_5_LUTOUT23(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT2_5_LUTOUT23)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_5_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_5_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_5_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT2_5_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_5_LUTOUT22 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_5_LUTOUT22 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_5_LUTOUT22(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT2_5_LUTOUT22)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_5_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_5_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_5_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT2_5_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_5_LUTOUT21 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_5_LUTOUT21 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_5_LUTOUT21(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT2_5_LUTOUT21)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_5_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_5_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_5_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT2_5_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_5_LUTOUT20 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_5_LUTOUT20 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_5_LUTOUT20(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT2_5_LUTOUT20)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT2_6 (0x00002470)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_6_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_6_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_6_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT2_6_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_6_LUTOUT27 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_6_LUTOUT27 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_6_LUTOUT27(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT2_6_LUTOUT27)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_6_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_6_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_6_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT2_6_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_6_LUTOUT26 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_6_LUTOUT26 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_6_LUTOUT26(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT2_6_LUTOUT26)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_6_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_6_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_6_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT2_6_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_6_LUTOUT25 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_6_LUTOUT25 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_6_LUTOUT25(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT2_6_LUTOUT25)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_6_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_6_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_6_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT2_6_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_6_LUTOUT24 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_6_LUTOUT24 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_6_LUTOUT24(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT2_6_LUTOUT24)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT2_7 (0x00002480)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_7_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_7_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_7_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT2_7_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_7_LUTOUT31 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_7_LUTOUT31 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_7_LUTOUT31(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT2_7_LUTOUT31)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_7_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_7_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_7_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT2_7_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_7_LUTOUT30 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_7_LUTOUT30 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_7_LUTOUT30(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT2_7_LUTOUT30)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_7_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_7_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_7_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT2_7_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_7_LUTOUT29 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_7_LUTOUT29 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_7_LUTOUT29(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT2_7_LUTOUT29)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_7_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_7_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_7_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT2_7_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT2_7_LUTOUT28 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT2_7_LUTOUT28 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT2_7_LUTOUT28(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT2_7_LUTOUT28)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT3_0 (0x00002490)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_0_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_0_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_0_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT3_0_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_0_LUTOUT3 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_0_LUTOUT3 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_0_LUTOUT3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT3_0_LUTOUT3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_0_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_0_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_0_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT3_0_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_0_LUTOUT2 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_0_LUTOUT2 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_0_LUTOUT2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT3_0_LUTOUT2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_0_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_0_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_0_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT3_0_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_0_LUTOUT1 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_0_LUTOUT1 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_0_LUTOUT1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT3_0_LUTOUT1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_0_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_0_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_0_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT3_0_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_0_LUTOUT0 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_0_LUTOUT0 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT3_0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT3_1 (0x000024a0)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_1_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_1_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_1_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT3_1_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_1_LUTOUT7 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_1_LUTOUT7 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_1_LUTOUT7(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT3_1_LUTOUT7)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_1_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_1_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_1_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT3_1_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_1_LUTOUT6 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_1_LUTOUT6 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_1_LUTOUT6(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT3_1_LUTOUT6)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_1_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_1_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_1_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT3_1_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_1_LUTOUT5 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_1_LUTOUT5 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_1_LUTOUT5(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT3_1_LUTOUT5)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_1_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_1_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_1_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT3_1_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_1_LUTOUT4 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_1_LUTOUT4 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_1_LUTOUT4(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT3_1_LUTOUT4)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT3_2 (0x000024b0)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_2_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_2_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_2_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT3_2_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_2_LUTOUT11 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_2_LUTOUT11 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_2_LUTOUT11(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT3_2_LUTOUT11)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_2_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_2_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_2_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT3_2_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_2_LUTOUT10 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_2_LUTOUT10 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_2_LUTOUT10(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT3_2_LUTOUT10)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_2_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_2_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_2_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT3_2_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_2_LUTOUT9 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_2_LUTOUT9 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_2_LUTOUT9(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT3_2_LUTOUT9)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_2_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_2_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_2_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT3_2_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_2_LUTOUT8 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_2_LUTOUT8 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_2_LUTOUT8(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT3_2_LUTOUT8)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT3_3 (0x000024c0)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_3_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_3_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_3_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT3_3_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_3_LUTOUT15 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_3_LUTOUT15 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_3_LUTOUT15(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT3_3_LUTOUT15)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_3_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_3_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_3_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT3_3_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_3_LUTOUT14 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_3_LUTOUT14 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_3_LUTOUT14(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT3_3_LUTOUT14)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_3_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_3_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_3_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT3_3_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_3_LUTOUT13 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_3_LUTOUT13 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_3_LUTOUT13(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT3_3_LUTOUT13)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_3_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_3_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_3_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT3_3_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_3_LUTOUT12 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_3_LUTOUT12 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_3_LUTOUT12(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT3_3_LUTOUT12)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT3_4 (0x000024e0)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_4_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_4_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_4_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT3_4_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_4_LUTOUT19 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_4_LUTOUT19 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_4_LUTOUT19(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT3_4_LUTOUT19)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_4_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_4_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_4_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT3_4_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_4_LUTOUT18 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_4_LUTOUT18 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_4_LUTOUT18(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT3_4_LUTOUT18)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_4_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_4_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_4_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT3_4_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_4_LUTOUT17 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_4_LUTOUT17 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_4_LUTOUT17(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT3_4_LUTOUT17)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_4_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_4_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_4_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT3_4_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_4_LUTOUT16 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_4_LUTOUT16 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_4_LUTOUT16(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT3_4_LUTOUT16)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT3_5 (0x000024f0)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_5_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_5_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_5_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT3_5_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_5_LUTOUT23 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_5_LUTOUT23 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_5_LUTOUT23(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT3_5_LUTOUT23)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_5_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_5_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_5_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT3_5_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_5_LUTOUT22 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_5_LUTOUT22 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_5_LUTOUT22(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT3_5_LUTOUT22)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_5_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_5_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_5_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT3_5_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_5_LUTOUT21 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_5_LUTOUT21 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_5_LUTOUT21(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT3_5_LUTOUT21)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_5_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_5_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_5_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT3_5_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_5_LUTOUT20 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_5_LUTOUT20 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_5_LUTOUT20(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT3_5_LUTOUT20)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT3_6 (0x00002500)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_6_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_6_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_6_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT3_6_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_6_LUTOUT27 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_6_LUTOUT27 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_6_LUTOUT27(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT3_6_LUTOUT27)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_6_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_6_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_6_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT3_6_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_6_LUTOUT26 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_6_LUTOUT26 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_6_LUTOUT26(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT3_6_LUTOUT26)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_6_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_6_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_6_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT3_6_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_6_LUTOUT25 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_6_LUTOUT25 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_6_LUTOUT25(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT3_6_LUTOUT25)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_6_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_6_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_6_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT3_6_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_6_LUTOUT24 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_6_LUTOUT24 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_6_LUTOUT24(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT3_6_LUTOUT24)
+
+#define HW_PXP_WFE_B_STG2_5X6_OUT3_7 (0x00002510)
+
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_7_RSVD0 30
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_7_RSVD0 0xC0000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_7_RSVD0(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X6_OUT3_7_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_7_LUTOUT31 24
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_7_LUTOUT31 0x3F000000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_7_LUTOUT31(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X6_OUT3_7_LUTOUT31)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_7_RSVD1 22
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_7_RSVD1 0x00C00000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_7_RSVD1(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X6_OUT3_7_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_7_LUTOUT30 16
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_7_LUTOUT30 0x003F0000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_7_LUTOUT30(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X6_OUT3_7_LUTOUT30)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_7_RSVD2 14
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_7_RSVD2 0x0000C000
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_7_RSVD2(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X6_OUT3_7_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_7_LUTOUT29 8
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_7_LUTOUT29 0x00003F00
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_7_LUTOUT29(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X6_OUT3_7_LUTOUT29)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_7_RSVD3 6
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_7_RSVD3 0x000000C0
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_7_RSVD3(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X6_OUT3_7_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X6_OUT3_7_LUTOUT28 0
+#define BM_PXP_WFE_B_STG2_5X6_OUT3_7_LUTOUT28 0x0000003F
+#define BF_PXP_WFE_B_STG2_5X6_OUT3_7_LUTOUT28(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X6_OUT3_7_LUTOUT28)
+
+#define HW_PXP_WFE_B_STAGE2_5X6_MASKS_0 (0x00002520)
+
+#define BP_PXP_WFE_B_STAGE2_5X6_MASKS_0_RSVD3 29
+#define BM_PXP_WFE_B_STAGE2_5X6_MASKS_0_RSVD3 0xE0000000
+#define BF_PXP_WFE_B_STAGE2_5X6_MASKS_0_RSVD3(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STAGE2_5X6_MASKS_0_RSVD3)
+#define BP_PXP_WFE_B_STAGE2_5X6_MASKS_0_MASK3 24
+#define BM_PXP_WFE_B_STAGE2_5X6_MASKS_0_MASK3 0x1F000000
+#define BF_PXP_WFE_B_STAGE2_5X6_MASKS_0_MASK3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE2_5X6_MASKS_0_MASK3)
+#define BP_PXP_WFE_B_STAGE2_5X6_MASKS_0_RSVD2 21
+#define BM_PXP_WFE_B_STAGE2_5X6_MASKS_0_RSVD2 0x00E00000
+#define BF_PXP_WFE_B_STAGE2_5X6_MASKS_0_RSVD2(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STAGE2_5X6_MASKS_0_RSVD2)
+#define BP_PXP_WFE_B_STAGE2_5X6_MASKS_0_MASK2 16
+#define BM_PXP_WFE_B_STAGE2_5X6_MASKS_0_MASK2 0x001F0000
+#define BF_PXP_WFE_B_STAGE2_5X6_MASKS_0_MASK2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE2_5X6_MASKS_0_MASK2)
+#define BP_PXP_WFE_B_STAGE2_5X6_MASKS_0_RSVD1 13
+#define BM_PXP_WFE_B_STAGE2_5X6_MASKS_0_RSVD1 0x0000E000
+#define BF_PXP_WFE_B_STAGE2_5X6_MASKS_0_RSVD1(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STAGE2_5X6_MASKS_0_RSVD1)
+#define BP_PXP_WFE_B_STAGE2_5X6_MASKS_0_MASK1 8
+#define BM_PXP_WFE_B_STAGE2_5X6_MASKS_0_MASK1 0x00001F00
+#define BF_PXP_WFE_B_STAGE2_5X6_MASKS_0_MASK1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE2_5X6_MASKS_0_MASK1)
+#define BP_PXP_WFE_B_STAGE2_5X6_MASKS_0_RSVD0 5
+#define BM_PXP_WFE_B_STAGE2_5X6_MASKS_0_RSVD0 0x000000E0
+#define BF_PXP_WFE_B_STAGE2_5X6_MASKS_0_RSVD0(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STAGE2_5X6_MASKS_0_RSVD0)
+#define BP_PXP_WFE_B_STAGE2_5X6_MASKS_0_MASK0 0
+#define BM_PXP_WFE_B_STAGE2_5X6_MASKS_0_MASK0 0x0000001F
+#define BF_PXP_WFE_B_STAGE2_5X6_MASKS_0_MASK0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE2_5X6_MASKS_0_MASK0)
+
+#define HW_PXP_WFE_B_STAGE2_5X6_ADDR_0 (0x00002530)
+
+#define BP_PXP_WFE_B_STAGE2_5X6_ADDR_0_RSVD3 30
+#define BM_PXP_WFE_B_STAGE2_5X6_ADDR_0_RSVD3 0xC0000000
+#define BF_PXP_WFE_B_STAGE2_5X6_ADDR_0_RSVD3(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STAGE2_5X6_ADDR_0_RSVD3)
+#define BP_PXP_WFE_B_STAGE2_5X6_ADDR_0_MUXADDR3 24
+#define BM_PXP_WFE_B_STAGE2_5X6_ADDR_0_MUXADDR3 0x3F000000
+#define BF_PXP_WFE_B_STAGE2_5X6_ADDR_0_MUXADDR3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STAGE2_5X6_ADDR_0_MUXADDR3)
+#define BP_PXP_WFE_B_STAGE2_5X6_ADDR_0_RSVD2 22
+#define BM_PXP_WFE_B_STAGE2_5X6_ADDR_0_RSVD2 0x00C00000
+#define BF_PXP_WFE_B_STAGE2_5X6_ADDR_0_RSVD2(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STAGE2_5X6_ADDR_0_RSVD2)
+#define BP_PXP_WFE_B_STAGE2_5X6_ADDR_0_MUXADDR2 16
+#define BM_PXP_WFE_B_STAGE2_5X6_ADDR_0_MUXADDR2 0x003F0000
+#define BF_PXP_WFE_B_STAGE2_5X6_ADDR_0_MUXADDR2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STAGE2_5X6_ADDR_0_MUXADDR2)
+#define BP_PXP_WFE_B_STAGE2_5X6_ADDR_0_RSVD1 14
+#define BM_PXP_WFE_B_STAGE2_5X6_ADDR_0_RSVD1 0x0000C000
+#define BF_PXP_WFE_B_STAGE2_5X6_ADDR_0_RSVD1(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STAGE2_5X6_ADDR_0_RSVD1)
+#define BP_PXP_WFE_B_STAGE2_5X6_ADDR_0_MUXADDR1 8
+#define BM_PXP_WFE_B_STAGE2_5X6_ADDR_0_MUXADDR1 0x00003F00
+#define BF_PXP_WFE_B_STAGE2_5X6_ADDR_0_MUXADDR1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STAGE2_5X6_ADDR_0_MUXADDR1)
+#define BP_PXP_WFE_B_STAGE2_5X6_ADDR_0_RSVD0 6
+#define BM_PXP_WFE_B_STAGE2_5X6_ADDR_0_RSVD0 0x000000C0
+#define BF_PXP_WFE_B_STAGE2_5X6_ADDR_0_RSVD0(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STAGE2_5X6_ADDR_0_RSVD0)
+#define BP_PXP_WFE_B_STAGE2_5X6_ADDR_0_MUXADDR0 0
+#define BM_PXP_WFE_B_STAGE2_5X6_ADDR_0_MUXADDR0 0x0000003F
+#define BF_PXP_WFE_B_STAGE2_5X6_ADDR_0_MUXADDR0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STAGE2_5X6_ADDR_0_MUXADDR0)
+
+#define HW_PXP_WFE_B_STG2_5X1_OUT0 (0x00002540)
+
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT31 0x80000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT31)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT30 0x40000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT30)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT29 0x20000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT29)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT28 0x10000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT28)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT27 0x08000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT27)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT26 0x04000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT26)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT25 0x02000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT25)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT24 0x01000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT24)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT23 0x00800000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT23)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT22 0x00400000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT22)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT21 0x00200000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT21)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT20 0x00100000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT20)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT19 0x00080000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT19)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT18 0x00040000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT18)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT17 0x00020000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT17)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT16 0x00010000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT16)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT15 0x00008000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT15)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT14 0x00004000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT14)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT13 0x00002000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT13)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT12 0x00001000
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT12)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT11 0x00000800
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT11)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT10 0x00000400
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT10)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT9 0x00000200
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT9)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT8 0x00000100
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT8)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT7 0x00000080
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT7)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT6 0x00000040
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT6)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT5 0x00000020
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT5)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT4 0x00000010
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT4)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT3 0x00000008
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT3)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT2 0x00000004
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT2)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT1 0x00000002
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT1)
+#define BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT0 0x00000001
+#define BF_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X1_OUT0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG2_5X1_OUT1 (0x00002550)
+
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT31 0x80000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT31)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT30 0x40000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT30)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT29 0x20000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT29)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT28 0x10000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT28)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT27 0x08000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT27)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT26 0x04000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT26)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT25 0x02000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT25)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT24 0x01000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT24)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT23 0x00800000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT23)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT22 0x00400000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT22)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT21 0x00200000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT21)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT20 0x00100000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT20)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT19 0x00080000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT19)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT18 0x00040000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT18)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT17 0x00020000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT17)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT16 0x00010000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT16)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT15 0x00008000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT15)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT14 0x00004000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT14)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT13 0x00002000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT13)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT12 0x00001000
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT12)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT11 0x00000800
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT11)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT10 0x00000400
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT10)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT9 0x00000200
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT9)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT8 0x00000100
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT8)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT7 0x00000080
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT7)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT6 0x00000040
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT6)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT5 0x00000020
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT5)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT4 0x00000010
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT4)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT3 0x00000008
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT3)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT2 0x00000004
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT2)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT1 0x00000002
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT1)
+#define BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT0 0x00000001
+#define BF_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X1_OUT1_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG2_5X1_OUT2 (0x00002560)
+
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT31 0x80000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT31)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT30 0x40000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT30)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT29 0x20000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT29)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT28 0x10000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT28)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT27 0x08000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT27)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT26 0x04000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT26)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT25 0x02000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT25)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT24 0x01000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT24)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT23 0x00800000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT23)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT22 0x00400000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT22)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT21 0x00200000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT21)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT20 0x00100000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT20)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT19 0x00080000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT19)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT18 0x00040000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT18)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT17 0x00020000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT17)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT16 0x00010000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT16)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT15 0x00008000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT15)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT14 0x00004000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT14)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT13 0x00002000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT13)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT12 0x00001000
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT12)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT11 0x00000800
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT11)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT10 0x00000400
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT10)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT9 0x00000200
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT9)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT8 0x00000100
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT8)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT7 0x00000080
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT7)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT6 0x00000040
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT6)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT5 0x00000020
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT5)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT4 0x00000010
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT4)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT3 0x00000008
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT3)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT2 0x00000004
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT2)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT1 0x00000002
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT1)
+#define BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT0 0x00000001
+#define BF_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X1_OUT2_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG2_5X1_OUT3 (0x00002570)
+
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT31 0x80000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT31)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT30 0x40000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT30)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT29 0x20000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT29)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT28 0x10000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT28)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT27 0x08000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT27)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT26 0x04000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT26)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT25 0x02000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT25)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT24 0x01000000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT24)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT23 0x00800000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT23)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT22 0x00400000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT22)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT21 0x00200000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT21)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT20 0x00100000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT20)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT19 0x00080000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT19)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT18 0x00040000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT18)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT17 0x00020000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT17)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT16 0x00010000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT16)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT15 0x00008000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT15)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT14 0x00004000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT14)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT13 0x00002000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT13)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT12 0x00001000
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT12)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT11 0x00000800
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT11)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT10 0x00000400
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT10)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT9 0x00000200
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT9)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT8 0x00000100
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT8)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT7 0x00000080
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT7)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT6 0x00000040
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT6)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT5 0x00000020
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT5)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT4 0x00000010
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT4)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT3 0x00000008
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT3)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT2 0x00000004
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT2)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT1 0x00000002
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT1)
+#define BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT0 0x00000001
+#define BF_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X1_OUT3_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG2_5X1_MASKS (0x00002580)
+
+#define BP_PXP_WFE_B_STG2_5X1_MASKS_RSVD3 29
+#define BM_PXP_WFE_B_STG2_5X1_MASKS_RSVD3 0xE0000000
+#define BF_PXP_WFE_B_STG2_5X1_MASKS_RSVD3(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG2_5X1_MASKS_RSVD3)
+#define BP_PXP_WFE_B_STG2_5X1_MASKS_MASK3 24
+#define BM_PXP_WFE_B_STG2_5X1_MASKS_MASK3 0x1F000000
+#define BF_PXP_WFE_B_STG2_5X1_MASKS_MASK3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG2_5X1_MASKS_MASK3)
+#define BP_PXP_WFE_B_STG2_5X1_MASKS_RSVD2 21
+#define BM_PXP_WFE_B_STG2_5X1_MASKS_RSVD2 0x00E00000
+#define BF_PXP_WFE_B_STG2_5X1_MASKS_RSVD2(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG2_5X1_MASKS_RSVD2)
+#define BP_PXP_WFE_B_STG2_5X1_MASKS_MASK2 16
+#define BM_PXP_WFE_B_STG2_5X1_MASKS_MASK2 0x001F0000
+#define BF_PXP_WFE_B_STG2_5X1_MASKS_MASK2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG2_5X1_MASKS_MASK2)
+#define BP_PXP_WFE_B_STG2_5X1_MASKS_RSVD1 13
+#define BM_PXP_WFE_B_STG2_5X1_MASKS_RSVD1 0x0000E000
+#define BF_PXP_WFE_B_STG2_5X1_MASKS_RSVD1(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG2_5X1_MASKS_RSVD1)
+#define BP_PXP_WFE_B_STG2_5X1_MASKS_MASK1 8
+#define BM_PXP_WFE_B_STG2_5X1_MASKS_MASK1 0x00001F00
+#define BF_PXP_WFE_B_STG2_5X1_MASKS_MASK1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG2_5X1_MASKS_MASK1)
+#define BP_PXP_WFE_B_STG2_5X1_MASKS_RSVD0 5
+#define BM_PXP_WFE_B_STG2_5X1_MASKS_RSVD0 0x000000E0
+#define BF_PXP_WFE_B_STG2_5X1_MASKS_RSVD0(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG2_5X1_MASKS_RSVD0)
+#define BP_PXP_WFE_B_STG2_5X1_MASKS_MASK0 0
+#define BM_PXP_WFE_B_STG2_5X1_MASKS_MASK0 0x0000001F
+#define BF_PXP_WFE_B_STG2_5X1_MASKS_MASK0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG2_5X1_MASKS_MASK0)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT0_0 (0x00002590)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT31 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT31)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT30 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT30)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT29 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT29)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT28 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT28)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT27 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT27)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT26 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT26)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT25 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT25)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT24 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT24)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT23 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT23)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT22 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT22)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT21 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT21)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT20 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT20)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT19 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT19)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT18 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT18)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT17 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT17)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT16 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT16)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT15 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT15)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT14 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT14)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT13 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT13)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT12 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT12)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT11 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT11)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT10 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT10)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT9 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT9)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT8 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT8)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT7 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT7)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT6 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT6)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT5 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT5)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT4 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT4)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT3 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT3)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT2 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT2)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT1 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT1)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT0 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT0_0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT0_1 (0x000025a0)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT63 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT63(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT63)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT62 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT62(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT62)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT61 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT61(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT61)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT60 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT60(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT60)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT59 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT59(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT59)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT58 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT58(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT58)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT57 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT57(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT57)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT56 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT56(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT56)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT55 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT55(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT55)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT54 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT54(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT54)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT53 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT53(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT53)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT52 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT52(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT52)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT51 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT51(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT51)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT50 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT50(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT50)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT49 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT49(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT49)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT48 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT48(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT48)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT47 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT47(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT47)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT46 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT46(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT46)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT45 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT45(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT45)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT44 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT44(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT44)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT43 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT43(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT43)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT42 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT42(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT42)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT41 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT41(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT41)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT40 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT40(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT40)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT39 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT39(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT39)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT38 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT38(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT38)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT37 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT37(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT37)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT36 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT36(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT36)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT35 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT35(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT35)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT34 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT34(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT34)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT33 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT33(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT33)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT32 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT32(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT0_1_LUTOUT32)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT0_2 (0x000025b0)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT95 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT95(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT95)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT94 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT94(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT94)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT93 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT93(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT93)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT92 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT92(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT92)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT91 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT91(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT91)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT90 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT90(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT90)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT89 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT89(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT89)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT88 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT88(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT88)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT87 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT87(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT87)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT86 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT86(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT86)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT85 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT85(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT85)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT84 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT84(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT84)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT83 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT83(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT83)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT82 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT82(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT82)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT81 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT81(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT81)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT80 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT80(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT80)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT79 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT79(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT79)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT78 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT78(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT78)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT77 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT77(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT77)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT76 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT76(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT76)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT75 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT75(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT75)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT74 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT74(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT74)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT73 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT73(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT73)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT72 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT72(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT72)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT71 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT71(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT71)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT70 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT70(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT70)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT69 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT69(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT69)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT68 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT68(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT68)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT67 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT67(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT67)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT66 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT66(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT66)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT65 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT65(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT65)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT64 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT64(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT0_2_LUTOUT64)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT0_3 (0x000025c0)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT127 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT127(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT127)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT126 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT126(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT126)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT125 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT125(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT125)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT124 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT124(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT124)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT123 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT123(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT123)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT122 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT122(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT122)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT121 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT121(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT121)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT120 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT120(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT120)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT119 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT119(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT119)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT118 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT118(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT118)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT117 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT117(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT117)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT116 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT116(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT116)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT115 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT115(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT115)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT114 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT114(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT114)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT113 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT113(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT113)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT112 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT112(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT112)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT111 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT111(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT111)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT110 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT110(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT110)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT109 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT109(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT109)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT108 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT108(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT108)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT107 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT107(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT107)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT106 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT106(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT106)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT105 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT105(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT105)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT104 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT104(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT104)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT103 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT103(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT103)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT102 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT102(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT102)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT101 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT101(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT101)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT100 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT100(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT100)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT99 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT99(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT99)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT98 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT98(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT98)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT97 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT97(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT97)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT96 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT96(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT0_3_LUTOUT96)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT0_4 (0x000025d0)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT159 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT159(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT159)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT158 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT158(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT158)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT157 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT157(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT157)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT156 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT156(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT156)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT155 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT155(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT155)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT154 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT154(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT154)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT153 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT153(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT153)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT152 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT152(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT152)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT151 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT151(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT151)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT150 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT150(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT150)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT149 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT149(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT149)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT148 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT148(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT148)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT147 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT147(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT147)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT146 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT146(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT146)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT145 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT145(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT145)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT144 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT144(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT144)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT143 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT143(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT143)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT142 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT142(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT142)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT141 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT141(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT141)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT140 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT140(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT140)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT139 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT139(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT139)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT138 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT138(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT138)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT137 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT137(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT137)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT136 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT136(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT136)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT135 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT135(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT135)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT134 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT134(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT134)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT133 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT133(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT133)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT132 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT132(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT132)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT131 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT131(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT131)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT130 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT130(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT130)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT129 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT129(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT129)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT128 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT128(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT0_4_LUTOUT128)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT0_5 (0x000025e0)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT191 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT191(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT191)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT190 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT190(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT190)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT189 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT189(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT189)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT188 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT188(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT188)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT187 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT187(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT187)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT186 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT186(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT186)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT185 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT185(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT185)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT184 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT184(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT184)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT183 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT183(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT183)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT182 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT182(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT182)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT181 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT181(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT181)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT180 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT180(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT180)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT179 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT179(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT179)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT178 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT178(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT178)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT177 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT177(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT177)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT176 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT176(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT176)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT175 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT175(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT175)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT174 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT174(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT174)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT173 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT173(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT173)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT172 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT172(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT172)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT171 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT171(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT171)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT170 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT170(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT170)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT169 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT169(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT169)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT168 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT168(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT168)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT167 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT167(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT167)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT166 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT166(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT166)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT165 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT165(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT165)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT164 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT164(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT164)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT163 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT163(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT163)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT162 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT162(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT162)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT161 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT161(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT161)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT160 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT160(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT0_5_LUTOUT160)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT0_6 (0x000025f0)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT223 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT223(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT223)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT222 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT222(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT222)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT221 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT221(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT221)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT220 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT220(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT220)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT219 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT219(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT219)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT218 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT218(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT218)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT217 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT217(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT217)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT216 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT216(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT216)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT215 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT215(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT215)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT214 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT214(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT214)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT213 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT213(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT213)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT212 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT212(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT212)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT211 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT211(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT211)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT210 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT210(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT210)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT209 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT209(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT209)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT208 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT208(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT208)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT207 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT207(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT207)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT206 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT206(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT206)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT205 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT205(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT205)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT204 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT204(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT204)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT203 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT203(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT203)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT202 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT202(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT202)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT201 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT201(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT201)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT200 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT200(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT200)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT199 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT199(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT199)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT198 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT198(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT198)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT197 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT197(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT197)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT196 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT196(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT196)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT195 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT195(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT195)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT194 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT194(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT194)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT193 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT193(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT193)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT192 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT192(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT0_6_LUTOUT192)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT0_7 (0x00002600)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT255 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT255(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT255)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT254 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT254(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT254)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT253 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT253(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT253)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT252 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT252(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT252)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT251 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT251(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT251)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT250 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT250(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT250)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT249 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT249(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT249)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT248 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT248(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT248)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT247 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT247(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT247)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT246 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT246(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT246)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT245 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT245(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT245)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT244 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT244(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT244)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT243 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT243(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT243)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT242 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT242(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT242)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT241 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT241(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT241)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT240 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT240(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT240)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT239 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT239(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT239)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT238 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT238(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT238)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT237 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT237(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT237)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT236 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT236(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT236)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT235 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT235(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT235)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT234 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT234(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT234)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT233 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT233(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT233)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT232 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT232(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT232)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT231 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT231(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT231)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT230 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT230(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT230)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT229 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT229(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT229)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT228 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT228(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT228)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT227 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT227(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT227)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT226 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT226(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT226)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT225 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT225(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT225)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT224 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT224(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT0_7_LUTOUT224)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT1_0 (0x00002610)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT31 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT31)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT30 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT30)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT29 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT29)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT28 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT28)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT27 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT27)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT26 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT26)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT25 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT25)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT24 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT24)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT23 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT23)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT22 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT22)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT21 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT21)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT20 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT20)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT19 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT19)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT18 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT18)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT17 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT17)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT16 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT16)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT15 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT15)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT14 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT14)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT13 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT13)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT12 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT12)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT11 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT11)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT10 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT10)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT9 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT9)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT8 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT8)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT7 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT7)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT6 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT6)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT5 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT5)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT4 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT4)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT3 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT3)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT2 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT2)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT1 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT1)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT0 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT1_0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT1_1 (0x00002620)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT63 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT63(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT63)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT62 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT62(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT62)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT61 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT61(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT61)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT60 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT60(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT60)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT59 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT59(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT59)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT58 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT58(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT58)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT57 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT57(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT57)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT56 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT56(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT56)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT55 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT55(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT55)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT54 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT54(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT54)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT53 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT53(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT53)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT52 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT52(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT52)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT51 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT51(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT51)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT50 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT50(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT50)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT49 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT49(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT49)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT48 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT48(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT48)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT47 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT47(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT47)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT46 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT46(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT46)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT45 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT45(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT45)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT44 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT44(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT44)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT43 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT43(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT43)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT42 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT42(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT42)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT41 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT41(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT41)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT40 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT40(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT40)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT39 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT39(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT39)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT38 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT38(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT38)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT37 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT37(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT37)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT36 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT36(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT36)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT35 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT35(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT35)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT34 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT34(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT34)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT33 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT33(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT33)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT32 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT32(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT1_1_LUTOUT32)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT1_2 (0x00002630)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT95 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT95(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT95)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT94 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT94(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT94)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT93 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT93(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT93)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT92 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT92(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT92)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT91 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT91(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT91)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT90 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT90(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT90)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT89 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT89(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT89)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT88 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT88(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT88)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT87 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT87(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT87)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT86 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT86(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT86)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT85 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT85(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT85)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT84 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT84(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT84)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT83 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT83(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT83)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT82 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT82(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT82)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT81 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT81(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT81)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT80 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT80(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT80)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT79 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT79(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT79)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT78 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT78(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT78)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT77 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT77(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT77)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT76 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT76(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT76)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT75 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT75(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT75)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT74 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT74(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT74)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT73 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT73(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT73)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT72 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT72(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT72)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT71 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT71(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT71)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT70 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT70(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT70)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT69 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT69(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT69)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT68 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT68(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT68)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT67 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT67(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT67)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT66 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT66(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT66)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT65 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT65(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT65)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT64 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT64(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT1_2_LUTOUT64)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT1_3 (0x00002640)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT127 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT127(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT127)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT126 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT126(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT126)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT125 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT125(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT125)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT124 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT124(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT124)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT123 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT123(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT123)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT122 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT122(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT122)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT121 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT121(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT121)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT120 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT120(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT120)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT119 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT119(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT119)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT118 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT118(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT118)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT117 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT117(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT117)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT116 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT116(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT116)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT115 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT115(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT115)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT114 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT114(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT114)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT113 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT113(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT113)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT112 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT112(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT112)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT111 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT111(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT111)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT110 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT110(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT110)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT109 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT109(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT109)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT108 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT108(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT108)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT107 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT107(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT107)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT106 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT106(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT106)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT105 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT105(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT105)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT104 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT104(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT104)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT103 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT103(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT103)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT102 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT102(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT102)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT101 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT101(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT101)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT100 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT100(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT100)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT99 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT99(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT99)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT98 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT98(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT98)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT97 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT97(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT97)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT96 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT96(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT1_3_LUTOUT96)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT1_4 (0x00002650)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT159 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT159(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT159)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT158 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT158(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT158)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT157 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT157(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT157)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT156 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT156(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT156)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT155 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT155(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT155)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT154 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT154(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT154)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT153 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT153(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT153)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT152 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT152(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT152)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT151 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT151(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT151)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT150 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT150(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT150)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT149 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT149(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT149)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT148 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT148(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT148)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT147 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT147(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT147)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT146 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT146(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT146)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT145 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT145(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT145)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT144 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT144(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT144)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT143 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT143(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT143)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT142 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT142(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT142)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT141 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT141(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT141)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT140 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT140(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT140)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT139 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT139(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT139)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT138 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT138(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT138)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT137 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT137(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT137)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT136 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT136(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT136)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT135 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT135(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT135)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT134 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT134(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT134)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT133 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT133(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT133)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT132 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT132(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT132)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT131 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT131(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT131)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT130 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT130(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT130)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT129 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT129(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT129)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT128 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT128(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT1_4_LUTOUT128)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT1_5 (0x00002660)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT191 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT191(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT191)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT190 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT190(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT190)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT189 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT189(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT189)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT188 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT188(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT188)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT187 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT187(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT187)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT186 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT186(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT186)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT185 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT185(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT185)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT184 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT184(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT184)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT183 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT183(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT183)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT182 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT182(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT182)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT181 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT181(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT181)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT180 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT180(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT180)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT179 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT179(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT179)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT178 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT178(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT178)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT177 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT177(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT177)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT176 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT176(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT176)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT175 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT175(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT175)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT174 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT174(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT174)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT173 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT173(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT173)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT172 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT172(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT172)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT171 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT171(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT171)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT170 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT170(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT170)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT169 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT169(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT169)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT168 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT168(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT168)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT167 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT167(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT167)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT166 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT166(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT166)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT165 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT165(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT165)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT164 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT164(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT164)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT163 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT163(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT163)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT162 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT162(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT162)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT161 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT161(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT161)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT160 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT160(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT1_5_LUTOUT160)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT1_6 (0x00002670)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT223 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT223(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT223)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT222 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT222(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT222)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT221 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT221(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT221)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT220 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT220(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT220)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT219 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT219(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT219)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT218 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT218(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT218)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT217 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT217(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT217)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT216 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT216(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT216)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT215 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT215(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT215)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT214 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT214(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT214)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT213 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT213(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT213)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT212 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT212(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT212)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT211 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT211(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT211)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT210 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT210(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT210)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT209 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT209(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT209)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT208 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT208(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT208)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT207 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT207(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT207)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT206 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT206(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT206)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT205 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT205(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT205)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT204 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT204(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT204)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT203 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT203(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT203)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT202 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT202(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT202)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT201 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT201(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT201)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT200 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT200(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT200)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT199 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT199(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT199)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT198 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT198(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT198)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT197 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT197(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT197)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT196 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT196(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT196)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT195 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT195(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT195)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT194 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT194(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT194)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT193 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT193(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT193)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT192 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT192(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT1_6_LUTOUT192)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT1_7 (0x00002680)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT255 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT255(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT255)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT254 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT254(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT254)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT253 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT253(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT253)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT252 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT252(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT252)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT251 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT251(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT251)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT250 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT250(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT250)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT249 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT249(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT249)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT248 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT248(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT248)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT247 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT247(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT247)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT246 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT246(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT246)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT245 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT245(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT245)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT244 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT244(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT244)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT243 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT243(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT243)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT242 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT242(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT242)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT241 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT241(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT241)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT240 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT240(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT240)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT239 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT239(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT239)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT238 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT238(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT238)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT237 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT237(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT237)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT236 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT236(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT236)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT235 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT235(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT235)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT234 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT234(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT234)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT233 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT233(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT233)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT232 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT232(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT232)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT231 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT231(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT231)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT230 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT230(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT230)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT229 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT229(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT229)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT228 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT228(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT228)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT227 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT227(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT227)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT226 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT226(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT226)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT225 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT225(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT225)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT224 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT224(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT1_7_LUTOUT224)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT2_0 (0x00002690)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT31 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT31)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT30 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT30)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT29 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT29)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT28 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT28)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT27 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT27)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT26 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT26)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT25 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT25)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT24 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT24)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT23 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT23)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT22 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT22)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT21 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT21)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT20 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT20)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT19 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT19)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT18 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT18)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT17 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT17)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT16 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT16)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT15 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT15)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT14 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT14)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT13 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT13)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT12 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT12)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT11 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT11)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT10 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT10)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT9 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT9)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT8 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT8)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT7 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT7)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT6 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT6)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT5 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT5)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT4 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT4)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT3 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT3)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT2 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT2)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT1 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT1)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT0 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT2_0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT2_1 (0x000026a0)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT63 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT63(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT63)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT62 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT62(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT62)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT61 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT61(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT61)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT60 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT60(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT60)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT59 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT59(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT59)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT58 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT58(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT58)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT57 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT57(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT57)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT56 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT56(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT56)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT55 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT55(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT55)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT54 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT54(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT54)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT53 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT53(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT53)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT52 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT52(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT52)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT51 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT51(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT51)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT50 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT50(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT50)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT49 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT49(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT49)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT48 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT48(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT48)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT47 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT47(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT47)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT46 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT46(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT46)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT45 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT45(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT45)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT44 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT44(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT44)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT43 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT43(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT43)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT42 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT42(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT42)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT41 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT41(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT41)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT40 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT40(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT40)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT39 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT39(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT39)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT38 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT38(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT38)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT37 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT37(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT37)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT36 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT36(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT36)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT35 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT35(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT35)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT34 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT34(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT34)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT33 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT33(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT33)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT32 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT32(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT2_1_LUTOUT32)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT2_2 (0x000026b0)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT95 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT95(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT95)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT94 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT94(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT94)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT93 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT93(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT93)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT92 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT92(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT92)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT91 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT91(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT91)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT90 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT90(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT90)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT89 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT89(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT89)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT88 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT88(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT88)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT87 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT87(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT87)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT86 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT86(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT86)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT85 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT85(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT85)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT84 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT84(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT84)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT83 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT83(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT83)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT82 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT82(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT82)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT81 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT81(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT81)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT80 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT80(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT80)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT79 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT79(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT79)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT78 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT78(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT78)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT77 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT77(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT77)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT76 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT76(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT76)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT75 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT75(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT75)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT74 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT74(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT74)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT73 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT73(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT73)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT72 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT72(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT72)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT71 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT71(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT71)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT70 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT70(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT70)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT69 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT69(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT69)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT68 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT68(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT68)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT67 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT67(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT67)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT66 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT66(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT66)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT65 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT65(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT65)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT64 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT64(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT2_2_LUTOUT64)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT2_3 (0x000026c0)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT127 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT127(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT127)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT126 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT126(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT126)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT125 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT125(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT125)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT124 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT124(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT124)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT123 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT123(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT123)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT122 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT122(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT122)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT121 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT121(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT121)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT120 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT120(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT120)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT119 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT119(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT119)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT118 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT118(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT118)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT117 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT117(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT117)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT116 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT116(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT116)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT115 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT115(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT115)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT114 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT114(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT114)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT113 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT113(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT113)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT112 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT112(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT112)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT111 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT111(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT111)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT110 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT110(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT110)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT109 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT109(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT109)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT108 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT108(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT108)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT107 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT107(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT107)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT106 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT106(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT106)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT105 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT105(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT105)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT104 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT104(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT104)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT103 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT103(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT103)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT102 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT102(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT102)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT101 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT101(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT101)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT100 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT100(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT100)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT99 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT99(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT99)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT98 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT98(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT98)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT97 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT97(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT97)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT96 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT96(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT2_3_LUTOUT96)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT2_4 (0x000026d0)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT159 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT159(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT159)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT158 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT158(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT158)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT157 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT157(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT157)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT156 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT156(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT156)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT155 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT155(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT155)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT154 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT154(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT154)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT153 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT153(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT153)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT152 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT152(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT152)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT151 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT151(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT151)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT150 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT150(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT150)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT149 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT149(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT149)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT148 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT148(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT148)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT147 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT147(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT147)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT146 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT146(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT146)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT145 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT145(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT145)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT144 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT144(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT144)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT143 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT143(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT143)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT142 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT142(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT142)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT141 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT141(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT141)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT140 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT140(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT140)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT139 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT139(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT139)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT138 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT138(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT138)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT137 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT137(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT137)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT136 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT136(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT136)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT135 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT135(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT135)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT134 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT134(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT134)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT133 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT133(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT133)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT132 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT132(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT132)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT131 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT131(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT131)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT130 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT130(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT130)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT129 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT129(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT129)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT128 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT128(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT2_4_LUTOUT128)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT2_5 (0x000026e0)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT191 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT191(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT191)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT190 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT190(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT190)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT189 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT189(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT189)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT188 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT188(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT188)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT187 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT187(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT187)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT186 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT186(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT186)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT185 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT185(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT185)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT184 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT184(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT184)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT183 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT183(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT183)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT182 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT182(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT182)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT181 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT181(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT181)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT180 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT180(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT180)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT179 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT179(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT179)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT178 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT178(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT178)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT177 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT177(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT177)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT176 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT176(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT176)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT175 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT175(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT175)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT174 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT174(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT174)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT173 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT173(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT173)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT172 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT172(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT172)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT171 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT171(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT171)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT170 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT170(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT170)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT169 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT169(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT169)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT168 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT168(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT168)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT167 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT167(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT167)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT166 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT166(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT166)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT165 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT165(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT165)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT164 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT164(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT164)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT163 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT163(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT163)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT162 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT162(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT162)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT161 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT161(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT161)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT160 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT160(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT2_5_LUTOUT160)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT2_6 (0x000026f0)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT223 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT223(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT223)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT222 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT222(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT222)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT221 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT221(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT221)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT220 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT220(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT220)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT219 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT219(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT219)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT218 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT218(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT218)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT217 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT217(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT217)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT216 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT216(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT216)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT215 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT215(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT215)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT214 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT214(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT214)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT213 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT213(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT213)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT212 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT212(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT212)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT211 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT211(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT211)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT210 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT210(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT210)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT209 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT209(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT209)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT208 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT208(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT208)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT207 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT207(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT207)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT206 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT206(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT206)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT205 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT205(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT205)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT204 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT204(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT204)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT203 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT203(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT203)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT202 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT202(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT202)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT201 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT201(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT201)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT200 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT200(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT200)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT199 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT199(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT199)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT198 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT198(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT198)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT197 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT197(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT197)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT196 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT196(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT196)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT195 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT195(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT195)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT194 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT194(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT194)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT193 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT193(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT193)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT192 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT192(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT2_6_LUTOUT192)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT2_7 (0x00002700)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT255 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT255(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT255)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT254 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT254(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT254)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT253 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT253(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT253)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT252 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT252(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT252)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT251 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT251(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT251)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT250 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT250(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT250)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT249 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT249(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT249)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT248 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT248(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT248)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT247 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT247(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT247)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT246 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT246(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT246)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT245 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT245(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT245)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT244 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT244(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT244)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT243 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT243(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT243)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT242 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT242(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT242)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT241 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT241(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT241)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT240 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT240(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT240)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT239 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT239(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT239)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT238 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT238(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT238)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT237 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT237(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT237)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT236 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT236(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT236)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT235 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT235(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT235)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT234 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT234(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT234)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT233 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT233(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT233)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT232 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT232(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT232)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT231 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT231(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT231)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT230 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT230(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT230)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT229 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT229(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT229)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT228 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT228(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT228)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT227 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT227(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT227)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT226 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT226(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT226)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT225 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT225(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT225)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT224 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT224(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT2_7_LUTOUT224)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT3_0 (0x00002710)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT31 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT31(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT31)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT30 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT30(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT30)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT29 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT29(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT29)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT28 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT28(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT28)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT27 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT27(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT27)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT26 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT26(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT26)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT25 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT25(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT25)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT24 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT24(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT24)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT23 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT23(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT23)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT22 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT22(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT22)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT21 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT21(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT21)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT20 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT20(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT20)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT19 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT19(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT19)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT18 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT18(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT18)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT17 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT17(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT17)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT16 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT16(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT16)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT15 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT15(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT15)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT14 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT14(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT14)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT13 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT13(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT13)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT12 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT12(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT12)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT11 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT11(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT11)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT10 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT10(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT10)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT9 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT9(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT9)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT8 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT8(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT8)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT7 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT7(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT7)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT6 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT6(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT6)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT5 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT5(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT5)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT4 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT4(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT4)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT3 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT3(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT3)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT2 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT2(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT2)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT1 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT1(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT1)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT0 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT3_0_LUTOUT0)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT3_1 (0x00002720)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT63 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT63(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT63)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT62 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT62(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT62)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT61 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT61(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT61)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT60 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT60(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT60)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT59 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT59(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT59)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT58 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT58(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT58)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT57 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT57(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT57)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT56 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT56(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT56)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT55 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT55(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT55)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT54 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT54(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT54)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT53 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT53(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT53)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT52 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT52(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT52)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT51 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT51(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT51)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT50 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT50(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT50)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT49 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT49(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT49)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT48 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT48(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT48)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT47 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT47(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT47)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT46 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT46(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT46)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT45 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT45(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT45)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT44 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT44(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT44)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT43 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT43(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT43)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT42 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT42(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT42)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT41 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT41(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT41)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT40 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT40(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT40)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT39 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT39(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT39)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT38 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT38(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT38)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT37 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT37(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT37)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT36 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT36(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT36)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT35 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT35(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT35)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT34 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT34(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT34)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT33 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT33(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT33)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT32 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT32(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT3_1_LUTOUT32)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT3_2 (0x00002730)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT95 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT95(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT95)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT94 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT94(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT94)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT93 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT93(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT93)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT92 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT92(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT92)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT91 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT91(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT91)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT90 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT90(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT90)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT89 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT89(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT89)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT88 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT88(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT88)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT87 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT87(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT87)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT86 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT86(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT86)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT85 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT85(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT85)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT84 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT84(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT84)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT83 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT83(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT83)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT82 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT82(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT82)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT81 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT81(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT81)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT80 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT80(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT80)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT79 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT79(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT79)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT78 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT78(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT78)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT77 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT77(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT77)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT76 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT76(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT76)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT75 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT75(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT75)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT74 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT74(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT74)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT73 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT73(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT73)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT72 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT72(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT72)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT71 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT71(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT71)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT70 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT70(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT70)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT69 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT69(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT69)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT68 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT68(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT68)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT67 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT67(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT67)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT66 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT66(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT66)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT65 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT65(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT65)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT64 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT64(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT3_2_LUTOUT64)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT3_3 (0x00002740)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT127 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT127(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT127)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT126 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT126(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT126)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT125 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT125(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT125)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT124 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT124(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT124)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT123 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT123(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT123)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT122 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT122(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT122)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT121 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT121(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT121)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT120 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT120(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT120)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT119 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT119(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT119)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT118 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT118(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT118)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT117 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT117(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT117)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT116 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT116(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT116)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT115 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT115(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT115)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT114 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT114(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT114)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT113 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT113(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT113)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT112 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT112(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT112)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT111 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT111(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT111)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT110 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT110(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT110)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT109 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT109(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT109)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT108 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT108(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT108)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT107 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT107(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT107)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT106 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT106(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT106)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT105 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT105(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT105)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT104 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT104(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT104)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT103 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT103(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT103)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT102 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT102(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT102)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT101 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT101(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT101)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT100 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT100(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT100)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT99 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT99(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT99)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT98 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT98(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT98)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT97 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT97(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT97)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT96 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT96(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT3_3_LUTOUT96)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT3_4 (0x00002750)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT159 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT159(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT159)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT158 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT158(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT158)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT157 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT157(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT157)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT156 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT156(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT156)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT155 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT155(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT155)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT154 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT154(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT154)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT153 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT153(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT153)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT152 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT152(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT152)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT151 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT151(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT151)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT150 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT150(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT150)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT149 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT149(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT149)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT148 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT148(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT148)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT147 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT147(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT147)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT146 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT146(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT146)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT145 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT145(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT145)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT144 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT144(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT144)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT143 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT143(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT143)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT142 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT142(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT142)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT141 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT141(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT141)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT140 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT140(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT140)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT139 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT139(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT139)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT138 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT138(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT138)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT137 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT137(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT137)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT136 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT136(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT136)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT135 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT135(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT135)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT134 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT134(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT134)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT133 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT133(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT133)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT132 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT132(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT132)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT131 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT131(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT131)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT130 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT130(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT130)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT129 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT129(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT129)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT128 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT128(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT3_4_LUTOUT128)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT3_5 (0x00002760)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT191 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT191(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT191)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT190 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT190(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT190)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT189 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT189(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT189)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT188 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT188(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT188)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT187 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT187(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT187)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT186 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT186(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT186)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT185 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT185(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT185)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT184 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT184(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT184)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT183 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT183(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT183)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT182 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT182(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT182)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT181 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT181(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT181)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT180 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT180(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT180)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT179 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT179(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT179)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT178 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT178(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT178)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT177 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT177(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT177)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT176 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT176(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT176)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT175 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT175(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT175)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT174 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT174(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT174)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT173 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT173(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT173)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT172 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT172(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT172)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT171 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT171(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT171)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT170 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT170(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT170)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT169 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT169(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT169)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT168 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT168(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT168)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT167 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT167(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT167)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT166 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT166(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT166)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT165 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT165(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT165)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT164 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT164(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT164)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT163 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT163(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT163)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT162 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT162(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT162)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT161 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT161(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT161)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT160 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT160(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT3_5_LUTOUT160)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT3_6 (0x00002770)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT223 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT223(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT223)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT222 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT222(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT222)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT221 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT221(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT221)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT220 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT220(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT220)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT219 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT219(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT219)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT218 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT218(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT218)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT217 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT217(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT217)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT216 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT216(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT216)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT215 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT215(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT215)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT214 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT214(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT214)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT213 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT213(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT213)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT212 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT212(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT212)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT211 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT211(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT211)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT210 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT210(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT210)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT209 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT209(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT209)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT208 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT208(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT208)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT207 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT207(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT207)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT206 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT206(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT206)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT205 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT205(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT205)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT204 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT204(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT204)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT203 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT203(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT203)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT202 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT202(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT202)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT201 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT201(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT201)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT200 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT200(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT200)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT199 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT199(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT199)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT198 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT198(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT198)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT197 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT197(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT197)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT196 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT196(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT196)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT195 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT195(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT195)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT194 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT194(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT194)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT193 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT193(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT193)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT192 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT192(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT3_6_LUTOUT192)
+
+#define HW_PXP_WFE_B_STG3_F8X1_OUT3_7 (0x00002780)
+
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT255 0x80000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT255(v) \
+ (((v) << 31) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT255)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT254 0x40000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT254(v) \
+ (((v) << 30) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT254)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT253 0x20000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT253(v) \
+ (((v) << 29) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT253)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT252 0x10000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT252(v) \
+ (((v) << 28) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT252)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT251 0x08000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT251(v) \
+ (((v) << 27) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT251)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT250 0x04000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT250(v) \
+ (((v) << 26) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT250)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT249 0x02000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT249(v) \
+ (((v) << 25) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT249)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT248 0x01000000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT248(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT248)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT247 0x00800000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT247(v) \
+ (((v) << 23) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT247)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT246 0x00400000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT246(v) \
+ (((v) << 22) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT246)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT245 0x00200000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT245(v) \
+ (((v) << 21) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT245)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT244 0x00100000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT244(v) \
+ (((v) << 20) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT244)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT243 0x00080000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT243(v) \
+ (((v) << 19) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT243)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT242 0x00040000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT242(v) \
+ (((v) << 18) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT242)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT241 0x00020000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT241(v) \
+ (((v) << 17) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT241)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT240 0x00010000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT240(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT240)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT239 0x00008000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT239(v) \
+ (((v) << 15) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT239)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT238 0x00004000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT238(v) \
+ (((v) << 14) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT238)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT237 0x00002000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT237(v) \
+ (((v) << 13) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT237)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT236 0x00001000
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT236(v) \
+ (((v) << 12) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT236)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT235 0x00000800
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT235(v) \
+ (((v) << 11) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT235)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT234 0x00000400
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT234(v) \
+ (((v) << 10) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT234)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT233 0x00000200
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT233(v) \
+ (((v) << 9) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT233)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT232 0x00000100
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT232(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT232)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT231 0x00000080
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT231(v) \
+ (((v) << 7) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT231)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT230 0x00000040
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT230(v) \
+ (((v) << 6) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT230)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT229 0x00000020
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT229(v) \
+ (((v) << 5) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT229)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT228 0x00000010
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT228(v) \
+ (((v) << 4) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT228)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT227 0x00000008
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT227(v) \
+ (((v) << 3) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT227)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT226 0x00000004
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT226(v) \
+ (((v) << 2) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT226)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT225 0x00000002
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT225(v) \
+ (((v) << 1) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT225)
+#define BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT224 0x00000001
+#define BF_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT224(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_OUT3_7_LUTOUT224)
+
+#define HW_PXP_WFE_B_STG3_F8X1_MASKS (0x00002790)
+
+#define BP_PXP_WFE_B_STG3_F8X1_MASKS_MASK3 24
+#define BM_PXP_WFE_B_STG3_F8X1_MASKS_MASK3 0xFF000000
+#define BF_PXP_WFE_B_STG3_F8X1_MASKS_MASK3(v) \
+ (((v) << 24) & BM_PXP_WFE_B_STG3_F8X1_MASKS_MASK3)
+#define BP_PXP_WFE_B_STG3_F8X1_MASKS_MASK2 16
+#define BM_PXP_WFE_B_STG3_F8X1_MASKS_MASK2 0x00FF0000
+#define BF_PXP_WFE_B_STG3_F8X1_MASKS_MASK2(v) \
+ (((v) << 16) & BM_PXP_WFE_B_STG3_F8X1_MASKS_MASK2)
+#define BP_PXP_WFE_B_STG3_F8X1_MASKS_MASK1 8
+#define BM_PXP_WFE_B_STG3_F8X1_MASKS_MASK1 0x0000FF00
+#define BF_PXP_WFE_B_STG3_F8X1_MASKS_MASK1(v) \
+ (((v) << 8) & BM_PXP_WFE_B_STG3_F8X1_MASKS_MASK1)
+#define BP_PXP_WFE_B_STG3_F8X1_MASKS_MASK0 0
+#define BM_PXP_WFE_B_STG3_F8X1_MASKS_MASK0 0x000000FF
+#define BF_PXP_WFE_B_STG3_F8X1_MASKS_MASK0(v) \
+ (((v) << 0) & BM_PXP_WFE_B_STG3_F8X1_MASKS_MASK0)
+
+#define HW_PXP_ALU_A_CTRL (0x00002810)
+#define HW_PXP_ALU_A_CTRL_SET (0x00002814)
+#define HW_PXP_ALU_A_CTRL_CLR (0x00002818)
+#define HW_PXP_ALU_A_CTRL_TOG (0x0000281c)
+
+#define BP_PXP_ALU_A_CTRL_RSVD0 29
+#define BM_PXP_ALU_A_CTRL_RSVD0 0xE0000000
+#define BF_PXP_ALU_A_CTRL_RSVD0(v) \
+ (((v) << 29) & BM_PXP_ALU_A_CTRL_RSVD0)
+#define BM_PXP_ALU_A_CTRL_DONE 0x10000000
+#define BF_PXP_ALU_A_CTRL_DONE(v) \
+ (((v) << 28) & BM_PXP_ALU_A_CTRL_DONE)
+#define BP_PXP_ALU_A_CTRL_RSVD1 21
+#define BM_PXP_ALU_A_CTRL_RSVD1 0x0FE00000
+#define BF_PXP_ALU_A_CTRL_RSVD1(v) \
+ (((v) << 21) & BM_PXP_ALU_A_CTRL_RSVD1)
+#define BM_PXP_ALU_A_CTRL_DONE_IRQ_EN 0x00100000
+#define BF_PXP_ALU_A_CTRL_DONE_IRQ_EN(v) \
+ (((v) << 20) & BM_PXP_ALU_A_CTRL_DONE_IRQ_EN)
+#define BP_PXP_ALU_A_CTRL_RSVD2 17
+#define BM_PXP_ALU_A_CTRL_RSVD2 0x000E0000
+#define BF_PXP_ALU_A_CTRL_RSVD2(v) \
+ (((v) << 17) & BM_PXP_ALU_A_CTRL_RSVD2)
+#define BM_PXP_ALU_A_CTRL_DONE_IRQ_FLAG 0x00010000
+#define BF_PXP_ALU_A_CTRL_DONE_IRQ_FLAG(v) \
+ (((v) << 16) & BM_PXP_ALU_A_CTRL_DONE_IRQ_FLAG)
+#define BP_PXP_ALU_A_CTRL_RSVD3 13
+#define BM_PXP_ALU_A_CTRL_RSVD3 0x0000E000
+#define BF_PXP_ALU_A_CTRL_RSVD3(v) \
+ (((v) << 13) & BM_PXP_ALU_A_CTRL_RSVD3)
+#define BM_PXP_ALU_A_CTRL_BYPASS 0x00001000
+#define BF_PXP_ALU_A_CTRL_BYPASS(v) \
+ (((v) << 12) & BM_PXP_ALU_A_CTRL_BYPASS)
+#define BV_PXP_ALU_A_CTRL_BYPASS__0 0x0
+#define BV_PXP_ALU_A_CTRL_BYPASS__1 0x1
+#define BP_PXP_ALU_A_CTRL_RSVD4 9
+#define BM_PXP_ALU_A_CTRL_RSVD4 0x00000E00
+#define BF_PXP_ALU_A_CTRL_RSVD4(v) \
+ (((v) << 9) & BM_PXP_ALU_A_CTRL_RSVD4)
+#define BM_PXP_ALU_A_CTRL_SW_RESET 0x00000100
+#define BF_PXP_ALU_A_CTRL_SW_RESET(v) \
+ (((v) << 8) & BM_PXP_ALU_A_CTRL_SW_RESET)
+#define BP_PXP_ALU_A_CTRL_RSVD5 5
+#define BM_PXP_ALU_A_CTRL_RSVD5 0x000000E0
+#define BF_PXP_ALU_A_CTRL_RSVD5(v) \
+ (((v) << 5) & BM_PXP_ALU_A_CTRL_RSVD5)
+#define BM_PXP_ALU_A_CTRL_START 0x00000010
+#define BF_PXP_ALU_A_CTRL_START(v) \
+ (((v) << 4) & BM_PXP_ALU_A_CTRL_START)
+#define BP_PXP_ALU_A_CTRL_RSVD6 1
+#define BM_PXP_ALU_A_CTRL_RSVD6 0x0000000E
+#define BF_PXP_ALU_A_CTRL_RSVD6(v) \
+ (((v) << 1) & BM_PXP_ALU_A_CTRL_RSVD6)
+#define BM_PXP_ALU_A_CTRL_ENABLE 0x00000001
+#define BF_PXP_ALU_A_CTRL_ENABLE(v) \
+ (((v) << 0) & BM_PXP_ALU_A_CTRL_ENABLE)
+#define BV_PXP_ALU_A_CTRL_ENABLE__0 0x0
+#define BV_PXP_ALU_A_CTRL_ENABLE__1 0x1
+
+#define HW_PXP_ALU_A_BUF_SIZE (0x00002820)
+
+#define BP_PXP_ALU_A_BUF_SIZE_RSVD0 28
+#define BM_PXP_ALU_A_BUF_SIZE_RSVD0 0xF0000000
+#define BF_PXP_ALU_A_BUF_SIZE_RSVD0(v) \
+ (((v) << 28) & BM_PXP_ALU_A_BUF_SIZE_RSVD0)
+#define BP_PXP_ALU_A_BUF_SIZE_BUF_HEIGHT 16
+#define BM_PXP_ALU_A_BUF_SIZE_BUF_HEIGHT 0x0FFF0000
+#define BF_PXP_ALU_A_BUF_SIZE_BUF_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_ALU_A_BUF_SIZE_BUF_HEIGHT)
+#define BP_PXP_ALU_A_BUF_SIZE_RSVD1 12
+#define BM_PXP_ALU_A_BUF_SIZE_RSVD1 0x0000F000
+#define BF_PXP_ALU_A_BUF_SIZE_RSVD1(v) \
+ (((v) << 12) & BM_PXP_ALU_A_BUF_SIZE_RSVD1)
+#define BP_PXP_ALU_A_BUF_SIZE_BUF_WIDTH 0
+#define BM_PXP_ALU_A_BUF_SIZE_BUF_WIDTH 0x00000FFF
+#define BF_PXP_ALU_A_BUF_SIZE_BUF_WIDTH(v) \
+ (((v) << 0) & BM_PXP_ALU_A_BUF_SIZE_BUF_WIDTH)
+
+#define HW_PXP_ALU_A_INST_ENTRY (0x00002830)
+
+#define BP_PXP_ALU_A_INST_ENTRY_RSVD0 16
+#define BM_PXP_ALU_A_INST_ENTRY_RSVD0 0xFFFF0000
+#define BF_PXP_ALU_A_INST_ENTRY_RSVD0(v) \
+ (((v) << 16) & BM_PXP_ALU_A_INST_ENTRY_RSVD0)
+#define BP_PXP_ALU_A_INST_ENTRY_ENTRY_ADDR 0
+#define BM_PXP_ALU_A_INST_ENTRY_ENTRY_ADDR 0x0000FFFF
+#define BF_PXP_ALU_A_INST_ENTRY_ENTRY_ADDR(v) \
+ (((v) << 0) & BM_PXP_ALU_A_INST_ENTRY_ENTRY_ADDR)
+
+#define HW_PXP_ALU_A_PARAM (0x00002840)
+
+#define BP_PXP_ALU_A_PARAM_RSVD0 16
+#define BM_PXP_ALU_A_PARAM_RSVD0 0xFFFF0000
+#define BF_PXP_ALU_A_PARAM_RSVD0(v) \
+ (((v) << 16) & BM_PXP_ALU_A_PARAM_RSVD0)
+#define BP_PXP_ALU_A_PARAM_PARAM1 8
+#define BM_PXP_ALU_A_PARAM_PARAM1 0x0000FF00
+#define BF_PXP_ALU_A_PARAM_PARAM1(v) \
+ (((v) << 8) & BM_PXP_ALU_A_PARAM_PARAM1)
+#define BP_PXP_ALU_A_PARAM_PARAM0 0
+#define BM_PXP_ALU_A_PARAM_PARAM0 0x000000FF
+#define BF_PXP_ALU_A_PARAM_PARAM0(v) \
+ (((v) << 0) & BM_PXP_ALU_A_PARAM_PARAM0)
+
+#define HW_PXP_ALU_A_CONFIG (0x00002850)
+
+#define BP_PXP_ALU_A_CONFIG_BUF_ADDR 0
+#define BM_PXP_ALU_A_CONFIG_BUF_ADDR 0xFFFFFFFF
+#define BF_PXP_ALU_A_CONFIG_BUF_ADDR(v) (v)
+
+#define HW_PXP_ALU_A_LUT_CONFIG (0x00002860)
+#define HW_PXP_ALU_A_LUT_CONFIG_SET (0x00002864)
+#define HW_PXP_ALU_A_LUT_CONFIG_CLR (0x00002868)
+#define HW_PXP_ALU_A_LUT_CONFIG_TOG (0x0000286c)
+
+#define BP_PXP_ALU_A_LUT_CONFIG_RSVD0 6
+#define BM_PXP_ALU_A_LUT_CONFIG_RSVD0 0xFFFFFFC0
+#define BF_PXP_ALU_A_LUT_CONFIG_RSVD0(v) \
+ (((v) << 6) & BM_PXP_ALU_A_LUT_CONFIG_RSVD0)
+#define BP_PXP_ALU_A_LUT_CONFIG_MODE 4
+#define BM_PXP_ALU_A_LUT_CONFIG_MODE 0x00000030
+#define BF_PXP_ALU_A_LUT_CONFIG_MODE(v) \
+ (((v) << 4) & BM_PXP_ALU_A_LUT_CONFIG_MODE)
+#define BV_PXP_ALU_A_LUT_CONFIG_MODE__0 0x0
+#define BV_PXP_ALU_A_LUT_CONFIG_MODE__1 0x1
+#define BV_PXP_ALU_A_LUT_CONFIG_MODE__2 0x2
+#define BV_PXP_ALU_A_LUT_CONFIG_MODE__3 0x3
+#define BP_PXP_ALU_A_LUT_CONFIG_RSVD1 1
+#define BM_PXP_ALU_A_LUT_CONFIG_RSVD1 0x0000000E
+#define BF_PXP_ALU_A_LUT_CONFIG_RSVD1(v) \
+ (((v) << 1) & BM_PXP_ALU_A_LUT_CONFIG_RSVD1)
+#define BM_PXP_ALU_A_LUT_CONFIG_EN 0x00000001
+#define BF_PXP_ALU_A_LUT_CONFIG_EN(v) \
+ (((v) << 0) & BM_PXP_ALU_A_LUT_CONFIG_EN)
+
+#define HW_PXP_ALU_A_LUT_DATA0 (0x00002870)
+
+#define BP_PXP_ALU_A_LUT_DATA0_LUT_DATA_L 0
+#define BM_PXP_ALU_A_LUT_DATA0_LUT_DATA_L 0xFFFFFFFF
+#define BF_PXP_ALU_A_LUT_DATA0_LUT_DATA_L(v) (v)
+
+#define HW_PXP_ALU_A_LUT_DATA1 (0x00002880)
+
+#define BP_PXP_ALU_A_LUT_DATA1_LUT_DATA_H 0
+#define BM_PXP_ALU_A_LUT_DATA1_LUT_DATA_H 0xFFFFFFFF
+#define BF_PXP_ALU_A_LUT_DATA1_LUT_DATA_H(v) (v)
+
+#define HW_PXP_ALU_A_DBG (0x00002890)
+
+#define BP_PXP_ALU_A_DBG_DEBUG_SEL 24
+#define BM_PXP_ALU_A_DBG_DEBUG_SEL 0xFF000000
+#define BF_PXP_ALU_A_DBG_DEBUG_SEL(v) \
+ (((v) << 24) & BM_PXP_ALU_A_DBG_DEBUG_SEL)
+#define BP_PXP_ALU_A_DBG_DEBUG_VALUE 0
+#define BM_PXP_ALU_A_DBG_DEBUG_VALUE 0x00FFFFFF
+#define BF_PXP_ALU_A_DBG_DEBUG_VALUE(v) \
+ (((v) << 0) & BM_PXP_ALU_A_DBG_DEBUG_VALUE)
+
+#define HW_PXP_ALU_B_CTRL (0x000028a0)
+#define HW_PXP_ALU_B_CTRL_SET (0x000028a4)
+#define HW_PXP_ALU_B_CTRL_CLR (0x000028a8)
+#define HW_PXP_ALU_B_CTRL_TOG (0x000028ac)
+
+#define BP_PXP_ALU_B_CTRL_RSVD0 29
+#define BM_PXP_ALU_B_CTRL_RSVD0 0xE0000000
+#define BF_PXP_ALU_B_CTRL_RSVD0(v) \
+ (((v) << 29) & BM_PXP_ALU_B_CTRL_RSVD0)
+#define BM_PXP_ALU_B_CTRL_DONE 0x10000000
+#define BF_PXP_ALU_B_CTRL_DONE(v) \
+ (((v) << 28) & BM_PXP_ALU_B_CTRL_DONE)
+#define BP_PXP_ALU_B_CTRL_RSVD1 21
+#define BM_PXP_ALU_B_CTRL_RSVD1 0x0FE00000
+#define BF_PXP_ALU_B_CTRL_RSVD1(v) \
+ (((v) << 21) & BM_PXP_ALU_B_CTRL_RSVD1)
+#define BM_PXP_ALU_B_CTRL_DONE_IRQ_EN 0x00100000
+#define BF_PXP_ALU_B_CTRL_DONE_IRQ_EN(v) \
+ (((v) << 20) & BM_PXP_ALU_B_CTRL_DONE_IRQ_EN)
+#define BP_PXP_ALU_B_CTRL_RSVD2 17
+#define BM_PXP_ALU_B_CTRL_RSVD2 0x000E0000
+#define BF_PXP_ALU_B_CTRL_RSVD2(v) \
+ (((v) << 17) & BM_PXP_ALU_B_CTRL_RSVD2)
+#define BM_PXP_ALU_B_CTRL_DONE_IRQ_FLAG 0x00010000
+#define BF_PXP_ALU_B_CTRL_DONE_IRQ_FLAG(v) \
+ (((v) << 16) & BM_PXP_ALU_B_CTRL_DONE_IRQ_FLAG)
+#define BP_PXP_ALU_B_CTRL_RSVD3 13
+#define BM_PXP_ALU_B_CTRL_RSVD3 0x0000E000
+#define BF_PXP_ALU_B_CTRL_RSVD3(v) \
+ (((v) << 13) & BM_PXP_ALU_B_CTRL_RSVD3)
+#define BM_PXP_ALU_B_CTRL_BYPASS 0x00001000
+#define BF_PXP_ALU_B_CTRL_BYPASS(v) \
+ (((v) << 12) & BM_PXP_ALU_B_CTRL_BYPASS)
+#define BV_PXP_ALU_B_CTRL_BYPASS__0 0x0
+#define BV_PXP_ALU_B_CTRL_BYPASS__1 0x1
+#define BP_PXP_ALU_B_CTRL_RSVD4 9
+#define BM_PXP_ALU_B_CTRL_RSVD4 0x00000E00
+#define BF_PXP_ALU_B_CTRL_RSVD4(v) \
+ (((v) << 9) & BM_PXP_ALU_B_CTRL_RSVD4)
+#define BM_PXP_ALU_B_CTRL_SW_RESET 0x00000100
+#define BF_PXP_ALU_B_CTRL_SW_RESET(v) \
+ (((v) << 8) & BM_PXP_ALU_B_CTRL_SW_RESET)
+#define BP_PXP_ALU_B_CTRL_RSVD5 5
+#define BM_PXP_ALU_B_CTRL_RSVD5 0x000000E0
+#define BF_PXP_ALU_B_CTRL_RSVD5(v) \
+ (((v) << 5) & BM_PXP_ALU_B_CTRL_RSVD5)
+#define BM_PXP_ALU_B_CTRL_START 0x00000010
+#define BF_PXP_ALU_B_CTRL_START(v) \
+ (((v) << 4) & BM_PXP_ALU_B_CTRL_START)
+#define BP_PXP_ALU_B_CTRL_RSVD6 1
+#define BM_PXP_ALU_B_CTRL_RSVD6 0x0000000E
+#define BF_PXP_ALU_B_CTRL_RSVD6(v) \
+ (((v) << 1) & BM_PXP_ALU_B_CTRL_RSVD6)
+#define BM_PXP_ALU_B_CTRL_ENABLE 0x00000001
+#define BF_PXP_ALU_B_CTRL_ENABLE(v) \
+ (((v) << 0) & BM_PXP_ALU_B_CTRL_ENABLE)
+#define BV_PXP_ALU_B_CTRL_ENABLE__0 0x0
+#define BV_PXP_ALU_B_CTRL_ENABLE__1 0x1
+
+#define HW_PXP_ALU_B_BUF_SIZE (0x000028b0)
+
+#define BP_PXP_ALU_B_BUF_SIZE_RSVD0 28
+#define BM_PXP_ALU_B_BUF_SIZE_RSVD0 0xF0000000
+#define BF_PXP_ALU_B_BUF_SIZE_RSVD0(v) \
+ (((v) << 28) & BM_PXP_ALU_B_BUF_SIZE_RSVD0)
+#define BP_PXP_ALU_B_BUF_SIZE_BUF_HEIGHT 16
+#define BM_PXP_ALU_B_BUF_SIZE_BUF_HEIGHT 0x0FFF0000
+#define BF_PXP_ALU_B_BUF_SIZE_BUF_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_ALU_B_BUF_SIZE_BUF_HEIGHT)
+#define BP_PXP_ALU_B_BUF_SIZE_RSVD1 12
+#define BM_PXP_ALU_B_BUF_SIZE_RSVD1 0x0000F000
+#define BF_PXP_ALU_B_BUF_SIZE_RSVD1(v) \
+ (((v) << 12) & BM_PXP_ALU_B_BUF_SIZE_RSVD1)
+#define BP_PXP_ALU_B_BUF_SIZE_BUF_WIDTH 0
+#define BM_PXP_ALU_B_BUF_SIZE_BUF_WIDTH 0x00000FFF
+#define BF_PXP_ALU_B_BUF_SIZE_BUF_WIDTH(v) \
+ (((v) << 0) & BM_PXP_ALU_B_BUF_SIZE_BUF_WIDTH)
+
+#define HW_PXP_ALU_B_INST_ENTRY (0x000028c0)
+
+#define BP_PXP_ALU_B_INST_ENTRY_RSVD0 16
+#define BM_PXP_ALU_B_INST_ENTRY_RSVD0 0xFFFF0000
+#define BF_PXP_ALU_B_INST_ENTRY_RSVD0(v) \
+ (((v) << 16) & BM_PXP_ALU_B_INST_ENTRY_RSVD0)
+#define BP_PXP_ALU_B_INST_ENTRY_ENTRY_ADDR 0
+#define BM_PXP_ALU_B_INST_ENTRY_ENTRY_ADDR 0x0000FFFF
+#define BF_PXP_ALU_B_INST_ENTRY_ENTRY_ADDR(v) \
+ (((v) << 0) & BM_PXP_ALU_B_INST_ENTRY_ENTRY_ADDR)
+
+#define HW_PXP_ALU_B_PARAM (0x000028d0)
+
+#define BP_PXP_ALU_B_PARAM_RSVD0 16
+#define BM_PXP_ALU_B_PARAM_RSVD0 0xFFFF0000
+#define BF_PXP_ALU_B_PARAM_RSVD0(v) \
+ (((v) << 16) & BM_PXP_ALU_B_PARAM_RSVD0)
+#define BP_PXP_ALU_B_PARAM_PARAM1 8
+#define BM_PXP_ALU_B_PARAM_PARAM1 0x0000FF00
+#define BF_PXP_ALU_B_PARAM_PARAM1(v) \
+ (((v) << 8) & BM_PXP_ALU_B_PARAM_PARAM1)
+#define BP_PXP_ALU_B_PARAM_PARAM0 0
+#define BM_PXP_ALU_B_PARAM_PARAM0 0x000000FF
+#define BF_PXP_ALU_B_PARAM_PARAM0(v) \
+ (((v) << 0) & BM_PXP_ALU_B_PARAM_PARAM0)
+
+#define HW_PXP_ALU_B_CONFIG (0x000028e0)
+
+#define BP_PXP_ALU_B_CONFIG_BUF_ADDR 0
+#define BM_PXP_ALU_B_CONFIG_BUF_ADDR 0xFFFFFFFF
+#define BF_PXP_ALU_B_CONFIG_BUF_ADDR(v) (v)
+
+#define HW_PXP_ALU_B_LUT_CONFIG (0x000028f0)
+#define HW_PXP_ALU_B_LUT_CONFIG_SET (0x000028f4)
+#define HW_PXP_ALU_B_LUT_CONFIG_CLR (0x000028f8)
+#define HW_PXP_ALU_B_LUT_CONFIG_TOG (0x000028fc)
+
+#define BP_PXP_ALU_B_LUT_CONFIG_RSVD0 6
+#define BM_PXP_ALU_B_LUT_CONFIG_RSVD0 0xFFFFFFC0
+#define BF_PXP_ALU_B_LUT_CONFIG_RSVD0(v) \
+ (((v) << 6) & BM_PXP_ALU_B_LUT_CONFIG_RSVD0)
+#define BP_PXP_ALU_B_LUT_CONFIG_MODE 4
+#define BM_PXP_ALU_B_LUT_CONFIG_MODE 0x00000030
+#define BF_PXP_ALU_B_LUT_CONFIG_MODE(v) \
+ (((v) << 4) & BM_PXP_ALU_B_LUT_CONFIG_MODE)
+#define BV_PXP_ALU_B_LUT_CONFIG_MODE__0 0x0
+#define BV_PXP_ALU_B_LUT_CONFIG_MODE__1 0x1
+#define BV_PXP_ALU_B_LUT_CONFIG_MODE__2 0x2
+#define BV_PXP_ALU_B_LUT_CONFIG_MODE__3 0x3
+#define BP_PXP_ALU_B_LUT_CONFIG_RSVD1 1
+#define BM_PXP_ALU_B_LUT_CONFIG_RSVD1 0x0000000E
+#define BF_PXP_ALU_B_LUT_CONFIG_RSVD1(v) \
+ (((v) << 1) & BM_PXP_ALU_B_LUT_CONFIG_RSVD1)
+#define BM_PXP_ALU_B_LUT_CONFIG_EN 0x00000001
+#define BF_PXP_ALU_B_LUT_CONFIG_EN(v) \
+ (((v) << 0) & BM_PXP_ALU_B_LUT_CONFIG_EN)
+
+#define HW_PXP_ALU_B_LUT_DATA0 (0x00002900)
+
+#define BP_PXP_ALU_B_LUT_DATA0_LUT_DATA_L 0
+#define BM_PXP_ALU_B_LUT_DATA0_LUT_DATA_L 0xFFFFFFFF
+#define BF_PXP_ALU_B_LUT_DATA0_LUT_DATA_L(v) (v)
+
+#define HW_PXP_ALU_B_LUT_DATA1 (0x00002910)
+
+#define BP_PXP_ALU_B_LUT_DATA1_LUT_DATA_H 0
+#define BM_PXP_ALU_B_LUT_DATA1_LUT_DATA_H 0xFFFFFFFF
+#define BF_PXP_ALU_B_LUT_DATA1_LUT_DATA_H(v) (v)
+
+#define HW_PXP_ALU_B_DBG (0x00002920)
+
+#define BP_PXP_ALU_B_DBG_DEBUG_SEL 24
+#define BM_PXP_ALU_B_DBG_DEBUG_SEL 0xFF000000
+#define BF_PXP_ALU_B_DBG_DEBUG_SEL(v) \
+ (((v) << 24) & BM_PXP_ALU_B_DBG_DEBUG_SEL)
+#define BP_PXP_ALU_B_DBG_DEBUG_VALUE 0
+#define BM_PXP_ALU_B_DBG_DEBUG_VALUE 0x00FFFFFF
+#define BF_PXP_ALU_B_DBG_DEBUG_VALUE(v) \
+ (((v) << 0) & BM_PXP_ALU_B_DBG_DEBUG_VALUE)
+
+#define HW_PXP_HIST_A_CTRL (0x00002a00)
+
+#define BP_PXP_HIST_A_CTRL_RSVD4 27
+#define BM_PXP_HIST_A_CTRL_RSVD4 0xF8000000
+#define BF_PXP_HIST_A_CTRL_RSVD4(v) \
+ (((v) << 27) & BM_PXP_HIST_A_CTRL_RSVD4)
+#define BP_PXP_HIST_A_CTRL_PIXEL_WIDTH 24
+#define BM_PXP_HIST_A_CTRL_PIXEL_WIDTH 0x07000000
+#define BF_PXP_HIST_A_CTRL_PIXEL_WIDTH(v) \
+ (((v) << 24) & BM_PXP_HIST_A_CTRL_PIXEL_WIDTH)
+#define BM_PXP_HIST_A_CTRL_RSVD3 0x00800000
+#define BF_PXP_HIST_A_CTRL_RSVD3(v) \
+ (((v) << 23) & BM_PXP_HIST_A_CTRL_RSVD3)
+#define BP_PXP_HIST_A_CTRL_PIXEL_OFFSET 16
+#define BM_PXP_HIST_A_CTRL_PIXEL_OFFSET 0x007F0000
+#define BF_PXP_HIST_A_CTRL_PIXEL_OFFSET(v) \
+ (((v) << 16) & BM_PXP_HIST_A_CTRL_PIXEL_OFFSET)
+#define BP_PXP_HIST_A_CTRL_RSVD2 13
+#define BM_PXP_HIST_A_CTRL_RSVD2 0x0000E000
+#define BF_PXP_HIST_A_CTRL_RSVD2(v) \
+ (((v) << 13) & BM_PXP_HIST_A_CTRL_RSVD2)
+#define BP_PXP_HIST_A_CTRL_STATUS 8
+#define BM_PXP_HIST_A_CTRL_STATUS 0x00001F00
+#define BF_PXP_HIST_A_CTRL_STATUS(v) \
+ (((v) << 8) & BM_PXP_HIST_A_CTRL_STATUS)
+#define BP_PXP_HIST_A_CTRL_RSVD1 5
+#define BM_PXP_HIST_A_CTRL_RSVD1 0x000000E0
+#define BF_PXP_HIST_A_CTRL_RSVD1(v) \
+ (((v) << 5) & BM_PXP_HIST_A_CTRL_RSVD1)
+#define BM_PXP_HIST_A_CTRL_CLEAR 0x00000010
+#define BF_PXP_HIST_A_CTRL_CLEAR(v) \
+ (((v) << 4) & BM_PXP_HIST_A_CTRL_CLEAR)
+#define BP_PXP_HIST_A_CTRL_RSVD0 1
+#define BM_PXP_HIST_A_CTRL_RSVD0 0x0000000E
+#define BF_PXP_HIST_A_CTRL_RSVD0(v) \
+ (((v) << 1) & BM_PXP_HIST_A_CTRL_RSVD0)
+#define BM_PXP_HIST_A_CTRL_ENABLE 0x00000001
+#define BF_PXP_HIST_A_CTRL_ENABLE(v) \
+ (((v) << 0) & BM_PXP_HIST_A_CTRL_ENABLE)
+
+#define HW_PXP_HIST_A_MASK (0x00002a10)
+
+#define BP_PXP_HIST_A_MASK_MASK_VALUE1 24
+#define BM_PXP_HIST_A_MASK_MASK_VALUE1 0xFF000000
+#define BF_PXP_HIST_A_MASK_MASK_VALUE1(v) \
+ (((v) << 24) & BM_PXP_HIST_A_MASK_MASK_VALUE1)
+#define BP_PXP_HIST_A_MASK_MASK_VALUE0 16
+#define BM_PXP_HIST_A_MASK_MASK_VALUE0 0x00FF0000
+#define BF_PXP_HIST_A_MASK_MASK_VALUE0(v) \
+ (((v) << 16) & BM_PXP_HIST_A_MASK_MASK_VALUE0)
+#define BP_PXP_HIST_A_MASK_MASK_WIDTH 13
+#define BM_PXP_HIST_A_MASK_MASK_WIDTH 0x0000E000
+#define BF_PXP_HIST_A_MASK_MASK_WIDTH(v) \
+ (((v) << 13) & BM_PXP_HIST_A_MASK_MASK_WIDTH)
+#define BP_PXP_HIST_A_MASK_MASK_OFFSET 6
+#define BM_PXP_HIST_A_MASK_MASK_OFFSET 0x00001FC0
+#define BF_PXP_HIST_A_MASK_MASK_OFFSET(v) \
+ (((v) << 6) & BM_PXP_HIST_A_MASK_MASK_OFFSET)
+#define BP_PXP_HIST_A_MASK_MASK_MODE 4
+#define BM_PXP_HIST_A_MASK_MASK_MODE 0x00000030
+#define BF_PXP_HIST_A_MASK_MASK_MODE(v) \
+ (((v) << 4) & BM_PXP_HIST_A_MASK_MASK_MODE)
+#define BV_PXP_HIST_A_MASK_MASK_MODE__EQUAL 0x0
+#define BV_PXP_HIST_A_MASK_MASK_MODE__NOT_EQUAL 0x1
+#define BV_PXP_HIST_A_MASK_MASK_MODE__INSIDE 0x2
+#define BV_PXP_HIST_A_MASK_MASK_MODE__OUTSIDE 0x3
+#define BP_PXP_HIST_A_MASK_RSVD0 1
+#define BM_PXP_HIST_A_MASK_RSVD0 0x0000000E
+#define BF_PXP_HIST_A_MASK_RSVD0(v) \
+ (((v) << 1) & BM_PXP_HIST_A_MASK_RSVD0)
+#define BM_PXP_HIST_A_MASK_MASK_EN 0x00000001
+#define BF_PXP_HIST_A_MASK_MASK_EN(v) \
+ (((v) << 0) & BM_PXP_HIST_A_MASK_MASK_EN)
+
+#define HW_PXP_HIST_A_BUF_SIZE (0x00002a20)
+
+#define BP_PXP_HIST_A_BUF_SIZE_RSVD0 28
+#define BM_PXP_HIST_A_BUF_SIZE_RSVD0 0xF0000000
+#define BF_PXP_HIST_A_BUF_SIZE_RSVD0(v) \
+ (((v) << 28) & BM_PXP_HIST_A_BUF_SIZE_RSVD0)
+#define BP_PXP_HIST_A_BUF_SIZE_HEIGHT 16
+#define BM_PXP_HIST_A_BUF_SIZE_HEIGHT 0x0FFF0000
+#define BF_PXP_HIST_A_BUF_SIZE_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_HIST_A_BUF_SIZE_HEIGHT)
+#define BP_PXP_HIST_A_BUF_SIZE_RSVD1 12
+#define BM_PXP_HIST_A_BUF_SIZE_RSVD1 0x0000F000
+#define BF_PXP_HIST_A_BUF_SIZE_RSVD1(v) \
+ (((v) << 12) & BM_PXP_HIST_A_BUF_SIZE_RSVD1)
+#define BP_PXP_HIST_A_BUF_SIZE_WIDTH 0
+#define BM_PXP_HIST_A_BUF_SIZE_WIDTH 0x00000FFF
+#define BF_PXP_HIST_A_BUF_SIZE_WIDTH(v) \
+ (((v) << 0) & BM_PXP_HIST_A_BUF_SIZE_WIDTH)
+
+#define HW_PXP_HIST_A_TOTAL_PIXEL (0x00002a30)
+
+#define BP_PXP_HIST_A_TOTAL_PIXEL_RSVD0 24
+#define BM_PXP_HIST_A_TOTAL_PIXEL_RSVD0 0xFF000000
+#define BF_PXP_HIST_A_TOTAL_PIXEL_RSVD0(v) \
+ (((v) << 24) & BM_PXP_HIST_A_TOTAL_PIXEL_RSVD0)
+#define BP_PXP_HIST_A_TOTAL_PIXEL_TOTAL_PIXEL 0
+#define BM_PXP_HIST_A_TOTAL_PIXEL_TOTAL_PIXEL 0x00FFFFFF
+#define BF_PXP_HIST_A_TOTAL_PIXEL_TOTAL_PIXEL(v) \
+ (((v) << 0) & BM_PXP_HIST_A_TOTAL_PIXEL_TOTAL_PIXEL)
+
+#define HW_PXP_HIST_A_ACTIVE_AREA_X (0x00002a40)
+
+#define BP_PXP_HIST_A_ACTIVE_AREA_X_RSVD1 28
+#define BM_PXP_HIST_A_ACTIVE_AREA_X_RSVD1 0xF0000000
+#define BF_PXP_HIST_A_ACTIVE_AREA_X_RSVD1(v) \
+ (((v) << 28) & BM_PXP_HIST_A_ACTIVE_AREA_X_RSVD1)
+#define BP_PXP_HIST_A_ACTIVE_AREA_X_MAX_X_OFFSET 16
+#define BM_PXP_HIST_A_ACTIVE_AREA_X_MAX_X_OFFSET 0x0FFF0000
+#define BF_PXP_HIST_A_ACTIVE_AREA_X_MAX_X_OFFSET(v) \
+ (((v) << 16) & BM_PXP_HIST_A_ACTIVE_AREA_X_MAX_X_OFFSET)
+#define BP_PXP_HIST_A_ACTIVE_AREA_X_RSVD0 12
+#define BM_PXP_HIST_A_ACTIVE_AREA_X_RSVD0 0x0000F000
+#define BF_PXP_HIST_A_ACTIVE_AREA_X_RSVD0(v) \
+ (((v) << 12) & BM_PXP_HIST_A_ACTIVE_AREA_X_RSVD0)
+#define BP_PXP_HIST_A_ACTIVE_AREA_X_MIN_X_OFFSET 0
+#define BM_PXP_HIST_A_ACTIVE_AREA_X_MIN_X_OFFSET 0x00000FFF
+#define BF_PXP_HIST_A_ACTIVE_AREA_X_MIN_X_OFFSET(v) \
+ (((v) << 0) & BM_PXP_HIST_A_ACTIVE_AREA_X_MIN_X_OFFSET)
+
+#define HW_PXP_HIST_A_ACTIVE_AREA_Y (0x00002a50)
+
+#define BP_PXP_HIST_A_ACTIVE_AREA_Y_RSVD1 28
+#define BM_PXP_HIST_A_ACTIVE_AREA_Y_RSVD1 0xF0000000
+#define BF_PXP_HIST_A_ACTIVE_AREA_Y_RSVD1(v) \
+ (((v) << 28) & BM_PXP_HIST_A_ACTIVE_AREA_Y_RSVD1)
+#define BP_PXP_HIST_A_ACTIVE_AREA_Y_MAX_Y_OFFSET 16
+#define BM_PXP_HIST_A_ACTIVE_AREA_Y_MAX_Y_OFFSET 0x0FFF0000
+#define BF_PXP_HIST_A_ACTIVE_AREA_Y_MAX_Y_OFFSET(v) \
+ (((v) << 16) & BM_PXP_HIST_A_ACTIVE_AREA_Y_MAX_Y_OFFSET)
+#define BP_PXP_HIST_A_ACTIVE_AREA_Y_RSVD0 12
+#define BM_PXP_HIST_A_ACTIVE_AREA_Y_RSVD0 0x0000F000
+#define BF_PXP_HIST_A_ACTIVE_AREA_Y_RSVD0(v) \
+ (((v) << 12) & BM_PXP_HIST_A_ACTIVE_AREA_Y_RSVD0)
+#define BP_PXP_HIST_A_ACTIVE_AREA_Y_MIN_Y_OFFSET 0
+#define BM_PXP_HIST_A_ACTIVE_AREA_Y_MIN_Y_OFFSET 0x00000FFF
+#define BF_PXP_HIST_A_ACTIVE_AREA_Y_MIN_Y_OFFSET(v) \
+ (((v) << 0) & BM_PXP_HIST_A_ACTIVE_AREA_Y_MIN_Y_OFFSET)
+
+#define HW_PXP_HIST_A_RAW_STAT0 (0x00002a60)
+
+#define BP_PXP_HIST_A_RAW_STAT0_STAT0 0
+#define BM_PXP_HIST_A_RAW_STAT0_STAT0 0xFFFFFFFF
+#define BF_PXP_HIST_A_RAW_STAT0_STAT0(v) (v)
+
+#define HW_PXP_HIST_A_RAW_STAT1 (0x00002a70)
+
+#define BP_PXP_HIST_A_RAW_STAT1_STAT1 0
+#define BM_PXP_HIST_A_RAW_STAT1_STAT1 0xFFFFFFFF
+#define BF_PXP_HIST_A_RAW_STAT1_STAT1(v) (v)
+
+#define HW_PXP_HIST_B_CTRL (0x00002a80)
+
+#define BP_PXP_HIST_B_CTRL_RSVD4 27
+#define BM_PXP_HIST_B_CTRL_RSVD4 0xF8000000
+#define BF_PXP_HIST_B_CTRL_RSVD4(v) \
+ (((v) << 27) & BM_PXP_HIST_B_CTRL_RSVD4)
+#define BP_PXP_HIST_B_CTRL_PIXEL_WIDTH 24
+#define BM_PXP_HIST_B_CTRL_PIXEL_WIDTH 0x07000000
+#define BF_PXP_HIST_B_CTRL_PIXEL_WIDTH(v) \
+ (((v) << 24) & BM_PXP_HIST_B_CTRL_PIXEL_WIDTH)
+#define BM_PXP_HIST_B_CTRL_RSVD3 0x00800000
+#define BF_PXP_HIST_B_CTRL_RSVD3(v) \
+ (((v) << 23) & BM_PXP_HIST_B_CTRL_RSVD3)
+#define BP_PXP_HIST_B_CTRL_PIXEL_OFFSET 16
+#define BM_PXP_HIST_B_CTRL_PIXEL_OFFSET 0x007F0000
+#define BF_PXP_HIST_B_CTRL_PIXEL_OFFSET(v) \
+ (((v) << 16) & BM_PXP_HIST_B_CTRL_PIXEL_OFFSET)
+#define BP_PXP_HIST_B_CTRL_RSVD2 13
+#define BM_PXP_HIST_B_CTRL_RSVD2 0x0000E000
+#define BF_PXP_HIST_B_CTRL_RSVD2(v) \
+ (((v) << 13) & BM_PXP_HIST_B_CTRL_RSVD2)
+#define BP_PXP_HIST_B_CTRL_STATUS 8
+#define BM_PXP_HIST_B_CTRL_STATUS 0x00001F00
+#define BF_PXP_HIST_B_CTRL_STATUS(v) \
+ (((v) << 8) & BM_PXP_HIST_B_CTRL_STATUS)
+#define BP_PXP_HIST_B_CTRL_RSVD1 5
+#define BM_PXP_HIST_B_CTRL_RSVD1 0x000000E0
+#define BF_PXP_HIST_B_CTRL_RSVD1(v) \
+ (((v) << 5) & BM_PXP_HIST_B_CTRL_RSVD1)
+#define BM_PXP_HIST_B_CTRL_CLEAR 0x00000010
+#define BF_PXP_HIST_B_CTRL_CLEAR(v) \
+ (((v) << 4) & BM_PXP_HIST_B_CTRL_CLEAR)
+#define BP_PXP_HIST_B_CTRL_RSVD0 1
+#define BM_PXP_HIST_B_CTRL_RSVD0 0x0000000E
+#define BF_PXP_HIST_B_CTRL_RSVD0(v) \
+ (((v) << 1) & BM_PXP_HIST_B_CTRL_RSVD0)
+#define BM_PXP_HIST_B_CTRL_ENABLE 0x00000001
+#define BF_PXP_HIST_B_CTRL_ENABLE(v) \
+ (((v) << 0) & BM_PXP_HIST_B_CTRL_ENABLE)
+
+#define HW_PXP_HIST_B_MASK (0x00002a90)
+
+#define BP_PXP_HIST_B_MASK_MASK_VALUE1 24
+#define BM_PXP_HIST_B_MASK_MASK_VALUE1 0xFF000000
+#define BF_PXP_HIST_B_MASK_MASK_VALUE1(v) \
+ (((v) << 24) & BM_PXP_HIST_B_MASK_MASK_VALUE1)
+#define BP_PXP_HIST_B_MASK_MASK_VALUE0 16
+#define BM_PXP_HIST_B_MASK_MASK_VALUE0 0x00FF0000
+#define BF_PXP_HIST_B_MASK_MASK_VALUE0(v) \
+ (((v) << 16) & BM_PXP_HIST_B_MASK_MASK_VALUE0)
+#define BP_PXP_HIST_B_MASK_MASK_WIDTH 13
+#define BM_PXP_HIST_B_MASK_MASK_WIDTH 0x0000E000
+#define BF_PXP_HIST_B_MASK_MASK_WIDTH(v) \
+ (((v) << 13) & BM_PXP_HIST_B_MASK_MASK_WIDTH)
+#define BP_PXP_HIST_B_MASK_MASK_OFFSET 6
+#define BM_PXP_HIST_B_MASK_MASK_OFFSET 0x00001FC0
+#define BF_PXP_HIST_B_MASK_MASK_OFFSET(v) \
+ (((v) << 6) & BM_PXP_HIST_B_MASK_MASK_OFFSET)
+#define BP_PXP_HIST_B_MASK_MASK_MODE 4
+#define BM_PXP_HIST_B_MASK_MASK_MODE 0x00000030
+#define BF_PXP_HIST_B_MASK_MASK_MODE(v) \
+ (((v) << 4) & BM_PXP_HIST_B_MASK_MASK_MODE)
+#define BV_PXP_HIST_B_MASK_MASK_MODE__EQUAL 0x0
+#define BV_PXP_HIST_B_MASK_MASK_MODE__NOT_EQUAL 0x1
+#define BV_PXP_HIST_B_MASK_MASK_MODE__INSIDE 0x2
+#define BV_PXP_HIST_B_MASK_MASK_MODE__OUTSIDE 0x3
+#define BP_PXP_HIST_B_MASK_RSVD0 1
+#define BM_PXP_HIST_B_MASK_RSVD0 0x0000000E
+#define BF_PXP_HIST_B_MASK_RSVD0(v) \
+ (((v) << 1) & BM_PXP_HIST_B_MASK_RSVD0)
+#define BM_PXP_HIST_B_MASK_MASK_EN 0x00000001
+#define BF_PXP_HIST_B_MASK_MASK_EN(v) \
+ (((v) << 0) & BM_PXP_HIST_B_MASK_MASK_EN)
+
+#define HW_PXP_HIST_B_BUF_SIZE (0x00002aa0)
+
+#define BP_PXP_HIST_B_BUF_SIZE_RSVD0 28
+#define BM_PXP_HIST_B_BUF_SIZE_RSVD0 0xF0000000
+#define BF_PXP_HIST_B_BUF_SIZE_RSVD0(v) \
+ (((v) << 28) & BM_PXP_HIST_B_BUF_SIZE_RSVD0)
+#define BP_PXP_HIST_B_BUF_SIZE_HEIGHT 16
+#define BM_PXP_HIST_B_BUF_SIZE_HEIGHT 0x0FFF0000
+#define BF_PXP_HIST_B_BUF_SIZE_HEIGHT(v) \
+ (((v) << 16) & BM_PXP_HIST_B_BUF_SIZE_HEIGHT)
+#define BP_PXP_HIST_B_BUF_SIZE_RSVD1 12
+#define BM_PXP_HIST_B_BUF_SIZE_RSVD1 0x0000F000
+#define BF_PXP_HIST_B_BUF_SIZE_RSVD1(v) \
+ (((v) << 12) & BM_PXP_HIST_B_BUF_SIZE_RSVD1)
+#define BP_PXP_HIST_B_BUF_SIZE_WIDTH 0
+#define BM_PXP_HIST_B_BUF_SIZE_WIDTH 0x00000FFF
+#define BF_PXP_HIST_B_BUF_SIZE_WIDTH(v) \
+ (((v) << 0) & BM_PXP_HIST_B_BUF_SIZE_WIDTH)
+
+#define HW_PXP_HIST_B_TOTAL_PIXEL (0x00002ab0)
+
+#define BP_PXP_HIST_B_TOTAL_PIXEL_RSVD0 24
+#define BM_PXP_HIST_B_TOTAL_PIXEL_RSVD0 0xFF000000
+#define BF_PXP_HIST_B_TOTAL_PIXEL_RSVD0(v) \
+ (((v) << 24) & BM_PXP_HIST_B_TOTAL_PIXEL_RSVD0)
+#define BP_PXP_HIST_B_TOTAL_PIXEL_TOTAL_PIXEL 0
+#define BM_PXP_HIST_B_TOTAL_PIXEL_TOTAL_PIXEL 0x00FFFFFF
+#define BF_PXP_HIST_B_TOTAL_PIXEL_TOTAL_PIXEL(v) \
+ (((v) << 0) & BM_PXP_HIST_B_TOTAL_PIXEL_TOTAL_PIXEL)
+
+#define HW_PXP_HIST_B_ACTIVE_AREA_X (0x00002ac0)
+
+#define BP_PXP_HIST_B_ACTIVE_AREA_X_RSVD1 28
+#define BM_PXP_HIST_B_ACTIVE_AREA_X_RSVD1 0xF0000000
+#define BF_PXP_HIST_B_ACTIVE_AREA_X_RSVD1(v) \
+ (((v) << 28) & BM_PXP_HIST_B_ACTIVE_AREA_X_RSVD1)
+#define BP_PXP_HIST_B_ACTIVE_AREA_X_MAX_X_OFFSET 16
+#define BM_PXP_HIST_B_ACTIVE_AREA_X_MAX_X_OFFSET 0x0FFF0000
+#define BF_PXP_HIST_B_ACTIVE_AREA_X_MAX_X_OFFSET(v) \
+ (((v) << 16) & BM_PXP_HIST_B_ACTIVE_AREA_X_MAX_X_OFFSET)
+#define BP_PXP_HIST_B_ACTIVE_AREA_X_RSVD0 12
+#define BM_PXP_HIST_B_ACTIVE_AREA_X_RSVD0 0x0000F000
+#define BF_PXP_HIST_B_ACTIVE_AREA_X_RSVD0(v) \
+ (((v) << 12) & BM_PXP_HIST_B_ACTIVE_AREA_X_RSVD0)
+#define BP_PXP_HIST_B_ACTIVE_AREA_X_MIN_X_OFFSET 0
+#define BM_PXP_HIST_B_ACTIVE_AREA_X_MIN_X_OFFSET 0x00000FFF
+#define BF_PXP_HIST_B_ACTIVE_AREA_X_MIN_X_OFFSET(v) \
+ (((v) << 0) & BM_PXP_HIST_B_ACTIVE_AREA_X_MIN_X_OFFSET)
+
+#define HW_PXP_HIST_B_ACTIVE_AREA_Y (0x00002ad0)
+
+#define BP_PXP_HIST_B_ACTIVE_AREA_Y_RSVD1 28
+#define BM_PXP_HIST_B_ACTIVE_AREA_Y_RSVD1 0xF0000000
+#define BF_PXP_HIST_B_ACTIVE_AREA_Y_RSVD1(v) \
+ (((v) << 28) & BM_PXP_HIST_B_ACTIVE_AREA_Y_RSVD1)
+#define BP_PXP_HIST_B_ACTIVE_AREA_Y_MAX_Y_OFFSET 16
+#define BM_PXP_HIST_B_ACTIVE_AREA_Y_MAX_Y_OFFSET 0x0FFF0000
+#define BF_PXP_HIST_B_ACTIVE_AREA_Y_MAX_Y_OFFSET(v) \
+ (((v) << 16) & BM_PXP_HIST_B_ACTIVE_AREA_Y_MAX_Y_OFFSET)
+#define BP_PXP_HIST_B_ACTIVE_AREA_Y_RSVD0 12
+#define BM_PXP_HIST_B_ACTIVE_AREA_Y_RSVD0 0x0000F000
+#define BF_PXP_HIST_B_ACTIVE_AREA_Y_RSVD0(v) \
+ (((v) << 12) & BM_PXP_HIST_B_ACTIVE_AREA_Y_RSVD0)
+#define BP_PXP_HIST_B_ACTIVE_AREA_Y_MIN_Y_OFFSET 0
+#define BM_PXP_HIST_B_ACTIVE_AREA_Y_MIN_Y_OFFSET 0x00000FFF
+#define BF_PXP_HIST_B_ACTIVE_AREA_Y_MIN_Y_OFFSET(v) \
+ (((v) << 0) & BM_PXP_HIST_B_ACTIVE_AREA_Y_MIN_Y_OFFSET)
+
+#define HW_PXP_HIST_B_RAW_STAT0 (0x00002ae0)
+
+#define BP_PXP_HIST_B_RAW_STAT0_STAT0 0
+#define BM_PXP_HIST_B_RAW_STAT0_STAT0 0xFFFFFFFF
+#define BF_PXP_HIST_B_RAW_STAT0_STAT0(v) (v)
+
+#define HW_PXP_HIST_B_RAW_STAT1 (0x00002af0)
+
+#define BP_PXP_HIST_B_RAW_STAT1_STAT1 0
+#define BM_PXP_HIST_B_RAW_STAT1_STAT1 0xFFFFFFFF
+#define BF_PXP_HIST_B_RAW_STAT1_STAT1(v) (v)
+
+#define HW_PXP_HIST2_PARAM (0x00002b00)
+
+#define BP_PXP_HIST2_PARAM_RSVD 16
+#define BM_PXP_HIST2_PARAM_RSVD 0xFFFF0000
+#define BF_PXP_HIST2_PARAM_RSVD(v) \
+ (((v) << 16) & BM_PXP_HIST2_PARAM_RSVD)
+#define BP_PXP_HIST2_PARAM_RSVD1 14
+#define BM_PXP_HIST2_PARAM_RSVD1 0x0000C000
+#define BF_PXP_HIST2_PARAM_RSVD1(v) \
+ (((v) << 14) & BM_PXP_HIST2_PARAM_RSVD1)
+#define BP_PXP_HIST2_PARAM_VALUE1 8
+#define BM_PXP_HIST2_PARAM_VALUE1 0x00003F00
+#define BF_PXP_HIST2_PARAM_VALUE1(v) \
+ (((v) << 8) & BM_PXP_HIST2_PARAM_VALUE1)
+#define BP_PXP_HIST2_PARAM_RSVD0 6
+#define BM_PXP_HIST2_PARAM_RSVD0 0x000000C0
+#define BF_PXP_HIST2_PARAM_RSVD0(v) \
+ (((v) << 6) & BM_PXP_HIST2_PARAM_RSVD0)
+#define BP_PXP_HIST2_PARAM_VALUE0 0
+#define BM_PXP_HIST2_PARAM_VALUE0 0x0000003F
+#define BF_PXP_HIST2_PARAM_VALUE0(v) \
+ (((v) << 0) & BM_PXP_HIST2_PARAM_VALUE0)
+
+#define HW_PXP_HIST4_PARAM (0x00002b10)
+
+#define BP_PXP_HIST4_PARAM_RSVD3 30
+#define BM_PXP_HIST4_PARAM_RSVD3 0xC0000000
+#define BF_PXP_HIST4_PARAM_RSVD3(v) \
+ (((v) << 30) & BM_PXP_HIST4_PARAM_RSVD3)
+#define BP_PXP_HIST4_PARAM_VALUE3 24
+#define BM_PXP_HIST4_PARAM_VALUE3 0x3F000000
+#define BF_PXP_HIST4_PARAM_VALUE3(v) \
+ (((v) << 24) & BM_PXP_HIST4_PARAM_VALUE3)
+#define BP_PXP_HIST4_PARAM_RSVD2 22
+#define BM_PXP_HIST4_PARAM_RSVD2 0x00C00000
+#define BF_PXP_HIST4_PARAM_RSVD2(v) \
+ (((v) << 22) & BM_PXP_HIST4_PARAM_RSVD2)
+#define BP_PXP_HIST4_PARAM_VALUE2 16
+#define BM_PXP_HIST4_PARAM_VALUE2 0x003F0000
+#define BF_PXP_HIST4_PARAM_VALUE2(v) \
+ (((v) << 16) & BM_PXP_HIST4_PARAM_VALUE2)
+#define BP_PXP_HIST4_PARAM_RSVD1 14
+#define BM_PXP_HIST4_PARAM_RSVD1 0x0000C000
+#define BF_PXP_HIST4_PARAM_RSVD1(v) \
+ (((v) << 14) & BM_PXP_HIST4_PARAM_RSVD1)
+#define BP_PXP_HIST4_PARAM_VALUE1 8
+#define BM_PXP_HIST4_PARAM_VALUE1 0x00003F00
+#define BF_PXP_HIST4_PARAM_VALUE1(v) \
+ (((v) << 8) & BM_PXP_HIST4_PARAM_VALUE1)
+#define BP_PXP_HIST4_PARAM_RSVD0 6
+#define BM_PXP_HIST4_PARAM_RSVD0 0x000000C0
+#define BF_PXP_HIST4_PARAM_RSVD0(v) \
+ (((v) << 6) & BM_PXP_HIST4_PARAM_RSVD0)
+#define BP_PXP_HIST4_PARAM_VALUE0 0
+#define BM_PXP_HIST4_PARAM_VALUE0 0x0000003F
+#define BF_PXP_HIST4_PARAM_VALUE0(v) \
+ (((v) << 0) & BM_PXP_HIST4_PARAM_VALUE0)
+
+#define HW_PXP_HIST8_PARAM0 (0x00002b20)
+
+#define BP_PXP_HIST8_PARAM0_RSVD3 30
+#define BM_PXP_HIST8_PARAM0_RSVD3 0xC0000000
+#define BF_PXP_HIST8_PARAM0_RSVD3(v) \
+ (((v) << 30) & BM_PXP_HIST8_PARAM0_RSVD3)
+#define BP_PXP_HIST8_PARAM0_VALUE3 24
+#define BM_PXP_HIST8_PARAM0_VALUE3 0x3F000000
+#define BF_PXP_HIST8_PARAM0_VALUE3(v) \
+ (((v) << 24) & BM_PXP_HIST8_PARAM0_VALUE3)
+#define BP_PXP_HIST8_PARAM0_RSVD2 22
+#define BM_PXP_HIST8_PARAM0_RSVD2 0x00C00000
+#define BF_PXP_HIST8_PARAM0_RSVD2(v) \
+ (((v) << 22) & BM_PXP_HIST8_PARAM0_RSVD2)
+#define BP_PXP_HIST8_PARAM0_VALUE2 16
+#define BM_PXP_HIST8_PARAM0_VALUE2 0x003F0000
+#define BF_PXP_HIST8_PARAM0_VALUE2(v) \
+ (((v) << 16) & BM_PXP_HIST8_PARAM0_VALUE2)
+#define BP_PXP_HIST8_PARAM0_RSVD1 14
+#define BM_PXP_HIST8_PARAM0_RSVD1 0x0000C000
+#define BF_PXP_HIST8_PARAM0_RSVD1(v) \
+ (((v) << 14) & BM_PXP_HIST8_PARAM0_RSVD1)
+#define BP_PXP_HIST8_PARAM0_VALUE1 8
+#define BM_PXP_HIST8_PARAM0_VALUE1 0x00003F00
+#define BF_PXP_HIST8_PARAM0_VALUE1(v) \
+ (((v) << 8) & BM_PXP_HIST8_PARAM0_VALUE1)
+#define BP_PXP_HIST8_PARAM0_RSVD0 6
+#define BM_PXP_HIST8_PARAM0_RSVD0 0x000000C0
+#define BF_PXP_HIST8_PARAM0_RSVD0(v) \
+ (((v) << 6) & BM_PXP_HIST8_PARAM0_RSVD0)
+#define BP_PXP_HIST8_PARAM0_VALUE0 0
+#define BM_PXP_HIST8_PARAM0_VALUE0 0x0000003F
+#define BF_PXP_HIST8_PARAM0_VALUE0(v) \
+ (((v) << 0) & BM_PXP_HIST8_PARAM0_VALUE0)
+
+#define HW_PXP_HIST8_PARAM1 (0x00002b30)
+
+#define BP_PXP_HIST8_PARAM1_RSVD7 30
+#define BM_PXP_HIST8_PARAM1_RSVD7 0xC0000000
+#define BF_PXP_HIST8_PARAM1_RSVD7(v) \
+ (((v) << 30) & BM_PXP_HIST8_PARAM1_RSVD7)
+#define BP_PXP_HIST8_PARAM1_VALUE7 24
+#define BM_PXP_HIST8_PARAM1_VALUE7 0x3F000000
+#define BF_PXP_HIST8_PARAM1_VALUE7(v) \
+ (((v) << 24) & BM_PXP_HIST8_PARAM1_VALUE7)
+#define BP_PXP_HIST8_PARAM1_RSVD6 22
+#define BM_PXP_HIST8_PARAM1_RSVD6 0x00C00000
+#define BF_PXP_HIST8_PARAM1_RSVD6(v) \
+ (((v) << 22) & BM_PXP_HIST8_PARAM1_RSVD6)
+#define BP_PXP_HIST8_PARAM1_VALUE6 16
+#define BM_PXP_HIST8_PARAM1_VALUE6 0x003F0000
+#define BF_PXP_HIST8_PARAM1_VALUE6(v) \
+ (((v) << 16) & BM_PXP_HIST8_PARAM1_VALUE6)
+#define BP_PXP_HIST8_PARAM1_RSVD5 14
+#define BM_PXP_HIST8_PARAM1_RSVD5 0x0000C000
+#define BF_PXP_HIST8_PARAM1_RSVD5(v) \
+ (((v) << 14) & BM_PXP_HIST8_PARAM1_RSVD5)
+#define BP_PXP_HIST8_PARAM1_VALUE5 8
+#define BM_PXP_HIST8_PARAM1_VALUE5 0x00003F00
+#define BF_PXP_HIST8_PARAM1_VALUE5(v) \
+ (((v) << 8) & BM_PXP_HIST8_PARAM1_VALUE5)
+#define BP_PXP_HIST8_PARAM1_RSVD4 6
+#define BM_PXP_HIST8_PARAM1_RSVD4 0x000000C0
+#define BF_PXP_HIST8_PARAM1_RSVD4(v) \
+ (((v) << 6) & BM_PXP_HIST8_PARAM1_RSVD4)
+#define BP_PXP_HIST8_PARAM1_VALUE4 0
+#define BM_PXP_HIST8_PARAM1_VALUE4 0x0000003F
+#define BF_PXP_HIST8_PARAM1_VALUE4(v) \
+ (((v) << 0) & BM_PXP_HIST8_PARAM1_VALUE4)
+
+#define HW_PXP_HIST16_PARAM0 (0x00002b40)
+
+#define BP_PXP_HIST16_PARAM0_RSVD3 30
+#define BM_PXP_HIST16_PARAM0_RSVD3 0xC0000000
+#define BF_PXP_HIST16_PARAM0_RSVD3(v) \
+ (((v) << 30) & BM_PXP_HIST16_PARAM0_RSVD3)
+#define BP_PXP_HIST16_PARAM0_VALUE3 24
+#define BM_PXP_HIST16_PARAM0_VALUE3 0x3F000000
+#define BF_PXP_HIST16_PARAM0_VALUE3(v) \
+ (((v) << 24) & BM_PXP_HIST16_PARAM0_VALUE3)
+#define BP_PXP_HIST16_PARAM0_RSVD2 22
+#define BM_PXP_HIST16_PARAM0_RSVD2 0x00C00000
+#define BF_PXP_HIST16_PARAM0_RSVD2(v) \
+ (((v) << 22) & BM_PXP_HIST16_PARAM0_RSVD2)
+#define BP_PXP_HIST16_PARAM0_VALUE2 16
+#define BM_PXP_HIST16_PARAM0_VALUE2 0x003F0000
+#define BF_PXP_HIST16_PARAM0_VALUE2(v) \
+ (((v) << 16) & BM_PXP_HIST16_PARAM0_VALUE2)
+#define BP_PXP_HIST16_PARAM0_RSVD1 14
+#define BM_PXP_HIST16_PARAM0_RSVD1 0x0000C000
+#define BF_PXP_HIST16_PARAM0_RSVD1(v) \
+ (((v) << 14) & BM_PXP_HIST16_PARAM0_RSVD1)
+#define BP_PXP_HIST16_PARAM0_VALUE1 8
+#define BM_PXP_HIST16_PARAM0_VALUE1 0x00003F00
+#define BF_PXP_HIST16_PARAM0_VALUE1(v) \
+ (((v) << 8) & BM_PXP_HIST16_PARAM0_VALUE1)
+#define BP_PXP_HIST16_PARAM0_RSVD0 6
+#define BM_PXP_HIST16_PARAM0_RSVD0 0x000000C0
+#define BF_PXP_HIST16_PARAM0_RSVD0(v) \
+ (((v) << 6) & BM_PXP_HIST16_PARAM0_RSVD0)
+#define BP_PXP_HIST16_PARAM0_VALUE0 0
+#define BM_PXP_HIST16_PARAM0_VALUE0 0x0000003F
+#define BF_PXP_HIST16_PARAM0_VALUE0(v) \
+ (((v) << 0) & BM_PXP_HIST16_PARAM0_VALUE0)
+
+#define HW_PXP_HIST16_PARAM1 (0x00002b50)
+
+#define BP_PXP_HIST16_PARAM1_RSVD7 30
+#define BM_PXP_HIST16_PARAM1_RSVD7 0xC0000000
+#define BF_PXP_HIST16_PARAM1_RSVD7(v) \
+ (((v) << 30) & BM_PXP_HIST16_PARAM1_RSVD7)
+#define BP_PXP_HIST16_PARAM1_VALUE7 24
+#define BM_PXP_HIST16_PARAM1_VALUE7 0x3F000000
+#define BF_PXP_HIST16_PARAM1_VALUE7(v) \
+ (((v) << 24) & BM_PXP_HIST16_PARAM1_VALUE7)
+#define BP_PXP_HIST16_PARAM1_RSVD6 22
+#define BM_PXP_HIST16_PARAM1_RSVD6 0x00C00000
+#define BF_PXP_HIST16_PARAM1_RSVD6(v) \
+ (((v) << 22) & BM_PXP_HIST16_PARAM1_RSVD6)
+#define BP_PXP_HIST16_PARAM1_VALUE6 16
+#define BM_PXP_HIST16_PARAM1_VALUE6 0x003F0000
+#define BF_PXP_HIST16_PARAM1_VALUE6(v) \
+ (((v) << 16) & BM_PXP_HIST16_PARAM1_VALUE6)
+#define BP_PXP_HIST16_PARAM1_RSVD5 14
+#define BM_PXP_HIST16_PARAM1_RSVD5 0x0000C000
+#define BF_PXP_HIST16_PARAM1_RSVD5(v) \
+ (((v) << 14) & BM_PXP_HIST16_PARAM1_RSVD5)
+#define BP_PXP_HIST16_PARAM1_VALUE5 8
+#define BM_PXP_HIST16_PARAM1_VALUE5 0x00003F00
+#define BF_PXP_HIST16_PARAM1_VALUE5(v) \
+ (((v) << 8) & BM_PXP_HIST16_PARAM1_VALUE5)
+#define BP_PXP_HIST16_PARAM1_RSVD4 6
+#define BM_PXP_HIST16_PARAM1_RSVD4 0x000000C0
+#define BF_PXP_HIST16_PARAM1_RSVD4(v) \
+ (((v) << 6) & BM_PXP_HIST16_PARAM1_RSVD4)
+#define BP_PXP_HIST16_PARAM1_VALUE4 0
+#define BM_PXP_HIST16_PARAM1_VALUE4 0x0000003F
+#define BF_PXP_HIST16_PARAM1_VALUE4(v) \
+ (((v) << 0) & BM_PXP_HIST16_PARAM1_VALUE4)
+
+#define HW_PXP_HIST16_PARAM2 (0x00002b60)
+
+#define BP_PXP_HIST16_PARAM2_RSVD11 30
+#define BM_PXP_HIST16_PARAM2_RSVD11 0xC0000000
+#define BF_PXP_HIST16_PARAM2_RSVD11(v) \
+ (((v) << 30) & BM_PXP_HIST16_PARAM2_RSVD11)
+#define BP_PXP_HIST16_PARAM2_VALUE11 24
+#define BM_PXP_HIST16_PARAM2_VALUE11 0x3F000000
+#define BF_PXP_HIST16_PARAM2_VALUE11(v) \
+ (((v) << 24) & BM_PXP_HIST16_PARAM2_VALUE11)
+#define BP_PXP_HIST16_PARAM2_RSVD10 22
+#define BM_PXP_HIST16_PARAM2_RSVD10 0x00C00000
+#define BF_PXP_HIST16_PARAM2_RSVD10(v) \
+ (((v) << 22) & BM_PXP_HIST16_PARAM2_RSVD10)
+#define BP_PXP_HIST16_PARAM2_VALUE10 16
+#define BM_PXP_HIST16_PARAM2_VALUE10 0x003F0000
+#define BF_PXP_HIST16_PARAM2_VALUE10(v) \
+ (((v) << 16) & BM_PXP_HIST16_PARAM2_VALUE10)
+#define BP_PXP_HIST16_PARAM2_RSVD9 14
+#define BM_PXP_HIST16_PARAM2_RSVD9 0x0000C000
+#define BF_PXP_HIST16_PARAM2_RSVD9(v) \
+ (((v) << 14) & BM_PXP_HIST16_PARAM2_RSVD9)
+#define BP_PXP_HIST16_PARAM2_VALUE9 8
+#define BM_PXP_HIST16_PARAM2_VALUE9 0x00003F00
+#define BF_PXP_HIST16_PARAM2_VALUE9(v) \
+ (((v) << 8) & BM_PXP_HIST16_PARAM2_VALUE9)
+#define BP_PXP_HIST16_PARAM2_RSVD8 6
+#define BM_PXP_HIST16_PARAM2_RSVD8 0x000000C0
+#define BF_PXP_HIST16_PARAM2_RSVD8(v) \
+ (((v) << 6) & BM_PXP_HIST16_PARAM2_RSVD8)
+#define BP_PXP_HIST16_PARAM2_VALUE8 0
+#define BM_PXP_HIST16_PARAM2_VALUE8 0x0000003F
+#define BF_PXP_HIST16_PARAM2_VALUE8(v) \
+ (((v) << 0) & BM_PXP_HIST16_PARAM2_VALUE8)
+
+#define HW_PXP_HIST16_PARAM3 (0x00002b70)
+
+#define BP_PXP_HIST16_PARAM3_RSVD15 30
+#define BM_PXP_HIST16_PARAM3_RSVD15 0xC0000000
+#define BF_PXP_HIST16_PARAM3_RSVD15(v) \
+ (((v) << 30) & BM_PXP_HIST16_PARAM3_RSVD15)
+#define BP_PXP_HIST16_PARAM3_VALUE15 24
+#define BM_PXP_HIST16_PARAM3_VALUE15 0x3F000000
+#define BF_PXP_HIST16_PARAM3_VALUE15(v) \
+ (((v) << 24) & BM_PXP_HIST16_PARAM3_VALUE15)
+#define BP_PXP_HIST16_PARAM3_RSVD14 22
+#define BM_PXP_HIST16_PARAM3_RSVD14 0x00C00000
+#define BF_PXP_HIST16_PARAM3_RSVD14(v) \
+ (((v) << 22) & BM_PXP_HIST16_PARAM3_RSVD14)
+#define BP_PXP_HIST16_PARAM3_VALUE14 16
+#define BM_PXP_HIST16_PARAM3_VALUE14 0x003F0000
+#define BF_PXP_HIST16_PARAM3_VALUE14(v) \
+ (((v) << 16) & BM_PXP_HIST16_PARAM3_VALUE14)
+#define BP_PXP_HIST16_PARAM3_RSVD13 14
+#define BM_PXP_HIST16_PARAM3_RSVD13 0x0000C000
+#define BF_PXP_HIST16_PARAM3_RSVD13(v) \
+ (((v) << 14) & BM_PXP_HIST16_PARAM3_RSVD13)
+#define BP_PXP_HIST16_PARAM3_VALUE13 8
+#define BM_PXP_HIST16_PARAM3_VALUE13 0x00003F00
+#define BF_PXP_HIST16_PARAM3_VALUE13(v) \
+ (((v) << 8) & BM_PXP_HIST16_PARAM3_VALUE13)
+#define BP_PXP_HIST16_PARAM3_RSVD12 6
+#define BM_PXP_HIST16_PARAM3_RSVD12 0x000000C0
+#define BF_PXP_HIST16_PARAM3_RSVD12(v) \
+ (((v) << 6) & BM_PXP_HIST16_PARAM3_RSVD12)
+#define BP_PXP_HIST16_PARAM3_VALUE12 0
+#define BM_PXP_HIST16_PARAM3_VALUE12 0x0000003F
+#define BF_PXP_HIST16_PARAM3_VALUE12(v) \
+ (((v) << 0) & BM_PXP_HIST16_PARAM3_VALUE12)
+
+#define HW_PXP_HIST32_PARAM0 (0x00002b80)
+
+#define BP_PXP_HIST32_PARAM0_RSVD3 30
+#define BM_PXP_HIST32_PARAM0_RSVD3 0xC0000000
+#define BF_PXP_HIST32_PARAM0_RSVD3(v) \
+ (((v) << 30) & BM_PXP_HIST32_PARAM0_RSVD3)
+#define BP_PXP_HIST32_PARAM0_VALUE3 24
+#define BM_PXP_HIST32_PARAM0_VALUE3 0x3F000000
+#define BF_PXP_HIST32_PARAM0_VALUE3(v) \
+ (((v) << 24) & BM_PXP_HIST32_PARAM0_VALUE3)
+#define BP_PXP_HIST32_PARAM0_RSVD2 22
+#define BM_PXP_HIST32_PARAM0_RSVD2 0x00C00000
+#define BF_PXP_HIST32_PARAM0_RSVD2(v) \
+ (((v) << 22) & BM_PXP_HIST32_PARAM0_RSVD2)
+#define BP_PXP_HIST32_PARAM0_VALUE2 16
+#define BM_PXP_HIST32_PARAM0_VALUE2 0x003F0000
+#define BF_PXP_HIST32_PARAM0_VALUE2(v) \
+ (((v) << 16) & BM_PXP_HIST32_PARAM0_VALUE2)
+#define BP_PXP_HIST32_PARAM0_RSVD1 14
+#define BM_PXP_HIST32_PARAM0_RSVD1 0x0000C000
+#define BF_PXP_HIST32_PARAM0_RSVD1(v) \
+ (((v) << 14) & BM_PXP_HIST32_PARAM0_RSVD1)
+#define BP_PXP_HIST32_PARAM0_VALUE1 8
+#define BM_PXP_HIST32_PARAM0_VALUE1 0x00003F00
+#define BF_PXP_HIST32_PARAM0_VALUE1(v) \
+ (((v) << 8) & BM_PXP_HIST32_PARAM0_VALUE1)
+#define BP_PXP_HIST32_PARAM0_RSVD0 6
+#define BM_PXP_HIST32_PARAM0_RSVD0 0x000000C0
+#define BF_PXP_HIST32_PARAM0_RSVD0(v) \
+ (((v) << 6) & BM_PXP_HIST32_PARAM0_RSVD0)
+#define BP_PXP_HIST32_PARAM0_VALUE0 0
+#define BM_PXP_HIST32_PARAM0_VALUE0 0x0000003F
+#define BF_PXP_HIST32_PARAM0_VALUE0(v) \
+ (((v) << 0) & BM_PXP_HIST32_PARAM0_VALUE0)
+
+#define HW_PXP_HIST32_PARAM1 (0x00002b90)
+
+#define BP_PXP_HIST32_PARAM1_RSVD7 30
+#define BM_PXP_HIST32_PARAM1_RSVD7 0xC0000000
+#define BF_PXP_HIST32_PARAM1_RSVD7(v) \
+ (((v) << 30) & BM_PXP_HIST32_PARAM1_RSVD7)
+#define BP_PXP_HIST32_PARAM1_VALUE7 24
+#define BM_PXP_HIST32_PARAM1_VALUE7 0x3F000000
+#define BF_PXP_HIST32_PARAM1_VALUE7(v) \
+ (((v) << 24) & BM_PXP_HIST32_PARAM1_VALUE7)
+#define BP_PXP_HIST32_PARAM1_RSVD6 22
+#define BM_PXP_HIST32_PARAM1_RSVD6 0x00C00000
+#define BF_PXP_HIST32_PARAM1_RSVD6(v) \
+ (((v) << 22) & BM_PXP_HIST32_PARAM1_RSVD6)
+#define BP_PXP_HIST32_PARAM1_VALUE6 16
+#define BM_PXP_HIST32_PARAM1_VALUE6 0x003F0000
+#define BF_PXP_HIST32_PARAM1_VALUE6(v) \
+ (((v) << 16) & BM_PXP_HIST32_PARAM1_VALUE6)
+#define BP_PXP_HIST32_PARAM1_RSVD5 14
+#define BM_PXP_HIST32_PARAM1_RSVD5 0x0000C000
+#define BF_PXP_HIST32_PARAM1_RSVD5(v) \
+ (((v) << 14) & BM_PXP_HIST32_PARAM1_RSVD5)
+#define BP_PXP_HIST32_PARAM1_VALUE5 8
+#define BM_PXP_HIST32_PARAM1_VALUE5 0x00003F00
+#define BF_PXP_HIST32_PARAM1_VALUE5(v) \
+ (((v) << 8) & BM_PXP_HIST32_PARAM1_VALUE5)
+#define BP_PXP_HIST32_PARAM1_RSVD4 6
+#define BM_PXP_HIST32_PARAM1_RSVD4 0x000000C0
+#define BF_PXP_HIST32_PARAM1_RSVD4(v) \
+ (((v) << 6) & BM_PXP_HIST32_PARAM1_RSVD4)
+#define BP_PXP_HIST32_PARAM1_VALUE4 0
+#define BM_PXP_HIST32_PARAM1_VALUE4 0x0000003F
+#define BF_PXP_HIST32_PARAM1_VALUE4(v) \
+ (((v) << 0) & BM_PXP_HIST32_PARAM1_VALUE4)
+
+#define HW_PXP_HIST32_PARAM2 (0x00002ba0)
+
+#define BP_PXP_HIST32_PARAM2_RSVD11 30
+#define BM_PXP_HIST32_PARAM2_RSVD11 0xC0000000
+#define BF_PXP_HIST32_PARAM2_RSVD11(v) \
+ (((v) << 30) & BM_PXP_HIST32_PARAM2_RSVD11)
+#define BP_PXP_HIST32_PARAM2_VALUE11 24
+#define BM_PXP_HIST32_PARAM2_VALUE11 0x3F000000
+#define BF_PXP_HIST32_PARAM2_VALUE11(v) \
+ (((v) << 24) & BM_PXP_HIST32_PARAM2_VALUE11)
+#define BP_PXP_HIST32_PARAM2_RSVD10 22
+#define BM_PXP_HIST32_PARAM2_RSVD10 0x00C00000
+#define BF_PXP_HIST32_PARAM2_RSVD10(v) \
+ (((v) << 22) & BM_PXP_HIST32_PARAM2_RSVD10)
+#define BP_PXP_HIST32_PARAM2_VALUE10 16
+#define BM_PXP_HIST32_PARAM2_VALUE10 0x003F0000
+#define BF_PXP_HIST32_PARAM2_VALUE10(v) \
+ (((v) << 16) & BM_PXP_HIST32_PARAM2_VALUE10)
+#define BP_PXP_HIST32_PARAM2_RSVD9 14
+#define BM_PXP_HIST32_PARAM2_RSVD9 0x0000C000
+#define BF_PXP_HIST32_PARAM2_RSVD9(v) \
+ (((v) << 14) & BM_PXP_HIST32_PARAM2_RSVD9)
+#define BP_PXP_HIST32_PARAM2_VALUE9 8
+#define BM_PXP_HIST32_PARAM2_VALUE9 0x00003F00
+#define BF_PXP_HIST32_PARAM2_VALUE9(v) \
+ (((v) << 8) & BM_PXP_HIST32_PARAM2_VALUE9)
+#define BP_PXP_HIST32_PARAM2_RSVD8 6
+#define BM_PXP_HIST32_PARAM2_RSVD8 0x000000C0
+#define BF_PXP_HIST32_PARAM2_RSVD8(v) \
+ (((v) << 6) & BM_PXP_HIST32_PARAM2_RSVD8)
+#define BP_PXP_HIST32_PARAM2_VALUE8 0
+#define BM_PXP_HIST32_PARAM2_VALUE8 0x0000003F
+#define BF_PXP_HIST32_PARAM2_VALUE8(v) \
+ (((v) << 0) & BM_PXP_HIST32_PARAM2_VALUE8)
+
+#define HW_PXP_HIST32_PARAM3 (0x00002bb0)
+
+#define BP_PXP_HIST32_PARAM3_RSVD15 30
+#define BM_PXP_HIST32_PARAM3_RSVD15 0xC0000000
+#define BF_PXP_HIST32_PARAM3_RSVD15(v) \
+ (((v) << 30) & BM_PXP_HIST32_PARAM3_RSVD15)
+#define BP_PXP_HIST32_PARAM3_VALUE15 24
+#define BM_PXP_HIST32_PARAM3_VALUE15 0x3F000000
+#define BF_PXP_HIST32_PARAM3_VALUE15(v) \
+ (((v) << 24) & BM_PXP_HIST32_PARAM3_VALUE15)
+#define BP_PXP_HIST32_PARAM3_RSVD14 22
+#define BM_PXP_HIST32_PARAM3_RSVD14 0x00C00000
+#define BF_PXP_HIST32_PARAM3_RSVD14(v) \
+ (((v) << 22) & BM_PXP_HIST32_PARAM3_RSVD14)
+#define BP_PXP_HIST32_PARAM3_VALUE14 16
+#define BM_PXP_HIST32_PARAM3_VALUE14 0x003F0000
+#define BF_PXP_HIST32_PARAM3_VALUE14(v) \
+ (((v) << 16) & BM_PXP_HIST32_PARAM3_VALUE14)
+#define BP_PXP_HIST32_PARAM3_RSVD13 14
+#define BM_PXP_HIST32_PARAM3_RSVD13 0x0000C000
+#define BF_PXP_HIST32_PARAM3_RSVD13(v) \
+ (((v) << 14) & BM_PXP_HIST32_PARAM3_RSVD13)
+#define BP_PXP_HIST32_PARAM3_VALUE13 8
+#define BM_PXP_HIST32_PARAM3_VALUE13 0x00003F00
+#define BF_PXP_HIST32_PARAM3_VALUE13(v) \
+ (((v) << 8) & BM_PXP_HIST32_PARAM3_VALUE13)
+#define BP_PXP_HIST32_PARAM3_RSVD12 6
+#define BM_PXP_HIST32_PARAM3_RSVD12 0x000000C0
+#define BF_PXP_HIST32_PARAM3_RSVD12(v) \
+ (((v) << 6) & BM_PXP_HIST32_PARAM3_RSVD12)
+#define BP_PXP_HIST32_PARAM3_VALUE12 0
+#define BM_PXP_HIST32_PARAM3_VALUE12 0x0000003F
+#define BF_PXP_HIST32_PARAM3_VALUE12(v) \
+ (((v) << 0) & BM_PXP_HIST32_PARAM3_VALUE12)
+
+#define HW_PXP_HIST32_PARAM4 (0x00002bc0)
+
+#define BP_PXP_HIST32_PARAM4_RSVD3 30
+#define BM_PXP_HIST32_PARAM4_RSVD3 0xC0000000
+#define BF_PXP_HIST32_PARAM4_RSVD3(v) \
+ (((v) << 30) & BM_PXP_HIST32_PARAM4_RSVD3)
+#define BP_PXP_HIST32_PARAM4_VALUE19 24
+#define BM_PXP_HIST32_PARAM4_VALUE19 0x3F000000
+#define BF_PXP_HIST32_PARAM4_VALUE19(v) \
+ (((v) << 24) & BM_PXP_HIST32_PARAM4_VALUE19)
+#define BP_PXP_HIST32_PARAM4_RSVD2 22
+#define BM_PXP_HIST32_PARAM4_RSVD2 0x00C00000
+#define BF_PXP_HIST32_PARAM4_RSVD2(v) \
+ (((v) << 22) & BM_PXP_HIST32_PARAM4_RSVD2)
+#define BP_PXP_HIST32_PARAM4_VALUE18 16
+#define BM_PXP_HIST32_PARAM4_VALUE18 0x003F0000
+#define BF_PXP_HIST32_PARAM4_VALUE18(v) \
+ (((v) << 16) & BM_PXP_HIST32_PARAM4_VALUE18)
+#define BP_PXP_HIST32_PARAM4_RSVD1 14
+#define BM_PXP_HIST32_PARAM4_RSVD1 0x0000C000
+#define BF_PXP_HIST32_PARAM4_RSVD1(v) \
+ (((v) << 14) & BM_PXP_HIST32_PARAM4_RSVD1)
+#define BP_PXP_HIST32_PARAM4_VALUE17 8
+#define BM_PXP_HIST32_PARAM4_VALUE17 0x00003F00
+#define BF_PXP_HIST32_PARAM4_VALUE17(v) \
+ (((v) << 8) & BM_PXP_HIST32_PARAM4_VALUE17)
+#define BP_PXP_HIST32_PARAM4_RSVD0 6
+#define BM_PXP_HIST32_PARAM4_RSVD0 0x000000C0
+#define BF_PXP_HIST32_PARAM4_RSVD0(v) \
+ (((v) << 6) & BM_PXP_HIST32_PARAM4_RSVD0)
+#define BP_PXP_HIST32_PARAM4_VALUE16 0
+#define BM_PXP_HIST32_PARAM4_VALUE16 0x0000003F
+#define BF_PXP_HIST32_PARAM4_VALUE16(v) \
+ (((v) << 0) & BM_PXP_HIST32_PARAM4_VALUE16)
+
+#define HW_PXP_HIST32_PARAM5 (0x00002bd0)
+
+#define BP_PXP_HIST32_PARAM5_RSVD7 30
+#define BM_PXP_HIST32_PARAM5_RSVD7 0xC0000000
+#define BF_PXP_HIST32_PARAM5_RSVD7(v) \
+ (((v) << 30) & BM_PXP_HIST32_PARAM5_RSVD7)
+#define BP_PXP_HIST32_PARAM5_VALUE23 24
+#define BM_PXP_HIST32_PARAM5_VALUE23 0x3F000000
+#define BF_PXP_HIST32_PARAM5_VALUE23(v) \
+ (((v) << 24) & BM_PXP_HIST32_PARAM5_VALUE23)
+#define BP_PXP_HIST32_PARAM5_RSVD6 22
+#define BM_PXP_HIST32_PARAM5_RSVD6 0x00C00000
+#define BF_PXP_HIST32_PARAM5_RSVD6(v) \
+ (((v) << 22) & BM_PXP_HIST32_PARAM5_RSVD6)
+#define BP_PXP_HIST32_PARAM5_VALUE22 16
+#define BM_PXP_HIST32_PARAM5_VALUE22 0x003F0000
+#define BF_PXP_HIST32_PARAM5_VALUE22(v) \
+ (((v) << 16) & BM_PXP_HIST32_PARAM5_VALUE22)
+#define BP_PXP_HIST32_PARAM5_RSVD5 14
+#define BM_PXP_HIST32_PARAM5_RSVD5 0x0000C000
+#define BF_PXP_HIST32_PARAM5_RSVD5(v) \
+ (((v) << 14) & BM_PXP_HIST32_PARAM5_RSVD5)
+#define BP_PXP_HIST32_PARAM5_VALUE21 8
+#define BM_PXP_HIST32_PARAM5_VALUE21 0x00003F00
+#define BF_PXP_HIST32_PARAM5_VALUE21(v) \
+ (((v) << 8) & BM_PXP_HIST32_PARAM5_VALUE21)
+#define BP_PXP_HIST32_PARAM5_RSVD4 6
+#define BM_PXP_HIST32_PARAM5_RSVD4 0x000000C0
+#define BF_PXP_HIST32_PARAM5_RSVD4(v) \
+ (((v) << 6) & BM_PXP_HIST32_PARAM5_RSVD4)
+#define BP_PXP_HIST32_PARAM5_VALUE20 0
+#define BM_PXP_HIST32_PARAM5_VALUE20 0x0000003F
+#define BF_PXP_HIST32_PARAM5_VALUE20(v) \
+ (((v) << 0) & BM_PXP_HIST32_PARAM5_VALUE20)
+
+#define HW_PXP_HIST32_PARAM6 (0x00002be0)
+
+#define BP_PXP_HIST32_PARAM6_RSVD11 30
+#define BM_PXP_HIST32_PARAM6_RSVD11 0xC0000000
+#define BF_PXP_HIST32_PARAM6_RSVD11(v) \
+ (((v) << 30) & BM_PXP_HIST32_PARAM6_RSVD11)
+#define BP_PXP_HIST32_PARAM6_VALUE27 24
+#define BM_PXP_HIST32_PARAM6_VALUE27 0x3F000000
+#define BF_PXP_HIST32_PARAM6_VALUE27(v) \
+ (((v) << 24) & BM_PXP_HIST32_PARAM6_VALUE27)
+#define BP_PXP_HIST32_PARAM6_RSVD10 22
+#define BM_PXP_HIST32_PARAM6_RSVD10 0x00C00000
+#define BF_PXP_HIST32_PARAM6_RSVD10(v) \
+ (((v) << 22) & BM_PXP_HIST32_PARAM6_RSVD10)
+#define BP_PXP_HIST32_PARAM6_VALUE26 16
+#define BM_PXP_HIST32_PARAM6_VALUE26 0x003F0000
+#define BF_PXP_HIST32_PARAM6_VALUE26(v) \
+ (((v) << 16) & BM_PXP_HIST32_PARAM6_VALUE26)
+#define BP_PXP_HIST32_PARAM6_RSVD9 14
+#define BM_PXP_HIST32_PARAM6_RSVD9 0x0000C000
+#define BF_PXP_HIST32_PARAM6_RSVD9(v) \
+ (((v) << 14) & BM_PXP_HIST32_PARAM6_RSVD9)
+#define BP_PXP_HIST32_PARAM6_VALUE25 8
+#define BM_PXP_HIST32_PARAM6_VALUE25 0x00003F00
+#define BF_PXP_HIST32_PARAM6_VALUE25(v) \
+ (((v) << 8) & BM_PXP_HIST32_PARAM6_VALUE25)
+#define BP_PXP_HIST32_PARAM6_RSVD8 6
+#define BM_PXP_HIST32_PARAM6_RSVD8 0x000000C0
+#define BF_PXP_HIST32_PARAM6_RSVD8(v) \
+ (((v) << 6) & BM_PXP_HIST32_PARAM6_RSVD8)
+#define BP_PXP_HIST32_PARAM6_VALUE24 0
+#define BM_PXP_HIST32_PARAM6_VALUE24 0x0000003F
+#define BF_PXP_HIST32_PARAM6_VALUE24(v) \
+ (((v) << 0) & BM_PXP_HIST32_PARAM6_VALUE24)
+
+#define HW_PXP_HIST32_PARAM7 (0x00002bf0)
+
+#define BP_PXP_HIST32_PARAM7_RSVD15 30
+#define BM_PXP_HIST32_PARAM7_RSVD15 0xC0000000
+#define BF_PXP_HIST32_PARAM7_RSVD15(v) \
+ (((v) << 30) & BM_PXP_HIST32_PARAM7_RSVD15)
+#define BP_PXP_HIST32_PARAM7_VALUE31 24
+#define BM_PXP_HIST32_PARAM7_VALUE31 0x3F000000
+#define BF_PXP_HIST32_PARAM7_VALUE31(v) \
+ (((v) << 24) & BM_PXP_HIST32_PARAM7_VALUE31)
+#define BP_PXP_HIST32_PARAM7_RSVD14 22
+#define BM_PXP_HIST32_PARAM7_RSVD14 0x00C00000
+#define BF_PXP_HIST32_PARAM7_RSVD14(v) \
+ (((v) << 22) & BM_PXP_HIST32_PARAM7_RSVD14)
+#define BP_PXP_HIST32_PARAM7_VALUE30 16
+#define BM_PXP_HIST32_PARAM7_VALUE30 0x003F0000
+#define BF_PXP_HIST32_PARAM7_VALUE30(v) \
+ (((v) << 16) & BM_PXP_HIST32_PARAM7_VALUE30)
+#define BP_PXP_HIST32_PARAM7_RSVD13 14
+#define BM_PXP_HIST32_PARAM7_RSVD13 0x0000C000
+#define BF_PXP_HIST32_PARAM7_RSVD13(v) \
+ (((v) << 14) & BM_PXP_HIST32_PARAM7_RSVD13)
+#define BP_PXP_HIST32_PARAM7_VALUE29 8
+#define BM_PXP_HIST32_PARAM7_VALUE29 0x00003F00
+#define BF_PXP_HIST32_PARAM7_VALUE29(v) \
+ (((v) << 8) & BM_PXP_HIST32_PARAM7_VALUE29)
+#define BP_PXP_HIST32_PARAM7_RSVD2 6
+#define BM_PXP_HIST32_PARAM7_RSVD2 0x000000C0
+#define BF_PXP_HIST32_PARAM7_RSVD2(v) \
+ (((v) << 6) & BM_PXP_HIST32_PARAM7_RSVD2)
+#define BP_PXP_HIST32_PARAM7_VALUE28 0
+#define BM_PXP_HIST32_PARAM7_VALUE28 0x0000003F
+#define BF_PXP_HIST32_PARAM7_VALUE28(v) \
+ (((v) << 0) & BM_PXP_HIST32_PARAM7_VALUE28)
+
+#define HW_PXP_COMP_CTRL (0x00002c00)
+#define HW_PXP_COMP_CTRL_SET (0x00002c04)
+#define HW_PXP_COMP_CTRL_CLR (0x00002c08)
+#define HW_PXP_COMP_CTRL_TOG (0x00002c0c)
+
+#define BP_PXP_COMP_CTRL_RSVD0 9
+#define BM_PXP_COMP_CTRL_RSVD0 0xFFFFFE00
+#define BF_PXP_COMP_CTRL_RSVD0(v) \
+ (((v) << 9) & BM_PXP_COMP_CTRL_RSVD0)
+#define BM_PXP_COMP_CTRL_SW_RESET 0x00000100
+#define BF_PXP_COMP_CTRL_SW_RESET(v) \
+ (((v) << 8) & BM_PXP_COMP_CTRL_SW_RESET)
+#define BP_PXP_COMP_CTRL_RSVD1 1
+#define BM_PXP_COMP_CTRL_RSVD1 0x000000FE
+#define BF_PXP_COMP_CTRL_RSVD1(v) \
+ (((v) << 1) & BM_PXP_COMP_CTRL_RSVD1)
+#define BM_PXP_COMP_CTRL_START 0x00000001
+#define BF_PXP_COMP_CTRL_START(v) \
+ (((v) << 0) & BM_PXP_COMP_CTRL_START)
+
+#define HW_PXP_COMP_FORMAT0 (0x00002c10)
+#define HW_PXP_COMP_FORMAT0_SET (0x00002c14)
+#define HW_PXP_COMP_FORMAT0_CLR (0x00002c18)
+#define HW_PXP_COMP_FORMAT0_TOG (0x00002c1c)
+
+#define BP_PXP_COMP_FORMAT0_RSVD0 28
+#define BM_PXP_COMP_FORMAT0_RSVD0 0xF0000000
+#define BF_PXP_COMP_FORMAT0_RSVD0(v) \
+ (((v) << 28) & BM_PXP_COMP_FORMAT0_RSVD0)
+#define BP_PXP_COMP_FORMAT0_PIXEL_PITCH_64B 16
+#define BM_PXP_COMP_FORMAT0_PIXEL_PITCH_64B 0x0FFF0000
+#define BF_PXP_COMP_FORMAT0_PIXEL_PITCH_64B(v) \
+ (((v) << 16) & BM_PXP_COMP_FORMAT0_PIXEL_PITCH_64B)
+#define BP_PXP_COMP_FORMAT0_RSVD1 10
+#define BM_PXP_COMP_FORMAT0_RSVD1 0x0000FC00
+#define BF_PXP_COMP_FORMAT0_RSVD1(v) \
+ (((v) << 10) & BM_PXP_COMP_FORMAT0_RSVD1)
+#define BP_PXP_COMP_FORMAT0_MASK_INDEX 8
+#define BM_PXP_COMP_FORMAT0_MASK_INDEX 0x00000300
+#define BF_PXP_COMP_FORMAT0_MASK_INDEX(v) \
+ (((v) << 8) & BM_PXP_COMP_FORMAT0_MASK_INDEX)
+#define BP_PXP_COMP_FORMAT0_RSVD2 6
+#define BM_PXP_COMP_FORMAT0_RSVD2 0x000000C0
+#define BF_PXP_COMP_FORMAT0_RSVD2(v) \
+ (((v) << 6) & BM_PXP_COMP_FORMAT0_RSVD2)
+#define BP_PXP_COMP_FORMAT0_FIELD_NUM 4
+#define BM_PXP_COMP_FORMAT0_FIELD_NUM 0x00000030
+#define BF_PXP_COMP_FORMAT0_FIELD_NUM(v) \
+ (((v) << 4) & BM_PXP_COMP_FORMAT0_FIELD_NUM)
+#define BP_PXP_COMP_FORMAT0_RSVD3 1
+#define BM_PXP_COMP_FORMAT0_RSVD3 0x0000000E
+#define BF_PXP_COMP_FORMAT0_RSVD3(v) \
+ (((v) << 1) & BM_PXP_COMP_FORMAT0_RSVD3)
+#define BM_PXP_COMP_FORMAT0_FLAG_32B 0x00000001
+#define BF_PXP_COMP_FORMAT0_FLAG_32B(v) \
+ (((v) << 0) & BM_PXP_COMP_FORMAT0_FLAG_32B)
+
+#define HW_PXP_COMP_FORMAT1 (0x00002c20)
+
+#define BP_PXP_COMP_FORMAT1_D_LEN 29
+#define BM_PXP_COMP_FORMAT1_D_LEN 0xE0000000
+#define BF_PXP_COMP_FORMAT1_D_LEN(v) \
+ (((v) << 29) & BM_PXP_COMP_FORMAT1_D_LEN)
+#define BP_PXP_COMP_FORMAT1_D_OFFSET 24
+#define BM_PXP_COMP_FORMAT1_D_OFFSET 0x1F000000
+#define BF_PXP_COMP_FORMAT1_D_OFFSET(v) \
+ (((v) << 24) & BM_PXP_COMP_FORMAT1_D_OFFSET)
+#define BP_PXP_COMP_FORMAT1_C_LEN 21
+#define BM_PXP_COMP_FORMAT1_C_LEN 0x00E00000
+#define BF_PXP_COMP_FORMAT1_C_LEN(v) \
+ (((v) << 21) & BM_PXP_COMP_FORMAT1_C_LEN)
+#define BP_PXP_COMP_FORMAT1_C_OFFSET 16
+#define BM_PXP_COMP_FORMAT1_C_OFFSET 0x001F0000
+#define BF_PXP_COMP_FORMAT1_C_OFFSET(v) \
+ (((v) << 16) & BM_PXP_COMP_FORMAT1_C_OFFSET)
+#define BP_PXP_COMP_FORMAT1_B_LEN 13
+#define BM_PXP_COMP_FORMAT1_B_LEN 0x0000E000
+#define BF_PXP_COMP_FORMAT1_B_LEN(v) \
+ (((v) << 13) & BM_PXP_COMP_FORMAT1_B_LEN)
+#define BP_PXP_COMP_FORMAT1_B_OFFSET 8
+#define BM_PXP_COMP_FORMAT1_B_OFFSET 0x00001F00
+#define BF_PXP_COMP_FORMAT1_B_OFFSET(v) \
+ (((v) << 8) & BM_PXP_COMP_FORMAT1_B_OFFSET)
+#define BP_PXP_COMP_FORMAT1_A_LEN 5
+#define BM_PXP_COMP_FORMAT1_A_LEN 0x000000E0
+#define BF_PXP_COMP_FORMAT1_A_LEN(v) \
+ (((v) << 5) & BM_PXP_COMP_FORMAT1_A_LEN)
+#define BP_PXP_COMP_FORMAT1_A_OFFSET 0
+#define BM_PXP_COMP_FORMAT1_A_OFFSET 0x0000001F
+#define BF_PXP_COMP_FORMAT1_A_OFFSET(v) \
+ (((v) << 0) & BM_PXP_COMP_FORMAT1_A_OFFSET)
+
+#define HW_PXP_COMP_FORMAT2 (0x00002c30)
+
+#define BP_PXP_COMP_FORMAT2_RSVD 16
+#define BM_PXP_COMP_FORMAT2_RSVD 0xFFFF0000
+#define BF_PXP_COMP_FORMAT2_RSVD(v) \
+ (((v) << 16) & BM_PXP_COMP_FORMAT2_RSVD)
+#define BP_PXP_COMP_FORMAT2_D_RUNLEN 12
+#define BM_PXP_COMP_FORMAT2_D_RUNLEN 0x0000F000
+#define BF_PXP_COMP_FORMAT2_D_RUNLEN(v) \
+ (((v) << 12) & BM_PXP_COMP_FORMAT2_D_RUNLEN)
+#define BP_PXP_COMP_FORMAT2_C_RUNLEN 8
+#define BM_PXP_COMP_FORMAT2_C_RUNLEN 0x00000F00
+#define BF_PXP_COMP_FORMAT2_C_RUNLEN(v) \
+ (((v) << 8) & BM_PXP_COMP_FORMAT2_C_RUNLEN)
+#define BP_PXP_COMP_FORMAT2_B_RUNLEN 4
+#define BM_PXP_COMP_FORMAT2_B_RUNLEN 0x000000F0
+#define BF_PXP_COMP_FORMAT2_B_RUNLEN(v) \
+ (((v) << 4) & BM_PXP_COMP_FORMAT2_B_RUNLEN)
+#define BP_PXP_COMP_FORMAT2_A_RUNLEN 0
+#define BM_PXP_COMP_FORMAT2_A_RUNLEN 0x0000000F
+#define BF_PXP_COMP_FORMAT2_A_RUNLEN(v) \
+ (((v) << 0) & BM_PXP_COMP_FORMAT2_A_RUNLEN)
+
+#define HW_PXP_COMP_MASK0 (0x00002c40)
+
+#define BP_PXP_COMP_MASK0_VLD_MASK_LOW 0
+#define BM_PXP_COMP_MASK0_VLD_MASK_LOW 0xFFFFFFFF
+#define BF_PXP_COMP_MASK0_VLD_MASK_LOW(v) (v)
+
+#define HW_PXP_COMP_MASK1 (0x00002c50)
+
+#define BP_PXP_COMP_MASK1_VLD_MASK_HIGH 0
+#define BM_PXP_COMP_MASK1_VLD_MASK_HIGH 0xFFFFFFFF
+#define BF_PXP_COMP_MASK1_VLD_MASK_HIGH(v) (v)
+
+#define HW_PXP_COMP_BUFFER_SIZE (0x00002c60)
+
+#define BP_PXP_COMP_BUFFER_SIZE_RSVD0 29
+#define BM_PXP_COMP_BUFFER_SIZE_RSVD0 0xE0000000
+#define BF_PXP_COMP_BUFFER_SIZE_RSVD0(v) \
+ (((v) << 29) & BM_PXP_COMP_BUFFER_SIZE_RSVD0)
+#define BP_PXP_COMP_BUFFER_SIZE_PIXEL_WIDTH 16
+#define BM_PXP_COMP_BUFFER_SIZE_PIXEL_WIDTH 0x1FFF0000
+#define BF_PXP_COMP_BUFFER_SIZE_PIXEL_WIDTH(v) \
+ (((v) << 16) & BM_PXP_COMP_BUFFER_SIZE_PIXEL_WIDTH)
+#define BP_PXP_COMP_BUFFER_SIZE_RSVD1 13
+#define BM_PXP_COMP_BUFFER_SIZE_RSVD1 0x0000E000
+#define BF_PXP_COMP_BUFFER_SIZE_RSVD1(v) \
+ (((v) << 13) & BM_PXP_COMP_BUFFER_SIZE_RSVD1)
+#define BP_PXP_COMP_BUFFER_SIZE_PIXEL_LENGTH 0
+#define BM_PXP_COMP_BUFFER_SIZE_PIXEL_LENGTH 0x00001FFF
+#define BF_PXP_COMP_BUFFER_SIZE_PIXEL_LENGTH(v) \
+ (((v) << 0) & BM_PXP_COMP_BUFFER_SIZE_PIXEL_LENGTH)
+
+#define HW_PXP_COMP_SOURCE (0x00002c70)
+
+#define BP_PXP_COMP_SOURCE_SOURCE_ADDR 0
+#define BM_PXP_COMP_SOURCE_SOURCE_ADDR 0xFFFFFFFF
+#define BF_PXP_COMP_SOURCE_SOURCE_ADDR(v) (v)
+
+#define HW_PXP_COMP_TARGET (0x00002c80)
+
+#define BP_PXP_COMP_TARGET_TARGET_ADDR 0
+#define BM_PXP_COMP_TARGET_TARGET_ADDR 0xFFFFFFFF
+#define BF_PXP_COMP_TARGET_TARGET_ADDR(v) (v)
+
+#define HW_PXP_COMP_BUFFER_A (0x00002c90)
+
+#define BP_PXP_COMP_BUFFER_A_A_SRAM_ADDR 0
+#define BM_PXP_COMP_BUFFER_A_A_SRAM_ADDR 0xFFFFFFFF
+#define BF_PXP_COMP_BUFFER_A_A_SRAM_ADDR(v) (v)
+
+#define HW_PXP_COMP_BUFFER_B (0x00002ca0)
+
+#define BP_PXP_COMP_BUFFER_B_B_SRAM_ADDR 0
+#define BM_PXP_COMP_BUFFER_B_B_SRAM_ADDR 0xFFFFFFFF
+#define BF_PXP_COMP_BUFFER_B_B_SRAM_ADDR(v) (v)
+
+#define HW_PXP_COMP_BUFFER_C (0x00002cb0)
+
+#define BP_PXP_COMP_BUFFER_C_C_SRAM_ADDR 0
+#define BM_PXP_COMP_BUFFER_C_C_SRAM_ADDR 0xFFFFFFFF
+#define BF_PXP_COMP_BUFFER_C_C_SRAM_ADDR(v) (v)
+
+#define HW_PXP_COMP_BUFFER_D (0x00002cc0)
+
+#define BP_PXP_COMP_BUFFER_D_D_SRAM_ADDR 0
+#define BM_PXP_COMP_BUFFER_D_D_SRAM_ADDR 0xFFFFFFFF
+#define BF_PXP_COMP_BUFFER_D_D_SRAM_ADDR(v) (v)
+
+#define HW_PXP_COMP_DEBUG (0x00002cd0)
+
+#define BP_PXP_COMP_DEBUG_DEBUG_VALUE 8
+#define BM_PXP_COMP_DEBUG_DEBUG_VALUE 0xFFFFFF00
+#define BF_PXP_COMP_DEBUG_DEBUG_VALUE(v) \
+ (((v) << 8) & BM_PXP_COMP_DEBUG_DEBUG_VALUE)
+#define BP_PXP_COMP_DEBUG_DEBUG_SEL 0
+#define BM_PXP_COMP_DEBUG_DEBUG_SEL 0x000000FF
+#define BF_PXP_COMP_DEBUG_DEBUG_SEL(v) \
+ (((v) << 0) & BM_PXP_COMP_DEBUG_DEBUG_SEL)
+
+#define HW_PXP_BUS_MUX (0x00002ce0)
+
+#define BP_PXP_BUS_MUX_RSVD1 24
+#define BM_PXP_BUS_MUX_RSVD1 0xFF000000
+#define BF_PXP_BUS_MUX_RSVD1(v) \
+ (((v) << 24) & BM_PXP_BUS_MUX_RSVD1)
+#define BP_PXP_BUS_MUX_WR_SEL 16
+#define BM_PXP_BUS_MUX_WR_SEL 0x00FF0000
+#define BF_PXP_BUS_MUX_WR_SEL(v) \
+ (((v) << 16) & BM_PXP_BUS_MUX_WR_SEL)
+#define BP_PXP_BUS_MUX_RSVD0 8
+#define BM_PXP_BUS_MUX_RSVD0 0x0000FF00
+#define BF_PXP_BUS_MUX_RSVD0(v) \
+ (((v) << 8) & BM_PXP_BUS_MUX_RSVD0)
+#define BP_PXP_BUS_MUX_RD_SEL 0
+#define BM_PXP_BUS_MUX_RD_SEL 0x000000FF
+#define BF_PXP_BUS_MUX_RD_SEL(v) \
+ (((v) << 0) & BM_PXP_BUS_MUX_RD_SEL)
+
+#define HW_PXP_HANDSHAKE_READY_MUX0 (0x00002cf0)
+
+#define BP_PXP_HANDSHAKE_READY_MUX0_HSK7 28
+#define BM_PXP_HANDSHAKE_READY_MUX0_HSK7 0xF0000000
+#define BF_PXP_HANDSHAKE_READY_MUX0_HSK7(v) \
+ (((v) << 28) & BM_PXP_HANDSHAKE_READY_MUX0_HSK7)
+#define BP_PXP_HANDSHAKE_READY_MUX0_HSK6 24
+#define BM_PXP_HANDSHAKE_READY_MUX0_HSK6 0x0F000000
+#define BF_PXP_HANDSHAKE_READY_MUX0_HSK6(v) \
+ (((v) << 24) & BM_PXP_HANDSHAKE_READY_MUX0_HSK6)
+#define BP_PXP_HANDSHAKE_READY_MUX0_HSK5 20
+#define BM_PXP_HANDSHAKE_READY_MUX0_HSK5 0x00F00000
+#define BF_PXP_HANDSHAKE_READY_MUX0_HSK5(v) \
+ (((v) << 20) & BM_PXP_HANDSHAKE_READY_MUX0_HSK5)
+#define BP_PXP_HANDSHAKE_READY_MUX0_HSK4 16
+#define BM_PXP_HANDSHAKE_READY_MUX0_HSK4 0x000F0000
+#define BF_PXP_HANDSHAKE_READY_MUX0_HSK4(v) \
+ (((v) << 16) & BM_PXP_HANDSHAKE_READY_MUX0_HSK4)
+#define BP_PXP_HANDSHAKE_READY_MUX0_HSK3 12
+#define BM_PXP_HANDSHAKE_READY_MUX0_HSK3 0x0000F000
+#define BF_PXP_HANDSHAKE_READY_MUX0_HSK3(v) \
+ (((v) << 12) & BM_PXP_HANDSHAKE_READY_MUX0_HSK3)
+#define BP_PXP_HANDSHAKE_READY_MUX0_HSK2 8
+#define BM_PXP_HANDSHAKE_READY_MUX0_HSK2 0x00000F00
+#define BF_PXP_HANDSHAKE_READY_MUX0_HSK2(v) \
+ (((v) << 8) & BM_PXP_HANDSHAKE_READY_MUX0_HSK2)
+#define BP_PXP_HANDSHAKE_READY_MUX0_HSK1 4
+#define BM_PXP_HANDSHAKE_READY_MUX0_HSK1 0x000000F0
+#define BF_PXP_HANDSHAKE_READY_MUX0_HSK1(v) \
+ (((v) << 4) & BM_PXP_HANDSHAKE_READY_MUX0_HSK1)
+#define BP_PXP_HANDSHAKE_READY_MUX0_HSK0 0
+#define BM_PXP_HANDSHAKE_READY_MUX0_HSK0 0x0000000F
+#define BF_PXP_HANDSHAKE_READY_MUX0_HSK0(v) \
+ (((v) << 0) & BM_PXP_HANDSHAKE_READY_MUX0_HSK0)
+
+#define HW_PXP_HANDSHAKE_READY_MUX1 (0x00002d00)
+
+#define BP_PXP_HANDSHAKE_READY_MUX1_HSK15 28
+#define BM_PXP_HANDSHAKE_READY_MUX1_HSK15 0xF0000000
+#define BF_PXP_HANDSHAKE_READY_MUX1_HSK15(v) \
+ (((v) << 28) & BM_PXP_HANDSHAKE_READY_MUX1_HSK15)
+#define BP_PXP_HANDSHAKE_READY_MUX1_HSK14 24
+#define BM_PXP_HANDSHAKE_READY_MUX1_HSK14 0x0F000000
+#define BF_PXP_HANDSHAKE_READY_MUX1_HSK14(v) \
+ (((v) << 24) & BM_PXP_HANDSHAKE_READY_MUX1_HSK14)
+#define BP_PXP_HANDSHAKE_READY_MUX1_HSK13 20
+#define BM_PXP_HANDSHAKE_READY_MUX1_HSK13 0x00F00000
+#define BF_PXP_HANDSHAKE_READY_MUX1_HSK13(v) \
+ (((v) << 20) & BM_PXP_HANDSHAKE_READY_MUX1_HSK13)
+#define BP_PXP_HANDSHAKE_READY_MUX1_HSK12 16
+#define BM_PXP_HANDSHAKE_READY_MUX1_HSK12 0x000F0000
+#define BF_PXP_HANDSHAKE_READY_MUX1_HSK12(v) \
+ (((v) << 16) & BM_PXP_HANDSHAKE_READY_MUX1_HSK12)
+#define BP_PXP_HANDSHAKE_READY_MUX1_HSK11 12
+#define BM_PXP_HANDSHAKE_READY_MUX1_HSK11 0x0000F000
+#define BF_PXP_HANDSHAKE_READY_MUX1_HSK11(v) \
+ (((v) << 12) & BM_PXP_HANDSHAKE_READY_MUX1_HSK11)
+#define BP_PXP_HANDSHAKE_READY_MUX1_HSK10 8
+#define BM_PXP_HANDSHAKE_READY_MUX1_HSK10 0x00000F00
+#define BF_PXP_HANDSHAKE_READY_MUX1_HSK10(v) \
+ (((v) << 8) & BM_PXP_HANDSHAKE_READY_MUX1_HSK10)
+#define BP_PXP_HANDSHAKE_READY_MUX1_HSK9 4
+#define BM_PXP_HANDSHAKE_READY_MUX1_HSK9 0x000000F0
+#define BF_PXP_HANDSHAKE_READY_MUX1_HSK9(v) \
+ (((v) << 4) & BM_PXP_HANDSHAKE_READY_MUX1_HSK9)
+#define BP_PXP_HANDSHAKE_READY_MUX1_HSK8 0
+#define BM_PXP_HANDSHAKE_READY_MUX1_HSK8 0x0000000F
+#define BF_PXP_HANDSHAKE_READY_MUX1_HSK8(v) \
+ (((v) << 0) & BM_PXP_HANDSHAKE_READY_MUX1_HSK8)
+
+#define HW_PXP_HANDSHAKE_DONE_MUX0 (0x00002d10)
+
+#define BP_PXP_HANDSHAKE_DONE_MUX0_HSK7 28
+#define BM_PXP_HANDSHAKE_DONE_MUX0_HSK7 0xF0000000
+#define BF_PXP_HANDSHAKE_DONE_MUX0_HSK7(v) \
+ (((v) << 28) & BM_PXP_HANDSHAKE_DONE_MUX0_HSK7)
+#define BP_PXP_HANDSHAKE_DONE_MUX0_HSK6 24
+#define BM_PXP_HANDSHAKE_DONE_MUX0_HSK6 0x0F000000
+#define BF_PXP_HANDSHAKE_DONE_MUX0_HSK6(v) \
+ (((v) << 24) & BM_PXP_HANDSHAKE_DONE_MUX0_HSK6)
+#define BP_PXP_HANDSHAKE_DONE_MUX0_HSK5 20
+#define BM_PXP_HANDSHAKE_DONE_MUX0_HSK5 0x00F00000
+#define BF_PXP_HANDSHAKE_DONE_MUX0_HSK5(v) \
+ (((v) << 20) & BM_PXP_HANDSHAKE_DONE_MUX0_HSK5)
+#define BP_PXP_HANDSHAKE_DONE_MUX0_HSK4 16
+#define BM_PXP_HANDSHAKE_DONE_MUX0_HSK4 0x000F0000
+#define BF_PXP_HANDSHAKE_DONE_MUX0_HSK4(v) \
+ (((v) << 16) & BM_PXP_HANDSHAKE_DONE_MUX0_HSK4)
+#define BP_PXP_HANDSHAKE_DONE_MUX0_HSK3 12
+#define BM_PXP_HANDSHAKE_DONE_MUX0_HSK3 0x0000F000
+#define BF_PXP_HANDSHAKE_DONE_MUX0_HSK3(v) \
+ (((v) << 12) & BM_PXP_HANDSHAKE_DONE_MUX0_HSK3)
+#define BP_PXP_HANDSHAKE_DONE_MUX0_HSK2 8
+#define BM_PXP_HANDSHAKE_DONE_MUX0_HSK2 0x00000F00
+#define BF_PXP_HANDSHAKE_DONE_MUX0_HSK2(v) \
+ (((v) << 8) & BM_PXP_HANDSHAKE_DONE_MUX0_HSK2)
+#define BP_PXP_HANDSHAKE_DONE_MUX0_HSK1 4
+#define BM_PXP_HANDSHAKE_DONE_MUX0_HSK1 0x000000F0
+#define BF_PXP_HANDSHAKE_DONE_MUX0_HSK1(v) \
+ (((v) << 4) & BM_PXP_HANDSHAKE_DONE_MUX0_HSK1)
+#define BP_PXP_HANDSHAKE_DONE_MUX0_HSK0 0
+#define BM_PXP_HANDSHAKE_DONE_MUX0_HSK0 0x0000000F
+#define BF_PXP_HANDSHAKE_DONE_MUX0_HSK0(v) \
+ (((v) << 0) & BM_PXP_HANDSHAKE_DONE_MUX0_HSK0)
+
+#define HW_PXP_HANDSHAKE_DONE_MUX1 (0x00002d20)
+
+#define BP_PXP_HANDSHAKE_DONE_MUX1_HSK15 28
+#define BM_PXP_HANDSHAKE_DONE_MUX1_HSK15 0xF0000000
+#define BF_PXP_HANDSHAKE_DONE_MUX1_HSK15(v) \
+ (((v) << 28) & BM_PXP_HANDSHAKE_DONE_MUX1_HSK15)
+#define BP_PXP_HANDSHAKE_DONE_MUX1_HSK14 24
+#define BM_PXP_HANDSHAKE_DONE_MUX1_HSK14 0x0F000000
+#define BF_PXP_HANDSHAKE_DONE_MUX1_HSK14(v) \
+ (((v) << 24) & BM_PXP_HANDSHAKE_DONE_MUX1_HSK14)
+#define BP_PXP_HANDSHAKE_DONE_MUX1_HSK13 20
+#define BM_PXP_HANDSHAKE_DONE_MUX1_HSK13 0x00F00000
+#define BF_PXP_HANDSHAKE_DONE_MUX1_HSK13(v) \
+ (((v) << 20) & BM_PXP_HANDSHAKE_DONE_MUX1_HSK13)
+#define BP_PXP_HANDSHAKE_DONE_MUX1_HSK12 16
+#define BM_PXP_HANDSHAKE_DONE_MUX1_HSK12 0x000F0000
+#define BF_PXP_HANDSHAKE_DONE_MUX1_HSK12(v) \
+ (((v) << 16) & BM_PXP_HANDSHAKE_DONE_MUX1_HSK12)
+#define BP_PXP_HANDSHAKE_DONE_MUX1_HSK11 12
+#define BM_PXP_HANDSHAKE_DONE_MUX1_HSK11 0x0000F000
+#define BF_PXP_HANDSHAKE_DONE_MUX1_HSK11(v) \
+ (((v) << 12) & BM_PXP_HANDSHAKE_DONE_MUX1_HSK11)
+#define BP_PXP_HANDSHAKE_DONE_MUX1_HSK10 8
+#define BM_PXP_HANDSHAKE_DONE_MUX1_HSK10 0x00000F00
+#define BF_PXP_HANDSHAKE_DONE_MUX1_HSK10(v) \
+ (((v) << 8) & BM_PXP_HANDSHAKE_DONE_MUX1_HSK10)
+#define BP_PXP_HANDSHAKE_DONE_MUX1_HSK9 4
+#define BM_PXP_HANDSHAKE_DONE_MUX1_HSK9 0x000000F0
+#define BF_PXP_HANDSHAKE_DONE_MUX1_HSK9(v) \
+ (((v) << 4) & BM_PXP_HANDSHAKE_DONE_MUX1_HSK9)
+#define BP_PXP_HANDSHAKE_DONE_MUX1_HSK8 0
+#define BM_PXP_HANDSHAKE_DONE_MUX1_HSK8 0x0000000F
+#define BF_PXP_HANDSHAKE_DONE_MUX1_HSK8(v) \
+ (((v) << 0) & BM_PXP_HANDSHAKE_DONE_MUX1_HSK8)
+
+#define HW_PXP_HANDSHAKE_CPU_FETCH (0x00002d30)
+#define HW_PXP_HANDSHAKE_CPU_FETCH_SET (0x00002d34)
+#define HW_PXP_HANDSHAKE_CPU_FETCH_CLR (0x00002d38)
+#define HW_PXP_HANDSHAKE_CPU_FETCH_TOG (0x00002d3c)
+
+#define BM_PXP_HANDSHAKE_CPU_FETCH_SW1_HSK_EN 0x80000000
+#define BF_PXP_HANDSHAKE_CPU_FETCH_SW1_HSK_EN(v) \
+ (((v) << 31) & BM_PXP_HANDSHAKE_CPU_FETCH_SW1_HSK_EN)
+#define BP_PXP_HANDSHAKE_CPU_FETCH_RSVD1 22
+#define BM_PXP_HANDSHAKE_CPU_FETCH_RSVD1 0x7FC00000
+#define BF_PXP_HANDSHAKE_CPU_FETCH_RSVD1(v) \
+ (((v) << 22) & BM_PXP_HANDSHAKE_CPU_FETCH_RSVD1)
+#define BP_PXP_HANDSHAKE_CPU_FETCH_SW1_BUF_LINES 20
+#define BM_PXP_HANDSHAKE_CPU_FETCH_SW1_BUF_LINES 0x00300000
+#define BF_PXP_HANDSHAKE_CPU_FETCH_SW1_BUF_LINES(v) \
+ (((v) << 20) & BM_PXP_HANDSHAKE_CPU_FETCH_SW1_BUF_LINES)
+#define BV_PXP_HANDSHAKE_CPU_FETCH_SW1_BUF_LINES__LINE_4 0x0
+#define BV_PXP_HANDSHAKE_CPU_FETCH_SW1_BUF_LINES__LINE_8 0x1
+#define BV_PXP_HANDSHAKE_CPU_FETCH_SW1_BUF_LINES__LINE_16 0x2
+#define BM_PXP_HANDSHAKE_CPU_FETCH_SW1_B1_DONE 0x00080000
+#define BF_PXP_HANDSHAKE_CPU_FETCH_SW1_B1_DONE(v) \
+ (((v) << 19) & BM_PXP_HANDSHAKE_CPU_FETCH_SW1_B1_DONE)
+#define BM_PXP_HANDSHAKE_CPU_FETCH_SW1_B0_DONE 0x00040000
+#define BF_PXP_HANDSHAKE_CPU_FETCH_SW1_B0_DONE(v) \
+ (((v) << 18) & BM_PXP_HANDSHAKE_CPU_FETCH_SW1_B0_DONE)
+#define BM_PXP_HANDSHAKE_CPU_FETCH_SW1_B1_READY 0x00020000
+#define BF_PXP_HANDSHAKE_CPU_FETCH_SW1_B1_READY(v) \
+ (((v) << 17) & BM_PXP_HANDSHAKE_CPU_FETCH_SW1_B1_READY)
+#define BM_PXP_HANDSHAKE_CPU_FETCH_SW1_B0_READY 0x00010000
+#define BF_PXP_HANDSHAKE_CPU_FETCH_SW1_B0_READY(v) \
+ (((v) << 16) & BM_PXP_HANDSHAKE_CPU_FETCH_SW1_B0_READY)
+#define BM_PXP_HANDSHAKE_CPU_FETCH_SW0_HSK_EN 0x00008000
+#define BF_PXP_HANDSHAKE_CPU_FETCH_SW0_HSK_EN(v) \
+ (((v) << 15) & BM_PXP_HANDSHAKE_CPU_FETCH_SW0_HSK_EN)
+#define BP_PXP_HANDSHAKE_CPU_FETCH_RSVD0 6
+#define BM_PXP_HANDSHAKE_CPU_FETCH_RSVD0 0x00007FC0
+#define BF_PXP_HANDSHAKE_CPU_FETCH_RSVD0(v) \
+ (((v) << 6) & BM_PXP_HANDSHAKE_CPU_FETCH_RSVD0)
+#define BP_PXP_HANDSHAKE_CPU_FETCH_SW0_BUF_LINES 4
+#define BM_PXP_HANDSHAKE_CPU_FETCH_SW0_BUF_LINES 0x00000030
+#define BF_PXP_HANDSHAKE_CPU_FETCH_SW0_BUF_LINES(v) \
+ (((v) << 4) & BM_PXP_HANDSHAKE_CPU_FETCH_SW0_BUF_LINES)
+#define BV_PXP_HANDSHAKE_CPU_FETCH_SW0_BUF_LINES__LINE_4 0x0
+#define BV_PXP_HANDSHAKE_CPU_FETCH_SW0_BUF_LINES__LINE_8 0x1
+#define BV_PXP_HANDSHAKE_CPU_FETCH_SW0_BUF_LINES__LINE_16 0x2
+#define BM_PXP_HANDSHAKE_CPU_FETCH_SW0_B1_DONE 0x00000008
+#define BF_PXP_HANDSHAKE_CPU_FETCH_SW0_B1_DONE(v) \
+ (((v) << 3) & BM_PXP_HANDSHAKE_CPU_FETCH_SW0_B1_DONE)
+#define BM_PXP_HANDSHAKE_CPU_FETCH_SW0_B0_DONE 0x00000004
+#define BF_PXP_HANDSHAKE_CPU_FETCH_SW0_B0_DONE(v) \
+ (((v) << 2) & BM_PXP_HANDSHAKE_CPU_FETCH_SW0_B0_DONE)
+#define BM_PXP_HANDSHAKE_CPU_FETCH_SW0_B1_READY 0x00000002
+#define BF_PXP_HANDSHAKE_CPU_FETCH_SW0_B1_READY(v) \
+ (((v) << 1) & BM_PXP_HANDSHAKE_CPU_FETCH_SW0_B1_READY)
+#define BM_PXP_HANDSHAKE_CPU_FETCH_SW0_B0_READY 0x00000001
+#define BF_PXP_HANDSHAKE_CPU_FETCH_SW0_B0_READY(v) \
+ (((v) << 0) & BM_PXP_HANDSHAKE_CPU_FETCH_SW0_B0_READY)
+
+#define HW_PXP_HANDSHAKE_CPU_STORE (0x00002d40)
+#define HW_PXP_HANDSHAKE_CPU_STORE_SET (0x00002d44)
+#define HW_PXP_HANDSHAKE_CPU_STORE_CLR (0x00002d48)
+#define HW_PXP_HANDSHAKE_CPU_STORE_TOG (0x00002d4c)
+
+#define BM_PXP_HANDSHAKE_CPU_STORE_SW1_HSK_EN 0x80000000
+#define BF_PXP_HANDSHAKE_CPU_STORE_SW1_HSK_EN(v) \
+ (((v) << 31) & BM_PXP_HANDSHAKE_CPU_STORE_SW1_HSK_EN)
+#define BP_PXP_HANDSHAKE_CPU_STORE_RSVD1 22
+#define BM_PXP_HANDSHAKE_CPU_STORE_RSVD1 0x7FC00000
+#define BF_PXP_HANDSHAKE_CPU_STORE_RSVD1(v) \
+ (((v) << 22) & BM_PXP_HANDSHAKE_CPU_STORE_RSVD1)
+#define BP_PXP_HANDSHAKE_CPU_STORE_SW1_BUF_LINES 20
+#define BM_PXP_HANDSHAKE_CPU_STORE_SW1_BUF_LINES 0x00300000
+#define BF_PXP_HANDSHAKE_CPU_STORE_SW1_BUF_LINES(v) \
+ (((v) << 20) & BM_PXP_HANDSHAKE_CPU_STORE_SW1_BUF_LINES)
+#define BV_PXP_HANDSHAKE_CPU_STORE_SW1_BUF_LINES__LINE_4 0x0
+#define BV_PXP_HANDSHAKE_CPU_STORE_SW1_BUF_LINES__LINE_8 0x1
+#define BV_PXP_HANDSHAKE_CPU_STORE_SW1_BUF_LINES__LINE_16 0x2
+#define BM_PXP_HANDSHAKE_CPU_STORE_SW1_B1_DONE 0x00080000
+#define BF_PXP_HANDSHAKE_CPU_STORE_SW1_B1_DONE(v) \
+ (((v) << 19) & BM_PXP_HANDSHAKE_CPU_STORE_SW1_B1_DONE)
+#define BM_PXP_HANDSHAKE_CPU_STORE_SW1_B0_DONE 0x00040000
+#define BF_PXP_HANDSHAKE_CPU_STORE_SW1_B0_DONE(v) \
+ (((v) << 18) & BM_PXP_HANDSHAKE_CPU_STORE_SW1_B0_DONE)
+#define BM_PXP_HANDSHAKE_CPU_STORE_SW1_B1_READY 0x00020000
+#define BF_PXP_HANDSHAKE_CPU_STORE_SW1_B1_READY(v) \
+ (((v) << 17) & BM_PXP_HANDSHAKE_CPU_STORE_SW1_B1_READY)
+#define BM_PXP_HANDSHAKE_CPU_STORE_SW1_B0_READY 0x00010000
+#define BF_PXP_HANDSHAKE_CPU_STORE_SW1_B0_READY(v) \
+ (((v) << 16) & BM_PXP_HANDSHAKE_CPU_STORE_SW1_B0_READY)
+#define BM_PXP_HANDSHAKE_CPU_STORE_SW0_HSK_EN 0x00008000
+#define BF_PXP_HANDSHAKE_CPU_STORE_SW0_HSK_EN(v) \
+ (((v) << 15) & BM_PXP_HANDSHAKE_CPU_STORE_SW0_HSK_EN)
+#define BP_PXP_HANDSHAKE_CPU_STORE_RSVD0 6
+#define BM_PXP_HANDSHAKE_CPU_STORE_RSVD0 0x00007FC0
+#define BF_PXP_HANDSHAKE_CPU_STORE_RSVD0(v) \
+ (((v) << 6) & BM_PXP_HANDSHAKE_CPU_STORE_RSVD0)
+#define BP_PXP_HANDSHAKE_CPU_STORE_SW0_BUF_LINES 4
+#define BM_PXP_HANDSHAKE_CPU_STORE_SW0_BUF_LINES 0x00000030
+#define BF_PXP_HANDSHAKE_CPU_STORE_SW0_BUF_LINES(v) \
+ (((v) << 4) & BM_PXP_HANDSHAKE_CPU_STORE_SW0_BUF_LINES)
+#define BV_PXP_HANDSHAKE_CPU_STORE_SW0_BUF_LINES__LINE_4 0x0
+#define BV_PXP_HANDSHAKE_CPU_STORE_SW0_BUF_LINES__LINE_8 0x1
+#define BV_PXP_HANDSHAKE_CPU_STORE_SW0_BUF_LINES__LINE_16 0x2
+#define BM_PXP_HANDSHAKE_CPU_STORE_SW0_B1_DONE 0x00000008
+#define BF_PXP_HANDSHAKE_CPU_STORE_SW0_B1_DONE(v) \
+ (((v) << 3) & BM_PXP_HANDSHAKE_CPU_STORE_SW0_B1_DONE)
+#define BM_PXP_HANDSHAKE_CPU_STORE_SW0_B0_DONE 0x00000004
+#define BF_PXP_HANDSHAKE_CPU_STORE_SW0_B0_DONE(v) \
+ (((v) << 2) & BM_PXP_HANDSHAKE_CPU_STORE_SW0_B0_DONE)
+#define BM_PXP_HANDSHAKE_CPU_STORE_SW0_B1_READY 0x00000002
+#define BF_PXP_HANDSHAKE_CPU_STORE_SW0_B1_READY(v) \
+ (((v) << 1) & BM_PXP_HANDSHAKE_CPU_STORE_SW0_B1_READY)
+#define BM_PXP_HANDSHAKE_CPU_STORE_SW0_B0_READY 0x00000001
+#define BF_PXP_HANDSHAKE_CPU_STORE_SW0_B0_READY(v) \
+ (((v) << 0) & BM_PXP_HANDSHAKE_CPU_STORE_SW0_B0_READY)
+#endif /* __ARCH_ARM___PXP_H */
diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c
index e47fc9b0944f..c940cec61f39 100644
--- a/drivers/dma/virt-dma.c
+++ b/drivers/dma/virt-dma.c
@@ -108,12 +108,13 @@ static void vchan_complete(unsigned long arg)
dmaengine_desc_get_callback(&vd->tx, &cb);
list_del(&vd->node);
+
+ dmaengine_desc_callback_invoke(&cb, NULL);
+
if (dmaengine_desc_test_reuse(&vd->tx))
list_add(&vd->node, &vc->desc_allocated);
else
vc->desc_free(vd);
-
- dmaengine_desc_callback_invoke(&cb, NULL);
}
}
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 04788d92ea52..462660029e9a 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -132,4 +132,13 @@ config EXTCON_USB_GPIO
Say Y here to enable GPIO based USB cable detection extcon support.
Used typically if GPIO is used for USB ID pin detection.
+config EXTCON_PTN5150
+ tristate "NXP PTN5150 CC Logic For Type-C Applications"
+ depends on I2C && GPIOLIB
+ select REGMAP_I2C
+ help
+ Say Y here to enable NXP PTN5150 CC logic for Type-C applications,
+ this chip can supply the CC flip, attach and detach detection.
+
+
endif
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 31a0a999c4fb..ed6e0d5cd936 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_EXTCON_QCOM_SPMI_MISC) += extcon-qcom-spmi-misc.o
obj-$(CONFIG_EXTCON_RT8973A) += extcon-rt8973a.o
obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o
obj-$(CONFIG_EXTCON_USB_GPIO) += extcon-usb-gpio.o
+obj-$(CONFIG_EXTCON_PTN5150) += extcon-ptn5150.o
diff --git a/drivers/extcon/extcon-ptn5150.c b/drivers/extcon/extcon-ptn5150.c
new file mode 100644
index 000000000000..778b427699c0
--- /dev/null
+++ b/drivers/extcon/extcon-ptn5150.c
@@ -0,0 +1,271 @@
+/*
+ * extcon-ptn5150.c - NXP CC logic for USB Type-C applications
+ *
+ * Copyright 2017 NXP
+ * Author: Peter Chen <peter.chen@nxp.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/extcon.h>
+#include <linux/gpio/consumer.h>
+
+/* PTN5150_REG_INT_STATUS */
+#define CABLE_ATTACHED (1 << 0)
+#define CABLE_DETACHED (1 << 1)
+/* PTN5150_REG_CC_STATUS */
+#define IS_DFP_ATTATCHED(val) (((val) & 0x1c) == 0x4)
+#define IS_UFP_ATTATCHED(val) (((val) & 0x1c) == 0x8)
+#define IS_NOT_CONNECTED(val) (((val) & 0x1c) == 0x0)
+/* PTN5150_REG_CON_DET */
+#define DISABLE_CON_DET (1 << 0)
+
+struct ptn5150_info {
+ struct device *dev;
+ struct extcon_dev *edev;
+
+ struct work_struct wq_detect_cable;
+ struct regmap *regmap;
+};
+
+/* List of detectable cables */
+static const unsigned int ptn5150_extcon_cable[] = {
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+ EXTCON_NONE,
+};
+
+enum ptn5150_reg {
+ PTN5150_REG_DEVICE_ID = 0x1,
+ PTN5150_REG_CONTROL,
+ PTN5150_REG_INT_STATUS,
+ PTN5150_REG_CC_STATUS,
+ PTN5150_REG_RSVD_5,
+ PTN5150_REG_RSVD_6,
+ PTN5150_REG_RSVD_7,
+ PTN5150_REG_RSVD_8,
+ PTN5150_REG_CON_DET,
+ PTN5150_REG_VCONN_STATUS,
+ PTN5150_REG_RESET = 0x10,
+ PTN5150_REG_RSVD_11,
+ PTN5150_REG_RSVD_12,
+ PTN5150_REG_RSVD_13,
+ PTN5150_REG_RSVD_14,
+ PTN5150_REG_RSVD_15,
+ PTN5150_REG_RSVD_16,
+ PTN5150_REG_RSVD_17,
+ PTN5150_REG_INT_MASK,
+ PTN5150_REG_INT_REG_STATUS,
+
+ PTN5150_REG_END,
+};
+static const struct regmap_config ptn5150_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = PTN5150_REG_END,
+};
+
+static void ptn5150_detect_cable(struct work_struct *work)
+{
+ struct ptn5150_info *info = container_of(work, struct ptn5150_info,
+ wq_detect_cable);
+ int ret;
+ unsigned int val;
+
+ ret = regmap_read(info->regmap, PTN5150_REG_CC_STATUS, &val);
+ if (ret)
+ dev_err(info->dev, "failed to get CC status:%d\n", ret);
+
+ if (IS_UFP_ATTATCHED(val)) {
+ extcon_set_state_sync(info->edev, EXTCON_USB, false);
+ extcon_set_state_sync(info->edev, EXTCON_USB_HOST,
+ true);
+ } else if (IS_DFP_ATTATCHED(val)) {
+ extcon_set_state_sync(info->edev, EXTCON_USB_HOST,
+ false);
+ extcon_set_state_sync(info->edev, EXTCON_USB, true);
+ } else if (IS_NOT_CONNECTED(val)) {
+ extcon_set_state_sync(info->edev, EXTCON_USB, false);
+ extcon_set_state_sync(info->edev, EXTCON_USB_HOST, false);
+ } else {
+ dev_dbg(info->dev, "other CC status is :0x%x", val);
+ }
+}
+
+static int ptn5150_clear_interrupt(struct ptn5150_info *info)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(info->regmap, PTN5150_REG_INT_STATUS, &val);
+ if (ret)
+ dev_err(info->dev,
+ "failed to clear interrupt status:%d\n",
+ ret);
+
+ return (ret < 0) ? ret : (int)val;
+}
+
+static irqreturn_t ptn5150_connect_irq_handler(int irq, void *dev_id)
+{
+ struct ptn5150_info *info = dev_id;
+
+ if (ptn5150_clear_interrupt(info) > 0)
+ queue_work(system_power_efficient_wq, &info->wq_detect_cable);
+
+ return IRQ_HANDLED;
+}
+
+static int ptn5150_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct device_node *np = i2c->dev.of_node;
+ struct ptn5150_info *info;
+ int ret, connect_irq, gpio_val, count = 1000;
+ unsigned int dev_id;
+ struct gpio_desc *connect_gpiod;
+
+ if (!np)
+ return -EINVAL;
+
+ info = devm_kzalloc(&i2c->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, info);
+ info->dev = &i2c->dev;
+ info->regmap = devm_regmap_init_i2c(i2c, &ptn5150_regmap_config);
+ if (IS_ERR(info->regmap)) {
+ ret = PTR_ERR(info->regmap);
+ dev_err(info->dev, "failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ /* Allocate extcon device */
+ info->edev = devm_extcon_dev_allocate(info->dev, ptn5150_extcon_cable);
+ if (IS_ERR(info->edev)) {
+ dev_err(info->dev, "failed to allocate memory for extcon\n");
+ return -ENOMEM;
+ }
+
+ /* Register extcon device */
+ ret = devm_extcon_dev_register(info->dev, info->edev);
+ if (ret) {
+ dev_err(info->dev, "failed to register extcon device\n");
+ return ret;
+ }
+
+ connect_gpiod = devm_gpiod_get(info->dev, "connect", GPIOD_IN);
+ if (IS_ERR(connect_gpiod)) {
+ dev_err(info->dev, "failed to get connect GPIO\n");
+ return PTR_ERR(connect_gpiod);
+ }
+
+ connect_irq = gpiod_to_irq(connect_gpiod);
+ if (connect_irq < 0) {
+ dev_err(info->dev, "failed to get connect IRQ\n");
+ return connect_irq;
+ }
+
+ /* Clear the pending interrupts */
+ ret = ptn5150_clear_interrupt(info);
+ if (ret < 0)
+ return ret;
+
+ gpio_val = gpiod_get_value(connect_gpiod);
+ /* Delay until the GPIO goes to high if it is low before */
+ while (gpio_val == 0 && count >= 0) {
+ gpio_val = gpiod_get_value(connect_gpiod);
+ usleep_range(10, 20);
+ count--;
+ }
+
+ if (count < 0)
+ dev_err(info->dev, "timeout for waiting gpio becoming high\n");
+
+ ret = regmap_read(info->regmap, PTN5150_REG_DEVICE_ID, &dev_id);
+ if (ret) {
+ dev_err(info->dev, "failed to read device id:%d\n", ret);
+ return ret;
+ }
+
+ dev_dbg(info->dev, "NXP PTN5150: Version ID:0x%x, Vendor ID:0x%x\n",
+ (dev_id >> 3), (dev_id & 0x3));
+
+ ret = regmap_update_bits(info->regmap, PTN5150_REG_CON_DET,
+ DISABLE_CON_DET, ~DISABLE_CON_DET);
+ if (ret) {
+ dev_err(info->dev,
+ "failed to enable CON_DET output on pin 5:%d\n",
+ ret);
+ return ret;
+ }
+
+ INIT_WORK(&info->wq_detect_cable, ptn5150_detect_cable);
+
+ ret = devm_request_threaded_irq(info->dev, connect_irq, NULL,
+ ptn5150_connect_irq_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ dev_name(info->dev), info);
+ if (ret < 0) {
+ dev_err(info->dev, "failed to request connect IRQ\n");
+ return ret;
+ }
+
+ /* Do cable detect now */
+ ptn5150_detect_cable(&info->wq_detect_cable);
+
+ return ret;
+}
+
+static int ptn5150_i2c_remove(struct i2c_client *i2c)
+{
+ return 0;
+}
+
+static const struct i2c_device_id ptn5150_id[] = {
+ { "ptn5150", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, ptn5150_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id ptn5150_of_match[] = {
+ { .compatible = "nxp,ptn5150", },
+ { .compatible = "nxp,ptn5150a", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ptn5150_of_match);
+#endif
+
+static struct i2c_driver ptn5150_i2c_driver = {
+ .driver = {
+ .name = "ptn5150",
+ .of_match_table = of_match_ptr(ptn5150_of_match),
+ },
+ .probe = ptn5150_i2c_probe,
+ .remove = ptn5150_i2c_remove,
+ .id_table = ptn5150_id,
+};
+module_i2c_driver(ptn5150_i2c_driver);
+
+MODULE_DESCRIPTION("NXP PTN5150 CC logic driver for USB Type-C");
+MODULE_AUTHOR("Peter Chen <peter.chen@nxp.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
index a27d350f69e3..d47573a31e17 100644
--- a/drivers/extcon/extcon-usb-gpio.c
+++ b/drivers/extcon/extcon-usb-gpio.c
@@ -24,10 +24,10 @@
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
-#include <linux/pm_wakeirq.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/acpi.h>
+#include <linux/pinctrl/consumer.h>
#define USB_GPIO_DEBOUNCE_MS 20 /* ms */
@@ -36,7 +36,9 @@ struct usb_extcon_info {
struct extcon_dev *edev;
struct gpio_desc *id_gpiod;
+ struct gpio_desc *vbus_gpiod;
int id_irq;
+ int vbus_irq;
unsigned long debounce_jiffies;
struct delayed_work wq_detcable;
@@ -48,31 +50,47 @@ static const unsigned int usb_extcon_cable[] = {
EXTCON_NONE,
};
+/*
+ * "USB" = VBUS and "USB-HOST" = !ID, so we have:
+ * Both "USB" and "USB-HOST" can't be set as active at the
+ * same time so if "USB-HOST" is active (i.e. ID is 0) we keep "USB" inactive
+ * even if VBUS is on.
+ *
+ * State | ID | VBUS
+ * ----------------------------------------
+ * [1] USB | H | H
+ * [2] none | H | L
+ * [3] USB-HOST | L | H
+ * [4] USB-HOST | L | L
+ *
+ * In case we have only one of these signals:
+ * - VBUS only - we want to distinguish between [1] and [2], so ID is always 1.
+ * - ID only - we want to distinguish between [1] and [4], so VBUS = ID.
+*/
static void usb_extcon_detect_cable(struct work_struct *work)
{
- int id;
+ int id, vbus;
struct usb_extcon_info *info = container_of(to_delayed_work(work),
struct usb_extcon_info,
wq_detcable);
- /* check ID and update cable state */
- id = gpiod_get_value_cansleep(info->id_gpiod);
- if (id) {
- /*
- * ID = 1 means USB HOST cable detached.
- * As we don't have event for USB peripheral cable attached,
- * we simulate USB peripheral attach here.
- */
+ /* check ID and VBUS and update cable state */
+ id = info->id_gpiod ?
+ gpiod_get_value_cansleep(info->id_gpiod) : 1;
+ vbus = info->vbus_gpiod ?
+ gpiod_get_value_cansleep(info->vbus_gpiod) : id;
+
+ /* at first we clean states which are no longer active */
+ if (id)
extcon_set_state_sync(info->edev, EXTCON_USB_HOST, false);
- extcon_set_state_sync(info->edev, EXTCON_USB, true);
- } else {
- /*
- * ID = 0 means USB HOST cable attached.
- * As we don't have event for USB peripheral cable detached,
- * we simulate USB peripheral detach here.
- */
+ if (!vbus)
extcon_set_state_sync(info->edev, EXTCON_USB, false);
+
+ if (!id) {
extcon_set_state_sync(info->edev, EXTCON_USB_HOST, true);
+ } else {
+ if (vbus)
+ extcon_set_state_sync(info->edev, EXTCON_USB, true);
}
}
@@ -101,12 +119,21 @@ static int usb_extcon_probe(struct platform_device *pdev)
return -ENOMEM;
info->dev = dev;
- info->id_gpiod = devm_gpiod_get(&pdev->dev, "id", GPIOD_IN);
- if (IS_ERR(info->id_gpiod)) {
- dev_err(dev, "failed to get ID GPIO\n");
- return PTR_ERR(info->id_gpiod);
+ info->id_gpiod = devm_gpiod_get_optional(&pdev->dev, "id", GPIOD_IN);
+ info->vbus_gpiod = devm_gpiod_get_optional(&pdev->dev, "vbus",
+ GPIOD_IN);
+
+ if (!info->id_gpiod && !info->vbus_gpiod) {
+ dev_err(dev, "failed to get gpios\n");
+ return -ENODEV;
}
+ if (IS_ERR(info->id_gpiod))
+ return PTR_ERR(info->id_gpiod);
+
+ if (IS_ERR(info->vbus_gpiod))
+ return PTR_ERR(info->vbus_gpiod);
+
info->edev = devm_extcon_dev_allocate(dev, usb_extcon_cable);
if (IS_ERR(info->edev)) {
dev_err(dev, "failed to allocate extcon device\n");
@@ -119,32 +146,56 @@ static int usb_extcon_probe(struct platform_device *pdev)
return ret;
}
- ret = gpiod_set_debounce(info->id_gpiod,
- USB_GPIO_DEBOUNCE_MS * 1000);
+ if (info->id_gpiod)
+ ret = gpiod_set_debounce(info->id_gpiod,
+ USB_GPIO_DEBOUNCE_MS * 1000);
+ if (!ret && info->vbus_gpiod)
+ ret = gpiod_set_debounce(info->vbus_gpiod,
+ USB_GPIO_DEBOUNCE_MS * 1000);
+
if (ret < 0)
info->debounce_jiffies = msecs_to_jiffies(USB_GPIO_DEBOUNCE_MS);
INIT_DELAYED_WORK(&info->wq_detcable, usb_extcon_detect_cable);
- info->id_irq = gpiod_to_irq(info->id_gpiod);
- if (info->id_irq < 0) {
- dev_err(dev, "failed to get ID IRQ\n");
- return info->id_irq;
+ if (info->id_gpiod) {
+ info->id_irq = gpiod_to_irq(info->id_gpiod);
+ if (info->id_irq < 0) {
+ dev_err(dev, "failed to get ID IRQ\n");
+ return info->id_irq;
+ }
+
+ ret = devm_request_threaded_irq(dev, info->id_irq, NULL,
+ usb_irq_handler,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ pdev->name, info);
+ if (ret < 0) {
+ dev_err(dev, "failed to request handler for ID IRQ\n");
+ return ret;
+ }
}
- ret = devm_request_threaded_irq(dev, info->id_irq, NULL,
- usb_irq_handler,
- IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- pdev->name, info);
- if (ret < 0) {
- dev_err(dev, "failed to request handler for ID IRQ\n");
- return ret;
+ if (info->vbus_gpiod) {
+ info->vbus_irq = gpiod_to_irq(info->vbus_gpiod);
+ if (info->vbus_irq < 0) {
+ dev_err(dev, "failed to get VBUS IRQ\n");
+ return info->vbus_irq;
+ }
+
+ ret = devm_request_threaded_irq(dev, info->vbus_irq, NULL,
+ usb_irq_handler,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ pdev->name, info);
+ if (ret < 0) {
+ dev_err(dev, "failed to request handler for VBUS IRQ\n");
+ return ret;
+ }
}
platform_set_drvdata(pdev, info);
- device_init_wakeup(dev, true);
- dev_pm_set_wake_irq(dev, info->id_irq);
+ device_set_wakeup_capable(&pdev->dev, true);
/* Perform initial detection */
usb_extcon_detect_cable(&info->wq_detcable.work);
@@ -157,8 +208,6 @@ static int usb_extcon_remove(struct platform_device *pdev)
struct usb_extcon_info *info = platform_get_drvdata(pdev);
cancel_delayed_work_sync(&info->wq_detcable);
-
- dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false);
return 0;
@@ -170,12 +219,35 @@ static int usb_extcon_suspend(struct device *dev)
struct usb_extcon_info *info = dev_get_drvdata(dev);
int ret = 0;
+ if (device_may_wakeup(dev)) {
+ if (info->id_gpiod) {
+ ret = enable_irq_wake(info->id_irq);
+ if (ret)
+ return ret;
+ }
+ if (info->vbus_gpiod) {
+ ret = enable_irq_wake(info->vbus_irq);
+ if (ret) {
+ if (info->id_gpiod)
+ disable_irq_wake(info->id_irq);
+
+ return ret;
+ }
+ }
+ }
+
/*
* We don't want to process any IRQs after this point
* as GPIOs used behind I2C subsystem might not be
* accessible until resume completes. So disable IRQ.
*/
- disable_irq(info->id_irq);
+ if (info->id_gpiod)
+ disable_irq(info->id_irq);
+ if (info->vbus_gpiod)
+ disable_irq(info->vbus_irq);
+
+ if (!device_may_wakeup(dev))
+ pinctrl_pm_select_sleep_state(dev);
return ret;
}
@@ -185,10 +257,33 @@ static int usb_extcon_resume(struct device *dev)
struct usb_extcon_info *info = dev_get_drvdata(dev);
int ret = 0;
- enable_irq(info->id_irq);
if (!device_may_wakeup(dev))
- queue_delayed_work(system_power_efficient_wq,
- &info->wq_detcable, 0);
+ pinctrl_pm_select_default_state(dev);
+
+ if (device_may_wakeup(dev)) {
+ if (info->id_gpiod) {
+ ret = disable_irq_wake(info->id_irq);
+ if (ret)
+ return ret;
+ }
+ if (info->vbus_gpiod) {
+ ret = disable_irq_wake(info->vbus_irq);
+ if (ret) {
+ if (info->id_gpiod)
+ enable_irq_wake(info->id_irq);
+
+ return ret;
+ }
+ }
+ }
+
+ if (info->id_gpiod)
+ enable_irq(info->id_irq);
+ if (info->vbus_gpiod)
+ enable_irq(info->vbus_irq);
+
+ queue_delayed_work(system_power_efficient_wq,
+ &info->wq_detcable, 0);
return ret;
}
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 12d417a4d4a8..62b268f9b485 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -321,7 +321,7 @@ config GPIO_MVEBU
config GPIO_MXC
def_bool y
- depends on ARCH_MXC
+ depends on ARCH_MXC || ARCH_MXC_ARM64 || COMPILE_TEST
select GPIO_GENERIC
select GENERIC_IRQ_CHIP
@@ -331,6 +331,13 @@ config GPIO_MXS
select GPIO_GENERIC
select GENERIC_IRQ_CHIP
+config GPIO_MXC_PAD_WAKEUP
+ def_bool n
+ depends on ARCH_MXC_ARM64 || COMPILE_TEST
+ select GPIO_MXC
+ help
+ Say Y here to enable the imx8 gpio pad wakeup
+
config GPIO_OCTEON
tristate "Cavium OCTEON GPIO"
depends on GPIOLIB && CAVIUM_OCTEON_SOC
@@ -443,6 +450,12 @@ config GPIO_VF610
help
Say yes here to support Vybrid vf610 GPIOs.
+config GPIO_IMX_RPMSG
+ bool "NXP i.MX7ULP RPMSG GPIO support"
+ depends on ARCH_MXC && RPMSG && GPIOLIB
+ help
+ This driver support i.MX7ULP RPMSG virtual GPIOs.
+
config GPIO_VR41XX
tristate "NEC VR4100 series General-purpose I/O Uint support"
depends on CPU_VR41XX
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index d074c2299393..95f52f4a97ce 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -124,6 +124,7 @@ obj-$(CONFIG_GPIO_TZ1090) += gpio-tz1090.o
obj-$(CONFIG_GPIO_TZ1090_PDC) += gpio-tz1090-pdc.o
obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
+obj-$(CONFIG_GPIO_IMX_RPMSG) += gpio-imx-rpmsg.o
obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c
index a6607faf2fdf..fbca09c92686 100644
--- a/drivers/gpio/gpio-74x164.c
+++ b/drivers/gpio/gpio-74x164.c
@@ -138,6 +138,9 @@ static int gen_74x164_probe(struct spi_device *spi)
chip->registers = nregs;
chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers;
+ of_property_read_u8_array(spi->dev.of_node, "registers-default",
+ chip->buffer, chip->registers);
+
chip->gpio_chip.can_sleep = true;
chip->gpio_chip.parent = &spi->dev;
chip->gpio_chip.owner = THIS_MODULE;
diff --git a/drivers/gpio/gpio-imx-rpmsg.c b/drivers/gpio/gpio-imx-rpmsg.c
new file mode 100644
index 000000000000..092c290942ba
--- /dev/null
+++ b/drivers/gpio/gpio-imx-rpmsg.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/imx_rpmsg.h>
+#include <linux/init.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+#include <linux/rpmsg.h>
+#include <linux/virtio.h>
+
+#define IMX_RPMSG_GPIO_PER_PORT 32
+#define RPMSG_TIMEOUT 1000
+
+enum gpio_input_trigger_type {
+ GPIO_RPMSG_TRI_IGNORE,
+ GPIO_RPMSG_TRI_RISING,
+ GPIO_RPMSG_TRI_FALLING,
+ GPIO_RPMSG_TRI_BOTH_EDGE,
+ GPIO_RPMSG_TRI_LOW_LEVEL,
+ GPIO_RPMSG_TRI_HIGH_LEVEL,
+};
+
+enum gpio_rpmsg_header_type {
+ GPIO_RPMSG_SETUP,
+ GPIO_RPMSG_REPLY,
+ GPIO_RPMSG_NOTIFY,
+};
+
+enum gpio_rpmsg_header_cmd {
+ GPIO_RPMSG_INPUT_INIT,
+ GPIO_RPMSG_OUTPUT_INIT,
+ GPIO_RPMSG_INPUT_GET,
+};
+
+struct gpio_rpmsg_data {
+ struct imx_rpmsg_head header;
+ u8 pin_idx;
+ u8 port_idx;
+ union {
+ u8 event;
+ u8 retcode;
+ u8 value;
+ } out;
+ union {
+ u8 wakeup;
+ u8 value;
+ } in;
+} __packed __aligned(8);
+
+struct imx_rpmsg_gpio_port {
+ struct gpio_chip gc;
+ struct irq_chip chip;
+ struct irq_domain *domain;
+ struct gpio_rpmsg_data msg;
+ u32 irq_type[IMX_RPMSG_GPIO_PER_PORT];
+ int idx;
+};
+
+struct imx_gpio_rpmsg_info {
+ struct rpmsg_device *rpdev;
+ struct gpio_rpmsg_data *notify_msg;
+ struct gpio_rpmsg_data *reply_msg;
+ struct pm_qos_request pm_qos_req;
+ struct completion cmd_complete;
+ struct mutex lock;
+};
+
+static struct imx_gpio_rpmsg_info gpio_rpmsg;
+
+static int gpio_send_message(struct imx_rpmsg_gpio_port *port,
+ struct gpio_rpmsg_data *msg,
+ struct imx_gpio_rpmsg_info *info,
+ bool sync)
+{
+ int err;
+
+ if (!info->rpdev) {
+ dev_dbg(&info->rpdev->dev,
+ "rpmsg channel not ready, m4 image ready?\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&info->lock);
+ pm_qos_add_request(&info->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, 0);
+
+ reinit_completion(&info->cmd_complete);
+
+ err = rpmsg_send(info->rpdev->ept, (void *)msg,
+ sizeof(struct gpio_rpmsg_data));
+
+ if (err) {
+ dev_err(&info->rpdev->dev, "rpmsg_send failed: %d\n", err);
+ goto err_out;
+ }
+
+ if (sync) {
+ err = wait_for_completion_timeout(&info->cmd_complete,
+ msecs_to_jiffies(RPMSG_TIMEOUT));
+ if (!err) {
+ dev_err(&info->rpdev->dev, "rpmsg_send timeout!\n");
+ err = -ETIMEDOUT;
+ goto err_out;
+ }
+
+ if (info->reply_msg->out.retcode != 0) {
+ dev_err(&info->rpdev->dev, "rpmsg not ack %d!\n",
+ info->reply_msg->out.retcode);
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ /* copy the reply message */
+ memcpy(&port->msg, info->reply_msg, sizeof(*info->reply_msg));
+
+ err = 0;
+ }
+
+err_out:
+ pm_qos_remove_request(&info->pm_qos_req);
+ mutex_unlock(&info->lock);
+
+ return err;
+}
+
+static int gpio_rpmsg_cb(struct rpmsg_device *rpdev,
+ void *data, int len, void *priv, u32 src)
+{
+ struct gpio_rpmsg_data *msg = (struct gpio_rpmsg_data *)data;
+
+ if (msg->header.type == GPIO_RPMSG_REPLY) {
+ gpio_rpmsg.reply_msg = msg;
+ complete(&gpio_rpmsg.cmd_complete);
+ } else if (msg->header.type == GPIO_RPMSG_NOTIFY) {
+ gpio_rpmsg.notify_msg = msg;
+ /* TBD for interrupt handler */
+ } else
+ dev_err(&gpio_rpmsg.rpdev->dev, "wrong command type!\n");
+
+ return 0;
+}
+
+static int imx_rpmsg_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct imx_rpmsg_gpio_port *port = gpiochip_get_data(gc);
+ struct gpio_rpmsg_data msg;
+ int ret;
+
+ memset(&msg, 0, sizeof(struct gpio_rpmsg_data));
+ msg.header.cate = IMX_RPMSG_GPIO;
+ msg.header.major = IMX_RMPSG_MAJOR;
+ msg.header.minor = IMX_RMPSG_MINOR;
+ msg.header.type = GPIO_RPMSG_SETUP;
+ msg.header.cmd = GPIO_RPMSG_INPUT_GET;
+ msg.pin_idx = gpio;
+ msg.port_idx = port->idx;
+
+ ret = gpio_send_message(port, &msg, &gpio_rpmsg, true);
+ if (!ret)
+ return !!port->msg.in.value;
+
+ return ret;
+}
+
+static int imx_rpmsg_gpio_direction_input(struct gpio_chip *gc,
+ unsigned int gpio)
+{
+ struct imx_rpmsg_gpio_port *port = gpiochip_get_data(gc);
+ struct gpio_rpmsg_data msg;
+
+ memset(&msg, 0, sizeof(struct gpio_rpmsg_data));
+ msg.header.cate = IMX_RPMSG_GPIO;
+ msg.header.major = IMX_RMPSG_MAJOR;
+ msg.header.minor = IMX_RMPSG_MINOR;
+ msg.header.type = GPIO_RPMSG_SETUP;
+ msg.header.cmd = GPIO_RPMSG_INPUT_INIT;
+ msg.pin_idx = gpio;
+ msg.port_idx = port->idx;
+
+ /* TBD: get event trigger and wakeup from GPIO descriptor */
+ msg.out.event = GPIO_RPMSG_TRI_IGNORE;
+ msg.in.wakeup = 0;
+
+ return gpio_send_message(port, &msg, &gpio_rpmsg, true);
+}
+
+static inline void imx_rpmsg_gpio_direction_output_init(struct gpio_chip *gc,
+ unsigned int gpio, int val, struct gpio_rpmsg_data *msg)
+{
+ struct imx_rpmsg_gpio_port *port = gpiochip_get_data(gc);
+
+ msg->header.cate = IMX_RPMSG_GPIO;
+ msg->header.major = IMX_RMPSG_MAJOR;
+ msg->header.minor = IMX_RMPSG_MINOR;
+ msg->header.type = GPIO_RPMSG_SETUP;
+ msg->header.cmd = GPIO_RPMSG_OUTPUT_INIT;
+ msg->pin_idx = gpio;
+ msg->port_idx = port->idx;
+ msg->out.value = val;
+}
+
+static void imx_rpmsg_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct imx_rpmsg_gpio_port *port = gpiochip_get_data(gc);
+ struct gpio_rpmsg_data msg;
+
+ memset(&msg, 0, sizeof(struct gpio_rpmsg_data));
+ imx_rpmsg_gpio_direction_output_init(gc, gpio, val, &msg);
+ gpio_send_message(port, &msg, &gpio_rpmsg, true);
+}
+
+static int imx_rpmsg_gpio_direction_output(struct gpio_chip *gc,
+ unsigned int gpio, int val)
+{
+ struct imx_rpmsg_gpio_port *port = gpiochip_get_data(gc);
+ struct gpio_rpmsg_data msg;
+
+ memset(&msg, 0, sizeof(struct gpio_rpmsg_data));
+ imx_rpmsg_gpio_direction_output_init(gc, gpio, val, &msg);
+ return gpio_send_message(port, &msg, &gpio_rpmsg, true);
+}
+
+static int gpio_rpmsg_probe(struct rpmsg_device *rpdev)
+{
+ gpio_rpmsg.rpdev = rpdev;
+ dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
+ rpdev->src, rpdev->dst);
+
+ init_completion(&gpio_rpmsg.cmd_complete);
+ mutex_init(&gpio_rpmsg.lock);
+
+ return 0;
+}
+
+static struct rpmsg_device_id gpio_rpmsg_id_table[] = {
+ { .name = "rpmsg-io-channel" },
+ {},
+};
+
+static struct rpmsg_driver gpio_rpmsg_driver = {
+ .drv.name = "gpio_rpmsg",
+ .drv.owner = THIS_MODULE,
+ .id_table = gpio_rpmsg_id_table,
+ .probe = gpio_rpmsg_probe,
+ .callback = gpio_rpmsg_cb,
+};
+
+static int imx_rpmsg_irq_set_type(struct irq_data *d, u32 type)
+{
+ struct imx_rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+ u32 gpio_idx = d->hwirq;
+ int edge = 0;
+ int ret = 0;
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ edge = GPIO_RPMSG_TRI_RISING;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ edge = GPIO_RPMSG_TRI_FALLING;
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ edge = GPIO_RPMSG_TRI_BOTH_EDGE;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ edge = GPIO_RPMSG_TRI_LOW_LEVEL;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ edge = GPIO_RPMSG_TRI_HIGH_LEVEL;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ port->irq_type[gpio_idx] = edge;
+ return ret;
+}
+
+static int imx_rpmsg_irq_set_wake(struct irq_data *d, u32 enable)
+{
+ struct imx_rpmsg_gpio_port *port = irq_data_get_irq_chip_data(d);
+ struct gpio_rpmsg_data msg;
+ u32 gpio_idx = d->hwirq;
+
+ memset(&msg, 0, sizeof(struct gpio_rpmsg_data));
+ msg.header.cate = IMX_RPMSG_GPIO;
+ msg.header.major = IMX_RMPSG_MAJOR;
+ msg.header.minor = IMX_RMPSG_MINOR;
+ msg.header.type = GPIO_RPMSG_SETUP;
+ msg.header.cmd = GPIO_RPMSG_INPUT_INIT;
+ msg.pin_idx = gpio_idx;
+ msg.port_idx = port->idx;
+
+ /* set wakeup trigger source,
+ * if not set irq type, then use high level as trigger type
+ */
+ msg.out.event = port->irq_type[gpio_idx];
+ if (!msg.out.event)
+ msg.out.event = GPIO_RPMSG_TRI_HIGH_LEVEL;
+
+ msg.in.wakeup = enable;
+
+ /* here should be atomic context */
+ gpio_send_message(port, &msg, &gpio_rpmsg, false);
+
+ return 0;
+}
+
+static void imx_rpmsg_unmask_irq(struct irq_data *d)
+{
+ /* No need to implement the callback */
+}
+
+static void imx_rpmsg_mask_irq(struct irq_data *d)
+{
+ /* No need to implement the callback */
+}
+
+static struct irq_chip imx_rpmsg_irq_chip = {
+ .irq_mask = imx_rpmsg_mask_irq,
+ .irq_unmask = imx_rpmsg_unmask_irq,
+ .irq_set_wake = imx_rpmsg_irq_set_wake,
+ .irq_set_type = imx_rpmsg_irq_set_type,
+};
+
+static int imx_rpmsg_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct imx_rpmsg_gpio_port *port;
+ struct gpio_chip *gc;
+ int i, irq_base;
+ int ret;
+
+ port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ ret = of_property_read_u32(np, "port_idx", &port->idx);
+ if (ret)
+ return ret;
+
+ gc = &port->gc;
+ gc->of_node = np;
+ gc->parent = dev;
+ gc->label = "imx-rpmsg-gpio";
+ gc->ngpio = IMX_RPMSG_GPIO_PER_PORT;
+ gc->base = of_alias_get_id(np, "gpio") * IMX_RPMSG_GPIO_PER_PORT;
+
+ gc->direction_input = imx_rpmsg_gpio_direction_input;
+ gc->direction_output = imx_rpmsg_gpio_direction_output;
+ gc->get = imx_rpmsg_gpio_get;
+ gc->set = imx_rpmsg_gpio_set;
+
+ platform_set_drvdata(pdev, port);
+
+ ret = devm_gpiochip_add_data(dev, gc, port);
+ if (ret < 0)
+ return ret;
+
+ /* generate one new irq domain */
+ port->chip = imx_rpmsg_irq_chip;
+ port->chip.name = kasprintf(GFP_KERNEL, "rpmsg-irq-port-%d", port->idx);
+ port->chip.parent_device = NULL;
+
+ irq_base = irq_alloc_descs(-1, 0, IMX_RPMSG_GPIO_PER_PORT,
+ numa_node_id());
+ WARN_ON(irq_base < 0);
+
+ port->domain = irq_domain_add_legacy(np, IMX_RPMSG_GPIO_PER_PORT,
+ irq_base, 0,
+ &irq_domain_simple_ops, port);
+ WARN_ON(!port->domain);
+ for (i = irq_base; i < irq_base + IMX_RPMSG_GPIO_PER_PORT; i++) {
+ irq_set_chip_and_handler(i, &port->chip, handle_level_irq);
+ irq_set_chip_data(i, port);
+ irq_clear_status_flags(i, IRQ_NOREQUEST);
+ irq_set_probe(i);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id imx_rpmsg_gpio_dt_ids[] = {
+ { .compatible = "fsl,imx-rpmsg-gpio" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver imx_rpmsg_gpio_driver = {
+ .driver = {
+ .name = "gpio-imx-rpmsg",
+ .of_match_table = imx_rpmsg_gpio_dt_ids,
+ },
+ .probe = imx_rpmsg_gpio_probe,
+};
+
+static int __init gpio_imx_rpmsg_init(void)
+{
+ int ret;
+
+ ret = register_rpmsg_driver(&gpio_rpmsg_driver);
+ if (ret)
+ return ret;
+
+ return platform_driver_register(&imx_rpmsg_gpio_driver);
+}
+device_initcall(gpio_imx_rpmsg_init);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("NXP i.MX7ULP rpmsg gpio driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index a9aaf9d822b4..f3a8fd3163e0 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -22,6 +22,7 @@
#include <linux/i2c.h>
#include <linux/i2c/max732x.h>
#include <linux/of.h>
+#include <linux/reset.h>
/*
@@ -643,6 +644,10 @@ static int max732x_probe(struct i2c_client *client,
return -ENOMEM;
chip->client = client;
+ ret = device_reset(&client->dev);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
nr_port = max732x_setup_gpio(chip, id, pdata->gpio_base);
chip->gpio_chip.parent = &client->dev;
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index c1a1e00b8cb0..22e114984e89 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -20,6 +20,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <linux/clk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -28,6 +29,7 @@
#include <linux/irqdomain.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/gpio/driver.h>
/* FIXME: for gpio_get_value() replace this with direct register read */
@@ -35,6 +37,10 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/bug.h>
+#ifdef CONFIG_GPIO_MXC_PAD_WAKEUP
+#include <soc/imx8/sc/sci.h>
+#include <soc/imx8/sc/svc/irq/api.h>
+#endif
enum mxc_gpio_hwtype {
IMX1_GPIO, /* runs on i.mx1 */
@@ -59,16 +65,36 @@ struct mxc_gpio_hwdata {
unsigned fall_edge;
};
+#ifdef CONFIG_GPIO_MXC_PAD_WAKEUP
+struct mxc_gpio_pad_wakeup {
+ u32 pin_id;
+ u32 type;
+ u32 line;
+};
+#endif
+
struct mxc_gpio_port {
struct list_head node;
+ struct clk *clk;
void __iomem *base;
int irq;
int irq_high;
struct irq_domain *domain;
struct gpio_chip gc;
u32 both_edges;
+ int saved_reg[6];
+ int suspend_saved_reg[6];
+ bool gpio_ranges;
+#ifdef CONFIG_GPIO_MXC_PAD_WAKEUP
+ u32 pad_wakeup_num;
+ struct mxc_gpio_pad_wakeup pad_wakeup[32];
+#endif
};
+#ifdef CONFIG_GPIO_MXC_PAD_WAKEUP
+static sc_ipc_t gpio_ipc_handle;
+#endif
+
static struct mxc_gpio_hwdata imx1_imx21_gpio_hwdata = {
.dr_reg = 0x1c,
.gdir_reg = 0x00,
@@ -310,6 +336,67 @@ static void mx2_gpio_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
+#ifdef CONFIG_GPIO_MXC_PAD_WAKEUP
+static int mxc_gpio_get_pad_wakeup(struct mxc_gpio_port *port)
+{
+ sc_err_t sciErr;
+ u8 wakeup_type;
+ int i;
+
+ for (i = 0; i < port->pad_wakeup_num; i++) {
+ /* get original pad type */
+ wakeup_type = port->pad_wakeup[i].type;
+ sciErr = sc_pad_get_wakeup(gpio_ipc_handle,
+ port->pad_wakeup[i].pin_id, &wakeup_type);
+ if (sciErr)
+ dev_err(port->gc.parent, "sc_pad_get_wakeup failed\n");
+ /* return wakeup gpio pin's line */
+ if (wakeup_type != port->pad_wakeup[i].type)
+ return port->pad_wakeup[i].line;
+ }
+
+ return -EINVAL;
+}
+
+static void mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable)
+{
+ sc_err_t sciErr;
+ int i;
+
+ for (i = 0; i < port->pad_wakeup_num; i++) {
+ sciErr = sc_pad_set_wakeup(gpio_ipc_handle,
+ port->pad_wakeup[i].pin_id,
+ enable ? port->pad_wakeup[i].type :
+ SC_PAD_WAKEUP_OFF);
+ if (sciErr)
+ dev_err(port->gc.parent, "sc_pad_set_wakeup failed\n");
+ }
+}
+
+static void mxc_gpio_handle_pad_wakeup(struct mxc_gpio_port *port, int line)
+{
+ struct irq_desc *desc = irq_to_desc(port->irq);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ u32 irq_stat;
+
+ /* skip invalid line */
+ if (line > 31) {
+ dev_err(port->gc.parent, "invalid wakeup line %d\n", line);
+ return;
+ }
+
+ dev_info(port->gc.parent, "wakeup by pad, line %d\n", line);
+
+ chained_irq_enter(chip, desc);
+
+ irq_stat = (1 << line);
+
+ mxc_gpio_irq_handler(port, irq_stat);
+
+ chained_irq_exit(chip, desc);
+}
+#endif
+
/*
* Set interrupt number "irq" in the GPIO as a wake-up source.
* While system is running, all registered GPIO interrupts need to have
@@ -340,7 +427,32 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable)
return 0;
}
-static int mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base)
+static int mxc_gpio_irq_reqres(struct irq_data *d)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct mxc_gpio_port *port = gc->private;
+
+ if (gpiochip_lock_as_irq(&port->gc, d->hwirq)) {
+ dev_err(port->gc.parent,
+ "unable to lock HW IRQ %lu for IRQ\n",
+ d->hwirq);
+ return -EINVAL;
+ }
+
+ return irq_chip_pm_get(d);
+}
+
+static void mxc_gpio_irq_relres(struct irq_data *d)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct mxc_gpio_port *port = gc->private;
+
+ gpiochip_unlock_as_irq(&port->gc, d->hwirq);
+ irq_chip_pm_put(d);
+}
+
+static int mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base,
+ struct device *dev)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
@@ -352,11 +464,14 @@ static int mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base)
gc->private = port;
ct = gc->chip_types;
+ ct->chip.parent_device = dev;
ct->chip.irq_ack = irq_gc_ack_set_bit;
ct->chip.irq_mask = irq_gc_mask_clr_bit;
ct->chip.irq_unmask = irq_gc_mask_set_bit;
ct->chip.irq_set_type = gpio_set_irq_type;
ct->chip.irq_set_wake = gpio_set_wake_irq;
+ ct->chip.irq_request_resources = mxc_gpio_irq_reqres;
+ ct->chip.irq_release_resources = mxc_gpio_irq_relres,
ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND;
ct->regs.ack = GPIO_ISR;
ct->regs.mask = GPIO_IMR;
@@ -404,13 +519,42 @@ static int mxc_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
return irq_find_mapping(port->domain, offset);
}
+static int mxc_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct mxc_gpio_port *port = gpiochip_get_data(chip);
+ int ret;
+
+ if (port->gpio_ranges) {
+ ret = gpiochip_generic_request(chip, offset);
+ if (ret)
+ return ret;
+ }
+
+ ret = pm_runtime_get_sync(chip->parent);
+ return ret < 0 ? ret : 0;
+}
+
+static void mxc_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct mxc_gpio_port *port = gpiochip_get_data(chip);
+
+ if (port->gpio_ranges)
+ gpiochip_generic_free(chip, offset);
+ pm_runtime_put(chip->parent);
+}
+
static int mxc_gpio_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct mxc_gpio_port *port;
struct resource *iores;
- int irq_base;
+ int irq_base = 0;
int err;
+#ifdef CONFIG_GPIO_MXC_PAD_WAKEUP
+ int i;
+ uint32_t mu_id;
+ sc_err_t sciErr;
+#endif
mxc_gpio_get_hw(pdev);
@@ -428,6 +572,58 @@ static int mxc_gpio_probe(struct platform_device *pdev)
if (port->irq < 0)
return port->irq;
+ /* the controller clock is optional */
+ port->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(port->clk))
+ port->clk = NULL;
+
+ err = clk_prepare_enable(port->clk);
+ if (err) {
+ dev_err(&pdev->dev, "Unable to enable clock.\n");
+ return err;
+ }
+
+#ifdef CONFIG_GPIO_MXC_PAD_WAKEUP
+ /*
+ * parse pad wakeup info from dtb, each pad has to provide
+ * <pin_id, type, line>, these info should be put in each
+ * gpio node and with a "pad-wakeup-num" to indicate the
+ * total lines are with pad wakeup enabled.
+ */
+ if (!of_property_read_u32(np, "pad-wakeup-num", &port->pad_wakeup_num)) {
+ if (port->pad_wakeup_num != 0) {
+ if (!gpio_ipc_handle) {
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ dev_err(&pdev->dev,
+ "can not obtain mu id: %d\n", sciErr);
+ return sciErr;
+ }
+ sciErr = sc_ipc_open(&gpio_ipc_handle, mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ dev_err(&pdev->dev,
+ "can not open mu channel to scu: %d\n", sciErr);
+ return sciErr;
+ }
+ }
+ for (i = 0; i < port->pad_wakeup_num; i++) {
+ of_property_read_u32_index(np, "pad-wakeup",
+ i * 3 + 0, &port->pad_wakeup[i].pin_id);
+ of_property_read_u32_index(np, "pad-wakeup",
+ i * 3 + 1, &port->pad_wakeup[i].type);
+ of_property_read_u32_index(np, "pad-wakeup",
+ i * 3 + 2, &port->pad_wakeup[i].line);
+ }
+ }
+ }
+#endif
+
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ err = pm_runtime_get_sync(&pdev->dev);
+ if (err < 0)
+ goto out_pm_dis;
+
/* disable the interrupt and clear the status */
writel(0, port->base + GPIO_IMR);
writel(~0, port->base + GPIO_ISR);
@@ -458,11 +654,14 @@ static int mxc_gpio_probe(struct platform_device *pdev)
if (err)
goto out_bgio;
- if (of_property_read_bool(np, "gpio-ranges")) {
- port->gc.request = gpiochip_generic_request;
- port->gc.free = gpiochip_generic_free;
- }
+ if (of_property_read_bool(np, "gpio_ranges"))
+ port->gpio_ranges = true;
+ else
+ port->gpio_ranges = false;
+ port->gc.request = mxc_gpio_request;
+ port->gc.free = mxc_gpio_free;
+ port->gc.parent = &pdev->dev;
port->gc.to_irq = mxc_gpio_to_irq;
port->gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 :
pdev->id * 32;
@@ -485,14 +684,20 @@ static int mxc_gpio_probe(struct platform_device *pdev)
}
/* gpio-mxc can be a generic irq chip */
- err = mxc_gpio_init_gc(port, irq_base);
+ err = mxc_gpio_init_gc(port, irq_base, &pdev->dev);
if (err < 0)
goto out_irqdomain_remove;
list_add_tail(&port->node, &mxc_gpio_ports);
+ platform_set_drvdata(pdev, port);
+ pm_runtime_put(&pdev->dev);
+
return 0;
+out_pm_dis:
+ pm_runtime_disable(&pdev->dev);
+ clk_disable_unprepare(port->clk);
out_irqdomain_remove:
irq_domain_remove(port->domain);
out_irqdesc_free:
@@ -502,9 +707,168 @@ out_bgio:
return err;
}
+static void mxc_gpio_save_regs(struct mxc_gpio_port *port)
+{
+ unsigned long flags;
+
+ if (mxc_gpio_hwtype == IMX21_GPIO)
+ return;
+
+ spin_lock_irqsave(&port->gc.bgpio_lock, flags);
+ port->saved_reg[0] = readl(port->base + GPIO_ICR1);
+ port->saved_reg[1] = readl(port->base + GPIO_ICR2);
+ port->saved_reg[2] = readl(port->base + GPIO_IMR);
+ port->saved_reg[3] = readl(port->base + GPIO_GDIR);
+ port->saved_reg[4] = readl(port->base + GPIO_EDGE_SEL);
+ port->saved_reg[5] = readl(port->base + GPIO_DR);
+ spin_unlock_irqrestore(&port->gc.bgpio_lock, flags);
+}
+
+static void mxc_gpio_restore_regs(struct mxc_gpio_port *port)
+{
+ unsigned long flags;
+
+ if (mxc_gpio_hwtype == IMX21_GPIO)
+ return;
+
+ spin_lock_irqsave(&port->gc.bgpio_lock, flags);
+ writel(port->saved_reg[0], port->base + GPIO_ICR1);
+ writel(port->saved_reg[1], port->base + GPIO_ICR2);
+ writel(port->saved_reg[2], port->base + GPIO_IMR);
+ writel(port->saved_reg[3], port->base + GPIO_GDIR);
+ writel(port->saved_reg[4], port->base + GPIO_EDGE_SEL);
+ writel(port->saved_reg[5], port->base + GPIO_DR);
+ spin_unlock_irqrestore(&port->gc.bgpio_lock, flags);
+}
+
+static int __maybe_unused mxc_gpio_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mxc_gpio_port *port = platform_get_drvdata(pdev);
+
+ mxc_gpio_save_regs(port);
+ clk_disable_unprepare(port->clk);
+
+ return 0;
+}
+
+static int __maybe_unused mxc_gpio_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mxc_gpio_port *port = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = clk_prepare_enable(port->clk);
+ if (ret)
+ return ret;
+
+ mxc_gpio_restore_regs(port);
+
+ return 0;
+}
+
+static int __maybe_unused mxc_gpio_noirq_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mxc_gpio_port *port = platform_get_drvdata(pdev);
+ unsigned long flags;
+ int ret;
+
+#ifdef CONFIG_GPIO_MXC_PAD_WAKEUP
+ mxc_gpio_set_pad_wakeup(port, true);
+#endif
+ if (mxc_gpio_hwtype == IMX21_GPIO)
+ return 0;
+
+ ret = clk_prepare_enable(port->clk);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&port->gc.bgpio_lock, flags);
+ port->suspend_saved_reg[0] = readl(port->base + GPIO_ICR1);
+ port->suspend_saved_reg[1] = readl(port->base + GPIO_ICR2);
+ port->suspend_saved_reg[2] = readl(port->base + GPIO_IMR);
+ port->suspend_saved_reg[3] = readl(port->base + GPIO_GDIR);
+ port->suspend_saved_reg[4] = readl(port->base + GPIO_EDGE_SEL);
+ port->suspend_saved_reg[5] = readl(port->base + GPIO_DR);
+ spin_unlock_irqrestore(&port->gc.bgpio_lock, flags);
+
+ clk_disable_unprepare(port->clk);
+
+ return 0;
+}
+
+static int __maybe_unused mxc_gpio_noirq_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mxc_gpio_port *port = platform_get_drvdata(pdev);
+ unsigned long flags;
+ int ret;
+#ifdef CONFIG_GPIO_MXC_PAD_WAKEUP
+ int wakeup_line = mxc_gpio_get_pad_wakeup(port);
+
+ mxc_gpio_set_pad_wakeup(port, false);
+#endif
+
+ if (mxc_gpio_hwtype == IMX21_GPIO)
+ return 0;
+
+ ret = clk_prepare_enable(port->clk);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&port->gc.bgpio_lock, flags);
+ writel(port->suspend_saved_reg[0], port->base + GPIO_ICR1);
+ writel(port->suspend_saved_reg[1], port->base + GPIO_ICR2);
+ writel(port->suspend_saved_reg[2], port->base + GPIO_IMR);
+ writel(port->suspend_saved_reg[3], port->base + GPIO_GDIR);
+ writel(port->suspend_saved_reg[4], port->base + GPIO_EDGE_SEL);
+ writel(port->suspend_saved_reg[5], port->base + GPIO_DR);
+#ifdef CONFIG_GPIO_MXC_PAD_WAKEUP
+ if (wakeup_line >= 0)
+ mxc_gpio_handle_pad_wakeup(port, wakeup_line);
+#endif
+ spin_unlock_irqrestore(&port->gc.bgpio_lock, flags);
+ clk_disable_unprepare(port->clk);
+
+ return 0;
+}
+
+static int __maybe_unused mxc_gpio_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int irq = platform_get_irq(pdev, 0);
+ struct irq_data *data = irq_get_irq_data(irq);
+
+ if (!irqd_is_wakeup_set(data))
+ return pm_runtime_force_suspend(dev);
+
+ return 0;
+}
+
+static int __maybe_unused mxc_gpio_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int irq = platform_get_irq(pdev, 0);
+ struct irq_data *data = irq_get_irq_data(irq);
+
+ if (!irqd_is_wakeup_set(data))
+ return pm_runtime_force_resume(dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops mxc_gpio_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mxc_gpio_suspend, mxc_gpio_resume)
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mxc_gpio_noirq_suspend, mxc_gpio_noirq_resume)
+ SET_RUNTIME_PM_OPS(mxc_gpio_runtime_suspend,
+ mxc_gpio_runtime_resume, NULL)
+};
+
static struct platform_driver mxc_gpio_driver = {
.driver = {
.name = "gpio-mxc",
+ .pm = &mxc_gpio_dev_pm_ops,
.of_match_table = mxc_gpio_dt_ids,
},
.probe = mxc_gpio_probe,
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index fe731f094257..f645dbd11e52 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -17,6 +17,7 @@
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/platform_data/pca953x.h>
+#include <linux/reset.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
#include <linux/of_platform.h>
@@ -813,6 +814,10 @@ static int pca953x_probe(struct i2c_client *client,
lockdep_set_subclass(&chip->i2c_lock,
i2c_adapter_depth(client->adapter));
+ ret = device_reset(&client->dev);
+ if (ret == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
/* initialize cached registers from their original values.
* we can't share this chip with another i2c master.
*/
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index 3edb09cb9ee0..0e3771f89040 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -16,6 +16,7 @@
*/
#include <linux/bitops.h>
+#include <linux/clk.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/init.h>
@@ -43,6 +44,7 @@ struct vf610_gpio_port {
#define GPIO_PCOR 0x08
#define GPIO_PTOR 0x0c
#define GPIO_PDIR 0x10
+#define GPIO_PDDR 0x14
#define PORT_PCR(n) ((n) * 0x4)
#define PORT_PCR_IRQC_OFFSET 16
@@ -79,8 +81,16 @@ static inline u32 vf610_gpio_readl(void __iomem *reg)
static int vf610_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct vf610_gpio_port *port = gpiochip_get_data(gc);
+ unsigned long mask = BIT(gpio);
+
+ mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
- return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDIR) & BIT(gpio));
+ if (mask)
+ return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDOR)
+ & BIT(gpio));
+ else
+ return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDIR)
+ & BIT(gpio));
}
static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
@@ -96,12 +106,24 @@ static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{
+ struct vf610_gpio_port *port = gpiochip_get_data(chip);
+ unsigned long mask = BIT(gpio);
+ u32 val;
+
+ val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
+ val &= ~mask;
+ vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR);
return pinctrl_gpio_direction_input(chip->base + gpio);
}
static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
int value)
{
+ struct vf610_gpio_port *port = gpiochip_get_data(chip);
+ unsigned long mask = BIT(gpio);
+
+ vf610_gpio_writel(mask, port->gpio_base + GPIO_PDDR);
+
vf610_gpio_set(chip, gpio, value);
return pinctrl_gpio_direction_output(chip->base + gpio);
@@ -218,6 +240,7 @@ static int vf610_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
+ struct clk *clk_port, *clk_gpio;
struct vf610_gpio_port *port;
struct resource *iores;
struct gpio_chip *gc;
@@ -241,6 +264,23 @@ static int vf610_gpio_probe(struct platform_device *pdev)
if (port->irq < 0)
return port->irq;
+ clk_port = devm_clk_get(&pdev->dev, "port");
+ clk_gpio = devm_clk_get(&pdev->dev, "gpio");
+ if (PTR_ERR(clk_port) == -EPROBE_DEFER ||
+ PTR_ERR(clk_gpio) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ if (!IS_ERR(clk_port) && !IS_ERR(clk_gpio)) {
+ ret = clk_prepare_enable(clk_port);
+ if (ret)
+ return ret;
+ ret = clk_prepare_enable(clk_gpio);
+ if (ret) {
+ clk_disable_unprepare(clk_port);
+ return ret;
+ }
+ }
+
gc = &port->gc;
gc->of_node = np;
gc->parent = dev;
@@ -262,6 +302,14 @@ static int vf610_gpio_probe(struct platform_device *pdev)
/* Clear the interrupt status register for all GPIO's */
vf610_gpio_writel(~0, port->base + PORT_ISFR);
+ /*
+ * At imx7ulp, any interrupts can wake system up from "standby" mode,
+ * so, mask interrupt at suspend mode by default, and the user
+ * can still enable wakeup through /sys entry.
+ */
+ if (of_machine_is_compatible("fsl,imx7ulp"))
+ vf610_gpio_irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND;
+
ret = gpiochip_irqchip_add(gc, &vf610_gpio_irq_chip, 0,
handle_edge_irq, IRQ_TYPE_NONE);
if (ret) {
diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile
index e9ed439a5b65..beaa25a03b9e 100644
--- a/drivers/gpu/Makefile
+++ b/drivers/gpu/Makefile
@@ -2,5 +2,5 @@
# taken to initialize them in the correct order. Link order is the only way
# to ensure this currently.
obj-$(CONFIG_TEGRA_HOST1X) += host1x/
+obj-y += imx/
obj-y += drm/ vga/
-obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 483059a22b1b..24a2f8050c66 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -160,6 +160,12 @@ config DRM_VGEM
as used by Mesa's software renderer for enhanced performance.
If M is selected the module will be called vgem.
+config DRM_VIVANTE
+ tristate "Vivante GCCore"
+ depends on DRM
+ help
+ Choose this option if you have a Vivante graphics card.
+ If M is selected, the module will be called vivante.
source "drivers/gpu/drm/exynos/Kconfig"
@@ -223,6 +229,8 @@ source "drivers/gpu/drm/hisilicon/Kconfig"
source "drivers/gpu/drm/mediatek/Kconfig"
+source "drivers/gpu/drm/mxsfb/Kconfig"
+
# Keep legacy drivers last
menuconfig DRM_LEGACY
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 25c720454017..44f73f692b5d 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -15,7 +15,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
drm_modeset_lock.o drm_atomic.o drm_bridge.o \
drm_framebuffer.o drm_connector.o drm_blend.o \
drm_encoder.o drm_mode_object.o drm_property.o \
- drm_plane.o drm_color_mgmt.o
+ drm_plane.o drm_color_mgmt.o drm_lease.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o
drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
@@ -27,7 +27,8 @@ drm-$(CONFIG_AGP) += drm_agpsupport.o
drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \
drm_kms_helper_common.o drm_dp_dual_mode_helper.o \
- drm_simple_kms_helper.o drm_modeset_helper.o
+ drm_simple_kms_helper.o drm_modeset_helper.o \
+ drm_scdc_helper.o
drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
@@ -42,6 +43,7 @@ obj-$(CONFIG_DRM) += drm.o
obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
obj-$(CONFIG_DRM_ARM) += arm/
obj-$(CONFIG_DRM_TTM) += ttm/
+obj-$(CONFIG_DRM_VIVANTE) += vivante/
obj-$(CONFIG_DRM_TDFX) += tdfx/
obj-$(CONFIG_DRM_R128) += r128/
obj-$(CONFIG_HSA_AMD) += amd/amdkfd/
@@ -77,12 +79,13 @@ obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio/
obj-$(CONFIG_DRM_MSM) += msm/
obj-$(CONFIG_DRM_TEGRA) += tegra/
obj-$(CONFIG_DRM_STI) += sti/
-obj-$(CONFIG_DRM_IMX) += imx/
obj-$(CONFIG_DRM_MEDIATEK) += mediatek/
obj-y += i2c/
obj-y += panel/
obj-y += bridge/
obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
+obj-$(CONFIG_DRM_IMX) += imx/
obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
obj-$(CONFIG_DRM_ARCPGU)+= arc/
obj-y += hisilicon/
+obj-$(CONFIG_DRM_MXSFB) += mxsfb/
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
index e9311eb7b8d9..22bdb8bd898e 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
@@ -224,7 +224,7 @@ amdgpu_connector_update_scratch_regs(struct drm_connector *connector,
if (connector->encoder_ids[i] == 0)
break;
- encoder = drm_encoder_find(connector->dev,
+ encoder = drm_encoder_find(connector->dev, NULL,
connector->encoder_ids[i]);
if (!encoder)
continue;
@@ -249,7 +249,7 @@ amdgpu_connector_find_encoder(struct drm_connector *connector,
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
if (connector->encoder_ids[i] == 0)
break;
- encoder = drm_encoder_find(connector->dev,
+ encoder = drm_encoder_find(connector->dev, NULL,
connector->encoder_ids[i]);
if (!encoder)
continue;
@@ -367,7 +367,7 @@ amdgpu_connector_best_single_encoder(struct drm_connector *connector)
/* pick the encoder ids */
if (enc_id)
- return drm_encoder_find(connector->dev, enc_id);
+ return drm_encoder_find(connector->dev, NULL, enc_id);
return NULL;
}
@@ -1084,7 +1084,7 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force)
if (connector->encoder_ids[i] == 0)
break;
- encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
+ encoder = drm_encoder_find(connector->dev, NULL, connector->encoder_ids[i]);
if (!encoder)
continue;
@@ -1143,7 +1143,7 @@ amdgpu_connector_dvi_encoder(struct drm_connector *connector)
if (connector->encoder_ids[i] == 0)
break;
- encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
+ encoder = drm_encoder_find(connector->dev, NULL, connector->encoder_ids[i]);
if (!encoder)
continue;
@@ -1162,7 +1162,7 @@ amdgpu_connector_dvi_encoder(struct drm_connector *connector)
/* then check use digitial */
/* pick the first one */
if (enc_id)
- return drm_encoder_find(connector->dev, enc_id);
+ return drm_encoder_find(connector->dev, NULL, enc_id);
return NULL;
}
@@ -1303,7 +1303,7 @@ u16 amdgpu_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *conn
if (connector->encoder_ids[i] == 0)
break;
- encoder = drm_encoder_find(connector->dev,
+ encoder = drm_encoder_find(connector->dev, NULL,
connector->encoder_ids[i]);
if (!encoder)
continue;
@@ -1332,7 +1332,7 @@ static bool amdgpu_connector_encoder_is_hbr2(struct drm_connector *connector)
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
if (connector->encoder_ids[i] == 0)
break;
- encoder = drm_encoder_find(connector->dev,
+ encoder = drm_encoder_find(connector->dev, NULL,
connector->encoder_ids[i]);
if (!encoder)
continue;
@@ -1538,7 +1538,7 @@ amdgpu_connector_virtual_encoder(struct drm_connector *connector)
if (connector->encoder_ids[i] == 0)
break;
- encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
+ encoder = drm_encoder_find(connector->dev, NULL, connector->encoder_ids[i]);
if (!encoder)
continue;
@@ -1548,7 +1548,7 @@ amdgpu_connector_virtual_encoder(struct drm_connector *connector)
/* pick the first one */
if (enc_id)
- return drm_encoder_find(connector->dev, enc_id);
+ return drm_encoder_find(connector->dev, NULL, enc_id);
return NULL;
}
diff --git a/drivers/gpu/drm/arc/arcpgu_crtc.c b/drivers/gpu/drm/arc/arcpgu_crtc.c
index 7130b044b004..1887bb271cd3 100644
--- a/drivers/gpu/drm/arc/arcpgu_crtc.c
+++ b/drivers/gpu/drm/arc/arcpgu_crtc.c
@@ -217,6 +217,7 @@ static struct drm_plane *arc_pgu_plane_init(struct drm_device *drm)
ret = drm_universal_plane_init(drm, plane, 0xff, &arc_pgu_plane_funcs,
formats, ARRAY_SIZE(formats),
+ NULL,
DRM_PLANE_TYPE_PRIMARY, NULL);
if (ret)
return ERR_PTR(ret);
diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c
index 28341b32067f..9da37d3a15c6 100644
--- a/drivers/gpu/drm/arm/hdlcd_crtc.c
+++ b/drivers/gpu/drm/arm/hdlcd_crtc.c
@@ -282,6 +282,7 @@ static struct drm_plane *hdlcd_plane_init(struct drm_device *drm)
ret = drm_universal_plane_init(drm, plane, 0xff, &hdlcd_plane_funcs,
formats, ARRAY_SIZE(formats),
+ NULL,
DRM_PLANE_TYPE_PRIMARY, NULL);
if (ret) {
devm_kfree(drm->dev, plane);
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index 8b009b549e45..1b0305a5eab2 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -246,7 +246,7 @@ int malidp_de_planes_init(struct drm_device *drm)
DRM_PLANE_TYPE_OVERLAY;
ret = drm_universal_plane_init(drm, &plane->base, crtcs,
&malidp_de_plane_funcs, formats,
- n, plane_type, NULL);
+ n, NULL, plane_type, NULL);
if (ret < 0)
goto cleanup;
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index 3137adf7b0af..d022c34fffbc 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -1210,6 +1210,7 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
&armada_primary_plane_funcs,
armada_primary_formats,
ARRAY_SIZE(armada_primary_formats),
+ NULL,
DRM_PLANE_TYPE_PRIMARY, NULL);
if (ret) {
kfree(primary);
diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c
index 6a9bba7206df..e111a11b0039 100644
--- a/drivers/gpu/drm/armada/armada_overlay.c
+++ b/drivers/gpu/drm/armada/armada_overlay.c
@@ -473,6 +473,7 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs)
&armada_ovl_plane_funcs,
armada_ovl_formats,
ARRAY_SIZE(armada_ovl_formats),
+ NULL,
DRM_PLANE_TYPE_OVERLAY, NULL);
if (ret) {
kfree(dplane);
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index 5957c3e659fe..f362cc459a37 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -690,7 +690,7 @@ static struct drm_encoder *ast_best_single_encoder(struct drm_connector *connect
int enc_id = connector->encoder_ids[0];
/* pick the encoder ids */
if (enc_id)
- return drm_encoder_find(connector->dev, enc_id);
+ return drm_encoder_find(connector->dev, NULL, enc_id);
return NULL;
}
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
index 9d4c030672f0..9c5907dfaeab 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -1028,7 +1028,8 @@ atmel_hlcdc_plane_create(struct drm_device *dev,
ret = drm_universal_plane_init(dev, &plane->base, 0,
&layer_plane_funcs,
desc->formats->formats,
- desc->formats->nformats, type, NULL);
+ desc->formats->nformats,
+ NULL, type, NULL);
if (ret)
return ERR_PTR(ret);
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 10e12e74fc9f..4cf570a994ee 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -39,6 +39,21 @@ config DRM_DW_HDMI_AHB_AUDIO
Designware HDMI block. This is used in conjunction with
the i.MX6 HDMI driver.
+config DRM_NWL_DSI
+ tristate
+ select DRM_KMS_HELPER
+ select DRM_MIPI_DSI
+ select DRM_PANEL
+
+config DRM_SEC_MIPI_DSIM
+ tristate "Samsung MIPI DSIM Bridge"
+ depends on OF
+ select DRM_KMS_HELPER
+ select DRM_MIPI_DSI
+ select DRM_PANEL
+ help
+ The Samsung MPI DSIM Bridge driver.
+
config DRM_NXP_PTN3460
tristate "NXP PTN3460 DP/LVDS bridge"
depends on OF
@@ -78,4 +93,12 @@ source "drivers/gpu/drm/bridge/analogix/Kconfig"
source "drivers/gpu/drm/bridge/adv7511/Kconfig"
+config DRM_ITE_IT6263
+ tristate "ITE IT6263 LVDS/HDMI bridge"
+ depends on OF
+ select DRM_KMS_HELPER
+ select REGMAP_I2C
+ ---help---
+ ITE IT6263 bridge chip driver.
+
endmenu
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index cdf3a3cf765d..8fa239e5f41a 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -4,9 +4,12 @@ obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o
obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
+obj-$(CONFIG_DRM_NWL_DSI) += nwl-dsi.o
+obj-$(CONFIG_DRM_SEC_MIPI_DSIM) += sec-dsim.o
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
obj-$(CONFIG_DRM_SII902X) += sii902x.o
obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o
obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/
obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/
+obj-$(CONFIG_DRM_ITE_IT6263) += it6263.o
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
index 3e74e1a6584c..27a5f026aada 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
@@ -294,6 +294,7 @@ struct adv7511_video_config {
enum adv7511_type {
ADV7511,
ADV7533,
+ ADV7535,
};
struct adv7511 {
@@ -301,6 +302,10 @@ struct adv7511 {
struct i2c_client *i2c_edid;
struct i2c_client *i2c_cec;
+ u32 addr_cec;
+ u32 addr_edid;
+ u32 addr_pkt;
+
struct regmap *regmap;
struct regmap *regmap_cec;
enum drm_connector_status status;
@@ -333,6 +338,7 @@ struct adv7511 {
struct device_node *host_node;
struct mipi_dsi_device *dsi;
u8 num_dsi_lanes;
+ u8 channel_id;
bool use_timing_gen;
enum adv7511_type type;
@@ -342,6 +348,7 @@ struct adv7511 {
void adv7533_dsi_power_on(struct adv7511 *adv);
void adv7533_dsi_power_off(struct adv7511 *adv);
void adv7533_mode_set(struct adv7511 *adv, struct drm_display_mode *mode);
+bool adv7533_mode_fixup(struct adv7511 *adv, struct drm_display_mode *mode);
int adv7533_patch_registers(struct adv7511 *adv);
void adv7533_uninit_cec(struct adv7511 *adv);
int adv7533_init_cec(struct adv7511 *adv);
@@ -362,6 +369,12 @@ static inline void adv7533_mode_set(struct adv7511 *adv,
{
}
+static inline bool adv7533_mode_fixup(struct adv7511 *adv,
+ struct drm_display_mode *mode)
+{
+ return true;
+}
+
static inline int adv7533_patch_registers(struct adv7511 *adv)
{
return -ENODEV;
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 32ab5c32834b..f2348b79b56f 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -9,7 +9,9 @@
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/of_graph.h>
#include <linux/slab.h>
#include <drm/drmP.h>
@@ -365,7 +367,7 @@ static void adv7511_power_on(struct adv7511 *adv7511)
*/
regcache_sync(adv7511->regmap);
- if (adv7511->type == ADV7533)
+ if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
adv7533_dsi_power_on(adv7511);
adv7511->powered = true;
}
@@ -382,7 +384,7 @@ static void __adv7511_power_off(struct adv7511 *adv7511)
static void adv7511_power_off(struct adv7511 *adv7511)
{
__adv7511_power_off(adv7511);
- if (adv7511->type == ADV7533)
+ if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
adv7533_dsi_power_off(adv7511);
adv7511->powered = false;
}
@@ -583,6 +585,8 @@ static int adv7511_get_modes(struct adv7511 *adv7511,
{
struct edid *edid;
unsigned int count;
+ u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+ int ret;
/* Reading the EDID only works if the device is powered */
if (!adv7511->powered) {
@@ -611,6 +615,14 @@ static int adv7511_get_modes(struct adv7511 *adv7511,
adv7511_set_config_csc(adv7511, connector, adv7511->rgb);
+ connector->display_info.bus_flags = DRM_BUS_FLAG_DE_LOW |
+ DRM_BUS_FLAG_PIXDATA_NEGEDGE;
+
+ ret = drm_display_info_set_bus_formats(&connector->display_info,
+ &bus_format, 1);
+ if (ret)
+ return ret;
+
return count;
}
@@ -735,21 +747,26 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
vsync_polarity = 1;
}
- if (mode->vrefresh <= 24000)
+ if (mode->vrefresh <= 24)
low_refresh_rate = ADV7511_LOW_REFRESH_RATE_24HZ;
- else if (mode->vrefresh <= 25000)
+ else if (mode->vrefresh <= 25)
low_refresh_rate = ADV7511_LOW_REFRESH_RATE_25HZ;
- else if (mode->vrefresh <= 30000)
+ else if (mode->vrefresh <= 30)
low_refresh_rate = ADV7511_LOW_REFRESH_RATE_30HZ;
else
low_refresh_rate = ADV7511_LOW_REFRESH_RATE_NONE;
- regmap_update_bits(adv7511->regmap, 0xfb,
- 0x6, low_refresh_rate << 1);
+ if (adv7511->type == ADV7535)
+ regmap_update_bits(adv7511->regmap, 0x4a,
+ 0xc, low_refresh_rate << 2);
+ else
+ regmap_update_bits(adv7511->regmap, 0xfb,
+ 0x6, low_refresh_rate << 1);
+
regmap_update_bits(adv7511->regmap, 0x17,
0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
- if (adv7511->type == ADV7533)
+ if (adv7511->type == ADV7533 || adv7511->type == ADV7535)
adv7533_mode_set(adv7511, adj_mode);
drm_mode_copy(&adv7511->curr_mode, adj_mode);
@@ -836,6 +853,18 @@ static void adv7511_bridge_mode_set(struct drm_bridge *bridge,
adv7511_mode_set(adv, mode, adj_mode);
}
+static bool adv7511_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct adv7511 *adv = bridge_to_adv7511(bridge);
+
+ if (adv->type == ADV7533 || adv->type == ADV7535)
+ return adv7533_mode_fixup(adv, adjusted_mode);
+
+ return true;
+}
+
static int adv7511_bridge_attach(struct drm_bridge *bridge)
{
struct adv7511 *adv = bridge_to_adv7511(bridge);
@@ -859,7 +888,7 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge)
&adv7511_connector_helper_funcs);
drm_mode_connector_attach_encoder(&adv->connector, bridge->encoder);
- if (adv->type == ADV7533)
+ if (adv->type == ADV7533 || adv->type == ADV7535)
ret = adv7533_attach_dsi(adv);
return ret;
@@ -869,6 +898,7 @@ static struct drm_bridge_funcs adv7511_bridge_funcs = {
.enable = adv7511_bridge_enable,
.disable = adv7511_bridge_disable,
.mode_set = adv7511_bridge_mode_set,
+ .mode_fixup = adv7511_bridge_mode_fixup,
.attach = adv7511_bridge_attach,
};
@@ -964,8 +994,15 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
struct adv7511_link_config link_config;
struct adv7511 *adv7511;
struct device *dev = &i2c->dev;
+#if IS_ENABLED(CONFIG_OF_DYNAMIC)
+ struct device_node *remote_node = NULL, *endpoint = NULL;
+ struct of_changeset ocs;
+ struct property *prop;
+#endif
unsigned int main_i2c_addr = i2c->addr << 1;
unsigned int edid_i2c_addr = main_i2c_addr + 4;
+ unsigned int cec_i2c_addr = main_i2c_addr - 2;
+ unsigned int pkt_i2c_addr = main_i2c_addr - 0xa;
unsigned int val;
int ret;
@@ -993,6 +1030,21 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
if (ret)
return ret;
+ if (adv7511->addr_cec != 0)
+ cec_i2c_addr = adv7511->addr_cec << 1;
+ else
+ adv7511->addr_cec = cec_i2c_addr >> 1;
+
+ if (adv7511->addr_edid != 0)
+ edid_i2c_addr = adv7511->addr_edid << 1;
+ else
+ adv7511->addr_edid = edid_i2c_addr >> 1;
+
+ if (adv7511->addr_pkt != 0)
+ pkt_i2c_addr = adv7511->addr_pkt << 1;
+ else
+ adv7511->addr_pkt = pkt_i2c_addr >> 1;
+
/*
* The power down GPIO is optional. If present, toggle it from active to
* inactive to wake up the encoder.
@@ -1007,12 +1059,14 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
}
adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config);
- if (IS_ERR(adv7511->regmap))
- return PTR_ERR(adv7511->regmap);
+ if (IS_ERR(adv7511->regmap)) {
+ ret = PTR_ERR(adv7511->regmap);
+ goto of_reconfig;
+ }
ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val);
if (ret)
- return ret;
+ goto of_reconfig;
dev_dbg(dev, "Rev. %d\n", val);
if (adv7511->type == ADV7511)
@@ -1024,11 +1078,12 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
if (ret)
return ret;
- regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr);
+ regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR,
+ edid_i2c_addr);
regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR,
- main_i2c_addr - 0xa);
+ pkt_i2c_addr);
regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR,
- main_i2c_addr - 2);
+ cec_i2c_addr);
adv7511_packet_disable(adv7511, 0xffff);
@@ -1037,7 +1092,7 @@ static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
if (!adv7511->i2c_edid)
return -ENOMEM;
- if (adv7511->type == ADV7533) {
+ if (adv7511->type == ADV7533 || adv7511->type == ADV7535) {
ret = adv7533_init_cec(adv7511);
if (ret)
goto err_i2c_unregister_edid;
@@ -1082,6 +1137,45 @@ err_unregister_cec:
adv7533_uninit_cec(adv7511);
err_i2c_unregister_edid:
i2c_unregister_device(adv7511->i2c_edid);
+of_reconfig:
+#if IS_ENABLED(CONFIG_OF_DYNAMIC)
+ endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+ if (endpoint)
+ remote_node = of_graph_get_remote_port_parent(endpoint);
+
+ if (remote_node) {
+ int num_endpoints = 0;
+
+ /*
+ * Remote node should have two endpoints (input and output: us)
+ * If remote node has more than two endpoints, probably that it
+ * has more outputs, so there is no need to disable it.
+ */
+ endpoint = NULL;
+ while ((endpoint = of_graph_get_next_endpoint(remote_node,
+ endpoint)))
+ num_endpoints++;
+
+ if (num_endpoints > 2) {
+ of_node_put(remote_node);
+ return ret;
+ }
+
+ prop = devm_kzalloc(dev, sizeof(*prop), GFP_KERNEL);
+ prop->name = devm_kstrdup(dev, "status", GFP_KERNEL);
+ prop->value = devm_kstrdup(dev, "disabled", GFP_KERNEL);
+ prop->length = 9;
+ of_changeset_init(&ocs);
+ of_changeset_update_property(&ocs, remote_node, prop);
+ ret = of_changeset_apply(&ocs);
+ if (!ret)
+ dev_warn(dev,
+ "Probe failed. Remote port '%s' disabled\n",
+ remote_node->full_name);
+
+ of_node_put(remote_node);
+ };
+#endif
return ret;
}
@@ -1090,16 +1184,17 @@ static int adv7511_remove(struct i2c_client *i2c)
{
struct adv7511 *adv7511 = i2c_get_clientdata(i2c);
- if (adv7511->type == ADV7533) {
+ if (adv7511->type == ADV7533 || adv7511->type == ADV7535) {
adv7533_detach_dsi(adv7511);
adv7533_uninit_cec(adv7511);
}
drm_bridge_remove(&adv7511->bridge);
- i2c_unregister_device(adv7511->i2c_edid);
-
- kfree(adv7511->edid);
+ if (adv7511->i2c_edid) {
+ i2c_unregister_device(adv7511->i2c_edid);
+ kfree(adv7511->edid);
+ }
return 0;
}
@@ -1110,6 +1205,7 @@ static const struct i2c_device_id adv7511_i2c_ids[] = {
{ "adv7513", ADV7511 },
#ifdef CONFIG_DRM_I2C_ADV7533
{ "adv7533", ADV7533 },
+ { "adv7535", ADV7535 },
#endif
{ }
};
@@ -1121,6 +1217,7 @@ static const struct of_device_id adv7511_of_ids[] = {
{ .compatible = "adi,adv7513", .data = (void *)ADV7511 },
#ifdef CONFIG_DRM_I2C_ADV7533
{ .compatible = "adi,adv7533", .data = (void *)ADV7533 },
+ { .compatible = "adi,adv7535", .data = (void *)ADV7535 },
#endif
{ }
};
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c
index d7f7b7ce8ebe..6a7dd000aeee 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7533.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c
@@ -117,11 +117,16 @@ void adv7533_dsi_power_off(struct adv7511 *adv)
void adv7533_mode_set(struct adv7511 *adv, struct drm_display_mode *mode)
{
+}
+
+bool adv7533_mode_fixup(struct adv7511 *adv,
+ struct drm_display_mode *mode)
+{
struct mipi_dsi_device *dsi = adv->dsi;
int lanes, ret;
if (adv->num_dsi_lanes != 4)
- return;
+ return true;
if (mode->clock > 80000)
lanes = 4;
@@ -130,11 +135,16 @@ void adv7533_mode_set(struct adv7511 *adv, struct drm_display_mode *mode)
if (lanes != dsi->lanes) {
mipi_dsi_detach(dsi);
- dsi->lanes = lanes;
+ swap(dsi->lanes, lanes);
ret = mipi_dsi_attach(dsi);
- if (ret)
+ if (ret) {
dev_err(&dsi->dev, "failed to change host lanes\n");
+ swap(dsi->lanes, lanes);
+ return false;
+ }
}
+
+ return true;
}
int adv7533_patch_registers(struct adv7511 *adv)
@@ -154,7 +164,7 @@ int adv7533_init_cec(struct adv7511 *adv)
int ret;
adv->i2c_cec = i2c_new_dummy(adv->i2c_main->adapter,
- adv->i2c_main->addr - 1);
+ adv->addr_cec);
if (!adv->i2c_cec)
return -ENOMEM;
@@ -184,7 +194,7 @@ int adv7533_attach_dsi(struct adv7511 *adv)
struct mipi_dsi_device *dsi;
int ret = 0;
const struct mipi_dsi_device_info info = { .type = "adv7533",
- .channel = 0,
+ .channel = adv->channel_id,
.node = NULL,
};
@@ -230,15 +240,25 @@ void adv7533_detach_dsi(struct adv7511 *adv)
int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
{
- u32 num_lanes;
+ struct device *dev = &adv->i2c_main->dev;
+ u32 num_lanes = 0, channel_id = 0;
struct device_node *endpoint;
+ of_property_read_u32(np, "adi,dsi-channel", &channel_id);
of_property_read_u32(np, "adi,dsi-lanes", &num_lanes);
- if (num_lanes < 1 || num_lanes > 4)
+ if (num_lanes < 1 || num_lanes > 4) {
+ dev_err(dev, "Invalid dsi-lanes: %d\n", num_lanes);
return -EINVAL;
+ }
+
+ if (channel_id > 3) {
+ dev_err(dev, "Invalid dsi-channel: %d\n", channel_id);
+ return -EINVAL;
+ }
adv->num_dsi_lanes = num_lanes;
+ adv->channel_id = channel_id;
endpoint = of_graph_get_next_endpoint(np, NULL);
if (!endpoint)
@@ -256,6 +276,10 @@ int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
adv->use_timing_gen = !of_property_read_bool(np,
"adi,disable-timing-generator");
+ of_property_read_u32(np, "adi,addr-cec", &adv->addr_cec);
+ of_property_read_u32(np, "adi,addr-edid", &adv->addr_edid);
+ of_property_read_u32(np, "adi,addr-pkt", &adv->addr_pkt);
+
/* TODO: Check if these need to be parsed by DT or not */
adv->rgb = true;
adv->embedded_sync = false;
diff --git a/drivers/gpu/drm/bridge/it6263.c b/drivers/gpu/drm/bridge/it6263.c
new file mode 100644
index 000000000000..169a9cfd18c1
--- /dev/null
+++ b/drivers/gpu/drm/bridge/it6263.c
@@ -0,0 +1,1007 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/regmap.h>
+
+#define REG_VENDOR_ID(n) (0x00 + (n)) /* n: 0/1 */
+#define REG_DEVICE_ID(n) (0x02 + (n)) /* n: 0/1 */
+#define LVDS_VENDER_ID_LOW 0x15
+#define LVDS_VENDER_ID_HIGH 0xCA
+#define LVDS_DEVICE_ID_LOW 0x61
+#define LVDS_DEVICE_ID_HIGH 0x62
+#define HDMI_VENDER_ID_LOW 0x01
+#define HDMI_VENDER_ID_HIGH 0xCA
+#define HDMI_DEVICE_ID_LOW 0x13
+#define HDMI_DEVICE_ID_HIGH 0x76
+
+/* LVDS registers */
+#define LVDS_REG_SW_RST 0x05
+#define SOFT_REFCLK_DM_RST BIT(0)
+#define SOFT_PCLK_DM_RST BIT(1)
+
+#define LVDS_REG_MODE 0x2C
+#define LVDS_COLOR_DEPTH 0x3
+enum {
+ LVDS_COLOR_DEPTH_18,
+ LVDS_COLOR_DEPTH_24,
+ LVDS_COLOR_DEPTH_30,
+ LVDS_COLOR_DEPTH_36,
+};
+#define LVDS_OUT_MAP BIT(4)
+#define VESA BIT(4)
+#define JEIDA 0
+#define DMODE BIT(7)
+#define SPLIT_MODE BIT(7)
+#define SINGLE_MODE 0
+
+#define LVDS_REG_STABLE 0x30
+#define VIDEO_STABLE BIT(0)
+#define PCLK_LOCK BIT(1)
+
+#define LVDS_REG_39 0x39
+
+#define LVDS_REG_PLL 0x3C
+#define LVDS_REG_AFE_3E 0x3E
+#define LVDS_REG_AFE_3F 0x3F
+#define LVDS_REG_AFE_47 0x47
+#define LVDS_REG_AFE_48 0x48
+#define LVDS_REG_AFE_4F 0x4F
+#define LVDS_REG_52 0x52
+#define LVDS_REG_PCLK_CNT_HIGH 0x57
+#define LVDS_REG_PCLK_CNT_LOW 0x58
+
+/*
+ * HDMI registers
+ *
+ * Registers are separated into three banks:
+ * 1) common bank: 0x00 ~ 0x2F
+ * 2) bank0: 0x30 ~ 0xFF
+ * 3) bank1: 0x130 ~ 0x1FF (HDMI packet registers)
+ *
+ * Use register HDMI_REG_BANK_CTRL @ 0x0F[1:0] to select bank0/1:
+ * 2b'00 - bank0
+ * 2b'01 - bank1
+ */
+
+/******************************/
+/* HDMI register common bank */
+/******************************/
+
+/* HDMI genernal registers */
+#define HDMI_REG_SW_RST 0x04
+#define SOFTREF_RST BIT(5)
+#define SOFTA_RST BIT(4)
+#define SOFTV_RST BIT(3)
+#define AUD_RST BIT(2)
+#define HDCP_RST BIT(0)
+#define HDMI_RST_ALL (SOFTREF_RST | SOFTA_RST | SOFTV_RST | \
+ AUD_RST | HDCP_RST)
+
+#define HDMI_REG_INT_CTRL 0x05
+#define INTPOL_ACTH BIT(7)
+#define INTPOL_ACTL 0
+#define INTIOMODE_OPENDRAIN BIT(6)
+#define INTIOMODE_PUSHPULL 0
+#define SELXTAL BIT(5) /* REFCLK <= XTALCLK */
+#define SELXTAL_QUARTER 0 /* REFCLK <= OSCCLK/4 */
+#define PDREFCNT(n) (((n) >> 2) << 2) /* REFCLK Div(n) */
+#define PDREFCLK BIT(1)
+#define PDTXCLK_GATED BIT(0)
+#define PDTXCLK_ACTIVE 0
+
+#define HDMI_REG_INT_STAT(n) (0x05 + (n)) /* n: 1/2/3 */
+#define HDMI_REG_INT_MASK(n) (0x08 + (n)) /* n: 1/2/3 */
+
+/* INT1 */
+#define INT_AUD_OVERFLOW BIT(7)
+#define INT_RDDC_NOACK BIT(5)
+#define INT_DDCFIFO_ERR BIT(4)
+#define INT_DDC_BUS_HANG BIT(2)
+#define INT_RX_SENSE BIT(1)
+#define INT_HPD BIT(0)
+
+/* INT2 */
+#define INT_VID_UNSTABLE BIT(6)
+#define INT_PKTACP BIT(5)
+#define INT_PKTNULL BIT(4)
+#define INT_PKTGEN BIT(3)
+#define INT_KSVLIST_CHK BIT(2)
+#define INT_AUTH_DONE BIT(1)
+#define INT_AUTH_FAIL BIT(0)
+
+/* INT3 */
+#define INT_AUD_CTS BIT(6)
+#define INT_VSYNC BIT(5)
+#define INT_VIDSTABLE BIT(4)
+#define INT_PKTMPG BIT(3)
+#define INT_PKTGBD BIT(2)
+#define INT_PKTAUD BIT(1)
+#define INT_PKTAVI BIT(0)
+
+#define INT_MASK_AUD_CTS BIT(5)
+#define INT_MASK_VSYNC BIT(4)
+#define INT_MASK_VIDSTABLE BIT(3)
+#define INT_MASK_PKTMPG BIT(2)
+#define INT_MASK_PKTGBD BIT(1)
+#define INT_MASK_PKTAUD BIT(0)
+
+#define HDMI_REG_INT_CLR(n) (0x0C + (n)) /* n: 0/1 */
+
+/* CLR0 */
+#define INT_CLR_PKTACP BIT(7)
+#define INT_CLR_PKTNULL BIT(6)
+#define INT_CLR_PKTGEN BIT(5)
+#define INT_CLR_KSVLIST_CHK BIT(4)
+#define INT_CLR_AUTH_DONE BIT(3)
+#define INT_CLR_AUTH_FAIL BIT(2)
+#define INT_CLR_RXSENSE BIT(1)
+#define INT_CLR_HPD BIT(0)
+
+/* CLR1 */
+#define INT_CLR_VSYNC BIT(7)
+#define INT_CLR_VIDSTABLE BIT(6)
+#define INT_CLR_PKTMPG BIT(5)
+#define INT_CLR_PKTGBD BIT(4)
+#define INT_CLR_PKTAUD BIT(3)
+#define INT_CLR_PKTAVI BIT(2)
+#define INT_CLR_VID_UNSTABLE BIT(0)
+
+#define HDMI_REG_SYS_STATUS 0x0E
+#define INT_ACTIVE BIT(7)
+#define HPDETECT BIT(6)
+#define RXSENDETECT BIT(5)
+#define TXVIDSTABLE BIT(4)
+#define CTSINTSTEP 0xC
+#define CLR_AUD_CTS BIT(1)
+#define INTACTDONE BIT(0)
+
+#define HDMI_REG_BANK_CTRL 0x0F
+#define BANK_SEL(n) ((n) ? 1 : 0)
+
+/* HDMI System DDC control registers */
+#define HDMI_REG_DDC_MASTER_CTRL 0x10
+#define MASTER_SEL_HOST BIT(0)
+#define MASTER_SEL_HDCP 0
+
+#define HDMI_REG_DDC_HEADER 0x11
+#define DDC_HDCP_ADDRESS 0x74
+
+#define HDMI_REG_DDC_REQOFF 0x12
+#define HDMI_REG_DDC_REQCOUNT 0x13
+#define HDMI_REG_DDC_EDIDSEG 0x14
+
+#define HDMI_REG_DDC_CMD 0x15
+#define DDC_CMD_SEQ_BURSTREAD 0x0
+#define DDC_CMD_LINK_CHKREAD 0x2
+#define DDC_CMD_EDID_READ 0x3
+#define DDC_CMD_FIFO_CLR 0x9
+#define DDC_CMD_GEN_SCLCLK 0xA
+#define DDC_CMD_ABORT 0xF
+
+#define HDMI_REG_DDC_STATUS 0x16
+#define DDC_DONE BIT(7)
+#define DDC_ACT BIT(6)
+#define DDC_NOACK BIT(5)
+#define DDC_WAITBUS BIT(4)
+#define DDC_ARBILOSE BIT(3)
+#define DDC_ERROR (DDC_NOACK | DDC_WAITBUS | DDC_ARBILOSE)
+#define DDC_FIFOFULL BIT(2)
+#define DDC_FIFOEMPTY BIT(1)
+
+#define HDMI_DDC_FIFO_SIZE 32 /* bytes */
+#define HDMI_REG_DDC_READFIFO 0x17
+#define HDMI_REG_ROM_STAT 0x1C
+#define HDMI_REG_LVDS_PORT 0x1D /* LVDS input ctrl i2c addr */
+#define HDMI_REG_LVDS_PORT_EN 0x1E /* and to enable */
+#define LVDS_INPUT_CTRL_I2C_ADDR 0x33
+
+/***********************/
+/* HDMI register bank0 */
+/***********************/
+
+/* HDMI clock control registers */
+#define HDMI_REG_CLK_CTRL1 0x59
+#define EN_TXCLK_COUNT BIT(5)
+#define VDO_LATCH_EDGE BIT(3)
+
+/* HDMI AFE registers */
+#define HDMI_REG_AFE_DRV_CTRL 0x61
+#define AFE_DRV_PWD BIT(5)
+#define AFE_DRV_RST BIT(4)
+#define AFE_DRV_PDRXDET BIT(2)
+#define AFE_DRV_TERMON BIT(1)
+#define AFE_DRV_ENCAL BIT(0)
+
+#define HDMI_REG_AFE_XP_CTRL 0x62
+#define AFE_XP_GAINBIT BIT(7)
+#define AFE_XP_PWDPLL BIT(6)
+#define AFE_XP_ENI BIT(5)
+#define AFE_XP_ER0 BIT(4)
+#define AFE_XP_RESETB BIT(3)
+#define AFE_XP_PWDI BIT(2)
+#define AFE_XP_DEI BIT(1)
+#define AFE_XP_DER BIT(0)
+
+#define HDMI_REG_AFE_ISW_CTRL 0x63
+#define AFE_RTERM_SEL BIT(7)
+#define AFE_IP_BYPASS BIT(6)
+#define AFE_DRV_ISW 0x38
+#define AFE_DRV_ISWK 7
+
+#define HDMI_REG_AFE_IP_CTRL 0x64
+#define AFE_IP_GAINBIT BIT(7)
+#define AFE_IP_PWDPLL BIT(6)
+#define AFE_IP_CKSEL 0x30
+#define AFE_IP_ER0 BIT(3)
+#define AFE_IP_RESETB BIT(2)
+#define AFE_IP_ENC BIT(1)
+#define AFE_IP_EC1 BIT(0)
+
+/* HDMI input data format registers */
+#define HDMI_REG_INPUT_MODE 0x70
+#define IN_RGB 0x00
+#define IN_YUV422 0x40
+#define IN_YUV444 0x80
+
+#define HDMI_REG_TXFIFO_RST 0x71
+#define ENAVMUTERST BIT(0)
+#define TXFFRST BIT(1)
+
+/* HDMI pattern generation SYNC/DE registers */
+#define HDMI_REG_9X(n) (0x90 + (n)) /* n: 0x0 ~ 0xF */
+#define HDMI_REG_AX(n) (0xA0 + (n)) /* n: 0x0 ~ 0xF */
+#define HDMI_REG_B0 0xB0
+
+/* HDMI general control registers */
+#define HDMI_REG_HDMI_MODE 0xC0
+#define TX_HDMI_MODE 1
+#define TX_DVI_MODE 0
+
+#define HDMI_REG_GCP 0xC1
+#define AVMUTE BIT(0)
+#define BLUE_SCR_MUTE BIT(1)
+#define NODEF_PHASE BIT(2)
+#define PHASE_RESYNC BIT(3)
+#define HDMI_COLOR_DEPTH 0x70
+enum {
+ HDMI_COLOR_DEPTH_DEF = 0x0, /* default as 24bit */
+ HDMI_COLOR_DEPTH_24 = 0x40,
+ HDMI_COLOR_DEPTH_30 = 0x50,
+ HDMI_COLOR_DEPTH_36 = 0x60,
+ HDMI_COLOR_DEPTH_48 = 0x70,
+};
+
+#define HDMI_REG_OESS_CYCLE 0xC3
+#define HDMI_REG_ENCRYPTION 0xC4 /* HDCP */
+
+#define HDMI_REG_PKT_SINGLE_CTRL 0xC5
+#define SINGLE_PKT BIT(0)
+#define BURST_PKT 0
+
+#define HDMI_REG_PKT_GENERAL_CTRL 0xC6
+#define HDMI_REG_NULL_CTRL 0xC9
+#define HDMI_REG_ACP_CTRL 0xCA
+#define HDMI_REG_ISRC1_CTRL 0xCB
+#define HDMI_REG_ISRC2_CTRL 0xCC
+#define HDMI_REG_AVI_INFOFRM_CTRL 0xCD
+#define HDMI_REG_AUD_INFOFRM_CTRL 0xCE
+#define HDMI_REG_SPD_INFOFRM_CTRL 0xCF
+#define HDMI_REG_MPG_INFOFRM_CTRL 0xD0
+#define ENABLE_PKT BIT(0)
+#define REPEAT_PKT BIT(1)
+
+/***********************/
+/* HDMI register bank1 */
+/***********************/
+
+/* AVI packet registers */
+#define HDMI_REG_AVI_DB1 0x58
+#define AVI_DB1_COLOR_SPACE 0x60
+enum {
+ AVI_COLOR_SPACE_RGB = 0x00,
+ AVI_COLOR_SPACE_YUV422 = 0x20,
+ AVI_COLOR_SPACE_YUV444 = 0x40,
+};
+
+struct it6263 {
+ struct i2c_client *hdmi_i2c;
+ struct i2c_client *lvds_i2c;
+ struct regmap *hdmi_regmap;
+ struct regmap *lvds_regmap;
+ struct drm_bridge bridge;
+ struct drm_connector connector;
+ struct gpio_desc *reset_gpio;
+ bool is_hdmi;
+ bool split_mode;
+};
+
+struct it6263_minimode {
+ int hdisplay;
+ int vdisplay;
+ int vrefresh;
+};
+
+static const struct it6263_minimode it6263_bad_mode_db[] = {
+ {1600, 900, 60},
+ {1280, 1024, 60},
+ {1280, 720, 30},
+ {1280, 720, 25},
+ {1280, 720, 24},
+ {1152, 864, 75},
+};
+
+static inline struct it6263 *bridge_to_it6263(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct it6263, bridge);
+}
+
+static inline struct it6263 *connector_to_it6263(struct drm_connector *con)
+{
+ return container_of(con, struct it6263, connector);
+}
+
+static inline void lvds_update_bits(struct it6263 *it6263, unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+ regmap_update_bits(it6263->lvds_regmap, reg, mask, val);
+}
+
+static inline void hdmi_update_bits(struct it6263 *it6263, unsigned int reg,
+ unsigned int mask, unsigned int val)
+{
+ regmap_update_bits(it6263->hdmi_regmap, reg, mask, val);
+}
+
+static void it6263_reset(struct it6263 *it6263)
+{
+ if (!it6263->reset_gpio)
+ return;
+
+ gpiod_set_value_cansleep(it6263->reset_gpio, 0);
+
+ usleep_range(1000, 2000);
+
+ gpiod_set_value_cansleep(it6263->reset_gpio, 1);
+
+ /*
+ * The chip maker says the low pulse should be at least 40ms,
+ * so 41ms is sure to be enough.
+ */
+ usleep_range(41000, 45000);
+
+ gpiod_set_value_cansleep(it6263->reset_gpio, 0);
+
+ /* somehow, addtional time to wait the high voltage to be stable */
+ usleep_range(5000, 6000);
+}
+
+static enum drm_connector_status
+it6263_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct it6263 *it6263 = connector_to_it6263(connector);
+ unsigned int status;
+ int i;
+
+ /*
+ * FIXME: We read status tens of times to workaround
+ * cable detection failure issue at boot time on some
+ * platforms.
+ * Spin on this for up to one second.
+ */
+ for (i = 0; i < 100; i++) {
+ regmap_read(it6263->hdmi_regmap, HDMI_REG_SYS_STATUS, &status);
+ if (status & HPDETECT)
+ return connector_status_connected;
+ usleep_range(5000, 10000);
+ }
+
+ return connector_status_disconnected;
+}
+
+static const struct drm_connector_funcs it6263_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .detect = it6263_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = drm_connector_cleanup,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int
+it6263_read_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+ struct it6263 *it6263 = data;
+ struct regmap *regmap = it6263->hdmi_regmap;
+ unsigned long timeout;
+ unsigned int status, count, val;
+ unsigned int segment = block >> 1;
+ unsigned int start = (block % 2) * EDID_LENGTH;
+
+ regmap_write(regmap, HDMI_REG_DDC_MASTER_CTRL, MASTER_SEL_HOST);
+ regmap_write(regmap, HDMI_REG_DDC_HEADER, DDC_ADDR << 1);
+ regmap_write(regmap, HDMI_REG_DDC_EDIDSEG, segment);
+
+ while (len) {
+ /* clear DDC FIFO */
+ regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_FIFO_CLR);
+
+ timeout = jiffies + msecs_to_jiffies(10);
+ do {
+ regmap_read(regmap, HDMI_REG_DDC_STATUS, &status);
+ } while (!(status & DDC_DONE) && time_before(jiffies, timeout));
+
+ if (!(status & DDC_DONE)) {
+ dev_err(&it6263->hdmi_i2c->dev,
+ "failed to clear DDC FIFO\n");
+ return -ETIMEDOUT;
+ }
+
+ count = len > HDMI_DDC_FIFO_SIZE ? HDMI_DDC_FIFO_SIZE : len;
+
+ /* fire the read command */
+ regmap_write(regmap, HDMI_REG_DDC_REQOFF, start);
+ regmap_write(regmap, HDMI_REG_DDC_REQCOUNT, count);
+ regmap_write(regmap, HDMI_REG_DDC_CMD, DDC_CMD_EDID_READ);
+
+ start += count;
+ len -= count;
+
+ /* wait for reading done */
+ timeout = jiffies + msecs_to_jiffies(250);
+ do {
+ regmap_read(regmap, HDMI_REG_DDC_STATUS, &status);
+ if (status & DDC_ERROR) {
+ dev_err(&it6263->hdmi_i2c->dev, "DDC error\n");
+ return -EIO;
+ }
+ } while (!(status & DDC_DONE) && time_before(jiffies, timeout));
+
+ if (!(status & DDC_DONE)) {
+ dev_err(&it6263->hdmi_i2c->dev,
+ "failed to read EDID\n");
+ return -ETIMEDOUT;
+ }
+
+ /* cache to buffer */
+ for (; count > 0; count--) {
+ regmap_read(regmap, HDMI_REG_DDC_READFIFO, &val);
+ *(buf++) = val;
+ }
+ }
+
+ return 0;
+}
+
+static int it6263_get_modes(struct drm_connector *connector)
+{
+ struct it6263 *it6263 = connector_to_it6263(connector);
+ struct regmap *regmap = it6263->hdmi_regmap;
+ u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+ struct edid *edid;
+ int num = 0;
+ int ret;
+
+ regmap_write(regmap, HDMI_REG_DDC_MASTER_CTRL, MASTER_SEL_HOST);
+
+ edid = drm_do_get_edid(connector, it6263_read_edid, it6263);
+ drm_mode_connector_update_edid_property(connector, edid);
+ if (edid) {
+ num = drm_add_edid_modes(connector, edid);
+ it6263->is_hdmi = drm_detect_hdmi_monitor(edid);
+ kfree(edid);
+ }
+
+ ret = drm_display_info_set_bus_formats(&connector->display_info,
+ &bus_format, 1);
+ if (ret)
+ return ret;
+
+ return num;
+}
+
+enum drm_mode_status it6263_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ const struct it6263_minimode *m;
+ int i, vrefresh = drm_mode_vrefresh(mode);
+
+ if (mode->clock > 150000)
+ return MODE_CLOCK_HIGH;
+
+ for (i = 0; i < ARRAY_SIZE(it6263_bad_mode_db); i++) {
+ m = &it6263_bad_mode_db[i];
+ if ((mode->hdisplay == m->hdisplay) &&
+ (mode->vdisplay == m->vdisplay) &&
+ (vrefresh == m->vrefresh))
+ return MODE_BAD;
+ }
+
+ return MODE_OK;
+}
+
+static const struct drm_connector_helper_funcs it6263_connector_helper_funcs = {
+ .get_modes = it6263_get_modes,
+ .mode_valid = it6263_mode_valid,
+};
+
+static void it6263_bridge_disable(struct drm_bridge *bridge)
+{
+ struct it6263 *it6263 = bridge_to_it6263(bridge);
+ struct regmap *regmap = it6263->hdmi_regmap;
+
+ /* AV mute */
+ hdmi_update_bits(it6263, HDMI_REG_GCP, AVMUTE, AVMUTE);
+
+ if (it6263->is_hdmi)
+ regmap_write(regmap, HDMI_REG_PKT_GENERAL_CTRL, 0);
+
+ hdmi_update_bits(it6263, HDMI_REG_SW_RST, SOFTV_RST, SOFTV_RST);
+ regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, AFE_DRV_RST | AFE_DRV_PWD);
+}
+
+static void it6263_bridge_enable(struct drm_bridge *bridge)
+{
+ struct it6263 *it6263 = bridge_to_it6263(bridge);
+ struct regmap *regmap = it6263->hdmi_regmap;
+ unsigned long timeout;
+ unsigned int status;
+
+ regmap_write(it6263->hdmi_regmap, HDMI_REG_BANK_CTRL, BANK_SEL(1));
+ /* set the color space to RGB in the AVI packet */
+ hdmi_update_bits(it6263, HDMI_REG_AVI_DB1, AVI_DB1_COLOR_SPACE,
+ AVI_COLOR_SPACE_RGB);
+ regmap_write(it6263->hdmi_regmap, HDMI_REG_BANK_CTRL, BANK_SEL(0));
+
+ /* software video reset */
+ hdmi_update_bits(it6263, HDMI_REG_SW_RST, SOFTV_RST, SOFTV_RST);
+ usleep_range(1000, 2000);
+ hdmi_update_bits(it6263, HDMI_REG_SW_RST, SOFTV_RST, 0);
+
+ timeout = jiffies + msecs_to_jiffies(500);
+ do {
+ regmap_read(regmap, HDMI_REG_SYS_STATUS, &status);
+ } while (!(status & TXVIDSTABLE) && time_before(jiffies, timeout));
+
+ if (!(status & TXVIDSTABLE))
+ dev_warn(&it6263->hdmi_i2c->dev,
+ "failed to wait for video stable\n");
+
+ regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, 0);
+
+ /* AV unmute */
+ hdmi_update_bits(it6263, HDMI_REG_GCP, AVMUTE, 0);
+
+ if (it6263->is_hdmi)
+ regmap_write(regmap, HDMI_REG_PKT_GENERAL_CTRL,
+ ENABLE_PKT | REPEAT_PKT);
+}
+
+static void it6263_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adj)
+{
+ struct it6263 *it6263 = bridge_to_it6263(bridge);
+ struct regmap *regmap = it6263->hdmi_regmap;
+ bool pclk_high = adj->clock > 80000 ? true : false;
+
+ regmap_write(regmap, HDMI_REG_HDMI_MODE,
+ it6263->is_hdmi ? TX_HDMI_MODE : TX_DVI_MODE);
+
+ dev_dbg(&it6263->hdmi_i2c->dev, "%s mode\n",
+ it6263->is_hdmi ? "HDMI" : "DVI");
+
+ /* setup AFE */
+ regmap_write(regmap, HDMI_REG_AFE_DRV_CTRL, AFE_DRV_RST);
+ if (pclk_high)
+ regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
+ AFE_XP_GAINBIT | AFE_XP_RESETB);
+ else
+ regmap_write(regmap, HDMI_REG_AFE_XP_CTRL,
+ AFE_XP_ER0 | AFE_XP_RESETB);
+ regmap_write(regmap, HDMI_REG_AFE_ISW_CTRL, 0x10);
+ if (pclk_high)
+ regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
+ AFE_IP_GAINBIT | AFE_IP_RESETB);
+ else
+ regmap_write(regmap, HDMI_REG_AFE_IP_CTRL,
+ AFE_IP_ER0 | AFE_IP_RESETB);
+}
+
+static int it6263_bridge_attach(struct drm_bridge *bridge)
+{
+ struct it6263 *it6263 = bridge_to_it6263(bridge);
+ struct drm_device *drm = bridge->dev;
+ int ret;
+
+ if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) {
+ dev_err(&it6263->hdmi_i2c->dev,
+ "it6263 driver only copes with atomic updates\n");
+ return -ENOTSUPP;
+ }
+
+ it6263->connector.polled = DRM_CONNECTOR_POLL_CONNECT |
+ DRM_CONNECTOR_POLL_DISCONNECT;
+ ret = drm_connector_init(drm, &it6263->connector,
+ &it6263_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+ if (ret) {
+ dev_err(&it6263->hdmi_i2c->dev,
+ "Failed to initialize connector with drm\n");
+ return ret;
+ }
+
+ drm_connector_helper_add(&it6263->connector,
+ &it6263_connector_helper_funcs);
+ drm_mode_connector_attach_encoder(&it6263->connector, bridge->encoder);
+
+ return ret;
+}
+
+static const struct drm_bridge_funcs it6263_bridge_funcs = {
+ .attach = it6263_bridge_attach,
+ .mode_set = it6263_bridge_mode_set,
+ .disable = it6263_bridge_disable,
+ .enable = it6263_bridge_enable,
+};
+
+static int it6263_check_chipid(struct it6263 *it6263)
+{
+ struct device *dev = &it6263->hdmi_i2c->dev;
+ u8 vendor_id[2], device_id[2];
+ int ret;
+
+ ret = regmap_bulk_read(it6263->hdmi_regmap, REG_VENDOR_ID(0),
+ &vendor_id, 2);
+ if (ret) {
+ dev_err(dev, "regmap_bulk_read failed %d\n", ret);
+ return ret;
+ }
+
+ if (vendor_id[0] != HDMI_VENDER_ID_LOW ||
+ vendor_id[1] != HDMI_VENDER_ID_HIGH) {
+ dev_err(dev,
+ "Invalid hdmi vendor id %02x %02x(expect 0x01 0xca)\n",
+ vendor_id[0], vendor_id[1]);
+ return -EINVAL;
+ }
+
+ ret = regmap_bulk_read(it6263->hdmi_regmap, REG_DEVICE_ID(0),
+ &device_id, 2);
+ if (ret) {
+ dev_err(dev, "regmap_bulk_read failed %d\n", ret);
+ return ret;
+ }
+
+ if (device_id[0] != HDMI_DEVICE_ID_LOW ||
+ device_id[1] != HDMI_DEVICE_ID_HIGH) {
+ dev_err(dev,
+ "Invalid hdmi device id %02x %02x(expect 0x13 0x76)\n",
+ device_id[0], device_id[1]);
+ return -EINVAL;
+ }
+
+ ret = regmap_bulk_read(it6263->lvds_regmap, REG_VENDOR_ID(0),
+ &vendor_id, 2);
+ if (ret) {
+ dev_err(dev, "regmap_bulk_read failed %d\n", ret);
+ return ret;
+ }
+
+ if (vendor_id[0] != LVDS_VENDER_ID_LOW ||
+ vendor_id[1] != LVDS_VENDER_ID_HIGH) {
+ dev_err(dev,
+ "Invalid lvds vendor id %02x %02x(expect 0x15 0xca)\n",
+ vendor_id[0], vendor_id[1]);
+ return -EINVAL;
+ }
+
+ ret = regmap_bulk_read(it6263->lvds_regmap, REG_DEVICE_ID(0),
+ &device_id, 2);
+ if (ret) {
+ dev_err(dev, "regmap_bulk_read failed %d\n", ret);
+ return ret;
+ }
+
+ if (device_id[0] != LVDS_DEVICE_ID_LOW ||
+ device_id[1] != LVDS_DEVICE_ID_HIGH) {
+ dev_err(dev,
+ "Invalid lvds device id %02x %02x(expect 0x61 0x62)\n",
+ device_id[0], device_id[1]);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static void it6263_lvds_reset(struct it6263 *it6263)
+{
+ /* AFE PLL reset */
+ lvds_update_bits(it6263, LVDS_REG_PLL, 0x1, 0x0);
+ usleep_range(1000, 2000);
+ lvds_update_bits(it6263, LVDS_REG_PLL, 0x1, 0x1);
+
+ /* pclk reset */
+ lvds_update_bits(it6263, LVDS_REG_SW_RST,
+ SOFT_PCLK_DM_RST, SOFT_PCLK_DM_RST);
+ usleep_range(1000, 2000);
+ lvds_update_bits(it6263, LVDS_REG_SW_RST, SOFT_PCLK_DM_RST, 0x0);
+
+ usleep_range(1000, 2000);
+}
+
+static void it6263_lvds_set_interface(struct it6263 *it6263)
+{
+ /* color depth */
+ lvds_update_bits(it6263, LVDS_REG_MODE, LVDS_COLOR_DEPTH,
+ LVDS_COLOR_DEPTH_24);
+
+ /* jeida mapping */
+ lvds_update_bits(it6263, LVDS_REG_MODE, LVDS_OUT_MAP, JEIDA);
+
+ if (it6263->split_mode) {
+ lvds_update_bits(it6263, LVDS_REG_MODE, DMODE, SPLIT_MODE);
+ lvds_update_bits(it6263, LVDS_REG_52, BIT(1), BIT(1));
+ } else {
+ lvds_update_bits(it6263, LVDS_REG_MODE, DMODE, SINGLE_MODE);
+ lvds_update_bits(it6263, LVDS_REG_52, BIT(1), 0);
+ }
+}
+
+static void it6263_lvds_set_afe(struct it6263 *it6263)
+{
+ struct regmap *regmap = it6263->lvds_regmap;
+
+ regmap_write(regmap, LVDS_REG_AFE_3E, 0xaa);
+ regmap_write(regmap, LVDS_REG_AFE_3F, 0x02);
+ regmap_write(regmap, LVDS_REG_AFE_47, 0xaa);
+ regmap_write(regmap, LVDS_REG_AFE_48, 0x02);
+ regmap_write(regmap, LVDS_REG_AFE_4F, 0x11);
+
+ lvds_update_bits(it6263, LVDS_REG_PLL, 0x07, 0);
+}
+
+static void it6263_hdmi_config(struct it6263 *it6263)
+{
+ regmap_write(it6263->hdmi_regmap, HDMI_REG_INPUT_MODE, IN_RGB);
+
+ hdmi_update_bits(it6263, HDMI_REG_GCP, HDMI_COLOR_DEPTH,
+ HDMI_COLOR_DEPTH_24);
+}
+
+static const struct regmap_range it6263_hdmi_volatile_ranges[] = {
+ { .range_min = 0, .range_max = 0x1ff },
+};
+
+static const struct regmap_access_table it6263_hdmi_volatile_table = {
+ .yes_ranges = it6263_hdmi_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(it6263_hdmi_volatile_ranges),
+};
+
+static const struct regmap_config it6263_hdmi_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &it6263_hdmi_volatile_table,
+ .cache_type = REGCACHE_NONE,
+};
+
+static const struct regmap_range it6263_lvds_volatile_ranges[] = {
+ { .range_min = 0, .range_max = 0xff },
+};
+
+static const struct regmap_access_table it6263_lvds_volatile_table = {
+ .yes_ranges = it6263_lvds_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(it6263_lvds_volatile_ranges),
+};
+
+static const struct regmap_config it6263_lvds_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &it6263_lvds_volatile_table,
+ .cache_type = REGCACHE_NONE,
+};
+
+static const struct i2c_board_info it6263_lvds_i2c = {
+ I2C_BOARD_INFO("it6263_LVDS_i2c", LVDS_INPUT_CTRL_I2C_ADDR),
+};
+
+static int it6263_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct device_node *np = dev->of_node;
+#if IS_ENABLED(CONFIG_OF_DYNAMIC)
+ struct device_node *remote_node = NULL, *endpoint = NULL;
+ struct of_changeset ocs;
+ struct property *prop;
+#endif
+ struct it6263 *it6263;
+ int ret;
+
+ it6263 = devm_kzalloc(dev, sizeof(*it6263), GFP_KERNEL);
+ if (!it6263)
+ return -ENOMEM;
+
+ it6263->split_mode = of_property_read_bool(np, "split-mode");
+
+ it6263->hdmi_i2c = client;
+ it6263->lvds_i2c = i2c_new_device(client->adapter, &it6263_lvds_i2c);
+ if (!it6263->lvds_i2c) {
+ ret = -ENODEV;
+ goto of_reconfig;
+ }
+
+ it6263->hdmi_regmap = devm_regmap_init_i2c(client,
+ &it6263_hdmi_regmap_config);
+ if (IS_ERR(it6263->hdmi_regmap)) {
+ ret = PTR_ERR(it6263->hdmi_regmap);
+ goto unregister_lvds_i2c;
+ }
+
+ it6263->lvds_regmap = devm_regmap_init_i2c(it6263->lvds_i2c,
+ &it6263_lvds_regmap_config);
+ if (IS_ERR(it6263->lvds_regmap)) {
+ ret = PTR_ERR(it6263->lvds_regmap);
+ goto unregister_lvds_i2c;
+ }
+
+ it6263->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(it6263->reset_gpio)) {
+ ret = PTR_ERR(it6263->reset_gpio);
+
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get reset gpio: %d\n", ret);
+
+ goto unregister_lvds_i2c;
+ }
+
+ it6263_reset(it6263);
+
+ ret = regmap_write(it6263->hdmi_regmap, HDMI_REG_SW_RST, HDMI_RST_ALL);
+ if (ret)
+ goto unregister_lvds_i2c;
+
+ usleep_range(1000, 2000);
+
+ ret = regmap_write(it6263->hdmi_regmap, HDMI_REG_LVDS_PORT,
+ LVDS_INPUT_CTRL_I2C_ADDR << 1);
+ if (ret)
+ goto unregister_lvds_i2c;
+
+ ret = regmap_write(it6263->hdmi_regmap, HDMI_REG_LVDS_PORT_EN, 0x01);
+ if (ret)
+ goto unregister_lvds_i2c;
+
+ /* select HDMI bank0 */
+ ret = regmap_write(it6263->hdmi_regmap, HDMI_REG_BANK_CTRL,
+ BANK_SEL(0));
+ if (ret)
+ goto unregister_lvds_i2c;
+
+ ret = it6263_check_chipid(it6263);
+ if (ret)
+ goto unregister_lvds_i2c;
+
+ it6263_lvds_reset(it6263);
+ it6263_lvds_set_interface(it6263);
+ it6263_lvds_set_afe(it6263);
+ it6263_hdmi_config(it6263);
+
+ it6263->bridge.funcs = &it6263_bridge_funcs;
+ it6263->bridge.of_node = np;
+ ret = drm_bridge_add(&it6263->bridge);
+ if (ret) {
+ dev_err(dev, "Failed to add drm_bridge\n");
+ return ret;
+ }
+
+ i2c_set_clientdata(client, it6263);
+
+ return ret;
+
+unregister_lvds_i2c:
+ i2c_unregister_device(it6263->lvds_i2c);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+of_reconfig:
+#if IS_ENABLED(CONFIG_OF_DYNAMIC)
+ endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+ if (endpoint)
+ remote_node = of_graph_get_remote_port_parent(endpoint);
+
+ if (remote_node) {
+ int num_endpoints = 0;
+
+ /*
+ * Remote node should have two endpoints (input and output: us)
+ * If remote node has more than two endpoints, probably that it
+ * has more outputs, so there is no need to disable it.
+ */
+ endpoint = NULL;
+ while ((endpoint = of_graph_get_next_endpoint(remote_node,
+ endpoint)))
+ num_endpoints++;
+
+ if (num_endpoints > 2) {
+ of_node_put(remote_node);
+ return ret;
+ }
+
+ prop = devm_kzalloc(dev, sizeof(*prop), GFP_KERNEL);
+ prop->name = devm_kstrdup(dev, "status", GFP_KERNEL);
+ prop->value = devm_kstrdup(dev, "disabled", GFP_KERNEL);
+ prop->length = 9;
+ of_changeset_init(&ocs);
+ of_changeset_update_property(&ocs, remote_node, prop);
+ ret = of_changeset_apply(&ocs);
+ if (!ret)
+ dev_warn(dev,
+ "Probe failed. Remote port '%s' disabled\n",
+ remote_node->full_name);
+
+ of_node_put(remote_node);
+ };
+#endif
+
+ return ret;
+}
+
+static int it6263_remove(struct i2c_client *client)
+
+{
+ struct it6263 *it6263 = i2c_get_clientdata(client);
+
+ drm_bridge_remove(&it6263->bridge);
+ i2c_unregister_device(it6263->lvds_i2c);
+
+ return 0;
+}
+
+static const struct of_device_id it6263_dt_ids[] = {
+ { .compatible = "ite,it6263", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, it6263_dt_ids);
+
+static const struct i2c_device_id it6263_i2c_ids[] = {
+ { "it6263", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, it6263_i2c_ids);
+
+static struct i2c_driver it6263_driver = {
+ .probe = it6263_probe,
+ .remove = it6263_remove,
+ .driver = {
+ .name = "it6263",
+ .of_match_table = it6263_dt_ids,
+ },
+ .id_table = it6263_i2c_ids,
+};
+module_i2c_driver(it6263_driver);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("ITE Tech. Inc. IT6263 LVDS->HDMI bridge");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c
new file mode 100644
index 000000000000..396f669ca41f
--- /dev/null
+++ b/drivers/gpu/drm/bridge/nwl-dsi.c
@@ -0,0 +1,1294 @@
+/*
+ * NWL DSI drm driver - Northwest Logic MIPI DSI bridge
+ *
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/unaligned.h>
+#include <drm/bridge/nwl_dsi.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/spinlock.h>
+#include <video/mipi_display.h>
+#include <video/videomode.h>
+
+#define MIPI_FIFO_TIMEOUT msecs_to_jiffies(500)
+
+/* DSI HOST registers */
+#define CFG_NUM_LANES 0x0
+#define CFG_NONCONTINUOUS_CLK 0x4
+#define CFG_T_PRE 0x8
+#define CFG_T_POST 0xc
+#define CFG_TX_GAP 0x10
+#define CFG_AUTOINSERT_EOTP 0x14
+#define CFG_EXTRA_CMDS_AFTER_EOTP 0x18
+#define CFG_HTX_TO_COUNT 0x1c
+#define CFG_LRX_H_TO_COUNT 0x20
+#define CFG_BTA_H_TO_COUNT 0x24
+#define CFG_TWAKEUP 0x28
+#define CFG_STATUS_OUT 0x2c
+#define RX_ERROR_STATUS 0x30
+
+/* DSI DPI registers */
+#define PIXEL_PAYLOAD_SIZE 0x200
+#define PIXEL_FIFO_SEND_LEVEL 0x204
+#define INTERFACE_COLOR_CODING 0x208
+#define PIXEL_FORMAT 0x20c
+#define VSYNC_POLARITY 0x210
+#define HSYNC_POLARITY 0x214
+#define VIDEO_MODE 0x218
+#define HFP 0x21c
+#define HBP 0x220
+#define HSA 0x224
+#define ENABLE_MULT_PKTS 0x228
+#define VBP 0x22c
+#define VFP 0x230
+#define BLLP_MODE 0x234
+#define USE_NULL_PKT_BLLP 0x238
+#define VACTIVE 0x23c
+#define VC 0x240
+
+/* DSI APB PKT control */
+#define TX_PAYLOAD 0x280
+#define PKT_CONTROL 0x284
+#define SEND_PACKET 0x288
+#define PKT_STATUS 0x28c
+#define PKT_FIFO_WR_LEVEL 0x290
+#define PKT_FIFO_RD_LEVEL 0x294
+#define RX_PAYLOAD 0x298
+#define RX_PKT_HEADER 0x29c
+
+/* PKT reg bit manipulation */
+#define REG_MASK(e, s) (((1 << ((e) - (s) + 1)) - 1) << (s))
+#define REG_PUT(x, e, s) (((x) << (s)) & REG_MASK(e, s))
+#define REG_GET(x, e, s) (((x) & REG_MASK(e, s)) >> (s))
+
+/*
+ * PKT_CONTROL format:
+ * [15: 0] - word count
+ * [17:16] - virtual channel
+ * [23:18] - data type
+ * [24] - LP or HS select (0 - LP, 1 - HS)
+ * [25] - perform BTA after packet is sent
+ * [26] - perform BTA only, no packet tx
+ */
+#define WC(x) REG_PUT((x), 15, 0)
+#define TX_VC(x) REG_PUT((x), 17, 16)
+#define TX_DT(x) REG_PUT((x), 23, 18)
+#define HS_SEL(x) REG_PUT((x), 24, 24)
+#define BTA_TX(x) REG_PUT((x), 25, 25)
+#define BTA_NO_TX(x) REG_PUT((x), 26, 26)
+
+/*
+ * RX_PKT_HEADER format:
+ * [15: 0] - word count
+ * [21:16] - data type
+ * [23:22] - virtual channel
+ */
+#define RX_DT(x) REG_GET((x), 21, 16)
+#define RX_VC(x) REG_GET((x), 23, 22)
+
+/* DSI IRQ handling */
+#define IRQ_STATUS 0x2a0
+#define SM_NOT_IDLE BIT(0)
+#define TX_PKT_DONE BIT(1)
+#define DPHY_DIRECTION BIT(2)
+#define TX_FIFO_OVFLW BIT(3)
+#define TX_FIFO_UDFLW BIT(4)
+#define RX_FIFO_OVFLW BIT(5)
+#define RX_FIFO_UDFLW BIT(6)
+#define RX_PKT_HDR_RCVD BIT(7)
+#define RX_PKT_PAYLOAD_DATA_RCVD BIT(8)
+#define BTA_TIMEOUT BIT(29)
+#define LP_RX_TIMEOUT BIT(30)
+#define HS_TX_TIMEOUT BIT(31)
+
+#define IRQ_STATUS2 0x2a4
+#define SINGLE_BIT_ECC_ERR BIT(0)
+#define MULTI_BIT_ECC_ERR BIT(1)
+#define CRC_ERR BIT(2)
+
+#define IRQ_MASK 0x2a8
+#define SM_NOT_IDLE_MASK BIT(0)
+#define TX_PKT_DONE_MASK BIT(1)
+#define DPHY_DIRECTION_MASK BIT(2)
+#define TX_FIFO_OVFLW_MASK BIT(3)
+#define TX_FIFO_UDFLW_MASK BIT(4)
+#define RX_FIFO_OVFLW_MASK BIT(5)
+#define RX_FIFO_UDFLW_MASK BIT(6)
+#define RX_PKT_HDR_RCVD_MASK BIT(7)
+#define RX_PKT_PAYLOAD_DATA_RCVD_MASK BIT(8)
+#define BTA_TIMEOUT_MASK BIT(29)
+#define LP_RX_TIMEOUT_MASK BIT(30)
+#define HS_TX_TIMEOUT_MASK BIT(31)
+
+#define IRQ_MASK2 0x2ac
+#define SINGLE_BIT_ECC_ERR_MASK BIT(0)
+#define MULTI_BIT_ECC_ERR_MASK BIT(1)
+#define CRC_ERR_MASK BIT(2)
+
+static const char IRQ_NAME[] = "nwl-dsi";
+
+enum {
+ CLK_PHY_REF = BIT(1),
+ CLK_RX_ESC = BIT(2),
+ CLK_TX_ESC = BIT(3)
+};
+
+enum transfer_direction {
+ DSI_PACKET_SEND,
+ DSI_PACKET_RECEIVE
+};
+
+struct mipi_dsi_transfer {
+ const struct mipi_dsi_msg *msg;
+ struct mipi_dsi_packet packet;
+ struct completion completed;
+
+ int status; /* status of transmission */
+ enum transfer_direction direction;
+ bool need_bta;
+ u8 cmd;
+ u16 rx_word_count;
+ size_t tx_len; /* bytes sent */
+ size_t rx_len; /* bytes received */
+};
+
+struct clk_config {
+ struct clk *clk;
+ unsigned long rate;
+ bool enabled;
+};
+
+struct nwl_mipi_dsi {
+ struct device *dev;
+ struct drm_panel *panel;
+ struct drm_bridge *next_bridge;
+ struct drm_bridge bridge;
+ struct drm_connector connector;
+ struct mipi_dsi_host host;
+ struct mipi_dsi_device *dsi_device;
+
+ struct phy *phy;
+
+ /* Mandatory clocks */
+ struct clk_config phy_ref;
+ struct clk_config rx_esc;
+ struct clk_config tx_esc;
+
+ void __iomem *base;
+ int irq;
+ enum mipi_dsi_pixel_format format;
+ struct videomode vm;
+
+ struct mipi_dsi_transfer *xfer;
+
+ u32 lanes;
+ u32 vc;
+ unsigned long dsi_mode_flags;
+ bool no_clk_reset;
+ bool enabled;
+};
+
+static inline void nwl_dsi_write(struct nwl_mipi_dsi *dsi, u32 reg, u32 val)
+{
+ writel(val, dsi->base + reg);
+}
+
+static inline u32 nwl_dsi_read(struct nwl_mipi_dsi *dsi, u32 reg)
+{
+ return readl(dsi->base + reg);
+}
+
+static enum mipi_dsi_pixel_format mipi_dsi_format_from_bus_format(
+ u32 bus_format)
+{
+ switch (bus_format) {
+ case MEDIA_BUS_FMT_RGB565_1X16:
+ return MIPI_DSI_FMT_RGB565;
+ case MEDIA_BUS_FMT_RGB666_1X18:
+ return MIPI_DSI_FMT_RGB666;
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ return MIPI_DSI_FMT_RGB888;
+ default:
+ return MIPI_DSI_FMT_RGB888;
+ }
+}
+
+static enum dpi_interface_color_coding nwl_dsi_get_dpi_interface_color_coding(
+ enum mipi_dsi_pixel_format format)
+{
+ switch (format) {
+ case MIPI_DSI_FMT_RGB565:
+ return DPI_16_BIT_565_PACKED;
+ case MIPI_DSI_FMT_RGB666:
+ return DPI_18_BIT_ALIGNED;
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ return DPI_18_BIT_PACKED;
+ case MIPI_DSI_FMT_RGB888:
+ return DPI_24_BIT;
+ default:
+ return DPI_24_BIT;
+ }
+}
+
+static enum dpi_pixel_format nwl_dsi_get_dpi_pixel_format(
+ enum mipi_dsi_pixel_format format)
+{
+ switch (format) {
+ case MIPI_DSI_FMT_RGB565:
+ return DPI_FMT_16_BIT;
+ case MIPI_DSI_FMT_RGB666:
+ return DPI_FMT_18_BIT;
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ return DPI_FMT_18_BIT_LOOSELY_PACKED;
+ case MIPI_DSI_FMT_RGB888:
+ return DPI_FMT_24_BIT;
+ default:
+ return DPI_FMT_24_BIT;
+ }
+}
+
+/* Adds a bridge to encoder bridge chain */
+bool nwl_dsi_add_bridge(struct drm_encoder *encoder,
+ struct drm_bridge *next_bridge)
+{
+ struct drm_bridge *bridge = encoder->bridge;
+
+ if (!next_bridge)
+ return false;
+
+ next_bridge->encoder = encoder;
+ if (!bridge) {
+ encoder->bridge = bridge;
+ return true;
+ }
+
+ while (bridge != next_bridge && bridge->next)
+ bridge = bridge->next;
+
+ /* Avoid adding an existing bridge to the chain */
+ if (bridge == next_bridge) {
+ next_bridge->encoder = NULL;
+ return false;
+ }
+
+ bridge->next = next_bridge;
+ return true;
+}
+EXPORT_SYMBOL_GPL(nwl_dsi_add_bridge);
+
+/* Removes last bridge from encoder bridge chain */
+bool nwl_dsi_del_bridge(struct drm_encoder *encoder,
+ struct drm_bridge *bridge)
+{
+ struct drm_bridge *b = encoder->bridge;
+ struct drm_bridge *prev = NULL;
+
+ if (!b || !bridge)
+ return false;
+
+ while (b->next) {
+ prev = b;
+ b = b->next;
+ }
+
+ bridge->encoder = NULL;
+ if (prev)
+ prev->next = NULL;
+ else
+ encoder->bridge = NULL;
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(nwl_dsi_del_bridge);
+
+unsigned long nwl_dsi_get_bit_clock(struct drm_bridge *bridge,
+ unsigned long pixclock)
+{
+ struct nwl_mipi_dsi *dsi;
+ int bpp;
+ u32 bus_format;
+ struct drm_crtc *crtc = 0;
+
+ /* Make sure the bridge is correctly initialized */
+ if (!bridge || !bridge->driver_private)
+ return 0;
+
+ dsi = bridge->driver_private;
+
+ if (dsi->lanes < 1 || dsi->lanes > 4)
+ return 0;
+
+ /* if CTRC updated the bus format, update dsi->format */
+ if (dsi->bridge.encoder)
+ crtc = dsi->bridge.encoder->crtc;
+ if (crtc && crtc->mode.private_flags & 0x1) {
+ bus_format = (crtc->mode.private_flags & 0x1FFFE) >> 1;
+ dsi->format = mipi_dsi_format_from_bus_format(bus_format);
+ /* propagate the format to the attached panel/bridge */
+ dsi->dsi_device->format = dsi->format;
+ /* clear bus format change indication*/
+ crtc->mode.private_flags &= ~0x1;
+ }
+
+ bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+
+ return (pixclock / dsi->lanes) * bpp;
+}
+EXPORT_SYMBOL_GPL(nwl_dsi_get_bit_clock);
+
+static void nwl_dsi_config_host(struct nwl_mipi_dsi *dsi)
+{
+ if (dsi->lanes < 1 || dsi->lanes > 4)
+ return;
+
+ nwl_dsi_write(dsi, CFG_NUM_LANES, dsi->lanes - 1);
+
+ if (dsi->dsi_mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) {
+ nwl_dsi_write(dsi, CFG_NONCONTINUOUS_CLK, 0x01);
+ nwl_dsi_write(dsi, CFG_AUTOINSERT_EOTP, 0x01);
+ } else {
+ nwl_dsi_write(dsi, CFG_NONCONTINUOUS_CLK, 0x00);
+ nwl_dsi_write(dsi, CFG_AUTOINSERT_EOTP, 0x00);
+ }
+
+ nwl_dsi_write(dsi, CFG_T_PRE, 0x01);
+ nwl_dsi_write(dsi, CFG_T_POST, 0x34);
+ nwl_dsi_write(dsi, CFG_TX_GAP, 0x0D);
+ nwl_dsi_write(dsi, CFG_EXTRA_CMDS_AFTER_EOTP, 0x00);
+ nwl_dsi_write(dsi, CFG_HTX_TO_COUNT, 0x00);
+ nwl_dsi_write(dsi, CFG_LRX_H_TO_COUNT, 0x00);
+ nwl_dsi_write(dsi, CFG_BTA_H_TO_COUNT, 0x00);
+ nwl_dsi_write(dsi, CFG_TWAKEUP, 0x3a98);
+}
+
+static void nwl_dsi_config_dpi(struct nwl_mipi_dsi *dsi)
+{
+ struct device *dev = dsi->dev;
+ struct videomode *vm = &dsi->vm;
+ enum dpi_pixel_format pixel_format =
+ nwl_dsi_get_dpi_pixel_format(dsi->format);
+ enum dpi_interface_color_coding color_coding =
+ nwl_dsi_get_dpi_interface_color_coding(dsi->format);
+ bool burst_mode;
+
+ nwl_dsi_write(dsi, INTERFACE_COLOR_CODING, color_coding);
+ nwl_dsi_write(dsi, PIXEL_FORMAT, pixel_format);
+ DRM_DEV_DEBUG_DRIVER(dev, "DSI format is: %d (CC=%d, PF=%d)\n",
+ dsi->format, color_coding, pixel_format);
+
+ /*TODO: need to make polarity configurable */
+ nwl_dsi_write(dsi, VSYNC_POLARITY, 0x00);
+ nwl_dsi_write(dsi, HSYNC_POLARITY, 0x00);
+
+ burst_mode = (dsi->dsi_mode_flags & MIPI_DSI_MODE_VIDEO_BURST) &&
+ !(dsi->dsi_mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE);
+
+ if (burst_mode) {
+ nwl_dsi_write(dsi, VIDEO_MODE, 0x2);
+ nwl_dsi_write(dsi, PIXEL_FIFO_SEND_LEVEL, 256);
+ } else {
+ nwl_dsi_write(dsi, VIDEO_MODE, 0x0);
+ nwl_dsi_write(dsi, PIXEL_FIFO_SEND_LEVEL, vm->hactive);
+ }
+
+ nwl_dsi_write(dsi, HFP, vm->hfront_porch);
+ nwl_dsi_write(dsi, HBP, vm->hback_porch);
+ nwl_dsi_write(dsi, HSA, vm->hsync_len);
+
+ nwl_dsi_write(dsi, ENABLE_MULT_PKTS, 0x0);
+ nwl_dsi_write(dsi, BLLP_MODE, 0x1);
+ nwl_dsi_write(dsi, ENABLE_MULT_PKTS, 0x0);
+ nwl_dsi_write(dsi, USE_NULL_PKT_BLLP, 0x0);
+ nwl_dsi_write(dsi, VC, 0x0);
+
+ nwl_dsi_write(dsi, PIXEL_PAYLOAD_SIZE, vm->hactive);
+ nwl_dsi_write(dsi, VACTIVE, vm->vactive - 1);
+ nwl_dsi_write(dsi, VBP, vm->vback_porch);
+ nwl_dsi_write(dsi, VFP, vm->vfront_porch);
+}
+
+static void nwl_dsi_enable_clocks(struct nwl_mipi_dsi *dsi, u32 clks)
+{
+ struct device *dev = dsi->dev;
+ unsigned long rate;
+
+ if (clks & CLK_PHY_REF && !dsi->phy_ref.enabled) {
+ clk_prepare_enable(dsi->phy_ref.clk);
+ dsi->phy_ref.enabled = true;
+ rate = clk_get_rate(dsi->phy_ref.clk);
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "Enabled phy_ref clk (rate=%lu)\n", rate);
+ }
+
+ if (clks & CLK_RX_ESC && !dsi->rx_esc.enabled) {
+ clk_set_rate(dsi->rx_esc.clk, dsi->rx_esc.rate);
+ clk_prepare_enable(dsi->rx_esc.clk);
+ dsi->rx_esc.enabled = true;
+ rate = clk_get_rate(dsi->rx_esc.clk);
+ }
+
+ if (clks & CLK_TX_ESC && !dsi->tx_esc.enabled) {
+ clk_set_rate(dsi->tx_esc.clk, dsi->tx_esc.rate);
+ clk_prepare_enable(dsi->tx_esc.clk);
+ dsi->tx_esc.enabled = true;
+ rate = clk_get_rate(dsi->tx_esc.clk);
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "Enabled tx_esc clk (rate=%lu)\n", rate);
+ }
+}
+
+static void nwl_dsi_disable_clocks(struct nwl_mipi_dsi *dsi, u32 clks)
+{
+ struct device *dev = dsi->dev;
+
+ if (clks & CLK_PHY_REF && dsi->phy_ref.enabled) {
+ clk_disable_unprepare(dsi->phy_ref.clk);
+ dsi->phy_ref.enabled = false;
+ DRM_DEV_DEBUG_DRIVER(dev, "Disabled phy_ref clk\n");
+ }
+
+ if (clks & CLK_RX_ESC && dsi->rx_esc.enabled) {
+ clk_disable_unprepare(dsi->rx_esc.clk);
+ dsi->rx_esc.enabled = false;
+ }
+
+ if (clks & CLK_TX_ESC && dsi->tx_esc.enabled) {
+ clk_disable_unprepare(dsi->tx_esc.clk);
+ dsi->tx_esc.enabled = false;
+ DRM_DEV_DEBUG_DRIVER(dev, "Disabled tx_esc clk\n");
+ }
+
+}
+
+static void nwl_dsi_init_interrupts(struct nwl_mipi_dsi *dsi)
+{
+ u32 irq_enable;
+
+ nwl_dsi_write(dsi, IRQ_MASK, 0xffffffff);
+ nwl_dsi_write(dsi, IRQ_MASK2, 0x7);
+
+ irq_enable = ~(u32)(TX_PKT_DONE_MASK |
+ RX_PKT_HDR_RCVD_MASK);
+
+ nwl_dsi_write(dsi, IRQ_MASK, irq_enable);
+}
+
+static bool nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct nwl_mipi_dsi *dsi = bridge->driver_private;
+ int bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
+ unsigned long pixclock = adjusted_mode->clock * 1000;
+ unsigned long data_rate;
+
+ if (dsi->lanes < 1 || dsi->lanes > 4)
+ return false;
+
+ /* Data rate is in bit clock for each lane */
+ data_rate = (pixclock / dsi->lanes) * bpp;
+
+ /* Max data rate for this controller is 1.5Gbps */
+ if (data_rate > 1500000000)
+ return false;
+
+ return true;
+}
+
+static void nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted)
+{
+ struct nwl_mipi_dsi *dsi = bridge->driver_private;
+
+ drm_display_mode_to_videomode(adjusted, &dsi->vm);
+
+ DRM_DEV_DEBUG_DRIVER(dsi->dev, "\n");
+ drm_mode_debug_printmodeline(adjusted);
+}
+
+static int nwl_dsi_host_attach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *device)
+{
+ struct nwl_mipi_dsi *dsi = container_of(host,
+ struct nwl_mipi_dsi,
+ host);
+ struct device *dev = dsi->dev;
+
+ DRM_DEV_INFO(dev, "lanes=%u, format=0x%x flags=0x%lx\n",
+ device->lanes, device->format, device->mode_flags);
+
+ if (device->lanes < 1 || device->lanes > 4)
+ return -EINVAL;
+
+ dsi->dsi_device = device;
+
+ /*
+ * Someone has attached to us; it could be a panel or another bridge.
+ * Check to is if this is a panel or not.
+ */
+ if (!dsi->next_bridge ||
+ device->dev.of_node != dsi->next_bridge->of_node)
+ dsi->panel = of_drm_find_panel(device->dev.of_node);
+
+ /*
+ * Bridge has priority in front of panel.
+ * Since the panel driver cannot tell if there is a physical
+ * panel connected, we'll asume that there is no physical panel if there
+ * is a bridge registered.
+ */
+ if (dsi->next_bridge &&
+ device->dev.of_node != NULL &&
+ device->dev.of_node != dsi->next_bridge->of_node) {
+ dsi->panel = NULL;
+ return -EPERM;
+ }
+
+ if (dsi->panel)
+ DRM_DEV_DEBUG_DRIVER(dsi->dev, "Panel attached\n");
+ else
+ DRM_DEV_DEBUG_DRIVER(dsi->dev, "Bridge attached\n");
+
+ dsi->lanes = device->lanes;
+ dsi->format = device->format;
+ dsi->dsi_mode_flags = device->mode_flags;
+
+ if (dsi->connector.dev)
+ drm_helper_hpd_irq_event(dsi->connector.dev);
+
+ return 0;
+}
+
+static int nwl_dsi_host_detach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *device)
+{
+ struct nwl_mipi_dsi *dsi = container_of(host,
+ struct nwl_mipi_dsi,
+ host);
+ if (dsi->panel)
+ dsi->panel = NULL;
+
+ if (dsi->connector.dev)
+ drm_helper_hpd_irq_event(dsi->connector.dev);
+
+ return 0;
+}
+
+static void nwl_dsi_print_error(struct device *dev, u16 error)
+{
+ DRM_DEV_DEBUG_DRIVER(dev, "DSI Error Register (detailed report):\n");
+ if (error & BIT(0))
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "SoT Error\n");
+ if (error & BIT(1))
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "SoT Sync Error\n");
+ if (error & BIT(2))
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "EoT Sync Error\n");
+ if (error & BIT(3))
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "Escape Mode Entry Command Error\n");
+ if (error & BIT(4))
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "Low-Power Transmit Sync Error\n");
+ if (error & BIT(5))
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "Peripheral Timeout Error\n");
+ if (error & BIT(6))
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "False Control Error\n");
+ if (error & BIT(7))
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "Contention Detected\n");
+ if (error & BIT(8))
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "ECC Error, single-bit (detected and corrected)\n");
+ if (error & BIT(9))
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "ECC Error, multi-bit (detected, not corrected)\n");
+ if (error & BIT(10))
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "Checksum Error (long packet only)\n");
+ if (error & BIT(11))
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "DSI Data Type Not Recognized\n");
+ if (error & BIT(12))
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "DSI VC ID Invalid\n");
+ if (error & BIT(13))
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "Invalid Transmission Length\n");
+ /* BIT(14) is reserved */
+ if (error & BIT(15))
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "DSI Protocol Violation\n");
+}
+
+static bool nwl_dsi_read_packet(struct nwl_mipi_dsi *dsi, u32 status)
+{
+ struct device *dev = dsi->dev;
+ struct mipi_dsi_transfer *xfer = dsi->xfer;
+ u8 *payload = xfer->msg->rx_buf;
+ u32 val;
+ u16 word_count;
+ u8 channel;
+ u8 data_type;
+
+ xfer->status = 0;
+
+ if (xfer->rx_word_count == 0) {
+ if (!(status & RX_PKT_HDR_RCVD))
+ return false;
+ /* Get the RX header and parse it */
+ val = nwl_dsi_read(dsi, RX_PKT_HEADER);
+ word_count = WC(val);
+ channel = RX_VC(val);
+ data_type = RX_DT(val);
+
+ if (channel != xfer->msg->channel) {
+ DRM_DEV_ERROR(dev,
+ "[%02X] Channel missmatch (%u != %u)\n",
+ xfer->cmd, channel, xfer->msg->channel);
+ return true;
+ }
+
+ switch (data_type) {
+ case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
+ /* Fall through */
+ case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
+ if (xfer->msg->rx_len > 1) {
+ /* read second byte */
+ payload[1] = word_count >> 8;
+ ++xfer->rx_len;
+ }
+ /* Fall through */
+ case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
+ /* Fall through */
+ case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
+ if (xfer->msg->rx_len > 0) {
+ /* read first byte */
+ payload[0] = word_count & 0xff;
+ ++xfer->rx_len;
+ }
+ xfer->status = xfer->rx_len;
+ return true;
+ case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
+ word_count &= 0xff;
+ DRM_DEV_ERROR(dev,
+ "[%02X] DSI error report: 0x%02x\n",
+ xfer->cmd, word_count);
+ nwl_dsi_print_error(dev, word_count);
+ xfer->status = -EPROTO;
+ return true;
+
+ }
+
+ if (word_count > xfer->msg->rx_len) {
+ DRM_DEV_ERROR(dev,
+ "[%02X] Receive buffer too small: %lu (< %u)\n",
+ xfer->cmd,
+ xfer->msg->rx_len,
+ word_count);
+ return true;
+ }
+
+ xfer->rx_word_count = word_count;
+ } else {
+ /* Set word_count from previous header read */
+ word_count = xfer->rx_word_count;
+ }
+
+ /* If RX payload is not yet received, wait for it */
+ if (!(status & RX_PKT_PAYLOAD_DATA_RCVD))
+ return false;
+
+ /* Read the RX payload */
+ while (word_count >= 4) {
+ val = nwl_dsi_read(dsi, RX_PAYLOAD);
+ payload[0] = (val >> 0) & 0xff;
+ payload[1] = (val >> 8) & 0xff;
+ payload[2] = (val >> 16) & 0xff;
+ payload[3] = (val >> 24) & 0xff;
+ payload += 4;
+ xfer->rx_len += 4;
+ word_count -= 4;
+ }
+
+ if (word_count > 0) {
+ val = nwl_dsi_read(dsi, RX_PAYLOAD);
+ switch (word_count) {
+ case 3:
+ payload[2] = (val >> 16) & 0xff;
+ ++xfer->rx_len;
+ /* Fall through */
+ case 2:
+ payload[1] = (val >> 8) & 0xff;
+ ++xfer->rx_len;
+ /* Fall through */
+ case 0:
+ payload[0] = (val >> 0) & 0xff;
+ ++xfer->rx_len;
+ break;
+ }
+ }
+
+ xfer->status = xfer->rx_len;
+
+ return true;
+}
+
+static void nwl_dsi_finish_transmission(struct nwl_mipi_dsi *dsi, u32 status)
+{
+ struct mipi_dsi_transfer *xfer = dsi->xfer;
+ bool end_packet = false;
+
+ if (!xfer)
+ return;
+
+ if (xfer->direction == DSI_PACKET_SEND && status & TX_PKT_DONE) {
+ xfer->status = xfer->tx_len;
+ end_packet = true;
+ } else if (status & DPHY_DIRECTION && status & RX_PKT_HDR_RCVD)
+ end_packet = nwl_dsi_read_packet(dsi, status);
+
+ if (end_packet)
+ complete(&xfer->completed);
+}
+
+static void nwl_dsi_begin_transmission(struct nwl_mipi_dsi *dsi)
+{
+ struct mipi_dsi_transfer *xfer = dsi->xfer;
+ struct mipi_dsi_packet *pkt = &xfer->packet;
+ const u8 *payload;
+ size_t length;
+ u16 word_count;
+ u8 lp_mode;
+ u32 val;
+
+ /* Send the payload, if any */
+ /* TODO: Need to check the TX FIFO overflow */
+ length = pkt->payload_length;
+ payload = pkt->payload;
+
+ while (length >= 4) {
+ val = get_unaligned_le32(payload);
+ nwl_dsi_write(dsi, TX_PAYLOAD, val);
+ payload += 4;
+ length -= 4;
+ }
+ /* Send the rest of the payload */
+ val = 0;
+ switch (length) {
+ case 3:
+ val |= payload[2] << 16;
+ /* Fall through */
+ case 2:
+ val |= payload[1] << 8;
+ /* Fall through */
+ case 1:
+ val |= payload[0];
+ nwl_dsi_write(dsi, TX_PAYLOAD, val);
+ break;
+ }
+ xfer->tx_len = length;
+
+ /*
+ * Now, send the header
+ * header structure is:
+ * header[0] = Virtual Channel + Data Type
+ * header[1] = Word Count LSB
+ * header[2] = Word Count MSB
+ */
+ word_count = pkt->header[1] | (pkt->header[2] << 8);
+ lp_mode = (xfer->msg->flags & MIPI_DSI_MSG_USE_LPM)?0:1;
+ val = WC(word_count) |
+ TX_VC(xfer->msg->channel) |
+ TX_DT(xfer->msg->type) |
+ HS_SEL(lp_mode) |
+ BTA_TX(xfer->need_bta);
+ nwl_dsi_write(dsi, PKT_CONTROL, val);
+
+ /* Send packet command */
+ nwl_dsi_write(dsi, SEND_PACKET, 0x1);
+}
+
+static ssize_t nwl_dsi_host_transfer(struct mipi_dsi_host *host,
+ const struct mipi_dsi_msg *msg)
+{
+ struct nwl_mipi_dsi *dsi = container_of(host,
+ struct nwl_mipi_dsi,
+ host);
+ struct mipi_dsi_transfer xfer;
+ ssize_t ret = 0;
+
+ /* Create packet to be sent */
+ dsi->xfer = &xfer;
+ ret = mipi_dsi_create_packet(&xfer.packet, msg);
+ if (ret < 0) {
+ dsi->xfer = NULL;
+ return ret;
+ }
+
+ if ((msg->type & MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM ||
+ msg->type & MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM ||
+ msg->type & MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM ||
+ msg->type & MIPI_DSI_DCS_READ) &&
+ msg->rx_len > 0 &&
+ msg->rx_buf != NULL)
+ xfer.direction = DSI_PACKET_RECEIVE;
+ else
+ xfer.direction = DSI_PACKET_SEND;
+
+ xfer.need_bta = (xfer.direction == DSI_PACKET_RECEIVE);
+ xfer.need_bta |= (msg->flags & MIPI_DSI_MSG_REQ_ACK)?1:0;
+ xfer.msg = msg;
+ xfer.status = -ETIMEDOUT;
+ xfer.rx_word_count = 0;
+ xfer.rx_len = 0;
+ xfer.cmd = 0x00;
+ if (msg->tx_len > 0)
+ xfer.cmd = ((u8 *)(msg->tx_buf))[0];
+ init_completion(&xfer.completed);
+
+ nwl_dsi_enable_clocks(dsi, CLK_RX_ESC);
+
+ /* Initiate the DSI packet transmision */
+ nwl_dsi_begin_transmission(dsi);
+
+ wait_for_completion_timeout(&xfer.completed, MIPI_FIFO_TIMEOUT);
+
+ ret = xfer.status;
+ if (xfer.status == -ETIMEDOUT)
+ DRM_DEV_ERROR(host->dev, "[%02X] DSI transfer timed out\n",
+ xfer.cmd);
+
+ nwl_dsi_disable_clocks(dsi, CLK_RX_ESC);
+
+ return ret;
+}
+
+static const struct mipi_dsi_host_ops nwl_dsi_host_ops = {
+ .attach = nwl_dsi_host_attach,
+ .detach = nwl_dsi_host_detach,
+ .transfer = nwl_dsi_host_transfer,
+};
+
+static irqreturn_t nwl_dsi_irq_handler(int irq, void *data)
+{
+ u32 irq_status;
+ struct nwl_mipi_dsi *dsi = data;
+
+ irq_status = nwl_dsi_read(dsi, IRQ_STATUS);
+
+ if (irq_status & TX_PKT_DONE ||
+ irq_status & RX_PKT_HDR_RCVD ||
+ irq_status & RX_PKT_PAYLOAD_DATA_RCVD)
+ nwl_dsi_finish_transmission(dsi, irq_status);
+
+ return IRQ_HANDLED;
+}
+
+static enum drm_connector_status nwl_dsi_connector_detect(
+ struct drm_connector *connector, bool force)
+{
+ struct nwl_mipi_dsi *dsi = container_of(connector,
+ struct nwl_mipi_dsi,
+ connector);
+
+ if (dsi->panel)
+ return connector_status_connected;
+
+ return connector_status_unknown;
+}
+
+static int nwl_dsi_connector_get_modes(struct drm_connector *connector)
+{
+ struct nwl_mipi_dsi *dsi = container_of(connector,
+ struct nwl_mipi_dsi,
+ connector);
+
+ if (dsi->panel)
+ return drm_panel_get_modes(dsi->panel);
+
+ return 0;
+}
+
+static const struct drm_connector_funcs nwl_dsi_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .detect = nwl_dsi_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = drm_connector_cleanup,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs
+ nwl_dsi_connector_helper_funcs = {
+ .get_modes = nwl_dsi_connector_get_modes,
+};
+
+static int nwl_dsi_create_connector(struct drm_device *drm,
+ struct nwl_mipi_dsi *dsi)
+{
+ struct device *dev = dsi->dev;
+ int ret;
+
+ ret = drm_connector_init(drm, &dsi->connector,
+ &nwl_dsi_connector_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "Failed to init drm connector: %d\n", ret);
+ return ret;
+ }
+
+ drm_connector_helper_add(&dsi->connector,
+ &nwl_dsi_connector_helper_funcs);
+
+ dsi->connector.dpms = DRM_MODE_DPMS_OFF;
+ drm_mode_connector_attach_encoder(&dsi->connector, dsi->bridge.encoder);
+
+ ret = drm_panel_attach(dsi->panel, &dsi->connector);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "Failed to attach panel: %d\n", ret);
+ drm_connector_cleanup(&dsi->connector);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int nwl_dsi_attach_next_bridge(struct drm_encoder *encoder,
+ struct drm_bridge *bridge)
+{
+ int ret = 0;
+
+ /* Attach the next bridge in chain */
+ if (!nwl_dsi_add_bridge(encoder, bridge))
+ return -EEXIST;
+ ret = drm_bridge_attach(encoder->dev, bridge);
+ if (ret)
+ nwl_dsi_del_bridge(encoder, bridge);
+
+ return ret;
+}
+
+static int nwl_dsi_bridge_attach(struct drm_bridge *bridge)
+{
+ struct nwl_mipi_dsi *dsi = bridge->driver_private;
+ struct device *dev = dsi->dev;
+ struct drm_encoder *encoder = bridge->encoder;
+ struct device_node *np = dev->of_node;
+ struct device_node *remote_node, *endpoint;
+
+ int ret = 0;
+
+ DRM_DEV_DEBUG_DRIVER(dsi->dev, "\n");
+ if (!encoder) {
+ DRM_DEV_ERROR(dev, "Parent encoder object not found\n");
+ return -ENODEV;
+ }
+
+ dsi->host.ops = &nwl_dsi_host_ops;
+ dsi->host.dev = dev;
+ ret = mipi_dsi_host_register(&dsi->host);
+ if (ret < 0) {
+ dev_err(dev, "failed to register DSI host (%d)\n", ret);
+ return ret;
+ }
+
+ endpoint = of_graph_get_next_endpoint(np, NULL);
+ while (endpoint && !dsi->next_bridge) {
+ remote_node = of_graph_get_remote_port_parent(endpoint);
+ if (!remote_node) {
+ DRM_DEV_ERROR(dev, "No endpoint found!\n");
+ return -ENODEV;
+ }
+
+ dsi->next_bridge = of_drm_find_bridge(remote_node);
+ ret = nwl_dsi_attach_next_bridge(encoder, dsi->next_bridge);
+ if (ret)
+ dsi->next_bridge = NULL;
+ of_node_put(remote_node);
+ endpoint = of_graph_get_next_endpoint(np, endpoint);
+ };
+
+ /*
+ * Create the connector. If we have a bridge, attach it and let the
+ * bridge create the connector.
+ */
+ if (dsi->panel)
+ ret = nwl_dsi_create_connector(encoder->dev, dsi);
+ else if (!dsi->next_bridge)
+ ret = -ENODEV;
+
+ return ret;
+}
+
+static void nwl_dsi_bridge_detach(struct drm_bridge *bridge)
+{
+ struct nwl_mipi_dsi *dsi = bridge->driver_private;
+
+ DRM_DEV_DEBUG_DRIVER(dsi->dev, "\n");
+ if (dsi->panel) {
+ drm_panel_detach(dsi->panel);
+ drm_connector_cleanup(&dsi->connector);
+ dsi->panel = NULL;
+ } else if (dsi->next_bridge) {
+ drm_bridge_detach(dsi->next_bridge);
+ nwl_dsi_del_bridge(dsi->next_bridge->encoder, dsi->next_bridge);
+ dsi->next_bridge = NULL;
+ }
+ if (dsi->host.dev)
+ mipi_dsi_host_unregister(&dsi->host);
+}
+
+static void nwl_dsi_bridge_enable(struct drm_bridge *bridge)
+{
+ struct nwl_mipi_dsi *dsi = bridge->driver_private;
+ struct device *dev = dsi->dev;
+ int ret;
+
+ if (dsi->enabled || (!dsi->panel && !dsi->next_bridge))
+ return;
+
+ if (!dsi->lanes) {
+ DRM_DEV_ERROR(dev, "Bridge not set up properly!\n");
+ return;
+ }
+
+ pm_runtime_get_sync(dev);
+
+ ret = devm_request_irq(dev, dsi->irq,
+ nwl_dsi_irq_handler, 0, IRQ_NAME, dsi);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "Failed to request IRQ: %d (%d)\n",
+ dsi->irq, ret);
+ return;
+ }
+
+ nwl_dsi_enable_clocks(dsi, CLK_PHY_REF | CLK_TX_ESC);
+
+ phy_init(dsi->phy);
+
+ ret = phy_power_on(dsi->phy);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "Failed to power on DPHY (%d)\n", ret);
+ goto phy_err;
+ }
+
+ nwl_dsi_init_interrupts(dsi);
+ nwl_dsi_config_dpi(dsi);
+
+ if (dsi->panel && drm_panel_prepare(dsi->panel)) {
+ DRM_DEV_ERROR(dev, "Failed to setup panel\n");
+ goto prepare_err;
+ }
+
+ nwl_dsi_config_host(dsi);
+
+ if (dsi->panel && drm_panel_enable(dsi->panel)) {
+ DRM_DEV_ERROR(dev, "Failed to enable panel\n");
+ drm_panel_unprepare(dsi->panel);
+ goto enable_err;
+ }
+
+ if (dsi->dsi_mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
+ nwl_dsi_write(dsi, CFG_NONCONTINUOUS_CLK, 0x00);
+
+ dsi->enabled = true;
+
+ return;
+
+enable_err:
+ drm_panel_unprepare(dsi->panel);
+
+prepare_err:
+ phy_power_off(dsi->phy);
+
+phy_err:
+ phy_exit(dsi->phy);
+ nwl_dsi_disable_clocks(dsi, CLK_PHY_REF | CLK_TX_ESC);
+ devm_free_irq(dev, dsi->irq, dsi);
+}
+
+static void nwl_dsi_bridge_disable(struct drm_bridge *bridge)
+{
+ struct nwl_mipi_dsi *dsi = bridge->driver_private;
+ struct device *dev = dsi->dev;
+
+ if (!dsi->enabled)
+ return;
+
+ if (dsi->panel) {
+ if (drm_panel_disable(dsi->panel)) {
+ DRM_DEV_ERROR(dev, "failed to disable panel\n");
+ return;
+ }
+ drm_panel_unprepare(dsi->panel);
+ }
+
+ phy_power_off(dsi->phy);
+ phy_exit(dsi->phy);
+
+ if (!dsi->no_clk_reset)
+ nwl_dsi_disable_clocks(dsi, CLK_PHY_REF | CLK_TX_ESC);
+
+ devm_free_irq(dev, dsi->irq, dsi);
+
+ pm_runtime_put_sync(dev);
+
+ dsi->enabled = false;
+}
+
+static const struct drm_bridge_funcs nwl_dsi_bridge_funcs = {
+ .enable = nwl_dsi_bridge_enable,
+ .disable = nwl_dsi_bridge_disable,
+ .mode_fixup = nwl_dsi_bridge_mode_fixup,
+ .mode_set = nwl_dsi_bridge_mode_set,
+ .attach = nwl_dsi_bridge_attach,
+ .detach = nwl_dsi_bridge_detach,
+};
+
+static int nwl_dsi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct nwl_mipi_dsi *dsi;
+ struct clk *clk;
+ struct resource *res;
+ int ret;
+
+ dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
+ if (!dsi)
+ return -ENOMEM;
+
+ dsi->phy = devm_phy_get(dev, "dphy");
+ if (IS_ERR(dsi->phy)) {
+ ret = PTR_ERR(dsi->phy);
+ dev_err(dev, "Could not get PHY (%d)\n", ret);
+ return ret;
+ }
+
+ clk = devm_clk_get(dev, "phy_ref");
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ dev_err(dev, "Failed to get phy_ref clock: %d\n", ret);
+ return ret;
+ }
+ dsi->phy_ref.clk = clk;
+ dsi->phy_ref.rate = clk_get_rate(clk);
+ dsi->phy_ref.enabled = false;
+
+ clk = devm_clk_get(dev, "rx_esc");
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ dev_err(dev, "Failed to get rx_esc clock: %d\n", ret);
+ return ret;
+ }
+ dsi->rx_esc.clk = clk;
+ dsi->rx_esc.rate = clk_get_rate(clk);
+ dsi->rx_esc.enabled = false;
+
+ clk = devm_clk_get(dev, "tx_esc");
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ dev_err(dev, "Failed to get tx_esc clock: %d\n", ret);
+ return ret;
+ }
+ dsi->tx_esc.clk = clk;
+ dsi->tx_esc.rate = clk_get_rate(clk);
+ dsi->tx_esc.enabled = false;
+ /* TX clk rate must be RX clk rate divided by 4 */
+ if (dsi->tx_esc.rate != (dsi->rx_esc.rate / 4))
+ dsi->tx_esc.rate = dsi->rx_esc.rate / 4;
+
+ dsi->enabled = false;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EBUSY;
+
+ dsi->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(dsi->base))
+ return PTR_ERR(dsi->base);
+
+ dsi->irq = platform_get_irq(pdev, 0);
+ if (dsi->irq < 0) {
+ DRM_DEV_ERROR(dev, "Failed to get device IRQ!\n");
+ return -EINVAL;
+ }
+
+ pm_runtime_enable(dev);
+
+ dsi->no_clk_reset = of_property_read_bool(dev->of_node, "no_clk_reset");
+
+ dsi->dev = dev;
+ platform_set_drvdata(pdev, dsi);
+
+ dsi->bridge.driver_private = dsi;
+ dsi->bridge.funcs = &nwl_dsi_bridge_funcs;
+ dsi->bridge.of_node = dev->of_node;
+
+ ret = drm_bridge_add(&dsi->bridge);
+ if (ret < 0)
+ dev_err(dev, "Failed to add nwl-dsi bridge (%d)\n", ret);
+
+ return ret;
+}
+
+static int nwl_dsi_remove(struct platform_device *pdev)
+{
+ struct nwl_mipi_dsi *dsi = platform_get_drvdata(pdev);
+
+ drm_bridge_remove(&dsi->bridge);
+
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id nwl_dsi_dt_ids[] = {
+ { .compatible = "nwl,mipi-dsi" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, nwl_dsi_dt_ids);
+
+static struct platform_driver imx_nwl_dsi_driver = {
+ .probe = nwl_dsi_probe,
+ .remove = nwl_dsi_remove,
+ .driver = {
+ .of_match_table = nwl_dsi_dt_ids,
+ .name = "nwl-mipi-dsi",
+ },
+};
+
+module_platform_driver(imx_nwl_dsi_driver);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("NWL MIPI-DSI transmitter driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:nwl-dsi");
diff --git a/drivers/gpu/drm/bridge/sec-dsim.c b/drivers/gpu/drm/bridge/sec-dsim.c
new file mode 100644
index 000000000000..b0431bd5cd04
--- /dev/null
+++ b/drivers/gpu/drm/bridge/sec-dsim.c
@@ -0,0 +1,1842 @@
+/*
+ * Samsung MIPI DSIM Bridge
+ *
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/unaligned.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <drm/bridge/sec_mipi_dsim.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+#include <video/videomode.h>
+#include <video/mipi_display.h>
+
+/* dsim registers */
+#define DSIM_VERSION 0x00
+#define DSIM_STATUS 0x04
+#define DSIM_RGB_STATUS 0x08
+#define DSIM_SWRST 0x0c
+#define DSIM_CLKCTRL 0x10
+#define DSIM_TIMEOUT 0x14
+#define DSIM_CONFIG 0x18
+#define DSIM_ESCMODE 0x1c
+#define DSIM_MDRESOL 0x20
+#define DSIM_MVPORCH 0x24
+#define DSIM_MHPORCH 0x28
+#define DSIM_MSYNC 0x2c
+#define DSIM_SDRESOL 0x30
+#define DSIM_INTSRC 0x34
+#define DSIM_INTMSK 0x38
+
+/* packet */
+#define DSIM_PKTHDR 0x3c
+#define DSIM_PAYLOAD 0x40
+#define DSIM_RXFIFO 0x44
+#define DSIM_FIFOTHLD 0x48
+#define DSIM_FIFOCTRL 0x4c
+#define DSIM_MEMACCHR 0x50
+#define DSIM_MULTI_PKT 0x78
+
+/* pll control */
+#define DSIM_PLLCTRL_1G 0x90
+#define DSIM_PLLCTRL 0x94
+#define DSIM_PLLCTRL1 0x98
+#define DSIM_PLLCTRL2 0x9c
+#define DSIM_PLLTMR 0xa0
+
+/* dphy */
+#define DSIM_PHYTIMING 0xb4
+#define DSIM_PHYTIMING1 0xb8
+#define DSIM_PHYTIMING2 0xbc
+
+/* reg bit manipulation */
+#define REG_MASK(e, s) (((1 << ((e) - (s) + 1)) - 1) << (s))
+#define REG_PUT(x, e, s) (((x) << (s)) & REG_MASK(e, s))
+#define REG_GET(x, e, s) (((x) & REG_MASK(e, s)) >> (s))
+
+/* register bit fields */
+#define STATUS_PLLSTABLE BIT(31)
+#define STATUS_SWRSTRLS BIT(20)
+#define STATUS_TXREADYHSCLK BIT(10)
+#define STATUS_ULPSCLK BIT(9)
+#define STATUS_STOPSTATECLK BIT(8)
+#define STATUS_GET_ULPSDAT(x) REG_GET(x, 7, 4)
+#define STATUS_GET_STOPSTATEDAT(x) REG_GET(x, 3, 0)
+
+#define RGB_STATUS_CMDMODE_INSEL BIT(31)
+#define RGB_STATUS_GET_RGBSTATE(x) REG_GET(x, 12, 0)
+
+#define CLKCTRL_TXREQUESTHSCLK BIT(31)
+#define CLKCTRL_DPHY_SEL_1G BIT(29)
+#define CLKCTRL_DPHY_SEL_1P5G (0x0 << 29)
+#define CLKCTRL_ESCCLKEN BIT(28)
+#define CLKCTRL_PLLBYPASS BIT(29)
+#define CLKCTRL_BYTECLKSRC_DPHY_PLL REG_PUT(0, 26, 25)
+#define CLKCTRL_BYTECLKEN BIT(24)
+#define CLKCTRL_SET_LANEESCCLKEN(x) REG_PUT(x, 23, 19)
+#define CLKCTRL_SET_ESCPRESCALER(x) REG_PUT(x, 15, 0)
+
+#define TIMEOUT_SET_BTAOUT(x) REG_PUT(x, 23, 16)
+#define TIMEOUT_SET_LPDRTOUT(x) REG_PUT(x, 15, 0)
+
+#define CONFIG_NON_CONTINUOUS_CLOCK_LANE BIT(31)
+#define CONFIG_CLKLANE_STOP_START BIT(30)
+#define CONFIG_MFLUSH_VS BIT(29)
+#define CONFIG_EOT_R03 BIT(28)
+#define CONFIG_SYNCINFORM BIT(27)
+#define CONFIG_BURSTMODE BIT(26)
+#define CONFIG_VIDEOMODE BIT(25)
+#define CONFIG_AUTOMODE BIT(24)
+#define CONFIG_HSEDISABLEMODE BIT(23)
+#define CONFIG_HFPDISABLEMODE BIT(22)
+#define CONFIG_HBPDISABLEMODE BIT(21)
+#define CONFIG_HSADISABLEMODE BIT(20)
+#define CONFIG_SET_MAINVC(x) REG_PUT(x, 19, 18)
+#define CONFIG_SET_SUBVC(x) REG_PUT(x, 17, 16)
+#define CONFIG_SET_MAINPIXFORMAT(x) REG_PUT(x, 14, 12)
+#define CONFIG_SET_SUBPIXFORMAT(x) REG_PUT(x, 10, 8)
+#define CONFIG_SET_NUMOFDATLANE(x) REG_PUT(x, 6, 5)
+#define CONFIG_SET_LANEEN(x) REG_PUT(x, 4, 0)
+
+#define ESCMODE_SET_STOPSTATE_CNT(X) REG_PUT(x, 31, 21)
+#define ESCMODE_FORCESTOPSTATE BIT(20)
+#define ESCMODE_FORCEBTA BIT(16)
+#define ESCMODE_CMDLPDT BIT(7)
+#define ESCMODE_TXLPDT BIT(6)
+#define ESCMODE_TXTRIGGERRST BIT(5)
+
+#define MDRESOL_MAINSTANDBY BIT(31)
+#define MDRESOL_SET_MAINVRESOL(x) REG_PUT(x, 27, 16)
+#define MDRESOL_SET_MAINHRESOL(x) REG_PUT(x, 11, 0)
+
+#define MVPORCH_SET_CMDALLOW(x) REG_PUT(x, 31, 28)
+#define MVPORCH_SET_STABLEVFP(x) REG_PUT(x, 26, 16)
+#define MVPORCH_SET_MAINVBP(x) REG_PUT(x, 10, 0)
+
+#define MHPORCH_SET_MAINHFP(x) REG_PUT(x, 31, 16)
+#define MHPORCH_SET_MAINHBP(x) REG_PUT(x, 15, 0)
+
+#define MSYNC_SET_MAINVSA(x) REG_PUT(x, 31, 22)
+#define MSYNC_SET_MAINHSA(x) REG_PUT(x, 15, 0)
+
+#define INTSRC_PLLSTABLE BIT(31)
+#define INTSRC_SWRSTRELEASE BIT(30)
+#define INTSRC_SFRPLFIFOEMPTY BIT(29)
+#define INTSRC_SFRPHFIFOEMPTY BIT(28)
+#define INTSRC_FRAMEDONE BIT(24)
+#define INTSRC_LPDRTOUT BIT(21)
+#define INTSRC_TATOUT BIT(20)
+#define INTSRC_RXDATDONE BIT(18)
+#define INTSRC_RXTE BIT(17)
+#define INTSRC_RXACK BIT(16)
+#define INTSRC_MASK (INTSRC_PLLSTABLE | \
+ INTSRC_SWRSTRELEASE | \
+ INTSRC_SFRPLFIFOEMPTY | \
+ INTSRC_SFRPHFIFOEMPTY | \
+ INTSRC_FRAMEDONE | \
+ INTSRC_LPDRTOUT | \
+ INTSRC_TATOUT | \
+ INTSRC_RXDATDONE | \
+ INTSRC_RXTE | \
+ INTSRC_RXACK)
+
+#define INTMSK_MSKPLLSTABLE BIT(31)
+#define INTMSK_MSKSWRELEASE BIT(30)
+#define INTMSK_MSKSFRPLFIFOEMPTY BIT(29)
+#define INTMSK_MSKSFRPHFIFOEMPTY BIT(28)
+#define INTMSK_MSKFRAMEDONE BIT(24)
+#define INTMSK_MSKLPDRTOUT BIT(21)
+#define INTMSK_MSKTATOUT BIT(20)
+#define INTMSK_MSKRXDATDONE BIT(18)
+#define INTMSK_MSKRXTE BIT(17)
+#define INTMSK_MSKRXACK BIT(16)
+
+#define PKTHDR_SET_DATA1(x) REG_PUT(x, 23, 16)
+#define PKTHDR_GET_DATA1(x) REG_GET(x, 23, 16)
+#define PKTHDR_SET_DATA0(x) REG_PUT(x, 15, 8)
+#define PKTHDR_GET_DATA0(x) REG_GET(x, 15, 8)
+#define PKTHDR_GET_WC(x) REG_GET(x, 23, 8)
+#define PKTHDR_SET_DI(x) REG_PUT(x, 7, 0)
+#define PKTHDR_GET_DI(x) REG_GET(x, 7, 0)
+#define PKTHDR_SET_DT(x) REG_PUT(x, 5, 0)
+#define PKTHDR_GET_DT(x) REG_GET(x, 5, 0)
+#define PKTHDR_SET_VC(x) REG_PUT(x, 7, 6)
+#define PKTHDR_GET_VC(x) REG_GET(x, 7, 6)
+
+#define FIFOCTRL_FULLRX BIT(25)
+#define FIFOCTRL_EMPTYRX BIT(24)
+#define FIFOCTRL_FULLHSFR BIT(23)
+#define FIFOCTRL_EMPTYHSFR BIT(22)
+#define FIFOCTRL_FULLLSFR BIT(21)
+#define FIFOCTRL_EMPTYLSFR BIT(20)
+#define FIFOCTRL_FULLHMAIN BIT(11)
+#define FIFOCTRL_EMPTYHMAIN BIT(10)
+#define FIFOCTRL_FULLLMAIN BIT(9)
+#define FIFOCTRL_EMPTYLMAIN BIT(8)
+#define FIFOCTRL_NINITRX BIT(4)
+#define FIFOCTRL_NINITSFR BIT(3)
+#define FIFOCTRL_NINITI80 BIT(2)
+#define FIFOCTRL_NINITSUB BIT(1)
+#define FIFOCTRL_NINITMAIN BIT(0)
+
+#define PLLCTRL_DPDNSWAP_CLK BIT(25)
+#define PLLCTRL_DPDNSWAP_DAT BIT(24)
+#define PLLCTRL_PLLEN BIT(23)
+#define PLLCTRL_SET_PMS(x) REG_PUT(x, 19, 1)
+ #define PLLCTRL_SET_P(x) REG_PUT(x, 18, 13)
+ #define PLLCTRL_SET_M(x) REG_PUT(x, 12, 3)
+ #define PLLCTRL_SET_S(x) REG_PUT(x, 2, 0)
+
+#define PHYTIMING_SET_M_TLPXCTL(x) REG_PUT(x, 15, 8)
+#define PHYTIMING_SET_M_THSEXITCTL(x) REG_PUT(x, 7, 0)
+
+#define PHYTIMING1_SET_M_TCLKPRPRCTL(x) REG_PUT(x, 31, 24)
+#define PHYTIMING1_SET_M_TCLKZEROCTL(x) REG_PUT(x, 23, 16)
+#define PHYTIMING1_SET_M_TCLKPOSTCTL(x) REG_PUT(x, 15, 8)
+#define PHYTIMING1_SET_M_TCLKTRAILCTL(x) REG_PUT(x, 7, 0)
+
+#define PHYTIMING2_SET_M_THSPRPRCTL(x) REG_PUT(x, 23, 16)
+#define PHYTIMING2_SET_M_THSZEROCTL(x) REG_PUT(x, 15, 8)
+#define PHYTIMING2_SET_M_THSTRAILCTL(x) REG_PUT(x, 7, 0)
+
+#define dsim_read(dsim, reg) readl(dsim->base + reg)
+#define dsim_write(dsim, val, reg) writel(val, dsim->base + reg)
+
+/* fixed phy ref clk rate */
+#define PHY_REF_CLK 27000000
+
+#define MAX_MAIN_HRESOL 2047
+#define MAX_MAIN_VRESOL 2047
+#define MAX_SUB_HRESOL 1024
+#define MAX_SUB_VRESOL 1024
+
+/* in KHZ */
+#define MAX_ESC_CLK_FREQ 20000
+
+/* dsim all irqs index */
+#define PLLSTABLE 1
+#define SWRSTRELEASE 2
+#define SFRPLFIFOEMPTY 3
+#define SFRPHFIFOEMPTY 4
+#define SYNCOVERRIDE 5
+#define BUSTURNOVER 6
+#define FRAMEDONE 7
+#define LPDRTOUT 8
+#define TATOUT 9
+#define RXDATDONE 10
+#define RXTE 11
+#define RXACK 12
+#define ERRRXECC 13
+#define ERRRXCRC 14
+#define ERRESC3 15
+#define ERRESC2 16
+#define ERRESC1 17
+#define ERRESC0 18
+#define ERRSYNC3 19
+#define ERRSYNC2 20
+#define ERRSYNC1 21
+#define ERRSYNC0 22
+#define ERRCONTROL3 23
+#define ERRCONTROL2 24
+#define ERRCONTROL1 25
+#define ERRCONTROL0 26
+
+#define MIPI_FIFO_TIMEOUT msecs_to_jiffies(250)
+
+#define to_sec_mipi_dsim(dsi) container_of(dsi, struct sec_mipi_dsim, dsi_host)
+#define conn_to_sec_mipi_dsim(conn) \
+ container_of(conn, struct sec_mipi_dsim, connector)
+
+/* DSIM PLL configuration from spec:
+ *
+ * Fout(DDR) = (M * Fin) / (P * 2^S), so Fout / Fin = M / (P * 2^S)
+ * Fin_pll = Fin / P (6 ~ 12 MHz)
+ * S: [2:0], M: [12:3], P: [18:13], so
+ * TODO: 'S' is in [0 ~ 3], 'M' is in, 'P' is in [1 ~ 33]
+ *
+ */
+
+/* used for CEA standard modes */
+struct dsim_hblank_par {
+ char *name; /* drm display mode name */
+ int vrefresh;
+ int hfp_wc;
+ int hbp_wc;
+ int hsa_wc;
+ int lanes;
+};
+
+struct dsim_pll_pms {
+ uint64_t bit_clk; /* kHz */
+ uint32_t p;
+ uint32_t m;
+ uint32_t s;
+};
+
+struct sec_mipi_dsim {
+ struct mipi_dsi_host dsi_host;
+ struct drm_connector connector;
+ struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
+ struct drm_bridge *next;
+ struct drm_panel *panel;
+ struct device *dev;
+
+ void __iomem *base;
+ int irq;
+
+ struct clk *clk_cfg;
+ struct clk *clk_pllref;
+ struct clk *pclk; /* pixel clock */
+
+ /* kHz clocks */
+ uint64_t pix_clk;
+ uint64_t bit_clk;
+
+ unsigned int lanes;
+ unsigned int channel; /* virtual channel */
+ enum mipi_dsi_pixel_format format;
+ unsigned long mode_flags;
+ const struct dsim_hblank_par *hpar;
+ unsigned int pms;
+ unsigned int p;
+ unsigned int m;
+ unsigned int s;
+ unsigned long long lp_data_rate;
+ unsigned long long hs_data_rate;
+ struct videomode vmode;
+
+ struct completion pll_stable;
+ struct completion ph_tx_done;
+ struct completion pl_tx_done;
+ struct completion rx_done;
+ const struct sec_mipi_dsim_plat_data *pdata;
+};
+
+#define DSIM_HBLANK_PARAM(nm, vf, hfp, hbp, hsa, num) \
+ .name = (nm), \
+ .vrefresh = (vf), \
+ .hfp_wc = (hfp), \
+ .hbp_wc = (hbp), \
+ .hsa_wc = (hsa), \
+ .lanes = (num)
+
+#define DSIM_PLL_PMS(c, pp, mm, ss) \
+ .bit_clk = (c), \
+ .p = (pp), \
+ .m = (mm), \
+ .s = (ss)
+
+static const struct dsim_hblank_par hblank_4lanes[] = {
+ /* { 88, 148, 44 } */
+ { DSIM_HBLANK_PARAM("1920x1080", 60, 60, 105, 27, 4), },
+ /* { 528, 148, 44 } */
+ { DSIM_HBLANK_PARAM("1920x1080", 50, 390, 105, 27, 4), },
+ /* { 88, 148, 44 } */
+ { DSIM_HBLANK_PARAM("1920x1080", 30, 60, 105, 27, 4), },
+ /* { 110, 220, 40 } */
+ { DSIM_HBLANK_PARAM("1280x720" , 60, 78, 159, 24, 4), },
+ /* { 440, 220, 40 } */
+ { DSIM_HBLANK_PARAM("1280x720" , 50, 324, 159, 24, 4), },
+ /* { 16, 60, 62 } */
+ { DSIM_HBLANK_PARAM("720x480" , 60, 6, 39, 40, 4), },
+ /* { 12, 68, 64 } */
+ { DSIM_HBLANK_PARAM("720x576" , 50, 3, 45, 42, 4), },
+ /* { 16, 48, 96 } */
+ { DSIM_HBLANK_PARAM("640x480" , 60, 6, 30, 66, 4), },
+};
+
+static const struct dsim_hblank_par hblank_2lanes[] = {
+ /* { 88, 148, 44 } */
+ { DSIM_HBLANK_PARAM("1920x1080", 30, 114, 210, 60, 2), },
+ /* { 110, 220, 40 } */
+ { DSIM_HBLANK_PARAM("1280x720" , 60, 159, 320, 40, 2), },
+ /* { 440, 220, 40 } */
+ { DSIM_HBLANK_PARAM("1280x720" , 50, 654, 320, 40, 2), },
+ /* { 16, 60, 62 } */
+ { DSIM_HBLANK_PARAM("720x480" , 60, 16, 66, 88, 2), },
+ /* { 12, 68, 64 } */
+ { DSIM_HBLANK_PARAM("720x576" , 50, 12, 96, 72, 2), },
+ /* { 16, 48, 96 } */
+ { DSIM_HBLANK_PARAM("640x480" , 60, 18, 66, 138, 2), },
+};
+
+static const struct dsim_pll_pms pll_pms[] = {
+ { DSIM_PLL_PMS(891000, 1, 66, 1), },
+ { DSIM_PLL_PMS(890112, 1, 66, 1), },
+ { DSIM_PLL_PMS(594000, 3, 66, 0), },
+ { DSIM_PLL_PMS(593408, 3, 66, 0), },
+ { DSIM_PLL_PMS(445500, 1, 66, 2), },
+ { DSIM_PLL_PMS(445056, 1, 66, 2), },
+ { DSIM_PLL_PMS(324000, 3, 72, 1), },
+ { DSIM_PLL_PMS(324324, 3, 72, 1), },
+ { DSIM_PLL_PMS(162000, 3, 72, 2), },
+ { DSIM_PLL_PMS(162162, 3, 72, 2), },
+};
+
+static const struct dsim_hblank_par *sec_mipi_dsim_get_hblank_par(const char *name,
+ int vrefresh,
+ int lanes)
+{
+ int i, size;
+ const struct dsim_hblank_par *hpar, *hblank;
+
+ if (unlikely(!name))
+ return NULL;
+
+ switch (lanes) {
+ case 2:
+ hblank = hblank_2lanes;
+ size = ARRAY_SIZE(hblank_2lanes);
+ break;
+ case 4:
+ hblank = hblank_4lanes;
+ size = ARRAY_SIZE(hblank_4lanes);
+ break;
+ default:
+ pr_err("No hblank data for mode %s with %d lanes\n",
+ name, lanes);
+ return NULL;
+ }
+
+ for (i = 0; i < size; i++) {
+ hpar = &hblank[i];
+
+ if (!strcmp(name, hpar->name)) {
+ if (vrefresh != hpar->vrefresh)
+ continue;
+
+ /* found */
+ return hpar;
+ }
+ }
+
+ return NULL;
+}
+
+static const struct dsim_pll_pms *sec_mipi_dsim_get_pms(uint64_t bit_clk)
+{
+ int i;
+ const struct dsim_pll_pms *pms;
+
+ for (i = 0; i < ARRAY_SIZE(pll_pms); i++) {
+ pms = &pll_pms[i];
+
+ if (bit_clk == pms->bit_clk)
+ return pms;
+ }
+
+ return NULL;
+}
+
+static void sec_mipi_dsim_irq_init(struct sec_mipi_dsim *dsim);
+
+/* For now, dsim only support one device attached */
+static int sec_mipi_dsim_host_attach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *dsi)
+{
+ struct sec_mipi_dsim *dsim = to_sec_mipi_dsim(host);
+ const struct sec_mipi_dsim_plat_data *pdata = dsim->pdata;
+ struct device *dev = dsim->dev;
+ struct drm_panel *panel;
+
+ if (!dsi->lanes || dsi->lanes > pdata->max_data_lanes) {
+ dev_err(dev, "invalid data lanes number\n");
+ return -EINVAL;
+ }
+
+ if (dsim->channel)
+ return -EINVAL;
+
+ if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO) ||
+ !((dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) ||
+ (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE))) {
+ dev_err(dev, "unsupported dsi mode\n");
+ return -EINVAL;
+ }
+
+ if (dsi->format != MIPI_DSI_FMT_RGB888 &&
+ dsi->format != MIPI_DSI_FMT_RGB565 &&
+ dsi->format != MIPI_DSI_FMT_RGB666 &&
+ dsi->format != MIPI_DSI_FMT_RGB666_PACKED) {
+ dev_err(dev, "unsupported pixel format: %#x\n", dsi->format);
+ return -EINVAL;
+ }
+
+ if (!dsim->next) {
+ /* 'dsi' must be panel device */
+ panel = of_drm_find_panel(dsi->dev.of_node);
+
+ if (!panel) {
+ dev_err(dev, "refuse unknown dsi device attach\n");
+ WARN_ON(!panel);
+ return -ENODEV;
+ }
+
+ /* Don't support multiple panels */
+ if (dsim->panel && panel && dsim->panel != panel) {
+ dev_err(dev, "don't support multiple panels\n");
+ return -EBUSY;
+ }
+
+ dsim->panel = panel;
+ }
+
+ /* TODO: DSIM 3 lanes has some display issue, so
+ * avoid 3 lanes enable, and force data lanes to
+ * be 2.
+ */
+ if (dsi->lanes == 3)
+ dsi->lanes = 2;
+
+ dsim->lanes = dsi->lanes;
+ dsim->channel = dsi->channel;
+ dsim->format = dsi->format;
+ dsim->mode_flags = dsi->mode_flags;
+
+ /* TODO: support later */
+#if 0
+ if (dsim->connector.dev)
+ drm_helper_hpd_irq_event(dsim->connector.dev);
+#endif
+
+ return 0;
+}
+
+static int sec_mipi_dsim_host_detach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *dsi)
+{
+ struct sec_mipi_dsim *dsim = to_sec_mipi_dsim(host);
+
+ if (WARN_ON(!dsim->next && !dsim->panel))
+ return -ENODEV;
+
+ /* clear the saved dsi parameters */
+ dsim->lanes = 0;
+ dsim->channel = 0;
+ dsim->format = 0;
+ dsim->mode_flags = 0;
+
+ return 0;
+}
+
+static void sec_mipi_dsim_config_cmd_lpm(struct sec_mipi_dsim *dsim,
+ bool enable)
+{
+ uint32_t escmode;
+
+ escmode = dsim_read(dsim, DSIM_ESCMODE);
+
+ if (enable)
+ escmode |= ESCMODE_CMDLPDT;
+ else
+ escmode &= ~ESCMODE_CMDLPDT;
+
+ /* force BTA at the end of packet transfer
+ * to receive the acknowledgment from dsi
+ * peripheral for this transfer
+ */
+ escmode |= ESCMODE_FORCEBTA;
+
+ dsim_write(dsim, escmode, DSIM_ESCMODE);
+}
+
+static void sec_mipi_dsim_write_pl_to_sfr_fifo(struct sec_mipi_dsim *dsim,
+ const void *payload,
+ size_t length)
+{
+ uint32_t pl_data;
+
+ if (!length)
+ return;
+
+ while (length >= 4) {
+ pl_data = get_unaligned_le32(payload);
+ dsim_write(dsim, pl_data, DSIM_PAYLOAD);
+ payload += 4;
+ length -= 4;
+ }
+
+ pl_data = 0;
+ switch (length) {
+ case 3:
+ pl_data |= ((u8 *)payload)[2] << 16;
+ case 2:
+ pl_data |= ((u8 *)payload)[1] << 8;
+ case 1:
+ pl_data |= ((u8 *)payload)[0];
+ dsim_write(dsim, pl_data, DSIM_PAYLOAD);
+ break;
+ }
+}
+
+static void sec_mipi_dsim_write_ph_to_sfr_fifo(struct sec_mipi_dsim *dsim,
+ void *header,
+ bool use_lpm)
+{
+ uint32_t pkthdr;
+
+ /* config LPM for CMD TX */
+ sec_mipi_dsim_config_cmd_lpm(dsim, use_lpm);
+
+ pkthdr = PKTHDR_SET_DATA1(((u8 *)header)[2]) | /* WC MSB */
+ PKTHDR_SET_DATA0(((u8 *)header)[1]) | /* WC LSB */
+ PKTHDR_SET_DI(((u8 *)header)[0]); /* Data ID */
+
+ dsim_write(dsim, pkthdr, DSIM_PKTHDR);
+}
+
+static int sec_mipi_dsim_read_pl_from_sfr_fifo(struct sec_mipi_dsim *dsim,
+ void *payload,
+ size_t length)
+{
+ uint8_t data_type;
+ uint16_t word_count = 0;
+ uint32_t fifoctrl, ph, pl;
+
+ fifoctrl = dsim_read(dsim, DSIM_FIFOCTRL);
+
+ if (WARN_ON(fifoctrl & FIFOCTRL_EMPTYRX))
+ return -EINVAL;
+
+ ph = dsim_read(dsim, DSIM_RXFIFO);
+ data_type = PKTHDR_GET_DT(ph);
+ switch (data_type) {
+ case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
+ dev_err(dsim->dev, "peripheral report error: (0-7)%x, (8-15)%x\n",
+ PKTHDR_GET_DATA0(ph), PKTHDR_GET_DATA1(ph));
+ return -EPROTO;
+ case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
+ case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
+ if (!WARN_ON(length < 2)) {
+ ((u8 *)payload)[1] = PKTHDR_GET_DATA1(ph);
+ word_count++;
+ }
+ /* fall through */
+ case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
+ case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
+ ((u8 *)payload)[0] = PKTHDR_GET_DATA0(ph);
+ word_count++;
+ length = word_count;
+ break;
+ case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
+ case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
+ word_count = PKTHDR_GET_WC(ph);
+ if (word_count > length) {
+ dev_err(dsim->dev, "invalid receive buffer length\n");
+ return -EINVAL;
+ }
+
+ length = word_count;
+
+ while (word_count >= 4) {
+ pl = dsim_read(dsim, DSIM_RXFIFO);
+ ((u8 *)payload)[0] = pl & 0xff;
+ ((u8 *)payload)[1] = (pl >> 8) & 0xff;
+ ((u8 *)payload)[2] = (pl >> 16) & 0xff;
+ ((u8 *)payload)[3] = (pl >> 24) & 0xff;
+ payload += 4;
+ word_count -= 4;
+ }
+
+ if (word_count > 0) {
+ pl = dsim_read(dsim, DSIM_RXFIFO);
+
+ switch (word_count) {
+ case 3:
+ ((u8 *)payload)[2] = (pl >> 16) & 0xff;
+ case 2:
+ ((u8 *)payload)[1] = (pl >> 8) & 0xff;
+ case 1:
+ ((u8 *)payload)[0] = pl & 0xff;
+ break;
+ }
+ }
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return length;
+}
+
+static ssize_t sec_mipi_dsim_host_transfer(struct mipi_dsi_host *host,
+ const struct mipi_dsi_msg *msg)
+{
+ int ret;
+ bool use_lpm;
+ struct mipi_dsi_packet packet;
+ struct sec_mipi_dsim *dsim = to_sec_mipi_dsim(host);
+
+ if ((msg->rx_buf && !msg->rx_len) || (msg->rx_len && !msg->rx_buf))
+ return -EINVAL;
+
+ ret = mipi_dsi_create_packet(&packet, msg);
+ if (ret) {
+ dev_err(dsim->dev, "failed to create dsi packet: %d\n", ret);
+ return ret;
+ }
+
+ /* need to read data from peripheral */
+ if (unlikely(msg->rx_buf))
+ reinit_completion(&dsim->rx_done);
+
+ use_lpm = msg->flags & MIPI_DSI_MSG_USE_LPM ? true : false;
+
+ if (packet.payload_length) { /* Long Packet case */
+ reinit_completion(&dsim->pl_tx_done);
+
+ /* write packet payload */
+ sec_mipi_dsim_write_pl_to_sfr_fifo(dsim,
+ packet.payload,
+ packet.payload_length);
+
+ /* write packet header */
+ sec_mipi_dsim_write_ph_to_sfr_fifo(dsim,
+ packet.header,
+ use_lpm);
+
+ ret = wait_for_completion_timeout(&dsim->ph_tx_done,
+ MIPI_FIFO_TIMEOUT);
+ if (!ret) {
+ dev_err(dsim->dev, "wait payload tx done time out\n");
+ return -EBUSY;
+ }
+ } else {
+ reinit_completion(&dsim->ph_tx_done);
+
+ /* write packet header */
+ sec_mipi_dsim_write_ph_to_sfr_fifo(dsim,
+ packet.header,
+ use_lpm);
+
+ ret = wait_for_completion_timeout(&dsim->ph_tx_done,
+ MIPI_FIFO_TIMEOUT);
+ if (!ret) {
+ dev_err(dsim->dev, "wait pkthdr tx done time out\n");
+ return -EBUSY;
+ }
+ }
+
+ /* read packet payload */
+ if (unlikely(msg->rx_buf)) {
+ ret = wait_for_completion_timeout(&dsim->rx_done,
+ MIPI_FIFO_TIMEOUT);
+ if (!ret) {
+ dev_err(dsim->dev, "wait rx done time out\n");
+ return -EBUSY;
+ }
+
+ ret = sec_mipi_dsim_read_pl_from_sfr_fifo(dsim,
+ msg->rx_buf,
+ msg->rx_len);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct mipi_dsi_host_ops sec_mipi_dsim_host_ops = {
+ .attach = sec_mipi_dsim_host_attach,
+ .detach = sec_mipi_dsim_host_detach,
+ .transfer = sec_mipi_dsim_host_transfer,
+};
+
+static int sec_mipi_dsim_bridge_attach(struct drm_bridge *bridge)
+{
+ int ret;
+ struct sec_mipi_dsim *dsim = bridge->driver_private;
+ struct device *dev = dsim->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *endpoint, *remote;
+ struct drm_device *drm_dev = bridge->dev;
+ struct drm_bridge *next = NULL;
+ struct drm_encoder *encoder = dsim->encoder;
+
+ /* TODO: All bridges and planes should have already been added */
+
+ /* A panel has been found, ignor other dsi devices */
+ if (dsim->panel)
+ return 0;
+
+ /* find next bridge */
+ endpoint = of_graph_get_next_endpoint(np, NULL);
+ /* At least one endpoint should be existed */
+ if (!endpoint)
+ return -ENODEV;
+
+ while(endpoint && !next) {
+ remote = of_graph_get_remote_port_parent(endpoint);
+
+ if (!remote || !of_device_is_available(remote)) {
+ of_node_put(remote);
+ endpoint = of_graph_get_next_endpoint(np, endpoint);
+ continue;
+ }
+
+ next = of_drm_find_bridge(remote);
+ if (next) {
+ /* Found */
+ of_node_put(endpoint);
+ break;
+ }
+
+ endpoint = of_graph_get_next_endpoint(np, endpoint);
+ }
+
+ /* No valid dsi device attached */
+ if (!next)
+ return -ENODEV;
+
+ /* duplicate bridges or next bridge exists */
+ WARN_ON(bridge == next || bridge->next || dsim->next);
+
+ dsim->next = next;
+ next->encoder = encoder;
+ ret = drm_bridge_attach(drm_dev, next);
+ if (ret) {
+ dev_err(dev, "Unable to attach bridge %s: %d\n",
+ remote->name, ret);
+ dsim->next = NULL;
+ return ret;
+ }
+
+ /* bridge chains */
+ bridge->next = next;
+
+ return 0;
+}
+
+static void sec_mipi_dsim_bridge_detach(struct drm_bridge *bridge)
+{
+ struct sec_mipi_dsim *dsim = bridge->driver_private;
+
+ if (bridge->next) {
+ drm_bridge_detach(dsim->next);
+
+ bridge->next->encoder = NULL;
+ bridge->next = NULL;
+ dsim->next = NULL;
+ }
+}
+
+static int sec_mipi_dsim_config_pll(struct sec_mipi_dsim *dsim)
+{
+ int ret;
+ uint32_t pllctrl = 0, status, data_lanes_en, stop;
+
+ dsim_write(dsim, 0x8000, DSIM_PLLTMR);
+
+ /* TODO: config dp/dn swap if requires */
+
+ pllctrl |= PLLCTRL_SET_PMS(dsim->pms) | PLLCTRL_PLLEN;
+ dsim_write(dsim, pllctrl, DSIM_PLLCTRL);
+
+ ret = wait_for_completion_timeout(&dsim->pll_stable, HZ / 10);
+ if (!ret) {
+ dev_err(dsim->dev, "wait for pll stable time out\n");
+ return -EBUSY;
+ }
+
+ /* wait for clk & data lanes to go to stop state */
+ mdelay(1);
+
+ data_lanes_en = (0x1 << dsim->lanes) - 1;
+ status = dsim_read(dsim, DSIM_STATUS);
+ if (!(status & STATUS_STOPSTATECLK)) {
+ dev_err(dsim->dev, "clock is not in stop state\n");
+ return -EBUSY;
+ }
+
+ stop = STATUS_GET_STOPSTATEDAT(status);
+ if ((stop & data_lanes_en) != data_lanes_en) {
+ dev_err(dsim->dev,
+ "one or more data lanes is not in stop state\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static void sec_mipi_dsim_set_main_mode(struct sec_mipi_dsim *dsim)
+{
+ uint32_t bpp, hfp_wc, hbp_wc, hsa_wc;
+ uint32_t mdresol = 0, mvporch = 0, mhporch = 0, msync = 0;
+ struct videomode *vmode = &dsim->vmode;
+
+ mdresol |= MDRESOL_SET_MAINVRESOL(vmode->vactive) |
+ MDRESOL_SET_MAINHRESOL(vmode->hactive);
+ dsim_write(dsim, mdresol, DSIM_MDRESOL);
+
+ mvporch |= MVPORCH_SET_MAINVBP(vmode->vback_porch) |
+ MVPORCH_SET_STABLEVFP(vmode->vfront_porch) |
+ MVPORCH_SET_CMDALLOW(0x0);
+ dsim_write(dsim, mvporch, DSIM_MVPORCH);
+
+ bpp = mipi_dsi_pixel_format_to_bpp(dsim->format);
+
+ /* calculate hfp & hbp word counts */
+ if (dsim->panel || !dsim->hpar) {
+ hfp_wc = vmode->hfront_porch * (bpp >> 3);
+ hbp_wc = vmode->hback_porch * (bpp >> 3);
+ } else {
+ hfp_wc = dsim->hpar->hfp_wc;
+ hbp_wc = dsim->hpar->hbp_wc;
+ }
+
+ mhporch |= MHPORCH_SET_MAINHFP(hfp_wc) |
+ MHPORCH_SET_MAINHBP(hbp_wc);
+
+ dsim_write(dsim, mhporch, DSIM_MHPORCH);
+
+ /* calculate hsa word counts */
+ if (dsim->panel || !dsim->hpar)
+ hsa_wc = vmode->hsync_len * (bpp >> 3);
+ else
+ hsa_wc = dsim->hpar->hsa_wc;
+
+ msync |= MSYNC_SET_MAINVSA(vmode->vsync_len) |
+ MSYNC_SET_MAINHSA(hsa_wc);
+
+ dsim_write(dsim, msync, DSIM_MSYNC);
+}
+
+static void sec_mipi_dsim_config_dpi(struct sec_mipi_dsim *dsim)
+{
+ uint32_t config = 0, rgb_status = 0, data_lanes_en;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO)
+ rgb_status &= ~RGB_STATUS_CMDMODE_INSEL;
+ else
+ rgb_status |= RGB_STATUS_CMDMODE_INSEL;
+
+ dsim_write(dsim, rgb_status, DSIM_RGB_STATUS);
+
+ if (dsim->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) {
+ config |= CONFIG_NON_CONTINUOUS_CLOCK_LANE;
+ config |= CONFIG_CLKLANE_STOP_START;
+ }
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VSYNC_FLUSH)
+ config |= CONFIG_MFLUSH_VS;
+
+ /* disable EoT packets in HS mode */
+ if (dsim->mode_flags & MIPI_DSI_MODE_EOT_PACKET)
+ config |= CONFIG_EOT_R03;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO) {
+ config |= CONFIG_VIDEOMODE;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+ config |= CONFIG_BURSTMODE;
+
+ else if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+ config |= CONFIG_SYNCINFORM;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_AUTO_VERT)
+ config |= CONFIG_AUTOMODE;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_HSE)
+ config |= CONFIG_HSEDISABLEMODE;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_HFP)
+ config |= CONFIG_HFPDISABLEMODE;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_HBP)
+ config |= CONFIG_HBPDISABLEMODE;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_HSA)
+ config |= CONFIG_HSADISABLEMODE;
+ }
+
+ config |= CONFIG_SET_MAINVC(dsim->channel);
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO) {
+ switch (dsim->format) {
+ case MIPI_DSI_FMT_RGB565:
+ config |= CONFIG_SET_MAINPIXFORMAT(0x4);
+ break;
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ config |= CONFIG_SET_MAINPIXFORMAT(0x5);
+ break;
+ case MIPI_DSI_FMT_RGB666:
+ config |= CONFIG_SET_MAINPIXFORMAT(0x6);
+ break;
+ case MIPI_DSI_FMT_RGB888:
+ config |= CONFIG_SET_MAINPIXFORMAT(0x7);
+ break;
+ default:
+ config |= CONFIG_SET_MAINPIXFORMAT(0x7);
+ break;
+ }
+ }
+
+ /* config data lanes number and enable lanes */
+ data_lanes_en = (0x1 << dsim->lanes) - 1;
+ config |= CONFIG_SET_NUMOFDATLANE(dsim->lanes - 1);
+ config |= CONFIG_SET_LANEEN(0x1 | data_lanes_en << 1);
+
+ dsim_write(dsim, config, DSIM_CONFIG);
+}
+
+static void sec_mipi_dsim_config_dphy(struct sec_mipi_dsim *dsim)
+{
+ struct sec_mipi_dsim_dphy_timing key = { 0 };
+ const struct sec_mipi_dsim_dphy_timing *match = NULL;
+ const struct sec_mipi_dsim_plat_data *pdata = dsim->pdata;
+ uint32_t phytiming = 0, phytiming1 = 0, phytiming2 = 0, timeout = 0;
+ uint32_t hactive, vactive;
+ struct videomode *vmode = &dsim->vmode;
+ struct drm_display_mode mode;
+
+ key.bit_clk = DIV_ROUND_CLOSEST_ULL(dsim->bit_clk, 1000);
+
+ /* '1280x720@60Hz' mode with 2 data lanes
+ * requires special fine tuning for DPHY
+ * TIMING config according to the tests.
+ */
+ if (dsim->lanes == 2) {
+ hactive = vmode->hactive;
+ vactive = vmode->vactive;
+
+ if (hactive == 1280 && vactive == 720) {
+ memset(&mode, 0x0, sizeof(mode));
+ drm_display_mode_from_videomode(vmode, &mode);
+
+ if (drm_mode_vrefresh(&mode) == 60)
+ key.bit_clk >>= 1;
+ }
+ }
+
+ match = bsearch(&key, pdata->dphy_timing, pdata->num_dphy_timing,
+ sizeof(struct sec_mipi_dsim_dphy_timing),
+ pdata->dphy_timing_cmp);
+ if (WARN_ON(!match))
+ return;
+
+ phytiming |= PHYTIMING_SET_M_TLPXCTL(match->lpx) |
+ PHYTIMING_SET_M_THSEXITCTL(match->hs_exit);
+ dsim_write(dsim, phytiming, DSIM_PHYTIMING);
+
+ phytiming1 |= PHYTIMING1_SET_M_TCLKPRPRCTL(match->clk_prepare) |
+ PHYTIMING1_SET_M_TCLKZEROCTL(match->clk_zero) |
+ PHYTIMING1_SET_M_TCLKPOSTCTL(match->clk_post) |
+ PHYTIMING1_SET_M_TCLKTRAILCTL(match->clk_trail);
+ dsim_write(dsim, phytiming1, DSIM_PHYTIMING1);
+
+ phytiming2 |= PHYTIMING2_SET_M_THSPRPRCTL(match->hs_prepare) |
+ PHYTIMING2_SET_M_THSZEROCTL(match->hs_zero) |
+ PHYTIMING2_SET_M_THSTRAILCTL(match->hs_trail);
+ dsim_write(dsim, phytiming2, DSIM_PHYTIMING2);
+
+ timeout |= TIMEOUT_SET_BTAOUT(0xff) |
+ TIMEOUT_SET_LPDRTOUT(0xff);
+ dsim_write(dsim, timeout, DSIM_TIMEOUT);
+}
+
+static void sec_mipi_dsim_init_fifo_pointers(struct sec_mipi_dsim *dsim)
+{
+ uint32_t fifoctrl, fifo_ptrs;
+
+ fifoctrl = dsim_read(dsim, DSIM_FIFOCTRL);
+
+ fifo_ptrs = FIFOCTRL_NINITRX |
+ FIFOCTRL_NINITSFR |
+ FIFOCTRL_NINITI80 |
+ FIFOCTRL_NINITSUB |
+ FIFOCTRL_NINITMAIN;
+
+ fifoctrl &= ~fifo_ptrs;
+ dsim_write(dsim, fifoctrl, DSIM_FIFOCTRL);
+ udelay(500);
+
+ fifoctrl |= fifo_ptrs;
+ dsim_write(dsim, fifoctrl, DSIM_FIFOCTRL);
+ udelay(500);
+}
+
+static void sec_mipi_dsim_config_clkctrl(struct sec_mipi_dsim *dsim)
+{
+ uint32_t clkctrl = 0, data_lanes_en;
+ uint64_t byte_clk, esc_prescaler;
+
+ clkctrl |= CLKCTRL_TXREQUESTHSCLK;
+
+ /* using 1.5Gbps PHY */
+ clkctrl |= CLKCTRL_DPHY_SEL_1P5G;
+
+ clkctrl |= CLKCTRL_ESCCLKEN;
+
+ clkctrl &= ~CLKCTRL_PLLBYPASS;
+
+ clkctrl |= CLKCTRL_BYTECLKSRC_DPHY_PLL;
+
+ clkctrl |= CLKCTRL_BYTECLKEN;
+
+ data_lanes_en = (0x1 << dsim->lanes) - 1;
+ clkctrl |= CLKCTRL_SET_LANEESCCLKEN(0x1 | data_lanes_en << 1);
+
+ /* calculate esc prescaler from byte clock:
+ * EscClk = ByteClk / EscPrescaler;
+ */
+ byte_clk = dsim->bit_clk >> 3;
+ esc_prescaler = DIV_ROUND_UP_ULL(byte_clk, MAX_ESC_CLK_FREQ);
+ clkctrl |= CLKCTRL_SET_ESCPRESCALER(esc_prescaler);
+
+ dsim_write(dsim, clkctrl, DSIM_CLKCTRL);
+}
+
+static void sec_mipi_dsim_set_standby(struct sec_mipi_dsim *dsim,
+ bool standby)
+{
+ uint32_t mdresol = 0;
+
+ mdresol = dsim_read(dsim, DSIM_MDRESOL);
+
+ if (standby)
+ mdresol |= MDRESOL_MAINSTANDBY;
+ else
+ mdresol &= ~MDRESOL_MAINSTANDBY;
+
+ dsim_write(dsim, mdresol, DSIM_MDRESOL);
+}
+
+int sec_mipi_dsim_check_pll_out(void *driver_private,
+ const struct drm_display_mode *mode)
+{
+ int bpp;
+ uint64_t pix_clk, bit_clk, ref_clk;
+ struct sec_mipi_dsim *dsim = driver_private;
+ const struct sec_mipi_dsim_plat_data *pdata = dsim->pdata;
+ const struct dsim_hblank_par *hpar;
+ const struct dsim_pll_pms *pms;
+
+ bpp = mipi_dsi_pixel_format_to_bpp(dsim->format);
+ if (bpp < 0)
+ return -EINVAL;
+
+ pix_clk = mode->clock * 1000;
+ bit_clk = DIV_ROUND_UP_ULL(pix_clk * bpp, dsim->lanes);
+
+ if (bit_clk > pdata->max_data_rate) {
+ dev_err(dsim->dev,
+ "reuest bit clk freq exceeds lane's maximum value\n");
+ return -EINVAL;
+ }
+
+ dsim->pix_clk = DIV_ROUND_UP_ULL(pix_clk, 1000);
+ dsim->bit_clk = DIV_ROUND_UP_ULL(bit_clk, 1000);
+
+ dsim->pms = 0x4210;
+ dsim->hpar = NULL;
+ if (dsim->panel)
+ return 0;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
+ hpar = sec_mipi_dsim_get_hblank_par(mode->name,
+ mode->vrefresh,
+ dsim->lanes);
+ if (!hpar)
+ return -EINVAL;
+ dsim->hpar = hpar;
+
+ pms = sec_mipi_dsim_get_pms(dsim->bit_clk);
+ if (WARN_ON(!pms))
+ return -EINVAL;
+
+ ref_clk = PHY_REF_CLK / 1000;
+ /* TODO: add PMS calculate and check
+ * Only support '1080p@60Hz' for now,
+ * add other modes support later
+ */
+ dsim->pms = PLLCTRL_SET_P(pms->p) |
+ PLLCTRL_SET_M(pms->m) |
+ PLLCTRL_SET_S(pms->s);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(sec_mipi_dsim_check_pll_out);
+
+static void sec_mipi_dsim_bridge_enable(struct drm_bridge *bridge)
+{
+ int ret;
+ struct sec_mipi_dsim *dsim = bridge->driver_private;
+
+ /* At this moment, the dsim bridge's preceding encoder has
+ * already been enabled. So the dsim can be configed here
+ */
+
+ /* config main display mode */
+ sec_mipi_dsim_set_main_mode(dsim);
+
+ /* config dsim dpi */
+ sec_mipi_dsim_config_dpi(dsim);
+
+ /* config dsim pll */
+ ret = sec_mipi_dsim_config_pll(dsim);
+ if (ret) {
+ dev_err(dsim->dev, "dsim pll config failed: %d\n", ret);
+ return;
+ }
+
+ /* config dphy timings */
+ sec_mipi_dsim_config_dphy(dsim);
+
+ /* initialize FIFO pointers */
+ sec_mipi_dsim_init_fifo_pointers(dsim);
+
+ /* prepare panel if exists */
+ if (dsim->panel) {
+ ret = drm_panel_prepare(dsim->panel);
+ if (unlikely(ret)) {
+ dev_err(dsim->dev, "panel prepare failed: %d\n", ret);
+ return;
+ }
+ }
+
+ /* config esc clock, byte clock and etc */
+ sec_mipi_dsim_config_clkctrl(dsim);
+
+ /* enable panel if exists */
+ if (dsim->panel) {
+ ret = drm_panel_enable(dsim->panel);
+ if (unlikely(ret)) {
+ dev_err(dsim->dev, "panel enable failed: %d\n", ret);
+ goto panel_unprepare;
+ }
+ }
+
+ /* enable data transfer of dsim */
+ sec_mipi_dsim_set_standby(dsim, true);
+
+ return;
+
+panel_unprepare:
+ ret = drm_panel_unprepare(dsim->panel);
+ if (unlikely(ret))
+ dev_err(dsim->dev, "panel unprepare failed: %d\n", ret);
+}
+
+static void sec_mipi_dsim_disable_clkctrl(struct sec_mipi_dsim *dsim)
+{
+ uint32_t clkctrl;
+
+ clkctrl = dsim_read(dsim, DSIM_CLKCTRL);
+
+ clkctrl &= ~CLKCTRL_TXREQUESTHSCLK;
+
+ clkctrl &= ~CLKCTRL_ESCCLKEN;
+
+ clkctrl &= ~CLKCTRL_BYTECLKEN;
+
+ dsim_write(dsim, clkctrl, DSIM_CLKCTRL);
+}
+
+static void sec_mipi_dsim_disable_pll(struct sec_mipi_dsim *dsim)
+{
+ uint32_t pllctrl;
+
+ pllctrl = dsim_read(dsim, DSIM_PLLCTRL);
+
+ pllctrl &= ~PLLCTRL_PLLEN;
+
+ dsim_write(dsim, pllctrl, DSIM_PLLCTRL);
+}
+
+static void sec_mipi_dsim_bridge_disable(struct drm_bridge *bridge)
+{
+ int ret;
+ struct sec_mipi_dsim *dsim = bridge->driver_private;
+
+ /* disable panel if exists */
+ if (dsim->panel) {
+ ret = drm_panel_disable(dsim->panel);
+ if (unlikely(ret))
+ dev_err(dsim->dev, "panel disable failed: %d\n", ret);
+ }
+
+ /* disable data transfer of dsim */
+ sec_mipi_dsim_set_standby(dsim, false);
+
+ /* disable esc clock & byte clock */
+ sec_mipi_dsim_disable_clkctrl(dsim);
+
+ /* disable dsim pll */
+ sec_mipi_dsim_disable_pll(dsim);
+
+ /* unprepare panel if exists */
+ if (dsim->panel) {
+ ret = drm_panel_unprepare(dsim->panel);
+ if (unlikely(ret))
+ dev_err(dsim->dev, "panel unprepare failed: %d\n", ret);
+ }
+}
+
+static bool sec_mipi_dsim_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ int private_flags;
+ struct sec_mipi_dsim *dsim = bridge->driver_private;
+
+ /* Since mipi dsi cannot do color conversion,
+ * so the pixel format output by mipi dsi should
+ * be the same with the pixel format recieved by
+ * mipi dsi. And the pixel format information needs
+ * to be passed to CRTC to be checked with the CRTC
+ * attached plane fb pixel format.
+ */
+ switch (dsim->format) {
+ case MIPI_DSI_FMT_RGB888:
+ private_flags = MEDIA_BUS_FMT_RGB888_1X24;
+ break;
+ case MIPI_DSI_FMT_RGB666:
+ private_flags = MEDIA_BUS_FMT_RGB666_1X24_CPADHI;
+ break;
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ private_flags = MEDIA_BUS_FMT_RGB666_1X18;
+ break;
+ case MIPI_DSI_FMT_RGB565:
+ private_flags = MEDIA_BUS_FMT_RGB565_1X16;
+ break;
+ default:
+ return false;
+ }
+
+ adjusted_mode->private_flags = private_flags;
+
+ /* the 'bus_flags' in connector's display_info is useless
+ * for mipi dsim, since dsim only sends packets with no
+ * polarities information in the packets. But the dsim
+ * host has some polarities requirements for the CRTC:
+ * dsim only can accpet active high Vsync, Hsync and DE
+ * signals.
+ */
+ if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) {
+ adjusted_mode->flags &= ~DRM_MODE_FLAG_NHSYNC;
+ adjusted_mode->flags |= DRM_MODE_FLAG_PHSYNC;
+ }
+
+ if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) {
+ adjusted_mode->flags &= ~DRM_MODE_FLAG_NVSYNC;
+ adjusted_mode->flags |= DRM_MODE_FLAG_PVSYNC;
+ }
+
+ return true;
+}
+
+static void sec_mipi_dsim_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct sec_mipi_dsim *dsim = bridge->driver_private;
+
+ /* This hook is called when the display pipe is completely
+ * off. And since the pm runtime is implemented, the dsim
+ * hardware cannot be accessed at this moment. So move all
+ * the mode_set config to ->enable() hook.
+ * And this hook is called only when 'mode_changed' is true,
+ * so it is called not every time atomic commit.
+ */
+
+ /* workaround for CEA standard mode "1280x720@60"
+ * display on 4 data lanes with Non-burst with sync
+ * pulse DSI mode, since use the standard horizontal
+ * timings cannot display correctly. And this code
+ * cannot be put into the dsim Bridge's mode_fixup,
+ * since the DSI device lane number change always
+ * happens after that.
+ */
+ if (!strcmp(mode->name, "1280x720") &&
+ mode->vrefresh == 60 &&
+ dsim->lanes == 4 &&
+ dsim->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
+ adjusted_mode->hsync_start += 2;
+ adjusted_mode->hsync_end += 2;
+ adjusted_mode->htotal += 2;
+ }
+
+ drm_display_mode_to_videomode(adjusted_mode, &dsim->vmode);
+}
+
+static const struct drm_bridge_funcs sec_mipi_dsim_bridge_funcs = {
+ .attach = sec_mipi_dsim_bridge_attach,
+ .detach = sec_mipi_dsim_bridge_detach,
+ .enable = sec_mipi_dsim_bridge_enable,
+ .disable = sec_mipi_dsim_bridge_disable,
+ .mode_set = sec_mipi_dsim_bridge_mode_set,
+ .mode_fixup = sec_mipi_dsim_bridge_mode_fixup,
+};
+
+void sec_mipi_dsim_suspend(struct device *dev)
+{
+ struct sec_mipi_dsim *dsim = dev_get_drvdata(dev);
+
+ /* TODO: add dsim reset */
+
+ clk_disable_unprepare(dsim->clk_cfg);
+
+ clk_disable_unprepare(dsim->clk_pllref);
+}
+EXPORT_SYMBOL(sec_mipi_dsim_suspend);
+
+void sec_mipi_dsim_resume(struct device *dev)
+{
+ struct sec_mipi_dsim *dsim = dev_get_drvdata(dev);
+
+ clk_prepare_enable(dsim->clk_pllref);
+
+ clk_prepare_enable(dsim->clk_cfg);
+
+ sec_mipi_dsim_irq_init(dsim);
+
+ /* TODO: add dsim de-reset */
+}
+EXPORT_SYMBOL(sec_mipi_dsim_resume);
+
+static void __maybe_unused sec_mipi_dsim_irq_mask(struct sec_mipi_dsim *dsim,
+ int irq_idx)
+{
+ uint32_t intmsk;
+
+ intmsk = dsim_read(dsim, DSIM_INTMSK);
+
+ switch (irq_idx) {
+ case PLLSTABLE:
+ intmsk |= INTMSK_MSKPLLSTABLE;
+ break;
+ case SWRSTRELEASE:
+ intmsk |= INTMSK_MSKSWRELEASE;
+ break;
+ case SFRPLFIFOEMPTY:
+ intmsk |= INTMSK_MSKSFRPLFIFOEMPTY;
+ break;
+ case SFRPHFIFOEMPTY:
+ intmsk |= INTMSK_MSKSFRPHFIFOEMPTY;
+ break;
+ case FRAMEDONE:
+ intmsk |= INTMSK_MSKFRAMEDONE;
+ break;
+ case LPDRTOUT:
+ intmsk |= INTMSK_MSKLPDRTOUT;
+ break;
+ case TATOUT:
+ intmsk |= INTMSK_MSKTATOUT;
+ break;
+ case RXDATDONE:
+ intmsk |= INTMSK_MSKRXDATDONE;
+ break;
+ case RXTE:
+ intmsk |= INTMSK_MSKRXTE;
+ break;
+ case RXACK:
+ intmsk |= INTMSK_MSKRXACK;
+ break;
+ default:
+ /* unsupported irq */
+ return;
+ }
+
+ writel(intmsk, dsim->base + DSIM_INTMSK);
+}
+
+static void sec_mipi_dsim_irq_unmask(struct sec_mipi_dsim *dsim,
+ int irq_idx)
+{
+ uint32_t intmsk;
+
+ intmsk = dsim_read(dsim, DSIM_INTMSK);
+
+ switch (irq_idx) {
+ case PLLSTABLE:
+ intmsk &= ~INTMSK_MSKPLLSTABLE;
+ break;
+ case SWRSTRELEASE:
+ intmsk &= ~INTMSK_MSKSWRELEASE;
+ break;
+ case SFRPLFIFOEMPTY:
+ intmsk &= ~INTMSK_MSKSFRPLFIFOEMPTY;
+ break;
+ case SFRPHFIFOEMPTY:
+ intmsk &= ~INTMSK_MSKSFRPHFIFOEMPTY;
+ break;
+ case FRAMEDONE:
+ intmsk &= ~INTMSK_MSKFRAMEDONE;
+ break;
+ case LPDRTOUT:
+ intmsk &= ~INTMSK_MSKLPDRTOUT;
+ break;
+ case TATOUT:
+ intmsk &= ~INTMSK_MSKTATOUT;
+ break;
+ case RXDATDONE:
+ intmsk &= ~INTMSK_MSKRXDATDONE;
+ break;
+ case RXTE:
+ intmsk &= ~INTMSK_MSKRXTE;
+ break;
+ case RXACK:
+ intmsk &= ~INTMSK_MSKRXACK;
+ break;
+ default:
+ /* unsupported irq */
+ return;
+ }
+
+ dsim_write(dsim, intmsk, DSIM_INTMSK);
+}
+
+/* write 1 clear irq */
+static void sec_mipi_dsim_irq_clear(struct sec_mipi_dsim *dsim,
+ int irq_idx)
+{
+ uint32_t intsrc = 0;
+
+ switch (irq_idx) {
+ case PLLSTABLE:
+ intsrc |= INTSRC_PLLSTABLE;
+ break;
+ case SWRSTRELEASE:
+ intsrc |= INTSRC_SWRSTRELEASE;
+ break;
+ case SFRPLFIFOEMPTY:
+ intsrc |= INTSRC_SFRPLFIFOEMPTY;
+ break;
+ case SFRPHFIFOEMPTY:
+ intsrc |= INTSRC_SFRPHFIFOEMPTY;
+ break;
+ case FRAMEDONE:
+ intsrc |= INTSRC_FRAMEDONE;
+ break;
+ case LPDRTOUT:
+ intsrc |= INTSRC_LPDRTOUT;
+ break;
+ case TATOUT:
+ intsrc |= INTSRC_TATOUT;
+ break;
+ case RXDATDONE:
+ intsrc |= INTSRC_RXDATDONE;
+ break;
+ case RXTE:
+ intsrc |= INTSRC_RXTE;
+ break;
+ case RXACK:
+ intsrc |= INTSRC_RXACK;
+ break;
+ default:
+ /* unsupported irq */
+ return;
+ }
+
+ dsim_write(dsim, intsrc, DSIM_INTSRC);
+}
+
+static void sec_mipi_dsim_irq_init(struct sec_mipi_dsim *dsim)
+{
+ sec_mipi_dsim_irq_unmask(dsim, PLLSTABLE);
+ sec_mipi_dsim_irq_unmask(dsim, SWRSTRELEASE);
+
+ if (dsim->panel) {
+ sec_mipi_dsim_irq_unmask(dsim, SFRPLFIFOEMPTY);
+ sec_mipi_dsim_irq_unmask(dsim, SFRPHFIFOEMPTY);
+ sec_mipi_dsim_irq_unmask(dsim, LPDRTOUT);
+ sec_mipi_dsim_irq_unmask(dsim, TATOUT);
+ sec_mipi_dsim_irq_unmask(dsim, RXDATDONE);
+ sec_mipi_dsim_irq_unmask(dsim, RXTE);
+ sec_mipi_dsim_irq_unmask(dsim, RXACK);
+ }
+}
+
+static irqreturn_t sec_mipi_dsim_irq_handler(int irq, void *data)
+{
+ uint32_t intsrc, status;
+ struct sec_mipi_dsim *dsim = data;
+
+ intsrc = dsim_read(dsim, DSIM_INTSRC);
+ status = dsim_read(dsim, DSIM_STATUS);
+
+ if (WARN_ON(!intsrc)) {
+ dev_err(dsim->dev, "interrupt is not from dsim\n");
+ return IRQ_NONE;
+ }
+
+ if (WARN_ON(!(intsrc & INTSRC_MASK))) {
+ dev_warn(dsim->dev, "unenable irq happens: %#x\n", intsrc);
+ /* just clear irqs */
+ dsim_write(dsim, intsrc, DSIM_INTSRC);
+ return IRQ_NONE;
+ }
+
+ if (intsrc & INTSRC_PLLSTABLE) {
+ WARN_ON(!(status & STATUS_PLLSTABLE));
+ sec_mipi_dsim_irq_clear(dsim, PLLSTABLE);
+ complete(&dsim->pll_stable);
+ }
+
+ if (intsrc & INTSRC_SWRSTRELEASE)
+ sec_mipi_dsim_irq_clear(dsim, SWRSTRELEASE);
+
+ if (intsrc & INTSRC_SFRPLFIFOEMPTY) {
+ sec_mipi_dsim_irq_clear(dsim, SFRPLFIFOEMPTY);
+ complete(&dsim->pl_tx_done);
+ }
+
+ if (intsrc & INTSRC_SFRPHFIFOEMPTY) {
+ sec_mipi_dsim_irq_clear(dsim, SFRPHFIFOEMPTY);
+ complete(&dsim->ph_tx_done);
+ }
+
+ if (WARN_ON(intsrc & INTSRC_LPDRTOUT)) {
+ sec_mipi_dsim_irq_clear(dsim, LPDRTOUT);
+ dev_warn(dsim->dev, "LP RX timeout\n");
+ }
+
+ if (WARN_ON(intsrc & INTSRC_TATOUT)) {
+ sec_mipi_dsim_irq_clear(dsim, TATOUT);
+ dev_warn(dsim->dev, "Turns around Acknowledge timeout\n");
+ }
+
+ if (intsrc & INTSRC_RXDATDONE) {
+ sec_mipi_dsim_irq_clear(dsim, RXDATDONE);
+ complete(&dsim->rx_done);
+ }
+
+ if (intsrc & INTSRC_RXTE) {
+ sec_mipi_dsim_irq_clear(dsim, RXTE);
+ dev_dbg(dsim->dev, "TE Rx trigger received\n");
+ }
+
+ if (intsrc & INTSRC_RXACK) {
+ sec_mipi_dsim_irq_clear(dsim, RXACK);
+ dev_dbg(dsim->dev, "ACK Rx trigger received\n");
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int sec_mipi_dsim_connector_get_modes(struct drm_connector *connector)
+{
+ struct sec_mipi_dsim *dsim = conn_to_sec_mipi_dsim(connector);
+
+ if (WARN_ON(!dsim->panel))
+ return -ENODEV;
+
+ return drm_panel_get_modes(dsim->panel);
+}
+
+static const struct drm_connector_helper_funcs
+ sec_mipi_dsim_connector_helper_funcs = {
+ .get_modes = sec_mipi_dsim_connector_get_modes,
+};
+
+static enum drm_connector_status
+ sec_mipi_dsim_connector_detect(struct drm_connector *connector,
+ bool force)
+{
+ /* TODO: add support later */
+
+ return connector_status_connected;
+}
+
+static const struct drm_connector_funcs sec_mipi_dsim_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .detect = sec_mipi_dsim_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = drm_connector_cleanup,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+int sec_mipi_dsim_bind(struct device *dev, struct device *master, void *data,
+ struct drm_encoder *encoder, struct resource *res,
+ int irq, const struct sec_mipi_dsim_plat_data *pdata)
+{
+ int ret, version;
+ struct drm_device *drm_dev = data;
+ struct drm_bridge *bridge;
+ struct drm_connector *connector;
+ struct sec_mipi_dsim *dsim;
+
+ dev_dbg(dev, "sec-dsim bridge bind begin\n");
+
+ dsim = devm_kzalloc(dev, sizeof(*dsim), GFP_KERNEL);
+ if (!dsim) {
+ dev_err(dev, "Unable to allocate 'dsim'\n");
+ return -ENOMEM;
+ }
+
+ dsim->dev = dev;
+ dsim->irq = irq;
+ dsim->pdata = pdata;
+ dsim->encoder = encoder;
+
+ dsim->dsi_host.ops = &sec_mipi_dsim_host_ops;
+ dsim->dsi_host.dev = dev;
+
+ dsim->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(dsim->base))
+ return PTR_ERR(dsim->base);
+
+ dsim->clk_pllref = devm_clk_get(dev, "pll-ref");
+ if (IS_ERR(dsim->clk_pllref)) {
+ ret = PTR_ERR(dsim->clk_pllref);
+ dev_err(dev, "Unable to get phy pll reference clock: %d\n", ret);
+ return ret;
+ }
+
+ dsim->clk_cfg = devm_clk_get(dev, "cfg");
+ if (IS_ERR(dsim->clk_cfg)) {
+ ret = PTR_ERR(dsim->clk_cfg);
+ dev_err(dev, "Unable to get configuration clock: %d\n", ret);
+ return ret;
+ }
+
+ clk_prepare_enable(dsim->clk_cfg);
+ version = dsim_read(dsim, DSIM_VERSION);
+ WARN_ON(version != pdata->version);
+ clk_disable_unprepare(dsim->clk_cfg);
+
+ dev_info(dev, "version number is %#x\n", version);
+
+ /* TODO: set pll ref clock rate to be fixed with 27MHz */
+ ret = clk_set_rate(dsim->clk_pllref, PHY_REF_CLK);
+ if (ret) {
+ dev_err(dev, "failed to set pll ref clock rate\n");
+ return ret;
+ }
+
+ ret = devm_request_irq(dev, dsim->irq,
+ sec_mipi_dsim_irq_handler,
+ 0, dev_name(dev), dsim);
+ if (ret) {
+ dev_err(dev, "failed to request dsim irq: %d\n", ret);
+ return ret;
+ }
+
+ init_completion(&dsim->pll_stable);
+ init_completion(&dsim->ph_tx_done);
+ init_completion(&dsim->pl_tx_done);
+ init_completion(&dsim->rx_done);
+
+ /* Initialize and attach sec dsim bridge */
+ bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
+ if (!bridge) {
+ dev_err(dev, "Unable to allocate 'bridge'\n");
+ return -ENOMEM;
+ }
+
+ /* mipi dsi host needs to be registered before bridge attach, since:
+ * 1. Have Panel
+ * The 'mipi_dsi_host_register' will allocate a mipi_dsi_device
+ * if the dsi host node has a panel child node in DTB. And dsi
+ * host ->attach() will be called in panel's probe().
+ *
+ * 2. Have Bridge
+ * The dsi host ->attach() will be called through the below
+ * 'drm_bridge_attach()' which will attach next bridge in a
+ * chain.
+ */
+ ret = mipi_dsi_host_register(&dsim->dsi_host);
+ if (ret) {
+ dev_err(dev, "Unable to register mipi dsi host: %d\n", ret);
+ return ret;
+ }
+
+ dsim->bridge = bridge;
+ bridge->driver_private = dsim;
+ bridge->funcs = &sec_mipi_dsim_bridge_funcs;
+ bridge->of_node = dev->of_node;
+ bridge->encoder = encoder;
+ encoder->bridge = bridge;
+
+ dev_set_drvdata(dev, dsim);
+
+ /* attach sec dsim bridge and its next bridge if exists */
+ ret = drm_bridge_attach(drm_dev, bridge);
+ if (ret) {
+ dev_err(dev, "Failed to attach bridge: %s\n", dev_name(dev));
+ mipi_dsi_host_unregister(&dsim->dsi_host);
+ return ret;
+ }
+
+ if (dsim->panel) {
+ /* A panel has been attached */
+ connector = &dsim->connector;
+
+ drm_connector_helper_add(connector,
+ &sec_mipi_dsim_connector_helper_funcs);
+ ret = drm_connector_init(drm_dev, connector,
+ &sec_mipi_dsim_connector_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+ if (ret)
+ goto host_unregister;
+
+ /* TODO */
+ connector->dpms = DRM_MODE_DPMS_OFF;
+
+ ret = drm_mode_connector_attach_encoder(connector, encoder);
+ if (ret)
+ goto cleanup_connector;
+
+ ret = drm_panel_attach(dsim->panel, connector);
+ if (ret)
+ goto cleanup_connector;
+ }
+
+ dev_dbg(dev, "sec-dsim bridge bind end\n");
+
+ return 0;
+
+cleanup_connector:
+ drm_connector_cleanup(connector);
+host_unregister:
+ mipi_dsi_host_unregister(&dsim->dsi_host);
+ return ret;
+}
+EXPORT_SYMBOL(sec_mipi_dsim_bind);
+
+void sec_mipi_dsim_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct sec_mipi_dsim *dsim = dev_get_drvdata(dev);
+
+ if (dsim->panel) {
+ drm_panel_detach(dsim->panel);
+ drm_connector_cleanup(&dsim->connector);
+ dsim->panel = NULL;
+ }
+
+ drm_bridge_detach(dsim->bridge);
+
+ mipi_dsi_host_unregister(&dsim->dsi_host);
+}
+EXPORT_SYMBOL(sec_mipi_dsim_unbind);
+
+MODULE_DESCRIPTION("Samsung MIPI DSI Host Controller bridge driver");
+MODULE_AUTHOR("Fancy Fang <chen.fang@nxp.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
index 17c915d9a03e..aab936dc5ea3 100644
--- a/drivers/gpu/drm/cirrus/cirrus_mode.c
+++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
@@ -494,7 +494,7 @@ static struct drm_encoder *cirrus_connector_best_encoder(struct drm_connector
int enc_id = connector->encoder_ids[0];
/* pick the encoder ids */
if (enc_id)
- return drm_encoder_find(connector->dev, enc_id);
+ return drm_encoder_find(connector->dev, NULL, enc_id);
return NULL;
}
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index dd6fff1c98d6..79852b4e28cb 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -414,7 +414,7 @@ drm_atomic_replace_property_blob(struct drm_property_blob **blob,
}
static int
-drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc,
+drm_atomic_replace_property_blob_from_id(struct drm_device *dev,
struct drm_property_blob **blob,
uint64_t blob_id,
ssize_t expected_size,
@@ -423,7 +423,7 @@ drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc,
struct drm_property_blob *new_blob = NULL;
if (blob_id != 0) {
- new_blob = drm_property_lookup_blob(crtc->dev, blob_id);
+ new_blob = drm_property_lookup_blob(dev, blob_id);
if (new_blob == NULL)
return -EINVAL;
@@ -473,7 +473,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
drm_property_unreference_blob(mode);
return ret;
} else if (property == config->degamma_lut_property) {
- ret = drm_atomic_replace_property_blob_from_id(crtc,
+ ret = drm_atomic_replace_property_blob_from_id(dev,
&state->degamma_lut,
val,
-1,
@@ -481,7 +481,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
state->color_mgmt_changed |= replaced;
return ret;
} else if (property == config->ctm_property) {
- ret = drm_atomic_replace_property_blob_from_id(crtc,
+ ret = drm_atomic_replace_property_blob_from_id(dev,
&state->ctm,
val,
sizeof(struct drm_color_ctm),
@@ -489,7 +489,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
state->color_mgmt_changed |= replaced;
return ret;
} else if (property == config->gamma_lut_property) {
- ret = drm_atomic_replace_property_blob_from_id(crtc,
+ ret = drm_atomic_replace_property_blob_from_id(dev,
&state->gamma_lut,
val,
-1,
@@ -689,12 +689,12 @@ int drm_atomic_plane_set_property(struct drm_plane *plane,
struct drm_mode_config *config = &dev->mode_config;
if (property == config->prop_fb_id) {
- struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, val);
+ struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, NULL, val);
drm_atomic_set_fb_for_plane(state, fb);
if (fb)
drm_framebuffer_unreference(fb);
} else if (property == config->prop_crtc_id) {
- struct drm_crtc *crtc = drm_crtc_find(dev, val);
+ struct drm_crtc *crtc = drm_crtc_find(dev, NULL, val);
return drm_atomic_set_crtc_for_plane(state, crtc);
} else if (property == config->prop_crtc_x) {
state->crtc_x = U642I64(val);
@@ -979,9 +979,11 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,
{
struct drm_device *dev = connector->dev;
struct drm_mode_config *config = &dev->mode_config;
+ bool replaced = false;
+ int ret;
if (property == config->prop_crtc_id) {
- struct drm_crtc *crtc = drm_crtc_find(dev, val);
+ struct drm_crtc *crtc = drm_crtc_find(dev, NULL, val);
return drm_atomic_set_crtc_for_connector(state, crtc);
} else if (property == config->dpms_property) {
/* setting DPMS property requires special handling, which
@@ -989,12 +991,42 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,
* now?) atomic writes to DPMS property:
*/
return -EINVAL;
+ } else if (property == config->link_status_property) {
+ /* Never downgrade from GOOD to BAD on userspace's request here,
+ * only hw issues can do that.
+ *
+ * For an atomic property the userspace doesn't need to be able
+ * to understand all the properties, but needs to be able to
+ * restore the state it wants on VT switch. So if the userspace
+ * tries to change the link_status from GOOD to BAD, driver
+ * silently rejects it and returns a 0. This prevents userspace
+ * from accidently breaking the display when it restores the
+ * state.
+ */
+ if (state->link_status != DRM_LINK_STATUS_GOOD)
+ state->link_status = val;
+ } else if (property == config->hdr_source_metadata_property) {
+ ret = drm_atomic_replace_property_blob_from_id(dev,
+ &state->hdr_source_metadata_blob_ptr,
+ val,
+ -1,
+ &replaced);
+ state->hdr_metadata_changed |= replaced;
+ if (ret < 0)
+ return ret;
+
+ if (connector->funcs->atomic_set_property) {
+ return connector->funcs->atomic_set_property(connector,
+ state, property, val);
+ }
} else if (connector->funcs->atomic_set_property) {
return connector->funcs->atomic_set_property(connector,
state, property, val);
} else {
return -EINVAL;
}
+
+ return 0;
}
EXPORT_SYMBOL(drm_atomic_connector_set_property);
@@ -1025,6 +1057,11 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
*val = (state->crtc) ? state->crtc->base.id : 0;
} else if (property == config->dpms_property) {
*val = connector->dpms;
+ } else if (property == config->link_status_property) {
+ *val = state->link_status;
+ } else if (property == config->hdr_source_metadata_property) {
+ *val = (state->hdr_source_metadata_blob_ptr) ?
+ state->hdr_source_metadata_blob_ptr->base.id : 0;
} else if (connector->funcs->atomic_get_property) {
return connector->funcs->atomic_get_property(connector,
state, property, val);
@@ -1668,7 +1705,7 @@ retry:
goto out;
}
- obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
+ obj = drm_mode_object_find(dev, file_priv, obj_id, DRM_MODE_OBJECT_ANY);
if (!obj) {
ret = -ENOENT;
goto out;
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 50acd799babe..ccd2500c5aff 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -518,6 +518,13 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
connector_state);
if (ret)
return ret;
+ if (connector->state->crtc) {
+ crtc_state = drm_atomic_get_existing_crtc_state(state,
+ connector->state->crtc);
+ if (connector->state->link_status !=
+ connector_state->link_status)
+ crtc_state->connectors_changed = true;
+ }
}
/*
@@ -2271,6 +2278,8 @@ static int update_output_state(struct drm_atomic_state *state,
NULL);
if (ret)
return ret;
+ /* Make sure legacy setCrtc always re-trains */
+ conn_state->link_status = DRM_LINK_STATUS_GOOD;
}
}
@@ -2314,6 +2323,12 @@ static int update_output_state(struct drm_atomic_state *state,
*
* Provides a default crtc set_config handler using the atomic driver interface.
*
+ * NOTE: For backwards compatibility with old userspace this automatically
+ * resets the "link-status" property to GOOD, to force any link
+ * re-training. The SETCRTC ioctl does not define whether an update does
+ * need a full modeset or just a plane update, hence we're allowed to do
+ * that. See also drm_mode_connector_set_link_status_property().
+ *
* Returns:
* Returns 0 on success, negative errno numbers on failure.
*/
@@ -2957,7 +2972,7 @@ struct drm_encoder *
drm_atomic_helper_best_encoder(struct drm_connector *connector)
{
WARN_ON(connector->encoder_ids[1]);
- return drm_encoder_find(connector->dev, connector->encoder_ids[0]);
+ return drm_encoder_find(connector->dev, NULL, connector->encoder_ids[0]);
}
EXPORT_SYMBOL(drm_atomic_helper_best_encoder);
@@ -3243,6 +3258,10 @@ __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
memcpy(state, connector->state, sizeof(*state));
if (state->crtc)
drm_connector_reference(connector);
+ if (state->hdr_source_metadata_blob_ptr)
+ drm_property_reference_blob(state->hdr_source_metadata_blob_ptr);
+
+ state->hdr_metadata_changed = false;
}
EXPORT_SYMBOL(__drm_atomic_helper_connector_duplicate_state);
@@ -3370,6 +3389,8 @@ __drm_atomic_helper_connector_destroy_state(struct drm_connector_state *state)
*/
if (state->crtc)
drm_connector_unreference(state->connector);
+ if (state->hdr_source_metadata_blob_ptr)
+ drm_property_unreference_blob(state->hdr_source_metadata_blob_ptr);
}
EXPORT_SYMBOL(__drm_atomic_helper_connector_destroy_state);
diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c
index 6b143514a566..b2ab53075de9 100644
--- a/drivers/gpu/drm/drm_auth.c
+++ b/drivers/gpu/drm/drm_auth.c
@@ -31,6 +31,7 @@
#include <drm/drmP.h>
#include "drm_internal.h"
#include "drm_legacy.h"
+#include <drm/drm_lease.h>
/**
* DOC: master and authentication
@@ -93,7 +94,7 @@ int drm_authmagic(struct drm_device *dev, void *data,
return file ? 0 : -EINVAL;
}
-static struct drm_master *drm_master_create(struct drm_device *dev)
+struct drm_master *drm_master_create(struct drm_device *dev)
{
struct drm_master *master;
@@ -107,6 +108,14 @@ static struct drm_master *drm_master_create(struct drm_device *dev)
idr_init(&master->magic_map);
master->dev = dev;
+ /* initialize the tree of output resource lessees */
+ master->lessor = NULL;
+ master->lessee_id = 0;
+ INIT_LIST_HEAD(&master->lessees);
+ INIT_LIST_HEAD(&master->lessee_list);
+ idr_init(&master->leases);
+ idr_init(&master->lessee_idr);
+
return master;
}
@@ -189,6 +198,12 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
goto out_unlock;
}
+ if (file_priv->master->lessor != NULL) {
+ DRM_DEBUG_LEASE("Attempt to set lessee %d as master\n", file_priv->master->lessee_id);
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
ret = drm_set_master(dev, file_priv, false);
out_unlock:
mutex_unlock(&dev->master_mutex);
@@ -215,6 +230,12 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
if (!dev->master)
goto out_unlock;
+ if (file_priv->master->lessor != NULL) {
+ DRM_DEBUG_LEASE("Attempt to drop lessee %d as master\n", file_priv->master->lessee_id);
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
ret = 0;
drm_drop_master(dev, file_priv);
out_unlock:
@@ -270,6 +291,13 @@ void drm_master_release(struct drm_file *file_priv)
if (dev->master == file_priv->master)
drm_drop_master(dev, file_priv);
out:
+ if (drm_core_check_feature(dev, DRIVER_MODESET) && file_priv->is_master) {
+ /* Revoke any leases held by this or lessees, but only if
+ * this is the "real" master
+ */
+ drm_lease_revoke(master);
+ }
+
/* drop the master reference held by the file priv */
if (file_priv->master)
drm_master_put(&file_priv->master);
@@ -288,7 +316,7 @@ out:
*/
bool drm_is_current_master(struct drm_file *fpriv)
{
- return fpriv->is_master && fpriv->master == fpriv->minor->dev->master;
+ return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master;
}
EXPORT_SYMBOL(drm_is_current_master);
@@ -310,12 +338,18 @@ static void drm_master_destroy(struct kref *kref)
struct drm_master *master = container_of(kref, struct drm_master, refcount);
struct drm_device *dev = master->dev;
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ drm_lease_destroy(master);
+
if (dev->driver->master_destroy)
dev->driver->master_destroy(dev, master);
drm_legacy_master_rmmaps(dev, master);
idr_destroy(&master->magic_map);
+ idr_destroy(&master->leases);
+ idr_destroy(&master->lessee_idr);
+
kfree(master->unique);
kfree(master);
}
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c
index adb1dd7fde5f..3ff9495b28d6 100644
--- a/drivers/gpu/drm/drm_bufs.c
+++ b/drivers/gpu/drm/drm_bufs.c
@@ -177,7 +177,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
switch (map->type) {
case _DRM_REGISTERS:
case _DRM_FRAME_BUFFER:
-#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__arm__)
+#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__arm__) && !defined(__aarch64__)
if (map->offset + (map->size-1) < map->offset ||
map->offset < virt_to_phys(high_memory)) {
kfree(map);
diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c
index d28ffdd2b929..d4a037391dd7 100644
--- a/drivers/gpu/drm/drm_color_mgmt.c
+++ b/drivers/gpu/drm/drm_color_mgmt.c
@@ -188,7 +188,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
return -EINVAL;
drm_modeset_lock_all(dev);
- crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
+ crtc = drm_crtc_find(dev, file_priv, crtc_lut->crtc_id);
if (!crtc) {
ret = -ENOENT;
goto out;
@@ -260,7 +260,7 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev,
return -EINVAL;
drm_modeset_lock_all(dev);
- crtc = drm_crtc_find(dev, crtc_lut->crtc_id);
+ crtc = drm_crtc_find(dev, file_priv, crtc_lut->crtc_id);
if (!crtc) {
ret = -ENOENT;
goto out;
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 0e934a9ac63c..65beb5b411bb 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -244,6 +244,14 @@ int drm_connector_init(struct drm_device *dev,
drm_object_attach_property(&connector->base,
config->dpms_property, 0);
+ drm_object_attach_property(&connector->base,
+ config->link_status_property,
+ 0);
+
+ drm_object_attach_property(&connector->base,
+ config->non_desktop_property,
+ 0);
+
if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
drm_object_attach_property(&connector->base, config->prop_crtc_id, 0);
}
@@ -519,6 +527,12 @@ static const struct drm_prop_enum_list drm_dpms_enum_list[] = {
};
DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
+static const struct drm_prop_enum_list drm_link_status_enum_list[] = {
+ { DRM_MODE_LINK_STATUS_GOOD, "Good" },
+ { DRM_MODE_LINK_STATUS_BAD, "Bad" },
+};
+DRM_ENUM_NAME_FN(drm_get_link_status_name, drm_link_status_enum_list)
+
/**
* drm_display_info_set_bus_formats - set the supported bus formats
* @info: display info to store bus formats in
@@ -635,6 +649,25 @@ int drm_connector_create_standard_properties(struct drm_device *dev)
return -ENOMEM;
dev->mode_config.tile_property = prop;
+ prop = drm_property_create(dev, DRM_MODE_PROP_BLOB,
+ "HDR_SOURCE_METADATA", 0);
+
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.hdr_source_metadata_property = prop;
+
+ prop = drm_property_create_enum(dev, 0, "link-status",
+ drm_link_status_enum_list,
+ ARRAY_SIZE(drm_link_status_enum_list));
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.link_status_property = prop;
+
+ prop = drm_property_create_bool(dev, DRM_MODE_PROP_IMMUTABLE, "non-desktop");
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.non_desktop_property = prop;
+
return 0;
}
@@ -954,6 +987,10 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
if (edid)
size = EDID_LENGTH * (1 + edid->extensions);
+ drm_object_property_set_value(&connector->base,
+ dev->mode_config.non_desktop_property,
+ connector->display_info.non_desktop);
+
ret = drm_property_replace_global_blob(dev,
&connector->edid_blob_ptr,
size,
@@ -964,6 +1001,36 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
}
EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
+/**
+ * drm_mode_connector_set_link_status_property - Set link status property of a connector
+ * @connector: drm connector
+ * @link_status: new value of link status property (0: Good, 1: Bad)
+ *
+ * In usual working scenario, this link status property will always be set to
+ * "GOOD". If something fails during or after a mode set, the kernel driver
+ * may set this link status property to "BAD". The caller then needs to send a
+ * hotplug uevent for userspace to re-check the valid modes through
+ * GET_CONNECTOR_IOCTL and retry modeset.
+ *
+ * Note: Drivers cannot rely on userspace to support this property and
+ * issue a modeset. As such, they may choose to handle issues (like
+ * re-training a link) without userspace's intervention.
+ *
+ * The reason for adding this property is to handle link training failures, but
+ * it is not limited to DP or link training. For example, if we implement
+ * asynchronous setcrtc, this property can be used to report any failures in that.
+ */
+void drm_mode_connector_set_link_status_property(struct drm_connector *connector,
+ uint64_t link_status)
+{
+ struct drm_device *dev = connector->dev;
+
+ drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+ connector->state->link_status = link_status;
+ drm_modeset_unlock(&dev->mode_config.connection_mutex);
+}
+EXPORT_SYMBOL(drm_mode_connector_set_link_status_property);
+
int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
struct drm_property *property,
uint64_t value)
@@ -1043,7 +1110,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
mutex_lock(&dev->mode_config.mutex);
- connector = drm_connector_lookup(dev, out_resp->connector_id);
+ connector = drm_connector_lookup(dev, file_priv, out_resp->connector_id);
if (!connector) {
ret = -ENOENT;
goto out_unlock;
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 2d7bedf28647..50f498231dc4 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -419,6 +419,13 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
return -ENOMEM;
dev->mode_config.gamma_lut_size_property = prop;
+ prop = drm_property_create(dev,
+ DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_BLOB,
+ "IN_FORMATS", 0);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.modifiers_property = prop;
+
return 0;
}
@@ -446,11 +453,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
struct drm_crtc *crtc;
struct drm_encoder *encoder;
int ret = 0;
- int connector_count = 0;
- int crtc_count = 0;
int fb_count = 0;
- int encoder_count = 0;
int copied = 0;
+ int count = 0;
uint32_t __user *fb_id;
uint32_t __user *crtc_id;
uint32_t __user *connector_id;
@@ -484,69 +489,60 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
card_res->count_fbs = fb_count;
mutex_unlock(&file_priv->fbs_lock);
- /* mode_config.mutex protects the connector list against e.g. DP MST
- * connector hot-adding. CRTC/Plane lists are invariant. */
- mutex_lock(&dev->mode_config.mutex);
- drm_for_each_crtc(crtc, dev)
- crtc_count++;
-
- drm_for_each_connector(connector, dev)
- connector_count++;
-
- drm_for_each_encoder(encoder, dev)
- encoder_count++;
-
card_res->max_height = dev->mode_config.max_height;
card_res->min_height = dev->mode_config.min_height;
card_res->max_width = dev->mode_config.max_width;
card_res->min_width = dev->mode_config.min_width;
/* CRTCs */
- if (card_res->count_crtcs >= crtc_count) {
- copied = 0;
- crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr;
- drm_for_each_crtc(crtc, dev) {
- if (put_user(crtc->base.id, crtc_id + copied)) {
- ret = -EFAULT;
- goto out;
+ crtc_id = u64_to_user_ptr(card_res->crtc_id_ptr);
+ mutex_lock(&dev->mode_config.mutex);
+ drm_for_each_crtc(crtc, dev) {
+ if (drm_lease_held(file_priv, crtc->base.id)) {
+ if (count < card_res->count_crtcs &&
+ put_user(crtc->base.id, crtc_id + count)) {
+ mutex_unlock(&dev->mode_config.mutex);
+ return -EFAULT;
}
- copied++;
+ count++;
}
}
- card_res->count_crtcs = crtc_count;
+ mutex_unlock(&dev->mode_config.mutex);
+ card_res->count_crtcs = count;
/* Encoders */
- if (card_res->count_encoders >= encoder_count) {
- copied = 0;
- encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr;
- drm_for_each_encoder(encoder, dev) {
- if (put_user(encoder->base.id, encoder_id +
- copied)) {
- ret = -EFAULT;
- goto out;
- }
- copied++;
+ count = 0;
+ encoder_id = u64_to_user_ptr(card_res->encoder_id_ptr);
+ mutex_lock(&dev->mode_config.mutex);
+ drm_for_each_encoder(encoder, dev) {
+ if (count < card_res->count_encoders &&
+ put_user(encoder->base.id, encoder_id + count)) {
+ mutex_unlock(&dev->mode_config.mutex);
+ return -EFAULT;
}
+ count++;
}
- card_res->count_encoders = encoder_count;
+ mutex_unlock(&dev->mode_config.mutex);
+ card_res->count_encoders = count;
+
/* Connectors */
- if (card_res->count_connectors >= connector_count) {
- copied = 0;
- connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr;
- drm_for_each_connector(connector, dev) {
- if (put_user(connector->base.id,
- connector_id + copied)) {
- ret = -EFAULT;
- goto out;
+ count = 0;
+ connector_id = u64_to_user_ptr(card_res->connector_id_ptr);
+ mutex_lock(&dev->mode_config.mutex);
+ drm_for_each_connector(connector, dev) {
+ if (drm_lease_held(file_priv, connector->base.id)) {
+ if (count < card_res->count_connectors &&
+ put_user(connector->base.id, connector_id + count)) {
+ mutex_unlock(&dev->mode_config.mutex);
+ return -EFAULT;
}
- copied++;
+ count++;
}
}
- card_res->count_connectors = connector_count;
-
-out:
mutex_unlock(&dev->mode_config.mutex);
+ card_res->count_connectors = count;
+
return ret;
}
@@ -572,7 +568,7 @@ int drm_mode_getcrtc(struct drm_device *dev,
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
- crtc = drm_crtc_find(dev, crtc_resp->crtc_id);
+ crtc = drm_crtc_find(dev, file_priv, crtc_resp->crtc_id);
if (!crtc)
return -ENOENT;
@@ -743,7 +739,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
return -ERANGE;
drm_modeset_lock_all(dev);
- crtc = drm_crtc_find(dev, crtc_req->crtc_id);
+ crtc = drm_crtc_find(dev, file_priv, crtc_req->crtc_id);
if (!crtc) {
DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
ret = -ENOENT;
@@ -764,7 +760,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
/* Make refcounting symmetric with the lookup path. */
drm_framebuffer_reference(fb);
} else {
- fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
+ fb = drm_framebuffer_lookup(dev, file_priv, crtc_req->fb_id);
if (!fb) {
DRM_DEBUG_KMS("Unknown FB ID%d\n",
crtc_req->fb_id);
@@ -848,7 +844,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
goto out;
}
- connector = drm_connector_lookup(dev, out_id);
+ connector = drm_connector_lookup(dev, file_priv, out_id);
if (!connector) {
DRM_DEBUG_KMS("Connector id %d unknown\n",
out_id);
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
index c48ba02c5365..4d4a2cf3aae8 100644
--- a/drivers/gpu/drm/drm_crtc_internal.h
+++ b/drivers/gpu/drm/drm_crtc_internal.h
@@ -97,6 +97,7 @@ void drm_mode_object_register(struct drm_device *dev,
int drm_mode_object_get(struct drm_device *dev,
struct drm_mode_object *obj, uint32_t obj_type);
struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
+ struct drm_file *file_priv,
uint32_t id, uint32_t type);
void drm_mode_object_unregister(struct drm_device *dev,
struct drm_mode_object *object);
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 80a903bd317d..728477494297 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -54,7 +54,8 @@ MODULE_PARM_DESC(debug, "Enable debug output, where each bit enables a debug cat
"\t\tBit 2 (0x04) will enable KMS messages (modesetting code)\n"
"\t\tBit 3 (0x08) will enable PRIME messages (prime code)\n"
"\t\tBit 4 (0x10) will enable ATOMIC messages (atomic code)\n"
-"\t\tBit 5 (0x20) will enable VBL messages (vblank code)");
+"\t\tBit 5 (0x20) will enable VBL messages (vblank code)\n"
+"\t\tBit 7 (0x80) will enable LEASE messages (leasing code)");
module_param_named(debug, drm_debug, int, 0600);
static DEFINE_SPINLOCK(drm_minor_lock);
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 37ba5f51378e..5346ac9e78d8 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -36,6 +36,7 @@
#include <drm/drmP.h>
#include <drm/drm_edid.h>
#include <drm/drm_displayid.h>
+#include <drm/drm_scdc_helper.h>
#define version_greater(edid, maj, min) \
(((edid)->version > (maj)) || \
@@ -78,6 +79,8 @@
#define EDID_QUIRK_FORCE_6BPC (1 << 10)
/* Force 10bpc */
#define EDID_QUIRK_FORCE_10BPC (1 << 11)
+/* Non desktop display (i.e. HMD) */
+#define EDID_QUIRK_NON_DESKTOP (1 << 12)
struct detailed_mode_closure {
struct drm_connector *connector;
@@ -159,6 +162,10 @@ static const struct edid_quirk {
/* Rotel RSX-1058 forwards sink's EDID but only does HDMI 1.1*/
{ "ETR", 13896, EDID_QUIRK_FORCE_8BPC },
+
+ /* Quantum data 980 */
+ { "QDI", 980, EDID_QUIRK_PREFER_LARGE_60 },
+ { "QDI", 178, EDID_QUIRK_PREFER_LARGE_60 },
};
/*
@@ -1008,6 +1015,221 @@ static const struct drm_display_mode edid_cea_modes[] = {
2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+ /* 65 - 1280x720@24Hz */
+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040,
+ 3080, 3300, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 66 - 1280x720@25Hz */
+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700,
+ 3740, 3960, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 67 - 1280x720@30Hz */
+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040,
+ 3080, 3300, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 68 - 1280x720@50Hz */
+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
+ 1760, 1980, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 69 - 1280x720@60Hz */
+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
+ 1430, 1650, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 70 - 1280x720@100Hz */
+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720,
+ 1760, 1980, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 71 - 1280x720@120Hz */
+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390,
+ 1430, 1650, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 72 - 1920x1080@24Hz */
+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558,
+ 2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 73 - 1920x1080@25Hz */
+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
+ 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 74 - 1920x1080@30Hz */
+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
+ 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 75 - 1920x1080@50Hz */
+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
+ 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 76 - 1920x1080@60Hz */
+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
+ 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 77 - 1920x1080@100Hz */
+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448,
+ 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 78 - 1920x1080@120Hz */
+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008,
+ 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 79 - 1680x720@24Hz */
+ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 59400, 1680, 3040,
+ 3080, 3300, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 80 - 1680x720@25Hz */
+ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 59400, 1680, 2908,
+ 2948, 3168, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 81 - 1680x720@30Hz */
+ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 59400, 1680, 2380,
+ 2420, 2640, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 82 - 1680x720@50Hz */
+ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 82500, 1680, 1940,
+ 1980, 2200, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 83 - 1680x720@60Hz */
+ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 99000, 1680, 1940,
+ 1980, 2200, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 84 - 1680x720@100Hz */
+ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 165000, 1680, 1740,
+ 1780, 2000, 0, 720, 725, 730, 825, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 85 - 1680x720@120Hz */
+ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 198000, 1680, 1740,
+ 1780, 2000, 0, 720, 725, 730, 825, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 86 - 2560x1080@24Hz */
+ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 99000, 2560, 3558,
+ 3602, 3750, 0, 1080, 1084, 1089, 1100, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 87 - 2560x1080@25Hz */
+ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 90000, 2560, 3008,
+ 3052, 3200, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 88 - 2560x1080@30Hz */
+ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 118800, 2560, 3328,
+ 3372, 3520, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 89 - 2560x1080@50Hz */
+ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 185625, 2560, 3108,
+ 3152, 3300, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 90 - 2560x1080@60Hz */
+ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 198000, 2560, 2808,
+ 2852, 3000, 0, 1080, 1084, 1089, 1100, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 91 - 2560x1080@100Hz */
+ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 371250, 2560, 2778,
+ 2822, 2970, 0, 1080, 1084, 1089, 1250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 92 - 2560x1080@120Hz */
+ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 495000, 2560, 3108,
+ 3152, 3300, 0, 1080, 1084, 1089, 1250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 93 - 3840x2160p@24Hz 16:9 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 5116,
+ 5204, 5500, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+ /* 94 - 3840x2160p@25Hz 16:9 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4896,
+ 4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+ /* 95 - 3840x2160p@30Hz 16:9 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016,
+ 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+ /* 96 - 3840x2160p@50Hz 16:9 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4896,
+ 4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+ /* 97 - 3840x2160p@60Hz 16:9 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016,
+ 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+ /* 98 - 4096x2160p@24Hz 256:135 */
+ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 5116,
+ 5204, 5500, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
+ /* 99 - 4096x2160p@25Hz 256:135 */
+ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 5064,
+ 5152, 5280, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
+ /* 100 - 4096x2160p@30Hz 256:135 */
+ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 4184,
+ 4272, 4400, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
+ /* 101 - 4096x2160p@50Hz 256:135 */
+ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 5064,
+ 5152, 5280, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
+ /* 102 - 4096x2160p@60Hz 256:135 */
+ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 4184,
+ 4272, 4400, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
+ /* 103 - 3840x2160p@24Hz 64:27 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 5116,
+ 5204, 5500, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 104 - 3840x2160p@25Hz 64:27 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4896,
+ 4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 105 - 3840x2160p@30Hz 64:27 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016,
+ 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 106 - 3840x2160p@50Hz 64:27 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4896,
+ 4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 107 - 3840x2160p@60Hz 64:27 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016,
+ 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
};
/*
@@ -2530,12 +2752,32 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
#define VIDEO_BLOCK 0x02
#define VENDOR_BLOCK 0x03
#define SPEAKER_BLOCK 0x04
-#define VIDEO_CAPABILITY_BLOCK 0x07
+#define USE_EXTENDED_TAG 0x07
+#define EXT_VIDEO_CAPABILITY_BLOCK 0x00
+#define EXT_VIDEO_DATA_BLOCK_420 0x0E
+#define EXT_VIDEO_CAP_BLOCK_Y420CMDB 0x0F
#define EDID_BASIC_AUDIO (1 << 6)
#define EDID_CEA_YCRCB444 (1 << 5)
#define EDID_CEA_YCRCB422 (1 << 4)
#define EDID_CEA_VCDB_QS (1 << 6)
+#define DATA_BLOCK_EXTENDED_TAG 0x07
+#define VIDEO_CAPABILITY_DATA_BLOCK 0x0
+#define VSVD_DATA_BLOCK 0x1
+#define COLORIMETRY_DATA_BLOCK 0x5
+#define HDR_STATIC_METADATA_BLOCK 0x6
+
+/* HDR Metadata Block: Bit fields */
+#define SUPPORTED_EOTF_MASK 0x3f
+#define TRADITIONAL_GAMMA_SDR (0x1 << 0)
+#define TRADITIONAL_GAMMA_HDR (0x1 << 1)
+#define SMPTE_ST2084 (0x1 << 2)
+#define BT_2100_HLG (0x1 << 3)
+#define FUTURE_EOTF (0x1 << 4)
+#define RESERVED_EOTF (0x3 << 5)
+
+#define STATIC_METADATA_TYPE1 (0x1 << 0)
+
/*
* Search EDID for CEA extension block.
*/
@@ -2824,6 +3066,15 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid)
return modes;
}
+static u8 svd_to_vic(u8 svd)
+{
+ /* 0-6 bit vic, 7th bit native mode indicator */
+ if ((svd >= 1 && svd <= 64) || (svd >= 129 && svd <= 192))
+ return svd & 127;
+
+ return svd;
+}
+
static struct drm_display_mode *
drm_display_mode_from_vic_index(struct drm_connector *connector,
const u8 *video_db, u8 video_len,
@@ -2837,7 +3088,7 @@ drm_display_mode_from_vic_index(struct drm_connector *connector,
return NULL;
/* CEA modes are numbered 1..127 */
- vic = (video_db[video_index] & 127);
+ vic = svd_to_vic(video_db[video_index]);
if (!drm_valid_cea_vic(vic))
return NULL;
@@ -2850,15 +3101,85 @@ drm_display_mode_from_vic_index(struct drm_connector *connector,
return newmode;
}
+/*
+ * do_y420vdb_modes - Parse YCBCR 420 only modes
+ * @connector: connector corresponding to the HDMI sink
+ * @svds: start of the data block of CEA YCBCR 420 VDB
+ * @len: length of the CEA YCBCR 420 VDB
+ *
+ * Parse the CEA-861-F YCBCR 420 Video Data Block (Y420VDB)
+ * which contains modes which can be supported in YCBCR 420
+ * output format only.
+ */
+static int do_y420vdb_modes(struct drm_connector *connector,
+ const u8 *svds, u8 svds_len)
+{
+ int modes = 0, i;
+ struct drm_device *dev = connector->dev;
+ struct drm_display_info *info = &connector->display_info;
+ struct drm_hdmi_info *hdmi = &info->hdmi;
+
+ for (i = 0; i < svds_len; i++) {
+ u8 vic = svd_to_vic(svds[i]);
+ struct drm_display_mode *newmode;
+
+ if (!drm_valid_cea_vic(vic))
+ continue;
+
+ newmode = drm_mode_duplicate(dev, &edid_cea_modes[vic]);
+ if (!newmode)
+ break;
+ bitmap_set(hdmi->y420_vdb_modes, vic, 1);
+ drm_mode_probed_add(connector, newmode);
+ modes++;
+ }
+
+ if (modes > 0)
+ info->color_formats |= DRM_COLOR_FORMAT_YCRCB420;
+ return modes;
+}
+
+/*
+ * drm_add_cmdb_modes - Add a YCBCR 420 mode into bitmap
+ * @connector: connector corresponding to the HDMI sink
+ * @vic: CEA vic for the video mode to be added in the map
+ *
+ * Makes an entry for a videomode in the YCBCR 420 bitmap
+ */
+static void
+drm_add_cmdb_modes(struct drm_connector *connector, u8 svd)
+{
+ u8 vic = svd_to_vic(svd);
+ struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
+
+ if (!drm_valid_cea_vic(vic))
+ return;
+
+ bitmap_set(hdmi->y420_cmdb_modes, vic, 1);
+}
+
static int
do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len)
{
int i, modes = 0;
+ struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
for (i = 0; i < len; i++) {
struct drm_display_mode *mode;
mode = drm_display_mode_from_vic_index(connector, db, len, i);
if (mode) {
+ /*
+ * YCBCR420 capability block contains a bitmap which
+ * gives the index of CEA modes from CEA VDB, which
+ * can support YCBCR 420 sampling output also (apart
+ * from RGB/YCBCR444 etc).
+ * For example, if the bit 0 in bitmap is set,
+ * first mode in VDB can support YCBCR420 output too.
+ * Add YCBCR420 modes only if sink is HDMI 2.0 capable.
+ */
+ if (i < 64 && hdmi->y420_cmdb_map & (1ULL << i))
+ drm_add_cmdb_modes(connector, db[i]);
+
drm_mode_probed_add(connector, mode);
modes++;
}
@@ -3140,6 +3461,12 @@ cea_db_payload_len(const u8 *db)
}
static int
+cea_db_extended_tag(const u8 *db)
+{
+ return db[1];
+}
+
+static int
cea_db_tag(const u8 *db)
{
return db[0] >> 5;
@@ -3179,9 +3506,92 @@ static bool cea_db_is_hdmi_vsdb(const u8 *db)
return hdmi_id == HDMI_IEEE_OUI;
}
+static bool cea_db_is_hdmi_forum_vsdb(const u8 *db)
+{
+ unsigned int oui;
+
+ if (cea_db_tag(db) != VENDOR_BLOCK)
+ return false;
+
+ if (cea_db_payload_len(db) < 7)
+ return false;
+
+ oui = db[3] << 16 | db[2] << 8 | db[1];
+
+ return oui == HDMI_FORUM_IEEE_OUI;
+}
+
+static bool cea_db_is_y420cmdb(const u8 *db)
+{
+ if (cea_db_tag(db) != USE_EXTENDED_TAG)
+ return false;
+
+ if (!cea_db_payload_len(db))
+ return false;
+
+ if (cea_db_extended_tag(db) != EXT_VIDEO_CAP_BLOCK_Y420CMDB)
+ return false;
+
+ return true;
+}
+
+static bool cea_db_is_y420vdb(const u8 *db)
+{
+ if (cea_db_tag(db) != USE_EXTENDED_TAG)
+ return false;
+
+ if (!cea_db_payload_len(db))
+ return false;
+
+ if (cea_db_extended_tag(db) != EXT_VIDEO_DATA_BLOCK_420)
+ return false;
+
+ return true;
+}
+
#define for_each_cea_db(cea, i, start, end) \
for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1)
+static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector,
+ const u8 *db)
+{
+ struct drm_display_info *info = &connector->display_info;
+ struct drm_hdmi_info *hdmi = &info->hdmi;
+ u8 map_len = cea_db_payload_len(db) - 1;
+ u8 count;
+ u64 map = 0;
+
+ if (map_len == 0) {
+ /* All CEA modes support ycbcr420 sampling also.*/
+ hdmi->y420_cmdb_map = U64_MAX;
+ info->color_formats |= DRM_COLOR_FORMAT_YCRCB420;
+ return;
+ }
+
+ /*
+ * This map indicates which of the existing CEA block modes
+ * from VDB can support YCBCR420 output too. So if bit=0 is
+ * set, first mode from VDB can support YCBCR420 output too.
+ * We will parse and keep this map, before parsing VDB itself
+ * to avoid going through the same block again and again.
+ *
+ * Spec is not clear about max possible size of this block.
+ * Clamping max bitmap block size at 8 bytes. Every byte can
+ * address 8 CEA modes, in this way this map can address
+ * 8*8 = first 64 SVDs.
+ */
+ if (WARN_ON_ONCE(map_len > 8))
+ map_len = 8;
+
+ for (count = 0; count < map_len; count++)
+ map |= (u64)db[2 + count] << (8 * count);
+
+ if (map)
+ info->color_formats |= DRM_COLOR_FORMAT_YCRCB420;
+
+ hdmi->y420_cmdb_map = map;
+}
+
static int
add_cea_modes(struct drm_connector *connector, struct edid *edid)
{
@@ -3204,10 +3614,16 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid)
video = db + 1;
video_len = dbl;
modes += do_cea_modes(connector, video, dbl);
- }
- else if (cea_db_is_hdmi_vsdb(db)) {
+ } else if (cea_db_is_hdmi_vsdb(db)) {
hdmi = db;
hdmi_len = dbl;
+ } else if (cea_db_is_y420vdb(db)) {
+ const u8 *vdb420 = &db[2];
+
+ /* Add 4:2:0(only) modes present in EDID */
+ modes += do_y420vdb_modes(connector,
+ vdb420,
+ dbl - 1);
}
}
}
@@ -3266,6 +3682,83 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode)
mode->clock = clock;
}
+static bool cea_db_is_hdmi_colorimetry_data_block(const u8 *db)
+{
+ if (cea_db_tag(db) != DATA_BLOCK_EXTENDED_TAG)
+ return false;
+
+ if (db[1] != COLORIMETRY_DATA_BLOCK)
+ return false;
+
+ return true;
+}
+
+static void
+drm_parse_colorimetry_data_block(struct drm_connector *connector, const u8 *db)
+{
+ struct drm_hdmi_info *info = &connector->display_info.hdmi;
+ uint16_t len;
+
+ len = cea_db_payload_len(db);
+ info->colorimetry = db[2];
+}
+
+
+static bool cea_db_is_hdmi_hdr_metadata_block(const u8 *db)
+{
+ if (cea_db_tag(db) != DATA_BLOCK_EXTENDED_TAG)
+ return false;
+
+ if (db[1] != HDR_STATIC_METADATA_BLOCK)
+ return false;
+
+ return true;
+}
+
+static uint16_t eotf_supported(const u8 *edid_ext)
+{
+ uint16_t val = 0;
+
+ if (edid_ext[2] & TRADITIONAL_GAMMA_SDR)
+ val |= TRADITIONAL_GAMMA_SDR;
+ if (edid_ext[2] & TRADITIONAL_GAMMA_HDR)
+ val |= TRADITIONAL_GAMMA_HDR;
+ if (edid_ext[2] & SMPTE_ST2084)
+ val |= SMPTE_ST2084;
+ if (edid_ext[2] & BT_2100_HLG)
+ val |= BT_2100_HLG;
+
+ return val;
+}
+
+static uint16_t hdr_metadata_type(const u8 *edid_ext)
+{
+ uint16_t val = 0;
+
+ if (edid_ext[3] & STATIC_METADATA_TYPE1)
+ val |= STATIC_METADATA_TYPE1;
+
+ return val;
+}
+
+static void
+drm_parse_hdr_metadata_block(struct drm_connector *connector, const u8 *db)
+{
+ struct drm_hdmi_info *info = &connector->display_info.hdmi;
+ uint16_t len;
+
+ len = cea_db_payload_len(db);
+ info->hdr_panel_metadata.eotf = eotf_supported(db);
+ info->hdr_panel_metadata.type = hdr_metadata_type(db);
+
+ if (len == 5) {
+ info->hdr_panel_metadata.max_cll = db[4];
+ info->hdr_panel_metadata.max_fall = db[5];
+ } else if (len == 4) {
+ info->hdr_panel_metadata.max_cll = db[4];
+ }
+}
+
static void
drm_parse_hdmi_vsdb_audio(struct drm_connector *connector, const u8 *db)
{
@@ -3728,8 +4221,10 @@ bool drm_rgb_quant_range_selectable(struct edid *edid)
return false;
for_each_cea_db(edid_ext, i, start, end) {
- if (cea_db_tag(&edid_ext[i]) == VIDEO_CAPABILITY_BLOCK &&
- cea_db_payload_len(&edid_ext[i]) == 2) {
+ if (cea_db_tag(&edid_ext[i]) == USE_EXTENDED_TAG &&
+ cea_db_payload_len(&edid_ext[i]) == 2 &&
+ cea_db_extended_tag(&edid_ext[i]) ==
+ EXT_VIDEO_CAPABILITY_BLOCK) {
DRM_DEBUG_KMS("CEA VCDB 0x%02x\n", edid_ext[i + 2]);
return edid_ext[i + 2] & EDID_CEA_VCDB_QS;
}
@@ -3739,6 +4234,60 @@ bool drm_rgb_quant_range_selectable(struct edid *edid)
}
EXPORT_SYMBOL(drm_rgb_quant_range_selectable);
+static void drm_parse_ycbcr420_deep_color_info(struct drm_connector *connector,
+ const u8 *db)
+{
+ u8 dc_mask;
+ struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
+
+ dc_mask = db[7] & DRM_EDID_YCBCR420_DC_MASK;
+ hdmi->y420_dc_modes |= dc_mask;
+}
+
+static void drm_parse_hdmi_forum_vsdb(struct drm_connector *connector,
+ const u8 *hf_vsdb)
+{
+ struct drm_display_info *display = &connector->display_info;
+ struct drm_hdmi_info *hdmi = &display->hdmi;
+
+ if (hf_vsdb[6] & 0x80) {
+ hdmi->scdc.supported = true;
+ if (hf_vsdb[6] & 0x40)
+ hdmi->scdc.read_request = true;
+ }
+
+ /*
+ * All HDMI 2.0 monitors must support scrambling at rates > 340 MHz.
+ * And as per the spec, three factors confirm this:
+ * * Availability of a HF-VSDB block in EDID (check)
+ * * Non zero Max_TMDS_Char_Rate filed in HF-VSDB (let's check)
+ * * SCDC support available (let's check)
+ * Lets check it out.
+ */
+
+ if (hf_vsdb[5]) {
+ /* max clock is 5000 KHz times block value */
+ u32 max_tmds_clock = hf_vsdb[5] * 5000;
+ struct drm_scdc *scdc = &hdmi->scdc;
+
+ if (max_tmds_clock > 340000) {
+ display->max_tmds_clock = max_tmds_clock;
+ DRM_DEBUG_KMS("HF-VSDB: max TMDS clock %d kHz\n",
+ display->max_tmds_clock);
+ }
+
+ if (scdc->supported) {
+ scdc->scrambling.supported = true;
+
+ /* Few sinks support scrambling for cloks < 340M */
+ if ((hf_vsdb[6] & 0x8))
+ scdc->scrambling.low_rates = true;
+ }
+ }
+
+ drm_parse_ycbcr420_deep_color_info(connector, hf_vsdb);
+}
+
static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector,
const u8 *hdmi)
{
@@ -3853,11 +4402,19 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
if (cea_db_is_hdmi_vsdb(db))
drm_parse_hdmi_vsdb_video(connector, db);
+ if (cea_db_is_hdmi_hdr_metadata_block(db))
+ drm_parse_hdr_metadata_block(connector, db);
+ if (cea_db_is_hdmi_forum_vsdb(db))
+ drm_parse_hdmi_forum_vsdb(connector, db);
+ if (cea_db_is_hdmi_colorimetry_data_block(db))
+ drm_parse_colorimetry_data_block(connector, db);
+ if (cea_db_is_y420cmdb(db))
+ drm_parse_y420cmdb_bitmap(connector, db);
}
}
static void drm_add_display_info(struct drm_connector *connector,
- struct edid *edid)
+ struct edid *edid, u32 quirks)
{
struct drm_display_info *info = &connector->display_info;
@@ -3871,6 +4428,8 @@ static void drm_add_display_info(struct drm_connector *connector,
info->max_tmds_clock = 0;
info->dvi_dual = false;
+ info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
+
if (edid->revision < 3)
return;
@@ -4087,6 +4646,13 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
quirks = edid_get_quirks(edid);
/*
+ * CEA-861-F adds ycbcr capability map block, for HDMI 2.0 sinks.
+ * To avoid multiple parsing of same block, lets parse that map
+ * from sink info, before parsing CEA modes.
+ */
+ drm_add_display_info(connector, edid, quirks);
+
+ /*
* EDID spec says modes should be preferred in this order:
* - preferred detailed mode
* - other detailed modes from base block
@@ -4113,8 +4679,6 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
edid_fixup_preferred(connector, quirks);
- drm_add_display_info(connector, edid);
-
if (quirks & EDID_QUIRK_FORCE_6BPC)
connector->display_info.bpc = 6;
@@ -4202,6 +4766,58 @@ void drm_set_preferred_mode(struct drm_connector *connector,
EXPORT_SYMBOL(drm_set_preferred_mode);
/**
+ * drm_hdmi_infoframe_set_hdr_metadata() - fill an HDMI AVI infoframe with
+ * HDR metadata from userspace
+ * @frame: HDMI AVI infoframe
+ * @hdr_source_metadata: hdr_source_metadata info from userspace
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int
+drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe *frame,
+ void *hdr_metadata)
+{
+ struct hdr_static_metadata *hdr_source_metadata;
+ int err, i;
+
+ if (!frame || !hdr_metadata)
+ return -EINVAL;
+
+ err = hdmi_drm_infoframe_init(frame);
+ if (err < 0)
+ return err;
+
+ hdr_source_metadata = (struct hdr_static_metadata *)hdr_metadata;
+
+ frame->length = sizeof(struct hdr_static_metadata);
+
+ frame->eotf = hdr_source_metadata->eotf;
+ frame->metadata_type = hdr_source_metadata->type;
+
+ for (i = 0; i < 3; i++) {
+ frame->display_primaries_x[i] =
+ hdr_source_metadata->display_primaries_x[i];
+ frame->display_primaries_y[i] =
+ hdr_source_metadata->display_primaries_y[i];
+ }
+
+ frame->white_point_x = hdr_source_metadata->white_point_x;
+ frame->white_point_y = hdr_source_metadata->white_point_y;
+
+ frame->max_mastering_display_luminance =
+ hdr_source_metadata->max_mastering_display_luminance;
+ frame->min_mastering_display_luminance =
+ hdr_source_metadata->min_mastering_display_luminance;
+
+ frame->max_cll = hdr_source_metadata->max_cll;
+ frame->max_fall = hdr_source_metadata->max_fall;
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_hdmi_infoframe_set_hdr_metadata);
+
+
+/**
* drm_hdmi_avi_infoframe_from_display_mode() - fill an HDMI AVI infoframe with
* data from a DRM display mode
* @frame: HDMI AVI infoframe
diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c
index 5c067719164d..0c545864080d 100644
--- a/drivers/gpu/drm/drm_encoder.c
+++ b/drivers/gpu/drm/drm_encoder.c
@@ -212,13 +212,13 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
- encoder = drm_encoder_find(dev, enc_resp->encoder_id);
+ encoder = drm_encoder_find(dev, file_priv, enc_resp->encoder_id);
if (!encoder)
return -ENOENT;
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
crtc = drm_encoder_get_crtc(encoder);
- if (crtc)
+ if (crtc && drm_lease_held(file_priv, crtc->base.id))
enc_resp->crtc_id = crtc->base.id;
else
enc_resp->crtc_id = 0;
@@ -226,7 +226,8 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
enc_resp->encoder_type = encoder->encoder_type;
enc_resp->encoder_id = encoder->base.id;
- enc_resp->possible_crtcs = encoder->possible_crtcs;
+ enc_resp->possible_crtcs = drm_lease_filter_crtcs(file_priv,
+ encoder->possible_crtcs);
enc_resp->possible_clones = encoder->possible_clones;
return 0;
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 6a48d6637e5c..a3dc4a781614 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1815,6 +1815,9 @@ static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
{
bool enable;
+ if (connector->display_info.non_desktop)
+ return false;
+
if (strict)
enable = connector->status == connector_status_connected;
else
@@ -1834,7 +1837,8 @@ static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
connector = fb_helper->connector_info[i]->connector;
enabled[i] = drm_connector_enabled(connector, true);
DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
- enabled[i] ? "yes" : "no");
+ connector->display_info.non_desktop ? "non desktop" : enabled[i] ? "yes" : "no");
+
any_enabled |= enabled[i];
}
diff --git a/drivers/gpu/drm/drm_fourcc.c b/drivers/gpu/drm/drm_fourcc.c
index 29c56b4331e0..bc9010381fcc 100644
--- a/drivers/gpu/drm/drm_fourcc.c
+++ b/drivers/gpu/drm/drm_fourcc.c
@@ -207,6 +207,7 @@ int drm_format_num_planes(uint32_t format)
case DRM_FORMAT_NV61:
case DRM_FORMAT_NV24:
case DRM_FORMAT_NV42:
+ case DRM_FORMAT_P010:
return 2;
default:
return 1;
@@ -242,6 +243,7 @@ int drm_format_plane_cpp(uint32_t format, int plane)
case DRM_FORMAT_NV61:
case DRM_FORMAT_NV24:
case DRM_FORMAT_NV42:
+ case DRM_FORMAT_P010:
return plane ? 2 : 1;
case DRM_FORMAT_YUV410:
case DRM_FORMAT_YVU410:
@@ -282,6 +284,7 @@ int drm_format_horz_chroma_subsampling(uint32_t format)
case DRM_FORMAT_UYVY:
case DRM_FORMAT_VYUY:
case DRM_FORMAT_NV12:
+ case DRM_FORMAT_P010:
case DRM_FORMAT_NV21:
case DRM_FORMAT_NV16:
case DRM_FORMAT_NV61:
@@ -314,6 +317,7 @@ int drm_format_vert_chroma_subsampling(uint32_t format)
case DRM_FORMAT_YVU420:
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV21:
+ case DRM_FORMAT_P010:
return 2;
default:
return 1;
diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c
index 398efd67cb93..63ed656a3633 100644
--- a/drivers/gpu/drm/drm_framebuffer.c
+++ b/drivers/gpu/drm/drm_framebuffer.c
@@ -182,6 +182,7 @@ static int format_check(const struct drm_mode_fb_cmd2 *r)
case DRM_FORMAT_NV61:
case DRM_FORMAT_NV24:
case DRM_FORMAT_NV42:
+ case DRM_FORMAT_P010:
case DRM_FORMAT_YUV410:
case DRM_FORMAT_YVU410:
case DRM_FORMAT_YUV411:
@@ -427,7 +428,7 @@ int drm_mode_rmfb(struct drm_device *dev,
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
- fb = drm_framebuffer_lookup(dev, *id);
+ fb = drm_framebuffer_lookup(dev, file_priv, *id);
if (!fb)
return -ENOENT;
@@ -496,7 +497,7 @@ int drm_mode_getfb(struct drm_device *dev,
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
- fb = drm_framebuffer_lookup(dev, r->fb_id);
+ fb = drm_framebuffer_lookup(dev, file_priv, r->fb_id);
if (!fb)
return -ENOENT;
@@ -561,7 +562,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
- fb = drm_framebuffer_lookup(dev, r->fb_id);
+ fb = drm_framebuffer_lookup(dev, file_priv, r->fb_id);
if (!fb)
return -ENOENT;
@@ -731,12 +732,13 @@ EXPORT_SYMBOL(drm_framebuffer_init);
* again, using @drm_framebuffer_unreference.
*/
struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
+ struct drm_file *file_priv,
uint32_t id)
{
struct drm_mode_object *obj;
struct drm_framebuffer *fb = NULL;
- obj = __drm_mode_object_find(dev, id, DRM_MODE_OBJECT_FB);
+ obj = __drm_mode_object_find(dev, file_priv, id, DRM_MODE_OBJECT_FB);
if (obj)
fb = obj_to_fb(obj);
return fb;
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 71c3473476c7..1190d659adcd 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -277,6 +277,9 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_
case DRM_CAP_ADDFB2_MODIFIERS:
req->value = dev->mode_config.allow_fb_modifiers;
break;
+ case DRM_CAP_CRTC_IN_VBLANK_EVENT:
+ req->value = 1;
+ break;
default:
return -EINVAL;
}
@@ -629,6 +632,10 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATEPROPBLOB, drm_mode_createblob_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROYPROPBLOB, drm_mode_destroyblob_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_LEASE, drm_mode_create_lease_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_LIST_LESSEES, drm_mode_list_lessees_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GET_LEASE, drm_mode_get_lease_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_REVOKE_LEASE, drm_mode_revoke_lease_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
};
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 00c815a7c414..dca26eea256d 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -1048,6 +1048,7 @@ void drm_crtc_arm_vblank_event(struct drm_crtc *crtc,
e->pipe = pipe;
e->event.sequence = drm_vblank_count(dev, pipe);
+ e->event.crtc_id = crtc->base.id;
list_add_tail(&e->base.link, &dev->vblank_event_list);
}
EXPORT_SYMBOL(drm_crtc_arm_vblank_event);
@@ -1078,6 +1079,7 @@ void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
now = get_drm_timestamp();
}
e->pipe = pipe;
+ e->event.crtc_id = crtc->base.id;
send_vblank_event(dev, e, seq, &now);
}
EXPORT_SYMBOL(drm_crtc_send_vblank_event);
@@ -1661,9 +1663,11 @@ err_put:
int drm_wait_vblank(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
+ struct drm_crtc *crtc;
struct drm_vblank_crtc *vblank;
union drm_wait_vblank *vblwait = data;
int ret;
+ unsigned int pipe_index;
unsigned int flags, seq, pipe, high_pipe;
if (!dev->irq_enabled)
@@ -1685,9 +1689,26 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
high_pipe = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK);
if (high_pipe)
- pipe = high_pipe >> _DRM_VBLANK_HIGH_CRTC_SHIFT;
+ pipe_index = high_pipe >> _DRM_VBLANK_HIGH_CRTC_SHIFT;
else
- pipe = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
+ pipe_index = flags & _DRM_VBLANK_SECONDARY ? 1 : 0;
+
+ /* Convert lease-relative crtc index into global crtc index */
+ if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ pipe = 0;
+ drm_for_each_crtc(crtc, dev) {
+ if (drm_lease_held(file_priv, crtc->base.id)) {
+ if (pipe_index == 0)
+ break;
+ pipe_index--;
+ }
+ pipe++;
+ }
+ } else {
+ pipe = pipe_index;
+ }
+
+
if (pipe >= dev->num_crtcs)
return -EINVAL;
diff --git a/drivers/gpu/drm/drm_lease.c b/drivers/gpu/drm/drm_lease.c
new file mode 100644
index 000000000000..4042c63b41bd
--- /dev/null
+++ b/drivers/gpu/drm/drm_lease.c
@@ -0,0 +1,765 @@
+/*
+ * Copyright © 2017 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include "drm_internal.h"
+#include "drm_legacy.h"
+#include "drm_crtc_internal.h"
+#include <drm/drm_lease.h>
+#include <drm/drm_auth.h>
+#include <drm/drm_crtc_helper.h>
+
+#define drm_for_each_lessee(lessee, lessor) \
+ list_for_each_entry((lessee), &(lessor)->lessees, lessee_list)
+
+static uint64_t drm_lease_idr_object;
+
+/**
+ * drm_lease_owner - return ancestor owner drm_master
+ * @master: drm_master somewhere within tree of lessees and lessors
+ *
+ * RETURN:
+ *
+ * drm_master at the top of the tree (i.e, with lessor NULL
+ */
+struct drm_master *drm_lease_owner(struct drm_master *master)
+{
+ while (master->lessor != NULL)
+ master = master->lessor;
+ return master;
+}
+EXPORT_SYMBOL(drm_lease_owner);
+
+/**
+ * _drm_find_lessee - find lessee by id (idr_mutex held)
+ * @master: drm_master of lessor
+ * @id: lessee_id
+ *
+ * RETURN:
+ *
+ * drm_master of the lessee if valid, NULL otherwise
+ */
+
+static struct drm_master*
+_drm_find_lessee(struct drm_master *master, int lessee_id)
+{
+ lockdep_assert_held(&master->dev->mode_config.idr_mutex);
+ return idr_find(&drm_lease_owner(master)->lessee_idr, lessee_id);
+}
+
+/**
+ * _drm_lease_held_master - check to see if an object is leased (or owned) by master (idr_mutex held)
+ * @master: the master to check the lease status of
+ * @id: the id to check
+ *
+ * Checks if the specified master holds a lease on the object. Return
+ * value:
+ *
+ * true 'master' holds a lease on (or owns) the object
+ * false 'master' does not hold a lease.
+ */
+static int _drm_lease_held_master(struct drm_master *master, int id)
+{
+ lockdep_assert_held(&master->dev->mode_config.idr_mutex);
+ if (master->lessor)
+ return idr_find(&master->leases, id) != NULL;
+ return true;
+}
+
+/**
+ * _drm_has_leased - check to see if an object has been leased (idr_mutex held)
+ * @master: the master to check the lease status of
+ * @id: the id to check
+ *
+ * Checks if any lessee of 'master' holds a lease on 'id'. Return
+ * value:
+ *
+ * true Some lessee holds a lease on the object.
+ * false No lessee has a lease on the object.
+ */
+static bool _drm_has_leased(struct drm_master *master, int id)
+{
+ struct drm_master *lessee;
+
+ lockdep_assert_held(&master->dev->mode_config.idr_mutex);
+ drm_for_each_lessee(lessee, master)
+ if (_drm_lease_held_master(lessee, id))
+ return true;
+ return false;
+}
+
+/**
+ * _drm_lease_held - check drm_mode_object lease status (idr_mutex held)
+ * @master: the drm_master
+ * @id: the object id
+ *
+ * Checks if the specified master holds a lease on the object. Return
+ * value:
+ *
+ * true 'master' holds a lease on (or owns) the object
+ * false 'master' does not hold a lease.
+ */
+bool _drm_lease_held(struct drm_file *file_priv, int id)
+{
+ if (file_priv == NULL || file_priv->master == NULL)
+ return true;
+
+ return _drm_lease_held_master(file_priv->master, id);
+}
+EXPORT_SYMBOL(_drm_lease_held);
+
+/**
+ * drm_lease_held - check drm_mode_object lease status (idr_mutex not held)
+ * @master: the drm_master
+ * @id: the object id
+ *
+ * Checks if the specified master holds a lease on the object. Return
+ * value:
+ *
+ * true 'master' holds a lease on (or owns) the object
+ * false 'master' does not hold a lease.
+ */
+bool drm_lease_held(struct drm_file *file_priv, int id)
+{
+ struct drm_master *master;
+ bool ret;
+
+ if (file_priv == NULL || file_priv->master == NULL)
+ return true;
+
+ master = file_priv->master;
+ mutex_lock(&master->dev->mode_config.idr_mutex);
+ ret = _drm_lease_held_master(master, id);
+ mutex_unlock(&master->dev->mode_config.idr_mutex);
+ return ret;
+}
+EXPORT_SYMBOL(drm_lease_held);
+
+/**
+ * drm_lease_filter_crtcs - restricted crtc set to leased values (idr_mutex not held)
+ * @file_priv: requestor file
+ * @crtcs: bitmask of crtcs to check
+ *
+ * Reconstructs a crtc mask based on the crtcs which are visible
+ * through the specified file.
+ */
+uint32_t drm_lease_filter_crtcs(struct drm_file *file_priv, uint32_t crtcs_in)
+{
+ struct drm_master *master;
+ struct drm_device *dev;
+ struct drm_crtc *crtc;
+ int count_in, count_out;
+ uint32_t crtcs_out = 0;
+
+ if (file_priv == NULL || file_priv->master == NULL)
+ return crtcs_in;
+
+ master = file_priv->master;
+ dev = master->dev;
+
+ count_in = count_out = 0;
+ mutex_lock(&master->dev->mode_config.idr_mutex);
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ if (_drm_lease_held_master(master, crtc->base.id)) {
+ uint32_t mask_in = 1ul << count_in;
+ if ((crtcs_in & mask_in) != 0) {
+ uint32_t mask_out = 1ul << count_out;
+ crtcs_out |= mask_out;
+ }
+ count_out++;
+ }
+ count_in++;
+ }
+ mutex_unlock(&master->dev->mode_config.idr_mutex);
+ return crtcs_out;
+}
+EXPORT_SYMBOL(drm_lease_filter_crtcs);
+
+/*
+ * drm_lease_create - create a new drm_master with leased objects (idr_mutex not held)
+ * @lessor: lease holder (or owner) of objects
+ * @leases: objects to lease to the new drm_master
+ *
+ * Uses drm_master_create to allocate a new drm_master, then checks to
+ * make sure all of the desired objects can be leased, atomically
+ * leasing them to the new drmmaster.
+ *
+ * ERR_PTR(-EACCESS) some other master holds the title to any object
+ * ERR_PTR(-ENOENT) some object is not a valid DRM object for this device
+ * ERR_PTR(-EBUSY) some other lessee holds title to this object
+ * ERR_PTR(-EEXIST) same object specified more than once in the provided list
+ * ERR_PTR(-ENOMEM) allocation failed
+ */
+static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr *leases)
+{
+ struct drm_device *dev = lessor->dev;
+ int error;
+ struct drm_master *lessee;
+ int object;
+ int id;
+ void *entry;
+
+ DRM_DEBUG_LEASE("lessor %d\n", lessor->lessee_id);
+
+ lessee = drm_master_create(lessor->dev);
+ if (!lessee) {
+ DRM_DEBUG_LEASE("drm_master_create failed\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ mutex_lock(&dev->mode_config.idr_mutex);
+
+ idr_for_each_entry(leases, entry, object) {
+ error = 0;
+ if (!idr_find(&dev->mode_config.crtc_idr, object))
+ error = -ENOENT;
+ else if (!_drm_lease_held_master(lessor, object))
+ error = -EACCES;
+ else if (_drm_has_leased(lessor, object))
+ error = -EBUSY;
+
+ if (error != 0) {
+ DRM_DEBUG_LEASE("object %d failed %d\n", object, error);
+ goto out_lessee;
+ }
+ }
+
+ /* Insert the new lessee into the tree */
+ id = idr_alloc(&(drm_lease_owner(lessor)->lessee_idr), lessee, 1, 0, GFP_KERNEL);
+ if (id < 0) {
+ error = id;
+ goto out_lessee;
+ }
+
+ lessee->lessee_id = id;
+ lessee->lessor = drm_master_get(lessor);
+ list_add_tail(&lessee->lessee_list, &lessor->lessees);
+
+ /* Move the leases over */
+ lessee->leases = *leases;
+ DRM_DEBUG_LEASE("new lessee %d %p, lessor %d %p\n", lessee->lessee_id, lessee, lessor->lessee_id, lessor);
+
+ mutex_unlock(&dev->mode_config.idr_mutex);
+ return lessee;
+
+out_lessee:
+ mutex_unlock(&dev->mode_config.idr_mutex);
+
+ drm_master_put(&lessee);
+
+ return ERR_PTR(error);
+}
+
+/**
+ * drm_lease_destroy - a master is going away (idr_mutex not held)
+ * @master: the drm_master being destroyed
+ *
+ * All lessees will have been destroyed as they
+ * hold a reference on their lessor. Notify any
+ * lessor for this master so that it can check
+ * the list of lessees.
+ */
+void drm_lease_destroy(struct drm_master *master)
+{
+ struct drm_device *dev = master->dev;
+
+ mutex_lock(&dev->mode_config.idr_mutex);
+
+ DRM_DEBUG_LEASE("drm_lease_destroy %d\n", master->lessee_id);
+
+ /* This master is referenced by all lessees, hence it cannot be destroyed
+ * until all of them have been
+ */
+ WARN_ON(!list_empty(&master->lessees));
+
+ /* Remove this master from the lessee idr in the owner */
+ if (master->lessee_id != 0) {
+ DRM_DEBUG_LEASE("remove master %d from device list of lessees\n", master->lessee_id);
+ idr_remove(&(drm_lease_owner(master)->lessee_idr), master->lessee_id);
+ }
+ /* Remove this master from any lessee list it may be on */
+ list_del(&master->lessee_list);
+
+ mutex_unlock(&dev->mode_config.idr_mutex);
+
+ if (master->lessor) {
+ /* Tell the master to check the lessee list */
+ drm_sysfs_hotplug_event(dev);
+ drm_master_put(&master->lessor);
+ }
+
+ DRM_DEBUG_LEASE("drm_lease_destroy done %d\n", master->lessee_id);
+}
+
+/**
+ * _drm_lease_revoke - revoke access to all leased objects (idr_mutex held)
+ * @master: the master losing its lease
+ */
+static void _drm_lease_revoke(struct drm_master *top)
+{
+ int object;
+ void *entry;
+ struct drm_master *master = top;
+
+ lockdep_assert_held(&top->dev->mode_config.idr_mutex);
+
+ /*
+ * Walk the tree starting at 'top' emptying all leases. Because
+ * the tree is fully connected, we can do this without recursing
+ */
+ for (;;) {
+ DRM_DEBUG_LEASE("revoke leases for %p %d\n", master, master->lessee_id);
+
+ /* Evacuate the lease */
+ idr_for_each_entry(&master->leases, entry, object)
+ idr_remove(&master->leases, object);
+
+ /* Depth-first list walk */
+
+ /* Down */
+ if (!list_empty(&master->lessees)) {
+ master = list_first_entry(&master->lessees, struct drm_master, lessee_list);
+ } else {
+ /* Up */
+ while (master != top && master == list_last_entry(&master->lessor->lessees, struct drm_master, lessee_list))
+ master = master->lessor;
+
+ if (master == top)
+ break;
+
+ /* Over */
+ master = list_entry(master->lessee_list.next, struct drm_master, lessee_list);
+ }
+ }
+}
+
+/**
+ * drm_lease_revoke - revoke access to all leased objects (idr_mutex not held)
+ * @top: the master losing its lease
+ */
+void drm_lease_revoke(struct drm_master *top)
+{
+ mutex_lock(&top->dev->mode_config.idr_mutex);
+ _drm_lease_revoke(top);
+ mutex_unlock(&top->dev->mode_config.idr_mutex);
+}
+
+static int validate_lease(struct drm_device *dev,
+ struct drm_file *lessor_priv,
+ int object_count,
+ struct drm_mode_object **objects)
+{
+ int o;
+ int has_crtc = -1;
+ int has_connector = -1;
+ int has_plane = -1;
+
+ /* we want to confirm that there is at least one crtc, plane
+ connector object. */
+
+ for (o = 0; o < object_count; o++) {
+ if (objects[o]->type == DRM_MODE_OBJECT_CRTC && has_crtc == -1) {
+ has_crtc = o;
+ }
+ if (objects[o]->type == DRM_MODE_OBJECT_CONNECTOR && has_connector == -1)
+ has_connector = o;
+
+ if (lessor_priv->universal_planes) {
+ if (objects[o]->type == DRM_MODE_OBJECT_PLANE && has_plane == -1)
+ has_plane = o;
+ }
+ }
+ if (has_crtc == -1 || has_connector == -1)
+ return -EINVAL;
+ if (lessor_priv->universal_planes && has_plane == -1)
+ return -EINVAL;
+ return 0;
+}
+
+static int fill_object_idr(struct drm_device *dev,
+ struct drm_file *lessor_priv,
+ struct idr *leases,
+ int object_count,
+ u32 *object_ids)
+{
+ struct drm_mode_object **objects;
+ u32 o;
+ int ret;
+ objects = kcalloc(object_count, sizeof(struct drm_mode_object *),
+ GFP_KERNEL);
+ if (!objects)
+ return -ENOMEM;
+
+ /* step one - get references to all the mode objects
+ and check for validity. */
+ for (o = 0; o < object_count; o++) {
+ if ((int) object_ids[o] < 0) {
+ ret = -EINVAL;
+ goto out_free_objects;
+ }
+
+ objects[o] = drm_mode_object_find(dev, lessor_priv,
+ object_ids[o],
+ DRM_MODE_OBJECT_ANY);
+ if (!objects[o]) {
+ ret = -ENOENT;
+ goto out_free_objects;
+ }
+
+ if (!drm_mode_object_lease_required(objects[o]->type)) {
+ ret = -EINVAL;
+ goto out_free_objects;
+ }
+ }
+ ret = validate_lease(dev, lessor_priv, object_count, objects);
+ if (ret)
+ goto out_free_objects;
+
+ /* add their IDs to the lease request - taking into account
+ universal planes */
+ for (o = 0; o < object_count; o++) {
+ struct drm_mode_object *obj = objects[o];
+ u32 object_id = objects[o]->id;
+ DRM_DEBUG_LEASE("Adding object %d to lease\n", object_id);
+
+ /*
+ * We're using an IDR to hold the set of leased
+ * objects, but we don't need to point at the object's
+ * data structure from the lease as the main crtc_idr
+ * will be used to actually find that. Instead, all we
+ * really want is a 'leased/not-leased' result, for
+ * which any non-NULL pointer will work fine.
+ */
+ ret = idr_alloc(leases, &drm_lease_idr_object , object_id, object_id + 1, GFP_KERNEL);
+ if (ret < 0) {
+ DRM_DEBUG_LEASE("Object %d cannot be inserted into leases (%d)\n",
+ object_id, ret);
+ goto out_free_objects;
+ }
+ if (obj->type == DRM_MODE_OBJECT_CRTC && !lessor_priv->universal_planes) {
+ struct drm_crtc *crtc = obj_to_crtc(obj);
+ ret = idr_alloc(leases, &drm_lease_idr_object, crtc->primary->base.id, crtc->primary->base.id + 1, GFP_KERNEL);
+ if (ret < 0) {
+ DRM_DEBUG_LEASE("Object primary plane %d cannot be inserted into leases (%d)\n",
+ object_id, ret);
+ goto out_free_objects;
+ }
+ if (crtc->cursor) {
+ ret = idr_alloc(leases, &drm_lease_idr_object, crtc->cursor->base.id, crtc->cursor->base.id + 1, GFP_KERNEL);
+ if (ret < 0) {
+ DRM_DEBUG_LEASE("Object cursor plane %d cannot be inserted into leases (%d)\n",
+ object_id, ret);
+ goto out_free_objects;
+ }
+ }
+ }
+ }
+
+ ret = 0;
+out_free_objects:
+ for (o = 0; o < object_count; o++) {
+ if (objects[o])
+ drm_mode_object_unreference(objects[o]);
+ }
+ kfree(objects);
+ return ret;
+}
+
+/**
+ * drm_mode_create_lease_ioctl - create a new lease
+ * @dev: the drm device
+ * @data: pointer to struct drm_mode_create_lease
+ * @file_priv: the file being manipulated
+ *
+ * The master associated with the specified file will have a lease
+ * created containing the objects specified in the ioctl structure.
+ * A file descriptor will be allocated for that and returned to the
+ * application.
+ */
+int drm_mode_create_lease_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *lessor_priv)
+{
+ struct drm_mode_create_lease *cl = data;
+ size_t object_count;
+ int ret = 0;
+ struct idr leases;
+ struct drm_master *lessor = lessor_priv->master;
+ struct drm_master *lessee = NULL;
+ struct file *lessee_file = NULL;
+ struct file *lessor_file = lessor_priv->filp;
+ struct drm_file *lessee_priv;
+ int fd = -1;
+ uint32_t *object_ids;
+
+ /* Can't lease without MODESET */
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ return -EINVAL;
+
+ /* Do not allow sub-leases */
+ if (lessor->lessor)
+ return -EINVAL;
+
+ /* need some objects */
+ if (cl->object_count == 0)
+ return -EINVAL;
+
+ if (cl->flags && (cl->flags & ~(O_CLOEXEC | O_NONBLOCK)))
+ return -EINVAL;
+
+ object_count = cl->object_count;
+
+ object_ids = memdup_user(u64_to_user_ptr(cl->object_ids), object_count * sizeof(__u32));
+ if (IS_ERR(object_ids))
+ return PTR_ERR(object_ids);
+
+ idr_init(&leases);
+
+ /* fill and validate the object idr */
+ ret = fill_object_idr(dev, lessor_priv, &leases,
+ object_count, object_ids);
+ kfree(object_ids);
+ if (ret) {
+ idr_destroy(&leases);
+ return ret;
+ }
+
+ /* Allocate a file descriptor for the lease */
+ fd = get_unused_fd_flags(cl->flags & (O_CLOEXEC | O_NONBLOCK));
+ if (fd < 0) {
+ idr_destroy(&leases);
+ return fd;
+ }
+
+ DRM_DEBUG_LEASE("Creating lease\n");
+ lessee = drm_lease_create(lessor, &leases);
+
+ if (IS_ERR(lessee)) {
+ ret = PTR_ERR(lessee);
+ goto out_leases;
+ }
+
+ /* Clone the lessor file to create a new file for us */
+ DRM_DEBUG_LEASE("Allocating lease file\n");
+ path_get(&lessor_file->f_path);
+ lessee_file = alloc_file(&lessor_file->f_path,
+ lessor_file->f_mode,
+ fops_get(lessor_file->f_inode->i_fop));
+
+ if (IS_ERR(lessee_file)) {
+ ret = PTR_ERR(lessee_file);
+ goto out_lessee;
+ }
+
+ /* Initialize the new file for DRM */
+ DRM_DEBUG_LEASE("Initializing the file with %p\n", lessee_file->f_op->open);
+ ret = lessee_file->f_op->open(lessee_file->f_inode, lessee_file);
+ if (ret)
+ goto out_lessee_file;
+
+ lessee_priv = lessee_file->private_data;
+
+ /* Change the file to a master one */
+ drm_master_put(&lessee_priv->master);
+ lessee_priv->master = lessee;
+ lessee_priv->is_master = 1;
+ lessee_priv->authenticated = 1;
+
+ /* Hook up the fd */
+ fd_install(fd, lessee_file);
+
+ /* Pass fd back to userspace */
+ DRM_DEBUG_LEASE("Returning fd %d id %d\n", fd, lessee->lessee_id);
+ cl->fd = fd;
+ cl->lessee_id = lessee->lessee_id;
+
+ DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl succeeded\n");
+ return 0;
+
+out_lessee_file:
+ fput(lessee_file);
+
+out_lessee:
+ drm_master_put(&lessee);
+
+out_leases:
+ put_unused_fd(fd);
+ idr_destroy(&leases);
+
+ DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl failed: %d\n", ret);
+ return ret;
+}
+
+/**
+ * drm_mode_list_lessees_ioctl - list lessee ids
+ * @dev: the drm device
+ * @data: pointer to struct drm_mode_list_lessees
+ * @lessor_priv: the file being manipulated
+ *
+ * Starting from the master associated with the specified file,
+ * the master with the provided lessee_id is found, and then
+ * an array of lessee ids associated with leases from that master
+ * are returned.
+ */
+
+int drm_mode_list_lessees_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *lessor_priv)
+{
+ struct drm_mode_list_lessees *arg = data;
+ __u32 __user *lessee_ids = (__u32 __user *) (uintptr_t) (arg->lessees_ptr);
+ __u32 count_lessees = arg->count_lessees;
+ struct drm_master *lessor = lessor_priv->master, *lessee;
+ int count;
+ int ret = 0;
+
+ if (arg->pad)
+ return -EINVAL;
+
+ /* Can't lease without MODESET */
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ return -EINVAL;
+
+ DRM_DEBUG_LEASE("List lessees for %d\n", lessor->lessee_id);
+
+ mutex_lock(&dev->mode_config.idr_mutex);
+
+ count = 0;
+ drm_for_each_lessee(lessee, lessor) {
+ /* Only list un-revoked leases */
+ if (!idr_is_empty(&lessee->leases)) {
+ if (count_lessees > count) {
+ DRM_DEBUG_LEASE("Add lessee %d\n", lessee->lessee_id);
+ ret = put_user(lessee->lessee_id, lessee_ids + count);
+ if (ret)
+ break;
+ }
+ count++;
+ }
+ }
+
+ DRM_DEBUG_LEASE("Lessor leases to %d\n", count);
+ if (ret == 0)
+ arg->count_lessees = count;
+
+ mutex_unlock(&dev->mode_config.idr_mutex);
+
+ return ret;
+}
+
+/**
+ * drm_mode_get_lease_ioctl - list leased objects
+ * @dev: the drm device
+ * @data: pointer to struct drm_mode_get_lease
+ * @file_priv: the file being manipulated
+ *
+ * Return the list of leased objects for the specified lessee
+ */
+
+int drm_mode_get_lease_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *lessee_priv)
+{
+ struct drm_mode_get_lease *arg = data;
+ __u32 __user *object_ids = (__u32 __user *) (uintptr_t) (arg->objects_ptr);
+ __u32 count_objects = arg->count_objects;
+ struct drm_master *lessee = lessee_priv->master;
+ struct idr *object_idr;
+ int count;
+ void *entry;
+ int object;
+ int ret = 0;
+
+ if (arg->pad)
+ return -EINVAL;
+
+ /* Can't lease without MODESET */
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ return -EINVAL;
+
+ DRM_DEBUG_LEASE("get lease for %d\n", lessee->lessee_id);
+
+ mutex_lock(&dev->mode_config.idr_mutex);
+
+ if (lessee->lessor == NULL)
+ /* owner can use all objects */
+ object_idr = &lessee->dev->mode_config.crtc_idr;
+ else
+ /* lessee can only use allowed object */
+ object_idr = &lessee->leases;
+
+ count = 0;
+ idr_for_each_entry(object_idr, entry, object) {
+ if (count_objects > count) {
+ DRM_DEBUG_LEASE("adding object %d\n", object);
+ ret = put_user(object, object_ids + count);
+ if (ret)
+ break;
+ }
+ count++;
+ }
+
+ DRM_DEBUG("lease holds %d objects\n", count);
+ if (ret == 0)
+ arg->count_objects = count;
+
+ mutex_unlock(&dev->mode_config.idr_mutex);
+
+ return ret;
+}
+
+/**
+ * drm_mode_revoke_lease_ioctl - revoke lease
+ * @dev: the drm device
+ * @data: pointer to struct drm_mode_revoke_lease
+ * @file_priv: the file being manipulated
+ *
+ * This removes all of the objects from the lease without
+ * actually getting rid of the lease itself; that way all
+ * references to it still work correctly
+ */
+int drm_mode_revoke_lease_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *lessor_priv)
+{
+ struct drm_mode_revoke_lease *arg = data;
+ struct drm_master *lessor = lessor_priv->master;
+ struct drm_master *lessee;
+ int ret = 0;
+
+ DRM_DEBUG_LEASE("revoke lease for %d\n", arg->lessee_id);
+
+ /* Can't lease without MODESET */
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ return -EINVAL;
+
+ mutex_lock(&dev->mode_config.idr_mutex);
+
+ lessee = _drm_find_lessee(lessor, arg->lessee_id);
+
+ /* No such lessee */
+ if (!lessee) {
+ ret = -ENOENT;
+ goto fail;
+ }
+
+ /* Lease is not held by lessor */
+ if (lessee->lessor != lessor) {
+ ret = -EACCES;
+ goto fail;
+ }
+
+ _drm_lease_revoke(lessee);
+
+fail:
+ mutex_unlock(&dev->mode_config.idr_mutex);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c
index 9f17085b1fdd..ec59b53bd562 100644
--- a/drivers/gpu/drm/drm_mode_object.c
+++ b/drivers/gpu/drm/drm_mode_object.c
@@ -86,6 +86,26 @@ void drm_mode_object_register(struct drm_device *dev,
}
/**
+ * drm_lease_required - check types which must be leased to be used
+ * @type: type of object
+ *
+ * Returns whether the provided type of drm_mode_object must
+ * be owned or leased to be used by a process.
+ */
+bool drm_mode_object_lease_required(uint32_t type)
+{
+ switch (type) {
+ case DRM_MODE_OBJECT_CRTC:
+ case DRM_MODE_OBJECT_CONNECTOR:
+ case DRM_MODE_OBJECT_PLANE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+/**
* drm_mode_object_unregister - free a modeset identifer
* @dev: DRM device
* @object: object to free
@@ -108,6 +128,7 @@ void drm_mode_object_unregister(struct drm_device *dev,
}
struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
+ struct drm_file *file_priv,
uint32_t id, uint32_t type)
{
struct drm_mode_object *obj = NULL;
@@ -119,6 +140,10 @@ struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
if (obj && obj->id != id)
obj = NULL;
+ if (obj && drm_mode_object_lease_required(obj->type) &&
+ !_drm_lease_held(file_priv, obj->id))
+ obj = NULL;
+
if (obj && obj->free_cb) {
if (!kref_get_unless_zero(&obj->refcount))
obj = NULL;
@@ -139,11 +164,12 @@ struct drm_mode_object *__drm_mode_object_find(struct drm_device *dev,
* by callind drm_mode_object_unreference().
*/
struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
- uint32_t id, uint32_t type)
+ struct drm_file *file_priv,
+ uint32_t id, uint32_t type)
{
struct drm_mode_object *obj = NULL;
- obj = __drm_mode_object_find(dev, id, type);
+ obj = __drm_mode_object_find(dev, file_priv, id, type);
return obj;
}
EXPORT_SYMBOL(drm_mode_object_find);
@@ -350,7 +376,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
drm_modeset_lock_all(dev);
- obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
+ obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type);
if (!obj) {
ret = -ENOENT;
goto out;
@@ -398,7 +424,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
drm_modeset_lock_all(dev);
- arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
+ arg_obj = drm_mode_object_find(dev, file_priv, arg->obj_id, arg->obj_type);
if (!arg_obj) {
ret = -ENOENT;
goto out;
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index e14366de0e6e..374d34c00289 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -1065,6 +1065,34 @@ drm_mode_validate_size(const struct drm_display_mode *mode,
}
EXPORT_SYMBOL(drm_mode_validate_size);
+/**
+ * drm_mode_validate_ycbcr420 - add 'ycbcr420-only' modes only when allowed
+ * @mode: mode to check
+ * @connector: drm connector under action
+ *
+ * This function is a helper which can be used to filter out any YCBCR420
+ * only mode, when the source doesn't support it.
+ *
+ * Returns:
+ * The mode status
+ */
+enum drm_mode_status
+drm_mode_validate_ycbcr420(const struct drm_display_mode *mode,
+ struct drm_connector *connector)
+{
+ u8 vic = drm_match_cea_mode(mode);
+ enum drm_mode_status status = MODE_OK;
+ struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
+
+ if (test_bit(vic, hdmi->y420_vdb_modes)) {
+ if (!connector->ycbcr_420_allowed)
+ status = MODE_NO_420;
+ }
+
+ return status;
+}
+EXPORT_SYMBOL(drm_mode_validate_ycbcr420);
+
#define MODE_STATUS(status) [MODE_ ## status + 3] = #status
static const char * const drm_mode_status_names[] = {
@@ -1104,6 +1132,7 @@ static const char * const drm_mode_status_names[] = {
MODE_STATUS(ONE_SIZE),
MODE_STATUS(NO_REDUCED),
MODE_STATUS(NO_STEREO),
+ MODE_STATUS(NO_420),
MODE_STATUS(STALE),
MODE_STATUS(BAD),
MODE_STATUS(ERROR),
@@ -1562,3 +1591,61 @@ int drm_mode_convert_umode(struct drm_display_mode *out,
out:
return ret;
}
+
+/**
+ * drm_mode_is_420_only - if a given videomode can be only supported in YCBCR420
+ * output format
+ *
+ * @connector: drm connector under action.
+ * @mode: video mode to be tested.
+ *
+ * Returns:
+ * true if the mode can be supported in YCBCR420 format
+ * false if not.
+ */
+bool drm_mode_is_420_only(const struct drm_display_info *display,
+ const struct drm_display_mode *mode)
+{
+ u8 vic = drm_match_cea_mode(mode);
+
+ return test_bit(vic, display->hdmi.y420_vdb_modes);
+}
+EXPORT_SYMBOL(drm_mode_is_420_only);
+
+/**
+ * drm_mode_is_420_also - if a given videomode can be supported in YCBCR420
+ * output format also (along with RGB/YCBCR444/422)
+ *
+ * @display: display under action.
+ * @mode: video mode to be tested.
+ *
+ * Returns:
+ * true if the mode can be support YCBCR420 format
+ * false if not.
+ */
+bool drm_mode_is_420_also(const struct drm_display_info *display,
+ const struct drm_display_mode *mode)
+{
+ u8 vic = drm_match_cea_mode(mode);
+
+ return test_bit(vic, display->hdmi.y420_cmdb_modes);
+}
+EXPORT_SYMBOL(drm_mode_is_420_also);
+/**
+ * drm_mode_is_420 - if a given videomode can be supported in YCBCR420
+ * output format
+ *
+ * @display: display under action.
+ * @mode: video mode to be tested.
+ *
+ * Returns:
+ * true if the mode can be supported in YCBCR420 format
+ * false if not.
+ */
+bool drm_mode_is_420(const struct drm_display_info *display,
+ const struct drm_display_mode *mode)
+{
+ return drm_mode_is_420_only(display, mode) ||
+ drm_mode_is_420_also(display, mode);
+}
+EXPORT_SYMBOL(drm_mode_is_420);
diff --git a/drivers/gpu/drm/drm_modeset_helper.c b/drivers/gpu/drm/drm_modeset_helper.c
index 1d45738f8f98..5f7e92630719 100644
--- a/drivers/gpu/drm/drm_modeset_helper.c
+++ b/drivers/gpu/drm/drm_modeset_helper.c
@@ -120,6 +120,7 @@ static struct drm_plane *create_primary_plane(struct drm_device *dev)
&drm_primary_helper_funcs,
safe_modeset_formats,
ARRAY_SIZE(safe_modeset_formats),
+ NULL,
DRM_PLANE_TYPE_PRIMARY, NULL);
if (ret) {
kfree(primary);
diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
index bc98bb94264d..495626e9bc04 100644
--- a/drivers/gpu/drm/drm_of.c
+++ b/drivers/gpu/drm/drm_of.c
@@ -64,8 +64,10 @@ uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
EXPORT_SYMBOL(drm_of_find_possible_crtcs);
/**
- * drm_of_component_probe - Generic probe function for a component based master
+ * drm_of_component_probe_with_match - Generic probe function with match
+ * entries for a component based master
* @dev: master device containing the OF node
+ * @match: component match pointer provided to store matches
* @compare_of: compare function used for matching components
* @master_ops: component master ops to be used
*
@@ -76,12 +78,12 @@ EXPORT_SYMBOL(drm_of_find_possible_crtcs);
*
* Returns zero if successful, or one of the standard error codes if it fails.
*/
-int drm_of_component_probe(struct device *dev,
+int drm_of_component_probe_with_match(struct device *dev,
+ struct component_match *match,
int (*compare_of)(struct device *, void *),
const struct component_master_ops *m_ops)
{
struct device_node *ep, *port, *remote;
- struct component_match *match = NULL;
int i;
if (!dev->of_node)
@@ -148,6 +150,29 @@ int drm_of_component_probe(struct device *dev,
return component_master_add_with_match(dev, m_ops, match);
}
+EXPORT_SYMBOL(drm_of_component_probe_with_match);
+
+/**
+ * drm_of_component_probe - Generic probe function for a component based master
+ * @dev: master device containing the OF node
+ * @compare_of: compare function used for matching components
+ * @master_ops: component master ops to be used
+ *
+ * Parse the platform device OF node and bind all the components associated
+ * with the master. Interface ports are added before the encoders in order to
+ * satisfy their .bind requirements
+ * See Documentation/devicetree/bindings/graph.txt for the bindings.
+ *
+ * Returns zero if successful, or one of the standard error codes if it fails.
+ */
+int drm_of_component_probe(struct device *dev,
+ int (*compare_of)(struct device *, void *),
+ const struct component_master_ops *m_ops)
+{
+ struct component_match *match = NULL;
+
+ return drm_of_component_probe_with_match(dev, match, compare_of, m_ops);
+}
EXPORT_SYMBOL(drm_of_component_probe);
/*
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index 249c0ae52c6d..a8e9c854db6d 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -62,6 +62,87 @@ static unsigned int drm_num_planes(struct drm_device *dev)
return num;
}
+static inline u32 *
+formats_ptr(struct drm_format_modifier_blob *blob)
+{
+ return (u32 *)(((char *)blob) + blob->formats_offset);
+}
+
+static inline struct drm_format_modifier *
+modifiers_ptr(struct drm_format_modifier_blob *blob)
+{
+ return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
+}
+
+static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane)
+{
+ const struct drm_mode_config *config = &dev->mode_config;
+ struct drm_property_blob *blob;
+ struct drm_format_modifier *mod;
+ size_t blob_size, formats_size, modifiers_size;
+ struct drm_format_modifier_blob *blob_data;
+ unsigned int i, j;
+
+ formats_size = sizeof(__u32) * plane->format_count;
+ if (WARN_ON(!formats_size)) {
+ /* 0 formats are never expected */
+ return 0;
+ }
+
+ modifiers_size =
+ sizeof(struct drm_format_modifier) * plane->modifier_count;
+
+ blob_size = sizeof(struct drm_format_modifier_blob);
+ /* Modifiers offset is a pointer to a struct with a 64 bit field so it
+ * should be naturally aligned to 8B.
+ */
+ BUILD_BUG_ON(sizeof(struct drm_format_modifier_blob) % 8);
+ blob_size += ALIGN(formats_size, 8);
+ blob_size += modifiers_size;
+
+ blob = drm_property_create_blob(dev, blob_size, NULL);
+ if (IS_ERR(blob))
+ return -1;
+
+ blob_data = (struct drm_format_modifier_blob *)blob->data;
+ blob_data->version = FORMAT_BLOB_CURRENT;
+ blob_data->count_formats = plane->format_count;
+ blob_data->formats_offset = sizeof(struct drm_format_modifier_blob);
+ blob_data->count_modifiers = plane->modifier_count;
+
+ blob_data->modifiers_offset =
+ ALIGN(blob_data->formats_offset + formats_size, 8);
+
+ memcpy(formats_ptr(blob_data), plane->format_types, formats_size);
+
+ /* If we can't determine support, just bail */
+ if (!plane->funcs->format_mod_supported)
+ goto done;
+
+ mod = modifiers_ptr(blob_data);
+ for (i = 0; i < plane->modifier_count; i++) {
+ for (j = 0; j < plane->format_count; j++) {
+ if (plane->funcs->format_mod_supported(plane,
+ plane->format_types[j],
+ plane->modifiers[i])) {
+
+ mod->formats |= 1ULL << j;
+ }
+ }
+
+ mod->modifier = plane->modifiers[i];
+ mod->offset = 0;
+ mod->pad = 0;
+ mod++;
+ }
+
+done:
+ drm_object_attach_property(&plane->base, config->modifiers_property,
+ blob->base.id);
+
+ return 0;
+}
+
/**
* drm_universal_plane_init - Initialize a new universal plane object
* @dev: DRM device
@@ -70,6 +151,8 @@ static unsigned int drm_num_planes(struct drm_device *dev)
* @funcs: callbacks for the new plane
* @formats: array of supported formats (DRM_FORMAT\_\*)
* @format_count: number of elements in @formats
+ * @format_modifiers: array of struct drm_format modifiers terminated by
+ * DRM_FORMAT_MOD_INVALID
* @type: type of plane (overlay, primary, cursor)
* @name: printf style format string for the plane name, or NULL for default name
*
@@ -79,13 +162,15 @@ static unsigned int drm_num_planes(struct drm_device *dev)
* Zero on success, error code on failure.
*/
int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
- unsigned long possible_crtcs,
+ uint32_t possible_crtcs,
const struct drm_plane_funcs *funcs,
const uint32_t *formats, unsigned int format_count,
+ const uint64_t *format_modifiers,
enum drm_plane_type type,
const char *name, ...)
{
struct drm_mode_config *config = &dev->mode_config;
+ unsigned int format_modifier_count = 0;
int ret;
ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
@@ -105,6 +190,31 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
return -ENOMEM;
}
+ /*
+ * First driver to need more than 64 formats needs to fix this. Each
+ * format is encoded as a bit and the current code only supports a u64.
+ */
+ if (WARN_ON(format_count > 64))
+ return -EINVAL;
+
+ if (format_modifiers) {
+ const uint64_t *temp_modifiers = format_modifiers;
+ while (*temp_modifiers++ != DRM_FORMAT_MOD_INVALID)
+ format_modifier_count++;
+ }
+
+ plane->modifier_count = format_modifier_count;
+ plane->modifiers = kmalloc_array(format_modifier_count,
+ sizeof(format_modifiers[0]),
+ GFP_KERNEL);
+
+ if (format_modifier_count && !plane->modifiers) {
+ DRM_DEBUG_KMS("out of memory when allocating plane\n");
+ kfree(plane->format_types);
+ drm_mode_object_unregister(dev, &plane->base);
+ return -ENOMEM;
+ }
+
if (name) {
va_list ap;
@@ -117,12 +227,15 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
}
if (!plane->name) {
kfree(plane->format_types);
+ kfree(plane->modifiers);
drm_mode_object_unregister(dev, &plane->base);
return -ENOMEM;
}
memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
plane->format_count = format_count;
+ memcpy(plane->modifiers, format_modifiers,
+ format_modifier_count * sizeof(format_modifiers[0]));
plane->possible_crtcs = possible_crtcs;
plane->type = type;
@@ -148,6 +261,9 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
drm_object_attach_property(&plane->base, config->prop_src_h, 0);
}
+ if (config->allow_fb_modifiers)
+ create_in_format_blob(dev, plane);
+
return 0;
}
EXPORT_SYMBOL(drm_universal_plane_init);
@@ -195,7 +311,7 @@ void drm_plane_unregister_all(struct drm_device *dev)
* Zero on success, error code on failure.
*/
int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
- unsigned long possible_crtcs,
+ uint32_t possible_crtcs,
const struct drm_plane_funcs *funcs,
const uint32_t *formats, unsigned int format_count,
bool is_primary)
@@ -204,7 +320,8 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
- formats, format_count, type, NULL);
+ formats, format_count,
+ NULL, type, NULL);
}
EXPORT_SYMBOL(drm_plane_init);
@@ -222,6 +339,7 @@ void drm_plane_cleanup(struct drm_plane *plane)
drm_modeset_lock_all(dev);
kfree(plane->format_types);
+ kfree(plane->modifiers);
drm_mode_object_unregister(dev, &plane->base);
BUG_ON(list_empty(&plane->head));
@@ -335,43 +453,38 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
struct drm_mode_config *config;
struct drm_plane *plane;
uint32_t __user *plane_ptr;
- int copied = 0;
- unsigned num_planes;
+ int count = 0;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
config = &dev->mode_config;
-
- if (file_priv->universal_planes)
- num_planes = config->num_total_plane;
- else
- num_planes = config->num_overlay_plane;
+ plane_ptr = u64_to_user_ptr(plane_resp->plane_id_ptr);
/*
* This ioctl is called twice, once to determine how much space is
* needed, and the 2nd time to fill it.
*/
- if (num_planes &&
- (plane_resp->count_planes >= num_planes)) {
- plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
-
- /* Plane lists are invariant, no locking needed. */
- drm_for_each_plane(plane, dev) {
- /*
- * Unless userspace set the 'universal planes'
- * capability bit, only advertise overlays.
- */
- if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
- !file_priv->universal_planes)
- continue;
-
- if (put_user(plane->base.id, plane_ptr + copied))
+
+ /* Plane lists are invariant, no locking needed. */
+ drm_for_each_plane(plane, dev) {
+ /*
+ * Unless userspace set the 'universal planes'
+ * capability bit, only advertise overlays.
+ */
+ if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
+ !file_priv->universal_planes)
+ continue;
+
+ if (drm_lease_held(file_priv, plane->base.id)) {
+ if (count < plane_resp->count_planes &&
+ put_user(plane->base.id, plane_ptr + count))
return -EFAULT;
- copied++;
+
+ count++;
}
}
- plane_resp->count_planes = num_planes;
+ plane_resp->count_planes = count;
return 0;
}
@@ -386,12 +499,12 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
- plane = drm_plane_find(dev, plane_resp->plane_id);
+ plane = drm_plane_find(dev, file_priv, plane_resp->plane_id);
if (!plane)
return -ENOENT;
drm_modeset_lock(&plane->mutex, NULL);
- if (plane->crtc)
+ if (plane->crtc && drm_lease_held(file_priv, plane->crtc->base.id))
plane_resp->crtc_id = plane->crtc->base.id;
else
plane_resp->crtc_id = 0;
@@ -403,7 +516,8 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
drm_modeset_unlock(&plane->mutex);
plane_resp->plane_id = plane->base.id;
- plane_resp->possible_crtcs = plane->possible_crtcs;
+ plane_resp->possible_crtcs = drm_lease_filter_crtcs(file_priv,
+ plane->possible_crtcs);
plane_resp->gamma_size = 0;
/*
@@ -557,7 +671,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
* First, find the plane, crtc, and fb objects. If not available,
* we don't bother to call the driver.
*/
- plane = drm_plane_find(dev, plane_req->plane_id);
+ plane = drm_plane_find(dev, file_priv, plane_req->plane_id);
if (!plane) {
DRM_DEBUG_KMS("Unknown plane ID %d\n",
plane_req->plane_id);
@@ -565,14 +679,14 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
}
if (plane_req->fb_id) {
- fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
+ fb = drm_framebuffer_lookup(dev, file_priv, plane_req->fb_id);
if (!fb) {
DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
plane_req->fb_id);
return -ENOENT;
}
- crtc = drm_crtc_find(dev, plane_req->crtc_id);
+ crtc = drm_crtc_find(dev, file_priv, plane_req->crtc_id);
if (!crtc) {
DRM_DEBUG_KMS("Unknown crtc ID %d\n",
plane_req->crtc_id);
@@ -680,7 +794,7 @@ static int drm_mode_cursor_common(struct drm_device *dev,
if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
return -EINVAL;
- crtc = drm_crtc_find(dev, req->crtc_id);
+ crtc = drm_crtc_find(dev, file_priv, req->crtc_id);
if (!crtc) {
DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
return -ENOENT;
@@ -779,7 +893,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
return -EINVAL;
- crtc = drm_crtc_find(dev, page_flip->crtc_id);
+ crtc = drm_crtc_find(dev, file_priv, page_flip->crtc_id);
if (!crtc)
return -ENOENT;
@@ -832,7 +946,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
goto out;
}
- fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
+ fb = drm_framebuffer_lookup(dev, file_priv, page_flip->fb_id);
if (!fb) {
ret = -ENOENT;
goto out;
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index b22a94dd7b53..8d77b2462594 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -290,7 +290,8 @@ static void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
*
* This wraps dma_buf_export() for use by generic GEM drivers that are using
* drm_gem_dmabuf_release(). In addition to calling dma_buf_export(), we take
- * a reference to the drm_device which is released by drm_gem_dmabuf_release().
+ * a reference to the &drm_device and the exported &drm_gem_object (stored in
+ * exp_info->priv) which is released by drm_gem_dmabuf_release().
*
* Returns the new dmabuf.
*/
@@ -300,8 +301,11 @@ struct dma_buf *drm_gem_dmabuf_export(struct drm_device *dev,
struct dma_buf *dma_buf;
dma_buf = dma_buf_export(exp_info);
- if (!IS_ERR(dma_buf))
- drm_dev_ref(dev);
+ if (IS_ERR(dma_buf))
+ return dma_buf;
+
+ drm_dev_ref(dev);
+ drm_gem_object_reference(exp_info->priv);
return dma_buf;
}
@@ -472,8 +476,6 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev,
*/
obj->dma_buf = dmabuf;
get_dma_buf(obj->dma_buf);
- /* Grab a new ref since the callers is now used by the dma-buf */
- drm_gem_object_reference(obj);
return dmabuf;
}
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index d7822bef1986..c1267f070745 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -330,6 +330,10 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
if (mode->status == MODE_OK && connector_funcs->mode_valid)
mode->status = connector_funcs->mode_valid(connector,
mode);
+
+ if (mode->status == MODE_OK)
+ mode->status = drm_mode_validate_ycbcr420(mode,
+ connector);
}
prune:
diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c
index a4d81cf4ffa0..96f9060a3831 100644
--- a/drivers/gpu/drm/drm_property.c
+++ b/drivers/gpu/drm/drm_property.c
@@ -452,7 +452,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
return -EINVAL;
drm_modeset_lock_all(dev);
- property = drm_property_find(dev, out_resp->prop_id);
+ property = drm_property_find(dev, file_priv, out_resp->prop_id);
if (!property) {
ret = -ENOENT;
goto done;
@@ -648,7 +648,7 @@ struct drm_property_blob *drm_property_lookup_blob(struct drm_device *dev,
struct drm_mode_object *obj;
struct drm_property_blob *blob = NULL;
- obj = __drm_mode_object_find(dev, id, DRM_MODE_OBJECT_BLOB);
+ obj = __drm_mode_object_find(dev, NULL, id, DRM_MODE_OBJECT_BLOB);
if (obj)
blob = obj_to_blob(obj);
return blob;
@@ -888,7 +888,7 @@ bool drm_property_change_valid_get(struct drm_property *property,
if (value == 0)
return true;
- *ref = __drm_mode_object_find(property->dev, value,
+ *ref = __drm_mode_object_find(property->dev, NULL, value,
property->values[0]);
return *ref != NULL;
}
diff --git a/drivers/gpu/drm/drm_scdc_helper.c b/drivers/gpu/drm/drm_scdc_helper.c
new file mode 100644
index 000000000000..3cd96a95736d
--- /dev/null
+++ b/drivers/gpu/drm/drm_scdc_helper.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2015 NVIDIA Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <drm/drm_scdc_helper.h>
+#include <drm/drmP.h>
+
+/**
+ * DOC: scdc helpers
+ *
+ * Status and Control Data Channel (SCDC) is a mechanism introduced by the
+ * HDMI 2.0 specification. It is a point-to-point protocol that allows the
+ * HDMI source and HDMI sink to exchange data. The same I2C interface that
+ * is used to access EDID serves as the transport mechanism for SCDC.
+ */
+
+#define SCDC_I2C_SLAVE_ADDRESS 0x54
+
+/**
+ * drm_scdc_read - read a block of data from SCDC
+ * @adapter: I2C controller
+ * @offset: start offset of block to read
+ * @buffer: return location for the block to read
+ * @size: size of the block to read
+ *
+ * Reads a block of data from SCDC, starting at a given offset.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
+ size_t size)
+{
+ int ret;
+ struct i2c_msg msgs[2] = {
+ {
+ .addr = SCDC_I2C_SLAVE_ADDRESS,
+ .flags = 0,
+ .len = 1,
+ .buf = &offset,
+ }, {
+ .addr = SCDC_I2C_SLAVE_ADDRESS,
+ .flags = I2C_M_RD,
+ .len = size,
+ .buf = buffer,
+ }
+ };
+
+ ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret < 0)
+ return ret;
+ if (ret != ARRAY_SIZE(msgs))
+ return -EPROTO;
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_scdc_read);
+
+/**
+ * drm_scdc_write - write a block of data to SCDC
+ * @adapter: I2C controller
+ * @offset: start offset of block to write
+ * @buffer: block of data to write
+ * @size: size of the block to write
+ *
+ * Writes a block of data to SCDC, starting at a given offset.
+ *
+ * Returns:
+ * 0 on success, negative error code on failure.
+ */
+ssize_t drm_scdc_write(struct i2c_adapter *adapter, u8 offset,
+ const void *buffer, size_t size)
+{
+ struct i2c_msg msg = {
+ .addr = SCDC_I2C_SLAVE_ADDRESS,
+ .flags = 0,
+ .len = 1 + size,
+ .buf = NULL,
+ };
+ void *data;
+ int err;
+
+ data = kmalloc(1 + size, GFP_TEMPORARY);
+ if (!data)
+ return -ENOMEM;
+
+ msg.buf = data;
+
+ memcpy(data, &offset, sizeof(offset));
+ memcpy(data + 1, buffer, size);
+
+ err = i2c_transfer(adapter, &msg, 1);
+
+ kfree(data);
+
+ if (err < 0)
+ return err;
+ if (err != 1)
+ return -EPROTO;
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_scdc_write);
+
+/**
+ * drm_scdc_check_scrambling_status - what is status of scrambling?
+ * @adapter: I2C adapter for DDC channel
+ *
+ * Reads the scrambler status over SCDC, and checks the
+ * scrambling status.
+ *
+ * Returns:
+ * True if the scrambling is enabled, false otherwise.
+ */
+
+bool drm_scdc_get_scrambling_status(struct i2c_adapter *adapter)
+{
+ u8 status;
+ int ret;
+
+ ret = drm_scdc_readb(adapter, SCDC_SCRAMBLER_STATUS, &status);
+ if (ret < 0) {
+ DRM_ERROR("Failed to read scrambling status, error %d\n", ret);
+ return false;
+ }
+
+ return status & SCDC_SCRAMBLING_STATUS;
+}
+EXPORT_SYMBOL(drm_scdc_get_scrambling_status);
+
+/**
+ * drm_scdc_set_scrambling - enable scrambling
+ * @adapter: I2C adapter for DDC channel
+ * @enable: bool to indicate if scrambling is to be enabled/disabled
+ *
+ * Writes the TMDS config register over SCDC channel, and:
+ * enables scrambling when enable = 1
+ * disables scrambling when enable = 0
+ *
+ * Returns:
+ * True if scrambling is set/reset successfully, false otherwise.
+ */
+
+bool drm_scdc_set_scrambling(struct i2c_adapter *adapter, bool enable)
+{
+ u8 config;
+ int ret;
+
+ ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
+ if (ret < 0) {
+ DRM_ERROR("Failed to read tmds config, err=%d\n", ret);
+ return false;
+ }
+
+ if (enable)
+ config |= SCDC_SCRAMBLING_ENABLE;
+ else
+ config &= ~SCDC_SCRAMBLING_ENABLE;
+
+ ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config);
+ if (ret < 0) {
+ DRM_ERROR("Failed to enable scrambling, error %d\n", ret);
+ return false;
+ }
+
+ return true;
+}
+EXPORT_SYMBOL(drm_scdc_set_scrambling);
+
+/**
+ * drm_scdc_set_high_tmds_clock_ratio - set TMDS clock ratio
+ * @adapter: I2C adapter for DDC channel
+ * @set: ret or reset the high clock ratio
+ *
+ * TMDS clock ratio calculations go like this:
+ * TMDS character = 10 bit TMDS encoded value
+ * TMDS character rate = The rate at which TMDS characters are transmitted(Mcsc)
+ * TMDS bit rate = 10x TMDS character rate
+ * As per the spec:
+ * TMDS clock rate for pixel clock < 340 MHz = 1x the character rate
+ * = 1/10 pixel clock rate
+ * TMDS clock rate for pixel clock > 340 MHz = 0.25x the character rate
+ * = 1/40 pixel clock rate
+ *
+ * Writes to the TMDS config register over SCDC channel, and:
+ * sets TMDS clock ratio to 1/40 when set = 1
+ * sets TMDS clock ratio to 1/10 when set = 0
+ *
+ * Returns:
+ * True if write is successful, false otherwise.
+ */
+bool drm_scdc_set_high_tmds_clock_ratio(struct i2c_adapter *adapter, bool set)
+{
+ u8 config;
+ int ret;
+
+ ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
+ if (ret < 0) {
+ DRM_ERROR("Failed to read tmds config, err=%d\n", ret);
+ return false;
+ }
+
+ if (set)
+ config |= SCDC_TMDS_BIT_CLOCK_RATIO_BY_40;
+ else
+ config &= ~SCDC_TMDS_BIT_CLOCK_RATIO_BY_40;
+
+ ret = drm_scdc_writeb(adapter, SCDC_TMDS_CONFIG, config);
+ if (ret < 0) {
+ DRM_ERROR("Failed to set TMDS clock ratio, error %d\n", ret);
+ return false;
+ }
+
+ /*
+ * The spec says that a source should wait minimum 1ms and maximum
+ * 100ms after writing the TMDS config for clock ratio. Lets allow a
+ * wait of upto 2ms here.
+ */
+ usleep_range(1000, 2000);
+ return true;
+}
+EXPORT_SYMBOL(drm_scdc_set_high_tmds_clock_ratio);
diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
index 7bae08c2bf0a..83ce9bf35149 100644
--- a/drivers/gpu/drm/drm_simple_kms_helper.c
+++ b/drivers/gpu/drm/drm_simple_kms_helper.c
@@ -212,6 +212,7 @@ EXPORT_SYMBOL(drm_simple_display_pipe_detach_bridge);
* @funcs: callbacks for the display pipe (optional)
* @formats: array of supported formats (DRM_FORMAT\_\*)
* @format_count: number of elements in @formats
+ * @format_modifiers: array of formats modifiers
* @connector: connector to attach and register (optional)
*
* Sets up a display pipeline which consist of a really simple
@@ -232,6 +233,7 @@ int drm_simple_display_pipe_init(struct drm_device *dev,
struct drm_simple_display_pipe *pipe,
const struct drm_simple_display_pipe_funcs *funcs,
const uint32_t *formats, unsigned int format_count,
+ const uint64_t *format_modifiers,
struct drm_connector *connector)
{
struct drm_encoder *encoder = &pipe->encoder;
@@ -246,6 +248,7 @@ int drm_simple_display_pipe_init(struct drm_device *dev,
ret = drm_universal_plane_init(dev, plane, 0,
&drm_simple_kms_plane_funcs,
formats, format_count,
+ format_modifiers,
DRM_PLANE_TYPE_PRIMARY, NULL);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index c2f17f30afab..75d4928dd196 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -284,7 +284,7 @@ int exynos_plane_init(struct drm_device *dev,
&exynos_plane_funcs,
config->pixel_formats,
config->num_pixel_formats,
- config->type, NULL);
+ NULL, config->type, NULL);
if (err) {
DRM_ERROR("failed to initialize plane\n");
return err;
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c
index a99f48847420..c3c6f939f583 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c
@@ -224,7 +224,7 @@ struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev)
&fsl_dcu_drm_plane_funcs,
fsl_dcu_drm_plane_formats,
ARRAY_SIZE(fsl_dcu_drm_plane_formats),
- DRM_PLANE_TYPE_PRIMARY, NULL);
+ NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
if (ret) {
kfree(primary);
primary = NULL;
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
index 0f563c954520..d15970595580 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
@@ -915,7 +915,7 @@ static int ade_plane_init(struct drm_device *dev, struct ade_plane *aplane,
return ret;
ret = drm_universal_plane_init(dev, &aplane->base, 1, &ade_plane_funcs,
- fmts, fmts_cnt, type, NULL);
+ fmts, fmts_cnt, NULL, type, NULL);
if (ret) {
DRM_ERROR("fail to init plane, ch=%d\n", aplane->ch);
return ret;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index c185625d67f2..388b30c273f7 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -14989,18 +14989,21 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
ret = drm_universal_plane_init(dev, &primary->base, 0,
&intel_plane_funcs,
intel_primary_formats, num_formats,
+ NULL,
DRM_PLANE_TYPE_PRIMARY,
"plane 1%c", pipe_name(pipe));
else if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev))
ret = drm_universal_plane_init(dev, &primary->base, 0,
&intel_plane_funcs,
intel_primary_formats, num_formats,
+ NULL,
DRM_PLANE_TYPE_PRIMARY,
"primary %c", pipe_name(pipe));
else
ret = drm_universal_plane_init(dev, &primary->base, 0,
&intel_plane_funcs,
intel_primary_formats, num_formats,
+ NULL,
DRM_PLANE_TYPE_PRIMARY,
"plane %c", plane_name(primary->plane));
if (ret)
@@ -15159,7 +15162,7 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
&intel_plane_funcs,
intel_cursor_formats,
ARRAY_SIZE(intel_cursor_formats),
- DRM_PLANE_TYPE_CURSOR,
+ NULL, DRM_PLANE_TYPE_CURSOR,
"cursor %c", pipe_name(pipe));
if (ret)
goto fail;
@@ -15306,7 +15309,7 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
struct drm_crtc *drmmode_crtc;
struct intel_crtc *crtc;
- drmmode_crtc = drm_crtc_find(dev, pipe_from_crtc_id->crtc_id);
+ drmmode_crtc = drm_crtc_find(dev, file, pipe_from_crtc_id->crtc_id);
if (!drmmode_crtc)
return -ENOENT;
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index 8ab6f30dc23c..cc3370071639 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -1136,7 +1136,7 @@ int intel_overlay_put_image_ioctl(struct drm_device *dev, void *data,
if (!params)
return -ENOMEM;
- drmmode_crtc = drm_crtc_find(dev, put_image_rec->crtc_id);
+ drmmode_crtc = drm_crtc_find(dev, file_priv, put_image_rec->crtc_id);
if (!drmmode_crtc) {
ret = -ENOENT;
goto out_free;
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 64f4e2e18594..f23aaf7366a8 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -980,7 +980,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
set->flags & I915_SET_COLORKEY_DESTINATION)
return -EINVAL;
- plane = drm_plane_find(dev, set->plane_id);
+ plane = drm_plane_find(dev, file_priv, set->plane_id);
if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY)
return -ENOENT;
@@ -1153,13 +1153,13 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs,
&intel_plane_funcs,
plane_formats, num_plane_formats,
- DRM_PLANE_TYPE_OVERLAY,
+ NULL, DRM_PLANE_TYPE_OVERLAY,
"plane %d%c", plane + 2, pipe_name(pipe));
else
ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs,
&intel_plane_funcs,
plane_formats, num_plane_formats,
- DRM_PLANE_TYPE_OVERLAY,
+ NULL, DRM_PLANE_TYPE_OVERLAY,
"sprite %c", sprite_name(pipe, plane));
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig
index f2c9ae822149..9bb79527ca35 100644
--- a/drivers/gpu/drm/imx/Kconfig
+++ b/drivers/gpu/drm/imx/Kconfig
@@ -4,8 +4,8 @@ config DRM_IMX
select VIDEOMODE_HELPERS
select DRM_GEM_CMA_HELPER
select DRM_KMS_CMA_HELPER
- depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM)
- depends on IMX_IPUV3_CORE
+ depends on DRM
+ depends on IMX_IPUV3_CORE || IMX_DPU_CORE || IMX_DCSS_CORE || IMX_LCDIF_CORE
help
enable i.MX graphics support
@@ -29,14 +29,7 @@ config DRM_IMX_LDB
select DRM_PANEL
help
Choose this to enable the internal LVDS Display Bridge (LDB)
- found on i.MX53 and i.MX6 processors.
-
-config DRM_IMX_IPUV3
- tristate
- depends on DRM_IMX
- depends on IMX_IPUV3_CORE
- default y if DRM_IMX=y
- default m if DRM_IMX=m
+ found on i.MX53, i.MX6 and i.MX8 processors.
config DRM_IMX_HDMI
tristate "Freescale i.MX DRM HDMI"
@@ -44,3 +37,27 @@ config DRM_IMX_HDMI
depends on DRM_IMX
help
Choose this if you want to use HDMI on i.MX6.
+
+config DRM_IMX_NWL_DSI
+ tristate "Support for Northwest Logic MIPI DSI displays"
+ depends on DRM_IMX
+ select MFD_SYSCON
+ select DRM_NWL_DSI
+ help
+ Choose this to enable the internal NWL MIPI DSI controller
+ found on i.MX8 processors.
+
+config DRM_IMX_SEC_DSIM
+ tristate "Support for Samsung MIPI DSIM displays"
+ depends on DRM_IMX
+ select MFD_SYSCON
+ select DRM_SEC_MIPI_DSIM
+ help
+ Choose this to enable the internal SEC MIPI DSIM controller
+ found on i.MX platform.
+
+source "drivers/gpu/drm/imx/ipuv3/Kconfig"
+source "drivers/gpu/drm/imx/dpu/Kconfig"
+source "drivers/gpu/drm/imx/hdp/Kconfig"
+source "drivers/gpu/drm/imx/dcss/Kconfig"
+source "drivers/gpu/drm/imx/lcdif/Kconfig"
diff --git a/drivers/gpu/drm/imx/Makefile b/drivers/gpu/drm/imx/Makefile
index f3ecd8903d97..91832561814e 100644
--- a/drivers/gpu/drm/imx/Makefile
+++ b/drivers/gpu/drm/imx/Makefile
@@ -6,7 +6,11 @@ obj-$(CONFIG_DRM_IMX) += imxdrm.o
obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
-
-imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o
-obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o
obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
+obj-$(CONFIG_DRM_IMX_NWL_DSI) += nwl_dsi-imx.o
+obj-$(CONFIG_DRM_IMX_SEC_DSIM) += sec_mipi_dsim-imx.o
+obj-$(CONFIG_DRM_IMX_IPUV3) += ipuv3/
+obj-$(CONFIG_DRM_IMX_DPU) += dpu/
+obj-$(CONFIG_DRM_IMX_HDP) += hdp/
+obj-$(CONFIG_DRM_IMX_DCSS) += dcss/
+obj-$(CONFIG_DRM_IMX_LCDIF) += lcdif/
diff --git a/drivers/gpu/drm/imx/dcss/Kconfig b/drivers/gpu/drm/imx/dcss/Kconfig
new file mode 100644
index 000000000000..f9581556aa3c
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/Kconfig
@@ -0,0 +1,6 @@
+config DRM_IMX_DCSS
+ tristate
+ depends on DRM_IMX
+ depends on IMX_DCSS_CORE
+ default y if DRM_IMX=y
+ default m if DRM_IMX=m
diff --git a/drivers/gpu/drm/imx/dcss/Makefile b/drivers/gpu/drm/imx/dcss/Makefile
new file mode 100644
index 000000000000..f7f7e9e9b550
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/Makefile
@@ -0,0 +1,4 @@
+ccflags-y += -Idrivers/gpu/drm/imx
+
+imx-dcss-crtc-objs := dcss-crtc.o dcss-plane.o dcss-kms.o
+obj-$(CONFIG_DRM_IMX_DCSS) += imx-dcss-crtc.o
diff --git a/drivers/gpu/drm/imx/dcss/dcss-crtc.c b/drivers/gpu/drm/imx/dcss/dcss-crtc.c
new file mode 100644
index 000000000000..6bd818009381
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-crtc.c
@@ -0,0 +1,501 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/component.h>
+#include <linux/pm_runtime.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
+#include <video/imx-dcss.h>
+
+#include "dcss-kms.h"
+#include "dcss-plane.h"
+#include "imx-drm.h"
+#include "dcss-crtc.h"
+
+#define TRACE_FLUSH 0
+#define TRACE_VBLANK 1
+
+struct dcss_crtc {
+ struct device *dev;
+ struct drm_crtc base;
+ struct imx_drm_crtc *imx_crtc;
+
+ struct dcss_plane *plane[3];
+
+ int irq;
+ bool irq_enabled;
+
+ struct drm_property *alpha;
+ struct drm_property *use_global;
+ struct drm_property *dtrc_table_ofs;
+
+ struct completion en_dis_completion;
+
+ enum dcss_hdr10_nonlinearity opipe_nl;
+ enum dcss_hdr10_gamut opipe_g;
+ enum dcss_hdr10_pixel_range opipe_pr;
+ u32 opipe_pix_format;
+};
+
+static void dcss_crtc_destroy(struct drm_crtc *crtc)
+{
+ struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+ base);
+
+ imx_drm_remove_crtc(dcss_crtc->imx_crtc);
+}
+
+static void dcss_crtc_reset(struct drm_crtc *crtc)
+{
+ struct imx_crtc_state *state;
+
+ if (crtc->state) {
+ if (crtc->state->mode_blob)
+ drm_property_unreference_blob(crtc->state->mode_blob);
+
+ state = to_imx_crtc_state(crtc->state);
+ memset(state, 0, sizeof(*state));
+ } else {
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return;
+ crtc->state = &state->base;
+ }
+
+ state->base.crtc = crtc;
+}
+
+static struct drm_crtc_state *dcss_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+ struct imx_crtc_state *state;
+
+ if (!crtc->state)
+ return NULL;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return NULL;
+
+ __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+
+ WARN_ON(state->base.crtc != crtc);
+ state->base.crtc = crtc;
+
+ return &state->base;
+}
+
+static void dcss_crtc_destroy_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ __drm_atomic_helper_crtc_destroy_state(state);
+ kfree(to_imx_crtc_state(state));
+}
+
+static const struct drm_crtc_funcs dcss_crtc_funcs = {
+ .set_config = drm_atomic_helper_set_config,
+ .destroy = dcss_crtc_destroy,
+ .page_flip = drm_atomic_helper_page_flip,
+ .reset = dcss_crtc_reset,
+ .atomic_duplicate_state = dcss_crtc_duplicate_state,
+ .atomic_destroy_state = dcss_crtc_destroy_state,
+};
+
+static int dcss_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ /* TODO: other checks? */
+
+ return 0;
+}
+
+static void dcss_crtc_atomic_begin(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+ drm_crtc_vblank_on(crtc);
+
+ spin_lock_irq(&crtc->dev->event_lock);
+ if (crtc->state->event) {
+ WARN_ON(drm_crtc_vblank_get(crtc));
+ drm_crtc_arm_vblank_event(crtc, crtc->state->event);
+ crtc->state->event = NULL;
+ }
+ spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static void dcss_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+ struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+ base);
+ struct dcss_soc *dcss = dev_get_drvdata(dcss_crtc->dev->parent);
+
+ dcss_trace_module(TRACE_DRM_CRTC, TRACE_FLUSH);
+
+ if (dcss_dtg_is_enabled(dcss))
+ dcss_ctxld_enable(dcss);
+}
+
+void dcss_crtc_setup_opipe(struct drm_crtc *crtc, struct drm_connector *conn,
+ u32 colorimetry, u32 eotf,
+ enum hdmi_quantization_range qr)
+{
+ struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+ base);
+ struct drm_display_info *di = &conn->display_info;
+ int vic;
+
+ if ((colorimetry & BIT(HDMI_EXTENDED_COLORIMETRY_BT2020)) ||
+ (colorimetry & BIT(HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM)))
+ dcss_crtc->opipe_g = G_REC2020;
+ else if (colorimetry & BIT(HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB))
+ dcss_crtc->opipe_g = G_ADOBE_ARGB;
+ else
+ dcss_crtc->opipe_g = G_REC709;
+
+ if ((eotf & (1 << 2)) && dcss_crtc->opipe_g == G_REC2020)
+ dcss_crtc->opipe_nl = NL_REC2084;
+ else
+ dcss_crtc->opipe_nl = NL_REC709;
+
+ if (qr == HDMI_QUANTIZATION_RANGE_FULL)
+ dcss_crtc->opipe_pr = PR_FULL;
+ else
+ dcss_crtc->opipe_pr = PR_LIMITED;
+
+ vic = drm_match_cea_mode(&crtc->state->adjusted_mode);
+
+ /* FIXME: we should get the connector colorspace some other way */
+ if (vic == 97 &&
+ (di->color_formats & DRM_COLOR_FORMAT_YCRCB420) &&
+ (di->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30))
+ dcss_crtc->opipe_pix_format = DRM_FORMAT_P010;
+ else
+ dcss_crtc->opipe_pix_format = DRM_FORMAT_ARGB8888;
+
+ DRM_DEBUG_KMS("OPIPE_CFG: gamut = %d, nl = %d, pr = %d, pix_fmt = %d\n",
+ dcss_crtc->opipe_g, dcss_crtc->opipe_nl,
+ dcss_crtc->opipe_pr, dcss_crtc->opipe_pix_format);
+}
+
+int dcss_crtc_get_opipe_cfg(struct drm_crtc *crtc,
+ struct dcss_hdr10_pipe_cfg *opipe_cfg)
+{
+ struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+ base);
+
+ opipe_cfg->pixel_format = dcss_crtc->opipe_pix_format;
+ opipe_cfg->g = dcss_crtc->opipe_g;
+ opipe_cfg->nl = dcss_crtc->opipe_nl;
+ opipe_cfg->pr = dcss_crtc->opipe_pr;
+
+ return 0;
+}
+
+static int dcss_enable_vblank(struct drm_crtc *crtc);
+
+static void dcss_crtc_enable(struct drm_crtc *crtc)
+{
+ struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+ base);
+ struct dcss_soc *dcss = dev_get_drvdata(dcss_crtc->dev->parent);
+ struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+ struct videomode vm;
+
+ drm_display_mode_to_videomode(mode, &vm);
+
+ pm_runtime_get_sync(dcss_crtc->dev->parent);
+
+ dcss_enable_vblank(crtc);
+
+ dcss_dtg_sync_set(dcss, &vm);
+
+ dcss_ss_subsam_set(dcss, dcss_crtc->opipe_pix_format);
+ dcss_ss_sync_set(dcss, &vm, mode->flags & DRM_MODE_FLAG_PHSYNC,
+ mode->flags & DRM_MODE_FLAG_PVSYNC);
+
+ dcss_dtg_css_set(dcss, dcss_crtc->opipe_pix_format);
+
+ dcss_ss_enable(dcss, true);
+ dcss_dtg_enable(dcss, true, NULL);
+ dcss_ctxld_enable(dcss);
+
+ reinit_completion(&dcss_crtc->en_dis_completion);
+ wait_for_completion_timeout(&dcss_crtc->en_dis_completion,
+ msecs_to_jiffies(100));
+
+ crtc->enabled = true;
+}
+
+static void dcss_crtc_atomic_disable(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+ struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+ base);
+ struct dcss_soc *dcss = dev_get_drvdata(dcss_crtc->dev->parent);
+
+ drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false);
+
+ spin_lock_irq(&crtc->dev->event_lock);
+ if (crtc->state->event) {
+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
+ crtc->state->event = NULL;
+ }
+ spin_unlock_irq(&crtc->dev->event_lock);
+
+ dcss_ss_enable(dcss, false);
+ dcss_dtg_enable(dcss, false, &dcss_crtc->en_dis_completion);
+ dcss_ctxld_enable(dcss);
+
+ crtc->enabled = false;
+
+ reinit_completion(&dcss_crtc->en_dis_completion);
+ wait_for_completion_timeout(&dcss_crtc->en_dis_completion,
+ msecs_to_jiffies(100));
+
+ drm_crtc_vblank_off(crtc);
+
+ pm_runtime_put_sync(dcss_crtc->dev->parent);
+}
+
+static const struct drm_crtc_helper_funcs dcss_helper_funcs = {
+ .atomic_check = dcss_crtc_atomic_check,
+ .atomic_begin = dcss_crtc_atomic_begin,
+ .atomic_flush = dcss_crtc_atomic_flush,
+ .enable = dcss_crtc_enable,
+ .atomic_disable = dcss_crtc_atomic_disable,
+};
+
+static int dcss_enable_vblank(struct drm_crtc *crtc)
+{
+ struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+ base);
+ struct dcss_soc *dcss = dev_get_drvdata(dcss_crtc->dev->parent);
+
+ if (dcss_crtc->irq_enabled)
+ return 0;
+
+ dcss_crtc->irq_enabled = true;
+
+ dcss_req_pm_qos(dcss, true);
+
+ dcss_vblank_irq_enable(dcss, true);
+
+ enable_irq(dcss_crtc->irq);
+
+ return 0;
+}
+
+static void dcss_disable_vblank(struct drm_crtc *crtc)
+{
+ struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+ base);
+ struct dcss_soc *dcss = dev_get_drvdata(dcss_crtc->dev->parent);
+
+ disable_irq_nosync(dcss_crtc->irq);
+
+ dcss_vblank_irq_enable(dcss, false);
+
+ dcss_req_pm_qos(dcss, false);
+
+ dcss_crtc->irq_enabled = false;
+}
+
+static const struct imx_drm_crtc_helper_funcs dcss_crtc_helper_funcs = {
+ .enable_vblank = dcss_enable_vblank,
+ .disable_vblank = dcss_disable_vblank,
+ .crtc_funcs = &dcss_crtc_funcs,
+ .crtc_helper_funcs = &dcss_helper_funcs,
+};
+
+static irqreturn_t dcss_crtc_irq_handler(int irq, void *dev_id)
+{
+ struct dcss_crtc *dcss_crtc = dev_id;
+ struct dcss_soc *dcss = dev_get_drvdata(dcss_crtc->dev->parent);
+
+ dcss_trace_module(TRACE_DRM_CRTC, TRACE_VBLANK);
+
+ complete(&dcss_crtc->en_dis_completion);
+
+ if (dcss_ctxld_is_flushed(dcss))
+ drm_crtc_handle_vblank(&dcss_crtc->base);
+
+ dcss_vblank_irq_clear(dcss);
+
+ return IRQ_HANDLED;
+}
+
+static int dcss_crtc_init(struct dcss_crtc *crtc,
+ struct dcss_client_platformdata *pdata,
+ struct drm_device *drm)
+{
+ struct dcss_soc *dcss = dev_get_drvdata(crtc->dev->parent);
+ int ret;
+
+ crtc->plane[0] = dcss_plane_init(drm, dcss, drm_crtc_mask(&crtc->base),
+ DRM_PLANE_TYPE_PRIMARY, 2);
+ if (IS_ERR(crtc->plane[0]))
+ return PTR_ERR(crtc->plane[0]);
+
+ ret = imx_drm_add_crtc(drm, &crtc->base, &crtc->imx_crtc,
+ &crtc->plane[0]->base,
+ &dcss_crtc_helper_funcs, pdata->of_node);
+ if (ret) {
+ dev_err(crtc->dev, "failed to init crtc\n");
+ return ret;
+ }
+
+ crtc->plane[1] = dcss_plane_init(drm, dcss, drm_crtc_mask(&crtc->base),
+ DRM_PLANE_TYPE_OVERLAY, 1);
+ if (IS_ERR(crtc->plane[1]))
+ crtc->plane[1] = NULL;
+
+ crtc->plane[2] = dcss_plane_init(drm, dcss, drm_crtc_mask(&crtc->base),
+ DRM_PLANE_TYPE_OVERLAY, 0);
+ if (IS_ERR(crtc->plane[2]))
+ crtc->plane[2] = NULL;
+
+ crtc->alpha = drm_property_create_range(drm, 0, "alpha", 0, 255);
+ if (!crtc->alpha) {
+ dev_err(crtc->dev, "cannot create alpha property\n");
+ return -ENOMEM;
+ }
+
+ crtc->use_global = drm_property_create_range(drm, 0,
+ "use_global_alpha", 0, 1);
+ if (!crtc->use_global) {
+ dev_err(crtc->dev, "cannot create use_global property\n");
+ return -ENOMEM;
+ }
+
+ crtc->dtrc_table_ofs = drm_property_create_range(drm, 0,
+ "dtrc_table_ofs", 0,
+ ULLONG_MAX);
+ if (!crtc->dtrc_table_ofs) {
+ dev_err(crtc->dev, "cannot create dtrc_table_ofs property\n");
+ return -ENOMEM;
+ }
+
+ /* attach alpha property to channel 0 */
+ drm_object_attach_property(&crtc->plane[0]->base.base,
+ crtc->alpha, 255);
+ crtc->plane[0]->alpha_prop = crtc->alpha;
+
+ drm_object_attach_property(&crtc->plane[0]->base.base,
+ crtc->use_global, 0);
+ crtc->plane[0]->use_global_prop = crtc->use_global;
+
+ /* attach DTRC table offsets property to overlay planes */
+ drm_object_attach_property(&crtc->plane[1]->base.base,
+ crtc->dtrc_table_ofs, 0);
+ crtc->plane[1]->dtrc_table_ofs_prop = crtc->dtrc_table_ofs;
+
+ drm_object_attach_property(&crtc->plane[2]->base.base,
+ crtc->dtrc_table_ofs, 0);
+ crtc->plane[2]->dtrc_table_ofs_prop = crtc->dtrc_table_ofs;
+
+ crtc->irq = dcss_vblank_irq_get(dcss);
+ if (crtc->irq < 0) {
+ dev_err(crtc->dev, "unable to get vblank interrupt\n");
+ return crtc->irq;
+ }
+
+ init_completion(&crtc->en_dis_completion);
+
+ ret = devm_request_irq(crtc->dev, crtc->irq, dcss_crtc_irq_handler,
+ IRQF_TRIGGER_RISING, "dcss_drm", crtc);
+ if (ret) {
+ dev_err(crtc->dev, "irq request failed with %d.\n", ret);
+ return ret;
+ }
+
+ disable_irq(crtc->irq);
+
+ return 0;
+}
+
+static int dcss_crtc_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct dcss_client_platformdata *pdata = dev->platform_data;
+ struct drm_device *drm = data;
+ struct dcss_crtc *crtc;
+ int ret;
+
+ crtc = devm_kzalloc(dev, sizeof(*crtc), GFP_KERNEL);
+ if (!crtc)
+ return -ENOMEM;
+
+ crtc->dev = dev;
+
+ ret = dcss_crtc_init(crtc, pdata, drm);
+ if (ret)
+ return ret;
+
+ if (!drm->mode_config.funcs)
+ drm->mode_config.funcs = &dcss_drm_mode_config_funcs;
+
+ if (!drm->mode_config.helper_private)
+ drm->mode_config.helper_private = &dcss_drm_mode_config_helpers;
+
+ dev_set_drvdata(dev, crtc);
+
+ return 0;
+}
+
+static void dcss_crtc_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+}
+
+static const struct component_ops dcss_crtc_ops = {
+ .bind = dcss_crtc_bind,
+ .unbind = dcss_crtc_unbind,
+};
+
+static int dcss_crtc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ if (!dev->platform_data) {
+ dev_err(dev, "no platform data\n");
+ return -EINVAL;
+ }
+
+ return component_add(dev, &dcss_crtc_ops);
+}
+
+static int dcss_crtc_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &dcss_crtc_ops);
+ return 0;
+}
+
+static struct platform_driver dcss_crtc_driver = {
+ .driver = {
+ .name = "imx-dcss-crtc",
+ },
+ .probe = dcss_crtc_probe,
+ .remove = dcss_crtc_remove,
+};
+module_platform_driver(dcss_crtc_driver);
+
+MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@nxp.com>");
+MODULE_DESCRIPTION("i.MX DCSS CRTC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-dcss-crtc");
diff --git a/drivers/gpu/drm/imx/dcss/dcss-crtc.h b/drivers/gpu/drm/imx/dcss/dcss-crtc.h
new file mode 100644
index 000000000000..fabf1e5c44a6
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-crtc.h
@@ -0,0 +1,12 @@
+#ifndef _DCSS_CRTC_H
+#include <linux/hdmi.h>
+#include <video/imx-dcss.h>
+
+void dcss_crtc_setup_opipe(struct drm_crtc *crtc, struct drm_connector *conn,
+ u32 colorimetry, u32 eotf,
+ enum hdmi_quantization_range qr);
+
+int dcss_crtc_get_opipe_cfg(struct drm_crtc *crtc,
+ struct dcss_hdr10_pipe_cfg *opipe_cfg);
+
+#endif
diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.c b/drivers/gpu/drm/imx/dcss/dcss-kms.c
new file mode 100644
index 000000000000..dce1858268ae
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-kms.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <linux/dma-buf.h>
+#include <linux/reservation.h>
+
+#include "imx-drm.h"
+#include "dcss-crtc.h"
+
+static void dcss_drm_output_poll_changed(struct drm_device *drm)
+{
+ struct imx_drm_device *imxdrm = drm->dev_private;
+
+ drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
+}
+
+static int dcss_drm_atomic_check(struct drm_device *drm,
+ struct drm_atomic_state *state)
+{
+ int ret;
+
+ ret = drm_atomic_helper_check_modeset(drm, state);
+ if (ret)
+ return ret;
+
+ ret = drm_atomic_helper_check_planes(drm, state);
+ if (ret)
+ return ret;
+
+ /*
+ * Check modeset again in case crtc_state->mode_changed is
+ * updated in plane's ->atomic_check callback.
+ */
+ return drm_atomic_helper_check_modeset(drm, state);
+}
+
+static int dcss_drm_atomic_commit(struct drm_device *drm,
+ struct drm_atomic_state *state,
+ bool nonblock)
+{
+ struct drm_plane_state *plane_state;
+ struct drm_plane *plane;
+ struct dma_buf *dma_buf;
+ int i;
+
+ /*
+ * If the plane fb has an dma-buf attached, fish out the exclusive
+ * fence for the atomic helper to wait on.
+ */
+ for_each_plane_in_state(state, plane, plane_state, i) {
+ if ((plane->state->fb != plane_state->fb) && plane_state->fb) {
+ dma_buf = drm_fb_cma_get_gem_obj(plane_state->fb,
+ 0)->base.dma_buf;
+ if (!dma_buf)
+ continue;
+ plane_state->fence =
+ reservation_object_get_excl_rcu(dma_buf->resv);
+ }
+ }
+
+ return drm_atomic_helper_commit(drm, state, nonblock);
+}
+
+static void dcss_kms_setup_output_pipe(struct drm_atomic_state *state)
+{
+ struct drm_crtc *crtc;
+ struct drm_connector *connector;
+ struct drm_connector_state *conn_state;
+ struct drm_display_info *di;
+ int i;
+
+ for_each_connector_in_state(state, connector, conn_state, i) {
+ if (!connector->state->best_encoder)
+ continue;
+
+ if (!connector->state->crtc->state->active ||
+ !drm_atomic_crtc_needs_modeset(connector->state->crtc->state))
+ continue;
+
+ crtc = connector->state->crtc;
+ di = &connector->display_info;
+
+ dcss_crtc_setup_opipe(crtc, connector, di->hdmi.colorimetry,
+ di->hdmi.hdr_panel_metadata.eotf,
+ HDMI_QUANTIZATION_RANGE_FULL);
+ }
+}
+
+static void dcss_drm_atomic_commit_tail(struct drm_atomic_state *state)
+{
+ struct drm_device *dev = state->dev;
+
+ drm_atomic_helper_commit_modeset_disables(dev, state);
+
+ dcss_kms_setup_output_pipe(state);
+
+ drm_atomic_helper_commit_modeset_enables(dev, state);
+
+ drm_atomic_helper_commit_planes(dev, state,
+ DRM_PLANE_COMMIT_ACTIVE_ONLY);
+
+ drm_atomic_helper_commit_hw_done(state);
+
+ drm_atomic_helper_wait_for_vblanks(dev, state);
+
+ drm_atomic_helper_cleanup_planes(dev, state);
+}
+
+const struct drm_mode_config_funcs dcss_drm_mode_config_funcs = {
+ .fb_create = drm_fb_cma_create,
+ .output_poll_changed = dcss_drm_output_poll_changed,
+ .atomic_check = dcss_drm_atomic_check,
+ .atomic_commit = dcss_drm_atomic_commit,
+};
+
+struct drm_mode_config_helper_funcs dcss_drm_mode_config_helpers = {
+ .atomic_commit_tail = dcss_drm_atomic_commit_tail,
+};
diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.h b/drivers/gpu/drm/imx/dcss/dcss-kms.h
new file mode 100644
index 000000000000..d7c233a82e73
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-kms.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef _DCSS_KMS_H_
+#define _DCSS_KMS_H_
+
+extern const struct drm_mode_config_funcs dcss_drm_mode_config_funcs;
+extern struct drm_mode_config_helper_funcs dcss_drm_mode_config_helpers;
+
+#endif
diff --git a/drivers/gpu/drm/imx/dcss/dcss-plane.c b/drivers/gpu/drm/imx/dcss/dcss-plane.c
new file mode 100644
index 000000000000..479c6e1d9cc1
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-plane.c
@@ -0,0 +1,701 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_atomic.h>
+#include <linux/dma-buf.h>
+
+#include "video/imx-dcss.h"
+#include "video/viv-metadata.h"
+#include "dcss-plane.h"
+#include "dcss-crtc.h"
+
+static const u32 dcss_common_formats[] = {
+ /* RGB */
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_RGBA8888,
+ DRM_FORMAT_RGBX8888,
+ DRM_FORMAT_BGRA8888,
+ DRM_FORMAT_BGRX8888,
+ DRM_FORMAT_XRGB2101010,
+ DRM_FORMAT_XBGR2101010,
+ DRM_FORMAT_RGBX1010102,
+ DRM_FORMAT_BGRX1010102,
+ DRM_FORMAT_ARGB2101010,
+ DRM_FORMAT_ABGR2101010,
+ DRM_FORMAT_RGBA1010102,
+ DRM_FORMAT_BGRA1010102,
+
+ /* YUV444 */
+ DRM_FORMAT_AYUV,
+
+ /* YUV422 */
+ DRM_FORMAT_UYVY,
+ DRM_FORMAT_VYUY,
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_YVYU,
+
+ /* YUV420 */
+ DRM_FORMAT_NV12,
+ DRM_FORMAT_NV21,
+ DRM_FORMAT_P010,
+};
+
+static const u64 dcss_video_format_modifiers[] = {
+ DRM_FORMAT_MOD_VSI_G1_TILED,
+ DRM_FORMAT_MOD_VSI_G2_TILED,
+ DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED,
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID,
+};
+
+static const u64 dcss_graphics_format_modifiers[] = {
+ DRM_FORMAT_MOD_VIVANTE_TILED,
+ DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
+ DRM_FORMAT_MOD_VIVANTE_SUPER_TILED_FC,
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID,
+};
+
+static inline struct dcss_plane *to_dcss_plane(struct drm_plane *p)
+{
+ return container_of(p, struct dcss_plane, base);
+}
+
+static void dcss_plane_destroy(struct drm_plane *plane)
+{
+ struct dcss_plane *dcss_plane = container_of(plane, struct dcss_plane,
+ base);
+
+ DRM_DEBUG_KMS("destroy plane\n");
+
+ drm_plane_cleanup(plane);
+ kfree(dcss_plane);
+}
+
+static int dcss_plane_atomic_set_property(struct drm_plane *plane,
+ struct drm_plane_state *state,
+ struct drm_property *property,
+ uint64_t val)
+{
+ struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+
+ if (property == dcss_plane->alpha_prop)
+ dcss_plane->alpha_val = val;
+ else if (property == dcss_plane->use_global_prop)
+ dcss_plane->use_global_val = val;
+ else if (property == dcss_plane->dtrc_table_ofs_prop)
+ dcss_plane->dtrc_table_ofs_val = val;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static int dcss_plane_atomic_get_property(struct drm_plane *plane,
+ const struct drm_plane_state *state,
+ struct drm_property *property,
+ uint64_t *val)
+{
+ struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+
+ if (property == dcss_plane->alpha_prop)
+ *val = dcss_plane->alpha_val;
+ else if (property == dcss_plane->use_global_prop)
+ *val = dcss_plane->use_global_val;
+ else if (property == dcss_plane->dtrc_table_ofs_prop)
+ *val = dcss_plane->dtrc_table_ofs_val;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static bool dcss_plane_format_mod_supported(struct drm_plane *plane,
+ uint32_t format,
+ uint64_t modifier)
+{
+ switch (plane->type) {
+ case DRM_PLANE_TYPE_PRIMARY:
+ switch (format) {
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ARGB2101010:
+ return modifier == DRM_FORMAT_MOD_LINEAR ||
+ modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
+ modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED ||
+ modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED_FC;
+ default:
+ return modifier == DRM_FORMAT_MOD_LINEAR;
+ }
+ break;
+ case DRM_PLANE_TYPE_OVERLAY:
+ switch (format) {
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_P010:
+ return modifier == DRM_FORMAT_MOD_LINEAR ||
+ modifier == DRM_FORMAT_MOD_VSI_G1_TILED ||
+ modifier == DRM_FORMAT_MOD_VSI_G2_TILED ||
+ modifier == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED;
+ default:
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+}
+
+static const struct drm_plane_funcs dcss_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = dcss_plane_destroy,
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+ .set_property = drm_atomic_helper_plane_set_property,
+ .atomic_set_property = dcss_plane_atomic_set_property,
+ .atomic_get_property = dcss_plane_atomic_get_property,
+ .format_mod_supported = dcss_plane_format_mod_supported,
+};
+
+static bool dcss_plane_can_rotate(u32 pixel_format, bool mod_present,
+ u64 modifier, unsigned int rotation)
+{
+ enum dcss_color_space cs = dcss_drm_fourcc_to_colorspace(pixel_format);
+ bool linear_format = !mod_present ||
+ (mod_present && modifier == DRM_FORMAT_MOD_LINEAR);
+ u32 supported_rotation = DRM_ROTATE_0;
+
+ if (cs == DCSS_COLORSPACE_RGB && linear_format)
+ supported_rotation = DRM_ROTATE_0 | DRM_ROTATE_180 |
+ DRM_REFLECT_MASK;
+ else if (cs == DCSS_COLORSPACE_RGB &&
+ modifier == DRM_FORMAT_MOD_VIVANTE_TILED)
+ supported_rotation = DRM_ROTATE_MASK | DRM_REFLECT_MASK;
+ else if (cs == DCSS_COLORSPACE_RGB &&
+ modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED_FC)
+ supported_rotation = DRM_ROTATE_0 | DRM_ROTATE_180 |
+ DRM_REFLECT_MASK;
+ else if (cs == DCSS_COLORSPACE_YUV && linear_format &&
+ (pixel_format == DRM_FORMAT_NV12 ||
+ pixel_format == DRM_FORMAT_NV21))
+ supported_rotation = DRM_ROTATE_0 | DRM_ROTATE_180 |
+ DRM_REFLECT_MASK;
+ else if (cs == DCSS_COLORSPACE_YUV && linear_format &&
+ pixel_format == DRM_FORMAT_P010)
+ supported_rotation = DRM_ROTATE_0 | DRM_REFLECT_Y;
+
+ return !!(rotation & supported_rotation);
+}
+
+static int dcss_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *cma_obj;
+ struct drm_crtc_state *crtc_state;
+ int hdisplay, vdisplay;
+ struct drm_rect crtc_rect, disp_rect;
+
+ if (!fb)
+ return 0;
+
+ if (!state->crtc)
+ return -EINVAL;
+
+ cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+ WARN_ON(!cma_obj);
+
+ crtc_state = drm_atomic_get_existing_crtc_state(state->state,
+ state->crtc);
+
+ hdisplay = crtc_state->adjusted_mode.hdisplay;
+ vdisplay = crtc_state->adjusted_mode.vdisplay;
+
+ crtc_rect.x1 = state->crtc_x;
+ crtc_rect.x2 = state->crtc_x + state->crtc_w;
+ crtc_rect.y1 = state->crtc_y;
+ crtc_rect.y2 = state->crtc_y + state->crtc_h;
+
+ disp_rect.x1 = 0;
+ disp_rect.y1 = 0;
+ disp_rect.x2 = hdisplay;
+ disp_rect.y2 = vdisplay;
+
+ /* make sure the crtc is visible */
+ if (!drm_rect_intersect(&crtc_rect, &disp_rect))
+ return -EINVAL;
+
+ if (!dcss_plane_can_rotate(fb->pixel_format,
+ !!(fb->flags & DRM_MODE_FB_MODIFIERS),
+ fb->modifier[0],
+ state->rotation)) {
+ DRM_ERROR("requested rotation is not allowed!\n");
+ return -EINVAL;
+ }
+
+ /* cropping is only available on overlay planes when DTRC is used */
+ if (state->crtc_x < 0 || state->crtc_y < 0 ||
+ state->crtc_x + state->crtc_w > hdisplay ||
+ state->crtc_y + state->crtc_h > vdisplay) {
+ if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+ return -EINVAL;
+ else if (!(fb->flags & DRM_MODE_FB_MODIFIERS) ||
+ (fb->flags & DRM_MODE_FB_MODIFIERS &&
+ fb->modifier[0] == DRM_FORMAT_MOD_LINEAR))
+ return -EINVAL;
+ }
+
+ if (!dcss_scaler_can_scale(dcss_plane->dcss, dcss_plane->ch_num,
+ state->src_w >> 16, state->src_h >> 16,
+ state->crtc_w, state->crtc_h)) {
+ DRM_DEBUG_KMS("Invalid upscale/downscale ratio.");
+ return -EINVAL;
+ }
+
+ if ((fb->flags & DRM_MODE_FB_MODIFIERS) &&
+ !plane->funcs->format_mod_supported(plane,
+ fb->pixel_format,
+ fb->modifier[0])) {
+ DRM_INFO("Invalid modifier: %llx", fb->modifier[0]);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct drm_gem_object *dcss_plane_gem_import(struct drm_device *dev,
+ struct dma_buf *dma_buf)
+{
+ struct drm_gem_object *obj;
+
+ if (IS_ERR(dma_buf))
+ return ERR_CAST(dma_buf);
+
+ mutex_lock(&dev->object_name_lock);
+
+ obj = dev->driver->gem_prime_import(dev, dma_buf);
+
+ mutex_unlock(&dev->object_name_lock);
+
+ return obj;
+}
+
+static void dcss_plane_atomic_set_base(struct dcss_plane *dcss_plane)
+{
+ int mod_idx;
+ struct drm_plane *plane = &dcss_plane->base;
+ struct drm_plane_state *state = plane->state;
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+ unsigned long p1_ba, p2_ba;
+ dma_addr_t caddr = 0;
+ bool modifiers_present = !!(fb->flags & DRM_MODE_FB_MODIFIERS);
+ u32 pix_format = state->fb->pixel_format;
+ bool compressed = true;
+ uint32_t compressed_format = 0;
+
+ BUG_ON(!cma_obj);
+
+ p1_ba = cma_obj->paddr + fb->offsets[0] +
+ fb->pitches[0] * (state->src_y >> 16) +
+ (fb->bits_per_pixel >> 3) * (state->src_x >> 16);
+
+ p2_ba = cma_obj->paddr + fb->offsets[1] +
+ fb->pitches[1] * (state->src_y >> 16) +
+ (fb->bits_per_pixel >> 3) * (state->src_x >> 16);
+
+ dcss_dpr_addr_set(dcss_plane->dcss, dcss_plane->ch_num, p1_ba, p2_ba,
+ fb->pitches[0]);
+
+ switch (plane->type) {
+ case DRM_PLANE_TYPE_PRIMARY:
+ if (!modifiers_present) {
+ /* No modifier: bypass dec400d */
+ dcss_dec400d_bypass(dcss_plane->dcss);
+ return;
+ }
+
+ for (mod_idx = 0; mod_idx < 4; mod_idx++)
+ dcss_dec400d_set_format_mod(dcss_plane->dcss,
+ pix_format,
+ mod_idx,
+ fb->modifier[mod_idx]);
+
+ switch (fb->modifier[0]) {
+ case DRM_FORMAT_MOD_LINEAR:
+ case DRM_FORMAT_MOD_VIVANTE_TILED:
+ case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+ /* Bypass dec400d */
+ dcss_dec400d_bypass(dcss_plane->dcss);
+ return;
+ case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED_FC:
+ do {
+ struct dma_buf *dma_buf = cma_obj->base.dma_buf;
+ struct drm_gem_object *gem_obj;
+ _VIV_VIDMEM_METADATA *mdata;
+
+ if (!dma_buf) {
+ caddr = cma_obj->paddr + ALIGN(fb->height, 64) * fb->pitches[0];
+ break;
+ }
+
+ mdata = dma_buf->priv;
+ if (!mdata || mdata->magic != VIV_VIDMEM_METADATA_MAGIC) {
+ return;
+ }
+ compressed = mdata->compressed ? true : false;
+ compressed_format = mdata->compress_format;
+
+ gem_obj = dcss_plane_gem_import(plane->dev, mdata->ts_dma_buf);
+ if (IS_ERR(gem_obj)) {
+ return;
+ }
+
+ caddr = to_drm_gem_cma_obj(gem_obj)->paddr;
+
+ /* release gem_obj */
+ drm_gem_object_unreference_unlocked(gem_obj);
+
+ dcss_dec400d_fast_clear_config(dcss_plane->dcss,
+ mdata->fc_value,
+ mdata->fc_enabled);
+ } while (0);
+ dcss_dec400d_read_config(dcss_plane->dcss, 0, compressed, compressed_format);
+ dcss_dec400d_addr_set(dcss_plane->dcss, p1_ba, caddr);
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ break;
+ case DRM_PLANE_TYPE_OVERLAY:
+ if (!modifiers_present ||
+ (modifiers_present && fb->modifier[0] == DRM_FORMAT_MOD_LINEAR) ||
+ (pix_format != DRM_FORMAT_NV12 &&
+ pix_format != DRM_FORMAT_NV21 &&
+ pix_format != DRM_FORMAT_P010)) {
+ dcss_dtrc_bypass(dcss_plane->dcss, dcss_plane->ch_num);
+ return;
+ }
+
+ dcss_dtrc_set_format_mod(dcss_plane->dcss, dcss_plane->ch_num,
+ fb->modifier[0]);
+ dcss_dtrc_addr_set(dcss_plane->dcss, dcss_plane->ch_num,
+ p1_ba, p2_ba, dcss_plane->dtrc_table_ofs_val);
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+}
+
+static bool dcss_plane_needs_setup(struct drm_plane_state *state,
+ struct drm_plane_state *old_state)
+{
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_framebuffer *old_fb = old_state->fb;
+
+ return state->crtc_x != old_state->crtc_x ||
+ state->crtc_y != old_state->crtc_y ||
+ state->crtc_w != old_state->crtc_w ||
+ state->crtc_h != old_state->crtc_h ||
+ state->src_x != old_state->src_x ||
+ state->src_y != old_state->src_y ||
+ state->src_w != old_state->src_w ||
+ state->src_h != old_state->src_h ||
+ fb->pixel_format != old_fb->pixel_format ||
+ fb->modifier[0] != old_fb->modifier[0] ||
+ state->rotation != old_state->rotation;
+}
+
+static void dcss_plane_adjust(struct drm_rect *dis_rect,
+ struct drm_rect *crtc,
+ struct drm_rect *src)
+{
+ struct drm_rect new_crtc = *dis_rect, new_src;
+ u32 hscale, vscale;
+
+ hscale = ((src->x2 - src->x1) << 16) / (crtc->x2 - crtc->x1);
+ vscale = ((src->y2 - src->y1) << 16) / (crtc->y2 - crtc->y1);
+
+ drm_rect_intersect(&new_crtc, crtc);
+
+ new_src.x1 = ((new_crtc.x1 - crtc->x1) * hscale + (1 << 15)) >> 16;
+ new_src.x2 = ((new_crtc.x2 - crtc->x1) * hscale + (1 << 15)) >> 16;
+ new_src.y1 = ((new_crtc.y1 - crtc->y1) * vscale + (1 << 15)) >> 16;
+ new_src.y2 = ((new_crtc.y2 - crtc->y1) * vscale + (1 << 15)) >> 16;
+
+ *crtc = new_crtc;
+ *src = new_src;
+}
+
+static bool dcss_plane_format_has_alpha_channel(u32 pix_format)
+{
+ return pix_format == DRM_FORMAT_ARGB8888 ||
+ pix_format == DRM_FORMAT_ABGR8888 ||
+ pix_format == DRM_FORMAT_RGBA8888 ||
+ pix_format == DRM_FORMAT_BGRA8888 ||
+ pix_format == DRM_FORMAT_BGRA8888 ||
+ pix_format == DRM_FORMAT_ARGB2101010 ||
+ pix_format == DRM_FORMAT_ABGR2101010 ||
+ pix_format == DRM_FORMAT_RGBA1010102 ||
+ pix_format == DRM_FORMAT_BGRA1010102;
+}
+
+static void dcss_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct drm_plane_state *state = plane->state;
+ struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+ struct drm_framebuffer *fb = state->fb;
+ u32 pixel_format;
+ struct drm_crtc_state *crtc_state;
+ bool modifiers_present;
+ u32 src_w, src_h, adj_w, adj_h;
+ struct drm_rect disp, crtc, src, old_src;
+ u32 scaler_w, scaler_h;
+ struct dcss_hdr10_pipe_cfg ipipe_cfg, opipe_cfg;
+ bool enable = true;
+
+ if (!fb || !state->crtc)
+ return;
+
+ pixel_format = state->fb->pixel_format;
+ crtc_state = state->crtc->state;
+ modifiers_present = !!(fb->flags & DRM_MODE_FB_MODIFIERS);
+
+ if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state) &&
+ !dcss_plane_needs_setup(state, old_state) &&
+ !dcss_dtg_global_alpha_changed(dcss_plane->dcss, dcss_plane->ch_num,
+ pixel_format, dcss_plane->alpha_val,
+ dcss_plane->use_global_val)) {
+ dcss_plane_atomic_set_base(dcss_plane);
+ if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+ dcss_dec400d_shadow_trig(dcss_plane->dcss);
+ return;
+ }
+
+ disp.x1 = 0;
+ disp.y1 = 0;
+ disp.x2 = crtc_state->adjusted_mode.hdisplay;
+ disp.y2 = crtc_state->adjusted_mode.vdisplay;
+
+ crtc.x1 = state->crtc_x;
+ crtc.y1 = state->crtc_y;
+ crtc.x2 = state->crtc_x + state->crtc_w;
+ crtc.y2 = state->crtc_y + state->crtc_h;
+
+ src.x1 = state->src_x >> 16;
+ src.y1 = state->src_y >> 16;
+ src.x2 = (state->src_x >> 16) + (state->src_w >> 16);
+ src.y2 = (state->src_y >> 16) + (state->src_h >> 16);
+
+ old_src = src;
+
+ dcss_plane_adjust(&disp, &crtc, &src);
+
+ /*
+ * The width and height after clipping, if image was partially
+ * outside the display area.
+ */
+ src_w = src.x2 - src.x1;
+ src_h = src.y2 - src.y1;
+
+ if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+ dcss_dtrc_set_res(dcss_plane->dcss, dcss_plane->ch_num,
+ &src, &old_src, pixel_format);
+
+ /* DTRC has probably aligned the sizes. */
+ adj_w = src.x2 - src.x1;
+ adj_h = src.y2 - src.y1;
+
+ if (plane->type == DRM_PLANE_TYPE_OVERLAY &&
+ modifiers_present && fb->modifier[0] == DRM_FORMAT_MOD_LINEAR)
+ modifiers_present = false;
+
+ dcss_dpr_format_set(dcss_plane->dcss, dcss_plane->ch_num, pixel_format,
+ modifiers_present);
+ if (!modifiers_present)
+ dcss_dpr_tile_derive(dcss_plane->dcss,
+ dcss_plane->ch_num,
+ DRM_FORMAT_MOD_LINEAR);
+ else
+ dcss_dpr_tile_derive(dcss_plane->dcss,
+ dcss_plane->ch_num,
+ fb->modifier[0]);
+
+ dcss_dpr_set_res(dcss_plane->dcss, dcss_plane->ch_num,
+ src_w, src_h, adj_w, adj_h);
+ dcss_dpr_set_rotation(dcss_plane->dcss, dcss_plane->ch_num,
+ state->rotation);
+ dcss_plane_atomic_set_base(dcss_plane);
+
+ if (fb->modifier[0] == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED) {
+ scaler_w = src.x1 ? adj_w : src_w;
+ scaler_h = src.y1 ? adj_h : src_h;
+ } else {
+ scaler_w = src_w;
+ scaler_h = src_h;
+ }
+
+ dcss_scaler_setup(dcss_plane->dcss, dcss_plane->ch_num,
+ pixel_format, scaler_w, scaler_h,
+ crtc.x2 - crtc.x1,
+ crtc.y2 - crtc.y1,
+ drm_mode_vrefresh(&crtc_state->mode));
+
+ ipipe_cfg.pixel_format = pixel_format;
+
+ dcss_crtc_get_opipe_cfg(state->crtc, &opipe_cfg);
+
+ ipipe_cfg.nl = opipe_cfg.nl == NL_REC2084 ? NL_REC2084 : NL_REC709;
+ ipipe_cfg.pr = PR_FULL;
+ ipipe_cfg.g = opipe_cfg.g == G_REC2020 ? G_REC2020 : G_REC709;
+
+ dcss_hdr10_setup(dcss_plane->dcss, dcss_plane->ch_num,
+ &ipipe_cfg, &opipe_cfg);
+
+ dcss_dtg_plane_pos_set(dcss_plane->dcss, dcss_plane->ch_num,
+ crtc.x1, crtc.y1,
+ crtc.x2 - crtc.x1,
+ crtc.y2 - crtc.y1);
+ dcss_dtg_plane_alpha_set(dcss_plane->dcss, dcss_plane->ch_num,
+ pixel_format, dcss_plane->alpha_val,
+ dcss_plane->use_global_val);
+
+ switch (plane->type) {
+ case DRM_PLANE_TYPE_PRIMARY:
+ dcss_dec400d_enable(dcss_plane->dcss);
+ break;
+ case DRM_PLANE_TYPE_OVERLAY:
+ dcss_dtrc_enable(dcss_plane->dcss, dcss_plane->ch_num, true);
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+
+ if (!dcss_plane->ch_num &&
+ ((dcss_plane->alpha_val == 0 &&
+ !dcss_plane_format_has_alpha_channel(pixel_format)) ||
+ (dcss_plane->alpha_val == 0 && dcss_plane->use_global_val &&
+ dcss_plane_format_has_alpha_channel(pixel_format))))
+ enable = false;
+
+ dcss_dpr_enable(dcss_plane->dcss, dcss_plane->ch_num, enable);
+ dcss_scaler_enable(dcss_plane->dcss, dcss_plane->ch_num, enable);
+
+ if (!enable)
+ dcss_dtg_plane_pos_set(dcss_plane->dcss, dcss_plane->ch_num,
+ 0, 0, 0, 0);
+
+ dcss_dtg_ch_enable(dcss_plane->dcss, dcss_plane->ch_num, enable);
+}
+
+static void dcss_plane_atomic_disable(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+
+ dcss_dtrc_enable(dcss_plane->dcss, dcss_plane->ch_num, false);
+ dcss_dpr_enable(dcss_plane->dcss, dcss_plane->ch_num, false);
+ dcss_scaler_enable(dcss_plane->dcss, dcss_plane->ch_num, false);
+ dcss_dtg_plane_pos_set(dcss_plane->dcss, dcss_plane->ch_num,
+ 0, 0, 0, 0);
+ dcss_dtg_ch_enable(dcss_plane->dcss, dcss_plane->ch_num, false);
+}
+
+static const struct drm_plane_helper_funcs dcss_plane_helper_funcs = {
+ .atomic_check = dcss_plane_atomic_check,
+ .atomic_update = dcss_plane_atomic_update,
+ .atomic_disable = dcss_plane_atomic_disable,
+};
+
+struct dcss_plane *dcss_plane_init(struct drm_device *drm,
+ struct dcss_soc *dcss,
+ unsigned int possible_crtcs,
+ enum drm_plane_type type,
+ unsigned int zpos)
+{
+ struct dcss_plane *dcss_plane;
+ const u64 *format_modifiers = dcss_video_format_modifiers;
+ int ret;
+
+ if (zpos > 2)
+ return ERR_PTR(-EINVAL);
+
+ dcss_plane = kzalloc(sizeof(*dcss_plane), GFP_KERNEL);
+ if (!dcss_plane) {
+ DRM_ERROR("failed to allocate plane\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ dcss_plane->dcss = dcss;
+
+ if (type == DRM_PLANE_TYPE_PRIMARY)
+ format_modifiers = dcss_graphics_format_modifiers;
+
+ ret = drm_universal_plane_init(drm, &dcss_plane->base, possible_crtcs,
+ &dcss_plane_funcs, dcss_common_formats,
+ ARRAY_SIZE(dcss_common_formats),
+ format_modifiers, type, NULL);
+ if (ret) {
+ DRM_ERROR("failed to initialize plane\n");
+ kfree(dcss_plane);
+ return ERR_PTR(ret);
+ }
+
+ if (type == DRM_PLANE_TYPE_OVERLAY)
+ dcss_plane->base.hdr_supported = true;
+
+ drm_plane_helper_add(&dcss_plane->base, &dcss_plane_helper_funcs);
+
+ ret = drm_plane_create_zpos_immutable_property(&dcss_plane->base, zpos);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (!drm->mode_config.rotation_property) {
+ drm->mode_config.rotation_property =
+ drm_mode_create_rotation_property(drm,
+ DRM_ROTATE_0 |
+ DRM_ROTATE_90 |
+ DRM_ROTATE_180 |
+ DRM_ROTATE_270 |
+ DRM_REFLECT_X |
+ DRM_REFLECT_Y);
+ if (!drm->mode_config.rotation_property)
+ return ERR_PTR(-ENOMEM);
+ }
+
+ drm_object_attach_property(&dcss_plane->base.base,
+ dcss_plane->base.dev->mode_config.rotation_property,
+ DRM_ROTATE_0);
+
+ dcss_plane->ch_num = 2 - zpos;
+ dcss_plane->alpha_val = 255;
+
+ return dcss_plane;
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-plane.h b/drivers/gpu/drm/imx/dcss/dcss-plane.h
new file mode 100644
index 000000000000..c607551f3927
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-plane.h
@@ -0,0 +1,28 @@
+#ifndef __DCSS_PLANE_H__
+#define __DCSS_PLANE_H__
+
+#include <drm/drm_crtc.h>
+
+struct dcss_plane {
+ struct drm_plane base;
+ struct dcss_soc *dcss;
+
+ int alpha_val;
+ struct drm_property *alpha_prop;
+
+ int use_global_val;
+ struct drm_property *use_global_prop;
+
+ uint64_t dtrc_table_ofs_val;
+ struct drm_property *dtrc_table_ofs_prop;
+
+ int ch_num;
+};
+
+struct dcss_plane *dcss_plane_init(struct drm_device *drm,
+ struct dcss_soc *dcss,
+ unsigned int possible_crtcs,
+ enum drm_plane_type type,
+ unsigned int zpos);
+
+#endif /* __DCSS_PLANE_H__ */
diff --git a/drivers/gpu/drm/imx/dpu/Kconfig b/drivers/gpu/drm/imx/dpu/Kconfig
new file mode 100644
index 000000000000..c5bd97f4f95b
--- /dev/null
+++ b/drivers/gpu/drm/imx/dpu/Kconfig
@@ -0,0 +1,6 @@
+config DRM_IMX_DPU
+ tristate
+ depends on DRM_IMX
+ depends on IMX_DPU_CORE
+ default y if DRM_IMX=y
+ default m if DRM_IMX=m
diff --git a/drivers/gpu/drm/imx/dpu/Makefile b/drivers/gpu/drm/imx/dpu/Makefile
new file mode 100644
index 000000000000..c09e487aa5c2
--- /dev/null
+++ b/drivers/gpu/drm/imx/dpu/Makefile
@@ -0,0 +1,7 @@
+ccflags-y += -Idrivers/gpu/drm/imx
+
+imx-dpu-crtc-objs := dpu-crtc.o dpu-plane.o dpu-kms.o
+obj-$(CONFIG_DRM_IMX_DPU) += imx-dpu-crtc.o
+
+imx-dpu-render-objs := dpu-blit.o
+obj-$(CONFIG_DRM_IMX_DPU) += imx-dpu-render.o
diff --git a/drivers/gpu/drm/imx/dpu/dpu-blit.c b/drivers/gpu/drm/imx/dpu/dpu-blit.c
new file mode 100644
index 000000000000..e8511bbe4e4e
--- /dev/null
+++ b/drivers/gpu/drm/imx/dpu/dpu-blit.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/imx_drm.h>
+#include <linux/component.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <video/dpu.h>
+
+#include "imx-drm.h"
+
+struct imx_drm_dpu_bliteng {
+ struct dpu_bliteng *dpu_be;
+ struct list_head list;
+};
+
+static DEFINE_MUTEX(imx_drm_dpu_bliteng_lock);
+static LIST_HEAD(imx_drm_dpu_bliteng_list);
+
+static int imx_dpu_num;
+
+static struct imx_drm_dpu_bliteng *imx_drm_dpu_bliteng_find_by_id(s32 id)
+{
+ struct imx_drm_dpu_bliteng *bliteng;
+
+ mutex_lock(&imx_drm_dpu_bliteng_lock);
+
+ list_for_each_entry(bliteng, &imx_drm_dpu_bliteng_list, list) {
+ if (id == dpu_bliteng_get_id(bliteng->dpu_be)) {
+ mutex_unlock(&imx_drm_dpu_bliteng_lock);
+ return bliteng;
+ }
+ }
+
+ mutex_unlock(&imx_drm_dpu_bliteng_lock);
+
+ return NULL;
+}
+
+static int imx_drm_dpu_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_imx_dpu_set_cmdlist *req;
+ struct imx_drm_dpu_bliteng *bliteng;
+ struct dpu_bliteng *dpu_be;
+ u32 cmd_nr, *cmd, *cmd_list;
+ void *user_data;
+ s32 id = 0;
+ struct drm_imx_dpu_frame_info frame_info;
+ int ret;
+
+ req = data;
+ user_data = (void *)(unsigned long)req->user_data;
+ if (copy_from_user(&id, (void __user *)user_data,
+ sizeof(id))) {
+ return -EFAULT;
+ }
+
+ if (id != 0 && id != 1)
+ return -EINVAL;
+
+ user_data += sizeof(id);
+ if (copy_from_user(&frame_info, (void __user *)user_data,
+ sizeof(frame_info))) {
+ return -EFAULT;
+ }
+
+ bliteng = imx_drm_dpu_bliteng_find_by_id(id);
+ if (!bliteng) {
+ DRM_ERROR("Failed to get dpu_bliteng\n");
+ return -ENODEV;
+ }
+
+ dpu_be = bliteng->dpu_be;
+
+retry:
+ ret = dpu_be_get(dpu_be);
+ if (ret == -EBUSY)
+ goto retry;
+
+ cmd_nr = req->cmd_nr;
+ cmd = (u32 *)(unsigned long)req->cmd;
+ cmd_list = dpu_bliteng_get_cmd_list(dpu_be);
+
+ if (copy_from_user(cmd_list, (void __user *)cmd,
+ sizeof(*cmd) * cmd_nr)) {
+ ret = -EFAULT;
+ goto err;
+ }
+
+ dpu_be_configure_prefetch(dpu_be, frame_info.width, frame_info.height,
+ frame_info.x_offset, frame_info.y_offset,
+ frame_info.stride, frame_info.format,
+ frame_info.modifier, frame_info.baddr,
+ frame_info.uv_addr);
+
+ ret = dpu_be_blit(dpu_be, cmd_list, cmd_nr);
+
+err:
+ dpu_be_put(dpu_be);
+
+ return ret;
+}
+
+static int imx_drm_dpu_wait_ioctl(struct drm_device *drm_dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_imx_dpu_wait *wait;
+ struct imx_drm_dpu_bliteng *bliteng;
+ struct dpu_bliteng *dpu_be;
+ void *user_data;
+ s32 id = 0;
+ int ret;
+
+ wait = data;
+ user_data = (void *)(unsigned long)wait->user_data;
+ if (copy_from_user(&id, (void __user *)user_data,
+ sizeof(id))) {
+ return -EFAULT;
+ }
+
+ if (id != 0 && id != 1)
+ return -EINVAL;
+
+ bliteng = imx_drm_dpu_bliteng_find_by_id(id);
+ if (!bliteng) {
+ DRM_ERROR("Failed to get dpu_bliteng\n");
+ return -ENODEV;
+ }
+
+ dpu_be = bliteng->dpu_be;
+
+retry:
+ ret = dpu_be_get(dpu_be);
+ if (ret == -EBUSY)
+ goto retry;
+
+ dpu_be_wait(dpu_be);
+
+ dpu_be_put(dpu_be);
+
+ return ret;
+}
+
+static int imx_drm_dpu_get_param_ioctl(struct drm_device *drm_dev, void *data,
+ struct drm_file *file)
+{
+ enum drm_imx_dpu_param *param = data;
+ int ret;
+
+ switch (*param) {
+ case (DRM_IMX_MAX_DPUS):
+ ret = imx_dpu_num;
+ break;
+ default:
+ ret = -EINVAL;
+ DRM_ERROR("Unknown param![%d]\n", *param);
+ break;
+ }
+
+ return ret;
+}
+
+static struct drm_ioctl_desc imx_drm_dpu_ioctls[] = {
+ DRM_IOCTL_DEF_DRV(IMX_DPU_SET_CMDLIST, imx_drm_dpu_set_cmdlist_ioctl,
+ DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(IMX_DPU_WAIT, imx_drm_dpu_wait_ioctl,
+ DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(IMX_DPU_GET_PARAM, imx_drm_dpu_get_param_ioctl,
+ DRM_RENDER_ALLOW),
+};
+
+static int dpu_bliteng_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct drm_device *drm = (struct drm_device *)data;
+ struct imx_drm_dpu_bliteng *bliteng;
+ struct dpu_bliteng *dpu_bliteng = NULL;
+ int ret;
+
+ bliteng = devm_kzalloc(dev, sizeof(*bliteng), GFP_KERNEL);
+ if (!bliteng)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&bliteng->list);
+
+ ret = dpu_bliteng_get_empty_instance(&dpu_bliteng, dev);
+ if (ret)
+ return ret;
+
+ dpu_bliteng_set_id(dpu_bliteng, imx_dpu_num);
+ dpu_bliteng_set_dev(dpu_bliteng, dev);
+
+ ret = dpu_bliteng_init(dpu_bliteng);
+ if (ret)
+ return ret;
+
+ mutex_lock(&imx_drm_dpu_bliteng_lock);
+ bliteng->dpu_be = dpu_bliteng;
+ list_add_tail(&bliteng->list, &imx_drm_dpu_bliteng_list);
+ mutex_unlock(&imx_drm_dpu_bliteng_lock);
+
+ dev_set_drvdata(dev, dpu_bliteng);
+
+ imx_dpu_num++;
+
+ if (drm->driver->num_ioctls == 0) {
+ drm->driver->ioctls = imx_drm_dpu_ioctls;
+ drm->driver->num_ioctls = ARRAY_SIZE(imx_drm_dpu_ioctls);
+ }
+
+ return 0;
+}
+
+static void dpu_bliteng_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct drm_device *drm = (struct drm_device *)data;
+ struct imx_drm_dpu_bliteng *bliteng;
+ struct dpu_bliteng *dpu_bliteng = dev_get_drvdata(dev);
+ s32 id = dpu_bliteng_get_id(dpu_bliteng);
+
+ bliteng = imx_drm_dpu_bliteng_find_by_id(id);
+ list_del(&bliteng->list);
+
+ dpu_bliteng_fini(dpu_bliteng);
+ dev_set_drvdata(dev, NULL);
+
+ imx_dpu_num--;
+
+ if (drm->driver->num_ioctls != 0) {
+ drm->driver->ioctls = NULL;
+ drm->driver->num_ioctls = 0;
+ }
+}
+
+static const struct component_ops dpu_bliteng_ops = {
+ .bind = dpu_bliteng_bind,
+ .unbind = dpu_bliteng_unbind,
+};
+
+static int dpu_bliteng_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ if (!dev->platform_data)
+ return -EINVAL;
+
+ return component_add(dev, &dpu_bliteng_ops);
+}
+
+static int dpu_bliteng_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &dpu_bliteng_ops);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dpu_bliteng_suspend(struct device *dev)
+{
+ struct dpu_bliteng *dpu_bliteng = dev_get_drvdata(dev);
+ int ret;
+
+ if (dpu_bliteng == NULL)
+ return 0;
+
+retry:
+ ret = dpu_be_get(dpu_bliteng);
+ if (ret == -EBUSY)
+ goto retry;
+
+ dpu_be_wait(dpu_bliteng);
+
+ dpu_be_put(dpu_bliteng);
+
+ dpu_bliteng_fini(dpu_bliteng);
+
+ return 0;
+}
+
+static int dpu_bliteng_resume(struct device *dev)
+{
+ struct dpu_bliteng *dpu_bliteng = dev_get_drvdata(dev);
+
+ if (dpu_bliteng != NULL)
+ dpu_bliteng_init(dpu_bliteng);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(dpu_bliteng_pm_ops,
+ dpu_bliteng_suspend, dpu_bliteng_resume);
+
+struct platform_driver dpu_bliteng_driver = {
+ .driver = {
+ .name = "imx-drm-dpu-bliteng",
+ .pm = &dpu_bliteng_pm_ops,
+ },
+ .probe = dpu_bliteng_probe,
+ .remove = dpu_bliteng_remove,
+};
+
+module_platform_driver(dpu_bliteng_driver);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("i.MX DRM DPU BLITENG");
diff --git a/drivers/gpu/drm/imx/dpu/dpu-crtc.c b/drivers/gpu/drm/imx/dpu/dpu-crtc.c
new file mode 100644
index 000000000000..8e4f804be861
--- /dev/null
+++ b/drivers/gpu/drm/imx/dpu/dpu-crtc.c
@@ -0,0 +1,812 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <linux/component.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <video/dpu.h>
+#include "dpu-kms.h"
+#include "dpu-plane.h"
+#include "imx-drm.h"
+
+struct dpu_crtc {
+ struct device *dev;
+ struct drm_crtc base;
+ struct imx_drm_crtc *imx_crtc;
+ struct dpu_constframe *cf;
+ struct dpu_disengcfg *dec;
+ struct dpu_extdst *ed;
+ struct dpu_framegen *fg;
+ struct dpu_tcon *tcon;
+ struct dpu_plane **plane;
+ unsigned int hw_plane_num;
+ unsigned int stream_id;
+ int vbl_irq;
+ int safety_shdld_irq;
+ int content_shdld_irq;
+ int dec_shdld_irq;
+
+ struct completion safety_shdld_done;
+ struct completion content_shdld_done;
+ struct completion dec_shdld_done;
+};
+
+struct dpu_crtc_state {
+ struct imx_crtc_state imx_crtc_state;
+ struct dpu_plane_state **dpu_plane_states;
+};
+
+static inline struct dpu_crtc_state *to_dpu_crtc_state(struct imx_crtc_state *s)
+{
+ return container_of(s, struct dpu_crtc_state, imx_crtc_state);
+}
+
+static inline struct dpu_crtc *to_dpu_crtc(struct drm_crtc *crtc)
+{
+ return container_of(crtc, struct dpu_crtc, base);
+}
+
+static inline struct dpu_plane_state **
+alloc_dpu_plane_states(struct dpu_crtc *dpu_crtc)
+{
+ struct dpu_plane_state **states;
+
+ states = kcalloc(dpu_crtc->hw_plane_num, sizeof(*states), GFP_KERNEL);
+ if (!states)
+ return ERR_PTR(-ENOMEM);
+
+ return states;
+}
+
+struct dpu_plane_state **
+crtc_state_get_dpu_plane_states(struct drm_crtc_state *state)
+{
+ struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(state);
+ struct dpu_crtc_state *dcstate = to_dpu_crtc_state(imx_crtc_state);
+
+ return dcstate->dpu_plane_states;
+}
+
+static void dpu_crtc_enable(struct drm_crtc *crtc)
+{
+ struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+ struct dpu_plane *dplane = to_dpu_plane(crtc->primary);
+ struct dpu_plane_res *res = &dplane->grp->res;
+ struct dpu_extdst *plane_ed = res->ed[dplane->stream_id];
+ unsigned long ret;
+
+ drm_crtc_vblank_on(crtc);
+
+ enable_irq(dpu_crtc->safety_shdld_irq);
+ enable_irq(dpu_crtc->content_shdld_irq);
+ enable_irq(dpu_crtc->dec_shdld_irq);
+
+ framegen_enable_clock(dpu_crtc->fg);
+ extdst_pixengcfg_sync_trigger(plane_ed);
+ extdst_pixengcfg_sync_trigger(dpu_crtc->ed);
+ framegen_shdtokgen(dpu_crtc->fg);
+ framegen_enable(dpu_crtc->fg);
+
+ ret = wait_for_completion_timeout(&dpu_crtc->safety_shdld_done, HZ);
+ if (ret == 0)
+ dev_warn(dpu_crtc->dev,
+ "enable - wait for safety shdld done timeout\n");
+ ret = wait_for_completion_timeout(&dpu_crtc->content_shdld_done, HZ);
+ if (ret == 0)
+ dev_warn(dpu_crtc->dev,
+ "enable - wait for content shdld done timeout\n");
+ ret = wait_for_completion_timeout(&dpu_crtc->dec_shdld_done, HZ);
+ if (ret == 0)
+ dev_warn(dpu_crtc->dev,
+ "enable - wait for DEC shdld done timeout\n");
+
+ disable_irq(dpu_crtc->safety_shdld_irq);
+ disable_irq(dpu_crtc->content_shdld_irq);
+ disable_irq(dpu_crtc->dec_shdld_irq);
+
+ if (crtc->state->event) {
+ spin_lock_irq(&crtc->dev->event_lock);
+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
+ spin_unlock_irq(&crtc->dev->event_lock);
+
+ crtc->state->event = NULL;
+ }
+
+ /*
+ * TKT320590:
+ * Turn TCON into operation mode later after the first dumb frame is
+ * generated by DPU. This makes DPR/PRG be able to evade the frame.
+ */
+ framegen_wait_for_frame_counter_moving(dpu_crtc->fg);
+ tcon_set_operation_mode(dpu_crtc->tcon);
+}
+
+static void dpu_crtc_atomic_disable(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+ struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+
+ framegen_disable(dpu_crtc->fg);
+ framegen_wait_done(dpu_crtc->fg, &old_crtc_state->adjusted_mode);
+ framegen_disable_clock(dpu_crtc->fg);
+
+ WARN_ON(!crtc->state->event);
+
+ if (crtc->state->event) {
+ spin_lock_irq(&crtc->dev->event_lock);
+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
+ spin_unlock_irq(&crtc->dev->event_lock);
+
+ crtc->state->event = NULL;
+ }
+
+ drm_crtc_vblank_off(crtc);
+}
+
+static void dpu_drm_crtc_reset(struct drm_crtc *crtc)
+{
+ struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+ struct imx_crtc_state *imx_crtc_state;
+ struct dpu_crtc_state *state;
+
+ if (crtc->state) {
+ __drm_atomic_helper_crtc_destroy_state(crtc->state);
+
+ imx_crtc_state = to_imx_crtc_state(crtc->state);
+ state = to_dpu_crtc_state(imx_crtc_state);
+ kfree(state->dpu_plane_states);
+ kfree(state);
+ crtc->state = NULL;
+ }
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (state) {
+ crtc->state = &state->imx_crtc_state.base;
+ crtc->state->crtc = crtc;
+
+ state->dpu_plane_states = alloc_dpu_plane_states(dpu_crtc);
+ if (IS_ERR(state->dpu_plane_states))
+ kfree(state);
+ }
+}
+
+static struct drm_crtc_state *
+dpu_drm_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+ struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+ struct dpu_crtc_state *state;
+
+ if (WARN_ON(!crtc->state))
+ return NULL;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return NULL;
+
+ state->dpu_plane_states = alloc_dpu_plane_states(dpu_crtc);
+ if (IS_ERR(state->dpu_plane_states)) {
+ kfree(state);
+ return NULL;
+ }
+
+ __drm_atomic_helper_crtc_duplicate_state(crtc,
+ &state->imx_crtc_state.base);
+
+ return &state->imx_crtc_state.base;
+}
+
+static void dpu_drm_crtc_destroy_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(state);
+ struct dpu_crtc_state *dcstate;
+
+ if (state) {
+ __drm_atomic_helper_crtc_destroy_state(state);
+ dcstate = to_dpu_crtc_state(imx_crtc_state);
+ kfree(dcstate->dpu_plane_states);
+ kfree(dcstate);
+ }
+}
+
+static void dpu_drm_crtc_destroy(struct drm_crtc *crtc)
+{
+ imx_drm_remove_crtc(to_dpu_crtc(crtc)->imx_crtc);
+}
+
+static const struct drm_crtc_funcs dpu_crtc_funcs = {
+ .set_config = drm_atomic_helper_set_config,
+ .destroy = dpu_drm_crtc_destroy,
+ .page_flip = drm_atomic_helper_page_flip,
+ .reset = dpu_drm_crtc_reset,
+ .atomic_duplicate_state = dpu_drm_crtc_duplicate_state,
+ .atomic_destroy_state = dpu_drm_crtc_destroy_state,
+};
+
+static irqreturn_t dpu_vbl_irq_handler(int irq, void *dev_id)
+{
+ struct dpu_crtc *dpu_crtc = dev_id;
+
+ drm_crtc_handle_vblank(&dpu_crtc->base);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t dpu_safety_shdld_irq_handler(int irq, void *dev_id)
+{
+ struct dpu_crtc *dpu_crtc = dev_id;
+
+ complete(&dpu_crtc->safety_shdld_done);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t dpu_content_shdld_irq_handler(int irq, void *dev_id)
+{
+ struct dpu_crtc *dpu_crtc = dev_id;
+
+ complete(&dpu_crtc->content_shdld_done);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t dpu_dec_shdld_irq_handler(int irq, void *dev_id)
+{
+ struct dpu_crtc *dpu_crtc = dev_id;
+
+ complete(&dpu_crtc->dec_shdld_done);
+
+ return IRQ_HANDLED;
+}
+
+static int dpu_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *crtc_state)
+{
+ struct drm_plane *plane;
+ struct drm_plane_state *plane_state;
+ struct dpu_plane_state *dpstate;
+ struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
+ struct dpu_crtc_state *dcstate = to_dpu_crtc_state(imx_crtc_state);
+ int i = 0;
+
+ /*
+ * cache the plane states so that the planes can be disabled in
+ * ->atomic_begin.
+ */
+ drm_for_each_plane_mask(plane, crtc->dev, crtc_state->plane_mask) {
+ plane_state =
+ drm_atomic_get_plane_state(crtc_state->state, plane);
+ if (IS_ERR(plane_state))
+ return PTR_ERR(plane_state);
+
+ dpstate = to_dpu_plane_state(plane_state);
+ dcstate->dpu_plane_states[i++] = dpstate;
+ }
+
+ return 0;
+}
+
+static void dpu_crtc_atomic_begin(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+ struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+ struct imx_crtc_state *imx_crtc_state =
+ to_imx_crtc_state(old_crtc_state);
+ struct dpu_crtc_state *old_dcstate = to_dpu_crtc_state(imx_crtc_state);
+ int i;
+
+ /*
+ * Disable all planes' resources in SHADOW only.
+ * Whether any of them would be disabled or kept running depends
+ * on new plane states' commit.
+ */
+ for (i = 0; i < dpu_crtc->hw_plane_num; i++) {
+ struct dpu_plane_state *old_dpstate;
+ struct drm_plane_state *plane_state;
+ struct dpu_plane *dplane;
+ struct drm_plane *plane;
+ struct dpu_plane_res *res;
+ struct dpu_fetchunit *fu;
+ struct dpu_fetchunit *fe = NULL;
+ struct dpu_hscaler *hs = NULL;
+ struct dpu_vscaler *vs = NULL;
+ struct dpu_layerblend *lb;
+ struct dpu_extdst *ed;
+ extdst_src_sel_t ed_src;
+ int lb_id;
+ bool crtc_disabling_on_primary = false;
+
+ old_dpstate = old_dcstate->dpu_plane_states[i];
+ if (!old_dpstate)
+ continue;
+
+ plane_state = &old_dpstate->base;
+ dplane = to_dpu_plane(plane_state->plane);
+ res = &dplane->grp->res;
+
+ fu = dpstate_to_fu(old_dpstate);
+ if (!fu)
+ return;
+
+ lb_id = blend_to_id(old_dpstate->blend);
+ if (lb_id < 0)
+ return;
+
+ lb = res->lb[lb_id];
+
+ layerblend_pixengcfg_clken(lb, CLKEN__DISABLE);
+ if (fetchunit_is_fetchdecode(fu)) {
+ fe = fetchdecode_get_fetcheco(fu);
+ hs = fetchdecode_get_hscaler(fu);
+ vs = fetchdecode_get_vscaler(fu);
+ hscaler_pixengcfg_clken(hs, CLKEN__DISABLE);
+ vscaler_pixengcfg_clken(vs, CLKEN__DISABLE);
+ hscaler_mode(hs, SCALER_NEUTRAL);
+ vscaler_mode(vs, SCALER_NEUTRAL);
+ }
+ if (old_dpstate->is_top) {
+ ed = res->ed[dplane->stream_id];
+ ed_src = dplane->stream_id ?
+ ED_SRC_CONSTFRAME1 : ED_SRC_CONSTFRAME0;
+ extdst_pixengcfg_src_sel(ed, ed_src);
+ }
+
+ plane = old_dpstate->base.plane;
+ if (!crtc->state->enable &&
+ plane->type == DRM_PLANE_TYPE_PRIMARY)
+ crtc_disabling_on_primary = true;
+
+ if (crtc_disabling_on_primary && old_dpstate->use_prefetch) {
+ fu->ops->pin_off(fu);
+ if (fetchunit_is_fetchdecode(fu) &&
+ fe->ops->is_enabled(fe))
+ fe->ops->pin_off(fe);
+ } else {
+ fu->ops->disable_src_buf(fu);
+ fu->ops->unpin_off(fu);
+ if (fetchunit_is_fetchdecode(fu)) {
+ fetchdecode_pixengcfg_dynamic_src_sel(fu,
+ FD_SRC_DISABLE);
+ fe->ops->disable_src_buf(fe);
+ fe->ops->unpin_off(fe);
+ }
+ }
+ }
+}
+
+static void dpu_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+ struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+ struct imx_crtc_state *imx_crtc_state =
+ to_imx_crtc_state(old_crtc_state);
+ struct dpu_crtc_state *old_dcstate = to_dpu_crtc_state(imx_crtc_state);
+ struct dpu_plane *dplane = to_dpu_plane(crtc->primary);
+ struct dpu_plane_res *res = &dplane->grp->res;
+ struct dpu_extdst *ed = res->ed[dplane->stream_id];
+ unsigned long ret;
+ int i;
+ bool need_modeset = drm_atomic_crtc_needs_modeset(crtc->state);
+
+ if (!crtc->state->active && !old_crtc_state->active)
+ return;
+
+ if (!need_modeset) {
+ enable_irq(dpu_crtc->content_shdld_irq);
+
+ extdst_pixengcfg_sync_trigger(ed);
+
+ ret = wait_for_completion_timeout(&dpu_crtc->content_shdld_done,
+ HZ);
+ if (ret == 0)
+ dev_warn(dpu_crtc->dev,
+ "flush - wait for content shdld done timeout\n");
+
+ disable_irq(dpu_crtc->content_shdld_irq);
+
+ WARN_ON(!crtc->state->event);
+
+ if (crtc->state->event) {
+ spin_lock_irq(&crtc->dev->event_lock);
+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
+ spin_unlock_irq(&crtc->dev->event_lock);
+
+ crtc->state->event = NULL;
+ }
+ } else if (!crtc->state->active) {
+ extdst_pixengcfg_sync_trigger(ed);
+ }
+
+ for (i = 0; i < dpu_crtc->hw_plane_num; i++) {
+ struct dpu_plane_state *old_dpstate;
+ struct dpu_fetchunit *fu;
+ struct dpu_fetchunit *fe;
+ struct dpu_hscaler *hs;
+ struct dpu_vscaler *vs;
+
+ old_dpstate = old_dcstate->dpu_plane_states[i];
+ if (!old_dpstate)
+ continue;
+
+ fu = dpstate_to_fu(old_dpstate);
+ if (!fu)
+ return;
+
+ if (!fu->ops->is_enabled(fu) || fu->ops->is_pinned_off(fu))
+ fu->ops->set_stream_id(fu, DPU_PLANE_SRC_DISABLED);
+
+ if (fetchunit_is_fetchdecode(fu)) {
+ fe = fetchdecode_get_fetcheco(fu);
+ if (!fe->ops->is_enabled(fe) ||
+ fe->ops->is_pinned_off(fe))
+ fe->ops->set_stream_id(fe,
+ DPU_PLANE_SRC_DISABLED);
+
+ hs = fetchdecode_get_hscaler(fu);
+ if (!hscaler_is_enabled(hs))
+ hscaler_set_stream_id(hs,
+ DPU_PLANE_SRC_DISABLED);
+
+ vs = fetchdecode_get_vscaler(fu);
+ if (!vscaler_is_enabled(vs))
+ vscaler_set_stream_id(vs,
+ DPU_PLANE_SRC_DISABLED);
+ }
+ }
+}
+
+static void dpu_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+ struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc->state);
+ struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+ struct drm_encoder *encoder;
+ struct dpu_plane *dplane = to_dpu_plane(crtc->primary);
+ struct dpu_plane_res *res = &dplane->grp->res;
+ struct dpu_extdst *plane_ed = res->ed[dplane->stream_id];
+ extdst_src_sel_t ed_src;
+ unsigned long encoder_types = 0;
+ u32 encoder_mask;
+ bool encoder_type_has_tmds = false;
+ bool encoder_type_has_lvds = false;
+
+ dev_dbg(dpu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
+ mode->hdisplay);
+ dev_dbg(dpu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__,
+ mode->vdisplay);
+
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ encoder_mask = 1 << drm_encoder_index(encoder);
+
+ if (!(crtc->state->encoder_mask & encoder_mask))
+ continue;
+
+ encoder_types |= BIT(encoder->encoder_type);
+ }
+
+ if (encoder_types & BIT(DRM_MODE_ENCODER_TMDS)) {
+ encoder_type_has_tmds = true;
+ dev_dbg(dpu_crtc->dev, "%s: encoder type has TMDS\n", __func__);
+ }
+
+ if (encoder_types & BIT(DRM_MODE_ENCODER_LVDS)) {
+ encoder_type_has_lvds = true;
+ dev_dbg(dpu_crtc->dev, "%s: encoder type has LVDS\n", __func__);
+ }
+
+ framegen_cfg_videomode(dpu_crtc->fg, mode,
+ encoder_type_has_tmds, encoder_type_has_lvds);
+ framegen_displaymode(dpu_crtc->fg, FGDM__SEC_ON_TOP);
+
+ framegen_panic_displaymode(dpu_crtc->fg, FGDM__TEST);
+
+ tcon_cfg_videomode(dpu_crtc->tcon, mode);
+ tcon_set_fmt(dpu_crtc->tcon, imx_crtc_state->bus_format);
+
+ disengcfg_polarity_ctrl(dpu_crtc->dec, mode->flags);
+
+ constframe_framedimensions(dpu_crtc->cf,
+ mode->crtc_hdisplay,
+ mode->crtc_vdisplay);
+
+ ed_src = dpu_crtc->stream_id ? ED_SRC_CONSTFRAME5 : ED_SRC_CONSTFRAME4;
+ extdst_pixengcfg_src_sel(dpu_crtc->ed, ed_src);
+
+ ed_src = dpu_crtc->stream_id ? ED_SRC_CONSTFRAME1 : ED_SRC_CONSTFRAME0;
+ extdst_pixengcfg_src_sel(plane_ed, ed_src);
+}
+
+static const struct drm_crtc_helper_funcs dpu_helper_funcs = {
+ .mode_set_nofb = dpu_crtc_mode_set_nofb,
+ .atomic_check = dpu_crtc_atomic_check,
+ .atomic_begin = dpu_crtc_atomic_begin,
+ .atomic_flush = dpu_crtc_atomic_flush,
+ .enable = dpu_crtc_enable,
+ .atomic_disable = dpu_crtc_atomic_disable,
+};
+
+static int dpu_enable_vblank(struct drm_crtc *crtc)
+{
+ struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+
+ enable_irq(dpu_crtc->vbl_irq);
+
+ return 0;
+}
+
+static void dpu_disable_vblank(struct drm_crtc *crtc)
+{
+ struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+
+ disable_irq_nosync(dpu_crtc->vbl_irq);
+}
+
+static const struct imx_drm_crtc_helper_funcs dpu_crtc_helper_funcs = {
+ .enable_vblank = dpu_enable_vblank,
+ .disable_vblank = dpu_disable_vblank,
+ .crtc_funcs = &dpu_crtc_funcs,
+ .crtc_helper_funcs = &dpu_helper_funcs,
+};
+
+static void dpu_crtc_put_resources(struct dpu_crtc *dpu_crtc)
+{
+ if (!IS_ERR_OR_NULL(dpu_crtc->cf))
+ dpu_cf_put(dpu_crtc->cf);
+ if (!IS_ERR_OR_NULL(dpu_crtc->dec))
+ dpu_dec_put(dpu_crtc->dec);
+ if (!IS_ERR_OR_NULL(dpu_crtc->ed))
+ dpu_ed_put(dpu_crtc->ed);
+ if (!IS_ERR_OR_NULL(dpu_crtc->fg))
+ dpu_fg_put(dpu_crtc->fg);
+ if (!IS_ERR_OR_NULL(dpu_crtc->tcon))
+ dpu_tcon_put(dpu_crtc->tcon);
+}
+
+static int dpu_crtc_get_resources(struct dpu_crtc *dpu_crtc,
+ unsigned int stream_id)
+{
+ struct dpu_soc *dpu = dev_get_drvdata(dpu_crtc->dev->parent);
+ int ret;
+
+ dpu_crtc->cf = dpu_cf_get(dpu, stream_id + 4);
+ if (IS_ERR(dpu_crtc->cf)) {
+ ret = PTR_ERR(dpu_crtc->cf);
+ goto err_out;
+ }
+
+ dpu_crtc->dec = dpu_dec_get(dpu, stream_id);
+ if (IS_ERR(dpu_crtc->dec)) {
+ ret = PTR_ERR(dpu_crtc->dec);
+ goto err_out;
+ }
+
+ dpu_crtc->ed = dpu_ed_get(dpu, stream_id + 4);
+ if (IS_ERR(dpu_crtc->ed)) {
+ ret = PTR_ERR(dpu_crtc->ed);
+ goto err_out;
+ }
+
+ dpu_crtc->fg = dpu_fg_get(dpu, stream_id);
+ if (IS_ERR(dpu_crtc->fg)) {
+ ret = PTR_ERR(dpu_crtc->fg);
+ goto err_out;
+ }
+
+ dpu_crtc->tcon = dpu_tcon_get(dpu, stream_id);
+ if (IS_ERR(dpu_crtc->tcon)) {
+ ret = PTR_ERR(dpu_crtc->tcon);
+ goto err_out;
+ }
+
+ return 0;
+err_out:
+ dpu_crtc_put_resources(dpu_crtc);
+
+ return ret;
+}
+
+static int dpu_crtc_init(struct dpu_crtc *dpu_crtc,
+ struct dpu_client_platformdata *pdata, struct drm_device *drm)
+{
+ struct dpu_soc *dpu = dev_get_drvdata(dpu_crtc->dev->parent);
+ struct device *dev = dpu_crtc->dev;
+ struct dpu_plane_grp *plane_grp = pdata->plane_grp;
+ unsigned int stream_id = pdata->stream_id;
+ int i, ret;
+
+ init_completion(&dpu_crtc->safety_shdld_done);
+ init_completion(&dpu_crtc->content_shdld_done);
+ init_completion(&dpu_crtc->dec_shdld_done);
+
+ dpu_crtc->stream_id = stream_id;
+ dpu_crtc->hw_plane_num = plane_grp->hw_plane_num;
+
+ dpu_crtc->plane = devm_kcalloc(dev, dpu_crtc->hw_plane_num,
+ sizeof(*dpu_crtc->plane), GFP_KERNEL);
+ if (!dpu_crtc->plane)
+ return -ENOMEM;
+
+ ret = dpu_crtc_get_resources(dpu_crtc, stream_id);
+ if (ret) {
+ dev_err(dev, "getting resources failed with %d.\n", ret);
+ return ret;
+ }
+
+ plane_grp->res.fg[stream_id] = dpu_crtc->fg;
+ dpu_crtc->plane[0] = dpu_plane_init(drm, 0, stream_id, plane_grp,
+ DRM_PLANE_TYPE_PRIMARY);
+ if (IS_ERR(dpu_crtc->plane[0])) {
+ ret = PTR_ERR(dpu_crtc->plane[0]);
+ dev_err(dev, "initializing plane0 failed with %d.\n", ret);
+ goto err_put_resources;
+ }
+
+ ret = imx_drm_add_crtc(drm, &dpu_crtc->base, &dpu_crtc->imx_crtc,
+ &dpu_crtc->plane[0]->base, &dpu_crtc_helper_funcs,
+ pdata->of_node);
+ if (ret) {
+ dev_err(dev, "adding crtc failed with %d.\n", ret);
+ goto err_put_resources;
+ }
+
+ for (i = 1; i < dpu_crtc->hw_plane_num; i++) {
+ dpu_crtc->plane[i] = dpu_plane_init(drm,
+ drm_crtc_mask(&dpu_crtc->base),
+ stream_id, plane_grp,
+ DRM_PLANE_TYPE_OVERLAY);
+ if (IS_ERR(dpu_crtc->plane[i])) {
+ ret = PTR_ERR(dpu_crtc->plane[i]);
+ dev_err(dev, "initializing plane%d failed with %d.\n",
+ i, ret);
+ goto err_remove_crtc;
+ }
+ }
+
+ dpu_crtc->vbl_irq = dpu_map_inner_irq(dpu, stream_id ?
+ IRQ_DISENGCFG_FRAMECOMPLETE1 :
+ IRQ_DISENGCFG_FRAMECOMPLETE0);
+ ret = devm_request_irq(dev, dpu_crtc->vbl_irq, dpu_vbl_irq_handler, 0,
+ "imx_drm", dpu_crtc);
+ if (ret < 0) {
+ dev_err(dev, "vblank irq request failed with %d.\n", ret);
+ goto err_remove_crtc;
+ }
+ disable_irq(dpu_crtc->vbl_irq);
+
+ dpu_crtc->safety_shdld_irq = dpu_map_inner_irq(dpu, stream_id ?
+ IRQ_EXTDST5_SHDLOAD : IRQ_EXTDST4_SHDLOAD);
+ ret = devm_request_irq(dev, dpu_crtc->safety_shdld_irq,
+ dpu_safety_shdld_irq_handler, 0, "imx_drm",
+ dpu_crtc);
+ if (ret < 0) {
+ dev_err(dev,
+ "safety shadow load irq request failed with %d.\n",
+ ret);
+ goto err_remove_crtc;
+ }
+ disable_irq(dpu_crtc->safety_shdld_irq);
+
+ dpu_crtc->content_shdld_irq = dpu_map_inner_irq(dpu, stream_id ?
+ IRQ_EXTDST1_SHDLOAD : IRQ_EXTDST0_SHDLOAD);
+ ret = devm_request_irq(dev, dpu_crtc->content_shdld_irq,
+ dpu_content_shdld_irq_handler, 0, "imx_drm",
+ dpu_crtc);
+ if (ret < 0) {
+ dev_err(dev,
+ "content shadow load irq request failed with %d.\n",
+ ret);
+ goto err_remove_crtc;
+ }
+ disable_irq(dpu_crtc->content_shdld_irq);
+
+ dpu_crtc->dec_shdld_irq = dpu_map_inner_irq(dpu, stream_id ?
+ IRQ_DISENGCFG_SHDLOAD1 : IRQ_DISENGCFG_SHDLOAD0);
+ ret = devm_request_irq(dev, dpu_crtc->dec_shdld_irq,
+ dpu_dec_shdld_irq_handler, 0, "imx_drm",
+ dpu_crtc);
+ if (ret < 0) {
+ dev_err(dev,
+ "DEC shadow load irq request failed with %d.\n",
+ ret);
+ goto err_remove_crtc;
+ }
+ disable_irq(dpu_crtc->dec_shdld_irq);
+
+ return 0;
+
+err_remove_crtc:
+ imx_drm_remove_crtc(dpu_crtc->imx_crtc);
+err_put_resources:
+ dpu_crtc_put_resources(dpu_crtc);
+
+ return ret;
+}
+
+static int dpu_crtc_bind(struct device *dev, struct device *master, void *data)
+{
+ struct dpu_client_platformdata *pdata = dev->platform_data;
+ struct drm_device *drm = data;
+ struct dpu_crtc *dpu_crtc;
+ int ret;
+
+ dpu_crtc = devm_kzalloc(dev, sizeof(*dpu_crtc), GFP_KERNEL);
+ if (!dpu_crtc)
+ return -ENOMEM;
+
+ dpu_crtc->dev = dev;
+
+ ret = dpu_crtc_init(dpu_crtc, pdata, drm);
+ if (ret)
+ return ret;
+
+ if (!drm->mode_config.funcs)
+ drm->mode_config.funcs = &dpu_drm_mode_config_funcs;
+
+ dev_set_drvdata(dev, dpu_crtc);
+
+ return 0;
+}
+
+static void dpu_crtc_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct dpu_crtc *dpu_crtc = dev_get_drvdata(dev);
+
+ dpu_crtc_put_resources(dpu_crtc);
+}
+
+static const struct component_ops dpu_crtc_ops = {
+ .bind = dpu_crtc_bind,
+ .unbind = dpu_crtc_unbind,
+};
+
+static int dpu_crtc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ if (!dev->platform_data)
+ return -EINVAL;
+
+ return component_add(dev, &dpu_crtc_ops);
+}
+
+static int dpu_crtc_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &dpu_crtc_ops);
+ return 0;
+}
+
+static struct platform_driver dpu_crtc_driver = {
+ .driver = {
+ .name = "imx-dpu-crtc",
+ },
+ .probe = dpu_crtc_probe,
+ .remove = dpu_crtc_remove,
+};
+module_platform_driver(dpu_crtc_driver);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("i.MX DPU CRTC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-dpu-crtc");
diff --git a/drivers/gpu/drm/imx/dpu/dpu-crtc.h b/drivers/gpu/drm/imx/dpu/dpu-crtc.h
new file mode 100644
index 000000000000..f624fb7e5365
--- /dev/null
+++ b/drivers/gpu/drm/imx/dpu/dpu-crtc.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef _DPU_CRTC_H_
+#define _DPU_CRTC_H_
+
+#include "dpu-plane.h"
+
+struct dpu_plane_state **
+crtc_state_get_dpu_plane_states(struct drm_crtc_state *state);
+
+#endif
diff --git a/drivers/gpu/drm/imx/dpu/dpu-kms.c b/drivers/gpu/drm/imx/dpu/dpu-kms.c
new file mode 100644
index 000000000000..dbd86650097c
--- /dev/null
+++ b/drivers/gpu/drm/imx/dpu/dpu-kms.c
@@ -0,0 +1,585 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <linux/dma-buf.h>
+#include <linux/reservation.h>
+#include <linux/sort.h>
+#include <video/dpu.h>
+#include "dpu-crtc.h"
+#include "dpu-plane.h"
+#include "imx-drm.h"
+
+static void dpu_drm_output_poll_changed(struct drm_device *dev)
+{
+ struct imx_drm_device *imxdrm = dev->dev_private;
+
+ drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
+}
+
+static struct drm_plane_state **
+dpu_atomic_alloc_tmp_planes_per_crtc(struct drm_device *dev)
+{
+ int total_planes = dev->mode_config.num_total_plane;
+ struct drm_plane_state **states;
+
+ states = kmalloc_array(total_planes, sizeof(*states), GFP_TEMPORARY);
+ if (!states)
+ return ERR_PTR(-ENOMEM);
+
+ return states;
+}
+
+static int zpos_cmp(const void *a, const void *b)
+{
+ const struct drm_plane_state *sa = *(struct drm_plane_state **)a;
+ const struct drm_plane_state *sb = *(struct drm_plane_state **)b;
+
+ return sa->normalized_zpos - sb->normalized_zpos;
+}
+
+static int dpu_atomic_sort_planes_per_crtc(struct drm_crtc_state *crtc_state,
+ struct drm_plane_state **states)
+{
+ struct drm_atomic_state *state = crtc_state->state;
+ struct drm_device *dev = state->dev;
+ struct drm_plane *plane;
+ int n = 0;
+
+ drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) {
+ struct drm_plane_state *plane_state =
+ drm_atomic_get_plane_state(state, plane);
+ if (IS_ERR(plane_state))
+ return PTR_ERR(plane_state);
+ states[n++] = plane_state;
+ }
+
+ sort(states, n, sizeof(*states), zpos_cmp, NULL);
+
+ return n;
+}
+
+static int
+dpu_atomic_compute_plane_base_per_crtc(struct drm_plane_state **states, int n)
+{
+ struct dpu_plane_state *dpstate;
+ int i, left, right, top, bottom, tmp;
+
+ /* compute the plane base */
+ left = states[0]->crtc_x;
+ top = states[0]->crtc_y;
+ right = states[0]->crtc_x + states[0]->crtc_w;
+ bottom = states[0]->crtc_y + states[0]->crtc_h;
+
+ for (i = 1; i < n; i++) {
+ left = min(states[i]->crtc_x, left);
+ top = min(states[i]->crtc_y, top);
+
+ tmp = states[i]->crtc_x + states[i]->crtc_w;
+ right = max(tmp, right);
+
+ tmp = states[i]->crtc_y + states[i]->crtc_h;
+ bottom = max(tmp, bottom);
+ }
+
+ /* BTW, be smart to compute the layer offset */
+ for (i = 0; i < n; i++) {
+ dpstate = to_dpu_plane_state(states[i]);
+ dpstate->layer_x = states[i]->crtc_x - left;
+ dpstate->layer_y = states[i]->crtc_y - top;
+ }
+
+ /* finally, store the base in plane state */
+ dpstate = to_dpu_plane_state(states[0]);
+ dpstate->base_x = left;
+ dpstate->base_y = top;
+ dpstate->base_w = right - left;
+ dpstate->base_h = bottom - top;
+
+ return 0;
+}
+
+static void
+dpu_atomic_set_top_plane_per_crtc(struct drm_plane_state **states, int n)
+{
+ struct dpu_plane_state *dpstate;
+ int i;
+
+ for (i = 0; i < n; i++) {
+ dpstate = to_dpu_plane_state(states[i]);
+ dpstate->is_top = (i == (n - 1)) ? true : false;
+ }
+}
+
+static int
+dpu_atomic_assign_plane_source_per_crtc(struct drm_plane_state **states, int n)
+{
+ struct dpu_plane_state *dpstate;
+ struct dpu_plane *dplane;
+ struct dpu_plane_grp *grp;
+ struct drm_framebuffer *fb;
+ struct dpu_fetchunit *fu;
+ struct dpu_fetchunit *fe;
+ struct dpu_hscaler *hs;
+ struct dpu_vscaler *vs;
+ unsigned int sid, src_sid;
+ unsigned int num_planes;
+ int i, j, k, l, m;
+ int total_asrc_num;
+ u32 src_a_mask, cap_mask, fe_mask, hs_mask, vs_mask;
+ bool need_fetcheco, need_hscaler, need_vscaler;
+ bool fmt_is_yuv;
+
+ /* for active planes only */
+ for (i = 0; i < n; i++) {
+ dpstate = to_dpu_plane_state(states[i]);
+ dplane = to_dpu_plane(states[i]->plane);
+ fb = states[i]->fb;
+ num_planes = drm_format_num_planes(fb->pixel_format);
+ fmt_is_yuv = drm_format_is_yuv(fb->pixel_format);
+ grp = dplane->grp;
+ sid = dplane->stream_id;
+
+ need_fetcheco = (num_planes > 1);
+ need_hscaler = (states[i]->src_w >> 16 != states[i]->crtc_w);
+ need_vscaler = (states[i]->src_h >> 16 != states[i]->crtc_h);
+
+ total_asrc_num = 0;
+ src_a_mask = grp->src_a_mask;
+ fe_mask = 0;
+ hs_mask = 0;
+ vs_mask = 0;
+
+ for (l = 0; l < (sizeof(grp->src_a_mask) * 8); l++) {
+ if (grp->src_a_mask & BIT(l))
+ total_asrc_num++;
+ }
+
+ /* assign source */
+ mutex_lock(&grp->mutex);
+ for (k = 0; k < total_asrc_num; k++) {
+ m = ffs(src_a_mask) - 1;
+
+ fu = source_to_fu(&grp->res, sources[m]);
+ if (!fu)
+ return -EINVAL;
+
+ /* avoid on-the-fly/hot migration */
+ src_sid = fu->ops->get_stream_id(fu);
+ if (src_sid && src_sid != BIT(sid))
+ goto next;
+
+ if (fetchunit_is_fetchdecode(fu)) {
+ cap_mask = fetchdecode_get_vproc_mask(fu);
+
+ if (need_fetcheco) {
+ fe = fetchdecode_get_fetcheco(fu);
+
+ /* avoid on-the-fly/hot migration */
+ src_sid = fu->ops->get_stream_id(fe);
+ if (src_sid && src_sid != BIT(sid))
+ goto next;
+
+ /* fetch unit has the fetcheco cap? */
+ if (!dpu_vproc_has_fetcheco_cap(cap_mask))
+ goto next;
+
+ fe_mask =
+ dpu_vproc_get_fetcheco_cap(cap_mask);
+
+ /* fetcheco available? */
+ if (grp->src_use_vproc_mask & fe_mask)
+ goto next;
+ }
+
+ if (need_hscaler) {
+ hs = fetchdecode_get_hscaler(fu);
+
+ /* avoid on-the-fly/hot migration */
+ src_sid = hscaler_get_stream_id(hs);
+ if (src_sid && src_sid != BIT(sid))
+ goto next;
+
+ /* fetch unit has the hscale cap */
+ if (!dpu_vproc_has_hscale_cap(cap_mask))
+ goto next;
+
+ hs_mask =
+ dpu_vproc_get_hscale_cap(cap_mask);
+
+ /* hscaler available? */
+ if (grp->src_use_vproc_mask & hs_mask)
+ goto next;
+ }
+
+ if (need_vscaler) {
+ vs = fetchdecode_get_vscaler(fu);
+
+ /* avoid on-the-fly/hot migration */
+ src_sid = vscaler_get_stream_id(vs);
+ if (src_sid && src_sid != BIT(sid))
+ goto next;
+
+ /* fetch unit has the vscale cap? */
+ if (!dpu_vproc_has_vscale_cap(cap_mask))
+ goto next;
+
+ vs_mask =
+ dpu_vproc_get_vscale_cap(cap_mask);
+
+ /* vscaler available? */
+ if (grp->src_use_vproc_mask & vs_mask)
+ goto next;
+ }
+ } else {
+ if (fmt_is_yuv || need_fetcheco ||
+ need_hscaler || need_vscaler)
+ goto next;
+ }
+
+ grp->src_a_mask &= ~BIT(m);
+ grp->src_use_vproc_mask |= fe_mask | hs_mask | vs_mask;
+ break;
+next:
+ src_a_mask &= ~BIT(m);
+ fe_mask = 0;
+ hs_mask = 0;
+ vs_mask = 0;
+ }
+ mutex_unlock(&grp->mutex);
+
+ if (k == total_asrc_num)
+ return -EINVAL;
+
+ dpstate->source = sources[m];
+
+ /* assign stage and blend */
+ if (sid) {
+ j = grp->hw_plane_num - (n - i);
+ dpstate->stage = i ? stages[j - 1] : cf_stages[sid];
+ dpstate->blend = blends[j];
+ } else {
+ dpstate->stage = i ? stages[i - 1] : cf_stages[sid];
+ dpstate->blend = blends[i];
+ }
+ }
+
+ return 0;
+}
+
+static void
+dpu_atomic_mark_pipe_states_prone_to_put_per_crtc(struct drm_crtc *crtc,
+ u32 crtc_mask,
+ struct drm_atomic_state *state,
+ bool *puts)
+{
+ struct drm_plane *plane;
+ struct drm_plane_state *plane_state;
+ bool found_pstate = false;
+ int i;
+
+ if ((crtc_mask & drm_crtc_mask(crtc)) == 0) {
+ for_each_plane_in_state(state, plane, plane_state, i) {
+ if (plane->possible_crtcs &
+ drm_crtc_mask(crtc)) {
+ found_pstate = true;
+ break;
+ }
+ }
+
+ if (!found_pstate)
+ puts[drm_crtc_index(crtc)] = true;
+ }
+}
+
+static void
+dpu_atomic_put_plane_state(struct drm_atomic_state *state,
+ struct drm_plane *plane)
+{
+ int index = drm_plane_index(plane);
+
+ plane->funcs->atomic_destroy_state(plane, state->planes[index].state);
+ state->planes[index].ptr = NULL;
+ state->planes[index].state = NULL;
+
+ drm_modeset_unlock(&plane->mutex);
+}
+
+static void
+dpu_atomic_put_crtc_state(struct drm_atomic_state *state,
+ struct drm_crtc *crtc)
+{
+ int index = drm_crtc_index(crtc);
+
+ crtc->funcs->atomic_destroy_state(crtc, state->crtcs[index].state);
+ state->crtcs[index].ptr = NULL;
+ state->crtcs[index].state = NULL;
+
+ drm_modeset_unlock(&crtc->mutex);
+}
+
+static void
+dpu_atomic_put_possible_states_per_crtc(struct drm_crtc_state *crtc_state)
+{
+ struct drm_atomic_state *state = crtc_state->state;
+ struct drm_crtc *crtc = crtc_state->crtc;
+ struct drm_crtc_state *old_crtc_state = crtc->state;
+ struct drm_plane *plane;
+ struct drm_plane_state *plane_state;
+ struct dpu_plane *dplane = to_dpu_plane(crtc->primary);
+ struct dpu_plane_state **old_dpstates;
+ struct dpu_plane_state *old_dpstate, *new_dpstate;
+ u32 active_mask = 0;
+ int i;
+
+ old_dpstates = crtc_state_get_dpu_plane_states(old_crtc_state);
+ if (WARN_ON(!old_dpstates))
+ return;
+
+ for (i = 0; i < dplane->grp->hw_plane_num; i++) {
+ old_dpstate = old_dpstates[i];
+ if (!old_dpstate)
+ continue;
+
+ active_mask |= BIT(i);
+
+ drm_atomic_crtc_state_for_each_plane(plane, crtc_state) {
+ if (drm_plane_index(plane) !=
+ drm_plane_index(old_dpstate->base.plane))
+ continue;
+
+ plane_state =
+ drm_atomic_get_existing_plane_state(state,
+ plane);
+ WARN_ON(!plane_state);
+
+ new_dpstate = to_dpu_plane_state(plane_state);
+
+ active_mask &= ~BIT(i);
+
+ /*
+ * Should be enough to check the below real HW plane
+ * resources only.
+ * Vproc resources and things like layer_x/y should
+ * be fine.
+ */
+ if (old_dpstate->stage != new_dpstate->stage ||
+ old_dpstate->source != new_dpstate->source ||
+ old_dpstate->blend != new_dpstate->blend)
+ return;
+ }
+ }
+
+ /* pure software check */
+ if (WARN_ON(active_mask))
+ return;
+
+ drm_atomic_crtc_state_for_each_plane(plane, crtc_state)
+ dpu_atomic_put_plane_state(state, plane);
+
+ dpu_atomic_put_crtc_state(state, crtc);
+}
+
+static int dpu_drm_atomic_check(struct drm_device *dev,
+ struct drm_atomic_state *state)
+{
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+ struct drm_plane *plane;
+ struct dpu_plane *dpu_plane;
+ const struct drm_plane_state *plane_state;
+ struct dpu_plane_grp *grp[MAX_DPU_PLANE_GRP];
+ int ret, i, grp_id;
+ int active_plane[MAX_DPU_PLANE_GRP];
+ int active_plane_fetcheco[MAX_DPU_PLANE_GRP];
+ int active_plane_hscale[MAX_DPU_PLANE_GRP];
+ int active_plane_vscale[MAX_DPU_PLANE_GRP];
+ bool pipe_states_prone_to_put[MAX_CRTC];
+ u32 crtc_mask_in_state = 0;
+
+ ret = drm_atomic_helper_check_modeset(dev, state);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < MAX_CRTC; i++)
+ pipe_states_prone_to_put[i] = false;
+
+ for (i = 0; i < MAX_DPU_PLANE_GRP; i++) {
+ active_plane[i] = 0;
+ active_plane_fetcheco[i] = 0;
+ active_plane_hscale[i] = 0;
+ active_plane_vscale[i] = 0;
+ grp[i] = NULL;
+ }
+
+ for_each_crtc_in_state(state, crtc, crtc_state, i)
+ crtc_mask_in_state |= drm_crtc_mask(crtc);
+
+ drm_for_each_crtc(crtc, dev) {
+ dpu_atomic_mark_pipe_states_prone_to_put_per_crtc(crtc,
+ crtc_mask_in_state, state,
+ pipe_states_prone_to_put);
+
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+
+ drm_atomic_crtc_state_for_each_plane(plane, crtc_state)
+ plane_state = drm_atomic_get_plane_state(state, plane);
+
+ drm_atomic_crtc_state_for_each_plane_state(plane, plane_state,
+ crtc_state) {
+ struct drm_framebuffer *fb = plane_state->fb;
+ dpu_plane = to_dpu_plane(plane);
+ grp_id = dpu_plane->grp->id;
+ active_plane[grp_id]++;
+
+ if (drm_format_num_planes(fb->pixel_format) > 1)
+ active_plane_fetcheco[grp_id]++;
+
+ if (plane_state->src_w >> 16 != plane_state->crtc_w)
+ active_plane_hscale[grp_id]++;
+
+ if (plane_state->src_h >> 16 != plane_state->crtc_h)
+ active_plane_vscale[grp_id]++;
+
+ if (grp[grp_id] == NULL)
+ grp[grp_id] = dpu_plane->grp;
+ }
+ }
+
+ /* enough resources? */
+ for (i = 0; i < MAX_DPU_PLANE_GRP; i++) {
+ if (grp[i]) {
+ if (active_plane[i] > grp[i]->hw_plane_num)
+ return -EINVAL;
+
+ if (active_plane_fetcheco[i] >
+ grp[i]->hw_plane_fetcheco_num)
+ return -EINVAL;
+
+ if (active_plane_hscale[i] >
+ grp[i]->hw_plane_hscaler_num)
+ return -EINVAL;
+
+ if (active_plane_vscale[i] >
+ grp[i]->hw_plane_vscaler_num)
+ return -EINVAL;
+ }
+ }
+
+ /* clear resource mask */
+ for (i = 0; i < MAX_DPU_PLANE_GRP; i++) {
+ if (grp[i]) {
+ mutex_lock(&grp[i]->mutex);
+ grp[i]->src_a_mask = ~grp[i]->src_na_mask;
+ grp[i]->src_use_vproc_mask = 0;
+ mutex_unlock(&grp[i]->mutex);
+ }
+ }
+
+ ret = drm_atomic_normalize_zpos(dev, state);
+ if (ret)
+ return ret;
+
+ for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ struct drm_plane_state **states;
+ int n;
+
+ states = dpu_atomic_alloc_tmp_planes_per_crtc(dev);
+ if (IS_ERR(states))
+ return PTR_ERR(states);
+
+ n = dpu_atomic_sort_planes_per_crtc(crtc_state, states);
+ if (n < 0) {
+ kfree(states);
+ return n;
+ }
+
+ /* no active planes? */
+ if (n == 0) {
+ kfree(states);
+ continue;
+ }
+
+ /* 'zpos = 0' means primary plane */
+ if (states[0]->plane->type != DRM_PLANE_TYPE_PRIMARY) {
+ kfree(states);
+ return -EINVAL;
+ }
+
+ ret = dpu_atomic_compute_plane_base_per_crtc(states, n);
+ if (ret) {
+ kfree(states);
+ return ret;
+ }
+
+ dpu_atomic_set_top_plane_per_crtc(states, n);
+
+ ret = dpu_atomic_assign_plane_source_per_crtc(states, n);
+ if (ret) {
+ kfree(states);
+ return ret;
+ }
+
+ kfree(states);
+
+ if (pipe_states_prone_to_put[drm_crtc_index(crtc)])
+ dpu_atomic_put_possible_states_per_crtc(crtc_state);
+ }
+
+ ret = drm_atomic_helper_check_planes(dev, state);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+static int dpu_drm_atomic_commit(struct drm_device *dev,
+ struct drm_atomic_state *state,
+ bool nonblock)
+{
+ struct drm_plane_state *plane_state;
+ struct drm_plane *plane;
+ struct dma_buf *dma_buf;
+ int i;
+
+ /*
+ * If the plane fb has an dma-buf attached, fish out the exclusive
+ * fence for the atomic helper to wait on.
+ */
+ for_each_plane_in_state(state, plane, plane_state, i) {
+ if ((plane->state->fb != plane_state->fb) && plane_state->fb) {
+ dma_buf = drm_fb_cma_get_gem_obj(plane_state->fb,
+ 0)->base.dma_buf;
+ if (!dma_buf)
+ continue;
+ plane_state->fence =
+ reservation_object_get_excl_rcu(dma_buf->resv);
+ }
+ }
+
+ return drm_atomic_helper_commit(dev, state, nonblock);
+}
+
+const struct drm_mode_config_funcs dpu_drm_mode_config_funcs = {
+ .fb_create = drm_fb_cma_create,
+ .output_poll_changed = dpu_drm_output_poll_changed,
+ .atomic_check = dpu_drm_atomic_check,
+ .atomic_commit = dpu_drm_atomic_commit,
+};
diff --git a/drivers/gpu/drm/imx/dpu/dpu-kms.h b/drivers/gpu/drm/imx/dpu/dpu-kms.h
new file mode 100644
index 000000000000..8c42abbf203b
--- /dev/null
+++ b/drivers/gpu/drm/imx/dpu/dpu-kms.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef _DPU_KMS_H_
+#define _DPU_KMS_H_
+
+extern const struct drm_mode_config_funcs dpu_drm_mode_config_funcs;
+
+#endif
diff --git a/drivers/gpu/drm/imx/dpu/dpu-plane.c b/drivers/gpu/drm/imx/dpu/dpu-plane.c
new file mode 100644
index 000000000000..33b053641912
--- /dev/null
+++ b/drivers/gpu/drm/imx/dpu/dpu-plane.c
@@ -0,0 +1,787 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <video/dpu.h>
+#include <video/imx8-prefetch.h>
+#include "dpu-plane.h"
+#include "imx-drm.h"
+
+/*
+ * RGB and packed/2planar YUV formats
+ * are widely supported by many fetch units.
+ */
+static const uint32_t dpu_primary_formats[] = {
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_RGBA8888,
+ DRM_FORMAT_RGBX8888,
+ DRM_FORMAT_BGRA8888,
+ DRM_FORMAT_BGRX8888,
+ DRM_FORMAT_RGB565,
+
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_UYVY,
+ DRM_FORMAT_NV12,
+ DRM_FORMAT_NV21,
+};
+
+static const uint32_t dpu_overlay_formats[] = {
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_RGBX8888,
+ DRM_FORMAT_BGRX8888,
+ DRM_FORMAT_RGB565,
+
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_UYVY,
+ DRM_FORMAT_NV12,
+ DRM_FORMAT_NV21,
+};
+
+static const uint64_t dpu_format_modifiers[] = {
+ DRM_FORMAT_MOD_VIVANTE_TILED,
+ DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
+ DRM_FORMAT_MOD_AMPHION_TILED,
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID,
+};
+
+static void dpu_plane_destroy(struct drm_plane *plane)
+{
+ struct dpu_plane *dpu_plane = to_dpu_plane(plane);
+
+ drm_plane_cleanup(plane);
+ kfree(dpu_plane);
+}
+
+static void dpu_plane_reset(struct drm_plane *plane)
+{
+ struct dpu_plane_state *state;
+
+ if (plane->state) {
+ __drm_atomic_helper_plane_destroy_state(plane->state);
+ kfree(to_dpu_plane_state(plane->state));
+ plane->state = NULL;
+ }
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return;
+
+ state->base.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
+
+ plane->state = &state->base;
+ plane->state->plane = plane;
+ plane->state->rotation = DRM_ROTATE_0;
+}
+
+static struct drm_plane_state *
+dpu_drm_atomic_plane_duplicate_state(struct drm_plane *plane)
+{
+ struct dpu_plane_state *state, *copy;
+
+ if (WARN_ON(!plane->state))
+ return NULL;
+
+ copy = kmalloc(sizeof(*state), GFP_KERNEL);
+ if (!copy)
+ return NULL;
+
+ __drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
+ state = to_dpu_plane_state(plane->state);
+ copy->stage = state->stage;
+ copy->source = state->source;
+ copy->blend = state->blend;
+ copy->layer_x = state->layer_x;
+ copy->layer_y = state->layer_y;
+ copy->base_x = state->base_x;
+ copy->base_y = state->base_y;
+ copy->base_w = state->base_w;
+ copy->base_h = state->base_h;
+ copy->is_top = state->is_top;
+ copy->use_prefetch = state->use_prefetch;
+
+ return &copy->base;
+}
+
+static void dpu_drm_atomic_plane_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ __drm_atomic_helper_plane_destroy_state(state);
+ kfree(to_dpu_plane_state(state));
+}
+
+static bool dpu_drm_plane_format_mod_supported(struct drm_plane *plane,
+ uint32_t format,
+ uint64_t modifier)
+{
+ if (WARN_ON(modifier == DRM_FORMAT_MOD_INVALID))
+ return false;
+
+ switch (format) {
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_UYVY:
+ return modifier == DRM_FORMAT_MOD_LINEAR;
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_RGBX8888:
+ case DRM_FORMAT_BGRA8888:
+ case DRM_FORMAT_BGRX8888:
+ case DRM_FORMAT_RGB565:
+ return modifier == DRM_FORMAT_MOD_LINEAR ||
+ modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
+ modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED;
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ return modifier == DRM_FORMAT_MOD_LINEAR ||
+ modifier == DRM_FORMAT_MOD_AMPHION_TILED;
+ default:
+ return false;
+ }
+}
+
+static const struct drm_plane_funcs dpu_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = dpu_plane_destroy,
+ .reset = dpu_plane_reset,
+ .set_property = drm_atomic_helper_plane_set_property,
+ .atomic_duplicate_state = dpu_drm_atomic_plane_duplicate_state,
+ .atomic_destroy_state = dpu_drm_atomic_plane_destroy_state,
+ .format_mod_supported = dpu_drm_plane_format_mod_supported,
+};
+
+static inline dma_addr_t
+drm_plane_state_to_baseaddr(struct drm_plane_state *state)
+{
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *cma_obj;
+ unsigned int x = state->src_x >> 16;
+ unsigned int y = state->src_y >> 16;
+
+ cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+ BUG_ON(!cma_obj);
+
+ if (fb->modifier[0])
+ return cma_obj->paddr + fb->offsets[0];
+
+ if (fb->flags & DRM_MODE_FB_INTERLACED)
+ y /= 2;
+
+ return cma_obj->paddr + fb->offsets[0] + fb->pitches[0] * y +
+ drm_format_plane_cpp(fb->pixel_format, 0) * x;
+}
+
+static inline dma_addr_t
+drm_plane_state_to_uvbaseaddr(struct drm_plane_state *state)
+{
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *cma_obj;
+ int x = state->src_x >> 16;
+ int y = state->src_y >> 16;
+
+ cma_obj = drm_fb_cma_get_gem_obj(fb, 1);
+ BUG_ON(!cma_obj);
+
+ if (fb->modifier[1])
+ return cma_obj->paddr + fb->offsets[1];
+
+ x /= drm_format_horz_chroma_subsampling(fb->pixel_format);
+ y /= drm_format_vert_chroma_subsampling(fb->pixel_format);
+
+ if (fb->flags & DRM_MODE_FB_INTERLACED)
+ y /= 2;
+
+ return cma_obj->paddr + fb->offsets[1] + fb->pitches[1] * y +
+ drm_format_plane_cpp(fb->pixel_format, 1) * x;
+}
+
+static int dpu_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct dpu_plane *dplane = to_dpu_plane(plane);
+ struct dpu_plane_state *dpstate = to_dpu_plane_state(state);
+ struct dpu_plane_state *old_dpstate = to_dpu_plane_state(plane->state);
+ struct drm_crtc_state *crtc_state;
+ struct drm_framebuffer *fb = state->fb;
+ struct dpu_fetchunit *fu;
+ struct dprc *dprc;
+ dma_addr_t baseaddr, uv_baseaddr = 0;
+ u32 src_w = state->src_w >> 16, src_h = state->src_h >> 16,
+ src_x = state->src_x >> 16, src_y = state->src_y >> 16;
+ unsigned int depth;
+ int bpp;
+ bool fb_is_interlaced;
+
+ /* pure software check */
+ if (plane->type != DRM_PLANE_TYPE_PRIMARY)
+ if (WARN_ON(dpstate->base_x || dpstate->base_y ||
+ dpstate->base_w || dpstate->base_h))
+ return -EINVAL;
+
+ /* ok to disable */
+ if (!fb) {
+ dpstate->stage = LB_PRIM_SEL__DISABLE;
+ dpstate->source = LB_SEC_SEL__DISABLE;
+ dpstate->blend = ID_NONE;
+ dpstate->layer_x = 0;
+ dpstate->layer_y = 0;
+ dpstate->base_x = 0;
+ dpstate->base_y = 0;
+ dpstate->base_w = 0;
+ dpstate->base_h = 0;
+ dpstate->is_top = false;
+ dpstate->use_prefetch = false;
+ return 0;
+ }
+
+ if (!state->crtc)
+ return -EINVAL;
+
+ fu = dpstate_to_fu(dpstate);
+ if (!fu)
+ return -EINVAL;
+
+ dprc = fu->dprc;
+
+ fb_is_interlaced = !!(fb->flags & DRM_MODE_FB_INTERLACED);
+
+ if (fb->modifier[0] &&
+ fb->modifier[0] != DRM_FORMAT_MOD_AMPHION_TILED &&
+ fb->modifier[0] != DRM_FORMAT_MOD_VIVANTE_TILED &&
+ fb->modifier[0] != DRM_FORMAT_MOD_VIVANTE_SUPER_TILED)
+ return -EINVAL;
+
+ if (fb->modifier[1] &&
+ fb->modifier[1] != DRM_FORMAT_MOD_AMPHION_TILED)
+ return -EINVAL;
+
+ if (fb->modifier[0] == DRM_FORMAT_MOD_AMPHION_TILED &&
+ fb->modifier[0] != fb->modifier[1])
+ return -EINVAL;
+
+ if (fb->modifier[2] || fb->modifier[3])
+ return -EINVAL;
+
+ if (dplane->grp->has_vproc) {
+ /* no down scaling */
+ if (src_w > state->crtc_w || src_h > state->crtc_h)
+ return -EINVAL;
+ } else {
+ /* no scaling */
+ if (src_w != state->crtc_w || src_h != state->crtc_h)
+ return -EINVAL;
+ }
+
+ /* no off screen */
+ if (state->crtc_x < 0 || state->crtc_y < 0)
+ return -EINVAL;
+
+ crtc_state =
+ drm_atomic_get_existing_crtc_state(state->state, state->crtc);
+ if (WARN_ON(!crtc_state))
+ return -EINVAL;
+
+ /* mode set is needed when base x/y is changed */
+ if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+ if ((dpstate->base_x != old_dpstate->base_x) ||
+ (dpstate->base_y != old_dpstate->base_y))
+ crtc_state->mode_changed = true;
+
+ if (state->crtc_x + state->crtc_w >
+ crtc_state->adjusted_mode.hdisplay)
+ return -EINVAL;
+ if (state->crtc_y + state->crtc_h >
+ crtc_state->adjusted_mode.vdisplay)
+ return -EINVAL;
+
+ /* pixel/line count and position parameters check */
+ if (drm_format_horz_chroma_subsampling(fb->pixel_format) == 2 &&
+ ((src_w % 2) || (src_x % 2)))
+ return -EINVAL;
+ if (drm_format_vert_chroma_subsampling(fb->pixel_format) == 2) {
+ if (src_h % (fb_is_interlaced ? 4 : 2))
+ return -EINVAL;
+ if (src_y % (fb_is_interlaced ? 4 : 2))
+ return -EINVAL;
+ }
+
+ /* for tile formats, framebuffer has to be tile aligned */
+ switch (fb->modifier[0]) {
+ case DRM_FORMAT_MOD_AMPHION_TILED:
+ if (fb->width % 8)
+ return -EINVAL;
+ if (fb->height % 256)
+ return -EINVAL;
+ break;
+ case DRM_FORMAT_MOD_VIVANTE_TILED:
+ if (fb->width % 4)
+ return -EINVAL;
+ if (fb->height % 4)
+ return -EINVAL;
+ break;
+ case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+ if (fb->width % 64)
+ return -EINVAL;
+ if (fb->height % 64)
+ return -EINVAL;
+ break;
+ default:
+ break;
+ }
+
+ if (dprc &&
+ dprc_format_supported(dprc, fb->pixel_format, fb->modifier[0]) &&
+ dprc_stride_supported(dprc, fb->pitches[0], fb->pitches[1],
+ src_w, fb->pixel_format))
+ dpstate->use_prefetch = true;
+ else
+ dpstate->use_prefetch = false;
+
+ if (fb->modifier[0] && !dpstate->use_prefetch)
+ return -EINVAL;
+
+ /*
+ * base address alignment check
+ *
+ * The (uv) base address offset introduced by PRG x/y
+ * offset(for tile formats) would not impact the alignment
+ * check, so we don't take the offset into consideration.
+ */
+ baseaddr = drm_plane_state_to_baseaddr(state);
+ switch (fb->pixel_format) {
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_UYVY:
+ bpp = 16;
+ break;
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ bpp = 8;
+ break;
+ default:
+ drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp);
+ break;
+ }
+ switch (bpp) {
+ case 32:
+ if (baseaddr & 0x3)
+ return -EINVAL;
+ break;
+ case 16:
+ if (fb->modifier[0]) {
+ if (baseaddr & 0x1)
+ return -EINVAL;
+ } else {
+ if (baseaddr & (dpstate->use_prefetch ? 0x7 : 0x1))
+ return -EINVAL;
+ }
+ break;
+ }
+
+ if (fb->pitches[0] > 0x10000)
+ return -EINVAL;
+
+ /* UV base address alignment check, assuming 16bpp */
+ if (drm_format_num_planes(fb->pixel_format) > 1) {
+ uv_baseaddr = drm_plane_state_to_uvbaseaddr(state);
+ if (fb->modifier[1]) {
+ if (uv_baseaddr & 0x1)
+ return -EINVAL;
+ } else {
+ if (uv_baseaddr & (dpstate->use_prefetch ? 0x7 : 0x1))
+ return -EINVAL;
+ }
+
+ if (fb->pitches[1] > 0x10000)
+ return -EINVAL;
+ }
+
+ if (dpstate->use_prefetch &&
+ !dprc_stride_double_check(dprc, src_w, src_x, fb->pixel_format,
+ fb->modifier[0],
+ baseaddr, uv_baseaddr)) {
+ if (fb->modifier[0])
+ return -EINVAL;
+
+ if (bpp == 16 && (baseaddr & 0x1))
+ return -EINVAL;
+
+ if (uv_baseaddr & 0x1)
+ return -EINVAL;
+
+ dpstate->use_prefetch = false;
+ }
+
+ return 0;
+}
+
+static void dpu_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct dpu_plane *dplane = to_dpu_plane(plane);
+ struct drm_plane_state *state = plane->state;
+ struct dpu_plane_state *dpstate = to_dpu_plane_state(state);
+ struct drm_framebuffer *fb = state->fb;
+ struct dpu_plane_res *res = &dplane->grp->res;
+ struct dpu_fetchunit *fu;
+ struct dpu_fetchunit *fe = NULL;
+ struct dprc *dprc;
+ struct dpu_hscaler *hs = NULL;
+ struct dpu_vscaler *vs = NULL;
+ struct dpu_layerblend *lb;
+ struct dpu_constframe *cf;
+ struct dpu_extdst *ed;
+ struct dpu_framegen *fg = res->fg[dplane->stream_id];
+ struct device *dev = plane->dev->dev;
+ dma_addr_t baseaddr, uv_baseaddr = 0;
+ dpu_block_id_t fe_id, vs_id = ID_NONE, hs_id;
+ lb_sec_sel_t lb_src = dpstate->source;
+ unsigned int depth, src_w, src_h, src_x, src_y;
+ unsigned int mt_w = 0, mt_h = 0; /* w/h in a micro-tile */
+ int bpp, lb_id;
+ bool need_fetcheco = false, need_hscaler = false, need_vscaler = false;
+ bool prefetch_start = false, aux_prefetch_start = false;
+ bool need_modeset;
+ bool is_overlay = plane->type == DRM_PLANE_TYPE_OVERLAY;
+ bool fb_is_interlaced;
+
+ /*
+ * Do nothing since the plane is disabled by
+ * crtc_func->atomic_begin/flush.
+ */
+ if (!fb)
+ return;
+
+ need_modeset = drm_atomic_crtc_needs_modeset(state->crtc->state);
+ fb_is_interlaced = !!(fb->flags & DRM_MODE_FB_INTERLACED);
+
+ fu = dpstate_to_fu(dpstate);
+ if (!fu)
+ return;
+
+ dprc = fu->dprc;
+
+ lb_id = blend_to_id(dpstate->blend);
+ if (lb_id < 0)
+ return;
+
+ lb = res->lb[lb_id];
+
+ src_w = state->src_w >> 16;
+ src_h = state->src_h >> 16;
+ src_x = fb->modifier[0] ? (state->src_x >> 16) : 0;
+ src_y = fb->modifier[0] ? (state->src_y >> 16) : 0;
+
+ if (fetchunit_is_fetchdecode(fu)) {
+ if (fetchdecode_need_fetcheco(fu, fb->pixel_format)) {
+ need_fetcheco = true;
+ fe = fetchdecode_get_fetcheco(fu);
+ if (IS_ERR(fe))
+ return;
+ }
+
+ if (src_w != state->crtc_w) {
+ need_hscaler = true;
+ hs = fetchdecode_get_hscaler(fu);
+ if (IS_ERR(hs))
+ return;
+ }
+
+ if ((src_h != state->crtc_h) || fb_is_interlaced) {
+ need_vscaler = true;
+ vs = fetchdecode_get_vscaler(fu);
+ if (IS_ERR(vs))
+ return;
+ }
+ }
+
+ switch (fb->pixel_format) {
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_UYVY:
+ bpp = 16;
+ break;
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ bpp = 8;
+ break;
+ default:
+ drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp);
+ break;
+ }
+
+ switch (fb->modifier[0]) {
+ case DRM_FORMAT_MOD_AMPHION_TILED:
+ mt_w = 8;
+ mt_h = 8;
+ break;
+ case DRM_FORMAT_MOD_VIVANTE_TILED:
+ case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+ mt_w = (bpp == 16) ? 8 : 4;
+ mt_h = 4;
+ break;
+ default:
+ break;
+ }
+
+ baseaddr = drm_plane_state_to_baseaddr(state);
+ if (need_fetcheco)
+ uv_baseaddr = drm_plane_state_to_uvbaseaddr(state);
+
+ if (dpstate->use_prefetch &&
+ (fu->ops->get_stream_id(fu) == DPU_PLANE_SRC_DISABLED ||
+ need_modeset))
+ prefetch_start = true;
+
+ fu->ops->set_burstlength(fu, src_x, mt_w, bpp,
+ baseaddr, dpstate->use_prefetch);
+ fu->ops->set_src_bpp(fu, bpp);
+ fu->ops->set_src_stride(fu, src_w, src_x, mt_w, bpp, fb->pitches[0],
+ baseaddr, dpstate->use_prefetch);
+ fu->ops->set_src_buf_dimensions(fu, src_w, src_h, 0, fb_is_interlaced);
+ fu->ops->set_fmt(fu, fb->pixel_format, fb_is_interlaced);
+ fu->ops->enable_src_buf(fu);
+ fu->ops->set_framedimensions(fu, src_w, src_h, fb_is_interlaced);
+ fu->ops->set_baseaddress(fu, src_w, src_x, src_y, mt_w, mt_h, bpp,
+ baseaddr);
+ fu->ops->set_stream_id(fu, dplane->stream_id ?
+ DPU_PLANE_SRC_TO_DISP_STREAM1 :
+ DPU_PLANE_SRC_TO_DISP_STREAM0);
+ fu->ops->unpin_off(fu);
+
+ dev_dbg(dev, "[PLANE:%d:%s] %s-0x%02x\n",
+ plane->base.id, plane->name, fu->name, fu->id);
+
+ if (need_fetcheco) {
+ fe_id = fetcheco_get_block_id(fe);
+ if (fe_id == ID_NONE)
+ return;
+
+ if (dpstate->use_prefetch &&
+ (fe->ops->get_stream_id(fe) == DPU_PLANE_SRC_DISABLED ||
+ need_modeset))
+ aux_prefetch_start = true;
+
+ fetchdecode_pixengcfg_dynamic_src_sel(fu,
+ (fd_dynamic_src_sel_t)fe_id);
+ fe->ops->set_burstlength(fe, src_x, mt_w, bpp, uv_baseaddr,
+ dpstate->use_prefetch);
+ fe->ops->set_src_bpp(fe, 16);
+ fe->ops->set_src_stride(fe, src_w, src_x, mt_w, bpp,
+ fb->pitches[1],
+ uv_baseaddr, dpstate->use_prefetch);
+ fe->ops->set_fmt(fe, fb->pixel_format, fb_is_interlaced);
+ fe->ops->set_src_buf_dimensions(fe, src_w, src_h,
+ fb->pixel_format,
+ fb_is_interlaced);
+ fe->ops->set_framedimensions(fe, src_w, src_h,
+ fb_is_interlaced);
+ fe->ops->set_baseaddress(fe, src_w, src_x, src_y / 2,
+ mt_w, mt_h, bpp, uv_baseaddr);
+ fe->ops->enable_src_buf(fe);
+ fe->ops->set_stream_id(fe, dplane->stream_id ?
+ DPU_PLANE_SRC_TO_DISP_STREAM1 :
+ DPU_PLANE_SRC_TO_DISP_STREAM0);
+ fe->ops->unpin_off(fe);
+
+ dev_dbg(dev, "[PLANE:%d:%s] %s-0x%02x\n",
+ plane->base.id, plane->name, fe->name, fe_id);
+ } else {
+ if (fetchunit_is_fetchdecode(fu))
+ fetchdecode_pixengcfg_dynamic_src_sel(fu,
+ FD_SRC_DISABLE);
+ }
+
+ /* vscaler comes first */
+ if (need_vscaler) {
+ vs_id = vscaler_get_block_id(vs);
+ if (vs_id == ID_NONE)
+ return;
+
+ vscaler_pixengcfg_dynamic_src_sel(vs,
+ (vs_src_sel_t)(dpstate->source));
+ vscaler_pixengcfg_clken(vs, CLKEN__AUTOMATIC);
+ vscaler_setup1(vs, src_h, state->crtc_h, fb_is_interlaced);
+ vscaler_setup2(vs, fb_is_interlaced);
+ vscaler_setup3(vs, fb_is_interlaced);
+ vscaler_output_size(vs, state->crtc_h);
+ vscaler_field_mode(vs, fb_is_interlaced ?
+ SCALER_ALWAYS0 : SCALER_INPUT);
+ vscaler_filter_mode(vs, SCALER_LINEAR);
+ vscaler_scale_mode(vs, SCALER_UPSCALE);
+ vscaler_mode(vs, SCALER_ACTIVE);
+ vscaler_set_stream_id(vs, dplane->stream_id ?
+ DPU_PLANE_SRC_TO_DISP_STREAM1 :
+ DPU_PLANE_SRC_TO_DISP_STREAM0);
+
+ lb_src = (lb_sec_sel_t)vs_id;
+
+ dev_dbg(dev, "[PLANE:%d:%s] vscaler-0x%02x\n",
+ plane->base.id, plane->name, vs_id);
+ }
+
+ /* and then, hscaler */
+ if (need_hscaler) {
+ hs_id = hscaler_get_block_id(hs);
+ if (hs_id == ID_NONE)
+ return;
+
+ hscaler_pixengcfg_dynamic_src_sel(hs, need_vscaler ?
+ (hs_src_sel_t)(vs_id) :
+ (hs_src_sel_t)(dpstate->source));
+ hscaler_pixengcfg_clken(hs, CLKEN__AUTOMATIC);
+ hscaler_setup1(hs, src_w, state->crtc_w);
+ hscaler_output_size(hs, state->crtc_w);
+ hscaler_filter_mode(hs, SCALER_LINEAR);
+ hscaler_scale_mode(hs, SCALER_UPSCALE);
+ hscaler_mode(hs, SCALER_ACTIVE);
+ hscaler_set_stream_id(hs, dplane->stream_id ?
+ DPU_PLANE_SRC_TO_DISP_STREAM1 :
+ DPU_PLANE_SRC_TO_DISP_STREAM0);
+
+ lb_src = (lb_sec_sel_t)hs_id;
+
+ dev_dbg(dev, "[PLANE:%d:%s] hscaler-0x%02x\n",
+ plane->base.id, plane->name, hs_id);
+ }
+
+ if (dpstate->use_prefetch) {
+ dprc_configure(dprc, dplane->stream_id,
+ src_w, src_h, src_x, src_y,
+ fb->pitches[0], fb->pixel_format,
+ fb->modifier[0], baseaddr, uv_baseaddr,
+ prefetch_start, aux_prefetch_start,
+ fb_is_interlaced);
+ if (prefetch_start || aux_prefetch_start)
+ dprc_enable(dprc);
+
+ dprc_reg_update(dprc);
+
+ if (prefetch_start || aux_prefetch_start) {
+ dprc_first_frame_handle(dprc);
+
+ if (!need_modeset && is_overlay)
+ framegen_wait_for_frame_counter_moving(fg);
+ }
+
+ dev_dbg(dev, "[PLANE:%d:%s] use prefetch\n",
+ plane->base.id, plane->name);
+ } else if (dprc) {
+ dprc_disable(dprc);
+
+ dev_dbg(dev, "[PLANE:%d:%s] bypass prefetch\n",
+ plane->base.id, plane->name);
+ }
+
+ layerblend_pixengcfg_dynamic_prim_sel(lb, dpstate->stage);
+ layerblend_pixengcfg_dynamic_sec_sel(lb, lb_src);
+ layerblend_control(lb, LB_BLEND);
+ layerblend_blendcontrol(lb, need_hscaler || need_vscaler);
+ layerblend_pixengcfg_clken(lb, CLKEN__AUTOMATIC);
+ layerblend_position(lb, dpstate->layer_x, dpstate->layer_y);
+
+ if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
+ cf = res->cf[dplane->stream_id];
+ constframe_framedimensions(cf,
+ dpstate->base_w, dpstate->base_h);
+ constframe_constantcolor(cf, 0, 0, 0, 0);
+
+ framegen_sacfg(fg, dpstate->base_x, dpstate->base_y);
+ }
+
+ if (dpstate->is_top) {
+ ed = res->ed[dplane->stream_id];
+ extdst_pixengcfg_src_sel(ed, (extdst_src_sel_t)dpstate->blend);
+ }
+
+ dev_dbg(dev, "[PLANE:%d:%s] source-0x%02x stage-0x%02x blend-0x%02x\n",
+ plane->base.id, plane->name,
+ dpstate->source, dpstate->stage, dpstate->blend);
+}
+
+static const struct drm_plane_helper_funcs dpu_plane_helper_funcs = {
+ .atomic_check = dpu_plane_atomic_check,
+ .atomic_update = dpu_plane_atomic_update,
+};
+
+struct dpu_plane *dpu_plane_init(struct drm_device *drm,
+ unsigned int possible_crtcs,
+ unsigned int stream_id,
+ struct dpu_plane_grp *grp,
+ enum drm_plane_type type)
+{
+ struct dpu_plane *dpu_plane;
+ struct drm_plane *plane;
+ unsigned int ov_num;
+ int ret;
+
+ dpu_plane = kzalloc(sizeof(*dpu_plane), GFP_KERNEL);
+ if (!dpu_plane)
+ return ERR_PTR(-ENOMEM);
+
+ dpu_plane->stream_id = stream_id;
+ dpu_plane->grp = grp;
+
+ plane = &dpu_plane->base;
+
+ if (type == DRM_PLANE_TYPE_PRIMARY)
+ ret = drm_universal_plane_init(drm, plane, possible_crtcs,
+ &dpu_plane_funcs,
+ dpu_primary_formats,
+ ARRAY_SIZE(dpu_primary_formats),
+ dpu_format_modifiers,
+ type, NULL);
+ else
+ ret = drm_universal_plane_init(drm, plane, possible_crtcs,
+ &dpu_plane_funcs,
+ dpu_overlay_formats,
+ ARRAY_SIZE(dpu_overlay_formats),
+ dpu_format_modifiers,
+ type, NULL);
+ if (ret) {
+ kfree(dpu_plane);
+ return ERR_PTR(ret);
+ }
+
+ drm_plane_helper_add(plane, &dpu_plane_helper_funcs);
+
+ switch (type) {
+ case DRM_PLANE_TYPE_PRIMARY:
+ ret = drm_plane_create_zpos_immutable_property(plane, 0);
+ break;
+ case DRM_PLANE_TYPE_OVERLAY:
+ /* filter out the primary plane */
+ ov_num = grp->hw_plane_num - 1;
+
+ ret = drm_plane_create_zpos_property(plane, 1, 1, ov_num);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ if (ret)
+ return ERR_PTR(ret);
+
+ return dpu_plane;
+}
diff --git a/drivers/gpu/drm/imx/dpu/dpu-plane.h b/drivers/gpu/drm/imx/dpu/dpu-plane.h
new file mode 100644
index 000000000000..eeb52f5262b6
--- /dev/null
+++ b/drivers/gpu/drm/imx/dpu/dpu-plane.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef __DPU_PLANE_H__
+#define __DPU_PLANE_H__
+
+#include <video/dpu.h>
+#include "imx-drm.h"
+
+#define MAX_DPU_PLANE_GRP (MAX_CRTC / 2)
+
+enum dpu_plane_src_type {
+ DPU_PLANE_SRC_FL,
+ DPU_PLANE_SRC_FW,
+ DPU_PLANE_SRC_FD,
+};
+
+struct dpu_plane {
+ struct drm_plane base;
+ struct dpu_plane_grp *grp;
+ struct list_head head;
+ unsigned int stream_id;
+};
+
+struct dpu_plane_state {
+ struct drm_plane_state base;
+ lb_prim_sel_t stage;
+ lb_sec_sel_t source;
+ dpu_block_id_t blend;
+ unsigned int layer_x;
+ unsigned int layer_y;
+ unsigned int base_x;
+ unsigned int base_y;
+ unsigned int base_w;
+ unsigned int base_h;
+ bool is_top;
+ bool use_prefetch;
+};
+
+static const lb_prim_sel_t cf_stages[] = {LB_PRIM_SEL__CONSTFRAME0,
+ LB_PRIM_SEL__CONSTFRAME1};
+static const lb_prim_sel_t stages[] = {LB_PRIM_SEL__LAYERBLEND0,
+ LB_PRIM_SEL__LAYERBLEND1,
+ LB_PRIM_SEL__LAYERBLEND2,
+ LB_PRIM_SEL__LAYERBLEND3,
+ LB_PRIM_SEL__LAYERBLEND4,
+ LB_PRIM_SEL__LAYERBLEND5};
+/* FIXME: Correct the source entries for subsidiary layers. */
+static const lb_sec_sel_t sources[] = {LB_SEC_SEL__FETCHLAYER0,
+ LB_SEC_SEL__FETCHLAYER1,
+ LB_SEC_SEL__FETCHWARP2,
+ LB_SEC_SEL__FETCHDECODE0,
+ LB_SEC_SEL__FETCHDECODE1,
+ LB_SEC_SEL__FETCHDECODE2,
+ LB_SEC_SEL__FETCHDECODE3};
+static const dpu_block_id_t blends[] = {ID_LAYERBLEND0, ID_LAYERBLEND1,
+ ID_LAYERBLEND2, ID_LAYERBLEND3,
+ ID_LAYERBLEND4, ID_LAYERBLEND5};
+
+static inline struct dpu_plane *to_dpu_plane(struct drm_plane *plane)
+{
+ return container_of(plane, struct dpu_plane, base);
+}
+
+static inline struct dpu_plane_state *
+to_dpu_plane_state(struct drm_plane_state *plane_state)
+{
+ return container_of(plane_state, struct dpu_plane_state, base);
+}
+
+static inline int source_to_type(lb_sec_sel_t source)
+{
+ switch (source) {
+ case LB_SEC_SEL__FETCHLAYER0:
+ case LB_SEC_SEL__FETCHLAYER1:
+ return DPU_PLANE_SRC_FL;
+ case LB_SEC_SEL__FETCHWARP2:
+ return DPU_PLANE_SRC_FW;
+ case LB_SEC_SEL__FETCHDECODE0:
+ case LB_SEC_SEL__FETCHDECODE1:
+ case LB_SEC_SEL__FETCHDECODE2:
+ case LB_SEC_SEL__FETCHDECODE3:
+ return DPU_PLANE_SRC_FD;
+ default:
+ break;
+ }
+
+ WARN_ON(1);
+ return -EINVAL;
+}
+
+static inline int source_to_id(lb_sec_sel_t source)
+{
+ int i, offset = 0;
+ int type = source_to_type(source);
+
+ for (i = 0; i < ARRAY_SIZE(sources); i++) {
+ if (source == sources[i]) {
+ if (type == DPU_PLANE_SRC_FD ||
+ type == DPU_PLANE_SRC_FW) {
+ while (offset < ARRAY_SIZE(sources)) {
+ if (source_to_type(sources[offset]) ==
+ type)
+ break;
+ offset++;
+ }
+
+ i -= offset;
+ }
+
+ return i;
+ }
+ }
+
+ WARN_ON(1);
+ return -EINVAL;
+}
+
+static inline struct dpu_fetchunit *
+source_to_fu(struct dpu_plane_res *res, lb_sec_sel_t source)
+{
+ int fu_type = source_to_type(source);
+ int fu_id = source_to_id(source);
+
+ if (fu_type < 0 || fu_id < 0)
+ return NULL;
+
+ switch (fu_type) {
+ case DPU_PLANE_SRC_FD:
+ return res->fd[fu_id];
+ case DPU_PLANE_SRC_FL:
+ return res->fl[fu_id];
+ case DPU_PLANE_SRC_FW:
+ return res->fw[fu_id];
+ }
+
+ return NULL;
+}
+
+static inline struct dpu_fetchunit *
+dpstate_to_fu(struct dpu_plane_state *dpstate)
+{
+ struct drm_plane *plane = dpstate->base.plane;
+ struct dpu_plane *dplane = to_dpu_plane(plane);
+ struct dpu_plane_res *res = &dplane->grp->res;
+
+ return source_to_fu(res, dpstate->source);
+}
+
+static inline int blend_to_id(dpu_block_id_t blend)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(blends); i++) {
+ if (blend == blends[i])
+ return i;
+ }
+
+ WARN_ON(1);
+ return -EINVAL;
+}
+
+static inline bool drm_format_is_yuv(uint32_t format)
+{
+ switch (format) {
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_UYVY:
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+struct dpu_plane *dpu_plane_init(struct drm_device *drm,
+ unsigned int possible_crtcs,
+ unsigned int stream_id,
+ struct dpu_plane_grp *grp,
+ enum drm_plane_type type);
+#endif
diff --git a/drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.c b/drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.c
new file mode 100644
index 000000000000..c22891423222
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.c
@@ -0,0 +1,419 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_AFE_mcu1_dp.c
+ *
+ ******************************************************************************
+ */
+
+#include <linux/delay.h>
+#include "API_AFE_mcu1_dp.h"
+#include "../../../../mxc/hdp/all.h"
+
+static void AFE_WriteReg(state_struct *state, ENUM_AFE_LINK_RATE link_rate,
+ unsigned int addr,
+ unsigned int val1_6,
+ unsigned int val2_1,
+ unsigned int val2_4,
+ unsigned int val2_7,
+ unsigned int val3_2,
+ unsigned int val4_3,
+ unsigned int val5_4)
+{
+ switch (link_rate) {
+ case AFE_LINK_RATE_1_6:
+ Afe_write(state, addr, val1_6);
+ break;
+ case AFE_LINK_RATE_2_1:
+ Afe_write(state, addr, val2_1);
+ break;
+ case AFE_LINK_RATE_2_4:
+ Afe_write(state, addr, val2_4);
+ break;
+ case AFE_LINK_RATE_2_7:
+ Afe_write(state, addr, val2_7);
+ break;
+ case AFE_LINK_RATE_3_2:
+ Afe_write(state, addr, val3_2);
+ break;
+ case AFE_LINK_RATE_4_3:
+ Afe_write(state, addr, val4_3);
+ break;
+ case AFE_LINK_RATE_5_4:
+ Afe_write(state, addr, val5_4);
+ break;
+ case AFE_LINK_RATE_8_1: /* Not used in MCU1 */
+ default:
+ pr_err("Warning. Unsupported Link Rate!\n");
+ break;
+ }
+}
+
+static void phy_cfg_24mhz(state_struct *state, int num_lanes)
+{
+ int k;
+
+ for (k = 0; k < num_lanes; k++) {
+ Afe_write(state, XCVR_DIAG_LANE_FCM_EN_MGN_TMR | (k << 9), 0x0090);
+ Afe_write(state, TX_RCVDET_EN_TMR | (k << 9), 0x0960);
+ Afe_write(state, TX_RCVDET_ST_TMR | (k << 9), 0x0030);
+ }
+}
+
+/* Valid for 24 MHz only */
+static void phy_cfg_dp_pll0(state_struct *state,
+ int num_lanes,
+ ENUM_AFE_LINK_RATE link_rate)
+{
+ int k;
+ volatile u16 rdata;
+
+ rdata = Afe_read(state, PHY_HDP_CLK_CTL);
+ rdata = rdata & 0x00FF;
+
+ switch (link_rate) {
+ case AFE_LINK_RATE_1_6:
+ case AFE_LINK_RATE_2_1:
+ case AFE_LINK_RATE_2_4:
+ case AFE_LINK_RATE_2_7:
+ rdata = rdata | 0x2400;
+ break;
+
+ case AFE_LINK_RATE_3_2:
+ case AFE_LINK_RATE_4_3:
+ case AFE_LINK_RATE_5_4:
+ rdata = rdata | 0x1200;
+ break;
+
+ case AFE_LINK_RATE_8_1: /* nNot used in MCU1 */
+ default:
+ pr_err("Warning. Unsupported Link Rate!\n");
+ break;
+ }
+
+ Afe_write(state, PHY_HDP_CLK_CTL, rdata);
+ rdata = Afe_read(state, CMN_DIAG_HSCLK_SEL);
+ rdata = rdata & 0xFFCC;
+ switch (link_rate) {
+ case AFE_LINK_RATE_1_6:
+ case AFE_LINK_RATE_2_1:
+ case AFE_LINK_RATE_2_4:
+ case AFE_LINK_RATE_2_7:
+ rdata = rdata | 0x0011;
+ break;
+
+ case AFE_LINK_RATE_3_2:
+ case AFE_LINK_RATE_4_3:
+ case AFE_LINK_RATE_5_4:
+ rdata = rdata | 0x0000;
+ break;
+
+ case AFE_LINK_RATE_8_1: /* Not used in MCU1 */
+ default:
+ pr_err("Warning. Unsupported Link Rate!\n");
+ break;
+ }
+ Afe_write(state, CMN_DIAG_HSCLK_SEL, rdata);
+ for (k = 0; k < num_lanes; k = k + 1) {
+ rdata = Afe_read(state, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
+ rdata = rdata & 0xCFFF;
+ switch (link_rate) {
+ case AFE_LINK_RATE_1_6:
+ case AFE_LINK_RATE_2_1:
+ case AFE_LINK_RATE_2_4:
+ case AFE_LINK_RATE_2_7:
+ rdata = rdata | 0x1000;
+ break;
+
+ case AFE_LINK_RATE_3_2:
+ case AFE_LINK_RATE_4_3:
+ case AFE_LINK_RATE_5_4:
+ rdata = rdata | 0x0000;
+ break;
+
+ case AFE_LINK_RATE_8_1: /* Not used in MCU1 */
+ default:
+ pr_err("Warning. Unsupported Link Rate!\n");
+ break;
+ }
+ Afe_write(state, (XCVR_DIAG_HSCLK_SEL | (k << 9)), rdata);
+ }
+ Afe_write(state, CMN_PLL0_VCOCAL_INIT_TMR, 0x00F0);
+ Afe_write(state, CMN_PLL0_VCOCAL_ITER_TMR, 0x0018);
+ AFE_WriteReg(state, link_rate, CMN_PLL0_VCOCAL_START, 0x3061, 0x3092, 0x30B3, 0x30D0, 0x3061, 0x3092, 0x30D0);
+ AFE_WriteReg(state, link_rate, CMN_PLL0_INTDIV, 0x0086, 0x00B3, 0x00CA, 0x00E0, 0x0086, 0x00B3, 0x00E0);
+ AFE_WriteReg(state, link_rate, CMN_PLL0_FRACDIV, 0xF917, 0xF6C7, 0x75A1, 0xF479, 0xF917, 0xF6C7, 0xF479);
+ AFE_WriteReg(state, link_rate, CMN_PLL0_HIGH_THR, 0x0022, 0x002D, 0x0033, 0x0038, 0x0022, 0x002D, 0x0038);
+#ifdef SSC_ON_INIT
+ AFE_WriteReg(state, link_rate, CMN_PLL0_SS_CTRL1, 0x0140, 0x01AB, 0x01E0, 0x0204, 0x0140, 0x01AB, 0x0204);
+ Afe_write(state, CMN_PLL0_SS_CTRL2, 0x7F03);
+#endif
+ Afe_write(state, CMN_PLL0_DSM_DIAG, 0x0020);
+ AFE_WriteReg(state, link_rate, CMN_PLLSM0_USER_DEF_CTRL, 0x0000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x1000);
+ Afe_write(state, CMN_DIAG_PLL0_OVRD, 0x0000);
+ Afe_write(state, CMN_DIAG_PLL0_FBH_OVRD, 0x0000);
+ Afe_write(state, CMN_DIAG_PLL0_FBL_OVRD, 0x0000);
+ AFE_WriteReg(state, link_rate, CMN_DIAG_PLL0_V2I_TUNE, 0x0006, 0x0007, 0x0007, 0x0007, 0x0006, 0x0007, 0x0007);
+ AFE_WriteReg(state, link_rate, CMN_DIAG_PLL0_CP_TUNE, 0x0026, 0x0029, 0x0029, 0x0029, 0x0026, 0x0029, 0x0029);
+ Afe_write(state, CMN_DIAG_PLL0_LF_PROG, 0x0008);
+ Afe_write(state, CMN_DIAG_PLL0_PTATIS_TUNE1, 0x008C);
+ Afe_write(state, CMN_DIAG_PLL0_PTATIS_TUNE2, 0x002E);
+ for (k = 0; k < num_lanes; k = k + 1) {
+ rdata = Afe_read(state, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
+ rdata = rdata & 0x8FFF;
+ switch (link_rate) {
+ case AFE_LINK_RATE_1_6:
+ case AFE_LINK_RATE_2_1:
+ case AFE_LINK_RATE_2_4:
+ case AFE_LINK_RATE_2_7:
+ rdata = rdata | 0x2000;
+ break;
+
+ case AFE_LINK_RATE_3_2:
+ case AFE_LINK_RATE_4_3:
+ case AFE_LINK_RATE_5_4:
+ rdata = rdata | 0x1000;
+ break;
+
+ case AFE_LINK_RATE_8_1: /* Not used in MCU1 */
+ default:
+ pr_err("Warning. Unsupported Link Rate!\n");
+ break;
+ }
+ Afe_write(state, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), rdata);
+ }
+}
+
+static void phy_cfg_dp_ln(state_struct *state, int num_lanes)
+{
+ int k;
+ u16 rdata;
+
+ for (k = 0; k < num_lanes; k = k + 1) {
+ Afe_write(state, (XCVR_PSM_RCTRL | (k << 9)), 0xBEFC);
+ if (state->edp == 0) {
+ Afe_write(state, (TX_PSC_A0 | (k << 9)), 0x6799);
+ Afe_write(state, (TX_PSC_A1 | (k << 9)), 0x6798);
+ Afe_write(state, (TX_PSC_A2 | (k << 9)), 0x0098);
+ Afe_write(state, (TX_PSC_A3 | (k << 9)), 0x0098);
+ } else {
+ Afe_write(state, (TX_PSC_A0 | (k << 9)), 0x279B);
+ Afe_write(state, (TX_PSC_A1 | (k << 9)), 0x2798);
+ Afe_write(state, (TX_PSC_A2 | (k << 9)), 0x0098);
+ Afe_write(state, (TX_PSC_A3 | (k << 9)), 0x0098);
+ rdata = Afe_read(state, TX_DIAG_TX_DRV | (k << 9));
+ rdata &= 0x0600; /* keep bits related to programmable boost */
+ rdata |= 0x00C0;
+ Afe_write(state, (TX_DIAG_TX_DRV | (k << 9)), rdata);
+ }
+ }
+}
+
+static u16 aux_cal_cfg(state_struct *state, u16 prev_calib_code)
+{
+ u16 txpu_calib_code;
+ u16 txpd_calib_code;
+ u16 txpu_adj_calib_code;
+ u16 txpd_adj_calib_code;
+ u16 new_calib_code;
+ u16 rdata;
+
+ txpu_calib_code = Afe_read(state, CMN_TXPUCAL_CTRL);
+ txpd_calib_code = Afe_read(state, CMN_TXPDCAL_CTRL);
+ txpu_adj_calib_code = Afe_read(state, CMN_TXPU_ADJ_CTRL);
+ txpd_adj_calib_code = Afe_read(state, CMN_TXPD_ADJ_CTRL);
+
+ new_calib_code = ((txpu_calib_code + txpd_calib_code) / 2)
+ + txpu_adj_calib_code + txpd_adj_calib_code;
+
+ if (new_calib_code != prev_calib_code) {
+ rdata = Afe_read(state, TX_ANA_CTRL_REG_1);
+ rdata &= 0xDFFF;
+ Afe_write(state, TX_ANA_CTRL_REG_1, rdata);
+ Afe_write(state, TX_DIG_CTRL_REG_2, new_calib_code);
+ udelay(10000);
+ rdata |= 0x2000;
+ Afe_write(state, TX_ANA_CTRL_REG_1, rdata);
+ udelay(150);
+ }
+
+ return new_calib_code;
+}
+
+static void aux_cfg(state_struct *state)
+{
+ volatile u16 rdata;
+
+ Afe_write(state, TX_DIG_CTRL_REG_2, 36);
+
+ Afe_write(state, TX_ANA_CTRL_REG_2, 0x0100);
+ udelay(150);
+ Afe_write(state, TX_ANA_CTRL_REG_2, 0x0300);
+ udelay(150);
+ Afe_write(state, TX_ANA_CTRL_REG_3, 0x0000);
+ udelay(150);
+ Afe_write(state, TX_ANA_CTRL_REG_1, 0x2008);
+ udelay(150);
+ Afe_write(state, TX_ANA_CTRL_REG_1, 0x2018);
+ udelay(150);
+ Afe_write(state, TX_ANA_CTRL_REG_1, 0xA018);
+ udelay(150);
+ Afe_write(state, TX_ANA_CTRL_REG_2, 0x030C);
+ udelay(150);
+ Afe_write(state, TX_ANA_CTRL_REG_5, 0x0000);
+ udelay(150);
+ Afe_write(state, TX_ANA_CTRL_REG_4, 0x1001);
+ udelay(150);
+ Afe_write(state, TX_ANA_CTRL_REG_1, 0xA098);
+ udelay(5000);
+ Afe_write(state, TX_ANA_CTRL_REG_1, 0xA198);
+ udelay(5000);
+ Afe_write(state, TX_ANA_CTRL_REG_2, 0x030D);
+ udelay(5000);
+ Afe_write(state, TX_ANA_CTRL_REG_2, 0x030F);
+ udelay(5000);
+
+ pr_info("TX_ANA_CTRL_REG_1 %x)\n", rdata);
+ rdata = Afe_read(state, TX_ANA_CTRL_REG_2);
+ pr_info("TX_ANA_CTRL_REG_2 %x)\n", rdata);
+ rdata = Afe_read(state, TX_ANA_CTRL_REG_3);
+ pr_info("TX_ANA_CTRL_REG_3 %x)\n", rdata);
+ rdata = Afe_read(state, TX_ANA_CTRL_REG_4);
+ pr_info("TX_ANA_CTRL_REG_4 %x)\n", rdata);
+ rdata = Afe_read(state, TX_ANA_CTRL_REG_5);
+ pr_info("TX_ANA_CTRL_REG_5 %x)\n", rdata);
+}
+
+void AFE_init(state_struct *state, int num_lanes, ENUM_AFE_LINK_RATE link_rate)
+{
+ volatile u16 val;
+
+ if (AFE_check_rate_supported(link_rate) == 0) {
+ pr_info
+ ("AFE_init() *E: Selected link rate not supported: 0x%x\n",
+ link_rate);
+ return;
+ }
+ val = Afe_read(state, PHY_PMA_CMN_CTRL1);
+ val = val & 0xFFF7;
+ val = val | 0x0008;
+ Afe_write(state, PHY_PMA_CMN_CTRL1, val);
+
+ Afe_write(state, CMN_DIAG_PLL0_TEST_MODE, 0x0022);
+ Afe_write(state, CMN_PSM_CLK_CTRL, 0x0016);
+
+ phy_cfg_24mhz(state, num_lanes);
+
+ phy_cfg_dp_pll0(state, num_lanes, link_rate);
+
+ val = Afe_read(state, PHY_PMA_CMN_CTRL1);
+ val = val & 0xFF8F;
+ val = val | 0x0030;
+ Afe_write(state, PHY_PMA_CMN_CTRL1, val);
+
+ if (state->edp != 0)
+ Afe_write(state, CMN_DIAG_CAL_CTRL, 0x0001);
+
+ phy_cfg_dp_ln(state, num_lanes);
+
+ /* Configure PHY in A2 Mode */
+ Afe_write(state, PHY_HDP_MODE_CTRL, 0x0004);
+}
+
+void AFE_power(state_struct *state, int num_lanes,
+ ENUM_AFE_LINK_RATE link_rate)
+{
+ static u16 prev_calib_code;
+
+ volatile u16 val;
+ if (AFE_check_rate_supported(link_rate) == 0) {
+ pr_info
+ ("AFE_power() *E: Selected link rate not supported: 0x%x\n",
+ link_rate);
+ return;
+ }
+
+ Afe_write(state, TX_DIAG_ACYA_0, 1);
+ Afe_write(state, TX_DIAG_ACYA_1, 1);
+ Afe_write(state, TX_DIAG_ACYA_2, 1);
+ Afe_write(state, TX_DIAG_ACYA_3, 1);
+
+ Afe_write(state, TXDA_CYA_AUXDA_CYA, 1);
+
+ /* Wait for A2 ACK (PHY_HDP_MODE_CTL [6] = 1’b1) */
+ do {
+ val = Afe_read(state, PHY_HDP_MODE_CTRL);
+ val = val >> 6;
+ } while ((val & 1) == 0);
+
+ /* to check if PLL has locked (bit 6) */
+ val = Afe_read(state, PHY_PMA_CMN_CTRL2);
+ val = val >> 6;
+
+ if ((val & 1) == 0) {
+ pr_err("ERROR: PLL is not locked\n");
+ } else {
+ pr_info("PHY_PMA_CMN_CTRL2 = %x\n", val);
+ }
+
+ /* to check if cmn_ready is asserted (bit 0) */
+ val = Afe_read(state, PHY_PMA_CMN_CTRL1);
+
+ if ((val & 1) == 0) {
+ pr_err("ERROR: cmn_ready is not asserted\n");
+ } else {
+ pr_info("PHY_PMA_CMN_CTRL1 = %x\n", val);
+ }
+
+ /* Configure PHY in A0 mode (PHY must be in the A0 power state in order to transmit data) */
+ Afe_write(state, PHY_HDP_MODE_CTRL, 0x0101);
+
+ /* Wait for A2 ACK (PHY_HDP_MODE_CTL [4] = 1’b1) */
+ do {
+ val = Afe_read(state, PHY_HDP_MODE_CTRL);
+ val = val >> 4;
+ } while ((val & 1) == 0);
+
+ prev_calib_code = aux_cal_cfg(state, prev_calib_code);
+
+ aux_cfg(state);
+
+}
diff --git a/drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.h b/drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.h
new file mode 100644
index 000000000000..af71347676ae
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.h
@@ -0,0 +1,168 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_AFE_mcu1_dp.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef API_AFE_MCU1_DP_H
+# define API_AFE_MCU1_DP_H
+
+#define PHY_PMA_CMN_CTRL1 0xC800
+#define PHY_PMA_CMN_CTRL2 0xC801
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR 0x40F2
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_0 0x40F2
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_1 0x42F2
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_2 0x44F2
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_3 0x46F2
+#define TX_RCVDET_EN_TMR 0x4122
+#define TX_RCVDET_EN_TMR_0 0x4122
+#define TX_RCVDET_EN_TMR_1 0x4322
+#define TX_RCVDET_EN_TMR_2 0x4522
+#define TX_RCVDET_EN_TMR_3 0x4722
+#define TX_RCVDET_ST_TMR 0x4123
+#define TX_RCVDET_ST_TMR_0 0x4123
+#define TX_RCVDET_ST_TMR_1 0x4323
+#define TX_RCVDET_ST_TMR_2 0x4523
+#define TX_RCVDET_ST_TMR_3 0x4723
+#define PHY_HDP_CLK_CTL 0xC009
+#define CMN_DIAG_HSCLK_SEL 0x01E0
+#define XCVR_DIAG_HSCLK_SEL 0x40E1
+#define XCVR_DIAG_HSCLK_SEL_0 0x40E1
+#define XCVR_DIAG_HSCLK_SEL_1 0x42E1
+#define XCVR_DIAG_HSCLK_SEL_2 0x44E1
+#define XCVR_DIAG_HSCLK_SEL_3 0x46E1
+#define CMN_PLL0_VCOCAL_START 0x0081
+#define CMN_PLLSM0_USER_DEF_CTRL 0x002F
+#define CMN_DIAG_PLL0_V2I_TUNE 0x01C5
+#define CMN_DIAG_PLL0_PTATIS_TUNE1 0x01C8
+#define CMN_DIAG_PLL0_PTATIS_TUNE2 0x01C9
+#define CMN_DIAG_PLL0_CP_TUNE 0x01C6
+#define CMN_DIAG_PER_CAL_ADJ 0x01EC
+#define CMN_DIAG_CAL_CTRL 0x01ED
+#define CMN_DIAG_PLL0_LF_PROG 0x01C7
+#define CMN_PLL0_VCOCAL_INIT_TMR 0x0084
+#define CMN_PLL0_VCOCAL_ITER_TMR 0x0085
+#define CMN_PLL0_INTDIV 0x0094
+#define CMN_PLL0_FRACDIV 0x0095
+#define CMN_PLL0_HIGH_THR 0x0096
+#define CMN_PLL0_SS_CTRL1 0x0098
+#define CMN_PLL0_SS_CTRL2 0x0099
+#define CMN_PLL0_DSM_DIAG 0x0097
+#define CMN_DIAG_PLL0_OVRD 0x01C2
+#define CMN_DIAG_PLL0_FBH_OVRD 0x01C0
+#define CMN_DIAG_PLL0_FBL_OVRD 0x01C1
+#define XCVR_DIAG_PLLDRC_CTRL 0x40E0
+#define XCVR_DIAG_PLLDRC_CTRL_0 0x40E0
+#define XCVR_DIAG_PLLDRC_CTRL_1 0x42E0
+#define XCVR_DIAG_PLLDRC_CTRL_2 0x44E0
+#define XCVR_DIAG_PLLDRC_CTRL_3 0x46E0
+#define CMN_DIAG_PLL0_TEST_MODE 0x01C4
+#define PHY_HDP_MODE_CTRL 0xC008
+#define XCVR_PSM_RCTRL 0x4001
+#define XCVR_PSM_RCTRL_0 0x4001
+#define XCVR_PSM_RCTRL_1 0x4201
+#define XCVR_PSM_RCTRL_2 0x4401
+#define XCVR_PSM_RCTRL_3 0x4601
+#define TX_PSC_A0 0x4100
+#define TX_PSC_A0_0 0x4100
+#define TX_PSC_A0_1 0x4300
+#define TX_PSC_A0_2 0x4500
+#define TX_PSC_A0_3 0x4700
+#define TX_PSC_A1 0x4101
+#define TX_PSC_A1_0 0x4101
+#define TX_PSC_A1_1 0x4301
+#define TX_PSC_A1_2 0x4501
+#define TX_PSC_A1_3 0x4701
+#define TX_PSC_A2 0x4102
+#define TX_PSC_A2_0 0x4102
+#define TX_PSC_A2_1 0x4302
+#define TX_PSC_A2_2 0x4502
+#define TX_PSC_A2_3 0x4702
+#define TX_PSC_A3 0x4103
+#define TX_PSC_A3_0 0x4103
+#define TX_PSC_A3_1 0x4303
+#define TX_PSC_A3_2 0x4503
+#define TX_PSC_A3_3 0x4703
+#define TX_DIAG_TX_DRV 0x41E1
+#define TX_DIAG_TX_DRV_0 0x41E1
+#define TX_DIAG_TX_DRV_1 0x43E1
+#define TX_DIAG_TX_DRV_2 0x45E1
+#define TX_DIAG_TX_DRV_3 0x47E1
+#define PHY_HDP_MODE_CTRL 0xC008
+#define TX_DIAG_ACYA_0 0x41ff
+#define TX_DIAG_ACYA_1 0x43ff
+#define TX_DIAG_ACYA_2 0x45ff
+#define TX_DIAG_ACYA_3 0x47ff
+
+#define TX_TXCC_MGNFS_MULT_000_0 0x4050
+#define TX_TXCC_MGNFS_MULT_000_1 0x4250
+#define TX_TXCC_MGNFS_MULT_000_2 0x4450
+#define TX_TXCC_MGNFS_MULT_000_3 0x4650
+
+#define TX_TXCC_CPOST_MULT_00_0 0x404C
+#define TX_TXCC_CPOST_MULT_00_1 0x424C
+#define TX_TXCC_CPOST_MULT_00_2 0x444C
+#define TX_TXCC_CPOST_MULT_00_3 0x464C
+
+#define TX_ANA_CTRL_REG_1 0x5020
+#define TX_ANA_CTRL_REG_2 0x5021
+#define TX_ANA_CTRL_REG_3 0x5026
+#define TX_ANA_CTRL_REG_4 0x5027
+#define TX_ANA_CTRL_REG_5 0x5029
+
+#define TX_DIG_CTRL_REG_2 0x5024
+#define TX_DIG_CTRL_REG_1 0x5023
+#define TXDA_CYA_AUXDA_CYA 0x5025
+#define CMN_TXPUCAL_CTRL 0x00E0
+#define CMN_TXPDCAL_CTRL 0x00F0
+#define CMN_TXPU_ADJ_CTRL 0x0108
+#define CMN_TXPD_ADJ_CTRL 0x010c
+#define TXDA_COEFF_CALC 0x5022
+#define CMN_PSM_CLK_CTRL 0x0061
+
+#define PHY_HDP_TX_CTL_L0 0xC408
+#define PHY_HDP_TX_CTL_L1 0xC448
+#define PHY_HDP_TX_CTL_L2 0xC488
+#define PHY_HDP_TX_CTL_L3 0xC4C8
+
+#endif /*API_AFE_MCU1_DP_H*/
diff --git a/drivers/gpu/drm/imx/hdp/API_AFE_mcu2_dp.c b/drivers/gpu/drm/imx/hdp/API_AFE_mcu2_dp.c
new file mode 100644
index 000000000000..8ef7b8e7d686
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/API_AFE_mcu2_dp.c
@@ -0,0 +1,610 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * Copyright 2018 NXP
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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. THE SOFTWARE IS PROVIDED "AS IS",
+ * WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ ******************************************************************************
+ *
+ * API_AFE_mcu2_dp.c
+ *
+ ******************************************************************************
+ */
+#include <linux/delay.h>
+#include "API_AFE_mcu2_dp.h"
+#include "../../../../mxc/hdp/all.h"
+
+static void afe_write_reg(state_struct *state,
+ ENUM_AFE_LINK_RATE link_rate,
+ unsigned int addr,
+ unsigned int val1_6,
+ unsigned int val2_1,
+ unsigned int val2_4,
+ unsigned int val2_7,
+ unsigned int val3_2,
+ unsigned int val4_3,
+ unsigned int val5_4)
+{
+ switch (link_rate) {
+ case AFE_LINK_RATE_1_6:
+ Afe_write(state, addr, val1_6); break;
+ case AFE_LINK_RATE_2_1:
+ Afe_write(state, addr, val2_1); break;
+ case AFE_LINK_RATE_2_4:
+ Afe_write(state, addr, val2_4); break;
+ case AFE_LINK_RATE_2_7:
+ Afe_write(state, addr, val2_7); break;
+ case AFE_LINK_RATE_3_2:
+ Afe_write(state, addr, val3_2); break;
+ case AFE_LINK_RATE_4_3:
+ Afe_write(state, addr, val4_3); break;
+ case AFE_LINK_RATE_5_4:
+ Afe_write(state, addr, val5_4); break;
+ default:
+ break;
+ }
+}
+
+static void phy_cfg_24mhz(state_struct *state, int num_lanes)
+{
+ int k;
+
+ for (k = 0; k < num_lanes; k++) {
+ /* Afe_write (XCVR_DIAG_LANE_FCM_EN_TO | (k << 9), 0x01e0); */
+ Afe_write(state, XCVR_DIAG_LANE_FCM_EN_MGN_TMR | (k << 9),
+ 0x0090);
+ Afe_write(state, TX_RCVDET_EN_TMR | (k << 9), 0x0960);
+ Afe_write(state, TX_RCVDET_ST_TMR | (k << 9), 0x0030);
+ }
+}
+
+static void phy_cfg_27mhz(state_struct *state, int num_lanes)
+{
+ int k;
+
+ Afe_write(state, CMN_SSM_BIAS_TMR, 0x0087);
+ Afe_write(state, CMN_PLLSM0_PLLEN_TMR, 0x001B);
+ Afe_write(state, CMN_PLLSM0_PLLPRE_TMR, 0x0036);
+ Afe_write(state, CMN_PLLSM0_PLLVREF_TMR, 0x001B);
+ Afe_write(state, CMN_PLLSM0_PLLLOCK_TMR, 0x006C);
+ Afe_write(state, CMN_ICAL_INIT_TMR, 0x0044);
+ Afe_write(state, CMN_ICAL_ITER_TMR, 0x0006);
+ Afe_write(state, CMN_ICAL_ADJ_INIT_TMR, 0x0022);
+ Afe_write(state, CMN_ICAL_ADJ_ITER_TMR, 0x0006);
+ Afe_write(state, CMN_TXPUCAL_INIT_TMR, 0x0022);
+ Afe_write(state, CMN_TXPUCAL_ITER_TMR, 0x0006);
+ Afe_write(state, CMN_TXPU_ADJ_INIT_TMR, 0x0022);
+ Afe_write(state, CMN_TXPU_ADJ_ITER_TMR, 0x0006);
+ Afe_write(state, CMN_TXPDCAL_INIT_TMR, 0x0022);
+ Afe_write(state, CMN_TXPDCAL_ITER_TMR, 0x0006);
+ Afe_write(state, CMN_TXPD_ADJ_INIT_TMR, 0x0022);
+ Afe_write(state, CMN_TXPD_ADJ_ITER_TMR, 0x0006);
+ Afe_write(state, CMN_RXCAL_INIT_TMR, 0x0022);
+ Afe_write(state, CMN_RXCAL_ITER_TMR, 0x0006);
+ Afe_write(state, CMN_RX_ADJ_INIT_TMR, 0x0022);
+ Afe_write(state, CMN_RX_ADJ_ITER_TMR, 0x0006);
+
+ for (k = 0; k < num_lanes; k++) {
+ Afe_write(state, XCVR_PSM_CAL_TMR | (k << 9), 0x016D);
+ Afe_write(state, XCVR_PSM_A0IN_TMR | (k << 9), 0x016D);
+ Afe_write(state, XCVR_DIAG_LANE_FCM_EN_MGN_TMR | (k << 9),
+ 0x00A2);
+ Afe_write(state, TX_DIAG_BGREF_PREDRV_DELAY | (k << 9),
+ 0x0097);
+ Afe_write(state, TX_RCVDET_EN_TMR | (k << 9), 0x0A8C);
+ Afe_write(state, TX_RCVDET_ST_TMR | (k << 9), 0x0036);
+ }
+}
+
+static void phy_cfg_dp_pll0_24mhz(state_struct *state,
+ int num_lanes,
+ ENUM_AFE_LINK_RATE link_rate)
+{
+ int k;
+ unsigned short rdata;
+
+ rdata = Afe_read(state, PHY_HDP_CLK_CTL);
+ rdata = rdata & 0x00FF;
+ switch (link_rate) {
+ case AFE_LINK_RATE_1_6:
+ case AFE_LINK_RATE_2_1:
+ case AFE_LINK_RATE_2_4:
+ case AFE_LINK_RATE_2_7:
+ rdata = rdata | 0x2400;
+ break;
+ case AFE_LINK_RATE_3_2:
+ case AFE_LINK_RATE_4_3:
+ case AFE_LINK_RATE_5_4:
+ rdata = rdata | 0x1200;
+ break;
+ case AFE_LINK_RATE_8_1: /* Not used in MCU2 */
+ default:
+ pr_info("Warning. Unsupported Link Rate!\n");
+ break;
+ }
+ Afe_write(state, PHY_HDP_CLK_CTL, rdata);
+ rdata = Afe_read(state, CMN_DIAG_HSCLK_SEL);
+ rdata = rdata & 0xFFCC;
+ switch (link_rate) {
+ case AFE_LINK_RATE_1_6:
+ case AFE_LINK_RATE_2_1:
+ case AFE_LINK_RATE_2_4:
+ case AFE_LINK_RATE_2_7:
+ rdata = rdata | 0x0011;
+ break;
+ case AFE_LINK_RATE_3_2:
+ case AFE_LINK_RATE_4_3:
+ case AFE_LINK_RATE_5_4:
+ rdata = rdata | 0x0000;
+ break;
+ default:
+ break;
+ }
+ Afe_write(state, CMN_DIAG_HSCLK_SEL, rdata);
+ for (k = 0; k < num_lanes; k = k + 1) {
+ rdata = Afe_read(state, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
+ rdata = rdata & 0xCFFF;
+ switch (link_rate) {
+ case AFE_LINK_RATE_1_6:
+ case AFE_LINK_RATE_2_1:
+ case AFE_LINK_RATE_2_4:
+ case AFE_LINK_RATE_2_7:
+ rdata = rdata | 0x1000;
+ break;
+ case AFE_LINK_RATE_3_2:
+ case AFE_LINK_RATE_4_3:
+ case AFE_LINK_RATE_5_4:
+ rdata = rdata | 0x0000;
+ break;
+ default:
+ break;
+ }
+ Afe_write(state, (XCVR_DIAG_HSCLK_SEL | (k << 9)), rdata);
+ }
+ /* Gbps 1.62 2.16 2.43 2.7 3.24 4.32 5.4 */
+ Afe_write(state, CMN_PLL0_VCOCAL_INIT_TMR, 0x00F0);
+ Afe_write(state, CMN_PLL0_VCOCAL_ITER_TMR, 0x0018);
+ afe_write_reg(state, link_rate, CMN_PLL0_VCOCAL_START,
+ 0x30B9, 0x3087, 0x3096, 0x30B4, 0x30B9, 0x3087, 0x30B4);
+ afe_write_reg(state, link_rate, CMN_PLL0_INTDIV,
+ 0x0086, 0x00B3, 0x00CA, 0x00E0, 0x0086, 0x00B3, 0x00E0);
+ afe_write_reg(state, link_rate, CMN_PLL0_FRACDIV,
+ 0xF915, 0xF6C7, 0x75A1, 0xF479, 0xF915, 0xF6C7, 0xF479);
+ afe_write_reg(state, link_rate, CMN_PLL0_HIGH_THR,
+ 0x0022, 0x002D, 0x0033, 0x0038, 0x0022, 0x002D, 0x0038);
+#ifdef SSC_ON_INIT
+ /* Following register writes enable SSC on PHY's initialization. */
+ afe_write_reg(state, link_rate, CMN_PLL0_SS_CTRL1,
+ 0x0140, 0x01AB, 0x01E0, 0x0204, 0x0140, 0x01AB, 0x0204);
+ Afe_write(state, CMN_PLL0_SS_CTRL2, 0x7F03);
+#endif
+ Afe_write(state, CMN_PLL0_DSM_DIAG, 0x0020);
+ afe_write_reg(state, link_rate, CMN_PLLSM0_USER_DEF_CTRL,
+ 0x0000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x1000);
+ Afe_write(state, CMN_DIAG_PLL0_OVRD, 0x0000);
+ Afe_write(state, CMN_DIAG_PLL0_FBH_OVRD, 0x0000);
+ Afe_write(state, CMN_DIAG_PLL0_FBL_OVRD, 0x0000);
+ afe_write_reg(state, link_rate, CMN_DIAG_PLL0_V2I_TUNE,
+ 0x0006, 0x0007, 0x0007, 0x0007, 0x0006, 0x0007, 0x0007);
+ Afe_write(state, CMN_DIAG_PLL0_CP_TUNE, 0x0045);
+ Afe_write(state, CMN_DIAG_PLL0_LF_PROG, 0x0008);
+ afe_write_reg(state, link_rate, CMN_DIAG_PLL0_PTATIS_TUNE1,
+ 0x0100, 0x0001, 0x0001, 0x0001, 0x0100, 0x0001, 0x0001);
+ afe_write_reg(state, link_rate, CMN_DIAG_PLL0_PTATIS_TUNE2,
+ 0x0007, 0x0001, 0x0001, 0x0001, 0x0007, 0x0001, 0x0001);
+ for (k = 0; k < num_lanes; k = k + 1) {
+ rdata = Afe_read(state, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
+ rdata = rdata & 0x8FFF;
+ switch (link_rate) {
+ case AFE_LINK_RATE_1_6:
+ case AFE_LINK_RATE_2_1:
+ case AFE_LINK_RATE_2_4:
+ case AFE_LINK_RATE_2_7:
+ rdata = rdata | 0x2000;
+ break;
+ case AFE_LINK_RATE_3_2:
+ case AFE_LINK_RATE_4_3:
+ case AFE_LINK_RATE_5_4:
+ rdata = rdata | 0x1000;
+ break;
+ default:
+ break;
+ }
+ Afe_write(state, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), rdata);
+ }
+}
+
+/* Valid for 27 MHz only */
+static void phy_cfg_dp_pll0_27mhz(state_struct *state,
+ int num_lanes,
+ ENUM_AFE_LINK_RATE link_rate)
+{
+ int k;
+ unsigned short rdata;
+
+ rdata = Afe_read(state, PHY_HDP_CLK_CTL);
+ rdata = rdata & 0x00FF;
+ switch (link_rate) {
+ case AFE_LINK_RATE_1_6:
+ case AFE_LINK_RATE_2_1:
+ case AFE_LINK_RATE_2_4:
+ case AFE_LINK_RATE_2_7:
+ rdata = rdata | 0x2400;
+ break;
+ case AFE_LINK_RATE_3_2:
+ case AFE_LINK_RATE_4_3:
+ case AFE_LINK_RATE_5_4:
+ rdata = rdata | 0x1200;
+ break;
+ case AFE_LINK_RATE_8_1: /* Not supported MCU1 or MCU2 */
+ default:
+ pr_info("Warning. Unsupported Link Rate!\n");
+ break;
+ }
+ Afe_write(state, PHY_HDP_CLK_CTL, rdata);
+ rdata = Afe_read(state, CMN_DIAG_HSCLK_SEL);
+ rdata = rdata & 0xFFCC;
+ switch (link_rate) {
+ case AFE_LINK_RATE_1_6:
+ case AFE_LINK_RATE_2_1:
+ case AFE_LINK_RATE_2_4:
+ case AFE_LINK_RATE_2_7:
+ rdata = rdata | 0x0011;
+ break;
+ case AFE_LINK_RATE_3_2:
+ case AFE_LINK_RATE_4_3:
+ case AFE_LINK_RATE_5_4:
+ rdata = rdata | 0x0000;
+ break;
+ default:
+ break;
+ }
+ Afe_write(state, CMN_DIAG_HSCLK_SEL, rdata);
+ for (k = 0; k < num_lanes; k = k + 1) {
+ rdata = Afe_read(state, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
+ rdata = rdata & 0xCFFF;
+ switch (link_rate) {
+ case AFE_LINK_RATE_1_6:
+ case AFE_LINK_RATE_2_1:
+ case AFE_LINK_RATE_2_4:
+ case AFE_LINK_RATE_2_7:
+ rdata = rdata | 0x1000;
+ break;
+ case AFE_LINK_RATE_3_2:
+ case AFE_LINK_RATE_4_3:
+ case AFE_LINK_RATE_5_4:
+ rdata = rdata | 0x0000;
+ break;
+ default:
+ break;
+ }
+ Afe_write(state, (XCVR_DIAG_HSCLK_SEL | (k << 9)), rdata);
+ }
+ /* Gbps 1.62 2.16 2.43 2.7 3.24 4.32 5.4 */
+ Afe_write(state, CMN_PLL0_VCOCAL_INIT_TMR, 0x010E);
+ Afe_write(state, CMN_PLL0_VCOCAL_ITER_TMR, 0x001B);
+ afe_write_reg(state, link_rate, CMN_PLL0_VCOCAL_START,
+ 0x30B9, 0x3087, 0x3096, 0x30B4, 0x30B9, 0x3087, 0x30B4);
+ afe_write_reg(state, link_rate, CMN_PLL0_INTDIV,
+ 0x0077, 0x009F, 0x00B3, 0x00C7, 0x0077, 0x009F, 0x00C7);
+ afe_write_reg(state, link_rate, CMN_PLL0_FRACDIV,
+ 0xF9DA, 0xF7CD, 0xF6C7, 0xF5C1, 0xF9DA, 0xF7CD, 0xF5C1);
+ afe_write_reg(state, link_rate, CMN_PLL0_HIGH_THR,
+ 0x001E, 0x0028, 0x002D, 0x0032, 0x001E, 0x0028, 0x0032);
+#ifdef SSC_ON_INIT
+ /* Following register writes enable SSC on PHY's initialization. */
+ afe_write_reg(state, link_rate, CMN_PLL0_SS_CTRL1,
+ 0x0152, 0x01C2, 0x01FB, 0x0233, 0x0152, 0x01C2, 0x0233);
+ Afe_write(state, CMN_PLL0_SS_CTRL2, 0x6B04);
+#endif
+ Afe_write(state, CMN_PLL0_DSM_DIAG, 0x0020);
+ afe_write_reg(state, link_rate, CMN_PLLSM0_USER_DEF_CTRL,
+ 0x0000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x1000);
+ Afe_write(state, CMN_DIAG_PLL0_OVRD, 0x0000);
+ Afe_write(state, CMN_DIAG_PLL0_FBH_OVRD, 0x0000);
+ Afe_write(state, CMN_DIAG_PLL0_FBL_OVRD, 0x0000);
+ afe_write_reg(state, link_rate, CMN_DIAG_PLL0_V2I_TUNE,
+ 0x0006, 0x0007, 0x0007, 0x0007, 0x0006, 0x0007, 0x0007);
+ afe_write_reg(state, link_rate, CMN_DIAG_PLL0_CP_TUNE,
+ 0x0043, 0x0043, 0x0043, 0x0042, 0x0043, 0x0043, 0x0042);
+ Afe_write(state, CMN_DIAG_PLL0_LF_PROG, 0x0008);
+ afe_write_reg(state, link_rate, CMN_DIAG_PLL0_PTATIS_TUNE1,
+ 0x0100, 0x0001, 0x0001, 0x0001, 0x0100, 0x0001, 0x0001);
+ afe_write_reg(state, link_rate, CMN_DIAG_PLL0_PTATIS_TUNE2,
+ 0x0007, 0x0001, 0x0001, 0x0001, 0x0007, 0x0001, 0x0001);
+ for (k = 0; k < num_lanes; k = k + 1) {
+ rdata = Afe_read(state, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
+ rdata = rdata & 0x8FFF;
+ switch (link_rate) {
+ case AFE_LINK_RATE_1_6:
+ case AFE_LINK_RATE_2_1:
+ case AFE_LINK_RATE_2_4:
+ case AFE_LINK_RATE_2_7:
+ rdata = rdata | 0x2000;
+ break;
+ case AFE_LINK_RATE_3_2:
+ case AFE_LINK_RATE_4_3:
+ case AFE_LINK_RATE_5_4:
+ rdata = rdata | 0x1000;
+ break;
+ default:
+ break;
+ }
+ Afe_write(state, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), rdata);
+ }
+}
+
+static void phy_cfg_dp_ln(state_struct *state, int num_lanes)
+{
+ int k;
+ unsigned short rdata;
+
+ for (k = 0; k < num_lanes; k = k + 1) {
+ Afe_write(state, (XCVR_PSM_RCTRL | (k << 9)), 0xBEFC);
+ if (state->edp == 0) {
+ Afe_write(state, (TX_PSC_A0 | (k << 9)), 0x6799);
+ Afe_write(state, (TX_PSC_A1 | (k << 9)), 0x6798);
+ Afe_write(state, (TX_PSC_A2 | (k << 9)), 0x0098);
+ Afe_write(state, (TX_PSC_A3 | (k << 9)), 0x0098);
+ } else {
+ Afe_write(state, (TX_PSC_A0 | (k << 9)), 0x279B);
+ Afe_write(state, (TX_PSC_A1 | (k << 9)), 0x2798);
+ Afe_write(state, (TX_PSC_A2 | (k << 9)), 0x0098);
+ Afe_write(state, (TX_PSC_A3 | (k << 9)), 0x0098);
+
+ rdata = Afe_read(state, TX_DIAG_TX_DRV | (k << 9));
+ /* keep bits related to programmable boost */
+ rdata &= 0x0600;
+ rdata |= 0x00C0;
+ Afe_write(state, (TX_DIAG_TX_DRV | (k << 9)), rdata);
+ }
+ rdata = Afe_read(state, RX_PSC_CAL | (k << 9));
+ rdata = rdata & 0xFFBB;
+ Afe_write(state, (RX_PSC_CAL | (k << 9)), rdata);
+ rdata = Afe_read(state, RX_PSC_A0 | (k << 9));
+ rdata = rdata & 0xFFBB;
+ Afe_write(state, (RX_PSC_A0 | (k << 9)), rdata);
+ }
+}
+
+static void aux_cfg_t28hpc(state_struct *state)
+{
+#ifdef DEBUG
+ unsigned short rdata;
+#endif
+ Afe_write(state, TX_DIG_CTRL_REG_2, 36);
+
+ Afe_write(state, TX_ANA_CTRL_REG_2, 0x0100);
+ cdn_usleep(150);
+ Afe_write(state, TX_ANA_CTRL_REG_2, 0x0300);
+ cdn_usleep(150);
+ Afe_write(state, TX_ANA_CTRL_REG_3, 0x0000);
+ cdn_usleep(150);
+ Afe_write(state, TX_ANA_CTRL_REG_1, 0x2008);
+ cdn_usleep(150);
+ Afe_write(state, TX_ANA_CTRL_REG_1, 0x2018);
+ cdn_usleep(150);
+ Afe_write(state, TX_ANA_CTRL_REG_1, 0xA018);
+ cdn_usleep(150);
+ Afe_write(state, TX_ANA_CTRL_REG_2, 0x030C);
+ cdn_usleep(150);
+ Afe_write(state, TX_ANA_CTRL_REG_5, 0x0000);
+ cdn_usleep(150);
+ Afe_write(state, TX_ANA_CTRL_REG_4, 0x1001);
+ cdn_usleep(150);
+ Afe_write(state, TX_ANA_CTRL_REG_1, 0xA098);
+ cdn_usleep(5000);
+ Afe_write(state, TX_ANA_CTRL_REG_1, 0xA198);
+ cdn_usleep(5000);
+ Afe_write(state, TX_ANA_CTRL_REG_2, 0x030d);
+ cdn_usleep(5000);
+ Afe_write(state, TX_ANA_CTRL_REG_2, 0x030f);
+ cdn_usleep(5000);
+
+#ifdef DEBUG
+ rdata = Afe_read(state, TX_ANA_CTRL_REG_1);
+ pr_info("TX_ANA_CTRL_REG_1 %x)\n", rdata);
+ rdata = Afe_read(state, TX_ANA_CTRL_REG_2);
+ pr_info("TX_ANA_CTRL_REG_2 %x)\n", rdata);
+ rdata = Afe_read(state, TX_ANA_CTRL_REG_3);
+ pr_info("TX_ANA_CTRL_REG_3 %x)\n", rdata);
+ rdata = Afe_read(state, TX_ANA_CTRL_REG_4);
+ pr_info("TX_ANA_CTRL_REG_4 %x)\n", rdata);
+ rdata = Afe_read(state, TX_ANA_CTRL_REG_5);
+ pr_info("TX_ANA_CTRL_REG_5 %x)\n", rdata);
+#endif
+}
+
+void afe_init_t28hpc(state_struct *state,
+ int num_lanes,
+ ENUM_AFE_LINK_RATE link_rate)
+{
+ u16 val;
+ const int phy_reset_workaround = 0;
+
+ const REFCLK_FREQ refclk = REFCLK_27MHZ;
+
+ if (AFE_check_rate_supported(link_rate) == 0) {
+ pr_err("afe_init_t28hpc(): Selected link rate not supported: 0x%x\n",
+ link_rate);
+ return;
+ }
+
+ if (phy_reset_workaround) {
+ int k;
+ uint32_t reg_val;
+ /* enable PHY isolation mode only for CMN */
+ /* register PHY_PMA_ISOLATION_CTRL */
+ Afe_write(state, 0xC81F, 0xD000);
+
+ /* set cmn_pll0_clk_datart1_div/cmn_pll0_clk_datart0_div
+ * dividers
+ */
+ /* register PHY_PMA_ISO_PLL_CTRL1 */
+ reg_val = Afe_read(state, 0xC812);
+ reg_val &= 0xFF00;
+ reg_val |= 0x0012;
+ Afe_write(state, 0xC812, reg_val);
+
+ /* assert PHY reset from isolation register */
+ /* register PHY_ISO_CMN_CTRL */
+ Afe_write(state, 0xC010, 0x0000);
+
+ /* assert PMA CMN reset */
+ /* register PHY_PMA_ISO_CMN_CTRL */
+ Afe_write(state, 0xC810, 0x0000);
+
+ for (k = 0; k < num_lanes; k++) {
+ /* register XCVR_DIAG_BIDI_CTRL */
+ Afe_write(state, 0x40E8 | (k << 9), 0x00FF);
+ }
+ }
+
+ val = Afe_read(state, PHY_PMA_CMN_CTRL1);
+ val = val & 0xFFF7;
+ val = val | 0x0008;
+ Afe_write(state, PHY_PMA_CMN_CTRL1, val);
+
+ Afe_write(state, CMN_DIAG_PLL0_TEST_MODE, 0x0022);
+ Afe_write(state, CMN_PSM_CLK_CTRL, 0x0016);
+
+ if (refclk == REFCLK_24MHZ) {
+ phy_cfg_24mhz(state, num_lanes);
+ phy_cfg_dp_pll0_24mhz(state, num_lanes, link_rate);
+ } else if (refclk == REFCLK_27MHZ) {
+ phy_cfg_27mhz(state, num_lanes);
+ phy_cfg_dp_pll0_27mhz(state, num_lanes, link_rate);
+ } else
+ pr_info("AFE_init() *E: Incorrect value of the refclk: %0d\n",
+ refclk);
+
+ val = Afe_read(state, PHY_PMA_CMN_CTRL1);
+ val = val & 0xFF8F;
+ /* for single ended reference clock on the cmn_ref_clk_int pin:
+ * PHY_PMA_CMN_CTRL1[6:4]=3'b011
+ * val |= 0x0030;
+ */
+
+ /* for differential clock on the refclk_p and refclk_m off chip pins:
+ * PHY_PMA_CMN_CTRL1[6:4]=3'b000
+ * val = val | 0x0030;
+ */
+ val = val | 0x0000; /* select external reference */
+ Afe_write(state, PHY_PMA_CMN_CTRL1, val);
+
+ /* for differential clock on the refclk_p and refclk_m off chip pins:
+ * CMN_DIAG_ACYA[8]=1'b1
+ */
+ Afe_write(state, CMN_DIAG_ACYA /*0x01FF*/, 0x0100);
+
+ if (phy_reset_workaround) {
+ int k;
+ /* Deassert PHY reset*/
+ /* register PHY_ISO_CMN_CTRL */
+ Afe_write(state, 0xC010, 0x0001);
+ /* register PHY_PMA_ISO_CMN_CTRL */
+ Afe_write(state, 0xC810, 0x0003);
+ for (k = 0; k < num_lanes; k++) {
+ /* register XCVR_PSM_RCTRL */
+ Afe_write(state, 0x4001 | (k << 9), 0xFEFC);
+ }
+ /* Assert cmn_macro_pwr_en */
+ /* register PHY_PMA_ISO_CMN_CTRL */
+ Afe_write(state, 0xC810, 0x0013);
+
+ /* wait for cmn_macro_pwr_en_ack */
+ /* PHY_PMA_ISO_CMN_CTRL */
+ while (!(Afe_read(state, 0xC810) & (1 << 5)))
+ ;
+
+ /* wait for cmn_ready */
+ /* PHY_PMA_CMN_CTRL1 */
+ while (!(Afe_read(state, 0xC800) & (1 << 0)))
+ ;
+ }
+
+ if (state->edp != 0)
+ Afe_write(state, CMN_DIAG_CAL_CTRL, 0x0001);
+
+ phy_cfg_dp_ln(state, num_lanes);
+
+ /* Configure PHY in A2 Mode */
+ Afe_write(state, PHY_HDP_MODE_CTRL, 0x0004);
+}
+
+void afe_power_t28hpc(state_struct *state,
+ int num_lanes,
+ ENUM_AFE_LINK_RATE link_rate)
+{
+ unsigned short val;
+ int i = 0;
+
+ if (AFE_check_rate_supported(link_rate) == 0) {
+ pr_err("%s() *E: Selected link rate not supported: 0x%x\n",
+ __func__, link_rate);
+ return;
+ }
+
+ Afe_write(state, TX_DIAG_ACYA_0, 1);
+ Afe_write(state, TX_DIAG_ACYA_1, 1);
+ Afe_write(state, TX_DIAG_ACYA_2, 1);
+ Afe_write(state, TX_DIAG_ACYA_3, 1);
+
+ Afe_write(state, TXDA_CYA_AUXDA_CYA, 1);
+
+ /* Wait for A2 ACK (PHY_HDP_MODE_CTL [6] = 1’b1) */
+ do {
+ val = Afe_read(state, PHY_HDP_MODE_CTRL);
+ val = val >> 6;
+ if (i++ % 10000 == 0)
+ pr_info("Wait for A2 ACK\n");
+ } while ((val & 1) == 0);
+
+ /* Configure PHY in A0 mode (PHY must be in the A0 power
+ * state in order to transmit data)
+ */
+ Afe_write(state, PHY_HDP_MODE_CTRL, 0x0101);
+ /* Wait for A2 ACK (PHY_HDP_MODE_CTL [4] = 1’b1) */
+ do {
+ val = Afe_read(state, PHY_HDP_MODE_CTRL);
+ val = val >> 4;
+ if (i++ % 10000 == 0)
+ pr_info("Wait for A2 ACK again\n");
+ } while ((val & 1) == 0);
+
+ aux_cfg_t28hpc(state);
+
+}
diff --git a/drivers/gpu/drm/imx/hdp/API_AFE_mcu2_dp.h b/drivers/gpu/drm/imx/hdp/API_AFE_mcu2_dp.h
new file mode 100644
index 000000000000..1f450b8f4d00
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/API_AFE_mcu2_dp.h
@@ -0,0 +1,195 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * Copyright 2018 NXP
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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. THE SOFTWARE IS PROVIDED "AS IS",
+ * WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ ******************************************************************************
+ *
+ * API_AFE_mcu2_dp.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef API_AFE_MCU2_DP_H
+# define API_AFE_MCU2_DP_H
+
+#define CMN_SSM_BIAS_TMR 0x0022
+#define CMN_PLLSM0_PLLEN_TMR 0x0029
+#define CMN_PLLSM0_PLLPRE_TMR 0x002A
+#define CMN_PLLSM0_PLLVREF_TMR 0x002B
+#define CMN_PLLSM0_PLLLOCK_TMR 0x002C
+#define CMN_ICAL_INIT_TMR 0x00C4
+#define CMN_ICAL_ITER_TMR 0x00C5
+#define CMN_ICAL_ADJ_INIT_TMR 0x0102
+#define CMN_ICAL_ADJ_ITER_TMR 0x0103
+#define CMN_TXPUCAL_INIT_TMR 0x00E4
+#define CMN_TXPUCAL_ITER_TMR 0x00E5
+#define CMN_TXPU_ADJ_INIT_TMR 0x010A
+#define CMN_TXPU_ADJ_ITER_TMR 0x010B
+#define CMN_TXPDCAL_INIT_TMR 0x00F4
+#define CMN_TXPDCAL_ITER_TMR 0x00F5
+#define CMN_TXPD_ADJ_INIT_TMR 0x010E
+#define CMN_TXPD_ADJ_ITER_TMR 0x010F
+#define CMN_RXCAL_INIT_TMR 0x00D4
+#define CMN_RXCAL_ITER_TMR 0x00D5
+#define CMN_RX_ADJ_INIT_TMR 0x0106
+#define CMN_RX_ADJ_ITER_TMR 0x0107
+#define XCVR_PSM_CAL_TMR 0x4002
+#define XCVR_PSM_A0IN_TMR 0x4003
+
+#define PHY_PMA_CMN_CTRL1 0xC800
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR 0x40F2
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_0 0x40F2
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_1 0x42F2
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_2 0x44F2
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_3 0x46F2
+#define TX_RCVDET_EN_TMR 0x4122
+#define TX_RCVDET_EN_TMR_0 0x4122
+#define TX_RCVDET_EN_TMR_1 0x4322
+#define TX_RCVDET_EN_TMR_2 0x4522
+#define TX_RCVDET_EN_TMR_3 0x4722
+#define TX_RCVDET_ST_TMR 0x4123
+#define TX_RCVDET_ST_TMR_0 0x4123
+#define TX_RCVDET_ST_TMR_1 0x4323
+#define TX_RCVDET_ST_TMR_2 0x4523
+#define TX_RCVDET_ST_TMR_3 0x4723
+#define PHY_HDP_CLK_CTL 0xC009
+#define CMN_DIAG_HSCLK_SEL 0x01E0
+#define XCVR_DIAG_HSCLK_SEL 0x40E1
+#define XCVR_DIAG_HSCLK_SEL_0 0x40E1
+#define XCVR_DIAG_HSCLK_SEL_1 0x42E1
+#define XCVR_DIAG_HSCLK_SEL_2 0x44E1
+#define XCVR_DIAG_HSCLK_SEL_3 0x46E1
+#define CMN_PLL0_VCOCAL_START 0x0081
+#define CMN_PLLSM0_USER_DEF_CTRL 0x002F
+#define CMN_DIAG_PLL0_V2I_TUNE 0x01C5
+#define CMN_DIAG_PLL0_PTATIS_TUNE1 0x01C8
+#define CMN_DIAG_PLL0_PTATIS_TUNE2 0x01C9
+#define CMN_DIAG_PLL0_CP_TUNE 0x01C6
+#define CMN_DIAG_PER_CAL_ADJ 0x01EC
+#define CMN_DIAG_CAL_CTRL 0x01ED
+#define CMN_DIAG_ACYA 0x01ff
+#define CMN_DIAG_PLL0_LF_PROG 0x01C7
+#define CMN_PLL0_VCOCAL_INIT_TMR 0x0084
+#define CMN_PLL0_VCOCAL_ITER_TMR 0x0085
+#define CMN_PLL0_INTDIV 0x0094
+#define CMN_PLL0_FRACDIV 0x0095
+#define CMN_PLL0_HIGH_THR 0x0096
+#define CMN_PLL0_SS_CTRL1 0x0098
+#define CMN_PLL0_SS_CTRL2 0x0099
+#define CMN_PLL0_DSM_DIAG 0x0097
+#define CMN_DIAG_PLL0_OVRD 0x01C2
+#define CMN_DIAG_PLL0_FBH_OVRD 0x01C0
+#define CMN_DIAG_PLL0_FBL_OVRD 0x01C1
+#define XCVR_DIAG_PLLDRC_CTRL 0x40E0
+#define XCVR_DIAG_PLLDRC_CTRL_0 0x40E0
+#define XCVR_DIAG_PLLDRC_CTRL_1 0x42E0
+#define XCVR_DIAG_PLLDRC_CTRL_2 0x44E0
+#define XCVR_DIAG_PLLDRC_CTRL_3 0x46E0
+#define CMN_DIAG_PLL0_TEST_MODE 0x01C4
+#define PHY_HDP_MODE_CTRL 0xC008
+#define XCVR_PSM_RCTRL 0x4001
+#define XCVR_PSM_RCTRL_0 0x4001
+#define XCVR_PSM_RCTRL_1 0x4201
+#define XCVR_PSM_RCTRL_2 0x4401
+#define XCVR_PSM_RCTRL_3 0x4601
+#define TX_PSC_A0 0x4100
+#define TX_PSC_A0_0 0x4100
+#define TX_PSC_A0_1 0x4300
+#define TX_PSC_A0_2 0x4500
+#define TX_PSC_A0_3 0x4700
+#define TX_PSC_A1 0x4101
+#define TX_PSC_A1_0 0x4101
+#define TX_PSC_A1_1 0x4301
+#define TX_PSC_A1_2 0x4501
+#define TX_PSC_A1_3 0x4701
+#define TX_PSC_A2 0x4102
+#define TX_PSC_A2_0 0x4102
+#define TX_PSC_A2_1 0x4302
+#define TX_PSC_A2_2 0x4502
+#define TX_PSC_A2_3 0x4702
+#define TX_PSC_A3 0x4103
+#define TX_PSC_A3_0 0x4103
+#define TX_PSC_A3_1 0x4303
+#define TX_PSC_A3_2 0x4503
+#define TX_PSC_A3_3 0x4703
+#define TX_DIAG_TX_DRV 0x41E1
+#define TX_DIAG_TX_DRV_0 0x41E1
+#define TX_DIAG_TX_DRV_1 0x43E1
+#define TX_DIAG_TX_DRV_2 0x45E1
+#define TX_DIAG_TX_DRV_3 0x47E1
+#define TX_DIAG_BGREF_PREDRV_DELAY 0x41E7
+#define PHY_HDP_MODE_CTRL 0xC008
+#define TX_DIAG_ACYA_0 0x41ff
+#define TX_DIAG_ACYA_1 0x43ff
+#define TX_DIAG_ACYA_2 0x45ff
+#define TX_DIAG_ACYA_3 0x47ff
+
+#define RX_PSC_A0 0x8000
+#define RX_PSC_CAL 0x8006
+#define TX_TXCC_MGNFS_MULT_000_0 0x4050
+#define TX_TXCC_MGNFS_MULT_000_1 0x4250
+#define TX_TXCC_MGNFS_MULT_000_2 0x4450
+#define TX_TXCC_MGNFS_MULT_000_3 0x4650
+
+#define TX_TXCC_CPOST_MULT_00_0 0x404C
+#define TX_TXCC_CPOST_MULT_00_1 0x424C
+#define TX_TXCC_CPOST_MULT_00_2 0x444C
+#define TX_TXCC_CPOST_MULT_00_3 0x464C
+
+#define TX_ANA_CTRL_REG_1 0x5020
+#define TX_ANA_CTRL_REG_2 0x5021
+#define TX_ANA_CTRL_REG_3 0x5026
+#define TX_ANA_CTRL_REG_4 0x5027
+#define TX_ANA_CTRL_REG_5 0x5029
+
+#define TX_DIG_CTRL_REG_2 0x5024
+#define TX_DIG_CTRL_REG_1 0x5023
+#define TXDA_CYA_AUXDA_CYA 0x5025
+#define CMN_TXPUCAL_CTRL 0x00E0
+#define CMN_TXPDCAL_CTRL 0x00F0
+#define CMN_TXPU_ADJ_CTRL 0x0108
+#define CMN_TXPD_ADJ_CTRL 0x010c
+#define TXDA_COEFF_CALC 0x5022
+#define CMN_PSM_CLK_CTRL 0x0061
+
+#define PHY_HDP_TX_CTL_L0 0xC408
+#define PHY_HDP_TX_CTL_L1 0xC448
+#define PHY_HDP_TX_CTL_L2 0xC488
+#define PHY_HDP_TX_CTL_L3 0xC4C8
+
+#endif //API_AFE_MCU2_DP_H
diff --git a/drivers/gpu/drm/imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.c b/drivers/gpu/drm/imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.c
new file mode 100644
index 000000000000..471039fb6a13
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.c
@@ -0,0 +1,550 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_AFE_ss28fdsoi_kiran_hdmitx.c
+ *
+ ******************************************************************************
+ */
+
+#include <drm/drmP.h>
+#include <linux/io.h>
+#include "API_AFE_ss28fdsoi_kiran_hdmitx.h"
+#include "ss28fdsoi_hdmitx_table.h"
+#include "imx-hdp.h"
+
+int phy_cfg_hdp_ss28fdsoi(state_struct *state,
+ int num_lanes,
+ struct drm_display_mode *mode,
+ int bpp,
+ VIC_PXL_ENCODING_FORMAT format)
+{
+ const int phy_reset_workaround = 0;
+ u32 vco_freq_khz;
+ unsigned char i;
+ u32 feedback_factor;
+ int row;
+ u32 reg_val;
+ int pixel_freq_khz = mode->clock;
+ u32 character_clock_ratio_num = 1;
+ u32 character_clock_ratio_den = 1;
+ int character_freq_khz;
+ u32 ftemp;
+ clk_ratio_t clk_ratio = CLK_RATIO_1_1;
+
+ reg_field_t cmnda_pll0_hs_sym_div_sel;
+ reg_field_t cmnda_pll0_ip_div;
+ reg_field_t cmnda_pll0_fb_div_low;
+ reg_field_t cmnda_pll0_fb_div_high;
+ reg_field_t cmn_ref_clk_dig_div;
+ reg_field_t divider_scaler;
+ reg_field_t cmnda_hs_clk_0_sel;
+ reg_field_t cmnda_hs_clk_1_sel;
+ reg_field_t tx_subrate;
+ reg_field_t vco_ring_select;
+ reg_field_t pll_feedback_divider_total;
+ reg_field_t voltage_to_current_coarse;
+ reg_field_t voltage_to_current;
+ reg_field_t ndac_ctrl;
+ reg_field_t pmos_ctrl;
+ reg_field_t ptat_ndac_ctrl;
+ reg_field_t charge_pump_gain;
+
+ /* Set field position in a target register */
+ cmnda_pll0_fb_div_high.value = 0x00A;
+ cmnda_pll0_hs_sym_div_sel.msb = 9;
+ cmnda_pll0_hs_sym_div_sel.lsb = 8;
+ cmnda_pll0_ip_div.msb = 7;
+ cmnda_pll0_ip_div.lsb = 0;
+ cmnda_pll0_fb_div_low.msb = 9;
+ cmnda_pll0_fb_div_low.lsb = 0;
+ cmnda_pll0_fb_div_high.msb = 9;
+ cmnda_pll0_fb_div_high.lsb = 0;
+ cmn_ref_clk_dig_div.msb = 13;
+ cmn_ref_clk_dig_div.lsb = 12;
+ divider_scaler.msb = 14;
+ divider_scaler.lsb = 12;
+ cmnda_hs_clk_0_sel.msb = 1;
+ cmnda_hs_clk_0_sel.lsb = 0;
+ cmnda_hs_clk_1_sel.msb = 1;
+ cmnda_hs_clk_1_sel.lsb = 0;
+ tx_subrate.msb = 2;
+ tx_subrate.lsb = 0;
+ vco_ring_select.msb = 12;
+ vco_ring_select.lsb = 12;
+ pll_feedback_divider_total.msb = 9;
+ pll_feedback_divider_total.lsb = 0;
+ voltage_to_current_coarse.msb = 2;
+ voltage_to_current_coarse.lsb = 0;
+ voltage_to_current.msb = 5;
+ voltage_to_current.lsb = 4;
+ ndac_ctrl.msb = 11;
+ ndac_ctrl.lsb = 8;
+ pmos_ctrl.msb = 7;
+ pmos_ctrl.lsb = 0;
+ ptat_ndac_ctrl.msb = 5;
+ ptat_ndac_ctrl.lsb = 0;
+ charge_pump_gain.msb = 8;
+ charge_pump_gain.lsb = 0;
+
+ DRM_INFO
+ ("phy_cfg_hdp() num_lanes: %0d, mode:%dx%dp%d, color depth: %0d-bit, encoding: %0d\n",
+ num_lanes, mode->hdisplay, mode->vdisplay, mode->vrefresh, bpp, format);
+
+ /* register PHY_PMA_ISOLATION_CTRL
+ * enable PHY isolation mode only for CMN */
+ if (phy_reset_workaround) {
+ Afe_write(state, 0xC81F, 0xD000);
+ reg_val = Afe_read(state, 0xC812);
+ reg_val &= 0xFF00;
+ reg_val |= 0x0012;
+ /* set cmn_pll0_clk_datart1_div/cmn_pll0_clk_datart0_div dividers */
+ Afe_write(state, 0xC812, reg_val);
+ /* register PHY_ISO_CMN_CTRL */
+ Afe_write(state, 0xC010, 0x0000); /* assert PHY reset from isolation register */
+ /* register PHY_PMA_ISO_CMN_CTRL */
+ Afe_write(state, 0xC810, 0x0000); /* assert PMA CMN reset */
+ /* register XCVR_DIAG_BIDI_CTRL */
+ for (i = 0; i < num_lanes; i++) {
+ Afe_write(state, 0x40E8 | (i << 9), 0x00FF);
+ }
+ } else {
+ /*--------------------------------------------------------------
+ * Describing Task phy_cfg_hdp
+ * ------------------------------------------------------------*/
+ /* register PHY_PMA_CMN_CTRL1 */
+ for (i = 0; i < num_lanes; i++)
+ Afe_write(state, 0x40E8 | (i << 9), 0x007F);
+ }
+ /* register CMN_DIAG_PLL0_TEST_MODE */
+ Afe_write(state, 0x01C4, 0x0022);
+ /* register CMN_PSM_CLK_CTRL */
+ Afe_write(state, 0x0061, 0x0016);
+
+ /* Determine the TMDS/PIXEL clock ratio */
+ switch (format) {
+ case YCBCR_4_2_2:
+ clk_ratio = CLK_RATIO_1_1;
+ character_clock_ratio_num = 1;
+ character_clock_ratio_den = 1;
+ break;
+ case YCBCR_4_2_0:
+ switch (bpp) {
+ case 8:
+ clk_ratio = CLK_RATIO_1_2;
+ character_clock_ratio_num = 1;
+ character_clock_ratio_den = 2;
+ break;
+ case 10:
+ clk_ratio = CLK_RATIO_5_8;
+ character_clock_ratio_num = 5;
+ character_clock_ratio_den = 8;
+ break;
+ case 12:
+ clk_ratio = CLK_RATIO_3_4;
+ character_clock_ratio_num = 3;
+ character_clock_ratio_den = 4;
+ break;
+ case 16:
+ clk_ratio = CLK_RATIO_1_1;
+ character_clock_ratio_num = 1;
+ character_clock_ratio_den = 1;
+ break;
+ default:
+ pr_err("Invalid ColorDepth\n");
+ }
+ break;
+
+ default:
+ switch (bpp) { /* Assume RGB */
+ case 10:
+ clk_ratio = CLK_RATIO_5_4;
+ character_clock_ratio_num = 5;
+ character_clock_ratio_den = 4;
+ break;
+ case 12:
+ clk_ratio = CLK_RATIO_3_2;
+ character_clock_ratio_num = 3;
+ character_clock_ratio_den = 2;
+ break;
+ case 16:
+ clk_ratio = CLK_RATIO_2_1;
+ character_clock_ratio_num = 2;
+ character_clock_ratio_den = 1;
+ break;
+ default:
+ clk_ratio = CLK_RATIO_1_1;
+ character_clock_ratio_num = 1;
+ character_clock_ratio_den = 1;
+ }
+ }
+
+ /* Determine a relevant feedback factor as used
+ * in the ss28fdsoi_hdmitx_clock_control_table table */
+ switch (clk_ratio) {
+ case CLK_RATIO_1_1:
+ feedback_factor = 1000;
+ break;
+ case CLK_RATIO_5_4:
+ feedback_factor = 1250;
+ break;
+ case CLK_RATIO_3_2:
+ feedback_factor = 1500;
+ break;
+ case CLK_RATIO_2_1:
+ feedback_factor = 2000;
+ break;
+ case CLK_RATIO_1_2:
+ feedback_factor = 500;
+ break;
+ case CLK_RATIO_5_8:
+ feedback_factor = 625;
+ break;
+ case CLK_RATIO_3_4:
+ feedback_factor = 750;
+ break;
+ }
+
+ /* Get right row from the ss28fdsoi_hdmitx_clock_control_table table.
+ * Check if 'pixel_freq_khz' falls inside the
+ * <PIXEL_CLK_FREQ_KHZ_MIN, PIXEL_CLK_FREQ_KHZ_MAX> range.
+ * Consider only the rows with FEEDBACK_FACTOR column matching feedback_factor. */
+ row =
+ get_table_row((const u32 *)&ss28fdsoi_hdmitx_clock_control_table,
+ SS28FDSOI_HDMITX_CLOCK_CONTROL_TABLE_ROWS,
+ SS28FDSOI_HDMITX_CLOCK_CONTROL_TABLE_COLS,
+ pixel_freq_khz, PIXEL_CLK_FREQ_KHZ_MIN,
+ PIXEL_CLK_FREQ_KHZ_MAX, FEEDBACK_FACTOR,
+ feedback_factor);
+
+ /* Check if row was found */
+ ftemp = pixel_freq_khz;
+ if (row == -1) {
+ DRM_WARN("Pixel clock frequency (%u kHz) not supported for this color depth (%0d-bit), row=%d\n",
+ ftemp, bpp, row);
+ return 0;
+ }
+ DRM_INFO
+ ("Pixel clock frequency (%u kHz) is supported in this color depth (%0d-bit). Settings found in row %0d\n",
+ ftemp, bpp, row);
+
+ character_freq_khz =
+ pixel_freq_khz * character_clock_ratio_num /
+ character_clock_ratio_den;
+ ftemp = character_freq_khz;
+ DRM_INFO("Character clock frequency: %u kHz.\n", ftemp);
+
+ /* Extract particular values from the ss28fdsoi_hdmitx_clock_control_table table */
+ set_field_value(&cmnda_pll0_hs_sym_div_sel,
+ ss28fdsoi_hdmitx_clock_control_table[row]
+ [CMNDA_PLL0_HS_SYM_DIV_SEL]);
+ set_field_value(&cmnda_pll0_ip_div,
+ ss28fdsoi_hdmitx_clock_control_table[row]
+ [CMNDA_PLL0_IP_DIV]);
+ set_field_value(&cmnda_pll0_fb_div_low,
+ ss28fdsoi_hdmitx_clock_control_table[row]
+ [CMNDA_PLL0_FB_DIV_LOW]);
+ set_field_value(&cmnda_pll0_fb_div_high,
+ ss28fdsoi_hdmitx_clock_control_table[row]
+ [CMNDA_PLL0_FB_DIV_HIGH]);
+ set_field_value(&cmn_ref_clk_dig_div,
+ ss28fdsoi_hdmitx_clock_control_table[row]
+ [CMN_REF_CLK_DIG_DIV]);
+ set_field_value(&divider_scaler,
+ ss28fdsoi_hdmitx_clock_control_table[row]
+ [REF_CLK_DIVIDER_SCALER]);
+ set_field_value(&cmnda_hs_clk_0_sel,
+ ss28fdsoi_hdmitx_clock_control_table[row]
+ [CMNDA_HS_CLK_0_SEL]);
+ set_field_value(&cmnda_hs_clk_1_sel,
+ ss28fdsoi_hdmitx_clock_control_table[row]
+ [CMNDA_HS_CLK_1_SEL]);
+ set_field_value(&tx_subrate, ss28fdsoi_hdmitx_clock_control_table[row]
+ [HSCLK_DIV_TX_SUB_RATE]);
+ set_field_value(&vco_ring_select,
+ ss28fdsoi_hdmitx_clock_control_table[row]
+ [VCO_RING_SELECT]);
+ set_field_value(&pll_feedback_divider_total,
+ ss28fdsoi_hdmitx_clock_control_table[row]
+ [PLL_FB_DIV_TOTAL]);
+
+ /* Display parameters (informative message) */
+ DRM_DEBUG("set_field_value() cmnda_pll0_hs_sym_div_sel : 0x%X\n",
+ cmnda_pll0_hs_sym_div_sel.value);
+ DRM_DEBUG("set_field_value() cmnda_pll0_ip_div : 0x%02X\n",
+ cmnda_pll0_ip_div.value);
+ DRM_DEBUG("set_field_value() cmnda_pll0_fb_div_low : 0x%03X\n",
+ cmnda_pll0_fb_div_low.value);
+ DRM_DEBUG("set_field_value() cmnda_pll0_fb_div_high : 0x%03X\n",
+ cmnda_pll0_fb_div_high.value);
+ DRM_DEBUG("set_field_value() cmn_ref_clk_dig_div : 0x%X\n",
+ cmn_ref_clk_dig_div.value);
+ DRM_DEBUG("set_field_value() divider_scaler : 0x%X\n",
+ divider_scaler.value);
+ DRM_DEBUG("set_field_value() cmnda_hs_clk_0_sel : %0d\n",
+ cmnda_hs_clk_0_sel.value);
+ DRM_DEBUG("set_field_value() cmnda_hs_clk_1_sel : %0d\n",
+ cmnda_hs_clk_1_sel.value);
+ DRM_DEBUG("set_field_value() tx_subrate : %0d\n",
+ tx_subrate.value);
+ DRM_DEBUG("set_field_value() vco_ring_select : %0d\n",
+ vco_ring_select.value);
+ DRM_DEBUG("set_field_value() pll_feedback_divider_total: %0d\n",
+ pll_feedback_divider_total.value);
+
+ vco_freq_khz =
+ pixel_freq_khz * pll_feedback_divider_total.value /
+ cmnda_pll0_ip_div.value;
+
+ /* Get right row from the ss28fdsoi_hdmitx_pll_tuning_table table.
+ * Check if 'vco_freq_mhz' falls inside the
+ * <PLL_VCO_FREQ_MHZ_MIN, PLL_VCO_FREQ_MHZ_MAX> range.
+ * Consider only the rows with PLL_FEEDBACK_DIV_TOTAL.
+ * column matching pll_feedback_divider_total. */
+ row =
+ get_table_row((const u32 *)&ss28fdsoi_hdmitx_pll_tuning_table,
+ SS28FDSOI_HDMITX_PLL_TUNING_TABLE_ROWS,
+ SS28FDSOI_HDMITX_PLL_TUNING_TABLE_COLS, vco_freq_khz,
+ PLL_VCO_FREQ_KHZ_MIN, PLL_VCO_FREQ_KHZ_MAX,
+ PLL_FEEDBACK_DIV_TOTAL,
+ pll_feedback_divider_total.value);
+ ftemp = vco_freq_khz;
+ if (row == -1) {
+ DRM_WARN("VCO frequency (%u kHz) not supported\n", ftemp);
+ return 0;
+ }
+ DRM_INFO
+ ("VCO frequency (%u kHz) is supported. Settings found in row %0d\n",
+ ftemp, row);
+
+ /* Extract particular values from the ss28fdsoi_hdmitx_pll_tuning_table table */
+ set_field_value(&voltage_to_current_coarse,
+ ss28fdsoi_hdmitx_pll_tuning_table[row]
+ [VOLTAGE_TO_CURRENT_COARSE]);
+ set_field_value(&voltage_to_current,
+ ss28fdsoi_hdmitx_pll_tuning_table[row]
+ [VOLTAGE_TO_CURRENT]);
+ set_field_value(&ndac_ctrl,
+ ss28fdsoi_hdmitx_pll_tuning_table[row][NDAC_CTRL]);
+ set_field_value(&pmos_ctrl,
+ ss28fdsoi_hdmitx_pll_tuning_table[row][PMOS_CTRL]);
+ set_field_value(&ptat_ndac_ctrl,
+ ss28fdsoi_hdmitx_pll_tuning_table[row][PTAT_NDAC_CTRL]);
+ set_field_value(&charge_pump_gain,
+ ss28fdsoi_hdmitx_pll_tuning_table[row]
+ [CHARGE_PUMP_GAIN]);
+
+ /* Display parameters (informative message) */
+ DRM_DEBUG("set_field_value() voltage_to_current_coarse : 0x%X\n",
+ voltage_to_current_coarse.value);
+ DRM_DEBUG("set_field_value() voltage_to_current : 0x%X\n",
+ voltage_to_current.value);
+ DRM_DEBUG("set_field_value() ndac_ctrl : 0x%X\n",
+ ndac_ctrl.value);
+ DRM_DEBUG("set_field_value() pmos_ctrl : 0x%02X\n",
+ pmos_ctrl.value);
+ DRM_DEBUG("set_field_value() ptat_ndac_ctrl : 0x%02X\n",
+ ptat_ndac_ctrl.value);
+ DRM_DEBUG("set_field_value() charge_pump_gain : 0x%03X\n",
+ charge_pump_gain.value);
+
+ /* ---------------------------------------------------------------
+ * Describing Task phy_cfg_hdmi_pll0_0pt5736
+ *---------------------------------------------------------------*/
+
+ Afe_write(state, 0x0081, 0x30A0);
+ /* register CMN_PLL0_VCOCAL_INIT_TMR */
+ Afe_write(state, 0x0084, 0x0064);
+ /* register CMN_PLL0_VCOCAL_ITER_TMR */
+ Afe_write(state, 0x0085, 0x000A);
+ /* register PHY_HDP_CLK_CTL */
+ reg_val = Afe_read(state, 0xC009);
+ reg_val &= 0x00FF;
+ reg_val |= 0x1200;
+ Afe_write(state, 0xC009, reg_val);
+ /* register CMN_DIAG_PLL0_INCLK_CTRL */
+ reg_val = set_reg_value(cmnda_pll0_hs_sym_div_sel);
+ reg_val |= set_reg_value(cmnda_pll0_ip_div);
+ Afe_write(state, 0x01CA, reg_val);
+ /* register CMN_DIAG_PLL0_FBL_OVRD */
+ reg_val = set_reg_value(cmnda_pll0_fb_div_low);
+ reg_val |= (1 << 15);
+ Afe_write(state, 0x01C1, reg_val);
+ /* register PHY_PMA_CMN_CTRL1 */
+ reg_val = Afe_read(state, 0xC800);
+ reg_val &= 0xCFFF;
+ reg_val |= set_reg_value(cmn_ref_clk_dig_div);
+ Afe_write(state, 0xC800, reg_val);
+ /* register CMN_CDIAG_REFCLK_CTRL */
+ reg_val = set_reg_value(divider_scaler);
+ Afe_write(state, 0x0062, reg_val);
+ /* register CMN_DIAG_HSCLK_SEL */
+ reg_val = Afe_read(state, 0x01E0);
+ reg_val &= 0xFF00;
+ reg_val |= (cmnda_hs_clk_0_sel.value >> 1) << 0;
+ reg_val |= (cmnda_hs_clk_1_sel.value >> 1) << 4;
+ Afe_write(state, 0x01E0, reg_val);
+
+ /* register XCVR_DIAG_HSCLK_SEL */
+ for (i = 0; i < num_lanes; i++) {
+ reg_val = Afe_read(state, 0x40E1 | (i << 9));
+ reg_val &= 0xCFFF;
+ reg_val |= (cmnda_hs_clk_0_sel.value >> 1) << 12;
+ Afe_write(state, 0x40E1 | (i << 9), reg_val);
+ }
+
+ /* register TX_DIAG_TX_CTRL */
+ for (i = 0; i < num_lanes; i++) {
+ reg_val = Afe_read(state, 0x41E0 | (i << 9));
+ reg_val &= 0xFF3F;
+ reg_val |= (tx_subrate.value >> 1) << 6;
+ Afe_write(state, 0x41E0 | (i << 9), reg_val);
+ }
+
+ /* register CMN_PLLSM0_USER_DEF_CTRL */
+ reg_val = set_reg_value(vco_ring_select);
+ Afe_write(state, 0x002F, reg_val);
+ /* register CMN_DIAG_PLL0_OVRD */
+ Afe_write(state, 0x01C2, 0x0000);
+ /* register CMN_DIAG_PLL0_FBH_OVRD */
+ reg_val = set_reg_value(cmnda_pll0_fb_div_high);
+ reg_val |= (1 << 15);
+ Afe_write(state, 0x01C0, reg_val);
+ /* register CMN_DIAG_PLL0_V2I_TUNE */
+ reg_val = set_reg_value(voltage_to_current_coarse);
+ reg_val |= set_reg_value(voltage_to_current);
+ Afe_write(state, 0x01C5, reg_val);
+ /* register CMN_DIAG_PLL0_PTATIS_TUNE1 */
+ reg_val = set_reg_value(pmos_ctrl);
+ reg_val |= set_reg_value(ndac_ctrl);
+ Afe_write(state, 0x01C8, reg_val);
+ /* register CMN_DIAG_PLL0_PTATIS_TUNE2 */
+ reg_val = set_reg_value(ptat_ndac_ctrl);
+ Afe_write(state, 0x01C9, reg_val);
+ /* register CMN_DIAG_PLL0_CP_TUNE */
+ reg_val = set_reg_value(charge_pump_gain);
+ Afe_write(state, 0x01C6, reg_val);
+ /* register CMN_DIAG_PLL0_LF_PROG */
+ Afe_write(state, 0x01C7, 0x0008);
+
+ /* register XCVR_DIAG_PLLDRC_CTRL */
+ for (i = 0; i < num_lanes; i++) {
+ reg_val = Afe_read(state, 0x40E0 | (i << 9));
+ reg_val &= 0xBFFF;
+ Afe_write(state, 0x40E0 | (i << 9), reg_val);
+ }
+
+ /* register PHY_PMA_CMN_CTRL1 */
+ reg_val = Afe_read(state, 0xC800);
+ reg_val &= 0xFF8F;
+ reg_val |= 0x0030;
+ Afe_write(state, 0xC800, reg_val);
+
+ /*--------------------------------------------------------------------
+ *--------------------Back to task phy_cfg_hdp------------------------
+ *--------------------------------------------------------------------*/
+
+ if (phy_reset_workaround) {
+ /* register PHY_ISO_CMN_CTRL */
+ Afe_write(state, 0xC010, 0x0001); // Deassert PHY reset */
+ for (i = 0; i < num_lanes; i++) {
+ /* register TX_DIAG_ACYA */
+ Afe_write(state, 0x41FF | (i << 9), 0x0001);
+ }
+ /* register PHY_PMA_ISO_CMN_CTRL */
+ Afe_write(state, 0xC810, 0x0003);
+ for (i = 0; i < num_lanes; i++) {
+ /* register XCVR_PSM_RCTRL */
+ Afe_write(state, 0x4001 | (i << 9), 0xFEFC);
+ }
+ /* register PHY_PMA_ISO_CMN_CTRL */
+ Afe_write(state, 0xC810, 0x0013); /* Assert cmn_macro_pwr_en */
+
+ /* PHY_PMA_ISO_CMN_CTRL */
+ while (!(Afe_read(state, 0xC810) & (1 << 5))) ; /* wait for cmn_macro_pwr_en_ack */
+
+ /* PHY_PMA_CMN_CTRL1 */
+ while (!(Afe_read(state, 0xC800) & (1 << 0))) ; /* wait for cmn_ready */
+ } else {
+ for (i = 0; i < num_lanes; i++) {
+ Afe_write(state, 0x41FF | (i << 9), 0x0001);
+ /* register XCVR_PSM_RCTRL */
+ Afe_write(state, 0x4001 | (i << 9), 0xBEFC);
+ }
+ }
+ for (i = 0; i < num_lanes; i++) {
+ /* register TX_PSC_A0 */
+ Afe_write(state, 0x4100 | (i << 9), 0x6791);
+ /* register TX_PSC_A1 */
+ Afe_write(state, 0x4101 | (i << 9), 0x6790);
+ /* register TX_PSC_A2 */
+ Afe_write(state, 0x4102 | (i << 9), 0x0090);
+ /* register TX_PSC_A3 */
+ Afe_write(state, 0x4103 | (i << 9), 0x0090);
+ }
+
+ /* register PHY_HDP_MODE_CTL */
+ Afe_write(state, 0xC008, 0x0004);
+ return character_freq_khz;
+
+}
+
+#define __ARC_CONFIG__
+
+int hdmi_tx_kiran_power_configuration_seq(state_struct *state, int num_lanes)
+{
+ /* Configure the power state. */
+
+ /* PHY_DP_MODE_CTL */
+ while (!(Afe_read(state, 0xC008) & (1 << 6))) ;
+
+#ifdef __ARC_CONFIG__
+ imx_arc_power_up(state);
+ imx_arc_calibrate(state);
+ imx_arc_config(state);
+#endif
+
+ /* PHY_DP_MODE_CTL */
+ Afe_write(state, 0xC008, (((0x0F << num_lanes) & 0x0F) << 12) | 0x0001);
+
+ /* PHY_DP_MODE_CTL */
+ while (!(Afe_read(state, 0xC008) & (1 << 4))) ;
+ return 0;
+}
diff --git a/drivers/gpu/drm/imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.h b/drivers/gpu/drm/imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.h
new file mode 100644
index 000000000000..410076214f27
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_AFE_ss28fdsoi_kiran_hdmitx.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef API_AFE_SS28FDSOI_KIRAN_HDMITX_H_
+#define API_AFE_SS28FDSOI_KIRAN_HDMITX_H_
+
+#include "../../../../mxc/hdp/all.h"
+
+int phy_cfg_hdp_ss28fdsoi(state_struct *state, int num_lanes,
+ struct drm_display_mode *mode, int bpp, VIC_PXL_ENCODING_FORMAT format);
+int hdmi_tx_kiran_power_configuration_seq(state_struct *state, int num_lanes);
+
+#endif
diff --git a/drivers/gpu/drm/imx/hdp/API_AFE_t28hpc_hdmitx.c b/drivers/gpu/drm/imx/hdp/API_AFE_t28hpc_hdmitx.c
new file mode 100644
index 000000000000..3b11545dad84
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/API_AFE_t28hpc_hdmitx.c
@@ -0,0 +1,781 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_AFE_t28hpc_hdmitx.c
+ *
+ ******************************************************************************
+ */
+
+#include <drm/drmP.h>
+#include "imx-hdp.h"
+#include "API_AFE_t28hpc_hdmitx.h"
+#include "t28hpc_hdmitx_table.h"
+
+/* check pixel clock rate in
+ * Table 8. HDMI TX pixel clock */
+int pixel_clock_range_t28hpc(struct drm_display_mode *mode)
+{
+ int i, row, rate;
+
+ row = T28HPC_HDMITX_CLOCK_CONTROL_TABLE_ROWS_PIXEL_OUT;
+ for (i = 0; i < row; i++) {
+ rate = t28hpc_hdmitx_clock_control_table_pixel_out[i][T8_PIXEL_CLK_FREQ_KHZ];
+ if (rate == mode->clock)
+ return 1;
+ }
+ return 0;
+}
+
+int phy_cfg_hdp_t28hpc(state_struct *state,
+ int num_lanes,
+ struct drm_display_mode *mode,
+ int bpp,
+ VIC_PXL_ENCODING_FORMAT format,
+ bool pixel_clk_from_phy)
+{
+ const int phy_reset_workaround = 1;
+ u32 vco_freq_khz;
+ unsigned char k;
+ int row;
+ u32 feedback_factor;
+ u32 reg_val;
+ u32 pll_feedback_divider_total;
+ int pixel_freq_khz = mode->clock;
+ u32 character_clock_ratio_num = 1;
+ u32 character_clock_ratio_den = 1;
+ u32 character_freq_khz;
+ const u32 refclk_freq_khz = 27000;
+ clk_ratio_t clk_ratio = CLK_RATIO_1_1;
+
+ reg_field_t cmnda_pll0_hs_sym_div_sel;
+ reg_field_t cmnda_pll0_ip_div;
+ reg_field_t cmnda_pll0_fb_div_low;
+ reg_field_t cmnda_pll0_fb_div_high;
+ reg_field_t cmn_ref_clk_dig_div;
+ reg_field_t divider_scaler;
+ reg_field_t cmnda_hs_clk_0_sel;
+ reg_field_t cmnda_hs_clk_1_sel;
+ reg_field_t tx_subrate;
+ reg_field_t voltage_to_current_coarse;
+ reg_field_t voltage_to_current;
+ reg_field_t ndac_ctrl;
+ reg_field_t pmos_ctrl;
+ reg_field_t ptat_ndac_ctrl;
+ reg_field_t charge_pump_gain;
+ reg_field_t vco_ring_select;
+
+ reg_field_t cmnda_pll0_pxdiv_high;
+ reg_field_t cmnda_pll0_pxdiv_low;
+ reg_field_t coarse_code;
+ reg_field_t v2i_code;
+ reg_field_t vco_cal_code;
+
+ /* Set field position */
+ cmnda_pll0_hs_sym_div_sel.msb = 9;
+ cmnda_pll0_hs_sym_div_sel.lsb = 8;
+ cmnda_pll0_ip_div.msb = 7;
+ cmnda_pll0_ip_div.lsb = 0;
+ cmnda_pll0_fb_div_low.msb = 9;
+ cmnda_pll0_fb_div_low.lsb = 0;
+ cmnda_pll0_fb_div_high.msb = 9;
+ cmnda_pll0_fb_div_high.lsb = 0;
+ cmn_ref_clk_dig_div.msb = 13;
+ cmn_ref_clk_dig_div.lsb = 12;
+ divider_scaler.msb = 14;
+ divider_scaler.lsb = 12;
+ cmnda_hs_clk_0_sel.msb = 1;
+ cmnda_hs_clk_0_sel.lsb = 0;
+ cmnda_hs_clk_1_sel.msb = 1;
+ cmnda_hs_clk_1_sel.lsb = 0;
+ tx_subrate.msb = 2;
+ tx_subrate.lsb = 0;
+ voltage_to_current_coarse.msb = 2;
+ voltage_to_current_coarse.lsb = 0;
+ voltage_to_current.msb = 5;
+ voltage_to_current.lsb = 4;
+ ndac_ctrl.msb = 11;
+ ndac_ctrl.lsb = 8;
+ pmos_ctrl.msb = 7;
+ pmos_ctrl.lsb = 0;
+ ptat_ndac_ctrl.msb = 5;
+ ptat_ndac_ctrl.lsb = 0;
+ charge_pump_gain.msb = 8;
+ charge_pump_gain.lsb = 0;
+ vco_ring_select.msb = 12;
+ vco_ring_select.lsb = 12;
+ cmnda_pll0_pxdiv_high.msb = 9;
+ cmnda_pll0_pxdiv_high.lsb = 0;
+ cmnda_pll0_pxdiv_low.msb = 9;
+ cmnda_pll0_pxdiv_low.lsb = 0;
+ coarse_code.msb = 7;
+ coarse_code.lsb = 0;
+ v2i_code.msb = 3;
+ v2i_code.lsb = 0;
+ vco_cal_code.msb = 8;
+ vco_cal_code.lsb = 0;
+
+ switch (format) {
+ case YCBCR_4_2_2:
+ clk_ratio = CLK_RATIO_1_1;
+ character_clock_ratio_num = 1;
+ character_clock_ratio_den = 1;
+ break;
+ case YCBCR_4_2_0:
+ switch (bpp) {
+ case 8:
+ clk_ratio = CLK_RATIO_1_2;
+ character_clock_ratio_num = 1;
+ character_clock_ratio_den = 2;
+ break;
+ case 10:
+ clk_ratio = CLK_RATIO_5_8;
+ character_clock_ratio_num = 5;
+ character_clock_ratio_den = 8;
+ break;
+ case 12:
+ clk_ratio = CLK_RATIO_3_4;
+ character_clock_ratio_num = 3;
+ character_clock_ratio_den = 4;
+ break;
+ case 16:
+ clk_ratio = CLK_RATIO_1_1;
+ character_clock_ratio_num = 1;
+ character_clock_ratio_den = 1;
+ break;
+ default:
+ DRM_WARN("Invalid ColorDepth\n");
+ }
+ break;
+
+ default:
+ switch (bpp) { /* Assume RGB */
+ case 10:
+ clk_ratio = CLK_RATIO_5_4;
+ character_clock_ratio_num = 5;
+ character_clock_ratio_den = 4;
+ break;
+ case 12:
+ clk_ratio = CLK_RATIO_3_2;
+ character_clock_ratio_num = 3;
+ character_clock_ratio_den = 2;
+ break;
+ case 16:
+ clk_ratio = CLK_RATIO_2_1;
+ character_clock_ratio_num = 2;
+ character_clock_ratio_den = 1;
+ break;
+ default:
+ clk_ratio = CLK_RATIO_1_1;
+ character_clock_ratio_num = 1;
+ character_clock_ratio_den = 1;
+ }
+ }
+
+ /* Determine a relevant feedback factor as used in the
+ * t28hpc_hdmitx_clock_control_table table */
+ switch (clk_ratio) {
+ case CLK_RATIO_1_1:
+ feedback_factor = 1000;
+ break;
+ case CLK_RATIO_5_4:
+ feedback_factor = 1250;
+ break;
+ case CLK_RATIO_3_2:
+ feedback_factor = 1500;
+ break;
+ case CLK_RATIO_2_1:
+ feedback_factor = 2000;
+ break;
+ case CLK_RATIO_1_2:
+ feedback_factor = 500;
+ break;
+ case CLK_RATIO_5_8:
+ feedback_factor = 625;
+ break;
+ case CLK_RATIO_3_4:
+ feedback_factor = 750;
+ break;
+ }
+
+ character_freq_khz =
+ pixel_freq_khz * character_clock_ratio_num /
+ character_clock_ratio_den;
+ DRM_INFO
+ ("Pixel clock frequency: %d KHz, character clock frequency: %d, color depth is %0d-bit.\n",
+ pixel_freq_khz, character_freq_khz, bpp);
+
+ if (pixel_clk_from_phy == 0) {
+
+ /* Get right row from the t28hpc_hdmitx_clock_control_table_pixel_in table.
+ * Check if 'pixel_freq_mhz' falls inside
+ * the <PIXEL_CLK_FREQ_MHZ_MIN, PIXEL_CLK_FREQ_MHZ_MAX> range.
+ * Consider only the rows with FEEDBACK_FACTOR column matching feedback_factor. */
+ row =
+ get_table_row((const u32 *)&t28hpc_hdmitx_clock_control_table_pixel_in,
+ T28HPC_HDMITX_CLOCK_CONTROL_TABLE_ROWS_PIXEL_IN,
+ T28HPC_HDMITX_CLOCK_CONTROL_TABLE_COLS_PIXEL_IN,
+ pixel_freq_khz, T6_PIXEL_CLK_FREQ_KHZ_MIN,
+ T6_PIXEL_CLK_FREQ_KHZ_MAX, T6_FEEDBACK_FACTOR,
+ feedback_factor);
+
+ /* Check if row was found */
+ if (row == -1) {
+ DRM_WARN("Pixel clock frequency (%d KHz) not supported for this color depth (%0d-bit)\n",
+ pixel_freq_khz, bpp);
+ return 0;
+ }
+ DRM_INFO
+ ("Pixel clock frequency (%d KHz) is supported in this color depth (%0d-bit). Settings found in row %0d\n",
+ pixel_freq_khz, bpp, row);
+
+ /* Extract particular values from the
+ * t28hpc_hdmitx_clock_control_table_pixel_in table */
+ set_field_value(&cmnda_pll0_ip_div,
+ t28hpc_hdmitx_clock_control_table_pixel_in[row]
+ [T6_CMNDA_PLL0_IP_DIV]);
+ set_field_value(&cmn_ref_clk_dig_div,
+ t28hpc_hdmitx_clock_control_table_pixel_in[row]
+ [T6_CMN_REF_CLK_DIG_DIV]);
+ set_field_value(&divider_scaler,
+ t28hpc_hdmitx_clock_control_table_pixel_in[row]
+ [T6_REF_CLK_DIVIDER_SCALER]);
+ set_field_value(&cmnda_pll0_fb_div_low,
+ t28hpc_hdmitx_clock_control_table_pixel_in[row]
+ [T6_CMNDA_PLL0_FB_DIV_LOW]);
+ set_field_value(&cmnda_pll0_fb_div_high,
+ t28hpc_hdmitx_clock_control_table_pixel_in[row]
+ [T6_CMNDA_PLL0_FB_DIV_HIGH]);
+ set_field_value(&vco_ring_select,
+ t28hpc_hdmitx_clock_control_table_pixel_in[row]
+ [T6_VCO_RING_SELECT]);
+ set_field_value(&cmnda_hs_clk_0_sel,
+ t28hpc_hdmitx_clock_control_table_pixel_in[row]
+ [T6_CMNDA_HS_CLK_0_SEL]);
+ set_field_value(&cmnda_hs_clk_1_sel,
+ t28hpc_hdmitx_clock_control_table_pixel_in[row]
+ [T6_CMNDA_HS_CLK_1_SEL]);
+ set_field_value(&tx_subrate,
+ t28hpc_hdmitx_clock_control_table_pixel_in[row]
+ [T6_HSCLK_DIV_TX_SUB_RATE]);
+ set_field_value(&cmnda_pll0_hs_sym_div_sel,
+ t28hpc_hdmitx_clock_control_table_pixel_in[row]
+ [T6_CMNDA_PLL0_HS_SYM_DIV_SEL]);
+
+ /* Display parameters (informative message) */
+ DRM_DEBUG("set_field_value() cmnda_pll0_ip_div : 0x%02X\n",
+ cmnda_pll0_ip_div.value);
+ DRM_DEBUG("set_field_value() cmn_ref_clk_dig_div : 0x%X\n",
+ cmn_ref_clk_dig_div.value);
+ DRM_DEBUG("set_field_value() divider_scaler : 0x%X\n",
+ divider_scaler.value);
+ DRM_DEBUG("set_field_value() cmnda_pll0_fb_div_low : 0x%03X\n",
+ cmnda_pll0_fb_div_low.value);
+ DRM_DEBUG("set_field_value() cmnda_pll0_fb_div_high : 0x%03X\n",
+ cmnda_pll0_fb_div_high.value);
+ DRM_DEBUG("set_field_value() vco_ring_select : %0d\n",
+ vco_ring_select.value);
+ DRM_DEBUG("set_field_value() cmnda_hs_clk_0_sel : %0d\n",
+ cmnda_hs_clk_0_sel.value);
+ DRM_DEBUG("set_field_value() cmnda_hs_clk_1_sel : %0d\n",
+ cmnda_hs_clk_1_sel.value);
+ DRM_DEBUG("set_field_value() tx_subrate : %0d\n",
+ tx_subrate.value);
+ DRM_DEBUG("set_field_value() cmnda_pll0_hs_sym_div_sel: 0x%X\n",
+ cmnda_pll0_hs_sym_div_sel.value);
+
+ pll_feedback_divider_total =
+ cmnda_pll0_fb_div_low.value + cmnda_pll0_fb_div_high.value + 4;
+ vco_freq_khz =
+ pixel_freq_khz * pll_feedback_divider_total /
+ cmnda_pll0_ip_div.value;
+ DRM_INFO("VCO frequency is %d\n", vco_freq_khz);
+
+ /* Get right row from the t28hpc_hdmitx_pll_tuning_table_pixel_in table.
+ * Check if 'vco_freq_khz' falls inside the
+ * <PLL_VCO_FREQ_KHZ_MIN, PLL_VCO_FREQ_KHZ_MAX> range.
+ * Consider only the rows with PLL_FEEDBACK_DIV_TOTAL
+ * column matching pll_feedback_divider_total. */
+ row =
+ get_table_row((const u32 *)&t28hpc_hdmitx_pll_tuning_table_pixel_in,
+ T28HPC_HDMITX_PLL_TUNING_TABLE_ROWS_PIXEL_IN,
+ T28HPC_HDMITX_PLL_TUNING_TABLE_COLS_PIXEL_IN,
+ vco_freq_khz, T7_PLL_VCO_FREQ_KHZ_MIN,
+ T7_PLL_VCO_FREQ_KHZ_MAX,
+ T7_PLL_FEEDBACK_DIV_TOTAL,
+ pll_feedback_divider_total);
+
+ if (row == -1) {
+ DRM_WARN("VCO frequency (%d KHz) not supported\n",
+ vco_freq_khz);
+ return 0;
+ }
+ DRM_INFO ("VCO frequency (%d KHz) is supported. Settings found in row %0d\n",
+ vco_freq_khz, row);
+
+ /* Extract particular values from
+ * the t28hpc_hdmitx_pll_tuning_table_pixel_in table */
+ set_field_value(&voltage_to_current_coarse,
+ t28hpc_hdmitx_pll_tuning_table_pixel_in[row]
+ [T7_VOLTAGE_TO_CURRENT_COARSE]);
+ set_field_value(&voltage_to_current,
+ t28hpc_hdmitx_pll_tuning_table_pixel_in[row]
+ [T7_VOLTAGE_TO_CURRENT]);
+ set_field_value(&ndac_ctrl,
+ t28hpc_hdmitx_pll_tuning_table_pixel_in[row]
+ [T7_NDAC_CTRL]);
+ set_field_value(&pmos_ctrl,
+ t28hpc_hdmitx_pll_tuning_table_pixel_in[row]
+ [T7_PMOS_CTRL]);
+ set_field_value(&ptat_ndac_ctrl,
+ t28hpc_hdmitx_pll_tuning_table_pixel_in[row]
+ [T7_PTAT_NDAC_CTRL]);
+ set_field_value(&charge_pump_gain,
+ t28hpc_hdmitx_pll_tuning_table_pixel_in[row]
+ [T7_CHARGE_PUMP_GAIN]);
+
+ /* Display parameters (informative message) */
+ DRM_DEBUG("set_field_value() voltage_to_current_coarse : 0x%X\n",
+ voltage_to_current_coarse.value);
+ DRM_DEBUG("set_field_value() voltage_to_current : 0x%X\n",
+ voltage_to_current.value);
+ DRM_DEBUG("set_field_value() ndac_ctrl : 0x%X\n",
+ ndac_ctrl.value);
+ DRM_DEBUG("set_field_value() pmos_ctrl : 0x%02X\n",
+ pmos_ctrl.value);
+ DRM_DEBUG("set_field_value() ptat_ndac_ctrl : 0x%02X\n",
+ ptat_ndac_ctrl.value);
+ DRM_DEBUG("set_field_value() charge_pump_gain : 0x%03X\n",
+ charge_pump_gain.value);
+
+ } else {
+ /* pixel_clk_from_phy == 1 */
+
+ /* Get right row from the t28hpc_hdmitx_clock_control_table_pixel_out table.
+ * Check if 'pixel_freq_khz' value matches the PIXEL_CLK_FREQ_MHZ column.
+ * Consider only the rows with FEEDBACK_FACTOR column matching feedback_factor. */
+ row =
+ get_table_row((const u32 *)&t28hpc_hdmitx_clock_control_table_pixel_out,
+ T28HPC_HDMITX_CLOCK_CONTROL_TABLE_ROWS_PIXEL_OUT,
+ T28HPC_HDMITX_CLOCK_CONTROL_TABLE_COLS_PIXEL_OUT,
+ pixel_freq_khz, T8_PIXEL_CLK_FREQ_KHZ,
+ T8_PIXEL_CLK_FREQ_KHZ, T8_FEEDBACK_FACTOR,
+ feedback_factor);
+
+ /* Check if row was found */
+ if (row == -1) {
+ DRM_WARN("Pixel clock frequency (%d KHz) not supported for this color depth (%0d-bit)\n",
+ pixel_freq_khz, bpp);
+ return 0;
+ }
+ DRM_INFO
+ ("Pixel clock frequency (%d KHz) is supported in this color depth (%0d-bit). Settings found in row %0d\n",
+ pixel_freq_khz, bpp, row);
+
+ /* Extract particular values from
+ * the t28hpc_hdmitx_clock_control_table_pixel_out table */
+ set_field_value(&cmnda_pll0_ip_div,
+ t28hpc_hdmitx_clock_control_table_pixel_out[row]
+ [T8_CMNDA_PLL0_IP_DIV]);
+ set_field_value(&cmn_ref_clk_dig_div,
+ t28hpc_hdmitx_clock_control_table_pixel_out[row]
+ [T8_CMN_REF_CLK_DIG_DIV]);
+ set_field_value(&divider_scaler,
+ t28hpc_hdmitx_clock_control_table_pixel_out[row]
+ [T8_REF_CLK_DIVIDER_SCALER]);
+ set_field_value(&cmnda_pll0_fb_div_low,
+ t28hpc_hdmitx_clock_control_table_pixel_out[row]
+ [T8_CMNDA_PLL0_FB_DIV_LOW]);
+ set_field_value(&cmnda_pll0_fb_div_high,
+ t28hpc_hdmitx_clock_control_table_pixel_out[row]
+ [T8_CMNDA_PLL0_FB_DIV_HIGH]);
+ set_field_value(&cmnda_pll0_pxdiv_low,
+ t28hpc_hdmitx_clock_control_table_pixel_out[row]
+ [T8_CMNDA_PLL0_PXDIV_LOW]);
+ set_field_value(&cmnda_pll0_pxdiv_high,
+ t28hpc_hdmitx_clock_control_table_pixel_out[row]
+ [T8_CMNDA_PLL0_PXDIV_HIGH]);
+ set_field_value(&vco_ring_select,
+ t28hpc_hdmitx_clock_control_table_pixel_out[row]
+ [T8_VCO_RING_SELECT]);
+ set_field_value(&cmnda_hs_clk_0_sel,
+ t28hpc_hdmitx_clock_control_table_pixel_out[row]
+ [T8_CMNDA_HS_CLK_0_SEL]);
+ set_field_value(&cmnda_hs_clk_1_sel,
+ t28hpc_hdmitx_clock_control_table_pixel_out[row]
+ [T8_CMNDA_HS_CLK_1_SEL]);
+ set_field_value(&tx_subrate,
+ t28hpc_hdmitx_clock_control_table_pixel_out[row]
+ [T8_HSCLK_DIV_TX_SUB_RATE]);
+ set_field_value(&cmnda_pll0_hs_sym_div_sel,
+ t28hpc_hdmitx_clock_control_table_pixel_out[row]
+ [T8_CMNDA_PLL0_HS_SYM_DIV_SEL]);
+
+ /* Display parameters (informative message) */
+ DRM_DEBUG("set_field_value() cmnda_pll0_ip_div : 0x%02X\n",
+ cmnda_pll0_ip_div.value);
+ DRM_DEBUG("set_field_value() cmn_ref_clk_dig_div : 0x%X\n",
+ cmn_ref_clk_dig_div.value);
+ DRM_DEBUG("set_field_value() divider_scaler : 0x%X\n",
+ divider_scaler.value);
+ DRM_DEBUG("set_field_value() cmnda_pll0_fb_div_low : 0x%03X\n",
+ cmnda_pll0_fb_div_low.value);
+ DRM_DEBUG("set_field_value() cmnda_pll0_fb_div_high : 0x%03X\n",
+ cmnda_pll0_fb_div_high.value);
+ DRM_DEBUG("set_field_value() cmnda_pll0_pxdiv_low : 0x%03X\n",
+ cmnda_pll0_pxdiv_low.value);
+ DRM_DEBUG("set_field_value() cmnda_pll0_pxdiv_high : 0x%03X\n",
+ cmnda_pll0_pxdiv_high.value);
+ DRM_DEBUG("set_field_value() vco_ring_select : %0d\n",
+ vco_ring_select.value);
+ DRM_DEBUG("set_field_value() cmnda_hs_clk_0_sel : %0d\n",
+ cmnda_hs_clk_0_sel.value);
+ DRM_DEBUG("set_field_value() cmnda_hs_clk_1_sel : %0d\n",
+ cmnda_hs_clk_1_sel.value);
+ DRM_DEBUG("set_field_value() tx_subrate : %0d\n",
+ tx_subrate.value);
+ DRM_DEBUG("set_field_value() cmnda_pll0_hs_sym_div_sel: 0x%X\n",
+ cmnda_pll0_hs_sym_div_sel.value);
+
+ pll_feedback_divider_total =
+ cmnda_pll0_fb_div_low.value + cmnda_pll0_fb_div_high.value + 4;
+ vco_freq_khz =
+ refclk_freq_khz * pll_feedback_divider_total / cmnda_pll0_ip_div.value;
+
+ DRM_INFO("VCO frequency is %d\n", vco_freq_khz);
+
+ /* Get right row from the t28hpc_hdmitx_pll_tuning_table table_pixel_out.
+ * Check if 'vco_freq_khz' falls inside
+ * the <PLL_VCO_FREQ_KH_MIN, PLL_VCO_FREQ_KHZ_MAX> range.
+ * Consider only the rows with PLL_FEEDBACK_DIV_TOTAL
+ * column matching pll_feedback_divider_total. */
+ row =
+ get_table_row((const u32 *)&t28hpc_hdmitx_pll_tuning_table_pixel_out,
+ T28HPC_HDMITX_PLL_TUNING_TABLE_ROWS_PIXEL_OUT,
+ T28HPC_HDMITX_PLL_TUNING_TABLE_COLS_PIXEL_OUT,
+ vco_freq_khz, T9_PLL_VCO_FREQ_KHZ_MIN,
+ T9_PLL_VCO_FREQ_KHZ_MAX,
+ T9_PLL_FEEDBACK_DIV_TOTAL,
+ pll_feedback_divider_total);
+
+ if (row == -1) {
+ DRM_WARN("VCO frequency (%d KHz) not supported\n",
+ vco_freq_khz);
+ return 0;
+ }
+ DRM_INFO("VCO frequency (%d KHz) is supported. Settings found in row %0d\n",
+ vco_freq_khz, row);
+
+ /* Extract particular values from
+ * the t28hpc_hdmitx_pll_tuning_table_pixel_out table. */
+ set_field_value(&voltage_to_current_coarse,
+ t28hpc_hdmitx_pll_tuning_table_pixel_out[row]
+ [T9_VOLTAGE_TO_CURRENT_COARSE]);
+ set_field_value(&voltage_to_current,
+ t28hpc_hdmitx_pll_tuning_table_pixel_out[row]
+ [T9_VOLTAGE_TO_CURRENT]);
+ set_field_value(&ndac_ctrl,
+ t28hpc_hdmitx_pll_tuning_table_pixel_out[row]
+ [T9_NDAC_CTRL]);
+ set_field_value(&pmos_ctrl,
+ t28hpc_hdmitx_pll_tuning_table_pixel_out[row]
+ [T9_PMOS_CTRL]);
+ set_field_value(&ptat_ndac_ctrl,
+ t28hpc_hdmitx_pll_tuning_table_pixel_out[row]
+ [T9_PTAT_NDAC_CTRL]);
+ set_field_value(&charge_pump_gain,
+ t28hpc_hdmitx_pll_tuning_table_pixel_out[row]
+ [T9_CHARGE_PUMP_GAIN]);
+ set_field_value(&coarse_code,
+ t28hpc_hdmitx_pll_tuning_table_pixel_out[row]
+ [T9_COARSE_CODE]);
+ set_field_value(&v2i_code,
+ t28hpc_hdmitx_pll_tuning_table_pixel_out[row]
+ [T9_V2I_CODE]);
+ set_field_value(&vco_cal_code,
+ t28hpc_hdmitx_pll_tuning_table_pixel_out[row]
+ [T9_VCO_CAL_CODE]);
+
+ /* Display parameters (informative message) */
+ DRM_DEBUG("set_field_value() voltage_to_current_coarse : 0x%X\n",
+ voltage_to_current_coarse.value);
+ DRM_DEBUG("set_field_value() voltage_to_current : 0x%X\n",
+ voltage_to_current.value);
+ DRM_DEBUG("set_field_value() ndac_ctrl : 0x%X\n",
+ ndac_ctrl.value);
+ DRM_DEBUG("set_field_value() pmos_ctrl : 0x%02X\n",
+ pmos_ctrl.value);
+ DRM_DEBUG("set_field_value() ptat_ndac_ctrl : 0x%02X\n",
+ ptat_ndac_ctrl.value);
+ DRM_DEBUG("set_field_value() charge_pump_gain : 0x%03X\n",
+ charge_pump_gain.value);
+ DRM_DEBUG("set_field_value() coarse_code : %0d\n",
+ coarse_code.value);
+ DRM_DEBUG("set_field_value() v2i_code : %0d\n",
+ v2i_code.value);
+ DRM_DEBUG("set_field_value() vco_cal_code : %0d\n",
+ vco_cal_code.value);
+ }
+
+ if (phy_reset_workaround) {
+ /* register PHY_PMA_ISOLATION_CTRL */
+ /* enable PHY isolation mode only for CMN */
+ Afe_write(state, 0xC81F, 0xD000);
+ /* register PHY_PMA_ISO_PLL_CTRL1 */
+ reg_val = Afe_read(state, 0xC812);
+ reg_val &= 0xFF00;
+ reg_val |= 0x0012;
+ /* set cmn_pll0_clk_datart1_div/cmn_pll0_clk_datart0_div dividers */
+ Afe_write(state, 0xC812, reg_val);
+ /* register PHY_ISO_CMN_CTRL */
+ /* assert PHY reset from isolation register */
+ Afe_write(state, 0xC010, 0x0000);
+ /* register PHY_PMA_ISO_CMN_CTRL */
+ /* assert PMA CMN reset */
+ Afe_write(state, 0xC810, 0x0000);
+ /* register XCVR_DIAG_BIDI_CTRL */
+ for (k = 0; k < num_lanes; k++) {
+ Afe_write(state, 0x40E8 | (k << 9), 0x00FF);
+ }
+ }
+ /* Describing Task phy_cfg_hdp */
+
+ /* register PHY_PMA_CMN_CTRL1 */
+ reg_val = Afe_read(state, 0xC800);
+ reg_val &= 0xFFF7;
+ reg_val |= 0x0008;
+ Afe_write(state, 0xC800, reg_val);
+
+ /* register CMN_DIAG_PLL0_TEST_MODE */
+ Afe_write(state, 0x01C4, 0x0020);
+ /* register CMN_PSM_CLK_CTRL */
+ Afe_write(state, 0x0061, 0x0016);
+
+ /* Describing Task phy_cfg_hdmi_pll0_0pt5736 */
+
+ /* register CMN_PLL0_VCOCAL_INIT_TMR */
+ Afe_write(state, 0x0084, 0x0064);
+ /* register CMN_PLL0_VCOCAL_ITER_TMR */
+ Afe_write(state, 0x0085, 0x000A);
+ /*register PHY_HDP_CLK_CTL */
+ reg_val = Afe_read(state, 0xC009);
+ reg_val &= 0x00FF;
+ reg_val |= 0x1200;
+ Afe_write(state, 0xC009, reg_val);
+ /* register CMN_DIAG_PLL0_INCLK_CTRL */
+ reg_val = set_reg_value(cmnda_pll0_hs_sym_div_sel);
+ reg_val |= set_reg_value(cmnda_pll0_ip_div);
+ Afe_write(state, 0x01CA, reg_val);
+ /* register CMN_DIAG_PLL0_FBH_OVRD */
+ reg_val = set_reg_value(cmnda_pll0_fb_div_high);
+ reg_val |= (1 << 15);
+ Afe_write(state, 0x01C0, reg_val);
+ /* register CMN_DIAG_PLL0_FBL_OVRD */
+ reg_val = set_reg_value(cmnda_pll0_fb_div_low);
+ reg_val |= (1 << 15);
+ Afe_write(state, 0x01C1, reg_val);
+ /*register PHY_PMA_CMN_CTRL1 */
+ reg_val = Afe_read(state, 0xC800);
+ reg_val &= 0xCFFF;
+ reg_val |= set_reg_value(cmn_ref_clk_dig_div);
+ Afe_write(state, 0xC800, reg_val);
+ /* register CMN_CDIAG_REFCLK_CTRL */
+ reg_val = Afe_read(state, 0x0062);
+ reg_val &= 0x8FFF;
+ reg_val |= set_reg_value(divider_scaler);
+ reg_val |= 0x00C0;
+ Afe_write(state, 0x0062, reg_val);
+ /*register CMN_DIAG_HSCLK_SEL */
+ reg_val = Afe_read(state, 0x01E0);
+ reg_val &= 0xFF00;
+ reg_val |= (cmnda_hs_clk_0_sel.value >> 1) << 0;
+ reg_val |= (cmnda_hs_clk_1_sel.value >> 1) << 4;
+ Afe_write(state, 0x01E0, reg_val);
+ /*register XCVR_DIAG_HSCLK_SEL */
+ for (k = 0; k < num_lanes; k++) {
+ reg_val = Afe_read(state, 0x40E1 | (k << 9));
+ reg_val &= 0xCFFF;
+ reg_val |= (cmnda_hs_clk_0_sel.value >> 1) << 12;
+ Afe_write(state, 0x40E1 | (k << 9), reg_val);
+ }
+ /* register TX_DIAG_TX_CTRL */
+ for (k = 0; k < num_lanes; k++) {
+ reg_val = Afe_read(state, 0x41E0 | (k << 9));
+ reg_val &= 0xFF3F;
+ reg_val |= (tx_subrate.value >> 1) << 6;
+ Afe_write(state, 0x41E0 | (k << 9), reg_val);
+ }
+ /* register CMN_PLLSM0_USER_DEF_CTRL */
+ reg_val = set_reg_value(vco_ring_select);
+ Afe_write(state, 0x002F, reg_val);
+ /* register CMN_DIAG_PLL0_OVRD */
+ Afe_write(state, 0x01C2, 0x0000);
+ /* register CMN_DIAG_PLL0_V2I_TUNE */
+ reg_val = set_reg_value(voltage_to_current_coarse);
+ reg_val |= set_reg_value(voltage_to_current);
+ Afe_write(state, 0x01C5, reg_val);
+ /* register CMN_DIAG_PLL0_PTATIS_TUNE1 */
+ reg_val = set_reg_value(pmos_ctrl);
+ reg_val |= set_reg_value(ndac_ctrl);
+ Afe_write(state, 0x01C8, reg_val);
+ /* register CMN_DIAG_PLL0_PTATIS_TUNE2 */
+ reg_val = set_reg_value(ptat_ndac_ctrl);
+ Afe_write(state, 0x01C9, reg_val);
+ /* register CMN_DIAG_PLL0_CP_TUNE */
+ reg_val = set_reg_value(charge_pump_gain);
+ Afe_write(state, 0x01C6, reg_val);
+ /* register CMN_DIAG_PLL0_LF_PROG */
+ Afe_write(state, 0x01C7, 0x0008);
+ /* register XCVR_DIAG_PLLDRC_CTRL */
+ for (k = 0; k < num_lanes; k++) {
+ reg_val = Afe_read(state, 0x40E0 | (k << 9));
+ reg_val &= 0xBFFF;
+ Afe_write(state, 0x40E0 | (k << 9), reg_val);
+ }
+ if (pixel_clk_from_phy == 1) {
+ /* register CMN_DIAG_PLL0_PXL_DIVL */
+ reg_val = set_reg_value(cmnda_pll0_pxdiv_low);
+ Afe_write(state, 0x01CC, reg_val);
+ /* register CMN_DIAG_PLL0_PXL_DIVH */
+ reg_val = set_reg_value(cmnda_pll0_pxdiv_high);
+ reg_val |= (1 << 15);
+ Afe_write(state, 0x01CB, reg_val);
+
+ /* register CMN_PLL0_VCOCAL_START */
+ reg_val = Afe_read(state, 0x0081);
+ reg_val &= 0xFE00;
+ reg_val |= set_reg_value(vco_cal_code);
+ Afe_write(state, 0x0081, reg_val);
+ }
+
+ /* Back to task phy_cfg_hdp */
+
+ /* register PHY_PMA_CMN_CTRL1 */
+ reg_val = Afe_read(state, 0xC800);
+ reg_val &= 0xFF8F;
+ /* for single ended reference clock
+ * on the cmn_ref_clk_int pin: PHY_PMA_CMN_CTRL1[6:4]=3'b011 */
+ /* for differential clock on the refclk_p and
+ * refclk_m off chip pins: PHY_PMA_CMN_CTRL1[6:4]=3'b000 */
+ reg_val |= 0x0000;
+ Afe_write(state, 0xC800, reg_val);
+
+ /*register CMN_DIAG_ACYA */
+ /* for differential clock on the refclk_p and
+ * refclk_m off chip pins: CMN_DIAG_ACYA[8]=1'b1 */
+ Afe_write(state, 0x01FF, 0x0100);
+
+ if (phy_reset_workaround) {
+ /* register PHY_ISO_CMN_CTRL */
+ /* Deassert PHY reset */
+ Afe_write(state, 0xC010, 0x0001);
+ /* register PHY_PMA_ISO_CMN_CTRL */
+ Afe_write(state, 0xC810, 0x0003);
+ for (k = 0; k < num_lanes; k++) {
+ /* register XCVR_PSM_RCTRL */
+ Afe_write(state, 0x4001 | (k << 9), 0xFEFC);
+ }
+ /* register PHY_PMA_ISO_CMN_CTRL */
+ /* Assert cmn_macro_pwr_en */
+ Afe_write(state, 0xC810, 0x0013);
+
+ /* PHY_PMA_ISO_CMN_CTRL */
+ /* wait for cmn_macro_pwr_en_ack */
+ while (!(Afe_read(state, 0xC810) & (1 << 5)));
+
+ /* PHY_PMA_CMN_CTRL1 */
+ /* wait for cmn_ready */
+ while (!(Afe_read(state, 0xC800) & (1 << 0)));
+ } else {
+ for (k = 0; k < num_lanes; k++)
+ /* register XCVR_PSM_RCTRL */
+ Afe_write(state, 0x4001 | (k << 9), 0xBEFC);
+ }
+ for (k = 0; k < num_lanes; k++) {
+ /* register TX_PSC_A0 */
+ Afe_write(state, 0x4100 | (k << 9), 0x6791);
+ /* register TX_PSC_A1 */
+ Afe_write(state, 0x4101 | (k << 9), 0x6790);
+ /* register TX_PSC_A2 */
+ Afe_write(state, 0x4102 | (k << 9), 0x0090);
+ /* register TX_PSC_A3 */
+ Afe_write(state, 0x4103 | (k << 9), 0x0090);
+ /* register RX_PSC_CAL */
+ reg_val = Afe_read(state, 0x8006 | (k << 9));
+ reg_val &= 0xFFBB;
+ Afe_write(state, 0x8006 | (k << 9), reg_val);
+ /* register RX_PSC_A0 */
+ reg_val = Afe_read(state, 0x8000 | (k << 9));
+ reg_val &= 0xFFBB;
+ Afe_write(state, 0x8000 | (k << 9), reg_val);
+ }
+
+ /* register PHY_HDP_MODE_CTL */
+ Afe_write(state, 0xC008, 0x0004);
+
+ return character_freq_khz;
+}
+
+int hdmi_tx_t28hpc_power_config_seq(state_struct *state, int num_lanes)
+{
+ unsigned char k;
+
+ /* Configure the power state.
+ * register TX_DIAG_ACYA */
+ for (k = 0; k < num_lanes; k++) {
+ /* register XCVR_PSM_CAL_TMR */
+ Afe_write(state, 0x41FF | (k << 9), 0x0001);
+ }
+
+ /* register PHY_DP_MODE_CTL */
+ while (!(Afe_read(state, 0xC008) & (1 << 6)));
+
+ imx_arc_power_up(state);
+ imx_arc_calibrate(state);
+ imx_arc_config(state);
+
+ /* PHY_DP_MODE_CTL */
+ Afe_write(state, 0xC008, (((0x0F << num_lanes) & 0x0F) << 12) | 0x0101);
+
+ /* PHY_DP_MODE_CTL */
+ while (!(Afe_read(state, 0xC008) & (1 << 4)));
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/imx/hdp/API_AFE_t28hpc_hdmitx.h b/drivers/gpu/drm/imx/hdp/API_AFE_t28hpc_hdmitx.h
new file mode 100644
index 000000000000..9475fab164c2
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/API_AFE_t28hpc_hdmitx.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_AFE_t28hpc_hdmitx.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef API_AFE_T28HPC_HDMITX_H_
+#define API_AFE_T28HPC_HDMITX_H_
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/io.h>
+
+#include "../../../../mxc/hdp/all.h"
+
+int phy_cfg_hdp_t28hpc(state_struct *state, int num_lanes, struct drm_display_mode *mode, int bpp,
+ VIC_PXL_ENCODING_FORMAT format, bool pixel_clk_from_phy);
+int hdmi_tx_t28hpc_power_config_seq(state_struct *state, int num_lanes);
+
+#endif
diff --git a/drivers/gpu/drm/imx/hdp/Kconfig b/drivers/gpu/drm/imx/hdp/Kconfig
new file mode 100644
index 000000000000..f4ee5a9029f8
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/Kconfig
@@ -0,0 +1,18 @@
+config DRM_IMX_HDP
+ tristate "IMX8 HD Display Controller"
+ select DRM_IMX
+ select MX8_HDP
+ select DRM_KMS_HELPER
+ select VIDEOMODE_HELPERS
+ select DRM_GEM_CMA_HELPER
+ select DRM_KMS_CMA_HELPER
+ select DRM_PANEL
+ help
+ Choose this if you want to use DP/HDMI on i.MX8.
+
+config IMX_HDP_CEC
+ bool "Enable IMX HDP CEC support"
+ depends on DRM_IMX_HDP && MEDIA_CEC
+ ---help---
+ When selected the imx hdmi will support the optional
+ HDMI CEC feature.
diff --git a/drivers/gpu/drm/imx/hdp/Makefile b/drivers/gpu/drm/imx/hdp/Makefile
new file mode 100644
index 000000000000..d0f8ab8c3fa2
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/Makefile
@@ -0,0 +1,9 @@
+obj-$(CONFIG_DRM_IMX_HDP) += imx-hdp.o \
+ imx-dp.o imx-hdmi.o imx-arc.o\
+ API_AFE_ss28fdsoi_kiran_hdmitx.o \
+ API_AFE_t28hpc_hdmitx.o \
+ ss28fdsoi_hdmitx_table.o \
+ t28hpc_hdmitx_table.o \
+ API_AFE_mcu1_dp.o \
+ API_AFE_mcu2_dp.o \
+ imx-hdp-audio.o
diff --git a/drivers/gpu/drm/imx/hdp/hdmitx_firmware.h b/drivers/gpu/drm/imx/hdp/hdmitx_firmware.h
new file mode 100644
index 000000000000..e62f9523de00
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/hdmitx_firmware.h
@@ -0,0 +1,77 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated from dram0.data and iram0.data firmware images
+ * Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * hdmitx_firmware.c
+ *
+ ******************************************************************************
+ */
+#include <linux/io.h>
+
+static u32 const hdmitx_iram0[] = {
+ 0x00000000,
+};
+
+static u32 const hdmitx_dram0[] = {
+ 0x00000000,
+};
+
+u32 const *hdmitx_iram0_get_ptr(void)
+{
+ return (u32 const *)hdmitx_iram0;
+}
+
+u32 const *hdmitx_dram0_get_ptr(void)
+{
+ return (u32 const *)hdmitx_dram0;
+}
+
+size_t hdmitx_iram0_get_size(void)
+{
+ return sizeof(hdmitx_iram0);
+}
+
+size_t hdmitx_dram0_get_size(void)
+{
+ return sizeof(hdmitx_dram0);
+}
diff --git a/drivers/gpu/drm/imx/hdp/imx-arc.c b/drivers/gpu/drm/imx/hdp/imx-arc.c
new file mode 100644
index 000000000000..be94437598cb
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/imx-arc.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "imx-hdp.h"
+
+void imx_arc_power_up(state_struct *state)
+{
+ DRM_DEBUG("arc_power_up()\n");
+
+ /* register CMN_RXCAL_OVRD */
+ Afe_write(state, 0x5025, 0x0001);
+}
+
+void imx_arc_calibrate(state_struct *state)
+{
+ u16 txpu_calib_code;
+ u16 txpd_calib_code;
+ u16 txpu_adj_calib_code;
+ u16 txpd_adj_calib_code;
+ u16 prev_calib_code;
+ u16 new_calib_code;
+ u16 rdata;
+
+ DRM_DEBUG("aux_cal_cfg() ARC programming\n");
+ /* register TX_DIG_CTRL_REG_2 */
+ prev_calib_code = Afe_read(state, 0x5024);
+ /* register CMN_TXPUCAL_CTRL */
+ txpu_calib_code = Afe_read(state, 0x00E0);
+ /* register CMN_TXPDCAL_CTRL */
+ txpd_calib_code = Afe_read(state, 0x00F0);
+ /* register CMN_TXPU_ADJ_CTRL */
+ txpu_adj_calib_code = Afe_read(state, 0x0108);
+ /* register CMN_TXPD_ADJ_CTRL */
+ txpd_adj_calib_code = Afe_read(state, 0x010c);
+
+ new_calib_code = ((txpu_calib_code + txpd_calib_code) / 2)
+ + txpu_adj_calib_code + txpd_adj_calib_code;
+
+ if (new_calib_code != prev_calib_code) {
+ /* register TX_ANA_CTRL_REG_1 */
+ rdata = Afe_read(state, 0x5020);
+ rdata &= 0xDFFF;
+ /* register TX_ANA_CTRL_REG_1 */
+ Afe_write(state, 0x5020, rdata);
+ /* register TX_DIG_CTRL_REG_2 */
+ Afe_write(state, 0x5024, new_calib_code);
+ mdelay(10);
+ rdata |= 0x2000;
+ /* register TX_ANA_CTRL_REG_1 */
+ Afe_write(state, 0x5020, rdata);
+ udelay(150);
+ }
+}
+
+void imx_arc_config(state_struct *state)
+{
+ DRM_DEBUG("arc_config() ARC programming\n");
+
+ /* register TX_ANA_CTRL_REG_2 */
+ Afe_write(state, 0x5021, 0x0100);
+ udelay(100);
+ /* register TX_ANA_CTRL_REG_2 */
+ Afe_write(state, 0x5021, 0x0300);
+ udelay(100);
+ /* register TX_ANA_CTRL_REG_3 */
+ Afe_write(state, 0x5026, 0x0000);
+ udelay(100);
+ /* register TX_ANA_CTRL_REG_1 */
+ Afe_write(state, 0x5020, 0x2008);
+ udelay(100);
+ /* register TX_ANA_CTRL_REG_1 */
+ Afe_write(state, 0x5020, 0x2018);
+ udelay(100);
+ /* register TX_ANA_CTRL_REG_1 */
+ Afe_write(state, 0x5020, 0x2098);
+ /* register TX_ANA_CTRL_REG_2 */
+ Afe_write(state, 0x5021, 0x030C);
+ /* register TX_ANA_CTRL_REG_5 */
+ Afe_write(state, 0x5029, 0x0010);
+ udelay(100);
+ /* register TX_ANA_CTRL_REG_4 */
+ Afe_write(state, 0x5027, 0x4001);
+ mdelay(5);
+ /* register TX_ANA_CTRL_REG_1 */
+ Afe_write(state, 0x5020, 0x2198);
+ mdelay(5);
+ /* register TX_ANA_CTRL_REG_2 */
+ Afe_write(state, 0x5021, 0x030D);
+ udelay(100);
+ Afe_write(state, 0x5021, 0x030F);
+}
+
diff --git a/drivers/gpu/drm/imx/hdp/imx-dp.c b/drivers/gpu/drm/imx/hdp/imx-dp.c
new file mode 100644
index 000000000000..276bd581b2e3
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/imx-dp.c
@@ -0,0 +1,511 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#ifdef DEBUG_FW_LOAD
+#include "mhdp_firmware.h"
+#endif
+#include "imx-hdp.h"
+#include "imx-hdmi.h"
+#include "imx-dp.h"
+
+#ifdef DEBUG_FW_LOAD
+void dp_fw_load(state_struct *state)
+{
+ DRM_INFO("loading hdmi firmware\n");
+ CDN_API_LoadFirmware(state,
+ (u8 *)mhdp_iram0_get_ptr(),
+ mhdp_iram0_get_size(),
+ (u8 *)mhdp_dram0_get_ptr(),
+ mhdp_dram0_get_size());
+}
+#endif
+int dp_fw_init(state_struct *state)
+{
+ u8 echo_msg[] = "echo test";
+ u8 echo_resp[sizeof(echo_msg) + 1];
+ struct imx_hdp *hdp = state_to_imx_hdp(state);
+ u32 core_rate;
+ int ret;
+ u8 resp;
+
+ core_rate = clk_get_rate(hdp->clks.clk_core);
+
+ /* configure the clock */
+ CDN_API_SetClock(state, core_rate/1000000);
+ pr_info("CDN_API_SetClock completed\n");
+
+ cdn_apb_write(state, APB_CTRL << 2, 0);
+ DRM_INFO("Started firmware!\n");
+
+ ret = CDN_API_CheckAlive_blocking(state);
+ if (ret != 0) {
+ DRM_ERROR("CDN_API_CheckAlive failed - check firmware!\n");
+ return -ENXIO;
+ }
+
+ DRM_INFO("CDN_API_CheckAlive returned ret = %d\n", ret);
+
+ /* turn on IP activity */
+ ret = CDN_API_MainControl_blocking(state, 1, &resp);
+ DRM_INFO("CDN_API_MainControl_blocking (ret = %d resp = %u)\n",
+ ret, resp);
+
+ ret = CDN_API_General_Test_Echo_Ext_blocking(state, echo_msg, echo_resp,
+ sizeof(echo_msg), CDN_BUS_TYPE_APB);
+ if (strncmp(echo_msg, echo_resp, sizeof(echo_msg)) != 0) {
+ DRM_ERROR("CDN_API_General_Test_Echo_Ext_blocking - echo test failed, check firmware!");
+ return -ENXIO;
+ }
+ DRM_INFO("CDN_API_General_Test_Echo_Ext_blocking (ret = %d echo_resp = %s)\n",
+ ret, echo_resp);
+
+ /* Line swaping */
+ CDN_API_General_Write_Register_blocking(state,
+ ADDR_SOURCD_PHY +
+ (LANES_CONFIG << 2),
+ 0x00400000 | hdp->lane_mapping);
+ DRM_INFO("CDN_API_General_Write_Register_blockin ... setting LANES_CONFIG\n");
+
+ return 0;
+}
+
+int dp_phy_init(state_struct *state, struct drm_display_mode *mode, int format,
+ int color_depth)
+{
+ struct imx_hdp *hdp = state_to_imx_hdp(state);
+ int max_link_rate = hdp->link_rate;
+ int num_lanes = 4;
+ int ret;
+
+ /* reset phy */
+ imx_hdp_call(hdp, phy_reset, hdp->ipcHndl, NULL, 0);
+
+ /* PHY initialization while phy reset pin is active */
+ AFE_init(state, num_lanes, (ENUM_AFE_LINK_RATE)max_link_rate);
+ DRM_INFO("AFE_init\n");
+
+ /* In this point the phy reset should be deactivated */
+ imx_hdp_call(hdp, phy_reset, hdp->ipcHndl, NULL, 1);
+ DRM_INFO("deasserted reset\n");
+
+ /* PHY power set */
+ AFE_power(state, num_lanes, (ENUM_AFE_LINK_RATE)max_link_rate);
+ DRM_INFO("AFE_power exit\n");
+
+ /* Video off */
+ ret = CDN_API_DPTX_SetVideo_blocking(state, 0);
+ DRM_INFO("CDN_API_DPTX_SetVideo_blocking (ret = %d)\n", ret);
+
+ return true;
+}
+
+#ifdef DEBUG
+void print_header(void)
+{
+ /* "0x00000000: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f"*/
+ DRM_INFO(" : 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"
+ );
+ DRM_INFO("-----------------------------------------------------------\n"
+ );
+}
+
+void print_bytes(unsigned int addr, unsigned char *buf, unsigned int size)
+{
+ int i, index = 0;
+ char line[160];
+
+ if (((size + 11) * 3) > sizeof(line))
+ return;
+
+ index += sprintf(line, "0x%08x:", addr);
+ for (i = 0; i < size; i++)
+ index += sprintf(&line[index], " %02x", buf[i]);
+ DRM_INFO("%s\n", line);
+
+}
+
+int dump_dpcd(state_struct *state)
+{
+ int ret;
+
+ DPTX_Read_DPCD_response resp_dpcd;
+
+ print_header();
+
+ ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x0, &resp_dpcd,
+ CDN_BUS_TYPE_APB);
+ if (ret) {
+ DRM_INFO("_debug: function returned with status %d\n", ret);
+ return -1;
+ }
+ print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+
+ ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x100, &resp_dpcd,
+ CDN_BUS_TYPE_APB);
+ if (ret) {
+ DRM_INFO("_debug: function returned with status %d\n", ret);
+ return -1;
+ }
+ print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+
+ ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x200, &resp_dpcd,
+ CDN_BUS_TYPE_APB);
+ if (ret) {
+ DRM_INFO("_debug: function returned with status %d\n", ret);
+ return -1;
+ }
+ print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+
+ ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x210, &resp_dpcd,
+ CDN_BUS_TYPE_APB);
+ if (ret) {
+ DRM_INFO("_debug: function returned with status %d\n", ret);
+ return -1;
+ }
+ print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+
+ ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x220, &resp_dpcd,
+ CDN_BUS_TYPE_APB);
+ if (ret) {
+ DRM_INFO("_debug: function returned with status %d\n", ret);
+ return -1;
+ }
+ print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+
+ ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x700, &resp_dpcd,
+ CDN_BUS_TYPE_APB);
+ if (ret) {
+ DRM_INFO("_debug: function returned with status %d\n", ret);
+ return -1;
+ }
+ print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+
+ ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x710, &resp_dpcd,
+ CDN_BUS_TYPE_APB);
+ if (ret) {
+ DRM_INFO("_debug: function returned with status %d\n", ret);
+ return -1;
+ }
+ print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+
+ ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x720, &resp_dpcd,
+ CDN_BUS_TYPE_APB);
+ if (ret) {
+ DRM_INFO("_debug: function returned with status %d\n", ret);
+ return -1;
+ }
+ print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+
+ ret = CDN_API_DPTX_Read_DPCD_blocking(state, 0x10, 0x730, &resp_dpcd,
+ CDN_BUS_TYPE_APB);
+ if (ret) {
+ DRM_INFO("_debug: function returned with status %d\n", ret);
+ return -1;
+ }
+
+ print_bytes(resp_dpcd.addr, resp_dpcd.buff, resp_dpcd.size);
+ return 0;
+}
+#endif
+
+int dp_get_training_status(state_struct *state)
+{
+ uint32_t evt;
+ uint8_t eventId;
+ uint8_t HPDevents;
+
+ do {
+ do {
+ CDN_API_Get_Event(state, &evt);
+ if (evt != 0)
+ DRM_DEBUG("_Get_Event %d\n", evt);
+ } while ((evt & 2) == 0);
+ CDN_API_DPTX_ReadEvent_blocking(state, &eventId, &HPDevents);
+ DRM_DEBUG("ReadEvent ID = %d HPD = %d\n", eventId, HPDevents);
+
+ switch (eventId) {
+ case 0x01:
+ DRM_INFO("INFO: Full link training started\n");
+ break;
+ case 0x02:
+ DRM_INFO("INFO: Fast link training started\n");
+ break;
+ case 0x04:
+ DRM_INFO("INFO: Clock recovery phase finished\n");
+ break;
+ case 0x08:
+ DRM_INFO("INFO: Channel equalization phase finished (this is last part meaning training finished)\n");
+ break;
+ case 0x10:
+ DRM_INFO("INFO: Fast link training finished\n");
+ break;
+ case 0x20:
+ DRM_INFO("ERROR: Clock recovery phase failed\n");
+ return -1;
+ case 0x40:
+ DRM_INFO("ERROR: Channel equalization phase failed\n");
+ return -1;
+ case 0x80:
+ DRM_INFO("ERROR: Fast link training failed\n");
+ return -1;
+ default:
+ DRM_INFO("ERROR: Invalid ID:%x\n", eventId);
+ return -1;
+ }
+ } while (eventId != 0x08 && eventId != 0x10);
+
+ return 0;
+}
+
+/* Max Link Rate: 06h (1.62Gbps), 0Ah (2.7Gbps), 14h (5.4Gbps),
+ * 1Eh (8.1Gbps)--N/A
+ */
+void dp_mode_set(state_struct *state,
+ struct drm_display_mode *mode,
+ int format,
+ int color_depth,
+ int max_link_rate)
+{
+ struct imx_hdp *hdp = state_to_imx_hdp(state);
+ int ret;
+ u8 training_retries = 10;
+ /* Set Host capabilities */
+ /* Number of lanes and SSC */
+ u8 num_lanes = 4;
+ u8 ssc = 0;
+ u8 scrambler = 0;
+ /* Max voltage swing */
+ u8 max_vswing = 3;
+ u8 force_max_vswing = 0;
+ /* Max pre-emphasis */
+ u8 max_preemph = 2;
+ u8 force_max_preemph = 0;
+ /* Supported test patterns mask */
+ u8 supp_test_patterns = 0x0F;
+ /* AUX training? */
+ u8 no_aux_training = 0;
+ /* Lane mapping */
+ u8 lane_mapping = hdp->lane_mapping; /* we have 4 lane, so it's OK */
+
+ /* Extended Host capabilities */
+ u8 ext_host_cap = 1;
+ /* Bits per sub-pixel */
+ u8 bits_per_subpixel = 8;
+ /* Stereoscopic video */
+ STEREO_VIDEO_ATTR stereo = 0;
+ /* B/W Balance Type: 0 no data, 1 IT601, 2 ITU709 */
+ BT_TYPE bt_type = 0;
+ /* Transfer Unit */
+ u8 transfer_unit = 64;
+ VIC_SYMBOL_RATE sym_rate;
+ u8 link_rate;
+ GENERAL_Read_Register_response regresp;
+
+ if (hdp->is_edp) {
+ /* eDP uses device tree link rate and number of lanes */
+ link_rate = hdp->edp_link_rate;
+ num_lanes = hdp->edp_num_lanes;
+
+ /* use the eDP supported rates */
+ switch (max_link_rate) {
+ case AFE_LINK_RATE_1_6:
+ sym_rate = RATE_1_6;
+ break;
+ case AFE_LINK_RATE_2_1:
+ sym_rate = RATE_2_1;
+ break;
+ case AFE_LINK_RATE_2_4:
+ sym_rate = RATE_2_4;
+ break;
+ case AFE_LINK_RATE_2_7:
+ sym_rate = RATE_2_7;
+ break;
+ case AFE_LINK_RATE_3_2:
+ sym_rate = RATE_3_2;
+ break;
+ case AFE_LINK_RATE_4_3:
+ sym_rate = RATE_4_3;
+ break;
+ case AFE_LINK_RATE_5_4:
+ sym_rate = RATE_5_4;
+ break;
+ /*case AFE_LINK_RATE_8_1: sym_rate = RATE_8_1; break; */
+ default:
+ sym_rate = RATE_1_6;
+ }
+ } else {
+ link_rate = max_link_rate;
+
+ switch (max_link_rate) {
+ case 0x0a:
+ sym_rate = RATE_2_7;
+ break;
+ case 0x14:
+ sym_rate = RATE_5_4;
+ break;
+ default:
+ sym_rate = RATE_1_6;
+ }
+ }
+
+ ret = CDN_API_DPTX_SetHostCap_blocking(state,
+ link_rate,
+ (num_lanes & 0x7) | ((ssc & 1) << 3) | ((scrambler & 1) << 4),
+ (max_vswing & 0x3) | ((force_max_vswing & 1) << 4),
+ (max_preemph & 0x3) | ((force_max_preemph & 1) << 4),
+ supp_test_patterns,
+ no_aux_training, /* fast link training */
+ lane_mapping,
+ ext_host_cap
+ );
+ DRM_INFO("CDN_API_DPTX_SetHostCap_blocking (ret = %d)\n", ret);
+
+
+ ret = CDN_API_DPTX_Set_VIC_blocking(state,
+ mode,
+ bits_per_subpixel,
+ num_lanes,
+ sym_rate,
+ format,
+ stereo,
+ bt_type,
+ transfer_unit
+ );
+ DRM_INFO("CDN_API_DPTX_Set_VIC_blocking (ret = %d)\n", ret);
+
+ CDN_API_General_Read_Register_blocking(state, ADDR_DPTX_FRAMER +
+ (DP_FRAMER_SP << 2), &regresp);
+ DRM_INFO("Initial DP_FRAMER_SP: 0x%.2X\n", regresp.val);
+ regresp.val &= ~0x03; // clear HSP and VSP bits
+
+ DRM_INFO("Final DP_FRAMER_SP: 0x%.2X\n", regresp.val);
+ CDN_API_General_Write_Register_blocking(state, ADDR_DPTX_FRAMER +
+ (DP_FRAMER_SP << 2),
+ regresp.val);
+
+ do {
+ ret = CDN_API_DPTX_TrainingControl_blocking(state, 1);
+ DRM_DEBUG("CDN_API_DPTX_TrainingControl_blocking (ret = %d) start\n",
+ ret);
+ if (dp_get_training_status(state) == 0)
+ break;
+ training_retries--;
+
+ ret = CDN_API_DPTX_TrainingControl_blocking(state, 0);
+ DRM_DEBUG("CDN_API_DPTX_TrainingControl_blocking (ret = %d) stop\n",
+ ret);
+ udelay(1000);
+
+ } while (training_retries > 0);
+
+ /* Set video on */
+ ret = CDN_API_DPTX_SetVideo_blocking(state, 1);
+ DRM_INFO("CDN_API_DPTX_SetVideo_blocking (ret = %d)\n", ret);
+
+ udelay(1000);
+
+#ifdef DEBUG
+ ret = CDN_API_DPTX_ReadLinkStat_blocking(state, &rls);
+ DRM_INFO("INFO: Get Read Link Status (ret = %d resp: rate: %d, lanes: %d, vswing 0..3: %d %d %d, preemp 0..3: %d %d %d\n",
+ ret, rls.rate, rls.lanes,
+ rls.swing[0], rls.swing[1], rls.swing[2],
+ rls.preemphasis[0], rls.preemphasis[1],
+ rls.preemphasis[2]);
+ dump_dpcd(state);
+#endif
+
+}
+
+int dp_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
+{
+ DPTX_Read_EDID_response edidResp;
+ state_struct *state = data;
+ CDN_API_STATUS ret = 0;
+
+ memset(&edidResp, 0, sizeof(edidResp));
+ switch (block) {
+ case 0:
+ ret = CDN_API_DPTX_Read_EDID_blocking(state, 0, 0, &edidResp);
+ break;
+ case 1:
+ ret = CDN_API_DPTX_Read_EDID_blocking(state, 0, 1, &edidResp);
+ break;
+ case 2:
+ ret = CDN_API_DPTX_Read_EDID_blocking(state, 1, 0, &edidResp);
+ break;
+ case 3:
+ ret = CDN_API_DPTX_Read_EDID_blocking(state, 1, 1, &edidResp);
+ break;
+ default:
+ DRM_WARN("EDID block %x read not support\n", block);
+ }
+
+ memcpy(buf, edidResp.buff, 128);
+
+ return ret;
+}
+
+int dp_get_hpd_state(state_struct *state, u8 *hpd)
+{
+ int ret;
+
+ ret = CDN_API_DPTX_GetHpdStatus_blocking(state, hpd);
+ return ret;
+}
+
+int dp_phy_init_t28hpc(state_struct *state,
+ struct drm_display_mode *mode,
+ int format,
+ int color_depth)
+{
+ struct imx_hdp *hdp = state_to_imx_hdp(state);
+ int max_link_rate = hdp->link_rate;
+ int num_lanes = 4;
+ int ret;
+ u8 lane_mapping = hdp->lane_mapping;
+ /* reset phy */
+ imx_hdp_call(hdp, phy_reset, 0, &hdp->mem, 0);
+
+ if (hdp->is_edp) {
+ max_link_rate = hdp->edp_link_rate;
+ num_lanes = hdp->edp_num_lanes;
+ }
+
+ /* Line swaping */
+ CDN_API_General_Write_Register_blocking(state,
+ ADDR_SOURCD_PHY +
+ (LANES_CONFIG << 2),
+ 0x00400000 | lane_mapping);
+ DRM_INFO("CDN_API_General_Write_Register_blocking ... setting LANES_CONFIG %x\n",
+ lane_mapping);
+
+ /* PHY initialization while phy reset pin is active */
+ afe_init_t28hpc(state, num_lanes, (ENUM_AFE_LINK_RATE)max_link_rate);
+ DRM_INFO("AFE_init\n");
+
+ /* In this point the phy reset should be deactivated */
+ imx_hdp_call(hdp, phy_reset, 0, &hdp->mem, 1);
+ DRM_INFO("deasserted reset\n");
+
+ /* PHY power set */
+ afe_power_t28hpc(state, num_lanes, (ENUM_AFE_LINK_RATE)max_link_rate);
+ DRM_INFO("AFE_power exit\n");
+
+ /* Video off */
+ ret = CDN_API_DPTX_SetVideo_blocking(state, 0);
+ DRM_INFO("CDN_API_DPTX_SetVideo_blocking (ret = %d)\n", ret);
+
+ return true;
+}
diff --git a/drivers/gpu/drm/imx/hdp/imx-dp.h b/drivers/gpu/drm/imx/hdp/imx-dp.h
new file mode 100644
index 000000000000..bc2bc9b18b79
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/imx-dp.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _IMX_DP_H_
+#define _IMX_DP_H_
+
+void dp_fw_load(state_struct *state);
+int dp_fw_init(state_struct *state);
+void dp_mode_set(state_struct *state,
+ struct drm_display_mode *mode,
+ int format, int color_depth,
+ int max_link_rate);
+int dp_phy_init(state_struct *state,
+ struct drm_display_mode *mode,
+ int format,
+ int color_depth);
+int dp_phy_init_t28hpc(state_struct *state,
+ struct drm_display_mode *mode,
+ int format,
+ int color_depth);
+int dp_get_edid_block(void *data, u8 *buf, u32 block, size_t len);
+int dp_get_hpd_state(state_struct *state, u8 *hpd);
+
+#endif
diff --git a/drivers/gpu/drm/imx/hdp/imx-hdmi.c b/drivers/gpu/drm/imx/hdp/imx-hdmi.c
new file mode 100644
index 000000000000..045252c2b68c
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/imx-hdmi.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#ifdef DEBUG_FW_LOAD
+#include "hdmitx_firmware.h"
+#endif
+#include "imx-hdp.h"
+#include "imx-hdmi.h"
+#include "API_AFE_ss28fdsoi_kiran_hdmitx.h"
+#include "API_AFE_t28hpc_hdmitx.h"
+
+static int character_freq_khz;
+#ifdef DEBUG_FW_LOAD
+void hdmi_fw_load(state_struct *state)
+{
+ DRM_INFO("loading hdmi firmware\n");
+ CDN_API_LoadFirmware(state,
+ (u8 *)hdmitx_iram0_get_ptr(),
+ hdmitx_iram0_get_size(),
+ (u8 *)hdmitx_dram0_get_ptr(),
+ hdmitx_dram0_get_size());
+}
+#endif
+int hdmi_fw_init(state_struct *state)
+{
+ u8 echo_msg[] = "echo test";
+ u8 echo_resp[sizeof(echo_msg) + 1];
+ struct imx_hdp *hdp = state_to_imx_hdp(state);
+ u32 core_rate;
+ int ret;
+ u8 sts;
+
+ core_rate = clk_get_rate(hdp->clks.clk_core);
+
+ /* configure the clock */
+ CDN_API_SetClock(state, core_rate/1000000);
+ pr_info("CDN_API_SetClock completed\n");
+
+ /* moved from CDN_API_LoadFirmware */
+ cdn_apb_write(state, APB_CTRL << 2, 0);
+ DRM_INFO("Started firmware!\n");
+
+ ret = CDN_API_CheckAlive_blocking(state);
+ if (ret != 0) {
+ DRM_ERROR("CDN_API_CheckAlive failed - check firmware!\n");
+ return -ENXIO;
+ } else
+ DRM_INFO("CDN_API_CheckAlive returned ret = %d\n", ret);
+
+ /* turn on IP activity */
+ ret = CDN_API_MainControl_blocking(state, 1, &sts);
+ DRM_INFO("CDN_API_MainControl_blocking ret = %d sts = %u\n", ret, sts);
+
+ ret = CDN_API_General_Test_Echo_Ext_blocking(state, echo_msg, echo_resp,
+ sizeof(echo_msg), CDN_BUS_TYPE_APB);
+
+ if (0 != strncmp(echo_msg, echo_resp, sizeof(echo_msg))) {
+ DRM_ERROR("CDN_API_General_Test_Echo_Ext_blocking - echo test failed, check firmware!");
+ return -ENXIO;
+ }
+ DRM_INFO("CDN_API_General_Test_Echo_Ext_blocking - APB(ret = %d echo_resp = %s)\n",
+ ret, echo_resp);
+
+ return 0;
+}
+
+#define RGB_ALLOWED_COLORIMETRY (BIT(HDMI_EXTENDED_COLORIMETRY_BT2020) |\
+ BIT(HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB))
+#define YCC_ALLOWED_COLORIMETRY (BIT(HDMI_EXTENDED_COLORIMETRY_BT2020) |\
+ BIT(HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM) |\
+ BIT(HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601) |\
+ BIT(HDMI_EXTENDED_COLORIMETRY_S_YCC_601) |\
+ BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_709) |\
+ BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_601))
+
+static int hdmi_avi_info_set(struct imx_hdp *hdp,
+ struct drm_display_mode *mode,
+ int format)
+{
+ struct hdmi_avi_infoframe frame;
+ struct drm_display_info *di = &hdp->connector.display_info;
+ enum hdmi_extended_colorimetry ext_colorimetry;
+ u32 sink_colorimetry;
+ u32 allowed_colorimetry;
+ u8 buf[32];
+ int ret;
+
+ /* Initialise info frame from DRM mode */
+ drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
+
+ /* Set up colorimetry */
+ allowed_colorimetry = format == PXL_RGB ? RGB_ALLOWED_COLORIMETRY :
+ YCC_ALLOWED_COLORIMETRY;
+
+ sink_colorimetry = di->hdmi.colorimetry & allowed_colorimetry;
+
+ if (sink_colorimetry & BIT(HDMI_EXTENDED_COLORIMETRY_BT2020))
+ ext_colorimetry = HDMI_EXTENDED_COLORIMETRY_BT2020;
+ else if (sink_colorimetry & BIT(HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM))
+ ext_colorimetry = HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM;
+ else if (sink_colorimetry & BIT(HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB))
+ ext_colorimetry = HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB;
+ else if (sink_colorimetry & BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_709))
+ ext_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
+ else if (sink_colorimetry & BIT(HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601))
+ ext_colorimetry = HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601;
+ else if (sink_colorimetry & BIT(HDMI_EXTENDED_COLORIMETRY_S_YCC_601))
+ ext_colorimetry = HDMI_EXTENDED_COLORIMETRY_S_YCC_601;
+ else if (sink_colorimetry & BIT(HDMI_EXTENDED_COLORIMETRY_XV_YCC_601))
+ ext_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
+ else
+ ext_colorimetry = 0;
+
+ frame.colorimetry = sink_colorimetry ? HDMI_COLORIMETRY_EXTENDED :
+ HDMI_COLORIMETRY_NONE;
+ frame.extended_colorimetry = ext_colorimetry;
+
+ switch (format) {
+ case YCBCR_4_4_4:
+ frame.colorspace = HDMI_COLORSPACE_YUV444;
+ break;
+ case YCBCR_4_2_2:
+ frame.colorspace = HDMI_COLORSPACE_YUV422;
+ break;
+ case YCBCR_4_2_0:
+ frame.colorspace = HDMI_COLORSPACE_YUV420;
+ break;
+ default:
+ frame.colorspace = HDMI_COLORSPACE_RGB;
+ break;
+ }
+
+ ret = hdmi_avi_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
+ if (ret < 0) {
+ DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
+ return -1;
+ }
+
+ buf[0] = 0;
+ return CDN_API_InfoframeSet(&hdp->state, 0, sizeof(buf),
+ (u32 *)buf, HDMI_INFOFRAME_TYPE_AVI);
+
+}
+
+int hdmi_phy_init_ss28fdsoi(state_struct *state, struct drm_display_mode *mode, int format, int color_depth)
+{
+ struct imx_hdp *hdp = state_to_imx_hdp(state);
+ int ret;
+
+ /* reset phy */
+ imx_hdp_call(hdp, phy_reset, hdp->ipcHndl, NULL, 0);
+
+ /* Configure PHY */
+ character_freq_khz = phy_cfg_hdp_ss28fdsoi(state, 4, mode, color_depth, format);
+ if (character_freq_khz == 0) {
+ DRM_ERROR("failed to set phy pclock\n");
+ return -EINVAL;
+ }
+
+ imx_hdp_call(hdp, phy_reset, hdp->ipcHndl, NULL, 1);
+
+ hdmi_tx_kiran_power_configuration_seq(state, 4);
+
+ /* Set the lane swapping */
+ ret = CDN_API_General_Write_Register_blocking(state, ADDR_SOURCD_PHY + (LANES_CONFIG << 2),
+ F_SOURCE_PHY_LANE0_SWAP(3) | F_SOURCE_PHY_LANE1_SWAP(0) |
+ F_SOURCE_PHY_LANE2_SWAP(1) | F_SOURCE_PHY_LANE3_SWAP(2) |
+ F_SOURCE_PHY_COMB_BYPASS(0) | F_SOURCE_PHY_20_10(1));
+ DRM_INFO("CDN_API_General_Write_Register_blocking LANES_CONFIG ret = %d\n", ret);
+
+ return true;
+}
+
+void hdmi_mode_set_ss28fdsoi(state_struct *state, struct drm_display_mode *mode, int format, int color_depth, int temp)
+{
+ struct imx_hdp *hdp = container_of(state, struct imx_hdp, state);
+ int ret;
+
+ /* Mode = 0 - DVI, 1 - HDMI1.4, 2 HDMI 2.0 */
+ HDMI_TX_MAIL_HANDLER_PROTOCOL_TYPE ptype = 1;
+
+ if (drm_match_cea_mode(mode) == VIC_MODE_97_60Hz ||
+ drm_match_cea_mode(mode) == VIC_MODE_96_50Hz)
+ ptype = 2;
+
+ ret = CDN_API_HDMITX_Init_blocking(state);
+ if (ret != CDN_OK) {
+ DRM_INFO("CDN_API_STATUS CDN_API_HDMITX_Init_blocking ret = %d\n", ret);
+ return;
+ }
+
+ /* force GCP CD to 0 when bpp=24 for pass CTS 7-19 */
+ if (color_depth == 8)
+ CDN_API_HDMITX_Disable_GCP(state);
+
+ /* Set HDMI TX Mode */
+ ret = CDN_API_HDMITX_Set_Mode_blocking(state, ptype, character_freq_khz);
+ if (ret != CDN_OK) {
+ DRM_INFO("CDN_API_HDMITX_Set_Mode_blocking ret = %d\n", ret);
+ return;
+ }
+
+ ret = hdmi_avi_info_set(hdp, mode, format);
+ if (ret != CDN_OK) {
+ DRM_ERROR("hdmi avi info set ret = %d\n", ret);
+ return;
+ }
+
+
+ ret = CDN_API_HDMITX_SetVic_blocking(state, mode, color_depth, format);
+ if (ret != CDN_OK) {
+ DRM_INFO("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret);
+ return;
+ }
+
+ msleep(50);
+}
+
+int hdmi_phy_init_t28hpc(state_struct *state, struct drm_display_mode *mode, int format, int color_depth)
+{
+ int ret;
+ /* 0- pixel clock from phy */
+ u32 pixel_clk_from_phy = 1;
+ char echo_msg[] = "echo test";
+ char echo_resp[sizeof(echo_msg) + 1];
+
+ /* Parameterization done */
+
+ ret = CDN_API_CheckAlive_blocking(state);
+ if (ret != 0) {
+ DRM_ERROR("NO HDMI FW running\n");
+ return -ENXIO;
+ }
+
+ ret = CDN_API_General_Test_Echo_Ext_blocking(state, echo_msg, echo_resp,
+ sizeof(echo_msg),
+ CDN_BUS_TYPE_APB);
+ if (ret != 0) {
+ DRM_ERROR("HDMI mailbox access failed\n");
+ return -ENXIO;
+ }
+
+ /* Configure PHY */
+ character_freq_khz =
+ phy_cfg_hdp_t28hpc(state, 4, mode, color_depth, format, pixel_clk_from_phy);
+ if (character_freq_khz == 0) {
+ DRM_ERROR("failed to set phy pclock\n");
+ return -EINVAL;
+ }
+
+ hdmi_tx_t28hpc_power_config_seq(state, 4);
+
+ /* Set the lane swapping */
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCD_PHY +
+ (LANES_CONFIG << 2),
+ F_SOURCE_PHY_LANE0_SWAP(0) |
+ F_SOURCE_PHY_LANE1_SWAP(1) |
+ F_SOURCE_PHY_LANE2_SWAP(2) |
+ F_SOURCE_PHY_LANE3_SWAP(3) |
+ F_SOURCE_PHY_COMB_BYPASS(0)
+ | F_SOURCE_PHY_20_10(1));
+ DRM_INFO
+ ("CDN_API_General_Write_Register_blocking LANES_CONFIG ret = %d\n",
+ ret);
+
+ return true;
+}
+
+void hdmi_mode_set_vswing(state_struct *state)
+{
+ GENERAL_Read_Register_response regresp[12];
+
+ Afe_write(state, 0x41e1, 0x7c0);
+ Afe_write(state, 0x43e1, 0x7c0);
+ Afe_write(state, 0x45e1, 0x7c0);
+ Afe_write(state, 0x47e1, 0x7c0);
+
+ Afe_write(state, 0x404C, 0x0);
+ Afe_write(state, 0x424C, 0x0);
+ Afe_write(state, 0x444C, 0x0);
+ Afe_write(state, 0x464C, 0x0);
+
+ Afe_write(state, 0x4047, 0x120);
+ Afe_write(state, 0x4247, 0x120);
+ Afe_write(state, 0x4447, 0x120);
+ Afe_write(state, 0x4647, 0x120);
+
+ regresp[0].val = Afe_read(state, 0x41e1);
+ regresp[1].val = Afe_read(state, 0x43e1);
+ regresp[2].val = Afe_read(state, 0x45e1);
+ regresp[3].val = Afe_read(state, 0x47e1);
+
+ regresp[4].val = Afe_read(state, 0x404C);
+ regresp[5].val = Afe_read(state, 0x424C);
+ regresp[6].val = Afe_read(state, 0x444C);
+ regresp[7].val = Afe_read(state, 0x464C);
+
+ regresp[8].val = Afe_read(state, 0x4047);
+ regresp[9].val = Afe_read(state, 0x4247);
+ regresp[10].val = Afe_read(state, 0x4447);
+ regresp[11].val = Afe_read(state, 0x4647);
+
+ DRM_DEBUG("LANE0_TX_DIAG_TX_DRV 0x%x \n"
+ "LANE1_TX_DIAG_TX_DRV 0x%x \n"
+ "LANE2_TX_DIAG_TX_DRV 0x%x \n"
+ "LANE3_TX_DIAG_TX_DRV 0x%x \n"
+ "Lane0_TX_TXCC_CPOST_MULT_00 0x%x \n"
+ "Lane1_TX_TXCC_CPOST_MULT_00 0x%x \n"
+ "Lane2_TX_TXCC_CPOST_MULT_00 0x%x \n"
+ "Lane3_TX_TXCC_CPOST_MULT_00 0x%x \n"
+ "Lane0_TX_TXCC_CAL_SCLR_MULT 0x%x \n"
+ "Lane1_TX_TXCC_CAL_SCLR_MULT 0x%x \n"
+ "Lane2_TX_TXCC_CAL_SCLR_MULT 0x%x \n"
+ "Lane3_TX_TXCC_CAL_SCLR_MULT 0x%x \n",
+ regresp[0].val,
+ regresp[1].val,
+ regresp[2].val,
+ regresp[3].val,
+ regresp[4].val,
+ regresp[5].val,
+ regresp[6].val,
+ regresp[7].val,
+ regresp[8].val,
+ regresp[9].val,
+ regresp[10].val,
+ regresp[11].val
+ );
+}
+
+void hdmi_mode_set_t28hpc(state_struct *state, struct drm_display_mode *mode, int format, int color_depth, int temp)
+{
+ struct imx_hdp *hdp = container_of(state, struct imx_hdp, state);
+ int ret;
+
+ /* Set HDMI TX Mode */
+ /* Mode = 0 - DVI, 1 - HDMI1.4, 2 HDMI 2.0 */
+ HDMI_TX_MAIL_HANDLER_PROTOCOL_TYPE ptype = 1;
+
+ if (drm_match_cea_mode(mode) == VIC_MODE_97_60Hz ||
+ drm_match_cea_mode(mode) == VIC_MODE_96_50Hz)
+ ptype = 2;
+
+ ret = CDN_API_HDMITX_Init_blocking(state);
+ if (ret != CDN_OK) {
+ DRM_ERROR("CDN_API_STATUS CDN_API_HDMITX_Init_blocking ret = %d\n", ret);
+ return;
+ }
+
+ /* force GCP CD to 0 when bpp=24 for pass CTS 7-19 */
+ if (color_depth == 8)
+ CDN_API_HDMITX_Disable_GCP(state);
+
+ /* Set HDMI TX Mode */
+ ret = CDN_API_HDMITX_Set_Mode_blocking(state, ptype, character_freq_khz);
+ if (ret != CDN_OK) {
+ DRM_ERROR("CDN_API_HDMITX_Set_Mode_blocking ret = %d\n", ret);
+ return;
+ }
+
+ ret = hdmi_avi_info_set(hdp, mode, format);
+ if (ret != CDN_OK) {
+ DRM_ERROR("hdmi avi info set ret = %d\n", ret);
+ return;
+ }
+
+ ret = CDN_API_HDMITX_SetVic_blocking(state, mode, color_depth, format);
+ if (ret != CDN_OK) {
+ DRM_ERROR("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret);
+ return;
+ }
+
+ hdmi_mode_set_vswing(state);
+}
+
+int hdmi_get_edid_block(void *data, u8 *buf, u32 block, size_t len)
+{
+ HDMITX_TRANS_DATA edidResp;
+ state_struct *state = data;
+ CDN_API_STATUS ret = 0;
+
+ memset(&edidResp, 0, sizeof(edidResp));
+ switch (block) {
+ case 0:
+ ret = CDN_API_HDMITX_READ_EDID_blocking(state, 0, 0, &edidResp);
+ break;
+ case 1:
+ ret = CDN_API_HDMITX_READ_EDID_blocking(state, 0, 1, &edidResp);
+ break;
+ case 2:
+ ret = CDN_API_HDMITX_READ_EDID_blocking(state, 1, 0, &edidResp);
+ break;
+ case 3:
+ ret = CDN_API_HDMITX_READ_EDID_blocking(state, 1, 1, &edidResp);
+ break;
+ default:
+ pr_warn("EDID block %x read not support\n", block);
+ }
+
+ if (ret == CDN_OK)
+ memcpy(buf, edidResp.buff, 128);
+
+ return ret;
+}
+
+int hdmi_get_hpd_state(state_struct *state, u8 *hpd)
+{
+ int ret;
+
+ ret = CDN_API_HDMITX_GetHpdStatus_blocking(state, hpd);
+ return ret;
+}
+
+int hdmi_write_hdr_metadata(state_struct *state,
+ union hdmi_infoframe *hdr_infoframe)
+{
+ struct imx_hdp *hdp = container_of(state, struct imx_hdp, state);
+ u8 buffer[40];
+ int infoframe_size;
+
+ infoframe_size = hdmi_infoframe_pack(hdr_infoframe,
+ buffer + 1, sizeof(buffer) - 1);
+ if (infoframe_size < 0) {
+ dev_err(hdp->dev, "Wrong metadata infoframe: %d\n",
+ infoframe_size);
+ return infoframe_size;
+ }
+
+ buffer[0] = 0;
+ infoframe_size++;
+
+ return CDN_API_InfoframeSet(state, 2, infoframe_size,
+ (u32 *)buffer,
+ HDMI_INFOFRAME_TYPE_DRM);
+}
diff --git a/drivers/gpu/drm/imx/hdp/imx-hdmi.h b/drivers/gpu/drm/imx/hdp/imx-hdmi.h
new file mode 100644
index 000000000000..3d53117e69f9
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/imx-hdmi.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _IMX_HDMI_H_
+#define _IMX_HDMI_H_
+
+void hdmi_fw_load(state_struct *state);
+int hdmi_fw_init(state_struct *state);
+int hdmi_phy_init_ss28fdsoi(state_struct *state,
+ struct drm_display_mode *mode, int format, int color_depth);
+void hdmi_mode_set_ss28fdsoi(state_struct *state,
+ struct drm_display_mode *mode, int format, int color_depth, int temp);
+int hdmi_phy_init_t28hpc(state_struct *state,
+ struct drm_display_mode *mode, int format, int color_depth);
+void hdmi_mode_set_t28hpc(state_struct *state,
+ struct drm_display_mode *mode, int format, int color_depth, int temp);
+int hdmi_get_edid_block(void *data, u8 *buf, u32 block, size_t len);
+int hdmi_get_hpd_state(state_struct *state, u8 *hpd);
+int hdmi_write_hdr_metadata(state_struct *state,
+ union hdmi_infoframe *hdr_infoframe);
+int pixel_clock_range_t28hpc(struct drm_display_mode *mode);
+
+#endif
diff --git a/drivers/gpu/drm/imx/hdp/imx-hdp-audio.c b/drivers/gpu/drm/imx/hdp/imx-hdp-audio.c
new file mode 100644
index 000000000000..dace3cc1e27d
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/imx-hdp-audio.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/component.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/irq.h>
+#include <linux/of_device.h>
+#include <sound/hdmi-codec.h>
+
+#include "imx-hdp.h"
+#include "imx-hdmi.h"
+#include "imx-dp.h"
+#include "../imx-drm.h"
+
+static u32 TMDS_rate_table[7] = {
+25200, 27000, 54000, 74250, 148500, 297000, 594000,
+};
+
+static u32 N_table_32k[8] = {
+/*25200, 27000, 54000, 74250, 148500, 297000, 594000,*/
+4096, 4096, 4096, 4096, 4096, 3072, 3072, 4096,
+};
+
+static u32 N_table_44k[8] = {
+6272, 6272, 6272, 6272, 6272, 4704, 9408, 6272,
+};
+
+static u32 N_table_48k[8] = {
+6144, 6144, 6144, 6144, 6144, 5120, 6144, 6144,
+};
+
+static int select_N_index(u32 pclk)
+{
+ int i = 0;
+
+ for (i = 0; i < 7; i++) {
+ if (pclk == TMDS_rate_table[i])
+ break;
+ }
+
+ if (i == 7)
+ DRM_WARN("pclkc %d is not supported!\n", pclk);
+
+ return i;
+}
+
+static void imx_hdmi_audio_avi_set(state_struct *state,
+ u32 channels)
+{
+ struct hdmi_audio_infoframe frame;
+ u8 buf[32];
+ int ret;
+
+ hdmi_audio_infoframe_init(&frame);
+
+ frame.channels = channels;
+ frame.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
+
+ ret = hdmi_audio_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
+ if (ret < 0) {
+ DRM_ERROR("failed to pack audio infoframe: %d\n", ret);
+ return;
+ }
+
+ buf[0] = 0;
+
+ CDN_API_InfoframeSet(state, 1, sizeof(buf),
+ (u32 *)buf, HDMI_INFOFRAME_TYPE_AUDIO);
+}
+
+static u32 imx_hdp_audio(struct imx_hdp *hdmi, AUDIO_TYPE type, u32 sample_rate, u32 channels, u32 width)
+{
+ AUDIO_FREQ freq;
+ AUDIO_WIDTH bits;
+ int ncts_n;
+ state_struct *state = &hdmi->state;
+ int idx_n = select_N_index(hdmi->video.cur_mode.clock);
+
+ switch (sample_rate) {
+ case 32000:
+ freq = AUDIO_FREQ_32;
+ ncts_n = N_table_32k[idx_n];
+ break;
+ case 44100:
+ freq = AUDIO_FREQ_44_1;
+ ncts_n = N_table_44k[idx_n];
+ break;
+ case 48000:
+ freq = AUDIO_FREQ_48;
+ ncts_n = N_table_48k[idx_n];
+ break;
+ case 88200:
+ freq = AUDIO_FREQ_88_2;
+ ncts_n = N_table_44k[idx_n] * 2;
+ break;
+ case 96000:
+ freq = AUDIO_FREQ_96;
+ ncts_n = N_table_48k[idx_n] * 2;
+ break;
+ case 176400:
+ freq = AUDIO_FREQ_176_4;
+ ncts_n = N_table_44k[idx_n] * 4;
+ break;
+ case 192000:
+ freq = AUDIO_FREQ_192;
+ ncts_n = N_table_48k[idx_n] * 4;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (width) {
+ case 16:
+ bits = AUDIO_WIDTH_16;
+ break;
+ case 24:
+ bits = AUDIO_WIDTH_24;
+ break;
+ case 32:
+ bits = AUDIO_WIDTH_32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+
+ CDN_API_AudioOff_blocking(state, type);
+ CDN_API_AudioAutoConfig_blocking(state,
+ type,
+ channels,
+ freq,
+ 0,
+ bits,
+ hdmi->audio_type,
+ ncts_n,
+ AUDIO_MUTE_MODE_UNMUTE);
+
+ if (hdmi->audio_type == CDN_HDMITX_TYPHOON ||
+ hdmi->audio_type == CDN_HDMITX_KIRAN)
+ imx_hdmi_audio_avi_set(state, channels);
+ return 0;
+}
+
+/*
+ * HDMI audio codec callbacks
+ */
+static int imx_hdp_audio_hw_params(struct device *dev, void *data,
+ struct hdmi_codec_daifmt *daifmt,
+ struct hdmi_codec_params *params)
+{
+ struct imx_hdp *hdmi = dev_get_drvdata(dev);
+ unsigned int chan = params->cea.channels;
+
+ dev_dbg(hdmi->dev, "%s: %u Hz, %d bit, %d channels\n", __func__,
+ params->sample_rate, params->sample_width, chan);
+
+ if (!hdmi->bridge.encoder)
+ return -ENODEV;
+
+ if (daifmt->fmt == HDMI_I2S)
+ imx_hdp_audio(hdmi,
+ AUDIO_TYPE_I2S,
+ params->sample_rate,
+ chan,
+ params->sample_width);
+ else if (daifmt->fmt == HDMI_SPDIF)
+ imx_hdp_audio(hdmi,
+ AUDIO_TYPE_SPIDIF_EXTERNAL,
+ params->sample_rate,
+ chan,
+ params->sample_width);
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static void imx_hdp_audio_shutdown(struct device *dev, void *data)
+{
+ struct imx_hdp *hdmi = dev_get_drvdata(dev);
+ state_struct *state = &hdmi->state;
+
+ CDN_API_InfoframeRemovePacket(state, 0x1, 0x84);
+}
+
+static int imx_hdp_audio_get_eld(struct device *dev, void *data, uint8_t *buf, size_t len)
+{
+ struct imx_hdp *hdmi = dev_get_drvdata(dev);
+
+ memcpy(buf, hdmi->connector.eld, min(sizeof(hdmi->connector.eld), len));
+
+ return 0;
+}
+
+static const struct hdmi_codec_ops imx_hdp_audio_codec_ops = {
+ .hw_params = imx_hdp_audio_hw_params,
+ .audio_shutdown = imx_hdp_audio_shutdown,
+ .get_eld = imx_hdp_audio_get_eld,
+};
+
+void imx_hdp_register_audio_driver(struct device *dev)
+{
+ struct hdmi_codec_pdata codec_data = {
+ .ops = &imx_hdp_audio_codec_ops,
+ .max_i2s_channels = 8,
+ .i2s = 1,
+ };
+ struct platform_device *pdev;
+
+ pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
+ 1, &codec_data,
+ sizeof(codec_data));
+ if (IS_ERR(pdev))
+ return;
+
+ DRM_INFO("%s driver bound to HDMI\n", HDMI_CODEC_DRV_NAME);
+}
+
+
diff --git a/drivers/gpu/drm/imx/hdp/imx-hdp.c b/drivers/gpu/drm/imx/hdp/imx-hdp.c
new file mode 100644
index 000000000000..b985297bab1d
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/imx-hdp.c
@@ -0,0 +1,1455 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/clk.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/component.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/irq.h>
+#include <linux/of_device.h>
+
+#include "imx-hdp.h"
+#include "imx-hdmi.h"
+#include "imx-dp.h"
+#include "../imx-drm.h"
+
+struct drm_display_mode *g_mode;
+
+static struct drm_display_mode edid_cea_modes[] = {
+ /* 3 - 720x480@60Hz */
+ { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
+ 798, 858, 0, 480, 489, 495, 525, 0,
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+ /* 4 - 1280x720@60Hz */
+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
+ 1430, 1650, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+ /* 16 - 1920x1080@60Hz */
+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
+ 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+ /* 97 - 3840x2160@60Hz */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000,
+ 3840, 4016, 4104, 4400, 0,
+ 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+ /* 96 - 3840x2160@30Hz */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000,
+ 3840, 4016, 4104, 4400, 0,
+ 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+};
+
+static inline struct imx_hdp *enc_to_imx_hdp(struct drm_encoder *e)
+{
+ return container_of(e, struct imx_hdp, encoder);
+}
+
+static void imx_hdp_state_init(struct imx_hdp *hdp)
+{
+ state_struct *state = &hdp->state;
+
+ memset(state, 0, sizeof(state_struct));
+ mutex_init(&state->mutex);
+
+ state->mem = &hdp->mem;
+ state->rw = hdp->rw;
+ state->edp = hdp->is_edp;
+}
+
+#ifdef CONFIG_IMX_HDP_CEC
+static void imx_hdp_cec_init(struct imx_hdp *hdp)
+{
+ state_struct *state = &hdp->state;
+ struct imx_cec_dev *cec = &hdp->cec;
+ u32 clk_MHz;
+
+ memset(cec, 0, sizeof(struct imx_cec_dev));
+
+ CDN_API_GetClock(state, &clk_MHz);
+ cec->clk_div = clk_MHz * 10;
+ cec->dev = hdp->dev;
+ cec->mem = &hdp->mem;
+ cec->rw = hdp->rw;
+}
+#endif
+
+static void imx8qm_pixel_link_mux(state_struct *state, struct drm_display_mode *mode)
+{
+ struct imx_hdp *hdp = state_to_imx_hdp(state);
+ u32 val;
+
+ val = 4; /* RGB */
+ if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+ val |= 1 << PL_MUX_CTL_VCP_OFFSET;
+ if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+ val |= 1 << PL_MUX_CTL_HCP_OFFSET;
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ val |= 0x2;
+
+ writel(val, hdp->mem.ss_base + CSR_PIXEL_LINK_MUX_CTL);
+}
+
+static int imx8qm_pixel_link_validate(state_struct *state)
+{
+ struct imx_hdp *hdp = state_to_imx_hdp(state);
+ sc_err_t sciErr;
+
+ sciErr = sc_ipc_getMuID(&hdp->mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ DRM_ERROR("Cannot obtain MU ID\n");
+ return -EINVAL;
+ }
+
+ sciErr = sc_ipc_open(&hdp->ipcHndl, hdp->mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ DRM_ERROR("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return -EINVAL;
+ }
+
+ sciErr = sc_misc_set_control(hdp->ipcHndl, SC_R_DC_0,
+ SC_C_PXL_LINK_MST1_VLD, 1);
+ if (sciErr != SC_ERR_NONE) {
+ DRM_ERROR("SC_R_DC_0:SC_C_PXL_LINK_MST1_VLD sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+ return -EINVAL;
+ }
+
+ sc_ipc_close(hdp->mu_id);
+
+ return 0;
+}
+
+static int imx8qm_pixel_link_invalidate(state_struct *state)
+{
+ struct imx_hdp *hdp = state_to_imx_hdp(state);
+ sc_err_t sciErr;
+
+ sciErr = sc_ipc_getMuID(&hdp->mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ DRM_ERROR("Cannot obtain MU ID\n");
+ return -EINVAL;
+ }
+
+ sciErr = sc_ipc_open(&hdp->ipcHndl, hdp->mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ DRM_ERROR("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return -EINVAL;
+ }
+
+ sciErr = sc_misc_set_control(hdp->ipcHndl, SC_R_DC_0, SC_C_PXL_LINK_MST1_VLD, 0);
+ if (sciErr != SC_ERR_NONE) {
+ DRM_ERROR("SC_R_DC_0:SC_C_PXL_LINK_MST1_VLD sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+ return -EINVAL;
+ }
+
+ sc_ipc_close(hdp->mu_id);
+
+ return 0;
+}
+
+static int imx8qm_pixel_link_sync_ctrl_enable(state_struct *state)
+{
+ struct imx_hdp *hdp = state_to_imx_hdp(state);
+ sc_err_t sciErr;
+
+ sciErr = sc_ipc_getMuID(&hdp->mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ DRM_ERROR("Cannot obtain MU ID\n");
+ return -EINVAL;
+ }
+
+ sciErr = sc_ipc_open(&hdp->ipcHndl, hdp->mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ DRM_ERROR("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return -EINVAL;
+ }
+
+ sciErr = sc_misc_set_control(hdp->ipcHndl, SC_R_DC_0, SC_C_SYNC_CTRL0, 1);
+ if (sciErr != SC_ERR_NONE) {
+ DRM_ERROR("SC_R_DC_0:SC_C_SYNC_CTRL0 sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+ return -EINVAL;
+ }
+
+ sc_ipc_close(hdp->mu_id);
+
+ return 0;
+}
+
+static int imx8qm_pixel_link_sync_ctrl_disable(state_struct *state)
+{
+ struct imx_hdp *hdp = state_to_imx_hdp(state);
+ sc_err_t sciErr;
+
+ sciErr = sc_ipc_getMuID(&hdp->mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ DRM_ERROR("Cannot obtain MU ID\n");
+ return -EINVAL;
+ }
+
+ sciErr = sc_ipc_open(&hdp->ipcHndl, hdp->mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ DRM_ERROR("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return -EINVAL;
+ }
+
+ sciErr = sc_misc_set_control(hdp->ipcHndl, SC_R_DC_0, SC_C_SYNC_CTRL0, 0);
+ if (sciErr != SC_ERR_NONE) {
+ DRM_ERROR("SC_R_DC_0:SC_C_SYNC_CTRL0 sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+ return -EINVAL;
+ }
+
+ sc_ipc_close(hdp->mu_id);
+
+ return 0;
+}
+
+void imx8qm_phy_reset(sc_ipc_t ipcHndl, struct hdp_mem *mem, u8 reset)
+{
+ sc_err_t sciErr;
+ /* set the pixel link mode and pixel type */
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_HDMI, SC_C_PHY_RESET, reset);
+ if (sciErr != SC_ERR_NONE)
+ DRM_ERROR("SC_R_HDMI PHY reset failed %d!\n", sciErr);
+}
+
+void imx8mq_phy_reset(sc_ipc_t ipcHndl, struct hdp_mem *mem, u8 reset)
+{
+ void *tmp_addr = mem->rst_base;
+
+ if (reset)
+ __raw_writel(0x8,
+ (volatile unsigned int *)(tmp_addr+0x4)); /*set*/
+ else
+ __raw_writel(0x8,
+ (volatile unsigned int *)(tmp_addr+0x8)); /*clear*/
+
+
+ return;
+}
+
+int imx8qm_clock_init(struct hdp_clks *clks)
+{
+ struct imx_hdp *hdp = clks_to_imx_hdp(clks);
+ struct device *dev = hdp->dev;
+
+ clks->av_pll = devm_clk_get(dev, "av_pll");
+ if (IS_ERR(clks->av_pll)) {
+ dev_warn(dev, "failed to get av pll clk\n");
+ return PTR_ERR(clks->av_pll);
+ }
+
+ clks->dig_pll = devm_clk_get(dev, "dig_pll");
+ if (IS_ERR(clks->dig_pll)) {
+ dev_warn(dev, "failed to get dig pll clk\n");
+ return PTR_ERR(clks->dig_pll);
+ }
+
+ clks->clk_ipg = devm_clk_get(dev, "clk_ipg");
+ if (IS_ERR(clks->clk_ipg)) {
+ dev_warn(dev, "failed to get dp ipg clk\n");
+ return PTR_ERR(clks->clk_ipg);
+ }
+
+ clks->clk_core = devm_clk_get(dev, "clk_core");
+ if (IS_ERR(clks->clk_core)) {
+ dev_warn(dev, "failed to get hdp core clk\n");
+ return PTR_ERR(clks->clk_core);
+ }
+
+ clks->clk_pxl = devm_clk_get(dev, "clk_pxl");
+ if (IS_ERR(clks->clk_pxl)) {
+ dev_warn(dev, "failed to get pxl clk\n");
+ return PTR_ERR(clks->clk_pxl);
+ }
+
+ clks->clk_pxl_mux = devm_clk_get(dev, "clk_pxl_mux");
+ if (IS_ERR(clks->clk_pxl_mux)) {
+ dev_warn(dev, "failed to get pxl mux clk\n");
+ return PTR_ERR(clks->clk_pxl_mux);
+ }
+
+ clks->clk_pxl_link = devm_clk_get(dev, "clk_pxl_link");
+ if (IS_ERR(clks->clk_pxl_mux)) {
+ dev_warn(dev, "failed to get pxl link clk\n");
+ return PTR_ERR(clks->clk_pxl_link);
+ }
+
+ clks->clk_hdp = devm_clk_get(dev, "clk_hdp");
+ if (IS_ERR(clks->clk_hdp)) {
+ dev_warn(dev, "failed to get hdp clk\n");
+ return PTR_ERR(clks->clk_hdp);
+ }
+
+ clks->clk_phy = devm_clk_get(dev, "clk_phy");
+ if (IS_ERR(clks->clk_phy)) {
+ dev_warn(dev, "failed to get phy clk\n");
+ return PTR_ERR(clks->clk_phy);
+ }
+ clks->clk_apb = devm_clk_get(dev, "clk_apb");
+ if (IS_ERR(clks->clk_apb)) {
+ dev_warn(dev, "failed to get apb clk\n");
+ return PTR_ERR(clks->clk_apb);
+ }
+ clks->clk_lis = devm_clk_get(dev, "clk_lis");
+ if (IS_ERR(clks->clk_lis)) {
+ dev_warn(dev, "failed to get lis clk\n");
+ return PTR_ERR(clks->clk_lis);
+ }
+ clks->clk_msi = devm_clk_get(dev, "clk_msi");
+ if (IS_ERR(clks->clk_msi)) {
+ dev_warn(dev, "failed to get msi clk\n");
+ return PTR_ERR(clks->clk_msi);
+ }
+ clks->clk_lpcg = devm_clk_get(dev, "clk_lpcg");
+ if (IS_ERR(clks->clk_lpcg)) {
+ dev_warn(dev, "failed to get lpcg clk\n");
+ return PTR_ERR(clks->clk_lpcg);
+ }
+ clks->clk_even = devm_clk_get(dev, "clk_even");
+ if (IS_ERR(clks->clk_even)) {
+ dev_warn(dev, "failed to get even clk\n");
+ return PTR_ERR(clks->clk_even);
+ }
+ clks->clk_dbl = devm_clk_get(dev, "clk_dbl");
+ if (IS_ERR(clks->clk_dbl)) {
+ dev_warn(dev, "failed to get dbl clk\n");
+ return PTR_ERR(clks->clk_dbl);
+ }
+ clks->clk_vif = devm_clk_get(dev, "clk_vif");
+ if (IS_ERR(clks->clk_vif)) {
+ dev_warn(dev, "failed to get vif clk\n");
+ return PTR_ERR(clks->clk_vif);
+ }
+ clks->clk_apb_csr = devm_clk_get(dev, "clk_apb_csr");
+ if (IS_ERR(clks->clk_apb_csr)) {
+ dev_warn(dev, "failed to get apb csr clk\n");
+ return PTR_ERR(clks->clk_apb_csr);
+ }
+ clks->clk_apb_ctrl = devm_clk_get(dev, "clk_apb_ctrl");
+ if (IS_ERR(clks->clk_apb_ctrl)) {
+ dev_warn(dev, "failed to get apb ctrl clk\n");
+ return PTR_ERR(clks->clk_apb_ctrl);
+ }
+ clks->clk_i2s = devm_clk_get(dev, "clk_i2s");
+ if (IS_ERR(clks->clk_i2s)) {
+ dev_warn(dev, "failed to get i2s clk\n");
+ return PTR_ERR(clks->clk_i2s);
+ }
+ clks->clk_i2s_bypass = devm_clk_get(dev, "clk_i2s_bypass");
+ if (IS_ERR(clks->clk_i2s_bypass)) {
+ dev_err(dev, "failed to get i2s bypass clk\n");
+ return PTR_ERR(clks->clk_i2s_bypass);
+ }
+ return true;
+}
+
+int imx8qm_pixel_clock_enable(struct hdp_clks *clks)
+{
+ struct imx_hdp *hdp = clks_to_imx_hdp(clks);
+ struct device *dev = hdp->dev;
+ int ret;
+
+ ret = clk_prepare_enable(clks->av_pll);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre av pll error\n", __func__);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(clks->clk_pxl);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk pxl error\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(clks->clk_pxl_mux);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk pxl mux error\n", __func__);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(clks->clk_pxl_link);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk pxl link error\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(clks->clk_vif);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk vif error\n", __func__);
+ return ret;
+ }
+ return ret;
+
+}
+
+void imx8qm_pixel_clock_disable(struct hdp_clks *clks)
+{
+ clk_disable_unprepare(clks->clk_vif);
+ clk_disable_unprepare(clks->clk_pxl);
+ clk_disable_unprepare(clks->clk_pxl_link);
+ clk_disable_unprepare(clks->clk_pxl_mux);
+ clk_disable_unprepare(clks->av_pll);
+}
+
+void imx8qm_dp_pixel_clock_set_rate(struct hdp_clks *clks)
+{
+ struct imx_hdp *hdp = clks_to_imx_hdp(clks);
+ unsigned int pclock = hdp->video.cur_mode.clock * 1000;
+
+ if (!hdp->is_digpll_dp_pclock) {
+ sc_err_t sci_err = 0;
+ sc_ipc_t ipc_handle = 0;
+ u32 mu_id;
+
+ sci_err = sc_ipc_getMuID(&mu_id);
+
+ if (sci_err != SC_ERR_NONE)
+ pr_err("Failed to get MU ID (%d)\n", sci_err);
+ sci_err = sc_ipc_open(&ipc_handle, mu_id);
+
+ if (sci_err != SC_ERR_NONE)
+ pr_err("Failed to open IPC (%d)\n", sci_err);
+
+ clk_set_rate(clks->av_pll, pclock);
+
+ /* Enable the 24MHz for HDP PHY */
+ sc_misc_set_control(ipc_handle, SC_R_HDMI, SC_C_MODE, 1);
+
+ sc_ipc_close(ipc_handle);
+ } else
+ clk_set_rate(clks->av_pll, 24000000);
+
+ if (hdp->dual_mode == true) {
+ clk_set_rate(clks->clk_pxl, pclock/2);
+ clk_set_rate(clks->clk_pxl_link, pclock/2);
+ } else {
+ clk_set_rate(clks->clk_pxl, pclock);
+ clk_set_rate(clks->clk_pxl_link, pclock);
+ }
+ clk_set_rate(clks->clk_pxl_mux, pclock);
+}
+
+void imx8qm_hdmi_pixel_clock_set_rate(struct hdp_clks *clks)
+{
+ struct imx_hdp *hdp = clks_to_imx_hdp(clks);
+ unsigned int pclock = hdp->video.cur_mode.clock * 1000;
+
+ /* pixel clock for HDMI */
+ clk_set_rate(clks->av_pll, pclock);
+
+ if (hdp->dual_mode == true) {
+ clk_set_rate(clks->clk_pxl, pclock/2);
+ clk_set_rate(clks->clk_pxl_link, pclock/2);
+ } else {
+ clk_set_rate(clks->clk_pxl_link, pclock);
+ clk_set_rate(clks->clk_pxl, pclock);
+ }
+ clk_set_rate(clks->clk_pxl_mux, pclock);
+}
+
+int imx8qm_ipg_clock_enable(struct hdp_clks *clks)
+{
+ int ret;
+ struct imx_hdp *hdp = clks_to_imx_hdp(clks);
+ struct device *dev = hdp->dev;
+
+ ret = clk_prepare_enable(clks->dig_pll);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre dig pll error\n", __func__);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(clks->clk_ipg);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk_ipg error\n", __func__);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(clks->clk_core);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk core error\n", __func__);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(clks->clk_hdp);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk hdp error\n", __func__);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(clks->clk_phy);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk phy\n", __func__);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(clks->clk_apb);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk apb error\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(clks->clk_lis);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk lis error\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(clks->clk_lpcg);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk lpcg error\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(clks->clk_msi);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk msierror\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(clks->clk_even);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk even error\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(clks->clk_dbl);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk dbl error\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(clks->clk_apb_csr);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk apb csr error\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(clks->clk_apb_ctrl);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk apb ctrl error\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(clks->clk_i2s);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk i2s error\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(clks->clk_i2s_bypass);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk i2s bypass error\n", __func__);
+ return ret;
+ }
+ return ret;
+}
+
+void imx8qm_ipg_clock_disable(struct hdp_clks *clks)
+{
+}
+
+void imx8qm_ipg_clock_set_rate(struct hdp_clks *clks)
+{
+ struct imx_hdp *hdp = clks_to_imx_hdp(clks);
+ u32 clk_rate, desired_rate;
+
+ if (hdp->is_digpll_dp_pclock)
+ desired_rate = PLL_1188MHZ;
+ else
+ desired_rate = PLL_675MHZ;
+
+ /* hdmi/dp ipg/core clock */
+ clk_rate = clk_get_rate(clks->dig_pll);
+
+ if (clk_rate != desired_rate) {
+ pr_warn("%s, dig_pll was %u MHz, changing to %u MHz\n",
+ __func__, clk_rate/1000000,
+ desired_rate/1000000);
+ }
+
+ if (hdp->is_digpll_dp_pclock) {
+ clk_set_rate(clks->dig_pll, desired_rate);
+ clk_set_rate(clks->clk_core, desired_rate/10);
+ clk_set_rate(clks->clk_ipg, desired_rate/12);
+ clk_set_rate(clks->av_pll, 24000000);
+ } else {
+ clk_set_rate(clks->dig_pll, desired_rate);
+ clk_set_rate(clks->clk_core, desired_rate/5);
+ clk_set_rate(clks->clk_ipg, desired_rate/8);
+ }
+}
+
+static u8 imx_hdp_link_rate(struct drm_display_mode *mode)
+{
+ if (mode->clock < 297000)
+ return AFE_LINK_RATE_1_6;
+ else if (mode->clock > 297000)
+ return AFE_LINK_RATE_5_4;
+ else
+ return AFE_LINK_RATE_2_7;
+}
+
+static void imx_hdp_mode_setup(struct imx_hdp *hdp, struct drm_display_mode *mode)
+{
+ int ret;
+
+ /* set pixel clock before video mode setup */
+ imx_hdp_call(hdp, pixel_clock_disable, &hdp->clks);
+
+ imx_hdp_call(hdp, pixel_clock_set_rate, &hdp->clks);
+
+ imx_hdp_call(hdp, pixel_clock_enable, &hdp->clks);
+
+ /* Config pixel link mux */
+ imx_hdp_call(hdp, pixel_link_mux, &hdp->state, mode);
+
+ hdp->link_rate = imx_hdp_link_rate(mode);
+
+ /* mode set */
+ ret = imx_hdp_call(hdp, phy_init, &hdp->state, mode, hdp->format, hdp->bpc);
+ if (ret < 0) {
+ DRM_ERROR("Failed to initialise HDP PHY\n");
+ return;
+ }
+ imx_hdp_call(hdp, mode_set, &hdp->state, mode,
+ hdp->format, hdp->bpc, hdp->link_rate);
+
+ /* Get vic of CEA-861 */
+ hdp->vic = drm_match_cea_mode(mode);
+}
+
+bool imx_hdp_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct imx_hdp *hdp = bridge->driver_private;
+ struct drm_display_info *di = &hdp->connector.display_info;
+ int vic = drm_match_cea_mode(mode);
+
+ if (vic < 0)
+ return false;
+
+ if (vic == VIC_MODE_97_60Hz &&
+ (di->color_formats & DRM_COLOR_FORMAT_YCRCB420) &&
+ (di->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)) {
+ hdp->bpc = 10;
+ hdp->format = YCBCR_4_2_0;
+ return true;
+ }
+
+ hdp->bpc = 8;
+ hdp->format = PXL_RGB;
+
+ return true;
+}
+
+static void imx_hdp_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *orig_mode,
+ struct drm_display_mode *mode)
+{
+ struct imx_hdp *hdp = bridge->driver_private;
+
+ mutex_lock(&hdp->mutex);
+
+ memcpy(&hdp->video.cur_mode, mode, sizeof(hdp->video.cur_mode));
+ imx_hdp_mode_setup(hdp, mode);
+ /* Store the display mode for plugin/DKMS poweron events */
+ memcpy(&hdp->video.pre_mode, mode, sizeof(hdp->video.pre_mode));
+
+ mutex_unlock(&hdp->mutex);
+}
+
+static void imx_hdp_bridge_disable(struct drm_bridge *bridge)
+{
+}
+
+static void imx_hdp_bridge_enable(struct drm_bridge *bridge)
+{
+}
+
+static enum drm_connector_status
+imx_hdp_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct imx_hdp *hdp = container_of(connector,
+ struct imx_hdp, connector);
+ int ret;
+ u8 hpd = 0xf;
+
+ ret = imx_hdp_call(hdp, get_hpd_state, &hdp->state, &hpd);
+ if (ret > 0)
+ return connector_status_unknown;
+
+ if (hpd == 1)
+ /* Cable Connected */
+ return connector_status_connected;
+ else if (hpd == 0)
+ /* Cable Disconnedted */
+ return connector_status_disconnected;
+ else {
+ /* Cable status unknown */
+ DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
+ return connector_status_unknown;
+ }
+}
+
+static int imx_hdp_default_video_modes(struct drm_connector *connector)
+{
+ struct drm_display_mode *mode;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(edid_cea_modes); i++) {
+ mode = drm_mode_create(connector->dev);
+ if (!mode)
+ return -EINVAL;
+ drm_mode_copy(mode, &edid_cea_modes[i]);
+ mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+ drm_mode_probed_add(connector, mode);
+ }
+ return i;
+}
+
+static int imx_hdp_connector_get_modes(struct drm_connector *connector)
+{
+ struct imx_hdp *hdp = container_of(connector, struct imx_hdp, connector);
+ struct edid *edid;
+ int num_modes = 0;
+
+ if (hdp->is_edid == true) {
+ edid = drm_do_get_edid(connector, hdp->ops->get_edid_block, &hdp->state);
+ if (edid) {
+ dev_dbg(hdp->dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
+ edid->header[0], edid->header[1], edid->header[2], edid->header[3],
+ edid->header[4], edid->header[5], edid->header[6], edid->header[7]);
+ drm_mode_connector_update_edid_property(connector, edid);
+ num_modes = drm_add_edid_modes(connector, edid);
+ if (num_modes == 0) {
+ dev_dbg(hdp->dev, "Invalid edid, use default video modes\n");
+ num_modes = imx_hdp_default_video_modes(connector);
+ } else
+ /* Store the ELD */
+ drm_edid_to_eld(connector, edid);
+ kfree(edid);
+ } else {
+ dev_dbg(hdp->dev, "failed to get edid, use default video modes\n");
+ num_modes = imx_hdp_default_video_modes(connector);
+ }
+ } else {
+ dev_dbg(hdp->dev, "No EDID function, use default video mode\n");
+ num_modes = imx_hdp_default_video_modes(connector);
+ }
+
+ return num_modes;
+}
+
+static enum drm_mode_status
+imx_hdp_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct imx_hdp *hdp = container_of(connector, struct imx_hdp,
+ connector);
+ enum drm_mode_status mode_status = MODE_OK;
+ struct drm_cmdline_mode *cmdline_mode;
+ int ret;
+
+ cmdline_mode = &connector->cmdline_mode;
+
+ /* cmdline mode is the max support video mode when edid disabled */
+ if (!hdp->is_edid) {
+ if (cmdline_mode->xres != 0 &&
+ cmdline_mode->xres < mode->hdisplay)
+ return MODE_BAD_HVALUE;
+ }
+
+ if (hdp->is_4kp60 && mode->clock > 594000)
+ return MODE_CLOCK_HIGH;
+ else if (!hdp->is_4kp60 && mode->clock > 297000)
+ return MODE_CLOCK_HIGH;
+
+ ret = imx_hdp_call(hdp, pixel_clock_range, mode);
+ if (ret == 0) {
+ DRM_DEBUG("pixel clock %d out of range\n", mode->clock);
+ return MODE_CLOCK_RANGE;
+ }
+
+ /* 4096x2160 is not supported now */
+ if (mode->hdisplay > 3840)
+ return MODE_BAD_HVALUE;
+
+ if (mode->vdisplay > 2160)
+ return MODE_BAD_VVALUE;
+
+
+ return mode_status;
+}
+
+static void imx_hdp_connector_force(struct drm_connector *connector)
+{
+ struct imx_hdp *hdp = container_of(connector, struct imx_hdp,
+ connector);
+
+ mutex_lock(&hdp->mutex);
+ hdp->force = connector->force;
+ mutex_unlock(&hdp->mutex);
+}
+
+static int imx_hdp_set_property(struct drm_connector *connector,
+ struct drm_connector_state *state,
+ struct drm_property *property, uint64_t val)
+{
+ struct imx_hdp *hdp = container_of(connector, struct imx_hdp,
+ connector);
+ int ret;
+ union hdmi_infoframe frame;
+ struct hdr_static_metadata *hdr_metadata;
+
+ if (state->hdr_source_metadata_blob_ptr &&
+ state->hdr_source_metadata_blob_ptr->length &&
+ hdp->ops->write_hdr_metadata) {
+ hdr_metadata = (struct hdr_static_metadata *)
+ state->hdr_source_metadata_blob_ptr->data;
+
+ ret = drm_hdmi_infoframe_set_hdr_metadata(&frame.drm,
+ hdr_metadata);
+
+ if (ret < 0) {
+ DRM_ERROR("could not set HDR metadata in infoframe\n");
+ return ret;
+ }
+
+ hdp->ops->write_hdr_metadata(&hdp->state, &frame);
+ }
+
+ return 0;
+}
+
+static const struct drm_connector_funcs imx_hdp_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = imx_hdp_connector_detect,
+ .destroy = drm_connector_cleanup,
+ .force = imx_hdp_connector_force,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .atomic_set_property = imx_hdp_set_property,
+ .set_property = drm_atomic_helper_connector_set_property,
+};
+
+static const struct drm_connector_helper_funcs imx_hdp_connector_helper_funcs = {
+ .get_modes = imx_hdp_connector_get_modes,
+ .mode_valid = imx_hdp_connector_mode_valid,
+};
+
+static const struct drm_bridge_funcs imx_hdp_bridge_funcs = {
+ .enable = imx_hdp_bridge_enable,
+ .disable = imx_hdp_bridge_disable,
+ .mode_set = imx_hdp_bridge_mode_set,
+ .mode_fixup = imx_hdp_bridge_mode_fixup,
+};
+
+static void imx_hdp_imx_encoder_disable(struct drm_encoder *encoder)
+{
+ struct imx_hdp *hdp = container_of(encoder, struct imx_hdp, encoder);
+
+ imx_hdp_call(hdp, pixel_link_sync_ctrl_disable, &hdp->state);
+ imx_hdp_call(hdp, pixel_link_invalidate, &hdp->state);
+}
+
+static void imx_hdp_imx_encoder_enable(struct drm_encoder *encoder)
+{
+ struct imx_hdp *hdp = container_of(encoder, struct imx_hdp, encoder);
+ union hdmi_infoframe frame;
+ struct hdr_static_metadata *hdr_metadata;
+ struct drm_connector_state *conn_state = hdp->connector.state;
+ int ret = 0;
+
+ if (!hdp->ops->write_hdr_metadata)
+ goto out;
+
+ if (hdp->hdr_metadata_present) {
+ hdr_metadata = (struct hdr_static_metadata *)
+ conn_state->hdr_source_metadata_blob_ptr->data;
+
+ ret = drm_hdmi_infoframe_set_hdr_metadata(&frame.drm,
+ hdr_metadata);
+ } else {
+ hdr_metadata = devm_kzalloc(hdp->dev,
+ sizeof(struct hdr_static_metadata),
+ GFP_KERNEL);
+ hdr_metadata->eotf = 0;
+
+ ret = drm_hdmi_infoframe_set_hdr_metadata(&frame.drm,
+ hdr_metadata);
+
+ devm_kfree(hdp->dev, hdr_metadata);
+ }
+
+ if (ret < 0) {
+ DRM_ERROR("could not set HDR metadata in infoframe\n");
+ return;
+ }
+
+ hdp->ops->write_hdr_metadata(&hdp->state, &frame);
+
+out:
+ imx_hdp_call(hdp, pixel_link_validate, &hdp->state);
+ imx_hdp_call(hdp, pixel_link_sync_ctrl_enable , &hdp->state);
+}
+
+static int imx_hdp_imx_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
+ struct imx_hdp *hdp = container_of(encoder, struct imx_hdp, encoder);
+
+ imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB101010_1X30;
+
+ if (conn_state->hdr_metadata_changed &&
+ conn_state->hdr_source_metadata_blob_ptr &&
+ conn_state->hdr_source_metadata_blob_ptr->length)
+ hdp->hdr_metadata_present = true;
+
+ return 0;
+}
+
+static const struct drm_encoder_helper_funcs imx_hdp_imx_encoder_helper_funcs = {
+ .enable = imx_hdp_imx_encoder_enable,
+ .disable = imx_hdp_imx_encoder_disable,
+ .atomic_check = imx_hdp_imx_encoder_atomic_check,
+};
+
+static const struct drm_encoder_funcs imx_hdp_imx_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static int imx8mq_hdp_read(struct hdp_mem *mem, unsigned int addr, unsigned int *value)
+{
+ unsigned int temp;
+ void *tmp_addr = mem->regs_base + addr;
+ temp = __raw_readl((volatile unsigned int *)tmp_addr);
+ *value = temp;
+ return 0;
+}
+
+static int imx8mq_hdp_write(struct hdp_mem *mem, unsigned int addr, unsigned int value)
+{
+ void *tmp_addr = mem->regs_base + addr;
+
+ __raw_writel(value, (volatile unsigned int *)tmp_addr);
+ return 0;
+}
+
+static int imx8mq_hdp_sread(struct hdp_mem *mem, unsigned int addr, unsigned int *value)
+{
+ unsigned int temp;
+ void *tmp_addr = mem->ss_base + addr;
+ temp = __raw_readl((volatile unsigned int *)tmp_addr);
+ *value = temp;
+ return 0;
+}
+
+static int imx8mq_hdp_swrite(struct hdp_mem *mem, unsigned int addr, unsigned int value)
+{
+ void *tmp_addr = mem->ss_base + addr;
+ __raw_writel(value, (volatile unsigned int *)tmp_addr);
+ return 0;
+}
+
+static int imx8qm_hdp_read(struct hdp_mem *mem, unsigned int addr, unsigned int *value)
+{
+ unsigned int temp;
+ void *tmp_addr = (addr & 0xfff) + mem->regs_base;
+ void *off_addr = 0x8 + mem->ss_base;;
+
+ __raw_writel(addr >> 12, off_addr);
+ temp = __raw_readl((volatile unsigned int *)tmp_addr);
+
+ *value = temp;
+ return 0;
+}
+
+static int imx8qm_hdp_write(struct hdp_mem *mem, unsigned int addr, unsigned int value)
+{
+ void *tmp_addr = (addr & 0xfff) + mem->regs_base;
+ void *off_addr = 0x8 + mem->ss_base;;
+
+ __raw_writel(addr >> 12, off_addr);
+
+ __raw_writel(value, (volatile unsigned int *) tmp_addr);
+
+ return 0;
+}
+
+static int imx8qm_hdp_sread(struct hdp_mem *mem, unsigned int addr, unsigned int *value)
+{
+ unsigned int temp;
+ void *tmp_addr = (addr & 0xfff) + mem->regs_base;
+ void *off_addr = 0xc + mem->ss_base;;
+
+ __raw_writel(addr >> 12, off_addr);
+
+ temp = __raw_readl((volatile unsigned int *)tmp_addr);
+ *value = temp;
+ return 0;
+}
+
+static int imx8qm_hdp_swrite(struct hdp_mem *mem, unsigned int addr, unsigned int value)
+{
+ void *tmp_addr = (addr & 0xfff) + mem->regs_base;
+ void *off_addr = 0xc + mem->ss_base;
+
+ __raw_writel(addr >> 12, off_addr);
+ __raw_writel(value, (volatile unsigned int *)tmp_addr);
+
+ return 0;
+}
+
+static struct hdp_rw_func imx8qm_rw = {
+ .read_reg = imx8qm_hdp_read,
+ .write_reg = imx8qm_hdp_write,
+ .sread_reg = imx8qm_hdp_sread,
+ .swrite_reg = imx8qm_hdp_swrite,
+};
+
+static struct hdp_ops imx8qm_dp_ops = {
+#ifdef DEBUG_FW_LOAD
+ .fw_load = dp_fw_load,
+#endif
+ .fw_init = dp_fw_init,
+ .phy_init = dp_phy_init,
+ .mode_set = dp_mode_set,
+ .get_edid_block = dp_get_edid_block,
+ .get_hpd_state = dp_get_hpd_state,
+
+ .phy_reset = imx8qm_phy_reset,
+ .pixel_link_validate = imx8qm_pixel_link_validate,
+ .pixel_link_invalidate = imx8qm_pixel_link_invalidate,
+ .pixel_link_sync_ctrl_enable = imx8qm_pixel_link_sync_ctrl_enable,
+ .pixel_link_sync_ctrl_disable = imx8qm_pixel_link_sync_ctrl_disable,
+ .pixel_link_mux = imx8qm_pixel_link_mux,
+
+ .clock_init = imx8qm_clock_init,
+ .ipg_clock_set_rate = imx8qm_ipg_clock_set_rate,
+ .ipg_clock_enable = imx8qm_ipg_clock_enable,
+ .ipg_clock_disable = imx8qm_ipg_clock_disable,
+ .pixel_clock_set_rate = imx8qm_dp_pixel_clock_set_rate,
+ .pixel_clock_enable = imx8qm_pixel_clock_enable,
+ .pixel_clock_disable = imx8qm_pixel_clock_disable,
+};
+
+static struct hdp_ops imx8qm_hdmi_ops = {
+#ifdef DEBUG_FW_LOAD
+ .fw_load = hdmi_fw_load,
+#endif
+ .fw_init = hdmi_fw_init,
+ .phy_init = hdmi_phy_init_ss28fdsoi,
+ .mode_set = hdmi_mode_set_ss28fdsoi,
+ .get_edid_block = hdmi_get_edid_block,
+ .get_hpd_state = hdmi_get_hpd_state,
+
+ .phy_reset = imx8qm_phy_reset,
+ .pixel_link_validate = imx8qm_pixel_link_validate,
+ .pixel_link_invalidate = imx8qm_pixel_link_invalidate,
+ .pixel_link_sync_ctrl_enable = imx8qm_pixel_link_sync_ctrl_enable,
+ .pixel_link_sync_ctrl_disable = imx8qm_pixel_link_sync_ctrl_disable,
+ .pixel_link_mux = imx8qm_pixel_link_mux,
+
+ .clock_init = imx8qm_clock_init,
+ .ipg_clock_set_rate = imx8qm_ipg_clock_set_rate,
+ .ipg_clock_enable = imx8qm_ipg_clock_enable,
+ .ipg_clock_disable = imx8qm_ipg_clock_disable,
+ .pixel_clock_set_rate = imx8qm_hdmi_pixel_clock_set_rate,
+ .pixel_clock_enable = imx8qm_pixel_clock_enable,
+ .pixel_clock_disable = imx8qm_pixel_clock_disable,
+};
+
+static struct hdp_devtype imx8qm_dp_devtype = {
+ .is_edid = false,
+ .is_4kp60 = false,
+ .audio_type = CDN_DPTX,
+ .ops = &imx8qm_dp_ops,
+ .rw = &imx8qm_rw,
+};
+
+static struct hdp_devtype imx8qm_hdmi_devtype = {
+ .is_edid = false,
+ .is_4kp60 = false,
+ .audio_type = CDN_HDMITX_TYPHOON,
+ .ops = &imx8qm_hdmi_ops,
+ .rw = &imx8qm_rw,
+};
+
+static struct hdp_rw_func imx8mq_rw = {
+ .read_reg = imx8mq_hdp_read,
+ .write_reg = imx8mq_hdp_write,
+ .sread_reg = imx8mq_hdp_sread,
+ .swrite_reg = imx8mq_hdp_swrite,
+};
+
+static struct hdp_ops imx8mq_ops = {
+ .phy_init = hdmi_phy_init_t28hpc,
+ .mode_set = hdmi_mode_set_t28hpc,
+ .get_edid_block = hdmi_get_edid_block,
+ .get_hpd_state = hdmi_get_hpd_state,
+ .write_hdr_metadata = hdmi_write_hdr_metadata,
+ .pixel_clock_range = pixel_clock_range_t28hpc,
+};
+
+static struct hdp_devtype imx8mq_hdmi_devtype = {
+ .is_edid = true,
+ .is_4kp60 = true,
+ .audio_type = CDN_HDMITX_KIRAN,
+ .ops = &imx8mq_ops,
+ .rw = &imx8mq_rw,
+};
+
+static struct hdp_ops imx8mq_dp_ops = {
+ .phy_init = dp_phy_init_t28hpc,
+ .mode_set = dp_mode_set,
+ .get_edid_block = dp_get_edid_block,
+ .get_hpd_state = dp_get_hpd_state,
+ .phy_reset = imx8mq_phy_reset,
+};
+
+static struct hdp_devtype imx8mq_dp_devtype = {
+ .is_edid = true,
+ .is_4kp60 = true,
+ .audio_type = CDN_DPTX,
+ .ops = &imx8mq_dp_ops,
+ .rw = &imx8mq_rw,
+};
+
+static const struct of_device_id imx_hdp_dt_ids[] = {
+ { .compatible = "fsl,imx8qm-hdmi", .data = &imx8qm_hdmi_devtype},
+ { .compatible = "fsl,imx8qm-dp", .data = &imx8qm_dp_devtype},
+ { .compatible = "fsl,imx8mq-hdmi", .data = &imx8mq_hdmi_devtype},
+ { .compatible = "fsl,imx8mq-dp", .data = &imx8mq_dp_devtype},
+ { }
+};
+MODULE_DEVICE_TABLE(of, imx_hdp_dt_ids);
+
+static void hotplug_work_func(struct work_struct *work)
+{
+ struct imx_hdp *hdp = container_of(work, struct imx_hdp,
+ hotplug_work.work);
+ struct drm_connector *connector = &hdp->connector;
+
+ drm_helper_hpd_irq_event(connector->dev);
+
+ if (connector->status == connector_status_connected) {
+ /* Cable Connected */
+ /* For HDMI2.0 SCDC should setup again.
+ * So recovery pre video mode if it is 4Kp60 */
+ if (drm_mode_equal(&hdp->video.pre_mode, &edid_cea_modes[3]))
+ imx_hdp_mode_setup(hdp, &hdp->video.pre_mode);
+ DRM_INFO("HDMI/DP Cable Plug In\n");
+ enable_irq(hdp->irq[HPD_IRQ_OUT]);
+ } else if (connector->status == connector_status_disconnected) {
+ /* Cable Disconnedted */
+ DRM_INFO("HDMI/DP Cable Plug Out\n");
+ enable_irq(hdp->irq[HPD_IRQ_IN]);
+ }
+}
+
+static irqreturn_t imx_hdp_irq_thread(int irq, void *data)
+{
+ struct imx_hdp *hdp = data;
+
+ disable_irq_nosync(irq);
+
+ mod_delayed_work(system_wq, &hdp->hotplug_work,
+ msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
+
+ return IRQ_HANDLED;
+}
+
+static int imx_hdp_imx_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = data;
+ struct imx_hdp *hdp;
+ const struct of_device_id *of_id =
+ of_match_device(imx_hdp_dt_ids, dev);
+ const struct hdp_devtype *devtype = of_id->data;
+ struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
+ struct drm_connector *connector;
+ struct resource *res;
+ u8 hpd;
+ int ret;
+
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ hdp = devm_kzalloc(&pdev->dev, sizeof(*hdp), GFP_KERNEL);
+ if (!hdp)
+ return -ENOMEM;
+
+ hdp->dev = &pdev->dev;
+ encoder = &hdp->encoder;
+ bridge = &hdp->bridge;
+ connector = &hdp->connector;
+
+ mutex_init(&hdp->mutex);
+
+ hdp->irq[HPD_IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
+ if (hdp->irq[HPD_IRQ_IN] < 0)
+ dev_info(&pdev->dev, "No plug_in irq number\n");
+
+ hdp->irq[HPD_IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
+ if (hdp->irq[HPD_IRQ_OUT] < 0)
+ dev_info(&pdev->dev, "No plug_out irq number\n");
+
+ /* register map */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hdp->mem.regs_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(hdp->mem.regs_base)) {
+ dev_err(dev, "Failed to get HDP CTRL base register\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ hdp->mem.ss_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(hdp->mem.ss_base)) {
+ dev_err(dev, "Failed to get HDP CRS base register\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ hdp->mem.rst_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(hdp->mem.rst_base)) {
+ dev_warn(dev, "Failed to get HDP RESET base register\n");
+ }
+
+ hdp->is_cec = of_property_read_bool(pdev->dev.of_node, "fsl,cec");
+
+ hdp->is_digpll_dp_pclock = of_property_read_bool(pdev->dev.of_node, "fsl,use_digpll_pclock");
+
+ hdp->is_edp = of_property_read_bool(pdev->dev.of_node, "fsl,edp");
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "lane_mapping",
+ &hdp->lane_mapping);
+ if (ret) {
+ hdp->lane_mapping = 0x1b;
+ dev_warn(dev, "Failed to get lane_mapping - using default\n");
+ }
+ dev_info(dev, "lane_mapping 0x%02x\n", hdp->lane_mapping);
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "edp_link_rate",
+ &hdp->edp_link_rate);
+ if (ret) {
+ hdp->edp_link_rate = 0;
+ dev_warn(dev, "Failed to get dp_link_rate - using default\n");
+ }
+ dev_info(dev, "edp_link_rate 0x%02x\n", hdp->edp_link_rate);
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "edp_num_lanes",
+ &hdp->edp_num_lanes);
+ if (ret) {
+ hdp->edp_num_lanes = 4;
+ dev_warn(dev, "Failed to get dp_num_lanes - using default\n");
+ }
+ dev_info(dev, "dp_num_lanes 0x%02x\n", hdp->edp_num_lanes);
+
+ hdp->is_edid = devtype->is_edid;
+ hdp->is_4kp60 = devtype->is_4kp60;
+ hdp->audio_type = devtype->audio_type;
+ hdp->ops = devtype->ops;
+ hdp->rw = devtype->rw;
+ hdp->bpc = 8;
+ hdp->format = PXL_RGB;
+
+ /* HDP controller init */
+ imx_hdp_state_init(hdp);
+
+ hdp->link_rate = AFE_LINK_RATE_1_6;
+
+ hdp->dual_mode = false;
+
+ ret = imx_hdp_call(hdp, clock_init, &hdp->clks);
+ if (ret < 0) {
+ DRM_ERROR("Failed to initialize clock\n");
+ return ret;
+ }
+
+ imx_hdp_call(hdp, ipg_clock_set_rate, &hdp->clks);
+
+ ret = imx_hdp_call(hdp, ipg_clock_enable, &hdp->clks);
+ if (ret < 0) {
+ DRM_ERROR("Failed to initialize IPG clock\n");
+ return ret;
+ }
+ imx_hdp_call(hdp, pixel_clock_enable, &hdp->clks);
+
+ imx_hdp_call(hdp, phy_reset, hdp->ipcHndl, &hdp->mem, 0);
+
+ imx_hdp_call(hdp, fw_load, &hdp->state);
+
+ ret = imx_hdp_call(hdp, fw_init, &hdp->state);
+ if (ret < 0) {
+ DRM_ERROR("Failed to initialise HDP firmware\n");
+ return ret;
+ }
+
+ /* Pixel Format - 1 RGB, 2 YCbCr 444, 3 YCbCr 420 */
+ /* bpp (bits per subpixel) - 8 24bpp, 10 30bpp, 12 36bpp, 16 48bpp */
+ /* default set hdmi to 1080p60 mode */
+ ret = imx_hdp_call(hdp, phy_init, &hdp->state, &edid_cea_modes[2],
+ hdp->format, hdp->bpc);
+ if (ret < 0) {
+ DRM_ERROR("Failed to initialise HDP PHY\n");
+ return ret;
+ }
+
+ /* encoder */
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+ /*
+ * If we failed to find the CRTC(s) which this encoder is
+ * supposed to be connected to, it's because the CRTC has
+ * not been registered yet. Defer probing, and hope that
+ * the required CRTC is added later.
+ */
+ if (encoder->possible_crtcs == 0)
+ return -EPROBE_DEFER;
+
+ /* encoder */
+ drm_encoder_helper_add(encoder, &imx_hdp_imx_encoder_helper_funcs);
+ drm_encoder_init(drm, encoder, &imx_hdp_imx_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS, NULL);
+
+ /* bridge */
+ bridge->encoder = encoder;
+ bridge->driver_private = hdp;
+ bridge->funcs = &imx_hdp_bridge_funcs;
+ ret = drm_bridge_attach(drm, bridge);
+ if (ret) {
+ DRM_ERROR("Failed to initialize bridge with drm\n");
+ return -EINVAL;
+ }
+
+ encoder->bridge = bridge;
+ hdp->connector.polled = DRM_CONNECTOR_POLL_HPD;
+ hdp->connector.ycbcr_420_allowed = true;
+
+ /* connector */
+ drm_connector_helper_add(connector,
+ &imx_hdp_connector_helper_funcs);
+
+ drm_connector_init(drm, connector,
+ &imx_hdp_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+
+ drm_object_attach_property(&connector->base,
+ connector->dev->mode_config.hdr_source_metadata_property, 0);
+
+ drm_mode_connector_attach_encoder(connector, encoder);
+
+ dev_set_drvdata(dev, hdp);
+
+ INIT_DELAYED_WORK(&hdp->hotplug_work, hotplug_work_func);
+
+ /* Check cable states before enable irq */
+ imx_hdp_call(hdp, get_hpd_state, &hdp->state, &hpd);
+
+ /* Enable Hotplug Detect IRQ thread */
+ if (hdp->irq[HPD_IRQ_IN] > 0) {
+ irq_set_status_flags(hdp->irq[HPD_IRQ_IN], IRQ_NOAUTOEN);
+ ret = devm_request_threaded_irq(dev, hdp->irq[HPD_IRQ_IN],
+ NULL, imx_hdp_irq_thread,
+ IRQF_ONESHOT, dev_name(dev), hdp);
+ if (ret) {
+ dev_err(&pdev->dev, "can't claim irq %d\n",
+ hdp->irq[HPD_IRQ_IN]);
+ goto err_irq;
+ }
+ /* Cable Disconnedted, enable Plug in IRQ */
+ if (hpd == 0)
+ enable_irq(hdp->irq[HPD_IRQ_IN]);
+ }
+ if (hdp->irq[HPD_IRQ_OUT] > 0) {
+ irq_set_status_flags(hdp->irq[HPD_IRQ_OUT], IRQ_NOAUTOEN);
+ ret = devm_request_threaded_irq(dev, hdp->irq[HPD_IRQ_OUT],
+ NULL, imx_hdp_irq_thread,
+ IRQF_ONESHOT, dev_name(dev), hdp);
+ if (ret) {
+ dev_err(&pdev->dev, "can't claim irq %d\n",
+ hdp->irq[HPD_IRQ_OUT]);
+ goto err_irq;
+ }
+ /* Cable Connected, enable Plug out IRQ */
+ if (hpd == 1)
+ enable_irq(hdp->irq[HPD_IRQ_OUT]);
+ }
+#ifdef CONFIG_IMX_HDP_CEC
+ if (hdp->is_cec) {
+ imx_hdp_cec_init(hdp);
+ imx_cec_register(&hdp->cec);
+ }
+#endif
+
+ imx_hdp_register_audio_driver(dev);
+
+ return 0;
+err_irq:
+ drm_encoder_cleanup(encoder);
+ return ret;
+}
+
+static void imx_hdp_imx_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct imx_hdp *hdp = dev_get_drvdata(dev);
+
+#ifdef CONFIG_IMX_HDP_CEC
+ if (hdp->is_cec)
+ imx_cec_unregister(&hdp->cec);
+#endif
+ imx_hdp_call(hdp, pixel_clock_disable, &hdp->clks);
+ drm_bridge_detach(&hdp->bridge);
+}
+
+static const struct component_ops imx_hdp_imx_ops = {
+ .bind = imx_hdp_imx_bind,
+ .unbind = imx_hdp_imx_unbind,
+};
+
+static int imx_hdp_imx_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &imx_hdp_imx_ops);
+}
+
+static int imx_hdp_imx_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &imx_hdp_imx_ops);
+
+ return 0;
+}
+
+static struct platform_driver imx_hdp_imx_platform_driver = {
+ .probe = imx_hdp_imx_probe,
+ .remove = imx_hdp_imx_remove,
+ .driver = {
+ .name = "i.mx8-hdp",
+ .of_match_table = imx_hdp_dt_ids,
+ },
+};
+
+module_platform_driver(imx_hdp_imx_platform_driver);
+
+MODULE_AUTHOR("Sandor Yu <Sandor.yu@nxp.com>");
+MODULE_DESCRIPTION("IMX8QM DP Display Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dp-hdmi-imx");
diff --git a/drivers/gpu/drm/imx/hdp/imx-hdp.h b/drivers/gpu/drm/imx/hdp/imx-hdp.h
new file mode 100644
index 000000000000..a2876b09b680
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/imx-hdp.h
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _IMX_HDP_H_
+#define _IMX_HDP_H_
+
+#include <linux/regmap.h>
+#include <linux/mutex.h>
+#include <drm/drm_of.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_atomic.h>
+#include <soc/imx8/sc/sci.h>
+
+#include <drm/drm_dp_helper.h>
+#include "../../../../mxc/hdp/all.h"
+#include "../../../../mxc/hdp-cec/imx-hdp-cec.h"
+
+/* For testing hdp firmware define DEBUG_FW_LOAD */
+#undef DEBUG_FW_LOAD
+#define PLL_1188MHZ (1188000000)
+#define PLL_675MHZ (675000000)
+
+#define HDP_TX_SS_LIS_BASE 0x0000
+#define HDP_TX_SS_CSR_BASE 0x1000
+#define HDP_TX_SS_GPIO_BASE 0x2000
+#define HDP_TX_SS_CTRL0_BASE 0x8000
+
+#define CSR_PIXEL_LINK_MUX_CTL 0x00
+#define PL_MUX_CTL_VCP_OFFSET 5
+#define PL_MUX_CTL_HCP_OFFSET 4
+#define PL_MUX_CTL_PL_MUX_OFFSET 2
+#define PL_MUX_CTL_PL_SEL_OFFSET 0
+
+#define CSR_PIXEL_LINK_MUX_STATUS 0x04
+#define PL_MUX_STATUS_PL1_INT_OFFSET 18
+#define PL_MUX_STATUS_PL1_ADD_OFFSET 16
+#define PL_MUX_STATUS_PL1_TYP_OFFSET 11
+#define PL_MUX_STATUS_PL0_INT_OFFSET 9
+#define PL_MUX_STATUS_PL0_ADD_OFFSET 7
+#define PL_MUX_STATUS_PL0_TYP_OFFSET 2
+#define PL_MUX_STATUS_PL_DLY_OFFSET 0
+
+#define CSR_HDP_TX_CTRL_CTRL0 0x08
+#define CSR_HDP_TX_CTRL_CTRL1 0x0c
+
+#define HOTPLUG_DEBOUNCE_MS 200
+
+#define VIC_MODE_96_50Hz 96
+#define VIC_MODE_97_60Hz 97
+/**
+ * imx_hdp_call - Calls a struct imx hdp_operations operation on
+ * an entity
+ *
+ * @entity: entity where the @operation will be called
+ * @operation: type of the operation. Should be the name of a member of
+ * struct &media_entity_operations.
+ *
+ * This helper function will check if @operation is not %NULL. On such case,
+ * it will issue a call to @operation\(@args\).
+ */
+
+#define imx_hdp_call(hdp, operation, args...) \
+ (!(hdp) ? -ENODEV : (((hdp)->ops && (hdp)->ops->operation) ? \
+ (hdp)->ops->operation(args) : ENOIOCTLCMD))
+
+#define clks_to_imx_hdp(env) \
+ container_of(env, struct imx_hdp, clks)
+
+#define state_to_imx_hdp(env) \
+ container_of(env, struct imx_hdp, state)
+
+struct hdp_clks;
+
+struct hdp_ops {
+ void (*fw_load)(state_struct *state);
+ int (*fw_init)(state_struct *state);
+ int (*phy_init)(state_struct *state, struct drm_display_mode *mode, int format, int color_depth);
+ void (*mode_set)(state_struct *state, struct drm_display_mode *mode, int format, int color_depth, int max_link);
+ int (*get_edid_block)(void *data, u8 *buf, u32 block, size_t len);
+ int (*get_hpd_state)(state_struct *state, u8 *hpd);
+ int (*write_hdr_metadata)(state_struct *state,
+ union hdmi_infoframe *hdr_infoframe);
+
+ void (*phy_reset)(sc_ipc_t ipcHndl, struct hdp_mem *mem, u8 reset);
+ int (*pixel_link_validate)(state_struct *state);
+ int (*pixel_link_invalidate)(state_struct *state);
+ int (*pixel_link_sync_ctrl_enable)(state_struct *state);
+ int (*pixel_link_sync_ctrl_disable)(state_struct *state);
+ void (*pixel_link_mux)(state_struct *state, struct drm_display_mode *mode);
+
+ int (*clock_init)(struct hdp_clks *clks);
+ int (*ipg_clock_enable)(struct hdp_clks *clks);
+ void (*ipg_clock_disable)(struct hdp_clks *clks);
+ void (*ipg_clock_set_rate)(struct hdp_clks *clks);
+ int (*pixel_clock_enable)(struct hdp_clks *clks);
+ void (*pixel_clock_disable)(struct hdp_clks *clks);
+ void (*pixel_clock_set_rate)(struct hdp_clks *clks);
+ int (*pixel_clock_range)(struct drm_display_mode *mode);
+};
+
+struct hdp_devtype {
+ u8 is_edid;
+ u8 is_4kp60;
+ u8 audio_type;
+ struct hdp_ops *ops;
+ struct hdp_rw_func *rw;
+};
+
+struct hdp_video {
+ u32 bpp;
+ u32 format;
+ u32 lanes;
+ u32 color_type; /* bt */
+ u32 color_depth; /* bpc */
+ struct drm_display_mode cur_mode;
+ struct drm_display_mode pre_mode;
+ void __iomem *regs_base;
+};
+
+struct hdp_audio {
+ u32 interface; /* I2S SPDIF */
+ u32 freq;
+ u32 nlanes;
+ u32 nChannels;
+ u32 sample_width;
+ u32 sample_rate;
+ u32 audio_cts;
+ u32 audio_n;
+ bool audio_enable;
+ spinlock_t audio_lock;
+ struct mutex audio_mutex;
+ void __iomem *regs_base;
+};
+
+struct hdp_hdcp {
+ void __iomem *regs_base;
+};
+
+struct hdp_phy {
+ u32 index;
+ u32 number;
+ bool enabled;
+ struct phy *phy;
+ void __iomem *regs_base;
+};
+
+struct hdp_clks {
+ struct clk *av_pll;
+ struct clk *dig_pll;
+ struct clk *clk_ipg;
+ struct clk *clk_core;
+ struct clk *clk_pxl;
+ struct clk *clk_pxl_mux;
+ struct clk *clk_pxl_link;
+
+ struct clk *clk_hdp;
+ struct clk *clk_phy;
+ struct clk *clk_apb;
+
+ struct clk *clk_lis;
+ struct clk *clk_msi;
+ struct clk *clk_lpcg;
+ struct clk *clk_even;
+ struct clk *clk_dbl;
+ struct clk *clk_vif;
+ struct clk *clk_apb_csr;
+ struct clk *clk_apb_ctrl;
+ struct clk *av_pll_div;
+ struct clk *dig_pll_div;
+ struct clk *clk_i2s;
+ struct clk *clk_i2s_bypass;
+};
+
+enum hdp_tx_irq {
+ HPD_IRQ_IN,
+ HPD_IRQ_OUT,
+ HPD_IRQ_NUM,
+};
+
+struct imx_hdp {
+ struct device *dev;
+ struct drm_connector connector;
+ struct drm_encoder encoder;
+ struct drm_bridge bridge;
+
+ struct edid *edid;
+ char cable_state;
+
+ struct hdp_mem mem;
+
+ u8 is_edid;
+ u8 is_4kp60;
+ u8 is_cec;
+ u8 is_edp;
+ u8 is_digpll_dp_pclock;
+ u8 audio_type;
+ u32 lane_mapping;
+ u32 edp_link_rate;
+ u32 edp_num_lanes;
+
+ struct mutex mutex; /* for state below and previous_mode */
+ enum drm_connector_force force; /* mutex-protected force state */
+
+ struct hdp_video video;
+
+ struct drm_dp_aux aux;
+ struct mutex aux_mutex;
+
+ struct drm_dp_link dp_link;
+ S_LINK_STAT lkstat;
+ ENUM_AFE_LINK_RATE link_rate;
+
+ sc_ipc_t ipcHndl;
+ u32 mu_id;
+ u32 dual_mode;
+ struct hdp_ops *ops;
+ struct hdp_rw_func *rw;
+ struct hdp_clks clks;
+ state_struct state;
+ int vic;
+ int irq[HPD_IRQ_NUM];
+ struct delayed_work hotplug_work;
+
+ struct imx_cec_dev cec;
+
+ int bpc;
+ VIC_PXL_ENCODING_FORMAT format;
+ bool hdr_metadata_present;
+ bool hdr_mode;
+};
+
+void imx_hdp_register_audio_driver(struct device *dev);
+void imx_arc_power_up(state_struct *state);
+void imx_arc_calibrate(state_struct *state);
+void imx_arc_config(state_struct *state);
+
+#endif
diff --git a/drivers/gpu/drm/imx/hdp/mhdp_firmware.h b/drivers/gpu/drm/imx/hdp/mhdp_firmware.h
new file mode 100644
index 000000000000..c52c8e302912
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/mhdp_firmware.h
@@ -0,0 +1,77 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated from dram0.data and iram0.data firmware images
+ * Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * mhdp_firmware.c
+ *
+ ******************************************************************************
+ */
+#include <linux/io.h>
+
+static u32 const mhdp_iram0[] = {
+ 0x00000000,
+};
+
+static u32 const mhdp_dram0[] = {
+ 0x00000000,
+};
+
+u32 const *mhdp_iram0_get_ptr(void)
+{
+ return (u32 const *)mhdp_iram0;
+}
+
+u32 const *mhdp_dram0_get_ptr(void)
+{
+ return (u32 const *)mhdp_dram0;
+}
+
+size_t mhdp_iram0_get_size(void)
+{
+ return sizeof(mhdp_iram0);
+}
+
+size_t mhdp_dram0_get_size(void)
+{
+ return sizeof(mhdp_dram0);
+}
diff --git a/drivers/gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.c b/drivers/gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.c
new file mode 100644
index 000000000000..6c25f8d7a3d9
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.c
@@ -0,0 +1,108 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * ss28fdsoi_hdmitx_table.c
+ *
+ ******************************************************************************
+ */
+
+#include "ss28fdsoi_hdmitx_table.h"
+
+const u32 ss28fdsoi_hdmitx_clock_control_table[SS28FDSOI_HDMITX_CLOCK_CONTROL_TABLE_ROWS][SS28FDSOI_HDMITX_CLOCK_CONTROL_TABLE_COLS] = {
+ { 25000, 42500, 1000, 250000, 425000, 0x05, 0x01, 0x01, 400, 0x182, 0x00A, 2000000, 3400000, 0, 2, 2, 2, 4, 125000, 212500, 0x03, 25000, 42500},
+ { 42500, 85000, 1000, 425000, 850000, 0x08, 0x03, 0x01, 320, 0x132, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 4, 212500, 425000, 0x02, 42500, 85000},
+ { 85000, 170000, 1000, 850000, 1700000, 0x11, 0x00, 0x07, 340, 0x146, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 2, 425000, 850000, 0x01, 85000, 170000},
+ {170000, 340000, 1000, 1700000, 3400000, 0x22, 0x01, 0x07, 340, 0x146, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 1, 850000, 1700000, 0x00, 170000, 340000},
+ {340000, 600000, 1000, 3400000, 6000000, 0x3C, 0x03, 0x06, 600, 0x24A, 0x00A, 3400000, 6000000, 1, 1, 1, 2, 1, 1700000, 3000000, 0x00, 340000, 600000},
+ { 25000, 34000, 1205, 312500, 425000, 0x04, 0x01, 0x01, 400, 0x182, 0x00A, 2500000, 3400000, 0, 2, 2, 2, 4, 156250, 212500, 0x03, 31250, 42500},
+ { 34000, 68000, 1205, 425000, 850000, 0x06, 0x02, 0x01, 300, 0x11E, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 4, 212500, 425000, 0x02, 42500, 85000},
+ { 68000, 136000, 1205, 850000, 1700000, 0x0D, 0x02, 0x02, 325, 0x137, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 2, 425000, 850000, 0x01, 85000, 170000},
+ {136000, 272000, 1205, 1700000, 3400000, 0x1A, 0x02, 0x04, 325, 0x137, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 1, 850000, 1700000, 0x00, 170000, 340000},
+ {272000, 480000, 1205, 3400000, 6000000, 0x30, 0x03, 0x05, 600, 0x24A, 0x00A, 3400000, 6000000, 1, 1, 1, 2, 1, 1700000, 3000000, 0x00, 340000, 600000},
+ { 25000, 28000, 1500, 375000, 420000, 0x03, 0x01, 0x01, 360, 0x15A, 0x00A, 3000000, 3360000, 0, 2, 2, 2, 4, 187500, 210000, 0x03, 37500, 42000},
+ { 28000, 56000, 1500, 420000, 840000, 0x06, 0x02, 0x01, 360, 0x15A, 0x00A, 1680000, 3360000, 0, 1, 1, 2, 4, 210000, 420000, 0x02, 42000, 84000},
+ { 56000, 113000, 1500, 840000, 1695000, 0x0B, 0x00, 0x05, 330, 0x13C, 0x00A, 1680000, 3390000, 0, 1, 1, 2, 2, 420000, 847500, 0x01, 84000, 169500},
+ {113000, 226000, 1500, 1695000, 3390000, 0x16, 0x01, 0x05, 330, 0x13C, 0x00A, 1695000, 3390000, 0, 1, 1, 2, 1, 847500, 1695000, 0x00, 169500, 339000},
+ {226000, 400000, 1500, 3390000, 6000000, 0x28, 0x03, 0x04, 600, 0x24A, 0x00A, 3390000, 6000000, 1, 1, 1, 2, 1, 1695000, 3000000, 0x00, 339000, 600000},
+ { 25000, 42500, 2000, 500000, 850000, 0x05, 0x01, 0x01, 400, 0x182, 0x00A, 2000000, 3400000, 0, 1, 1, 2, 4, 250000, 425000, 0x02, 50000, 85000},
+ { 42500, 85000, 2000, 850000, 1700000, 0x08, 0x03, 0x01, 320, 0x132, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 2, 425000, 850000, 0x01, 85000, 170000},
+ { 85000, 170000, 2000, 1700000, 3400000, 0x11, 0x00, 0x07, 340, 0x146, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 1, 850000, 1700000, 0x00, 170000, 340000},
+ {170000, 300000, 2000, 3400000, 6000000, 0x22, 0x01, 0x06, 680, 0x29A, 0x00A, 3400000, 6000000, 1, 1, 1, 2, 1, 1700000, 3000000, 0x00, 340000, 600000}
+};
+
+const u32 ss28fdsoi_hdmitx_pll_tuning_table[SS28FDSOI_HDMITX_PLL_TUNING_TABLE_ROWS][SS28FDSOI_HDMITX_PLL_TUNING_TABLE_COLS] = {
+ {0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 300, 0x08D},
+ {0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 320, 0x08E},
+ {0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 325, 0x08E},
+ {0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 330, 0x08E},
+ {0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 340, 0x08F},
+ {0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 360, 0x0A7},
+ {0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 400, 0x0C5},
+ {1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 300, 0x086},
+ {1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 320, 0x087},
+ {1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 325, 0x087},
+ {1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 330, 0x104},
+ {1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 340, 0x08B},
+ {1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 360, 0x08D},
+ {1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 400, 0x0A6},
+ {2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 300, 0x04E},
+ {2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 320, 0x04F},
+ {2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 325, 0x04F},
+ {2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 330, 0x085},
+ {2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 340, 0x085},
+ {2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 360, 0x086},
+ {2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 400, 0x08B},
+ {3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 300, 0x047},
+ {3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 320, 0x04B},
+ {3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 325, 0x04B},
+ {3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 330, 0x04B},
+ {3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 340, 0x04D},
+ {3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 360, 0x04E},
+ {3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 400, 0x085},
+ {4, 3400000, 3900000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 600, 0x08D},
+ {4, 3400000, 3900000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 680, 0x0A6},
+ {5, 3900000, 4500000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 600, 0x087},
+ {5, 3900000, 4500000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 680, 0x0A4},
+ {6, 4500000, 5200000, 0x7, 0x1, 0x0, 0x04, 0x0D, 600, 0x04F},
+ {6, 4500000, 5200000, 0x7, 0x1, 0x0, 0x04, 0x0D, 680, 0x086},
+ {7, 5200000, 6000000, 0x7, 0x1, 0x0, 0x04, 0x0D, 600, 0x04D},
+ {7, 5200000, 6000000, 0x7, 0x1, 0x0, 0x04, 0x0D, 680, 0x04F}
+};
diff --git a/drivers/gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.h b/drivers/gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.h
new file mode 100644
index 000000000000..716812fcb116
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.h
@@ -0,0 +1,104 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * ss28fdsoi_hdmitx_table.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef SS28FDSOI_HDMITX_TABLE_H_
+#define SS28FDSOI_HDMITX_TABLE_H_
+
+#include <linux/io.h>
+
+# define SS28FDSOI_HDMITX_CLOCK_CONTROL_TABLE_ROWS 19
+# define SS28FDSOI_HDMITX_CLOCK_CONTROL_TABLE_COLS 23
+
+# define SS28FDSOI_HDMITX_PLL_TUNING_TABLE_ROWS 36
+# define SS28FDSOI_HDMITX_PLL_TUNING_TABLE_COLS 10
+
+typedef enum {
+ PIXEL_CLK_FREQ_KHZ_MIN,
+ PIXEL_CLK_FREQ_KHZ_MAX,
+ FEEDBACK_FACTOR,
+ DATA_RANGE_MBPS_MIN,
+ DATA_RANGE_MBPS_MAX,
+ CMNDA_PLL0_IP_DIV,
+ CMN_REF_CLK_DIG_DIV,
+ REF_CLK_DIVIDER_SCALER,
+ PLL_FB_DIV_TOTAL,
+ CMNDA_PLL0_FB_DIV_LOW,
+ CMNDA_PLL0_FB_DIV_HIGH,
+ VCO_FREQ_KHZ_MIN,
+ VCO_FREQ_KHZ_MAX,
+ VCO_RING_SELECT,
+ CMNDA_HS_CLK_0_SEL,
+ CMNDA_HS_CLK_1_SEL,
+ HSCLK_DIV_AT_XCVR,
+ HSCLK_DIV_TX_SUB_RATE,
+ TX_CLK_KHZ_MIN,
+ TX_CLK_KHZ_MAX,
+ CMNDA_PLL0_HS_SYM_DIV_SEL,
+ CMNDA_PLL0_CLK_FREQ_KHZ_MIN,
+ CMNDA_PLL0_CLK_FREQ_KHZ_MAX
+} CLK_CTRL_PARAM;
+
+typedef enum {
+ VCO_FREQ_BIN,
+ PLL_VCO_FREQ_KHZ_MIN,
+ PLL_VCO_FREQ_KHZ_MAX,
+ VOLTAGE_TO_CURRENT_COARSE,
+ VOLTAGE_TO_CURRENT,
+ NDAC_CTRL,
+ PMOS_CTRL,
+ PTAT_NDAC_CTRL,
+ PLL_FEEDBACK_DIV_TOTAL,
+ CHARGE_PUMP_GAIN
+} PLL_TUNE_PARAM;
+
+extern const u32
+ss28fdsoi_hdmitx_clock_control_table[SS28FDSOI_HDMITX_CLOCK_CONTROL_TABLE_ROWS]
+ [SS28FDSOI_HDMITX_CLOCK_CONTROL_TABLE_COLS];
+extern const u32
+ss28fdsoi_hdmitx_pll_tuning_table[SS28FDSOI_HDMITX_PLL_TUNING_TABLE_ROWS]
+ [SS28FDSOI_HDMITX_PLL_TUNING_TABLE_COLS];
+
+#endif
diff --git a/drivers/gpu/drm/imx/hdp/t28hpc_hdmitx_table.c b/drivers/gpu/drm/imx/hdp/t28hpc_hdmitx_table.c
new file mode 100644
index 000000000000..de30d5eafdeb
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/t28hpc_hdmitx_table.c
@@ -0,0 +1,175 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * The material contained herein is the proprietary and confidential
+ * information of Cadence or its licensors, and is supplied subject to, and may
+ * be used only by Cadence's customer in accordance with a previously executed
+ * license and maintenance agreement between Cadence and that customer.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * t28hpc_hdmitx_table.c
+ *
+ ******************************************************************************
+ */
+
+#include "t28hpc_hdmitx_table.h"
+
+/* Table 6. HDMI TX clock control settings (pixel clock is input) */
+const u32 t28hpc_hdmitx_clock_control_table_pixel_in[T28HPC_HDMITX_CLOCK_CONTROL_TABLE_ROWS_PIXEL_IN][T28HPC_HDMITX_CLOCK_CONTROL_TABLE_COLS_PIXEL_IN] = {
+ { 25000, 42500, 1000, 250000, 425000, 0x05, 0x01, 0x01, 400, 0x182, 0x00A, 2000000, 3400000, 0, 2, 2, 2, 4, 125000, 212500, 0x03, 25000, 42500},
+ { 42500, 85000, 1000, 425000, 850000, 0x08, 0x03, 0x01, 320, 0x132, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 4, 212500, 425000, 0x02, 42500, 85000},
+ { 85000, 170000, 1000, 850000, 1700000, 0x11, 0x00, 0x07, 340, 0x146, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 2, 425000, 850000, 0x01, 85000, 170000},
+ {170000, 340000, 1000, 1700000, 3400000, 0x22, 0x01, 0x07, 340, 0x146, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 1, 850000, 1700000, 0x00, 170000, 340000},
+ {340000, 600000, 1000, 3400000, 6000000, 0x3C, 0x03, 0x06, 600, 0x24A, 0x00A, 3400000, 6000000, 1, 1, 1, 2, 1, 1700000, 3000000, 0x00, 340000, 600000},
+ { 25000, 34000, 1250, 312000, 425000, 0x04, 0x01, 0x01, 400, 0x182, 0x00A, 2500000, 3400000, 0, 2, 2, 2, 4, 156250, 212500, 0x03, 31250, 42500},
+ { 34000, 68000, 1250, 425000, 850000, 0x06, 0x02, 0x01, 300, 0x11E, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 4, 212500, 425000, 0x02, 42500, 85000},
+ { 68000, 136000, 1250, 850000, 1700000, 0x0D, 0x02, 0x02, 325, 0x137, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 2, 425000, 850000, 0x01, 85000, 170000},
+ {136000, 272000, 1250, 1700000, 3400000, 0x1A, 0x02, 0x04, 325, 0x137, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 1, 850000, 1700000, 0x00, 170000, 340000},
+ {272000, 480000, 1250, 3400000, 6000000, 0x30, 0x03, 0x05, 600, 0x24A, 0x00A, 3400000, 6000000, 1, 1, 1, 2, 1, 1700000, 3000000, 0x00, 340000, 600000},
+ { 25000, 28000, 1500, 375000, 420000, 0x03, 0x01, 0x01, 360, 0x15A, 0x00A, 3000000, 3360000, 0, 2, 2, 2, 4, 187500, 210000, 0x03, 37500, 42000},
+ { 28000, 56000, 1500, 420000, 840000, 0x06, 0x02, 0x01, 360, 0x15A, 0x00A, 1680000, 3360000, 0, 1, 1, 2, 4, 210000, 420000, 0x02, 42000, 84000},
+ { 56000, 113000, 1500, 840000, 1695000, 0x0B, 0x00, 0x05, 330, 0x13C, 0x00A, 1680000, 3390000, 0, 1, 1, 2, 2, 420000, 847500, 0x01, 84000, 169500},
+ {113000, 226000, 1500, 1695000, 3390000, 0x16, 0x01, 0x05, 330, 0x13C, 0x00A, 1695000, 3390000, 0, 1, 1, 2, 1, 847500, 1695000, 0x00, 169500, 339000},
+ {226000, 400000, 1500, 3390000, 6000000, 0x28, 0x03, 0x04, 600, 0x24A, 0x00A, 3390000, 6000000, 1, 1, 1, 2, 1, 1695000, 3000000, 0x00, 339000, 600000},
+ { 25000, 42500, 2000, 500000, 850000, 0x05, 0x01, 0x01, 400, 0x182, 0x00A, 2000000, 3400000, 0, 1, 1, 2, 4, 250000, 425000, 0x02, 50000, 85000},
+ { 42500, 85000, 2000, 850000, 1700000, 0x08, 0x03, 0x01, 320, 0x132, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 2, 425000, 850000, 0x01, 85000, 170000},
+ { 85000, 170000, 2000, 1700000, 3400000, 0x11, 0x00, 0x07, 340, 0x146, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 1, 850000, 1700000, 0x00, 170000, 340000},
+ {170000, 300000, 2000, 3400000, 6000000, 0x22, 0x01, 0x06, 680, 0x29A, 0x00A, 3400000, 6000000, 1, 1, 1, 2, 1, 1700000, 3000000, 0x00, 340000, 600000},
+ {594000, 594000, 500, 2970000, 2970000, 0x3C, 0x03, 0x06, 600, 0x24A, 0x00A, 5940000, 5940000, 1, 1, 1, 2, 2, 1485000, 1485000, 0x01, 297000, 297000},
+ {594000, 594000, 625, 3712000, 3712000, 0x3C, 0x03, 0x06, 375, 0x169, 0x00A, 3712500, 3712500, 1, 1, 1, 2, 1, 1856250, 1856250, 0x00, 371250, 371250},
+ {594000, 594000, 750, 4455000, 4455000, 0x3C, 0x03, 0x06, 450, 0x1B4, 0x00A, 4455000, 4455000, 1, 1, 1, 2, 1, 2227500, 2227500, 0x00, 445500, 445500}
+};
+
+/* Table 7. HDMI TX PLL tuning settings (pixel clock is input) */
+const u32 t28hpc_hdmitx_pll_tuning_table_pixel_in[T28HPC_HDMITX_PLL_TUNING_TABLE_ROWS_PIXEL_IN][T28HPC_HDMITX_PLL_TUNING_TABLE_COLS_PIXEL_IN] = {
+ {0, 1700000, 2000000, 0x4, 0x3, 0x0, 0x09, 0x09, 300.0, 0x082},
+ {0, 1700000, 2000000, 0x4, 0x3, 0x0, 0x09, 0x09, 320.0, 0x083},
+ {0, 1700000, 2000000, 0x4, 0x3, 0x0, 0x09, 0x09, 325.0, 0x083},
+ {0, 1700000, 2000000, 0x4, 0x3, 0x0, 0x09, 0x09, 330.0, 0x084},
+ {0, 1700000, 2000000, 0x4, 0x3, 0x0, 0x09, 0x09, 340.0, 0x084},
+ {0, 1700000, 2000000, 0x4, 0x3, 0x0, 0x09, 0x09, 360.0, 0x086},
+ {0, 1700000, 2000000, 0x4, 0x3, 0x0, 0x09, 0x09, 400.0, 0x0A2},
+ {1, 2000000, 2400000, 0x4, 0x3, 0x0, 0x09, 0x09, 300.0, 0x047},
+ {1, 2000000, 2400000, 0x4, 0x3, 0x0, 0x09, 0x09, 320.0, 0x04B},
+ {1, 2000000, 2400000, 0x4, 0x3, 0x0, 0x09, 0x09, 325.0, 0x04C},
+ {1, 2000000, 2400000, 0x4, 0x3, 0x0, 0x09, 0x09, 330.0, 0x080},
+ {1, 2000000, 2400000, 0x4, 0x3, 0x0, 0x09, 0x09, 340.0, 0x081},
+ {1, 2000000, 2400000, 0x4, 0x3, 0x0, 0x09, 0x09, 360.0, 0x082},
+ {1, 2000000, 2400000, 0x4, 0x3, 0x0, 0x09, 0x09, 400.0, 0x084},
+ {2, 2400000, 2800000, 0x5, 0x3, 0x1, 0x00, 0x07, 300.0, 0x043},
+ {2, 2400000, 2800000, 0x5, 0x3, 0x1, 0x00, 0x07, 320.0, 0x045},
+ {2, 2400000, 2800000, 0x5, 0x3, 0x1, 0x00, 0x07, 325.0, 0x045},
+ {2, 2400000, 2800000, 0x5, 0x3, 0x1, 0x00, 0x07, 330.0, 0x045},
+ {2, 2400000, 2800000, 0x5, 0x3, 0x1, 0x00, 0x07, 340.0, 0x086},
+ {2, 2400000, 2800000, 0x5, 0x3, 0x1, 0x00, 0x07, 360.0, 0x04A},
+ {2, 2400000, 2800000, 0x5, 0x3, 0x1, 0x00, 0x07, 400.0, 0x081},
+ {3, 2800000, 3400000, 0x6, 0x3, 0x1, 0x00, 0x07, 300.0, 0x03D},
+ {3, 2800000, 3400000, 0x6, 0x3, 0x1, 0x00, 0x07, 320.0, 0x041},
+ {3, 2800000, 3400000, 0x6, 0x3, 0x1, 0x00, 0x07, 325.0, 0x041},
+ {3, 2800000, 3400000, 0x6, 0x3, 0x1, 0x00, 0x07, 330.0, 0x041},
+ {3, 2800000, 3400000, 0x6, 0x3, 0x1, 0x00, 0x07, 340.0, 0x042},
+ {3, 2800000, 3400000, 0x6, 0x3, 0x1, 0x00, 0x07, 360.0, 0x043},
+ {3, 2800000, 3400000, 0x6, 0x3, 0x1, 0x00, 0x07, 400.0, 0x046},
+ {4, 3400000, 3900000, 0x4, 0x3, 0x0, 0x07, 0x0F, 375.0, 0x041},
+ {4, 3400000, 3900000, 0x4, 0x3, 0x0, 0x07, 0x0F, 600.0, 0x082},
+ {4, 3400000, 3900000, 0x4, 0x3, 0x0, 0x07, 0x0F, 680.0, 0x085},
+ {5, 3900000, 4500000, 0x5, 0x3, 0x0, 0x07, 0x0F, 450.0, 0x041},
+ {5, 3900000, 4500000, 0x5, 0x3, 0x0, 0x07, 0x0F, 600.0, 0x04B},
+ {5, 3900000, 4500000, 0x5, 0x3, 0x0, 0x07, 0x0F, 680.0, 0x082},
+ {6, 4500000, 5200000, 0x6, 0x3, 0x1, 0x00, 0x07, 600.0, 0x045},
+ {6, 4500000, 5200000, 0x6, 0x3, 0x1, 0x00, 0x07, 680.0, 0x04A},
+ {7, 5200000, 6000000, 0x7, 0x3, 0x1, 0x00, 0x07, 600.0, 0x042},
+ {7, 5200000, 6000000, 0x7, 0x3, 0x1, 0x00, 0x07, 680.0, 0x045}
+};
+
+
+/* Table 8. HDMI TX clock control settings (pixel clock is output) */
+const u32 t28hpc_hdmitx_clock_control_table_pixel_out[T28HPC_HDMITX_CLOCK_CONTROL_TABLE_ROWS_PIXEL_OUT][T28HPC_HDMITX_CLOCK_CONTROL_TABLE_COLS_PIXEL_OUT] = {
+ { 27000, 1000, 270000, 0x03, 0x1, 0x1, 240, 0x0BC, 0x030, 80, 0x026, 0x026, 2160000, 0, 2, 2, 2, 4, 135000, 0x3, 27000, 1},
+ { 27000, 1250, 337500, 0x03, 0x1, 0x1, 300, 0x0EC, 0x03C, 100, 0x030, 0x030, 2700000, 0, 2, 2, 2, 4, 168750, 0x3, 33750, 1},
+ { 27000, 1500, 405000, 0x03, 0x1, 0x1, 360, 0x11C, 0x048, 120, 0x03A, 0x03A, 3240000, 0, 2, 2, 2, 4, 202500, 0x3, 40500, 1},
+ { 27000, 2000, 540000, 0x03, 0x1, 0x1, 240, 0x0BC, 0x030, 80, 0x026, 0x026, 2160000, 0, 2, 2, 2, 4, 270000, 0x2, 54000, 1},
+ { 54000, 1000, 540000, 0x03, 0x1, 0x1, 480, 0x17C, 0x060, 80, 0x026, 0x026, 4320000, 1, 2, 2, 2, 4, 270000, 0x3, 54000, 1},
+ { 54000, 1250, 675000, 0x04, 0x1, 0x1, 400, 0x13C, 0x050, 50, 0x017, 0x017, 2700000, 0, 1, 1, 2, 4, 337500, 0x2, 67500, 1},
+ { 54000, 1500, 810000, 0x04, 0x1, 0x1, 480, 0x17C, 0x060, 60, 0x01C, 0x01C, 3240000, 0, 2, 2, 2, 2, 405000, 0x2, 81000, 1},
+ { 54000, 2000, 1080000, 0x03, 0x1, 0x1, 240, 0x0BC, 0x030, 40, 0x012, 0x012, 2160000, 0, 2, 2, 2, 1, 540000, 0x1, 108000, 1},
+ { 74250, 1000, 742500, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 80, 0x026, 0x026, 5940000, 1, 2, 2, 2, 4, 371250, 0x3, 74250, 1},
+ { 74250, 1250, 928125, 0x04, 0x1, 0x1, 550, 0x1B4, 0x06E, 50, 0x017, 0x017, 3712500, 1, 1, 1, 2, 4, 464062, 0x2, 92812, 1},
+ { 74250, 1500, 1113750, 0x04, 0x1, 0x1, 660, 0x20C, 0x084, 60, 0x01C, 0x01C, 4455000, 1, 2, 2, 2, 2, 556875, 0x2, 111375, 1},
+ { 74250, 2000, 1485000, 0x03, 0x1, 0x1, 330, 0x104, 0x042, 40, 0x012, 0x012, 2970000, 0, 2, 2, 2, 1, 742500, 0x1, 148500, 1},
+ { 99000, 1000, 990000, 0x03, 0x1, 0x1, 440, 0x15C, 0x058, 40, 0x012, 0x012, 3960000, 1, 2, 2, 2, 2, 495000, 0x2, 99000, 1},
+ { 99000, 1250, 1237500, 0x03, 0x1, 0x1, 275, 0x0D8, 0x037, 25, 0x00B, 0x00A, 2475000, 0, 1, 1, 2, 2, 618750, 0x1, 123750, 1},
+ { 99000, 1500, 1485000, 0x03, 0x1, 0x1, 330, 0x104, 0x042, 30, 0x00D, 0x00D, 2970000, 0, 2, 2, 2, 1, 742500, 0x1, 148500, 1},
+ { 99000, 2000, 1980000, 0x03, 0x1, 0x1, 440, 0x15C, 0x058, 40, 0x012, 0x012, 3960000, 1, 2, 2, 2, 1, 990000, 0x1, 198000, 1},
+ {148500, 1000, 1485000, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 40, 0x012, 0x012, 5940000, 1, 2, 2, 2, 2, 742500, 0x2, 148500, 1},
+ {148500, 1250, 1856250, 0x04, 0x1, 0x1, 550, 0x1B4, 0x06E, 25, 0x00B, 0x00A, 3712500, 1, 1, 1, 2, 2, 928125, 0x1, 185625, 1},
+ {148500, 1500, 2227500, 0x03, 0x1, 0x1, 495, 0x188, 0x063, 30, 0x00D, 0x00D, 4455000, 1, 1, 1, 2, 2, 1113750, 0x1, 222750, 1},
+ {148500, 2000, 2970000, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 40, 0x012, 0x012, 5940000, 1, 2, 2, 2, 1, 1485000, 0x1, 297000, 1},
+ {198000, 1000, 1980000, 0x03, 0x1, 0x1, 220, 0x0AC, 0x02C, 10, 0x003, 0x003, 1980000, 0, 1, 1, 2, 1, 990000, 0x0, 198000, 1},
+ {198000, 1250, 2475000, 0x03, 0x1, 0x1, 550, 0x1B4, 0x06E, 25, 0x00B, 0x00A, 4950000, 1, 1, 1, 2, 2, 1237500, 0x1, 247500, 1},
+ {198000, 1500, 2970000, 0x03, 0x1, 0x1, 330, 0x104, 0x042, 15, 0x006, 0x005, 2970000, 0, 1, 1, 2, 1, 1485000, 0x0, 297000, 1},
+ {198000, 2000, 3960000, 0x03, 0x1, 0x1, 440, 0x15C, 0x058, 20, 0x008, 0x008, 3960000, 1, 1, 1, 2, 1, 1980000, 0x0, 396000, 1},
+ {297000, 1000, 2970000, 0x03, 0x1, 0x1, 330, 0x104, 0x042, 10, 0x003, 0x003, 2970000, 0, 1, 1, 2, 1, 1485000, 0x0, 297000, 1},
+ {297000, 1500, 4455000, 0x03, 0x1, 0x1, 495, 0x188, 0x063, 15, 0x006, 0x005, 4455000, 1, 1, 1, 2, 1, 2227500, 0x0, 445500, 1},
+ {297000, 2000, 5940000, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 20, 0x008, 0x008, 5940000, 1, 1, 1, 2, 1, 2970000, 0x0, 594000, 1},
+ {594000, 1000, 5940000, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 10, 0x003, 0x003, 5940000, 1, 1, 1, 2, 1, 2970000, 0x0, 594000, 1},
+ {594000, 750, 4455000, 0x03, 0x1, 0x1, 495, 0x188, 0x063, 10, 0x003, 0x003, 4455000, 1, 1, 1, 2, 1, 2227500, 0x0, 445500, 0},
+ {594000, 625, 3712500, 0x04, 0x1, 0x1, 550, 0x1B4, 0x06E, 10, 0x003, 0x003, 3712500, 1, 1, 1, 2, 1, 1856250, 0x0, 371250, 0},
+ {594000, 500, 2970000, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 10, 0x003, 0x003, 5940000, 1, 1, 1, 2, 2, 1485000, 0x1, 297000, 1},
+ /* new VESA */
+#if 0 /* VESA pixel clock rate support in debuging */
+ { 40000, 1000, 400275, 0x05, 0x1, 0x1, 593, 0x126, 0x127, 80, 0x026, 0x026, 3202200, 1, 1, 1, 1, 1, 200137, 0x3, 40027, 1},
+ { 40000, 1250, 500175, 0x05, 0x1, 0x1, 741, 0x170, 0x171, 100, 0x030, 0x030, 4001400, 1, 1, 1, 1, 1, 250087, 0x3, 50017, 1},
+ { 40000, 1500, 600075, 0x05, 0x1, 0x1, 889, 0x1BA, 0x1BB, 120, 0x03A, 0x03A, 4800600, 1, 1, 1, 1, 1, 300037, 0x3, 60007, 1},
+ { 40000, 2000, 800550, 0x05, 0x1, 0x1, 593, 0x126, 0x127, 80, 0x026, 0x026, 3202200, 1, 1, 1, 1, 1, 400275, 0x2, 80055, 1},
+ { 65000, 1000, 650025, 0x05, 0x1, 0x1, 963, 0x1DF, 0x1E0, 80, 0x026, 0x026, 5200200, 1, 1, 1, 1, 1, 325012, 0x3, 65002, 1},
+ { 65000, 1250, 812700, 0x05, 0x1, 0x1, 602, 0x12B, 0x12B, 50, 0x017, 0x017, 3250800, 1, 1, 1, 1, 1, 406350, 0x2, 81270, 1},
+ { 65000, 1500, 974700, 0x05, 0x1, 0x1, 722, 0x167, 0x167, 60, 0x01C, 0x01C, 3898800, 1, 1, 1, 1, 1, 487350, 0x2, 97470, 1},
+ { 65000, 2000, 1300050, 0x05, 0x1, 0x1, 963, 0x1DF, 0x1E0, 80, 0x026, 0x026, 5200200, 1, 1, 1, 1, 1, 650025, 0x2, 130005, 1},
+ {108000, 1000, 1080000, 0x05, 0x1, 0x1, 800, 0x18E, 0x18E, 40, 0x012, 0x012, 4320000, 1, 1, 1, 1, 1, 540000, 0x2, 108000, 1},
+ {108000, 1250, 1350000, 0x05, 0x1, 0x1, 1000, 0x1F2, 0x1F2, 50, 0x017, 0x017, 5400000, 1, 1, 1, 1, 1, 675000, 0x2, 135000, 1},
+ {108000, 1500, 1620000, 0x05, 0x1, 0x1, 600, 0x12A, 0x12A, 30, 0x00D, 0x00D, 3240000, 1, 1, 1, 1, 1, 810000, 0x1, 162000, 1},
+ {108000, 2000, 2160000, 0x05, 0x1, 0x1, 800, 0x18E, 0x18E, 40, 0x012, 0x012, 4320000, 1, 1, 1, 1, 1, 1080000, 0x1, 216000, 1},
+ {154000, 1000, 1539000, 0x05, 0x1, 0x1, 570, 0x11B, 0x11B, 20, 0x008, 0x008, 3078000, 1, 1, 1, 1, 1, 769500, 0x1, 153900, 1},
+ {154000, 1250, 1925100, 0x05, 0x1, 0x1, 713, 0x162, 0x163, 25, 0x00A, 0x00B, 3850200, 1, 1, 1, 1, 1, 962550, 0x1, 192510, 1},
+ {154000, 1500, 2311200, 0x05, 0x1, 0x1, 856, 0x1AA, 0x1AA, 30, 0x00D, 0x00D, 4622400, 1, 1, 1, 1, 1, 1155600, 0x1, 231120, 1},
+ {154000, 2000, 3078000, 0x05, 0x1, 0x1, 570, 0x11B, 0x11B, 20, 0x008, 0x008, 3078000, 1, 1, 1, 1, 1, 1539000, 0x0, 307800, 1}
+#endif
+};
+
+/* Table 9. HDMI TX PLL tuning settings (pixel clock is output) */
+const u32 t28hpc_hdmitx_pll_tuning_table_pixel_out[T28HPC_HDMITX_PLL_TUNING_TABLE_ROWS_PIXEL_OUT][T28HPC_HDMITX_PLL_TUNING_TABLE_COLS_PIXEL_OUT] = {
+ { 1, 1980000, 1980000, 0x4, 0x3, 0x0, 0x09, 0x09, 220, 0x42, 160, 5, 183},
+ { 2, 2160000, 2160000, 0x4, 0x3, 0x0, 0x09, 0x09, 240, 0x42, 166, 6, 208},
+ { 3, 2475000, 2475000, 0x5, 0x3, 0x1, 0x00, 0x07, 275, 0x42, 167, 6, 209},
+ { 4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 300, 0x42, 188, 6, 230},
+ { 4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 400, 0x4C, 188, 6, 230},
+ { 5, 2970000, 2970000, 0x6, 0x3, 0x1, 0x00, 0x07, 330, 0x42, 183, 6, 225},
+ { 6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 360, 0x42, 203, 7, 256},
+ { 6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 480, 0x4C, 203, 7, 256},
+ { 7, 3712500, 3712500, 0x4, 0x3, 0x0, 0x07, 0x0F, 550, 0x4C, 212, 7, 257},
+ { 8, 3960000, 3960000, 0x5, 0x3, 0x0, 0x07, 0x0F, 440, 0x42, 184, 6, 226},
+ { 9, 4320000, 4320000, 0x5, 0x3, 0x1, 0x07, 0x0F, 480, 0x42, 205, 7, 258},
+ {10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 495, 0x42, 219, 7, 272},
+ {10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 660, 0x4C, 219, 7, 272},
+ {11, 4950000, 4950000, 0x6, 0x3, 0x1, 0x00, 0x07, 550, 0x42, 213, 7, 258},
+ {12, 5940000, 5940000, 0x7, 0x3, 0x1, 0x00, 0x07, 660, 0x42, 244, 8, 292},
+ /* new VESA */
+ {13, 3078000, 3078000, 0x6, 0x3, 0x1, 0x00, 0x07, 570, 0x4C, 183, 6, 225}, /* nominal VCO freq: 3078000 */
+ {14, 3202100, 3202300, 0x6, 0x3, 0x1, 0x00, 0x07, 593, 0x4C, 203, 7, 256}, /* nominal VCO freq: 3202200 */
+ {15, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 600, 0x4C, 203, 7, 256}, /* nominal VCO freq: 3240000 */
+ {16, 3250700, 3250900, 0x6, 0x3, 0x1, 0x00, 0x07, 602, 0x4C, 203, 7, 256}, /* nominal VCO freq: 3250800 */
+ {17, 3850100, 3850300, 0x5, 0x3, 0x0, 0x07, 0x0F, 713, 0x42, 184, 6, 226}, /* nominal VCO freq: 3850200 */
+ {18, 3898700, 3898900, 0x5, 0x3, 0x0, 0x07, 0x0F, 722, 0x42, 184, 6, 226}, /* nominal VCO freq: 3898800 */
+ {19, 4001300, 4001500, 0x5, 0x3, 0x0, 0x07, 0x0F, 741, 0x42, 184, 6, 226}, /* nominal VCO freq: 4001400 */
+ {20, 4320000, 4320000, 0x5, 0x3, 0x1, 0x07, 0x0F, 800, 0x42, 205, 7, 258}, /* nominal VCO freq: 4320000 */
+ {21, 4622300, 4622500, 0x5, 0x3, 0x0, 0x07, 0x0F, 856, 0x4C, 219, 7, 272}, /* nominal VCO freq: 4622400 */
+ {22, 4800500, 4800700, 0x6, 0x3, 0x1, 0x00, 0x07, 889, 0x42, 213, 7, 258}, /* nominal VCO freq: 4800600 */
+ {23, 5200100, 5200300, 0x6, 0x3, 0x1, 0x00, 0x07, 963, 0x42, 213, 7, 258}, /* nominal VCO freq: 5200200 */
+ {24, 5400000, 5400000, 0x6, 0x3, 0x1, 0x00, 0x07, 1000, 0x42, 213, 7, 258} /* nominal VCO freq: 5400000 */
+};
diff --git a/drivers/gpu/drm/imx/hdp/t28hpc_hdmitx_table.h b/drivers/gpu/drm/imx/hdp/t28hpc_hdmitx_table.h
new file mode 100644
index 000000000000..5cbcffe3f373
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/t28hpc_hdmitx_table.h
@@ -0,0 +1,129 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2015-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * The material contained herein is the proprietary and confidential
+ * information of Cadence or its licensors, and is supplied subject to, and may
+ * be used only by Cadence's customer in accordance with a previously executed
+ * license and maintenance agreement between Cadence and that customer.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * t28hpc_hdmitx_table.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef T28HPC_HDMITX_TABLE_H_
+#define T28HPC_HDMITX_TABLE_H_
+
+#include <linux/io.h>
+
+#define T28HPC_HDMITX_CLOCK_CONTROL_TABLE_ROWS_PIXEL_IN 22
+
+#define T28HPC_HDMITX_PLL_TUNING_TABLE_ROWS_PIXEL_IN 38
+
+#define T28HPC_HDMITX_CLOCK_CONTROL_TABLE_ROWS_PIXEL_OUT 47
+
+#define T28HPC_HDMITX_PLL_TUNING_TABLE_ROWS_PIXEL_OUT 27
+
+/* Table 6. HDMI TX clock control settings (pixel clock is input) */
+typedef enum {
+ T6_PIXEL_CLK_FREQ_KHZ_MIN,
+ T6_PIXEL_CLK_FREQ_KHZ_MAX,
+ T6_FEEDBACK_FACTOR,
+ T6_DATA_RANGE_MBPS_MIN,
+ T6_DATA_RANGE_MBPS_MAX,
+ T6_CMNDA_PLL0_IP_DIV,
+ T6_CMN_REF_CLK_DIG_DIV,
+ T6_REF_CLK_DIVIDER_SCALER,
+ T6_PLL_FB_DIV_TOTAL,
+ T6_CMNDA_PLL0_FB_DIV_LOW,
+ T6_CMNDA_PLL0_FB_DIV_HIGH,
+ T6_VCO_FREQ_KHZ_MIN,
+ T6_VCO_FREQ_KHZ_MAX,
+ T6_VCO_RING_SELECT,
+ T6_CMNDA_HS_CLK_0_SEL,
+ T6_CMNDA_HS_CLK_1_SEL,
+ T6_HSCLK_DIV_AT_XCVR,
+ T6_HSCLK_DIV_TX_SUB_RATE,
+ T6_TX_CLK_KHZ_MIN,
+ T6_TX_CLK_KHZ_MAX,
+ T6_CMNDA_PLL0_HS_SYM_DIV_SEL,
+ T6_CMNDA_PLL0_CLK_FREQ_KHZ_MIN,
+ T6_CMNDA_PLL0_CLK_FREQ_KHZ_MAX,
+ T28HPC_HDMITX_CLOCK_CONTROL_TABLE_COLS_PIXEL_IN
+} CLK_CTRL_PARAM_PIXEL_IN;
+
+
+/* Table 7. HDMI TX PLL tuning settings (pixel clock is input) */
+typedef enum {
+ T7_VCO_FREQ_BIN,
+ T7_PLL_VCO_FREQ_KHZ_MIN,
+ T7_PLL_VCO_FREQ_KHZ_MAX,
+ T7_VOLTAGE_TO_CURRENT_COARSE,
+ T7_VOLTAGE_TO_CURRENT,
+ T7_NDAC_CTRL,
+ T7_PMOS_CTRL,
+ T7_PTAT_NDAC_CTRL,
+ T7_PLL_FEEDBACK_DIV_TOTAL,
+ T7_CHARGE_PUMP_GAIN,
+ T28HPC_HDMITX_PLL_TUNING_TABLE_COLS_PIXEL_IN
+} PLL_TUNE_PARAM_PIXEL_IN;
+
+
+/* Table 8. HDMI TX control settings (pixel clock is output) */
+typedef enum {
+ T8_PIXEL_CLK_FREQ_KHZ,
+ T8_FEEDBACK_FACTOR,
+ T8_DATA_RANGE_MBPS,
+ T8_CMNDA_PLL0_IP_DIV,
+ T8_CMN_REF_CLK_DIG_DIV,
+ T8_REF_CLK_DIVIDER_SCALER,
+ T8_PLL_FB_DIV_TOTAL,
+ T8_CMNDA_PLL0_FB_DIV_LOW,
+ T8_CMNDA_PLL0_FB_DIV_HIGH,
+ T8_PIXEL_DIV_TOTAL,
+ T8_CMNDA_PLL0_PXDIV_LOW,
+ T8_CMNDA_PLL0_PXDIV_HIGH,
+ T8_VCO_FREQ_KHZ,
+ T8_VCO_RING_SELECT,
+ T8_CMNDA_HS_CLK_0_SEL,
+ T8_CMNDA_HS_CLK_1_SEL,
+ T8_HSCLK_DIV_AT_XCVR,
+ T8_HSCLK_DIV_TX_SUB_RATE,
+ T8_TX_CLK_KHZ,
+ T8_CMNDA_PLL0_HS_SYM_DIV_SEL,
+ T8_CMNDA_PLL0_CLK_FREQ_KHZ,
+ T8_PIXEL_CLK_OUTPUT_ENABLE,
+ T28HPC_HDMITX_CLOCK_CONTROL_TABLE_COLS_PIXEL_OUT
+} CLK_CTRL_PARAM_PIXEL_OUT;
+
+/* Table 9. HDMI TX PLL tuning settings (pixel clock is output) */
+typedef enum {
+ T9_VCO_FREQ_BIN,
+ T9_PLL_VCO_FREQ_KHZ_MIN,
+ T9_PLL_VCO_FREQ_KHZ_MAX,
+ T9_VOLTAGE_TO_CURRENT_COARSE,
+ T9_VOLTAGE_TO_CURRENT,
+ T9_NDAC_CTRL,
+ T9_PMOS_CTRL,
+ T9_PTAT_NDAC_CTRL,
+ T9_PLL_FEEDBACK_DIV_TOTAL,
+ T9_CHARGE_PUMP_GAIN,
+ T9_COARSE_CODE,
+ T9_V2I_CODE,
+ T9_VCO_CAL_CODE,
+ T28HPC_HDMITX_PLL_TUNING_TABLE_COLS_PIXEL_OUT
+} PLL_TUNE_PARAM_PIXEL_OUT;
+
+extern const u32 t28hpc_hdmitx_clock_control_table_pixel_in[T28HPC_HDMITX_CLOCK_CONTROL_TABLE_ROWS_PIXEL_IN][T28HPC_HDMITX_CLOCK_CONTROL_TABLE_COLS_PIXEL_IN];
+extern const u32 t28hpc_hdmitx_pll_tuning_table_pixel_in[T28HPC_HDMITX_PLL_TUNING_TABLE_ROWS_PIXEL_IN][T28HPC_HDMITX_PLL_TUNING_TABLE_COLS_PIXEL_IN];
+extern const u32 t28hpc_hdmitx_clock_control_table_pixel_out[T28HPC_HDMITX_CLOCK_CONTROL_TABLE_ROWS_PIXEL_OUT][T28HPC_HDMITX_CLOCK_CONTROL_TABLE_COLS_PIXEL_OUT];
+extern const u32 t28hpc_hdmitx_pll_tuning_table_pixel_out[T28HPC_HDMITX_PLL_TUNING_TABLE_ROWS_PIXEL_OUT][T28HPC_HDMITX_PLL_TUNING_TABLE_COLS_PIXEL_OUT];
+
+#endif
+
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
index 9672b579f950..b41c0e4551ae 100644
--- a/drivers/gpu/drm/imx/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
@@ -15,10 +15,8 @@
*/
#include <linux/component.h>
#include <linux/device.h>
-#include <linux/dma-buf.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/reservation.h>
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
@@ -29,24 +27,17 @@
#include <drm/drm_plane_helper.h>
#include <drm/drm_of.h>
#include <video/imx-ipu-v3.h>
+#include <video/dpu.h>
+#include <video/imx-dcss.h>
+#include <video/imx-lcdif.h>
#include "imx-drm.h"
-#define MAX_CRTC 4
-
struct imx_drm_component {
struct device_node *of_node;
struct list_head list;
};
-struct imx_drm_device {
- struct drm_device *drm;
- struct imx_drm_crtc *crtc[MAX_CRTC];
- unsigned int pipes;
- struct drm_fbdev_cma *fbhelper;
- struct drm_atomic_state *state;
-};
-
struct imx_drm_crtc {
struct drm_crtc *crtc;
struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
@@ -101,6 +92,9 @@ static const struct file_operations imx_drm_driver_fops = {
.open = drm_open,
.release = drm_release,
.unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
.mmap = drm_gem_cma_mmap,
.poll = drm_poll,
.read = drm_read,
@@ -120,94 +114,6 @@ void imx_drm_encoder_destroy(struct drm_encoder *encoder)
}
EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
-static void imx_drm_output_poll_changed(struct drm_device *drm)
-{
- struct imx_drm_device *imxdrm = drm->dev_private;
-
- drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
-}
-
-static int imx_drm_atomic_check(struct drm_device *dev,
- struct drm_atomic_state *state)
-{
- int ret;
-
- ret = drm_atomic_helper_check_modeset(dev, state);
- if (ret)
- return ret;
-
- ret = drm_atomic_helper_check_planes(dev, state);
- if (ret)
- return ret;
-
- /*
- * Check modeset again in case crtc_state->mode_changed is
- * updated in plane's ->atomic_check callback.
- */
- ret = drm_atomic_helper_check_modeset(dev, state);
- if (ret)
- return ret;
-
- return ret;
-}
-
-static int imx_drm_atomic_commit(struct drm_device *dev,
- struct drm_atomic_state *state,
- bool nonblock)
-{
- struct drm_plane_state *plane_state;
- struct drm_plane *plane;
- struct dma_buf *dma_buf;
- int i;
-
- /*
- * If the plane fb has an dma-buf attached, fish out the exclusive
- * fence for the atomic helper to wait on.
- */
- for_each_plane_in_state(state, plane, plane_state, i) {
- if ((plane->state->fb != plane_state->fb) && plane_state->fb) {
- dma_buf = drm_fb_cma_get_gem_obj(plane_state->fb,
- 0)->base.dma_buf;
- if (!dma_buf)
- continue;
- plane_state->fence =
- reservation_object_get_excl_rcu(dma_buf->resv);
- }
- }
-
- return drm_atomic_helper_commit(dev, state, nonblock);
-}
-
-static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
- .fb_create = drm_fb_cma_create,
- .output_poll_changed = imx_drm_output_poll_changed,
- .atomic_check = imx_drm_atomic_check,
- .atomic_commit = imx_drm_atomic_commit,
-};
-
-static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
-{
- struct drm_device *dev = state->dev;
-
- drm_atomic_helper_commit_modeset_disables(dev, state);
-
- drm_atomic_helper_commit_planes(dev, state,
- DRM_PLANE_COMMIT_ACTIVE_ONLY |
- DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET);
-
- drm_atomic_helper_commit_modeset_enables(dev, state);
-
- drm_atomic_helper_commit_hw_done(state);
-
- drm_atomic_helper_wait_for_vblanks(dev, state);
-
- drm_atomic_helper_cleanup_planes(dev, state);
-}
-
-static struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = {
- .atomic_commit_tail = imx_drm_atomic_commit_tail,
-};
-
/*
* imx_drm_add_crtc - add a new crtc
*/
@@ -339,6 +245,33 @@ static int compare_of(struct device *dev, void *data)
struct ipu_client_platformdata *pdata = dev->platform_data;
return pdata->of_node == np;
+ } else if (strcmp(dev->driver->name, "imx-dpu-crtc") == 0) {
+ struct dpu_client_platformdata *pdata = dev->platform_data;
+
+ return pdata->of_node == np;
+ } else if (strcmp(dev->driver->name, "imx-dcss-crtc") == 0) {
+ struct dcss_client_platformdata *pdata = dev->platform_data;
+
+ return pdata->of_node == np;
+ } else if (strcmp(dev->driver->name, "imx-lcdif-crtc") == 0) {
+ struct lcdif_client_platformdata *pdata = dev->platform_data;
+#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
+ /* set legacyfb_depth to be 32 for lcdif, since
+ * default format of the connectors attached to
+ * lcdif is usually RGB888
+ */
+ if (pdata->of_node == np)
+ legacyfb_depth = 32;
+#endif
+
+ return pdata->of_node == np;
+ }
+
+ /* This is a special case for dpu bliteng. */
+ if (strcmp(dev->driver->name, "imx-drm-dpu-bliteng") == 0) {
+ struct dpu_client_platformdata *pdata = dev->platform_data;
+
+ return pdata->of_node == np;
}
/* Special case for LDB, one device for two channels */
@@ -350,12 +283,115 @@ static int compare_of(struct device *dev, void *data)
return dev->of_node == np;
}
+static const char *const imx_drm_dpu_comp_parents[] = {
+ "fsl,imx8qm-dpu",
+ "fsl,imx8qxp-dpu",
+};
+
+static const char *const imx_drm_dcss_comp_parents[] = {
+ "nxp,imx8mq-dcss",
+};
+
+static bool imx_drm_parent_is_compatible(struct device *dev,
+ const char *const comp_parents[],
+ int comp_parents_size)
+{
+ struct device_node *port, *parent;
+ bool ret = false;
+ int i;
+
+ port = of_parse_phandle(dev->of_node, "ports", 0);
+ if (!port)
+ return ret;
+
+ parent = of_get_parent(port);
+
+ for (i = 0; i < comp_parents_size; i++) {
+ if (of_device_is_compatible(parent, comp_parents[i])) {
+ ret = true;
+ break;
+ }
+ }
+
+ of_node_put(parent);
+
+ of_node_put(port);
+
+ return ret;
+}
+
+static inline bool has_dpu(struct device *dev)
+{
+ return imx_drm_parent_is_compatible(dev, imx_drm_dpu_comp_parents,
+ ARRAY_SIZE(imx_drm_dpu_comp_parents));
+}
+
+static inline bool has_dcss(struct device *dev)
+{
+ return imx_drm_parent_is_compatible(dev, imx_drm_dcss_comp_parents,
+ ARRAY_SIZE(imx_drm_dcss_comp_parents));
+}
+
+static void add_dpu_bliteng_components(struct device *dev,
+ struct component_match **matchptr)
+{
+ /*
+ * As there may be two dpu bliteng device,
+ * so need add something in compare data to distinguish.
+ * Use its parent dpu's of_node as the data here.
+ */
+ struct device_node *port, *parent;
+ /* assume max dpu number is 8 */
+ struct device_node *dpu[8];
+ int num_dpu = 0;
+ int i, j;
+ bool found = false;
+
+ for (i = 0; ; i++) {
+ port = of_parse_phandle(dev->of_node, "ports", i);
+ if (!port)
+ break;
+
+ parent = of_get_parent(port);
+
+ for (j = 0; j < num_dpu; j++) {
+ if (dpu[j] == parent) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ found = false;
+ } else {
+ if (num_dpu >= ARRAY_SIZE(dpu)) {
+ dev_err(dev, "The number of found dpu is greater than max [%ld].\n",
+ ARRAY_SIZE(dpu));
+ of_node_put(parent);
+ of_node_put(port);
+ break;
+ }
+
+ dpu[num_dpu] = parent;
+ num_dpu++;
+
+ component_match_add(dev, matchptr, compare_of, parent);
+ }
+
+ of_node_put(parent);
+ of_node_put(port);
+ }
+}
+
static int imx_drm_bind(struct device *dev)
{
struct drm_device *drm;
struct imx_drm_device *imxdrm;
int ret;
+ if (has_dpu(dev))
+ imx_drm_driver.driver_features |= DRIVER_RENDER;
+
drm = drm_dev_alloc(&imx_drm_driver, dev);
if (IS_ERR(drm))
return PTR_ERR(drm);
@@ -389,8 +425,11 @@ static int imx_drm_bind(struct device *dev)
drm->mode_config.min_height = 64;
drm->mode_config.max_width = 4096;
drm->mode_config.max_height = 4096;
- drm->mode_config.funcs = &imx_drm_mode_config_funcs;
- drm->mode_config.helper_private = &imx_drm_mode_config_helpers;
+
+ if (has_dpu(dev) || has_dcss(dev)) {
+ drm->mode_config.allow_fb_modifiers = true;
+ dev_dbg(dev, "allow fb modifiers\n");
+ }
drm_mode_config_init(drm);
@@ -417,6 +456,10 @@ static int imx_drm_bind(struct device *dev)
dev_warn(dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n");
legacyfb_depth = 16;
}
+
+ if (legacyfb_depth == 16 && has_dcss(dev))
+ legacyfb_depth = 32;
+
imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
drm->mode_config.num_crtc, MAX_CRTC);
if (IS_ERR(imxdrm->fbhelper)) {
@@ -443,6 +486,7 @@ err_unbind:
#endif
component_unbind_all(drm->dev, drm);
err_vblank:
+ dev_set_drvdata(dev, NULL);
drm_vblank_cleanup(drm);
err_kms:
drm_mode_config_cleanup(drm);
@@ -457,6 +501,9 @@ static void imx_drm_unbind(struct device *dev)
struct drm_device *drm = dev_get_drvdata(dev);
struct imx_drm_device *imxdrm = drm->dev_private;
+ if (has_dpu(dev))
+ imx_drm_driver.driver_features &= ~DRIVER_RENDER;
+
drm_dev_unregister(drm);
drm_kms_helper_poll_fini(drm);
@@ -479,7 +526,14 @@ static const struct component_master_ops imx_drm_ops = {
static int imx_drm_platform_probe(struct platform_device *pdev)
{
- int ret = drm_of_component_probe(&pdev->dev, compare_of, &imx_drm_ops);
+ struct component_match *match = NULL;
+ int ret;
+
+ if (has_dpu(&pdev->dev))
+ add_dpu_bliteng_components(&pdev->dev, &match);
+
+ ret = drm_of_component_probe_with_match(&pdev->dev, match, compare_of,
+ &imx_drm_ops);
if (!ret)
ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h
index 5a91cb16c8fa..487189b42922 100644
--- a/drivers/gpu/drm/imx/imx-drm.h
+++ b/drivers/gpu/drm/imx/imx-drm.h
@@ -1,6 +1,8 @@
#ifndef _IMX_DRM_H_
#define _IMX_DRM_H_
+#define MAX_CRTC 4
+
struct device_node;
struct drm_crtc;
struct drm_connector;
@@ -13,6 +15,14 @@ struct drm_plane;
struct imx_drm_crtc;
struct platform_device;
+struct imx_drm_device {
+ struct drm_device *drm;
+ struct imx_drm_crtc *crtc[MAX_CRTC];
+ unsigned int pipes;
+ struct drm_fbdev_cma *fbhelper;
+ struct drm_atomic_state *state;
+};
+
struct imx_crtc_state {
struct drm_crtc_state base;
u32 bus_format;
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
index 67881e5517fb..ca0ae52078f5 100644
--- a/drivers/gpu/drm/imx/imx-ldb.c
+++ b/drivers/gpu/drm/imx/imx-ldb.c
@@ -29,8 +29,12 @@
#include <linux/of_graph.h>
#include <video/of_display_timing.h>
#include <video/of_videomode.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mixel-lvds.h>
+#include <linux/phy/phy-mixel-lvds-combo.h>
#include <linux/regmap.h>
#include <linux/videodev2.h>
+#include <soc/imx8/sc/sci.h>
#include "imx-drm.h"
@@ -50,6 +54,13 @@
#define LDB_DI0_VS_POL_ACT_LOW (1 << 9)
#define LDB_DI1_VS_POL_ACT_LOW (1 << 10)
#define LDB_BGREF_RMODE_INT (1 << 15)
+#define LDB_CH0_10BIT_EN (1 << 22)
+#define LDB_CH1_10BIT_EN (1 << 23)
+#define LDB_CH0_DATA_WIDTH_24BIT (1 << 24)
+#define LDB_CH1_DATA_WIDTH_24BIT (1 << 26)
+#define LDB_CH0_DATA_WIDTH_30BIT (2 << 24)
+#define LDB_CH1_DATA_WIDTH_30BIT (2 << 26)
+#define LDB_CH_SEL (1 << 28)
struct imx_ldb;
@@ -62,6 +73,10 @@ struct imx_ldb_channel {
struct drm_panel *panel;
struct drm_bridge *bridge;
+ struct phy *phy;
+ struct phy *aux_phy;
+ bool phy_is_on;
+
struct device_node *child;
struct i2c_adapter *ddc;
int chno;
@@ -89,16 +104,61 @@ struct bus_mux {
int mask;
};
+struct devtype {
+ int ctrl_reg;
+ struct bus_mux *bus_mux;
+ bool capable_10bit;
+ bool visible_phy;
+ bool has_mux;
+ bool has_ch_sel;
+ bool has_aux_ldb;
+ bool is_imx8;
+ bool use_mixel_phy;
+ bool use_mixel_combo_phy;
+ bool padding_quirks;
+ bool pixel_link_init_quirks;
+ bool pixel_link_valid_quirks;
+ bool pixel_link_enable_quirks;
+
+ /* pixel rate in KHz */
+ unsigned int max_prate_single_mode;
+ unsigned int max_prate_dual_mode;
+};
+
struct imx_ldb {
struct regmap *regmap;
+ struct regmap *aux_regmap;
struct device *dev;
struct imx_ldb_channel channel[2];
struct clk *clk[2]; /* our own clock */
struct clk *clk_sel[4]; /* parent of display clock */
struct clk *clk_parent[4]; /* original parent of clk_sel */
struct clk *clk_pll[2]; /* upstream clock we can adjust */
+ struct clk *clk_pixel;
+ struct clk *clk_bypass;
+ struct clk *clk_aux_pixel;
+ struct clk *clk_aux_bypass;
+ u32 ldb_ctrl_reg;
u32 ldb_ctrl;
const struct bus_mux *lvds_mux;
+ bool capable_10bit;
+ bool visible_phy;
+ bool has_mux;
+ bool has_ch_sel;
+ bool has_aux_ldb;
+ bool is_imx8;
+ bool use_mixel_phy;
+ bool use_mixel_combo_phy;
+ bool padding_quirks;
+ bool pixel_link_init_quirks;
+ bool pixel_link_valid_quirks;
+ bool pixel_link_enable_quirks;
+
+ /* pixel rate in KHz */
+ unsigned int max_prate_single_mode;
+ unsigned int max_prate_dual_mode;
+
+ int id;
};
static enum drm_connector_status imx_ldb_connector_detect(
@@ -118,16 +178,38 @@ static void imx_ldb_ch_set_bus_format(struct imx_ldb_channel *imx_ldb_ch,
break;
case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
if (imx_ldb_ch->chno == 0 || dual)
- ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24;
+ ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 |
+ LDB_CH0_DATA_WIDTH_24BIT;
if (imx_ldb_ch->chno == 1 || dual)
- ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24;
+ ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 |
+ LDB_CH1_DATA_WIDTH_24BIT;
break;
case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
if (imx_ldb_ch->chno == 0 || dual)
ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH0_24 |
+ LDB_CH0_DATA_WIDTH_24BIT |
LDB_BIT_MAP_CH0_JEIDA;
if (imx_ldb_ch->chno == 1 || dual)
ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 |
+ LDB_CH1_DATA_WIDTH_24BIT |
+ LDB_BIT_MAP_CH1_JEIDA;
+ break;
+ case MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG:
+ if (imx_ldb_ch->chno == 0 || dual)
+ ldb->ldb_ctrl |= LDB_CH0_10BIT_EN |
+ LDB_CH0_DATA_WIDTH_30BIT;
+ if (imx_ldb_ch->chno == 1 || dual)
+ ldb->ldb_ctrl |= LDB_CH1_10BIT_EN |
+ LDB_CH1_DATA_WIDTH_30BIT;
+ break;
+ case MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA:
+ if (imx_ldb_ch->chno == 0 || dual)
+ ldb->ldb_ctrl |= LDB_CH0_10BIT_EN |
+ LDB_CH0_DATA_WIDTH_30BIT |
+ LDB_BIT_MAP_CH0_JEIDA;
+ if (imx_ldb_ch->chno == 1 || dual)
+ ldb->ldb_ctrl |= LDB_CH1_10BIT_EN |
+ LDB_CH1_DATA_WIDTH_30BIT |
LDB_BIT_MAP_CH1_JEIDA;
break;
}
@@ -180,8 +262,31 @@ static struct drm_encoder *imx_ldb_connector_best_encoder(
static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno,
unsigned long serial_clk, unsigned long di_clk)
{
+ int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
int ret;
+ if (ldb->is_imx8) {
+ /*
+ * To workaround setting clock rate failure issue
+ * when the system resumes back from PM sleep mode,
+ * we need to get the clock rates before setting
+ * their rates, otherwise, setting the clock rates
+ * will fail.
+ */
+ clk_get_rate(ldb->clk_bypass);
+ clk_get_rate(ldb->clk_pixel);
+ clk_set_rate(ldb->clk_bypass, di_clk);
+ clk_set_rate(ldb->clk_pixel, di_clk);
+
+ if (dual && ldb->has_aux_ldb) {
+ clk_get_rate(ldb->clk_aux_bypass);
+ clk_get_rate(ldb->clk_aux_pixel);
+ clk_set_rate(ldb->clk_aux_bypass, di_clk);
+ clk_set_rate(ldb->clk_aux_pixel, di_clk);
+ }
+ return;
+ }
+
dev_dbg(ldb->dev, "%s: now: %ld want: %ld\n", __func__,
clk_get_rate(ldb->clk_pll[chno]), serial_clk);
clk_set_rate(ldb->clk_pll[chno], serial_clk);
@@ -205,6 +310,170 @@ static void imx_ldb_set_clock(struct imx_ldb *ldb, int mux, int chno,
chno);
}
+#ifndef CONFIG_HAVE_IMX8_SOC
+static void dpu_pixel_link_validate(int dpu_id, int stream_id) {}
+static void dpu_pixel_link_invalidate(int dpu_id, int stream_id) {}
+static void dpu_pixel_link_enable(int dpu_id, int stream_id) {}
+static void dpu_pixel_link_disable(int dpu_id, int stream_id) {}
+#else
+/* FIXME: validate pixel link in a proper manner */
+static void dpu_pixel_link_validate(int dpu_id, int stream_id)
+{
+ sc_err_t sciErr;
+ sc_ipc_t ipcHndl = 0;
+ u32 mu_id;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("Cannot obtain MU ID\n");
+ return;
+ }
+
+ sciErr = sc_ipc_open(&ipcHndl, mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return;
+ }
+
+ if (dpu_id == 0) {
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0,
+ stream_id ? SC_C_PXL_LINK_MST2_VLD : SC_C_PXL_LINK_MST1_VLD, 1);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_PXL_LINK_MST%d_VLD sc_misc_set_control failed! (sciError = %d)\n", stream_id + 1, sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0,
+ stream_id ? SC_C_SYNC_CTRL1 : SC_C_SYNC_CTRL0, 1);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_SYNC_CTRL%d sc_misc_set_control failed! (sciError = %d)\n", stream_id, sciErr);
+ } else if (dpu_id == 1) {
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1,
+ stream_id ? SC_C_PXL_LINK_MST2_VLD : SC_C_PXL_LINK_MST1_VLD, 1);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_PXL_LINK_MST%d_VLD sc_misc_set_control failed! (sciError = %d)\n", stream_id + 1, sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1,
+ stream_id ? SC_C_SYNC_CTRL1 : SC_C_SYNC_CTRL0, 1);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_SYNC_CTRL%d sc_misc_set_control failed! (sciError = %d)\n", stream_id, sciErr);
+ }
+
+ sc_ipc_close(mu_id);
+}
+
+/* FIXME: invalidate pixel link in a proper manner */
+static void dpu_pixel_link_invalidate(int dpu_id, int stream_id)
+{
+ sc_err_t sciErr;
+ sc_ipc_t ipcHndl = 0;
+ u32 mu_id;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("Cannot obtain MU ID\n");
+ return;
+ }
+
+ sciErr = sc_ipc_open(&ipcHndl, mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return;
+ }
+
+ if (dpu_id == 0) {
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0,
+ stream_id ? SC_C_SYNC_CTRL1 : SC_C_SYNC_CTRL0, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_SYNC_CTRL%d sc_misc_set_control failed! (sciError = %d)\n", stream_id, sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0,
+ stream_id ? SC_C_PXL_LINK_MST2_VLD : SC_C_PXL_LINK_MST1_VLD, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_PXL_LINK_MST%d_VLD sc_misc_set_control failed! (sciError = %d)\n", stream_id + 1, sciErr);
+ } else if (dpu_id == 1) {
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1,
+ stream_id ? SC_C_SYNC_CTRL1 : SC_C_SYNC_CTRL0, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_SYNC_CTRL%d sc_misc_set_control failed! (sciError = %d)\n", stream_id, sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1,
+ stream_id ? SC_C_PXL_LINK_MST2_VLD : SC_C_PXL_LINK_MST1_VLD, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_PXL_LINK_MST%d_VLD sc_misc_set_control failed! (sciError = %d)\n", stream_id + 1, sciErr);
+
+ }
+
+ sc_ipc_close(mu_id);
+}
+
+/* FIXME: enable pixel link in a proper manner */
+static void dpu_pixel_link_enable(int dpu_id, int stream_id)
+{
+ sc_err_t sciErr;
+ sc_ipc_t ipcHndl = 0;
+ u32 mu_id;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("Cannot obtain MU ID\n");
+ return;
+ }
+
+ sciErr = sc_ipc_open(&ipcHndl, mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return;
+ }
+
+ if (dpu_id == 0) {
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0,
+ stream_id ? SC_C_PXL_LINK_MST2_ENB : SC_C_PXL_LINK_MST1_ENB, 1);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_PXL_LINK_MST%d_ENB sc_misc_set_control failed! (sciError = %d)\n", stream_id + 1, sciErr);
+ } else if (dpu_id == 1) {
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1,
+ stream_id ? SC_C_PXL_LINK_MST2_ENB : SC_C_PXL_LINK_MST1_ENB, 1);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_PXL_LINK_MST%d_ENB sc_misc_set_control failed! (sciError = %d)\n", stream_id + 1, sciErr);
+ }
+
+ sc_ipc_close(mu_id);
+}
+
+/* FIXME: disable pixel link in a proper manner */
+static void dpu_pixel_link_disable(int dpu_id, int stream_id)
+{
+ sc_err_t sciErr;
+ sc_ipc_t ipcHndl = 0;
+ u32 mu_id;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("Cannot obtain MU ID\n");
+ return;
+ }
+
+ sciErr = sc_ipc_open(&ipcHndl, mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return;
+ }
+
+ if (dpu_id == 0) {
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0,
+ stream_id ? SC_C_PXL_LINK_MST2_ENB : SC_C_PXL_LINK_MST1_ENB, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_PXL_LINK_MST%d_ENB sc_misc_set_control failed! (sciError = %d)\n", stream_id + 1, sciErr);
+ } else if (dpu_id == 1) {
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1,
+ stream_id ? SC_C_PXL_LINK_MST2_ENB : SC_C_PXL_LINK_MST1_ENB, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_PXL_LINK_MST%d_ENB sc_misc_set_control failed! (sciError = %d)\n", stream_id + 1, sciErr);
+ }
+
+ sc_ipc_close(mu_id);
+}
+#endif
+
static void imx_ldb_encoder_enable(struct drm_encoder *encoder)
{
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
@@ -214,16 +483,37 @@ static void imx_ldb_encoder_enable(struct drm_encoder *encoder)
drm_panel_prepare(imx_ldb_ch->panel);
- if (dual) {
- clk_set_parent(ldb->clk_sel[mux], ldb->clk[0]);
- clk_set_parent(ldb->clk_sel[mux], ldb->clk[1]);
+ if (ldb->is_imx8) {
+ clk_prepare_enable(ldb->clk_pixel);
+ clk_prepare_enable(ldb->clk_bypass);
- clk_prepare_enable(ldb->clk[0]);
- clk_prepare_enable(ldb->clk[1]);
- } else {
- clk_set_parent(ldb->clk_sel[mux], ldb->clk[imx_ldb_ch->chno]);
+ if (dual && ldb->has_aux_ldb) {
+ clk_prepare_enable(ldb->clk_aux_pixel);
+ clk_prepare_enable(ldb->clk_aux_bypass);
+ }
}
+ if (ldb->has_mux) {
+ if (dual) {
+ clk_set_parent(ldb->clk_sel[mux], ldb->clk[0]);
+ clk_set_parent(ldb->clk_sel[mux], ldb->clk[1]);
+
+ clk_prepare_enable(ldb->clk[0]);
+ clk_prepare_enable(ldb->clk[1]);
+ } else {
+ clk_set_parent(ldb->clk_sel[mux],
+ ldb->clk[imx_ldb_ch->chno]);
+ }
+ }
+
+ /*
+ * LDB frontend doesn't know if the auxiliary LDB is used or not.
+ * Enable pixel link after dual or single LDB clocks are enabled
+ * so that the dual LDBs are synchronized.
+ */
+ if (ldb->has_aux_ldb && ldb->pixel_link_enable_quirks)
+ dpu_pixel_link_enable(0, ldb->id);
+
if (imx_ldb_ch == &ldb->channel[0] || dual) {
ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
if (mux == 0 || ldb->lvds_mux)
@@ -251,7 +541,33 @@ static void imx_ldb_encoder_enable(struct drm_encoder *encoder)
mux << lvds_mux->shift);
}
- regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
+ regmap_write(ldb->regmap, ldb->ldb_ctrl_reg, ldb->ldb_ctrl);
+ if (dual && ldb->has_aux_ldb)
+ regmap_write(ldb->aux_regmap, ldb->ldb_ctrl_reg,
+ ldb->ldb_ctrl | LDB_CH_SEL);
+
+ if (dual) {
+ phy_power_on(ldb->channel[0].phy);
+ if (ldb->has_aux_ldb)
+ phy_power_on(ldb->channel[0].aux_phy);
+ else
+ phy_power_on(ldb->channel[1].phy);
+
+ ldb->channel[0].phy_is_on = true;
+ if (!ldb->has_aux_ldb)
+ ldb->channel[1].phy_is_on = true;
+ } else {
+ phy_power_on(imx_ldb_ch->phy);
+
+ imx_ldb_ch->phy_is_on = true;
+ }
+
+ if (ldb->pixel_link_valid_quirks) {
+ if (ldb->use_mixel_phy)
+ dpu_pixel_link_validate(ldb->id, 1);
+ else if (ldb->use_mixel_combo_phy)
+ dpu_pixel_link_validate(0, ldb->id);
+ }
drm_panel_enable(imx_ldb_ch->panel);
}
@@ -270,39 +586,163 @@ imx_ldb_encoder_atomic_mode_set(struct drm_encoder *encoder,
int mux = drm_of_encoder_active_port_id(imx_ldb_ch->child, encoder);
u32 bus_format = imx_ldb_ch->bus_format;
- if (mode->clock > 170000) {
+ if (mode->clock > ldb->max_prate_dual_mode) {
dev_warn(ldb->dev,
- "%s: mode exceeds 170 MHz pixel clock\n", __func__);
+ "%s: mode exceeds %u MHz pixel clock\n", __func__,
+ ldb->max_prate_dual_mode / 1000);
}
- if (mode->clock > 85000 && !dual) {
+ if (mode->clock > ldb->max_prate_single_mode && !dual) {
dev_warn(ldb->dev,
- "%s: mode exceeds 85 MHz pixel clock\n", __func__);
+ "%s: mode exceeds %u MHz pixel clock\n", __func__,
+ ldb->max_prate_single_mode / 1000);
}
if (dual) {
serial_clk = 3500UL * mode->clock;
imx_ldb_set_clock(ldb, mux, 0, serial_clk, di_clk);
imx_ldb_set_clock(ldb, mux, 1, serial_clk, di_clk);
+
+ if (ldb->use_mixel_phy) {
+ mixel_phy_lvds_set_phy_speed(ldb->channel[0].phy,
+ di_clk / 2);
+ mixel_phy_lvds_set_phy_speed(ldb->channel[1].phy,
+ di_clk / 2);
+ } else if (ldb->use_mixel_combo_phy) {
+ mixel_phy_combo_lvds_set_phy_speed(ldb->channel[0].phy,
+ di_clk / 2);
+ mixel_phy_combo_lvds_set_phy_speed(ldb->channel[0].aux_phy,
+ di_clk / 2);
+ }
} else {
serial_clk = 7000UL * mode->clock;
imx_ldb_set_clock(ldb, mux, imx_ldb_ch->chno, serial_clk,
di_clk);
+
+ if (ldb->use_mixel_phy)
+ mixel_phy_lvds_set_phy_speed(imx_ldb_ch->phy, di_clk);
+ else if (ldb->use_mixel_combo_phy)
+ mixel_phy_combo_lvds_set_phy_speed(imx_ldb_ch->phy,
+ di_clk);
+ }
+
+ if (ldb->has_ch_sel) {
+ if (imx_ldb_ch == &ldb->channel[0])
+ ldb->ldb_ctrl &= ~LDB_CH_SEL;
+ if (imx_ldb_ch == &ldb->channel[1])
+ ldb->ldb_ctrl |= LDB_CH_SEL;
}
/* FIXME - assumes straight connections DI0 --> CH0, DI1 --> CH1 */
if (imx_ldb_ch == &ldb->channel[0] || dual) {
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
ldb->ldb_ctrl |= LDB_DI0_VS_POL_ACT_LOW;
- else if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+ else
ldb->ldb_ctrl &= ~LDB_DI0_VS_POL_ACT_LOW;
}
if (imx_ldb_ch == &ldb->channel[1] || dual) {
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
ldb->ldb_ctrl |= LDB_DI1_VS_POL_ACT_LOW;
- else if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+ else
ldb->ldb_ctrl &= ~LDB_DI1_VS_POL_ACT_LOW;
}
+ /* settle vsync polarity and channel selection down early */
+ if (dual && ldb->has_aux_ldb) {
+ regmap_write(ldb->regmap, ldb->ldb_ctrl_reg, ldb->ldb_ctrl);
+ regmap_write(ldb->aux_regmap, ldb->ldb_ctrl_reg,
+ ldb->ldb_ctrl | LDB_CH_SEL);
+ }
+
+ if (dual) {
+ if (ldb->use_mixel_phy) {
+ /* VSYNC */
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC) {
+ mixel_phy_lvds_set_vsync_pol(
+ ldb->channel[0].phy, false);
+ mixel_phy_lvds_set_vsync_pol(
+ ldb->channel[1].phy, false);
+ } else {
+ mixel_phy_lvds_set_vsync_pol(
+ ldb->channel[0].phy, true);
+ mixel_phy_lvds_set_vsync_pol(
+ ldb->channel[1].phy, true);
+ }
+ /* HSYNC */
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC) {
+ mixel_phy_lvds_set_hsync_pol(
+ ldb->channel[0].phy, false);
+ mixel_phy_lvds_set_hsync_pol(
+ ldb->channel[1].phy, false);
+ } else {
+ mixel_phy_lvds_set_hsync_pol(
+ ldb->channel[0].phy, true);
+ mixel_phy_lvds_set_hsync_pol(
+ ldb->channel[1].phy, true);
+ }
+ } else if (ldb->use_mixel_combo_phy) {
+ /* VSYNC */
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC) {
+ mixel_phy_combo_lvds_set_vsync_pol(
+ ldb->channel[0].phy, false);
+ mixel_phy_combo_lvds_set_vsync_pol(
+ ldb->channel[0].aux_phy, false);
+ } else {
+ mixel_phy_combo_lvds_set_vsync_pol(
+ ldb->channel[0].phy, true);
+ mixel_phy_combo_lvds_set_vsync_pol(
+ ldb->channel[0].aux_phy, true);
+ }
+ /* HSYNC */
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC) {
+ mixel_phy_combo_lvds_set_hsync_pol(
+ ldb->channel[0].phy, false);
+ mixel_phy_combo_lvds_set_hsync_pol(
+ ldb->channel[0].aux_phy, false);
+ } else {
+ mixel_phy_combo_lvds_set_hsync_pol(
+ ldb->channel[0].phy, true);
+ mixel_phy_combo_lvds_set_hsync_pol(
+ ldb->channel[0].aux_phy, true);
+ }
+ }
+ } else {
+ if (ldb->use_mixel_phy) {
+ /* VSYNC */
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ mixel_phy_lvds_set_vsync_pol(imx_ldb_ch->phy,
+ false);
+ else
+ mixel_phy_lvds_set_vsync_pol(imx_ldb_ch->phy,
+ true);
+ /* HSYNC */
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ mixel_phy_lvds_set_hsync_pol(imx_ldb_ch->phy,
+ false);
+ else
+ mixel_phy_lvds_set_hsync_pol(imx_ldb_ch->phy,
+ true);
+ } else if (ldb->use_mixel_combo_phy) {
+ /* VSYNC */
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ mixel_phy_combo_lvds_set_vsync_pol(
+ imx_ldb_ch->phy,
+ false);
+ else
+ mixel_phy_combo_lvds_set_vsync_pol(
+ imx_ldb_ch->phy,
+ true);
+ /* HSYNC */
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ mixel_phy_combo_lvds_set_hsync_pol(
+ imx_ldb_ch->phy,
+ false);
+ else
+ mixel_phy_combo_lvds_set_hsync_pol(
+ imx_ldb_ch->phy,
+ true);
+ }
+ }
+
if (!bus_format) {
struct drm_connector *connector = connector_state->connector;
struct drm_display_info *di = &connector->display_info;
@@ -317,34 +757,64 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
{
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
struct imx_ldb *ldb = imx_ldb_ch->ldb;
+ int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
int mux, ret;
- /*
- * imx_ldb_encoder_disable is called by
- * drm_helper_disable_unused_functions without
- * the encoder being enabled before.
- */
- if (imx_ldb_ch == &ldb->channel[0] &&
- (ldb->ldb_ctrl & LDB_CH0_MODE_EN_MASK) == 0)
- return;
- else if (imx_ldb_ch == &ldb->channel[1] &&
- (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0)
- return;
-
drm_panel_disable(imx_ldb_ch->panel);
+ if (ldb->pixel_link_valid_quirks) {
+ if (ldb->use_mixel_phy)
+ dpu_pixel_link_invalidate(ldb->id, 1);
+ else if (ldb->use_mixel_combo_phy)
+ dpu_pixel_link_invalidate(0, ldb->id);
+ }
+
+ if (dual) {
+ phy_power_off(ldb->channel[0].phy);
+ if (ldb->has_aux_ldb)
+ phy_power_off(ldb->channel[0].aux_phy);
+ else
+ phy_power_off(ldb->channel[1].phy);
+
+ ldb->channel[0].phy_is_on = false;
+ if (!ldb->has_aux_ldb)
+ ldb->channel[1].phy_is_on = false;
+ } else {
+ phy_power_off(imx_ldb_ch->phy);
+
+ imx_ldb_ch->phy_is_on = false;
+ }
+
if (imx_ldb_ch == &ldb->channel[0])
ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
else if (imx_ldb_ch == &ldb->channel[1])
ldb->ldb_ctrl &= ~LDB_CH1_MODE_EN_MASK;
- regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
+ regmap_write(ldb->regmap, ldb->ldb_ctrl_reg, ldb->ldb_ctrl);
+ if (dual && ldb->has_aux_ldb)
+ regmap_write(ldb->aux_regmap, ldb->ldb_ctrl_reg, ldb->ldb_ctrl);
- if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
- clk_disable_unprepare(ldb->clk[0]);
- clk_disable_unprepare(ldb->clk[1]);
+ if (ldb->is_imx8) {
+ clk_disable_unprepare(ldb->clk_bypass);
+ clk_disable_unprepare(ldb->clk_pixel);
+
+ if (dual && ldb->has_aux_ldb) {
+ clk_disable_unprepare(ldb->clk_aux_bypass);
+ clk_disable_unprepare(ldb->clk_aux_pixel);
+ }
+ } else {
+ if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
+ clk_disable_unprepare(ldb->clk[0]);
+ clk_disable_unprepare(ldb->clk[1]);
+ }
}
+ if (ldb->has_aux_ldb && ldb->pixel_link_enable_quirks)
+ dpu_pixel_link_disable(0, ldb->id);
+
+ if (!ldb->has_mux)
+ goto unprepare_panel;
+
if (ldb->lvds_mux) {
const struct bus_mux *lvds_mux = NULL;
@@ -367,6 +837,7 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
"unable to set di%d parent clock to original parent\n",
mux);
+unprepare_panel:
drm_panel_unprepare(imx_ldb_ch->panel);
}
@@ -376,6 +847,7 @@ static int imx_ldb_encoder_atomic_check(struct drm_encoder *encoder,
{
struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
+ struct imx_ldb *ldb = imx_ldb_ch->ldb;
struct drm_display_info *di = &conn_state->connector->display_info;
u32 bus_format = imx_ldb_ch->bus_format;
@@ -389,11 +861,23 @@ static int imx_ldb_encoder_atomic_check(struct drm_encoder *encoder,
}
switch (bus_format) {
case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
- imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB666_1X18;
+ if (ldb->padding_quirks)
+ imx_crtc_state->bus_format =
+ MEDIA_BUS_FMT_RGB666_1X30_PADLO;
+ else
+ imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB666_1X18;
break;
case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
- imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+ if (ldb->padding_quirks)
+ imx_crtc_state->bus_format =
+ MEDIA_BUS_FMT_RGB888_1X30_PADLO;
+ else
+ imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+ break;
+ case MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG:
+ case MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA:
+ imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB101010_1X30;
break;
default:
return -EINVAL;
@@ -436,6 +920,9 @@ static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno)
{
char clkname[16];
+ if (ldb->is_imx8)
+ return 0;
+
snprintf(clkname, sizeof(clkname), "di%d", chno);
ldb->clk[chno] = devm_clk_get(ldb->dev, clkname);
if (IS_ERR(ldb->clk[chno]))
@@ -519,12 +1006,15 @@ struct imx_ldb_bit_mapping {
};
static const struct imx_ldb_bit_mapping imx_ldb_bit_mappings[] = {
- { MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, 18, "spwg" },
- { MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, 24, "spwg" },
- { MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 24, "jeida" },
+ { MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, 18, "spwg" },
+ { MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, 24, "spwg" },
+ { MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, 24, "jeida" },
+ { MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG, 30, "spwg" },
+ { MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA, 30, "jeida" },
};
-static u32 of_get_bus_format(struct device *dev, struct device_node *np)
+static u32 of_get_bus_format(struct device *dev, struct imx_ldb *ldb,
+ struct device_node *np)
{
const char *bm;
u32 datawidth = 0;
@@ -536,6 +1026,11 @@ static u32 of_get_bus_format(struct device *dev, struct device_node *np)
of_property_read_u32(np, "fsl,data-width", &datawidth);
+ if (!ldb->capable_10bit && datawidth == 30) {
+ dev_err(dev, "invalid data width: %d-bit\n", datawidth);
+ return -ENOENT;
+ }
+
for (i = 0; i < ARRAY_SIZE(imx_ldb_bit_mappings); i++) {
if (!strcasecmp(bm, imx_ldb_bit_mappings[i].mapping) &&
datawidth == imx_ldb_bit_mappings[i].datawidth)
@@ -547,6 +1042,16 @@ static u32 of_get_bus_format(struct device *dev, struct device_node *np)
return -ENOENT;
}
+static struct devtype imx53_ldb_devtype = {
+ .ctrl_reg = IOMUXC_GPR2,
+ .bus_mux = NULL,
+ .capable_10bit = false,
+ .visible_phy = false,
+ .has_mux = true,
+ .max_prate_single_mode = 85000,
+ .max_prate_dual_mode = 150000,
+};
+
static struct bus_mux imx6q_lvds_mux[2] = {
{
.reg = IOMUXC_GPR3,
@@ -559,15 +1064,57 @@ static struct bus_mux imx6q_lvds_mux[2] = {
}
};
+static struct devtype imx6q_ldb_devtype = {
+ .ctrl_reg = IOMUXC_GPR2,
+ .bus_mux = imx6q_lvds_mux,
+ .capable_10bit = false,
+ .visible_phy = false,
+ .has_mux = true,
+ .max_prate_single_mode = 85000,
+ .max_prate_dual_mode = 170000,
+};
+
+static struct devtype imx8qm_ldb_devtype = {
+ .ctrl_reg = 0x10e0,
+ .bus_mux = NULL,
+ .capable_10bit = true,
+ .visible_phy = true,
+ .is_imx8 = true,
+ .use_mixel_phy = true,
+ .padding_quirks = true,
+ .pixel_link_valid_quirks = true,
+ .max_prate_single_mode = 150000,
+ .max_prate_dual_mode = 300000,
+};
+
+static struct devtype imx8qxp_ldb_devtype = {
+ .ctrl_reg = 0x10e0,
+ .bus_mux = NULL,
+ .visible_phy = true,
+ .has_ch_sel = true,
+ .has_aux_ldb = true,
+ .is_imx8 = true,
+ .use_mixel_combo_phy = true,
+ .padding_quirks = true,
+ .pixel_link_init_quirks = true,
+ .pixel_link_valid_quirks = true,
+ .pixel_link_enable_quirks = true,
+ .max_prate_single_mode = 150000,
+ .max_prate_dual_mode = 300000,
+};
+
/*
- * For a device declaring compatible = "fsl,imx6q-ldb", "fsl,imx53-ldb",
- * of_match_device will walk through this list and take the first entry
- * matching any of its compatible values. Therefore, the more generic
- * entries (in this case fsl,imx53-ldb) need to be ordered last.
+ * For a device declaring compatible = "fsl,imx8qxp-ldb", "fsl,imx8qm-ldb",
+ * "fsl,imx6q-ldb", "fsl,imx53-ldb", of_match_device will walk through this
+ * list and take the first entry matching any of its compatible values.
+ * Therefore, the more generic entries (in this case fsl,imx53-ldb) need to be
+ * ordered last.
*/
static const struct of_device_id imx_ldb_dt_ids[] = {
- { .compatible = "fsl,imx6q-ldb", .data = imx6q_lvds_mux, },
- { .compatible = "fsl,imx53-ldb", .data = NULL, },
+ { .compatible = "fsl,imx8qxp-ldb", .data = &imx8qxp_ldb_devtype, },
+ { .compatible = "fsl,imx8qm-ldb", .data = &imx8qm_ldb_devtype, },
+ { .compatible = "fsl,imx6q-ldb", .data = &imx6q_ldb_devtype, },
+ { .compatible = "fsl,imx53-ldb", .data = &imx53_ldb_devtype, },
{ }
};
MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
@@ -612,12 +1159,68 @@ static int imx_ldb_panel_ddc(struct device *dev,
return 0;
}
+#ifndef CONFIG_HAVE_IMX8_SOC
+static void ldb_pixel_link_init(int id, bool dual) {}
+#else
+static void ldb_pixel_link_init(int id, bool dual)
+{
+ sc_err_t sciErr;
+ sc_ipc_t ipcHndl = 0;
+ u32 mu_id;
+ bool is_aux = false;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("Cannot obtain MU ID\n");
+ return;
+ }
+
+ sciErr = sc_ipc_open(&ipcHndl, mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return;
+ }
+
+again:
+ if (id == 0) {
+ sc_misc_set_control(ipcHndl, SC_R_MIPI_0, SC_C_MODE, 1);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_MIPI_%d MODE failed %d!\n", id, sciErr);
+ sc_misc_set_control(ipcHndl, SC_R_MIPI_0, SC_C_DUAL_MODE, is_aux);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_MIPI_%d DUAL_MODE failed %d!\n", id, sciErr);
+ sc_misc_set_control(ipcHndl, SC_R_MIPI_0, SC_C_PXL_LINK_SEL, is_aux);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_MIPI_%d PXL_LINK_SEL failed %d!\n", id, sciErr);
+ } else {
+ sc_misc_set_control(ipcHndl, SC_R_MIPI_1, SC_C_MODE, 1);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_MIPI_%d MODE failed %d!\n", id, sciErr);
+ sc_misc_set_control(ipcHndl, SC_R_MIPI_1, SC_C_DUAL_MODE, is_aux);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_MIPI_%d DUAL_MODE failed %d!\n", id, sciErr);
+ sc_misc_set_control(ipcHndl, SC_R_MIPI_1, SC_C_PXL_LINK_SEL, is_aux);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_MIPI_%d PXL_LINK_SEL failed %d!\n", id, sciErr);
+ }
+
+ if (dual && !is_aux) {
+ id ^= 1;
+ is_aux = true;
+ goto again;
+ }
+
+ sc_ipc_close(mu_id);
+}
+#endif
+
static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
{
struct drm_device *drm = data;
struct device_node *np = dev->of_node;
const struct of_device_id *of_id =
of_match_device(imx_ldb_dt_ids, dev);
+ const struct devtype *devtype = of_id->data;
struct device_node *child;
struct imx_ldb *imx_ldb;
int dual;
@@ -638,46 +1241,103 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
regmap_write(imx_ldb->regmap, IOMUXC_GPR2, 0);
imx_ldb->dev = dev;
-
- if (of_id)
- imx_ldb->lvds_mux = of_id->data;
+ imx_ldb->ldb_ctrl_reg = devtype->ctrl_reg;
+ imx_ldb->lvds_mux = devtype->bus_mux;
+ imx_ldb->capable_10bit = devtype->capable_10bit;
+ imx_ldb->visible_phy = devtype->visible_phy;
+ imx_ldb->has_mux = devtype->has_mux;
+ imx_ldb->has_ch_sel = devtype->has_ch_sel;
+ imx_ldb->has_aux_ldb = devtype->has_aux_ldb;
+ imx_ldb->is_imx8 = devtype->is_imx8;
+ imx_ldb->use_mixel_phy = devtype->use_mixel_phy;
+ imx_ldb->use_mixel_combo_phy = devtype->use_mixel_combo_phy;
+ imx_ldb->padding_quirks = devtype->padding_quirks;
+ imx_ldb->pixel_link_init_quirks = devtype->pixel_link_init_quirks;
+ imx_ldb->pixel_link_valid_quirks = devtype->pixel_link_valid_quirks;
+ imx_ldb->pixel_link_enable_quirks = devtype->pixel_link_enable_quirks;
+ imx_ldb->max_prate_single_mode = devtype->max_prate_single_mode;
+ imx_ldb->max_prate_dual_mode = devtype->max_prate_dual_mode;
dual = of_property_read_bool(np, "fsl,dual-channel");
if (dual)
imx_ldb->ldb_ctrl |= LDB_SPLIT_MODE_EN;
- /*
- * There are three different possible clock mux configurations:
- * i.MX53: ipu1_di0_sel, ipu1_di1_sel
- * i.MX6q: ipu1_di0_sel, ipu1_di1_sel, ipu2_di0_sel, ipu2_di1_sel
- * i.MX6dl: ipu1_di0_sel, ipu1_di1_sel, lcdif_sel
- * Map them all to di0_sel...di3_sel.
- */
- for (i = 0; i < 4; i++) {
- char clkname[16];
-
- sprintf(clkname, "di%d_sel", i);
- imx_ldb->clk_sel[i] = devm_clk_get(imx_ldb->dev, clkname);
- if (IS_ERR(imx_ldb->clk_sel[i])) {
- ret = PTR_ERR(imx_ldb->clk_sel[i]);
- imx_ldb->clk_sel[i] = NULL;
- break;
+ if (dual && imx_ldb->has_aux_ldb) {
+ imx_ldb->aux_regmap =
+ syscon_regmap_lookup_by_phandle(np, "aux-gpr");
+ if (IS_ERR(imx_ldb->aux_regmap)) {
+ dev_err(dev, "failed to get parent auxiliary regmap\n");
+ return PTR_ERR(imx_ldb->aux_regmap);
}
+ }
- imx_ldb->clk_parent[i] = clk_get_parent(imx_ldb->clk_sel[i]);
+ if (imx_ldb->is_imx8) {
+ imx_ldb->clk_pixel = devm_clk_get(imx_ldb->dev, "pixel");
+ if (IS_ERR(imx_ldb->clk_pixel))
+ return PTR_ERR(imx_ldb->clk_pixel);
+
+ imx_ldb->clk_bypass = devm_clk_get(imx_ldb->dev, "bypass");
+ if (IS_ERR(imx_ldb->clk_bypass))
+ return PTR_ERR(imx_ldb->clk_bypass);
+
+ if (dual && imx_ldb->has_aux_ldb) {
+ imx_ldb->clk_aux_pixel =
+ devm_clk_get(imx_ldb->dev, "aux_pixel");
+ if (IS_ERR(imx_ldb->clk_aux_pixel))
+ return PTR_ERR(imx_ldb->clk_aux_pixel);
+
+ imx_ldb->clk_aux_bypass =
+ devm_clk_get(imx_ldb->dev, "aux_bypass");
+ if (IS_ERR(imx_ldb->clk_aux_bypass))
+ return PTR_ERR(imx_ldb->clk_aux_bypass);
+ }
+ }
+
+ if (imx_ldb->has_mux) {
+ /*
+ * There are three different possible clock mux configurations:
+ * i.MX53: ipu1_di0_sel, ipu1_di1_sel
+ * i.MX6q: ipu1_di0_sel, ipu1_di1_sel, ipu2_di0_sel,
+ * ipu2_di1_sel
+ * i.MX6dl: ipu1_di0_sel, ipu1_di1_sel, lcdif_sel
+ * Map them all to di0_sel...di3_sel.
+ */
+ for (i = 0; i < 4; i++) {
+ char clkname[16];
+
+ sprintf(clkname, "di%d_sel", i);
+ imx_ldb->clk_sel[i] = devm_clk_get(imx_ldb->dev,
+ clkname);
+ if (IS_ERR(imx_ldb->clk_sel[i])) {
+ ret = PTR_ERR(imx_ldb->clk_sel[i]);
+ imx_ldb->clk_sel[i] = NULL;
+ break;
+ }
+
+ imx_ldb->clk_parent[i] =
+ clk_get_parent(imx_ldb->clk_sel[i]);
+ }
+ if (i == 0)
+ return ret;
}
- if (i == 0)
- return ret;
for_each_child_of_node(np, child) {
struct imx_ldb_channel *channel;
struct device_node *ep;
int bus_format;
+ int port_reg;
+ bool auxiliary_ch = false;
ret = of_property_read_u32(child, "reg", &i);
if (ret || i < 0 || i > 1)
return -EINVAL;
+ if (dual && imx_ldb->use_mixel_phy && i > 0) {
+ auxiliary_ch = true;
+ channel = &imx_ldb->channel[i];
+ goto get_phy;
+ }
+
if (!of_device_is_available(child))
continue;
@@ -693,11 +1353,14 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
/*
* The output port is port@4 with an external 4-port mux or
- * port@2 with the internal 2-port mux.
+ * port@2 with the internal 2-port mux or port@1 without mux.
*/
- ep = of_graph_get_endpoint_by_regs(child,
- imx_ldb->lvds_mux ? 4 : 2,
- -1);
+ if (imx_ldb->has_mux)
+ port_reg = imx_ldb->lvds_mux ? 4 : 2;
+ else
+ port_reg = 1;
+
+ ep = of_graph_get_endpoint_by_regs(child, port_reg, -1);
if (ep) {
struct device_node *remote;
@@ -724,7 +1387,7 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
return ret;
}
- bus_format = of_get_bus_format(dev, child);
+ bus_format = of_get_bus_format(dev, imx_ldb, child);
if (bus_format == -EINVAL) {
/*
* If no bus format was specified in the device tree,
@@ -741,6 +1404,57 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
}
channel->bus_format = bus_format;
+get_phy:
+ if (imx_ldb->visible_phy) {
+ channel->phy = devm_of_phy_get(dev, child, "ldb_phy");
+ if (IS_ERR(channel->phy)) {
+ ret = PTR_ERR(channel->phy);
+ if (ret == -EPROBE_DEFER) {
+ return ret;
+ } else {
+ dev_err(dev,
+ "can't get channel%d phy: %d\n",
+ channel->chno, ret);
+ return ret;
+ }
+ }
+
+ ret = phy_init(channel->phy);
+ if (ret < 0) {
+ dev_err(dev,
+ "failed to initialize channel%d phy: %d\n",
+ channel->chno, ret);
+ return ret;
+ }
+
+ if (dual && imx_ldb->has_aux_ldb) {
+ channel->aux_phy =
+ devm_of_phy_get(dev, child, "aux_ldb_phy");
+ if (IS_ERR(channel->aux_phy)) {
+ ret = PTR_ERR(channel->aux_phy);
+ if (ret == -EPROBE_DEFER) {
+ return ret;
+ } else {
+ dev_err(dev,
+ "can't get channel%d aux phy: %d\n",
+ channel->chno, ret);
+ return ret;
+ }
+ }
+
+ ret = phy_init(channel->aux_phy);
+ if (ret < 0) {
+ dev_err(dev,
+ "failed to initialize channel%d aux phy: %d\n",
+ channel->chno, ret);
+ return ret;
+ }
+ }
+
+ if (auxiliary_ch)
+ continue;
+ }
+
ret = imx_ldb_register(drm, channel);
if (ret)
return ret;
@@ -748,6 +1462,13 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
dev_set_drvdata(dev, imx_ldb);
+ if (imx_ldb->pixel_link_valid_quirks ||
+ imx_ldb->pixel_link_init_quirks)
+ imx_ldb->id = of_alias_get_id(np, "ldb");
+
+ if (imx_ldb->pixel_link_init_quirks)
+ ldb_pixel_link_init(imx_ldb->id, dual);
+
return 0;
}
@@ -755,11 +1476,22 @@ static void imx_ldb_unbind(struct device *dev, struct device *master,
void *data)
{
struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
+ int dual = imx_ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
int i;
for (i = 0; i < 2; i++) {
struct imx_ldb_channel *channel = &imx_ldb->channel[i];
+ if (channel->phy_is_on) {
+ phy_power_off(channel->phy);
+ if (dual && imx_ldb->has_aux_ldb)
+ phy_power_off(channel->aux_phy);
+ }
+
+ phy_exit(channel->phy);
+ if (dual && imx_ldb->has_aux_ldb && i == 0)
+ phy_exit(channel->aux_phy);
+
if (channel->bridge)
drm_bridge_detach(channel->bridge);
if (channel->panel)
@@ -768,6 +1500,8 @@ static void imx_ldb_unbind(struct device *dev, struct device *master,
kfree(channel->edid);
i2c_put_adapter(channel->ddc);
}
+
+ dev_set_drvdata(dev, NULL);
}
static const struct component_ops imx_ldb_ops = {
@@ -786,12 +1520,72 @@ static int imx_ldb_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int imx_ldb_suspend(struct device *dev)
+{
+ struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
+ struct imx_ldb_channel *channel;
+ int i, dual;
+
+ if (imx_ldb == NULL)
+ return 0;
+
+ dual = imx_ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
+
+ for (i = 0; i < 2; i++) {
+ channel = &imx_ldb->channel[i];
+
+ if (channel->phy_is_on)
+ phy_power_off(channel->phy);
+
+ phy_exit(channel->phy);
+
+ if (dual && imx_ldb->has_aux_ldb && i == 0) {
+ if (channel->phy_is_on)
+ phy_power_off(channel->aux_phy);
+
+ phy_exit(channel->aux_phy);
+ }
+ }
+
+ return 0;
+}
+
+static int imx_ldb_resume(struct device *dev)
+{
+ struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
+ int i, dual;
+
+ if (imx_ldb == NULL)
+ return 0;
+
+ dual = imx_ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
+
+ if (imx_ldb->visible_phy) {
+ for (i = 0; i < 2; i++) {
+ phy_init(imx_ldb->channel[i].phy);
+
+ if (dual && imx_ldb->has_aux_ldb && i == 0)
+ phy_init(imx_ldb->channel[i].aux_phy);
+ }
+ }
+
+ if (imx_ldb->pixel_link_init_quirks)
+ ldb_pixel_link_init(imx_ldb->id, dual);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(imx_ldb_pm_ops, imx_ldb_suspend, imx_ldb_resume);
+
static struct platform_driver imx_ldb_driver = {
.probe = imx_ldb_probe,
.remove = imx_ldb_remove,
.driver = {
.of_match_table = imx_ldb_dt_ids,
.name = DRIVER_NAME,
+ .pm = &imx_ldb_pm_ops,
},
};
diff --git a/drivers/gpu/drm/imx/ipuv3/Kconfig b/drivers/gpu/drm/imx/ipuv3/Kconfig
new file mode 100644
index 000000000000..718da3784070
--- /dev/null
+++ b/drivers/gpu/drm/imx/ipuv3/Kconfig
@@ -0,0 +1,6 @@
+config DRM_IMX_IPUV3
+ tristate
+ depends on DRM_IMX
+ depends on IMX_IPUV3_CORE
+ default y if DRM_IMX=y
+ default m if DRM_IMX=m
diff --git a/drivers/gpu/drm/imx/ipuv3/Makefile b/drivers/gpu/drm/imx/ipuv3/Makefile
new file mode 100644
index 000000000000..e8ccced92385
--- /dev/null
+++ b/drivers/gpu/drm/imx/ipuv3/Makefile
@@ -0,0 +1,4 @@
+ccflags-y += -Idrivers/gpu/drm/imx
+
+imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o ipuv3-kms.o
+obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c
index 8dbba61a2708..4c7f2e101bf3 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-crtc.c
@@ -28,6 +28,7 @@
#include <video/imx-ipu-v3.h>
#include "imx-drm.h"
+#include "ipuv3-kms.h"
#include "ipuv3-plane.h"
#define DRIVER_DESC "i.MX IPUv3 Graphics"
@@ -86,7 +87,7 @@ static void ipu_crtc_atomic_disable(struct drm_crtc *crtc,
drm_crtc_vblank_off(crtc);
}
-static void imx_drm_crtc_reset(struct drm_crtc *crtc)
+static void ipu_crtc_reset(struct drm_crtc *crtc)
{
struct imx_crtc_state *state;
@@ -106,7 +107,7 @@ static void imx_drm_crtc_reset(struct drm_crtc *crtc)
state->base.crtc = crtc;
}
-static struct drm_crtc_state *imx_drm_crtc_duplicate_state(struct drm_crtc *crtc)
+static struct drm_crtc_state *ipu_crtc_duplicate_state(struct drm_crtc *crtc)
{
struct imx_crtc_state *state;
@@ -122,25 +123,25 @@ static struct drm_crtc_state *imx_drm_crtc_duplicate_state(struct drm_crtc *crtc
return &state->base;
}
-static void imx_drm_crtc_destroy_state(struct drm_crtc *crtc,
- struct drm_crtc_state *state)
+static void ipu_crtc_destroy_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
{
__drm_atomic_helper_crtc_destroy_state(state);
kfree(to_imx_crtc_state(state));
}
-static void imx_drm_crtc_destroy(struct drm_crtc *crtc)
+static void ipu_crtc_destroy(struct drm_crtc *crtc)
{
imx_drm_remove_crtc(to_ipu_crtc(crtc)->imx_crtc);
}
static const struct drm_crtc_funcs ipu_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
- .destroy = imx_drm_crtc_destroy,
+ .destroy = ipu_crtc_destroy,
.page_flip = drm_atomic_helper_page_flip,
- .reset = imx_drm_crtc_reset,
- .atomic_duplicate_state = imx_drm_crtc_duplicate_state,
- .atomic_destroy_state = imx_drm_crtc_destroy_state,
+ .reset = ipu_crtc_reset,
+ .atomic_duplicate_state = ipu_crtc_duplicate_state,
+ .atomic_destroy_state = ipu_crtc_destroy_state,
};
static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
@@ -420,6 +421,12 @@ static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
if (ret)
return ret;
+ if (!drm->mode_config.funcs)
+ drm->mode_config.funcs = &ipuv3_drm_mode_config_funcs;
+ if (!drm->mode_config.helper_private)
+ drm->mode_config.helper_private =
+ &ipuv3_drm_mode_config_helpers;
+
dev_set_drvdata(dev, ipu_crtc);
return 0;
diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-kms.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-kms.c
new file mode 100644
index 000000000000..70bc2d452109
--- /dev/null
+++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-kms.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <linux/dma-buf.h>
+#include <linux/reservation.h>
+#include "imx-drm.h"
+
+static void ipuv3_drm_output_poll_changed(struct drm_device *dev)
+{
+ struct imx_drm_device *imxdrm = dev->dev_private;
+
+ drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
+}
+
+static int ipuv3_drm_atomic_check(struct drm_device *dev,
+ struct drm_atomic_state *state)
+{
+ int ret;
+
+ ret = drm_atomic_helper_check_modeset(dev, state);
+ if (ret)
+ return ret;
+
+ ret = drm_atomic_helper_check_planes(dev, state);
+ if (ret)
+ return ret;
+
+ /*
+ * Check modeset again in case crtc_state->mode_changed is
+ * updated in plane's ->atomic_check callback.
+ */
+ ret = drm_atomic_helper_check_modeset(dev, state);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+static int ipuv3_drm_atomic_commit(struct drm_device *dev,
+ struct drm_atomic_state *state,
+ bool nonblock)
+{
+ struct drm_plane_state *plane_state;
+ struct drm_plane *plane;
+ struct dma_buf *dma_buf;
+ int i;
+
+ /*
+ * If the plane fb has an dma-buf attached, fish out the exclusive
+ * fence for the atomic helper to wait on.
+ */
+ for_each_plane_in_state(state, plane, plane_state, i) {
+ if ((plane->state->fb != plane_state->fb) && plane_state->fb) {
+ dma_buf = drm_fb_cma_get_gem_obj(plane_state->fb,
+ 0)->base.dma_buf;
+ if (!dma_buf)
+ continue;
+ plane_state->fence =
+ reservation_object_get_excl_rcu(dma_buf->resv);
+ }
+ }
+
+ return drm_atomic_helper_commit(dev, state, nonblock);
+}
+
+const struct drm_mode_config_funcs ipuv3_drm_mode_config_funcs = {
+ .fb_create = drm_fb_cma_create,
+ .output_poll_changed = ipuv3_drm_output_poll_changed,
+ .atomic_check = ipuv3_drm_atomic_check,
+ .atomic_commit = ipuv3_drm_atomic_commit,
+};
+
+static void ipuv3_drm_atomic_commit_tail(struct drm_atomic_state *state)
+{
+ struct drm_device *dev = state->dev;
+
+ drm_atomic_helper_commit_modeset_disables(dev, state);
+
+ drm_atomic_helper_commit_planes(dev, state,
+ DRM_PLANE_COMMIT_ACTIVE_ONLY |
+ DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET);
+
+ drm_atomic_helper_commit_modeset_enables(dev, state);
+
+ drm_atomic_helper_commit_hw_done(state);
+
+ drm_atomic_helper_wait_for_vblanks(dev, state);
+
+ drm_atomic_helper_cleanup_planes(dev, state);
+}
+
+struct drm_mode_config_helper_funcs ipuv3_drm_mode_config_helpers = {
+ .atomic_commit_tail = ipuv3_drm_atomic_commit_tail,
+};
+
diff --git a/drivers/gpu/drm/imx/ipuv3/ipuv3-kms.h b/drivers/gpu/drm/imx/ipuv3/ipuv3-kms.h
new file mode 100644
index 000000000000..3968131d11af
--- /dev/null
+++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-kms.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#ifndef _IPUV3_KMS_H_
+#define _IPUV3_KMS_H_
+
+extern const struct drm_mode_config_funcs ipuv3_drm_mode_config_funcs;
+extern struct drm_mode_config_helper_funcs ipuv3_drm_mode_config_helpers;
+
+#endif
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c
index d5864ed4d772..52a975efc129 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.c
@@ -483,8 +483,8 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
&ipu_plane_funcs, ipu_plane_formats,
- ARRAY_SIZE(ipu_plane_formats), type,
- NULL);
+ ARRAY_SIZE(ipu_plane_formats),
+ NULL, type, NULL);
if (ret) {
DRM_ERROR("failed to initialize plane\n");
kfree(ipu_plane);
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.h b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.h
index 338b88a74eb6..338b88a74eb6 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.h
+++ b/drivers/gpu/drm/imx/ipuv3/ipuv3-plane.h
diff --git a/drivers/gpu/drm/imx/lcdif/Kconfig b/drivers/gpu/drm/imx/lcdif/Kconfig
new file mode 100644
index 000000000000..4460ffacd1f7
--- /dev/null
+++ b/drivers/gpu/drm/imx/lcdif/Kconfig
@@ -0,0 +1,8 @@
+config DRM_IMX_LCDIF
+ tristate "i.MX LCDIF controller DRM driver"
+ depends on DRM_IMX
+ depends on IMX_LCDIF_CORE
+ default y if DRM_IMX=y
+ default m if DRM_IMX=m
+ help
+ enable i.MX LCDIF controller DRM driver under DRM_IMX.
diff --git a/drivers/gpu/drm/imx/lcdif/Makefile b/drivers/gpu/drm/imx/lcdif/Makefile
new file mode 100644
index 000000000000..fcdecff9e861
--- /dev/null
+++ b/drivers/gpu/drm/imx/lcdif/Makefile
@@ -0,0 +1,4 @@
+ccflags-y += -Idrivers/gpu/drm/imx
+
+imx-lcdif-crtc-objs := lcdif-crtc.o lcdif-plane.o lcdif-kms.o
+obj-$(CONFIG_DRM_IMX_LCDIF) += imx-lcdif-crtc.o
diff --git a/drivers/gpu/drm/imx/lcdif/lcdif-crtc.c b/drivers/gpu/drm/imx/lcdif/lcdif-crtc.c
new file mode 100644
index 000000000000..df7618c308f0
--- /dev/null
+++ b/drivers/gpu/drm/imx/lcdif/lcdif-crtc.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/component.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <video/imx-lcdif.h>
+#include <video/videomode.h>
+
+#include "imx-drm.h"
+#include "lcdif-plane.h"
+#include "lcdif-kms.h"
+
+struct lcdif_crtc {
+ struct device *dev;
+
+ struct drm_crtc base;
+ struct imx_drm_crtc *imx_crtc;
+ struct lcdif_plane *plane[2];
+
+ int vbl_irq;
+ u32 pix_fmt; /* drm fourcc */
+};
+
+#define to_lcdif_crtc(crtc) container_of(crtc, struct lcdif_crtc, base)
+
+static void lcdif_crtc_destroy(struct drm_crtc *crtc)
+{
+ struct lcdif_crtc *lcdif_crtc = to_lcdif_crtc(crtc);
+
+ imx_drm_remove_crtc(lcdif_crtc->imx_crtc);
+ lcdif_crtc->imx_crtc = NULL;
+}
+
+static void lcdif_crtc_reset(struct drm_crtc *crtc)
+{
+ struct imx_crtc_state *state;
+
+ if (crtc->state) {
+ __drm_atomic_helper_crtc_destroy_state(crtc->state);
+
+ state = to_imx_crtc_state(crtc->state);
+ kfree(state);
+ crtc->state = NULL;
+ }
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return;
+
+ crtc->state = &state->base;
+ crtc->state->crtc = crtc;
+}
+
+static struct drm_crtc_state *lcdif_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+ struct imx_crtc_state *state, *orig_state;
+
+ if (WARN_ON(!crtc->state))
+ return NULL;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return NULL;
+
+ __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+
+ orig_state = to_imx_crtc_state(crtc->state);
+ state->bus_format = orig_state->bus_format;
+ state->bus_flags = orig_state->bus_flags;
+ state->di_hsync_pin = orig_state->di_hsync_pin;
+ state->di_vsync_pin = orig_state->di_vsync_pin;
+
+ return &state->base;
+}
+
+static void lcdif_crtc_destroy_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ __drm_atomic_helper_crtc_destroy_state(state);
+ kfree(to_imx_crtc_state(state));
+}
+
+static const struct drm_crtc_funcs lcdif_crtc_funcs = {
+ .set_config = drm_atomic_helper_set_config,
+ .destroy = lcdif_crtc_destroy,
+ .page_flip = drm_atomic_helper_page_flip,
+ .reset = lcdif_crtc_reset,
+ .atomic_duplicate_state = lcdif_crtc_duplicate_state,
+ .atomic_destroy_state = lcdif_crtc_destroy_state,
+};
+
+static int lcdif_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct lcdif_crtc *lcdif_crtc = to_lcdif_crtc(crtc);
+ struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(state);
+
+ /* return directly when no devices attached
+ * to LCDIF to avoid below error messsage to
+ * make noises in this case.
+ */
+ if (!imx_crtc_state->bus_format)
+ return -EINVAL;
+
+ /* check the requested bus format can be
+ * supported by LCDIF CTRC or not
+ */
+ switch (imx_crtc_state->bus_format) {
+ case MEDIA_BUS_FMT_RGB565_1X16:
+ case MEDIA_BUS_FMT_RGB666_1X18:
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ break;
+ default:
+ dev_err(lcdif_crtc->dev,
+ "unsupported bus format: %#x\n",
+ imx_crtc_state->bus_format);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void lcdif_crtc_atomic_begin(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+ drm_crtc_vblank_on(crtc);
+
+ spin_lock_irq(&crtc->dev->event_lock);
+ if (crtc->state->event) {
+ WARN_ON(drm_crtc_vblank_get(crtc));
+ drm_crtc_arm_vblank_event(crtc, crtc->state->event);
+ crtc->state->event = NULL;
+ }
+ spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static void lcdif_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+ /* LCDIF doesn't have command buffer */
+ return;
+}
+
+static void lcdif_crtc_enable(struct drm_crtc *crtc)
+{
+ struct lcdif_crtc *lcdif_crtc = to_lcdif_crtc(crtc);
+ struct lcdif_soc *lcdif = dev_get_drvdata(lcdif_crtc->dev->parent);
+ struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+ struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc->state);
+ struct videomode vm;
+
+ drm_display_mode_to_videomode(mode, &vm);
+
+ if (imx_crtc_state->bus_flags & DRM_BUS_FLAG_DE_HIGH)
+ vm.flags |= DISPLAY_FLAGS_DE_HIGH;
+ else
+ vm.flags |= DISPLAY_FLAGS_DE_LOW;
+
+ if (imx_crtc_state->bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
+ vm.flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
+ else
+ vm.flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
+
+ pm_runtime_get_sync(lcdif_crtc->dev->parent);
+
+ lcdif_set_mode(lcdif, &vm);
+
+ /* config LCDIF output bus format */
+ lcdif_set_bus_fmt(lcdif, imx_crtc_state->bus_format);
+
+ /* defer the lcdif controller enable to plane update,
+ * since until then the lcdif config is complete to
+ * enable the controller to run actually.
+ */
+}
+
+static void lcdif_crtc_atomic_disable(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+ struct lcdif_crtc *lcdif_crtc = to_lcdif_crtc(crtc);
+ struct lcdif_soc *lcdif = dev_get_drvdata(lcdif_crtc->dev->parent);
+
+ spin_lock_irq(&crtc->dev->event_lock);
+ if (crtc->state->event) {
+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
+ crtc->state->event = NULL;
+ }
+ spin_unlock_irq(&crtc->dev->event_lock);
+
+ drm_crtc_vblank_off(crtc);
+
+ lcdif_disable_controller(lcdif);
+
+ pm_runtime_put(lcdif_crtc->dev->parent);
+}
+
+static const struct drm_crtc_helper_funcs lcdif_helper_funcs = {
+ .atomic_check = lcdif_crtc_atomic_check,
+ .atomic_begin = lcdif_crtc_atomic_begin,
+ .atomic_flush = lcdif_crtc_atomic_flush,
+ .enable = lcdif_crtc_enable,
+ .atomic_disable = lcdif_crtc_atomic_disable,
+};
+
+static int lcdif_enable_vblank(struct drm_crtc *crtc)
+{
+ struct lcdif_crtc *lcdif_crtc = to_lcdif_crtc(crtc);
+ struct lcdif_soc *lcdif = dev_get_drvdata(lcdif_crtc->dev->parent);
+
+ lcdif_vblank_irq_enable(lcdif);
+ enable_irq(lcdif_crtc->vbl_irq);
+
+ return 0;
+}
+
+static void lcdif_disable_vblank(struct drm_crtc *crtc)
+{
+ struct lcdif_crtc *lcdif_crtc = to_lcdif_crtc(crtc);
+ struct lcdif_soc *lcdif = dev_get_drvdata(lcdif_crtc->dev->parent);
+
+ disable_irq_nosync(lcdif_crtc->vbl_irq);
+ lcdif_vblank_irq_disable(lcdif);
+}
+
+static const struct imx_drm_crtc_helper_funcs lcdif_crtc_helper_funcs = {
+ .enable_vblank = lcdif_enable_vblank,
+ .disable_vblank = lcdif_disable_vblank,
+ .crtc_funcs = &lcdif_crtc_funcs,
+ .crtc_helper_funcs = &lcdif_helper_funcs,
+};
+
+static irqreturn_t lcdif_crtc_vblank_irq_handler(int irq, void *dev_id)
+{
+ struct lcdif_crtc *lcdif_crtc = dev_id;
+ struct lcdif_soc *lcdif = dev_get_drvdata(lcdif_crtc->dev->parent);
+
+ drm_crtc_handle_vblank(&lcdif_crtc->base);
+
+ lcdif_vblank_irq_clear(lcdif);
+
+ return IRQ_HANDLED;
+}
+
+static int lcdif_crtc_init(struct lcdif_crtc *lcdif_crtc,
+ struct lcdif_client_platformdata *pdata,
+ struct drm_device *drm)
+{
+ int ret;
+ struct lcdif_plane *primary = lcdif_crtc->plane[0];
+ struct lcdif_soc *lcdif = dev_get_drvdata(lcdif_crtc->dev->parent);
+
+ /* Primary plane
+ * The 'possible_crtcs' of primary plane will be
+ * recalculated during the 'crtc' initialization
+ * later.
+ */
+ primary = lcdif_plane_init(drm, lcdif, 0, DRM_PLANE_TYPE_PRIMARY, 0);
+ if (IS_ERR(primary))
+ return PTR_ERR(primary);
+ lcdif_crtc->plane[0] = primary;
+
+ /* TODO: Overlay plane */
+
+ ret = imx_drm_add_crtc(drm, &lcdif_crtc->base,
+ &lcdif_crtc->imx_crtc, &primary->base,
+ &lcdif_crtc_helper_funcs, pdata->of_node);
+ if (ret) {
+ dev_err(lcdif_crtc->dev, "failed to init crtc\n");
+ goto primary_plane_deinit;
+ }
+
+ lcdif_crtc->vbl_irq = lcdif_vblank_irq_get(lcdif);
+ WARN_ON(lcdif_crtc->vbl_irq < 0);
+
+ ret = devm_request_irq(lcdif_crtc->dev, lcdif_crtc->vbl_irq,
+ lcdif_crtc_vblank_irq_handler, 0,
+ dev_name(lcdif_crtc->dev), lcdif_crtc);
+ if (ret) {
+ dev_err(lcdif_crtc->dev,
+ "vblank irq request failed: %d\n", ret);
+ goto primary_plane_deinit;
+ }
+
+ disable_irq(lcdif_crtc->vbl_irq);
+
+ return 0;
+
+primary_plane_deinit:
+ lcdif_plane_deinit(drm, primary);
+
+ return ret;
+}
+
+static int lcdif_crtc_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ int ret;
+ struct drm_device *drm = data;
+ struct lcdif_crtc *lcdif_crtc;
+ struct lcdif_client_platformdata *pdata = dev->platform_data;
+
+ dev_dbg(dev, "%s: lcdif crtc bind begin\n", __func__);
+
+ lcdif_crtc = devm_kzalloc(dev, sizeof(*lcdif_crtc), GFP_KERNEL);
+ if (!lcdif_crtc)
+ return -ENOMEM;
+
+ lcdif_crtc->dev = dev;
+
+ ret = lcdif_crtc_init(lcdif_crtc, pdata, drm);
+ if (ret)
+ return ret;
+
+ if (!drm->mode_config.funcs)
+ drm->mode_config.funcs = &lcdif_drm_mode_config_funcs;
+
+ if (!drm->mode_config.helper_private)
+ drm->mode_config.helper_private = &lcdif_drm_mode_config_helpers;
+
+ /* limit the max width and height */
+ drm->mode_config.max_width = 1920;
+ drm->mode_config.max_height = 1920;
+
+ dev_set_drvdata(dev, lcdif_crtc);
+
+ dev_dbg(dev, "%s: lcdif crtc bind end\n", __func__);
+
+ return 0;
+}
+
+static void lcdif_crtc_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct drm_device *drm = data;
+ struct lcdif_crtc *lcdif_crtc = dev_get_drvdata(dev);
+
+ if (lcdif_crtc->imx_crtc) {
+ imx_drm_remove_crtc(lcdif_crtc->imx_crtc);
+ lcdif_crtc->imx_crtc = NULL;
+ }
+
+ lcdif_plane_deinit(drm, lcdif_crtc->plane[0]);
+}
+
+static const struct component_ops lcdif_crtc_ops = {
+ .bind = lcdif_crtc_bind,
+ .unbind = lcdif_crtc_unbind,
+};
+
+static int lcdif_crtc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ dev_dbg(&pdev->dev, "%s: lcdif crtc probe begin\n", __func__);
+
+ if (!dev->platform_data) {
+ dev_err(dev, "no platform data\n");
+ return -EINVAL;
+ }
+
+ return component_add(dev, &lcdif_crtc_ops);
+}
+
+static int lcdif_crtc_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &lcdif_crtc_ops);
+
+ return 0;
+}
+
+static struct platform_driver lcdif_crtc_driver = {
+ .probe = lcdif_crtc_probe,
+ .remove = lcdif_crtc_remove,
+ .driver = {
+ .name = "imx-lcdif-crtc",
+ },
+};
+module_platform_driver(lcdif_crtc_driver);
+
+MODULE_DESCRIPTION("NXP i.MX LCDIF DRM CRTC driver");
+MODULE_AUTHOR("Fancy Fang <chen.fang@nxp.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/imx/lcdif/lcdif-kms.c b/drivers/gpu/drm/imx/lcdif/lcdif-kms.c
new file mode 100644
index 000000000000..f013bf0ce7f8
--- /dev/null
+++ b/drivers/gpu/drm/imx/lcdif/lcdif-kms.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_fb_cma_helper.h>
+
+static void lcdif_drm_atomic_commit_tail(struct drm_atomic_state *state)
+{
+ struct drm_device *dev = state->dev;
+
+ drm_atomic_helper_commit_modeset_disables(dev, state);
+
+ drm_atomic_helper_commit_modeset_enables(dev, state);
+
+ drm_atomic_helper_commit_planes(dev, state, DRM_PLANE_COMMIT_ACTIVE_ONLY);
+
+ drm_atomic_helper_commit_hw_done(state);
+
+ drm_atomic_helper_wait_for_vblanks(dev, state);
+
+ drm_atomic_helper_cleanup_planes(dev, state);
+}
+
+const struct drm_mode_config_funcs lcdif_drm_mode_config_funcs = {
+ .fb_create = drm_fb_cma_create,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+};
+
+struct drm_mode_config_helper_funcs lcdif_drm_mode_config_helpers = {
+ .atomic_commit_tail = lcdif_drm_atomic_commit_tail,
+};
diff --git a/drivers/gpu/drm/imx/lcdif/lcdif-kms.h b/drivers/gpu/drm/imx/lcdif/lcdif-kms.h
new file mode 100644
index 000000000000..fcf7d257c6b7
--- /dev/null
+++ b/drivers/gpu/drm/imx/lcdif/lcdif-kms.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LCDIF_KMS_H
+#define __LCDIF_KMS_H
+
+extern const struct drm_mode_config_funcs lcdif_drm_mode_config_funcs;
+extern struct drm_mode_config_helper_funcs lcdif_drm_mode_config_helpers;
+
+#endif
diff --git a/drivers/gpu/drm/imx/lcdif/lcdif-plane.c b/drivers/gpu/drm/imx/lcdif/lcdif-plane.c
new file mode 100644
index 000000000000..7c416bfc77d5
--- /dev/null
+++ b/drivers/gpu/drm/imx/lcdif/lcdif-plane.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_rect.h>
+#include <video/imx-lcdif.h>
+
+#include "lcdif-plane.h"
+
+static uint32_t lcdif_pixel_formats[] = {
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_RGBX8888,
+ DRM_FORMAT_RGBA8888,
+ DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_XRGB1555,
+ DRM_FORMAT_ABGR1555,
+ DRM_FORMAT_XBGR1555,
+ DRM_FORMAT_BGR565,
+};
+
+static int lcdif_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *plane_state)
+{
+ int ret;
+ struct drm_plane_state *old_state = plane->state;
+ struct drm_framebuffer *fb = plane_state->fb;
+ struct drm_framebuffer *old_fb = old_state->fb;
+ struct drm_crtc_state *crtc_state;
+ struct drm_display_mode *mode;
+ struct drm_rect clip = { 0 };
+
+ /* 'fb' should also be NULL which has been checked in
+ * the core sanity check function 'drm_atomic_plane_check()'
+ */
+ if (!plane_state->crtc) {
+ WARN_ON(fb);
+ return 0;
+ }
+
+ /* lcdif crtc can only display from (0,0) for each plane */
+ if (plane_state->crtc_x || plane_state->crtc_y)
+ return -EINVAL;
+
+ crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
+ plane_state->crtc);
+ mode = &crtc_state->adjusted_mode;
+
+ clip.x2 = mode->hdisplay;
+ clip.y2 = mode->vdisplay;
+
+ ret = drm_plane_helper_check_state(plane_state, &clip,
+ DRM_PLANE_HELPER_NO_SCALING,
+ DRM_PLANE_HELPER_NO_SCALING,
+ false, true);
+ if (ret)
+ return ret;
+
+ if (!plane_state->visible)
+ return -EINVAL;
+
+ /* force 'mode_changed' when fb pitches changed, since
+ * the pitch related registers configuration of LCDIF
+ * can not be done when LCDIF is running.
+ */
+ if (old_fb && likely(!crtc_state->mode_changed)) {
+ if (old_fb->pitches[0] != fb->pitches[0])
+ crtc_state->mode_changed = true;
+ }
+
+ return 0;
+}
+
+static void lcdif_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct lcdif_plane *lcdif_plane = to_lcdif_plane(plane);
+ struct lcdif_soc *lcdif = lcdif_plane->lcdif;
+ struct drm_plane_state *state = plane->state;
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *gem_obj = NULL;
+ u32 fb_addr, src_off, src_w, fb_idx, cpp, stride;
+ bool crop;
+
+ /* plane and crtc is disabling */
+ if (!fb)
+ return;
+
+ /* TODO: for now we just update the next buf addr
+ * and the fb pixel format, since the mode set will
+ * be done in crtc's ->enable() helper func
+ */
+ if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+ lcdif_set_pix_fmt(lcdif, fb->pixel_format);
+
+ switch (plane->type) {
+ case DRM_PLANE_TYPE_PRIMARY:
+ /* TODO: only support RGB */
+ gem_obj = drm_fb_cma_get_gem_obj(fb, 0);
+ src_off = (state->src_y >> 16) * fb->pitches[0] +
+ (state->src_x >> 16) * fb->bits_per_pixel;
+ fb_addr = gem_obj->paddr + fb->offsets[0] + src_off;
+ fb_idx = 0;
+ break;
+ default:
+ /* TODO: add overlay later */
+ return;
+ }
+
+ lcdif_set_fb_addr(lcdif, fb_idx, fb_addr);
+
+ /* config horizontal cropping if crtc needs modeset */
+ if (unlikely(drm_atomic_crtc_needs_modeset(state->crtc->state))) {
+ cpp = fb->bits_per_pixel >> 3;
+ stride = DIV_ROUND_UP(fb->pitches[0], cpp);
+
+ src_w = state->src_w >> 16;
+ WARN_ON(src_w > fb->width);
+
+ crop = src_w != stride ? true : false;
+ lcdif_set_fb_hcrop(lcdif, src_w, stride, crop);
+ }
+
+ lcdif_enable_controller(lcdif);
+}
+
+static void lcdif_plane_atomic_disable(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct drm_plane_state *state = plane->state;
+ struct drm_framebuffer *fb = state->fb;
+
+ WARN_ON(fb);
+
+ /* TODO: CRTC disabled has been done by CRTC helper function,
+ * so it seems that no more required, the only possible thing
+ * is to set next buf addr to 0 in CRTC
+ */
+}
+
+static const struct drm_plane_helper_funcs lcdif_plane_helper_funcs = {
+ .atomic_check = lcdif_plane_atomic_check,
+ .atomic_update = lcdif_plane_atomic_update,
+ .atomic_disable = lcdif_plane_atomic_disable,
+};
+
+static void lcdif_plane_destroy(struct drm_plane *plane)
+{
+ struct lcdif_plane *lcdif_plane = to_lcdif_plane(plane);
+
+ drm_plane_cleanup(plane);
+ kfree(lcdif_plane);
+}
+
+static const struct drm_plane_funcs lcdif_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = lcdif_plane_destroy,
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+ .set_property = drm_atomic_helper_plane_set_property,
+};
+
+struct lcdif_plane *lcdif_plane_init(struct drm_device *dev,
+ struct lcdif_soc *lcdif,
+ unsigned int possible_crtcs,
+ enum drm_plane_type type,
+ unsigned int zpos)
+{
+ int ret;
+ struct lcdif_plane *lcdif_plane;
+
+ /* lcdif doesn't support fb modifiers */
+ if (zpos || dev->mode_config.allow_fb_modifiers)
+ return ERR_PTR(-EINVAL);
+
+ lcdif_plane = kzalloc(sizeof(*lcdif_plane), GFP_KERNEL);
+ if (!lcdif_plane)
+ return ERR_PTR(-ENOMEM);
+
+ lcdif_plane->lcdif = lcdif;
+
+ drm_plane_helper_add(&lcdif_plane->base, &lcdif_plane_helper_funcs);
+ ret = drm_universal_plane_init(dev, &lcdif_plane->base, possible_crtcs,
+ &lcdif_plane_funcs, lcdif_pixel_formats,
+ ARRAY_SIZE(lcdif_pixel_formats), NULL,
+ type, NULL);
+ if (ret) {
+ kfree(lcdif_plane);
+ return ERR_PTR(ret);
+ }
+
+ ret = drm_plane_create_zpos_immutable_property(&lcdif_plane->base, zpos);
+ if (ret) {
+ kfree(lcdif_plane);
+ return ERR_PTR(ret);
+ }
+
+ return lcdif_plane;
+}
+
+void lcdif_plane_deinit(struct drm_device *dev,
+ struct lcdif_plane *lcdif_plane)
+{
+ struct drm_plane *plane = &lcdif_plane->base;
+
+ if (plane->zpos_property)
+ drm_property_destroy(dev, plane->zpos_property);
+
+ lcdif_plane_destroy(plane);
+}
diff --git a/drivers/gpu/drm/imx/lcdif/lcdif-plane.h b/drivers/gpu/drm/imx/lcdif/lcdif-plane.h
new file mode 100644
index 000000000000..acd7aead606a
--- /dev/null
+++ b/drivers/gpu/drm/imx/lcdif/lcdif-plane.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LCDIF_PLANE_H
+#define __LCDIF_PLANE_H
+
+#include <drm/drm_plane.h>
+#include <video/imx-lcdif.h>
+
+struct lcdif_plane {
+ struct drm_plane base;
+ struct lcdif_soc *lcdif;
+};
+
+#define to_lcdif_plane(plane) container_of(plane, struct lcdif_plane, base)
+
+struct lcdif_plane *lcdif_plane_init(struct drm_device *drm,
+ struct lcdif_soc *lcdif,
+ unsigned int possible_crtcs,
+ enum drm_plane_type type,
+ unsigned int zpos);
+
+void lcdif_plane_deinit(struct drm_device *dev,
+ struct lcdif_plane *lcdif_plane);
+
+#endif
diff --git a/drivers/gpu/drm/imx/nwl_dsi-imx.c b/drivers/gpu/drm/imx/nwl_dsi-imx.c
new file mode 100644
index 000000000000..55d623af5f74
--- /dev/null
+++ b/drivers/gpu/drm/imx/nwl_dsi-imx.c
@@ -0,0 +1,1052 @@
+/*
+ * i.MX drm driver - Northwest Logic MIPI DSI display driver
+ *
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/bridge/nwl_dsi.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_of.h>
+#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx8mq-iomuxc-gpr.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy-mixel-mipi-dsi.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+#include <soc/imx8/sc/sci.h>
+#include <video/videomode.h>
+
+#include "imx-drm.h"
+
+#define DRIVER_NAME "nwl_dsi-imx"
+
+/* 8MQ SRC specific registers */
+#define SRC_MIPIPHY_RCR 0x28
+#define RESET_BYTE_N BIT(1)
+#define RESET_N BIT(2)
+#define DPI_RESET_N BIT(3)
+#define ESC_RESET_N BIT(4)
+#define PCLK_RESET_N BIT(5)
+
+#define DC_ID(x) SC_R_DC_ ## x
+#define MIPI_ID(x) SC_R_MIPI_ ## x
+#define SYNC_CTRL(x) SC_C_SYNC_CTRL ## x
+#define PXL_VLD(x) SC_C_PXL_LINK_MST ## x ## _VLD
+#define PXL_ADDR(x) SC_C_PXL_LINK_MST ## x ## _ADDR
+
+/* Possible clocks */
+#define CLK_PIXEL "pixel"
+#define CLK_CORE "core"
+#define CLK_BYPASS "bypass"
+#define CLK_PHYREF "phy_ref"
+
+/* Possible valid PHY reference clock rates*/
+u32 phyref_rates[] = {
+ 24000000,
+ 25000000,
+ 27000000,
+};
+
+struct imx_mipi_dsi {
+ struct drm_encoder encoder;
+ struct drm_bridge bridge;
+ struct drm_bridge *next_bridge;
+ struct device *dev;
+ struct phy *phy;
+
+ /* Optional external regs */
+ struct regmap *csr;
+ struct regmap *reset;
+ struct regmap *mux_sel;
+
+ /* Optional clocks */
+ struct clk_config *clk_config;
+ size_t clk_num;
+
+ u32 tx_ulps_reg;
+ u32 pxl2dpi_reg;
+
+ unsigned long bit_clk;
+ unsigned long pix_clk;
+ u32 phyref_rate;
+ u32 instance;
+ u32 sync_pol;
+ u32 power_on_delay;
+ bool no_clk_reset;
+ bool enabled;
+ bool suspended;
+};
+
+struct clk_config {
+ const char *id;
+ struct clk *clk;
+ bool present;
+ bool enabled;
+ u32 rate;
+};
+
+enum imx_ext_regs {
+ IMX_REG_CSR = BIT(1),
+ IMX_REG_SRC = BIT(2),
+ IMX_REG_GPR = BIT(3),
+};
+
+struct devtype {
+ int (*poweron)(struct imx_mipi_dsi *);
+ void (*poweroff)(struct imx_mipi_dsi *);
+ u32 ext_regs; /* required external registers */
+ u32 tx_ulps_reg;
+ u32 pxl2dpi_reg;
+ u8 max_instances;
+ struct clk_config clk_config[4];
+};
+
+static int imx8qm_dsi_poweron(struct imx_mipi_dsi *dsi);
+static void imx8qm_dsi_poweroff(struct imx_mipi_dsi *dsi);
+static struct devtype imx8qm_dev = {
+ .poweron = &imx8qm_dsi_poweron,
+ .poweroff = &imx8qm_dsi_poweroff,
+ .clk_config = {
+ { .id = CLK_CORE, .present = false },
+ { .id = CLK_PIXEL, .present = true },
+ { .id = CLK_BYPASS, .present = true },
+ { .id = CLK_PHYREF, .present = true },
+ },
+ .ext_regs = IMX_REG_CSR,
+ .tx_ulps_reg = 0x00,
+ .pxl2dpi_reg = 0x04,
+ .max_instances = 2,
+};
+
+static int imx8qxp_dsi_poweron(struct imx_mipi_dsi *dsi);
+static void imx8qxp_dsi_poweroff(struct imx_mipi_dsi *dsi);
+static struct devtype imx8qxp_dev = {
+ .poweron = &imx8qxp_dsi_poweron,
+ .poweroff = &imx8qxp_dsi_poweroff,
+ .clk_config = {
+ { .id = CLK_CORE, .present = false },
+ { .id = CLK_PIXEL, .present = true },
+ { .id = CLK_BYPASS, .present = true },
+ { .id = CLK_PHYREF, .present = true },
+ },
+ .ext_regs = IMX_REG_CSR,
+ .tx_ulps_reg = 0x30,
+ .pxl2dpi_reg = 0x40,
+ .max_instances = 2,
+};
+
+static int imx8mq_dsi_poweron(struct imx_mipi_dsi *dsi);
+static void imx8mq_dsi_poweroff(struct imx_mipi_dsi *dsi);
+static struct devtype imx8mq_dev = {
+ .poweron = &imx8mq_dsi_poweron,
+ .poweroff = &imx8mq_dsi_poweroff,
+ .clk_config = {
+ { .id = CLK_CORE, .present = true },
+ { .id = CLK_PIXEL, .present = false },
+ { .id = CLK_BYPASS, .present = false },
+ { .id = CLK_PHYREF, .present = true },
+ },
+ .ext_regs = IMX_REG_SRC | IMX_REG_GPR,
+ .max_instances = 1,
+};
+
+static const struct of_device_id imx_nwl_dsi_dt_ids[] = {
+ { .compatible = "fsl,imx8qm-mipi-dsi", .data = &imx8qm_dev, },
+ { .compatible = "fsl,imx8qxp-mipi-dsi", .data = &imx8qxp_dev, },
+ { .compatible = "fsl,imx8mq-mipi-dsi_drm", .data = &imx8mq_dev, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_nwl_dsi_dt_ids);
+
+static inline struct imx_mipi_dsi *encoder_to_dsi(struct drm_encoder *encoder)
+{
+ return container_of(encoder, struct imx_mipi_dsi, encoder);
+}
+
+static void imx_nwl_dsi_set_clocks(struct imx_mipi_dsi *dsi, bool enable)
+{
+ struct device *dev = dsi->dev;
+ const char *id;
+ struct clk *clk;
+ unsigned long new_rate, cur_rate;
+ bool enabled;
+ size_t i;
+
+ for (i = 0; i < dsi->clk_num; i++) {
+ if (!dsi->clk_config[i].present)
+ continue;
+ id = dsi->clk_config[i].id;
+ clk = dsi->clk_config[i].clk;
+ new_rate = dsi->clk_config[i].rate;
+ cur_rate = clk_get_rate(clk);
+ enabled = dsi->clk_config[i].enabled;
+
+ /* BYPASS clk must have the same rate as PHY_REF clk */
+ if (!strcmp(id, CLK_BYPASS) || !strcmp(id, CLK_PHYREF))
+ new_rate = dsi->phyref_rate;
+
+ if (enable) {
+ if (enabled && new_rate != cur_rate)
+ clk_disable_unprepare(clk);
+ else if (enabled && new_rate == cur_rate)
+ continue;
+ if (new_rate > 0)
+ clk_set_rate(clk, new_rate);
+ clk_prepare_enable(clk);
+ dsi->clk_config[i].enabled = true;
+ cur_rate = clk_get_rate(clk);
+ DRM_DEV_DEBUG_DRIVER(dev,
+ "Enabled %s clk (rate: req=%lu act=%lu)\n",
+ id, new_rate, cur_rate);
+ } else if (enabled) {
+ clk_disable_unprepare(clk);
+ dsi->clk_config[i].enabled = false;
+ DRM_DEV_DEBUG_DRIVER(dev, "Disabled %s clk\n", id);
+ }
+ }
+}
+
+/*
+ * v2 is true for QXP
+ * On QM, we have 2 DPUs, each one with a MIPI-DSI link
+ * On QXP, we have 1 DPU with two MIPI-DSI links
+ * Because of this, we will have different initialization
+ * paths for MIPI0 and MIPI1 on QM vs QXP
+ */
+static int imx8q_dsi_poweron(struct imx_mipi_dsi *dsi, bool v2)
+{
+ struct device *dev = dsi->dev;
+ int ret = 0;
+ sc_err_t sci_err = 0;
+ sc_ipc_t ipc_handle = 0;
+ u32 inst = dsi->instance;
+ u32 mu_id;
+ sc_rsrc_t mipi_id, dc_id;
+ sc_ctrl_t mipi_ctrl;
+
+ sci_err = sc_ipc_getMuID(&mu_id);
+ if (sci_err != SC_ERR_NONE) {
+ DRM_DEV_ERROR(dev, "Failed to get MU ID (%d)\n", sci_err);
+ return -ENODEV;
+ }
+ sci_err = sc_ipc_open(&ipc_handle, mu_id);
+ if (sci_err != SC_ERR_NONE) {
+ DRM_DEV_ERROR(dev, "Failed to open IPC (%d)\n", sci_err);
+ return -ENODEV;
+ }
+
+ mipi_id = inst?MIPI_ID(1):MIPI_ID(0);
+ dc_id = (!v2 && inst)?DC_ID(1):DC_ID(0);
+ DRM_DEV_DEBUG_DRIVER(dev, "MIPI ID: %d DC ID: %d\n",
+ mipi_id,
+ dc_id);
+
+ if (v2) {
+ sci_err = sc_misc_set_control(ipc_handle,
+ mipi_id, SC_C_MODE, 0);
+ if (sci_err != SC_ERR_NONE)
+ DRM_DEV_ERROR(dev,
+ "Failed to set SC_C_MODE (%d)\n",
+ sci_err);
+ sci_err = sc_misc_set_control(ipc_handle,
+ mipi_id, SC_C_DUAL_MODE, 0);
+ if (sci_err != SC_ERR_NONE)
+ DRM_DEV_ERROR(dev,
+ "Failed to set SC_C_DUAL_MODE (%d)\n",
+ sci_err);
+ sci_err = sc_misc_set_control(ipc_handle,
+ mipi_id, SC_C_PXL_LINK_SEL, 0);
+ if (sci_err != SC_ERR_NONE)
+ DRM_DEV_ERROR(dev,
+ "Failed to set SC_C_PXL_LINK_SEL (%d)\n",
+ sci_err);
+ }
+
+ /* Initialize Pixel Link */
+ mipi_ctrl = (v2 && inst)?PXL_ADDR(2):PXL_ADDR(1);
+ sci_err = sc_misc_set_control(ipc_handle,
+ dc_id,
+ mipi_ctrl,
+ 0);
+ if (sci_err != SC_ERR_NONE) {
+ DRM_DEV_ERROR(dev,
+ "Failed to set SC_C_PXL_LINK_MST%d_ADDR (%d)\n",
+ inst,
+ sci_err);
+ ret = -ENODEV;
+ goto err_ipc;
+ }
+
+ mipi_ctrl = (v2 && inst)?PXL_VLD(2):PXL_VLD(1);
+ sci_err = sc_misc_set_control(ipc_handle,
+ dc_id,
+ mipi_ctrl,
+ 1);
+ if (sci_err != SC_ERR_NONE) {
+ DRM_DEV_ERROR(dev,
+ "Failed to set SC_C_PXL_LINK_MST%d_VLD (%d)\n",
+ inst + 1,
+ sci_err);
+ ret = -ENODEV;
+ goto err_ipc;
+ }
+
+ mipi_ctrl = (v2 && inst)?SYNC_CTRL(1):SYNC_CTRL(0);
+ sci_err = sc_misc_set_control(ipc_handle,
+ dc_id,
+ mipi_ctrl,
+ 1);
+ if (sci_err != SC_ERR_NONE) {
+ DRM_DEV_ERROR(dev,
+ "Failed to set SC_C_SYNC_CTRL%d (%d)\n",
+ inst,
+ sci_err);
+ ret = -ENODEV;
+ goto err_ipc;
+ }
+
+ /* Assert DPI and MIPI bits */
+ sci_err = sc_misc_set_control(ipc_handle,
+ mipi_id,
+ SC_C_DPI_RESET,
+ 1);
+ if (sci_err != SC_ERR_NONE) {
+ DRM_DEV_ERROR(dev,
+ "Failed to assert DPI reset (%d)\n",
+ sci_err);
+ ret = -ENODEV;
+ goto err_ipc;
+ }
+
+ sci_err = sc_misc_set_control(ipc_handle,
+ mipi_id,
+ SC_C_MIPI_RESET,
+ 1);
+ if (sci_err != SC_ERR_NONE) {
+ DRM_DEV_ERROR(dev,
+ "Failed to assert MIPI reset (%d)\n",
+ sci_err);
+ ret = -ENODEV;
+ goto err_ipc;
+ }
+
+ regmap_write(dsi->csr,
+ dsi->tx_ulps_reg,
+ 0);
+ regmap_write(dsi->csr,
+ dsi->pxl2dpi_reg,
+ DPI_24_BIT);
+
+ sc_ipc_close(ipc_handle);
+ return ret;
+
+err_ipc:
+ sc_ipc_close(ipc_handle);
+ return ret;
+}
+
+static void imx8q_dsi_poweroff(struct imx_mipi_dsi *dsi, bool v2)
+{
+ struct device *dev = dsi->dev;
+ sc_err_t sci_err = 0;
+ sc_ipc_t ipc_handle = 0;
+ u32 mu_id;
+ u32 inst = dsi->instance;
+ sc_rsrc_t mipi_id, dc_id;
+ sc_ctrl_t mipi_ctrl;
+
+ mipi_id = inst?MIPI_ID(1):MIPI_ID(0);
+ dc_id = (!v2 && inst)?DC_ID(1):DC_ID(0);
+
+ /* Deassert DPI and MIPI bits */
+ if (sc_ipc_getMuID(&mu_id) != SC_ERR_NONE ||
+ sc_ipc_open(&ipc_handle, mu_id) != SC_ERR_NONE)
+ return;
+
+ sci_err = sc_misc_set_control(ipc_handle,
+ mipi_id, SC_C_DPI_RESET, 0);
+ if (sci_err != SC_ERR_NONE)
+ DRM_DEV_ERROR(dev,
+ "Failed to deassert DPI reset (%d)\n",
+ sci_err);
+
+ sci_err = sc_misc_set_control(ipc_handle,
+ mipi_id, SC_C_MIPI_RESET, 0);
+ if (sci_err != SC_ERR_NONE)
+ DRM_DEV_ERROR(dev,
+ "Failed to deassert MIPI reset (%d)\n",
+ sci_err);
+
+ mipi_ctrl = (v2 && inst)?SYNC_CTRL(1):SYNC_CTRL(0);
+ sci_err = sc_misc_set_control(ipc_handle,
+ dc_id, mipi_ctrl, 0);
+ if (sci_err != SC_ERR_NONE)
+ DRM_DEV_ERROR(dev,
+ "Failed to reset SC_C_SYNC_CTRL0 (%d)\n",
+ sci_err);
+
+ mipi_ctrl = (v2 && inst)?PXL_VLD(2):PXL_VLD(1);
+ sci_err = sc_misc_set_control(ipc_handle,
+ dc_id, mipi_ctrl, 0);
+ if (sci_err != SC_ERR_NONE)
+ DRM_DEV_ERROR(dev,
+ "Failed to reset SC_C_SYNC_CTRL0 (%d)\n",
+ sci_err);
+
+ sc_ipc_close(ipc_handle);
+}
+
+static int imx8qm_dsi_poweron(struct imx_mipi_dsi *dsi)
+{
+ return imx8q_dsi_poweron(dsi, false);
+}
+
+static void imx8qm_dsi_poweroff(struct imx_mipi_dsi *dsi)
+{
+ return imx8q_dsi_poweroff(dsi, false);
+}
+
+static int imx8qxp_dsi_poweron(struct imx_mipi_dsi *dsi)
+{
+ return imx8q_dsi_poweron(dsi, true);
+}
+
+static void imx8qxp_dsi_poweroff(struct imx_mipi_dsi *dsi)
+{
+ return imx8q_dsi_poweroff(dsi, true);
+}
+
+static int imx8mq_dsi_poweron(struct imx_mipi_dsi *dsi)
+{
+ regmap_update_bits(dsi->reset, SRC_MIPIPHY_RCR,
+ PCLK_RESET_N, PCLK_RESET_N);
+ regmap_update_bits(dsi->reset, SRC_MIPIPHY_RCR,
+ ESC_RESET_N, ESC_RESET_N);
+ regmap_update_bits(dsi->reset, SRC_MIPIPHY_RCR,
+ RESET_BYTE_N, RESET_BYTE_N);
+ regmap_update_bits(dsi->reset, SRC_MIPIPHY_RCR,
+ DPI_RESET_N, DPI_RESET_N);
+
+ return 0;
+}
+
+static void imx8mq_dsi_poweroff(struct imx_mipi_dsi *dsi)
+{
+ regmap_update_bits(dsi->reset, SRC_MIPIPHY_RCR,
+ PCLK_RESET_N, 0);
+ regmap_update_bits(dsi->reset, SRC_MIPIPHY_RCR,
+ ESC_RESET_N, 0);
+ regmap_update_bits(dsi->reset, SRC_MIPIPHY_RCR,
+ RESET_BYTE_N, 0);
+ regmap_update_bits(dsi->reset, SRC_MIPIPHY_RCR,
+ DPI_RESET_N, 0);
+}
+
+static void imx_nwl_dsi_enable(struct imx_mipi_dsi *dsi)
+{
+ struct device *dev = dsi->dev;
+ const struct of_device_id *of_id = of_match_device(imx_nwl_dsi_dt_ids,
+ dev);
+ const struct devtype *devtype = of_id->data;
+ unsigned long bit_clk, min_sleep, max_sleep;
+ int ret;
+
+ if (dsi->enabled)
+ return;
+
+ DRM_DEV_DEBUG_DRIVER(dev, "id = %s\n", (dsi->instance)?"DSI1":"DSI0");
+
+ /*
+ * TODO: we are doing this here, because the ADV7535 which is a drm
+ * bridge, may change the DSI parameters in mode_set. One of the
+ * changed parameter is DSI lanes, which affects the PHY settings.
+ * This is why, we need run this function again, here, in order
+ * to correctly set-up the PHY. Since we can't do anything here, we
+ * will ignore it's status.
+ * In the future, maybe it will be best to move the PHY handling
+ * into the DSI host driver.
+ */
+ bit_clk = nwl_dsi_get_bit_clock(dsi->next_bridge, dsi->pix_clk);
+ if (bit_clk != dsi->bit_clk) {
+ mixel_phy_mipi_set_phy_speed(dsi->phy,
+ bit_clk,
+ dsi->phyref_rate,
+ false);
+ dsi->bit_clk = bit_clk;
+ }
+
+ /*
+ * On some systems we need to wait some time before enabling the
+ * phy_ref clock, in order to allow the parent PLL to become stable
+ */
+ if (dsi->power_on_delay > 20) {
+ msleep(dsi->power_on_delay);
+ } else if (dsi->power_on_delay > 0) {
+ max_sleep = dsi->power_on_delay * 1000;
+ min_sleep = 1000;
+ if (max_sleep > 6000)
+ min_sleep = max_sleep - 5000;
+ usleep_range(min_sleep, max_sleep);
+ }
+
+ request_bus_freq(BUS_FREQ_HIGH);
+
+ imx_nwl_dsi_set_clocks(dsi, true);
+
+ ret = devtype->poweron(dsi);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "Failed to power on DSI (%d)\n", ret);
+ return;
+ }
+
+ dsi->enabled = true;
+}
+
+static void imx_nwl_dsi_disable(struct imx_mipi_dsi *dsi)
+{
+ struct device *dev = dsi->dev;
+ const struct of_device_id *of_id = of_match_device(imx_nwl_dsi_dt_ids,
+ dev);
+ const struct devtype *devtype = of_id->data;
+
+ if (!dsi->enabled)
+ return;
+
+ DRM_DEV_DEBUG_DRIVER(dev, "id = %s\n", (dsi->instance)?"DSI1":"DSI0");
+
+ if (!dsi->no_clk_reset)
+ devtype->poweroff(dsi);
+
+ imx_nwl_dsi_set_clocks(dsi, false);
+
+ release_bus_freq(BUS_FREQ_HIGH);
+
+ dsi->enabled = false;
+}
+
+static void imx_nwl_update_sync_polarity(unsigned int *flags, u32 sync_pol)
+{
+ /* Make sure all flags are set-up accordingly */
+ if (sync_pol) {
+ *flags |= DRM_MODE_FLAG_PHSYNC;
+ *flags |= DRM_MODE_FLAG_PVSYNC;
+ *flags &= ~DRM_MODE_FLAG_NHSYNC;
+ *flags &= ~DRM_MODE_FLAG_NVSYNC;
+ } else {
+ *flags &= ~DRM_MODE_FLAG_PHSYNC;
+ *flags &= ~DRM_MODE_FLAG_PVSYNC;
+ *flags |= DRM_MODE_FLAG_NHSYNC;
+ *flags |= DRM_MODE_FLAG_NVSYNC;
+ }
+}
+
+/*
+ * This function will try the required phy speed for current mode
+ * If the phy speed can be achieved, the phy will save the speed
+ * configuration
+ */
+static int imx_nwl_try_phy_speed(struct imx_mipi_dsi *dsi,
+ struct drm_display_mode *mode)
+{
+ struct device *dev = dsi->dev;
+ unsigned long pixclock;
+ unsigned long bit_clk;
+ size_t i, num_rates = ARRAY_SIZE(phyref_rates);
+ int ret = 0;
+
+ pixclock = mode->clock * 1000;
+ /*
+ * DSI host should know the required bit clock, since it has info
+ * about bits-per-pixel and number of lanes from DSI device
+ */
+ bit_clk = nwl_dsi_get_bit_clock(dsi->next_bridge, pixclock);
+
+ /* If bit_clk is the same with current, we're good */
+ if (bit_clk == dsi->bit_clk)
+ return 0;
+
+ for (i = 0; i < num_rates; i++) {
+ dsi->phyref_rate = phyref_rates[i];
+ DRM_DEV_DEBUG_DRIVER(dev, "Trying PHY ref rate: %u\n",
+ dsi->phyref_rate);
+ ret = mixel_phy_mipi_set_phy_speed(dsi->phy,
+ bit_clk,
+ dsi->phyref_rate,
+ false);
+ /* Pick the first non-failing rate */
+ if (!ret)
+ break;
+ }
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev,
+ "Cannot setup PHY for mode: %ux%u @%d kHz\n",
+ mode->hdisplay,
+ mode->vdisplay,
+ mode->clock);
+ DRM_DEV_ERROR(dev, "PHY_REF clk: %u, bit clk: %lu\n",
+ dsi->phyref_rate, bit_clk);
+ } else {
+ dsi->bit_clk = bit_clk;
+ dsi->pix_clk = pixclock;
+ }
+
+ return ret;
+}
+
+static void imx_nwl_dsi_encoder_enable(struct drm_encoder *encoder)
+{
+ struct imx_mipi_dsi *dsi = encoder_to_dsi(encoder);
+
+ pm_runtime_get_sync(dsi->dev);
+ imx_nwl_dsi_enable(dsi);
+}
+
+static void imx_nwl_dsi_encoder_disable(struct drm_encoder *encoder)
+{
+ struct imx_mipi_dsi *dsi = encoder_to_dsi(encoder);
+
+ imx_nwl_dsi_disable(dsi);
+ pm_runtime_put_sync(dsi->dev);
+}
+
+static int imx_nwl_dsi_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
+ struct imx_mipi_dsi *dsi = encoder_to_dsi(encoder);
+ unsigned int *flags = &crtc_state->adjusted_mode.flags;
+
+ imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB101010_1X30;
+ imx_nwl_update_sync_polarity(flags, dsi->sync_pol);
+
+ /* Try to see if the phy can satisfy the current mode */
+ return imx_nwl_try_phy_speed(dsi, &crtc_state->adjusted_mode);
+}
+
+static const struct drm_encoder_helper_funcs
+imx_nwl_dsi_encoder_helper_funcs = {
+ .enable = imx_nwl_dsi_encoder_enable,
+ .disable = imx_nwl_dsi_encoder_disable,
+ .atomic_check = imx_nwl_dsi_encoder_atomic_check,
+};
+
+static void imx_nwl_dsi_encoder_destroy(struct drm_encoder *encoder)
+{
+ drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs imx_nwl_dsi_encoder_funcs = {
+ .destroy = imx_nwl_dsi_encoder_destroy,
+};
+
+
+static void imx_nwl_dsi_bridge_enable(struct drm_bridge *bridge)
+{
+ struct imx_mipi_dsi *dsi = bridge->driver_private;
+
+ imx_nwl_dsi_enable(dsi);
+ pm_runtime_get_sync(dsi->dev);
+}
+
+static void imx_nwl_dsi_bridge_disable(struct drm_bridge *bridge)
+{
+ struct imx_mipi_dsi *dsi = bridge->driver_private;
+
+ imx_nwl_dsi_disable(dsi);
+ pm_runtime_put_sync(dsi->dev);
+}
+
+static bool imx_nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct imx_mipi_dsi *dsi = bridge->driver_private;
+ unsigned int *flags = &adjusted_mode->flags;
+
+ imx_nwl_update_sync_polarity(flags, dsi->sync_pol);
+
+ return (imx_nwl_try_phy_speed(dsi, adjusted_mode) == 0);
+}
+
+static int imx_nwl_dsi_bridge_attach(struct drm_bridge *bridge)
+{
+ struct imx_mipi_dsi *dsi = bridge->driver_private;
+ struct drm_encoder *encoder = bridge->encoder;
+ int ret = 0;
+
+ DRM_DEV_DEBUG_DRIVER(dsi->dev, "id = %s\n",
+ (dsi->instance)?"DSI1":"DSI0");
+ if (!encoder) {
+ DRM_DEV_ERROR(dsi->dev, "Parent encoder object not found\n");
+ return -ENODEV;
+ }
+
+ /* Attach the next bridge in chain */
+ nwl_dsi_add_bridge(encoder, dsi->next_bridge);
+ ret = drm_bridge_attach(encoder->dev, dsi->next_bridge);
+ if (ret) {
+ DRM_DEV_ERROR(dsi->dev, "Failed to attach bridge! (%d)\n",
+ ret);
+ nwl_dsi_del_bridge(encoder, dsi->next_bridge);
+ }
+
+ return ret;
+}
+
+static void imx_nwl_dsi_bridge_detach(struct drm_bridge *bridge)
+{
+ struct imx_mipi_dsi *dsi = bridge->driver_private;
+
+ DRM_DEV_DEBUG_DRIVER(dsi->dev, "id = %s\n",
+ (dsi->instance)?"DSI1":"DSI0");
+ drm_bridge_detach(dsi->next_bridge);
+ nwl_dsi_del_bridge(dsi->next_bridge->encoder, dsi->next_bridge);
+}
+
+static const struct drm_bridge_funcs imx_nwl_dsi_bridge_funcs = {
+ .enable = imx_nwl_dsi_bridge_enable,
+ .disable = imx_nwl_dsi_bridge_disable,
+ .mode_fixup = imx_nwl_dsi_bridge_mode_fixup,
+ .attach = imx_nwl_dsi_bridge_attach,
+ .detach = imx_nwl_dsi_bridge_detach,
+};
+
+static int imx_nwl_dsi_parse_of(struct device *dev, bool as_bridge)
+{
+ struct device_node *np = dev->of_node;
+ const struct of_device_id *of_id = of_match_device(imx_nwl_dsi_dt_ids,
+ dev);
+ const struct devtype *devtype = of_id->data;
+ struct imx_mipi_dsi *dsi = dev_get_drvdata(dev);
+ struct clk *clk;
+ const char *clk_id;
+ size_t i, clk_config_sz;
+ int id;
+ u32 mux_val;
+ int ret = 0;
+
+ id = of_alias_get_id(np, "mipi_dsi");
+ if (id < 0) {
+ dev_err(dev, "No mipi_dsi alias found!");
+ return id;
+ }
+ if (id > devtype->max_instances - 1) {
+ dev_err(dev, "Too many instances! (cur: %d, max: %d)\n",
+ id, devtype->max_instances);
+ return -ENODEV;
+ }
+ dsi->instance = id;
+
+ dsi->phy = devm_phy_get(dev, "dphy");
+ if (IS_ERR(dsi->phy)) {
+ ret = PTR_ERR(dsi->phy);
+ dev_err(dev, "Could not get PHY (%d)\n", ret);
+ return ret;
+ }
+
+ /* Look for optional clocks */
+ dsi->clk_num = ARRAY_SIZE(devtype->clk_config);
+ dsi->clk_config = devm_kcalloc(dev,
+ dsi->clk_num,
+ sizeof(struct clk_config),
+ GFP_KERNEL);
+ clk_config_sz = dsi->clk_num * sizeof(struct clk_config);
+ memcpy(dsi->clk_config, devtype->clk_config, clk_config_sz);
+
+ for (i = 0; i < dsi->clk_num; i++) {
+ if (!dsi->clk_config[i].present)
+ continue;
+
+ clk_id = dsi->clk_config[i].id;
+ clk = devm_clk_get(dev, clk_id);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ dev_err(dev, "Failed to get %s clock (%d)\n",
+ clk_id, ret);
+ return ret;
+ }
+ dev_dbg(dev, "Setup clk %s (rate: %lu)\n",
+ clk_id, clk_get_rate(clk));
+ dsi->clk_config[i].clk = clk;
+ }
+
+ dsi->tx_ulps_reg = devtype->tx_ulps_reg;
+ dsi->pxl2dpi_reg = devtype->pxl2dpi_reg;
+
+ of_property_read_u32(np, "sync-pol", &dsi->sync_pol);
+ of_property_read_u32(np, "pwr-delay", &dsi->power_on_delay);
+
+ /* Look for optional regmaps */
+ dsi->csr = syscon_regmap_lookup_by_phandle(np, "csr");
+ if (IS_ERR(dsi->csr) && (devtype->ext_regs & IMX_REG_CSR)) {
+ ret = PTR_ERR(dsi->csr);
+ dev_err(dev, "Failed to get CSR regmap (%d)\n", ret);
+ return ret;
+ }
+ dsi->reset = syscon_regmap_lookup_by_phandle(np, "src");
+ if (IS_ERR(dsi->reset) && (devtype->ext_regs & IMX_REG_SRC)) {
+ ret = PTR_ERR(dsi->reset);
+ dev_err(dev, "Failed to get SRC regmap (%d)\n", ret);
+ return ret;
+ }
+ dsi->mux_sel = syscon_regmap_lookup_by_phandle(np, "mux-sel");
+ if (IS_ERR(dsi->mux_sel) && (devtype->ext_regs & IMX_REG_GPR)) {
+ ret = PTR_ERR(dsi->mux_sel);
+ dev_err(dev, "Failed to get GPR regmap (%d)\n", ret);
+ return ret;
+ }
+ if (IS_ERR(dsi->mux_sel))
+ return 0;
+
+ mux_val = IMX8MQ_GPR13_MIPI_MUX_SEL;
+ if (as_bridge)
+ mux_val = 0;
+ dev_info(dev, "Using %s as input source\n",
+ (mux_val)?"DCSS":"LCDIF");
+ regmap_update_bits(dsi->mux_sel,
+ IOMUXC_GPR13,
+ IMX8MQ_GPR13_MIPI_MUX_SEL,
+ mux_val);
+
+ dsi->no_clk_reset = of_property_read_bool(np, "no_clk_reset");
+
+ return 0;
+}
+
+static int imx_nwl_dsi_bind(struct device *dev,
+ struct device *master,
+ void *data)
+{
+ struct drm_device *drm = data;
+ struct drm_bridge *next_bridge = NULL;
+ struct imx_mipi_dsi *dsi = dev_get_drvdata(dev);
+ int ret = 0;
+
+ ret = imx_nwl_dsi_parse_of(dev, false);
+ if (ret)
+ return ret;
+
+ DRM_DEV_DEBUG_DRIVER(dev, "id = %s\n", (dsi->instance)?"DSI1":"DSI0");
+
+ /* Re-validate the bridge */
+ if (dsi->next_bridge)
+ next_bridge = of_drm_find_bridge(dsi->next_bridge->of_node);
+ dsi->next_bridge = next_bridge;
+
+ if (!dsi->next_bridge) {
+ dev_warn(dev, "No bridge found, skipping encoder creation\n");
+ return ret;
+ }
+
+ ret = imx_drm_encoder_parse_of(drm, &dsi->encoder, dev->of_node);
+ if (ret)
+ return ret;
+
+ drm_encoder_helper_add(&dsi->encoder,
+ &imx_nwl_dsi_encoder_helper_funcs);
+ ret = drm_encoder_init(drm,
+ &dsi->encoder,
+ &imx_nwl_dsi_encoder_funcs,
+ DRM_MODE_ENCODER_DSI,
+ NULL);
+ if (ret) {
+ DRM_DEV_ERROR(dev, "failed to init DSI encoder (%d)\n", ret);
+ return ret;
+ }
+
+ dsi->next_bridge->encoder = &dsi->encoder;
+ dsi->encoder.bridge = dsi->next_bridge;
+ ret = drm_bridge_attach(dsi->encoder.dev, dsi->next_bridge);
+ if (ret)
+ drm_encoder_cleanup(&dsi->encoder);
+
+ return ret;
+}
+
+static void imx_nwl_dsi_unbind(struct device *dev,
+ struct device *master,
+ void *data)
+{
+ struct imx_mipi_dsi *dsi = dev_get_drvdata(dev);
+ struct drm_bridge *next_bridge = NULL;
+
+ DRM_DEV_DEBUG_DRIVER(dev, "id = %s\n", (dsi->instance)?"DSI1":"DSI0");
+
+ /*
+ * At this point, our next bridge in chain might be already removed,
+ * so update it's status.
+ */
+ if (dsi->next_bridge)
+ next_bridge = of_drm_find_bridge(dsi->next_bridge->of_node);
+ if (next_bridge)
+ drm_bridge_detach(next_bridge);
+ dsi->next_bridge = next_bridge;
+
+ if (dsi->enabled)
+ imx_nwl_dsi_encoder_disable(&dsi->encoder);
+
+ if (dsi->encoder.dev)
+ drm_encoder_cleanup(&dsi->encoder);
+
+ pm_runtime_disable(dev);
+}
+
+static const struct component_ops imx_nwl_dsi_component_ops = {
+ .bind = imx_nwl_dsi_bind,
+ .unbind = imx_nwl_dsi_unbind,
+};
+
+static int imx_nwl_dsi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *remote_node, *endpoint;
+ int remote_ports = 0;
+ struct imx_mipi_dsi *dsi;
+ int ret = 0;
+
+ if (!np)
+ return -ENODEV;
+
+ dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
+ if (!dsi)
+ return -ENOMEM;
+
+ /* Search for next bridge (usually the DSI HOST bridge) */
+ endpoint = of_graph_get_next_endpoint(np, NULL);
+ while (endpoint && !dsi->next_bridge) {
+ remote_node = of_graph_get_remote_port_parent(endpoint);
+ if (!remote_node) {
+ dev_err(dev, "No endpoint found!\n");
+ return -ENODEV;
+ }
+
+ dsi->next_bridge = of_drm_find_bridge(remote_node);
+ of_node_put(remote_node);
+ endpoint = of_graph_get_next_endpoint(np, endpoint);
+ if (!of_device_is_available(remote_node))
+ continue;
+ remote_ports++;
+ };
+
+ /*
+ * Normally, we should have two remote ports: one is our input source,
+ * while the second is the NWL host bridge. This bridge can be disabled
+ * if the connector fails to find a physical device. In this case, we
+ * should continue and do nothing, so that DRM master can bind all the
+ * components.
+ */
+ if (!dsi->next_bridge && remote_ports == 2) {
+ dev_warn(dev, "Waiting for DSI host bridge\n");
+ return -EPROBE_DEFER;
+ }
+
+ dsi->dev = dev;
+ dev_set_drvdata(dev, dsi);
+
+ pm_runtime_enable(dev);
+
+ if (of_property_read_bool(dev->of_node, "as_bridge")) {
+ ret = imx_nwl_dsi_parse_of(dev, true);
+ if (ret)
+ return ret;
+ /* Create our bridge */
+ dsi->bridge.driver_private = dsi;
+ dsi->bridge.funcs = &imx_nwl_dsi_bridge_funcs;
+ dsi->bridge.of_node = np;
+
+ ret = drm_bridge_add(&dsi->bridge);
+ if (ret) {
+ dev_err(dev, "Failed to add imx-nwl-dsi bridge (%d)\n",
+ ret);
+ return ret;
+ }
+ dev_info(dev, "Added drm bridge!");
+ return 0;
+ }
+
+ return component_add(&pdev->dev, &imx_nwl_dsi_component_ops);
+}
+
+static int imx_nwl_dsi_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &imx_nwl_dsi_component_ops);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int imx_nwl_suspend(struct device *dev)
+{
+ struct imx_mipi_dsi *dsi = dev_get_drvdata(dev);
+
+ if (!dsi->enabled)
+ return 0;
+
+ if (dsi->next_bridge)
+ drm_bridge_disable(dsi->next_bridge);
+ imx_nwl_dsi_disable(dsi);
+ dsi->suspended = true;
+
+ return 0;
+}
+
+static int imx_nwl_resume(struct device *dev)
+{
+ struct imx_mipi_dsi *dsi = dev_get_drvdata(dev);
+
+ if (!dsi->suspended)
+ return 0;
+
+ imx_nwl_dsi_enable(dsi);
+ if (dsi->next_bridge)
+ drm_bridge_enable(dsi->next_bridge);
+ dsi->suspended = false;
+
+ return 0;
+}
+
+#endif
+
+static const struct dev_pm_ops imx_nwl_pm_ops = {
+ SET_RUNTIME_PM_OPS(imx_nwl_suspend, imx_nwl_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(imx_nwl_suspend, imx_nwl_resume)
+};
+
+static struct platform_driver imx_nwl_dsi_driver = {
+ .probe = imx_nwl_dsi_probe,
+ .remove = imx_nwl_dsi_remove,
+ .driver = {
+ .of_match_table = imx_nwl_dsi_dt_ids,
+ .name = DRIVER_NAME,
+ .pm = &imx_nwl_pm_ops,
+ },
+};
+
+module_platform_driver(imx_nwl_dsi_driver);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("i.MX Northwest Logic MIPI-DSI driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/gpu/drm/imx/sec_mipi_dphy_ln14lpp.h b/drivers/gpu/drm/imx/sec_mipi_dphy_ln14lpp.h
new file mode 100644
index 000000000000..b302ed064e25
--- /dev/null
+++ b/drivers/gpu/drm/imx/sec_mipi_dphy_ln14lpp.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SEC_DSIM_DPHY_LN14LPP_H__
+#define __SEC_DSIM_DPHY_LN14LPP_H__
+
+#include <drm/bridge/sec_mipi_dsim.h>
+
+/* descending order based on 'bit_clk' value */
+static const struct sec_mipi_dsim_dphy_timing dphy_timing_ln14lpp_v1p2[] = {
+ { DSIM_DPHY_TIMING(2100, 19, 91, 22, 19, 20, 35, 22, 15, 26), },
+ { DSIM_DPHY_TIMING(2090, 19, 91, 22, 19, 19, 35, 22, 15, 26), },
+ { DSIM_DPHY_TIMING(2080, 19, 91, 21, 18, 19, 35, 22, 15, 26), },
+ { DSIM_DPHY_TIMING(2070, 18, 90, 21, 18, 19, 35, 22, 15, 25), },
+ { DSIM_DPHY_TIMING(2060, 18, 90, 21, 18, 19, 34, 22, 15, 25), },
+ { DSIM_DPHY_TIMING(2050, 18, 89, 21, 18, 19, 34, 22, 15, 25), },
+ { DSIM_DPHY_TIMING(2040, 18, 89, 21, 18, 19, 34, 21, 15, 25), },
+ { DSIM_DPHY_TIMING(2030, 18, 88, 21, 18, 19, 34, 21, 15, 25), },
+ { DSIM_DPHY_TIMING(2020, 18, 88, 21, 18, 19, 34, 21, 15, 25), },
+ { DSIM_DPHY_TIMING(2010, 18, 87, 21, 18, 19, 34, 21, 15, 25), },
+ { DSIM_DPHY_TIMING(2000, 18, 87, 21, 18, 19, 33, 21, 15, 25), },
+ { DSIM_DPHY_TIMING(1990, 18, 87, 21, 18, 18, 33, 21, 14, 24), },
+ { DSIM_DPHY_TIMING(1980, 18, 86, 21, 18, 18, 33, 21, 14, 24), },
+ { DSIM_DPHY_TIMING(1970, 17, 86, 21, 17, 18, 33, 21, 14, 24), },
+ { DSIM_DPHY_TIMING(1960, 17, 85, 21, 17, 18, 33, 21, 14, 24), },
+ { DSIM_DPHY_TIMING(1950, 17, 85, 21, 17, 18, 32, 21, 14, 24), },
+ { DSIM_DPHY_TIMING(1940, 17, 84, 20, 17, 18, 32, 21, 14, 24), },
+ { DSIM_DPHY_TIMING(1930, 17, 84, 20, 17, 18, 32, 20, 14, 24), },
+ { DSIM_DPHY_TIMING(1920, 17, 84, 20, 17, 18, 32, 20, 14, 24), },
+ { DSIM_DPHY_TIMING(1910, 17, 83, 20, 17, 18, 32, 20, 14, 23), },
+ { DSIM_DPHY_TIMING(1900, 17, 83, 20, 17, 18, 32, 20, 14, 23), },
+ { DSIM_DPHY_TIMING(1890, 17, 82, 20, 17, 18, 31, 20, 14, 23), },
+ { DSIM_DPHY_TIMING(1880, 17, 82, 20, 17, 17, 31, 20, 14, 23), },
+ { DSIM_DPHY_TIMING(1870, 17, 81, 20, 17, 17, 31, 20, 14, 23), },
+ { DSIM_DPHY_TIMING(1860, 16, 81, 20, 17, 17, 31, 20, 13, 23), },
+ { DSIM_DPHY_TIMING(1850, 16, 80, 20, 16, 17, 31, 20, 13, 23), },
+ { DSIM_DPHY_TIMING(1840, 16, 80, 20, 16, 17, 30, 20, 13, 23), },
+ { DSIM_DPHY_TIMING(1830, 16, 80, 20, 16, 17, 30, 20, 13, 22), },
+ { DSIM_DPHY_TIMING(1820, 16, 79, 20, 16, 17, 30, 19, 13, 22), },
+ { DSIM_DPHY_TIMING(1810, 16, 79, 19, 16, 17, 30, 19, 13, 22), },
+ { DSIM_DPHY_TIMING(1800, 16, 78, 19, 16, 17, 30, 19, 13, 22), },
+ { DSIM_DPHY_TIMING(1790, 16, 78, 19, 16, 17, 30, 19, 13, 22), },
+ { DSIM_DPHY_TIMING(1780, 16, 77, 19, 16, 16, 29, 19, 13, 22), },
+ { DSIM_DPHY_TIMING(1770, 16, 77, 19, 16, 16, 29, 19, 13, 22), },
+ { DSIM_DPHY_TIMING(1760, 16, 77, 19, 16, 16, 29, 19, 13, 22), },
+ { DSIM_DPHY_TIMING(1750, 15, 76, 19, 16, 16, 29, 19, 13, 21), },
+ { DSIM_DPHY_TIMING(1740, 15, 76, 19, 15, 16, 29, 19, 13, 21), },
+ { DSIM_DPHY_TIMING(1730, 15, 75, 19, 15, 16, 28, 19, 12, 21), },
+ { DSIM_DPHY_TIMING(1720, 15, 75, 19, 15, 16, 28, 19, 12, 21), },
+ { DSIM_DPHY_TIMING(1710, 15, 74, 19, 15, 16, 28, 18, 12, 21), },
+ { DSIM_DPHY_TIMING(1700, 15, 74, 19, 15, 16, 28, 18, 12, 21), },
+ { DSIM_DPHY_TIMING(1690, 15, 73, 19, 15, 16, 28, 18, 12, 21), },
+ { DSIM_DPHY_TIMING(1680, 15, 73, 18, 15, 16, 28, 18, 12, 21), },
+ { DSIM_DPHY_TIMING(1670, 15, 73, 18, 15, 15, 27, 18, 12, 20), },
+ { DSIM_DPHY_TIMING(1660, 15, 72, 18, 15, 15, 27, 18, 12, 20), },
+ { DSIM_DPHY_TIMING(1650, 14, 72, 18, 15, 15, 27, 18, 12, 20), },
+ { DSIM_DPHY_TIMING(1640, 14, 71, 18, 15, 15, 27, 18, 12, 20), },
+ { DSIM_DPHY_TIMING(1630, 14, 71, 18, 15, 15, 27, 18, 12, 20), },
+ { DSIM_DPHY_TIMING(1620, 14, 70, 18, 14, 15, 26, 18, 12, 20), },
+ { DSIM_DPHY_TIMING(1610, 14, 70, 18, 14, 15, 26, 17, 12, 20), },
+ { DSIM_DPHY_TIMING(1600, 14, 70, 18, 14, 15, 26, 17, 12, 20), },
+ { DSIM_DPHY_TIMING(1590, 14, 69, 18, 14, 15, 26, 17, 11, 19), },
+ { DSIM_DPHY_TIMING(1580, 14, 69, 18, 14, 15, 26, 17, 11, 19), },
+ { DSIM_DPHY_TIMING(1570, 14, 68, 18, 14, 15, 26, 17, 11, 19), },
+ { DSIM_DPHY_TIMING(1560, 14, 68, 18, 14, 14, 25, 17, 11, 19), },
+ { DSIM_DPHY_TIMING(1550, 14, 67, 18, 14, 14, 25, 17, 11, 19), },
+ { DSIM_DPHY_TIMING(1540, 13, 67, 17, 14, 14, 25, 17, 11, 19), },
+ { DSIM_DPHY_TIMING(1530, 13, 66, 17, 14, 14, 25, 17, 11, 19), },
+ { DSIM_DPHY_TIMING(1520, 13, 66, 17, 14, 14, 25, 17, 11, 19), },
+ { DSIM_DPHY_TIMING(1510, 13, 66, 17, 13, 14, 24, 17, 11, 18), },
+ { DSIM_DPHY_TIMING(1500, 13, 65, 17, 13, 14, 24, 16, 11, 18), },
+ { DSIM_DPHY_TIMING(1490, 13, 65, 17, 13, 14, 24, 16, 11, 18), },
+ { DSIM_DPHY_TIMING(1480, 13, 64, 17, 13, 14, 24, 16, 11, 18), },
+ { DSIM_DPHY_TIMING(1470, 13, 64, 17, 13, 14, 24, 16, 11, 18), },
+ { DSIM_DPHY_TIMING(1460, 13, 63, 17, 13, 13, 24, 16, 10, 18), },
+ { DSIM_DPHY_TIMING(1450, 13, 63, 17, 13, 13, 23, 16, 10, 18), },
+ { DSIM_DPHY_TIMING(1440, 13, 63, 17, 13, 13, 23, 16, 10, 18), },
+ { DSIM_DPHY_TIMING(1430, 12, 62, 17, 13, 13, 23, 16, 10, 17), },
+ { DSIM_DPHY_TIMING(1420, 12, 62, 17, 13, 13, 23, 16, 10, 17), },
+ { DSIM_DPHY_TIMING(1410, 12, 61, 16, 13, 13, 23, 16, 10, 17), },
+ { DSIM_DPHY_TIMING(1400, 12, 61, 16, 13, 13, 23, 16, 10, 17), },
+ { DSIM_DPHY_TIMING(1390, 12, 60, 16, 12, 13, 22, 15, 10, 17), },
+ { DSIM_DPHY_TIMING(1380, 12, 60, 16, 12, 13, 22, 15, 10, 17), },
+ { DSIM_DPHY_TIMING(1370, 12, 59, 16, 12, 13, 22, 15, 10, 17), },
+ { DSIM_DPHY_TIMING(1360, 12, 59, 16, 12, 13, 22, 15, 10, 17), },
+ { DSIM_DPHY_TIMING(1350, 12, 59, 16, 12, 12, 22, 15, 10, 16), },
+ { DSIM_DPHY_TIMING(1340, 12, 58, 16, 12, 12, 21, 15, 10, 16), },
+ { DSIM_DPHY_TIMING(1330, 11, 58, 16, 12, 12, 21, 15, 9, 16), },
+ { DSIM_DPHY_TIMING(1320, 11, 57, 16, 12, 12, 21, 15, 9, 16), },
+ { DSIM_DPHY_TIMING(1310, 11, 57, 16, 12, 12, 21, 15, 9, 16), },
+ { DSIM_DPHY_TIMING(1300, 11, 56, 16, 12, 12, 21, 15, 9, 16), },
+ { DSIM_DPHY_TIMING(1290, 11, 56, 16, 12, 12, 21, 15, 9, 16), },
+ { DSIM_DPHY_TIMING(1280, 11, 56, 15, 11, 12, 20, 14, 9, 16), },
+ { DSIM_DPHY_TIMING(1270, 11, 55, 15, 11, 12, 20, 14, 9, 15), },
+ { DSIM_DPHY_TIMING(1260, 11, 55, 15, 11, 12, 20, 14, 9, 15), },
+ { DSIM_DPHY_TIMING(1250, 11, 54, 15, 11, 11, 20, 14, 9, 15), },
+ { DSIM_DPHY_TIMING(1240, 11, 54, 15, 11, 11, 20, 14, 9, 15), },
+ { DSIM_DPHY_TIMING(1230, 11, 53, 15, 11, 11, 19, 14, 9, 15), },
+ { DSIM_DPHY_TIMING(1220, 10, 53, 15, 11, 11, 19, 14, 9, 15), },
+ { DSIM_DPHY_TIMING(1210, 10, 52, 15, 11, 11, 19, 14, 9, 15), },
+ { DSIM_DPHY_TIMING(1200, 10, 52, 15, 11, 11, 19, 14, 9, 15), },
+ { DSIM_DPHY_TIMING(1190, 10, 52, 15, 11, 11, 19, 14, 8, 14), },
+ { DSIM_DPHY_TIMING(1180, 10, 51, 15, 11, 11, 19, 13, 8, 14), },
+ { DSIM_DPHY_TIMING(1170, 10, 51, 15, 10, 11, 18, 13, 8, 14), },
+ { DSIM_DPHY_TIMING(1160, 10, 50, 15, 10, 11, 18, 13, 8, 14), },
+ { DSIM_DPHY_TIMING(1150, 10, 50, 15, 10, 11, 18, 13, 8, 14), },
+ { DSIM_DPHY_TIMING(1140, 10, 49, 14, 10, 10, 18, 13, 8, 14), },
+ { DSIM_DPHY_TIMING(1130, 10, 49, 14, 10, 10, 18, 13, 8, 14), },
+ { DSIM_DPHY_TIMING(1120, 10, 49, 14, 10, 10, 17, 13, 8, 14), },
+ { DSIM_DPHY_TIMING(1110, 9, 48, 14, 10, 10, 17, 13, 8, 13), },
+ { DSIM_DPHY_TIMING(1100, 9, 48, 14, 10, 10, 17, 13, 8, 13), },
+ { DSIM_DPHY_TIMING(1090, 9, 47, 14, 10, 10, 17, 13, 8, 13), },
+ { DSIM_DPHY_TIMING(1080, 9, 47, 14, 10, 10, 17, 13, 8, 13), },
+ { DSIM_DPHY_TIMING(1070, 9, 46, 14, 10, 10, 17, 12, 8, 13), },
+ { DSIM_DPHY_TIMING(1060, 9, 46, 14, 10, 10, 16, 12, 7, 13), },
+ { DSIM_DPHY_TIMING(1050, 9, 45, 14, 9, 10, 16, 12, 7, 13), },
+ { DSIM_DPHY_TIMING(1040, 9, 45, 14, 9, 10, 16, 12, 7, 13), },
+ { DSIM_DPHY_TIMING(1030, 9, 45, 14, 9, 9, 16, 12, 7, 12), },
+ { DSIM_DPHY_TIMING(1020, 9, 44, 14, 9, 9, 16, 12, 7, 12), },
+ { DSIM_DPHY_TIMING(1010, 8, 44, 13, 9, 9, 15, 12, 7, 12), },
+ { DSIM_DPHY_TIMING(1000, 8, 43, 13, 9, 9, 15, 12, 7, 12), },
+ { DSIM_DPHY_TIMING( 990, 8, 43, 13, 9, 9, 15, 12, 7, 12), },
+ { DSIM_DPHY_TIMING( 980, 8, 42, 13, 9, 9, 15, 12, 7, 12), },
+ { DSIM_DPHY_TIMING( 970, 8, 42, 13, 9, 9, 15, 12, 7, 12), },
+ { DSIM_DPHY_TIMING( 960, 8, 42, 13, 9, 9, 15, 11, 7, 12), },
+ { DSIM_DPHY_TIMING( 950, 8, 41, 13, 9, 9, 14, 11, 7, 11), },
+ { DSIM_DPHY_TIMING( 940, 8, 41, 13, 8, 9, 14, 11, 7, 11), },
+ { DSIM_DPHY_TIMING( 930, 8, 40, 13, 8, 8, 14, 11, 6, 11), },
+ { DSIM_DPHY_TIMING( 920, 8, 40, 13, 8, 8, 14, 11, 6, 11), },
+ { DSIM_DPHY_TIMING( 910, 8, 39, 13, 8, 8, 14, 11, 6, 11), },
+ { DSIM_DPHY_TIMING( 900, 7, 39, 13, 8, 8, 13, 11, 6, 11), },
+ { DSIM_DPHY_TIMING( 890, 7, 38, 13, 8, 8, 13, 11, 6, 11), },
+ { DSIM_DPHY_TIMING( 880, 7, 38, 12, 8, 8, 13, 11, 6, 11), },
+ { DSIM_DPHY_TIMING( 870, 7, 38, 12, 8, 8, 13, 11, 6, 10), },
+ { DSIM_DPHY_TIMING( 860, 7, 37, 12, 8, 8, 13, 11, 6, 10), },
+ { DSIM_DPHY_TIMING( 850, 7, 37, 12, 8, 8, 13, 10, 6, 10), },
+ { DSIM_DPHY_TIMING( 840, 7, 36, 12, 8, 8, 12, 10, 6, 10), },
+ { DSIM_DPHY_TIMING( 830, 7, 36, 12, 8, 8, 12, 10, 6, 10), },
+ { DSIM_DPHY_TIMING( 820, 7, 35, 12, 7, 7, 12, 10, 6, 10), },
+ { DSIM_DPHY_TIMING( 810, 7, 35, 12, 7, 7, 12, 10, 6, 10), },
+ { DSIM_DPHY_TIMING( 800, 7, 35, 12, 7, 7, 12, 10, 6, 10), },
+ { DSIM_DPHY_TIMING( 790, 6, 34, 12, 7, 7, 11, 10, 5, 9), },
+ { DSIM_DPHY_TIMING( 780, 6, 34, 12, 7, 7, 11, 10, 5, 9), },
+ { DSIM_DPHY_TIMING( 770, 6, 33, 12, 7, 7, 11, 10, 5, 9), },
+ { DSIM_DPHY_TIMING( 760, 6, 33, 12, 7, 7, 11, 10, 5, 9), },
+ { DSIM_DPHY_TIMING( 750, 6, 32, 12, 7, 7, 11, 9, 5, 9), },
+ { DSIM_DPHY_TIMING( 740, 6, 32, 11, 7, 7, 11, 9, 5, 9), },
+ { DSIM_DPHY_TIMING( 730, 6, 31, 11, 7, 7, 10, 9, 5, 9), },
+ { DSIM_DPHY_TIMING( 720, 6, 31, 11, 7, 6, 10, 9, 5, 9), },
+ { DSIM_DPHY_TIMING( 710, 6, 31, 11, 6, 6, 10, 9, 5, 8), },
+ { DSIM_DPHY_TIMING( 700, 6, 30, 11, 6, 6, 10, 9, 5, 8), },
+ { DSIM_DPHY_TIMING( 690, 5, 30, 11, 6, 6, 10, 9, 5, 8), },
+ { DSIM_DPHY_TIMING( 680, 5, 29, 11, 6, 6, 9, 9, 5, 8), },
+ { DSIM_DPHY_TIMING( 670, 5, 29, 11, 6, 6, 9, 9, 5, 8), },
+ { DSIM_DPHY_TIMING( 660, 5, 28, 11, 6, 6, 9, 9, 4, 8), },
+ { DSIM_DPHY_TIMING( 650, 5, 28, 11, 6, 6, 9, 9, 4, 8), },
+ { DSIM_DPHY_TIMING( 640, 5, 28, 11, 6, 6, 9, 8, 4, 8), },
+ { DSIM_DPHY_TIMING( 630, 5, 27, 11, 6, 6, 9, 8, 4, 7), },
+ { DSIM_DPHY_TIMING( 620, 5, 27, 11, 6, 6, 8, 8, 4, 7), },
+ { DSIM_DPHY_TIMING( 610, 5, 26, 10, 6, 5, 8, 8, 4, 7), },
+ { DSIM_DPHY_TIMING( 600, 5, 26, 10, 6, 5, 8, 8, 4, 7), },
+ { DSIM_DPHY_TIMING( 590, 5, 25, 10, 5, 5, 8, 8, 4, 7), },
+ { DSIM_DPHY_TIMING( 580, 4, 25, 10, 5, 5, 8, 8, 4, 7), },
+ { DSIM_DPHY_TIMING( 570, 4, 24, 10, 5, 5, 7, 8, 4, 7), },
+ { DSIM_DPHY_TIMING( 560, 4, 24, 10, 5, 5, 7, 8, 4, 7), },
+ { DSIM_DPHY_TIMING( 550, 4, 24, 10, 5, 5, 7, 8, 4, 6), },
+ { DSIM_DPHY_TIMING( 540, 4, 23, 10, 5, 5, 7, 8, 4, 6), },
+ { DSIM_DPHY_TIMING( 530, 4, 23, 10, 5, 5, 7, 7, 3, 6), },
+ { DSIM_DPHY_TIMING( 520, 4, 22, 10, 5, 5, 7, 7, 3, 6), },
+ { DSIM_DPHY_TIMING( 510, 4, 22, 10, 5, 5, 6, 7, 3, 6), },
+ { DSIM_DPHY_TIMING( 500, 4, 21, 10, 5, 4, 6, 7, 3, 6), },
+ { DSIM_DPHY_TIMING( 490, 4, 21, 10, 5, 4, 6, 7, 3, 6), },
+ { DSIM_DPHY_TIMING( 480, 4, 21, 9, 4, 4, 6, 7, 3, 6), },
+ { DSIM_DPHY_TIMING( 470, 3, 20, 9, 4, 4, 6, 7, 3, 5), },
+ { DSIM_DPHY_TIMING( 460, 3, 20, 9, 4, 4, 5, 7, 3, 5), },
+ { DSIM_DPHY_TIMING( 450, 3, 19, 9, 4, 4, 5, 7, 3, 5), },
+ { DSIM_DPHY_TIMING( 440, 3, 19, 9, 4, 4, 5, 7, 3, 5), },
+ { DSIM_DPHY_TIMING( 430, 3, 18, 9, 4, 4, 5, 7, 3, 5), },
+ { DSIM_DPHY_TIMING( 420, 3, 18, 9, 4, 4, 5, 6, 3, 5), },
+ { DSIM_DPHY_TIMING( 410, 3, 17, 9, 4, 4, 5, 6, 3, 5), },
+ { DSIM_DPHY_TIMING( 400, 3, 17, 9, 4, 3, 4, 6, 3, 5), },
+ { DSIM_DPHY_TIMING( 390, 3, 17, 9, 4, 3, 4, 6, 2, 4), },
+ { DSIM_DPHY_TIMING( 380, 3, 16, 9, 4, 3, 4, 6, 2, 4), },
+ { DSIM_DPHY_TIMING( 370, 2, 16, 9, 3, 3, 4, 6, 2, 4), },
+ { DSIM_DPHY_TIMING( 360, 2, 15, 9, 3, 3, 4, 6, 2, 4), },
+ { DSIM_DPHY_TIMING( 350, 2, 15, 9, 3, 3, 3, 6, 2, 4), },
+ { DSIM_DPHY_TIMING( 340, 2, 14, 8, 3, 3, 3, 6, 2, 4), },
+ { DSIM_DPHY_TIMING( 330, 2, 14, 8, 3, 3, 3, 6, 2, 4), },
+ { DSIM_DPHY_TIMING( 320, 2, 14, 8, 3, 3, 3, 5, 2, 4), },
+ { DSIM_DPHY_TIMING( 310, 2, 13, 8, 3, 3, 3, 5, 2, 3), },
+ { DSIM_DPHY_TIMING( 300, 2, 13, 8, 3, 3, 3, 5, 2, 3), },
+ { DSIM_DPHY_TIMING( 290, 2, 12, 8, 3, 2, 2, 5, 2, 3), },
+ { DSIM_DPHY_TIMING( 280, 2, 12, 8, 3, 2, 2, 5, 2, 3), },
+ { DSIM_DPHY_TIMING( 270, 2, 11, 8, 3, 2, 2, 5, 2, 3), },
+ { DSIM_DPHY_TIMING( 260, 1, 11, 8, 3, 2, 2, 5, 1, 3), },
+ { DSIM_DPHY_TIMING( 250, 1, 10, 8, 2, 2, 2, 5, 1, 3), },
+ { DSIM_DPHY_TIMING( 240, 1, 9, 8, 2, 2, 1, 5, 1, 3), },
+ { DSIM_DPHY_TIMING( 230, 1, 8, 8, 2, 2, 1, 5, 1, 2), },
+ { DSIM_DPHY_TIMING( 220, 1, 8, 8, 2, 2, 1, 5, 1, 2), },
+ { DSIM_DPHY_TIMING( 210, 1, 7, 7, 2, 2, 1, 4, 1, 2), },
+ { DSIM_DPHY_TIMING( 200, 1, 7, 7, 2, 2, 1, 4, 1, 2), },
+ { DSIM_DPHY_TIMING( 190, 1, 7, 7, 2, 1, 1, 4, 1, 2), },
+ { DSIM_DPHY_TIMING( 180, 1, 6, 7, 2, 1, 0, 4, 1, 2), },
+ { DSIM_DPHY_TIMING( 170, 1, 6, 7, 2, 1, 0, 4, 1, 2), },
+ { DSIM_DPHY_TIMING( 160, 1, 6, 7, 2, 1, 0, 4, 1, 2), },
+ { DSIM_DPHY_TIMING( 150, 0, 5, 7, 2, 1, 0, 4, 1, 1), },
+ { DSIM_DPHY_TIMING( 140, 0, 5, 7, 1, 1, 0, 4, 1, 1), },
+ { DSIM_DPHY_TIMING( 130, 0, 4, 7, 1, 1, 0, 4, 0, 1), },
+ { DSIM_DPHY_TIMING( 120, 0, 4, 7, 1, 1, 0, 4, 0, 1), },
+ { DSIM_DPHY_TIMING( 110, 0, 3, 7, 1, 0, 0, 4, 0, 1), },
+ { DSIM_DPHY_TIMING( 100, 0, 3, 7, 1, 0, 0, 3, 0, 1), },
+ { DSIM_DPHY_TIMING( 90, 0, 2, 7, 1, 0, 0, 3, 0, 1), },
+ { DSIM_DPHY_TIMING( 80, 0, 2, 6, 1, 0, 0, 3, 0, 1), },
+};
+
+#endif
diff --git a/drivers/gpu/drm/imx/sec_mipi_dsim-imx.c b/drivers/gpu/drm/imx/sec_mipi_dsim-imx.c
new file mode 100644
index 000000000000..eafbd226c5b2
--- /dev/null
+++ b/drivers/gpu/drm/imx/sec_mipi_dsim-imx.c
@@ -0,0 +1,388 @@
+/*
+ * Samsung MIPI DSI Host Controller on IMX
+ *
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <drm/bridge/sec_mipi_dsim.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_modeset_helper_vtables.h>
+
+#include "imx-drm.h"
+#include "sec_mipi_dphy_ln14lpp.h"
+
+#define DRIVER_NAME "imx_sec_dsim_drv"
+
+/* Dispmix Control & GPR Registers */
+#define DISPLAY_MIX_SFT_RSTN_CSR 0X00
+ #define MIPI_DSI_I_PRESETn_SFT_EN BIT(5)
+#define DISPLAY_MIX_CLK_EN_CSR 0x04
+ #define MIPI_DSI_PCLK_SFT_EN BIT(8)
+ #define MIPI_DSI_CLKREF_SFT_EN BIT(9)
+#define GPR_MIPI_RESET_DIV 0x08
+ /* Clock & Data lanes reset: Active Low */
+ #define GPR_MIPI_S_RESETN BIT(16)
+ #define GPR_MIPI_M_RESETN BIT(17)
+
+struct imx_sec_dsim_device {
+ struct device *dev;
+ struct drm_encoder encoder;
+ struct regmap *gpr;
+
+ atomic_t rpm_suspended;
+};
+
+#define enc_to_dsim(enc) container_of(enc, struct imx_sec_dsim_device, encoder)
+
+static struct imx_sec_dsim_device *dsim_dev;
+
+#if CONFIG_PM
+static int imx_sec_dsim_runtime_suspend(struct device *dev);
+static int imx_sec_dsim_runtime_resume(struct device *dev);
+#else
+static int imx_sec_dsim_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+static int imx_sec_dsim_runtime_resume(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+static void disp_mix_dsim_soft_reset_release(struct regmap *gpr, bool release)
+{
+ if (release)
+ /* release dsi blk reset */
+ regmap_update_bits(gpr, DISPLAY_MIX_SFT_RSTN_CSR,
+ MIPI_DSI_I_PRESETn_SFT_EN,
+ MIPI_DSI_I_PRESETn_SFT_EN);
+ else
+ regmap_update_bits(gpr, DISPLAY_MIX_SFT_RSTN_CSR,
+ MIPI_DSI_I_PRESETn_SFT_EN,
+ 0x0);
+}
+
+static void disp_mix_dsim_clks_enable(struct regmap *gpr, bool enable)
+{
+ if (enable)
+ regmap_update_bits(gpr, DISPLAY_MIX_CLK_EN_CSR,
+ MIPI_DSI_PCLK_SFT_EN | MIPI_DSI_CLKREF_SFT_EN,
+ MIPI_DSI_PCLK_SFT_EN | MIPI_DSI_CLKREF_SFT_EN);
+ else
+ regmap_update_bits(gpr, DISPLAY_MIX_CLK_EN_CSR,
+ MIPI_DSI_PCLK_SFT_EN | MIPI_DSI_CLKREF_SFT_EN,
+ 0x0);
+}
+
+static void imx_sec_dsim_lanes_reset(struct regmap *gpr, bool reset)
+{
+ if (!reset)
+ /* release lanes reset */
+ regmap_update_bits(gpr, GPR_MIPI_RESET_DIV,
+ GPR_MIPI_S_RESETN | GPR_MIPI_M_RESETN,
+ GPR_MIPI_S_RESETN | GPR_MIPI_M_RESETN);
+ else
+ /* reset lanes */
+ regmap_update_bits(gpr, GPR_MIPI_RESET_DIV,
+ GPR_MIPI_S_RESETN | GPR_MIPI_M_RESETN,
+ 0x0);
+}
+
+static void imx_sec_dsim_encoder_helper_enable(struct drm_encoder *encoder)
+{
+ struct imx_sec_dsim_device *dsim_dev = enc_to_dsim(encoder);
+
+ pm_runtime_get_sync(dsim_dev->dev);
+
+ imx_sec_dsim_lanes_reset(dsim_dev->gpr, false);
+}
+
+static void imx_sec_dsim_encoder_helper_disable(struct drm_encoder *encoder)
+{
+ struct imx_sec_dsim_device *dsim_dev = enc_to_dsim(encoder);
+
+ imx_sec_dsim_lanes_reset(dsim_dev->gpr, true);
+
+ pm_runtime_put_sync(dsim_dev->dev);
+}
+
+static int imx_sec_dsim_encoder_helper_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ int i, ret;
+ u32 bus_format;
+ unsigned int num_bus_formats;
+ struct imx_sec_dsim_device *dsim_dev = enc_to_dsim(encoder);
+ struct drm_bridge *bridge = encoder->bridge;
+ struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
+ struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
+ struct drm_display_info *display_info = &conn_state->connector->display_info;
+
+ num_bus_formats = display_info->num_bus_formats;
+ if (unlikely(!num_bus_formats))
+ dev_warn(dsim_dev->dev, "no bus formats assigned by connector\n");
+
+ bus_format = adjusted_mode->private_flags & 0xffff;
+
+ for (i = 0; i < num_bus_formats; i++) {
+ if (display_info->bus_formats[i] != bus_format)
+ continue;
+ break;
+ }
+
+ if (i && i == num_bus_formats) {
+ dev_err(dsim_dev->dev, "invalid bus format for connector\n");
+ return -EINVAL;
+ }
+
+ /* check pll out */
+ ret = sec_mipi_dsim_check_pll_out(bridge->driver_private,
+ adjusted_mode);
+ if (ret)
+ return ret;
+
+ /* sec dsim can only accept active hight DE */
+ imx_crtc_state->bus_flags |= DRM_BUS_FLAG_DE_HIGH;
+
+ /* For the dotclock polarity, default is neg edge;
+ * and in the dsim spec, there is no explict words
+ * to illustrate the dotclock polarity requirement.
+ */
+ imx_crtc_state->bus_flags |= DRM_BUS_FLAG_PIXDATA_NEGEDGE;
+
+ /* set the bus format for CRTC output which should be
+ * the same as the bus format between dsim and connector,
+ * since dsim cannot do any pixel conversions.
+ */
+ imx_crtc_state->bus_format = bus_format;
+
+ return 0;
+}
+
+static const struct drm_encoder_helper_funcs imx_sec_dsim_encoder_helper_funcs = {
+ .enable = imx_sec_dsim_encoder_helper_enable,
+ .disable = imx_sec_dsim_encoder_helper_disable,
+ .atomic_check = imx_sec_dsim_encoder_helper_atomic_check,
+};
+
+static const struct drm_encoder_funcs imx_sec_dsim_encoder_funcs = {
+ .destroy = imx_drm_encoder_destroy,
+};
+
+static const struct sec_mipi_dsim_plat_data imx8mm_mipi_dsim_plat_data = {
+ .version = 0x1060200,
+ .max_data_lanes = 4,
+ .max_data_rate = 1500000000ULL,
+ .dphy_timing = dphy_timing_ln14lpp_v1p2,
+ .num_dphy_timing = ARRAY_SIZE(dphy_timing_ln14lpp_v1p2),
+ .dphy_timing_cmp = dphy_timing_default_cmp,
+ .mode_valid = NULL,
+};
+
+static const struct of_device_id imx_sec_dsim_dt_ids[] = {
+ {
+ .compatible = "fsl,imx8mm-mipi-dsim",
+ .data = &imx8mm_mipi_dsim_plat_data,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_sec_dsim_dt_ids);
+
+static int imx_sec_dsim_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ int ret, irq;
+ struct resource *res;
+ struct drm_device *drm_dev = data;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct device_node *np = dev->of_node;
+ const struct of_device_id *of_id = of_match_device(imx_sec_dsim_dt_ids,
+ dev);
+ const struct sec_mipi_dsim_plat_data *pdata = of_id->data;
+ struct drm_encoder *encoder;
+
+ dev_dbg(dev, "%s: dsim bind begin\n", __func__);
+ dsim_dev = devm_kzalloc(dev, sizeof(*dsim_dev), GFP_KERNEL);
+ if (!dsim_dev) {
+ dev_err(dev, "Unable to allocate 'dsim_dev'\n");
+ return -ENOMEM;
+ }
+
+ dsim_dev->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return -ENODEV;
+
+ dsim_dev->gpr = syscon_regmap_lookup_by_phandle(np, "dsi-gpr");
+ if (IS_ERR(dsim_dev->gpr))
+ return PTR_ERR(dsim_dev->gpr);
+
+ encoder = &dsim_dev->encoder;
+ ret = imx_drm_encoder_parse_of(drm_dev, encoder, np);
+ if (ret)
+ return ret;
+
+ drm_encoder_helper_add(encoder, &imx_sec_dsim_encoder_helper_funcs);
+
+ ret = drm_encoder_init(drm_dev, encoder,
+ &imx_sec_dsim_encoder_funcs,
+ DRM_MODE_ENCODER_DSI, dev_name(dev));
+ if (ret)
+ return ret;
+
+ /* bind sec dsim bridge */
+ ret = sec_mipi_dsim_bind(dev, master, data, encoder, res, irq, pdata);
+ if (ret) {
+ dev_err(dev, "failed to bind sec dsim bridge: %d\n", ret);
+ drm_encoder_cleanup(encoder);
+ return ret;
+ }
+
+ atomic_set(&dsim_dev->rpm_suspended, 0);
+ pm_runtime_enable(dev);
+ atomic_inc(&dsim_dev->rpm_suspended);
+
+ dev_dbg(dev, "%s: dsim bind end\n", __func__);
+
+ return 0;
+}
+
+static void imx_sec_dsim_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ pm_runtime_disable(dev);
+
+ sec_mipi_dsim_unbind(dev, master, data);
+
+ drm_encoder_cleanup(&dsim_dev->encoder);
+}
+
+static const struct component_ops imx_sec_dsim_ops = {
+ .bind = imx_sec_dsim_bind,
+ .unbind = imx_sec_dsim_unbind,
+};
+
+static int imx_sec_dsim_probe(struct platform_device *pdev)
+{
+ dev_dbg(&pdev->dev, "%s: dsim probe begin\n", __func__);
+
+ return component_add(&pdev->dev, &imx_sec_dsim_ops);
+}
+
+static int imx_sec_dsim_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &imx_sec_dsim_ops);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int imx_sec_dsim_suspend(struct device *dev)
+{
+ return imx_sec_dsim_runtime_suspend(dev);
+}
+
+static int imx_sec_dsim_resume(struct device *dev)
+{
+ return imx_sec_dsim_runtime_resume(dev);
+}
+#else
+static int imx_sec_dsim_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int imx_sec_dsim_resume(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static int imx_sec_dsim_runtime_suspend(struct device *dev)
+{
+ if (atomic_inc_return(&dsim_dev->rpm_suspended) > 1)
+ return 0;
+
+ sec_mipi_dsim_suspend(dev);
+
+ release_bus_freq(BUS_FREQ_HIGH);
+
+ return 0;
+}
+
+static int imx_sec_dsim_runtime_resume(struct device *dev)
+{
+ if (unlikely(!atomic_read(&dsim_dev->rpm_suspended))) {
+ dev_warn(dsim_dev->dev,
+ "Unbalanced %s!\n", __func__);
+ return 0;
+ }
+
+ if (!atomic_dec_and_test(&dsim_dev->rpm_suspended))
+ return 0;
+
+ request_bus_freq(BUS_FREQ_HIGH);
+
+ /* Pull dsim out of reset */
+ disp_mix_dsim_soft_reset_release(dsim_dev->gpr, true);
+ disp_mix_dsim_clks_enable(dsim_dev->gpr, true);
+ imx_sec_dsim_lanes_reset(dsim_dev->gpr, false);
+
+ sec_mipi_dsim_resume(dev);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops imx_sec_dsim_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(imx_sec_dsim_suspend,
+ imx_sec_dsim_resume)
+ SET_RUNTIME_PM_OPS(imx_sec_dsim_runtime_suspend,
+ imx_sec_dsim_runtime_resume,
+ NULL)
+};
+
+struct platform_driver imx_sec_dsim_driver = {
+ .probe = imx_sec_dsim_probe,
+ .remove = imx_sec_dsim_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = imx_sec_dsim_dt_ids,
+ .pm = &imx_sec_dsim_pm_ops,
+ },
+};
+
+module_platform_driver(imx_sec_dsim_driver);
+
+MODULE_DESCRIPTION("NXP i.MX MIPI DSI Host Controller driver");
+MODULE_AUTHOR("Fancy Fang <chen.fang@nxp.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_plane.c b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
index c461a232cbf5..c3e6d37864b8 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_plane.c
@@ -173,7 +173,7 @@ int mtk_plane_init(struct drm_device *dev, struct drm_plane *plane,
err = drm_universal_plane_init(dev, plane, possible_crtcs,
&mtk_plane_funcs, formats,
- ARRAY_SIZE(formats), type, NULL);
+ ARRAY_SIZE(formats), NULL, type, NULL);
if (err) {
DRM_ERROR("failed to initialize plane\n");
return err;
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index 6b21cb27e1cc..458b0f1a860e 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1654,7 +1654,7 @@ static struct drm_encoder *mga_connector_best_encoder(struct drm_connector
int enc_id = connector->encoder_ids[0];
/* pick the encoder ids */
if (enc_id)
- return drm_encoder_find(connector->dev, enc_id);
+ return drm_encoder_find(connector->dev, NULL, enc_id);
return NULL;
}
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
index 3903dbcda763..b58212cd16f7 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
@@ -398,7 +398,7 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
ret = drm_universal_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
mdp4_plane->formats, mdp4_plane->nformats,
- type, NULL);
+ NULL, type, NULL);
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
index 83bf997dda03..5363715b4ca5 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
@@ -901,7 +901,7 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
mdp5_plane->formats, mdp5_plane->nformats,
- type, NULL);
+ NULL, type, NULL);
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/mxsfb/Kconfig b/drivers/gpu/drm/mxsfb/Kconfig
new file mode 100644
index 000000000000..e9a8d90e6723
--- /dev/null
+++ b/drivers/gpu/drm/mxsfb/Kconfig
@@ -0,0 +1,19 @@
+config DRM_MXS
+ bool
+ help
+ Choose this option to select drivers for MXS FB devices
+
+config DRM_MXSFB
+ tristate "i.MX23/i.MX28/i.MX6SX MXSFB LCD controller"
+ depends on DRM && OF
+ depends on COMMON_CLK
+ select DRM_MXS
+ select DRM_KMS_HELPER
+ select DRM_KMS_FB_HELPER
+ select DRM_KMS_CMA_HELPER
+ select DRM_PANEL
+ help
+ Choose this option if you have an i.MX23/i.MX28/i.MX6SX MXSFB
+ LCD controller.
+
+ If M is selected the module will be called mxsfb.
diff --git a/drivers/gpu/drm/mxsfb/Makefile b/drivers/gpu/drm/mxsfb/Makefile
new file mode 100644
index 000000000000..857f3a4545ff
--- /dev/null
+++ b/drivers/gpu/drm/mxsfb/Makefile
@@ -0,0 +1,2 @@
+mxsfb-y := mxsfb_drv.o mxsfb_crtc.o mxsfb_out.o
+obj-$(CONFIG_DRM_MXSFB) += mxsfb.o
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_crtc.c b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
new file mode 100644
index 000000000000..15823954d7dd
--- /dev/null
+++ b/drivers/gpu/drm/mxsfb/mxsfb_crtc.c
@@ -0,0 +1,489 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * This code is based on drivers/video/fbdev/mxsfb.c :
+ * Copyright (C) 2010 Juergen Beisert, Pengutronix
+ * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/of_graph.h>
+#include <linux/platform_data/simplefb.h>
+#include <video/videomode.h>
+
+#include "mxsfb_drv.h"
+#include "mxsfb_regs.h"
+
+#define MXS_SET_ADDR 0x4
+#define MXS_CLR_ADDR 0x8
+#define MODULE_CLKGATE BIT(30)
+#define MODULE_SFTRST BIT(31)
+/* 1 second delay should be plenty of time for block reset */
+#define RESET_TIMEOUT 1000000
+
+static u32 set_hsync_pulse_width(struct mxsfb_drm_private *mxsfb, u32 val)
+{
+ return (val & mxsfb->devdata->hs_wdth_mask) <<
+ mxsfb->devdata->hs_wdth_shift;
+}
+
+/* Setup the MXSFB registers for decoding the pixels out of the framebuffer */
+static int mxsfb_set_pixel_fmt(struct mxsfb_drm_private *mxsfb, bool update)
+{
+ struct drm_crtc *crtc = &mxsfb->pipe.crtc;
+ struct drm_device *drm = crtc->dev;
+ const u32 format = crtc->primary->state->fb->pixel_format;
+ u32 ctrl = 0, ctrl1 = 0;
+ bool bgr_format = true;
+ char *format_name;
+
+ if (!update)
+ ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER;
+
+ /*
+ * WARNING: The bus width, CTRL_SET_BUS_WIDTH(), is configured to
+ * match the selected mode here. This differs from the original
+ * MXSFB driver, which had the option to configure the bus width
+ * to arbitrary value. This limitation should not pose an issue.
+ */
+
+ if (!update) {
+ /* CTRL1 contains IRQ config and status bits, preserve those. */
+ ctrl1 = readl(mxsfb->base + LCDC_CTRL1);
+ ctrl1 &= CTRL1_CUR_FRAME_DONE_IRQ_EN | CTRL1_CUR_FRAME_DONE_IRQ;
+ }
+
+ format_name = drm_get_format_name(format);
+ DRM_DEV_DEBUG_DRIVER(drm->dev, "Setting up %s mode\n", format_name);
+ kfree(format_name);
+
+ /* Do some clean-up that we might have from a previous mode */
+ ctrl &= ~CTRL_SHIFT_DIR(1);
+ ctrl &= ~CTRL_SHIFT_NUM(0x3f);
+ if (mxsfb->devdata->ipversion >= 4)
+ writel(CTRL2_ODD_LINE_PATTERN(0x7) |
+ CTRL2_EVEN_LINE_PATTERN(0x7),
+ mxsfb->base + LCDC_V4_CTRL2 + REG_CLR);
+
+ switch (format) {
+ case DRM_FORMAT_BGR565: /* BG16 */
+ if (mxsfb->devdata->ipversion < 4)
+ goto err;
+ writel(CTRL2_ODD_LINE_PATTERN(0x5) |
+ CTRL2_EVEN_LINE_PATTERN(0x5),
+ mxsfb->base + LCDC_V4_CTRL2 + REG_SET);
+ /* Fall through */
+ case DRM_FORMAT_RGB565: /* RG16 */
+ ctrl |= CTRL_SET_WORD_LENGTH(0);
+ ctrl &= ~CTRL_DF16;
+ ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
+ break;
+ case DRM_FORMAT_XBGR1555: /* XB15 */
+ case DRM_FORMAT_ABGR1555: /* AB15 */
+ if (mxsfb->devdata->ipversion < 4)
+ goto err;
+ writel(CTRL2_ODD_LINE_PATTERN(0x5) |
+ CTRL2_EVEN_LINE_PATTERN(0x5),
+ mxsfb->base + LCDC_V4_CTRL2 + REG_SET);
+ /* Fall through */
+ case DRM_FORMAT_XRGB1555: /* XR15 */
+ case DRM_FORMAT_ARGB1555: /* AR15 */
+ ctrl |= CTRL_SET_WORD_LENGTH(0);
+ ctrl |= CTRL_DF16;
+ ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
+ break;
+ case DRM_FORMAT_RGBX8888: /* RX24 */
+ case DRM_FORMAT_RGBA8888: /* RA24 */
+ /* RGBX - > 0RGB */
+ ctrl |= CTRL_SHIFT_DIR(1);
+ ctrl |= CTRL_SHIFT_NUM(8);
+ bgr_format = false;
+ /* Fall through */
+ case DRM_FORMAT_XBGR8888: /* XB24 */
+ case DRM_FORMAT_ABGR8888: /* AB24 */
+ if (bgr_format) {
+ if (mxsfb->devdata->ipversion < 4)
+ goto err;
+ writel(CTRL2_ODD_LINE_PATTERN(0x5) |
+ CTRL2_EVEN_LINE_PATTERN(0x5),
+ mxsfb->base + LCDC_V4_CTRL2 + REG_SET);
+ }
+ /* Fall through */
+ case DRM_FORMAT_XRGB8888: /* XR24 */
+ case DRM_FORMAT_ARGB8888: /* AR24 */
+ ctrl |= CTRL_SET_WORD_LENGTH(3);
+ /* Do not use packed pixels = one pixel per word instead. */
+ ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
+ break;
+ default:
+ goto err;
+ }
+
+ if (update) {
+ writel(ctrl, mxsfb->base + LCDC_CTRL + REG_SET);
+ writel(ctrl1, mxsfb->base + LCDC_CTRL1 + REG_SET);
+ } else {
+ writel(ctrl, mxsfb->base + LCDC_CTRL);
+ writel(ctrl1, mxsfb->base + LCDC_CTRL1);
+ }
+
+ return 0;
+
+err:
+ format_name = drm_get_format_name(format);
+ DRM_DEV_ERROR(drm->dev, "Unhandled pixel format: %s\n", format_name);
+ kfree(format_name);
+
+ return -EINVAL;
+}
+
+static u32 get_bus_format_from_bpp(u32 bpp)
+{
+ switch (bpp) {
+ case 16:
+ return MEDIA_BUS_FMT_RGB565_1X16;
+ case 18:
+ return MEDIA_BUS_FMT_RGB666_1X18;
+ case 24:
+ return MEDIA_BUS_FMT_RGB888_1X24;
+ default:
+ return MEDIA_BUS_FMT_RGB888_1X24;
+ }
+}
+
+static void mxsfb_set_bus_fmt(struct mxsfb_drm_private *mxsfb)
+{
+ struct drm_crtc *crtc = &mxsfb->pipe.crtc;
+ unsigned int bits_per_pixel = crtc->primary->state->fb->bits_per_pixel;
+ struct drm_device *drm = crtc->dev;
+ u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+ int num_bus_formats = mxsfb->connector->display_info.num_bus_formats;
+ const u32 *bus_formats = mxsfb->connector->display_info.bus_formats;
+ u32 reg = 0;
+ int i = 0;
+
+ /* match the user requested bus_format to one supported by the panel */
+ if (num_bus_formats) {
+ u32 user_bus_format = get_bus_format_from_bpp(bits_per_pixel);
+
+ bus_format = bus_formats[0];
+ for (i = 0; i < num_bus_formats; i++) {
+ if (user_bus_format == bus_formats[i]) {
+ bus_format = user_bus_format;
+ break;
+ }
+ }
+ }
+
+ /*
+ * CRTC will dictate the bus format via private_flags[16:1]
+ * and private_flags[0] will signal a bus format change
+ */
+ crtc->mode.private_flags &= ~0x1FFFF; /* clear bus format */
+ crtc->mode.private_flags |= (bus_format << 1); /* set bus format */
+ crtc->mode.private_flags |= 0x1; /* bus format change indication*/
+
+ DRM_DEV_DEBUG_DRIVER(mxsfb->dev,
+ "Using bus_format: 0x%08X\n", bus_format);
+
+ switch (bus_format) {
+ case MEDIA_BUS_FMT_RGB565_1X16:
+ reg = CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT);
+ break;
+ case MEDIA_BUS_FMT_RGB666_1X18:
+ reg = CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT);
+ break;
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ reg = CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT);
+ break;
+ default:
+ dev_err(drm->dev, "Unknown media bus format %d\n", bus_format);
+ break;
+ }
+ writel(reg, mxsfb->base + LCDC_CTRL + REG_SET);
+}
+
+static void mxsfb_enable_controller(struct mxsfb_drm_private *mxsfb)
+{
+ u32 reg;
+
+ if (mxsfb->clk_disp_axi)
+ clk_prepare_enable(mxsfb->clk_disp_axi);
+ clk_prepare_enable(mxsfb->clk);
+ mxsfb_enable_axi_clk(mxsfb);
+
+ if (mxsfb->devdata->ipversion >= 4)
+ writel(CTRL2_OUTSTANDING_REQS(REQ_16),
+ mxsfb->base + LCDC_V4_CTRL2 + REG_SET);
+
+ /* If it was disabled, re-enable the mode again */
+ writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_SET);
+
+ /* Enable the SYNC signals first, then the DMA engine */
+ reg = readl(mxsfb->base + LCDC_VDCTRL4);
+ reg |= VDCTRL4_SYNC_SIGNALS_ON;
+ writel(reg, mxsfb->base + LCDC_VDCTRL4);
+
+ writel(CTRL_MASTER, mxsfb->base + LCDC_CTRL + REG_SET);
+ writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_SET);
+
+ writel(CTRL1_RECOVERY_ON_UNDERFLOW, mxsfb->base + LCDC_CTRL1 + REG_SET);
+}
+
+static void mxsfb_disable_controller(struct mxsfb_drm_private *mxsfb)
+{
+ u32 reg;
+
+ if (mxsfb->devdata->ipversion >= 4)
+ writel(CTRL2_OUTSTANDING_REQS(0x7),
+ mxsfb->base + LCDC_V4_CTRL2 + REG_CLR);
+
+ writel(CTRL_RUN, mxsfb->base + LCDC_CTRL + REG_CLR);
+
+ /*
+ * Even if we disable the controller here, it will still continue
+ * until its FIFOs are running out of data
+ */
+ writel(CTRL_DOTCLK_MODE, mxsfb->base + LCDC_CTRL + REG_CLR);
+
+ readl_poll_timeout(mxsfb->base + LCDC_CTRL, reg, !(reg & CTRL_RUN),
+ 0, 1000);
+
+ writel(CTRL_MASTER, mxsfb->base + LCDC_CTRL + REG_CLR);
+
+ reg = readl(mxsfb->base + LCDC_VDCTRL4);
+ reg &= ~VDCTRL4_SYNC_SIGNALS_ON;
+ writel(reg, mxsfb->base + LCDC_VDCTRL4);
+
+ mxsfb_disable_axi_clk(mxsfb);
+
+ if (mxsfb->clk_disp_axi)
+ clk_disable_unprepare(mxsfb->clk_disp_axi);
+ clk_disable_unprepare(mxsfb->clk);
+}
+
+/*
+ * Clear the bit and poll it cleared. This is usually called with
+ * a reset address and mask being either SFTRST(bit 31) or CLKGATE
+ * (bit 30).
+ */
+static int clear_poll_bit(void __iomem *addr, u32 mask)
+{
+ u32 reg;
+
+ writel(mask, addr + MXS_CLR_ADDR);
+ return readl_poll_timeout(addr, reg, !(reg & mask), 0, RESET_TIMEOUT);
+}
+
+static int mxsfb_reset_block(void __iomem *reset_addr)
+{
+ int ret;
+
+ ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
+ if (ret)
+ return ret;
+
+ writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR);
+
+ ret = clear_poll_bit(reset_addr, MODULE_SFTRST);
+ if (ret)
+ return ret;
+
+ return clear_poll_bit(reset_addr, MODULE_CLKGATE);
+}
+
+static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
+{
+ struct drm_display_mode *m = &mxsfb->pipe.crtc.state->adjusted_mode;
+ const u32 bus_flags = mxsfb->connector->display_info.bus_flags;
+ u32 vdctrl0, vsync_pulse_len, hsync_pulse_len;
+ int err;
+
+ /*
+ * It seems, you can't re-program the controller if it is still
+ * running. This may lead to shifted pictures (FIFO issue?), so
+ * first stop the controller and drain its FIFOs.
+ */
+ mxsfb_enable_axi_clk(mxsfb);
+
+ /* Mandatory eLCDIF reset as per the Reference Manual */
+ err = mxsfb_reset_block(mxsfb->base);
+ if (err)
+ return;
+
+ /* Clear the FIFOs */
+ writel(CTRL1_FIFO_CLEAR, mxsfb->base + LCDC_CTRL1 + REG_SET);
+
+ err = mxsfb_set_pixel_fmt(mxsfb, false);
+ if (err)
+ return;
+
+ clk_set_rate(mxsfb->clk, m->crtc_clock * 1000);
+
+ DRM_DEV_DEBUG_DRIVER(mxsfb->dev,
+ "Connector bus_flags: 0x%08X\n", bus_flags);
+ DRM_DEV_DEBUG_DRIVER(mxsfb->dev,
+ "Mode flags: 0x%08X\n", m->flags);
+
+ writel(TRANSFER_COUNT_SET_VCOUNT(m->crtc_vdisplay) |
+ TRANSFER_COUNT_SET_HCOUNT(m->crtc_hdisplay),
+ mxsfb->base + mxsfb->devdata->transfer_count);
+
+ vsync_pulse_len = m->crtc_vsync_end - m->crtc_vsync_start;
+
+ vdctrl0 = VDCTRL0_ENABLE_PRESENT | /* Always in DOTCLOCK mode */
+ VDCTRL0_VSYNC_PERIOD_UNIT |
+ VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
+ VDCTRL0_SET_VSYNC_PULSE_WIDTH(vsync_pulse_len);
+ if (m->flags & DRM_MODE_FLAG_PHSYNC)
+ vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
+ if (m->flags & DRM_MODE_FLAG_PVSYNC)
+ vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
+ /* Make sure Data Enable is high active by default */
+ if (!(bus_flags & DRM_BUS_FLAG_DE_LOW))
+ vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
+ /*
+ * DRM_BUS_FLAG_PIXDATA_ defines are controller centric,
+ * controllers VDCTRL0_DOTCLK is display centric.
+ * Drive on positive edge -> display samples on falling edge
+ * DRM_BUS_FLAG_PIXDATA_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING
+ */
+ if (bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
+ vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
+
+ writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0);
+
+ mxsfb_set_bus_fmt(mxsfb);
+
+ /* Frame length in lines. */
+ writel(m->crtc_vtotal, mxsfb->base + LCDC_VDCTRL1);
+
+ /* Line length in units of clocks or pixels. */
+ hsync_pulse_len = m->crtc_hsync_end - m->crtc_hsync_start;
+ writel(set_hsync_pulse_width(mxsfb, hsync_pulse_len) |
+ VDCTRL2_SET_HSYNC_PERIOD(m->crtc_htotal),
+ mxsfb->base + LCDC_VDCTRL2);
+
+ writel(SET_HOR_WAIT_CNT(m->crtc_htotal - m->crtc_hsync_start) |
+ SET_VERT_WAIT_CNT(m->crtc_vtotal - m->crtc_vsync_start),
+ mxsfb->base + LCDC_VDCTRL3);
+
+ writel(SET_DOTCLK_H_VALID_DATA_CNT(m->hdisplay),
+ mxsfb->base + LCDC_VDCTRL4);
+
+ if (mxsfb->gem != NULL) {
+ writel(mxsfb->gem->paddr,
+ mxsfb->base + mxsfb->devdata->next_buf);
+ mxsfb->gem = NULL;
+ }
+
+ mxsfb_disable_axi_clk(mxsfb);
+}
+
+void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb)
+{
+ if (mxsfb->enabled)
+ return;
+
+ if (mxsfb->devdata->flags & MXSFB_FLAG_BUSFREQ)
+ request_bus_freq(BUS_FREQ_HIGH);
+
+ writel(0, mxsfb->base + LCDC_CTRL);
+ mxsfb_crtc_mode_set_nofb(mxsfb);
+ mxsfb_enable_controller(mxsfb);
+
+ mxsfb->enabled = true;
+}
+
+void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb)
+{
+ if (!mxsfb->enabled)
+ return;
+
+ mxsfb_disable_controller(mxsfb);
+
+ if (mxsfb->devdata->flags & MXSFB_FLAG_BUSFREQ)
+ release_bus_freq(BUS_FREQ_HIGH);
+
+ mxsfb->enabled = false;
+}
+
+void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
+ struct drm_plane_state *old_state)
+{
+ struct drm_simple_display_pipe *pipe = &mxsfb->pipe;
+ struct drm_crtc *crtc = &pipe->crtc;
+ struct drm_device *drm = crtc->dev;
+ struct drm_framebuffer *fb = pipe->plane.state->fb;
+ struct drm_framebuffer *old_fb = old_state->fb;
+ struct drm_pending_vblank_event *event;
+ struct drm_gem_cma_object *gem;
+
+ if (!crtc)
+ return;
+
+ spin_lock_irq(&crtc->dev->event_lock);
+ event = crtc->state->event;
+ if (event) {
+ crtc->state->event = NULL;
+
+ if (drm_crtc_vblank_get(crtc) == 0) {
+ drm_crtc_arm_vblank_event(crtc, event);
+ } else {
+ drm_crtc_send_vblank_event(crtc, event);
+ }
+ }
+ spin_unlock_irq(&crtc->dev->event_lock);
+
+ if (!fb)
+ return;
+
+ gem = drm_fb_cma_get_gem_obj(fb, 0);
+
+ if (!mxsfb->enabled) {
+ mxsfb->gem = gem;
+ return;
+ }
+
+ /*
+ * TODO: Currently, we only support pixel format change, but we need
+ * also to care about size changes too
+ */
+ if (old_fb->pixel_format != fb->pixel_format) {
+ char *old_fmt_name = drm_get_format_name(old_fb->pixel_format);
+ char *new_fmt_name = drm_get_format_name(fb->pixel_format);
+ DRM_DEV_DEBUG_DRIVER(drm->dev,
+ "Switching pixel format: %s -> %s\n",
+ old_fmt_name,
+ new_fmt_name);
+ kfree(old_fmt_name);
+ kfree(new_fmt_name);
+ mxsfb_set_pixel_fmt(mxsfb, true);
+ }
+
+ mxsfb_enable_axi_clk(mxsfb);
+ writel(gem->paddr, mxsfb->base + mxsfb->devdata->next_buf);
+ mxsfb_disable_axi_clk(mxsfb);
+}
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
new file mode 100644
index 000000000000..96536bf0ef2d
--- /dev/null
+++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c
@@ -0,0 +1,644 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * This code is based on drivers/video/fbdev/mxsfb.c :
+ * Copyright (C) 2010 Juergen Beisert, Pengutronix
+ * Copyright (C) 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/list.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/pm_runtime.h>
+#include <linux/reservation.h>
+#include <linux/version.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#include "mxsfb_drv.h"
+#include "mxsfb_regs.h"
+
+/* The eLCDIF max possible CRTCs */
+#define MAX_CRTCS 1
+
+enum mxsfb_devtype {
+ MXSFB_V3,
+ MXSFB_V4,
+};
+
+/*
+ * When adding new formats, make sure to update the num_formats from
+ * mxsfb_devdata below.
+ */
+static const uint32_t mxsfb_formats[] = {
+ /* MXSFB_V3 */
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_RGB565,
+ /* MXSFB_V4 */
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_RGBX8888,
+ DRM_FORMAT_RGBA8888,
+ DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_XRGB1555,
+ DRM_FORMAT_ABGR1555,
+ DRM_FORMAT_XBGR1555,
+ DRM_FORMAT_BGR565
+};
+
+static const struct mxsfb_devdata mxsfb_devdata[] = {
+ [MXSFB_V3] = {
+ .transfer_count = LCDC_V3_TRANSFER_COUNT,
+ .cur_buf = LCDC_V3_CUR_BUF,
+ .next_buf = LCDC_V3_NEXT_BUF,
+ .debug0 = LCDC_V3_DEBUG0,
+ .hs_wdth_mask = 0xff,
+ .hs_wdth_shift = 24,
+ .ipversion = 3,
+ .flags = MXSFB_FLAG_NULL,
+ .num_formats = 3,
+ },
+ [MXSFB_V4] = {
+ .transfer_count = LCDC_V4_TRANSFER_COUNT,
+ .cur_buf = LCDC_V4_CUR_BUF,
+ .next_buf = LCDC_V4_NEXT_BUF,
+ .debug0 = LCDC_V4_DEBUG0,
+ .hs_wdth_mask = 0x3fff,
+ .hs_wdth_shift = 18,
+ .ipversion = 4,
+ .flags = MXSFB_FLAG_BUSFREQ,
+ .num_formats = ARRAY_SIZE(mxsfb_formats),
+ },
+};
+
+static struct mxsfb_drm_private *
+drm_pipe_to_mxsfb_drm_private(struct drm_simple_display_pipe *pipe)
+{
+ return container_of(pipe, struct mxsfb_drm_private, pipe);
+}
+
+void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb)
+{
+ if (mxsfb->clk_axi)
+ clk_prepare_enable(mxsfb->clk_axi);
+}
+
+void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb)
+{
+ if (mxsfb->clk_axi)
+ clk_disable_unprepare(mxsfb->clk_axi);
+}
+
+/**
+ * mxsfb_atomic_helper_check - validate state object
+ * @dev: DRM device
+ * @state: the driver state object
+ *
+ * On top of the drm imlementation drm_atomic_helper_check,
+ * check if the bpp is changed, if so, signal mode_changed,
+ * this will trigger disable/enable
+ *
+ * RETURNS:
+ * Zero for success or -errno
+ */
+static int mxsfb_atomic_helper_check(struct drm_device *dev,
+ struct drm_atomic_state *state)
+{
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+ int i, ret;
+
+ ret = drm_atomic_helper_check(dev, state);
+ if (ret)
+ return ret;
+
+ for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ struct drm_plane_state *primary_state;
+ int old_bpp = 0;
+ int new_bpp = 0;
+
+ if (!crtc->primary || !crtc->primary->old_fb)
+ continue;
+ primary_state =
+ drm_atomic_get_plane_state(state, crtc->primary);
+ if (!primary_state || !primary_state->fb)
+ continue;
+ old_bpp = crtc->primary->old_fb->bits_per_pixel;
+ new_bpp = primary_state->fb->bits_per_pixel;
+ if (old_bpp != new_bpp) {
+ crtc_state->mode_changed = true;
+ DRM_DEBUG_ATOMIC(
+ "[CRTC:%d:%s] mode changed, bpp %d->%d\n",
+ crtc->base.id, crtc->name, old_bpp, new_bpp);
+ }
+ }
+ return ret;
+}
+
+static const struct drm_mode_config_funcs mxsfb_mode_config_funcs = {
+ .fb_create = drm_fb_cma_create,
+ .atomic_check = mxsfb_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+};
+
+static void mxsfb_pipe_enable(struct drm_simple_display_pipe *pipe,
+ struct drm_crtc_state *crtc_state)
+{
+ struct drm_device *drm = pipe->encoder.dev;
+ struct drm_connector *connector;
+ struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
+
+ if (!mxsfb->connector) {
+ list_for_each_entry(connector,
+ &drm->mode_config.connector_list,
+ head)
+ if (connector->encoder == &(mxsfb->pipe.encoder)) {
+ mxsfb->connector = connector;
+ break;
+ }
+ }
+
+ if (!mxsfb->connector) {
+ dev_warn(drm->dev, "No connector attached, using default\n");
+ mxsfb->connector = &mxsfb->panel_connector;
+ }
+
+ drm_crtc_vblank_on(&mxsfb->pipe.crtc);
+
+ mxsfb_crtc_enable(mxsfb);
+ pm_runtime_get_sync(mxsfb->dev);
+}
+
+static void mxsfb_pipe_disable(struct drm_simple_display_pipe *pipe)
+{
+ struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
+ struct drm_crtc *crtc = &pipe->crtc;
+
+ spin_lock_irq(&crtc->dev->event_lock);
+ if (crtc->state->event) {
+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
+ crtc->state->event = NULL;
+ }
+ spin_unlock_irq(&crtc->dev->event_lock);
+
+ mxsfb_crtc_disable(mxsfb);
+ pm_runtime_put_sync(mxsfb->dev);
+
+ if (mxsfb->connector != &mxsfb->panel_connector)
+ mxsfb->connector = NULL;
+}
+
+static void mxsfb_pipe_update(struct drm_simple_display_pipe *pipe,
+ struct drm_plane_state *plane_state)
+{
+ struct mxsfb_drm_private *mxsfb = drm_pipe_to_mxsfb_drm_private(pipe);
+
+ mxsfb_plane_atomic_update(mxsfb, plane_state);
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
+static int mxsfb_pipe_prepare_fb(struct drm_simple_display_pipe *pipe,
+ struct drm_plane_state *plane_state)
+{
+ return drm_fb_cma_prepare_fb(&pipe->plane, plane_state);
+}
+#endif
+
+struct drm_simple_display_pipe_funcs mxsfb_funcs = {
+ .enable = mxsfb_pipe_enable,
+ .disable = mxsfb_pipe_disable,
+ .update = mxsfb_pipe_update,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
+ .prepare_fb = mxsfb_pipe_prepare_fb,
+#endif
+};
+
+static int mxsfb_load(struct drm_device *drm, unsigned long flags)
+{
+ struct platform_device *pdev = to_platform_device(drm->dev);
+ struct mxsfb_drm_private *mxsfb;
+ struct resource *res;
+ u32 max_res[2] = {0, 0};
+ int ret;
+
+ mxsfb = devm_kzalloc(&pdev->dev, sizeof(*mxsfb), GFP_KERNEL);
+ if (!mxsfb)
+ return -ENOMEM;
+
+ drm->dev_private = mxsfb;
+ mxsfb->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];
+ mxsfb->dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, drm);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mxsfb->base = devm_ioremap_resource(drm->dev, res);
+ if (IS_ERR(mxsfb->base))
+ return PTR_ERR(mxsfb->base);
+
+ mxsfb->clk = devm_clk_get(drm->dev, NULL);
+ if (IS_ERR(mxsfb->clk))
+ return PTR_ERR(mxsfb->clk);
+
+ mxsfb->clk_axi = devm_clk_get(drm->dev, "axi");
+ if (IS_ERR(mxsfb->clk_axi))
+ mxsfb->clk_axi = NULL;
+
+ mxsfb->clk_disp_axi = devm_clk_get(drm->dev, "disp_axi");
+ if (IS_ERR(mxsfb->clk_disp_axi))
+ mxsfb->clk_disp_axi = NULL;
+
+ ret = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ pm_runtime_enable(drm->dev);
+
+ ret = drm_vblank_init(drm, MAX_CRTCS);
+ if (ret < 0) {
+ dev_err(drm->dev, "Failed to initialise vblank\n");
+ goto err_vblank;
+ }
+
+ /* Modeset init */
+ drm_mode_config_init(drm);
+
+ ret = mxsfb_create_output(drm);
+ if (ret < 0) {
+ dev_err(drm->dev, "Failed to create outputs\n");
+ goto err_vblank;
+ }
+
+ ret = drm_simple_display_pipe_init(drm, &mxsfb->pipe, &mxsfb_funcs,
+ mxsfb_formats, mxsfb->devdata->num_formats, NULL,
+ mxsfb->connector);
+ if (ret < 0) {
+ dev_err(drm->dev, "Cannot setup simple display pipe\n");
+ goto err_vblank;
+ }
+
+ drm_crtc_vblank_off(&mxsfb->pipe.crtc);
+
+ /*
+ * Attach panel only if there is one.
+ * If there is no panel attach, it must be a bridge. In this case, we
+ * need a reference to its connector for a proper initialization.
+ * We will do this check in pipe->enable(), since the connector won't
+ * be attached to an encoder until then.
+ */
+
+ if (mxsfb->panel) {
+ ret = drm_panel_attach(mxsfb->panel, mxsfb->connector);
+ if (ret) {
+ dev_err(drm->dev, "Cannot connect panel\n");
+ goto err_vblank;
+ }
+ } else if (mxsfb->bridge) {
+ ret = drm_simple_display_pipe_attach_bridge(&mxsfb->pipe,
+ mxsfb->bridge);
+ if (ret) {
+ dev_err(drm->dev, "Cannot connect bridge\n");
+ goto err_vblank;
+ }
+ }
+
+ of_property_read_u32_array(drm->dev->of_node, "max-res",
+ &max_res[0], 2);
+ if (!max_res[0])
+ max_res[0] = MXSFB_MAX_XRES;
+ if (!max_res[1])
+ max_res[1] = MXSFB_MAX_YRES;
+
+ drm->mode_config.min_width = MXSFB_MIN_XRES;
+ drm->mode_config.min_height = MXSFB_MIN_YRES;
+ drm->mode_config.max_width = max_res[0];
+ drm->mode_config.max_height = max_res[1];
+ drm->mode_config.funcs = &mxsfb_mode_config_funcs;
+
+ drm_mode_config_reset(drm);
+
+ pm_runtime_get_sync(drm->dev);
+ ret = drm_irq_install(drm, platform_get_irq(pdev, 0));
+ pm_runtime_put_sync(drm->dev);
+
+ if (ret < 0) {
+ dev_err(drm->dev, "Failed to install IRQ handler\n");
+ goto err_irq;
+ }
+
+ drm_kms_helper_poll_init(drm);
+
+ mxsfb->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_crtc,
+ drm->mode_config.num_connector);
+ if (IS_ERR(mxsfb->fbdev)) {
+ mxsfb->fbdev = NULL;
+ dev_err(drm->dev, "Failed to init FB CMA area\n");
+ goto err_cma;
+ }
+
+
+ drm_helper_hpd_irq_event(drm);
+
+ return 0;
+
+err_cma:
+ drm_irq_uninstall(drm);
+err_irq:
+ drm_panel_detach(mxsfb->panel);
+err_vblank:
+ pm_runtime_disable(drm->dev);
+
+ return ret;
+}
+
+static void mxsfb_unload(struct drm_device *drm)
+{
+ struct mxsfb_drm_private *mxsfb = drm->dev_private;
+
+ if (mxsfb->fbdev)
+ drm_fbdev_cma_fini(mxsfb->fbdev);
+
+ drm_kms_helper_poll_fini(drm);
+ drm_mode_config_cleanup(drm);
+ drm_vblank_cleanup(drm);
+
+ pm_runtime_get_sync(drm->dev);
+ drm_irq_uninstall(drm);
+ pm_runtime_put_sync(drm->dev);
+
+ drm->dev_private = NULL;
+
+ pm_runtime_disable(drm->dev);
+}
+
+static void mxsfb_lastclose(struct drm_device *drm)
+{
+ struct mxsfb_drm_private *mxsfb = drm->dev_private;
+
+ drm_fbdev_cma_restore_mode(mxsfb->fbdev);
+}
+
+static int mxsfb_enable_vblank(struct drm_device *drm, unsigned int crtc)
+{
+ struct mxsfb_drm_private *mxsfb = drm->dev_private;
+
+ /* Clear and enable VBLANK IRQ */
+ mxsfb_enable_axi_clk(mxsfb);
+ writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
+ writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET);
+ mxsfb_disable_axi_clk(mxsfb);
+
+ return 0;
+}
+
+static void mxsfb_disable_vblank(struct drm_device *drm, unsigned int crtc)
+{
+ struct mxsfb_drm_private *mxsfb = drm->dev_private;
+
+ /* Disable and clear VBLANK IRQ */
+ mxsfb_enable_axi_clk(mxsfb);
+ writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR);
+ writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
+ mxsfb_disable_axi_clk(mxsfb);
+}
+
+static void mxsfb_irq_preinstall(struct drm_device *drm)
+{
+ mxsfb_disable_vblank(drm, 0);
+}
+
+static irqreturn_t mxsfb_irq_handler(int irq, void *data)
+{
+ struct drm_device *drm = data;
+ struct mxsfb_drm_private *mxsfb = drm->dev_private;
+ u32 reg;
+
+ mxsfb_enable_axi_clk(mxsfb);
+
+ reg = readl(mxsfb->base + LCDC_CTRL1);
+
+ if (reg & CTRL1_CUR_FRAME_DONE_IRQ)
+ drm_crtc_handle_vblank(&mxsfb->pipe.crtc);
+
+ writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
+
+ mxsfb_disable_axi_clk(mxsfb);
+
+ return IRQ_HANDLED;
+}
+
+static const struct file_operations fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
+ .poll = drm_poll,
+ .read = drm_read,
+ .llseek = noop_llseek,
+ .mmap = drm_gem_cma_mmap,
+};
+
+static struct drm_driver mxsfb_driver = {
+ .driver_features = DRIVER_GEM | DRIVER_MODESET |
+ DRIVER_PRIME | DRIVER_ATOMIC |
+ DRIVER_HAVE_IRQ,
+ .lastclose = mxsfb_lastclose,
+ .irq_handler = mxsfb_irq_handler,
+ .irq_preinstall = mxsfb_irq_preinstall,
+ .irq_uninstall = mxsfb_irq_preinstall,
+ .get_vblank_counter = drm_vblank_no_hw_counter,
+ .enable_vblank = mxsfb_enable_vblank,
+ .disable_vblank = mxsfb_disable_vblank,
+ .gem_free_object = drm_gem_cma_free_object,
+ .gem_vm_ops = &drm_gem_cma_vm_ops,
+ .dumb_create = drm_gem_cma_dumb_create,
+ .dumb_map_offset = drm_gem_cma_dumb_map_offset,
+ .dumb_destroy = drm_gem_dumb_destroy,
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = drm_gem_prime_export,
+ .gem_prime_import = drm_gem_prime_import,
+ .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+ .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+ .gem_prime_vmap = drm_gem_cma_prime_vmap,
+ .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
+ .gem_prime_mmap = drm_gem_cma_prime_mmap,
+ .fops = &fops,
+ .name = "mxsfb-drm",
+ .desc = "MXSFB Controller DRM",
+ .date = "20160824",
+ .major = 1,
+ .minor = 0,
+};
+
+static const struct platform_device_id mxsfb_devtype[] = {
+ { .name = "imx23-fb", .driver_data = MXSFB_V3, },
+ { .name = "imx28-fb", .driver_data = MXSFB_V4, },
+ { .name = "imx6sx-fb", .driver_data = MXSFB_V4, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, mxsfb_devtype);
+
+static const struct of_device_id mxsfb_dt_ids[] = {
+ { .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devtype[0], },
+ { .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devtype[1], },
+ { .compatible = "fsl,imx6sx-lcdif", .data = &mxsfb_devtype[2], },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxsfb_dt_ids);
+
+static int mxsfb_probe(struct platform_device *pdev)
+{
+ struct drm_device *drm;
+ const struct of_device_id *of_id =
+ of_match_device(mxsfb_dt_ids, &pdev->dev);
+ int ret;
+
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ if (of_id)
+ pdev->id_entry = of_id->data;
+
+ drm = drm_dev_alloc(&mxsfb_driver, &pdev->dev);
+ if (!drm)
+ return -ENOMEM;
+
+ ret = mxsfb_load(drm, 0);
+ if (ret)
+ goto err_free;
+
+ ret = drm_dev_register(drm, 0);
+ if (ret)
+ goto err_unload;
+
+ return 0;
+
+err_unload:
+ mxsfb_unload(drm);
+err_free:
+ drm_dev_unref(drm);
+
+ return ret;
+}
+
+static int mxsfb_remove(struct platform_device *pdev)
+{
+ struct drm_device *drm = platform_get_drvdata(pdev);
+
+ drm_dev_unregister(drm);
+ mxsfb_unload(drm);
+ drm_dev_unref(drm);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mxsfb_runtime_suspend(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct mxsfb_drm_private *mxsfb = drm->dev_private;
+
+ if (!drm->registered)
+ return 0;
+
+ if (mxsfb->enabled) {
+ mxsfb_crtc_disable(mxsfb);
+ mxsfb->suspended = true;
+ }
+
+ return 0;
+}
+
+static int mxsfb_runtime_resume(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct mxsfb_drm_private *mxsfb = drm->dev_private;
+
+ if (!drm->registered || !mxsfb->suspended)
+ return 0;
+
+ mxsfb_crtc_enable(mxsfb);
+ mxsfb->suspended = false;
+
+ return 0;
+}
+
+static int mxsfb_suspend(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct mxsfb_drm_private *mxsfb = drm->dev_private;
+
+ if (mxsfb->enabled) {
+ mxsfb_crtc_disable(mxsfb);
+ mxsfb->suspended = true;
+ }
+
+ return 0;
+}
+
+static int mxsfb_resume(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct mxsfb_drm_private *mxsfb = drm->dev_private;
+
+ if (!mxsfb->suspended)
+ return 0;
+
+ mxsfb_crtc_enable(mxsfb);
+ mxsfb->suspended = false;
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops mxsfb_pm_ops = {
+ SET_RUNTIME_PM_OPS(mxsfb_runtime_suspend, mxsfb_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(mxsfb_suspend, mxsfb_resume)
+};
+
+static struct platform_driver mxsfb_platform_driver = {
+ .probe = mxsfb_probe,
+ .remove = mxsfb_remove,
+ .id_table = mxsfb_devtype,
+ .driver = {
+ .name = "mxsfb_drm",
+ .of_match_table = mxsfb_dt_ids,
+ .pm = &mxsfb_pm_ops,
+ },
+};
+
+module_platform_driver(mxsfb_platform_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_DESCRIPTION("Freescale MXS DRM/KMS driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.h b/drivers/gpu/drm/mxsfb/mxsfb_drv.h
new file mode 100644
index 000000000000..b4c98d44c5d0
--- /dev/null
+++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * i.MX23/i.MX28/i.MX6SX MXSFB LCD controller driver.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MXSFB_DRV_H__
+#define __MXSFB_DRV_H__
+
+struct mxsfb_devdata {
+ unsigned int transfer_count;
+ unsigned int cur_buf;
+ unsigned int next_buf;
+ unsigned int debug0;
+ unsigned int hs_wdth_mask;
+ unsigned int hs_wdth_shift;
+ unsigned int ipversion;
+ unsigned int flags;
+ unsigned int num_formats;
+};
+
+struct mxsfb_drm_private {
+ struct device *dev;
+ const struct mxsfb_devdata *devdata;
+
+ void __iomem *base; /* registers */
+ struct clk *clk;
+ struct clk *clk_axi;
+ struct clk *clk_disp_axi;
+
+ struct drm_simple_display_pipe pipe;
+ struct drm_connector panel_connector;
+ struct drm_connector *connector;
+ struct drm_panel *panel;
+ struct drm_bridge *bridge;
+ struct drm_fbdev_cma *fbdev;
+
+ struct drm_gem_cma_object *gem;
+ bool enabled;
+ bool suspended;
+};
+
+int mxsfb_setup_crtc(struct drm_device *dev);
+int mxsfb_create_output(struct drm_device *dev);
+
+void mxsfb_enable_axi_clk(struct mxsfb_drm_private *mxsfb);
+void mxsfb_disable_axi_clk(struct mxsfb_drm_private *mxsfb);
+
+void mxsfb_crtc_enable(struct mxsfb_drm_private *mxsfb);
+void mxsfb_crtc_disable(struct mxsfb_drm_private *mxsfb);
+void mxsfb_plane_atomic_update(struct mxsfb_drm_private *mxsfb,
+ struct drm_plane_state *old_state);
+
+#endif /* __MXSFB_DRV_H__ */
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_out.c b/drivers/gpu/drm/mxsfb/mxsfb_out.c
new file mode 100644
index 000000000000..5587341862ab
--- /dev/null
+++ b/drivers/gpu/drm/mxsfb/mxsfb_out.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of_graph.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+#include <drm/drmP.h>
+
+#include "mxsfb_drv.h"
+
+static struct mxsfb_drm_private *
+drm_connector_to_mxsfb_drm_private(struct drm_connector *connector)
+{
+ return container_of(connector, struct mxsfb_drm_private,
+ panel_connector);
+}
+
+static int mxsfb_panel_get_modes(struct drm_connector *connector)
+{
+ struct mxsfb_drm_private *mxsfb =
+ drm_connector_to_mxsfb_drm_private(connector);
+
+ if (mxsfb->panel)
+ return mxsfb->panel->funcs->get_modes(mxsfb->panel);
+
+ return 0;
+}
+
+static const struct
+drm_connector_helper_funcs mxsfb_panel_connector_helper_funcs = {
+ .get_modes = mxsfb_panel_get_modes,
+};
+
+static enum drm_connector_status
+mxsfb_panel_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct mxsfb_drm_private *mxsfb =
+ drm_connector_to_mxsfb_drm_private(connector);
+
+ if (mxsfb->panel)
+ return connector_status_connected;
+
+ return connector_status_disconnected;
+}
+
+static void mxsfb_panel_connector_destroy(struct drm_connector *connector)
+{
+ struct mxsfb_drm_private *mxsfb =
+ drm_connector_to_mxsfb_drm_private(connector);
+
+ if (mxsfb->panel)
+ drm_panel_detach(mxsfb->panel);
+
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs mxsfb_panel_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .detect = mxsfb_panel_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = mxsfb_panel_connector_destroy,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int mxsfb_attach_endpoint(struct drm_device *drm,
+ const struct of_endpoint *ep)
+{
+ struct mxsfb_drm_private *mxsfb = drm->dev_private;
+ struct device_node *np;
+ int ret = 0;
+
+ np = of_graph_get_remote_port_parent(ep->local_node);
+ mxsfb->panel = of_drm_find_panel(np);
+ if (!mxsfb->panel)
+ mxsfb->bridge = of_drm_find_bridge(np);
+ of_node_put(np);
+
+ if (!mxsfb->panel && !mxsfb->bridge)
+ return -EPROBE_DEFER;
+
+ if (mxsfb->panel) {
+ mxsfb->connector = &mxsfb->panel_connector;
+ mxsfb->connector->dpms = DRM_MODE_DPMS_OFF;
+ mxsfb->connector->polled = 0;
+ drm_connector_helper_add(mxsfb->connector,
+ &mxsfb_panel_connector_helper_funcs);
+ ret = drm_connector_init(drm, mxsfb->connector,
+ &mxsfb_panel_connector_funcs,
+ DRM_MODE_CONNECTOR_Unknown);
+ }
+
+ return ret;
+}
+
+int mxsfb_create_output(struct drm_device *drm)
+{
+ struct device_node *ep_np = NULL;
+ struct of_endpoint ep;
+ int ret;
+
+ for_each_endpoint_of_node(drm->dev->of_node, ep_np) {
+ ret = of_graph_parse_endpoint(ep_np, &ep);
+ if (!ret)
+ ret = mxsfb_attach_endpoint(drm, &ep);
+
+ if (ret) {
+ of_node_put(ep_np);
+ return ret;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/mxsfb/mxsfb_regs.h b/drivers/gpu/drm/mxsfb/mxsfb_regs.h
new file mode 100644
index 000000000000..b8ceeb3b1f2c
--- /dev/null
+++ b/drivers/gpu/drm/mxsfb/mxsfb_regs.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2010 Juergen Beisert, Pengutronix
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * i.MX23/i.MX28/i.MX6SX MXSFB LCD controller driver.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MXSFB_REGS_H__
+#define __MXSFB_REGS_H__
+
+#define REG_SET 4
+#define REG_CLR 8
+
+#define LCDC_CTRL 0x00
+#define LCDC_CTRL1 0x10
+#define LCDC_V4_CTRL2 0x20
+#define LCDC_V3_TRANSFER_COUNT 0x20
+#define LCDC_V4_TRANSFER_COUNT 0x30
+#define LCDC_V4_CUR_BUF 0x40
+#define LCDC_V4_NEXT_BUF 0x50
+#define LCDC_V3_CUR_BUF 0x30
+#define LCDC_V3_NEXT_BUF 0x40
+#define LCDC_TIMING 0x60
+#define LCDC_VDCTRL0 0x70
+#define LCDC_VDCTRL1 0x80
+#define LCDC_VDCTRL2 0x90
+#define LCDC_VDCTRL3 0xa0
+#define LCDC_VDCTRL4 0xb0
+#define LCDC_DVICTRL0 0xc0
+#define LCDC_DVICTRL1 0xd0
+#define LCDC_DVICTRL2 0xe0
+#define LCDC_DVICTRL3 0xf0
+#define LCDC_DVICTRL4 0x100
+#define LCDC_V4_DATA 0x180
+#define LCDC_V3_DATA 0x1b0
+#define LCDC_V4_DEBUG0 0x1d0
+#define LCDC_V3_DEBUG0 0x1f0
+#define LCDC_AS_CTRL 0x210
+#define LCDC_AS_BUF 0x220
+#define LCDC_AS_NEXT_BUF 0x230
+
+/* reg bit manipulation */
+#define REG_MASK(e, s) (((1 << ((e) - (s) + 1)) - 1) << (s))
+#define REG_PUT(x, e, s) (((x) << (s)) & REG_MASK(e, s))
+#define REG_GET(x, e, s) (((x) & REG_MASK(e, s)) >> (s))
+
+#define SWIZZLE_LE 0 /* Little-Endian or No swap */
+#define SWIZZLE_BE 1 /* Big-Endian or swap all */
+#define SWIZZLE_HWD 2 /* Swap half-words */
+#define SWIZZLE_HWD_BYTE 3 /* Swap bytes within each half-word */
+
+#define CTRL_SFTRST BIT(31)
+#define CTRL_CLKGATE BIT(30)
+#define CTRL_SHIFT_DIR(x) REG_PUT((x), 26, 26)
+#define CTRL_SHIFT_NUM(x) REG_PUT((x), 25, 21)
+#define CTRL_BYPASS_COUNT BIT(19)
+#define CTRL_VSYNC_MODE BIT(18)
+#define CTRL_DOTCLK_MODE BIT(17)
+#define CTRL_DATA_SELECT BIT(16)
+#define CTRL_INPUT_SWIZZLE(x) REG_PUT((x), 15, 14)
+#define CTRL_CSC_SWIZZLE(x) REG_PUT((x), 13, 12)
+#define CTRL_SET_BUS_WIDTH(x) REG_PUT((x), 11, 10)
+#define CTRL_GET_BUS_WIDTH(x) REG_GET((x), 11, 10)
+#define CTRL_BUS_WIDTH_MASK REG_PUT((0x3), 11, 10)
+#define CTRL_SET_WORD_LENGTH(x) REG_PUT((x), 9, 8)
+#define CTRL_GET_WORD_LENGTH(x) REG_GET((x), 9, 8)
+#define CTRL_MASTER BIT(5)
+#define CTRL_DF16 BIT(3)
+#define CTRL_DF18 BIT(2)
+#define CTRL_DF24 BIT(1)
+#define CTRL_RUN BIT(0)
+
+#define CTRL1_RECOVERY_ON_UNDERFLOW BIT(24)
+#define CTRL1_FIFO_CLEAR BIT(21)
+#define CTRL1_SET_BYTE_PACKAGING(x) REG_PUT((x), 19, 16)
+#define CTRL1_GET_BYTE_PACKAGING(x) REG_GET((x), 19, 16)
+#define CTRL1_CUR_FRAME_DONE_IRQ_EN BIT(13)
+#define CTRL1_CUR_FRAME_DONE_IRQ BIT(9)
+
+#define REQ_1 0
+#define REQ_2 1
+#define REQ_4 2
+#define REQ_8 3
+#define REQ_16 4
+
+#define CTRL2_OUTSTANDING_REQS(x) REG_PUT((x), 23, 21)
+#define CTRL2_ODD_LINE_PATTERN(x) REG_PUT((x), 18, 16)
+#define CTRL2_EVEN_LINE_PATTERN(x) REG_PUT((x), 14, 12)
+
+#define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16)
+#define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff)
+#define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff)
+#define TRANSFER_COUNT_GET_HCOUNT(x) ((x) & 0xffff)
+
+#define VDCTRL0_ENABLE_PRESENT BIT(28)
+#define VDCTRL0_VSYNC_ACT_HIGH BIT(27)
+#define VDCTRL0_HSYNC_ACT_HIGH BIT(26)
+#define VDCTRL0_DOTCLK_ACT_FALLING BIT(25)
+#define VDCTRL0_ENABLE_ACT_HIGH BIT(24)
+#define VDCTRL0_VSYNC_PERIOD_UNIT BIT(21)
+#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT BIT(20)
+#define VDCTRL0_HALF_LINE BIT(19)
+#define VDCTRL0_HALF_LINE_MODE BIT(18)
+#define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
+#define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
+
+#define VDCTRL2_SET_HSYNC_PERIOD(x) ((x) & 0x3ffff)
+#define VDCTRL2_GET_HSYNC_PERIOD(x) ((x) & 0x3ffff)
+
+#define VDCTRL3_MUX_SYNC_SIGNALS BIT(29)
+#define VDCTRL3_VSYNC_ONLY BIT(28)
+#define SET_HOR_WAIT_CNT(x) (((x) & 0xfff) << 16)
+#define GET_HOR_WAIT_CNT(x) (((x) >> 16) & 0xfff)
+#define SET_VERT_WAIT_CNT(x) ((x) & 0xffff)
+#define GET_VERT_WAIT_CNT(x) ((x) & 0xffff)
+
+#define VDCTRL4_SET_DOTCLK_DLY(x) (((x) & 0x7) << 29) /* v4 only */
+#define VDCTRL4_GET_DOTCLK_DLY(x) (((x) >> 29) & 0x7) /* v4 only */
+#define VDCTRL4_SYNC_SIGNALS_ON BIT(18)
+#define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff)
+
+#define DEBUG0_HSYNC (1 < 26)
+#define DEBUG0_VSYNC (1 < 25)
+
+#define MXSFB_MIN_XRES 120
+#define MXSFB_MIN_YRES 120
+#define MXSFB_MAX_XRES 0xffff
+#define MXSFB_MAX_YRES 0xffff
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define TRANSP 3
+
+#define STMLCDIF_8BIT 1 /* pixel data bus to the display is of 8 bit width */
+#define STMLCDIF_16BIT 0 /* pixel data bus to the display is of 16 bit width */
+#define STMLCDIF_18BIT 2 /* pixel data bus to the display is of 18 bit width */
+#define STMLCDIF_24BIT 3 /* pixel data bus to the display is of 24 bit width */
+
+#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT BIT(6)
+#define MXSFB_SYNC_DOTCLK_FALLING_ACT BIT(7) /* negative edge sampling */
+
+#define MXSFB_FLAG_NULL BIT(0)
+#define MXSFB_FLAG_BUSFREQ BIT(1)
+
+#endif /* __MXSFB_REGS_H__ */
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 5bfae1f972c7..bbaae946525b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -76,7 +76,7 @@ find_encoder(struct drm_connector *connector, int type)
if (!id)
break;
- enc = drm_encoder_find(dev, id);
+ enc = drm_encoder_find(dev, NULL, id);
if (!enc)
continue;
nv_encoder = nouveau_encoder(enc);
@@ -144,7 +144,7 @@ nouveau_connector_ddc_detect(struct drm_connector *connector)
if (id == 0)
break;
- encoder = drm_encoder_find(dev, id);
+ encoder = drm_encoder_find(dev, NULL, id);
if (!encoder)
continue;
nv_encoder = nouveau_encoder(encoder);
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index 66ac8c40db26..eb396d6301ab 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -371,7 +371,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
ret = drm_universal_plane_init(dev, plane, (1 << priv->num_crtcs) - 1,
&omap_plane_funcs, omap_plane->formats,
- omap_plane->nformats, type, NULL);
+ omap_plane->nformats, NULL, type, NULL);
if (ret < 0)
goto error;
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 62aba976e744..fa7234810dea 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -81,4 +81,13 @@ config DRM_PANEL_SHARP_LS043T1LE01
Say Y here if you want to enable support for Sharp LS043T1LE01 qHD
(540x960) DSI panel as found on the Qualcomm APQ8074 Dragonboard
+config DRM_PANEL_RAYDIUM_RM67191
+ tristate "Raydium RM67191 FHD panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y here if you want to enable support for Raydium RM67191 FHD
+ (1080x1920) DSI panel.
+
endmenu
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index a5c7ec0236e0..5d1d85c0c7f6 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o
obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o
+obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM67191) += panel-raydium-rm67191.o
diff --git a/drivers/gpu/drm/panel/panel-raydium-rm67191.c b/drivers/gpu/drm/panel/panel-raydium-rm67191.c
new file mode 100644
index 000000000000..940f780860c6
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-raydium-rm67191.c
@@ -0,0 +1,691 @@
+/*
+ * i.MX drm driver - Raydium MIPI-DSI panel driver
+ *
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+#include <video/mipi_display.h>
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+
+#define CMD_TABLE_LEN 2
+typedef u8 cmd_set_table[CMD_TABLE_LEN];
+
+/* Write Manufacture Command Set Control */
+#define WRMAUCCTR 0xFE
+
+/* Manufacturer Command Set pages (CMD2) */
+static const cmd_set_table manufacturer_cmd_set[] = {
+ {0xFE, 0x0B},
+ {0x28, 0x40},
+ {0x29, 0x4F},
+ {0xFE, 0x0E},
+ {0x4B, 0x00},
+ {0x4C, 0x0F},
+ {0x4D, 0x20},
+ {0x4E, 0x40},
+ {0x4F, 0x60},
+ {0x50, 0xA0},
+ {0x51, 0xC0},
+ {0x52, 0xE0},
+ {0x53, 0xFF},
+ {0xFE, 0x0D},
+ {0x18, 0x08},
+ {0x42, 0x00},
+ {0x08, 0x41},
+ {0x46, 0x02},
+ {0x72, 0x09},
+ {0xFE, 0x0A},
+ {0x24, 0x17},
+ {0x04, 0x07},
+ {0x1A, 0x0C},
+ {0x0F, 0x44},
+ {0xFE, 0x04},
+ {0x00, 0x0C},
+ {0x05, 0x08},
+ {0x06, 0x08},
+ {0x08, 0x08},
+ {0x09, 0x08},
+ {0x0A, 0xE6},
+ {0x0B, 0x8C},
+ {0x1A, 0x12},
+ {0x1E, 0xE0},
+ {0x29, 0x93},
+ {0x2A, 0x93},
+ {0x2F, 0x02},
+ {0x31, 0x02},
+ {0x33, 0x05},
+ {0x37, 0x2D},
+ {0x38, 0x2D},
+ {0x3A, 0x1E},
+ {0x3B, 0x1E},
+ {0x3D, 0x27},
+ {0x3F, 0x80},
+ {0x40, 0x40},
+ {0x41, 0xE0},
+ {0x4F, 0x2F},
+ {0x50, 0x1E},
+ {0xFE, 0x06},
+ {0x00, 0xCC},
+ {0x05, 0x05},
+ {0x07, 0xA2},
+ {0x08, 0xCC},
+ {0x0D, 0x03},
+ {0x0F, 0xA2},
+ {0x32, 0xCC},
+ {0x37, 0x05},
+ {0x39, 0x83},
+ {0x3A, 0xCC},
+ {0x41, 0x04},
+ {0x43, 0x83},
+ {0x44, 0xCC},
+ {0x49, 0x05},
+ {0x4B, 0xA2},
+ {0x4C, 0xCC},
+ {0x51, 0x03},
+ {0x53, 0xA2},
+ {0x75, 0xCC},
+ {0x7A, 0x03},
+ {0x7C, 0x83},
+ {0x7D, 0xCC},
+ {0x82, 0x02},
+ {0x84, 0x83},
+ {0x85, 0xEC},
+ {0x86, 0x0F},
+ {0x87, 0xFF},
+ {0x88, 0x00},
+ {0x8A, 0x02},
+ {0x8C, 0xA2},
+ {0x8D, 0xEA},
+ {0x8E, 0x01},
+ {0x8F, 0xE8},
+ {0xFE, 0x06},
+ {0x90, 0x0A},
+ {0x92, 0x06},
+ {0x93, 0xA0},
+ {0x94, 0xA8},
+ {0x95, 0xEC},
+ {0x96, 0x0F},
+ {0x97, 0xFF},
+ {0x98, 0x00},
+ {0x9A, 0x02},
+ {0x9C, 0xA2},
+ {0xAC, 0x04},
+ {0xFE, 0x06},
+ {0xB1, 0x12},
+ {0xB2, 0x17},
+ {0xB3, 0x17},
+ {0xB4, 0x17},
+ {0xB5, 0x17},
+ {0xB6, 0x11},
+ {0xB7, 0x08},
+ {0xB8, 0x09},
+ {0xB9, 0x06},
+ {0xBA, 0x07},
+ {0xBB, 0x17},
+ {0xBC, 0x17},
+ {0xBD, 0x17},
+ {0xBE, 0x17},
+ {0xBF, 0x17},
+ {0xC0, 0x17},
+ {0xC1, 0x17},
+ {0xC2, 0x17},
+ {0xC3, 0x17},
+ {0xC4, 0x0F},
+ {0xC5, 0x0E},
+ {0xC6, 0x00},
+ {0xC7, 0x01},
+ {0xC8, 0x10},
+ {0xFE, 0x06},
+ {0x95, 0xEC},
+ {0x8D, 0xEE},
+ {0x44, 0xEC},
+ {0x4C, 0xEC},
+ {0x32, 0xEC},
+ {0x3A, 0xEC},
+ {0x7D, 0xEC},
+ {0x75, 0xEC},
+ {0x00, 0xEC},
+ {0x08, 0xEC},
+ {0x85, 0xEC},
+ {0xA6, 0x21},
+ {0xA7, 0x05},
+ {0xA9, 0x06},
+ {0x82, 0x06},
+ {0x41, 0x06},
+ {0x7A, 0x07},
+ {0x37, 0x07},
+ {0x05, 0x06},
+ {0x49, 0x06},
+ {0x0D, 0x04},
+ {0x51, 0x04},
+};
+
+static const u32 rad_bus_formats[] = {
+ MEDIA_BUS_FMT_RGB888_1X24,
+ MEDIA_BUS_FMT_RGB666_1X18,
+ MEDIA_BUS_FMT_RGB565_1X16,
+};
+
+struct rad_panel {
+ struct drm_panel base;
+ struct mipi_dsi_device *dsi;
+
+ struct gpio_desc *reset;
+ struct backlight_device *backlight;
+
+ bool prepared;
+ bool enabled;
+
+ struct videomode vm;
+ u32 width_mm;
+ u32 height_mm;
+};
+
+static inline struct rad_panel *to_rad_panel(struct drm_panel *panel)
+{
+ return container_of(panel, struct rad_panel, base);
+}
+
+static int rad_panel_push_cmd_list(struct mipi_dsi_device *dsi)
+{
+ size_t i;
+ const u8 *cmd;
+ size_t count = sizeof(manufacturer_cmd_set) / CMD_TABLE_LEN;
+ int ret = 0;
+
+ for (i = 0; i < count ; i++) {
+ cmd = manufacturer_cmd_set[i];
+ ret = mipi_dsi_generic_write(dsi, cmd, CMD_TABLE_LEN);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+};
+
+static int color_format_from_dsi_format(enum mipi_dsi_pixel_format format)
+{
+ switch (format) {
+ case MIPI_DSI_FMT_RGB565:
+ return 0x55;
+ case MIPI_DSI_FMT_RGB666:
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ return 0x66;
+ case MIPI_DSI_FMT_RGB888:
+ return 0x77;
+ default:
+ return 0x77; /* for backward compatibility */
+ }
+};
+
+static int rad_panel_prepare(struct drm_panel *panel)
+{
+ struct rad_panel *rad = to_rad_panel(panel);
+
+ if (rad->prepared)
+ return 0;
+
+ if (rad->reset != NULL) {
+ gpiod_set_value(rad->reset, 0);
+ usleep_range(5000, 10000);
+ gpiod_set_value(rad->reset, 1);
+ usleep_range(20000, 25000);
+ }
+
+ rad->prepared = true;
+
+ return 0;
+}
+
+static int rad_panel_unprepare(struct drm_panel *panel)
+{
+ struct rad_panel *rad = to_rad_panel(panel);
+ struct device *dev = &rad->dsi->dev;
+
+ if (!rad->prepared)
+ return 0;
+
+ if (rad->enabled) {
+ DRM_DEV_ERROR(dev, "Panel still enabled!\n");
+ return -EPERM;
+ }
+
+ if (rad->reset != NULL) {
+ gpiod_set_value(rad->reset, 0);
+ usleep_range(15000, 17000);
+ gpiod_set_value(rad->reset, 1);
+ }
+
+ rad->prepared = false;
+
+ return 0;
+}
+
+static int rad_panel_enable(struct drm_panel *panel)
+{
+ struct rad_panel *rad = to_rad_panel(panel);
+ struct mipi_dsi_device *dsi = rad->dsi;
+ struct device *dev = &dsi->dev;
+ int color_format = color_format_from_dsi_format(dsi->format);
+ u16 brightness;
+ int ret;
+
+ if (rad->enabled)
+ return 0;
+
+ if (!rad->prepared) {
+ DRM_DEV_ERROR(dev, "Panel not prepared!\n");
+ return -EPERM;
+ }
+
+ dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ ret = rad_panel_push_cmd_list(dsi);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "Failed to send MCS (%d)\n", ret);
+ goto fail;
+ }
+
+ /* Select User Command Set table (CMD1) */
+ ret = mipi_dsi_generic_write(dsi, (u8[]){ WRMAUCCTR, 0x00 }, 2);
+ if (ret < 0)
+ goto fail;
+
+ /* Software reset */
+ ret = mipi_dsi_dcs_soft_reset(dsi);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "Failed to do Software Reset (%d)\n", ret);
+ goto fail;
+ }
+
+ usleep_range(10000, 15000);
+
+ /* Set DSI mode */
+ ret = mipi_dsi_generic_write(dsi, (u8[]){ 0xC2, 0x0B }, 2);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "Failed to set DSI mode (%d)\n", ret);
+ goto fail;
+ }
+ /* Set tear ON */
+ ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "Failed to set tear ON (%d)\n", ret);
+ goto fail;
+ }
+ /* Set tear scanline */
+ ret = mipi_dsi_dcs_set_tear_scanline(dsi, 0x380);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "Failed to set tear scanline (%d)\n", ret);
+ goto fail;
+ }
+ /* Set pixel format */
+ ret = mipi_dsi_dcs_set_pixel_format(dsi, color_format);
+ DRM_DEV_DEBUG_DRIVER(dev, "Interface color format set to 0x%x\n",
+ color_format);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "Failed to set pixel format (%d)\n", ret);
+ goto fail;
+ }
+ /* Set display brightness */
+ brightness = rad->backlight->props.brightness;
+ ret = mipi_dsi_dcs_set_display_brightness(dsi, brightness);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "Failed to set display brightness (%d)\n",
+ ret);
+ goto fail;
+ }
+ /* Exit sleep mode */
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "Failed to exit sleep mode (%d)\n", ret);
+ goto fail;
+ }
+
+ usleep_range(5000, 10000);
+
+ ret = mipi_dsi_dcs_set_display_on(dsi);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "Failed to set display ON (%d)\n", ret);
+ goto fail;
+ }
+
+ rad->backlight->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(rad->backlight);
+
+ rad->enabled = true;
+
+ return 0;
+
+fail:
+ if (rad->reset != NULL)
+ gpiod_set_value(rad->reset, 0);
+
+ return ret;
+}
+
+static int rad_panel_disable(struct drm_panel *panel)
+{
+ struct rad_panel *rad = to_rad_panel(panel);
+ struct mipi_dsi_device *dsi = rad->dsi;
+ struct device *dev = &dsi->dev;
+ int ret;
+
+ if (!rad->enabled)
+ return 0;
+
+ dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ ret = mipi_dsi_dcs_set_display_off(dsi);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "Failed to set display OFF (%d)\n", ret);
+ return ret;
+ }
+
+ usleep_range(5000, 10000);
+
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "Failed to enter sleep mode (%d)\n", ret);
+ return ret;
+ }
+
+ usleep_range(10000, 15000);
+
+ rad->backlight->props.power = FB_BLANK_POWERDOWN;
+ backlight_update_status(rad->backlight);
+
+ rad->enabled = false;
+
+ return 0;
+}
+
+static int rad_panel_get_modes(struct drm_panel *panel)
+{
+ struct rad_panel *rad = to_rad_panel(panel);
+ struct device *dev = &rad->dsi->dev;
+ struct drm_connector *connector = panel->connector;
+ struct drm_display_mode *mode;
+ u32 *bus_flags = &connector->display_info.bus_flags;
+ int ret;
+
+ mode = drm_mode_create(connector->dev);
+ if (!mode) {
+ DRM_DEV_ERROR(dev, "Failed to create display mode!\n");
+ return 0;
+ }
+
+ drm_display_mode_from_videomode(&rad->vm, mode);
+ mode->width_mm = rad->width_mm;
+ mode->height_mm = rad->height_mm;
+ connector->display_info.width_mm = rad->width_mm;
+ connector->display_info.height_mm = rad->height_mm;
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+
+ if (rad->vm.flags & DISPLAY_FLAGS_DE_HIGH)
+ *bus_flags |= DRM_BUS_FLAG_DE_HIGH;
+ if (rad->vm.flags & DISPLAY_FLAGS_DE_LOW)
+ *bus_flags |= DRM_BUS_FLAG_DE_LOW;
+ if (rad->vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+ *bus_flags |= DRM_BUS_FLAG_PIXDATA_NEGEDGE;
+ if (rad->vm.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
+ *bus_flags |= DRM_BUS_FLAG_PIXDATA_POSEDGE;
+
+ ret = drm_display_info_set_bus_formats(&connector->display_info,
+ rad_bus_formats, ARRAY_SIZE(rad_bus_formats));
+ if (ret)
+ return ret;
+
+ drm_mode_probed_add(panel->connector, mode);
+
+ return 1;
+}
+
+static int rad_bl_get_brightness(struct backlight_device *bl)
+{
+ struct mipi_dsi_device *dsi = bl_get_data(bl);
+ struct rad_panel *rad = mipi_dsi_get_drvdata(dsi);
+ struct device *dev = &dsi->dev;
+ u16 brightness;
+ int ret;
+
+ if (!rad->prepared)
+ return 0;
+
+ DRM_DEV_DEBUG_DRIVER(dev, "\n");
+
+ dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness);
+ if (ret < 0)
+ return ret;
+
+ bl->props.brightness = brightness;
+
+ return brightness & 0xff;
+}
+
+static int rad_bl_update_status(struct backlight_device *bl)
+{
+ struct mipi_dsi_device *dsi = bl_get_data(bl);
+ struct rad_panel *rad = mipi_dsi_get_drvdata(dsi);
+ struct device *dev = &dsi->dev;
+ int ret = 0;
+
+ if (!rad->prepared)
+ return 0;
+
+ DRM_DEV_DEBUG_DRIVER(dev, "New brightness: %d\n", bl->props.brightness);
+
+ dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ ret = mipi_dsi_dcs_set_display_brightness(dsi, bl->props.brightness);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static const struct backlight_ops rad_bl_ops = {
+ .update_status = rad_bl_update_status,
+ .get_brightness = rad_bl_get_brightness,
+};
+
+static const struct drm_panel_funcs rad_panel_funcs = {
+ .prepare = rad_panel_prepare,
+ .unprepare = rad_panel_unprepare,
+ .enable = rad_panel_enable,
+ .disable = rad_panel_disable,
+ .get_modes = rad_panel_get_modes,
+};
+
+/*
+ * The clock might range from 66MHz (30Hz refresh rate)
+ * to 132MHz (60Hz refresh rate)
+ */
+static const struct display_timing rad_default_timing = {
+ .pixelclock = { 66000000, 132000000, 132000000 },
+ .hactive = { 1080, 1080, 1080 },
+ .hfront_porch = { 20, 20, 20 },
+ .hsync_len = { 2, 2, 2 },
+ .hback_porch = { 34, 34, 34 },
+ .vactive = { 1920, 1920, 1920 },
+ .vfront_porch = { 10, 10, 10 },
+ .vsync_len = { 2, 2, 2 },
+ .vback_porch = { 4, 4, 4 },
+ .flags = DISPLAY_FLAGS_HSYNC_LOW |
+ DISPLAY_FLAGS_VSYNC_LOW |
+ DISPLAY_FLAGS_DE_LOW |
+ DISPLAY_FLAGS_PIXDATA_NEGEDGE,
+};
+
+static int rad_panel_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *timings;
+ struct rad_panel *panel;
+ struct backlight_properties bl_props;
+ int ret;
+ u32 video_mode;
+
+ panel = devm_kzalloc(&dsi->dev, sizeof(*panel), GFP_KERNEL);
+ if (!panel)
+ return -ENOMEM;
+
+ mipi_dsi_set_drvdata(dsi, panel);
+
+ panel->dsi = dsi;
+
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO |
+ MIPI_DSI_CLOCK_NON_CONTINUOUS;
+
+ ret = of_property_read_u32(np, "video-mode", &video_mode);
+ if (!ret) {
+ switch (video_mode) {
+ case 0:
+ /* burst mode */
+ dsi->mode_flags |= MIPI_DSI_MODE_VIDEO_BURST;
+ break;
+ case 1:
+ /* non-burst mode with sync event */
+ break;
+ case 2:
+ /* non-burst mode with sync pulse */
+ dsi->mode_flags |= MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+ break;
+ default:
+ dev_warn(dev, "invalid video mode %d\n", video_mode);
+ break;
+
+ }
+ }
+
+ ret = of_property_read_u32(np, "dsi-lanes", &dsi->lanes);
+ if (ret < 0) {
+ dev_err(dev, "Failed to get dsi-lanes property (%d)\n", ret);
+ return ret;
+ }
+
+ /*
+ * 'display-timings' is optional, so verify if the node is present
+ * before calling of_get_videomode so we won't get console error
+ * messages
+ */
+ timings = of_get_child_by_name(np, "display-timings");
+ if (timings) {
+ of_node_put(timings);
+ ret = of_get_videomode(np, &panel->vm, 0);
+ } else {
+ videomode_from_timing(&rad_default_timing, &panel->vm);
+ }
+ if (ret < 0)
+ return ret;
+
+ of_property_read_u32(np, "panel-width-mm", &panel->width_mm);
+ of_property_read_u32(np, "panel-height-mm", &panel->height_mm);
+
+ panel->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+
+ if (IS_ERR(panel->reset))
+ panel->reset = NULL;
+ else
+ gpiod_set_value(panel->reset, 0);
+
+
+ memset(&bl_props, 0, sizeof(bl_props));
+ bl_props.type = BACKLIGHT_RAW;
+ bl_props.brightness = 255;
+ bl_props.max_brightness = 255;
+
+ panel->backlight = devm_backlight_device_register(
+ dev, dev_name(dev),
+ dev, dsi,
+ &rad_bl_ops, &bl_props);
+ if (IS_ERR(panel->backlight)) {
+ ret = PTR_ERR(panel->backlight);
+ dev_err(dev, "Failed to register backlight (%d)\n", ret);
+ return ret;
+ }
+
+ drm_panel_init(&panel->base);
+ panel->base.funcs = &rad_panel_funcs;
+ panel->base.dev = dev;
+
+ ret = drm_panel_add(&panel->base);
+
+ if (ret < 0)
+ return ret;
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0)
+ drm_panel_remove(&panel->base);
+
+ return ret;
+}
+
+static int rad_panel_remove(struct mipi_dsi_device *dsi)
+{
+ struct rad_panel *rad = mipi_dsi_get_drvdata(dsi);
+ struct device *dev = &dsi->dev;
+ int ret;
+
+ ret = mipi_dsi_detach(dsi);
+ if (ret < 0)
+ DRM_DEV_ERROR(dev, "Failed to detach from host (%d)\n",
+ ret);
+
+ drm_panel_detach(&rad->base);
+
+ if (rad->base.dev)
+ drm_panel_remove(&rad->base);
+
+ return 0;
+}
+
+static void rad_panel_shutdown(struct mipi_dsi_device *dsi)
+{
+ struct rad_panel *rad = mipi_dsi_get_drvdata(dsi);
+
+ rad_panel_disable(&rad->base);
+ rad_panel_unprepare(&rad->base);
+}
+
+static const struct of_device_id rad_of_match[] = {
+ { .compatible = "raydium,rm67191", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, rad_of_match);
+
+static struct mipi_dsi_driver rad_panel_driver = {
+ .driver = {
+ .name = "panel-raydium-rm67191",
+ .of_match_table = rad_of_match,
+ },
+ .probe = rad_panel_probe,
+ .remove = rad_panel_remove,
+ .shutdown = rad_panel_shutdown,
+};
+module_mipi_dsi_driver(rad_panel_driver);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("Raydium RM67191");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index 5b2a9f97ff04..fd065e5cd97f 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -1001,6 +1001,42 @@ static const struct panel_desc innolux_zj070na_01p = {
},
};
+static const struct display_timing jdi_tx26d202vm0bwa_timing = {
+ .pixelclock = { 151820000, 156720000, 159780000 },
+ .hactive = { 1920, 1920, 1920 },
+ .hfront_porch = { 76, 100, 112 },
+ .hback_porch = { 74, 100, 112 },
+ .hsync_len = { 30, 30, 30 },
+ .vactive = { 1200, 1200, 1200},
+ .vfront_porch = { 3, 5, 10 },
+ .vback_porch = { 2, 5, 10 },
+ .vsync_len = { 5, 5, 5 },
+ .flags = DISPLAY_FLAGS_DE_HIGH,
+};
+
+static const struct panel_desc jdi_tx26d202vm0bwa = {
+ .timings = &jdi_tx26d202vm0bwa_timing,
+ .num_timings = 1,
+ .bpc = 8,
+ .size = {
+ .width = 217,
+ .height = 136,
+ },
+ .delay = {
+ /*
+ * The panel spec recommends one second delay
+ * to the below items. However, it's a bit too
+ * long in pratical. Based on tests, it turns
+ * out 100 milliseconds is fine.
+ */
+ .prepare = 100,
+ .enable = 100,
+ .unprepare = 100,
+ .disable = 100,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+};
+
static const struct display_timing kyo_tcg121xglp_timing = {
.pixelclock = { 52000000, 65000000, 71000000 },
.hactive = { 1024, 1024, 1024 },
@@ -1634,6 +1670,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "innolux,zj070na-01p",
.data = &innolux_zj070na_01p,
}, {
+ .compatible = "jdi,tx26d202vm0bwa",
+ .data = &jdi_tx26d202vm0bwa,
+ }, {
.compatible = "kyo,tcg121xglp",
.data = &kyo_tcg121xglp,
}, {
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index f5e84f4b58e6..98fcf7720ebd 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -1460,7 +1460,7 @@ int r100_cs_packet_parse_vline(struct radeon_cs_parser *p)
header = radeon_get_ib_value(p, h_idx);
crtc_id = radeon_get_ib_value(p, h_idx + 5);
reg = R100_CP_PACKET0_GET_REG(header);
- crtc = drm_crtc_find(p->rdev->ddev, crtc_id);
+ crtc = drm_crtc_find(p->rdev->ddev, p->flip, crtc_id);
if (!crtc) {
DRM_ERROR("cannot find crtc %d\n", crtc_id);
return -ENOENT;
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index b69c8de35bd3..c22b0656cec4 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -886,7 +886,7 @@ int r600_cs_common_vline_parse(struct radeon_cs_parser *p,
crtc_id = radeon_get_ib_value(p, h_idx + 2 + 7 + 1);
reg = R600_CP_PACKET0_GET_REG(header);
- crtc = drm_crtc_find(p->rdev->ddev, crtc_id);
+ crtc = drm_crtc_find(p->rdev->ddev, p->flip, crtc_id);
if (!crtc) {
DRM_ERROR("cannot find crtc %d\n", crtc_id);
return -ENOENT;
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index c5e1aa5f1d8e..c1f7d4829942 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -256,7 +256,7 @@ radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_c
if (connector->encoder_ids[i] == 0)
break;
- encoder = drm_encoder_find(connector->dev,
+ encoder = drm_encoder_find(connector->dev, NULL,
connector->encoder_ids[i]);
if (!encoder)
continue;
@@ -283,7 +283,7 @@ static struct drm_encoder *radeon_find_encoder(struct drm_connector *connector,
if (connector->encoder_ids[i] == 0)
break;
- encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
+ encoder = drm_encoder_find(connector->dev, NULL, connector->encoder_ids[i]);
if (!encoder)
continue;
@@ -397,7 +397,7 @@ static struct drm_encoder *radeon_best_single_encoder(struct drm_connector *conn
int enc_id = connector->encoder_ids[0];
/* pick the encoder ids */
if (enc_id)
- return drm_encoder_find(connector->dev, enc_id);
+ return drm_encoder_find(connector->dev, NULL, enc_id);
return NULL;
}
@@ -1376,7 +1376,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
if (connector->encoder_ids[i] == 0)
break;
- encoder = drm_encoder_find(connector->dev,
+ encoder = drm_encoder_find(connector->dev, NULL,
connector->encoder_ids[i]);
if (!encoder)
continue;
@@ -1464,7 +1464,7 @@ static struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector)
if (connector->encoder_ids[i] == 0)
break;
- encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
+ encoder = drm_encoder_find(connector->dev, NULL, connector->encoder_ids[i]);
if (!encoder)
continue;
@@ -1483,7 +1483,7 @@ static struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector)
/* then check use digitial */
/* pick the first one */
if (enc_id)
- return drm_encoder_find(connector->dev, enc_id);
+ return drm_encoder_find(connector->dev, NULL, enc_id);
return NULL;
}
@@ -1630,7 +1630,7 @@ u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *conn
if (connector->encoder_ids[i] == 0)
break;
- encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]);
+ encoder = drm_encoder_find(connector->dev, NULL, connector->encoder_ids[i]);
if (!encoder)
continue;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index a74f8ed8ca2e..7635a87c3115 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -743,8 +743,8 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp)
ret = drm_universal_plane_init(rcdu->ddev, &plane->plane, crtcs,
&rcar_du_plane_funcs, formats,
- ARRAY_SIZE(formats), type,
- NULL);
+ ARRAY_SIZE(formats),
+ NULL, type, NULL);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index 83ebd162f3ef..58e9321962d0 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -364,8 +364,8 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp)
1 << vsp->index,
&rcar_du_vsp_plane_funcs,
formats_kms,
- ARRAY_SIZE(formats_kms), type,
- NULL);
+ ARRAY_SIZE(formats_kms),
+ NULL, type, NULL);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 32d87c6035c9..aa7678a5e75e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -1221,7 +1221,7 @@ static int vop_create_crtc(struct vop *vop)
0, &vop_plane_funcs,
win_data->phy->data_formats,
win_data->phy->nformats,
- win_data->type, NULL);
+ NULL, win_data->type, NULL);
if (ret) {
DRM_DEV_ERROR(vop->dev, "failed to init plane %d\n",
ret);
@@ -1260,7 +1260,7 @@ static int vop_create_crtc(struct vop *vop)
&vop_plane_funcs,
win_data->phy->data_formats,
win_data->phy->nformats,
- win_data->type, NULL);
+ NULL, win_data->type, NULL);
if (ret) {
DRM_DEV_ERROR(vop->dev, "failed to init overlay %d\n",
ret);
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c
index cca75bddb9ad..97c25e204bf4 100644
--- a/drivers/gpu/drm/sti/sti_cursor.c
+++ b/drivers/gpu/drm/sti/sti_cursor.c
@@ -393,7 +393,7 @@ struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
&sti_cursor_plane_helpers_funcs,
cursor_supported_formats,
ARRAY_SIZE(cursor_supported_formats),
- DRM_PLANE_TYPE_CURSOR, NULL);
+ NULL, DRM_PLANE_TYPE_CURSOR, NULL);
if (res) {
DRM_ERROR("Failed to initialize universal plane\n");
goto err_plane;
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
index 7fd496f99385..5ce8b7df46b4 100644
--- a/drivers/gpu/drm/sti/sti_gdp.c
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -923,7 +923,7 @@ struct drm_plane *sti_gdp_create(struct drm_device *drm_dev,
&sti_gdp_plane_helpers_funcs,
gdp_supported_formats,
ARRAY_SIZE(gdp_supported_formats),
- type, NULL);
+ NULL, type, NULL);
if (res) {
DRM_ERROR("Failed to initialize universal plane\n");
goto err;
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c
index f88130f2eb48..8ea422323e81 100644
--- a/drivers/gpu/drm/sti/sti_hqvdp.c
+++ b/drivers/gpu/drm/sti/sti_hqvdp.c
@@ -1277,7 +1277,7 @@ static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev,
&sti_hqvdp_plane_helpers_funcs,
hqvdp_supported_formats,
ARRAY_SIZE(hqvdp_supported_formats),
- DRM_PLANE_TYPE_OVERLAY, NULL);
+ NULL, DRM_PLANE_TYPE_OVERLAY, NULL);
if (res) {
DRM_ERROR("Failed to initialize universal plane\n");
return NULL;
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index f0035bf5efea..e3b44b2b7f3c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -111,7 +111,7 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
ret = drm_universal_plane_init(drm, &layer->plane, BIT(0),
&sun4i_backend_layer_funcs,
plane->formats, plane->nformats,
- plane->type, NULL);
+ NULL, plane->type, NULL);
if (ret) {
dev_err(drm->dev, "Couldn't initialize layer\n");
return ERR_PTR(ret);
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 4010d69cbd08..e110b2e35af3 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -655,8 +655,8 @@ static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm,
err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
&tegra_primary_plane_funcs, formats,
- num_formats, DRM_PLANE_TYPE_PRIMARY,
- NULL);
+ num_formats, NULL,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
if (err < 0) {
kfree(plane);
return ERR_PTR(err);
@@ -821,8 +821,8 @@ static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,
err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
&tegra_cursor_plane_funcs, formats,
- num_formats, DRM_PLANE_TYPE_CURSOR,
- NULL);
+ num_formats, NULL,
+ DRM_PLANE_TYPE_CURSOR, NULL);
if (err < 0) {
kfree(plane);
return ERR_PTR(err);
@@ -883,8 +883,8 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
&tegra_overlay_plane_funcs, formats,
- num_formats, DRM_PLANE_TYPE_OVERLAY,
- NULL);
+ num_formats, NULL,
+ DRM_PLANE_TYPE_OVERLAY, NULL);
if (err < 0) {
kfree(plane);
return ERR_PTR(err);
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 8ab47b502d83..d6296ca27a54 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -160,6 +160,8 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
drm->mode_config.max_width = 4096;
drm->mode_config.max_height = 4096;
+ drm->mode_config.allow_fb_modifiers = true;
+
drm->mode_config.funcs = &tegra_drm_mode_funcs;
err = tegra_drm_fb_prepare(drm);
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index e6d71fa4028e..f95fca0f00ce 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -52,9 +52,26 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer,
struct tegra_bo_tiling *tiling)
{
struct tegra_fb *fb = to_tegra_fb(framebuffer);
-
- /* TODO: handle YUV formats? */
- *tiling = fb->planes[0]->tiling;
+ uint64_t modifier = fb->base.modifier;
+
+ switch (fourcc_mod_tegra_mod(modifier)) {
+ case NV_FORMAT_MOD_TEGRA_TILED:
+ tiling->mode = TEGRA_BO_TILING_MODE_TILED;
+ tiling->value = 0;
+ break;
+
+ case NV_FORMAT_MOD_TEGRA_16BX2_BLOCK(0):
+ tiling->mode = TEGRA_BO_TILING_MODE_BLOCK;
+ tiling->value = fourcc_mod_tegra_param(modifier);
+ if (tiling->value > 5)
+ return -EINVAL;
+ break;
+
+ default:
+ /* TODO: handle YUV formats? */
+ *tiling = fb->planes[0]->tiling;
+ break;
+ }
return 0;
}
diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c
index d2f57c52f7db..59de243e5ffc 100644
--- a/drivers/gpu/drm/udl/udl_connector.c
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -105,7 +105,7 @@ static struct drm_encoder*
udl_best_single_encoder(struct drm_connector *connector)
{
int enc_id = connector->encoder_ids[0];
- return drm_encoder_find(connector->dev, enc_id);
+ return drm_encoder_find(connector->dev, NULL, enc_id);
}
static int udl_connector_set_property(struct drm_connector *connector,
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index a2d8630058ed..24593e534b2e 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -497,8 +497,8 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
u32 ctl0_offset = vc4_state->dlist_count;
const struct hvs_format *format = vc4_get_hvs_format(fb->pixel_format);
int num_planes = drm_format_num_planes(format->drm);
- u32 scl0, scl1;
- u32 lbm_size;
+ u32 scl0, scl1, pitch0;
+ u32 lbm_size, tiling;
unsigned long irqflags;
int ret, i;
@@ -539,11 +539,31 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
scl1 = vc4_get_scl_field(state, 0);
}
+ switch (fb->modifier) {
+ case DRM_FORMAT_MOD_LINEAR:
+ tiling = SCALER_CTL0_TILING_LINEAR;
+ pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH);
+ break;
+ case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
+ tiling = SCALER_CTL0_TILING_256B_OR_T;
+
+ pitch0 = (VC4_SET_FIELD(0, SCALER_PITCH0_TILE_Y_OFFSET),
+ VC4_SET_FIELD(0, SCALER_PITCH0_TILE_WIDTH_L),
+ VC4_SET_FIELD((vc4_state->src_w[0] + 31) >> 5,
+ SCALER_PITCH0_TILE_WIDTH_R));
+ break;
+ default:
+ DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx",
+ (long long)fb->modifier);
+ return -EINVAL;
+ }
+
/* Control word */
vc4_dlist_write(vc4_state,
SCALER_CTL0_VALID |
(format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
(format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
+ VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
(vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
@@ -597,8 +617,11 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
for (i = 0; i < num_planes; i++)
vc4_dlist_write(vc4_state, 0xc0c0c0c0);
- /* Pitch word 0/1/2 */
- for (i = 0; i < num_planes; i++) {
+ /* Pitch word 0 */
+ vc4_dlist_write(vc4_state, pitch0);
+
+ /* Pitch word 1/2 */
+ for (i = 1; i < num_planes; i++) {
vc4_dlist_write(vc4_state,
VC4_SET_FIELD(fb->pitches[i], SCALER_SRC_PITCH));
}
@@ -863,7 +886,7 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev,
ret = drm_universal_plane_init(dev, plane, 0xff,
&vc4_plane_funcs,
formats, num_formats,
- type, NULL);
+ NULL, type, NULL);
drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index 39f6886b2410..e030d7eb27ef 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -599,6 +599,13 @@ enum hvs_pixel_format {
#define SCALER_CTL0_SIZE_MASK VC4_MASK(29, 24)
#define SCALER_CTL0_SIZE_SHIFT 24
+#define SCALER_CTL0_TILING_MASK VC4_MASK(21, 20)
+#define SCALER_CTL0_TILING_SHIFT 20
+#define SCALER_CTL0_TILING_LINEAR 0
+#define SCALER_CTL0_TILING_64B 1
+#define SCALER_CTL0_TILING_128B 2
+#define SCALER_CTL0_TILING_256B_OR_T 3
+
#define SCALER_CTL0_HFLIP BIT(16)
#define SCALER_CTL0_VFLIP BIT(15)
@@ -728,7 +735,19 @@ enum hvs_pixel_format {
#define SCALER_PPF_KERNEL_OFFSET_SHIFT 0
#define SCALER_PPF_KERNEL_UNCACHED BIT(31)
+/* PITCH0/1/2 fields for raster. */
#define SCALER_SRC_PITCH_MASK VC4_MASK(15, 0)
#define SCALER_SRC_PITCH_SHIFT 0
+/* PITCH0 fields for T-tiled. */
+#define SCALER_PITCH0_TILE_WIDTH_L_MASK VC4_MASK(22, 16)
+#define SCALER_PITCH0_TILE_WIDTH_L_SHIFT 16
+#define SCALER_PITCH0_TILE_LINE_DIR BIT(15)
+#define SCALER_PITCH0_TILE_INITIAL_LINE_DIR BIT(14)
+/* Y offset within a tile. */
+#define SCALER_PITCH0_TILE_Y_OFFSET_MASK VC4_MASK(13, 7)
+#define SCALER_PITCH0_TILE_Y_OFFSET_SHIFT 7
+#define SCALER_PITCH0_TILE_WIDTH_R_MASK VC4_MASK(6, 0)
+#define SCALER_PITCH0_TILE_WIDTH_R_SHIFT 0
+
#endif /* VC4_REGS_H */
diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c
index ba28c0f6f28a..11c0a5daae86 100644
--- a/drivers/gpu/drm/virtio/virtgpu_plane.c
+++ b/drivers/gpu/drm/virtio/virtgpu_plane.c
@@ -225,7 +225,7 @@ struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev,
ret = drm_universal_plane_init(dev, plane, 1 << index,
&virtio_gpu_plane_funcs,
formats, nformats,
- type, NULL);
+ NULL, type, NULL);
if (ret)
goto err_plane_init;
diff --git a/drivers/gpu/drm/vivante/Makefile b/drivers/gpu/drm/vivante/Makefile
new file mode 100644
index 000000000000..d87c8e8752a6
--- /dev/null
+++ b/drivers/gpu/drm/vivante/Makefile
@@ -0,0 +1,29 @@
+##############################################################################
+#
+# Copyright (C) 2005 - 2013 by Vivante Corp.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the license, or
+# (at your option) any later version.
+#
+# 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.
+#
+##############################################################################
+
+
+#
+# Makefile for the drm device driver. This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y := -Iinclude/drm
+vivante-y := vivante_drv.o
+
+obj-$(CONFIG_DRM_VIVANTE) += vivante.o
diff --git a/drivers/gpu/drm/vivante/vivante_drv.c b/drivers/gpu/drm/vivante/vivante_drv.c
new file mode 100644
index 000000000000..a19d21276214
--- /dev/null
+++ b/drivers/gpu/drm/vivante/vivante_drv.c
@@ -0,0 +1,131 @@
+/****************************************************************************
+*
+* Copyright (C) 2005 - 2013 by Vivante Corp.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the license, or
+* (at your option) any later version.
+*
+* 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.
+*
+*****************************************************************************/
+
+
+/* vivante_drv.c -- vivante driver -*- linux-c -*-
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Rickard E. (Rik) Faith <faith@valinux.com>
+ * Daryll Strauss <daryll@valinux.com>
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include "drmP.h"
+#include "vivante_drv.h"
+
+#include "drm_pciids.h"
+#include "drm_legacy.h"
+
+static char platformdevicename[] = "Vivante GCCore";
+static struct platform_device *pplatformdev;
+
+
+int viv_set_busid(struct drm_device *dev, struct drm_master *master)
+{
+ int id;
+
+ id = dev->platformdev->id;
+ if (id < 0)
+ id = 0;
+
+ master->unique = kasprintf(GFP_KERNEL, "platform:%s:%02d",
+ dev->platformdev->name, id);
+ if (!master->unique)
+ return -ENOMEM;
+
+ master->unique_len = strlen(master->unique);
+ return 0;
+}
+
+static const struct file_operations viv_driver_fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+ .mmap = drm_legacy_mmap,
+ .poll = drm_poll,
+ .llseek = noop_llseek,
+};
+
+static struct drm_driver driver = {
+ .fops = &viv_driver_fops,
+ .set_busid = viv_set_busid,
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+ .patchlevel = DRIVER_PATCHLEVEL,
+ .driver_features = DRIVER_LEGACY,
+};
+
+static int __init vivante_init(void)
+{
+ int retcode;
+
+ pplatformdev = platform_device_register_simple(platformdevicename,
+ -1, NULL, 0);
+ if (pplatformdev == NULL)
+ printk(KERN_ERR"Platform device is null\n");
+
+ retcode = drm_platform_init(&driver, pplatformdev);
+
+ return retcode;
+}
+
+static void __exit vivante_exit(void)
+{
+ if (pplatformdev) {
+ /* The drvdata is set in drm_get_platform_dev() */
+ drm_put_dev(platform_get_drvdata(pplatformdev));
+ platform_device_unregister(pplatformdev);
+ pplatformdev = NULL;
+ }
+}
+
+module_init(vivante_init);
+module_exit(vivante_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/vivante/vivante_drv.h b/drivers/gpu/drm/vivante/vivante_drv.h
new file mode 100644
index 000000000000..03f5884ce19b
--- /dev/null
+++ b/drivers/gpu/drm/vivante/vivante_drv.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+*
+* Copyright (C) 2005 - 2013 by Vivante Corp.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the license, or
+* (at your option) any later version.
+*
+* 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.
+*
+*****************************************************************************/
+
+
+/* vivante_drv.h -- Vivante DRM template customization -*- linux-c -*-
+ * Created: Wed Feb 14 12:32:32 2012 by John Zhao
+ */
+/*
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Gareth Hughes <gareth@valinux.com>
+ */
+
+#ifndef __VIVANTE_DRV_H__
+#define __VIVANTE_DRV_H__
+
+/* General customization:
+ */
+
+#define DRIVER_AUTHOR "Vivante Inc."
+
+#define DRIVER_NAME "vivante"
+#define DRIVER_DESC "Vivante GCCore"
+#define DRIVER_DATE "20120216"
+
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+#define DRIVER_PATCHLEVEL 0
+
+#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index 5ec24fd801cd..01be355525e4 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -286,7 +286,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
drm_modeset_lock_all(dev);
- fb = drm_framebuffer_lookup(dev, arg->fb_id);
+ fb = drm_framebuffer_lookup(dev, file_priv, arg->fb_id);
if (!fb) {
DRM_ERROR("Invalid framebuffer id.\n");
ret = -ENOENT;
@@ -369,7 +369,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
drm_modeset_lock_all(dev);
- fb = drm_framebuffer_lookup(dev, arg->fb_id);
+ fb = drm_framebuffer_lookup(dev, file_priv, arg->fb_id);
if (!fb) {
DRM_ERROR("Invalid framebuffer id.\n");
ret = -ENOENT;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 33ca24ab983e..a924de6221f1 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -1190,7 +1190,7 @@ int vmw_kms_cursor_bypass_ioctl(struct drm_device *dev, void *data,
return 0;
}
- crtc = drm_crtc_find(dev, arg->crtc_id);
+ crtc = drm_crtc_find(dev, file_priv, arg->crtc_id);
if (!crtc) {
ret = -ENOENT;
goto out;
diff --git a/drivers/gpu/imx/Kconfig b/drivers/gpu/imx/Kconfig
new file mode 100644
index 000000000000..2eb65e6a0aea
--- /dev/null
+++ b/drivers/gpu/imx/Kconfig
@@ -0,0 +1,15 @@
+config IMX8_PRG
+ tristate
+ default y if IMX_DPU_CORE=y
+ default m if IMX_DPU_CORE=m
+
+config IMX8_DPRC
+ tristate
+ default y if IMX_DPU_CORE=y
+ default m if IMX_DPU_CORE=m
+
+source drivers/gpu/imx/ipu-v3/Kconfig
+source drivers/gpu/imx/dpu/Kconfig
+source drivers/gpu/imx/dpu-blit/Kconfig
+source drivers/gpu/imx/dcss/Kconfig
+source drivers/gpu/imx/lcdif/Kconfig
diff --git a/drivers/gpu/imx/Makefile b/drivers/gpu/imx/Makefile
new file mode 100644
index 000000000000..af4a94ddcfef
--- /dev/null
+++ b/drivers/gpu/imx/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_IMX8_PRG) += imx8_prg.o
+obj-$(CONFIG_IMX8_DPRC) += imx8_dprc.o
+
+obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/
+obj-$(CONFIG_IMX_DPU_CORE) += dpu/
+obj-$(CONFIG_IMX_DPU_BLIT) += dpu-blit/
+obj-$(CONFIG_IMX_DCSS_CORE) += dcss/
+obj-$(CONFIG_IMX_LCDIF_CORE) += lcdif/
diff --git a/drivers/gpu/imx/dcss/Kconfig b/drivers/gpu/imx/dcss/Kconfig
new file mode 100644
index 000000000000..0c74c349b9fd
--- /dev/null
+++ b/drivers/gpu/imx/dcss/Kconfig
@@ -0,0 +1,9 @@
+config IMX_DCSS_CORE
+ tristate "i.MX DCSS core support"
+ depends on ARCH_FSL_IMX8MQ
+ depends on RESET_CONTROLLER
+ select IMX_IRQSTEER
+ help
+ Choose this if you have a Freescale i.MX8MQ system and want to use the
+ Display Controller Sub System. This option only enables DCSS base
+ support.
diff --git a/drivers/gpu/imx/dcss/Makefile b/drivers/gpu/imx/dcss/Makefile
new file mode 100644
index 000000000000..70d05d35c5d5
--- /dev/null
+++ b/drivers/gpu/imx/dcss/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_IMX_DCSS_CORE) += imx-dcss-core.o
+
+imx-dcss-core-objs := dcss-common.o dcss-blkctl.o dcss-ctxld.o \
+ dcss-dpr.o dcss-dtg.o dcss-ss.o dcss-hdr10.o \
+ dcss-scaler.o dcss-dtrc.o dcss-dec400d.o dcss-wrscl.o \
+ dcss-rdsrc.o
diff --git a/drivers/gpu/imx/dcss/dcss-blkctl.c b/drivers/gpu/imx/dcss/dcss-blkctl.c
new file mode 100644
index 000000000000..2f13b33dba35
--- /dev/null
+++ b/drivers/gpu/imx/dcss/dcss-blkctl.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+#include <soc/imx8/soc.h>
+
+#include "dcss-prv.h"
+#include <video/imx-dcss.h>
+
+#define DCSS_BLKCTL_RESET_CTRL 0x00
+#define B_CLK_RESETN BIT(0)
+#define APB_CLK_RESETN BIT(1)
+#define P_CLK_RESETN BIT(2)
+#define RTR_CLK_RESETN BIT(3)
+#define HDMI_RESETN BIT(4)
+#define DCSS_BLKCTL_CONTROL0 0x10
+#define HDMI_MIPI_CLK_SEL BIT(0)
+#define DISPMIX_REFCLK_SEL_POS 4
+#define DISPMIX_REFCLK_SEL_MASK GENMASK(5, 4)
+#define DISPMIX_PIXCLK_SEL BIT(8)
+#define HDMI_SRC_SECURE_EN BIT(16)
+
+#define B0_SILICON_ID 0x20
+
+static struct dcss_debug_reg blkctl_debug_reg[] = {
+ DCSS_DBG_REG(DCSS_BLKCTL_RESET_CTRL),
+ DCSS_DBG_REG(DCSS_BLKCTL_CONTROL0),
+};
+
+struct dcss_blkctl_priv {
+ struct dcss_soc *dcss;
+ void __iomem *base_reg;
+
+ bool hdmi_output;
+ u32 clk_setting;
+};
+
+#ifdef CONFIG_DEBUG_FS
+void dcss_blkctl_dump_regs(struct seq_file *s, void *data)
+{
+ struct dcss_soc *dcss = data;
+ int j;
+
+ seq_puts(s, ">> Dumping BLKCTL:\n");
+ for (j = 0; j < ARRAY_SIZE(blkctl_debug_reg); j++)
+ seq_printf(s, "%-35s(0x%04x) -> 0x%08x\n",
+ blkctl_debug_reg[j].name,
+ blkctl_debug_reg[j].ofs,
+ dcss_readl(dcss->blkctl_priv->base_reg +
+ blkctl_debug_reg[j].ofs));
+}
+#endif
+
+static void dcss_blkctl_clk_reset(struct dcss_blkctl_priv *blkctl,
+ u32 assert, u32 deassert)
+{
+ if (assert)
+ dcss_clr(assert, blkctl->base_reg + DCSS_BLKCTL_RESET_CTRL);
+
+ if (deassert)
+ dcss_set(deassert, blkctl->base_reg + DCSS_BLKCTL_RESET_CTRL);
+}
+
+void dcss_blkctl_cfg(struct dcss_soc *dcss)
+{
+ struct dcss_blkctl_priv *blkctl = dcss->blkctl_priv;
+
+ if (blkctl->hdmi_output)
+ dcss_writel((blkctl->clk_setting ^ HDMI_MIPI_CLK_SEL),
+ blkctl->base_reg + DCSS_BLKCTL_CONTROL0);
+ else
+ dcss_writel((blkctl->clk_setting ^ HDMI_MIPI_CLK_SEL) |
+ DISPMIX_PIXCLK_SEL,
+ blkctl->base_reg + DCSS_BLKCTL_CONTROL0);
+
+ /* deassert clock domains resets */
+ dcss_blkctl_clk_reset(blkctl, 0, 0xffffff);
+}
+
+int dcss_blkctl_init(struct dcss_soc *dcss, unsigned long blkctl_base)
+{
+ struct device_node *node = dcss->dev->of_node;
+ int len;
+ const char *disp_dev;
+ struct dcss_blkctl_priv *blkctl;
+
+ blkctl = devm_kzalloc(dcss->dev, sizeof(*blkctl), GFP_KERNEL);
+ if (!blkctl)
+ return -ENOMEM;
+
+ blkctl->base_reg = devm_ioremap(dcss->dev, blkctl_base, SZ_4K);
+ if (!blkctl->base_reg) {
+ dev_err(dcss->dev, "unable to remap BLK CTRL base\n");
+ return -ENOMEM;
+ }
+
+ blkctl->dcss = dcss;
+ dcss->blkctl_priv = blkctl;
+
+ disp_dev = of_get_property(node, "disp-dev", &len);
+ if (!disp_dev || !strncmp(disp_dev, "hdmi_disp", 9))
+ blkctl->hdmi_output = true;
+
+ if (imx8_get_soc_revision() >= B0_SILICON_ID)
+ blkctl->clk_setting = HDMI_MIPI_CLK_SEL;
+
+ dcss_blkctl_cfg(dcss);
+
+ return 0;
+}
+
+void dcss_blkctl_exit(struct dcss_soc *dcss)
+{
+ /* assert clock domains resets */
+ dcss_blkctl_clk_reset(dcss->blkctl_priv,
+ B_CLK_RESETN | APB_CLK_RESETN | P_CLK_RESETN |
+ HDMI_RESETN | RTR_CLK_RESETN, 0);
+}
+
+/* disabled only by cold reset/reboot */
+void dcss_blkctl_hdmi_secure_src_en(struct dcss_soc *dcss)
+{
+ struct dcss_blkctl_priv *blkctl = dcss->blkctl_priv;
+
+ dcss_set(HDMI_SRC_SECURE_EN, blkctl->base_reg + DCSS_BLKCTL_CONTROL0);
+}
+EXPORT_SYMBOL(dcss_blkctl_hdmi_secure_src_en);
+
diff --git a/drivers/gpu/imx/dcss/dcss-common.c b/drivers/gpu/imx/dcss/dcss-common.c
new file mode 100644
index 000000000000..528ef258f513
--- /dev/null
+++ b/drivers/gpu/imx/dcss/dcss-common.c
@@ -0,0 +1,739 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/busfreq-imx.h>
+#include <linux/pm_qos.h>
+#include <video/imx-dcss.h>
+
+#include <drm/drm_fourcc.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+
+struct dcss_devtype {
+ const char *name;
+ u32 blkctl_ofs;
+ u32 ctxld_ofs;
+ u32 rdsrc_ofs;
+ u32 wrscl_ofs;
+ u32 dtg_ofs;
+ u32 scaler_ofs;
+ u32 ss_ofs;
+ u32 dpr_ofs;
+ u32 dtrc_ofs;
+ u32 dec400d_ofs;
+ u32 hdr10_ofs;
+};
+
+static struct dcss_devtype dcss_type_imx8m = {
+ .name = "DCSS_imx8m",
+ .blkctl_ofs = 0x2F000,
+ .ctxld_ofs = 0x23000,
+ .rdsrc_ofs = 0x22000,
+ .wrscl_ofs = 0x21000,
+ .dtg_ofs = 0x20000,
+ .scaler_ofs = 0x1C000,
+ .ss_ofs = 0x1B000,
+ .dpr_ofs = 0x18000,
+ .dtrc_ofs = 0x16000,
+ .dec400d_ofs = 0x15000,
+ .hdr10_ofs = 0x00000,
+};
+
+enum dcss_color_space dcss_drm_fourcc_to_colorspace(u32 drm_fourcc)
+{
+ switch (drm_fourcc) {
+ case DRM_FORMAT_ARGB1555:
+ case DRM_FORMAT_ABGR1555:
+ case DRM_FORMAT_RGBA5551:
+ case DRM_FORMAT_BGRA5551:
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_BGR565:
+ case DRM_FORMAT_RGB888:
+ case DRM_FORMAT_BGR888:
+ case DRM_FORMAT_ARGB4444:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_RGBX8888:
+ case DRM_FORMAT_BGRX8888:
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_BGRA8888:
+ case DRM_FORMAT_XRGB2101010:
+ case DRM_FORMAT_XBGR2101010:
+ case DRM_FORMAT_RGBX1010102:
+ case DRM_FORMAT_BGRX1010102:
+ case DRM_FORMAT_ARGB2101010:
+ case DRM_FORMAT_ABGR2101010:
+ case DRM_FORMAT_RGBA1010102:
+ case DRM_FORMAT_BGRA1010102:
+ return DCSS_COLORSPACE_RGB;
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_UYVY:
+ case DRM_FORMAT_YVYU:
+ case DRM_FORMAT_VYUY:
+ case DRM_FORMAT_YUV420:
+ case DRM_FORMAT_YVU420:
+ case DRM_FORMAT_YUV422:
+ case DRM_FORMAT_YVU422:
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV61:
+ case DRM_FORMAT_P010:
+ return DCSS_COLORSPACE_YUV;
+ default:
+ return DCSS_COLORSPACE_UNKNOWN;
+ }
+}
+EXPORT_SYMBOL_GPL(dcss_drm_fourcc_to_colorspace);
+
+int dcss_vblank_irq_get(struct dcss_soc *dcss)
+{
+ struct platform_device *pdev = to_platform_device(dcss->dev);
+
+ return platform_get_irq_byname(pdev, "dtg_prg1");
+}
+EXPORT_SYMBOL(dcss_vblank_irq_get);
+
+void dcss_vblank_irq_enable(struct dcss_soc *dcss, bool en)
+{
+ dcss_dtg_vblank_irq_enable(dcss, en);
+}
+EXPORT_SYMBOL(dcss_vblank_irq_enable);
+
+void dcss_vblank_irq_clear(struct dcss_soc *dcss)
+{
+ dcss_dtg_vblank_irq_clear(dcss);
+}
+EXPORT_SYMBOL(dcss_vblank_irq_clear);
+
+static int dcss_submodules_init(struct dcss_soc *dcss)
+{
+ int ret;
+ u32 dcss_base = dcss->start_addr;
+
+ ret = dcss_blkctl_init(dcss, dcss_base + dcss->devtype->blkctl_ofs);
+ if (ret)
+ goto blkctl_err;
+
+ ret = dcss_ctxld_init(dcss, dcss_base + dcss->devtype->ctxld_ofs);
+ if (ret)
+ goto ctxld_err;
+
+ ret = dcss_dtrc_init(dcss, dcss_base + dcss->devtype->dtrc_ofs);
+ if (ret)
+ goto dtrc_err;
+
+ ret = dcss_dec400d_init(dcss, dcss_base + dcss->devtype->dec400d_ofs);
+ if (ret)
+ goto dec400d_err;
+
+ ret = dcss_dtg_init(dcss, dcss_base + dcss->devtype->dtg_ofs);
+ if (ret)
+ goto dtg_err;
+
+ ret = dcss_ss_init(dcss, dcss_base + dcss->devtype->ss_ofs);
+ if (ret)
+ goto ss_err;
+
+ ret = dcss_dpr_init(dcss, dcss_base + dcss->devtype->dpr_ofs);
+ if (ret)
+ goto dpr_err;
+
+ ret = dcss_scaler_init(dcss, dcss_base + dcss->devtype->scaler_ofs);
+ if (ret)
+ goto scaler_err;
+
+ ret = dcss_hdr10_init(dcss, dcss_base + dcss->devtype->hdr10_ofs);
+ if (ret)
+ goto hdr10_err;
+
+ ret = dcss_wrscl_init(dcss, dcss_base + dcss->devtype->wrscl_ofs);
+ if (ret)
+ goto wrscl_err;
+
+ ret = dcss_rdsrc_init(dcss, dcss_base + dcss->devtype->rdsrc_ofs);
+ if (ret)
+ goto rdsrc_err;
+
+ return 0;
+
+rdsrc_err:
+ dcss_rdsrc_exit(dcss);
+
+wrscl_err:
+ dcss_wrscl_exit(dcss);
+
+hdr10_err:
+ dcss_hdr10_exit(dcss);
+
+scaler_err:
+ dcss_scaler_exit(dcss);
+
+dpr_err:
+ dcss_dpr_exit(dcss);
+
+ss_err:
+ dcss_ss_exit(dcss);
+
+dtg_err:
+ dcss_dtg_exit(dcss);
+
+dec400d_err:
+ dcss_dec400d_exit(dcss);
+
+dtrc_err:
+ dcss_dtrc_exit(dcss);
+
+ctxld_err:
+ dcss_ctxld_exit(dcss);
+
+blkctl_err:
+ dcss_blkctl_exit(dcss);
+
+ return ret;
+}
+
+struct dcss_platform_reg {
+ struct dcss_client_platformdata pdata;
+ const char *name;
+};
+
+static struct dcss_platform_reg client_reg = {
+ .pdata = { },
+ .name = "imx-dcss-crtc",
+};
+
+static int dcss_add_client_devices(struct dcss_soc *dcss)
+{
+ struct device *dev = dcss->dev;
+ struct platform_device *pdev;
+ struct device_node *of_node;
+ int ret;
+
+ of_node = of_graph_get_port_by_id(dev->of_node, 0);
+ if (!of_node) {
+ dev_err(dev, "no port@0 node in %s\n", dev->of_node->full_name);
+ return -ENODEV;
+ }
+
+ pdev = platform_device_alloc(client_reg.name, 0);
+ if (!pdev) {
+ dev_err(dev, "cannot allocate platform device\n");
+ return -ENOMEM;
+ }
+
+ pdev->dev.parent = dev;
+
+ client_reg.pdata.of_node = of_node;
+ ret = platform_device_add_data(pdev, &client_reg.pdata,
+ sizeof(client_reg.pdata));
+ if (!ret)
+ ret = platform_device_add(pdev);
+ if (ret) {
+ platform_device_put(pdev);
+ goto err_register;
+ }
+
+ pdev->dev.of_node = of_node;
+
+ return 0;
+
+err_register:
+ platform_device_unregister(pdev);
+ return ret;
+}
+
+static int dcss_clks_init(struct dcss_soc *dcss)
+{
+ int ret, i, j;
+ struct {
+ const char *id;
+ struct clk **clk;
+ } clks[] = {
+ {"apb", &dcss->apb_clk},
+ {"axi", &dcss->axi_clk},
+ {"pix_div", &dcss->pdiv_clk},
+ {"pix_out", &dcss->pout_clk},
+ {"rtrm", &dcss->apb_clk},
+ {"dtrc", &dcss->dtrc_clk},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(clks); i++) {
+ *clks[i].clk = devm_clk_get(dcss->dev, clks[i].id);
+ if (IS_ERR(*clks[i].clk)) {
+ dev_err(dcss->dev, "failed to get %s clock\n",
+ clks[i].id);
+ ret = PTR_ERR(*clks[i].clk);
+ goto err;
+ }
+
+ clk_prepare_enable(*clks[i].clk);
+ }
+
+ dcss->clks_on = true;
+
+ return 0;
+
+err:
+ for (j = 0; j < i; j++)
+ clk_disable_unprepare(*clks[j].clk);
+
+ return ret;
+}
+
+static void dcss_clocks_enable(struct dcss_soc *dcss, bool en)
+{
+ if (en && !dcss->clks_on) {
+ clk_prepare_enable(dcss->axi_clk);
+ clk_prepare_enable(dcss->apb_clk);
+ clk_prepare_enable(dcss->rtrm_clk);
+ clk_prepare_enable(dcss->dtrc_clk);
+ clk_prepare_enable(dcss->pdiv_clk);
+ clk_prepare_enable(dcss->pout_clk);
+ }
+
+ if (!en && dcss->clks_on) {
+ clk_disable_unprepare(dcss->pout_clk);
+ clk_disable_unprepare(dcss->pdiv_clk);
+ clk_disable_unprepare(dcss->dtrc_clk);
+ clk_disable_unprepare(dcss->rtrm_clk);
+ clk_disable_unprepare(dcss->apb_clk);
+ clk_disable_unprepare(dcss->axi_clk);
+ }
+
+ dcss->clks_on = en;
+}
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+
+static unsigned int dcss_tracing;
+EXPORT_SYMBOL(dcss_tracing);
+
+module_param_named(tracing, dcss_tracing, int, 0600);
+
+struct dcss_trace {
+ u64 seq;
+ u64 time_ns;
+ u64 tag;
+ struct list_head node;
+};
+
+static LIST_HEAD(dcss_trace_list);
+static spinlock_t lock;
+static u64 seq;
+
+void dcss_trace_write(u64 tag)
+{
+ struct dcss_trace *trace;
+ unsigned long flags;
+
+ if (!dcss_tracing)
+ return;
+
+ trace = kzalloc(sizeof(*trace), GFP_KERNEL);
+ if (!trace)
+ return;
+
+ trace->time_ns = local_clock();
+ trace->tag = tag;
+ trace->seq = seq;
+
+ spin_lock_irqsave(&lock, flags);
+ list_add_tail(&trace->node, &dcss_trace_list);
+ seq++;
+ spin_unlock_irqrestore(&lock, flags);
+}
+EXPORT_SYMBOL(dcss_trace_write);
+
+static int dcss_trace_dump_show(struct seq_file *s, void *data)
+{
+ struct dcss_trace *trace = data;
+
+ if (trace)
+ seq_printf(s, "%lld %lld %lld\n",
+ trace->seq, trace->time_ns, trace->tag);
+
+ return 0;
+}
+
+static void *dcss_trace_dump_start(struct seq_file *s, loff_t *pos)
+{
+ unsigned long flags;
+ struct dcss_trace *trace = NULL;
+
+ spin_lock_irqsave(&lock, flags);
+ if (!list_empty(&dcss_trace_list)) {
+ trace = list_first_entry(&dcss_trace_list,
+ struct dcss_trace, node);
+ goto exit;
+ }
+
+exit:
+ spin_unlock_irqrestore(&lock, flags);
+ return trace;
+}
+
+static void *dcss_trace_dump_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ unsigned long flags;
+ struct dcss_trace *next_trace = NULL;
+ struct dcss_trace *trace = v;
+
+ ++*pos;
+ spin_lock_irqsave(&lock, flags);
+ if (!list_is_last(&trace->node, &dcss_trace_list)) {
+ next_trace = list_entry(trace->node.next,
+ struct dcss_trace, node);
+ goto exit;
+ }
+
+exit:
+ spin_unlock_irqrestore(&lock, flags);
+ return next_trace;
+}
+
+static void dcss_trace_dump_stop(struct seq_file *s, void *v)
+{
+ unsigned long flags;
+ struct dcss_trace *trace, *tmp;
+ struct dcss_trace *last_trace = v;
+
+ spin_lock_irqsave(&lock, flags);
+ if (!list_empty(&dcss_trace_list)) {
+ list_for_each_entry_safe(trace, tmp, &dcss_trace_list, node) {
+ if (last_trace && trace->seq >= last_trace->seq)
+ break;
+
+ list_del(&trace->node);
+ kfree(trace);
+ }
+ }
+ spin_unlock_irqrestore(&lock, flags);
+}
+
+static const struct seq_operations dcss_trace_seq_ops = {
+ .start = dcss_trace_dump_start,
+ .next = dcss_trace_dump_next,
+ .stop = dcss_trace_dump_stop,
+ .show = dcss_trace_dump_show,
+};
+
+static int dcss_trace_dump_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &dcss_trace_seq_ops);
+}
+
+static int dcss_dump_regs_show(struct seq_file *s, void *data)
+{
+ struct dcss_soc *dcss = s->private;
+
+ pm_runtime_get_sync(dcss->dev);
+
+ dcss_blkctl_dump_regs(s, s->private);
+ dcss_dtrc_dump_regs(s, s->private);
+ dcss_dpr_dump_regs(s, s->private);
+ dcss_scaler_dump_regs(s, s->private);
+ dcss_wrscl_dump_regs(s, s->private);
+ dcss_rdsrc_dump_regs(s, s->private);
+ dcss_dtg_dump_regs(s, s->private);
+ dcss_ss_dump_regs(s, s->private);
+ dcss_hdr10_dump_regs(s, s->private);
+ dcss_ctxld_dump_regs(s, s->private);
+
+ pm_runtime_put_sync(dcss->dev);
+
+ return 0;
+}
+
+static int dcss_dump_ctx_show(struct seq_file *s, void *data)
+{
+ dcss_ctxld_dump(s, s->private);
+
+ return 0;
+}
+
+static int dcss_dump_regs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dcss_dump_regs_show, inode->i_private);
+}
+
+static int dcss_dump_ctx_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dcss_dump_ctx_show, inode->i_private);
+}
+
+static const struct file_operations dcss_dump_regs_fops = {
+ .open = dcss_dump_regs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations dcss_dump_ctx_fops = {
+ .open = dcss_dump_ctx_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations dcss_dump_trace_fops = {
+ .open = dcss_trace_dump_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static void dcss_debugfs_init(struct dcss_soc *dcss)
+{
+ struct dentry *d, *root;
+
+ root = debugfs_create_dir("imx-dcss", NULL);
+ if (IS_ERR(root) || !root)
+ goto err;
+
+ d = debugfs_create_file("dump_registers", 0444, root, dcss,
+ &dcss_dump_regs_fops);
+ if (!d)
+ goto err;
+
+ d = debugfs_create_file("dump_context", 0444, root, dcss,
+ &dcss_dump_ctx_fops);
+ if (!d)
+ goto err;
+
+ d = debugfs_create_file("dump_trace_log", 0444, root, dcss,
+ &dcss_dump_trace_fops);
+ if (!d)
+ goto err;
+
+ return;
+
+err:
+ dev_err(dcss->dev, "Unable to create debugfs entries\n");
+}
+#else
+static void dcss_debugfs_init(struct dcss_soc *dcss)
+{
+}
+
+void dcss_trace_write(u64 tag)
+{
+}
+EXPORT_SYMBOL(dcss_trace_write);
+#endif
+
+static void dcss_bus_freq(struct dcss_soc *dcss, bool en)
+{
+ if (en && !dcss->bus_freq_req)
+ request_bus_freq(BUS_FREQ_HIGH);
+
+ if (!en && dcss->bus_freq_req)
+ release_bus_freq(BUS_FREQ_HIGH);
+
+ dcss->bus_freq_req = en;
+}
+
+static int dcss_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct resource *res;
+ struct dcss_soc *dcss;
+ const struct dcss_devtype *devtype;
+
+ devtype = of_device_get_match_data(&pdev->dev);
+ if (!devtype) {
+ dev_err(&pdev->dev, "no device match found\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "cannot get memory resource\n");
+ return -EINVAL;
+ }
+
+ dcss = devm_kzalloc(&pdev->dev, sizeof(struct dcss_soc), GFP_KERNEL);
+ if (!dcss)
+ return -ENOMEM;
+
+ dcss->dev = &pdev->dev;
+ dcss->devtype = devtype;
+
+ platform_set_drvdata(pdev, dcss);
+
+ ret = dcss_clks_init(dcss);
+ if (ret) {
+ dev_err(&pdev->dev, "clocks initialization failed\n");
+ return ret;
+ }
+
+ dcss->start_addr = res->start;
+
+ ret = dcss_submodules_init(dcss);
+ if (ret) {
+ dev_err(&pdev->dev, "submodules initialization failed\n");
+ return ret;
+ }
+
+ dcss_debugfs_init(dcss);
+
+ pm_runtime_enable(&pdev->dev);
+
+ dcss_bus_freq(dcss, true);
+
+ return dcss_add_client_devices(dcss);
+}
+
+static int dcss_remove(struct platform_device *pdev)
+{
+ struct dcss_soc *dcss = platform_get_drvdata(pdev);
+
+ dcss_bus_freq(dcss, false);
+
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+void dcss_req_pm_qos(struct dcss_soc *dcss, bool en)
+{
+ if (en && !dcss->pm_req_active) {
+ pm_qos_add_request(&dcss->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, 0);
+ dcss->pm_req_active = true;
+ return;
+ }
+
+ if (dcss_dtrc_is_running(dcss, 1) || dcss_dtrc_is_running(dcss, 2))
+ return;
+
+ pm_qos_remove_request(&dcss->pm_qos_req);
+ dcss->pm_req_active = false;
+}
+EXPORT_SYMBOL(dcss_req_pm_qos);
+
+#ifdef CONFIG_PM_SLEEP
+static int dcss_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct dcss_soc *dcss = platform_get_drvdata(pdev);
+ int ret;
+
+ if (pm_runtime_suspended(dev))
+ return 0;
+
+ ret = dcss_ctxld_suspend(dcss);
+ if (ret)
+ return ret;
+
+ dcss_clocks_enable(dcss, false);
+
+ dcss_bus_freq(dcss, false);
+
+ return 0;
+}
+
+static int dcss_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct dcss_soc *dcss = platform_get_drvdata(pdev);
+
+ if (pm_runtime_suspended(dev))
+ return 0;
+
+ dcss_bus_freq(dcss, true);
+
+ dcss_clocks_enable(dcss, true);
+
+ dcss_blkctl_cfg(dcss);
+
+ dcss_ctxld_resume(dcss);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static int dcss_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct dcss_soc *dcss = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = dcss_ctxld_suspend(dcss);
+ if (ret)
+ return ret;
+
+ dcss_clocks_enable(dcss, false);
+
+ dcss_bus_freq(dcss, false);
+
+ return 0;
+}
+
+static int dcss_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct dcss_soc *dcss = platform_get_drvdata(pdev);
+
+ dcss_bus_freq(dcss, true);
+
+ dcss_clocks_enable(dcss, true);
+
+ dcss_blkctl_cfg(dcss);
+
+ dcss_ctxld_resume(dcss);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops dcss_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(dcss_suspend, dcss_resume)
+ SET_RUNTIME_PM_OPS(dcss_runtime_suspend,
+ dcss_runtime_resume, NULL)
+};
+
+static const struct of_device_id dcss_dt_ids[] = {
+ { .compatible = "nxp,imx8mq-dcss", .data = &dcss_type_imx8m, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, dcss_dt_ids);
+
+static struct platform_driver dcss_driver = {
+ .driver = {
+ .name = "dcss-core",
+ .of_match_table = dcss_dt_ids,
+ .pm = &dcss_pm,
+ },
+ .probe = dcss_probe,
+ .remove = dcss_remove,
+};
+
+module_platform_driver(dcss_driver);
+
+MODULE_DESCRIPTION("i.MX DCSS driver");
+MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@nxp.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/imx/dcss/dcss-ctxld.c b/drivers/gpu/imx/dcss/dcss-ctxld.c
new file mode 100644
index 000000000000..076c4279c4d6
--- /dev/null
+++ b/drivers/gpu/imx/dcss/dcss-ctxld.c
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/sizes.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <asm/cacheflush.h>
+
+#include "video/imx-dcss.h"
+#include "dcss-prv.h"
+
+#define DCSS_CTXLD_DEVNAME "dcss_ctxld"
+
+#define DCSS_CTXLD_CONTROL_STATUS 0x0
+#define CTXLD_ENABLE BIT(0)
+#define ARB_SEL BIT(1)
+#define RD_ERR_EN BIT(2)
+#define DB_COMP_EN BIT(3)
+#define SB_HP_COMP_EN BIT(4)
+#define SB_LP_COMP_EN BIT(5)
+#define DB_PEND_SB_REC_EN BIT(6)
+#define SB_PEND_DISP_ACTIVE_EN BIT(7)
+#define AHB_ERR_EN BIT(8)
+#define RD_ERR BIT(16)
+#define DB_COMP BIT(17)
+#define SB_HP_COMP BIT(18)
+#define SB_LP_COMP BIT(19)
+#define DB_PEND_SB_REC BIT(20)
+#define SB_PEND_DISP_ACTIVE BIT(21)
+#define AHB_ERR BIT(22)
+#define DCSS_CTXLD_DB_BASE_ADDR 0x10
+#define DCSS_CTXLD_DB_COUNT 0x14
+#define DCSS_CTXLD_SB_BASE_ADDR 0x18
+#define DCSS_CTXLD_SB_COUNT 0x1C
+#define SB_HP_COUNT_POS 0
+#define SB_HP_COUNT_MASK 0xffff
+#define SB_LP_COUNT_POS 16
+#define SB_LP_COUNT_MASK 0xffff0000
+#define DCSS_AHB_ERR_ADDR 0x20
+
+#define CTXLD_IRQ_NAME "ctx_ld" /* irq steer irq name */
+#define CTXLD_IRQ_COMPLETION (DB_COMP | SB_HP_COMP | SB_LP_COMP)
+#define CTXLD_IRQ_ERROR (RD_ERR | DB_PEND_SB_REC | AHB_ERR)
+
+/* The following sizes are in entries, 8 bytes each */
+#define CTXLD_DB_CTX_ENTRIES 1024 /* max 65536 */
+#define CTXLD_SB_LP_CTX_ENTRIES 10240 /* max 65536 */
+#define CTXLD_SB_HP_CTX_ENTRIES 20000 /* max 65536 */
+#define CTXLD_SB_CTX_ENTRIES (CTXLD_SB_LP_CTX_ENTRIES + \
+ CTXLD_SB_HP_CTX_ENTRIES)
+
+#define TRACE_ARM (1LL << 48)
+#define TRACE_IRQ (2LL << 48)
+#define TRACE_KICK (3LL << 48)
+
+static struct dcss_debug_reg ctxld_debug_reg[] = {
+ DCSS_DBG_REG(DCSS_CTXLD_CONTROL_STATUS),
+ DCSS_DBG_REG(DCSS_CTXLD_DB_BASE_ADDR),
+ DCSS_DBG_REG(DCSS_CTXLD_DB_COUNT),
+ DCSS_DBG_REG(DCSS_CTXLD_SB_BASE_ADDR),
+ DCSS_DBG_REG(DCSS_CTXLD_SB_COUNT),
+ DCSS_DBG_REG(DCSS_AHB_ERR_ADDR),
+};
+
+/* Sizes, in entries, of the DB, SB_HP and SB_LP context regions. */
+static u16 dcss_ctxld_ctx_size[3] = {
+ CTXLD_DB_CTX_ENTRIES,
+ CTXLD_SB_HP_CTX_ENTRIES,
+ CTXLD_SB_LP_CTX_ENTRIES
+};
+
+/* this represents an entry in the context loader map */
+struct dcss_ctxld_item {
+ u32 val;
+ u32 ofs;
+};
+
+#define CTX_ITEM_SIZE sizeof(struct dcss_ctxld_item)
+
+struct dcss_ctxld_priv {
+ struct dcss_soc *dcss;
+ void __iomem *ctxld_reg;
+ int irq;
+ bool irq_en;
+
+ struct dcss_ctxld_item *db[2];
+ struct dcss_ctxld_item *sb_hp[2];
+ struct dcss_ctxld_item *sb_lp[2];
+
+ dma_addr_t db_paddr[2];
+ dma_addr_t sb_paddr[2];
+
+ u16 ctx_size[2][3]; /* holds the sizes of DB, SB_HP and SB_LP ctx */
+ u8 current_ctx;
+
+ bool in_use;
+ bool armed;
+
+ spinlock_t lock; /* protects concurent access to private data */
+};
+
+#ifdef CONFIG_DEBUG_FS
+void dcss_ctxld_dump_regs(struct seq_file *s, void *data)
+{
+ struct dcss_soc *dcss = data;
+ int j;
+
+ seq_puts(s, ">> Dumping CTXLD:\n");
+ for (j = 0; j < ARRAY_SIZE(ctxld_debug_reg); j++) {
+ seq_printf(s, "%-35s(0x%04x) -> 0x%08x\n",
+ ctxld_debug_reg[j].name,
+ ctxld_debug_reg[j].ofs,
+ dcss_readl(dcss->ctxld_priv->ctxld_reg +
+ ctxld_debug_reg[j].ofs));
+ }
+}
+#endif
+
+static int __dcss_ctxld_enable(struct dcss_ctxld_priv *ctxld);
+
+static irqreturn_t dcss_ctxld_irq_handler(int irq, void *data)
+{
+ struct dcss_ctxld_priv *priv = data;
+ u32 irq_status;
+
+ irq_status = dcss_readl(priv->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+ if (irq_status & CTXLD_IRQ_COMPLETION &&
+ !(irq_status & CTXLD_ENABLE) && priv->in_use) {
+ priv->in_use = false;
+
+ dcss_trace_module(TRACE_CTXLD,
+ TRACE_IRQ | (priv->current_ctx ^ 1));
+
+ if (priv->dcss->dcss_disable_callback) {
+ struct dcss_dtg_priv *dtg = priv->dcss->dtg_priv;
+
+ priv->dcss->dcss_disable_callback(dtg);
+ }
+ } else if (irq_status & CTXLD_IRQ_ERROR) {
+ /*
+ * Except for throwing an error message and clearing the status
+ * register, there's not much we can do here.
+ */
+ dev_err(priv->dcss->dev, "ctxld: error encountered: %08x\n",
+ irq_status);
+ dev_err(priv->dcss->dev, "ctxld: db=%d, sb_hp=%d, sb_lp=%d\n",
+ priv->ctx_size[priv->current_ctx ^ 1][CTX_DB],
+ priv->ctx_size[priv->current_ctx ^ 1][CTX_SB_HP],
+ priv->ctx_size[priv->current_ctx ^ 1][CTX_SB_LP]);
+ }
+
+ dcss_clr(irq_status & (CTXLD_IRQ_ERROR | CTXLD_IRQ_COMPLETION),
+ priv->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+ return IRQ_HANDLED;
+}
+
+static int dcss_ctxld_irq_config(struct dcss_ctxld_priv *ctxld)
+{
+ struct dcss_soc *dcss = ctxld->dcss;
+ struct platform_device *pdev = to_platform_device(dcss->dev);
+ int ret;
+
+ ctxld->irq = platform_get_irq_byname(pdev, CTXLD_IRQ_NAME);
+ if (ctxld->irq < 0) {
+ dev_err(dcss->dev, "ctxld: can't get irq number\n");
+ return ctxld->irq;
+ }
+
+ ret = devm_request_irq(dcss->dev, ctxld->irq,
+ dcss_ctxld_irq_handler,
+ IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+ DCSS_CTXLD_DEVNAME, ctxld);
+ if (ret) {
+ dev_err(dcss->dev, "ctxld: irq request failed.\n");
+ return ret;
+ }
+
+ ctxld->irq_en = true;
+
+ return 0;
+}
+
+void dcss_ctxld_hw_cfg(struct dcss_soc *dcss)
+{
+ struct dcss_ctxld_priv *ctxld = dcss->ctxld_priv;
+
+ dcss_writel(RD_ERR_EN | SB_HP_COMP_EN |
+ DB_PEND_SB_REC_EN | AHB_ERR_EN | RD_ERR | AHB_ERR,
+ ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+}
+
+/**
+ * dcss_ctxld_alloc_ctx - Allocate context memory.
+ *
+ * @ctxld: Pointer to ctxld.
+ *
+ * Returns:
+ * Zeron on success, negative errno on failure.
+ */
+static int dcss_ctxld_alloc_ctx(struct dcss_ctxld_priv *ctxld)
+{
+ struct dcss_soc *dcss = ctxld->dcss;
+ struct dcss_ctxld_item *ctx;
+ int i;
+ dma_addr_t dma_handle;
+
+ for (i = 0; i < 2; i++) {
+ ctx = dmam_alloc_coherent(dcss->dev,
+ CTXLD_DB_CTX_ENTRIES * sizeof(*ctx),
+ &dma_handle, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctxld->db[i] = ctx;
+ ctxld->db_paddr[i] = dma_handle;
+
+ ctx = dmam_alloc_coherent(dcss->dev,
+ CTXLD_SB_CTX_ENTRIES * sizeof(*ctx),
+ &dma_handle, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctxld->sb_hp[i] = ctx;
+ ctxld->sb_lp[i] = ctx + CTXLD_SB_HP_CTX_ENTRIES;
+
+ ctxld->sb_paddr[i] = dma_handle;
+ }
+
+ return 0;
+}
+
+int dcss_ctxld_init(struct dcss_soc *dcss, unsigned long ctxld_base)
+{
+ struct dcss_ctxld_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dcss->dev, sizeof(struct dcss_ctxld_priv),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dcss->ctxld_priv = priv;
+ priv->dcss = dcss;
+
+ ret = dcss_ctxld_alloc_ctx(priv);
+ if (ret) {
+ dev_err(dcss->dev, "ctxld: cannot allocate context memory.\n");
+ return ret;
+ }
+
+ priv->ctxld_reg = devm_ioremap(dcss->dev, ctxld_base, SZ_4K);
+ if (!priv->ctxld_reg) {
+ dev_err(dcss->dev, "ctxld: unable to remap ctxld base\n");
+ return -ENOMEM;
+ }
+
+ ret = dcss_ctxld_irq_config(priv);
+ if (!ret)
+ return ret;
+
+ dcss_ctxld_hw_cfg(dcss);
+
+ return 0;
+}
+
+void dcss_ctxld_exit(struct dcss_soc *dcss)
+{
+}
+
+static int __dcss_ctxld_enable(struct dcss_ctxld_priv *ctxld)
+{
+ int curr_ctx = ctxld->current_ctx;
+ u32 db_base, sb_base, sb_count;
+ u32 sb_hp_cnt, sb_lp_cnt, db_cnt;
+
+ dcss_dpr_write_sysctrl(ctxld->dcss);
+ dcss_scaler_write_sclctrl(ctxld->dcss);
+
+ if (dcss_dtrc_is_running(ctxld->dcss, 1) ||
+ dcss_dtrc_is_running(ctxld->dcss, 2)) {
+ dcss_dtrc_switch_banks(ctxld->dcss);
+ ctxld->armed = true;
+ }
+
+ sb_hp_cnt = ctxld->ctx_size[curr_ctx][CTX_SB_HP];
+ sb_lp_cnt = ctxld->ctx_size[curr_ctx][CTX_SB_LP];
+ db_cnt = ctxld->ctx_size[curr_ctx][CTX_DB];
+
+ /* make sure SB_LP context area comes after SB_HP */
+ if (sb_lp_cnt &&
+ ctxld->sb_lp[curr_ctx] != ctxld->sb_hp[curr_ctx] + sb_hp_cnt) {
+ struct dcss_ctxld_item *sb_lp_adjusted;
+
+ sb_lp_adjusted = ctxld->sb_hp[curr_ctx] + sb_hp_cnt;
+
+ memcpy(sb_lp_adjusted, ctxld->sb_lp[curr_ctx],
+ sb_lp_cnt * CTX_ITEM_SIZE);
+ }
+
+ db_base = db_cnt ? ctxld->db_paddr[curr_ctx] : 0;
+
+ dcss_writel(db_base, ctxld->ctxld_reg + DCSS_CTXLD_DB_BASE_ADDR);
+ dcss_writel(db_cnt, ctxld->ctxld_reg + DCSS_CTXLD_DB_COUNT);
+
+ if (sb_hp_cnt)
+ sb_count = ((sb_hp_cnt << SB_HP_COUNT_POS) & SB_HP_COUNT_MASK) |
+ ((sb_lp_cnt << SB_LP_COUNT_POS) & SB_LP_COUNT_MASK);
+ else
+ sb_count = (sb_lp_cnt << SB_HP_COUNT_POS) & SB_HP_COUNT_MASK;
+
+ sb_base = sb_count ? ctxld->sb_paddr[curr_ctx] : 0;
+
+ dcss_writel(sb_base, ctxld->ctxld_reg + DCSS_CTXLD_SB_BASE_ADDR);
+ dcss_writel(sb_count, ctxld->ctxld_reg + DCSS_CTXLD_SB_COUNT);
+
+ dcss_trace_module(TRACE_CTXLD,
+ TRACE_ARM | db_cnt | (sb_count << 16) |
+ ((u64)ctxld->current_ctx << 32));
+
+ /* enable the context loader */
+ dcss_set(CTXLD_ENABLE, ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+ ctxld->in_use = true;
+
+ /*
+ * Toggle the current context to the alternate one so that any updates
+ * in the modules' settings take place there.
+ */
+ ctxld->current_ctx ^= 1;
+
+ ctxld->ctx_size[ctxld->current_ctx][CTX_DB] = 0;
+ ctxld->ctx_size[ctxld->current_ctx][CTX_SB_HP] = 0;
+ ctxld->ctx_size[ctxld->current_ctx][CTX_SB_LP] = 0;
+
+ return 0;
+}
+
+/**
+ * dcss_ctxld_enable - Enable context loader module.
+ *
+ * @dcss: pointer to dcss_soc.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int dcss_ctxld_enable(struct dcss_soc *dcss)
+{
+ struct dcss_ctxld_priv *ctxld = dcss->ctxld_priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctxld->lock, flags);
+ ctxld->armed = true;
+ spin_unlock_irqrestore(&ctxld->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(dcss_ctxld_enable);
+
+void dcss_ctxld_kick(struct dcss_soc *dcss)
+{
+ struct dcss_ctxld_priv *ctxld = dcss->ctxld_priv;
+ unsigned long flags;
+
+ dcss_trace_module(TRACE_CTXLD, TRACE_KICK);
+
+ spin_lock_irqsave(&ctxld->lock, flags);
+ if (ctxld->armed) {
+ ctxld->armed = false;
+ __dcss_ctxld_enable(dcss->ctxld_priv);
+ }
+ spin_unlock_irqrestore(&ctxld->lock, flags);
+}
+EXPORT_SYMBOL(dcss_ctxld_kick);
+
+void dcss_ctxld_write_irqsafe(struct dcss_soc *dcss, u32 ctx_id, u32 val,
+ u32 reg_ofs)
+{
+ struct dcss_ctxld_priv *ctxld = dcss->ctxld_priv;
+ int curr_ctx = ctxld->current_ctx;
+ struct dcss_ctxld_item *ctx[] = {
+ [CTX_DB] = ctxld->db[curr_ctx],
+ [CTX_SB_HP] = ctxld->sb_hp[curr_ctx],
+ [CTX_SB_LP] = ctxld->sb_lp[curr_ctx]
+ };
+ int item_idx = ctxld->ctx_size[curr_ctx][ctx_id];
+
+ /* if we hit this, we've got to increase the maximum context size */
+ BUG_ON(dcss_ctxld_ctx_size[ctx_id] - 1 < item_idx);
+
+ ctx[ctx_id][item_idx].val = val;
+ ctx[ctx_id][item_idx].ofs = reg_ofs;
+ ctxld->ctx_size[curr_ctx][ctx_id] += 1;
+}
+
+void dcss_ctxld_write(struct dcss_soc *dcss, u32 ctx_id, u32 val, u32 reg_ofs)
+{
+ struct dcss_ctxld_priv *ctxld = dcss->ctxld_priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctxld->lock, flags);
+ dcss_ctxld_write_irqsafe(dcss, ctx_id, val, reg_ofs);
+ spin_unlock_irqrestore(&ctxld->lock, flags);
+}
+
+bool dcss_ctxld_is_flushed(struct dcss_soc *dcss)
+{
+ struct dcss_ctxld_priv *ctxld = dcss->ctxld_priv;
+
+ return ctxld->ctx_size[ctxld->current_ctx][CTX_DB] == 0 &&
+ ctxld->ctx_size[ctxld->current_ctx][CTX_SB_HP] == 0 &&
+ ctxld->ctx_size[ctxld->current_ctx][CTX_SB_LP] == 0;
+}
+EXPORT_SYMBOL(dcss_ctxld_is_flushed);
+
+int dcss_ctxld_resume(struct dcss_soc *dcss)
+{
+ struct dcss_ctxld_priv *ctxld = dcss->ctxld_priv;
+
+ dcss_ctxld_hw_cfg(dcss);
+
+ if (!ctxld->irq_en) {
+ enable_irq(dcss->ctxld_priv->irq);
+ ctxld->irq_en = true;
+ }
+
+ return 0;
+}
+
+int dcss_ctxld_suspend(struct dcss_soc *dcss)
+{
+ int ret = 0;
+ struct dcss_ctxld_priv *ctxld = dcss->ctxld_priv;
+ int wait_time_ms = 0;
+ unsigned long flags;
+
+ while (ctxld->in_use && wait_time_ms < 500) {
+ msleep(20);
+ wait_time_ms += 20;
+ }
+
+ if (wait_time_ms > 500)
+ return -ETIMEDOUT;
+
+ spin_lock_irqsave(&ctxld->lock, flags);
+
+ if (ctxld->irq_en) {
+ disable_irq_nosync(dcss->ctxld_priv->irq);
+ ctxld->irq_en = false;
+ }
+
+ /* reset context region and sizes */
+ ctxld->current_ctx = 0;
+ ctxld->ctx_size[0][CTX_DB] = 0;
+ ctxld->ctx_size[0][CTX_SB_HP] = 0;
+ ctxld->ctx_size[0][CTX_SB_LP] = 0;
+
+ spin_unlock_irqrestore(&ctxld->lock, flags);
+ return ret;
+}
+
+#ifdef CONFIG_DEBUG_FS
+void dcss_ctxld_dump(struct seq_file *s, void *data)
+{
+ struct dcss_soc *dcss = data;
+ struct dcss_ctxld_priv *ctxld = dcss->ctxld_priv;
+ int curr_ctx = ctxld->current_ctx;
+ int i;
+ struct dcss_ctxld_item *ctx_db, *ctx_sb_hp, *ctx_sb_lp;
+ u32 ctx_db_size, ctx_sb_hp_size, ctx_sb_lp_size;
+
+ ctx_db_size = ctxld->ctx_size[curr_ctx ^ 1][CTX_DB];
+ ctx_sb_hp_size = ctxld->ctx_size[curr_ctx ^ 1][CTX_SB_HP];
+ ctx_sb_lp_size = ctxld->ctx_size[curr_ctx ^ 1][CTX_SB_LP];
+
+ ctx_db = ctxld->db[curr_ctx ^ 1];
+ ctx_sb_hp = ctxld->sb_hp[curr_ctx ^ 1];
+ ctx_sb_lp = ctxld->sb_hp[curr_ctx ^ 1] + ctx_sb_hp_size;
+
+ seq_puts(s, ">> Dumping loaded context:\n");
+ seq_puts(s, "\t>>Dumping CTX_DB:\n");
+ for (i = 0; i < ctx_db_size; i++)
+ seq_printf(s, "\t0x%16llx -> 0x%08x : 0x%08x\n",
+ (u64)&ctx_db[i], ctx_db[i].ofs, ctx_db[i].val);
+ seq_puts(s, "\t>>Dumping CTX_SB_HP:\n");
+ for (i = 0; i < ctx_sb_hp_size; i++)
+ seq_printf(s, "\t0x%16llx -> 0x%08x : 0x%08x\n",
+ (u64)&ctx_sb_hp[i], ctx_sb_hp[i].ofs,
+ ctx_sb_hp[i].val);
+ seq_puts(s, "\t>>Dumping CTX_SB_LP:\n");
+ for (i = 0; i < ctx_sb_lp_size; i++)
+ seq_printf(s, "\t0x%16llx -> 0x%08x : 0x%08x\n",
+ (u64)&ctx_sb_lp[i], ctx_sb_lp[i].ofs,
+ ctx_sb_lp[i].val);
+}
+#endif
diff --git a/drivers/gpu/imx/dcss/dcss-dec400d.c b/drivers/gpu/imx/dcss/dcss-dec400d.c
new file mode 100644
index 000000000000..24fa04461407
--- /dev/null
+++ b/drivers/gpu/imx/dcss/dcss-dec400d.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <drm/drm_fourcc.h>
+
+#include <video/imx-dcss.h>
+#include <video/viv-metadata.h>
+#include "dcss-prv.h"
+
+#define USE_CTXLD 1
+
+/* DEC400D registers offsets */
+#define DEC400D_READCONFIG_BASE 0x800
+#define DEC400D_READCONFIG(i) (DEC400D_READCONFIG_BASE + ((i) << 2))
+#define DEC400D_READCONFIG_BASE 0x800
+#define DEC400D_READBUFFERBASE0 0x900
+#define DEC400D_READCACHEBASE0 0x980
+#define DEC400D_CONTROL 0xB00
+#define DEC400D_CLEAR 0xB80
+
+#define COMPRESSION_ENABLE_BIT 0
+#define COMPRESSION_FORMAT_BIT 3
+#define COMPRESSION_ALIGN_MODE_BIT 16
+#define TILE_ALIGN_MODE_BIT 22
+#define TILE_MODE_BIT 25
+#define DISABLE_COMPRESSION_BIT 1
+#define SHADOW_TRIGGER_BIT 29
+
+#define DEC400_CFMT_ARGB8 0x0
+#define DEC400_CFMT_XRGB8 0x1
+#define DEC400_CFMT_AYUV 0x2
+#define DEC400_CFMT_UYVY 0x3
+#define DEC400_CFMT_YUY2 0x4
+#define DEC400_CFMT_YUV_ONLY 0x5
+#define DEC400_CFMT_UV_MIX 0x6
+#define DEC400_CFMT_ARGB4 0x7
+#define DEC400_CFMT_XRGB4 0x8
+#define DEC400_CFMT_A1R5G5B5 0x9
+#define DEC400_CFMT_X1R5G5B5 0xA
+#define DEC400_CFMT_R5G6B5 0xB
+#define DEC400_CFMT_Z24S8 0xC
+#define DEC400_CFMT_Z24 0xD
+#define DEC400_CFMT_Z16 0xE
+#define DEC400_CFMT_A2R10G10B10 0xF
+#define DEC400_CFMT_BAYER 0x10
+#define DEC400_CFMT_SIGNED_BAYER 0x11
+
+struct dcss_dec400d_priv {
+ struct dcss_soc *dcss;
+ void __iomem *dec400d_reg;
+ uint32_t dec400d_reg_base;
+ uint64_t modifier[4];
+ uint32_t pixel_format;
+ uint32_t ctx_id;
+ bool bypass; /* bypass or decompress */
+};
+
+static void dcss_dec400d_write(struct dcss_dec400d_priv *dec400d,
+ uint32_t value,
+ uint32_t offset)
+{
+#if !USE_CTXLD
+ dcss_writel(value, dec400d->dec400d_reg + offset);
+#else
+ dcss_ctxld_write(dec400d->dcss, dec400d->ctx_id,
+ value, dec400d->dec400d_reg_base + offset);
+#endif
+}
+
+int dcss_dec400d_init(struct dcss_soc *dcss, unsigned long dec400d_base)
+{
+ struct dcss_dec400d_priv *dec400d;
+
+ dec400d = devm_kzalloc(dcss->dev, sizeof(*dec400d), GFP_KERNEL);
+ if (!dec400d)
+ return -ENOMEM;
+
+ dcss->dec400d_priv = dec400d;
+ dec400d->dcss = dcss;
+
+ dec400d->dec400d_reg = devm_ioremap(dcss->dev, dec400d_base, SZ_4K);
+ if (!dec400d->dec400d_reg) {
+ dev_err(dcss->dev, "dec400d: unable to remap dec400d base\n");
+ return -ENOMEM;
+ }
+
+ dec400d->dec400d_reg_base = dec400d_base;
+
+#if USE_CTXLD
+ dec400d->ctx_id = CTX_SB_HP;
+#endif
+
+ return 0;
+}
+
+void dcss_dec400d_exit(struct dcss_soc *dcss)
+{
+ struct dcss_dec400d_priv *dec400d = dcss->dec400d_priv;
+
+ if (!IS_ERR(dec400d)) {
+ devm_kfree(dcss->dev, dec400d);
+ dcss->dec400d_priv = NULL;
+ }
+}
+
+void dcss_dec400d_set_format_mod(struct dcss_soc *dcss,
+ uint32_t fourcc,
+ uint32_t mod_idx,
+ uint64_t modifier)
+{
+ struct dcss_dec400d_priv *dec400d = dcss->dec400d_priv;
+
+ if (mod_idx > 3) {
+ WARN_ON(1);
+ return;
+ }
+
+ if (mod_idx == 0)
+ dec400d->pixel_format = fourcc;
+
+ dec400d->modifier[mod_idx] = modifier;
+}
+EXPORT_SYMBOL(dcss_dec400d_set_format_mod);
+
+void dcss_dec400d_bypass(struct dcss_soc *dcss)
+{
+ uint32_t control;
+ struct dcss_dec400d_priv *dec400d = dcss->dec400d_priv;
+
+ dcss_dec400d_read_config(dcss, 0, false, 0);
+
+ control = dcss_readl(dec400d->dec400d_reg + DEC400D_CONTROL);
+ pr_debug("%s: dec400d control = %#x\n", __func__, control);
+
+ control |= 0x1 << DISABLE_COMPRESSION_BIT;
+ dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
+
+ /* Trigger shadow registers */
+ control |= 0x1 << SHADOW_TRIGGER_BIT;
+ dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
+
+ dec400d->bypass = true;
+}
+EXPORT_SYMBOL(dcss_dec400d_bypass);
+
+void dcss_dec400d_shadow_trig(struct dcss_soc *dcss)
+{
+ uint32_t control;
+ struct dcss_dec400d_priv *dec400d = dcss->dec400d_priv;
+
+ /* do nothing */
+ if (dec400d->bypass == true)
+ return;
+
+ control = dcss_readl(dec400d->dec400d_reg + DEC400D_CONTROL);
+
+ /* Trigger shadow registers */
+ control |= 0x1 << SHADOW_TRIGGER_BIT;
+ dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
+}
+EXPORT_SYMBOL(dcss_dec400d_shadow_trig);
+
+void dcss_dec400d_addr_set(struct dcss_soc *dcss,
+ uint32_t baddr,
+ uint32_t caddr)
+{
+ struct dcss_dec400d_priv *dec400d = dcss->dec400d_priv;
+
+ /* set frame buffer base addr */
+ dcss_dec400d_write(dec400d, baddr, DEC400D_READBUFFERBASE0);
+
+ /* set tile status cache addr */
+ dcss_dec400d_write(dec400d, caddr, DEC400D_READCACHEBASE0);
+
+ dec400d->bypass = false;
+}
+EXPORT_SYMBOL(dcss_dec400d_addr_set);
+
+void dcss_dec400d_read_config(struct dcss_soc *dcss,
+ uint32_t read_id,
+ bool compress_en,
+ uint32_t compress_format)
+{
+ uint32_t cformat = 0;
+ uint32_t read_config = 0x0;
+ struct dcss_dec400d_priv *dec400d = dcss->dec400d_priv;
+
+ /* TODO: using 'read_id' 0 by default */
+ if (read_id) {
+ WARN_ON(1);
+ return;
+ }
+
+ if (compress_en == false)
+ goto config;
+
+ switch (compress_format) {
+ case _VIV_CFMT_ARGB8:
+ cformat = DEC400_CFMT_ARGB8;
+ break;
+ case _VIV_CFMT_XRGB8:
+ cformat = DEC400_CFMT_XRGB8;
+ break;
+ case _VIV_CFMT_AYUV:
+ cformat = DEC400_CFMT_AYUV;
+ break;
+ case _VIV_CFMT_UYVY:
+ cformat = DEC400_CFMT_UYVY;
+ break;
+ case _VIV_CFMT_YUY2:
+ cformat = DEC400_CFMT_YUY2;
+ break;
+ case _VIV_CFMT_YUV_ONLY:
+ cformat = DEC400_CFMT_YUV_ONLY;
+ break;
+ case _VIV_CFMT_UV_MIX:
+ cformat = DEC400_CFMT_UV_MIX;
+ break;
+ case _VIV_CFMT_ARGB4:
+ cformat = DEC400_CFMT_ARGB4;
+ break;
+ case _VIV_CFMT_XRGB4:
+ cformat = DEC400_CFMT_XRGB4;
+ break;
+ case _VIV_CFMT_A1R5G5B5:
+ cformat = DEC400_CFMT_A1R5G5B5;
+ break;
+ case _VIV_CFMT_X1R5G5B5:
+ cformat = DEC400_CFMT_X1R5G5B5;
+ break;
+ case _VIV_CFMT_R5G6B5:
+ cformat = DEC400_CFMT_R5G6B5;
+ break;
+ case _VIV_CFMT_Z24S8:
+ cformat = DEC400_CFMT_Z24S8;
+ break;
+ case _VIV_CFMT_Z24:
+ cformat = DEC400_CFMT_Z24;
+ break;
+ case _VIV_CFMT_Z16:
+ cformat = DEC400_CFMT_Z16;
+ break;
+ case _VIV_CFMT_A2R10G10B10:
+ cformat = DEC400_CFMT_A2R10G10B10;
+ break;
+ case _VIV_CFMT_BAYER:
+ cformat = DEC400_CFMT_BAYER;
+ break;
+ case _VIV_CFMT_SIGNED_BAYER:
+ cformat = DEC400_CFMT_SIGNED_BAYER;
+ break;
+ default:
+ /* TODO: not support yet */
+ WARN_ON(1);
+ return;
+ }
+
+ /* Dec compress format */
+ read_config |= cformat << COMPRESSION_FORMAT_BIT;
+
+ /* ALIGN32_BYTE */
+ read_config |= 0x2 << COMPRESSION_ALIGN_MODE_BIT;
+
+ /* TILE1_ALIGN */
+ read_config |= 0x0 << TILE_ALIGN_MODE_BIT;
+
+ /* TILE8x4 */
+ read_config |= 0x3 << TILE_MODE_BIT;
+
+ /* Compression Enable */
+ read_config |= 0x1 << COMPRESSION_ENABLE_BIT;
+
+config:
+ dcss_dec400d_write(dec400d, read_config, DEC400D_READCONFIG(read_id));
+}
+EXPORT_SYMBOL(dcss_dec400d_read_config);
+
+void dcss_dec400d_fast_clear_config(struct dcss_soc *dcss,
+ uint32_t fc_value,
+ bool enable)
+{
+ struct dcss_dec400d_priv *dec400d = dcss->dec400d_priv;
+
+ dcss_dec400d_write(dec400d, fc_value, DEC400D_CLEAR);
+}
+EXPORT_SYMBOL(dcss_dec400d_fast_clear_config);
+
+void dcss_dec400d_enable(struct dcss_soc *dcss)
+{
+ uint32_t control;
+ struct dcss_dec400d_priv *dec400d = dcss->dec400d_priv;
+
+ if (dec400d->bypass)
+ return;
+
+ control = dcss_readl(dec400d->dec400d_reg + DEC400D_CONTROL);
+
+ /* enable compression */
+ control &= ~(0x1 << DISABLE_COMPRESSION_BIT);
+ dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
+
+ /* Trigger shadow registers */
+ control |= 0x1 << SHADOW_TRIGGER_BIT;
+ dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
+}
+EXPORT_SYMBOL(dcss_dec400d_enable);
diff --git a/drivers/gpu/imx/dcss/dcss-dpr.c b/drivers/gpu/imx/dcss/dcss-dpr.c
new file mode 100644
index 000000000000..5d700e67f6c6
--- /dev/null
+++ b/drivers/gpu/imx/dcss/dcss-dpr.c
@@ -0,0 +1,754 @@
+/*
+ * Copyright (C) 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/sizes.h>
+#include <linux/io.h>
+#include <drm/drmP.h>
+#include <drm/drm_fourcc.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+
+#define USE_CTXLD
+
+#define DCSS_DPR_DEV_NAME "dcss_dpr"
+
+#define DCSS_DPR_SYSTEM_CTRL0 0x000
+#define RUN_EN BIT(0)
+#define SOFT_RESET BIT(1)
+#define REPEAT_EN BIT(2)
+#define SHADOW_LOAD_EN BIT(3)
+#define SW_SHADOW_LOAD_SEL BIT(4)
+#define BCMD2AXI_MSTR_ID_CTRL BIT(16)
+#define DCSS_DPR_IRQ_MASK 0x020
+#define DCSS_DPR_IRQ_MASK_STATUS 0x030
+#define DCSS_DPR_IRQ_NONMASK_STATUS 0x040
+#define IRQ_DPR_CTRL_DONE BIT(0)
+#define IRQ_DPR_RUN BIT(1)
+#define IRQ_DPR_SHADOW_LOADED BIT(2)
+#define IRQ_AXI_READ_ERR BIT(3)
+#define DPR2RTR_YRGB_FIFO_OVFL BIT(4)
+#define DPR2RTR_UV_FIFO_OVFL BIT(5)
+#define DPR2RTR_FIFO_LD_BUF_RDY_YRGB_ERR BIT(6)
+#define DPR2RTR_FIFO_LD_BUF_RDY_UV_ERR BIT(7)
+#define DCSS_DPR_MODE_CTRL0 0x050
+#define RTR_3BUF_EN BIT(0)
+#define RTR_4LINE_BUF_EN BIT(1)
+#define TILE_TYPE_POS 2
+#define TILE_TYPE_MASK GENMASK(4, 2)
+#define YUV_EN BIT(6)
+#define COMP_2PLANE_EN BIT(7)
+#define PIX_SIZE_POS 8
+#define PIX_SIZE_MASK GENMASK(9, 8)
+#define PIX_LUMA_UV_SWAP BIT(10)
+#define PIX_UV_SWAP BIT(11)
+#define B_COMP_SEL_POS 12
+#define B_COMP_SEL_MASK GENMASK(13, 12)
+#define G_COMP_SEL_POS 14
+#define G_COMP_SEL_MASK GENMASK(15, 14)
+#define R_COMP_SEL_POS 16
+#define R_COMP_SEL_MASK GENMASK(17, 16)
+#define A_COMP_SEL_POS 18
+#define A_COMP_SEL_MASK GENMASK(19, 18)
+#define DCSS_DPR_FRAME_CTRL0 0x070
+#define HFLIP_EN BIT(0)
+#define VFLIP_EN BIT(1)
+#define ROT_ENC_POS 2
+#define ROT_ENC_MASK GENMASK(3, 2)
+#define ROT_FLIP_ORDER_EN BIT(4)
+#define PITCH_POS 16
+#define PITCH_MASK GENMASK(31, 16)
+#define DCSS_DPR_FRAME_1P_CTRL0 0x090
+#define DCSS_DPR_FRAME_1P_PIX_X_CTRL 0x0A0
+#define DCSS_DPR_FRAME_1P_PIX_Y_CTRL 0x0B0
+#define DCSS_DPR_FRAME_1P_BASE_ADDR 0x0C0
+#define DCSS_DPR_FRAME_2P_CTRL0 0x0E0
+#define DCSS_DPR_FRAME_2P_PIX_X_CTRL 0x0F0
+#define DCSS_DPR_FRAME_2P_PIX_Y_CTRL 0x100
+#define DCSS_DPR_FRAME_2P_BASE_ADDR 0x110
+#define DCSS_DPR_STATUS_CTRL0 0x130
+#define STATUS_MUX_SEL_MASK GENMASK(2, 0)
+#define STATUS_SRC_SEL_POS 16
+#define STATUS_SRC_SEL_MASK GENMASK(18, 16)
+#define DCSS_DPR_STATUS_CTRL1 0x140
+#define DCSS_DPR_RTRAM_CTRL0 0x200
+#define NUM_ROWS_ACTIVE BIT(0)
+#define THRES_HIGH_POS 1
+#define THRES_HIGH_MASK GENMASK(3, 1)
+#define THRES_LOW_POS 4
+#define THRES_LOW_MASK GENMASK(6, 4)
+#define ABORT_SEL BIT(7)
+
+#define TRACE_COMPLETION (1LL << 48)
+#define TRACE_BUF_SUBMISSION (2LL << 48)
+
+struct dcss_dpr_ch {
+ void __iomem *base_reg;
+ u32 base_ofs;
+ u32 ctx_id; /* an ID to the allocated region in context loader */
+
+ u32 pix_format;
+ u32 bpp;
+ u32 planes;
+ enum dcss_pix_size pix_size;
+ enum dcss_tile_type tile;
+ bool rtram_4line_en;
+ bool rtram_3buf_en;
+
+ u32 frame_ctrl;
+ u32 mode_ctrl;
+ u32 sys_ctrl;
+ u32 rtram_ctrl;
+
+ bool sys_ctrl_chgd;
+
+ u32 pitch;
+
+ bool use_dtrc;
+
+ int ch_num;
+ int irq;
+};
+
+struct dcss_dpr_priv {
+ struct dcss_soc *dcss;
+ struct dcss_dpr_ch ch[3];
+};
+
+static void dcss_dpr_write(struct dcss_dpr_priv *dpr, int ch_num,
+ u32 val, u32 ofs)
+{
+#if !defined(USE_CTXLD)
+ dcss_writel(val, dpr->ch[ch_num].base_reg + ofs);
+#else
+ dcss_ctxld_write(dpr->dcss, dpr->ch[ch_num].ctx_id,
+ val, dpr->ch[ch_num].base_ofs + ofs);
+#endif
+}
+
+#ifdef CONFIG_DEBUG_FS
+static struct dcss_debug_reg dpr_debug_reg[] = {
+ DCSS_DBG_REG(DCSS_DPR_SYSTEM_CTRL0),
+ DCSS_DBG_REG(DCSS_DPR_IRQ_MASK),
+ DCSS_DBG_REG(DCSS_DPR_IRQ_MASK_STATUS),
+ DCSS_DBG_REG(DCSS_DPR_IRQ_NONMASK_STATUS),
+ DCSS_DBG_REG(DCSS_DPR_MODE_CTRL0),
+ DCSS_DBG_REG(DCSS_DPR_FRAME_CTRL0),
+ DCSS_DBG_REG(DCSS_DPR_FRAME_1P_CTRL0),
+ DCSS_DBG_REG(DCSS_DPR_FRAME_1P_PIX_X_CTRL),
+ DCSS_DBG_REG(DCSS_DPR_FRAME_1P_PIX_Y_CTRL),
+ DCSS_DBG_REG(DCSS_DPR_FRAME_1P_BASE_ADDR),
+ DCSS_DBG_REG(DCSS_DPR_FRAME_2P_CTRL0),
+ DCSS_DBG_REG(DCSS_DPR_FRAME_2P_PIX_X_CTRL),
+ DCSS_DBG_REG(DCSS_DPR_FRAME_2P_PIX_Y_CTRL),
+ DCSS_DBG_REG(DCSS_DPR_FRAME_2P_BASE_ADDR),
+ DCSS_DBG_REG(DCSS_DPR_STATUS_CTRL0),
+ DCSS_DBG_REG(DCSS_DPR_STATUS_CTRL1),
+ DCSS_DBG_REG(DCSS_DPR_RTRAM_CTRL0),
+};
+
+void dcss_dpr_dump_regs(struct seq_file *s, void *data)
+{
+ struct dcss_soc *dcss = data;
+ int i, j;
+
+ for (i = 0; i < 3; i++) {
+ seq_printf(s, ">> Dumping DPR CH %d:\n", i);
+ for (j = 0; j < ARRAY_SIZE(dpr_debug_reg); j++)
+ seq_printf(s, "%-35s(0x%04x) -> 0x%08x\n",
+ dpr_debug_reg[j].name,
+ dpr_debug_reg[j].ofs,
+ dcss_readl(dcss->dpr_priv->ch[i].base_reg +
+ dpr_debug_reg[j].ofs));
+ }
+}
+#endif
+
+static irqreturn_t dcss_dpr_irq_handler(int irq, void *data)
+{
+ struct dcss_dpr_ch *ch = data;
+
+ dcss_trace_module(TRACE_DPR, TRACE_COMPLETION | ch->ch_num);
+
+ dcss_clr(1, ch->base_reg + DCSS_DPR_IRQ_NONMASK_STATUS);
+
+ return IRQ_HANDLED;
+}
+
+static int dcss_dpr_irq_config(struct dcss_soc *dcss, int ch_num)
+{
+ struct platform_device *pdev = to_platform_device(dcss->dev);
+ struct dcss_dpr_priv *dpr = dcss->dpr_priv;
+ struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+ int ret;
+ char irq_name[20];
+
+ sprintf(irq_name, "dpr_dc_ch%d", ch_num);
+ irq_name[10] = 0;
+
+ ch->irq = platform_get_irq_byname(pdev, irq_name);
+ if (ch->irq < 0) {
+ dev_err(dcss->dev, "dpr: can't get DPR irq\n");
+ return ch->irq;
+ }
+
+ ret = devm_request_irq(dcss->dev, ch->irq,
+ dcss_dpr_irq_handler,
+ IRQF_TRIGGER_HIGH,
+ "dcss-dpr", ch);
+ if (ret) {
+ dev_err(dcss->dev, "dpr: irq request failed.\n");
+ return ret;
+ }
+
+ /* mask interrupts off */
+ dcss_set(0xff, ch->base_reg + DCSS_DPR_IRQ_MASK);
+
+ return 0;
+}
+
+static int dcss_dpr_ch_init_all(struct dcss_soc *dcss, unsigned long dpr_base)
+{
+ struct dcss_dpr_priv *priv = dcss->dpr_priv;
+ struct dcss_dpr_ch *ch;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ ch = &priv->ch[i];
+
+ ch->base_ofs = dpr_base + i * 0x1000;
+
+ ch->base_reg = devm_ioremap(dcss->dev, ch->base_ofs, SZ_4K);
+ if (!ch->base_reg) {
+ dev_err(dcss->dev, "dpr: unable to remap ch %d base\n",
+ i);
+ return -ENOMEM;
+ }
+
+ ch->ch_num = i;
+
+ dcss_dpr_irq_config(dcss, i);
+
+#if defined(USE_CTXLD)
+ ch->ctx_id = CTX_SB_HP;
+#endif
+ }
+
+ return 0;
+}
+
+int dcss_dpr_init(struct dcss_soc *dcss, unsigned long dpr_base)
+{
+ struct dcss_dpr_priv *priv;
+
+ priv = devm_kzalloc(dcss->dev, sizeof(struct dcss_dpr_priv),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dcss->dpr_priv = priv;
+ priv->dcss = dcss;
+
+ return dcss_dpr_ch_init_all(dcss, dpr_base);
+}
+
+void dcss_dpr_exit(struct dcss_soc *dcss)
+{
+ struct dcss_dpr_priv *dpr = dcss->dpr_priv;
+ int ch_no;
+
+ /* stop DPR on all channels */
+ for (ch_no = 0; ch_no < 3; ch_no++) {
+ struct dcss_dpr_ch *ch = &dpr->ch[ch_no];
+
+ dcss_writel(0, ch->base_reg + DCSS_DPR_SYSTEM_CTRL0);
+ }
+}
+
+static u32 dcss_dpr_x_pix_wide_adjust(struct dcss_dpr_ch *ch, u32 pix_wide,
+ u32 pix_format)
+{
+ u8 pix_in_64byte_map[3][5] = {
+ /* LIN, GPU_STD, GPU_SUP, VPU_YUV420, VPU_VP9 */
+ { 64, 8, 8, 8, 16}, /* PIX_SIZE_8 */
+ { 32, 8, 8, 8, 8}, /* PIX_SIZE_16 */
+ { 16, 4, 4, 8, 8}, /* PIX_SIZE_32 */
+ };
+ u32 offset;
+ u32 div_64byte_mod, pix_in_64byte;
+
+ pix_in_64byte = pix_in_64byte_map[ch->pix_size][ch->tile];
+
+ if (pix_format == DRM_FORMAT_P010)
+ pix_wide = pix_wide * 10 / 8;
+
+ div_64byte_mod = pix_wide % pix_in_64byte;
+ offset = (div_64byte_mod == 0) ? 0 : (pix_in_64byte - div_64byte_mod);
+
+ return pix_wide + offset;
+}
+
+static u32 dcss_dpr_y_pix_high_adjust(struct dcss_dpr_ch *ch, u32 pix_high,
+ u32 pix_format)
+{
+ u8 num_rows_buf = ch->rtram_4line_en ? 4 : 8;
+ u32 offset, pix_y_mod;
+
+ pix_y_mod = pix_high % num_rows_buf;
+ offset = pix_y_mod ? (num_rows_buf - pix_y_mod) : 0;
+
+ return pix_high + offset;
+}
+
+void dcss_dpr_set_res(struct dcss_soc *dcss, int ch_num, u32 xres, u32 yres,
+ u32 adj_w, u32 adj_h)
+{
+ struct dcss_dpr_priv *dpr = dcss->dpr_priv;
+ struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+ u32 pix_x_wide, pix_y_high;
+ int plane, max_planes = 1;
+ u32 gap = DCSS_DPR_FRAME_2P_BASE_ADDR - DCSS_DPR_FRAME_1P_BASE_ADDR;
+ u32 pix_format = dpr->ch[ch_num].pix_format;
+
+ if (pix_format == DRM_FORMAT_NV12 ||
+ pix_format == DRM_FORMAT_NV21 ||
+ pix_format == DRM_FORMAT_P010)
+ max_planes = 2;
+
+ if (pix_format == DRM_FORMAT_P010)
+ adj_w = adj_w * 10 / 8;
+
+ for (plane = 0; plane < max_planes; plane++) {
+ yres = plane == 1 ? yres >> 1 : yres;
+
+ pix_x_wide = dcss_dpr_x_pix_wide_adjust(ch, xres, pix_format);
+ pix_y_high = dcss_dpr_y_pix_high_adjust(ch, yres, pix_format);
+
+ /* DTRC may need another width alignment. If it does, use it. */
+ if (pix_x_wide < adj_w)
+ pix_x_wide = adj_w;
+
+ if (pix_y_high != adj_h)
+ pix_y_high = plane == 0 ? adj_h : adj_h >> 1;
+
+ if (plane == 0)
+ ch->pitch = pix_x_wide;
+
+ dcss_dpr_write(dpr, ch_num, pix_x_wide,
+ DCSS_DPR_FRAME_1P_PIX_X_CTRL + plane * gap);
+ dcss_dpr_write(dpr, ch_num, pix_y_high,
+ DCSS_DPR_FRAME_1P_PIX_Y_CTRL + plane * gap);
+
+ dcss_dpr_write(dpr, ch_num, ch->use_dtrc ? 7 : 2,
+ DCSS_DPR_FRAME_1P_CTRL0 + plane * gap);
+ }
+}
+EXPORT_SYMBOL(dcss_dpr_set_res);
+
+void dcss_dpr_addr_set(struct dcss_soc *dcss, int ch_num, u32 luma_base_addr,
+ u32 chroma_base_addr, u16 pitch)
+{
+ struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+ dcss_trace_module(TRACE_DPR, TRACE_BUF_SUBMISSION |
+ ((u64)ch_num << 32) | luma_base_addr);
+
+ if (ch->use_dtrc) {
+ luma_base_addr = 0x0;
+ chroma_base_addr = 0x10000000;
+ }
+
+ if (!dcss_dtrc_is_running(dcss, ch_num)) {
+ dcss_dpr_write(dcss->dpr_priv, ch_num, luma_base_addr,
+ DCSS_DPR_FRAME_1P_BASE_ADDR);
+
+ dcss_dpr_write(dcss->dpr_priv, ch_num, chroma_base_addr,
+ DCSS_DPR_FRAME_2P_BASE_ADDR);
+ }
+
+ if (ch->use_dtrc)
+ pitch = ch->pitch;
+
+ ch->frame_ctrl &= ~PITCH_MASK;
+ ch->frame_ctrl |= ((pitch << PITCH_POS) & PITCH_MASK);
+}
+EXPORT_SYMBOL(dcss_dpr_addr_set);
+
+static void dcss_dpr_argb_comp_sel(struct dcss_soc *dcss, int ch_num,
+ int a_sel, int r_sel, int g_sel, int b_sel)
+{
+ struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+ u32 sel;
+
+ sel = ((a_sel << A_COMP_SEL_POS) & A_COMP_SEL_MASK) |
+ ((r_sel << R_COMP_SEL_POS) & R_COMP_SEL_MASK) |
+ ((g_sel << G_COMP_SEL_POS) & G_COMP_SEL_MASK) |
+ ((b_sel << B_COMP_SEL_POS) & B_COMP_SEL_MASK);
+
+ ch->mode_ctrl &= ~(A_COMP_SEL_MASK | R_COMP_SEL_MASK |
+ G_COMP_SEL_MASK | B_COMP_SEL_MASK);
+ ch->mode_ctrl |= sel;
+}
+
+static void dcss_dpr_pix_size_set(struct dcss_soc *dcss, int ch_num,
+ int pix_size)
+{
+ u32 val;
+ struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+ switch (pix_size) {
+ case 8:
+ val = 0;
+ break;
+ case 16:
+ val = 1;
+ break;
+ case 32:
+ val = 2;
+ break;
+ default:
+ val = 2;
+ break;
+ }
+
+ ch->pix_size = val;
+
+ ch->mode_ctrl &= ~PIX_SIZE_MASK;
+ ch->mode_ctrl |= ((val << PIX_SIZE_POS) & PIX_SIZE_MASK);
+}
+
+static void dcss_dpr_uv_swap(struct dcss_soc *dcss, int ch_num, bool swap)
+{
+ struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+ ch->mode_ctrl &= ~PIX_UV_SWAP;
+ ch->mode_ctrl |= (swap ? PIX_UV_SWAP : 0);
+}
+
+static void dcss_dpr_y_uv_swap(struct dcss_soc *dcss, int ch_num, bool swap)
+{
+ struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+ ch->mode_ctrl &= ~PIX_LUMA_UV_SWAP;
+ ch->mode_ctrl |= (swap ? PIX_LUMA_UV_SWAP : 0);
+}
+
+static void dcss_dpr_2plane_en(struct dcss_soc *dcss, int ch_num, bool en)
+{
+ struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+ ch->mode_ctrl &= ~COMP_2PLANE_EN;
+ ch->mode_ctrl |= (en ? COMP_2PLANE_EN : 0);
+}
+
+static void dcss_dpr_yuv_en(struct dcss_soc *dcss, int ch_num, bool en)
+{
+ struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+ ch->mode_ctrl &= ~YUV_EN;
+ ch->mode_ctrl |= (en ? YUV_EN : 0);
+}
+
+static void dcss_dpr_tile_set(struct dcss_soc *dcss, int ch_num,
+ enum dcss_tile_type tile)
+{
+ struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+ ch->mode_ctrl &= ~TILE_TYPE_MASK;
+ ch->mode_ctrl |= ((tile << TILE_TYPE_POS) & TILE_TYPE_MASK);
+}
+
+void dcss_dpr_enable(struct dcss_soc *dcss, int ch_num, bool en)
+{
+ struct dcss_dpr_priv *dpr = dcss->dpr_priv;
+ struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+ u32 sys_ctrl;
+
+ sys_ctrl = (en ? REPEAT_EN | RUN_EN : 0);
+
+ if (en) {
+ dcss_dpr_write(dpr, ch_num, ch->mode_ctrl, DCSS_DPR_MODE_CTRL0);
+ dcss_dpr_write(dpr, ch_num, ch->frame_ctrl,
+ DCSS_DPR_FRAME_CTRL0);
+ dcss_dpr_write(dpr, ch_num, ch->rtram_ctrl,
+ DCSS_DPR_RTRAM_CTRL0);
+ }
+
+ if (ch->sys_ctrl != sys_ctrl)
+ ch->sys_ctrl_chgd = true;
+
+ ch->sys_ctrl = sys_ctrl;
+}
+EXPORT_SYMBOL(dcss_dpr_enable);
+
+struct rgb_comp_sel {
+ u32 drm_format;
+ int a_sel;
+ int r_sel;
+ int g_sel;
+ int b_sel;
+};
+
+static struct rgb_comp_sel comp_sel_map[] = {
+ {DRM_FORMAT_ARGB8888, 3, 2, 1, 0},
+ {DRM_FORMAT_XRGB8888, 3, 2, 1, 0},
+ {DRM_FORMAT_ABGR8888, 3, 0, 1, 2},
+ {DRM_FORMAT_XBGR8888, 3, 0, 1, 2},
+ {DRM_FORMAT_RGBA8888, 0, 3, 2, 1},
+ {DRM_FORMAT_RGBX8888, 0, 3, 2, 1},
+ {DRM_FORMAT_BGRA8888, 0, 1, 2, 3},
+ {DRM_FORMAT_BGRX8888, 0, 1, 2, 3},
+};
+
+static int to_comp_sel(u32 pix_fmt, int *a_sel, int *r_sel, int *g_sel,
+ int *b_sel)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(comp_sel_map); i++) {
+ if (comp_sel_map[i].drm_format == pix_fmt) {
+ *a_sel = comp_sel_map[i].a_sel;
+ *r_sel = comp_sel_map[i].r_sel;
+ *g_sel = comp_sel_map[i].g_sel;
+ *b_sel = comp_sel_map[i].b_sel;
+
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static void dcss_dpr_rtram_set(struct dcss_soc *dcss, int ch_num,
+ u32 pix_format)
+{
+ u32 val, mask;
+ struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+ switch (pix_format) {
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_P010:
+ ch->rtram_3buf_en = 1;
+ ch->rtram_4line_en = 0;
+ break;
+
+ default:
+ ch->rtram_3buf_en = 1;
+ ch->rtram_4line_en = 1;
+ break;
+ }
+
+ val = (ch->rtram_4line_en ? RTR_4LINE_BUF_EN : 0);
+ val |= (ch->rtram_3buf_en ? RTR_3BUF_EN : 0);
+ mask = RTR_4LINE_BUF_EN | RTR_3BUF_EN;
+
+ ch->mode_ctrl &= ~mask;
+ ch->mode_ctrl |= (val & mask);
+
+ /* TODO: Should the thresholds be hardcoded? */
+ val = (ch->rtram_4line_en ? 0 : NUM_ROWS_ACTIVE);
+ val |= (3 << THRES_LOW_POS) & THRES_LOW_MASK;
+ val |= (4 << THRES_HIGH_POS) & THRES_HIGH_MASK;
+ mask = THRES_LOW_MASK | THRES_HIGH_MASK | NUM_ROWS_ACTIVE;
+
+ ch->rtram_ctrl &= ~mask;
+ ch->rtram_ctrl |= (val & mask);
+}
+
+static void dcss_dpr_setup_components(struct dcss_soc *dcss, int ch_num,
+ u32 pix_format)
+{
+ enum dcss_color_space cs = dcss_drm_fourcc_to_colorspace(pix_format);
+ int a_sel, r_sel, g_sel, b_sel;
+ bool uv_swap, y_uv_swap;
+
+ switch (pix_format) {
+ case DRM_FORMAT_YVYU:
+ uv_swap = true;
+ y_uv_swap = true;
+ break;
+
+ case DRM_FORMAT_VYUY:
+ case DRM_FORMAT_NV21:
+ uv_swap = true;
+ y_uv_swap = false;
+ break;
+
+ case DRM_FORMAT_YUYV:
+ uv_swap = false;
+ y_uv_swap = true;
+ break;
+
+ default:
+ uv_swap = false;
+ y_uv_swap = false;
+ break;
+ }
+
+ dcss_dpr_uv_swap(dcss, ch_num, uv_swap);
+
+ dcss_dpr_y_uv_swap(dcss, ch_num, y_uv_swap);
+
+ if (cs == DCSS_COLORSPACE_RGB) {
+ if (!to_comp_sel(pix_format, &a_sel, &r_sel, &g_sel, &b_sel)) {
+ dcss_dpr_argb_comp_sel(dcss, ch_num, a_sel, r_sel,
+ g_sel, b_sel);
+ } else {
+ dcss_dpr_argb_comp_sel(dcss, ch_num, 3, 2, 1, 0);
+ }
+ } else {
+ dcss_dpr_argb_comp_sel(dcss, ch_num, 0, 0, 0, 0);
+ }
+}
+
+static int dcss_dpr_get_bpp(u32 pix_format)
+{
+ int bpp;
+ unsigned int depth;
+
+ switch (pix_format) {
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_P010:
+ bpp = 8;
+ break;
+
+ case DRM_FORMAT_UYVY:
+ case DRM_FORMAT_VYUY:
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_YVYU:
+ bpp = 16;
+ break;
+
+ default:
+ drm_fb_get_bpp_depth(pix_format, &depth, &bpp);
+ break;
+ }
+
+ return bpp;
+}
+
+void dcss_dpr_tile_derive(struct dcss_soc *dcss,
+ int ch_num,
+ uint64_t modifier)
+{
+ struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+ switch (ch_num) {
+ case 0:
+ switch (modifier) {
+ case DRM_FORMAT_MOD_LINEAR:
+ dcss_dpr_tile_set(dcss, ch_num, TILE_LINEAR);
+ ch->tile = TILE_LINEAR;
+ break;
+ case DRM_FORMAT_MOD_VIVANTE_TILED:
+ dcss_dpr_tile_set(dcss, ch_num, TILE_GPU_STANDARD);
+ ch->tile = TILE_GPU_STANDARD;
+ break;
+ case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+ case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED_FC:
+ dcss_dpr_tile_set(dcss, ch_num, TILE_GPU_SUPER);
+ ch->tile = TILE_GPU_SUPER;
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+ break;
+ case 1:
+ case 2:
+ dcss_dpr_tile_set(dcss, ch_num, TILE_LINEAR);
+ ch->tile = TILE_LINEAR;
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+}
+EXPORT_SYMBOL(dcss_dpr_tile_set);
+
+void dcss_dpr_format_set(struct dcss_soc *dcss, int ch_num, u32 pix_format,
+ bool modifiers_present)
+{
+ struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+ enum dcss_color_space dcss_cs;
+
+ dcss_cs = dcss_drm_fourcc_to_colorspace(pix_format);
+ ch->planes = drm_format_num_planes(pix_format);
+ ch->bpp = dcss_dpr_get_bpp(pix_format);
+ ch->pix_format = pix_format;
+ ch->use_dtrc = ch_num && modifiers_present;
+
+ dev_dbg(dcss->dev, "pix_format = %s, colorspace = %d, bpp = %d\n",
+ drm_get_format_name(pix_format), dcss_cs, ch->bpp);
+
+ dcss_dpr_yuv_en(dcss, ch_num, dcss_cs == DCSS_COLORSPACE_YUV);
+
+ dcss_dpr_pix_size_set(dcss, ch_num, ch->bpp);
+
+ dcss_dpr_setup_components(dcss, ch_num, pix_format);
+
+ dcss_dpr_2plane_en(dcss, ch_num, ch->planes == 2 ? true : false);
+
+ dcss_dpr_rtram_set(dcss, ch_num, pix_format);
+}
+EXPORT_SYMBOL(dcss_dpr_format_set);
+
+void dcss_dpr_write_sysctrl(struct dcss_soc *dcss)
+{
+ int chnum;
+
+ for (chnum = 0; chnum < 3; chnum++) {
+ struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[chnum];
+
+ if (ch->sys_ctrl_chgd) {
+ dcss_ctxld_write_irqsafe(dcss, ch->ctx_id, ch->sys_ctrl,
+ ch->base_ofs +
+ DCSS_DPR_SYSTEM_CTRL0);
+ ch->sys_ctrl_chgd = false;
+ }
+ }
+}
+
+void dcss_dpr_irq_enable(struct dcss_soc *dcss, bool en)
+{
+ struct dcss_dpr_priv *dpr = dcss->dpr_priv;
+
+ dcss_writel(en ? 0xfe : 0xff, dpr->ch[0].base_reg + DCSS_DPR_IRQ_MASK);
+ dcss_writel(en ? 0xfe : 0xff, dpr->ch[1].base_reg + DCSS_DPR_IRQ_MASK);
+ dcss_writel(en ? 0xfe : 0xff, dpr->ch[2].base_reg + DCSS_DPR_IRQ_MASK);
+}
+
+void dcss_dpr_set_rotation(struct dcss_soc *dcss, int ch_num, u32 rotation)
+{
+ struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+ ch->frame_ctrl &= ~(HFLIP_EN | VFLIP_EN | ROT_ENC_MASK);
+
+ ch->frame_ctrl |= rotation & DRM_REFLECT_X ? HFLIP_EN : 0;
+ ch->frame_ctrl |= rotation & DRM_REFLECT_Y ? VFLIP_EN : 0;
+
+ if (rotation & DRM_ROTATE_90)
+ ch->frame_ctrl |= 1 << ROT_ENC_POS;
+ else if (rotation & DRM_ROTATE_180)
+ ch->frame_ctrl |= 2 << ROT_ENC_POS;
+ else if (rotation & DRM_ROTATE_270)
+ ch->frame_ctrl |= 3 << ROT_ENC_POS;
+}
+EXPORT_SYMBOL(dcss_dpr_set_rotation);
diff --git a/drivers/gpu/imx/dcss/dcss-dtg.c b/drivers/gpu/imx/dcss/dcss-dtg.c
new file mode 100644
index 000000000000..cf56ef1e038b
--- /dev/null
+++ b/drivers/gpu/imx/dcss/dcss-dtg.c
@@ -0,0 +1,496 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <drm/drm_fourcc.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+
+#define USE_CTXLD
+
+#define DCSS_DTG_TC_CONTROL_STATUS 0x00
+#define CH3_EN BIT(0)
+#define CH2_EN BIT(1)
+#define CH1_EN BIT(2)
+#define OVL_DATA_MODE BIT(3)
+#define BLENDER_VIDEO_ALPHA_SEL BIT(7)
+#define DTG_START BIT(8)
+#define DBY_MODE_EN BIT(9)
+#define CH1_ALPHA_SEL BIT(10)
+#define CSS_PIX_COMP_SWAP_POS 12
+#define CSS_PIX_COMP_SWAP_MASK GENMASK(14, 12)
+#define DEFAULT_FG_ALPHA_POS 24
+#define DEFAULT_FG_ALPHA_MASK GENMASK(31, 24)
+#define DCSS_DTG_TC_DTG 0x04
+#define DCSS_DTG_TC_DISP_TOP 0x08
+#define DCSS_DTG_TC_DISP_BOT 0x0C
+#define DCSS_DTG_TC_CH1_TOP 0x10
+#define DCSS_DTG_TC_CH1_BOT 0x14
+#define DCSS_DTG_TC_CH2_TOP 0x18
+#define DCSS_DTG_TC_CH2_BOT 0x1C
+#define DCSS_DTG_TC_CH3_TOP 0x20
+#define DCSS_DTG_TC_CH3_BOT 0x24
+#define TC_X_POS 0
+#define TC_X_MASK GENMASK(12, 0)
+#define TC_Y_POS 16
+#define TC_Y_MASK GENMASK(28, 16)
+#define DCSS_DTG_TC_CTXLD 0x28
+#define TC_CTXLD_DB_Y_POS 0
+#define TC_CTXLD_DB_Y_MASK GENMASK(12, 0)
+#define TC_CTXLD_SB_Y_POS 16
+#define TC_CTXLD_SB_Y_MASK GENMASK(28, 16)
+#define DCSS_DTG_TC_CH1_BKRND 0x2C
+#define DCSS_DTG_TC_CH2_BKRND 0x30
+#define BKRND_R_Y_COMP_POS 20
+#define BKRND_R_Y_COMP_MASK GENMASK(29, 20)
+#define BKRND_G_U_COMP_POS 10
+#define BKRND_G_U_COMP_MASK GENMASK(19, 10)
+#define BKRND_B_V_COMP_POS 0
+#define BKRND_B_V_COMP_MASK GENMASK(9, 0)
+#define DCSS_DTG_BLENDER_DBY_RANGEINV 0x38
+#define DCSS_DTG_BLENDER_DBY_RANGEMIN 0x3C
+#define DCSS_DTG_BLENDER_DBY_BDP 0x40
+#define DCSS_DTG_BLENDER_BKRND_I 0x44
+#define DCSS_DTG_BLENDER_BKRND_P 0x48
+#define DCSS_DTG_BLENDER_BKRND_T 0x4C
+#define DCSS_DTG_LINE0_INT 0x50
+#define DCSS_DTG_LINE1_INT 0x54
+#define DCSS_DTG_BG_ALPHA_DEFAULT 0x58
+#define DCSS_DTG_INT_STATUS 0x5C
+#define DCSS_DTG_INT_CONTROL 0x60
+#define DCSS_DTG_TC_CH3_BKRND 0x64
+#define DCSS_DTG_INT_MASK 0x68
+#define LINE0_IRQ BIT(0)
+#define LINE1_IRQ BIT(1)
+#define LINE2_IRQ BIT(2)
+#define LINE3_IRQ BIT(3)
+#define DCSS_DTG_LINE2_INT 0x6C
+#define DCSS_DTG_LINE3_INT 0x70
+#define DCSS_DTG_DBY_OL 0x74
+#define DCSS_DTG_DBY_BL 0x78
+#define DCSS_DTG_DBY_EL 0x7C
+
+static struct dcss_debug_reg dtg_debug_reg[] = {
+ DCSS_DBG_REG(DCSS_DTG_TC_CONTROL_STATUS),
+ DCSS_DBG_REG(DCSS_DTG_TC_DTG),
+ DCSS_DBG_REG(DCSS_DTG_TC_DISP_TOP),
+ DCSS_DBG_REG(DCSS_DTG_TC_DISP_BOT),
+ DCSS_DBG_REG(DCSS_DTG_TC_CH1_TOP),
+ DCSS_DBG_REG(DCSS_DTG_TC_CH1_BOT),
+ DCSS_DBG_REG(DCSS_DTG_TC_CH2_TOP),
+ DCSS_DBG_REG(DCSS_DTG_TC_CH2_BOT),
+ DCSS_DBG_REG(DCSS_DTG_TC_CH3_TOP),
+ DCSS_DBG_REG(DCSS_DTG_TC_CH3_BOT),
+ DCSS_DBG_REG(DCSS_DTG_TC_CTXLD),
+ DCSS_DBG_REG(DCSS_DTG_TC_CH1_BKRND),
+ DCSS_DBG_REG(DCSS_DTG_TC_CH2_BKRND),
+ DCSS_DBG_REG(DCSS_DTG_BLENDER_DBY_RANGEINV),
+ DCSS_DBG_REG(DCSS_DTG_BLENDER_DBY_RANGEMIN),
+ DCSS_DBG_REG(DCSS_DTG_BLENDER_DBY_BDP),
+ DCSS_DBG_REG(DCSS_DTG_BLENDER_BKRND_I),
+ DCSS_DBG_REG(DCSS_DTG_BLENDER_BKRND_P),
+ DCSS_DBG_REG(DCSS_DTG_BLENDER_BKRND_T),
+ DCSS_DBG_REG(DCSS_DTG_LINE0_INT),
+ DCSS_DBG_REG(DCSS_DTG_LINE1_INT),
+ DCSS_DBG_REG(DCSS_DTG_BG_ALPHA_DEFAULT),
+ DCSS_DBG_REG(DCSS_DTG_INT_STATUS),
+ DCSS_DBG_REG(DCSS_DTG_INT_CONTROL),
+ DCSS_DBG_REG(DCSS_DTG_TC_CH3_BKRND),
+ DCSS_DBG_REG(DCSS_DTG_INT_MASK),
+ DCSS_DBG_REG(DCSS_DTG_LINE2_INT),
+ DCSS_DBG_REG(DCSS_DTG_LINE3_INT),
+ DCSS_DBG_REG(DCSS_DTG_DBY_OL),
+ DCSS_DBG_REG(DCSS_DTG_DBY_BL),
+ DCSS_DBG_REG(DCSS_DTG_DBY_EL),
+};
+
+struct dcss_dtg_priv {
+ struct dcss_soc *dcss;
+ void __iomem *base_reg;
+ u32 base_ofs;
+
+ u32 ctx_id;
+
+ bool in_use;
+
+ u32 dis_ulc_x;
+ u32 dis_ulc_y;
+
+ u32 control_status;
+ u32 alpha;
+ u32 use_global;
+
+ int ctxld_kick_irq;
+
+ /*
+ * This will be passed on by DRM CRTC so that we can signal when DTG has
+ * been successfully stopped. Otherwise, any modesetting while DTG is
+ * still on may result in unpredictable behavior.
+ */
+ struct completion *dis_completion;
+};
+
+static void dcss_dtg_write(struct dcss_dtg_priv *dtg, u32 val, u32 ofs)
+{
+ if (!dtg->in_use)
+ dcss_writel(val, dtg->base_reg + ofs);
+#if defined(USE_CTXLD)
+ dcss_ctxld_write(dtg->dcss, dtg->ctx_id, val, dtg->base_ofs + ofs);
+#endif
+}
+
+#ifdef CONFIG_DEBUG_FS
+void dcss_dtg_dump_regs(struct seq_file *s, void *data)
+{
+ struct dcss_soc *dcss = data;
+ int j;
+
+ seq_puts(s, ">> Dumping DTG:\n");
+ for (j = 0; j < ARRAY_SIZE(dtg_debug_reg); j++)
+ seq_printf(s, "%-35s(0x%04x) -> 0x%08x\n",
+ dtg_debug_reg[j].name,
+ dtg_debug_reg[j].ofs,
+ dcss_readl(dcss->dtg_priv->base_reg +
+ dtg_debug_reg[j].ofs));
+}
+#endif
+
+static irqreturn_t dcss_dtg_irq_handler(int irq, void *data)
+{
+ struct dcss_dtg_priv *dtg = data;
+ u32 status;
+
+ status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS);
+
+ dcss_ctxld_kick(dtg->dcss);
+
+ dcss_writel(status & LINE1_IRQ, dtg->base_reg + DCSS_DTG_INT_CONTROL);
+
+ return IRQ_HANDLED;
+}
+
+static int dcss_dtg_irq_config(struct dcss_dtg_priv *dtg)
+{
+ struct dcss_soc *dcss = dtg->dcss;
+ struct platform_device *pdev = to_platform_device(dcss->dev);
+ int ret;
+
+ dtg->ctxld_kick_irq = platform_get_irq_byname(pdev, "ctxld_kick");
+ if (dtg->ctxld_kick_irq < 0) {
+ dev_err(dcss->dev, "dtg: can't get line2 irq number\n");
+ return dtg->ctxld_kick_irq;
+ }
+
+ ret = devm_request_irq(dcss->dev, dtg->ctxld_kick_irq,
+ dcss_dtg_irq_handler,
+ IRQF_TRIGGER_HIGH,
+ "dcss_ctxld_kick", dtg);
+ if (ret) {
+ dev_err(dcss->dev, "dtg: irq request failed.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int dcss_dtg_init(struct dcss_soc *dcss, unsigned long dtg_base)
+{
+ struct dcss_dtg_priv *dtg;
+
+ dtg = devm_kzalloc(dcss->dev, sizeof(*dtg), GFP_KERNEL);
+ if (!dtg)
+ return -ENOMEM;
+
+ dcss->dtg_priv = dtg;
+ dtg->dcss = dcss;
+
+ dtg->base_reg = devm_ioremap(dcss->dev, dtg_base, SZ_4K);
+ if (!dtg->base_reg) {
+ dev_err(dcss->dev, "dtg: unable to remap dtg base\n");
+ return -ENOMEM;
+ }
+
+ dtg->base_ofs = dtg_base;
+
+#if defined(USE_CTXLD)
+ dtg->ctx_id = CTX_DB;
+#endif
+
+ dtg->alpha = 255;
+ dtg->use_global = 0;
+
+ dtg->control_status |= OVL_DATA_MODE | BLENDER_VIDEO_ALPHA_SEL |
+ ((dtg->alpha << DEFAULT_FG_ALPHA_POS) & DEFAULT_FG_ALPHA_MASK);
+
+ return dcss_dtg_irq_config(dtg);
+}
+
+void dcss_dtg_exit(struct dcss_soc *dcss)
+{
+ struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+
+ /* stop DTG */
+ dcss_writel(DTG_START, dtg->base_reg + DCSS_DTG_TC_CONTROL_STATUS);
+}
+
+void dcss_dtg_sync_set(struct dcss_soc *dcss, struct videomode *vm)
+{
+ struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+ u16 dtg_lrc_x, dtg_lrc_y;
+ u16 dis_ulc_x, dis_ulc_y;
+ u16 dis_lrc_x, dis_lrc_y;
+ u32 sb_ctxld_trig, db_ctxld_trig;
+
+ dev_dbg(dcss->dev, "hfront_porch = %d\n", vm->hfront_porch);
+ dev_dbg(dcss->dev, "hback_porch = %d\n", vm->hback_porch);
+ dev_dbg(dcss->dev, "hsync_len = %d\n", vm->hsync_len);
+ dev_dbg(dcss->dev, "hactive = %d\n", vm->hactive);
+ dev_dbg(dcss->dev, "vfront_porch = %d\n", vm->vfront_porch);
+ dev_dbg(dcss->dev, "vback_porch = %d\n", vm->vback_porch);
+ dev_dbg(dcss->dev, "vsync_len = %d\n", vm->vsync_len);
+ dev_dbg(dcss->dev, "vactive = %d\n", vm->vactive);
+
+ dtg_lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
+ vm->hactive - 1;
+ dtg_lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len +
+ vm->vactive - 1;
+ dis_ulc_x = vm->hsync_len + vm->hback_porch - 1;
+ dis_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch - 1;
+ dis_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1;
+ dis_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch +
+ vm->vactive - 1;
+
+ clk_disable_unprepare(dcss->pout_clk);
+ clk_disable_unprepare(dcss->pdiv_clk);
+ clk_set_rate(dcss->pdiv_clk, vm->pixelclock);
+ clk_prepare_enable(dcss->pdiv_clk);
+ clk_prepare_enable(dcss->pout_clk);
+
+ msleep(50);
+
+ dcss_dtg_write(dtg, ((dtg_lrc_y << TC_Y_POS) | dtg_lrc_x),
+ DCSS_DTG_TC_DTG);
+ dcss_dtg_write(dtg, ((dis_ulc_y << TC_Y_POS) | dis_ulc_x),
+ DCSS_DTG_TC_DISP_TOP);
+ dcss_dtg_write(dtg, ((dis_lrc_y << TC_Y_POS) | dis_lrc_x),
+ DCSS_DTG_TC_DISP_BOT);
+
+ dtg->dis_ulc_x = dis_ulc_x;
+ dtg->dis_ulc_y = dis_ulc_y;
+
+ sb_ctxld_trig = ((0 * dis_lrc_y / 100) << TC_CTXLD_SB_Y_POS) &
+ TC_CTXLD_SB_Y_MASK;
+ db_ctxld_trig = ((99 * dis_lrc_y / 100) << TC_CTXLD_DB_Y_POS) &
+ TC_CTXLD_DB_Y_MASK;
+
+ dcss_dtg_write(dtg, sb_ctxld_trig | db_ctxld_trig, DCSS_DTG_TC_CTXLD);
+
+ /* vblank trigger */
+ dcss_dtg_write(dtg, 0, DCSS_DTG_LINE0_INT);
+
+ /* CTXLD trigger */
+ dcss_dtg_write(dtg, ((98 * dis_lrc_y) / 100) << 16, DCSS_DTG_LINE1_INT);
+}
+EXPORT_SYMBOL(dcss_dtg_sync_set);
+
+void dcss_dtg_plane_pos_set(struct dcss_soc *dcss, int ch_num,
+ int px, int py, int pw, int ph)
+{
+ struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+ u16 p_ulc_x, p_ulc_y;
+ u16 p_lrc_x, p_lrc_y;
+
+ p_ulc_x = dtg->dis_ulc_x + px;
+ p_ulc_y = dtg->dis_ulc_y + py;
+ p_lrc_x = p_ulc_x + pw;
+ p_lrc_y = p_ulc_y + ph;
+
+ if (!px && !py && !pw && !ph) {
+ dcss_dtg_write(dtg, 0, DCSS_DTG_TC_CH1_TOP + 0x8 * ch_num);
+ dcss_dtg_write(dtg, 0, DCSS_DTG_TC_CH1_BOT + 0x8 * ch_num);
+ } else {
+ dcss_dtg_write(dtg, ((p_ulc_y << TC_Y_POS) | p_ulc_x),
+ DCSS_DTG_TC_CH1_TOP + 0x8 * ch_num);
+ dcss_dtg_write(dtg, ((p_lrc_y << TC_Y_POS) | p_lrc_x),
+ DCSS_DTG_TC_CH1_BOT + 0x8 * ch_num);
+ }
+}
+EXPORT_SYMBOL(dcss_dtg_plane_pos_set);
+
+static bool dcss_dtg_global_alpha_needed(u32 pix_format)
+{
+ return pix_format == DRM_FORMAT_XRGB8888 ||
+ pix_format == DRM_FORMAT_XBGR8888 ||
+ pix_format == DRM_FORMAT_RGBX8888 ||
+ pix_format == DRM_FORMAT_BGRX8888 ||
+ pix_format == DRM_FORMAT_XRGB2101010 ||
+ pix_format == DRM_FORMAT_XBGR2101010 ||
+ pix_format == DRM_FORMAT_RGBX1010102 ||
+ pix_format == DRM_FORMAT_BGRX1010102 ||
+ pix_format == DRM_FORMAT_UYVY ||
+ pix_format == DRM_FORMAT_VYUY ||
+ pix_format == DRM_FORMAT_YUYV ||
+ pix_format == DRM_FORMAT_YVYU ||
+ pix_format == DRM_FORMAT_NV12 ||
+ pix_format == DRM_FORMAT_NV21 ||
+ pix_format == DRM_FORMAT_P010;
+}
+
+bool dcss_dtg_global_alpha_changed(struct dcss_soc *dcss, int ch_num,
+ u32 pix_format, int alpha,
+ int use_global_alpha)
+{
+ struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+
+ if (ch_num)
+ return false;
+
+ return alpha != dtg->alpha || use_global_alpha != dtg->use_global;
+}
+EXPORT_SYMBOL(dcss_dtg_global_alpha_changed);
+
+void dcss_dtg_plane_alpha_set(struct dcss_soc *dcss, int ch_num,
+ u32 pix_format, int alpha, bool use_global_alpha)
+{
+ struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+ u32 alpha_val;
+
+ /* we care about alpha only when channel 0 is concerned */
+ if (ch_num)
+ return;
+
+ alpha_val = (alpha << DEFAULT_FG_ALPHA_POS) & DEFAULT_FG_ALPHA_MASK;
+
+ /*
+ * Use global alpha if pixel format does not have alpha channel or the
+ * user explicitly chose to use global alpha.
+ */
+ if (dcss_dtg_global_alpha_needed(pix_format) || use_global_alpha) {
+ dtg->control_status &= ~(CH1_ALPHA_SEL | DEFAULT_FG_ALPHA_MASK);
+ dtg->control_status |= alpha_val;
+ } else {
+ dtg->control_status |= CH1_ALPHA_SEL;
+ }
+
+ dtg->alpha = alpha;
+ dtg->use_global = use_global_alpha;
+}
+EXPORT_SYMBOL(dcss_dtg_plane_alpha_set);
+
+void dcss_dtg_css_set(struct dcss_soc *dcss, u32 pix_format)
+{
+ struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+
+ if (pix_format == DRM_FORMAT_P010) {
+ dtg->control_status &= ~CSS_PIX_COMP_SWAP_MASK;
+ return;
+ }
+
+ dtg->control_status |=
+ (0x5 << CSS_PIX_COMP_SWAP_POS) & CSS_PIX_COMP_SWAP_MASK;
+}
+EXPORT_SYMBOL(dcss_dtg_css_set);
+
+static void dcss_dtg_disable_callback(void *data)
+{
+ struct dcss_dtg_priv *dtg = data;
+
+ dtg->control_status &= ~DTG_START;
+
+ dcss_writel(dtg->control_status,
+ dtg->base_reg + DCSS_DTG_TC_CONTROL_STATUS);
+
+ dtg->in_use = false;
+
+ complete(dtg->dis_completion);
+}
+
+void dcss_dtg_enable(struct dcss_soc *dcss, bool en,
+ struct completion *dis_completion)
+{
+ struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+
+ if (!en) {
+ dcss->dcss_disable_callback = dcss_dtg_disable_callback;
+ dtg->dis_completion = dis_completion;
+ return;
+ }
+
+ dcss->dcss_disable_callback = NULL;
+ dtg->dis_completion = NULL;
+
+ dtg->control_status |= DTG_START;
+
+ dcss_dtg_write(dtg, dtg->control_status, DCSS_DTG_TC_CONTROL_STATUS);
+
+ dtg->in_use = true;
+}
+EXPORT_SYMBOL(dcss_dtg_enable);
+
+bool dcss_dtg_is_enabled(struct dcss_soc *dcss)
+{
+ return dcss->dtg_priv->in_use;
+}
+EXPORT_SYMBOL(dcss_dtg_is_enabled);
+
+void dcss_dtg_ch_enable(struct dcss_soc *dcss, int ch_num, bool en)
+{
+ struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+ u32 ch_en_map[] = {CH1_EN, CH2_EN, CH3_EN};
+ u32 control_status;
+
+ control_status = dtg->control_status & ~ch_en_map[ch_num];
+ control_status |= en ? ch_en_map[ch_num] : 0;
+
+ if (dtg->control_status != control_status)
+ dcss_dtg_write(dtg, control_status, DCSS_DTG_TC_CONTROL_STATUS);
+
+ dtg->control_status = control_status;
+}
+EXPORT_SYMBOL(dcss_dtg_ch_enable);
+
+void dcss_dtg_vblank_irq_enable(struct dcss_soc *dcss, bool en)
+{
+ void __iomem *reg;
+ struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+ u32 val = en ? (LINE0_IRQ | LINE1_IRQ) : 0;
+
+ /* need to keep the CTXLD kick interrupt ON if DTRC is used */
+ if (!en && (dcss_dtrc_is_running(dcss, 1) ||
+ dcss_dtrc_is_running(dcss, 2)))
+ val |= LINE1_IRQ;
+
+ reg = dtg->base_reg + DCSS_DTG_INT_MASK;
+
+ dcss_update(val, LINE0_IRQ | LINE1_IRQ, reg);
+
+ dcss_dpr_irq_enable(dcss, en);
+}
+
+void dcss_dtg_vblank_irq_clear(struct dcss_soc *dcss)
+{
+ void __iomem *reg;
+ struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+
+ reg = dtg->base_reg + DCSS_DTG_INT_CONTROL;
+
+ dcss_update(LINE0_IRQ, LINE0_IRQ, reg);
+}
diff --git a/drivers/gpu/imx/dcss/dcss-dtrc.c b/drivers/gpu/imx/dcss/dcss-dtrc.c
new file mode 100644
index 000000000000..5ce145388d6b
--- /dev/null
+++ b/drivers/gpu/imx/dcss/dcss-dtrc.c
@@ -0,0 +1,612 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <drm/drm_fourcc.h>
+#include <linux/delay.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+
+#define USE_CTXLD
+
+#define DTRC_F0_OFS 0x00
+#define DTRC_F1_OFS 0x60
+
+#define DCSS_DTRC_DYDSADDR 0x00
+#define DCSS_DTRC_DCDSADDR 0x04
+#define DCSS_DTRC_DYTSADDR 0x08
+#define DCSS_DTRC_DCTSADDR 0x0C
+#define DCSS_DTRC_SIZE 0x10
+#define FRAME_WIDTH_POS 0
+#define FRAME_WIDTH_MASK GENMASK(9, 0)
+#define FRAME_HEIGHT_POS 16
+#define FRAME_HEIGHT_MASK GENMASK(25, 16)
+#define DCSS_DTRC_SYSSA 0x14
+#define DCSS_DTRC_SYSEA 0x18
+#define DCSS_DTRC_SUVSSA 0x1C
+#define DCSS_DTRC_SUVSEA 0x20
+#define DCSS_DTRC_CROPORIG 0x24
+#define DCSS_DTRC_CROPSIZE 0x28
+#define CROP_HEIGHT_POS 16
+#define CROP_HEIGHT_MASK GENMASK(28, 16)
+#define CROP_WIDTH_POS 0
+#define CROP_WIDTH_MASK GENMASK(12, 0)
+#define DCSS_DTRC_DCTL 0x2C
+#define CROPPING_EN BIT(18)
+#define COMPRESSION_DIS BIT(17)
+#define PIX_DEPTH_8BIT_EN BIT(1)
+#define CONFIG_READY BIT(0)
+#define DCSS_DTRC_DYDSADDR_EXT 0x30
+#define DCSS_DTRC_DCDSADDR_EXT 0x34
+#define DCSS_DTRC_DYTSADDR_EXT 0x38
+#define DCSS_DTRC_DCTSADDR_EXT 0x3C
+#define DCSS_DTRC_SYSSA_EXT 0x40
+#define DCSS_DTRC_SYSEA_EXT 0x44
+#define DCSS_DTRC_SUVSSA_EXT 0x48
+#define DCSS_DTRC_SUVSEA_EXT 0x4C
+
+#define DCSS_DTRC_INTEN 0xC0
+#define DCSS_DTRC_FDINTR 0xC4
+#define DCSS_DTRC_DTCTRL 0xC8
+#define CURRENT_FRAME BIT(31)
+#define ADDRESS_ID_ENABLE BIT(30)
+#define ENDIANNESS_10BIT BIT(29)
+#define MERGE_ARID_ENABLE BIT(28)
+#define NON_G1_2_SWAP_MODE_POS 24
+#define NON_G1_2_SWAP_MODE_MASK GENMASK(27, 24)
+#define TABLE_DATA_SWAP_POS 20
+#define TABLE_DATA_SWAP_MASK GENMASK(23, 20)
+#define TILED_SWAP_POS 16
+#define TILED_SWAP_MASK GENMASK(19, 16)
+#define RASTER_SWAP_POS 12
+#define RASTER_SWAP_MASK GENMASK(15, 12)
+#define BURST_LENGTH_POS 4
+#define BURST_LENGTH_MASK GENMASK(11, 4)
+#define G1_TILED_DATA_EN BIT(3)
+#define HOT_RESET BIT(2)
+#define ARIDR_MODE_DETILE 0
+#define ARIDR_MODE_BYPASS 2
+#define DCSS_DTRC_ARIDR 0xCC
+#define DCSS_DTRC_DTID2DDR 0xD0
+#define DCSS_DTRC_CONFIG 0xD4
+#define DCSS_DTRC_VER 0xD8
+#define DCSS_DTRC_PFCTRL 0xF0
+#define DCSS_DTRC_PFCR 0xF4
+#define DCSS_DTRC_TOCR 0xF8
+
+#define TRACE_IRQ (1LL << 48)
+#define TRACE_SWITCH_BANKS (2LL << 48)
+
+struct dcss_dtrc_ch {
+ void __iomem *base_reg;
+ u32 base_ofs;
+
+ u32 xres;
+ u32 yres;
+ u32 pix_format;
+ u64 format_modifier;
+ u32 y_dec_ofs;
+ u32 uv_dec_ofs;
+
+ int curr_frame;
+
+ u32 dctl;
+
+ u32 ctx_id;
+
+ bool bypass;
+ bool running;
+
+ int irq;
+ int ch_num;
+};
+
+struct dcss_dtrc_priv {
+ struct dcss_soc *dcss;
+ void __iomem *dtrc_reg;
+
+ struct dcss_dtrc_ch ch[2];
+};
+
+#ifdef CONFIG_DEBUG_FS
+static struct dcss_debug_reg dtrc_frame_debug_reg[] = {
+ DCSS_DBG_REG(DCSS_DTRC_DYDSADDR),
+ DCSS_DBG_REG(DCSS_DTRC_DCDSADDR),
+ DCSS_DBG_REG(DCSS_DTRC_DYTSADDR),
+ DCSS_DBG_REG(DCSS_DTRC_DCTSADDR),
+ DCSS_DBG_REG(DCSS_DTRC_SIZE),
+ DCSS_DBG_REG(DCSS_DTRC_SYSSA),
+ DCSS_DBG_REG(DCSS_DTRC_SYSEA),
+ DCSS_DBG_REG(DCSS_DTRC_SUVSSA),
+ DCSS_DBG_REG(DCSS_DTRC_SUVSEA),
+ DCSS_DBG_REG(DCSS_DTRC_CROPORIG),
+ DCSS_DBG_REG(DCSS_DTRC_CROPSIZE),
+ DCSS_DBG_REG(DCSS_DTRC_DCTL),
+ DCSS_DBG_REG(DCSS_DTRC_DYDSADDR_EXT),
+ DCSS_DBG_REG(DCSS_DTRC_DCDSADDR_EXT),
+ DCSS_DBG_REG(DCSS_DTRC_DYTSADDR_EXT),
+ DCSS_DBG_REG(DCSS_DTRC_DCTSADDR_EXT),
+ DCSS_DBG_REG(DCSS_DTRC_SYSSA_EXT),
+ DCSS_DBG_REG(DCSS_DTRC_SYSEA_EXT),
+ DCSS_DBG_REG(DCSS_DTRC_SUVSSA_EXT),
+ DCSS_DBG_REG(DCSS_DTRC_SUVSEA_EXT),
+};
+
+static struct dcss_debug_reg dtrc_ctrl_debug_reg[] = {
+ DCSS_DBG_REG(DCSS_DTRC_INTEN),
+ DCSS_DBG_REG(DCSS_DTRC_FDINTR),
+ DCSS_DBG_REG(DCSS_DTRC_DTCTRL),
+ DCSS_DBG_REG(DCSS_DTRC_ARIDR),
+ DCSS_DBG_REG(DCSS_DTRC_DTID2DDR),
+ DCSS_DBG_REG(DCSS_DTRC_CONFIG),
+ DCSS_DBG_REG(DCSS_DTRC_VER),
+ DCSS_DBG_REG(DCSS_DTRC_PFCTRL),
+ DCSS_DBG_REG(DCSS_DTRC_PFCR),
+ DCSS_DBG_REG(DCSS_DTRC_TOCR),
+};
+
+static void dcss_dtrc_dump_frame_regs(struct seq_file *s, void *data,
+ int ch, int frame)
+{
+ struct dcss_soc *dcss = data;
+ int i;
+
+ seq_printf(s, "\t>> Dumping F%d regs:\n", frame);
+ for (i = 0; i < ARRAY_SIZE(dtrc_frame_debug_reg); i++)
+ seq_printf(s, "\t%-35s(0x%04x) -> 0x%08x\n",
+ dtrc_frame_debug_reg[i].name,
+ dtrc_frame_debug_reg[i].ofs + frame * DTRC_F1_OFS,
+ dcss_readl(dcss->dtrc_priv->ch[ch].base_reg +
+ dtrc_frame_debug_reg[i].ofs +
+ frame * DTRC_F1_OFS));
+}
+
+void dcss_dtrc_dump_regs(struct seq_file *s, void *data)
+{
+ struct dcss_soc *dcss = data;
+ int ch, fr, i;
+
+ for (ch = 0; ch < 2; ch++) {
+ seq_printf(s, ">> Dumping DTRC for CH %d:\n", ch + 1);
+ for (fr = 0; fr < 2; fr++)
+ dcss_dtrc_dump_frame_regs(s, data, ch, fr);
+
+ seq_printf(s, "\t>> Dumping DTRC CTRL regs for CH %d:\n",
+ ch + 1);
+ for (i = 0; i < ARRAY_SIZE(dtrc_ctrl_debug_reg); i++)
+ seq_printf(s, "\t%-35s(0x%04x) -> 0x%08x\n",
+ dtrc_ctrl_debug_reg[i].name,
+ dtrc_ctrl_debug_reg[i].ofs,
+ dcss_readl(dcss->dtrc_priv->ch[ch].base_reg +
+ dtrc_ctrl_debug_reg[i].ofs));
+ }
+}
+#endif
+
+static irqreturn_t dcss_dtrc_irq_handler(int irq, void *data)
+{
+ struct dcss_dtrc_ch *ch = data;
+ u32 b0, b1, curr_bank;
+
+ b0 = dcss_readl(ch->base_reg + DCSS_DTRC_DCTL) & 0x1;
+ b1 = dcss_readl(ch->base_reg + DTRC_F1_OFS + DCSS_DTRC_DCTL) & 0x1;
+ curr_bank = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
+
+ dcss_trace_module(TRACE_DTRC, TRACE_IRQ | (ch->ch_num + 1) << 3 |
+ curr_bank << 2 | b0 << 0 | b1 << 1);
+
+ dcss_update(1, 1, ch->base_reg + DCSS_DTRC_FDINTR);
+
+ return IRQ_HANDLED;
+}
+
+static int dcss_dtrc_irq_config(struct dcss_soc *dcss, int ch_num)
+{
+ struct platform_device *pdev = to_platform_device(dcss->dev);
+ struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+ struct dcss_dtrc_ch *ch = &dtrc->ch[ch_num];
+ char irq_name[20];
+ int ret;
+
+ sprintf(irq_name, "dtrc_ch%d", ch_num + 1);
+ irq_name[8] = 0;
+
+ ch->irq = platform_get_irq_byname(pdev, irq_name);
+ if (ch->irq < 0) {
+ dev_err(dcss->dev, "dtrc: can't get DTRC irq\n");
+ return ch->irq;
+ }
+
+ ret = devm_request_irq(dcss->dev, ch->irq,
+ dcss_dtrc_irq_handler,
+ IRQF_TRIGGER_HIGH,
+ "dcss-dtrc", ch);
+ if (ret) {
+ dev_err(dcss->dev, "dtrc: irq request failed.\n");
+ return ret;
+ }
+
+ dcss_writel(1, ch->base_reg + DCSS_DTRC_INTEN);
+
+ return 0;
+}
+
+static int dcss_dtrc_ch_init_all(struct dcss_soc *dcss, unsigned long dtrc_base)
+{
+ struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+ struct dcss_dtrc_ch *ch;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ ch = &dtrc->ch[i];
+
+ ch->base_ofs = dtrc_base + i * 0x1000;
+
+ ch->base_reg = devm_ioremap(dcss->dev, ch->base_ofs, SZ_4K);
+ if (!ch->base_reg) {
+ dev_err(dcss->dev, "dtrc: unable to remap ch base\n");
+ return -ENOMEM;
+ }
+
+ ch->ch_num = i;
+
+ dcss_dtrc_irq_config(dcss, i);
+
+#if defined(USE_CTXLD)
+ ch->ctx_id = CTX_SB_HP;
+#endif
+ }
+
+ return 0;
+}
+
+static void dcss_dtrc_write(struct dcss_dtrc_priv *dtrc, int ch_num,
+ u32 val, u32 ofs)
+{
+#if !defined(USE_CTXLD)
+ dcss_writel(val, dtrc->ch[ch_num].base_reg + ofs);
+#else
+ dcss_ctxld_write(dtrc->dcss, dtrc->ch[ch_num].ctx_id,
+ val, dtrc->ch[ch_num].base_ofs + ofs);
+#endif
+}
+
+static void dcss_dtrc_write_irqsafe(struct dcss_dtrc_priv *dtrc, int ch_num,
+ u32 val, u32 ofs)
+{
+#if !defined(USE_CTXLD)
+ dcss_writel(val, dtrc->ch[ch_num].base_reg + ofs);
+#else
+ dcss_ctxld_write_irqsafe(dtrc->dcss, dtrc->ch[ch_num].ctx_id,
+ val, dtrc->ch[ch_num].base_ofs + ofs);
+#endif
+}
+
+int dcss_dtrc_init(struct dcss_soc *dcss, unsigned long dtrc_base)
+{
+ struct dcss_dtrc_priv *dtrc;
+
+ dtrc = devm_kzalloc(dcss->dev, sizeof(*dtrc), GFP_KERNEL);
+ if (!dtrc)
+ return -ENOMEM;
+
+ dcss->dtrc_priv = dtrc;
+ dtrc->dcss = dcss;
+
+ return dcss_dtrc_ch_init_all(dcss, dtrc_base);
+}
+
+void dcss_dtrc_exit(struct dcss_soc *dcss)
+{
+ struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+
+ /* reset the module to default */
+ dcss_writel(HOT_RESET, dtrc->dtrc_reg + DCSS_DTRC_DTCTRL);
+}
+
+void dcss_dtrc_bypass(struct dcss_soc *dcss, int ch_num)
+{
+ struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+
+ if (ch_num == 0)
+ return;
+
+ ch_num -= 1;
+
+ if (dtrc->ch[ch_num].bypass)
+ return;
+
+ dcss_dtrc_write(dtrc, ch_num, ARIDR_MODE_BYPASS, DCSS_DTRC_DTCTRL);
+ dcss_dtrc_write(dtrc, ch_num, 0, DCSS_DTRC_DYTSADDR);
+ dcss_dtrc_write(dtrc, ch_num, 0, DCSS_DTRC_DCTSADDR);
+ dcss_dtrc_write(dtrc, ch_num, 0x0f0e0100, DCSS_DTRC_ARIDR);
+ dcss_dtrc_write(dtrc, ch_num, 0x0f0e, DCSS_DTRC_DTID2DDR);
+
+ dtrc->ch[ch_num].bypass = true;
+}
+EXPORT_SYMBOL(dcss_dtrc_bypass);
+
+void dcss_dtrc_addr_set(struct dcss_soc *dcss, int ch_num, u32 p1_ba, u32 p2_ba,
+ uint64_t dec_table_ofs)
+{
+ struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+ struct dcss_dtrc_ch *ch;
+
+ if (ch_num == 0)
+ return;
+
+ ch_num -= 1;
+
+ ch = &dtrc->ch[ch_num];
+
+ dcss_dtrc_write(dtrc, ch_num, p1_ba, DCSS_DTRC_DYDSADDR);
+ dcss_dtrc_write(dtrc, ch_num, p2_ba, DCSS_DTRC_DCDSADDR);
+
+ dcss_dtrc_write(dtrc, ch_num, p1_ba, DTRC_F1_OFS + DCSS_DTRC_DYDSADDR);
+ dcss_dtrc_write(dtrc, ch_num, p2_ba, DTRC_F1_OFS + DCSS_DTRC_DCDSADDR);
+
+ if (ch->format_modifier == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED) {
+ ch->y_dec_ofs = dec_table_ofs & 0xFFFFFFFF;
+ ch->uv_dec_ofs = dec_table_ofs >> 32;
+
+ dcss_dtrc_write(dtrc, ch_num, p1_ba + ch->y_dec_ofs,
+ DCSS_DTRC_DYTSADDR);
+ dcss_dtrc_write(dtrc, ch_num, p1_ba + ch->uv_dec_ofs,
+ DCSS_DTRC_DCTSADDR);
+ dcss_dtrc_write(dtrc, ch_num, p1_ba + ch->y_dec_ofs,
+ DTRC_F1_OFS + DCSS_DTRC_DYTSADDR);
+ dcss_dtrc_write(dtrc, ch_num, p1_ba + ch->uv_dec_ofs,
+ DTRC_F1_OFS + DCSS_DTRC_DCTSADDR);
+ }
+
+ dtrc->ch[ch_num].bypass = false;
+}
+EXPORT_SYMBOL(dcss_dtrc_addr_set);
+
+void dcss_dtrc_set_res(struct dcss_soc *dcss, int ch_num, struct drm_rect *src,
+ struct drm_rect *old_src, u32 pixel_format)
+{
+ struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+ struct dcss_dtrc_ch *ch;
+ u32 frame_height, frame_width;
+ u32 crop_w, crop_h, crop_orig_w, crop_orig_h;
+ int bank;
+ u32 old_xres, old_yres, xres, yres;
+ u32 pix_depth;
+ u16 width_align = 0;
+
+ if (ch_num == 0)
+ return;
+
+ ch_num -= 1;
+
+ ch = &dtrc->ch[ch_num];
+
+ bank = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
+
+ ch->pix_format = pixel_format;
+
+ pix_depth = ch->pix_format == DRM_FORMAT_P010 ? 10 : 8;
+ old_xres = old_src->x2 - old_src->x1;
+ old_yres = old_src->y2 - old_src->y1;
+ xres = src->x2 - src->x1;
+ yres = src->y2 - src->y1;
+
+ frame_height = ((old_yres >> 3) << FRAME_HEIGHT_POS) & FRAME_HEIGHT_MASK;
+ frame_width = ((old_xres >> 3) << FRAME_WIDTH_POS) & FRAME_WIDTH_MASK;
+
+ dcss_dtrc_write(dcss->dtrc_priv, ch_num, frame_height | frame_width,
+ DTRC_F1_OFS * bank + DCSS_DTRC_SIZE);
+
+ dcss_dtrc_write(dcss->dtrc_priv, ch_num, frame_height | frame_width,
+ DTRC_F1_OFS * (bank ^ 1) + DCSS_DTRC_SIZE);
+
+ /*
+ * Image original size is aligned:
+ * - 128 pixels for width (8-bit) or 256 (10-bit);
+ * - 8 lines for height;
+ */
+ width_align = ch->pix_format == DRM_FORMAT_P010 ? 0xff : 0x7f;
+ if (xres == old_xres && !(xres & width_align) &&
+ yres == old_yres && !(yres & 0xf)) {
+ ch->dctl &= ~CROPPING_EN;
+ goto exit;
+ }
+
+ /* align the image size: down align for compressed formats */
+ if (ch->format_modifier == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED && src->x1)
+ xres = xres & ~width_align;
+ else
+ xres = (xres - 1 + width_align) & ~width_align;
+
+ if (ch->format_modifier == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED && src->y1)
+ yres = yres & ~0xf;
+ else
+ yres = (yres - 1 + 0xf) & ~0xf;
+
+ src->x1 &= ~1;
+ src->x2 &= ~1;
+
+ crop_orig_w = (src->x1 << CROP_WIDTH_POS) & CROP_WIDTH_MASK;
+ crop_orig_h = (src->y1 << CROP_HEIGHT_POS) & CROP_HEIGHT_MASK;
+
+ dcss_dtrc_write(dcss->dtrc_priv, ch_num, crop_orig_w | crop_orig_h,
+ DCSS_DTRC_CROPORIG);
+ dcss_dtrc_write(dcss->dtrc_priv, ch_num, crop_orig_w | crop_orig_h,
+ DTRC_F1_OFS + DCSS_DTRC_CROPORIG);
+
+ crop_w = (xres << CROP_WIDTH_POS) & CROP_WIDTH_MASK;
+ crop_h = (yres << CROP_HEIGHT_POS) & CROP_HEIGHT_MASK;
+
+ dcss_dtrc_write(dcss->dtrc_priv, ch_num, crop_w | crop_h,
+ DTRC_F1_OFS * bank + DCSS_DTRC_CROPSIZE);
+ dcss_dtrc_write(dcss->dtrc_priv, ch_num, crop_w | crop_h,
+ DTRC_F1_OFS * (bank ^ 1) + DCSS_DTRC_CROPSIZE);
+
+ ch->dctl |= CROPPING_EN;
+
+exit:
+ dcss_dtrc_write(dtrc, ch_num, xres * yres * pix_depth / 8,
+ DCSS_DTRC_SYSEA);
+ dcss_dtrc_write(dtrc, ch_num, xres * yres * pix_depth / 8,
+ DTRC_F1_OFS + DCSS_DTRC_SYSEA);
+
+ dcss_dtrc_write(dtrc, ch_num, 0x10000000 + xres * yres * pix_depth / 8 / 2,
+ DCSS_DTRC_SUVSEA);
+ dcss_dtrc_write(dtrc, ch_num, 0x10000000 + xres * yres * pix_depth / 8 / 2,
+ DTRC_F1_OFS + DCSS_DTRC_SUVSEA);
+
+ src->x2 = src->x1 + xres;
+ src->y2 = src->y1 + yres;
+
+ if (ch->running)
+ return;
+
+ dcss_dtrc_write(dtrc, ch_num, 0x0, DCSS_DTRC_SYSSA);
+ dcss_dtrc_write(dtrc, ch_num, 0x0,
+ DTRC_F1_OFS + DCSS_DTRC_SYSSA);
+
+ dcss_dtrc_write(dtrc, ch_num, 0x10000000, DCSS_DTRC_SUVSSA);
+ dcss_dtrc_write(dtrc, ch_num, 0x10000000,
+ DTRC_F1_OFS + DCSS_DTRC_SUVSSA);
+}
+EXPORT_SYMBOL(dcss_dtrc_set_res);
+
+void dcss_dtrc_enable(struct dcss_soc *dcss, int ch_num, bool enable)
+{
+ struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+ struct dcss_dtrc_ch *ch;
+ int curr_frame;
+ u32 fdctl, dtctrl;
+
+ if (ch_num == 0)
+ return;
+
+ ch_num -= 1;
+
+ ch = &dtrc->ch[ch_num];
+
+ if (ch->bypass)
+ return;
+
+ if (!enable) {
+ ch->running = false;
+ return;
+ }
+
+ if (ch->running)
+ return;
+
+ dcss_update(HOT_RESET, HOT_RESET, ch->base_reg + DCSS_DTRC_DTCTRL);
+ while (dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) & HOT_RESET)
+ usleep_range(100, 200);
+
+ dcss_dtrc_write(dcss->dtrc_priv, ch_num, 0x0f0e0100,
+ DCSS_DTRC_ARIDR);
+ dcss_dtrc_write(dcss->dtrc_priv, ch_num, 0x0f0e,
+ DCSS_DTRC_DTID2DDR);
+
+ dtctrl = ADDRESS_ID_ENABLE | MERGE_ARID_ENABLE |
+ ((0xF << TABLE_DATA_SWAP_POS) & TABLE_DATA_SWAP_MASK) |
+ ((0x10 << BURST_LENGTH_POS) & BURST_LENGTH_MASK);
+
+ if (ch->format_modifier == DRM_FORMAT_MOD_VSI_G1_TILED)
+ dtctrl |= G1_TILED_DATA_EN;
+
+ dcss_dtrc_write(dtrc, ch_num, dtctrl, DCSS_DTRC_DTCTRL);
+
+ curr_frame = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
+
+ fdctl = ch->dctl & ~(PIX_DEPTH_8BIT_EN | COMPRESSION_DIS);
+
+ fdctl |= ch->pix_format == DRM_FORMAT_P010 ? 0 : PIX_DEPTH_8BIT_EN;
+
+ if (ch->format_modifier != DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED)
+ fdctl |= COMPRESSION_DIS;
+
+ dcss_dtrc_write(dtrc, ch_num, fdctl,
+ (curr_frame ^ 1) * DTRC_F1_OFS + DCSS_DTRC_DCTL);
+ dcss_dtrc_write(dtrc, ch_num, fdctl | (enable ? CONFIG_READY : 0),
+ curr_frame * DTRC_F1_OFS + DCSS_DTRC_DCTL);
+
+ ch->curr_frame = curr_frame;
+ ch->dctl = fdctl;
+ ch->running = true;
+}
+EXPORT_SYMBOL(dcss_dtrc_enable);
+
+bool dcss_dtrc_is_running(struct dcss_soc *dcss, int ch_num)
+{
+ struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+ struct dcss_dtrc_ch *ch;
+
+ if (!ch_num)
+ return false;
+
+ ch_num -= 1;
+
+ ch = &dtrc->ch[ch_num];
+
+ return ch->running;
+}
+
+void dcss_dtrc_set_format_mod(struct dcss_soc *dcss, int ch_num, u64 modifier)
+{
+ struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+ struct dcss_dtrc_ch *ch;
+
+ if (!ch_num)
+ return;
+
+ ch_num -= 1;
+
+ ch = &dtrc->ch[ch_num];
+
+ ch->format_modifier = modifier;
+}
+EXPORT_SYMBOL(dcss_dtrc_set_format_mod);
+
+static void dcss_dtrc_ch_switch_banks(struct dcss_dtrc_priv *dtrc, int dtrc_ch)
+{
+ struct dcss_dtrc_ch *ch = &dtrc->ch[dtrc_ch];
+ u32 b0, b1;
+
+ if (!ch->running)
+ return;
+
+ b0 = dcss_readl(ch->base_reg + DCSS_DTRC_DCTL) & 0x1;
+ b1 = dcss_readl(ch->base_reg + DTRC_F1_OFS + DCSS_DTRC_DCTL) & 0x1;
+
+ ch->curr_frame = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
+
+ dcss_trace_module(TRACE_DTRC, TRACE_SWITCH_BANKS |
+ (dtrc_ch + 1) << 3 | ch->curr_frame << 2 |
+ b0 << 0 | b1 << 1);
+
+ dcss_dtrc_write_irqsafe(dtrc, dtrc_ch, ch->dctl | CONFIG_READY,
+ (ch->curr_frame ^ 1) * DTRC_F1_OFS + DCSS_DTRC_DCTL);
+}
+
+void dcss_dtrc_switch_banks(struct dcss_soc *dcss)
+{
+ struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+
+ dcss_dtrc_ch_switch_banks(dtrc, 0);
+ dcss_dtrc_ch_switch_banks(dtrc, 1);
+}
diff --git a/drivers/gpu/imx/dcss/dcss-hdr10-tables.h b/drivers/gpu/imx/dcss/dcss-hdr10-tables.h
new file mode 100644
index 000000000000..ee1820895a55
--- /dev/null
+++ b/drivers/gpu/imx/dcss/dcss-hdr10-tables.h
@@ -0,0 +1,1680 @@
+/*
+ * Copyright (C) 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#ifndef __DCSS_HDR10_TABLES_H__
+#define __DCSS_HDR10_TABLES_H__
+
+/*
+ * Table descriptor (64 bit) contains flags with identify to which
+ * input/output configurations' combinations the table is applied. Choosing the
+ * right CSC depends on both output/input pipe configuration.
+ *
+ * Bit 0-2: Table type
+ * * LUT - bit 0
+ * * CSCA - bit 1 (CSC for output pipe)
+ * * CSCB - bit 2 (not used for output pipe)
+ * Bit 3: Pipe type
+ * * Input - unset
+ * * Output - set
+ * Bit 4-5: Input pipe bits-per-component
+ * * 8 bpc - bit 4
+ * * 10 bpc - bit 5
+ * Bit 6-7: Input pipe colorspace
+ * * RGB - bit 6
+ * * YUV - bit 7
+ * Bit 8-12: Input pipe nonlinearity
+ * * REC2084 - bit 8
+ * * REC709 - bit 9
+ * * BT1886 - bit 10
+ * * REC2100HLG - bit 11
+ * * SRGB - bit 12
+ * Bit 13-14: Input pipe pixel range
+ * * Limited - bit 13
+ * * Full - bit 14
+ * Bit 15-19: Input pipe gamut
+ * * REC2020 - bit 15
+ * * REC709 - bit 16
+ * * REC601_NTSC - bit 17
+ * * REC601_PAL - bit 18
+ * * ADOBE_RGB - bit 19
+ * Bit 20-21: Output pipe bits-per-component (see above)
+ * Bit 22-23: Output pipe colorspace (see above)
+ * Bit 24-28: Output pipe nonlinearity (see above)
+ * Bit 29-30: Ouptut pipe pixel range (see above)
+ * Bit 31-35: Output pipe gamut (see above)
+ */
+
+static u32 dcss_hdr10_tables[] = {
+ /* table descriptor */
+ 0xe1ffffe9, 0xf,
+ /* table length */
+ 0x400,
+ /* table data */
+ 0x2c59, 0x2416, 0x3322, 0x1dd0, 0x287e, 0x2ff0, 0x3679, 0x188b, 0x2131,
+ 0x2661, 0x2a78, 0x2e2b, 0x3186, 0x34c8, 0x3836, 0x141d, 0x1b81, 0x1fa3,
+ 0x22a3, 0x2531, 0x277a, 0x2988, 0x2b6b, 0x2d33, 0x2eed, 0x30a3, 0x325a,
+ 0x3416, 0x35b5, 0x374e, 0x38f8, 0xff8, 0x1698, 0x1a32, 0x1ca3, 0x1eab,
+ 0x206e, 0x2210, 0x2355, 0x2497, 0x25e9, 0x26e2, 0x2816, 0x28f9, 0x2a17,
+ 0x2ae8, 0x2c01, 0x2cbe, 0x2dbb, 0x2e85, 0x2f65, 0x3047, 0x310d, 0x3209,
+ 0x32b7, 0x339e, 0x3469, 0x3536, 0x3624, 0x36db, 0x37d2, 0x388f, 0x3971,
+ 0xbe0, 0x124a, 0x1572, 0x17b5, 0x1962, 0x1acc, 0x1c29, 0x1d30, 0x1e43,
+ 0x1f20, 0x201b, 0x20ca, 0x21a2, 0x2256, 0x22f8, 0x23bc, 0x2454, 0x24e1,
+ 0x2589, 0x2629, 0x269f, 0x272b, 0x27d0, 0x2848, 0x28b9, 0x293d, 0x29d8,
+ 0x2a45, 0x2aae, 0x2b27, 0x2bb4, 0x2c2b, 0x2c89, 0x2cf6, 0x2d74, 0x2e03,
+ 0x2e57, 0x2eb8, 0x2f27, 0x2fa8, 0x301e, 0x3073, 0x30d6, 0x3147, 0x31ca,
+ 0x3230, 0x3287, 0x32eb, 0x335e, 0x33e3, 0x343e, 0x3497, 0x34fd, 0x3573,
+ 0x35fc, 0x364d, 0x36a8, 0x3712, 0x378d, 0x380e, 0x3861, 0x38c1, 0x3932,
+ 0x39b5, 0x700, 0xe30, 0x1120, 0x132c, 0x14bb, 0x1621, 0x171f, 0x182e,
+ 0x18f2, 0x19de, 0x1a7c, 0x1b23, 0x1be6, 0x1c64, 0x1ce7, 0x1d7d, 0x1e14,
+ 0x1e75, 0x1ee3, 0x1f60, 0x1feb, 0x2043, 0x209b, 0x20fc, 0x2168, 0x21e0,
+ 0x2232, 0x227b, 0x22cc, 0x2325, 0x2387, 0x23f3, 0x2434, 0x2475, 0x24bb,
+ 0x2508, 0x255d, 0x25b8, 0x260e, 0x2644, 0x2680, 0x26c0, 0x2706, 0x2752,
+ 0x27a4, 0x27fd, 0x282f, 0x2863, 0x289b, 0x28d8, 0x291a, 0x2962, 0x29af,
+ 0x2a01, 0x2a2e, 0x2a5e, 0x2a92, 0x2aca, 0x2b07, 0x2b48, 0x2b8f, 0x2bda,
+ 0x2c16, 0x2c41, 0x2c70, 0x2ca3, 0x2cda, 0x2d14, 0x2d53, 0x2d97, 0x2de0,
+ 0x2e17, 0x2e41, 0x2e6e, 0x2e9e, 0x2ed2, 0x2f0a, 0x2f46, 0x2f86, 0x2fcb,
+ 0x300a, 0x3032, 0x305d, 0x308b, 0x30bc, 0x30f1, 0x3129, 0x3166, 0x31a8,
+ 0x31ee, 0x321c, 0x3245, 0x3270, 0x329f, 0x32d1, 0x3306, 0x3340, 0x337e,
+ 0x33c0, 0x3404, 0x342a, 0x3453, 0x347f, 0x34af, 0x34e2, 0x3519, 0x3554,
+ 0x3593, 0x35d8, 0x3610, 0x3638, 0x3662, 0x3690, 0x36c1, 0x36f6, 0x372f,
+ 0x376d, 0x37af, 0x37f7, 0x3821, 0x384b, 0x3878, 0x38a8, 0x38dc, 0x3914,
+ 0x3951, 0x3992, 0x39d9, 0x200, 0xa20, 0xd00, 0xf00, 0x1084, 0x11d0,
+ 0x12b6, 0x13ae, 0x1469, 0x1513, 0x15d7, 0x165b, 0x16da, 0x1768, 0x1803,
+ 0x185b, 0x18bd, 0x1929, 0x199f, 0x1a10, 0x1a56, 0x1aa3, 0x1af6, 0x1b51,
+ 0x1bb2, 0x1c0e, 0x1c46, 0x1c83, 0x1cc5, 0x1d0b, 0x1d56, 0x1da6, 0x1dfc,
+ 0x1e2b, 0x1e5c, 0x1e90, 0x1ec7, 0x1f01, 0x1f3f, 0x1f81, 0x1fc7, 0x2008,
+ 0x202f, 0x2058, 0x2084, 0x20b2, 0x20e3, 0x2116, 0x214c, 0x2185, 0x21c1,
+ 0x2200, 0x2221, 0x2244, 0x2268, 0x228f, 0x22b7, 0x22e2, 0x230e, 0x233d,
+ 0x236e, 0x23a1, 0x23d7, 0x2407, 0x2425, 0x2444, 0x2464, 0x2486, 0x24a9,
+ 0x24ce, 0x24f4, 0x251d, 0x2547, 0x2573, 0x25a1, 0x25d1, 0x2601, 0x261b,
+ 0x2636, 0x2653, 0x2670, 0x268f, 0x26af, 0x26d1, 0x26f4, 0x2718, 0x273e,
+ 0x2766, 0x278f, 0x27b9, 0x27e6, 0x280a, 0x2822, 0x283b, 0x2855, 0x2870,
+ 0x288d, 0x28aa, 0x28c9, 0x28e8, 0x2909, 0x292c, 0x294f, 0x2975, 0x299b,
+ 0x29c3, 0x29ed, 0x2a0c, 0x2a22, 0x2a39, 0x2a52, 0x2a6b, 0x2a85, 0x2aa0,
+ 0x2abc, 0x2ad9, 0x2af7, 0x2b17, 0x2b38, 0x2b59, 0x2b7d, 0x2ba1, 0x2bc7,
+ 0x2bee, 0x2c0b, 0x2c20, 0x2c36, 0x2c4d, 0x2c64, 0x2c7d, 0x2c96, 0x2cb0,
+ 0x2ccc, 0x2ce8, 0x2d05, 0x2d24, 0x2d43, 0x2d64, 0x2d85, 0x2da9, 0x2dcd,
+ 0x2df3, 0x2e0d, 0x2e21, 0x2e36, 0x2e4c, 0x2e62, 0x2e79, 0x2e92, 0x2eab,
+ 0x2ec5, 0x2ee0, 0x2efb, 0x2f18, 0x2f36, 0x2f55, 0x2f76, 0x2f97, 0x2fb9,
+ 0x2fdd, 0x3001, 0x3014, 0x3028, 0x303d, 0x3052, 0x3068, 0x307f, 0x3097,
+ 0x30af, 0x30c9, 0x30e3, 0x30ff, 0x311b, 0x3138, 0x3157, 0x3176, 0x3197,
+ 0x31b9, 0x31dc, 0x3200, 0x3213, 0x3226, 0x323a, 0x324f, 0x3265, 0x327b,
+ 0x3293, 0x32ab, 0x32c4, 0x32de, 0x32f8, 0x3314, 0x3331, 0x334f, 0x336e,
+ 0x338e, 0x33af, 0x33d2, 0x33f5, 0x340d, 0x3420, 0x3434, 0x3448, 0x345e,
+ 0x3474, 0x348b, 0x34a3, 0x34bb, 0x34d5, 0x34ef, 0x350b, 0x3527, 0x3545,
+ 0x3563, 0x3583, 0x35a4, 0x35c6, 0x35ea, 0x3607, 0x361a, 0x362e, 0x3642,
+ 0x3657, 0x366d, 0x3684, 0x369c, 0x36b5, 0x36ce, 0x36e9, 0x3704, 0x3721,
+ 0x373e, 0x375d, 0x377d, 0x379e, 0x37c1, 0x37e4, 0x3804, 0x3818, 0x382c,
+ 0x3840, 0x3856, 0x386c, 0x3883, 0x389b, 0x38b5, 0x38cf, 0x38ea, 0x3906,
+ 0x3923, 0x3941, 0x3961, 0x3981, 0x39a3, 0x39c7, 0x39ec, 0x0, 0x500,
+ 0x8c0, 0xae0, 0xc70, 0xdb0, 0xe98, 0xf78, 0x103c, 0x10d0, 0x1178,
+ 0x1218, 0x127e, 0x12f0, 0x136c, 0x13f2, 0x1442, 0x1491, 0x14e6, 0x1542,
+ 0x15a4, 0x1606, 0x163e, 0x1679, 0x16b9, 0x16fc, 0x1743, 0x178e, 0x17dd,
+ 0x1818, 0x1844, 0x1873, 0x18a4, 0x18d7, 0x190d, 0x1945, 0x1980, 0x19be,
+ 0x19ff, 0x1a21, 0x1a44, 0x1a69, 0x1a8f, 0x1ab7, 0x1ae1, 0x1b0c, 0x1b39,
+ 0x1b68, 0x1b99, 0x1bcc, 0x1c00, 0x1c1b, 0x1c38, 0x1c55, 0x1c74, 0x1c93,
+ 0x1cb4, 0x1cd6, 0x1cf9, 0x1d1d, 0x1d42, 0x1d69, 0x1d91, 0x1dbb, 0x1de6,
+ 0x1e09, 0x1e20, 0x1e37, 0x1e4f, 0x1e69, 0x1e82, 0x1e9d, 0x1eb9, 0x1ed5,
+ 0x1ef2, 0x1f10, 0x1f2f, 0x1f4f, 0x1f70, 0x1f92, 0x1fb5, 0x1fd9, 0x1ffe,
+ 0x2012, 0x2025, 0x2039, 0x204e, 0x2063, 0x2079, 0x208f, 0x20a6, 0x20be,
+ 0x20d6, 0x20ef, 0x2109, 0x2123, 0x213e, 0x215a, 0x2176, 0x2194, 0x21b2,
+ 0x21d0, 0x21f0, 0x2208, 0x2218, 0x2229, 0x223b, 0x224d, 0x225f, 0x2272,
+ 0x2285, 0x2299, 0x22ad, 0x22c2, 0x22d7, 0x22ed, 0x2303, 0x231a, 0x2331,
+ 0x2349, 0x2361, 0x237a, 0x2394, 0x23ae, 0x23c9, 0x23e5, 0x2400, 0x240f,
+ 0x241d, 0x242c, 0x243c, 0x244c, 0x245c, 0x246c, 0x247d, 0x248e, 0x24a0,
+ 0x24b2, 0x24c4, 0x24d7, 0x24eb, 0x24fe, 0x2512, 0x2527, 0x253c, 0x2552,
+ 0x2568, 0x257e, 0x2595, 0x25ac, 0x25c4, 0x25dd, 0x25f6, 0x2607, 0x2614,
+ 0x2622, 0x262f, 0x263d, 0x264c, 0x265a, 0x2669, 0x2678, 0x2687, 0x2697,
+ 0x26a7, 0x26b8, 0x26c8, 0x26d9, 0x26eb, 0x26fd, 0x270f, 0x2722, 0x2734,
+ 0x2748, 0x275c, 0x2770, 0x2784, 0x2799, 0x27af, 0x27c4, 0x27db, 0x27f1,
+ 0x2804, 0x2810, 0x281c, 0x2828, 0x2835, 0x2842, 0x284f, 0x285c, 0x286a,
+ 0x2877, 0x2886, 0x2894, 0x28a3, 0x28b2, 0x28c1, 0x28d0, 0x28e0, 0x28f1,
+ 0x2901, 0x2912, 0x2923, 0x2935, 0x2946, 0x2959, 0x296b, 0x297e, 0x2991,
+ 0x29a5, 0x29b9, 0x29cd, 0x29e2, 0x29f7, 0x2a06, 0x2a11, 0x2a1c, 0x2a28,
+ 0x2a33, 0x2a3f, 0x2a4b, 0x2a58, 0x2a64, 0x2a71, 0x2a7e, 0x2a8b, 0x2a99,
+ 0x2aa7, 0x2ab5, 0x2ac3, 0x2ad2, 0x2ae1, 0x2af0, 0x2aff, 0x2b0f, 0x2b1f,
+ 0x2b2f, 0x2b40, 0x2b51, 0x2b62, 0x2b74, 0x2b86, 0x2b98, 0x2baa, 0x2bbd,
+ 0x2bd0, 0x2be4, 0x2bf8, 0x2c06, 0x2c10, 0x2c1b, 0x2c26, 0x2c31, 0x2c3c,
+ 0x2c47, 0x2c53, 0x2c5e, 0x2c6a, 0x2c77, 0x2c83, 0x2c90, 0x2c9d, 0x2caa,
+ 0x2cb7, 0x2cc5, 0x2cd3, 0x2ce1, 0x2cef, 0x2cfe, 0x2d0d, 0x2d1c, 0x2d2b,
+ 0x2d3b, 0x2d4b, 0x2d5b, 0x2d6c, 0x2d7d, 0x2d8e, 0x2da0, 0x2db2, 0x2dc4,
+ 0x2dd6, 0x2de9, 0x2dfc, 0x2e08, 0x2e12, 0x2e1c, 0x2e26, 0x2e30, 0x2e3b,
+ 0x2e46, 0x2e51, 0x2e5c, 0x2e68, 0x2e73, 0x2e7f, 0x2e8b, 0x2e98, 0x2ea4,
+ 0x2eb1, 0x2ebe, 0x2ecb, 0x2ed9, 0x2ee6, 0x2ef4, 0x2f03, 0x2f11, 0x2f20,
+ 0x2f2f, 0x2f3e, 0x2f4e, 0x2f5d, 0x2f6d, 0x2f7e, 0x2f8e, 0x2f9f, 0x2fb1,
+ 0x2fc2, 0x2fd4, 0x2fe6, 0x2ff9, 0x3006, 0x300f, 0x3019, 0x3023, 0x302d,
+ 0x3037, 0x3042, 0x304d, 0x3057, 0x3062, 0x306e, 0x3079, 0x3085, 0x3091,
+ 0x309d, 0x30a9, 0x30b6, 0x30c2, 0x30cf, 0x30dd, 0x30ea, 0x30f8, 0x3106,
+ 0x3114, 0x3122, 0x3131, 0x3140, 0x314f, 0x315e, 0x316e, 0x317e, 0x318f,
+ 0x319f, 0x31b0, 0x31c1, 0x31d3, 0x31e5, 0x31f7, 0x3204, 0x320e, 0x3217,
+ 0x3221, 0x322b, 0x3235, 0x323f, 0x324a, 0x3255, 0x325f, 0x326a, 0x3276,
+ 0x3281, 0x328d, 0x3299, 0x32a5, 0x32b1, 0x32bd, 0x32ca, 0x32d7, 0x32e4,
+ 0x32f2, 0x32ff, 0x330d, 0x331b, 0x332a, 0x3338, 0x3347, 0x3357, 0x3366,
+ 0x3376, 0x3386, 0x3396, 0x33a7, 0x33b8, 0x33c9, 0x33da, 0x33ec, 0x33fe,
+ 0x3408, 0x3412, 0x341b, 0x3425, 0x342f, 0x3439, 0x3443, 0x344e, 0x3458,
+ 0x3463, 0x346e, 0x347a, 0x3485, 0x3491, 0x349d, 0x34a9, 0x34b5, 0x34c2,
+ 0x34ce, 0x34db, 0x34e9, 0x34f6, 0x3504, 0x3512, 0x3520, 0x352f, 0x353d,
+ 0x354c, 0x355c, 0x356b, 0x357b, 0x358b, 0x359c, 0x35ad, 0x35be, 0x35cf,
+ 0x35e1, 0x35f3, 0x3602, 0x360c, 0x3615, 0x361f, 0x3629, 0x3633, 0x363d,
+ 0x3647, 0x3652, 0x365d, 0x3668, 0x3673, 0x367f, 0x368a, 0x3696, 0x36a2,
+ 0x36ae, 0x36bb, 0x36c8, 0x36d5, 0x36e2, 0x36f0, 0x36fd, 0x370b, 0x371a,
+ 0x3728, 0x3737, 0x3746, 0x3755, 0x3765, 0x3775, 0x3785, 0x3796, 0x37a7,
+ 0x37b8, 0x37c9, 0x37db, 0x37ed, 0x3800, 0x3809, 0x3813, 0x381d, 0x3826,
+ 0x3831, 0x383b, 0x3846, 0x3850, 0x385b, 0x3866, 0x3872, 0x387d, 0x3889,
+ 0x3895, 0x38a2, 0x38ae, 0x38bb, 0x38c8, 0x38d5, 0x38e3, 0x38f1, 0x38ff,
+ 0x390d, 0x391b, 0x392a, 0x3939, 0x3949, 0x3959, 0x3969, 0x3979, 0x398a,
+ 0x399b, 0x39ac, 0x39be, 0x39d0, 0x39e2, 0x39f5, 0xc,
+ /* table descriptor */
+ 0xe2ffffe9, 0xf,
+ /* table length */
+ 0x400,
+ /* table data */
+ 0x3612, 0x327c, 0x3840, 0x2fb2, 0x3475, 0x3728, 0x390e, 0x2d7f, 0x3134,
+ 0x3397, 0x353d, 0x3695, 0x37cb, 0x38a2, 0x3982, 0x2b71, 0x2ea4, 0x3079,
+ 0x3204, 0x3302, 0x341c, 0x34d5, 0x35ad, 0x3651, 0x36dc, 0x3778, 0x3811,
+ 0x3870, 0x38d7, 0x3946, 0x39bf, 0x2955, 0x2c9c, 0x2e31, 0x2f25, 0x3026,
+ 0x30d3, 0x319b, 0x323e, 0x32bd, 0x334b, 0x33e6, 0x3448, 0x34a4, 0x3508,
+ 0x3574, 0x35e7, 0x3631, 0x3672, 0x36b8, 0x3702, 0x374f, 0x37a1, 0x37f7,
+ 0x3828, 0x3857, 0x3889, 0x38bc, 0x38f2, 0x392a, 0x3964, 0x39a0, 0x39de,
+ 0x271c, 0x2a8e, 0x2c2a, 0x2d0e, 0x2df1, 0x2e69, 0x2ee3, 0x2f6a, 0x2ffe,
+ 0x304f, 0x30a5, 0x3102, 0x3166, 0x31d1, 0x3221, 0x325d, 0x329c, 0x32df,
+ 0x3326, 0x3370, 0x33be, 0x3407, 0x3432, 0x345e, 0x348c, 0x34bd, 0x34ef,
+ 0x3522, 0x3558, 0x3590, 0x35ca, 0x3602, 0x3621, 0x3641, 0x3662, 0x3683,
+ 0x36a6, 0x36ca, 0x36ef, 0x3715, 0x373b, 0x3763, 0x378c, 0x37b6, 0x37e1,
+ 0x3806, 0x381d, 0x3834, 0x384b, 0x3864, 0x387c, 0x3895, 0x38af, 0x38c9,
+ 0x38e4, 0x3900, 0x391c, 0x3938, 0x3955, 0x3973, 0x3991, 0x39af, 0x39cf,
+ 0x39ee, 0x24aa, 0x2871, 0x2a1c, 0x2aff, 0x2be3, 0x2c63, 0x2cd5, 0x2d47,
+ 0x2db8, 0x2e15, 0x2e4c, 0x2e86, 0x2ec4, 0x2f04, 0x2f47, 0x2f8e, 0x2fd8,
+ 0x3012, 0x303a, 0x3064, 0x308f, 0x30bc, 0x30eb, 0x311b, 0x314d, 0x3180,
+ 0x31b5, 0x31ec, 0x3212, 0x322f, 0x324d, 0x326c, 0x328c, 0x32ad, 0x32ce,
+ 0x32f1, 0x3314, 0x3338, 0x335d, 0x3383, 0x33aa, 0x33d2, 0x33fb, 0x3412,
+ 0x3427, 0x343d, 0x3453, 0x346a, 0x3481, 0x3498, 0x34b0, 0x34c9, 0x34e2,
+ 0x34fb, 0x3515, 0x3530, 0x354b, 0x3566, 0x3582, 0x359e, 0x35bb, 0x35d8,
+ 0x35f6, 0x360a, 0x3619, 0x3629, 0x3639, 0x3649, 0x3659, 0x366a, 0x367b,
+ 0x368c, 0x369d, 0x36af, 0x36c1, 0x36d3, 0x36e6, 0x36f8, 0x370b, 0x371e,
+ 0x3732, 0x3745, 0x3759, 0x376d, 0x3782, 0x3797, 0x37ac, 0x37c1, 0x37d6,
+ 0x37ec, 0x3801, 0x380c, 0x3817, 0x3823, 0x382e, 0x383a, 0x3846, 0x3851,
+ 0x385e, 0x386a, 0x3876, 0x3883, 0x388f, 0x389c, 0x38a9, 0x38b6, 0x38c3,
+ 0x38d0, 0x38de, 0x38eb, 0x38f9, 0x3907, 0x3915, 0x3923, 0x3931, 0x393f,
+ 0x394e, 0x395c, 0x396b, 0x397a, 0x3989, 0x3998, 0x39a8, 0x39b7, 0x39c7,
+ 0x39d6, 0x39e6, 0x39f6, 0x218e, 0x2638, 0x27ff, 0x28e3, 0x29c7, 0x2a55,
+ 0x2ac7, 0x2b38, 0x2baa, 0x2c0e, 0x2c47, 0x2c7f, 0x2cb8, 0x2cf1, 0x2d2a,
+ 0x2d63, 0x2d9c, 0x2dd5, 0x2e07, 0x2e23, 0x2e3f, 0x2e5a, 0x2e77, 0x2e95,
+ 0x2eb4, 0x2ed3, 0x2ef4, 0x2f14, 0x2f36, 0x2f59, 0x2f7c, 0x2fa0, 0x2fc5,
+ 0x2feb, 0x3008, 0x301c, 0x3030, 0x3044, 0x3059, 0x306e, 0x3084, 0x309a,
+ 0x30b1, 0x30c7, 0x30df, 0x30f6, 0x310f, 0x3127, 0x3140, 0x3159, 0x3173,
+ 0x318d, 0x31a8, 0x31c3, 0x31de, 0x31fa, 0x320b, 0x3219, 0x3228, 0x3237,
+ 0x3246, 0x3255, 0x3265, 0x3274, 0x3284, 0x3294, 0x32a5, 0x32b5, 0x32c6,
+ 0x32d7, 0x32e8, 0x32f9, 0x330b, 0x331d, 0x332f, 0x3341, 0x3354, 0x3367,
+ 0x337a, 0x338d, 0x33a0, 0x33b4, 0x33c8, 0x33dc, 0x33f0, 0x3402, 0x340d,
+ 0x3417, 0x3422, 0x342c, 0x3437, 0x3442, 0x344d, 0x3459, 0x3464, 0x346f,
+ 0x347b, 0x3487, 0x3492, 0x349e, 0x34aa, 0x34b6, 0x34c3, 0x34cf, 0x34dc,
+ 0x34e8, 0x34f5, 0x3502, 0x350f, 0x351c, 0x3529, 0x3536, 0x3544, 0x3551,
+ 0x355f, 0x356d, 0x357b, 0x3589, 0x3597, 0x35a5, 0x35b4, 0x35c2, 0x35d1,
+ 0x35e0, 0x35ef, 0x35fe, 0x3606, 0x360e, 0x3616, 0x361d, 0x3625, 0x362d,
+ 0x3635, 0x363d, 0x3645, 0x364d, 0x3655, 0x365e, 0x3666, 0x366e, 0x3677,
+ 0x367f, 0x3688, 0x3690, 0x3699, 0x36a2, 0x36ab, 0x36b4, 0x36bc, 0x36c5,
+ 0x36cf, 0x36d8, 0x36e1, 0x36ea, 0x36f3, 0x36fd, 0x3706, 0x3710, 0x3719,
+ 0x3723, 0x372d, 0x3737, 0x3740, 0x374a, 0x3754, 0x375e, 0x3768, 0x3772,
+ 0x377d, 0x3787, 0x3791, 0x379c, 0x37a6, 0x37b1, 0x37bb, 0x37c6, 0x37d1,
+ 0x37dc, 0x37e7, 0x37f1, 0x37fc, 0x3804, 0x3809, 0x380f, 0x3814, 0x381a,
+ 0x3820, 0x3825, 0x382b, 0x3831, 0x3837, 0x383d, 0x3843, 0x3848, 0x384e,
+ 0x3854, 0x385a, 0x3861, 0x3867, 0x386d, 0x3873, 0x3879, 0x387f, 0x3886,
+ 0x388c, 0x3892, 0x3899, 0x389f, 0x38a5, 0x38ac, 0x38b2, 0x38b9, 0x38c0,
+ 0x38c6, 0x38cd, 0x38d3, 0x38da, 0x38e1, 0x38e8, 0x38ee, 0x38f5, 0x38fc,
+ 0x3903, 0x390a, 0x3911, 0x3918, 0x391f, 0x3926, 0x392d, 0x3934, 0x393c,
+ 0x3943, 0x394a, 0x3951, 0x3959, 0x3960, 0x3967, 0x396f, 0x3976, 0x397e,
+ 0x3985, 0x398d, 0x3995, 0x399c, 0x39a4, 0x39ac, 0x39b3, 0x39bb, 0x39c3,
+ 0x39cb, 0x39d3, 0x39da, 0x39e2, 0x39ea, 0x39f2, 0x39fa, 0x0, 0x238e,
+ 0x258e, 0x26aa, 0x278e, 0x2838, 0x28aa, 0x291c, 0x298e, 0x29ff, 0x2a38,
+ 0x2a71, 0x2aaa, 0x2ae3, 0x2b1c, 0x2b55, 0x2b8e, 0x2bc7, 0x2bff, 0x2c1c,
+ 0x2c38, 0x2c55, 0x2c71, 0x2c8e, 0x2caa, 0x2cc7, 0x2ce3, 0x2cff, 0x2d1c,
+ 0x2d38, 0x2d55, 0x2d71, 0x2d8e, 0x2daa, 0x2dc7, 0x2de3, 0x2dff, 0x2e0e,
+ 0x2e1c, 0x2e2a, 0x2e38, 0x2e47, 0x2e53, 0x2e61, 0x2e70, 0x2e7f, 0x2e8e,
+ 0x2e9d, 0x2eac, 0x2ebc, 0x2ecb, 0x2edb, 0x2eeb, 0x2efc, 0x2f0c, 0x2f1d,
+ 0x2f2e, 0x2f3f, 0x2f50, 0x2f61, 0x2f73, 0x2f85, 0x2f97, 0x2fa9, 0x2fbc,
+ 0x2fce, 0x2fe1, 0x2ff4, 0x3003, 0x300d, 0x3017, 0x3021, 0x302b, 0x3035,
+ 0x303f, 0x304a, 0x3054, 0x305f, 0x3069, 0x3074, 0x307f, 0x308a, 0x3095,
+ 0x30a0, 0x30ab, 0x30b6, 0x30c2, 0x30cd, 0x30d9, 0x30e5, 0x30f1, 0x30fc,
+ 0x3109, 0x3115, 0x3121, 0x312d, 0x313a, 0x3146, 0x3153, 0x3160, 0x316d,
+ 0x317a, 0x3187, 0x3194, 0x31a1, 0x31af, 0x31bc, 0x31ca, 0x31d8, 0x31e5,
+ 0x31f3, 0x3200, 0x3208, 0x320f, 0x3216, 0x321d, 0x3224, 0x322c, 0x3233,
+ 0x323b, 0x3242, 0x324a, 0x3251, 0x3259, 0x3261, 0x3268, 0x3270, 0x3278,
+ 0x3280, 0x3288, 0x3290, 0x3298, 0x32a0, 0x32a9, 0x32b1, 0x32b9, 0x32c2,
+ 0x32ca, 0x32d3, 0x32db, 0x32e4, 0x32ec, 0x32f5, 0x32fe, 0x3307, 0x3310,
+ 0x3318, 0x3321, 0x332a, 0x3334, 0x333d, 0x3346, 0x334f, 0x3359, 0x3362,
+ 0x336b, 0x3375, 0x337e, 0x3388, 0x3392, 0x339b, 0x33a5, 0x33af, 0x33b9,
+ 0x33c3, 0x33cd, 0x33d7, 0x33e1, 0x33eb, 0x33f5, 0x3400, 0x3405, 0x340a,
+ 0x340f, 0x3414, 0x341a, 0x341f, 0x3424, 0x342a, 0x342f, 0x3435, 0x343a,
+ 0x3440, 0x3445, 0x344b, 0x3450, 0x3456, 0x345b, 0x3461, 0x3467, 0x346d,
+ 0x3472, 0x3478, 0x347e, 0x3484, 0x348a, 0x348f, 0x3495, 0x349b, 0x34a1,
+ 0x34a7, 0x34ad, 0x34b3, 0x34ba, 0x34c0, 0x34c6, 0x34cc, 0x34d2, 0x34d8,
+ 0x34df, 0x34e5, 0x34eb, 0x34f2, 0x34f8, 0x34ff, 0x3505, 0x350c, 0x3512,
+ 0x3519, 0x351f, 0x3526, 0x352c, 0x3533, 0x353a, 0x3540, 0x3547, 0x354e,
+ 0x3555, 0x355c, 0x3563, 0x3569, 0x3570, 0x3577, 0x357e, 0x3585, 0x358c,
+ 0x3594, 0x359b, 0x35a2, 0x35a9, 0x35b0, 0x35b7, 0x35bf, 0x35c6, 0x35cd,
+ 0x35d5, 0x35dc, 0x35e4, 0x35eb, 0x35f2, 0x35fa, 0x3600, 0x3604, 0x3608,
+ 0x360c, 0x3610, 0x3614, 0x3617, 0x361b, 0x361f, 0x3623, 0x3627, 0x362b,
+ 0x362f, 0x3633, 0x3637, 0x363b, 0x363f, 0x3643, 0x3647, 0x364b, 0x364f,
+ 0x3653, 0x3657, 0x365b, 0x3660, 0x3664, 0x3668, 0x366c, 0x3670, 0x3675,
+ 0x3679, 0x367d, 0x3681, 0x3686, 0x368a, 0x368e, 0x3693, 0x3697, 0x369b,
+ 0x36a0, 0x36a4, 0x36a8, 0x36ad, 0x36b1, 0x36b6, 0x36ba, 0x36bf, 0x36c3,
+ 0x36c8, 0x36cc, 0x36d1, 0x36d5, 0x36da, 0x36df, 0x36e3, 0x36e8, 0x36ec,
+ 0x36f1, 0x36f6, 0x36fb, 0x36ff, 0x3704, 0x3709, 0x370d, 0x3712, 0x3717,
+ 0x371c, 0x3721, 0x3725, 0x372a, 0x372f, 0x3734, 0x3739, 0x373e, 0x3743,
+ 0x3748, 0x374d, 0x3752, 0x3757, 0x375c, 0x3761, 0x3766, 0x376b, 0x3770,
+ 0x3775, 0x377a, 0x377f, 0x3784, 0x378a, 0x378f, 0x3794, 0x3799, 0x379e,
+ 0x37a4, 0x37a9, 0x37ae, 0x37b3, 0x37b9, 0x37be, 0x37c3, 0x37c9, 0x37ce,
+ 0x37d4, 0x37d9, 0x37de, 0x37e4, 0x37e9, 0x37ef, 0x37f4, 0x37fa, 0x37ff,
+ 0x3802, 0x3805, 0x3808, 0x380a, 0x380d, 0x3810, 0x3813, 0x3816, 0x3819,
+ 0x381b, 0x381e, 0x3821, 0x3824, 0x3827, 0x382a, 0x382d, 0x3830, 0x3832,
+ 0x3835, 0x3838, 0x383b, 0x383e, 0x3841, 0x3844, 0x3847, 0x384a, 0x384d,
+ 0x3850, 0x3853, 0x3856, 0x3859, 0x385c, 0x385f, 0x3862, 0x3865, 0x3868,
+ 0x386b, 0x386e, 0x3871, 0x3874, 0x3878, 0x387b, 0x387e, 0x3881, 0x3884,
+ 0x3887, 0x388a, 0x388e, 0x3891, 0x3894, 0x3897, 0x389a, 0x389d, 0x38a1,
+ 0x38a4, 0x38a7, 0x38aa, 0x38ae, 0x38b1, 0x38b4, 0x38b7, 0x38bb, 0x38be,
+ 0x38c1, 0x38c4, 0x38c8, 0x38cb, 0x38ce, 0x38d2, 0x38d5, 0x38d8, 0x38dc,
+ 0x38df, 0x38e3, 0x38e6, 0x38e9, 0x38ed, 0x38f0, 0x38f4, 0x38f7, 0x38fa,
+ 0x38fe, 0x3901, 0x3905, 0x3908, 0x390c, 0x390f, 0x3913, 0x3916, 0x391a,
+ 0x391d, 0x3921, 0x3924, 0x3928, 0x392b, 0x392f, 0x3933, 0x3936, 0x393a,
+ 0x393d, 0x3941, 0x3945, 0x3948, 0x394c, 0x3950, 0x3953, 0x3957, 0x395b,
+ 0x395e, 0x3962, 0x3966, 0x3969, 0x396d, 0x3971, 0x3974, 0x3978, 0x397c,
+ 0x3980, 0x3983, 0x3987, 0x398b, 0x398f, 0x3993, 0x3996, 0x399a, 0x399e,
+ 0x39a2, 0x39a6, 0x39aa, 0x39ad, 0x39b1, 0x39b5, 0x39b9, 0x39bd, 0x39c1,
+ 0x39c5, 0x39c9, 0x39cd, 0x39d1, 0x39d5, 0x39d8, 0x39dc, 0x39e0, 0x39e4,
+ 0x39e8, 0x39ec, 0x39f0, 0x39f4, 0x39f8, 0x39fc, 0xc,
+ /* table descriptor */
+ 0xe4ffffe9, 0xf,
+ /* table length */
+ 0x400,
+ /* table data */
+ 0x3505, 0x3047, 0x3800, 0x2b6c, 0x3306, 0x3695, 0x38e6, 0x268b, 0x2e47,
+ 0x31e6, 0x3431, 0x3601, 0x373f, 0x386d, 0x396c, 0x21b6, 0x2968, 0x2cef,
+ 0x2f4d, 0x3106, 0x3274, 0x33aa, 0x3496, 0x357e, 0x3648, 0x36e7, 0x379d,
+ 0x3835, 0x38a8, 0x3927, 0x39b3, 0x1c99, 0x2484, 0x2830, 0x2a7a, 0x2c46,
+ 0x2db1, 0x2ec3, 0x2fe6, 0x30a3, 0x3172, 0x3231, 0x32ba, 0x3356, 0x3402,
+ 0x3462, 0x34cc, 0x3540, 0x35bf, 0x3624, 0x366e, 0x36bd, 0x3712, 0x376d,
+ 0x37ce, 0x381a, 0x3850, 0x388a, 0x38c6, 0x3906, 0x3949, 0x398f, 0x39d9,
+ 0x1756, 0x1fa0, 0x2338, 0x25ac, 0x2763, 0x28c2, 0x2a11, 0x2aed, 0x2bf6,
+ 0x2c97, 0x2d4d, 0x2e0e, 0x2e83, 0x2f06, 0x2f98, 0x301c, 0x3074, 0x30d4,
+ 0x313b, 0x31ab, 0x3211, 0x3252, 0x3296, 0x32e0, 0x332d, 0x337f, 0x33d6,
+ 0x3419, 0x3449, 0x347c, 0x34b1, 0x34e8, 0x3522, 0x355f, 0x359e, 0x35e0,
+ 0x3612, 0x3636, 0x365b, 0x3681, 0x36a9, 0x36d2, 0x36fd, 0x3729, 0x3756,
+ 0x3785, 0x37b5, 0x37e7, 0x380d, 0x3827, 0x3842, 0x385e, 0x387b, 0x3899,
+ 0x38b7, 0x38d6, 0x38f6, 0x3916, 0x3938, 0x395a, 0x397d, 0x39a1, 0x39c6,
+ 0x39eb, 0x117c, 0x1a78, 0x1e4a, 0x20aa, 0x227b, 0x2408, 0x2510, 0x262c,
+ 0x26f3, 0x27dd, 0x2877, 0x2913, 0x29c3, 0x2a44, 0x2ab2, 0x2b2b, 0x2baf,
+ 0x2c1f, 0x2c6e, 0x2cc2, 0x2d1d, 0x2d7e, 0x2de6, 0x2e2a, 0x2e64, 0x2ea3,
+ 0x2ee4, 0x2f29, 0x2f72, 0x2fbf, 0x3007, 0x3031, 0x305d, 0x308b, 0x30bb,
+ 0x30ed, 0x3121, 0x3156, 0x318e, 0x31c8, 0x3202, 0x3221, 0x3241, 0x3263,
+ 0x3285, 0x32a8, 0x32cd, 0x32f3, 0x3319, 0x3341, 0x336a, 0x3395, 0x33c0,
+ 0x33ed, 0x340d, 0x3425, 0x343d, 0x3455, 0x346f, 0x3489, 0x34a3, 0x34be,
+ 0x34da, 0x34f7, 0x3514, 0x3531, 0x3550, 0x356f, 0x358e, 0x35af, 0x35d0,
+ 0x35f1, 0x3609, 0x361b, 0x362d, 0x363f, 0x3651, 0x3664, 0x3677, 0x368b,
+ 0x369f, 0x36b3, 0x36c8, 0x36dd, 0x36f2, 0x3707, 0x371d, 0x3734, 0x374a,
+ 0x3762, 0x3779, 0x3791, 0x37a9, 0x37c1, 0x37da, 0x37f4, 0x3806, 0x3813,
+ 0x3821, 0x382e, 0x383c, 0x3849, 0x3857, 0x3866, 0x3874, 0x3882, 0x3891,
+ 0x38a0, 0x38af, 0x38bf, 0x38ce, 0x38de, 0x38ee, 0x38fe, 0x390e, 0x391f,
+ 0x392f, 0x3940, 0x3951, 0x3963, 0x3974, 0x3986, 0x3998, 0x39aa, 0x39bd,
+ 0x39cf, 0x39e2, 0x39f5, 0x9c0, 0x14fa, 0x190d, 0x1bb0, 0x1d82, 0x1eea,
+ 0x2037, 0x2129, 0x2227, 0x22d6, 0x23a1, 0x2445, 0x24c8, 0x255c, 0x2600,
+ 0x265a, 0x26be, 0x272a, 0x279f, 0x280f, 0x2853, 0x289c, 0x28ea, 0x293d,
+ 0x2995, 0x29f3, 0x2a2a, 0x2a5f, 0x2a95, 0x2acf, 0x2b0b, 0x2b4b, 0x2b8d,
+ 0x2bd2, 0x2c0d, 0x2c32, 0x2c5a, 0x2c82, 0x2cac, 0x2cd8, 0x2d05, 0x2d34,
+ 0x2d65, 0x2d97, 0x2dcb, 0x2e00, 0x2e1c, 0x2e38, 0x2e55, 0x2e74, 0x2e93,
+ 0x2eb3, 0x2ed3, 0x2ef5, 0x2f18, 0x2f3b, 0x2f60, 0x2f85, 0x2fab, 0x2fd2,
+ 0x2ffa, 0x3012, 0x3027, 0x303c, 0x3052, 0x3068, 0x307f, 0x3097, 0x30af,
+ 0x30c7, 0x30e0, 0x30f9, 0x3113, 0x312e, 0x3149, 0x3164, 0x3180, 0x319d,
+ 0x31ba, 0x31d7, 0x31f5, 0x320a, 0x3219, 0x3229, 0x3239, 0x3249, 0x325a,
+ 0x326b, 0x327c, 0x328e, 0x329f, 0x32b1, 0x32c4, 0x32d6, 0x32e9, 0x32fc,
+ 0x3310, 0x3323, 0x3337, 0x334c, 0x3360, 0x3375, 0x338a, 0x339f, 0x33b5,
+ 0x33cb, 0x33e2, 0x33f8, 0x3407, 0x3413, 0x341f, 0x342b, 0x3437, 0x3443,
+ 0x344f, 0x345c, 0x3468, 0x3475, 0x3482, 0x348f, 0x349c, 0x34aa, 0x34b7,
+ 0x34c5, 0x34d3, 0x34e1, 0x34ef, 0x34fe, 0x350c, 0x351b, 0x352a, 0x3539,
+ 0x3548, 0x3557, 0x3567, 0x3576, 0x3586, 0x3596, 0x35a6, 0x35b7, 0x35c7,
+ 0x35d8, 0x35e9, 0x35fa, 0x3605, 0x360e, 0x3617, 0x361f, 0x3628, 0x3631,
+ 0x363a, 0x3643, 0x364d, 0x3656, 0x365f, 0x3669, 0x3673, 0x367c, 0x3686,
+ 0x3690, 0x369a, 0x36a4, 0x36ae, 0x36b8, 0x36c2, 0x36cd, 0x36d7, 0x36e2,
+ 0x36ec, 0x36f7, 0x3702, 0x370d, 0x3718, 0x3723, 0x372e, 0x3739, 0x3745,
+ 0x3750, 0x375c, 0x3767, 0x3773, 0x377f, 0x378b, 0x3797, 0x37a3, 0x37af,
+ 0x37bb, 0x37c8, 0x37d4, 0x37e1, 0x37ed, 0x37fa, 0x3803, 0x380a, 0x3810,
+ 0x3817, 0x381d, 0x3824, 0x382b, 0x3831, 0x3838, 0x383f, 0x3846, 0x384d,
+ 0x3854, 0x385b, 0x3862, 0x3869, 0x3870, 0x3877, 0x387f, 0x3886, 0x388d,
+ 0x3895, 0x389c, 0x38a4, 0x38ab, 0x38b3, 0x38bb, 0x38c2, 0x38ca, 0x38d2,
+ 0x38da, 0x38e2, 0x38ea, 0x38f2, 0x38fa, 0x3902, 0x390a, 0x3912, 0x391b,
+ 0x3923, 0x392b, 0x3934, 0x393c, 0x3945, 0x394d, 0x3956, 0x395e, 0x3967,
+ 0x3970, 0x3979, 0x3982, 0x398b, 0x3994, 0x399d, 0x39a6, 0x39af, 0x39b8,
+ 0x39c1, 0x39ca, 0x39d4, 0x39dd, 0x39e7, 0x39f0, 0x39fa, 0x0, 0xea0,
+ 0x137c, 0x164e, 0x184c, 0x19ee, 0x1b0b, 0x1c34, 0x1d09, 0x1e03, 0x1e97,
+ 0x1f42, 0x2002, 0x206e, 0x20e8, 0x216e, 0x2200, 0x2250, 0x22a8, 0x2306,
+ 0x236b, 0x23d8, 0x2426, 0x2464, 0x24a6, 0x24ec, 0x2536, 0x2583, 0x25d6,
+ 0x2616, 0x2643, 0x2672, 0x26a4, 0x26d8, 0x270e, 0x2746, 0x2781, 0x27be,
+ 0x27fd, 0x281f, 0x2841, 0x2865, 0x2889, 0x28af, 0x28d6, 0x28fe, 0x2928,
+ 0x2952, 0x297f, 0x29ac, 0x29db, 0x2a05, 0x2a1e, 0x2a37, 0x2a51, 0x2a6c,
+ 0x2a87, 0x2aa4, 0x2ac0, 0x2ade, 0x2afc, 0x2b1b, 0x2b3b, 0x2b5b, 0x2b7c,
+ 0x2b9e, 0x2bc1, 0x2be4, 0x2c04, 0x2c16, 0x2c29, 0x2c3c, 0x2c50, 0x2c64,
+ 0x2c78, 0x2c8d, 0x2ca2, 0x2cb7, 0x2ccd, 0x2ce3, 0x2cfa, 0x2d11, 0x2d29,
+ 0x2d40, 0x2d59, 0x2d71, 0x2d8b, 0x2da4, 0x2dbe, 0x2dd8, 0x2df3, 0x2e07,
+ 0x2e15, 0x2e23, 0x2e31, 0x2e3f, 0x2e4e, 0x2e5d, 0x2e6c, 0x2e7b, 0x2e8b,
+ 0x2e9b, 0x2eab, 0x2ebb, 0x2ecb, 0x2edc, 0x2eed, 0x2efe, 0x2f0f, 0x2f20,
+ 0x2f32, 0x2f44, 0x2f56, 0x2f69, 0x2f7c, 0x2f8e, 0x2fa2, 0x2fb5, 0x2fc8,
+ 0x2fdc, 0x2ff0, 0x3002, 0x300c, 0x3017, 0x3021, 0x302c, 0x3037, 0x3041,
+ 0x304c, 0x3058, 0x3063, 0x306e, 0x307a, 0x3085, 0x3091, 0x309d, 0x30a9,
+ 0x30b5, 0x30c1, 0x30cd, 0x30da, 0x30e6, 0x30f3, 0x3100, 0x310d, 0x311a,
+ 0x3127, 0x3134, 0x3142, 0x3150, 0x315d, 0x316b, 0x3179, 0x3187, 0x3195,
+ 0x31a4, 0x31b2, 0x31c1, 0x31d0, 0x31df, 0x31ee, 0x31fd, 0x3206, 0x320e,
+ 0x3215, 0x321d, 0x3225, 0x322d, 0x3235, 0x323d, 0x3245, 0x324e, 0x3256,
+ 0x325e, 0x3267, 0x326f, 0x3278, 0x3281, 0x3289, 0x3292, 0x329b, 0x32a4,
+ 0x32ad, 0x32b6, 0x32bf, 0x32c8, 0x32d2, 0x32db, 0x32e4, 0x32ee, 0x32f7,
+ 0x3301, 0x330b, 0x3314, 0x331e, 0x3328, 0x3332, 0x333c, 0x3346, 0x3351,
+ 0x335b, 0x3365, 0x3370, 0x337a, 0x3385, 0x338f, 0x339a, 0x33a5, 0x33b0,
+ 0x33bb, 0x33c6, 0x33d1, 0x33dc, 0x33e7, 0x33f2, 0x33fe, 0x3404, 0x340a,
+ 0x3410, 0x3416, 0x341c, 0x3422, 0x3428, 0x342e, 0x3434, 0x343a, 0x3440,
+ 0x3446, 0x344c, 0x3452, 0x3458, 0x345f, 0x3465, 0x346b, 0x3472, 0x3478,
+ 0x347f, 0x3485, 0x348c, 0x3492, 0x3499, 0x34a0, 0x34a6, 0x34ad, 0x34b4,
+ 0x34bb, 0x34c2, 0x34c9, 0x34d0, 0x34d7, 0x34de, 0x34e5, 0x34ec, 0x34f3,
+ 0x34fa, 0x3501, 0x3509, 0x3510, 0x3517, 0x351f, 0x3526, 0x352e, 0x3535,
+ 0x353d, 0x3544, 0x354c, 0x3553, 0x355b, 0x3563, 0x356b, 0x3573, 0x357a,
+ 0x3582, 0x358a, 0x3592, 0x359a, 0x35a2, 0x35aa, 0x35b3, 0x35bb, 0x35c3,
+ 0x35cb, 0x35d4, 0x35dc, 0x35e4, 0x35ed, 0x35f5, 0x35fe, 0x3603, 0x3607,
+ 0x360c, 0x3610, 0x3614, 0x3619, 0x361d, 0x3622, 0x3626, 0x362a, 0x362f,
+ 0x3634, 0x3638, 0x363d, 0x3641, 0x3646, 0x364a, 0x364f, 0x3654, 0x3658,
+ 0x365d, 0x3662, 0x3667, 0x366b, 0x3670, 0x3675, 0x367a, 0x367f, 0x3684,
+ 0x3688, 0x368d, 0x3692, 0x3697, 0x369c, 0x36a1, 0x36a6, 0x36ab, 0x36b0,
+ 0x36b6, 0x36bb, 0x36c0, 0x36c5, 0x36ca, 0x36cf, 0x36d5, 0x36da, 0x36df,
+ 0x36e4, 0x36ea, 0x36ef, 0x36f4, 0x36fa, 0x36ff, 0x3705, 0x370a, 0x3710,
+ 0x3715, 0x371b, 0x3720, 0x3726, 0x372b, 0x3731, 0x3737, 0x373c, 0x3742,
+ 0x3748, 0x374d, 0x3753, 0x3759, 0x375f, 0x3764, 0x376a, 0x3770, 0x3776,
+ 0x377c, 0x3782, 0x3788, 0x378e, 0x3794, 0x379a, 0x37a0, 0x37a6, 0x37ac,
+ 0x37b2, 0x37b8, 0x37be, 0x37c5, 0x37cb, 0x37d1, 0x37d7, 0x37de, 0x37e4,
+ 0x37ea, 0x37f1, 0x37f7, 0x37fd, 0x3802, 0x3805, 0x3808, 0x380b, 0x380f,
+ 0x3812, 0x3815, 0x3818, 0x381c, 0x381f, 0x3822, 0x3826, 0x3829, 0x382c,
+ 0x3830, 0x3833, 0x3837, 0x383a, 0x383d, 0x3841, 0x3844, 0x3848, 0x384b,
+ 0x384f, 0x3852, 0x3856, 0x3859, 0x385d, 0x3860, 0x3864, 0x3867, 0x386b,
+ 0x386e, 0x3872, 0x3876, 0x3879, 0x387d, 0x3881, 0x3884, 0x3888, 0x388c,
+ 0x388f, 0x3893, 0x3897, 0x389a, 0x389e, 0x38a2, 0x38a6, 0x38aa, 0x38ad,
+ 0x38b1, 0x38b5, 0x38b9, 0x38bd, 0x38c0, 0x38c4, 0x38c8, 0x38cc, 0x38d0,
+ 0x38d4, 0x38d8, 0x38dc, 0x38e0, 0x38e4, 0x38e8, 0x38ec, 0x38f0, 0x38f4,
+ 0x38f8, 0x38fc, 0x3900, 0x3904, 0x3908, 0x390c, 0x3910, 0x3914, 0x3918,
+ 0x391d, 0x3921, 0x3925, 0x3929, 0x392d, 0x3932, 0x3936, 0x393a, 0x393e,
+ 0x3942, 0x3947, 0x394b, 0x394f, 0x3954, 0x3958, 0x395c, 0x3961, 0x3965,
+ 0x3969, 0x396e, 0x3972, 0x3977, 0x397b, 0x397f, 0x3984, 0x3988, 0x398d,
+ 0x3991, 0x3996, 0x399a, 0x399f, 0x39a3, 0x39a8, 0x39ad, 0x39b1, 0x39b6,
+ 0x39ba, 0x39bf, 0x39c4, 0x39c8, 0x39cd, 0x39d1, 0x39d6, 0x39db, 0x39e0,
+ 0x39e4, 0x39e9, 0x39ee, 0x39f3, 0x39f7, 0x39fc, 0xc,
+ /* table descriptor */
+ 0xe8ffffe9, 0xf,
+ /* table length */
+ 0x400,
+ /* table data */
+ 0x32a8, 0x2ea6, 0x361d, 0x2aa0, 0x30fc, 0x344a, 0x3808, 0x2696, 0x2cf8,
+ 0x3012, 0x3208, 0x3374, 0x3517, 0x36eb, 0x38d8, 0x2281, 0x28f0, 0x2c0f,
+ 0x2e06, 0x2f5a, 0x3082, 0x3181, 0x3256, 0x3305, 0x33f8, 0x34a8, 0x359c,
+ 0x367b, 0x3771, 0x3867, 0x395e, 0x1e58, 0x24e1, 0x2808, 0x2a01, 0x2b54,
+ 0x2c7e, 0x2d7d, 0x2e53, 0x2efd, 0x2fbd, 0x3049, 0x30be, 0x313d, 0x31c8,
+ 0x322e, 0x327e, 0x32d5, 0x333a, 0x33b3, 0x3421, 0x3477, 0x34dd, 0x3557,
+ 0x35e8, 0x364a, 0x36b1, 0x372b, 0x37bd, 0x3835, 0x389d, 0x3918, 0x39ab,
+ 0x1a0b, 0x20c2, 0x23f6, 0x25f1, 0x2748, 0x2877, 0x2974, 0x2a4e, 0x2af8,
+ 0x2bb6, 0x2c45, 0x2cba, 0x2d39, 0x2dc3, 0x2e2c, 0x2e7c, 0x2ed1, 0x2f2b,
+ 0x2f8b, 0x2ff0, 0x302d, 0x3065, 0x309f, 0x30dd, 0x311d, 0x315f, 0x31a4,
+ 0x31ec, 0x321b, 0x3242, 0x326a, 0x3293, 0x32be, 0x32ec, 0x331f, 0x3356,
+ 0x3393, 0x33d5, 0x340e, 0x3435, 0x3460, 0x348f, 0x34c2, 0x34fa, 0x3536,
+ 0x3579, 0x35c1, 0x3608, 0x3633, 0x3662, 0x3695, 0x36cd, 0x370b, 0x374d,
+ 0x3796, 0x37e6, 0x381e, 0x384d, 0x3881, 0x38ba, 0x38f7, 0x393a, 0x3984,
+ 0x39d4, 0x1500, 0x1c85, 0x1fc3, 0x21cc, 0x2331, 0x2468, 0x2563, 0x2644,
+ 0x26ec, 0x27aa, 0x283e, 0x28b2, 0x2931, 0x29bb, 0x2a27, 0x2a76, 0x2acb,
+ 0x2b25, 0x2b85, 0x2bea, 0x2c2a, 0x2c61, 0x2c9c, 0x2cd9, 0x2d18, 0x2d5b,
+ 0x2da0, 0x2de8, 0x2e19, 0x2e3f, 0x2e67, 0x2e90, 0x2ebb, 0x2ee7, 0x2f14,
+ 0x2f43, 0x2f72, 0x2fa4, 0x2fd6, 0x3005, 0x301f, 0x303b, 0x3057, 0x3073,
+ 0x3091, 0x30ae, 0x30cd, 0x30ec, 0x310c, 0x312d, 0x314e, 0x3170, 0x3193,
+ 0x31b6, 0x31da, 0x31ff, 0x3212, 0x3225, 0x3238, 0x324c, 0x3260, 0x3274,
+ 0x3289, 0x329e, 0x32b3, 0x32c9, 0x32e0, 0x32f9, 0x3312, 0x332c, 0x3348,
+ 0x3365, 0x3383, 0x33a3, 0x33c4, 0x33e6, 0x3405, 0x3418, 0x342b, 0x3440,
+ 0x3455, 0x346b, 0x3483, 0x349b, 0x34b5, 0x34cf, 0x34eb, 0x3508, 0x3527,
+ 0x3546, 0x3568, 0x358a, 0x35ae, 0x35d4, 0x35fc, 0x3612, 0x3628, 0x363e,
+ 0x3656, 0x366e, 0x3688, 0x36a3, 0x36bf, 0x36dc, 0x36fb, 0x371b, 0x373c,
+ 0x375f, 0x3783, 0x37aa, 0x37d1, 0x37fb, 0x3813, 0x382a, 0x3841, 0x385a,
+ 0x3874, 0x388f, 0x38ab, 0x38c8, 0x38e7, 0x3907, 0x3929, 0x394c, 0x3971,
+ 0x3997, 0x39bf, 0x39e9, 0xea8, 0x1815, 0x1b60, 0x1d86, 0x1f03, 0x204c,
+ 0x2142, 0x2231, 0x22d6, 0x2391, 0x2430, 0x24a3, 0x2521, 0x25a9, 0x261e,
+ 0x266c, 0x26c0, 0x271a, 0x2779, 0x27dd, 0x2823, 0x285a, 0x2894, 0x28d1,
+ 0x2910, 0x2952, 0x2997, 0x29df, 0x2a14, 0x2a3a, 0x2a62, 0x2a8b, 0x2ab6,
+ 0x2ae1, 0x2b0e, 0x2b3d, 0x2b6c, 0x2b9d, 0x2bd0, 0x2c02, 0x2c1c, 0x2c37,
+ 0x2c53, 0x2c70, 0x2c8d, 0x2cab, 0x2cc9, 0x2ce8, 0x2d08, 0x2d29, 0x2d4a,
+ 0x2d6c, 0x2d8e, 0x2db2, 0x2dd5, 0x2dfa, 0x2e0f, 0x2e22, 0x2e36, 0x2e49,
+ 0x2e5d, 0x2e71, 0x2e86, 0x2e9b, 0x2eb0, 0x2ec6, 0x2edc, 0x2ef2, 0x2f09,
+ 0x2f20, 0x2f37, 0x2f4e, 0x2f66, 0x2f7f, 0x2f97, 0x2fb0, 0x2fc9, 0x2fe3,
+ 0x2ffd, 0x300b, 0x3019, 0x3026, 0x3034, 0x3042, 0x3050, 0x305e, 0x306c,
+ 0x307b, 0x3089, 0x3098, 0x30a7, 0x30b6, 0x30c5, 0x30d5, 0x30e4, 0x30f4,
+ 0x3104, 0x3114, 0x3125, 0x3135, 0x3146, 0x3157, 0x3168, 0x3179, 0x318a,
+ 0x319c, 0x31ad, 0x31bf, 0x31d1, 0x31e3, 0x31f5, 0x3204, 0x320d, 0x3216,
+ 0x3220, 0x3229, 0x3233, 0x323d, 0x3247, 0x3251, 0x325b, 0x3265, 0x326f,
+ 0x3279, 0x3283, 0x328e, 0x3298, 0x32a3, 0x32ae, 0x32b8, 0x32c4, 0x32cf,
+ 0x32da, 0x32e6, 0x32f2, 0x32ff, 0x330c, 0x3318, 0x3326, 0x3333, 0x3341,
+ 0x334f, 0x335e, 0x336c, 0x337c, 0x338b, 0x339b, 0x33ab, 0x33bb, 0x33cc,
+ 0x33dd, 0x33ef, 0x3400, 0x3409, 0x3413, 0x341c, 0x3426, 0x3430, 0x343a,
+ 0x3445, 0x3450, 0x345b, 0x3466, 0x3471, 0x347d, 0x3489, 0x3495, 0x34a2,
+ 0x34ae, 0x34bb, 0x34c9, 0x34d6, 0x34e4, 0x34f2, 0x3501, 0x3510, 0x351f,
+ 0x352f, 0x353e, 0x354f, 0x355f, 0x3570, 0x3581, 0x3593, 0x35a5, 0x35b8,
+ 0x35cb, 0x35de, 0x35f2, 0x3603, 0x360d, 0x3618, 0x3622, 0x362d, 0x3639,
+ 0x3644, 0x3650, 0x365c, 0x3668, 0x3675, 0x3682, 0x368f, 0x369c, 0x36aa,
+ 0x36b8, 0x36c6, 0x36d5, 0x36e4, 0x36f3, 0x3703, 0x3713, 0x3723, 0x3734,
+ 0x3745, 0x3756, 0x3768, 0x377a, 0x378d, 0x37a0, 0x37b3, 0x37c7, 0x37dc,
+ 0x37f0, 0x3802, 0x380d, 0x3818, 0x3824, 0x382f, 0x383b, 0x3847, 0x3854,
+ 0x3860, 0x386d, 0x387a, 0x3888, 0x3896, 0x38a4, 0x38b2, 0x38c1, 0x38d0,
+ 0x38df, 0x38ef, 0x38ff, 0x3910, 0x3920, 0x3932, 0x3943, 0x3955, 0x3967,
+ 0x397a, 0x398d, 0x39a1, 0x39b5, 0x39c9, 0x39de, 0x39f4, 0x0, 0x12aa,
+ 0x16ab, 0x1900, 0x1aab, 0x1c15, 0x1d00, 0x1e0b, 0x1eab, 0x1f60, 0x2015,
+ 0x2085, 0x2100, 0x2186, 0x220b, 0x2258, 0x22ab, 0x2303, 0x2360, 0x23c3,
+ 0x2415, 0x244c, 0x2485, 0x24c2, 0x2500, 0x2542, 0x2586, 0x25cc, 0x260b,
+ 0x2631, 0x2658, 0x2681, 0x26ab, 0x26d6, 0x2703, 0x2731, 0x2760, 0x2791,
+ 0x27c3, 0x27f6, 0x2815, 0x2830, 0x284c, 0x2868, 0x2885, 0x28a3, 0x28c2,
+ 0x28e1, 0x2900, 0x2921, 0x2942, 0x2963, 0x2986, 0x29a9, 0x29cc, 0x29f1,
+ 0x2a0b, 0x2a1e, 0x2a31, 0x2a44, 0x2a58, 0x2a6c, 0x2a81, 0x2a96, 0x2aab,
+ 0x2ac0, 0x2ad6, 0x2aec, 0x2b03, 0x2b1a, 0x2b31, 0x2b48, 0x2b60, 0x2b79,
+ 0x2b91, 0x2baa, 0x2bc3, 0x2bdd, 0x2bf6, 0x2c08, 0x2c15, 0x2c23, 0x2c30,
+ 0x2c3e, 0x2c4c, 0x2c5a, 0x2c68, 0x2c77, 0x2c85, 0x2c94, 0x2ca3, 0x2cb2,
+ 0x2cc2, 0x2cd1, 0x2ce1, 0x2cf0, 0x2d00, 0x2d10, 0x2d21, 0x2d31, 0x2d42,
+ 0x2d52, 0x2d63, 0x2d74, 0x2d86, 0x2d97, 0x2da9, 0x2dbb, 0x2dcc, 0x2ddf,
+ 0x2df1, 0x2e01, 0x2e0b, 0x2e14, 0x2e1e, 0x2e27, 0x2e31, 0x2e3a, 0x2e44,
+ 0x2e4e, 0x2e58, 0x2e62, 0x2e6c, 0x2e76, 0x2e81, 0x2e8b, 0x2e96, 0x2ea0,
+ 0x2eab, 0x2eb6, 0x2ec0, 0x2ecb, 0x2ed6, 0x2ee1, 0x2eec, 0x2ef8, 0x2f03,
+ 0x2f0e, 0x2f1a, 0x2f25, 0x2f31, 0x2f3d, 0x2f48, 0x2f54, 0x2f60, 0x2f6c,
+ 0x2f79, 0x2f85, 0x2f91, 0x2f9d, 0x2faa, 0x2fb6, 0x2fc3, 0x2fd0, 0x2fdd,
+ 0x2fea, 0x2ff6, 0x3002, 0x3008, 0x300f, 0x3015, 0x301c, 0x3023, 0x302a,
+ 0x3030, 0x3037, 0x303e, 0x3045, 0x304c, 0x3053, 0x305a, 0x3061, 0x3068,
+ 0x3070, 0x3077, 0x307e, 0x3085, 0x308d, 0x3094, 0x309c, 0x30a3, 0x30ab,
+ 0x30b2, 0x30ba, 0x30c2, 0x30c9, 0x30d1, 0x30d9, 0x30e1, 0x30e8, 0x30f0,
+ 0x30f8, 0x3100, 0x3108, 0x3110, 0x3118, 0x3121, 0x3129, 0x3131, 0x3139,
+ 0x3142, 0x314a, 0x3152, 0x315b, 0x3163, 0x316c, 0x3174, 0x317d, 0x3186,
+ 0x318e, 0x3197, 0x31a0, 0x31a9, 0x31b2, 0x31bb, 0x31c3, 0x31cc, 0x31d5,
+ 0x31df, 0x31e8, 0x31f1, 0x31fa, 0x3201, 0x3206, 0x320b, 0x320f, 0x3214,
+ 0x3219, 0x321e, 0x3222, 0x3227, 0x322c, 0x3231, 0x3236, 0x323a, 0x323f,
+ 0x3244, 0x3249, 0x324e, 0x3253, 0x3258, 0x325d, 0x3262, 0x3267, 0x326c,
+ 0x3271, 0x3276, 0x327c, 0x3281, 0x3286, 0x328b, 0x3290, 0x3296, 0x329b,
+ 0x32a0, 0x32a6, 0x32ab, 0x32b0, 0x32b6, 0x32bb, 0x32c1, 0x32c6, 0x32cc,
+ 0x32d2, 0x32d8, 0x32dd, 0x32e3, 0x32e9, 0x32ef, 0x32f6, 0x32fc, 0x3302,
+ 0x3308, 0x330f, 0x3315, 0x331c, 0x3322, 0x3329, 0x3330, 0x3337, 0x333e,
+ 0x3345, 0x334c, 0x3353, 0x335a, 0x3361, 0x3369, 0x3370, 0x3378, 0x337f,
+ 0x3387, 0x338f, 0x3397, 0x339f, 0x33a7, 0x33af, 0x33b7, 0x33bf, 0x33c8,
+ 0x33d0, 0x33d9, 0x33e2, 0x33eb, 0x33f3, 0x33fc, 0x3402, 0x3407, 0x340c,
+ 0x3410, 0x3415, 0x341a, 0x341f, 0x3424, 0x3429, 0x342e, 0x3433, 0x3438,
+ 0x343d, 0x3442, 0x3448, 0x344d, 0x3452, 0x3458, 0x345d, 0x3463, 0x3469,
+ 0x346e, 0x3474, 0x347a, 0x3480, 0x3486, 0x348c, 0x3492, 0x3498, 0x349e,
+ 0x34a5, 0x34ab, 0x34b2, 0x34b8, 0x34bf, 0x34c5, 0x34cc, 0x34d3, 0x34da,
+ 0x34e1, 0x34e8, 0x34ef, 0x34f6, 0x34fd, 0x3505, 0x350c, 0x3514, 0x351b,
+ 0x3523, 0x352b, 0x3532, 0x353a, 0x3542, 0x354b, 0x3553, 0x355b, 0x3563,
+ 0x356c, 0x3574, 0x357d, 0x3586, 0x358f, 0x3598, 0x35a1, 0x35aa, 0x35b3,
+ 0x35bc, 0x35c6, 0x35cf, 0x35d9, 0x35e3, 0x35ed, 0x35f7, 0x3600, 0x3605,
+ 0x360a, 0x3610, 0x3615, 0x361a, 0x3620, 0x3625, 0x362b, 0x3630, 0x3636,
+ 0x363b, 0x3641, 0x3647, 0x364d, 0x3653, 0x3659, 0x365f, 0x3665, 0x366b,
+ 0x3672, 0x3678, 0x367e, 0x3685, 0x368b, 0x3692, 0x3699, 0x36a0, 0x36a6,
+ 0x36ad, 0x36b4, 0x36bb, 0x36c3, 0x36ca, 0x36d1, 0x36d9, 0x36e0, 0x36e8,
+ 0x36ef, 0x36f7, 0x36ff, 0x3707, 0x370f, 0x3717, 0x371f, 0x3727, 0x372f,
+ 0x3738, 0x3740, 0x3749, 0x3752, 0x375b, 0x3764, 0x376d, 0x3776, 0x377f,
+ 0x3788, 0x3792, 0x379b, 0x37a5, 0x37ae, 0x37b8, 0x37c2, 0x37cc, 0x37d6,
+ 0x37e1, 0x37eb, 0x37f6, 0x3800, 0x3805, 0x380b, 0x3810, 0x3816, 0x381b,
+ 0x3821, 0x3827, 0x382c, 0x3832, 0x3838, 0x383e, 0x3844, 0x384a, 0x3851,
+ 0x3857, 0x385d, 0x3864, 0x386a, 0x3870, 0x3877, 0x387e, 0x3885, 0x388b,
+ 0x3892, 0x3899, 0x38a0, 0x38a7, 0x38af, 0x38b6, 0x38bd, 0x38c5, 0x38cc,
+ 0x38d4, 0x38dc, 0x38e3, 0x38eb, 0x38f3, 0x38fb, 0x3903, 0x390c, 0x3914,
+ 0x391c, 0x3925, 0x392d, 0x3936, 0x393f, 0x3948, 0x3951, 0x395a, 0x3963,
+ 0x396c, 0x3975, 0x397f, 0x3989, 0x3992, 0x399c, 0x39a6, 0x39b0, 0x39ba,
+ 0x39c4, 0x39cf, 0x39d9, 0x39e4, 0x39ee, 0x39f9, 0xc,
+ /* table descriptor */
+ 0xf0ffffe9, 0xf,
+ /* table length */
+ 0x400,
+ /* table data */
+ 0x356a, 0x313b, 0x3816, 0x2da0, 0x33b2, 0x36c8, 0x38f3, 0x2a96, 0x2fb9,
+ 0x3288, 0x348f, 0x3634, 0x376f, 0x387f, 0x3973, 0x2866, 0x2c4a, 0x2eab,
+ 0x307e, 0x320b, 0x3315, 0x3430, 0x34f8, 0x35e5, 0x367b, 0x3719, 0x37cb,
+ 0x3849, 0x38b8, 0x3932, 0x39b7, 0x2652, 0x29a9, 0x2b80, 0x2ce9, 0x2e37,
+ 0x2f2b, 0x3029, 0x30d9, 0x31a5, 0x3248, 0x32cc, 0x3361, 0x3403, 0x345e,
+ 0x34c2, 0x3530, 0x35a6, 0x3613, 0x3657, 0x36a1, 0x36f0, 0x3743, 0x379c,
+ 0x37fb, 0x382f, 0x3863, 0x389b, 0x38d5, 0x3912, 0x3952, 0x3995, 0x39da,
+ 0x242a, 0x278f, 0x2904, 0x2a30, 0x2b06, 0x2c02, 0x2c97, 0x2d42, 0x2e02,
+ 0x2e6f, 0x2ee9, 0x2f70, 0x3002, 0x3053, 0x30aa, 0x3109, 0x316f, 0x31dd,
+ 0x3229, 0x3267, 0x32aa, 0x32f0, 0x333a, 0x3389, 0x33dc, 0x3419, 0x3447,
+ 0x3477, 0x34a9, 0x34dd, 0x3513, 0x354c, 0x3587, 0x35c5, 0x3602, 0x3623,
+ 0x3646, 0x3669, 0x368e, 0x36b4, 0x36db, 0x3704, 0x372e, 0x3759, 0x3786,
+ 0x37b3, 0x37e3, 0x3809, 0x3822, 0x383c, 0x3856, 0x3871, 0x388d, 0x38a9,
+ 0x38c6, 0x38e4, 0x3902, 0x3922, 0x3942, 0x3962, 0x3984, 0x39a6, 0x39c9,
+ 0x39ec, 0x21b7, 0x2567, 0x26f0, 0x2816, 0x28b5, 0x2954, 0x2a01, 0x2a62,
+ 0x2acd, 0x2b41, 0x2bc1, 0x2c25, 0x2c6f, 0x2cbf, 0x2d15, 0x2d70, 0x2dd2,
+ 0x2e1c, 0x2e53, 0x2e8d, 0x2eca, 0x2f0a, 0x2f4d, 0x2f94, 0x2fde, 0x3015,
+ 0x303e, 0x3068, 0x3094, 0x30c1, 0x30f1, 0x3122, 0x3155, 0x318a, 0x31c1,
+ 0x31fa, 0x321a, 0x3238, 0x3257, 0x3277, 0x3299, 0x32bb, 0x32de, 0x3302,
+ 0x3327, 0x334e, 0x3375, 0x339d, 0x33c7, 0x33f1, 0x340e, 0x3424, 0x343b,
+ 0x3452, 0x346a, 0x3483, 0x349c, 0x34b5, 0x34d0, 0x34ea, 0x3506, 0x3521,
+ 0x353e, 0x355b, 0x3578, 0x3597, 0x35b5, 0x35d5, 0x35f5, 0x360a, 0x361b,
+ 0x362c, 0x363d, 0x364e, 0x3660, 0x3672, 0x3685, 0x3697, 0x36aa, 0x36be,
+ 0x36d2, 0x36e5, 0x36fa, 0x370e, 0x3723, 0x3739, 0x374e, 0x3764, 0x377a,
+ 0x3791, 0x37a8, 0x37bf, 0x37d7, 0x37ef, 0x3803, 0x380f, 0x381c, 0x3829,
+ 0x3835, 0x3842, 0x384f, 0x385d, 0x386a, 0x3878, 0x3886, 0x3894, 0x38a2,
+ 0x38b0, 0x38bf, 0x38ce, 0x38dc, 0x38eb, 0x38fb, 0x390a, 0x391a, 0x392a,
+ 0x393a, 0x394a, 0x395a, 0x396b, 0x397b, 0x398c, 0x399d, 0x39af, 0x39c0,
+ 0x39d2, 0x39e3, 0x39f5, 0x1e7a, 0x2318, 0x24c9, 0x2603, 0x26a1, 0x2740,
+ 0x27de, 0x283e, 0x288d, 0x28dd, 0x292c, 0x297e, 0x29d5, 0x2a18, 0x2a49,
+ 0x2a7c, 0x2ab1, 0x2ae9, 0x2b23, 0x2b60, 0x2ba0, 0x2be2, 0x2c13, 0x2c37,
+ 0x2c5c, 0x2c83, 0x2cab, 0x2cd4, 0x2cff, 0x2d2b, 0x2d59, 0x2d88, 0x2db9,
+ 0x2deb, 0x2e0f, 0x2e2a, 0x2e45, 0x2e61, 0x2e7e, 0x2e9c, 0x2eba, 0x2ed9,
+ 0x2efa, 0x2f1a, 0x2f3c, 0x2f5f, 0x2f82, 0x2fa6, 0x2fcb, 0x2ff1, 0x300c,
+ 0x301f, 0x3034, 0x3048, 0x305d, 0x3073, 0x3089, 0x309f, 0x30b6, 0x30cd,
+ 0x30e5, 0x30fd, 0x3116, 0x312f, 0x3148, 0x3162, 0x317d, 0x3198, 0x31b3,
+ 0x31cf, 0x31eb, 0x3204, 0x3212, 0x3221, 0x3230, 0x3240, 0x324f, 0x325f,
+ 0x326f, 0x3280, 0x3290, 0x32a1, 0x32b2, 0x32c4, 0x32d5, 0x32e7, 0x32f9,
+ 0x330b, 0x331e, 0x3331, 0x3344, 0x3357, 0x336b, 0x337f, 0x3393, 0x33a7,
+ 0x33bc, 0x33d1, 0x33e6, 0x33fc, 0x3408, 0x3413, 0x341f, 0x342a, 0x3435,
+ 0x3441, 0x344d, 0x3458, 0x3464, 0x3470, 0x347d, 0x3489, 0x3496, 0x34a2,
+ 0x34af, 0x34bc, 0x34c9, 0x34d6, 0x34e4, 0x34f1, 0x34ff, 0x350c, 0x351a,
+ 0x3528, 0x3537, 0x3545, 0x3553, 0x3562, 0x3571, 0x3580, 0x358f, 0x359e,
+ 0x35ae, 0x35bd, 0x35cd, 0x35dd, 0x35ed, 0x35fd, 0x3606, 0x360e, 0x3617,
+ 0x361f, 0x3628, 0x3630, 0x3639, 0x3641, 0x364a, 0x3653, 0x365c, 0x3665,
+ 0x366e, 0x3677, 0x3680, 0x3689, 0x3693, 0x369c, 0x36a6, 0x36af, 0x36b9,
+ 0x36c3, 0x36cd, 0x36d6, 0x36e0, 0x36eb, 0x36f5, 0x36ff, 0x3709, 0x3714,
+ 0x371e, 0x3729, 0x3733, 0x373e, 0x3749, 0x3754, 0x375f, 0x376a, 0x3775,
+ 0x3780, 0x378b, 0x3797, 0x37a2, 0x37ae, 0x37b9, 0x37c5, 0x37d1, 0x37dd,
+ 0x37e9, 0x37f5, 0x3800, 0x3806, 0x380c, 0x3813, 0x3819, 0x381f, 0x3825,
+ 0x382c, 0x3832, 0x3839, 0x383f, 0x3846, 0x384c, 0x3853, 0x3859, 0x3860,
+ 0x3867, 0x386e, 0x3874, 0x387b, 0x3882, 0x3889, 0x3890, 0x3897, 0x389e,
+ 0x38a5, 0x38ad, 0x38b4, 0x38bb, 0x38c2, 0x38ca, 0x38d1, 0x38d9, 0x38e0,
+ 0x38e8, 0x38ef, 0x38f7, 0x38ff, 0x3906, 0x390e, 0x3916, 0x391e, 0x3926,
+ 0x392e, 0x3936, 0x393e, 0x3946, 0x394e, 0x3956, 0x395e, 0x3966, 0x396f,
+ 0x3977, 0x397f, 0x3988, 0x3990, 0x3999, 0x39a2, 0x39aa, 0x39b3, 0x39bc,
+ 0x39c4, 0x39cd, 0x39d6, 0x39df, 0x39e8, 0x39f1, 0x39fa, 0x0, 0x207a,
+ 0x227a, 0x23b7, 0x247a, 0x2518, 0x25b7, 0x262a, 0x267a, 0x26c9, 0x2718,
+ 0x2767, 0x27b7, 0x2803, 0x282a, 0x2852, 0x287a, 0x28a1, 0x28c9, 0x28f0,
+ 0x2918, 0x2940, 0x2969, 0x2994, 0x29bf, 0x29ec, 0x2a0d, 0x2a24, 0x2a3d,
+ 0x2a55, 0x2a6f, 0x2a89, 0x2aa3, 0x2abf, 0x2adb, 0x2af7, 0x2b14, 0x2b32,
+ 0x2b51, 0x2b70, 0x2b90, 0x2bb0, 0x2bd1, 0x2bf3, 0x2c0b, 0x2c1c, 0x2c2e,
+ 0x2c40, 0x2c53, 0x2c66, 0x2c79, 0x2c8d, 0x2ca1, 0x2cb5, 0x2cca, 0x2cdf,
+ 0x2cf4, 0x2d0a, 0x2d20, 0x2d37, 0x2d4d, 0x2d65, 0x2d7c, 0x2d94, 0x2dad,
+ 0x2dc5, 0x2dde, 0x2df8, 0x2e09, 0x2e16, 0x2e23, 0x2e30, 0x2e3e, 0x2e4c,
+ 0x2e5a, 0x2e68, 0x2e77, 0x2e85, 0x2e94, 0x2ea3, 0x2eb3, 0x2ec2, 0x2ed2,
+ 0x2ee1, 0x2ef1, 0x2f02, 0x2f12, 0x2f23, 0x2f34, 0x2f45, 0x2f56, 0x2f67,
+ 0x2f79, 0x2f8b, 0x2f9d, 0x2faf, 0x2fc2, 0x2fd5, 0x2fe7, 0x2ffb, 0x3007,
+ 0x3010, 0x301a, 0x3024, 0x302e, 0x3039, 0x3043, 0x304d, 0x3058, 0x3063,
+ 0x306d, 0x3078, 0x3083, 0x308e, 0x3099, 0x30a5, 0x30b0, 0x30bc, 0x30c7,
+ 0x30d3, 0x30df, 0x30eb, 0x30f7, 0x3103, 0x310f, 0x311c, 0x3128, 0x3135,
+ 0x3142, 0x314f, 0x315c, 0x3169, 0x3176, 0x3183, 0x3191, 0x319e, 0x31ac,
+ 0x31ba, 0x31c8, 0x31d6, 0x31e4, 0x31f2, 0x3200, 0x3207, 0x320f, 0x3216,
+ 0x321e, 0x3225, 0x322d, 0x3234, 0x323c, 0x3244, 0x324b, 0x3253, 0x325b,
+ 0x3263, 0x326b, 0x3273, 0x327c, 0x3284, 0x328c, 0x3294, 0x329d, 0x32a5,
+ 0x32ae, 0x32b6, 0x32bf, 0x32c8, 0x32d1, 0x32da, 0x32e2, 0x32eb, 0x32f4,
+ 0x32fe, 0x3307, 0x3310, 0x3319, 0x3323, 0x332c, 0x3336, 0x333f, 0x3349,
+ 0x3352, 0x335c, 0x3366, 0x3370, 0x337a, 0x3384, 0x338e, 0x3398, 0x33a2,
+ 0x33ad, 0x33b7, 0x33c1, 0x33cc, 0x33d6, 0x33e1, 0x33ec, 0x33f6, 0x3400,
+ 0x3406, 0x340b, 0x3411, 0x3416, 0x341c, 0x3421, 0x3427, 0x342d, 0x3432,
+ 0x3438, 0x343e, 0x3444, 0x344a, 0x344f, 0x3455, 0x345b, 0x3461, 0x3467,
+ 0x346d, 0x3473, 0x347a, 0x3480, 0x3486, 0x348c, 0x3492, 0x3499, 0x349f,
+ 0x34a5, 0x34ac, 0x34b2, 0x34b9, 0x34bf, 0x34c6, 0x34cc, 0x34d3, 0x34d9,
+ 0x34e0, 0x34e7, 0x34ee, 0x34f4, 0x34fb, 0x3502, 0x3509, 0x3510, 0x3517,
+ 0x351e, 0x3525, 0x352c, 0x3533, 0x353a, 0x3541, 0x3549, 0x3550, 0x3557,
+ 0x355e, 0x3566, 0x356d, 0x3575, 0x357c, 0x3584, 0x358b, 0x3593, 0x359a,
+ 0x35a2, 0x35aa, 0x35b1, 0x35b9, 0x35c1, 0x35c9, 0x35d1, 0x35d9, 0x35e1,
+ 0x35e9, 0x35f1, 0x35f9, 0x3600, 0x3604, 0x3608, 0x360c, 0x3610, 0x3615,
+ 0x3619, 0x361d, 0x3621, 0x3625, 0x362a, 0x362e, 0x3632, 0x3636, 0x363b,
+ 0x363f, 0x3643, 0x3648, 0x364c, 0x3651, 0x3655, 0x365a, 0x365e, 0x3662,
+ 0x3667, 0x366b, 0x3670, 0x3675, 0x3679, 0x367e, 0x3682, 0x3687, 0x368c,
+ 0x3690, 0x3695, 0x369a, 0x369f, 0x36a3, 0x36a8, 0x36ad, 0x36b2, 0x36b7,
+ 0x36bb, 0x36c0, 0x36c5, 0x36ca, 0x36cf, 0x36d4, 0x36d9, 0x36de, 0x36e3,
+ 0x36e8, 0x36ed, 0x36f2, 0x36f7, 0x36fc, 0x3701, 0x3707, 0x370c, 0x3711,
+ 0x3716, 0x371b, 0x3721, 0x3726, 0x372b, 0x3731, 0x3736, 0x373b, 0x3741,
+ 0x3746, 0x374b, 0x3751, 0x3756, 0x375c, 0x3761, 0x3767, 0x376c, 0x3772,
+ 0x3778, 0x377d, 0x3783, 0x3788, 0x378e, 0x3794, 0x379a, 0x379f, 0x37a5,
+ 0x37ab, 0x37b1, 0x37b6, 0x37bc, 0x37c2, 0x37c8, 0x37ce, 0x37d4, 0x37da,
+ 0x37e0, 0x37e6, 0x37ec, 0x37f2, 0x37f8, 0x37fe, 0x3802, 0x3805, 0x3808,
+ 0x380b, 0x380e, 0x3811, 0x3814, 0x3817, 0x381a, 0x381d, 0x3821, 0x3824,
+ 0x3827, 0x382a, 0x382d, 0x3831, 0x3834, 0x3837, 0x383a, 0x383d, 0x3841,
+ 0x3844, 0x3847, 0x384a, 0x384e, 0x3851, 0x3854, 0x3858, 0x385b, 0x385e,
+ 0x3862, 0x3865, 0x3869, 0x386c, 0x386f, 0x3873, 0x3876, 0x387a, 0x387d,
+ 0x3881, 0x3884, 0x3887, 0x388b, 0x388e, 0x3892, 0x3895, 0x3899, 0x389d,
+ 0x38a0, 0x38a4, 0x38a7, 0x38ab, 0x38ae, 0x38b2, 0x38b6, 0x38b9, 0x38bd,
+ 0x38c1, 0x38c4, 0x38c8, 0x38cc, 0x38cf, 0x38d3, 0x38d7, 0x38db, 0x38de,
+ 0x38e2, 0x38e6, 0x38ea, 0x38ed, 0x38f1, 0x38f5, 0x38f9, 0x38fd, 0x3901,
+ 0x3904, 0x3908, 0x390c, 0x3910, 0x3914, 0x3918, 0x391c, 0x3920, 0x3924,
+ 0x3928, 0x392c, 0x3930, 0x3934, 0x3938, 0x393c, 0x3940, 0x3944, 0x3948,
+ 0x394c, 0x3950, 0x3954, 0x3958, 0x395c, 0x3960, 0x3964, 0x3968, 0x396d,
+ 0x3971, 0x3975, 0x3979, 0x397d, 0x3982, 0x3986, 0x398a, 0x398e, 0x3993,
+ 0x3997, 0x399b, 0x399f, 0x39a4, 0x39a8, 0x39ac, 0x39b1, 0x39b5, 0x39b9,
+ 0x39be, 0x39c2, 0x39c7, 0x39cb, 0x39cf, 0x39d4, 0x39d8, 0x39dd, 0x39e1,
+ 0x39e6, 0x39ea, 0x39ef, 0x39f3, 0x39f8, 0x39fc, 0xc,
+ /* table descriptor */
+ 0xbf7fffea, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x36ce, 0x0, 0x0, 0x0, 0x36ce, 0x0, 0x0, 0x0, 0x36ce, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff, 0xe, 0x40, 0x40, 0x40, 0x40,
+ 0x40, 0x40, 0x3ac, 0x3ac, 0x3ac,
+ /* table descriptor */
+ 0xdf7fffea, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x8000, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xbfbfffea, 0x0,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0xe66, 0x2528, 0x340, 0xfffff82c, 0xffffebcd, 0x1c07, 0x1c07,
+ 0xffffe63a, 0xfffffdbf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff,
+ 0x3ff, 0xe, 0x40, 0x200, 0x200, 0x40, 0x40, 0x40, 0x3ac, 0x3c0, 0x3c0,
+ /* table descriptor */
+ 0x3fbfffea, 0x1,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0xba7, 0x2732, 0x3f5, 0xfffff994, 0xffffea65, 0x1c07, 0x1c07,
+ 0xffffe68b, 0xfffffd6e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff,
+ 0x3ff, 0xe, 0x40, 0x200, 0x200, 0x40, 0x40, 0x40, 0x3ac, 0x3c0, 0x3c0,
+ /* table descriptor */
+ 0x3fbfffea, 0x6,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x1063, 0x202b, 0x63f, 0xfffff68b, 0xffffed6e, 0x1c07, 0x1c07,
+ 0xffffe888, 0xfffffb71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff,
+ 0x3ff, 0xe, 0x40, 0x200, 0x200, 0x40, 0x40, 0x40, 0x3ac, 0x3c0, 0x3c0,
+ /* table descriptor */
+ 0x3fbfffea, 0x8,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x36ce, 0x0, 0x0, 0x0, 0x380e, 0x0, 0x0, 0x0, 0x380e, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff, 0xe, 0x40, 0x200, 0x200, 0x40,
+ 0x40, 0x40, 0x3ac, 0x3c0, 0x3c0,
+ /* table descriptor */
+ 0xdfbfffea, 0x0,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x10d0, 0x2b64, 0x3cc, 0xfffff710, 0xffffe8f0, 0x2000, 0x2000,
+ 0xffffe293, 0xfffffd6d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff,
+ 0x3ff, 0xe, 0x0, 0x200, 0x200, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0x5fbfffea, 0x1,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0xd9b, 0x2dc6, 0x49f, 0xfffff8ab, 0xffffe755, 0x2000, 0x2000,
+ 0xffffe2ef, 0xfffffd11, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff,
+ 0x3ff, 0xe, 0x0, 0x200, 0x200, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0x5fbfffea, 0x6,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x1323, 0x2591, 0x74c, 0xfffff533, 0xffffeacd, 0x2000, 0x2000,
+ 0xffffe534, 0xfffffacc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff,
+ 0x3ff, 0xe, 0x0, 0x200, 0x200, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0x5fbfffea, 0x8,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff, 0xe, 0x0, 0x200, 0x200, 0x0,
+ 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfff0e1e1, 0xf,
+ /* table length */
+ 0x402,
+ /* table data */
+ 0x3, 0x0, 0x200, 0x500, 0x700, 0x8c0, 0xa20, 0xae0, 0xbe0, 0xc70,
+ 0xd00, 0xdb0, 0xe30, 0xe98, 0xf00, 0xf78, 0xff8, 0x103c, 0x1084,
+ 0x10d0, 0x1120, 0x1178, 0x11d0, 0x1218, 0x124a, 0x127e, 0x12b6, 0x12f0,
+ 0x132c, 0x136c, 0x13ae, 0x13f2, 0x141d, 0x1442, 0x1469, 0x1491, 0x14bb,
+ 0x14e6, 0x1513, 0x1542, 0x1572, 0x15a4, 0x15d7, 0x1606, 0x1621, 0x163e,
+ 0x165b, 0x1679, 0x1698, 0x16b9, 0x16da, 0x16fc, 0x171f, 0x1743, 0x1768,
+ 0x178e, 0x17b5, 0x17dd, 0x1803, 0x1818, 0x182e, 0x1844, 0x185b, 0x1873,
+ 0x188b, 0x18a4, 0x18bd, 0x18d7, 0x18f2, 0x190d, 0x1929, 0x1945, 0x1962,
+ 0x1980, 0x199f, 0x19be, 0x19de, 0x19ff, 0x1a10, 0x1a21, 0x1a32, 0x1a44,
+ 0x1a56, 0x1a69, 0x1a7c, 0x1a8f, 0x1aa3, 0x1ab7, 0x1acc, 0x1ae1, 0x1af6,
+ 0x1b0c, 0x1b23, 0x1b39, 0x1b51, 0x1b68, 0x1b81, 0x1b99, 0x1bb2, 0x1bcc,
+ 0x1be6, 0x1c00, 0x1c0e, 0x1c1b, 0x1c29, 0x1c38, 0x1c46, 0x1c55, 0x1c64,
+ 0x1c74, 0x1c83, 0x1c93, 0x1ca3, 0x1cb4, 0x1cc5, 0x1cd6, 0x1ce7, 0x1cf9,
+ 0x1d0b, 0x1d1d, 0x1d30, 0x1d42, 0x1d56, 0x1d69, 0x1d7d, 0x1d91, 0x1da6,
+ 0x1dbb, 0x1dd0, 0x1de6, 0x1dfc, 0x1e09, 0x1e14, 0x1e20, 0x1e2b, 0x1e37,
+ 0x1e43, 0x1e4f, 0x1e5c, 0x1e69, 0x1e75, 0x1e82, 0x1e90, 0x1e9d, 0x1eab,
+ 0x1eb9, 0x1ec7, 0x1ed5, 0x1ee3, 0x1ef2, 0x1f01, 0x1f10, 0x1f20, 0x1f2f,
+ 0x1f3f, 0x1f4f, 0x1f60, 0x1f70, 0x1f81, 0x1f92, 0x1fa3, 0x1fb5, 0x1fc7,
+ 0x1fd9, 0x1feb, 0x1ffe, 0x2008, 0x2012, 0x201b, 0x2025, 0x202f, 0x2039,
+ 0x2043, 0x204e, 0x2058, 0x2063, 0x206e, 0x2079, 0x2084, 0x208f, 0x209b,
+ 0x20a6, 0x20b2, 0x20be, 0x20ca, 0x20d6, 0x20e3, 0x20ef, 0x20fc, 0x2109,
+ 0x2116, 0x2123, 0x2131, 0x213e, 0x214c, 0x215a, 0x2168, 0x2176, 0x2185,
+ 0x2194, 0x21a2, 0x21b2, 0x21c1, 0x21d0, 0x21e0, 0x21f0, 0x2200, 0x2208,
+ 0x2210, 0x2218, 0x2221, 0x2229, 0x2232, 0x223b, 0x2244, 0x224d, 0x2256,
+ 0x225f, 0x2268, 0x2272, 0x227b, 0x2285, 0x228f, 0x2299, 0x22a3, 0x22ad,
+ 0x22b7, 0x22c2, 0x22cc, 0x22d7, 0x22e2, 0x22ed, 0x22f8, 0x2303, 0x230e,
+ 0x231a, 0x2325, 0x2331, 0x233d, 0x2349, 0x2355, 0x2361, 0x236e, 0x237a,
+ 0x2387, 0x2394, 0x23a1, 0x23ae, 0x23bc, 0x23c9, 0x23d7, 0x23e5, 0x23f3,
+ 0x2400, 0x2407, 0x240f, 0x2416, 0x241d, 0x2425, 0x242c, 0x2434, 0x243c,
+ 0x2444, 0x244c, 0x2454, 0x245c, 0x2464, 0x246c, 0x2475, 0x247d, 0x2486,
+ 0x248e, 0x2497, 0x24a0, 0x24a9, 0x24b2, 0x24bb, 0x24c4, 0x24ce, 0x24d7,
+ 0x24e1, 0x24eb, 0x24f4, 0x24fe, 0x2508, 0x2512, 0x251d, 0x2527, 0x2531,
+ 0x253c, 0x2547, 0x2552, 0x255d, 0x2568, 0x2573, 0x257e, 0x2589, 0x2595,
+ 0x25a1, 0x25ac, 0x25b8, 0x25c4, 0x25d1, 0x25dd, 0x25e9, 0x25f6, 0x2601,
+ 0x2607, 0x260e, 0x2614, 0x261b, 0x2622, 0x2629, 0x262f, 0x2636, 0x263d,
+ 0x2644, 0x264c, 0x2653, 0x265a, 0x2661, 0x2669, 0x2670, 0x2678, 0x2680,
+ 0x2687, 0x268f, 0x2697, 0x269f, 0x26a7, 0x26af, 0x26b8, 0x26c0, 0x26c8,
+ 0x26d1, 0x26d9, 0x26e2, 0x26eb, 0x26f4, 0x26fd, 0x2706, 0x270f, 0x2718,
+ 0x2722, 0x272b, 0x2734, 0x273e, 0x2748, 0x2752, 0x275c, 0x2766, 0x2770,
+ 0x277a, 0x2784, 0x278f, 0x2799, 0x27a4, 0x27af, 0x27b9, 0x27c4, 0x27d0,
+ 0x27db, 0x27e6, 0x27f1, 0x27fd, 0x2804, 0x280a, 0x2810, 0x2816, 0x281c,
+ 0x2822, 0x2828, 0x282f, 0x2835, 0x283b, 0x2842, 0x2848, 0x284f, 0x2855,
+ 0x285c, 0x2863, 0x286a, 0x2870, 0x2877, 0x287e, 0x2886, 0x288d, 0x2894,
+ 0x289b, 0x28a3, 0x28aa, 0x28b2, 0x28b9, 0x28c1, 0x28c9, 0x28d0, 0x28d8,
+ 0x28e0, 0x28e8, 0x28f1, 0x28f9, 0x2901, 0x2909, 0x2912, 0x291a, 0x2923,
+ 0x292c, 0x2935, 0x293d, 0x2946, 0x294f, 0x2959, 0x2962, 0x296b, 0x2975,
+ 0x297e, 0x2988, 0x2991, 0x299b, 0x29a5, 0x29af, 0x29b9, 0x29c3, 0x29cd,
+ 0x29d8, 0x29e2, 0x29ed, 0x29f7, 0x2a01, 0x2a06, 0x2a0c, 0x2a11, 0x2a17,
+ 0x2a1c, 0x2a22, 0x2a28, 0x2a2e, 0x2a33, 0x2a39, 0x2a3f, 0x2a45, 0x2a4b,
+ 0x2a52, 0x2a58, 0x2a5e, 0x2a64, 0x2a6b, 0x2a71, 0x2a78, 0x2a7e, 0x2a85,
+ 0x2a8b, 0x2a92, 0x2a99, 0x2aa0, 0x2aa7, 0x2aae, 0x2ab5, 0x2abc, 0x2ac3,
+ 0x2aca, 0x2ad2, 0x2ad9, 0x2ae1, 0x2ae8, 0x2af0, 0x2af7, 0x2aff, 0x2b07,
+ 0x2b0f, 0x2b17, 0x2b1f, 0x2b27, 0x2b2f, 0x2b38, 0x2b40, 0x2b48, 0x2b51,
+ 0x2b59, 0x2b62, 0x2b6b, 0x2b74, 0x2b7d, 0x2b86, 0x2b8f, 0x2b98, 0x2ba1,
+ 0x2baa, 0x2bb4, 0x2bbd, 0x2bc7, 0x2bd0, 0x2bda, 0x2be4, 0x2bee, 0x2bf8,
+ 0x2c01, 0x2c06, 0x2c0b, 0x2c10, 0x2c16, 0x2c1b, 0x2c20, 0x2c26, 0x2c2b,
+ 0x2c31, 0x2c36, 0x2c3c, 0x2c41, 0x2c47, 0x2c4d, 0x2c53, 0x2c59, 0x2c5e,
+ 0x2c64, 0x2c6a, 0x2c70, 0x2c77, 0x2c7d, 0x2c83, 0x2c89, 0x2c90, 0x2c96,
+ 0x2c9d, 0x2ca3, 0x2caa, 0x2cb0, 0x2cb7, 0x2cbe, 0x2cc5, 0x2ccc, 0x2cd3,
+ 0x2cda, 0x2ce1, 0x2ce8, 0x2cef, 0x2cf6, 0x2cfe, 0x2d05, 0x2d0d, 0x2d14,
+ 0x2d1c, 0x2d24, 0x2d2b, 0x2d33, 0x2d3b, 0x2d43, 0x2d4b, 0x2d53, 0x2d5b,
+ 0x2d64, 0x2d6c, 0x2d74, 0x2d7d, 0x2d85, 0x2d8e, 0x2d97, 0x2da0, 0x2da9,
+ 0x2db2, 0x2dbb, 0x2dc4, 0x2dcd, 0x2dd6, 0x2de0, 0x2de9, 0x2df3, 0x2dfc,
+ 0x2e03, 0x2e08, 0x2e0d, 0x2e12, 0x2e17, 0x2e1c, 0x2e21, 0x2e26, 0x2e2b,
+ 0x2e30, 0x2e36, 0x2e3b, 0x2e41, 0x2e46, 0x2e4c, 0x2e51, 0x2e57, 0x2e5c,
+ 0x2e62, 0x2e68, 0x2e6e, 0x2e73, 0x2e79, 0x2e7f, 0x2e85, 0x2e8b, 0x2e92,
+ 0x2e98, 0x2e9e, 0x2ea4, 0x2eab, 0x2eb1, 0x2eb8, 0x2ebe, 0x2ec5, 0x2ecb,
+ 0x2ed2, 0x2ed9, 0x2ee0, 0x2ee6, 0x2eed, 0x2ef4, 0x2efb, 0x2f03, 0x2f0a,
+ 0x2f11, 0x2f18, 0x2f20, 0x2f27, 0x2f2f, 0x2f36, 0x2f3e, 0x2f46, 0x2f4e,
+ 0x2f55, 0x2f5d, 0x2f65, 0x2f6d, 0x2f76, 0x2f7e, 0x2f86, 0x2f8e, 0x2f97,
+ 0x2f9f, 0x2fa8, 0x2fb1, 0x2fb9, 0x2fc2, 0x2fcb, 0x2fd4, 0x2fdd, 0x2fe6,
+ 0x2ff0, 0x2ff9, 0x3001, 0x3006, 0x300a, 0x300f, 0x3014, 0x3019, 0x301e,
+ 0x3023, 0x3028, 0x302d, 0x3032, 0x3037, 0x303d, 0x3042, 0x3047, 0x304d,
+ 0x3052, 0x3057, 0x305d, 0x3062, 0x3068, 0x306e, 0x3073, 0x3079, 0x307f,
+ 0x3085, 0x308b, 0x3091, 0x3097, 0x309d, 0x30a3, 0x30a9, 0x30af, 0x30b6,
+ 0x30bc, 0x30c2, 0x30c9, 0x30cf, 0x30d6, 0x30dd, 0x30e3, 0x30ea, 0x30f1,
+ 0x30f8, 0x30ff, 0x3106, 0x310d, 0x3114, 0x311b, 0x3122, 0x3129, 0x3131,
+ 0x3138, 0x3140, 0x3147, 0x314f, 0x3157, 0x315e, 0x3166, 0x316e, 0x3176,
+ 0x317e, 0x3186, 0x318f, 0x3197, 0x319f, 0x31a8, 0x31b0, 0x31b9, 0x31c1,
+ 0x31ca, 0x31d3, 0x31dc, 0x31e5, 0x31ee, 0x31f7, 0x3200, 0x3204, 0x3209,
+ 0x320e, 0x3213, 0x3217, 0x321c, 0x3221, 0x3226, 0x322b, 0x3230, 0x3235,
+ 0x323a, 0x323f, 0x3245, 0x324a, 0x324f, 0x3255, 0x325a, 0x325f, 0x3265,
+ 0x326a, 0x3270, 0x3276, 0x327b, 0x3281, 0x3287, 0x328d, 0x3293, 0x3299,
+ 0x329f, 0x32a5, 0x32ab, 0x32b1, 0x32b7, 0x32bd, 0x32c4, 0x32ca, 0x32d1,
+ 0x32d7, 0x32de, 0x32e4, 0x32eb, 0x32f2, 0x32f8, 0x32ff, 0x3306, 0x330d,
+ 0x3314, 0x331b, 0x3322, 0x332a, 0x3331, 0x3338, 0x3340, 0x3347, 0x334f,
+ 0x3357, 0x335e, 0x3366, 0x336e, 0x3376, 0x337e, 0x3386, 0x338e, 0x3396,
+ 0x339e, 0x33a7, 0x33af, 0x33b8, 0x33c0, 0x33c9, 0x33d2, 0x33da, 0x33e3,
+ 0x33ec, 0x33f5, 0x33fe, 0x3404, 0x3408, 0x340d, 0x3412, 0x3416, 0x341b,
+ 0x3420, 0x3425, 0x342a, 0x342f, 0x3434, 0x3439, 0x343e, 0x3443, 0x3448,
+ 0x344e, 0x3453, 0x3458, 0x345e, 0x3463, 0x3469, 0x346e, 0x3474, 0x347a,
+ 0x347f, 0x3485, 0x348b, 0x3491, 0x3497, 0x349d, 0x34a3, 0x34a9, 0x34af,
+ 0x34b5, 0x34bb, 0x34c2, 0x34c8, 0x34ce, 0x34d5, 0x34db, 0x34e2, 0x34e9,
+ 0x34ef, 0x34f6, 0x34fd, 0x3504, 0x350b, 0x3512, 0x3519, 0x3520, 0x3527,
+ 0x352f, 0x3536, 0x353d, 0x3545, 0x354c, 0x3554, 0x355c, 0x3563, 0x356b,
+ 0x3573, 0x357b, 0x3583, 0x358b, 0x3593, 0x359c, 0x35a4, 0x35ad, 0x35b5,
+ 0x35be, 0x35c6, 0x35cf, 0x35d8, 0x35e1, 0x35ea, 0x35f3, 0x35fc, 0x3602,
+ 0x3607, 0x360c, 0x3610, 0x3615, 0x361a, 0x361f, 0x3624, 0x3629, 0x362e,
+ 0x3633, 0x3638, 0x363d, 0x3642, 0x3647, 0x364d, 0x3652, 0x3657, 0x365d,
+ 0x3662, 0x3668, 0x366d, 0x3673, 0x3679, 0x367f, 0x3684, 0x368a, 0x3690,
+ 0x3696, 0x369c, 0x36a2, 0x36a8, 0x36ae, 0x36b5, 0x36bb, 0x36c1, 0x36c8,
+ 0x36ce, 0x36d5, 0x36db, 0x36e2, 0x36e9, 0x36f0, 0x36f6, 0x36fd, 0x3704,
+ 0x370b, 0x3712, 0x371a, 0x3721, 0x3728, 0x372f, 0x3737, 0x373e, 0x3746,
+ 0x374e, 0x3755, 0x375d, 0x3765, 0x376d, 0x3775, 0x377d, 0x3785, 0x378d,
+ 0x3796, 0x379e, 0x37a7, 0x37af, 0x37b8, 0x37c1, 0x37c9, 0x37d2, 0x37db,
+ 0x37e4, 0x37ed, 0x37f7, 0x3800, 0x3804, 0x3809, 0x380e, 0x3813, 0x3818,
+ 0x381d, 0x3821, 0x3826, 0x382c, 0x3831, 0x3836, 0x383b, 0x3840, 0x3846,
+ 0x384b, 0x3850, 0x3856, 0x385b, 0x3861, 0x3866, 0x386c, 0x3872, 0x3878,
+ 0x387d, 0x3883, 0x3889, 0x388f, 0x3895, 0x389b, 0x38a2, 0x38a8, 0x38ae,
+ 0x38b5, 0x38bb, 0x38c1, 0x38c8, 0x38cf, 0x38d5, 0x38dc, 0x38e3, 0x38ea,
+ 0x38f1, 0x38f8, 0x38ff, 0x3906, 0x390d, 0x3914, 0x391b, 0x3923, 0x392a,
+ 0x3932, 0x3939, 0x3941, 0x3949, 0x3951, 0x3959, 0x3961, 0x3969, 0x3971,
+ 0x3979, 0x3981, 0x398a, 0x3992, 0x399b, 0x39a3, 0x39ac, 0x39b5, 0x39be,
+ 0x39c7, 0x39d0, 0x39d9, 0x39e2, 0x39ec, 0x39f5, 0x39ff, 0x3,
+ /* table descriptor */
+ 0xffffe2e1, 0xf,
+ /* table length */
+ 0x402,
+ /* table data */
+ 0x3, 0x0, 0x3, 0x7, 0xa, 0xe, 0x11, 0x15, 0x18, 0x1c, 0x20, 0x23, 0x27,
+ 0x2a, 0x2e, 0x31, 0x35, 0x38, 0x3c, 0x40, 0x43, 0x47, 0x4a, 0x4e, 0x51,
+ 0x55, 0x58, 0x5c, 0x60, 0x63, 0x67, 0x6a, 0x6e, 0x71, 0x75, 0x78, 0x7c,
+ 0x80, 0x83, 0x87, 0x8a, 0x8e, 0x91, 0x95, 0x99, 0x9c, 0xa0, 0xa3, 0xa7,
+ 0xaa, 0xae, 0xb1, 0xb5, 0xb9, 0xbc, 0xc0, 0xc3, 0xc7, 0xca, 0xce, 0xd1,
+ 0xd5, 0xd9, 0xdc, 0xe0, 0xe3, 0xe7, 0xea, 0xee, 0xf1, 0xf5, 0xf9, 0xfc,
+ 0x100, 0x103, 0x107, 0x10a, 0x10e, 0x112, 0x115, 0x119, 0x11c, 0x120,
+ 0x123, 0x126, 0x12a, 0x12d, 0x131, 0x134, 0x138, 0x13c, 0x13f, 0x143,
+ 0x147, 0x14b, 0x14e, 0x152, 0x156, 0x15a, 0x15e, 0x162, 0x166, 0x16a,
+ 0x16e, 0x172, 0x176, 0x17a, 0x17e, 0x182, 0x186, 0x18a, 0x18f, 0x193,
+ 0x197, 0x19b, 0x1a0, 0x1a4, 0x1a8, 0x1ad, 0x1b1, 0x1b5, 0x1ba, 0x1be,
+ 0x1c3, 0x1c7, 0x1cc, 0x1d0, 0x1d5, 0x1d9, 0x1de, 0x1e3, 0x1e7, 0x1ec,
+ 0x1f1, 0x1f6, 0x1fa, 0x1ff, 0x204, 0x209, 0x20e, 0x213, 0x217, 0x21c,
+ 0x221, 0x226, 0x22b, 0x230, 0x236, 0x23b, 0x240, 0x245, 0x24a, 0x24f,
+ 0x255, 0x25a, 0x25f, 0x264, 0x26a, 0x26f, 0x274, 0x27a, 0x27f, 0x285,
+ 0x28a, 0x290, 0x295, 0x29b, 0x2a0, 0x2a6, 0x2ac, 0x2b1, 0x2b7, 0x2bd,
+ 0x2c2, 0x2c8, 0x2ce, 0x2d4, 0x2da, 0x2df, 0x2e5, 0x2eb, 0x2f1, 0x2f7,
+ 0x2fd, 0x303, 0x309, 0x30f, 0x315, 0x31c, 0x322, 0x328, 0x32e, 0x334,
+ 0x33b, 0x341, 0x347, 0x34d, 0x354, 0x35a, 0x361, 0x367, 0x36d, 0x374,
+ 0x37a, 0x381, 0x388, 0x38e, 0x395, 0x39b, 0x3a2, 0x3a9, 0x3b0, 0x3b6,
+ 0x3bd, 0x3c4, 0x3cb, 0x3d2, 0x3d8, 0x3df, 0x3e6, 0x3ed, 0x3f4, 0x3fb,
+ 0x402, 0x409, 0x411, 0x418, 0x41f, 0x426, 0x42d, 0x434, 0x43c, 0x443,
+ 0x44a, 0x452, 0x459, 0x460, 0x468, 0x46f, 0x477, 0x47e, 0x486, 0x48d,
+ 0x495, 0x49c, 0x4a4, 0x4ac, 0x4b3, 0x4bb, 0x4c3, 0x4cb, 0x4d3, 0x4da,
+ 0x4e2, 0x4ea, 0x4f2, 0x4fa, 0x502, 0x50a, 0x512, 0x51a, 0x522, 0x52a,
+ 0x532, 0x53a, 0x543, 0x54b, 0x553, 0x55b, 0x564, 0x56c, 0x574, 0x57d,
+ 0x585, 0x58d, 0x596, 0x59e, 0x5a7, 0x5af, 0x5b8, 0x5c1, 0x5c9, 0x5d2,
+ 0x5db, 0x5e3, 0x5ec, 0x5f5, 0x5fe, 0x606, 0x60f, 0x618, 0x621, 0x62a,
+ 0x633, 0x63c, 0x645, 0x64e, 0x657, 0x660, 0x669, 0x672, 0x67b, 0x685,
+ 0x68e, 0x697, 0x6a0, 0x6aa, 0x6b3, 0x6bd, 0x6c6, 0x6cf, 0x6d9, 0x6e2,
+ 0x6ec, 0x6f5, 0x6ff, 0x709, 0x712, 0x71c, 0x726, 0x72f, 0x739, 0x743,
+ 0x74d, 0x756, 0x760, 0x76a, 0x774, 0x77e, 0x788, 0x792, 0x79c, 0x7a6,
+ 0x7b0, 0x7ba, 0x7c4, 0x7cf, 0x7d9, 0x7e3, 0x7ed, 0x7f7, 0x802, 0x80c,
+ 0x816, 0x821, 0x82b, 0x836, 0x840, 0x84b, 0x855, 0x860, 0x86a, 0x875,
+ 0x880, 0x88a, 0x895, 0x8a0, 0x8ab, 0x8b5, 0x8c0, 0x8cb, 0x8d6, 0x8e1,
+ 0x8ec, 0x8f7, 0x902, 0x90d, 0x918, 0x923, 0x92e, 0x939, 0x944, 0x950,
+ 0x95b, 0x966, 0x971, 0x97d, 0x988, 0x993, 0x99f, 0x9aa, 0x9b6, 0x9c1,
+ 0x9cd, 0x9d8, 0x9e4, 0x9f0, 0x9fb, 0xa07, 0xa13, 0xa1e, 0xa2a, 0xa36,
+ 0xa42, 0xa4e, 0xa59, 0xa65, 0xa71, 0xa7d, 0xa89, 0xa95, 0xaa1, 0xaad,
+ 0xab9, 0xac6, 0xad2, 0xade, 0xaea, 0xaf6, 0xb03, 0xb0f, 0xb1b, 0xb28,
+ 0xb34, 0xb41, 0xb4d, 0xb5a, 0xb66, 0xb73, 0xb7f, 0xb8c, 0xb98, 0xba5,
+ 0xbb2, 0xbbf, 0xbcb, 0xbd8, 0xbe5, 0xbf2, 0xbff, 0xc0c, 0xc19, 0xc25,
+ 0xc32, 0xc40, 0xc4d, 0xc5a, 0xc67, 0xc74, 0xc81, 0xc8e, 0xc9c, 0xca9,
+ 0xcb6, 0xcc3, 0xcd1, 0xcde, 0xcec, 0xcf9, 0xd07, 0xd14, 0xd22, 0xd2f,
+ 0xd3d, 0xd4a, 0xd58, 0xd66, 0xd73, 0xd81, 0xd8f, 0xd9d, 0xdab, 0xdb8,
+ 0xdc6, 0xdd4, 0xde2, 0xdf0, 0xdfe, 0xe0c, 0xe1a, 0xe29, 0xe37, 0xe45,
+ 0xe53, 0xe61, 0xe70, 0xe7e, 0xe8c, 0xe9a, 0xea9, 0xeb7, 0xec6, 0xed4,
+ 0xee3, 0xef1, 0xf00, 0xf0e, 0xf1d, 0xf2c, 0xf3a, 0xf49, 0xf58, 0xf67,
+ 0xf75, 0xf84, 0xf93, 0xfa2, 0xfb1, 0xfc0, 0xfcf, 0xfde, 0xfed, 0xffc,
+ 0x100b, 0x101a, 0x102a, 0x1039, 0x1048, 0x1057, 0x1067, 0x1076, 0x1085,
+ 0x1095, 0x10a4, 0x10b4, 0x10c3, 0x10d3, 0x10e2, 0x10f2, 0x1101, 0x1111,
+ 0x1121, 0x1130, 0x1140, 0x1150, 0x1160, 0x116f, 0x117f, 0x118f, 0x119f,
+ 0x11af, 0x11bf, 0x11cf, 0x11df, 0x11ef, 0x11ff, 0x120f, 0x121f, 0x1230,
+ 0x1240, 0x1250, 0x1260, 0x1271, 0x1281, 0x1291, 0x12a2, 0x12b2, 0x12c3,
+ 0x12d3, 0x12e4, 0x12f4, 0x1305, 0x1316, 0x1326, 0x1337, 0x1348, 0x1359,
+ 0x1369, 0x137a, 0x138b, 0x139c, 0x13ad, 0x13be, 0x13cf, 0x13e0, 0x13f1,
+ 0x1402, 0x1413, 0x1424, 0x1435, 0x1446, 0x1458, 0x1469, 0x147a, 0x148b,
+ 0x149d, 0x14ae, 0x14c0, 0x14d1, 0x14e3, 0x14f4, 0x1506, 0x1517, 0x1529,
+ 0x153a, 0x154c, 0x155e, 0x156f, 0x1581, 0x1593, 0x15a5, 0x15b7, 0x15c9,
+ 0x15db, 0x15ec, 0x15fe, 0x1610, 0x1623, 0x1635, 0x1647, 0x1659, 0x166b,
+ 0x167d, 0x168f, 0x16a2, 0x16b4, 0x16c6, 0x16d9, 0x16eb, 0x16fe, 0x1710,
+ 0x1722, 0x1735, 0x1748, 0x175a, 0x176d, 0x177f, 0x1792, 0x17a5, 0x17b8,
+ 0x17ca, 0x17dd, 0x17f0, 0x1803, 0x1816, 0x1829, 0x183c, 0x184f, 0x1862,
+ 0x1875, 0x1888, 0x189b, 0x18ae, 0x18c1, 0x18d5, 0x18e8, 0x18fb, 0x190e,
+ 0x1922, 0x1935, 0x1949, 0x195c, 0x196f, 0x1983, 0x1996, 0x19aa, 0x19be,
+ 0x19d1, 0x19e5, 0x19f9, 0x1a0c, 0x1a20, 0x1a34, 0x1a48, 0x1a5c, 0x1a70,
+ 0x1a84, 0x1a97, 0x1aab, 0x1ac0, 0x1ad4, 0x1ae8, 0x1afc, 0x1b10, 0x1b24,
+ 0x1b38, 0x1b4d, 0x1b61, 0x1b75, 0x1b8a, 0x1b9e, 0x1bb2, 0x1bc7, 0x1bdb,
+ 0x1bf0, 0x1c04, 0x1c19, 0x1c2e, 0x1c42, 0x1c57, 0x1c6c, 0x1c80, 0x1c95,
+ 0x1caa, 0x1cbf, 0x1cd4, 0x1ce8, 0x1cfd, 0x1d12, 0x1d27, 0x1d3c, 0x1d51,
+ 0x1d67, 0x1d7c, 0x1d91, 0x1da6, 0x1dbb, 0x1dd1, 0x1de6, 0x1dfb, 0x1e10,
+ 0x1e26, 0x1e3b, 0x1e51, 0x1e66, 0x1e7c, 0x1e91, 0x1ea7, 0x1ebd, 0x1ed2,
+ 0x1ee8, 0x1efe, 0x1f13, 0x1f29, 0x1f3f, 0x1f55, 0x1f6b, 0x1f81, 0x1f96,
+ 0x1fac, 0x1fc2, 0x1fd9, 0x1fef, 0x2005, 0x201b, 0x2031, 0x2047, 0x205d,
+ 0x2074, 0x208a, 0x20a0, 0x20b7, 0x20cd, 0x20e4, 0x20fa, 0x2111, 0x2127,
+ 0x213e, 0x2154, 0x216b, 0x2182, 0x2198, 0x21af, 0x21c6, 0x21dd, 0x21f3,
+ 0x220a, 0x2221, 0x2238, 0x224f, 0x2266, 0x227d, 0x2294, 0x22ab, 0x22c2,
+ 0x22da, 0x22f1, 0x2308, 0x231f, 0x2337, 0x234e, 0x2365, 0x237d, 0x2394,
+ 0x23ac, 0x23c3, 0x23db, 0x23f2, 0x240a, 0x2421, 0x2439, 0x2451, 0x2469,
+ 0x2480, 0x2498, 0x24b0, 0x24c8, 0x24e0, 0x24f8, 0x2510, 0x2528, 0x2540,
+ 0x2558, 0x2570, 0x2588, 0x25a0, 0x25b8, 0x25d0, 0x25e9, 0x2601, 0x2619,
+ 0x2632, 0x264a, 0x2663, 0x267b, 0x2693, 0x26ac, 0x26c5, 0x26dd, 0x26f6,
+ 0x270e, 0x2727, 0x2740, 0x2759, 0x2771, 0x278a, 0x27a3, 0x27bc, 0x27d5,
+ 0x27ee, 0x2807, 0x2820, 0x2839, 0x2852, 0x286b, 0x2884, 0x289e, 0x28b7,
+ 0x28d0, 0x28e9, 0x2903, 0x291c, 0x2936, 0x294f, 0x2968, 0x2982, 0x299c,
+ 0x29b5, 0x29cf, 0x29e8, 0x2a02, 0x2a1c, 0x2a35, 0x2a4f, 0x2a69, 0x2a83,
+ 0x2a9d, 0x2ab7, 0x2ad1, 0x2aeb, 0x2b05, 0x2b1f, 0x2b39, 0x2b53, 0x2b6d,
+ 0x2b87, 0x2ba1, 0x2bbc, 0x2bd6, 0x2bf0, 0x2c0b, 0x2c25, 0x2c3f, 0x2c5a,
+ 0x2c74, 0x2c8f, 0x2ca9, 0x2cc4, 0x2cdf, 0x2cf9, 0x2d14, 0x2d2f, 0x2d49,
+ 0x2d64, 0x2d7f, 0x2d9a, 0x2db5, 0x2dd0, 0x2deb, 0x2e06, 0x2e21, 0x2e3c,
+ 0x2e57, 0x2e72, 0x2e8d, 0x2ea8, 0x2ec4, 0x2edf, 0x2efa, 0x2f16, 0x2f31,
+ 0x2f4c, 0x2f68, 0x2f83, 0x2f9f, 0x2fba, 0x2fd6, 0x2ff1, 0x300d, 0x3029,
+ 0x3044, 0x3060, 0x307c, 0x3098, 0x30b4, 0x30d0, 0x30eb, 0x3107, 0x3123,
+ 0x313f, 0x315b, 0x3178, 0x3194, 0x31b0, 0x31cc, 0x31e8, 0x3205, 0x3221,
+ 0x323d, 0x325a, 0x3276, 0x3292, 0x32af, 0x32cb, 0x32e8, 0x3304, 0x3321,
+ 0x333e, 0x335a, 0x3377, 0x3394, 0x33b1, 0x33cd, 0x33ea, 0x3407, 0x3424,
+ 0x3441, 0x345e, 0x347b, 0x3498, 0x34b5, 0x34d2, 0x34ef, 0x350d, 0x352a,
+ 0x3547, 0x3564, 0x3582, 0x359f, 0x35bc, 0x35da, 0x35f7, 0x3615, 0x3632,
+ 0x3650, 0x366e, 0x368b, 0x36a9, 0x36c7, 0x36e4, 0x3702, 0x3720, 0x373e,
+ 0x375c, 0x377a, 0x3798, 0x37b6, 0x37d4, 0x37f2, 0x3810, 0x382e, 0x384c,
+ 0x386a, 0x3888, 0x38a7, 0x38c5, 0x38e3, 0x3902, 0x3920, 0x393f, 0x395d,
+ 0x397c, 0x399a, 0x39b9, 0x39d7, 0x39f6, 0x3a15, 0x3a33, 0x3a52, 0x3a71,
+ 0x3a90, 0x3aaf, 0x3acd, 0x3aec, 0x3b0b, 0x3b2a, 0x3b49, 0x3b68, 0x3b87,
+ 0x3ba7, 0x3bc6, 0x3be5, 0x3c04, 0x3c24, 0x3c43, 0x3c62, 0x3c82, 0x3ca1,
+ 0x3cc0, 0x3ce0, 0x3cff, 0x3d1f, 0x3d3f, 0x3d5e, 0x3d7e, 0x3d9e, 0x3dbd,
+ 0x3ddd, 0x3dfd, 0x3e1d, 0x3e3d, 0x3e5d, 0x3e7c, 0x3e9c, 0x3ebc, 0x3edc,
+ 0x3efd, 0x3f1d, 0x3f3d, 0x3f5d, 0x3f7d, 0x3f9e, 0x3fbe, 0x3fde, 0x3fff,
+ 0x0,
+ /* table descriptor */
+ 0xffffe4e1, 0xf,
+ /* table length */
+ 0x402,
+ /* table data */
+ 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2,
+ 0x2, 0x2, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x6, 0x6, 0x6,
+ 0x7, 0x7, 0x8, 0x8, 0x9, 0x9, 0xa, 0xa, 0xb, 0xb, 0xc, 0xc, 0xd, 0xe,
+ 0xe, 0xf, 0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14, 0x15, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1f, 0x20, 0x22,
+ 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x31, 0x32, 0x33, 0x35, 0x36, 0x37, 0x39, 0x3a, 0x3c, 0x3d, 0x3f, 0x40,
+ 0x42, 0x43, 0x45, 0x47, 0x48, 0x4a, 0x4b, 0x4d, 0x4f, 0x51, 0x52, 0x54,
+ 0x56, 0x58, 0x5a, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65, 0x67, 0x69, 0x6b,
+ 0x6d, 0x6f, 0x71, 0x73, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 0x81, 0x83, 0x85,
+ 0x88, 0x8a, 0x8c, 0x8f, 0x91, 0x94, 0x96, 0x99, 0x9b, 0x9e, 0xa0, 0xa3,
+ 0xa6, 0xa8, 0xab, 0xae, 0xb0, 0xb3, 0xb6, 0xb9, 0xbb, 0xbe, 0xc1, 0xc4,
+ 0xc7, 0xca, 0xcd, 0xd0, 0xd3, 0xd6, 0xd9, 0xdc, 0xdf, 0xe2, 0xe6, 0xe9,
+ 0xec, 0xef, 0xf3, 0xf6, 0xf9, 0xfd, 0x100, 0x103, 0x107, 0x10a, 0x10e,
+ 0x111, 0x115, 0x118, 0x11c, 0x120, 0x123, 0x127, 0x12b, 0x12e, 0x132,
+ 0x136, 0x13a, 0x13e, 0x142, 0x145, 0x149, 0x14d, 0x151, 0x155, 0x159,
+ 0x15d, 0x162, 0x166, 0x16a, 0x16e, 0x172, 0x176, 0x17b, 0x17f, 0x183,
+ 0x188, 0x18c, 0x190, 0x195, 0x199, 0x19e, 0x1a2, 0x1a7, 0x1ab, 0x1b0,
+ 0x1b5, 0x1b9, 0x1be, 0x1c3, 0x1c7, 0x1cc, 0x1d1, 0x1d6, 0x1db, 0x1e0,
+ 0x1e4, 0x1e9, 0x1ee, 0x1f3, 0x1f8, 0x1fd, 0x203, 0x208, 0x20d, 0x212,
+ 0x217, 0x21c, 0x222, 0x227, 0x22c, 0x232, 0x237, 0x23d, 0x242, 0x247,
+ 0x24d, 0x253, 0x258, 0x25e, 0x263, 0x269, 0x26f, 0x274, 0x27a, 0x280,
+ 0x286, 0x28c, 0x291, 0x297, 0x29d, 0x2a3, 0x2a9, 0x2af, 0x2b5, 0x2bb,
+ 0x2c2, 0x2c8, 0x2ce, 0x2d4, 0x2da, 0x2e1, 0x2e7, 0x2ed, 0x2f4, 0x2fa,
+ 0x301, 0x307, 0x30e, 0x314, 0x31b, 0x321, 0x328, 0x32f, 0x335, 0x33c,
+ 0x343, 0x349, 0x350, 0x357, 0x35e, 0x365, 0x36c, 0x373, 0x37a, 0x381,
+ 0x388, 0x38f, 0x396, 0x39d, 0x3a5, 0x3ac, 0x3b3, 0x3ba, 0x3c2, 0x3c9,
+ 0x3d1, 0x3d8, 0x3e0, 0x3e7, 0x3ef, 0x3f6, 0x3fe, 0x405, 0x40d, 0x415,
+ 0x41c, 0x424, 0x42c, 0x434, 0x43c, 0x444, 0x44c, 0x454, 0x45c, 0x464,
+ 0x46c, 0x474, 0x47c, 0x484, 0x48c, 0x495, 0x49d, 0x4a5, 0x4ad, 0x4b6,
+ 0x4be, 0x4c7, 0x4cf, 0x4d8, 0x4e0, 0x4e9, 0x4f1, 0x4fa, 0x503, 0x50b,
+ 0x514, 0x51d, 0x526, 0x52f, 0x538, 0x540, 0x549, 0x552, 0x55b, 0x565,
+ 0x56e, 0x577, 0x580, 0x589, 0x592, 0x59c, 0x5a5, 0x5ae, 0x5b8, 0x5c1,
+ 0x5cb, 0x5d4, 0x5de, 0x5e7, 0x5f1, 0x5fa, 0x604, 0x60e, 0x617, 0x621,
+ 0x62b, 0x635, 0x63f, 0x649, 0x653, 0x65c, 0x666, 0x671, 0x67b, 0x685,
+ 0x68f, 0x699, 0x6a3, 0x6ae, 0x6b8, 0x6c2, 0x6cd, 0x6d7, 0x6e2, 0x6ec,
+ 0x6f7, 0x701, 0x70c, 0x716, 0x721, 0x72c, 0x736, 0x741, 0x74c, 0x757,
+ 0x762, 0x76d, 0x778, 0x783, 0x78e, 0x799, 0x7a4, 0x7af, 0x7ba, 0x7c5,
+ 0x7d1, 0x7dc, 0x7e7, 0x7f3, 0x7fe, 0x809, 0x815, 0x820, 0x82c, 0x838,
+ 0x843, 0x84f, 0x85b, 0x866, 0x872, 0x87e, 0x88a, 0x896, 0x8a2, 0x8ae,
+ 0x8ba, 0x8c6, 0x8d2, 0x8de, 0x8ea, 0x8f6, 0x902, 0x90f, 0x91b, 0x927,
+ 0x934, 0x940, 0x94d, 0x959, 0x966, 0x972, 0x97f, 0x98b, 0x998, 0x9a5,
+ 0x9b2, 0x9be, 0x9cb, 0x9d8, 0x9e5, 0x9f2, 0x9ff, 0xa0c, 0xa19, 0xa26,
+ 0xa33, 0xa41, 0xa4e, 0xa5b, 0xa68, 0xa76, 0xa83, 0xa90, 0xa9e, 0xaab,
+ 0xab9, 0xac7, 0xad4, 0xae2, 0xaf0, 0xafd, 0xb0b, 0xb19, 0xb27, 0xb35,
+ 0xb43, 0xb50, 0xb5f, 0xb6d, 0xb7b, 0xb89, 0xb97, 0xba5, 0xbb3, 0xbc2,
+ 0xbd0, 0xbde, 0xbed, 0xbfb, 0xc0a, 0xc18, 0xc27, 0xc35, 0xc44, 0xc53,
+ 0xc61, 0xc70, 0xc7f, 0xc8e, 0xc9d, 0xcac, 0xcbb, 0xcca, 0xcd9, 0xce8,
+ 0xcf7, 0xd06, 0xd15, 0xd25, 0xd34, 0xd43, 0xd52, 0xd62, 0xd71, 0xd81,
+ 0xd90, 0xda0, 0xdb0, 0xdbf, 0xdcf, 0xddf, 0xdee, 0xdfe, 0xe0e, 0xe1e,
+ 0xe2e, 0xe3e, 0xe4e, 0xe5e, 0xe6e, 0xe7e, 0xe8e, 0xe9f, 0xeaf, 0xebf,
+ 0xed0, 0xee0, 0xef0, 0xf01, 0xf11, 0xf22, 0xf32, 0xf43, 0xf54, 0xf65,
+ 0xf75, 0xf86, 0xf97, 0xfa8, 0xfb9, 0xfca, 0xfdb, 0xfec, 0xffd, 0x100e,
+ 0x101f, 0x1030, 0x1042, 0x1053, 0x1064, 0x1076, 0x1087, 0x1099, 0x10aa,
+ 0x10bc, 0x10cd, 0x10df, 0x10f1, 0x1102, 0x1114, 0x1126, 0x1138, 0x114a,
+ 0x115c, 0x116e, 0x1180, 0x1192, 0x11a4, 0x11b6, 0x11c8, 0x11da, 0x11ed,
+ 0x11ff, 0x1211, 0x1224, 0x1236, 0x1249, 0x125b, 0x126e, 0x1280, 0x1293,
+ 0x12a6, 0x12b8, 0x12cb, 0x12de, 0x12f1, 0x1304, 0x1317, 0x132a, 0x133d,
+ 0x1350, 0x1363, 0x1376, 0x1389, 0x139d, 0x13b0, 0x13c3, 0x13d7, 0x13ea,
+ 0x13fe, 0x1411, 0x1425, 0x1438, 0x144c, 0x1460, 0x1473, 0x1487, 0x149b,
+ 0x14af, 0x14c3, 0x14d7, 0x14eb, 0x14ff, 0x1513, 0x1527, 0x153b, 0x154f,
+ 0x1564, 0x1578, 0x158c, 0x15a1, 0x15b5, 0x15ca, 0x15de, 0x15f3, 0x1607,
+ 0x161c, 0x1631, 0x1645, 0x165a, 0x166f, 0x1684, 0x1699, 0x16ae, 0x16c3,
+ 0x16d8, 0x16ed, 0x1702, 0x1717, 0x172c, 0x1742, 0x1757, 0x176c, 0x1782,
+ 0x1797, 0x17ad, 0x17c2, 0x17d8, 0x17ee, 0x1803, 0x1819, 0x182f, 0x1845,
+ 0x185a, 0x1870, 0x1886, 0x189c, 0x18b2, 0x18c8, 0x18de, 0x18f5, 0x190b,
+ 0x1921, 0x1937, 0x194e, 0x1964, 0x197b, 0x1991, 0x19a8, 0x19be, 0x19d5,
+ 0x19eb, 0x1a02, 0x1a19, 0x1a30, 0x1a47, 0x1a5d, 0x1a74, 0x1a8b, 0x1aa2,
+ 0x1ab9, 0x1ad1, 0x1ae8, 0x1aff, 0x1b16, 0x1b2d, 0x1b45, 0x1b5c, 0x1b74,
+ 0x1b8b, 0x1ba3, 0x1bba, 0x1bd2, 0x1bea, 0x1c01, 0x1c19, 0x1c31, 0x1c49,
+ 0x1c61, 0x1c78, 0x1c90, 0x1ca8, 0x1cc1, 0x1cd9, 0x1cf1, 0x1d09, 0x1d21,
+ 0x1d3a, 0x1d52, 0x1d6a, 0x1d83, 0x1d9b, 0x1db4, 0x1dcc, 0x1de5, 0x1dfe,
+ 0x1e17, 0x1e2f, 0x1e48, 0x1e61, 0x1e7a, 0x1e93, 0x1eac, 0x1ec5, 0x1ede,
+ 0x1ef7, 0x1f10, 0x1f2a, 0x1f43, 0x1f5c, 0x1f76, 0x1f8f, 0x1fa8, 0x1fc2,
+ 0x1fdc, 0x1ff5, 0x200f, 0x2029, 0x2042, 0x205c, 0x2076, 0x2090, 0x20aa,
+ 0x20c4, 0x20de, 0x20f8, 0x2112, 0x212c, 0x2146, 0x2161, 0x217b, 0x2195,
+ 0x21b0, 0x21ca, 0x21e5, 0x21ff, 0x221a, 0x2234, 0x224f, 0x226a, 0x2285,
+ 0x22a0, 0x22ba, 0x22d5, 0x22f0, 0x230b, 0x2326, 0x2342, 0x235d, 0x2378,
+ 0x2393, 0x23af, 0x23ca, 0x23e5, 0x2401, 0x241c, 0x2438, 0x2453, 0x246f,
+ 0x248b, 0x24a7, 0x24c2, 0x24de, 0x24fa, 0x2516, 0x2532, 0x254e, 0x256a,
+ 0x2586, 0x25a2, 0x25bf, 0x25db, 0x25f7, 0x2614, 0x2630, 0x264c, 0x2669,
+ 0x2685, 0x26a2, 0x26bf, 0x26db, 0x26f8, 0x2715, 0x2732, 0x274f, 0x276c,
+ 0x2789, 0x27a6, 0x27c3, 0x27e0, 0x27fd, 0x281a, 0x2838, 0x2855, 0x2872,
+ 0x2890, 0x28ad, 0x28cb, 0x28e8, 0x2906, 0x2924, 0x2942, 0x295f, 0x297d,
+ 0x299b, 0x29b9, 0x29d7, 0x29f5, 0x2a13, 0x2a31, 0x2a4f, 0x2a6d, 0x2a8c,
+ 0x2aaa, 0x2ac8, 0x2ae7, 0x2b05, 0x2b24, 0x2b42, 0x2b61, 0x2b80, 0x2b9e,
+ 0x2bbd, 0x2bdc, 0x2bfb, 0x2c1a, 0x2c39, 0x2c58, 0x2c77, 0x2c96, 0x2cb5,
+ 0x2cd4, 0x2cf3, 0x2d13, 0x2d32, 0x2d51, 0x2d71, 0x2d90, 0x2db0, 0x2dd0,
+ 0x2def, 0x2e0f, 0x2e2f, 0x2e4f, 0x2e6e, 0x2e8e, 0x2eae, 0x2ece, 0x2eee,
+ 0x2f0e, 0x2f2f, 0x2f4f, 0x2f6f, 0x2f8f, 0x2fb0, 0x2fd0, 0x2ff0, 0x3011,
+ 0x3032, 0x3052, 0x3073, 0x3093, 0x30b4, 0x30d5, 0x30f6, 0x3117, 0x3138,
+ 0x3159, 0x317a, 0x319b, 0x31bc, 0x31dd, 0x31fe, 0x3220, 0x3241, 0x3263,
+ 0x3284, 0x32a6, 0x32c7, 0x32e9, 0x330a, 0x332c, 0x334e, 0x3370, 0x3392,
+ 0x33b3, 0x33d5, 0x33f7, 0x3419, 0x343c, 0x345e, 0x3480, 0x34a2, 0x34c5,
+ 0x34e7, 0x3509, 0x352c, 0x354e, 0x3571, 0x3594, 0x35b6, 0x35d9, 0x35fc,
+ 0x361f, 0x3641, 0x3664, 0x3687, 0x36aa, 0x36cd, 0x36f1, 0x3714, 0x3737,
+ 0x375a, 0x377e, 0x37a1, 0x37c5, 0x37e8, 0x380c, 0x382f, 0x3853, 0x3876,
+ 0x389a, 0x38be, 0x38e2, 0x3906, 0x392a, 0x394e, 0x3972, 0x3996, 0x39ba,
+ 0x39de, 0x3a03, 0x3a27, 0x3a4b, 0x3a70, 0x3a94, 0x3ab9, 0x3add, 0x3b02,
+ 0x3b27, 0x3b4b, 0x3b70, 0x3b95, 0x3bba, 0x3bdf, 0x3c04, 0x3c29, 0x3c4e,
+ 0x3c73, 0x3c98, 0x3cbe, 0x3ce3, 0x3d08, 0x3d2e, 0x3d53, 0x3d79, 0x3d9e,
+ 0x3dc4, 0x3dea, 0x3e0f, 0x3e35, 0x3e5b, 0x3e81, 0x3ea7, 0x3ecd, 0x3ef3,
+ 0x3f19, 0x3f3f, 0x3f65, 0x3f8b, 0x3fb2, 0x3fd8, 0x3fff, 0x0,
+ /* table descriptor */
+ 0xfff0e8e1, 0xf,
+ /* table length */
+ 0x402,
+ /* table data */
+ 0x3, 0x0, 0xea8, 0x12aa, 0x1500, 0x16ab, 0x1815, 0x1900, 0x1a0b,
+ 0x1aab, 0x1b60, 0x1c15, 0x1c85, 0x1d00, 0x1d86, 0x1e0b, 0x1e58, 0x1eab,
+ 0x1f03, 0x1f60, 0x1fc3, 0x2015, 0x204c, 0x2085, 0x20c2, 0x2100, 0x2142,
+ 0x2186, 0x21cc, 0x220b, 0x2231, 0x2258, 0x2281, 0x22ab, 0x22d6, 0x2303,
+ 0x2331, 0x2360, 0x2391, 0x23c3, 0x23f6, 0x2415, 0x2430, 0x244c, 0x2468,
+ 0x2485, 0x24a3, 0x24c2, 0x24e1, 0x2500, 0x2521, 0x2542, 0x2563, 0x2586,
+ 0x25a9, 0x25cc, 0x25f1, 0x260b, 0x261e, 0x2631, 0x2644, 0x2658, 0x266c,
+ 0x2681, 0x2696, 0x26ab, 0x26c0, 0x26d6, 0x26ec, 0x2703, 0x271a, 0x2731,
+ 0x2748, 0x2760, 0x2779, 0x2791, 0x27aa, 0x27c3, 0x27dd, 0x27f6, 0x2808,
+ 0x2815, 0x2823, 0x2830, 0x283e, 0x284c, 0x285a, 0x2868, 0x2877, 0x2885,
+ 0x2894, 0x28a3, 0x28b2, 0x28c2, 0x28d1, 0x28e1, 0x28f0, 0x2900, 0x2910,
+ 0x2921, 0x2931, 0x2942, 0x2952, 0x2963, 0x2974, 0x2986, 0x2997, 0x29a9,
+ 0x29bb, 0x29cc, 0x29df, 0x29f1, 0x2a01, 0x2a0b, 0x2a14, 0x2a1e, 0x2a27,
+ 0x2a31, 0x2a3a, 0x2a44, 0x2a4e, 0x2a58, 0x2a62, 0x2a6c, 0x2a76, 0x2a81,
+ 0x2a8b, 0x2a96, 0x2aa0, 0x2aab, 0x2ab6, 0x2ac0, 0x2acb, 0x2ad6, 0x2ae1,
+ 0x2aec, 0x2af8, 0x2b03, 0x2b0e, 0x2b1a, 0x2b25, 0x2b31, 0x2b3d, 0x2b48,
+ 0x2b54, 0x2b60, 0x2b6c, 0x2b79, 0x2b85, 0x2b91, 0x2b9d, 0x2baa, 0x2bb6,
+ 0x2bc3, 0x2bd0, 0x2bdd, 0x2bea, 0x2bf6, 0x2c02, 0x2c08, 0x2c0f, 0x2c15,
+ 0x2c1c, 0x2c23, 0x2c2a, 0x2c30, 0x2c37, 0x2c3e, 0x2c45, 0x2c4c, 0x2c53,
+ 0x2c5a, 0x2c61, 0x2c68, 0x2c70, 0x2c77, 0x2c7e, 0x2c85, 0x2c8d, 0x2c94,
+ 0x2c9c, 0x2ca3, 0x2cab, 0x2cb2, 0x2cba, 0x2cc2, 0x2cc9, 0x2cd1, 0x2cd9,
+ 0x2ce1, 0x2ce8, 0x2cf0, 0x2cf8, 0x2d00, 0x2d08, 0x2d10, 0x2d18, 0x2d21,
+ 0x2d29, 0x2d31, 0x2d39, 0x2d42, 0x2d4a, 0x2d52, 0x2d5b, 0x2d63, 0x2d6c,
+ 0x2d74, 0x2d7d, 0x2d86, 0x2d8e, 0x2d97, 0x2da0, 0x2da9, 0x2db2, 0x2dbb,
+ 0x2dc3, 0x2dcc, 0x2dd5, 0x2ddf, 0x2de8, 0x2df1, 0x2dfa, 0x2e01, 0x2e06,
+ 0x2e0b, 0x2e0f, 0x2e14, 0x2e19, 0x2e1e, 0x2e22, 0x2e27, 0x2e2c, 0x2e31,
+ 0x2e36, 0x2e3a, 0x2e3f, 0x2e44, 0x2e49, 0x2e4e, 0x2e53, 0x2e58, 0x2e5d,
+ 0x2e62, 0x2e67, 0x2e6c, 0x2e71, 0x2e76, 0x2e7c, 0x2e81, 0x2e86, 0x2e8b,
+ 0x2e90, 0x2e96, 0x2e9b, 0x2ea0, 0x2ea6, 0x2eab, 0x2eb0, 0x2eb6, 0x2ebb,
+ 0x2ec0, 0x2ec6, 0x2ecb, 0x2ed1, 0x2ed6, 0x2edc, 0x2ee1, 0x2ee7, 0x2eec,
+ 0x2ef2, 0x2ef8, 0x2efd, 0x2f03, 0x2f09, 0x2f0e, 0x2f14, 0x2f1a, 0x2f20,
+ 0x2f25, 0x2f2b, 0x2f31, 0x2f37, 0x2f3d, 0x2f43, 0x2f48, 0x2f4e, 0x2f54,
+ 0x2f5a, 0x2f60, 0x2f66, 0x2f6c, 0x2f72, 0x2f79, 0x2f7f, 0x2f85, 0x2f8b,
+ 0x2f91, 0x2f97, 0x2f9d, 0x2fa4, 0x2faa, 0x2fb0, 0x2fb6, 0x2fbd, 0x2fc3,
+ 0x2fc9, 0x2fd0, 0x2fd6, 0x2fdd, 0x2fe3, 0x2fea, 0x2ff0, 0x2ff6, 0x2ffd,
+ 0x3002, 0x3005, 0x3008, 0x300b, 0x300f, 0x3012, 0x3015, 0x3019, 0x301c,
+ 0x301f, 0x3023, 0x3026, 0x302a, 0x302d, 0x3030, 0x3034, 0x3037, 0x303b,
+ 0x303e, 0x3042, 0x3045, 0x3049, 0x304c, 0x3050, 0x3053, 0x3057, 0x305a,
+ 0x305e, 0x3061, 0x3065, 0x3068, 0x306c, 0x3070, 0x3073, 0x3077, 0x307b,
+ 0x307e, 0x3082, 0x3085, 0x3089, 0x308d, 0x3091, 0x3094, 0x3098, 0x309c,
+ 0x309f, 0x30a3, 0x30a7, 0x30ab, 0x30ae, 0x30b2, 0x30b6, 0x30ba, 0x30be,
+ 0x30c2, 0x30c5, 0x30c9, 0x30cd, 0x30d1, 0x30d5, 0x30d9, 0x30dd, 0x30e1,
+ 0x30e4, 0x30e8, 0x30ec, 0x30f0, 0x30f4, 0x30f8, 0x30fc, 0x3100, 0x3104,
+ 0x3108, 0x310c, 0x3110, 0x3114, 0x3118, 0x311d, 0x3121, 0x3125, 0x3129,
+ 0x312d, 0x3131, 0x3135, 0x3139, 0x313d, 0x3142, 0x3146, 0x314a, 0x314e,
+ 0x3152, 0x3157, 0x315b, 0x315f, 0x3163, 0x3168, 0x316c, 0x3170, 0x3174,
+ 0x3179, 0x317d, 0x3181, 0x3186, 0x318a, 0x318e, 0x3193, 0x3197, 0x319c,
+ 0x31a0, 0x31a4, 0x31a9, 0x31ad, 0x31b2, 0x31b6, 0x31bb, 0x31bf, 0x31c3,
+ 0x31c8, 0x31cc, 0x31d1, 0x31d5, 0x31da, 0x31df, 0x31e3, 0x31e8, 0x31ec,
+ 0x31f1, 0x31f5, 0x31fa, 0x31ff, 0x3201, 0x3204, 0x3206, 0x3208, 0x320b,
+ 0x320d, 0x320f, 0x3212, 0x3214, 0x3216, 0x3219, 0x321b, 0x321e, 0x3220,
+ 0x3222, 0x3225, 0x3227, 0x3229, 0x322c, 0x322e, 0x3231, 0x3233, 0x3236,
+ 0x3238, 0x323a, 0x323d, 0x323f, 0x3242, 0x3244, 0x3247, 0x3249, 0x324c,
+ 0x324e, 0x3251, 0x3253, 0x3256, 0x3258, 0x325b, 0x325d, 0x3260, 0x3262,
+ 0x3265, 0x3267, 0x326a, 0x326c, 0x326f, 0x3271, 0x3274, 0x3276, 0x3279,
+ 0x327c, 0x327e, 0x3281, 0x3283, 0x3286, 0x3289, 0x328b, 0x328e, 0x3290,
+ 0x3293, 0x3296, 0x3298, 0x329b, 0x329e, 0x32a0, 0x32a3, 0x32a6, 0x32a8,
+ 0x32ab, 0x32ae, 0x32b0, 0x32b3, 0x32b6, 0x32b8, 0x32bb, 0x32be, 0x32c1,
+ 0x32c4, 0x32c6, 0x32c9, 0x32cc, 0x32cf, 0x32d2, 0x32d5, 0x32d8, 0x32da,
+ 0x32dd, 0x32e0, 0x32e3, 0x32e6, 0x32e9, 0x32ec, 0x32ef, 0x32f2, 0x32f6,
+ 0x32f9, 0x32fc, 0x32ff, 0x3302, 0x3305, 0x3308, 0x330c, 0x330f, 0x3312,
+ 0x3315, 0x3318, 0x331c, 0x331f, 0x3322, 0x3326, 0x3329, 0x332c, 0x3330,
+ 0x3333, 0x3337, 0x333a, 0x333e, 0x3341, 0x3345, 0x3348, 0x334c, 0x334f,
+ 0x3353, 0x3356, 0x335a, 0x335e, 0x3361, 0x3365, 0x3369, 0x336c, 0x3370,
+ 0x3374, 0x3378, 0x337c, 0x337f, 0x3383, 0x3387, 0x338b, 0x338f, 0x3393,
+ 0x3397, 0x339b, 0x339f, 0x33a3, 0x33a7, 0x33ab, 0x33af, 0x33b3, 0x33b7,
+ 0x33bb, 0x33bf, 0x33c4, 0x33c8, 0x33cc, 0x33d0, 0x33d5, 0x33d9, 0x33dd,
+ 0x33e2, 0x33e6, 0x33eb, 0x33ef, 0x33f3, 0x33f8, 0x33fc, 0x3400, 0x3402,
+ 0x3405, 0x3407, 0x3409, 0x340c, 0x340e, 0x3410, 0x3413, 0x3415, 0x3418,
+ 0x341a, 0x341c, 0x341f, 0x3421, 0x3424, 0x3426, 0x3429, 0x342b, 0x342e,
+ 0x3430, 0x3433, 0x3435, 0x3438, 0x343a, 0x343d, 0x3440, 0x3442, 0x3445,
+ 0x3448, 0x344a, 0x344d, 0x3450, 0x3452, 0x3455, 0x3458, 0x345b, 0x345d,
+ 0x3460, 0x3463, 0x3466, 0x3469, 0x346b, 0x346e, 0x3471, 0x3474, 0x3477,
+ 0x347a, 0x347d, 0x3480, 0x3483, 0x3486, 0x3489, 0x348c, 0x348f, 0x3492,
+ 0x3495, 0x3498, 0x349b, 0x349e, 0x34a2, 0x34a5, 0x34a8, 0x34ab, 0x34ae,
+ 0x34b2, 0x34b5, 0x34b8, 0x34bb, 0x34bf, 0x34c2, 0x34c5, 0x34c9, 0x34cc,
+ 0x34cf, 0x34d3, 0x34d6, 0x34da, 0x34dd, 0x34e1, 0x34e4, 0x34e8, 0x34eb,
+ 0x34ef, 0x34f2, 0x34f6, 0x34fa, 0x34fd, 0x3501, 0x3505, 0x3508, 0x350c,
+ 0x3510, 0x3514, 0x3517, 0x351b, 0x351f, 0x3523, 0x3527, 0x352b, 0x352f,
+ 0x3532, 0x3536, 0x353a, 0x353e, 0x3542, 0x3546, 0x354b, 0x354f, 0x3553,
+ 0x3557, 0x355b, 0x355f, 0x3563, 0x3568, 0x356c, 0x3570, 0x3574, 0x3579,
+ 0x357d, 0x3581, 0x3586, 0x358a, 0x358f, 0x3593, 0x3598, 0x359c, 0x35a1,
+ 0x35a5, 0x35aa, 0x35ae, 0x35b3, 0x35b8, 0x35bc, 0x35c1, 0x35c6, 0x35cb,
+ 0x35cf, 0x35d4, 0x35d9, 0x35de, 0x35e3, 0x35e8, 0x35ed, 0x35f2, 0x35f7,
+ 0x35fc, 0x3600, 0x3603, 0x3605, 0x3608, 0x360a, 0x360d, 0x3610, 0x3612,
+ 0x3615, 0x3618, 0x361a, 0x361d, 0x3620, 0x3622, 0x3625, 0x3628, 0x362b,
+ 0x362d, 0x3630, 0x3633, 0x3636, 0x3639, 0x363b, 0x363e, 0x3641, 0x3644,
+ 0x3647, 0x364a, 0x364d, 0x3650, 0x3653, 0x3656, 0x3659, 0x365c, 0x365f,
+ 0x3662, 0x3665, 0x3668, 0x366b, 0x366e, 0x3672, 0x3675, 0x3678, 0x367b,
+ 0x367e, 0x3682, 0x3685, 0x3688, 0x368b, 0x368f, 0x3692, 0x3695, 0x3699,
+ 0x369c, 0x36a0, 0x36a3, 0x36a6, 0x36aa, 0x36ad, 0x36b1, 0x36b4, 0x36b8,
+ 0x36bb, 0x36bf, 0x36c3, 0x36c6, 0x36ca, 0x36cd, 0x36d1, 0x36d5, 0x36d9,
+ 0x36dc, 0x36e0, 0x36e4, 0x36e8, 0x36eb, 0x36ef, 0x36f3, 0x36f7, 0x36fb,
+ 0x36ff, 0x3703, 0x3707, 0x370b, 0x370f, 0x3713, 0x3717, 0x371b, 0x371f,
+ 0x3723, 0x3727, 0x372b, 0x372f, 0x3734, 0x3738, 0x373c, 0x3740, 0x3745,
+ 0x3749, 0x374d, 0x3752, 0x3756, 0x375b, 0x375f, 0x3764, 0x3768, 0x376d,
+ 0x3771, 0x3776, 0x377a, 0x377f, 0x3783, 0x3788, 0x378d, 0x3792, 0x3796,
+ 0x379b, 0x37a0, 0x37a5, 0x37aa, 0x37ae, 0x37b3, 0x37b8, 0x37bd, 0x37c2,
+ 0x37c7, 0x37cc, 0x37d1, 0x37d6, 0x37dc, 0x37e1, 0x37e6, 0x37eb, 0x37f0,
+ 0x37f6, 0x37fb, 0x3800, 0x3802, 0x3805, 0x3808, 0x380b, 0x380d, 0x3810,
+ 0x3813, 0x3816, 0x3818, 0x381b, 0x381e, 0x3821, 0x3824, 0x3827, 0x382a,
+ 0x382c, 0x382f, 0x3832, 0x3835, 0x3838, 0x383b, 0x383e, 0x3841, 0x3844,
+ 0x3847, 0x384a, 0x384d, 0x3851, 0x3854, 0x3857, 0x385a, 0x385d, 0x3860,
+ 0x3864, 0x3867, 0x386a, 0x386d, 0x3870, 0x3874, 0x3877, 0x387a, 0x387e,
+ 0x3881, 0x3885, 0x3888, 0x388b, 0x388f, 0x3892, 0x3896, 0x3899, 0x389d,
+ 0x38a0, 0x38a4, 0x38a7, 0x38ab, 0x38af, 0x38b2, 0x38b6, 0x38ba, 0x38bd,
+ 0x38c1, 0x38c5, 0x38c8, 0x38cc, 0x38d0, 0x38d4, 0x38d8, 0x38dc, 0x38df,
+ 0x38e3, 0x38e7, 0x38eb, 0x38ef, 0x38f3, 0x38f7, 0x38fb, 0x38ff, 0x3903,
+ 0x3907, 0x390c, 0x3910, 0x3914, 0x3918, 0x391c, 0x3920, 0x3925, 0x3929,
+ 0x392d, 0x3932, 0x3936, 0x393a, 0x393f, 0x3943, 0x3948, 0x394c, 0x3951,
+ 0x3955, 0x395a, 0x395e, 0x3963, 0x3967, 0x396c, 0x3971, 0x3975, 0x397a,
+ 0x397f, 0x3984, 0x3989, 0x398d, 0x3992, 0x3997, 0x399c, 0x39a1, 0x39a6,
+ 0x39ab, 0x39b0, 0x39b5, 0x39ba, 0x39bf, 0x39c4, 0x39c9, 0x39cf, 0x39d4,
+ 0x39d9, 0x39de, 0x39e4, 0x39e9, 0x39ee, 0x39f4, 0x39f9, 0x39ff, 0x3,
+ /* table descriptor */
+ 0xfffff0e1, 0xf,
+ /* table length */
+ 0x402,
+ /* table data */
+ 0x3, 0x0, 0x1, 0x2, 0x3, 0x4, 0x6, 0x7, 0x8, 0x9, 0xb, 0xc, 0xd, 0xe,
+ 0x10, 0x11, 0x12, 0x13, 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1d,
+ 0x1e, 0x20, 0x21, 0x22, 0x23, 0x25, 0x26, 0x27, 0x28, 0x2a, 0x2b, 0x2c,
+ 0x2d, 0x2f, 0x30, 0x31, 0x32, 0x34, 0x35, 0x36, 0x37, 0x39, 0x3a, 0x3c,
+ 0x3d, 0x3e, 0x40, 0x41, 0x43, 0x44, 0x46, 0x47, 0x49, 0x4a, 0x4c, 0x4d,
+ 0x4f, 0x51, 0x52, 0x54, 0x56, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x60, 0x62,
+ 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a,
+ 0x7c, 0x7e, 0x80, 0x82, 0x85, 0x87, 0x89, 0x8b, 0x8e, 0x90, 0x92, 0x94,
+ 0x97, 0x99, 0x9c, 0x9e, 0xa0, 0xa3, 0xa5, 0xa8, 0xaa, 0xad, 0xb0, 0xb2,
+ 0xb5, 0xb7, 0xba, 0xbd, 0xc0, 0xc2, 0xc5, 0xc8, 0xcb, 0xcd, 0xd0, 0xd3,
+ 0xd6, 0xd9, 0xdc, 0xdf, 0xe2, 0xe5, 0xe8, 0xeb, 0xee, 0xf1, 0xf4, 0xf7,
+ 0xfb, 0xfe, 0x101, 0x104, 0x108, 0x10b, 0x10e, 0x111, 0x115, 0x118,
+ 0x11c, 0x11f, 0x123, 0x126, 0x12a, 0x12d, 0x131, 0x134, 0x138, 0x13b,
+ 0x13f, 0x143, 0x146, 0x14a, 0x14e, 0x152, 0x155, 0x159, 0x15d, 0x161,
+ 0x165, 0x169, 0x16d, 0x171, 0x175, 0x179, 0x17d, 0x181, 0x185, 0x189,
+ 0x18d, 0x192, 0x196, 0x19a, 0x19e, 0x1a2, 0x1a7, 0x1ab, 0x1af, 0x1b4,
+ 0x1b8, 0x1bd, 0x1c1, 0x1c6, 0x1ca, 0x1cf, 0x1d3, 0x1d8, 0x1dc, 0x1e1,
+ 0x1e6, 0x1ea, 0x1ef, 0x1f4, 0x1f9, 0x1fe, 0x202, 0x207, 0x20c, 0x211,
+ 0x216, 0x21b, 0x220, 0x225, 0x22a, 0x22f, 0x234, 0x239, 0x23e, 0x244,
+ 0x249, 0x24e, 0x253, 0x258, 0x25e, 0x263, 0x269, 0x26e, 0x273, 0x279,
+ 0x27e, 0x284, 0x289, 0x28f, 0x294, 0x29a, 0x2a0, 0x2a5, 0x2ab, 0x2b1,
+ 0x2b7, 0x2bc, 0x2c2, 0x2c8, 0x2ce, 0x2d4, 0x2da, 0x2e0, 0x2e6, 0x2ec,
+ 0x2f2, 0x2f8, 0x2fe, 0x304, 0x30a, 0x310, 0x316, 0x31d, 0x323, 0x329,
+ 0x32f, 0x336, 0x33c, 0x343, 0x349, 0x350, 0x356, 0x35d, 0x363, 0x36a,
+ 0x370, 0x377, 0x37e, 0x384, 0x38b, 0x392, 0x398, 0x39f, 0x3a6, 0x3ad,
+ 0x3b4, 0x3bb, 0x3c2, 0x3c9, 0x3d0, 0x3d7, 0x3de, 0x3e5, 0x3ec, 0x3f3,
+ 0x3fb, 0x402, 0x409, 0x410, 0x418, 0x41f, 0x426, 0x42e, 0x435, 0x43d,
+ 0x444, 0x44c, 0x453, 0x45b, 0x462, 0x46a, 0x472, 0x479, 0x481, 0x489,
+ 0x491, 0x499, 0x4a0, 0x4a8, 0x4b0, 0x4b8, 0x4c0, 0x4c8, 0x4d0, 0x4d8,
+ 0x4e0, 0x4e8, 0x4f1, 0x4f9, 0x501, 0x509, 0x512, 0x51a, 0x522, 0x52b,
+ 0x533, 0x53b, 0x544, 0x54c, 0x555, 0x55e, 0x566, 0x56f, 0x577, 0x580,
+ 0x589, 0x592, 0x59a, 0x5a3, 0x5ac, 0x5b5, 0x5be, 0x5c7, 0x5d0, 0x5d9,
+ 0x5e2, 0x5eb, 0x5f4, 0x5fd, 0x606, 0x60f, 0x619, 0x622, 0x62b, 0x635,
+ 0x63e, 0x647, 0x651, 0x65a, 0x664, 0x66d, 0x677, 0x680, 0x68a, 0x694,
+ 0x69d, 0x6a7, 0x6b1, 0x6bb, 0x6c4, 0x6ce, 0x6d8, 0x6e2, 0x6ec, 0x6f6,
+ 0x700, 0x70a, 0x714, 0x71e, 0x728, 0x732, 0x73d, 0x747, 0x751, 0x75b,
+ 0x766, 0x770, 0x77a, 0x785, 0x78f, 0x79a, 0x7a4, 0x7af, 0x7ba, 0x7c4,
+ 0x7cf, 0x7da, 0x7e4, 0x7ef, 0x7fa, 0x805, 0x810, 0x81a, 0x825, 0x830,
+ 0x83b, 0x846, 0x851, 0x85d, 0x868, 0x873, 0x87e, 0x889, 0x895, 0x8a0,
+ 0x8ab, 0x8b7, 0x8c2, 0x8cd, 0x8d9, 0x8e4, 0x8f0, 0x8fb, 0x907, 0x913,
+ 0x91e, 0x92a, 0x936, 0x942, 0x94d, 0x959, 0x965, 0x971, 0x97d, 0x989,
+ 0x995, 0x9a1, 0x9ad, 0x9b9, 0x9c5, 0x9d2, 0x9de, 0x9ea, 0x9f6, 0xa03,
+ 0xa0f, 0xa1c, 0xa28, 0xa34, 0xa41, 0xa4d, 0xa5a, 0xa67, 0xa73, 0xa80,
+ 0xa8d, 0xa99, 0xaa6, 0xab3, 0xac0, 0xacd, 0xada, 0xae7, 0xaf4, 0xb01,
+ 0xb0e, 0xb1b, 0xb28, 0xb35, 0xb42, 0xb50, 0xb5d, 0xb6a, 0xb77, 0xb85,
+ 0xb92, 0xba0, 0xbad, 0xbbb, 0xbc8, 0xbd6, 0xbe4, 0xbf1, 0xbff, 0xc0d,
+ 0xc1a, 0xc28, 0xc36, 0xc44, 0xc52, 0xc60, 0xc6e, 0xc7c, 0xc8a, 0xc98,
+ 0xca6, 0xcb4, 0xcc3, 0xcd1, 0xcdf, 0xced, 0xcfc, 0xd0a, 0xd19, 0xd27,
+ 0xd35, 0xd44, 0xd53, 0xd61, 0xd70, 0xd7e, 0xd8d, 0xd9c, 0xdab, 0xdba,
+ 0xdc8, 0xdd7, 0xde6, 0xdf5, 0xe04, 0xe13, 0xe22, 0xe31, 0xe41, 0xe50,
+ 0xe5f, 0xe6e, 0xe7e, 0xe8d, 0xe9c, 0xeac, 0xebb, 0xecb, 0xeda, 0xeea,
+ 0xef9, 0xf09, 0xf19, 0xf28, 0xf38, 0xf48, 0xf58, 0xf68, 0xf77, 0xf87,
+ 0xf97, 0xfa7, 0xfb7, 0xfc7, 0xfd8, 0xfe8, 0xff8, 0x1008, 0x1018,
+ 0x1029, 0x1039, 0x1049, 0x105a, 0x106a, 0x107b, 0x108b, 0x109c, 0x10ad,
+ 0x10bd, 0x10ce, 0x10df, 0x10ef, 0x1100, 0x1111, 0x1122, 0x1133, 0x1144,
+ 0x1155, 0x1166, 0x1177, 0x1188, 0x1199, 0x11aa, 0x11bb, 0x11cd, 0x11de,
+ 0x11ef, 0x1201, 0x1212, 0x1223, 0x1235, 0x1246, 0x1258, 0x126a, 0x127b,
+ 0x128d, 0x129f, 0x12b0, 0x12c2, 0x12d4, 0x12e6, 0x12f8, 0x130a, 0x131c,
+ 0x132e, 0x1340, 0x1352, 0x1364, 0x1376, 0x1388, 0x139b, 0x13ad, 0x13bf,
+ 0x13d2, 0x13e4, 0x13f6, 0x1409, 0x141c, 0x142e, 0x1441, 0x1453, 0x1466,
+ 0x1479, 0x148b, 0x149e, 0x14b1, 0x14c4, 0x14d7, 0x14ea, 0x14fd, 0x1510,
+ 0x1523, 0x1536, 0x1549, 0x155c, 0x1570, 0x1583, 0x1596, 0x15aa, 0x15bd,
+ 0x15d0, 0x15e4, 0x15f7, 0x160b, 0x161e, 0x1632, 0x1646, 0x1659, 0x166d,
+ 0x1681, 0x1695, 0x16a9, 0x16bd, 0x16d1, 0x16e4, 0x16f9, 0x170d, 0x1721,
+ 0x1735, 0x1749, 0x175d, 0x1771, 0x1786, 0x179a, 0x17af, 0x17c3, 0x17d7,
+ 0x17ec, 0x1800, 0x1815, 0x182a, 0x183e, 0x1853, 0x1868, 0x187d, 0x1891,
+ 0x18a6, 0x18bb, 0x18d0, 0x18e5, 0x18fa, 0x190f, 0x1924, 0x1939, 0x194f,
+ 0x1964, 0x1979, 0x198e, 0x19a4, 0x19b9, 0x19cf, 0x19e4, 0x19fa, 0x1a0f,
+ 0x1a25, 0x1a3a, 0x1a50, 0x1a66, 0x1a7b, 0x1a91, 0x1aa7, 0x1abd, 0x1ad3,
+ 0x1ae9, 0x1aff, 0x1b15, 0x1b2b, 0x1b41, 0x1b57, 0x1b6d, 0x1b84, 0x1b9a,
+ 0x1bb0, 0x1bc7, 0x1bdd, 0x1bf4, 0x1c0a, 0x1c21, 0x1c37, 0x1c4e, 0x1c64,
+ 0x1c7b, 0x1c92, 0x1ca9, 0x1cbf, 0x1cd6, 0x1ced, 0x1d04, 0x1d1b, 0x1d32,
+ 0x1d49, 0x1d60, 0x1d78, 0x1d8f, 0x1da6, 0x1dbd, 0x1dd5, 0x1dec, 0x1e03,
+ 0x1e1b, 0x1e32, 0x1e4a, 0x1e61, 0x1e79, 0x1e91, 0x1ea8, 0x1ec0, 0x1ed8,
+ 0x1ef0, 0x1f07, 0x1f1f, 0x1f37, 0x1f4f, 0x1f67, 0x1f7f, 0x1f98, 0x1fb0,
+ 0x1fc8, 0x1fe0, 0x1ff8, 0x2011, 0x2029, 0x2042, 0x205a, 0x2072, 0x208b,
+ 0x20a4, 0x20bc, 0x20d5, 0x20ee, 0x2106, 0x211f, 0x2138, 0x2151, 0x216a,
+ 0x2183, 0x219c, 0x21b5, 0x21ce, 0x21e7, 0x2200, 0x2219, 0x2233, 0x224c,
+ 0x2265, 0x227f, 0x2298, 0x22b2, 0x22cb, 0x22e5, 0x22fe, 0x2318, 0x2331,
+ 0x234b, 0x2365, 0x237f, 0x2399, 0x23b3, 0x23cc, 0x23e6, 0x2401, 0x241b,
+ 0x2435, 0x244f, 0x2469, 0x2483, 0x249e, 0x24b8, 0x24d2, 0x24ed, 0x2507,
+ 0x2522, 0x253c, 0x2557, 0x2571, 0x258c, 0x25a7, 0x25c2, 0x25dc, 0x25f7,
+ 0x2612, 0x262d, 0x2648, 0x2663, 0x267e, 0x2699, 0x26b4, 0x26cf, 0x26eb,
+ 0x2706, 0x2721, 0x273d, 0x2758, 0x2774, 0x278f, 0x27ab, 0x27c6, 0x27e2,
+ 0x27fd, 0x2819, 0x2835, 0x2851, 0x286d, 0x2888, 0x28a4, 0x28c0, 0x28dc,
+ 0x28f8, 0x2915, 0x2931, 0x294d, 0x2969, 0x2985, 0x29a2, 0x29be, 0x29db,
+ 0x29f7, 0x2a14, 0x2a30, 0x2a4d, 0x2a69, 0x2a86, 0x2aa3, 0x2ac0, 0x2adc,
+ 0x2af9, 0x2b16, 0x2b33, 0x2b50, 0x2b6d, 0x2b8a, 0x2ba7, 0x2bc4, 0x2be2,
+ 0x2bff, 0x2c1c, 0x2c3a, 0x2c57, 0x2c74, 0x2c92, 0x2caf, 0x2ccd, 0x2ceb,
+ 0x2d08, 0x2d26, 0x2d44, 0x2d61, 0x2d7f, 0x2d9d, 0x2dbb, 0x2dd9, 0x2df7,
+ 0x2e15, 0x2e33, 0x2e51, 0x2e70, 0x2e8e, 0x2eac, 0x2eca, 0x2ee9, 0x2f07,
+ 0x2f26, 0x2f44, 0x2f63, 0x2f81, 0x2fa0, 0x2fbf, 0x2fdd, 0x2ffc, 0x301b,
+ 0x303a, 0x3059, 0x3078, 0x3097, 0x30b6, 0x30d5, 0x30f4, 0x3113, 0x3132,
+ 0x3152, 0x3171, 0x3190, 0x31b0, 0x31cf, 0x31ef, 0x320e, 0x322e, 0x324e,
+ 0x326d, 0x328d, 0x32ad, 0x32cd, 0x32ec, 0x330c, 0x332c, 0x334c, 0x336c,
+ 0x338c, 0x33ac, 0x33cd, 0x33ed, 0x340d, 0x342e, 0x344e, 0x346e, 0x348f,
+ 0x34af, 0x34d0, 0x34f0, 0x3511, 0x3532, 0x3552, 0x3573, 0x3594, 0x35b5,
+ 0x35d6, 0x35f7, 0x3618, 0x3639, 0x365a, 0x367b, 0x369c, 0x36bd, 0x36df,
+ 0x3700, 0x3721, 0x3743, 0x3764, 0x3786, 0x37a7, 0x37c9, 0x37eb, 0x380c,
+ 0x382e, 0x3850, 0x3872, 0x3894, 0x38b6, 0x38d8, 0x38fa, 0x391c, 0x393e,
+ 0x3960, 0x3982, 0x39a4, 0x39c7, 0x39e9, 0x3a0b, 0x3a2e, 0x3a50, 0x3a73,
+ 0x3a95, 0x3ab8, 0x3adb, 0x3afd, 0x3b20, 0x3b43, 0x3b66, 0x3b89, 0x3bac,
+ 0x3bcf, 0x3bf2, 0x3c15, 0x3c38, 0x3c5b, 0x3c7e, 0x3ca2, 0x3cc5, 0x3ce8,
+ 0x3d0c, 0x3d2f, 0x3d53, 0x3d76, 0x3d9a, 0x3dbe, 0x3de1, 0x3e05, 0x3e29,
+ 0x3e4d, 0x3e71, 0x3e95, 0x3eb9, 0x3edd, 0x3f01, 0x3f25, 0x3f49, 0x3f6d,
+ 0x3f91, 0x3fb6, 0x3fda, 0x3fff, 0x0,
+ /* table descriptor */
+ 0xffffbf62, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4abd, 0x0, 0x0, 0x0, 0x4abd, 0x0, 0x0, 0x0, 0x4abd, 0xffffffc0,
+ 0xffffffc0, 0xffffffc0, 0x0, 0x0, 0x0, 0x36c, 0x36c, 0x36c, 0xe, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xffffdf62, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfff0bfa2, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x255f, 0x0, 0x35e0, 0x255f, 0xfffff9fd, 0xffffeb20, 0x255f,
+ 0x44bd, 0x0, 0xffffffc0, 0xfffffe00, 0xfffffe00, 0x0, 0xfffffe40,
+ 0xfffffe40, 0x36c, 0x1c0, 0x1c0, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfff136a2, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x255f, 0x0, 0x3989, 0x255f, 0xfffff928, 0xffffeee6, 0x255f,
+ 0x43cc, 0x0, 0xffffffc0, 0xfffffe00, 0xfffffe00, 0x0, 0xfffffe40,
+ 0xfffffe40, 0x36c, 0x1c0, 0x1c0, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfff636a2, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x255f, 0x0, 0x3339, 0x255f, 0xfffff36d, 0xffffe5e9, 0x255f,
+ 0x40be, 0x0, 0xffffffc0, 0xfffffe00, 0xfffffe00, 0x0, 0xfffffe40,
+ 0xfffffe40, 0x36c, 0x1c0, 0x1c0, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfff836a2, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4abd, 0x0, 0x0, 0x0, 0x4912, 0x0, 0x0, 0x0, 0x4912, 0xffffffc0,
+ 0xfffffe00, 0xfffffe00, 0x0, 0xfffffe40, 0xfffffe40, 0x36c, 0x1c0,
+ 0x1c0, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfff0dfa2, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4000, 0x0, 0x5e60, 0x4000, 0xfffff578, 0xffffdb6f, 0x4000,
+ 0x7869, 0x0, 0x0, 0xfffffe00, 0xfffffe00, 0x0, 0xfffffe00, 0xfffffe00,
+ 0x3ff, 0x1ff, 0x1ff, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff,
+ 0x3ff,
+ /* table descriptor */
+ 0xfff156a2, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4000, 0x0, 0x64ca, 0x4000, 0xfffff403, 0xffffe20a, 0x4000,
+ 0x76c2, 0x0, 0x0, 0xfffffe00, 0xfffffe00, 0x0, 0xfffffe00, 0xfffffe00,
+ 0x3ff, 0x1ff, 0x1ff, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff,
+ 0x3ff,
+ /* table descriptor */
+ 0xfff656a2, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4000, 0x0, 0x59ba, 0x4000, 0xffffe9fa, 0xffffd24c, 0x4000,
+ 0x7168, 0x0, 0x0, 0xfffffe00, 0xfffffe00, 0x0, 0xfffffe00, 0xfffffe00,
+ 0x3ff, 0x1ff, 0x1ff, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff,
+ 0x3ff,
+ /* table descriptor */
+ 0xfff856a2, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0,
+ 0xfffffe00, 0xfffffe00, 0x0, 0xfffffe00, 0xfffffe00, 0x3ff, 0x1ff,
+ 0x1ff, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfff17664, 0x0,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x357d, 0x1c13, 0x3b1, 0x5e4, 0x4e65, 0xf8, 0x166, 0x781, 0x4c5b,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x2, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0xfff27664, 0x0,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x37d8, 0x19c3, 0x3a6, 0x626, 0x4e26, 0xf5, 0x176, 0x858, 0x4b74,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x2, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0xfff47664, 0x0,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x3403, 0x1d94, 0x3aa, 0x719, 0x4b7d, 0x2ab, 0x15b, 0x6f0, 0x4cf7,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x2, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0xfff87664, 0x0,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4ae5, 0x68c, 0x3d1, 0x8f4, 0x4b4d, 0x100, 0x2b9, 0x3a3, 0x4ee6,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x2, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0xfff176a4, 0x0,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x503c, 0x2a1c, 0x58a, 0x8d6, 0x7598, 0x174, 0x219, 0xb41, 0x7288,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x1, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0xfff276a4, 0x0,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x53c5, 0x26a4, 0x579, 0x93a, 0x7539, 0x170, 0x230, 0xc84, 0x712e,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x1, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0xfff476a4, 0x0,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4e04, 0x2c5e, 0x57f, 0xaa6, 0x713c, 0x400, 0x208, 0xa67, 0x7372,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x1, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0xfff876a4, 0x0,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x7057, 0x9d1, 0x5b9, 0xd6e, 0x70f3, 0x180, 0x416, 0x574, 0x7659,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x1, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff27664, 0x1,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x5903, 0xfffffc3f, 0x0, 0x0, 0x5541, 0x0, 0x0, 0x101, 0x5440,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x2, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff47664, 0x1,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x5218, 0x440, 0xfffffee9, 0x18e, 0x51c8, 0x1ec, 0xffffffdc,
+ 0xffffffa1, 0x55c4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff,
+ 0x3fff, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000,
+ 0xffc0000,
+ /* table descriptor */
+ 0x7ff87664, 0x1,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x76e7, 0xffffde5b, 0x0, 0xcb, 0x5476, 0x0, 0xc9, 0xfffffc60,
+ 0x5818, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x2, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff276a4, 0x1,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x42c2, 0xfffffd2f, 0x0, 0x0, 0x3ff1, 0x0, 0x0, 0xc1, 0x3f30, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff476a4, 0x1,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x3d92, 0x330, 0xffffff2f, 0x12a, 0x3d56, 0x171, 0xffffffe5,
+ 0xffffffb9, 0x4053, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff,
+ 0x3fff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000,
+ 0xffc0000,
+ /* table descriptor */
+ 0x7ff876a4, 0x1,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x592d, 0xffffe6c4, 0x0, 0x98, 0x3f59, 0x0, 0x97, 0xfffffd48,
+ 0x4212, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff17664, 0x2,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x51a9, 0x399, 0x0, 0x0, 0x5541, 0x0, 0x0, 0xfffffefc, 0x5646,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x2, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff47664, 0x2,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4eb2, 0x785, 0xffffff0a, 0x18e, 0x51c8, 0x1ec, 0xffffffd7,
+ 0xfffffea6, 0x56c4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff,
+ 0x3fff, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000,
+ 0xffc0000,
+ /* table descriptor */
+ 0x7ff87664, 0x2,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x71eb, 0xffffe356, 0x0, 0xcb, 0x5476, 0x0, 0xc9, 0xfffffb53,
+ 0x5925, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x2, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff176a4, 0x2,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x3d3e, 0x2b3, 0x0, 0x0, 0x3ff1, 0x0, 0x0, 0xffffff3d, 0x40b4,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff476a4, 0x2,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x3b06, 0x5a4, 0xffffff47, 0x12a, 0x3d56, 0x171, 0xffffffe1,
+ 0xfffffefd, 0x4113, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff,
+ 0x3fff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000,
+ 0xffc0000,
+ /* table descriptor */
+ 0x7ff876a4, 0x2,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x5570, 0xffffea81, 0x0, 0x98, 0x3f59, 0x0, 0x97, 0xfffffc7e,
+ 0x42dc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff17664, 0x4,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x58a0, 0xfffffb67, 0x13a, 0xfffffe50, 0x58f5, 0xfffffdfc, 0x24,
+ 0x60, 0x54bd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff,
+ 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff27664, 0x4,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x5c88, 0xfffff783, 0x137, 0xfffffe3d, 0x5902, 0xfffffe02, 0x25,
+ 0x15f, 0x53be, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff,
+ 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff87664, 0x4,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x7b92, 0xffffd86a, 0x145, 0xfffffe75, 0x58e1, 0xfffffdeb, 0xfb,
+ 0xfffffcb7, 0x5790, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff,
+ 0x3fff, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000,
+ 0xffc0000,
+ /* table descriptor */
+ 0x7ff176a4, 0x4,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4278, 0xfffffc8d, 0xec, 0xfffffebc, 0x42b8, 0xfffffe7d, 0x1b,
+ 0x48, 0x3f8e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff276a4, 0x4,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4566, 0xfffff9a2, 0xe9, 0xfffffeae, 0x42c1, 0xfffffe82, 0x1c,
+ 0x107, 0x3ece, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff876a4, 0x4,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x5cae, 0xffffe250, 0xf4, 0xfffffed8, 0x42a9, 0xfffffe70, 0xbc,
+ 0xfffffd89, 0x41ac, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff,
+ 0x3fff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000,
+ 0xffc0000,
+ /* table descriptor */
+ 0x7ff17664, 0x8,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x3cf8, 0x1849, 0x0, 0xffffff6d, 0x55d4, 0x0, 0xffffff6f, 0x351,
+ 0x5282, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x2, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff27664, 0x8,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x3fa7, 0x159a, 0x0, 0xffffff67, 0x55da, 0x0, 0xffffff68, 0x450,
+ 0x5189, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x2, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff47664, 0x8,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x3b26, 0x1a56, 0xffffffc5, 0x103, 0x524d, 0x1f1, 0xffffff60,
+ 0x2cb, 0x5316, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff,
+ 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7fff7664, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x5541, 0x0, 0x0, 0x0, 0x5541, 0x0, 0x0, 0x0, 0x5541, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x2, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0xfff0ffe4, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0,
+ /* table descriptor */
+ 0x7ff176a4, 0x8,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x2dba, 0x1237, 0x0, 0xffffff92, 0x405f, 0x0, 0xffffff93, 0x27d,
+ 0x3de1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff276a4, 0x8,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x2fbd, 0x1034, 0x0, 0xffffff8d, 0x4064, 0x0, 0xffffff8e, 0x33c,
+ 0x3d27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7ff476a4, 0x8,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x58ba, 0x2781, 0xffffffa7, 0x185, 0x7b74, 0x2ea, 0xffffff11,
+ 0x431, 0x7ca0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff,
+ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+ /* table descriptor */
+ 0x7fff76a4, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x7fe2, 0x0, 0x0, 0x0, 0x7fe2, 0x0, 0x0, 0x0, 0x7fe2, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x3fff, 0x3fff, 0x3fff, 0x1, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0xffc0000, 0xffc0000, 0xffc0000,
+};
+
+#endif /* __DCSS_HDR10_TABLES_H__ */
diff --git a/drivers/gpu/imx/dcss/dcss-hdr10.c b/drivers/gpu/imx/dcss/dcss-hdr10.c
new file mode 100644
index 000000000000..d5888936034f
--- /dev/null
+++ b/drivers/gpu/imx/dcss/dcss-hdr10.c
@@ -0,0 +1,656 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/firmware.h>
+#include <drm/drm_fourcc.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+
+#define USE_TBL_HEADER
+
+#ifdef USE_TBL_HEADER
+#include "dcss-hdr10-tables.h"
+#endif
+
+#define USE_CTXLD
+
+#define DCSS_HDR10_A0_LUT 0x0000
+#define DCSS_HDR10_A1_LUT 0x1000
+#define DCSS_HDR10_A2_LUT 0x2000
+/* one CSCA and CSCB for each channel(pipe) */
+#define DCSS_HDR10_CSCA_BASE 0x3000
+#define DCSS_HDR10_CSCB_BASE 0x3800
+
+/* one CSCO for all channels(pipes) */
+#define DCSS_HDR10_CSCO_BASE 0x3000
+
+#define DCSS_HDR10_LUT_CONTROL (DCSS_HDR10_CSCA_BASE + 0x80)
+#define LUT_ENABLE BIT(0)
+#define LUT_EN_FOR_ALL_PELS BIT(1)
+#define LUT_BYPASS BIT(15)
+#define DCSS_HDR10_FL2FX (DCSS_HDR10_CSCB_BASE + 0x74)
+#define DCSS_HDR10_LTNL (DCSS_HDR10_CSCO_BASE + 0x74)
+#define LTNL_PASS_THRU BIT(0)
+#define FIX2FLT_DISABLE BIT(1)
+#define LTNL_EN_FOR_ALL_PELS BIT(2)
+#define FIX2FLT_EN_FOR_ALL_PELS BIT(3)
+
+/* following offsets are relative to CSC(A|B|O)_BASE */
+#define DCSS_HDR10_CSC_CONTROL 0x00
+#define CSC_EN BIT(0)
+#define CSC_ALL_PIX_EN BIT(1)
+#define CSC_BYPASS BIT(15)
+#define DCSS_HDR10_CSC_H00 0x04
+#define DCSS_HDR10_CSC_H10 0x08
+#define DCSS_HDR10_CSC_H20 0x0C
+#define DCSS_HDR10_CSC_H01 0x10
+#define DCSS_HDR10_CSC_H11 0x14
+#define DCSS_HDR10_CSC_H21 0x18
+#define DCSS_HDR10_CSC_H02 0x1C
+#define DCSS_HDR10_CSC_H12 0x20
+#define DCSS_HDR10_CSC_H22 0x24
+#define H_COEF_MASK GENMASK(15, 0)
+#define DCSS_HDR10_CSC_IO0 0x28
+#define DCSS_HDR10_CSC_IO1 0x2C
+#define DCSS_HDR10_CSC_IO2 0x30
+#define PRE_OFFSET_MASK GENMASK(9, 0)
+#define DCSS_HDR10_CSC_IO_MIN0 0x34
+#define DCSS_HDR10_CSC_IO_MIN1 0x38
+#define DCSS_HDR10_CSC_IO_MIN2 0x3C
+#define DCSS_HDR10_CSC_IO_MAX0 0x40
+#define DCSS_HDR10_CSC_IO_MAX1 0x44
+#define DCSS_HDR10_CSC_IO_MAX2 0x48
+#define IO_CLIP_MASK GENMASK(9, 0)
+#define DCSS_HDR10_CSC_NORM 0x4C
+#define NORM_MASK GENMASK(4, 0)
+#define DCSS_HDR10_CSC_OO0 0x50
+#define DCSS_HDR10_CSC_OO1 0x54
+#define DCSS_HDR10_CSC_OO2 0x58
+#define POST_OFFSET_MASK GENMASK(27, 0)
+#define DCSS_HDR10_CSC_OMIN0 0x5C
+#define DCSS_HDR10_CSC_OMIN1 0x60
+#define DCSS_HDR10_CSC_OMIN2 0x64
+#define DCSS_HDR10_CSC_OMAX0 0x68
+#define DCSS_HDR10_CSC_OMAX1 0x6C
+#define DCSS_HDR10_CSC_OMAX2 0x70
+#define POST_CLIP_MASK GENMASK(9, 0)
+
+#define HDR10_IPIPE_LUT_MAX_ENTRIES 1024
+#define HDR10_OPIPE_LUT_MAX_ENTRIES 1023
+#define HDR10_CSC_MAX_REGS 29
+
+#define OPIPE_CH_NO 3
+
+/* Pipe config descriptor */
+
+/* bits per component */
+#define HDR10_BPC_POS 0
+#define HDR10_BPC_MASK GENMASK(1, 0)
+/* colorspace */
+#define HDR10_CS_POS 2
+#define HDR10_CS_MASK GENMASK(3, 2)
+/* nonlinearity type */
+#define HDR10_NL_POS 4
+#define HDR10_NL_MASK GENMASK(8, 4)
+/* pixel range */
+#define HDR10_PR_POS 9
+#define HDR10_PR_MASK GENMASK(10, 9)
+/* gamut type */
+#define HDR10_G_POS 11
+#define HDR10_G_MASK GENMASK(15, 11)
+
+/* FW Table Descriptor */
+#define HDR10_TT_LUT BIT(0)
+#define HDR10_TT_CSCA BIT(1)
+#define HDR10_TT_CSCB BIT(2)
+/* Pipe type */
+#define HDR10_PT_OUTPUT BIT(3)
+/* Output pipe config descriptor */
+#define HDR10_IPIPE_DESC_POS 4
+#define HDR10_IPIPE_DESC_MASK GENMASK(19, 4)
+/* Input pipe config descriptor */
+#define HDR10_OPIPE_DESC_POS 20
+#define HDR10_OPIPE_DESC_MASK GENMASK(35, 20)
+
+/* config invalid */
+#define HDR10_DESC_INVALID BIT(63)
+
+enum dcss_hdr10_csc {
+ HDR10_CSCA,
+ HDR10_CSCB,
+};
+
+struct dcss_hdr10_tbl_node {
+ u64 tbl_descriptor;
+ u32 *tbl_data;
+
+ struct list_head node;
+};
+
+struct dcss_hdr10_opipe_tbls {
+ struct list_head lut;
+ struct list_head csc;
+};
+
+struct dcss_hdr10_ipipe_tbls {
+ struct list_head lut;
+ struct list_head csca;
+ struct list_head cscb;
+};
+
+struct dcss_hdr10_ch {
+ void __iomem *base_reg;
+ u32 base_ofs;
+
+ u32 ctx_id;
+
+ u64 old_cfg_desc;
+};
+
+struct dcss_hdr10_priv {
+ struct dcss_soc *dcss;
+
+ struct dcss_hdr10_ch ch[4]; /* 4th channel is, actually, OPIPE */
+
+ struct dcss_hdr10_ipipe_tbls *ipipe_tbls;
+ struct dcss_hdr10_opipe_tbls *opipe_tbls;
+
+ u8 *fw_data;
+ u32 fw_size;
+};
+
+static struct dcss_debug_reg hdr10_debug_reg[] = {
+ DCSS_DBG_REG(DCSS_HDR10_CSC_CONTROL),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_H00),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_H10),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_H20),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_H01),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_H11),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_H21),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_H02),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_H12),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_H22),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_IO0),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_IO1),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_IO2),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MIN0),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MIN1),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MIN2),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MAX0),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MAX1),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MAX2),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_NORM),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_OO0),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_OO1),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_OO2),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_OMIN0),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_OMIN1),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_OMIN2),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_OMAX0),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_OMAX1),
+ DCSS_DBG_REG(DCSS_HDR10_CSC_OMAX2),
+};
+
+static void dcss_hdr10_write(struct dcss_soc *dcss, u32 ch_num,
+ u32 val, u32 ofs)
+{
+ struct dcss_hdr10_priv *hdr10 = dcss->hdr10_priv;
+
+#if !defined(USE_CTXLD)
+ dcss_writel(val, hdr10->ch[ch_num].base_reg + ofs);
+#else
+ dcss_ctxld_write(dcss, hdr10->ch[ch_num].ctx_id, val,
+ hdr10->ch[ch_num].base_ofs + ofs);
+#endif
+}
+
+#ifdef CONFIG_DEBUG_FS
+void dcss_hdr10_dump_regs(struct seq_file *s, void *data)
+{
+ struct dcss_soc *dcss = data;
+ int ch, csc, r;
+ int csc_no;
+
+ for (ch = 0; ch < 4; ch++) {
+ void __iomem *csc_base = dcss->hdr10_priv->ch[ch].base_reg +
+ DCSS_HDR10_CSCA_BASE;
+
+ if (ch < 3) {
+ seq_printf(s, ">> Dumping HDR10 CH %d:\n", ch);
+ csc_no = 2;
+ } else {
+ seq_puts(s, ">> Dumping HDR10 OPIPE:\n");
+ csc_no = 1;
+ }
+
+ for (csc = 0; csc < csc_no; csc++) {
+ csc_base += csc * 0x800;
+
+ if (ch < 3)
+ seq_printf(s, "\t>> Dumping CSC%s of CH %d:\n",
+ csc ? "B" : "A", ch);
+ else
+ seq_puts(s, "\t>> Dumping CSC of OPIPE:\n");
+
+ for (r = 0; r < ARRAY_SIZE(hdr10_debug_reg); r++)
+ seq_printf(s, "\t%-35s(0x%04x) -> 0x%08x\n",
+ hdr10_debug_reg[r].name,
+ hdr10_debug_reg[r].ofs,
+ dcss_readl(csc_base +
+ hdr10_debug_reg[r].ofs));
+
+ if (csc == 0 && ch != 3)
+ seq_printf(s, "\t%-35s(0x%04x) -> 0x%08x\n",
+ "DCSS_HDR10_LUT_CONTROL",
+ 0x80, dcss_readl(csc_base + 0x80));
+
+ if (csc == 1 || ch == 3)
+ seq_printf(s, "\t%-35s(0x%04x) -> 0x%08x\n",
+ ch == 3 ? "DCSS_HDR10_LTNL" :
+ "DCSS_HDR10_FL2FX",
+ 0x74, dcss_readl(csc_base + 0x74));
+ }
+ }
+}
+#endif
+
+static void dcss_hdr10_csc_fill(struct dcss_soc *dcss, int ch_num,
+ enum dcss_hdr10_csc csc_to_use,
+ u32 *map)
+{
+ int i;
+ u32 csc_base_ofs[] = {
+ DCSS_HDR10_CSCA_BASE + DCSS_HDR10_CSC_CONTROL,
+ DCSS_HDR10_CSCB_BASE + DCSS_HDR10_CSC_CONTROL,
+ };
+
+ for (i = 0; i < HDR10_CSC_MAX_REGS; i++) {
+ u32 reg_ofs = csc_base_ofs[csc_to_use] + i * sizeof(u32);
+
+ dcss_hdr10_write(dcss, ch_num, map[i], reg_ofs);
+ }
+}
+
+static void dcss_hdr10_lut_fill(struct dcss_soc *dcss, int ch_num, u32 *map)
+{
+ int i, comp;
+ u32 lut_base_ofs, ctrl_ofs, lut_entries;
+
+ if (ch_num == OPIPE_CH_NO) {
+ ctrl_ofs = DCSS_HDR10_LTNL;
+ lut_entries = HDR10_OPIPE_LUT_MAX_ENTRIES;
+ } else {
+ ctrl_ofs = DCSS_HDR10_LUT_CONTROL;
+ lut_entries = HDR10_IPIPE_LUT_MAX_ENTRIES;
+ }
+
+ if (ch_num != OPIPE_CH_NO)
+ dcss_hdr10_write(dcss, ch_num, *map++, ctrl_ofs);
+
+ for (comp = 0; comp < 3; comp++) {
+ lut_base_ofs = DCSS_HDR10_A0_LUT + comp * 0x1000;
+
+ if (ch_num == OPIPE_CH_NO) {
+ dcss_hdr10_write(dcss, ch_num, map[0], lut_base_ofs);
+ lut_base_ofs += 4;
+ }
+
+ for (i = 0; i < lut_entries; i++) {
+ u32 reg_ofs = lut_base_ofs + i * sizeof(u32);
+
+ dcss_hdr10_write(dcss, ch_num, map[i], reg_ofs);
+ }
+ }
+
+ map += lut_entries;
+
+ if (ch_num != OPIPE_CH_NO)
+ dcss_hdr10_write(dcss, ch_num, *map, DCSS_HDR10_FL2FX);
+ else
+ dcss_hdr10_write(dcss, ch_num, *map, ctrl_ofs);
+}
+
+static int dcss_hdr10_ch_init_all(struct dcss_soc *dcss,
+ unsigned long hdr10_base)
+{
+ struct dcss_hdr10_priv *hdr10 = dcss->hdr10_priv;
+ struct dcss_hdr10_ch *ch;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ ch = &hdr10->ch[i];
+
+ ch->base_ofs = hdr10_base + i * 0x4000;
+
+ ch->base_reg = devm_ioremap(dcss->dev, ch->base_ofs, SZ_16K);
+ if (!ch->base_reg) {
+ dev_err(dcss->dev, "hdr10: unable to remap ch base\n");
+ return -ENOMEM;
+ }
+
+ ch->old_cfg_desc = HDR10_DESC_INVALID;
+
+#if defined(USE_CTXLD)
+ ch->ctx_id = CTX_SB_HP;
+#endif
+ }
+
+ return 0;
+}
+
+static u32 *dcss_hdr10_find_tbl(u64 desc, struct list_head *head)
+{
+ struct list_head *node;
+ struct dcss_hdr10_tbl_node *tbl_node;
+
+ list_for_each(node, head) {
+ tbl_node = container_of(node, struct dcss_hdr10_tbl_node, node);
+
+ if ((tbl_node->tbl_descriptor & desc) == desc)
+ return tbl_node->tbl_data;
+ }
+
+ return NULL;
+}
+
+static int dcss_hdr10_get_tbls(struct dcss_hdr10_priv *hdr10, bool input,
+ u64 desc, u32 **lut, u32 **csca, u32 **cscb)
+{
+ struct list_head *lut_list, *csca_list, *cscb_list;
+
+ lut_list = input ? &hdr10->ipipe_tbls->lut : &hdr10->opipe_tbls->lut;
+ csca_list = input ? &hdr10->ipipe_tbls->csca : &hdr10->opipe_tbls->csc;
+ cscb_list = input ? &hdr10->ipipe_tbls->cscb : NULL;
+
+ *lut = dcss_hdr10_find_tbl(desc, lut_list);
+ *csca = dcss_hdr10_find_tbl(desc, csca_list);
+
+ *cscb = NULL;
+ if (cscb_list)
+ *cscb = dcss_hdr10_find_tbl(desc, cscb_list);
+
+ return 0;
+}
+
+static void dcss_hdr10_write_pipe_tbls(struct dcss_soc *dcss, int ch_num,
+ u32 *lut, u32 *csca, u32 *cscb)
+{
+ if (csca)
+ dcss_hdr10_csc_fill(dcss, ch_num, HDR10_CSCA, csca);
+
+ if (ch_num != OPIPE_CH_NO && cscb)
+ dcss_hdr10_csc_fill(dcss, ch_num, HDR10_CSCB, cscb);
+
+ if (lut)
+ dcss_hdr10_lut_fill(dcss, ch_num, lut);
+}
+
+static void dcss_hdr10_tbl_add(struct dcss_hdr10_priv *hdr10, u64 desc, u32 sz,
+ u32 *data)
+{
+ struct device *dev = hdr10->dcss->dev;
+ struct dcss_hdr10_tbl_node *node;
+
+ node = devm_kzalloc(dev, sizeof(*node), GFP_KERNEL);
+ if (!node) {
+ dev_err(dev, "hdr10: cannot alloc memory for table node.\n");
+ return;
+ }
+
+ /* we don't need to store the table type and pipe type */
+ node->tbl_descriptor = desc >> 4;
+ node->tbl_data = data;
+
+ if (!(desc & HDR10_PT_OUTPUT)) {
+ if (desc & HDR10_TT_LUT)
+ list_add(&node->node, &hdr10->ipipe_tbls->lut);
+ else if (desc & HDR10_TT_CSCA)
+ list_add(&node->node, &hdr10->ipipe_tbls->csca);
+ else if (desc & HDR10_TT_CSCB)
+ list_add(&node->node, &hdr10->ipipe_tbls->cscb);
+
+ return;
+ }
+
+ if (desc & HDR10_TT_LUT)
+ list_add(&node->node, &hdr10->opipe_tbls->lut);
+ else if (desc & HDR10_TT_CSCA)
+ list_add(&node->node, &hdr10->opipe_tbls->csc);
+}
+
+static void dcss_hdr10_parse_fw_data(struct dcss_hdr10_priv *hdr10)
+{
+ u32 *data = (u32 *)hdr10->fw_data;
+ u32 remaining = hdr10->fw_size / sizeof(u32);
+ u64 tbl_desc;
+ u32 tbl_size;
+
+ while (remaining) {
+ tbl_desc = *((u64 *)data);
+ data += 2;
+ tbl_size = *data++;
+
+ dcss_hdr10_tbl_add(hdr10, tbl_desc, tbl_size, data);
+
+ data += tbl_size;
+ remaining -= tbl_size + 3;
+ }
+}
+
+#ifndef USE_TBL_HEADER
+static void dcss_hdr10_fw_handler(const struct firmware *fw, void *context)
+{
+ struct dcss_hdr10_priv *hdr10 = context;
+ int i;
+
+ if (!fw) {
+ dev_err(hdr10->dcss->dev, "hdr10: DCSS FW load failed.\n");
+ return;
+ }
+
+ /* we need to keep the tables for the entire life of the driver */
+ hdr10->fw_data = devm_kzalloc(hdr10->dcss->dev, fw->size, GFP_KERNEL);
+ if (!hdr10->fw_data) {
+ dev_err(hdr10->dcss->dev, "hdr10: cannot alloc FW memory.\n");
+ return;
+ }
+
+ memcpy(hdr10->fw_data, fw->data, fw->size);
+ hdr10->fw_size = fw->size;
+
+ release_firmware(fw);
+
+ dcss_hdr10_parse_fw_data(hdr10);
+
+ for (i = 0; i < 4; i++) {
+ u32 *lut, *csca, *cscb;
+ struct dcss_hdr10_ch *ch = &hdr10->ch[i];
+ bool is_input_pipe = i != OPIPE_CH_NO ? true : false;
+
+ if (ch->old_cfg_desc != HDR10_DESC_INVALID) {
+ dcss_hdr10_get_tbls(hdr10, is_input_pipe,
+ ch->old_cfg_desc, &lut,
+ &csca, &cscb);
+ dcss_hdr10_write_pipe_tbls(hdr10->dcss, i, lut,
+ csca, cscb);
+ }
+ }
+
+ dev_info(hdr10->dcss->dev, "hdr10: DCSS FW loaded successfully\n");
+}
+#endif
+
+static int dcss_hdr10_tbls_init(struct dcss_hdr10_priv *hdr10)
+{
+ struct device *dev = hdr10->dcss->dev;
+
+ hdr10->ipipe_tbls = devm_kzalloc(dev, sizeof(*hdr10->ipipe_tbls),
+ GFP_KERNEL);
+ if (!hdr10->ipipe_tbls)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&hdr10->ipipe_tbls->lut);
+ INIT_LIST_HEAD(&hdr10->ipipe_tbls->csca);
+ INIT_LIST_HEAD(&hdr10->ipipe_tbls->cscb);
+
+ hdr10->opipe_tbls = devm_kzalloc(dev, sizeof(*hdr10->opipe_tbls),
+ GFP_KERNEL);
+ if (!hdr10->opipe_tbls)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&hdr10->opipe_tbls->lut);
+ INIT_LIST_HEAD(&hdr10->opipe_tbls->csc);
+
+ return 0;
+}
+
+int dcss_hdr10_init(struct dcss_soc *dcss, unsigned long hdr10_base)
+{
+ int ret;
+ struct dcss_hdr10_priv *hdr10;
+
+ hdr10 = devm_kzalloc(dcss->dev, sizeof(*hdr10), GFP_KERNEL);
+ if (!hdr10)
+ return -ENOMEM;
+
+ dcss->hdr10_priv = hdr10;
+ hdr10->dcss = dcss;
+
+ ret = dcss_hdr10_tbls_init(hdr10);
+ if (ret < 0) {
+ dev_err(dcss->dev, "hdr10: Cannot init table lists.\n");
+ return ret;
+ }
+
+#ifndef USE_TBL_HEADER
+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, "dcss.fw",
+ dcss->dev, GFP_KERNEL, hdr10,
+ dcss_hdr10_fw_handler);
+ if (ret < 0) {
+ dev_err(dcss->dev, "hdr10: Cannot async load DCSS FW.\n");
+ return ret;
+ }
+#else
+ hdr10->fw_data = (u8 *)dcss_hdr10_tables;
+ hdr10->fw_size = sizeof(dcss_hdr10_tables);
+
+ dcss_hdr10_parse_fw_data(hdr10);
+#endif
+
+ return dcss_hdr10_ch_init_all(dcss, hdr10_base);
+}
+
+void dcss_hdr10_exit(struct dcss_soc *dcss)
+{
+}
+
+static u32 dcss_hdr10_get_bpc(u32 pix_format)
+{
+ int bpp;
+ u32 depth, bpc;
+
+ switch (pix_format) {
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ bpc = 8;
+ break;
+
+ case DRM_FORMAT_UYVY:
+ case DRM_FORMAT_VYUY:
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_YVYU:
+ bpc = 8;
+ break;
+
+ case DRM_FORMAT_P010:
+ bpc = 10;
+ break;
+
+ default:
+ drm_fb_get_bpp_depth(pix_format, &depth, &bpp);
+ bpc = depth == 30 ? 10 : 8;
+ break;
+ }
+
+ return bpc;
+}
+
+static u32 dcss_hdr10_pipe_desc(struct dcss_hdr10_pipe_cfg *pipe_cfg)
+{
+ u32 bpc, cs, desc;
+
+ bpc = dcss_hdr10_get_bpc(pipe_cfg->pixel_format);
+ cs = dcss_drm_fourcc_to_colorspace(pipe_cfg->pixel_format);
+
+ desc = bpc == 10 ? 2 << HDR10_BPC_POS : 1 << HDR10_BPC_POS;
+ desc |= cs == DCSS_COLORSPACE_YUV ? 2 << HDR10_CS_POS :
+ 1 << HDR10_CS_POS;
+ desc |= ((1 << pipe_cfg->nl) << HDR10_NL_POS) & HDR10_NL_MASK;
+ desc |= ((1 << pipe_cfg->pr) << HDR10_PR_POS) & HDR10_PR_MASK;
+ desc |= ((1 << pipe_cfg->g) << HDR10_G_POS) & HDR10_G_MASK;
+
+ return desc;
+}
+
+static u64 dcss_hdr10_get_desc(struct dcss_hdr10_pipe_cfg *ipipe_cfg,
+ struct dcss_hdr10_pipe_cfg *opipe_cfg)
+{
+ u32 ipipe_desc, opipe_desc;
+
+ ipipe_desc = dcss_hdr10_pipe_desc(ipipe_cfg) & (~HDR10_BPC_MASK);
+ ipipe_desc |= 2 << HDR10_BPC_POS;
+ opipe_desc = dcss_hdr10_pipe_desc(opipe_cfg);
+
+ return (ipipe_desc & 0xFFFF) |
+ (opipe_desc & 0xFFFF) << 16;
+}
+
+static void dcss_hdr10_pipe_setup(struct dcss_soc *dcss, int ch_num,
+ u64 desc)
+{
+ struct dcss_hdr10_ch *ch = &dcss->hdr10_priv->ch[ch_num];
+ bool pipe_cfg_chgd;
+ u32 *csca, *cscb, *lut;
+
+ pipe_cfg_chgd = ch->old_cfg_desc != desc;
+
+ if (!pipe_cfg_chgd)
+ return;
+
+ dcss_hdr10_get_tbls(dcss->hdr10_priv, ch_num != OPIPE_CH_NO,
+ desc, &lut, &csca, &cscb);
+ dcss_hdr10_write_pipe_tbls(dcss, ch_num, lut, csca, cscb);
+
+ ch->old_cfg_desc = desc;
+}
+
+void dcss_hdr10_setup(struct dcss_soc *dcss, int ch_num,
+ struct dcss_hdr10_pipe_cfg *ipipe_cfg,
+ struct dcss_hdr10_pipe_cfg *opipe_cfg)
+{
+ u64 desc = dcss_hdr10_get_desc(ipipe_cfg, opipe_cfg);
+
+ dcss_hdr10_pipe_setup(dcss, ch_num, desc);
+
+ /*
+ * Input pipe configuration doesn't matter for configuring the output
+ * pipe. So, will just mask off the input part of the descriptor.
+ */
+ dcss_hdr10_pipe_setup(dcss, OPIPE_CH_NO, desc | 0xfffe);
+}
+EXPORT_SYMBOL(dcss_hdr10_setup);
diff --git a/drivers/gpu/imx/dcss/dcss-prv.h b/drivers/gpu/imx/dcss/dcss-prv.h
new file mode 100644
index 000000000000..4e5ddc2622d5
--- /dev/null
+++ b/drivers/gpu/imx/dcss/dcss-prv.h
@@ -0,0 +1,181 @@
+#ifndef __DCSS_PRV_H__
+#define __DCSS_PRV_H__
+
+#include <linux/pm_qos.h>
+
+#define SET 0x04
+#define CLR 0x08
+#define TGL 0x0C
+
+#define dcss_writel(v, c) writel((v), (c))
+#define dcss_readl(c) readl(c)
+#define dcss_set(v, c) writel((v), (c) + SET)
+#define dcss_clr(v, c) writel((v), (c) + CLR)
+#define dcss_toggle(v, c) writel((v), (c) + TGL)
+#define dcss_update(v, m, c) writel((readl(c) & ~(m)) | (v), (c))
+
+#define DCSS_DBG_REG(reg) {.name = #reg, .ofs = reg}
+
+struct dcss_debug_reg {
+ char *name;
+ u32 ofs;
+};
+
+enum dcss_ctxld_ctx_type {
+ CTX_DB,
+ CTX_SB_HP, /* high-priority */
+ CTX_SB_LP, /* low-priority */
+};
+
+struct dcss_soc;
+struct dcss_devtype;
+
+struct dcss_soc {
+ struct device *dev;
+ const struct dcss_devtype *devtype;
+
+ u32 start_addr;
+
+ struct dcss_blkctl_priv *blkctl_priv;
+ struct dcss_ctxld_priv *ctxld_priv;
+ struct dcss_dpr_priv *dpr_priv;
+ struct dcss_dtg_priv *dtg_priv;
+ struct dcss_ss_priv *ss_priv;
+ struct dcss_hdr10_priv *hdr10_priv;
+ struct dcss_scaler_priv *scaler_priv;
+ struct dcss_dtrc_priv *dtrc_priv;
+ struct dcss_dec400d_priv *dec400d_priv;
+ struct dcss_wrscl_priv *wrscl_priv;
+ struct dcss_rdsrc_priv *rdsrc_priv;
+
+ struct clk *apb_clk;
+ struct clk *axi_clk;
+ struct clk *pdiv_clk;
+ struct clk *pout_clk;
+ struct clk *rtrm_clk;
+ struct clk *dtrc_clk;
+
+ void (*dcss_disable_callback)(void *data);
+
+ bool bus_freq_req;
+ bool clks_on;
+
+ struct pm_qos_request pm_qos_req;
+ bool pm_req_active;
+};
+
+/* BLKCTL */
+int dcss_blkctl_init(struct dcss_soc *dcss, unsigned long blkctl_base);
+void dcss_blkctl_cfg(struct dcss_soc *dcss);
+void dcss_blkctl_exit(struct dcss_soc *dcss);
+
+/* CTXLD */
+int dcss_ctxld_init(struct dcss_soc *dcss, unsigned long ctxld_base);
+void dcss_ctxld_hw_cfg(struct dcss_soc *dcss);
+void dcss_ctxld_exit(struct dcss_soc *dcss);
+void dcss_ctxld_write(struct dcss_soc *dcss, u32 ctx_id, u32 val, u32 reg_idx);
+void dcss_ctxld_update(struct dcss_soc *dcss, u32 ctx_id, u32 val, u32 mask,
+ u32 reg_idx);
+void dcss_ctxld_dump(struct seq_file *s, void *data);
+int dcss_ctxld_resume(struct dcss_soc *dcss);
+int dcss_ctxld_suspend(struct dcss_soc *dcss);
+void dcss_ctxld_write_irqsafe(struct dcss_soc *dcss, u32 ctx_id, u32 val,
+ u32 reg_ofs);
+void dcss_ctxld_kick(struct dcss_soc *dcss);
+
+/* DPR */
+int dcss_dpr_init(struct dcss_soc *dcss, unsigned long dpr_base);
+void dcss_dpr_exit(struct dcss_soc *dcss);
+void dcss_dpr_write_sysctrl(struct dcss_soc *dcss);
+void dcss_dpr_irq_enable(struct dcss_soc *dcss, bool en);
+
+/* DTG */
+int dcss_dtg_init(struct dcss_soc *dcss, unsigned long dtg_base);
+void dcss_dtg_exit(struct dcss_soc *dcss);
+void dcss_dtg_vblank_irq_enable(struct dcss_soc *dcss, bool en);
+void dcss_dtg_vblank_irq_clear(struct dcss_soc *dcss);
+
+/* SUBSAM */
+int dcss_ss_init(struct dcss_soc *dcss, unsigned long subsam_base);
+void dcss_ss_exit(struct dcss_soc *dcss);
+
+/* HDR10 */
+int dcss_hdr10_init(struct dcss_soc *dcss, unsigned long hdr10_base);
+void dcss_hdr10_exit(struct dcss_soc *dcss);
+void dcss_hdr10_cfg(struct dcss_soc *dcss);
+
+/* SCALER */
+int dcss_scaler_init(struct dcss_soc *dcss, unsigned long scaler_base);
+void dcss_scaler_exit(struct dcss_soc *dcss);
+void dcss_scaler_write_sclctrl(struct dcss_soc *dcss);
+
+/* DTRC */
+int dcss_dtrc_init(struct dcss_soc *dcss, unsigned long dtrc_base);
+void dcss_dtrc_exit(struct dcss_soc *dcss);
+void dcss_dtrc_switch_banks(struct dcss_soc *dcss);
+bool dcss_dtrc_is_running(struct dcss_soc *dcss, int ch_num);
+
+/* DEC400d */
+int dcss_dec400d_init(struct dcss_soc *dcss, unsigned long dec400d_base);
+void dcss_dec400d_exit(struct dcss_soc *dcss);
+
+/* enums common to both WRSCL and RDSRC */
+enum dcss_wrscl_rdsrc_psize {
+ PSIZE_64,
+ PSIZE_128,
+ PSIZE_256,
+ PSIZE_512,
+ PSIZE_1024,
+ PSIZE_2048,
+ PSIZE_4096,
+};
+
+enum dcss_wrscl_rdsrc_tsize {
+ TSIZE_64,
+ TSIZE_128,
+ TSIZE_256,
+ TSIZE_512,
+};
+
+enum dcss_wrscl_rdsrc_fifo_size {
+ FIFO_512,
+ FIFO_1024,
+ FIFO_2048,
+ FIFO_4096,
+};
+
+enum dcss_wrscl_rdsrc_bpp {
+ BPP_38, /* 38 bit unpacked components */
+ BPP_32_UPCONVERT,
+ BPP_32_10BIT_OUTPUT,
+ BPP_20, /* 10-bit YUV422 */
+ BPP_16, /* 8-bit YUV422 */
+};
+
+/* WRSCL */
+int dcss_wrscl_init(struct dcss_soc *dcss, unsigned long wrscl_base);
+void dcss_wrscl_exit(struct dcss_soc *dcss);
+u32 dcss_wrscl_setup(struct dcss_soc *dcss, u32 pix_format, u32 pix_clk_hz,
+ u32 dst_xres, u32 dst_yres);
+void dcss_wrscl_enable(struct dcss_soc *dcss, bool en);
+
+/* RDSRC */
+int dcss_rdsrc_init(struct dcss_soc *dcss, unsigned long rdsrc_base);
+void dcss_rdsrc_exit(struct dcss_soc *dcss);
+void dcss_rdsrc_setup(struct dcss_soc *dcss, u32 pix_format, u32 dst_xres,
+ u32 dst_yres, u32 base_addr);
+void dcss_rdsrc_enable(struct dcss_soc *dcss, bool en);
+
+/* debug: dump registers routines */
+void dcss_blkctl_dump_regs(struct seq_file *s, void *data);
+void dcss_dtrc_dump_regs(struct seq_file *s, void *data);
+void dcss_dpr_dump_regs(struct seq_file *s, void *data);
+void dcss_dtg_dump_regs(struct seq_file *s, void *data);
+void dcss_ss_dump_regs(struct seq_file *s, void *data);
+void dcss_scaler_dump_regs(struct seq_file *s, void *data);
+void dcss_ctxld_dump_regs(struct seq_file *s, void *data);
+void dcss_hdr10_dump_regs(struct seq_file *s, void *data);
+void dcss_wrscl_dump_regs(struct seq_file *s, void *data);
+void dcss_rdsrc_dump_regs(struct seq_file *s, void *data);
+
+#endif /* __DCSS_PRV_H__ */
diff --git a/drivers/gpu/imx/dcss/dcss-rdsrc.c b/drivers/gpu/imx/dcss/dcss-rdsrc.c
new file mode 100644
index 000000000000..1fa9c099dfc7
--- /dev/null
+++ b/drivers/gpu/imx/dcss/dcss-rdsrc.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+
+#define USE_CTXLD
+
+#define DCSS_RDSRC_CTRL_STATUS 0x00
+#define RDSRC_RD_ERR BIT(31)
+#define RDSRC_FRAME_COMP BIT(30)
+#define RDSRC_FIFO_SIZE_POS 16
+#define RDSRC_FIFO_SIZE_MASK GENMASK(22, 16)
+#define RDSRC_RD_ERR_EN BIT(15)
+#define RDSRC_FRAME_COMP_EN BIT(14)
+#define RDSRC_P_SIZE_POS 7
+#define RDSRC_P_SIZE_MASK GENMASK(9, 7)
+#define RDSRC_T_SIZE_POS 5
+#define RDSRC_T_SIZE_MASK GENMASK(6, 5)
+#define RDSRC_BPP_POS 2
+#define RDSRC_BPP_MASK GENMASK(4, 2)
+#define RDSRC_ENABLE BIT(0)
+#define DCSS_RDSRC_BASE_ADDR 0x10
+#define DCSS_RDSRC_PITCH 0x14
+#define DCSS_RDSRC_WIDTH 0x18
+#define DCSS_RDSRC_HEIGHT 0x1C
+
+struct dcss_rdsrc_priv {
+ void __iomem *base_reg;
+ u32 base_ofs;
+ struct dcss_soc *dcss;
+
+ u32 ctx_id;
+
+ u32 buf_addr;
+
+ u32 ctrl_status;
+};
+
+#ifdef CONFIG_DEBUG_FS
+static struct dcss_debug_reg rdsrc_debug_reg[] = {
+ DCSS_DBG_REG(DCSS_RDSRC_CTRL_STATUS),
+ DCSS_DBG_REG(DCSS_RDSRC_BASE_ADDR),
+ DCSS_DBG_REG(DCSS_RDSRC_PITCH),
+ DCSS_DBG_REG(DCSS_RDSRC_WIDTH),
+ DCSS_DBG_REG(DCSS_RDSRC_HEIGHT),
+};
+
+void dcss_rdsrc_dump_regs(struct seq_file *s, void *data)
+{
+ struct dcss_soc *dcss = data;
+ int i;
+
+ seq_puts(s, ">> Dumping RD_SRC:\n");
+ for (i = 0; i < ARRAY_SIZE(rdsrc_debug_reg); i++) {
+ seq_printf(s, "%-35s(0x%04x) -> 0x%08x\n",
+ rdsrc_debug_reg[i].name,
+ rdsrc_debug_reg[i].ofs,
+ dcss_readl(dcss->rdsrc_priv->base_reg +
+ rdsrc_debug_reg[i].ofs));
+ }
+}
+#endif
+
+static void dcss_rdsrc_write(struct dcss_rdsrc_priv *rdsrc, u32 val, u32 ofs)
+{
+#if !defined(USE_CTXLD)
+ dcss_writel(val, rdsrc->base_reg + ofs);
+#else
+ dcss_ctxld_write(rdsrc->dcss, rdsrc->ctx_id,
+ val, rdsrc->base_ofs + ofs);
+#endif
+}
+
+int dcss_rdsrc_init(struct dcss_soc *dcss, unsigned long rdsrc_base)
+{
+ struct dcss_rdsrc_priv *rdsrc;
+
+ rdsrc = devm_kzalloc(dcss->dev, sizeof(*rdsrc), GFP_KERNEL);
+ if (!rdsrc)
+ return -ENOMEM;
+
+ rdsrc->base_reg = devm_ioremap(dcss->dev, rdsrc_base, SZ_4K);
+ if (!rdsrc->base_reg) {
+ dev_err(dcss->dev, "rdsrc: unable to remap base\n");
+ return -ENOMEM;
+ }
+
+ dcss->rdsrc_priv = rdsrc;
+ rdsrc->base_ofs = rdsrc_base;
+ rdsrc->dcss = dcss;
+
+#if defined(USE_CTXLD)
+ rdsrc->ctx_id = CTX_SB_HP;
+#endif
+
+ return 0;
+}
+
+void dcss_rdsrc_exit(struct dcss_soc *dcss)
+{
+}
+
+void dcss_rdsrc_setup(struct dcss_soc *dcss, u32 pix_format, u32 dst_xres,
+ u32 dst_yres, u32 base_addr)
+{
+ struct dcss_rdsrc_priv *rdsrc = dcss->rdsrc_priv;
+ u32 buf_size, pitch, bpp;
+
+ /* since the scaler output is YUV444, the RDSRC output has to match */
+ bpp = 4;
+
+ rdsrc->ctrl_status = FIFO_512 << RDSRC_FIFO_SIZE_POS;
+ rdsrc->ctrl_status |= PSIZE_256 << RDSRC_P_SIZE_POS;
+ rdsrc->ctrl_status |= TSIZE_256 << RDSRC_T_SIZE_POS;
+ rdsrc->ctrl_status |= BPP_32_10BIT_OUTPUT << RDSRC_BPP_POS;
+
+ buf_size = dst_xres * dst_yres * bpp;
+ pitch = dst_xres * bpp;
+
+ rdsrc->buf_addr = base_addr;
+
+ dcss_rdsrc_write(rdsrc, rdsrc->buf_addr, DCSS_RDSRC_BASE_ADDR);
+ dcss_rdsrc_write(rdsrc, pitch, DCSS_RDSRC_PITCH);
+ dcss_rdsrc_write(rdsrc, dst_xres, DCSS_RDSRC_WIDTH);
+ dcss_rdsrc_write(rdsrc, dst_yres, DCSS_RDSRC_HEIGHT);
+}
+
+void dcss_rdsrc_enable(struct dcss_soc *dcss, bool en)
+{
+ struct dcss_rdsrc_priv *rdsrc = dcss->rdsrc_priv;
+
+ /* RDSRC is turned off by setting the width and height to 0 */
+ if (!en) {
+ dcss_rdsrc_write(rdsrc, 0, DCSS_RDSRC_WIDTH);
+ dcss_rdsrc_write(rdsrc, 0, DCSS_RDSRC_HEIGHT);
+ }
+
+ dcss_rdsrc_write(rdsrc, rdsrc->ctrl_status, DCSS_RDSRC_CTRL_STATUS);
+}
diff --git a/drivers/gpu/imx/dcss/dcss-scaler.c b/drivers/gpu/imx/dcss/dcss-scaler.c
new file mode 100644
index 000000000000..919eafd23110
--- /dev/null
+++ b/drivers/gpu/imx/dcss/dcss-scaler.c
@@ -0,0 +1,994 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <drm/drm_fourcc.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+
+#define USE_CTXLD
+
+#define DCSS_SCALER_CTRL 0x00
+#define SCALER_EN BIT(0)
+#define REPEAT_EN BIT(4)
+#define SCALE2MEM_EN BIT(8)
+#define MEM2OFIFO_EN BIT(12)
+#define DCSS_SCALER_OFIFO_CTRL 0x04
+#define OFIFO_LOW_THRES_POS 0
+#define OFIFO_LOW_THRES_MASK GENMASK(9, 0)
+#define OFIFO_HIGH_THRES_POS 16
+#define OFIFO_HIGH_THRES_MASK GENMASK(25, 16)
+#define UNDERRUN_DETECT_CLR BIT(26)
+#define LOW_THRES_DETECT_CLR BIT(27)
+#define HIGH_THRES_DETECT_CLR BIT(28)
+#define UNDERRUN_DETECT_EN BIT(29)
+#define LOW_THRES_DETECT_EN BIT(30)
+#define HIGH_THRES_DETECT_EN BIT(31)
+#define DCSS_SCALER_SDATA_CTRL 0x08
+#define YUV_EN BIT(0)
+#define RTRAM_8LINES BIT(1)
+#define Y_UV_BYTE_SWAP BIT(4)
+#define A2R10G10B10_FORMAT_POS 8
+#define A2R10G10B10_FORMAT_MASK GENMASK(11, 8)
+#define DCSS_SCALER_BIT_DEPTH 0x0C
+#define LUM_BIT_DEPTH_POS 0
+#define LUM_BIT_DEPTH_MASK GENMASK(1, 0)
+#define CHR_BIT_DEPTH_POS 4
+#define CHR_BIT_DEPTH_MASK GENMASK(5, 4)
+#define DCSS_SCALER_SRC_FORMAT 0x10
+#define DCSS_SCALER_DST_FORMAT 0x14
+#define FORMAT_MASK GENMASK(1, 0)
+#define DCSS_SCALER_SRC_LUM_RES 0x18
+#define DCSS_SCALER_SRC_CHR_RES 0x1C
+#define DCSS_SCALER_DST_LUM_RES 0x20
+#define DCSS_SCALER_DST_CHR_RES 0x24
+#define WIDTH_POS 0
+#define WIDTH_MASK GENMASK(11, 0)
+#define HEIGHT_POS 16
+#define HEIGHT_MASK GENMASK(27, 16)
+#define DCSS_SCALER_V_LUM_START 0x48
+#define V_START_MASK GENMASK(15, 0)
+#define DCSS_SCALER_V_LUM_INC 0x4C
+#define V_INC_MASK GENMASK(15, 0)
+#define DCSS_SCALER_H_LUM_START 0x50
+#define H_START_MASK GENMASK(18, 0)
+#define DCSS_SCALER_H_LUM_INC 0x54
+#define H_INC_MASK GENMASK(15, 0)
+#define DCSS_SCALER_V_CHR_START 0x58
+#define DCSS_SCALER_V_CHR_INC 0x5C
+#define DCSS_SCALER_H_CHR_START 0x60
+#define DCSS_SCALER_H_CHR_INC 0x64
+#define DCSS_SCALER_COEF_VLUM 0x80
+#define DCSS_SCALER_COEF_HLUM 0x140
+#define DCSS_SCALER_COEF_VCHR 0x200
+#define DCSS_SCALER_COEF_HCHR 0x300
+
+static struct dcss_debug_reg scaler_debug_reg[] = {
+ DCSS_DBG_REG(DCSS_SCALER_CTRL),
+ DCSS_DBG_REG(DCSS_SCALER_OFIFO_CTRL),
+ DCSS_DBG_REG(DCSS_SCALER_SDATA_CTRL),
+ DCSS_DBG_REG(DCSS_SCALER_BIT_DEPTH),
+ DCSS_DBG_REG(DCSS_SCALER_SRC_FORMAT),
+ DCSS_DBG_REG(DCSS_SCALER_DST_FORMAT),
+ DCSS_DBG_REG(DCSS_SCALER_SRC_LUM_RES),
+ DCSS_DBG_REG(DCSS_SCALER_SRC_CHR_RES),
+ DCSS_DBG_REG(DCSS_SCALER_DST_LUM_RES),
+ DCSS_DBG_REG(DCSS_SCALER_DST_CHR_RES),
+ DCSS_DBG_REG(DCSS_SCALER_V_LUM_START),
+ DCSS_DBG_REG(DCSS_SCALER_V_LUM_INC),
+ DCSS_DBG_REG(DCSS_SCALER_H_LUM_START),
+ DCSS_DBG_REG(DCSS_SCALER_H_LUM_INC),
+ DCSS_DBG_REG(DCSS_SCALER_V_CHR_START),
+ DCSS_DBG_REG(DCSS_SCALER_V_CHR_INC),
+ DCSS_DBG_REG(DCSS_SCALER_H_CHR_START),
+ DCSS_DBG_REG(DCSS_SCALER_H_CHR_INC),
+};
+
+struct dcss_scaler_ch {
+ void __iomem *base_reg;
+ u32 base_ofs;
+
+ u32 ctx_id;
+
+ u32 sdata_ctrl;
+ u32 scaler_ctrl;
+
+ bool scaler_ctrl_chgd;
+
+ u32 c_vstart;
+ u32 c_hstart;
+};
+
+struct dcss_scaler_priv {
+ struct dcss_soc *dcss;
+ struct dcss_scaler_ch ch[3];
+
+ int ch_using_wrscl;
+};
+
+/* scaler coefficients generator */
+#define PSC_FRAC_BITS 30
+#define PSC_FRAC_SCALE BIT(PSC_FRAC_BITS)
+#define PSC_BITS_FOR_PHASE 4
+#define PSC_NUM_PHASES 16
+#define PSC_STORED_PHASES (PSC_NUM_PHASES / 2 + 1)
+#define PSC_NUM_TAPS 7
+#define PSC_NUM_TAPS_RGBA 5
+#define PSC_COEFF_PRECISION 10
+#define PSC_PHASE_FRACTION_BITS 13
+#define PSC_PHASE_MASK (PSC_NUM_PHASES - 1)
+#define PSC_Q_FRACTION 19
+#define PSC_Q_ROUND_OFFSET (1 << (PSC_Q_FRACTION - 1))
+
+/**
+ * mult_q() - Performs fixed-point multiplication.
+ * @A: multiplier
+ * @B: multiplicand
+ */
+static int mult_q(int A, int B)
+{
+ int result;
+ s64 temp;
+
+ temp = (int64_t)A * (int64_t)B;
+ temp += PSC_Q_ROUND_OFFSET;
+ result = (int)(temp >> PSC_Q_FRACTION);
+ return result;
+}
+
+/**
+ * div_q() - Performs fixed-point division.
+ * @A: dividend
+ * @B: divisor
+ */
+static int div_q(int A, int B)
+{
+ int result;
+ s64 temp;
+
+ temp = (int64_t)A << PSC_Q_FRACTION;
+ if ((temp >= 0 && B >= 0) || (temp < 0 && B < 0))
+ temp += B / 2;
+ else
+ temp -= B / 2;
+
+ result = (int)(temp / B);
+ return result;
+}
+
+/**
+ * exp_approx_q() - Compute approximation to exp(x) function using Taylor
+ * series.
+ * @x: fixed-point argument of exp function
+ */
+static int exp_approx_q(int x)
+{
+ int sum = 1 << PSC_Q_FRACTION;
+ int term = 1 << PSC_Q_FRACTION;
+
+ term = mult_q(term, div_q(x, 1 << PSC_Q_FRACTION));
+ sum += term;
+ term = mult_q(term, div_q(x, 2 << PSC_Q_FRACTION));
+ sum += term;
+ term = mult_q(term, div_q(x, 3 << PSC_Q_FRACTION));
+ sum += term;
+ term = mult_q(term, div_q(x, 4 << PSC_Q_FRACTION));
+ sum += term;
+
+ return sum;
+}
+
+/**
+ * dcss_scaler_gaussian_filter() -Generate gaussian prototype filter.
+ * @fc_q: fixed-point cutoff frequency normalized to range [0, 1]
+ * @use_5_taps: indicates whether to use 5 taps or 7 taps
+ * @coef: output filter coefficients
+ */
+static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps,
+ bool phase0_identity,
+ int coef[][PSC_NUM_TAPS])
+{
+ int sigma_q, g0_q, g1_q, g2_q;
+ int tap_cnt1, tap_cnt2, phase_cnt;
+ int mid;
+ int phase;
+ int i;
+
+ if (use_5_taps)
+ for (phase = 0; phase < PSC_STORED_PHASES; phase++) {
+ coef[phase][0] = 0;
+ coef[phase][PSC_NUM_TAPS - 1] = 0;
+ }
+
+ /* seed coefficient scanner */
+ mid = (PSC_NUM_PHASES * (use_5_taps ? PSC_NUM_TAPS_RGBA : PSC_NUM_TAPS)) / 2 - 1;
+ phase_cnt = (PSC_NUM_PHASES * (PSC_NUM_TAPS + 1)) / 2;
+ tap_cnt1 = (PSC_NUM_PHASES * PSC_NUM_TAPS) / 2;
+ tap_cnt2 = (PSC_NUM_PHASES * PSC_NUM_TAPS) / 2;
+
+ /* seed gaussian filter generator */
+ sigma_q = div_q(PSC_Q_ROUND_OFFSET, fc_q);
+ g0_q = 1 << PSC_Q_FRACTION;
+ g1_q = exp_approx_q(div_q(-PSC_Q_ROUND_OFFSET, mult_q(sigma_q, sigma_q)));
+ g2_q = mult_q(g1_q, g1_q);
+ coef[phase_cnt & PSC_PHASE_MASK][tap_cnt1 >> PSC_BITS_FOR_PHASE] = g0_q;
+
+ for (i = 0; i < mid; i++) {
+ phase_cnt++;
+ tap_cnt1--;
+ tap_cnt2++;
+
+ g0_q = mult_q(g0_q, g1_q);
+ g1_q = mult_q(g1_q, g2_q);
+
+ if ((phase_cnt & PSC_PHASE_MASK) <= 8)
+ coef[phase_cnt & PSC_PHASE_MASK][tap_cnt1 >> PSC_BITS_FOR_PHASE] = g0_q;
+ if (((-phase_cnt) & PSC_PHASE_MASK) <= 8)
+ coef[(-phase_cnt) & PSC_PHASE_MASK][tap_cnt2 >> PSC_BITS_FOR_PHASE] = g0_q;
+ }
+
+ phase_cnt++;
+ tap_cnt1--;
+ coef[phase_cnt & PSC_PHASE_MASK][tap_cnt1 >> PSC_BITS_FOR_PHASE] = 0;
+
+ /* override phase 0 with identity filter if specified */
+ if (phase0_identity)
+ for (i = 0; i < PSC_NUM_TAPS; i++)
+ coef[0][i] = i == (PSC_NUM_TAPS >> 1) ? (1 << PSC_COEFF_PRECISION) : 0;
+
+ /* normalize coef */
+ for (phase = 0; phase < PSC_STORED_PHASES; phase++) {
+ int sum = 0;
+ s64 ll_temp;
+
+ for (i = 0; i < PSC_NUM_TAPS; i++)
+ sum += coef[phase][i];
+ for (i = 0; i < PSC_NUM_TAPS; i++) {
+ ll_temp = coef[phase][i];
+ ll_temp <<= PSC_COEFF_PRECISION;
+ ll_temp += sum >> 1;
+ ll_temp /= sum;
+ coef[phase][i] = (int)ll_temp;
+ }
+ }
+}
+
+/**
+ * dcss_scaler_filter_design() - Compute filter coefficients using Gaussian filter.
+ * @src_length: length of input
+ * @dst_length: length of output
+ * @use_5_taps: 0 for 7 taps per phase, 1 for 5 taps
+ * @coef: output coefficients
+ */
+static void dcss_scaler_filter_design(int src_length, int dst_length,
+ bool use_5_taps, bool phase0_identity,
+ int coef[][PSC_NUM_TAPS])
+{
+ int fc_q;
+
+ /* compute cutoff frequency */
+ if (dst_length >= src_length)
+ fc_q = div_q(1, PSC_NUM_PHASES);
+ else
+ fc_q = div_q(dst_length, src_length * PSC_NUM_PHASES);
+
+ /* compute gaussian filter coefficients */
+ dcss_scaler_gaussian_filter(fc_q, use_5_taps, phase0_identity, coef);
+}
+
+static void dcss_scaler_write(struct dcss_scaler_priv *scl, int ch_num,
+ u32 val, u32 ofs)
+{
+#if !defined(USE_CTXLD)
+ dcss_writel(val, scl->ch[ch_num].base_reg + ofs);
+#else
+ dcss_ctxld_write(scl->dcss, scl->ch[ch_num].ctx_id,
+ val, scl->ch[ch_num].base_ofs + ofs);
+#endif
+}
+
+#ifdef CONFIG_DEBUG_FS
+void dcss_scaler_dump_regs(struct seq_file *s, void *data)
+{
+ struct dcss_soc *dcss = data;
+ int i, j;
+
+ for (i = 0; i < 3; i++) {
+ seq_printf(s, ">> Dumping SCALER CH %d:\n", i);
+ for (j = 0; j < ARRAY_SIZE(scaler_debug_reg); j++) {
+ seq_printf(s, "%-35s(0x%04x) -> 0x%08x\n",
+ scaler_debug_reg[j].name,
+ scaler_debug_reg[j].ofs,
+ dcss_readl(dcss->scaler_priv->ch[i].base_reg +
+ scaler_debug_reg[j].ofs));
+ }
+ }
+}
+#endif
+
+static int dcss_scaler_ch_init_all(struct dcss_soc *dcss,
+ unsigned long scaler_base)
+{
+ struct dcss_scaler_priv *scaler = dcss->scaler_priv;
+ struct dcss_scaler_ch *ch;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ ch = &scaler->ch[i];
+
+ ch->base_ofs = scaler_base + i * 0x400;
+
+ ch->base_reg = devm_ioremap(dcss->dev, ch->base_ofs, SZ_4K);
+ if (!ch->base_reg) {
+ dev_err(dcss->dev, "scaler: unable to remap ch base\n");
+ return -ENOMEM;
+ }
+
+#if defined(USE_CTXLD)
+ ch->ctx_id = CTX_SB_HP;
+#endif
+ }
+
+ return 0;
+}
+
+int dcss_scaler_init(struct dcss_soc *dcss, unsigned long scaler_base)
+{
+ struct dcss_scaler_priv *scaler;
+
+ scaler = devm_kzalloc(dcss->dev, sizeof(*scaler), GFP_KERNEL);
+ if (!scaler)
+ return -ENOMEM;
+
+ dcss->scaler_priv = scaler;
+ scaler->dcss = dcss;
+
+ scaler->ch_using_wrscl = -1;
+
+ return dcss_scaler_ch_init_all(dcss, scaler_base);
+}
+
+void dcss_scaler_exit(struct dcss_soc *dcss)
+{
+ struct dcss_scaler_priv *scaler = dcss->scaler_priv;
+ int ch_no;
+
+ for (ch_no = 0; ch_no < 3; ch_no++) {
+ struct dcss_scaler_ch *ch = &scaler->ch[ch_no];
+
+ dcss_writel(0, ch->base_reg + DCSS_SCALER_CTRL);
+ }
+}
+
+void dcss_scaler_enable(struct dcss_soc *dcss, int ch_num, bool en)
+{
+ struct dcss_scaler_priv *scaler = dcss->scaler_priv;
+ struct dcss_scaler_ch *ch = &scaler->ch[ch_num];
+ u32 scaler_ctrl;
+
+ if (scaler->ch_using_wrscl == ch_num) {
+ if (en) {
+ scaler_ctrl = SCALE2MEM_EN | MEM2OFIFO_EN | REPEAT_EN;
+ } else {
+ dcss_wrscl_enable(dcss, false);
+ dcss_rdsrc_enable(dcss, false);
+
+ scaler->ch_using_wrscl = -1;
+ scaler_ctrl = 0;
+ }
+ } else {
+ scaler_ctrl = en ? SCALER_EN | REPEAT_EN : 0;
+ }
+
+ if (en)
+ dcss_scaler_write(dcss->scaler_priv, ch_num, ch->sdata_ctrl,
+ DCSS_SCALER_SDATA_CTRL);
+
+ if (ch->scaler_ctrl != scaler_ctrl)
+ ch->scaler_ctrl_chgd = true;
+
+ ch->scaler_ctrl = scaler_ctrl;
+}
+EXPORT_SYMBOL(dcss_scaler_enable);
+
+static void dcss_scaler_yuv_enable(struct dcss_soc *dcss, int ch_num, bool en)
+{
+ struct dcss_scaler_ch *ch = &dcss->scaler_priv->ch[ch_num];
+
+ ch->sdata_ctrl &= ~YUV_EN;
+ ch->sdata_ctrl |= en ? YUV_EN : 0;
+}
+
+static void dcss_scaler_rtr_8lines_enable(struct dcss_soc *dcss, int ch_num,
+ bool en)
+{
+ struct dcss_scaler_ch *ch = &dcss->scaler_priv->ch[ch_num];
+
+ ch->sdata_ctrl &= ~RTRAM_8LINES;
+ ch->sdata_ctrl |= en ? RTRAM_8LINES : 0;
+}
+
+static void dcss_scaler_bit_depth_set(struct dcss_soc *dcss, int ch_num,
+ int depth)
+{
+ u32 val;
+
+ val = depth == 30 ? 2 : 0;
+
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ ((val << CHR_BIT_DEPTH_POS) & CHR_BIT_DEPTH_MASK) |
+ ((val << LUM_BIT_DEPTH_POS) & LUM_BIT_DEPTH_MASK),
+ DCSS_SCALER_BIT_DEPTH);
+}
+
+enum buffer_format {
+ BUF_FMT_YUV420,
+ BUF_FMT_YUV422,
+ BUF_FMT_ARGB8888_YUV444,
+};
+
+enum chroma_location {
+ PSC_LOC_HORZ_0_VERT_1_OVER_4 = 0,
+ PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4 = 1,
+ PSC_LOC_HORZ_0_VERT_0 = 2,
+ PSC_LOC_HORZ_1_OVER_4_VERT_0 = 3,
+ PSC_LOC_HORZ_0_VERT_1_OVER_2 = 4,
+ PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2 = 5
+};
+
+static void dcss_scaler_format_set(struct dcss_soc *dcss, int ch_num,
+ enum buffer_format src_fmt,
+ enum buffer_format dst_fmt)
+{
+ dcss_scaler_write(dcss->scaler_priv, ch_num, src_fmt,
+ DCSS_SCALER_SRC_FORMAT);
+ dcss_scaler_write(dcss->scaler_priv, ch_num, dst_fmt,
+ DCSS_SCALER_DST_FORMAT);
+}
+
+static void dcss_scaler_res_set(struct dcss_soc *dcss, int ch_num,
+ int src_xres, int src_yres,
+ int dst_xres, int dst_yres,
+ u32 pix_format, enum buffer_format dst_format)
+{
+ u32 lsrc_xres, lsrc_yres, csrc_xres, csrc_yres;
+ u32 ldst_xres, ldst_yres, cdst_xres, cdst_yres;
+ bool src_is_444 = true;
+
+ lsrc_xres = csrc_xres = src_xres;
+ lsrc_yres = csrc_yres = src_yres;
+ ldst_xres = cdst_xres = dst_xres;
+ ldst_yres = cdst_yres = dst_yres;
+
+ if (pix_format == DRM_FORMAT_UYVY || pix_format == DRM_FORMAT_VYUY ||
+ pix_format == DRM_FORMAT_YUYV || pix_format == DRM_FORMAT_YVYU) {
+ csrc_xres >>= 1;
+ src_is_444 = false;
+ } else if (pix_format == DRM_FORMAT_NV12 ||
+ pix_format == DRM_FORMAT_NV21 ||
+ pix_format == DRM_FORMAT_P010) {
+ csrc_xres >>= 1;
+ csrc_yres >>= 1;
+ src_is_444 = false;
+ }
+
+ if (dst_format == BUF_FMT_YUV422)
+ cdst_xres >>= 1;
+
+ /* for 4:4:4 to 4:2:2 conversion, source height should be 1 less */
+ if (src_is_444 && dst_format == BUF_FMT_YUV422) {
+ lsrc_yres--;
+ csrc_yres--;
+ }
+
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ (((lsrc_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+ (((lsrc_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+ DCSS_SCALER_SRC_LUM_RES);
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ (((csrc_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+ (((csrc_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+ DCSS_SCALER_SRC_CHR_RES);
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ (((ldst_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+ (((ldst_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+ DCSS_SCALER_DST_LUM_RES);
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ (((cdst_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+ (((cdst_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+ DCSS_SCALER_DST_CHR_RES);
+}
+
+#define max_downscale(ratio) ((ratio) << 13)
+#define max_upscale(ratio) ((1 << 13) / (ratio))
+
+struct dcss_scaler_ratios {
+ u16 downscale;
+ u16 upscale;
+};
+
+static const struct dcss_scaler_ratios dcss_scaler_ratios[] = {
+ {max_downscale(3), max_upscale(8)},
+ {max_downscale(5), max_upscale(8)},
+ {max_downscale(5), max_upscale(8)},
+};
+
+static const struct dcss_scaler_ratios dcss_scaler_wrscl_ratios[] = {
+ {max_downscale(5), max_upscale(8)},
+ {max_downscale(7), max_upscale(8)},
+ {max_downscale(7), max_upscale(8)},
+};
+
+static bool dcss_scaler_fractions_set(struct dcss_soc *dcss, int ch_num,
+ int src_xres, int src_yres,
+ int dst_xres, int dst_yres,
+ u32 src_format, u32 dst_format,
+ enum chroma_location src_chroma_loc)
+{
+ struct dcss_scaler_ch *ch = &dcss->scaler_priv->ch[ch_num];
+ int src_c_xres, src_c_yres, dst_c_xres, dst_c_yres;
+ u32 l_vinc, l_hinc, c_vinc, c_hinc;
+ u32 c_vstart, c_hstart;
+
+ src_c_xres = src_xres;
+ src_c_yres = src_yres;
+ dst_c_xres = dst_xres;
+ dst_c_yres = dst_yres;
+
+ c_vstart = 0;
+ c_hstart = 0;
+
+ /* adjustments for source chroma location */
+ if (src_format == BUF_FMT_YUV420) {
+ /* vertical input chroma position adjustment */
+ switch (src_chroma_loc) {
+ case PSC_LOC_HORZ_0_VERT_1_OVER_4:
+ case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4:
+ /*
+ * move chroma up to first luma line
+ * (1/4 chroma input line spacing)
+ */
+ c_vstart -= (1 << (PSC_PHASE_FRACTION_BITS - 2));
+ break;
+ case PSC_LOC_HORZ_0_VERT_1_OVER_2:
+ case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2:
+ /*
+ * move chroma up to first luma line
+ * (1/2 chroma input line spacing)
+ */
+ c_vstart -= (1 << (PSC_PHASE_FRACTION_BITS - 1));
+ break;
+ default:
+ break;
+ }
+ /* horizontal input chroma position adjustment */
+ switch (src_chroma_loc) {
+ case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4:
+ case PSC_LOC_HORZ_1_OVER_4_VERT_0:
+ case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2:
+ /* move chroma left 1/4 chroma input sample spacing */
+ c_hstart -= (1 << (PSC_PHASE_FRACTION_BITS - 2));
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* adjustments to chroma resolution */
+ if (src_format == BUF_FMT_YUV420) {
+ src_c_xres >>= 1;
+ src_c_yres >>= 1;
+ } else if (src_format == BUF_FMT_YUV422) {
+ src_c_xres >>= 1;
+ }
+
+ if (dst_format == BUF_FMT_YUV422)
+ dst_c_xres >>= 1;
+
+ l_vinc = ((src_yres << 13) + (dst_yres >> 1)) / dst_yres;
+ c_vinc = ((src_c_yres << 13) + (dst_c_yres >> 1)) / dst_c_yres;
+ l_hinc = ((src_xres << 13) + (dst_xres >> 1)) / dst_xres;
+ c_hinc = ((src_c_xres << 13) + (dst_c_xres >> 1)) / dst_c_xres;
+
+ /* save chroma start phase */
+ ch->c_vstart = c_vstart;
+ ch->c_hstart = c_hstart;
+
+ dcss_scaler_write(dcss->scaler_priv, ch_num, 0,
+ DCSS_SCALER_V_LUM_START);
+ dcss_scaler_write(dcss->scaler_priv, ch_num, l_vinc,
+ DCSS_SCALER_V_LUM_INC);
+
+ dcss_scaler_write(dcss->scaler_priv, ch_num, 0,
+ DCSS_SCALER_H_LUM_START);
+ dcss_scaler_write(dcss->scaler_priv, ch_num, l_hinc,
+ DCSS_SCALER_H_LUM_INC);
+
+ dcss_scaler_write(dcss->scaler_priv, ch_num, c_vstart,
+ DCSS_SCALER_V_CHR_START);
+ dcss_scaler_write(dcss->scaler_priv, ch_num, c_vinc,
+ DCSS_SCALER_V_CHR_INC);
+
+ dcss_scaler_write(dcss->scaler_priv, ch_num, c_hstart,
+ DCSS_SCALER_H_CHR_START);
+ dcss_scaler_write(dcss->scaler_priv, ch_num, c_hinc,
+ DCSS_SCALER_H_CHR_INC);
+
+ /* return if WR_SCL is needed to scale */
+ return l_vinc > dcss_scaler_ratios[ch_num].downscale ||
+ l_vinc < dcss_scaler_ratios[ch_num].upscale ||
+ l_hinc > dcss_scaler_ratios[ch_num].downscale ||
+ l_hinc < dcss_scaler_ratios[ch_num].upscale;
+}
+
+bool dcss_scaler_can_scale(struct dcss_soc *dcss, int ch_num,
+ int src_xres, int src_yres,
+ int dst_xres, int dst_yres)
+{
+ struct dcss_scaler_priv *scaler = dcss->scaler_priv;
+ u32 vscale_fp, hscale_fp;
+ const struct dcss_scaler_ratios *ratios_map = dcss_scaler_ratios;
+
+ /* Convert to fixed point. Easier to work with. */
+ vscale_fp = ((src_yres << 13) + (dst_yres >> 1)) / dst_yres;
+ hscale_fp = ((src_xres << 13) + (dst_xres >> 1)) / dst_xres;
+
+ if (scaler->ch_using_wrscl == -1 || scaler->ch_using_wrscl == ch_num)
+ ratios_map = dcss_scaler_wrscl_ratios;
+
+ return vscale_fp <= ratios_map[ch_num].downscale &&
+ vscale_fp >= ratios_map[ch_num].upscale &&
+ hscale_fp <= ratios_map[ch_num].downscale &&
+ hscale_fp >= ratios_map[ch_num].upscale;
+}
+EXPORT_SYMBOL(dcss_scaler_can_scale);
+
+static void dcss_scaler_program_7_coef_set(struct dcss_soc *dcss, int ch_num,
+ int base_addr,
+ int coef[][PSC_NUM_TAPS])
+{
+ int i, phase;
+
+ for (i = 0; i < PSC_STORED_PHASES; i++) {
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ ((coef[i][0] & 0xfff) << 16 |
+ (coef[i][1] & 0xfff) << 4 |
+ (coef[i][2] & 0xf00) >> 8),
+ base_addr + i * sizeof(u32));
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ ((coef[i][2] & 0x0ff) << 20 |
+ (coef[i][3] & 0xfff) << 8 |
+ (coef[i][4] & 0xff0) >> 4),
+ base_addr + 0x40 + i * sizeof(u32));
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ ((coef[i][4] & 0x00f) << 24 |
+ (coef[i][5] & 0xfff) << 12 |
+ (coef[i][6] & 0xfff)),
+ base_addr + 0x80 + i * sizeof(u32));
+ }
+
+ /* reverse both phase and tap orderings */
+ for (phase = (PSC_NUM_PHASES >> 1) - 1; i < PSC_NUM_PHASES; i++, phase--) {
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ ((coef[phase][6] & 0xfff) << 16 |
+ (coef[phase][5] & 0xfff) << 4 |
+ (coef[phase][4] & 0xf00) >> 8),
+ base_addr + i * sizeof(u32));
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ ((coef[phase][4] & 0x0ff) << 20 |
+ (coef[phase][3] & 0xfff) << 8 |
+ (coef[phase][2] & 0xff0) >> 4),
+ base_addr + 0x40 + i * sizeof(u32));
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ ((coef[phase][2] & 0x00f) << 24 |
+ (coef[phase][1] & 0xfff) << 12 |
+ (coef[phase][0] & 0xfff)),
+ base_addr + 0x80 + i * sizeof(u32));
+ }
+}
+
+static void dcss_scaler_program_5_coef_set(struct dcss_soc *dcss, int ch_num,
+ int base_addr,
+ int coef[][PSC_NUM_TAPS])
+{
+ int i, phase;
+
+ for (i = 0; i < PSC_STORED_PHASES; i++) {
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ ((coef[i][1] & 0xfff) << 16 |
+ (coef[i][2] & 0xfff) << 4 |
+ (coef[i][3] & 0xf00) >> 8),
+ base_addr + i * sizeof(u32));
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ ((coef[i][3] & 0x0ff) << 20 |
+ (coef[i][4] & 0xfff) << 8 |
+ (coef[i][5] & 0xff0) >> 4),
+ base_addr + 0x40 + i * sizeof(u32));
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ ((coef[i][5] & 0x00f) << 24),
+ base_addr + 0x80 + i * sizeof(u32));
+ }
+ /* reverse both phase and tap orderings */
+ for (phase = (PSC_NUM_PHASES >> 1) - 1; i < PSC_NUM_PHASES; i++, phase--) {
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ ((coef[phase][5] & 0xfff) << 16 |
+ (coef[phase][4] & 0xfff) << 4 |
+ (coef[phase][3] & 0xf00) >> 8),
+ base_addr + i * sizeof(u32));
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ ((coef[phase][3] & 0x0ff) << 20 |
+ (coef[phase][2] & 0xfff) << 8 |
+ (coef[phase][1] & 0xff0) >> 4),
+ base_addr + 0x40 + i * sizeof(u32));
+ dcss_scaler_write(dcss->scaler_priv, ch_num,
+ ((coef[phase][1] & 0x00f) << 24),
+ base_addr + 0x80 + i * sizeof(u32));
+ }
+}
+
+static void dcss_scaler_yuv_coef_set(struct dcss_soc *dcss, int ch_num,
+ enum buffer_format src_format,
+ enum buffer_format dst_format,
+ bool use_5_taps,
+ int src_xres, int src_yres, int dst_xres,
+ int dst_yres)
+{
+ struct dcss_scaler_ch *ch = &dcss->scaler_priv->ch[ch_num];
+ int coef[PSC_STORED_PHASES][PSC_NUM_TAPS];
+ bool program_5_taps = use_5_taps ||
+ (dst_format == BUF_FMT_YUV422 &&
+ src_format == BUF_FMT_ARGB8888_YUV444);
+
+ /* horizontal luma */
+ dcss_scaler_filter_design(src_xres, dst_xres, 0,
+ src_xres == dst_xres, coef);
+ dcss_scaler_program_7_coef_set(dcss, ch_num,
+ DCSS_SCALER_COEF_HLUM, coef);
+
+ /* vertical luma */
+ dcss_scaler_filter_design(src_yres, dst_yres, use_5_taps,
+ src_yres == dst_yres, coef);
+
+ if (program_5_taps)
+ dcss_scaler_program_5_coef_set(dcss, ch_num,
+ DCSS_SCALER_COEF_VLUM, coef);
+ else
+ dcss_scaler_program_7_coef_set(dcss, ch_num,
+ DCSS_SCALER_COEF_VLUM, coef);
+
+ /* adjust chroma resolution */
+ if (src_format != BUF_FMT_ARGB8888_YUV444)
+ src_xres >>= 1;
+ if (src_format == BUF_FMT_YUV420)
+ src_yres >>= 1;
+ if (dst_format != BUF_FMT_ARGB8888_YUV444)
+ dst_xres >>= 1;
+ if (dst_format == BUF_FMT_YUV420) /* should not happen */
+ dst_yres >>= 1;
+
+ /* horizontal chroma */
+ dcss_scaler_filter_design(src_xres, dst_xres, 0,
+ (src_xres == dst_xres) && (ch->c_hstart == 0),
+ coef);
+
+ dcss_scaler_program_7_coef_set(dcss, ch_num,
+ DCSS_SCALER_COEF_HCHR, coef);
+
+ /* vertical chroma */
+ dcss_scaler_filter_design(src_yres, dst_yres, use_5_taps,
+ (src_yres == dst_yres) && (ch->c_vstart == 0),
+ coef);
+
+ if (program_5_taps)
+ dcss_scaler_program_5_coef_set(dcss, ch_num,
+ DCSS_SCALER_COEF_VCHR, coef);
+ else
+ dcss_scaler_program_7_coef_set(dcss, ch_num,
+ DCSS_SCALER_COEF_VCHR, coef);
+}
+
+static void dcss_scaler_rgb_coef_set(struct dcss_soc *dcss, int ch_num,
+ int src_xres, int src_yres, int dst_xres,
+ int dst_yres)
+{
+ int coef[PSC_STORED_PHASES][PSC_NUM_TAPS];
+
+ /* horizontal RGB */
+ dcss_scaler_filter_design(src_xres, dst_xres, 0,
+ src_xres == dst_xres, coef);
+ dcss_scaler_program_7_coef_set(dcss, ch_num,
+ DCSS_SCALER_COEF_HLUM, coef);
+
+ /* vertical RGB */
+ dcss_scaler_filter_design(src_yres, dst_yres, 1,
+ src_yres == dst_yres, coef);
+ dcss_scaler_program_5_coef_set(dcss, ch_num,
+ DCSS_SCALER_COEF_VLUM, coef);
+}
+
+static void dcss_scaler_set_rgb10_order(struct dcss_soc *dcss, int ch_num,
+ u32 pix_format)
+{
+ struct dcss_scaler_ch *ch = &dcss->scaler_priv->ch[ch_num];
+ enum dcss_color_space dcss_cs;
+ unsigned int pixel_depth;
+ int bpp;
+ u32 a2r10g10b10_format;
+
+ dcss_cs = dcss_drm_fourcc_to_colorspace(pix_format);
+
+ if (dcss_cs != DCSS_COLORSPACE_RGB)
+ return;
+
+ drm_fb_get_bpp_depth(pix_format, &pixel_depth, &bpp);
+
+ ch->sdata_ctrl &= ~A2R10G10B10_FORMAT_MASK;
+
+ if (pixel_depth != 30)
+ return;
+
+ switch (pix_format) {
+ case DRM_FORMAT_ARGB2101010:
+ case DRM_FORMAT_XRGB2101010:
+ a2r10g10b10_format = 0;
+ break;
+
+ case DRM_FORMAT_ABGR2101010:
+ case DRM_FORMAT_XBGR2101010:
+ a2r10g10b10_format = 5;
+ break;
+
+ case DRM_FORMAT_RGBA1010102:
+ case DRM_FORMAT_RGBX1010102:
+ a2r10g10b10_format = 6;
+ break;
+
+ case DRM_FORMAT_BGRA1010102:
+ case DRM_FORMAT_BGRX1010102:
+ a2r10g10b10_format = 11;
+ break;
+
+ default:
+ a2r10g10b10_format = 0;
+ break;
+ }
+
+ ch->sdata_ctrl |= a2r10g10b10_format << A2R10G10B10_FORMAT_POS;
+}
+
+static void dcss_scaler_setup_path(struct dcss_soc *dcss, int ch_num,
+ u32 pix_format, int dst_xres,
+ int dst_yres, u32 vrefresh_hz,
+ bool wrscl_needed)
+{
+ struct dcss_scaler_priv *scaler = dcss->scaler_priv;
+ u32 base_addr;
+
+ /* nothing to do if WRSCL path is needed but it's already used */
+ if (wrscl_needed && scaler->ch_using_wrscl != -1 &&
+ scaler->ch_using_wrscl != ch_num)
+ return;
+
+ if (!wrscl_needed) {
+ /* Channel has finished using WRSCL. Release WRSCL/RDSRC. */
+ if (scaler->ch_using_wrscl == ch_num) {
+ dcss_wrscl_enable(dcss, false);
+ dcss_rdsrc_enable(dcss, false);
+
+ scaler->ch_using_wrscl = -1;
+ }
+
+ return;
+ }
+
+ base_addr = dcss_wrscl_setup(dcss, pix_format, vrefresh_hz,
+ dst_xres, dst_yres);
+
+ dcss_rdsrc_setup(dcss, pix_format, dst_xres, dst_yres,
+ base_addr);
+
+ dcss_wrscl_enable(dcss, true);
+ dcss_rdsrc_enable(dcss, true);
+
+ scaler->ch_using_wrscl = ch_num;
+}
+
+void dcss_scaler_setup(struct dcss_soc *dcss, int ch_num, u32 pix_format,
+ int src_xres, int src_yres, int dst_xres, int dst_yres,
+ u32 vrefresh_hz)
+{
+ enum dcss_color_space dcss_cs;
+ int planes;
+ unsigned int pixel_depth = 0;
+ bool rtr_8line_en = false;
+ bool use_5_taps = false;
+ u32 bpp;
+ enum buffer_format src_format = BUF_FMT_ARGB8888_YUV444;
+ enum buffer_format dst_format = BUF_FMT_ARGB8888_YUV444;
+ bool wrscl_needed = false;
+
+ dcss_cs = dcss_drm_fourcc_to_colorspace(pix_format);
+ planes = drm_format_num_planes(pix_format);
+
+ if (dcss_cs == DCSS_COLORSPACE_YUV) {
+ dcss_scaler_yuv_enable(dcss, ch_num, true);
+
+ if (pix_format == DRM_FORMAT_NV12 ||
+ pix_format == DRM_FORMAT_NV21 ||
+ pix_format == DRM_FORMAT_P010) {
+ rtr_8line_en = true;
+ src_format = BUF_FMT_YUV420;
+ } else if (pix_format == DRM_FORMAT_UYVY ||
+ pix_format == DRM_FORMAT_VYUY ||
+ pix_format == DRM_FORMAT_YUYV ||
+ pix_format == DRM_FORMAT_YVYU) {
+ src_format = BUF_FMT_YUV422;
+ }
+
+ use_5_taps = !rtr_8line_en;
+ if (pix_format == DRM_FORMAT_P010)
+ pixel_depth = 30;
+
+ } else if (dcss_cs == DCSS_COLORSPACE_RGB) {
+ dcss_scaler_yuv_enable(dcss, ch_num, false);
+
+ drm_fb_get_bpp_depth(pix_format, &pixel_depth, &bpp);
+ }
+
+ /* TODO: get src_chroma_loc from VPU metadata */
+ wrscl_needed = dcss_scaler_fractions_set(dcss, ch_num, src_xres,
+ src_yres, dst_xres,
+ dst_yres, src_format,
+ dst_format,
+ 0 /* src_chroma_loc */);
+
+ if (dcss_cs == DCSS_COLORSPACE_YUV) {
+ dcss_scaler_yuv_coef_set(dcss, ch_num, src_format, dst_format,
+ use_5_taps, src_xres, src_yres,
+ dst_xres, dst_yres);
+ } else if (dcss_cs == DCSS_COLORSPACE_RGB) {
+ dcss_scaler_rgb_coef_set(dcss, ch_num, src_xres, src_yres,
+ dst_xres, dst_yres);
+ }
+
+ dcss_scaler_rtr_8lines_enable(dcss, ch_num, rtr_8line_en);
+ dcss_scaler_bit_depth_set(dcss, ch_num, pixel_depth);
+ dcss_scaler_set_rgb10_order(dcss, ch_num, pix_format);
+ dcss_scaler_format_set(dcss, ch_num, src_format, dst_format);
+ dcss_scaler_res_set(dcss, ch_num, src_xres, src_yres,
+ dst_xres, dst_yres, pix_format, dst_format);
+
+ dcss_scaler_setup_path(dcss, ch_num, pix_format, dst_xres,
+ dst_yres, vrefresh_hz, wrscl_needed);
+}
+EXPORT_SYMBOL(dcss_scaler_setup);
+
+void dcss_scaler_write_sclctrl(struct dcss_soc *dcss)
+{
+ int chnum;
+
+ for (chnum = 0; chnum < 3; chnum++) {
+ struct dcss_scaler_ch *ch = &dcss->scaler_priv->ch[chnum];
+
+ if (ch->scaler_ctrl_chgd) {
+ dcss_ctxld_write_irqsafe(dcss, ch->ctx_id,
+ ch->scaler_ctrl,
+ ch->base_ofs + DCSS_SCALER_CTRL);
+ ch->scaler_ctrl_chgd = false;
+ }
+ }
+}
diff --git a/drivers/gpu/imx/dcss/dcss-ss.c b/drivers/gpu/imx/dcss/dcss-ss.c
new file mode 100644
index 000000000000..f44fb602e140
--- /dev/null
+++ b/drivers/gpu/imx/dcss/dcss-ss.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <video/videomode.h>
+#include <drm/drm_fourcc.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+
+#define USE_CTXLD
+
+#define DCSS_SS_SYS_CTRL 0x00
+#define RUN_EN BIT(0)
+#define DCSS_SS_DISPLAY 0x10
+#define LRC_X_POS 0
+#define LRC_X_MASK GENMASK(12, 0)
+#define LRC_Y_POS 16
+#define LRC_Y_MASK GENMASK(28, 16)
+#define DCSS_SS_HSYNC 0x20
+#define DCSS_SS_VSYNC 0x30
+#define SYNC_START_POS 0
+#define SYNC_START_MASK GENMASK(12, 0)
+#define SYNC_END_POS 16
+#define SYNC_END_MASK GENMASK(28, 16)
+#define SYNC_POL BIT(31)
+#define DCSS_SS_DE_ULC 0x40
+#define ULC_X_POS 0
+#define ULC_X_MASK GENMASK(12, 0)
+#define ULC_Y_POS 16
+#define ULC_Y_MASK GENMASK(28, 16)
+#define ULC_POL BIT(31)
+#define DCSS_SS_DE_LRC 0x50
+#define DCSS_SS_MODE 0x60
+#define PIPE_MODE_POS 0
+#define PIPE_MODE_MASK GENMASK(1, 0)
+#define DCSS_SS_COEFF 0x70
+#define HORIZ_A_POS 0
+#define HORIZ_A_MASK GENMASK(3, 0)
+#define HORIZ_B_POS 4
+#define HORIZ_B_MASK GENMASK(7, 4)
+#define HORIZ_C_POS 8
+#define HORIZ_C_MASK GENMASK(11, 8)
+#define HORIZ_H_NORM_POS 12
+#define HORIZ_H_NORM_MASK GENMASK(14, 12)
+#define VERT_A_POS 16
+#define VERT_A_MASK GENMASK(19, 16)
+#define VERT_B_POS 20
+#define VERT_B_MASK GENMASK(23, 20)
+#define VERT_C_POS 24
+#define VERT_C_MASK GENMASK(27, 24)
+#define VERT_H_NORM_POS 28
+#define VERT_H_NORM_MASK GENMASK(30, 28)
+#define DCSS_SS_CLIP_CB 0x80
+#define DCSS_SS_CLIP_CR 0x90
+#define CLIP_MIN_POS 0
+#define CLIP_MIN_MASK GENMASK(9, 0)
+#define CLIP_MAX_POS 0
+#define CLIP_MAX_MASK GENMASK(23, 16)
+#define DCSS_SS_INTER_MODE 0xA0
+#define INT_EN BIT(0)
+#define VSYNC_SHIFT BIT(1)
+
+static struct dcss_debug_reg ss_debug_reg[] = {
+ DCSS_DBG_REG(DCSS_SS_SYS_CTRL),
+ DCSS_DBG_REG(DCSS_SS_DISPLAY),
+ DCSS_DBG_REG(DCSS_SS_HSYNC),
+ DCSS_DBG_REG(DCSS_SS_VSYNC),
+ DCSS_DBG_REG(DCSS_SS_DE_ULC),
+ DCSS_DBG_REG(DCSS_SS_DE_LRC),
+ DCSS_DBG_REG(DCSS_SS_MODE),
+ DCSS_DBG_REG(DCSS_SS_COEFF),
+ DCSS_DBG_REG(DCSS_SS_CLIP_CB),
+ DCSS_DBG_REG(DCSS_SS_CLIP_CR),
+ DCSS_DBG_REG(DCSS_SS_INTER_MODE),
+};
+
+struct dcss_ss_priv {
+ struct dcss_soc *dcss;
+ void __iomem *base_reg;
+ u32 base_ofs;
+
+ u32 ctx_id;
+
+ bool in_use;
+};
+
+static void dcss_ss_write(struct dcss_ss_priv *ss, u32 val, u32 ofs)
+{
+ if (!ss->in_use)
+ dcss_writel(val, ss->base_reg + ofs);
+#if defined(USE_CTXLD)
+ dcss_ctxld_write(ss->dcss, ss->ctx_id, val,
+ ss->base_ofs + ofs);
+#endif
+}
+
+#ifdef CONFIG_DEBUG_FS
+void dcss_ss_dump_regs(struct seq_file *s, void *data)
+{
+ struct dcss_soc *dcss = data;
+ int j;
+
+ seq_puts(s, ">> Dumping SUBSAM:\n");
+ for (j = 0; j < ARRAY_SIZE(ss_debug_reg); j++)
+ seq_printf(s, "%-35s(0x%04x) -> 0x%08x\n",
+ ss_debug_reg[j].name,
+ ss_debug_reg[j].ofs,
+ dcss_readl(dcss->ss_priv->base_reg +
+ ss_debug_reg[j].ofs));
+}
+#endif
+
+int dcss_ss_init(struct dcss_soc *dcss, unsigned long ss_base)
+{
+ struct dcss_ss_priv *ss;
+
+ ss = devm_kzalloc(dcss->dev, sizeof(*ss), GFP_KERNEL);
+ if (!ss)
+ return -ENOMEM;
+
+ dcss->ss_priv = ss;
+ ss->dcss = dcss;
+
+ ss->base_reg = devm_ioremap(dcss->dev, ss_base, SZ_4K);
+ if (!ss->base_reg) {
+ dev_err(dcss->dev, "ss: unable to remap ss base\n");
+ return -ENOMEM;
+ }
+
+ ss->base_ofs = ss_base;
+
+#if defined(USE_CTXLD)
+ ss->ctx_id = CTX_SB_HP;
+#endif
+
+ return 0;
+}
+
+void dcss_ss_exit(struct dcss_soc *dcss)
+{
+ dcss_writel(0, dcss->ss_priv->base_reg + DCSS_SS_SYS_CTRL);
+}
+
+void dcss_ss_subsam_set(struct dcss_soc *dcss, u32 pix_format)
+{
+ if (pix_format == DRM_FORMAT_P010) {
+ dcss_ss_write(dcss->ss_priv, 0x21612161, DCSS_SS_COEFF);
+ dcss_ss_write(dcss->ss_priv, 2, DCSS_SS_MODE);
+ dcss_ss_write(dcss->ss_priv, 0x03c00040, DCSS_SS_CLIP_CB);
+ dcss_ss_write(dcss->ss_priv, 0x03c00040, DCSS_SS_CLIP_CR);
+
+ return;
+ }
+
+ dcss_ss_write(dcss->ss_priv, 0x41614161, DCSS_SS_COEFF);
+ dcss_ss_write(dcss->ss_priv, 0, DCSS_SS_MODE);
+ dcss_ss_write(dcss->ss_priv, 0x03ff0000, DCSS_SS_CLIP_CB);
+ dcss_ss_write(dcss->ss_priv, 0x03ff0000, DCSS_SS_CLIP_CR);
+}
+
+void dcss_ss_sync_set(struct dcss_soc *dcss, struct videomode *vm,
+ bool phsync, bool pvsync)
+{
+ struct dcss_ss_priv *ss = dcss->ss_priv;
+ u16 lrc_x, lrc_y;
+ u16 hsync_start, hsync_end;
+ u16 vsync_start, vsync_end;
+ u16 de_ulc_x, de_ulc_y;
+ u16 de_lrc_x, de_lrc_y;
+
+ lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
+ vm->hactive - 1;
+ lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len +
+ vm->vactive - 1;
+
+ dcss_ss_write(ss, (lrc_y << LRC_Y_POS) | lrc_x, DCSS_SS_DISPLAY);
+
+ hsync_start = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
+ vm->hactive - 1;
+ hsync_end = vm->hsync_len - 1;
+
+ dcss_ss_write(ss, (phsync ? SYNC_POL : 0) |
+ (hsync_end << SYNC_END_POS) | hsync_start,
+ DCSS_SS_HSYNC);
+
+ vsync_start = vm->vfront_porch - 1;
+ vsync_end = vm->vfront_porch + vm->vsync_len - 1;
+
+ dcss_ss_write(ss, (pvsync ? SYNC_POL : 0) |
+ (vsync_end << SYNC_END_POS) | vsync_start, DCSS_SS_VSYNC);
+
+ de_ulc_x = vm->hsync_len + vm->hback_porch - 1;
+ de_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch;
+
+ dcss_ss_write(ss, SYNC_POL | (de_ulc_y << ULC_Y_POS) | de_ulc_x,
+ DCSS_SS_DE_ULC);
+
+ de_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1;
+ de_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch +
+ vm->vactive - 1;
+
+ dcss_ss_write(ss, (de_lrc_y << LRC_Y_POS) | de_lrc_x, DCSS_SS_DE_LRC);
+}
+EXPORT_SYMBOL(dcss_ss_sync_set);
+
+void dcss_ss_enable(struct dcss_soc *dcss, bool en)
+{
+ struct dcss_ss_priv *ss = dcss->ss_priv;
+
+ dcss_ss_write(ss, en ? RUN_EN : 0, DCSS_SS_SYS_CTRL);
+}
+EXPORT_SYMBOL(dcss_ss_enable);
diff --git a/drivers/gpu/imx/dcss/dcss-wrscl.c b/drivers/gpu/imx/dcss/dcss-wrscl.c
new file mode 100644
index 000000000000..30b225958cf7
--- /dev/null
+++ b/drivers/gpu/imx/dcss/dcss-wrscl.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+
+#define USE_CTXLD
+
+#define DCSS_WRSCL_CTRL_STATUS 0x00
+#define WRSCL_ERR BIT(31)
+#define WRSCL_ERR_EN BIT(30)
+#define WRSCL_FRAME_COMP BIT(29)
+#define WRSCL_FRAME_COMP_EN BIT(28)
+#define WRSCL_FIFO_SIZE_POS 18
+#define WRSCL_FIFO_SIZE_MASK GENMAK(24, 18)
+#define WRSCL_P_FREQ_POS 10
+#define WRSCL_P_FREQ_MASK GENMASK(17, 10)
+#define WRSCL_P_SIZE_POS 7
+#define WRSCL_P_SIZE_MASK GENMASK(9, 7)
+#define WRSCL_T_SIZE_POS 5
+#define WRSCL_T_SIZE_MASK GENMASK(6, 5)
+#define WRSCL_BPP_POS 2
+#define WRSCL_BPP_MASK GENMASK(4, 2)
+#define WRSCL_REPEAT BIT(1)
+#define WRSCL_ENABLE BIT(0)
+#define DCSS_WRSCL_BASE_ADDR 0x10
+#define DCSS_WRSCL_PITCH 0x14
+
+struct dcss_wrscl_priv {
+ void __iomem *base_reg;
+ u32 base_ofs;
+ struct dcss_soc *dcss;
+
+ u32 ctx_id;
+
+ u32 buf_size;
+ u32 buf_addr;
+ void *buf_vaddr;
+
+ u32 ctrl_status;
+};
+
+#ifdef CONFIG_DEBUG_FS
+static struct dcss_debug_reg wrscl_debug_reg[] = {
+ DCSS_DBG_REG(DCSS_WRSCL_CTRL_STATUS),
+ DCSS_DBG_REG(DCSS_WRSCL_BASE_ADDR),
+ DCSS_DBG_REG(DCSS_WRSCL_PITCH),
+};
+
+void dcss_wrscl_dump_regs(struct seq_file *s, void *data)
+{
+ struct dcss_soc *dcss = data;
+ int i;
+
+ seq_puts(s, ">> Dumping WR_SCL:\n");
+ for (i = 0; i < ARRAY_SIZE(wrscl_debug_reg); i++) {
+ seq_printf(s, "%-35s(0x%04x) -> 0x%08x\n",
+ wrscl_debug_reg[i].name,
+ wrscl_debug_reg[i].ofs,
+ dcss_readl(dcss->wrscl_priv->base_reg +
+ wrscl_debug_reg[i].ofs));
+ }
+}
+#endif
+
+static void dcss_wrscl_write(struct dcss_wrscl_priv *wrscl, u32 val, u32 ofs)
+{
+#if !defined(USE_CTXLD)
+ dcss_writel(val, wrscl->base_reg + ofs);
+#else
+ dcss_ctxld_write(wrscl->dcss, wrscl->ctx_id,
+ val, wrscl->base_ofs + ofs);
+#endif
+}
+
+int dcss_wrscl_init(struct dcss_soc *dcss, unsigned long wrscl_base)
+{
+ struct dcss_wrscl_priv *wrscl;
+
+ wrscl = devm_kzalloc(dcss->dev, sizeof(*wrscl), GFP_KERNEL);
+ if (!wrscl)
+ return -ENOMEM;
+
+ wrscl->base_reg = devm_ioremap(dcss->dev, wrscl_base, SZ_4K);
+ if (!wrscl->base_reg) {
+ dev_err(dcss->dev, "wrscl: unable to remap base\n");
+ return -ENOMEM;
+ }
+
+ dcss->wrscl_priv = wrscl;
+ wrscl->base_ofs = wrscl_base;
+ wrscl->dcss = dcss;
+
+#if defined(USE_CTXLD)
+ wrscl->ctx_id = CTX_SB_HP;
+#endif
+
+ return 0;
+}
+
+void dcss_wrscl_exit(struct dcss_soc *dcss)
+{
+}
+
+static const u16 dcss_wrscl_psize_map[] = {64, 128, 256, 512, 1024, 2048, 4096};
+
+u32 dcss_wrscl_setup(struct dcss_soc *dcss, u32 pix_format, u32 vrefresh_hz,
+ u32 dst_xres, u32 dst_yres)
+{
+ struct dcss_wrscl_priv *wrscl = dcss->wrscl_priv;
+ u32 pitch, p_size, p_freq, bpp;
+ dma_addr_t dma_handle;
+ u32 b_clk = clk_get_rate(dcss->axi_clk);
+
+ /* we'd better release the old buffer */
+ if (wrscl->buf_addr)
+ dmam_free_coherent(dcss->dev, wrscl->buf_size,
+ wrscl->buf_vaddr, wrscl->buf_addr);
+
+ p_size = PSIZE_256;
+
+ /* scaler output is YUV444 */
+ bpp = 4;
+
+ /* spread the load over the entire frame */
+ p_freq = ((u64)b_clk * dcss_wrscl_psize_map[p_size]) /
+ ((u64)dst_xres * dst_yres * vrefresh_hz * bpp * 8);
+
+ /* choose a slightly smaller p_freq */
+ p_freq = p_freq - 3 > 255 ? 255 : p_freq - 3;
+
+ wrscl->ctrl_status = FIFO_512 << WRSCL_FIFO_SIZE_POS;
+ wrscl->ctrl_status |= p_size << WRSCL_P_SIZE_POS;
+ wrscl->ctrl_status |= TSIZE_256 << WRSCL_T_SIZE_POS;
+ wrscl->ctrl_status |= BPP_32_10BIT_OUTPUT << WRSCL_BPP_POS;
+ wrscl->ctrl_status |= p_freq << WRSCL_P_FREQ_POS;
+
+ wrscl->buf_size = dst_xres * dst_yres * bpp;
+ pitch = dst_xres * bpp;
+
+ wrscl->buf_vaddr = dmam_alloc_coherent(dcss->dev, wrscl->buf_size,
+ &dma_handle, GFP_KERNEL);
+ if (!wrscl->buf_vaddr) {
+ dev_err(dcss->dev, "wrscl: cannot alloc buf mem\n");
+ return 0;
+ }
+
+ wrscl->buf_addr = dma_handle;
+
+ dcss_wrscl_write(wrscl, wrscl->buf_addr, DCSS_WRSCL_BASE_ADDR);
+ dcss_wrscl_write(wrscl, pitch, DCSS_WRSCL_PITCH);
+
+ return wrscl->buf_addr;
+}
+
+void dcss_wrscl_enable(struct dcss_soc *dcss, bool en)
+{
+ struct dcss_wrscl_priv *wrscl = dcss->wrscl_priv;
+
+ if (en)
+ wrscl->ctrl_status |= WRSCL_ENABLE | WRSCL_REPEAT;
+ else
+ wrscl->ctrl_status &= ~(WRSCL_ENABLE | WRSCL_REPEAT);
+
+ dcss_wrscl_write(wrscl, wrscl->ctrl_status, DCSS_WRSCL_CTRL_STATUS);
+
+ if (!en && wrscl->buf_addr) {
+ dmam_free_coherent(dcss->dev, wrscl->buf_size,
+ wrscl->buf_vaddr, wrscl->buf_addr);
+ wrscl->buf_addr = 0;
+ }
+}
+
diff --git a/drivers/gpu/imx/dpu-blit/Kconfig b/drivers/gpu/imx/dpu-blit/Kconfig
new file mode 100644
index 000000000000..d71d9a7f9515
--- /dev/null
+++ b/drivers/gpu/imx/dpu-blit/Kconfig
@@ -0,0 +1,5 @@
+config IMX_DPU_BLIT
+ tristate
+ depends on IMX_DPU_CORE
+ default y if IMX_DPU_CORE=y
+ default m if IMX_DPU_CORE=m
diff --git a/drivers/gpu/imx/dpu-blit/Makefile b/drivers/gpu/imx/dpu-blit/Makefile
new file mode 100644
index 000000000000..a1c760d36ad8
--- /dev/null
+++ b/drivers/gpu/imx/dpu-blit/Makefile
@@ -0,0 +1,5 @@
+ccflags-y += -Idrivers/gpu/imx/dpu
+
+imx-dpu-blit-objs := dpu-blit.o
+
+obj-$(CONFIG_IMX_DPU_BLIT) += imx-dpu-blit.o
diff --git a/drivers/gpu/imx/dpu-blit/dpu-blit-registers.h b/drivers/gpu/imx/dpu-blit/dpu-blit-registers.h
new file mode 100644
index 000000000000..3d86b272e281
--- /dev/null
+++ b/drivers/gpu/imx/dpu-blit/dpu-blit-registers.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef __DPU_BLIT_REGISTERS_H__
+#define __DPU_BLIT_REGISTERS_H__
+
+/* Registers Defination */
+#define COMCTRL_IPIDENTIFIER ((uint32_t)(0))
+
+#define PIXENGCFG_STORE9_TRIGGER ((uint32_t)(0x954))
+
+#define COMCTRL_USERINTERRUPTMASK0 ((uint32_t)(0x48))
+#define COMCTRL_USERINTERRUPTMASK0_USERINTERRUPTMASK0_MASK 0xFFFFFFFFU
+#define COMCTRL_USERINTERRUPTENABLE0 ((uint32_t)(0x80))
+
+#define COMCTRL_INTERRUPTENABLE0 ((uint32_t)(0x50))
+
+#define COMCTRL_INTERRUPTSTATUS0 ((uint32_t)(0x68))
+#define COMCTRL_USERINTERRUPTSTATUS0 ((uint32_t)(0x98))
+
+#define COMCTRL_USERINTERRUPTCLEAR0 ((uint32_t)(0x90))
+#define COMCTRL_USERINTERRUPTCLEAR0_USERINTERRUPTCLEAR0_MASK 0xFFFFFFFFU
+
+#define COMCTRL_INTERRUPTCLEAR0 ((uint32_t)(0x60))
+#define COMCTRL_INTERRUPTCLEAR0_INTERRUPTCLEAR0_MASK 0xFFFFFFFFU
+
+
+#define PIXENGCFG_FETCHDECODE9_DYNAMIC ((uint32_t)(0x828))
+#define PIXENGCFG_FETCHDECODE9_DYNAMIC_RESET_VALUE 0U
+
+#define PIXENGCFG_FETCHWARP9_DYNAMIC ((uint32_t)(0x848))
+#define PIXENGCFG_FETCHWARP9_DYNAMIC_RESET_VALUE 0U
+
+#define PIXENGCFG_ROP9_DYNAMIC ((uint32_t)(0x868))
+#define PIXENGCFG_ROP9_DYNAMIC_RESET_VALUE 0x1000000U
+
+#define PIXENGCFG_MATRIX9_DYNAMIC ((uint32_t)(0x8A8))
+#define PIXENGCFG_MATRIX9_DYNAMIC_RESET_VALUE 0x1000000U
+
+#define PIXENGCFG_HSCALER9_DYNAMIC ((uint32_t)(0x8C8))
+#define PIXENGCFG_HSCALER9_DYNAMIC_RESET_VALUE 0x1000000U
+
+#define PIXENGCFG_VSCALER9_DYNAMIC ((uint32_t)(0x8E8))
+#define PIXENGCFG_VSCALER9_DYNAMIC_RESET_VALUE 0x1000000U
+
+#define PIXENGCFG_BLITBLEND9_DYNAMIC ((uint32_t)(0x928))
+#define PIXENGCFG_BLITBLEND9_DYNAMIC_RESET_VALUE 0x1000000U
+
+#define PIXENGCFG_STORE9_STATIC ((uint32_t)(0x948))
+#define PIXENGCFG_STORE9_STATIC_RESET_VALUE 0x800010U
+#define PIXENGCFG_STORE9_STATIC_RESET_MASK 0xFFFFFFFFU
+#define PIXENGCFG_STORE9_STATIC_STORE9_SHDEN_MASK 0x1U
+#define PIXENGCFG_STORE9_STATIC_STORE9_SHDEN_SHIFT 0U
+#define PIXENGCFG_STORE9_STATIC_STORE9_POWERDOWN_MASK 0x10U
+#define PIXENGCFG_STORE9_STATIC_STORE9_POWERDOWN_SHIFT 4U
+#define PIXENGCFG_STORE9_STATIC_STORE9_SYNC_MODE_MASK 0x100U
+#define PIXENGCFG_STORE9_STATIC_STORE9_SYNC_MODE_SHIFT 8U
+#define PIXENGCFG_STORE9_STATIC_STORE9_SYNC_MODE__SINGLE 0U
+#define PIXENGCFG_STORE9_STATIC_STORE9_SYNC_MODE__AUTO 0x1U
+#define PIXENGCFG_STORE9_STATIC_STORE9_SW_RESET_MASK 0x800U
+#define PIXENGCFG_STORE9_STATIC_STORE9_SW_RESET_SHIFT 11U
+/* Field Value: STORE9_SW_RESET__OPERATION, Normal Operation */
+#define PIXENGCFG_STORE9_STATIC_STORE9_SW_RESET__OPERATION 0U
+/* Field Value: STORE9_SW_RESET__SWRESET, Software Reset */
+#define PIXENGCFG_STORE9_STATIC_STORE9_SW_RESET__SWRESET 0x1U
+#define PIXENGCFG_STORE9_STATIC_STORE9_DIV_MASK 0xFF0000U
+#define PIXENGCFG_STORE9_STATIC_STORE9_DIV_SHIFT 16U
+
+#define PIXENGCFG_STORE9_DYNAMIC ((uint32_t)(0x94C))
+
+#define FETCHDECODE9_STATICCONTROL ((uint32_t)(0x1008))
+#define FETCHDECODE9_STATICCONTROL_OFFSET ((uint32_t)(0x8))
+#define FETCHDECODE9_STATICCONTROL_RESET_VALUE 0U
+#define FETCHDECODE9_STATICCONTROL_SHDEN_MASK 0x1U
+#define FETCHDECODE9_STATICCONTROL_SHDEN_SHIFT 0U
+#define FETCHDECODE9_STATICCONTROL_BASEADDRESSAUTOUPDATE_MASK 0xFF0000U
+#define FETCHDECODE9_STATICCONTROL_BASEADDRESSAUTOUPDATE_SHIFT 16U
+
+#define FETCHDECODE9_BURSTBUFFERMANAGEMENT ((uint32_t)(0x100C))
+#define FETCHDECODE9_BASEADDRESS0 ((uint32_t)(0x101C))
+#define FETCHDECODE9_SOURCEBUFFERATTRIBUTES0 ((uint32_t)(0x1020))
+#define FETCHDECODE9_SOURCEBUFFERDIMENSION0 ((uint32_t)(0x1024))
+#define FETCHDECODE9_COLORCOMPONENTBITS0 ((uint32_t)(0x1028))
+#define FETCHDECODE9_COLORCOMPONENTSHIFT0 ((uint32_t)(0x102C))
+#define FETCHDECODE9_LAYEROFFSET0 ((uint32_t)(0x1030))
+#define FETCHDECODE9_CLIPWINDOWOFFSET0 ((uint32_t)(0x1034))
+#define FETCHDECODE9_CLIPWINDOWDIMENSIONS0 ((uint32_t)(0x1038))
+#define FETCHDECODE9_CONSTANTCOLOR0 ((uint32_t)(0x103C))
+#define FETCHDECODE9_LAYERPROPERTY0 ((uint32_t)(0x1040))
+#define FETCHDECODE9_FRAMEDIMENSIONS ((uint32_t)(0x1044))
+#define FETCHDECODE9_FRAMERESAMPLING ((uint32_t)(0x1048))
+#define FETCHDECODE9_CONTROL ((uint32_t)(0x1054))
+
+#define FETCHWARP9_STATICCONTROL ((uint32_t)(0x1808))
+#define FETCHWARP9_STATICCONTROL_OFFSET ((uint32_t)(0x8))
+#define FETCHWARP9_STATICCONTROL_RESET_VALUE 0xFF000000U
+#define FETCHWARP9_STATICCONTROL_RESET_MASK 0xFFFFFFFFU
+#define FETCHWARP9_STATICCONTROL_SHDEN_MASK 0x1U
+#define FETCHWARP9_STATICCONTROL_SHDEN_SHIFT 0U
+#define FETCHWARP9_STATICCONTROL_BASEADDRESSAUTOUPDATE_MASK 0xFF0000U
+#define FETCHWARP9_STATICCONTROL_BASEADDRESSAUTOUPDATE_SHIFT 16U
+#define FETCHWARP9_STATICCONTROL_SHDLDREQSTICKY_MASK 0xFF000000U
+#define FETCHWARP9_STATICCONTROL_SHDLDREQSTICKY_SHIFT 24U
+
+#define FETCHWARP9_BURSTBUFFERMANAGEMENT ((uint32_t)(0x180C))
+#define FETCHWARP9_BASEADDRESS0 ((uint32_t)(0x1810))
+#define FETCHWARP9_SOURCEBUFFERATTRIBUTES0 ((uint32_t)(0x1814))
+#define FETCHWARP9_SOURCEBUFFERDIMENSION0 ((uint32_t)(0x1818))
+#define FETCHWARP9_COLORCOMPONENTBITS0 ((uint32_t)(0x181C))
+#define FETCHWARP9_COLORCOMPONENTSHIFT0 ((uint32_t)(0x1820))
+#define FETCHWARP9_LAYEROFFSET0 ((uint32_t)(0x1824))
+#define FETCHWARP9_CLIPWINDOWOFFSET0 ((uint32_t)(0x1828))
+#define FETCHWARP9_CLIPWINDOWDIMENSIONS0 ((uint32_t)(0x182C))
+#define FETCHWARP9_CONSTANTCOLOR0 ((uint32_t)(0x1830))
+#define FETCHWARP9_LAYERPROPERTY0 ((uint32_t)(0x1834))
+#define FETCHWARP9_FRAMEDIMENSIONS ((uint32_t)(0x1950))
+#define FETCHWARP9_FRAMERESAMPLING ((uint32_t)(0x1954))
+#define FETCHWARP9_CONTROL ((uint32_t)(0x1970))
+
+
+#define FETCHECO9_STATICCONTROL ((uint32_t)(0x1C08))
+#define FETCHECO9_STATICCONTROL_OFFSET ((uint32_t)(0x8))
+#define FETCHECO9_STATICCONTROL_RESET_VALUE 0U
+#define FETCHECO9_STATICCONTROL_RESET_MASK 0xFFFFFFFFU
+#define FETCHECO9_STATICCONTROL_SHDEN_MASK 0x1U
+#define FETCHECO9_STATICCONTROL_SHDEN_SHIFT 0U
+#define FETCHECO9_STATICCONTROL_BASEADDRESSAUTOUPDATE_MASK 0xFF0000U
+#define FETCHECO9_STATICCONTROL_BASEADDRESSAUTOUPDATE_SHIFT 16U
+
+#define FETCHECO9_BURSTBUFFERMANAGEMENT ((uint32_t)(0x1C0C))
+#define FETCHECO9_BASEADDRESS0 ((uint32_t)(0x1C10))
+#define FETCHECO9_SOURCEBUFFERATTRIBUTES0 ((uint32_t)(0x1C14))
+#define FETCHECO9_SOURCEBUFFERDIMENSION0 ((uint32_t)(0x1C18))
+#define FETCHECO9_COLORCOMPONENTBITS0 ((uint32_t)(0x1C1C))
+#define FETCHECO9_COLORCOMPONENTSHIFT0 ((uint32_t)(0x1C20))
+#define FETCHECO9_LAYEROFFSET0 ((uint32_t)(0x1C24))
+#define FETCHECO9_CLIPWINDOWOFFSET0 ((uint32_t)(0x1C28))
+#define FETCHECO9_CLIPWINDOWDIMENSIONS0 ((uint32_t)(0x1C2C))
+#define FETCHECO9_CONSTANTCOLOR0 ((uint32_t)(0x1C30))
+#define FETCHECO9_LAYERPROPERTY0 ((uint32_t)(0x1C34))
+#define FETCHECO9_FRAMEDIMENSIONS ((uint32_t)(0x1C38))
+#define FETCHECO9_FRAMERESAMPLING ((uint32_t)(0x1C3C))
+#define FETCHECO9_CONTROL ((uint32_t)(0x1C40))
+
+
+#define ROP9_STATICCONTROL ((uint32_t)(0x2008))
+#define ROP9_STATICCONTROL_OFFSET ((uint32_t)(0x8))
+#define ROP9_STATICCONTROL_RESET_VALUE 0U
+#define ROP9_STATICCONTROL_RESET_MASK 0xFFFFFFFFU
+#define ROP9_STATICCONTROL_SHDEN_MASK 0x1U
+#define ROP9_STATICCONTROL_SHDEN_SHIFT 0U
+
+#define ROP9_CONTROL ((uint32_t)(0x200C))
+
+#define MATRIX9_STATICCONTROL ((uint32_t)(0x2C08))
+#define MATRIX9_STATICCONTROL_OFFSET ((uint32_t)(0x8))
+#define MATRIX9_STATICCONTROL_RESET_VALUE 0U
+#define MATRIX9_STATICCONTROL_RESET_MASK 0xFFFFFFFFU
+#define MATRIX9_STATICCONTROL_SHDEN_MASK 0x1U
+#define MATRIX9_STATICCONTROL_SHDEN_SHIFT 0U
+
+#define MATRIX9_CONTROL ((uint32_t)(0x2C0C))
+
+#define HSCALER9_SETUP1 ((uint32_t)(0x300C))
+#define HSCALER9_SETUP2 ((uint32_t)(0x3010))
+#define HSCALER9_CONTROL ((uint32_t)(0x3014))
+
+#define VSCALER9_STATICCONTROL ((uint32_t)(0x3408))
+#define VSCALER9_STATICCONTROL_OFFSET ((uint32_t)(0x8))
+#define VSCALER9_STATICCONTROL_RESET_VALUE 0U
+#define VSCALER9_STATICCONTROL_RESET_MASK 0xFFFFFFFFU
+#define VSCALER9_STATICCONTROL_SHDEN_MASK 0x1U
+#define VSCALER9_STATICCONTROL_SHDEN_SHIFT 0U
+
+#define VSCALER9_SETUP1 ((uint32_t)(0x340C))
+#define VSCALER9_SETUP2 ((uint32_t)(0x3410))
+#define VSCALER9_SETUP3 ((uint32_t)(0x3414))
+#define VSCALER9_SETUP4 ((uint32_t)(0x3418))
+#define VSCALER9_SETUP5 ((uint32_t)(0x341C))
+#define VSCALER9_CONTROL ((uint32_t)(0x3420))
+
+#define HSCALER9_STATICCONTROL ((uint32_t)(0x3008))
+#define HSCALER9_STATICCONTROL_OFFSET ((uint32_t)(0x8))
+#define HSCALER9_STATICCONTROL_RESET_VALUE 0U
+#define HSCALER9_STATICCONTROL_RESET_MASK 0xFFFFFFFFU
+#define HSCALER9_STATICCONTROL_SHDEN_MASK 0x1U
+#define HSCALER9_STATICCONTROL_SHDEN_SHIFT 0U
+
+#define BLITBLEND9_STATICCONTROL ((uint32_t)(0x3C08))
+#define BLITBLEND9_STATICCONTROL_OFFSET ((uint32_t)(0x8))
+#define BLITBLEND9_STATICCONTROL_RESET_VALUE 0U
+#define BLITBLEND9_STATICCONTROL_RESET_MASK 0xFFFFFFFFU
+#define BLITBLEND9_STATICCONTROL_SHDEN_MASK 0x1U
+#define BLITBLEND9_STATICCONTROL_SHDEN_SHIFT 0U
+
+#define BLITBLEND9_CONTROL ((uint32_t)(0x3C0C))
+#define BLITBLEND9_CONSTANTCOLOR ((uint32_t)(0x3C14))
+#define BLITBLEND9_COLORREDBLENDFUNCTION ((uint32_t)(0x3C18))
+#define BLITBLEND9_COLORGREENBLENDFUNCTION ((uint32_t)(0x3C1C))
+#define BLITBLEND9_COLORBLUEBLENDFUNCTION ((uint32_t)(0x3C20))
+#define BLITBLEND9_ALPHABLENDFUNCTION ((uint32_t)(0x3C24))
+#define BLITBLEND9_BLENDMODE1 ((uint32_t)(0x3C28))
+#define BLITBLEND9_BLENDMODE2 ((uint32_t)(0x3C2C))
+
+
+#define STORE9_STATICCONTROL ((uint32_t)(0x4008))
+#define STORE9_STATICCONTROL_OFFSET ((uint32_t)(0x8))
+#define STORE9_STATICCONTROL_RESET_VALUE 0U
+#define STORE9_STATICCONTROL_RESET_MASK 0xFFFFFFFFU
+#define STORE9_STATICCONTROL_SHDEN_MASK 0x1U
+#define STORE9_STATICCONTROL_SHDEN_SHIFT 0U
+#define STORE9_STATICCONTROL_BASEADDRESSAUTOUPDATE_MASK 0x100U
+#define STORE9_STATICCONTROL_BASEADDRESSAUTOUPDATE_SHIFT 8U
+
+#define STORE9_BURSTBUFFERMANAGEMENT ((uint32_t)(0x400C))
+#define STORE9_BASEADDRESS ((uint32_t)(0x4018))
+#define STORE9_DESTINATIONBUFFERATTRIBUTES ((uint32_t)(0x401C))
+#define STORE9_DESTINATIONBUFFERDIMENSION ((uint32_t)(0x4020))
+#define STORE9_FRAMEOFFSET ((uint32_t)(0x4024))
+#define STORE9_COLORCOMPONENTBITS ((uint32_t)(0x4028))
+#define STORE9_COLORCOMPONENTSHIFT ((uint32_t)(0x402C))
+#define STORE9_CONTROL ((uint32_t)(0x4030))
+
+#define STORE9_START ((uint32_t)(0x403C))
+
+/* pixengcfg */
+#define PIXENGCFG_CLKEN_MASK 0x3000000U
+#define PIXENGCFG_CLKEN_SHIFT 24U
+/* Field Value: _CLKEN__DISABLE, Clock for block is disabled */
+#define PIXENGCFG_CLKEN__DISABLE 0U
+#define PIXENGCFG_CLKEN__AUTOMATIC 0x1U
+/* Field Value: _CLKEN__FULL, Clock for block is without gating */
+#define PIXENGCFG_CLKEN__FULL 0x3U
+
+#define PIXENGCFG_DIVIDER_RESET 0x80
+
+
+/* command sequencer */
+#define CMDSEQ_HIF ((uint32_t)(0x400))
+
+#define CMDSEQ_LOCKUNLOCKHIF ((uint32_t)(0x500))
+#define CMDSEQ_LOCKUNLOCKHIF_LOCKUNLOCKHIF__LOCK_KEY 0x5651F763U
+#define CMDSEQ_LOCKUNLOCKHIF_LOCKUNLOCKHIF__UNLOCK_KEY 0x691DB936U
+
+#define CMDSEQ_LOCKUNLOCK ((uint32_t)(0x580))
+#define CMDSEQ_LOCKUNLOCK_LOCKUNLOCK__LOCK_KEY 0x5651F763U
+#define CMDSEQ_LOCKUNLOCK_LOCKUNLOCK__UNLOCK_KEY 0x691DB936U
+
+#define CMDSEQ_BUFFERADDRESS ((uint32_t)(0x588))
+#define CMDSEQ_BUFFERSIZE ((uint32_t)(0x58C))
+
+#define CMDSEQ_CONTROL ((uint32_t)(0x594))
+#define CMDSEQ_CONTROL_OFFSET ((uint32_t)(0x194))
+#define CMDSEQ_CONTROL_RESET_VALUE 0U
+#define CMDSEQ_CONTROL_RESET_MASK 0xFFFFFFFFU
+#define CMDSEQ_CONTROL_CLRAXIW_MASK 0x1U
+#define CMDSEQ_CONTROL_CLRAXIW_SHIFT 0U
+#define CMDSEQ_CONTROL_CLRRBUF_MASK 0x4U
+#define CMDSEQ_CONTROL_CLRRBUF_SHIFT 2U
+#define CMDSEQ_CONTROL_CLRCMDBUF_MASK 0x8U
+#define CMDSEQ_CONTROL_CLRCMDBUF_SHIFT 3U
+#define CMDSEQ_CONTROL_CLEAR_MASK 0x80000000U
+#define CMDSEQ_CONTROL_CLEAR_SHIFT 31U
+
+#define CMDSEQ_STATUS ((uint32_t)(0x598))
+#define CMDSEQ_STATUS_OFFSET ((uint32_t)(0x198))
+#define CMDSEQ_STATUS_RESET_VALUE 0x41000080U
+#define CMDSEQ_STATUS_RESET_MASK 0xFFFFFFFFU
+#define CMDSEQ_STATUS_FIFOSPACE_MASK 0x1FFFFU
+#define CMDSEQ_STATUS_IDLE_MASK 0x40000000U
+
+#endif
diff --git a/drivers/gpu/imx/dpu-blit/dpu-blit.c b/drivers/gpu/imx/dpu-blit/dpu-blit.c
new file mode 100644
index 000000000000..bb747d411111
--- /dev/null
+++ b/drivers/gpu/imx/dpu-blit/dpu-blit.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include <video/imx8-prefetch.h>
+
+#include "dpu-blit.h"
+#include "dpu-blit-registers.h"
+#include "dpu-prv.h"
+
+static inline u32 dpu_be_read(struct dpu_bliteng *dpu_be, unsigned int offset)
+{
+ return readl(dpu_be->base + offset);
+}
+
+static inline void dpu_be_write(struct dpu_bliteng *dpu_be, u32 value,
+ unsigned int offset)
+{
+ writel(value, dpu_be->base + offset);
+}
+
+static void dpu_cs_wait_fifo_space(struct dpu_bliteng *dpu_be)
+{
+ while ((dpu_be_read(dpu_be, CMDSEQ_STATUS) &
+ CMDSEQ_STATUS_FIFOSPACE_MASK) < CMDSEQ_FIFO_SPACE_THRESHOLD)
+ usleep_range(1000, 2000);
+}
+
+static void dpu_cs_wait_idle(struct dpu_bliteng *dpu_be)
+{
+ while ((dpu_be_read(dpu_be, CMDSEQ_STATUS) &
+ CMDSEQ_STATUS_IDLE_MASK) == 0x0)
+ mdelay(1);
+}
+
+static int dpu_cs_alloc_command_buffer(struct dpu_bliteng *dpu_be)
+{
+ /* command buffer need 32 bit address */
+ dpu_be->buffer_addr_virt =
+ alloc_pages_exact(COMMAND_BUFFER_SIZE,
+ GFP_KERNEL | GFP_DMA | GFP_DMA32 | __GFP_ZERO);
+ if (!dpu_be->buffer_addr_virt) {
+ dev_err(dpu_be->dev, "memory alloc failed for dpu command buffer\n");
+ return -ENOMEM;
+ }
+
+ dpu_be->buffer_addr_phy =
+ (u32)virt_to_phys(dpu_be->buffer_addr_virt);
+
+ return 0;
+}
+
+static void dpu_cs_static_setup(struct dpu_bliteng *dpu_be)
+{
+ dpu_cs_wait_idle(dpu_be);
+
+ /* LockUnlock and LockUnlockHIF */
+ dpu_be_write(dpu_be, CMDSEQ_LOCKUNLOCKHIF_LOCKUNLOCKHIF__UNLOCK_KEY,
+ CMDSEQ_LOCKUNLOCKHIF);
+ dpu_be_write(dpu_be, CMDSEQ_LOCKUNLOCK_LOCKUNLOCK__UNLOCK_KEY,
+ CMDSEQ_LOCKUNLOCK);
+
+ /* Control */
+ dpu_be_write(dpu_be, 1 << CMDSEQ_CONTROL_CLEAR_SHIFT,
+ CMDSEQ_CONTROL);
+
+ /* BufferAddress and BufferSize */
+ dpu_be_write(dpu_be, dpu_be->buffer_addr_phy, CMDSEQ_BUFFERADDRESS);
+ dpu_be_write(dpu_be, COMMAND_BUFFER_SIZE / WORD_SIZE,
+ CMDSEQ_BUFFERSIZE);
+}
+
+static struct dprc *
+dpu_be_dprc_get(struct dpu_soc *dpu, int dprc_id)
+{
+ struct dprc *dprc;
+
+ dprc = dprc_lookup_by_phandle(dpu->dev,
+ "fsl,dpr-channels",
+ dprc_id);
+
+ return dprc;
+}
+
+void dpu_be_configure_prefetch(struct dpu_bliteng *dpu_be,
+ u32 width, u32 height,
+ u32 x_offset, u32 y_offset,
+ u32 stride, u32 format, u64 modifier,
+ u64 baddr, u64 uv_addr)
+{
+ struct dprc *dprc;
+
+ /* Enable DPR, dprc1 is connected to plane0 */
+ dprc = dpu_be->dprc[1];
+
+ /*
+ * Force sync command sequncer in conditions:
+ * 1. tile work with dprc/prg (baddr)
+ * 2. switch tile to linear (!start)
+ */
+ if (!dpu_be->start || baddr) {
+ dpu_be_wait(dpu_be);
+ }
+
+ if (baddr == 0x0) {
+ if (!dpu_be->start) {
+ dprc_disable(dprc);
+ dpu_be->handle_start = false;
+ }
+ dpu_be->start = true;
+ return;
+ }
+
+ if (dpu_be->handle_start) {
+ dprc_first_frame_handle(dprc);
+ dpu_be->handle_start = false;
+ }
+
+ dprc_configure(dprc, 0,
+ width, height,
+ x_offset, y_offset,
+ stride, format, modifier,
+ baddr, uv_addr,
+ dpu_be->start,
+ dpu_be->start,
+ false);
+
+ if (dpu_be->start) {
+ dprc_enable(dprc);
+ dpu_be->handle_start = true;
+ }
+
+ dprc_reg_update(dprc);
+
+ dpu_be->start = false;
+}
+EXPORT_SYMBOL(dpu_be_configure_prefetch);
+
+int dpu_bliteng_get_empty_instance(struct dpu_bliteng **dpu_be,
+ struct device *dev)
+{
+ if (!dpu_be || !dev)
+ return -EINVAL;
+
+ *dpu_be = devm_kzalloc(dev, sizeof(struct dpu_bliteng), GFP_KERNEL);
+ if (!(*dpu_be))
+ return -ENOMEM;
+
+ return 0;
+}
+EXPORT_SYMBOL(dpu_bliteng_get_empty_instance);
+
+u32 *dpu_bliteng_get_cmd_list(struct dpu_bliteng *dpu_be)
+{
+ return dpu_be->cmd_list;
+}
+EXPORT_SYMBOL(dpu_bliteng_get_cmd_list);
+
+s32 dpu_bliteng_get_id(struct dpu_bliteng *dpu_be)
+{
+ return dpu_be->id;
+}
+EXPORT_SYMBOL(dpu_bliteng_get_id);
+
+void dpu_bliteng_set_id(struct dpu_bliteng *dpu_be, int id)
+{
+ dpu_be->id = id;
+}
+EXPORT_SYMBOL(dpu_bliteng_set_id);
+
+void dpu_bliteng_set_dev(struct dpu_bliteng *dpu_be, struct device *dev)
+{
+ dpu_be->dev = dev;
+}
+EXPORT_SYMBOL(dpu_bliteng_set_dev);
+
+int dpu_be_get(struct dpu_bliteng *dpu_be)
+{
+ mutex_lock(&dpu_be->mutex);
+ if (dpu_be->inuse) {
+ mutex_unlock(&dpu_be->mutex);
+ return -EBUSY;
+ }
+
+ dpu_be->inuse = true;
+ mutex_unlock(&dpu_be->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(dpu_be_get);
+
+void dpu_be_put(struct dpu_bliteng *dpu_be)
+{
+ mutex_lock(&dpu_be->mutex);
+
+ dpu_be->inuse = false;
+
+ mutex_unlock(&dpu_be->mutex);
+}
+EXPORT_SYMBOL(dpu_be_put);
+
+int dpu_be_blit(struct dpu_bliteng *dpu_be,
+ u32 *cmdlist, u32 cmdnum)
+{
+ int i;
+
+ if (cmdnum > CMDSEQ_FIFO_SPACE_THRESHOLD) {
+ dev_err(dpu_be->dev, "dpu blit cmdnum[%d] should be less than %d !\n",
+ cmdnum, CMDSEQ_FIFO_SPACE_THRESHOLD);
+ return -EINVAL;
+ }
+ dpu_cs_wait_fifo_space(dpu_be);
+
+ for (i = 0; i < cmdnum; i++)
+ dpu_be_write(dpu_be, cmdlist[i], CMDSEQ_HIF);
+
+ return 0;
+}
+EXPORT_SYMBOL(dpu_be_blit);
+
+#define STORE9_SEQCOMPLETE_IRQ 2U
+#define STORE9_SEQCOMPLETE_IRQ_MASK (1U<<STORE9_SEQCOMPLETE_IRQ)
+void dpu_be_wait(struct dpu_bliteng *dpu_be)
+{
+ dpu_cs_wait_fifo_space(dpu_be);
+
+ dpu_be_write(dpu_be, 0x14000001, CMDSEQ_HIF);
+ dpu_be_write(dpu_be, PIXENGCFG_STORE9_TRIGGER, CMDSEQ_HIF);
+ dpu_be_write(dpu_be, 0x10, CMDSEQ_HIF);
+
+ while ((dpu_be_read(dpu_be, COMCTRL_INTERRUPTSTATUS0) &
+ STORE9_SEQCOMPLETE_IRQ_MASK) == 0)
+ usleep_range(1000, 2000);
+
+ dpu_be_write(dpu_be, STORE9_SEQCOMPLETE_IRQ_MASK,
+ COMCTRL_INTERRUPTCLEAR0);
+}
+EXPORT_SYMBOL(dpu_be_wait);
+
+static void dpu_be_init_units(struct dpu_bliteng *dpu_be)
+{
+ u32 staticcontrol;
+ u32 pixengcfg_unit_static, pixengcfg_unit_dynamic;
+
+ staticcontrol =
+ 1 << FETCHDECODE9_STATICCONTROL_SHDEN_SHIFT |
+ 0 << FETCHDECODE9_STATICCONTROL_BASEADDRESSAUTOUPDATE_SHIFT |
+ FETCHDECODE9_STATICCONTROL_RESET_VALUE;
+ dpu_be_write(dpu_be, staticcontrol, FETCHDECODE9_STATICCONTROL);
+
+ staticcontrol =
+ 1 << FETCHWARP9_STATICCONTROL_SHDEN_SHIFT |
+ 0 << FETCHWARP9_STATICCONTROL_BASEADDRESSAUTOUPDATE_SHIFT |
+ FETCHWARP9_STATICCONTROL_RESET_VALUE;
+ dpu_be_write(dpu_be, staticcontrol, FETCHWARP9_STATICCONTROL);
+
+ staticcontrol =
+ 1 << FETCHECO9_STATICCONTROL_SHDEN_SHIFT |
+ 0 << FETCHECO9_STATICCONTROL_BASEADDRESSAUTOUPDATE_SHIFT |
+ FETCHECO9_STATICCONTROL_RESET_VALUE;
+ dpu_be_write(dpu_be, staticcontrol, FETCHECO9_STATICCONTROL);
+
+ staticcontrol =
+ 1 << HSCALER9_STATICCONTROL_SHDEN_SHIFT |
+ HSCALER9_STATICCONTROL_RESET_VALUE;
+ dpu_be_write(dpu_be, staticcontrol, HSCALER9_STATICCONTROL);
+
+ staticcontrol =
+ 1 << VSCALER9_STATICCONTROL_SHDEN_SHIFT |
+ VSCALER9_STATICCONTROL_RESET_VALUE;
+ dpu_be_write(dpu_be, staticcontrol, VSCALER9_STATICCONTROL);
+
+ staticcontrol =
+ 1 << ROP9_STATICCONTROL_SHDEN_SHIFT |
+ ROP9_STATICCONTROL_RESET_VALUE;
+ dpu_be_write(dpu_be, staticcontrol, ROP9_STATICCONTROL);
+
+ staticcontrol =
+ 1 << MATRIX9_STATICCONTROL_SHDEN_SHIFT |
+ MATRIX9_STATICCONTROL_RESET_VALUE;
+ dpu_be_write(dpu_be, staticcontrol, MATRIX9_STATICCONTROL);
+
+ staticcontrol =
+ 1 << BLITBLEND9_STATICCONTROL_SHDEN_SHIFT |
+ BLITBLEND9_STATICCONTROL_RESET_VALUE;
+ dpu_be_write(dpu_be, staticcontrol, BLITBLEND9_STATICCONTROL);
+
+ staticcontrol =
+ 1 << STORE9_STATICCONTROL_SHDEN_SHIFT |
+ 0 << STORE9_STATICCONTROL_BASEADDRESSAUTOUPDATE_SHIFT |
+ STORE9_STATICCONTROL_RESET_VALUE;
+ dpu_be_write(dpu_be, staticcontrol, STORE9_STATICCONTROL);
+
+ /* Safety_Pixengcfg Static */
+ pixengcfg_unit_static =
+ 1 << PIXENGCFG_STORE9_STATIC_STORE9_SHDEN_SHIFT |
+ 0 << PIXENGCFG_STORE9_STATIC_STORE9_POWERDOWN_SHIFT |
+ PIXENGCFG_STORE9_STATIC_STORE9_SYNC_MODE__SINGLE <<
+ PIXENGCFG_STORE9_STATIC_STORE9_SYNC_MODE_SHIFT |
+ PIXENGCFG_STORE9_STATIC_STORE9_SW_RESET__OPERATION <<
+ PIXENGCFG_STORE9_STATIC_STORE9_SW_RESET_SHIFT |
+ PIXENGCFG_DIVIDER_RESET <<
+ PIXENGCFG_STORE9_STATIC_STORE9_DIV_SHIFT;
+ dpu_be_write(dpu_be, pixengcfg_unit_static, PIXENGCFG_STORE9_STATIC);
+
+ /* Safety_Pixengcfg Dynamic */
+ pixengcfg_unit_dynamic =
+ PIXENGCFG_CLKEN__AUTOMATIC << PIXENGCFG_CLKEN_SHIFT |
+ PIXENGCFG_FETCHDECODE9_DYNAMIC_RESET_VALUE;
+ dpu_be_write(dpu_be, pixengcfg_unit_dynamic,
+ PIXENGCFG_FETCHDECODE9_DYNAMIC);
+
+ pixengcfg_unit_dynamic =
+ PIXENGCFG_CLKEN__AUTOMATIC << PIXENGCFG_CLKEN_SHIFT |
+ PIXENGCFG_FETCHWARP9_DYNAMIC_RESET_VALUE;
+ dpu_be_write(dpu_be, pixengcfg_unit_dynamic,
+ PIXENGCFG_FETCHWARP9_DYNAMIC);
+
+ pixengcfg_unit_dynamic =
+ PIXENGCFG_CLKEN__AUTOMATIC << PIXENGCFG_CLKEN_SHIFT |
+ PIXENGCFG_ROP9_DYNAMIC_RESET_VALUE;
+ dpu_be_write(dpu_be, pixengcfg_unit_dynamic,
+ PIXENGCFG_ROP9_DYNAMIC);
+
+ pixengcfg_unit_dynamic =
+ PIXENGCFG_CLKEN__AUTOMATIC << PIXENGCFG_CLKEN_SHIFT |
+ PIXENGCFG_MATRIX9_DYNAMIC_RESET_VALUE;
+ dpu_be_write(dpu_be, pixengcfg_unit_dynamic,
+ PIXENGCFG_MATRIX9_DYNAMIC);
+
+ pixengcfg_unit_dynamic =
+ PIXENGCFG_CLKEN__AUTOMATIC << PIXENGCFG_CLKEN_SHIFT |
+ PIXENGCFG_HSCALER9_DYNAMIC_RESET_VALUE;
+ dpu_be_write(dpu_be, pixengcfg_unit_dynamic,
+ PIXENGCFG_HSCALER9_DYNAMIC);
+
+ pixengcfg_unit_dynamic =
+ PIXENGCFG_CLKEN__AUTOMATIC << PIXENGCFG_CLKEN_SHIFT |
+ PIXENGCFG_VSCALER9_DYNAMIC_RESET_VALUE;
+ dpu_be_write(dpu_be, pixengcfg_unit_dynamic,
+ PIXENGCFG_VSCALER9_DYNAMIC);
+
+ pixengcfg_unit_dynamic =
+ PIXENGCFG_CLKEN__AUTOMATIC << PIXENGCFG_CLKEN_SHIFT |
+ PIXENGCFG_BLITBLEND9_DYNAMIC_RESET_VALUE;
+ dpu_be_write(dpu_be, pixengcfg_unit_dynamic,
+ PIXENGCFG_BLITBLEND9_DYNAMIC);
+}
+
+int dpu_bliteng_init(struct dpu_bliteng *dpu_bliteng)
+{
+ struct dpu_soc *dpu = dev_get_drvdata(dpu_bliteng->dev->parent);
+ struct platform_device *dpu_pdev =
+ container_of(dpu->dev, struct platform_device, dev);
+ struct resource *res;
+ unsigned long dpu_base;
+ void __iomem *base;
+ u32 *cmd_list;
+ int ret;
+
+ cmd_list = kzalloc(sizeof(*cmd_list) * CMDSEQ_FIFO_SPACE_THRESHOLD,
+ GFP_KERNEL);
+ if (!cmd_list)
+ return -ENOMEM;
+ dpu_bliteng->cmd_list = cmd_list;
+
+ res = platform_get_resource(dpu_pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+ dpu_base = res->start;
+
+ /* remap with bigger size */
+ base = devm_ioremap(dpu->dev, dpu_base, 64*SZ_1K);
+ dpu_bliteng->base = base;
+ dpu_bliteng->dpu = dpu;
+
+ mutex_init(&dpu_bliteng->mutex);
+
+ /* Init the uints used by blit engine */
+ /* Maybe this should be in dpu-common.c */
+ dpu_be_init_units(dpu_bliteng);
+
+ /* Init for command sequencer */
+ ret = dpu_cs_alloc_command_buffer(dpu_bliteng);
+ if (ret)
+ return ret;
+
+ dpu_cs_static_setup(dpu_bliteng);
+
+ /* DPR, each blit engine has two dprc, 0 & 1 */
+ dpu_bliteng->dprc[0] = dpu_be_dprc_get(dpu, 0);
+ dpu_bliteng->dprc[1] = dpu_be_dprc_get(dpu, 1);
+
+ dprc_disable(dpu_bliteng->dprc[0]);
+ dprc_disable(dpu_bliteng->dprc[1]);
+
+ dpu_bliteng->handle_start = false;
+ dpu_bliteng->start = true;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dpu_bliteng_init);
+
+void dpu_bliteng_fini(struct dpu_bliteng *dpu_bliteng)
+{
+ /* LockUnlock and LockUnlockHIF */
+ dpu_be_write(dpu_bliteng, CMDSEQ_LOCKUNLOCKHIF_LOCKUNLOCKHIF__LOCK_KEY,
+ CMDSEQ_LOCKUNLOCKHIF);
+ dpu_be_write(dpu_bliteng, CMDSEQ_LOCKUNLOCK_LOCKUNLOCK__LOCK_KEY,
+ CMDSEQ_LOCKUNLOCK);
+
+ kfree(dpu_bliteng->cmd_list);
+
+ if (dpu_bliteng->buffer_addr_virt)
+ free_pages_exact(dpu_bliteng->buffer_addr_virt,
+ COMMAND_BUFFER_SIZE);
+}
+EXPORT_SYMBOL_GPL(dpu_bliteng_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("i.MX DPU BLITENG");
+MODULE_ALIAS("platform:imx-dpu-bliteng");
diff --git a/drivers/gpu/imx/dpu-blit/dpu-blit.h b/drivers/gpu/imx/dpu-blit/dpu-blit.h
new file mode 100644
index 000000000000..28509338ca0b
--- /dev/null
+++ b/drivers/gpu/imx/dpu-blit/dpu-blit.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef __DPU_BLIT_H__
+#define __DPU_BLIT_H__
+
+#define COMMAND_BUFFER_SIZE 65536 /* up to 64k bytes */
+#define CMDSEQ_FIFO_SPACE_THRESHOLD 192
+#define WORD_SIZE 4
+
+struct dpu_bliteng {
+ struct device *dev;
+ void __iomem *base;
+ s32 id;
+ struct mutex mutex;
+ bool inuse;
+ s32 irq_store9_shdload;
+ s32 irq_store9_framecomplete;
+ s32 irq_store9_seqcomplete;
+
+ void *buffer_addr_virt;
+ u32 buffer_addr_phy;
+
+ u32 *cmd_list;
+
+ struct dpu_soc *dpu;
+
+ struct dprc *dprc[2];
+
+ bool handle_start;
+ bool start;
+};
+
+#endif
diff --git a/drivers/gpu/imx/dpu/Kconfig b/drivers/gpu/imx/dpu/Kconfig
new file mode 100644
index 000000000000..ba89d95a0b07
--- /dev/null
+++ b/drivers/gpu/imx/dpu/Kconfig
@@ -0,0 +1,11 @@
+config IMX_DPU_CORE
+ tristate "i.MX DPU core support"
+ depends on ARCH_FSL_IMX8QM || ARCH_FSL_IMX8QXP
+ depends on RESET_CONTROLLER
+ select GENERIC_IRQ_CHIP
+ select IMX8_PRG
+ select IMX8_DPRC
+ help
+ Choose this if you have a Freescale i.MX8QM or i.MX8QXP system and
+ want to use the Display Processing Unit. This option only enables
+ DPU base support.
diff --git a/drivers/gpu/imx/dpu/Makefile b/drivers/gpu/imx/dpu/Makefile
new file mode 100644
index 000000000000..784b2a8ff46b
--- /dev/null
+++ b/drivers/gpu/imx/dpu/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_IMX_DPU_CORE) += imx-dpu-core.o
+
+imx-dpu-core-objs := dpu-common.o dpu-constframe.o dpu-disengcfg.o \
+ dpu-extdst.o dpu-fetchdecode.o dpu-fetcheco.o \
+ dpu-fetchlayer.o dpu-fetchwarp.o dpu-fetchunit.o \
+ dpu-framegen.o dpu-hscaler.o dpu-layerblend.o \
+ dpu-tcon.o dpu-vscaler.o
diff --git a/drivers/gpu/imx/dpu/dpu-common.c b/drivers/gpu/imx/dpu/dpu-common.c
new file mode 100644
index 000000000000..4e31c1ec5b0b
--- /dev/null
+++ b/drivers/gpu/imx/dpu/dpu-common.c
@@ -0,0 +1,1809 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#include <linux/clk.h>
+#include <linux/fb.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <soc/imx8/sc/sci.h>
+#include <video/dpu.h>
+#include <video/imx8-prefetch.h>
+#include "dpu-prv.h"
+
+static bool display_plane_video_proc = true;
+module_param(display_plane_video_proc, bool, 0444);
+MODULE_PARM_DESC(display_plane_video_proc,
+ "Enable video processing for display [default=true]");
+
+#define DPU_CM_REG_DEFINE1(name1, name2) \
+static inline u32 name1(const struct cm_reg_ofs *ofs) \
+{ \
+ return ofs->name2; \
+}
+
+#define DPU_CM_REG_DEFINE2(name1, name2) \
+static inline u32 name1(const struct cm_reg_ofs *ofs, \
+ unsigned int n) \
+{ \
+ return ofs->name2 + (4 * n); \
+}
+
+DPU_CM_REG_DEFINE1(IPIDENTIFIER, ipidentifier);
+
+#define DESIGNDELIVERYID_MASK 0xF0U
+#define DESIGNDELIVERYID_SHIFT 4U
+
+#define DESIGNMATURITYLEVEL_MASK 0xF00U
+#define DESIGNMATURITYLEVEL_SHIFT 8U
+enum design_maturity_level {
+ /* Pre feasibility study. */
+ DESIGNMATURITYLEVEL__PREFS = 1 << DESIGNMATURITYLEVEL_SHIFT,
+ /* Feasibility study. */
+ DESIGNMATURITYLEVEL__FS = 2 << DESIGNMATURITYLEVEL_SHIFT,
+ /* Functionality complete. */
+ DESIGNMATURITYLEVEL__R0 = 3 << DESIGNMATURITYLEVEL_SHIFT,
+ /* Verification complete. */
+ DESIGNMATURITYLEVEL__R1 = 4 << DESIGNMATURITYLEVEL_SHIFT,
+};
+
+#define IPEVOLUTION_MASK 0xF000U
+#define IPEVOLUTION_SHIFT 12U
+
+#define IPFEATURESET_MASK 0xF0000U
+#define IPFEATURESET_SHIFT 16U
+enum ip_feature_set {
+ /* Minimal functionality (Eco). */
+ IPFEATURESET__E = 1 << IPFEATURESET_SHIFT,
+ /* Reduced functionality (Light). */
+ IPFEATURESET__L = 2 << IPFEATURESET_SHIFT,
+ /* Advanced functionality (Plus). */
+ IPFEATURESET__P = 4 << IPFEATURESET_SHIFT,
+ /* Extensive functionality (eXtensive). */
+ IPFEATURESET__X = 5 << IPFEATURESET_SHIFT,
+};
+
+#define IPAPPLICATION_MASK 0xF00000U
+#define IPAPPLICATION_SHIFT 20U
+enum ip_application {
+ /* Blit Engine only. */
+ IPAPPLICATION__B = 1 << IPAPPLICATION_SHIFT,
+ /* Blit Engine and Display Controller. */
+ IPAPPLICATION__D = 2 << IPAPPLICATION_SHIFT,
+ /* Display Controller only (with direct capture). */
+ IPAPPLICATION__V = 3 << IPAPPLICATION_SHIFT,
+ /*
+ * Blit Engine, Display Controller (with direct capture),
+ * Capture Controller (buffered capture) and Drawing Engine.
+ */
+ IPAPPLICATION__G = 4 << IPAPPLICATION_SHIFT,
+ /* Display Controller only. */
+ IPAPPLICATION__C = 5 << IPAPPLICATION_SHIFT,
+};
+
+#define IPCONFIGURATION_MASK 0xF000000U
+#define IPCONFIGURATION_SHIFT 24U
+enum ip_configuration {
+ /* Graphics core only (Module). */
+ IPCONFIGURATION__M = 1 << IPCONFIGURATION_SHIFT,
+ /* Subsystem including a graphics core (System). */
+ IPCONFIGURATION__S = 2 << IPCONFIGURATION_SHIFT,
+};
+
+#define IPFAMILY_MASK 0xF0000000U
+#define IPFAMILY_SHIFT 28U
+enum ip_family {
+ /* IMXDPU building block generation 2010. */
+ IPFAMILY__IMXDPU2010 = 0,
+ /* IMXDPU building block generation 2012. */
+ IPFAMILY__IMXDPU2012 = 1 << IPFAMILY_SHIFT,
+ /* IMXDPU building block generation 2013. */
+ IPFAMILY__IMXDPU2013 = 2 << IPFAMILY_SHIFT,
+};
+
+DPU_CM_REG_DEFINE1(LOCKUNLOCK, lockunlock);
+DPU_CM_REG_DEFINE1(LOCKSTATUS, lockstatus);
+DPU_CM_REG_DEFINE2(USERINTERRUPTMASK, userinterruptmask);
+DPU_CM_REG_DEFINE2(INTERRUPTENABLE, interruptenable);
+DPU_CM_REG_DEFINE2(INTERRUPTPRESET, interruptpreset);
+DPU_CM_REG_DEFINE2(INTERRUPTCLEAR, interruptclear);
+DPU_CM_REG_DEFINE2(INTERRUPTSTATUS, interruptstatus);
+DPU_CM_REG_DEFINE2(USERINTERRUPTENABLE, userinterruptenable);
+DPU_CM_REG_DEFINE2(USERINTERRUPTPRESET, userinterruptpreset);
+DPU_CM_REG_DEFINE2(USERINTERRUPTCLEAR, userinterruptclear);
+DPU_CM_REG_DEFINE2(USERINTERRUPTSTATUS, userinterruptstatus);
+DPU_CM_REG_DEFINE1(GENERALPURPOSE, generalpurpose);
+
+static inline u32 dpu_cm_read(struct dpu_soc *dpu, unsigned int offset)
+{
+ return readl(dpu->cm_reg + offset);
+}
+
+static inline void dpu_cm_write(struct dpu_soc *dpu, u32 value,
+ unsigned int offset)
+{
+ writel(value, dpu->cm_reg + offset);
+}
+
+/* Constant Frame Unit */
+static const unsigned long cf_ofss[] = {0x4400, 0x5400, 0x4c00, 0x5c00};
+static const unsigned long cf_pec_ofss_v1[] = {0x980, 0xa00, 0x9c0, 0xa40};
+static const unsigned long cf_pec_ofss_v2[] = {0x960, 0x9e0, 0x9a0, 0xa20};
+
+/* Display Engine Configuration Unit */
+static const unsigned long dec_ofss_v1[] = {0x10000, 0x10020};
+static const unsigned long dec_ofss_v2[] = {0xb400, 0xb420};
+
+/* External Destination Unit */
+static const unsigned long ed_ofss[] = {0x4800, 0x5800, 0x5000, 0x6000};
+static const unsigned long ed_pec_ofss_v1[] = {0x9a0, 0xa20, 0x9e0, 0xa60};
+static const unsigned long ed_pec_ofss_v2[] = {0x980, 0xa00, 0x9c0, 0xa40};
+
+/* Fetch Decode Unit */
+static const unsigned long fd_ofss_v1[] = {0x8c00, 0x9800, 0x7400, 0x7c00};
+static const unsigned long fd_ofss_v2[] = {0x6c00, 0x7800};
+static const unsigned long fd_pec_ofss_v1[] = {0xb60, 0xb80, 0xb00, 0xb20};
+static const unsigned long fd_pec_ofss_v2[] = {0xa80, 0xaa0};
+
+/* Fetch ECO Unit */
+static const unsigned long fe_ofss_v1[] = {0x9400, 0xa000, 0x8800, 0x1c00};
+static const unsigned long fe_ofss_v2[] = {0x7400, 0x8000, 0x6800, 0x1c00};
+static const unsigned long fe_pec_ofss_v1[] = {0xb70, 0xb90, 0xb50, 0x870};
+static const unsigned long fe_pec_ofss_v2[] = {0xa90, 0xab0, 0xa70, 0x850};
+
+/* Frame Generator Unit */
+static const unsigned long fg_ofss_v1[] = {0x10c00, 0x12800};
+static const unsigned long fg_ofss_v2[] = {0xb800, 0xd400};
+
+/* Fetch Layer Unit */
+static const unsigned long fl_ofss_v1[] = {0xa400, 0xac00};
+static const unsigned long fl_ofss_v2[] = {0x8400};
+static const unsigned long fl_pec_ofss_v1[] = {0xba0, 0xbb0};
+static const unsigned long fl_pec_ofss_v2[] = {0xac0};
+
+/* Fetch Warp Unit */
+static const unsigned long fw_ofss_v1[] = {0x8400};
+static const unsigned long fw_ofss_v2[] = {0x6400};
+static const unsigned long fw_pec_ofss_v1[] = {0xb40};
+static const unsigned long fw_pec_ofss_v2[] = {0xa60};
+
+/* Horizontal Scaler Unit */
+static const unsigned long hs_ofss_v1[] = {0xbc00, 0xd000, 0x3000};
+static const unsigned long hs_ofss_v2[] = {0x9000, 0x9c00, 0x3000};
+static const unsigned long hs_pec_ofss_v1[] = {0xc00, 0xca0, 0x8e0};
+static const unsigned long hs_pec_ofss_v2[] = {0xb00, 0xb60, 0x8c0};
+
+/* Layer Blend Unit */
+static const unsigned long lb_ofss_v1[] = {0xdc00, 0xe000, 0xe400, 0xe800,
+ 0xec00, 0xf000, 0xf400};
+static const unsigned long lb_ofss_v2[] = {0xa400, 0xa800, 0xac00, 0xb000};
+static const unsigned long lb_pec_ofss_v1[] = {0xd00, 0xd20, 0xd40, 0xd60,
+ 0xd80, 0xda0, 0xdc0};
+static const unsigned long lb_pec_ofss_v2[] = {0xba0, 0xbc0, 0xbe0, 0xc00};
+
+/* Timing Controller Unit */
+static const unsigned long tcon_ofss_v1[] = {0x12000, 0x13c00};
+static const unsigned long tcon_ofss_v2[] = {0xcc00, 0xe800};
+
+/* Vertical Scaler Unit */
+static const unsigned long vs_ofss_v1[] = {0xc000, 0xd400, 0x3400};
+static const unsigned long vs_ofss_v2[] = {0x9400, 0xa000, 0x3400};
+static const unsigned long vs_pec_ofss_v1[] = {0xc20, 0xcc0, 0x900};
+static const unsigned long vs_pec_ofss_v2[] = {0xb20, 0xb80, 0x8e0};
+
+static const struct dpu_unit cfs_v1 = {
+ .name = "ConstFrame",
+ .num = ARRAY_SIZE(cf_ids),
+ .ids = cf_ids,
+ .pec_ofss = cf_pec_ofss_v1,
+ .ofss = cf_ofss,
+};
+
+static const struct dpu_unit cfs_v2 = {
+ .name = "ConstFrame",
+ .num = ARRAY_SIZE(cf_ids),
+ .ids = cf_ids,
+ .pec_ofss = cf_pec_ofss_v2,
+ .ofss = cf_ofss,
+};
+
+static const struct dpu_unit decs_v1 = {
+ .name = "DisEngCfg",
+ .num = ARRAY_SIZE(dec_ids),
+ .ids = dec_ids,
+ .pec_ofss = NULL,
+ .ofss = dec_ofss_v1,
+};
+
+static const struct dpu_unit decs_v2 = {
+ .name = "DisEngCfg",
+ .num = ARRAY_SIZE(dec_ids),
+ .ids = dec_ids,
+ .pec_ofss = NULL,
+ .ofss = dec_ofss_v2,
+};
+
+static const struct dpu_unit eds_v1 = {
+ .name = "ExtDst",
+ .num = ARRAY_SIZE(ed_ids),
+ .ids = ed_ids,
+ .pec_ofss = ed_pec_ofss_v1,
+ .ofss = ed_ofss,
+};
+
+static const struct dpu_unit eds_v2 = {
+ .name = "ExtDst",
+ .num = ARRAY_SIZE(ed_ids),
+ .ids = ed_ids,
+ .pec_ofss = ed_pec_ofss_v2,
+ .ofss = ed_ofss,
+};
+
+static const struct dpu_unit fds_v1 = {
+ .name = "FetchDecode",
+ .num = ARRAY_SIZE(fd_ids),
+ .ids = fd_ids,
+ .pec_ofss = fd_pec_ofss_v1,
+ .ofss = fd_ofss_v1,
+};
+
+static const struct dpu_unit fds_v2 = {
+ .name = "FetchDecode",
+ .num = 2,
+ .ids = fd_ids,
+ .pec_ofss = fd_pec_ofss_v2,
+ .ofss = fd_ofss_v2,
+ .dprc_ids = fd_dprc_ids,
+};
+
+static const struct dpu_unit fes_v1 = {
+ .name = "FetchECO",
+ .num = ARRAY_SIZE(fe_ids),
+ .ids = fe_ids,
+ .pec_ofss = fe_pec_ofss_v1,
+ .ofss = fe_ofss_v1,
+};
+
+static const struct dpu_unit fes_v2 = {
+ .name = "FetchECO",
+ .num = ARRAY_SIZE(fe_ids),
+ .ids = fe_ids,
+ .pec_ofss = fe_pec_ofss_v2,
+ .ofss = fe_ofss_v2,
+};
+
+static const struct dpu_unit fgs_v1 = {
+ .name = "FrameGen",
+ .num = ARRAY_SIZE(fg_ids),
+ .ids = fg_ids,
+ .pec_ofss = NULL,
+ .ofss = fg_ofss_v1,
+};
+
+static const struct dpu_unit fgs_v2 = {
+ .name = "FrameGen",
+ .num = ARRAY_SIZE(fg_ids),
+ .ids = fg_ids,
+ .pec_ofss = NULL,
+ .ofss = fg_ofss_v2,
+};
+
+static const struct dpu_unit fls_v1 = {
+ .name = "FetchLayer",
+ .num = ARRAY_SIZE(fl_ids),
+ .ids = fl_ids,
+ .pec_ofss = fl_pec_ofss_v1,
+ .ofss = fl_ofss_v1,
+};
+
+static const struct dpu_unit fls_v2 = {
+ .name = "FetchLayer",
+ .num = 1,
+ .ids = fl_ids,
+ .pec_ofss = fl_pec_ofss_v2,
+ .ofss = fl_ofss_v2,
+ .dprc_ids = fl_dprc_ids,
+};
+
+static const struct dpu_unit fws_v1 = {
+ .name = "FetchWarp",
+ .num = ARRAY_SIZE(fw_ids),
+ .ids = fw_ids,
+ .pec_ofss = fw_pec_ofss_v1,
+ .ofss = fw_ofss_v1,
+};
+
+static const struct dpu_unit fws_v2 = {
+ .name = "FetchWarp",
+ .num = ARRAY_SIZE(fw_ids),
+ .ids = fw_ids,
+ .pec_ofss = fw_pec_ofss_v2,
+ .ofss = fw_ofss_v2,
+ .dprc_ids = fw_dprc_ids,
+};
+
+static const struct dpu_unit hss_v1 = {
+ .name = "HScaler",
+ .num = ARRAY_SIZE(hs_ids),
+ .ids = hs_ids,
+ .pec_ofss = hs_pec_ofss_v1,
+ .ofss = hs_ofss_v1,
+};
+
+static const struct dpu_unit hss_v2 = {
+ .name = "HScaler",
+ .num = ARRAY_SIZE(hs_ids),
+ .ids = hs_ids,
+ .pec_ofss = hs_pec_ofss_v2,
+ .ofss = hs_ofss_v2,
+};
+
+static const struct dpu_unit lbs_v1 = {
+ .name = "LayerBlend",
+ .num = ARRAY_SIZE(lb_ids),
+ .ids = lb_ids,
+ .pec_ofss = lb_pec_ofss_v1,
+ .ofss = lb_ofss_v1,
+};
+
+static const struct dpu_unit lbs_v2 = {
+ .name = "LayerBlend",
+ .num = 4,
+ .ids = lb_ids,
+ .pec_ofss = lb_pec_ofss_v2,
+ .ofss = lb_ofss_v2,
+};
+
+static const struct dpu_unit tcons_v1 = {
+ .name = "TCon",
+ .num = ARRAY_SIZE(tcon_ids),
+ .ids = tcon_ids,
+ .pec_ofss = NULL,
+ .ofss = tcon_ofss_v1,
+};
+
+static const struct dpu_unit tcons_v2 = {
+ .name = "TCon",
+ .num = ARRAY_SIZE(tcon_ids),
+ .ids = tcon_ids,
+ .pec_ofss = NULL,
+ .ofss = tcon_ofss_v2,
+};
+
+static const struct dpu_unit vss_v1 = {
+ .name = "VScaler",
+ .num = ARRAY_SIZE(vs_ids),
+ .ids = vs_ids,
+ .pec_ofss = vs_pec_ofss_v1,
+ .ofss = vs_ofss_v1,
+};
+
+static const struct dpu_unit vss_v2 = {
+ .name = "VScaler",
+ .num = ARRAY_SIZE(vs_ids),
+ .ids = vs_ids,
+ .pec_ofss = vs_pec_ofss_v2,
+ .ofss = vs_ofss_v2,
+};
+
+static const struct cm_reg_ofs cm_reg_ofs_v1 = {
+ .ipidentifier = 0,
+ .lockunlock = 0x80,
+ .lockstatus = 0x84,
+ .userinterruptmask = 0x88,
+ .interruptenable = 0x94,
+ .interruptpreset = 0xa0,
+ .interruptclear = 0xac,
+ .interruptstatus = 0xb8,
+ .userinterruptenable = 0x100,
+ .userinterruptpreset = 0x10c,
+ .userinterruptclear = 0x118,
+ .userinterruptstatus = 0x124,
+ .generalpurpose = 0x200,
+};
+
+static const struct cm_reg_ofs cm_reg_ofs_v2 = {
+ .ipidentifier = 0,
+ .lockunlock = 0x40,
+ .lockstatus = 0x44,
+ .userinterruptmask = 0x48,
+ .interruptenable = 0x50,
+ .interruptpreset = 0x58,
+ .interruptclear = 0x60,
+ .interruptstatus = 0x68,
+ .userinterruptenable = 0x80,
+ .userinterruptpreset = 0x88,
+ .userinterruptclear = 0x90,
+ .userinterruptstatus = 0x98,
+ .generalpurpose = 0x100,
+};
+
+static const unsigned int intsteer_map_v1[] = {
+ /* 0 1 2 3 4 5 6 7 */ /* 0~31: int0 */
+ 448, 449, 450, 64, 65, 66, 67, 68,
+ /* 8 9 10 11 12 13 14 15 */
+ 69, 70, 193, 194, 195, 196, 197, 320,
+ /* 16 17 18 19 20 21 22 23 */
+ 321, 322, 384, 385, 386, NA, 323, NA,
+ /* 24 25 26 27 28 29 30 31 */
+ 387, 71, 198, 72, 73, 74, 75, 76,
+ /* 32 33 34 35 36 37 38 39 */ /* 32~63: int1 */
+ 77, 78, 79, 80, 81, 199, 200, 201,
+ /* 40 41 42 43 44 45 46 47 */
+ 202, 203, 204, 205, 206, 207, 208, 324,
+ /* 48 49 50 51 52 53 54 55 */
+ 389, NA, 0, 1, 2, 3, 4, 82,
+ /* 56 57 58 59 60 61 62 63 */
+ 83, 84, 85, 209, 210, 211, 212, 325,
+ /* 64 65 66 */ /* 64+: int2 */
+ 326, 390, 391,
+};
+static const unsigned long unused_irq_v1[] = {0x00a00000, 0x00020000,
+ 0xfffffff8};
+
+static const unsigned int intsteer_map_v2[] = {
+ /* 0 1 2 3 4 5 6 7 */ /* 0~31: int0 */
+ 448, 449, 450, 64, 65, 66, 67, 68,
+ /* 8 9 10 11 12 13 14 15 */
+ 69, 70, 193, 194, 195, 196, 197, 72,
+ /* 16 17 18 19 20 21 22 23 */
+ 73, 74, 75, 76, 77, 78, 79, 80,
+ /* 24 25 26 27 28 29 30 31 */
+ 81, 199, 200, 201, 202, 203, 204, 205,
+ /* 32 33 34 35 36 37 38 39 */ /* 32+: int1 */
+ 206, 207, 208, NA, 0, 1, 2, 3,
+ /* 40 41 42 43 44 45 46 47 */
+ 4, 82, 83, 84, 85, 209, 210, 211,
+ /* 48 */
+ 212,
+};
+static const unsigned long unused_irq_v2[] = {0x00000000, 0xfffe0008};
+
+static const unsigned int sw2hw_irq_map_v2[] = {
+ /* 0 1 2 3 4 5 6 7 */
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ /* 8 9 10 11 12 13 14 15 */
+ 8, 9, 10, 11, 12, 13, 14, NA,
+ /* 16 17 18 19 20 21 22 23 */
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ /* 24 25 26 27 28 29 30 31 */
+ NA, NA, NA, 15, 16, 17, 18, 19,
+ /* 32 33 34 35 36 37 38 39 */
+ 20, 21, 22, 23, 24, 25, 26, 27,
+ /* 40 41 42 43 44 45 46 47 */
+ 28, 29, 30, 31, 32, 33, 34, NA,
+ /* 48 49 50 51 52 53 54 55 */
+ NA, NA, 36, 37, 38, 39, 40, 41,
+ /* 56 57 58 59 60 61 62 63 */
+ 42, 43, 44, 45, 46, 47, 48, NA,
+ /* 64 65 66 */
+ NA, NA, NA,
+};
+
+/* FIXME: overkill for some N/As, revive them when needed */
+static const unsigned int sw2hw_block_id_map_v2[] = {
+ /* 0 1 2 3 4 5 6 7 */
+ 0x00, NA, NA, 0x03, NA, NA, NA, 0x07,
+ /* 8 9 10 11 12 13 14 15 */
+ 0x08, NA, 0x0a, NA, 0x0c, NA, 0x0e, NA,
+ /* 16 17 18 19 20 21 22 23 */
+ 0x10, NA, 0x12, NA, NA, NA, NA, NA,
+ /* 24 25 26 27 28 29 30 31 */
+ NA, NA, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+ /* 32 33 34 35 36 37 38 39 */
+ 0x1a, NA, NA, 0x1b, 0x1c, 0x1d, NA, NA,
+ /* 40 41 42 43 44 45 46 47 */
+ 0x1e, 0x1f, 0x20, NA, 0x21, 0x22, 0x23, 0x24,
+ /* 48 49 50 51 52 53 54 55 */
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ /* 56 57 58 59 60 61 62 63 */
+ NA, NA, NA, NA, NA, NA, NA, NA,
+ /* 64 65 66 67 */
+ NA, NA, NA, NA,
+};
+
+static const struct dpu_devtype dpu_type_v1 = {
+ .cm_ofs = 0x0,
+ .cfs = &cfs_v1,
+ .decs = &decs_v1,
+ .eds = &eds_v1,
+ .fds = &fds_v1,
+ .fes = &fes_v1,
+ .fgs = &fgs_v1,
+ .fls = &fls_v1,
+ .fws = &fws_v1,
+ .hss = &hss_v1,
+ .lbs = &lbs_v1,
+ .tcons = &tcons_v1,
+ .vss = &vss_v1,
+ .cm_reg_ofs = &cm_reg_ofs_v1,
+ .intsteer_map = intsteer_map_v1,
+ .intsteer_map_size = ARRAY_SIZE(intsteer_map_v1),
+ .unused_irq = unused_irq_v1,
+ .plane_src_na_mask = 0xffffff80,
+ .has_capture = true,
+ .has_prefetch = false,
+ .has_disp_sel_clk = false,
+ .has_dual_ldb = false,
+ .pixel_link_quirks = false,
+ .pixel_link_nhvsync = false,
+ .version = DPU_V1,
+};
+
+static const struct dpu_devtype dpu_type_v2_qm = {
+ .cm_ofs = 0x0,
+ .cfs = &cfs_v2,
+ .decs = &decs_v2,
+ .eds = &eds_v2,
+ .fds = &fds_v2,
+ .fes = &fes_v2,
+ .fgs = &fgs_v2,
+ .fls = &fls_v2,
+ .fws = &fws_v2,
+ .hss = &hss_v2,
+ .lbs = &lbs_v2,
+ .tcons = &tcons_v2,
+ .vss = &vss_v2,
+ .cm_reg_ofs = &cm_reg_ofs_v2,
+ .intsteer_map = intsteer_map_v2,
+ .intsteer_map_size = ARRAY_SIZE(intsteer_map_v2),
+ .unused_irq = unused_irq_v2,
+ .sw2hw_irq_map = sw2hw_irq_map_v2,
+ .sw2hw_block_id_map = sw2hw_block_id_map_v2,
+ .plane_src_na_mask = 0xffffffe2,
+ .has_capture = false,
+ .has_prefetch = true,
+ .has_disp_sel_clk = true,
+ .has_dual_ldb = false,
+ .pixel_link_quirks = true,
+ .pixel_link_nhvsync = true,
+ .version = DPU_V2,
+};
+
+static const struct dpu_devtype dpu_type_v2_qxp = {
+ .cm_ofs = 0x0,
+ .cfs = &cfs_v2,
+ .decs = &decs_v2,
+ .eds = &eds_v2,
+ .fds = &fds_v2,
+ .fes = &fes_v2,
+ .fgs = &fgs_v2,
+ .fls = &fls_v2,
+ .fws = &fws_v2,
+ .hss = &hss_v2,
+ .lbs = &lbs_v2,
+ .tcons = &tcons_v2,
+ .vss = &vss_v2,
+ .cm_reg_ofs = &cm_reg_ofs_v2,
+ .intsteer_map = intsteer_map_v2,
+ .intsteer_map_size = ARRAY_SIZE(intsteer_map_v2),
+ .unused_irq = unused_irq_v2,
+ .sw2hw_irq_map = sw2hw_irq_map_v2,
+ .sw2hw_block_id_map = sw2hw_block_id_map_v2,
+ .plane_src_na_mask = 0xffffffe2,
+ .has_capture = false,
+ .has_prefetch = true,
+ .has_disp_sel_clk = false,
+ .has_dual_ldb = true,
+ .pixel_link_quirks = true,
+ .pixel_link_nhvsync = true,
+ .version = DPU_V2,
+};
+
+static const struct of_device_id dpu_dt_ids[] = {
+ {
+ .compatible = "fsl,imx8qm-dpu",
+ .data = &dpu_type_v2_qm,
+ }, {
+ .compatible = "fsl,imx8qxp-dpu",
+ .data = &dpu_type_v2_qxp,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, dpu_dt_ids);
+
+bool dpu_vproc_has_fetcheco_cap(u32 cap_mask)
+{
+ return !!(cap_mask & DPU_VPROC_CAP_FETCHECO);
+}
+EXPORT_SYMBOL_GPL(dpu_vproc_has_fetcheco_cap);
+
+bool dpu_vproc_has_hscale_cap(u32 cap_mask)
+{
+ return !!(cap_mask & DPU_VPROC_CAP_HSCALE);
+}
+EXPORT_SYMBOL_GPL(dpu_vproc_has_hscale_cap);
+
+bool dpu_vproc_has_vscale_cap(u32 cap_mask)
+{
+ return !!(cap_mask & DPU_VPROC_CAP_VSCALE);
+}
+EXPORT_SYMBOL_GPL(dpu_vproc_has_vscale_cap);
+
+u32 dpu_vproc_get_fetcheco_cap(u32 cap_mask)
+{
+ return cap_mask & DPU_VPROC_CAP_FETCHECO;
+}
+EXPORT_SYMBOL_GPL(dpu_vproc_get_fetcheco_cap);
+
+u32 dpu_vproc_get_hscale_cap(u32 cap_mask)
+{
+ return cap_mask & DPU_VPROC_CAP_HSCALE;
+}
+EXPORT_SYMBOL_GPL(dpu_vproc_get_hscale_cap);
+
+u32 dpu_vproc_get_vscale_cap(u32 cap_mask)
+{
+ return cap_mask & DPU_VPROC_CAP_VSCALE;
+}
+EXPORT_SYMBOL_GPL(dpu_vproc_get_vscale_cap);
+
+int dpu_format_horz_chroma_subsampling(u32 format)
+{
+ switch (format) {
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_UYVY:
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV61:
+ return 2;
+ default:
+ return 1;
+ }
+}
+
+int dpu_format_vert_chroma_subsampling(u32 format)
+{
+ switch (format) {
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ return 2;
+ default:
+ return 1;
+ }
+}
+
+int dpu_format_num_planes(u32 format)
+{
+ switch (format) {
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV61:
+ case DRM_FORMAT_NV24:
+ case DRM_FORMAT_NV42:
+ return 2;
+ default:
+ return 1;
+ }
+}
+
+int dpu_format_plane_width(int width, u32 format, int plane)
+{
+ if (plane >= dpu_format_num_planes(format))
+ return 0;
+
+ if (plane == 0)
+ return width;
+
+ return width / dpu_format_horz_chroma_subsampling(format);
+}
+
+int dpu_format_plane_height(int height, u32 format, int plane)
+{
+ if (plane >= dpu_format_num_planes(format))
+ return 0;
+
+ if (plane == 0)
+ return height;
+
+ return height / dpu_format_vert_chroma_subsampling(format);
+}
+
+#define _DPU_UNITS_INIT(unit) \
+{ \
+ const struct dpu_unit *us = devtype->unit##s; \
+ int i; \
+ \
+ /* software check */ \
+ if (WARN_ON(us->num > ARRAY_SIZE(unit##_ids))) \
+ return -EINVAL; \
+ \
+ for (i = 0; i < us->num; i++) \
+ _dpu_##unit##_init(dpu, us->ids[i]); \
+}
+
+static int
+_dpu_submodules_init(struct dpu_soc *dpu, struct platform_device *pdev)
+{
+ const struct dpu_devtype *devtype = dpu->devtype;
+
+ _DPU_UNITS_INIT(cf);
+ _DPU_UNITS_INIT(dec);
+ _DPU_UNITS_INIT(ed);
+ _DPU_UNITS_INIT(fd);
+ _DPU_UNITS_INIT(fe);
+ _DPU_UNITS_INIT(fg);
+ _DPU_UNITS_INIT(fl);
+ _DPU_UNITS_INIT(fw);
+ _DPU_UNITS_INIT(hs);
+ _DPU_UNITS_INIT(lb);
+ _DPU_UNITS_INIT(tcon);
+ _DPU_UNITS_INIT(vs);
+
+ return 0;
+}
+
+#define DPU_UNIT_INIT(dpu, base, unit, name, id, pec_ofs, ofs) \
+{ \
+ int ret; \
+ ret = dpu_##unit##_init((dpu), (id), \
+ (pec_ofs) ? (base) + (pec_ofs) : 0, \
+ (base) + (ofs)); \
+ if (ret) { \
+ dev_err((dpu)->dev, "init %s%d failed with %d\n", \
+ (name), (id), ret); \
+ return ret; \
+ } \
+}
+
+#define DPU_UNITS_INIT(unit) \
+{ \
+ const struct dpu_unit *us = devtype->unit##s; \
+ int i; \
+ \
+ /* software check */ \
+ if (WARN_ON(us->num > ARRAY_SIZE(unit##_ids))) \
+ return -EINVAL; \
+ \
+ for (i = 0; i < us->num; i++) \
+ DPU_UNIT_INIT(dpu, dpu_base, unit, us->name, \
+ us->ids[i], \
+ us->pec_ofss ? us->pec_ofss[i] : 0, \
+ us->ofss[i]); \
+}
+
+static int dpu_submodules_init(struct dpu_soc *dpu,
+ struct platform_device *pdev, unsigned long dpu_base)
+{
+ const struct dpu_devtype *devtype = dpu->devtype;
+ const struct dpu_unit *fds = devtype->fds;
+ const struct dpu_unit *fls = devtype->fls;
+ const struct dpu_unit *fws = devtype->fws;
+
+ DPU_UNITS_INIT(cf);
+ DPU_UNITS_INIT(dec);
+ DPU_UNITS_INIT(ed);
+ DPU_UNITS_INIT(fd);
+ DPU_UNITS_INIT(fe);
+ DPU_UNITS_INIT(fg);
+ DPU_UNITS_INIT(fl);
+ DPU_UNITS_INIT(fw);
+ DPU_UNITS_INIT(hs);
+ DPU_UNITS_INIT(lb);
+ DPU_UNITS_INIT(tcon);
+ DPU_UNITS_INIT(vs);
+
+ /* get DPR channel for submodules */
+ if (devtype->has_prefetch) {
+ struct dpu_fetchunit *fu;
+ struct dprc *dprc;
+ int i;
+
+ for (i = 0; i < fds->num; i++) {
+ dprc = dprc_lookup_by_phandle(dpu->dev,
+ "fsl,dpr-channels",
+ fds->dprc_ids[i]);
+ if (!dprc)
+ return -EPROBE_DEFER;
+
+ fu = dpu_fd_get(dpu, i);
+ fetchunit_get_dprc(fu, dprc);
+ dpu_fd_put(fu);
+ }
+
+ for (i = 0; i < fls->num; i++) {
+ dprc = dprc_lookup_by_phandle(dpu->dev,
+ "fsl,dpr-channels",
+ fls->dprc_ids[i]);
+ if (!dprc)
+ return -EPROBE_DEFER;
+
+ fu = dpu_fl_get(dpu, i);
+ fetchunit_get_dprc(fu, dprc);
+ dpu_fl_put(fu);
+ }
+
+ for (i = 0; i < fws->num; i++) {
+ dprc = dprc_lookup_by_phandle(dpu->dev,
+ "fsl,dpr-channels",
+ fws->dprc_ids[i]);
+ if (!dprc)
+ return -EPROBE_DEFER;
+
+ fu = dpu_fw_get(dpu, fw_ids[i]);
+ fetchunit_get_dprc(fu, dprc);
+ dpu_fw_put(fu);
+ }
+ }
+
+ return 0;
+}
+
+#define DPU_UNITS_ADDR_DBG(unit) \
+{ \
+ const struct dpu_unit *us = devtype->unit##s; \
+ int i; \
+ for (i = 0; i < us->num; i++) { \
+ if (us->pec_ofss) { \
+ dev_dbg(&pdev->dev, "%s%d: pixengcfg @ 0x%08lx,"\
+ " unit @ 0x%08lx\n", us->name, \
+ us->ids[i], \
+ dpu_base + us->pec_ofss[i], \
+ dpu_base + us->ofss[i]); \
+ } else { \
+ dev_dbg(&pdev->dev, \
+ "%s%d: unit @ 0x%08lx\n", us->name, \
+ us->ids[i], dpu_base + us->ofss[i]); \
+ } \
+ } \
+}
+
+enum dpu_irq_line {
+ DPU_IRQ_LINE_CM = 0,
+ DPU_IRQ_LINE_STREAM0A = 1,
+ DPU_IRQ_LINE_STREAM1A = 3,
+ DPU_IRQ_LINE_RESERVED0 = 5,
+ DPU_IRQ_LINE_RESERVED1 = 6,
+ DPU_IRQ_LINE_BLIT = 7,
+};
+
+static inline unsigned int dpu_get_max_intsteer_num(enum dpu_irq_line irq_line)
+{
+ return 64 * (++irq_line) - 1;
+}
+
+static inline unsigned int dpu_get_min_intsteer_num(enum dpu_irq_line irq_line)
+{
+ return 64 * irq_line;
+}
+
+static void
+dpu_inner_irq_handle(struct irq_desc *desc, enum dpu_irq_line irq_line)
+{
+ struct dpu_soc *dpu = irq_desc_get_handler_data(desc);
+ const struct dpu_devtype *devtype = dpu->devtype;
+ const struct cm_reg_ofs *ofs = devtype->cm_reg_ofs;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned int i, virq, min_intsteer_num, max_intsteer_num;
+ u32 status;
+
+ chained_irq_enter(chip, desc);
+
+ min_intsteer_num = dpu_get_min_intsteer_num(irq_line);
+ max_intsteer_num = dpu_get_max_intsteer_num(irq_line);
+
+ for (i = 0; i < devtype->intsteer_map_size; i++) {
+ if (devtype->intsteer_map[i] >= min_intsteer_num &&
+ devtype->intsteer_map[i] <= max_intsteer_num) {
+ status = dpu_cm_read(dpu,
+ USERINTERRUPTSTATUS(ofs, i / 32));
+ status &= dpu_cm_read(dpu,
+ USERINTERRUPTENABLE(ofs, i / 32));
+
+ if (status & BIT(i % 32)) {
+ virq = irq_linear_revmap(dpu->domain, i);
+ if (virq) {
+ generic_handle_irq(virq);
+ }
+ }
+ }
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+#define DPU_INNER_IRQ_HANDLER_DEFINE(name1, name2) \
+static void dpu_##name1##_irq_handler(struct irq_desc *desc) \
+{ \
+ dpu_inner_irq_handle(desc, DPU_IRQ_LINE_##name2); \
+}
+
+DPU_INNER_IRQ_HANDLER_DEFINE(cm, CM)
+DPU_INNER_IRQ_HANDLER_DEFINE(stream0a, STREAM0A)
+DPU_INNER_IRQ_HANDLER_DEFINE(stream1a, STREAM1A)
+DPU_INNER_IRQ_HANDLER_DEFINE(reserved0, RESERVED0)
+DPU_INNER_IRQ_HANDLER_DEFINE(reserved1, RESERVED1)
+DPU_INNER_IRQ_HANDLER_DEFINE(blit, BLIT)
+
+int dpu_map_inner_irq(struct dpu_soc *dpu, int irq)
+{
+ const unsigned int *sw2hw_irq_map = dpu->devtype->sw2hw_irq_map;
+ int virq, mapped_irq;
+
+ mapped_irq = sw2hw_irq_map ? sw2hw_irq_map[irq] : irq;
+ if (WARN_ON(mapped_irq == NA))
+ return -EINVAL;
+
+ virq = irq_linear_revmap(dpu->domain, mapped_irq);
+ if (!virq)
+ virq = irq_create_mapping(dpu->domain, mapped_irq);
+
+ return virq;
+}
+EXPORT_SYMBOL_GPL(dpu_map_inner_irq);
+
+static int platform_remove_devices_fn(struct device *dev, void *unused)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ platform_device_unregister(pdev);
+
+ return 0;
+}
+
+static void platform_device_unregister_children(struct platform_device *pdev)
+{
+ device_for_each_child(&pdev->dev, NULL, platform_remove_devices_fn);
+}
+
+struct dpu_platform_reg {
+ struct dpu_client_platformdata pdata;
+ const char *name;
+};
+
+static struct dpu_platform_reg client_reg[] = {
+ {
+ /* placeholder */
+ .pdata = { },
+ .name = "imx-dpu-csi",
+ }, {
+ /* placeholder */
+ .pdata = { },
+ .name = "imx-dpu-csi",
+ }, {
+ .pdata = {
+ .stream_id = 0,
+ },
+ .name = "imx-dpu-crtc",
+ }, {
+ .pdata = {
+ .stream_id = 1,
+ },
+ .name = "imx-dpu-crtc",
+ }, {
+ .pdata = { },
+ .name = "imx-drm-dpu-bliteng",
+ },
+};
+
+static DEFINE_MUTEX(dpu_client_id_mutex);
+static int dpu_client_id;
+
+static int dpu_get_plane_resource(struct dpu_soc *dpu,
+ struct dpu_plane_res *res)
+{
+ const struct dpu_unit *fds = dpu->devtype->fds;
+ const struct dpu_unit *fls = dpu->devtype->fls;
+ const struct dpu_unit *fws = dpu->devtype->fws;
+ const struct dpu_unit *lbs = dpu->devtype->lbs;
+ struct dpu_plane_grp *grp = plane_res_to_grp(res);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(res->cf); i++) {
+ res->cf[i] = dpu_cf_get(dpu, i);
+ if (IS_ERR(res->cf[i]))
+ return PTR_ERR(res->cf[i]);
+ }
+ for (i = 0; i < ARRAY_SIZE(res->ed); i++) {
+ res->ed[i] = dpu_ed_get(dpu, i);
+ if (IS_ERR(res->ed[i]))
+ return PTR_ERR(res->ed[i]);
+ }
+ for (i = 0; i < fds->num; i++) {
+ res->fd[i] = dpu_fd_get(dpu, i);
+ if (IS_ERR(res->fd[i]))
+ return PTR_ERR(res->fd[i]);
+ }
+ for (i = 0; i < ARRAY_SIZE(res->fe); i++) {
+ res->fe[i] = dpu_fe_get(dpu, i);
+ if (IS_ERR(res->fe[i]))
+ return PTR_ERR(res->fe[i]);
+ grp->hw_plane_fetcheco_num = ARRAY_SIZE(res->fe);
+ }
+ for (i = 0; i < fls->num; i++) {
+ res->fl[i] = dpu_fl_get(dpu, i);
+ if (IS_ERR(res->fl[i]))
+ return PTR_ERR(res->fl[i]);
+ }
+ for (i = 0; i < fws->num; i++) {
+ res->fw[i] = dpu_fw_get(dpu, fw_ids[i]);
+ if (IS_ERR(res->fw[i]))
+ return PTR_ERR(res->fw[i]);
+ }
+ /* HScaler could be shared with capture. */
+ if (display_plane_video_proc) {
+ for (i = 0; i < ARRAY_SIZE(res->hs); i++) {
+ res->hs[i] = dpu_hs_get(dpu, hs_ids[i]);
+ if (IS_ERR(res->hs[i]))
+ return PTR_ERR(res->hs[i]);
+ }
+ grp->hw_plane_hscaler_num = ARRAY_SIZE(res->hs);
+ }
+ for (i = 0; i < lbs->num; i++) {
+ res->lb[i] = dpu_lb_get(dpu, i);
+ if (IS_ERR(res->lb[i]))
+ return PTR_ERR(res->lb[i]);
+ }
+ /* VScaler could be shared with capture. */
+ if (display_plane_video_proc) {
+ for (i = 0; i < ARRAY_SIZE(res->vs); i++) {
+ res->vs[i] = dpu_vs_get(dpu, vs_ids[i]);
+ if (IS_ERR(res->vs[i]))
+ return PTR_ERR(res->vs[i]);
+ }
+ grp->hw_plane_vscaler_num = ARRAY_SIZE(res->vs);
+ }
+
+ grp->hw_plane_num = fds->num + fls->num + fws->num;
+
+ return 0;
+}
+
+static void dpu_put_plane_resource(struct dpu_plane_res *res)
+{
+ struct dpu_plane_grp *grp = plane_res_to_grp(res);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(res->cf); i++) {
+ if (!IS_ERR_OR_NULL(res->cf[i]))
+ dpu_cf_put(res->cf[i]);
+ }
+ for (i = 0; i < ARRAY_SIZE(res->ed); i++) {
+ if (!IS_ERR_OR_NULL(res->ed[i]))
+ dpu_ed_put(res->ed[i]);
+ }
+ for (i = 0; i < ARRAY_SIZE(res->fd); i++) {
+ if (!IS_ERR_OR_NULL(res->fd[i]))
+ dpu_fd_put(res->fd[i]);
+ }
+ for (i = 0; i < ARRAY_SIZE(res->fe); i++) {
+ if (!IS_ERR_OR_NULL(res->fe[i]))
+ dpu_fe_put(res->fe[i]);
+ }
+ for (i = 0; i < ARRAY_SIZE(res->fl); i++) {
+ if (!IS_ERR_OR_NULL(res->fl[i]))
+ dpu_fl_put(res->fl[i]);
+ }
+ for (i = 0; i < ARRAY_SIZE(res->fw); i++) {
+ if (!IS_ERR_OR_NULL(res->fw[i]))
+ dpu_fw_put(res->fw[i]);
+ }
+ for (i = 0; i < ARRAY_SIZE(res->hs); i++) {
+ if (!IS_ERR_OR_NULL(res->hs[i]))
+ dpu_hs_put(res->hs[i]);
+ }
+ for (i = 0; i < ARRAY_SIZE(res->lb); i++) {
+ if (!IS_ERR_OR_NULL(res->lb[i]))
+ dpu_lb_put(res->lb[i]);
+ }
+ for (i = 0; i < ARRAY_SIZE(res->vs); i++) {
+ if (!IS_ERR_OR_NULL(res->vs[i]))
+ dpu_vs_put(res->vs[i]);
+ }
+
+ grp->hw_plane_num = 0;
+}
+
+static int dpu_add_client_devices(struct dpu_soc *dpu)
+{
+ const struct dpu_devtype *devtype = dpu->devtype;
+ struct device *dev = dpu->dev;
+ struct dpu_platform_reg *reg;
+ struct dpu_plane_grp *plane_grp;
+ size_t client_num, reg_size;
+ int i, id, ret;
+
+ client_num = ARRAY_SIZE(client_reg);
+ if (!devtype->has_capture)
+ client_num -= 2;
+
+ reg = devm_kcalloc(dev, client_num, sizeof(*reg), GFP_KERNEL);
+ if (!reg)
+ return -ENODEV;
+
+ plane_grp = devm_kzalloc(dev, sizeof(*plane_grp), GFP_KERNEL);
+ if (!plane_grp)
+ return -ENODEV;
+
+ mutex_init(&plane_grp->mutex);
+
+ mutex_lock(&dpu_client_id_mutex);
+ id = dpu_client_id;
+ dpu_client_id += client_num;
+ mutex_unlock(&dpu_client_id_mutex);
+
+ reg_size = client_num * sizeof(struct dpu_platform_reg);
+ if (devtype->has_capture)
+ memcpy(reg, client_reg, reg_size);
+ else
+ memcpy(reg, &client_reg[2], reg_size);
+
+ plane_grp->src_na_mask = devtype->plane_src_na_mask;
+ plane_grp->id = id / client_num;
+ plane_grp->has_vproc = display_plane_video_proc;
+
+ ret = dpu_get_plane_resource(dpu, &plane_grp->res);
+ if (ret)
+ goto err_get_plane_res;
+
+ for (i = 0; i < client_num; i++) {
+ struct platform_device *pdev;
+ struct device_node *of_node = NULL;
+ bool is_disp, is_bliteng;
+
+ if (devtype->has_capture) {
+ is_bliteng = (i == 4) ? true : false;
+ is_disp = (!is_bliteng) && ((i / 2) ? true : false);
+ } else {
+ is_bliteng = (i == 2) ? true : false;
+ is_disp = !is_bliteng;
+ }
+
+ if (is_bliteng) {
+ /* As bliteng has no of_node, so to use dpu's. */
+ of_node = dev->of_node;
+ } else {
+ /*
+ * Associate subdevice with the
+ * corresponding port node.
+ */
+ of_node = of_graph_get_port_by_id(dev->of_node, i);
+ if (!of_node) {
+ dev_info(dev, "no port@%d node in %s, not using %s%d\n",
+ i, dev->of_node->full_name,
+ is_disp ? "DISP" : "CSI", i % 2);
+ continue;
+ }
+ }
+
+ if (is_disp)
+ reg[i].pdata.plane_grp = plane_grp;
+
+ pdev = platform_device_alloc(reg[i].name, id++);
+ if (!pdev) {
+ ret = -ENOMEM;
+ goto err_register;
+ }
+
+ pdev->dev.parent = dev;
+
+ reg[i].pdata.of_node = of_node;
+ ret = platform_device_add_data(pdev, &reg[i].pdata,
+ sizeof(reg[i].pdata));
+ if (!ret)
+ ret = platform_device_add(pdev);
+ if (ret) {
+ platform_device_put(pdev);
+ goto err_register;
+ }
+ }
+
+ return 0;
+
+err_register:
+ platform_device_unregister_children(to_platform_device(dev));
+err_get_plane_res:
+ dpu_put_plane_resource(&plane_grp->res);
+
+ return ret;
+}
+
+#define IRQSTEER_CHANnCTL 0x0
+#define IRQSTEER_CHANnCTL_CH(n) BIT(n)
+#define IRQSTEER_CHANnMASK(n) ((n) + 4)
+#define LINE_TO_MASK_OFFSET(n) ((15 - ((n) / 32)) * 4)
+#define LINE_TO_MASK_SHIFT(n) ((n) % 32)
+
+static void dpu_inner_irq_gc_mask_set_bit(struct irq_data *d)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
+ struct dpu_soc *dpu = gc->domain->host_data;
+ unsigned long flags;
+ u32 mask = d->mask;
+
+ irq_gc_lock(gc);
+ spin_lock_irqsave(&dpu->intsteer_lock, flags);
+ if (++dpu->intsteer_usecount == 1)
+ /* assuming fast I/O regmap */
+ regmap_write(dpu->intsteer_regmap, IRQSTEER_CHANnCTL,
+ IRQSTEER_CHANnCTL_CH(0));
+ spin_unlock_irqrestore(&dpu->intsteer_lock, flags);
+ *ct->mask_cache |= mask;
+ irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask);
+ irq_gc_unlock(gc);
+}
+
+static void dpu_inner_irq_gc_mask_clr_bit(struct irq_data *d)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
+ struct dpu_soc *dpu = gc->domain->host_data;
+ unsigned long flags;
+ u32 mask = d->mask;
+
+ irq_gc_lock(gc);
+ spin_lock_irqsave(&dpu->intsteer_lock, flags);
+ if (!--dpu->intsteer_usecount) {
+ WARN(dpu->intsteer_usecount < 0,
+ "intsteer usecount %d is less than zero",
+ dpu->intsteer_usecount);
+ regmap_write(dpu->intsteer_regmap, IRQSTEER_CHANnCTL, 0);
+ }
+ spin_unlock_irqrestore(&dpu->intsteer_lock, flags);
+ *ct->mask_cache &= ~mask;
+ irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask);
+ irq_gc_unlock(gc);
+}
+
+static void
+dpu_inner_intsteer_enable_line(struct dpu_soc *dpu, unsigned int line)
+{
+ unsigned int offset = LINE_TO_MASK_OFFSET(line);
+ unsigned int shift = LINE_TO_MASK_SHIFT(line);
+
+ regmap_update_bits(dpu->intsteer_regmap, IRQSTEER_CHANnMASK(offset),
+ BIT(shift), BIT(shift));
+}
+
+static void dpu_inner_intsteer_enable_lines(struct dpu_soc *dpu)
+{
+ const struct dpu_devtype *devtype = dpu->devtype;
+ int i;
+
+ for (i = 0; i < devtype->intsteer_map_size; i++) {
+ if (devtype->intsteer_map[i] == NA)
+ continue;
+
+ dpu_inner_intsteer_enable_line(dpu, devtype->intsteer_map[i]);
+ }
+}
+
+static int dpu_inner_irq_init(struct dpu_soc *dpu)
+{
+ const struct dpu_devtype *devtype = dpu->devtype;
+ const struct cm_reg_ofs *ofs = devtype->cm_reg_ofs;
+ struct irq_chip_generic *gc;
+ struct irq_chip_type *ct;
+ int ret, i;
+
+ dpu_inner_intsteer_enable_lines(dpu);
+
+ dpu->domain = irq_domain_add_linear(dpu->dev->of_node,
+ devtype->intsteer_map_size,
+ &irq_generic_chip_ops, dpu);
+ if (!dpu->domain) {
+ dev_err(dpu->dev, "failed to add irq domain\n");
+ return -ENODEV;
+ }
+
+ ret = irq_alloc_domain_generic_chips(dpu->domain, 32, 1, "DPU",
+ handle_level_irq, 0, 0, 0);
+ if (ret < 0) {
+ dev_err(dpu->dev, "failed to alloc generic irq chips\n");
+ irq_domain_remove(dpu->domain);
+ return ret;
+ }
+
+ for (i = 0; i < devtype->intsteer_map_size; i += 32) {
+ /* Mask and clear all interrupts */
+ dpu_cm_write(dpu, 0,
+ USERINTERRUPTENABLE(ofs, i / 32));
+ dpu_cm_write(dpu, ~devtype->unused_irq[i / 32],
+ USERINTERRUPTCLEAR(ofs, i / 32));
+ dpu_cm_write(dpu, 0,
+ INTERRUPTENABLE(ofs, i / 32));
+ dpu_cm_write(dpu, ~devtype->unused_irq[i / 32],
+ INTERRUPTCLEAR(ofs, i / 32));
+
+ /* Set all interrupts to user mode */
+ dpu_cm_write(dpu, ~devtype->unused_irq[i / 32],
+ USERINTERRUPTMASK(ofs, i / 32));
+
+ gc = irq_get_domain_generic_chip(dpu->domain, i);
+ gc->reg_base = dpu->cm_reg;
+ gc->unused = devtype->unused_irq[i / 32];
+ ct = gc->chip_types;
+ ct->chip.irq_ack = irq_gc_ack_set_bit;
+ ct->chip.irq_mask = dpu_inner_irq_gc_mask_clr_bit;
+ ct->chip.irq_unmask = dpu_inner_irq_gc_mask_set_bit;
+ ct->regs.ack = USERINTERRUPTCLEAR(ofs, i / 32);
+ ct->regs.mask = USERINTERRUPTENABLE(ofs, i / 32);
+ }
+
+#define DPU_INNER_IRQ_SET_CHAINED_HANDLER_AND_DATA1(name) \
+irq_set_chained_handler_and_data(dpu->irq_##name, dpu_##name##_irq_handler, dpu)
+
+ DPU_INNER_IRQ_SET_CHAINED_HANDLER_AND_DATA1(cm);
+ DPU_INNER_IRQ_SET_CHAINED_HANDLER_AND_DATA1(stream0a);
+ DPU_INNER_IRQ_SET_CHAINED_HANDLER_AND_DATA1(stream1a);
+ DPU_INNER_IRQ_SET_CHAINED_HANDLER_AND_DATA1(reserved0);
+ DPU_INNER_IRQ_SET_CHAINED_HANDLER_AND_DATA1(reserved1);
+ DPU_INNER_IRQ_SET_CHAINED_HANDLER_AND_DATA1(blit);
+
+ return 0;
+}
+
+static void dpu_inner_irq_exit(struct dpu_soc *dpu)
+{
+ const struct dpu_devtype *devtype = dpu->devtype;
+ unsigned int i, irq;
+
+#define DPU_INNER_IRQ_SET_CHAINED_HANDLER_AND_DATA2(name) \
+irq_set_chained_handler_and_data(dpu->irq_##name, NULL, NULL)
+
+ DPU_INNER_IRQ_SET_CHAINED_HANDLER_AND_DATA2(cm);
+ DPU_INNER_IRQ_SET_CHAINED_HANDLER_AND_DATA2(stream0a);
+ DPU_INNER_IRQ_SET_CHAINED_HANDLER_AND_DATA2(stream1a);
+ DPU_INNER_IRQ_SET_CHAINED_HANDLER_AND_DATA2(reserved0);
+ DPU_INNER_IRQ_SET_CHAINED_HANDLER_AND_DATA2(reserved1);
+ DPU_INNER_IRQ_SET_CHAINED_HANDLER_AND_DATA2(blit);
+
+ for (i = 0; i < devtype->intsteer_map_size; i++) {
+ irq = irq_linear_revmap(dpu->domain, i);
+ if (irq)
+ irq_dispose_mapping(irq);
+ }
+
+ irq_domain_remove(dpu->domain);
+}
+
+static irqreturn_t dpu_dpr0_irq_handler(int irq, void *desc)
+{
+ struct dpu_soc *dpu = desc;
+ const struct dpu_unit *fls = dpu->devtype->fls;
+ struct dpu_fetchunit *fu;
+ int i;
+
+ for (i = 0; i < fls->num; i++) {
+ fu = dpu->fl_priv[i];
+ dprc_irq_handle(fu->dprc);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t dpu_dpr1_irq_handler(int irq, void *desc)
+{
+ struct dpu_soc *dpu = desc;
+ const struct dpu_unit *fds = dpu->devtype->fds;
+ const struct dpu_unit *fws = dpu->devtype->fws;
+ struct dpu_fetchunit *fu;
+ int i;
+
+ for (i = 0; i < fds->num; i++) {
+ fu = dpu->fd_priv[i];
+ dprc_irq_handle(fu->dprc);
+ }
+
+ for (i = 0; i < fws->num; i++) {
+ fu = dpu->fw_priv[i];
+ dprc_irq_handle(fu->dprc);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void dpu_debug_ip_identity(struct dpu_soc *dpu)
+{
+ struct device *dev = dpu->dev;
+ const struct cm_reg_ofs *ofs = dpu->devtype->cm_reg_ofs;
+ u32 reg;
+ int id = 0;
+
+ reg = dpu_cm_read(dpu, IPIDENTIFIER(ofs));
+
+ dev_dbg(dev, "%d) Maturatiy level:\n", ++id);
+ switch (reg & DESIGNMATURITYLEVEL_MASK) {
+ case DESIGNMATURITYLEVEL__PREFS:
+ dev_dbg(dev, "\tPre feasibility study.\n");
+ break;
+ case DESIGNMATURITYLEVEL__FS:
+ dev_dbg(dev, "\tFeasibility study.\n");
+ break;
+ case DESIGNMATURITYLEVEL__R0:
+ dev_dbg(dev, "\tFunctionality complete.\n");
+ break;
+ case DESIGNMATURITYLEVEL__R1:
+ dev_dbg(dev, "\tVerification complete.\n");
+ break;
+ default:
+ dev_dbg(dev, "\tUnknown.\n");
+ break;
+ }
+
+ dev_dbg(dev, "%d) IP feature set:\n", ++id);
+ switch (reg & IPFEATURESET_MASK) {
+ case IPFEATURESET__E:
+ dev_dbg(dev, "\tMinimal functionality (Eco).\n");
+ break;
+ case IPFEATURESET__L:
+ dev_dbg(dev, "\tReduced functionality (Light).\n");
+ break;
+ case IPFEATURESET__P:
+ dev_dbg(dev, "\tAdvanced functionality (Plus).\n");
+ break;
+ case IPFEATURESET__X:
+ dev_dbg(dev, "\tExtensive functionality (eXtensive).\n");
+ break;
+ default:
+ dev_dbg(dev, "\tUnknown.\n");
+ break;
+ }
+
+ dev_dbg(dev, "%d) IP application:\n", ++id);
+ switch (reg & IPAPPLICATION_MASK) {
+ case IPAPPLICATION__B:
+ dev_dbg(dev, "\tBlit engine only.\n");
+ break;
+ case IPAPPLICATION__D:
+ dev_dbg(dev, "\tBlit engine and display controller.\n");
+ break;
+ case IPAPPLICATION__V:
+ dev_dbg(dev, "\tDisplay controller only "
+ "(with direct capture).\n");
+ break;
+ case IPAPPLICATION__G:
+ dev_dbg(dev, "\tBlit engine, display controller "
+ "(with direct capture),\n"
+ "\tcapture controller (buffered capture) "
+ "and drawing engine.\n");
+ break;
+ case IPAPPLICATION__C:
+ dev_dbg(dev, "\tDisplay controller only.\n");
+ break;
+ default:
+ dev_dbg(dev, "\tUnknown.\n");
+ break;
+ }
+
+ dev_dbg(dev, "%d) IP configuration:\n", ++id);
+ switch (reg & IPCONFIGURATION_MASK) {
+ case IPCONFIGURATION__M:
+ dev_dbg(dev, "\tGraphics core only (Module).\n");
+ break;
+ case IPCONFIGURATION__S:
+ dev_dbg(dev, "\tSubsystem including a graphics core "
+ "(System).\n");
+ break;
+ default:
+ dev_dbg(dev, "\tUnknown.\n");
+ break;
+ }
+
+ dev_dbg(dev, "%d) IP family:\n", ++id);
+ switch (reg & IPFAMILY_MASK) {
+ case IPFAMILY__IMXDPU2010:
+ dev_dbg(dev, "\tBuilding block generation 2010.\n");
+ break;
+ case IPFAMILY__IMXDPU2012:
+ dev_dbg(dev, "\tBuilding block generation 2012.\n");
+ break;
+ case IPFAMILY__IMXDPU2013:
+ dev_dbg(dev, "\tBuilding block generation 2013.\n");
+ break;
+ default:
+ dev_dbg(dev, "\tUnknown.\n");
+ break;
+ }
+}
+
+/* FIXME: initialize pixel link in a proper manner */
+static void dpu_pixel_link_init(int id)
+{
+ sc_err_t sciErr;
+ sc_ipc_t ipcHndl = 0;
+ u32 mu_id;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("Cannot obtain MU ID\n");
+ return;
+ }
+
+ sciErr = sc_ipc_open(&ipcHndl, mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return;
+ }
+
+ if (id == 0) {
+ /* SC_C_KACHUNK_CNT is for blit */
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0, SC_C_KACHUNK_CNT, 32);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_KACHUNK_CNT sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0, SC_C_PXL_LINK_MST1_ADDR, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_PXL_LINK_MST1_ADDR sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0, SC_C_PXL_LINK_MST1_ENB, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_PXL_LINK_MST1_ENB sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0, SC_C_PXL_LINK_MST1_VLD, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_PXL_LINK_MST1_VLD sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0, SC_C_PXL_LINK_MST2_ADDR, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_PXL_LINK_MST2_ADDR sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0, SC_C_PXL_LINK_MST2_ENB, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_PXL_LINK_MST2_ENB sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0, SC_C_PXL_LINK_MST2_VLD, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_PXL_LINK_MST2_VLD sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0, SC_C_SYNC_CTRL0, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_SYNC_CTRL0 sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0, SC_C_SYNC_CTRL1, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_SYNC_CTRL1 sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+ } else if (id == 1) {
+ /* SC_C_KACHUNK_CNT is for blit */
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1, SC_C_KACHUNK_CNT, 32);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_KACHUNK_CNT sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1, SC_C_PXL_LINK_MST1_ADDR, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_PXL_LINK_MST1_ADDR sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1, SC_C_PXL_LINK_MST1_ENB, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_PXL_LINK_MST1_ENB sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1, SC_C_PXL_LINK_MST1_VLD, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_PXL_LINK_MST1_VLD sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1, SC_C_PXL_LINK_MST2_ADDR, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_PXL_LINK_MST2_ADDR sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1, SC_C_PXL_LINK_MST2_ENB, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_PXL_LINK_MST2_ENB sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1, SC_C_PXL_LINK_MST2_VLD, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_PXL_LINK_MST2_VLD sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1, SC_C_SYNC_CTRL0, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_SYNC_CTRL0 sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1, SC_C_SYNC_CTRL1, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_SYNC_CTRL1 sc_misc_set_control failed! (sciError = %d)\n", sciErr);
+ }
+
+ sc_ipc_close(mu_id);
+}
+
+static int dpu_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id =
+ of_match_device(dpu_dt_ids, &pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
+ struct dpu_soc *dpu;
+ struct resource *res;
+ unsigned long dpu_base;
+ const struct dpu_devtype *devtype;
+ int ret;
+
+ devtype = of_id->data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ dpu_base = res->start;
+
+ dpu = devm_kzalloc(&pdev->dev, sizeof(*dpu), GFP_KERNEL);
+ if (!dpu)
+ return -ENODEV;
+
+ dpu->dev = &pdev->dev;
+ dpu->devtype = devtype;
+ dpu->id = of_alias_get_id(np, "dpu");
+
+ /* inner irqs */
+ dpu->irq_cm = platform_get_irq(pdev, 0);
+ dpu->irq_stream0a = platform_get_irq(pdev, 1);
+ dpu->irq_stream1a = platform_get_irq(pdev, 3);
+ dpu->irq_reserved0 = platform_get_irq(pdev, 5);
+ dpu->irq_reserved1 = platform_get_irq(pdev, 6);
+ dpu->irq_blit = platform_get_irq(pdev, 7);
+
+ dev_dbg(dpu->dev, "irq_cm: %d\n", dpu->irq_cm);
+ dev_dbg(dpu->dev, "irq_stream0a: %d, irq_stream1a: %d\n",
+ dpu->irq_stream0a, dpu->irq_stream1a);
+ dev_dbg(dpu->dev, "irq_reserved0: %d, irq_reserved1: %d\n",
+ dpu->irq_reserved0, dpu->irq_reserved1);
+ dev_dbg(dpu->dev, "irq_blit: %d\n", dpu->irq_blit);
+
+ if (dpu->irq_cm < 0 ||
+ dpu->irq_stream0a < 0 || dpu->irq_stream1a < 0 ||
+ dpu->irq_reserved0 < 0 || dpu->irq_reserved1 < 0 ||
+ dpu->irq_blit < 0)
+ return -ENODEV;
+
+ dpu->intsteer_regmap = syscon_regmap_lookup_by_phandle(np, "intsteer");
+ if (IS_ERR(dpu->intsteer_regmap)) {
+ dev_err(dpu->dev, "failed to get intsteer regmap\n");
+ return PTR_ERR(dpu->intsteer_regmap);
+ }
+
+ /* DPR irqs */
+ if (dpu->devtype->has_prefetch) {
+ dpu->irq_dpr0 = platform_get_irq(pdev, 8);
+ dpu->irq_dpr1 = platform_get_irq(pdev, 9);
+
+ dev_dbg(dpu->dev, "irq_dpr0: %d\n", dpu->irq_dpr0);
+ dev_dbg(dpu->dev, "irq_dpr1: %d\n", dpu->irq_dpr1);
+
+ if (dpu->irq_dpr0 < 0 || dpu->irq_dpr1 < 0)
+ return -ENODEV;
+
+ ret = devm_request_irq(dpu->dev, dpu->irq_dpr0,
+ dpu_dpr0_irq_handler, 0, pdev->name, dpu);
+ if (ret) {
+ dev_err(dpu->dev, "request dpr0 interrupt failed\n");
+ return ret;
+ }
+
+ ret = devm_request_irq(dpu->dev, dpu->irq_dpr1,
+ dpu_dpr1_irq_handler, 0, pdev->name, dpu);
+ if (ret) {
+ dev_err(dpu->dev, "request dpr1 interrupt failed\n");
+ return ret;
+ }
+ }
+
+ spin_lock_init(&dpu->lock);
+ spin_lock_init(&dpu->intsteer_lock);
+
+ dev_dbg(dpu->dev, "Common: 0x%08lx\n", dpu_base + devtype->cm_ofs);
+ DPU_UNITS_ADDR_DBG(cf);
+ DPU_UNITS_ADDR_DBG(dec);
+ DPU_UNITS_ADDR_DBG(ed);
+ DPU_UNITS_ADDR_DBG(fd);
+ DPU_UNITS_ADDR_DBG(fe);
+ DPU_UNITS_ADDR_DBG(fg);
+ DPU_UNITS_ADDR_DBG(fl);
+ DPU_UNITS_ADDR_DBG(fw);
+ DPU_UNITS_ADDR_DBG(hs);
+ DPU_UNITS_ADDR_DBG(lb);
+ DPU_UNITS_ADDR_DBG(tcon);
+ DPU_UNITS_ADDR_DBG(vs);
+
+ dpu->cm_reg = devm_ioremap(dpu->dev, dpu_base + devtype->cm_ofs, SZ_1K);
+ if (!dpu->cm_reg)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, dpu);
+
+ ret = dpu_inner_irq_init(dpu);
+ if (ret)
+ goto failed_inner_irq;
+
+ ret = dpu_submodules_init(dpu, pdev, dpu_base);
+ if (ret)
+ goto failed_submodules_init;
+
+ ret = dpu_add_client_devices(dpu);
+ if (ret) {
+ dev_err(dpu->dev, "adding client devices failed with %d\n",
+ ret);
+ goto failed_add_clients;
+ }
+
+ dpu_debug_ip_identity(dpu);
+
+ if (devtype->pixel_link_quirks)
+ dpu_pixel_link_init(dpu->id);
+
+ dev_info(dpu->dev, "driver probed\n");
+
+ return 0;
+
+failed_add_clients:
+failed_submodules_init:
+ dpu_inner_irq_exit(dpu);
+failed_inner_irq:
+ return ret;
+}
+
+static int dpu_remove(struct platform_device *pdev)
+{
+ struct dpu_soc *dpu = platform_get_drvdata(pdev);
+
+ platform_device_unregister_children(pdev);
+ dpu_inner_irq_exit(dpu);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dpu_suspend(struct device *dev)
+{
+ /*
+ * The dpu core driver currently depends on the client drivers
+ * to do suspend operations to leave dpu a cleaned up state
+ * machine status before the system enters sleep mode.
+ */
+ return 0;
+}
+
+static int dpu_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct dpu_soc *dpu = platform_get_drvdata(pdev);
+
+ dpu_inner_intsteer_enable_lines(dpu);
+
+ if (dpu->devtype->pixel_link_quirks)
+ dpu_pixel_link_init(dpu->id);
+
+ _dpu_submodules_init(dpu, pdev);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops dpu_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(dpu_suspend, dpu_resume)
+};
+
+static struct platform_driver dpu_driver = {
+ .driver = {
+ .pm = &dpu_pm_ops,
+ .name = "dpu-core",
+ .of_match_table = dpu_dt_ids,
+ },
+ .probe = dpu_probe,
+ .remove = dpu_remove,
+};
+
+module_platform_driver(dpu_driver);
+
+MODULE_DESCRIPTION("i.MX DPU driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/imx/dpu/dpu-constframe.c b/drivers/gpu/imx/dpu/dpu-constframe.c
new file mode 100644
index 000000000000..d0148306524c
--- /dev/null
+++ b/drivers/gpu/imx/dpu/dpu-constframe.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+static unsigned int safety_stream_cf_color = 0x0;
+module_param(safety_stream_cf_color, uint, 0444);
+MODULE_PARM_DESC(safety_stream_cf_color,
+"Safety stream constframe color in hex(0xRRGGBBAA) [default=0x00000000]");
+
+#define FRAMEDIMENSIONS 0xC
+#define WIDTH(w) (((w) - 1) & 0x3FFF)
+#define HEIGHT(h) ((((h) - 1) & 0x3FFF) << 16)
+#define CONSTANTCOLOR 0x10
+#define RED(r) (((r) & 0xFF) << 24)
+#define GREEN(g) (((g) & 0xFF) << 16)
+#define BLUE(b) (((b) & 0xFF) << 8)
+#define ALPHA(a) ((a) & 0xFF)
+#define CONTROLTRIGGER 0x14
+#define START 0x18
+#define STATUS 0x1C
+
+static const shadow_load_req_t cf_shdlreqs[] = {
+ SHLDREQID_CONSTFRAME0, SHLDREQID_CONSTFRAME1,
+ SHLDREQID_CONSTFRAME4, SHLDREQID_CONSTFRAME5,
+};
+
+struct dpu_constframe {
+ void __iomem *pec_base;
+ void __iomem *base;
+ struct mutex mutex;
+ int id;
+ bool inuse;
+ struct dpu_soc *dpu;
+ shadow_load_req_t shdlreq;
+};
+
+static inline void dpu_cf_write(struct dpu_constframe *cf, u32 value,
+ unsigned int offset)
+{
+ writel(value, cf->base + offset);
+}
+
+void constframe_shden(struct dpu_constframe *cf, bool enable)
+{
+ u32 val;
+
+ val = enable ? SHDEN : 0;
+
+ mutex_lock(&cf->mutex);
+ dpu_cf_write(cf, val, STATICCONTROL);
+ mutex_unlock(&cf->mutex);
+}
+EXPORT_SYMBOL_GPL(constframe_shden);
+
+void constframe_framedimensions(struct dpu_constframe *cf, unsigned int w,
+ unsigned int h)
+{
+ u32 val;
+
+ val = WIDTH(w) | HEIGHT(h);
+
+ mutex_lock(&cf->mutex);
+ dpu_cf_write(cf, val, FRAMEDIMENSIONS);
+ mutex_unlock(&cf->mutex);
+}
+EXPORT_SYMBOL_GPL(constframe_framedimensions);
+
+void constframe_constantcolor(struct dpu_constframe *cf, unsigned int r,
+ unsigned int g, unsigned int b, unsigned int a)
+{
+ u32 val;
+
+ val = RED(r) | GREEN(g) | BLUE(b) | ALPHA(a);
+
+ mutex_lock(&cf->mutex);
+ dpu_cf_write(cf, val, CONSTANTCOLOR);
+ mutex_unlock(&cf->mutex);
+}
+EXPORT_SYMBOL_GPL(constframe_constantcolor);
+
+void constframe_controltrigger(struct dpu_constframe *cf, bool trigger)
+{
+ u32 val;
+
+ val = trigger ? SHDTOKGEN : 0;
+
+ mutex_lock(&cf->mutex);
+ dpu_cf_write(cf, val, CONTROLTRIGGER);
+ mutex_unlock(&cf->mutex);
+}
+EXPORT_SYMBOL_GPL(constframe_controltrigger);
+
+shadow_load_req_t constframe_to_shdldreq_t(struct dpu_constframe *cf)
+{
+ shadow_load_req_t t = 0;
+
+ switch (cf->id) {
+ case 0:
+ t = SHLDREQID_CONSTFRAME0;
+ break;
+ case 1:
+ t = SHLDREQID_CONSTFRAME1;
+ break;
+ case 4:
+ t = SHLDREQID_CONSTFRAME4;
+ break;
+ case 5:
+ t = SHLDREQID_CONSTFRAME5;
+ break;
+ }
+
+ return t;
+}
+EXPORT_SYMBOL_GPL(constframe_to_shdldreq_t);
+
+struct dpu_constframe *dpu_cf_get(struct dpu_soc *dpu, int id)
+{
+ struct dpu_constframe *cf;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cf_ids); i++)
+ if (cf_ids[i] == id)
+ break;
+
+ if (i == ARRAY_SIZE(cf_ids))
+ return ERR_PTR(-EINVAL);
+
+ cf = dpu->cf_priv[i];
+
+ mutex_lock(&cf->mutex);
+
+ if (cf->inuse) {
+ cf = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
+ cf->inuse = true;
+out:
+ mutex_unlock(&cf->mutex);
+
+ return cf;
+}
+EXPORT_SYMBOL_GPL(dpu_cf_get);
+
+void dpu_cf_put(struct dpu_constframe *cf)
+{
+ mutex_lock(&cf->mutex);
+
+ cf->inuse = false;
+
+ mutex_unlock(&cf->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_cf_put);
+
+void _dpu_cf_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_constframe *cf;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cf_ids); i++)
+ if (cf_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(cf_ids)))
+ return;
+
+ cf = dpu->cf_priv[i];
+
+ constframe_shden(cf, true);
+
+ if (id == 4 || id == 5) {
+ mutex_lock(&cf->mutex);
+ dpu_cf_write(cf, safety_stream_cf_color, CONSTANTCOLOR);
+ mutex_unlock(&cf->mutex);
+ }
+}
+
+int dpu_cf_init(struct dpu_soc *dpu, unsigned int id,
+ unsigned long pec_base, unsigned long base)
+{
+ struct dpu_constframe *cf;
+ int i;
+
+ cf = devm_kzalloc(dpu->dev, sizeof(*cf), GFP_KERNEL);
+ if (!cf)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(cf_ids); i++)
+ if (cf_ids[i] == id)
+ break;
+
+ dpu->cf_priv[i] = cf;
+
+ cf->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_16);
+ if (!cf->pec_base)
+ return -ENOMEM;
+
+ cf->base = devm_ioremap(dpu->dev, base, SZ_32);
+ if (!cf->base)
+ return -ENOMEM;
+
+ cf->dpu = dpu;
+ cf->id = id;
+ cf->shdlreq = cf_shdlreqs[i];
+
+ mutex_init(&cf->mutex);
+
+ _dpu_cf_init(dpu, id);
+
+ return 0;
+}
diff --git a/drivers/gpu/imx/dpu/dpu-disengcfg.c b/drivers/gpu/imx/dpu/dpu-disengcfg.c
new file mode 100644
index 000000000000..007da25d4f98
--- /dev/null
+++ b/drivers/gpu/imx/dpu/dpu-disengcfg.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <drm/drm_mode.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include "dpu-prv.h"
+
+#define CLOCKCTRL 0x8
+typedef enum {
+ DSPCLKDIVIDE__DIV1, /* Ext disp clk signal has pix clk freq. */
+ DSPCLKDIVIDE__DIV2, /* Ext disp clk signal has 2x the pix clk freq. */
+} clkdivide_t;
+#define POLARITYCTRL 0xC
+#define POLHS_HIGH BIT(0)
+#define POLVS_HIGH BIT(1)
+#define POLEN_HIGH BIT(2)
+#define PIXINV_INV BIT(3)
+#define SRCSELECT 0x10
+
+struct dpu_disengcfg {
+ void __iomem *base;
+ struct mutex mutex;
+ int id;
+ bool inuse;
+ struct dpu_soc *dpu;
+};
+
+static inline u32 dpu_dec_read(struct dpu_disengcfg *dec, unsigned int offset)
+{
+ return readl(dec->base + offset);
+}
+
+static inline void dpu_dec_write(struct dpu_disengcfg *dec, u32 value,
+ unsigned int offset)
+{
+ writel(value, dec->base + offset);
+}
+
+void disengcfg_polarity_ctrl(struct dpu_disengcfg *dec, unsigned int flags)
+{
+ const struct dpu_devtype *devtype = dec->dpu->devtype;
+ u32 val;
+
+ mutex_lock(&dec->mutex);
+ val = dpu_dec_read(dec, POLARITYCTRL);
+ if (devtype->pixel_link_nhvsync) {
+ val &= ~POLHS_HIGH;
+ val &= ~POLVS_HIGH;
+ } else {
+ if (flags & DRM_MODE_FLAG_PHSYNC)
+ val |= POLHS_HIGH;
+ if (flags & DRM_MODE_FLAG_NHSYNC)
+ val &= ~POLHS_HIGH;
+ if (flags & DRM_MODE_FLAG_PVSYNC)
+ val |= POLVS_HIGH;
+ if (flags & DRM_MODE_FLAG_NVSYNC)
+ val &= ~POLVS_HIGH;
+ }
+ dpu_dec_write(dec, val, POLARITYCTRL);
+ mutex_unlock(&dec->mutex);
+}
+EXPORT_SYMBOL_GPL(disengcfg_polarity_ctrl);
+
+struct dpu_disengcfg *dpu_dec_get(struct dpu_soc *dpu, int id)
+{
+ struct dpu_disengcfg *dec;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dec_ids); i++)
+ if (dec_ids[i] == id)
+ break;
+
+ if (i == ARRAY_SIZE(dec_ids))
+ return ERR_PTR(-EINVAL);
+
+ dec = dpu->dec_priv[i];
+
+ mutex_lock(&dec->mutex);
+
+ if (dec->inuse) {
+ dec = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
+ dec->inuse = true;
+out:
+ mutex_unlock(&dec->mutex);
+
+ return dec;
+}
+EXPORT_SYMBOL_GPL(dpu_dec_get);
+
+void dpu_dec_put(struct dpu_disengcfg *dec)
+{
+ mutex_lock(&dec->mutex);
+
+ dec->inuse = false;
+
+ mutex_unlock(&dec->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_dec_put);
+
+void _dpu_dec_init(struct dpu_soc *dpu, unsigned int id)
+{
+}
+
+int dpu_dec_init(struct dpu_soc *dpu, unsigned int id,
+ unsigned long unused, unsigned long base)
+{
+ struct dpu_disengcfg *dec;
+
+ dec = devm_kzalloc(dpu->dev, sizeof(*dec), GFP_KERNEL);
+ if (!dec)
+ return -ENOMEM;
+
+ dpu->dec_priv[id] = dec;
+
+ dec->base = devm_ioremap(dpu->dev, base, SZ_16);
+ if (!dec->base)
+ return -ENOMEM;
+
+ dec->dpu = dpu;
+ dec->id = id;
+ mutex_init(&dec->mutex);
+
+ return 0;
+}
diff --git a/drivers/gpu/imx/dpu/dpu-extdst.c b/drivers/gpu/imx/dpu/dpu-extdst.c
new file mode 100644
index 000000000000..ab79fe6a02c8
--- /dev/null
+++ b/drivers/gpu/imx/dpu/dpu-extdst.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define PIXENGCFG_STATIC 0x8
+#define POWERDOWN BIT(4)
+#define SYNC_MODE BIT(8)
+#define SW_RESET BIT(11)
+#define DIV(n) (((n) & 0xFF) << 16)
+#define DIV_RESET 0x80
+#define PIXENGCFG_DYNAMIC 0xC
+#define PIXENGCFG_REQUEST 0x10
+#define SHDLDREQ(n) BIT(n)
+#define SEL_SHDLDREQ BIT(0)
+#define PIXENGCFG_TRIGGER 0x14
+#define SYNC_TRIGGER BIT(0)
+#define TRIGGER_SEQUENCE_COMPLETE BIT(4)
+#define PIXENGCFG_STATUS 0x18
+#define SYNC_BUSY BIT(8)
+#define KICK_MODE BIT(8)
+#define PERFCOUNTMODE BIT(12)
+#define CONTROL 0xC
+#define GAMMAAPPLYENABLE BIT(0)
+#define SOFTWAREKICK 0x10
+#define KICK BIT(0)
+#define STATUS 0x14
+#define CNT_ERR_STS BIT(0)
+#define CONTROLWORD 0x18
+#define CURPIXELCNT 0x1C
+static u16 get_xval(u32 pixel_cnt)
+{
+ return pixel_cnt && 0xFF;
+}
+
+static u16 get_yval(u32 pixel_cnt)
+{
+ return pixel_cnt >> 16;
+}
+#define LASTPIXELCNT 0x20
+#define PERFCOUNTER 0x24
+
+struct dpu_extdst {
+ void __iomem *pec_base;
+ void __iomem *base;
+ struct mutex mutex;
+ int id;
+ bool inuse;
+ struct dpu_soc *dpu;
+};
+
+static inline u32 dpu_pec_ed_read(struct dpu_extdst *ed, unsigned int offset)
+{
+ return readl(ed->pec_base + offset);
+}
+
+static inline void dpu_pec_ed_write(struct dpu_extdst *ed, u32 value,
+ unsigned int offset)
+{
+ writel(value, ed->pec_base + offset);
+}
+
+static inline u32 dpu_ed_read(struct dpu_extdst *ed, unsigned int offset)
+{
+ return readl(ed->base + offset);
+}
+
+static inline void dpu_ed_write(struct dpu_extdst *ed, u32 value,
+ unsigned int offset)
+{
+ writel(value, ed->base + offset);
+}
+
+static inline bool dpu_ed_is_safety_stream(struct dpu_extdst *ed)
+{
+ if (ed->id == 4 || ed->id == 5)
+ return true;
+
+ return false;
+}
+
+static inline bool dpu_ed_src_sel_is_extsrc(extdst_src_sel_t src)
+{
+ if (src == ED_SRC_EXTSRC4 || src == ED_SRC_EXTSRC5)
+ return true;
+
+ return false;
+}
+
+void extdst_pixengcfg_shden(struct dpu_extdst *ed, bool enable)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_pec_ed_read(ed, PIXENGCFG_STATIC);
+ if (enable)
+ val |= SHDEN;
+ else
+ val &= ~SHDEN;
+ dpu_pec_ed_write(ed, val, PIXENGCFG_STATIC);
+ mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_shden);
+
+void extdst_pixengcfg_powerdown(struct dpu_extdst *ed, bool powerdown)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_pec_ed_read(ed, PIXENGCFG_STATIC);
+ if (powerdown)
+ val |= POWERDOWN;
+ else
+ val &= ~POWERDOWN;
+ dpu_pec_ed_write(ed, val, PIXENGCFG_STATIC);
+ mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_powerdown);
+
+void extdst_pixengcfg_sync_mode(struct dpu_extdst *ed, ed_sync_mode_t mode)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_pec_ed_read(ed, PIXENGCFG_STATIC);
+ if (mode == AUTO)
+ val |= SYNC_MODE;
+ else
+ val &= ~SYNC_MODE;
+ dpu_pec_ed_write(ed, val, PIXENGCFG_STATIC);
+ mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_sync_mode);
+
+void extdst_pixengcfg_reset(struct dpu_extdst *ed, bool reset)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_pec_ed_read(ed, PIXENGCFG_STATIC);
+ if (reset)
+ val |= SW_RESET;
+ else
+ val &= ~SW_RESET;
+ dpu_pec_ed_write(ed, val, PIXENGCFG_STATIC);
+ mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_reset);
+
+void extdst_pixengcfg_div(struct dpu_extdst *ed, u16 div)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_pec_ed_read(ed, PIXENGCFG_STATIC);
+ val &= ~0xFF0000;
+ val |= DIV(div);
+ dpu_pec_ed_write(ed, val, PIXENGCFG_STATIC);
+ mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_div);
+
+int extdst_pixengcfg_src_sel(struct dpu_extdst *ed, extdst_src_sel_t src)
+{
+ struct dpu_soc *dpu = ed->dpu;
+ const unsigned int *block_id_map = dpu->devtype->sw2hw_block_id_map;
+ u32 mapped_src;
+
+ mapped_src = block_id_map ? block_id_map[src] : src;
+ if (WARN_ON(mapped_src == NA))
+ return -EINVAL;
+
+ if (dpu_ed_is_safety_stream(ed) && dpu_ed_src_sel_is_extsrc(src)) {
+ dev_err(dpu->dev, "ExtDst%d source cannot be ExtSrc\n", ed->id);
+ return -EINVAL;
+ }
+
+ mutex_lock(&ed->mutex);
+ dpu_pec_ed_write(ed, mapped_src, PIXENGCFG_DYNAMIC);
+ mutex_unlock(&ed->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_src_sel);
+
+void extdst_pixengcfg_sel_shdldreq(struct dpu_extdst *ed)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_pec_ed_read(ed, PIXENGCFG_REQUEST);
+ val |= SEL_SHDLDREQ;
+ dpu_pec_ed_write(ed, val, PIXENGCFG_REQUEST);
+ mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_sel_shdldreq);
+
+void extdst_pixengcfg_shdldreq(struct dpu_extdst *ed, u32 req_mask)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_pec_ed_read(ed, PIXENGCFG_REQUEST);
+ val |= req_mask;
+ dpu_pec_ed_write(ed, val, PIXENGCFG_REQUEST);
+ mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_shdldreq);
+
+void extdst_pixengcfg_sync_trigger(struct dpu_extdst *ed)
+{
+ mutex_lock(&ed->mutex);
+ dpu_pec_ed_write(ed, SYNC_TRIGGER, PIXENGCFG_TRIGGER);
+ mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_sync_trigger);
+
+void extdst_pixengcfg_trigger_sequence_complete(struct dpu_extdst *ed)
+{
+ mutex_lock(&ed->mutex);
+ dpu_pec_ed_write(ed, TRIGGER_SEQUENCE_COMPLETE, PIXENGCFG_TRIGGER);
+ mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_trigger_sequence_complete);
+
+bool extdst_pixengcfg_is_sync_busy(struct dpu_extdst *ed)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_pec_ed_read(ed, PIXENGCFG_STATUS);
+ mutex_unlock(&ed->mutex);
+
+ return val & SYNC_BUSY;
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_is_sync_busy);
+
+ed_pipeline_status_t extdst_pixengcfg_pipeline_status(struct dpu_extdst *ed)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_pec_ed_read(ed, PIXENGCFG_STATUS);
+ mutex_unlock(&ed->mutex);
+
+ return val & 0x3;
+}
+EXPORT_SYMBOL_GPL(extdst_pixengcfg_pipeline_status);
+
+void extdst_shden(struct dpu_extdst *ed, bool enable)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_ed_read(ed, STATICCONTROL);
+ if (enable)
+ val |= SHDEN;
+ else
+ val &= ~SHDEN;
+ dpu_ed_write(ed, val, STATICCONTROL);
+ mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_shden);
+
+void extdst_kick_mode(struct dpu_extdst *ed, ed_kick_mode_t mode)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_ed_read(ed, STATICCONTROL);
+ val &= ~KICK_MODE;
+ val |= mode;
+ dpu_ed_write(ed, val, STATICCONTROL);
+ mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_kick_mode);
+
+void extdst_perfcountmode(struct dpu_extdst *ed, bool enable)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_ed_read(ed, STATICCONTROL);
+ if (enable)
+ val |= PERFCOUNTMODE;
+ else
+ val &= ~PERFCOUNTMODE;
+ dpu_ed_write(ed, val, STATICCONTROL);
+ mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_perfcountmode);
+
+void extdst_gamma_apply_enable(struct dpu_extdst *ed, bool enable)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_ed_read(ed, CONTROL);
+ if (enable)
+ val |= GAMMAAPPLYENABLE;
+ else
+ val &= ~GAMMAAPPLYENABLE;
+ dpu_ed_write(ed, val, CONTROL);
+ mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_gamma_apply_enable);
+
+void extdst_kick(struct dpu_extdst *ed)
+{
+ mutex_lock(&ed->mutex);
+ dpu_ed_write(ed, KICK, SOFTWAREKICK);
+ mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_kick);
+
+void extdst_cnt_err_clear(struct dpu_extdst *ed)
+{
+ mutex_lock(&ed->mutex);
+ dpu_ed_write(ed, CNT_ERR_STS, STATUS);
+ mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(extdst_cnt_err_clear);
+
+bool extdst_cnt_err_status(struct dpu_extdst *ed)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_ed_read(ed, STATUS);
+ mutex_unlock(&ed->mutex);
+
+ return val & CNT_ERR_STS;
+}
+EXPORT_SYMBOL_GPL(extdst_cnt_err_status);
+
+u32 extdst_last_control_word(struct dpu_extdst *ed)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_ed_read(ed, CONTROLWORD);
+ mutex_unlock(&ed->mutex);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(extdst_last_control_word);
+
+void extdst_pixel_cnt(struct dpu_extdst *ed, u16 *x, u16 *y)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_ed_read(ed, CURPIXELCNT);
+ mutex_unlock(&ed->mutex);
+
+ *x = get_xval(val);
+ *y = get_yval(val);
+}
+EXPORT_SYMBOL_GPL(extdst_pixel_cnt);
+
+void extdst_last_pixel_cnt(struct dpu_extdst *ed, u16 *x, u16 *y)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_ed_read(ed, LASTPIXELCNT);
+ mutex_unlock(&ed->mutex);
+
+ *x = get_xval(val);
+ *y = get_yval(val);
+}
+EXPORT_SYMBOL_GPL(extdst_last_pixel_cnt);
+
+u32 extdst_perfresult(struct dpu_extdst *ed)
+{
+ u32 val;
+
+ mutex_lock(&ed->mutex);
+ val = dpu_ed_read(ed, PERFCOUNTER);
+ mutex_unlock(&ed->mutex);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(extdst_perfresult);
+
+struct dpu_extdst *dpu_ed_get(struct dpu_soc *dpu, int id)
+{
+ struct dpu_extdst *ed;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ed_ids); i++)
+ if (ed_ids[i] == id)
+ break;
+
+ if (i == ARRAY_SIZE(ed_ids))
+ return ERR_PTR(-EINVAL);
+
+ ed = dpu->ed_priv[i];
+
+ mutex_lock(&ed->mutex);
+
+ if (ed->inuse) {
+ ed = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
+ ed->inuse = true;
+out:
+ mutex_unlock(&ed->mutex);
+
+ return ed;
+}
+EXPORT_SYMBOL_GPL(dpu_ed_get);
+
+void dpu_ed_put(struct dpu_extdst *ed)
+{
+ mutex_lock(&ed->mutex);
+
+ ed->inuse = false;
+
+ mutex_unlock(&ed->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_ed_put);
+
+void _dpu_ed_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_extdst *ed;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ed_ids); i++)
+ if (ed_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(ed_ids)))
+ return;
+
+ ed = dpu->ed_priv[i];
+
+ extdst_pixengcfg_src_sel(ed, ED_SRC_DISABLE);
+ extdst_pixengcfg_shden(ed, true);
+ extdst_pixengcfg_powerdown(ed, false);
+ extdst_pixengcfg_sync_mode(ed, SINGLE);
+ extdst_pixengcfg_reset(ed, false);
+ extdst_pixengcfg_div(ed, DIV_RESET);
+ extdst_shden(ed, true);
+ extdst_perfcountmode(ed, false);
+ extdst_kick_mode(ed, EXTERNAL);
+}
+
+int dpu_ed_init(struct dpu_soc *dpu, unsigned int id,
+ unsigned long pec_base, unsigned long base)
+{
+ struct dpu_extdst *ed;
+ int ret, i;
+
+ ed = devm_kzalloc(dpu->dev, sizeof(*ed), GFP_KERNEL);
+ if (!ed)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(ed_ids); i++)
+ if (ed_ids[i] == id)
+ break;
+
+ dpu->ed_priv[i] = ed;
+
+ ed->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_32);
+ if (!ed->pec_base)
+ return -ENOMEM;
+
+ ed->base = devm_ioremap(dpu->dev, base, SZ_64);
+ if (!ed->base)
+ return -ENOMEM;
+
+ ed->dpu = dpu;
+ ed->id = id;
+ mutex_init(&ed->mutex);
+
+ ret = extdst_pixengcfg_src_sel(ed, ED_SRC_DISABLE);
+ if (ret < 0)
+ return ret;
+
+ _dpu_ed_init(dpu, id);
+
+ return 0;
+}
diff --git a/drivers/gpu/imx/dpu/dpu-fetchdecode.c b/drivers/gpu/imx/dpu/dpu-fetchdecode.c
new file mode 100644
index 000000000000..cbf4ca9cf3c8
--- /dev/null
+++ b/drivers/gpu/imx/dpu/dpu-fetchdecode.c
@@ -0,0 +1,778 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define FD_NUM_V1 4
+#define FD_NUM_V2 2
+
+static const u32 fd_vproc_cap_v1[FD_NUM_V1] = {
+ DPU_VPROC_CAP_HSCALER4 | DPU_VPROC_CAP_VSCALER4 |
+ DPU_VPROC_CAP_FETCHECO0,
+ DPU_VPROC_CAP_HSCALER5 | DPU_VPROC_CAP_VSCALER5 |
+ DPU_VPROC_CAP_FETCHECO1,
+ DPU_VPROC_CAP_HSCALER4 | DPU_VPROC_CAP_VSCALER4 |
+ DPU_VPROC_CAP_FETCHECO0,
+ DPU_VPROC_CAP_HSCALER5 | DPU_VPROC_CAP_VSCALER5 |
+ DPU_VPROC_CAP_FETCHECO1,
+};
+
+static const u32 fd_vproc_cap_v2[FD_NUM_V2] = {
+ DPU_VPROC_CAP_HSCALER4 | DPU_VPROC_CAP_VSCALER4 |
+ DPU_VPROC_CAP_FETCHECO0,
+ DPU_VPROC_CAP_HSCALER5 | DPU_VPROC_CAP_VSCALER5 |
+ DPU_VPROC_CAP_FETCHECO1,
+};
+
+#define PIXENGCFG_DYNAMIC 0x8
+#define SRC_NUM_V1 3
+#define SRC_NUM_V2 4
+static const fd_dynamic_src_sel_t fd_srcs_v1[FD_NUM_V1][SRC_NUM_V1] = {
+ { FD_SRC_DISABLE, FD_SRC_FETCHECO0, FD_SRC_FETCHDECODE2 },
+ { FD_SRC_DISABLE, FD_SRC_FETCHECO1, FD_SRC_FETCHDECODE3 },
+ { FD_SRC_DISABLE, FD_SRC_FETCHECO0, FD_SRC_FETCHECO2 },
+ { FD_SRC_DISABLE, FD_SRC_FETCHECO1, FD_SRC_FETCHECO2 },
+};
+
+static const fd_dynamic_src_sel_t fd_srcs_v2[FD_NUM_V2][SRC_NUM_V2] = {
+ {
+ FD_SRC_DISABLE, FD_SRC_FETCHECO0,
+ FD_SRC_FETCHDECODE1, FD_SRC_FETCHWARP2
+ }, {
+ FD_SRC_DISABLE, FD_SRC_FETCHECO1,
+ FD_SRC_FETCHDECODE0, FD_SRC_FETCHWARP2
+ },
+};
+
+#define PIXENGCFG_STATUS 0xC
+
+#define RINGBUFSTARTADDR0 0x10
+#define RINGBUFWRAPADDR0 0x14
+#define FRAMEPROPERTIES0 0x18
+#define BASEADDRESS0 0x1C
+#define SOURCEBUFFERATTRIBUTES0 0x20
+#define SOURCEBUFFERDIMENSION0 0x24
+#define COLORCOMPONENTBITS0 0x28
+#define COLORCOMPONENTSHIFT0 0x2C
+#define LAYEROFFSET0 0x30
+#define CLIPWINDOWOFFSET0 0x34
+#define CLIPWINDOWDIMENSIONS0 0x38
+#define CONSTANTCOLOR0 0x3C
+#define LAYERPROPERTY0 0x40
+#define FRAMEDIMENSIONS 0x44
+#define FRAMERESAMPLING 0x48
+#define DECODECONTROL 0x4C
+#define SOURCEBUFFERLENGTH 0x50
+#define CONTROL 0x54
+#define CONTROLTRIGGER 0x58
+#define START 0x5C
+#define FETCHTYPE 0x60
+#define DECODERSTATUS 0x64
+#define READADDRESS0 0x68
+#define BURSTBUFFERPROPERTIES 0x6C
+#define STATUS 0x70
+#define HIDDENSTATUS 0x74
+
+static const shadow_load_req_t fd_shdlreqs[] = {
+ SHLDREQID_FETCHDECODE0, SHLDREQID_FETCHDECODE1,
+ SHLDREQID_FETCHDECODE2, SHLDREQID_FETCHDECODE3,
+};
+
+struct dpu_fetchdecode {
+ struct dpu_fetchunit fu;
+ fetchtype_t fetchtype;
+ shadow_load_req_t shdlreq;
+};
+
+int fetchdecode_pixengcfg_dynamic_src_sel(struct dpu_fetchunit *fu,
+ fd_dynamic_src_sel_t src)
+{
+ struct dpu_soc *dpu = fu->dpu;
+ const struct dpu_devtype *devtype = dpu->devtype;
+ int i;
+
+ mutex_lock(&fu->mutex);
+ if (devtype->version == DPU_V1) {
+ for (i = 0; i < SRC_NUM_V1; i++) {
+ if (fd_srcs_v1[fu->id][i] == src) {
+ dpu_pec_fu_write(fu, src, PIXENGCFG_DYNAMIC);
+ mutex_unlock(&fu->mutex);
+ return 0;
+ }
+ }
+ } else if (devtype->version == DPU_V2) {
+ const unsigned int *block_id_map = devtype->sw2hw_block_id_map;
+ u32 mapped_src;
+
+ if (WARN_ON(!block_id_map))
+ return -EINVAL;
+
+ for (i = 0; i < SRC_NUM_V2; i++) {
+ if (fd_srcs_v2[fu->id][i] == src) {
+ mapped_src = block_id_map[src];
+ if (WARN_ON(mapped_src == NA))
+ return -EINVAL;
+
+ dpu_pec_fu_write(fu, mapped_src,
+ PIXENGCFG_DYNAMIC);
+ mutex_unlock(&fu->mutex);
+ return 0;
+ }
+ }
+ } else {
+ WARN_ON(1);
+ }
+ mutex_unlock(&fu->mutex);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(fetchdecode_pixengcfg_dynamic_src_sel);
+
+static void
+fetchdecode_set_baseaddress(struct dpu_fetchunit *fu, unsigned int width,
+ unsigned int x_offset, unsigned int y_offset,
+ unsigned int mt_w, unsigned int mt_h,
+ int bpp, dma_addr_t baddr)
+{
+ unsigned int burst_size, stride;
+ bool nonzero_mod = !!mt_w;
+
+ if (nonzero_mod) {
+ /* consider PRG x offset to calculate buffer address */
+ baddr += (x_offset % mt_w) * (bpp / 8);
+
+ /*
+ * address TKT343664:
+ * fetch unit base address has to align to burst size
+ */
+ burst_size = 1 << (ffs(baddr) - 1);
+ burst_size = round_up(burst_size, 8);
+ burst_size = min(burst_size, 128U);
+
+ stride = width * (bpp >> 3);
+ /*
+ * address TKT339017:
+ * fixup for burst size vs stride mismatch
+ */
+ stride = round_up(stride + round_up(baddr % 8, 8), burst_size);
+
+ /* consider PRG y offset to calculate buffer address */
+ baddr += (y_offset % mt_h) * stride;
+ }
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, baddr, BASEADDRESS0);
+ mutex_unlock(&fu->mutex);
+}
+
+static void fetchdecode_set_src_bpp(struct dpu_fetchunit *fu, int bpp)
+{
+ u32 val;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, SOURCEBUFFERATTRIBUTES0);
+ val &= ~0x3f0000;
+ val |= BITSPERPIXEL(bpp);
+ dpu_fu_write(fu, val, SOURCEBUFFERATTRIBUTES0);
+ mutex_unlock(&fu->mutex);
+}
+
+static void
+fetchdecode_set_src_stride(struct dpu_fetchunit *fu,
+ unsigned int width, unsigned int x_offset,
+ unsigned int mt_w, int bpp, unsigned int stride,
+ dma_addr_t baddr, bool use_prefetch)
+{
+ unsigned int burst_size;
+ bool nonzero_mod = !!mt_w;
+ u32 val;
+
+ if (use_prefetch) {
+ /* consider PRG x offset to calculate buffer address */
+ if (nonzero_mod)
+ baddr += (x_offset % mt_w) * (bpp / 8);
+
+ /*
+ * address TKT343664:
+ * fetch unit base address has to align to burst size
+ */
+ burst_size = 1 << (ffs(baddr) - 1);
+ burst_size = round_up(burst_size, 8);
+ burst_size = min(burst_size, 128U);
+
+ stride = width * (bpp >> 3);
+ /*
+ * address TKT339017:
+ * fixup for burst size vs stride mismatch
+ */
+ if (nonzero_mod)
+ stride = round_up(stride + round_up(baddr % 8, 8),
+ burst_size);
+ else
+ stride = round_up(stride, burst_size);
+ }
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, SOURCEBUFFERATTRIBUTES0);
+ val &= ~0xffff;
+ val |= STRIDE(stride);
+ dpu_fu_write(fu, val, SOURCEBUFFERATTRIBUTES0);
+ mutex_unlock(&fu->mutex);
+}
+
+static void
+fetchdecode_set_src_buf_dimensions(struct dpu_fetchunit *fu,
+ unsigned int w, unsigned int h,
+ u32 unused, bool deinterlace)
+{
+ u32 val;
+
+ if (deinterlace)
+ h /= 2;
+
+ val = LINEWIDTH(w) | LINECOUNT(h);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, SOURCEBUFFERDIMENSION0);
+ mutex_unlock(&fu->mutex);
+}
+
+static void
+fetchdecode_set_fmt(struct dpu_fetchunit *fu, u32 fmt, bool deinterlace)
+{
+ u32 val, bits, shift;
+ bool is_planar_yuv = false, is_rastermode_yuv422 = false;
+ bool is_yuv422upsamplingmode_interpolate = false;
+ bool is_inputselect_compact = false;
+ bool need_csc = false;
+ int i;
+
+ switch (fmt) {
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_UYVY:
+ is_rastermode_yuv422 = true;
+ is_yuv422upsamplingmode_interpolate = true;
+ need_csc = true;
+ break;
+ case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV61:
+ is_yuv422upsamplingmode_interpolate = true;
+ /* fall-through */
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ if (deinterlace)
+ is_yuv422upsamplingmode_interpolate = true;
+ is_planar_yuv = true;
+ is_rastermode_yuv422 = true;
+ is_inputselect_compact = true;
+ need_csc = true;
+ break;
+ case DRM_FORMAT_NV24:
+ case DRM_FORMAT_NV42:
+ is_planar_yuv = true;
+ is_yuv422upsamplingmode_interpolate = true;
+ is_inputselect_compact = true;
+ need_csc = true;
+ break;
+ default:
+ break;
+ }
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, CONTROL);
+ val &= ~YUV422UPSAMPLINGMODE_MASK;
+ val &= ~INPUTSELECT_MASK;
+ val &= ~RASTERMODE_MASK;
+ if (is_yuv422upsamplingmode_interpolate)
+ val |= YUV422UPSAMPLINGMODE(YUV422UPSAMPLINGMODE__INTERPOLATE);
+ else
+ val |= YUV422UPSAMPLINGMODE(YUV422UPSAMPLINGMODE__REPLICATE);
+ if (is_inputselect_compact)
+ val |= INPUTSELECT(INPUTSELECT__COMPPACK);
+ else
+ val |= INPUTSELECT(INPUTSELECT__INACTIVE);
+ if (is_rastermode_yuv422)
+ val |= RASTERMODE(RASTERMODE__YUV422);
+ else
+ val |= RASTERMODE(RASTERMODE__NORMAL);
+ dpu_fu_write(fu, val, CONTROL);
+
+ val = dpu_fu_read(fu, LAYERPROPERTY0);
+ val &= ~YUVCONVERSIONMODE_MASK;
+ if (need_csc)
+ /*
+ * assuming fetchdecode always ouputs RGB pixel formats
+ *
+ * FIXME:
+ * determine correct standard here - ITU601 or ITU601_FR
+ * or ITU709
+ */
+ val |= YUVCONVERSIONMODE(YUVCONVERSIONMODE__ITU601_FR);
+ else
+ val |= YUVCONVERSIONMODE(YUVCONVERSIONMODE__OFF);
+ dpu_fu_write(fu, val, LAYERPROPERTY0);
+ mutex_unlock(&fu->mutex);
+
+ for (i = 0; i < ARRAY_SIZE(dpu_pixel_format_matrix); i++) {
+ if (dpu_pixel_format_matrix[i].pixel_format == fmt) {
+ bits = dpu_pixel_format_matrix[i].bits;
+ shift = dpu_pixel_format_matrix[i].shift;
+
+ if (is_planar_yuv) {
+ bits &= ~(U_BITS_MASK | V_BITS_MASK);
+ shift &= ~(U_SHIFT_MASK | V_SHIFT_MASK);
+ }
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, bits, COLORCOMPONENTBITS0);
+ dpu_fu_write(fu, shift, COLORCOMPONENTSHIFT0);
+ mutex_unlock(&fu->mutex);
+ return;
+ }
+ }
+
+ WARN_ON(1);
+}
+
+void fetchdecode_layeroffset(struct dpu_fetchunit *fu, unsigned int x,
+ unsigned int y)
+{
+ u32 val;
+
+ val = LAYERXOFFSET(x) | LAYERYOFFSET(y);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, LAYEROFFSET0);
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchdecode_layeroffset);
+
+void fetchdecode_clipoffset(struct dpu_fetchunit *fu, unsigned int x,
+ unsigned int y)
+{
+ u32 val;
+
+ val = CLIPWINDOWXOFFSET(x) | CLIPWINDOWYOFFSET(y);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, CLIPWINDOWOFFSET0);
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchdecode_clipoffset);
+
+static void fetchdecode_enable_src_buf(struct dpu_fetchunit *fu)
+{
+ u32 val;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, LAYERPROPERTY0);
+ val |= SOURCEBUFFERENABLE;
+ dpu_fu_write(fu, val, LAYERPROPERTY0);
+ mutex_unlock(&fu->mutex);
+}
+
+static void fetchdecode_disable_src_buf(struct dpu_fetchunit *fu)
+{
+ u32 val;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, LAYERPROPERTY0);
+ val &= ~SOURCEBUFFERENABLE;
+ dpu_fu_write(fu, val, LAYERPROPERTY0);
+ mutex_unlock(&fu->mutex);
+}
+
+static bool fetchdecode_is_enabled(struct dpu_fetchunit *fu)
+{
+ u32 val;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, LAYERPROPERTY0);
+ mutex_unlock(&fu->mutex);
+
+ return !!(val & SOURCEBUFFERENABLE);
+}
+
+void fetchdecode_clipdimensions(struct dpu_fetchunit *fu, unsigned int w,
+ unsigned int h)
+{
+ u32 val;
+
+ val = CLIPWINDOWWIDTH(w) | CLIPWINDOWHEIGHT(h);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, CLIPWINDOWDIMENSIONS0);
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchdecode_clipdimensions);
+
+static void
+fetchdecode_set_framedimensions(struct dpu_fetchunit *fu,
+ unsigned int w, unsigned int h,
+ bool deinterlace)
+{
+ u32 val;
+
+ if (deinterlace)
+ h /= 2;
+
+ val = FRAMEWIDTH(w) | FRAMEHEIGHT(h);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, FRAMEDIMENSIONS);
+ mutex_unlock(&fu->mutex);
+}
+
+void fetchdecode_rgb_constantcolor(struct dpu_fetchunit *fu,
+ u8 r, u8 g, u8 b, u8 a)
+{
+ u32 val;
+
+ val = rgb_color(r, g, b, a);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, CONSTANTCOLOR0);
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchdecode_rgb_constantcolor);
+
+void fetchdecode_yuv_constantcolor(struct dpu_fetchunit *fu, u8 y, u8 u, u8 v)
+{
+ u32 val;
+
+ val = yuv_color(y, u, v);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, CONSTANTCOLOR0);
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchdecode_yuv_constantcolor);
+
+static void fetchdecode_set_controltrigger(struct dpu_fetchunit *fu)
+{
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, SHDTOKGEN, CONTROLTRIGGER);
+ mutex_unlock(&fu->mutex);
+}
+
+int fetchdecode_fetchtype(struct dpu_fetchunit *fu, fetchtype_t *type)
+{
+ struct dpu_soc *dpu = fu->dpu;
+ u32 val;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, FETCHTYPE);
+ val &= FETCHTYPE_MASK;
+ mutex_unlock(&fu->mutex);
+
+ switch (val) {
+ case FETCHTYPE__DECODE:
+ dev_dbg(dpu->dev, "FetchDecode%d with RL and RLAD decoder\n",
+ fu->id);
+ break;
+ case FETCHTYPE__LAYER:
+ dev_dbg(dpu->dev, "FetchDecode%d with fractional "
+ "plane(8 layers)\n", fu->id);
+ break;
+ case FETCHTYPE__WARP:
+ dev_dbg(dpu->dev, "FetchDecode%d with arbitrary warping and "
+ "fractional plane(8 layers)\n", fu->id);
+ break;
+ case FETCHTYPE__ECO:
+ dev_dbg(dpu->dev, "FetchDecode%d with minimum feature set for "
+ "alpha, chroma and coordinate planes\n",
+ fu->id);
+ break;
+ case FETCHTYPE__PERSP:
+ dev_dbg(dpu->dev, "FetchDecode%d with affine, perspective and "
+ "arbitrary warping\n", fu->id);
+ break;
+ case FETCHTYPE__ROT:
+ dev_dbg(dpu->dev, "FetchDecode%d with affine and arbitrary "
+ "warping\n", fu->id);
+ break;
+ case FETCHTYPE__DECODEL:
+ dev_dbg(dpu->dev, "FetchDecode%d with RL and RLAD decoder, "
+ "reduced feature set\n", fu->id);
+ break;
+ case FETCHTYPE__LAYERL:
+ dev_dbg(dpu->dev, "FetchDecode%d with fractional "
+ "plane(8 layers), reduced feature set\n",
+ fu->id);
+ break;
+ case FETCHTYPE__ROTL:
+ dev_dbg(dpu->dev, "FetchDecode%d with affine and arbitrary "
+ "warping, reduced feature set\n", fu->id);
+ break;
+ default:
+ dev_warn(dpu->dev, "Invalid fetch type %u for FetchDecode%d\n",
+ val, fu->id);
+ return -EINVAL;
+ }
+
+ *type = val;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fetchdecode_fetchtype);
+
+shadow_load_req_t fetchdecode_to_shdldreq_t(struct dpu_fetchunit *fu)
+{
+ shadow_load_req_t t = 0;
+
+ switch (fu->id) {
+ case 0:
+ t = SHLDREQID_FETCHDECODE0;
+ break;
+ case 1:
+ t = SHLDREQID_FETCHDECODE1;
+ break;
+ case 2:
+ t = SHLDREQID_FETCHDECODE2;
+ break;
+ case 3:
+ t = SHLDREQID_FETCHDECODE3;
+ break;
+ default:
+ break;
+ }
+
+ return t;
+}
+EXPORT_SYMBOL_GPL(fetchdecode_to_shdldreq_t);
+
+u32 fetchdecode_get_vproc_mask(struct dpu_fetchunit *fu)
+{
+ struct dpu_soc *dpu = fu->dpu;
+ const struct dpu_devtype *devtype = dpu->devtype;
+
+ return devtype->version == DPU_V1 ?
+ fd_vproc_cap_v1[fu->id] : fd_vproc_cap_v2[fu->id];
+}
+EXPORT_SYMBOL_GPL(fetchdecode_get_vproc_mask);
+
+struct dpu_fetchunit *fetchdecode_get_fetcheco(struct dpu_fetchunit *fu)
+{
+ struct dpu_soc *dpu = fu->dpu;
+
+ switch (fu->id) {
+ case 0:
+ case 1:
+ return dpu->fe_priv[fu->id];
+ case 2:
+ case 3:
+ /* TODO: for DPU v1, add FetchEco2 support */
+ return dpu->fe_priv[fu->id - 2];
+ default:
+ WARN_ON(1);
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(fetchdecode_get_fetcheco);
+
+bool fetchdecode_need_fetcheco(struct dpu_fetchunit *fu, u32 fmt)
+{
+ struct dpu_fetchunit *fe = fetchdecode_get_fetcheco(fu);
+
+ if (IS_ERR_OR_NULL(fe))
+ return false;
+
+ switch (fmt) {
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV61:
+ case DRM_FORMAT_NV24:
+ case DRM_FORMAT_NV42:
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(fetchdecode_need_fetcheco);
+
+struct dpu_hscaler *fetchdecode_get_hscaler(struct dpu_fetchunit *fu)
+{
+ struct dpu_soc *dpu = fu->dpu;
+
+ switch (fu->id) {
+ case 0:
+ case 2:
+ return dpu->hs_priv[0];
+ case 1:
+ case 3:
+ return dpu->hs_priv[1];
+ default:
+ WARN_ON(1);
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(fetchdecode_get_hscaler);
+
+struct dpu_vscaler *fetchdecode_get_vscaler(struct dpu_fetchunit *fu)
+{
+ struct dpu_soc *dpu = fu->dpu;
+
+ switch (fu->id) {
+ case 0:
+ case 2:
+ return dpu->vs_priv[0];
+ case 1:
+ case 3:
+ return dpu->vs_priv[1];
+ default:
+ WARN_ON(1);
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(fetchdecode_get_vscaler);
+
+struct dpu_fetchunit *dpu_fd_get(struct dpu_soc *dpu, int id)
+{
+ struct dpu_fetchunit *fu;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fd_ids); i++)
+ if (fd_ids[i] == id)
+ break;
+
+ if (i == ARRAY_SIZE(fd_ids))
+ return ERR_PTR(-EINVAL);
+
+ fu = dpu->fd_priv[i];
+
+ mutex_lock(&fu->mutex);
+
+ if (fu->inuse) {
+ fu = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
+ fu->inuse = true;
+out:
+ mutex_unlock(&fu->mutex);
+
+ return fu;
+}
+EXPORT_SYMBOL_GPL(dpu_fd_get);
+
+void dpu_fd_put(struct dpu_fetchunit *fu)
+{
+ mutex_lock(&fu->mutex);
+
+ fu->inuse = false;
+
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_fd_put);
+
+static const struct dpu_fetchunit_ops fd_ops = {
+ .set_burstlength = fetchunit_set_burstlength,
+ .set_baseaddress = fetchdecode_set_baseaddress,
+ .set_src_bpp = fetchdecode_set_src_bpp,
+ .set_src_stride = fetchdecode_set_src_stride,
+ .set_src_buf_dimensions = fetchdecode_set_src_buf_dimensions,
+ .set_fmt = fetchdecode_set_fmt,
+ .enable_src_buf = fetchdecode_enable_src_buf,
+ .disable_src_buf = fetchdecode_disable_src_buf,
+ .is_enabled = fetchdecode_is_enabled,
+ .set_framedimensions = fetchdecode_set_framedimensions,
+ .set_controltrigger = fetchdecode_set_controltrigger,
+ .get_stream_id = fetchunit_get_stream_id,
+ .set_stream_id = fetchunit_set_stream_id,
+ .pin_off = fetchunit_pin_off,
+ .unpin_off = fetchunit_unpin_off,
+ .is_pinned_off = fetchunit_is_pinned_off,
+};
+
+void _dpu_fd_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_fetchunit *fu;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fd_ids); i++)
+ if (fd_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(fd_ids)))
+ return;
+
+ fu = dpu->fd_priv[i];
+
+ fetchdecode_pixengcfg_dynamic_src_sel(fu, FD_SRC_DISABLE);
+ fetchunit_baddr_autoupdate(fu, 0x0);
+ fetchunit_shden(fu, true);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, SETNUMBUFFERS(16) | SETBURSTLENGTH(16),
+ BURSTBUFFERMANAGEMENT);
+ mutex_unlock(&fu->mutex);
+}
+
+int dpu_fd_init(struct dpu_soc *dpu, unsigned int id,
+ unsigned long pec_base, unsigned long base)
+{
+ struct dpu_fetchdecode *fd;
+ struct dpu_fetchunit *fu;
+ int ret, i;
+
+ fd = devm_kzalloc(dpu->dev, sizeof(*fd), GFP_KERNEL);
+ if (!fd)
+ return -ENOMEM;
+
+ fu = &fd->fu;
+ dpu->fd_priv[id] = fu;
+
+ fu->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_16);
+ if (!fu->pec_base)
+ return -ENOMEM;
+
+ fu->base = devm_ioremap(dpu->dev, base, SZ_1K);
+ if (!fu->base)
+ return -ENOMEM;
+
+ fu->dpu = dpu;
+ fu->id = id;
+ fu->type = FU_T_FD;
+ fu->ops = &fd_ops;
+ fu->name = "fetchdecode";
+ for (i = 0; i < ARRAY_SIZE(fd_ids); i++) {
+ if (fd_ids[i] == id) {
+ fd->shdlreq = fd_shdlreqs[i];
+ break;
+ }
+ }
+ mutex_init(&fu->mutex);
+
+ ret = fetchdecode_pixengcfg_dynamic_src_sel(fu, FD_SRC_DISABLE);
+ if (ret < 0)
+ return ret;
+
+ ret = fetchdecode_fetchtype(fu, &fd->fetchtype);
+ if (ret < 0)
+ return ret;
+
+ _dpu_fd_init(dpu, id);
+
+ return 0;
+}
diff --git a/drivers/gpu/imx/dpu/dpu-fetcheco.c b/drivers/gpu/imx/dpu/dpu-fetcheco.c
new file mode 100644
index 000000000000..903fddc3e84b
--- /dev/null
+++ b/drivers/gpu/imx/dpu/dpu-fetcheco.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define BASEADDRESS0 0x10
+#define SOURCEBUFFERATTRIBUTES0 0x14
+#define SOURCEBUFFERDIMENSION0 0x18
+#define COLORCOMPONENTBITS0 0x1C
+#define COLORCOMPONENTSHIFT0 0x20
+#define LAYEROFFSET0 0x24
+#define CLIPWINDOWOFFSET0 0x28
+#define CLIPWINDOWDIMENSIONS0 0x2C
+#define CONSTANTCOLOR0 0x30
+#define LAYERPROPERTY0 0x34
+#define FRAMEDIMENSIONS 0x38
+#define FRAMERESAMPLING 0x3C
+#define CONTROL 0x40
+#define CONTROLTRIGGER 0x44
+#define START 0x48
+#define FETCHTYPE 0x4C
+#define BURSTBUFFERPROPERTIES 0x50
+#define HIDDENSTATUS 0x54
+
+struct dpu_fetcheco {
+ struct dpu_fetchunit fu;
+};
+
+static void
+fetcheco_set_src_buf_dimensions(struct dpu_fetchunit *fu,
+ unsigned int w, unsigned int h,
+ u32 fmt, bool deinterlace)
+{
+ int width, height;
+ u32 val;
+
+ if (deinterlace) {
+ width = w;
+ height = h / 2;
+ } else {
+ width = dpu_format_plane_width(w, fmt, 1);
+ height = dpu_format_plane_height(h, fmt, 1);
+ }
+
+ switch (fmt) {
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV61:
+ case DRM_FORMAT_NV24:
+ case DRM_FORMAT_NV42:
+ break;
+ default:
+ WARN(1, "Unsupported FetchEco pixel format 0x%08x\n", fmt);
+ return;
+ }
+
+ val = LINEWIDTH(width) | LINECOUNT(height);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, SOURCEBUFFERDIMENSION0);
+ mutex_unlock(&fu->mutex);
+}
+
+static void fetcheco_set_fmt(struct dpu_fetchunit *fu, u32 fmt, bool unused)
+{
+ u32 val, bits, shift;
+ int i, hsub, vsub;
+ unsigned int x, y;
+
+ switch (fmt) {
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV61:
+ case DRM_FORMAT_NV24:
+ case DRM_FORMAT_NV42:
+ break;
+ default:
+ WARN(1, "Unsupported FetchEco pixel format 0x%08x\n", fmt);
+ return;
+ }
+
+ hsub = dpu_format_horz_chroma_subsampling(fmt);
+ switch (hsub) {
+ case 1:
+ x = 0x4;
+ break;
+ case 2:
+ x = 0x2;
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ vsub = dpu_format_vert_chroma_subsampling(fmt);
+ switch (vsub) {
+ case 1:
+ y = 0x4;
+ break;
+ case 2:
+ y = 0x2;
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, FRAMERESAMPLING);
+ val &= ~(DELTAX_MASK | DELTAY_MASK);
+ val |= DELTAX(x) | DELTAY(y);
+ dpu_fu_write(fu, val, FRAMERESAMPLING);
+
+ val = dpu_fu_read(fu, CONTROL);
+ val &= ~RASTERMODE_MASK;
+ val |= RASTERMODE(RASTERMODE__NORMAL);
+ dpu_fu_write(fu, val, CONTROL);
+ mutex_unlock(&fu->mutex);
+
+ for (i = 0; i < ARRAY_SIZE(dpu_pixel_format_matrix); i++) {
+ if (dpu_pixel_format_matrix[i].pixel_format == fmt) {
+ bits = dpu_pixel_format_matrix[i].bits;
+ shift = dpu_pixel_format_matrix[i].shift;
+
+ bits &= ~Y_BITS_MASK;
+ shift &= ~Y_SHIFT_MASK;
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, bits, COLORCOMPONENTBITS0);
+ dpu_fu_write(fu, shift, COLORCOMPONENTSHIFT0);
+ mutex_unlock(&fu->mutex);
+ return;
+ }
+ }
+
+ WARN_ON(1);
+}
+
+void fetcheco_layeroffset(struct dpu_fetchunit *fu, unsigned int x,
+ unsigned int y)
+{
+ u32 val;
+
+ val = LAYERXOFFSET(x) | LAYERYOFFSET(y);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, LAYEROFFSET0);
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetcheco_layeroffset);
+
+void fetcheco_clipoffset(struct dpu_fetchunit *fu, unsigned int x,
+ unsigned int y)
+{
+ u32 val;
+
+ val = CLIPWINDOWXOFFSET(x) | CLIPWINDOWYOFFSET(y);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, CLIPWINDOWOFFSET0);
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetcheco_clipoffset);
+
+void fetcheco_clipdimensions(struct dpu_fetchunit *fu, unsigned int w,
+ unsigned int h)
+{
+ u32 val;
+
+ val = CLIPWINDOWWIDTH(w) | CLIPWINDOWHEIGHT(h);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, CLIPWINDOWDIMENSIONS0);
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetcheco_clipdimensions);
+
+static void
+fetcheco_set_framedimensions(struct dpu_fetchunit *fu,
+ unsigned int w, unsigned int h,
+ bool deinterlace)
+{
+ u32 val;
+
+ if (deinterlace)
+ h /= 2;
+
+ val = FRAMEWIDTH(w) | FRAMEHEIGHT(h);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, FRAMEDIMENSIONS);
+ mutex_unlock(&fu->mutex);
+}
+
+void fetcheco_frameresampling(struct dpu_fetchunit *fu, unsigned int x,
+ unsigned int y)
+{
+ u32 val;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, FRAMERESAMPLING);
+ val &= ~(DELTAX_MASK | DELTAY_MASK);
+ val |= DELTAX(x) | DELTAY(y);
+ dpu_fu_write(fu, val, FRAMERESAMPLING);
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetcheco_frameresampling);
+
+static void fetcheco_set_controltrigger(struct dpu_fetchunit *fu)
+{
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, SHDTOKGEN, CONTROLTRIGGER);
+ mutex_unlock(&fu->mutex);
+}
+
+int fetcheco_fetchtype(struct dpu_fetchunit *fu, fetchtype_t *type)
+{
+ struct dpu_soc *dpu = fu->dpu;
+ u32 val;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, FETCHTYPE);
+ val &= FETCHTYPE_MASK;
+ mutex_unlock(&fu->mutex);
+
+ switch (val) {
+ case FETCHTYPE__DECODE:
+ dev_dbg(dpu->dev, "FetchEco%d with RL and RLAD decoder\n",
+ fu->id);
+ break;
+ case FETCHTYPE__LAYER:
+ dev_dbg(dpu->dev, "FetchEco%d with fractional "
+ "plane(8 layers)\n", fu->id);
+ break;
+ case FETCHTYPE__WARP:
+ dev_dbg(dpu->dev, "FetchEco%d with arbitrary warping and "
+ "fractional plane(8 layers)\n", fu->id);
+ break;
+ case FETCHTYPE__ECO:
+ dev_dbg(dpu->dev, "FetchEco%d with minimum feature set for "
+ "alpha, chroma and coordinate planes\n",
+ fu->id);
+ break;
+ case FETCHTYPE__PERSP:
+ dev_dbg(dpu->dev, "FetchEco%d with affine, perspective and "
+ "arbitrary warping\n", fu->id);
+ break;
+ case FETCHTYPE__ROT:
+ dev_dbg(dpu->dev, "FetchEco%d with affine and arbitrary "
+ "warping\n", fu->id);
+ break;
+ case FETCHTYPE__DECODEL:
+ dev_dbg(dpu->dev, "FetchEco%d with RL and RLAD decoder, "
+ "reduced feature set\n", fu->id);
+ break;
+ case FETCHTYPE__LAYERL:
+ dev_dbg(dpu->dev, "FetchEco%d with fractional "
+ "plane(8 layers), reduced feature set\n",
+ fu->id);
+ break;
+ case FETCHTYPE__ROTL:
+ dev_dbg(dpu->dev, "FetchEco%d with affine and arbitrary "
+ "warping, reduced feature set\n", fu->id);
+ break;
+ default:
+ dev_warn(dpu->dev, "Invalid fetch type %u for FetchEco%d\n",
+ val, fu->id);
+ return -EINVAL;
+ }
+
+ *type = val;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fetcheco_fetchtype);
+
+dpu_block_id_t fetcheco_get_block_id(struct dpu_fetchunit *fu)
+{
+ switch (fu->id) {
+ case 0:
+ return ID_FETCHECO0;
+ case 1:
+ return ID_FETCHECO1;
+ case 2:
+ return ID_FETCHECO2;
+ case 9:
+ return ID_FETCHECO9;
+ default:
+ WARN_ON(1);
+ }
+
+ return ID_NONE;
+}
+EXPORT_SYMBOL_GPL(fetcheco_get_block_id);
+
+struct dpu_fetchunit *dpu_fe_get(struct dpu_soc *dpu, int id)
+{
+ struct dpu_fetchunit *fu;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fe_ids); i++)
+ if (fe_ids[i] == id)
+ break;
+
+ if (i == ARRAY_SIZE(fe_ids))
+ return ERR_PTR(-EINVAL);
+
+ fu = dpu->fe_priv[i];
+
+ mutex_lock(&fu->mutex);
+
+ if (fu->inuse) {
+ fu = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
+ fu->inuse = true;
+out:
+ mutex_unlock(&fu->mutex);
+
+ return fu;
+}
+EXPORT_SYMBOL_GPL(dpu_fe_get);
+
+void dpu_fe_put(struct dpu_fetchunit *fu)
+{
+ mutex_lock(&fu->mutex);
+
+ fu->inuse = false;
+
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_fe_put);
+
+static const struct dpu_fetchunit_ops fe_ops = {
+ .set_burstlength = fetchunit_set_burstlength,
+ .set_baseaddress = fetchunit_set_baseaddress,
+ .set_src_bpp = fetchunit_set_src_bpp,
+ .set_src_stride = fetchunit_set_src_stride,
+ .set_src_buf_dimensions = fetcheco_set_src_buf_dimensions,
+ .set_fmt = fetcheco_set_fmt,
+ .enable_src_buf = fetchunit_enable_src_buf,
+ .disable_src_buf = fetchunit_disable_src_buf,
+ .is_enabled = fetchunit_is_enabled,
+ .set_framedimensions = fetcheco_set_framedimensions,
+ .set_controltrigger = fetcheco_set_controltrigger,
+ .get_stream_id = fetchunit_get_stream_id,
+ .set_stream_id = fetchunit_set_stream_id,
+ .pin_off = fetchunit_pin_off,
+ .unpin_off = fetchunit_unpin_off,
+ .is_pinned_off = fetchunit_is_pinned_off,
+};
+
+void _dpu_fe_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_fetchunit *fu;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fe_ids); i++)
+ if (fe_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(fe_ids)))
+ return;
+
+ fu = dpu->fe_priv[i];
+
+ fetchunit_shden(fu, true);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, SETNUMBUFFERS(16) | SETBURSTLENGTH(16),
+ BURSTBUFFERMANAGEMENT);
+ mutex_unlock(&fu->mutex);
+}
+
+int dpu_fe_init(struct dpu_soc *dpu, unsigned int id,
+ unsigned long pec_base, unsigned long base)
+{
+ struct dpu_fetcheco *fe;
+ struct dpu_fetchunit *fu;
+ int i;
+
+ fe = devm_kzalloc(dpu->dev, sizeof(*fe), GFP_KERNEL);
+ if (!fe)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(fe_ids); i++)
+ if (fe_ids[i] == id)
+ break;
+
+ fu = &fe->fu;
+ dpu->fe_priv[i] = fu;
+
+ fu->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_16);
+ if (!fu->pec_base)
+ return -ENOMEM;
+
+ fu->base = devm_ioremap(dpu->dev, base, SZ_128);
+ if (!fu->base)
+ return -ENOMEM;
+
+ fu->dpu = dpu;
+ fu->id = id;
+ fu->type = FU_T_FE;
+ fu->ops = &fe_ops;
+ fu->name = "fetcheco";
+
+ mutex_init(&fu->mutex);
+
+ _dpu_fe_init(dpu, id);
+
+ return 0;
+}
diff --git a/drivers/gpu/imx/dpu/dpu-fetchlayer.c b/drivers/gpu/imx/dpu/dpu-fetchlayer.c
new file mode 100644
index 000000000000..15738a051fce
--- /dev/null
+++ b/drivers/gpu/imx/dpu/dpu-fetchlayer.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define PIXENGCFG_STATUS 0x8
+#define BASEADDRESS(n) (0x10 + (n) * 0x28)
+#define SOURCEBUFFERATTRIBUTES(n) (0x14 + (n) * 0x28)
+#define SOURCEBUFFERDIMENSION(n) (0x18 + (n) * 0x28)
+#define COLORCOMPONENTBITS(n) (0x1C + (n) * 0x28)
+#define COLORCOMPONENTSHIFT(n) (0x20 + (n) * 0x28)
+#define LAYEROFFSET(n) (0x24 + (n) * 0x28)
+#define CLIPWINDOWOFFSET(n) (0x28 + (n) * 0x28)
+#define CLIPWINDOWDIMENSIONS(n) (0x2C + (n) * 0x28)
+#define CONSTANTCOLOR(n) (0x30 + (n) * 0x28)
+#define LAYERPROPERTY(n) (0x34 + (n) * 0x28)
+#define FRAMEDIMENSIONS 0x150
+#define FRAMERESAMPLING 0x154
+#define CONTROL 0x158
+#define TRIGGERENABLE 0x15C
+#define SHDLDREQ(lm) ((lm) & 0xFF)
+#define CONTROLTRIGGER 0x160
+#define START 0x164
+#define FETCHTYPE 0x168
+#define BURSTBUFFERPROPERTIES 0x16C
+#define STATUS 0x170
+#define HIDDENSTATUS 0x174
+
+static const shadow_load_req_t fl_shdlreqs[] = {
+ SHLDREQID_FETCHLAYER0, SHLDREQID_FETCHLAYER1,
+};
+
+struct dpu_fetchlayer {
+ struct dpu_fetchunit fu;
+ fetchtype_t fetchtype;
+ shadow_load_req_t shdlreq;
+};
+
+static void
+fetchlayer_set_src_buf_dimensions(struct dpu_fetchunit *fu,
+ unsigned int w, unsigned int h,
+ u32 unused1, bool unused2)
+{
+ u32 val;
+
+ val = LINEWIDTH(w) | LINECOUNT(h);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, SOURCEBUFFERDIMENSION(fu->sub_id));
+ mutex_unlock(&fu->mutex);
+}
+
+static void fetchlayer_set_fmt(struct dpu_fetchunit *fu, u32 fmt, bool unused)
+{
+ u32 val, bits, shift;
+ int i, sub_id = fu->sub_id;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, LAYERPROPERTY(sub_id));
+ val &= ~YUVCONVERSIONMODE_MASK;
+ val |= YUVCONVERSIONMODE(YUVCONVERSIONMODE__OFF);
+ dpu_fu_write(fu, val, LAYERPROPERTY(sub_id));
+ mutex_unlock(&fu->mutex);
+
+ for (i = 0; i < ARRAY_SIZE(dpu_pixel_format_matrix); i++) {
+ if (dpu_pixel_format_matrix[i].pixel_format == fmt) {
+ bits = dpu_pixel_format_matrix[i].bits;
+ shift = dpu_pixel_format_matrix[i].shift;
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, bits, COLORCOMPONENTBITS(sub_id));
+ dpu_fu_write(fu, shift, COLORCOMPONENTSHIFT(sub_id));
+ mutex_unlock(&fu->mutex);
+ return;
+ }
+ }
+
+ WARN_ON(1);
+}
+
+static void
+fetchlayer_set_framedimensions(struct dpu_fetchunit *fu, unsigned int w,
+ unsigned int h, bool unused)
+{
+ u32 val;
+
+ val = FRAMEWIDTH(w) | FRAMEHEIGHT(h);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, FRAMEDIMENSIONS);
+ mutex_unlock(&fu->mutex);
+}
+
+void fetchlayer_rgb_constantcolor(struct dpu_fetchunit *fu,
+ u8 r, u8 g, u8 b, u8 a)
+{
+ u32 val;
+
+ val = rgb_color(r, g, b, a);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, CONSTANTCOLOR(fu->id));
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchlayer_rgb_constantcolor);
+
+void fetchlayer_yuv_constantcolor(struct dpu_fetchunit *fu, u8 y, u8 u, u8 v)
+{
+ u32 val;
+
+ val = yuv_color(y, u, v);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, CONSTANTCOLOR(fu->id));
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchlayer_yuv_constantcolor);
+
+static void fetchlayer_set_controltrigger(struct dpu_fetchunit *fu)
+{
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, SHDTOKGEN, CONTROLTRIGGER);
+ mutex_unlock(&fu->mutex);
+}
+
+int fetchlayer_fetchtype(struct dpu_fetchunit *fu, fetchtype_t *type)
+{
+ struct dpu_soc *dpu = fu->dpu;
+ u32 val;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, FETCHTYPE);
+ val &= FETCHTYPE_MASK;
+ mutex_unlock(&fu->mutex);
+
+ switch (val) {
+ case FETCHTYPE__DECODE:
+ dev_dbg(dpu->dev, "FetchLayer%d with RL and RLAD decoder\n",
+ fu->id);
+ break;
+ case FETCHTYPE__LAYER:
+ dev_dbg(dpu->dev, "FetchLayer%d with fractional "
+ "plane(8 layers)\n", fu->id);
+ break;
+ case FETCHTYPE__WARP:
+ dev_dbg(dpu->dev, "FetchLayer%d with arbitrary warping and "
+ "fractional plane(8 layers)\n", fu->id);
+ break;
+ case FETCHTYPE__ECO:
+ dev_dbg(dpu->dev, "FetchLayer%d with minimum feature set for "
+ "alpha, chroma and coordinate planes\n",
+ fu->id);
+ break;
+ case FETCHTYPE__PERSP:
+ dev_dbg(dpu->dev, "FetchLayer%d with affine, perspective and "
+ "arbitrary warping\n", fu->id);
+ break;
+ case FETCHTYPE__ROT:
+ dev_dbg(dpu->dev, "FetchLayer%d with affine and arbitrary "
+ "warping\n", fu->id);
+ break;
+ case FETCHTYPE__DECODEL:
+ dev_dbg(dpu->dev, "FetchLayer%d with RL and RLAD decoder, "
+ "reduced feature set\n", fu->id);
+ break;
+ case FETCHTYPE__LAYERL:
+ dev_dbg(dpu->dev, "FetchLayer%d with fractional "
+ "plane(8 layers), reduced feature set\n",
+ fu->id);
+ break;
+ case FETCHTYPE__ROTL:
+ dev_dbg(dpu->dev, "FetchLayer%d with affine and arbitrary "
+ "warping, reduced feature set\n", fu->id);
+ break;
+ default:
+ dev_warn(dpu->dev, "Invalid fetch type %u for FetchLayer%d\n",
+ val, fu->id);
+ return -EINVAL;
+ }
+
+ *type = val;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fetchlayer_fetchtype);
+
+struct dpu_fetchunit *dpu_fl_get(struct dpu_soc *dpu, int id)
+{
+ struct dpu_fetchunit *fu;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fl_ids); i++)
+ if (fl_ids[i] == id)
+ break;
+
+ if (i == ARRAY_SIZE(fl_ids))
+ return ERR_PTR(-EINVAL);
+
+ fu = dpu->fl_priv[i];
+
+ mutex_lock(&fu->mutex);
+
+ if (fu->inuse) {
+ fu = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
+ fu->inuse = true;
+out:
+ mutex_unlock(&fu->mutex);
+
+ return fu;
+}
+EXPORT_SYMBOL_GPL(dpu_fl_get);
+
+void dpu_fl_put(struct dpu_fetchunit *fu)
+{
+ mutex_lock(&fu->mutex);
+
+ fu->inuse = false;
+
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_fl_put);
+
+static const struct dpu_fetchunit_ops fl_ops = {
+ .set_burstlength = fetchunit_set_burstlength,
+ .set_baseaddress = fetchunit_set_baseaddress,
+ .set_src_bpp = fetchunit_set_src_bpp,
+ .set_src_stride = fetchunit_set_src_stride,
+ .set_src_buf_dimensions = fetchlayer_set_src_buf_dimensions,
+ .set_fmt = fetchlayer_set_fmt,
+ .enable_src_buf = fetchunit_enable_src_buf,
+ .disable_src_buf = fetchunit_disable_src_buf,
+ .is_enabled = fetchunit_is_enabled,
+ .set_framedimensions = fetchlayer_set_framedimensions,
+ .set_controltrigger = fetchlayer_set_controltrigger,
+ .get_stream_id = fetchunit_get_stream_id,
+ .set_stream_id = fetchunit_set_stream_id,
+ .pin_off = fetchunit_pin_off,
+ .unpin_off = fetchunit_unpin_off,
+ .is_pinned_off = fetchunit_is_pinned_off,
+};
+
+void _dpu_fl_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_fetchunit *fu;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fl_ids); i++)
+ if (fl_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(fl_ids)))
+ return;
+
+ fu = dpu->fl_priv[i];
+
+ fetchunit_baddr_autoupdate(fu, 0x0);
+ fetchunit_shden(fu, true);
+ fetchunit_shdldreq_sticky(fu, 0xFF);
+ fetchunit_disable_src_buf(fu);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, SETNUMBUFFERS(16) | SETBURSTLENGTH(16),
+ BURSTBUFFERMANAGEMENT);
+ mutex_unlock(&fu->mutex);
+}
+
+int dpu_fl_init(struct dpu_soc *dpu, unsigned int id,
+ unsigned long pec_base, unsigned long base)
+{
+ struct dpu_fetchlayer *fl;
+ struct dpu_fetchunit *fu;
+ int ret, i;
+
+ fl = devm_kzalloc(dpu->dev, sizeof(*fl), GFP_KERNEL);
+ if (!fl)
+ return -ENOMEM;
+
+ fu = &fl->fu;
+ dpu->fl_priv[id] = fu;
+
+ fu->pec_base = devm_ioremap(dpu->dev, base, SZ_16);
+ if (!fu->pec_base)
+ return -ENOMEM;
+
+ fu->base = devm_ioremap(dpu->dev, base, SZ_512);
+ if (!fu->base)
+ return -ENOMEM;
+
+ fu->dpu = dpu;
+ fu->id = id;
+ fu->sub_id = 0;
+ fu->type = FU_T_FL;
+ fu->ops = &fl_ops;
+ fu->name = "fetchlayer";
+ for (i = 0; i < ARRAY_SIZE(fl_ids); i++) {
+ if (fl_ids[i] == id) {
+ fl->shdlreq = fl_shdlreqs[i];
+ break;
+ }
+ }
+ mutex_init(&fu->mutex);
+
+ ret = fetchlayer_fetchtype(fu, &fl->fetchtype);
+ if (ret < 0)
+ return ret;
+
+ _dpu_fl_init(dpu, id);
+
+ return 0;
+}
diff --git a/drivers/gpu/imx/dpu/dpu-fetchunit.c b/drivers/gpu/imx/dpu/dpu-fetchunit.c
new file mode 100644
index 000000000000..b482b2e75e7f
--- /dev/null
+++ b/drivers/gpu/imx/dpu/dpu-fetchunit.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define BASEADDRESS(n) (0x10 + (n) * 0x28)
+#define SOURCEBUFFERATTRIBUTES(n) (0x14 + (n) * 0x28)
+#define SOURCEBUFFERDIMENSION(n) (0x18 + (n) * 0x28)
+#define COLORCOMPONENTBITS(n) (0x1C + (n) * 0x28)
+#define COLORCOMPONENTSHIFT(n) (0x20 + (n) * 0x28)
+#define LAYEROFFSET(n) (0x24 + (n) * 0x28)
+#define CLIPWINDOWOFFSET(n) (0x28 + (n) * 0x28)
+#define CLIPWINDOWDIMENSIONS(n) (0x2C + (n) * 0x28)
+#define CONSTANTCOLOR(n) (0x30 + (n) * 0x28)
+#define LAYERPROPERTY(n) (0x34 + (n) * 0x28)
+
+void fetchunit_get_dprc(struct dpu_fetchunit *fu, void *data)
+{
+ if (WARN_ON(!fu))
+ return;
+
+ fu->dprc = data;
+}
+EXPORT_SYMBOL_GPL(fetchunit_get_dprc);
+
+void fetchunit_shden(struct dpu_fetchunit *fu, bool enable)
+{
+ u32 val;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, STATICCONTROL);
+ if (enable)
+ val |= SHDEN;
+ else
+ val &= ~SHDEN;
+ dpu_fu_write(fu, val, STATICCONTROL);
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_shden);
+
+void fetchunit_baddr_autoupdate(struct dpu_fetchunit *fu, u8 layer_mask)
+{
+ u32 val;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, STATICCONTROL);
+ val &= ~BASEADDRESSAUTOUPDATE_MASK;
+ val |= BASEADDRESSAUTOUPDATE(layer_mask);
+ dpu_fu_write(fu, val, STATICCONTROL);
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_baddr_autoupdate);
+
+void fetchunit_shdldreq_sticky(struct dpu_fetchunit *fu, u8 layer_mask)
+{
+ u32 val;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, STATICCONTROL);
+ val &= ~SHDLDREQSTICKY_MASK;
+ val |= SHDLDREQSTICKY(layer_mask);
+ dpu_fu_write(fu, val, STATICCONTROL);
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_shdldreq_sticky);
+
+void fetchunit_set_burstlength(struct dpu_fetchunit *fu,
+ unsigned int x_offset, unsigned int mt_w,
+ int bpp, dma_addr_t baddr, bool use_prefetch)
+{
+ struct dpu_soc *dpu = fu->dpu;
+ unsigned int burst_size, burst_length;
+ bool nonzero_mod = !!mt_w;
+ u32 val;
+
+ if (use_prefetch) {
+ /* consider PRG x offset to calculate buffer address */
+ if (nonzero_mod)
+ baddr += (x_offset % mt_w) * (bpp / 8);
+
+ /*
+ * address TKT343664:
+ * fetch unit base address has to align to burst size
+ */
+ burst_size = 1 << (ffs(baddr) - 1);
+ burst_size = round_up(burst_size, 8);
+ burst_size = min(burst_size, 128U);
+ burst_length = burst_size / 8;
+ } else {
+ burst_length = 16;
+ }
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, BURSTBUFFERMANAGEMENT);
+ val &= ~SETBURSTLENGTH_MASK;
+ val |= SETBURSTLENGTH(burst_length);
+ dpu_fu_write(fu, val, BURSTBUFFERMANAGEMENT);
+ mutex_unlock(&fu->mutex);
+
+ dev_dbg(dpu->dev, "%s%d burst length is %u\n",
+ fu->name, fu->id, burst_length);
+}
+EXPORT_SYMBOL_GPL(fetchunit_set_burstlength);
+
+void fetchunit_set_baseaddress(struct dpu_fetchunit *fu, unsigned int width,
+ unsigned int x_offset, unsigned int y_offset,
+ unsigned int mt_w, unsigned int mt_h,
+ int bpp, dma_addr_t baddr)
+{
+ unsigned int burst_size, stride;
+ bool nonzero_mod = !!mt_w;
+
+ if (nonzero_mod) {
+ /* consider PRG x offset to calculate buffer address */
+ baddr += (x_offset % mt_w) * (bpp / 8);
+
+ /*
+ * address TKT343664:
+ * fetch unit base address has to align to burst size
+ */
+ burst_size = 1 << (ffs(baddr) - 1);
+ burst_size = round_up(burst_size, 8);
+ burst_size = min(burst_size, 128U);
+
+ stride = width * (bpp >> 3);
+ /*
+ * address TKT339017:
+ * fixup for burst size vs stride mismatch
+ */
+ stride = round_up(stride + round_up(baddr % 8, 8), burst_size);
+
+ /* consider PRG y offset to calculate buffer address */
+ baddr += (y_offset % mt_h) * stride;
+ }
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, baddr, BASEADDRESS(fu->sub_id));
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_set_baseaddress);
+
+void fetchunit_set_src_bpp(struct dpu_fetchunit *fu, int bpp)
+{
+ u32 val;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, SOURCEBUFFERATTRIBUTES(fu->sub_id));
+ val &= ~0x3f0000;
+ val |= BITSPERPIXEL(bpp);
+ dpu_fu_write(fu, val, SOURCEBUFFERATTRIBUTES(fu->sub_id));
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_set_src_bpp);
+
+/*
+ * The arguments width and bpp are valid only when use_prefetch is true.
+ * For fetcheco, since the pixel format has to be NV12 or NV21 when
+ * use_prefetch is true, we assume width stands for how many UV we have
+ * in bytes for one line, while bpp should be 8bits for every U or V component.
+ */
+void fetchunit_set_src_stride(struct dpu_fetchunit *fu,
+ unsigned int width, unsigned int x_offset,
+ unsigned int mt_w, int bpp, unsigned int stride,
+ dma_addr_t baddr, bool use_prefetch)
+{
+ unsigned int burst_size;
+ bool nonzero_mod = !!mt_w;
+ u32 val;
+
+ if (use_prefetch) {
+ /* consider PRG x offset to calculate buffer address */
+ if (nonzero_mod)
+ baddr += (x_offset % mt_w) * (bpp / 8);
+
+ /*
+ * address TKT343664:
+ * fetch unit base address has to align to burst size
+ */
+ burst_size = 1 << (ffs(baddr) - 1);
+ burst_size = round_up(burst_size, 8);
+ burst_size = min(burst_size, 128U);
+
+ stride = width * (bpp >> 3);
+ /*
+ * address TKT339017:
+ * fixup for burst size vs stride mismatch
+ */
+ if (nonzero_mod)
+ stride = round_up(stride + round_up(baddr % 8, 8),
+ burst_size);
+ else
+ stride = round_up(stride, burst_size);
+ }
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, SOURCEBUFFERATTRIBUTES(fu->sub_id));
+ val &= ~0xffff;
+ val |= STRIDE(stride);
+ dpu_fu_write(fu, val, SOURCEBUFFERATTRIBUTES(fu->sub_id));
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_set_src_stride);
+
+void fetchunit_enable_src_buf(struct dpu_fetchunit *fu)
+{
+ u32 val;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, LAYERPROPERTY(fu->sub_id));
+ val |= SOURCEBUFFERENABLE;
+ dpu_fu_write(fu, val, LAYERPROPERTY(fu->sub_id));
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_enable_src_buf);
+
+void fetchunit_disable_src_buf(struct dpu_fetchunit *fu)
+{
+ u32 val;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, LAYERPROPERTY(fu->sub_id));
+ val &= ~SOURCEBUFFERENABLE;
+ dpu_fu_write(fu, val, LAYERPROPERTY(fu->sub_id));
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchunit_disable_src_buf);
+
+bool fetchunit_is_enabled(struct dpu_fetchunit *fu)
+{
+ u32 val;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, LAYERPROPERTY(fu->sub_id));
+ mutex_unlock(&fu->mutex);
+
+ return !!(val & SOURCEBUFFERENABLE);
+}
+EXPORT_SYMBOL_GPL(fetchunit_is_enabled);
+
+unsigned int fetchunit_get_stream_id(struct dpu_fetchunit *fu)
+{
+ if (WARN_ON(!fu))
+ return DPU_PLANE_SRC_DISABLED;
+
+ return fu->stream_id;
+}
+EXPORT_SYMBOL_GPL(fetchunit_get_stream_id);
+
+void fetchunit_set_stream_id(struct dpu_fetchunit *fu, unsigned int id)
+{
+ if (WARN_ON(!fu))
+ return;
+
+ switch (id) {
+ case DPU_PLANE_SRC_TO_DISP_STREAM0:
+ case DPU_PLANE_SRC_TO_DISP_STREAM1:
+ case DPU_PLANE_SRC_DISABLED:
+ fu->stream_id = id;
+ break;
+ default:
+ WARN_ON(1);
+ }
+}
+EXPORT_SYMBOL_GPL(fetchunit_set_stream_id);
+
+void fetchunit_pin_off(struct dpu_fetchunit *fu)
+{
+ if (WARN_ON(!fu))
+ return;
+
+ fu->pin_off = true;
+}
+EXPORT_SYMBOL_GPL(fetchunit_pin_off);
+
+void fetchunit_unpin_off(struct dpu_fetchunit *fu)
+{
+ if (WARN_ON(!fu))
+ return;
+
+ fu->pin_off = false;
+}
+EXPORT_SYMBOL_GPL(fetchunit_unpin_off);
+
+bool fetchunit_is_pinned_off(struct dpu_fetchunit *fu)
+{
+ if (WARN_ON(!fu))
+ return false;
+
+ return fu->pin_off;
+}
+EXPORT_SYMBOL_GPL(fetchunit_is_pinned_off);
+
+bool fetchunit_is_fetchdecode(struct dpu_fetchunit *fu)
+{
+ if (WARN_ON(!fu))
+ return false;
+
+ return fu->type == FU_T_FD;
+}
+EXPORT_SYMBOL_GPL(fetchunit_is_fetchdecode);
+
+bool fetchunit_is_fetcheco(struct dpu_fetchunit *fu)
+{
+ if (WARN_ON(!fu))
+ return false;
+
+ return fu->type == FU_T_FE;
+}
+EXPORT_SYMBOL_GPL(fetchunit_is_fetcheco);
+
+bool fetchunit_is_fetchlayer(struct dpu_fetchunit *fu)
+{
+ if (WARN_ON(!fu))
+ return false;
+
+ return fu->type == FU_T_FL;
+}
+EXPORT_SYMBOL_GPL(fetchunit_is_fetchlayer);
+
+bool fetchunit_is_fetchwarp(struct dpu_fetchunit *fu)
+{
+ if (WARN_ON(!fu))
+ return false;
+
+ return fu->type == FU_T_FW;
+}
+EXPORT_SYMBOL_GPL(fetchunit_is_fetchwarp);
diff --git a/drivers/gpu/imx/dpu/dpu-fetchwarp.c b/drivers/gpu/imx/dpu/dpu-fetchwarp.c
new file mode 100644
index 000000000000..673c738da8a7
--- /dev/null
+++ b/drivers/gpu/imx/dpu/dpu-fetchwarp.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define PIXENGCFG_STATUS 0x8
+#define BASEADDRESS(n) (0x10 + (n) * 0x28)
+#define SOURCEBUFFERATTRIBUTES(n) (0x14 + (n) * 0x28)
+#define SOURCEBUFFERDIMENSION(n) (0x18 + (n) * 0x28)
+#define COLORCOMPONENTBITS(n) (0x1C + (n) * 0x28)
+#define COLORCOMPONENTSHIFT(n) (0x20 + (n) * 0x28)
+#define LAYEROFFSET(n) (0x24 + (n) * 0x28)
+#define CLIPWINDOWOFFSET(n) (0x28 + (n) * 0x28)
+#define CLIPWINDOWDIMENSIONS(n) (0x2C + (n) * 0x28)
+#define CONSTANTCOLOR(n) (0x30 + (n) * 0x28)
+#define LAYERPROPERTY(n) (0x34 + (n) * 0x28)
+#define FRAMEDIMENSIONS 0x150
+#define FRAMERESAMPLING 0x154
+#define WARPCONTROL 0x158
+#define ARBSTARTX 0x15c
+#define ARBSTARTY 0x160
+#define ARBDELTA 0x164
+#define FIRPOSITIONS 0x168
+#define FIRCOEFFICIENTS 0x16c
+#define CONTROL 0x170
+#define TRIGGERENABLE 0x174
+#define SHDLDREQ(lm) ((lm) & 0xFF)
+#define CONTROLTRIGGER 0x178
+#define START 0x17c
+#define FETCHTYPE 0x180
+#define BURSTBUFFERPROPERTIES 0x184
+#define STATUS 0x188
+#define HIDDENSTATUS 0x18c
+
+struct dpu_fetchwarp {
+ struct dpu_fetchunit fu;
+ fetchtype_t fetchtype;
+};
+
+static void
+fetchwarp_set_src_buf_dimensions(struct dpu_fetchunit *fu,
+ unsigned int w, unsigned int h,
+ u32 unused1, bool unused2)
+{
+ u32 val;
+
+ val = LINEWIDTH(w) | LINECOUNT(h);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, SOURCEBUFFERDIMENSION(fu->sub_id));
+ mutex_unlock(&fu->mutex);
+}
+
+static void fetchwarp_set_fmt(struct dpu_fetchunit *fu,
+ u32 fmt, bool unused)
+{
+ u32 val, bits, shift;
+ int i, sub_id = fu->sub_id;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, LAYERPROPERTY(sub_id));
+ val &= ~YUVCONVERSIONMODE_MASK;
+ dpu_fu_write(fu, val, LAYERPROPERTY(sub_id));
+ mutex_unlock(&fu->mutex);
+
+ for (i = 0; i < ARRAY_SIZE(dpu_pixel_format_matrix); i++) {
+ if (dpu_pixel_format_matrix[i].pixel_format == fmt) {
+ bits = dpu_pixel_format_matrix[i].bits;
+ shift = dpu_pixel_format_matrix[i].shift;
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, bits, COLORCOMPONENTBITS(sub_id));
+ dpu_fu_write(fu, shift, COLORCOMPONENTSHIFT(sub_id));
+ mutex_unlock(&fu->mutex);
+ return;
+ }
+ }
+
+ WARN_ON(1);
+}
+
+static void
+fetchwarp_set_framedimensions(struct dpu_fetchunit *fu,
+ unsigned int w, unsigned int h, bool unused)
+{
+ u32 val;
+
+ val = FRAMEWIDTH(w) | FRAMEHEIGHT(h);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, FRAMEDIMENSIONS);
+ mutex_unlock(&fu->mutex);
+}
+
+void fetchwarp_rgb_constantcolor(struct dpu_fetchunit *fu,
+ u8 r, u8 g, u8 b, u8 a)
+{
+ u32 val;
+
+ val = rgb_color(r, g, b, a);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, CONSTANTCOLOR(fu->id));
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchwarp_rgb_constantcolor);
+
+void fetchwarp_yuv_constantcolor(struct dpu_fetchunit *fu, u8 y, u8 u, u8 v)
+{
+ u32 val;
+
+ val = yuv_color(y, u, v);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, val, CONSTANTCOLOR(fu->id));
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(fetchwarp_yuv_constantcolor);
+
+static void fetchwarp_set_controltrigger(struct dpu_fetchunit *fu)
+{
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, SHDTOKGEN, CONTROLTRIGGER);
+ mutex_unlock(&fu->mutex);
+}
+
+int fetchwarp_fetchtype(struct dpu_fetchunit *fu, fetchtype_t *type)
+{
+ struct dpu_soc *dpu = fu->dpu;
+ u32 val;
+
+ mutex_lock(&fu->mutex);
+ val = dpu_fu_read(fu, FETCHTYPE);
+ val &= FETCHTYPE_MASK;
+ mutex_unlock(&fu->mutex);
+
+ switch (val) {
+ case FETCHTYPE__DECODE:
+ dev_dbg(dpu->dev, "FetchWarp%d with RL and RLAD decoder\n",
+ fu->id);
+ break;
+ case FETCHTYPE__LAYER:
+ dev_dbg(dpu->dev, "FetchWarp%d with fractional "
+ "plane(8 layers)\n", fu->id);
+ break;
+ case FETCHTYPE__WARP:
+ dev_dbg(dpu->dev, "FetchWarp%d with arbitrary warping and "
+ "fractional plane(8 layers)\n", fu->id);
+ break;
+ case FETCHTYPE__ECO:
+ dev_dbg(dpu->dev, "FetchWarp%d with minimum feature set for "
+ "alpha, chroma and coordinate planes\n",
+ fu->id);
+ break;
+ case FETCHTYPE__PERSP:
+ dev_dbg(dpu->dev, "FetchWarp%d with affine, perspective and "
+ "arbitrary warping\n", fu->id);
+ break;
+ case FETCHTYPE__ROT:
+ dev_dbg(dpu->dev, "FetchWarp%d with affine and arbitrary "
+ "warping\n", fu->id);
+ break;
+ case FETCHTYPE__DECODEL:
+ dev_dbg(dpu->dev, "FetchWarp%d with RL and RLAD decoder, "
+ "reduced feature set\n", fu->id);
+ break;
+ case FETCHTYPE__LAYERL:
+ dev_dbg(dpu->dev, "FetchWarp%d with fractional "
+ "plane(8 layers), reduced feature set\n",
+ fu->id);
+ break;
+ case FETCHTYPE__ROTL:
+ dev_dbg(dpu->dev, "FetchWarp%d with affine and arbitrary "
+ "warping, reduced feature set\n", fu->id);
+ break;
+ default:
+ dev_warn(dpu->dev, "Invalid fetch type %u for FetchWarp%d\n",
+ val, fu->id);
+ return -EINVAL;
+ }
+
+ *type = val;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fetchwarp_fetchtype);
+
+struct dpu_fetchunit *dpu_fw_get(struct dpu_soc *dpu, int id)
+{
+ struct dpu_fetchunit *fu;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fw_ids); i++)
+ if (fw_ids[i] == id)
+ break;
+
+ if (i == ARRAY_SIZE(fw_ids))
+ return ERR_PTR(-EINVAL);
+
+ fu = dpu->fw_priv[i];
+
+ mutex_lock(&fu->mutex);
+
+ if (fu->inuse) {
+ fu = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
+ fu->inuse = true;
+out:
+ mutex_unlock(&fu->mutex);
+
+ return fu;
+}
+EXPORT_SYMBOL_GPL(dpu_fw_get);
+
+void dpu_fw_put(struct dpu_fetchunit *fu)
+{
+ mutex_lock(&fu->mutex);
+
+ fu->inuse = false;
+
+ mutex_unlock(&fu->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_fw_put);
+
+static const struct dpu_fetchunit_ops fw_ops = {
+ .set_burstlength = fetchunit_set_burstlength,
+ .set_baseaddress = fetchunit_set_baseaddress,
+ .set_src_bpp = fetchunit_set_src_bpp,
+ .set_src_stride = fetchunit_set_src_stride,
+ .set_src_buf_dimensions = fetchwarp_set_src_buf_dimensions,
+ .set_fmt = fetchwarp_set_fmt,
+ .enable_src_buf = fetchunit_enable_src_buf,
+ .disable_src_buf = fetchunit_disable_src_buf,
+ .is_enabled = fetchunit_is_enabled,
+ .set_framedimensions = fetchwarp_set_framedimensions,
+ .set_controltrigger = fetchwarp_set_controltrigger,
+ .get_stream_id = fetchunit_get_stream_id,
+ .set_stream_id = fetchunit_set_stream_id,
+ .pin_off = fetchunit_pin_off,
+ .unpin_off = fetchunit_unpin_off,
+ .is_pinned_off = fetchunit_is_pinned_off,
+};
+
+void _dpu_fw_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_fetchunit *fu;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fw_ids); i++)
+ if (fw_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(fw_ids)))
+ return;
+
+ fu = dpu->fw_priv[i];
+
+ fetchunit_baddr_autoupdate(fu, 0x0);
+ fetchunit_shden(fu, true);
+ fetchunit_shdldreq_sticky(fu, 0xFF);
+ fetchunit_disable_src_buf(fu);
+
+ mutex_lock(&fu->mutex);
+ dpu_fu_write(fu, SETNUMBUFFERS(16) | SETBURSTLENGTH(16),
+ BURSTBUFFERMANAGEMENT);
+ mutex_unlock(&fu->mutex);
+}
+
+int dpu_fw_init(struct dpu_soc *dpu, unsigned int id,
+ unsigned long pec_base, unsigned long base)
+{
+ struct dpu_fetchwarp *fw;
+ struct dpu_fetchunit *fu;
+ int i, ret;
+
+ fw = devm_kzalloc(dpu->dev, sizeof(*fw), GFP_KERNEL);
+ if (!fw)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(fw_ids); i++)
+ if (fw_ids[i] == id)
+ break;
+
+ fu = &fw->fu;
+ dpu->fw_priv[i] = fu;
+
+ fu->pec_base = devm_ioremap(dpu->dev, base, SZ_16);
+ if (!fu->pec_base)
+ return -ENOMEM;
+
+ fu->base = devm_ioremap(dpu->dev, base, SZ_512);
+ if (!fu->base)
+ return -ENOMEM;
+
+ fu->dpu = dpu;
+ fu->id = id;
+ fu->sub_id = 0;
+ fu->type = FU_T_FW;
+ fu->ops = &fw_ops;
+ fu->name = "fetchwarp";
+
+ mutex_init(&fu->mutex);
+
+ ret = fetchwarp_fetchtype(fu, &fw->fetchtype);
+ if (ret < 0)
+ return ret;
+
+ _dpu_fw_init(dpu, id);
+
+ return 0;
+}
diff --git a/drivers/gpu/imx/dpu/dpu-framegen.c b/drivers/gpu/imx/dpu/dpu-framegen.c
new file mode 100644
index 000000000000..981aefe96488
--- /dev/null
+++ b/drivers/gpu/imx/dpu/dpu-framegen.c
@@ -0,0 +1,618 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <soc/imx8/sc/sci.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define FGSTCTRL 0x8
+#define FGSYNCMODE_MASK 0x6
+typedef enum {
+ /* No side-by-side synchronization. */
+ FGSYNCMODE__OFF = 0,
+ /* Framegen is master. */
+ FGSYNCMODE__MASTER = 1 << 1,
+ /* Runs in cyclic synchronization mode. */
+ FGSYNCMODE__SLAVE_CYC = 2 << 1,
+ /* Runs in one time synchronization mode. */
+ FGSYNCMODE__SLAVE_ONCE = 3 << 1,
+} fgsyncmode_t;
+#define HTCFG1 0xC
+#define HTOTAL(n) ((((n) - 1) & 0x3FFF) << 16)
+#define HACT(n) ((n) & 0x3FFF)
+#define HTCFG2 0x10
+#define HSEN BIT(31)
+#define HSBP(n) ((((n) - 1) & 0x3FFF) << 16)
+#define HSYNC(n) (((n) - 1) & 0x3FFF)
+#define VTCFG1 0x14
+#define VTOTAL(n) ((((n) - 1) & 0x3FFF) << 16)
+#define VACT(n) ((n) & 0x3FFF)
+#define VTCFG2 0x18
+#define VSEN BIT(31)
+#define VSBP(n) ((((n) - 1) & 0x3FFF) << 16)
+#define VSYNC(n) (((n) - 1) & 0x3FFF)
+#define INTCONFIG(n) (0x1C + 4 * (n))
+#define EN BIT(31)
+#define ROW(n) (((n) & 0x3FFF) << 16)
+#define COL(n) ((n) & 0x3FFF)
+#define PKICKCONFIG 0x2C
+#define SKICKCONFIG 0x30
+#define SECSTATCONFIG 0x34
+#define FGSRCR1 0x38
+#define FGSRCR2 0x3C
+#define FGSRCR3 0x40
+#define FGSRCR4 0x44
+#define FGSRCR5 0x48
+#define FGSRCR6 0x4C
+#define FGKSDR 0x50
+#define PACFG 0x54
+#define STARTX(n) (((n) + 1) & 0x3FFF)
+#define STARTY(n) (((((n) + 1) & 0x3FFF)) << 16)
+#define SACFG 0x58
+#define FGINCTRL 0x5C
+#define FGDM_MASK 0x7
+#define ENPRIMALPHA BIT(3)
+#define ENSECALPHA BIT(4)
+#define FGINCTRLPANIC 0x60
+#define FGCCR 0x64
+#define CCALPHA(a) (((a) & 0x1) << 30)
+#define CCRED(r) (((r) & 0x3FF) << 20)
+#define CCGREEN(g) (((g) & 0x3FF) << 10)
+#define CCBLUE(b) ((b) & 0x3FF)
+#define FGENABLE 0x68
+#define FGEN BIT(0)
+#define FGSLR 0x6C
+#define FGENSTS 0x70
+#define ENSTS BIT(0)
+#define FGTIMESTAMP 0x74
+#define LINEINDEX_MASK 0x3FFF
+#define LINEINDEX_SHIFT 0
+#define FRAMEINDEX_MASK 0xFFFFC000
+#define FRAMEINDEX_SHIFT 14
+#define FGCHSTAT 0x78
+#define FGCHSTATCLR 0x7C
+#define FGSKEWMON 0x80
+#define FGSFIFOMIN 0x84
+#define FGSFIFOMAX 0x88
+#define FGSFIFOFILLCLR 0x8C
+#define FGSREPD 0x90
+#define FGSRFTD 0x94
+
+#define KHZ 1000
+#define PLL_MIN_FREQ_HZ 648000000
+
+struct dpu_framegen {
+ void __iomem *base;
+ struct clk *clk_pll;
+ struct clk *clk_bypass;
+ struct clk *clk_disp_sel;
+ struct clk *clk_disp;
+ struct mutex mutex;
+ int id;
+ bool inuse;
+ bool use_bypass_clk;
+ bool encoder_type_has_lvds;
+ struct dpu_soc *dpu;
+};
+
+static inline u32 dpu_fg_read(struct dpu_framegen *fg, unsigned int offset)
+{
+ return readl(fg->base + offset);
+}
+
+static inline void dpu_fg_write(struct dpu_framegen *fg, u32 value,
+ unsigned int offset)
+{
+ writel(value, fg->base + offset);
+}
+
+/* FIXME: enable pixel link in a proper manner */
+static void dpu_pixel_link_enable(int dpu_id, int stream_id)
+{
+ sc_err_t sciErr;
+ sc_ipc_t ipcHndl = 0;
+ u32 mu_id;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("Cannot obtain MU ID\n");
+ return;
+ }
+
+ sciErr = sc_ipc_open(&ipcHndl, mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return;
+ }
+
+ if (dpu_id == 0) {
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0,
+ stream_id ? SC_C_PXL_LINK_MST2_ENB : SC_C_PXL_LINK_MST1_ENB, 1);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_PXL_LINK_MST%d_ENB sc_misc_set_control failed! (sciError = %d)\n", stream_id + 1, sciErr);
+ } else if (dpu_id == 1) {
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1,
+ stream_id ? SC_C_PXL_LINK_MST2_ENB : SC_C_PXL_LINK_MST1_ENB, 1);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_PXL_LINK_MST%d_ENB sc_misc_set_control failed! (sciError = %d)\n", stream_id + 1, sciErr);
+ }
+
+ sc_ipc_close(mu_id);
+}
+
+/* FIXME: disable pixel link in a proper manner */
+static void dpu_pixel_link_disable(int dpu_id, int stream_id)
+{
+ sc_err_t sciErr;
+ sc_ipc_t ipcHndl = 0;
+ u32 mu_id;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("Cannot obtain MU ID\n");
+ return;
+ }
+
+ sciErr = sc_ipc_open(&ipcHndl, mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return;
+ }
+
+ if (dpu_id == 0) {
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0,
+ stream_id ? SC_C_PXL_LINK_MST2_ENB : SC_C_PXL_LINK_MST1_ENB, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_PXL_LINK_MST%d_ENB sc_misc_set_control failed! (sciError = %d)\n", stream_id + 1, sciErr);
+ } else if (dpu_id == 1) {
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1,
+ stream_id ? SC_C_PXL_LINK_MST2_ENB : SC_C_PXL_LINK_MST1_ENB, 0);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_PXL_LINK_MST%d_ENB sc_misc_set_control failed! (sciError = %d)\n", stream_id + 1, sciErr);
+ }
+
+ sc_ipc_close(mu_id);
+}
+
+/* FIXME: set MST address for pixel link in a proper manner */
+static void dpu_pixel_link_set_mst_addr(int dpu_id, int stream_id, int mst_addr)
+{
+ sc_err_t sciErr;
+ sc_ipc_t ipcHndl = 0;
+ u32 mu_id;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("Cannot obtain MU ID\n");
+ return;
+ }
+
+ sciErr = sc_ipc_open(&ipcHndl, mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return;
+ }
+
+ if (dpu_id == 0) {
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_0, stream_id ?
+ SC_C_PXL_LINK_MST2_ADDR : SC_C_PXL_LINK_MST1_ADDR,
+ mst_addr);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_0:SC_C_PXL_LINK_MST%d_ADDR sc_misc_set_control failed! (sciError = %d)\n", stream_id + 1, sciErr);
+ } else if (dpu_id == 1) {
+ sciErr = sc_misc_set_control(ipcHndl, SC_R_DC_1, stream_id ?
+ SC_C_PXL_LINK_MST2_ADDR : SC_C_PXL_LINK_MST1_ADDR,
+ mst_addr);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("SC_R_DC_1:SC_C_PXL_LINK_MST%d_ADDR sc_misc_set_control failed! (sciError = %d)\n", stream_id + 1, sciErr);
+ }
+
+ sc_ipc_close(mu_id);
+}
+
+void framegen_enable(struct dpu_framegen *fg)
+{
+ struct dpu_soc *dpu = fg->dpu;
+ const struct dpu_devtype *devtype = dpu->devtype;
+
+ mutex_lock(&fg->mutex);
+ dpu_fg_write(fg, FGEN, FGENABLE);
+ mutex_unlock(&fg->mutex);
+
+ if (!(devtype->has_dual_ldb && fg->encoder_type_has_lvds))
+ dpu_pixel_link_enable(dpu->id, fg->id);
+}
+EXPORT_SYMBOL_GPL(framegen_enable);
+
+void framegen_disable(struct dpu_framegen *fg)
+{
+ struct dpu_soc *dpu = fg->dpu;
+ const struct dpu_devtype *devtype = dpu->devtype;
+
+ if (!(devtype->has_dual_ldb && fg->encoder_type_has_lvds))
+ dpu_pixel_link_disable(dpu->id, fg->id);
+
+ mutex_lock(&fg->mutex);
+ dpu_fg_write(fg, 0, FGENABLE);
+ mutex_unlock(&fg->mutex);
+}
+EXPORT_SYMBOL_GPL(framegen_disable);
+
+void framegen_shdtokgen(struct dpu_framegen *fg)
+{
+ mutex_lock(&fg->mutex);
+ dpu_fg_write(fg, SHDTOKGEN, FGSLR);
+ mutex_unlock(&fg->mutex);
+}
+EXPORT_SYMBOL_GPL(framegen_shdtokgen);
+
+void
+framegen_cfg_videomode(struct dpu_framegen *fg, struct drm_display_mode *m,
+ bool encoder_type_has_tmds, bool encoder_type_has_lvds)
+{
+ struct dpu_soc *dpu = fg->dpu;
+ const struct dpu_devtype *devtype = dpu->devtype;
+ u32 hact, htotal, hsync, hsbp;
+ u32 vact, vtotal, vsync, vsbp;
+ u32 val;
+ unsigned long disp_clock_rate, pll_clock_rate = 0;
+ int div = 0;
+
+ fg->encoder_type_has_lvds = encoder_type_has_lvds;
+
+ hact = m->crtc_hdisplay;
+ htotal = m->crtc_htotal;
+ hsync = m->crtc_hsync_end - m->crtc_hsync_start;
+ hsbp = m->crtc_htotal - m->crtc_hsync_start;
+
+ vact = m->crtc_vdisplay;
+ vtotal = m->crtc_vtotal;
+ vsync = m->crtc_vsync_end - m->crtc_vsync_start;
+ vsbp = m->crtc_vtotal - m->crtc_vsync_start;
+
+ mutex_lock(&fg->mutex);
+ /* video mode */
+ dpu_fg_write(fg, HACT(hact) | HTOTAL(htotal), HTCFG1);
+ dpu_fg_write(fg, HSYNC(hsync) | HSBP(hsbp) | HSEN, HTCFG2);
+ dpu_fg_write(fg, VACT(vact) | VTOTAL(vtotal), VTCFG1);
+ dpu_fg_write(fg, VSYNC(vsync) | VSBP(vsbp) | VSEN, VTCFG2);
+
+ /* pkickconfig */
+ dpu_fg_write(fg, COL(hact) | ROW(vact) | EN, PKICKCONFIG);
+
+ /* skikconfig */
+ dpu_fg_write(fg, COL(hact) | ROW(vact) | EN, SKICKCONFIG);
+
+ /* primary position config */
+ dpu_fg_write(fg, STARTX(0) | STARTY(0), PACFG);
+
+ /* alpha */
+ val = dpu_fg_read(fg, FGINCTRL);
+ val &= ~(ENPRIMALPHA | ENSECALPHA);
+ dpu_fg_write(fg, val, FGINCTRL);
+
+ val = dpu_fg_read(fg, FGINCTRLPANIC);
+ val &= ~(ENPRIMALPHA | ENSECALPHA);
+ dpu_fg_write(fg, val, FGINCTRLPANIC);
+
+ /* constant color */
+ dpu_fg_write(fg, 0, FGCCR);
+ mutex_unlock(&fg->mutex);
+
+ disp_clock_rate = m->clock * 1000;
+
+ /*
+ * To workaround setting clock rate failure issue
+ * when the system resumes back from PM sleep mode,
+ * we need to get the clock rates before setting
+ * their rates, otherwise, setting the clock rates
+ * will fail.
+ */
+ if (devtype->has_disp_sel_clk && encoder_type_has_tmds) {
+ dpu_pixel_link_set_mst_addr(dpu->id, fg->id, 1);
+
+ clk_set_parent(fg->clk_disp_sel, fg->clk_bypass);
+
+ fg->use_bypass_clk = true;
+ } else {
+ dpu_pixel_link_set_mst_addr(dpu->id, fg->id, 0);
+
+ /* find an even divisor for PLL */
+ do {
+ div += 2;
+ pll_clock_rate = disp_clock_rate * div;
+ } while (pll_clock_rate < PLL_MIN_FREQ_HZ);
+
+ if (devtype->has_disp_sel_clk)
+ clk_set_parent(fg->clk_disp_sel, fg->clk_pll);
+
+ clk_get_rate(fg->clk_pll);
+ clk_get_rate(fg->clk_disp);
+ clk_set_rate(fg->clk_pll, pll_clock_rate);
+ clk_set_rate(fg->clk_disp, disp_clock_rate);
+
+ fg->use_bypass_clk = false;
+ }
+}
+EXPORT_SYMBOL_GPL(framegen_cfg_videomode);
+
+void framegen_pkickconfig(struct dpu_framegen *fg, bool enable)
+{
+ u32 val;
+
+ mutex_lock(&fg->mutex);
+ val = dpu_fg_read(fg, PKICKCONFIG);
+ if (enable)
+ val |= EN;
+ else
+ val &= ~EN;
+ dpu_fg_write(fg, val, PKICKCONFIG);
+ mutex_unlock(&fg->mutex);
+}
+EXPORT_SYMBOL_GPL(framegen_pkickconfig);
+
+void framegen_sacfg(struct dpu_framegen *fg, unsigned int x, unsigned int y)
+{
+ mutex_lock(&fg->mutex);
+ dpu_fg_write(fg, STARTX(x) | STARTY(y), SACFG);
+ mutex_unlock(&fg->mutex);
+}
+EXPORT_SYMBOL_GPL(framegen_sacfg);
+
+void framegen_displaymode(struct dpu_framegen *fg, fgdm_t mode)
+{
+ u32 val;
+
+ mutex_lock(&fg->mutex);
+ val = dpu_fg_read(fg, FGINCTRL);
+ val &= ~FGDM_MASK;
+ val |= mode;
+ dpu_fg_write(fg, val, FGINCTRL);
+ mutex_unlock(&fg->mutex);
+}
+EXPORT_SYMBOL_GPL(framegen_displaymode);
+
+void framegen_panic_displaymode(struct dpu_framegen *fg, fgdm_t mode)
+{
+ u32 val;
+
+ mutex_lock(&fg->mutex);
+ val = dpu_fg_read(fg, FGINCTRLPANIC);
+ val &= ~FGDM_MASK;
+ val |= mode;
+ dpu_fg_write(fg, val, FGINCTRLPANIC);
+ mutex_unlock(&fg->mutex);
+}
+EXPORT_SYMBOL_GPL(framegen_panic_displaymode);
+
+void framegen_wait_done(struct dpu_framegen *fg, struct drm_display_mode *m)
+{
+ unsigned long timeout, pending_framedur_jiffies;
+ int frame_size = m->crtc_htotal * m->crtc_vtotal;
+ int dotclock, pending_framedur_ns;
+ u32 val;
+
+ dotclock = clk_get_rate(fg->clk_disp) / KHZ;
+ if (dotclock == 0) {
+ /* fall back to display mode's clock */
+ dotclock = m->crtc_clock;
+
+ dev_warn(fg->dpu->dev,
+ "pixel clock for FrameGen%d is zero\n", fg->id);
+ }
+
+ /*
+ * The SoC designer indicates that there are two pending frames
+ * to complete in the worst case.
+ * So, three pending frames are enough for sure.
+ */
+ pending_framedur_ns = div_u64((u64) 3 * frame_size * 1000000, dotclock);
+ pending_framedur_jiffies = nsecs_to_jiffies(pending_framedur_ns);
+ if (pending_framedur_jiffies > (3 * HZ)) {
+ pending_framedur_jiffies = 3 * HZ;
+
+ dev_warn(fg->dpu->dev,
+ "truncate FrameGen%d pending frame duration to 3sec\n",
+ fg->id);
+ }
+ timeout = jiffies + pending_framedur_jiffies;
+
+ mutex_lock(&fg->mutex);
+ do {
+ val = dpu_fg_read(fg, FGENSTS);
+ } while ((val & ENSTS) && time_before(jiffies, timeout));
+ mutex_unlock(&fg->mutex);
+
+ dev_dbg(fg->dpu->dev, "FrameGen%d pending frame duration is %ums\n",
+ fg->id, jiffies_to_msecs(pending_framedur_jiffies));
+
+ if (val & ENSTS)
+ dev_err(fg->dpu->dev, "failed to wait for FrameGen%d done\n",
+ fg->id);
+}
+EXPORT_SYMBOL_GPL(framegen_wait_done);
+
+static inline u32 framegen_frame_index(u32 stamp)
+{
+ return (stamp & FRAMEINDEX_MASK) >> FRAMEINDEX_SHIFT;
+}
+
+static inline u32 framegen_line_index(u32 stamp)
+{
+ return (stamp & LINEINDEX_MASK) >> LINEINDEX_SHIFT;
+}
+
+void framegen_read_timestamp(struct dpu_framegen *fg,
+ u32 *frame_index, u32 *line_index)
+{
+ u32 stamp;
+
+ mutex_lock(&fg->mutex);
+ stamp = dpu_fg_read(fg, FGTIMESTAMP);
+ *frame_index = framegen_frame_index(stamp);
+ *line_index = framegen_line_index(stamp);
+ mutex_unlock(&fg->mutex);
+}
+EXPORT_SYMBOL_GPL(framegen_read_timestamp);
+
+void framegen_wait_for_frame_counter_moving(struct dpu_framegen *fg)
+{
+ u32 frame_index, line_index, last_frame_index;
+ unsigned long timeout = jiffies + msecs_to_jiffies(50);
+
+ framegen_read_timestamp(fg, &frame_index, &line_index);
+ do {
+ last_frame_index = frame_index;
+ framegen_read_timestamp(fg, &frame_index, &line_index);
+ } while (last_frame_index == frame_index &&
+ time_before(jiffies, timeout));
+
+ if (last_frame_index == frame_index)
+ dev_err(fg->dpu->dev,
+ "failed to wait for FrameGen%d frame counter moving\n",
+ fg->id);
+ else
+ dev_dbg(fg->dpu->dev,
+ "FrameGen%d frame counter moves - last %u, curr %d\n",
+ fg->id, last_frame_index, frame_index);
+}
+EXPORT_SYMBOL_GPL(framegen_wait_for_frame_counter_moving);
+
+void framegen_enable_clock(struct dpu_framegen *fg)
+{
+ if (!fg->use_bypass_clk)
+ clk_prepare_enable(fg->clk_pll);
+ clk_prepare_enable(fg->clk_disp);
+}
+EXPORT_SYMBOL_GPL(framegen_enable_clock);
+
+void framegen_disable_clock(struct dpu_framegen *fg)
+{
+ if (!fg->use_bypass_clk)
+ clk_disable_unprepare(fg->clk_pll);
+ clk_disable_unprepare(fg->clk_disp);
+}
+EXPORT_SYMBOL_GPL(framegen_disable_clock);
+
+struct dpu_framegen *dpu_fg_get(struct dpu_soc *dpu, int id)
+{
+ struct dpu_framegen *fg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fg_ids); i++)
+ if (fg_ids[i] == id)
+ break;
+
+ if (i == ARRAY_SIZE(fg_ids))
+ return ERR_PTR(-EINVAL);
+
+ fg = dpu->fg_priv[i];
+
+ mutex_lock(&fg->mutex);
+
+ if (fg->inuse) {
+ fg = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
+ fg->inuse = true;
+out:
+ mutex_unlock(&fg->mutex);
+
+ return fg;
+}
+EXPORT_SYMBOL_GPL(dpu_fg_get);
+
+void dpu_fg_put(struct dpu_framegen *fg)
+{
+ mutex_lock(&fg->mutex);
+
+ fg->inuse = false;
+
+ mutex_unlock(&fg->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_fg_put);
+
+void _dpu_fg_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_framegen *fg;
+ u32 val;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fg_ids); i++)
+ if (fg_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(fg_ids)))
+ return;
+
+ fg = dpu->fg_priv[i];
+
+ mutex_lock(&fg->mutex);
+ val = dpu_fg_read(fg, FGSTCTRL);
+ val &= ~FGSYNCMODE_MASK;
+ val |= FGSYNCMODE__OFF;
+ dpu_fg_write(fg, val, FGSTCTRL);
+ mutex_unlock(&fg->mutex);
+}
+
+int dpu_fg_init(struct dpu_soc *dpu, unsigned int id,
+ unsigned long unused, unsigned long base)
+{
+ struct dpu_framegen *fg;
+
+ fg = devm_kzalloc(dpu->dev, sizeof(*fg), GFP_KERNEL);
+ if (!fg)
+ return -ENOMEM;
+
+ dpu->fg_priv[id] = fg;
+
+ fg->base = devm_ioremap(dpu->dev, base, SZ_256);
+ if (!fg->base)
+ return -ENOMEM;
+
+ fg->clk_pll = devm_clk_get(dpu->dev, id ? "pll1" : "pll0");
+ if (IS_ERR(fg->clk_pll))
+ return PTR_ERR(fg->clk_pll);
+
+ if (dpu->devtype->has_disp_sel_clk) {
+ fg->clk_bypass = devm_clk_get(dpu->dev, "bypass0");
+ if (IS_ERR(fg->clk_bypass))
+ return PTR_ERR(fg->clk_bypass);
+
+ fg->clk_disp_sel = devm_clk_get(dpu->dev,
+ id ? "disp1_sel" : "disp0_sel");
+ if (IS_ERR(fg->clk_disp_sel))
+ return PTR_ERR(fg->clk_disp_sel);
+ }
+
+ fg->clk_disp = devm_clk_get(dpu->dev, id ? "disp1" : "disp0");
+ if (IS_ERR(fg->clk_disp))
+ return PTR_ERR(fg->clk_disp);
+
+ fg->dpu = dpu;
+ fg->id = id;
+ mutex_init(&fg->mutex);
+
+ _dpu_fg_init(dpu, id);
+
+ return 0;
+}
diff --git a/drivers/gpu/imx/dpu/dpu-hscaler.c b/drivers/gpu/imx/dpu/dpu-hscaler.c
new file mode 100644
index 000000000000..d9e34bce46bc
--- /dev/null
+++ b/drivers/gpu/imx/dpu/dpu-hscaler.c
@@ -0,0 +1,392 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define PIXENGCFG_DYNAMIC 0x8
+#define PIXENGCFG_DYNAMIC_SRC_SEL_MASK 0x3F
+
+#define SETUP1 0xC
+#define SCALE_FACTOR_MASK 0xFFFFF
+#define SCALE_FACTOR(n) ((n) & 0xFFFFF)
+#define SETUP2 0x10
+#define PHASE_OFFSET_MASK 0x1FFFFF
+#define PHASE_OFFSET(n) ((n) & 0x1FFFFF)
+#define CONTROL 0x14
+#define OUTPUT_SIZE_MASK 0x3FFF0000
+#define OUTPUT_SIZE(n) ((((n) - 1) << 16) & OUTPUT_SIZE_MASK)
+#define FILTER_MODE 0x100
+#define SCALE_MODE 0x10
+#define MODE 0x1
+
+static const hs_src_sel_t src_sels[3][6] = {
+ {
+ HS_SRC_SEL__DISABLE,
+ HS_SRC_SEL__EXTSRC4,
+ HS_SRC_SEL__FETCHDECODE0,
+ HS_SRC_SEL__FETCHDECODE2,
+ HS_SRC_SEL__MATRIX4,
+ HS_SRC_SEL__VSCALER4,
+ }, {
+ HS_SRC_SEL__DISABLE,
+ HS_SRC_SEL__EXTSRC5,
+ HS_SRC_SEL__FETCHDECODE1,
+ HS_SRC_SEL__FETCHDECODE3,
+ HS_SRC_SEL__MATRIX5,
+ HS_SRC_SEL__VSCALER5,
+ }, {
+ HS_SRC_SEL__DISABLE,
+ HS_SRC_SEL__MATRIX9,
+ HS_SRC_SEL__VSCALER9,
+ HS_SRC_SEL__FILTER9,
+ },
+};
+
+struct dpu_hscaler {
+ void __iomem *pec_base;
+ void __iomem *base;
+ struct mutex mutex;
+ int id;
+ bool inuse;
+ struct dpu_soc *dpu;
+ /* see DPU_PLANE_SRC_xxx */
+ unsigned int stream_id;
+};
+
+static inline u32 dpu_pec_hs_read(struct dpu_hscaler *hs,
+ unsigned int offset)
+{
+ return readl(hs->pec_base + offset);
+}
+
+static inline void dpu_pec_hs_write(struct dpu_hscaler *hs, u32 value,
+ unsigned int offset)
+{
+ writel(value, hs->pec_base + offset);
+}
+
+static inline u32 dpu_hs_read(struct dpu_hscaler *hs, unsigned int offset)
+{
+ return readl(hs->base + offset);
+}
+
+static inline void dpu_hs_write(struct dpu_hscaler *hs, u32 value,
+ unsigned int offset)
+{
+ writel(value, hs->base + offset);
+}
+
+int hscaler_pixengcfg_dynamic_src_sel(struct dpu_hscaler *hs, hs_src_sel_t src)
+{
+ struct dpu_soc *dpu = hs->dpu;
+ const unsigned int *block_id_map = dpu->devtype->sw2hw_block_id_map;
+ const unsigned int hs_id_array[] = {4, 5, 9};
+ int i, j;
+ u32 val, mapped_src;
+
+ for (i = 0; i < ARRAY_SIZE(hs_id_array); i++)
+ if (hs_id_array[i] == hs->id)
+ break;
+
+ if (WARN_ON(i == (ARRAY_SIZE(hs_id_array) + 1)))
+ return -EINVAL;
+
+ mutex_lock(&hs->mutex);
+ for (j = 0; j < ARRAY_SIZE(src_sels[0]); j++) {
+ if (src_sels[i][j] == src) {
+ mapped_src = block_id_map ? block_id_map[src] : src;
+ if (WARN_ON(mapped_src == NA))
+ return -EINVAL;
+
+ val = dpu_pec_hs_read(hs, PIXENGCFG_DYNAMIC);
+ val &= ~PIXENGCFG_DYNAMIC_SRC_SEL_MASK;
+ val |= mapped_src;
+ dpu_pec_hs_write(hs, val, PIXENGCFG_DYNAMIC);
+ mutex_unlock(&hs->mutex);
+ return 0;
+ }
+ }
+ mutex_unlock(&hs->mutex);
+
+ dev_err(dpu->dev, "Invalid source for HScaler%d\n", hs->id);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(hscaler_pixengcfg_dynamic_src_sel);
+
+void hscaler_pixengcfg_clken(struct dpu_hscaler *hs, pixengcfg_clken_t clken)
+{
+ u32 val;
+
+ mutex_lock(&hs->mutex);
+ val = dpu_pec_hs_read(hs, PIXENGCFG_DYNAMIC);
+ val &= ~CLKEN_MASK;
+ val |= clken << CLKEN_MASK_SHIFT;
+ dpu_pec_hs_write(hs, val, PIXENGCFG_DYNAMIC);
+ mutex_unlock(&hs->mutex);
+}
+EXPORT_SYMBOL_GPL(hscaler_pixengcfg_clken);
+
+void hscaler_shden(struct dpu_hscaler *hs, bool enable)
+{
+ u32 val;
+
+ mutex_lock(&hs->mutex);
+ val = dpu_hs_read(hs, STATICCONTROL);
+ if (enable)
+ val |= SHDEN;
+ else
+ val &= ~SHDEN;
+ dpu_hs_write(hs, val, STATICCONTROL);
+ mutex_unlock(&hs->mutex);
+}
+EXPORT_SYMBOL_GPL(hscaler_shden);
+
+void hscaler_setup1(struct dpu_hscaler *hs, u32 src, u32 dst)
+{
+ struct dpu_soc *dpu = hs->dpu;
+ u32 scale_factor;
+ u64 tmp64;
+
+ if (src == dst) {
+ scale_factor = 0x80000;
+ } else {
+ if (src > dst) {
+ tmp64 = (u64)((u64)dst * 0x80000);
+ do_div(tmp64, src);
+
+ } else {
+ tmp64 = (u64)((u64)src * 0x80000);
+ do_div(tmp64, dst);
+ }
+ scale_factor = (u32)tmp64;
+ }
+
+ WARN_ON(scale_factor > 0x80000);
+
+ mutex_lock(&hs->mutex);
+ dpu_hs_write(hs, SCALE_FACTOR(scale_factor), SETUP1);
+ mutex_unlock(&hs->mutex);
+
+ dev_dbg(dpu->dev, "Hscaler%d scale factor 0x%08x\n",
+ hs->id, scale_factor);
+}
+EXPORT_SYMBOL_GPL(hscaler_setup1);
+
+void hscaler_setup2(struct dpu_hscaler *hs, u32 phase_offset)
+{
+ mutex_lock(&hs->mutex);
+ dpu_hs_write(hs, PHASE_OFFSET(phase_offset), SETUP2);
+ mutex_unlock(&hs->mutex);
+}
+EXPORT_SYMBOL_GPL(hscaler_setup2);
+
+void hscaler_output_size(struct dpu_hscaler *hs, u32 line_num)
+{
+ u32 val;
+
+ mutex_lock(&hs->mutex);
+ val = dpu_hs_read(hs, CONTROL);
+ val &= ~OUTPUT_SIZE_MASK;
+ val |= OUTPUT_SIZE(line_num);
+ dpu_hs_write(hs, val, CONTROL);
+ mutex_unlock(&hs->mutex);
+}
+EXPORT_SYMBOL_GPL(hscaler_output_size);
+
+void hscaler_filter_mode(struct dpu_hscaler *hs, scaler_filter_mode_t m)
+{
+ u32 val;
+
+ mutex_lock(&hs->mutex);
+ val = dpu_hs_read(hs, CONTROL);
+ val &= ~FILTER_MODE;
+ val |= m;
+ dpu_hs_write(hs, val, CONTROL);
+ mutex_unlock(&hs->mutex);
+}
+EXPORT_SYMBOL_GPL(hscaler_filter_mode);
+
+void hscaler_scale_mode(struct dpu_hscaler *hs, scaler_scale_mode_t m)
+{
+ u32 val;
+
+ mutex_lock(&hs->mutex);
+ val = dpu_hs_read(hs, CONTROL);
+ val &= ~SCALE_MODE;
+ val |= m;
+ dpu_hs_write(hs, val, CONTROL);
+ mutex_unlock(&hs->mutex);
+}
+EXPORT_SYMBOL_GPL(hscaler_scale_mode);
+
+void hscaler_mode(struct dpu_hscaler *hs, scaler_mode_t m)
+{
+ u32 val;
+
+ mutex_lock(&hs->mutex);
+ val = dpu_hs_read(hs, CONTROL);
+ val &= ~MODE;
+ val |= m;
+ dpu_hs_write(hs, val, CONTROL);
+ mutex_unlock(&hs->mutex);
+}
+EXPORT_SYMBOL_GPL(hscaler_mode);
+
+bool hscaler_is_enabled(struct dpu_hscaler *hs)
+{
+ u32 val;
+
+ mutex_lock(&hs->mutex);
+ val = dpu_hs_read(hs, CONTROL);
+ mutex_unlock(&hs->mutex);
+
+ return (val & MODE) == SCALER_ACTIVE;
+}
+EXPORT_SYMBOL_GPL(hscaler_is_enabled);
+
+dpu_block_id_t hscaler_get_block_id(struct dpu_hscaler *hs)
+{
+ switch (hs->id) {
+ case 4:
+ return ID_HSCALER4;
+ case 5:
+ return ID_HSCALER5;
+ case 9:
+ return ID_HSCALER9;
+ default:
+ WARN_ON(1);
+ }
+
+ return ID_NONE;
+}
+EXPORT_SYMBOL_GPL(hscaler_get_block_id);
+
+unsigned int hscaler_get_stream_id(struct dpu_hscaler *hs)
+{
+ return hs->stream_id;
+}
+EXPORT_SYMBOL_GPL(hscaler_get_stream_id);
+
+void hscaler_set_stream_id(struct dpu_hscaler *hs, unsigned int id)
+{
+ switch (id) {
+ case DPU_PLANE_SRC_TO_DISP_STREAM0:
+ case DPU_PLANE_SRC_TO_DISP_STREAM1:
+ case DPU_PLANE_SRC_DISABLED:
+ hs->stream_id = id;
+ break;
+ default:
+ WARN_ON(1);
+ }
+}
+EXPORT_SYMBOL_GPL(hscaler_set_stream_id);
+
+struct dpu_hscaler *dpu_hs_get(struct dpu_soc *dpu, int id)
+{
+ struct dpu_hscaler *hs;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hs_ids); i++)
+ if (hs_ids[i] == id)
+ break;
+
+ if (i == ARRAY_SIZE(hs_ids))
+ return ERR_PTR(-EINVAL);
+
+ hs = dpu->hs_priv[i];
+
+ mutex_lock(&hs->mutex);
+
+ if (hs->inuse) {
+ hs = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
+ hs->inuse = true;
+out:
+ mutex_unlock(&hs->mutex);
+
+ return hs;
+}
+EXPORT_SYMBOL_GPL(dpu_hs_get);
+
+void dpu_hs_put(struct dpu_hscaler *hs)
+{
+ mutex_lock(&hs->mutex);
+
+ hs->inuse = false;
+
+ mutex_unlock(&hs->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_hs_put);
+
+void _dpu_hs_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_hscaler *hs;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hs_ids); i++)
+ if (hs_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(hs_ids)))
+ return;
+
+ hs = dpu->hs_priv[i];
+
+ hscaler_shden(hs, true);
+ hscaler_setup2(hs, 0);
+ hscaler_pixengcfg_dynamic_src_sel(hs, HS_SRC_SEL__DISABLE);
+}
+
+int dpu_hs_init(struct dpu_soc *dpu, unsigned int id,
+ unsigned long pec_base, unsigned long base)
+{
+ struct dpu_hscaler *hs;
+ int i;
+
+ hs = devm_kzalloc(dpu->dev, sizeof(*hs), GFP_KERNEL);
+ if (!hs)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(hs_ids); i++)
+ if (hs_ids[i] == id)
+ break;
+
+ dpu->hs_priv[i] = hs;
+
+ hs->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_8);
+ if (!hs->pec_base)
+ return -ENOMEM;
+
+ hs->base = devm_ioremap(dpu->dev, base, SZ_1K);
+ if (!hs->base)
+ return -ENOMEM;
+
+ hs->dpu = dpu;
+ hs->id = id;
+
+ mutex_init(&hs->mutex);
+
+ _dpu_hs_init(dpu, id);
+
+ return 0;
+}
diff --git a/drivers/gpu/imx/dpu/dpu-layerblend.c b/drivers/gpu/imx/dpu/dpu-layerblend.c
new file mode 100644
index 000000000000..c18420988df7
--- /dev/null
+++ b/drivers/gpu/imx/dpu/dpu-layerblend.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define PIXENGCFG_DYNAMIC 0x8
+#define PIXENGCFG_DYNAMIC_PRIM_SEL_MASK 0x3F
+#define PIXENGCFG_DYNAMIC_SEC_SEL_MASK 0x3F00
+#define PIXENGCFG_DYNAMIC_SEC_SEL_SHIFT 8
+
+static const lb_prim_sel_t prim_sels[] = {
+ LB_PRIM_SEL__DISABLE,
+ LB_PRIM_SEL__BLITBLEND9,
+ LB_PRIM_SEL__CONSTFRAME0,
+ LB_PRIM_SEL__CONSTFRAME1,
+ LB_PRIM_SEL__CONSTFRAME4,
+ LB_PRIM_SEL__CONSTFRAME5,
+ LB_PRIM_SEL__MATRIX4,
+ LB_PRIM_SEL__HSCALER4,
+ LB_PRIM_SEL__VSCALER4,
+ LB_PRIM_SEL__EXTSRC4,
+ LB_PRIM_SEL__MATRIX5,
+ LB_PRIM_SEL__HSCALER5,
+ LB_PRIM_SEL__VSCALER5,
+ LB_PRIM_SEL__EXTSRC5,
+ LB_PRIM_SEL__LAYERBLEND0,
+ LB_PRIM_SEL__LAYERBLEND1,
+ LB_PRIM_SEL__LAYERBLEND2,
+ LB_PRIM_SEL__LAYERBLEND3,
+ LB_PRIM_SEL__LAYERBLEND4,
+ LB_PRIM_SEL__LAYERBLEND5,
+};
+
+#define PIXENGCFG_STATUS 0xC
+#define SHDTOKSEL (0x3 << 3)
+#define SHDTOKSEL_SHIFT 3
+#define SHDLDSEL (0x3 << 1)
+#define SHDLDSEL_SHIFT 1
+#define CONTROL 0xC
+#define MODE_MASK BIT(0)
+#define BLENDCONTROL 0x10
+#define ALPHA(a) (((a) & 0xFF) << 16)
+#define PRIM_C_BLD_FUNC__ONE_MINUS_SEC_ALPHA 0x5
+#define PRIM_C_BLD_FUNC__PRIM_ALPHA 0x2
+#define SEC_C_BLD_FUNC__CONST_ALPHA (0x6 << 4)
+#define SEC_C_BLD_FUNC__ONE_MINUS_PRIM_ALPHA (0x3 << 4)
+#define PRIM_A_BLD_FUNC__ONE_MINUS_SEC_ALPHA (0x5 << 8)
+#define PRIM_A_BLD_FUNC__ZERO (0x0 << 8)
+#define SEC_A_BLD_FUNC__ONE (0x1 << 12)
+#define SEC_A_BLD_FUNC__ZERO (0x0 << 12)
+#define POSITION 0x14
+#define XPOS(x) ((x) & 0x7FFF)
+#define YPOS(y) (((y) & 0x7FFF) << 16)
+#define PRIMCONTROLWORD 0x18
+#define SECCONTROLWORD 0x1C
+
+#define CONTROLWORD 0x18
+#define CURPIXELCNT 0x1C
+static u16 get_xval(u32 pixel_cnt)
+{
+ return pixel_cnt && 0xFF;
+}
+
+static u16 get_yval(u32 pixel_cnt)
+{
+ return pixel_cnt >> 16;
+}
+#define LASTPIXELCNT 0x20
+#define PERFCOUNTER 0x24
+
+struct dpu_layerblend {
+ void __iomem *pec_base;
+ void __iomem *base;
+ struct mutex mutex;
+ int id;
+ bool inuse;
+ struct dpu_soc *dpu;
+};
+
+static inline u32 dpu_pec_lb_read(struct dpu_layerblend *lb,
+ unsigned int offset)
+{
+ return readl(lb->pec_base + offset);
+}
+
+static inline void dpu_pec_lb_write(struct dpu_layerblend *lb, u32 value,
+ unsigned int offset)
+{
+ writel(value, lb->pec_base + offset);
+}
+
+static inline u32 dpu_lb_read(struct dpu_layerblend *lb, unsigned int offset)
+{
+ return readl(lb->base + offset);
+}
+
+static inline void dpu_lb_write(struct dpu_layerblend *lb, u32 value,
+ unsigned int offset)
+{
+ writel(value, lb->base + offset);
+}
+
+int layerblend_pixengcfg_dynamic_prim_sel(struct dpu_layerblend *lb,
+ lb_prim_sel_t prim)
+{
+ struct dpu_soc *dpu = lb->dpu;
+ const unsigned int *block_id_map = dpu->devtype->sw2hw_block_id_map;
+ int fixed_sels_num = ARRAY_SIZE(prim_sels) - 6;
+ int i;
+ u32 val, mapped_prim;
+
+ mutex_lock(&lb->mutex);
+ for (i = 0; i < fixed_sels_num + lb->id; i++) {
+ if (prim_sels[i] == prim) {
+ mapped_prim = block_id_map ? block_id_map[prim] : prim;
+ if (WARN_ON(mapped_prim == NA))
+ return -EINVAL;
+
+ val = dpu_pec_lb_read(lb, PIXENGCFG_DYNAMIC);
+ val &= ~PIXENGCFG_DYNAMIC_PRIM_SEL_MASK;
+ val |= mapped_prim;
+ dpu_pec_lb_write(lb, val, PIXENGCFG_DYNAMIC);
+ mutex_unlock(&lb->mutex);
+ return 0;
+ }
+ }
+ mutex_unlock(&lb->mutex);
+
+ dev_err(dpu->dev, "Invalid primary source for LayerBlend%d\n", lb->id);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(layerblend_pixengcfg_dynamic_prim_sel);
+
+void layerblend_pixengcfg_dynamic_sec_sel(struct dpu_layerblend *lb,
+ lb_sec_sel_t sec)
+{
+ struct dpu_soc *dpu = lb->dpu;
+ const unsigned int *block_id_map = dpu->devtype->sw2hw_block_id_map;
+ u32 val, mapped_sec;
+
+ mapped_sec = block_id_map ? block_id_map[sec] : sec;
+ if (WARN_ON(mapped_sec == NA))
+ return;
+
+ mutex_lock(&lb->mutex);
+ val = dpu_pec_lb_read(lb, PIXENGCFG_DYNAMIC);
+ val &= ~PIXENGCFG_DYNAMIC_SEC_SEL_MASK;
+ val |= mapped_sec << PIXENGCFG_DYNAMIC_SEC_SEL_SHIFT;
+ dpu_pec_lb_write(lb, val, PIXENGCFG_DYNAMIC);
+ mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(layerblend_pixengcfg_dynamic_sec_sel);
+
+void layerblend_pixengcfg_clken(struct dpu_layerblend *lb,
+ pixengcfg_clken_t clken)
+{
+ u32 val;
+
+ mutex_lock(&lb->mutex);
+ val = dpu_pec_lb_read(lb, PIXENGCFG_DYNAMIC);
+ val &= ~CLKEN_MASK;
+ val |= clken << CLKEN_MASK_SHIFT;
+ dpu_pec_lb_write(lb, val, PIXENGCFG_DYNAMIC);
+ mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(layerblend_pixengcfg_clken);
+
+void layerblend_shden(struct dpu_layerblend *lb, bool enable)
+{
+ u32 val;
+
+ mutex_lock(&lb->mutex);
+ val = dpu_lb_read(lb, STATICCONTROL);
+ if (enable)
+ val |= SHDEN;
+ else
+ val &= ~SHDEN;
+ dpu_lb_write(lb, val, STATICCONTROL);
+ mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(layerblend_shden);
+
+void layerblend_shdtoksel(struct dpu_layerblend *lb, lb_shadow_sel_t sel)
+{
+ u32 val;
+
+ mutex_lock(&lb->mutex);
+ val = dpu_lb_read(lb, STATICCONTROL);
+ val &= ~SHDTOKSEL;
+ val |= (sel << SHDTOKSEL_SHIFT);
+ dpu_lb_write(lb, val, STATICCONTROL);
+ mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(layerblend_shdtoksel);
+
+void layerblend_shdldsel(struct dpu_layerblend *lb, lb_shadow_sel_t sel)
+{
+ u32 val;
+
+ mutex_lock(&lb->mutex);
+ val = dpu_lb_read(lb, STATICCONTROL);
+ val &= ~SHDLDSEL;
+ val |= (sel << SHDLDSEL_SHIFT);
+ dpu_lb_write(lb, val, STATICCONTROL);
+ mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(layerblend_shdldsel);
+
+void layerblend_control(struct dpu_layerblend *lb, lb_mode_t mode)
+{
+ u32 val;
+
+ mutex_lock(&lb->mutex);
+ val = dpu_lb_read(lb, CONTROL);
+ val &= ~MODE_MASK;
+ val |= mode;
+ dpu_lb_write(lb, val, CONTROL);
+ mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(layerblend_control);
+
+void layerblend_blendcontrol(struct dpu_layerblend *lb, bool sec_from_scaler)
+{
+ u32 val;
+
+ val = ALPHA(0xff) |
+ PRIM_C_BLD_FUNC__PRIM_ALPHA |
+ SEC_C_BLD_FUNC__ONE_MINUS_PRIM_ALPHA |
+ PRIM_A_BLD_FUNC__ZERO;
+
+ val |= sec_from_scaler ? SEC_A_BLD_FUNC__ZERO : SEC_A_BLD_FUNC__ONE;
+
+ mutex_lock(&lb->mutex);
+ dpu_lb_write(lb, val, BLENDCONTROL);
+ mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(layerblend_blendcontrol);
+
+void layerblend_position(struct dpu_layerblend *lb, int x, int y)
+{
+ mutex_lock(&lb->mutex);
+ dpu_lb_write(lb, XPOS(x) | YPOS(y), POSITION);
+ mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(layerblend_position);
+
+u32 layerblend_last_control_word(struct dpu_layerblend *lb)
+{
+ u32 val;
+
+ mutex_lock(&lb->mutex);
+ val = dpu_lb_read(lb, CONTROLWORD);
+ mutex_unlock(&lb->mutex);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(layerblend_last_control_word);
+
+void layerblend_pixel_cnt(struct dpu_layerblend *lb, u16 *x, u16 *y)
+{
+ u32 val;
+
+ mutex_lock(&lb->mutex);
+ val = dpu_lb_read(lb, CURPIXELCNT);
+ mutex_unlock(&lb->mutex);
+
+ *x = get_xval(val);
+ *y = get_yval(val);
+}
+EXPORT_SYMBOL_GPL(layerblend_pixel_cnt);
+
+void layerblend_last_pixel_cnt(struct dpu_layerblend *lb, u16 *x, u16 *y)
+{
+ u32 val;
+
+ mutex_lock(&lb->mutex);
+ val = dpu_lb_read(lb, LASTPIXELCNT);
+ mutex_unlock(&lb->mutex);
+
+ *x = get_xval(val);
+ *y = get_yval(val);
+}
+EXPORT_SYMBOL_GPL(layerblend_last_pixel_cnt);
+
+u32 layerblend_perfresult(struct dpu_layerblend *lb)
+{
+ u32 val;
+
+ mutex_lock(&lb->mutex);
+ val = dpu_lb_read(lb, PERFCOUNTER);
+ mutex_unlock(&lb->mutex);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(layerblend_perfresult);
+
+struct dpu_layerblend *dpu_lb_get(struct dpu_soc *dpu, int id)
+{
+ struct dpu_layerblend *lb;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lb_ids); i++)
+ if (lb_ids[i] == id)
+ break;
+
+ if (i == ARRAY_SIZE(lb_ids))
+ return ERR_PTR(-EINVAL);
+
+ lb = dpu->lb_priv[i];
+
+ mutex_lock(&lb->mutex);
+
+ if (lb->inuse) {
+ lb = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
+ lb->inuse = true;
+out:
+ mutex_unlock(&lb->mutex);
+
+ return lb;
+}
+EXPORT_SYMBOL_GPL(dpu_lb_get);
+
+void dpu_lb_put(struct dpu_layerblend *lb)
+{
+ mutex_lock(&lb->mutex);
+
+ lb->inuse = false;
+
+ mutex_unlock(&lb->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_lb_put);
+
+void _dpu_lb_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_layerblend *lb;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lb_ids); i++)
+ if (lb_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(lb_ids)))
+ return;
+
+ lb = dpu->lb_priv[i];
+
+ layerblend_pixengcfg_dynamic_prim_sel(lb, LB_PRIM_SEL__DISABLE);
+ layerblend_pixengcfg_dynamic_sec_sel(lb, LB_SEC_SEL__DISABLE);
+ layerblend_pixengcfg_clken(lb, CLKEN__AUTOMATIC);
+ layerblend_shdldsel(lb, BOTH);
+ layerblend_shdtoksel(lb, BOTH);
+ layerblend_shden(lb, true);
+}
+
+int dpu_lb_init(struct dpu_soc *dpu, unsigned int id,
+ unsigned long pec_base, unsigned long base)
+{
+ struct dpu_layerblend *lb;
+ int ret;
+
+ lb = devm_kzalloc(dpu->dev, sizeof(*lb), GFP_KERNEL);
+ if (!lb)
+ return -ENOMEM;
+
+ dpu->lb_priv[id] = lb;
+
+ lb->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_16);
+ if (!lb->pec_base)
+ return -ENOMEM;
+
+ lb->base = devm_ioremap(dpu->dev, base, SZ_32);
+ if (!lb->base)
+ return -ENOMEM;
+
+ lb->dpu = dpu;
+ lb->id = id;
+ mutex_init(&lb->mutex);
+
+ ret = layerblend_pixengcfg_dynamic_prim_sel(lb, LB_PRIM_SEL__DISABLE);
+ if (ret < 0)
+ return ret;
+
+ _dpu_lb_init(dpu, id);
+
+ return 0;
+}
diff --git a/drivers/gpu/imx/dpu/dpu-prv.h b/drivers/gpu/imx/dpu/dpu-prv.h
new file mode 100644
index 000000000000..3bfcaad6d252
--- /dev/null
+++ b/drivers/gpu/imx/dpu/dpu-prv.h
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#ifndef __DPU_PRV_H__
+#define __DPU_PRV_H__
+
+#include <drm/drm_fourcc.h>
+#include <video/dpu.h>
+
+#define NA 0xDEADBEEF /* not available */
+
+#define STATICCONTROL 0x8
+#define SHDLDREQSTICKY(lm) (((lm) & 0xFF) << 24)
+#define SHDLDREQSTICKY_MASK (0xFF << 24)
+#define BASEADDRESSAUTOUPDATE(lm) (((lm) & 0xFF) << 16)
+#define BASEADDRESSAUTOUPDATE_MASK (0xFF << 16)
+#define SHDEN BIT(0)
+#define BURSTBUFFERMANAGEMENT 0xC
+#define SETNUMBUFFERS(n) ((n) & 0xFF)
+#define SETBURSTLENGTH(n) (((n) & 0x1F) << 8)
+#define SETBURSTLENGTH_MASK 0x1F00
+#define LINEMODE_MASK 0x80000000U
+#define LINEMODE_SHIFT 31U
+enum linemode {
+ /*
+ * Mandatory setting for operation in the Display Controller.
+ * Works also for Blit Engine with marginal performance impact.
+ */
+ LINEMODE__DISPLAY = 0,
+ /* Recommended setting for operation in the Blit Engine. */
+ LINEMODE__BLIT = 1 << LINEMODE_SHIFT,
+};
+
+#define BITSPERPIXEL(bpp) (((bpp) & 0x3F) << 16)
+#define STRIDE(n) (((n) - 1) & 0xFFFF)
+#define LINEWIDTH(w) (((w) - 1) & 0x3FFF)
+#define LINECOUNT(h) ((((h) - 1) & 0x3FFF) << 16)
+#define ITUFORMAT BIT(31)
+#define R_BITS(n) (((n) & 0xF) << 24)
+#define G_BITS(n) (((n) & 0xF) << 16)
+#define B_BITS(n) (((n) & 0xF) << 8)
+#define A_BITS(n) ((n) & 0xF)
+#define R_SHIFT(n) (((n) & 0x1F) << 24)
+#define G_SHIFT(n) (((n) & 0x1F) << 16)
+#define B_SHIFT(n) (((n) & 0x1F) << 8)
+#define A_SHIFT(n) ((n) & 0x1F)
+#define Y_BITS(n) R_BITS(n)
+#define Y_BITS_MASK 0xF000000
+#define U_BITS(n) G_BITS(n)
+#define U_BITS_MASK 0xF0000
+#define V_BITS(n) B_BITS(n)
+#define V_BITS_MASK 0xF00
+#define Y_SHIFT(n) R_SHIFT(n)
+#define Y_SHIFT_MASK 0x1F000000
+#define U_SHIFT(n) G_SHIFT(n)
+#define U_SHIFT_MASK 0x1F0000
+#define V_SHIFT(n) B_SHIFT(n)
+#define V_SHIFT_MASK 0x1F00
+#define LAYERXOFFSET(x) ((x) & 0x7FFF)
+#define LAYERYOFFSET(y) (((y) & 0x7FFF) << 16)
+#define CLIPWINDOWXOFFSET(x) ((x) & 0x7FFF)
+#define CLIPWINDOWYOFFSET(y) (((y) & 0x7FFF) << 16)
+#define CLIPWINDOWWIDTH(w) (((w) - 1) & 0x3FFF)
+#define CLIPWINDOWHEIGHT(h) ((((h) - 1) & 0x3FFF) << 16)
+#define PALETTEENABLE BIT(0)
+typedef enum {
+ TILE_FILL_ZERO,
+ TILE_FILL_CONSTANT,
+ TILE_PAD,
+ TILE_PAD_ZERO,
+} tilemode_t;
+#define ALPHASRCENABLE BIT(8)
+#define ALPHACONSTENABLE BIT(9)
+#define ALPHAMASKENABLE BIT(10)
+#define ALPHATRANSENABLE BIT(11)
+#define RGBALPHASRCENABLE BIT(12)
+#define RGBALPHACONSTENABLE BIT(13)
+#define RGBALPHAMASKENABLE BIT(14)
+#define RGBALPHATRANSENABLE BIT(15)
+#define PREMULCONSTRGB BIT(16)
+typedef enum {
+ YUVCONVERSIONMODE__OFF,
+ YUVCONVERSIONMODE__ITU601,
+ YUVCONVERSIONMODE__ITU601_FR,
+ YUVCONVERSIONMODE__ITU709,
+} yuvconversionmode_t;
+#define YUVCONVERSIONMODE_MASK 0x60000
+#define YUVCONVERSIONMODE(m) (((m) & 0x3) << 17)
+#define GAMMAREMOVEENABLE BIT(20)
+#define CLIPWINDOWENABLE BIT(30)
+#define SOURCEBUFFERENABLE BIT(31)
+#define EMPTYFRAME BIT(31)
+#define FRAMEWIDTH(w) (((w) - 1) & 0x3FFF)
+#define FRAMEHEIGHT(h) ((((h) - 1) & 0x3FFF) << 16)
+#define DELTAX_MASK 0x3F000
+#define DELTAY_MASK 0xFC0000
+#define DELTAX(x) (((x) & 0x3F) << 12)
+#define DELTAY(y) (((y) & 0x3F) << 18)
+#define YUV422UPSAMPLINGMODE_MASK BIT(5)
+#define YUV422UPSAMPLINGMODE(m) (((m) & 0x1) << 5)
+typedef enum {
+ YUV422UPSAMPLINGMODE__REPLICATE,
+ YUV422UPSAMPLINGMODE__INTERPOLATE,
+} yuv422upsamplingmode_t;
+#define INPUTSELECT_MASK 0x18
+#define INPUTSELECT(s) (((s) & 0x3) << 3)
+typedef enum {
+ INPUTSELECT__INACTIVE,
+ INPUTSELECT__COMPPACK,
+ INPUTSELECT__ALPHAMASK,
+ INPUTSELECT__COORDINATE,
+} inputselect_t;
+#define RASTERMODE_MASK 0x7
+#define RASTERMODE(m) ((m) & 0x7)
+typedef enum {
+ RASTERMODE__NORMAL,
+ RASTERMODE__DECODE,
+ RASTERMODE__ARBITRARY,
+ RASTERMODE__PERSPECTIVE,
+ RASTERMODE__YUV422,
+ RASTERMODE__AFFINE,
+} rastermode_t;
+#define SHDTOKGEN BIT(0)
+#define FETCHTYPE_MASK 0xF
+
+#define DPU_FRAC_PLANE_LAYER_NUM 8
+
+enum {
+ DPU_V1,
+ DPU_V2,
+};
+
+#define DPU_VPROC_CAP_HSCALER4 BIT(0)
+#define DPU_VPROC_CAP_VSCALER4 BIT(1)
+#define DPU_VPROC_CAP_HSCALER5 BIT(2)
+#define DPU_VPROC_CAP_VSCALER5 BIT(3)
+#define DPU_VPROC_CAP_FETCHECO0 BIT(4)
+#define DPU_VPROC_CAP_FETCHECO1 BIT(5)
+
+#define DPU_VPROC_CAP_HSCALE (DPU_VPROC_CAP_HSCALER4 | \
+ DPU_VPROC_CAP_HSCALER5)
+#define DPU_VPROC_CAP_VSCALE (DPU_VPROC_CAP_VSCALER4 | \
+ DPU_VPROC_CAP_VSCALER5)
+#define DPU_VPROC_CAP_FETCHECO (DPU_VPROC_CAP_FETCHECO0 | \
+ DPU_VPROC_CAP_FETCHECO1)
+
+struct dpu_unit {
+ char *name;
+ unsigned int num;
+ const unsigned int *ids;
+ const unsigned long *pec_ofss; /* PixEngCFG */
+ const unsigned long *ofss;
+ const unsigned int *dprc_ids;
+};
+
+struct cm_reg_ofs {
+ u32 ipidentifier;
+ u32 lockunlock;
+ u32 lockstatus;
+ u32 userinterruptmask;
+ u32 interruptenable;
+ u32 interruptpreset;
+ u32 interruptclear;
+ u32 interruptstatus;
+ u32 userinterruptenable;
+ u32 userinterruptpreset;
+ u32 userinterruptclear;
+ u32 userinterruptstatus;
+ u32 generalpurpose;
+};
+
+struct dpu_devtype {
+ const unsigned long cm_ofs; /* common */
+ const struct dpu_unit *cfs;
+ const struct dpu_unit *decs;
+ const struct dpu_unit *eds;
+ const struct dpu_unit *fds;
+ const struct dpu_unit *fes;
+ const struct dpu_unit *fgs;
+ const struct dpu_unit *fls;
+ const struct dpu_unit *fws;
+ const struct dpu_unit *hss;
+ const struct dpu_unit *lbs;
+ const struct dpu_unit *tcons;
+ const struct dpu_unit *vss;
+ const struct cm_reg_ofs *cm_reg_ofs;
+ const unsigned int *intsteer_map;
+ const unsigned int intsteer_map_size;
+ const unsigned long *unused_irq;
+ const unsigned int *sw2hw_irq_map; /* NULL means linear */
+ const unsigned int *sw2hw_block_id_map; /* NULL means linear */
+ /*
+ * index: 0 1 2 3 4 5 6
+ * source: fl0(sub0) fl1(sub0) fw2(sub0) fd0 fd1 fd2 fd3
+ */
+ const u32 plane_src_na_mask;
+ bool has_capture;
+ bool has_prefetch;
+ bool has_disp_sel_clk;
+ bool has_dual_ldb;
+ bool pixel_link_quirks;
+ bool pixel_link_nhvsync; /* HSYNC and VSYNC high active */
+ unsigned int version;
+};
+
+struct dpu_soc {
+ struct device *dev;
+ const struct dpu_devtype *devtype;
+ spinlock_t lock;
+
+ void __iomem *cm_reg;
+
+ int id;
+ int usecount;
+
+ struct regmap *intsteer_regmap;
+ int intsteer_usecount;
+ spinlock_t intsteer_lock;
+ int irq_cm; /* irq common */
+ int irq_stream0a;
+ int irq_stream1a;
+ int irq_reserved0;
+ int irq_reserved1;
+ int irq_blit;
+ int irq_dpr0;
+ int irq_dpr1;
+ struct irq_domain *domain;
+
+ struct dpu_constframe *cf_priv[4];
+ struct dpu_disengcfg *dec_priv[2];
+ struct dpu_extdst *ed_priv[4];
+ struct dpu_fetchunit *fd_priv[4];
+ struct dpu_fetchunit *fe_priv[4];
+ struct dpu_framegen *fg_priv[2];
+ struct dpu_fetchunit *fl_priv[2];
+ struct dpu_fetchunit *fw_priv[1];
+ struct dpu_hscaler *hs_priv[3];
+ struct dpu_layerblend *lb_priv[7];
+ struct dpu_tcon *tcon_priv[2];
+ struct dpu_vscaler *vs_priv[3];
+};
+
+int dpu_format_horz_chroma_subsampling(u32 format);
+int dpu_format_vert_chroma_subsampling(u32 format);
+int dpu_format_num_planes(u32 format);
+int dpu_format_plane_width(int width, u32 format, int plane);
+int dpu_format_plane_height(int height, u32 format, int plane);
+
+#define _DECLARE_DPU_UNIT_INIT_FUNC(block) \
+void _dpu_##block##_init(struct dpu_soc *dpu, unsigned int id) \
+
+_DECLARE_DPU_UNIT_INIT_FUNC(cf);
+_DECLARE_DPU_UNIT_INIT_FUNC(dec);
+_DECLARE_DPU_UNIT_INIT_FUNC(ed);
+_DECLARE_DPU_UNIT_INIT_FUNC(fd);
+_DECLARE_DPU_UNIT_INIT_FUNC(fe);
+_DECLARE_DPU_UNIT_INIT_FUNC(fg);
+_DECLARE_DPU_UNIT_INIT_FUNC(fl);
+_DECLARE_DPU_UNIT_INIT_FUNC(fw);
+_DECLARE_DPU_UNIT_INIT_FUNC(hs);
+_DECLARE_DPU_UNIT_INIT_FUNC(lb);
+_DECLARE_DPU_UNIT_INIT_FUNC(tcon);
+_DECLARE_DPU_UNIT_INIT_FUNC(vs);
+
+#define DECLARE_DPU_UNIT_INIT_FUNC(block) \
+int dpu_##block##_init(struct dpu_soc *dpu, unsigned int id, \
+ unsigned long pec_base, unsigned long base)
+
+DECLARE_DPU_UNIT_INIT_FUNC(cf);
+DECLARE_DPU_UNIT_INIT_FUNC(dec);
+DECLARE_DPU_UNIT_INIT_FUNC(ed);
+DECLARE_DPU_UNIT_INIT_FUNC(fd);
+DECLARE_DPU_UNIT_INIT_FUNC(fe);
+DECLARE_DPU_UNIT_INIT_FUNC(fg);
+DECLARE_DPU_UNIT_INIT_FUNC(fl);
+DECLARE_DPU_UNIT_INIT_FUNC(fw);
+DECLARE_DPU_UNIT_INIT_FUNC(hs);
+DECLARE_DPU_UNIT_INIT_FUNC(lb);
+DECLARE_DPU_UNIT_INIT_FUNC(tcon);
+DECLARE_DPU_UNIT_INIT_FUNC(vs);
+
+static inline u32 dpu_pec_fu_read(struct dpu_fetchunit *fu, unsigned int offset)
+{
+ return readl(fu->pec_base + offset);
+}
+
+static inline void dpu_pec_fu_write(struct dpu_fetchunit *fu, u32 value,
+ unsigned int offset)
+{
+ writel(value, fu->pec_base + offset);
+}
+
+static inline u32 dpu_fu_read(struct dpu_fetchunit *fu, unsigned int offset)
+{
+ return readl(fu->base + offset);
+}
+
+static inline void dpu_fu_write(struct dpu_fetchunit *fu, u32 value,
+ unsigned int offset)
+{
+ writel(value, fu->base + offset);
+}
+
+static inline u32 rgb_color(u8 r, u8 g, u8 b, u8 a)
+{
+ return (r << 24) | (g << 16) | (b << 8) | a;
+}
+
+static inline u32 yuv_color(u8 y, u8 u, u8 v)
+{
+ return (y << 24) | (u << 16) | (v << 8);
+}
+
+static const unsigned int cf_ids[] = {0, 1, 4, 5};
+static const unsigned int dec_ids[] = {0, 1};
+static const unsigned int ed_ids[] = {0, 1, 4, 5};
+static const unsigned int fd_ids[] = {0, 1, 2, 3};
+static const unsigned int fe_ids[] = {0, 1, 2, 9};
+static const unsigned int fg_ids[] = {0, 1};
+static const unsigned int fl_ids[] = {0, 1};
+static const unsigned int fw_ids[] = {2};
+static const unsigned int hs_ids[] = {4, 5, 9};
+static const unsigned int lb_ids[] = {0, 1, 2, 3, 4, 5, 6};
+static const unsigned int tcon_ids[] = {0, 1};
+static const unsigned int vs_ids[] = {4, 5, 9};
+
+static const unsigned int fd_dprc_ids[] = {3, 4};
+static const unsigned int fl_dprc_ids[] = {2};
+static const unsigned int fw_dprc_ids[] = {5};
+
+struct dpu_pixel_format {
+ u32 pixel_format;
+ u32 bits;
+ u32 shift;
+};
+
+static const struct dpu_pixel_format dpu_pixel_format_matrix[] = {
+ {
+ DRM_FORMAT_ARGB8888,
+ R_BITS(8) | G_BITS(8) | B_BITS(8) | A_BITS(8),
+ R_SHIFT(16) | G_SHIFT(8) | B_SHIFT(0) | A_SHIFT(24),
+ }, {
+ DRM_FORMAT_XRGB8888,
+ R_BITS(8) | G_BITS(8) | B_BITS(8) | A_BITS(0),
+ R_SHIFT(16) | G_SHIFT(8) | B_SHIFT(0) | A_SHIFT(0),
+ }, {
+ DRM_FORMAT_ABGR8888,
+ R_BITS(8) | G_BITS(8) | B_BITS(8) | A_BITS(8),
+ R_SHIFT(0) | G_SHIFT(8) | B_SHIFT(16) | A_SHIFT(24),
+ }, {
+ DRM_FORMAT_XBGR8888,
+ R_BITS(8) | G_BITS(8) | B_BITS(8) | A_BITS(0),
+ R_SHIFT(0) | G_SHIFT(8) | B_SHIFT(16) | A_SHIFT(0),
+ }, {
+ DRM_FORMAT_RGBA8888,
+ R_BITS(8) | G_BITS(8) | B_BITS(8) | A_BITS(8),
+ R_SHIFT(24) | G_SHIFT(16) | B_SHIFT(8) | A_SHIFT(0),
+ }, {
+ DRM_FORMAT_RGBX8888,
+ R_BITS(8) | G_BITS(8) | B_BITS(8) | A_BITS(0),
+ R_SHIFT(24) | G_SHIFT(16) | B_SHIFT(8) | A_SHIFT(0),
+ }, {
+ DRM_FORMAT_BGRA8888,
+ R_BITS(8) | G_BITS(8) | B_BITS(8) | A_BITS(8),
+ R_SHIFT(8) | G_SHIFT(16) | B_SHIFT(24) | A_SHIFT(0),
+ }, {
+ DRM_FORMAT_BGRX8888,
+ R_BITS(8) | G_BITS(8) | B_BITS(8) | A_BITS(0),
+ R_SHIFT(8) | G_SHIFT(16) | B_SHIFT(24) | A_SHIFT(0),
+ }, {
+ DRM_FORMAT_RGB888,
+ R_BITS(8) | G_BITS(8) | B_BITS(8) | A_BITS(0),
+ R_SHIFT(16) | G_SHIFT(8) | B_SHIFT(0) | A_SHIFT(0),
+ }, {
+ DRM_FORMAT_BGR888,
+ R_BITS(8) | G_BITS(8) | B_BITS(8) | A_BITS(0),
+ R_SHIFT(0) | G_SHIFT(8) | B_SHIFT(16) | A_SHIFT(0),
+ }, {
+ DRM_FORMAT_RGB565,
+ R_BITS(5) | G_BITS(6) | B_BITS(5) | A_BITS(0),
+ R_SHIFT(11) | G_SHIFT(5) | B_SHIFT(0) | A_SHIFT(0),
+ }, {
+ DRM_FORMAT_YUYV,
+ Y_BITS(8) | U_BITS(8) | V_BITS(8) | A_BITS(0),
+ Y_SHIFT(0) | U_SHIFT(8) | V_SHIFT(8) | A_SHIFT(0),
+ }, {
+ DRM_FORMAT_UYVY,
+ Y_BITS(8) | U_BITS(8) | V_BITS(8) | A_BITS(0),
+ Y_SHIFT(8) | U_SHIFT(0) | V_SHIFT(0) | A_SHIFT(0),
+ }, {
+ DRM_FORMAT_NV12,
+ Y_BITS(8) | U_BITS(8) | V_BITS(8) | A_BITS(0),
+ Y_SHIFT(0) | U_SHIFT(0) | V_SHIFT(8) | A_SHIFT(0),
+ }, {
+ DRM_FORMAT_NV21,
+ Y_BITS(8) | U_BITS(8) | V_BITS(8) | A_BITS(0),
+ Y_SHIFT(0) | U_SHIFT(8) | V_SHIFT(0) | A_SHIFT(0),
+ }, {
+ DRM_FORMAT_NV16,
+ Y_BITS(8) | U_BITS(8) | V_BITS(8) | A_BITS(0),
+ Y_SHIFT(0) | U_SHIFT(0) | V_SHIFT(8) | A_SHIFT(0),
+ }, {
+ DRM_FORMAT_NV61,
+ Y_BITS(8) | U_BITS(8) | V_BITS(8) | A_BITS(0),
+ Y_SHIFT(0) | U_SHIFT(8) | V_SHIFT(0) | A_SHIFT(0),
+ }, {
+ DRM_FORMAT_NV24,
+ Y_BITS(8) | U_BITS(8) | V_BITS(8) | A_BITS(0),
+ Y_SHIFT(0) | U_SHIFT(0) | V_SHIFT(8) | A_SHIFT(0),
+ }, {
+ DRM_FORMAT_NV42,
+ Y_BITS(8) | U_BITS(8) | V_BITS(8) | A_BITS(0),
+ Y_SHIFT(0) | U_SHIFT(8) | V_SHIFT(0) | A_SHIFT(0),
+ },
+};
+
+#endif /* __DPU_PRV_H__ */
diff --git a/drivers/gpu/imx/dpu/dpu-tcon.c b/drivers/gpu/imx/dpu/dpu-tcon.c
new file mode 100644
index 000000000000..a0a94ce0f47d
--- /dev/null
+++ b/drivers/gpu/imx/dpu/dpu-tcon.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/media-bus-format.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define SSQCNTS 0
+#define SSQCYCLE 0x8
+#define SWRESET 0xC
+#define TCON_CTRL 0x10
+#define BYPASS BIT(3)
+#define RSDSINVCTRL 0x14
+#define MAPBIT3_0 0x18
+#define MAPBIT7_4 0x1C
+#define MAPBIT11_8 0x20
+#define MAPBIT15_12 0x24
+#define MAPBIT19_16 0x28
+#define MAPBIT23_20 0x2C
+#define MAPBIT27_24 0x30
+#define MAPBIT31_28 0x34
+#define MAPBIT34_32 0x38
+#define MAPBIT3_0_DUAL 0x3C
+#define MAPBIT7_4_DUAL 0x40
+#define MAPBIT11_8_DUAL 0x44
+#define MAPBIT15_12_DUAL 0x48
+#define MAPBIT19_16_DUAL 0x4C
+#define MAPBIT23_20_DUAL 0x50
+#define MAPBIT27_24_DUAL 0x54
+#define MAPBIT31_28_DUAL 0x58
+#define MAPBIT34_32_DUAL 0x5C
+#define SPGPOSON(n) (0x60 + (n) * 16)
+#define X(n) (((n) & 0x7FFF) << 16)
+#define Y(n) ((n) & 0x7FFF)
+#define SPGMASKON(n) (0x64 + (n) * 16)
+#define SPGPOSOFF(n) (0x68 + (n) * 16)
+#define SPGMASKOFF(n) (0x6C + (n) * 16)
+#define SMXSIGS(n) (0x120 + (n) * 8)
+#define SMXFCTTABLE(n) (0x124 + (n) * 8)
+#define RESET_OVER_UNFERFLOW 0x180
+#define DUAL_DEBUG 0x184
+
+struct dpu_tcon {
+ void __iomem *base;
+ struct mutex mutex;
+ int id;
+ bool inuse;
+ struct dpu_soc *dpu;
+};
+
+static inline u32 dpu_tcon_read(struct dpu_tcon *tcon, unsigned int offset)
+{
+ return readl(tcon->base + offset);
+}
+
+static inline void dpu_tcon_write(struct dpu_tcon *tcon, u32 value,
+ unsigned int offset)
+{
+ writel(value, tcon->base + offset);
+}
+
+int tcon_set_fmt(struct dpu_tcon *tcon, u32 bus_format)
+{
+ mutex_lock(&tcon->mutex);
+ switch (bus_format) {
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ dpu_tcon_write(tcon, 0x19181716, MAPBIT3_0);
+ dpu_tcon_write(tcon, 0x1d1c1b1a, MAPBIT7_4);
+ dpu_tcon_write(tcon, 0x0f0e0d0c, MAPBIT11_8);
+ dpu_tcon_write(tcon, 0x13121110, MAPBIT15_12);
+ dpu_tcon_write(tcon, 0x05040302, MAPBIT19_16);
+ dpu_tcon_write(tcon, 0x09080706, MAPBIT23_20);
+ break;
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ case MEDIA_BUS_FMT_RGB888_1X30_PADLO:
+ case MEDIA_BUS_FMT_RGB666_1X30_PADLO:
+ dpu_tcon_write(tcon, 0x17161514, MAPBIT3_0);
+ dpu_tcon_write(tcon, 0x1b1a1918, MAPBIT7_4);
+ dpu_tcon_write(tcon, 0x0b0a1d1c, MAPBIT11_8);
+ dpu_tcon_write(tcon, 0x0f0e0d0c, MAPBIT15_12);
+ dpu_tcon_write(tcon, 0x13121110, MAPBIT19_16);
+ dpu_tcon_write(tcon, 0x03020100, MAPBIT23_20);
+ dpu_tcon_write(tcon, 0x07060504, MAPBIT27_24);
+ dpu_tcon_write(tcon, 0x00000908, MAPBIT31_28);
+ break;
+ default:
+ mutex_unlock(&tcon->mutex);
+ return -EINVAL;
+ }
+ mutex_unlock(&tcon->mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tcon_set_fmt);
+
+/* This function is used to workaround TKT320590 which is related to DPR/PRG. */
+void tcon_set_operation_mode(struct dpu_tcon *tcon)
+{
+ u32 val;
+
+ mutex_lock(&tcon->mutex);
+ val = dpu_tcon_read(tcon, TCON_CTRL);
+ val &= ~BYPASS;
+ dpu_tcon_write(tcon, val, TCON_CTRL);
+ mutex_unlock(&tcon->mutex);
+}
+EXPORT_SYMBOL_GPL(tcon_set_operation_mode);
+
+void tcon_cfg_videomode(struct dpu_tcon *tcon, struct drm_display_mode *m)
+{
+ u32 val;
+
+ mutex_lock(&tcon->mutex);
+ /*
+ * TKT320590:
+ * Turn TCON into operation mode later after the first dumb frame is
+ * generated by DPU. This makes DPR/PRG be able to evade the frame.
+ */
+ val = dpu_tcon_read(tcon, TCON_CTRL);
+ val |= BYPASS;
+ dpu_tcon_write(tcon, val, TCON_CTRL);
+
+ /* dsp_control[0]: hsync */
+ dpu_tcon_write(tcon, X(m->hsync_start), SPGPOSON(0));
+ dpu_tcon_write(tcon, 0xffff, SPGMASKON(0));
+
+ dpu_tcon_write(tcon, X(m->hsync_end), SPGPOSOFF(0));
+ dpu_tcon_write(tcon, 0xffff, SPGMASKOFF(0));
+
+ dpu_tcon_write(tcon, 0x2, SMXSIGS(0));
+ dpu_tcon_write(tcon, 0x1, SMXFCTTABLE(0));
+
+ /* dsp_control[1]: vsync */
+ dpu_tcon_write(tcon, X(m->hsync_start) | Y(m->vsync_start - 1),
+ SPGPOSON(1));
+ dpu_tcon_write(tcon, 0x0, SPGMASKON(1));
+
+ dpu_tcon_write(tcon, X(m->hsync_start) | Y(m->vsync_end - 1),
+ SPGPOSOFF(1));
+ dpu_tcon_write(tcon, 0x0, SPGMASKOFF(1));
+
+ dpu_tcon_write(tcon, 0x3, SMXSIGS(1));
+ dpu_tcon_write(tcon, 0x1, SMXFCTTABLE(1));
+
+ /* dsp_control[2]: data enable */
+ /* horizontal */
+ dpu_tcon_write(tcon, 0x0, SPGPOSON(2));
+ dpu_tcon_write(tcon, 0xffff, SPGMASKON(2));
+
+ dpu_tcon_write(tcon, X(m->hdisplay), SPGPOSOFF(2));
+ dpu_tcon_write(tcon, 0xffff, SPGMASKOFF(2));
+
+ /* vertical */
+ dpu_tcon_write(tcon, 0x0, SPGPOSON(3));
+ dpu_tcon_write(tcon, 0x7fff0000, SPGMASKON(3));
+
+ dpu_tcon_write(tcon, Y(m->vdisplay), SPGPOSOFF(3));
+ dpu_tcon_write(tcon, 0x7fff0000, SPGMASKOFF(3));
+
+ dpu_tcon_write(tcon, 0x2c, SMXSIGS(2));
+ dpu_tcon_write(tcon, 0x8, SMXFCTTABLE(2));
+
+ /* dsp_control[3]: kachuck */
+ dpu_tcon_write(tcon, X(0xa) | Y(m->vdisplay), SPGPOSON(4));
+ dpu_tcon_write(tcon, 0x0, SPGMASKON(4));
+
+ dpu_tcon_write(tcon, X(0x2a) | Y(m->vdisplay), SPGPOSOFF(4));
+ dpu_tcon_write(tcon, 0x0, SPGMASKOFF(4));
+
+ dpu_tcon_write(tcon, 0x6, SMXSIGS(3));
+ dpu_tcon_write(tcon, 0x2, SMXFCTTABLE(3));
+ mutex_unlock(&tcon->mutex);
+}
+EXPORT_SYMBOL_GPL(tcon_cfg_videomode);
+
+struct dpu_tcon *dpu_tcon_get(struct dpu_soc *dpu, int id)
+{
+ struct dpu_tcon *tcon;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tcon_ids); i++)
+ if (tcon_ids[i] == id)
+ break;
+
+ if (i == ARRAY_SIZE(tcon_ids))
+ return ERR_PTR(-EINVAL);
+
+ tcon = dpu->tcon_priv[i];
+
+ mutex_lock(&tcon->mutex);
+
+ if (tcon->inuse) {
+ tcon = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
+ tcon->inuse = true;
+out:
+ mutex_unlock(&tcon->mutex);
+
+ return tcon;
+}
+EXPORT_SYMBOL_GPL(dpu_tcon_get);
+
+void dpu_tcon_put(struct dpu_tcon *tcon)
+{
+ mutex_lock(&tcon->mutex);
+
+ tcon->inuse = false;
+
+ mutex_unlock(&tcon->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_tcon_put);
+
+void _dpu_tcon_init(struct dpu_soc *dpu, unsigned int id)
+{
+}
+
+int dpu_tcon_init(struct dpu_soc *dpu, unsigned int id,
+ unsigned long unused, unsigned long base)
+{
+ struct dpu_tcon *tcon;
+
+ tcon = devm_kzalloc(dpu->dev, sizeof(*tcon), GFP_KERNEL);
+ if (!tcon)
+ return -ENOMEM;
+
+ dpu->tcon_priv[id] = tcon;
+
+ tcon->base = devm_ioremap(dpu->dev, base, SZ_512);
+ if (!tcon->base)
+ return -ENOMEM;
+
+ tcon->dpu = dpu;
+ mutex_init(&tcon->mutex);
+
+ return 0;
+}
diff --git a/drivers/gpu/imx/dpu/dpu-vscaler.c b/drivers/gpu/imx/dpu/dpu-vscaler.c
new file mode 100644
index 000000000000..d58042b80402
--- /dev/null
+++ b/drivers/gpu/imx/dpu/dpu-vscaler.c
@@ -0,0 +1,444 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <video/dpu.h>
+#include "dpu-prv.h"
+
+#define PIXENGCFG_DYNAMIC 0x8
+#define PIXENGCFG_DYNAMIC_SRC_SEL_MASK 0x3F
+
+#define SETUP1 0xC
+#define SCALE_FACTOR_MASK 0xFFFFF
+#define SCALE_FACTOR(n) ((n) & 0xFFFFF)
+#define SETUP2 0x10
+#define SETUP3 0x14
+#define SETUP4 0x18
+#define SETUP5 0x1C
+#define PHASE_OFFSET_MASK 0x1FFFFF
+#define PHASE_OFFSET(n) ((n) & 0x1FFFFF)
+#define CONTROL 0x20
+#define OUTPUT_SIZE_MASK 0x3FFF0000
+#define OUTPUT_SIZE(n) ((((n) - 1) << 16) & OUTPUT_SIZE_MASK)
+#define FIELD_MODE 0x3000
+#define FILTER_MODE 0x100
+#define SCALE_MODE 0x10
+#define MODE 0x1
+
+static const vs_src_sel_t src_sels[3][6] = {
+ {
+ VS_SRC_SEL__DISABLE,
+ VS_SRC_SEL__EXTSRC4,
+ VS_SRC_SEL__FETCHDECODE0,
+ VS_SRC_SEL__FETCHDECODE2,
+ VS_SRC_SEL__MATRIX4,
+ VS_SRC_SEL__HSCALER4,
+ }, {
+ VS_SRC_SEL__DISABLE,
+ VS_SRC_SEL__EXTSRC5,
+ VS_SRC_SEL__FETCHDECODE1,
+ VS_SRC_SEL__FETCHDECODE3,
+ VS_SRC_SEL__MATRIX5,
+ VS_SRC_SEL__HSCALER5,
+ }, {
+ VS_SRC_SEL__DISABLE,
+ VS_SRC_SEL__MATRIX9,
+ VS_SRC_SEL__HSCALER9,
+ },
+};
+
+struct dpu_vscaler {
+ void __iomem *pec_base;
+ void __iomem *base;
+ struct mutex mutex;
+ int id;
+ bool inuse;
+ struct dpu_soc *dpu;
+ /* see DPU_PLANE_SRC_xxx */
+ unsigned int stream_id;
+};
+
+static inline u32 dpu_pec_vs_read(struct dpu_vscaler *vs,
+ unsigned int offset)
+{
+ return readl(vs->pec_base + offset);
+}
+
+static inline void dpu_pec_vs_write(struct dpu_vscaler *vs, u32 value,
+ unsigned int offset)
+{
+ writel(value, vs->pec_base + offset);
+}
+
+static inline u32 dpu_vs_read(struct dpu_vscaler *vs, unsigned int offset)
+{
+ return readl(vs->base + offset);
+}
+
+static inline void dpu_vs_write(struct dpu_vscaler *vs, u32 value,
+ unsigned int offset)
+{
+ writel(value, vs->base + offset);
+}
+
+int vscaler_pixengcfg_dynamic_src_sel(struct dpu_vscaler *vs, vs_src_sel_t src)
+{
+ struct dpu_soc *dpu = vs->dpu;
+ const unsigned int *block_id_map = dpu->devtype->sw2hw_block_id_map;
+ const unsigned int vs_id_array[] = {4, 5, 9};
+ int i, j;
+ u32 val, mapped_src;
+
+ for (i = 0; i < ARRAY_SIZE(vs_id_array); i++)
+ if (vs_id_array[i] == vs->id)
+ break;
+
+ if (WARN_ON(i == (ARRAY_SIZE(vs_id_array) + 1)))
+ return -EINVAL;
+
+ mutex_lock(&vs->mutex);
+ for (j = 0; j < ARRAY_SIZE(src_sels[0]); j++) {
+ if (src_sels[i][j] == src) {
+ mapped_src = block_id_map ? block_id_map[src] : src;
+ if (WARN_ON(mapped_src == NA))
+ return -EINVAL;
+
+ val = dpu_pec_vs_read(vs, PIXENGCFG_DYNAMIC);
+ val &= ~PIXENGCFG_DYNAMIC_SRC_SEL_MASK;
+ val |= mapped_src;
+ dpu_pec_vs_write(vs, val, PIXENGCFG_DYNAMIC);
+ mutex_unlock(&vs->mutex);
+ return 0;
+ }
+ }
+ mutex_unlock(&vs->mutex);
+
+ dev_err(dpu->dev, "Invalid source for VScaler%d\n", vs->id);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(vscaler_pixengcfg_dynamic_src_sel);
+
+void vscaler_pixengcfg_clken(struct dpu_vscaler *vs, pixengcfg_clken_t clken)
+{
+ u32 val;
+
+ mutex_lock(&vs->mutex);
+ val = dpu_pec_vs_read(vs, PIXENGCFG_DYNAMIC);
+ val &= ~CLKEN_MASK;
+ val |= clken << CLKEN_MASK_SHIFT;
+ dpu_pec_vs_write(vs, val, PIXENGCFG_DYNAMIC);
+ mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_pixengcfg_clken);
+
+void vscaler_shden(struct dpu_vscaler *vs, bool enable)
+{
+ u32 val;
+
+ mutex_lock(&vs->mutex);
+ val = dpu_vs_read(vs, STATICCONTROL);
+ if (enable)
+ val |= SHDEN;
+ else
+ val &= ~SHDEN;
+ dpu_vs_write(vs, val, STATICCONTROL);
+ mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_shden);
+
+void vscaler_setup1(struct dpu_vscaler *vs, u32 src, u32 dst, bool deinterlace)
+{
+ struct dpu_soc *dpu = vs->dpu;
+ u32 scale_factor;
+ u64 tmp64;
+
+ if (deinterlace)
+ dst *= 2;
+
+ if (src == dst) {
+ scale_factor = 0x80000;
+ } else {
+ if (src > dst) {
+ tmp64 = (u64)((u64)dst * 0x80000);
+ do_div(tmp64, src);
+
+ } else {
+ tmp64 = (u64)((u64)src * 0x80000);
+ do_div(tmp64, dst);
+ }
+ scale_factor = (u32)tmp64;
+ }
+
+ WARN_ON(scale_factor > 0x80000);
+
+ mutex_lock(&vs->mutex);
+ dpu_vs_write(vs, SCALE_FACTOR(scale_factor), SETUP1);
+ mutex_unlock(&vs->mutex);
+
+ dev_dbg(dpu->dev, "Vscaler%d scale factor 0x%08x\n",
+ vs->id, scale_factor);
+}
+EXPORT_SYMBOL_GPL(vscaler_setup1);
+
+void vscaler_setup2(struct dpu_vscaler *vs, bool deinterlace)
+{
+ /* 0x20000: +0.25 phase offset for deinterlace */
+ u32 phase_offset = deinterlace ? 0x20000 : 0;
+
+ mutex_lock(&vs->mutex);
+ dpu_vs_write(vs, PHASE_OFFSET(phase_offset), SETUP2);
+ mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_setup2);
+
+void vscaler_setup3(struct dpu_vscaler *vs, bool deinterlace)
+{
+ /* 0x1e0000: -0.25 phase offset for deinterlace */
+ u32 phase_offset = deinterlace ? 0x1e0000 : 0;
+
+ mutex_lock(&vs->mutex);
+ dpu_vs_write(vs, PHASE_OFFSET(phase_offset), SETUP3);
+ mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_setup3);
+
+void vscaler_setup4(struct dpu_vscaler *vs, u32 phase_offset)
+{
+ mutex_lock(&vs->mutex);
+ dpu_vs_write(vs, PHASE_OFFSET(phase_offset), SETUP4);
+ mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_setup4);
+
+void vscaler_setup5(struct dpu_vscaler *vs, u32 phase_offset)
+{
+ mutex_lock(&vs->mutex);
+ dpu_vs_write(vs, PHASE_OFFSET(phase_offset), SETUP5);
+ mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_setup5);
+
+void vscaler_output_size(struct dpu_vscaler *vs, u32 line_num)
+{
+ u32 val;
+
+ mutex_lock(&vs->mutex);
+ val = dpu_vs_read(vs, CONTROL);
+ val &= ~OUTPUT_SIZE_MASK;
+ val |= OUTPUT_SIZE(line_num);
+ dpu_vs_write(vs, val, CONTROL);
+ mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_output_size);
+
+void vscaler_field_mode(struct dpu_vscaler *vs, scaler_field_mode_t m)
+{
+ u32 val;
+
+ mutex_lock(&vs->mutex);
+ val = dpu_vs_read(vs, CONTROL);
+ val &= ~FIELD_MODE;
+ val |= m;
+ dpu_vs_write(vs, val, CONTROL);
+ mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_field_mode);
+
+void vscaler_filter_mode(struct dpu_vscaler *vs, scaler_filter_mode_t m)
+{
+ u32 val;
+
+ mutex_lock(&vs->mutex);
+ val = dpu_vs_read(vs, CONTROL);
+ val &= ~FILTER_MODE;
+ val |= m;
+ dpu_vs_write(vs, val, CONTROL);
+ mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_filter_mode);
+
+void vscaler_scale_mode(struct dpu_vscaler *vs, scaler_scale_mode_t m)
+{
+ u32 val;
+
+ mutex_lock(&vs->mutex);
+ val = dpu_vs_read(vs, CONTROL);
+ val &= ~SCALE_MODE;
+ val |= m;
+ dpu_vs_write(vs, val, CONTROL);
+ mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_scale_mode);
+
+void vscaler_mode(struct dpu_vscaler *vs, scaler_mode_t m)
+{
+ u32 val;
+
+ mutex_lock(&vs->mutex);
+ val = dpu_vs_read(vs, CONTROL);
+ val &= ~MODE;
+ val |= m;
+ dpu_vs_write(vs, val, CONTROL);
+ mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(vscaler_mode);
+
+bool vscaler_is_enabled(struct dpu_vscaler *vs)
+{
+ u32 val;
+
+ mutex_lock(&vs->mutex);
+ val = dpu_vs_read(vs, CONTROL);
+ mutex_unlock(&vs->mutex);
+
+ return (val & MODE) == SCALER_ACTIVE;
+}
+EXPORT_SYMBOL_GPL(vscaler_is_enabled);
+
+dpu_block_id_t vscaler_get_block_id(struct dpu_vscaler *vs)
+{
+ switch (vs->id) {
+ case 4:
+ return ID_VSCALER4;
+ case 5:
+ return ID_VSCALER5;
+ case 9:
+ return ID_VSCALER9;
+ default:
+ WARN_ON(1);
+ }
+
+ return ID_NONE;
+}
+EXPORT_SYMBOL_GPL(vscaler_get_block_id);
+
+unsigned int vscaler_get_stream_id(struct dpu_vscaler *vs)
+{
+ return vs->stream_id;
+}
+EXPORT_SYMBOL_GPL(vscaler_get_stream_id);
+
+void vscaler_set_stream_id(struct dpu_vscaler *vs, unsigned int id)
+{
+ switch (id) {
+ case DPU_PLANE_SRC_TO_DISP_STREAM0:
+ case DPU_PLANE_SRC_TO_DISP_STREAM1:
+ case DPU_PLANE_SRC_DISABLED:
+ vs->stream_id = id;
+ break;
+ default:
+ WARN_ON(1);
+ }
+}
+EXPORT_SYMBOL_GPL(vscaler_set_stream_id);
+
+struct dpu_vscaler *dpu_vs_get(struct dpu_soc *dpu, int id)
+{
+ struct dpu_vscaler *vs;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vs_ids); i++)
+ if (vs_ids[i] == id)
+ break;
+
+ if (i == ARRAY_SIZE(vs_ids))
+ return ERR_PTR(-EINVAL);
+
+ vs = dpu->vs_priv[i];
+
+ mutex_lock(&vs->mutex);
+
+ if (vs->inuse) {
+ vs = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
+ vs->inuse = true;
+out:
+ mutex_unlock(&vs->mutex);
+
+ return vs;
+}
+EXPORT_SYMBOL_GPL(dpu_vs_get);
+
+void dpu_vs_put(struct dpu_vscaler *vs)
+{
+ mutex_lock(&vs->mutex);
+
+ vs->inuse = false;
+
+ mutex_unlock(&vs->mutex);
+}
+EXPORT_SYMBOL_GPL(dpu_vs_put);
+
+void _dpu_vs_init(struct dpu_soc *dpu, unsigned int id)
+{
+ struct dpu_vscaler *vs;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vs_ids); i++)
+ if (vs_ids[i] == id)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(vs_ids)))
+ return;
+
+ vs = dpu->vs_priv[i];
+
+ vscaler_shden(vs, true);
+ vscaler_setup2(vs, false);
+ vscaler_setup3(vs, false);
+ vscaler_setup4(vs, 0);
+ vscaler_setup5(vs, 0);
+ vscaler_pixengcfg_dynamic_src_sel(vs, VS_SRC_SEL__DISABLE);
+}
+
+int dpu_vs_init(struct dpu_soc *dpu, unsigned int id,
+ unsigned long pec_base, unsigned long base)
+{
+ struct dpu_vscaler *vs;
+ int i;
+
+ vs = devm_kzalloc(dpu->dev, sizeof(*vs), GFP_KERNEL);
+ if (!vs)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(vs_ids); i++)
+ if (vs_ids[i] == id)
+ break;
+
+ dpu->vs_priv[i] = vs;
+
+ vs->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_8);
+ if (!vs->pec_base)
+ return -ENOMEM;
+
+ vs->base = devm_ioremap(dpu->dev, base, SZ_1K);
+ if (!vs->base)
+ return -ENOMEM;
+
+ vs->dpu = dpu;
+ vs->id = id;
+
+ mutex_init(&vs->mutex);
+
+ _dpu_vs_init(dpu, id);
+
+ return 0;
+}
diff --git a/drivers/gpu/imx/imx8_dprc.c b/drivers/gpu/imx/imx8_dprc.c
new file mode 100644
index 000000000000..162485f5ea73
--- /dev/null
+++ b/drivers/gpu/imx/imx8_dprc.c
@@ -0,0 +1,896 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#include <drm/drm_fourcc.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <soc/imx8/sc/sci.h>
+#include <video/imx8-prefetch.h>
+
+#define SET 0x4
+#define CLR 0x8
+#define TOG 0xc
+
+#define SYSTEM_CTRL0 0x00
+#define BCMD2AXI_MASTR_ID_CTRL BIT(16)
+#define SW_SHADOW_LOAD_SEL BIT(4)
+#define SHADOW_LOAD_EN BIT(3)
+#define REPEAT_EN BIT(2)
+#define SOFT_RESET BIT(1)
+#define RUN_EN BIT(0) /* self-clearing */
+
+#define IRQ_MASK 0x20
+#define IRQ_MASK_STATUS 0x30
+#define IRQ_NONMASK_STATUS 0x40
+#define DPR2RTR_FIFO_LOAD_BUF_RDY_UV_ERROR BIT(7)
+#define DPR2RTR_FIFO_LOAD_BUF_RDY_YRGB_ERROR BIT(6)
+#define DPR2RTR_UV_FIFO_OVFL BIT(5)
+#define DPR2RTR_YRGB_FIFO_OVFL BIT(4)
+#define IRQ_AXI_READ_ERROR BIT(3)
+#define IRQ_DPR_SHADOW_LOADED_MASK BIT(2)
+#define IRQ_DPR_RUN BIT(1)
+#define IRQ_DPR_CRTL_DONE BIT(0)
+#define IRQ_ERROR_MASK 0xf8
+#define IRQ_CTRL_MASK 0x7
+
+#define MODE_CTRL0 0x50
+#define PIX_COMP_SEL_MASK 0x3fc00
+#define A_COMP_SEL(byte) (((byte) & 0x3) << 16)
+#define R_COMP_SEL(byte) (((byte) & 0x3) << 14)
+#define G_COMP_SEL(byte) (((byte) & 0x3) << 12)
+#define B_COMP_SEL(byte) (((byte) & 0x3) << 10)
+#define PIX_UV_SWAP BIT(9)
+#define VU BIT(9)
+#define UV 0
+#define PIXEL_LUMA_UV_SWAP BIT(8)
+#define UYVY BIT(8)
+#define YUYV 0
+#define PIX_SIZE 0xc0
+enum {
+ PIX_SIZE_8BIT = (0 << 6),
+ PIX_SIZE_16BIT = (1 << 6),
+ PIX_SIZE_32BIT = (2 << 6),
+ PIX_SIZE_RESERVED = (3 << 6),
+};
+#define COMP_2PLANE_EN BIT(5)
+#define YUV_EN BIT(4)
+#define TILE_TYPE 0xc
+enum {
+ LINEAR_TILE = (0 << 2),
+ GPU_STANDARD_TILE = (1 << 2),
+ GPU_SUPER_TILE = (2 << 2),
+ VPU_TILE = (3 << 2),
+};
+#define RTR_4LINE_BUF_EN BIT(1)
+#define LINE4 BIT(1)
+#define LINE8 0
+#define RTR_3BUF_EN BIT(0)
+#define BUF3 BIT(0)
+#define BUF2 0
+
+#define FRAME_CTRL0 0x70
+#define PITCH(n) (((n) & 0xffff) << 16)
+#define ROT_FLIP_ORDER_EN BIT(4)
+#define ROT_FIRST BIT(4)
+#define FLIP_FIRST 0
+#define ROT_ENC 0xc
+#define DEGREE(n) ((((n) / 90) & 0x3) << 2)
+#define VFLIP_EN BIT(1)
+#define HFLIP_EN BIT(0)
+
+#define FRAME_1P_CTRL0 0x90
+#define FRAME_2P_CTRL0 0xe0
+#define MAX_BYTES_PREQ 0x7
+enum {
+ BYTE_64 = 0x0,
+ BYTE_128 = 0x1,
+ BYTE_256 = 0x2,
+ BYTE_512 = 0x3,
+ BYTE_1K = 0x4,
+ BYTE_2K = 0x5,
+ BYTE_4K = 0x6,
+};
+
+#define FRAME_1P_PIX_X_CTRL 0xa0
+#define FRAME_2P_PIX_X_CTRL 0xf0
+#define NUM_X_PIX_WIDE(n) ((n) & 0xffff)
+#define FRAME_PIX_X_ULC_CTRL 0xf0
+#define CROP_ULC_X(n) ((n) & 0xffff)
+
+#define FRAME_1P_PIX_Y_CTRL 0xb0
+#define FRAME_2P_PIX_Y_CTRL 0x100
+#define NUM_Y_PIX_HIGH(n) ((n) & 0xffff)
+#define FRAME_PIX_Y_ULC_CTRL 0x100
+#define CROP_ULC_Y(n) ((n) & 0xffff)
+
+#define FRAME_1P_BASE_ADDR_CTRL0 0xc0
+#define FRAME_2P_BASE_ADDR_CTRL0 0x110
+
+#define STATUS_CTRL0 0x130
+#define STATUS_SRC_SEL 0x70000
+enum {
+ DPR_CTRL = 0x0,
+ PREFETCH_1PLANE = 0x1,
+ RESPONSE_1PLANE = 0x2,
+ PREFETCH_2PLANE = 0x3,
+ RESPONSE_2PLANE = 0x4,
+};
+#define STATUS_MUX_SEL 0x7
+
+#define STATUS_CTRL1 0x140
+
+#define RTRAM_CTRL0 0x200
+#define ABORT_SEL BIT(7)
+#define ABORT BIT(7)
+#define STALL 0
+#define THRES_LOW_MASK 0x70
+#define THRES_LOW(n) (((n) & 0x7) << 4)
+#define THRES_HIGH_MASK 0xe
+#define THRES_HIGH(n) (((n) & 0x7) << 1)
+#define NUM_ROWS_ACTIVE BIT(0)
+#define ROWS_0_6 BIT(0)
+#define ROWS_0_4 0
+
+struct dprc {
+ struct device *dev;
+ void __iomem *base;
+ struct list_head list;
+ struct clk *clk_apb;
+ struct clk *clk_b;
+ struct clk *clk_rtram;
+ spinlock_t spin_lock;
+ u32 sc_resource;
+ bool is_blit_chan;
+
+ /* The second one, if non-NULL, is auxiliary for UV buffer. */
+ struct prg *prgs[2];
+ bool has_aux_prg;
+ bool use_aux_prg;
+};
+
+struct dprc_format_info {
+ u32 format;
+ u8 depth;
+ u8 num_planes;
+ u8 cpp[3];
+ u8 hsub;
+ u8 vsub;
+};
+
+static const struct dprc_format_info formats[] = {
+ {
+ .format = DRM_FORMAT_RGB565,
+ .depth = 16, .num_planes = 1, .cpp = { 2, 0, 0 },
+ .hsub = 1, .vsub = 1,
+ }, {
+ .format = DRM_FORMAT_ARGB8888,
+ .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 },
+ .hsub = 1, .vsub = 1,
+ }, {
+ .format = DRM_FORMAT_XRGB8888,
+ .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 },
+ .hsub = 1, .vsub = 1,
+ }, {
+ .format = DRM_FORMAT_ABGR8888,
+ .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 },
+ .hsub = 1, .vsub = 1,
+ }, {
+ .format = DRM_FORMAT_XBGR8888,
+ .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 },
+ .hsub = 1, .vsub = 1,
+ }, {
+ .format = DRM_FORMAT_RGBA8888,
+ .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 },
+ .hsub = 1, .vsub = 1,
+ }, {
+ .format = DRM_FORMAT_RGBX8888,
+ .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 },
+ .hsub = 1, .vsub = 1,
+ }, {
+ .format = DRM_FORMAT_BGRA8888,
+ .depth = 32, .num_planes = 1, .cpp = { 4, 0, 0 },
+ .hsub = 1, .vsub = 1,
+ }, {
+ .format = DRM_FORMAT_BGRX8888,
+ .depth = 24, .num_planes = 1, .cpp = { 4, 0, 0 },
+ .hsub = 1, .vsub = 1,
+ }, {
+ .format = DRM_FORMAT_NV12,
+ .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 },
+ .hsub = 2, .vsub = 2,
+ }, {
+ .format = DRM_FORMAT_NV21,
+ .depth = 0, .num_planes = 2, .cpp = { 1, 2, 0 },
+ .hsub = 2, .vsub = 2,
+ }, {
+ .format = DRM_FORMAT_YUYV,
+ .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 },
+ .hsub = 2, .vsub = 1,
+ }, {
+ .format = DRM_FORMAT_UYVY,
+ .depth = 0, .num_planes = 1, .cpp = { 2, 0, 0 },
+ .hsub = 2, .vsub = 1,
+ }
+};
+
+static const struct dprc_format_info *dprc_format_info(u32 format)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+ if (formats[i].format == format)
+ return &formats[i];
+ }
+
+ return NULL;
+}
+
+static DEFINE_MUTEX(dprc_list_mutex);
+static LIST_HEAD(dprc_list);
+
+static inline u32 dprc_read(struct dprc *dprc, unsigned int offset)
+{
+ return readl(dprc->base + offset);
+}
+
+static inline void dprc_write(struct dprc *dprc, u32 value, unsigned int offset)
+{
+ writel(value, dprc->base + offset);
+}
+
+static void dprc_reset(struct dprc *dprc)
+{
+ dprc_write(dprc, SOFT_RESET, SYSTEM_CTRL0 + SET);
+ usleep_range(1000, 2000);
+ dprc_write(dprc, SOFT_RESET, SYSTEM_CTRL0 + CLR);
+}
+
+void dprc_enable(struct dprc *dprc)
+{
+ if (WARN_ON(!dprc))
+ return;
+
+ prg_enable(dprc->prgs[0]);
+ if (dprc->use_aux_prg)
+ prg_enable(dprc->prgs[1]);
+}
+EXPORT_SYMBOL_GPL(dprc_enable);
+
+void dprc_disable(struct dprc *dprc)
+{
+ if (WARN_ON(!dprc))
+ return;
+
+ dprc_write(dprc, SHADOW_LOAD_EN | SW_SHADOW_LOAD_SEL, SYSTEM_CTRL0);
+
+ prg_disable(dprc->prgs[0]);
+ if (dprc->has_aux_prg)
+ prg_disable(dprc->prgs[1]);
+
+ prg_reg_update(dprc->prgs[0]);
+ if (dprc->has_aux_prg)
+ prg_reg_update(dprc->prgs[1]);
+}
+EXPORT_SYMBOL_GPL(dprc_disable);
+
+static void dprc_dpu_gpr_configure(struct dprc *dprc, unsigned int stream_id)
+{
+ sc_err_t sciErr;
+ sc_ipc_t ipcHndl = 0;
+ u32 mu_id;
+
+ if (WARN_ON(!dprc))
+ return;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ dev_err(dprc->dev, "cannot obtain MU ID %d\n", sciErr);
+ return;
+ }
+
+ sciErr = sc_ipc_open(&ipcHndl, mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ dev_err(dprc->dev, "sc_ipc_open failed %d\n", sciErr);
+ return;
+ }
+
+ sciErr = sc_misc_set_control(ipcHndl, dprc->sc_resource,
+ SC_C_KACHUNK_SEL, stream_id);
+ if (sciErr != SC_ERR_NONE)
+ dev_err(dprc->dev, "sc_misc_set_control failed %d\n", sciErr);
+
+ sc_ipc_close(mu_id);
+}
+
+static void dprc_prg_sel_configure(struct dprc *dprc, u32 resource, bool enable)
+{
+ sc_err_t sciErr;
+ sc_ipc_t ipcHndl = 0;
+ u32 mu_id;
+
+ if (WARN_ON(!dprc))
+ return;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ dev_err(dprc->dev, "cannot obtain MU ID %d\n", sciErr);
+ return;
+ }
+
+ sciErr = sc_ipc_open(&ipcHndl, mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ dev_err(dprc->dev, "sc_ipc_open failed %d\n", sciErr);
+ return;
+ }
+
+ sciErr = sc_misc_set_control(ipcHndl, resource, SC_C_SEL0, enable);
+ if (sciErr != SC_ERR_NONE)
+ dev_err(dprc->dev, "sc_misc_set_control failed %d\n", sciErr);
+
+ sc_ipc_close(mu_id);
+}
+
+void dprc_configure(struct dprc *dprc, unsigned int stream_id,
+ unsigned int width, unsigned int height,
+ unsigned int x_offset, unsigned int y_offset,
+ unsigned int stride, u32 format, u64 modifier,
+ unsigned long baddr, unsigned long uv_baddr,
+ bool start, bool aux_start, bool interlace_frame)
+{
+ const struct dprc_format_info *info = dprc_format_info(format);
+ unsigned int dprc_width = width + x_offset;
+ unsigned int dprc_height;
+ unsigned int p1_w, p1_h, p2_w, p2_h;
+ unsigned int prg_stride = width * info->cpp[0];
+ unsigned int bpp = 8 * info->cpp[0];
+ unsigned int preq;
+ unsigned int mt_w = 0, mt_h = 0; /* w/h in a micro-tile */
+ u32 val;
+
+ if (WARN_ON(!dprc))
+ return;
+
+ dprc->use_aux_prg = false;
+
+ if (start) {
+ dprc_reset(dprc);
+
+ if (!dprc->is_blit_chan)
+ dprc_dpu_gpr_configure(dprc, stream_id);
+ }
+
+ if (interlace_frame) {
+ height /= 2;
+ y_offset /= 2;
+ }
+
+ dprc_height = height + y_offset;
+
+ /* disable all control irqs and enable all error irqs */
+ dprc_write(dprc, IRQ_CTRL_MASK, IRQ_MASK);
+
+ if (info->num_planes > 1) {
+ p1_w = round_up(dprc_width, modifier ? 8 : 64);
+ p1_h = round_up(dprc_height, 8);
+
+ p2_w = p1_w;
+ if (modifier)
+ p2_h = dprc_height / info->vsub;
+ else
+ p2_h = round_up((dprc_height / info->vsub), 8);
+
+ preq = modifier ? BYTE_64 : BYTE_1K;
+
+ dprc_write(dprc, preq, FRAME_2P_CTRL0);
+ if (dprc->sc_resource == SC_R_DC_0_BLIT1) {
+ dprc_prg_sel_configure(dprc, SC_R_DC_0_BLIT0, true);
+ prg_set_auxiliary(dprc->prgs[1]);
+ dprc->has_aux_prg = true;
+ }
+ dprc_write(dprc, uv_baddr, FRAME_2P_BASE_ADDR_CTRL0);
+ } else {
+ switch (dprc->sc_resource) {
+ case SC_R_DC_0_BLIT0:
+ dprc_prg_sel_configure(dprc, SC_R_DC_0_BLIT0, false);
+ prg_set_primary(dprc->prgs[0]);
+ break;
+ case SC_R_DC_0_BLIT1:
+ dprc->has_aux_prg = false;
+ break;
+ default:
+ break;
+ }
+
+ switch (modifier) {
+ case DRM_FORMAT_MOD_VIVANTE_TILED:
+ p1_w = round_up(dprc_width, info->cpp[0] == 2 ? 8 : 4);
+ break;
+ case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+ if (dprc->is_blit_chan)
+ p1_w = round_up(dprc_width,
+ info->cpp[0] == 2 ? 8 : 4);
+ else
+ p1_w = round_up(dprc_width, 64);
+ break;
+ default:
+ p1_w = round_up(dprc_width,
+ info->cpp[0] == 2 ? 32 : 16);
+ break;
+ }
+ p1_h = round_up(dprc_height, 4);
+ }
+
+ dprc_write(dprc, PITCH(stride), FRAME_CTRL0);
+ switch (modifier) {
+ case DRM_FORMAT_MOD_AMPHION_TILED:
+ preq = BYTE_64;
+ mt_w = 8;
+ mt_h = 8;
+ break;
+ case DRM_FORMAT_MOD_VIVANTE_TILED:
+ case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+ if (bpp == 16) {
+ preq = BYTE_64;
+ mt_w = 8;
+ } else {
+ preq = (x_offset % 8) ? BYTE_64 : BYTE_128;
+ mt_w = 4;
+ }
+ mt_h = 4;
+ break;
+ default:
+ preq = BYTE_1K;
+ break;
+ }
+ dprc_write(dprc, preq, FRAME_1P_CTRL0);
+ dprc_write(dprc, NUM_X_PIX_WIDE(p1_w), FRAME_1P_PIX_X_CTRL);
+ dprc_write(dprc, NUM_Y_PIX_HIGH(p1_h), FRAME_1P_PIX_Y_CTRL);
+ dprc_write(dprc, baddr, FRAME_1P_BASE_ADDR_CTRL0);
+ if (modifier) {
+ dprc_write(dprc, CROP_ULC_X(round_down(x_offset, mt_w)),
+ FRAME_PIX_X_ULC_CTRL);
+ dprc_write(dprc, CROP_ULC_Y(round_down(y_offset, mt_h)),
+ FRAME_PIX_Y_ULC_CTRL);
+ }
+
+ val = dprc_read(dprc, RTRAM_CTRL0);
+ val &= ~THRES_LOW_MASK;
+ val |= THRES_LOW(3);
+ val &= ~THRES_HIGH_MASK;
+ val |= THRES_HIGH(7);
+ dprc_write(dprc, val, RTRAM_CTRL0);
+
+ val = dprc_read(dprc, MODE_CTRL0);
+ val &= ~PIX_UV_SWAP;
+ val &= ~PIXEL_LUMA_UV_SWAP;
+ val &= ~COMP_2PLANE_EN;
+ val &= ~YUV_EN;
+ val &= ~TILE_TYPE;
+ switch (modifier) {
+ case DRM_FORMAT_MOD_NONE:
+ break;
+ case DRM_FORMAT_MOD_AMPHION_TILED:
+ val |= VPU_TILE;
+ break;
+ case DRM_FORMAT_MOD_VIVANTE_TILED:
+ val |= GPU_STANDARD_TILE;
+ break;
+ case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+ val |= GPU_SUPER_TILE;
+ break;
+ default:
+ dev_err(dprc->dev, "unsupported modifier 0x%016llx\n",
+ modifier);
+ return;
+ }
+ val &= ~RTR_4LINE_BUF_EN;
+ val |= info->num_planes > 1 ? LINE8 : LINE4;
+ val &= ~RTR_3BUF_EN;
+ val |= BUF2;
+ val &= ~(PIX_COMP_SEL_MASK | PIX_SIZE);
+ switch (format) {
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_RGBX8888:
+ case DRM_FORMAT_BGRA8888:
+ case DRM_FORMAT_BGRX8888:
+ /*
+ * It turns out pixel components are mapped directly
+ * without position change via DPR processing with
+ * the following color component configurations.
+ * Leave the pixel format to be handled by the
+ * display controllers.
+ */
+ val |= A_COMP_SEL(3) | R_COMP_SEL(2) |
+ G_COMP_SEL(1) | B_COMP_SEL(0);
+ val |= PIX_SIZE_32BIT;
+ break;
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_UYVY:
+ val |= YUV_EN;
+ /* fall-through */
+ case DRM_FORMAT_RGB565:
+ val |= PIX_SIZE_16BIT;
+ break;
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ dprc->use_aux_prg = true;
+
+ val |= COMP_2PLANE_EN;
+ val |= YUV_EN;
+ val |= PIX_SIZE_8BIT;
+ break;
+ default:
+ dev_err(dprc->dev, "unsupported format 0x%08x\n", format);
+ return;
+ }
+ dprc_write(dprc, val, MODE_CTRL0);
+
+ if (start) {
+ /* software shadow load for the first frame */
+ val = SW_SHADOW_LOAD_SEL;
+ if (dprc->is_blit_chan) {
+ val |= RUN_EN | REPEAT_EN | SHADOW_LOAD_EN;
+ dprc_write(dprc, val, SYSTEM_CTRL0);
+ } else {
+ val |= SHADOW_LOAD_EN;
+ dprc_write(dprc, val, SYSTEM_CTRL0);
+
+ /* and then, run... */
+ val |= RUN_EN | REPEAT_EN;
+ dprc_write(dprc, val, SYSTEM_CTRL0);
+ }
+ }
+
+ prg_configure(dprc->prgs[0], width, height, x_offset, y_offset,
+ prg_stride, bpp, baddr, format, modifier, start);
+ if (dprc->use_aux_prg)
+ prg_configure(dprc->prgs[1], width, height, x_offset, y_offset,
+ prg_stride, 8, uv_baddr, format, modifier, aux_start);
+
+ dev_dbg(dprc->dev, "w-%u, h-%u, s-%u, fmt-0x%08x, mod-0x%016llx\n",
+ width, height, stride, format, modifier);
+}
+EXPORT_SYMBOL_GPL(dprc_configure);
+
+void dprc_reg_update(struct dprc *dprc)
+{
+ if (WARN_ON(!dprc))
+ return;
+
+ prg_reg_update(dprc->prgs[0]);
+ if (dprc->use_aux_prg)
+ prg_reg_update(dprc->prgs[1]);
+}
+EXPORT_SYMBOL_GPL(dprc_reg_update);
+
+void dprc_first_frame_handle(struct dprc *dprc)
+{
+ if (WARN_ON(!dprc))
+ return;
+
+ if (dprc->is_blit_chan)
+ dprc_write(dprc, SW_SHADOW_LOAD_SEL, SYSTEM_CTRL0 + CLR);
+ else
+ dprc_write(dprc, REPEAT_EN, SYSTEM_CTRL0);
+
+ prg_shadow_enable(dprc->prgs[0]);
+ if (dprc->use_aux_prg)
+ prg_shadow_enable(dprc->prgs[1]);
+}
+EXPORT_SYMBOL_GPL(dprc_first_frame_handle);
+
+void dprc_irq_handle(struct dprc *dprc)
+{
+ u32 mask, status;
+
+ if (WARN_ON(!dprc))
+ return;
+
+ spin_lock(&dprc->spin_lock);
+
+ mask = dprc_read(dprc, IRQ_MASK);
+ mask = ~mask;
+ status = dprc_read(dprc, IRQ_MASK_STATUS);
+ status &= mask;
+
+ /* disable irqs to be handled */
+ dprc_write(dprc, status, IRQ_MASK + SET);
+
+ /* clear status */
+ dprc_write(dprc, status, IRQ_MASK_STATUS);
+
+ if (status & DPR2RTR_FIFO_LOAD_BUF_RDY_UV_ERROR)
+ dev_err(dprc->dev,
+ "DPR to RTRAM FIFO load UV buffer ready error\n");
+
+ if (status & DPR2RTR_FIFO_LOAD_BUF_RDY_YRGB_ERROR)
+ dev_err(dprc->dev,
+ "DPR to RTRAM FIFO load YRGB buffer ready error\n");
+
+ if (status & DPR2RTR_UV_FIFO_OVFL)
+ dev_err(dprc->dev, "DPR to RTRAM FIFO UV FIFO overflow\n");
+
+ if (status & DPR2RTR_YRGB_FIFO_OVFL)
+ dev_err(dprc->dev, "DPR to RTRAM FIFO YRGB FIFO overflow\n");
+
+ if (status & IRQ_AXI_READ_ERROR)
+ dev_err(dprc->dev, "AXI read error\n");
+
+ if (status & IRQ_DPR_CRTL_DONE)
+ dprc_first_frame_handle(dprc);
+
+ spin_unlock(&dprc->spin_lock);
+}
+EXPORT_SYMBOL_GPL(dprc_irq_handle);
+
+void dprc_enable_ctrl_done_irq(struct dprc *dprc)
+{
+ unsigned long lock_flags;
+
+ if (WARN_ON(!dprc))
+ return;
+
+ spin_lock_irqsave(&dprc->spin_lock, lock_flags);
+ dprc_write(dprc, IRQ_DPR_CRTL_DONE, IRQ_MASK + CLR);
+ spin_unlock_irqrestore(&dprc->spin_lock, lock_flags);
+}
+EXPORT_SYMBOL_GPL(dprc_enable_ctrl_done_irq);
+
+bool dprc_format_supported(struct dprc *dprc, u32 format, u64 modifier)
+{
+ if (WARN_ON(!dprc))
+ return false;
+
+ switch (format) {
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_RGBX8888:
+ case DRM_FORMAT_BGRA8888:
+ case DRM_FORMAT_BGRX8888:
+ case DRM_FORMAT_RGB565:
+ return (modifier == DRM_FORMAT_MOD_NONE ||
+ modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
+ modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED);
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_UYVY:
+ switch (dprc->sc_resource) {
+ case SC_R_DC_0_FRAC0:
+ case SC_R_DC_1_FRAC0:
+ case SC_R_DC_0_WARP:
+ case SC_R_DC_1_WARP:
+ return false;
+ }
+ return modifier == DRM_FORMAT_MOD_NONE;
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ switch (dprc->sc_resource) {
+ case SC_R_DC_0_FRAC0:
+ case SC_R_DC_1_FRAC0:
+ case SC_R_DC_0_WARP:
+ case SC_R_DC_1_WARP:
+ return false;
+ case SC_R_DC_0_BLIT1:
+ return (modifier == DRM_FORMAT_MOD_NONE ||
+ modifier == DRM_FORMAT_MOD_AMPHION_TILED);
+ }
+ return (dprc->has_aux_prg &&
+ (modifier == DRM_FORMAT_MOD_NONE ||
+ modifier == DRM_FORMAT_MOD_AMPHION_TILED));
+ }
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(dprc_format_supported);
+
+bool dprc_stride_supported(struct dprc *dprc,
+ unsigned int stride, unsigned int uv_stride,
+ unsigned int width, u32 format)
+{
+ const struct dprc_format_info *info = dprc_format_info(format);
+ unsigned int prg_stride = width * info->cpp[0];
+
+ if (WARN_ON(!dprc))
+ return false;
+
+ if (stride > 0xffff)
+ return false;
+
+ if (info->num_planes > 1 && stride != uv_stride)
+ return false;
+
+ return prg_stride_supported(dprc->prgs[0], prg_stride);
+}
+EXPORT_SYMBOL_GPL(dprc_stride_supported);
+
+bool dprc_stride_double_check(struct dprc *dprc,
+ unsigned int width, unsigned int x_offset,
+ u32 format, u64 modifier,
+ dma_addr_t baddr, dma_addr_t uv_baddr)
+{
+ const struct dprc_format_info *info = dprc_format_info(format);
+ unsigned int bpp = 8 * info->cpp[0];
+ unsigned int prg_stride = width * info->cpp[0];
+
+ if (WARN_ON(!dprc))
+ return false;
+
+ if (!prg_stride_double_check(dprc->prgs[0], width, x_offset,
+ bpp, modifier, prg_stride, baddr))
+ return false;
+
+ if (info->num_planes > 1 &&
+ !prg_stride_double_check(dprc->prgs[1], width, x_offset,
+ bpp, modifier, prg_stride, uv_baddr))
+ return false;
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(dprc_stride_double_check);
+
+struct dprc *
+dprc_lookup_by_phandle(struct device *dev, const char *name, int index)
+{
+ struct device_node *dprc_node = of_parse_phandle(dev->of_node,
+ name, index);
+ struct dprc *dprc;
+
+ mutex_lock(&dprc_list_mutex);
+ list_for_each_entry(dprc, &dprc_list, list) {
+ if (dprc_node == dprc->dev->of_node) {
+ mutex_unlock(&dprc_list_mutex);
+ device_link_add(dev, dprc->dev, DL_FLAG_AUTOREMOVE);
+ return dprc;
+ }
+ }
+ mutex_unlock(&dprc_list_mutex);
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(dprc_lookup_by_phandle);
+
+static const struct of_device_id dprc_dt_ids[] = {
+ { .compatible = "fsl,imx8qm-dpr-channel", },
+ { .compatible = "fsl,imx8qxp-dpr-channel", },
+ { /* sentinel */ },
+};
+
+static int dprc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct dprc *dprc;
+ int ret, i;
+
+ dprc = devm_kzalloc(dev, sizeof(*dprc), GFP_KERNEL);
+ if (!dprc)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dprc->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dprc->base))
+ return PTR_ERR(dprc->base);
+
+ dprc->clk_apb = devm_clk_get(dev, "apb");
+ if (IS_ERR(dprc->clk_apb))
+ return PTR_ERR(dprc->clk_apb);
+ clk_prepare_enable(dprc->clk_apb);
+
+ dprc->clk_b = devm_clk_get(dev, "b");
+ if (IS_ERR(dprc->clk_b))
+ return PTR_ERR(dprc->clk_b);
+ clk_prepare_enable(dprc->clk_b);
+
+ dprc->clk_rtram = devm_clk_get(dev, "rtram");
+ if (IS_ERR(dprc->clk_rtram))
+ return PTR_ERR(dprc->clk_rtram);
+ clk_prepare_enable(dprc->clk_rtram);
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "fsl,sc-resource", &dprc->sc_resource);
+ if (ret) {
+ dev_err(dev, "cannot get SC resource %d\n", ret);
+ return ret;
+ }
+
+ switch (dprc->sc_resource) {
+ case SC_R_DC_0_BLIT1:
+ dprc->has_aux_prg = true;
+ /* fall-through */
+ case SC_R_DC_0_BLIT0:
+ case SC_R_DC_1_BLIT0:
+ case SC_R_DC_1_BLIT1:
+ dprc->is_blit_chan = true;
+ /* fall-through */
+ case SC_R_DC_0_FRAC0:
+ case SC_R_DC_1_FRAC0:
+ break;
+ case SC_R_DC_0_VIDEO0:
+ case SC_R_DC_0_VIDEO1:
+ case SC_R_DC_1_VIDEO0:
+ case SC_R_DC_1_VIDEO1:
+ case SC_R_DC_0_WARP:
+ case SC_R_DC_1_WARP:
+ dprc->has_aux_prg = true;
+ break;
+ default:
+ dev_err(dev, "wrong SC resource %u\n", dprc->sc_resource);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 2; i++) {
+ if (i == 1 && !dprc->has_aux_prg)
+ break;
+
+ dprc->prgs[i] = prg_lookup_by_phandle(dev, "fsl,prgs", i);
+ if (!dprc->prgs[i])
+ return -EPROBE_DEFER;
+
+ if (i == 1)
+ prg_set_auxiliary(dprc->prgs[i]);
+
+ if (dprc->is_blit_chan)
+ prg_set_blit(dprc->prgs[i]);
+ }
+
+ dprc->dev = dev;
+ spin_lock_init(&dprc->spin_lock);
+ platform_set_drvdata(pdev, dprc);
+ mutex_lock(&dprc_list_mutex);
+ list_add(&dprc->list, &dprc_list);
+ mutex_unlock(&dprc_list_mutex);
+
+ dprc_reset(dprc);
+
+ return 0;
+}
+
+static int dprc_remove(struct platform_device *pdev)
+{
+ struct dprc *dprc = platform_get_drvdata(pdev);
+
+ mutex_lock(&dprc_list_mutex);
+ list_del(&dprc->list);
+ mutex_unlock(&dprc_list_mutex);
+
+ clk_disable_unprepare(dprc->clk_rtram);
+ clk_disable_unprepare(dprc->clk_b);
+ clk_disable_unprepare(dprc->clk_apb);
+
+ return 0;
+}
+
+struct platform_driver dprc_drv = {
+ .probe = dprc_probe,
+ .remove = dprc_remove,
+ .driver = {
+ .name = "imx8-dpr-channel",
+ .of_match_table = dprc_dt_ids,
+ },
+};
+module_platform_driver(dprc_drv);
+
+MODULE_DESCRIPTION("i.MX8 DPRC driver");
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/imx/imx8_prg.c b/drivers/gpu/imx/imx8_prg.c
new file mode 100644
index 000000000000..a7b2ae9963cd
--- /dev/null
+++ b/drivers/gpu/imx/imx8_prg.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#include <drm/drm_fourcc.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <video/imx8-prefetch.h>
+
+#define SET 0x4
+#define CLR 0x8
+#define TOG 0xc
+
+#define PRG_CTRL 0x00
+#define BYPASS BIT(0)
+#define SC_DATA_TYPE BIT(2)
+#define SC_DATA_TYPE_8BIT 0
+#define SC_DATA_TYPE_10BIT BIT(2)
+#define UV_EN BIT(3)
+#define HANDSHAKE_MODE BIT(4)
+#define HANDSHAKE_MODE_4LINES 0
+#define HANDSHAKE_MODE_8LINES BIT(4)
+#define SHADOW_LOAD_MODE BIT(5)
+#define DES_DATA_TYPE 0x30000
+enum {
+ DES_DATA_TYPE_32BPP = (0 << 16),
+ DES_DATA_TYPE_24BPP = (1 << 16),
+ DES_DATA_TYPE_16BPP = (2 << 16),
+ DES_DATA_TYPE_8BPP = (3 << 16),
+};
+#define SOFTRST BIT(30)
+#define SHADOW_EN BIT(31)
+
+#define PRG_STATUS 0x10
+#define BUFFER_VALID_B BIT(1)
+#define BUFFER_VALID_A BIT(0)
+
+#define PRG_REG_UPDATE 0x20
+#define REG_UPDATE BIT(0)
+
+#define PRG_STRIDE 0x30
+#define STRIDE(n) (((n) - 1) & 0xffff)
+
+#define PRG_HEIGHT 0x40
+#define HEIGHT(n) (((n) - 1) & 0xffff)
+
+#define PRG_BADDR 0x50
+
+#define PRG_OFFSET 0x60
+#define Y(n) (((n) & 0x7) << 16)
+#define X(n) ((n) & 0xffff)
+
+#define PRG_WIDTH 0x70
+#define WIDTH(n) (((n) - 1) & 0xffff)
+
+struct prg {
+ struct device *dev;
+ void __iomem *base;
+ struct list_head list;
+ struct clk *clk_apb;
+ struct clk *clk_rtram;
+ bool is_auxiliary;
+ bool is_blit;
+};
+
+static DEFINE_MUTEX(prg_list_mutex);
+static LIST_HEAD(prg_list);
+
+static inline u32 prg_read(struct prg *prg, unsigned int offset)
+{
+ return readl(prg->base + offset);
+}
+
+static inline void prg_write(struct prg *prg, u32 value, unsigned int offset)
+{
+ writel(value, prg->base + offset);
+}
+
+static void prg_reset(struct prg *prg)
+{
+ prg_write(prg, SOFTRST, PRG_CTRL + SET);
+ usleep_range(1000, 2000);
+ prg_write(prg, SOFTRST, PRG_CTRL + CLR);
+}
+
+void prg_enable(struct prg *prg)
+{
+ if (WARN_ON(!prg))
+ return;
+
+ prg_write(prg, BYPASS, PRG_CTRL + CLR);
+}
+EXPORT_SYMBOL_GPL(prg_enable);
+
+void prg_disable(struct prg *prg)
+{
+ if (WARN_ON(!prg))
+ return;
+
+ prg_write(prg, BYPASS, PRG_CTRL);
+}
+EXPORT_SYMBOL_GPL(prg_disable);
+
+void prg_configure(struct prg *prg, unsigned int width, unsigned int height,
+ unsigned int x_offset, unsigned int y_offset,
+ unsigned int stride, unsigned int bits_per_pixel,
+ unsigned long baddr, u32 format, u64 modifier,
+ bool start)
+{
+ unsigned int burst_size;
+ unsigned int mt_w = 0, mt_h = 0; /* w/h in a micro-tile */
+ unsigned long _baddr;
+ u32 val;
+
+ if (WARN_ON(!prg))
+ return;
+
+ if (start)
+ prg_reset(prg);
+
+ /* prg finer cropping into micro-tile block - top/left start point */
+ switch (modifier) {
+ case DRM_FORMAT_MOD_NONE:
+ break;
+ case DRM_FORMAT_MOD_AMPHION_TILED:
+ mt_w = 8;
+ mt_h = 8;
+ break;
+ case DRM_FORMAT_MOD_VIVANTE_TILED:
+ case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+ mt_w = (bits_per_pixel == 16) ? 8 : 4;
+ mt_h = 4;
+ break;
+ default:
+ dev_err(prg->dev, "unsupported modifier 0x%016llx\n", modifier);
+ return;
+ }
+
+ if (modifier) {
+ x_offset %= mt_w;
+ y_offset %= mt_h;
+
+ /* consider x offset to calculate stride */
+ _baddr = baddr + (x_offset * (bits_per_pixel / 8));
+ } else {
+ x_offset = 0;
+ y_offset = 0;
+ _baddr = baddr;
+ }
+
+ /*
+ * address TKT343664:
+ * fetch unit base address has to align to burst_size
+ */
+ burst_size = 1 << (ffs(_baddr) - 1);
+ burst_size = round_up(burst_size, 8);
+ burst_size = min(burst_size, 128U);
+
+ /*
+ * address TKT339017:
+ * fixup for burst size vs stride mismatch
+ */
+ if (modifier)
+ stride = round_up(stride + round_up(_baddr % 8, 8), burst_size);
+ else
+ stride = round_up(stride, burst_size);
+
+ /*
+ * address TKT342628(part 1):
+ * when prg stride is less or equals to burst size,
+ * the auxiliary prg height needs to be a half
+ */
+ if (prg->is_auxiliary && stride <= burst_size) {
+ height /= 2;
+ if (modifier)
+ y_offset /= 2;
+ }
+
+ prg_write(prg, STRIDE(stride), PRG_STRIDE);
+ prg_write(prg, WIDTH(width), PRG_WIDTH);
+ prg_write(prg, HEIGHT(height), PRG_HEIGHT);
+ prg_write(prg, X(x_offset) | Y(y_offset), PRG_OFFSET);
+ prg_write(prg, baddr, PRG_BADDR);
+
+ val = prg_read(prg, PRG_CTRL);
+ val &= ~SC_DATA_TYPE;
+ val |= SC_DATA_TYPE_8BIT;
+ val &= ~HANDSHAKE_MODE;
+ if (format == DRM_FORMAT_NV21 || format == DRM_FORMAT_NV12) {
+ val |= HANDSHAKE_MODE_8LINES;
+ /*
+ * address TKT342628(part 2):
+ * when prg stride is less or equals to burst size,
+ * we disable UV_EN bit for the auxiliary prg
+ */
+ if (prg->is_auxiliary && stride > burst_size)
+ val |= UV_EN;
+ else
+ val &= ~UV_EN;
+ } else {
+ val |= HANDSHAKE_MODE_4LINES;
+ val &= ~UV_EN;
+ }
+ val |= SHADOW_LOAD_MODE;
+ val &= ~DES_DATA_TYPE;
+ switch (bits_per_pixel) {
+ case 32:
+ val |= DES_DATA_TYPE_32BPP;
+ break;
+ case 24:
+ val |= DES_DATA_TYPE_24BPP;
+ break;
+ case 16:
+ val |= DES_DATA_TYPE_16BPP;
+ break;
+ case 8:
+ val |= DES_DATA_TYPE_8BPP;
+ break;
+ }
+ if (start)
+ /* no shadow for the first frame */
+ val &= ~SHADOW_EN;
+ else
+ val |= SHADOW_EN;
+ prg_write(prg, val, PRG_CTRL);
+
+ dev_dbg(prg->dev, "bits per pixel %u\n", bits_per_pixel);
+}
+EXPORT_SYMBOL_GPL(prg_configure);
+
+void prg_reg_update(struct prg *prg)
+{
+ if (WARN_ON(!prg))
+ return;
+
+ prg_write(prg, REG_UPDATE, PRG_REG_UPDATE);
+}
+EXPORT_SYMBOL_GPL(prg_reg_update);
+
+void prg_shadow_enable(struct prg *prg)
+{
+ if (WARN_ON(!prg))
+ return;
+
+ prg_write(prg, SHADOW_EN, PRG_CTRL + SET);
+}
+EXPORT_SYMBOL_GPL(prg_shadow_enable);
+
+bool prg_stride_supported(struct prg *prg, unsigned int stride)
+{
+ return stride < 0x10000;
+}
+EXPORT_SYMBOL_GPL(prg_stride_supported);
+
+bool prg_stride_double_check(struct prg *prg,
+ unsigned int width, unsigned int x_offset,
+ unsigned int bits_per_pixel, u64 modifier,
+ unsigned int stride, dma_addr_t baddr)
+{
+ unsigned int burst_size;
+ unsigned int mt_w = 0; /* w in a micro-tile */
+ dma_addr_t _baddr;
+
+ if (WARN_ON(!prg))
+ return false;
+
+ /* prg finer cropping into micro-tile block - top/left start point */
+ switch (modifier) {
+ case DRM_FORMAT_MOD_NONE:
+ break;
+ case DRM_FORMAT_MOD_AMPHION_TILED:
+ mt_w = 8;
+ break;
+ case DRM_FORMAT_MOD_VIVANTE_TILED:
+ case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+ mt_w = (bits_per_pixel == 16) ? 8 : 4;
+ break;
+ default:
+ dev_err(prg->dev, "unsupported modifier 0x%016llx\n", modifier);
+ return false;
+ }
+
+ if (modifier) {
+ x_offset %= mt_w;
+
+ /* consider x offset to calculate stride */
+ _baddr = baddr + (x_offset * (bits_per_pixel / 8));
+ } else {
+ _baddr = baddr;
+ }
+
+ /*
+ * address TKT343664:
+ * fetch unit base address has to align to burst size
+ */
+ burst_size = 1 << (ffs(_baddr) - 1);
+ burst_size = round_up(burst_size, 8);
+ burst_size = min(burst_size, 128U);
+
+ /*
+ * address TKT339017:
+ * fixup for burst size vs stride mismatch
+ */
+ if (modifier)
+ stride = round_up(stride + round_up(_baddr % 8, 8), burst_size);
+ else
+ stride = round_up(stride, burst_size);
+
+ return stride < 0x10000;
+}
+EXPORT_SYMBOL_GPL(prg_stride_double_check);
+
+void prg_set_auxiliary(struct prg *prg)
+{
+ if (WARN_ON(!prg))
+ return;
+
+ prg->is_auxiliary = true;
+}
+EXPORT_SYMBOL_GPL(prg_set_auxiliary);
+
+void prg_set_primary(struct prg *prg)
+{
+ if (WARN_ON(!prg))
+ return;
+
+ prg->is_auxiliary = false;
+}
+EXPORT_SYMBOL_GPL(prg_set_primary);
+
+void prg_set_blit(struct prg *prg)
+{
+ if (WARN_ON(!prg))
+ return;
+
+ prg->is_blit = true;
+}
+EXPORT_SYMBOL_GPL(prg_set_blit);
+
+struct prg *
+prg_lookup_by_phandle(struct device *dev, const char *name, int index)
+{
+ struct device_node *prg_node = of_parse_phandle(dev->of_node,
+ name, index);
+ struct prg *prg;
+
+ mutex_lock(&prg_list_mutex);
+ list_for_each_entry(prg, &prg_list, list) {
+ if (prg_node == prg->dev->of_node) {
+ mutex_unlock(&prg_list_mutex);
+ device_link_add(dev, prg->dev, DL_FLAG_AUTOREMOVE);
+ return prg;
+ }
+ }
+ mutex_unlock(&prg_list_mutex);
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(prg_lookup_by_phandle);
+
+static const struct of_device_id prg_dt_ids[] = {
+ { .compatible = "fsl,imx8qm-prg", },
+ { .compatible = "fsl,imx8qxp-prg", },
+ { /* sentinel */ },
+};
+
+static int prg_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct prg *prg;
+
+ prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL);
+ if (!prg)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ prg->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(prg->base))
+ return PTR_ERR(prg->base);
+
+ prg->clk_apb = devm_clk_get(dev, "apb");
+ if (IS_ERR(prg->clk_apb))
+ return PTR_ERR(prg->clk_apb);
+ clk_prepare_enable(prg->clk_apb);
+
+ prg->clk_rtram = devm_clk_get(dev, "rtram");
+ if (IS_ERR(prg->clk_rtram))
+ return PTR_ERR(prg->clk_rtram);
+ clk_prepare_enable(prg->clk_rtram);
+
+ prg->dev = dev;
+ platform_set_drvdata(pdev, prg);
+ mutex_lock(&prg_list_mutex);
+ list_add(&prg->list, &prg_list);
+ mutex_unlock(&prg_list_mutex);
+
+ prg_reset(prg);
+
+ return 0;
+}
+
+static int prg_remove(struct platform_device *pdev)
+{
+ struct prg *prg = platform_get_drvdata(pdev);
+
+ mutex_lock(&prg_list_mutex);
+ list_del(&prg->list);
+ mutex_unlock(&prg_list_mutex);
+
+ clk_disable_unprepare(prg->clk_rtram);
+ clk_disable_unprepare(prg->clk_apb);
+
+ return 0;
+}
+
+struct platform_driver prg_drv = {
+ .probe = prg_probe,
+ .remove = prg_remove,
+ .driver = {
+ .name = "imx8-prg",
+ .of_match_table = prg_dt_ids,
+ },
+};
+module_platform_driver(prg_drv);
+
+MODULE_DESCRIPTION("i.MX8 PRG driver");
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/ipu-v3/Kconfig b/drivers/gpu/imx/ipu-v3/Kconfig
index aefdff95356d..aefdff95356d 100644
--- a/drivers/gpu/ipu-v3/Kconfig
+++ b/drivers/gpu/imx/ipu-v3/Kconfig
diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/imx/ipu-v3/Makefile
index 5f961416c4ee..5f961416c4ee 100644
--- a/drivers/gpu/ipu-v3/Makefile
+++ b/drivers/gpu/imx/ipu-v3/Makefile
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/imx/ipu-v3/ipu-common.c
index b9539f7c5e9a..b9539f7c5e9a 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/imx/ipu-v3/ipu-common.c
diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/imx/ipu-v3/ipu-cpmem.c
index fcb7dc86167b..fcb7dc86167b 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/imx/ipu-v3/ipu-cpmem.c
diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/imx/ipu-v3/ipu-csi.c
index 8774bf17c853..8774bf17c853 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/imx/ipu-v3/ipu-csi.c
diff --git a/drivers/gpu/ipu-v3/ipu-dc.c b/drivers/gpu/imx/ipu-v3/ipu-dc.c
index 659475c1e44a..659475c1e44a 100644
--- a/drivers/gpu/ipu-v3/ipu-dc.c
+++ b/drivers/gpu/imx/ipu-v3/ipu-dc.c
diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/imx/ipu-v3/ipu-di.c
index a8d87ddd8a17..a8d87ddd8a17 100644
--- a/drivers/gpu/ipu-v3/ipu-di.c
+++ b/drivers/gpu/imx/ipu-v3/ipu-di.c
diff --git a/drivers/gpu/ipu-v3/ipu-dmfc.c b/drivers/gpu/imx/ipu-v3/ipu-dmfc.c
index a40f211f382f..a40f211f382f 100644
--- a/drivers/gpu/ipu-v3/ipu-dmfc.c
+++ b/drivers/gpu/imx/ipu-v3/ipu-dmfc.c
diff --git a/drivers/gpu/ipu-v3/ipu-dp.c b/drivers/gpu/imx/ipu-v3/ipu-dp.c
index 98686edbcdbb..98686edbcdbb 100644
--- a/drivers/gpu/ipu-v3/ipu-dp.c
+++ b/drivers/gpu/imx/ipu-v3/ipu-dp.c
diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/imx/ipu-v3/ipu-ic.c
index 321eb983c2f5..321eb983c2f5 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/imx/ipu-v3/ipu-ic.c
diff --git a/drivers/gpu/ipu-v3/ipu-image-convert.c b/drivers/gpu/imx/ipu-v3/ipu-image-convert.c
index 805b6fa7b5f4..805b6fa7b5f4 100644
--- a/drivers/gpu/ipu-v3/ipu-image-convert.c
+++ b/drivers/gpu/imx/ipu-v3/ipu-image-convert.c
diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/imx/ipu-v3/ipu-prv.h
index 22e47b68b14a..22e47b68b14a 100644
--- a/drivers/gpu/ipu-v3/ipu-prv.h
+++ b/drivers/gpu/imx/ipu-v3/ipu-prv.h
diff --git a/drivers/gpu/ipu-v3/ipu-smfc.c b/drivers/gpu/imx/ipu-v3/ipu-smfc.c
index 4ef910991413..4ef910991413 100644
--- a/drivers/gpu/ipu-v3/ipu-smfc.c
+++ b/drivers/gpu/imx/ipu-v3/ipu-smfc.c
diff --git a/drivers/gpu/ipu-v3/ipu-vdi.c b/drivers/gpu/imx/ipu-v3/ipu-vdi.c
index f27bf5a12ebc..f27bf5a12ebc 100644
--- a/drivers/gpu/ipu-v3/ipu-vdi.c
+++ b/drivers/gpu/imx/ipu-v3/ipu-vdi.c
diff --git a/drivers/gpu/imx/lcdif/Kconfig b/drivers/gpu/imx/lcdif/Kconfig
new file mode 100644
index 000000000000..326cebd207f8
--- /dev/null
+++ b/drivers/gpu/imx/lcdif/Kconfig
@@ -0,0 +1,8 @@
+config IMX_LCDIF_CORE
+ tristate "i.MX LCDIF core support"
+ depends on ARCH_FSL_IMX8MM
+ depends on RESET_CONTROLLER
+ help
+ Choose this if you have a NXP i.MX8MM platform and want to use the
+ LCDIF display controller. This option only enables LCDIF base support.
+
diff --git a/drivers/gpu/imx/lcdif/Makefile b/drivers/gpu/imx/lcdif/Makefile
new file mode 100644
index 000000000000..8c7ce5ccce95
--- /dev/null
+++ b/drivers/gpu/imx/lcdif/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_IMX_LCDIF_CORE) += imx-lcdif-core.o
+
+imx-lcdif-core-objs := lcdif-common.o
diff --git a/drivers/gpu/imx/lcdif/lcdif-common.c b/drivers/gpu/imx/lcdif/lcdif-common.c
new file mode 100644
index 000000000000..06abc666ad52
--- /dev/null
+++ b/drivers/gpu/imx/lcdif/lcdif-common.c
@@ -0,0 +1,799 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/media-bus-format.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+#include <drm/drm_fourcc.h>
+#include <video/imx-lcdif.h>
+#include <video/videomode.h>
+
+#include "lcdif-regs.h"
+
+#define DRIVER_NAME "imx-lcdif"
+
+/* TODO: add this to platform data later */
+#define DISP_MIX_SFT_RSTN_CSR 0x00
+#define DISP_MIX_CLK_EN_CSR 0x04
+
+/* 'DISP_MIX_SFT_RSTN_CSR' bit fields */
+#define BUS_RSTN_BLK_SYNC_SFT_EN BIT(6)
+
+/* 'DISP_MIX_CLK_EN_CSR' bit fields */
+#define BUS_BLK_CLK_SFT_EN BIT(12)
+#define LCDIF_PIXEL_CLK_SFT_EN BIT(7)
+#define LCDIF_APB_CLK_SFT_EN BIT(6)
+
+struct lcdif_soc {
+ struct device *dev;
+
+ int irq;
+ void __iomem *base;
+ struct regmap *gpr;
+ atomic_t rpm_suspended;
+
+ struct clk *clk_pix;
+ struct clk *clk_disp_axi;
+ struct clk *clk_disp_apb;
+};
+
+struct lcdif_soc_pdata {
+ bool hsync_invert;
+ bool vsync_invert;
+ bool de_invert;
+};
+
+struct lcdif_platform_reg {
+ struct lcdif_client_platformdata pdata;
+ char *name;
+};
+
+struct lcdif_platform_reg client_reg[] = {
+ {
+ .pdata = { },
+ .name = "imx-lcdif-crtc",
+ },
+};
+
+struct lcdif_soc_pdata imx8mm_pdata = {
+ .hsync_invert = true,
+ .vsync_invert = true,
+ .de_invert = true,
+};
+
+static const struct of_device_id imx_lcdif_dt_ids[] = {
+ { .compatible = "fsl,imx8mm-lcdif", .data = &imx8mm_pdata, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, lcdif_dt_ids);
+
+#ifdef CONFIG_PM
+static int imx_lcdif_runtime_suspend(struct device *dev);
+static int imx_lcdif_runtime_resume(struct device *dev);
+#else
+static int imx_lcdif_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+static int imx_lcdif_runtime_resume(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+void disp_mix_bus_rstn_reset(struct regmap *gpr, bool reset)
+{
+ if (!reset)
+ /* release reset */
+ regmap_update_bits(gpr, DISP_MIX_SFT_RSTN_CSR,
+ BUS_RSTN_BLK_SYNC_SFT_EN,
+ BUS_RSTN_BLK_SYNC_SFT_EN);
+ else
+ /* hold reset */
+ regmap_update_bits(gpr, DISP_MIX_SFT_RSTN_CSR,
+ BUS_RSTN_BLK_SYNC_SFT_EN,
+ 0x0);
+}
+
+void disp_mix_lcdif_clks_enable(struct regmap *gpr, bool enable)
+{
+ if (enable)
+ /* enable lcdif clks */
+ regmap_update_bits(gpr, DISP_MIX_CLK_EN_CSR,
+ LCDIF_PIXEL_CLK_SFT_EN | LCDIF_APB_CLK_SFT_EN,
+ LCDIF_PIXEL_CLK_SFT_EN | LCDIF_APB_CLK_SFT_EN);
+ else
+ /* disable lcdif clks */
+ regmap_update_bits(gpr, DISP_MIX_CLK_EN_CSR,
+ LCDIF_PIXEL_CLK_SFT_EN | LCDIF_APB_CLK_SFT_EN,
+ 0x0);
+}
+
+static int lcdif_enable_clocks(struct lcdif_soc *lcdif)
+{
+ int ret;
+
+ if (lcdif->clk_disp_axi) {
+ ret = clk_prepare_enable(lcdif->clk_disp_axi);
+ if (ret)
+ return ret;
+ }
+
+ if (lcdif->clk_disp_apb) {
+ ret = clk_prepare_enable(lcdif->clk_disp_apb);
+ if (ret)
+ goto disable_disp_axi;
+ }
+
+ ret = clk_prepare_enable(lcdif->clk_pix);
+ if (ret)
+ goto disable_disp_apb;
+
+ return 0;
+
+disable_disp_apb:
+ if (lcdif->clk_disp_apb)
+ clk_disable_unprepare(lcdif->clk_disp_apb);
+disable_disp_axi:
+ if (lcdif->clk_disp_axi)
+ clk_disable_unprepare(lcdif->clk_disp_axi);
+
+ return ret;
+}
+
+static void lcdif_disable_clocks(struct lcdif_soc *lcdif)
+{
+ clk_disable_unprepare(lcdif->clk_pix);
+
+ if (lcdif->clk_disp_axi)
+ clk_disable_unprepare(lcdif->clk_disp_axi);
+
+ if (lcdif->clk_disp_apb)
+ clk_disable_unprepare(lcdif->clk_disp_apb);
+}
+
+int lcdif_vblank_irq_get(struct lcdif_soc *lcdif)
+{
+ return lcdif->irq;
+}
+EXPORT_SYMBOL(lcdif_vblank_irq_get);
+
+void lcdif_dump_registers(struct lcdif_soc *lcdif)
+{
+ pr_info("%#x : %#x\n", LCDIF_CTRL,
+ readl(lcdif->base + LCDIF_CTRL));
+ pr_info("%#x : %#x\n", LCDIF_CTRL1,
+ readl(lcdif->base + LCDIF_CTRL1));
+ pr_info("%#x : %#x\n", LCDIF_CTRL2,
+ readl(lcdif->base + LCDIF_CTRL2));
+ pr_info("%#x : %#x\n", LCDIF_TRANSFER_COUNT,
+ readl(lcdif->base + LCDIF_TRANSFER_COUNT));
+ pr_info("%#x : %#x\n", LCDIF_CUR_BUF,
+ readl(lcdif->base + LCDIF_CUR_BUF));
+ pr_info("%#x : %#x\n", LCDIF_NEXT_BUF,
+ readl(lcdif->base + LCDIF_NEXT_BUF));
+ pr_info("%#x : %#x\n", LCDIF_VDCTRL0,
+ readl(lcdif->base + LCDIF_VDCTRL0));
+ pr_info("%#x : %#x\n", LCDIF_VDCTRL1,
+ readl(lcdif->base + LCDIF_VDCTRL1));
+ pr_info("%#x : %#x\n", LCDIF_VDCTRL2,
+ readl(lcdif->base + LCDIF_VDCTRL2));
+ pr_info("%#x : %#x\n", LCDIF_VDCTRL3,
+ readl(lcdif->base + LCDIF_VDCTRL3));
+ pr_info("%#x : %#x\n", LCDIF_VDCTRL4,
+ readl(lcdif->base + LCDIF_VDCTRL4));
+}
+EXPORT_SYMBOL(lcdif_dump_registers);
+
+void lcdif_vblank_irq_enable(struct lcdif_soc *lcdif)
+{
+ writel(CTRL1_CUR_FRAME_DONE_IRQ, lcdif->base + LCDIF_CTRL1 + REG_CLR);
+ writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, lcdif->base + LCDIF_CTRL1 + REG_SET);
+}
+EXPORT_SYMBOL(lcdif_vblank_irq_enable);
+
+void lcdif_vblank_irq_disable(struct lcdif_soc *lcdif)
+{
+ writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, lcdif->base + LCDIF_CTRL1 + REG_CLR);
+ writel(CTRL1_CUR_FRAME_DONE_IRQ, lcdif->base + LCDIF_CTRL1 + REG_CLR);
+}
+EXPORT_SYMBOL(lcdif_vblank_irq_disable);
+
+void lcdif_vblank_irq_clear(struct lcdif_soc *lcdif)
+{
+ writel(CTRL1_CUR_FRAME_DONE_IRQ, lcdif->base + LCDIF_CTRL1 + REG_CLR);
+}
+EXPORT_SYMBOL(lcdif_vblank_irq_clear);
+
+static uint32_t lcdif_get_bpp_from_fmt(uint32_t format)
+{
+ /* TODO: only support RGB for now */
+
+ switch (format) {
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_BGR565:
+ case DRM_FORMAT_ARGB1555:
+ case DRM_FORMAT_XRGB1555:
+ case DRM_FORMAT_ABGR1555:
+ case DRM_FORMAT_XBGR1555:
+ return 16;
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_RGBX8888:
+ return 32;
+ default:
+ /* unsupported format */
+ return 0;
+ }
+}
+
+/*
+ * Get the bus format supported by LCDIF
+ * according to drm fourcc format
+ */
+int lcdif_get_bus_fmt_from_pix_fmt(struct lcdif_soc *lcdif,
+ uint32_t format)
+{
+ uint32_t bpp;
+
+ bpp = lcdif_get_bpp_from_fmt(format);
+ if (!bpp)
+ return -EINVAL;
+
+ switch (bpp) {
+ case 16:
+ return MEDIA_BUS_FMT_RGB565_1X16;
+ case 18:
+ return MEDIA_BUS_FMT_RGB666_1X18;
+ case 24:
+ case 32:
+ return MEDIA_BUS_FMT_RGB888_1X24;
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(lcdif_get_bus_fmt_from_pix_fmt);
+
+int lcdif_set_pix_fmt(struct lcdif_soc *lcdif, u32 format)
+{
+ u32 ctrl = 0, ctrl1 = 0;
+
+ /* TODO: lcdif should be disabled to set pixel format */
+
+ ctrl = readl(lcdif->base + LCDIF_CTRL);
+ ctrl1 = readl(lcdif->base + LCDIF_CTRL1);
+
+ /* clear pixel format related bits */
+ ctrl &= ~(CTRL_SHIFT_NUM(0x3f) | CTRL_INPUT_SWIZZLE(0x3) |
+ CTRL_CSC_SWIZZLE(0x3) | CTRL_SET_WORD_LENGTH(0x3));
+
+ ctrl1 &= ~CTRL1_SET_BYTE_PACKAGING(0xf);
+
+ /* default is 'RGB' order */
+ writel(CTRL2_ODD_LINE_PATTERN(0x7) |
+ CTRL2_EVEN_LINE_PATTERN(0x7),
+ lcdif->base + LCDIF_CTRL2 + REG_CLR);
+
+ switch (format) {
+ /* bpp 16 */
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_BGR565:
+ case DRM_FORMAT_ARGB1555:
+ case DRM_FORMAT_XRGB1555:
+ case DRM_FORMAT_ABGR1555:
+ case DRM_FORMAT_XBGR1555:
+ /* Data format */
+ ctrl = (format == DRM_FORMAT_RGB565 ||
+ format == DRM_FORMAT_BGR565) ?
+ (ctrl & ~CTRL_DF16) : (ctrl | CTRL_DF16);
+
+ ctrl |= CTRL_SET_WORD_LENGTH(0x0);
+
+ /* Byte packing */
+ ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0xf);
+
+ /* 'BGR' order */
+ if (format == DRM_FORMAT_BGR565 ||
+ format == DRM_FORMAT_ABGR1555 ||
+ format == DRM_FORMAT_XBGR1555)
+ writel(CTRL2_ODD_LINE_PATTERN(0x5) |
+ CTRL2_EVEN_LINE_PATTERN(0x5),
+ lcdif->base + LCDIF_CTRL2 + REG_SET);
+ break;
+ /* bpp 32 */
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_XBGR8888:
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_RGBX8888:
+ /*Data format */
+ ctrl &= ~CTRL_DF24;
+ ctrl |= CTRL_SET_WORD_LENGTH(3);
+
+ if (format == DRM_FORMAT_RGBA8888 ||
+ format == DRM_FORMAT_RGBX8888)
+ ctrl |= CTRL_SHIFT_DIR(1) | CTRL_SHIFT_NUM(8);
+
+ /* Byte packing */
+ ctrl1 |= CTRL1_SET_BYTE_PACKAGING(0x7);
+
+ /* 'BGR' order */
+ if (format == DRM_FORMAT_ABGR8888 ||
+ format == DRM_FORMAT_XBGR8888)
+ writel(CTRL2_ODD_LINE_PATTERN(0x5) |
+ CTRL2_EVEN_LINE_PATTERN(0x5),
+ lcdif->base + LCDIF_CTRL2 + REG_SET);
+ break;
+ default:
+ dev_err(lcdif->dev, "unsupported pixel format: %s\n",
+ drm_get_format_name(format));
+ return -EINVAL;
+ }
+
+ writel(ctrl, lcdif->base + LCDIF_CTRL);
+ writel(ctrl1, lcdif->base + LCDIF_CTRL1);
+
+ return 0;
+}
+EXPORT_SYMBOL(lcdif_set_pix_fmt);
+
+void lcdif_set_bus_fmt(struct lcdif_soc *lcdif, u32 bus_format)
+{
+ u32 bus_width;
+
+ switch (bus_format) {
+ case MEDIA_BUS_FMT_RGB565_1X16:
+ bus_width = CTRL_SET_BUS_WIDTH(STMLCDIF_16BIT);
+ break;
+ case MEDIA_BUS_FMT_RGB666_1X18:
+ bus_width = CTRL_SET_BUS_WIDTH(STMLCDIF_18BIT);
+ break;
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ bus_width = CTRL_SET_BUS_WIDTH(STMLCDIF_24BIT);
+ break;
+ default:
+ dev_err(lcdif->dev, "unknown bus format: %#x\n", bus_format);
+ return;
+ }
+
+ writel(CTRL_SET_BUS_WIDTH(0x3), lcdif->base + LCDIF_CTRL + REG_CLR);
+ writel(bus_width, lcdif->base + LCDIF_CTRL + REG_SET);
+}
+EXPORT_SYMBOL(lcdif_set_bus_fmt);
+
+void lcdif_set_fb_addr(struct lcdif_soc *lcdif, int id, u32 addr)
+{
+ switch (id) {
+ case 0:
+ /* primary plane */
+ writel(addr, lcdif->base + LCDIF_NEXT_BUF);
+ break;
+ default:
+ /* TODO: add overlay support */
+ return;
+ }
+}
+EXPORT_SYMBOL(lcdif_set_fb_addr);
+
+void lcdif_set_fb_hcrop(struct lcdif_soc *lcdif, u32 src_w,
+ u32 fb_w, bool crop)
+{
+ u32 mask_cnt, htotal, hcount;
+ u32 vdctrl2, vdctrl3, vdctrl4, transfer_count;
+ u32 pigeon_12_0, pigeon_12_1, pigeon_12_2;
+
+ if (!crop) {
+ writel(0x0, lcdif->base + HW_EPDC_PIGEON_12_0);
+ writel(0x0, lcdif->base + HW_EPDC_PIGEON_12_1);
+
+ return;
+ }
+
+ /* transfer_count's hcount, vdctrl2's htotal and vdctrl4's
+ * H_VALID_DATA_CNT should use fb width instead of hactive
+ * when requires cropping.
+ * */
+ transfer_count = readl(lcdif->base + LCDIF_TRANSFER_COUNT);
+ hcount = TRANSFER_COUNT_GET_HCOUNT(transfer_count);
+
+ transfer_count &= ~TRANSFER_COUNT_SET_HCOUNT(0xffff);
+ transfer_count |= TRANSFER_COUNT_SET_HCOUNT(fb_w);
+ writel(transfer_count, lcdif->base + LCDIF_TRANSFER_COUNT);
+
+ vdctrl2 = readl(lcdif->base + LCDIF_VDCTRL2);
+ htotal = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2);
+ htotal += fb_w - hcount;
+ vdctrl2 &= ~VDCTRL2_SET_HSYNC_PERIOD(0x3ffff);
+ vdctrl2 |= VDCTRL2_SET_HSYNC_PERIOD(htotal);
+ writel(vdctrl2, lcdif->base + LCDIF_VDCTRL2);
+
+ vdctrl4 = readl(lcdif->base + LCDIF_VDCTRL4);
+ vdctrl4 &= ~SET_DOTCLK_H_VALID_DATA_CNT(0x3ffff);
+ vdctrl4 |= SET_DOTCLK_H_VALID_DATA_CNT(fb_w);
+ writel(vdctrl4, lcdif->base + LCDIF_VDCTRL4);
+
+ /* configure related pigeon registers */
+ vdctrl3 = readl(lcdif->base + LCDIF_VDCTRL3);
+ mask_cnt = GET_HOR_WAIT_CNT(vdctrl3) - 5;
+
+ pigeon_12_0 = PIGEON_12_0_SET_STATE_MASK(0x24) |
+ PIGEON_12_0_SET_MASK_CNT(mask_cnt) |
+ PIGEON_12_0_SET_MASK_CNT_SEL(0x6) |
+ PIGEON_12_0_POL_ACTIVE_LOW |
+ PIGEON_12_0_EN;
+ writel(pigeon_12_0, lcdif->base + HW_EPDC_PIGEON_12_0);
+
+ pigeon_12_1 = PIGEON_12_1_SET_CLR_CNT(src_w) |
+ PIGEON_12_1_SET_SET_CNT(0x0);
+ writel(pigeon_12_1, lcdif->base + HW_EPDC_PIGEON_12_1);
+
+ pigeon_12_2 = 0x0;
+ writel(pigeon_12_2, lcdif->base + HW_EPDC_PIGEON_12_2);
+}
+EXPORT_SYMBOL(lcdif_set_fb_hcrop);
+
+
+void lcdif_set_mode(struct lcdif_soc *lcdif, struct videomode *vmode)
+{
+ const struct of_device_id *of_id =
+ of_match_device(imx_lcdif_dt_ids, lcdif->dev);
+ const struct lcdif_soc_pdata *soc_pdata = of_id->data;
+ u32 vdctrl0, vdctrl1, vdctrl2, vdctrl3, vdctrl4, htotal;
+
+ /* Clear the FIFO */
+ writel(CTRL1_FIFO_CLEAR, lcdif->base + LCDIF_CTRL1 + REG_SET);
+ writel(CTRL1_FIFO_CLEAR, lcdif->base + LCDIF_CTRL1 + REG_CLR);
+
+ /* set pixel clock rate */
+ clk_disable_unprepare(lcdif->clk_pix);
+ clk_set_rate(lcdif->clk_pix, vmode->pixelclock);
+ clk_prepare_enable(lcdif->clk_pix);
+
+ /* config display timings */
+ writel(TRANSFER_COUNT_SET_VCOUNT(vmode->vactive) |
+ TRANSFER_COUNT_SET_HCOUNT(vmode->hactive),
+ lcdif->base + LCDIF_TRANSFER_COUNT);
+
+ vdctrl0 = VDCTRL0_ENABLE_PRESENT |
+ VDCTRL0_VSYNC_PERIOD_UNIT |
+ VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
+ VDCTRL0_SET_VSYNC_PULSE_WIDTH(vmode->vsync_len);
+
+ /* Polarities */
+ if (soc_pdata) {
+ if ((soc_pdata->hsync_invert &&
+ vmode->flags & DISPLAY_FLAGS_HSYNC_LOW) ||
+ (!soc_pdata->hsync_invert &&
+ vmode->flags & DISPLAY_FLAGS_HSYNC_HIGH))
+ vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
+
+ if ((soc_pdata->vsync_invert &&
+ vmode->flags & DISPLAY_FLAGS_VSYNC_LOW) ||
+ (!soc_pdata->vsync_invert &&
+ vmode->flags & DISPLAY_FLAGS_VSYNC_HIGH))
+ vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
+
+ if ((soc_pdata->de_invert &&
+ vmode->flags & DISPLAY_FLAGS_DE_LOW) ||
+ (!soc_pdata->de_invert &&
+ vmode->flags & DISPLAY_FLAGS_DE_HIGH))
+ vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
+ } else {
+ if (vmode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
+ vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
+ if (vmode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
+ vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
+ if (vmode->flags & DISPLAY_FLAGS_DE_HIGH)
+ vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
+ }
+
+ if (vmode->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
+ vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
+
+ writel(vdctrl0, lcdif->base + LCDIF_VDCTRL0);
+
+ vdctrl1 = vmode->vactive + vmode->vsync_len +
+ vmode->vfront_porch + vmode->vback_porch;
+ writel(vdctrl1, lcdif->base + LCDIF_VDCTRL1);
+
+ htotal = vmode->hactive + vmode->hsync_len +
+ vmode->hfront_porch + vmode->hback_porch;
+ vdctrl2 = VDCTRL2_SET_HSYNC_PULSE_WIDTH(vmode->hsync_len) |
+ VDCTRL2_SET_HSYNC_PERIOD(htotal);
+ writel(vdctrl2, lcdif->base + LCDIF_VDCTRL2);
+
+ vdctrl3 = SET_HOR_WAIT_CNT(vmode->hsync_len + vmode->hback_porch) |
+ SET_VERT_WAIT_CNT(vmode->vsync_len + vmode->vback_porch);
+ writel(vdctrl3, lcdif->base + LCDIF_VDCTRL3);
+
+ vdctrl4 = SET_DOTCLK_H_VALID_DATA_CNT(vmode->hactive);
+ writel(vdctrl4, lcdif->base + LCDIF_VDCTRL4);
+}
+EXPORT_SYMBOL(lcdif_set_mode);
+
+void lcdif_enable_controller(struct lcdif_soc *lcdif)
+{
+ u32 ctrl2, vdctrl4;
+
+ ctrl2 = readl(lcdif->base + LCDIF_CTRL2);
+ vdctrl4 = readl(lcdif->base + LCDIF_VDCTRL4);
+
+ ctrl2 &= ~CTRL2_OUTSTANDING_REQS(0x7);
+ ctrl2 |= CTRL2_OUTSTANDING_REQS(REQ_16);
+ writel(ctrl2, lcdif->base + LCDIF_CTRL2);
+
+ /* Continous dotclock mode */
+ writel(CTRL_BYPASS_COUNT | CTRL_DOTCLK_MODE,
+ lcdif->base + LCDIF_CTRL + REG_SET);
+
+ /* enable the SYNC signals first, then the DMA engine */
+ vdctrl4 |= VDCTRL4_SYNC_SIGNALS_ON;
+ writel(vdctrl4, lcdif->base + LCDIF_VDCTRL4);
+
+ /* enable underflow recovery */
+ writel(CTRL1_RECOVERY_ON_UNDERFLOW,
+ lcdif->base + LCDIF_CTRL1 + REG_SET);
+
+ /* run lcdif */
+ writel(CTRL_MASTER, lcdif->base + LCDIF_CTRL + REG_SET);
+ writel(CTRL_RUN, lcdif->base + LCDIF_CTRL + REG_SET);
+}
+EXPORT_SYMBOL(lcdif_enable_controller);
+
+void lcdif_disable_controller(struct lcdif_soc *lcdif)
+{
+ int ret;
+ u32 ctrl, vdctrl4;
+
+ writel(CTRL_RUN, lcdif->base + LCDIF_CTRL + REG_CLR);
+ writel(CTRL_DOTCLK_MODE, lcdif->base + LCDIF_CTRL + REG_CLR);
+
+ ret = readl_poll_timeout(lcdif->base + LCDIF_CTRL, ctrl,
+ !(ctrl & CTRL_RUN), 0, 1000);
+ if (WARN_ON(ret))
+ dev_err(lcdif->dev, "disable lcdif run timeout\n");
+
+ writel(CTRL_MASTER, lcdif->base + LCDIF_CTRL + REG_CLR);
+
+ vdctrl4 = readl(lcdif->base + LCDIF_VDCTRL4);
+ vdctrl4 &= ~VDCTRL4_SYNC_SIGNALS_ON;
+ writel(vdctrl4, lcdif->base + LCDIF_VDCTRL4);
+}
+EXPORT_SYMBOL(lcdif_disable_controller);
+
+static int platform_remove_device_fn(struct device *dev, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ platform_device_unregister(pdev);
+
+ return 0;
+}
+
+static void platform_device_unregister_children(struct platform_device *pdev)
+{
+ device_for_each_child(&pdev->dev, NULL, platform_remove_device_fn);
+}
+
+static int lcdif_add_client_devices(struct lcdif_soc *lcdif)
+{
+ int ret = 0, i;
+ struct device *dev = lcdif->dev;
+ struct platform_device *pdev = NULL;
+ struct device_node *of_node;
+
+ for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
+ of_node = of_graph_get_port_by_id(dev->of_node, i);
+ if (!of_node) {
+ dev_info(dev, "no port@%d node in %s\n",
+ i, dev->of_node->full_name);
+ continue;
+ }
+ of_node_put(of_node);
+
+ pdev = platform_device_alloc(client_reg[i].name, i);
+ if (!pdev) {
+ dev_err(dev, "Can't allocate port pdev\n");
+ ret = -ENOMEM;
+ goto err_register;
+ }
+
+ pdev->dev.parent = dev;
+ client_reg[i].pdata.of_node = of_node;
+
+ ret = platform_device_add_data(pdev, &client_reg[i].pdata,
+ sizeof(client_reg[i].pdata));
+ if (!ret)
+ ret = platform_device_add(pdev);
+ if (ret) {
+ platform_device_put(pdev);
+ goto err_register;
+ }
+
+ pdev->dev.of_node = of_node;
+ }
+
+ if (!pdev)
+ return -ENODEV;
+
+ return 0;
+
+err_register:
+ platform_device_unregister_children(to_platform_device(dev));
+ return ret;
+}
+
+static int imx_lcdif_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct lcdif_soc *lcdif;
+ struct resource *res;
+
+ dev_dbg(dev, "%s: probe begin\n", __func__);
+
+ lcdif = devm_kzalloc(dev, sizeof(*lcdif), GFP_KERNEL);
+ if (!lcdif) {
+ dev_err(dev, "Can't allocate 'lcdif_soc' structure\n");
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ lcdif->irq = platform_get_irq(pdev, 0);
+ if (lcdif->irq < 0)
+ return -ENODEV;
+
+ lcdif->clk_pix = devm_clk_get(dev, "pix");
+ if (IS_ERR(lcdif->clk_pix))
+ return PTR_ERR(lcdif->clk_pix);
+
+ lcdif->clk_disp_axi = devm_clk_get(dev, "disp-axi");
+ if (IS_ERR(lcdif->clk_disp_axi))
+ lcdif->clk_disp_axi = NULL;
+
+ lcdif->clk_disp_apb = devm_clk_get(dev, "disp-apb");
+ if (IS_ERR(lcdif->clk_disp_apb))
+ lcdif->clk_disp_apb = NULL;
+
+ lcdif->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(lcdif->base))
+ return PTR_ERR(lcdif->base);
+
+ lcdif->gpr = syscon_regmap_lookup_by_phandle(np, "lcdif-gpr");
+ if (IS_ERR(lcdif->gpr))
+ return PTR_ERR(lcdif->gpr);
+
+ lcdif->dev = dev;
+ platform_set_drvdata(pdev, lcdif);
+
+ atomic_set(&lcdif->rpm_suspended, 0);
+ pm_runtime_enable(dev);
+ atomic_inc(&lcdif->rpm_suspended);
+
+ dev_dbg(dev, "%s: probe end\n", __func__);
+
+ return lcdif_add_client_devices(lcdif);
+}
+
+static int imx_lcdif_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int imx_lcdif_suspend(struct device *dev)
+{
+ return imx_lcdif_runtime_suspend(dev);
+}
+
+static int imx_lcdif_resume(struct device *dev)
+{
+ return imx_lcdif_runtime_resume(dev);
+}
+#else
+static int imx_lcdif_suspend(struct device *dev)
+{
+ return 0;
+}
+static int imx_lcdif_resume(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static int imx_lcdif_runtime_suspend(struct device *dev)
+{
+ struct lcdif_soc *lcdif = dev_get_drvdata(dev);
+
+ if (atomic_inc_return(&lcdif->rpm_suspended) > 1)
+ return 0;
+
+ lcdif_disable_clocks(lcdif);
+
+ release_bus_freq(BUS_FREQ_HIGH);
+
+ return 0;
+}
+
+static int imx_lcdif_runtime_resume(struct device *dev)
+{
+ int ret = 0;
+ struct lcdif_soc *lcdif = dev_get_drvdata(dev);
+
+ if (unlikely(!atomic_read(&lcdif->rpm_suspended))) {
+ dev_warn(lcdif->dev, "Unbalanced %s!\n", __func__);
+ return 0;
+ }
+
+ if (!atomic_dec_and_test(&lcdif->rpm_suspended))
+ return 0;
+
+ request_bus_freq(BUS_FREQ_HIGH);
+
+ ret = lcdif_enable_clocks(lcdif);
+ if (ret) {
+ release_bus_freq(BUS_FREQ_HIGH);
+ return ret;
+ }
+
+ disp_mix_bus_rstn_reset(lcdif->gpr, false);
+ disp_mix_lcdif_clks_enable(lcdif->gpr, true);
+
+ /* Pull LCDIF out of reset */
+ writel(0x0, lcdif->base + LCDIF_CTRL);
+
+ return ret;
+}
+#endif
+
+static const struct dev_pm_ops imx_lcdif_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(imx_lcdif_suspend, imx_lcdif_resume)
+ SET_RUNTIME_PM_OPS(imx_lcdif_runtime_suspend,
+ imx_lcdif_runtime_resume, NULL)
+};
+
+struct platform_driver imx_lcdif_driver = {
+ .probe = imx_lcdif_probe,
+ .remove = imx_lcdif_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = imx_lcdif_dt_ids,
+ .pm = &imx_lcdif_pm_ops,
+ },
+};
+
+module_platform_driver(imx_lcdif_driver);
+
+MODULE_DESCRIPTION("NXP i.MX LCDIF Display Controller driver");
+MODULE_AUTHOR("Fancy Fang <chen.fang@nxp.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/imx/lcdif/lcdif-regs.h b/drivers/gpu/imx/lcdif/lcdif-regs.h
new file mode 100644
index 000000000000..de2f1c55591c
--- /dev/null
+++ b/drivers/gpu/imx/lcdif/lcdif-regs.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LCDIF_REGS_H
+#define __LCDIF_REGS_H
+
+#define REG_SET 4
+#define REG_CLR 8
+
+/* regs offset */
+#define LCDIF_CTRL 0x00
+#define LCDIF_CTRL1 0X10
+#define LCDIF_CTRL2 0X20
+#define LCDIF_TRANSFER_COUNT 0x30
+#define LCDIF_CUR_BUF 0x40
+#define LCDIF_NEXT_BUF 0x50
+#define LCDIF_TIMING 0x60
+#define LCDIF_VDCTRL0 0x70
+#define LCDIF_VDCTRL1 0x80
+#define LCDIF_VDCTRL2 0x90
+#define LCDIF_VDCTRL3 0xa0
+#define LCDIF_VDCTRL4 0xb0
+
+/* pigeon registers for crop */
+#define HW_EPDC_PIGEON_12_0 0xb00
+#define HW_EPDC_PIGEON_12_1 0xb10
+#define HW_EPDC_PIGEON_12_2 0xb20
+
+/* reg bit manipulation */
+#define REG_MASK(e, s) (((1 << ((e) - (s) + 1)) - 1) << (s))
+#define REG_PUT(x, e, s) (((x) << (s)) & REG_MASK(e, s))
+#define REG_GET(x, e, s) (((x) & REG_MASK(e, s)) >> (s))
+
+#define SWIZZLE_LE 0 /* Little-Endian or No swap */
+#define SWIZZLE_BE 1 /* Big-Endian or swap all */
+#define SWIZZLE_HWD 2 /* Swap half-words */
+#define SWIZZLE_HWD_BYTE 3 /* Swap bytes within each half-word */
+
+/* regs bit fields */
+#define CTRL_SFTRST BIT(31)
+#define CTRL_CLKGATE BIT(30)
+#define CTRL_SHIFT_DIR(x) REG_PUT((x), 26, 26)
+#define CTRL_SHIFT_NUM(x) REG_PUT((x), 25, 21)
+#define CTRL_BYPASS_COUNT BIT(19)
+#define CTRL_VSYNC_MODE BIT(18)
+#define CTRL_DOTCLK_MODE BIT(17)
+#define CTRL_DATA_SELECT BIT(16)
+#define CTRL_INPUT_SWIZZLE(x) REG_PUT((x), 15, 14)
+#define CTRL_CSC_SWIZZLE(x) REG_PUT((x), 13, 12)
+#define CTRL_SET_BUS_WIDTH(x) REG_PUT((x), 11, 10)
+#define CTRL_GET_BUS_WIDTH(x) REG_GET((x), 11, 10)
+#define CTRL_BUS_WIDTH_MASK REG_PUT((0x3), 11, 10)
+#define CTRL_SET_WORD_LENGTH(x) REG_PUT((x), 9, 8)
+#define CTRL_GET_WORD_LENGTH(x) REG_GET((x), 9, 8)
+#define CTRL_MASTER BIT(5)
+#define CTRL_DF16 BIT(3)
+#define CTRL_DF18 BIT(2)
+#define CTRL_DF24 BIT(1)
+#define CTRL_RUN BIT(0)
+
+#define CTRL1_RECOVERY_ON_UNDERFLOW BIT(24)
+#define CTRL1_FIFO_CLEAR BIT(21)
+#define CTRL1_SET_BYTE_PACKAGING(x) REG_PUT((x), 19, 16)
+#define CTRL1_GET_BYTE_PACKAGING(x) REG_GET((x), 19, 16)
+#define CTRL1_CUR_FRAME_DONE_IRQ_EN BIT(13)
+#define CTRL1_CUR_FRAME_DONE_IRQ BIT(9)
+
+#define REQ_1 0
+#define REQ_2 1
+#define REQ_4 2
+#define REQ_8 3
+#define REQ_16 4
+
+#define CTRL2_OUTSTANDING_REQS(x) REG_PUT((x), 23, 21)
+#define CTRL2_ODD_LINE_PATTERN(x) REG_PUT((x), 18, 16)
+#define CTRL2_EVEN_LINE_PATTERN(x) REG_PUT((x), 14, 12)
+
+#define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16)
+#define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff)
+#define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff)
+#define TRANSFER_COUNT_GET_HCOUNT(x) ((x) & 0xffff)
+
+#define VDCTRL0_ENABLE_PRESENT BIT(28)
+#define VDCTRL0_VSYNC_ACT_HIGH BIT(27)
+#define VDCTRL0_HSYNC_ACT_HIGH BIT(26)
+#define VDCTRL0_DOTCLK_ACT_FALLING BIT(25)
+#define VDCTRL0_ENABLE_ACT_HIGH BIT(24)
+#define VDCTRL0_VSYNC_PERIOD_UNIT BIT(21)
+#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT BIT(20)
+#define VDCTRL0_HALF_LINE BIT(19)
+#define VDCTRL0_HALF_LINE_MODE BIT(18)
+#define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
+#define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff)
+
+#define VDCTRL2_SET_HSYNC_PULSE_WIDTH(x) (((x) & 0x3fff) << 18)
+#define VDCTRL2_GET_HSYNC_PULSE_WIDTH(x) (((x) >> 18) & 0x3fff)
+#define VDCTRL2_SET_HSYNC_PERIOD(x) ((x) & 0x3ffff)
+#define VDCTRL2_GET_HSYNC_PERIOD(x) ((x) & 0x3ffff)
+
+#define VDCTRL3_MUX_SYNC_SIGNALS BIT(29)
+#define VDCTRL3_VSYNC_ONLY BIT(28)
+#define SET_HOR_WAIT_CNT(x) (((x) & 0xfff) << 16)
+#define GET_HOR_WAIT_CNT(x) (((x) >> 16) & 0xfff)
+#define SET_VERT_WAIT_CNT(x) ((x) & 0xffff)
+#define GET_VERT_WAIT_CNT(x) ((x) & 0xffff)
+
+#define VDCTRL4_SET_DOTCLK_DLY(x) (((x) & 0x7) << 29) /* v4 only */
+#define VDCTRL4_GET_DOTCLK_DLY(x) (((x) >> 29) & 0x7) /* v4 only */
+#define VDCTRL4_SYNC_SIGNALS_ON BIT(18)
+#define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff)
+
+#define PIGEON_12_0_SET_STATE_MASK(x) REG_PUT((x), 31, 24)
+#define PIGEON_12_0_SET_MASK_CNT(x) REG_PUT((x), 23, 12)
+#define PIGEON_12_0_SET_MASK_CNT_SEL(x) REG_PUT((x), 11, 8)
+#define PIGEON_12_0_SET_OFFSET(x) REG_PUT((x), 7, 4)
+#define PIGEON_12_0_SET_INC_SEL(x) REG_PUT((x), 3, 2)
+#define PIGEON_12_0_POL_ACTIVE_LOW BIT(1)
+#define PIGEON_12_0_EN BIT(0)
+
+#define PIGEON_12_1_SET_CLR_CNT(x) REG_PUT((x), 31, 16)
+#define PIGEON_12_1_SET_SET_CNT(x) REG_PUT((x), 15, 0)
+
+#define STMLCDIF_8BIT 1 /* pixel data bus to the display is of 8 bit width */
+#define STMLCDIF_16BIT 0 /* pixel data bus to the display is of 16 bit width */
+#define STMLCDIF_18BIT 2 /* pixel data bus to the display is of 18 bit width */
+#define STMLCDIF_24BIT 3 /* pixel data bus to the display is of 24 bit width */
+
+#define MIN_XRES 120
+#define MIN_YRES 120
+#define MAX_XRES 0xffff
+#define MAX_YRES 0xffff
+
+#endif
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 45cef3d2c75c..3105d8b3f0b3 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -825,6 +825,15 @@ config SENSORS_MAX1668
This driver can also be built as a module. If so, the module
will be called max1668.
+config SENSORS_MAX17135
+ tristate "Maxim MAX17135 EPD temperature sensor"
+ depends on I2C
+ help
+ If you say yes here you get support for MAX17135 PMIC sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called max17135_sensor.
+
config SENSORS_MAX197
tristate "Maxim MAX197 and compatibles"
help
@@ -1506,7 +1515,7 @@ config SENSORS_ADS7871
config SENSORS_AMC6821
tristate "Texas Instruments AMC6821"
- depends on I2C
+ depends on I2C
help
If you say yes here you get support for the Texas Instruments
AMC6821 hardware monitoring chips.
@@ -1857,4 +1866,18 @@ config SENSORS_ATK0110
endif # ACPI
+config SENSORS_MAG3110
+ tristate "Freescale MAG3110 e-compass sensor"
+ depends on I2C && SYSFS
+ help
+ If you say yes here you get support for the Freescale MAG3110
+ e-compass sensor.
+ This driver can also be built as a module. If so, the module
+ will be called mag3110.
+
+config MXC_MMA8451
+ tristate "MMA8451 device driver"
+ depends on I2C
+ default y
+
endif # HWMON
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index aecf4ba17460..28a22f6c7391 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -113,6 +113,7 @@ obj-$(CONFIG_SENSORS_MAX1111) += max1111.o
obj-$(CONFIG_SENSORS_MAX16065) += max16065.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_MAX1668) += max1668.o
+obj-$(CONFIG_SENSORS_MAX17135) += max17135-hwmon.o
obj-$(CONFIG_SENSORS_MAX197) += max197.o
obj-$(CONFIG_SENSORS_MAX31722) += max31722.o
obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
@@ -166,6 +167,8 @@ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
obj-$(CONFIG_SENSORS_XGENE) += xgene-hwmon.o
+obj-$(CONFIG_SENSORS_MAG3110) += mag3110.o
+obj-$(CONFIG_MXC_MMA8451) += mxc_mma8451.o
obj-$(CONFIG_PMBUS) += pmbus/
diff --git a/drivers/hwmon/mag3110.c b/drivers/hwmon/mag3110.c
new file mode 100644
index 000000000000..c38fd6e0da52
--- /dev/null
+++ b/drivers/hwmon/mag3110.c
@@ -0,0 +1,654 @@
+/*
+ *
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/input-polldev.h>
+#include <linux/hwmon.h>
+#include <linux/input.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#define MAG3110_DRV_NAME "mag3110"
+#define MAG3110_ID (0xC4)
+#define MAG3110_XYZ_DATA_LEN (6)
+#define MAG3110_STATUS_ZYXDR (0x08)
+#define MAG3110_AC_MASK (0x01)
+#define MAG3110_AC_OFFSET (0)
+#define MAG3110_DR_MODE_MASK (0x7 << 5)
+#define MAG3110_DR_MODE_OFFSET (5)
+
+#define POLL_INTERVAL_MAX (500)
+#define POLL_INTERVAL (100)
+#define INT_TIMEOUT (1000)
+#define DEFAULT_POSITION (2)
+
+/* register enum for mag3110 registers */
+enum {
+ MAG3110_DR_STATUS = 0x00,
+ MAG3110_OUT_X_MSB,
+ MAG3110_OUT_X_LSB,
+ MAG3110_OUT_Y_MSB,
+ MAG3110_OUT_Y_LSB,
+ MAG3110_OUT_Z_MSB,
+ MAG3110_OUT_Z_LSB,
+ MAG3110_WHO_AM_I,
+
+ MAG3110_OFF_X_MSB,
+ MAG3110_OFF_X_LSB,
+ MAG3110_OFF_Y_MSB,
+ MAG3110_OFF_Y_LSB,
+ MAG3110_OFF_Z_MSB,
+ MAG3110_OFF_Z_LSB,
+
+ MAG3110_DIE_TEMP,
+
+ MAG3110_CTRL_REG1 = 0x10,
+ MAG3110_CTRL_REG2,
+};
+
+enum {
+ MAG_STANDBY,
+ MAG_ACTIVED
+};
+
+struct mag3110_data {
+ struct i2c_client *client;
+ struct input_polled_dev *poll_dev;
+ struct device *hwmon_dev;
+ wait_queue_head_t waitq;
+ bool data_ready;
+ u8 ctl_reg1;
+ int active;
+ int position;
+ int use_irq;
+};
+
+static short MAGHAL[8][3][3] = {
+ { {0, 1, 0}, {-1, 0, 0}, {0, 0, 1} },
+ { {1, 0, 0}, {0, 1, 0}, {0, 0, 1} },
+ { {0, -1, 0}, {1, 0, 0}, {0, 0, 1} },
+ { {-1, 0, 0}, {0, -1, 0}, {0, 0, 1} },
+
+ { {0, 1, 0}, {1, 0, 0}, {0, 0, -1} },
+ { {1, 0, 0}, {0, -1, 0}, {0, 0, -1} },
+ { {0, -1, 0}, {-1, 0, 0}, {0, 0, -1} },
+ { {-1, 0, 0}, {0, 1, 0}, {0, 0, -1} },
+};
+
+static struct mag3110_data *mag3110_pdata;
+static DEFINE_MUTEX(mag3110_lock);
+
+/*
+ * This function do one mag3110 register read.
+ */
+static int mag3110_adjust_position(short *x, short *y, short *z)
+{
+ short rawdata[3], data[3];
+ int i, j;
+ int position = mag3110_pdata->position;
+ if (position < 0 || position > 7)
+ position = 0;
+ rawdata[0] = *x;
+ rawdata[1] = *y;
+ rawdata[2] = *z;
+ for (i = 0; i < 3; i++) {
+ data[i] = 0;
+ for (j = 0; j < 3; j++)
+ data[i] += rawdata[j] * MAGHAL[position][i][j];
+ }
+ *x = data[0];
+ *y = data[1];
+ *z = data[2];
+ return 0;
+}
+
+static int mag3110_read_reg(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+/*
+ * This function do one mag3110 register write.
+ */
+static int mag3110_write_reg(struct i2c_client *client, u8 reg, char value)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, reg, value);
+ if (ret < 0)
+ dev_err(&client->dev, "i2c write failed\n");
+ return ret;
+}
+
+/*
+ * This function do multiple mag3110 registers read.
+ */
+static int mag3110_read_block_data(struct i2c_client *client, u8 reg,
+ int count, u8 *addr)
+{
+ if (i2c_smbus_read_i2c_block_data(client, reg, count, addr) < count) {
+ dev_err(&client->dev, "i2c block read failed\n");
+ return -1;
+ }
+
+ return count;
+}
+
+/*
+ * Initialization function
+ */
+static int mag3110_init_client(struct i2c_client *client)
+{
+ int val, ret;
+
+ /* enable automatic resets */
+ val = 0x80;
+ ret = mag3110_write_reg(client, MAG3110_CTRL_REG2, val);
+
+ /* set default data rate to 10HZ */
+ val = mag3110_read_reg(client, MAG3110_CTRL_REG1);
+ val |= (0x0 << MAG3110_DR_MODE_OFFSET);
+ ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, val);
+
+ return ret;
+}
+
+/*
+ * read sensor data from mag3110
+ */
+static int mag3110_read_data(short *x, short *y, short *z)
+{
+ struct mag3110_data *data;
+ u8 tmp_data[MAG3110_XYZ_DATA_LEN];
+ int retry = 3;
+ int result;
+
+ if (!mag3110_pdata || mag3110_pdata->active == MAG_STANDBY)
+ return -EINVAL;
+
+ data = mag3110_pdata;
+ if (data->use_irq && !wait_event_interruptible_timeout
+ (data->waitq, data->data_ready != 0,
+ msecs_to_jiffies(INT_TIMEOUT))) {
+ dev_dbg(&data->client->dev, "interrupt not received\n");
+ return -ETIME;
+ }
+
+ do {
+ msleep(1);
+ result = i2c_smbus_read_byte_data(data->client,
+ MAG3110_DR_STATUS);
+ retry--;
+ } while (!(result & MAG3110_STATUS_ZYXDR) && retry > 0);
+ /* Clear data_ready flag after data is read out */
+ if (retry == 0)
+ return -EINVAL;
+
+ data->data_ready = 0;
+
+ while (i2c_smbus_read_byte_data(data->client, MAG3110_DR_STATUS)) {
+ if (mag3110_read_block_data(data->client,
+ MAG3110_OUT_X_MSB, MAG3110_XYZ_DATA_LEN,
+ tmp_data) < 0)
+ return -1;
+ }
+
+ *x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1];
+ *y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3];
+ *z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5];
+
+ return 0;
+}
+
+static void report_abs(void)
+{
+ struct input_dev *idev;
+ short x, y, z;
+
+ mutex_lock(&mag3110_lock);
+ if (mag3110_read_data(&x, &y, &z) != 0)
+ goto out;
+ mag3110_adjust_position(&x, &y, &z);
+ idev = mag3110_pdata->poll_dev->input;
+ input_report_abs(idev, ABS_X, x);
+ input_report_abs(idev, ABS_Y, y);
+ input_report_abs(idev, ABS_Z, z);
+ input_sync(idev);
+out:
+ mutex_unlock(&mag3110_lock);
+}
+
+static void mag3110_dev_poll(struct input_polled_dev *dev)
+{
+ report_abs();
+}
+
+static irqreturn_t mag3110_irq_handler(int irq, void *dev_id)
+{
+ int result;
+ u8 tmp_data[MAG3110_XYZ_DATA_LEN];
+ result = i2c_smbus_read_byte_data(mag3110_pdata->client,
+ MAG3110_DR_STATUS);
+ if (!(result & MAG3110_STATUS_ZYXDR))
+ return IRQ_NONE;
+
+ mag3110_pdata->data_ready = 1;
+
+ if (mag3110_pdata->active == MAG_STANDBY)
+ /*
+ * Since the mode will be changed, sometimes irq will
+ * be handled in StandBy mode because of interrupt latency.
+ * So just clear the interrutp flag via reading block data.
+ */
+ mag3110_read_block_data(mag3110_pdata->client,
+ MAG3110_OUT_X_MSB,
+ MAG3110_XYZ_DATA_LEN, tmp_data);
+ else
+ wake_up_interruptible(&mag3110_pdata->waitq);
+
+ return IRQ_HANDLED;
+}
+
+static ssize_t mag3110_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client;
+ int val;
+ mutex_lock(&mag3110_lock);
+ client = mag3110_pdata->client;
+ val = mag3110_read_reg(client, MAG3110_CTRL_REG1) & MAG3110_AC_MASK;
+
+ mutex_unlock(&mag3110_lock);
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t mag3110_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client;
+ int reg, ret;
+ long enable;
+ u8 tmp_data[MAG3110_XYZ_DATA_LEN];
+
+ ret = kstrtol(buf, 10, &enable);
+ if (ret) {
+ dev_err(dev, "string to long error\n");
+ return ret;
+ }
+
+ mutex_lock(&mag3110_lock);
+ client = mag3110_pdata->client;
+
+ reg = mag3110_read_reg(client, MAG3110_CTRL_REG1);
+ if (enable && mag3110_pdata->active == MAG_STANDBY) {
+ reg |= MAG3110_AC_MASK;
+ ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg);
+ if (!ret)
+ mag3110_pdata->active = MAG_ACTIVED;
+ } else if (!enable && mag3110_pdata->active == MAG_ACTIVED) {
+ reg &= ~MAG3110_AC_MASK;
+ ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg);
+ if (!ret)
+ mag3110_pdata->active = MAG_STANDBY;
+ }
+
+ /* Read out MSB data to clear interrupt flag */
+ msleep(100);
+ mag3110_read_block_data(mag3110_pdata->client, MAG3110_OUT_X_MSB,
+ MAG3110_XYZ_DATA_LEN, tmp_data);
+ mutex_unlock(&mag3110_lock);
+ return count;
+}
+
+static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO,
+ mag3110_enable_show, mag3110_enable_store);
+
+static ssize_t mag3110_dr_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client;
+ int val;
+
+ client = mag3110_pdata->client;
+ val = (mag3110_read_reg(client, MAG3110_CTRL_REG1)
+ & MAG3110_DR_MODE_MASK) >> MAG3110_DR_MODE_OFFSET;
+
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t mag3110_dr_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client;
+ int reg, ret;
+ unsigned long val;
+
+ /* This must be done when mag3110 is disabled */
+ if ((kstrtoul(buf, 10, &val) < 0) || (val > 7))
+ return -EINVAL;
+
+ client = mag3110_pdata->client;
+ reg = mag3110_read_reg(client, MAG3110_CTRL_REG1) &
+ ~MAG3110_DR_MODE_MASK;
+ reg |= (val << MAG3110_DR_MODE_OFFSET);
+ /* MAG3110_CTRL_REG1 bit 5-7: data rate mode */
+ ret = mag3110_write_reg(client, MAG3110_CTRL_REG1, reg);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(dr_mode, S_IWUSR | S_IRUGO,
+ mag3110_dr_mode_show, mag3110_dr_mode_store);
+
+static ssize_t mag3110_position_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int val;
+ mutex_lock(&mag3110_lock);
+ val = mag3110_pdata->position;
+ mutex_unlock(&mag3110_lock);
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t mag3110_position_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ long position;
+ int ret;
+ ret = kstrtol(buf, 10, &position);
+ if (ret) {
+ dev_err(dev, "string to long error\n");
+ return ret;
+ }
+
+ mutex_lock(&mag3110_lock);
+ mag3110_pdata->position = (int)position;
+ mutex_unlock(&mag3110_lock);
+ return count;
+}
+
+static DEVICE_ATTR(position, S_IWUSR | S_IRUGO,
+ mag3110_position_show, mag3110_position_store);
+
+static struct attribute *mag3110_attributes[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_dr_mode.attr,
+ &dev_attr_position.attr,
+ NULL
+};
+
+static const struct attribute_group mag3110_attr_group = {
+ .attrs = mag3110_attributes,
+};
+
+static int mag3110_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter;
+ struct input_dev *idev = NULL;
+ struct mag3110_data *data;
+ int ret = 0;
+ struct regulator *vdd, *vdd_io;
+ u32 pos = 0;
+ struct device_node *of_node = client->dev.of_node;
+ u32 irq_flag;
+ struct irq_data *irq_data = NULL;
+ bool shared_irq = of_property_read_bool(of_node, "shared-interrupt");
+
+ vdd = NULL;
+ vdd_io = NULL;
+
+ vdd = devm_regulator_get(&client->dev, "vdd");
+ if (!IS_ERR(vdd)) {
+ ret = regulator_enable(vdd);
+ if (ret) {
+ dev_err(&client->dev, "vdd set voltage error\n");
+ return ret;
+ }
+ }
+
+ vdd_io = devm_regulator_get(&client->dev, "vddio");
+ if (!IS_ERR(vdd_io)) {
+ ret = regulator_enable(vdd_io);
+ if (ret) {
+ dev_err(&client->dev, "vddio set voltage error\n");
+ return ret;
+ }
+ }
+
+ adapter = to_i2c_adapter(client->dev.parent);
+ if (!i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK))
+ return -EIO;
+
+ dev_info(&client->dev, "check mag3110 chip ID\n");
+ ret = mag3110_read_reg(client, MAG3110_WHO_AM_I);
+
+ if (MAG3110_ID != ret) {
+ dev_err(&client->dev,
+ "read chip ID 0x%x is not equal to 0x%x!\n", ret,
+ MAG3110_ID);
+ return -EINVAL;
+ }
+ data = kzalloc(sizeof(struct mag3110_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ data->client = client;
+ i2c_set_clientdata(client, data);
+ /* Init queue */
+ init_waitqueue_head(&data->waitq);
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ dev_err(&client->dev, "hwmon register failed!\n");
+ ret = PTR_ERR(data->hwmon_dev);
+ goto error_rm_dev_sysfs;
+ }
+
+ if (client->irq > 0) {
+ data->use_irq = 1;
+ irq_data = irq_get_irq_data(client->irq);
+ }
+
+ /*input poll device register */
+ data->poll_dev = input_allocate_polled_device();
+ if (!data->poll_dev) {
+ dev_err(&client->dev, "alloc poll device failed!\n");
+ ret = -ENOMEM;
+ goto error_rm_hwmon_dev;
+ }
+ data->poll_dev->poll = mag3110_dev_poll;
+ data->poll_dev->poll_interval = POLL_INTERVAL;
+ data->poll_dev->poll_interval_max = POLL_INTERVAL_MAX;
+ idev = data->poll_dev->input;
+ idev->name = MAG3110_DRV_NAME;
+ idev->id.bustype = BUS_I2C;
+ idev->evbit[0] = BIT_MASK(EV_ABS);
+ input_set_abs_params(idev, ABS_X, -15000, 15000, 0, 0);
+ input_set_abs_params(idev, ABS_Y, -15000, 15000, 0, 0);
+ input_set_abs_params(idev, ABS_Z, -15000, 15000, 0, 0);
+ ret = input_register_polled_device(data->poll_dev);
+ if (ret) {
+ dev_err(&client->dev, "register poll device failed!\n");
+ goto error_free_poll_dev;
+ }
+
+ /*create device group in sysfs as user interface */
+ ret = sysfs_create_group(&idev->dev.kobj, &mag3110_attr_group);
+ if (ret) {
+ dev_err(&client->dev, "create device file failed!\n");
+ ret = -EINVAL;
+ goto error_rm_poll_dev;
+ }
+
+ if (data->use_irq) {
+ irq_flag = irqd_get_trigger_type(irq_data);
+ irq_flag |= IRQF_ONESHOT;
+ if (shared_irq)
+ irq_flag |= IRQF_SHARED;
+ ret = request_threaded_irq(client->irq, NULL, mag3110_irq_handler,
+ irq_flag, client->dev.driver->name, idev);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed to register irq %d!\n",
+ client->irq);
+ goto error_rm_dev_sysfs;
+ }
+ }
+
+ /* Initialize mag3110 chip */
+ mag3110_init_client(client);
+ mag3110_pdata = data;
+ mag3110_pdata->active = MAG_STANDBY;
+ ret = of_property_read_u32(of_node, "position", &pos);
+ if (ret)
+ pos = DEFAULT_POSITION;
+ mag3110_pdata->position = (int)pos;
+ dev_info(&client->dev, "mag3110 is probed\n");
+ return 0;
+error_rm_dev_sysfs:
+ sysfs_remove_group(&client->dev.kobj, &mag3110_attr_group);
+error_rm_poll_dev:
+ input_unregister_polled_device(data->poll_dev);
+error_free_poll_dev:
+ input_free_polled_device(data->poll_dev);
+error_rm_hwmon_dev:
+ hwmon_device_unregister(data->hwmon_dev);
+
+ kfree(data);
+ mag3110_pdata = NULL;
+
+ return ret;
+}
+
+static int mag3110_remove(struct i2c_client *client)
+{
+ struct mag3110_data *data;
+ int ret;
+
+ data = i2c_get_clientdata(client);
+
+ data->ctl_reg1 = mag3110_read_reg(client, MAG3110_CTRL_REG1);
+ ret = mag3110_write_reg(client, MAG3110_CTRL_REG1,
+ data->ctl_reg1 & ~MAG3110_AC_MASK);
+
+ free_irq(client->irq, data);
+ input_unregister_polled_device(data->poll_dev);
+ input_free_polled_device(data->poll_dev);
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &mag3110_attr_group);
+ kfree(data);
+ mag3110_pdata = NULL;
+
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int mag3110_suspend(struct device *dev)
+{
+ int ret = 0;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mag3110_data *data = i2c_get_clientdata(client);
+
+ if (data->active == MAG_ACTIVED) {
+ data->ctl_reg1 = mag3110_read_reg(client, MAG3110_CTRL_REG1);
+ ret = mag3110_write_reg(client, MAG3110_CTRL_REG1,
+ data->ctl_reg1 & ~MAG3110_AC_MASK);
+ }
+ return ret;
+}
+
+static int mag3110_resume(struct device *dev)
+{
+ int ret = 0;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mag3110_data *data = i2c_get_clientdata(client);
+ u8 tmp_data[MAG3110_XYZ_DATA_LEN];
+
+ if (data->active == MAG_ACTIVED) {
+ ret = mag3110_write_reg(client, MAG3110_CTRL_REG1,
+ data->ctl_reg1);
+
+ if (data->ctl_reg1 & MAG3110_AC_MASK) {
+ /* Read out MSB data to clear interrupt
+ flag automatically */
+ mag3110_read_block_data(client, MAG3110_OUT_X_MSB,
+ MAG3110_XYZ_DATA_LEN, tmp_data);
+ }
+ }
+ return ret;
+}
+
+static const struct dev_pm_ops mag3110_dev_pm_ops = {
+ .suspend = mag3110_suspend,
+ .resume = mag3110_resume,
+};
+#define MAG3110_DEV_PM_OPS (&mag3110_dev_pm_ops)
+
+#else
+#define MAG3110_DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static const struct i2c_device_id mag3110_id[] = {
+ {MAG3110_DRV_NAME, 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, mag3110_id);
+static struct i2c_driver mag3110_driver = {
+ .driver = {
+ .name = MAG3110_DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = MAG3110_DEV_PM_OPS,
+ },
+ .probe = mag3110_probe,
+ .remove = mag3110_remove,
+ .id_table = mag3110_id,
+};
+
+static int __init mag3110_init(void)
+{
+ return i2c_add_driver(&mag3110_driver);
+}
+
+static void __exit mag3110_exit(void)
+{
+ i2c_del_driver(&mag3110_driver);
+}
+
+module_init(mag3110_init);
+module_exit(mag3110_exit);
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Freescale mag3110 3-axis magnetometer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/max17135-hwmon.c b/drivers/hwmon/max17135-hwmon.c
new file mode 100644
index 000000000000..c8ddb252a616
--- /dev/null
+++ b/drivers/hwmon/max17135-hwmon.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ *
+ */
+/*
+ * max17135.c
+ *
+ * Based on the MAX1619 driver.
+ * Copyright (C) 2003-2004 Alexey Fisher <fishor@mail.ru>
+ * Jean Delvare <khali@linux-fr.org>
+ *
+ * The MAX17135 is a sensor chip made by Maxim.
+ * It reports up to two temperatures (its own plus up to
+ * one external one).
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/max17135.h>
+
+/*
+ * Conversions
+ */
+static int temp_from_reg(int val)
+{
+ return val >> 8;
+}
+
+/*
+ * Functions declaration
+ */
+static int max17135_sensor_probe(struct platform_device *pdev);
+static int max17135_sensor_remove(struct platform_device *pdev);
+
+static const struct platform_device_id max17135_sns_id[] = {
+ { "max17135-sns", 0},
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, max17135_sns_id);
+
+/*
+ * Driver data (common to all clients)
+ */
+static struct platform_driver max17135_sensor_driver = {
+ .probe = max17135_sensor_probe,
+ .remove = max17135_sensor_remove,
+ .id_table = max17135_sns_id,
+ .driver = {
+ .name = "max17135_sensor",
+ },
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+struct max17135_data {
+ struct device *hwmon_dev;
+};
+
+/*
+ * Sysfs stuff
+ */
+static ssize_t show_temp_input1(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned int reg_val;
+ max17135_reg_read(REG_MAX17135_INT_TEMP, &reg_val);
+ return snprintf(buf, PAGE_SIZE, "%d\n", temp_from_reg(reg_val));
+}
+
+static ssize_t show_temp_input2(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned int reg_val;
+ max17135_reg_read(REG_MAX17135_EXT_TEMP, &reg_val);
+ return snprintf(buf, PAGE_SIZE, "%d\n", temp_from_reg(reg_val));
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
+static DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input2, NULL);
+
+static struct attribute *max17135_attributes[] = {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp2_input.attr,
+ NULL
+};
+
+static const struct attribute_group max17135_group = {
+ .attrs = max17135_attributes,
+};
+
+/*
+ * Real code
+ */
+static int max17135_sensor_probe(struct platform_device *pdev)
+{
+ struct max17135_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct max17135_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ /* Register sysfs hooks */
+ err = sysfs_create_group(&pdev->dev.kobj, &max17135_group);
+ if (err)
+ goto exit_free;
+
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove_files;
+ }
+
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+
+exit_remove_files:
+ sysfs_remove_group(&pdev->dev.kobj, &max17135_group);
+exit_free:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int max17135_sensor_remove(struct platform_device *pdev)
+{
+ struct max17135_data *data = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&pdev->dev.kobj, &max17135_group);
+
+ kfree(data);
+ return 0;
+}
+
+static int __init sensors_max17135_init(void)
+{
+ return platform_driver_register(&max17135_sensor_driver);
+}
+module_init(sensors_max17135_init);
+
+static void __exit sensors_max17135_exit(void)
+{
+ platform_driver_unregister(&max17135_sensor_driver);
+}
+module_exit(sensors_max17135_exit);
+
+MODULE_DESCRIPTION("MAX17135 sensor driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/hwmon/mxc_mma8451.c b/drivers/hwmon/mxc_mma8451.c
new file mode 100644
index 000000000000..9d6c53927757
--- /dev/null
+++ b/drivers/hwmon/mxc_mma8451.c
@@ -0,0 +1,599 @@
+/*
+ * mma8451.c - Linux kernel modules for 3-Axis Orientation/Motion
+ * Detection Sensor
+ *
+ * Copyright (C) 2010-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/pm.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/input-polldev.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#define MMA8451_I2C_ADDR 0x1C
+#define MMA8451_ID 0x1A
+#define MMA8452_ID 0x2A
+#define MMA8453_ID 0x3A
+
+#define POLL_INTERVAL_MIN 1
+#define POLL_INTERVAL_MAX 500
+#define POLL_INTERVAL 100 /* msecs */
+#define INPUT_FUZZ 32
+#define INPUT_FLAT 32
+#define MODE_CHANGE_DELAY_MS 100
+
+#define MMA8451_STATUS_ZYXDR 0x08
+#define MMA8451_BUF_SIZE 7
+#define DEFAULT_POSITION 0
+
+/* register enum for mma8451 registers */
+enum {
+ MMA8451_STATUS = 0x00,
+ MMA8451_OUT_X_MSB,
+ MMA8451_OUT_X_LSB,
+ MMA8451_OUT_Y_MSB,
+ MMA8451_OUT_Y_LSB,
+ MMA8451_OUT_Z_MSB,
+ MMA8451_OUT_Z_LSB,
+
+ MMA8451_F_SETUP = 0x09,
+ MMA8451_TRIG_CFG,
+ MMA8451_SYSMOD,
+ MMA8451_INT_SOURCE,
+ MMA8451_WHO_AM_I,
+ MMA8451_XYZ_DATA_CFG,
+ MMA8451_HP_FILTER_CUTOFF,
+
+ MMA8451_PL_STATUS,
+ MMA8451_PL_CFG,
+ MMA8451_PL_COUNT,
+ MMA8451_PL_BF_ZCOMP,
+ MMA8451_P_L_THS_REG,
+
+ MMA8451_FF_MT_CFG,
+ MMA8451_FF_MT_SRC,
+ MMA8451_FF_MT_THS,
+ MMA8451_FF_MT_COUNT,
+
+ MMA8451_TRANSIENT_CFG = 0x1D,
+ MMA8451_TRANSIENT_SRC,
+ MMA8451_TRANSIENT_THS,
+ MMA8451_TRANSIENT_COUNT,
+
+ MMA8451_PULSE_CFG,
+ MMA8451_PULSE_SRC,
+ MMA8451_PULSE_THSX,
+ MMA8451_PULSE_THSY,
+ MMA8451_PULSE_THSZ,
+ MMA8451_PULSE_TMLT,
+ MMA8451_PULSE_LTCY,
+ MMA8451_PULSE_WIND,
+
+ MMA8451_ASLP_COUNT,
+ MMA8451_CTRL_REG1,
+ MMA8451_CTRL_REG2,
+ MMA8451_CTRL_REG3,
+ MMA8451_CTRL_REG4,
+ MMA8451_CTRL_REG5,
+
+ MMA8451_OFF_X,
+ MMA8451_OFF_Y,
+ MMA8451_OFF_Z,
+
+ MMA8451_REG_END,
+};
+
+/* The sensitivity is represented in counts/g. In 2g mode the
+sensitivity is 1024 counts/g. In 4g mode the sensitivity is 512
+counts/g and in 8g mode the sensitivity is 256 counts/g.
+ */
+enum {
+ MODE_2G = 0,
+ MODE_4G,
+ MODE_8G,
+};
+
+enum {
+ MMA_STANDBY = 0,
+ MMA_ACTIVED,
+};
+
+/* mma8451 status */
+struct mma8451_status {
+ u8 mode;
+ u8 ctl_reg1;
+ int active;
+ int position;
+};
+
+static struct mma8451_status mma_status;
+static struct input_polled_dev *mma8451_idev;
+static struct device *hwmon_dev;
+static struct i2c_client *mma8451_i2c_client;
+
+static int senstive_mode = MODE_2G;
+static int ACCHAL[8][3][3] = {
+ { {0, -1, 0}, {1, 0, 0}, {0, 0, 1} },
+ { {-1, 0, 0}, {0, -1, 0}, {0, 0, 1} },
+ { {0, 1, 0}, {-1, 0, 0}, {0, 0, 1} },
+ { {1, 0, 0}, {0, 1, 0}, {0, 0, 1} },
+
+ { {0, -1, 0}, {-1, 0, 0}, {0, 0, -1} },
+ { {-1, 0, 0}, {0, 1, 0}, {0, 0, -1} },
+ { {0, 1, 0}, {1, 0, 0}, {0, 0, -1} },
+ { {1, 0, 0}, {0, -1, 0}, {0, 0, -1} },
+};
+
+static DEFINE_MUTEX(mma8451_lock);
+static int mma8451_adjust_position(short *x, short *y, short *z)
+{
+ short rawdata[3], data[3];
+ int i, j;
+ int position = mma_status.position;
+ if (position < 0 || position > 7)
+ position = 0;
+ rawdata[0] = *x;
+ rawdata[1] = *y;
+ rawdata[2] = *z;
+ for (i = 0; i < 3; i++) {
+ data[i] = 0;
+ for (j = 0; j < 3; j++)
+ data[i] += rawdata[j] * ACCHAL[position][i][j];
+ }
+ *x = data[0];
+ *y = data[1];
+ *z = data[2];
+ return 0;
+}
+
+static int mma8451_change_mode(struct i2c_client *client, int mode)
+{
+ int result;
+
+ mma_status.ctl_reg1 = 0;
+ result = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, 0);
+ if (result < 0)
+ goto out;
+ mma_status.active = MMA_STANDBY;
+
+ result = i2c_smbus_write_byte_data(client, MMA8451_XYZ_DATA_CFG,
+ mode);
+ if (result < 0)
+ goto out;
+ mdelay(MODE_CHANGE_DELAY_MS);
+ mma_status.mode = mode;
+
+ return 0;
+out:
+ dev_err(&client->dev, "error when init mma8451:(%d)", result);
+ return result;
+}
+
+static int mma8451_read_data(short *x, short *y, short *z)
+{
+ u8 tmp_data[MMA8451_BUF_SIZE];
+ int ret;
+
+ ret = i2c_smbus_read_i2c_block_data(mma8451_i2c_client,
+ MMA8451_OUT_X_MSB, 7, tmp_data);
+ if (ret < MMA8451_BUF_SIZE) {
+ dev_err(&mma8451_i2c_client->dev, "i2c block read failed\n");
+ return -EIO;
+ }
+
+ *x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1];
+ *y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3];
+ *z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5];
+ return 0;
+}
+
+static void report_abs(void)
+{
+ short x, y, z;
+ int result;
+ int retry = 3;
+
+ mutex_lock(&mma8451_lock);
+ if (mma_status.active == MMA_STANDBY)
+ goto out;
+ /* wait for the data ready */
+ do {
+ result = i2c_smbus_read_byte_data(mma8451_i2c_client,
+ MMA8451_STATUS);
+ retry--;
+ msleep(1);
+ } while (!(result & MMA8451_STATUS_ZYXDR) && retry > 0);
+ if (retry == 0)
+ goto out;
+ if (mma8451_read_data(&x, &y, &z) != 0)
+ goto out;
+ mma8451_adjust_position(&x, &y, &z);
+ input_report_abs(mma8451_idev->input, ABS_X, x);
+ input_report_abs(mma8451_idev->input, ABS_Y, y);
+ input_report_abs(mma8451_idev->input, ABS_Z, z);
+ input_sync(mma8451_idev->input);
+out:
+ mutex_unlock(&mma8451_lock);
+}
+
+static void mma8451_dev_poll(struct input_polled_dev *dev)
+{
+ report_abs();
+}
+
+static ssize_t mma8451_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client;
+ u8 val;
+ int enable;
+
+ mutex_lock(&mma8451_lock);
+ client = mma8451_i2c_client;
+ val = i2c_smbus_read_byte_data(client, MMA8451_CTRL_REG1);
+ if ((val & 0x01) && mma_status.active == MMA_ACTIVED)
+ enable = 1;
+ else
+ enable = 0;
+ mutex_unlock(&mma8451_lock);
+ return sprintf(buf, "%d\n", enable);
+}
+
+static ssize_t mma8451_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client;
+ int ret;
+ unsigned long enable;
+ u8 val = 0;
+
+ ret = kstrtoul(buf, 10, &enable);
+ if (ret) {
+ dev_err(dev, "string transform error\n");
+ return ret;
+ }
+
+ mutex_lock(&mma8451_lock);
+ client = mma8451_i2c_client;
+ enable = (enable > 0) ? 1 : 0;
+ if (enable && mma_status.active == MMA_STANDBY) {
+ val = i2c_smbus_read_byte_data(client, MMA8451_CTRL_REG1);
+ ret =
+ i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1,
+ val | 0x01);
+ if (!ret)
+ mma_status.active = MMA_ACTIVED;
+
+ } else if (enable == 0 && mma_status.active == MMA_ACTIVED) {
+ val = i2c_smbus_read_byte_data(client, MMA8451_CTRL_REG1);
+ ret =
+ i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1,
+ val & 0xFE);
+ if (!ret)
+ mma_status.active = MMA_STANDBY;
+
+ }
+ mutex_unlock(&mma8451_lock);
+ return count;
+}
+
+static ssize_t mma8451_position_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int position = 0;
+ mutex_lock(&mma8451_lock);
+ position = mma_status.position;
+ mutex_unlock(&mma8451_lock);
+ return sprintf(buf, "%d\n", position);
+}
+
+static ssize_t mma8451_position_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long position;
+ int ret;
+ ret = kstrtoul(buf, 10, &position);
+ if (ret) {
+ dev_err(dev, "string transform error\n");
+ return ret;
+ }
+
+ mutex_lock(&mma8451_lock);
+ mma_status.position = (int)position;
+ mutex_unlock(&mma8451_lock);
+ return count;
+}
+
+static ssize_t mma8451_scalemode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int mode = 0;
+ mutex_lock(&mma8451_lock);
+ mode = (int)mma_status.mode;
+ mutex_unlock(&mma8451_lock);
+
+ return sprintf(buf, "%d\n", mode);
+}
+
+static ssize_t mma8451_scalemode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long mode;
+ int ret, active_save;
+ struct i2c_client *client = mma8451_i2c_client;
+
+ ret = kstrtoul(buf, 10, &mode);
+ if (ret) {
+ dev_err(dev, "string transform error\n");
+ goto out;
+ }
+
+ if (mode > MODE_8G) {
+ dev_warn(dev, "not supported mode\n");
+ ret = count;
+ goto out;
+ }
+
+ mutex_lock(&mma8451_lock);
+ if (mode == mma_status.mode) {
+ ret = count;
+ goto out_unlock;
+ }
+
+ active_save = mma_status.active;
+ ret = mma8451_change_mode(client, mode);
+ if (ret)
+ goto out_unlock;
+
+ if (active_save == MMA_ACTIVED) {
+ ret = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1, 1);
+
+ if (ret)
+ goto out_unlock;
+ mma_status.active = active_save;
+ }
+
+out_unlock:
+ mutex_unlock(&mma8451_lock);
+out:
+ return ret;
+}
+
+static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO,
+ mma8451_enable_show, mma8451_enable_store);
+static DEVICE_ATTR(position, S_IWUSR | S_IRUGO,
+ mma8451_position_show, mma8451_position_store);
+static DEVICE_ATTR(scalemode, S_IWUSR | S_IRUGO,
+ mma8451_scalemode_show, mma8451_scalemode_store);
+
+static struct attribute *mma8451_attributes[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_position.attr,
+ &dev_attr_scalemode.attr,
+ NULL
+};
+
+static const struct attribute_group mma8451_attr_group = {
+ .attrs = mma8451_attributes,
+};
+
+static int mma8451_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int result, client_id;
+ struct input_dev *idev;
+ struct i2c_adapter *adapter;
+ u32 pos;
+ struct device_node *of_node = client->dev.of_node;
+ struct regulator *vdd, *vdd_io;
+
+ mma8451_i2c_client = client;
+
+ vdd = devm_regulator_get(&client->dev, "vdd");
+ if (!IS_ERR(vdd)) {
+ result = regulator_enable(vdd);
+ if (result) {
+ dev_err(&client->dev, "vdd set voltage error\n");
+ return result;
+ }
+ }
+
+ vdd_io = devm_regulator_get(&client->dev, "vddio");
+ if (!IS_ERR(vdd_io)) {
+ result = regulator_enable(vdd_io);
+ if (result) {
+ dev_err(&client->dev, "vddio set voltage error\n");
+ return result;
+ }
+ }
+
+ adapter = to_i2c_adapter(client->dev.parent);
+ result = i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA);
+ if (!result)
+ goto err_out;
+
+ client_id = i2c_smbus_read_byte_data(client, MMA8451_WHO_AM_I);
+ if (client_id != MMA8451_ID && client_id != MMA8452_ID
+ && client_id != MMA8453_ID) {
+ dev_err(&client->dev,
+ "read chip ID 0x%x is not equal to 0x%x or 0x%x!\n",
+ result, MMA8451_ID, MMA8452_ID);
+ result = -EINVAL;
+ goto err_out;
+ }
+
+ /* Initialize the MMA8451 chip */
+ result = mma8451_change_mode(client, senstive_mode);
+ if (result) {
+ dev_err(&client->dev,
+ "error when init mma8451 chip:(%d)\n", result);
+ goto err_out;
+ }
+
+ hwmon_dev = hwmon_device_register(&client->dev);
+ if (!hwmon_dev) {
+ result = -ENOMEM;
+ dev_err(&client->dev, "error when register hwmon device\n");
+ goto err_out;
+ }
+
+ mma8451_idev = input_allocate_polled_device();
+ if (!mma8451_idev) {
+ result = -ENOMEM;
+ dev_err(&client->dev, "alloc poll device failed!\n");
+ goto err_alloc_poll_device;
+ }
+ mma8451_idev->poll = mma8451_dev_poll;
+ mma8451_idev->poll_interval = POLL_INTERVAL;
+ mma8451_idev->poll_interval_min = POLL_INTERVAL_MIN;
+ mma8451_idev->poll_interval_max = POLL_INTERVAL_MAX;
+ idev = mma8451_idev->input;
+ idev->name = "mma845x";
+ idev->id.bustype = BUS_I2C;
+ idev->evbit[0] = BIT_MASK(EV_ABS);
+
+ input_set_abs_params(idev, ABS_X, -8192, 8191, INPUT_FUZZ, INPUT_FLAT);
+ input_set_abs_params(idev, ABS_Y, -8192, 8191, INPUT_FUZZ, INPUT_FLAT);
+ input_set_abs_params(idev, ABS_Z, -8192, 8191, INPUT_FUZZ, INPUT_FLAT);
+
+ result = input_register_polled_device(mma8451_idev);
+ if (result) {
+ dev_err(&client->dev, "register poll device failed!\n");
+ goto err_register_polled_device;
+ }
+ result = sysfs_create_group(&idev->dev.kobj, &mma8451_attr_group);
+ if (result) {
+ dev_err(&client->dev, "create device file failed!\n");
+ result = -EINVAL;
+ goto err_register_polled_device;
+ }
+
+ result = of_property_read_u32(of_node, "position", &pos);
+ if (result)
+ pos = DEFAULT_POSITION;
+ mma_status.position = (int)pos;
+
+ return 0;
+err_register_polled_device:
+ input_free_polled_device(mma8451_idev);
+err_alloc_poll_device:
+ hwmon_device_unregister(&client->dev);
+err_out:
+ return result;
+}
+
+static int mma8451_stop_chip(struct i2c_client *client)
+{
+ int ret = 0;
+ if (mma_status.active == MMA_ACTIVED) {
+ mma_status.ctl_reg1 = i2c_smbus_read_byte_data(client,
+ MMA8451_CTRL_REG1);
+ ret = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1,
+ mma_status.ctl_reg1 & 0xFE);
+ }
+ return ret;
+}
+
+static int mma8451_remove(struct i2c_client *client)
+{
+ int ret;
+ ret = mma8451_stop_chip(client);
+ hwmon_device_unregister(hwmon_dev);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mma8451_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return mma8451_stop_chip(client);
+}
+
+static int mma8451_resume(struct device *dev)
+{
+ int ret = 0;
+ struct i2c_client *client = to_i2c_client(dev);
+ if (mma_status.active == MMA_ACTIVED)
+ ret = i2c_smbus_write_byte_data(client, MMA8451_CTRL_REG1,
+ mma_status.ctl_reg1);
+ return ret;
+
+}
+#endif
+
+static const struct i2c_device_id mma8451_id[] = {
+ {"mma8451", 0},
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(i2c, mma8451_id);
+
+static SIMPLE_DEV_PM_OPS(mma8451_pm_ops, mma8451_suspend, mma8451_resume);
+static struct i2c_driver mma8451_driver = {
+ .driver = {
+ .name = "mma8451",
+ .owner = THIS_MODULE,
+ .pm = &mma8451_pm_ops,
+ },
+ .probe = mma8451_probe,
+ .remove = mma8451_remove,
+ .id_table = mma8451_id,
+};
+
+static int __init mma8451_init(void)
+{
+ /* register driver */
+ int res;
+
+ res = i2c_add_driver(&mma8451_driver);
+ if (res < 0) {
+ printk(KERN_INFO "add mma8451 i2c driver failed\n");
+ return -ENODEV;
+ }
+ return res;
+}
+
+static void __exit mma8451_exit(void)
+{
+ i2c_del_driver(&mma8451_driver);
+}
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MMA8451 3-Axis Orientation/Motion Detection Sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(mma8451_init);
+module_exit(mma8451_exit);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index d252276feadf..6f6315d7d10d 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -589,7 +589,7 @@ config I2C_IMG
config I2C_IMX
tristate "IMX I2C interface"
- depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE
+ depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE || ARCH_MXC_ARM64
help
Say Y here if you want to use the IIC bus controller on
the Freescale i.MX/MXC, Layerscape or ColdFire processors.
@@ -597,6 +597,16 @@ config I2C_IMX
This driver can also be built as a module. If so, the module
will be called i2c-imx.
+config I2C_IMX_LPI2C
+ tristate "IMX Low Power I2C interface"
+ depends on ARCH_MXC || COMPILE_TEST || ARCH_MXC_ARM64
+ help
+ Say Y here if you want to use the Low Power IIC bus controller
+ on the Freescale i.MX processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-imx-lpi2c.
+
config I2C_IOP3XX
tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 29764cc20a44..05195cdd4bea 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_I2C_HIX5HD2) += i2c-hix5hd2.o
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
obj-$(CONFIG_I2C_IMG) += i2c-img-scb.o
obj-$(CONFIG_I2C_IMX) += i2c-imx.o
+obj-$(CONFIG_I2C_IMX_LPI2C) += i2c-imx-lpi2c.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o
obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
new file mode 100644
index 000000000000..c2b08f9c7298
--- /dev/null
+++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
@@ -0,0 +1,740 @@
+/*
+ * This is i.MX low power i2c controller driver.
+ *
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#define DRIVER_NAME "imx-lpi2c"
+
+#define LPI2C_PARAM 0x04 /* i2c RX/TX FIFO size */
+#define LPI2C_MCR 0x10 /* i2c contrl register */
+#define LPI2C_MSR 0x14 /* i2c status register */
+#define LPI2C_MIER 0x18 /* i2c interrupt enable */
+#define LPI2C_MCFGR0 0x20 /* i2c master configuration */
+#define LPI2C_MCFGR1 0x24 /* i2c master configuration */
+#define LPI2C_MCFGR2 0x28 /* i2c master configuration */
+#define LPI2C_MCFGR3 0x2C /* i2c master configuration */
+#define LPI2C_MCCR0 0x48 /* i2c master clk configuration */
+#define LPI2C_MCCR1 0x50 /* i2c master clk configuration */
+#define LPI2C_MFCR 0x58 /* i2c master FIFO control */
+#define LPI2C_MFSR 0x5C /* i2c master FIFO status */
+#define LPI2C_MTDR 0x60 /* i2c master TX data register */
+#define LPI2C_MRDR 0x70 /* i2c master RX data register */
+
+/* i2c command */
+#define TRAN_DATA 0X00
+#define RECV_DATA 0X01
+#define GEN_STOP 0X02
+#define RECV_DISCARD 0X03
+#define GEN_START 0X04
+#define START_NACK 0X05
+#define START_HIGH 0X06
+#define START_HIGH_NACK 0X07
+
+#define MCR_MEN BIT(0)
+#define MCR_RST BIT(1)
+#define MCR_DOZEN BIT(2)
+#define MCR_DBGEN BIT(3)
+#define MCR_RTF BIT(8)
+#define MCR_RRF BIT(9)
+#define MSR_TDF BIT(0)
+#define MSR_RDF BIT(1)
+#define MSR_SDF BIT(9)
+#define MSR_NDF BIT(10)
+#define MSR_ALF BIT(11)
+#define MSR_MBF BIT(24)
+#define MSR_BBF BIT(25)
+#define MIER_TDIE BIT(0)
+#define MIER_RDIE BIT(1)
+#define MIER_SDIE BIT(9)
+#define MIER_NDIE BIT(10)
+#define MCFGR1_AUTOSTOP BIT(8)
+#define MCFGR1_IGNACK BIT(9)
+#define MRDR_RXEMPTY BIT(14)
+
+#define I2C_CLK_RATIO 2
+#define CHUNK_DATA 256
+
+#define LPI2C_RX_FIFOSIZE 4
+#define LPI2C_TX_FIFOSIZE 4
+
+#define LPI2C_DEFAULT_RATE 200000
+#define STARDARD_MAX_BITRATE 400000
+#define FAST_MAX_BITRATE 1000000
+#define FAST_PLUS_MAX_BITRATE 3400000
+#define HIGHSPEED_MAX_BITRATE 5000000
+
+#define I2C_PM_TIMEOUT 10 /* ms */
+
+enum lpi2c_imx_mode {
+ STANDARD, /* 100+Kbps */
+ FAST, /* 400+Kbps */
+ FAST_PLUS, /* 1.0+Mbps */
+ HS, /* 3.4+Mbps */
+ ULTRA_FAST, /* 5.0+Mbps */
+};
+
+enum lpi2c_imx_pincfg {
+ TWO_PIN_OD,
+ TWO_PIN_OO,
+ TWO_PIN_PP,
+ FOUR_PIN_PP,
+};
+
+struct lpi2c_imx_struct {
+ struct i2c_adapter adapter;
+ int irq;
+ struct clk *clk_per;
+ struct clk *clk_ipg;
+ void __iomem *base;
+ __u8 *rx_buf;
+ __u8 *tx_buf;
+ struct completion complete;
+ unsigned int msglen;
+ unsigned int delivered;
+ unsigned int block_data;
+ unsigned int bitrate;
+ enum lpi2c_imx_mode mode;
+};
+
+static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx,
+ unsigned int enable)
+{
+ writel(enable, lpi2c_imx->base + LPI2C_MIER);
+}
+
+static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned long orig_jiffies = jiffies;
+ unsigned int temp;
+
+ while (1) {
+ temp = readl(lpi2c_imx->base + LPI2C_MSR);
+
+ /* check for arbitration lost, clear if set */
+ if (temp & MSR_ALF) {
+ writel(temp, lpi2c_imx->base + LPI2C_MSR);
+ return -EAGAIN;
+ }
+
+ if (temp & (MSR_BBF | MSR_MBF))
+ break;
+
+ if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
+ dev_dbg(&lpi2c_imx->adapter.dev, "bus not work\n");
+ return -ETIMEDOUT;
+ }
+ schedule();
+ }
+
+ return 0;
+}
+
+static void lpi2c_imx_set_mode(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int bitrate = lpi2c_imx->bitrate;
+ enum lpi2c_imx_mode mode;
+
+ if (bitrate < STARDARD_MAX_BITRATE)
+ mode = STANDARD;
+ else if (bitrate < FAST_MAX_BITRATE)
+ mode = FAST;
+ else if (bitrate < FAST_PLUS_MAX_BITRATE)
+ mode = FAST_PLUS;
+ else if (bitrate < HIGHSPEED_MAX_BITRATE)
+ mode = HS;
+ else
+ mode = ULTRA_FAST;
+
+ lpi2c_imx->mode = mode;
+}
+
+static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx,
+ struct i2c_msg *msgs)
+{
+ unsigned int temp;
+ u8 read;
+
+ temp = readl(lpi2c_imx->base + LPI2C_MCR);
+ temp |= MCR_RRF | MCR_RTF;
+ writel(temp, lpi2c_imx->base + LPI2C_MCR);
+ writel(0x7f00, lpi2c_imx->base + LPI2C_MSR);
+
+ read = msgs->flags & I2C_M_RD;
+ temp = (msgs->addr << 1 | read) | (GEN_START << 8);
+ writel(temp, lpi2c_imx->base + LPI2C_MTDR);
+
+ return lpi2c_imx_bus_busy(lpi2c_imx);
+}
+
+static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned long orig_jiffies = jiffies;
+ unsigned int temp;
+
+ writel(GEN_STOP << 8, lpi2c_imx->base + LPI2C_MTDR);
+
+ do {
+ temp = readl(lpi2c_imx->base + LPI2C_MSR);
+ if (temp & MSR_SDF)
+ break;
+
+ if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
+ dev_dbg(&lpi2c_imx->adapter.dev, "stop timeout\n");
+ break;
+ }
+ schedule();
+
+ } while (1);
+}
+
+/* CLKLO = I2C_CLK_RATIO * CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI/2 */
+static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ u8 prescale, filt, sethold, clkhi, clklo, datavd;
+ unsigned int clk_rate, clk_cycle;
+ enum lpi2c_imx_pincfg pincfg;
+ unsigned int temp;
+
+ lpi2c_imx_set_mode(lpi2c_imx);
+
+ clk_rate = clk_get_rate(lpi2c_imx->clk_per);
+ if (!clk_rate) {
+ dev_dbg(&lpi2c_imx->adapter.dev, "clk_per rate is 0\n");
+ return -EINVAL;
+ }
+
+ if (lpi2c_imx->mode == HS || lpi2c_imx->mode == ULTRA_FAST)
+ filt = 0;
+ else
+ filt = 2;
+
+ for (prescale = 0; prescale <= 7; prescale++) {
+ clk_cycle = clk_rate / ((1 << prescale) * lpi2c_imx->bitrate)
+ - 3 - (filt >> 1);
+ clkhi = (clk_cycle + I2C_CLK_RATIO) / (I2C_CLK_RATIO + 1);
+ clklo = clk_cycle - clkhi;
+ if (clklo < 64)
+ break;
+ }
+
+ if (prescale > 7)
+ return -EINVAL;
+
+ /* set MCFGR1: PINCFG, PRESCALE, IGNACK */
+ if (lpi2c_imx->mode == ULTRA_FAST)
+ pincfg = TWO_PIN_OO;
+ else
+ pincfg = TWO_PIN_OD;
+ temp = prescale | pincfg << 24;
+
+ if (lpi2c_imx->mode == ULTRA_FAST)
+ temp |= MCFGR1_IGNACK;
+
+ writel(temp, lpi2c_imx->base + LPI2C_MCFGR1);
+
+ /* set MCFGR2: FILTSDA, FILTSCL */
+ temp = (filt << 16) | (filt << 24);
+ writel(temp, lpi2c_imx->base + LPI2C_MCFGR2);
+
+ /* set MCCR: DATAVD, SETHOLD, CLKHI, CLKLO */
+ sethold = clkhi;
+ datavd = clkhi >> 1;
+ temp = datavd << 24 | sethold << 16 | clkhi << 8 | clklo;
+
+ if (lpi2c_imx->mode == HS)
+ writel(temp, lpi2c_imx->base + LPI2C_MCCR1);
+ else
+ writel(temp, lpi2c_imx->base + LPI2C_MCCR0);
+
+ return 0;
+}
+
+static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int temp;
+ int ret;
+
+ ret = pm_runtime_get_sync(lpi2c_imx->adapter.dev.parent);
+ if (ret < 0)
+ return ret;
+
+ temp = MCR_RST;
+ writel(temp, lpi2c_imx->base + LPI2C_MCR);
+ writel(0, lpi2c_imx->base + LPI2C_MCR);
+
+ ret = lpi2c_imx_config(lpi2c_imx);
+ if (ret)
+ goto rpm_put;
+
+ temp = readl(lpi2c_imx->base + LPI2C_MCR);
+ temp |= MCR_MEN;
+ writel(temp, lpi2c_imx->base + LPI2C_MCR);
+
+ return 0;
+
+rpm_put:
+ pm_runtime_mark_last_busy(lpi2c_imx->adapter.dev.parent);
+ pm_runtime_put_autosuspend(lpi2c_imx->adapter.dev.parent);
+
+ return ret;
+}
+
+static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ u32 temp;
+
+ temp = readl(lpi2c_imx->base + LPI2C_MCR);
+ temp &= ~MCR_MEN;
+ writel(temp, lpi2c_imx->base + LPI2C_MCR);
+
+ pm_runtime_mark_last_busy(lpi2c_imx->adapter.dev.parent);
+ pm_runtime_put_autosuspend(lpi2c_imx->adapter.dev.parent);
+
+ return 0;
+}
+
+static int lpi2c_imx_msg_complete(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned long timeout;
+
+ timeout = wait_for_completion_timeout(&lpi2c_imx->complete, HZ);
+
+ return timeout ? 0 : -ETIMEDOUT;
+}
+
+static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned long orig_jiffies = jiffies;
+ u32 txcnt;
+
+ do {
+ txcnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff;
+
+ if (readl(lpi2c_imx->base + LPI2C_MSR) & MSR_NDF) {
+ dev_dbg(&lpi2c_imx->adapter.dev, "NDF detected\n");
+ return -EIO;
+ }
+
+ if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
+ dev_dbg(&lpi2c_imx->adapter.dev, "txfifo empty timeout\n");
+ return -ETIMEDOUT;
+ }
+ schedule();
+
+ } while (txcnt);
+
+ return 0;
+}
+
+static void lpi2c_imx_set_tx_watermark(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ writel(LPI2C_TX_FIFOSIZE >> 1, lpi2c_imx->base + LPI2C_MFCR);
+}
+
+static void lpi2c_imx_set_rx_watermark(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int temp, remaining;
+
+ remaining = lpi2c_imx->msglen - lpi2c_imx->delivered;
+
+ if (remaining > (LPI2C_RX_FIFOSIZE >> 1))
+ temp = LPI2C_RX_FIFOSIZE >> 1;
+ else
+ temp = 0;
+
+ writel(temp << 16, lpi2c_imx->base + LPI2C_MFCR);
+}
+
+static void lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int data, txcnt;
+
+ txcnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff;
+
+ while (txcnt < LPI2C_TX_FIFOSIZE) {
+ if (lpi2c_imx->delivered == lpi2c_imx->msglen)
+ break;
+
+ data = lpi2c_imx->tx_buf[lpi2c_imx->delivered++];
+ writel(data, lpi2c_imx->base + LPI2C_MTDR);
+ txcnt++;
+ }
+
+ if (lpi2c_imx->delivered < lpi2c_imx->msglen)
+ lpi2c_imx_intctrl(lpi2c_imx, MIER_TDIE | MIER_NDIE);
+ else
+ complete(&lpi2c_imx->complete);
+}
+
+static void lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx)
+{
+ unsigned int blocklen, remaining;
+ unsigned int temp, data;
+
+ do {
+ data = readl(lpi2c_imx->base + LPI2C_MRDR);
+ if (data & MRDR_RXEMPTY)
+ break;
+
+ lpi2c_imx->rx_buf[lpi2c_imx->delivered++] = data & 0xff;
+ } while (1);
+
+ /*
+ * First byte is the length of remaining packet in the SMBus block
+ * data read. Add it to msgs->len.
+ */
+ if (lpi2c_imx->block_data) {
+ blocklen = lpi2c_imx->rx_buf[0];
+ lpi2c_imx->msglen += blocklen;
+ }
+
+ remaining = lpi2c_imx->msglen - lpi2c_imx->delivered;
+
+ if (!remaining) {
+ complete(&lpi2c_imx->complete);
+ return;
+ }
+
+ /* not finished, still waiting for rx data */
+ lpi2c_imx_set_rx_watermark(lpi2c_imx);
+
+ /* multiple receive commands */
+ if (lpi2c_imx->block_data) {
+ lpi2c_imx->block_data = 0;
+ temp = remaining;
+ temp |= (RECV_DATA << 8);
+ writel(temp, lpi2c_imx->base + LPI2C_MTDR);
+ } else if (!(lpi2c_imx->delivered & 0xff)) {
+ temp = (remaining > CHUNK_DATA ? CHUNK_DATA : remaining) - 1;
+ temp |= (RECV_DATA << 8);
+ writel(temp, lpi2c_imx->base + LPI2C_MTDR);
+ }
+
+ lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE);
+}
+
+static void lpi2c_imx_write(struct lpi2c_imx_struct *lpi2c_imx,
+ struct i2c_msg *msgs)
+{
+ lpi2c_imx->tx_buf = msgs->buf;
+ lpi2c_imx_set_tx_watermark(lpi2c_imx);
+ lpi2c_imx_write_txfifo(lpi2c_imx);
+}
+
+static void lpi2c_imx_read(struct lpi2c_imx_struct *lpi2c_imx,
+ struct i2c_msg *msgs)
+{
+ unsigned int temp;
+
+ lpi2c_imx->rx_buf = msgs->buf;
+ lpi2c_imx->block_data = msgs->flags & I2C_M_RECV_LEN;
+
+ lpi2c_imx_set_rx_watermark(lpi2c_imx);
+ temp = msgs->len > CHUNK_DATA ? CHUNK_DATA - 1 : msgs->len - 1;
+ temp |= (RECV_DATA << 8);
+ writel(temp, lpi2c_imx->base + LPI2C_MTDR);
+
+ lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE | MIER_NDIE);
+}
+
+static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ struct lpi2c_imx_struct *lpi2c_imx = i2c_get_adapdata(adapter);
+ unsigned int temp;
+ int i, result;
+
+ result = lpi2c_imx_master_enable(lpi2c_imx);
+ if (result)
+ return result;
+
+ for (i = 0; i < num; i++) {
+ result = lpi2c_imx_start(lpi2c_imx, &msgs[i]);
+ if (result)
+ goto disable;
+
+ /* quick smbus */
+ if (num == 1 && msgs[0].len == 0)
+ goto stop;
+
+ lpi2c_imx->delivered = 0;
+ lpi2c_imx->msglen = msgs[i].len;
+ init_completion(&lpi2c_imx->complete);
+
+ if (msgs[i].flags & I2C_M_RD)
+ lpi2c_imx_read(lpi2c_imx, &msgs[i]);
+ else
+ lpi2c_imx_write(lpi2c_imx, &msgs[i]);
+
+ result = lpi2c_imx_msg_complete(lpi2c_imx);
+ if (result)
+ goto stop;
+
+ if (!(msgs[i].flags & I2C_M_RD)) {
+ result = lpi2c_imx_txfifo_empty(lpi2c_imx);
+ if (result)
+ goto stop;
+ }
+ }
+
+stop:
+ lpi2c_imx_stop(lpi2c_imx);
+
+ temp = readl(lpi2c_imx->base + LPI2C_MSR);
+ if ((temp & MSR_NDF) && !result)
+ result = -EIO;
+
+disable:
+ lpi2c_imx_master_disable(lpi2c_imx);
+
+ dev_dbg(&lpi2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
+ (result < 0) ? "error" : "success msg",
+ (result < 0) ? result : num);
+
+ return (result < 0) ? result : num;
+}
+
+static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id)
+{
+ struct lpi2c_imx_struct *lpi2c_imx = dev_id;
+ unsigned int temp;
+
+ lpi2c_imx_intctrl(lpi2c_imx, 0);
+ temp = readl(lpi2c_imx->base + LPI2C_MSR);
+
+ if (temp & MSR_NDF) {
+ complete(&lpi2c_imx->complete);
+ goto ret;
+ }
+
+ if (temp & MSR_RDF)
+ lpi2c_imx_read_rxfifo(lpi2c_imx);
+ else if (temp & MSR_TDF)
+ lpi2c_imx_write_txfifo(lpi2c_imx);
+
+ret:
+ return IRQ_HANDLED;
+}
+
+static u32 lpi2c_imx_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA;
+}
+
+static struct i2c_algorithm lpi2c_imx_algo = {
+ .master_xfer = lpi2c_imx_xfer,
+ .functionality = lpi2c_imx_func,
+};
+
+static const struct of_device_id lpi2c_imx_of_match[] = {
+ { .compatible = "fsl,imx7ulp-lpi2c" },
+ { .compatible = "fsl,imx8qm-lpi2c" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, lpi2c_imx_of_match);
+
+static int lpi2c_imx_probe(struct platform_device *pdev)
+{
+ struct lpi2c_imx_struct *lpi2c_imx;
+ struct resource *res;
+ int ret;
+
+ lpi2c_imx = devm_kzalloc(&pdev->dev, sizeof(*lpi2c_imx), GFP_KERNEL);
+ if (!lpi2c_imx)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ lpi2c_imx->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(lpi2c_imx->base))
+ return PTR_ERR(lpi2c_imx->base);
+
+ lpi2c_imx->irq = platform_get_irq(pdev, 0);
+ if (lpi2c_imx->irq < 0) {
+ dev_err(&pdev->dev, "can't get irq number\n");
+ return lpi2c_imx->irq;
+ }
+
+ lpi2c_imx->adapter.owner = THIS_MODULE;
+ lpi2c_imx->adapter.algo = &lpi2c_imx_algo;
+ lpi2c_imx->adapter.dev.parent = &pdev->dev;
+ lpi2c_imx->adapter.dev.of_node = pdev->dev.of_node;
+ strlcpy(lpi2c_imx->adapter.name, pdev->name,
+ sizeof(lpi2c_imx->adapter.name));
+
+ lpi2c_imx->clk_per = devm_clk_get(&pdev->dev, "per");
+ if (IS_ERR(lpi2c_imx->clk_per)) {
+ dev_err(&pdev->dev, "can't get I2C peripheral clock\n");
+ return PTR_ERR(lpi2c_imx->clk_per);
+ }
+
+ lpi2c_imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
+ if (IS_ERR(lpi2c_imx->clk_ipg)) {
+ dev_err(&pdev->dev, "can't get I2C ipg clock\n");
+ return PTR_ERR(lpi2c_imx->clk_ipg);
+ }
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "clock-frequency", &lpi2c_imx->bitrate);
+ if (ret)
+ lpi2c_imx->bitrate = LPI2C_DEFAULT_RATE;
+
+ i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx);
+ platform_set_drvdata(pdev, lpi2c_imx);
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ ret = i2c_add_adapter(&lpi2c_imx->adapter);
+ if (ret)
+ goto rpm_disable;
+
+ dev_info(&lpi2c_imx->adapter.dev, "LPI2C adapter registered\n");
+
+ return 0;
+
+rpm_disable:
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+
+ return ret;
+}
+
+static int lpi2c_imx_remove(struct platform_device *pdev)
+{
+ struct lpi2c_imx_struct *lpi2c_imx = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&lpi2c_imx->adapter);
+
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int lpi2c_runtime_suspend(struct device *dev)
+{
+ struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
+
+ devm_free_irq(dev, lpi2c_imx->irq, lpi2c_imx);
+ clk_disable_unprepare(lpi2c_imx->clk_ipg);
+ clk_disable_unprepare(lpi2c_imx->clk_per);
+ pinctrl_pm_select_idle_state(dev);
+
+ return 0;
+}
+
+static int lpi2c_runtime_resume(struct device *dev)
+{
+ struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
+ int ret;
+
+ pinctrl_pm_select_default_state(dev);
+ ret = clk_prepare_enable(lpi2c_imx->clk_per);
+ if (ret) {
+ dev_err(dev, "can't enable I2C per clock, ret=%d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(lpi2c_imx->clk_ipg);
+ if (ret) {
+ clk_disable_unprepare(lpi2c_imx->clk_per);
+ dev_err(dev, "can't enable I2C ipg clock, ret=%d\n", ret);
+ }
+
+ ret = devm_request_irq(dev, lpi2c_imx->irq, lpi2c_imx_isr,
+ IRQF_NO_SUSPEND,
+ dev_name(dev), lpi2c_imx);
+ if (ret) {
+ dev_err(dev, "can't claim irq %d\n", lpi2c_imx->irq);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int lpi2c_suspend_noirq(struct device *dev)
+{
+ int ret;
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ return ret;
+
+ pinctrl_pm_select_sleep_state(dev);
+ return 0;
+}
+
+static int lpi2c_resume_noirq(struct device *dev)
+{
+ return pm_runtime_force_resume(dev);
+}
+
+static const struct dev_pm_ops lpi2c_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(lpi2c_suspend_noirq,
+ lpi2c_resume_noirq)
+ SET_RUNTIME_PM_OPS(lpi2c_runtime_suspend,
+ lpi2c_runtime_resume, NULL)
+};
+#define IMX_LPI2C_PM (&lpi2c_pm_ops)
+#else
+#define IMX_LPI2C_PM NULL
+#endif
+
+static struct platform_driver lpi2c_imx_driver = {
+ .probe = lpi2c_imx_probe,
+ .remove = lpi2c_imx_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = lpi2c_imx_of_match,
+ .pm = IMX_LPI2C_PM,
+ },
+};
+
+static int __init lpi2c_imx_init(void)
+{
+ return platform_driver_register(&lpi2c_imx_driver);
+}
+subsys_initcall(lpi2c_imx_init);
+
+static void __exit lpi2c_imx_exit(void)
+{
+ platform_driver_unregister(&lpi2c_imx_driver);
+}
+module_exit(lpi2c_imx_exit);
+
+MODULE_AUTHOR("Gao Pan <pandy.gao@nxp.com>");
+MODULE_DESCRIPTION("I2C adapter driver for LPI2C bus");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index c4188308cefa..71c32f456a33 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -884,10 +884,17 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
unsigned int i, temp;
int result;
bool is_lastmsg = false;
+ bool enable_runtime_pm = false;
struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+
+ if (!pm_runtime_enabled(i2c_imx->adapter.dev.parent)) {
+ pm_runtime_enable(i2c_imx->adapter.dev.parent);
+ enable_runtime_pm = true;
+ }
+
result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
if (result < 0)
goto out;
@@ -959,6 +966,9 @@ fail0:
pm_runtime_put_autosuspend(i2c_imx->adapter.dev.parent);
out:
+ if (enable_runtime_pm)
+ pm_runtime_disable(i2c_imx->adapter.dev.parent);
+
dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
(result < 0) ? "error" : "success msg",
(result < 0) ? result : num);
@@ -1099,8 +1109,8 @@ static int i2c_imx_probe(struct platform_device *pdev)
}
/* Request IRQ */
- ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
- pdev->name, i2c_imx);
+ ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr,
+ IRQF_NO_SUSPEND, pdev->name, i2c_imx);
if (ret) {
dev_err(&pdev->dev, "can't claim irq %d\n", irq);
goto clk_disable;
@@ -1208,6 +1218,7 @@ static int i2c_imx_runtime_suspend(struct device *dev)
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
clk_disable_unprepare(i2c_imx->clk);
+ pinctrl_pm_select_sleep_state(dev);
return 0;
}
@@ -1217,6 +1228,7 @@ static int i2c_imx_runtime_resume(struct device *dev)
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
int ret;
+ pinctrl_pm_select_default_state(dev);
ret = clk_prepare_enable(i2c_imx->clk);
if (ret)
dev_err(dev, "can't enable I2C clock, ret=%d\n", ret);
@@ -1224,7 +1236,20 @@ static int i2c_imx_runtime_resume(struct device *dev)
return ret;
}
+static int i2c_imx_suspend(struct device *dev)
+{
+ pinctrl_pm_select_sleep_state(dev);
+ return 0;
+}
+
+static int i2c_imx_resume(struct device *dev)
+{
+ pinctrl_pm_select_default_state(dev);
+ return 0;
+}
+
static const struct dev_pm_ops i2c_imx_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend, i2c_imx_resume)
SET_RUNTIME_PM_OPS(i2c_imx_runtime_suspend,
i2c_imx_runtime_resume, NULL)
};
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 9c4ac26c014e..6b052391b0ab 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -57,6 +57,7 @@ enum pca_type {
pca_9546,
pca_9547,
pca_9548,
+ pca_9646,
};
struct chip_desc {
@@ -105,6 +106,10 @@ static const struct chip_desc chips[] = {
.nchans = 8,
.muxtype = pca954x_isswi,
},
+ [pca_9646] = {
+ .nchans = 4,
+ .muxtype = pca954x_isswi,
+ },
};
static const struct i2c_device_id pca954x_id[] = {
@@ -116,6 +121,7 @@ static const struct i2c_device_id pca954x_id[] = {
{ "pca9546", pca_9545 },
{ "pca9547", pca_9547 },
{ "pca9548", pca_9548 },
+ { "pca9646", pca_9646 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pca954x_id);
@@ -130,6 +136,7 @@ static const struct of_device_id pca954x_of_match[] = {
{ .compatible = "nxp,pca9546", .data = &chips[pca_9546] },
{ .compatible = "nxp,pca9547", .data = &chips[pca_9547] },
{ .compatible = "nxp,pca9548", .data = &chips[pca_9548] },
+ { .compatible = "nxp,pca9646", .data = &chips[pca_9646] },
{}
};
#endif
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c
index 05352f490d60..f90ea221f7f2 100644
--- a/drivers/ide/ide-atapi.c
+++ b/drivers/ide/ide-atapi.c
@@ -211,7 +211,7 @@ void ide_prep_sense(ide_drive_t *drive, struct request *rq)
sense_rq->cmd[0] = GPCMD_REQUEST_SENSE;
sense_rq->cmd[4] = cmd_len;
sense_rq->cmd_type = REQ_TYPE_ATA_SENSE;
- sense_rq->cmd_flags |= REQ_PREEMPT;
+ sense_rq->rq_flags |= RQF_PREEMPT;
if (drive->media == ide_tape)
sense_rq->cmd[13] = REQ_IDETAPE_PC1;
@@ -295,7 +295,7 @@ int ide_cd_expiry(ide_drive_t *drive)
wait = ATAPI_WAIT_PC;
break;
default:
- if (!(rq->cmd_flags & REQ_QUIET))
+ if (!(rq->rq_flags & RQF_QUIET))
printk(KERN_INFO PFX "cmd 0x%x timed out\n",
rq->cmd[0]);
wait = 0;
@@ -375,7 +375,7 @@ int ide_check_ireason(ide_drive_t *drive, struct request *rq, int len,
}
if (dev_is_idecd(drive) && rq->cmd_type == REQ_TYPE_ATA_PC)
- rq->cmd_flags |= REQ_FAILED;
+ rq->rq_flags |= RQF_FAILED;
return 1;
}
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 883fe2cdd42c..757f03a21375 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -98,7 +98,7 @@ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq)
struct request_sense *sense = &drive->sense_data;
int log = 0;
- if (!sense || !rq || (rq->cmd_flags & REQ_QUIET))
+ if (!sense || !rq || (rq->rq_flags & RQF_QUIET))
return 0;
ide_debug_log(IDE_DBG_SENSE, "sense_key: 0x%x", sense->sense_key);
@@ -291,7 +291,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
* (probably while trying to recover from a former error).
* Just give up.
*/
- rq->cmd_flags |= REQ_FAILED;
+ rq->rq_flags |= RQF_FAILED;
return 2;
}
@@ -311,7 +311,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
cdrom_saw_media_change(drive);
if (rq->cmd_type == REQ_TYPE_FS &&
- !(rq->cmd_flags & REQ_QUIET))
+ !(rq->rq_flags & RQF_QUIET))
printk(KERN_ERR PFX "%s: tray open\n",
drive->name);
}
@@ -346,7 +346,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
* No point in retrying after an illegal request or data
* protect error.
*/
- if (!(rq->cmd_flags & REQ_QUIET))
+ if (!(rq->rq_flags & RQF_QUIET))
ide_dump_status(drive, "command error", stat);
do_end_request = 1;
break;
@@ -355,14 +355,14 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
* No point in re-trying a zillion times on a bad sector.
* If we got here the error is not correctable.
*/
- if (!(rq->cmd_flags & REQ_QUIET))
+ if (!(rq->rq_flags & RQF_QUIET))
ide_dump_status(drive, "media error "
"(bad sector)", stat);
do_end_request = 1;
break;
case BLANK_CHECK:
/* disk appears blank? */
- if (!(rq->cmd_flags & REQ_QUIET))
+ if (!(rq->rq_flags & RQF_QUIET))
ide_dump_status(drive, "media error (blank)",
stat);
do_end_request = 1;
@@ -380,7 +380,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat)
}
if (rq->cmd_type != REQ_TYPE_FS) {
- rq->cmd_flags |= REQ_FAILED;
+ rq->rq_flags |= RQF_FAILED;
do_end_request = 1;
}
@@ -422,19 +422,19 @@ static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd)
int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
int write, void *buffer, unsigned *bufflen,
struct request_sense *sense, int timeout,
- unsigned int cmd_flags)
+ req_flags_t rq_flags)
{
struct cdrom_info *info = drive->driver_data;
struct request_sense local_sense;
int retries = 10;
- unsigned int flags = 0;
+ req_flags_t flags = 0;
if (!sense)
sense = &local_sense;
ide_debug_log(IDE_DBG_PC, "cmd[0]: 0x%x, write: 0x%x, timeout: %d, "
- "cmd_flags: 0x%x",
- cmd[0], write, timeout, cmd_flags);
+ "rq_flags: 0x%x",
+ cmd[0], write, timeout, rq_flags);
/* start of retry loop */
do {
@@ -446,7 +446,7 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
memcpy(rq->cmd, cmd, BLK_MAX_CDB);
rq->cmd_type = REQ_TYPE_ATA_PC;
rq->sense = sense;
- rq->cmd_flags |= cmd_flags;
+ rq->rq_flags |= rq_flags;
rq->timeout = timeout;
if (buffer) {
error = blk_rq_map_kern(drive->queue, rq, buffer,
@@ -462,14 +462,14 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
if (buffer)
*bufflen = rq->resid_len;
- flags = rq->cmd_flags;
+ flags = rq->rq_flags;
blk_put_request(rq);
/*
* FIXME: we should probably abort/retry or something in case of
* failure.
*/
- if (flags & REQ_FAILED) {
+ if (flags & RQF_FAILED) {
/*
* The request failed. Retry if it was due to a unit
* attention status (usually means media was changed).
@@ -494,10 +494,10 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd,
}
/* end of retry loop */
- } while ((flags & REQ_FAILED) && retries >= 0);
+ } while ((flags & RQF_FAILED) && retries >= 0);
/* return an error if the command failed */
- return (flags & REQ_FAILED) ? -EIO : 0;
+ return (flags & RQF_FAILED) ? -EIO : 0;
}
/*
@@ -589,7 +589,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
"(%u bytes)\n", drive->name, __func__,
cmd->nleft);
if (!write)
- rq->cmd_flags |= REQ_FAILED;
+ rq->rq_flags |= RQF_FAILED;
uptodate = 0;
}
} else if (rq->cmd_type != REQ_TYPE_BLOCK_PC) {
@@ -607,7 +607,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
}
if (!uptodate)
- rq->cmd_flags |= REQ_FAILED;
+ rq->rq_flags |= RQF_FAILED;
}
goto out_end;
}
@@ -745,9 +745,9 @@ static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
rq->cmd[0], rq->cmd_type);
if (rq->cmd_type == REQ_TYPE_BLOCK_PC)
- rq->cmd_flags |= REQ_QUIET;
+ rq->rq_flags |= RQF_QUIET;
else
- rq->cmd_flags &= ~REQ_FAILED;
+ rq->rq_flags &= ~RQF_FAILED;
drive->dma = 0;
@@ -867,7 +867,7 @@ int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
*/
cmd[7] = cdi->sanyo_slot % 3;
- return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, sense, 0, REQ_QUIET);
+ return ide_cd_queue_pc(drive, cmd, 0, NULL, NULL, sense, 0, RQF_QUIET);
}
static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
@@ -890,7 +890,7 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
cmd[0] = GPCMD_READ_CDVD_CAPACITY;
stat = ide_cd_queue_pc(drive, cmd, 0, &capbuf, &len, sense, 0,
- REQ_QUIET);
+ RQF_QUIET);
if (stat)
return stat;
@@ -943,7 +943,7 @@ static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
if (msf_flag)
cmd[1] = 2;
- return ide_cd_queue_pc(drive, cmd, 0, buf, &buflen, sense, 0, REQ_QUIET);
+ return ide_cd_queue_pc(drive, cmd, 0, buf, &buflen, sense, 0, RQF_QUIET);
}
/* Try to read the entire TOC for the disk into our internal buffer. */
diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h
index 1efc936f5b66..eea60c986c4f 100644
--- a/drivers/ide/ide-cd.h
+++ b/drivers/ide/ide-cd.h
@@ -101,7 +101,7 @@ void ide_cd_log_error(const char *, struct request *, struct request_sense *);
/* ide-cd.c functions used by ide-cd_ioctl.c */
int ide_cd_queue_pc(ide_drive_t *, const unsigned char *, int, void *,
- unsigned *, struct request_sense *, int, unsigned int);
+ unsigned *, struct request_sense *, int, req_flags_t);
int ide_cd_read_toc(ide_drive_t *, struct request_sense *);
int ide_cdrom_get_capabilities(ide_drive_t *, u8 *);
void ide_cdrom_update_speed(ide_drive_t *, u8 *);
diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c
index 5887a7a09e37..f085e3a2e1d6 100644
--- a/drivers/ide/ide-cd_ioctl.c
+++ b/drivers/ide/ide-cd_ioctl.c
@@ -305,7 +305,7 @@ int ide_cdrom_reset(struct cdrom_device_info *cdi)
rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM);
rq->cmd_type = REQ_TYPE_DRV_PRIV;
- rq->cmd_flags = REQ_QUIET;
+ rq->rq_flags = RQF_QUIET;
ret = blk_execute_rq(drive->queue, cd->disk, rq, 0);
blk_put_request(rq);
/*
@@ -449,7 +449,7 @@ int ide_cdrom_packet(struct cdrom_device_info *cdi,
struct packet_command *cgc)
{
ide_drive_t *drive = cdi->handle;
- unsigned int flags = 0;
+ req_flags_t flags = 0;
unsigned len = cgc->buflen;
if (cgc->timeout <= 0)
@@ -463,7 +463,7 @@ int ide_cdrom_packet(struct cdrom_device_info *cdi,
memset(cgc->sense, 0, sizeof(struct request_sense));
if (cgc->quiet)
- flags |= REQ_QUIET;
+ flags |= RQF_QUIET;
cgc->stat = ide_cd_queue_pc(drive, cgc->cmd,
cgc->data_direction == CGC_DATA_WRITE,
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 669ea1e45795..6360bbd37efe 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -307,7 +307,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
{
ide_startstop_t startstop;
- BUG_ON(!(rq->cmd_flags & REQ_STARTED));
+ BUG_ON(!(rq->rq_flags & RQF_STARTED));
#ifdef DEBUG
printk("%s: start_request: current=0x%08lx\n",
@@ -316,7 +316,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
/* bail early if we've exceeded max_failures */
if (drive->max_failures && (drive->failures > drive->max_failures)) {
- rq->cmd_flags |= REQ_FAILED;
+ rq->rq_flags |= RQF_FAILED;
goto kill_rq;
}
@@ -539,7 +539,7 @@ repeat:
*/
if ((drive->dev_flags & IDE_DFLAG_BLOCKED) &&
ata_pm_request(rq) == 0 &&
- (rq->cmd_flags & REQ_PREEMPT) == 0) {
+ (rq->rq_flags & RQF_PREEMPT) == 0) {
/* there should be no pending command at this point */
ide_unlock_port(hwif);
goto plug_device;
diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c
index e34af488693a..a015acdffb39 100644
--- a/drivers/ide/ide-pm.c
+++ b/drivers/ide/ide-pm.c
@@ -53,7 +53,7 @@ static int ide_pm_execute_rq(struct request *rq)
spin_lock_irq(q->queue_lock);
if (unlikely(blk_queue_dying(q))) {
- rq->cmd_flags |= REQ_QUIET;
+ rq->rq_flags |= RQF_QUIET;
rq->errors = -ENXIO;
__blk_end_request_all(rq, rq->errors);
spin_unlock_irq(q->queue_lock);
@@ -90,7 +90,7 @@ int generic_ide_resume(struct device *dev)
memset(&rqpm, 0, sizeof(rqpm));
rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM);
rq->cmd_type = REQ_TYPE_ATA_PM_RESUME;
- rq->cmd_flags |= REQ_PREEMPT;
+ rq->rq_flags |= RQF_PREEMPT;
rq->special = &rqpm;
rqpm.pm_step = IDE_PM_START_RESUME;
rqpm.pm_state = PM_EVENT_ON;
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 99c051490eff..7eb76cac46bc 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -245,6 +245,16 @@ config IMX7D_ADC
This driver can also be built as a module. If so, the module will be
called imx7d_adc.
+config IMX8QXP_ADC
+ tristate "IMX8QXP ADC driver"
+ depends on ARCH_MXC_ARM64 || COMPILE_TEST
+ depends on HAS_IOMEM
+ help
+ Say yes here to build support for IMX8QXP ADC.
+
+ This driver can also be built as a module. If so, the module will be
+ called imx8qxp_adc.
+
config LP8788_ADC
tristate "LP8788 ADC driver"
depends on MFD_LP8788
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 7a40c04c311f..02dfe936616b 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
obj-$(CONFIG_FSL_MX25_ADC) += fsl-imx25-gcq.o
obj-$(CONFIG_HI8435) += hi8435.o
obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
+obj-$(CONFIG_IMX8QXP_ADC) += imx8qxp_adc.o
obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
diff --git a/drivers/iio/adc/imx8qxp_adc.c b/drivers/iio/adc/imx8qxp_adc.c
new file mode 100644
index 000000000000..7408fce6cdd8
--- /dev/null
+++ b/drivers/iio/adc/imx8qxp_adc.c
@@ -0,0 +1,724 @@
+/*
+ * NXP i.MX8QXP ADC driver
+ *
+ * Copyright (C) 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/driver.h>
+#include <linux/iio/sysfs.h>
+
+/* ADC register */
+#define IMX8QXP_REG_ADC_VERID 0x00
+#define IMX8QXP_REG_ADC_PARAM 0x04
+#define IMX8QXP_REG_ADC_CTRL 0x10
+#define IMX8QXP_REG_ADC_STAT 0x14
+#define IMX8QXP_REG_ADC_IE 0x18
+#define IMX8QXP_REG_ADC_DE 0x1c
+#define IMX8QXP_REG_ADC_CFG 0x20
+#define IMX8QXP_REG_ADC_PAUSE 0x24
+#define IMX8QXP_REG_ADC_FCTRL 0x30
+#define IMX8QXP_REG_ADC_SWTRIG 0x34
+#define IMX8QXP_REG_ADC_TCTRL0 0xc0
+#define IMX8QXP_REG_ADC_TCTRL1 0xc4
+#define IMX8QXP_REG_ADC_TCTRL2 0xc8
+#define IMX8QXP_REG_ADC_TCTRL3 0xcc
+#define IMX8QXP_REG_ADC_TCTRL4 0xd0
+#define IMX8QXP_REG_ADC_TCTRL5 0xd4
+#define IMX8QXP_REG_ADC_TCTRL6 0xd8
+#define IMX8QXP_REG_ADC_TCTRL7 0xdc
+#define IMX8QXP_REG_ADC_CMDL1 0x100
+#define IMX8QXP_REG_ADC_CMDH1 0x104
+#define IMX8QXP_REG_ADC_CMDL2 0x108
+#define IMX8QXP_REG_ADC_CMDH2 0x10c
+#define IMX8QXP_REG_ADC_CMDL3 0x110
+#define IMX8QXP_REG_ADC_CMDH3 0x114
+#define IMX8QXP_REG_ADC_CMDL4 0x118
+#define IMX8QXP_REG_ADC_CMDH4 0x11c
+#define IMX8QXP_REG_ADC_CMDL5 0x120
+#define IMX8QXP_REG_ADC_CMDH5 0x124
+#define IMX8QXP_REG_ADC_CMDL6 0x128
+#define IMX8QXP_REG_ADC_CMDH6 0x12c
+#define IMX8QXP_REG_ADC_CMDL7 0x130
+#define IMX8QXP_REG_ADC_CMDH7 0x134
+#define IMX8QXP_REG_ADC_CMDL8 0x138
+#define IMX8QXP_REG_ADC_CMDH8 0x13c
+#define IMX8QXP_REG_ADC_CV1 0x200
+#define IMX8QXP_REG_ADC_CV2 0x204
+#define IMX8QXP_REG_ADC_CV3 0x208
+#define IMX8QXP_REG_ADC_CV4 0x20c
+#define IMX8QXP_REG_ADC_RESFIFO 0x300
+#define IMX8QXP_REG_ADC_TST 0xffc
+
+/* ADC IE bit shift */
+#define IMX8QXP_REG_ADC_IE_FOFIE_SHIFT (1)
+#define IMX8QXP_REG_ADC_IE_FWMIE_SHIFT (0)
+/* ADC CTRL bit shift*/
+#define IMX8QXP_REG_ADC_CTRL_FIFO_RESET_SHIFT (8)
+#define IMX8QXP_REG_ADC_CTRL_SOFTWARE_RESET_SHIFT (1)
+#define IMX8QXP_REG_ADC_CTRL_ADC_ENABLE (0)
+/* ADC TCTRL bit shift*/
+#define IMX8QXP_REG_ADC_TCTRL_TCMD_SHIFT (24)
+#define IMX8QXP_REG_ADC_TCTRL_TDLY_SHIFT (16)
+#define IMX8QXP_REG_ADC_TCTRL_TPRI_SHIFT (8)
+#define IMX8QXP_REG_ADC_TCTRL_HTEN_SHIFT (0)
+/* ADC CMDL bit shift*/
+#define IMX8QXP_REG_ADC_CMDL_CSCALE_SHIFT (8)
+#define IMX8QXP_REG_ADC_CMDL_MODE_SHIFT (7)
+#define IMX8QXP_REG_ADC_CMDL_DIFF_SHIFT (6)
+#define IMX8QXP_REG_ADC_CMDL_ABSEL_SHIFT (5)
+#define IMX8QXP_REG_ADC_CMDL_ADCH_SHIFT (0)
+/* ADC CMDH bit shift*/
+#define IMX8QXP_REG_ADC_CMDH_NEXT_SHIFT (24)
+#define IMX8QXP_REG_ADC_CMDH_LOOP_SHIFT (16)
+#define IMX8QXP_REG_ADC_CMDH_AVGS_SHIFT (12)
+#define IMX8QXP_REG_ADC_CMDH_STS_SHIFT (8)
+#define IMX8QXP_REG_ADC_CMDH_LWI_SHIFT (7)
+#define IMX8QXP_REG_ADC_CMDH_CMPEN_SHIFT (0)
+/* ADC CFG bit shift*/
+#define IMX8QXP_REG_ADC_CFG_PWREN_SHIFT (28)
+#define IMX8QXP_REG_ADC_CFG_PUDLY_SHIFT (16)
+#define IMX8QXP_REG_ADC_CFG_REFSEL_SHIFT (6)
+#define IMX8QXP_REG_ADC_CFG_PWRSEL_SHIFT (4)
+#define IMX8QXP_REG_ADC_CFG_TPRICTRL_SHIFT (0)
+/* ADC FCTRL bit shift*/
+#define IMX8QXP_ADC_FCTRL_FWMARK_SHIFT (16)
+#define IMX8QXP_ADC_FCTRL_FWMARK_MASK (0x1f << 16)
+#define IMX8QXP_ADC_FCTRL_FCOUNT_MASK (0x1f)
+/* ADC STAT bit shift*/
+#define IMX8QXP_REG_ADC_STAT_CMDACT_SHIFT (24)
+#define IMX8QXP_REG_ADC_STAT_TRGACT_SHIFT (16)
+#define IMX8QXP_REG_ADC_STAT_FOF_SHIFT (1)
+#define IMX8QXP_REG_ADC_STAT_RDY_SHIFT (0)
+
+/* ADC CMD PARAMETER*/
+#define IMX8QXP_REG_ADC_CMDL_CNANNEL_SCALE_DOWN (0)
+#define IMX8QXP_REG_ADC_CMDL_CHANNEL_SCALE_FULL (0x3f)
+#define IMX8QXP_REG_ADC_CMDL_SEL_A_A_B_CHANNEL (0)
+#define IMX8QXP_REG_ADC_CMDL_SEL_B_B_A_CHANNEL (1)
+#define IMX8QXP_REG_ADC_CMDL_STANDARD_RESOLUTION (0)
+#define IMX8QXP_REG_ADC_CMDL_HIGH_RESOLUTION (1)
+#define IMX8QXP_REG_ADC_CMDL_MODE_SINGLE (0)
+#define IMX8QXP_REG_ADC_CMDL_MODE_DIFF (1)
+
+#define IMX8QXP_REG_ADC_CMDH_LWI_INCREMENT_ENABLE (1)
+#define IMX8QXP_REG_ADC_CMDH_LWI_INCREMENT_DISABLE (0)
+#define IMX8QXP_REG_ADC_CMDH_CMPEN_DISABLE (0)
+#define IMX8QXP_REG_ADC_CMDH_CMPEN_ENABLE_TRUE (2)
+#define IMX8QXP_REG_ADC_CMDH_CMPEN_ENABLE_UNTILE_TRUE (0x3)
+
+/* ADC PAUSE PARAMETER*/
+#define IMX8QXP_REG_ADC_PAUSE_ENABLE (0x80000000)
+/* ADC TRIGGER PARAMETER*/
+#define IMX8QXP_REG_ADC_TCTRL_TPRI_PRIORITY_HIGH (0)
+#define IMX8QXP_REG_ADC_TCTRL_TPRI_PRIORITY_LOW (1)
+
+#define IMX8QXP_REG_ADC_TCTRL_HTEN_HARDWARE_TIRGGER_DISABLE (0)
+#define IMX8QXP_REG_ADC_TCTRC_HTEN_HARDWARE_TIRGGER_ENABLE (1)
+
+#define MAX_CMD (8)
+#define MAX_TRIG (8)
+
+#define IMX8QXP_ADC_TIMEOUT msecs_to_jiffies(100)
+
+struct imx8qxp_adc_trigger_ctrl {
+ u32 tcmd;
+ u32 tdly;
+ u32 tpri;
+ u32 hten;
+};
+
+struct imx8qxp_adc_cmd_l {
+ u32 scale;
+ u32 mode;
+ u32 diff;
+ u32 absel;
+ u32 adch;
+};
+
+struct imx8qxp_adc_cmd_h {
+ u32 next;
+ u32 loop;
+ u32 avgs;
+ u32 sts;
+ u32 lwi;
+ u32 cmpen;
+};
+
+struct imx8qxp_adc_cfg {
+ u32 pwren;
+ u32 pudly;
+ u32 refsel;
+ u32 pwrsel;
+ u32 tprictrl;
+};
+
+struct imx8qxp_adc {
+ struct device *dev;
+ void __iomem *regs;
+ struct clk *clk;
+ struct clk *ipg_clk;
+
+ u32 vref_uv;
+ u32 value;
+ u32 channel_id;
+ u32 trigger_id;
+ u32 cmd_id;
+
+ struct regulator *vref;
+ struct imx8qxp_adc_cmd_l adc_cmd_l[MAX_CMD + 1];
+ struct imx8qxp_adc_cmd_h adc_cmd_h[MAX_CMD + 1];
+ struct imx8qxp_adc_trigger_ctrl adc_trigger_ctrl[MAX_TRIG + 1];
+ struct imx8qxp_adc_cfg adc_cfg;
+ struct completion completion;
+};
+
+#define IMX8QXP_ADC_CHAN(_idx) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (_idx), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+}
+
+static const struct iio_chan_spec imx8qxp_adc_iio_channels[] = {
+ IMX8QXP_ADC_CHAN(0),
+ IMX8QXP_ADC_CHAN(1),
+ IMX8QXP_ADC_CHAN(2),
+ IMX8QXP_ADC_CHAN(3),
+ IMX8QXP_ADC_CHAN(4),
+ IMX8QXP_ADC_CHAN(5),
+ IMX8QXP_ADC_CHAN(6),
+ IMX8QXP_ADC_CHAN(7),
+};
+
+static void imx8qxp_adc_feature_prepare(struct imx8qxp_adc *adc)
+{
+ u32 i;
+
+ adc->trigger_id = 0;
+ adc->cmd_id = 0;
+ adc->channel_id = 0;
+
+ for (i = 0; i < MAX_CMD + 1; i++) {
+ adc->adc_cmd_l[i].scale = 1;
+ adc->adc_cmd_l[i].mode = 0;
+ adc->adc_cmd_l[i].diff = 0;
+ adc->adc_cmd_l[i].absel = 0;
+ adc->adc_cmd_l[i].adch = 0;
+ adc->adc_cmd_h[i].next = 0;
+ adc->adc_cmd_h[i].loop = 0;
+ adc->adc_cmd_h[i].avgs = 0;
+ adc->adc_cmd_h[i].sts = 0;
+ adc->adc_cmd_h[i].lwi = 0;
+ adc->adc_cmd_h[i].cmpen = 0;
+ }
+
+ for (i = 0; i < MAX_TRIG; i++) {
+ adc->adc_trigger_ctrl[i].tcmd = 0;
+ adc->adc_trigger_ctrl[i].tdly = 0;
+ adc->adc_trigger_ctrl[i].tpri = 0;
+ adc->adc_trigger_ctrl[i].hten = 0;
+ }
+
+ adc->adc_cfg.pwren = 0;
+ adc->adc_cfg.pudly = 0;
+ adc->adc_cfg.refsel = 0;
+ adc->adc_cfg.pwrsel = 0;
+ adc->adc_cfg.tprictrl = 0;
+}
+
+static void imx8qxp_adc_reset(struct imx8qxp_adc *adc)
+{
+ u32 ctrl;
+
+ /*software reset, need to clear the set bit*/
+ ctrl = readl(adc->regs + IMX8QXP_REG_ADC_CTRL);
+ ctrl |= 1 << IMX8QXP_REG_ADC_CTRL_SOFTWARE_RESET_SHIFT;
+ writel(ctrl, adc->regs + IMX8QXP_REG_ADC_CTRL);
+ udelay(10);
+ ctrl &= ~(1 << IMX8QXP_REG_ADC_CTRL_SOFTWARE_RESET_SHIFT);
+ writel(ctrl, adc->regs + IMX8QXP_REG_ADC_CTRL);
+
+ /* reset the fifo */
+ ctrl |= 1 << IMX8QXP_REG_ADC_CTRL_FIFO_RESET_SHIFT;
+ writel(ctrl, adc->regs + IMX8QXP_REG_ADC_CTRL);
+}
+
+static void imx8qxp_adc_reg_config(struct imx8qxp_adc *adc)
+{
+ u32 adc_cfg, adc_tctrl, adc_cmdl, adc_cmdh;
+ u32 t_id, c_id;
+
+ adc_cfg = adc->adc_cfg.pwren << IMX8QXP_REG_ADC_CFG_PWREN_SHIFT
+ | adc->adc_cfg.pudly << IMX8QXP_REG_ADC_CFG_PUDLY_SHIFT
+ | adc->adc_cfg.refsel << IMX8QXP_REG_ADC_CFG_REFSEL_SHIFT
+ | adc->adc_cfg.pwrsel << IMX8QXP_REG_ADC_CFG_PWRSEL_SHIFT
+ | adc->adc_cfg.tprictrl << IMX8QXP_REG_ADC_CFG_TPRICTRL_SHIFT;
+ writel(adc_cfg, adc->regs + IMX8QXP_REG_ADC_CFG);
+
+ t_id = adc->trigger_id;
+ adc_tctrl = adc->adc_trigger_ctrl[t_id].tcmd << IMX8QXP_REG_ADC_TCTRL_TCMD_SHIFT
+ | adc->adc_trigger_ctrl[t_id].tdly << IMX8QXP_REG_ADC_TCTRL_TDLY_SHIFT
+ | adc->adc_trigger_ctrl[t_id].tpri << IMX8QXP_REG_ADC_TCTRL_TPRI_SHIFT
+ | adc->adc_trigger_ctrl[t_id].hten << IMX8QXP_REG_ADC_TCTRL_HTEN_SHIFT;
+ writel(adc_tctrl, adc->regs + IMX8QXP_REG_ADC_TCTRL0 + t_id * 4);
+
+ c_id = adc->cmd_id - 1;
+ adc_cmdl = adc->adc_cmd_l[c_id].scale << IMX8QXP_REG_ADC_CMDL_CSCALE_SHIFT
+ | adc->adc_cmd_l[c_id].mode << IMX8QXP_REG_ADC_CMDL_MODE_SHIFT
+ | adc->adc_cmd_l[c_id].diff << IMX8QXP_REG_ADC_CMDL_DIFF_SHIFT
+ | adc->adc_cmd_l[c_id].absel << IMX8QXP_REG_ADC_CMDL_ABSEL_SHIFT
+ | adc->adc_cmd_l[c_id].adch << IMX8QXP_REG_ADC_CMDL_ADCH_SHIFT;
+ writel(adc_cmdl, adc->regs + IMX8QXP_REG_ADC_CMDL1 + c_id * 8);
+
+ adc_cmdh = adc->adc_cmd_h[c_id].next << IMX8QXP_REG_ADC_CMDH_NEXT_SHIFT
+ | adc->adc_cmd_h[c_id].loop << IMX8QXP_REG_ADC_CMDH_LOOP_SHIFT
+ | adc->adc_cmd_h[c_id].avgs << IMX8QXP_REG_ADC_CMDH_AVGS_SHIFT
+ | adc->adc_cmd_h[c_id].sts << IMX8QXP_REG_ADC_CMDH_STS_SHIFT
+ | adc->adc_cmd_h[c_id].lwi << IMX8QXP_REG_ADC_CMDH_LWI_SHIFT
+ | adc->adc_cmd_h[c_id].cmpen << IMX8QXP_REG_ADC_CMDH_CMPEN_SHIFT;
+ writel(adc_cmdh, adc->regs + IMX8QXP_REG_ADC_CMDH1 + c_id * 8);
+}
+
+static void imx8qxp_adc_mode_config(struct imx8qxp_adc *adc)
+{
+ u32 cmd_id, trigger_id, channel_id;
+
+ channel_id = adc->channel_id;
+ cmd_id = adc->cmd_id - 1;
+ trigger_id = adc->trigger_id;
+
+ /* config the cmd */
+ adc->adc_cmd_l[cmd_id].scale = IMX8QXP_REG_ADC_CMDL_CHANNEL_SCALE_FULL;
+ adc->adc_cmd_l[cmd_id].mode = IMX8QXP_REG_ADC_CMDL_STANDARD_RESOLUTION;
+ adc->adc_cmd_l[cmd_id].diff = IMX8QXP_REG_ADC_CMDL_MODE_SINGLE;
+ adc->adc_cmd_l[cmd_id].absel = IMX8QXP_REG_ADC_CMDL_SEL_A_A_B_CHANNEL;
+ adc->adc_cmd_l[cmd_id].adch = channel_id;
+
+ adc->adc_cmd_h[cmd_id].next = 0;
+ adc->adc_cmd_h[cmd_id].loop = 0;
+ adc->adc_cmd_h[cmd_id].avgs = 7; // 128 times conversion
+ adc->adc_cmd_h[cmd_id].sts = 0;
+ adc->adc_cmd_h[cmd_id].lwi = IMX8QXP_REG_ADC_CMDH_LWI_INCREMENT_DISABLE;
+ adc->adc_cmd_h[cmd_id].cmpen = IMX8QXP_REG_ADC_CMDH_CMPEN_DISABLE;
+
+ /* config the trigger control */
+ adc->adc_trigger_ctrl[trigger_id].tcmd = adc->cmd_id; //point to cmd1
+ adc->adc_trigger_ctrl[trigger_id].tdly = 0;
+ adc->adc_trigger_ctrl[trigger_id].tpri = IMX8QXP_REG_ADC_TCTRL_TPRI_PRIORITY_HIGH;
+ adc->adc_trigger_ctrl[trigger_id].hten = IMX8QXP_REG_ADC_TCTRL_HTEN_HARDWARE_TIRGGER_DISABLE;
+
+ /* ADC configuration */
+ adc->adc_cfg.pwren = 1;
+ adc->adc_cfg.pudly = 0x80;
+ adc->adc_cfg.refsel = 0;
+ adc->adc_cfg.pwrsel = 3;
+ adc->adc_cfg.tprictrl = 0;
+
+ imx8qxp_adc_reg_config(adc);
+}
+
+static void imx8qxp_adc_fifo_config(struct imx8qxp_adc *adc)
+{
+ u32 fifo_ctrl, interrupt_en;
+
+ fifo_ctrl = readl(adc->regs + IMX8QXP_REG_ADC_FCTRL);
+ fifo_ctrl &= ~IMX8QXP_ADC_FCTRL_FWMARK_MASK;
+ /* set the watermark level to 1 */
+ fifo_ctrl |= 0 << IMX8QXP_ADC_FCTRL_FWMARK_SHIFT;
+ writel(fifo_ctrl, adc->regs + IMX8QXP_REG_ADC_FCTRL);
+
+ /* FIFO Watermark Interrupt Enable */
+ interrupt_en = readl(adc->regs + IMX8QXP_REG_ADC_IE);
+ interrupt_en |= 1 << IMX8QXP_REG_ADC_IE_FWMIE_SHIFT;
+ writel(interrupt_en, adc->regs + IMX8QXP_REG_ADC_IE);
+}
+
+static void imx8qxp_adc_disable(struct imx8qxp_adc *adc)
+{
+ u32 ctrl;
+
+ ctrl = readl(adc->regs + IMX8QXP_REG_ADC_CTRL);
+ ctrl &= ~(1 << IMX8QXP_REG_ADC_CTRL_ADC_ENABLE);
+ writel(ctrl, adc->regs + IMX8QXP_REG_ADC_CTRL);
+}
+
+static void imx8qxp_adc_enable(struct imx8qxp_adc *adc)
+{
+ u32 ctrl;
+
+ ctrl = readl(adc->regs + IMX8QXP_REG_ADC_CTRL);
+ ctrl |= 1 << IMX8QXP_REG_ADC_CTRL_ADC_ENABLE;
+ writel(ctrl, adc->regs + IMX8QXP_REG_ADC_CTRL);
+
+}
+
+static void imx8qxp_adc_start_trigger(struct imx8qxp_adc *adc)
+{
+ writel(1 << adc->trigger_id, adc->regs + IMX8QXP_REG_ADC_SWTRIG);
+}
+
+static u32 imx8qxp_adc_get_sample_rate(struct imx8qxp_adc *adc)
+{
+
+ u32 input_clk;
+
+ input_clk = clk_get_rate(adc->clk);
+
+ return input_clk / 3;
+}
+
+static int imx8qxp_adc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+
+ struct imx8qxp_adc *adc = iio_priv(indio_dev);
+
+ u32 channel;
+ long ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ pm_runtime_get_sync(adc->dev);
+
+ mutex_lock(&indio_dev->mlock);
+ reinit_completion(&adc->completion);
+
+ channel = chan->channel & 0x07;
+ adc->channel_id = channel;
+ adc->cmd_id = 1;
+ adc->trigger_id = 0;
+ imx8qxp_adc_mode_config(adc);
+
+ imx8qxp_adc_fifo_config(adc);
+
+ imx8qxp_adc_enable(adc);
+
+ imx8qxp_adc_start_trigger(adc);
+
+ ret = wait_for_completion_interruptible_timeout
+ (&adc->completion, IMX8QXP_ADC_TIMEOUT);
+
+ pm_runtime_mark_last_busy(adc->dev);
+ pm_runtime_put_sync_autosuspend(adc->dev);
+
+ if (ret == 0) {
+ mutex_unlock(&indio_dev->mlock);
+ return -ETIMEDOUT;
+ }
+ if (ret < 0) {
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+ }
+
+ *val = adc->value;
+ mutex_unlock(&indio_dev->mlock);
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ adc->vref_uv = regulator_get_voltage(adc->vref);
+ *val = adc->vref_uv / 1000;
+ *val2 = 12;
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = imx8qxp_adc_get_sample_rate(adc);
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int imx8qxp_adc_read_data(struct imx8qxp_adc *adc)
+{
+ u32 value;
+
+ value = readl(adc->regs + IMX8QXP_REG_ADC_RESFIFO);
+ value &= 0xffff;
+ return (value >> 3);
+}
+
+static irqreturn_t imx8qxp_adc_isr(int irq, void *dev_id)
+{
+ struct imx8qxp_adc *adc = (struct imx8qxp_adc *)dev_id;
+
+ u32 fifo_count;
+
+ fifo_count = readl(adc->regs + IMX8QXP_REG_ADC_FCTRL)
+ & IMX8QXP_ADC_FCTRL_FCOUNT_MASK;
+
+ if (fifo_count) {
+ adc->value = imx8qxp_adc_read_data(adc);
+ complete(&adc->completion);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int imx8qxp_adc_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg, unsigned int writeval,
+ unsigned int *readval)
+{
+ struct imx8qxp_adc *adc = iio_priv(indio_dev);
+
+ if (!readval || reg % 4 || reg > IMX8QXP_REG_ADC_TST)
+ return -EINVAL;
+
+ pm_runtime_get_sync(adc->dev);
+
+ *readval = readl(adc->regs + reg);
+
+ pm_runtime_mark_last_busy(adc->dev);
+ pm_runtime_put_sync_autosuspend(adc->dev);
+
+ return 0;
+}
+
+static const struct iio_info imx8qxp_adc_iio_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &imx8qxp_adc_read_raw,
+ .debugfs_reg_access = &imx8qxp_adc_reg_access,
+};
+
+static const struct of_device_id imx8qxp_adc_match[] = {
+ { .compatible = "fsl,imx8qxp-adc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx8qxp_adc_match);
+
+static int imx8qxp_adc_probe(struct platform_device *pdev)
+{
+ struct imx8qxp_adc *adc;
+ struct iio_dev *indio_dev;
+ struct resource *mem;
+ int irq;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
+ if (!indio_dev) {
+ dev_err(&pdev->dev, "Failed allocating iio device\n");
+ return -ENOMEM;
+ }
+
+ adc = iio_priv(indio_dev);
+ adc->dev = &pdev->dev;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ adc->regs = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(adc->regs)) {
+ ret = PTR_ERR(adc->regs);
+ dev_err(&pdev->dev,
+ "Failed to remap adc memory, err = %d\n", ret);
+ return ret;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "No irq resource?\n");
+ return irq;
+ }
+
+ adc->clk = devm_clk_get(&pdev->dev, "per");
+ if (IS_ERR(adc->clk)) {
+ ret = PTR_ERR(adc->clk);
+ dev_err(&pdev->dev, "Failed getting clock, err = %d\n", ret);
+ return ret;
+ }
+
+ adc->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
+ if (IS_ERR(adc->ipg_clk)) {
+ ret = PTR_ERR(adc->ipg_clk);
+ dev_err(&pdev->dev, "Failed getting clock, err = %d\n", ret);
+ return ret;
+ }
+
+ adc->vref = devm_regulator_get(&pdev->dev, "vref");
+ if (IS_ERR(adc->vref)) {
+ ret = PTR_ERR(adc->vref);
+ dev_err(&pdev->dev,
+ "Failed getting reference voltage, err = %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_enable(adc->vref);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Can't enable adc reference top voltage, err = %d\n",
+ ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ init_completion(&adc->completion);
+
+ indio_dev->name = dev_name(&pdev->dev);
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->info = &imx8qxp_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = imx8qxp_adc_iio_channels;
+ indio_dev->num_channels = ARRAY_SIZE(imx8qxp_adc_iio_channels);
+
+ ret = clk_prepare_enable(adc->clk);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Could not prepare or enable the clock.\n");
+ goto error_adc_clk_enable;
+ }
+
+ ret = clk_prepare_enable(adc->ipg_clk);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Could not prepare or enable the clock.\n");
+ goto error_adc_ipg_clk_enable;
+ }
+
+ ret = devm_request_irq(adc->dev, irq,
+ imx8qxp_adc_isr, 0,
+ dev_name(&pdev->dev), adc);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed requesting irq, irq = %d\n", irq);
+ goto error_iio_device_register;
+ }
+
+ imx8qxp_adc_feature_prepare(adc);
+ imx8qxp_adc_reset(adc);
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ imx8qxp_adc_disable(adc);
+ dev_err(&pdev->dev, "Couldn't register the device.\n");
+ goto error_iio_device_register;
+ }
+
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+
+error_iio_device_register:
+ clk_disable_unprepare(adc->ipg_clk);
+error_adc_ipg_clk_enable:
+ clk_disable_unprepare(adc->clk);
+error_adc_clk_enable:
+ regulator_disable(adc->vref);
+
+ return ret;
+}
+
+static int imx8qxp_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct imx8qxp_adc *adc = iio_priv(indio_dev);
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ iio_device_unregister(indio_dev);
+
+ imx8qxp_adc_disable(adc);
+
+ clk_disable_unprepare(adc->clk);
+ clk_disable_unprepare(adc->ipg_clk);
+ regulator_disable(adc->vref);
+
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+
+
+ return 0;
+}
+
+static int imx8qxp_adc_runtime_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct imx8qxp_adc *adc = iio_priv(indio_dev);
+
+ imx8qxp_adc_disable(adc);
+
+ clk_disable_unprepare(adc->clk);
+ clk_disable_unprepare(adc->ipg_clk);
+ regulator_disable(adc->vref);
+
+ return 0;
+}
+
+static int imx8qxp_adc_runtime_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct imx8qxp_adc *adc = iio_priv(indio_dev);
+ int ret;
+
+ ret = regulator_enable(adc->vref);
+ if (ret) {
+ dev_err(adc->dev,
+ "Can't enable adc reference top voltage, err = %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(adc->clk);
+ if (ret) {
+ dev_err(adc->dev,
+ "Could not prepare or enable clock.\n");
+ regulator_disable(adc->vref);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(adc->ipg_clk);
+ if (ret) {
+ dev_err(adc->dev,
+ "Could not prepare or enable clock.\n");
+ clk_disable_unprepare(adc->clk);
+ regulator_disable(adc->vref);
+ return ret;
+ }
+ imx8qxp_adc_reset(adc);
+
+ return 0;
+}
+
+static const struct dev_pm_ops imx8qxp_adc_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(imx8qxp_adc_runtime_suspend, imx8qxp_adc_runtime_resume, NULL)
+};
+
+static struct platform_driver imx8qxp_adc_driver = {
+ .probe = imx8qxp_adc_probe,
+ .remove = imx8qxp_adc_remove,
+ .driver = {
+ .name = "imx8qxp_adc",
+ .of_match_table = imx8qxp_adc_match,
+ .pm = &imx8qxp_adc_pm_ops,
+ },
+};
+
+module_platform_driver(imx8qxp_adc_driver);
+
+MODULE_AUTHOR("Haibo Chen <haibo.chen@nxp.com>");
+MODULE_DESCRIPTION("NXP IMX8QXP ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index d1bde6d2721e..12d3e352a867 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -1,7 +1,7 @@
/*
* Freescale Vybrid vf610 ADC driver
*
- * Copyright 2013 Freescale Semiconductor, Inc.
+ * Copyright 2013-2015 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -819,6 +819,7 @@ static int vf610_adc_probe(struct platform_device *pdev)
struct resource *mem;
int irq;
int ret;
+ u32 channels;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct vf610_adc));
if (!indio_dev) {
@@ -877,13 +878,18 @@ static int vf610_adc_probe(struct platform_device *pdev)
init_completion(&info->completion);
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "num-channels", &channels);
+ if (ret)
+ channels = ARRAY_SIZE(vf610_adc_iio_channels);
+
indio_dev->name = dev_name(&pdev->dev);
indio_dev->dev.parent = &pdev->dev;
indio_dev->dev.of_node = pdev->dev.of_node;
indio_dev->info = &vf610_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = vf610_adc_iio_channels;
- indio_dev->num_channels = ARRAY_SIZE(vf610_adc_iio_channels);
+ indio_dev->num_channels = (int)channels;
ret = clk_prepare_enable(info->clk);
if (ret) {
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index cbd75cf44739..ec9c93fc9d7e 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -416,9 +416,18 @@ config KEYBOARD_MPR121
To compile this driver as a module, choose M here: the
module will be called mpr121_touchkey.
+config KEYBOARD_RPMSG
+ tristate "i.MX Rpmsg Keys Driver"
+ depends on (SOC_IMX7ULP)
+ depends on RPMSG
+ depends on OF
+ help
+ This is rpmsg keys driver on i.mx7ulp, because some keys located
+ in M4 side.
+
config KEYBOARD_SNVS_PWRKEY
tristate "IMX SNVS Power Key Driver"
- depends on SOC_IMX6SX
+ depends on (SOC_IMX6SX || SOC_IMX6UL || SOC_IMX7 || ARCH_FSL_IMX8MQ)
depends on OF
help
This is the snvs powerkey driver for the Freescale i.MX application
@@ -427,6 +436,21 @@ config KEYBOARD_SNVS_PWRKEY
To compile this driver as a module, choose M here; the
module will be called snvs_pwrkey.
+config KEYBOARD_IMX_SC_PWRKEY
+ tristate "IMX SC Power Key Driver"
+ depends on (ARCH_FSL_IMX8QM || ARCH_FSL_IMX8QXP)
+ help
+ This is the virtual snvs powerkey driver for NXP i.mx8Q/QXP family
+ whose SCU hold snvs inside.
+
+config KEYBOARD_PF1550_ONKEY
+ tristate "PF1550 OnKey Driver"
+ depends on MFD_PF1550
+ depends on OF
+ help
+ This is onkey driver for PF1550 pmic, onkey can trigger release
+ and 1s(push hold), 2s, 3s, 4s, 8s interrupt for long press detect
+
config KEYBOARD_IMX
tristate "IMX keypad support"
depends on ARCH_MXC
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index d9f4cfcf3410..1448be5c6b33 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -50,9 +50,12 @@ obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o
obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o
+obj-$(CONFIG_KEYBOARD_RPMSG) += rpmsg-keys.o
obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o
obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
obj-$(CONFIG_KEYBOARD_SNVS_PWRKEY) += snvs_pwrkey.o
+obj-$(CONFIG_KEYBOARD_IMX_SC_PWRKEY) += imx_sc_pwrkey.o
+obj-$(CONFIG_KEYBOARD_PF1550_ONKEY) += pf1550_onkey.o
obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index ec876b5b1382..a7a52e6a19b8 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -1807,7 +1807,8 @@ static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = {
static int __init atkbd_init(void)
{
- dmi_check_system(atkbd_dmi_quirk_table);
+ if (!dmi_check_system(atkbd_dmi_quirk_table))
+ return -ENODEV;
return serio_register_driver(&atkbd_drv);
}
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 9b8079ca0fb4..50023867c255 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -849,6 +849,8 @@ static int gpio_keys_suspend(struct device *dev)
mutex_unlock(&input->mutex);
}
+ pinctrl_pm_select_sleep_state(dev);
+
return 0;
}
@@ -859,6 +861,8 @@ static int gpio_keys_resume(struct device *dev)
int error = 0;
int i;
+ pinctrl_pm_select_default_state(dev);
+
if (device_may_wakeup(dev)) {
for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i];
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index 2165f3dd328b..9b14cab768d5 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -1,6 +1,7 @@
/*
* Driver for the IMX keypad port.
* Copyright (C) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -267,6 +268,7 @@ static void imx_keypad_check_for_events(unsigned long data)
reg_val |= KBD_STAT_KDIE;
reg_val &= ~KBD_STAT_KRIE;
writew(reg_val, keypad->mmio_base + KPSR);
+ pm_relax(keypad->input_dev->dev.parent);
} else {
/*
* Some keys are still pressed. Schedule a rescan in
@@ -280,11 +282,6 @@ static void imx_keypad_check_for_events(unsigned long data)
reg_val = readw(keypad->mmio_base + KPSR);
reg_val |= KBD_STAT_KPKR | KBD_STAT_KRSS;
writew(reg_val, keypad->mmio_base + KPSR);
-
- reg_val = readw(keypad->mmio_base + KPSR);
- reg_val |= KBD_STAT_KRIE;
- reg_val &= ~KBD_STAT_KDIE;
- writew(reg_val, keypad->mmio_base + KPSR);
}
}
@@ -302,6 +299,7 @@ static irqreturn_t imx_keypad_irq_handler(int irq, void *dev_id)
writew(reg_val, keypad->mmio_base + KPSR);
if (keypad->enabled) {
+ pm_stay_awake(keypad->input_dev->dev.parent);
/* The matrix is supposed to be changed */
keypad->stable_count = 0;
@@ -530,11 +528,12 @@ static int imx_keypad_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused imx_kbd_suspend(struct device *dev)
+static int __maybe_unused imx_kbd_suspend_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_keypad *kbd = platform_get_drvdata(pdev);
struct input_dev *input_dev = kbd->input_dev;
+ unsigned short reg_val = readw(kbd->mmio_base + KPSR);
/* imx kbd can wake up system even clock is disabled */
mutex_lock(&input_dev->mutex);
@@ -544,13 +543,20 @@ static int __maybe_unused imx_kbd_suspend(struct device *dev)
mutex_unlock(&input_dev->mutex);
- if (device_may_wakeup(&pdev->dev))
+ if (device_may_wakeup(&pdev->dev)) {
+ if (reg_val & KBD_STAT_KPKD)
+ reg_val |= KBD_STAT_KRIE;
+ if (reg_val & KBD_STAT_KPKR)
+ reg_val |= KBD_STAT_KDIE;
+ writew(reg_val, kbd->mmio_base + KPSR);
+
enable_irq_wake(kbd->irq);
+ }
return 0;
}
-static int __maybe_unused imx_kbd_resume(struct device *dev)
+static int __maybe_unused imx_kbd_resume_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_keypad *kbd = platform_get_drvdata(pdev);
@@ -574,7 +580,10 @@ err_clk:
return ret;
}
-static SIMPLE_DEV_PM_OPS(imx_kbd_pm_ops, imx_kbd_suspend, imx_kbd_resume);
+static const struct dev_pm_ops imx_kbd_pm_ops = {
+ .suspend_noirq = imx_kbd_suspend_noirq,
+ .resume_noirq = imx_kbd_resume_noirq,
+};
static struct platform_driver imx_keypad_driver = {
.driver = {
diff --git a/drivers/input/keyboard/imx_sc_pwrkey.c b/drivers/input/keyboard/imx_sc_pwrkey.c
new file mode 100644
index 000000000000..10c0d06884a9
--- /dev/null
+++ b/drivers/input/keyboard/imx_sc_pwrkey.c
@@ -0,0 +1,173 @@
+/*
+ * Driver for the IMX SNVS ON/OFF Power Key over sc api
+ * Copyright (C) 2017 NXP. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <soc/imx8/sc/sci.h>
+#include <soc/imx8/sc/svc/irq/api.h>
+
+#define DEBOUNCE_TIME 100
+#define REPEAT_INTERVAL 60
+
+struct pwrkey_drv_data {
+ int keycode;
+ bool keystate; /* 1: pressed, 0: release */
+ bool delay_check;
+ sc_ipc_t ipcHandle;
+ int wakeup;
+ struct delayed_work check_work;
+ struct input_dev *input;
+};
+
+static struct pwrkey_drv_data *pdata;
+
+static int imx_sc_pwrkey_notify(struct notifier_block *nb,
+ unsigned long event, void *group)
+{
+ /* ignore other irqs */
+ if (!(pdata && pdata->ipcHandle && (event & SC_IRQ_BUTTON) &&
+ (*(sc_irq_group_t *)group == SC_IRQ_GROUP_WAKE)))
+ return 0;
+
+ if (!pdata->delay_check) {
+ pdata->delay_check = 1;
+ schedule_delayed_work(&pdata->check_work,
+ msecs_to_jiffies(REPEAT_INTERVAL));
+ }
+
+ return 0;
+}
+
+static void imx_sc_check_for_events(struct work_struct *work)
+{
+ struct input_dev *input = pdata->input;
+ bool state;
+
+ sc_misc_get_button_status(pdata->ipcHandle, &state);
+ /*
+ * restore status back if press interrupt received but pin's status
+ * released, which caused by pressing so quickly.
+ */
+ if (!state && !pdata->keystate)
+ state = true;
+
+ if (state ^ pdata->keystate) {
+ pm_wakeup_event(input->dev.parent, 0);
+ pdata->keystate = !!state;
+ input_event(input, EV_KEY, pdata->keycode, !!state);
+ input_sync(input);
+ if (!state)
+ pdata->delay_check = 0;
+ pm_relax(pdata->input->dev.parent);
+ }
+ /* repeat check if pressed long */
+ if (state)
+ schedule_delayed_work(&pdata->check_work,
+ msecs_to_jiffies(DEBOUNCE_TIME));
+}
+
+static struct notifier_block imx_sc_pwrkey_notifier = {
+ .notifier_call = imx_sc_pwrkey_notify,
+};
+
+static int imx_sc_pwrkey_probe(struct platform_device *pdev)
+{
+ struct input_dev *input = NULL;
+ struct device_node *np = pdev->dev.of_node;
+ int error;
+ uint32_t mu_id;
+ sc_err_t sciErr;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ if (of_property_read_u32(np, "linux,keycode", &pdata->keycode)) {
+ pdata->keycode = KEY_POWER;
+ dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n");
+ }
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ dev_err(&pdev->dev, "can not obtain mu id: %d\n", sciErr);
+ return sciErr;
+ }
+
+ sciErr = sc_ipc_open(&pdata->ipcHandle, mu_id);
+
+ if (sciErr != SC_ERR_NONE) {
+ dev_err(&pdev->dev, "can not get ipc handler: %d\n", sciErr);
+ return sciErr;
+ };
+
+ INIT_DELAYED_WORK(&pdata->check_work, imx_sc_check_for_events);
+
+ pdata->wakeup = of_property_read_bool(np, "wakeup-source");
+
+ input = devm_input_allocate_device(&pdev->dev);
+
+ if (!input) {
+ dev_err(&pdev->dev, "failed to allocate the input device\n");
+ return -ENOMEM;
+ }
+
+ input->name = pdev->name;
+ input->phys = "imx-sc-pwrkey/input0";
+ input->id.bustype = BUS_HOST;
+
+ input_set_capability(input, EV_KEY, pdata->keycode);
+
+ error = input_register_device(input);
+ if (error < 0) {
+ dev_err(&pdev->dev, "failed to register input device\n");
+ return error;
+ }
+
+ pdata->input = input;
+ platform_set_drvdata(pdev, pdata);
+
+ device_init_wakeup(&pdev->dev, !!(pdata->wakeup));
+
+ return register_scu_notifier(&imx_sc_pwrkey_notifier);
+}
+
+static const struct of_device_id imx_sc_pwrkey_ids[] = {
+ { .compatible = "fsl,imx8-pwrkey" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_sc_pwrkey_ids);
+
+static struct platform_driver imx_sc_pwrkey_driver = {
+ .driver = {
+ .name = "imx8-pwrkey",
+ .of_match_table = imx_sc_pwrkey_ids,
+ },
+ .probe = imx_sc_pwrkey_probe,
+};
+module_platform_driver(imx_sc_pwrkey_driver);
+
+MODULE_AUTHOR("Robin Gong <yibin.gong@nxp.com>");
+MODULE_DESCRIPTION("i.MX8 power key driver based on scu");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/pf1550_onkey.c b/drivers/input/keyboard/pf1550_onkey.c
new file mode 100644
index 000000000000..2ba0d155ef99
--- /dev/null
+++ b/drivers/input/keyboard/pf1550_onkey.c
@@ -0,0 +1,206 @@
+/*
+ * Driver for the PF1550 ON_KEY
+ * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/pf1550.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+struct onkey_drv_data {
+ struct device *dev;
+ struct pf1550_dev *pf1550;
+ int irq;
+ int keycode;
+ int wakeup;
+ struct input_dev *input;
+};
+
+static struct pf1550_irq_info pf1550_onkey_irqs[] = {
+ { PF1550_ONKEY_IRQ_PUSHI, "release" },
+ { PF1550_ONKEY_IRQ_1SI, "1S" },
+ { PF1550_ONKEY_IRQ_2SI, "2S" },
+ { PF1550_ONKEY_IRQ_3SI, "3S" },
+ { PF1550_ONKEY_IRQ_4SI, "4S" },
+ { PF1550_ONKEY_IRQ_8SI, "8S" },
+};
+
+static irqreturn_t pf1550_onkey_irq_handler(int irq, void *data)
+{
+ struct onkey_drv_data *onkey = data;
+ int i, state, irq_type = -1;
+
+ onkey->irq = irq;
+
+ for (i = 0; i < ARRAY_SIZE(pf1550_onkey_irqs); i++)
+ if (onkey->irq == pf1550_onkey_irqs[i].virq)
+ irq_type = pf1550_onkey_irqs[i].irq;
+ switch (irq_type) {
+ case PF1550_ONKEY_IRQ_PUSHI:
+ state = 0;
+ break;
+ case PF1550_ONKEY_IRQ_1SI:
+ case PF1550_ONKEY_IRQ_2SI:
+ case PF1550_ONKEY_IRQ_3SI:
+ case PF1550_ONKEY_IRQ_4SI:
+ case PF1550_ONKEY_IRQ_8SI:
+ state = 1;
+ break;
+ default:
+ dev_err(onkey->dev, "onkey interrupt: irq %d occurred\n",
+ irq_type);
+ return IRQ_HANDLED;
+ }
+
+ input_event(onkey->input, EV_KEY, onkey->keycode, state);
+ input_sync(onkey->input);
+
+ return IRQ_HANDLED;
+}
+
+static int pf1550_onkey_probe(struct platform_device *pdev)
+{
+ struct onkey_drv_data *onkey;
+ struct input_dev *input = NULL;
+ struct device_node *np = pdev->dev.of_node;
+ struct pf1550_dev *pf1550 = dev_get_drvdata(pdev->dev.parent);
+ int i, error;
+
+ if (!np)
+ return -ENODEV;
+
+ onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL);
+ if (!onkey)
+ return -ENOMEM;
+
+ if (of_property_read_u32(np, "linux,keycode", &onkey->keycode)) {
+ onkey->keycode = KEY_POWER;
+ dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n");
+ }
+
+ onkey->wakeup = of_property_read_bool(np, "wakeup");
+
+ input = devm_input_allocate_device(&pdev->dev);
+ if (!input) {
+ dev_err(&pdev->dev, "failed to allocate the input device\n");
+ return -ENOMEM;
+ }
+
+ input->name = pdev->name;
+ input->phys = "pf1550-onkey/input0";
+ input->id.bustype = BUS_HOST;
+
+ input_set_capability(input, EV_KEY, onkey->keycode);
+
+ for (i = 0; i < ARRAY_SIZE(pf1550_onkey_irqs); i++) {
+ struct pf1550_irq_info *onkey_irq =
+ &pf1550_onkey_irqs[i];
+ unsigned int virq = 0;
+
+ virq = regmap_irq_get_virq(pf1550->irq_data_onkey,
+ onkey_irq->irq);
+ if (!virq)
+ return -EINVAL;
+
+ onkey_irq->virq = virq;
+
+ error = devm_request_threaded_irq(&pdev->dev, virq, NULL,
+ pf1550_onkey_irq_handler,
+ IRQF_NO_SUSPEND,
+ onkey_irq->name, onkey);
+ if (error) {
+ dev_err(&pdev->dev,
+ "failed: irq request (IRQ: %d, error :%d)\n",
+ onkey_irq->irq, error);
+ return error;
+ }
+ }
+
+ error = input_register_device(input);
+ if (error < 0) {
+ dev_err(&pdev->dev, "failed to register input device\n");
+ input_free_device(input);
+ return error;
+ }
+
+ onkey->input = input;
+ onkey->pf1550 = pf1550;
+ platform_set_drvdata(pdev, onkey);
+
+ device_init_wakeup(&pdev->dev, onkey->wakeup);
+
+ return 0;
+}
+
+static int pf1550_onkey_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct onkey_drv_data *onkey = platform_get_drvdata(pdev);
+
+ if (!device_may_wakeup(&pdev->dev))
+ regmap_write(onkey->pf1550->regmap,
+ PF1550_PMIC_REG_ONKEY_INT_MASK0,
+ ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI | ONKEY_IRQ_2SI |
+ ONKEY_IRQ_3SI | ONKEY_IRQ_4SI | ONKEY_IRQ_8SI);
+ else
+ enable_irq_wake(onkey->pf1550->irq);
+
+ return 0;
+}
+
+static int pf1550_onkey_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct onkey_drv_data *onkey = platform_get_drvdata(pdev);
+
+ if (!device_may_wakeup(&pdev->dev))
+ regmap_write(onkey->pf1550->regmap,
+ PF1550_PMIC_REG_ONKEY_INT_MASK0,
+ ~(ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI | ONKEY_IRQ_2SI |
+ ONKEY_IRQ_3SI | ONKEY_IRQ_4SI | ONKEY_IRQ_8SI));
+ else
+ disable_irq_wake(onkey->pf1550->irq);
+
+ return 0;
+}
+
+static const struct of_device_id pf1550_onkey_ids[] = {
+ { .compatible = "fsl,pf1550-onkey" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pf1550_onkey_ids);
+
+static SIMPLE_DEV_PM_OPS(pf1550_onkey_pm_ops, pf1550_onkey_suspend,
+ pf1550_onkey_resume);
+
+static struct platform_driver pf1550_onkey_driver = {
+ .driver = {
+ .name = "pf1550-onkey",
+ .pm = &pf1550_onkey_pm_ops,
+ .of_match_table = pf1550_onkey_ids,
+ },
+ .probe = pf1550_onkey_probe,
+};
+module_platform_driver(pf1550_onkey_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor");
+MODULE_DESCRIPTION(" PF1550 onkey Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/rpmsg-keys.c b/drivers/input/keyboard/rpmsg-keys.c
new file mode 100644
index 000000000000..f6012e87f9a6
--- /dev/null
+++ b/drivers/input/keyboard/rpmsg-keys.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/imx_rpmsg.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+#include <linux/rpmsg.h>
+#include <linux/uaccess.h>
+#include <linux/virtio.h>
+
+#define RPMSG_TIMEOUT 1000
+
+enum key_cmd_type {
+ KEY_RPMSG_SETUP,
+ KEY_RPMSG_REPLY,
+ KEY_RPMSG_NOTIFY,
+};
+
+enum keys_type {
+ KEY_PRESS = 1,
+ KEY_RELEASE,
+ KEY_BOTH,
+};
+
+struct key_rpmsg_data {
+ struct imx_rpmsg_head header;
+ u8 key_index;
+ union {
+ u8 event;
+ u8 retcode;
+ };
+ u8 wakeup;
+} __attribute__((packed));
+
+struct rpmsg_keys_button {
+ unsigned int code;
+ enum keys_type type;
+ int wakeup;
+ struct input_dev *input;
+};
+
+struct rpmsg_keys_drvdata {
+ struct input_dev *input;
+ struct rpmsg_device *rpdev;
+ struct device *dev;
+ struct key_rpmsg_data *msg;
+ bool ack;
+ struct pm_qos_request pm_qos_req;
+ struct delayed_work keysetup_work;
+ struct completion cmd_complete;
+ int nbuttons;
+ struct rpmsg_keys_button buttons[0];
+};
+
+static struct rpmsg_keys_drvdata *keys_rpmsg;
+
+static int key_send_message(struct key_rpmsg_data *msg,
+ struct rpmsg_keys_drvdata *info, bool ack)
+{
+ int err;
+
+ if (!info->rpdev) {
+ dev_dbg(info->dev,
+ "rpmsg channel not ready, m4 image ready?\n");
+ return -EINVAL;
+ }
+
+ pm_qos_add_request(&info->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, 0);
+
+ if (ack) {
+ info->ack = true;
+ reinit_completion(&info->cmd_complete);
+ }
+
+ err = rpmsg_send(info->rpdev->ept, (void *)msg,
+ sizeof(struct key_rpmsg_data));
+ if (err) {
+ dev_err(&info->rpdev->dev, "rpmsg_send failed: %d\n", err);
+ goto err_out;
+ }
+
+ if (ack) {
+ err = wait_for_completion_timeout(&info->cmd_complete,
+ msecs_to_jiffies(RPMSG_TIMEOUT));
+ if (!err) {
+ dev_err(&info->rpdev->dev, "rpmsg_send timeout!\n");
+ err = -ETIMEDOUT;
+ goto err_out;
+ }
+
+ if (info->msg->retcode != 0) {
+ dev_err(&info->rpdev->dev, "rpmsg not ack %d!\n",
+ info->msg->retcode);
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ err = 0;
+ }
+
+err_out:
+ info->ack = true;
+ pm_qos_remove_request(&info->pm_qos_req);
+
+ return err;
+}
+
+static int keys_rpmsg_cb(struct rpmsg_device *rpdev,
+ void *data, int len, void *priv, u32 src)
+{
+ struct key_rpmsg_data *msg = (struct key_rpmsg_data *)data;
+
+ if (msg->header.type == KEY_RPMSG_REPLY) {
+ keys_rpmsg->msg = msg;
+ complete(&keys_rpmsg->cmd_complete);
+ return 0;
+ } else if (msg->header.type == KEY_RPMSG_NOTIFY) {
+ keys_rpmsg->msg = msg;
+ keys_rpmsg->ack = false;
+ } else
+ dev_err(&keys_rpmsg->rpdev->dev, "wrong command type!\n");
+
+ input_event(keys_rpmsg->input, EV_KEY, msg->key_index, msg->event);
+ input_sync(keys_rpmsg->input);
+
+ return 0;
+}
+
+static void keys_init_handler(struct work_struct *work)
+{
+ struct key_rpmsg_data msg;
+ int i;
+
+ /* setup keys */
+ for (i = 0; i < keys_rpmsg->nbuttons; i++) {
+ struct rpmsg_keys_button *button = &keys_rpmsg->buttons[i];
+
+ msg.header.cate = IMX_RPMSG_KEY;
+ msg.header.major = IMX_RMPSG_MAJOR;
+ msg.header.minor = IMX_RMPSG_MINOR;
+ msg.header.type = KEY_RPMSG_SETUP;
+ msg.header.cmd = 0;
+ msg.key_index = button->code;
+ msg.wakeup = button->wakeup;
+ msg.event = button->type;
+ if (key_send_message(&msg, keys_rpmsg, true))
+ dev_err(&keys_rpmsg->rpdev->dev,
+ "key %d setup failed!\n", button->code);
+ }
+}
+
+static int keys_rpmsg_probe(struct rpmsg_device *rpdev)
+{
+ keys_rpmsg->rpdev = rpdev;
+
+ dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
+ rpdev->src, rpdev->dst);
+
+ init_completion(&keys_rpmsg->cmd_complete);
+
+ INIT_DELAYED_WORK(&keys_rpmsg->keysetup_work,
+ keys_init_handler);
+ schedule_delayed_work(&keys_rpmsg->keysetup_work,
+ msecs_to_jiffies(100));
+
+ return 0;
+}
+
+static struct rpmsg_device_id keys_rpmsg_id_table[] = {
+ { .name = "rpmsg-keypad-channel" },
+ { },
+};
+
+static struct rpmsg_driver keys_rpmsg_driver = {
+ .drv.name = "key_rpmsg",
+ .drv.owner = THIS_MODULE,
+ .id_table = keys_rpmsg_id_table,
+ .probe = keys_rpmsg_probe,
+ .callback = keys_rpmsg_cb,
+};
+
+static struct rpmsg_keys_drvdata *
+rpmsg_keys_get_devtree_pdata(struct device *dev)
+{
+ struct device_node *node, *pp;
+ struct rpmsg_keys_drvdata *ddata;
+ struct rpmsg_keys_button *button;
+ int nbuttons;
+ int i;
+
+ node = dev->of_node;
+ if (!node)
+ return ERR_PTR(-ENODEV);
+
+ nbuttons = of_get_child_count(node);
+ if (nbuttons == 0)
+ return ERR_PTR(-ENODEV);
+
+ ddata = devm_kzalloc(dev,
+ sizeof(*ddata) + nbuttons *
+ sizeof(struct rpmsg_keys_button),
+ GFP_KERNEL);
+ if (!ddata)
+ return ERR_PTR(-ENOMEM);
+
+ ddata->nbuttons = nbuttons;
+
+ i = 0;
+ for_each_child_of_node(node, pp) {
+ button = &ddata->buttons[i++];
+
+ if (of_property_read_u32(pp, "linux,code", &button->code)) {
+ dev_err(dev, "Button without keycode: 0x%x\n",
+ button->code);
+ return ERR_PTR(-EINVAL);
+ }
+
+ button->wakeup = !!of_get_property(pp, "rpmsg-key,wakeup",
+ NULL);
+ button->type = KEY_BOTH;
+ }
+
+ return ddata;
+}
+
+static int rpmsg_keys_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rpmsg_keys_drvdata *ddata;
+ int i, error;
+ struct input_dev *input;
+
+ ddata = rpmsg_keys_get_devtree_pdata(dev);
+ if (IS_ERR(ddata))
+ return PTR_ERR(ddata);
+
+ input = devm_input_allocate_device(dev);
+ if (!input) {
+ dev_err(dev, "failed to allocate input device\n");
+ return -ENOMEM;
+ }
+
+ ddata->input = input;
+
+ keys_rpmsg = ddata;
+ platform_set_drvdata(pdev, ddata);
+
+ input->name = pdev->name;
+ input->phys = "rpmsg-keys/input0";
+ input->dev.parent = &pdev->dev;
+
+ input->id.bustype = BUS_HOST;
+
+ for (i = 0; i < ddata->nbuttons; i++) {
+ struct rpmsg_keys_button *button = &ddata->buttons[i];
+
+ input_set_capability(input, EV_KEY, button->code);
+ }
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(dev, "Unable to register input device, error: %d\n",
+ error);
+ goto err_out;
+ }
+
+ return register_rpmsg_driver(&keys_rpmsg_driver);
+err_out:
+ return error;
+}
+
+static const struct of_device_id rpmsg_keys_of_match[] = {
+ { .compatible = "fsl,rpmsg-keys", },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, rpmsg_keys_of_match);
+
+static struct platform_driver rpmsg_keys_device_driver = {
+ .probe = rpmsg_keys_probe,
+ .driver = {
+ .name = "rpmsg-keys",
+ .of_match_table = of_match_ptr(rpmsg_keys_of_match)
+ }
+};
+
+module_platform_driver(rpmsg_keys_device_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Robin Gong <yibin.gong@nxp.com>");
+MODULE_DESCRIPTION("Keyboard driver based on rpmsg");
diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
index 7544888c4749..8f8de877ded7 100644
--- a/drivers/input/keyboard/snvs_pwrkey.c
+++ b/drivers/input/keyboard/snvs_pwrkey.c
@@ -156,15 +156,6 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
return error;
}
- error = devm_request_irq(&pdev->dev, pdata->irq,
- imx_snvs_pwrkey_interrupt,
- 0, pdev->name, pdev);
-
- if (error) {
- dev_err(&pdev->dev, "interrupt not available.\n");
- return error;
- }
-
error = input_register_device(input);
if (error < 0) {
dev_err(&pdev->dev, "failed to register input device\n");
@@ -176,6 +167,16 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, pdata->wakeup);
+ error = devm_request_irq(&pdev->dev, pdata->irq,
+ imx_snvs_pwrkey_interrupt,
+ 0, pdev->name, pdev);
+
+ if (error) {
+ dev_err(&pdev->dev, "interrupt not available.\n");
+ input_unregister_device(input);
+ return error;
+ }
+
return 0;
}
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 7ffb614ce566..adeac9208505 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -831,4 +831,39 @@ config INPUT_HISI_POWERKEY
To compile this driver as a module, choose M here: the
module will be called hisi_powerkey.
+config INPUT_MPL3115
+ tristate "MPL3115 pressure temperature sensor"
+ depends on I2C && SYSFS
+ help
+ If you say yes here you get support for the Freescale MPL3115
+ pressure temperature sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called mpl3115
+
+config SENSOR_FXLS8471
+ tristate "FXLS8471 motion sensor device driver"
+ depends on I2C
+ default n
+
+config SENSOR_IMX_RPMSG
+ tristate "NXP IMX rpmsg virtual sensor device driver"
+ depends on (SOC_IMX7ULP)
+ depends on RPMSG && SYSFS
+ depends on OF
+ default n
+ help
+ This is rpmsg virtual sensor driver on i.mx7ulp, because some
+ sensors connect with M4 core.
+
+config INPUT_ISL29023
+ tristate "Intersil ISL29023 ambient light sensor"
+ depends on I2C && SYSFS
+ help
+ If you say yes here you get support for the Intersil ISL29023
+ ambient light sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called isl29023.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 0b6d025f0487..a6d887f50de0 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -78,3 +78,7 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o
+obj-$(CONFIG_INPUT_MPL3115) += mpl3115.o
+obj-$(CONFIG_SENSOR_FXLS8471) += fxls8471.o fxls8471_i2c.o
+obj-$(CONFIG_INPUT_ISL29023) += isl29023.o
+obj-$(CONFIG_SENSOR_IMX_RPMSG) += rpmsg_input.o
diff --git a/drivers/input/misc/fxls8471.c b/drivers/input/misc/fxls8471.c
new file mode 100644
index 000000000000..ef7368bb519b
--- /dev/null
+++ b/drivers/input/misc/fxls8471.c
@@ -0,0 +1,583 @@
+/*
+ * fxls8471.c - Linux kernel modules for 3-Axis Accel sensor
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/input-polldev.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include "fxls8471.h"
+
+#define SENSOR_IOCTL_BASE 'S'
+#define SENSOR_GET_MODEL_NAME _IOR(SENSOR_IOCTL_BASE, 0, char *)
+#define SENSOR_GET_POWER_STATUS _IOR(SENSOR_IOCTL_BASE, 2, int)
+#define SENSOR_SET_POWER_STATUS _IOR(SENSOR_IOCTL_BASE, 3, int)
+#define SENSOR_GET_DELAY_TIME _IOR(SENSOR_IOCTL_BASE, 4, int)
+#define SENSOR_SET_DELAY_TIME _IOR(SENSOR_IOCTL_BASE, 5, int)
+#define SENSOR_GET_RAW_DATA _IOR(SENSOR_IOCTL_BASE, 6, short[3])
+
+#define FXLS8471_POSITION_DEFAULT 2
+#define FXLS8471_DELAY_DEFAULT 200
+
+#define FXLS8471_STATUS_ZYXDR 0x08
+#define FXLS8471_BUF_SIZE 6
+
+struct fxls8471_data fxls8471_dev;
+EXPORT_SYMBOL(fxls8471_dev);
+
+static int fxls8471_position_setting[8][3][3] = {
+ {{0, -1, 0}, {1, 0, 0}, {0, 0, 1} },
+ {{-1, 0, 0}, {0, -1, 0}, {0, 0, 1} },
+ {{0, 1, 0}, {-1, 0, 0}, {0, 0, 1} },
+ {{1, 0, 0}, {0, 1, 0}, {0, 0, 1} },
+
+ {{0, -1, 0}, {-1, 0, 0}, {0, 0, -1} },
+ {{-1, 0, 0}, {0, 1, 0}, {0, 0, -1} },
+ {{0, 1, 0}, {1, 0, 0}, {0, 0, -1} },
+ {{1, 0, 0}, {0, -1, 0}, {0, 0, -1} },
+};
+
+static int fxls8471_bus_write(struct fxls8471_data *pdata, u8 reg, u8 val)
+{
+ if (pdata && pdata->write)
+ return pdata->write(pdata, reg, val);
+ return -EIO;
+}
+
+static int fxls8471_bus_read(struct fxls8471_data *pdata, u8 reg)
+{
+ if (pdata && pdata->read)
+ return pdata->read(pdata, reg);
+ return -EIO;
+}
+
+static int fxls8471_bus_read_block(struct fxls8471_data *pdata, u8 reg, u8 len,
+ u8 *val)
+{
+ if (pdata && pdata->read_block)
+ return pdata->read_block(pdata, reg, len, val);
+ return -EIO;
+}
+
+static int fxls8471_data_convert(struct fxls8471_data *pdata,
+ struct fxls8471_data_axis *axis_data)
+{
+ short rawdata[3], data[3];
+ int i, j;
+ int position = atomic_read(&pdata->position);
+
+ if (position < 0 || position > 7)
+ position = 0;
+ rawdata[0] = axis_data->x;
+ rawdata[1] = axis_data->y;
+ rawdata[2] = axis_data->z;
+ for (i = 0; i < 3; i++) {
+ data[i] = 0;
+ for (j = 0; j < 3; j++)
+ data[i] +=
+ rawdata[j] *
+ fxls8471_position_setting[position][i][j];
+ }
+ axis_data->x = data[0];
+ axis_data->y = data[1];
+ axis_data->z = data[2];
+ return 0;
+}
+
+static int fxls8471_device_init(struct fxls8471_data *pdata)
+{
+ int result;
+ result = fxls8471_bus_write(pdata, FXLS8471_CTRL_REG1, 0);
+ if (result < 0)
+ goto out;
+
+ result = fxls8471_bus_write(pdata, FXLS8471_XYZ_DATA_CFG, MODE_2G);
+ if (result < 0)
+ goto out;
+
+ if (pdata->irq) {
+ result = fxls8471_bus_write(pdata, FXLS8471_CTRL_REG5, 0x01);
+ if (result < 0)
+ goto out;
+ result = fxls8471_bus_write(pdata, FXLS8471_CTRL_REG4, 0x01);
+ if (result < 0)
+ goto out;
+ }
+ atomic_set(&pdata->active, STANDBY);
+ return 0;
+out:
+ printk("FXLS8471 device init error\n");
+ return result;
+
+}
+
+static int fxls8471_change_mode(struct fxls8471_data *pdata, int mode)
+{
+ u8 val;
+ int ret;
+ val = fxls8471_bus_read(pdata, FXLS8471_CTRL_REG1);
+ if (mode == ACTIVED)
+ val |= 0x01;
+ else
+ val &= (~0x01);
+ ret = fxls8471_bus_write(pdata, FXLS8471_CTRL_REG1, val);
+ return ret;
+}
+
+static int fxls8471_set_delay(struct fxls8471_data *pdata, int delay)
+{
+ u8 val;
+ val = fxls8471_bus_read(pdata, FXLS8471_CTRL_REG1);
+ /* set sensor standby */
+ fxls8471_bus_write(pdata, FXLS8471_CTRL_REG1, (val & ~0x01));
+ val &= ~(0x7 << 3);
+ if (delay <= 10)
+ val |= 0x02 << 3;
+ else if (delay <= 20)
+ val |= 0x03 << 3;
+ else if (delay <= 67)
+ val |= 0x04 << 3;
+ else
+ val |= 0x05 << 3;
+ /* set sensor standby */
+ fxls8471_bus_write(pdata, FXLS8471_CTRL_REG1, val);
+ return 0;
+}
+
+static int fxls8471_change_range(struct fxls8471_data *pdata, int range)
+{
+ int ret;
+
+ ret = fxls8471_bus_write(pdata, FXLS8471_XYZ_DATA_CFG, range);
+
+ return ret;
+}
+
+static int fxls8471_read_data(struct fxls8471_data *pdata,
+ struct fxls8471_data_axis *data)
+{
+ u8 tmp_data[FXLS8471_BUF_SIZE];
+ int ret;
+ ret = fxls8471_bus_read_block(pdata, FXLS8471_OUT_X_MSB,
+ FXLS8471_BUF_SIZE, tmp_data);
+ if (ret < FXLS8471_BUF_SIZE) {
+ printk(KERN_ERR "FXLS8471 read sensor block data error\n");
+ return -EIO;
+ }
+ data->x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1];
+ data->y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3];
+ data->z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5];
+ return 0;
+}
+
+/* fxls8471 miscdevice */
+static long fxls8471_ioctl(struct file *file, unsigned int reg,
+ unsigned long arg)
+{
+ struct fxls8471_data *pdata = file->private_data;
+ void __user *argp = (void __user *)arg;
+ long ret = 0;
+ short sdata[3];
+ int enable;
+ int delay;
+ struct fxls8471_data_axis data;
+ if (!pdata) {
+ printk(KERN_ERR "FXLS8471 struct datt point is NULL.");
+ return -EFAULT;
+ }
+ switch (reg) {
+ case SENSOR_GET_MODEL_NAME:
+ if (copy_to_user(argp, "fxls8471", strlen("fxls8471") + 1)) {
+ printk(KERN_ERR
+ "SENSOR_GET_MODEL_NAME copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ break;
+ case SENSOR_GET_POWER_STATUS:
+ enable = atomic_read(&pdata->active);
+ if (copy_to_user(argp, &enable, sizeof(int))) {
+ printk(KERN_ERR
+ "SENSOR_SET_POWER_STATUS copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ break;
+ case SENSOR_SET_POWER_STATUS:
+ if (copy_from_user(&enable, argp, sizeof(int))) {
+ printk(KERN_ERR
+ "SENSOR_SET_POWER_STATUS copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ if (pdata) {
+ ret =
+ fxls8471_change_mode(pdata,
+ enable ? ACTIVED : STANDBY);
+ if (!ret)
+ atomic_set(&pdata->active, enable);
+ }
+ break;
+ case SENSOR_GET_DELAY_TIME:
+ delay = atomic_read(&pdata->delay);
+ if (copy_to_user(argp, &delay, sizeof(delay))) {
+ printk(KERN_ERR
+ "SENSOR_GET_DELAY_TIME copy_to_user failed.");
+ return -EFAULT;
+ }
+ break;
+ case SENSOR_SET_DELAY_TIME:
+ if (copy_from_user(&delay, argp, sizeof(int))) {
+ printk(KERN_ERR
+ "SENSOR_GET_DELAY_TIME copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ if (pdata && delay > 0 && delay <= 500) {
+ ret = fxls8471_set_delay(pdata, delay);
+ if (!ret)
+ atomic_set(&pdata->delay, delay);
+ }
+ break;
+ case SENSOR_GET_RAW_DATA:
+ ret = fxls8471_read_data(pdata, &data);
+ if (!ret) {
+ fxls8471_data_convert(pdata, &data);
+ sdata[0] = data.x;
+ sdata[1] = data.y;
+ sdata[2] = data.z;
+ if (copy_to_user(argp, sdata, sizeof(sdata))) {
+ printk(KERN_ERR
+ "SENSOR_GET_RAW_DATA copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ }
+ break;
+ default:
+ ret = -1;
+ }
+ return ret;
+}
+
+static int fxls8471_open(struct inode *inode, struct file *file)
+{
+ file->private_data = &fxls8471_dev;
+ return nonseekable_open(inode, file);
+}
+
+static int fxls8471_release(struct inode *inode, struct file *file)
+{
+ /* note: releasing the wdt in NOWAYOUT-mode does not stop it */
+ return 0;
+}
+
+static const struct file_operations fxls8471_fops = {
+ .owner = THIS_MODULE,
+ .open = fxls8471_open,
+ .release = fxls8471_release,
+ .unlocked_ioctl = fxls8471_ioctl,
+};
+
+static struct miscdevice fxls8471_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "FreescaleAccelerometer",
+ .fops = &fxls8471_fops,
+};
+
+static ssize_t fxls8471_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fxls8471_data *pdata = &fxls8471_dev;
+ int enable = 0;
+ enable = atomic_read(&pdata->active);
+ return sprintf(buf, "%d\n", enable);
+}
+
+static ssize_t fxls8471_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fxls8471_data *pdata = &fxls8471_dev;
+ int ret;
+ unsigned long enable;
+
+ if (kstrtoul(buf, 10, &enable) < 0)
+ return -EINVAL;
+ enable = (enable > 0) ? 1 : 0;
+ ret = fxls8471_change_mode(pdata, (enable > 0 ? ACTIVED : STANDBY));
+ if (!ret) {
+ atomic_set(&pdata->active, enable);
+ if (enable)
+ printk(KERN_INFO "mma enable setting actived\n");
+ else
+ printk(KERN_INFO "mma enable setting standby\n");
+ }
+ return count;
+}
+
+static ssize_t fxls8471_poll_delay_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct fxls8471_data *pdata = &fxls8471_dev;
+ int delay = 0;
+ delay = atomic_read(&pdata->delay);
+ return sprintf(buf, "%d\n", delay);
+}
+
+static ssize_t fxls8471_poll_delay_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fxls8471_data *pdata = &fxls8471_dev;
+ int ret;
+ unsigned long delay;
+
+ if (kstrtoul(buf, 10, &delay) < 0)
+ return -EINVAL;
+ ret = fxls8471_set_delay(pdata, delay);
+ if (!ret)
+ atomic_set(&pdata->delay, delay);
+
+ return count;
+}
+
+static ssize_t fxls8471_position_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fxls8471_data *pdata = &fxls8471_dev;
+ int position = 0;
+ position = atomic_read(&pdata->position);
+ return sprintf(buf, "%d\n", position);
+}
+
+static ssize_t fxls8471_position_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fxls8471_data *pdata = &fxls8471_dev;
+ unsigned long position;
+
+ if (kstrtoul(buf, 10, &position) < 0)
+ return -EINVAL;
+ atomic_set(&pdata->position, position);
+
+ return count;
+}
+
+static ssize_t fxls8471_data_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fxls8471_data *pdata = &fxls8471_dev;
+ int ret = 0;
+ struct fxls8471_data_axis data;
+ ret = fxls8471_read_data(pdata, &data);
+ if (!ret)
+ fxls8471_data_convert(pdata, &data);
+ return sprintf(buf, "%d,%d,%d\n", data.x, data.y, data.z);
+}
+
+static ssize_t fxls8471_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fxls8471_data *pdata = &fxls8471_dev;
+ int range = 0;
+
+ range = atomic_read(&pdata->range);
+ return sprintf(buf, "%d\n", range);
+}
+
+static ssize_t fxls8471_range_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fxls8471_data *pdata = &fxls8471_dev;
+ int ret;
+ unsigned long range;
+
+ if (kstrtoul(buf, 10, &range) < 0)
+ return -EINVAL;
+
+ if (range == atomic_read(&pdata->range))
+ return count;
+
+ if (atomic_read(&pdata->active))
+ printk(KERN_INFO "Pls set the sensor standby and then actived\n");
+ ret = fxls8471_change_range(pdata, range);
+ if (!ret)
+ atomic_set(&pdata->range, range);
+
+ return count;
+}
+
+static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, fxls8471_enable_show, fxls8471_enable_store);
+static DEVICE_ATTR(poll_delay, S_IWUSR | S_IRUGO, fxls8471_poll_delay_show,
+ fxls8471_poll_delay_store);
+
+static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, fxls8471_position_show,
+ fxls8471_position_store);
+
+static DEVICE_ATTR(data, S_IWUSR | S_IRUGO, fxls8471_data_show, NULL);
+
+static DEVICE_ATTR(range, S_IWUSR | S_IRUGO, fxls8471_range_show, fxls8471_range_store);
+
+static struct attribute *fxls8471_attributes[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_poll_delay.attr,
+ &dev_attr_position.attr,
+ &dev_attr_data.attr,
+ &dev_attr_range.attr,
+ NULL
+};
+
+static const struct attribute_group fxls8471_attr_group = {
+ .attrs = fxls8471_attributes,
+};
+
+static irqreturn_t fxls8471_irq_handler(int irq, void *dev)
+{
+ int ret;
+ u8 int_src;
+ struct fxls8471_data *pdata = (struct fxls8471_data *)dev;
+ struct fxls8471_data_axis data;
+ int_src = fxls8471_bus_read(pdata, FXLS8471_INT_SOURCE);
+ /* data ready interrupt */
+ if (int_src & 0x01) {
+ ret = fxls8471_read_data(pdata, &data);
+ if (!ret) {
+ fxls8471_data_convert(pdata, &data);
+ input_report_abs(pdata->idev, ABS_X, data.x);
+ input_report_abs(pdata->idev, ABS_Y, data.y);
+ input_report_abs(pdata->idev, ABS_Z, data.z);
+ input_sync(pdata->idev);
+ }
+
+ }
+ return IRQ_HANDLED;
+}
+
+int fxls8471_driver_init(struct fxls8471_data *pdata)
+{
+ int result, chip_id;
+
+ chip_id = fxls8471_bus_read(pdata, FXLS8471_WHO_AM_I);
+
+ if (chip_id != FXSL8471_ID) {
+ printk(KERN_ERR "read sensor who am i (0x%x)error !\n",
+ chip_id);
+ result = -EINVAL;
+ goto err_out;
+ }
+ /* Initialize the FXLS8471 chip */
+ pdata->chip_id = chip_id;
+ atomic_set(&pdata->delay, FXLS8471_DELAY_DEFAULT);
+ atomic_set(&pdata->position, FXLS8471_POSITION_DEFAULT);
+ result = misc_register(&fxls8471_device);
+ if (result != 0) {
+ printk(KERN_ERR "register acc miscdevice error");
+ goto err_out;
+ }
+
+ result =
+ sysfs_create_group(&fxls8471_device.this_device->kobj,
+ &fxls8471_attr_group);
+ if (result) {
+ printk(KERN_ERR "create device file failed!\n");
+ result = -EINVAL;
+ goto err_create_sysfs;
+ }
+ /*create data input device */
+ pdata->idev = input_allocate_device();
+ if (!pdata->idev) {
+ result = -ENOMEM;
+ printk(KERN_ERR "alloc fxls8471 input device failed!\n");
+ goto err_alloc_input_device;
+ }
+ pdata->idev->name = "FreescaleAccelerometer";
+ pdata->idev->id.bustype = BUS_I2C;
+ pdata->idev->evbit[0] = BIT_MASK(EV_ABS);
+ input_set_abs_params(pdata->idev, ABS_X, -0x7fff, 0x7fff, 0, 0);
+ input_set_abs_params(pdata->idev, ABS_Y, -0x7fff, 0x7fff, 0, 0);
+ input_set_abs_params(pdata->idev, ABS_Z, -0x7fff, 0x7fff, 0, 0);
+ result = input_register_device(pdata->idev);
+ if (result) {
+ printk(KERN_ERR "register fxls8471 input device failed!\n");
+ goto err_register_input_device;
+ }
+ if (pdata->irq) {
+ result =
+ request_threaded_irq(pdata->irq, NULL, fxls8471_irq_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ pdata->idev->name, pdata);
+ if (result < 0) {
+ printk(KERN_ERR "failed to register MMA8x5x irq %d!\n",
+ pdata->irq);
+ goto err_register_irq;
+ }
+ }
+ fxls8471_device_init(pdata);
+ printk("fxls8471 device driver probe successfully\n");
+ return 0;
+err_register_irq:
+ input_unregister_device(pdata->idev);
+err_register_input_device:
+ input_free_device(pdata->idev);
+err_alloc_input_device:
+ sysfs_remove_group(&fxls8471_device.this_device->kobj,
+ &fxls8471_attr_group);
+err_create_sysfs:
+ misc_deregister(&fxls8471_device);
+err_out:
+ return result;
+}
+EXPORT_SYMBOL_GPL(fxls8471_driver_init);
+
+int fxls8471_driver_remove(struct fxls8471_data *pdata)
+{
+ fxls8471_change_mode(pdata, STANDBY);
+ misc_deregister(&fxls8471_device);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fxls8471_driver_remove);
+
+#ifdef CONFIG_PM_SLEEP
+int fxls8471_driver_suspend(struct fxls8471_data *pdata)
+{
+ if (atomic_read(&pdata->active))
+ fxls8471_change_mode(pdata, STANDBY);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fxls8471_driver_suspend);
+
+int fxls8471_driver_resume(struct fxls8471_data *pdata)
+{
+ if (atomic_read(&pdata->active))
+ fxls8471_change_mode(pdata, ACTIVED);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fxls8471_driver_resume);
+
+#endif
diff --git a/drivers/input/misc/fxls8471.h b/drivers/input/misc/fxls8471.h
new file mode 100644
index 000000000000..6820ad1c0517
--- /dev/null
+++ b/drivers/input/misc/fxls8471.h
@@ -0,0 +1,94 @@
+/*
+ * fxls8471.h - Linux kernel modules for 3-Axis Accel sensor
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _FXSL8471_H
+#define _FXSL8471_H
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/input.h>
+
+#define FXSL8471_ID 0x6a
+
+/* register enum for fxls8471 registers */
+enum { FXLS8471_STATUS = 0x00, FXLS8471_OUT_X_MSB, FXLS8471_OUT_X_LSB,
+ FXLS8471_OUT_Y_MSB, FXLS8471_OUT_Y_LSB, FXLS8471_OUT_Z_MSB,
+ FXLS8471_OUT_Z_LSB, FXLS8471_F_SETUP =
+ 0x09, FXLS8471_TRIG_CFG, FXLS8471_SYSMOD,
+ FXLS8471_INT_SOURCE, FXLS8471_WHO_AM_I,
+ FXLS8471_XYZ_DATA_CFG, FXLS8471_HP_FILTER_CUTOFF,
+ FXLS8471_PL_STATUS, FXLS8471_PL_CFG, FXLS8471_PL_COUNT,
+ FXLS8471_PL_BF_ZCOMP, FXLS8471_P_L_THS_REG,
+ FXLS8471_FF_MT_CFG, FXLS8471_FF_MT_SRC, FXLS8471_FF_MT_THS,
+ FXLS8471_FF_MT_COUNT, FXLS8471_TRANSIENT_CFG =
+ 0x1D, FXLS8471_TRANSIENT_SRC, FXLS8471_TRANSIENT_THS,
+ FXLS8471_TRANSIENT_COUNT, FXLS8471_PULSE_CFG,
+ FXLS8471_PULSE_SRC, FXLS8471_PULSE_THSX, FXLS8471_PULSE_THSY,
+ FXLS8471_PULSE_THSZ, FXLS8471_PULSE_TMLT,
+ FXLS8471_PULSE_LTCY, FXLS8471_PULSE_WIND,
+ FXLS8471_ASLP_COUNT, FXLS8471_CTRL_REG1, FXLS8471_CTRL_REG2,
+ FXLS8471_CTRL_REG3, FXLS8471_CTRL_REG4, FXLS8471_CTRL_REG5,
+ FXLS8471_OFF_X, FXLS8471_OFF_Y, FXLS8471_OFF_Z,
+ FXLS8471_REG_END,
+};
+
+enum { STANDBY = 0, ACTIVED,
+};
+
+enum { MODE_2G = 0, MODE_4G, MODE_8G,
+};
+
+struct fxls8471_data_axis {
+ short x;
+ short y;
+ short z;
+};
+
+struct fxls8471_data {
+ void *bus_priv;
+ u16 bus_type;
+ int irq;
+ s32 (*write)(struct fxls8471_data *pdata, u8 reg, u8 val);
+ s32 (*read)(struct fxls8471_data *pdata, u8 reg);
+ s32 (*read_block)(struct fxls8471_data *pdata, u8 reg, u8 len,
+ u8 *val);
+ struct input_dev *idev;
+ atomic_t active;
+ atomic_t delay;
+ atomic_t position;
+ atomic_t range;
+ u8 chip_id;
+};
+
+extern struct fxls8471_data fxls8471_dev;
+
+int fxls8471_driver_init(struct fxls8471_data *pdata);
+int fxls8471_driver_remove(struct fxls8471_data *pdata);
+int fxls8471_driver_suspend(struct fxls8471_data *pdata);
+int fxls8471_driver_resume(struct fxls8471_data *pdata);
+
+#endif /* */
diff --git a/drivers/input/misc/fxls8471_i2c.c b/drivers/input/misc/fxls8471_i2c.c
new file mode 100644
index 000000000000..f752ddd0d14b
--- /dev/null
+++ b/drivers/input/misc/fxls8471_i2c.c
@@ -0,0 +1,111 @@
+/*
+ * fxls8471-i2c.c - Linux kernel modules for 3-Axis Smart Orientation
+ * /Motion Sensor
+ * Version : 01.00
+ * Time : Dec.26, 2012
+ * Author : rick zhang <rick.zhang@freescale.com>
+ *
+ * Copyright (C) 2010-2011 Freescale Semiconductor.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include "fxls8471.h"
+
+static s32 fxls8471_i2c_write(struct fxls8471_data *pdata, u8 reg, u8 val)
+{
+ struct i2c_client *client = (struct i2c_client *)pdata->bus_priv;
+ return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int fxls8471_i2c_read(struct fxls8471_data *pdata, u8 reg)
+{
+ struct i2c_client *client = (struct i2c_client *)pdata->bus_priv;
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int fxls8471_i2c_read_block(struct fxls8471_data *pdata, u8 reg, u8 len,
+ u8 *val)
+{
+ struct i2c_client *client = (struct i2c_client *)pdata->bus_priv;
+ return i2c_smbus_read_i2c_block_data(client, reg, len, val);
+}
+
+static int fxls8471_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ fxls8471_dev.bus_priv = client;
+ fxls8471_dev.bus_type = BUS_I2C;
+ fxls8471_dev.irq = client->irq;
+ fxls8471_dev.read = fxls8471_i2c_read;
+ fxls8471_dev.write = fxls8471_i2c_write;
+ fxls8471_dev.read_block = fxls8471_i2c_read_block;
+ i2c_set_clientdata(client, &fxls8471_dev);
+ return fxls8471_driver_init(&fxls8471_dev);
+}
+
+static int fxls8471_i2c_remove(struct i2c_client *client)
+{
+ return fxls8471_driver_remove(&fxls8471_dev);
+}
+
+#ifdef CONFIG_PM
+static int fxls8471_i2c_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ return fxls8471_driver_suspend(i2c_get_clientdata(client));
+}
+
+static int fxls8471_i2c_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ return fxls8471_driver_resume(i2c_get_clientdata(client));
+}
+
+#else /* */
+#define fxls8471_i2c_suspend NULL
+#define fxls8471_i2c_resume NULL
+#endif /* */
+static const struct i2c_device_id fxls8471_i2c_id[] = {
+ {"fxls8471", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, fxls8471_i2c_id);
+
+static SIMPLE_DEV_PM_OPS(fxls8471_pm_ops, fxls8471_i2c_suspend,
+ fxls8471_i2c_resume);
+
+static struct i2c_driver fxls8471_i2c_driver = {
+ .driver = {
+ .name = "fxls8471",
+ .owner = THIS_MODULE,
+ .pm = &fxls8471_pm_ops,
+ },
+ .probe = fxls8471_i2c_probe,
+ .remove = fxls8471_i2c_remove,
+ .id_table = fxls8471_i2c_id,
+};
+
+module_i2c_driver(fxls8471_i2c_driver);
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("FXLS8471 3-Axis Acc Sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/isl29023.c b/drivers/input/misc/isl29023.c
new file mode 100644
index 000000000000..ebe8d3a304d1
--- /dev/null
+++ b/drivers/input/misc/isl29023.c
@@ -0,0 +1,1075 @@
+/*
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+#include <linux/isl29023.h>
+
+#define ISL29023_DRV_NAME "isl29023"
+#define DRIVER_VERSION "1.0"
+
+#define ISL29023_COMMAND1 (0x00)
+#define ISL29023_MODE_SHIFT (5)
+#define ISL29023_MODE_MASK (0x7 << ISL29023_MODE_SHIFT)
+#define ISL29023_INT_FLAG_SHIFT (2)
+#define ISL29023_INT_FLAG_MASK (0x1 << ISL29023_INT_FLAG_SHIFT)
+#define ISL29023_INT_PERSISTS_SHIFT (0)
+#define ISL29023_INT_PERSISTS_MASK (0x3 << ISL29023_INT_PERSISTS_SHIFT)
+
+#define ISL29023_COMMAND2 (0x01)
+#define ISL29023_RES_SHIFT (2)
+#define ISL29023_RES_MASK (0x3 << ISL29023_RES_SHIFT)
+#define ISL29023_RANGE_SHIFT (0)
+#define ISL29023_RANGE_MASK (0x3 << ISL29023_RANGE_SHIFT)
+
+#define ISL29023_REG_LSB_SENSOR (0x02)
+#define ISL29023_REG_MSB_SENSOR (0x03)
+#define ISL29023_REG_IRQ_TH_LO_LSB (0x04)
+#define ISL29023_REG_IRQ_TH_LO_MSB (0x05)
+#define ISL29023_REG_IRQ_TH_HI_LSB (0x06)
+#define ISL29023_REG_IRQ_TH_HI_MSB (0x07)
+
+#define ISL29023_NUM_CACHABLE_REGS 8
+#define DEF_RANGE 2
+#define DEFAULT_REGISTOR_VAL 499
+
+struct isl29023_data {
+ struct i2c_client *client;
+ struct mutex lock;
+ struct input_dev *input;
+ struct work_struct work;
+ struct workqueue_struct *workqueue;
+ char phys[32];
+ u8 reg_cache[ISL29023_NUM_CACHABLE_REGS];
+ u8 mode_before_suspend;
+ u8 mode_before_interrupt;
+ u16 rext;
+};
+
+static int gain_range[] = {
+ 1000, 4000, 16000, 64000
+};
+
+/*
+ * register access helpers
+ */
+static int __isl29023_read_reg(struct i2c_client *client,
+ u32 reg, u8 mask, u8 shift)
+{
+ struct isl29023_data *data = i2c_get_clientdata(client);
+ return (data->reg_cache[reg] & mask) >> shift;
+}
+
+static int __isl29023_write_reg(struct i2c_client *client,
+ u32 reg, u8 mask, u8 shift, u8 val)
+{
+ struct isl29023_data *data = i2c_get_clientdata(client);
+ int ret = 0;
+ u8 tmp;
+
+ if (reg >= ISL29023_NUM_CACHABLE_REGS)
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+
+ tmp = data->reg_cache[reg];
+ tmp &= ~mask;
+ tmp |= val << shift;
+
+ ret = i2c_smbus_write_byte_data(client, reg, tmp);
+ if (!ret)
+ data->reg_cache[reg] = tmp;
+
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+/*
+ * internally used functions
+ */
+static int isl29023_get_int_persists(struct i2c_client *client)
+{
+ return __isl29023_read_reg(client, ISL29023_COMMAND1,
+ ISL29023_INT_PERSISTS_MASK, ISL29023_INT_PERSISTS_SHIFT);
+}
+
+static int isl29023_set_int_persists(struct i2c_client *client,
+ int int_persists)
+{
+ return __isl29023_write_reg(client, ISL29023_COMMAND1,
+ ISL29023_INT_PERSISTS_MASK, ISL29023_INT_PERSISTS_SHIFT,
+ int_persists);
+}
+
+/*
+ * interrupt flag
+ */
+static int isl29023_get_int_flag(struct i2c_client *client)
+{
+ return __isl29023_read_reg(client, ISL29023_COMMAND1,
+ ISL29023_INT_FLAG_MASK, ISL29023_INT_FLAG_SHIFT);
+}
+
+static int isl29023_set_int_flag(struct i2c_client *client, int flag)
+{
+ return __isl29023_write_reg(client, ISL29023_COMMAND1,
+ ISL29023_INT_FLAG_MASK, ISL29023_INT_FLAG_SHIFT, flag);
+}
+
+/*
+ * interrupt lt
+ */
+static int isl29023_get_int_lt(struct i2c_client *client)
+{
+ struct isl29023_data *data = i2c_get_clientdata(client);
+ int lsb, msb, lt;
+
+ mutex_lock(&data->lock);
+ lsb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_LO_LSB);
+
+ if (lsb < 0) {
+ mutex_unlock(&data->lock);
+ return lsb;
+ }
+
+ msb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_LO_MSB);
+ mutex_unlock(&data->lock);
+
+ if (msb < 0)
+ return msb;
+
+ lt = ((msb << 8) | lsb);
+
+ return lt;
+}
+
+static int isl29023_set_int_lt(struct i2c_client *client, int lt)
+{
+ int ret = 0;
+ struct isl29023_data *data = i2c_get_clientdata(client);
+
+ mutex_lock(&data->lock);
+ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_LO_LSB,
+ lt & 0xff);
+ if (ret < 0) {
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_LO_MSB,
+ (lt >> 8) & 0xff);
+ if (ret < 0) {
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ data->reg_cache[ISL29023_REG_IRQ_TH_LO_MSB] = (lt >> 8) & 0xff;
+ data->reg_cache[ISL29023_REG_IRQ_TH_LO_LSB] = lt & 0xff;
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+/*
+ * interrupt ht
+ */
+static int isl29023_get_int_ht(struct i2c_client *client)
+{
+ struct isl29023_data *data = i2c_get_clientdata(client);
+ int lsb, msb, ht;
+
+ mutex_lock(&data->lock);
+ lsb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_HI_LSB);
+
+ if (lsb < 0) {
+ mutex_unlock(&data->lock);
+ return lsb;
+ }
+
+ msb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_HI_MSB);
+ mutex_unlock(&data->lock);
+
+ if (msb < 0)
+ return msb;
+
+ ht = ((msb << 8) | lsb);
+
+ return ht;
+}
+
+static int isl29023_set_int_ht(struct i2c_client *client, int ht)
+{
+ int ret = 0;
+ struct isl29023_data *data = i2c_get_clientdata(client);
+
+ mutex_lock(&data->lock);
+ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_HI_LSB,
+ ht & 0xff);
+ if (ret < 0) {
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_HI_MSB,
+ (ht >> 8) & 0xff);
+ if (ret < 0) {
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ data->reg_cache[ISL29023_REG_IRQ_TH_HI_MSB] = (ht >> 8) & 0xff;
+ data->reg_cache[ISL29023_REG_IRQ_TH_HI_LSB] = ht & 0xff;
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+/*
+ * range
+ */
+static int isl29023_get_range(struct i2c_client *client)
+{
+ return __isl29023_read_reg(client, ISL29023_COMMAND2,
+ ISL29023_RANGE_MASK, ISL29023_RANGE_SHIFT);
+}
+
+static int isl29023_set_range(struct i2c_client *client, int range)
+{
+ return __isl29023_write_reg(client, ISL29023_COMMAND2,
+ ISL29023_RANGE_MASK, ISL29023_RANGE_SHIFT, range);
+}
+
+/*
+ * resolution
+ */
+static int isl29023_get_resolution(struct i2c_client *client)
+{
+ return __isl29023_read_reg(client, ISL29023_COMMAND2,
+ ISL29023_RES_MASK, ISL29023_RES_SHIFT);
+}
+
+static int isl29023_set_resolution(struct i2c_client *client, int res)
+{
+ return __isl29023_write_reg(client, ISL29023_COMMAND2,
+ ISL29023_RES_MASK, ISL29023_RES_SHIFT, res);
+}
+
+/*
+ * mode
+ */
+static int isl29023_get_mode(struct i2c_client *client)
+{
+ return __isl29023_read_reg(client, ISL29023_COMMAND1,
+ ISL29023_MODE_MASK, ISL29023_MODE_SHIFT);
+}
+
+static int isl29023_set_mode(struct i2c_client *client, int mode)
+{
+ return __isl29023_write_reg(client, ISL29023_COMMAND1,
+ ISL29023_MODE_MASK, ISL29023_MODE_SHIFT, mode);
+}
+
+/*
+ * power_state
+ */
+static int isl29023_set_power_state(struct i2c_client *client, int state)
+{
+ return __isl29023_write_reg(client, ISL29023_COMMAND1,
+ ISL29023_MODE_MASK, ISL29023_MODE_SHIFT,
+ state ?
+ ISL29023_ALS_ONCE_MODE : ISL29023_PD_MODE);
+}
+
+static int isl29023_get_power_state(struct i2c_client *client)
+{
+ struct isl29023_data *data = i2c_get_clientdata(client);
+ u8 cmdreg = data->reg_cache[ISL29023_COMMAND1];
+
+ if (cmdreg & ISL29023_MODE_MASK)
+ return 1;
+ else
+ return 0;
+}
+
+static int isl29023_get_adc_value(struct i2c_client *client)
+{
+ struct isl29023_data *data = i2c_get_clientdata(client);
+ int lsb, msb, range, bitdepth;
+
+ mutex_lock(&data->lock);
+ lsb = i2c_smbus_read_byte_data(client, ISL29023_REG_LSB_SENSOR);
+
+ if (lsb < 0) {
+ mutex_unlock(&data->lock);
+ return lsb;
+ }
+
+ msb = i2c_smbus_read_byte_data(client, ISL29023_REG_MSB_SENSOR);
+ mutex_unlock(&data->lock);
+
+ if (msb < 0)
+ return msb;
+
+ range = isl29023_get_range(client);
+ bitdepth = (4 - isl29023_get_resolution(client)) * 4;
+ return (((msb << 8) | lsb) * ((gain_range[range] * 499) / data->rext))
+ >> bitdepth;
+}
+
+static int isl29023_get_int_lt_value(struct i2c_client *client)
+{
+ struct isl29023_data *data = i2c_get_clientdata(client);
+ int lsb, msb, range, bitdepth;
+
+ mutex_lock(&data->lock);
+ lsb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_LO_LSB);
+
+ if (lsb < 0) {
+ mutex_unlock(&data->lock);
+ return lsb;
+ }
+
+ msb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_LO_MSB);
+ mutex_unlock(&data->lock);
+
+ if (msb < 0)
+ return msb;
+
+ range = isl29023_get_range(client);
+ bitdepth = (4 - isl29023_get_resolution(client)) * 4;
+ return (((msb << 8) | lsb) * ((gain_range[range] * 499) / data->rext))
+ >> bitdepth;
+}
+
+static int isl29023_get_int_ht_value(struct i2c_client *client)
+{
+ struct isl29023_data *data = i2c_get_clientdata(client);
+ int lsb, msb, range, bitdepth;
+
+ mutex_lock(&data->lock);
+ lsb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_HI_LSB);
+
+ if (lsb < 0) {
+ mutex_unlock(&data->lock);
+ return lsb;
+ }
+
+ msb = i2c_smbus_read_byte_data(client, ISL29023_REG_IRQ_TH_HI_MSB);
+ mutex_unlock(&data->lock);
+
+ if (msb < 0)
+ return msb;
+
+ range = isl29023_get_range(client);
+ bitdepth = (4 - isl29023_get_resolution(client)) * 4;
+ return (((msb << 8) | lsb) * ((gain_range[range] * 499) / data->rext))
+ >> bitdepth;
+}
+
+/*
+ * sysfs layer
+ */
+
+/*
+ * interrupt persists
+ */
+static ssize_t isl29023_show_int_persists(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ return sprintf(buf, "%i\n", isl29023_get_int_persists(client));
+}
+
+static ssize_t isl29023_store_int_persists(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned long val;
+ int ret;
+
+ if ((kstrtoul(buf, 10, &val) < 0) ||
+ (val > ISL29023_INT_PERSISTS_16))
+ return -EINVAL;
+
+ ret = isl29023_set_int_persists(client, val);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(int_persists, S_IWUSR | S_IRUGO,
+ isl29023_show_int_persists, isl29023_store_int_persists);
+
+/*
+ *interrupt flag
+ */
+static ssize_t isl29023_show_int_flag(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ return sprintf(buf, "%i\n", isl29023_get_int_flag(client));
+}
+
+static ssize_t isl29023_store_int_flag(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned long val;
+ int ret;
+
+ if ((kstrtoul(buf, 10, &val) < 0) || (val > 1))
+ return -EINVAL;
+
+ ret = isl29023_set_int_flag(client, val);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(int_flag, S_IWUSR | S_IRUGO,
+ isl29023_show_int_flag, isl29023_store_int_flag);
+
+/*
+ * interrupt lt
+ */
+static ssize_t isl29023_show_int_lt(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ return sprintf(buf, "%i\n", isl29023_get_int_lt(client));
+}
+
+static ssize_t isl29023_store_int_lt(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned long val;
+ int ret;
+
+ if ((kstrtoul(buf, 16, &val) < 0) || (val > 0xffff))
+ return -EINVAL;
+
+ ret = isl29023_set_int_lt(client, val);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(int_lt, S_IWUSR | S_IRUGO,
+ isl29023_show_int_lt, isl29023_store_int_lt);
+
+/*
+ *interrupt ht
+ */
+static ssize_t isl29023_show_int_ht(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ return sprintf(buf, "%i\n", isl29023_get_int_ht(client));
+}
+
+static ssize_t isl29023_store_int_ht(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned long val;
+ int ret;
+
+ if ((kstrtoul(buf, 16, &val) < 0) || (val > 0xffff))
+ return -EINVAL;
+
+ ret = isl29023_set_int_ht(client, val);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(int_ht, S_IWUSR | S_IRUGO,
+ isl29023_show_int_ht, isl29023_store_int_ht);
+
+/*
+ * range
+ */
+static ssize_t isl29023_show_range(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ return sprintf(buf, "%i\n", isl29023_get_range(client));
+}
+
+static ssize_t isl29023_store_range(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned long val;
+ int ret;
+
+ if ((kstrtoul(buf, 10, &val) < 0) || (val > ISL29023_RANGE_64K))
+ return -EINVAL;
+
+ ret = isl29023_set_range(client, val);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(range, S_IWUSR | S_IRUGO,
+ isl29023_show_range, isl29023_store_range);
+
+
+/*
+ * resolution
+ */
+static ssize_t isl29023_show_resolution(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ return sprintf(buf, "%d\n", isl29023_get_resolution(client));
+}
+
+static ssize_t isl29023_store_resolution(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned long val;
+ int ret;
+
+ if ((kstrtoul(buf, 10, &val) < 0) || (val > ISL29023_RES_4))
+ return -EINVAL;
+
+ ret = isl29023_set_resolution(client, val);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(resolution, S_IWUSR | S_IRUGO,
+ isl29023_show_resolution, isl29023_store_resolution);
+
+/*
+ *mode
+ */
+static ssize_t isl29023_show_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ return sprintf(buf, "%d\n", isl29023_get_mode(client));
+}
+
+static ssize_t isl29023_store_mode(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned long val;
+ int ret;
+
+ if ((kstrtoul(buf, 10, &val) < 0) ||
+ (val > ISL29023_IR_CONT_MODE))
+ return -EINVAL;
+
+ /* clear the interrupt flag */
+ i2c_smbus_read_byte_data(client, ISL29023_COMMAND1);
+ ret = isl29023_set_mode(client, val);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO,
+ isl29023_show_mode, isl29023_store_mode);
+
+
+/*
+ *power state
+ */
+static ssize_t isl29023_show_power_state(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ return sprintf(buf, "%d\n", isl29023_get_power_state(client));
+}
+
+static ssize_t isl29023_store_power_state(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned long val;
+ int ret;
+
+ if ((kstrtoul(buf, 10, &val) < 0) || (val > 1))
+ return -EINVAL;
+
+ ret = isl29023_set_power_state(client, val);
+ return ret ? ret : count;
+}
+
+static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
+ isl29023_show_power_state, isl29023_store_power_state);
+
+/*
+ * lux
+ */
+static ssize_t isl29023_show_lux(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ /* No LUX data if not operational */
+ if (!isl29023_get_power_state(client))
+ return -EBUSY;
+
+ return sprintf(buf, "%d\n", isl29023_get_adc_value(client));
+}
+
+static DEVICE_ATTR(lux, S_IRUGO, isl29023_show_lux, NULL);
+
+/*
+ * lux interrupt low threshold
+ */
+static ssize_t isl29023_show_int_lt_lux(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ /* No LUX data if not operational */
+ if (isl29023_get_mode(client) != ISL29023_ALS_ONCE_MODE &&
+ isl29023_get_mode(client) != ISL29023_ALS_CONT_MODE)
+ return -EIO;
+
+ return sprintf(buf, "%d\n", isl29023_get_int_lt_value(client));
+}
+
+static ssize_t isl29023_store_int_lt_lux(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct isl29023_data *data = i2c_get_clientdata(client);
+ unsigned long val, lux_data;
+ int range, bitdepth, ret;
+ u8 lsb, msb;
+
+ if ((kstrtoul(buf, 10, &val) < 0))
+ return -EINVAL;
+
+ /* No LUX data if not operational */
+ if (isl29023_get_mode(client) != ISL29023_ALS_ONCE_MODE &&
+ isl29023_get_mode(client) != ISL29023_ALS_CONT_MODE)
+ return -EIO;
+
+ if (val > (gain_range[isl29023_get_range(client)]*499/data->rext))
+ return -EINVAL;
+
+ range = isl29023_get_range(client);
+ bitdepth = (4 - isl29023_get_resolution(client)) * 4;
+ lux_data = ((unsigned long)(val << bitdepth)) /
+ ((gain_range[range] * 499) / data->rext);
+ lux_data &= 0xffff;
+
+ msb = lux_data >> 8;
+ lsb = lux_data & 0xff;
+
+ mutex_lock(&data->lock);
+ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_LO_LSB,
+ lsb);
+ if (ret < 0) {
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_LO_MSB,
+ msb);
+ if (ret < 0) {
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ data->reg_cache[ISL29023_REG_IRQ_TH_LO_MSB] = msb;
+ data->reg_cache[ISL29023_REG_IRQ_TH_LO_LSB] = lsb;
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static DEVICE_ATTR(int_lt_lux, S_IWUSR | S_IRUGO,
+ isl29023_show_int_lt_lux, isl29023_store_int_lt_lux);
+
+/*
+ * lux interrupt high threshold
+ */
+static ssize_t isl29023_show_int_ht_lux(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ /* No LUX data if not operational */
+ if (isl29023_get_mode(client) != ISL29023_ALS_ONCE_MODE &&
+ isl29023_get_mode(client) != ISL29023_ALS_CONT_MODE)
+ return -EIO;
+
+ return sprintf(buf, "%d\n", isl29023_get_int_ht_value(client));
+}
+
+static ssize_t isl29023_store_int_ht_lux(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct isl29023_data *data = i2c_get_clientdata(client);
+ unsigned long val, lux_data;
+ int range, bitdepth, ret;
+ u8 lsb, msb;
+
+ if ((kstrtoul(buf, 10, &val) < 0))
+ return -EINVAL;
+
+ /* No LUX data if not operational */
+ if (isl29023_get_mode(client) != ISL29023_ALS_ONCE_MODE &&
+ isl29023_get_mode(client) != ISL29023_ALS_CONT_MODE)
+ return -EIO;
+
+ if (val > (gain_range[isl29023_get_range(client)]*499/data->rext))
+ return -EINVAL;
+
+ range = isl29023_get_range(client);
+ bitdepth = (4 - isl29023_get_resolution(client)) * 4;
+ lux_data = ((unsigned long)(val << bitdepth)) /
+ ((gain_range[range] * 499) / data->rext);
+ lux_data &= 0xffff;
+
+ msb = lux_data >> 8;
+ lsb = lux_data & 0xff;
+
+ mutex_lock(&data->lock);
+ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_HI_LSB,
+ lsb);
+ if (ret < 0) {
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, ISL29023_REG_IRQ_TH_HI_MSB,
+ msb);
+ if (ret < 0) {
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ data->reg_cache[ISL29023_REG_IRQ_TH_HI_MSB] = msb;
+ data->reg_cache[ISL29023_REG_IRQ_TH_HI_LSB] = lsb;
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static DEVICE_ATTR(int_ht_lux, S_IWUSR | S_IRUGO,
+ isl29023_show_int_ht_lux, isl29023_store_int_ht_lux);
+
+static struct attribute *isl29023_attributes[] = {
+ &dev_attr_int_persists.attr,
+ &dev_attr_range.attr,
+ &dev_attr_resolution.attr,
+ &dev_attr_mode.attr,
+ &dev_attr_power_state.attr,
+ &dev_attr_lux.attr,
+ &dev_attr_int_lt_lux.attr,
+ &dev_attr_int_ht_lux.attr,
+ &dev_attr_int_lt.attr,
+ &dev_attr_int_ht.attr,
+ &dev_attr_int_flag.attr,
+ NULL
+};
+
+static const struct attribute_group isl29023_attr_group = {
+ .attrs = isl29023_attributes,
+};
+
+static int isl29023_init_client(struct i2c_client *client)
+{
+ struct isl29023_data *data = i2c_get_clientdata(client);
+ int i;
+
+ /* read all the registers once to fill the cache.
+ * if one of the reads fails, we consider the init failed */
+ for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) {
+ int v = i2c_smbus_read_byte_data(client, i);
+ if (v < 0)
+ return -ENODEV;
+
+ data->reg_cache[i] = v;
+ }
+
+ /* set defaults */
+ isl29023_set_int_persists(client, ISL29023_INT_PERSISTS_8);
+ isl29023_set_int_ht(client, 0xffff);
+ isl29023_set_int_lt(client, 0x0);
+ isl29023_set_range(client, ISL29023_RANGE_16K);
+ isl29023_set_resolution(client, ISL29023_RES_16);
+ isl29023_set_mode(client, ISL29023_ALS_ONCE_MODE);
+ isl29023_set_int_flag(client, 0);
+ isl29023_set_power_state(client, 0);
+
+ return 0;
+}
+
+static void isl29023_work(struct work_struct *work)
+{
+ struct isl29023_data *data =
+ container_of(work, struct isl29023_data, work);
+ struct i2c_client *client = data->client;
+ int lux;
+
+ /* Clear interrupt flag */
+ isl29023_set_int_flag(client, 0);
+
+ data->mode_before_interrupt = isl29023_get_mode(client);
+ lux = isl29023_get_adc_value(client);
+
+ /* To clear the interrpt status */
+ isl29023_set_power_state(client, ISL29023_PD_MODE);
+ isl29023_set_mode(client, data->mode_before_interrupt);
+
+ msleep(100);
+
+ input_report_abs(data->input, ABS_MISC, lux);
+ input_sync(data->input);
+}
+
+static irqreturn_t isl29023_irq_handler(int irq, void *handle)
+{
+ struct isl29023_data *data = handle;
+ int cmd_1;
+ cmd_1 = i2c_smbus_read_byte_data(data->client, ISL29023_COMMAND1);
+ if (!(cmd_1 & ISL29023_INT_FLAG_MASK))
+ return IRQ_NONE;
+
+ queue_work(data->workqueue, &data->work);
+ return IRQ_HANDLED;
+}
+
+/*
+ * I2C layer
+ */
+static int isl29023_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct isl29023_data *data;
+ struct input_dev *input_dev;
+ int err = 0;
+ struct regulator *vdd = NULL;
+ u32 rext = 0;
+ struct device_node *of_node = client->dev.of_node;
+ struct irq_data *irq_data = irq_get_irq_data(client->irq);
+ u32 irq_flag;
+ bool shared_irq;
+
+ vdd = devm_regulator_get(&client->dev, "vdd");
+ if (!IS_ERR(vdd)) {
+ err = regulator_enable(vdd);
+ if (err) {
+ dev_err(&client->dev, "vdd set voltage error\n");
+ return err;
+ }
+ }
+
+ err = of_property_read_u32(of_node, "rext", &rext);
+ if (err)
+ rext = DEFAULT_REGISTOR_VAL;
+ shared_irq = of_property_read_bool(of_node, "shared-interrupt");
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
+ return -EIO;
+
+ data = kzalloc(sizeof(struct isl29023_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->client = client;
+ data->rext = (u16)rext;
+ snprintf(data->phys, sizeof(data->phys),
+ "%s", dev_name(&client->dev));
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->lock);
+
+ /* initialize the ISL29023 chip */
+ err = isl29023_init_client(client);
+ if (err)
+ goto exit_kfree;
+
+ /* register sysfs hooks */
+ err = sysfs_create_group(&client->dev.kobj, &isl29023_attr_group);
+ if (err)
+ goto exit_kfree;
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ err = -ENOMEM;
+ goto exit_kfree;
+ }
+
+ data->input = input_dev;
+ input_dev->name = "isl29023 light sensor";
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->phys = data->phys;
+
+ __set_bit(EV_ABS, input_dev->evbit);
+ input_set_abs_params(input_dev, ABS_MISC, 0,
+ gain_range[DEF_RANGE]*499/data->rext, 0, 0);
+
+ err = input_register_device(input_dev);
+ if (err)
+ goto exit_free_input;
+
+ irq_flag = irqd_get_trigger_type(irq_data);
+ irq_flag |= IRQF_ONESHOT;
+ if (shared_irq)
+ irq_flag |= IRQF_SHARED;
+ err = request_threaded_irq(client->irq, NULL,
+ isl29023_irq_handler, irq_flag,
+ client->dev.driver->name, data);
+ if (err < 0) {
+ dev_err(&client->dev, "failed to register irq %d!\n",
+ client->irq);
+ goto exit_free_input;
+ }
+
+ data->workqueue = create_singlethread_workqueue("isl29023");
+ INIT_WORK(&data->work, isl29023_work);
+ if (data->workqueue == NULL) {
+ dev_err(&client->dev, "couldn't create workqueue\n");
+ err = -ENOMEM;
+ goto exit_free_interrupt;
+ }
+
+ dev_info(&client->dev, "driver version %s enabled\n", DRIVER_VERSION);
+ return 0;
+
+exit_free_interrupt:
+ free_irq(client->irq, data);
+exit_free_input:
+ input_free_device(input_dev);
+exit_kfree:
+ kfree(data);
+ return err;
+}
+
+static int isl29023_remove(struct i2c_client *client)
+{
+ struct isl29023_data *data = i2c_get_clientdata(client);
+
+ cancel_work_sync(&data->work);
+ destroy_workqueue(data->workqueue);
+ free_irq(client->irq, data);
+ input_unregister_device(data->input);
+ input_free_device(data->input);
+ sysfs_remove_group(&client->dev.kobj, &isl29023_attr_group);
+ isl29023_set_power_state(client, 0);
+ kfree(i2c_get_clientdata(client));
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int isl29023_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct isl29023_data *data = i2c_get_clientdata(client);
+
+ data->mode_before_suspend = isl29023_get_mode(client);
+ return isl29023_set_power_state(client, ISL29023_PD_MODE);
+}
+
+static int isl29023_resume(struct device *dev)
+{
+ int i;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct isl29023_data *data = i2c_get_clientdata(client);
+
+ /* restore registers from cache */
+ for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++)
+ if (i2c_smbus_write_byte_data(client, i, data->reg_cache[i]))
+ return -EIO;
+
+ return isl29023_set_mode(client, data->mode_before_suspend);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(isl29023_pm_ops, isl29023_suspend, isl29023_resume);
+
+static const struct i2c_device_id isl29023_id[] = {
+ { ISL29023_DRV_NAME, 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, isl29023_id);
+
+static struct i2c_driver isl29023_driver = {
+ .driver = {
+ .name = ISL29023_DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &isl29023_pm_ops,
+ },
+ .probe = isl29023_probe,
+ .remove = isl29023_remove,
+ .id_table = isl29023_id,
+};
+
+static int __init isl29023_init(void)
+{
+ return i2c_add_driver(&isl29023_driver);
+}
+
+static void __exit isl29023_exit(void)
+{
+ i2c_del_driver(&isl29023_driver);
+}
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("ISL29023 ambient light sensor driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
+module_init(isl29023_init);
+module_exit(isl29023_exit);
diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c
index 19c73574458e..7df8e6d1f337 100644
--- a/drivers/input/misc/mma8450.c
+++ b/drivers/input/misc/mma8450.c
@@ -1,7 +1,7 @@
/*
* Driver for Freescale's 3-Axis Accelerometer MMA8450
*
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@
#include <linux/i2c.h>
#include <linux/input-polldev.h>
#include <linux/of_device.h>
+#include <linux/mutex.h>
#define MMA8450_DRV_NAME "mma8450"
@@ -51,11 +52,22 @@
#define MMA8450_CTRL_REG1 0x38
#define MMA8450_CTRL_REG2 0x39
+#define MMA8450_ID 0xC6
+#define MMA8450_WHO_AM_I 0x0F
+
+enum {
+ MODE_STANDBY = 0,
+ MODE_2G,
+ MODE_4G,
+ MODE_8G,
+};
/* mma8450 status */
struct mma8450 {
struct i2c_client *client;
struct input_polled_dev *idev;
+ struct mutex mma8450_lock;
+ u8 mode;
};
static int mma8450_read(struct mma8450 *m, unsigned off)
@@ -112,16 +124,19 @@ static void mma8450_poll(struct input_polled_dev *dev)
int ret;
u8 buf[6];
- ret = mma8450_read(m, MMA8450_STATUS);
- if (ret < 0)
- return;
+ mutex_lock(&m->mma8450_lock);
- if (!(ret & MMA8450_STATUS_ZXYDR))
+ ret = mma8450_read(m, MMA8450_STATUS);
+ if (ret < 0 || !(ret & MMA8450_STATUS_ZXYDR)) {
+ mutex_unlock(&m->mma8450_lock);
return;
+ }
ret = mma8450_read_block(m, MMA8450_OUT_X_LSB, buf, sizeof(buf));
- if (ret < 0)
+ if (ret < 0) {
+ mutex_unlock(&m->mma8450_lock);
return;
+ }
x = ((int)(s8)buf[1] << 4) | (buf[0] & 0xf);
y = ((int)(s8)buf[3] << 4) | (buf[2] & 0xf);
@@ -131,10 +146,12 @@ static void mma8450_poll(struct input_polled_dev *dev)
input_report_abs(dev->input, ABS_Y, y);
input_report_abs(dev->input, ABS_Z, z);
input_sync(dev->input);
+
+ mutex_unlock(&m->mma8450_lock);
}
/* Initialize the MMA8450 chip */
-static void mma8450_open(struct input_polled_dev *dev)
+static s32 mma8450_open(struct input_polled_dev *dev)
{
struct mma8450 *m = dev->private;
int err;
@@ -142,18 +159,20 @@ static void mma8450_open(struct input_polled_dev *dev)
/* enable all events from X/Y/Z, no FIFO */
err = mma8450_write(m, MMA8450_XYZ_DATA_CFG, 0x07);
if (err)
- return;
+ return err;
/*
* Sleep mode poll rate - 50Hz
* System output data rate - 400Hz
- * Full scale selection - Active, +/- 2G
+ * Standby mode
*/
- err = mma8450_write(m, MMA8450_CTRL_REG1, 0x01);
- if (err < 0)
- return;
-
+ err = mma8450_write(m, MMA8450_CTRL_REG1, MODE_STANDBY);
+ if (err)
+ return err;
+ m->mode = MODE_STANDBY;
msleep(MODE_CHANGE_DELAY_MS);
+
+ return 0;
}
static void mma8450_close(struct input_polled_dev *dev)
@@ -164,6 +183,76 @@ static void mma8450_close(struct input_polled_dev *dev)
mma8450_write(m, MMA8450_CTRL_REG2, 0x01);
}
+static ssize_t mma8450_scalemode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int mode = 0;
+ struct mma8450 *m;
+ struct i2c_client *client = to_i2c_client(dev);
+
+ m = i2c_get_clientdata(client);
+
+ mutex_lock(&m->mma8450_lock);
+ mode = (int)m->mode;
+ mutex_unlock(&m->mma8450_lock);
+
+ return sprintf(buf, "%d\n", mode);
+}
+
+static ssize_t mma8450_scalemode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long mode;
+ int ret;
+ struct mma8450 *m = NULL;
+ struct i2c_client *client = to_i2c_client(dev);
+
+ ret = kstrtoul(buf, 10, &mode);
+ if (ret) {
+ dev_err(dev, "string transform error\n");
+ return ret;
+ }
+
+ if (mode > MODE_8G) {
+ dev_warn(dev, "not supported mode %d\n", (int)mode);
+ return count;
+ }
+
+ m = i2c_get_clientdata(client);
+
+ mutex_lock(&m->mma8450_lock);
+ if (mode == m->mode) {
+ mutex_unlock(&m->mma8450_lock);
+ return count;
+ }
+
+ ret = mma8450_write(m, MMA8450_CTRL_REG1, mode);
+ if (ret < 0) {
+ mutex_unlock(&m->mma8450_lock);
+ return ret;
+ }
+
+ msleep(MODE_CHANGE_DELAY_MS);
+ m->mode = (u8)mode;
+ mutex_unlock(&m->mma8450_lock);
+
+ return count;
+}
+
+static DEVICE_ATTR(scalemode, S_IWUSR | S_IRUGO,
+ mma8450_scalemode_show, mma8450_scalemode_store);
+
+static struct attribute *mma8450_attributes[] = {
+ &dev_attr_scalemode.attr,
+ NULL
+};
+
+static const struct attribute_group mma8450_attr_group = {
+ .attrs = mma8450_attributes,
+};
+
/*
* I2C init/probing/exit functions
*/
@@ -172,7 +261,24 @@ static int mma8450_probe(struct i2c_client *c,
{
struct input_polled_dev *idev;
struct mma8450 *m;
- int err;
+ int err, client_id;
+ struct i2c_adapter *adapter = NULL;
+
+ adapter = to_i2c_adapter(c->dev.parent);
+ err = i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA);
+ if (!err)
+ return err;
+
+ client_id = i2c_smbus_read_byte_data(c, MMA8450_WHO_AM_I);
+
+ if (MMA8450_ID != client_id) {
+ dev_err(&c->dev,
+ "read chip ID 0x%x is not equal to 0x%x!\n", client_id,
+ MMA8450_ID);
+ return -EINVAL;
+ }
m = devm_kzalloc(&c->dev, sizeof(*m), GFP_KERNEL);
if (!m)
@@ -184,6 +290,7 @@ static int mma8450_probe(struct i2c_client *c,
m->client = c;
m->idev = idev;
+ i2c_set_clientdata(c, m);
idev->private = m;
idev->input->name = MMA8450_DRV_NAME;
@@ -191,8 +298,6 @@ static int mma8450_probe(struct i2c_client *c,
idev->poll = mma8450_poll;
idev->poll_interval = POLL_INTERVAL;
idev->poll_interval_max = POLL_INTERVAL_MAX;
- idev->open = mma8450_open;
- idev->close = mma8450_close;
__set_bit(EV_ABS, idev->input->evbit);
input_set_abs_params(idev->input, ABS_X, -2048, 2047, 32, 32);
@@ -205,7 +310,40 @@ static int mma8450_probe(struct i2c_client *c,
return err;
}
- i2c_set_clientdata(c, m);
+ mutex_init(&m->mma8450_lock);
+
+ err = mma8450_open(idev);
+ if (err) {
+ dev_err(&c->dev, "failed to initialize mma8450\n");
+ goto err_unreg_dev;
+ }
+
+ err = sysfs_create_group(&c->dev.kobj, &mma8450_attr_group);
+ if (err) {
+ dev_err(&c->dev, "create device file failed!\n");
+ err = -EINVAL;
+ goto err_close;
+ }
+
+ return 0;
+
+err_close:
+ mma8450_close(idev);
+err_unreg_dev:
+ mutex_destroy(&m->mma8450_lock);
+ input_unregister_polled_device(idev);
+ return err;
+}
+
+static int mma8450_remove(struct i2c_client *c)
+{
+ struct mma8450 *m = i2c_get_clientdata(c);
+ struct input_polled_dev *idev = m->idev;
+
+ sysfs_remove_group(&c->dev.kobj, &mma8450_attr_group);
+ mma8450_close(idev);
+ mutex_destroy(&m->mma8450_lock);
+ input_unregister_polled_device(idev);
return 0;
}
@@ -228,6 +366,7 @@ static struct i2c_driver mma8450_driver = {
.of_match_table = mma8450_dt_ids,
},
.probe = mma8450_probe,
+ .remove = mma8450_remove,
.id_table = mma8450_id,
};
diff --git a/drivers/input/misc/mpl3115.c b/drivers/input/misc/mpl3115.c
new file mode 100644
index 000000000000..4bd5420e4e93
--- /dev/null
+++ b/drivers/input/misc/mpl3115.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2010-2015 Freescale , Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/pm.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/input-polldev.h>
+
+#define MPL3115_DRV_NAME "mpl3115"
+#define ABS_TEMPTERAURE ABS_MISC
+
+#define INPUT_FUZZ 32
+#define INPUT_FLAT 32
+#define MPL_ACTIVED 1
+#define MPL_STANDBY 0
+#define POLL_INTERVAL_MAX 500
+#define POLL_INTERVAL 100
+#define POLL_INTERVAL_MIN 1
+#define MPL3115_ID 0xc4
+#define MPLL_ACTIVE_MASK 0x01
+#define MPL3115_STATUS_DR 0x08
+
+/* MPL3115A register address */
+#define MPL3115_STATUS 0x00
+#define MPL3115_PRESSURE_DATA 0x01
+#define MPL3115_DR_STATUS 0x06
+#define MPL3115_DELTA_DATA 0x07
+#define MPL3115_WHO_AM_I 0x0c
+#define MPL3115_FIFO_STATUS 0x0d
+#define MPL3115_FIFO_DATA 0x0e
+#define MPL3115_FIFO_SETUP 0x0e
+#define MPL3115_TIME_DELAY 0x10
+#define MPL3115_SYS_MODE 0x11
+#define MPL3115_INT_SORCE 0x12
+#define MPL3115_PT_DATA_CFG 0x13
+#define MPL3115_BAR_IN_MSB 0x14
+#define MPL3115_P_ARLARM_MSB 0x16
+#define MPL3115_T_ARLARM 0x18
+#define MPL3115_P_ARLARM_WND_MSB 0x19
+#define MPL3115_T_ARLARM_WND 0x1b
+#define MPL3115_P_MIN_DATA 0x1c
+#define MPL3115_T_MIN_DATA 0x1f
+#define MPL3115_P_MAX_DATA 0x21
+#define MPL3115_T_MAX_DATA 0x24
+#define MPL3115_CTRL_REG1 0x26
+#define MPL3115_CTRL_REG2 0x27
+#define MPL3115_CTRL_REG3 0x28
+#define MPL3115_CTRL_REG4 0x29
+#define MPL3115_CTRL_REG5 0x2a
+#define MPL3115_OFFSET_P 0x2b
+#define MPL3115_OFFSET_T 0x2c
+#define MPL3115_OFFSET_H 0x2d
+
+#define DATA_SHIFT_BIT(data, bit) ((data << bit) & (0xff << bit))
+
+struct mpl3115_data {
+ struct i2c_client *client;
+ struct input_polled_dev *poll_dev;
+ struct mutex data_lock;
+ int active;
+};
+
+static int mpl3115_i2c_read(struct i2c_client *client, u8 reg, u8 *values, u8 length)
+{
+ return i2c_smbus_read_i2c_block_data(client, reg, length, values);
+}
+
+static int mpl3115_i2c_write(struct i2c_client *client, u8 reg, const u8 *values, u8 length)
+{
+ return i2c_smbus_write_i2c_block_data(client, reg, length, values);
+}
+
+static ssize_t mpl3115_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int val;
+ u8 sysmode;
+
+ struct input_polled_dev *poll_dev = dev_get_drvdata(dev);
+ struct mpl3115_data *pdata = (struct mpl3115_data *)(poll_dev->private);
+ struct i2c_client *client = pdata->client;
+ mutex_lock(&pdata->data_lock);
+ mpl3115_i2c_read(client, MPL3115_CTRL_REG1, &sysmode, 1);
+ sysmode &= MPLL_ACTIVE_MASK;
+ val = (sysmode ? 1 : 0);
+ mutex_unlock(&pdata->data_lock);
+
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t mpl3115_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret, enable;
+ u8 val;
+ struct input_polled_dev *poll_dev = dev_get_drvdata(dev);
+ struct mpl3115_data *pdata = (struct mpl3115_data *)(poll_dev->private);
+ struct i2c_client *client = pdata->client;
+
+ enable = simple_strtoul(buf, NULL, 10);
+ mutex_lock(&pdata->data_lock);
+ mpl3115_i2c_read(client, MPL3115_CTRL_REG1, &val, 1);
+ if (enable && pdata->active == MPL_STANDBY) {
+ val |= MPLL_ACTIVE_MASK;
+ ret = mpl3115_i2c_write(client, MPL3115_CTRL_REG1, &val, 1);
+ if (!ret)
+ pdata->active = MPL_ACTIVED;
+ printk("mpl3115 set active\n");
+ } else if (!enable && pdata->active == MPL_ACTIVED) {
+ val &= ~MPLL_ACTIVE_MASK;
+ ret = mpl3115_i2c_write(client, MPL3115_CTRL_REG1, &val, 1);
+ if (!ret)
+ pdata->active = MPL_STANDBY;
+ printk("mpl3115 set inactive\n");
+ }
+ mutex_unlock(&pdata->data_lock);
+
+ return count;
+}
+
+static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, mpl3115_enable_show, mpl3115_enable_store);
+
+static struct attribute *mpl3115_attributes[] = {
+ &dev_attr_enable.attr,
+ NULL
+};
+
+static const struct attribute_group mpl3115_attr_group = {
+ .attrs = mpl3115_attributes,
+};
+
+static void mpl3115_device_init(struct i2c_client *client)
+{
+ u8 val[8];
+ struct device_node *np = client->dev.of_node;
+
+ /* set interrupt pin as open-drain */
+ if (of_get_property(np, "interrupt-open-drain", NULL)) {
+ val[0] = 0x11;
+ mpl3115_i2c_write(client, MPL3115_CTRL_REG3, val, 1);
+ }
+
+ val[0] = 0x28;
+ mpl3115_i2c_write(client, MPL3115_CTRL_REG1, val, 1);
+}
+
+static int mpl3115_read_data(struct i2c_client *client, int *pres, short *temp)
+{
+ u8 tmp[5];
+
+ mpl3115_i2c_read(client, MPL3115_PRESSURE_DATA, tmp, 5);
+ *pres = (DATA_SHIFT_BIT(tmp[0], 24) | DATA_SHIFT_BIT(tmp[1], 16) | DATA_SHIFT_BIT(tmp[2], 8)) >> 12;
+ *temp = (DATA_SHIFT_BIT(tmp[3], 8) | DATA_SHIFT_BIT(tmp[4], 0)) >> 4;
+ return 0;
+}
+
+static void report_abs(struct mpl3115_data *pdata)
+{
+ struct input_dev *idev;
+ int pressure = 0;
+ short temperature = 0;
+
+ mutex_lock(&pdata->data_lock);
+ if (pdata->active == MPL_STANDBY)
+ goto out;
+ idev = pdata->poll_dev->input;
+ mpl3115_read_data(pdata->client, &pressure, &temperature);
+ input_report_abs(idev, ABS_PRESSURE, pressure);
+ input_report_abs(idev, ABS_TEMPTERAURE, temperature);
+ input_sync(idev);
+out:
+ mutex_unlock(&pdata->data_lock);
+}
+
+static void mpl3115_dev_poll(struct input_polled_dev *dev)
+{
+ struct mpl3115_data *pdata = (struct mpl3115_data *)dev->private;
+
+ report_abs(pdata);
+}
+
+static int mpl3115_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int result, client_id;
+ struct input_dev *idev;
+ struct i2c_adapter *adapter;
+ struct mpl3115_data *pdata;
+
+ adapter = to_i2c_adapter(client->dev.parent);
+ result = i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA);
+ if (!result)
+ goto err_out;
+
+ client_id = i2c_smbus_read_byte_data(client, MPL3115_WHO_AM_I);
+ printk("read mpl3115 chip id 0x%x\n", client_id);
+ if (client_id != MPL3115_ID) {
+ dev_err(&client->dev,
+ "read chip ID 0x%x is not equal to 0x%x!\n",
+ result, MPL3115_ID);
+ result = -EINVAL;
+ goto err_out;
+ }
+ pdata = kzalloc(sizeof(struct mpl3115_data), GFP_KERNEL);
+ if (!pdata)
+ goto err_out;
+ pdata->client = client;
+ i2c_set_clientdata(client, pdata);
+ mutex_init(&pdata->data_lock);
+ pdata->poll_dev = input_allocate_polled_device();
+ if (!pdata->poll_dev) {
+ result = -ENOMEM;
+ dev_err(&client->dev, "alloc poll device failed!\n");
+ goto err_alloc_data;
+ }
+ pdata->poll_dev->poll = mpl3115_dev_poll;
+ pdata->poll_dev->private = pdata;
+ pdata->poll_dev->poll_interval = POLL_INTERVAL;
+ pdata->poll_dev->poll_interval_min = POLL_INTERVAL_MIN;
+ pdata->poll_dev->poll_interval_max = POLL_INTERVAL_MAX;
+ idev = pdata->poll_dev->input;
+ idev->name = MPL3115_DRV_NAME;
+ idev->id.bustype = BUS_I2C;
+ idev->evbit[0] = BIT_MASK(EV_ABS);
+
+ input_set_abs_params(idev, ABS_PRESSURE, -0x7FFFFFFF, 0x7FFFFFFF, 0, 0);
+ input_set_abs_params(idev, ABS_TEMPTERAURE, -0x7FFFFFFF, 0x7FFFFFFF, 0, 0);
+ result = input_register_polled_device(pdata->poll_dev);
+ if (result) {
+ dev_err(&client->dev, "register poll device failed!\n");
+ goto error_free_poll_dev;
+ }
+ result = sysfs_create_group(&idev->dev.kobj, &mpl3115_attr_group);
+ if (result) {
+ dev_err(&client->dev, "create device file failed!\n");
+ result = -EINVAL;
+ goto error_register_polled_device;
+ }
+ mpl3115_device_init(client);
+ printk("mpl3115 device driver probe successfully");
+ return 0;
+error_register_polled_device:
+ input_unregister_polled_device(pdata->poll_dev);
+error_free_poll_dev:
+ input_free_polled_device(pdata->poll_dev);
+err_alloc_data:
+ kfree(pdata);
+err_out:
+ return result;
+}
+
+static int mpl3115_stop_chip(struct i2c_client *client)
+{
+ u8 val;
+ int ret;
+
+ mpl3115_i2c_read(client, MPL3115_CTRL_REG1, &val, 1);
+ val &= ~MPLL_ACTIVE_MASK;
+ ret = mpl3115_i2c_write(client, MPL3115_CTRL_REG1, &val, 1);
+
+ return 0;
+}
+static int mpl3115_start_chip(struct i2c_client *client)
+{
+ u8 val;
+ int ret;
+
+ mpl3115_i2c_read(client, MPL3115_CTRL_REG1, &val, 1);
+ val |= MPLL_ACTIVE_MASK;
+ ret = mpl3115_i2c_write(client, MPL3115_CTRL_REG1, &val, 1);
+
+ return 0;
+}
+static int mpl3115_remove(struct i2c_client *client)
+{
+ struct mpl3115_data *pdata = i2c_get_clientdata(client);
+ struct input_dev *idev = pdata->poll_dev->input;
+
+ mpl3115_stop_chip(client);
+ sysfs_remove_group(&idev->dev.kobj, &mpl3115_attr_group);
+ input_unregister_polled_device(pdata->poll_dev);
+ kfree(pdata);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mpl3115_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mpl3115_data *pdata = i2c_get_clientdata(client);
+ if (pdata->active == MPL_ACTIVED)
+ mpl3115_stop_chip(client);
+ return 0;
+}
+
+static int mpl3115_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mpl3115_data *pdata = i2c_get_clientdata(client);
+ if (pdata->active == MPL_ACTIVED)
+ mpl3115_start_chip(client);
+ return 0;
+}
+#endif
+
+static const struct i2c_device_id mpl3115_id[] = {
+ {MPL3115_DRV_NAME, 0},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, mpl3115_id);
+
+static SIMPLE_DEV_PM_OPS(mpl3115_pm_ops, mpl3115_suspend, mpl3115_resume);
+static struct i2c_driver mpl3115_driver = {
+ .driver = {
+ .name = MPL3115_DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &mpl3115_pm_ops,
+ },
+ .probe = mpl3115_probe,
+ .remove = mpl3115_remove,
+ .id_table = mpl3115_id,
+};
+
+module_i2c_driver(mpl3115_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MPL3115 Smart Pressure Sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/rpmsg_input.c b/drivers/input/misc/rpmsg_input.c
new file mode 100644
index 000000000000..8f3d07b59ef0
--- /dev/null
+++ b/drivers/input/misc/rpmsg_input.c
@@ -0,0 +1,528 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/imx_rpmsg.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+#include <linux/rpmsg.h>
+#include <linux/uaccess.h>
+#include <linux/virtio.h>
+
+#define RPMSG_INPUT_DEV_STANDBY 0x00
+#define RPMSG_INPUT_DEV_ACTIVED 0x01
+#define DETECTOR_DEVICE "step_detector"
+#define COUNTER_DEVICE "step_counter"
+
+#define PEDOMETER_TYPE 0x0
+#define PEDOMETER_IDX 0x0
+
+#define RPMSG_TIMEOUT 1000
+
+enum rpmsg_input_header_type {
+ RPMSG_INPUT_SETUP,
+ RPMSG_INPUT_REPLY,
+ RPMSG_INPUT_NOTIFY,
+};
+
+enum rpmsg_input_header_cmd {
+ RPMSG_INPUT_DETECTOR_CMD,
+ RPMSG_INPUT_COUNTER_CMD,
+ RPMSG_INPUT_POLL_DELAY_CMD,
+};
+
+struct rpmsg_input_msg {
+ struct imx_rpmsg_head header;
+ u8 sensor_type;
+ u8 sensor_index;
+ union {
+ union {
+ u8 enable;
+ u8 retcode;
+ } inout;
+
+ u32 val;
+ } instruct;
+} __packed __aligned(8);
+
+struct rpmsg_input_data {
+ struct device *dev;
+ struct miscdevice *detector_miscdev;
+ struct miscdevice *counter_miscdev;
+ struct input_dev *detector_input;
+ struct input_dev *counter_input;
+ atomic_t detector_active;
+ atomic_t counter_active;
+ atomic_t counter_delay;
+
+ struct rpmsg_device *rpdev;
+ struct rpmsg_input_msg *reply_msg;
+ struct rpmsg_input_msg *notify_msg;
+ struct pm_qos_request pm_qos_req;
+ struct completion cmd_complete;
+ struct mutex lock;
+};
+
+static struct rpmsg_input_data *input_rpmsg;
+
+static int input_send_message(struct rpmsg_input_msg *msg,
+ struct rpmsg_input_data *info)
+{
+ int err;
+
+ if (!info->rpdev) {
+ dev_dbg(info->dev,
+ "rpmsg channel not ready, m4 image ready?\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&info->lock);
+ pm_qos_add_request(&info->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, 0);
+
+ reinit_completion(&info->cmd_complete);
+
+ err = rpmsg_send(info->rpdev->ept, (void *)msg,
+ sizeof(struct rpmsg_input_msg));
+ if (err) {
+ dev_err(&info->rpdev->dev, "rpmsg_send failed: %d\n", err);
+ goto err_out;
+ }
+
+ err = wait_for_completion_timeout(&info->cmd_complete,
+ msecs_to_jiffies(RPMSG_TIMEOUT));
+ if (!err) {
+ dev_err(&info->rpdev->dev, "rpmsg_send timeout!\n");
+ err = -ETIMEDOUT;
+ goto err_out;
+ }
+
+ err = info->reply_msg->instruct.inout.retcode;
+ if (err != 0) {
+ dev_err(&info->rpdev->dev, "rpmsg not ack %d!\n", err);
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ err = 0;
+
+err_out:
+ pm_qos_remove_request(&info->pm_qos_req);
+ mutex_unlock(&info->lock);
+
+ return err;
+}
+
+static inline void rpmsg_input_evt_report(struct rpmsg_input_msg *msg)
+{
+ int val = 0x1;
+
+ if (msg->header.cmd == RPMSG_INPUT_DETECTOR_CMD) {
+ input_report_rel(input_rpmsg->detector_input, REL_MISC, val);
+ input_sync(input_rpmsg->detector_input);
+ } else if (msg->header.cmd == RPMSG_INPUT_COUNTER_CMD) {
+ val = msg->instruct.val;
+ input_report_abs(input_rpmsg->counter_input, ABS_MISC, val);
+ input_sync(input_rpmsg->counter_input);
+ }
+}
+
+static int rpmsg_input_cb(struct rpmsg_device *rpdev,
+ void *data, int len, void *priv, u32 src)
+{
+ struct rpmsg_input_msg *msg = (struct rpmsg_input_msg *)data;
+
+ if (msg->header.type == RPMSG_INPUT_REPLY) {
+ input_rpmsg->reply_msg = msg;
+ complete(&input_rpmsg->cmd_complete);
+ return 0;
+ } else if (msg->header.type == RPMSG_INPUT_NOTIFY) {
+ input_rpmsg->notify_msg = msg;
+ rpmsg_input_evt_report(msg);
+ } else
+ dev_err(&input_rpmsg->rpdev->dev, "wrong command type!\n");
+
+ return 0;
+}
+
+static int rpmsg_input_probe(struct rpmsg_device *rpdev)
+{
+ input_rpmsg->rpdev = rpdev;
+
+ dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
+ rpdev->src, rpdev->dst);
+
+ init_completion(&input_rpmsg->cmd_complete);
+ mutex_init(&input_rpmsg->lock);
+
+ return 0;
+}
+
+static struct rpmsg_device_id rpmsg_input_id_table[] = {
+ { .name = "rpmsg-sensor-channel" },
+ { },
+};
+
+static struct rpmsg_driver rpmsg_input_driver = {
+ .drv.name = "input_rpmsg",
+ .drv.owner = THIS_MODULE,
+ .id_table = rpmsg_input_id_table,
+ .probe = rpmsg_input_probe,
+ .callback = rpmsg_input_cb,
+};
+
+static int rpmsg_input_open(struct inode *inode, struct file *file)
+{
+ file->private_data = input_rpmsg;
+ return nonseekable_open(inode, file);
+}
+
+static int rpmsg_input_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static long
+rpmsg_input_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ /* TBD: for future sensor interfaces support */
+ return 0;
+}
+
+static const struct file_operations rpmsg_input_fops = {
+ .owner = THIS_MODULE,
+ .open = rpmsg_input_open,
+ .release = rpmsg_input_release,
+ .unlocked_ioctl = rpmsg_input_ioctl,
+};
+
+static struct miscdevice step_detector_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "step_detector",
+ .fops = &rpmsg_input_fops,
+};
+
+static struct miscdevice step_counter_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "step_counter",
+ .fops = &rpmsg_input_fops,
+};
+
+static int rpmsg_input_change_mode(int cmd, int enable)
+{
+
+ struct rpmsg_input_msg msg;
+
+ memset(&msg, 0, sizeof(struct rpmsg_input_msg));
+ msg.header.cate = IMX_RPMSG_SENSOR;
+ msg.header.major = IMX_RMPSG_MAJOR;
+ msg.header.minor = IMX_RMPSG_MINOR;
+ msg.header.type = RPMSG_INPUT_SETUP;
+ msg.header.cmd = cmd;
+ msg.sensor_type = PEDOMETER_TYPE;
+ msg.sensor_index = PEDOMETER_IDX;
+ msg.instruct.inout.enable = enable;
+
+ return input_send_message(&msg, input_rpmsg);
+}
+
+static int rpmsg_input_set_poll_delay(int cmd, int delay)
+{
+ struct rpmsg_input_msg msg;
+
+ memset(&msg, 0, sizeof(struct rpmsg_input_msg));
+ msg.header.cate = IMX_RPMSG_SENSOR;
+ msg.header.major = IMX_RMPSG_MAJOR;
+ msg.header.minor = IMX_RMPSG_MINOR;
+ msg.header.type = RPMSG_INPUT_SETUP;
+ msg.header.cmd = cmd;
+ msg.sensor_type = PEDOMETER_TYPE;
+ msg.sensor_index = PEDOMETER_IDX;
+ msg.instruct.val = delay;
+
+ return input_send_message(&msg, input_rpmsg);
+}
+
+static ssize_t rpmsg_input_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct miscdevice *misc_dev = dev_get_drvdata(dev);
+ struct rpmsg_input_data *pdata = input_rpmsg;
+ int enable = 0;
+
+ if (pdata->detector_miscdev == misc_dev)
+ enable = atomic_read(&pdata->detector_active);
+ if (pdata->counter_miscdev == misc_dev)
+ enable = atomic_read(&pdata->counter_active);
+
+ return sprintf(buf, "%d\n", enable);
+}
+
+static ssize_t rpmsg_input_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct miscdevice *misc_dev = dev_get_drvdata(dev);
+ struct rpmsg_input_data *pdata = input_rpmsg;
+ unsigned long enable;
+ int cmd;
+ int ret;
+
+ if (kstrtoul(buf, 10, &enable) < 0)
+ return -EINVAL;
+
+ if (misc_dev == pdata->detector_miscdev)
+ cmd = RPMSG_INPUT_DETECTOR_CMD;
+ if (misc_dev == pdata->counter_miscdev)
+ cmd = RPMSG_INPUT_COUNTER_CMD;
+
+ enable = enable > 0 ? RPMSG_INPUT_DEV_ACTIVED :
+ RPMSG_INPUT_DEV_STANDBY;
+ ret = rpmsg_input_change_mode(cmd, enable);
+ if (!ret) {
+ if (cmd == RPMSG_INPUT_DETECTOR_CMD)
+ atomic_set(&pdata->detector_active, enable);
+ else if (cmd == RPMSG_INPUT_COUNTER_CMD)
+ atomic_set(&pdata->counter_active, enable);
+ }
+
+ return count;
+}
+
+static ssize_t rpmsg_input_poll_delay_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct miscdevice *misc_dev = dev_get_drvdata(dev);
+ struct rpmsg_input_data *pdata = input_rpmsg;
+ int poll_delay = 0;
+
+ if (pdata->detector_miscdev == misc_dev)
+ return -ENOTSUPP;
+
+ if (pdata->counter_miscdev == misc_dev)
+ poll_delay = atomic_read(&pdata->counter_delay);
+
+ return sprintf(buf, "%d\n", poll_delay);
+}
+
+
+static ssize_t rpmsg_input_poll_delay_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct miscdevice *misc_dev = dev_get_drvdata(dev);
+ struct rpmsg_input_data *pdata = input_rpmsg;
+ unsigned long delay;
+ int cmd;
+ int ret;
+
+ if (kstrtoul(buf, 10, &delay) < 0)
+ return -EINVAL;
+
+ if (pdata->detector_miscdev == misc_dev)
+ return -ENOTSUPP;
+
+ if (pdata->counter_miscdev == misc_dev)
+ cmd = RPMSG_INPUT_POLL_DELAY_CMD;
+
+ ret = rpmsg_input_set_poll_delay(cmd, delay);
+ if (!ret) {
+ if (cmd == RPMSG_INPUT_POLL_DELAY_CMD)
+ atomic_set(&pdata->counter_delay, delay);
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO,
+ rpmsg_input_enable_show,
+ rpmsg_input_enable_store);
+static DEVICE_ATTR(poll_delay, S_IWUSR | S_IRUGO,
+ rpmsg_input_poll_delay_show,
+ rpmsg_input_poll_delay_store);
+
+static struct attribute *rpmsg_input_attributes[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_poll_delay.attr,
+ NULL
+};
+
+static const struct attribute_group rpmsg_input_attr_group = {
+ .attrs = rpmsg_input_attributes,
+};
+
+static int rpmsg_input_register_sysfs_device(struct rpmsg_input_data *pdata)
+{
+ struct miscdevice *misc_dev = NULL;
+ int err = 0;
+
+ /* register sysfs for detector */
+ misc_dev = pdata->detector_miscdev;
+ err = sysfs_create_group(&misc_dev->this_device->kobj,
+ &rpmsg_input_attr_group);
+ if (err)
+ goto out;
+
+ /* register sysfs for counter */
+ misc_dev = pdata->counter_miscdev;
+ err = sysfs_create_group(&misc_dev->this_device->kobj,
+ &rpmsg_input_attr_group);
+ if (err)
+ goto err_register_sysfs;
+
+ return 0;
+
+err_register_sysfs:
+ misc_dev = pdata->detector_miscdev;
+ sysfs_remove_group(&misc_dev->this_device->kobj, &rpmsg_input_attr_group);
+out:
+ return err;
+}
+
+static int rpmsg_input_device_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rpmsg_input_data *pdata;
+ struct input_dev *detector_input;
+ struct input_dev *counter_input;
+ int ret = 0;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ detector_input = devm_input_allocate_device(dev);
+ if (!detector_input) {
+ dev_err(dev, "failed to allocate detector device\n");
+ return -ENOMEM;
+ }
+
+ counter_input = devm_input_allocate_device(dev);
+ if (!counter_input) {
+ dev_err(dev, "failed to allocate counter device\n");
+ return -ENOMEM;
+ }
+
+ detector_input->name = DETECTOR_DEVICE;
+ detector_input->phys = "rpmsg-input/input0";
+ detector_input->dev.parent = &pdev->dev;
+ detector_input->id.bustype = BUS_HOST;
+ detector_input->evbit[0] = BIT_MASK(EV_REL);
+ detector_input->relbit[0] = BIT_MASK(REL_MISC);
+ pdata->detector_input = detector_input;
+
+ counter_input->name = COUNTER_DEVICE;
+ counter_input->phys = "rpmsg-input/input1";
+ counter_input->dev.parent = &pdev->dev;
+ counter_input->id.bustype = BUS_HOST;
+ counter_input->evbit[0] = BIT_MASK(EV_ABS);
+ input_set_abs_params(counter_input, ABS_MISC, 0, 0xFFFFFFFF, 0, 0);
+ pdata->counter_input = counter_input;
+
+ input_rpmsg = pdata;
+ platform_set_drvdata(pdev, pdata);
+
+ ret = misc_register(&step_detector_device);
+ if (ret != 0) {
+ dev_err(dev, "register acc miscdevice error");
+ goto err_register_detector_misc;
+ }
+ pdata->detector_miscdev = &step_detector_device;
+
+ ret = misc_register(&step_counter_device);
+ if (ret != 0) {
+ dev_err(dev, "register acc miscdevice error");
+ goto err_register_counter_misc;
+ }
+ pdata->counter_miscdev = &step_counter_device;
+
+ ret = rpmsg_input_register_sysfs_device(pdata);
+ if (ret) {
+ dev_err(dev, "Unable to register input sysfs, error: %d\n",
+ ret);
+ goto err_register_sysfs;
+ }
+
+ ret = input_register_device(detector_input);
+ if (ret) {
+ dev_err(dev, "Unable to register detector device, error: %d\n",
+ ret);
+ goto err_register_detector_input;
+ }
+
+ ret = input_register_device(counter_input);
+ if (ret) {
+ dev_err(dev, "Unable to register counter device, error: %d\n",
+ ret);
+ goto err_register_counter_input;
+ }
+
+ ret = register_rpmsg_driver(&rpmsg_input_driver);
+ if (ret) {
+ dev_err(dev, "Unable to register rpmsg driver, error: %d\n",
+ ret);
+ goto err_register_rmpsg_driver;
+ }
+
+ return ret;
+
+err_register_rmpsg_driver:
+ input_unregister_device(counter_input);
+err_register_counter_input:
+ input_unregister_device(detector_input);
+err_register_detector_input:
+err_register_sysfs:
+ misc_deregister(&step_counter_device);
+ pdata->counter_miscdev = NULL;
+err_register_counter_misc:
+ misc_deregister(&step_detector_device);
+ pdata->detector_miscdev = NULL;
+err_register_detector_misc:
+ pdata->detector_input = NULL;
+ pdata->counter_input = NULL;
+ platform_set_drvdata(pdev, NULL);
+ return ret;
+}
+
+static const struct of_device_id rpmsg_input_of_match[] = {
+ { .compatible = "fsl,rpmsg-input", },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, rpmsg_input_of_match);
+
+static struct platform_driver rpmsg_input_device_driver = {
+ .probe = rpmsg_input_device_probe,
+ .driver = {
+ .name = "rpmsg-input",
+ .of_match_table = of_match_ptr(rpmsg_input_of_match)
+ }
+};
+
+module_platform_driver(rpmsg_input_device_driver);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("NXP i.MX7ULP rpmsg sensor input driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index efca0133e266..14931da02921 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -46,6 +46,19 @@ config TOUCHSCREEN_ADS7846
To compile this driver as a module, choose M here: the
module will be called ads7846.
+config TOUCHSCREEN_CT36X_WLD
+ default y
+ tristate "CT36X based touchscreens for WLD"
+ help
+ Say Y here if you have a touchscreen interface using the
+ CT36X controller, i2c touchscreen
+ controller.
+
+ If unsure, say N (but it's safe to say "Y").
+
+ To compile this driver as a module, choose M here: the
+ module will be called vtl_ts.
+
config TOUCHSCREEN_AD7877
tristate "AD7877 based touchscreens"
depends on SPI_MASTER
@@ -314,6 +327,18 @@ config TOUCHSCREEN_EGALAX_SERIAL
To compile this driver as a module, choose M here: the
module will be called egalax_ts_serial.
+config TOUCHSCREEN_ELAN_TS
+ tristate "ELAN touchscreen input driver"
+ depends on I2C
+ help
+ Say Y here if you have an I2C ELAN touchscreen
+ attached.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called elan-touch.
+
config TOUCHSCREEN_FUJITSU
tristate "Fujitsu serial touchscreen"
select SERIO
@@ -1214,4 +1239,7 @@ config TOUCHSCREEN_ROHM_BU21023
To compile this driver as a module, choose M here: the
module will be called bu21023_ts.
+source "drivers/input/touchscreen/synaptics_dsx/Kconfig"
endif
+
+source "drivers/input/touchscreen/focaltech_touch/Kconfig"
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 81b86451782d..d9a53317f05a 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -35,8 +35,11 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
obj-$(CONFIG_TOUCHSCREEN_EKTF2127) += ektf2127.o
obj-$(CONFIG_TOUCHSCREEN_ELAN) += elants_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
+obj-$(CONFIG_TOUCHSCREEN_ELAN_TS) += elan_ts.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o
+obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_touch/
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX) += synaptics_dsx/
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
@@ -96,6 +99,7 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_SX8654) += sx8654.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
+obj-$(CONFIG_TOUCHSCREEN_CT36X_WLD) += vtl/
obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o
obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o
obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 1ce3ecbe37f8..fc21a7459e3e 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -1188,6 +1188,7 @@ static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev)
struct ads7846_platform_data *pdata;
struct device_node *node = dev->of_node;
const struct of_device_id *match;
+ int ret;
if (!node) {
dev_err(dev, "Device does not have associated DT data\n");
@@ -1233,8 +1234,11 @@ static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev)
of_property_read_u16(node, "ti,debounce-tol", &pdata->debounce_tol);
of_property_read_u16(node, "ti,debounce-rep", &pdata->debounce_rep);
- of_property_read_u32(node, "ti,pendown-gpio-debounce",
+ ret = of_property_read_u32(node, "ti,pendown-gpio-debounce",
&pdata->gpio_pendown_debounce);
+ if (!ret)
+ dev_info(dev, "Set pendown gpio debounce time to %d microseconds\n",
+ pdata->gpio_pendown_debounce);
pdata->wakeup = of_property_read_bool(node, "wakeup-source") ||
of_property_read_bool(node, "linux,wakeup");
diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c
index 1afc08b08155..94799928259c 100644
--- a/drivers/input/touchscreen/egalax_ts.c
+++ b/drivers/input/touchscreen/egalax_ts.c
@@ -119,6 +119,26 @@ static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static int egalax_irq_request(struct egalax_ts *ts)
+{
+ int ret;
+ struct i2c_client *client = ts->client;
+
+ ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+ egalax_ts_interrupt,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "egalax_ts", ts);
+ if (ret < 0)
+ dev_err(&client->dev, "Failed to register interrupt\n");
+
+ return ret;
+}
+
+static void egalax_free_irq(struct egalax_ts *ts)
+{
+ devm_free_irq(&ts->client->dev, ts->client->irq, ts);
+}
+
/* wake up controller by an falling edge of interrupt gpio. */
static int egalax_wake_up_device(struct i2c_client *client)
{
@@ -186,6 +206,20 @@ static int egalax_ts_probe(struct i2c_client *client,
ts->client = client;
ts->input_dev = input_dev;
+ /* HannStar (HSD100PXN1 Rev: 1-A00C11 F/W:0634) LVDS touch
+ * screen needs to trigger I2C event to device FW at booting
+ * first, and then the FW can switch to I2C interface.
+ * Otherwise, the FW can’t work with I2C interface. So here
+ * just use the exist function egalax_firmware_version() to
+ * send a I2C command to the device, make sure the device FW
+ * switch to I2C interface.
+ */
+ error = egalax_firmware_version(client);
+ if (error) {
+ dev_err(&client->dev, "Failed to switch to I2C interface\n");
+ return error;
+ }
+
/* controller may be in sleep, wake it up. */
error = egalax_wake_up_device(client);
if (error) {
@@ -216,14 +250,9 @@ static int egalax_ts_probe(struct i2c_client *client,
input_set_drvdata(input_dev, ts);
- error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
- egalax_ts_interrupt,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- "egalax_ts", ts);
- if (error < 0) {
- dev_err(&client->dev, "Failed to register interrupt\n");
+ error = egalax_irq_request(ts);
+ if (error)
return error;
- }
error = input_register_device(ts->input_dev);
if (error)
@@ -245,8 +274,10 @@ static int __maybe_unused egalax_ts_suspend(struct device *dev)
0x3, 0x6, 0xa, 0x3, 0x36, 0x3f, 0x2, 0, 0, 0
};
struct i2c_client *client = to_i2c_client(dev);
+ struct egalax_ts *ts = i2c_get_clientdata(client);
int ret;
+ egalax_free_irq(ts);
ret = i2c_master_send(client, suspend_cmd, MAX_I2C_DATA_LEN);
return ret > 0 ? 0 : ret;
}
@@ -254,8 +285,14 @@ static int __maybe_unused egalax_ts_suspend(struct device *dev)
static int __maybe_unused egalax_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
+ struct egalax_ts *ts = i2c_get_clientdata(client);
+ int ret;
+
+ ret = egalax_wake_up_device(client);
+ if (!ret)
+ ret = egalax_irq_request(ts);
- return egalax_wake_up_device(client);
+ return ret;
}
static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume);
diff --git a/drivers/input/touchscreen/elan_ts.c b/drivers/input/touchscreen/elan_ts.c
new file mode 100644
index 000000000000..8590a947b624
--- /dev/null
+++ b/drivers/input/touchscreen/elan_ts.c
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2007-2008 HTC Corporation.
+ *
+ * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
+ *
+ * This driver is adapted from elan8232_i2c.c written by Shan-Fu Chiou
+ * <sfchiou@gmail.com> and Jay Tu <jay_tu@htc.com>.
+ * This driver is also adapted from the ELAN Touch Screen driver
+ * written by Stanley Zeng <stanley.zeng@emc.com.tw>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/hrtimer.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+
+static const char ELAN_TS_NAME[] = "elan-touch";
+
+#define ELAN_TS_X_MAX 1088
+#define ELAN_TS_Y_MAX 768
+#define ELAN_USER_X_MAX 800
+#define ELAN_USER_Y_MAX 600
+#define IDX_PACKET_SIZE 8
+
+enum {
+ hello_packet = 0x55,
+ idx_coordinate_packet = 0x5a,
+};
+
+enum {
+ idx_finger_state = 7,
+};
+
+static struct workqueue_struct *elan_wq;
+
+static struct elan_data {
+ int intr_gpio;
+ int use_irq;
+ struct hrtimer timer;
+ struct work_struct work;
+ struct i2c_client *client;
+ struct input_dev *input;
+ wait_queue_head_t wait;
+} elan_touch_data;
+
+/*--------------------------------------------------------------*/
+static int elan_touch_detect_int_level(void)
+{
+ int v;
+ v = gpio_get_value(elan_touch_data.intr_gpio);
+
+ return v;
+}
+
+static int __elan_touch_poll(struct i2c_client *client)
+{
+ int status = 0, retry = 20;
+
+ do {
+ status = elan_touch_detect_int_level();
+ retry--;
+ mdelay(20);
+ } while (status == 1 && retry > 0);
+
+ return status == 0 ? 0 : -ETIMEDOUT;
+}
+
+static int elan_touch_poll(struct i2c_client *client)
+{
+ return __elan_touch_poll(client);
+}
+
+static int __hello_packet_handler(struct i2c_client *client)
+{
+ int rc;
+ uint8_t buf_recv[4] = { 0 };
+
+ rc = elan_touch_poll(client);
+
+ if (rc < 0)
+ return -EINVAL;
+
+ rc = i2c_master_recv(client, buf_recv, 4);
+
+ if (rc != 4) {
+ return rc;
+ } else {
+ int i;
+ pr_info("hello packet: [0x%02x 0x%02x 0x%02x 0x%02x]\n",
+ buf_recv[0], buf_recv[1], buf_recv[2], buf_recv[3]);
+
+ for (i = 0; i < 4; i++)
+ if (buf_recv[i] != hello_packet)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static inline int elan_touch_parse_xy(uint8_t *data, uint16_t *x,
+ uint16_t *y)
+{
+ *x = (data[0] & 0xf0);
+ *x <<= 4;
+ *x |= data[1];
+ if (*x >= ELAN_TS_X_MAX)
+ *x = ELAN_TS_X_MAX;
+ *x = ((((ELAN_TS_X_MAX -
+ *x) * 1000) / ELAN_TS_X_MAX) * ELAN_USER_X_MAX) / 1000;
+
+ *y = (data[0] & 0x0f);
+ *y <<= 8;
+ *y |= data[2];
+ if (*y >= ELAN_TS_Y_MAX)
+ *y = ELAN_TS_Y_MAX;
+ *y = ((((ELAN_TS_Y_MAX -
+ *y) * 1000) / ELAN_TS_Y_MAX) * ELAN_USER_Y_MAX) / 1000;
+
+ return 0;
+}
+
+/* __elan_touch_init -- hand shaking with touch panel
+ *
+ * 1.recv hello packet
+ */
+static int __elan_touch_init(struct i2c_client *client)
+{
+ int rc;
+ rc = __hello_packet_handler(client);
+ if (rc < 0)
+ goto hand_shake_failed;
+
+hand_shake_failed:
+ return rc;
+}
+
+static int elan_touch_recv_data(struct i2c_client *client, uint8_t *buf)
+{
+ int rc, bytes_to_recv = IDX_PACKET_SIZE;
+
+ if (buf == NULL)
+ return -EINVAL;
+
+ memset(buf, 0, bytes_to_recv);
+ rc = i2c_master_recv(client, buf, bytes_to_recv);
+ if (rc != bytes_to_recv)
+ return -EINVAL;
+
+ return rc;
+}
+
+static void elan_touch_report_data(struct i2c_client *client, uint8_t *buf)
+{
+ switch (buf[0]) {
+ case idx_coordinate_packet:
+ {
+ uint16_t x1, x2, y1, y2;
+ uint8_t finger_stat;
+
+ finger_stat = (buf[idx_finger_state] & 0x06) >> 1;
+
+ if (finger_stat == 0) {
+ input_report_key(elan_touch_data.input, BTN_TOUCH, 0);
+ input_report_key(elan_touch_data.input, BTN_2, 0);
+ } else if (finger_stat == 1) {
+ elan_touch_parse_xy(&buf[1], &x1, &y1);
+ input_report_abs(elan_touch_data.input, ABS_X, x1);
+ input_report_abs(elan_touch_data.input, ABS_Y, y1);
+ input_report_key(elan_touch_data.input, BTN_TOUCH, 1);
+ input_report_key(elan_touch_data.input, BTN_2, 0);
+ } else if (finger_stat == 2) {
+ elan_touch_parse_xy(&buf[1], &x1, &y1);
+ input_report_abs(elan_touch_data.input, ABS_X, x1);
+ input_report_abs(elan_touch_data.input, ABS_Y, y1);
+ input_report_key(elan_touch_data.input, BTN_TOUCH, 1);
+ elan_touch_parse_xy(&buf[4], &x2, &y2);
+ input_report_abs(elan_touch_data.input, ABS_HAT0X, x2);
+ input_report_abs(elan_touch_data.input, ABS_HAT0Y, y2);
+ input_report_key(elan_touch_data.input, BTN_2, 1);
+ }
+ input_sync(elan_touch_data.input);
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+static void elan_touch_work_func(struct work_struct *work)
+{
+ int rc;
+ uint8_t buf[IDX_PACKET_SIZE] = { 0 };
+ struct i2c_client *client = elan_touch_data.client;
+
+ if (elan_touch_detect_int_level())
+ return;
+
+ rc = elan_touch_recv_data(client, buf);
+ if (rc < 0)
+ return;
+
+ elan_touch_report_data(client, buf);
+}
+
+static irqreturn_t elan_touch_ts_interrupt(int irq, void *dev_id)
+{
+ queue_work(elan_wq, &elan_touch_data.work);
+
+ return IRQ_HANDLED;
+}
+
+static enum hrtimer_restart elan_touch_timer_func(struct hrtimer *timer)
+{
+ queue_work(elan_wq, &elan_touch_data.work);
+ hrtimer_start(&elan_touch_data.timer, ktime_set(0, 12500000),
+ HRTIMER_MODE_REL);
+
+ return HRTIMER_NORESTART;
+}
+
+static int elan_touch_register_interrupt(struct i2c_client *client)
+{
+ int err = 0;
+
+ if (client->irq) {
+ elan_touch_data.use_irq = 1;
+ err =
+ request_irq(client->irq, elan_touch_ts_interrupt,
+ IRQF_TRIGGER_FALLING, ELAN_TS_NAME,
+ &elan_touch_data);
+
+ if (err < 0) {
+ pr_info("%s(%s): Can't allocate irq %d\n", __FILE__,
+ __func__, client->irq);
+ elan_touch_data.use_irq = 0;
+ }
+ }
+
+ if (!elan_touch_data.use_irq) {
+ hrtimer_init(&elan_touch_data.timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ elan_touch_data.timer.function = elan_touch_timer_func;
+ hrtimer_start(&elan_touch_data.timer, ktime_set(1, 0),
+ HRTIMER_MODE_REL);
+ }
+
+ pr_info("elan ts starts in %s mode.\n",
+ elan_touch_data.use_irq == 1 ? "interrupt" : "polling");
+
+ return 0;
+}
+
+static int elan_touch_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device_node *np = client->dev.of_node;
+ int gpio_elan_cs, gpio_elan_rst, err = 0;
+
+ if (!np)
+ return -ENODEV;
+
+ elan_touch_data.intr_gpio = of_get_named_gpio(np, "gpio_intr", 0);
+ if (!gpio_is_valid(elan_touch_data.intr_gpio))
+ return -ENODEV;
+
+ err = devm_gpio_request_one(&client->dev, elan_touch_data.intr_gpio,
+ GPIOF_IN, "gpio_elan_intr");
+ if (err < 0) {
+ dev_err(&client->dev,
+ "request gpio failed: %d\n", err);
+ return err;
+ }
+
+ /* elan touch init */
+ gpio_elan_cs = of_get_named_gpio(np, "gpio_elan_cs", 0);
+ if (!gpio_is_valid(gpio_elan_cs))
+ return -ENODEV;
+
+ err = devm_gpio_request_one(&client->dev, gpio_elan_cs,
+ GPIOF_OUT_INIT_HIGH, "gpio_elan_cs");
+ if (err < 0) {
+ dev_err(&client->dev,
+ "request gpio failed: %d\n", err);
+ return err;
+ }
+ gpio_set_value(gpio_elan_cs, 0);
+
+ gpio_elan_rst = of_get_named_gpio(np, "gpio_elan_rst", 0);
+ if (!gpio_is_valid(gpio_elan_rst))
+ return -ENODEV;
+
+ err = devm_gpio_request_one(&client->dev, gpio_elan_rst,
+ GPIOF_OUT_INIT_HIGH, "gpio_elan_rst");
+ if (err < 0) {
+ dev_err(&client->dev,
+ "request gpio failed: %d\n", err);
+ return err;
+ }
+ gpio_set_value(gpio_elan_rst, 0);
+ msleep(10);
+ gpio_set_value(gpio_elan_rst, 1);
+
+ gpio_set_value(gpio_elan_cs, 1);
+ msleep(100);
+
+ elan_wq = create_singlethread_workqueue("elan_wq");
+ if (!elan_wq) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ elan_touch_data.client = client;
+ strlcpy(client->name, ELAN_TS_NAME, I2C_NAME_SIZE);
+
+ INIT_WORK(&elan_touch_data.work, elan_touch_work_func);
+
+ elan_touch_data.input = input_allocate_device();
+ if (elan_touch_data.input == NULL) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ err = __elan_touch_init(client);
+ if (err < 0) {
+ dev_err(&client->dev, "elan - Read Hello Packet Failed\n");
+ goto fail;
+ }
+
+ elan_touch_data.input->name = ELAN_TS_NAME;
+ elan_touch_data.input->id.bustype = BUS_I2C;
+
+ set_bit(EV_SYN, elan_touch_data.input->evbit);
+
+ set_bit(EV_KEY, elan_touch_data.input->evbit);
+ set_bit(BTN_TOUCH, elan_touch_data.input->keybit);
+ set_bit(BTN_2, elan_touch_data.input->keybit);
+
+ set_bit(EV_ABS, elan_touch_data.input->evbit);
+ set_bit(ABS_X, elan_touch_data.input->absbit);
+ set_bit(ABS_Y, elan_touch_data.input->absbit);
+ set_bit(ABS_HAT0X, elan_touch_data.input->absbit);
+ set_bit(ABS_HAT0Y, elan_touch_data.input->absbit);
+
+ input_set_abs_params(elan_touch_data.input, ABS_X, 0, ELAN_USER_X_MAX,
+ 0, 0);
+ input_set_abs_params(elan_touch_data.input, ABS_Y, 0, ELAN_USER_Y_MAX,
+ 0, 0);
+ input_set_abs_params(elan_touch_data.input, ABS_HAT0X, 0,
+ ELAN_USER_X_MAX, 0, 0);
+ input_set_abs_params(elan_touch_data.input, ABS_HAT0Y, 0,
+ ELAN_USER_Y_MAX, 0, 0);
+
+ err = input_register_device(elan_touch_data.input);
+ if (err < 0)
+ goto fail;
+
+ elan_touch_register_interrupt(elan_touch_data.client);
+
+ return 0;
+
+fail:
+ input_free_device(elan_touch_data.input);
+ if (elan_wq)
+ destroy_workqueue(elan_wq);
+ return err;
+}
+
+static int elan_touch_remove(struct i2c_client *client)
+{
+ if (elan_wq)
+ destroy_workqueue(elan_wq);
+
+ input_unregister_device(elan_touch_data.input);
+
+ if (elan_touch_data.use_irq)
+ free_irq(client->irq, client);
+ else
+ hrtimer_cancel(&elan_touch_data.timer);
+ return 0;
+}
+
+/* -------------------------------------------------------------------- */
+static const struct i2c_device_id elan_touch_id[] = {
+ {"elan-touch", 0},
+ {}
+};
+
+static const struct of_device_id elan_dt_ids[] = {
+ {
+ .compatible = "elan,elan-touch",
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, elan_dt_ids);
+
+static int elan_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int elan_resume(struct device *dev)
+{
+ uint8_t buf[IDX_PACKET_SIZE] = { 0 };
+
+ if (0 == elan_touch_detect_int_level()) {
+ dev_dbg(dev, "Got touch during suspend period.\n");
+ /*
+ * if touch screen during suspend, recv and drop the
+ * data, then touch interrupt pin will return high after
+ * receving data.
+ */
+ elan_touch_recv_data(elan_touch_data.client, buf);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops elan_dev_pm_ops = {
+ .suspend = elan_suspend,
+ .resume = elan_resume,
+};
+
+static struct i2c_driver elan_touch_driver = {
+ .probe = elan_touch_probe,
+ .remove = elan_touch_remove,
+ .id_table = elan_touch_id,
+ .driver = {
+ .name = "elan-touch",
+ .owner = THIS_MODULE,
+ .of_match_table = elan_dt_ids,
+#ifdef CONFIG_PM
+ .pm = &elan_dev_pm_ops,
+#endif
+ },
+};
+
+static int __init elan_touch_init(void)
+{
+ return i2c_add_driver(&elan_touch_driver);
+}
+
+static void __exit elan_touch_exit(void)
+{
+ i2c_del_driver(&elan_touch_driver);
+}
+
+module_init(elan_touch_init);
+module_exit(elan_touch_exit);
+
+MODULE_AUTHOR("Stanley Zeng <stanley.zeng@emc.com.tw>");
+MODULE_DESCRIPTION("ELAN Touch Screen driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/focaltech_touch/Kconfig b/drivers/input/touchscreen/focaltech_touch/Kconfig
new file mode 100644
index 000000000000..e1ec3b91202e
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/Kconfig
@@ -0,0 +1,16 @@
+#
+# Focaltech Touchscreen driver configuration
+#
+
+config TOUCHSCREEN_FTS
+ bool "Focaltech Touchscreen"
+ depends on I2C
+ 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/drivers/input/touchscreen/focaltech_touch/Makefile b/drivers/input/touchscreen/focaltech_touch/Makefile
new file mode 100644
index 000000000000..1b2b8ec8acd4
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the focaltech touchscreen drivers.
+#
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_core.o
+obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_esdcheck.o
+obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_ex_mode.o
+obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_gesture.o
+obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_point_report_check.o
+obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_i2c.o
+obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_sensor.o
diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_common.h b/drivers/input/touchscreen/focaltech_touch/focaltech_common.h
new file mode 100644
index 000000000000..ae4807c7b700
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/focaltech_common.h
@@ -0,0 +1,211 @@
+/*
+ *
+ * FocalTech fts TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, 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 V1.2 20161229"
+
+#define FLAGBIT(x) (0x00000001 << (x))
+#define FLAGBITS(x, y) ((0xFFFFFFFF >> (32 - (y) - 1)) << (x))
+
+#define FLAG_ICSERIALS_LEN 5
+#define FLAG_IDC_BIT 11
+
+#define FTS_CHIP_TYPE_MAPPING { \
+ {0x01, 0x58, 0x22, 0x58, 0x22, 0x00, 0x00, 0x58, 0x2C}, \
+ {0x02, 0x54, 0x22, 0x54, 0x22, 0x00, 0x00, 0x54, 0x2C}, \
+ {0x03, 0x64, 0x26, 0x64, 0x26, 0x00, 0x00, 0x79, 0x1C}, \
+ {0x04, 0x33, 0x67, 0x64, 0x26, 0x00, 0x00, 0x79, 0x1C}, \
+ {0x05, 0x87, 0x16, 0x87, 0x16, 0x87, 0xA6, 0x00, 0x00}, \
+ {0x06, 0x87, 0x36, 0x87, 0x36, 0x87, 0xC6, 0x00, 0x00}, \
+ {0x07, 0x80, 0x06, 0x80, 0x06, 0x80, 0xC6, 0x80, 0xB6}, \
+ {0x08, 0x86, 0x06, 0x86, 0x06, 0x86, 0xA6, 0x00, 0x00}, \
+ {0x09, 0x86, 0x07, 0x86, 0x07, 0x86, 0xA7, 0x00, 0x00}, \
+ {0x0A, 0xE7, 0x16, 0x87, 0x16, 0xE7, 0xA6, 0x87, 0xB6}, \
+}
+
+#define I2C_BUFFER_LENGTH_MAXINUM 256
+#define FILE_NAME_LENGTH 128
+#define ENABLE 1
+#define DISABLE 0
+/*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_CHIP_ID 0xA3
+#define FTS_REG_CHIP_ID2 0x9F
+#define FTS_REG_POWER_MODE 0xA5
+#define FTS_REG_POWER_MODE_SLEEP_VALUE 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_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_ESD_SATURATE 0xED
+
+/*****************************************************************************
+* 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 {
+ unsigned long type;
+ unsigned char chip_idh;
+ unsigned char chip_idl;
+ unsigned char rom_idh;
+ unsigned char rom_idl;
+ unsigned char pramboot_idh;
+ unsigned char pramboot_idl;
+ unsigned char bootloader_idh;
+ unsigned char bootloader_idl;
+};
+
+/* i2c communication*/
+int fts_i2c_write_reg(struct i2c_client *client, u8 regaddr, u8 regvalue);
+int fts_i2c_read_reg(struct i2c_client *client, u8 regaddr, u8 *regvalue);
+int fts_i2c_read(struct i2c_client *client, char *writebuf, int writelen,
+ char *readbuf, int readlen);
+int fts_i2c_write(struct i2c_client *client, char *writebuf, int writelen);
+int fts_i2c_init(void);
+int fts_i2c_exit(void);
+
+/* Gesture functions */
+#if FTS_GESTURE_EN
+int fts_gesture_init(struct input_dev *input_dev, struct i2c_client *client);
+int fts_gesture_exit(struct i2c_client *client);
+void fts_gesture_recovery(struct i2c_client *client);
+int fts_gesture_readdata(struct i2c_client *client);
+int fts_gesture_suspend(struct i2c_client *i2c_client);
+int fts_gesture_resume(struct i2c_client *client);
+#endif
+
+/* Apk and functions */
+#if FTS_APK_NODE_EN
+int fts_create_apk_debug_channel(struct i2c_client *client);
+void fts_release_apk_debug_channel(void);
+#endif
+
+/* ADB functions */
+#if FTS_SYSFS_NODE_EN
+int fts_create_sysfs(struct i2c_client *client);
+int fts_remove_sysfs(struct i2c_client *client);
+#endif
+
+/* ESD */
+#if FTS_ESDCHECK_EN
+int fts_esdcheck_init(void);
+int fts_esdcheck_exit(void);
+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);
+int fts_esdcheck_get_status(void);
+#endif
+
+/* Production test */
+#if FTS_TEST_EN
+int fts_test_init(struct i2c_client *client);
+int fts_test_exit(struct i2c_client *client);
+#endif
+
+/* Point Report Check*/
+#if FTS_POINT_REPORT_CHECK_EN
+int fts_point_report_check_init(void);
+int fts_point_report_check_exit(void);
+void fts_point_report_check_queue_work(void);
+#endif
+
+/* Other */
+extern int g_show_log;
+int fts_reset_proc(int hdelayms);
+int fts_wait_tp_to_valid(struct i2c_client *client);
+void fts_tp_state_recovery(struct i2c_client *client);
+int fts_ex_mode_init(struct i2c_client *client);
+int fts_ex_mode_exit(struct i2c_client *client);
+int fts_ex_mode_recovery(struct i2c_client *client);
+
+void fts_irq_disable(void);
+void fts_irq_enable(void);
+
+/*****************************************************************************
+* DEBUG function define here
+*****************************************************************************/
+#if FTS_DEBUG_EN
+#define FTS_DEBUG_LEVEL 1
+
+#if (FTS_DEBUG_LEVEL == 2)
+#define FTS_DEBUG(fmt, args...) \
+ printk(KERN_ERR "[FTS][%s]"fmt"\n", __func__, ##args)
+#else
+#define FTS_DEBUG(fmt, args...) \
+ printk(KERN_ERR "[FTS]"fmt"\n", ##args)
+#endif
+
+#define FTS_FUNC_ENTER() \
+ printk(KERN_ERR "[FTS]%s: Enter\n", __func__)
+#define FTS_FUNC_EXIT() \
+ printk(KERN_ERR "[FTS]%s: Exit(%d)\n", __func__, __LINE__)
+#else
+#define FTS_DEBUG(fmt, args...)
+#define FTS_FUNC_ENTER()
+#define FTS_FUNC_EXIT()
+#endif
+
+#define FTS_INFO(fmt, args...) do { \
+ if (g_show_log) \
+ printk(KERN_ERR "[FTS][Info]"fmt"\n", ##args); \
+ } while (0)
+
+#define FTS_ERROR(fmt, args...) do { \
+ if (g_show_log) \
+ printk(KERN_ERR "[FTS][Error]"fmt"\n", ##args); \
+ } while (0)
+
+#endif /* __LINUX_FOCALTECH_COMMON_H__ */
diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_config.h b/drivers/input/touchscreen/focaltech_touch/focaltech_config.h
new file mode 100644
index 000000000000..87b622e77942
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/focaltech_config.h
@@ -0,0 +1,219 @@
+/*
+ *
+ * FocalTech TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, 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 _FT8716 0x87160805
+#define _FT8736 0x87360806
+#define _FT8006 0x80060807
+#define _FT8606 0x86060808
+#define _FT8607 0x86070809
+#define _FTE716 0xE716080a
+
+#define _FT5416 0x54160002
+#define _FT5426 0x54260002
+#define _FT5435 0x54350002
+#define _FT5436 0x54360002
+#define _FT5526 0x55260002
+#define _FT5526I 0x5526B002
+#define _FT5446 0x54460002
+#define _FT5346 0x53460002
+#define _FT5446I 0x5446B002
+#define _FT5346I 0x5346B002
+#define _FT7661 0x76610002
+#define _FT7511 0x75110002
+#define _FT7421 0x74210002
+#define _FT7681 0x76810002
+#define _FT3C47U 0x3C47D002
+#define _FT3417 0x34170002
+#define _FT3517 0x35170002
+#define _FT3327 0x33270002
+#define _FT3427 0x34270002
+
+#define _FT5626 0x56260001
+#define _FT5726 0x57260001
+#define _FT5826B 0x5826B001
+#define _FT5826S 0x5826C001
+#define _FT7811 0x78110001
+#define _FT3D47 0x3D470001
+#define _FT3617 0x36170001
+#define _FT3717 0x37170001
+#define _FT3817B 0x3817B001
+
+#define _FT6236U 0x6236D003
+#define _FT6336G 0x6336A003
+#define _FT6336U 0x6336D003
+#define _FT6436U 0x6436D003
+
+#define _FT3267 0x32670004
+#define _FT3367 0x33670004
+
+/******************* 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
+ */
+#define FTS_MT_PROTOCOL_B_EN 1
+
+/*
+ * Report Pressure in multitouch
+ * 1:enable(default),0:disable
+*/
+#define FTS_REPORT_PRESSURE_EN 1
+
+/*
+ * Force touch support
+ * different pressure for multitouch
+ * 1: true pressure for force touch
+ * 0: constant pressure(default)
+ */
+#define FTS_FORCE_TOUCH_EN 0
+
+/*
+ * Gesture function enable
+ * default: disable
+ */
+#define FTS_GESTURE_EN 0
+
+/*
+ * ESD check & protection
+ * default: disable
+ */
+#define FTS_ESDCHECK_EN 0
+
+/*
+ * Production test enable
+ * 1: enable, 0:disable(default)
+ */
+#define FTS_TEST_EN 0
+
+/*
+ * Glove mode enable
+ * 1: enable, 0:disable(default)
+ */
+#define FTS_GLOVE_EN 0
+/*
+ * cover enable
+ * 1: enable, 0:disable(default)
+ */
+#define FTS_COVER_EN 0
+/*
+ * Charger enable
+ * 1: enable, 0:disable(default)
+ */
+#define FTS_CHARGER_EN 0
+
+/*
+ * Proximity sensor
+ * default: disable
+ */
+#define FTS_PSENSOR_EN 0
+
+/*
+ * Nodes for tools, please keep enable
+ */
+#define FTS_SYSFS_NODE_EN 1
+#define FTS_APK_NODE_EN 1
+
+/*
+ * Customer power enable
+ * enable it when customer need control TP power
+ * default: disable
+ */
+#define FTS_POWER_SOURCE_CUST_EN 0
+
+/****************************************************/
+
+/********************** Upgrade ****************************/
+/*
+ * auto upgrade, please keep enable
+ */
+#define FTS_AUTO_UPGRADE_EN 1
+
+/*
+ * auto upgrade for lcd cfg
+ * default: 0
+ */
+#define FTS_AUTO_UPGRADE_FOR_LCD_CFG_EN 0
+
+/* auto cb check
+ * default: disable
+ */
+#define FTS_AUTO_CLB_EN 0
+
+/*
+ * FW_APP.i file for upgrade
+ * define your own fw_app, the sample one is invalid
+ */
+#define FTS_UPGRADE_FW_APP "include/firmware/FT8716_app_sample.i"
+
+/*
+ * lcd_cfg.i file for lcd cfg upgrade
+ * define your own lcd_cfg.i, the sample one is invalid
+ */
+#define FTS_UPGRADE_LCD_CFG "include/firmware/lcd_cfg.i"
+
+/* get vedor id from flash
+ * default: enable
+ */
+#define FTS_GET_VENDOR_ID 0
+
+/*
+ * vendor_id(s) for the ic
+ * you need confirm vendor_id for upgrade
+ * if only one vendor, ignore vendor_2_id, otherwise
+ * you need define both of them
+ */
+#define FTS_VENDOR_1_ID 0x8d
+#define FTS_VENDOR_2_ID 0x8d
+
+/*
+ * upgrade stress test for debug
+ * enable it for upgrade debug if needed
+ * default: disable
+ */
+#define FTS_UPGRADE_STRESS_TEST 0
+/* stress test times, default: 1000 */
+#define FTS_UPGRADE_TEST_NUMBER 1000
+
+/*********************************************************/
+
+#endif /* _LINUX_FOCLATECH_CONFIG_H_ */
diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_core.c b/drivers/input/touchscreen/focaltech_touch/focaltech_core.c
new file mode 100644
index 000000000000..38aa6c88f7e0
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/focaltech_core.c
@@ -0,0 +1,1439 @@
+/*
+ *
+ * FocalTech TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, 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:
+*
+* Reference:
+*
+*****************************************************************************/
+
+/*****************************************************************************
+* Included header files
+*****************************************************************************/
+#include "focaltech_core.h"
+
+#if defined(CONFIG_FB)
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+#include <linux/earlysuspend.h>
+#define FTS_SUSPEND_LEVEL 1 /* Early-suspend level */
+#endif
+
+/*****************************************************************************
+* Private constant and macro definitions using #define
+*****************************************************************************/
+#define FTS_DRIVER_NAME "fts_ts"
+#define INTERVAL_READ_REG 20
+#define TIMEOUT_READ_REG 300
+#if FTS_POWER_SOURCE_CUST_EN
+#define FTS_VTG_MIN_UV 2600000
+#define FTS_VTG_MAX_UV 3300000
+#define FTS_I2C_VTG_MIN_UV 1800000
+#define FTS_I2C_VTG_MAX_UV 1800000
+#endif
+#define FTS_READ_TOUCH_BUFFER_DIVIDED 0
+/*****************************************************************************
+* Global variable or extern global variabls/functions
+******************************************************************************/
+struct i2c_client *fts_i2c_client;
+struct fts_ts_data *fts_wq_data;
+struct input_dev *fts_input_dev;
+
+#if FTS_DEBUG_EN
+int g_show_log = 1;
+#else
+int g_show_log;
+#endif
+
+#if (FTS_DEBUG_EN && (FTS_DEBUG_LEVEL == 2))
+char g_sz_debug[1024] = { 0 };
+#endif
+
+/*****************************************************************************
+* Static function prototypes
+*****************************************************************************/
+static void fts_release_all_finger(void);
+static int fts_ts_suspend(struct device *dev);
+static int fts_ts_resume(struct device *dev);
+
+static bool fts_chip_idc(struct fts_ts_data *data)
+{
+ return ((data->pdata->fts_chip_type & FLAGBIT(FLAG_IDC_BIT)) ==
+ FLAGBIT(FLAG_IDC_BIT));
+}
+
+/*****************************************************************************
+* Name: fts_wait_tp_to_valid
+* Brief: Read chip id until TP FW become valid,
+* need call when reset/power on/resume...
+* 1. Read Chip ID per INTERVAL_READ_REG(20ms)
+* 2. Timeout: TIMEOUT_READ_REG(300ms)
+* Input:
+* Output:
+* Return: 0 - Get correct Device ID
+*****************************************************************************/
+int fts_wait_tp_to_valid(struct i2c_client *client)
+{
+ int ret = 0;
+ int cnt = 0;
+ u8 reg_value = 0;
+
+ do {
+ ret = fts_i2c_read_reg(client, FTS_REG_CHIP_ID, &reg_value);
+ if (ret < 0)
+ FTS_INFO("TP Not Ready, ReadData = 0x%x", reg_value);
+ else {
+ FTS_INFO("TP Ready, Device ID = 0x%x", reg_value);
+ return 0;
+ }
+ cnt++;
+ msleep(INTERVAL_READ_REG);
+ } while ((cnt * INTERVAL_READ_REG) < TIMEOUT_READ_REG);
+
+ /* error: not get correct reg data */
+ return -1;
+}
+
+/*****************************************************************************
+* Name: fts_recover_state
+* Brief: Need execute this function when reset
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+void fts_tp_state_recovery(struct i2c_client *client)
+{
+ /* wait tp stable */
+ fts_wait_tp_to_valid(client);
+ /* recover TP charger state 0x8B */
+ /* recover TP glove state 0xC0 */
+ /* recover TP cover state 0xC1 */
+ fts_ex_mode_recovery(client);
+ /* recover TP gesture state 0xD0 */
+#if FTS_GESTURE_EN
+ fts_gesture_recovery(client);
+#endif
+
+ fts_release_all_finger();
+}
+
+/*****************************************************************************
+* Name: fts_reset_proc
+* Brief: Execute reset operation
+* Input: hdelayms - delay time unit:ms
+* Output:
+* Return:
+*****************************************************************************/
+int fts_reset_proc(int hdelayms)
+{
+ gpio_direction_output(fts_wq_data->pdata->reset_gpio, 0);
+ msleep(20);
+ gpio_direction_output(fts_wq_data->pdata->reset_gpio, 1);
+ msleep(hdelayms);
+
+ return 0;
+}
+
+/*****************************************************************************
+* Name: fts_irq_disable
+* Brief: disable irq
+* Input:
+* sync:
+* Output:
+* Return:
+*****************************************************************************/
+void fts_irq_disable(void)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&fts_wq_data->irq_lock, irqflags);
+
+ if (!fts_wq_data->irq_disable) {
+ disable_irq(fts_wq_data->client->irq);
+ fts_wq_data->irq_disable = 1;
+ }
+
+ spin_unlock_irqrestore(&fts_wq_data->irq_lock, irqflags);
+}
+
+/*****************************************************************************
+* Name: fts_irq_enable
+* Brief: enable irq
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+void fts_irq_enable(void)
+{
+ unsigned long irqflags = 0;
+
+ spin_lock_irqsave(&fts_wq_data->irq_lock, irqflags);
+
+ if (fts_wq_data->irq_disable) {
+ enable_irq(fts_wq_data->client->irq);
+ fts_wq_data->irq_disable = 0;
+ }
+
+ spin_unlock_irqrestore(&fts_wq_data->irq_lock, irqflags);
+}
+
+/*****************************************************************************
+* Name: fts_input_dev_init
+* Brief: input dev init
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static int fts_input_dev_init(struct i2c_client *client,
+ struct fts_ts_data *data,
+ struct input_dev *input_dev,
+ struct fts_ts_platform_data *pdata)
+{
+ int err, len;
+
+ FTS_FUNC_ENTER();
+
+ /* Init and register Input device */
+ input_dev->name = FTS_DRIVER_NAME;
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->dev.parent = &client->dev;
+
+ input_set_drvdata(input_dev, data);
+ i2c_set_clientdata(client, data);
+
+ __set_bit(EV_KEY, input_dev->evbit);
+ if (data->pdata->have_key) {
+ FTS_DEBUG("set key capabilities");
+ for (len = 0; len < data->pdata->key_number; len++) {
+ input_set_capability(input_dev, EV_KEY,
+ data->pdata->keys[len]);
+ }
+ }
+ __set_bit(EV_ABS, input_dev->evbit);
+ __set_bit(BTN_TOUCH, input_dev->keybit);
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+
+#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
+
+ err = input_register_device(input_dev);
+ if (err) {
+ FTS_ERROR("Input device registration failed");
+ goto free_inputdev;
+ }
+
+ FTS_FUNC_EXIT();
+
+ return 0;
+
+free_inputdev:
+ input_free_device(input_dev);
+ FTS_FUNC_EXIT();
+ return err;
+
+}
+
+/*****************************************************************************
+* Power Control
+*****************************************************************************/
+#if FTS_POWER_SOURCE_CUST_EN
+static int fts_power_source_init(struct fts_ts_data *data)
+{
+ int rc;
+
+ FTS_FUNC_ENTER();
+
+ data->vdd = regulator_get(&data->client->dev, "vdd");
+ if (IS_ERR(data->vdd)) {
+ rc = PTR_ERR(data->vdd);
+ FTS_ERROR("Regulator get failed vdd rc=%d", rc);
+ }
+
+ if (regulator_count_voltages(data->vdd) > 0) {
+ rc = regulator_set_voltage(data->vdd, FTS_VTG_MIN_UV,
+ FTS_VTG_MAX_UV);
+ if (rc) {
+ FTS_ERROR("Regulator set_vtg failed vdd rc=%d", rc);
+ goto reg_vdd_put;
+ }
+ }
+
+ data->vcc_i2c = regulator_get(&data->client->dev, "vcc_i2c");
+ if (IS_ERR(data->vcc_i2c)) {
+ rc = PTR_ERR(data->vcc_i2c);
+ FTS_ERROR("Regulator get failed vcc_i2c rc=%d", rc);
+ goto reg_vdd_set_vtg;
+ }
+
+ if (regulator_count_voltages(data->vcc_i2c) > 0) {
+ rc = regulator_set_voltage(data->vcc_i2c, FTS_I2C_VTG_MIN_UV,
+ FTS_I2C_VTG_MAX_UV);
+ if (rc) {
+ FTS_ERROR("Regulator set_vtg failed vcc_i2c rc=%d", rc);
+ goto reg_vcc_i2c_put;
+ }
+ }
+
+ FTS_FUNC_EXIT();
+ return 0;
+
+reg_vcc_i2c_put:
+ regulator_put(data->vcc_i2c);
+reg_vdd_set_vtg:
+ if (regulator_count_voltages(data->vdd) > 0)
+ regulator_set_voltage(data->vdd, 0, FTS_VTG_MAX_UV);
+reg_vdd_put:
+ regulator_put(data->vdd);
+ FTS_FUNC_EXIT();
+ return rc;
+}
+
+static int fts_power_source_ctrl(struct fts_ts_data *data, int enable)
+{
+ int rc;
+
+ FTS_FUNC_ENTER();
+ if (enable) {
+ rc = regulator_enable(data->vdd);
+ if (rc)
+ FTS_ERROR("Regulator vdd enable failed rc=%d", rc);
+
+ rc = regulator_enable(data->vcc_i2c);
+ if (rc)
+ FTS_ERROR("Regulator vcc_i2c enable failed rc=%d", rc);
+ } else {
+ rc = regulator_disable(data->vdd);
+ if (rc)
+ FTS_ERROR("Regulator vdd disable failed rc=%d", rc);
+ rc = regulator_disable(data->vcc_i2c);
+ if (rc)
+ FTS_ERROR("Regulator vcc_i2c disable failed rc=%d", rc);
+ }
+ FTS_FUNC_EXIT();
+ return 0;
+}
+
+#endif
+
+/*****************************************************************************
+* Reprot related
+*****************************************************************************/
+/*****************************************************************************
+* Name: fts_release_all_finger
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static void fts_release_all_finger(void)
+{
+#if FTS_MT_PROTOCOL_B_EN
+ unsigned int finger_count = 0;
+
+ for (finger_count = 0;
+ finger_count < fts_wq_data->pdata->max_touch_number;
+ finger_count++) {
+ input_mt_slot(fts_input_dev, finger_count);
+ input_mt_report_slot_state(fts_input_dev, MT_TOOL_FINGER,
+ false);
+ }
+#else
+ input_mt_sync(fts_input_dev);
+#endif
+ input_report_key(fts_input_dev, BTN_TOUCH, 0);
+ input_sync(fts_input_dev);
+}
+
+#if (FTS_DEBUG_EN && (FTS_DEBUG_LEVEL == 2))
+static void fts_show_touch_buffer(u8 *buf, int point_num)
+{
+ int len = point_num * FTS_ONE_TCH_LEN;
+ int count = 0;
+ int i;
+
+ memset(g_sz_debug, 0, 1024);
+ if (len > (POINT_READ_BUF - 3))
+ len = POINT_READ_BUF - 3;
+ else if (len == 0) {
+ len += FTS_ONE_TCH_LEN;
+
+ count += sprintf(g_sz_debug, "%02X,%02X,%02X", buf[0], buf[1], buf[2]);
+ for (i = 0; i < len; i++)
+ count += sprintf(g_sz_debug + count, ",%02X", buf[i + 3]);
+
+ FTS_DEBUG("buffer: %s", g_sz_debug);
+}
+#endif
+
+static int fts_input_dev_report_key_event(struct ts_event *event,
+ struct fts_ts_data *data)
+{
+ int i;
+
+ if (data->pdata->have_key) {
+ if ((1 == event->touch_point || 1 == event->point_num)
+ && (event->au16_y[0] == data->pdata->key_y_coord)) {
+
+ if (event->point_num == 0) {
+ FTS_DEBUG("Keys All Up!");
+ for (i = 0; i < data->pdata->key_number; i++) {
+ input_report_key(data->input_dev,
+ data->pdata->keys[i],
+ 0);
+ }
+ } else {
+ for (i = 0; i < data->pdata->key_number; i++) {
+ if (event->au16_x[0] >
+ (data->pdata->key_x_coords[i] -
+ FTS_KEY_WIDTH)
+ && event->au16_x[0] <
+ (data->pdata->key_x_coords[i] +
+ FTS_KEY_WIDTH)) {
+
+ if (event->au8_touch_event[i] ==
+ 0
+ || event->au8_touch_event[i]
+ == 2) {
+ input_report_key
+ (data->input_dev,
+ data->pdata->keys
+ [i], 1);
+ FTS_DEBUG
+ ("Key%d(%d, %d) DOWN!",
+ i,
+ event->au16_x[0],
+ event->au16_y[0]);
+ } else {
+ input_report_key
+ (data->input_dev,
+ data->pdata->keys
+ [i], 0);
+ FTS_DEBUG
+ ("Key%d(%d, %d) Up!",
+ i,
+ event->au16_x[0],
+ event->au16_y[0]);
+ }
+ break;
+ }
+ }
+ }
+ input_sync(data->input_dev);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+#if FTS_MT_PROTOCOL_B_EN
+static int fts_input_dev_report_b(struct ts_event *event,
+ struct fts_ts_data *data)
+{
+ int i = 0;
+ int uppoint = 0;
+ int touchs = 0;
+
+ for (i = 0; i < event->touch_point; i++) {
+ input_mt_slot(data->input_dev, event->au8_finger_id[i]);
+
+ if (event->au8_touch_event[i] == FTS_TOUCH_DOWN
+ || event->au8_touch_event[i] == FTS_TOUCH_CONTACT) {
+ input_mt_report_slot_state(data->input_dev,
+ MT_TOOL_FINGER, true);
+
+#if FTS_REPORT_PRESSURE_EN
+#if FTS_FORCE_TOUCH_EN
+ if (event->pressure[i] <= 0) {
+ FTS_ERROR("[B]Illegal pressure: %d",
+ event->pressure[i]);
+ event->pressure[i] = 1;
+ }
+#else
+ event->pressure[i] = 0x3f;
+#endif
+ input_report_abs(data->input_dev, ABS_MT_PRESSURE,
+ event->pressure[i]);
+#endif
+
+ if (event->area[i] <= 0) {
+ FTS_ERROR("[B]Illegal touch-major: %d",
+ event->area[i]);
+ event->area[i] = 1;
+ }
+ input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR,
+ event->area[i]);
+
+ input_report_abs(data->input_dev, ABS_MT_POSITION_X,
+ event->au16_x[i]);
+ input_report_abs(data->input_dev, ABS_MT_POSITION_Y,
+ event->au16_y[i]);
+ touchs |= BIT(event->au8_finger_id[i]);
+ data->touchs |= BIT(event->au8_finger_id[i]);
+
+#if FTS_REPORT_PRESSURE_EN
+ FTS_DEBUG("[B]P%d(%d, %d)[p:%d,tm:%d] DOWN!",
+ event->au8_finger_id[i], event->au16_x[i],
+ event->au16_y[i], event->pressure[i],
+ event->area[i]);
+#else
+ FTS_DEBUG("[B]P%d(%d, %d)[tm:%d] DOWN!",
+ event->au8_finger_id[i], event->au16_x[i],
+ event->au16_y[i], event->area[i]);
+#endif
+ } else {
+ uppoint++;
+ input_mt_report_slot_state(data->input_dev,
+ MT_TOOL_FINGER, false);
+#if FTS_REPORT_PRESSURE_EN
+ input_report_abs(data->input_dev, ABS_MT_PRESSURE, 0);
+#endif
+ data->touchs &= ~BIT(event->au8_finger_id[i]);
+ FTS_DEBUG("[B]P%d UP!", event->au8_finger_id[i]);
+ }
+ }
+
+ if (unlikely(data->touchs ^ touchs)) {
+ for (i = 0; i < data->pdata->max_touch_number; i++) {
+ if (BIT(i) & (data->touchs ^ touchs)) {
+ FTS_DEBUG("[B]P%d UP!", i);
+ input_mt_slot(data->input_dev, i);
+ input_mt_report_slot_state(data->input_dev,
+ MT_TOOL_FINGER,
+ false);
+#if FTS_REPORT_PRESSURE_EN
+ input_report_abs(data->input_dev,
+ ABS_MT_PRESSURE, 0);
+#endif
+ }
+ }
+ }
+
+ data->touchs = touchs;
+ if (event->touch_point == uppoint) {
+ FTS_DEBUG("Points All Up!");
+ input_report_key(data->input_dev, BTN_TOUCH, 0);
+ } else {
+ input_report_key(data->input_dev, BTN_TOUCH,
+ event->touch_point > 0);
+ }
+
+ input_sync(data->input_dev);
+
+ return 0;
+
+}
+
+#else
+static int fts_input_dev_report_a(struct ts_event *event,
+ struct fts_ts_data *data)
+{
+ int i = 0;
+ int uppoint = 0;
+ int touchs = 0;
+
+ for (i = 0; i < event->touch_point; i++) {
+
+ if (event->au8_touch_event[i] == FTS_TOUCH_DOWN
+ || event->au8_touch_event[i] == FTS_TOUCH_CONTACT) {
+ input_report_abs(data->input_dev, ABS_MT_TRACKING_ID,
+ event->au8_finger_id[i]);
+#if FTS_REPORT_PRESSURE_EN
+#if FTS_FORCE_TOUCH_EN
+ if (event->pressure[i] <= 0) {
+ FTS_ERROR("[B]Illegal pressure: %d",
+ event->pressure[i]);
+ event->pressure[i] = 1;
+ }
+#else
+ event->pressure[i] = 0x3f;
+#endif
+ input_report_abs(data->input_dev, ABS_MT_PRESSURE,
+ event->pressure[i]);
+#endif
+
+ if (event->area[i] <= 0) {
+ FTS_ERROR("[B]Illegal touch-major: %d",
+ event->area[i]);
+ event->area[i] = 1;
+ }
+ input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR,
+ event->area[i]);
+
+ input_report_abs(data->input_dev, ABS_MT_POSITION_X,
+ event->au16_x[i]);
+ input_report_abs(data->input_dev, ABS_MT_POSITION_Y,
+ event->au16_y[i]);
+
+ input_mt_sync(data->input_dev);
+
+#if FTS_REPORT_PRESSURE_EN
+ FTS_DEBUG("[B]P%d(%d, %d)[p:%d,tm:%d] DOWN!",
+ event->au8_finger_id[i], event->au16_x[i],
+ event->au16_y[i], event->pressure[i],
+ event->area[i]);
+#else
+ FTS_DEBUG("[B]P%d(%d, %d)[tm:%d] DOWN!",
+ event->au8_finger_id[i], event->au16_x[i],
+ event->au16_y[i], event->area[i]);
+#endif
+ } else {
+ uppoint++;
+ }
+ }
+
+ data->touchs = touchs;
+ if (event->touch_point == uppoint) {
+ FTS_DEBUG("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,
+ event->touch_point > 0);
+ }
+
+ input_sync(data->input_dev);
+
+ return 0;
+}
+#endif
+
+/*****************************************************************************
+* Name: fts_read_touchdata
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static int fts_read_touchdata(struct fts_ts_data *data)
+{
+ u8 buf[POINT_READ_BUF] = { 0 };
+ u8 pointid = FTS_MAX_ID;
+ int ret = -1;
+ int i;
+ struct ts_event *event = &(data->event);
+
+#if FTS_GESTURE_EN
+ {
+ u8 state;
+
+ if (data->suspended) {
+ fts_i2c_read_reg(data->client, FTS_REG_GESTURE_EN,
+ &state);
+ if (state == 1) {
+ fts_gesture_readdata(data->client);
+ return 1;
+ }
+ }
+ }
+#endif
+
+#if FTS_PSENSOR_EN
+ if ((fts_sensor_read_data(data) != 0) && (data->suspended == 1))
+ return 1;
+#endif
+
+#if FTS_READ_TOUCH_BUFFER_DIVIDED
+ memset(buf, 0xFF, POINT_READ_BUF);
+ memset(event, 0, sizeof(struct ts_event));
+
+ buf[0] = 0x00;
+ ret = fts_i2c_read(data->client, buf, 1, buf, (3 + FTS_ONE_TCH_LEN));
+ if (ret < 0) {
+ FTS_ERROR("%s read touchdata failed.", __func__);
+ return ret;
+ }
+ event->touch_point = 0;
+ event->point_num = buf[FTS_TOUCH_POINT_NUM] & 0x0F;
+ if (event->point_num > data->pdata->max_touch_number)
+ event->point_num = data->pdata->max_touch_number;
+
+ if (event->point_num > 1) {
+ buf[9] = 0x09;
+ fts_i2c_read(data->client, buf + 9, 1, buf + 9,
+ (event->point_num - 1) * FTS_ONE_TCH_LEN);
+ }
+#else
+ ret = fts_i2c_read(data->client, buf, 1, buf, POINT_READ_BUF);
+ if (ret < 0) {
+ FTS_ERROR("[B]Read touchdata failed, ret: %d", ret);
+ return ret;
+ }
+#if FTS_POINT_REPORT_CHECK_EN
+ fts_point_report_check_queue_work();
+#endif
+
+ memset(event, 0, sizeof(struct ts_event));
+ event->point_num = buf[FTS_TOUCH_POINT_NUM] & 0x0F;
+ if (event->point_num > data->pdata->max_touch_number)
+ event->point_num = data->pdata->max_touch_number;
+ event->touch_point = 0;
+#endif
+
+#if (FTS_DEBUG_EN && (FTS_DEBUG_LEVEL == 2))
+ fts_show_touch_buffer(buf, event->point_num);
+#endif
+
+ for (i = 0; i < data->pdata->max_touch_number; i++) {
+ pointid = (buf[FTS_TOUCH_ID_POS + FTS_ONE_TCH_LEN * i]) >> 4;
+ if (pointid >= FTS_MAX_ID)
+ break;
+
+ event->touch_point++;
+ event->au16_x[i] =
+ (s16) (buf[FTS_TOUCH_X_H_POS + FTS_ONE_TCH_LEN * i] & 0x0F)
+ << 8 | (s16) buf[FTS_TOUCH_X_L_POS + FTS_ONE_TCH_LEN * i];
+ event->au16_y[i] =
+ (s16) (buf[FTS_TOUCH_Y_H_POS + FTS_ONE_TCH_LEN * i] & 0x0F)
+ << 8 | (s16) buf[FTS_TOUCH_Y_L_POS + FTS_ONE_TCH_LEN * i];
+ event->au8_touch_event[i] =
+ buf[FTS_TOUCH_EVENT_POS + FTS_ONE_TCH_LEN * i] >> 6;
+
+ if (data->pdata->swap)
+ swap(event->au16_x[i], event->au16_y[i]);
+
+ if (data->pdata->scaling_down_half) {
+ event->au16_x[i] = event->au16_x[i] >> 1;
+ event->au16_y[i] = event->au16_y[i] >> 1;
+ }
+
+ event->au8_finger_id[i] =
+ (buf[FTS_TOUCH_ID_POS + FTS_ONE_TCH_LEN * i]) >> 4;
+ event->area[i] =
+ (buf[FTS_TOUCH_AREA_POS + FTS_ONE_TCH_LEN * i]) >> 4;
+ event->pressure[i] =
+ (s16) buf[FTS_TOUCH_PRE_POS + FTS_ONE_TCH_LEN * i];
+
+ if (0 == event->area[i])
+ event->area[i] = 0x09;
+
+ if (0 == event->pressure[i])
+ event->pressure[i] = 0x3f;
+
+ if ((event->au8_touch_event[i] == 0
+ || event->au8_touch_event[i] == 2)
+ && (event->point_num == 0))
+ break;
+ }
+ return 0;
+}
+
+/*****************************************************************************
+* Name: fts_report_value
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static void fts_report_value(struct fts_ts_data *data)
+{
+ struct ts_event *event = &data->event;
+
+ FTS_DEBUG("point number: %d, touch point: %d", event->point_num,
+ event->touch_point);
+
+ if (0 == fts_input_dev_report_key_event(event, data))
+ return;
+#if FTS_MT_PROTOCOL_B_EN
+ fts_input_dev_report_b(event, data);
+#else
+ fts_input_dev_report_a(event, data);
+#endif
+
+ return;
+
+}
+
+/*****************************************************************************
+* Name: fts_ts_interrupt
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static irqreturn_t fts_ts_interrupt(int irq, void *dev_id)
+{
+ struct fts_ts_data *fts_ts = dev_id;
+ int ret = -1;
+
+ if (!fts_ts) {
+ FTS_ERROR("[INTR]: Invalid fts_ts");
+ return IRQ_HANDLED;
+ }
+#if FTS_ESDCHECK_EN
+ fts_esdcheck_set_intr(1);
+#endif
+
+ ret = fts_read_touchdata(fts_wq_data);
+
+ if (ret == 0)
+ fts_report_value(fts_wq_data);
+#if FTS_ESDCHECK_EN
+ fts_esdcheck_set_intr(0);
+#endif
+
+ return IRQ_HANDLED;
+}
+
+/*****************************************************************************
+* Name: fts_gpio_configure
+* Brief: Configure IRQ&RESET GPIO
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static int fts_gpio_configure(struct fts_ts_data *data)
+{
+ int err = 0;
+
+ FTS_FUNC_ENTER();
+ /* request irq gpio */
+ if (gpio_is_valid(data->pdata->irq_gpio)) {
+ err = gpio_request(data->pdata->irq_gpio, "fts_irq_gpio");
+ if (err) {
+ FTS_ERROR("[GPIO]irq gpio request failed");
+ goto err_irq_gpio_req;
+ }
+
+ err = gpio_direction_input(data->pdata->irq_gpio);
+ if (err) {
+ 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)) {
+ err = gpio_request(data->pdata->reset_gpio, "fts_reset_gpio");
+ if (err) {
+ FTS_ERROR("[GPIO]reset gpio request failed");
+ goto err_irq_gpio_dir;
+ }
+
+ err = gpio_direction_output(data->pdata->reset_gpio, 1);
+ if (err) {
+ 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 err;
+}
+
+/*****************************************************************************
+* Name: fts_get_dt_coords
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static int fts_get_dt_coords(struct device *dev, char *name,
+ struct fts_ts_platform_data *pdata)
+{
+ u32 coords[FTS_COORDS_ARR_SIZE];
+ struct property *prop;
+ struct device_node *np = dev->of_node;
+ int coords_size, rc;
+
+ 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", name);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32_array(np, name, coords, coords_size);
+ if (rc && (rc != -EINVAL)) {
+ FTS_ERROR("Unable to read %s", name);
+ return rc;
+ }
+
+ if (!strcmp(name, "focaltech,display-coords")) {
+ pdata->x_min = coords[0];
+ pdata->y_min = coords[1];
+ pdata->x_max = coords[2];
+ pdata->y_max = coords[3];
+ } else {
+ FTS_ERROR("unsupported property %s", name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+* Name: fts_parse_dt
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static int fts_parse_dt(struct device *dev, struct fts_ts_platform_data *pdata)
+{
+ int rc;
+ struct device_node *np = dev->of_node;
+ u32 temp_val;
+
+ FTS_FUNC_ENTER();
+
+ pdata->fts_chip_type = _FT5416;
+ rc = of_property_read_u32(np, "focaltech,panel-type",
+ &pdata->fts_chip_type);
+ if (rc)
+ FTS_ERROR("Panel type is undefined, use default panel FT5416");
+
+ rc = fts_get_dt_coords(dev, "focaltech,display-coords", pdata);
+ if (rc)
+ FTS_ERROR("Unable to get display-coords");
+
+ /* key */
+ pdata->have_key = of_property_read_bool(np, "focaltech,have-key");
+ if (pdata->have_key) {
+ rc = of_property_read_u32(np, "focaltech,key-number",
+ &pdata->key_number);
+ if (rc)
+ FTS_ERROR("Key number undefined!");
+ rc = of_property_read_u32_array(np, "focaltech,keys",
+ pdata->keys, pdata->key_number);
+ if (rc)
+ FTS_ERROR("Keys undefined!");
+ rc = of_property_read_u32(np, "focaltech,key-y-coord",
+ &pdata->key_y_coord);
+ if (rc)
+ FTS_ERROR("Key Y Coord undefined!");
+ rc = of_property_read_u32_array(np, "focaltech,key-x-coords",
+ pdata->key_x_coords,
+ pdata->key_number);
+ if (rc)
+ FTS_ERROR("Key X Coords undefined!");
+
+ FTS_DEBUG("%d: (%d, %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_x_coords[1], pdata->key_x_coords[2],
+ pdata->key_y_coord);
+ }
+
+ /* 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");
+
+ rc = of_property_read_u32(np, "focaltech,max-touch-number", &temp_val);
+ if (!rc) {
+ pdata->max_touch_number = temp_val;
+ FTS_DEBUG("max_touch_number=%d", pdata->max_touch_number);
+ } else {
+ FTS_ERROR("Unable to get max-touch-number");
+ pdata->max_touch_number = FTS_MAX_POINTS;
+ }
+
+ pdata->swap = of_property_read_bool(np, "focaltech,swap-xy");
+ pdata->scaling_down_half = of_property_read_bool(np,
+ "focaltech,scaling-down-half");
+
+ FTS_FUNC_EXIT();
+ return 0;
+}
+
+#if defined(CONFIG_FB)
+/*****************************************************************************
+* Name: fb_notifier_callback
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ struct fb_event *evdata = data;
+ int *blank;
+ struct fts_ts_data *fts_data =
+ container_of(self, struct fts_ts_data, fb_notif);
+
+ if (evdata && evdata->data && event == FB_EVENT_BLANK && fts_data
+ && fts_data->client) {
+ blank = evdata->data;
+ if (*blank == FB_BLANK_UNBLANK)
+ fts_ts_resume(&fts_data->client->dev);
+ else if (*blank == FB_BLANK_POWERDOWN)
+ fts_ts_suspend(&fts_data->client->dev);
+ }
+
+ return 0;
+}
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+/*****************************************************************************
+* Name: fts_ts_early_suspend
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static void fts_ts_early_suspend(struct early_suspend *handler)
+{
+ struct fts_ts_data *data = container_of(handler,
+ struct fts_ts_data,
+ early_suspend);
+
+ fts_ts_suspend(&data->client->dev);
+}
+
+/*****************************************************************************
+* Name: fts_ts_late_resume
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static void fts_ts_late_resume(struct early_suspend *handler)
+{
+ struct fts_ts_data *data = container_of(handler,
+ struct fts_ts_data,
+ early_suspend);
+
+ fts_ts_resume(&data->client->dev);
+}
+#endif
+
+/*****************************************************************************
+* Name: fts_ts_probe
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static int fts_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct fts_ts_platform_data *pdata;
+ struct fts_ts_data *data;
+ struct input_dev *input_dev;
+ int err;
+
+ FTS_FUNC_ENTER();
+ /* 1. Get Platform data */
+ if (client->dev.of_node) {
+ pdata =
+ devm_kzalloc(&client->dev,
+ sizeof(struct fts_ts_platform_data),
+ GFP_KERNEL);
+ if (!pdata) {
+ FTS_ERROR("[MEMORY]Failed to allocate memory");
+ FTS_FUNC_EXIT();
+ return -ENOMEM;
+ }
+ err = fts_parse_dt(&client->dev, pdata);
+ if (err)
+ FTS_ERROR("[DTS]DT parsing failed");
+ } else
+ pdata = client->dev.platform_data;
+
+ if (!pdata) {
+ FTS_ERROR("Invalid pdata");
+ FTS_FUNC_EXIT();
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ FTS_ERROR("I2C not supported");
+ FTS_FUNC_EXIT();
+ return -ENODEV;
+ }
+
+ data =
+ devm_kzalloc(&client->dev, sizeof(struct fts_ts_data), GFP_KERNEL);
+ if (!data) {
+ FTS_ERROR("[MEMORY]Failed to allocate memory");
+ FTS_FUNC_EXIT();
+ return -ENOMEM;
+ }
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ FTS_ERROR("[INPUT]Failed to allocate input device");
+ FTS_FUNC_EXIT();
+ return -ENOMEM;
+ }
+
+ data->input_dev = input_dev;
+ data->client = client;
+ data->pdata = pdata;
+
+ fts_wq_data = data;
+ fts_i2c_client = client;
+ fts_input_dev = input_dev;
+
+ spin_lock_init(&fts_wq_data->irq_lock);
+
+ fts_input_dev_init(client, data, input_dev, pdata);
+
+#if FTS_POWER_SOURCE_CUST_EN
+ fts_power_source_init(data);
+ fts_power_source_ctrl(data, 1);
+#endif
+
+ err = fts_gpio_configure(data);
+ if (err < 0) {
+ FTS_ERROR("[GPIO]Failed to configure the gpios");
+ goto free_gpio;
+ }
+
+ fts_reset_proc(200);
+ fts_wait_tp_to_valid(client);
+
+ err =
+ request_threaded_irq(client->irq, NULL, fts_ts_interrupt,
+ pdata->irq_gpio_flags | IRQF_ONESHOT |
+ IRQF_TRIGGER_FALLING, client->dev.driver->name,
+ data);
+ if (err) {
+ FTS_ERROR("Request irq failed!");
+ goto free_gpio;
+ }
+
+ fts_irq_disable();
+
+#if FTS_PSENSOR_EN
+ if (fts_sensor_init(data) != 0) {
+ FTS_ERROR("fts_sensor_init failed!");
+ FTS_FUNC_EXIT();
+ return 0;
+ }
+#endif
+
+#if FTS_POINT_REPORT_CHECK_EN
+ fts_point_report_check_init();
+#endif
+
+ fts_ex_mode_init(client);
+
+#if FTS_GESTURE_EN
+ fts_gesture_init(input_dev, client);
+#endif
+
+#if FTS_ESDCHECK_EN
+ fts_esdcheck_init();
+#endif
+
+ fts_irq_enable();
+
+#if FTS_TEST_EN
+ fts_test_init(client);
+#endif
+
+#if defined(CONFIG_FB)
+ data->fb_notif.notifier_call = fb_notifier_callback;
+ err = fb_register_client(&data->fb_notif);
+ if (err)
+ FTS_ERROR("[FB]Unable to register fb_notifier: %d", err);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+ data->early_suspend.level =
+ EARLY_SUSPEND_LEVEL_BLANK_SCREEN + FTS_SUSPEND_LEVEL;
+ data->early_suspend.suspend = fts_ts_early_suspend;
+ data->early_suspend.resume = fts_ts_late_resume;
+ register_early_suspend(&data->early_suspend);
+#endif
+
+ FTS_FUNC_EXIT();
+ return 0;
+
+free_gpio:
+ if (gpio_is_valid(pdata->reset_gpio))
+ gpio_free(pdata->reset_gpio);
+ if (gpio_is_valid(pdata->irq_gpio))
+ gpio_free(pdata->irq_gpio);
+ return err;
+
+}
+
+/*****************************************************************************
+* Name: fts_ts_remove
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static int fts_ts_remove(struct i2c_client *client)
+{
+ struct fts_ts_data *data = i2c_get_clientdata(client);
+
+ FTS_FUNC_ENTER();
+ cancel_work_sync(&data->touch_event_work);
+
+#if FTS_PSENSOR_EN
+ fts_sensor_remove(data);
+#endif
+
+#if FTS_POINT_REPORT_CHECK_EN
+ fts_point_report_check_exit();
+#endif
+
+ fts_ex_mode_exit(client);
+
+#if defined(CONFIG_FB)
+ if (fb_unregister_client(&data->fb_notif))
+ FTS_ERROR("Error occurred while unregistering fb_notifier.");
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+ unregister_early_suspend(&data->early_suspend);
+#endif
+ free_irq(client->irq, data);
+
+ if (gpio_is_valid(data->pdata->reset_gpio))
+ gpio_free(data->pdata->reset_gpio);
+
+ if (gpio_is_valid(data->pdata->irq_gpio))
+ gpio_free(data->pdata->irq_gpio);
+
+ input_unregister_device(data->input_dev);
+
+#if FTS_TEST_EN
+ fts_test_exit(client);
+#endif
+
+#if FTS_ESDCHECK_EN
+ fts_esdcheck_exit();
+#endif
+
+ FTS_FUNC_EXIT();
+ return 0;
+}
+
+/*****************************************************************************
+* Name: fts_ts_suspend
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static int fts_ts_suspend(struct device *dev)
+{
+ struct fts_ts_data *data = dev_get_drvdata(dev);
+ int retval = 0;
+
+ FTS_FUNC_ENTER();
+ if (data->suspended) {
+ FTS_INFO("Already in suspend state");
+ FTS_FUNC_EXIT();
+ return -1;
+ }
+
+ fts_release_all_finger();
+
+#if FTS_GESTURE_EN
+ retval = fts_gesture_suspend(data->client);
+ if (retval == 0) {
+ /* Enter into gesture mode(suspend) */
+ retval = enable_irq_wake(fts_wq_data->client->irq);
+ if (retval)
+ FTS_ERROR("%s: set_irq_wake failed", __func__);
+ data->suspended = true;
+ FTS_FUNC_EXIT();
+ return 0;
+ }
+#endif
+
+#if FTS_PSENSOR_EN
+ if (fts_sensor_suspend(data) != 0) {
+ enable_irq_wake(data->client->irq);
+ data->suspended = true;
+ return 0;
+ }
+#endif
+
+#if FTS_ESDCHECK_EN
+ fts_esdcheck_suspend();
+#endif
+
+ fts_irq_disable();
+
+ /* TP enter sleep mode */
+ retval =
+ fts_i2c_write_reg(data->client, FTS_REG_POWER_MODE,
+ FTS_REG_POWER_MODE_SLEEP_VALUE);
+ if (retval < 0)
+ FTS_ERROR("Set TP to sleep mode fail, ret=%d!", retval);
+ data->suspended = true;
+
+ FTS_FUNC_EXIT();
+
+ return 0;
+}
+
+/*****************************************************************************
+* Name: fts_ts_resume
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static int fts_ts_resume(struct device *dev)
+{
+ struct fts_ts_data *data = dev_get_drvdata(dev);
+
+ FTS_FUNC_ENTER();
+ if (!data->suspended) {
+ FTS_DEBUG("Already in awake state");
+ FTS_FUNC_EXIT();
+ return -1;
+ }
+
+ if (!fts_chip_idc(data))
+ fts_reset_proc(200);
+
+ fts_tp_state_recovery(data->client);
+
+#if FTS_GESTURE_EN
+ if (fts_gesture_resume(data->client) == 0) {
+ int err;
+
+ err = disable_irq_wake(data->client->irq);
+ if (err)
+ FTS_ERROR("%s: disable_irq_wake failed", __func__);
+ data->suspended = false;
+ FTS_FUNC_EXIT();
+ return 0;
+ }
+#endif
+
+#if FTS_PSENSOR_EN
+ if (fts_sensor_resume(data) != 0) {
+ disable_irq_wake(data->client->irq);
+ data->suspended = false;
+ FTS_FUNC_EXIT();
+ return 0;
+ }
+#endif
+
+ data->suspended = false;
+
+ fts_irq_enable();
+
+#if FTS_ESDCHECK_EN
+ fts_esdcheck_resume();
+#endif
+ FTS_FUNC_EXIT();
+ return 0;
+}
+
+/*****************************************************************************
+* I2C Driver
+*****************************************************************************/
+static const struct i2c_device_id fts_ts_id[] = {
+ {FTS_DRIVER_NAME, 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, fts_ts_id);
+
+static struct of_device_id fts_match_table[] = {
+ {.compatible = "focaltech,fts",},
+ {},
+};
+
+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 = fts_match_table,
+ },
+ .id_table = fts_ts_id,
+};
+
+/*****************************************************************************
+* Name: fts_ts_init
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+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;
+}
+
+/*****************************************************************************
+* Name: fts_ts_exit
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+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/drivers/input/touchscreen/focaltech_touch/focaltech_core.h b/drivers/input/touchscreen/focaltech_touch/focaltech_core.h
new file mode 100644
index 000000000000..b8ef41f58420
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/focaltech_core.h
@@ -0,0 +1,189 @@
+/*
+ *
+ * FocalTech TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, 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 <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/firmware.h>
+#include <linux/debugfs.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/workqueue.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/init.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/mount.h>
+#include <linux/netdevice.h>
+#include <linux/unistd.h>
+#include <linux/ioctl.h>
+#include "focaltech_common.h"
+
+/*****************************************************************************
+* Private constant and macro definitions using #define
+*****************************************************************************/
+#define LEN_FLASH_ECC_MAX 0xFFFE
+
+#define FTS_WORKQUEUE_NAME "fts_wq"
+
+#define FTS_MAX_POINTS 10
+#define FTS_KEY_WIDTH 50
+#define FTS_ONE_TCH_LEN 6
+#define POINT_READ_BUF (3 + FTS_ONE_TCH_LEN * FTS_MAX_POINTS)
+
+#define FTS_MAX_ID 0x0F
+#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_TOUCH_DOWN 0
+#define FTS_TOUCH_UP 1
+#define FTS_TOUCH_CONTACT 2
+
+#define FTS_SYSFS_ECHO_ON(buf) ((strnicmp(buf, "1", 1) == 0) || \
+ (strnicmp(buf, "on", 2) == 0))
+#define FTS_SYSFS_ECHO_OFF(buf) ((strnicmp(buf, "0", 1) == 0) || \
+ (strnicmp(buf, "off", 3) == 0))
+
+/*****************************************************************************
+* Private enumerations, structures and unions using typedef
+*****************************************************************************/
+
+struct fts_ts_platform_data {
+ u32 fts_chip_type;
+ u32 irq_gpio;
+ u32 irq_gpio_flags;
+ u32 reset_gpio;
+ u32 reset_gpio_flags;
+ bool have_key;
+ u32 key_number;
+ u32 keys[4];
+ u32 key_y_coord;
+ u32 key_x_coords[4];
+ u32 x_max;
+ u32 y_max;
+ u32 x_min;
+ u32 y_min;
+ u32 max_touch_number;
+
+ bool swap;
+ bool scaling_down_half;
+};
+
+struct ts_event {
+ u16 au16_x[FTS_MAX_POINTS]; /*x coordinate */
+ u16 au16_y[FTS_MAX_POINTS]; /*y coordinate */
+ u16 pressure[FTS_MAX_POINTS];
+ /* touch event: 0 -- down; 1-- up; 2 -- contact */
+ u8 au8_touch_event[FTS_MAX_POINTS];
+ u8 au8_finger_id[FTS_MAX_POINTS]; /*touch ID */
+ u8 area[FTS_MAX_POINTS];
+ u8 touch_point;
+ u8 point_num;
+};
+
+struct fts_ts_data {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ struct ts_event event;
+ const struct fts_ts_platform_data *pdata;
+#if FTS_PSENSOR_EN
+ struct fts_psensor_platform_data *psensor_pdata;
+#endif
+ struct work_struct touch_event_work;
+ struct workqueue_struct *ts_workqueue;
+ struct regulator *vdd;
+ struct regulator *vcc_i2c;
+ spinlock_t irq_lock;
+ u16 addr;
+ bool suspended;
+ u8 fw_ver[3];
+ u8 fw_vendor_id;
+ int touchs;
+ int irq_disable;
+
+#if defined(CONFIG_FB)
+ struct notifier_block fb_notif;
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+ struct early_suspend early_suspend;
+#endif
+};
+
+#if FTS_PSENSOR_EN
+struct fts_psensor_platform_data {
+ struct input_dev *input_psensor_dev;
+ struct sensors_classdev ps_cdev;
+ int tp_psensor_opened;
+ char tp_psensor_data; /* 0 near, 1 far */
+ struct fts_ts_data *data;
+};
+
+int fts_sensor_init(struct fts_ts_data *data);
+int fts_sensor_read_data(struct fts_ts_data *data);
+int fts_sensor_suspend(struct fts_ts_data *data);
+int fts_sensor_resume(struct fts_ts_data *data);
+int fts_sensor_remove(struct fts_ts_data *data);
+#endif
+
+/*****************************************************************************
+* Static variables
+*****************************************************************************/
+extern struct i2c_client *fts_i2c_client;
+extern struct fts_ts_data *fts_wq_data;
+extern struct input_dev *fts_input_dev;
+
+#endif /* __LINUX_FOCALTECH_CORE_H__ */
diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_esdcheck.c b/drivers/input/touchscreen/focaltech_touch/focaltech_esdcheck.c
new file mode 100644
index 000000000000..565507d02523
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/focaltech_esdcheck.c
@@ -0,0 +1,473 @@
+/*
+ *
+ * FocalTech TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, 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: luoguojin
+*
+* Created: 2016-08-03
+*
+* Abstract: ESD check function
+*
+* Version: v1.0
+*
+* Revision History:
+* v1.0:
+* First release. By luougojin 2016-08-03
+*****************************************************************************/
+
+/*****************************************************************************
+* Included header files
+*****************************************************************************/
+#include "focaltech_core.h"
+
+#if FTS_ESDCHECK_EN
+/*****************************************************************************
+* Private constant and macro definitions using #define
+*****************************************************************************/
+#define ESDCHECK_WAIT_TIME 1000
+
+/*****************************************************************************
+* Private enumerations, structures and unions using typedef
+*****************************************************************************/
+struct fts_esdcheck_st {
+ u8 active:1;
+ u8 suspend:1;
+ u8 proc_debug:1; /* apk or adb is accessing I2C */
+ u8 intr:1; /* 1- Interrupt trigger */
+ u8 unused:4;
+ u8 flow_work_hold_cnt;
+ u8 flow_work_cnt_last;
+ u32 hardware_reset_cnt;
+ u32 i2c_nack_cnt;
+ u32 i2c_dataerror_cnt;
+};
+
+/*****************************************************************************
+* Static variables
+*****************************************************************************/
+static struct delayed_work fts_esdcheck_work;
+static struct workqueue_struct *fts_esdcheck_workqueue;
+static struct fts_esdcheck_st fts_esdcheck_data;
+
+/*****************************************************************************
+* Global variable or extern global variabls/functions
+*****************************************************************************/
+
+/*****************************************************************************
+* Static function prototypes
+*****************************************************************************/
+
+/*****************************************************************************
+* functions body
+*****************************************************************************/
+/*****************************************************************************
+* Name: lcd_esdcheck
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+int lcd_need_reset;
+static int tp_need_recovery; /* LCD reset cause Tp reset */
+int idc_esdcheck_lcderror(void)
+{
+ u8 val;
+ int ret;
+
+ FTS_DEBUG("[ESD]Check LCD ESD");
+ if ((tp_need_recovery == 1) && (lcd_need_reset == 0)) {
+ tp_need_recovery = 0;
+ /* LCD reset, need recover TP state */
+ fts_tp_state_recovery(fts_i2c_client);
+ }
+
+ ret = fts_i2c_read_reg(fts_i2c_client, FTS_REG_ESD_SATURATE, &val);
+ if (ret < 0) {
+ FTS_ERROR("[ESD]: Read ESD_SATURATE(0xED) failed 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, Execute LCD reset!");
+ lcd_need_reset = 1;
+ tp_need_recovery = 1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+* Name: fts_esdcheck_tp_reset
+* Brief: esd check algorithm
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static int fts_esdcheck_tp_reset(void)
+{
+ FTS_FUNC_ENTER();
+
+ fts_esdcheck_data.flow_work_hold_cnt = 0;
+ fts_esdcheck_data.hardware_reset_cnt++;
+
+ fts_reset_proc(200);
+ fts_tp_state_recovery(fts_i2c_client);
+
+ FTS_FUNC_EXIT();
+ return 0;
+}
+
+/*****************************************************************************
+* Name: get_chip_id
+* Brief: Read Chip Id 3 times
+* Input:
+* Output:
+* Return: 1 - Read Chip Id 3 times failed
+* 0 - Read Chip Id pass
+*****************************************************************************/
+static bool get_chip_id(void)
+{
+ int err = 0;
+ int i = 0;
+ u8 reg_value = 0;
+ u8 reg_addr = 0;
+
+ for (i = 0; i < 3; i++) {
+ reg_addr = FTS_REG_CHIP_ID;
+ err = fts_i2c_read(fts_i2c_client, &reg_addr, 1, &reg_value, 1);
+
+ if (err < 0) {
+ FTS_ERROR("[ESD]: Read Reg 0xA3 failed ret = %d!!",
+ err);
+ fts_esdcheck_data.i2c_nack_cnt++;
+ } else {
+ /* Upgrade sometimes can't detect */
+ if ((reg_value == chip_types.chip_idh)
+ || (reg_value == 0xEF))
+ break;
+ else
+ fts_esdcheck_data.i2c_dataerror_cnt++;
+ }
+ }
+
+ /* if can't get correct data in 3 times, then need hardware reset */
+ if (i >= 3) {
+ FTS_ERROR
+ ("[ESD]: Read Chip id 3 times failed,"
+ "need execute TP reset!!");
+ return 1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+* Name: get_flow_cnt
+* Brief: Read flow cnt(0x91)
+* Input:
+* Output:
+* Return: 1 - Reg 0x91(flow cnt) abnormal: hold a value for 5 times
+* 0 - Reg 0x91(flow cnt) normal
+*****************************************************************************/
+static bool get_flow_cnt(void)
+{
+ int err = 0;
+ u8 reg_value = 0;
+ u8 reg_addr = 0;
+
+ reg_addr = FTS_REG_FLOW_WORK_CNT;
+ err = fts_i2c_read(fts_i2c_client, &reg_addr, 1, &reg_value, 1);
+ if (err < 0) {
+ FTS_ERROR("[ESD]: Read Reg 0x91 failed ret = %d!!", err);
+ fts_esdcheck_data.i2c_nack_cnt++;
+ } else {
+ if (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;
+ }
+
+ /*
+ * if read flow work cnt 5 times and the value are
+ * all the same, then need hardware_reset
+ */
+ if (fts_esdcheck_data.flow_work_hold_cnt >= 5) {
+ FTS_DEBUG("[ESD]: Flow Work Cnt(reg0x91) keep a value"
+ "for 5 times, need execute TP reset!!");
+ return 1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+* Name: esdcheck_algorithm
+* Brief: esd check algorithm
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static int esdcheck_algorithm(void)
+{
+ int err = 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_INFO("[ESD]: In interrupt state,"
+ "not check esd, return immediately!!");
+ return 0;
+ }
+
+ /* 2. check power state, if suspend, no need check esd */
+ if (fts_esdcheck_data.suspend == 1) {
+ FTS_INFO("[ESD]: In suspend, not check esd,"
+ "return immediately!!");
+ /* 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
+ */
+ fts_esdcheck_data.active = 0;
+ 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("[ESD]: In apk or adb command mode,"
+ "not check esd, return immediately!!");
+ return 0;
+ }
+
+ /* 4. In factory mode, can't check esd */
+ reg_addr = FTS_REG_WORKMODE;
+ err = fts_i2c_read(fts_i2c_client, &reg_addr, 1, &reg_value, 1);
+ if (err < 0) {
+ fts_esdcheck_data.i2c_nack_cnt++;
+ } else if ((reg_value & 0x70) == FTS_REG_WORKMODE_FACTORY_VALUE) {
+ FTS_INFO("[ESD]: In factory mode,"
+ "not check esd, return immediately!!");
+ return 0;
+ }
+
+ /* 5. Get Chip ID */
+ hardware_reset = get_chip_id();
+
+ /*
+ * 6. get Flow work cnt: 0x91 If no change for 5 times,
+ * then ESD and reset
+ */
+ if (!hardware_reset)
+ hardware_reset = get_flow_cnt();
+
+ /* 7. If need hardware reset, then handle it here */
+ if (hardware_reset == 1)
+ fts_esdcheck_tp_reset();
+
+ FTS_INFO("[ESD]: NoACK=%d, Error Data=%d, Hardware Reset=%d\n",
+ fts_esdcheck_data.i2c_nack_cnt,
+ fts_esdcheck_data.i2c_dataerror_cnt,
+ fts_esdcheck_data.hardware_reset_cnt);
+ return 0;
+}
+
+/*****************************************************************************
+* Name: fts_esdcheck_func
+* Brief: fts_esdcheck_func
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static void esdcheck_func(struct work_struct *work)
+{
+ FTS_FUNC_ENTER();
+
+ idc_esdcheck_lcderror();
+
+ esdcheck_algorithm();
+
+ if (fts_esdcheck_data.suspend == 0) {
+ queue_delayed_work(fts_esdcheck_workqueue, &fts_esdcheck_work,
+ msecs_to_jiffies(ESDCHECK_WAIT_TIME));
+ }
+
+ FTS_FUNC_EXIT();
+}
+
+/*****************************************************************************
+* Name: fts_esdcheck_set_intr
+* Brief: interrupt flag (main used in interrupt tp report)
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+int fts_esdcheck_set_intr(bool intr)
+{
+ /* interrupt don't add debug message */
+ fts_esdcheck_data.intr = intr;
+ return 0;
+}
+
+/*****************************************************************************
+* Name: fts_esdcheck_get_status(void)
+* Brief: get current status
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+int fts_esdcheck_get_status(void)
+{
+ /* interrupt don't add debug message */
+ return fts_esdcheck_data.active;
+}
+
+/*****************************************************************************
+* 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)
+{
+ FTS_FUNC_ENTER();
+ if (enable == 1) {
+ if (fts_esdcheck_data.active == 0) {
+ FTS_INFO("[ESD]: ESD check start!!");
+ fts_esdcheck_data.active = 1;
+ queue_delayed_work(fts_esdcheck_workqueue,
+ &fts_esdcheck_work,
+ msecs_to_jiffies
+ (ESDCHECK_WAIT_TIME));
+ }
+ } else {
+ if (fts_esdcheck_data.active == 1) {
+ FTS_INFO("[ESD]: ESD check stop!!");
+ fts_esdcheck_data.active = 0;
+ cancel_delayed_work_sync(&fts_esdcheck_work);
+ }
+ }
+
+ FTS_FUNC_EXIT();
+ return 0;
+}
+
+/*****************************************************************************
+* Name: fts_esdcheck_suspend
+* Brief: Run when tp enter into suspend
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+int fts_esdcheck_suspend(void)
+{
+ FTS_FUNC_ENTER();
+ fts_esdcheck_switch(DISABLE);
+ fts_esdcheck_data.suspend = 1;
+ FTS_FUNC_EXIT();
+ return 0;
+}
+
+/*****************************************************************************
+* Name: fts_esdcheck_resume
+* Brief: Run when tp resume
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+int fts_esdcheck_resume(void)
+{
+ FTS_FUNC_ENTER();
+ fts_esdcheck_switch(ENABLE);
+ fts_esdcheck_data.suspend = 0;
+ FTS_FUNC_EXIT();
+ return 0;
+}
+
+/*****************************************************************************
+* Name: fts_esdcheck_init
+* Brief: Init and create a queue work to check esd
+* Input:
+* Output:
+* Return: < 0: Fail to create esd check queue
+*****************************************************************************/
+int fts_esdcheck_init(void)
+{
+ FTS_FUNC_ENTER();
+
+ INIT_DELAYED_WORK(&fts_esdcheck_work, esdcheck_func);
+ fts_esdcheck_workqueue = create_workqueue("fts_esdcheck_wq");
+ if (fts_esdcheck_workqueue == NULL)
+ FTS_INFO("[ESD]: Failed to create esd work queue!!");
+
+ memset((u8 *) &fts_esdcheck_data, 0, sizeof(struct fts_esdcheck_st));
+
+ fts_esdcheck_switch(ENABLE);
+ FTS_FUNC_EXIT();
+ return 0;
+}
+
+/*****************************************************************************
+* Name: fts_esdcheck_exit
+* Brief: When FTS TP driver is removed,
+* then call this function to destroy work queue
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+int fts_esdcheck_exit(void)
+{
+ FTS_FUNC_ENTER();
+
+ destroy_workqueue(fts_esdcheck_workqueue);
+
+ FTS_FUNC_EXIT();
+ return 0;
+}
+#endif /* FTS_ESDCHECK_EN */
diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_ex_mode.c b/drivers/input/touchscreen/focaltech_touch/focaltech_ex_mode.c
new file mode 100644
index 000000000000..6ab5d47170cc
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/focaltech_ex_mode.c
@@ -0,0 +1,357 @@
+/*
+ *
+ * FocalTech ftxxxx TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, 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: Liu WeiGuang
+*
+* 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
+*****************************************************************************/
+struct fts_mode_flag {
+ int fts_glove_mode_flag;
+ int fts_cover_mode_flag;
+ int fts_charger_mode_flag;
+};
+
+struct fts_mode_flag g_fts_mode_flag;
+
+/*****************************************************************************
+* 4.Static variables
+*****************************************************************************/
+
+/*****************************************************************************
+* 5.Global variable or extern global variabls/functions
+*****************************************************************************/
+int fts_enter_glove_mode(struct i2c_client *client, int mode);
+int fts_glove_init(struct i2c_client *client);
+int fts_glove_exit(struct i2c_client *client);
+
+int fts_enter_cover_mode(struct i2c_client *client, int mode);
+int fts_cover_init(struct i2c_client *client);
+int fts_cover_exit(struct i2c_client *client);
+
+int fts_enter_charger_mode(struct i2c_client *client, int mode);
+int fts_charger_init(struct i2c_client *client);
+int fts_charger_exit(struct i2c_client *client);
+
+/*****************************************************************************
+* 6.Static function prototypes
+*******************************************************************************/
+
+#if FTS_GLOVE_EN
+static ssize_t fts_touch_glove_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "Glove: %s\n",
+ g_fts_mode_flag.fts_glove_mode_flag ? "On" : "Off");
+}
+
+static ssize_t fts_touch_glove_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+
+ if (FTS_SYSFS_ECHO_ON(buf)) {
+ if (!g_fts_mode_flag.fts_glove_mode_flag) {
+ FTS_INFO("[Mode]enter glove mode");
+ ret = fts_enter_glove_mode(fts_i2c_client, true);
+ if (ret >= 0)
+ g_fts_mode_flag.fts_glove_mode_flag = true;
+ }
+ } else if (FTS_SYSFS_ECHO_OFF(buf)) {
+ if (g_fts_mode_flag.fts_glove_mode_flag) {
+ FTS_INFO("[Mode]exit glove mode");
+ ret = fts_enter_glove_mode(fts_i2c_client, false);
+ if (ret >= 0)
+ g_fts_mode_flag.fts_glove_mode_flag = false;
+ }
+ }
+ FTS_INFO("[Mode]glove mode status: %d",
+ g_fts_mode_flag.fts_glove_mode_flag);
+ return count;
+}
+
+/************************************************************************
+* Name: fts_enter_glove_mode
+* Brief: change glove mode
+* Input: glove mode
+* Output: no
+* Return: success >=0, otherwise failed
+***********************************************************************/
+int fts_enter_glove_mode(struct i2c_client *client, int mode)
+{
+ int ret = 0;
+ static u8 buf_addr[2] = { 0 };
+ static u8 buf_value[2] = { 0 };
+
+ buf_addr[0] = FTS_REG_GLOVE_MODE_EN;
+
+ if (mode)
+ buf_value[0] = 0x01;
+ else
+ buf_value[0] = 0x00;
+
+ ret = fts_i2c_write_reg(client, buf_addr[0], buf_value[0]);
+ if (ret < 0)
+ FTS_ERROR("[Mode]fts_enter_glove_mode write value fail");
+
+ return ret;
+
+}
+
+/* read and write glove mode
+* read example: cat fts_touch_glove_mode---read glove mode
+* write example:echo 01 > fts_touch_glove_mode ---write glove mode to 01
+*
+*/
+static DEVICE_ATTR(fts_glove_mode, S_IRUGO | S_IWUSR, fts_touch_glove_show,
+ fts_touch_glove_store);
+
+#endif
+
+#if FTS_COVER_EN
+static ssize_t fts_touch_cover_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "Cover: %s\n",
+ g_fts_mode_flag.fts_cover_mode_flag ? "On" : "Off");
+}
+
+static ssize_t fts_touch_cover_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+
+ if (FTS_SYSFS_ECHO_ON(buf)) {
+ if (!g_fts_mode_flag.fts_cover_mode_flag) {
+ FTS_INFO("[Mode]enter cover mode");
+ ret = fts_enter_cover_mode(fts_i2c_client, true);
+ if (ret >= 0)
+ g_fts_mode_flag.fts_cover_mode_flag = true;
+ }
+ } else if (FTS_SYSFS_ECHO_OFF(buf)) {
+ if (g_fts_mode_flag.fts_cover_mode_flag) {
+ FTS_INFO("[Mode]exit cover mode");
+ ret = fts_enter_cover_mode(fts_i2c_client, false);
+ if (ret >= 0)
+ g_fts_mode_flag.fts_cover_mode_flag = false;
+ }
+ }
+ FTS_INFO("[Mode]cover mode status: %d",
+ g_fts_mode_flag.fts_cover_mode_flag);
+ return count;
+}
+
+/************************************************************************
+* Name: fts_enter_cover_mode
+* Brief: change cover mode
+* Input: cover mode
+* Output: no
+* Return: success >=0, otherwise failed
+***********************************************************************/
+int fts_enter_cover_mode(struct i2c_client *client, int mode)
+{
+ int ret = 0;
+ static u8 buf_addr[2] = { 0 };
+ static u8 buf_value[2] = { 0 };
+
+ buf_addr[0] = FTS_REG_COVER_MODE_EN;
+
+ if (mode)
+ buf_value[0] = 0x01;
+ else
+ buf_value[0] = 0x00;
+
+ ret = fts_i2c_write_reg(client, buf_addr[0], buf_value[0]);
+ if (ret < 0)
+ FTS_ERROR("[Mode] fts_enter_cover_mode write value fail\n");
+
+ return ret;
+
+}
+
+/* read and write cover mode
+* read example: cat fts_touch_cover_mode---read cover mode
+* write example:echo 01 > fts_touch_cover_mode ---write cover mode to 01
+*
+*/
+static DEVICE_ATTR(fts_cover_mode, S_IRUGO | S_IWUSR, fts_touch_cover_show,
+ fts_touch_cover_store);
+
+#endif
+
+#if FTS_CHARGER_EN
+static ssize_t fts_touch_charger_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "Charger: %s\n",
+ g_fts_mode_flag.fts_charger_mode_flag ? "On" : "Off");
+}
+
+static ssize_t fts_touch_charger_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+
+ if (FTS_SYSFS_ECHO_ON(buf)) {
+ if (!g_fts_mode_flag.fts_charger_mode_flag) {
+ FTS_INFO("[Mode]enter charger mode");
+ ret = fts_enter_charger_mode(fts_i2c_client, true);
+ if (ret >= 0)
+ g_fts_mode_flag.fts_charger_mode_flag = true;
+ }
+ } else if (FTS_SYSFS_ECHO_OFF(buf)) {
+ if (g_fts_mode_flag.fts_charger_mode_flag) {
+ FTS_INFO("[Mode]exit charger mode");
+ ret = fts_enter_charger_mode(fts_i2c_client, false);
+ if (ret >= 0)
+ g_fts_mode_flag.fts_charger_mode_flag = false;
+ }
+ }
+ FTS_INFO("[Mode]charger mode status: %d",
+ g_fts_mode_flag.fts_charger_mode_flag);
+ return count;
+}
+
+/************************************************************************
+* Name: fts_enter_charger_mode
+* Brief: change charger mode
+* Input: charger mode
+* Output: no
+* Return: success >=0, otherwise failed
+***********************************************************************/
+int fts_enter_charger_mode(struct i2c_client *client, int mode)
+{
+ int ret = 0;
+ static u8 buf_addr[2] = { 0 };
+ static u8 buf_value[2] = { 0 };
+
+ buf_addr[0] = FTS_REG_CHARGER_MODE_EN;
+
+ if (mode)
+ buf_value[0] = 0x01;
+ else
+ buf_value[0] = 0x00;
+
+ ret = fts_i2c_write_reg(client, buf_addr[0], buf_value[0]);
+ if (ret < 0)
+ FTS_DEBUG("[Mode]fts_enter_charger_mode write value fail");
+
+ return ret;
+
+}
+
+/* read and write charger mode
+* read example: cat fts_touch_charger_mode---read charger mode
+* write example:echo 01 > fts_touch_charger_mode ---write charger mode to 01
+*
+*/
+static DEVICE_ATTR(fts_charger_mode, S_IRUGO | S_IWUSR, fts_touch_charger_show,
+ fts_touch_charger_store);
+
+#endif
+
+static struct attribute *fts_touch_mode_attrs[] = {
+#if FTS_GLOVE_EN
+ &dev_attr_fts_glove_mode.attr,
+#endif
+
+#if FTS_COVER_EN
+ &dev_attr_fts_cover_mode.attr,
+#endif
+
+#if FTS_CHARGER_EN
+ &dev_attr_fts_charger_mode.attr,
+#endif
+
+ NULL,
+};
+
+static struct attribute_group fts_touch_mode_group = {
+ .attrs = fts_touch_mode_attrs,
+};
+
+int fts_ex_mode_init(struct i2c_client *client)
+{
+ int err = 0;
+
+ g_fts_mode_flag.fts_glove_mode_flag = false;
+ g_fts_mode_flag.fts_cover_mode_flag = false;
+ g_fts_mode_flag.fts_charger_mode_flag = false;
+
+ err = sysfs_create_group(&client->dev.kobj, &fts_touch_mode_group);
+ if (0 != err) {
+ FTS_ERROR("[Mode]create sysfs failed.");
+ sysfs_remove_group(&client->dev.kobj, &fts_touch_mode_group);
+ return -EIO;
+ }
+
+ FTS_DEBUG("[Mode]create sysfs succeeded");
+
+ return err;
+
+}
+
+int fts_ex_mode_exit(struct i2c_client *client)
+{
+ sysfs_remove_group(&client->dev.kobj, &fts_touch_mode_group);
+ return 0;
+}
+
+int fts_ex_mode_recovery(struct i2c_client *client)
+{
+ int ret = 0;
+#if FTS_GLOVE_EN
+ if (g_fts_mode_flag.fts_glove_mode_flag)
+ ret = fts_enter_glove_mode(client, true);
+#endif
+
+#if FTS_COVER_EN
+ if (g_fts_mode_flag.fts_cover_mode_flag)
+ ret = fts_enter_cover_mode(client, true);
+#endif
+
+#if FTS_CHARGER_EN
+ if (g_fts_mode_flag.fts_charger_mode_flag)
+ ret = fts_enter_charger_mode(client, true);
+#endif
+
+ return ret;
+}
diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_gesture.c b/drivers/input/touchscreen/focaltech_touch/focaltech_gesture.c
new file mode 100644
index 000000000000..9faabb8681bb
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/focaltech_gesture.c
@@ -0,0 +1,652 @@
+/*
+ *
+ * FocalTech TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, 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"
+#if FTS_GESTURE_EN
+/******************************************************************************
+* 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
+#define FTS_GESTRUE_POINTS 255
+#define FTS_GESTRUE_POINTS_HEADER 8
+#define FTS_GESTURE_OUTPUT_ADRESS 0xD3
+/*****************************************************************************
+* Private enumerations, structures and unions using typedef
+*****************************************************************************/
+struct fts_gesture_st {
+ u8 header[FTS_GESTRUE_POINTS_HEADER];
+ u16 coordinate_x[FTS_GESTRUE_POINTS];
+ u16 coordinate_y[FTS_GESTRUE_POINTS];
+ u8 mode;
+ u8 active;
+};
+
+/*****************************************************************************
+* Static variables
+*****************************************************************************/
+static struct fts_gesture_st fts_gesture_data;
+extern struct fts_ts_data *fts_wq_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);
+static ssize_t fts_gesture_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count);
+static ssize_t fts_gesture_buf_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+static ssize_t fts_gesture_buf_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count);
+
+/* sysfs gesture node
+ * read example: cat fts_gesture_mode ---read gesture mode
+ * write example:echo 01 > fts_gesture_mode ---write gesture mode to 01
+ *
+ */
+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,
+};
+
+/************************************************************************
+* Name: fts_gesture_show
+* Brief: no
+* Input: device, device attribute, char buf
+* Output: no
+* Return:
+***********************************************************************/
+static ssize_t fts_gesture_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int count;
+ u8 val;
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ mutex_lock(&fts_input_dev->mutex);
+ fts_i2c_read_reg(client, FTS_REG_GESTURE_EN, &val);
+ count =
+ sprintf(buf, "Gesture Mode: %s\n",
+ fts_gesture_data.mode ? "On" : "Off");
+ count += sprintf(buf + count, "Reg(0xD0) = %d\n", val);
+ mutex_unlock(&fts_input_dev->mutex);
+
+ return count;
+}
+
+/************************************************************************
+* Name: fts_gesture_store
+* Brief: no
+* Input: device, device attribute, char buf, char count
+* Output: no
+* Return:
+***********************************************************************/
+static ssize_t fts_gesture_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ mutex_lock(&fts_input_dev->mutex);
+
+ if (FTS_SYSFS_ECHO_ON(buf)) {
+ FTS_INFO("[GESTURE]enable gesture");
+ fts_gesture_data.mode = ENABLE;
+ } else if (FTS_SYSFS_ECHO_OFF(buf)) {
+ FTS_INFO("[GESTURE]disable gesture");
+ fts_gesture_data.mode = DISABLE;
+ }
+
+ mutex_unlock(&fts_input_dev->mutex);
+
+ return count;
+}
+
+/************************************************************************
+* Name: fts_gesture_buf_show
+* Brief: no
+* Input: device, device attribute, char buf
+* Output: no
+* Return:
+***********************************************************************/
+static ssize_t fts_gesture_buf_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int count;
+ int i = 0;
+
+ mutex_lock(&fts_input_dev->mutex);
+ count =
+ snprintf(buf, PAGE_SIZE, "Gesture ID: 0x%x\n",
+ fts_gesture_data.header[0]);
+ count +=
+ snprintf(buf + count, PAGE_SIZE, "Gesture PointNum: %d\n",
+ fts_gesture_data.header[1]);
+ count += snprintf(buf + count, PAGE_SIZE, "Gesture Point Buf:\n");
+ for (i = 0; i < fts_gesture_data.header[1]; i++) {
+ count +=
+ snprintf(buf + count, PAGE_SIZE, "%3d(%4d,%4d) ", i,
+ fts_gesture_data.coordinate_x[i],
+ fts_gesture_data.coordinate_y[i]);
+ if ((i + 1) % 4 == 0)
+ count += snprintf(buf + count, PAGE_SIZE, "\n");
+ }
+ count += snprintf(buf + count, PAGE_SIZE, "\n");
+ mutex_unlock(&fts_input_dev->mutex);
+
+ return count;
+}
+
+/************************************************************************
+* Name: fts_gesture_buf_store
+* Brief: no
+* Input: device, device attribute, char buf, char count
+* Output: no
+* Return:
+***********************************************************************/
+static ssize_t fts_gesture_buf_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ /* place holder for future use */
+ return -EPERM;
+}
+
+/*****************************************************************************
+* Name: fts_create_gesture_sysfs
+* Brief:
+* Input:
+* Output: None
+* Return: 0-success or error
+*****************************************************************************/
+int fts_create_gesture_sysfs(struct i2c_client *client)
+{
+ int ret = 0;
+
+ ret = sysfs_create_group(&client->dev.kobj, &fts_gesture_group);
+ if (ret != 0) {
+ FTS_ERROR
+ ("[GESTURE]fts_gesture_mode_group(sysfs) create failed!");
+ sysfs_remove_group(&client->dev.kobj, &fts_gesture_group);
+ return ret;
+ }
+ return 0;
+}
+
+/*****************************************************************************
+* Name: fts_gesture_recovery
+* Brief: recovery gesture state when reset
+* Input:
+* Output: None
+* Return:
+*****************************************************************************/
+void fts_gesture_recovery(struct i2c_client *client)
+{
+ if (fts_gesture_data.mode && fts_gesture_data.active) {
+ fts_i2c_write_reg(client, 0xD1, 0xff);
+ fts_i2c_write_reg(client, 0xD2, 0xff);
+ fts_i2c_write_reg(client, 0xD5, 0xff);
+ fts_i2c_write_reg(client, 0xD6, 0xff);
+ fts_i2c_write_reg(client, 0xD7, 0xff);
+ fts_i2c_write_reg(client, 0xD8, 0xff);
+ fts_i2c_write_reg(client, FTS_REG_GESTURE_EN, ENABLE);
+ }
+}
+
+/*****************************************************************************
+* Name: fts_gesture_init
+* Brief:
+* Input:
+* Output: None
+* Return: None
+*****************************************************************************/
+int fts_gesture_init(struct input_dev *input_dev, struct i2c_client *client)
+{
+ 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(client);
+ fts_gesture_data.mode = 0;
+ fts_gesture_data.active = 0;
+ FTS_FUNC_EXIT();
+ return 0;
+}
+
+/************************************************************************
+* Name: fts_gesture_exit
+* Brief: remove sys
+* Input: i2c info
+* Output: no
+* Return: no
+***********************************************************************/
+int fts_gesture_exit(struct i2c_client *client)
+{
+ sysfs_remove_group(&client->dev.kobj, &fts_gesture_group);
+ return 0;
+}
+
+/*****************************************************************************
+* Name: fts_check_gesture
+* Brief:
+* Input:
+* Output: None
+* Return: None
+*****************************************************************************/
+static void fts_check_gesture(struct input_dev *input_dev, int gesture_id)
+{
+ char *envp[2];
+ int gesture;
+
+ FTS_FUNC_ENTER();
+ switch (gesture_id) {
+ case GESTURE_LEFT:
+ envp[0] = "GESTURE=LEFT";
+ gesture = KEY_GESTURE_LEFT;
+ break;
+ case GESTURE_RIGHT:
+ envp[0] = "GESTURE=RIGHT";
+ gesture = KEY_GESTURE_RIGHT;
+ break;
+ case GESTURE_UP:
+ envp[0] = "GESTURE=UP";
+ gesture = KEY_GESTURE_UP;
+ break;
+ case GESTURE_DOWN:
+ envp[0] = "GESTURE=DOWN";
+ gesture = KEY_GESTURE_DOWN;
+ break;
+ case GESTURE_DOUBLECLICK:
+ envp[0] = "GESTURE=DOUBLE_CLICK";
+ gesture = KEY_POWER;
+ break;
+ case GESTURE_O:
+ envp[0] = "GESTURE=O";
+ gesture = KEY_GESTURE_O;
+ break;
+ case GESTURE_W:
+ envp[0] = "GESTURE=W";
+ gesture = KEY_GESTURE_W;
+ break;
+ case GESTURE_M:
+ envp[0] = "GESTURE=M";
+ gesture = KEY_GESTURE_M;
+ break;
+ case GESTURE_E:
+ envp[0] = "GESTURE=E";
+ gesture = KEY_GESTURE_E;
+ break;
+ case GESTURE_L:
+ envp[0] = "GESTURE=L";
+ gesture = KEY_GESTURE_L;
+ break;
+ case GESTURE_S:
+ envp[0] = "GESTURE=S";
+ gesture = KEY_GESTURE_S;
+ break;
+ case GESTURE_V:
+ envp[0] = "GESTURE=V";
+ gesture = KEY_GESTURE_V;
+ break;
+ case GESTURE_Z:
+ envp[0] = "GESTURE=Z";
+ gesture = KEY_GESTURE_Z;
+ break;
+ case GESTURE_C:
+ envp[0] = "GESTURE=C";
+ gesture = KEY_GESTURE_C;
+ break;
+ default:
+ envp[0] = "GESTURE=NONE";
+ gesture = -1;
+ break;
+ }
+ FTS_DEBUG("envp[0]: %s", envp[0]);
+ /* report event key */
+ /*if (gesture != -1)
+ {
+ input_report_key(input_dev, gesture, 1);
+ input_sync(input_dev);
+ input_report_key(input_dev, gesture, 0);
+ input_sync(input_dev);
+ } */
+
+ envp[1] = NULL;
+ kobject_uevent_env(&fts_wq_data->client->dev.kobj, KOBJ_CHANGE, envp);
+ sysfs_notify(&fts_wq_data->client->dev.kobj, NULL, "GESTURE_ID");
+
+ FTS_FUNC_EXIT();
+}
+
+/************************************************************************
+* Name: fts_gesture_readdata
+* Brief: read data from TP register
+* Input: no
+* Output: no
+* Return: fail <0
+***********************************************************************/
+static int fts_gesture_read_buffer(struct i2c_client *client, u8 *buf,
+ int read_bytes)
+{
+ int remain_bytes;
+ int ret;
+ int i;
+
+ if (read_bytes <= I2C_BUFFER_LENGTH_MAXINUM) {
+ ret = fts_i2c_read(client, buf, 1, buf, read_bytes);
+ } else {
+ ret =
+ fts_i2c_read(client, buf, 1, buf,
+ I2C_BUFFER_LENGTH_MAXINUM);
+ remain_bytes = read_bytes - I2C_BUFFER_LENGTH_MAXINUM;
+ for (i = 1; remain_bytes > 0; i++) {
+ if (remain_bytes <= I2C_BUFFER_LENGTH_MAXINUM)
+ ret =
+ fts_i2c_read(client, buf, 0,
+ buf +
+ I2C_BUFFER_LENGTH_MAXINUM * i,
+ remain_bytes);
+ else
+ ret =
+ fts_i2c_read(client, buf, 0,
+ buf +
+ I2C_BUFFER_LENGTH_MAXINUM * i,
+ I2C_BUFFER_LENGTH_MAXINUM);
+ remain_bytes -= I2C_BUFFER_LENGTH_MAXINUM;
+ }
+ }
+
+ return ret;
+}
+
+/************************************************************************
+* Name: fts_gesture_readdata
+* Brief: read data from TP register
+* Input: no
+* Output: no
+* Return: fail <0
+***********************************************************************/
+int fts_gesture_readdata(struct i2c_client *client)
+{
+ u8 buf[FTS_GESTRUE_POINTS * 4] = { 0 };
+ int ret = -1;
+ int i = 0;
+ int gestrue_id = 0;
+ int read_bytes = 0;
+ u8 pointnum;
+
+ FTS_FUNC_ENTER();
+ /* init variable before read gesture point */
+ memset(fts_gesture_data.header, 0, FTS_GESTRUE_POINTS_HEADER);
+ memset(fts_gesture_data.coordinate_x, 0,
+ FTS_GESTRUE_POINTS * sizeof(u16));
+ memset(fts_gesture_data.coordinate_y, 0,
+ FTS_GESTRUE_POINTS * sizeof(u16));
+
+ buf[0] = FTS_REG_GESTURE_OUTPUT_ADDRESS;
+ ret = fts_i2c_read(client, buf, 1, buf, FTS_GESTRUE_POINTS_HEADER);
+ if (ret < 0) {
+ FTS_ERROR("[GESTURE]Read gesture header data failed!!");
+ FTS_FUNC_EXIT();
+ return ret;
+ }
+
+ /* FW recognize gesture */
+ if (chip_types.chip_idh == 0x54 || chip_types.chip_idh == 0x58
+ || chip_types.chip_idh == 0x86 || chip_types.chip_idh == 0x87
+ || chip_types.chip_idh == 0x64) {
+ memcpy(fts_gesture_data.header, buf, FTS_GESTRUE_POINTS_HEADER);
+ gestrue_id = buf[0];
+ pointnum = buf[1];
+ read_bytes = ((int)pointnum) * 4 + 2;
+ buf[0] = FTS_REG_GESTURE_OUTPUT_ADDRESS;
+ FTS_DEBUG("[GESTURE]PointNum=%d", pointnum);
+ ret = fts_gesture_read_buffer(client, buf, read_bytes);
+ if (ret < 0) {
+ FTS_ERROR("[GESTURE]Read gesture touch data failed!!");
+ FTS_FUNC_EXIT();
+ return ret;
+ }
+
+ fts_check_gesture(fts_input_dev, gestrue_id);
+ for (i = 0; i < pointnum; i++) {
+ fts_gesture_data.coordinate_x[i] =
+ (((s16) buf[0 + (4 * i + 2)]) & 0x0F) << 8 |
+ (((s16) buf[1 + (4 * i + 2)]) & 0xFF);
+ fts_gesture_data.coordinate_y[i] =
+ (((s16) buf[2 + (4 * i + 2)]) & 0x0F) << 8 |
+ (((s16) buf[3 + (4 * i + 2)]) & 0xFF);
+ }
+ FTS_FUNC_EXIT();
+ return 0;
+ }
+ /* other IC's gestrue in driver */
+ if (0x24 == buf[0]) {
+ gestrue_id = 0x24;
+ fts_check_gesture(fts_input_dev, gestrue_id);
+ FTS_DEBUG("[GESTURE]%d check_gesture gestrue_id", gestrue_id);
+ FTS_FUNC_EXIT();
+ return -1;
+ }
+
+ /* Host Driver recognize gesture */
+ pointnum = buf[1];
+ read_bytes = ((int)pointnum) * 4 + 2;
+ buf[0] = FTS_REG_GESTURE_OUTPUT_ADDRESS;
+ ret = fts_gesture_read_buffer(client, buf, read_bytes);
+ if (ret < 0) {
+ FTS_ERROR ("[GESTURE]Driver recognize gesture -"
+ "Read gesture touch data failed!!");
+ FTS_FUNC_EXIT();
+ return ret;
+ }
+
+ /*
+ * Host Driver recognize gesture, need gesture lib.a
+ * Not use now for compatibility
+ gestrue_id = fetch_object_sample(buf, pointnum);
+ */
+ gestrue_id = 0x24;
+ fts_check_gesture(fts_input_dev, gestrue_id);
+ FTS_DEBUG("[GESTURE]%d read gestrue_id", gestrue_id);
+
+ for (i = 0; i < pointnum; i++) {
+ fts_gesture_data.coordinate_x[i] =
+ (((s16) buf[0 + (4 * i + 8)]) & 0x0F) << 8 |
+ (((s16) buf[1 + (4 * i + 8)]) & 0xFF);
+ fts_gesture_data.coordinate_y[i] =
+ (((s16) buf[2 + (4 * i + 8)]) & 0x0F) << 8 |
+ (((s16) buf[3 + (4 * i + 8)]) & 0xFF);
+ }
+ FTS_FUNC_EXIT();
+ return -1;
+}
+
+/*****************************************************************************
+* Name: fts_gesture_suspend
+* Brief:
+* Input:
+* Output: None
+* Return: None
+*****************************************************************************/
+int fts_gesture_suspend(struct i2c_client *i2c_client)
+{
+ int i;
+ u8 state;
+
+ FTS_FUNC_ENTER();
+
+ /* gesture not enable, return immediately */
+ if (fts_gesture_data.mode == 0) {
+ FTS_DEBUG("gesture is disabled");
+ FTS_FUNC_EXIT();
+ return -1;
+ }
+
+ for (i = 0; i < 5; i++) {
+ fts_i2c_write_reg(i2c_client, 0xd1, 0xff);
+ fts_i2c_write_reg(i2c_client, 0xd2, 0xff);
+ fts_i2c_write_reg(i2c_client, 0xd5, 0xff);
+ fts_i2c_write_reg(i2c_client, 0xd6, 0xff);
+ fts_i2c_write_reg(i2c_client, 0xd7, 0xff);
+ fts_i2c_write_reg(i2c_client, 0xd8, 0xff);
+ fts_i2c_write_reg(i2c_client, FTS_REG_GESTURE_EN, 0x01);
+ msleep(1);
+ fts_i2c_read_reg(i2c_client, FTS_REG_GESTURE_EN, &state);
+ if (state == 1)
+ break;
+ }
+
+ if (i >= 5) {
+ FTS_ERROR("[GESTURE]Enter into gesture(suspend) failed!\n");
+ FTS_FUNC_EXIT();
+ return -1;
+ }
+
+ fts_gesture_data.active = 1;
+ FTS_DEBUG("[GESTURE]Enter into gesture(suspend) successfully!");
+ FTS_FUNC_EXIT();
+ return 0;
+}
+
+/*****************************************************************************
+* Name: fts_gesture_resume
+* Brief:
+* Input:
+* Output: None
+* Return: None
+*****************************************************************************/
+int fts_gesture_resume(struct i2c_client *client)
+{
+ int i;
+ u8 state;
+
+ FTS_FUNC_ENTER();
+
+ /* gesture not enable, return immediately */
+ if (fts_gesture_data.mode == 0) {
+ FTS_DEBUG("gesture is disabled");
+ FTS_FUNC_EXIT();
+ return -1;
+ }
+
+ fts_gesture_data.active = 0;
+ for (i = 0; i < 5; i++) {
+ fts_i2c_write_reg(client, FTS_REG_GESTURE_EN, 0x00);
+ msleep(1);
+ fts_i2c_read_reg(client, FTS_REG_GESTURE_EN, &state);
+ if (state == 0)
+ break;
+ }
+
+ if (i >= 5)
+ FTS_ERROR("[GESTURE]Clear gesture(resume) failed!\n");
+
+ FTS_FUNC_EXIT();
+ return 0;
+}
+#endif
diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_i2c.c b/drivers/input/touchscreen/focaltech_touch/focaltech_i2c.c
new file mode 100644
index 000000000000..75cd917eae2b
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/focaltech_i2c.c
@@ -0,0 +1,209 @@
+/*
+ *
+ * FocalTech TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, 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: fupeipei
+*
+* Created: 2016-08-04
+*
+* Abstract: i2c communication with TP
+*
+* Version: v1.0
+*
+* Revision History:
+* v1.0:
+* First release. By fupeipei 2016-08-04
+************************************************************************/
+
+/*****************************************************************************
+* Included header files
+*****************************************************************************/
+#include "focaltech_core.h"
+
+/*****************************************************************************
+* Private constant and macro definitions using #define
+*****************************************************************************/
+
+/*****************************************************************************
+* Private enumerations, structures and unions using typedef
+*****************************************************************************/
+
+/*****************************************************************************
+* Static variables
+*****************************************************************************/
+static DEFINE_MUTEX(i2c_rw_access);
+
+/*****************************************************************************
+* Global variable or extern global variabls/functions
+*****************************************************************************/
+
+/*****************************************************************************
+* Static function prototypes
+*****************************************************************************/
+
+/*****************************************************************************
+* functions body
+*****************************************************************************/
+
+/************************************************************************
+* Name: fts_i2c_read
+* Brief: i2c read
+* Input: i2c info, write buf, write len, read buf, read len
+* Output: get data in the 3rd buf
+* Return: fail <0
+***********************************************************************/
+int fts_i2c_read(struct i2c_client *client, char *writebuf, int writelen,
+ char *readbuf, int readlen)
+{
+ int ret = 0;
+
+ mutex_lock(&i2c_rw_access);
+
+ if (readlen > 0) {
+ if (writelen > 0) {
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = writelen,
+ .buf = writebuf,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = readlen,
+ .buf = readbuf,
+ },
+ };
+ ret = i2c_transfer(client->adapter, msgs, 2);
+ if (ret < 0) {
+ FTS_ERROR("[IIC]: i2c_transfer(write)"
+ "error,ret=%d!!", ret);
+ }
+ } else {
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = readlen,
+ .buf = readbuf,
+ },
+ };
+ ret = i2c_transfer(client->adapter, msgs, 1);
+ if (ret < 0) {
+ FTS_ERROR("[IIC]: i2c_transfer(read)"
+ "error, ret=%d!!", ret);
+ }
+ }
+ }
+
+ mutex_unlock(&i2c_rw_access);
+ return ret;
+}
+
+/************************************************************************
+* Name: fts_i2c_write
+* Brief: i2c write
+* Input: i2c info, write buf, write len
+* Output: no
+* Return: fail <0
+***********************************************************************/
+int fts_i2c_write(struct i2c_client *client, char *writebuf, int writelen)
+{
+ int ret = 0;
+
+ mutex_lock(&i2c_rw_access);
+ if (writelen > 0) {
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = writelen,
+ .buf = writebuf,
+ },
+ };
+ ret = i2c_transfer(client->adapter, msgs, 1);
+ if (ret < 0) {
+ FTS_ERROR("%s: i2c_transfer(write) error, ret=%d",
+ __func__, ret);
+ }
+ }
+ mutex_unlock(&i2c_rw_access);
+
+ return ret;
+}
+
+/************************************************************************
+* Name: fts_i2c_write_reg
+* Brief: write register
+* Input: i2c info, reg address, reg value
+* Output: no
+* Return: fail <0
+***********************************************************************/
+int fts_i2c_write_reg(struct i2c_client *client, u8 regaddr, u8 regvalue)
+{
+ u8 buf[2] = { 0 };
+
+ buf[0] = regaddr;
+ buf[1] = regvalue;
+ return fts_i2c_write(client, buf, sizeof(buf));
+}
+
+/************************************************************************
+* Name: fts_i2c_read_reg
+* Brief: read register
+* Input: i2c info, reg address, reg value
+* Output: get reg value
+* Return: fail <0
+***********************************************************************/
+int fts_i2c_read_reg(struct i2c_client *client, u8 regaddr, u8 *regvalue)
+{
+ return fts_i2c_read(client, &regaddr, 1, regvalue, 1);
+}
+
+/************************************************************************
+* Name: fts_i2c_init
+* Brief: fts i2c init
+* Input:
+* Output:
+* Return:
+***********************************************************************/
+int fts_i2c_init(void)
+{
+ FTS_FUNC_ENTER();
+
+ FTS_FUNC_EXIT();
+ return 0;
+}
+
+/************************************************************************
+* Name: fts_i2c_exit
+* Brief: fts i2c exit
+* Input:
+* Output:
+* Return:
+***********************************************************************/
+int fts_i2c_exit(void)
+{
+ FTS_FUNC_ENTER();
+
+ FTS_FUNC_EXIT();
+ return 0;
+}
diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_point_report_check.c b/drivers/input/touchscreen/focaltech_touch/focaltech_point_report_check.c
new file mode 100644
index 000000000000..0fa561748f75
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/focaltech_point_report_check.c
@@ -0,0 +1,151 @@
+/*
+ *
+ * FocalTech TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, 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: WangTao
+*
+* Created: 2016-11-16
+*
+* Abstract: point report check function
+*
+* Version: v1.0
+*
+* Revision History:
+* v1.0:
+* First release. By WangTao 2016-11-16
+*****************************************************************************/
+
+/*****************************************************************************
+* 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
+
+/*****************************************************************************
+* Private enumerations, structures and unions using typedef
+*****************************************************************************/
+
+/*****************************************************************************
+* Static variables
+*****************************************************************************/
+static struct delayed_work fts_point_report_check_work;
+static struct workqueue_struct *fts_point_report_check_workqueue;
+
+/*****************************************************************************
+* Global variable or extern global variabls/functions
+*****************************************************************************/
+
+/*****************************************************************************
+* Static function prototypes
+*****************************************************************************/
+
+/*****************************************************************************
+* functions body
+*****************************************************************************/
+
+/*****************************************************************************
+* Name: fts_point_report_check_func
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static void fts_point_report_check_func(struct work_struct *work)
+{
+
+#if FTS_MT_PROTOCOL_B_EN
+ unsigned int finger_count = 0;
+
+ FTS_FUNC_ENTER();
+
+ for (finger_count = 0; finger_count < FTS_MAX_POINTS; finger_count++) {
+ input_mt_slot(fts_input_dev, finger_count);
+ input_mt_report_slot_state(fts_input_dev, MT_TOOL_FINGER,
+ false);
+ }
+#else
+ input_mt_sync(fts_input_dev);
+#endif
+ input_report_key(fts_input_dev, BTN_TOUCH, 0);
+ input_sync(fts_input_dev);
+
+ FTS_FUNC_EXIT();
+}
+
+void fts_point_report_check_queue_work(void)
+{
+
+ cancel_delayed_work(&fts_point_report_check_work);
+ queue_delayed_work(fts_point_report_check_workqueue,
+ &fts_point_report_check_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(void)
+{
+ FTS_FUNC_ENTER();
+
+ INIT_DELAYED_WORK(&fts_point_report_check_work,
+ fts_point_report_check_func);
+ fts_point_report_check_workqueue =
+ create_workqueue("fts_point_report_check_func_wq");
+ if (fts_point_report_check_workqueue == NULL) {
+ FTS_ERROR("[POINT_REPORT]: Failed to create"
+ "fts_point_report_check_workqueue!!");
+ } else {
+ FTS_DEBUG("[POINT_REPORT]: Success to create"
+ "fts_point_report_check_workqueue!!");
+ }
+
+ FTS_FUNC_EXIT();
+
+ return 0;
+}
+
+/*****************************************************************************
+* Name: fts_point_report_check_exit
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+int fts_point_report_check_exit(void)
+{
+ FTS_FUNC_ENTER();
+
+ destroy_workqueue(fts_point_report_check_workqueue);
+
+ FTS_FUNC_EXIT();
+ return 0;
+}
+#endif /* FTS_POINT_REPORT_CHECK_EN */
diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c b/drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c
new file mode 100644
index 000000000000..4a62ee65eaa6
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/focaltech_sensor.c
@@ -0,0 +1,311 @@
+/*
+ *
+ * FocalTech TouchScreen driver.
+ *
+ * Copyright (c) 2010-2016, 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: Sensor
+*
+* Version: v1.0
+*
+* Revision History:
+* v1.0:
+* First release. By luougojin 2016-08-03
+*****************************************************************************/
+
+/*****************************************************************************
+* Included header files
+*****************************************************************************/
+#include "focaltech_core.h"
+
+#if FTS_PSENSOR_EN
+/*****************************************************************************
+* Private constant and macro definitions using #define
+*****************************************************************************/
+/* psensor register address*/
+#define FTS_REG_PSENSOR_ENABLE 0xB0
+#define FTS_REG_PSENSOR_STATUS 0x01
+
+/* psensor register bits*/
+#define FTS_PSENSOR_ENABLE_MASK 0x01
+#define FTS_PSENSOR_STATUS_NEAR 0xC0
+#define FTS_PSENSOR_STATUS_FAR 0xE0
+#define FTS_PSENSOR_FAR_TO_NEAR 0
+#define FTS_PSENSOR_NEAR_TO_FAR 1
+#define FTS_PSENSOR_ORIGINAL_STATE_FAR 1
+#define FTS_PSENSOR_WAKEUP_TIMEOUT 500
+
+/*****************************************************************************
+* Static variables
+*****************************************************************************/
+static struct sensors_classdev __maybe_unused sensors_proximity_cdev = {
+ .name = "fts-proximity",
+ .vendor = "FocalTech",
+ .version = 1,
+ .handle = SENSORS_PROXIMITY_HANDLE,
+ .type = SENSOR_TYPE_PROXIMITY,
+ .max_range = "5.0",
+ .resolution = "5.0",
+ .sensor_power = "0.1",
+ .min_delay = 0,
+ .fifo_reserved_event_count = 0,
+ .fifo_max_event_count = 0,
+ .enabled = 0,
+ .delay_msec = 200,
+ .sensors_enable = NULL,
+ .sensors_poll_delay = NULL,
+};
+
+/*****************************************************************************
+* functions body
+*****************************************************************************/
+/*****************************************************************************
+* Name: fts_psensor_support_enabled
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static inline bool fts_psensor_support_enabled(void)
+{
+ /*return config_enabled(CONFIG_TOUCHSCREEN_FTS_PSENSOR); */
+ return FTS_PSENSOR_EN;
+}
+
+/*****************************************************************************
+* Name: fts_psensor_enable
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static void fts_psensor_enable(struct fts_ts_data *data, int enable)
+{
+ u8 state;
+ int ret = -1;
+
+ if (data->client == NULL)
+ return;
+
+ fts_i2c_read_reg(data->client, FTS_REG_PSENSOR_ENABLE, &state);
+ if (enable)
+ state |= FTS_PSENSOR_ENABLE_MASK;
+ else
+ state &= ~FTS_PSENSOR_ENABLE_MASK;
+
+ ret = fts_i2c_write_reg(data->client, FTS_REG_PSENSOR_ENABLE, state);
+ if (ret < 0)
+ FTS_ERROR("write psensor switch command failed");
+}
+
+/*****************************************************************************
+* Name: fts_psensor_enable_set
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static int fts_psensor_enable_set(struct sensors_classdev *sensors_cdev,
+ unsigned int enable)
+{
+ struct fts_psensor_platform_data *psensor_pdata =
+ container_of(sensors_cdev,
+ struct fts_psensor_platform_data, ps_cdev);
+ struct fts_ts_data *data = psensor_pdata->data;
+ struct input_dev *input_dev = data->psensor_pdata->input_psensor_dev;
+
+ mutex_lock(&input_dev->mutex);
+ fts_psensor_enable(data, enable);
+ psensor_pdata->tp_psensor_data = FTS_PSENSOR_ORIGINAL_STATE_FAR;
+ if (enable)
+ psensor_pdata->tp_psensor_opened = 1;
+ else
+ psensor_pdata->tp_psensor_opened = 0;
+ mutex_unlock(&input_dev->mutex);
+ return enable;
+}
+
+/*****************************************************************************
+* Name: fts_read_tp_psensor_data
+* Brief:
+* Input:
+* Output:
+* Return:
+*****************************************************************************/
+static int fts_read_tp_psensor_data(struct fts_ts_data *data)
+{
+ u8 psensor_status;
+ char tmp;
+ int ret = 1;
+
+ fts_i2c_read_reg(data->client, FTS_REG_PSENSOR_STATUS, &psensor_status);
+
+ tmp = data->psensor_pdata->tp_psensor_data;
+ if (psensor_status == FTS_PSENSOR_STATUS_NEAR)
+ data->psensor_pdata->tp_psensor_data = FTS_PSENSOR_FAR_TO_NEAR;
+ else if (psensor_status == FTS_PSENSOR_STATUS_FAR)
+ data->psensor_pdata->tp_psensor_data = FTS_PSENSOR_NEAR_TO_FAR;
+
+ if (tmp != data->psensor_pdata->tp_psensor_data) {
+ FTS_ERROR("%s sensor data changed", __func__);
+ ret = 0;
+ }
+ return ret;
+}
+
+int fts_sensor_read_data(struct fts_ts_data *data)
+{
+ int ret = 0;
+
+ if (fts_psensor_support_enabled()
+ && data->psensor_pdata->tp_psensor_opened) {
+ ret = fts_read_tp_psensor_data(data);
+ if (!ret) {
+ if (data->suspended) {
+ pm_wakeup_event(&data->client->dev,
+ FTS_PSENSOR_WAKEUP_TIMEOUT);
+ }
+ input_report_abs(data->psensor_pdata->input_psensor_dev,
+ ABS_DISTANCE,
+ data->psensor_pdata->tp_psensor_data);
+ input_sync(data->psensor_pdata->input_psensor_dev);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+int fts_sensor_suspend(struct fts_ts_data *data)
+{
+ int ret = 0;
+
+ if (fts_psensor_support_enabled()
+ && device_may_wakeup(&data->client->dev)
+ && data->psensor_pdata->tp_psensor_opened) {
+ ret = enable_irq_wake(data->client->irq);
+ if (ret != 0)
+ FTS_ERROR("%s: set_irq_wake failed", __func__);
+ data->suspended = true;
+ return 1;
+ }
+
+ return 0;
+}
+
+int fts_sensor_resume(struct fts_ts_data *data)
+{
+ int ret = 0;
+
+ if (fts_psensor_support_enabled()
+ && device_may_wakeup(&data->client->dev)
+ && data->psensor_pdata->tp_psensor_opened) {
+ ret = disable_irq_wake(data->client->irq);
+ if (ret)
+ FTS_ERROR("%s: disable_irq_wake failed", __func__);
+ data->suspended = false;
+ return 1;
+ }
+
+ return 0;
+}
+
+int fts_sensor_init(struct fts_ts_data *data)
+{
+ struct fts_psensor_platform_data *psensor_pdata;
+ struct input_dev *psensor_input_dev;
+ int err;
+
+ if (fts_psensor_support_enabled()) {
+ device_init_wakeup(&data->client->dev, 1);
+ psensor_pdata =
+ devm_kzalloc(&data->client->dev,
+ sizeof(struct fts_psensor_platform_data),
+ GFP_KERNEL);
+ if (!psensor_pdata) {
+ FTS_ERROR("Failed to allocate memory");
+ goto irq_free;
+ }
+ data->psensor_pdata = psensor_pdata;
+
+ psensor_input_dev = input_allocate_device();
+ if (!psensor_input_dev) {
+ FTS_ERROR("Failed to allocate device");
+ goto free_psensor_pdata;
+ }
+
+ __set_bit(EV_ABS, psensor_input_dev->evbit);
+ input_set_abs_params(psensor_input_dev, ABS_DISTANCE, 0, 1, 0,
+ 0);
+ psensor_input_dev->name = "proximity";
+ psensor_input_dev->id.bustype = BUS_I2C;
+ psensor_input_dev->dev.parent = &data->client->dev;
+ data->psensor_pdata->input_psensor_dev = psensor_input_dev;
+
+ err = input_register_device(psensor_input_dev);
+ if (err) {
+ FTS_ERROR("Unable to register device, err=%d", err);
+ goto free_psensor_input_dev;
+ }
+
+ psensor_pdata->ps_cdev = sensors_proximity_cdev;
+ psensor_pdata->ps_cdev.sensors_enable = fts_psensor_enable_set;
+ psensor_pdata->data = data;
+
+ err =
+ sensors_classdev_register(&data->client->dev,
+ &psensor_pdata->ps_cdev);
+ if (err)
+ goto unregister_psensor_input_device;
+ }
+
+ return 0;
+unregister_psensor_input_device:
+ if (fts_psensor_support_enabled())
+ input_unregister_device(data->psensor_pdata->input_psensor_dev);
+free_psensor_input_dev:
+ if (fts_psensor_support_enabled())
+ input_free_device(data->psensor_pdata->input_psensor_dev);
+free_psensor_pdata:
+ if (fts_psensor_support_enabled()) {
+ devm_kfree(&data->client->dev, psensor_pdata);
+ data->psensor_pdata = NULL;
+ }
+irq_free:
+ if (fts_psensor_support_enabled())
+ device_init_wakeup(&data->client->dev, 0);
+ free_irq(data->client->irq, data);
+
+ return 1;
+}
+
+int fts_sensor_remove(struct fts_ts_data *data)
+{
+ if (fts_psensor_support_enabled()) {
+ device_init_wakeup(&data->client->dev, 0);
+ sensors_classdev_unregister(&data->psensor_pdata->ps_cdev);
+ input_unregister_device(data->psensor_pdata->input_psensor_dev);
+ devm_kfree(&data->client->dev, data->psensor_pdata);
+ data->psensor_pdata = NULL;
+ }
+ return 0;
+}
+#endif /* FTS_PSENSOR_EN */
diff --git a/drivers/input/touchscreen/focaltech_touch/include/firmware/FT8716_app_sample.i b/drivers/input/touchscreen/focaltech_touch/include/firmware/FT8716_app_sample.i
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/include/firmware/FT8716_app_sample.i
diff --git a/drivers/input/touchscreen/focaltech_touch/include/firmware/lcd_cfg.i b/drivers/input/touchscreen/focaltech_touch/include/firmware/lcd_cfg.i
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/include/firmware/lcd_cfg.i
diff --git a/drivers/input/touchscreen/focaltech_touch/include/pramboot/FT8606_Pramboot_V0.7_20150507.i b/drivers/input/touchscreen/focaltech_touch/include/pramboot/FT8606_Pramboot_V0.7_20150507.i
new file mode 100644
index 000000000000..f031758e0207
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/include/pramboot/FT8606_Pramboot_V0.7_20150507.i
@@ -0,0 +1,244 @@
+0x2, 0x9, 0x9b, 0xca, 0x39, 0x12, 0xc, 0x4b, 0xda, 0x39, 0x32, 0x2, 0x0, 0x3,
+ 0x6d, 0x22, 0x80, 0x13, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6,
+ 0xb3, 0xe5, 0xb5, 0x7a, 0xb, 0xb0, 0xb, 0x14, 0xb, 0x24, 0xbd, 0x32, 0x38,
+ 0xe9, 0x22, 0xff, 0x2, 0xa, 0x70, 0xa9, 0xc2, 0xb4, 0x74, 0x5, 0x12, 0xc,
+ 0x36, 0x12, 0xc, 0x1d, 0xa9, 0xd2, 0xb4, 0x30, 0xe0, 0x2, 0xd3, 0x22, 0xc3,
+ 0x22, 0x2, 0x0, 0xf9, 0xca, 0x3b, 0x7a, 0xd, 0x8, 0x7f, 0x31, 0xe5, 0x23,
+ 0xb4, 0x80, 0x2, 0x80, 0x3, 0x2, 0x0, 0xdc, 0x7f, 0x13, 0x5e, 0x34, 0x0,
+ 0x7f, 0x7d, 0x23, 0x7e, 0x34, 0x0, 0x80, 0x9d, 0x32, 0x7a, 0x35, 0xe, 0x7e,
+ 0x35, 0xc, 0xbe, 0x35, 0xe, 0x38, 0x2, 0x80, 0x5d, 0x7e, 0x35, 0xe, 0x7a,
+ 0x35, 0x10, 0x7f, 0x13, 0x7e, 0xd, 0x8, 0x12, 0x8, 0xf3, 0x7e, 0x35, 0xc,
+ 0x9e, 0x35, 0xe, 0x7a, 0x35, 0xc, 0x7e, 0x35, 0xe, 0x6d, 0x22, 0x2f, 0x31,
+ 0x7e, 0x1d, 0x8, 0x2e, 0x35, 0xe, 0x7a, 0x1d, 0x8, 0x80, 0x27, 0x7e, 0x34,
+ 0x0, 0x80, 0x7a, 0x35, 0x10, 0x7f, 0x13, 0x7e, 0xd, 0x8, 0x12, 0x8, 0xf3,
+ 0x7e, 0x35, 0xc, 0x9e, 0x34, 0x0, 0x80, 0x7a, 0x35, 0xc, 0x7e, 0x1d, 0x8,
+ 0x2e, 0x34, 0x0, 0x80, 0x7a, 0x1d, 0x8, 0x2e, 0x38, 0x0, 0x80, 0x7e, 0x35,
+ 0xc, 0xbe, 0x34, 0x0, 0x80, 0x50, 0xd0, 0x4d, 0x33, 0x68, 0x26, 0x7a, 0x35,
+ 0x10, 0x7f, 0x13, 0x7e, 0xd, 0x8, 0x12, 0x8, 0xf3, 0x80, 0x19, 0x74, 0x2,
+ 0x12, 0x8, 0x3d, 0x5e, 0x70, 0xf4, 0x12, 0x9, 0xe7, 0x7e, 0x35, 0xc, 0x7a,
+ 0x35, 0x10, 0x7f, 0x13, 0x7e, 0xd, 0x8, 0x12, 0x6, 0x42, 0xd3, 0xda, 0x3b,
+ 0x22, 0xa9, 0xc0, 0x93, 0x75, 0x38, 0x0, 0x32, 0xc, 0x60, 0xf3, 0x9f, 0x46,
+ 0xb9, 0x2, 0xfd, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x7c, 0x6b, 0xc2, 0x2, 0xe5, 0x21, 0x14, 0x78, 0x3, 0x2, 0x2,
+ 0xbf, 0x1b, 0xb1, 0x78, 0x3, 0x2, 0x2, 0x30, 0x1b, 0xb1, 0x78, 0x3, 0x2,
+ 0x2, 0x7c, 0x1b, 0xb1, 0x78, 0x3, 0x2, 0x2, 0x8d, 0x1b, 0xb1, 0x78, 0x3,
+ 0x2, 0x2, 0xa6, 0x24, 0xf9, 0x78, 0x3, 0x2, 0x2, 0xbb, 0x24, 0xaf, 0x78,
+ 0x3, 0x2, 0x3, 0x29, 0x24, 0xfd, 0x68, 0x2d, 0x14, 0x78, 0x3, 0x2, 0x2,
+ 0xc2, 0x14, 0x78, 0x3, 0x2, 0x2, 0xbf, 0x1b, 0xb2, 0x78, 0x3, 0x2, 0x2,
+ 0xbf, 0x24, 0xda, 0x68, 0x19, 0x24, 0xe6, 0x68, 0x12, 0x24, 0xeb, 0x68,
+ 0x2e, 0x24, 0xf3, 0x78, 0x3, 0x2, 0x2, 0xbf, 0x24, 0x77, 0x68, 0x3, 0x2,
+ 0x3, 0x33, 0x2, 0x3, 0x30, 0xbe, 0x60, 0x4, 0x50, 0xc, 0x75, 0x16, 0x0,
+ 0x7c, 0x16, 0x2e, 0x10, 0x24, 0x7c, 0xb7, 0xa5, 0xf7, 0xa5, 0xbe, 0x0, 0x2,
+ 0x80, 0x3, 0x2, 0x3, 0x33, 0xd2, 0x2, 0x22, 0x7c, 0xb6, 0x24, 0x0, 0x78,
+ 0x3, 0x2, 0x3, 0x33, 0x1b, 0xb1, 0x68, 0x1e, 0x14, 0x68, 0x1e, 0x14, 0x68,
+ 0x1e, 0x14, 0x68, 0x1e, 0xb, 0xb2, 0x78, 0x33, 0x30, 0x1, 0x7, 0x7e, 0x8,
+ 0x0, 0x3e, 0x2, 0x2, 0x4d, 0x7e, 0x8, 0x1, 0x4a, 0x2, 0x2, 0x4d, 0x2, 0x2,
+ 0xe7, 0x2, 0x2, 0xee, 0x2, 0x3, 0x6, 0xa, 0x27, 0x7e, 0xd, 0x39, 0xb, 0x16,
+ 0xb, 0xa, 0x30, 0x2d, 0x32, 0x1b, 0xa, 0x30, 0x6d, 0x33, 0x7e, 0xd, 0x39,
+ 0x79, 0x30, 0x0, 0x6, 0x22, 0x7c, 0xb7, 0x62, 0x16, 0x7e, 0x2d, 0x39, 0x2e,
+ 0x54, 0x0, 0x6, 0xb, 0x2a, 0x20, 0x7d, 0x12, 0xb, 0x14, 0x1b, 0x2a, 0x10,
+ 0x7e, 0xd, 0x39, 0x2d, 0x12, 0x39, 0x70, 0x0, 0x8, 0x7e, 0xd, 0x39, 0x69,
+ 0x50, 0x0, 0x4, 0x69, 0x20, 0x0, 0x6, 0xbd, 0x25, 0x50, 0x3, 0x2, 0x3, 0x33,
+ 0xb2, 0x1, 0x7a, 0xd, 0x33, 0x7e, 0x34, 0x0, 0x2, 0x2, 0x3, 0x25, 0x7c,
+ 0xb6, 0x1b, 0xb1, 0x68, 0x1d, 0x14, 0x68, 0x1d, 0xb, 0xb1, 0x68, 0x3, 0x2,
+ 0x3, 0x33, 0x30, 0x1, 0x6, 0x7e, 0x8, 0x0, 0x3e, 0x80, 0x4, 0x7e, 0x8, 0x1,
+ 0x4a, 0x7a, 0xd, 0x39, 0x2, 0x2, 0xd6, 0x2, 0x2, 0xe7, 0xa, 0x57, 0x6d,
+ 0x44, 0x7e, 0xd, 0x39, 0x69, 0x30, 0x0, 0x2, 0xb, 0xa, 0x20, 0x2f, 0x12,
+ 0x79, 0x30, 0x0, 0x2, 0x1b, 0xa, 0x20, 0x7e, 0x1d, 0x39, 0x7a, 0x1d, 0x33,
+ 0xd2, 0x2, 0x7e, 0x34, 0x0, 0x1, 0x2, 0x3, 0x25, 0xbe, 0x60, 0x1, 0x68, 0x9,
+ 0xa5, 0xbe, 0x2, 0x5, 0x7a, 0x71, 0x3d, 0xd2, 0x3, 0xd2, 0x2, 0x22, 0x75,
+ 0xe6, 0x0, 0xe4, 0x7e, 0x34, 0x1, 0x4, 0x7e, 0x24, 0x0, 0xff, 0x7a, 0x1b,
+ 0xb0, 0x7e, 0x34, 0x1, 0x5, 0x7a, 0x1b, 0xb0, 0xd2, 0x4, 0x22, 0xa5, 0xbe,
+ 0x1, 0x4, 0x7a, 0x71, 0x37, 0x22, 0xa5, 0xbe, 0x2, 0x2, 0x80, 0x3, 0x2, 0x3,
+ 0x33, 0x7a, 0x71, 0x22, 0x22, 0x7a, 0x71, 0x32, 0x22, 0xd2, 0x2, 0x22, 0x1b,
+ 0x61, 0x68, 0x21, 0x1b, 0x60, 0x68, 0x24, 0x1b, 0x60, 0x68, 0x38, 0x1b,
+ 0x60, 0x68, 0x40, 0xb, 0x62, 0x78, 0x5d, 0xa, 0x37, 0x7d, 0x3, 0x6d, 0x11,
+ 0x7e, 0x1d, 0x39, 0x79, 0x11, 0x0, 0x2, 0x1b, 0x1a, 0x0, 0x22, 0xa, 0x57,
+ 0x7c, 0xab, 0xe4, 0x80, 0x2, 0xa, 0x57, 0x6d, 0x44, 0x7e, 0xd, 0x39, 0x69,
+ 0x30, 0x0, 0x2, 0xb, 0xa, 0x20, 0x2f, 0x12, 0x79, 0x30, 0x0, 0x2, 0x1b, 0xa,
+ 0x20, 0x22, 0x7c, 0x67, 0x6c, 0x77, 0x7e, 0xd, 0x39, 0x79, 0x30, 0x0, 0x4,
+ 0x22, 0xa, 0x27, 0x7e, 0xd, 0x39, 0xb, 0x16, 0xb, 0xa, 0x30, 0x2d, 0x32,
+ 0x1b, 0xa, 0x30, 0x7e, 0x34, 0x0, 0x3, 0x7a, 0x35, 0x2e, 0x22, 0x7e, 0x34,
+ 0x0, 0x4, 0x7a, 0x35, 0x2e, 0x75, 0x16, 0x0, 0x22, 0xca, 0x3b, 0x7a, 0x15,
+ 0x8, 0x7f, 0x31, 0x7e, 0x35, 0x8, 0xbe, 0x34, 0x0, 0x0, 0x38, 0x4f, 0x7e,
+ 0x34, 0xff, 0xff, 0x7a, 0x35, 0x8, 0x75, 0xe, 0x1, 0x80, 0x43, 0x7e, 0x34,
+ 0x0, 0x80, 0x7a, 0x35, 0x11, 0x7f, 0x13, 0x7e, 0x8, 0x2, 0x56, 0x12, 0xc,
+ 0x1, 0x7e, 0x35, 0x8, 0x9e, 0x34, 0x0, 0x80, 0x7a, 0x35, 0x8, 0x2e, 0x38,
+ 0x0, 0x80, 0x6d, 0x33, 0x7a, 0x35, 0xf, 0x7e, 0x35, 0xf, 0x9, 0x63, 0x2,
+ 0x56, 0x7e, 0xd, 0xa, 0x7e, 0xb, 0x70, 0x6c, 0x76, 0x7a, 0xb, 0x70, 0x7e,
+ 0x35, 0xf, 0xb, 0x34, 0x7a, 0x35, 0xf, 0xbe, 0x34, 0x0, 0x80, 0x78, 0xe0,
+ 0x7e, 0x35, 0x8, 0xbe, 0x34, 0x0, 0x80, 0x38, 0xb4, 0xe5, 0xe, 0x60, 0x5,
+ 0xb, 0x34, 0x7a, 0x35, 0x8, 0x7e, 0x35, 0x8, 0x7a, 0x35, 0x11, 0x7f, 0x13,
+ 0x7e, 0x8, 0x2, 0x56, 0x12, 0xc, 0x1, 0x6d, 0x33, 0x80, 0x17, 0x7e, 0x35,
+ 0xf, 0x9, 0x63, 0x2, 0x56, 0x7e, 0xd, 0xa, 0x7e, 0xb, 0x70, 0x6c, 0x76,
+ 0x7a, 0xb, 0x70, 0x7e, 0x35, 0xf, 0xb, 0x34, 0x7a, 0x35, 0xf, 0x7e, 0x35,
+ 0x8, 0xbe, 0x35, 0xf, 0x38, 0xde, 0xda, 0x3b, 0x22, 0x80, 0x18, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe5, 0x3d, 0x70, 0xa, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7d, 0x23, 0x1b, 0x34, 0x4d, 0x22,
+ 0x78, 0xe0, 0x22, 0x56, 0x30, 0x2e, 0x36, 0x4d, 0x61, 0x79, 0x20, 0x30,
+ 0x37, 0x20, 0x32, 0x30, 0x31, 0x35, 0x0, 0x46, 0x54, 0x53, 0x38, 0x36, 0x30,
+ 0x36, 0x5f, 0x70, 0x72, 0x61, 0x6d, 0x62, 0x6f, 0x6f, 0x74, 0x12, 0xb, 0xbd,
+ 0x2, 0x5, 0x66, 0x7e, 0x35, 0x2e, 0x1b, 0x34, 0x68, 0x57, 0x1b, 0x35, 0x78,
+ 0x3, 0x2, 0x4, 0xb3, 0x1b, 0x34, 0x78, 0x3, 0x2, 0x4, 0xdd, 0xb, 0x35, 0x68,
+ 0x3, 0x2, 0x5, 0x52, 0x6d, 0x33, 0x7a, 0x35, 0x2e, 0x7a, 0x35, 0x30, 0x30,
+ 0x5, 0x5, 0x12, 0xb, 0xf0, 0xc2, 0x5, 0x7e, 0xd, 0x33, 0x69, 0x30, 0x0, 0x4,
+ 0x7a, 0x35, 0xc, 0x69, 0x30, 0x0, 0x2, 0xb, 0xa, 0x20, 0x2e, 0x14, 0x0, 0x8,
+ 0x12, 0x0, 0x46, 0xd2, 0x5, 0x7e, 0x2d, 0x33, 0x69, 0x12, 0x0, 0x4, 0x69,
+ 0x32, 0x0, 0x2, 0xb, 0x2a, 0x20, 0x12, 0x9, 0x48, 0x2e, 0x34, 0x10, 0x0,
+ 0x2, 0x5, 0x4f, 0x6d, 0x33, 0x7a, 0x35, 0x2e, 0x7e, 0x34, 0x1, 0x0, 0x7a,
+ 0x35, 0x11, 0x7e, 0xd, 0x33, 0x69, 0x30, 0x0, 0x2, 0xb, 0xa, 0x20, 0x2e,
+ 0x14, 0x0, 0x8, 0x12, 0xc, 0x1, 0x20, 0x0, 0x3, 0x2, 0x5, 0x52, 0x7e, 0x1d,
+ 0x33, 0x29, 0xb1, 0x0, 0x8, 0xf5, 0x91, 0x2, 0x5, 0x52, 0x6d, 0x33, 0x7a,
+ 0x35, 0x2e, 0x7a, 0x35, 0x30, 0x7e, 0x18, 0x0, 0x16, 0x7a, 0x1d, 0xa, 0x7e,
+ 0xd, 0x33, 0x69, 0x30, 0x0, 0x2, 0xb, 0xa, 0x20, 0x69, 0x10, 0x0, 0x4, 0x12,
+ 0x3, 0x34, 0x12, 0xb, 0xf0, 0x7e, 0x34, 0xf0, 0x55, 0x2, 0x5, 0x4f, 0x6d,
+ 0x33, 0x7a, 0x35, 0x2e, 0x7a, 0x35, 0x30, 0xe5, 0x37, 0xb4, 0xa, 0x15, 0xe5,
+ 0x23, 0xb4, 0x80, 0xb, 0xe4, 0x12, 0xa, 0x32, 0x74, 0x1, 0x12, 0xa, 0x32,
+ 0x80, 0x4e, 0x12, 0x6, 0xd8, 0x80, 0x49, 0xe5, 0x37, 0xb4, 0xb, 0x27, 0xe5,
+ 0x23, 0xb4, 0x80, 0x11, 0x7e, 0xf0, 0x1, 0x7c, 0xbf, 0x12, 0x5, 0x6d, 0xb,
+ 0xf0, 0xbe, 0xf0, 0x11, 0x78, 0xf4, 0x80, 0x2e, 0x7e, 0xf0, 0x4, 0x7c, 0xbf,
+ 0x12, 0x5, 0x6d, 0xb, 0xf0, 0xbe, 0xf0, 0x40, 0x78, 0xf4, 0x80, 0x1d, 0xe5,
+ 0x37, 0xa, 0x3b, 0x9e, 0x34, 0x0, 0x80, 0x7c, 0xe7, 0x6c, 0xdd, 0x80, 0x9,
+ 0x7c, 0xbe, 0x12, 0x5, 0x6d, 0xb, 0xe0, 0xb, 0xd0, 0xe5, 0x22, 0xbc, 0xbd,
+ 0x38, 0xf1, 0x12, 0xb, 0xf0, 0x7e, 0x34, 0xf0, 0xaa, 0x7a, 0x35, 0x30, 0x30,
+ 0x4, 0x11, 0x7e, 0x34, 0x13, 0x88, 0x12, 0x3, 0xdd, 0x7e, 0x34, 0x13, 0x88,
+ 0x12, 0x3, 0xdd, 0x75, 0xe9, 0xff, 0x30, 0x6, 0x3, 0x2, 0x4, 0x26, 0x22,
+ 0xca, 0xf8, 0x7c, 0xfb, 0xe5, 0x23, 0xb4, 0x80, 0x4a, 0xd2, 0x7, 0x12, 0xb,
+ 0xdd, 0x74, 0x20, 0xca, 0xb8, 0xa, 0x3f, 0x6d, 0x22, 0x74, 0xc, 0x2f, 0x11,
+ 0x14, 0x78, 0xfb, 0xda, 0xb8, 0x12, 0xb, 0x44, 0xa9, 0xd2, 0xb4, 0x12, 0xc,
+ 0x41, 0x12, 0x0, 0x2e, 0x50, 0x9, 0x7e, 0x35, 0x17, 0xbe, 0x34, 0x1, 0xf4,
+ 0x28, 0xf2, 0x7e, 0x35, 0x17, 0xbe, 0x34, 0x1, 0xf4, 0x38, 0x6, 0x12, 0xc,
+ 0x5c, 0x2, 0x6, 0x3f, 0xc2, 0x86, 0x7e, 0x34, 0x13, 0x88, 0x12, 0x3, 0xdd,
+ 0xd2, 0x86, 0x2, 0x6, 0x3f, 0x74, 0x1, 0x12, 0x7, 0xd5, 0x74, 0x1, 0x6d,
+ 0x33, 0x12, 0x9, 0xe7, 0xe4, 0x12, 0x8, 0x3d, 0x5e, 0x34, 0x80, 0x0, 0x7c,
+ 0x4f, 0x6c, 0x55, 0x3e, 0x24, 0x4d, 0x32, 0x12, 0x9, 0xe7, 0x74, 0x4, 0x6d,
+ 0x33, 0x12, 0x9, 0xe7, 0x7e, 0x34, 0x0, 0x50, 0x12, 0x9, 0xe7, 0x7e, 0x34,
+ 0x0, 0x19, 0x12, 0x3, 0xdd, 0x74, 0x4, 0x7e, 0x34, 0x0, 0x51, 0x12, 0x9,
+ 0xe7, 0x7e, 0x34, 0xa2, 0x1c, 0x12, 0x3, 0xdd, 0x74, 0x4, 0x7e, 0x34, 0x0,
+ 0x11, 0x12, 0x9, 0xe7, 0x7e, 0x34, 0x0, 0x19, 0x12, 0x3, 0xdd, 0x74, 0x4,
+ 0x7e, 0x34, 0x0, 0x10, 0x12, 0x9, 0xe7, 0x7e, 0x34, 0x0, 0x19, 0x12, 0x3,
+ 0xdd, 0x74, 0x4, 0x6d, 0x33, 0x12, 0x9, 0xe7, 0x7e, 0x34, 0x0, 0x5, 0x12,
+ 0x3, 0xdd, 0xe4, 0x12, 0x7, 0xd5, 0x74, 0x4, 0x7e, 0x34, 0xff, 0xf7, 0x12,
+ 0x9, 0xe7, 0xda, 0xf8, 0x22, 0xca, 0x3b, 0x7f, 0x30, 0x7c, 0xb6, 0xf5, 0x12,
+ 0x7c, 0xb7, 0xf5, 0x13, 0x74, 0x1, 0x7e, 0x35, 0x10, 0x1e, 0x34, 0x1b, 0x34,
+ 0x4e, 0x60, 0x80, 0x12, 0x9, 0xe7, 0x12, 0x7, 0xd5, 0xa9, 0xc2, 0xb4, 0xa9,
+ 0xc6, 0xb3, 0x75, 0xb5, 0x2, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x75,
+ 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x85, 0x12, 0xb5, 0xa9,
+ 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x85, 0x13, 0xb5, 0xa9, 0x36, 0xb3,
+ 0xfc, 0xa9, 0xc6, 0xb3, 0x6d, 0x33, 0x80, 0x2a, 0x7f, 0x13, 0x2e, 0x35,
+ 0x14, 0x7e, 0x1b, 0xb0, 0xf5, 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6,
+ 0xb3, 0x7e, 0x35, 0x14, 0x5e, 0x34, 0x0, 0x1, 0xbe, 0x34, 0x0, 0x1, 0x78,
+ 0x7, 0x7e, 0x34, 0x0, 0x78, 0x12, 0x3, 0xdd, 0x7e, 0x35, 0x14, 0xb, 0x34,
+ 0x7a, 0x35, 0x14, 0x7e, 0x35, 0x10, 0xbe, 0x35, 0x14, 0x38, 0xcb, 0xa9,
+ 0xd2, 0xb4, 0x7e, 0x34, 0x0, 0x5, 0x12, 0x3, 0xdd, 0xe4, 0x12, 0x7, 0xd5,
+ 0xda, 0x3b, 0x22, 0xe5, 0x23, 0xb4, 0x80, 0x16, 0xd2, 0x7, 0x12, 0xb, 0xdd,
+ 0xa9, 0xc2, 0xb4, 0x74, 0x60, 0x12, 0xc, 0x36, 0xa9, 0xd2, 0xb4, 0x12, 0x0,
+ 0x2e, 0x40, 0xfb, 0x22, 0x74, 0x1, 0x12, 0x7, 0xd5, 0xe4, 0x6d, 0x33, 0x12,
+ 0x9, 0xe7, 0x74, 0x1, 0x6d, 0x33, 0x12, 0x9, 0xe7, 0x74, 0x4, 0x6d, 0x33,
+ 0x12, 0x9, 0xe7, 0x7e, 0x34, 0x0, 0x54, 0x12, 0x9, 0xe7, 0x7e, 0x34, 0x0,
+ 0x19, 0x12, 0x3, 0xdd, 0x74, 0x4, 0x7e, 0x34, 0x0, 0x55, 0x12, 0x9, 0xe7,
+ 0x7e, 0x34, 0xa2, 0x1c, 0x12, 0x3, 0xdd, 0x74, 0x4, 0x7e, 0x34, 0x0, 0x15,
+ 0x12, 0x9, 0xe7, 0x7e, 0x34, 0x0, 0xa0, 0x12, 0x3, 0xdd, 0x74, 0x4, 0x7e,
+ 0x34, 0x0, 0x14, 0x12, 0x9, 0xe7, 0x7e, 0x34, 0x0, 0x19, 0x12, 0x3, 0xdd,
+ 0x74, 0x4, 0x7e, 0x34, 0x0, 0x4, 0x12, 0x9, 0xe7, 0x7e, 0x34, 0x0, 0x5,
+ 0x12, 0x3, 0xdd, 0xe4, 0x12, 0x7, 0xd5, 0x74, 0x4, 0x7e, 0x34, 0xff, 0xf7,
+ 0x2, 0x9, 0xe7, 0x7c, 0x7b, 0x7e, 0xa0, 0xef, 0xe5, 0x21, 0x24, 0xfd, 0x68,
+ 0x38, 0x1b, 0xb1, 0x68, 0x22, 0x24, 0x9f, 0x68, 0x3d, 0x1b, 0xb2, 0x68,
+ 0x3e, 0x24, 0x9e, 0x68, 0x35, 0x24, 0x3c, 0x78, 0x4c, 0xa5, 0xbf, 0x0, 0x5,
+ 0x7e, 0xa0, 0x86, 0x80, 0x43, 0xa5, 0xbf, 0x1, 0x3f, 0x7e, 0xa0, 0xa6, 0x80,
+ 0x3a, 0xa5, 0xbf, 0x0, 0x5, 0x7e, 0xa1, 0x23, 0x80, 0x31, 0xa5, 0xbf, 0x1,
+ 0x2d, 0x7e, 0xa1, 0x3d, 0x80, 0x28, 0xa, 0x17, 0x7e, 0x1d, 0x39, 0x2d, 0x31,
+ 0x29, 0xa1, 0x0, 0x8, 0x80, 0x1b, 0x7e, 0xa1, 0x16, 0x80, 0x16, 0xa5, 0xbf,
+ 0x0, 0x9, 0x7e, 0x35, 0x30, 0xa, 0x56, 0x7c, 0xab, 0x80, 0x9, 0xa5, 0xbf,
+ 0x1, 0x5, 0x7e, 0x55, 0x30, 0x7c, 0xab, 0x7c, 0xba, 0x22, 0xca, 0x79, 0xbe,
+ 0xb0, 0x0, 0x28, 0x2e, 0x74, 0x6, 0x12, 0x8, 0x3d, 0x7d, 0x73, 0x6c, 0xff,
+ 0x7e, 0xf0, 0xa5, 0x7d, 0x37, 0x12, 0x9, 0xe7, 0x6c, 0xff, 0x7e, 0xf0, 0xf,
+ 0x7d, 0x37, 0x12, 0x9, 0xe7, 0x6c, 0xff, 0x7e, 0xf0, 0x6a, 0x7d, 0x37, 0x12,
+ 0x9, 0xe7, 0x7e, 0x34, 0x0, 0x5, 0x12, 0x3, 0xdd, 0x80, 0x30, 0x74, 0x1,
+ 0x7e, 0x34, 0xdf, 0xff, 0x12, 0x9, 0xe7, 0x74, 0x6, 0x12, 0x8, 0x3d, 0x7d,
+ 0x73, 0x6c, 0xff, 0x7d, 0x37, 0x12, 0x9, 0xe7, 0x7d, 0x37, 0x12, 0x9, 0xe7,
+ 0x7d, 0x37, 0x12, 0x9, 0xe7, 0x74, 0x2, 0x12, 0x8, 0x3d, 0x7d, 0x73, 0x4e,
+ 0xf0, 0x1, 0x7d, 0x37, 0x12, 0x9, 0xe7, 0xda, 0x79, 0x22, 0xa9, 0xc2, 0xb4,
+ 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3,
+ 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0,
+ 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0xf5, 0xb5, 0xa9, 0x36, 0xb3,
+ 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6,
+ 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x7e, 0x71,
+ 0xb5, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x7e, 0xa1,
+ 0xb5, 0xa9, 0xd2, 0xb4, 0x7c, 0x47, 0x6c, 0x55, 0xa, 0x3a, 0x4d, 0x32, 0x22,
+ 0xca, 0xf8, 0x7e, 0xf0, 0x70, 0x75, 0x91, 0x0, 0xc2, 0x90, 0xc2, 0x91, 0x20,
+ 0x87, 0x3, 0x7e, 0xf1, 0xe4, 0x30, 0x6, 0x30, 0x7e, 0x34, 0x0, 0x2, 0x7a,
+ 0x35, 0x11, 0x7e, 0x18, 0x7, 0x80, 0x7e, 0x8, 0x0, 0x8, 0x12, 0xc, 0x1,
+ 0xe5, 0x8, 0xbe, 0xb0, 0xff, 0x68, 0x17, 0xe5, 0x8, 0x60, 0x13, 0xe5, 0x9,
+ 0xa, 0x2b, 0xe5, 0x8, 0xa, 0x3b, 0x2d, 0x32, 0xbe, 0x34, 0x0, 0xff, 0x78,
+ 0x3, 0x7e, 0xf1, 0x8, 0x5e, 0xf0, 0xfe, 0x7a, 0xf1, 0x92, 0xd2, 0xe8, 0xc2,
+ 0xc0, 0xa9, 0xd5, 0xb7, 0xd2, 0xbd, 0xd2, 0xad, 0xda, 0xf8, 0x22, 0x7f,
+ 0x70, 0xd2, 0x7, 0x12, 0xb, 0xdd, 0x74, 0x2, 0x12, 0xb, 0x44, 0x6d, 0x33,
+ 0x80, 0x12, 0x7f, 0x7, 0x2d, 0x13, 0x7e, 0xb, 0xb0, 0xf5, 0xb5, 0xa9, 0x36,
+ 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0xb, 0x34, 0x7e, 0x25, 0x10, 0xbd, 0x23, 0x38,
+ 0xe7, 0xa9, 0xd2, 0xb4, 0x12, 0xc, 0x41, 0x12, 0x0, 0x2e, 0x50, 0x9, 0x7e,
+ 0x35, 0x17, 0xbe, 0x34, 0x1, 0xf4, 0x28, 0xf2, 0x7e, 0x35, 0x17, 0xbe, 0x34,
+ 0x1, 0xf4, 0x38, 0x3, 0x2, 0xc, 0x5c, 0xc2, 0x86, 0x7e, 0x34, 0x13, 0x88,
+ 0x12, 0x3, 0xdd, 0xd2, 0x86, 0x22, 0x6d, 0x0, 0x74, 0x10, 0x4d, 0x0, 0x78,
+ 0xb, 0x4d, 0x22, 0x78, 0x27, 0x8d, 0x31, 0x7d, 0x12, 0x6d, 0x22, 0x22, 0x7d,
+ 0x43, 0x7d, 0x32, 0x6d, 0x22, 0x2f, 0x11, 0x2d, 0x44, 0x50, 0x2, 0xa5, 0xf,
+ 0xbf, 0x10, 0x40, 0x4, 0x9f, 0x10, 0xb, 0x90, 0x14, 0x78, 0xed, 0x7f, 0x1,
+ 0x6d, 0x22, 0x7d, 0x34, 0x22, 0x7d, 0x41, 0x7d, 0x13, 0x8d, 0x24, 0x7d, 0x2,
+ 0x2f, 0x0, 0x40, 0x4, 0xbd, 0x4, 0x40, 0x4, 0x9d, 0x4, 0xb, 0x14, 0x14,
+ 0x78, 0xf1, 0x7d, 0x23, 0x7d, 0x31, 0x7d, 0x10, 0x6d, 0x0, 0x22, 0x75, 0x84,
+ 0x1, 0x7e, 0x44, 0x1f, 0xff, 0xe4, 0x7a, 0x49, 0xb0, 0x1b, 0x44, 0x78, 0xf9,
+ 0x7e, 0xf8, 0x2, 0xd5, 0xd2, 0x5, 0xc2, 0x6, 0x75, 0x16, 0x0, 0x75, 0x17,
+ 0x0, 0x75, 0x18, 0x0, 0xd2, 0x0, 0xc2, 0x2, 0xc2, 0x3, 0xc2, 0x4, 0x75,
+ 0x21, 0x0, 0x75, 0x22, 0x0, 0x75, 0x23, 0x80, 0x75, 0x2e, 0x0, 0x75, 0x2f,
+ 0x0, 0x75, 0x30, 0x0, 0x75, 0x31, 0x0, 0x75, 0x32, 0x0, 0x75, 0x37, 0xb,
+ 0x75, 0x38, 0x0, 0x75, 0x3d, 0x1, 0x2, 0x4, 0x20, 0x7d, 0x23, 0xa, 0x36,
+ 0x7c, 0xa5, 0xa9, 0xc2, 0xb4, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x1, 0xa9, 0x36,
+ 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9,
+ 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0xf5,
+ 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x7a, 0x71, 0xb5, 0xa9,
+ 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x7a, 0xa1, 0xb5, 0xa9, 0x36, 0xb3,
+ 0xfc, 0xa9, 0xc6, 0xb3, 0xa9, 0xd2, 0xb4, 0x22, 0x7c, 0xab, 0xd2, 0x7, 0x12,
+ 0xb, 0xdd, 0x74, 0xd8, 0xa, 0x3a, 0x7d, 0x23, 0x6d, 0x33, 0x12, 0xb, 0x44,
+ 0xa9, 0xd2, 0xb4, 0x12, 0xc, 0x41, 0x12, 0x0, 0x2e, 0x50, 0x9, 0x7e, 0x35,
+ 0x17, 0xbe, 0x34, 0x5, 0xdc, 0x28, 0xf2, 0x7e, 0x35, 0x17, 0xbe, 0x34, 0x5,
+ 0xdc, 0x38, 0x3, 0x2, 0xc, 0x5c, 0xc2, 0x86, 0x7e, 0x34, 0x13, 0x88, 0x12,
+ 0x3, 0xdd, 0xd2, 0x86, 0x22, 0xca, 0x2b, 0xca, 0x1b, 0xca, 0xb, 0xd2, 0x0,
+ 0x30, 0x90, 0x1c, 0xc2, 0x90, 0x7e, 0x71, 0x91, 0xe5, 0x38, 0x70, 0x3, 0x7a,
+ 0x71, 0x21, 0xe5, 0x38, 0x12, 0x1, 0x20, 0x5, 0x38, 0x30, 0x2, 0x6, 0xe4,
+ 0x12, 0x7, 0x67, 0xf5, 0x91, 0x30, 0x91, 0xb, 0xc2, 0x91, 0x5, 0x38, 0xe5,
+ 0x38, 0x12, 0x7, 0x67, 0xf5, 0x91, 0xda, 0xb, 0xda, 0x1b, 0xda, 0x2b, 0x32,
+ 0xca, 0xf8, 0x7c, 0xfb, 0xe5, 0x23, 0xb4, 0x81, 0x23, 0x74, 0x2, 0x12, 0x8,
+ 0x3d, 0x4c, 0xff, 0x78, 0x8, 0xa9, 0xc0, 0xca, 0x5e, 0x70, 0xdf, 0x80, 0x6,
+ 0xa9, 0xd0, 0xca, 0x4e, 0x70, 0x20, 0x74, 0x2, 0x12, 0x9, 0xe7, 0x74, 0x2,
+ 0x12, 0x8, 0x3d, 0x80, 0x8, 0xe5, 0x23, 0xb4, 0x80, 0x3, 0x12, 0xb, 0x16,
+ 0xda, 0xf8, 0x22, 0xd2, 0x7, 0x12, 0xb, 0xdd, 0xa9, 0xc2, 0xb4, 0x74, 0x9f,
+ 0x12, 0xc, 0x36, 0x12, 0xc, 0x1d, 0xa9, 0xd2, 0xb4, 0x60, 0x3, 0xb4, 0xff,
+ 0x1a, 0x75, 0x23, 0x81, 0xa9, 0xd5, 0xca, 0xa9, 0xd0, 0xca, 0x75, 0xed,
+ 0x9f, 0x75, 0xad, 0x20, 0xa9, 0xd1, 0xea, 0xa9, 0xc1, 0xea, 0x74, 0x1, 0x2,
+ 0xa, 0xac, 0x22, 0xd2, 0x7, 0x12, 0xb, 0xdd, 0xa9, 0xc2, 0xb4, 0x74, 0x5,
+ 0x12, 0xc, 0x36, 0x12, 0xc, 0x1d, 0x7c, 0xab, 0xa9, 0xd2, 0xb4, 0x5e, 0xa0,
+ 0xe3, 0xa9, 0xc2, 0xb4, 0x74, 0x1, 0x12, 0xc, 0x36, 0x7c, 0xba, 0x12, 0xc,
+ 0x36, 0xa9, 0xd2, 0xb4, 0x12, 0x0, 0x2e, 0x40, 0xfb, 0x22, 0x7c, 0xab, 0x7d,
+ 0x12, 0x7c, 0xb3, 0xf5, 0x14, 0x7c, 0x36, 0x7c, 0x25, 0xa, 0x4, 0x7c, 0xb3,
+ 0xf5, 0x13, 0x7c, 0xb7, 0xf5, 0x12, 0xa9, 0xc2, 0xb4, 0x7c, 0xba, 0x12, 0xc,
+ 0x36, 0xe5, 0x14, 0x12, 0xc, 0x36, 0xe5, 0x13, 0x12, 0xc, 0x36, 0xe5, 0x12,
+ 0x2, 0xc, 0x36, 0x7d, 0x52, 0xf5, 0x15, 0x7c, 0xb6, 0x7c, 0xa5, 0xa, 0x44,
+ 0xf5, 0x14, 0x7f, 0x21, 0xf5, 0x13, 0xa9, 0xc2, 0xb4, 0x74, 0xb, 0x12, 0xc,
+ 0x36, 0xe5, 0x15, 0x12, 0xc, 0x36, 0xe5, 0x14, 0x12, 0xc, 0x36, 0xe5, 0x13,
+ 0x12, 0xc, 0x36, 0xe4, 0x2, 0xc, 0x36, 0xd2, 0xcf, 0x85, 0x3d, 0xcc, 0x75,
+ 0xec, 0xff, 0x75, 0xee, 0xff, 0x75, 0xeb, 0x3, 0x75, 0xac, 0x40, 0xa9, 0xc5,
+ 0xca, 0x75, 0xed, 0xf, 0x75, 0xad, 0xb0, 0xa9, 0xd7, 0x94, 0xa9, 0xd4, 0x94,
+ 0x22, 0x12, 0xb, 0x9c, 0xa9, 0xa6, 0x94, 0xb3, 0x92, 0x6, 0x30, 0x6, 0x6,
+ 0x12, 0xc, 0x2a, 0x12, 0xa, 0xe3, 0x12, 0x8, 0x9a, 0x12, 0xc, 0xf, 0xd2,
+ 0xaf, 0x30, 0x3, 0xfd, 0x2, 0xc, 0x54, 0xa9, 0xc2, 0xb4, 0x30, 0x7, 0x4,
+ 0x74, 0x6, 0x80, 0x2, 0x74, 0x4, 0x12, 0xc, 0x36, 0xa9, 0xd2, 0xb4, 0x22,
+ 0xe5, 0x32, 0xb4, 0xc, 0xb, 0xc2, 0x86, 0x7e, 0x34, 0x0, 0x64, 0x12, 0x3,
+ 0xdd, 0xd2, 0x86, 0x22, 0x12, 0xb, 0x71, 0x7e, 0x35, 0x11, 0x12, 0x0, 0xe,
+ 0xa9, 0xd2, 0xb4, 0xd3, 0x22, 0xc2, 0x8c, 0x43, 0x89, 0x2, 0x75, 0x8c, 0x1,
+ 0x75, 0x8a, 0x0, 0xd2, 0xa9, 0x22, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc,
+ 0xa9, 0xc6, 0xb3, 0xe5, 0xb5, 0x22, 0xd2, 0xc8, 0x75, 0xb3, 0x13, 0xa9,
+ 0xd1, 0xb4, 0xa9, 0xc0, 0xb4, 0x22, 0xf5, 0xb5, 0xa9, 0x36, 0xb3, 0xfc,
+ 0xa9, 0xc6, 0xb3, 0xd3, 0x22, 0xc2, 0x8c, 0x6d, 0x33, 0x7a, 0x35, 0x17,
+ 0xd2, 0x8c, 0x22, 0x7e, 0x35, 0x17, 0xb, 0x34, 0x7a, 0x35, 0x17, 0x22, 0x85,
+ 0x3d, 0xcc, 0xe5, 0x3d, 0x2, 0xa, 0xac, 0x2, 0xc, 0x4b, 0xff,
diff --git a/drivers/input/touchscreen/focaltech_touch/include/pramboot/FT8607_Pramboot_V0.3_20160727.i b/drivers/input/touchscreen/focaltech_touch/include/pramboot/FT8607_Pramboot_V0.3_20160727.i
new file mode 100644
index 000000000000..ebb31f1ebc7c
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/include/pramboot/FT8607_Pramboot_V0.3_20160727.i
@@ -0,0 +1,248 @@
+0x2, 0x9, 0xb2, 0xca, 0x39, 0x12, 0xc, 0x71, 0xda, 0x39, 0x32, 0x2, 0x0, 0x3,
+ 0x6d, 0x22, 0x80, 0x13, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6,
+ 0xb3, 0xe5, 0xb5, 0x7a, 0xb, 0xb0, 0xb, 0x14, 0xb, 0x24, 0xbd, 0x32, 0x38,
+ 0xe9, 0x22, 0xff, 0x2, 0xa, 0x87, 0xa9, 0xc2, 0xb4, 0x74, 0x5, 0x12, 0xc,
+ 0x5c, 0x12, 0xc, 0x43, 0xa9, 0xd2, 0xb4, 0x30, 0xe0, 0x2, 0xd3, 0x22, 0xc3,
+ 0x22, 0x2, 0x0, 0xf9, 0xca, 0x3b, 0x7a, 0xd, 0x8, 0x7f, 0x31, 0xe5, 0x23,
+ 0xb4, 0x80, 0x2, 0x80, 0x3, 0x2, 0x0, 0xdc, 0x7f, 0x13, 0x5e, 0x34, 0x0,
+ 0x7f, 0x7d, 0x23, 0x7e, 0x34, 0x0, 0x80, 0x9d, 0x32, 0x7a, 0x35, 0xe, 0x7e,
+ 0x35, 0xc, 0xbe, 0x35, 0xe, 0x38, 0x2, 0x80, 0x5d, 0x7e, 0x35, 0xe, 0x7a,
+ 0x35, 0x10, 0x7f, 0x13, 0x7e, 0xd, 0x8, 0x12, 0x9, 0xa, 0x7e, 0x35, 0xc,
+ 0x9e, 0x35, 0xe, 0x7a, 0x35, 0xc, 0x7e, 0x35, 0xe, 0x6d, 0x22, 0x2f, 0x31,
+ 0x7e, 0x1d, 0x8, 0x2e, 0x35, 0xe, 0x7a, 0x1d, 0x8, 0x80, 0x27, 0x7e, 0x34,
+ 0x0, 0x80, 0x7a, 0x35, 0x10, 0x7f, 0x13, 0x7e, 0xd, 0x8, 0x12, 0x9, 0xa,
+ 0x7e, 0x35, 0xc, 0x9e, 0x34, 0x0, 0x80, 0x7a, 0x35, 0xc, 0x7e, 0x1d, 0x8,
+ 0x2e, 0x34, 0x0, 0x80, 0x7a, 0x1d, 0x8, 0x2e, 0x38, 0x0, 0x80, 0x7e, 0x35,
+ 0xc, 0xbe, 0x34, 0x0, 0x80, 0x50, 0xd0, 0x4d, 0x33, 0x68, 0x26, 0x7a, 0x35,
+ 0x10, 0x7f, 0x13, 0x7e, 0xd, 0x8, 0x12, 0x9, 0xa, 0x80, 0x19, 0x74, 0x2,
+ 0x12, 0x8, 0xad, 0x5e, 0x70, 0xf4, 0x12, 0x9, 0xfe, 0x7e, 0x35, 0xc, 0x7a,
+ 0x35, 0x10, 0x7f, 0x13, 0x7e, 0xd, 0x8, 0x12, 0x6, 0x42, 0xd3, 0xda, 0x3b,
+ 0x22, 0xa9, 0xc0, 0x93, 0x75, 0x38, 0x0, 0x32, 0xc, 0x86, 0xf3, 0x79, 0x96,
+ 0x69, 0x34, 0xcb, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x7c, 0x6b, 0xc2, 0x2, 0xe5, 0x21, 0x14, 0x78, 0x3, 0x2, 0x2,
+ 0xcd, 0x1b, 0xb1, 0x78, 0x3, 0x2, 0x2, 0x30, 0x1b, 0xb1, 0x78, 0x3, 0x2,
+ 0x2, 0x7c, 0x1b, 0xb1, 0x78, 0x3, 0x2, 0x2, 0x8d, 0x1b, 0xb1, 0x78, 0x3,
+ 0x2, 0x2, 0xb4, 0x24, 0xf9, 0x78, 0x3, 0x2, 0x2, 0xc9, 0x24, 0xaf, 0x78,
+ 0x3, 0x2, 0x3, 0x37, 0x24, 0xfd, 0x68, 0x2d, 0x14, 0x78, 0x3, 0x2, 0x2,
+ 0xd0, 0x14, 0x78, 0x3, 0x2, 0x2, 0xcd, 0x1b, 0xb2, 0x78, 0x3, 0x2, 0x2,
+ 0xcd, 0x24, 0xda, 0x68, 0x19, 0x24, 0xe6, 0x68, 0x12, 0x24, 0xeb, 0x68,
+ 0x2e, 0x24, 0xf3, 0x78, 0x3, 0x2, 0x2, 0xcd, 0x24, 0x77, 0x68, 0x3, 0x2,
+ 0x3, 0x41, 0x2, 0x3, 0x3e, 0xbe, 0x60, 0x4, 0x50, 0xc, 0x75, 0x16, 0x0,
+ 0x7c, 0x16, 0x2e, 0x10, 0x24, 0x7c, 0xb7, 0xa5, 0xf7, 0xa5, 0xbe, 0x0, 0x2,
+ 0x80, 0x3, 0x2, 0x3, 0x41, 0xd2, 0x2, 0x22, 0x7c, 0xb6, 0x24, 0x0, 0x78,
+ 0x3, 0x2, 0x3, 0x41, 0x1b, 0xb1, 0x68, 0x1e, 0x14, 0x68, 0x1e, 0x14, 0x68,
+ 0x1e, 0x14, 0x68, 0x1e, 0xb, 0xb2, 0x78, 0x33, 0x30, 0x1, 0x7, 0x7e, 0x8,
+ 0x0, 0x3e, 0x2, 0x2, 0x4d, 0x7e, 0x8, 0x1, 0x4a, 0x2, 0x2, 0x4d, 0x2, 0x2,
+ 0xf5, 0x2, 0x2, 0xfc, 0x2, 0x3, 0x14, 0xa, 0x27, 0x7e, 0xd, 0x39, 0xb, 0x16,
+ 0xb, 0xa, 0x30, 0x2d, 0x32, 0x1b, 0xa, 0x30, 0x6d, 0x33, 0x7e, 0xd, 0x39,
+ 0x79, 0x30, 0x0, 0x6, 0x22, 0x7c, 0xb7, 0x62, 0x16, 0x7e, 0x2d, 0x39, 0x2e,
+ 0x54, 0x0, 0x6, 0xb, 0x2a, 0x20, 0x7d, 0x12, 0xb, 0x14, 0x1b, 0x2a, 0x10,
+ 0x7e, 0xd, 0x39, 0x2d, 0x12, 0x39, 0x70, 0x0, 0x8, 0x7e, 0xd, 0x39, 0x69,
+ 0x50, 0x0, 0x4, 0x69, 0x20, 0x0, 0x6, 0xbd, 0x25, 0x50, 0x3, 0x2, 0x3, 0x41,
+ 0xb2, 0x1, 0x7a, 0xd, 0x33, 0x7e, 0x34, 0x0, 0x2, 0x2, 0x3, 0x33, 0x7c,
+ 0xb6, 0x1b, 0xb1, 0x68, 0x1d, 0x14, 0x68, 0x1d, 0xb, 0xb1, 0x68, 0x3, 0x2,
+ 0x3, 0x41, 0x30, 0x1, 0x6, 0x7e, 0x8, 0x0, 0x3e, 0x80, 0x4, 0x7e, 0x8, 0x1,
+ 0x4a, 0x7a, 0xd, 0x39, 0x2, 0x2, 0xe4, 0x2, 0x2, 0xf5, 0xa, 0x57, 0x6d,
+ 0x44, 0x7e, 0xd, 0x39, 0x69, 0x30, 0x0, 0x2, 0xb, 0xa, 0x20, 0x2f, 0x12,
+ 0x79, 0x30, 0x0, 0x2, 0x1b, 0xa, 0x20, 0x7e, 0x1d, 0x39, 0x7a, 0x1d, 0x33,
+ 0xd2, 0x2, 0x7e, 0x34, 0x0, 0x1, 0x2, 0x3, 0x33, 0xbe, 0x60, 0x1, 0x68, 0x9,
+ 0xa5, 0xbe, 0x2, 0x5, 0x7a, 0x71, 0x3d, 0xd2, 0x3, 0xd2, 0x2, 0x22, 0x75,
+ 0xe6, 0x0, 0xe4, 0x7e, 0x34, 0x1, 0x4, 0x7e, 0x24, 0x0, 0xff, 0x7a, 0x1b,
+ 0xb0, 0x7e, 0x34, 0x1, 0x5, 0x7a, 0x1b, 0xb0, 0x7e, 0x34, 0x1, 0x8, 0x7a,
+ 0x1b, 0xb0, 0x7e, 0x34, 0x1, 0x9, 0x7a, 0x1b, 0xb0, 0xd2, 0x4, 0x22, 0xa5,
+ 0xbe, 0x1, 0x4, 0x7a, 0x71, 0x37, 0x22, 0xa5, 0xbe, 0x2, 0x2, 0x80, 0x3,
+ 0x2, 0x3, 0x41, 0x7a, 0x71, 0x22, 0x22, 0x7a, 0x71, 0x32, 0x22, 0xd2, 0x2,
+ 0x22, 0x1b, 0x61, 0x68, 0x21, 0x1b, 0x60, 0x68, 0x24, 0x1b, 0x60, 0x68,
+ 0x38, 0x1b, 0x60, 0x68, 0x40, 0xb, 0x62, 0x78, 0x5d, 0xa, 0x37, 0x7d, 0x3,
+ 0x6d, 0x11, 0x7e, 0x1d, 0x39, 0x79, 0x11, 0x0, 0x2, 0x1b, 0x1a, 0x0, 0x22,
+ 0xa, 0x57, 0x7c, 0xab, 0xe4, 0x80, 0x2, 0xa, 0x57, 0x6d, 0x44, 0x7e, 0xd,
+ 0x39, 0x69, 0x30, 0x0, 0x2, 0xb, 0xa, 0x20, 0x2f, 0x12, 0x79, 0x30, 0x0,
+ 0x2, 0x1b, 0xa, 0x20, 0x22, 0x7c, 0x67, 0x6c, 0x77, 0x7e, 0xd, 0x39, 0x79,
+ 0x30, 0x0, 0x4, 0x22, 0xa, 0x27, 0x7e, 0xd, 0x39, 0xb, 0x16, 0xb, 0xa, 0x30,
+ 0x2d, 0x32, 0x1b, 0xa, 0x30, 0x7e, 0x34, 0x0, 0x3, 0x7a, 0x35, 0x2e, 0x22,
+ 0x7e, 0x34, 0x0, 0x4, 0x7a, 0x35, 0x2e, 0x75, 0x16, 0x0, 0x22, 0xca, 0x3b,
+ 0x7a, 0x15, 0x8, 0x7f, 0x31, 0x75, 0xe, 0x0, 0x7e, 0x35, 0x8, 0xbe, 0x34,
+ 0x0, 0x0, 0x38, 0x4f, 0x7e, 0x34, 0xff, 0xff, 0x7a, 0x35, 0x8, 0x75, 0xe,
+ 0x1, 0x80, 0x43, 0x7e, 0x34, 0x0, 0x80, 0x7a, 0x35, 0x11, 0x7f, 0x13, 0x7e,
+ 0x8, 0x2, 0x56, 0x12, 0xc, 0x27, 0x7e, 0x35, 0x8, 0x9e, 0x34, 0x0, 0x80,
+ 0x7a, 0x35, 0x8, 0x2e, 0x38, 0x0, 0x80, 0x6d, 0x33, 0x7a, 0x35, 0xf, 0x7e,
+ 0x35, 0xf, 0x9, 0x63, 0x2, 0x56, 0x7e, 0xd, 0xa, 0x7e, 0xb, 0x70, 0x6c,
+ 0x76, 0x7a, 0xb, 0x70, 0x7e, 0x35, 0xf, 0xb, 0x34, 0x7a, 0x35, 0xf, 0xbe,
+ 0x34, 0x0, 0x80, 0x78, 0xe0, 0x7e, 0x35, 0x8, 0xbe, 0x34, 0x0, 0x80, 0x38,
+ 0xb4, 0xe5, 0xe, 0x60, 0x5, 0xb, 0x34, 0x7a, 0x35, 0x8, 0x7e, 0x35, 0x8,
+ 0x7a, 0x35, 0x11, 0x7f, 0x13, 0x7e, 0x8, 0x2, 0x56, 0x12, 0xc, 0x27, 0x6d,
+ 0x33, 0x80, 0x17, 0x7e, 0x35, 0xf, 0x9, 0x63, 0x2, 0x56, 0x7e, 0xd, 0xa,
+ 0x7e, 0xb, 0x70, 0x6c, 0x76, 0x7a, 0xb, 0x70, 0x7e, 0x35, 0xf, 0xb, 0x34,
+ 0x7a, 0x35, 0xf, 0x7e, 0x35, 0x8, 0xbe, 0x35, 0xf, 0x38, 0xde, 0xda, 0x3b,
+ 0x22, 0xe5, 0x32, 0xb4, 0xc, 0xb, 0xc2, 0x86, 0x7e, 0x34, 0x0, 0x64, 0x12,
+ 0xb, 0xb0, 0xd2, 0x86, 0x22, 0xff, 0x56, 0x30, 0x2e, 0x33, 0x4a, 0x75, 0x6c,
+ 0x20, 0x32, 0x37, 0x20, 0x32, 0x30, 0x31, 0x36, 0x0, 0x46, 0x54, 0x53, 0x38,
+ 0x36, 0x30, 0x37, 0x5f, 0x70, 0x72, 0x61, 0x6d, 0x62, 0x6f, 0x6f, 0x74,
+ 0x12, 0xb, 0xf4, 0x2, 0x5, 0x66, 0x7e, 0x35, 0x2e, 0x1b, 0x34, 0x68, 0x57,
+ 0x1b, 0x35, 0x78, 0x3, 0x2, 0x4, 0xb3, 0x1b, 0x34, 0x78, 0x3, 0x2, 0x4,
+ 0xdd, 0xb, 0x35, 0x68, 0x3, 0x2, 0x5, 0x52, 0x6d, 0x33, 0x7a, 0x35, 0x2e,
+ 0x7a, 0x35, 0x30, 0x30, 0x5, 0x5, 0x12, 0x3, 0xee, 0xc2, 0x5, 0x7e, 0xd,
+ 0x33, 0x69, 0x30, 0x0, 0x4, 0x7a, 0x35, 0xc, 0x69, 0x30, 0x0, 0x2, 0xb, 0xa,
+ 0x20, 0x2e, 0x14, 0x0, 0x8, 0x12, 0x0, 0x46, 0xd2, 0x5, 0x7e, 0x2d, 0x33,
+ 0x69, 0x12, 0x0, 0x4, 0x69, 0x32, 0x0, 0x2, 0xb, 0x2a, 0x20, 0x12, 0x9,
+ 0x5f, 0x2e, 0x34, 0x10, 0x0, 0x2, 0x5, 0x4f, 0x6d, 0x33, 0x7a, 0x35, 0x2e,
+ 0x7e, 0x34, 0x1, 0x0, 0x7a, 0x35, 0x11, 0x7e, 0xd, 0x33, 0x69, 0x30, 0x0,
+ 0x2, 0xb, 0xa, 0x20, 0x2e, 0x14, 0x0, 0x8, 0x12, 0xc, 0x27, 0x20, 0x0, 0x3,
+ 0x2, 0x5, 0x52, 0x7e, 0x1d, 0x33, 0x29, 0xb1, 0x0, 0x8, 0xf5, 0x91, 0x2,
+ 0x5, 0x52, 0x6d, 0x33, 0x7a, 0x35, 0x2e, 0x7a, 0x35, 0x30, 0x7e, 0x18, 0x0,
+ 0x16, 0x7a, 0x1d, 0xa, 0x7e, 0xd, 0x33, 0x69, 0x30, 0x0, 0x2, 0xb, 0xa,
+ 0x20, 0x69, 0x10, 0x0, 0x4, 0x12, 0x3, 0x42, 0x12, 0x3, 0xee, 0x7e, 0x34,
+ 0xf0, 0x55, 0x2, 0x5, 0x4f, 0x6d, 0x33, 0x7a, 0x35, 0x2e, 0x7a, 0x35, 0x30,
+ 0xe5, 0x37, 0xb4, 0xa, 0x15, 0xe5, 0x23, 0xb4, 0x80, 0xb, 0xe4, 0x12, 0xa,
+ 0x49, 0x74, 0x1, 0x12, 0xa, 0x49, 0x80, 0x4e, 0x12, 0x6, 0xd8, 0x80, 0x49,
+ 0xe5, 0x37, 0xb4, 0xb, 0x27, 0xe5, 0x23, 0xb4, 0x80, 0x11, 0x7e, 0xf0, 0x1,
+ 0x7c, 0xbf, 0x12, 0x5, 0x6d, 0xb, 0xf0, 0xbe, 0xf0, 0x11, 0x78, 0xf4, 0x80,
+ 0x2e, 0x7e, 0xf0, 0x4, 0x7c, 0xbf, 0x12, 0x5, 0x6d, 0xb, 0xf0, 0xbe, 0xf0,
+ 0x40, 0x78, 0xf4, 0x80, 0x1d, 0xe5, 0x37, 0xa, 0x3b, 0x9e, 0x34, 0x0, 0x80,
+ 0x7c, 0xe7, 0x6c, 0xdd, 0x80, 0x9, 0x7c, 0xbe, 0x12, 0x5, 0x6d, 0xb, 0xe0,
+ 0xb, 0xd0, 0xe5, 0x22, 0xbc, 0xbd, 0x38, 0xf1, 0x12, 0x3, 0xee, 0x7e, 0x34,
+ 0xf0, 0xaa, 0x7a, 0x35, 0x30, 0x30, 0x4, 0x11, 0x7e, 0x34, 0x13, 0x88, 0x12,
+ 0xb, 0xb0, 0x7e, 0x34, 0x13, 0x88, 0x12, 0xb, 0xb0, 0x75, 0xe9, 0xff, 0x30,
+ 0x6, 0x3, 0x2, 0x4, 0x26, 0x22, 0xca, 0xf8, 0x7c, 0xfb, 0xe5, 0x23, 0xb4,
+ 0x80, 0x4a, 0xd2, 0x7, 0x12, 0xc, 0x14, 0x74, 0x20, 0xca, 0xb8, 0xa, 0x3f,
+ 0x6d, 0x22, 0x74, 0xc, 0x2f, 0x11, 0x14, 0x78, 0xfb, 0xda, 0xb8, 0x12, 0xb,
+ 0x2b, 0xa9, 0xd2, 0xb4, 0x12, 0xc, 0x67, 0x12, 0x0, 0x2e, 0x50, 0x9, 0x7e,
+ 0x35, 0x17, 0xbe, 0x34, 0x1, 0xf4, 0x28, 0xf2, 0x7e, 0x35, 0x17, 0xbe, 0x34,
+ 0x1, 0xf4, 0x38, 0x6, 0x12, 0xc, 0x82, 0x2, 0x6, 0x3f, 0xc2, 0x86, 0x7e,
+ 0x34, 0x13, 0x88, 0x12, 0xb, 0xb0, 0xd2, 0x86, 0x2, 0x6, 0x3f, 0x74, 0x1,
+ 0x12, 0x8, 0x45, 0x74, 0x1, 0x6d, 0x33, 0x12, 0x9, 0xfe, 0xe4, 0x12, 0x8,
+ 0xad, 0x5e, 0x34, 0x80, 0x0, 0x7c, 0x4f, 0x6c, 0x55, 0x3e, 0x24, 0x4d, 0x32,
+ 0x12, 0x9, 0xfe, 0x74, 0x4, 0x6d, 0x33, 0x12, 0x9, 0xfe, 0x7e, 0x34, 0x0,
+ 0x50, 0x12, 0x9, 0xfe, 0x7e, 0x34, 0x0, 0x19, 0x12, 0xb, 0xb0, 0x74, 0x4,
+ 0x7e, 0x34, 0x0, 0x51, 0x12, 0x9, 0xfe, 0x7e, 0x34, 0xa2, 0x1c, 0x12, 0xb,
+ 0xb0, 0x74, 0x4, 0x7e, 0x34, 0x0, 0x11, 0x12, 0x9, 0xfe, 0x7e, 0x34, 0x0,
+ 0x19, 0x12, 0xb, 0xb0, 0x74, 0x4, 0x7e, 0x34, 0x0, 0x10, 0x12, 0x9, 0xfe,
+ 0x7e, 0x34, 0x0, 0x19, 0x12, 0xb, 0xb0, 0x74, 0x4, 0x6d, 0x33, 0x12, 0x9,
+ 0xfe, 0x7e, 0x34, 0x0, 0x5, 0x12, 0xb, 0xb0, 0xe4, 0x12, 0x8, 0x45, 0x74,
+ 0x4, 0x7e, 0x34, 0xff, 0xf7, 0x12, 0x9, 0xfe, 0xda, 0xf8, 0x22, 0xca, 0x3b,
+ 0x7f, 0x30, 0x7c, 0xb6, 0xf5, 0x12, 0x7c, 0xb7, 0xf5, 0x13, 0x74, 0x1, 0x7e,
+ 0x35, 0x10, 0x1e, 0x34, 0x1b, 0x34, 0x4e, 0x60, 0x80, 0x12, 0x9, 0xfe, 0x12,
+ 0x8, 0x45, 0xa9, 0xc2, 0xb4, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x2, 0xa9, 0x36,
+ 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9,
+ 0xc6, 0xb3, 0x85, 0x12, 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3,
+ 0x85, 0x13, 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x6d, 0x33,
+ 0x80, 0x2a, 0x7f, 0x13, 0x2e, 0x35, 0x14, 0x7e, 0x1b, 0xb0, 0xf5, 0xb5,
+ 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x7e, 0x35, 0x14, 0x5e, 0x34, 0x0,
+ 0x1, 0xbe, 0x34, 0x0, 0x1, 0x78, 0x7, 0x7e, 0x34, 0x0, 0x78, 0x12, 0xb,
+ 0xb0, 0x7e, 0x35, 0x14, 0xb, 0x34, 0x7a, 0x35, 0x14, 0x7e, 0x35, 0x10, 0xbe,
+ 0x35, 0x14, 0x38, 0xcb, 0xa9, 0xd2, 0xb4, 0x7e, 0x34, 0x0, 0x5, 0x12, 0xb,
+ 0xb0, 0xe4, 0x12, 0x8, 0x45, 0xda, 0x3b, 0x22, 0xe5, 0x23, 0xb4, 0x80, 0x16,
+ 0xd2, 0x7, 0x12, 0xc, 0x14, 0xa9, 0xc2, 0xb4, 0x74, 0x60, 0x12, 0xc, 0x5c,
+ 0xa9, 0xd2, 0xb4, 0x12, 0x0, 0x2e, 0x40, 0xfb, 0x22, 0x74, 0x1, 0x12, 0x8,
+ 0x45, 0xe4, 0x6d, 0x33, 0x12, 0x9, 0xfe, 0x74, 0x1, 0x6d, 0x33, 0x12, 0x9,
+ 0xfe, 0x74, 0x4, 0x6d, 0x33, 0x12, 0x9, 0xfe, 0x7e, 0x34, 0x0, 0x54, 0x12,
+ 0x9, 0xfe, 0x7e, 0x34, 0x0, 0x19, 0x12, 0xb, 0xb0, 0x74, 0x4, 0x7e, 0x34,
+ 0x0, 0x55, 0x12, 0x9, 0xfe, 0x7e, 0x34, 0xa2, 0x1c, 0x12, 0xb, 0xb0, 0x74,
+ 0x4, 0x7e, 0x34, 0x0, 0x15, 0x12, 0x9, 0xfe, 0x7e, 0x34, 0x0, 0xa0, 0x12,
+ 0xb, 0xb0, 0x74, 0x4, 0x7e, 0x34, 0x0, 0x14, 0x12, 0x9, 0xfe, 0x7e, 0x34,
+ 0x0, 0x19, 0x12, 0xb, 0xb0, 0x74, 0x4, 0x7e, 0x34, 0x0, 0x4, 0x12, 0x9,
+ 0xfe, 0x7e, 0x34, 0x0, 0x5, 0x12, 0xb, 0xb0, 0xe4, 0x12, 0x8, 0x45, 0x74,
+ 0x4, 0x7e, 0x34, 0xff, 0xf7, 0x2, 0x9, 0xfe, 0xca, 0xf8, 0xc2, 0x7, 0x7e,
+ 0xf0, 0x70, 0x75, 0x91, 0x0, 0xc2, 0x90, 0xc2, 0x91, 0x20, 0x7, 0x10, 0x7e,
+ 0xf1, 0xe4, 0xbe, 0xf0, 0x2, 0x40, 0x5, 0xbe, 0xf0, 0xfd, 0x28, 0x3, 0x7e,
+ 0xf0, 0x70, 0x30, 0x6, 0x38, 0x7e, 0x34, 0x0, 0x2, 0x7a, 0x35, 0x11, 0x7e,
+ 0x18, 0x7, 0x80, 0x7e, 0x8, 0x0, 0x8, 0x12, 0xc, 0x27, 0xe5, 0x8, 0xbe,
+ 0xb0, 0xff, 0x68, 0x19, 0xe5, 0x8, 0x60, 0x15, 0xe5, 0x9, 0xa, 0x2b, 0xe5,
+ 0x8, 0xa, 0x3b, 0x2d, 0x32, 0xbe, 0x34, 0x0, 0xff, 0x78, 0x5, 0x7e, 0xf1,
+ 0x8, 0xd2, 0x7, 0x20, 0x7, 0x3, 0x7e, 0xf0, 0x70, 0x5e, 0xf0, 0xfe, 0x7a,
+ 0xf1, 0x92, 0xd2, 0xe8, 0xc2, 0xc0, 0xa9, 0xd5, 0xb7, 0xd2, 0xbd, 0xd2,
+ 0xad, 0xda, 0xf8, 0x22, 0x7c, 0x7b, 0x7e, 0xa0, 0xef, 0xe5, 0x21, 0x24,
+ 0xfd, 0x68, 0x38, 0x1b, 0xb1, 0x68, 0x22, 0x24, 0x9f, 0x68, 0x3d, 0x1b,
+ 0xb2, 0x68, 0x3e, 0x24, 0x9e, 0x68, 0x35, 0x24, 0x3c, 0x78, 0x4c, 0xa5,
+ 0xbf, 0x0, 0x5, 0x7e, 0xa0, 0x86, 0x80, 0x43, 0xa5, 0xbf, 0x1, 0x3f, 0x7e,
+ 0xa0, 0xa7, 0x80, 0x3a, 0xa5, 0xbf, 0x0, 0x5, 0x7e, 0xa1, 0x23, 0x80, 0x31,
+ 0xa5, 0xbf, 0x1, 0x2d, 0x7e, 0xa1, 0x3d, 0x80, 0x28, 0xa, 0x17, 0x7e, 0x1d,
+ 0x39, 0x2d, 0x31, 0x29, 0xa1, 0x0, 0x8, 0x80, 0x1b, 0x7e, 0xa1, 0x16, 0x80,
+ 0x16, 0xa5, 0xbf, 0x0, 0x9, 0x7e, 0x35, 0x30, 0xa, 0x56, 0x7c, 0xab, 0x80,
+ 0x9, 0xa5, 0xbf, 0x1, 0x5, 0x7e, 0x55, 0x30, 0x7c, 0xab, 0x7c, 0xba, 0x22,
+ 0xca, 0x79, 0xbe, 0xb0, 0x0, 0x28, 0x2e, 0x74, 0x6, 0x12, 0x8, 0xad, 0x7d,
+ 0x73, 0x6c, 0xff, 0x7e, 0xf0, 0xa5, 0x7d, 0x37, 0x12, 0x9, 0xfe, 0x6c, 0xff,
+ 0x7e, 0xf0, 0xf, 0x7d, 0x37, 0x12, 0x9, 0xfe, 0x6c, 0xff, 0x7e, 0xf0, 0x6a,
+ 0x7d, 0x37, 0x12, 0x9, 0xfe, 0x7e, 0x34, 0x0, 0x5, 0x12, 0xb, 0xb0, 0x80,
+ 0x30, 0x74, 0x1, 0x7e, 0x34, 0xdf, 0xff, 0x12, 0x9, 0xfe, 0x74, 0x6, 0x12,
+ 0x8, 0xad, 0x7d, 0x73, 0x6c, 0xff, 0x7d, 0x37, 0x12, 0x9, 0xfe, 0x7d, 0x37,
+ 0x12, 0x9, 0xfe, 0x7d, 0x37, 0x12, 0x9, 0xfe, 0x74, 0x2, 0x12, 0x8, 0xad,
+ 0x7d, 0x73, 0x4e, 0xf0, 0x1, 0x7d, 0x37, 0x12, 0x9, 0xfe, 0xda, 0x79, 0x22,
+ 0xa9, 0xc2, 0xb4, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x5, 0xa9, 0x36, 0xb3, 0xfc,
+ 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3,
+ 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0xf5, 0xb5, 0xa9,
+ 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc,
+ 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3,
+ 0x7e, 0x71, 0xb5, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3,
+ 0x7e, 0xa1, 0xb5, 0xa9, 0xd2, 0xb4, 0x7c, 0x47, 0x6c, 0x55, 0xa, 0x3a, 0x4d,
+ 0x32, 0x22, 0x7f, 0x70, 0xd2, 0x7, 0x12, 0xc, 0x14, 0x74, 0x2, 0x12, 0xb,
+ 0x2b, 0x6d, 0x33, 0x80, 0x12, 0x7f, 0x7, 0x2d, 0x13, 0x7e, 0xb, 0xb0, 0xf5,
+ 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0xb, 0x34, 0x7e, 0x25, 0x10,
+ 0xbd, 0x23, 0x38, 0xe7, 0xa9, 0xd2, 0xb4, 0x12, 0xc, 0x67, 0x12, 0x0, 0x2e,
+ 0x50, 0x9, 0x7e, 0x35, 0x17, 0xbe, 0x34, 0x1, 0xf4, 0x28, 0xf2, 0x7e, 0x35,
+ 0x17, 0xbe, 0x34, 0x1, 0xf4, 0x38, 0x3, 0x2, 0xc, 0x82, 0xc2, 0x86, 0x7e,
+ 0x34, 0x13, 0x88, 0x12, 0xb, 0xb0, 0xd2, 0x86, 0x22, 0x6d, 0x0, 0x74, 0x10,
+ 0x4d, 0x0, 0x78, 0xb, 0x4d, 0x22, 0x78, 0x27, 0x8d, 0x31, 0x7d, 0x12, 0x6d,
+ 0x22, 0x22, 0x7d, 0x43, 0x7d, 0x32, 0x6d, 0x22, 0x2f, 0x11, 0x2d, 0x44,
+ 0x50, 0x2, 0xa5, 0xf, 0xbf, 0x10, 0x40, 0x4, 0x9f, 0x10, 0xb, 0x90, 0x14,
+ 0x78, 0xed, 0x7f, 0x1, 0x6d, 0x22, 0x7d, 0x34, 0x22, 0x7d, 0x41, 0x7d, 0x13,
+ 0x8d, 0x24, 0x7d, 0x2, 0x2f, 0x0, 0x40, 0x4, 0xbd, 0x4, 0x40, 0x4, 0x9d,
+ 0x4, 0xb, 0x14, 0x14, 0x78, 0xf1, 0x7d, 0x23, 0x7d, 0x31, 0x7d, 0x10, 0x6d,
+ 0x0, 0x22, 0x75, 0x84, 0x1, 0x7e, 0x44, 0x1f, 0xff, 0xe4, 0x7a, 0x49, 0xb0,
+ 0x1b, 0x44, 0x78, 0xf9, 0x7e, 0xf8, 0x2, 0xd5, 0xd2, 0x5, 0xc2, 0x6, 0x75,
+ 0x16, 0x0, 0x75, 0x17, 0x0, 0x75, 0x18, 0x0, 0xd2, 0x0, 0xc2, 0x2, 0xc2,
+ 0x3, 0xc2, 0x4, 0x75, 0x21, 0x0, 0x75, 0x22, 0x0, 0x75, 0x23, 0x80, 0x75,
+ 0x2e, 0x0, 0x75, 0x2f, 0x0, 0x75, 0x30, 0x0, 0x75, 0x31, 0x0, 0x75, 0x32,
+ 0x0, 0x75, 0x37, 0xb, 0x75, 0x38, 0x0, 0x75, 0x3d, 0x1, 0x2, 0x4, 0x20,
+ 0x7d, 0x23, 0xa, 0x36, 0x7c, 0xa5, 0xa9, 0xc2, 0xb4, 0xa9, 0xc6, 0xb3, 0x75,
+ 0xb5, 0x1, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9,
+ 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc,
+ 0xa9, 0xc6, 0xb3, 0xf5, 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3,
+ 0x7a, 0x71, 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x7a, 0xa1,
+ 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0xa9, 0xd2, 0xb4, 0x22,
+ 0x7c, 0xab, 0xd2, 0x7, 0x12, 0xc, 0x14, 0x74, 0xd8, 0xa, 0x3a, 0x7d, 0x23,
+ 0x6d, 0x33, 0x12, 0xb, 0x2b, 0xa9, 0xd2, 0xb4, 0x12, 0xc, 0x67, 0x12, 0x0,
+ 0x2e, 0x50, 0x9, 0x7e, 0x35, 0x17, 0xbe, 0x34, 0x5, 0xdc, 0x28, 0xf2, 0x7e,
+ 0x35, 0x17, 0xbe, 0x34, 0x5, 0xdc, 0x38, 0x3, 0x2, 0xc, 0x82, 0xc2, 0x86,
+ 0x7e, 0x34, 0x13, 0x88, 0x12, 0xb, 0xb0, 0xd2, 0x86, 0x22, 0xca, 0x2b, 0xca,
+ 0x1b, 0xca, 0xb, 0xd2, 0x0, 0x30, 0x90, 0x1c, 0xc2, 0x90, 0x7e, 0x71, 0x91,
+ 0xe5, 0x38, 0x70, 0x3, 0x7a, 0x71, 0x21, 0xe5, 0x38, 0x12, 0x1, 0x20, 0x5,
+ 0x38, 0x30, 0x2, 0x6, 0xe4, 0x12, 0x7, 0xd7, 0xf5, 0x91, 0x30, 0x91, 0xb,
+ 0xc2, 0x91, 0x5, 0x38, 0xe5, 0x38, 0x12, 0x7, 0xd7, 0xf5, 0x91, 0xda, 0xb,
+ 0xda, 0x1b, 0xda, 0x2b, 0x32, 0xd2, 0x7, 0x12, 0xc, 0x14, 0xa9, 0xc2, 0xb4,
+ 0x74, 0x9f, 0x12, 0xc, 0x5c, 0x12, 0xc, 0x43, 0xa9, 0xd2, 0xb4, 0x60, 0x3,
+ 0xb4, 0xff, 0x1a, 0x75, 0x23, 0x81, 0xa9, 0xd5, 0xca, 0xa9, 0xd0, 0xca,
+ 0x75, 0xed, 0x9f, 0x75, 0xad, 0x20, 0xa9, 0xd1, 0xea, 0xa9, 0xc1, 0xea,
+ 0x74, 0x1, 0x2, 0xb, 0x58, 0x2, 0xa, 0xf8, 0xd2, 0x7, 0x12, 0xc, 0x14, 0xa9,
+ 0xc2, 0xb4, 0x74, 0x5, 0x12, 0xc, 0x5c, 0x12, 0xc, 0x43, 0x7c, 0xab, 0xa9,
+ 0xd2, 0xb4, 0xd2, 0x7, 0x12, 0xc, 0x14, 0x5e, 0xa0, 0xe3, 0xa9, 0xc2, 0xb4,
+ 0x74, 0x1, 0x12, 0xc, 0x5c, 0x7c, 0xba, 0x12, 0xc, 0x5c, 0xa9, 0xd2, 0xb4,
+ 0x12, 0x0, 0x2e, 0x40, 0xfb, 0x22, 0x7c, 0xab, 0x7d, 0x12, 0x7c, 0xb3, 0xf5,
+ 0x14, 0x7c, 0x36, 0x7c, 0x25, 0xa, 0x4, 0x7c, 0xb3, 0xf5, 0x13, 0x7c, 0xb7,
+ 0xf5, 0x12, 0xa9, 0xc2, 0xb4, 0x7c, 0xba, 0x12, 0xc, 0x5c, 0xe5, 0x14, 0x12,
+ 0xc, 0x5c, 0xe5, 0x13, 0x12, 0xc, 0x5c, 0xe5, 0x12, 0x2, 0xc, 0x5c, 0xca,
+ 0xf8, 0x7c, 0xfb, 0xe5, 0x23, 0xb4, 0x81, 0x21, 0x74, 0x2, 0x12, 0x8, 0xad,
+ 0x4c, 0xff, 0x78, 0x8, 0xa9, 0xc0, 0xca, 0x5e, 0x70, 0xdf, 0x80, 0x6, 0xa9,
+ 0xd0, 0xca, 0x4e, 0x70, 0x20, 0x74, 0x2, 0x12, 0x9, 0xfe, 0x74, 0x2, 0x12,
+ 0x8, 0xad, 0xda, 0xf8, 0x22, 0x7d, 0x52, 0xf5, 0x15, 0x7c, 0xb6, 0x7c, 0xa5,
+ 0xa, 0x44, 0xf5, 0x14, 0x7f, 0x21, 0xf5, 0x13, 0xa9, 0xc2, 0xb4, 0x74, 0xb,
+ 0x12, 0xc, 0x5c, 0xe5, 0x15, 0x12, 0xc, 0x5c, 0xe5, 0x14, 0x12, 0xc, 0x5c,
+ 0xe5, 0x13, 0x12, 0xc, 0x5c, 0xe4, 0x2, 0xc, 0x5c, 0x80, 0x18, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe5, 0x3d, 0x70, 0xa, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7d, 0x23, 0x1b, 0x34, 0x4d, 0x22,
+ 0x78, 0xe0, 0x22, 0xd2, 0xcf, 0x85, 0x3d, 0xcc, 0x75, 0xec, 0xff, 0x75,
+ 0xee, 0xff, 0x75, 0xeb, 0x3, 0x75, 0xac, 0x40, 0xa9, 0xc5, 0xca, 0x75, 0xed,
+ 0xf, 0x75, 0xad, 0xb0, 0xa9, 0xd7, 0x94, 0xa9, 0xd4, 0x94, 0x22, 0x12, 0xb,
+ 0xd3, 0xa9, 0xa6, 0x94, 0xb3, 0x92, 0x6, 0x30, 0x6, 0x6, 0x12, 0xc, 0x50,
+ 0x12, 0xa, 0xc3, 0x12, 0x7, 0x67, 0x12, 0xc, 0x35, 0xd2, 0xaf, 0x30, 0x3,
+ 0xfd, 0x2, 0xc, 0x7a, 0xa9, 0xc2, 0xb4, 0x30, 0x7, 0x4, 0x74, 0x6, 0x80,
+ 0x2, 0x74, 0x4, 0x12, 0xc, 0x5c, 0xa9, 0xd2, 0xb4, 0x22, 0x12, 0xb, 0x85,
+ 0x7e, 0x35, 0x11, 0x12, 0x0, 0xe, 0xa9, 0xd2, 0xb4, 0xd3, 0x22, 0xc2, 0x8c,
+ 0x43, 0x89, 0x2, 0x75, 0x8c, 0x1, 0x75, 0x8a, 0x0, 0xd2, 0xa9, 0x22, 0x75,
+ 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0xe5, 0xb5, 0x22, 0xd2,
+ 0xc8, 0x75, 0xb3, 0x13, 0xa9, 0xd1, 0xb4, 0xa9, 0xc0, 0xb4, 0x22, 0xf5,
+ 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0xd3, 0x22, 0xc2, 0x8c,
+ 0x6d, 0x33, 0x7a, 0x35, 0x17, 0xd2, 0x8c, 0x22, 0x7e, 0x35, 0x17, 0xb, 0x34,
+ 0x7a, 0x35, 0x17, 0x22, 0x85, 0x3d, 0xcc, 0xe5, 0x3d, 0x2, 0xb, 0x58, 0x2,
+ 0xc, 0x71, 0xff,
diff --git a/drivers/input/touchscreen/focaltech_touch/include/pramboot/FT8716_Pramboot_V0.5_20160723.i b/drivers/input/touchscreen/focaltech_touch/include/pramboot/FT8716_Pramboot_V0.5_20160723.i
new file mode 100644
index 000000000000..805c8bfaf191
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/include/pramboot/FT8716_Pramboot_V0.5_20160723.i
@@ -0,0 +1,303 @@
+0x2, 0x3, 0x83, 0xca, 0x39, 0x12, 0xf, 0x3c, 0xda, 0x39, 0x32, 0x2, 0x0, 0x3,
+ 0x6d, 0x22, 0x80, 0x13, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6,
+ 0xb3, 0xe5, 0xb5, 0x7a, 0xb, 0xb0, 0xb, 0x14, 0xb, 0x24, 0xbd, 0x32, 0x38,
+ 0xe9, 0x22, 0xff, 0x2, 0xd, 0xf, 0xe5, 0x33, 0xb4, 0xc, 0xf, 0xc2, 0x86,
+ 0xc2, 0x87, 0x7e, 0x34, 0x0, 0x64, 0x12, 0xe, 0x86, 0xd2, 0x86, 0xd2, 0x87,
+ 0x22, 0x2, 0x0, 0xf9, 0xca, 0x3b, 0x7a, 0xd, 0x10, 0x7f, 0x31, 0xe5, 0x24,
+ 0xb4, 0x80, 0x2, 0x80, 0x3, 0x2, 0x0, 0xdc, 0x7f, 0x13, 0x5e, 0x34, 0x0,
+ 0x7f, 0x7d, 0x23, 0x7e, 0x34, 0x0, 0x80, 0x9d, 0x32, 0x7a, 0x35, 0x16, 0x7e,
+ 0x35, 0x14, 0xbe, 0x35, 0x16, 0x38, 0x2, 0x80, 0x5d, 0x7e, 0x35, 0x16, 0x7a,
+ 0x35, 0x18, 0x7f, 0x13, 0x7e, 0xd, 0x10, 0x12, 0xa, 0xe6, 0x7e, 0x35, 0x14,
+ 0x9e, 0x35, 0x16, 0x7a, 0x35, 0x14, 0x7e, 0x35, 0x16, 0x6d, 0x22, 0x2f,
+ 0x31, 0x7e, 0x1d, 0x10, 0x2e, 0x35, 0x16, 0x7a, 0x1d, 0x10, 0x80, 0x27,
+ 0x7e, 0x34, 0x0, 0x80, 0x7a, 0x35, 0x18, 0x7f, 0x13, 0x7e, 0xd, 0x10, 0x12,
+ 0xa, 0xe6, 0x7e, 0x35, 0x14, 0x9e, 0x34, 0x0, 0x80, 0x7a, 0x35, 0x14, 0x7e,
+ 0x1d, 0x10, 0x2e, 0x34, 0x0, 0x80, 0x7a, 0x1d, 0x10, 0x2e, 0x38, 0x0, 0x80,
+ 0x7e, 0x35, 0x14, 0xbe, 0x34, 0x0, 0x80, 0x50, 0xd0, 0x4d, 0x33, 0x68, 0x26,
+ 0x7a, 0x35, 0x18, 0x7f, 0x13, 0x7e, 0xd, 0x10, 0x12, 0xa, 0xe6, 0x80, 0x19,
+ 0x74, 0x2, 0x12, 0xa, 0x89, 0x5e, 0x70, 0xf4, 0x12, 0xc, 0x86, 0x7e, 0x35,
+ 0x14, 0x7a, 0x35, 0x18, 0x7f, 0x13, 0x7e, 0xd, 0x10, 0x12, 0x8, 0xe, 0xd3,
+ 0xda, 0x3b, 0x22, 0xa9, 0xc0, 0x93, 0x75, 0x39, 0x0, 0x32, 0xf, 0x60, 0xf0,
+ 0x9f, 0x4c, 0xf1, 0xb3, 0xe, 0xce, 0xb9, 0x31, 0x46, 0xff, 0x0, 0xff, 0x0,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x7c, 0x6b, 0xc2, 0x2, 0xe5, 0x22, 0x14, 0x78, 0x3,
+ 0x2, 0x2, 0xda, 0x1b, 0xb1, 0x78, 0x3, 0x2, 0x2, 0x3d, 0x1b, 0xb1, 0x78,
+ 0x3, 0x2, 0x2, 0x89, 0x1b, 0xb1, 0x78, 0x3, 0x2, 0x2, 0x9a, 0x1b, 0xb1,
+ 0x78, 0x3, 0x2, 0x2, 0xc1, 0x24, 0xf9, 0x78, 0x3, 0x2, 0x2, 0xd6, 0x24,
+ 0xaf, 0x78, 0x3, 0x2, 0x3, 0x3b, 0x24, 0xfd, 0x68, 0x3a, 0x14, 0x78, 0x3,
+ 0x2, 0x2, 0xdd, 0x14, 0x78, 0x3, 0x2, 0x2, 0xda, 0x1b, 0xb2, 0x78, 0x3, 0x2,
+ 0x2, 0xda, 0x24, 0xda, 0x68, 0x26, 0x24, 0xe6, 0x68, 0x1f, 0x24, 0xeb, 0x68,
+ 0x3b, 0x24, 0xf3, 0x78, 0x3, 0x2, 0x2, 0xda, 0x24, 0xe4, 0x78, 0x3, 0x2,
+ 0x3, 0x46, 0x14, 0x78, 0x3, 0x2, 0x2, 0xda, 0x24, 0x94, 0x68, 0x3, 0x2, 0x3,
+ 0x82, 0x2, 0x3, 0x42, 0xbe, 0x60, 0x4, 0x50, 0xc, 0x75, 0x3f, 0x0, 0x7c,
+ 0x16, 0x2e, 0x10, 0x25, 0x7c, 0xb7, 0xa5, 0xf7, 0xa5, 0xbe, 0x0, 0x2, 0x80,
+ 0x3, 0x2, 0x3, 0x82, 0xd2, 0x2, 0x22, 0x7c, 0xb6, 0x24, 0x0, 0x78, 0x3, 0x2,
+ 0x3, 0x82, 0x1b, 0xb1, 0x68, 0x1e, 0x14, 0x68, 0x1e, 0x14, 0x68, 0x1e, 0x14,
+ 0x68, 0x1e, 0xb, 0xb2, 0x78, 0x33, 0x30, 0x1, 0x7, 0x7e, 0x8, 0x0, 0x44,
+ 0x2, 0x2, 0x5a, 0x7e, 0x8, 0x1, 0x50, 0x2, 0x2, 0x5a, 0x2, 0x2, 0xfb, 0x2,
+ 0x3, 0x2, 0x2, 0x3, 0x1a, 0xa, 0x27, 0x7e, 0xd, 0x3a, 0xb, 0x16, 0xb, 0xa,
+ 0x30, 0x2d, 0x32, 0x1b, 0xa, 0x30, 0x6d, 0x33, 0x7e, 0xd, 0x3a, 0x79, 0x30,
+ 0x0, 0x6, 0x22, 0x7c, 0xb7, 0x62, 0x3f, 0x7e, 0x2d, 0x3a, 0x2e, 0x54, 0x0,
+ 0x6, 0xb, 0x2a, 0x20, 0x7d, 0x12, 0xb, 0x14, 0x1b, 0x2a, 0x10, 0x7e, 0xd,
+ 0x3a, 0x2d, 0x12, 0x39, 0x70, 0x0, 0x8, 0x7e, 0xd, 0x3a, 0x69, 0x50, 0x0,
+ 0x4, 0x69, 0x20, 0x0, 0x6, 0xbd, 0x25, 0x50, 0x3, 0x2, 0x3, 0x82, 0xb2, 0x1,
+ 0x7a, 0xd, 0x34, 0x7e, 0x34, 0x0, 0x2, 0x2, 0x3, 0x7f, 0x7c, 0xb6, 0x1b,
+ 0xb1, 0x68, 0x1d, 0x14, 0x68, 0x1d, 0xb, 0xb1, 0x68, 0x3, 0x2, 0x3, 0x82,
+ 0x30, 0x1, 0x6, 0x7e, 0x8, 0x0, 0x44, 0x80, 0x4, 0x7e, 0x8, 0x1, 0x50, 0x7a,
+ 0xd, 0x3a, 0x2, 0x2, 0xf3, 0x2, 0x2, 0xfb, 0xa, 0x57, 0x6d, 0x44, 0x7e, 0xd,
+ 0x3a, 0x69, 0x30, 0x0, 0x2, 0xb, 0xa, 0x20, 0x2f, 0x12, 0x79, 0x30, 0x0,
+ 0x2, 0x1b, 0xa, 0x20, 0x7e, 0x1d, 0x3a, 0x7a, 0x1d, 0x34, 0xd2, 0x2, 0x7e,
+ 0x34, 0x0, 0x1, 0x2, 0x3, 0x7f, 0xbe, 0x60, 0x1, 0x68, 0x9, 0xa5, 0xbe, 0x2,
+ 0x5, 0x7a, 0x71, 0x3e, 0xd2, 0x3, 0xd2, 0x2, 0x22, 0x75, 0xe6, 0x0, 0xe4,
+ 0x7e, 0x34, 0x1, 0x4, 0x7e, 0x24, 0x0, 0xff, 0x7a, 0x1b, 0xb0, 0x7e, 0x34,
+ 0x1, 0x5, 0x7a, 0x1b, 0xb0, 0x7e, 0x34, 0x1, 0x8, 0x7a, 0x1b, 0xb0, 0x7e,
+ 0x34, 0x1, 0x9, 0x7a, 0x1b, 0xb0, 0xd2, 0x4, 0x22, 0xa5, 0xbe, 0x1, 0x4,
+ 0x7a, 0x71, 0x38, 0x22, 0xa5, 0xbe, 0x2, 0x2, 0x80, 0x3, 0x2, 0x3, 0x82,
+ 0x7a, 0x71, 0x23, 0x22, 0x7a, 0x71, 0x33, 0x22, 0xd2, 0x2, 0x22, 0x7c, 0xb6,
+ 0x1b, 0xb1, 0x68, 0x18, 0x14, 0x68, 0x1c, 0x14, 0x68, 0x31, 0x14, 0x68,
+ 0x3a, 0xb, 0xb2, 0x68, 0x3, 0x2, 0x3, 0x82, 0xa, 0x37, 0x7d, 0x3, 0x6d,
+ 0x11, 0x80, 0x59, 0xa, 0x57, 0x7c, 0xab, 0xe4, 0x80, 0x2, 0xa, 0x57, 0x6d,
+ 0x44, 0x7e, 0xd, 0x3a, 0x69, 0x30, 0x0, 0x2, 0xb, 0xa, 0x20, 0x2f, 0x12,
+ 0x79, 0x30, 0x0, 0x2, 0x1b, 0xa, 0x20, 0x22, 0x7c, 0x67, 0x6c, 0x77, 0x7e,
+ 0xd, 0x3a, 0x79, 0x30, 0x0, 0x4, 0x22, 0xa, 0x27, 0x7e, 0xd, 0x3a, 0xb,
+ 0x16, 0xb, 0xa, 0x30, 0x2d, 0x32, 0x1b, 0xa, 0x30, 0x7e, 0x34, 0x0, 0x3,
+ 0x80, 0x44, 0x7e, 0x34, 0x0, 0x4, 0x7a, 0x35, 0x2f, 0x75, 0x3f, 0x0, 0x22,
+ 0x1b, 0x61, 0x68, 0x15, 0xb, 0x60, 0x78, 0x34, 0x7c, 0x27, 0x6c, 0x33, 0x6d,
+ 0x0, 0x7e, 0x1d, 0x3a, 0x79, 0x11, 0x0, 0x2, 0x1b, 0x1a, 0x0, 0x22, 0xa,
+ 0x57, 0x6d, 0x44, 0x7e, 0xd, 0x3a, 0x69, 0x30, 0x0, 0x2, 0xb, 0xa, 0x20,
+ 0x2f, 0x12, 0x79, 0x30, 0x0, 0x2, 0x1b, 0xa, 0x20, 0xe4, 0x7a, 0xb3, 0x2,
+ 0xe4, 0x7e, 0x34, 0x0, 0x5, 0x7a, 0x35, 0x2f, 0x22, 0x75, 0x84, 0x1, 0x7e,
+ 0x44, 0x1f, 0xff, 0xe4, 0x7a, 0x49, 0xb0, 0x1b, 0x44, 0x78, 0xf9, 0x7e,
+ 0xf8, 0x2, 0xe8, 0xd2, 0x7, 0xc2, 0x8, 0x75, 0x3f, 0x0, 0x75, 0x40, 0x87,
+ 0x75, 0x41, 0xa6, 0x75, 0x42, 0x0, 0x75, 0x43, 0x0, 0xd2, 0x0, 0xc2, 0x2,
+ 0xc2, 0x3, 0xc2, 0x4, 0x75, 0x22, 0x0, 0x75, 0x23, 0x0, 0x75, 0x24, 0x80,
+ 0x75, 0x2f, 0x0, 0x75, 0x30, 0x0, 0x75, 0x31, 0x0, 0x75, 0x32, 0x0, 0x75,
+ 0x33, 0x0, 0x75, 0x38, 0xb, 0x75, 0x39, 0x0, 0x75, 0x3e, 0x1, 0x7e, 0x4,
+ 0x0, 0xff, 0x7e, 0x14, 0xf, 0x50, 0xb, 0xa, 0x40, 0x5d, 0x44, 0x68, 0x1a,
+ 0x69, 0x20, 0x0, 0x2, 0xb, 0xe, 0xb, 0x44, 0x80, 0xa, 0x7e, 0xb, 0xb0, 0x7a,
+ 0x29, 0xb0, 0xb, 0x24, 0xb, 0xc, 0x1b, 0x44, 0x78, 0xf2, 0x80, 0xdf, 0x2,
+ 0x4, 0x20, 0xff, 0xff, 0x56, 0x30, 0x2e, 0x35, 0x4a, 0x75, 0x6c, 0x20, 0x32,
+ 0x33, 0x20, 0x32, 0x30, 0x31, 0x36, 0x0, 0x46, 0x54, 0x53, 0x38, 0x37, 0x31,
+ 0x36, 0x5f, 0x70, 0x72, 0x61, 0x6d, 0x62, 0x6f, 0x6f, 0x74, 0x12, 0xe, 0x63,
+ 0x2, 0x5, 0xbc, 0x7e, 0x35, 0x2f, 0x1b, 0x34, 0x68, 0x60, 0x1b, 0x35, 0x78,
+ 0x3, 0x2, 0x4, 0xbc, 0x1b, 0x34, 0x78, 0x3, 0x2, 0x4, 0xe6, 0x1b, 0x34,
+ 0x78, 0x3, 0x2, 0x5, 0x96, 0x2e, 0x34, 0x0, 0x3, 0x68, 0x3, 0x2, 0x5, 0xa8,
+ 0x6d, 0x33, 0x7a, 0x35, 0x2f, 0x7a, 0x35, 0x31, 0x30, 0x7, 0x5, 0x12, 0x0,
+ 0x2e, 0xc2, 0x7, 0x7e, 0xd, 0x34, 0x69, 0x30, 0x0, 0x4, 0x7a, 0x35, 0x14,
+ 0x69, 0x30, 0x0, 0x2, 0xb, 0xa, 0x20, 0x2e, 0x14, 0x0, 0x8, 0x12, 0x0, 0x46,
+ 0xd2, 0x7, 0x7e, 0x2d, 0x34, 0x69, 0x12, 0x0, 0x4, 0x69, 0x32, 0x0, 0x2,
+ 0xb, 0x2a, 0x20, 0x12, 0xb, 0xe2, 0x2e, 0x34, 0x10, 0x0, 0x2, 0x5, 0x91,
+ 0x6d, 0x33, 0x7a, 0x35, 0x2f, 0x7e, 0x34, 0x1, 0x0, 0x7a, 0x35, 0x15, 0x7e,
+ 0xd, 0x34, 0x69, 0x30, 0x0, 0x2, 0xb, 0xa, 0x20, 0x2e, 0x14, 0x0, 0x8, 0x12,
+ 0xe, 0xf2, 0x20, 0x0, 0x3, 0x2, 0x5, 0xa8, 0x7e, 0x1d, 0x34, 0x29, 0xb1,
+ 0x0, 0x8, 0xf5, 0x91, 0x2, 0x5, 0xa8, 0x6d, 0x33, 0x7a, 0x35, 0x2f, 0x7a,
+ 0x35, 0x31, 0x7e, 0x18, 0x0, 0x3f, 0x7a, 0x1d, 0xe, 0x7e, 0xd, 0x34, 0x69,
+ 0x30, 0x0, 0x2, 0xb, 0xa, 0x20, 0x69, 0x10, 0x0, 0x4, 0x12, 0x7, 0x62, 0x12,
+ 0x0, 0x2e, 0x7e, 0x34, 0xf0, 0x55, 0x2, 0x5, 0x91, 0x7e, 0x18, 0x10, 0x0,
+ 0x7a, 0x1d, 0x8, 0xd2, 0x5, 0x6d, 0x33, 0x7a, 0x35, 0x2f, 0x7a, 0x35, 0x31,
+ 0xe5, 0x38, 0xb4, 0xa, 0x17, 0xe5, 0x24, 0xb4, 0x80, 0xc, 0xe4, 0x12, 0xc,
+ 0xd1, 0x74, 0x1, 0x12, 0xc, 0xd1, 0x2, 0x5, 0x7f, 0x12, 0x8, 0xa4, 0x2, 0x5,
+ 0x7f, 0xe5, 0x38, 0xb4, 0xb, 0x27, 0xe5, 0x24, 0xb4, 0x80, 0x11, 0x7e, 0xf0,
+ 0x1, 0x7c, 0xbf, 0x12, 0x5, 0xc3, 0xb, 0xf0, 0xbe, 0xf0, 0x11, 0x78, 0xf4,
+ 0x80, 0x51, 0x7e, 0xf0, 0x4, 0x7c, 0xbf, 0x12, 0x5, 0xc3, 0xb, 0xf0, 0xbe,
+ 0xf0, 0x40, 0x78, 0xf4, 0x80, 0x40, 0xe5, 0x38, 0xa, 0x3b, 0x9e, 0x34, 0x0,
+ 0x80, 0x7c, 0xe7, 0xe5, 0x24, 0xb4, 0x80, 0x10, 0xa, 0x3e, 0x6d, 0x22, 0x74,
+ 0xc, 0x2f, 0x11, 0x14, 0x78, 0xfb, 0x7a, 0x1d, 0x8, 0x80, 0xe, 0xa, 0x3e,
+ 0x6d, 0x22, 0x74, 0xa, 0x2f, 0x11, 0x14, 0x78, 0xfb, 0x7a, 0x1d, 0x8, 0x6c,
+ 0xdd, 0x80, 0x9, 0x7c, 0xbe, 0x12, 0x5, 0xc3, 0xb, 0xe0, 0xb, 0xd0, 0xe5,
+ 0x23, 0xbc, 0xbd, 0x38, 0xf1, 0x7e, 0x1d, 0x8, 0x12, 0xe, 0xd, 0x92, 0x5,
+ 0x12, 0x0, 0x2e, 0x30, 0x5, 0x1b, 0x7e, 0x34, 0xf0, 0xaa, 0x7a, 0x35, 0x31,
+ 0x80, 0x12, 0x6d, 0x33, 0x7a, 0x35, 0x2f, 0x7a, 0x35, 0x31, 0x7e, 0xd, 0x34,
+ 0x69, 0x30, 0x0, 0x2, 0x12, 0x6, 0x98, 0x30, 0x4, 0x11, 0x7e, 0x34, 0x13,
+ 0x88, 0x12, 0xe, 0x86, 0x7e, 0x34, 0x13, 0x88, 0x12, 0xe, 0x86, 0x75, 0xe9,
+ 0xff, 0x30, 0x8, 0x3, 0x2, 0x4, 0x26, 0x22, 0xca, 0xf8, 0x7c, 0xfb, 0xe5,
+ 0x24, 0xb4, 0x80, 0x4a, 0xd2, 0x6, 0x12, 0xe, 0xdf, 0x74, 0x20, 0xca, 0xb8,
+ 0xa, 0x3f, 0x6d, 0x22, 0x74, 0xc, 0x2f, 0x11, 0x14, 0x78, 0xfb, 0xda, 0xb8,
+ 0x12, 0xd, 0xb3, 0xa9, 0xd2, 0xb4, 0x12, 0xf, 0x32, 0x12, 0xe, 0xca, 0x50,
+ 0x9, 0x7e, 0x35, 0x42, 0xbe, 0x34, 0x1, 0xf4, 0x28, 0xf2, 0x7e, 0x35, 0x42,
+ 0xbe, 0x34, 0x1, 0xf4, 0x38, 0x6, 0x12, 0xf, 0x4d, 0x2, 0x6, 0x95, 0xc2,
+ 0x86, 0x7e, 0x34, 0x13, 0x88, 0x12, 0xe, 0x86, 0xd2, 0x86, 0x2, 0x6, 0x95,
+ 0x74, 0x1, 0x12, 0xa, 0x21, 0x74, 0x1, 0x6d, 0x33, 0x12, 0xc, 0x86, 0xe4,
+ 0x12, 0xa, 0x89, 0x5e, 0x34, 0x80, 0x0, 0x7c, 0x4f, 0x6c, 0x55, 0x3e, 0x24,
+ 0x4d, 0x32, 0x12, 0xc, 0x86, 0x74, 0x4, 0x6d, 0x33, 0x12, 0xc, 0x86, 0x7e,
+ 0x34, 0x0, 0x50, 0x12, 0xc, 0x86, 0x7e, 0x34, 0x0, 0x19, 0x12, 0xe, 0x86,
+ 0x74, 0x4, 0x7e, 0x34, 0x0, 0x51, 0x12, 0xc, 0x86, 0x7e, 0x34, 0xa2, 0x1c,
+ 0x12, 0xe, 0x86, 0x74, 0x4, 0x7e, 0x34, 0x0, 0x11, 0x12, 0xc, 0x86, 0x7e,
+ 0x34, 0x0, 0x19, 0x12, 0xe, 0x86, 0x74, 0x4, 0x7e, 0x34, 0x0, 0x10, 0x12,
+ 0xc, 0x86, 0x7e, 0x34, 0x0, 0x19, 0x12, 0xe, 0x86, 0x74, 0x4, 0x6d, 0x33,
+ 0x12, 0xc, 0x86, 0x7e, 0x34, 0x0, 0x5, 0x12, 0xe, 0x86, 0xe4, 0x12, 0xa,
+ 0x21, 0x74, 0x4, 0x7e, 0x34, 0xff, 0xf7, 0x12, 0xc, 0x86, 0xda, 0xf8, 0x22,
+ 0xca, 0xf8, 0xe4, 0x7a, 0xb3, 0x2, 0xe4, 0xe5, 0x24, 0xbe, 0xb0, 0x80, 0x68,
+ 0x9, 0x74, 0x1, 0x7a, 0xb3, 0x2, 0xe4, 0x2, 0x7, 0x5f, 0xbe, 0x34, 0xff,
+ 0xff, 0x68, 0x6, 0xbe, 0x34, 0x0, 0x12, 0x50, 0x4, 0x7e, 0x34, 0x0, 0x12,
+ 0x7d, 0x13, 0x6d, 0x0, 0x74, 0xc, 0x2f, 0x0, 0x14, 0x78, 0xfb, 0x7a, 0xd,
+ 0xc, 0x7c, 0xb7, 0x12, 0x5, 0xc3, 0x7e, 0x1d, 0xc, 0x12, 0xe, 0xd, 0xe4,
+ 0x33, 0x7c, 0xfb, 0xbe, 0xf0, 0x1, 0x78, 0xa, 0x7e, 0xb3, 0x2, 0xe4, 0x44,
+ 0x2, 0x7a, 0xb3, 0x2, 0xe4, 0x6c, 0xaa, 0xa, 0x3a, 0x19, 0xa3, 0x2, 0xdc,
+ 0xb, 0xa0, 0xbe, 0xa0, 0x8, 0x78, 0xf3, 0x7e, 0x34, 0x0, 0x8, 0x7a, 0x35,
+ 0x14, 0x7e, 0x1d, 0xc, 0x7e, 0x8, 0x2, 0xdc, 0x12, 0x0, 0x46, 0x6c, 0xaa,
+ 0xe4, 0xa, 0x4a, 0x19, 0xb4, 0x2, 0xdc, 0xb, 0xa0, 0xbe, 0xa0, 0x8, 0x78,
+ 0xf3, 0x7e, 0x34, 0x0, 0x8, 0x7a, 0x35, 0x15, 0x7e, 0x1d, 0xc, 0x7e, 0x8,
+ 0x2, 0xdc, 0x12, 0xe, 0xf2, 0x7e, 0xf0, 0x1, 0x6c, 0xaa, 0xa, 0x3a, 0x9,
+ 0xb3, 0x2, 0xdc, 0xbc, 0xba, 0x68, 0x4, 0x6c, 0xff, 0x80, 0x7, 0xb, 0xa0,
+ 0xbe, 0xa0, 0x8, 0x40, 0xeb, 0xbe, 0xf0, 0x1, 0x78, 0xa, 0x7e, 0xb3, 0x2,
+ 0xe4, 0x44, 0x4, 0x7a, 0xb3, 0x2, 0xe4, 0x7e, 0xb3, 0x2, 0xe4, 0x44, 0x1,
+ 0x7a, 0xb3, 0x2, 0xe4, 0xda, 0xf8, 0x22, 0xca, 0x3b, 0x7a, 0x15, 0xc, 0x7f,
+ 0x31, 0x75, 0x12, 0x0, 0x7e, 0x35, 0xc, 0xbe, 0x34, 0x0, 0x0, 0x38, 0x4f,
+ 0x7e, 0x34, 0xff, 0xff, 0x7a, 0x35, 0xc, 0x75, 0x12, 0x1, 0x80, 0x43, 0x7e,
+ 0x34, 0x0, 0x80, 0x7a, 0x35, 0x15, 0x7f, 0x13, 0x7e, 0x8, 0x2, 0x5c, 0x12,
+ 0xe, 0xf2, 0x7e, 0x35, 0xc, 0x9e, 0x34, 0x0, 0x80, 0x7a, 0x35, 0xc, 0x2e,
+ 0x38, 0x0, 0x80, 0x6d, 0x33, 0x7a, 0x35, 0x13, 0x7e, 0x35, 0x13, 0x9, 0x63,
+ 0x2, 0x5c, 0x7e, 0xd, 0xe, 0x7e, 0xb, 0x70, 0x6c, 0x76, 0x7a, 0xb, 0x70,
+ 0x7e, 0x35, 0x13, 0xb, 0x34, 0x7a, 0x35, 0x13, 0xbe, 0x34, 0x0, 0x80, 0x78,
+ 0xe0, 0x7e, 0x35, 0xc, 0xbe, 0x34, 0x0, 0x80, 0x38, 0xb4, 0xe5, 0x12, 0x60,
+ 0x5, 0xb, 0x34, 0x7a, 0x35, 0xc, 0x7e, 0x35, 0xc, 0x7a, 0x35, 0x15, 0x7f,
+ 0x13, 0x7e, 0x8, 0x2, 0x5c, 0x12, 0xe, 0xf2, 0x6d, 0x33, 0x80, 0x17, 0x7e,
+ 0x35, 0x13, 0x9, 0x63, 0x2, 0x5c, 0x7e, 0xd, 0xe, 0x7e, 0xb, 0x70, 0x6c,
+ 0x76, 0x7a, 0xb, 0x70, 0x7e, 0x35, 0x13, 0xb, 0x34, 0x7a, 0x35, 0x13, 0x7e,
+ 0x35, 0xc, 0xbe, 0x35, 0x13, 0x38, 0xde, 0xda, 0x3b, 0x22, 0xca, 0x3b, 0x7f,
+ 0x30, 0x7c, 0xb6, 0xf5, 0x1a, 0x7c, 0xb7, 0xf5, 0x1b, 0x74, 0x1, 0x7e, 0x35,
+ 0x18, 0x1e, 0x34, 0x1b, 0x34, 0x4e, 0x60, 0x80, 0x12, 0xc, 0x86, 0x12, 0xa,
+ 0x21, 0xa9, 0xc2, 0xb4, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x2, 0xa9, 0x36, 0xb3,
+ 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6,
+ 0xb3, 0x85, 0x1a, 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x85,
+ 0x1b, 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x6d, 0x33, 0x80,
+ 0x2a, 0x7f, 0x13, 0x2e, 0x35, 0x1c, 0x7e, 0x1b, 0xb0, 0xf5, 0xb5, 0xa9,
+ 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x7e, 0x35, 0x1c, 0x5e, 0x34, 0x0, 0x1,
+ 0xbe, 0x34, 0x0, 0x1, 0x78, 0x7, 0x7e, 0x34, 0x0, 0x78, 0x12, 0xe, 0x86,
+ 0x7e, 0x35, 0x1c, 0xb, 0x34, 0x7a, 0x35, 0x1c, 0x7e, 0x35, 0x18, 0xbe, 0x35,
+ 0x1c, 0x38, 0xcb, 0xa9, 0xd2, 0xb4, 0x7e, 0x34, 0x0, 0x5, 0x12, 0xe, 0x86,
+ 0xe4, 0x12, 0xa, 0x21, 0xda, 0x3b, 0x22, 0xe5, 0x24, 0xb4, 0x80, 0x16, 0xd2,
+ 0x6, 0x12, 0xe, 0xdf, 0xa9, 0xc2, 0xb4, 0x74, 0x60, 0x12, 0xf, 0x27, 0xa9,
+ 0xd2, 0xb4, 0x12, 0xe, 0xca, 0x40, 0xfb, 0x22, 0x74, 0x1, 0x12, 0xa, 0x21,
+ 0xe4, 0x6d, 0x33, 0x12, 0xc, 0x86, 0x74, 0x1, 0x6d, 0x33, 0x12, 0xc, 0x86,
+ 0x74, 0x4, 0x6d, 0x33, 0x12, 0xc, 0x86, 0x7e, 0x34, 0x0, 0x54, 0x12, 0xc,
+ 0x86, 0x7e, 0x34, 0x0, 0x19, 0x12, 0xe, 0x86, 0x74, 0x4, 0x7e, 0x34, 0x0,
+ 0x55, 0x12, 0xc, 0x86, 0x7e, 0x34, 0xa2, 0x1c, 0x12, 0xe, 0x86, 0x74, 0x4,
+ 0x7e, 0x34, 0x0, 0x15, 0x12, 0xc, 0x86, 0x7e, 0x34, 0x0, 0xa0, 0x12, 0xe,
+ 0x86, 0x74, 0x4, 0x7e, 0x34, 0x0, 0x14, 0x12, 0xc, 0x86, 0x7e, 0x34, 0x0,
+ 0x19, 0x12, 0xe, 0x86, 0x74, 0x4, 0x7e, 0x34, 0x0, 0x4, 0x12, 0xc, 0x86,
+ 0x7e, 0x34, 0x0, 0x5, 0x12, 0xe, 0x86, 0xe4, 0x12, 0xa, 0x21, 0x74, 0x4,
+ 0x7e, 0x34, 0xff, 0xf7, 0x2, 0xc, 0x86, 0x7c, 0x7b, 0x7e, 0xa0, 0xef, 0xe5,
+ 0x22, 0x24, 0xfd, 0x68, 0x3c, 0x1b, 0xb1, 0x68, 0x26, 0x24, 0x9f, 0x68,
+ 0x41, 0x1b, 0xb2, 0x68, 0x42, 0x24, 0x9e, 0x68, 0x39, 0x24, 0xe3, 0x68,
+ 0x52, 0x24, 0x59, 0x78, 0x52, 0xa5, 0xbf, 0x0, 0x5, 0x7e, 0xa1, 0x40, 0x80,
+ 0x49, 0xa5, 0xbf, 0x1, 0x45, 0x7e, 0xa1, 0x41, 0x80, 0x40, 0xa5, 0xbf, 0x0,
+ 0x5, 0x7e, 0xa1, 0x24, 0x80, 0x37, 0xa5, 0xbf, 0x1, 0x33, 0x7e, 0xa1, 0x3e,
+ 0x80, 0x2e, 0xa, 0x17, 0x7e, 0x1d, 0x3a, 0x2d, 0x31, 0x29, 0xa1, 0x0, 0x8,
+ 0x80, 0x21, 0x7e, 0xa1, 0x3f, 0x80, 0x1c, 0xa5, 0xbf, 0x0, 0x9, 0x7e, 0x35,
+ 0x31, 0xa, 0x56, 0x7c, 0xab, 0x80, 0xf, 0xa5, 0xbf, 0x1, 0xb, 0x7e, 0x55,
+ 0x31, 0x7c, 0xab, 0x80, 0x4, 0x7e, 0xa3, 0x2, 0xe4, 0x7c, 0xba, 0x22, 0xca,
+ 0x79, 0x6c, 0xee, 0x7e, 0xf0, 0x70, 0x75, 0x91, 0x0, 0xc2, 0x90, 0xc2, 0x91,
+ 0x30, 0x8, 0x31, 0x7e, 0x34, 0x0, 0x2, 0x7a, 0x35, 0x15, 0x9f, 0x11, 0x7e,
+ 0x8, 0x0, 0xc, 0x12, 0xe, 0xf2, 0xe5, 0xc, 0xbe, 0xb0, 0xff, 0x68, 0x1a,
+ 0xe5, 0xc, 0x60, 0x16, 0xe5, 0xd, 0xa, 0x2b, 0xe5, 0xc, 0xa, 0x3b, 0x2d,
+ 0x32, 0xbe, 0x34, 0x0, 0xff, 0x78, 0x6, 0x7e, 0xf1, 0xc, 0x7e, 0xe0, 0x1,
+ 0x4c, 0xee, 0x78, 0x1c, 0xa9, 0xd1, 0xcb, 0xd2, 0xcc, 0x12, 0xc, 0x35, 0x7c,
+ 0xfb, 0xc2, 0xcc, 0xa9, 0xc1, 0xcb, 0xbe, 0xf0, 0x2, 0x40, 0x5, 0xbe, 0xf0,
+ 0xfd, 0x28, 0x3, 0x7e, 0xf0, 0x70, 0x7c, 0xbf, 0x54, 0xfe, 0xf5, 0x92, 0xd2,
+ 0xe8, 0xc2, 0xc0, 0xa9, 0xd5, 0xb7, 0xd2, 0xbd, 0xd2, 0xad, 0xda, 0x79,
+ 0x22, 0xca, 0x79, 0xbe, 0xb0, 0x0, 0x28, 0x2e, 0x74, 0x6, 0x12, 0xa, 0x89,
+ 0x7d, 0x73, 0x6c, 0xff, 0x7e, 0xf0, 0xa5, 0x7d, 0x37, 0x12, 0xc, 0x86, 0x6c,
+ 0xff, 0x7e, 0xf0, 0xf, 0x7d, 0x37, 0x12, 0xc, 0x86, 0x6c, 0xff, 0x7e, 0xf0,
+ 0x6a, 0x7d, 0x37, 0x12, 0xc, 0x86, 0x7e, 0x34, 0x0, 0x5, 0x12, 0xe, 0x86,
+ 0x80, 0x30, 0x74, 0x1, 0x7e, 0x34, 0xdf, 0xff, 0x12, 0xc, 0x86, 0x74, 0x6,
+ 0x12, 0xa, 0x89, 0x7d, 0x73, 0x6c, 0xff, 0x7d, 0x37, 0x12, 0xc, 0x86, 0x7d,
+ 0x37, 0x12, 0xc, 0x86, 0x7d, 0x37, 0x12, 0xc, 0x86, 0x74, 0x2, 0x12, 0xa,
+ 0x89, 0x7d, 0x73, 0x4e, 0xf0, 0x1, 0x7d, 0x37, 0x12, 0xc, 0x86, 0xda, 0x79,
+ 0x22, 0xa9, 0xc2, 0xb4, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x5, 0xa9, 0x36, 0xb3,
+ 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6,
+ 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0xf5, 0xb5,
+ 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3,
+ 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6,
+ 0xb3, 0x7e, 0x71, 0xb5, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6,
+ 0xb3, 0x7e, 0xa1, 0xb5, 0xa9, 0xd2, 0xb4, 0x7c, 0x47, 0x6c, 0x55, 0xa, 0x3a,
+ 0x4d, 0x32, 0x22, 0x7f, 0x70, 0xd2, 0x6, 0x12, 0xe, 0xdf, 0x74, 0x2, 0x12,
+ 0xd, 0xb3, 0x6d, 0x33, 0x80, 0x12, 0x7f, 0x7, 0x2d, 0x13, 0x7e, 0xb, 0xb0,
+ 0xf5, 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0xb, 0x34, 0x7e, 0x25,
+ 0x18, 0xbd, 0x23, 0x38, 0xe7, 0xa9, 0xd2, 0xb4, 0x12, 0xf, 0x32, 0x12, 0xe,
+ 0xca, 0x50, 0x9, 0x7e, 0x35, 0x42, 0xbe, 0x34, 0x1, 0xf4, 0x28, 0xf2, 0x7e,
+ 0x35, 0x42, 0xbe, 0x34, 0x1, 0xf4, 0x38, 0x3, 0x2, 0xf, 0x4d, 0xc2, 0x86,
+ 0x7e, 0x34, 0x13, 0x88, 0x12, 0xe, 0x86, 0xd2, 0x86, 0x22, 0xa9, 0xd1, 0xcb,
+ 0xd2, 0xcc, 0x7e, 0x34, 0x0, 0x4, 0x7e, 0x8, 0x2, 0x5c, 0x74, 0xc, 0x12,
+ 0xb, 0x8f, 0xa9, 0xd1, 0xcb, 0xc2, 0xcc, 0x6c, 0xaa, 0x7e, 0x70, 0x2, 0xac,
+ 0x7a, 0x7e, 0x8, 0x2, 0x5c, 0x2d, 0x13, 0xb, 0xa, 0x30, 0x7d, 0x23, 0x7c,
+ 0x45, 0x6c, 0x55, 0xa, 0x36, 0x4d, 0x32, 0x1b, 0xa, 0x30, 0xb, 0xa0, 0xbe,
+ 0xa0, 0xc, 0x78, 0xde, 0x7e, 0x37, 0x2, 0x6c, 0x7d, 0x23, 0xa, 0x54, 0x7c,
+ 0xa7, 0xb4, 0xe7, 0xb, 0xbe, 0xa0, 0x16, 0x78, 0x6, 0x75, 0x40, 0xe7, 0x75,
+ 0x41, 0xa6, 0x22, 0x7e, 0x24, 0x0, 0x1, 0x7e, 0x7f, 0x2, 0xe5, 0x79, 0x27,
+ 0x0, 0x6, 0x7e, 0x7f, 0x2, 0xe5, 0x69, 0x27, 0x0, 0x6, 0x4d, 0x22, 0x78,
+ 0xf4, 0x5e, 0x60, 0x7f, 0x1b, 0x7a, 0x30, 0x7e, 0x1f, 0x2, 0xe5, 0x69, 0x31,
+ 0x0, 0x8, 0x4d, 0x33, 0x68, 0xf4, 0x6c, 0xaa, 0x80, 0x20, 0x6d, 0x44, 0x7e,
+ 0x1f, 0x2, 0xe5, 0x1b, 0x1a, 0x40, 0x7e, 0x1f, 0x2, 0xe5, 0x69, 0x41, 0x0,
+ 0x8, 0x4d, 0x44, 0x68, 0xf4, 0x69, 0x41, 0x0, 0x2, 0x1b, 0xa, 0x40, 0xb,
+ 0x15, 0xb, 0xa0, 0xbc, 0xba, 0x38, 0xdc, 0x22, 0x6d, 0x0, 0x74, 0x10, 0x4d,
+ 0x0, 0x78, 0xb, 0x4d, 0x22, 0x78, 0x27, 0x8d, 0x31, 0x7d, 0x12, 0x6d, 0x22,
+ 0x22, 0x7d, 0x43, 0x7d, 0x32, 0x6d, 0x22, 0x2f, 0x11, 0x2d, 0x44, 0x50, 0x2,
+ 0xa5, 0xf, 0xbf, 0x10, 0x40, 0x4, 0x9f, 0x10, 0xb, 0x90, 0x14, 0x78, 0xed,
+ 0x7f, 0x1, 0x6d, 0x22, 0x7d, 0x34, 0x22, 0x7d, 0x41, 0x7d, 0x13, 0x8d, 0x24,
+ 0x7d, 0x2, 0x2f, 0x0, 0x40, 0x4, 0xbd, 0x4, 0x40, 0x4, 0x9d, 0x4, 0xb, 0x14,
+ 0x14, 0x78, 0xf1, 0x7d, 0x23, 0x7d, 0x31, 0x7d, 0x10, 0x6d, 0x0, 0x22, 0x7e,
+ 0x34, 0x0, 0x2, 0x7e, 0xf, 0x2, 0xe5, 0x79, 0x30, 0x0, 0x4, 0x7e, 0x34, 0x0,
+ 0x1, 0x7e, 0xf, 0x2, 0xe5, 0x79, 0x30, 0x0, 0x6, 0x7e, 0xf, 0x2, 0xe5, 0x69,
+ 0x30, 0x0, 0x6, 0x4d, 0x33, 0x78, 0xf4, 0x7e, 0x34, 0x0, 0x4, 0x1b, 0xa,
+ 0x30, 0x7e, 0xf, 0x2, 0xe5, 0x69, 0x30, 0x0, 0x8, 0x4d, 0x33, 0x68, 0xf4,
+ 0x6d, 0x33, 0x1b, 0xa, 0x30, 0x7e, 0x1f, 0x2, 0xe5, 0x69, 0x11, 0x0, 0x8,
+ 0x4d, 0x11, 0x68, 0xf4, 0x69, 0x51, 0x0, 0x2, 0x5e, 0x54, 0x0, 0xfe, 0x22,
+ 0x7d, 0x23, 0xa, 0x36, 0x7c, 0xa5, 0xa9, 0xc2, 0xb4, 0xa9, 0xc6, 0xb3, 0x75,
+ 0xb5, 0x1, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9,
+ 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc,
+ 0xa9, 0xc6, 0xb3, 0xf5, 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3,
+ 0x7a, 0x71, 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x7a, 0xa1,
+ 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0xa9, 0xd2, 0xb4, 0x22,
+ 0x7c, 0xab, 0xd2, 0x6, 0x12, 0xe, 0xdf, 0x74, 0xd8, 0xa, 0x3a, 0x7d, 0x23,
+ 0x6d, 0x33, 0x12, 0xd, 0xb3, 0xa9, 0xd2, 0xb4, 0x12, 0xf, 0x32, 0x12, 0xe,
+ 0xca, 0x50, 0x9, 0x7e, 0x35, 0x42, 0xbe, 0x34, 0x5, 0xdc, 0x28, 0xf2, 0x7e,
+ 0x35, 0x42, 0xbe, 0x34, 0x5, 0xdc, 0x38, 0x3, 0x2, 0xf, 0x4d, 0xc2, 0x86,
+ 0x7e, 0x34, 0x13, 0x88, 0x12, 0xe, 0x86, 0xd2, 0x86, 0x22, 0xca, 0x2b, 0xca,
+ 0x1b, 0xca, 0xb, 0xd2, 0x0, 0x30, 0x90, 0x1c, 0xc2, 0x90, 0x7e, 0x71, 0x91,
+ 0xe5, 0x39, 0x70, 0x3, 0x7a, 0x71, 0x22, 0xe5, 0x39, 0x12, 0x1, 0x20, 0x5,
+ 0x39, 0x30, 0x2, 0x6, 0xe4, 0x12, 0x9, 0x33, 0xf5, 0x91, 0x30, 0x91, 0xb,
+ 0xc2, 0x91, 0x5, 0x39, 0xe5, 0x39, 0x12, 0x9, 0x33, 0xf5, 0x91, 0xda, 0xb,
+ 0xda, 0x1b, 0xda, 0x2b, 0x32, 0xd2, 0x6, 0x12, 0xe, 0xdf, 0xa9, 0xc2, 0xb4,
+ 0x74, 0x9f, 0x12, 0xf, 0x27, 0x12, 0xf, 0xe, 0xa9, 0xd2, 0xb4, 0x60, 0x3,
+ 0xb4, 0xff, 0x1a, 0x75, 0x24, 0x81, 0xa9, 0xd5, 0xca, 0xa9, 0xd0, 0xca,
+ 0x75, 0xed, 0x9f, 0x75, 0xad, 0x20, 0xa9, 0xd1, 0xea, 0xa9, 0xc1, 0xea,
+ 0x74, 0x1, 0x2, 0xd, 0xe0, 0x2, 0xd, 0x80, 0xd2, 0x6, 0x12, 0xe, 0xdf, 0xa9,
+ 0xc2, 0xb4, 0x74, 0x5, 0x12, 0xf, 0x27, 0x12, 0xf, 0xe, 0x7c, 0xab, 0xa9,
+ 0xd2, 0xb4, 0xd2, 0x6, 0x12, 0xe, 0xdf, 0x5e, 0xa0, 0xe3, 0xa9, 0xc2, 0xb4,
+ 0x74, 0x1, 0x12, 0xf, 0x27, 0x7c, 0xba, 0x12, 0xf, 0x27, 0xa9, 0xd2, 0xb4,
+ 0x12, 0xe, 0xca, 0x40, 0xfb, 0x22, 0x7c, 0xab, 0x7d, 0x12, 0x7c, 0xb3, 0xf5,
+ 0x1c, 0x7c, 0x36, 0x7c, 0x25, 0xa, 0x4, 0x7c, 0xb3, 0xf5, 0x1b, 0x7c, 0xb7,
+ 0xf5, 0x1a, 0xa9, 0xc2, 0xb4, 0x7c, 0xba, 0x12, 0xf, 0x27, 0xe5, 0x1c, 0x12,
+ 0xf, 0x27, 0xe5, 0x1b, 0x12, 0xf, 0x27, 0xe5, 0x1a, 0x2, 0xf, 0x27, 0xca,
+ 0xf8, 0x7c, 0xfb, 0xe5, 0x24, 0xb4, 0x81, 0x21, 0x74, 0x2, 0x12, 0xa, 0x89,
+ 0x4c, 0xff, 0x78, 0x8, 0xa9, 0xc0, 0xca, 0x5e, 0x70, 0xdf, 0x80, 0x6, 0xa9,
+ 0xd0, 0xca, 0x4e, 0x70, 0x20, 0x74, 0x2, 0x12, 0xc, 0x86, 0x74, 0x2, 0x12,
+ 0xa, 0x89, 0xda, 0xf8, 0x22, 0xd2, 0x6, 0x7e, 0x14, 0x0, 0x8, 0x7a, 0x15,
+ 0x15, 0x7e, 0x8, 0x2, 0xdc, 0x12, 0xe, 0xf2, 0x6c, 0xaa, 0xa, 0x3a, 0x9,
+ 0xb3, 0x2, 0xdc, 0xbe, 0xb0, 0xff, 0x68, 0x4, 0xc2, 0x6, 0x80, 0x7, 0xb,
+ 0xa0, 0xbe, 0xa0, 0x8, 0x40, 0xea, 0xa2, 0x6, 0x22, 0x7d, 0x52, 0xf5, 0x19,
+ 0x7c, 0xb6, 0x7c, 0xa5, 0xa, 0x44, 0xf5, 0x18, 0x7f, 0x21, 0xf5, 0x17, 0xa9,
+ 0xc2, 0xb4, 0x74, 0xb, 0x12, 0xf, 0x27, 0xe5, 0x19, 0x12, 0xf, 0x27, 0xe5,
+ 0x18, 0x12, 0xf, 0x27, 0xe5, 0x17, 0x12, 0xf, 0x27, 0xe4, 0x2, 0xf, 0x27,
+ 0x12, 0xe, 0xa9, 0x12, 0xb, 0x3b, 0xa9, 0xa6, 0x94, 0xb3, 0x92, 0x8, 0x30,
+ 0x8, 0x6, 0x12, 0xf, 0x1b, 0x12, 0xd, 0x4b, 0x12, 0x9, 0xab, 0x12, 0xf, 0x0,
+ 0xd2, 0xaf, 0x30, 0x3, 0xfd, 0x2, 0xf, 0x45, 0x80, 0x18, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe5, 0x3e, 0x70, 0xa, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7d, 0x23, 0x1b, 0x34, 0x4d, 0x22, 0x78,
+ 0xe0, 0x22, 0xd2, 0xcf, 0x85, 0x3e, 0xcc, 0x75, 0xec, 0xff, 0x75, 0xee,
+ 0xff, 0x75, 0xeb, 0x3, 0x75, 0xac, 0xc0, 0xa9, 0xc5, 0xca, 0x75, 0xed, 0xf,
+ 0x75, 0xad, 0xb0, 0xa9, 0xd7, 0x94, 0xa9, 0xd4, 0x94, 0x22, 0xa9, 0xc2,
+ 0xb4, 0x74, 0x5, 0x12, 0xf, 0x27, 0x12, 0xf, 0xe, 0xa9, 0xd2, 0xb4, 0x30,
+ 0xe0, 0x2, 0xd3, 0x22, 0xc3, 0x22, 0xa9, 0xc2, 0xb4, 0x30, 0x6, 0x4, 0x74,
+ 0x6, 0x80, 0x2, 0x74, 0x4, 0x12, 0xf, 0x27, 0xa9, 0xd2, 0xb4, 0x22, 0x12,
+ 0xe, 0x38, 0x7e, 0x35, 0x15, 0x12, 0x0, 0xe, 0xa9, 0xd2, 0xb4, 0xd3, 0x22,
+ 0xc2, 0x8c, 0x43, 0x89, 0x2, 0x75, 0x8c, 0x1, 0x75, 0x8a, 0x0, 0xd2, 0xa9,
+ 0x22, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0xe5, 0xb5,
+ 0x22, 0xd2, 0xc8, 0x75, 0xb3, 0x13, 0xa9, 0xd1, 0xb4, 0xa9, 0xc0, 0xb4,
+ 0x22, 0xf5, 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0xd3, 0x22,
+ 0xc2, 0x8c, 0x6d, 0x33, 0x7a, 0x35, 0x42, 0xd2, 0x8c, 0x22, 0x7e, 0x35,
+ 0x42, 0xb, 0x34, 0x7a, 0x35, 0x42, 0x22, 0x85, 0x3e, 0xcc, 0xe5, 0x3e, 0x2,
+ 0xd, 0xe0, 0x2, 0xf, 0x3c, 0x0, 0x1, 0x2, 0xe4, 0x0, 0x0, 0x4, 0x2, 0xe5,
+ 0x0, 0x0, 0x9c, 0x0, 0x0, 0x0, 0xff,
diff --git a/drivers/input/touchscreen/focaltech_touch/include/pramboot/FT8736_Pramboot_V0.4_20160627.i b/drivers/input/touchscreen/focaltech_touch/include/pramboot/FT8736_Pramboot_V0.4_20160627.i
new file mode 100644
index 000000000000..b1e3b1c08564
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_touch/include/pramboot/FT8736_Pramboot_V0.4_20160627.i
@@ -0,0 +1,288 @@
+0x2, 0x8, 0x9e, 0xca, 0x39, 0x12, 0xe, 0x6c, 0xda, 0x39, 0x32, 0x2, 0x0, 0x3,
+ 0x6d, 0x22, 0x80, 0x13, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6,
+ 0xb3, 0xe5, 0xb5, 0x7a, 0xb, 0xb0, 0xb, 0x14, 0xb, 0x24, 0xbd, 0x32, 0x38,
+ 0xe9, 0x22, 0xff, 0x2, 0xc, 0x47, 0xa9, 0xc2, 0xb4, 0x74, 0x5, 0x12, 0xe,
+ 0x4d, 0x12, 0xe, 0x34, 0xa9, 0xd2, 0xb4, 0x30, 0xe0, 0x2, 0xd3, 0x22, 0xc3,
+ 0x22, 0x2, 0x0, 0xf9, 0xca, 0x3b, 0x7a, 0xd, 0x8, 0x7f, 0x31, 0xe5, 0x23,
+ 0xb4, 0x80, 0x2, 0x80, 0x3, 0x2, 0x0, 0xdc, 0x7f, 0x13, 0x5e, 0x34, 0x0,
+ 0x7f, 0x7d, 0x23, 0x7e, 0x34, 0x0, 0x80, 0x9d, 0x32, 0x7a, 0x35, 0xe, 0x7e,
+ 0x35, 0xc, 0xbe, 0x35, 0xe, 0x38, 0x2, 0x80, 0x5d, 0x7e, 0x35, 0xe, 0x7a,
+ 0x35, 0x10, 0x7f, 0x13, 0x7e, 0xd, 0x8, 0x12, 0xa, 0xba, 0x7e, 0x35, 0xc,
+ 0x9e, 0x35, 0xe, 0x7a, 0x35, 0xc, 0x7e, 0x35, 0xe, 0x6d, 0x22, 0x2f, 0x31,
+ 0x7e, 0x1d, 0x8, 0x2e, 0x35, 0xe, 0x7a, 0x1d, 0x8, 0x80, 0x27, 0x7e, 0x34,
+ 0x0, 0x80, 0x7a, 0x35, 0x10, 0x7f, 0x13, 0x7e, 0xd, 0x8, 0x12, 0xa, 0xba,
+ 0x7e, 0x35, 0xc, 0x9e, 0x34, 0x0, 0x80, 0x7a, 0x35, 0xc, 0x7e, 0x1d, 0x8,
+ 0x2e, 0x34, 0x0, 0x80, 0x7a, 0x1d, 0x8, 0x2e, 0x38, 0x0, 0x80, 0x7e, 0x35,
+ 0xc, 0xbe, 0x34, 0x0, 0x80, 0x50, 0xd0, 0x4d, 0x33, 0x68, 0x26, 0x7a, 0x35,
+ 0x10, 0x7f, 0x13, 0x7e, 0xd, 0x8, 0x12, 0xa, 0xba, 0x80, 0x19, 0x74, 0x2,
+ 0x12, 0xa, 0x5d, 0x5e, 0x70, 0xf4, 0x12, 0x3, 0xb4, 0x7e, 0x35, 0xc, 0x7a,
+ 0x35, 0x10, 0x7f, 0x13, 0x7e, 0xd, 0x8, 0x12, 0x6, 0xeb, 0xd3, 0xda, 0x3b,
+ 0x22, 0xa9, 0xc0, 0x93, 0x75, 0x38, 0x0, 0x32, 0xe, 0x8a, 0xf1, 0x75, 0xf4,
+ 0xf8, 0xb, 0x7, 0xca, 0xca, 0x35, 0x35, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x70, 0x8f, 0x0, 0xff, 0xff, 0x0, 0xff, 0xac, 0xff, 0xac, 0x1,
+ 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0x6b, 0xc2, 0x2, 0xe5, 0x21,
+ 0x14, 0x78, 0x3, 0x2, 0x3, 0x3f, 0x1b, 0xb1, 0x78, 0x3, 0x2, 0x2, 0xb0,
+ 0x1b, 0xb1, 0x78, 0x3, 0x2, 0x2, 0xfc, 0x1b, 0xb1, 0x78, 0x3, 0x2, 0x3, 0xd,
+ 0x1b, 0xb1, 0x78, 0x3, 0x2, 0x3, 0x26, 0x24, 0xf9, 0x78, 0x3, 0x2, 0x3,
+ 0x3b, 0x24, 0xaf, 0x78, 0x3, 0x2, 0x3, 0xa9, 0x24, 0xfd, 0x68, 0x2d, 0x14,
+ 0x78, 0x3, 0x2, 0x3, 0x42, 0x14, 0x78, 0x3, 0x2, 0x3, 0x3f, 0x1b, 0xb2,
+ 0x78, 0x3, 0x2, 0x3, 0x3f, 0x24, 0xda, 0x68, 0x19, 0x24, 0xe6, 0x68, 0x12,
+ 0x24, 0xeb, 0x68, 0x2e, 0x24, 0xf3, 0x78, 0x3, 0x2, 0x3, 0x3f, 0x24, 0x77,
+ 0x68, 0x3, 0x2, 0x3, 0xb3, 0x2, 0x3, 0xb0, 0xbe, 0x60, 0x4, 0x50, 0xc, 0x75,
+ 0x16, 0x0, 0x7c, 0x16, 0x2e, 0x10, 0x24, 0x7c, 0xb7, 0xa5, 0xf7, 0xa5, 0xbe,
+ 0x0, 0x2, 0x80, 0x3, 0x2, 0x3, 0xb3, 0xd2, 0x2, 0x22, 0x7c, 0xb6, 0x24, 0x0,
+ 0x78, 0x3, 0x2, 0x3, 0xb3, 0x1b, 0xb1, 0x68, 0x1e, 0x14, 0x68, 0x1e, 0x14,
+ 0x68, 0x1e, 0x14, 0x68, 0x1e, 0xb, 0xb2, 0x78, 0x33, 0x30, 0x1, 0x7, 0x7e,
+ 0x8, 0x0, 0x3e, 0x2, 0x2, 0xcd, 0x7e, 0x8, 0x1, 0x4a, 0x2, 0x2, 0xcd, 0x2,
+ 0x3, 0x67, 0x2, 0x3, 0x6e, 0x2, 0x3, 0x86, 0xa, 0x27, 0x7e, 0xd, 0x39, 0xb,
+ 0x16, 0xb, 0xa, 0x30, 0x2d, 0x32, 0x1b, 0xa, 0x30, 0x6d, 0x33, 0x7e, 0xd,
+ 0x39, 0x79, 0x30, 0x0, 0x6, 0x22, 0x7c, 0xb7, 0x62, 0x16, 0x7e, 0x2d, 0x39,
+ 0x2e, 0x54, 0x0, 0x6, 0xb, 0x2a, 0x20, 0x7d, 0x12, 0xb, 0x14, 0x1b, 0x2a,
+ 0x10, 0x7e, 0xd, 0x39, 0x2d, 0x12, 0x39, 0x70, 0x0, 0x8, 0x7e, 0xd, 0x39,
+ 0x69, 0x50, 0x0, 0x4, 0x69, 0x20, 0x0, 0x6, 0xbd, 0x25, 0x50, 0x3, 0x2, 0x3,
+ 0xb3, 0xb2, 0x1, 0x7a, 0xd, 0x33, 0x7e, 0x34, 0x0, 0x2, 0x2, 0x3, 0xa5,
+ 0x7c, 0xb6, 0x1b, 0xb1, 0x68, 0x1d, 0x14, 0x68, 0x1d, 0xb, 0xb1, 0x68, 0x3,
+ 0x2, 0x3, 0xb3, 0x30, 0x1, 0x6, 0x7e, 0x8, 0x0, 0x3e, 0x80, 0x4, 0x7e, 0x8,
+ 0x1, 0x4a, 0x7a, 0xd, 0x39, 0x2, 0x3, 0x56, 0x2, 0x3, 0x67, 0xa, 0x57, 0x6d,
+ 0x44, 0x7e, 0xd, 0x39, 0x69, 0x30, 0x0, 0x2, 0xb, 0xa, 0x20, 0x2f, 0x12,
+ 0x79, 0x30, 0x0, 0x2, 0x1b, 0xa, 0x20, 0x7e, 0x1d, 0x39, 0x7a, 0x1d, 0x33,
+ 0xd2, 0x2, 0x7e, 0x34, 0x0, 0x1, 0x2, 0x3, 0xa5, 0xbe, 0x60, 0x1, 0x68, 0x9,
+ 0xa5, 0xbe, 0x2, 0x5, 0x7a, 0x71, 0x3d, 0xd2, 0x3, 0xd2, 0x2, 0x22, 0x75,
+ 0xe6, 0x0, 0xe4, 0x7e, 0x34, 0x1, 0x4, 0x7e, 0x24, 0x0, 0xff, 0x7a, 0x1b,
+ 0xb0, 0x7e, 0x34, 0x1, 0x5, 0x7a, 0x1b, 0xb0, 0xd2, 0x4, 0x22, 0xa5, 0xbe,
+ 0x1, 0x4, 0x7a, 0x71, 0x37, 0x22, 0xa5, 0xbe, 0x2, 0x2, 0x80, 0x3, 0x2, 0x3,
+ 0xb3, 0x7a, 0x71, 0x22, 0x22, 0x7a, 0x71, 0x32, 0x22, 0xd2, 0x2, 0x22, 0x1b,
+ 0x61, 0x68, 0x21, 0x1b, 0x60, 0x68, 0x24, 0x1b, 0x60, 0x68, 0x38, 0x1b,
+ 0x60, 0x68, 0x40, 0xb, 0x62, 0x78, 0x5d, 0xa, 0x37, 0x7d, 0x3, 0x6d, 0x11,
+ 0x7e, 0x1d, 0x39, 0x79, 0x11, 0x0, 0x2, 0x1b, 0x1a, 0x0, 0x22, 0xa, 0x57,
+ 0x7c, 0xab, 0xe4, 0x80, 0x2, 0xa, 0x57, 0x6d, 0x44, 0x7e, 0xd, 0x39, 0x69,
+ 0x30, 0x0, 0x2, 0xb, 0xa, 0x20, 0x2f, 0x12, 0x79, 0x30, 0x0, 0x2, 0x1b, 0xa,
+ 0x20, 0x22, 0x7c, 0x67, 0x6c, 0x77, 0x7e, 0xd, 0x39, 0x79, 0x30, 0x0, 0x4,
+ 0x22, 0xa, 0x27, 0x7e, 0xd, 0x39, 0xb, 0x16, 0xb, 0xa, 0x30, 0x2d, 0x32,
+ 0x1b, 0xa, 0x30, 0x7e, 0x34, 0x0, 0x3, 0x7a, 0x35, 0x2e, 0x22, 0x7e, 0x34,
+ 0x0, 0x4, 0x7a, 0x35, 0x2e, 0x75, 0x16, 0x0, 0x22, 0x7d, 0x23, 0xa, 0x36,
+ 0x7c, 0xa5, 0xa9, 0xc2, 0xb4, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x1, 0xa9, 0x36,
+ 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9,
+ 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0xf5,
+ 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x7a, 0x71, 0xb5, 0xa9,
+ 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x7a, 0xa1, 0xb5, 0xa9, 0x36, 0xb3,
+ 0xfc, 0xa9, 0xc6, 0xb3, 0xa9, 0xd2, 0xb4, 0x22, 0xff, 0x56, 0x30, 0x2e,
+ 0x32, 0x5f, 0x4a, 0x75, 0x6e, 0x20, 0x32, 0x37, 0x20, 0x32, 0x30, 0x31,
+ 0x36, 0x46, 0x54, 0x53, 0x38, 0x37, 0x33, 0x36, 0x5f, 0x50, 0x72, 0x61,
+ 0x6d, 0x62, 0x6f, 0x6f, 0x74, 0x12, 0xd, 0x73, 0x2, 0x5, 0x66, 0x7e, 0x35,
+ 0x2e, 0x1b, 0x34, 0x68, 0x57, 0x1b, 0x35, 0x78, 0x3, 0x2, 0x4, 0xb3, 0x1b,
+ 0x34, 0x78, 0x3, 0x2, 0x4, 0xdd, 0xb, 0x35, 0x68, 0x3, 0x2, 0x5, 0x52, 0x6d,
+ 0x33, 0x7a, 0x35, 0x2e, 0x7a, 0x35, 0x30, 0x30, 0x5, 0x5, 0x12, 0xe, 0x7,
+ 0xc2, 0x5, 0x7e, 0xd, 0x33, 0x69, 0x30, 0x0, 0x4, 0x7a, 0x35, 0xc, 0x69,
+ 0x30, 0x0, 0x2, 0xb, 0xa, 0x20, 0x2e, 0x14, 0x0, 0x8, 0x12, 0x0, 0x46, 0xd2,
+ 0x5, 0x7e, 0x2d, 0x33, 0x69, 0x12, 0x0, 0x4, 0x69, 0x32, 0x0, 0x2, 0xb,
+ 0x2a, 0x20, 0x12, 0xb, 0xb6, 0x2e, 0x34, 0x10, 0x0, 0x2, 0x5, 0x4f, 0x6d,
+ 0x33, 0x7a, 0x35, 0x2e, 0x7e, 0x34, 0x1, 0x0, 0x7a, 0x35, 0x11, 0x7e, 0xd,
+ 0x33, 0x69, 0x30, 0x0, 0x2, 0xb, 0xa, 0x20, 0x2e, 0x14, 0x0, 0x8, 0x12, 0xe,
+ 0x18, 0x20, 0x0, 0x3, 0x2, 0x5, 0x52, 0x7e, 0x1d, 0x33, 0x29, 0xb1, 0x0,
+ 0x8, 0xf5, 0x91, 0x2, 0x5, 0x52, 0x6d, 0x33, 0x7a, 0x35, 0x2e, 0x7a, 0x35,
+ 0x30, 0x7e, 0x18, 0x0, 0x16, 0x7a, 0x1d, 0xa, 0x7e, 0xd, 0x33, 0x69, 0x30,
+ 0x0, 0x2, 0xb, 0xa, 0x20, 0x69, 0x10, 0x0, 0x4, 0x12, 0x6, 0x42, 0x12, 0xe,
+ 0x7, 0x7e, 0x34, 0xf0, 0x55, 0x2, 0x5, 0x4f, 0x6d, 0x33, 0x7a, 0x35, 0x2e,
+ 0x7a, 0x35, 0x30, 0xe5, 0x37, 0xb4, 0xa, 0x15, 0xe5, 0x23, 0xb4, 0x80, 0xb,
+ 0xe4, 0x12, 0xc, 0x9, 0x74, 0x1, 0x12, 0xc, 0x9, 0x80, 0x4e, 0x12, 0x7,
+ 0x81, 0x80, 0x49, 0xe5, 0x37, 0xb4, 0xb, 0x27, 0xe5, 0x23, 0xb4, 0x80, 0x11,
+ 0x7e, 0xf0, 0x1, 0x7c, 0xbf, 0x12, 0x5, 0x6d, 0xb, 0xf0, 0xbe, 0xf0, 0x11,
+ 0x78, 0xf4, 0x80, 0x2e, 0x7e, 0xf0, 0x4, 0x7c, 0xbf, 0x12, 0x5, 0x6d, 0xb,
+ 0xf0, 0xbe, 0xf0, 0x40, 0x78, 0xf4, 0x80, 0x1d, 0xe5, 0x37, 0xa, 0x3b, 0x9e,
+ 0x34, 0x0, 0x80, 0x7c, 0xe7, 0x6c, 0xdd, 0x80, 0x9, 0x7c, 0xbe, 0x12, 0x5,
+ 0x6d, 0xb, 0xe0, 0xb, 0xd0, 0xe5, 0x22, 0xbc, 0xbd, 0x38, 0xf1, 0x12, 0xe,
+ 0x7, 0x7e, 0x34, 0xf0, 0xaa, 0x7a, 0x35, 0x30, 0x30, 0x4, 0x11, 0x7e, 0x34,
+ 0x13, 0x88, 0x12, 0xd, 0x96, 0x7e, 0x34, 0x13, 0x88, 0x12, 0xd, 0x96, 0x75,
+ 0xe9, 0xff, 0x30, 0x6, 0x3, 0x2, 0x4, 0x26, 0x22, 0xca, 0xf8, 0x7c, 0xfb,
+ 0xe5, 0x23, 0xb4, 0x80, 0x4a, 0xd2, 0x7, 0x12, 0xd, 0xf4, 0x74, 0x20, 0xca,
+ 0xb8, 0xa, 0x3f, 0x6d, 0x22, 0x74, 0xc, 0x2f, 0x11, 0x14, 0x78, 0xfb, 0xda,
+ 0xb8, 0x12, 0xd, 0x1b, 0xa9, 0xd2, 0xb4, 0x12, 0xe, 0x62, 0x12, 0x0, 0x2e,
+ 0x50, 0x9, 0x7e, 0x35, 0x19, 0xbe, 0x34, 0x1, 0xf4, 0x28, 0xf2, 0x7e, 0x35,
+ 0x19, 0xbe, 0x34, 0x1, 0xf4, 0x38, 0x6, 0x12, 0xe, 0x7d, 0x2, 0x6, 0x3f,
+ 0xc2, 0x86, 0x7e, 0x34, 0x13, 0x88, 0x12, 0xd, 0x96, 0xd2, 0x86, 0x2, 0x6,
+ 0x3f, 0x74, 0x1, 0x12, 0x9, 0xf5, 0x74, 0x1, 0x6d, 0x33, 0x12, 0x3, 0xb4,
+ 0xe4, 0x12, 0xa, 0x5d, 0x5e, 0x34, 0x80, 0x0, 0x7c, 0x4f, 0x6c, 0x55, 0x3e,
+ 0x24, 0x4d, 0x32, 0x12, 0x3, 0xb4, 0x74, 0x4, 0x6d, 0x33, 0x12, 0x3, 0xb4,
+ 0x7e, 0x34, 0x0, 0x50, 0x12, 0x3, 0xb4, 0x7e, 0x34, 0x0, 0x19, 0x12, 0xd,
+ 0x96, 0x74, 0x4, 0x7e, 0x34, 0x0, 0x51, 0x12, 0x3, 0xb4, 0x7e, 0x34, 0xa2,
+ 0x1c, 0x12, 0xd, 0x96, 0x74, 0x4, 0x7e, 0x34, 0x0, 0x11, 0x12, 0x3, 0xb4,
+ 0x7e, 0x34, 0x0, 0x19, 0x12, 0xd, 0x96, 0x74, 0x4, 0x7e, 0x34, 0x0, 0x10,
+ 0x12, 0x3, 0xb4, 0x7e, 0x34, 0x0, 0x19, 0x12, 0xd, 0x96, 0x74, 0x4, 0x6d,
+ 0x33, 0x12, 0x3, 0xb4, 0x7e, 0x34, 0x0, 0x5, 0x12, 0xd, 0x96, 0xe4, 0x12,
+ 0x9, 0xf5, 0x74, 0x4, 0x7e, 0x34, 0xff, 0xf7, 0x12, 0x3, 0xb4, 0xda, 0xf8,
+ 0x22, 0xca, 0x3b, 0x7a, 0x15, 0x8, 0x7f, 0x31, 0x7e, 0x35, 0x8, 0xbe, 0x34,
+ 0x0, 0x0, 0x38, 0x4f, 0x7e, 0x34, 0xff, 0xff, 0x7a, 0x35, 0x8, 0x75, 0xe,
+ 0x1, 0x80, 0x43, 0x7e, 0x34, 0x0, 0x80, 0x7a, 0x35, 0x11, 0x7f, 0x13, 0x7e,
+ 0x8, 0x2, 0x56, 0x12, 0xe, 0x18, 0x7e, 0x35, 0x8, 0x9e, 0x34, 0x0, 0x80,
+ 0x7a, 0x35, 0x8, 0x2e, 0x38, 0x0, 0x80, 0x6d, 0x33, 0x7a, 0x35, 0xf, 0x7e,
+ 0x35, 0xf, 0x9, 0x63, 0x2, 0x56, 0x7e, 0xd, 0xa, 0x7e, 0xb, 0x70, 0x6c,
+ 0x76, 0x7a, 0xb, 0x70, 0x7e, 0x35, 0xf, 0xb, 0x34, 0x7a, 0x35, 0xf, 0xbe,
+ 0x34, 0x0, 0x80, 0x78, 0xe0, 0x7e, 0x35, 0x8, 0xbe, 0x34, 0x0, 0x80, 0x38,
+ 0xb4, 0xe5, 0xe, 0x60, 0x5, 0xb, 0x34, 0x7a, 0x35, 0x8, 0x7e, 0x35, 0x8,
+ 0x7a, 0x35, 0x11, 0x7f, 0x13, 0x7e, 0x8, 0x2, 0x56, 0x12, 0xe, 0x18, 0x6d,
+ 0x33, 0x80, 0x17, 0x7e, 0x35, 0xf, 0x9, 0x63, 0x2, 0x56, 0x7e, 0xd, 0xa,
+ 0x7e, 0xb, 0x70, 0x6c, 0x76, 0x7a, 0xb, 0x70, 0x7e, 0x35, 0xf, 0xb, 0x34,
+ 0x7a, 0x35, 0xf, 0x7e, 0x35, 0x8, 0xbe, 0x35, 0xf, 0x38, 0xde, 0xda, 0x3b,
+ 0x22, 0xca, 0x3b, 0x7f, 0x30, 0x7c, 0xb6, 0xf5, 0x12, 0x7c, 0xb7, 0xf5,
+ 0x13, 0x74, 0x1, 0x7e, 0x35, 0x10, 0x1e, 0x34, 0x1b, 0x34, 0x4e, 0x60, 0x80,
+ 0x12, 0x3, 0xb4, 0x12, 0x9, 0xf5, 0xa9, 0xc2, 0xb4, 0xa9, 0xc6, 0xb3, 0x75,
+ 0xb5, 0x2, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9,
+ 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x85, 0x12, 0xb5, 0xa9, 0x36, 0xb3,
+ 0xfc, 0xa9, 0xc6, 0xb3, 0x85, 0x13, 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9,
+ 0xc6, 0xb3, 0x6d, 0x33, 0x80, 0x2a, 0x7f, 0x13, 0x2e, 0x35, 0x14, 0x7e,
+ 0x1b, 0xb0, 0xf5, 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x7e,
+ 0x35, 0x14, 0x5e, 0x34, 0x0, 0x1, 0xbe, 0x34, 0x0, 0x1, 0x78, 0x7, 0x7e,
+ 0x34, 0x0, 0x78, 0x12, 0xd, 0x96, 0x7e, 0x35, 0x14, 0xb, 0x34, 0x7a, 0x35,
+ 0x14, 0x7e, 0x35, 0x10, 0xbe, 0x35, 0x14, 0x38, 0xcb, 0xa9, 0xd2, 0xb4,
+ 0x7e, 0x34, 0x0, 0x5, 0x12, 0xd, 0x96, 0xe4, 0x12, 0x9, 0xf5, 0xda, 0x3b,
+ 0x22, 0xe5, 0x23, 0xb4, 0x80, 0x16, 0xd2, 0x7, 0x12, 0xd, 0xf4, 0xa9, 0xc2,
+ 0xb4, 0x74, 0x60, 0x12, 0xe, 0x4d, 0xa9, 0xd2, 0xb4, 0x12, 0x0, 0x2e, 0x40,
+ 0xfb, 0x22, 0x74, 0x1, 0x12, 0x9, 0xf5, 0xe4, 0x6d, 0x33, 0x12, 0x3, 0xb4,
+ 0x74, 0x1, 0x6d, 0x33, 0x12, 0x3, 0xb4, 0x74, 0x4, 0x6d, 0x33, 0x12, 0x3,
+ 0xb4, 0x7e, 0x34, 0x0, 0x54, 0x12, 0x3, 0xb4, 0x7e, 0x34, 0x0, 0x19, 0x12,
+ 0xd, 0x96, 0x74, 0x4, 0x7e, 0x34, 0x0, 0x55, 0x12, 0x3, 0xb4, 0x7e, 0x34,
+ 0xa2, 0x1c, 0x12, 0xd, 0x96, 0x74, 0x4, 0x7e, 0x34, 0x0, 0x15, 0x12, 0x3,
+ 0xb4, 0x7e, 0x34, 0x0, 0xa0, 0x12, 0xd, 0x96, 0x74, 0x4, 0x7e, 0x34, 0x0,
+ 0x14, 0x12, 0x3, 0xb4, 0x7e, 0x34, 0x0, 0x19, 0x12, 0xd, 0x96, 0x74, 0x4,
+ 0x7e, 0x34, 0x0, 0x4, 0x12, 0x3, 0xb4, 0x7e, 0x34, 0x0, 0x5, 0x12, 0xd,
+ 0x96, 0xe4, 0x12, 0x9, 0xf5, 0x74, 0x4, 0x7e, 0x34, 0xff, 0xf7, 0x2, 0x3,
+ 0xb4, 0xca, 0xf8, 0x7e, 0xf0, 0x70, 0xc2, 0x7, 0x75, 0x91, 0x0, 0xc2, 0x90,
+ 0xc2, 0x91, 0x30, 0x6, 0x4e, 0x7e, 0x34, 0x0, 0x6, 0x7a, 0x35, 0x11, 0x7e,
+ 0x18, 0xf, 0x80, 0x7e, 0x8, 0x2, 0xd6, 0x12, 0xe, 0x18, 0x7e, 0xb3, 0x2,
+ 0xd6, 0x7e, 0x73, 0x2, 0xd7, 0x12, 0xd, 0xda, 0x92, 0x7, 0x30, 0x7, 0x6,
+ 0x7e, 0xf3, 0x2, 0xd6, 0x80, 0x26, 0x7e, 0x34, 0x0, 0x6, 0x7a, 0x35, 0x11,
+ 0x7e, 0x18, 0x11, 0x20, 0x7e, 0x8, 0x2, 0xf6, 0x12, 0xe, 0x18, 0x7e, 0xb3,
+ 0x2, 0xf6, 0x7e, 0x73, 0x2, 0xf7, 0x12, 0xd, 0xda, 0x92, 0x7, 0x30, 0x7,
+ 0x4, 0x7e, 0xf3, 0x2, 0xf6, 0x20, 0x6, 0x18, 0xd2, 0xcc, 0x12, 0xe, 0x58,
+ 0x7c, 0xab, 0xc2, 0xcc, 0x7c, 0x7a, 0x6e, 0x70, 0xff, 0x12, 0xd, 0xda, 0x92,
+ 0x7, 0x30, 0x7, 0x2, 0x7c, 0xfa, 0x5e, 0xf0, 0xfe, 0x7a, 0xf1, 0x92, 0xd2,
+ 0xe8, 0xc2, 0xc0, 0xa9, 0xd5, 0xb7, 0xd2, 0xbd, 0xd2, 0xad, 0xda, 0xf8,
+ 0x22, 0x75, 0x84, 0x1, 0x7e, 0x44, 0x1f, 0xff, 0xe4, 0x7a, 0x49, 0xb0, 0x1b,
+ 0x44, 0x78, 0xf9, 0x7e, 0xf8, 0x3, 0x19, 0xd2, 0x5, 0xc2, 0x6, 0x75, 0x16,
+ 0x0, 0x75, 0x17, 0x87, 0x75, 0x18, 0xc6, 0x75, 0x19, 0x0, 0x75, 0x1a, 0x0,
+ 0xd2, 0x0, 0xc2, 0x2, 0xc2, 0x3, 0xc2, 0x4, 0x75, 0x21, 0x0, 0x75, 0x22,
+ 0x0, 0x75, 0x23, 0x80, 0x75, 0x2e, 0x0, 0x75, 0x2f, 0x0, 0x75, 0x30, 0x0,
+ 0x75, 0x31, 0x0, 0x75, 0x32, 0x0, 0x75, 0x37, 0xb, 0x75, 0x38, 0x0, 0x75,
+ 0x3d, 0x1, 0x7e, 0x4, 0x0, 0xff, 0x7e, 0x14, 0xe, 0x80, 0xb, 0xa, 0x40,
+ 0x5d, 0x44, 0x68, 0x1a, 0x69, 0x20, 0x0, 0x2, 0xb, 0xe, 0xb, 0x44, 0x80,
+ 0xa, 0x7e, 0xb, 0xb0, 0x7a, 0x29, 0xb0, 0xb, 0x24, 0xb, 0xc, 0x1b, 0x44,
+ 0x78, 0xf2, 0x80, 0xdf, 0x2, 0x4, 0x20, 0xca, 0x79, 0x7d, 0x73, 0x12, 0xe,
+ 0x62, 0x7e, 0x34, 0x0, 0x1, 0x7e, 0xf, 0x3, 0x16, 0x79, 0x30, 0x0, 0x4,
+ 0x7e, 0xf, 0x3, 0x16, 0x79, 0x30, 0x0, 0x6, 0x7e, 0x1f, 0x3, 0x16, 0x69,
+ 0x11, 0x0, 0x6, 0x4d, 0x11, 0x68, 0x9, 0x7e, 0x15, 0x19, 0xbe, 0x14, 0x0,
+ 0x3c, 0x28, 0xeb, 0x1b, 0x1a, 0x70, 0x7e, 0xf, 0x3, 0x16, 0x69, 0x30, 0x0,
+ 0x8, 0x4d, 0x33, 0x78, 0x9, 0x7e, 0x35, 0x19, 0xbe, 0x34, 0x0, 0x3c, 0x28,
+ 0xeb, 0x6d, 0x33, 0x1b, 0xa, 0x30, 0x7e, 0x1f, 0x3, 0x16, 0x69, 0x11, 0x0,
+ 0x8, 0x4d, 0x11, 0x78, 0x9, 0x7e, 0x15, 0x19, 0xbe, 0x14, 0x0, 0x3c, 0x28,
+ 0xeb, 0x69, 0x71, 0x0, 0x2, 0x12, 0xe, 0x7d, 0x7d, 0x37, 0xda, 0x79, 0x22,
+ 0x7c, 0x7b, 0x7e, 0xa0, 0xef, 0xe5, 0x21, 0x24, 0xfd, 0x68, 0x38, 0x1b,
+ 0xb1, 0x68, 0x22, 0x24, 0x9f, 0x68, 0x3d, 0x1b, 0xb2, 0x68, 0x3e, 0x24,
+ 0x9e, 0x68, 0x35, 0x24, 0x3c, 0x78, 0x4c, 0xa5, 0xbf, 0x0, 0x5, 0x7e, 0xa1,
+ 0x17, 0x80, 0x43, 0xa5, 0xbf, 0x1, 0x3f, 0x7e, 0xa1, 0x18, 0x80, 0x3a, 0xa5,
+ 0xbf, 0x0, 0x5, 0x7e, 0xa1, 0x23, 0x80, 0x31, 0xa5, 0xbf, 0x1, 0x2d, 0x7e,
+ 0xa1, 0x3d, 0x80, 0x28, 0xa, 0x17, 0x7e, 0x1d, 0x39, 0x2d, 0x31, 0x29, 0xa1,
+ 0x0, 0x8, 0x80, 0x1b, 0x7e, 0xa1, 0x16, 0x80, 0x16, 0xa5, 0xbf, 0x0, 0x9,
+ 0x7e, 0x35, 0x30, 0xa, 0x56, 0x7c, 0xab, 0x80, 0x9, 0xa5, 0xbf, 0x1, 0x5,
+ 0x7e, 0x55, 0x30, 0x7c, 0xab, 0x7c, 0xba, 0x22, 0xca, 0x79, 0xbe, 0xb0, 0x0,
+ 0x28, 0x2e, 0x74, 0x6, 0x12, 0xa, 0x5d, 0x7d, 0x73, 0x6c, 0xff, 0x7e, 0xf0,
+ 0xa5, 0x7d, 0x37, 0x12, 0x3, 0xb4, 0x6c, 0xff, 0x7e, 0xf0, 0xf, 0x7d, 0x37,
+ 0x12, 0x3, 0xb4, 0x6c, 0xff, 0x7e, 0xf0, 0x6a, 0x7d, 0x37, 0x12, 0x3, 0xb4,
+ 0x7e, 0x34, 0x0, 0x5, 0x12, 0xd, 0x96, 0x80, 0x30, 0x74, 0x1, 0x7e, 0x34,
+ 0xdf, 0xff, 0x12, 0x3, 0xb4, 0x74, 0x6, 0x12, 0xa, 0x5d, 0x7d, 0x73, 0x6c,
+ 0xff, 0x7d, 0x37, 0x12, 0x3, 0xb4, 0x7d, 0x37, 0x12, 0x3, 0xb4, 0x7d, 0x37,
+ 0x12, 0x3, 0xb4, 0x74, 0x2, 0x12, 0xa, 0x5d, 0x7d, 0x73, 0x4e, 0xf0, 0x1,
+ 0x7d, 0x37, 0x12, 0x3, 0xb4, 0xda, 0x79, 0x22, 0xa9, 0xc2, 0xb4, 0xa9, 0xc6,
+ 0xb3, 0x75, 0xb5, 0x5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5,
+ 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36,
+ 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0xf5, 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9,
+ 0xc6, 0xb3, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x75,
+ 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x7e, 0x71, 0xb5, 0x75,
+ 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9, 0xc6, 0xb3, 0x7e, 0xa1, 0xb5, 0xa9,
+ 0xd2, 0xb4, 0x7c, 0x47, 0x6c, 0x55, 0xa, 0x3a, 0x4d, 0x32, 0x22, 0x7f, 0x70,
+ 0xd2, 0x7, 0x12, 0xd, 0xf4, 0x74, 0x2, 0x12, 0xd, 0x1b, 0x6d, 0x33, 0x80,
+ 0x12, 0x7f, 0x7, 0x2d, 0x13, 0x7e, 0xb, 0xb0, 0xf5, 0xb5, 0xa9, 0x36, 0xb3,
+ 0xfc, 0xa9, 0xc6, 0xb3, 0xb, 0x34, 0x7e, 0x25, 0x10, 0xbd, 0x23, 0x38, 0xe7,
+ 0xa9, 0xd2, 0xb4, 0x12, 0xe, 0x62, 0x12, 0x0, 0x2e, 0x50, 0x9, 0x7e, 0x35,
+ 0x19, 0xbe, 0x34, 0x1, 0xf4, 0x28, 0xf2, 0x7e, 0x35, 0x19, 0xbe, 0x34, 0x1,
+ 0xf4, 0x38, 0x3, 0x2, 0xe, 0x7d, 0xc2, 0x86, 0x7e, 0x34, 0x13, 0x88, 0x12,
+ 0xd, 0x96, 0xd2, 0x86, 0x22, 0xa9, 0xd1, 0xcb, 0xd2, 0xcc, 0x7e, 0x34, 0x0,
+ 0x4, 0x7e, 0x8, 0x2, 0x56, 0x74, 0xc, 0x12, 0xb, 0x63, 0xa9, 0xd1, 0xcb,
+ 0xc2, 0xcc, 0x6c, 0xaa, 0x7e, 0x70, 0x2, 0xac, 0x7a, 0x7e, 0x8, 0x2, 0x56,
+ 0x2d, 0x13, 0xb, 0xa, 0x30, 0x7d, 0x23, 0x7c, 0x45, 0x6c, 0x55, 0xa, 0x36,
+ 0x4d, 0x32, 0x1b, 0xa, 0x30, 0xb, 0xa0, 0xbe, 0xa0, 0xc, 0x78, 0xde, 0x7e,
+ 0x37, 0x2, 0x66, 0x7d, 0x23, 0xa, 0x54, 0x7c, 0xa7, 0xb4, 0xe7, 0xb, 0xbe,
+ 0xa0, 0x36, 0x78, 0x6, 0x75, 0x17, 0xe7, 0x75, 0x18, 0xc6, 0x22, 0x7e, 0x24,
+ 0x0, 0x1, 0x7e, 0x7f, 0x3, 0x16, 0x79, 0x27, 0x0, 0x6, 0x7e, 0x7f, 0x3,
+ 0x16, 0x69, 0x27, 0x0, 0x6, 0x4d, 0x22, 0x78, 0xf4, 0x5e, 0x60, 0x7f, 0x1b,
+ 0x7a, 0x30, 0x7e, 0x1f, 0x3, 0x16, 0x69, 0x31, 0x0, 0x8, 0x4d, 0x33, 0x68,
+ 0xf4, 0x6c, 0xaa, 0x80, 0x20, 0x6d, 0x44, 0x7e, 0x1f, 0x3, 0x16, 0x1b, 0x1a,
+ 0x40, 0x7e, 0x1f, 0x3, 0x16, 0x69, 0x41, 0x0, 0x8, 0x4d, 0x44, 0x68, 0xf4,
+ 0x69, 0x41, 0x0, 0x2, 0x1b, 0xa, 0x40, 0xb, 0x15, 0xb, 0xa0, 0xbc, 0xba,
+ 0x38, 0xdc, 0x22, 0x6d, 0x0, 0x74, 0x10, 0x4d, 0x0, 0x78, 0xb, 0x4d, 0x22,
+ 0x78, 0x27, 0x8d, 0x31, 0x7d, 0x12, 0x6d, 0x22, 0x22, 0x7d, 0x43, 0x7d,
+ 0x32, 0x6d, 0x22, 0x2f, 0x11, 0x2d, 0x44, 0x50, 0x2, 0xa5, 0xf, 0xbf, 0x10,
+ 0x40, 0x4, 0x9f, 0x10, 0xb, 0x90, 0x14, 0x78, 0xed, 0x7f, 0x1, 0x6d, 0x22,
+ 0x7d, 0x34, 0x22, 0x7d, 0x41, 0x7d, 0x13, 0x8d, 0x24, 0x7d, 0x2, 0x2f, 0x0,
+ 0x40, 0x4, 0xbd, 0x4, 0x40, 0x4, 0x9d, 0x4, 0xb, 0x14, 0x14, 0x78, 0xf1,
+ 0x7d, 0x23, 0x7d, 0x31, 0x7d, 0x10, 0x6d, 0x0, 0x22, 0x7c, 0xab, 0xd2, 0x7,
+ 0x12, 0xd, 0xf4, 0x74, 0xd8, 0xa, 0x3a, 0x7d, 0x23, 0x6d, 0x33, 0x12, 0xd,
+ 0x1b, 0xa9, 0xd2, 0xb4, 0x12, 0xe, 0x62, 0x12, 0x0, 0x2e, 0x50, 0x9, 0x7e,
+ 0x35, 0x19, 0xbe, 0x34, 0x5, 0xdc, 0x28, 0xf2, 0x7e, 0x35, 0x19, 0xbe, 0x34,
+ 0x5, 0xdc, 0x38, 0x3, 0x2, 0xe, 0x7d, 0xc2, 0x86, 0x7e, 0x34, 0x13, 0x88,
+ 0x12, 0xd, 0x96, 0xd2, 0x86, 0x22, 0xca, 0x2b, 0xca, 0x1b, 0xca, 0xb, 0xd2,
+ 0x0, 0x30, 0x90, 0x1c, 0xc2, 0x90, 0x7e, 0x71, 0x91, 0xe5, 0x38, 0x70, 0x3,
+ 0x7a, 0x71, 0x21, 0xe5, 0x38, 0x12, 0x1, 0xa0, 0x5, 0x38, 0x30, 0x2, 0x6,
+ 0xe4, 0x12, 0x9, 0x87, 0xf5, 0x91, 0x30, 0x91, 0xb, 0xc2, 0x91, 0x5, 0x38,
+ 0xe5, 0x38, 0x12, 0x9, 0x87, 0xf5, 0x91, 0xda, 0xb, 0xda, 0x1b, 0xda, 0x2b,
+ 0x32, 0xca, 0xf8, 0x7c, 0xfb, 0xe5, 0x23, 0xb4, 0x81, 0x23, 0x74, 0x2, 0x12,
+ 0xa, 0x5d, 0x4c, 0xff, 0x78, 0x8, 0xa9, 0xc0, 0xca, 0x5e, 0x70, 0xdf, 0x80,
+ 0x6, 0xa9, 0xd0, 0xca, 0x4e, 0x70, 0x20, 0x74, 0x2, 0x12, 0x3, 0xb4, 0x74,
+ 0x2, 0x12, 0xa, 0x5d, 0x80, 0x8, 0xe5, 0x23, 0xb4, 0x80, 0x3, 0x12, 0xc,
+ 0xed, 0xda, 0xf8, 0x22, 0xd2, 0x7, 0x12, 0xd, 0xf4, 0xa9, 0xc2, 0xb4, 0x74,
+ 0x9f, 0x12, 0xe, 0x4d, 0x12, 0xe, 0x34, 0xa9, 0xd2, 0xb4, 0x60, 0x3, 0xb4,
+ 0xff, 0x1a, 0x75, 0x23, 0x81, 0xa9, 0xd5, 0xca, 0xa9, 0xd0, 0xca, 0x75,
+ 0xed, 0x9f, 0x75, 0xad, 0x20, 0xa9, 0xd1, 0xea, 0xa9, 0xc1, 0xea, 0x74, 0x1,
+ 0x2, 0xc, 0x83, 0x22, 0xd2, 0x7, 0x12, 0xd, 0xf4, 0xa9, 0xc2, 0xb4, 0x74,
+ 0x5, 0x12, 0xe, 0x4d, 0x12, 0xe, 0x34, 0x7c, 0xab, 0xa9, 0xd2, 0xb4, 0x5e,
+ 0xa0, 0xe3, 0xa9, 0xc2, 0xb4, 0x74, 0x1, 0x12, 0xe, 0x4d, 0x7c, 0xba, 0x12,
+ 0xe, 0x4d, 0xa9, 0xd2, 0xb4, 0x12, 0x0, 0x2e, 0x40, 0xfb, 0x22, 0x7c, 0xab,
+ 0x7d, 0x12, 0x7c, 0xb3, 0xf5, 0x14, 0x7c, 0x36, 0x7c, 0x25, 0xa, 0x4, 0x7c,
+ 0xb3, 0xf5, 0x13, 0x7c, 0xb7, 0xf5, 0x12, 0xa9, 0xc2, 0xb4, 0x7c, 0xba,
+ 0x12, 0xe, 0x4d, 0xe5, 0x14, 0x12, 0xe, 0x4d, 0xe5, 0x13, 0x12, 0xe, 0x4d,
+ 0xe5, 0x12, 0x2, 0xe, 0x4d, 0x7d, 0x52, 0xf5, 0x15, 0x7c, 0xb6, 0x7c, 0xa5,
+ 0xa, 0x44, 0xf5, 0x14, 0x7f, 0x21, 0xf5, 0x13, 0xa9, 0xc2, 0xb4, 0x74, 0xb,
+ 0x12, 0xe, 0x4d, 0xe5, 0x15, 0x12, 0xe, 0x4d, 0xe5, 0x14, 0x12, 0xe, 0x4d,
+ 0xe5, 0x13, 0x12, 0xe, 0x4d, 0xe4, 0x2, 0xe, 0x4d, 0x12, 0xd, 0xb9, 0x12,
+ 0xb, 0xf, 0xa9, 0xa6, 0x94, 0xb3, 0x92, 0x6, 0x30, 0x6, 0x6, 0x12, 0xe,
+ 0x41, 0x12, 0xc, 0xba, 0x12, 0x8, 0x10, 0x12, 0xe, 0x26, 0xd2, 0xaf, 0x30,
+ 0x3, 0xfd, 0x2, 0xe, 0x75, 0x80, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0xe5, 0x3d, 0x70, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x7d, 0x23, 0x1b, 0x34, 0x4d, 0x22, 0x78, 0xe0, 0x22, 0xd2,
+ 0xcf, 0x85, 0x3d, 0xcc, 0x75, 0xec, 0xff, 0x75, 0xee, 0xff, 0x75, 0xeb, 0x3,
+ 0x75, 0xac, 0x40, 0xa9, 0xc5, 0xca, 0x75, 0xed, 0xf, 0x75, 0xad, 0xb0, 0xa9,
+ 0xd7, 0x94, 0xa9, 0xd4, 0x94, 0x22, 0xa, 0x27, 0xa, 0x3b, 0x2d, 0x32, 0xbe,
+ 0x34, 0x0, 0xff, 0x78, 0xc, 0xbe, 0xb0, 0x2, 0x40, 0x7, 0xbe, 0xb0, 0xfe,
+ 0x38, 0x2, 0xd3, 0x22, 0xc3, 0x22, 0xa9, 0xc2, 0xb4, 0x30, 0x7, 0x4, 0x74,
+ 0x6, 0x80, 0x2, 0x74, 0x4, 0x12, 0xe, 0x4d, 0xa9, 0xd2, 0xb4, 0x22, 0xe5,
+ 0x32, 0xb4, 0xc, 0xb, 0xc2, 0x86, 0x7e, 0x34, 0x0, 0x64, 0x12, 0xd, 0x96,
+ 0xd2, 0x86, 0x22, 0x12, 0xd, 0x48, 0x7e, 0x35, 0x11, 0x12, 0x0, 0xe, 0xa9,
+ 0xd2, 0xb4, 0xd3, 0x22, 0xc2, 0x8c, 0x43, 0x89, 0x2, 0x75, 0x8c, 0x1, 0x75,
+ 0x8a, 0x0, 0xd2, 0xa9, 0x22, 0x75, 0xb5, 0x0, 0xa9, 0x36, 0xb3, 0xfc, 0xa9,
+ 0xc6, 0xb3, 0xe5, 0xb5, 0x22, 0xd2, 0xc8, 0x75, 0xb3, 0x13, 0xa9, 0xd1,
+ 0xb4, 0xa9, 0xc0, 0xb4, 0x22, 0xf5, 0xb5, 0xa9, 0x36, 0xb3, 0xfc, 0xa9,
+ 0xc6, 0xb3, 0xd3, 0x22, 0x7e, 0x34, 0x0, 0x4, 0x12, 0x9, 0x19, 0x7d, 0x53,
+ 0x22, 0xc2, 0x8c, 0x6d, 0x33, 0x7a, 0x35, 0x19, 0xd2, 0x8c, 0x22, 0x7e,
+ 0x35, 0x19, 0xb, 0x34, 0x7a, 0x35, 0x19, 0x22, 0x85, 0x3d, 0xcc, 0xe5, 0x3d,
+ 0x2, 0xc, 0x83, 0x2, 0xe, 0x6c, 0x0, 0x4, 0x3, 0x16, 0x0, 0x0, 0x9c, 0x0,
+ 0x0, 0x0,
diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c
index 82079cde849c..4c4d559e0d04 100644
--- a/drivers/input/touchscreen/max11801_ts.c
+++ b/drivers/input/touchscreen/max11801_ts.c
@@ -2,7 +2,7 @@
* Driver for MAXI MAX11801 - A Resistive touch screen controller with
* i2c interface
*
- * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc.
* Author: Zhang Jiejing <jiejing.zhang@freescale.com>
*
* Based on mcs5000_ts.c
@@ -38,6 +38,10 @@
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
/* Register Address define */
#define GENERNAL_STATUS_REG 0x00
@@ -53,13 +57,30 @@
#define AUX_MESURE_CONF_REG 0x0a
#define OP_MODE_CONF_REG 0x0b
+#define Panel_Setup_X (0x69 << 1)
+#define Panel_Setup_Y (0x6b << 1)
+
+#define XY_combined_measurement (0x70 << 1)
+#define X_measurement (0x78 << 1)
+#define Y_measurement (0x7a << 1)
+#define AUX_measurement (0x76 << 1)
+
/* FIFO is found only in max11800 and max11801 */
#define FIFO_RD_CMD (0x50 << 1)
#define MAX11801_FIFO_INT (1 << 2)
#define MAX11801_FIFO_OVERFLOW (1 << 3)
+#define MAX11801_EDGE_INT (1 << 1)
+
+#define FIFO_RD_X_MSB (0x52 << 1)
+#define FIFO_RD_X_LSB (0x53 << 1)
+#define FIFO_RD_Y_MSB (0x54 << 1)
+#define FIFO_RD_Y_LSB (0x55 << 1)
+#define FIFO_RD_AUX_MSB (0x5a << 1)
+#define FIFO_RD_AUX_LSB (0x5b << 1)
#define XY_BUFSIZE 4
#define XY_BUF_OFFSET 4
+#define AUX_BUFSIZE 2
#define MAX11801_MAX_X 0xfff
#define MAX11801_MAX_Y 0xfff
@@ -84,6 +105,64 @@ struct max11801_data {
struct input_dev *input_dev;
};
+static struct i2c_client *max11801_client;
+static unsigned int max11801_workmode;
+static u8 aux_buf[AUX_BUFSIZE];
+
+static int max11801_dcm_write_command(struct i2c_client *client, int command)
+{
+ return i2c_smbus_write_byte(client, command);
+}
+
+static int max11801_dcm_sample_aux(struct i2c_client *client)
+{
+ int ret;
+ int aux = 0;
+ int sample_data;
+
+ /* AUX_measurement */
+ max11801_dcm_write_command(client, AUX_measurement);
+ mdelay(5);
+ ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_AUX_MSB,
+ 1, &aux_buf[0]);
+ if (ret < 0) {
+ dev_err(&client->dev, "FIFO_RD_AUX_MSB read failed (%d)\n",
+ ret);
+ return ret;
+ }
+ mdelay(5);
+ ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_AUX_LSB,
+ 1, &aux_buf[1]);
+ if (ret < 0) {
+ dev_err(&client->dev, "FIFO_RD_AUX_LSB read failed (%d)\n",
+ ret);
+ return ret;
+ }
+
+ aux = (aux_buf[0] << 4) + (aux_buf[1] >> 4);
+ /*
+ * voltage = (9170*aux)/7371;
+ * voltage is (26.2*3150*aux)/(16.2*0xFFF)
+ * V(aux)=3150*sample/0xFFF,V(battery)=212*V(aux)/81
+ * sample_data = (14840*aux)/7371-1541;
+ */
+ sample_data = (14840 * aux) / 7371;
+
+ return sample_data;
+}
+
+int max11801_read_adc(void)
+{
+ int adc_data;
+
+ if (!max11801_client)
+ return -ENODEV;
+ adc_data = max11801_dcm_sample_aux(max11801_client);
+
+ return adc_data;
+}
+EXPORT_SYMBOL_GPL(max11801_read_adc);
+
static u8 read_register(struct i2c_client *client, int addr)
{
/* XXX: The chip ignores LSB of register address */
@@ -104,29 +183,62 @@ static irqreturn_t max11801_ts_interrupt(int irq, void *dev_id)
u8 buf[XY_BUFSIZE];
int x = -1;
int y = -1;
+ u8 command = FIFO_RD_X_MSB;
status = read_register(data->client, GENERNAL_STATUS_REG);
-
- if (status & (MAX11801_FIFO_INT | MAX11801_FIFO_OVERFLOW)) {
+ if ((!max11801_workmode && (status & (MAX11801_FIFO_INT |
+ MAX11801_FIFO_OVERFLOW))) || (max11801_workmode && (status &
+ MAX11801_EDGE_INT))) {
status = read_register(data->client, GENERNAL_STATUS_REG);
-
- ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_CMD,
- XY_BUFSIZE, buf);
-
- /*
- * We should get 4 bytes buffer that contains X,Y
- * and event tag
- */
- if (ret < XY_BUFSIZE)
- goto out;
+ if (!max11801_workmode) {
+ /* ACM mode */
+ ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_CMD,
+ XY_BUFSIZE, buf);
+ /*
+ * We should get 4 bytes buffer that contains X,Y
+ * and event tag
+ */
+ if (ret < XY_BUFSIZE)
+ goto out;
+ } else {
+ /* DCM mode */
+ /* X = panel setup */
+ max11801_dcm_write_command(client, Panel_Setup_X);
+ /* X_measurement */
+ max11801_dcm_write_command(client, X_measurement);
+ for (i = 0; i < 2; i++) {
+ ret = i2c_smbus_read_i2c_block_data(client,
+ command, 1, &buf[i]);
+ if (ret < 1)
+ goto out;
+
+ command = FIFO_RD_X_LSB;
+ }
+
+ /* Y = panel setup */
+ max11801_dcm_write_command(client, Panel_Setup_Y);
+ /* Y_measurement */
+ max11801_dcm_write_command(client, Y_measurement);
+ command = FIFO_RD_Y_MSB;
+ for (i = 2; i < XY_BUFSIZE; i++) {
+ ret = i2c_smbus_read_i2c_block_data(client,
+ command, 1, &buf[i]);
+ if (ret < 1)
+ goto out;
+
+ command = FIFO_RD_Y_LSB;
+ }
+ }
for (i = 0; i < XY_BUFSIZE; i += XY_BUFSIZE / 2) {
- if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_X_TAG)
+ if ((buf[i + 1] & MEASURE_TAG_MASK) ==
+ MEASURE_X_TAG)
x = (buf[i] << XY_BUF_OFFSET) +
- (buf[i + 1] >> XY_BUF_OFFSET);
- else if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_Y_TAG)
+ (buf[i + 1] >> XY_BUF_OFFSET);
+ else if ((buf[i + 1] & MEASURE_TAG_MASK) ==
+ MEASURE_Y_TAG)
y = (buf[i] << XY_BUF_OFFSET) +
- (buf[i + 1] >> XY_BUF_OFFSET);
+ (buf[i + 1] >> XY_BUF_OFFSET);
}
if ((buf[1] & EVENT_TAG_MASK) != (buf[3] & EVENT_TAG_MASK))
@@ -137,18 +249,17 @@ static irqreturn_t max11801_ts_interrupt(int irq, void *dev_id)
/* fall through */
case EVENT_MIDDLE:
input_report_abs(data->input_dev, ABS_X, x);
+ y = MAX11801_MAX_Y - y; /* Calibration */
input_report_abs(data->input_dev, ABS_Y, y);
input_event(data->input_dev, EV_KEY, BTN_TOUCH, 1);
input_sync(data->input_dev);
break;
-
case EVENT_RELEASE:
input_event(data->input_dev, EV_KEY, BTN_TOUCH, 0);
input_sync(data->input_dev);
break;
-
case EVENT_FIFO_END:
- break;
+ break;
}
}
out:
@@ -159,18 +270,37 @@ static void max11801_ts_phy_init(struct max11801_data *data)
{
struct i2c_client *client = data->client;
- /* Average X,Y, take 16 samples, average eight media sample */
+ max11801_client = client;
+ /* Average X,Y, take 16 samples average eight media sample */
max11801_write_reg(client, MESURE_AVER_CONF_REG, 0xff);
/* X,Y panel setup time set to 20us */
max11801_write_reg(client, PANEL_SETUPTIME_CONF_REG, 0x11);
- /* Rough pullup time (2uS), Fine pullup time (10us) */
+ /* Rough pullup time (2uS), Fine pullup time (10us) */
max11801_write_reg(client, TOUCH_DETECT_PULLUP_CONF_REG, 0x10);
- /* Auto mode init period = 5ms , scan period = 5ms*/
+ /* Auto mode init period = 5ms, scan period = 5ms */
max11801_write_reg(client, AUTO_MODE_TIME_CONF_REG, 0xaa);
/* Aperture X,Y set to +- 4LSB */
max11801_write_reg(client, APERTURE_CONF_REG, 0x33);
- /* Enable Power, enable Automode, enable Aperture, enable Average X,Y */
- max11801_write_reg(client, OP_MODE_CONF_REG, 0x36);
+ /*
+ * Enable Power, enable Automode, enable Aperture,
+ * enable Average X,Y
+ */
+ if (!max11801_workmode)
+ max11801_write_reg(client, OP_MODE_CONF_REG, 0x36);
+ else {
+ max11801_write_reg(client, OP_MODE_CONF_REG, 0x16);
+ /*
+ * Delay initial=1ms, Sampling time 2us
+ * Averaging sample depth 2
+ * samples, Resolution 12bit
+ */
+ max11801_write_reg(client, AUX_MESURE_CONF_REG, 0x76);
+ /*
+ * Use edge interrupt with
+ * direct conversion mode
+ */
+ max11801_write_reg(client, GENERNAL_CONF_REG, 0xf3);
+ }
}
static int max11801_ts_probe(struct i2c_client *client,
@@ -179,6 +309,7 @@ static int max11801_ts_probe(struct i2c_client *client,
struct max11801_data *data;
struct input_dev *input_dev;
int error;
+ struct device_node *of_node = client->dev.of_node;
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
input_dev = devm_input_allocate_device(&client->dev);
@@ -201,6 +332,9 @@ static int max11801_ts_probe(struct i2c_client *client,
input_set_abs_params(input_dev, ABS_Y, 0, MAX11801_MAX_Y, 0, 0);
input_set_drvdata(input_dev, data);
+ if (of_property_read_u32(of_node, "work-mode", &max11801_workmode))
+ max11801_workmode = *(int *)(client->dev).platform_data;
+
max11801_ts_phy_init(data);
error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
@@ -226,9 +360,17 @@ static const struct i2c_device_id max11801_ts_id[] = {
};
MODULE_DEVICE_TABLE(i2c, max11801_ts_id);
+static const struct of_device_id max11801_ts_dt_ids[] = {
+ { .compatible = "maxim,max11801", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, max11801_ts_dt_ids);
+
static struct i2c_driver max11801_ts_driver = {
.driver = {
.name = "max11801_ts",
+ .owner = THIS_MODULE,
+ .of_match_table = max11801_ts_dt_ids,
},
.id_table = max11801_ts_id,
.probe = max11801_ts_probe,
diff --git a/drivers/input/touchscreen/synaptics_dsx/Kconfig b/drivers/input/touchscreen/synaptics_dsx/Kconfig
new file mode 100644
index 000000000000..6410f7ec7cd1
--- /dev/null
+++ b/drivers/input/touchscreen/synaptics_dsx/Kconfig
@@ -0,0 +1,27 @@
+#
+# Synaptics DSX touchscreen driver configuration
+#
+menuconfig TOUCHSCREEN_SYNAPTICS_DSX
+ bool "Synaptics DSX touchscreen"
+ default y
+ help
+ Say Y here if you have a Synaptics DSX I2C touchscreen
+ connected to your system
+
+ if unsure, say N.
+
+if TOUCHSCREEN_SYNAPTICS_DSX
+
+config TOUCHSCREEN_SYNAPTICS_DSX_I2C
+ tristate "Synaptics DSX core driver module"
+ depends on I2C
+ help
+ Say Y here if you have a Synaptics DSX I2C touchscreen
+ connected to your system
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called synaptics_dsx_i2c.
+
+endif
diff --git a/drivers/input/touchscreen/synaptics_dsx/Makefile b/drivers/input/touchscreen/synaptics_dsx/Makefile
new file mode 100644
index 000000000000..b46f3df6d9d5
--- /dev/null
+++ b/drivers/input/touchscreen/synaptics_dsx/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_I2C) += synaptics_dsx_i2c.o
+
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx.h b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx.h
new file mode 100644
index 000000000000..5adeb65b6b3f
--- /dev/null
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx.h
@@ -0,0 +1,86 @@
+/*
+ * Synaptics DSX touchscreen driver
+ *
+ * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
+ *
+ * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
+ * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
+ * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
+ * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
+ * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
+ * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
+ * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
+ * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
+ * DOLLARS.
+ */
+
+#ifndef _SYNAPTICS_DSX_H_
+#define _SYNAPTICS_DSX_H_
+
+/*
+ * synaptics_dsx_cap_button_map - 0d button map
+ * @nbuttons: number of 0d buttons
+ * @map: pointer to array of button types
+ */
+struct synaptics_dsx_cap_button_map {
+ unsigned int nbuttons;
+ unsigned int *map;
+};
+
+/*
+ * struct synaptics_dsx_platform_data - dsx platform data
+ * @x_flip: x flip flag
+ * @y_flip: y flip flag
+ * @irq_gpio: attention interrupt gpio
+ * @power_gpio: power switch gpio
+ * @power_on_state: power switch active state
+ * @reset_gpio: reset gpio
+ * @reset_on_state: reset active state
+ * @irq_flags: irq flags
+ * @panel_x: x-axis resolution of display panel
+ * @panel_y: y-axis resolution of display panel
+ * @power_delay_ms: delay time to wait after power-on
+ * @reset_delay_ms: delay time to wait after reset
+ * @reset_active_ms: reset active time
+ * @regulator_name: pointer to name of regulator
+ * @gpio_config: pointer to gpio configuration function
+ * @cap_button_map: pointer to 0d button map
+ */
+struct synaptics_dsx_platform_data {
+ bool x_flip;
+ bool y_flip;
+ bool swap_axes;
+ int irq_gpio;
+ int power_gpio;
+ int power_on_state;
+ int reset_gpio;
+ int reset_on_state;
+ unsigned long irq_flags;
+ unsigned int panel_x;
+ unsigned int panel_y;
+ unsigned int power_delay_ms;
+ unsigned int reset_delay_ms;
+ unsigned int reset_active_ms;
+ unsigned char *regulator_name;
+ int (*gpio_config)(int gpio, bool configure, int dir, int state);
+ struct synaptics_dsx_cap_button_map *cap_button_map;
+};
+
+#endif
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c
new file mode 100644
index 000000000000..35fc226a5190
--- /dev/null
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.c
@@ -0,0 +1,3615 @@
+/*
+ * Synaptics DSX touchscreen driver
+ *
+ * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
+ *
+ * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
+ * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ * Copyright 2018 NXP
+ *
+ * This program is free software; 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.
+ *
+ * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
+ * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
+ * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
+ * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
+ * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
+ * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
+ * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
+ * DOLLARS.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/stringify.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/dma-mapping.h>
+#include <linux/kthread.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+
+#include "synaptics_dsx_i2c.h"
+#include "synaptics_dsx.h"
+
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+
+#include <linux/input/mt.h>
+
+
+#define DRIVER_NAME "synaptics_dsx_i2c"
+#define INPUT_PHYS_NAME "synaptics_dsx_i2c/input0"
+
+#define TYPE_B_PROTOCOL
+
+#define UBL_I2C_ADDR 0x2c
+
+#define SENSOR_MAX_X 1080
+#define SENSOR_MAX_Y 1920
+
+#define WAKEUP_GESTURE false
+
+#define NO_0D_WHILE_2D
+#define REPORT_2D_W
+
+#define F12_DATA_15_WORKAROUND
+
+#define RPT_TYPE (1 << 0)
+#define RPT_X_LSB (1 << 1)
+#define RPT_X_MSB (1 << 2)
+#define RPT_Y_LSB (1 << 3)
+#define RPT_Y_MSB (1 << 4)
+#define RPT_Z (1 << 5)
+#define RPT_WX (1 << 6)
+#define RPT_WY (1 << 7)
+#define RPT_DEFAULT (RPT_TYPE | RPT_X_LSB | RPT_X_MSB | RPT_Y_LSB | RPT_Y_MSB)
+#define attrify(propname) (&dev_attr_##propname.attr)
+
+#define EXP_FN_WORK_DELAY_MS 1000 /* ms */
+#define SYN_I2C_RETRY_TIMES 5
+#define MAX_F11_TOUCH_WIDTH 15
+
+#define CHECK_STATUS_TIMEOUT_MS 100
+#define DELAY_BOOT_READY 200
+#define DELAY_RESET_LOW 20
+#define DELAY_UI_READY 200
+
+#define F01_STD_QUERY_LEN 21
+#define F01_BUID_ID_OFFSET 18
+#define F11_STD_QUERY_LEN 9
+#define F11_STD_CTRL_LEN 10
+#define F11_STD_DATA_LEN 12
+
+#define STATUS_NO_ERROR 0x00
+#define STATUS_RESET_OCCURRED 0x01
+#define STATUS_INVALID_CONFIG 0x02
+#define STATUS_DEVICE_FAILURE 0x03
+#define STATUS_CONFIG_CRC_FAILURE 0x04
+#define STATUS_FIRMWARE_CRC_FAILURE 0x05
+#define STATUS_CRC_IN_PROGRESS 0x06
+
+#define NORMAL_OPERATION (0 << 0)
+#define SENSOR_SLEEP (1 << 0)
+#define NO_SLEEP_OFF (0 << 2)
+#define NO_SLEEP_ON (1 << 2)
+#define CONFIGURED (1 << 7)
+
+
+#define F11_CONTINUOUS_MODE 0x00
+#define F11_WAKEUP_GESTURE_MODE 0x04
+#define F12_CONTINUOUS_MODE 0x00
+#define F12_WAKEUP_GESTURE_MODE 0x02
+
+#define F12_UDG_DETECT 0x0f
+
+#ifdef USE_I2C_DMA
+#include <linux/dma-mapping.h>
+static unsigned char *wDMABuf_va;
+static dma_addr_t wDMABuf_pa;
+#endif
+
+static struct task_struct *thread;
+static DECLARE_WAIT_QUEUE_HEAD(waiter);
+int tpd_halt;
+static int tpd_flag;
+DEFINE_MUTEX(rmi4_report_mutex);
+static struct device *g_dev;
+
+/* for 0D button */
+static unsigned int cap_button_codes[] = {KEY_APPSELECT, KEY_HOMEPAGE, KEY_BACK};
+static struct synaptics_dsx_cap_button_map cap_button_map = {
+ .nbuttons = ARRAY_SIZE(cap_button_codes),
+ .map = cap_button_codes,
+};
+
+#ifdef CONFIG_OF_TOUCH
+unsigned int touch_irq;
+#endif
+
+#ifdef CONFIG_OF_TOUCH
+static irqreturn_t tpd_eint_handler(unsigned int irq, struct irq_desc *desc);
+#else
+static void tpd_eint_handler(void);
+#endif
+
+static int touch_event_handler(void *data);
+
+static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
+ unsigned short addr, unsigned char *data,
+ unsigned short length);
+
+static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data,
+ unsigned short addr, unsigned char *data,
+ unsigned short length);
+
+static int synaptics_rmi4_f12_set_enables(struct synaptics_rmi4_data *rmi4_data,
+ unsigned short ctrl28);
+
+static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data);
+static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data);
+static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data);
+
+
+static int __maybe_unused synaptics_rmi4_suspend(struct device *dev);
+
+static int __maybe_unused synaptics_rmi4_resume(struct device *dev);
+
+static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t synaptics_rmi4_f01_productinfo_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t synaptics_rmi4_f01_buildid_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t synaptics_rmi4_f01_flashprog_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t synaptics_rmi4_0dbutton_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t synaptics_rmi4_0dbutton_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t synaptics_rmi4_suspend_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t synaptics_rmi4_wake_gesture_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t synaptics_rmi4_wake_gesture_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count);
+struct synaptics_rmi4_f01_device_status {
+ union {
+ struct {
+ unsigned char status_code:4;
+ unsigned char reserved:2;
+ unsigned char flash_prog:1;
+ unsigned char unconfigured:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct synaptics_rmi4_f11_query_0_5 {
+ union {
+ struct {
+ /* query 0 */
+ unsigned char f11_query0_b0__2:3;
+ unsigned char has_query_9:1;
+ unsigned char has_query_11:1;
+ unsigned char has_query_12:1;
+ unsigned char has_query_27:1;
+ unsigned char has_query_28:1;
+
+ /* query 1 */
+ unsigned char num_of_fingers:3;
+ unsigned char has_rel:1;
+ unsigned char has_abs:1;
+ unsigned char has_gestures:1;
+ unsigned char has_sensitibity_adjust:1;
+ unsigned char f11_query1_b7:1;
+
+ /* query 2 */
+ unsigned char num_of_x_electrodes;
+
+ /* query 3 */
+ unsigned char num_of_y_electrodes;
+
+ /* query 4 */
+ unsigned char max_electrodes:7;
+ unsigned char f11_query4_b7:1;
+
+ /* query 5 */
+ unsigned char abs_data_size:2;
+ unsigned char has_anchored_finger:1;
+ unsigned char has_adj_hyst:1;
+ unsigned char has_dribble:1;
+ unsigned char has_bending_correction:1;
+ unsigned char has_large_object_suppression:1;
+ unsigned char has_jitter_filter:1;
+ } __packed;
+ unsigned char data[6];
+ };
+};
+
+struct synaptics_rmi4_f11_query_7_8 {
+ union {
+ struct {
+ /* query 7 */
+ unsigned char has_single_tap:1;
+ unsigned char has_tap_and_hold:1;
+ unsigned char has_double_tap:1;
+ unsigned char has_early_tap:1;
+ unsigned char has_flick:1;
+ unsigned char has_press:1;
+ unsigned char has_pinch:1;
+ unsigned char has_chiral_scroll:1;
+
+ /* query 8 */
+ unsigned char has_palm_detect:1;
+ unsigned char has_rotate:1;
+ unsigned char has_touch_shapes:1;
+ unsigned char has_scroll_zones:1;
+ unsigned char individual_scroll_zones:1;
+ unsigned char has_multi_finger_scroll:1;
+ unsigned char has_multi_finger_scroll_edge_motion:1;
+ unsigned char has_multi_finger_scroll_inertia:1;
+ } __packed;
+ unsigned char data[2];
+ };
+};
+
+struct synaptics_rmi4_f11_query_9 {
+ union {
+ struct {
+ unsigned char has_pen:1;
+ unsigned char has_proximity:1;
+ unsigned char has_large_object_sensitivity:1;
+ unsigned char has_suppress_on_large_object_detect:1;
+ unsigned char has_two_pen_thresholds:1;
+ unsigned char has_contact_geometry:1;
+ unsigned char has_pen_hover_discrimination:1;
+ unsigned char has_pen_hover_and_edge_filters:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct synaptics_rmi4_f11_query_12 {
+ union {
+ struct {
+ unsigned char has_small_object_detection:1;
+ unsigned char has_small_object_detection_tuning:1;
+ unsigned char has_8bit_w:1;
+ unsigned char has_2d_adjustable_mapping:1;
+ unsigned char has_general_information_2:1;
+ unsigned char has_physical_properties:1;
+ unsigned char has_finger_limit:1;
+ unsigned char has_linear_cofficient_2:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct synaptics_rmi4_f11_query_27 {
+ union {
+ struct {
+ unsigned char f11_query27_b0:1;
+ unsigned char has_pen_position_correction:1;
+ unsigned char has_pen_jitter_filter_coefficient:1;
+ unsigned char has_group_decomposition:1;
+ unsigned char has_wakeup_gesture:1;
+ unsigned char has_small_finger_correction:1;
+ unsigned char has_data_37:1;
+ unsigned char f11_query27_b7:1;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct synaptics_rmi4_f11_ctrl_6_9 {
+ union {
+ struct {
+ unsigned char sensor_max_x_pos_7_0;
+ unsigned char sensor_max_x_pos_11_8:4;
+ unsigned char f11_ctrl7_b4__7:4;
+ unsigned char sensor_max_y_pos_7_0;
+ unsigned char sensor_max_y_pos_11_8:4;
+ unsigned char f11_ctrl9_b4__7:4;
+ } __packed;
+ unsigned char data[4];
+ };
+};
+
+struct synaptics_rmi4_f11_data_1_5 {
+ union {
+ struct {
+ unsigned char x_position_11_4;
+ unsigned char y_position_11_4;
+ unsigned char x_position_3_0:4;
+ unsigned char y_position_3_0:4;
+ unsigned char wx:4;
+ unsigned char wy:4;
+ unsigned char z;
+ } __packed;
+ unsigned char data[5];
+ };
+};
+
+struct synaptics_rmi4_f12_query_5 {
+ union {
+ struct {
+ unsigned char size_of_query6;
+ struct {
+ unsigned char ctrl0_is_present:1;
+ unsigned char ctrl1_is_present:1;
+ unsigned char ctrl2_is_present:1;
+ unsigned char ctrl3_is_present:1;
+ unsigned char ctrl4_is_present:1;
+ unsigned char ctrl5_is_present:1;
+ unsigned char ctrl6_is_present:1;
+ unsigned char ctrl7_is_present:1;
+ } __packed;
+ struct {
+ unsigned char ctrl8_is_present:1;
+ unsigned char ctrl9_is_present:1;
+ unsigned char ctrl10_is_present:1;
+ unsigned char ctrl11_is_present:1;
+ unsigned char ctrl12_is_present:1;
+ unsigned char ctrl13_is_present:1;
+ unsigned char ctrl14_is_present:1;
+ unsigned char ctrl15_is_present:1;
+ } __packed;
+ struct {
+ unsigned char ctrl16_is_present:1;
+ unsigned char ctrl17_is_present:1;
+ unsigned char ctrl18_is_present:1;
+ unsigned char ctrl19_is_present:1;
+ unsigned char ctrl20_is_present:1;
+ unsigned char ctrl21_is_present:1;
+ unsigned char ctrl22_is_present:1;
+ unsigned char ctrl23_is_present:1;
+ } __packed;
+ struct {
+ unsigned char ctrl24_is_present:1;
+ unsigned char ctrl25_is_present:1;
+ unsigned char ctrl26_is_present:1;
+ unsigned char ctrl27_is_present:1;
+ unsigned char ctrl28_is_present:1;
+ unsigned char ctrl29_is_present:1;
+ unsigned char ctrl30_is_present:1;
+ unsigned char ctrl31_is_present:1;
+ } __packed;
+ };
+ unsigned char data[5];
+ };
+};
+
+struct synaptics_rmi4_f12_query_8 {
+ union {
+ struct {
+ unsigned char size_of_query9;
+ struct {
+ unsigned char data0_is_present:1;
+ unsigned char data1_is_present:1;
+ unsigned char data2_is_present:1;
+ unsigned char data3_is_present:1;
+ unsigned char data4_is_present:1;
+ unsigned char data5_is_present:1;
+ unsigned char data6_is_present:1;
+ unsigned char data7_is_present:1;
+ } __packed;
+ struct {
+ unsigned char data8_is_present:1;
+ unsigned char data9_is_present:1;
+ unsigned char data10_is_present:1;
+ unsigned char data11_is_present:1;
+ unsigned char data12_is_present:1;
+ unsigned char data13_is_present:1;
+ unsigned char data14_is_present:1;
+ unsigned char data15_is_present:1;
+ } __packed;
+ };
+ unsigned char data[3];
+ };
+};
+
+struct synaptics_rmi4_f12_ctrl_8 {
+ union {
+ struct {
+ unsigned char max_x_coord_lsb;
+ unsigned char max_x_coord_msb;
+ unsigned char max_y_coord_lsb;
+ unsigned char max_y_coord_msb;
+ unsigned char rx_pitch_lsb;
+ unsigned char rx_pitch_msb;
+ unsigned char tx_pitch_lsb;
+ unsigned char tx_pitch_msb;
+ unsigned char low_rx_clip;
+ unsigned char high_rx_clip;
+ unsigned char low_tx_clip;
+ unsigned char high_tx_clip;
+ unsigned char num_of_rx;
+ unsigned char num_of_tx;
+ };
+ unsigned char data[14];
+ };
+};
+
+struct synaptics_rmi4_f12_ctrl_23 {
+ union {
+ struct {
+ unsigned char obj_type_enable;
+ unsigned char max_reported_objects;
+ };
+ unsigned char data[2];
+ };
+};
+
+struct synaptics_rmi4_f12_finger_data {
+ unsigned char object_type_and_status;
+ unsigned char x_lsb;
+ unsigned char x_msb;
+ unsigned char y_lsb;
+ unsigned char y_msb;
+#ifdef REPORT_2D_Z
+ unsigned char z;
+#endif
+#ifdef REPORT_2D_W
+ unsigned char wx;
+ unsigned char wy;
+#endif
+};
+
+struct synaptics_rmi4_f1a_query {
+ union {
+ struct {
+ unsigned char max_button_count:3;
+ unsigned char reserved:5;
+ unsigned char has_general_control:1;
+ unsigned char has_interrupt_enable:1;
+ unsigned char has_multibutton_select:1;
+ unsigned char has_tx_rx_map:1;
+ unsigned char has_perbutton_threshold:1;
+ unsigned char has_release_threshold:1;
+ unsigned char has_strongestbtn_hysteresis:1;
+ unsigned char has_filter_strength:1;
+ } __packed;
+ unsigned char data[2];
+ };
+};
+
+struct synaptics_rmi4_f1a_control_0 {
+ union {
+ struct {
+ unsigned char multibutton_report:2;
+ unsigned char filter_mode:2;
+ unsigned char reserved:4;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct synaptics_rmi4_f1a_control {
+ struct synaptics_rmi4_f1a_control_0 general_control;
+ unsigned char button_int_enable;
+ unsigned char multi_button;
+ unsigned char *txrx_map;
+ unsigned char *button_threshold;
+ unsigned char button_release_threshold;
+ unsigned char strongest_button_hysteresis;
+ unsigned char filter_strength;
+};
+
+struct synaptics_rmi4_f1a_handle {
+ int button_bitmask_size;
+ unsigned int max_count;
+ unsigned char valid_button_count;
+ unsigned char *button_data_buffer;
+ unsigned int *button_map;
+ struct synaptics_rmi4_f1a_query button_query;
+ struct synaptics_rmi4_f1a_control button_control;
+};
+
+struct synaptics_rmi4_exp_fhandler {
+ struct synaptics_rmi4_exp_fn *exp_fn;
+ bool insert;
+ bool remove;
+ struct list_head link;
+};
+
+struct synaptics_rmi4_exp_fn_data {
+ bool initialized;
+ bool queue_work;
+ struct mutex mutex;
+ struct list_head list;
+ struct delayed_work work;
+ struct workqueue_struct *workqueue;
+ struct synaptics_rmi4_data *rmi4_data;
+};
+
+static struct synaptics_rmi4_exp_fn_data exp_data;
+
+static struct device_attribute attrs[] = {
+ __ATTR(reset, 0660,
+ synaptics_rmi4_show_error,
+ synaptics_rmi4_f01_reset_store),
+ __ATTR(productinfo, 0444,
+ synaptics_rmi4_f01_productinfo_show,
+ synaptics_rmi4_store_error),
+ __ATTR(buildid, 0444,
+ synaptics_rmi4_f01_buildid_show,
+ synaptics_rmi4_store_error),
+ __ATTR(flashprog, 0444,
+ synaptics_rmi4_f01_flashprog_show,
+ synaptics_rmi4_store_error),
+ __ATTR(0dbutton, 0660,
+ synaptics_rmi4_0dbutton_show,
+ synaptics_rmi4_0dbutton_store),
+ __ATTR(suspend, 0660,
+ synaptics_rmi4_show_error,
+ synaptics_rmi4_suspend_store),
+ __ATTR(wake_gesture, 0660,
+ synaptics_rmi4_wake_gesture_show,
+ synaptics_rmi4_wake_gesture_store),
+};
+
+static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned int reset;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ if (sscanf(buf, "%u", &reset) != 1)
+ return -EINVAL;
+
+ if (reset != 1)
+ return -EINVAL;
+
+ retval = synaptics_rmi4_reset_device(rmi4_data);
+ if (retval < 0) {
+ dev_err(dev,
+ "%s: Failed to issue reset command, error = %d\n",
+ __func__, retval);
+ return retval;
+ }
+
+ return count;
+}
+
+static ssize_t synaptics_rmi4_f01_productinfo_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "0x%02x 0x%02x\n",
+ (rmi4_data->rmi4_mod_info.product_info[0]),
+ (rmi4_data->rmi4_mod_info.product_info[1]));
+}
+
+static ssize_t synaptics_rmi4_f01_buildid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ rmi4_data->firmware_id);
+}
+
+static ssize_t synaptics_rmi4_f01_flashprog_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int retval;
+ struct synaptics_rmi4_f01_device_status device_status;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_data_base_addr,
+ device_status.data,
+ sizeof(device_status.data));
+ if (retval < 0) {
+ dev_err(dev,
+ "%s: Failed to read device status, error = %d\n",
+ __func__, retval);
+ return retval;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ device_status.flash_prog);
+}
+
+static ssize_t synaptics_rmi4_0dbutton_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ rmi4_data->button_0d_enabled);
+}
+
+static ssize_t synaptics_rmi4_0dbutton_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned int input;
+ unsigned char ii;
+ unsigned char intr_enable;
+ struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+ struct synaptics_rmi4_device_info *rmi;
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+ if (sscanf(buf, "%u", &input) != 1)
+ return -EINVAL;
+
+ input = input > 0 ? 1 : 0;
+
+ if (rmi4_data->button_0d_enabled == input)
+ return count;
+
+ if (list_empty(&rmi->support_fn_list))
+ return -ENODEV;
+
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) {
+ ii = fhandler->intr_reg_num;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_ctrl_base_addr + 1 + ii,
+ &intr_enable,
+ sizeof(intr_enable));
+ if (retval < 0)
+ return retval;
+
+ if (input == 1)
+ intr_enable |= fhandler->intr_mask;
+ else
+ intr_enable &= ~fhandler->intr_mask;
+
+ retval = synaptics_rmi4_i2c_write(rmi4_data,
+ rmi4_data->f01_ctrl_base_addr + 1 + ii,
+ &intr_enable,
+ sizeof(intr_enable));
+ if (retval < 0)
+ return retval;
+ }
+ }
+
+ rmi4_data->button_0d_enabled = input;
+
+ return count;
+}
+
+static ssize_t synaptics_rmi4_suspend_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned int input;
+
+ if (sscanf(buf, "%u", &input) != 1)
+ return -EINVAL;
+
+ if (input == 1)
+ synaptics_rmi4_suspend(dev);
+ else if (input == 0)
+ synaptics_rmi4_resume(dev);
+ else
+ return -EINVAL;
+
+ return count;
+}
+
+
+static ssize_t synaptics_rmi4_wake_gesture_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ rmi4_data->enable_wakeup_gesture);
+}
+
+static ssize_t synaptics_rmi4_wake_gesture_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned int input;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ if (sscanf(buf, "%u", &input) != 1)
+ return -EINVAL;
+
+ input = input > 0 ? 1 : 0;
+
+ if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture)
+ rmi4_data->enable_wakeup_gesture = input;
+
+ return count;
+}
+
+static int tpd_set_page(struct synaptics_rmi4_data *rmi4_data,
+ unsigned short addr)
+{
+ int retval = 0;
+ unsigned char retry;
+ unsigned char buf[PAGE_SELECT_LEN];
+ unsigned char page;
+ struct i2c_client *i2c = rmi4_data->i2c_client;
+
+ page = ((addr >> 8) & MASK_8BIT);
+ if (page != rmi4_data->current_page) {
+ buf[0] = MASK_8BIT;
+ buf[1] = page;
+ for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
+ retval = i2c_master_send(i2c, buf, PAGE_SELECT_LEN);
+ if (retval != PAGE_SELECT_LEN) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: I2C retry %d\n", __func__, retry + 1);
+ msleep(20);
+ if (retry == (SYN_I2C_RETRY_TIMES / 2)) {
+ if (i2c->addr == rmi4_data->i2c_addr)
+ i2c->addr = UBL_I2C_ADDR;
+ else
+ i2c->addr = rmi4_data->i2c_addr;
+ }
+ } else {
+ rmi4_data->current_page = page;
+ break;
+ }
+ }
+ } else {
+ retval = PAGE_SELECT_LEN;
+ }
+
+ return retval;
+}
+
+
+int tpd_i2c_read_data(struct synaptics_rmi4_data *rmi4_data, struct i2c_client *client,
+ unsigned short addr, unsigned char *data, unsigned short length)
+{
+
+ unsigned char retry = 0;
+ unsigned char *pData = data;
+ unsigned char tmp_addr = (unsigned char)addr;
+ int retval = 0;
+ int left_len = length;
+
+ /* u16 old_flag; */
+ mutex_lock(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+ retval = tpd_set_page(rmi4_data, addr);
+ if (retval != PAGE_SELECT_LEN) {
+ retval = -EIO;
+ goto exit;
+ }
+
+ retval = i2c_master_send(client, &tmp_addr, 1);
+ while (left_len > 0) {
+ for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
+ if (left_len > 8)
+ retval = i2c_master_recv(client, pData, 8);
+ else
+ retval = i2c_master_recv(client, pData, left_len);
+ if (retval <= 0) {
+ dev_err(&client->dev, "%s: I2C retry %d\n", __func__, retry + 1);
+ msleep(20);
+ if (retry == (SYN_I2C_RETRY_TIMES / 2)) {
+ if (client->addr == rmi4_data->i2c_addr)
+ client->addr = UBL_I2C_ADDR;
+ else
+ client->addr = rmi4_data->i2c_addr;
+ }
+ left_len = length;
+ pData = data;
+ retval = i2c_master_send(client, &tmp_addr, 1);
+ continue;
+ } else {
+ break;
+ }
+ }
+ if (retry == SYN_I2C_RETRY_TIMES) {
+ retval = -EIO;
+ goto exit;
+ }
+ left_len -= 8;
+ pData += 8;
+ }
+exit:
+ mutex_unlock(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+ return retval;
+}
+EXPORT_SYMBOL(tpd_i2c_read_data);
+
+#ifdef USE_I2C_DMA
+int tpd_i2c_write_data_dma(struct synaptics_rmi4_data *rmi4_data, struct i2c_client *client,
+ unsigned short addr, unsigned char *data, unsigned short length)
+{
+ int retval = 0;
+ unsigned char retry;
+ unsigned char *buf_va = NULL;
+ struct i2c_msg msg[1];
+
+ mutex_lock(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+ msg[0].addr = rmi4_data->i2c_client->addr;
+ msg[0].flags = 0;
+ msg[0].len = length + 1;
+ msg[0].ext_flag = (rmi4_data->i2c_client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG),
+ msg[0].buf = (unsigned char *)(uintptr_t)wDMABuf_pa;
+ msg[0].timing = 400;
+
+ retval = tpd_set_page(rmi4_data, addr);
+ if (retval != PAGE_SELECT_LEN) {
+ retval = -EIO;
+ goto exit;
+ }
+
+ buf_va = wDMABuf_va;
+ buf_va[0] = addr & MASK_8BIT;
+ memcpy(&buf_va[1], &data[0], length);
+
+ for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
+ if (i2c_transfer(rmi4_data->i2c_client->adapter, msg, 1) == 1) {
+ retval = length;
+ break;
+ }
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: I2C retry %d\n",
+ __func__, retry + 1);
+ msleep(20);
+
+ if (retry == (SYN_I2C_RETRY_TIMES / 2)) {
+ if (rmi4_data->i2c_client->addr == rmi4_data->i2c_addr)
+ rmi4_data->i2c_client->addr = UBL_I2C_ADDR;
+ else
+ rmi4_data->i2c_client->addr = rmi4_data->i2c_addr;
+ msg[0].addr = rmi4_data->i2c_client->addr;
+ }
+ }
+
+ if (retry == SYN_I2C_RETRY_TIMES) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: I2C write over retry limit\n",
+ __func__);
+ retval = -EIO;
+ }
+
+exit:
+ mutex_unlock(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+ return retval;
+}
+EXPORT_SYMBOL(tpd_i2c_write_data_dma);
+
+#else
+int tpd_i2c_write_data(struct synaptics_rmi4_data *rmi4_data, struct i2c_client *client,
+ unsigned short addr, unsigned char *data, unsigned short length)
+{
+ int retval = 0;
+ u8 retry = 0;
+ u8 *buf;
+ int tmp_addr = addr;
+
+
+ mutex_lock(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+ retval = tpd_set_page(rmi4_data, addr);
+ if (retval != PAGE_SELECT_LEN) {
+ pr_err("tpd_set_page fail, retval = %d\n", retval);
+ retval = -EIO;
+ goto exit;
+ }
+
+ buf = kzalloc(sizeof(unsigned char) * (length + 1), GFP_KERNEL);
+ *buf = tmp_addr;
+ memcpy(buf + 1, data, length);
+ for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
+ retval = i2c_master_send(client, buf, (length + 1));
+ if (retval <= 0) {
+ dev_err(&client->dev, "%s: I2C retry %d\n", __func__, retry + 1);
+ msleep(20);
+ continue;
+ } else {
+ break;
+ }
+ }
+ kfree(buf);
+
+exit:
+ mutex_unlock(&(rmi4_data->rmi4_io_ctrl_mutex));
+
+ return retval;
+}
+EXPORT_SYMBOL(tpd_i2c_write_data);
+
+#endif
+
+ /**
+ * synaptics_rmi4_i2c_read()
+ *
+ * Called by various functions in this driver, and also exported to
+ * other expansion Function modules such as rmi_dev.
+ *
+ * This function reads data of an arbitrary length from the sensor,
+ * starting from an assigned register address of the sensor, via I2C
+ * with a retry mechanism.
+ */
+static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
+ unsigned short addr, unsigned char *data, unsigned short length)
+{
+ return tpd_i2c_read_data(rmi4_data, rmi4_data->i2c_client, addr, data, length);
+}
+
+ /**
+ * synaptics_rmi4_i2c_write()
+ *
+ * Called by various functions in this driver, and also exported to
+ * other expansion Function modules such as rmi_dev.
+ *
+ * This function writes data of an arbitrary length to the sensor,
+ * starting from an assigned register address of the sensor, via I2C with
+ * a retry mechanism.
+ */
+static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data,
+ unsigned short addr, unsigned char *data, unsigned short length)
+{
+#ifdef USE_I2C_DMA
+ return tpd_i2c_write_data_dma(rmi4_data, rmi4_data->i2c_client, addr, data, length);
+#else
+ return tpd_i2c_write_data(rmi4_data, rmi4_data->i2c_client, addr, data, length);
+#endif
+}
+
+ /**
+ * synaptics_rmi4_f11_abs_report()
+ *
+ * Called by synaptics_rmi4_report_touch() when valid Function $11
+ * finger data has been detected.
+ *
+ * This function reads the Function $11 data registers, determines the
+ * status of each finger supported by the Function, processes any
+ * necessary coordinate manipulation, reports the finger data to
+ * the input subsystem, and returns the number of fingers detected.
+ */
+static int synaptics_rmi4_f11_abs_report(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler)
+{
+ int retval;
+ unsigned char touch_count = 0; /* number of touch points */
+ unsigned char reg_index;
+ unsigned char finger;
+ unsigned char fingers_supported;
+ unsigned char num_of_finger_status_regs;
+ unsigned char finger_shift;
+ unsigned char finger_status;
+ unsigned char finger_status_reg[3];
+ unsigned char detected_gestures;
+ unsigned short data_addr;
+ unsigned short data_offset;
+ int x;
+ int y;
+ int wx;
+ int wy;
+ //int temp;
+ struct synaptics_rmi4_f11_data_1_5 data;
+ struct synaptics_rmi4_f11_extra_data *extra_data;
+
+ /*
+ * The number of finger status registers is determined by the
+ * maximum number of fingers supported - 2 bits per finger. So
+ * the number of finger status registers to read is:
+ * register_count = ceil(max_num_of_fingers / 4)
+ */
+ fingers_supported = fhandler->num_of_data_points;
+ num_of_finger_status_regs = (fingers_supported + 3) / 4;
+ data_addr = fhandler->full_addr.data_base;
+
+ extra_data = (struct synaptics_rmi4_f11_extra_data *)fhandler->extra;
+
+ if (rmi4_data->sensor_sleep && rmi4_data->enable_wakeup_gesture) {
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ data_addr + extra_data->data38_offset,
+ &detected_gestures,
+ sizeof(detected_gestures));
+ if (retval < 0)
+ return 0;
+
+ if (detected_gestures) {
+ input_report_key(rmi4_data->input_dev, KEY_POWER, 1);
+ input_sync(rmi4_data->input_dev);
+ input_report_key(rmi4_data->input_dev, KEY_POWER, 0);
+ input_sync(rmi4_data->input_dev);
+ rmi4_data->sensor_sleep = false;
+ }
+
+ return 0;
+ }
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ data_addr,
+ finger_status_reg,
+ num_of_finger_status_regs);
+ if (retval < 0)
+ return 0;
+ mutex_lock(&rmi4_report_mutex);
+ for (finger = 0; finger < fingers_supported; finger++) {
+ reg_index = finger / 4;
+ finger_shift = (finger % 4) * 2;
+ finger_status = (finger_status_reg[reg_index] >> finger_shift)
+ & MASK_2BIT;
+
+ /*
+ * Each 2-bit finger status field represents the following:
+ * 00 = finger not present
+ * 01 = finger present and data accurate
+ * 10 = finger present but data may be inaccurate
+ * 11 = reserved
+ */
+#ifdef TYPE_B_PROTOCOL
+ input_mt_slot(rmi4_data->input_dev, finger);
+ input_mt_report_slot_state(rmi4_data->input_dev,
+ MT_TOOL_FINGER, finger_status);
+#endif
+
+ if (finger_status) {
+ data_offset = data_addr +
+ num_of_finger_status_regs +
+ (finger * sizeof(data.data));
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ data_offset,
+ data.data,
+ sizeof(data.data));
+ if (retval < 0) {
+ touch_count = 0;
+ goto exit;
+ }
+
+ x = (data.x_position_11_4 << 4) | data.x_position_3_0;
+ y = (data.y_position_11_4 << 4) | data.y_position_3_0;
+ if (rmi4_data->diagonal_rotation) {
+ x = rmi4_data->sensor_max_x - x;
+ y = rmi4_data->sensor_max_y - y;
+ }
+
+ wx = data.wx;
+ wy = data.wy;
+
+ input_report_key(rmi4_data->input_dev,
+ BTN_TOUCH, 1);
+ input_report_key(rmi4_data->input_dev,
+ BTN_TOOL_FINGER, 1);
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_POSITION_X, x);
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_POSITION_Y, y);
+#ifdef REPORT_2D_W
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_TOUCH_MAJOR, max(wx, wy));
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_TOUCH_MINOR, min(wx, wy));
+#endif
+#ifndef TYPE_B_PROTOCOL
+ input_mt_sync(rmi4_data->input_dev);
+#endif
+
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Finger %d:\n"
+ "status = 0x%02x\n"
+ "x = %d\n"
+ "y = %d\n"
+ "wx = %d\n"
+ "wy = %d\n",
+ __func__, finger,
+ finger_status,
+ x, y, wx, wy);
+
+ touch_count++;
+ }
+ }
+
+ if (touch_count == 0) {
+ input_report_key(rmi4_data->input_dev,
+ BTN_TOUCH, 0);
+ input_report_key(rmi4_data->input_dev,
+ BTN_TOOL_FINGER, 0);
+#ifndef TYPE_B_PROTOCOL
+ input_mt_sync(rmi4_data->input_dev);
+#endif
+ }
+
+ input_sync(rmi4_data->input_dev);
+exit:
+ mutex_unlock(&(rmi4_report_mutex));
+ return touch_count;
+}
+
+ /**
+ * synaptics_rmi4_f12_abs_report()
+ *
+ * Called by synaptics_rmi4_report_touch() when valid Function $12
+ * finger data has been detected.
+ *
+ * This function reads the Function $12 data registers, determines the
+ * status of each finger supported by the Function, processes any
+ * necessary coordinate manipulation, reports the finger data to
+ * the input subsystem, and returns the number of fingers detected.
+ */
+static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler)
+{
+ int retval;
+ unsigned char touch_count = 0; /* number of touch points */
+ unsigned char finger;
+ unsigned char fingers_to_process;
+ unsigned char finger_status;
+ unsigned char size_of_2d_data;
+ unsigned char detected_gestures[F12_GESTURE_DETECTION_LEN]; // byte0 indicate gesture type, byte1~byte4 are gesture parameter
+ unsigned short data_addr;
+ int x;
+ int y;
+ int wx;
+ int wy;
+ int temp;
+ struct synaptics_rmi4_f12_extra_data *extra_data;
+ struct synaptics_rmi4_f12_finger_data *data;
+ struct synaptics_rmi4_f12_finger_data *finger_data;
+#ifdef F12_DATA_15_WORKAROUND
+ static unsigned char fingers_already_present;
+#endif
+
+ fingers_to_process = fhandler->num_of_data_points;
+ data_addr = fhandler->full_addr.data_base;
+ extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
+ size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data);
+
+
+ if (rmi4_data->sensor_sleep && rmi4_data->enable_wakeup_gesture) {
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ data_addr + extra_data->data4_offset,
+ detected_gestures,
+ sizeof(detected_gestures));
+ if (retval < 0)
+ return 0;
+
+ if (detected_gestures[0] && (detected_gestures[0] != F12_UDG_DETECT)) { // here is demo only, customer could decode gesture data and do whatever they want
+ input_report_key(rmi4_data->input_dev, KEY_POWER, 1);
+ input_sync(rmi4_data->input_dev);
+ input_report_key(rmi4_data->input_dev, KEY_POWER, 0);
+ input_sync(rmi4_data->input_dev);
+ rmi4_data->sensor_sleep = false;
+ }
+
+ return 0;
+ }
+
+
+ /* Determine the total number of fingers to process */
+ if (extra_data->data15_size) {
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ data_addr + extra_data->data15_offset,
+ extra_data->data15_data,
+ extra_data->data15_size);
+ if (retval < 0)
+ return 0;
+
+ /* Start checking from the highest bit */
+ temp = extra_data->data15_size - 1; /* Highest byte */
+ finger = (fingers_to_process - 1) % 8; /* Highest bit */
+ do {
+ if (extra_data->data15_data[temp] & (1 << finger))
+ break;
+
+ if (finger) {
+ finger--;
+ } else {
+ temp--; /* Move to the next lower byte */
+ finger = 7;
+ }
+
+ fingers_to_process--;
+ } while (fingers_to_process);
+
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Number of fingers to process = %d\n",
+ __func__, fingers_to_process);
+ }
+
+#ifdef F12_DATA_15_WORKAROUND
+ fingers_to_process = max(fingers_to_process, fingers_already_present);
+#endif
+
+ if (!fingers_to_process) {
+ synaptics_rmi4_free_fingers(rmi4_data);
+ return 0;
+ }
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ data_addr + extra_data->data1_offset,
+ (unsigned char *)fhandler->data,
+ fingers_to_process * size_of_2d_data);
+ if (retval < 0)
+ return 0;
+
+ data = (struct synaptics_rmi4_f12_finger_data *)fhandler->data;
+ mutex_lock(&rmi4_report_mutex);
+ for (finger = 0; finger < fingers_to_process; finger++) {
+ finger_data = data + finger;
+ finger_status = finger_data->object_type_and_status & MASK_1BIT;
+
+#ifdef TYPE_B_PROTOCOL
+ input_mt_slot(rmi4_data->input_dev, finger);
+ input_mt_report_slot_state(rmi4_data->input_dev,
+ MT_TOOL_FINGER, finger_status);
+#endif
+
+ if (finger_status) {
+#ifdef F12_DATA_15_WORKAROUND
+ fingers_already_present = finger + 1;
+#endif
+
+ x = (finger_data->x_msb << 8) | (finger_data->x_lsb);
+ y = (finger_data->y_msb << 8) | (finger_data->y_lsb);
+ if (rmi4_data->diagonal_rotation) {
+ x = rmi4_data->sensor_max_x - x;
+ y = rmi4_data->sensor_max_y - y;
+ }
+
+#ifdef REPORT_2D_W
+ wx = finger_data->wx;
+ wy = finger_data->wy;
+#endif
+
+ input_report_key(rmi4_data->input_dev,
+ BTN_TOUCH, 1);
+ input_report_key(rmi4_data->input_dev,
+ BTN_TOOL_FINGER, 1);
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_POSITION_X, x);
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_POSITION_Y, y);
+#ifdef REPORT_2D_W
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_TOUCH_MAJOR, max(wx, wy));
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_TOUCH_MINOR, min(wx, wy));
+#endif
+#ifndef TYPE_B_PROTOCOL
+ input_mt_sync(rmi4_data->input_dev);
+#endif
+
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Finger %d:\n"
+ "status = 0x%02x\n"
+ "x = %d\n"
+ "y = %d\n"
+ "wx = %d\n"
+ "wy = %d\n",
+ __func__, finger,
+ finger_status,
+ x, y, wx, wy);
+
+ touch_count++;
+ }
+ }
+
+ if (touch_count == 0) {
+ input_report_key(rmi4_data->input_dev,
+ BTN_TOUCH, 0);
+ input_report_key(rmi4_data->input_dev,
+ BTN_TOOL_FINGER, 0);
+#ifndef TYPE_B_PROTOCOL
+ input_mt_sync(rmi4_data->input_dev);
+#endif
+ }
+
+ input_sync(rmi4_data->input_dev);
+ mutex_unlock(&rmi4_report_mutex);
+ return touch_count;
+}
+
+static void synaptics_rmi4_f1a_report(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler)
+{
+ int retval;
+ unsigned char touch_count = 0;
+ unsigned char button;
+ unsigned char index;
+ unsigned char shift;
+ unsigned char status;
+ unsigned char *data;
+ unsigned short data_addr = fhandler->full_addr.data_base;
+ struct synaptics_rmi4_f1a_handle *f1a = fhandler->data;
+ static unsigned char do_once = 1;
+ static bool current_status[MAX_NUMBER_OF_BUTTONS];
+#ifdef NO_0D_WHILE_2D
+ static bool before_2d_status[MAX_NUMBER_OF_BUTTONS];
+ static bool while_2d_status[MAX_NUMBER_OF_BUTTONS];
+#endif
+
+ if (do_once) {
+ memset(current_status, 0, sizeof(current_status));
+#ifdef NO_0D_WHILE_2D
+ memset(before_2d_status, 0, sizeof(before_2d_status));
+ memset(while_2d_status, 0, sizeof(while_2d_status));
+#endif
+ do_once = 0;
+ }
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ data_addr,
+ f1a->button_data_buffer,
+ f1a->button_bitmask_size);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read button data registers\n",
+ __func__);
+ return;
+ }
+
+ data = f1a->button_data_buffer;
+ mutex_lock(&rmi4_report_mutex);
+ for (button = 0; button < f1a->valid_button_count; button++) {
+ index = button / 8;
+ shift = button % 8;
+ status = ((data[index] >> shift) & MASK_1BIT);
+
+ if (current_status[button] == status)
+ continue;
+ else
+ current_status[button] = status;
+
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Button %d (code %d) ->%d\n",
+ __func__, button,
+ f1a->button_map[button],
+ status);
+#ifdef NO_0D_WHILE_2D
+ if (rmi4_data->fingers_on_2d == false) {
+ if (status == 1) {
+ before_2d_status[button] = 1;
+ } else {
+ if (while_2d_status[button] == 1) {
+ while_2d_status[button] = 0;
+ continue;
+ } else {
+ before_2d_status[button] = 0;
+ }
+ }
+ touch_count++;
+ input_report_key(rmi4_data->input_dev,
+ f1a->button_map[button],
+ status);
+ } else {
+ if (before_2d_status[button] == 1) {
+ before_2d_status[button] = 0;
+ touch_count++;
+ input_report_key(rmi4_data->input_dev,
+ f1a->button_map[button],
+ status);
+ } else {
+ if (status == 1)
+ while_2d_status[button] = 1;
+ else
+ while_2d_status[button] = 0;
+ }
+ }
+#else
+ touch_count++;
+ input_report_key(rmi4_data->input_dev,
+ f1a->button_map[button],
+ status);
+#endif
+ }
+
+ if (touch_count)
+ input_sync(rmi4_data->input_dev);
+ mutex_unlock(&rmi4_report_mutex);
+ return;
+}
+
+ /**
+ * synaptics_rmi4_report_touch()
+ *
+ * Called by synaptics_rmi4_sensor_report().
+ *
+ * This function calls the appropriate finger data reporting function
+ * based on the function handler it receives and returns the number of
+ * fingers detected.
+ */
+static void synaptics_rmi4_report_touch(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler)
+{
+ unsigned char touch_count_2d;
+
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Function %02x reporting\n",
+ __func__, fhandler->fn_number);
+
+ switch (fhandler->fn_number) {
+ case SYNAPTICS_RMI4_F11:
+ touch_count_2d = synaptics_rmi4_f11_abs_report(rmi4_data,
+ fhandler);
+
+ if (touch_count_2d)
+ rmi4_data->fingers_on_2d = true;
+ else
+ rmi4_data->fingers_on_2d = false;
+ break;
+ case SYNAPTICS_RMI4_F12:
+ touch_count_2d = synaptics_rmi4_f12_abs_report(rmi4_data,
+ fhandler);
+ if (touch_count_2d)
+ rmi4_data->fingers_on_2d = true;
+ else
+ rmi4_data->fingers_on_2d = false;
+ break;
+ case SYNAPTICS_RMI4_F1A:
+ synaptics_rmi4_f1a_report(rmi4_data, fhandler);
+ break;
+ default:
+ break;
+ }
+
+ return;
+}
+
+ /**
+ * synaptics_rmi4_sensor_report()
+ *
+ * Called by synaptics_rmi4_irq().
+ *
+ * This function determines the interrupt source(s) from the sensor
+ * and calls synaptics_rmi4_report_touch() with the appropriate
+ * function handler for each function with valid data inputs.
+ */
+static void synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval;
+ unsigned char data[MAX_INTR_REGISTERS + 1];
+ unsigned char *intr = &data[1];
+ struct synaptics_rmi4_f01_device_status status;
+ struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_exp_fhandler *exp_fhandler;
+ struct synaptics_rmi4_device_info *rmi;
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+ /*
+ * Get interrupt status information from F01 Data1 register to
+ * determine the source(s) that are flagging the interrupt.
+ */
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_data_base_addr,
+ data,
+ rmi4_data->num_of_intr_regs + 1);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read interrupt status\n",
+ __func__);
+ return;
+ }
+
+ status.data[0] = data[0];
+ if (status.unconfigured && !status.flash_prog) {
+ pr_notice("%s: spontaneous reset detected\n", __func__);
+ retval = synaptics_rmi4_reinit_device(rmi4_data);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to reinit device\n",
+ __func__);
+ }
+ return;
+ }
+
+ /*
+ * Traverse the function handler list and service the source(s)
+ * of the interrupt accordingly.
+ */
+ if (!list_empty(&rmi->support_fn_list)) {
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ if (fhandler->num_of_data_sources) {
+ if (fhandler->intr_mask &
+ intr[fhandler->intr_reg_num]) {
+ synaptics_rmi4_report_touch(rmi4_data,
+ fhandler);
+ }
+ }
+ }
+ }
+
+ mutex_lock(&exp_data.mutex);
+ if (!list_empty(&exp_data.list)) {
+ list_for_each_entry(exp_fhandler, &exp_data.list, link) {
+ if (!exp_fhandler->insert &&
+ !exp_fhandler->remove &&
+ (exp_fhandler->exp_fn->attn != NULL))
+ exp_fhandler->exp_fn->attn(rmi4_data, intr[0]);
+ }
+ }
+ mutex_unlock(&exp_data.mutex);
+
+ return;
+}
+
+ /**
+ * synaptics_rmi4_irq()
+ *
+ * Called by the kernel when an interrupt occurs (when the sensor
+ * asserts the attention irq).
+ *
+ * This function is the ISR thread and handles the acquisition
+ * and the reporting of finger data when the presence of fingers
+ * is detected.
+ */
+#ifdef CONFIG_OF_TOUCH
+static irqreturn_t tpd_eint_handler(unsigned int irq, struct irq_desc *desc)
+{
+ disable_irq_nosync(touch_irq);
+
+ tpd_flag = 1;
+ wake_up_interruptible(&waiter);
+ return IRQ_HANDLED;
+}
+#else
+static void tpd_eint_handler(void)
+{
+ tpd_flag = 1;
+ wake_up_interruptible(&waiter);
+}
+#endif
+
+static int touch_event_handler(void *data)
+{
+ struct synaptics_rmi4_data *rmi4_data = data;
+
+ do {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ while (tpd_halt) {
+ tpd_flag = 0;
+ msleep(20);
+ }
+
+ wait_event_interruptible(waiter, tpd_flag != 0);
+
+ tpd_flag = 0;
+ set_current_state(TASK_RUNNING);
+
+ if (!rmi4_data->touch_stopped)
+ synaptics_rmi4_sensor_report(rmi4_data);
+#ifdef CONFIG_OF_TOUCH
+ enable_irq(touch_irq);
+#else
+ mt_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM);
+#endif
+
+ } while (1);
+
+ return 0;
+}
+
+ /**
+ * synaptics_rmi4_irq_enable()
+ *
+ * Called by synaptics_rmi4_probe() and the power management functions
+ * in this driver and also exported to other expansion Function modules
+ * such as rmi_dev.
+ *
+ * This function handles the enabling and disabling of the attention
+ * irq including the setting up of the ISR thread.
+ */
+static int synaptics_rmi4_irq_enable(struct synaptics_rmi4_data *rmi4_data,
+ bool enable)
+{
+ int retval = 0;
+
+ if (enable) {
+ /* set up irq */
+ if (!rmi4_data->irq_enabled) {
+#ifdef CONFIG_OF_TOUCH
+ enable_irq(touch_irq);
+#else
+ mt_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM);
+#endif
+ rmi4_data->irq_enabled = true;
+
+ }
+
+ } else {
+ if (rmi4_data->irq_enabled) {
+#ifdef CONFIG_OF_TOUCH
+ disable_irq_nosync(touch_irq);
+#else
+ mt_eint_mask(CUST_EINT_TOUCH_PANEL_NUM);
+#endif
+ rmi4_data->irq_enabled = false;
+ }
+ }
+
+ return retval;
+}
+
+static void synaptics_rmi4_set_intr_mask(struct synaptics_rmi4_fn *fhandler,
+ struct synaptics_rmi4_fn_desc *fd,
+ unsigned int intr_count)
+{
+ unsigned char ii;
+ unsigned char intr_offset;
+
+ fhandler->intr_reg_num = (intr_count + 7) / 8;
+ if (fhandler->intr_reg_num != 0)
+ fhandler->intr_reg_num -= 1;
+
+ /* Set an enable bit for each data source */
+ intr_offset = intr_count % 8;
+ fhandler->intr_mask = 0;
+ for (ii = intr_offset;
+ ii < ((fd->intr_src_count & MASK_3BIT) +
+ intr_offset);
+ ii++)
+ fhandler->intr_mask |= 1 << ii;
+
+ return;
+}
+
+static int synaptics_rmi4_f01_init(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler,
+ struct synaptics_rmi4_fn_desc *fd,
+ unsigned int intr_count)
+{
+ fhandler->fn_number = fd->fn_number;
+ fhandler->num_of_data_sources = fd->intr_src_count;
+ fhandler->data = NULL;
+ fhandler->extra = NULL;
+
+ synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
+
+ rmi4_data->f01_query_base_addr = fd->query_base_addr;
+ rmi4_data->f01_ctrl_base_addr = fd->ctrl_base_addr;
+ rmi4_data->f01_data_base_addr = fd->data_base_addr;
+ rmi4_data->f01_cmd_base_addr = fd->cmd_base_addr;
+
+ return 0;
+}
+
+ /**
+ * synaptics_rmi4_f11_init()
+ *
+ * Called by synaptics_rmi4_query_device().
+ *
+ * This function parses information from the Function 11 registers
+ * and determines the number of fingers supported, x and y data ranges,
+ * offset to the associated interrupt status register, interrupt bit
+ * mask, and gathers finger data acquisition capabilities from the query
+ * registers.
+ */
+static int synaptics_rmi4_f11_init(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler,
+ struct synaptics_rmi4_fn_desc *fd,
+ unsigned int intr_count)
+{
+ int retval;
+ unsigned char offset;
+ unsigned char fingers_supported;
+ struct synaptics_rmi4_f11_extra_data *extra_data;
+ struct synaptics_rmi4_f11_query_0_5 query_0_5;
+ struct synaptics_rmi4_f11_query_7_8 query_7_8;
+ struct synaptics_rmi4_f11_query_9 query_9;
+ struct synaptics_rmi4_f11_query_12 query_12;
+ struct synaptics_rmi4_f11_query_27 query_27;
+ struct synaptics_rmi4_f11_ctrl_6_9 control_6_9;
+
+ fhandler->fn_number = fd->fn_number;
+ fhandler->num_of_data_sources = fd->intr_src_count;
+ fhandler->extra = kmalloc(sizeof(*extra_data), GFP_KERNEL);
+ if (!fhandler->extra) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for fhandle->extra\n",
+ __func__);
+ return -ENOMEM;
+ }
+ extra_data = (struct synaptics_rmi4_f11_extra_data *)fhandler->extra;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.query_base,
+ query_0_5.data,
+ sizeof(query_0_5.data));
+ if (retval < 0)
+ return retval;
+
+ /* Maximum number of fingers supported */
+ if (query_0_5.num_of_fingers <= 4)
+ fhandler->num_of_data_points = query_0_5.num_of_fingers + 1;
+ else if (query_0_5.num_of_fingers == 5)
+ fhandler->num_of_data_points = 10;
+
+ rmi4_data->num_of_fingers = fhandler->num_of_data_points;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.ctrl_base + 6,
+ control_6_9.data,
+ sizeof(control_6_9.data));
+ if (retval < 0)
+ return retval;
+
+ /* Maximum x and y */
+ rmi4_data->sensor_max_x = SENSOR_MAX_X;
+ rmi4_data->sensor_max_y = SENSOR_MAX_Y; //control_6_9.sensor_max_y_pos_7_0 |
+ //(control_6_9.sensor_max_y_pos_11_8 << 8);
+
+ /* It's recommended to parse max_x and max_y from contrel register, but this does not match MTK's mtk-tpd.c */
+
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Function %02x max x = %d max y = %d\n",
+ __func__, fhandler->fn_number,
+ rmi4_data->sensor_max_x,
+ rmi4_data->sensor_max_y);
+
+ rmi4_data->max_touch_width = MAX_F11_TOUCH_WIDTH;
+
+ synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
+
+ fhandler->data = NULL;
+
+ offset = sizeof(query_0_5.data);
+
+ /* query 6 */
+ if (query_0_5.has_rel)
+ offset += 1;
+
+ /* queries 7 8 */
+ if (query_0_5.has_gestures) {
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.query_base + offset,
+ query_7_8.data,
+ sizeof(query_7_8.data));
+ if (retval < 0)
+ return retval;
+
+ offset += sizeof(query_7_8.data);
+ }
+
+ /* query 9 */
+ if (query_0_5.has_query_9) {
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.query_base + offset,
+ query_9.data,
+ sizeof(query_9.data));
+ if (retval < 0)
+ return retval;
+
+ offset += sizeof(query_9.data);
+ }
+
+ /* query 10 */
+ if (query_0_5.has_gestures && query_7_8.has_touch_shapes)
+ offset += 1;
+
+ /* query 11 */
+ if (query_0_5.has_query_11)
+ offset += 1;
+
+ /* query 12 */
+ if (query_0_5.has_query_12) {
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.query_base + offset,
+ query_12.data,
+ sizeof(query_12.data));
+ if (retval < 0)
+ return retval;
+
+ offset += sizeof(query_12.data);
+ }
+
+ /* query 13 */
+ if (query_0_5.has_jitter_filter)
+ offset += 1;
+
+ /* query 14 */
+ if (query_0_5.has_query_12 && query_12.has_general_information_2)
+ offset += 1;
+
+ /* queries 15 16 17 18 19 20 21 22 23 24 25 26*/
+ if (query_0_5.has_query_12 && query_12.has_physical_properties)
+ offset += 12;
+
+ /* query 27 */
+ if (query_0_5.has_query_27) {
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.query_base + offset,
+ query_27.data,
+ sizeof(query_27.data));
+ if (retval < 0)
+ return retval;
+
+ rmi4_data->f11_wakeup_gesture = query_27.has_wakeup_gesture;
+ }
+
+ if (!rmi4_data->f11_wakeup_gesture)
+ return retval;
+
+ /* data 0 */
+ fingers_supported = fhandler->num_of_data_points;
+ offset = (fingers_supported + 3) / 4;
+
+ /* data 1 2 3 4 5 */
+ offset += 5 * fingers_supported;
+
+ /* data 6 7 */
+ if (query_0_5.has_rel)
+ offset += 2 * fingers_supported;
+
+ /* data 8 */
+ if (query_0_5.has_gestures && query_7_8.data[0])
+ offset += 1;
+
+ /* data 9 */
+ if (query_0_5.has_gestures && (query_7_8.data[0] || query_7_8.data[1]))
+ offset += 1;
+
+ /* data 10 */
+ if (query_0_5.has_gestures &&
+ (query_7_8.has_pinch || query_7_8.has_flick))
+ offset += 1;
+
+ /* data 11 12 */
+ if (query_0_5.has_gestures &&
+ (query_7_8.has_flick || query_7_8.has_rotate))
+ offset += 2;
+
+ /* data 13 */
+ if (query_0_5.has_gestures && query_7_8.has_touch_shapes)
+ offset += (fingers_supported + 3) / 4;
+
+ /* data 14 15 */
+ if (query_0_5.has_gestures &&
+ (query_7_8.has_scroll_zones ||
+ query_7_8.has_multi_finger_scroll ||
+ query_7_8.has_chiral_scroll))
+ offset += 2;
+
+ /* data 16 17 */
+ if (query_0_5.has_gestures &&
+ (query_7_8.has_scroll_zones &&
+ query_7_8.individual_scroll_zones))
+ offset += 2;
+
+ /* data 18 19 20 21 22 23 24 25 26 27 */
+ if (query_0_5.has_query_9 && query_9.has_contact_geometry)
+ offset += 10 * fingers_supported;
+
+ /* data 28 */
+ if (query_0_5.has_bending_correction ||
+ query_0_5.has_large_object_suppression)
+ offset += 1;
+
+ /* data 29 30 31 */
+ if (query_0_5.has_query_9 && query_9.has_pen_hover_discrimination)
+ offset += 3;
+
+ /* data 32 */
+ if (query_0_5.has_query_12 &&
+ query_12.has_small_object_detection_tuning)
+ offset += 1;
+
+ /* data 33 34 */
+ if (query_0_5.has_query_27 && query_27.f11_query27_b0)
+ offset += 2;
+
+ /* data 35 */
+ if (query_0_5.has_query_12 && query_12.has_8bit_w)
+ offset += fingers_supported;
+
+ /* data 36 */
+ if (query_0_5.has_bending_correction)
+ offset += 1;
+
+ /* data 37 */
+ if (query_0_5.has_query_27 && query_27.has_data_37)
+ offset += 1;
+
+ /* data 38 */
+ if (query_0_5.has_query_27 && query_27.has_wakeup_gesture)
+ extra_data->data38_offset = offset;
+
+ return retval;
+}
+
+static int synaptics_rmi4_f12_set_enables(struct synaptics_rmi4_data *rmi4_data,
+ unsigned short ctrl28)
+{
+ int retval;
+ static unsigned short ctrl_28_address;
+
+ if (ctrl28)
+ ctrl_28_address = ctrl28;
+
+ retval = synaptics_rmi4_i2c_write(rmi4_data,
+ ctrl_28_address,
+ &rmi4_data->report_enable,
+ sizeof(rmi4_data->report_enable));
+ if (retval < 0)
+ return retval;
+
+ return retval;
+}
+
+ /**
+ * synaptics_rmi4_f12_init()
+ *
+ * Called by synaptics_rmi4_query_device().
+ *
+ * This function parses information from the Function 12 registers and
+ * determines the number of fingers supported, offset to the data1
+ * register, x and y data ranges, offset to the associated interrupt
+ * status register, interrupt bit mask, and allocates memory resources
+ * for finger data acquisition.
+ */
+static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler,
+ struct synaptics_rmi4_fn_desc *fd,
+ unsigned int intr_count)
+{
+ int retval;
+ unsigned char size_of_2d_data;
+ unsigned char size_of_query8;
+ unsigned char ctrl_8_offset;
+ unsigned char ctrl_20_offset;
+ unsigned char ctrl_23_offset;
+ unsigned char ctrl_27_offset;
+ unsigned char ctrl_28_offset;
+ unsigned char num_of_fingers;
+ struct synaptics_rmi4_f12_extra_data *extra_data;
+ struct synaptics_rmi4_f12_query_5 query_5;
+ struct synaptics_rmi4_f12_query_8 query_8;
+ struct synaptics_rmi4_f12_ctrl_8 ctrl_8;
+ struct synaptics_rmi4_f12_ctrl_23 ctrl_23;
+
+ fhandler->fn_number = fd->fn_number;
+ fhandler->num_of_data_sources = fd->intr_src_count;
+ fhandler->extra = kmalloc(sizeof(*extra_data), GFP_KERNEL);
+ if (!fhandler->extra) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for fhandler->extra\n",
+ __func__);
+ return -ENOMEM;
+ }
+ extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
+ size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data);
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.query_base + 5,
+ query_5.data,
+ sizeof(query_5.data));
+ if (retval < 0)
+ return retval;
+
+ ctrl_8_offset = query_5.ctrl0_is_present +
+ query_5.ctrl1_is_present +
+ query_5.ctrl2_is_present +
+ query_5.ctrl3_is_present +
+ query_5.ctrl4_is_present +
+ query_5.ctrl5_is_present +
+ query_5.ctrl6_is_present +
+ query_5.ctrl7_is_present;
+
+ ctrl_20_offset = ctrl_8_offset +
+ query_5.ctrl8_is_present +
+ query_5.ctrl9_is_present +
+ query_5.ctrl10_is_present +
+ query_5.ctrl11_is_present +
+ query_5.ctrl12_is_present +
+ query_5.ctrl13_is_present +
+ query_5.ctrl14_is_present +
+ query_5.ctrl15_is_present +
+ query_5.ctrl16_is_present +
+ query_5.ctrl17_is_present +
+ query_5.ctrl18_is_present +
+ query_5.ctrl19_is_present;
+
+ ctrl_23_offset = ctrl_20_offset +
+ query_5.ctrl20_is_present +
+ query_5.ctrl21_is_present +
+ query_5.ctrl22_is_present;
+ ctrl_27_offset = ctrl_23_offset +
+ query_5.ctrl23_is_present +
+ query_5.ctrl24_is_present +
+ query_5.ctrl25_is_present +
+ query_5.ctrl26_is_present;
+ ctrl_28_offset = ctrl_27_offset +
+ query_5.ctrl27_is_present;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.ctrl_base + ctrl_23_offset,
+ ctrl_23.data,
+ sizeof(ctrl_23.data));
+ if (retval < 0)
+ return retval;
+
+ /* Maximum number of fingers supported */
+ fhandler->num_of_data_points = min(ctrl_23.max_reported_objects,
+ (unsigned char)F12_FINGERS_TO_SUPPORT);
+
+ num_of_fingers = fhandler->num_of_data_points;
+ rmi4_data->num_of_fingers = num_of_fingers;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.query_base + 7,
+ &size_of_query8,
+ sizeof(size_of_query8));
+ if (retval < 0)
+ return retval;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.query_base + 8,
+ query_8.data,
+ size_of_query8);
+ if (retval < 0)
+ return retval;
+
+ /* Determine the presence of the Data0 register */
+ extra_data->data1_offset = query_8.data0_is_present;
+
+ if ((size_of_query8 >= 3) && (query_8.data15_is_present)) {
+ extra_data->data15_offset = query_8.data0_is_present +
+ query_8.data1_is_present +
+ query_8.data2_is_present +
+ query_8.data3_is_present +
+ query_8.data4_is_present +
+ query_8.data5_is_present +
+ query_8.data6_is_present +
+ query_8.data7_is_present +
+ query_8.data8_is_present +
+ query_8.data9_is_present +
+ query_8.data10_is_present +
+ query_8.data11_is_present +
+ query_8.data12_is_present +
+ query_8.data13_is_present +
+ query_8.data14_is_present;
+ extra_data->data15_size = (num_of_fingers + 7) / 8;
+ } else {
+ extra_data->data15_size = 0;
+ }
+
+ rmi4_data->report_enable = RPT_DEFAULT;
+#ifdef REPORT_2D_Z
+ rmi4_data->report_enable |= RPT_Z;
+#endif
+#ifdef REPORT_2D_W
+ rmi4_data->report_enable |= (RPT_WX | RPT_WY);
+#endif
+
+ retval = synaptics_rmi4_f12_set_enables(rmi4_data,
+ fhandler->full_addr.ctrl_base + ctrl_28_offset);
+ if (retval < 0)
+ return retval;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.ctrl_base + ctrl_8_offset,
+ ctrl_8.data,
+ sizeof(ctrl_8.data));
+ if (retval < 0)
+ return retval;
+
+ /* Maximum x and y */
+ rmi4_data->sensor_max_x = SENSOR_MAX_X;
+ rmi4_data->sensor_max_y = SENSOR_MAX_Y;
+
+ /* It's recommended to parse max_x and max_y from contrel register, but this does not match MTK's mtk-tpd.c */
+
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Function %02x max x = %d max y = %d\n",
+ __func__, fhandler->fn_number,
+ rmi4_data->sensor_max_x,
+ rmi4_data->sensor_max_y);
+
+ rmi4_data->num_of_rx = ctrl_8.num_of_rx;
+ rmi4_data->num_of_tx = ctrl_8.num_of_tx;
+ rmi4_data->max_touch_width = max(rmi4_data->num_of_rx,
+ rmi4_data->num_of_tx);
+ rmi4_data->f12_wakeup_gesture = query_5.ctrl27_is_present;
+ if (rmi4_data->f12_wakeup_gesture) {
+ extra_data->ctrl20_offset = ctrl_20_offset;
+ extra_data->data4_offset = query_8.data0_is_present +
+ query_8.data1_is_present +
+ query_8.data2_is_present +
+ query_8.data3_is_present;
+ extra_data->ctrl27_offset = ctrl_27_offset;
+ }
+
+ synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
+
+ /* Allocate memory for finger data storage space */
+ fhandler->data_size = num_of_fingers * size_of_2d_data;
+ fhandler->data = kmalloc(fhandler->data_size, GFP_KERNEL);
+ if (!fhandler->data) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for fhandler->data\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ return retval;
+}
+
+static int synaptics_rmi4_f1a_alloc_mem(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler)
+{
+ int retval;
+ struct synaptics_rmi4_f1a_handle *f1a;
+
+ f1a = kzalloc(sizeof(*f1a), GFP_KERNEL);
+ if (!f1a) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for function handle\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ fhandler->data = (void *)f1a;
+ fhandler->extra = NULL;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.query_base,
+ f1a->button_query.data,
+ sizeof(f1a->button_query.data));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read query registers\n",
+ __func__);
+ return retval;
+ }
+
+ f1a->max_count = f1a->button_query.max_button_count + 1;
+
+ f1a->button_control.txrx_map = kzalloc(f1a->max_count * 2, GFP_KERNEL);
+ if (!f1a->button_control.txrx_map) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for tx rx mapping\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ f1a->button_bitmask_size = (f1a->max_count + 7) / 8;
+
+ f1a->button_data_buffer = kcalloc(f1a->button_bitmask_size,
+ sizeof(*(f1a->button_data_buffer)), GFP_KERNEL);
+ if (!f1a->button_data_buffer) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for data buffer\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ f1a->button_map = kcalloc(f1a->max_count,
+ sizeof(*(f1a->button_map)), GFP_KERNEL);
+ if (!f1a->button_map) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc mem for button map\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int synaptics_rmi4_f1a_button_map(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler)
+{
+ int retval;
+ unsigned char ii;
+ unsigned char mapping_offset = 0;
+ struct synaptics_rmi4_f1a_handle *f1a = fhandler->data;
+
+ mapping_offset = f1a->button_query.has_general_control +
+ f1a->button_query.has_interrupt_enable +
+ f1a->button_query.has_multibutton_select;
+
+ if (f1a->button_query.has_tx_rx_map) {
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.ctrl_base + mapping_offset,
+ f1a->button_control.txrx_map,
+ sizeof(f1a->button_control.txrx_map));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read tx rx mapping\n",
+ __func__);
+ return retval;
+ }
+
+ rmi4_data->button_txrx_mapping = f1a->button_control.txrx_map;
+ }
+
+ if (cap_button_map.map) {
+ if (cap_button_map.nbuttons != f1a->max_count) {
+ f1a->valid_button_count = min(f1a->max_count,
+ cap_button_map.nbuttons);
+ } else {
+ f1a->valid_button_count = f1a->max_count;
+ }
+
+ for (ii = 0; ii < f1a->valid_button_count; ii++)
+ f1a->button_map[ii] = cap_button_map.map[ii];
+ }
+ return 0;
+}
+
+static void synaptics_rmi4_f1a_kfree(struct synaptics_rmi4_fn *fhandler)
+{
+ struct synaptics_rmi4_f1a_handle *f1a = fhandler->data;
+
+ if (f1a) {
+ kfree(f1a->button_control.txrx_map);
+ kfree(f1a->button_data_buffer);
+ kfree(f1a->button_map);
+ kfree(f1a);
+ fhandler->data = NULL;
+ }
+
+ return;
+}
+
+static int synaptics_rmi4_f1a_init(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler,
+ struct synaptics_rmi4_fn_desc *fd,
+ unsigned int intr_count)
+{
+ int retval;
+
+ fhandler->fn_number = fd->fn_number;
+ fhandler->num_of_data_sources = fd->intr_src_count;
+
+ synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
+
+ retval = synaptics_rmi4_f1a_alloc_mem(rmi4_data, fhandler);
+ if (retval < 0)
+ goto error_exit;
+
+ retval = synaptics_rmi4_f1a_button_map(rmi4_data, fhandler);
+ if (retval < 0)
+ goto error_exit;
+
+ rmi4_data->button_0d_enabled = 1;
+
+ return 0;
+
+error_exit:
+ synaptics_rmi4_f1a_kfree(fhandler);
+
+ return retval;
+}
+
+static void synaptics_rmi4_empty_fn_list(struct synaptics_rmi4_data *rmi4_data)
+{
+ struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_fn *fhandler_temp;
+ struct synaptics_rmi4_device_info *rmi;
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+ if (!list_empty(&rmi->support_fn_list)) {
+ list_for_each_entry_safe(fhandler,
+ fhandler_temp,
+ &rmi->support_fn_list,
+ link) {
+ if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) {
+ synaptics_rmi4_f1a_kfree(fhandler);
+ } else {
+ kfree(fhandler->extra);
+ kfree(fhandler->data);
+ }
+ list_del(&fhandler->link);
+ kfree(fhandler);
+ }
+ }
+ INIT_LIST_HEAD(&rmi->support_fn_list);
+
+ return;
+}
+
+static int synaptics_rmi4_check_status(struct synaptics_rmi4_data *rmi4_data,
+ bool *was_in_bl_mode)
+{
+ int retval;
+ int timeout = CHECK_STATUS_TIMEOUT_MS;
+ unsigned char command = 0x01;
+ unsigned char intr_status;
+ struct synaptics_rmi4_f01_device_status status;
+
+ /* Do a device reset first */
+ retval = synaptics_rmi4_i2c_write(rmi4_data,
+ rmi4_data->f01_cmd_base_addr,
+ &command,
+ sizeof(command));
+ if (retval < 0)
+ return retval;
+
+ msleep(DELAY_UI_READY);
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_data_base_addr,
+ status.data,
+ sizeof(status.data));
+ if (retval < 0)
+ return retval;
+
+ while (status.status_code == STATUS_CRC_IN_PROGRESS) {
+ if (timeout > 0)
+ msleep(20);
+ else
+ return -1;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_data_base_addr,
+ status.data,
+ sizeof(status.data));
+ if (retval < 0)
+ return retval;
+
+ timeout -= 20;
+ }
+
+ if (timeout != CHECK_STATUS_TIMEOUT_MS)
+ *was_in_bl_mode = true;
+
+ if (status.flash_prog == 1) {
+ rmi4_data->flash_prog_mode = true;
+ pr_notice("%s: In flash prog mode, status = 0x%02x\n",
+ __func__,
+ status.status_code);
+ } else {
+ rmi4_data->flash_prog_mode = false;
+ }
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_data_base_addr + 1,
+ &intr_status,
+ sizeof(intr_status));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read interrupt status\n",
+ __func__);
+ return retval;
+ }
+
+ return 0;
+}
+
+static void synaptics_rmi4_set_configured(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval;
+ unsigned char device_ctrl;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_ctrl_base_addr,
+ &device_ctrl,
+ sizeof(device_ctrl));
+ if (retval < 0) {
+ dev_err(&(rmi4_data->input_dev->dev),
+ "%s: Failed to set configured\n",
+ __func__);
+ return;
+ }
+
+ rmi4_data->no_sleep_setting = device_ctrl & NO_SLEEP_ON;
+ device_ctrl |= CONFIGURED;
+
+ retval = synaptics_rmi4_i2c_write(rmi4_data,
+ rmi4_data->f01_ctrl_base_addr,
+ &device_ctrl,
+ sizeof(device_ctrl));
+ if (retval < 0) {
+ dev_err(&(rmi4_data->input_dev->dev),
+ "%s: Failed to set configured\n",
+ __func__);
+ }
+
+ return;
+}
+
+static int synaptics_rmi4_alloc_fh(struct synaptics_rmi4_fn **fhandler,
+ struct synaptics_rmi4_fn_desc *rmi_fd, int page_number)
+{
+ *fhandler = kmalloc(sizeof(**fhandler), GFP_KERNEL);
+ if (!(*fhandler))
+ return -ENOMEM;
+
+ (*fhandler)->full_addr.data_base =
+ (rmi_fd->data_base_addr |
+ (page_number << 8));
+ (*fhandler)->full_addr.ctrl_base =
+ (rmi_fd->ctrl_base_addr |
+ (page_number << 8));
+ (*fhandler)->full_addr.cmd_base =
+ (rmi_fd->cmd_base_addr |
+ (page_number << 8));
+ (*fhandler)->full_addr.query_base =
+ (rmi_fd->query_base_addr |
+ (page_number << 8));
+
+ return 0;
+}
+
+ /**
+ * synaptics_rmi4_query_device()
+ *
+ * Called by synaptics_rmi4_probe().
+ *
+ * This function scans the page description table, records the offsets
+ * to the register types of Function $01, sets up the function handlers
+ * for Function $11 and Function $12, determines the number of interrupt
+ * sources from the sensor, adds valid Functions with data inputs to the
+ * Function linked list, parses information from the query registers of
+ * Function $01, and enables the interrupt sources from the valid Functions
+ * with data inputs.
+ */
+static int synaptics_rmi4_query_device(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval;
+ unsigned char ii;
+ unsigned char page_number;
+ unsigned char intr_count;
+ unsigned char f01_query[F01_STD_QUERY_LEN];
+ unsigned short pdt_entry_addr;
+ unsigned short intr_addr;
+ bool was_in_bl_mode;
+ struct synaptics_rmi4_fn_desc rmi_fd;
+ struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_device_info *rmi;
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+rescan_pdt:
+ was_in_bl_mode = false;
+ intr_count = 0;
+ INIT_LIST_HEAD(&rmi->support_fn_list);
+
+ /* Scan the page description tables of the pages to service */
+ for (page_number = 0; page_number < PAGES_TO_SERVICE; page_number++) {
+ for (pdt_entry_addr = PDT_START; pdt_entry_addr > PDT_END;
+ pdt_entry_addr -= PDT_ENTRY_SIZE) {
+ pdt_entry_addr |= (page_number << 8);
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ pdt_entry_addr,
+ (unsigned char *)&rmi_fd,
+ sizeof(rmi_fd));
+ if (retval < 0)
+ return retval;
+
+ fhandler = NULL;
+
+ if (rmi_fd.fn_number == 0) {
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Reached end of PDT\n",
+ __func__);
+ break;
+ }
+
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: F%02x found (page %d)\n",
+ __func__, rmi_fd.fn_number,
+ page_number);
+
+ switch (rmi_fd.fn_number) {
+ case SYNAPTICS_RMI4_F01:
+ if (rmi_fd.intr_src_count == 0)
+ break;
+
+ retval = synaptics_rmi4_alloc_fh(&fhandler,
+ &rmi_fd, page_number);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc for F%d\n",
+ __func__,
+ rmi_fd.fn_number);
+ return retval;
+ }
+
+ retval = synaptics_rmi4_f01_init(rmi4_data,
+ fhandler, &rmi_fd, intr_count);
+ if (retval < 0)
+ return retval;
+
+ retval = synaptics_rmi4_check_status(rmi4_data,
+ &was_in_bl_mode);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to check status\n",
+ __func__);
+ return retval;
+ }
+
+ if (was_in_bl_mode) {
+ kfree(fhandler);
+ fhandler = NULL;
+ goto rescan_pdt;
+ }
+
+ if (rmi4_data->flash_prog_mode)
+ goto flash_prog_mode;
+
+ break;
+ case SYNAPTICS_RMI4_F11:
+ if (rmi_fd.intr_src_count == 0)
+ break;
+
+ retval = synaptics_rmi4_alloc_fh(&fhandler,
+ &rmi_fd, page_number);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc for F%d\n",
+ __func__,
+ rmi_fd.fn_number);
+ return retval;
+ }
+
+ retval = synaptics_rmi4_f11_init(rmi4_data,
+ fhandler, &rmi_fd, intr_count);
+ if (retval < 0)
+ return retval;
+ break;
+ case SYNAPTICS_RMI4_F12:
+ if (rmi_fd.intr_src_count == 0)
+ break;
+
+ retval = synaptics_rmi4_alloc_fh(&fhandler,
+ &rmi_fd, page_number);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc for F%d\n",
+ __func__,
+ rmi_fd.fn_number);
+ return retval;
+ }
+
+ retval = synaptics_rmi4_f12_init(rmi4_data,
+ fhandler, &rmi_fd, intr_count);
+ if (retval < 0)
+ return retval;
+ break;
+ case SYNAPTICS_RMI4_F1A:
+ if (rmi_fd.intr_src_count == 0)
+ break;
+
+ retval = synaptics_rmi4_alloc_fh(&fhandler,
+ &rmi_fd, page_number);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc for F%d\n",
+ __func__,
+ rmi_fd.fn_number);
+ return retval;
+ }
+
+ retval = synaptics_rmi4_f1a_init(rmi4_data,
+ fhandler, &rmi_fd, intr_count);
+ if (retval < 0) {
+#ifdef IGNORE_FN_INIT_FAILURE
+ kfree(fhandler);
+ fhandler = NULL;
+#else
+ return retval;
+#endif
+ }
+ break;
+ }
+
+ /* Accumulate the interrupt count */
+ intr_count += (rmi_fd.intr_src_count & MASK_3BIT);
+
+ if (fhandler && rmi_fd.intr_src_count) {
+ list_add_tail(&fhandler->link,
+ &rmi->support_fn_list);
+ }
+ }
+ }
+
+flash_prog_mode:
+ rmi4_data->num_of_intr_regs = (intr_count + 7) / 8;
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Number of interrupt registers = %d\n",
+ __func__, rmi4_data->num_of_intr_regs);
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_query_base_addr,
+ f01_query,
+ sizeof(f01_query));
+ if (retval < 0)
+ return retval;
+
+ /* RMI Version 4.0 currently supported */
+ rmi->version_major = 4;
+ rmi->version_minor = 0;
+
+ rmi->manufacturer_id = f01_query[0];
+ rmi->product_props = f01_query[1];
+ rmi->product_info[0] = f01_query[2] & MASK_7BIT;
+ rmi->product_info[1] = f01_query[3] & MASK_7BIT;
+ rmi->date_code[0] = f01_query[4] & MASK_5BIT;
+ rmi->date_code[1] = f01_query[5] & MASK_4BIT;
+ rmi->date_code[2] = f01_query[6] & MASK_5BIT;
+ rmi->tester_id = ((f01_query[7] & MASK_7BIT) << 8) |
+ (f01_query[8] & MASK_7BIT);
+ rmi->serial_number = ((f01_query[9] & MASK_7BIT) << 8) |
+ (f01_query[10] & MASK_7BIT);
+ memcpy(rmi->product_id_string, &f01_query[11], 10);
+
+ if (rmi->manufacturer_id != 1) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Non-Synaptics device found, manufacturer ID = %d\n",
+ __func__, rmi->manufacturer_id);
+ }
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_query_base_addr + F01_BUID_ID_OFFSET,
+ rmi->build_id,
+ sizeof(rmi->build_id));
+ if (retval < 0)
+ return retval;
+
+ rmi4_data->firmware_id = (unsigned int)rmi->build_id[0] +
+ (unsigned int)rmi->build_id[1] * 0x100 +
+ (unsigned int)rmi->build_id[2] * 0x10000;
+
+ memset(rmi4_data->intr_mask, 0x00, sizeof(rmi4_data->intr_mask));
+
+ /*
+ * Map out the interrupt bit masks for the interrupt sources
+ * from the registered function handlers.
+ */
+ if (!list_empty(&rmi->support_fn_list)) {
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ if (fhandler->num_of_data_sources) {
+ rmi4_data->intr_mask[fhandler->intr_reg_num] |=
+ fhandler->intr_mask;
+ }
+ }
+ }
+
+ if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture)
+ rmi4_data->enable_wakeup_gesture = WAKEUP_GESTURE;
+ else
+ rmi4_data->enable_wakeup_gesture = false;
+
+ /* Enable the interrupt sources */
+ for (ii = 0; ii < rmi4_data->num_of_intr_regs; ii++) {
+ if (rmi4_data->intr_mask[ii] != 0x00) {
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Interrupt enable mask %d = 0x%02x\n",
+ __func__, ii, rmi4_data->intr_mask[ii]);
+ intr_addr = rmi4_data->f01_ctrl_base_addr + 1 + ii;
+ retval = synaptics_rmi4_i2c_write(rmi4_data,
+ intr_addr,
+ &(rmi4_data->intr_mask[ii]),
+ sizeof(rmi4_data->intr_mask[ii]));
+ if (retval < 0)
+ return retval;
+ }
+ }
+
+ synaptics_rmi4_set_configured(rmi4_data);
+
+ return 0;
+}
+
+static void synaptics_rmi4_set_params(struct synaptics_rmi4_data *rmi4_data)
+{
+ unsigned char ii;
+ struct synaptics_rmi4_f1a_handle *f1a;
+ struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_device_info *rmi;
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+ input_set_abs_params(rmi4_data->input_dev,
+ ABS_MT_POSITION_X, 0,
+ rmi4_data->sensor_max_x, 0, 0);
+ input_set_abs_params(rmi4_data->input_dev,
+ ABS_MT_POSITION_Y, 0,
+ rmi4_data->sensor_max_y, 0, 0);
+#ifdef REPORT_2D_W
+ input_set_abs_params(rmi4_data->input_dev,
+ ABS_MT_TOUCH_MAJOR, 0,
+ rmi4_data->max_touch_width, 0, 0);
+ input_set_abs_params(rmi4_data->input_dev,
+ ABS_MT_TOUCH_MINOR, 0,
+ rmi4_data->max_touch_width, 0, 0);
+#endif
+
+#ifdef TYPE_B_PROTOCOL
+ input_mt_init_slots(rmi4_data->input_dev,
+ rmi4_data->num_of_fingers, 0);
+#endif
+
+ f1a = NULL;
+ if (!list_empty(&rmi->support_fn_list)) {
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
+ f1a = fhandler->data;
+ }
+ }
+
+ if (f1a) {
+ for (ii = 0; ii < f1a->valid_button_count; ii++) {
+ set_bit(f1a->button_map[ii],
+ rmi4_data->input_dev->keybit);
+ input_set_capability(rmi4_data->input_dev,
+ EV_KEY, f1a->button_map[ii]);
+ }
+ }
+
+ if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture) {
+ set_bit(KEY_POWER, rmi4_data->input_dev->keybit);
+ input_set_capability(rmi4_data->input_dev, EV_KEY, KEY_POWER);
+ }
+ return;
+}
+
+static int synaptics_rmi4_set_input_dev(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval;
+
+ rmi4_data->input_dev = input_allocate_device();
+ if (rmi4_data->input_dev == NULL) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to allocate input device\n",
+ __func__);
+ retval = -ENOMEM;
+ goto err_input_device;
+ }
+
+ retval = synaptics_rmi4_query_device(rmi4_data);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to query device\n",
+ __func__);
+ goto err_query_device;
+ }
+
+ rmi4_data->input_dev->name = DRIVER_NAME;
+ rmi4_data->input_dev->phys = INPUT_PHYS_NAME;
+ rmi4_data->input_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
+ rmi4_data->input_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
+ rmi4_data->input_dev->id.bustype = BUS_I2C;
+ rmi4_data->input_dev->dev.parent = &rmi4_data->i2c_client->dev;
+ input_set_drvdata(rmi4_data->input_dev, rmi4_data);
+
+ set_bit(EV_SYN, rmi4_data->input_dev->evbit);
+ set_bit(EV_KEY, rmi4_data->input_dev->evbit);
+ set_bit(EV_ABS, rmi4_data->input_dev->evbit);
+ set_bit(BTN_TOUCH, rmi4_data->input_dev->keybit);
+ set_bit(BTN_TOOL_FINGER, rmi4_data->input_dev->keybit);
+#ifdef INPUT_PROP_DIRECT
+ set_bit(INPUT_PROP_DIRECT, rmi4_data->input_dev->propbit);
+#endif
+
+ synaptics_rmi4_set_params(rmi4_data);
+
+ retval = input_register_device(rmi4_data->input_dev);
+ if (retval) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to register input device\n",
+ __func__);
+ goto err_register_input;
+ }
+
+ return 0;
+
+err_register_input:
+err_query_device:
+ synaptics_rmi4_empty_fn_list(rmi4_data);
+ input_free_device(rmi4_data->input_dev);
+
+err_input_device:
+ return retval;
+}
+
+static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data)
+{
+ unsigned char ii;
+ mutex_lock(&rmi4_report_mutex);
+
+#ifdef TYPE_B_PROTOCOL
+ for (ii = 0; ii < rmi4_data->num_of_fingers; ii++) {
+ input_mt_slot(rmi4_data->input_dev, ii);
+ input_mt_report_slot_state(rmi4_data->input_dev,
+ MT_TOOL_FINGER, 0);
+ }
+#endif
+ input_report_key(rmi4_data->input_dev,
+ BTN_TOUCH, 0);
+ input_report_key(rmi4_data->input_dev,
+ BTN_TOOL_FINGER, 0);
+#ifndef TYPE_B_PROTOCOL
+ input_mt_sync(rmi4_data->input_dev);
+#endif
+ input_sync(rmi4_data->input_dev);
+ mutex_unlock(&rmi4_report_mutex);
+ rmi4_data->fingers_on_2d = false;
+
+ return 0;
+}
+
+static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval;
+ unsigned char ii;
+ unsigned short intr_addr;
+ struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_exp_fhandler *exp_fhandler;
+ struct synaptics_rmi4_device_info *rmi;
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+ mutex_lock(&(rmi4_data->rmi4_reset_mutex));
+
+ synaptics_rmi4_free_fingers(rmi4_data);
+
+ if (!list_empty(&rmi->support_fn_list)) {
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ if (fhandler->fn_number == SYNAPTICS_RMI4_F12) {
+ synaptics_rmi4_f12_set_enables(rmi4_data, 0);
+ break;
+ }
+ }
+ }
+
+ for (ii = 0; ii < rmi4_data->num_of_intr_regs; ii++) {
+ if (rmi4_data->intr_mask[ii] != 0x00) {
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Interrupt enable mask %d = 0x%02x\n",
+ __func__, ii, rmi4_data->intr_mask[ii]);
+ intr_addr = rmi4_data->f01_ctrl_base_addr + 1 + ii;
+ retval = synaptics_rmi4_i2c_write(rmi4_data,
+ intr_addr,
+ &(rmi4_data->intr_mask[ii]),
+ sizeof(rmi4_data->intr_mask[ii]));
+ if (retval < 0)
+ goto exit;
+ }
+ }
+
+ mutex_lock(&exp_data.mutex);
+ if (!list_empty(&exp_data.list)) {
+ list_for_each_entry(exp_fhandler, &exp_data.list, link)
+ if (exp_fhandler->exp_fn->reinit != NULL)
+ exp_fhandler->exp_fn->reinit(rmi4_data);
+ }
+ mutex_unlock(&exp_data.mutex);
+
+ synaptics_rmi4_set_configured(rmi4_data);
+
+ retval = 0;
+
+exit:
+ mutex_unlock(&(rmi4_data->rmi4_reset_mutex));
+ return retval;
+}
+
+static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data)
+{
+ int retval;
+ unsigned char command = 0x01;
+ struct synaptics_rmi4_exp_fhandler *exp_fhandler;
+
+ mutex_lock(&(rmi4_data->rmi4_reset_mutex));
+
+ rmi4_data->touch_stopped = true;
+
+ synaptics_rmi4_irq_enable(rmi4_data, false);
+
+ retval = synaptics_rmi4_i2c_write(rmi4_data,
+ rmi4_data->f01_cmd_base_addr,
+ &command,
+ sizeof(command));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to issue reset command, error = %d\n",
+ __func__, retval);
+ mutex_unlock(&(rmi4_data->rmi4_reset_mutex));
+ return retval;
+ }
+
+ msleep(DELAY_UI_READY);
+
+ synaptics_rmi4_free_fingers(rmi4_data);
+
+ synaptics_rmi4_empty_fn_list(rmi4_data);
+
+ retval = synaptics_rmi4_query_device(rmi4_data);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to query device\n",
+ __func__);
+ mutex_unlock(&(rmi4_data->rmi4_reset_mutex));
+ return retval;
+ }
+
+ synaptics_rmi4_set_params(rmi4_data);
+
+ mutex_lock(&exp_data.mutex);
+ if (!list_empty(&exp_data.list)) {
+ list_for_each_entry(exp_fhandler, &exp_data.list, link)
+ if (exp_fhandler->exp_fn->reset != NULL)
+ exp_fhandler->exp_fn->reset(rmi4_data);
+ }
+ mutex_unlock(&exp_data.mutex);
+
+ rmi4_data->touch_stopped = false;
+
+ synaptics_rmi4_irq_enable(rmi4_data, true);
+
+ mutex_unlock(&(rmi4_data->rmi4_reset_mutex));
+
+ return 0;
+}
+
+
+static void synaptics_rmi4_sleep_enable(struct synaptics_rmi4_data *rmi4_data,
+ bool enable)
+{
+ int retval;
+ unsigned char device_ctrl;
+ unsigned char no_sleep_setting = rmi4_data->no_sleep_setting;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ rmi4_data->f01_ctrl_base_addr,
+ &device_ctrl,
+ sizeof(device_ctrl));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to read device control\n",
+ __func__);
+ return;
+ }
+
+ device_ctrl = device_ctrl & ~MASK_3BIT;
+ if (enable)
+ device_ctrl = device_ctrl | NO_SLEEP_OFF | SENSOR_SLEEP;
+ else
+ device_ctrl = device_ctrl | no_sleep_setting | NORMAL_OPERATION;
+
+ retval = synaptics_rmi4_i2c_write(rmi4_data,
+ rmi4_data->f01_ctrl_base_addr,
+ &device_ctrl,
+ sizeof(device_ctrl));
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to write device control\n",
+ __func__);
+ return;
+ }
+
+ rmi4_data->sensor_sleep = enable;
+
+ return;
+}
+
+
+
+
+/**
+ * synaptics_rmi4_exp_fn_work()
+ *
+ * Called by the kernel at the scheduled time.
+ *
+ * This function is a work thread that checks for the insertion and
+ * removal of other expansion Function modules such as rmi_dev and calls
+ * their initialization and removal callback functions accordingly.
+ */
+static void synaptics_rmi4_exp_fn_work(struct work_struct *work)
+{
+ int retval;
+ struct synaptics_rmi4_exp_fhandler *exp_fhandler;
+ struct synaptics_rmi4_exp_fhandler *exp_fhandler_temp;
+ struct synaptics_rmi4_data *rmi4_data = exp_data.rmi4_data;
+
+ mutex_lock(&exp_data.mutex);
+ if (!list_empty(&exp_data.list)) {
+ list_for_each_entry_safe(exp_fhandler,
+ exp_fhandler_temp,
+ &exp_data.list,
+ link) {
+ if ((exp_fhandler->exp_fn->init != NULL) &&
+ exp_fhandler->insert) {
+ retval = exp_fhandler->exp_fn->init(rmi4_data);
+ if (retval < 0) {
+ list_del(&exp_fhandler->link);
+ kfree(exp_fhandler);
+ } else {
+ exp_fhandler->insert = false;
+ }
+ } else if ((exp_fhandler->exp_fn->remove != NULL) &&
+ exp_fhandler->remove) {
+ exp_fhandler->exp_fn->remove(rmi4_data);
+ list_del(&exp_fhandler->link);
+ kfree(exp_fhandler);
+ }
+ }
+ }
+ mutex_unlock(&exp_data.mutex);
+
+ return;
+}
+
+/**
+ * synaptics_rmi4_new_function()
+ *
+ * Called by other expansion Function modules in their module init and
+ * module exit functions.
+ *
+ * This function is used by other expansion Function modules such as
+ * rmi_dev to register themselves with the driver by providing their
+ * initialization and removal callback function pointers so that they
+ * can be inserted or removed dynamically at module init and exit times,
+ * respectively.
+ */
+void synaptics_rmi4_new_function(struct synaptics_rmi4_exp_fn *exp_fn,
+ bool insert)
+{
+ struct synaptics_rmi4_exp_fhandler *exp_fhandler;
+
+ if (!exp_data.initialized) {
+ mutex_init(&exp_data.mutex);
+ INIT_LIST_HEAD(&exp_data.list);
+ exp_data.initialized = true;
+ }
+
+ mutex_lock(&exp_data.mutex);
+ if (insert) {
+ exp_fhandler = kzalloc(sizeof(*exp_fhandler), GFP_KERNEL);
+ if (!exp_fhandler) {
+ pr_err("%s: Failed to alloc mem for expansion function\n",
+ __func__);
+ goto exit;
+ }
+ exp_fhandler->exp_fn = exp_fn;
+ exp_fhandler->insert = true;
+ exp_fhandler->remove = false;
+ list_add_tail(&exp_fhandler->link, &exp_data.list);
+ } else if (!list_empty(&exp_data.list)) {
+ list_for_each_entry(exp_fhandler, &exp_data.list, link) {
+ if (exp_fhandler->exp_fn->fn_type == exp_fn->fn_type) {
+ exp_fhandler->insert = false;
+ exp_fhandler->remove = true;
+ goto exit;
+ }
+ }
+ }
+
+exit:
+ mutex_unlock(&exp_data.mutex);
+
+ if (exp_data.queue_work) {
+ queue_delayed_work(exp_data.workqueue,
+ &exp_data.work,
+ msecs_to_jiffies(EXP_FN_WORK_DELAY_MS));
+ }
+
+ return;
+}
+EXPORT_SYMBOL(synaptics_rmi4_new_function);
+
+
+static ssize_t synaptics_rmi4_f34_configid_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "0x%x\n", rmi4_data->config_id);
+}
+
+
+
+static ssize_t synaptics_rmi4_f01_product_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ (rmi4_data->rmi4_mod_info.product_id_string));
+}
+
+
+static DEVICE_ATTR(tp_firmware_version, 0664, synaptics_rmi4_f34_configid_show, synaptics_rmi4_store_error);
+static DEVICE_ATTR(product_id, 0664, synaptics_rmi4_f01_product_id_show, synaptics_rmi4_store_error);
+
+static struct attribute *synaptics_rmi4_attrs[] = {
+ attrify(tp_firmware_version),
+ attrify(product_id),
+ NULL,
+};
+
+static struct attribute_group attr_group = {
+ .attrs = synaptics_rmi4_attrs,
+};
+ /**
+ * synaptics_rmi4_probe()
+ *
+ * Called by the kernel when an association with an I2C device of the
+ * same name is made (after doing i2c_add_driver).
+ *
+ * This function allocates and initializes the resources for the driver
+ * as an input driver, turns on the power to the sensor, queries the
+ * sensor for its supported Functions and characteristics, registers
+ * the driver to the input subsystem, sets up the interrupt, handles
+ * the registration of the early_suspend and late_resume functions,
+ * and creates a work queue for detection of other expansion Function
+ * modules.
+ */
+static int synaptics_rmi4_probe(struct i2c_client *client,
+ const struct i2c_device_id *dev_id)
+{
+ int retval, ret;
+ unsigned char attr_count;
+ struct synaptics_rmi4_data *rmi4_data;
+ struct device_node *np = client->dev.of_node;
+#if 0
+ int rst_gpio;
+#endif
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev,
+ "%s: SMBus byte data not supported\n",
+ __func__);
+ return -EIO;
+ }
+
+#ifdef USE_I2C_DMA
+ wDMABuf_va = (unsigned char *)dma_zalloc_coherent(&client->dev, WRITE_SIZE_LIMIT,
+ &wDMABuf_pa, GFP_KERNEL);
+ if (!wDMABuf_va) {
+ dev_err(&client->dev, "Allocate DMA I2C Buffer failed, exit\n");
+ return -ENOMEM;
+ }
+#endif
+
+ if (!np)
+ return -ENODEV;
+#if 0
+ rst_gpio = of_get_named_gpio(np, "rest-gpios", 0);
+ if (!gpio_is_valid(rst_gpio))
+ return -ENODEV;
+
+ ret = gpio_request(rst_gpio, "synaptics_rmi4_rest");
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "request rest gpio failed, cannot wake up controller: %d\n",
+ ret);
+ return ret;
+ }
+
+ gpio_direction_output(rst_gpio, 0);
+ gpio_set_value(rst_gpio, 1);
+ msleep(DELAY_BOOT_READY);
+ gpio_set_value(rst_gpio, 0);
+ msleep(DELAY_RESET_LOW);
+ gpio_set_value(rst_gpio, 1);
+ msleep(DELAY_UI_READY);
+#endif
+
+ rmi4_data = kzalloc(sizeof(*rmi4_data), GFP_KERNEL);
+ if (!rmi4_data) {
+ dev_err(&client->dev,
+ "%s: Failed to alloc mem for rmi4_data\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ rmi4_data->i2c_client = client;
+ rmi4_data->current_page = MASK_8BIT;
+ rmi4_data->touch_stopped = false;
+ rmi4_data->sensor_sleep = false;
+ rmi4_data->irq_enabled = false;
+ rmi4_data->fingers_on_2d = false;
+
+ rmi4_data->i2c_read = synaptics_rmi4_i2c_read;
+ rmi4_data->i2c_write = synaptics_rmi4_i2c_write;
+ rmi4_data->irq_enable = synaptics_rmi4_irq_enable;
+ rmi4_data->reset_device = synaptics_rmi4_reset_device;
+ rmi4_data->sleep_enable = synaptics_rmi4_sleep_enable;
+
+ rmi4_data->i2c_addr = client->addr;
+ rmi4_data->diagonal_rotation = of_property_read_bool(np,
+ "synaptics,diagonal-rotation");
+
+ mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));
+ mutex_init(&(rmi4_data->rmi4_reset_mutex));
+ mutex_init(&(rmi4_data->rmi4_exp_init_mutex));
+
+ i2c_set_clientdata(client, rmi4_data);
+ retval = synaptics_rmi4_set_input_dev(rmi4_data);
+ if (retval < 0) {
+ dev_err(&client->dev,
+ "%s: Failed to set up input device\n",
+ __func__);
+ goto err_set_input_dev;
+ }
+
+ thread = kthread_run(touch_event_handler, rmi4_data, "synaptics_dsx");
+ if (IS_ERR(thread)) {
+ retval = PTR_ERR(thread);
+ pr_err(" %s: failed to create kernel thread: %d\n", __func__, retval);
+ }
+
+ touch_irq = client->irq;
+ ret = devm_request_irq(&client->dev, touch_irq, (irq_handler_t) tpd_eint_handler,
+ IRQF_TRIGGER_LOW, "synaptics_rmi4_touch", NULL);
+
+ disable_irq_nosync(touch_irq);
+ retval = synaptics_rmi4_irq_enable(rmi4_data, true);
+ if (retval < 0) {
+ dev_err(&client->dev,
+ "%s: Failed to register attention interrupt\n",
+ __func__);
+ goto err_enable_irq;
+ }
+
+ if (!exp_data.initialized) {
+ mutex_init(&exp_data.mutex);
+ INIT_LIST_HEAD(&exp_data.list);
+ exp_data.initialized = true;
+ }
+
+
+ exp_data.workqueue = create_singlethread_workqueue("dsx_exp_workqueue");
+ INIT_DELAYED_WORK(&exp_data.work, synaptics_rmi4_exp_fn_work);
+ exp_data.rmi4_data = rmi4_data;
+ exp_data.queue_work = true;
+ queue_delayed_work(exp_data.workqueue,
+ &exp_data.work,
+ msecs_to_jiffies(EXP_FN_WORK_DELAY_MS));
+
+ for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+ retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
+ &attrs[attr_count].attr);
+ if (retval < 0) {
+ dev_err(&client->dev,
+ "%s: Failed to create sysfs attributes\n",
+ __func__);
+ goto err_sysfs;
+ }
+ }
+
+ retval = sysfs_create_group(&client->dev.kobj, &attr_group);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to create sysfs attributes\n",
+ __func__);
+ goto err_sysfs;
+ }
+
+ g_dev = &rmi4_data->input_dev->dev;
+
+ return retval;
+
+err_sysfs:
+ sysfs_remove_group(&client->dev.kobj, &attr_group);
+ for (attr_count--; attr_count >= 0; attr_count--) {
+ sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
+ &attrs[attr_count].attr);
+ }
+
+ cancel_delayed_work_sync(&exp_data.work);
+ flush_workqueue(exp_data.workqueue);
+ destroy_workqueue(exp_data.workqueue);
+
+ synaptics_rmi4_irq_enable(rmi4_data, false);
+
+err_enable_irq:
+
+ synaptics_rmi4_empty_fn_list(rmi4_data);
+ input_unregister_device(rmi4_data->input_dev);
+ rmi4_data->input_dev = NULL;
+
+err_set_input_dev:
+ kfree(rmi4_data);
+
+ return retval;
+}
+
+ /**
+ * synaptics_rmi4_remove()
+ *
+ * Called by the kernel when the association with an I2C device of the
+ * same name is broken (when the driver is unloaded).
+ *
+ * This function terminates the work queue, stops sensor data acquisition,
+ * frees the interrupt, unregisters the driver from the input subsystem,
+ * turns off the power to the sensor, and frees other allocated resources.
+ */
+static int synaptics_rmi4_remove(struct i2c_client *client)
+{
+ unsigned char attr_count;
+ struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client);
+
+ for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
+ sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
+ &attrs[attr_count].attr);
+ }
+
+ cancel_delayed_work_sync(&exp_data.work);
+ flush_workqueue(exp_data.workqueue);
+ destroy_workqueue(exp_data.workqueue);
+
+ synaptics_rmi4_irq_enable(rmi4_data, false);
+
+ synaptics_rmi4_empty_fn_list(rmi4_data);
+ input_unregister_device(rmi4_data->input_dev);
+ rmi4_data->input_dev = NULL;
+
+#ifdef USE_I2C_DMA
+ if (wDMABuf_va)
+ dma_free_coherent(&client->dev, WRITE_SIZE_LIMIT, wDMABuf_va, wDMABuf_pa);
+#endif
+
+ kfree(rmi4_data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static void synaptics_rmi4_f11_wg(struct synaptics_rmi4_data *rmi4_data,
+ bool enable)
+{
+ int retval;
+ unsigned char reporting_control;
+ struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_device_info *rmi;
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ if (fhandler->fn_number == SYNAPTICS_RMI4_F11)
+ break;
+ }
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.ctrl_base,
+ &reporting_control,
+ sizeof(reporting_control));
+ if (retval < 0) {
+ dev_err(&(rmi4_data->input_dev->dev),
+ "%s: Failed to change reporting mode\n",
+ __func__);
+ return;
+ }
+
+ reporting_control = (reporting_control & ~MASK_3BIT);
+ if (enable)
+ reporting_control |= F11_WAKEUP_GESTURE_MODE;
+ else
+ reporting_control |= F11_CONTINUOUS_MODE;
+
+ retval = synaptics_rmi4_i2c_write(rmi4_data,
+ fhandler->full_addr.ctrl_base,
+ &reporting_control,
+ sizeof(reporting_control));
+ if (retval < 0) {
+ dev_err(&(rmi4_data->input_dev->dev),
+ "%s: Failed to change reporting mode\n",
+ __func__);
+ return;
+ }
+
+ return;
+}
+
+static void synaptics_rmi4_f12_wg(struct synaptics_rmi4_data *rmi4_data,
+ bool enable)
+{
+ int retval;
+ unsigned char offset;
+ unsigned char reporting_control[3];
+ struct synaptics_rmi4_f12_extra_data *extra_data;
+ struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_device_info *rmi;
+
+ rmi = &(rmi4_data->rmi4_mod_info);
+
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ if (fhandler->fn_number == SYNAPTICS_RMI4_F12)
+ break;
+ }
+
+ extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
+ offset = extra_data->ctrl20_offset;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.ctrl_base + offset,
+ reporting_control,
+ sizeof(reporting_control));
+ if (retval < 0) {
+ dev_err(&(rmi4_data->input_dev->dev),
+ "%s: Failed to change reporting mode\n",
+ __func__);
+ return;
+ }
+
+ if (enable)
+ reporting_control[2] = F12_WAKEUP_GESTURE_MODE;
+ else
+ reporting_control[2] = F12_CONTINUOUS_MODE;
+
+ retval = synaptics_rmi4_i2c_write(rmi4_data,
+ fhandler->full_addr.ctrl_base + offset,
+ reporting_control,
+ sizeof(reporting_control));
+ if (retval < 0) {
+ dev_err(&(rmi4_data->input_dev->dev),
+ "%s: Failed to change reporting mode\n",
+ __func__);
+ return;
+ }
+
+ return;
+}
+
+static void synaptics_rmi4_wakeup_gesture(struct synaptics_rmi4_data *rmi4_data,
+ bool enable)
+{
+ if (rmi4_data->f11_wakeup_gesture)
+ synaptics_rmi4_f11_wg(rmi4_data, enable);
+ else if (rmi4_data->f12_wakeup_gesture)
+ synaptics_rmi4_f12_wg(rmi4_data, enable);
+
+ return;
+}
+
+ /**
+ * synaptics_rmi4_suspend()
+ *
+ * Called by the kernel during the suspend phase when the system
+ * enters suspend.
+ *
+ * This function stops finger data acquisition and puts the sensor to
+ * sleep (if not already done so during the early suspend phase),
+ * disables the interrupt, and turns off the power to the sensor.
+ */
+static int __maybe_unused synaptics_rmi4_suspend(struct device *dev)
+{
+ struct synaptics_rmi4_exp_fhandler *exp_fhandler;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(g_dev);
+
+ if (rmi4_data->staying_awake)
+ return 0;
+
+ if (rmi4_data->enable_wakeup_gesture) {
+ synaptics_rmi4_wakeup_gesture(rmi4_data, true);
+ goto exit;
+ }
+
+ if (!rmi4_data->sensor_sleep) {
+ rmi4_data->touch_stopped = true;
+ synaptics_rmi4_irq_enable(rmi4_data, false);
+ synaptics_rmi4_sleep_enable(rmi4_data, true);
+ synaptics_rmi4_free_fingers(rmi4_data);
+ }
+
+ tpd_halt = 1;
+
+exit:
+ mutex_lock(&exp_data.mutex);
+ if (!list_empty(&exp_data.list)) {
+ list_for_each_entry(exp_fhandler, &exp_data.list, link)
+ if (exp_fhandler->exp_fn->suspend != NULL)
+ exp_fhandler->exp_fn->suspend(rmi4_data);
+ }
+ mutex_unlock(&exp_data.mutex);
+
+
+ rmi4_data->sensor_sleep = true;
+
+ return 0;
+}
+
+ /**
+ * synaptics_rmi4_resume()
+ *
+ * Called by the kernel during the resume phase when the system
+ * wakes up from suspend.
+ *
+ * This function turns on the power to the sensor, wakes the sensor
+ * from sleep, enables the interrupt, and starts finger data
+ * acquisition.
+ */
+static int __maybe_unused synaptics_rmi4_resume(struct device *dev)
+{
+ int retval;
+ struct synaptics_rmi4_exp_fhandler *exp_fhandler;
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(g_dev);
+
+ if (rmi4_data->staying_awake)
+ return 0;
+
+ if (rmi4_data->enable_wakeup_gesture) {
+ synaptics_rmi4_wakeup_gesture(rmi4_data, false);
+ goto exit;
+ }
+
+ synaptics_rmi4_sleep_enable(rmi4_data, false);
+ synaptics_rmi4_irq_enable(rmi4_data, true);
+ retval = synaptics_rmi4_reinit_device(rmi4_data);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to reinit device\n",
+ __func__);
+ return 0;
+ }
+exit:
+ mutex_lock(&exp_data.mutex);
+ if (!list_empty(&exp_data.list)) {
+ list_for_each_entry(exp_fhandler, &exp_data.list, link)
+ if (exp_fhandler->exp_fn->resume != NULL)
+ exp_fhandler->exp_fn->resume(rmi4_data);
+ }
+ mutex_unlock(&exp_data.mutex);
+
+
+ rmi4_data->sensor_sleep = false;
+ rmi4_data->touch_stopped = false;
+ tpd_halt = 0;
+
+ return 0;
+}
+
+#endif
+
+static const struct i2c_device_id synaptics_rmi4_id_table[] = {
+ {"synaptics_dsx", 0},
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table);
+
+static SIMPLE_DEV_PM_OPS(synaptics_rmi4_pm_ops, synaptics_rmi4_suspend, synaptics_rmi4_resume);
+
+
+static const struct of_device_id synaptics_rmi4_dt_ids[] = {
+ { .compatible = "synaptics_dsx" },
+ { /* sentinel */},
+};
+
+static struct i2c_driver synaptics_rmi4_driver = {
+ .driver = {
+ .name = "synaptics_dsx",
+ .pm = &synaptics_rmi4_pm_ops,
+ .of_match_table = synaptics_rmi4_dt_ids,
+ },
+ .id_table = synaptics_rmi4_id_table,
+ .probe = synaptics_rmi4_probe,
+ .remove = synaptics_rmi4_remove,
+};
+
+module_i2c_driver(synaptics_rmi4_driver);
+
+MODULE_AUTHOR("Synaptics, Inc.");
+MODULE_DESCRIPTION("Synaptics DSX I2C Touch Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.h b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.h
new file mode 100644
index 000000000000..12d7bf4ca225
--- /dev/null
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_i2c.h
@@ -0,0 +1,421 @@
+/*
+ * Synaptics DSX touchscreen driver
+ *
+ * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
+ *
+ * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
+ * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
+ * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
+ * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
+ * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
+ * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
+ * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
+ * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
+ * DOLLARS.
+ */
+#ifndef _SYNAPTICS_DSX_RMI4_H_
+#define _SYNAPTICS_DSX_RMI4_H_
+
+#define SYNAPTICS_DS4 (1 << 0)
+#define SYNAPTICS_DS5 (1 << 1)
+#define SYNAPTICS_DSX_DRIVER_PRODUCT (SYNAPTICS_DS4 | SYNAPTICS_DS5)
+#define SYNAPTICS_DSX_DRIVER_VERSION 0x2000
+#define SYNAPTICS_MTK_DRIVER_VERSION 0x6043
+
+#include <linux/version.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#ifdef CONFIG_OF
+#define CONFIG_OF_TOUCH
+#endif
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))
+#define KERNEL_ABOVE_2_6_38
+#endif
+
+#ifdef KERNEL_ABOVE_2_6_38
+#define sstrtoul(...) kstrtoul(__VA_ARGS__)
+#else
+#define sstrtoul(...) strict_strtoul(__VA_ARGS__)
+#endif
+
+#define WRITE_SIZE_LIMIT 1024
+
+extern unsigned char g_log_enable;
+#define TP_DEBUG(fmt, arg...) do {\
+ if (g_log_enable)\
+ printk("%s %d " fmt, __func__, __LINE__, ##arg);\
+ } while (0)
+#define PDT_PROPS (0X00EF)
+#define PDT_START (0x00E9)
+#define PDT_END (0x00D0)
+#define PDT_ENTRY_SIZE (0x0006)
+#define PAGES_TO_SERVICE (10)
+#define PAGE_SELECT_LEN (2)
+#define ADDRESS_WORD_LEN (2)
+
+#define SYNAPTICS_RMI4_F01 (0x01)
+#define SYNAPTICS_RMI4_F11 (0x11)
+#define SYNAPTICS_RMI4_F12 (0x12)
+#define SYNAPTICS_RMI4_F1A (0x1a)
+#define SYNAPTICS_RMI4_F34 (0x34)
+#define SYNAPTICS_RMI4_F35 (0x35)
+#define SYNAPTICS_RMI4_F38 (0x38)
+#define SYNAPTICS_RMI4_F51 (0x51)
+#define SYNAPTICS_RMI4_F54 (0x54)
+#define SYNAPTICS_RMI4_F55 (0x55)
+#define SYNAPTICS_RMI4_FDB (0xdb)
+
+#define SYNAPTICS_RMI4_DATE_CODE_SIZE 3
+#define PRODUCT_INFO_SIZE 2
+#define PRODUCT_ID_SIZE 10
+#define BUILD_ID_SIZE 3
+
+#define F12_FINGERS_TO_SUPPORT 10
+#define F12_NO_OBJECT_STATUS 0x00
+#define F12_FINGER_STATUS 0x01
+#define F12_STYLUS_STATUS 0x02
+#define F12_PALM_STATUS 0x03
+#define F12_HOVERING_FINGER_STATUS 0x05
+#define F12_GLOVED_FINGER_STATUS 0x06
+
+#define F12_GESTURE_DETECTION_LEN 5
+
+
+#define MAX_NUMBER_OF_BUTTONS 4
+#define MAX_INTR_REGISTERS 4
+
+#define MASK_16BIT 0xFFFF
+#define MASK_8BIT 0xFF
+#define MASK_7BIT 0x7F
+#define MASK_6BIT 0x3F
+#define MASK_5BIT 0x1F
+#define MASK_4BIT 0x0F
+#define MASK_3BIT 0x07
+#define MASK_2BIT 0x03
+#define MASK_1BIT 0x01
+
+enum exp_fn {
+ RMI_DEV = 0,
+ RMI_F54,
+ RMI_FW_UPDATER,
+ RMI_PROXIMITY,
+ RMI_ACTIVE_PEN,
+ RMI_GESTURE,
+ RMI_LAST,
+};
+
+/*
+ * struct synaptics_rmi4_fn_desc - function descriptor fields in PDT entry
+ * @query_base_addr: base address for query registers
+ * @cmd_base_addr: base address for command registers
+ * @ctrl_base_addr: base address for control registers
+ * @data_base_addr: base address for data registers
+ * @intr_src_count: number of interrupt sources
+ * @fn_version: version of function
+ * @fn_number: function number
+ */
+struct synaptics_rmi4_fn_desc {
+ union {
+ struct {
+ unsigned char query_base_addr;
+ unsigned char cmd_base_addr;
+ unsigned char ctrl_base_addr;
+ unsigned char data_base_addr;
+ unsigned char intr_src_count:3;
+ unsigned char reserved_1:2;
+ unsigned char fn_version:2;
+ unsigned char reserved_2:1;
+ unsigned char fn_number;
+ } __packed;
+ unsigned char data[6];
+ };
+};
+
+/*
+ * synaptics_rmi4_fn_full_addr - full 16-bit base addresses
+ * @query_base: 16-bit base address for query registers
+ * @cmd_base: 16-bit base address for command registers
+ * @ctrl_base: 16-bit base address for control registers
+ * @data_base: 16-bit base address for data registers
+ */
+struct synaptics_rmi4_fn_full_addr {
+ unsigned short query_base;
+ unsigned short cmd_base;
+ unsigned short ctrl_base;
+ unsigned short data_base;
+};
+
+/*
+ * struct synaptics_rmi4_f11_extra_data - extra data of F$11
+ * @data38_offset: offset to F11_2D_DATA38 register
+ */
+struct synaptics_rmi4_f11_extra_data {
+ unsigned char data38_offset;
+};
+
+/*
+ * struct synaptics_rmi4_f12_extra_data - extra data of F$12
+ * @data1_offset: offset to F12_2D_DATA01 register
+ * @data4_offset: offset to F12_2D_DATA04 register
+ * @data15_offset: offset to F12_2D_DATA15 register
+ * @data15_size: size of F12_2D_DATA15 register
+ * @data15_data: buffer for reading F12_2D_DATA15 register
+ * @ctrl20_offset: offset to F12_2D_CTRL20 register
+ */
+struct synaptics_rmi4_f12_extra_data {
+ unsigned char data1_offset;
+ unsigned char data4_offset;
+ unsigned char data15_offset;
+ unsigned char data15_size;
+ unsigned char data15_data[(F12_FINGERS_TO_SUPPORT + 7) / 8];
+ unsigned char ctrl20_offset;
+ unsigned char ctrl27_offset;
+};
+
+/*
+ * struct synaptics_rmi4_fn - RMI function handler
+ * @fn_number: function number
+ * @num_of_data_sources: number of data sources
+ * @num_of_data_points: maximum number of fingers supported
+ * @intr_reg_num: index to associated interrupt register
+ * @intr_mask: interrupt mask
+ * @full_addr: full 16-bit base addresses of function registers
+ * @link: linked list for function handlers
+ * @data_size: size of private data
+ * @data: pointer to private data
+ * @extra: pointer to extra data
+ */
+struct synaptics_rmi4_fn {
+ unsigned char fn_number;
+ unsigned char num_of_data_sources;
+ unsigned char num_of_data_points;
+ unsigned char intr_reg_num;
+ unsigned char intr_mask;
+ struct synaptics_rmi4_fn_full_addr full_addr;
+ struct list_head link;
+ int data_size;
+ void *data;
+ void *extra;
+};
+
+/*
+ * struct synaptics_rmi4_device_info - device information
+ * @version_major: RMI protocol major version number
+ * @version_minor: RMI protocol minor version number
+ * @manufacturer_id: manufacturer ID
+ * @product_props: product properties
+ * @product_info: product information
+ * @product_id_string: product ID
+ * @build_id: firmware build ID
+ * @support_fn_list: linked list for function handlers
+ */
+struct synaptics_rmi4_device_info {
+ unsigned int version_major;
+ unsigned int version_minor;
+ unsigned char manufacturer_id;
+ unsigned char product_props;
+ unsigned char product_info[PRODUCT_INFO_SIZE];
+ unsigned char date_code[SYNAPTICS_RMI4_DATE_CODE_SIZE];
+ unsigned short tester_id;
+ unsigned short serial_number;
+ unsigned char product_id_string[PRODUCT_ID_SIZE + 1];
+ unsigned char build_id[BUILD_ID_SIZE];
+ struct list_head support_fn_list;
+};
+
+/*
+ * struct synaptics_rmi4_data - rmi4 device instance data
+ * @i2c_client: pointer to associated i2c client
+ * @input_dev: pointer to associated input device
+ * @board: constant pointer to platform data
+ * @rmi4_mod_info: device information
+ * @regulator: pointer to associated regulator
+ * @rmi4_io_ctrl_mutex: mutex for i2c i/o control
+ * @early_suspend: instance to support early suspend power management
+ * @current_page: current page in sensor to access
+ * @button_0d_enabled: flag for 0d button support
+ * @full_pm_cycle: flag for full power management cycle in early suspend stage
+ * @num_of_intr_regs: number of interrupt registers
+ * @f01_query_base_addr: query base address for f01
+ * @f01_cmd_base_addr: command base address for f01
+ * @f01_ctrl_base_addr: control base address for f01
+ * @f01_data_base_addr: data base address for f01
+ * @irq: attention interrupt
+ * @sensor_max_x: sensor maximum x value
+ * @sensor_max_y: sensor maximum y value
+ * @irq_enabled: flag for indicating interrupt enable status
+ * @fingers_on_2d: flag to indicate presence of fingers in 2d area
+ * @sensor_sleep: flag to indicate sleep state of sensor
+ * @wait: wait queue for touch data polling in interrupt thread
+ * @i2c_read: pointer to i2c read function
+ * @i2c_write: pointer to i2c write function
+ * @irq_enable: pointer to irq enable function
+ */
+struct synaptics_rmi4_data {
+ struct i2c_client *i2c_client;
+ struct input_dev *input_dev;
+ const struct synaptics_dsx_platform_data *board;
+ struct synaptics_rmi4_device_info rmi4_mod_info;
+ struct regulator *regulator;
+ struct mutex rmi4_reset_mutex;
+ struct mutex rmi4_io_ctrl_mutex;
+ struct mutex rmi4_exp_init_mutex;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
+ unsigned char i2c_addr;
+ unsigned char current_page;
+ unsigned char button_0d_enabled;
+ unsigned char full_pm_cycle;
+ unsigned char num_of_rx;
+ unsigned char num_of_tx;
+ unsigned char num_of_fingers;
+ unsigned char max_touch_width;
+ unsigned char report_enable;
+ unsigned char no_sleep_setting;
+ unsigned char intr_mask[MAX_INTR_REGISTERS];
+ unsigned char *button_txrx_mapping;
+ unsigned short num_of_intr_regs;
+ unsigned short f01_query_base_addr;
+ unsigned short f01_cmd_base_addr;
+ unsigned short f01_ctrl_base_addr;
+ unsigned short f01_data_base_addr;
+ unsigned int firmware_id;
+ unsigned int config_id;
+ int irq;
+ int sensor_max_x;
+ int sensor_max_y;
+ bool diagonal_rotation;
+ bool flash_prog_mode;
+ bool irq_enabled;
+ bool touch_stopped;
+ bool fingers_on_2d;
+ bool sensor_sleep;
+ bool stay_awake;
+ bool f11_wakeup_gesture;
+ bool f12_wakeup_gesture;
+ bool enable_wakeup_gesture;
+ bool staying_awake;
+ bool ext_afe_button;
+ unsigned char gesture_detection[F12_GESTURE_DETECTION_LEN];
+ int (*i2c_read)(struct synaptics_rmi4_data *pdata, unsigned short addr,
+ unsigned char *data, unsigned short length);
+ int (*i2c_write)(struct synaptics_rmi4_data *pdata, unsigned short addr,
+ unsigned char *data, unsigned short length);
+ int (*irq_enable)(struct synaptics_rmi4_data *rmi4_data, bool enable);
+ int (*reset_device)(struct synaptics_rmi4_data *rmi4_data);
+ void (*sleep_enable)(struct synaptics_rmi4_data *rmi4_data,
+ bool enable);
+};
+
+struct synaptics_rmi4_exp_fn {
+ enum exp_fn fn_type;
+ int (*init)(struct synaptics_rmi4_data *rmi4_data);
+ void (*remove)(struct synaptics_rmi4_data *rmi4_data);
+ void (*reset)(struct synaptics_rmi4_data *rmi4_data);
+ void (*reinit)(struct synaptics_rmi4_data *rmi4_data);
+ void (*early_suspend)(struct synaptics_rmi4_data *rmi4_data);
+ void (*suspend)(struct synaptics_rmi4_data *rmi4_data);
+ void (*resume)(struct synaptics_rmi4_data *rmi4_data);
+ void (*late_resume)(struct synaptics_rmi4_data *rmi4_data);
+ void (*attn)(struct synaptics_rmi4_data *rmi4_data,
+ unsigned char intr_mask);
+};
+
+struct synaptics_rmi4_access_ptr {
+ int (*read)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
+ unsigned char *data, unsigned short length);
+ int (*write)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
+ unsigned char *data, unsigned short length);
+ int (*enable)(struct synaptics_rmi4_data *rmi4_data, bool enable);
+};
+
+static inline int synaptics_rmi4_reg_read(
+ struct synaptics_rmi4_data *rmi4_data,
+ unsigned short addr,
+ unsigned char *data,
+ unsigned short len)
+{
+ return rmi4_data->i2c_read(rmi4_data, addr, data, len);
+}
+
+static inline int synaptics_rmi4_reg_write(
+ struct synaptics_rmi4_data *rmi4_data,
+ unsigned short addr,
+ unsigned char *data,
+ unsigned short len)
+{
+ return rmi4_data->i2c_write(rmi4_data, addr, data, len);
+}
+
+
+
+void synaptics_rmi4_new_function(struct synaptics_rmi4_exp_fn *exp_fn_module,
+ bool insert);
+
+int synaptics_fw_updater(const unsigned char *fw_data);
+
+static inline ssize_t synaptics_rmi4_show_error(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ dev_warn(dev, "%s Attempted to read from write-only attribute %s\n",
+ __func__, attr->attr.name);
+ return -EPERM;
+}
+
+static inline ssize_t synaptics_rmi4_store_error(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ dev_warn(dev, "%s Attempted to write to read-only attribute %s\n",
+ __func__, attr->attr.name);
+ return -EPERM;
+}
+
+static inline int secure_memcpy(unsigned char *dest, unsigned int dest_size,
+ const unsigned char *src, unsigned int src_size,
+ unsigned int count)
+{
+ if (dest == NULL || src == NULL)
+ return -EINVAL;
+
+ if (count > dest_size || count > src_size)
+ return -EINVAL;
+
+ memcpy((void *)dest, (const void *)src, count);
+
+ return 0;
+}
+
+static inline void batohs(unsigned short *dest, unsigned char *src)
+{
+ *dest = src[1] * 0x100 + src[0];
+}
+
+static inline void hstoba(unsigned char *dest, unsigned short src)
+{
+ dest[0] = src % 0x100;
+ dest[1] = src / 0x100;
+}
+
+#endif
diff --git a/drivers/input/touchscreen/vtl/Makefile b/drivers/input/touchscreen/vtl/Makefile
new file mode 100644
index 000000000000..2ee7f7aefe43
--- /dev/null
+++ b/drivers/input/touchscreen/vtl/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the VTL touchscreen driver.
+#
+
+obj-y += vtl_ts.o
diff --git a/drivers/input/touchscreen/vtl/vtl_ts.c b/drivers/input/touchscreen/vtl/vtl_ts.c
new file mode 100644
index 000000000000..f7bef9e81158
--- /dev/null
+++ b/drivers/input/touchscreen/vtl/vtl_ts.c
@@ -0,0 +1,496 @@
+/*
+ * VTL CTP driver
+ *
+ * Copyright (C) 2013 VTL Corporation
+ * Copyright (C) 2016 Freescale Semiconductor, Inc
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/pm_qos.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define FORCE_SINGLE_EVENT 1
+
+#include "vtl_ts.h"
+
+#define MIN_X 0x00
+#define MIN_Y 0x00
+#define MAX_X 1023
+#define MAX_Y 767
+#define MAX_AREA 0xff
+#define MAX_FINGERS 2
+
+
+/* Global or static variables */
+struct ts_driver g_driver;
+
+static struct ts_info g_ts = {
+ .driver = &g_driver,
+};
+static struct ts_info *pg_ts = &g_ts;
+
+static struct i2c_device_id vtl_ts_id[] = {
+ { DRIVER_NAME, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, vtl_ts_id);
+
+
+static int vtl_ts_config(struct ts_info *ts)
+{
+ struct device *dev;
+
+ DEBUG();
+
+ dev = &ts->driver->client->dev;
+
+ /* ts config */
+ ts->config_info.touch_point_number = TOUCH_POINT_NUM;
+
+ pr_info("Configuring vtl\n");
+ ts->config_info.screen_max_x = SCREEN_MAX_X;
+ ts->config_info.screen_max_y = SCREEN_MAX_y;
+ return 0;
+}
+
+void vtl_ts_free_gpio(void)
+{
+ struct ts_info *ts;
+
+ ts = pg_ts;
+ DEBUG();
+
+ gpio_free(ts->config_info.irq_gpio_number);
+}
+
+void vtl_ts_hw_reset(void)
+{
+ struct ts_info *ts;
+
+ ts = pg_ts;
+ DEBUG();
+
+ gpio_set_value(ts->config_info.rst_gpio_number, 0);
+ mdelay(50);
+ gpio_set_value(ts->config_info.rst_gpio_number, 1);
+}
+
+static irqreturn_t vtl_ts_irq(int irq, void *dev)
+{
+ struct ts_info *ts;
+
+ ts = pg_ts;
+ DEBUG();
+
+ queue_work(ts->driver->workqueue, &ts->driver->event_work);
+
+ return IRQ_HANDLED;
+}
+
+static union ts_xy_data *vtl_read_xy_data(struct ts_info *ts)
+{
+ struct i2c_msg msgs;
+ int err;
+
+ DEBUG();
+
+ msgs.addr = ts->driver->client->addr;
+ msgs.flags = 0x01;
+ msgs.len = sizeof(ts->xy_data.buf);
+ msgs.buf = ts->xy_data.buf;
+
+ err = i2c_transfer(ts->driver->client->adapter, &msgs, 1);
+ if (err != 1) {
+ pr_err("___%s:i2c read err___\n", __func__);
+ return NULL;
+ }
+ return &ts->xy_data;
+}
+
+static void vtl_report_xy_coord(struct input_dev *input_dev,
+ union ts_xy_data *xy_data,
+ unsigned char touch_point_number)
+{
+ struct ts_info *ts;
+ int id;
+ int sync;
+ int x, y;
+ unsigned int press;
+ static unsigned int release;
+
+ ts = pg_ts;
+ DEBUG();
+
+ /* report points */
+ sync = 0; press = 0;
+ for (id = 0; id < touch_point_number; id++) {
+ if ((xy_data->point[id].xhi != 0xFF) &&
+ (xy_data->point[id].yhi != 0xFF) &&
+ ((xy_data->point[id].status == 1) ||
+ (xy_data->point[id].status == 2))) {
+ x = (xy_data->point[id].xhi<<4) |
+ (xy_data->point[id].xlo&0xF);
+ y = (xy_data->point[id].yhi<<4) |
+ (xy_data->point[id].ylo&0xF);
+
+ if (ts->config_info.exchange_x_y_flag)
+ swap(x, y);
+
+ if (ts->config_info.revert_x_flag)
+ x = ts->config_info.screen_max_x - x;
+
+ if (ts->config_info.revert_y_flag)
+ y = ts->config_info.screen_max_y - y;
+#ifndef FORCE_SINGLE_EVENT
+ input_mt_slot(input_dev, xy_data->point[id].id - 1);
+ input_mt_report_slot_state(input_dev,
+ MT_TOOL_FINGER, true);
+ input_report_abs(input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, 30);
+ input_report_abs(input_dev, ABS_MT_WIDTH_MAJOR, 128);
+#else
+ input_report_abs(input_dev, ABS_X, x);
+ input_report_abs(input_dev, ABS_Y, y);
+ input_report_key(input_dev, BTN_TOUCH, 1);
+ input_report_abs(input_dev, ABS_PRESSURE, 1);
+#endif
+ sync = 1;
+ press |= 0x01 << (xy_data->point[id].id - 1);
+ }
+ }
+
+ release &= (release ^ press); /*release point flag */
+ for (id = 0; id < touch_point_number; id++) {
+ if (release & (0x01 << id)) {
+#ifndef FORCE_SINGLE_EVENT
+ input_mt_slot(input_dev, id);
+ input_mt_report_slot_state(input_dev,
+ MT_TOOL_FINGER, false);
+#else
+ input_report_key(input_dev, BTN_TOUCH, 0);
+ input_report_abs(input_dev, ABS_PRESSURE, 0);
+#endif
+ sync = 1;
+ }
+
+ }
+ release = press;
+
+ if (sync)
+ input_sync(input_dev);
+}
+
+static void vtl_ts_workfunc(struct work_struct *work)
+{
+
+ union ts_xy_data *xy_data;
+ struct input_dev *input_dev;
+ unsigned char touch_point_number;
+
+ DEBUG();
+
+ input_dev = pg_ts->driver->input_dev;
+ touch_point_number = pg_ts->config_info.touch_point_number;
+
+ xy_data = vtl_read_xy_data(pg_ts);
+ if (xy_data != NULL)
+ vtl_report_xy_coord(input_dev, xy_data, touch_point_number);
+ else
+ pr_err("____xy_data error___\n");
+}
+
+#ifdef CONFIG_PM_SLEEP
+int vtl_ts_suspend(struct device *dev)
+{
+ struct ts_info *ts;
+
+ ts = pg_ts;
+ DEBUG();
+
+ disable_irq(ts->config_info.irq_number);
+ cancel_work_sync(&ts->driver->event_work);
+
+ return 0;
+}
+
+int vtl_ts_resume(struct device *dev)
+{
+ struct ts_info *ts;
+
+ ts = pg_ts;
+ DEBUG();
+
+ /* Hardware reset */
+ vtl_ts_hw_reset();
+ enable_irq(ts->config_info.irq_number);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void vtl_ts_early_suspend(struct early_suspend *handler)
+{
+ struct ts_info *ts;
+
+ ts = pg_ts;
+ DEBUG();
+
+ vtl_ts_suspend(ts->driver->client, PMSG_SUSPEND);
+}
+
+static void vtl_ts_early_resume(struct early_suspend *handler)
+{
+ struct ts_info *ts;
+
+ ts = pg_ts;
+ DEBUG();
+
+ vtl_ts_resume(ts->driver->client);
+}
+#endif
+
+int vtl_ts_remove(struct i2c_client *client)
+{
+ struct ts_info *ts;
+
+ ts = pg_ts;
+ DEBUG();
+
+ /* Driver clean up */
+
+ free_irq(ts->config_info.irq_number, ts);
+ vtl_ts_free_gpio();
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&ts->driver->early_suspend);
+#endif
+
+ cancel_work_sync(&ts->driver->event_work);
+ destroy_workqueue(ts->driver->workqueue);
+
+ input_unregister_device(ts->driver->input_dev);
+ input_free_device(ts->driver->input_dev);
+
+ if (ts->driver->proc_entry != NULL)
+ remove_proc_entry(DRIVER_NAME, NULL);
+
+ return 0;
+}
+
+static int init_input_dev(struct ts_info *ts)
+{
+ struct input_dev *input_dev;
+ struct device *dev;
+ int err;
+
+ DEBUG();
+
+ dev = &ts->driver->client->dev;
+
+ /* allocate input device */
+ ts->driver->input_dev = devm_input_allocate_device(dev);
+ if (ts->driver->input_dev == NULL) {
+ dev_err(dev, "Unable to allocate input device for device %s\n",
+ DRIVER_NAME);
+ return -1;
+ }
+
+ input_dev = ts->driver->input_dev;
+
+ input_dev->name = "VTL for wld";
+ input_dev->phys = "I2C";
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->id.vendor = 0xaaaa;
+ input_dev->id.product = 0x5555;
+ input_dev->id.version = 0x0001;
+ input_dev->dev.parent = dev;
+
+ /* config input device */
+ __set_bit(EV_SYN, input_dev->evbit);
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(EV_ABS, input_dev->evbit);
+
+#ifdef FORCE_SINGLE_EVENT
+ input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1, 0, 0);
+ input_set_abs_params(input_dev, ABS_X, MIN_X, MAX_X, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, MIN_Y, MAX_Y, 0, 0);
+#else
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+
+ input_mt_init_slots(input_dev, TOUCH_POINT_NUM, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
+ ts->config_info.screen_max_x, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
+ ts->config_info.screen_max_y, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
+#endif
+ /* register input device */
+ err = input_register_device(input_dev);
+ if (err) {
+ dev_err(dev, "Unable to register input device for device %s\n",
+ DRIVER_NAME);
+ return -1;
+ }
+
+ return 0;
+}
+
+int ct36x_test_tp(struct i2c_client *client)
+{
+ struct i2c_msg msgs;
+ char buf;
+
+ msgs.addr = 0x7F;
+ msgs.flags = 0x01;
+ msgs.len = 1;
+ msgs.buf = &buf;
+
+ if (i2c_transfer(client->adapter, &msgs, 1) != 1)
+ return -1;
+
+ return 0;
+}
+
+int vtl_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ int err = -1;
+ struct ts_info *ts;
+ struct device *dev;
+
+ ts = pg_ts;
+ ts->driver->client = client;
+ dev = &ts->driver->client->dev;
+
+ /*Probing TouchScreen*/
+ pr_info("Probing vtl touchscreen, touchscreen node found\n");
+ if (ct36x_test_tp(client) < 0) {
+ pr_err("vtl tp not found\n");
+ goto ERR_TS_CONFIG;
+ }
+
+ /* Request platform resources (gpio/interrupt pins) */
+ err = vtl_ts_config(ts);
+ if (err) {
+ dev_err(dev, "VTL touch screen config Failed.\n");
+ goto ERR_TS_CONFIG;
+ }
+
+ /*Requestion GPIO*/
+ ts->config_info.rst_gpio_number = of_get_gpio(client->dev.of_node, 0);
+ if (gpio_is_valid(ts->config_info.rst_gpio_number)) {
+ err = devm_gpio_request(dev,
+ ts->config_info.rst_gpio_number, NULL);
+ if (err) {
+ dev_err(dev, "Unable to request GPIO %d\n",
+ ts->config_info.rst_gpio_number);
+ return err;
+ }
+ }
+
+ /* Check I2C Functionality */
+ err = i2c_check_functionality(client->adapter, I2C_FUNC_I2C);
+ if (!err) {
+ dev_err(dev, "Check I2C Functionality Failed.\n");
+ return -ENODEV;
+ }
+
+ err = devm_request_threaded_irq(dev, client->irq,
+ NULL, vtl_ts_irq,
+ IRQF_ONESHOT,
+ client->name, ts);
+ if (err) {
+ dev_err(&client->dev, "VTL Failed to register interrupt\n");
+
+ goto ERR_IRQ_REQ;
+ }
+
+ vtl_ts_hw_reset();
+
+ /*init input dev*/
+ err = init_input_dev(ts);
+ if (err) {
+
+ dev_err(dev, "init input dev failed.\n");
+ goto ERR_INIT_INPUT;
+ }
+
+ /* register early suspend */
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ ts->driver->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ ts->driver->early_suspend.suspend = vtl_ts_early_suspend;
+ ts->driver->early_suspend.resume = vtl_ts_early_resume;
+ register_early_suspend(&ts->driver->early_suspend);
+#endif
+ /* Create work queue */
+ INIT_WORK(&ts->driver->event_work, vtl_ts_workfunc);
+ ts->driver->workqueue = create_singlethread_workqueue(DRIVER_NAME);
+
+ return 0;
+
+ERR_IRQ_REQ:
+ cancel_work_sync(&ts->driver->event_work);
+ destroy_workqueue(ts->driver->workqueue);
+
+ERR_INIT_INPUT:
+ input_free_device(ts->driver->input_dev);
+ gpio_free(ts->config_info.rst_gpio_number);
+ERR_TS_CONFIG:
+
+ return err;
+}
+
+
+static SIMPLE_DEV_PM_OPS(vtl_ts_pm_ops, vtl_ts_suspend, vtl_ts_resume);
+
+static const struct of_device_id vtl_ts_dt_ids[] = {
+ { .compatible = "vtl,ct365", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, vtl_ts_dt_ids);
+
+
+static struct i2c_driver vtl_ts_driver = {
+ .probe = vtl_ts_probe,
+ .remove = vtl_ts_remove,
+ .id_table = vtl_ts_id,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .pm = &vtl_ts_pm_ops,
+ .of_match_table = of_match_ptr(vtl_ts_dt_ids),
+ },
+};
+
+module_i2c_driver(vtl_ts_driver);
+
+MODULE_AUTHOR("VTL");
+MODULE_DESCRIPTION("VTL TouchScreen driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/vtl/vtl_ts.h b/drivers/input/touchscreen/vtl/vtl_ts.h
new file mode 100644
index 000000000000..9f61565d6639
--- /dev/null
+++ b/drivers/input/touchscreen/vtl/vtl_ts.h
@@ -0,0 +1,181 @@
+/*
+ * VTL CTP driver
+ *
+ * Copyright (C) 2016 Freescale Semiconductor, Inc
+ *
+ * Using code from:
+ * - github.com/qdk0901/q98_source:drivers/input/touchscreen/vtl/vtl_ts.h
+ *
+ * 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.
+ *
+ */
+
+#ifndef _TS_CORE_H_
+#define _TS_CORE_H_
+
+#include <linux/gpio.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+
+#ifdef TS_DEBUG
+#define DEBUG() pr_debug("___%s___\n", __func__)
+#else
+#define DEBUG()
+#endif
+
+
+/* platform define */
+#define COMMON 0x01 /* Samsung,Freescale,Amlogic,actions */
+#define ROCKCHIP 0X02
+#define ALLWINER 0X03
+#define MTK 0X04
+
+/* vtl touch IC define */
+#define CT36X 0x01
+#define CT360 0x02
+
+/* xy data protocol */
+#define OLD_PROTOCOL 0x01
+#define NEW_PROTOCOL 0x02
+
+
+/* vtl ts driver config */
+
+/*platform config*/
+#define PLATFORM COMMON
+
+/*vtl ts driver name*/
+#define DRIVER_NAME "vtl_ts"
+
+/*vtl chip ID*/
+#define CHIP_ID CT36X
+
+#define XY_DATA_PROTOCOL NEW_PROTOCOL
+
+
+/* maybe not use,please refer to the function
+ * vtl_ts_config() in the file "vtl_ts.c"
+ */
+#define SCREEN_MAX_X 1024
+#define SCREEN_MAX_y 600
+
+#define TS_IRQ_GPIO_NUM /* RK30_PIN4_PC2 */
+#define TS_RST_GPIO_NUM /* RK30_PIN4_PD0 */
+#define TS_I2C_SPEED 400000 /* for rockchip */
+
+
+/* priate define and declare */
+#if (CHIP_ID == CT360)
+#define TOUCH_POINT_NUM 1
+#elif (CHIP_ID == CT36X)
+#define TOUCH_POINT_NUM 1
+#endif
+
+
+#if (CHIP_ID == CT360)
+struct xy_data {
+#if (XY_DATA_PROTOCOL == OLD_PROTOCOL)
+ unsigned char status:4; /* Action information, 1:Down;
+ 2: Move; 3: Up */
+ unsigned char id:4; /* ID information, from 1 to
+ CFG_MAX_POINT_NUM */
+#endif
+ unsigned char xhi; /* X coordinate Hi */
+ unsigned char yhi; /* Y coordinate Hi */
+ unsigned char ylo:4; /* Y coordinate Lo */
+ unsigned char xlo:4; /* X coordinate Lo */
+#if (XY_DATA_PROTOCOL == NEW_PROTOCOL)
+ unsigned char status:4; /* Action information, 1: Down;
+ 2: Move; 3: Up */
+ unsigned char id:4; /* ID information, from 1 to
+ CFG_MAX_POINT_NUM */
+#endif
+};
+#else
+struct xy_data {
+#if (XY_DATA_PROTOCOL == OLD_PROTOCOL)
+ unsigned char status:3; /* Action information, 1: Down;
+ 2: Move; 3: Up */
+ unsigned char id:5; /* ID information, from 1 to
+ CFG_MAX_POINT_NUM */
+#endif
+ unsigned char xhi; /* X coordinate Hi */
+ unsigned char yhi; /* Y coordinate Hi */
+ unsigned char ylo:4; /* Y coordinate Lo */
+ unsigned char xlo:4; /* X coordinate Lo */
+#if (XY_DATA_PROTOCOL == NEW_PROTOCOL)
+ unsigned char status:3; /* Action information, 1: Down;
+ 2: Move; 3: Up */
+ unsigned char id:5; /* ID information, from 1 to
+ CFG_MAX_POINT_NUM */
+#endif
+ unsigned char area; /* Touch area */
+ unsigned char pressure; /* Touch Pressure */
+};
+#endif
+
+
+union ts_xy_data {
+ struct xy_data point[TOUCH_POINT_NUM];
+ unsigned char buf[TOUCH_POINT_NUM * sizeof(struct xy_data)];
+};
+
+
+struct ts_driver {
+
+ struct i2c_client *client;
+
+ /* input devices */
+ struct input_dev *input_dev;
+
+ struct proc_dir_entry *proc_entry;
+
+ /* Work thread settings */
+ struct work_struct event_work;
+ struct workqueue_struct *workqueue;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
+};
+
+struct ts_config_info {
+
+ unsigned int screen_max_x;
+ unsigned int screen_max_y;
+ unsigned int irq_gpio_number;
+ unsigned int irq_number;
+ unsigned int rst_gpio_number;
+ unsigned char touch_point_number;
+ unsigned char ctp_used;
+ unsigned char i2c_bus_number;
+ unsigned char revert_x_flag;
+ unsigned char revert_y_flag;
+ unsigned char exchange_x_y_flag;
+ int (*tp_enter_init)(void);
+ void (*tp_exit_init)(int state);
+};
+
+
+struct ts_chip_info {
+ unsigned char chip_id;
+};
+
+struct ts_info {
+
+ struct ts_driver *driver;
+ struct ts_config_info config_info;
+ struct ts_chip_info chip_info;
+ union ts_xy_data xy_data;
+};
+
+#endif
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 5a9a4416f467..e6f774a987c2 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -247,6 +247,7 @@ enum arm_smmu_s2cr_privcfg {
#define ARM_MMU500_ACTLR_CPRE (1 << 1)
#define ARM_MMU500_ACR_CACHE_LOCK (1 << 26)
+#define ARM_MMU500_ACR_SMTNMB_TLBEN (1 << 8)
#define CB_PAR_F (1 << 0)
@@ -1581,16 +1582,22 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
for (i = 0; i < smmu->num_mapping_groups; ++i)
arm_smmu_write_sme(smmu, i);
- /*
- * Before clearing ARM_MMU500_ACTLR_CPRE, need to
- * clear CACHE_LOCK bit of ACR first. And, CACHE_LOCK
- * bit is only present in MMU-500r2 onwards.
- */
- reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID7);
- major = (reg >> ID7_MAJOR_SHIFT) & ID7_MAJOR_MASK;
- if ((smmu->model == ARM_MMU500) && (major >= 2)) {
+ if (smmu->model == ARM_MMU500) {
+ /*
+ * Before clearing ARM_MMU500_ACTLR_CPRE, need to
+ * clear CACHE_LOCK bit of ACR first. And, CACHE_LOCK
+ * bit is only present in MMU-500r2 onwards.
+ */
+ reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID7);
+ major = (reg >> ID7_MAJOR_SHIFT) & ID7_MAJOR_MASK;
reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_sACR);
- reg &= ~ARM_MMU500_ACR_CACHE_LOCK;
+ if (major >= 2)
+ reg &= ~ARM_MMU500_ACR_CACHE_LOCK;
+ /*
+ * Allow unmatched Stream IDs to allocate bypass
+ * TLB entries for reduced latency.
+ */
+ reg |= ARM_MMU500_ACR_SMTNMB_TLBEN;
writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_sACR);
}
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 7c9d632f1d09..76fb7d465cbd 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -14,6 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) 2014 ARM Limited
+ * Copyright 2017 NXP
*
* Author: Will Deacon <will.deacon@arm.com>
*/
@@ -212,7 +213,7 @@ static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp,
{
struct device *dev = cfg->iommu_dev;
dma_addr_t dma;
- void *pages = alloc_pages_exact(size, gfp | __GFP_ZERO);
+ void *pages = alloc_pages_exact(size, gfp | __GFP_ZERO | __GFP_DMA);
if (!pages)
return NULL;
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 910cb5e23371..5464684dd11b 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -251,6 +251,18 @@ config IMX_GPCV2
help
Enables the wakeup IRQs for IMX platforms with GPCv2 block
+config IMX_IRQSTEER
+ def_bool y if ARCH_MXC_ARM64
+ select IRQ_DOMAIN
+ help
+ Enables the IRQ Steer for NXP IMX platforms
+
+config IMX_INTMUX
+ def_bool y if ARCH_MXC_ARM64
+ select IRQ_DOMAIN
+ help
+ Enables the IRQ MUX for NXP IMX platforms
+
config IRQ_MXS
def_bool y if MACH_ASM9260 || ARCH_MXS
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index e4dbfc85abdb..e9080c5af812 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -67,6 +67,8 @@ obj-$(CONFIG_RENESAS_H8S_INTC) += irq-renesas-h8s.o
obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o
obj-$(CONFIG_INGENIC_IRQ) += irq-ingenic.o
obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o
+obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o
+obj-$(CONFIG_IMX_INTMUX) += irq-imx-intmux.o
obj-$(CONFIG_PIC32_EVIC) += irq-pic32-evic.o
obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o
obj-$(CONFIG_MVEBU_PIC) += irq-mvebu-pic.o
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index f7b8681aed3f..30ae43d8cc69 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -62,6 +62,8 @@ struct gic_chip_data {
static struct gic_chip_data gic_data __read_mostly;
static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE;
+static void __iomem *iomuxc_gpr_base;
+
static struct gic_kvm_info gic_v3_kvm_info;
#define gic_data_rdist() (this_cpu_ptr(gic_data.rdists.rdist))
@@ -607,6 +609,7 @@ static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)
static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
{
int cpu;
+ u32 val;
if (WARN_ON(irq >= 16))
return;
@@ -623,8 +626,18 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
tlist = gic_compute_target_list(&cpu, mask, cluster_id);
gic_send_sgi(cluster_id, tlist, irq);
- }
+ if (iomuxc_gpr_base) {
+ /* pending the IRQ32 to wakeup the core */
+ val = readl_relaxed(iomuxc_gpr_base + 0x4);
+ val |= (1 << 12);
+ writel_relaxed(val, iomuxc_gpr_base + 0x4);
+ /* delay for a while to make sure cores wakeup done */
+ udelay(10);
+ val &= ~(1 << 12);
+ writel_relaxed(val, iomuxc_gpr_base + 0x4);
+ }
+ }
/* Force the above writes to ICC_SGI1R_EL1 to be executed */
isb();
}
@@ -1164,6 +1177,12 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
rdist_regs[i].phys_base = res.start;
}
+ if (of_machine_is_compatible("fsl,imx8mq")) {
+ /* sw workaround for IPI can't wakeup CORE
+ ERRATA(ERR011171) on i.MX8MQ */
+ iomuxc_gpr_base = of_iomap(node, 2);
+ }
+
if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
redist_stride = 0;
diff --git a/drivers/irqchip/irq-imx-intmux.c b/drivers/irqchip/irq-imx-intmux.c
new file mode 100644
index 000000000000..72959d096074
--- /dev/null
+++ b/drivers/irqchip/irq-imx-intmux.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_platform.h>
+#include <linux/spinlock.h>
+
+#define CHANCSR(n) (0x0 + 0x40 * n)
+#define CHANVEC(n) (0x4 + 0x40 * n)
+#define CHANIER(n) (0x10 + (0x40 * n))
+#define CHANIPR(n) (0x20 + (0x40 * n))
+
+struct intmux_irqchip_data {
+ int chanidx;
+ int irq;
+ struct irq_domain *domain;
+ unsigned int irqstat;
+};
+
+
+struct intmux_data {
+ spinlock_t lock;
+ struct platform_device *pdev;
+ void __iomem *regs;
+ struct clk *ipg_clk;
+ int channum;
+ struct intmux_irqchip_data irqchip_data[];
+};
+
+static void imx_intmux_irq_unmask(struct irq_data *d)
+{
+ struct intmux_irqchip_data *irqchip_data = d->chip_data;
+ u32 idx = irqchip_data->chanidx;
+ struct intmux_data *intmux_data = container_of(irqchip_data, struct intmux_data, irqchip_data[idx]);
+ void __iomem *reg;
+ u32 val;
+
+ spin_lock(&intmux_data->lock);
+ reg = intmux_data->regs + CHANIER(idx);
+ val = readl_relaxed(reg);
+ val |= 1 << d->hwirq;
+ writel_relaxed(val, reg);
+ spin_unlock(&intmux_data->lock);
+}
+
+static void imx_intmux_irq_mask(struct irq_data *d)
+{
+ struct intmux_irqchip_data *irqchip_data = d->chip_data;
+ u32 idx = irqchip_data->chanidx;
+ struct intmux_data *intmux_data = container_of(irqchip_data, struct intmux_data, irqchip_data[idx]);
+ void __iomem *reg;
+ u32 val;
+
+ spin_lock(&intmux_data->lock);
+ reg = intmux_data->regs + CHANIER(idx);
+ val = readl_relaxed(reg);
+ val &= ~(1 << d->hwirq);
+ writel_relaxed(val, reg);
+ spin_unlock(&intmux_data->lock);
+}
+
+static void imx_intmux_irq_ack(struct irq_data *d)
+{
+ /* the irqchip has no ack */
+}
+
+static struct irq_chip imx_intmux_irq_chip = {
+ .name = "intmux",
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_mask = imx_intmux_irq_mask,
+ .irq_unmask = imx_intmux_irq_unmask,
+ .irq_ack = imx_intmux_irq_ack,
+};
+
+static int imx_intmux_irq_map(struct irq_domain *h, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ irq_set_chip_data(irq, h->host_data);
+ irq_set_chip_and_handler(irq, &imx_intmux_irq_chip, handle_edge_irq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops imx_intmux_domain_ops = {
+ .map = imx_intmux_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static void imx_intmux_update_irqstat(struct intmux_irqchip_data *irqchip_data)
+{
+ int i = irqchip_data->chanidx;
+ struct intmux_data *intmux_data = container_of(irqchip_data, struct intmux_data, irqchip_data[i]);
+
+ irqchip_data->irqstat = readl_relaxed(intmux_data->regs + CHANIPR(i));
+}
+
+static void imx_intmux_irq_handler(struct irq_desc *desc)
+{
+ struct intmux_irqchip_data *irqchip_data = irq_desc_get_handler_data(desc);
+ int pos, virq;
+
+ chained_irq_enter(irq_desc_get_chip(desc), desc);
+
+ imx_intmux_update_irqstat(irqchip_data);
+
+ for_each_set_bit(pos, (unsigned long *)&irqchip_data->irqstat, 32) {
+ virq = irq_find_mapping(irqchip_data->domain, pos);
+ if (virq)
+ generic_handle_irq(virq);
+ }
+
+ chained_irq_exit(irq_desc_get_chip(desc), desc);
+}
+
+static int imx_intmux_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct intmux_data *intmux_data;
+ struct resource *res;
+ int i;
+ int channum;
+ int ret;
+
+ ret = of_property_read_u32(np, "nxp,intmux_chans", &channum);
+ if (ret)
+ channum = 1;
+
+ intmux_data = devm_kzalloc(&pdev->dev, sizeof(*intmux_data) +
+ channum *
+ sizeof(intmux_data->irqchip_data[0]),
+ GFP_KERNEL);
+ if (!intmux_data)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ intmux_data->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(intmux_data->regs)) {
+ dev_err(&pdev->dev, "failed to initialize reg\n");
+ return PTR_ERR(intmux_data->regs);
+ }
+
+ intmux_data->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
+ if (IS_ERR(intmux_data->ipg_clk)) {
+ ret = PTR_ERR(intmux_data->ipg_clk);
+ dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret);
+ return ret;
+ }
+
+ intmux_data->channum = channum;
+ intmux_data->pdev = pdev;
+ spin_lock_init(&intmux_data->lock);
+
+ ret = clk_prepare_enable(intmux_data->ipg_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable ipg clk: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < channum; i++) {
+ intmux_data->irqchip_data[i].chanidx = i;
+ intmux_data->irqchip_data[i].irq = platform_get_irq(pdev, i);
+ if (intmux_data->irqchip_data[i].irq <= 0) {
+ dev_err(&pdev->dev, "failed to get irq\n");
+ return -ENODEV;
+ }
+
+ intmux_data->irqchip_data[i].domain = irq_domain_add_linear(np,
+ 32,
+ &imx_intmux_domain_ops,
+ &intmux_data->irqchip_data[i]);
+ if (!intmux_data->irqchip_data[i].domain) {
+ dev_err(&intmux_data->pdev->dev,
+ "failed to create IRQ domain\n");
+ return -ENOMEM;
+ }
+
+ irq_set_chained_handler_and_data(intmux_data->irqchip_data[i].irq,
+ imx_intmux_irq_handler,
+ &intmux_data->irqchip_data[i]);
+ }
+
+ platform_set_drvdata(pdev, intmux_data);
+
+ return 0;
+}
+
+static int imx_intmux_remove(struct platform_device *pdev)
+{
+ struct intmux_data *intmux_data = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < intmux_data->channum; i++) {
+ irq_set_chained_handler_and_data(intmux_data->irqchip_data[i].irq, NULL, NULL);
+
+ irq_domain_remove(intmux_data->irqchip_data[i].domain);
+ }
+
+ platform_set_drvdata(pdev, NULL);
+ clk_disable_unprepare(intmux_data->ipg_clk);
+
+ return 0;
+}
+
+static const struct of_device_id imx_intmux_id[] = {
+ { .compatible = "nxp,imx-intmux", },
+ {},
+};
+
+static struct platform_driver imx_intmux_driver = {
+ .driver = {
+ .name = "imx-intmux",
+ .of_match_table = imx_intmux_id,
+ },
+ .probe = imx_intmux_probe,
+ .remove = imx_intmux_remove,
+};
+
+static int __init irq_imx_intmux_init(void)
+{
+ return platform_driver_register(&imx_intmux_driver);
+}
+arch_initcall(irq_imx_intmux_init);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("NXP i.MX8 irq steering driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c
new file mode 100644
index 000000000000..e26d242e1c66
--- /dev/null
+++ b/drivers/irqchip/irq-imx-irqsteer.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_platform.h>
+#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
+
+#define CHANREG_OFF (irqsteer_data->channum * 4)
+#define CHANCTRL 0x0
+#define CHANMASK(n) (0x4 + 0x4 * (n))
+#define CHANSET(n) (0x4 + (0x4 * (n)) + CHANREG_OFF)
+#define CHANSTATUS(n) (0x4 + (0x4 * (n)) + (CHANREG_OFF * 2))
+#define CHAN_MINTDIS (0x4 + (CHANREG_OFF * 3))
+#define CHAN_MASTRSTAT (CHAN_MINTDIS + 0x4)
+
+struct irqsteer_irqchip_data {
+ struct irq_chip chip;
+ spinlock_t lock;
+ struct platform_device *pdev;
+ void __iomem *regs;
+ struct clk *ipg_clk;
+ int irq;
+ int channum;
+ int endian; /* 0: littel endian; 1: big endian */
+ struct irq_domain *domain;
+ int *saved_reg;
+ bool inited;
+ unsigned int irqstat[];
+};
+
+static void imx_irqsteer_irq_unmask(struct irq_data *d)
+{
+ struct irqsteer_irqchip_data *irqsteer_data = d->chip_data;
+ void __iomem *reg;
+ u32 val, idx;
+
+ spin_lock(&irqsteer_data->lock);
+ idx = irqsteer_data->endian ?
+ (irqsteer_data->channum - d->hwirq / 32 - 1) : d->hwirq / 32;
+ reg = irqsteer_data->regs + CHANMASK(idx);
+ val = readl_relaxed(reg);
+ val |= 1 << (d->hwirq % 32);
+ writel_relaxed(val, reg);
+ spin_unlock(&irqsteer_data->lock);
+}
+
+static void imx_irqsteer_irq_mask(struct irq_data *d)
+{
+ struct irqsteer_irqchip_data *irqsteer_data = d->chip_data;
+ void __iomem *reg;
+ u32 val, idx;
+
+ spin_lock(&irqsteer_data->lock);
+ idx = irqsteer_data->endian ?
+ (irqsteer_data->channum - d->hwirq / 32 - 1) : d->hwirq / 32;
+ reg = irqsteer_data->regs + CHANMASK(idx);
+ val = readl_relaxed(reg);
+ val &= ~(1 << (d->hwirq % 32));
+ writel_relaxed(val, reg);
+ spin_unlock(&irqsteer_data->lock);
+}
+
+static void imx_irqsteer_irq_ack(struct irq_data *d)
+{
+ /* the irqchip has no ack */
+}
+
+static struct irq_chip imx_irqsteer_irq_chip = {
+ .name = "irqsteer",
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_mask = imx_irqsteer_irq_mask,
+ .irq_unmask = imx_irqsteer_irq_unmask,
+ .irq_ack = imx_irqsteer_irq_ack,
+};
+
+static int imx_irqsteer_irq_map(struct irq_domain *h, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct irqsteer_irqchip_data *irqsteer_data = h->host_data;
+
+ irq_set_chip_data(irq, h->host_data);
+ irq_set_chip_and_handler(irq, &irqsteer_data->chip, handle_level_irq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops imx_irqsteer_domain_ops = {
+ .map = imx_irqsteer_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static void imx_irqsteer_init(struct irqsteer_irqchip_data *irqsteer_data)
+{
+ /* enable channel 1 in default */
+ writel_relaxed(1, irqsteer_data->regs + CHANCTRL);
+
+ /* read back CHANCTRL register cannot reflact on HW register
+ * real value due to the HW action, so add one flag here.
+ */
+ irqsteer_data->inited = true;
+}
+
+static void imx_irqsteer_update_irqstat(struct irqsteer_irqchip_data *irqsteer_data)
+{
+ int i;
+
+ /*
+ * From irq steering doc, there have one mapping:
+ * word[0] bit 31 -> irq 31 ... word[0] bit 0 -> irq 0
+ * word[1] bit 31 -> irq 63 ... word[1] bit 0 -> irq 32
+ * ......
+ * word[15] bit 31 -> irq 511 ... word[15] bit 0 -> irq 480
+ */
+ for (i = 0; i < irqsteer_data->channum; i++)
+ irqsteer_data->irqstat[i] = readl_relaxed(irqsteer_data->regs +
+ CHANSTATUS(irqsteer_data->endian ?
+ (irqsteer_data->channum - i - 1) :
+ i));
+}
+
+static void imx_irqsteer_irq_handler(struct irq_desc *desc)
+{
+ struct irqsteer_irqchip_data *irqsteer_data = irq_desc_get_handler_data(desc);
+ unsigned long val;
+ int irqnum;
+ int pos, virq;
+
+ chained_irq_enter(irq_desc_get_chip(desc), desc);
+
+ val = readl_relaxed(irqsteer_data->regs + CHAN_MASTRSTAT);
+ if (!val)
+ goto out;
+
+ imx_irqsteer_update_irqstat(irqsteer_data);
+
+ irqnum = irqsteer_data->channum * 32;
+ for_each_set_bit(pos, (unsigned long *)irqsteer_data->irqstat, irqnum) {
+ virq = irq_find_mapping(irqsteer_data->domain, pos);
+ if (virq)
+ generic_handle_irq(virq);
+ }
+
+out:
+ chained_irq_exit(irq_desc_get_chip(desc), desc);
+}
+
+static int imx_irqsteer_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct irqsteer_irqchip_data *irqsteer_data;
+ struct resource *res;
+ int channum, endian;
+ int ret;
+
+ ret = of_property_read_u32(np, "nxp,irqsteer_chans", &channum);
+ if (ret)
+ channum = 1;
+
+ ret = of_property_read_u32(np, "nxp,endian", &endian);
+ if (ret)
+ /* default is LSB */
+ endian = 0;
+
+ irqsteer_data = devm_kzalloc(&pdev->dev, sizeof(*irqsteer_data) +
+ channum *
+ sizeof(irqsteer_data->irqstat[0]),
+ GFP_KERNEL);
+ if (!irqsteer_data)
+ return -ENOMEM;
+
+ irqsteer_data->saved_reg = devm_kzalloc(&pdev->dev, sizeof(int) *
+ (channum + 1), GFP_KERNEL);
+ if (!irqsteer_data->saved_reg)
+ return -ENOMEM;
+
+ irqsteer_data->chip = imx_irqsteer_irq_chip;
+ irqsteer_data->chip.parent_device = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irqsteer_data->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(irqsteer_data->regs)) {
+ dev_err(&pdev->dev, "failed to initialize reg\n");
+ return PTR_ERR(irqsteer_data->regs);
+ }
+
+ irqsteer_data->irq = platform_get_irq(pdev, 0);
+ if (irqsteer_data->irq <= 0) {
+ dev_err(&pdev->dev, "failed to get irq\n");
+ return -ENODEV;
+ }
+
+ irqsteer_data->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
+ if (IS_ERR(irqsteer_data->ipg_clk)) {
+ ret = PTR_ERR(irqsteer_data->ipg_clk);
+ dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret);
+ return ret;
+ }
+
+ irqsteer_data->channum = channum;
+ irqsteer_data->endian = endian;
+ irqsteer_data->pdev = pdev;
+ irqsteer_data->inited = false;
+ spin_lock_init(&irqsteer_data->lock);
+
+ irqsteer_data->domain = irq_domain_add_linear(np,
+ irqsteer_data->channum * 32,
+ &imx_irqsteer_domain_ops,
+ irqsteer_data);
+ if (!irqsteer_data->domain) {
+ dev_err(&irqsteer_data->pdev->dev,
+ "failed to create IRQ domain\n");
+ return -ENOMEM;
+ }
+
+ irq_set_chained_handler_and_data(irqsteer_data->irq,
+ imx_irqsteer_irq_handler,
+ irqsteer_data);
+
+ platform_set_drvdata(pdev, irqsteer_data);
+
+ pm_runtime_enable(&pdev->dev);
+ return 0;
+}
+
+static int imx_irqsteer_remove(struct platform_device *pdev)
+{
+ struct irqsteer_irqchip_data *irqsteer_data = platform_get_drvdata(pdev);
+
+ irq_set_chained_handler_and_data(irqsteer_data->irq, NULL, NULL);
+
+ irq_domain_remove(irqsteer_data->domain);
+
+ return pm_runtime_force_suspend(&pdev->dev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static void imx_irqsteer_save_regs(struct irqsteer_irqchip_data *data)
+{
+ int num;
+
+ data->saved_reg[0] = readl_relaxed(data->regs + CHANCTRL);
+ for (num = 0; num < data->channum; num++)
+ data->saved_reg[num + 1] = readl_relaxed(data->regs + CHANMASK(num));
+}
+
+static void imx_irqsteer_restore_regs(struct irqsteer_irqchip_data *data)
+{
+ int num;
+
+ writel_relaxed(data->saved_reg[0], data->regs + CHANCTRL);
+ for (num = 0; num < data->channum; num++)
+ writel_relaxed(data->saved_reg[num + 1], data->regs + CHANMASK(num));
+}
+
+static int imx_irqsteer_runtime_suspend(struct device *dev)
+{
+ struct irqsteer_irqchip_data *irqsteer_data = dev_get_drvdata(dev);
+
+ /* After device's runtime suspended, device's power domain maybe off,
+ * if some sub_irqs resouces are not freed, it needs to save registers
+ * when device's suspend force runtime suspend. And even if all sub_irqs
+ * are freed, it also needs to save CHANCTRL register.
+ */
+ imx_irqsteer_save_regs(irqsteer_data);
+
+ clk_disable_unprepare(irqsteer_data->ipg_clk);
+
+ return 0;
+}
+
+static int imx_irqsteer_runtime_resume(struct device *dev)
+{
+ struct irqsteer_irqchip_data *irqsteer_data = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(irqsteer_data->ipg_clk);
+ if (ret) {
+ dev_err(dev, "failed to enable ipg clk: %d\n", ret);
+ return ret;
+ }
+
+ /* don't need restore registers when first sub_irq requested */
+ if (!irqsteer_data->inited)
+ imx_irqsteer_init(irqsteer_data);
+ else
+ imx_irqsteer_restore_regs(irqsteer_data);
+
+ return 0;
+}
+
+static const struct dev_pm_ops imx_irqsteer_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(imx_irqsteer_runtime_suspend,
+ imx_irqsteer_runtime_resume, NULL)
+};
+#define IMX_IRQSTEER_PM (&imx_irqsteer_pm_ops)
+#else
+#define IMX_IRQSTEER_PM NULL
+#endif
+
+static const struct of_device_id imx_irqsteer_id[] = {
+ { .compatible = "nxp,imx-irqsteer", },
+ {},
+};
+
+static struct platform_driver imx_irqsteer_driver = {
+ .driver = {
+ .name = "imx-irqsteer",
+ .of_match_table = imx_irqsteer_id,
+ .pm = IMX_IRQSTEER_PM,
+ },
+ .probe = imx_irqsteer_probe,
+ .remove = imx_irqsteer_remove,
+};
+
+static int __init irq_imx_irqsteer_init(void)
+{
+ return platform_driver_register(&imx_irqsteer_driver);
+}
+arch_initcall(irq_imx_irqsteer_init);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("NXP i.MX8 irq steering driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 0aedd0ebccec..0f08d97115bb 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -1135,7 +1135,7 @@ static void clone_init(struct dm_crypt_io *io, struct bio *clone)
clone->bi_private = io;
clone->bi_end_io = crypt_endio;
clone->bi_bdev = cc->dev->bdev;
- bio_set_op_attrs(clone, bio_op(io->base_bio), bio_flags(io->base_bio));
+ clone->bi_opf = io->base_bio->bi_opf;
}
static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c
index ba7c4c685db3..12bf9c079c4d 100644
--- a/drivers/md/dm-rq.c
+++ b/drivers/md/dm-rq.c
@@ -319,7 +319,7 @@ static void dm_unprep_request(struct request *rq)
if (!rq->q->mq_ops) {
rq->special = NULL;
- rq->cmd_flags &= ~REQ_DONTPREP;
+ rq->rq_flags &= ~RQF_DONTPREP;
}
if (clone)
@@ -437,7 +437,7 @@ static void dm_softirq_done(struct request *rq)
return;
}
- if (rq->cmd_flags & REQ_FAILED)
+ if (rq->rq_flags & RQF_FAILED)
mapped = false;
dm_done(clone, tio->error, mapped);
@@ -466,7 +466,7 @@ static void dm_complete_request(struct request *rq, int error)
*/
static void dm_kill_unmapped_request(struct request *rq, int error)
{
- rq->cmd_flags |= REQ_FAILED;
+ rq->rq_flags |= RQF_FAILED;
dm_complete_request(rq, error);
}
@@ -482,7 +482,7 @@ static void end_clone_request(struct request *clone, int error)
* For just cleaning up the information of the queue in which
* the clone was dispatched.
* The clone is *NOT* freed actually here because it is alloced
- * from dm own mempool (REQ_ALLOCED isn't set).
+ * from dm own mempool (RQF_ALLOCED isn't set).
*/
__blk_put_request(clone->q, clone);
}
@@ -503,7 +503,7 @@ static void dm_dispatch_clone_request(struct request *clone, struct request *rq)
int r;
if (blk_queue_io_stat(clone->q))
- clone->cmd_flags |= REQ_IO_STAT;
+ clone->rq_flags |= RQF_IO_STAT;
clone->start_time = jiffies;
r = blk_insert_cloned_request(clone->q, clone);
@@ -639,7 +639,7 @@ static int dm_old_prep_fn(struct request_queue *q, struct request *rq)
return BLKPREP_DEFER;
rq->special = tio;
- rq->cmd_flags |= REQ_DONTPREP;
+ rq->rq_flags |= RQF_DONTPREP;
return BLKPREP_OK;
}
@@ -852,7 +852,8 @@ static void dm_old_request_fn(struct request_queue *q)
int dm_old_init_request_queue(struct mapped_device *md)
{
/* Fully initialize the queue */
- if (!blk_init_allocated_queue(md->queue, dm_old_request_fn, NULL))
+ md->queue->request_fn = dm_old_request_fn;
+ if (blk_init_allocated_queue(md->queue) < 0)
return -EINVAL;
/* disable dm_old_request_fn's merge heuristic by default */
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 5ff803efdc03..fef1147703a1 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -114,6 +114,28 @@ config VIDEO_S3C_CAMIF
To compile this driver as a module, choose M here: the module
will be called s3c-camif.
+config VIDEO_MXC_OUTPUT
+ tristate "MXC Video For Linux Video Output"
+ depends on VIDEO_DEV && ARCH_MXC && FB_MXC
+ select VIDEOBUF_DMA_CONTIG
+ ---help---
+ This is the video4linux2 output driver based on MXC module.
+
+config VIDEO_MXC_CAPTURE
+ tristate "MXC Video For Linux Video Capture"
+ depends on VIDEO_V4L2
+ ---help---
+ This is the video4linux2 capture driver based on i.MX video-in module.
+
+config VIDEO_MX8_CAPTURE
+ tristate "MX8 Video For Linux Video Capture"
+ depends on VIDEO_V4L2
+ ---help---
+ This is the video4linux2 capture driver based on i.MX8 module.
+
+source "drivers/media/platform/imx8/Kconfig"
+source "drivers/media/platform/mxc/capture/Kconfig"
+source "drivers/media/platform/mxc/output/Kconfig"
source "drivers/media/platform/soc_camera/Kconfig"
source "drivers/media/platform/exynos4-is/Kconfig"
source "drivers/media/platform/am437x/Kconfig"
@@ -134,6 +156,7 @@ config VIDEO_TI_CAL
In TI Technical Reference Manual this module is referred as
Camera Interface Subsystem (CAMSS).
+
endif # V4L_PLATFORM_DRIVERS
menuconfig V4L_MEM2MEM_DRIVERS
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 40b18d12726e..ce35b4560e3b 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -61,6 +61,12 @@ obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vin/
obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel/
+obj-$(CONFIG_VIDEO_MXC_OUTPUT) += mxc/output/
+
+obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc/capture/
+obj-$(CONFIG_VIDEO_MXC_OUTPUT) += mxc/output/
+obj-$(CONFIG_VIDEO_MX8_CAPTURE) += imx8/
+
ccflags-y += -I$(srctree)/drivers/media/i2c
obj-$(CONFIG_VIDEO_MEDIATEK_VPU) += mtk-vpu/
diff --git a/drivers/media/platform/imx8/Kconfig b/drivers/media/platform/imx8/Kconfig
new file mode 100644
index 000000000000..60f048c5d098
--- /dev/null
+++ b/drivers/media/platform/imx8/Kconfig
@@ -0,0 +1,55 @@
+if VIDEO_MX8_CAPTURE
+menu "IMX8 Camera ISI/MIPI Features support"
+
+config IMX8_MEDIA_DEVICE
+ tristate "IMX8 Media Device Driver"
+ default y
+
+config IMX8_CAPTURE_DRIVER
+ tristate "IMX8 Camera Controller"
+ depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ select V4L2_MEM2MEM_DEV
+ select VIDEOBUF2_DMA_CONTIG
+ default y
+
+config IMX8_MIPI_CSI2
+ tristate "IMX8 MIPI CSI2 Controller"
+ default y
+
+config IMX8_PARALLEL_CSI
+ tristate "IMX8 PARALLEL CSI Controller"
+ default y
+
+config IMX8_MIPI_CSI2_YAV
+ tristate "IMX8 MIPI CSI2 Controller Yet Another Version"
+ default y
+
+config MXC_CAMERA_OV5640_V3
+ tristate "Maxim OV5640_V3 driver support"
+ depends on I2C
+ default y
+
+config MXC_CAMERA_OV5640_MIPI_V3
+ tristate "Maxim OV5640_MIPI_V3 driver support"
+ depends on I2C
+ default y
+
+config GMSL_MAX9286
+ tristate "Maxim max9286 GMSL Deserializer Input support"
+ select SENSOR_OV10635
+ depends on I2C
+ ---help---
+ If you plan to use the max9286 GMSL Deserializer with your capture system, say Y here.
+
+config IMX8_JPEG
+ tristate "IMX8 JPEG Encoder/Decoder"
+ depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ select V4L2_MEM2MEM_DEV
+ select VIDEOBUF2_DMA_CONTIG
+ default y
+
+source "drivers/media/platform/imx8/hdmi/Kconfig"
+
+endmenu
+endif #VIDEO_MX8_CAPTURE
+
diff --git a/drivers/media/platform/imx8/Makefile b/drivers/media/platform/imx8/Makefile
new file mode 100644
index 000000000000..892a53c91f18
--- /dev/null
+++ b/drivers/media/platform/imx8/Makefile
@@ -0,0 +1,14 @@
+mxc-capture-objs := mxc-isi-core.o mxc-isi-cap.o mxc-isi-hw.o
+
+obj-$(CONFIG_IMX8_CAPTURE_DRIVER) += mxc-capture.o
+obj-$(CONFIG_IMX8_MIPI_CSI2) += mxc-mipi-csi2.o
+obj-$(CONFIG_IMX8_PARALLEL_CSI) += mxc-parallel-csi.o
+obj-$(CONFIG_IMX8_MIPI_CSI2_YAV) += mxc-mipi-csi2_yav.o
+ov5640_camera_v3-objs := ov5640_v3.o
+obj-$(CONFIG_MXC_CAMERA_OV5640_V3) += ov5640_camera_v3.o
+obj-$(CONFIG_MXC_CAMERA_OV5640_MIPI_V3) += ov5640_mipi_v3.o
+max9286_gmsl-objs := max9286.o
+obj-$(CONFIG_GMSL_MAX9286) += max9286_gmsl.o
+obj-$(CONFIG_IMX8_MEDIA_DEVICE) += mxc-media-dev.o
+obj-$(CONFIG_IMX8_JPEG) += mxc-jpeg-hw.o mxc-jpeg.o
+obj-$(CONFIG_IMX8_HDMI_RX) += hdmi/
diff --git a/drivers/media/platform/imx8/hdmi/API_AFE_ss28fdsoi_hdmirx.c b/drivers/media/platform/imx8/hdmi/API_AFE_ss28fdsoi_hdmirx.c
new file mode 100644
index 000000000000..7961b6a9acf8
--- /dev/null
+++ b/drivers/media/platform/imx8/hdmi/API_AFE_ss28fdsoi_hdmirx.c
@@ -0,0 +1,1233 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_AFE_ss28fdsoi_hdmirx.c
+ *
+ ******************************************************************************
+ */
+
+#include "API_AFE_ss28fdsoi_hdmirx.h"
+
+static inline void write16(state_struct *state, u32 addr, u16 val)
+{
+ Afe_write(state, addr, val);
+}
+
+static inline void multi_write16(state_struct *state, u32 addr,
+ u16 val)
+{
+ u16 addr_tmp = addr;
+
+ if ((addr & 0x1E00) == LINK_ID << 9) {
+ addr_tmp |= LINK_WRITE;
+ Afe_write(state, addr_tmp, val);
+ } else {
+ Afe_write(state, addr_tmp, val);
+ }
+}
+
+static inline u16 read16(state_struct *state, u32 addr)
+{
+ u16 reg_val;
+
+ reg_val = Afe_read(state, addr);
+ return reg_val;
+}
+
+u16 inside_i(u16 value, u16 left_sharp_corner,
+ u16 right_sharp_corner)
+{
+ if (value < left_sharp_corner)
+ return 0;
+ if (value > right_sharp_corner)
+ return 0;
+ return 1;
+}
+
+u16 inside_f(u32 value, u32 left_sharp_corner, u32 right_sharp_corner)
+{
+ if (value < left_sharp_corner)
+ return 0;
+ if (value > right_sharp_corner)
+ return 0;
+ return 1;
+}
+
+void arc_config(state_struct *state)
+{
+ u16 reg_val;
+
+ write16(state, TXDA_CYA_AUXDA_CYA_ADDR, 0x0001);
+
+ write16(state, TX_DIG_CTRL_REG_1_ADDR, 0x3);
+ write16(state, TX_DIG_CTRL_REG_2_ADDR, 0x0024);
+
+ reg_val = read16(state, TX_ANA_CTRL_REG_1_ADDR);
+ reg_val |= 0x2000;
+ write16(state, TX_ANA_CTRL_REG_1_ADDR, reg_val);
+
+ write16(state, TX_ANA_CTRL_REG_2_ADDR, 0x0100);
+ write16(state, TX_ANA_CTRL_REG_2_ADDR, 0x0300);
+ write16(state, TX_ANA_CTRL_REG_3_ADDR, 0x0000);
+ write16(state, TX_ANA_CTRL_REG_1_ADDR, 0x2008);
+ write16(state, TX_ANA_CTRL_REG_1_ADDR, 0x2018);
+ write16(state, TX_ANA_CTRL_REG_1_ADDR, 0x2098);
+ write16(state, TX_ANA_CTRL_REG_2_ADDR, 0x030C);
+ write16(state, TX_ANA_CTRL_REG_5_ADDR, 0x0010);
+ write16(state, TX_ANA_CTRL_REG_4_ADDR, 0x4001);
+ write16(state, TX_ANA_CTRL_REG_1_ADDR, 0x2198);
+ write16(state, TX_ANA_CTRL_REG_2_ADDR, 0x030D);
+ write16(state, TX_ANA_CTRL_REG_2_ADDR, 0x030F);
+}
+
+void pma_config(state_struct *state)
+{
+ int i;
+ u16 reg_val = 0;
+ pr_info("pma_config() Configuring PMA\n");
+
+ write16(state, CMN_CMSMT_REF_CLK_TMR_VALUE_ADDR, 0x0801);
+ write16(state, RX_CLK_SLICER_CAL_INIT_TMR_ADDR, 0x00FF);
+ write16(state, CMN_RXCAL_INIT_TMR_ADDR, 0x003F);
+ write16(state, CMN_DIAG_PLL0_TEST_MODE_ADDR, 0x0022);
+ multi_write16(state, XCVR_PSM_CAL_TMR_ADDR, 0x0160);
+
+ /* Drives the rx_differential_invert PMA input for the associated lane */
+ for (i = 0; i < 3; i++) {
+ reg_val = 0x0c61;
+ write16(state, (PHY_PMA_XCVR_CTRL_ADDR | (i << 6)), reg_val);
+ }
+}
+
+void pre_data_rate_change(state_struct *state)
+{
+ u16 reg_val;
+
+ pr_info("pre_data_rate_change() Set the A3 power mode\n");
+ reg_val = read16(state, PHY_MODE_CTL_ADDR);
+ reg_val &= 0xFFF0;
+ reg_val |= 0x0008;
+ write16(state, PHY_MODE_CTL_ADDR, reg_val);
+
+ msleep(20);
+
+ /* Disable PLL */
+ pr_info("pre_data_rate_change() Disable PLL0\n");
+ reg_val = read16(state, PHY_MODE_CTL_ADDR);
+ reg_val &= 0xEFFF;
+ write16(state, PHY_MODE_CTL_ADDR, reg_val);
+
+ msleep(20);
+}
+
+u8 pma_cmn_ready(state_struct *state)
+{
+ u32 i;
+
+ for (i = 0; i < 20; i++) {
+ if (read16(state, PHY_PMA_CMN_CTRL1_ADDR) & (1 << 0))
+ break;
+ msleep(10);
+ }
+ if (i == 20)
+ return -1;
+ return 0;
+}
+
+u8 pma_rx_clk_signal_detect(state_struct *state)
+{
+ u32 i;
+
+ for (i = 0; i < 20; i++) {
+ if (read16(state, PHY_MODE_CTL_ADDR) & (1 << 8))
+ break;
+ msleep(10);
+ }
+ if (i == 20)
+ return -1;
+ return 0;
+}
+
+u32 pma_rx_clk_freq_detect(state_struct *state)
+{
+ u16 reg_val;
+ u32 rx_clk_freq;
+ u32 i;
+
+ pr_info("pma_rx_clk_freq_detect() Starting Rx clock frequency detection...\n");
+
+ /* Start frequency detection: */
+ write16(state, CMN_CMSMT_CLK_FREQ_MSMT_CTRL_ADDR, 0x8000);
+
+ /* Wait for pma_rx_clk_freq_detect_done */
+ for (i = 0; i < 20; i++) {
+ if (read16(state, CMN_CMSMT_CLK_FREQ_MSMT_CTRL_ADDR) & (1 << 14))
+ break;
+ msleep(10);
+ }
+ if (i == 20)
+ return -1;
+
+ /* Read the measured value */
+ reg_val = read16(state, CMN_CMSMT_TEST_CLK_CNT_VALUE_ADDR);
+
+ /* Calculate TMDS clock frequency */
+ rx_clk_freq = reg_val * REFCLK_FREQ_KHZ / 2048;
+
+ /* Turn off frequency measurement: */
+ write16(state, CMN_CMSMT_CLK_FREQ_MSMT_CTRL_ADDR, 0x0000);
+ pr_info("pma_rx_clk_freq_detect() Starting Rx clock frequency detection... DONE (TMDS clock freq: %d kHz)\n",
+ rx_clk_freq);
+ return rx_clk_freq;
+}
+
+u8 pma_pll_config(state_struct *state,
+ u32 rx_clk_freq,
+ clk_ratio_t clk_ratio,
+ tmds_bit_clock_ratio_t tmds_bit_clk_ratio,
+ unsigned char data_rate_change)
+{
+ int i, loop;
+ u16 reg_val;
+ u64 vco_freq_khz;
+
+ reg_field_t cmnda_pll0_ip_div;
+ reg_field_t cmnda_pll0_hs_sym_div_sel;
+ reg_field_t cmn_pll0_fb_div_high_ovrd_en;
+ reg_field_t cmnda_pll0_fb_div_high_out;
+ reg_field_t cmn_pll0_fb_div_low_ovrd_en;
+ reg_field_t cmnda_pll0_fb_div_low_out;
+ reg_field_t cmn_pll_clk_osr;
+ reg_field_t cmn_pll_clk_div2_ratio;
+ reg_field_t cmn_pll_clk_div2_sel;
+ reg_field_t rx_diag_smplr_osr;
+ reg_field_t rx_psc_a0;
+ reg_field_t rx_ree_pergcsm_eqenm_ph1;
+ reg_field_t rx_ree_pergcsm_eqenm_ph2;
+ reg_field_t vga_gain_accum_override_en;
+ reg_field_t vga_gain_accum_override;
+ reg_field_t vga_gain_tgt_adj_override_en;
+ reg_field_t vga_gain_tgt_adj_override;
+ reg_field_t ree_gen_sm_en_usb;
+ reg_field_t ree_gen_sm_en_periodic;
+ reg_field_t ana_en_epath_gen_ctrl_sm_usb;
+ reg_field_t ana_en_epath_gen_ctrl_sm_periodic;
+ reg_field_t rxda_eq_range_sel;
+ reg_field_t rxda_vga_sa_range_sel;
+ reg_field_t vco_ring_select;
+ reg_field_t cmnda_pll0_v2i_prog;
+ reg_field_t cmnda_pll0_coarse_prog;
+ reg_field_t cmnda_pll0_cp_gain;
+ reg_field_t cmnda_pll0_const_ndac_cntrl;
+ reg_field_t cmnda_pll0_const_pmos_cntrl;
+ reg_field_t cmnda_pll0_ptat_ndac_cntrl;
+ reg_field_t rxda_pi_iq_bias_trim;
+ reg_field_t rxda_pi_iq_pload_bias_trim;
+ reg_field_t rxda_pi_iq_pload_trim;
+ reg_field_t rxda_pi_e_bias_trim;
+ reg_field_t rxda_pi_e_pload_bias_trim;
+ reg_field_t rxda_pi_e_pload_trim;
+ reg_field_t rxda_pi_range_sel;
+ reg_field_t rxda_pi_cal_cm_trim;
+ reg_field_t xcvr_pll_en;
+ reg_field_t xcvr_link_reset_n;
+ reg_field_t xcvr_power_state_req;
+ reg_field_t xcvr_power_state_ack;
+ reg_field_t iso_pma_cmn_pll0_clk_datart1_div;
+ reg_field_t iso_pma_cmn_pll0_clk_datart0_div;
+ reg_field_t iso_pma_cmn_pll0_clk_en;
+
+ /* Set fields' labels */
+ cmnda_pll0_ip_div.label = "cmnda_pll0_ip_div";
+ cmnda_pll0_hs_sym_div_sel.label = "cmnda_pll0_hs_sym_div_sel";
+ cmn_pll0_fb_div_high_ovrd_en.label = "cmn_pll0_fb_div_high_ovrd_en";
+ cmnda_pll0_fb_div_high_out.label = "cmnda_pll0_fb_div_high_out";
+ cmn_pll0_fb_div_low_ovrd_en.label = "cmn_pll0_fb_div_low_ovrd_en";
+ cmnda_pll0_fb_div_low_out.label = "cmnda_pll0_fb_div_low_out";
+ cmn_pll_clk_osr.label = "cmn_pll_clk_osr";
+ cmn_pll_clk_div2_ratio.label = "cmn_pll_clk_div2_ratio";
+ cmn_pll_clk_div2_sel.label = "cmn_pll_clk_div2_sel";
+ rx_diag_smplr_osr.label = "rx_diag_smplr_osr";
+ rx_psc_a0.label = "rx_psc_a0";
+ rx_ree_pergcsm_eqenm_ph1.label = "rx_ree_pergcsm_eqenm_ph1";
+ rx_ree_pergcsm_eqenm_ph2.label = "rx_ree_pergcsm_eqenm_ph2";
+ vga_gain_accum_override_en.label = "vga_gain_accum_override_en";
+ vga_gain_accum_override.label = "vga_gain_accum_override";
+ vga_gain_tgt_adj_override_en.label = "vga_gain_tgt_adj_override_en";
+ vga_gain_tgt_adj_override.label = "vga_gain_tgt_adj_override";
+ ree_gen_sm_en_usb.label = "ree_gen_sm_en_usb";
+ ree_gen_sm_en_periodic.label = "ree_gen_sm_en_periodic";
+ ana_en_epath_gen_ctrl_sm_usb.label = "ana_en_epath_gen_ctrl_sm_usb";
+ ana_en_epath_gen_ctrl_sm_periodic.label =
+ "ana_en_epath_gen_ctrl_sm_periodic";
+ rxda_eq_range_sel.label = "rxda_eq_range_sel";
+ rxda_vga_sa_range_sel.label = "rxda_vga_sa_range_sel";
+ vco_ring_select.label = "vco_ring_select";
+ cmnda_pll0_v2i_prog.label = "cmnda_pll0_v2i_prog";
+ cmnda_pll0_coarse_prog.label = "cmnda_pll0_coarse_prog";
+ cmnda_pll0_cp_gain.label = "cmnda_pll0_cp_gain";
+ cmnda_pll0_const_ndac_cntrl.label = "cmnda_pll0_const_ndac_cntrl";
+ cmnda_pll0_const_pmos_cntrl.label = "cmnda_pll0_const_pmos_cntrl";
+ cmnda_pll0_ptat_ndac_cntrl.label = "cmnda_pll0_ptat_ndac_cntrl";
+ rxda_pi_iq_bias_trim.label = "rxda_pi_iq_bias_trim";
+ rxda_pi_iq_pload_bias_trim.label = "rxda_pi_iq_pload_bias_trim";
+ rxda_pi_iq_pload_trim.label = "rxda_pi_iq_pload_trim";
+ rxda_pi_e_bias_trim.label = "rxda_pi_e_bias_trim";
+ rxda_pi_e_pload_bias_trim.label = "rxda_pi_e_pload_bias_trim";
+ rxda_pi_e_pload_trim.label = "rxda_pi_e_pload_trim";
+ rxda_pi_range_sel.label = "rxda_pi_range_sel";
+ rxda_pi_cal_cm_trim.label = "rxda_pi_cal_cm_trim";
+ xcvr_pll_en.label = "xcvr_pll_en";
+ xcvr_link_reset_n.label = "xcvr_link_reset_n";
+ xcvr_power_state_req.label = "xcvr_power_state_req";
+ xcvr_power_state_ack.label = "xcvr_power_state_ack";
+ iso_pma_cmn_pll0_clk_datart1_div.label = "iso_pma_cmn_pll0_clk_datart1_div";
+ iso_pma_cmn_pll0_clk_datart0_div.label = "iso_pma_cmn_pll0_clk_datart0_div";
+ iso_pma_cmn_pll0_clk_en.label = "iso_pma_cmn_pll0_clk_en";
+
+ /* Set field position in a target register */
+ cmnda_pll0_ip_div.msb = 7;
+ cmnda_pll0_ip_div.lsb = 0;
+ cmnda_pll0_hs_sym_div_sel.msb = 9;
+ cmnda_pll0_hs_sym_div_sel.lsb = 8;
+ cmn_pll0_fb_div_high_ovrd_en.msb = 15;
+ cmn_pll0_fb_div_high_ovrd_en.lsb = 15;
+ cmnda_pll0_fb_div_high_out.msb = 9;
+ cmnda_pll0_fb_div_high_out.lsb = 0;
+ cmn_pll0_fb_div_low_ovrd_en.msb = 15;
+ cmn_pll0_fb_div_low_ovrd_en.lsb = 15;
+ cmnda_pll0_fb_div_low_out.msb = 9;
+ cmnda_pll0_fb_div_low_out.lsb = 0;
+ cmn_pll_clk_osr.msb = 2;
+ cmn_pll_clk_osr.lsb = 0;
+ cmn_pll_clk_div2_ratio.msb = 6;
+ cmn_pll_clk_div2_ratio.lsb = 4;
+ cmn_pll_clk_div2_sel.msb = 9;
+ cmn_pll_clk_div2_sel.lsb = 8;
+ rx_diag_smplr_osr.msb = 2;
+ rx_diag_smplr_osr.lsb = 0;
+ rx_psc_a0.msb = 15;
+ rx_psc_a0.lsb = 0;
+ rx_ree_pergcsm_eqenm_ph1.msb = 15;
+ rx_ree_pergcsm_eqenm_ph1.lsb = 0;
+ rx_ree_pergcsm_eqenm_ph2.msb = 15;
+ rx_ree_pergcsm_eqenm_ph2.lsb = 0;
+ vga_gain_accum_override_en.msb = 7;
+ vga_gain_accum_override_en.lsb = 7;
+ vga_gain_accum_override.msb = 4;
+ vga_gain_accum_override.lsb = 0;
+ vga_gain_tgt_adj_override_en.msb = 15;
+ vga_gain_tgt_adj_override_en.lsb = 15;
+ vga_gain_tgt_adj_override.msb = 12;
+ vga_gain_tgt_adj_override.lsb = 8;
+ ree_gen_sm_en_usb.msb = 3;
+ ree_gen_sm_en_usb.lsb = 0;
+ ree_gen_sm_en_periodic.msb = 11;
+ ree_gen_sm_en_periodic.lsb = 8;
+ ana_en_epath_gen_ctrl_sm_usb.msb = 7;
+ ana_en_epath_gen_ctrl_sm_usb.lsb = 4;
+ ana_en_epath_gen_ctrl_sm_periodic.msb = 15;
+ ana_en_epath_gen_ctrl_sm_periodic.lsb = 12;
+ rxda_eq_range_sel.msb = 2;
+ rxda_eq_range_sel.lsb = 0;
+ rxda_vga_sa_range_sel.msb = 6;
+ rxda_vga_sa_range_sel.lsb = 4;
+ vco_ring_select.msb = 12;
+ vco_ring_select.lsb = 12;
+ cmnda_pll0_v2i_prog.msb = 5;
+ cmnda_pll0_v2i_prog.lsb = 4;
+ cmnda_pll0_coarse_prog.msb = 2;
+ cmnda_pll0_coarse_prog.lsb = 0;
+ cmnda_pll0_cp_gain.msb = 8;
+ cmnda_pll0_cp_gain.lsb = 0;
+ cmnda_pll0_const_ndac_cntrl.msb = 11;
+ cmnda_pll0_const_ndac_cntrl.lsb = 8;
+ cmnda_pll0_const_pmos_cntrl.msb = 7;
+ cmnda_pll0_const_pmos_cntrl.lsb = 0;
+ cmnda_pll0_ptat_ndac_cntrl.msb = 5;
+ cmnda_pll0_ptat_ndac_cntrl.lsb = 0;
+ rxda_pi_iq_bias_trim.msb = 14;
+ rxda_pi_iq_bias_trim.lsb = 12;
+ rxda_pi_iq_pload_bias_trim.msb = 10;
+ rxda_pi_iq_pload_bias_trim.lsb = 8;
+ rxda_pi_iq_pload_trim.msb = 7;
+ rxda_pi_iq_pload_trim.lsb = 0;
+ rxda_pi_e_bias_trim.msb = 14;
+ rxda_pi_e_bias_trim.lsb = 12;
+ rxda_pi_e_pload_bias_trim.msb = 10;
+ rxda_pi_e_pload_bias_trim.lsb = 8;
+ rxda_pi_e_pload_trim.msb = 7;
+ rxda_pi_e_pload_trim.lsb = 0;
+ rxda_pi_range_sel.msb = 11;
+ rxda_pi_range_sel.lsb = 8;
+ rxda_pi_cal_cm_trim.msb = 7;
+ rxda_pi_cal_cm_trim.lsb = 0;
+ xcvr_pll_en.msb = 12;
+ xcvr_pll_en.lsb = 12;
+ xcvr_link_reset_n.msb = 13;
+ xcvr_link_reset_n.lsb = 13;
+ xcvr_power_state_req.msb = 3;
+ xcvr_power_state_req.lsb = 0;
+ xcvr_power_state_ack.msb = 7;
+ xcvr_power_state_ack.lsb = 4;
+ iso_pma_cmn_pll0_clk_datart1_div.msb = 14;
+ iso_pma_cmn_pll0_clk_datart1_div.lsb = 11;
+ iso_pma_cmn_pll0_clk_datart0_div.msb = 10;
+ iso_pma_cmn_pll0_clk_datart0_div.lsb = 7;
+ iso_pma_cmn_pll0_clk_en.msb = 5;
+ iso_pma_cmn_pll0_clk_en.lsb = 5;
+
+ pr_info("pma_pll_config() Configuring PLL0 ...\n");
+
+ if (tmds_bit_clk_ratio == TMDS_BIT_CLOCK_RATIO_1_10) {
+ if (inside_f(rx_clk_freq, 18750, 37500)) {
+ set_field_value(&cmnda_pll0_ip_div, 0x1);
+ set_field_value(&cmnda_pll0_hs_sym_div_sel, 0x0);
+ set_field_value(&cmn_pll0_fb_div_high_ovrd_en, 0x1);
+ set_field_value(&cmnda_pll0_fb_div_high_out, 0x1E);
+ set_field_value(&cmn_pll0_fb_div_low_ovrd_en, 0x1);
+ set_field_value(&cmnda_pll0_fb_div_low_out, 0x7E);
+ set_field_value(&rx_diag_smplr_osr, 0x4);
+ set_field_value(&rx_psc_a0, 0x8BF5);
+ set_field_value(&rx_ree_pergcsm_eqenm_ph1, 0x0080);
+ set_field_value(&rx_ree_pergcsm_eqenm_ph2, 0x0080);
+ set_field_value(&vga_gain_accum_override_en, 0x1);
+ set_field_value(&vga_gain_accum_override, 0x1A);
+ set_field_value(&vga_gain_tgt_adj_override_en, 0x0);
+ set_field_value(&vga_gain_tgt_adj_override, 0x00);
+ set_field_value(&ree_gen_sm_en_usb, 0x1);
+ set_field_value(&ree_gen_sm_en_periodic, 0x1);
+ set_field_value(&ana_en_epath_gen_ctrl_sm_usb, 0x0);
+ set_field_value(&ana_en_epath_gen_ctrl_sm_periodic,
+ 0x0);
+ set_field_value(&rxda_eq_range_sel, 0x1);
+ set_field_value(&rxda_vga_sa_range_sel, 0x2);
+ switch (clk_ratio) {
+ case CLK_RATIO_1_1:
+ set_field_value(&cmn_pll_clk_osr, 0x4);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x0);
+ break;
+ case CLK_RATIO_5_4:
+ set_field_value(&cmn_pll_clk_osr, 0x4);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x4);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_3_2:
+ set_field_value(&cmn_pll_clk_osr, 0x4);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x5);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_2_1:
+ set_field_value(&cmn_pll_clk_osr, 0x4);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x3);
+ break;
+ case CLK_RATIO_1_2:
+ set_field_value(&cmn_pll_clk_osr, 0x4);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_5_8:
+ set_field_value(&cmn_pll_clk_osr, 0x4);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x1);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_3_4:
+ set_field_value(&cmn_pll_clk_osr, 0x4);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x2);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ }
+ } else if (inside_f(rx_clk_freq, 37500, 75000)) {
+ set_field_value(&cmnda_pll0_ip_div, 0x1);
+ set_field_value(&cmnda_pll0_hs_sym_div_sel, 0x0);
+ set_field_value(&cmn_pll0_fb_div_high_ovrd_en, 0x1);
+ set_field_value(&cmnda_pll0_fb_div_high_out, 0x0E);
+ set_field_value(&cmn_pll0_fb_div_low_ovrd_en, 0x1);
+ set_field_value(&cmnda_pll0_fb_div_low_out, 0x3E);
+ set_field_value(&rx_diag_smplr_osr, 0x3);
+ set_field_value(&rx_psc_a0, 0x8BF5);
+ set_field_value(&rx_ree_pergcsm_eqenm_ph1, 0x0080);
+ set_field_value(&rx_ree_pergcsm_eqenm_ph2, 0x0080);
+ set_field_value(&vga_gain_accum_override_en, 0x1);
+ set_field_value(&vga_gain_accum_override, 0x1A);
+ set_field_value(&vga_gain_tgt_adj_override_en, 0x0);
+ set_field_value(&vga_gain_tgt_adj_override, 0x00);
+ set_field_value(&ree_gen_sm_en_usb, 0x1);
+ set_field_value(&ree_gen_sm_en_periodic, 0x1);
+ set_field_value(&ana_en_epath_gen_ctrl_sm_usb, 0x0);
+ set_field_value(&ana_en_epath_gen_ctrl_sm_periodic,
+ 0x0);
+ set_field_value(&rxda_eq_range_sel, 0x1);
+ set_field_value(&rxda_vga_sa_range_sel, 0x2);
+ switch (clk_ratio) {
+ case CLK_RATIO_1_1:
+ set_field_value(&cmn_pll_clk_osr, 0x3);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x0);
+ break;
+ case CLK_RATIO_5_4:
+ set_field_value(&cmn_pll_clk_osr, 0x3);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x4);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_3_2:
+ set_field_value(&cmn_pll_clk_osr, 0x3);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x5);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_2_1:
+ set_field_value(&cmn_pll_clk_osr, 0x3);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x3);
+ break;
+ case CLK_RATIO_1_2:
+ set_field_value(&cmn_pll_clk_osr, 0x3);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_5_8:
+ set_field_value(&cmn_pll_clk_osr, 0x3);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x1);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_3_4:
+ set_field_value(&cmn_pll_clk_osr, 0x3);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x2);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ }
+ } else if (inside_f(rx_clk_freq, 75000, 150000)) {
+ set_field_value(&cmnda_pll0_ip_div, 0x1);
+ set_field_value(&cmnda_pll0_hs_sym_div_sel, 0x0);
+ set_field_value(&cmn_pll0_fb_div_high_ovrd_en, 0x1);
+ set_field_value(&cmnda_pll0_fb_div_high_out, 0x0A);
+ set_field_value(&cmn_pll0_fb_div_low_ovrd_en, 0x1);
+ set_field_value(&cmnda_pll0_fb_div_low_out, 0x1A);
+ set_field_value(&rx_diag_smplr_osr, 0x2);
+ set_field_value(&rx_psc_a0, 0x8BF5);
+ set_field_value(&rx_ree_pergcsm_eqenm_ph1, 0x0080);
+ set_field_value(&rx_ree_pergcsm_eqenm_ph2, 0x0080);
+ set_field_value(&vga_gain_accum_override_en, 0x1);
+ set_field_value(&vga_gain_accum_override, 0x1A);
+ set_field_value(&vga_gain_tgt_adj_override_en, 0x0);
+ set_field_value(&vga_gain_tgt_adj_override, 0x00);
+ set_field_value(&ree_gen_sm_en_usb, 0x1);
+ set_field_value(&ree_gen_sm_en_periodic, 0x1);
+ set_field_value(&ana_en_epath_gen_ctrl_sm_usb, 0x0);
+ set_field_value(&ana_en_epath_gen_ctrl_sm_periodic,
+ 0x0);
+ set_field_value(&rxda_eq_range_sel, 0x1);
+ set_field_value(&rxda_vga_sa_range_sel, 0x2);
+ switch (clk_ratio) {
+ case CLK_RATIO_1_1:
+ set_field_value(&cmn_pll_clk_osr, 0x2);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x0);
+ break;
+ case CLK_RATIO_5_4:
+ set_field_value(&cmn_pll_clk_osr, 0x2);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x4);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_3_2:
+ set_field_value(&cmn_pll_clk_osr, 0x2);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x5);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_2_1:
+ set_field_value(&cmn_pll_clk_osr, 0x2);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x3);
+ break;
+ case CLK_RATIO_1_2:
+ set_field_value(&cmn_pll_clk_osr, 0x2);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_5_8:
+ set_field_value(&cmn_pll_clk_osr, 0x2);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x1);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_3_4:
+ set_field_value(&cmn_pll_clk_osr, 0x2);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x2);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ }
+ } else if (inside_f(rx_clk_freq, 150000, 300000)) {
+ set_field_value(&cmnda_pll0_ip_div, 0x2);
+ set_field_value(&cmnda_pll0_hs_sym_div_sel, 0x0);
+ set_field_value(&cmn_pll0_fb_div_high_ovrd_en, 0x1);
+ set_field_value(&cmnda_pll0_fb_div_high_out, 0x0A);
+ set_field_value(&cmn_pll0_fb_div_low_ovrd_en, 0x1);
+ set_field_value(&cmnda_pll0_fb_div_low_out, 0x1A);
+ set_field_value(&rx_diag_smplr_osr, 0x1);
+ set_field_value(&rx_psc_a0, 0x8BF5);
+ set_field_value(&rx_ree_pergcsm_eqenm_ph1, 0x0080);
+ set_field_value(&rx_ree_pergcsm_eqenm_ph2, 0x0080);
+ set_field_value(&vga_gain_accum_override_en, 0x1);
+ set_field_value(&vga_gain_accum_override, 0x1A);
+ set_field_value(&vga_gain_tgt_adj_override_en, 0x0);
+ set_field_value(&vga_gain_tgt_adj_override, 0x00);
+ set_field_value(&ree_gen_sm_en_usb, 0x1);
+ set_field_value(&ree_gen_sm_en_periodic, 0x1);
+ set_field_value(&ana_en_epath_gen_ctrl_sm_usb, 0x0);
+ set_field_value(&ana_en_epath_gen_ctrl_sm_periodic,
+ 0x0);
+ set_field_value(&rxda_eq_range_sel, 0x2);
+ set_field_value(&rxda_vga_sa_range_sel, 0x3);
+ switch (clk_ratio) {
+ case CLK_RATIO_1_1:
+ set_field_value(&cmn_pll_clk_osr, 0x1);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x0);
+ break;
+ case CLK_RATIO_5_4:
+ set_field_value(&cmn_pll_clk_osr, 0x1);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x4);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_3_2:
+ set_field_value(&cmn_pll_clk_osr, 0x1);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x5);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_2_1:
+ set_field_value(&cmn_pll_clk_osr, 0x1);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x3);
+ break;
+ case CLK_RATIO_1_2:
+ set_field_value(&cmn_pll_clk_osr, 0x1);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_5_8:
+ set_field_value(&cmn_pll_clk_osr, 0x1);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x1);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_3_4:
+ set_field_value(&cmn_pll_clk_osr, 0x1);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x2);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ }
+ } else if (inside_f(rx_clk_freq, 300000, 340000)) {
+ set_field_value(&cmnda_pll0_ip_div, 0x3);
+ set_field_value(&cmnda_pll0_hs_sym_div_sel, 0x0);
+ set_field_value(&cmn_pll0_fb_div_high_ovrd_en, 0x1);
+ set_field_value(&cmnda_pll0_fb_div_high_out, 0x0A);
+ set_field_value(&cmn_pll0_fb_div_low_ovrd_en, 0x1);
+ set_field_value(&cmnda_pll0_fb_div_low_out, 0x10);
+ set_field_value(&rx_diag_smplr_osr, 0x0);
+ set_field_value(&rx_psc_a0, 0x8BF5);
+ set_field_value(&rx_ree_pergcsm_eqenm_ph1, 0x0080);
+ set_field_value(&rx_ree_pergcsm_eqenm_ph2, 0x0080);
+ set_field_value(&vga_gain_accum_override_en, 0x1);
+ set_field_value(&vga_gain_accum_override, 0x1A);
+ set_field_value(&vga_gain_tgt_adj_override_en, 0x0);
+ set_field_value(&vga_gain_tgt_adj_override, 0x00);
+ set_field_value(&ree_gen_sm_en_usb, 0x1);
+ set_field_value(&ree_gen_sm_en_periodic, 0x1);
+ set_field_value(&ana_en_epath_gen_ctrl_sm_usb, 0x0);
+ set_field_value(&ana_en_epath_gen_ctrl_sm_periodic,
+ 0x0);
+ set_field_value(&rxda_eq_range_sel, 0x3);
+ set_field_value(&rxda_vga_sa_range_sel, 0x3);
+ switch (clk_ratio) {
+ case CLK_RATIO_1_1:
+ set_field_value(&cmn_pll_clk_osr, 0x0);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x0);
+ break;
+ case CLK_RATIO_5_4:
+ set_field_value(&cmn_pll_clk_osr, 0x0);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x4);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_3_2:
+ set_field_value(&cmn_pll_clk_osr, 0x0);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x5);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_2_1:
+ set_field_value(&cmn_pll_clk_osr, 0x0);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x3);
+ break;
+ case CLK_RATIO_1_2:
+ set_field_value(&cmn_pll_clk_osr, 0x0);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_5_8:
+ set_field_value(&cmn_pll_clk_osr, 0x0);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x1);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_3_4:
+ set_field_value(&cmn_pll_clk_osr, 0x0);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x2);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ }
+ } else
+ pr_err("TMDS clock frequency (%d KHz) is out of range\n", rx_clk_freq);
+
+ } else { /* TMDS_BIT_CLOCK_RATIO_1_40 */
+ if (inside_f(rx_clk_freq, 85000, 150000)) {
+ set_field_value(&cmnda_pll0_ip_div, 0x1);
+ set_field_value(&cmnda_pll0_hs_sym_div_sel, 0x0);
+ set_field_value(&cmn_pll0_fb_div_high_ovrd_en, 0x1);
+ set_field_value(&cmnda_pll0_fb_div_high_out, 0x0A);
+ set_field_value(&cmn_pll0_fb_div_low_ovrd_en, 0x1);
+ set_field_value(&cmnda_pll0_fb_div_low_out, 0x1A);
+ set_field_value(&rx_diag_smplr_osr, 0x0);
+ set_field_value(&rx_psc_a0, 0x8BFD);
+ set_field_value(&rx_ree_pergcsm_eqenm_ph1, 0x019F);
+ set_field_value(&rx_ree_pergcsm_eqenm_ph2, 0x019F);
+ set_field_value(&vga_gain_accum_override_en, 0x0);
+ set_field_value(&vga_gain_accum_override, 0x01);
+ set_field_value(&vga_gain_tgt_adj_override_en, 0x0);
+ set_field_value(&vga_gain_tgt_adj_override, 0x1F);
+ set_field_value(&ree_gen_sm_en_usb, 0x1);
+ set_field_value(&ree_gen_sm_en_periodic, 0x1);
+ set_field_value(&ana_en_epath_gen_ctrl_sm_usb, 0x0);
+ set_field_value(&ana_en_epath_gen_ctrl_sm_periodic, 0x1);
+ set_field_value(&rxda_eq_range_sel, 0x3);
+ set_field_value(&rxda_vga_sa_range_sel, 0x3);
+ switch (clk_ratio) {
+ case CLK_RATIO_1_1:
+ set_field_value(&cmn_pll_clk_osr, 0x00);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x0);
+ break;
+ case CLK_RATIO_5_4:
+ set_field_value(&cmn_pll_clk_osr, 0x00);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x4);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_3_2:
+ set_field_value(&cmn_pll_clk_osr, 0x00);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x5);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_2_1:
+ set_field_value(&cmn_pll_clk_osr, 0x00);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x3);
+ break;
+ case CLK_RATIO_1_2:
+ set_field_value(&cmn_pll_clk_osr, 0x00);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x0);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_5_8:
+ set_field_value(&cmn_pll_clk_osr, 0x00);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x1);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ case CLK_RATIO_3_4:
+ set_field_value(&cmn_pll_clk_osr, 0x00);
+ set_field_value(&cmn_pll_clk_div2_ratio, 0x2);
+ set_field_value(&cmn_pll_clk_div2_sel, 0x1);
+ break;
+ }
+ } else
+ pr_err("pma_pll_config() *E: TMDS clock frequency (%d kHz) is out of range\n",
+ rx_clk_freq);
+ }
+
+ vco_freq_khz =
+ (2048 * (u64) rx_clk_freq * (1 << cmn_pll_clk_osr.value) * tmds_bit_clk_ratio) / 2047;
+
+ pr_info("VCO frequency (refclk: %d kHz, TMDS clk: %d kHz, OSR: %0d, tmds_bit_clk_ratio: %d) equals %llu kHz\n",
+ REFCLK_FREQ_KHZ, rx_clk_freq, 1 << cmn_pll_clk_osr.value,
+ tmds_bit_clk_ratio, vco_freq_khz);
+
+ if (inside_f(vco_freq_khz, 3000000, 3400000 - 1000)) {
+ set_field_value(&vco_ring_select, 0x0);
+ set_field_value(&cmnda_pll0_v2i_prog, 0x0);
+ set_field_value(&cmnda_pll0_coarse_prog, 0x3);
+ switch (cmnda_pll0_fb_div_low_out.value) {
+ case 0x7E:
+ set_field_value(&cmnda_pll0_cp_gain, 0x78);
+ break;
+ case 0x3E:
+ set_field_value(&cmnda_pll0_cp_gain, 0x78);
+ break;
+ case 0x10:
+ set_field_value(&cmnda_pll0_cp_gain, 0x58);
+ break;
+ default:
+ set_field_value(&cmnda_pll0_cp_gain, 0x78);
+ }
+ set_field_value(&cmnda_pll0_const_ndac_cntrl, 0x0);
+ set_field_value(&cmnda_pll0_const_pmos_cntrl, 0x04);
+ set_field_value(&cmnda_pll0_ptat_ndac_cntrl, 0x0D);
+ } else if (inside_f(vco_freq_khz, 3400000, 3687000 - 1000)) {
+ set_field_value(&vco_ring_select, 0x1);
+ set_field_value(&cmnda_pll0_v2i_prog, 0x1);
+ set_field_value(&cmnda_pll0_coarse_prog, 0x7);
+ switch (cmnda_pll0_fb_div_low_out.value) {
+ case 0x7E:
+ set_field_value(&cmnda_pll0_cp_gain, 0x68);
+ break;
+ case 0x3E:
+ set_field_value(&cmnda_pll0_cp_gain, 0x68);
+ break;
+ case 0x10:
+ set_field_value(&cmnda_pll0_cp_gain, 0x59);
+ break;
+ default:
+ set_field_value(&cmnda_pll0_cp_gain, 0x68);
+ }
+ set_field_value(&cmnda_pll0_const_ndac_cntrl, 0x0);
+ set_field_value(&cmnda_pll0_const_pmos_cntrl, 0x8E);
+ set_field_value(&cmnda_pll0_ptat_ndac_cntrl, 0x2F);
+ } else if (inside_f(vco_freq_khz, 3687000, 3999000 - 1000)) {
+ set_field_value(&vco_ring_select, 0x1);
+ set_field_value(&cmnda_pll0_v2i_prog, 0x1);
+ set_field_value(&cmnda_pll0_coarse_prog, 0x7);
+ set_field_value(&cmnda_pll0_cp_gain, 0x64);
+ set_field_value(&cmnda_pll0_const_ndac_cntrl, 0x0);
+ set_field_value(&cmnda_pll0_const_pmos_cntrl, 0x8E);
+ set_field_value(&cmnda_pll0_ptat_ndac_cntrl, 0x2F);
+ } else if (inside_f(vco_freq_khz, 3999000, 4337000 - 1000)) {
+ set_field_value(&vco_ring_select, 0x1);
+ set_field_value(&cmnda_pll0_v2i_prog, 0x1);
+ set_field_value(&cmnda_pll0_coarse_prog, 0x7);
+ set_field_value(&cmnda_pll0_cp_gain, 0x56);
+ set_field_value(&cmnda_pll0_const_ndac_cntrl, 0x0);
+ set_field_value(&cmnda_pll0_const_pmos_cntrl, 0x8E);
+ set_field_value(&cmnda_pll0_ptat_ndac_cntrl, 0x2F);
+ } else if (inside_f(vco_freq_khz, 4337000, 4703000 - 1000)) {
+ set_field_value(&vco_ring_select, 0x1);
+ set_field_value(&cmnda_pll0_v2i_prog, 0x1);
+ set_field_value(&cmnda_pll0_coarse_prog, 0x7);
+ set_field_value(&cmnda_pll0_cp_gain, 0x58);
+ set_field_value(&cmnda_pll0_const_ndac_cntrl, 0x0);
+ set_field_value(&cmnda_pll0_const_pmos_cntrl, 0x8E);
+ set_field_value(&cmnda_pll0_ptat_ndac_cntrl, 0x2F);
+ } else if (inside_f(vco_freq_khz, 4703000, 5101000 - 1000)) {
+ set_field_value(&vco_ring_select, 0x1);
+ set_field_value(&cmnda_pll0_v2i_prog, 0x1);
+ set_field_value(&cmnda_pll0_coarse_prog, 0x7);
+ set_field_value(&cmnda_pll0_cp_gain, 0x54);
+ set_field_value(&cmnda_pll0_const_ndac_cntrl, 0x0);
+ set_field_value(&cmnda_pll0_const_pmos_cntrl, 0x04);
+ set_field_value(&cmnda_pll0_ptat_ndac_cntrl, 0x0D);
+ } else if (inside_f(vco_freq_khz, 5101000, 5532000 - 1000)) {
+ set_field_value(&vco_ring_select, 0x1);
+ set_field_value(&cmnda_pll0_v2i_prog, 0x1);
+ set_field_value(&cmnda_pll0_coarse_prog, 0x7);
+ set_field_value(&cmnda_pll0_cp_gain, 0x49);
+ set_field_value(&cmnda_pll0_const_ndac_cntrl, 0x0);
+ set_field_value(&cmnda_pll0_const_pmos_cntrl, 0x04);
+ set_field_value(&cmnda_pll0_ptat_ndac_cntrl, 0x0D);
+ } else if (inside_f(vco_freq_khz, 5532000, 6000000 - 1000)) {
+ set_field_value(&vco_ring_select, 0x1);
+ set_field_value(&cmnda_pll0_v2i_prog, 0x1);
+ set_field_value(&cmnda_pll0_coarse_prog, 0x7);
+ set_field_value(&cmnda_pll0_cp_gain, 0x3E);
+ set_field_value(&cmnda_pll0_const_ndac_cntrl, 0x0);
+ set_field_value(&cmnda_pll0_const_pmos_cntrl, 0x04);
+ set_field_value(&cmnda_pll0_ptat_ndac_cntrl, 0x0D);
+ } else
+ pr_err("%s VCO frequency (%llu KHz) is out of range\n", __func__, vco_freq_khz);
+
+ if (inside_f(vco_freq_khz, 3000000, 4000000)) {
+ set_field_value(&rxda_pi_iq_bias_trim, 0x5);
+ set_field_value(&rxda_pi_iq_pload_bias_trim, 0x2);
+ set_field_value(&rxda_pi_iq_pload_trim, 0x3F);
+ set_field_value(&rxda_pi_e_bias_trim, 0x5);
+ set_field_value(&rxda_pi_e_pload_bias_trim, 0x2);
+ set_field_value(&rxda_pi_e_pload_trim, 0x3F);
+ set_field_value(&rxda_pi_range_sel, 0x2);
+ set_field_value(&rxda_pi_cal_cm_trim, 0x00);
+ } else if (inside_f(vco_freq_khz, 4000000, 6000000)) {
+ set_field_value(&rxda_pi_iq_bias_trim, 0x5);
+ set_field_value(&rxda_pi_iq_pload_bias_trim, 0x4);
+ set_field_value(&rxda_pi_iq_pload_trim, 0x3F);
+ set_field_value(&rxda_pi_e_bias_trim, 0x5);
+ set_field_value(&rxda_pi_e_pload_bias_trim, 0x4);
+ set_field_value(&rxda_pi_e_pload_trim, 0x3F);
+ set_field_value(&rxda_pi_range_sel, 0x3);
+ set_field_value(&rxda_pi_cal_cm_trim, 0x00);
+ }
+ set_field_value(&xcvr_pll_en, 0x1);
+ set_field_value(&xcvr_link_reset_n, 0x0);
+ set_field_value(&xcvr_power_state_req, 0x0);
+ set_field_value(&iso_pma_cmn_pll0_clk_datart1_div, 0x1);
+ set_field_value(&iso_pma_cmn_pll0_clk_datart0_div, 0x2);
+ set_field_value(&iso_pma_cmn_pll0_clk_en, 0x1);
+
+ /*******************************************************
+ * Register setting
+ ********************************************************/
+
+ /* CMN_DIAG_PLL0_INCLK_CTRL */
+ reg_val = set_reg_value(cmnda_pll0_ip_div);
+ reg_val |= set_reg_value(cmnda_pll0_hs_sym_div_sel);
+ write16(state, CMN_DIAG_PLL0_INCLK_CTRL_ADDR, reg_val);
+
+ /* CMN_DIAG_PLL0_FBH_OVRD */
+ reg_val = set_reg_value(cmn_pll0_fb_div_high_ovrd_en);
+ reg_val |= set_reg_value(cmnda_pll0_fb_div_high_out);
+ write16(state, CMN_DIAG_PLL0_FBH_OVRD_ADDR, reg_val);
+
+ /* CMN_DIAG_PLL0_FBL_OVRD */
+ reg_val = set_reg_value(cmn_pll0_fb_div_low_ovrd_en);
+ reg_val |= set_reg_value(cmnda_pll0_fb_div_low_out);
+ write16(state, CMN_DIAG_PLL0_FBL_OVRD_ADDR, reg_val);
+
+ /* CMN_PLL0_DIV2SEL_OSR_CTRL */
+ reg_val = set_reg_value(cmn_pll_clk_osr);
+ reg_val |= set_reg_value(cmn_pll_clk_div2_ratio);
+ reg_val |= set_reg_value(cmn_pll_clk_div2_sel);
+ write16(state, CMN_PLL0_DIV2SEL_OSR_CTRL_ADDR, reg_val);
+
+ /* RX_DIAG_SMPLR_OSR */
+ reg_val = set_reg_value(rx_diag_smplr_osr);
+ multi_write16(state, RX_DIAG_SMPLR_OSR_ADDR, reg_val);
+
+ /* RX_PSC_A0 */
+ reg_val = set_reg_value(rx_psc_a0);
+ multi_write16(state, RX_PSC_A0_ADDR, reg_val);
+
+ /* RX_REE_PERGCSM_EQENM_PH1 */
+ reg_val = set_reg_value(rx_ree_pergcsm_eqenm_ph1);
+ multi_write16(state, RX_REE_PERGCSM_EQENM_PH1_ADDR, reg_val);
+
+ /* RX_REE_PERGCSM_EQENM_PH1 */
+ reg_val = set_reg_value(rx_ree_pergcsm_eqenm_ph2);
+ multi_write16(state, RX_REE_PERGCSM_EQENM_PH2_ADDR, reg_val);
+
+ /* RX_REE_VGA_GAIN_OVRD */
+ reg_val = set_reg_value(vga_gain_accum_override_en);
+ reg_val |= set_reg_value(vga_gain_accum_override);
+ reg_val |= set_reg_value(vga_gain_tgt_adj_override_en);
+ reg_val |= set_reg_value(vga_gain_tgt_adj_override);
+ multi_write16(state, RX_REE_VGA_GAIN_OVRD_ADDR, reg_val);
+
+ /* RX_REE_SMGM_CTRL1 */
+ reg_val = set_reg_value(ree_gen_sm_en_usb);
+ reg_val |= set_reg_value(ree_gen_sm_en_periodic);
+ reg_val |= set_reg_value(ana_en_epath_gen_ctrl_sm_usb);
+ reg_val |= set_reg_value(ana_en_epath_gen_ctrl_sm_periodic);
+ multi_write16(state, RX_REE_SMGM_CTRL1_ADDR, reg_val);
+
+ /* RX_DIAG_DFE_CTRL2 */
+ reg_val = set_reg_value(rxda_eq_range_sel);
+ reg_val |= set_reg_value(rxda_vga_sa_range_sel);
+ multi_write16(state, RX_DIAG_DFE_CTRL2_ADDR, reg_val);
+
+ /* CMN_PLLSM0_USER_DEF_CTRL */
+ reg_val = set_reg_value(vco_ring_select);
+ write16(state, CMN_PLLSM0_USER_DEF_CTRL_ADDR, reg_val);
+
+ /* CMN_DIAG_PLL0_V2I_TUNE */
+ reg_val = set_reg_value(cmnda_pll0_v2i_prog);
+ reg_val |= set_reg_value(cmnda_pll0_coarse_prog);
+ write16(state, CMN_DIAG_PLL0_V2I_TUNE_ADDR, reg_val);
+
+ /* CMN_DIAG_PLL0_CP_TUNE */
+ reg_val = set_reg_value(cmnda_pll0_cp_gain);
+ write16(state, CMN_DIAG_PLL0_CP_TUNE_ADDR, reg_val);
+
+ /* CMN_DIAG_PLL0_PTATIS_TUNE1 */
+ reg_val = set_reg_value(cmnda_pll0_const_ndac_cntrl);
+ reg_val |= set_reg_value(cmnda_pll0_const_pmos_cntrl);
+ write16(state, CMN_DIAG_PLL0_PTATIS_TUNE1_ADDR, reg_val);
+
+ /* CMN_DIAG_PLL0_PTATIS_TUNE2 */
+ reg_val = set_reg_value(cmnda_pll0_ptat_ndac_cntrl);
+ write16(state, CMN_DIAG_PLL0_PTATIS_TUNE2_ADDR, reg_val);
+
+ /* RX_DIAG_ILL_IQ_TRIM0 */
+ reg_val = set_reg_value(rxda_pi_iq_bias_trim);
+ reg_val |= set_reg_value(rxda_pi_iq_pload_bias_trim);
+ reg_val |= set_reg_value(rxda_pi_iq_pload_trim);
+ write16(state, RX_DIAG_ILL_IQ_TRIM0_ADDR, reg_val);
+
+ /* RX_DIAG_ILL_E_TRIM0 */
+ reg_val = set_reg_value(rxda_pi_e_bias_trim);
+ reg_val |= set_reg_value(rxda_pi_e_pload_bias_trim);
+ reg_val |= set_reg_value(rxda_pi_e_pload_trim);
+ write16(state, RX_DIAG_ILL_E_TRIM0_ADDR, reg_val);
+
+ /* RX_DIAG_ILL_IQE_TRIM2 */
+ reg_val = set_reg_value(rxda_pi_range_sel);
+ reg_val |= set_reg_value(rxda_pi_cal_cm_trim);
+ write16(state, RX_DIAG_ILL_IQE_TRIM2_ADDR, reg_val);
+
+ /* Enable PLL */
+ /* PHY_MODE_CTL */
+ reg_val = set_reg_value(xcvr_pll_en);
+ reg_val |= set_reg_value(xcvr_link_reset_n);
+ reg_val |= set_reg_value(xcvr_power_state_req);
+ write16(state, PHY_MODE_CTL_ADDR, reg_val);
+
+ /* Wait for PLL0 ready: */
+ /* PHY_PMA_CMN_CTRL2 */
+ for (i = 0; i < 20; i++) {
+ if (read16(state, PHY_PMA_CMN_CTRL2_ADDR) & (1 << 0))
+ break;
+ msleep(10);
+ }
+ if (i == 20) {
+ pr_err("pma_pll_ready failed\n");
+ return -1;
+ }
+
+ /* Turn on output clocks: */
+ /* PHY_PMA_CMN_CTRL2 */
+ reg_val = set_reg_value(iso_pma_cmn_pll0_clk_datart1_div);
+ reg_val |= set_reg_value(iso_pma_cmn_pll0_clk_datart0_div);
+ reg_val |= set_reg_value(iso_pma_cmn_pll0_clk_en);
+ write16(state, PHY_PMA_CMN_CTRL2_ADDR, reg_val);
+
+ if (data_rate_change) {
+ pr_info("pma_pll_config() Disable Rx Eq Training\n");
+ for (i = 0; i < 3; i++) {
+ reg_val =
+ read16(state, PHY_PMA_XCVR_CTRL_ADDR | (i << 6));
+ reg_val &= 0xFFEF;
+ write16(state, PHY_PMA_XCVR_CTRL_ADDR | (i << 6), reg_val);
+ }
+ }
+ /* Get current power state: */
+ /* PHY_MODE_CTL */
+ reg_val = read16(state, PHY_MODE_CTL_ADDR);
+ reg_val &= 0x00F0;
+ pr_info("pma_pll_config() Current power state: 0x%02X\n", (reg_val >> 4));
+
+ /* Deassert link reset: */
+ /* PHY_MODE_CTL */
+ pr_info("pma_pll_config() Deassert link reset\n");
+ set_field_value(&xcvr_link_reset_n, 0x1);
+ reg_val |= set_reg_value(xcvr_pll_en);
+ reg_val |= set_reg_value(xcvr_link_reset_n);
+ write16(state, PHY_MODE_CTL_ADDR, reg_val);
+
+ /* Wait for xcvr_psm_ready for all the lanes */
+ loop = 0;
+ do {
+ reg_val = (1 << 13);
+ for (i = 0; i < 3; i++) {
+ reg_val &= read16(state, PHY_PMA_XCVR_CTRL_ADDR | (i << 6)) & (1 << 13);
+ pr_info("pma_pll_config() xcvr_psm_ready(%0d): 0x%0X\n", i, reg_val >> 13);
+ }
+ msleep(10);
+ loop++;
+ } while (!reg_val && loop < 20);
+ /* Timeout */
+ if (loop == 20) {
+ pr_err("pma_pll_config() Waiting for xcvr_psm_ready... failed\n");
+ return -1;
+ }
+
+ /* Set A0 power state: */
+ /* PHY_MODE_CTL */
+ set_field_value(&xcvr_power_state_req, 0x1);
+ reg_val = set_reg_value(xcvr_pll_en);
+ reg_val |= set_reg_value(xcvr_link_reset_n);
+ reg_val |= set_reg_value(xcvr_power_state_req);
+ write16(state, PHY_MODE_CTL_ADDR, reg_val);
+ pr_info("pma_pll_config() Requested A0 power mode\n");
+
+ /* Wait for A0 power mode acknowledged: */
+ /* PHY_MODE_CTL */
+ set_field_value(&xcvr_power_state_ack, 0x1);
+
+ for (i = 0; i < 20; i++) {
+ if (((read16(state, PHY_MODE_CTL_ADDR) & 0x00F0) == set_reg_value(xcvr_power_state_ack)))
+ break;
+ msleep(10);
+ }
+ if (i == 20) {
+ pr_err("Waiting for A0 power mode acknowledged failed\n");
+ return -1;
+ }
+
+ if (data_rate_change) {
+ pr_info("pma_pll_config() Enable Rx Eq Training\n");
+ for (i = 0; i < 3; i++) {
+ reg_val =
+ read16(state, PHY_PMA_XCVR_CTRL_ADDR | (i << 6));
+ reg_val |= 0x0010;
+ write16(state, PHY_PMA_XCVR_CTRL_ADDR | (i << 6),
+ reg_val);
+ }
+ }
+ return 0;
+}
+
+clk_ratio_t clk_ratio_detect(state_struct *state,
+ u32 rx_clk_freq, /* khz */
+ u32 pxl_clk_freq, /* khz */
+ u8 vic,
+ pixel_encoding_t pixel_encoding,
+ tmds_bit_clock_ratio_t tmds_bit_clk_ratio)
+{
+ clk_ratio_t clk_ratio_detected = CLK_RATIO_1_1;
+
+ u64 tmds_freq_nominal_1_1, tmds_freq_nominal_1_1_min,
+ tmds_freq_nominal_1_1_max;
+ u64 tmds_freq_nominal_5_4, tmds_freq_nominal_5_4_min,
+ tmds_freq_nominal_5_4_max;
+ u64 tmds_freq_nominal_3_2, tmds_freq_nominal_3_2_min,
+ tmds_freq_nominal_3_2_max;
+ u64 tmds_freq_nominal_2_1, tmds_freq_nominal_2_1_min,
+ tmds_freq_nominal_2_1_max;
+ u64 tmds_freq_nominal_1_2, tmds_freq_nominal_1_2_min,
+ tmds_freq_nominal_1_2_max;
+ u64 tmds_freq_nominal_5_8, tmds_freq_nominal_5_8_min,
+ tmds_freq_nominal_5_8_max;
+ u64 tmds_freq_nominal_3_4, tmds_freq_nominal_3_4_min,
+ tmds_freq_nominal_3_4_max;
+ u64 min, max;
+
+ /* Check the TMDS/pixel clock ratio. */
+ pr_info("VIC %0d, pixel encoding: %0d, TMDS bit clock ratio: %0d and TMDS clk %d KHz\n",
+ vic, pixel_encoding, tmds_bit_clk_ratio, rx_clk_freq);
+
+ tmds_freq_nominal_1_1 = pxl_clk_freq;
+
+ min = 990;
+ max = 1010;
+
+ tmds_freq_nominal_5_4 = tmds_freq_nominal_1_1;
+ tmds_freq_nominal_3_2 = tmds_freq_nominal_1_1;
+ tmds_freq_nominal_2_1 = tmds_freq_nominal_1_1;
+ tmds_freq_nominal_1_2 = tmds_freq_nominal_1_1;
+ tmds_freq_nominal_5_8 = tmds_freq_nominal_1_1;
+ tmds_freq_nominal_3_4 = tmds_freq_nominal_1_1;
+
+ /* Exclude some of the clock ratios based on pixel excoding */
+ switch (pixel_encoding) {
+ case PIXEL_ENCODING_YUV422:
+ tmds_freq_nominal_5_4 = 0;
+ tmds_freq_nominal_3_2 = 0;
+ tmds_freq_nominal_2_1 = 0;
+ tmds_freq_nominal_1_2 = 0;
+ tmds_freq_nominal_5_8 = 0;
+ tmds_freq_nominal_3_4 = 0;
+ break;
+ case PIXEL_ENCODING_YUV420:
+ tmds_freq_nominal_5_4 = 0;
+ tmds_freq_nominal_3_2 = 0;
+ tmds_freq_nominal_2_1 = 0;
+ break;
+ default: /* RGB/YUV444 */
+ tmds_freq_nominal_1_2 = 0;
+ tmds_freq_nominal_5_8 = 0;
+ tmds_freq_nominal_3_4 = 0;
+ }
+
+ tmds_freq_nominal_1_1_min =
+ min * tmds_freq_nominal_1_1 * 10 * 1 / (tmds_bit_clk_ratio * 1000 * 1);
+ tmds_freq_nominal_1_1_max =
+ max * tmds_freq_nominal_1_1 * 10 * 1 / (tmds_bit_clk_ratio * 1000 * 1);
+ tmds_freq_nominal_5_4_min =
+ min * tmds_freq_nominal_5_4 * 10 * 5 / (tmds_bit_clk_ratio * 1000 * 4);
+ tmds_freq_nominal_5_4_max =
+ max * tmds_freq_nominal_5_4 * 10 * 5 / (tmds_bit_clk_ratio * 1000 * 4);
+ tmds_freq_nominal_3_2_min =
+ min * tmds_freq_nominal_3_2 * 10 * 3 / (tmds_bit_clk_ratio * 1000 * 2);
+ tmds_freq_nominal_3_2_max =
+ max * tmds_freq_nominal_3_2 * 10 * 3 / (tmds_bit_clk_ratio * 1000 * 2);
+ tmds_freq_nominal_2_1_min =
+ min * tmds_freq_nominal_2_1 * 10 * 2 / (tmds_bit_clk_ratio * 1000 * 1);
+ tmds_freq_nominal_2_1_max =
+ max * tmds_freq_nominal_2_1 * 10 * 2 / (tmds_bit_clk_ratio * 1000 * 1);
+ tmds_freq_nominal_1_2_min =
+ min * tmds_freq_nominal_1_2 * 10 * 1 / (tmds_bit_clk_ratio * 1000 * 2);
+ tmds_freq_nominal_1_2_max =
+ max * tmds_freq_nominal_1_2 * 10 * 1 / (tmds_bit_clk_ratio * 1000 * 2);
+ tmds_freq_nominal_5_8_min =
+ min * tmds_freq_nominal_5_8 * 10 * 5 / (tmds_bit_clk_ratio * 1000 * 8);
+ tmds_freq_nominal_5_8_max =
+ max * tmds_freq_nominal_5_8 * 10 * 5 / (tmds_bit_clk_ratio * 1000 * 8);
+ tmds_freq_nominal_3_4_min =
+ min * tmds_freq_nominal_3_4 * 10 * 3 / (tmds_bit_clk_ratio * 1000 * 4);
+ tmds_freq_nominal_3_4_max =
+ max * tmds_freq_nominal_3_4 * 10 * 3 / (tmds_bit_clk_ratio * 1000 * 4);
+
+ if (rx_clk_freq > tmds_freq_nominal_1_1_min
+ && rx_clk_freq < tmds_freq_nominal_1_1_max) {
+ clk_ratio_detected = CLK_RATIO_1_1;
+ pr_info("Detected TMDS/pixel clock ratio of 1:1\n");
+ } else if (rx_clk_freq > tmds_freq_nominal_5_4_min
+ && rx_clk_freq < tmds_freq_nominal_5_4_max) {
+ clk_ratio_detected = CLK_RATIO_5_4;
+ pr_info("Detected TMDS/pixel clock ratio of 5:4\n");
+ } else if (rx_clk_freq > tmds_freq_nominal_3_2_min
+ && rx_clk_freq < tmds_freq_nominal_3_2_max) {
+ clk_ratio_detected = CLK_RATIO_3_2;
+ pr_info("Detected TMDS/pixel clock ratio of 3:2\n");
+ } else if (rx_clk_freq > tmds_freq_nominal_2_1_min
+ && rx_clk_freq < tmds_freq_nominal_2_1_max) {
+ clk_ratio_detected = CLK_RATIO_2_1;
+ pr_info("Detected TMDS/pixel clock ratio of 2:1\n");
+ } else if (rx_clk_freq > tmds_freq_nominal_1_2_min
+ && rx_clk_freq < tmds_freq_nominal_1_2_max) {
+ clk_ratio_detected = CLK_RATIO_1_2;
+ pr_info("Detected TMDS/pixel clock ratio of 1:2\n");
+ } else if (rx_clk_freq > tmds_freq_nominal_5_8_min
+ && rx_clk_freq < tmds_freq_nominal_5_8_max) {
+ clk_ratio_detected = CLK_RATIO_5_8;
+ pr_info("Detected TMDS/pixel clock ratio of 5:8\n");
+ } else if (rx_clk_freq > tmds_freq_nominal_3_4_min
+ && rx_clk_freq < tmds_freq_nominal_3_4_max) {
+ clk_ratio_detected = CLK_RATIO_3_4;
+ pr_info("Detected TMDS/pixel clock ratio of 3:4\n");
+ } else {
+ pr_err("Failed to detected TMDS/pixel clock ratio\n");
+ pr_err("VIC: %02d and TMDS clock of %d KHz\n", vic, rx_clk_freq);
+ }
+
+ return clk_ratio_detected;
+}
diff --git a/drivers/media/platform/imx8/hdmi/API_AFE_ss28fdsoi_hdmirx.h b/drivers/media/platform/imx8/hdmi/API_AFE_ss28fdsoi_hdmirx.h
new file mode 100644
index 000000000000..14992f650f7f
--- /dev/null
+++ b/drivers/media/platform/imx8/hdmi/API_AFE_ss28fdsoi_hdmirx.h
@@ -0,0 +1,142 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_AFE_ss28fdsoi_hdmirx.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef API_AFE_SS28FDSOI_HDMIRX_H_
+#define API_AFE_SS28FDSOI_HDMIRX_H_
+
+#include <linux/io.h>
+#include "../../../../mxc/hdp/all.h"
+
+#define REFCLK_FREQ_KHZ 24000
+#define LINK_WRITE 0x2000
+#define LINK_ID 0x0
+
+#define CMN_PLLSM0_PLLEN_TMR_ADDR 0x0029
+#define CMN_PLLSM0_PLLPRE_TMR_ADDR 0x002A
+#define CMN_PLLSM0_PLLVREF_TMR_ADDR 0x002B
+#define CMN_PLLSM0_PLLLOCK_TMR_ADDR 0x002C
+#define CMN_PLLSM0_USER_DEF_CTRL_ADDR 0x002F
+#define CMN_PLL0_VCOCAL_CTRL_ADDR 0x0080
+#define CMN_PLL0_VCOCAL_OVRD_ADDR 0x0083
+#define CMN_PLL0_LOCK_REFCNT_START_ADDR 0x0090
+#define CMN_PLL0_LOCK_PLLCNT_START_ADDR 0x0092
+#define CMN_PLL0_DIV2SEL_OSR_CTRL_ADDR 0x009B
+#define CMN_ICAL_CTRL_ADDR 0x00C0
+#define CMN_ICAL_OVRD_ADDR 0x00C1
+#define CMN_RXCAL_CTRL_ADDR 0x00D0
+#define CMN_RXCAL_OVRD_ADDR 0x00D1
+#define CMN_RXCAL_INIT_TMR_ADDR 0x00D4
+#define CMN_TXPUCAL_OVRD_ADDR 0x00E1
+#define CMN_TXPDCAL_OVRD_ADDR 0x00F1
+#define CMN_CMSMT_CLK_FREQ_MSMT_CTRL_ADDR 0x01A0
+#define CMN_CMSMT_REF_CLK_TMR_VALUE_ADDR 0x01A2
+#define CMN_CMSMT_TEST_CLK_CNT_VALUE_ADDR 0x01A3
+#define CMN_DIAG_PLL0_FBH_OVRD_ADDR 0x01C0
+#define CMN_DIAG_PLL0_FBL_OVRD_ADDR 0x01C1
+#define CMN_DIAG_PLL0_TEST_MODE_ADDR 0x01C4
+#define CMN_DIAG_PLL0_INCLK_CTRL_ADDR 0x01CA
+#define CMN_DIAG_PLL0_V2I_TUNE_ADDR 0x01C5
+#define CMN_DIAG_PLL0_CP_TUNE_ADDR 0x01C6
+#define CMN_DIAG_PLL0_PTATIS_TUNE1_ADDR 0x01C8
+#define CMN_DIAG_PLL0_PTATIS_TUNE2_ADDR 0x01C9
+#define XCVR_PSM_CAL_TMR_ADDR 0x4002
+#define XCVR_PSM_A0IN_TMR_ADDR 0x4003
+#define XCVR_DIAG_RX_LANE_CAL_RST_TMR_ADDR 0x40EA
+#define TX_ANA_CTRL_REG_1_ADDR 0x5020
+#define TX_ANA_CTRL_REG_2_ADDR 0x5021
+#define TX_DIG_CTRL_REG_1_ADDR 0x5023
+#define TX_DIG_CTRL_REG_2_ADDR 0x5024
+#define TXDA_CYA_AUXDA_CYA_ADDR 0x5025
+#define TX_ANA_CTRL_REG_3_ADDR 0x5026
+#define TX_ANA_CTRL_REG_4_ADDR 0x5027
+#define TX_ANA_CTRL_REG_5_ADDR 0x5029
+#define RX_PSC_A0_ADDR 0x8000
+#define RX_IQPI_ILL_CAL_OVRD_ADDR 0x8023
+#define RX_EPI_ILL_CAL_OVRD_ADDR 0x8033
+#define RX_SLC_CTRL_ADDR 0x80E0
+#define RX_REE_PERGCSM_EQENM_PH1_ADDR 0x8179
+#define RX_REE_PERGCSM_EQENM_PH2_ADDR 0x817A
+#define RX_REE_VGA_GAIN_OVRD_ADDR 0x81AD
+#define RX_REE_SMGM_CTRL1_ADDR 0x81BD
+#define RX_DIAG_ILL_IQ_TRIM0_ADDR 0x81C1
+#define RX_DIAG_ILL_E_TRIM0_ADDR 0x81C2
+#define RX_DIAG_ILL_IQE_TRIM2_ADDR 0x81C5
+#define RX_DIAG_DFE_CTRL2_ADDR 0x81D4
+#define RX_DIAG_SC2C_DELAY_ADDR 0x81E1
+#define RX_DIAG_SMPLR_OSR_ADDR 0x81E2
+#define RX_CLK_SLICER_CAL_OVRD_ADDR 0x8621
+#define RX_CLK_SLICER_CAL_INIT_TMR_ADDR 0x8624
+#define PHY_MODE_CTL_ADDR 0xC008
+#define PHY_PMA_CMN_CTRL1_ADDR 0xC800
+#define PHY_PMA_CMN_CTRL2_ADDR 0xC801
+#define PHY_PMA_SSM_STATE_ADDR 0xC802
+#define PHY_PMA_PLL_SM_STATE_ADDR 0xC803
+#define PHY_PMA_XCVR_CTRL_ADDR 0xCC00
+
+typedef enum {
+ TMDS_BIT_CLOCK_RATIO_1_10 = 10,
+ TMDS_BIT_CLOCK_RATIO_1_40 = 40
+} tmds_bit_clock_ratio_t;
+
+typedef enum {
+ PIXEL_ENCODING_RGB = 0,
+ PIXEL_ENCODING_YUV422 = 1,
+ PIXEL_ENCODING_YUV444 = 2,
+ PIXEL_ENCODING_YUV420 = 3,
+} pixel_encoding_t;
+
+void speedup_config(state_struct *state);
+void arc_config(state_struct *state);
+void pma_config(state_struct *state);
+u8 pma_cmn_ready(state_struct *state);
+u8 pma_rx_clk_signal_detect(state_struct *state);
+u32 pma_rx_clk_freq_detect(state_struct *state);
+void pre_data_rate_change(state_struct *state);
+u8 pma_pll_config(state_struct *state, u32, clk_ratio_t, tmds_bit_clock_ratio_t, unsigned char);
+clk_ratio_t clk_ratio_detect(state_struct *state, u32, u32, u8, pixel_encoding_t, tmds_bit_clock_ratio_t);
+void phy_status(state_struct *state);
+
+#endif
diff --git a/drivers/media/platform/imx8/hdmi/Kconfig b/drivers/media/platform/imx8/hdmi/Kconfig
new file mode 100644
index 000000000000..ed2736f82de3
--- /dev/null
+++ b/drivers/media/platform/imx8/hdmi/Kconfig
@@ -0,0 +1,4 @@
+config IMX8_HDMI_RX
+ tristate "IMX8 HDMI RX Controller"
+ select MX8_HDP_RX
+ default y
diff --git a/drivers/media/platform/imx8/hdmi/Makefile b/drivers/media/platform/imx8/hdmi/Makefile
new file mode 100644
index 000000000000..93c0b3f44d72
--- /dev/null
+++ b/drivers/media/platform/imx8/hdmi/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_IMX8_HDMI_RX) += mxc-hdmi-rx.o mxc-hdmi-hw.o API_AFE_ss28fdsoi_hdmirx.o \
+ mxc-hdmi-rx-audio.o
diff --git a/drivers/media/platform/imx8/hdmi/mxc-hdmi-hw.c b/drivers/media/platform/imx8/hdmi/mxc-hdmi-hw.c
new file mode 100644
index 000000000000..d8ebd019c994
--- /dev/null
+++ b/drivers/media/platform/imx8/hdmi/mxc-hdmi-hw.c
@@ -0,0 +1,440 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "API_AFE_ss28fdsoi_hdmirx.h"
+#include "mxc-hdmi-rx.h"
+
+u8 block0[128] = {
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x1e, 0x6d, 0xfd, 0x5a, 0x9b, 0x5f, 0x02, 0x00,
+ 0x07, 0x19, 0x01, 0x04, 0xb5, 0x3c, 0x22, 0x78,
+ 0x9f, 0x30, 0x35, 0xa7, 0x55, 0x4e, 0xa3, 0x26,
+ 0x0f, 0x50, 0x54, 0x21, 0x08, 0x00, 0x71, 0x40,
+ 0x81, 0x80, 0x81, 0xc0, 0xa9, 0xc0, 0xd1, 0xc0,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x50, 0xd0,
+ 0x00, 0xa0, 0xf0, 0x70, 0x3e, 0x80, 0x08, 0x90,
+ 0x65, 0x0c, 0x58, 0x54, 0x21, 0x00, 0x00, 0x1a,
+ 0x28, 0x68, 0x00, 0xa0, 0xf0, 0x70, 0x3e, 0x80,
+ 0x08, 0x90, 0x65, 0x0c, 0x58, 0x54, 0x21, 0x00,
+ 0x00, 0x1a, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x28,
+ 0x3d, 0x87, 0x87, 0x38, 0x01, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
+ 0x00, 0x32, 0x37, 0x4d, 0x55, 0x36, 0x37, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xd4
+};
+
+u8 block1[128] = {
+ 0x02, 0x03, 0x11, 0x71, 0x44, 0x90, 0x04, 0x03,
+ 0x01, 0x23, 0x09, 0x07, 0x07, 0x83, 0x01, 0x00,
+ 0x00, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d,
+ 0x40, 0x58, 0x2c, 0x45, 0x00, 0x58, 0x54, 0x21,
+ 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41
+};
+
+S_HDMI_SCDC_SET_MSG scdcExampleData = {
+ .sink_ver = 6,
+ .manufacturer_oui_1 = 0x1,
+ .manufacturer_oui_2 = 0x2,
+ .manufacturer_oui_3 = 0x3,
+ .devId = {1, 2, 3, 4, 5, 6, 7, 8},
+ .hardware_major_rev = 12,
+ .hardware_minor_rev = 13,
+ .software_major_rev = 0xAB,
+ .software_minor_rev = 0XBC,
+ .manufacturerSpecific = {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}
+};
+
+u8 hdmi_infoframe_poll(state_struct *state)
+{
+ GENERAL_Read_Register_response regresp;
+ u32 regread;
+ struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
+
+ /* Unmask "AVI InfoFrame received" interrupt */
+ CDN_API_General_Write_Register_blocking(state,
+ ADDR_SINK_MHL_HD + (TMDS_MHL_HD_INT_MASK << 2),
+ F_TMDS_MHL_HD_MASK(0xFD));
+ dev_dbg(&hdmi_rx->pdev->dev, "AVI InfoFrame packet received - interrupt unmasked.\n");
+
+ /* Unmask "tmds_mhl_hd_int" interrupt */
+ CDN_API_General_Write_Register_blocking(state,
+ ADDR_SINK_MHL_HD + (MHL_HD_INT_MASK << 2),
+ F_MHL_HD_INT_MASK(0xE));
+ dev_dbg(&hdmi_rx->pdev->dev, "tmds_mhl_hd_int interrupt unmasked.\n");
+
+ /* MHL_HD_INT_STAT */
+ dev_dbg(&hdmi_rx->pdev->dev, "Waiting for tmds_mhl_hd_int...\n");
+ do {
+ CDN_API_General_Read_Register_blocking(state,
+ ADDR_SINK_MHL_HD + (MHL_HD_INT_STAT << 2),
+ &regresp);
+ } while (!(regresp.val & (1 << 0)));
+ dev_dbg(&hdmi_rx->pdev->dev, "Waiting for tmds_mhl_hd_int...DONE\n");
+
+ /* Mask "AVI InfoFrame received" interrupt */
+ CDN_API_General_Write_Register_blocking(state,
+ ADDR_SINK_MHL_HD + (TMDS_MHL_HD_INT_MASK << 2),
+ F_TMDS_MHL_HD_MASK(0xFF));
+ dev_dbg(&hdmi_rx->pdev->dev, "AVI InfoFrame packet received - interrupt masked.\n");
+
+ /* Mask "tmds_mhl_hd_int" interrupt */
+ CDN_API_General_Write_Register_blocking(state,
+ ADDR_SINK_MHL_HD + (MHL_HD_INT_MASK << 2),
+ F_MHL_HD_INT_MASK(0xF));
+ dev_dbg(&hdmi_rx->pdev->dev, "tmds_mhl_hd_int interrupt masked.\n");
+
+ /* Read back TMDS_MHL_HD_INT_STAT to clear the interrupt */
+ CDN_API_General_Read_Register_blocking(state,
+ ADDR_SINK_MHL_HD + (TMDS_MHL_HD_INT_STAT << 2),
+ &regresp);
+ dev_dbg(&hdmi_rx->pdev->dev, "AVI InfoFrame packet received - interrupt cleared.\n");
+
+ /* Packet 0 read request */
+ cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_CTRL << 2),
+ F_PACKET_RDN_WR(0x0) | F_PACKET_NUM(0x0));
+ dev_dbg(&hdmi_rx->pdev->dev, "PIF Packet 0 read request.\n");
+
+ /* Wait for pkt_host_rdy_status */
+ dev_dbg(&hdmi_rx->pdev->dev, "Waiting for packet data available for reading...\n");
+ do {
+ cdn_apb_read(state, ADDR_SINK_PIF + (PKT_INT_STATUS << 2), &regread);
+ } while (!(regread & (1 << 16)));
+ dev_dbg(&hdmi_rx->pdev->dev, "Waiting for packet data available for reading...DONE\n");
+
+ return 0;
+}
+
+/* Exemplary code to configure the controller */
+/* for the AVI_InfoFrame reception */
+static void get_avi_infoframe(state_struct *state)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
+ GENERAL_Read_Register_response regresp;
+
+ dev_dbg(&hdmi_rx->pdev->dev, "%s\n", __func__);
+ /* Get VIC code and pixel encoding */
+ hdmi_infoframe_poll(state);
+
+ CDN_API_General_Read_Register_blocking(state, ADDR_SINK_MHL_HD + (PKT_AVI_DATA_LOW << 2), &regresp);
+ hdmi_rx->vic_code = (regresp.val & 0xFF000000) >> 24;
+ hdmi_rx->pixel_encoding = (regresp.val & 0x00000060) >> 5;
+}
+
+static void get_vendor_infoframe(state_struct *state)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
+ u32 regread;
+
+ dev_dbg(&hdmi_rx->pdev->dev, "%s\n", __func__);
+ /* Set info_type1 to vendor Info Frame */
+ cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_TYPE_CFG1 << 2),
+ F_INFO_TYPE1(0x81));
+
+ hdmi_infoframe_poll(state);
+
+ /* Get IEEE OUI */
+ cdn_apb_read(state, ADDR_SINK_PIF + (PKT_INFO_DATA1 << 2), &regread);
+ if (regread >> 8 == 0x000c03)
+ dev_info(&hdmi_rx->pdev->dev, "HDMI 1.4b Vendor Specific Infoframe\n");
+ else if (regread >> 8 == 0xC45DD8)
+ dev_info(&hdmi_rx->pdev->dev, "HDMI 2.0 Vendor Specific Infoframe\n");
+ else
+ dev_err(&hdmi_rx->pdev->dev,
+ "Error Vendro Infoframe IEEE OUI=0x%6X\n", regread >> 8);
+
+ /* Get HDMI Video format */
+ cdn_apb_read(state, ADDR_SINK_PIF + (PKT_INFO_DATA2 << 2), &regread);
+
+ /* Extened resoluction format */
+ if (((regread >> 5) & 0x0000007) == 1) {
+ hdmi_rx->hdmi_vic = (regread >> 8) & 0xff;
+ dev_info(&hdmi_rx->pdev->dev, "hdmi_vic=%d\n", hdmi_rx->hdmi_vic);
+ }
+
+ /* Clear info_type1 */
+ cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_TYPE_CFG1 << 2),
+ F_INFO_TYPE1(0x00));
+}
+
+static void get_color_depth(struct mxc_hdmi_rx_dev *hdmi_rx,
+ clk_ratio_t clk_ratio)
+{
+ u8 pixel_encoding = hdmi_rx->pixel_encoding;
+
+ hdmi_rx->color_depth = 8;
+
+ switch (pixel_encoding) {
+ case PIXEL_ENCODING_YUV422:
+ switch (clk_ratio) {
+ case CLK_RATIO_1_1:
+ hdmi_rx->color_depth = 8;
+ break;
+ case CLK_RATIO_5_4:
+ case CLK_RATIO_3_2:
+ case CLK_RATIO_2_1:
+ case CLK_RATIO_1_2:
+ case CLK_RATIO_5_8:
+ case CLK_RATIO_3_4:
+ default:
+ pr_err("YUV422 Not supported clk ration\n");
+ }
+ break;
+ case PIXEL_ENCODING_YUV420:
+ switch (clk_ratio) {
+ case CLK_RATIO_1_1:
+ hdmi_rx->color_depth = 16;
+ break;
+ case CLK_RATIO_1_2:
+ hdmi_rx->color_depth = 8;
+ break;
+ case CLK_RATIO_5_8:
+ hdmi_rx->color_depth = 10;
+ break;
+ case CLK_RATIO_3_4:
+ hdmi_rx->color_depth = 12;
+ break;
+ case CLK_RATIO_5_4:
+ case CLK_RATIO_3_2:
+ case CLK_RATIO_2_1:
+ default:
+ pr_err("YUV420 Not supported clk ration\n");
+ }
+ break;
+ default: /* RGB/YUV444 */
+ switch (clk_ratio) {
+ case CLK_RATIO_1_1:
+ hdmi_rx->color_depth = 8;
+ break;
+ case CLK_RATIO_5_4:
+ hdmi_rx->color_depth = 10;
+ break;
+ case CLK_RATIO_3_2:
+ hdmi_rx->color_depth = 12;
+ break;
+ case CLK_RATIO_2_1:
+ hdmi_rx->color_depth = 16;
+ break;
+ case CLK_RATIO_1_2:
+ case CLK_RATIO_5_8:
+ case CLK_RATIO_3_4:
+ default:
+ pr_err("RGB/YUV444 Not supported clk ration\n");
+ }
+ }
+}
+
+int hdmi_rx_init(state_struct *state)
+{
+ u32 ret = 0;
+ /* Set uCPU Clock frequency for FW's use [MHz]; */
+ CDN_API_SetClock(state, 200);
+
+ /* Relase uCPU */
+ cdn_apb_write(state, ADDR_APB_CFG, 0);
+
+ /* Check if the firmware is running */
+ ret = CDN_API_CheckAlive_blocking(state);
+ return ret;
+}
+
+/* Bring-up sequence for the HDMI-RX */
+int hdmirx_startup(state_struct *state)
+{
+ u8 sts;
+ u32 rx_clk_freq;
+ u8 event5V = 0;
+ u8 data_rate_change = 0;
+ u8 scrambling_en;
+ clk_ratio_t clk_ratio, clk_ratio_detected;
+ tmds_bit_clock_ratio_t tmds_bit_clock_ratio;
+ struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
+ S_HDMI_SCDC_GET_MSG *scdcData = &hdmi_rx->scdcData;
+ u8 ret = 0;
+ u32 i;
+
+ /* Start from TMDS/pixel clock ratio of 1:1.
+ * It affects only pixel clock frequency as the character/data clocks are generated based on
+ * a measured TMDS clock.
+ * This guarantees that the TMDS characters are correctly decoded in the controller regardless
+ * of the pixel clock ratio being programmed. */
+ clk_ratio = CLK_RATIO_1_1;
+
+ /* Set driver and firmware active */
+ CDN_API_MainControl_blocking(state, 1, &sts);
+
+ /* Set EDID - block 0 */
+ CDN_API_HDMIRX_SET_EDID_blocking(state, 0, 0, &block0[0]);
+
+ /* Set EDID - block 1 */
+ CDN_API_HDMIRX_SET_EDID_blocking(state, 0, 1, &block1[0]);
+ dev_dbg(&hdmi_rx->pdev->dev, "EDID block 0/1 set complete.\n");
+
+ /* Set SCDC data sample */
+ CDN_API_HDMIRX_SET_SCDC_SLAVE_blocking(state, &scdcExampleData);
+ dev_dbg(&hdmi_rx->pdev->dev, "SCDC set complete.\n");
+
+ /* Get TMDS_Bit_Clock_Ratio and Scrambling setting */
+ CDN_API_HDMIRX_GET_SCDC_SLAVE_blocking(state, scdcData);
+ tmds_bit_clock_ratio =
+ ((scdcData->TMDS_Config & (1 << 1)) >> 1) ?
+ TMDS_BIT_CLOCK_RATIO_1_40 : TMDS_BIT_CLOCK_RATIO_1_10;
+ scrambling_en = scdcData->TMDS_Config & (1 << 0);
+ dev_dbg(&hdmi_rx->pdev->dev,
+ "TMDS ratio: 1/%0d, Scrambling %0d).\n", tmds_bit_clock_ratio, scrambling_en);
+
+ /* Clear HPD */
+ CDN_API_HDMIRX_SetHpd_blocking(state, 0);
+ dev_dbg(&hdmi_rx->pdev->dev, "Clear HDP\n");
+
+ /* check for 5v to get hdmi cable state */
+ CDN_API_HDMIRX_ReadEvent(state, &event5V);
+ dev_dbg(&hdmi_rx->pdev->dev, "event5V = 0x%02X\n", event5V);
+ for (i = 0; i < 5; i++) {
+ if (event5V & (1 << HDMI_RX_EVENT_5V_VAL)) {
+ dev_info(&hdmi_rx->pdev->dev, "HDMI 5V present\n");
+ break;
+ }
+ msleep(20);
+ CDN_API_HDMIRX_ReadEvent(state, &event5V);
+ dev_dbg(&hdmi_rx->pdev->dev, "event5V = 0x%02X\n", event5V);
+ }
+ if (i == 5) {
+ dev_info(&hdmi_rx->pdev->dev, "No HDMI 5V present!!!\n");
+ return -1;
+ }
+
+ /* Got 5v, set hpd */
+ msleep(100); /* provide minimum low pulse length (100ms) */
+ CDN_API_HDMIRX_SetHpd_blocking(state, 1);
+ dev_dbg(&hdmi_rx->pdev->dev, "Set HDP\n");
+
+ /* Configure the PHY */
+ pma_config(state);
+
+ /* Reset HDMI RX PHY */
+ imx8qm_hdmi_phy_reset(state, 1);
+
+ ret = pma_cmn_ready(state);
+ if (ret < 0) {
+ pr_err("pma_cmn_ready failed\n");
+ return -1;
+ }
+
+ msleep(500);
+
+ arc_config(state);
+
+ ret = pma_rx_clk_signal_detect(state);
+ if (ret < 0) {
+ pr_err("pma_rx_clk_signal_detect failed\n");
+ return -1;
+ }
+ /* Get TMDS clock frequency */
+ rx_clk_freq = pma_rx_clk_freq_detect(state);
+
+ ret = pma_pll_config(state, rx_clk_freq, clk_ratio, tmds_bit_clock_ratio,
+ data_rate_change);
+ if (ret < 0) {
+ pr_err("pma_pll_config failed\n");
+ return -1;
+ }
+ msleep(500);
+
+ /* Setup the scrambling mode */
+ CDN_API_General_Write_Register_blocking(state,
+ ADDR_SINK_MHL_HD + (TMDS_SCR_CTRL << 2),
+ F_SCRAMBLER_MODE(scrambling_en));
+ dev_info(&hdmi_rx->pdev->dev,
+ "Scrambling %s.\n", (scrambling_en) ? "enabled" : "disabled");
+ /*Just to initiate the counters: */
+ CDN_API_General_Write_Register_blocking(state,
+ ADDR_SINK_MHL_HD + (TMDS_SCR_CNT_INT_CTRL << 2),
+ F_SCRAMBLER_SSCP_LINE_DET_THR(0) |
+ F_SCRAMBLER_CTRL_LINE_DET_THR(0));
+ CDN_API_General_Write_Register_blocking(state,
+ ADDR_SINK_MHL_HD + (TMDS_SCR_VALID_CTRL << 2),
+ F_SCRAMBLER_SSCP_LINE_VALID_THR(1) |
+ F_SCRAMBLER_CTRL_LINE_VALID_THR(0));
+
+ /* The PHY got programmed with the assumed TMDS/pixel clock ratio of 1:1.
+ * Implement the link training procedure to find out the real clock ratio:
+ * 1. Wait for AVI InfoFrame packet
+ * 2. Get the VIC code and pixel encoding from the packet
+ * 3. Evaluate the TMDS/pixel clock ratio based on the vic_table.c
+ * 4. Compare the programmed clock ratio with evaluated one
+ * 5. If mismatch found - reprogram the PHY
+ * 6. Enable the video data path in the controller */
+
+ get_avi_infoframe(state);
+ get_vendor_infoframe(state);
+
+ dev_dbg(&hdmi_rx->pdev->dev,
+ "get_avi_infoframe() vic_code: %0d, pixel_encoding: %0d.\n",
+ hdmi_rx->vic_code, hdmi_rx->pixel_encoding);
+ mxc_hdmi_frame_timing(hdmi_rx);
+
+ clk_ratio_detected = clk_ratio_detect(state, rx_clk_freq,
+ hdmi_rx->timings->timings.bt.
+ pixelclock / 1000,
+ hdmi_rx->vic_code,
+ hdmi_rx->pixel_encoding,
+ tmds_bit_clock_ratio);
+
+ data_rate_change = (clk_ratio != clk_ratio_detected);
+ if (data_rate_change) {
+ dev_dbg(&hdmi_rx->pdev->dev,
+ "TMDS/pixel clock ratio mismatch detected (programmed: %0d, detected: %0d)\n",
+ clk_ratio, clk_ratio_detected);
+
+ /* Reconfigure the PHY */
+ pre_data_rate_change(state);
+ pma_rx_clk_signal_detect(state);
+ rx_clk_freq = pma_rx_clk_freq_detect(state);
+ pma_pll_config(state, rx_clk_freq, clk_ratio_detected,
+ tmds_bit_clock_ratio, data_rate_change);
+ } else
+ dev_info(&hdmi_rx->pdev->dev, "TMDS/pixel clock ratio correct\n");
+
+ get_color_depth(hdmi_rx, clk_ratio_detected);
+ dev_dbg(&hdmi_rx->pdev->dev, "Get colordepth is %d bpc\n", hdmi_rx->color_depth);
+
+ /* Do post PHY programming settings */
+ CDN_API_MainControl_blocking(state, 0x80, &sts);
+ dev_dbg(&hdmi_rx->pdev->dev,
+ "CDN_API_MainControl_blocking() Stage 2 complete.\n");
+
+ /* Initialize HDMI RX */
+ CDN_API_HDMIRX_Init_blocking(state);
+ dev_dbg(&hdmi_rx->pdev->dev,
+ "CDN_API_HDMIRX_Init_blocking() complete.\n");
+
+ /* Initialize HDMI RX CEC */
+ CDN_API_General_Write_Register_blocking(state,
+ ADDR_SINK_CAR + (SINK_CEC_CAR << 2),
+ F_SINK_CEC_SYS_CLK_EN(1) |
+ F_SINK_CEC_SYS_CLK_RSTN_EN(1));
+ return 0;
+}
diff --git a/drivers/media/platform/imx8/hdmi/mxc-hdmi-rx-audio.c b/drivers/media/platform/imx8/hdmi/mxc-hdmi-rx-audio.c
new file mode 100644
index 000000000000..22a55df879d7
--- /dev/null
+++ b/drivers/media/platform/imx8/hdmi/mxc-hdmi-rx-audio.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/component.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/irq.h>
+#include <linux/of_device.h>
+#include <sound/hdmi-codec.h>
+
+#include "mxc-hdmi-rx.h"
+#include "../../../../mxc/hdp/API_Audio.h"
+#include "../../../../mxc/hdp/API_HDMI_RX_Audio.h"
+#include "../../../../mxc/hdp/sink_pif.h"
+#include "../../../../mxc/hdp/aif_pckt2smp.h"
+
+
+static int get_audio_infoframe(state_struct *state, unsigned int *chan)
+{
+
+ unsigned int regread;
+ int ret = 0;
+ int times = 0;
+
+ cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_TYPE_CFG1 << 2), F_INFO_TYPE1(0x84));
+
+ cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INT_MASK << 2), 0x1FFFE);
+
+ do {
+ cdn_apb_read(state, ADDR_SINK_PIF + (PKT_INT_STATUS << 2), &regread);
+ udelay(100);
+ times++;
+ } while (!(regread & (1 << 0)) && times < 5000);
+
+ if (times == 5000) {
+ ret = -EINVAL;
+ return ret;
+ }
+
+ cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_CTRL << 2), F_PACKET_RDN_WR(0x0) | F_PACKET_NUM(0x0));
+
+ times = 0;
+
+ do {
+ cdn_apb_read(state, ADDR_SINK_PIF + (PKT_INT_STATUS << 2), &regread);
+ udelay(10);
+ times++;
+ } while (!(regread & (1 << 16)) && times < 100);
+
+ if (times == 100) {
+ ret = -EINVAL;
+ return ret;
+ }
+
+ cdn_apb_read(state, ADDR_SINK_PIF + (PKT_INFO_DATA1 << 2), &regread);
+
+ cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_TYPE_CFG1 << 2), F_INFO_TYPE1(0x00));
+
+ *chan = ((regread & 0x700) >> 8) + 1;
+
+ cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_HEADER << 2), 0);
+ cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_DATA1 << 2), 0);
+ cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_DATA2 << 2), 0);
+ cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_DATA3 << 2), 0);
+ cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_DATA4 << 2), 0);
+ cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_DATA5 << 2), 0);
+ cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_DATA6 << 2), 0);
+ cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_DATA7 << 2), 0);
+
+ cdn_apb_write(state, ADDR_SINK_PIF + (PKT_INFO_CTRL << 2), F_PACKET_RDN_WR(0x1) | F_PACKET_NUM(0x0));
+
+ times = 0;
+ do {
+ cdn_apb_read(state, ADDR_SINK_PIF + (PKT_INT_STATUS << 2), &regread);
+ udelay(10);
+ times++;
+ } while (!(regread & (1 << 16)) && times < 100);
+
+ if (times == 100) {
+ ret = -EINVAL;
+ return ret;
+ }
+
+ return ret;
+}
+
+static u32 TMDS_rate_table[7] = {
+25200, 27000, 54000, 74250, 148500, 297000, 594000,
+};
+
+static u32 N_table_32k[8] = {
+/*25200, 27000, 54000, 74250, 148500, 297000, 594000,*/
+4096, 4096, 4096, 4096, 4096, 3072, 3072, 4096,
+};
+
+static u32 N_table_44k[8] = {
+6272, 6272, 6272, 6272, 6272, 4704, 9408, 6272,
+};
+
+static u32 N_table_48k[8] = {
+6144, 6144, 6144, 6144, 6144, 5120, 6144, 6144,
+};
+
+static int select_rate(u32 pclk, u32 N)
+{
+ int i = 0;
+ int rate = 0;
+
+ for (i = 0; i < 7; i++) {
+ if (pclk == TMDS_rate_table[i])
+ break;
+ }
+
+ if (i == 7)
+ DRM_WARN("pclkc %d is not supported!\n", pclk);
+
+ if (N_table_32k[i] == N)
+ rate = 32000;
+
+ if (N_table_44k[i] == N)
+ rate = 44100;
+
+ if (N_table_44k[i] * 2 == N)
+ rate = 44100 * 2;
+
+ if (N_table_44k[i] * 4 == N)
+ rate = 44100 * 4;
+
+ if (N_table_48k[i] == N)
+ rate = 48000;
+
+ if (N_table_48k[i] * 2 == N)
+ rate = 48000 * 2;
+
+ if (N_table_48k[i] * 4 == N)
+ rate = 48000 * 4;
+
+ return rate;
+}
+
+
+
+static int mxc_hdmi_rx_audio(struct mxc_hdmi_rx_dev *hdmi)
+{
+ state_struct *state = &hdmi->state;
+ u32 regread;
+ u32 rate;
+ u32 chan = 2;
+ CDN_API_STATUS status;
+ int ret;
+
+ ret = get_audio_infoframe(state, &chan);
+ if (ret)
+ return ret;
+
+ status = CDN_API_RX_AudioAutoConfig(state, chan, chan/2, 0, 32, 32);
+ if (status != CDN_OK)
+ return -EINVAL;
+
+ if (cdn_apb_read(state, ADDR_AIF_ENCODER + (AIF_ACR_N_ST << 2), &regread))
+ return -EINVAL;
+
+ rate = select_rate(hdmi->timings->timings.bt.pixelclock/1000, regread);
+
+ hdmi->channels = chan;
+ hdmi->sample_rate = rate;
+
+ return 0;
+}
+
+/*
+ * HDMI audio codec callbacks
+ */
+static int mxc_hdmi_rx_audio_hw_params(struct device *dev, void *data,
+ struct hdmi_codec_daifmt *daifmt,
+ struct hdmi_codec_params *params)
+{
+ return 0;
+}
+
+static void mxc_hdmi_rx_audio_shutdown(struct device *dev, void *data)
+{
+ pm_runtime_put_sync(dev);
+}
+
+static int mxc_hdmi_rx_audio_startup(struct device *dev, void *data)
+{
+ struct mxc_hdmi_rx_dev *hdmi = dev_get_drvdata(dev);
+ int ret;
+
+ pm_runtime_get_sync(dev);
+ ret = mxc_hdmi_rx_audio(hdmi);
+
+ return ret;
+}
+
+static int mxc_hdmi_rx_audio_get_eld(struct device *dev, void *data, uint8_t *buf, size_t len)
+{
+ struct mxc_hdmi_rx_dev *hdmi = dev_get_drvdata(dev);
+
+ if (len < 8)
+ return -EINVAL;
+
+ memcpy(buf, &hdmi->sample_rate, 4);
+ memcpy(buf + 4, &hdmi->channels, 4);
+
+ return 0;
+}
+
+static const struct hdmi_codec_ops mxc_hdmi_rx_audio_codec_ops = {
+ .hw_params = mxc_hdmi_rx_audio_hw_params,
+ .audio_shutdown = mxc_hdmi_rx_audio_shutdown,
+ .audio_startup = mxc_hdmi_rx_audio_startup,
+ .get_eld = mxc_hdmi_rx_audio_get_eld,
+};
+
+void mxc_hdmi_rx_register_audio_driver(struct device *dev)
+{
+ struct hdmi_codec_pdata codec_data = {
+ .ops = &mxc_hdmi_rx_audio_codec_ops,
+ .max_i2s_channels = 8,
+ .i2s = 1,
+ };
+ struct platform_device *pdev;
+
+ pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
+ 2, &codec_data,
+ sizeof(codec_data));
+ if (IS_ERR(pdev))
+ return;
+
+ DRM_INFO("%s driver bound to HDMI\n", HDMI_CODEC_DRV_NAME);
+}
+
+
diff --git a/drivers/media/platform/imx8/hdmi/mxc-hdmi-rx.c b/drivers/media/platform/imx8/hdmi/mxc-hdmi-rx.c
new file mode 100644
index 000000000000..92acd0ee2ebd
--- /dev/null
+++ b/drivers/media/platform/imx8/hdmi/mxc-hdmi-rx.c
@@ -0,0 +1,923 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "mxc-hdmi-rx.h"
+#include "API_AFE_ss28fdsoi_hdmirx.h"
+
+#define MXC_HDMI_DRIVER_NAME "iMX HDMI RX"
+#define MXC_HDMI_MIN_WIDTH 640
+#define MXC_HDMI_MAX_WIDTH 3840
+#define MXC_HDMI_MIN_HEIGHT 480
+#define MXC_HDMI_MAX_HEIGHT 2160
+
+/* V4L2_DV_BT_CEA_640X480P59_94 */
+#define MXC_HDMI_MIN_PIXELCLOCK 24000000
+/* V4L2_DV_BT_CEA_3840X2160P30 */
+#define MXC_HDMI_MAX_PIXELCLOCK 297000000
+
+#define imx_sd_to_hdmi(sd) container_of(sd, struct mxc_hdmi_rx_dev, sd)
+
+static void mxc_hdmi_cec_init(struct mxc_hdmi_rx_dev *hdmi_rx);
+
+static const struct v4l2_dv_timings_cap mxc_hdmi_timings_cap = {
+ .type = V4L2_DV_BT_656_1120,
+ /* keep this initialization for compatibility with GCC < 4.4.6 */
+ .reserved = { 0 },
+
+ V4L2_INIT_BT_TIMINGS(MXC_HDMI_MIN_WIDTH, MXC_HDMI_MAX_WIDTH,
+ MXC_HDMI_MIN_HEIGHT, MXC_HDMI_MAX_HEIGHT,
+ MXC_HDMI_MIN_PIXELCLOCK,
+ MXC_HDMI_MAX_PIXELCLOCK,
+ V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT,
+ V4L2_DV_BT_CAP_PROGRESSIVE)
+};
+
+struct mxc_hdmi_rx_dev_video_standards
+mxc_hdmi_video_standards[] = {
+ {V4L2_DV_BT_CEA_640X480P59_94, 1, 0, 60},
+ {V4L2_DV_BT_CEA_720X480P59_94, 2, 0, 60},
+ {V4L2_DV_BT_CEA_720X480P59_94, 3, 0, 60},
+ {V4L2_DV_BT_CEA_720X576P50, 18, 0, 50},
+ {V4L2_DV_BT_CEA_720X576P50, 17, 0, 50},
+ {V4L2_DV_BT_CEA_1280X720P60, 4, 0, 60},
+ {V4L2_DV_BT_CEA_1280X720P50, 19, 0, 50},
+ {V4L2_DV_BT_CEA_1280X720P30, 62, 0, 30},
+ {V4L2_DV_BT_CEA_1280X720P25, 61, 0, 25},
+ {V4L2_DV_BT_CEA_1280X720P24, 60, 0, 24},
+ {V4L2_DV_BT_CEA_1920X1080P60, 16, 0, 60},
+ {V4L2_DV_BT_CEA_1920X1080P50, 31, 0, 50},
+ {V4L2_DV_BT_CEA_1920X1080P30, 34, 0, 30},
+ {V4L2_DV_BT_CEA_1920X1080P25, 33, 0, 25},
+ {V4L2_DV_BT_CEA_1920X1080P24, 32, 0, 24},
+ {V4L2_DV_BT_CEA_3840X2160P24, 93, 3, 24},
+ {V4L2_DV_BT_CEA_3840X2160P25, 94, 2, 25},
+ {V4L2_DV_BT_CEA_3840X2160P30, 95, 1, 30},
+ {V4L2_DV_BT_CEA_4096X2160P24, 98, 4, 24},
+ {V4L2_DV_BT_CEA_4096X2160P25, 99, 0, 25},
+ {V4L2_DV_BT_CEA_4096X2160P30, 100, 0, 30},
+ /* SVGA */
+ {V4L2_DV_BT_DMT_800X600P56, 0x0, 0, 56},
+ {V4L2_DV_BT_DMT_800X600P60, 0x0, 0, 60},
+ {V4L2_DV_BT_DMT_800X600P72, 0x0, 0, 72},
+ {V4L2_DV_BT_DMT_800X600P75, 0x0, 0, 75},
+ {V4L2_DV_BT_DMT_800X600P85, 0x0, 0, 85},
+ /* SXGA */
+ {V4L2_DV_BT_DMT_1280X1024P60, 0x0, 0, 60},
+ {V4L2_DV_BT_DMT_1280X1024P75, 0x0, 0, 75},
+ /* VGA */
+ { V4L2_DV_BT_DMT_640X480P72, 0x0, 0, 72},
+ { V4L2_DV_BT_DMT_640X480P75, 0x0, 0, 75},
+ { V4L2_DV_BT_DMT_640X480P85, 0x0, 0, 85},
+ /* XGA */
+ { V4L2_DV_BT_DMT_1024X768P60, 0x0, 0, 60},
+ { V4L2_DV_BT_DMT_1024X768P70, 0x0, 0, 70},
+ { V4L2_DV_BT_DMT_1024X768P75, 0x0, 0, 75},
+ { V4L2_DV_BT_DMT_1024X768P85, 0x0, 0, 85},
+ /* UXGA */
+ { V4L2_DV_BT_DMT_1600X1200P60, 0x0, 0, 60},
+};
+
+int mxc_hdmi_frame_timing(struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+ struct mxc_hdmi_rx_dev_video_standards *stds;
+ u32 i, vic, hdmi_vic;
+
+ vic = hdmi_rx->vic_code;
+ hdmi_vic = hdmi_rx->hdmi_vic;
+ stds = mxc_hdmi_video_standards;
+
+ if (vic == 0 && hdmi_vic != 0) {
+ for (i = 0; i < ARRAY_SIZE(mxc_hdmi_video_standards); i++) {
+ if (stds[i].hdmi_vic == hdmi_vic) {
+ hdmi_rx->timings = &stds[i];
+ return true;
+ }
+ }
+ } else if (vic > 109) {
+ dev_err(&hdmi_rx->pdev->dev,
+ "Unsupported mode vic=%d, hdmi_vic=%d\n", vic, hdmi_vic);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mxc_hdmi_video_standards); i++) {
+ if (stds[i].vic == vic) {
+ hdmi_rx->timings = &stds[i];
+ return true;
+ }
+ }
+
+ if (i >= ARRAY_SIZE(mxc_hdmi_video_standards))
+ return -EINVAL;
+
+ return true;
+}
+
+static int mxc_hdmi_clock_init(struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+ struct device *dev = &hdmi_rx->pdev->dev;
+
+ hdmi_rx->ref_clk = devm_clk_get(dev, "ref_clk");
+ if (IS_ERR(hdmi_rx->ref_clk)) {
+ dev_err(dev, "failed to get hdmi rx ref clk\n");
+ return PTR_ERR(hdmi_rx->ref_clk);
+ }
+
+ hdmi_rx->pxl_clk = devm_clk_get(dev, "pxl_clk");
+ if (IS_ERR(hdmi_rx->pxl_clk)) {
+ dev_err(dev, "failed to get hdmi rx pxl clk\n");
+ return PTR_ERR(hdmi_rx->pxl_clk);
+ }
+ hdmi_rx->pclk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(hdmi_rx->pclk)) {
+ dev_err(dev, "failed to get hdmi rx pclk\n");
+ return PTR_ERR(hdmi_rx->pclk);
+ }
+
+ hdmi_rx->sclk = devm_clk_get(dev, "sclk");
+ if (IS_ERR(hdmi_rx->sclk)) {
+ dev_err(dev, "failed to get hdmi rx sclk\n");
+ return PTR_ERR(hdmi_rx->sclk);
+ }
+
+ hdmi_rx->enc_clk = devm_clk_get(dev, "enc_clk");
+ if (IS_ERR(hdmi_rx->enc_clk)) {
+ dev_err(dev, "failed to get hdmi rx enc clk\n");
+ return PTR_ERR(hdmi_rx->enc_clk);
+ }
+
+ hdmi_rx->i2s_clk = devm_clk_get(dev, "i2s_clk");
+ if (IS_ERR(hdmi_rx->i2s_clk)) {
+ dev_err(dev, "failed to get hdmi rx i2s clk\n");
+ return PTR_ERR(hdmi_rx->i2s_clk);
+ }
+
+ hdmi_rx->spdif_clk = devm_clk_get(dev, "spdif_clk");
+ if (IS_ERR(hdmi_rx->spdif_clk)) {
+ dev_err(dev, "failed to get hdmi rx spdif clk\n");
+ return PTR_ERR(hdmi_rx->spdif_clk);
+ }
+
+ hdmi_rx->pxl_link_clk = devm_clk_get(dev, "pxl_link_clk");
+ if (IS_ERR(hdmi_rx->pxl_link_clk)) {
+ dev_err(dev, "failed to get hdmi rx pixel link clk\n");
+ return PTR_ERR(hdmi_rx->pxl_link_clk);
+ }
+
+ return 0;
+}
+
+static int mxc_hdmi_clock_enable(struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+ struct device *dev = &hdmi_rx->pdev->dev;
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+ ret = clk_prepare_enable(hdmi_rx->ref_clk);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre ref_clk error %d\n", __func__, ret);
+ return ret;
+ }
+ ret = clk_prepare_enable(hdmi_rx->pxl_clk);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre pxl_clk error %d\n", __func__, ret);
+ return ret;
+ }
+ ret = clk_prepare_enable(hdmi_rx->enc_clk);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre enc_clk error %d\n", __func__, ret);
+ return ret;
+ }
+ ret = clk_prepare_enable(hdmi_rx->sclk);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre sclk error %d\n", __func__, ret);
+ return ret;
+ }
+ ret = clk_prepare_enable(hdmi_rx->pclk);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre pclk error %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi_rx->i2s_clk);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre i2s_clk error %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi_rx->spdif_clk);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre spdif_clk error %d\n", __func__, ret);
+ return ret;
+ }
+ ret = clk_prepare_enable(hdmi_rx->pxl_link_clk);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre pxl_link_clk error %d\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void mxc_hdmi_clock_disable(struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+ dev_dbg(&hdmi_rx->pdev->dev, "%s\n", __func__);
+
+ clk_disable_unprepare(hdmi_rx->ref_clk);
+ clk_disable_unprepare(hdmi_rx->pxl_clk);
+ clk_disable_unprepare(hdmi_rx->enc_clk);
+ clk_disable_unprepare(hdmi_rx->sclk);
+ clk_disable_unprepare(hdmi_rx->pclk);
+ clk_disable_unprepare(hdmi_rx->i2s_clk);
+ clk_disable_unprepare(hdmi_rx->spdif_clk);
+ clk_disable_unprepare(hdmi_rx->pxl_link_clk);
+}
+
+static void imx8qm_pixel_link_encoder(struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+ u32 val;
+
+ switch (hdmi_rx->pixel_encoding) {
+ case PIXEL_ENCODING_YUV422:
+ val = 3;
+ break;
+ case PIXEL_ENCODING_YUV420:
+ val = 4;
+ break;
+ case PIXEL_ENCODING_YUV444:
+ val = 2;
+ break;
+ case PIXEL_ENCODING_RGB:
+ val = 0;
+ break;
+ default:
+ val = 0x6;
+ }
+
+ /* HDMI RX H/Vsync Polarity */
+ if (hdmi_rx->timings->timings.bt.polarities & V4L2_DV_VSYNC_POS_POL)
+ val |= 1 << PL_ENC_CTL_PXL_VCP;
+ if (hdmi_rx->timings->timings.bt.polarities & V4L2_DV_HSYNC_POS_POL)
+ val |= 1 << PL_ENC_CTL_PXL_HCP;
+
+ writel(val, hdmi_rx->mem.ss_base);
+}
+
+/* -----------------------------------------------------------------------------
+ * v4l2_subdev_video_ops
+ */
+
+static int mxc_hdmi_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+ struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+ int ret = 0;
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cparm->timeperframe.denominator = hdmi_rx->timings->fps;
+ cparm->timeperframe.numerator = 1;
+ ret = 0;
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ ret = -EINVAL;
+ break;
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int mxc_hdmi_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+ u32 val;
+
+ dev_dbg(&hdmi_rx->pdev->dev, "%s\n", __func__);
+ imx8qm_pixel_link_encoder(hdmi_rx);
+
+ if (enable) {
+ val = readl(hdmi_rx->mem.ss_base);
+ val |= 1 << PL_ENC_CTL_PXL_EN;
+ writel(val, hdmi_rx->mem.ss_base);
+ mdelay(17);
+
+ val = readl(hdmi_rx->mem.ss_base);
+ val |= 1 << PL_ENC_CTL_PXL_VAL;
+ writel(val, hdmi_rx->mem.ss_base);
+ } else {
+ val = readl(hdmi_rx->mem.ss_base);
+ val |= ~(1 << PL_ENC_CTL_PXL_VAL);
+ writel(val, hdmi_rx->mem.ss_base);
+ mdelay(17);
+
+ val = readl(hdmi_rx->mem.ss_base);
+ val |= ~(1 << PL_ENC_CTL_PXL_EN);
+ writel(val, hdmi_rx->mem.ss_base);
+ }
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops imx_video_ops_hdmi = {
+ .s_stream = mxc_hdmi_s_stream,
+ .g_parm = mxc_hdmi_g_parm,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media Operations
+ */
+
+static const struct media_entity_operations hdmi_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/* -----------------------------------------------------------------------------
+ * v4l2_subdev_pad_ops
+ */
+static int mxc_hdmi_enum_framesizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+
+ if (fse->index > 1)
+ return -EINVAL;
+
+ fse->min_width = hdmi_rx->timings->timings.bt.width;
+ fse->max_width = fse->min_width;
+
+ fse->min_height = hdmi_rx->timings->timings.bt.height;
+ fse->max_height = fse->min_height;
+ return 0;
+}
+static int mxc_hdmi_enum_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+
+ if (fie->index < 0 || fie->index > 8)
+ return -EINVAL;
+
+ if (fie->width == 0 || fie->height == 0 ||
+ fie->code == 0) {
+ pr_warning("Please assign pixel format, width and height.\n");
+ return -EINVAL;
+ }
+
+ fie->interval.numerator = 1;
+
+ /* TODO Reserved to extension */
+ fie->interval.denominator = hdmi_rx->timings->fps;
+ return 0;
+}
+
+static int mxc_hdmi_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index != 0)
+ return -EINVAL;
+
+ code->code = MEDIA_BUS_FMT_RGB888_1X24;
+
+ return 0;
+}
+
+static int mxc_hdmi_get_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *sdformat)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+ struct v4l2_mbus_framefmt *mbusformat = &sdformat->format;
+
+ if (sdformat->pad != MXC_HDMI_RX_PAD_SOURCE)
+ return -EINVAL;
+
+ switch (hdmi_rx->pixel_encoding) {
+ case PIXEL_ENCODING_YUV422:
+ mbusformat->code = MEDIA_BUS_FMT_YUYV8_1X16;
+ break;
+ case PIXEL_ENCODING_YUV420:
+ mbusformat->code = MEDIA_BUS_FMT_UV8_1X8;
+ break;
+ case PIXEL_ENCODING_YUV444:
+ mbusformat->code = MEDIA_BUS_FMT_AYUV8_1X32;
+ break;
+ default:
+ mbusformat->code = MEDIA_BUS_FMT_RGB888_1X24;
+ }
+
+ mbusformat->width = hdmi_rx->timings->timings.bt.width;
+ mbusformat->height = hdmi_rx->timings->timings.bt.height;
+ mbusformat->colorspace = V4L2_COLORSPACE_JPEG;
+
+ return 0;
+}
+
+static int mxc_hdmi_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+
+ memset(edid->reserved, 0, sizeof(edid->reserved));
+
+ if (!hdmi_rx->edid.present)
+ return -ENODATA;
+
+ if (edid->start_block == 0 && edid->blocks == 0) {
+ edid->blocks = hdmi_rx->edid.blocks;
+ return 0;
+ }
+
+ if (edid->start_block >= hdmi_rx->edid.blocks)
+ return -EINVAL;
+
+ if (edid->start_block + edid->blocks > hdmi_rx->edid.blocks)
+ edid->blocks = hdmi_rx->edid.blocks - edid->start_block;
+
+ memcpy(edid->edid, hdmi_rx->edid.edid + edid->start_block * 128,
+ edid->blocks * 128);
+
+ return 0;
+}
+
+static int mxc_hdmi_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+ state_struct *state = &hdmi_rx->state;
+ int err, i;
+
+ memset(edid->reserved, 0, sizeof(edid->reserved));
+
+ if (edid->start_block != 0)
+ return -EINVAL;
+
+ if (edid->blocks == 0) {
+ /* Default EDID */
+ hdmi_rx->edid.blocks = 2;
+ hdmi_rx->edid.present = true;
+ } else if (edid->blocks > 4) {
+ edid->blocks = 4;
+ return -E2BIG;
+ } else {
+ memcpy(hdmi_rx->edid.edid, edid->edid, 128 * edid->blocks);
+ hdmi_rx->edid.blocks = edid->blocks;
+ hdmi_rx->edid.present = true;
+ }
+
+ for (i = 0; i < hdmi_rx->edid.blocks; i++) {
+ /* EDID block */
+ err = CDN_API_HDMIRX_SET_EDID_blocking(state, 0, i, &hdmi_rx->edid.edid[i * 128]);
+ if (err != CDN_OK) {
+ v4l2_err(sd, "error %d writing edid pad %d\n", err, edid->pad);
+ return -err;
+ }
+ }
+
+ return 0;
+}
+
+static bool mxc_hdmi_check_dv_timings(const struct v4l2_dv_timings *timings,
+ void *hdl)
+{
+ const struct mxc_hdmi_rx_dev_video_standards *stds =
+ mxc_hdmi_video_standards;
+ u32 i;
+
+ for (i = 0; stds[i].timings.bt.width; i++)
+ if (v4l2_match_dv_timings(timings, &stds[i].timings, 0, false))
+ return true;
+
+ return false;
+}
+
+static int mxc_hdmi_enum_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_enum_dv_timings *timings)
+{
+ return v4l2_enum_dv_timings_cap(timings, &mxc_hdmi_timings_cap,
+ mxc_hdmi_check_dv_timings, NULL);
+}
+
+static int mxc_hdmi_dv_timings_cap(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings_cap *cap)
+{
+ *cap = mxc_hdmi_timings_cap;
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops imx_pad_ops_hdmi = {
+ .enum_mbus_code = mxc_hdmi_enum_mbus_code,
+ .enum_frame_size = mxc_hdmi_enum_framesizes,
+ .enum_frame_interval = mxc_hdmi_enum_frame_interval,
+ .get_fmt = mxc_hdmi_get_format,
+ .get_edid = mxc_hdmi_get_edid,
+ .set_edid = mxc_hdmi_set_edid,
+ .dv_timings_cap = mxc_hdmi_dv_timings_cap,
+ .enum_dv_timings = mxc_hdmi_enum_dv_timings,
+};
+
+static int mxc_hdmi_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = imx_sd_to_hdmi(sd);
+ struct device *dev = &hdmi_rx->pdev->dev;
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ return 0;
+}
+static struct v4l2_subdev_core_ops imx_core_ops_hdmi = {
+ .s_power = mxc_hdmi_s_power,
+};
+
+/* -----------------------------------------------------------------------------
+ * v4l2_subdev_ops
+ */
+static const struct v4l2_subdev_ops imx_ops_hdmi = {
+ .core = &imx_core_ops_hdmi,
+ .video = &imx_video_ops_hdmi,
+ .pad = &imx_pad_ops_hdmi,
+};
+
+void imx8qm_hdmi_phy_reset(state_struct *state, u8 reset)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = state_to_mxc_hdmirx(state);
+ sc_err_t sciErr;
+
+ dev_dbg(&hdmi_rx->pdev->dev, "%s\n", __func__);
+ /* set the pixel link mode and pixel type */
+ sciErr = sc_misc_set_control(hdmi_rx->ipcHndl, SC_R_HDMI_RX, SC_C_PHY_RESET, reset);
+ if (sciErr != SC_ERR_NONE)
+ DRM_ERROR("SC_R_HDMI PHY reset failed %d!\n", sciErr);
+}
+
+static int imx8qm_hdp_read(struct hdp_mem *mem, u32 addr, u32 *value)
+{
+ u32 temp;
+ void *tmp_addr = (addr & 0xfff) + mem->regs_base;
+ void *off_addr = 0x4 + mem->ss_base;;
+
+ __raw_writel(addr >> 12, off_addr);
+ temp = __raw_readl((volatile u32 *)tmp_addr);
+
+ *value = temp;
+ return 0;
+}
+
+static int imx8qm_hdp_write(struct hdp_mem *mem, u32 addr, u32 value)
+{
+ void *tmp_addr = (addr & 0xfff) + mem->regs_base;
+ void *off_addr = 0x4 + mem->ss_base;;
+
+ __raw_writel(addr >> 12, off_addr);
+
+ __raw_writel(value, (volatile u32 *) tmp_addr);
+
+ return 0;
+}
+
+static int imx8qm_hdp_sread(struct hdp_mem *mem, u32 addr, u32 *value)
+{
+ u32 temp;
+ void *tmp_addr = (addr & 0xfff) + mem->regs_base;
+ void *off_addr = 0xc + mem->ss_base;;
+
+ __raw_writel(addr >> 12, off_addr);
+
+ temp = __raw_readl((volatile u32 *)tmp_addr);
+ *value = temp;
+ return 0;
+}
+
+static int imx8qm_hdp_swrite(struct hdp_mem *mem, u32 addr, u32 value)
+{
+ void *tmp_addr = (addr & 0xfff) + mem->regs_base;
+ void *off_addr = 0xc + mem->ss_base;
+
+ __raw_writel(addr >> 12, off_addr);
+ __raw_writel(value, (volatile u32 *)tmp_addr);
+
+ return 0;
+}
+static struct hdp_rw_func imx8qm_rw = {
+ .read_reg = imx8qm_hdp_read,
+ .write_reg = imx8qm_hdp_write,
+ .sread_reg = imx8qm_hdp_sread,
+ .swrite_reg = imx8qm_hdp_swrite,
+};
+
+static void mxc_hdmi_state_init(struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+ state_struct *state = &hdmi_rx->state;
+
+ memset(state, 0, sizeof(state_struct));
+ mutex_init(&state->mutex);
+
+ state->mem = &hdmi_rx->mem;
+ state->rw = &imx8qm_rw;
+}
+
+#ifdef CONFIG_IMX_HDP_CEC
+static void mxc_hdmi_cec_init(struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+ state_struct *state = &hdmi_rx->state;
+ struct imx_cec_dev *cec = &hdmi_rx->cec;
+ u32 clk_rate;
+
+ memset(cec, 0, sizeof(struct imx_cec_dev));
+
+ CDN_API_GetClock(state, &clk_rate);
+ cec->clk_div = clk_rate * 10;
+ cec->dev = &hdmi_rx->pdev->dev;
+ cec->mem = &hdmi_rx->mem;
+ cec->rw = &imx8qm_rw;
+}
+#endif
+
+
+int mxc_hdmi_init(struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+ sc_err_t sciErr;
+ u32 ret = 0;
+
+ dev_dbg(&hdmi_rx->pdev->dev, "%s\n", __func__);
+ mxc_hdmi_state_init(hdmi_rx);
+
+ sciErr = sc_ipc_getMuID(&hdmi_rx->mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ DRM_ERROR("Cannot obtain MU ID\n");
+ return -EINVAL;
+ }
+
+ sciErr = sc_ipc_open(&hdmi_rx->ipcHndl, hdmi_rx->mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ DRM_ERROR("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return -EINVAL;
+ }
+
+ ret = hdmi_rx_init(&hdmi_rx->state);
+
+ return ret;
+}
+
+static int mxc_hdmi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mxc_hdmi_rx_dev *hdmi_rx;
+ struct resource *res;
+ int ret = 0;
+
+ dev_dbg(dev, "%s\n", __func__);
+ hdmi_rx = devm_kzalloc(dev, sizeof(*hdmi_rx), GFP_KERNEL);
+ if (!hdmi_rx)
+ return -ENOMEM;
+
+ hdmi_rx->pdev = pdev;
+
+ spin_lock_init(&hdmi_rx->slock);
+
+ /* register map */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hdmi_rx->mem.regs_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(hdmi_rx->mem.regs_base)) {
+ dev_err(dev, "Failed to get HDMI RX CTRL base register\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ hdmi_rx->mem.ss_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(hdmi_rx->mem.ss_base)) {
+ dev_err(dev, "Failed to get HDMI RX CRS base register\n");
+ return -EINVAL;
+ }
+
+#if 0
+ /* TODO B0 */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_warn(dev, "Failed to get IRQ resource\n");
+ return -EINVAL;
+ }
+
+ ret = devm_request_irq(dev, res->start, mxc_hdmi_irq_handler,
+ 0, dev_name(dev), mxc_hdmi);
+ if (ret < 0) {
+ dev_err(dev, "failed to install irq (%d)\n", ret);
+ return -EINVAL;
+ }
+#endif
+
+ v4l2_subdev_init(&hdmi_rx->sd, &imx_ops_hdmi);
+ /* sd.dev may use by match_of */
+ hdmi_rx->sd.dev = dev;
+
+ /* the owner is the same as the i2c_client's driver owner */
+ hdmi_rx->sd.owner = THIS_MODULE;
+ hdmi_rx->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ hdmi_rx->sd.entity.function = MEDIA_ENT_F_IO_DTV;
+
+ /* This allows to retrieve the platform device id by the host driver */
+ v4l2_set_subdevdata(&hdmi_rx->sd, pdev);
+
+ /* initialize name */
+ snprintf(hdmi_rx->sd.name, sizeof(hdmi_rx->sd.name), "%s",
+ MXC_HDMI_RX_SUBDEV_NAME);
+
+ hdmi_rx->pads[MXC_HDMI_RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ hdmi_rx->pads[MXC_HDMI_RX_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ hdmi_rx->sd.entity.ops = &hdmi_media_ops;
+ ret = media_entity_pads_init(&hdmi_rx->sd.entity,
+ MXC_HDMI_RX_PADS_NUM, hdmi_rx->pads);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, hdmi_rx);
+ ret = v4l2_async_register_subdev(&hdmi_rx->sd);
+ if (ret < 0) {
+ dev_err(dev,
+ "%s--Async register failed, ret=%d\n", __func__, ret);
+ media_entity_cleanup(&hdmi_rx->sd.entity);
+ }
+
+ hdmi_rx->is_cec = of_property_read_bool(pdev->dev.of_node, "fsl,cec");
+
+ mxc_hdmi_clock_init(hdmi_rx);
+
+ hdmi_rx->flags = MXC_HDMI_RX_PM_POWERED;
+
+ mxc_hdmi_clock_enable(hdmi_rx);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+ ret = mxc_hdmi_init(hdmi_rx);
+ if (ret) {
+ dev_info(dev, "mxc hdmi rx init failed\n");
+ goto failed;
+ }
+ ret = hdmirx_startup(&hdmi_rx->state);
+ if (ret) {
+ dev_info(dev, "mxc hdmi rx startup failed\n");
+ goto failed;
+ }
+#ifdef CONFIG_IMX_HDP_CEC
+ if (hdmi_rx->is_cec) {
+ mxc_hdmi_cec_init(hdmi_rx);
+ imx_cec_register(&hdmi_rx->cec);
+ }
+#endif
+
+ mxc_hdmi_rx_register_audio_driver(dev);
+
+ dev_info(dev, "mxc hdmi rx probe successfully\n");
+
+ return ret;
+failed:
+ v4l2_async_unregister_subdev(&hdmi_rx->sd);
+ media_entity_cleanup(&hdmi_rx->sd.entity);
+
+ mxc_hdmi_clock_disable(hdmi_rx);
+ pm_runtime_disable(dev);
+ dev_info(dev, "mxc hdmi rx probe failed\n");
+ return ret;
+}
+
+static int mxc_hdmi_remove(struct platform_device *pdev)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = platform_get_drvdata(pdev);
+ state_struct *state = &hdmi_rx->state;
+ struct device *dev = &pdev->dev;
+ u8 sts;
+
+ dev_dbg(dev, "%s\n", __func__);
+ v4l2_async_unregister_subdev(&hdmi_rx->sd);
+ media_entity_cleanup(&hdmi_rx->sd.entity);
+
+#ifdef CONFIG_IMX_HDP_CEC
+ if (hdmi_rx->is_cec)
+ imx_cec_unregister(&hdmi_rx->cec);
+#endif
+
+ /* Reset HDMI RX PHY */
+ CDN_API_HDMIRX_Stop_blocking(state);
+ CDN_API_MainControl_blocking(state, 0, &sts);
+
+ mxc_hdmi_clock_disable(hdmi_rx);
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mxc_hdmi_pm_suspend(struct device *dev)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "%s\n", __func__);
+ if ((hdmi_rx->flags & MXC_HDMI_RX_PM_SUSPENDED) ||
+ (hdmi_rx->flags & MXC_HDMI_RX_RUNTIME_SUSPEND))
+ return 0;
+
+ mxc_hdmi_clock_disable(hdmi_rx);
+ hdmi_rx->flags |= MXC_HDMI_RX_PM_SUSPENDED;
+ hdmi_rx->flags &= ~MXC_HDMI_RX_PM_POWERED;
+
+ return 0;
+}
+
+static int mxc_hdmi_pm_resume(struct device *dev)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = dev_get_drvdata(dev);
+ int ret;
+
+ dev_dbg(dev, "%s\n", __func__);
+ if (hdmi_rx->flags & MXC_HDMI_RX_PM_POWERED)
+ return 0;
+
+ hdmi_rx->flags |= MXC_HDMI_RX_PM_POWERED;
+ hdmi_rx->flags &= ~MXC_HDMI_RX_PM_SUSPENDED;
+
+ ret = mxc_hdmi_clock_enable(hdmi_rx);
+ return (ret) ? -EAGAIN : 0;
+}
+#endif
+
+static int mxc_hdmi_runtime_suspend(struct device *dev)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "%s\n", __func__);
+ if (hdmi_rx->flags & MXC_HDMI_RX_RUNTIME_SUSPEND)
+ return 0;
+
+ if (hdmi_rx->flags & MXC_HDMI_RX_PM_POWERED) {
+ mxc_hdmi_clock_disable(hdmi_rx);
+ hdmi_rx->flags |= MXC_HDMI_RX_RUNTIME_SUSPEND;
+ hdmi_rx->flags &= ~MXC_HDMI_RX_PM_POWERED;
+ }
+ return 0;
+}
+
+static int mxc_hdmi_runtime_resume(struct device *dev)
+{
+ struct mxc_hdmi_rx_dev *hdmi_rx = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "%s\n", __func__);
+ if (hdmi_rx->flags & MXC_HDMI_RX_PM_POWERED)
+ return 0;
+
+ if (hdmi_rx->flags & MXC_HDMI_RX_RUNTIME_SUSPEND) {
+ mxc_hdmi_clock_enable(hdmi_rx);
+ hdmi_rx->flags |= MXC_HDMI_RX_PM_POWERED;
+ hdmi_rx->flags &= ~MXC_HDMI_RX_RUNTIME_SUSPEND;
+ }
+ return 0;
+}
+
+static const struct dev_pm_ops mxc_hdmi_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mxc_hdmi_pm_suspend, mxc_hdmi_pm_resume)
+ SET_RUNTIME_PM_OPS(mxc_hdmi_runtime_suspend, mxc_hdmi_runtime_resume, NULL)
+};
+
+static const struct of_device_id mxc_hdmi_of_match[] = {
+ {.compatible = "fsl,imx-hdmi-rx",},
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mxc_hdmi_of_match);
+
+static struct platform_driver mxc_hdmi_driver = {
+ .probe = mxc_hdmi_probe,
+ .remove = mxc_hdmi_remove,
+ .driver = {
+ .of_match_table = mxc_hdmi_of_match,
+ .name = MXC_HDMI_RX_DRIVER_NAME,
+ .pm = &mxc_hdmi_pm_ops,
+ }
+};
+
+module_platform_driver(mxc_hdmi_driver);
diff --git a/drivers/media/platform/imx8/hdmi/mxc-hdmi-rx.h b/drivers/media/platform/imx8/hdmi/mxc-hdmi-rx.h
new file mode 100644
index 000000000000..5c892d18161c
--- /dev/null
+++ b/drivers/media/platform/imx8/hdmi/mxc-hdmi-rx.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MXC_HDMI_RX_
+#define _MXC_HDMI_RX_
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-dv-timings.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <soc/imx8/sc/sci.h>
+#include <drm/drm_of.h>
+#include <drm/drmP.h>
+
+#include <uapi/linux/v4l2-dv-timings.h>
+
+#include "../../../../mxc/hdp/all.h"
+#include "../../../../mxc/hdp-cec/imx-hdp-cec.h"
+
+#define state_to_mxc_hdmirx(env) \
+ container_of(env, struct mxc_hdmi_rx_dev, state)
+
+#define MXC_HDMI_RX_DRIVER_NAME "mxc-hdmi-rx"
+#define MXC_HDMI_RX_SUBDEV_NAME MXC_HDMI_RX_DRIVER_NAME
+
+#define MXC_HDMI_RX_NODE_NAME "hdmi_rx"
+
+#define MXC_HDMI_RX_MAX_DEVS 2
+#define MXC_HDMI_RX_MAX_LANES 4
+
+#define MXC_HDMI_RX_PAD_SINK 1
+#define MXC_HDMI_RX_PAD_SOURCE 2
+#define MXC_HDMI_RX_PADS_NUM 3
+
+#define CSR_PIXEL_LINK_ENC_CTL 0x00
+#define PL_ENC_CTL_PXL_VAL 15
+#define PL_ENC_CTL_PXL_VPP 14
+#define PL_ENC_CTL_PXL_HPP 13
+#define PL_ENC_CTL_PXL_VCP 12
+#define PL_ENC_CTL_PXL_HCP 11
+#define PL_ENC_CTL_PXL_ADD 9
+#define PL_ENC_CTL_PXL_EXT 7
+#define PL_ENC_CTL_PXL_EN 6
+#define PL_ENC_CTL_PXL_ITC 4
+#define PL_ENC_CTL_PXL_ODD_EVEN 3
+#define PL_ENC_CTL_PXL_TYP 1
+#define PL_ENC_CTL_PXL_YUV 0
+
+#define CSR_HDP_RX_CTRL_CTRL0 0x04
+#define CSR_HDP_RX_CTRL_CTRL1 0x08
+
+struct mxc_hdmi_rx_dev_video_standards {
+ struct v4l2_dv_timings timings;
+ u8 vic;
+ u8 hdmi_vic;
+ u8 fps;
+};
+
+struct mxc_hdmi_rx_dev {
+ spinlock_t slock;
+ struct mutex lock;
+ wait_queue_head_t irq_queue;
+ struct media_pad pads[MXC_HDMI_RX_PADS_NUM];
+
+ struct platform_device *pdev;
+ struct v4l2_device *v4l2_dev;
+ struct v4l2_subdev sd;
+ struct v4l2_async_subdev asd;
+ struct v4l2_ctrl_handler ctrl_hdl;
+ struct v4l2_mbus_framefmt format;
+ struct v4l2_fract aspect_ratio;
+ struct {
+ u8 edid[512];
+ u32 present;
+ u32 blocks;
+ } edid;
+
+ state_struct state;
+ struct clk *sclk;
+ struct clk *pclk;
+ struct clk *ref_clk;
+ struct clk *pxl_clk;
+ struct clk *enc_clk;
+ struct clk *i2s_clk;
+ struct clk *spdif_clk;
+ struct clk *pxl_link_clk;
+ struct hdp_mem mem;
+
+ u32 flags;
+ sc_ipc_t ipcHndl;
+ u32 mu_id;
+ S_HDMI_SCDC_GET_MSG scdcData;
+
+ struct mxc_hdmi_rx_dev_video_standards *timings;
+ u8 vic_code;
+ u8 hdmi_vic;
+ u8 pixel_encoding;
+ u8 color_depth;
+
+ u8 is_cec;
+ struct imx_cec_dev cec;
+ u32 sample_rate;
+ u32 sample_width;
+ u32 channels;
+};
+
+enum mxc_hdmi_rx_power_state {
+ MXC_HDMI_RX_PM_SUSPENDED = 0x01,
+ MXC_HDMI_RX_PM_POWERED = 0x02,
+ MXC_HDMI_RX_RUNTIME_SUSPEND = 0x04,
+};
+
+int hdmirx_startup(state_struct *state);
+void imx8qm_hdmi_phy_reset(state_struct *state, u8 reset);
+int hdmi_rx_init(state_struct *state);
+int mxc_hdmi_frame_timing(struct mxc_hdmi_rx_dev *hdmi_rx);
+void mxc_hdmi_rx_register_audio_driver(struct device *dev);
+
+#endif
diff --git a/drivers/media/platform/imx8/max9286.c b/drivers/media/platform/imx8/max9286.c
new file mode 100644
index 000000000000..64d79a0ef400
--- /dev/null
+++ b/drivers/media/platform/imx8/max9286.c
@@ -0,0 +1,2994 @@
+/*
+ * Copyright 2017-2018 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/i2c.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-subdev.h>
+
+
+#define MAX9271_MAX_SENSOR_NUM 4
+#define CAMERA_USES_15HZ
+
+#define ADDR_MAX9286 0x6A
+#define ADDR_MAX9271 0x40
+#define ADDR_MAX9271_ALL (ADDR_MAX9271 + 5) /* Broadcast address */
+
+#define MIPI_CSI2_SENS_VC0_PAD_SOURCE 0
+#define MIPI_CSI2_SENS_VC1_PAD_SOURCE 1
+#define MIPI_CSI2_SENS_VC2_PAD_SOURCE 2
+#define MIPI_CSI2_SENS_VC3_PAD_SOURCE 3
+#define MIPI_CSI2_SENS_VCX_PADS_NUM 4
+
+#define MAX_FPS 30
+#define MIN_FPS 30
+#define DEFAULT_FPS 30
+
+#define ADDR_OV_SENSOR 0x30
+#define ADDR_AP_SENSOR 0x5D
+
+/*!
+ * Maintains the information on the current state of the sesor.
+ */
+struct imxdpu_videomode {
+ char name[64]; /* may not be needed */
+
+ uint32_t pixelclock; /* Hz */
+
+ /* htotal (pixels) = hlen + hfp + hsync + hbp */
+ uint32_t hlen;
+ uint32_t hfp;
+ uint32_t hbp;
+ uint32_t hsync;
+
+ /* field0 - vtotal (lines) = vlen + vfp + vsync + vbp */
+ uint32_t vlen;
+ uint32_t vfp;
+ uint32_t vbp;
+ uint32_t vsync;
+
+ /* field1 */
+ uint32_t vlen1;
+ uint32_t vfp1;
+ uint32_t vbp1;
+ uint32_t vsync1;
+
+ uint32_t flags;
+
+ uint32_t format;
+ uint32_t dest_format; /*buffer format for capture*/
+
+ int16_t clip_top;
+ int16_t clip_left;
+ uint16_t clip_width;
+ uint16_t clip_height;
+};
+
+struct sensor_data {
+ struct v4l2_subdev subdev;
+ struct media_pad pads[MIPI_CSI2_SENS_VCX_PADS_NUM];
+ struct i2c_client *i2c_client;
+ struct v4l2_mbus_framefmt format;
+ struct v4l2_captureparm streamcap;
+ char running;
+
+ /* control settings */
+ int brightness;
+ int hue;
+ int contrast;
+ int saturation;
+ int red;
+ int green;
+ int blue;
+ int ae_mode;
+
+ u32 mclk;
+ u8 mclk_source;
+ struct clk *sensor_clk;
+ int v_channel;
+ bool is_mipi;
+ struct imxdpu_videomode cap_mode;
+
+ unsigned int sensor_num; /* sensor num connect max9271 */
+ unsigned char sensor_is_there; /* Bit 0~3 for 4 cameras, 0b1= is there; 0b0 = is not there */
+ int pwn_gpio;
+};
+
+static unsigned int g_max9286_width = 1280;
+static unsigned int g_max9286_height = 800;
+
+#define OV10635_REG_PID 0x300A
+#define OV10635_REG_VER 0x300B
+
+struct reg_value {
+ unsigned short reg_addr;
+ unsigned char val;
+ unsigned int delay_ms;
+};
+
+enum ov10635_frame_rate {
+ OV10635_30_FPS,
+};
+
+static struct reg_value ov10635_init_data[] = {
+ { 0x0103, 0x01, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x300c, 0x61, 0 },
+ { 0x301b, 0xff, 0 },
+ { 0x301c, 0xff, 0 },
+ { 0x301a, 0xff, 0 },
+ { 0x3011, 0x42, 0 },
+ { 0x6900, 0x0c, 0 },
+ { 0x6901, 0x11, 0 },
+ { 0x3503, 0x10, 0 },
+ { 0x3025, 0x03, 0 },
+ { 0x3003, 0x20, 0 },
+ { 0x3004, 0x21, 0 },
+ { 0x3005, 0x20, 0 },
+ { 0x3006, 0x91, 0 },
+ { 0x3600, 0x74, 0 },
+ { 0x3601, 0x2b, 0 },
+ { 0x3612, 0x00, 0 },
+ { 0x3611, 0x67, 0 },
+ { 0x3633, 0xca, 0 },
+ { 0x3602, 0x2f, 0 },
+ { 0x3603, 0x00, 0 },
+ { 0x3630, 0x28, 0 },
+ { 0x3631, 0x16, 0 },
+ { 0x3714, 0x10, 0 },
+ { 0x371d, 0x01, 0 },
+ { 0x4300, 0x38, 0 },
+ { 0x3007, 0x01, 0 },
+ { 0x3024, 0x01, 0 },
+ { 0x3020, 0x0b, 0 },
+ { 0x3702, 0x20, 0 },
+ { 0x3703, 0x48, 0 },
+ { 0x3704, 0x32, 0 },
+ { 0x3709, 0xa8, 0 },
+ { 0x3709, 0xa8, 0 },
+ { 0x370c, 0xc7, 0 },
+ { 0x370d, 0x80, 0 },
+ { 0x3712, 0x00, 0 },
+ { 0x3713, 0x20, 0 },
+ { 0x3715, 0x04, 0 },
+ { 0x381d, 0x40, 0 },
+ { 0x381c, 0x00, 0 },
+ { 0x3822, 0x50, 0 },
+ { 0x3824, 0x50, 0 },
+ { 0x3815, 0x8c, 0 },
+ { 0x3804, 0x05, 0 },
+ { 0x3805, 0x1f, 0 },
+ { 0x3800, 0x00, 0 },
+ { 0x3801, 0x00, 0 },
+ { 0x3806, 0x03, 0 },
+ { 0x3807, 0x29, 0 },
+ { 0x3802, 0x00, 0 },
+ { 0x3803, 0x04, 0 },
+ { 0x3808, 0x05, 0 },
+ { 0x3809, 0x00, 0 },
+ { 0x380a, 0x03, 0 },
+ { 0x380b, 0x20, 0 },
+ { 0x380c, 0x07, 0 },
+ { 0x380d, 0x71, 0 },
+ { 0x6e42, 0x03, 0 },
+ { 0x6e43, 0x48, 0 },
+ { 0x380e, 0x03, 0 },
+ { 0x380f, 0x48, 0 },
+ { 0x3813, 0x02, 0 },
+ { 0x3811, 0x10, 0 },
+ { 0x381f, 0x0c, 0 },
+ { 0x3828, 0x03, 0 },
+ { 0x3829, 0x10, 0 },
+ { 0x382a, 0x10, 0 },
+ { 0x382b, 0x10, 0 },
+ { 0x3621, 0x64, 0 },
+ { 0x5005, 0x08, 0 },
+ { 0x56d5, 0x00, 0 },
+ { 0x56d6, 0x80, 0 },
+ { 0x56d7, 0x00, 0 },
+ { 0x56d8, 0x00, 0 },
+ { 0x56d9, 0x00, 0 },
+ { 0x56da, 0x80, 0 },
+ { 0x56db, 0x00, 0 },
+ { 0x56dc, 0x00, 0 },
+ { 0x56e8, 0x00, 0 },
+ { 0x56e9, 0x7f, 0 },
+ { 0x56ea, 0x00, 0 },
+ { 0x56eb, 0x7f, 0 },
+ { 0x5100, 0x00, 0 },
+ { 0x5101, 0x80, 0 },
+ { 0x5102, 0x00, 0 },
+ { 0x5103, 0x80, 0 },
+ { 0x5104, 0x00, 0 },
+ { 0x5105, 0x80, 0 },
+ { 0x5106, 0x00, 0 },
+ { 0x5107, 0x80, 0 },
+ { 0x5108, 0x00, 0 },
+ { 0x5109, 0x00, 0 },
+ { 0x510a, 0x00, 0 },
+ { 0x510b, 0x00, 0 },
+ { 0x510c, 0x00, 0 },
+ { 0x510d, 0x00, 0 },
+ { 0x510e, 0x00, 0 },
+ { 0x510f, 0x00, 0 },
+ { 0x5110, 0x00, 0 },
+ { 0x5111, 0x80, 0 },
+ { 0x5112, 0x00, 0 },
+ { 0x5113, 0x80, 0 },
+ { 0x5114, 0x00, 0 },
+ { 0x5115, 0x80, 0 },
+ { 0x5116, 0x00, 0 },
+ { 0x5117, 0x80, 0 },
+ { 0x5118, 0x00, 0 },
+ { 0x5119, 0x00, 0 },
+ { 0x511a, 0x00, 0 },
+ { 0x511b, 0x00, 0 },
+ { 0x511c, 0x00, 0 },
+ { 0x511d, 0x00, 0 },
+ { 0x511e, 0x00, 0 },
+ { 0x511f, 0x00, 0 },
+ { 0x56d0, 0x00, 0 },
+ { 0x5006, 0x24, 0 },
+ { 0x5608, 0x0d, 0 },
+ { 0x52d7, 0x06, 0 },
+ { 0x528d, 0x08, 0 },
+ { 0x5293, 0x12, 0 },
+ { 0x52d3, 0x12, 0 },
+ { 0x5288, 0x06, 0 },
+ { 0x5289, 0x20, 0 },
+ { 0x52c8, 0x06, 0 },
+ { 0x52c9, 0x20, 0 },
+ { 0x52cd, 0x04, 0 },
+ { 0x5381, 0x00, 0 },
+ { 0x5382, 0xff, 0 },
+ { 0x5589, 0x76, 0 },
+ { 0x558a, 0x47, 0 },
+ { 0x558b, 0xef, 0 },
+ { 0x558c, 0xc9, 0 },
+ { 0x558d, 0x49, 0 },
+ { 0x558e, 0x30, 0 },
+ { 0x558f, 0x67, 0 },
+ { 0x5590, 0x3f, 0 },
+ { 0x5591, 0xf0, 0 },
+ { 0x5592, 0x10, 0 },
+ { 0x55a2, 0x6d, 0 },
+ { 0x55a3, 0x55, 0 },
+ { 0x55a4, 0xc3, 0 },
+ { 0x55a5, 0xb5, 0 },
+ { 0x55a6, 0x43, 0 },
+ { 0x55a7, 0x38, 0 },
+ { 0x55a8, 0x5f, 0 },
+ { 0x55a9, 0x4b, 0 },
+ { 0x55aa, 0xf0, 0 },
+ { 0x55ab, 0x10, 0 },
+ { 0x5581, 0x52, 0 },
+ { 0x5300, 0x01, 0 },
+ { 0x5301, 0x00, 0 },
+ { 0x5302, 0x00, 0 },
+ { 0x5303, 0x0e, 0 },
+ { 0x5304, 0x00, 0 },
+ { 0x5305, 0x0e, 0 },
+ { 0x5306, 0x00, 0 },
+ { 0x5307, 0x36, 0 },
+ { 0x5308, 0x00, 0 },
+ { 0x5309, 0xd9, 0 },
+ { 0x530a, 0x00, 0 },
+ { 0x530b, 0x0f, 0 },
+ { 0x530c, 0x00, 0 },
+ { 0x530d, 0x2c, 0 },
+ { 0x530e, 0x00, 0 },
+ { 0x530f, 0x59, 0 },
+ { 0x5310, 0x00, 0 },
+ { 0x5311, 0x7b, 0 },
+ { 0x5312, 0x00, 0 },
+ { 0x5313, 0x22, 0 },
+ { 0x5314, 0x00, 0 },
+ { 0x5315, 0xd5, 0 },
+ { 0x5316, 0x00, 0 },
+ { 0x5317, 0x13, 0 },
+ { 0x5318, 0x00, 0 },
+ { 0x5319, 0x18, 0 },
+ { 0x531a, 0x00, 0 },
+ { 0x531b, 0x26, 0 },
+ { 0x531c, 0x00, 0 },
+ { 0x531d, 0xdc, 0 },
+ { 0x531e, 0x00, 0 },
+ { 0x531f, 0x02, 0 },
+ { 0x5320, 0x00, 0 },
+ { 0x5321, 0x24, 0 },
+ { 0x5322, 0x00, 0 },
+ { 0x5323, 0x56, 0 },
+ { 0x5324, 0x00, 0 },
+ { 0x5325, 0x85, 0 },
+ { 0x5326, 0x00, 0 },
+ { 0x5327, 0x20, 0 },
+ { 0x5609, 0x01, 0 },
+ { 0x560a, 0x40, 0 },
+ { 0x560b, 0x01, 0 },
+ { 0x560c, 0x40, 0 },
+ { 0x560d, 0x00, 0 },
+ { 0x560e, 0xfa, 0 },
+ { 0x560f, 0x00, 0 },
+ { 0x5610, 0xfa, 0 },
+ { 0x5611, 0x02, 0 },
+ { 0x5612, 0x80, 0 },
+ { 0x5613, 0x02, 0 },
+ { 0x5614, 0x80, 0 },
+ { 0x5615, 0x01, 0 },
+ { 0x5616, 0x2c, 0 },
+ { 0x5617, 0x01, 0 },
+ { 0x5618, 0x2c, 0 },
+ { 0x563b, 0x01, 0 },
+ { 0x563c, 0x01, 0 },
+ { 0x563d, 0x01, 0 },
+ { 0x563e, 0x01, 0 },
+ { 0x563f, 0x03, 0 },
+ { 0x5640, 0x03, 0 },
+ { 0x5641, 0x03, 0 },
+ { 0x5642, 0x05, 0 },
+ { 0x5643, 0x09, 0 },
+ { 0x5644, 0x05, 0 },
+ { 0x5645, 0x05, 0 },
+ { 0x5646, 0x05, 0 },
+ { 0x5647, 0x05, 0 },
+ { 0x5651, 0x00, 0 },
+ { 0x5652, 0x80, 0 },
+ { 0x521a, 0x01, 0 },
+ { 0x521b, 0x03, 0 },
+ { 0x521c, 0x06, 0 },
+ { 0x521d, 0x0a, 0 },
+ { 0x521e, 0x0e, 0 },
+ { 0x521f, 0x12, 0 },
+ { 0x5220, 0x16, 0 },
+ { 0x5223, 0x02, 0 },
+ { 0x5225, 0x04, 0 },
+ { 0x5227, 0x08, 0 },
+ { 0x5229, 0x0c, 0 },
+ { 0x522b, 0x12, 0 },
+ { 0x522d, 0x18, 0 },
+ { 0x522f, 0x1e, 0 },
+ { 0x5241, 0x04, 0 },
+ { 0x5242, 0x01, 0 },
+ { 0x5243, 0x03, 0 },
+ { 0x5244, 0x06, 0 },
+ { 0x5245, 0x0a, 0 },
+ { 0x5246, 0x0e, 0 },
+ { 0x5247, 0x12, 0 },
+ { 0x5248, 0x16, 0 },
+ { 0x524a, 0x03, 0 },
+ { 0x524c, 0x04, 0 },
+ { 0x524e, 0x08, 0 },
+ { 0x5250, 0x0c, 0 },
+ { 0x5252, 0x12, 0 },
+ { 0x5254, 0x18, 0 },
+ { 0x5256, 0x1e, 0 },
+ { 0x4606, 0x07, 0 },
+ { 0x4607, 0x71, 0 },
+ { 0x460a, 0x02, 0 },
+ { 0x460b, 0x70, 0 },
+ { 0x460c, 0x00, 0 },
+ { 0x4620, 0x0e, 0 },
+ { 0x4700, 0x04, 0 },
+ { 0x4701, 0x00, 0 },
+ { 0x4702, 0x01, 0 },
+ { 0x4004, 0x04, 0 },
+ { 0x4005, 0x18, 0 },
+ { 0x4001, 0x06, 0 },
+ { 0x4050, 0x22, 0 },
+ { 0x4051, 0x24, 0 },
+ { 0x4052, 0x02, 0 },
+ { 0x4057, 0x9c, 0 },
+ { 0x405a, 0x00, 0 },
+ { 0x4202, 0x02, 0 },
+ { 0x3023, 0x10, 0 },
+ { 0x100 , 0x0f, 0 },
+ { 0x100 , 0x0f, 0 },
+ { 0x6f10, 0x07, 0 },
+ { 0x6f11, 0x82, 0 },
+ { 0x6f12, 0x04, 0 },
+ { 0x6f13, 0x00, 0 },
+ { 0x6f14, 0x1f, 0 },
+ { 0x6f15, 0xdd, 0 },
+ { 0x6f16, 0x04, 0 },
+ { 0x6f17, 0x04, 0 },
+ { 0x6f18, 0x36, 0 },
+ { 0x6f19, 0x66, 0 },
+ { 0x6f1a, 0x04, 0 },
+ { 0x6f1b, 0x08, 0 },
+ { 0x6f1c, 0x0c, 0 },
+ { 0x6f1d, 0xe7, 0 },
+ { 0x6f1e, 0x04, 0 },
+ { 0x6f1f, 0x0c, 0 },
+ { 0xd000, 0x19, 0 },
+ { 0xd001, 0xa0, 0 },
+ { 0xd002, 0x00, 0 },
+ { 0xd003, 0x01, 0 },
+ { 0xd004, 0xa9, 0 },
+ { 0xd005, 0xad, 0 },
+ { 0xd006, 0x10, 0 },
+ { 0xd007, 0x40, 0 },
+ { 0xd008, 0x44, 0 },
+ { 0xd009, 0x00, 0 },
+ { 0xd00a, 0x68, 0 },
+ { 0xd00b, 0x00, 0 },
+ { 0xd00c, 0x15, 0 },
+ { 0xd00d, 0x00, 0 },
+ { 0xd00e, 0x00, 0 },
+ { 0xd00f, 0x00, 0 },
+ { 0xd010, 0x19, 0 },
+ { 0xd011, 0xa0, 0 },
+ { 0xd012, 0x00, 0 },
+ { 0xd013, 0x01, 0 },
+ { 0xd014, 0xa9, 0 },
+ { 0xd015, 0xad, 0 },
+ { 0xd016, 0x13, 0 },
+ { 0xd017, 0xd0, 0 },
+ { 0xd018, 0x44, 0 },
+ { 0xd019, 0x00, 0 },
+ { 0xd01a, 0x68, 0 },
+ { 0xd01b, 0x00, 0 },
+ { 0xd01c, 0x15, 0 },
+ { 0xd01d, 0x00, 0 },
+ { 0xd01e, 0x00, 0 },
+ { 0xd01f, 0x00, 0 },
+ { 0xd020, 0x19, 0 },
+ { 0xd021, 0xa0, 0 },
+ { 0xd022, 0x00, 0 },
+ { 0xd023, 0x01, 0 },
+ { 0xd024, 0xa9, 0 },
+ { 0xd025, 0xad, 0 },
+ { 0xd026, 0x14, 0 },
+ { 0xd027, 0xb8, 0 },
+ { 0xd028, 0x44, 0 },
+ { 0xd029, 0x00, 0 },
+ { 0xd02a, 0x68, 0 },
+ { 0xd02b, 0x00, 0 },
+ { 0xd02c, 0x15, 0 },
+ { 0xd02d, 0x00, 0 },
+ { 0xd02e, 0x00, 0 },
+ { 0xd02f, 0x00, 0 },
+ { 0xd030, 0x19, 0 },
+ { 0xd031, 0xa0, 0 },
+ { 0xd032, 0x00, 0 },
+ { 0xd033, 0x01, 0 },
+ { 0xd034, 0xa9, 0 },
+ { 0xd035, 0xad, 0 },
+ { 0xd036, 0x14, 0 },
+ { 0xd037, 0xdc, 0 },
+ { 0xd038, 0x44, 0 },
+ { 0xd039, 0x00, 0 },
+ { 0xd03a, 0x68, 0 },
+ { 0xd03b, 0x00, 0 },
+ { 0xd03c, 0x15, 0 },
+ { 0xd03d, 0x00, 0 },
+ { 0xd03e, 0x00, 0 },
+ { 0xd03f, 0x00, 0 },
+ { 0xd040, 0x9c, 0 },
+ { 0xd041, 0x21, 0 },
+ { 0xd042, 0xff, 0 },
+ { 0xd043, 0xe4, 0 },
+ { 0xd044, 0xd4, 0 },
+ { 0xd045, 0x01, 0 },
+ { 0xd046, 0x48, 0 },
+ { 0xd047, 0x00, 0 },
+ { 0xd048, 0xd4, 0 },
+ { 0xd049, 0x01, 0 },
+ { 0xd04a, 0x50, 0 },
+ { 0xd04b, 0x04, 0 },
+ { 0xd04c, 0xd4, 0 },
+ { 0xd04d, 0x01, 0 },
+ { 0xd04e, 0x60, 0 },
+ { 0xd04f, 0x08, 0 },
+ { 0xd050, 0xd4, 0 },
+ { 0xd051, 0x01, 0 },
+ { 0xd052, 0x70, 0 },
+ { 0xd053, 0x0c, 0 },
+ { 0xd054, 0xd4, 0 },
+ { 0xd055, 0x01, 0 },
+ { 0xd056, 0x80, 0 },
+ { 0xd057, 0x10, 0 },
+ { 0xd058, 0x19, 0 },
+ { 0xd059, 0xc0, 0 },
+ { 0xd05a, 0x00, 0 },
+ { 0xd05b, 0x01, 0 },
+ { 0xd05c, 0xa9, 0 },
+ { 0xd05d, 0xce, 0 },
+ { 0xd05e, 0x02, 0 },
+ { 0xd05f, 0xa4, 0 },
+ { 0xd060, 0x9c, 0 },
+ { 0xd061, 0xa0, 0 },
+ { 0xd062, 0x00, 0 },
+ { 0xd063, 0x00, 0 },
+ { 0xd064, 0x84, 0 },
+ { 0xd065, 0x6e, 0 },
+ { 0xd066, 0x00, 0 },
+ { 0xd067, 0x00, 0 },
+ { 0xd068, 0xd8, 0 },
+ { 0xd069, 0x03, 0 },
+ { 0xd06a, 0x28, 0 },
+ { 0xd06b, 0x76, 0 },
+ { 0xd06c, 0x1a, 0 },
+ { 0xd06d, 0x00, 0 },
+ { 0xd06e, 0x00, 0 },
+ { 0xd06f, 0x01, 0 },
+ { 0xd070, 0xaa, 0 },
+ { 0xd071, 0x10, 0 },
+ { 0xd072, 0x03, 0 },
+ { 0xd073, 0xf0, 0 },
+ { 0xd074, 0x18, 0 },
+ { 0xd075, 0x60, 0 },
+ { 0xd076, 0x00, 0 },
+ { 0xd077, 0x01, 0 },
+ { 0xd078, 0xa8, 0 },
+ { 0xd079, 0x63, 0 },
+ { 0xd07a, 0x07, 0 },
+ { 0xd07b, 0x80, 0 },
+ { 0xd07c, 0xe0, 0 },
+ { 0xd07d, 0xa0, 0 },
+ { 0xd07e, 0x00, 0 },
+ { 0xd07f, 0x04, 0 },
+ { 0xd080, 0x18, 0 },
+ { 0xd081, 0xc0, 0 },
+ { 0xd082, 0x00, 0 },
+ { 0xd083, 0x00, 0 },
+ { 0xd084, 0xa8, 0 },
+ { 0xd085, 0xc6, 0 },
+ { 0xd086, 0x00, 0 },
+ { 0xd087, 0x00, 0 },
+ { 0xd088, 0x8c, 0 },
+ { 0xd089, 0x63, 0 },
+ { 0xd08a, 0x00, 0 },
+ { 0xd08b, 0x00, 0 },
+ { 0xd08c, 0xd4, 0 },
+ { 0xd08d, 0x01, 0 },
+ { 0xd08e, 0x28, 0 },
+ { 0xd08f, 0x14, 0 },
+ { 0xd090, 0xd4, 0 },
+ { 0xd091, 0x01, 0 },
+ { 0xd092, 0x30, 0 },
+ { 0xd093, 0x18, 0 },
+ { 0xd094, 0x07, 0 },
+ { 0xd095, 0xff, 0 },
+ { 0xd096, 0xf8, 0 },
+ { 0xd097, 0xfd, 0 },
+ { 0xd098, 0x9c, 0 },
+ { 0xd099, 0x80, 0 },
+ { 0xd09a, 0x00, 0 },
+ { 0xd09b, 0x03, 0 },
+ { 0xd09c, 0xa5, 0 },
+ { 0xd09d, 0x6b, 0 },
+ { 0xd09e, 0x00, 0 },
+ { 0xd09f, 0xff, 0 },
+ { 0xd0a0, 0x18, 0 },
+ { 0xd0a1, 0xc0, 0 },
+ { 0xd0a2, 0x00, 0 },
+ { 0xd0a3, 0x01, 0 },
+ { 0xd0a4, 0xa8, 0 },
+ { 0xd0a5, 0xc6, 0 },
+ { 0xd0a6, 0x01, 0 },
+ { 0xd0a7, 0x02, 0 },
+ { 0xd0a8, 0xe1, 0 },
+ { 0xd0a9, 0x6b, 0 },
+ { 0xd0aa, 0x58, 0 },
+ { 0xd0ab, 0x00, 0 },
+ { 0xd0ac, 0x84, 0 },
+ { 0xd0ad, 0x8e, 0 },
+ { 0xd0ae, 0x00, 0 },
+ { 0xd0af, 0x00, 0 },
+ { 0xd0b0, 0xe1, 0 },
+ { 0xd0b1, 0x6b, 0 },
+ { 0xd0b2, 0x30, 0 },
+ { 0xd0b3, 0x00, 0 },
+ { 0xd0b4, 0x98, 0 },
+ { 0xd0b5, 0xb0, 0 },
+ { 0xd0b6, 0x00, 0 },
+ { 0xd0b7, 0x00, 0 },
+ { 0xd0b8, 0x8c, 0 },
+ { 0xd0b9, 0x64, 0 },
+ { 0xd0ba, 0x00, 0 },
+ { 0xd0bb, 0x6e, 0 },
+ { 0xd0bc, 0xe5, 0 },
+ { 0xd0bd, 0xa5, 0 },
+ { 0xd0be, 0x18, 0 },
+ { 0xd0bf, 0x00, 0 },
+ { 0xd0c0, 0x10, 0 },
+ { 0xd0c1, 0x00, 0 },
+ { 0xd0c2, 0x00, 0 },
+ { 0xd0c3, 0x06, 0 },
+ { 0xd0c4, 0x95, 0 },
+ { 0xd0c5, 0x8b, 0 },
+ { 0xd0c6, 0x00, 0 },
+ { 0xd0c7, 0x00, 0 },
+ { 0xd0c8, 0x94, 0 },
+ { 0xd0c9, 0xa4, 0 },
+ { 0xd0ca, 0x00, 0 },
+ { 0xd0cb, 0x70, 0 },
+ { 0xd0cc, 0xe5, 0 },
+ { 0xd0cd, 0x65, 0 },
+ { 0xd0ce, 0x60, 0 },
+ { 0xd0cf, 0x00, 0 },
+ { 0xd0d0, 0x0c, 0 },
+ { 0xd0d1, 0x00, 0 },
+ { 0xd0d2, 0x00, 0 },
+ { 0xd0d3, 0x62, 0 },
+ { 0xd0d4, 0x15, 0 },
+ { 0xd0d5, 0x00, 0 },
+ { 0xd0d6, 0x00, 0 },
+ { 0xd0d7, 0x00, 0 },
+ { 0xd0d8, 0x18, 0 },
+ { 0xd0d9, 0x60, 0 },
+ { 0xd0da, 0x80, 0 },
+ { 0xd0db, 0x06, 0 },
+ { 0xd0dc, 0xa8, 0 },
+ { 0xd0dd, 0x83, 0 },
+ { 0xd0de, 0x38, 0 },
+ { 0xd0df, 0x29, 0 },
+ { 0xd0e0, 0xa8, 0 },
+ { 0xd0e1, 0xe3, 0 },
+ { 0xd0e2, 0x40, 0 },
+ { 0xd0e3, 0x08, 0 },
+ { 0xd0e4, 0x8c, 0 },
+ { 0xd0e5, 0x84, 0 },
+ { 0xd0e6, 0x00, 0 },
+ { 0xd0e7, 0x00, 0 },
+ { 0xd0e8, 0xa8, 0 },
+ { 0xd0e9, 0xa3, 0 },
+ { 0xd0ea, 0x40, 0 },
+ { 0xd0eb, 0x09, 0 },
+ { 0xd0ec, 0xa8, 0 },
+ { 0xd0ed, 0xc3, 0 },
+ { 0xd0ee, 0x38, 0 },
+ { 0xd0ef, 0x2a, 0 },
+ { 0xd0f0, 0xd8, 0 },
+ { 0xd0f1, 0x07, 0 },
+ { 0xd0f2, 0x20, 0 },
+ { 0xd0f3, 0x00, 0 },
+ { 0xd0f4, 0x8c, 0 },
+ { 0xd0f5, 0x66, 0 },
+ { 0xd0f6, 0x00, 0 },
+ { 0xd0f7, 0x00, 0 },
+ { 0xd0f8, 0xd8, 0 },
+ { 0xd0f9, 0x05, 0 },
+ { 0xd0fa, 0x18, 0 },
+ { 0xd0fb, 0x00, 0 },
+ { 0xd0fc, 0x18, 0 },
+ { 0xd0fd, 0x60, 0 },
+ { 0xd0fe, 0x00, 0 },
+ { 0xd0ff, 0x01, 0 },
+ { 0xd100, 0x98, 0 },
+ { 0xd101, 0x90, 0 },
+ { 0xd102, 0x00, 0 },
+ { 0xd103, 0x00, 0 },
+ { 0xd104, 0x84, 0 },
+ { 0xd105, 0xae, 0 },
+ { 0xd106, 0x00, 0 },
+ { 0xd107, 0x00, 0 },
+ { 0xd108, 0xa8, 0 },
+ { 0xd109, 0x63, 0 },
+ { 0xd10a, 0x06, 0 },
+ { 0xd10b, 0x4c, 0 },
+ { 0xd10c, 0x9c, 0 },
+ { 0xd10d, 0xc0, 0 },
+ { 0xd10e, 0x00, 0 },
+ { 0xd10f, 0x00, 0 },
+ { 0xd110, 0xd8, 0 },
+ { 0xd111, 0x03, 0 },
+ { 0xd112, 0x30, 0 },
+ { 0xd113, 0x00, 0 },
+ { 0xd114, 0x8c, 0 },
+ { 0xd115, 0x65, 0 },
+ { 0xd116, 0x00, 0 },
+ { 0xd117, 0x6e, 0 },
+ { 0xd118, 0xe5, 0 },
+ { 0xd119, 0x84, 0 },
+ { 0xd11a, 0x18, 0 },
+ { 0xd11b, 0x00, 0 },
+ { 0xd11c, 0x10, 0 },
+ { 0xd11d, 0x00, 0 },
+ { 0xd11e, 0x00, 0 },
+ { 0xd11f, 0x07, 0 },
+ { 0xd120, 0x18, 0 },
+ { 0xd121, 0x80, 0 },
+ { 0xd122, 0x80, 0 },
+ { 0xd123, 0x06, 0 },
+ { 0xd124, 0x94, 0 },
+ { 0xd125, 0x65, 0 },
+ { 0xd126, 0x00, 0 },
+ { 0xd127, 0x70, 0 },
+ { 0xd128, 0xe5, 0 },
+ { 0xd129, 0x43, 0 },
+ { 0xd12a, 0x60, 0 },
+ { 0xd12b, 0x00, 0 },
+ { 0xd12c, 0x0c, 0 },
+ { 0xd12d, 0x00, 0 },
+ { 0xd12e, 0x00, 0 },
+ { 0xd12f, 0x3e, 0 },
+ { 0xd130, 0xa8, 0 },
+ { 0xd131, 0x64, 0 },
+ { 0xd132, 0x38, 0 },
+ { 0xd133, 0x24, 0 },
+ { 0xd134, 0x18, 0 },
+ { 0xd135, 0x80, 0 },
+ { 0xd136, 0x80, 0 },
+ { 0xd137, 0x06, 0 },
+ { 0xd138, 0xa8, 0 },
+ { 0xd139, 0x64, 0 },
+ { 0xd13a, 0x38, 0 },
+ { 0xd13b, 0x24, 0 },
+ { 0xd13c, 0x8c, 0 },
+ { 0xd13d, 0x63, 0 },
+ { 0xd13e, 0x00, 0 },
+ { 0xd13f, 0x00, 0 },
+ { 0xd140, 0xa4, 0 },
+ { 0xd141, 0x63, 0 },
+ { 0xd142, 0x00, 0 },
+ { 0xd143, 0x40, 0 },
+ { 0xd144, 0xbc, 0 },
+ { 0xd145, 0x23, 0 },
+ { 0xd146, 0x00, 0 },
+ { 0xd147, 0x00, 0 },
+ { 0xd148, 0x0c, 0 },
+ { 0xd149, 0x00, 0 },
+ { 0xd14a, 0x00, 0 },
+ { 0xd14b, 0x2a, 0 },
+ { 0xd14c, 0xa8, 0 },
+ { 0xd14d, 0x64, 0 },
+ { 0xd14e, 0x6e, 0 },
+ { 0xd14f, 0x44, 0 },
+ { 0xd150, 0x19, 0 },
+ { 0xd151, 0x00, 0 },
+ { 0xd152, 0x80, 0 },
+ { 0xd153, 0x06, 0 },
+ { 0xd154, 0xa8, 0 },
+ { 0xd155, 0xe8, 0 },
+ { 0xd156, 0x3d, 0 },
+ { 0xd157, 0x05, 0 },
+ { 0xd158, 0x8c, 0 },
+ { 0xd159, 0x67, 0 },
+ { 0xd15a, 0x00, 0 },
+ { 0xd15b, 0x00, 0 },
+ { 0xd15c, 0xb8, 0 },
+ { 0xd15d, 0x63, 0 },
+ { 0xd15e, 0x00, 0 },
+ { 0xd15f, 0x18, 0 },
+ { 0xd160, 0xb8, 0 },
+ { 0xd161, 0x63, 0 },
+ { 0xd162, 0x00, 0 },
+ { 0xd163, 0x98, 0 },
+ { 0xd164, 0xbc, 0 },
+ { 0xd165, 0x03, 0 },
+ { 0xd166, 0x00, 0 },
+ { 0xd167, 0x00, 0 },
+ { 0xd168, 0x10, 0 },
+ { 0xd169, 0x00, 0 },
+ { 0xd16a, 0x00, 0 },
+ { 0xd16b, 0x10, 0 },
+ { 0xd16c, 0xa9, 0 },
+ { 0xd16d, 0x48, 0 },
+ { 0xd16e, 0x67, 0 },
+ { 0xd16f, 0x02, 0 },
+ { 0xd170, 0xb8, 0 },
+ { 0xd171, 0xa3, 0 },
+ { 0xd172, 0x00, 0 },
+ { 0xd173, 0x19, 0 },
+ { 0xd174, 0x8c, 0 },
+ { 0xd175, 0x8a, 0 },
+ { 0xd176, 0x00, 0 },
+ { 0xd177, 0x00, 0 },
+ { 0xd178, 0xa9, 0 },
+ { 0xd179, 0x68, 0 },
+ { 0xd17a, 0x67, 0 },
+ { 0xd17b, 0x03, 0 },
+ { 0xd17c, 0xb8, 0 },
+ { 0xd17d, 0xc4, 0 },
+ { 0xd17e, 0x00, 0 },
+ { 0xd17f, 0x08, 0 },
+ { 0xd180, 0x8c, 0 },
+ { 0xd181, 0x6b, 0 },
+ { 0xd182, 0x00, 0 },
+ { 0xd183, 0x00, 0 },
+ { 0xd184, 0xb8, 0 },
+ { 0xd185, 0x85, 0 },
+ { 0xd186, 0x00, 0 },
+ { 0xd187, 0x98, 0 },
+ { 0xd188, 0xe0, 0 },
+ { 0xd189, 0x63, 0 },
+ { 0xd18a, 0x30, 0 },
+ { 0xd18b, 0x04, 0 },
+ { 0xd18c, 0xe0, 0 },
+ { 0xd18d, 0x64, 0 },
+ { 0xd18e, 0x18, 0 },
+ { 0xd18f, 0x00, 0 },
+ { 0xd190, 0xa4, 0 },
+ { 0xd191, 0x83, 0 },
+ { 0xd192, 0xff, 0 },
+ { 0xd193, 0xff, 0 },
+ { 0xd194, 0xb8, 0 },
+ { 0xd195, 0x64, 0 },
+ { 0xd196, 0x00, 0 },
+ { 0xd197, 0x48, 0 },
+ { 0xd198, 0xd8, 0 },
+ { 0xd199, 0x0a, 0 },
+ { 0xd19a, 0x18, 0 },
+ { 0xd19b, 0x00, 0 },
+ { 0xd19c, 0xd8, 0 },
+ { 0xd19d, 0x0b, 0 },
+ { 0xd19e, 0x20, 0 },
+ { 0xd19f, 0x00, 0 },
+ { 0xd1a0, 0x9c, 0 },
+ { 0xd1a1, 0x60, 0 },
+ { 0xd1a2, 0x00, 0 },
+ { 0xd1a3, 0x00, 0 },
+ { 0xd1a4, 0xd8, 0 },
+ { 0xd1a5, 0x07, 0 },
+ { 0xd1a6, 0x18, 0 },
+ { 0xd1a7, 0x00, 0 },
+ { 0xd1a8, 0xa8, 0 },
+ { 0xd1a9, 0x68, 0 },
+ { 0xd1aa, 0x38, 0 },
+ { 0xd1ab, 0x22, 0 },
+ { 0xd1ac, 0x9c, 0 },
+ { 0xd1ad, 0x80, 0 },
+ { 0xd1ae, 0x00, 0 },
+ { 0xd1af, 0x70, 0 },
+ { 0xd1b0, 0xa8, 0 },
+ { 0xd1b1, 0xe8, 0 },
+ { 0xd1b2, 0x38, 0 },
+ { 0xd1b3, 0x43, 0 },
+ { 0xd1b4, 0xd8, 0 },
+ { 0xd1b5, 0x03, 0 },
+ { 0xd1b6, 0x20, 0 },
+ { 0xd1b7, 0x00, 0 },
+ { 0xd1b8, 0x9c, 0 },
+ { 0xd1b9, 0xa0, 0 },
+ { 0xd1ba, 0x00, 0 },
+ { 0xd1bb, 0x00, 0 },
+ { 0xd1bc, 0xa8, 0 },
+ { 0xd1bd, 0xc8, 0 },
+ { 0xd1be, 0x38, 0 },
+ { 0xd1bf, 0x42, 0 },
+ { 0xd1c0, 0x8c, 0 },
+ { 0xd1c1, 0x66, 0 },
+ { 0xd1c2, 0x00, 0 },
+ { 0xd1c3, 0x00, 0 },
+ { 0xd1c4, 0x9c, 0 },
+ { 0xd1c5, 0xa5, 0 },
+ { 0xd1c6, 0x00, 0 },
+ { 0xd1c7, 0x01, 0 },
+ { 0xd1c8, 0xb8, 0 },
+ { 0xd1c9, 0x83, 0 },
+ { 0xd1ca, 0x00, 0 },
+ { 0xd1cb, 0x08, 0 },
+ { 0xd1cc, 0xa4, 0 },
+ { 0xd1cd, 0xa5, 0 },
+ { 0xd1ce, 0x00, 0 },
+ { 0xd1cf, 0xff, 0 },
+ { 0xd1d0, 0x8c, 0 },
+ { 0xd1d1, 0x67, 0 },
+ { 0xd1d2, 0x00, 0 },
+ { 0xd1d3, 0x00, 0 },
+ { 0xd1d4, 0xe0, 0 },
+ { 0xd1d5, 0x63, 0 },
+ { 0xd1d6, 0x20, 0 },
+ { 0xd1d7, 0x00, 0 },
+ { 0xd1d8, 0xa4, 0 },
+ { 0xd1d9, 0x63, 0 },
+ { 0xd1da, 0xff, 0 },
+ { 0xd1db, 0xff, 0 },
+ { 0xd1dc, 0xbc, 0 },
+ { 0xd1dd, 0x43, 0 },
+ { 0xd1de, 0x00, 0 },
+ { 0xd1df, 0x07, 0 },
+ { 0xd1e0, 0x0c, 0 },
+ { 0xd1e1, 0x00, 0 },
+ { 0xd1e2, 0x00, 0 },
+ { 0xd1e3, 0x5b, 0 },
+ { 0xd1e4, 0xbc, 0 },
+ { 0xd1e5, 0x05, 0 },
+ { 0xd1e6, 0x00, 0 },
+ { 0xd1e7, 0x02, 0 },
+ { 0xd1e8, 0x03, 0 },
+ { 0xd1e9, 0xff, 0 },
+ { 0xd1ea, 0xff, 0 },
+ { 0xd1eb, 0xf6, 0 },
+ { 0xd1ec, 0x9c, 0 },
+ { 0xd1ed, 0xa0, 0 },
+ { 0xd1ee, 0x00, 0 },
+ { 0xd1ef, 0x00, 0 },
+ { 0xd1f0, 0xa8, 0 },
+ { 0xd1f1, 0xa4, 0 },
+ { 0xd1f2, 0x55, 0 },
+ { 0xd1f3, 0x86, 0 },
+ { 0xd1f4, 0x8c, 0 },
+ { 0xd1f5, 0x63, 0 },
+ { 0xd1f6, 0x00, 0 },
+ { 0xd1f7, 0x00, 0 },
+ { 0xd1f8, 0xa8, 0 },
+ { 0xd1f9, 0xc4, 0 },
+ { 0xd1fa, 0x6e, 0 },
+ { 0xd1fb, 0x45, 0 },
+ { 0xd1fc, 0xa8, 0 },
+ { 0xd1fd, 0xe4, 0 },
+ { 0xd1fe, 0x55, 0 },
+ { 0xd1ff, 0x87, 0 },
+ { 0xd200, 0xd8, 0 },
+ { 0xd201, 0x05, 0 },
+ { 0xd202, 0x18, 0 },
+ { 0xd203, 0x00, 0 },
+ { 0xd204, 0x8c, 0 },
+ { 0xd205, 0x66, 0 },
+ { 0xd206, 0x00, 0 },
+ { 0xd207, 0x00, 0 },
+ { 0xd208, 0xa8, 0 },
+ { 0xd209, 0xa4, 0 },
+ { 0xd20a, 0x6e, 0 },
+ { 0xd20b, 0x46, 0 },
+ { 0xd20c, 0xd8, 0 },
+ { 0xd20d, 0x07, 0 },
+ { 0xd20e, 0x18, 0 },
+ { 0xd20f, 0x00, 0 },
+ { 0xd210, 0xa8, 0 },
+ { 0xd211, 0x84, 0 },
+ { 0xd212, 0x55, 0 },
+ { 0xd213, 0x88, 0 },
+ { 0xd214, 0x8c, 0 },
+ { 0xd215, 0x65, 0 },
+ { 0xd216, 0x00, 0 },
+ { 0xd217, 0x00, 0 },
+ { 0xd218, 0xd8, 0 },
+ { 0xd219, 0x04, 0 },
+ { 0xd21a, 0x18, 0 },
+ { 0xd21b, 0x00, 0 },
+ { 0xd21c, 0x03, 0 },
+ { 0xd21d, 0xff, 0 },
+ { 0xd21e, 0xff, 0 },
+ { 0xd21f, 0xce, 0 },
+ { 0xd220, 0x19, 0 },
+ { 0xd221, 0x00, 0 },
+ { 0xd222, 0x80, 0 },
+ { 0xd223, 0x06, 0 },
+ { 0xd224, 0x8c, 0 },
+ { 0xd225, 0x63, 0 },
+ { 0xd226, 0x00, 0 },
+ { 0xd227, 0x00, 0 },
+ { 0xd228, 0xa4, 0 },
+ { 0xd229, 0x63, 0 },
+ { 0xd22a, 0x00, 0 },
+ { 0xd22b, 0x40, 0 },
+ { 0xd22c, 0xbc, 0 },
+ { 0xd22d, 0x23, 0 },
+ { 0xd22e, 0x00, 0 },
+ { 0xd22f, 0x00, 0 },
+ { 0xd230, 0x13, 0 },
+ { 0xd231, 0xff, 0 },
+ { 0xd232, 0xff, 0 },
+ { 0xd233, 0xc8, 0 },
+ { 0xd234, 0x9d, 0 },
+ { 0xd235, 0x00, 0 },
+ { 0xd236, 0x00, 0 },
+ { 0xd237, 0x40, 0 },
+ { 0xd238, 0xa8, 0 },
+ { 0xd239, 0x64, 0 },
+ { 0xd23a, 0x55, 0 },
+ { 0xd23b, 0x86, 0 },
+ { 0xd23c, 0xa8, 0 },
+ { 0xd23d, 0xa4, 0 },
+ { 0xd23e, 0x55, 0 },
+ { 0xd23f, 0x87, 0 },
+ { 0xd240, 0xd8, 0 },
+ { 0xd241, 0x03, 0 },
+ { 0xd242, 0x40, 0 },
+ { 0xd243, 0x00, 0 },
+ { 0xd244, 0xa8, 0 },
+ { 0xd245, 0x64, 0 },
+ { 0xd246, 0x55, 0 },
+ { 0xd247, 0x88, 0 },
+ { 0xd248, 0xd8, 0 },
+ { 0xd249, 0x05, 0 },
+ { 0xd24a, 0x40, 0 },
+ { 0xd24b, 0x00, 0 },
+ { 0xd24c, 0xd8, 0 },
+ { 0xd24d, 0x03, 0 },
+ { 0xd24e, 0x40, 0 },
+ { 0xd24f, 0x00, 0 },
+ { 0xd250, 0x03, 0 },
+ { 0xd251, 0xff, 0 },
+ { 0xd252, 0xff, 0 },
+ { 0xd253, 0xc1, 0 },
+ { 0xd254, 0x19, 0 },
+ { 0xd255, 0x00, 0 },
+ { 0xd256, 0x80, 0 },
+ { 0xd257, 0x06, 0 },
+ { 0xd258, 0x94, 0 },
+ { 0xd259, 0x84, 0 },
+ { 0xd25a, 0x00, 0 },
+ { 0xd25b, 0x72, 0 },
+ { 0xd25c, 0xe5, 0 },
+ { 0xd25d, 0xa4, 0 },
+ { 0xd25e, 0x60, 0 },
+ { 0xd25f, 0x00, 0 },
+ { 0xd260, 0x0c, 0 },
+ { 0xd261, 0x00, 0 },
+ { 0xd262, 0x00, 0 },
+ { 0xd263, 0x3f, 0 },
+ { 0xd264, 0x9d, 0 },
+ { 0xd265, 0x60, 0 },
+ { 0xd266, 0x01, 0 },
+ { 0xd267, 0x00, 0 },
+ { 0xd268, 0x85, 0 },
+ { 0xd269, 0x4e, 0 },
+ { 0xd26a, 0x00, 0 },
+ { 0xd26b, 0x00, 0 },
+ { 0xd26c, 0x98, 0 },
+ { 0xd26d, 0x70, 0 },
+ { 0xd26e, 0x00, 0 },
+ { 0xd26f, 0x00, 0 },
+ { 0xd270, 0x8c, 0 },
+ { 0xd271, 0x8a, 0 },
+ { 0xd272, 0x00, 0 },
+ { 0xd273, 0x6f, 0 },
+ { 0xd274, 0xe5, 0 },
+ { 0xd275, 0x63, 0 },
+ { 0xd276, 0x20, 0 },
+ { 0xd277, 0x00, 0 },
+ { 0xd278, 0x10, 0 },
+ { 0xd279, 0x00, 0 },
+ { 0xd27a, 0x00, 0 },
+ { 0xd27b, 0x07, 0 },
+ { 0xd27c, 0x15, 0 },
+ { 0xd27d, 0x00, 0 },
+ { 0xd27e, 0x00, 0 },
+ { 0xd27f, 0x00, 0 },
+ { 0xd280, 0x8c, 0 },
+ { 0xd281, 0xaa, 0 },
+ { 0xd282, 0x00, 0 },
+ { 0xd283, 0x6e, 0 },
+ { 0xd284, 0xe0, 0 },
+ { 0xd285, 0x63, 0 },
+ { 0xd286, 0x28, 0 },
+ { 0xd287, 0x02, 0 },
+ { 0xd288, 0xe0, 0 },
+ { 0xd289, 0x84, 0 },
+ { 0xd28a, 0x28, 0 },
+ { 0xd28b, 0x02, 0 },
+ { 0xd28c, 0x07, 0 },
+ { 0xd28d, 0xff, 0 },
+ { 0xd28e, 0xf8, 0 },
+ { 0xd28f, 0x66, 0 },
+ { 0xd290, 0xe0, 0 },
+ { 0xd291, 0x63, 0 },
+ { 0xd292, 0x5b, 0 },
+ { 0xd293, 0x06, 0 },
+ { 0xd294, 0x8c, 0 },
+ { 0xd295, 0x6a, 0 },
+ { 0xd296, 0x00, 0 },
+ { 0xd297, 0x77, 0 },
+ { 0xd298, 0xe0, 0 },
+ { 0xd299, 0x63, 0 },
+ { 0xd29a, 0x5b, 0 },
+ { 0xd29b, 0x06, 0 },
+ { 0xd29c, 0xbd, 0 },
+ { 0xd29d, 0x63, 0 },
+ { 0xd29e, 0x00, 0 },
+ { 0xd29f, 0x00, 0 },
+ { 0xd2a0, 0x0c, 0 },
+ { 0xd2a1, 0x00, 0 },
+ { 0xd2a2, 0x00, 0 },
+ { 0xd2a3, 0x3c, 0 },
+ { 0xd2a4, 0x15, 0 },
+ { 0xd2a5, 0x00, 0 },
+ { 0xd2a6, 0x00, 0 },
+ { 0xd2a7, 0x00, 0 },
+ { 0xd2a8, 0x8c, 0 },
+ { 0xd2a9, 0x8a, 0 },
+ { 0xd2aa, 0x00, 0 },
+ { 0xd2ab, 0x78, 0 },
+ { 0xd2ac, 0xb8, 0 },
+ { 0xd2ad, 0x63, 0 },
+ { 0xd2ae, 0x00, 0 },
+ { 0xd2af, 0x88, 0 },
+ { 0xd2b0, 0xe1, 0 },
+ { 0xd2b1, 0x64, 0 },
+ { 0xd2b2, 0x5b, 0 },
+ { 0xd2b3, 0x06, 0 },
+ { 0xd2b4, 0xbd, 0 },
+ { 0xd2b5, 0x6b, 0 },
+ { 0xd2b6, 0x00, 0 },
+ { 0xd2b7, 0x00, 0 },
+ { 0xd2b8, 0x0c, 0 },
+ { 0xd2b9, 0x00, 0 },
+ { 0xd2ba, 0x00, 0 },
+ { 0xd2bb, 0x34, 0 },
+ { 0xd2bc, 0xd4, 0 },
+ { 0xd2bd, 0x01, 0 },
+ { 0xd2be, 0x18, 0 },
+ { 0xd2bf, 0x14, 0 },
+ { 0xd2c0, 0xb9, 0 },
+ { 0xd2c1, 0x6b, 0 },
+ { 0xd2c2, 0x00, 0 },
+ { 0xd2c3, 0x88, 0 },
+ { 0xd2c4, 0x85, 0 },
+ { 0xd2c5, 0x01, 0 },
+ { 0xd2c6, 0x00, 0 },
+ { 0xd2c7, 0x14, 0 },
+ { 0xd2c8, 0xbd, 0 },
+ { 0xd2c9, 0x68, 0 },
+ { 0xd2ca, 0x00, 0 },
+ { 0xd2cb, 0x00, 0 },
+ { 0xd2cc, 0x0c, 0 },
+ { 0xd2cd, 0x00, 0 },
+ { 0xd2ce, 0x00, 0 },
+ { 0xd2cf, 0x2c, 0 },
+ { 0xd2d0, 0xd4, 0 },
+ { 0xd2d1, 0x01, 0 },
+ { 0xd2d2, 0x58, 0 },
+ { 0xd2d3, 0x18, 0 },
+ { 0xd2d4, 0x84, 0 },
+ { 0xd2d5, 0x81, 0 },
+ { 0xd2d6, 0x00, 0 },
+ { 0xd2d7, 0x14, 0 },
+ { 0xd2d8, 0xbd, 0 },
+ { 0xd2d9, 0xa4, 0 },
+ { 0xd2da, 0x01, 0 },
+ { 0xd2db, 0x00, 0 },
+ { 0xd2dc, 0x10, 0 },
+ { 0xd2dd, 0x00, 0 },
+ { 0xd2de, 0x00, 0 },
+ { 0xd2df, 0x05, 0 },
+ { 0xd2e0, 0x84, 0 },
+ { 0xd2e1, 0xc1, 0 },
+ { 0xd2e2, 0x00, 0 },
+ { 0xd2e3, 0x18, 0 },
+ { 0xd2e4, 0x9c, 0 },
+ { 0xd2e5, 0xa0, 0 },
+ { 0xd2e6, 0x01, 0 },
+ { 0xd2e7, 0x00, 0 },
+ { 0xd2e8, 0xd4, 0 },
+ { 0xd2e9, 0x01, 0 },
+ { 0xd2ea, 0x28, 0 },
+ { 0xd2eb, 0x14, 0 },
+ { 0xd2ec, 0x84, 0 },
+ { 0xd2ed, 0xc1, 0 },
+ { 0xd2ee, 0x00, 0 },
+ { 0xd2ef, 0x18, 0 },
+ { 0xd2f0, 0xbd, 0 },
+ { 0xd2f1, 0x66, 0 },
+ { 0xd2f2, 0x00, 0 },
+ { 0xd2f3, 0x00, 0 },
+ { 0xd2f4, 0x0c, 0 },
+ { 0xd2f5, 0x00, 0 },
+ { 0xd2f6, 0x00, 0 },
+ { 0xd2f7, 0x20, 0 },
+ { 0xd2f8, 0x9d, 0 },
+ { 0xd2f9, 0x00, 0 },
+ { 0xd2fa, 0x00, 0 },
+ { 0xd2fb, 0x00, 0 },
+ { 0xd2fc, 0x84, 0 },
+ { 0xd2fd, 0x61, 0 },
+ { 0xd2fe, 0x00, 0 },
+ { 0xd2ff, 0x18, 0 },
+ { 0xd300, 0xbd, 0 },
+ { 0xd301, 0xa3, 0 },
+ { 0xd302, 0x01, 0 },
+ { 0xd303, 0x00, 0 },
+ { 0xd304, 0x10, 0 },
+ { 0xd305, 0x00, 0 },
+ { 0xd306, 0x00, 0 },
+ { 0xd307, 0x03, 0 },
+ { 0xd308, 0x9c, 0 },
+ { 0xd309, 0x80, 0 },
+ { 0xd30a, 0x01, 0 },
+ { 0xd30b, 0x00, 0 },
+ { 0xd30c, 0xd4, 0 },
+ { 0xd30d, 0x01, 0 },
+ { 0xd30e, 0x20, 0 },
+ { 0xd30f, 0x18, 0 },
+ { 0xd310, 0x18, 0 },
+ { 0xd311, 0x60, 0 },
+ { 0xd312, 0x80, 0 },
+ { 0xd313, 0x06, 0 },
+ { 0xd314, 0x85, 0 },
+ { 0xd315, 0x01, 0 },
+ { 0xd316, 0x00, 0 },
+ { 0xd317, 0x14, 0 },
+ { 0xd318, 0xa8, 0 },
+ { 0xd319, 0x83, 0 },
+ { 0xd31a, 0x38, 0 },
+ { 0xd31b, 0x29, 0 },
+ { 0xd31c, 0xa8, 0 },
+ { 0xd31d, 0xc3, 0 },
+ { 0xd31e, 0x40, 0 },
+ { 0xd31f, 0x08, 0 },
+ { 0xd320, 0x8c, 0 },
+ { 0xd321, 0x84, 0 },
+ { 0xd322, 0x00, 0 },
+ { 0xd323, 0x00, 0 },
+ { 0xd324, 0xa8, 0 },
+ { 0xd325, 0xa3, 0 },
+ { 0xd326, 0x38, 0 },
+ { 0xd327, 0x2a, 0 },
+ { 0xd328, 0xa8, 0 },
+ { 0xd329, 0xe3, 0 },
+ { 0xd32a, 0x40, 0 },
+ { 0xd32b, 0x09, 0 },
+ { 0xd32c, 0xe0, 0 },
+ { 0xd32d, 0x64, 0 },
+ { 0xd32e, 0x40, 0 },
+ { 0xd32f, 0x00, 0 },
+ { 0xd330, 0xd8, 0 },
+ { 0xd331, 0x06, 0 },
+ { 0xd332, 0x18, 0 },
+ { 0xd333, 0x00, 0 },
+ { 0xd334, 0x8c, 0 },
+ { 0xd335, 0x65, 0 },
+ { 0xd336, 0x00, 0 },
+ { 0xd337, 0x00, 0 },
+ { 0xd338, 0x84, 0 },
+ { 0xd339, 0x81, 0 },
+ { 0xd33a, 0x00, 0 },
+ { 0xd33b, 0x18, 0 },
+ { 0xd33c, 0xe3, 0 },
+ { 0xd33d, 0xe3, 0 },
+ { 0xd33e, 0x20, 0 },
+ { 0xd33f, 0x00, 0 },
+ { 0xd340, 0xd8, 0 },
+ { 0xd341, 0x07, 0 },
+ { 0xd342, 0xf8, 0 },
+ { 0xd343, 0x00, 0 },
+ { 0xd344, 0x03, 0 },
+ { 0xd345, 0xff, 0 },
+ { 0xd346, 0xff, 0 },
+ { 0xd347, 0x6f, 0 },
+ { 0xd348, 0x18, 0 },
+ { 0xd349, 0x60, 0 },
+ { 0xd34a, 0x00, 0 },
+ { 0xd34b, 0x01, 0 },
+ { 0xd34c, 0xf , 0 },
+ { 0xd34d, 0xff, 0 },
+ { 0xd34e, 0xff, 0 },
+ { 0xd34f, 0x9d, 0 },
+ { 0xd350, 0x18, 0 },
+ { 0xd351, 0x60, 0 },
+ { 0xd352, 0x80, 0 },
+ { 0xd353, 0x06, 0 },
+ { 0xd354, 0x00, 0 },
+ { 0xd355, 0x00, 0 },
+ { 0xd356, 0x00, 0 },
+ { 0xd357, 0x11, 0 },
+ { 0xd358, 0xa8, 0 },
+ { 0xd359, 0x83, 0 },
+ { 0xd35a, 0x6e, 0 },
+ { 0xd35b, 0x43, 0 },
+ { 0xd35c, 0xe0, 0 },
+ { 0xd35d, 0x6c, 0 },
+ { 0xd35e, 0x28, 0 },
+ { 0xd35f, 0x02, 0 },
+ { 0xd360, 0xe0, 0 },
+ { 0xd361, 0x84, 0 },
+ { 0xd362, 0x28, 0 },
+ { 0xd363, 0x02, 0 },
+ { 0xd364, 0x07, 0 },
+ { 0xd365, 0xff, 0 },
+ { 0xd366, 0xf8, 0 },
+ { 0xd367, 0x30, 0 },
+ { 0xd368, 0xb8, 0 },
+ { 0xd369, 0x63, 0 },
+ { 0xd36a, 0x00, 0 },
+ { 0xd36b, 0x08, 0 },
+ { 0xd36c, 0x03, 0 },
+ { 0xd36d, 0xff, 0 },
+ { 0xd36e, 0xff, 0 },
+ { 0xd36f, 0xc0, 0 },
+ { 0xd370, 0x85, 0 },
+ { 0xd371, 0x4e, 0 },
+ { 0xd372, 0x00, 0 },
+ { 0xd373, 0x00, 0 },
+ { 0xd374, 0x03, 0 },
+ { 0xd375, 0xff, 0 },
+ { 0xd376, 0xff, 0 },
+ { 0xd377, 0xe7, 0 },
+ { 0xd378, 0xd4, 0 },
+ { 0xd379, 0x01, 0 },
+ { 0xd37a, 0x40, 0 },
+ { 0xd37b, 0x18, 0 },
+ { 0xd37c, 0x9c, 0 },
+ { 0xd37d, 0x60, 0 },
+ { 0xd37e, 0x00, 0 },
+ { 0xd37f, 0x00, 0 },
+ { 0xd380, 0x03, 0 },
+ { 0xd381, 0xff, 0 },
+ { 0xd382, 0xff, 0 },
+ { 0xd383, 0xdb, 0 },
+ { 0xd384, 0xd4, 0 },
+ { 0xd385, 0x01, 0 },
+ { 0xd386, 0x18, 0 },
+ { 0xd387, 0x14, 0 },
+ { 0xd388, 0x03, 0 },
+ { 0xd389, 0xff, 0 },
+ { 0xd38a, 0xff, 0 },
+ { 0xd38b, 0xce, 0 },
+ { 0xd38c, 0x9d, 0 },
+ { 0xd38d, 0x6b, 0 },
+ { 0xd38e, 0x00, 0 },
+ { 0xd38f, 0xff, 0 },
+ { 0xd390, 0x03, 0 },
+ { 0xd391, 0xff, 0 },
+ { 0xd392, 0xff, 0 },
+ { 0xd393, 0xc6, 0 },
+ { 0xd394, 0x9c, 0 },
+ { 0xd395, 0x63, 0 },
+ { 0xd396, 0x00, 0 },
+ { 0xd397, 0xff, 0 },
+ { 0xd398, 0xa8, 0 },
+ { 0xd399, 0xe3, 0 },
+ { 0xd39a, 0x38, 0 },
+ { 0xd39b, 0xf , 0 },
+ { 0xd39c, 0x8c, 0 },
+ { 0xd39d, 0x84, 0 },
+ { 0xd39e, 0x00, 0 },
+ { 0xd39f, 0x00, 0 },
+ { 0xd3a0, 0xa8, 0 },
+ { 0xd3a1, 0xa3, 0 },
+ { 0xd3a2, 0x38, 0 },
+ { 0xd3a3, 0x0e, 0 },
+ { 0xd3a4, 0xa8, 0 },
+ { 0xd3a5, 0xc3, 0 },
+ { 0xd3a6, 0x6e, 0 },
+ { 0xd3a7, 0x42, 0 },
+ { 0xd3a8, 0xd8, 0 },
+ { 0xd3a9, 0x07, 0 },
+ { 0xd3aa, 0x20, 0 },
+ { 0xd3ab, 0x00, 0 },
+ { 0xd3ac, 0x8c, 0 },
+ { 0xd3ad, 0x66, 0 },
+ { 0xd3ae, 0x00, 0 },
+ { 0xd3af, 0x00, 0 },
+ { 0xd3b0, 0xd8, 0 },
+ { 0xd3b1, 0x05, 0 },
+ { 0xd3b2, 0x18, 0 },
+ { 0xd3b3, 0x00, 0 },
+ { 0xd3b4, 0x85, 0 },
+ { 0xd3b5, 0x21, 0 },
+ { 0xd3b6, 0x00, 0 },
+ { 0xd3b7, 0x00, 0 },
+ { 0xd3b8, 0x85, 0 },
+ { 0xd3b9, 0x41, 0 },
+ { 0xd3ba, 0x00, 0 },
+ { 0xd3bb, 0x04, 0 },
+ { 0xd3bc, 0x85, 0 },
+ { 0xd3bd, 0x81, 0 },
+ { 0xd3be, 0x00, 0 },
+ { 0xd3bf, 0x08, 0 },
+ { 0xd3c0, 0x85, 0 },
+ { 0xd3c1, 0xc1, 0 },
+ { 0xd3c2, 0x00, 0 },
+ { 0xd3c3, 0x0c, 0 },
+ { 0xd3c4, 0x86, 0 },
+ { 0xd3c5, 0x01, 0 },
+ { 0xd3c6, 0x00, 0 },
+ { 0xd3c7, 0x10, 0 },
+ { 0xd3c8, 0x44, 0 },
+ { 0xd3c9, 0x00, 0 },
+ { 0xd3ca, 0x48, 0 },
+ { 0xd3cb, 0x00, 0 },
+ { 0xd3cc, 0x9c, 0 },
+ { 0xd3cd, 0x21, 0 },
+ { 0xd3ce, 0x00, 0 },
+ { 0xd3cf, 0x1c, 0 },
+ { 0xd3d0, 0x9c, 0 },
+ { 0xd3d1, 0x21, 0 },
+ { 0xd3d2, 0xff, 0 },
+ { 0xd3d3, 0xfc, 0 },
+ { 0xd3d4, 0xd4, 0 },
+ { 0xd3d5, 0x01, 0 },
+ { 0xd3d6, 0x48, 0 },
+ { 0xd3d7, 0x00, 0 },
+ { 0xd3d8, 0x18, 0 },
+ { 0xd3d9, 0x60, 0 },
+ { 0xd3da, 0x00, 0 },
+ { 0xd3db, 0x01, 0 },
+ { 0xd3dc, 0xa8, 0 },
+ { 0xd3dd, 0x63, 0 },
+ { 0xd3de, 0x07, 0 },
+ { 0xd3df, 0x80, 0 },
+ { 0xd3e0, 0x8c, 0 },
+ { 0xd3e1, 0x63, 0 },
+ { 0xd3e2, 0x00, 0 },
+ { 0xd3e3, 0x68, 0 },
+ { 0xd3e4, 0xbc, 0 },
+ { 0xd3e5, 0x03, 0 },
+ { 0xd3e6, 0x00, 0 },
+ { 0xd3e7, 0x00, 0 },
+ { 0xd3e8, 0x10, 0 },
+ { 0xd3e9, 0x00, 0 },
+ { 0xd3ea, 0x00, 0 },
+ { 0xd3eb, 0x0c, 0 },
+ { 0xd3ec, 0x15, 0 },
+ { 0xd3ed, 0x00, 0 },
+ { 0xd3ee, 0x00, 0 },
+ { 0xd3ef, 0x00, 0 },
+ { 0xd3f0, 0x07, 0 },
+ { 0xd3f1, 0xff, 0 },
+ { 0xd3f2, 0xd9, 0 },
+ { 0xd3f3, 0x98, 0 },
+ { 0xd3f4, 0x15, 0 },
+ { 0xd3f5, 0x00, 0 },
+ { 0xd3f6, 0x00, 0 },
+ { 0xd3f7, 0x00, 0 },
+ { 0xd3f8, 0x18, 0 },
+ { 0xd3f9, 0x60, 0 },
+ { 0xd3fa, 0x80, 0 },
+ { 0xd3fb, 0x06, 0 },
+ { 0xd3fc, 0xa8, 0 },
+ { 0xd3fd, 0x63, 0 },
+ { 0xd3fe, 0xc4, 0 },
+ { 0xd3ff, 0xb8, 0 },
+ { 0xd400, 0x8c, 0 },
+ { 0xd401, 0x63, 0 },
+ { 0xd402, 0x00, 0 },
+ { 0xd403, 0x00, 0 },
+ { 0xd404, 0xbc, 0 },
+ { 0xd405, 0x23, 0 },
+ { 0xd406, 0x00, 0 },
+ { 0xd407, 0x01, 0 },
+ { 0xd408, 0x10, 0 },
+ { 0xd409, 0x00, 0 },
+ { 0xd40a, 0x00, 0 },
+ { 0xd40b, 0x25, 0 },
+ { 0xd40c, 0x9d, 0 },
+ { 0xd40d, 0x00, 0 },
+ { 0xd40e, 0x00, 0 },
+ { 0xd40f, 0x00, 0 },
+ { 0xd410, 0x00, 0 },
+ { 0xd411, 0x00, 0 },
+ { 0xd412, 0x00, 0 },
+ { 0xd413, 0x0b, 0 },
+ { 0xd414, 0xb8, 0 },
+ { 0xd415, 0xe8, 0 },
+ { 0xd416, 0x00, 0 },
+ { 0xd417, 0x02, 0 },
+ { 0xd418, 0x07, 0 },
+ { 0xd419, 0xff, 0 },
+ { 0xd41a, 0xd6, 0 },
+ { 0xd41b, 0x24, 0 },
+ { 0xd41c, 0x15, 0 },
+ { 0xd41d, 0x00, 0 },
+ { 0xd41e, 0x00, 0 },
+ { 0xd41f, 0x00, 0 },
+ { 0xd420, 0x18, 0 },
+ { 0xd421, 0x60, 0 },
+ { 0xd422, 0x80, 0 },
+ { 0xd423, 0x06, 0 },
+ { 0xd424, 0xa8, 0 },
+ { 0xd425, 0x63, 0 },
+ { 0xd426, 0xc4, 0 },
+ { 0xd427, 0xb8, 0 },
+ { 0xd428, 0x8c, 0 },
+ { 0xd429, 0x63, 0 },
+ { 0xd42a, 0x00, 0 },
+ { 0xd42b, 0x00, 0 },
+ { 0xd42c, 0xbc, 0 },
+ { 0xd42d, 0x23, 0 },
+ { 0xd42e, 0x00, 0 },
+ { 0xd42f, 0x01, 0 },
+ { 0xd430, 0x10, 0 },
+ { 0xd431, 0x00, 0 },
+ { 0xd432, 0x00, 0 },
+ { 0xd433, 0x1b, 0 },
+ { 0xd434, 0x9d, 0 },
+ { 0xd435, 0x00, 0 },
+ { 0xd436, 0x00, 0 },
+ { 0xd437, 0x00, 0 },
+ { 0xd438, 0xb8, 0 },
+ { 0xd439, 0xe8, 0 },
+ { 0xd43a, 0x00, 0 },
+ { 0xd43b, 0x02, 0 },
+ { 0xd43c, 0x9c, 0 },
+ { 0xd43d, 0xc0, 0 },
+ { 0xd43e, 0x00, 0 },
+ { 0xd43f, 0x00, 0 },
+ { 0xd440, 0x18, 0 },
+ { 0xd441, 0xa0, 0 },
+ { 0xd442, 0x80, 0 },
+ { 0xd443, 0x06, 0 },
+ { 0xd444, 0xe0, 0 },
+ { 0xd445, 0x67, 0 },
+ { 0xd446, 0x30, 0 },
+ { 0xd447, 0x00, 0 },
+ { 0xd448, 0xa8, 0 },
+ { 0xd449, 0xa5, 0 },
+ { 0xd44a, 0xce, 0 },
+ { 0xd44b, 0xb0, 0 },
+ { 0xd44c, 0x19, 0 },
+ { 0xd44d, 0x60, 0 },
+ { 0xd44e, 0x00, 0 },
+ { 0xd44f, 0x01, 0 },
+ { 0xd450, 0xa9, 0 },
+ { 0xd451, 0x6b, 0 },
+ { 0xd452, 0x06, 0 },
+ { 0xd453, 0x14, 0 },
+ { 0xd454, 0xe0, 0 },
+ { 0xd455, 0x83, 0 },
+ { 0xd456, 0x28, 0 },
+ { 0xd457, 0x00, 0 },
+ { 0xd458, 0x9c, 0 },
+ { 0xd459, 0xc6, 0 },
+ { 0xd45a, 0x00, 0 },
+ { 0xd45b, 0x01, 0 },
+ { 0xd45c, 0xe0, 0 },
+ { 0xd45d, 0x63, 0 },
+ { 0xd45e, 0x18, 0 },
+ { 0xd45f, 0x00, 0 },
+ { 0xd460, 0x8c, 0 },
+ { 0xd461, 0x84, 0 },
+ { 0xd462, 0x00, 0 },
+ { 0xd463, 0x00, 0 },
+ { 0xd464, 0xe0, 0 },
+ { 0xd465, 0xa3, 0 },
+ { 0xd466, 0x58, 0 },
+ { 0xd467, 0x00, 0 },
+ { 0xd468, 0xa4, 0 },
+ { 0xd469, 0xc6, 0 },
+ { 0xd46a, 0x00, 0 },
+ { 0xd46b, 0xff, 0 },
+ { 0xd46c, 0xb8, 0 },
+ { 0xd46d, 0x64, 0 },
+ { 0xd46e, 0x00, 0 },
+ { 0xd46f, 0x18, 0 },
+ { 0xd470, 0xbc, 0 },
+ { 0xd471, 0x46, 0 },
+ { 0xd472, 0x00, 0 },
+ { 0xd473, 0x03, 0 },
+ { 0xd474, 0x94, 0 },
+ { 0xd475, 0x85, 0 },
+ { 0xd476, 0x00, 0 },
+ { 0xd477, 0x00, 0 },
+ { 0xd478, 0xb8, 0 },
+ { 0xd479, 0x63, 0 },
+ { 0xd47a, 0x00, 0 },
+ { 0xd47b, 0x98, 0 },
+ { 0xd47c, 0xe0, 0 },
+ { 0xd47d, 0x64, 0 },
+ { 0xd47e, 0x18, 0 },
+ { 0xd47f, 0x00, 0 },
+ { 0xd480, 0xf , 0 },
+ { 0xd481, 0xff, 0 },
+ { 0xd482, 0xff, 0 },
+ { 0xd483, 0xf0, 0 },
+ { 0xd484, 0xdc, 0 },
+ { 0xd485, 0x05, 0 },
+ { 0xd486, 0x18, 0 },
+ { 0xd487, 0x00, 0 },
+ { 0xd488, 0x9c, 0 },
+ { 0xd489, 0x68, 0 },
+ { 0xd48a, 0x00, 0 },
+ { 0xd48b, 0x01, 0 },
+ { 0xd48c, 0xa5, 0 },
+ { 0xd48d, 0x03, 0 },
+ { 0xd48e, 0x00, 0 },
+ { 0xd48f, 0xff, 0 },
+ { 0xd490, 0xbc, 0 },
+ { 0xd491, 0x48, 0 },
+ { 0xd492, 0x00, 0 },
+ { 0xd493, 0x01, 0 },
+ { 0xd494, 0xf , 0 },
+ { 0xd495, 0xff, 0 },
+ { 0xd496, 0xff, 0 },
+ { 0xd497, 0xea, 0 },
+ { 0xd498, 0xb8, 0 },
+ { 0xd499, 0xe8, 0 },
+ { 0xd49a, 0x00, 0 },
+ { 0xd49b, 0x02, 0 },
+ { 0xd49c, 0x18, 0 },
+ { 0xd49d, 0x60, 0 },
+ { 0xd49e, 0x00, 0 },
+ { 0xd49f, 0x01, 0 },
+ { 0xd4a0, 0xa8, 0 },
+ { 0xd4a1, 0x63, 0 },
+ { 0xd4a2, 0x06, 0 },
+ { 0xd4a3, 0x14, 0 },
+ { 0xd4a4, 0x07, 0 },
+ { 0xd4a5, 0xff, 0 },
+ { 0xd4a6, 0xe4, 0 },
+ { 0xd4a7, 0x05, 0 },
+ { 0xd4a8, 0x9c, 0 },
+ { 0xd4a9, 0x83, 0 },
+ { 0xd4aa, 0x00, 0 },
+ { 0xd4ab, 0x10, 0 },
+ { 0xd4ac, 0x85, 0 },
+ { 0xd4ad, 0x21, 0 },
+ { 0xd4ae, 0x00, 0 },
+ { 0xd4af, 0x00, 0 },
+ { 0xd4b0, 0x44, 0 },
+ { 0xd4b1, 0x00, 0 },
+ { 0xd4b2, 0x48, 0 },
+ { 0xd4b3, 0x00, 0 },
+ { 0xd4b4, 0x9c, 0 },
+ { 0xd4b5, 0x21, 0 },
+ { 0xd4b6, 0x00, 0 },
+ { 0xd4b7, 0x04, 0 },
+ { 0xd4b8, 0x18, 0 },
+ { 0xd4b9, 0x60, 0 },
+ { 0xd4ba, 0x00, 0 },
+ { 0xd4bb, 0x01, 0 },
+ { 0xd4bc, 0x9c, 0 },
+ { 0xd4bd, 0x80, 0 },
+ { 0xd4be, 0xff, 0 },
+ { 0xd4bf, 0xff, 0 },
+ { 0xd4c0, 0xa8, 0 },
+ { 0xd4c1, 0x63, 0 },
+ { 0xd4c2, 0x09, 0 },
+ { 0xd4c3, 0xef, 0 },
+ { 0xd4c4, 0xd8, 0 },
+ { 0xd4c5, 0x03, 0 },
+ { 0xd4c6, 0x20, 0 },
+ { 0xd4c7, 0x00, 0 },
+ { 0xd4c8, 0x18, 0 },
+ { 0xd4c9, 0x60, 0 },
+ { 0xd4ca, 0x80, 0 },
+ { 0xd4cb, 0x06, 0 },
+ { 0xd4cc, 0xa8, 0 },
+ { 0xd4cd, 0x63, 0 },
+ { 0xd4ce, 0xc9, 0 },
+ { 0xd4cf, 0xef, 0 },
+ { 0xd4d0, 0xd8, 0 },
+ { 0xd4d1, 0x03, 0 },
+ { 0xd4d2, 0x20, 0 },
+ { 0xd4d3, 0x00, 0 },
+ { 0xd4d4, 0x44, 0 },
+ { 0xd4d5, 0x00, 0 },
+ { 0xd4d6, 0x48, 0 },
+ { 0xd4d7, 0x00, 0 },
+ { 0xd4d8, 0x15, 0 },
+ { 0xd4d9, 0x00, 0 },
+ { 0xd4da, 0x00, 0 },
+ { 0xd4db, 0x00, 0 },
+ { 0xd4dc, 0x18, 0 },
+ { 0xd4dd, 0x80, 0 },
+ { 0xd4de, 0x00, 0 },
+ { 0xd4df, 0x01, 0 },
+ { 0xd4e0, 0xa8, 0 },
+ { 0xd4e1, 0x84, 0 },
+ { 0xd4e2, 0x0a, 0 },
+ { 0xd4e3, 0x12, 0 },
+ { 0xd4e4, 0x8c, 0 },
+ { 0xd4e5, 0x64, 0 },
+ { 0xd4e6, 0x00, 0 },
+ { 0xd4e7, 0x00, 0 },
+ { 0xd4e8, 0xbc, 0 },
+ { 0xd4e9, 0x03, 0 },
+ { 0xd4ea, 0x00, 0 },
+ { 0xd4eb, 0x00, 0 },
+ { 0xd4ec, 0x13, 0 },
+ { 0xd4ed, 0xff, 0 },
+ { 0xd4ee, 0xff, 0 },
+ { 0xd4ef, 0xfe, 0 },
+ { 0xd4f0, 0x15, 0 },
+ { 0xd4f1, 0x00, 0 },
+ { 0xd4f2, 0x00, 0 },
+ { 0xd4f3, 0x00, 0 },
+ { 0xd4f4, 0x44, 0 },
+ { 0xd4f5, 0x00, 0 },
+ { 0xd4f6, 0x48, 0 },
+ { 0xd4f7, 0x00, 0 },
+ { 0xd4f8, 0x15, 0 },
+ { 0xd4f9, 0x00, 0 },
+ { 0xd4fa, 0x00, 0 },
+ { 0xd4fb, 0x00, 0 },
+ { 0xd4fc, 0x00, 0 },
+ { 0xd4fd, 0x00, 0 },
+ { 0xd4fe, 0x00, 0 },
+ { 0xd4ff, 0x00, 0 },
+ { 0xd500, 0x00, 0 },
+ { 0xd501, 0x00, 0 },
+ { 0xd502, 0x00, 0 },
+ { 0xd503, 0x00, 0 },
+ { 0x6f0e, 0x33, 0 },
+ { 0x6f0f, 0x33, 0 },
+ { 0x460e, 0x08, 0 },
+ { 0x460f, 0x01, 0 },
+ { 0x4610, 0x00, 0 },
+ { 0x4611, 0x01, 0 },
+ { 0x4612, 0x00, 0 },
+ { 0x4613, 0x01, 0 },
+ { 0x4605, 0x08, 0 },
+ { 0x4608, 0x00, 0 },
+ { 0x4609, 0x08, 0 },
+ { 0x6804, 0x00, 0 },
+ { 0x6805, 0x06, 0 },
+ { 0x6806, 0x00, 0 },
+ { 0x5120, 0x00, 0 },
+ { 0x3510, 0x00, 0 },
+ { 0x3504, 0x00, 0 },
+ { 0x6800, 0x00, 0 },
+ { 0x6f0d, 0xf , 0 },
+ { 0x5000, 0xff, 0 },
+ { 0x5001, 0xbf, 0 },
+ { 0x5002, 0x7e, 0 },
+ { 0x5003, 0x0c, 0 },
+ { 0x503d, 0x00, 0 },
+ { 0xc450, 0x01, 0 },
+ { 0xc452, 0x04, 0 },
+ { 0xc453, 0x00, 0 },
+ { 0xc454, 0x00, 0 },
+ { 0xc455, 0x00, 0 },
+ { 0xc456, 0x00, 0 },
+ { 0xc457, 0x00, 0 },
+ { 0xc458, 0x00, 0 },
+ { 0xc459, 0x00, 0 },
+ { 0xc45b, 0x00, 0 },
+ { 0xc45c, 0x00, 0 },
+ { 0xc45d, 0x00, 0 },
+ { 0xc45e, 0x00, 0 },
+ { 0xc45f, 0x00, 0 },
+ { 0xc460, 0x00, 0 },
+ { 0xc461, 0x01, 0 },
+ { 0xc462, 0x01, 0 },
+ { 0xc464, 0x88, 0 },
+ { 0xc465, 0x00, 0 },
+ { 0xc466, 0x8a, 0 },
+ { 0xc467, 0x00, 0 },
+ { 0xc468, 0x86, 0 },
+ { 0xc469, 0x00, 0 },
+ { 0xc46a, 0x40, 0 },
+ { 0xc46b, 0x50, 0 },
+ { 0xc46c, 0x30, 0 },
+ { 0xc46d, 0x28, 0 },
+ { 0xc46e, 0x60, 0 },
+ { 0xc46f, 0x40, 0 },
+ { 0xc47c, 0x01, 0 },
+ { 0xc47d, 0x38, 0 },
+ { 0xc47e, 0x00, 0 },
+ { 0xc47f, 0x00, 0 },
+ { 0xc480, 0x00, 0 },
+ { 0xc481, 0xff, 0 },
+ { 0xc482, 0x00, 0 },
+ { 0xc483, 0x40, 0 },
+ { 0xc484, 0x00, 0 },
+ { 0xc485, 0x18, 0 },
+ { 0xc486, 0x00, 0 },
+ { 0xc487, 0x18, 0 },
+ { 0xc488, 0x34, 0 },
+ { 0xc489, 0x00, 0 },
+ { 0xc48a, 0x34, 0 },
+ { 0xc48b, 0x00, 0 },
+ { 0xc48c, 0x00, 0 },
+ { 0xc48d, 0x04, 0 },
+ { 0xc48e, 0x00, 0 },
+ { 0xc48f, 0x04, 0 },
+ { 0xc490, 0x07, 0 },
+ { 0xc492, 0x20, 0 },
+ { 0xc493, 0x08, 0 },
+ { 0xc498, 0x02, 0 },
+ { 0xc499, 0x00, 0 },
+ { 0xc49a, 0x02, 0 },
+ { 0xc49b, 0x00, 0 },
+ { 0xc49c, 0x02, 0 },
+ { 0xc49d, 0x00, 0 },
+ { 0xc49e, 0x02, 0 },
+ { 0xc49f, 0x60, 0 },
+ { 0xc4a0, 0x03, 0 },
+ { 0xc4a1, 0x00, 0 },
+ { 0xc4a2, 0x04, 0 },
+ { 0xc4a3, 0x00, 0 },
+ { 0xc4a4, 0x00, 0 },
+ { 0xc4a5, 0x10, 0 },
+ { 0xc4a6, 0x00, 0 },
+ { 0xc4a7, 0x40, 0 },
+ { 0xc4a8, 0x00, 0 },
+ { 0xc4a9, 0x80, 0 },
+ { 0xc4aa, 0x0d, 0 },
+ { 0xc4ab, 0x00, 0 },
+ { 0xc4ac, 0xf , 0 },
+ { 0xc4ad, 0xc0, 0 },
+ { 0xc4b4, 0x01, 0 },
+ { 0xc4b5, 0x01, 0 },
+ { 0xc4b6, 0x00, 0 },
+ { 0xc4b7, 0x01, 0 },
+ { 0xc4b8, 0x00, 0 },
+ { 0xc4b9, 0x01, 0 },
+ { 0xc4ba, 0x01, 0 },
+ { 0xc4bb, 0x00, 0 },
+ { 0xc4bc, 0x01, 0 },
+ { 0xc4bd, 0x60, 0 },
+ { 0xc4be, 0x02, 0 },
+ { 0xc4bf, 0x33, 0 },
+ { 0xc4c8, 0x03, 0 },
+ { 0xc4c9, 0xd0, 0 },
+ { 0xc4ca, 0x0e, 0 },
+ { 0xc4cb, 0x00, 0 },
+ { 0xc4cc, 0x10, 0 },
+ { 0xc4cd, 0x18, 0 },
+ { 0xc4ce, 0x10, 0 },
+ { 0xc4cf, 0x18, 0 },
+ { 0xc4d0, 0x04, 0 },
+ { 0xc4d1, 0x80, 0 },
+ { 0xc4e0, 0x04, 0 },
+ { 0xc4e1, 0x02, 0 },
+ { 0xc4e2, 0x01, 0 },
+ { 0xc4e4, 0x10, 0 },
+ { 0xc4e5, 0x20, 0 },
+ { 0xc4e6, 0x30, 0 },
+ { 0xc4e7, 0x40, 0 },
+ { 0xc4e8, 0x50, 0 },
+ { 0xc4e9, 0x60, 0 },
+ { 0xc4ea, 0x70, 0 },
+ { 0xc4eb, 0x80, 0 },
+ { 0xc4ec, 0x90, 0 },
+ { 0xc4ed, 0xa0, 0 },
+ { 0xc4ee, 0xb0, 0 },
+ { 0xc4ef, 0xc0, 0 },
+ { 0xc4f0, 0xd0, 0 },
+ { 0xc4f1, 0xe0, 0 },
+ { 0xc4f2, 0xf0, 0 },
+ { 0xc4f3, 0x80, 0 },
+ { 0xc4f4, 0x00, 0 },
+ { 0xc4f5, 0x20, 0 },
+ { 0xc4f6, 0x02, 0 },
+ { 0xc4f7, 0x00, 0 },
+ { 0xc4f8, 0x04, 0 },
+ { 0xc4f9, 0x0b, 0 },
+ { 0xc4fa, 0x00, 0 },
+ { 0xc4fb, 0x00, 0 },
+ { 0xc4fc, 0x01, 0 },
+ { 0xc4fd, 0x00, 0 },
+ { 0xc4fe, 0x04, 0 },
+ { 0xc4ff, 0x02, 0 },
+ { 0xc500, 0x48, 0 },
+ { 0xc501, 0x74, 0 },
+ { 0xc502, 0x58, 0 },
+ { 0xc503, 0x80, 0 },
+ { 0xc504, 0x05, 0 },
+ { 0xc505, 0x80, 0 },
+ { 0xc506, 0x03, 0 },
+ { 0xc507, 0x80, 0 },
+ { 0xc508, 0x01, 0 },
+ { 0xc509, 0xc0, 0 },
+ { 0xc50a, 0x01, 0 },
+ { 0xc50b, 0xa0, 0 },
+ { 0xc50c, 0x01, 0 },
+ { 0xc50d, 0x2c, 0 },
+ { 0xc50e, 0x01, 0 },
+ { 0xc50f, 0x0a, 0 },
+ { 0xc510, 0x00, 0 },
+ { 0xc511, 0x01, 0 },
+ { 0xc512, 0x01, 0 },
+ { 0xc513, 0x80, 0 },
+ { 0xc514, 0x04, 0 },
+ { 0xc515, 0x00, 0 },
+ { 0xc518, 0x03, 0 },
+ { 0xc519, 0x48, 0 },
+ { 0xc51a, 0x07, 0 },
+ { 0xc51b, 0x70, 0 },
+ { 0xc2e0, 0x00, 0 },
+ { 0xc2e1, 0x51, 0 },
+ { 0xc2e2, 0x00, 0 },
+ { 0xc2e3, 0xd6, 0 },
+ { 0xc2e4, 0x01, 0 },
+ { 0xc2e5, 0x5e, 0 },
+ { 0xc2e9, 0x01, 0 },
+ { 0xc2ea, 0x7a, 0 },
+ { 0xc2eb, 0x90, 0 },
+ { 0xc2ed, 0x00, 0 },
+ { 0xc2ee, 0x7a, 0 },
+ { 0xc2ef, 0x64, 0 },
+ { 0xc308, 0x00, 0 },
+ { 0xc309, 0x00, 0 },
+ { 0xc30a, 0x00, 0 },
+ { 0xc30c, 0x00, 0 },
+ { 0xc30d, 0x01, 0 },
+ { 0xc30e, 0x00, 0 },
+ { 0xc30f, 0x00, 0 },
+ { 0xc310, 0x01, 0 },
+ { 0xc311, 0x60, 0 },
+ { 0xc312, 0xff, 0 },
+ { 0xc313, 0x08, 0 },
+ { 0xc314, 0x01, 0 },
+ { 0xc315, 0x7f, 0 },
+ { 0xc316, 0xff, 0 },
+ { 0xc317, 0x0b, 0 },
+ { 0xc318, 0x00, 0 },
+ { 0xc319, 0x0c, 0 },
+ { 0xc31a, 0x00, 0 },
+ { 0xc31b, 0xe0, 0 },
+ { 0xc31c, 0x00, 0 },
+ { 0xc31d, 0x14, 0 },
+ { 0xc31e, 0x00, 0 },
+ { 0xc31f, 0xc5, 0 },
+ { 0xc320, 0xff, 0 },
+ { 0xc321, 0x4b, 0 },
+ { 0xc322, 0xff, 0 },
+ { 0xc323, 0xf0, 0 },
+ { 0xc324, 0xff, 0 },
+ { 0xc325, 0xe8, 0 },
+ { 0xc326, 0x00, 0 },
+ { 0xc327, 0x46, 0 },
+ { 0xc328, 0xff, 0 },
+ { 0xc329, 0xd2, 0 },
+ { 0xc32a, 0xff, 0 },
+ { 0xc32b, 0xe4, 0 },
+ { 0xc32c, 0xff, 0 },
+ { 0xc32d, 0xbb, 0 },
+ { 0xc32e, 0x00, 0 },
+ { 0xc32f, 0x61, 0 },
+ { 0xc330, 0xff, 0 },
+ { 0xc331, 0xf9, 0 },
+ { 0xc332, 0x00, 0 },
+ { 0xc333, 0xd9, 0 },
+ { 0xc334, 0x00, 0 },
+ { 0xc335, 0x2e, 0 },
+ { 0xc336, 0x00, 0 },
+ { 0xc337, 0xb1, 0 },
+ { 0xc338, 0xff, 0 },
+ { 0xc339, 0x64, 0 },
+ { 0xc33a, 0xff, 0 },
+ { 0xc33b, 0xeb, 0 },
+ { 0xc33c, 0xff, 0 },
+ { 0xc33d, 0xe8, 0 },
+ { 0xc33e, 0x00, 0 },
+ { 0xc33f, 0x48, 0 },
+ { 0xc340, 0xff, 0 },
+ { 0xc341, 0xd0, 0 },
+ { 0xc342, 0xff, 0 },
+ { 0xc343, 0xed, 0 },
+ { 0xc344, 0xff, 0 },
+ { 0xc345, 0xad, 0 },
+ { 0xc346, 0x00, 0 },
+ { 0xc347, 0x66, 0 },
+ { 0xc348, 0x01, 0 },
+ { 0xc349, 0x00, 0 },
+ { 0x6700, 0x04, 0 },
+ { 0x6701, 0x7b, 0 },
+ { 0x6702, 0xfd, 0 },
+ { 0x6703, 0xf9, 0 },
+ { 0x6704, 0x3d, 0 },
+ { 0x6705, 0x71, 0 },
+ { 0x6706, 0x78, 0 },
+ { 0x6708, 0x05, 0 },
+ { 0x6f06, 0x6f, 0 },
+ { 0x6f07, 0x00, 0 },
+ { 0x6f0a, 0x6f, 0 },
+ { 0x6f0b, 0x00, 0 },
+ { 0x6f00, 0x03, 0 },
+ { 0xc34c, 0x01, 0 },
+ { 0xc34d, 0x00, 0 },
+ { 0xc34e, 0x46, 0 },
+ { 0xc34f, 0x55, 0 },
+ { 0xc350, 0x00, 0 },
+ { 0xc351, 0x40, 0 },
+ { 0xc352, 0x00, 0 },
+ { 0xc353, 0xff, 0 },
+ { 0xc354, 0x04, 0 },
+ { 0xc355, 0x08, 0 },
+ { 0xc356, 0x01, 0 },
+ { 0xc357, 0xef, 0 },
+ { 0xc358, 0x30, 0 },
+ { 0xc359, 0x01, 0 },
+ { 0xc35a, 0x64, 0 },
+ { 0xc35b, 0x46, 0 },
+ { 0xc35c, 0x00, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x3042, 0xf0, 0 },
+ { 0x301b, 0xf0, 0 },
+ { 0x301c, 0xf0, 0 },
+ { 0x301a, 0xf0, 0 },
+ { 0xceb0, 0x00, 0 },
+ { 0xceb1, 0x00, 0 },
+ { 0xceb2, 0x00, 0 },
+ { 0xceb3, 0x00, 0 },
+ { 0xceb4, 0x00, 0 },
+ { 0xceb5, 0x00, 0 },
+ { 0xceb6, 0x00, 0 },
+ { 0xceb7, 0x00, 0 },
+ { 0xc4bc, 0x01, 0 },
+ { 0xc4bd, 0x60, 0 },
+
+ { 0x4709, 0x10, 0 },/* dvp swap */
+ { 0x4300, 0x3a, 0 },/* YUV order UYVY */
+ { 0x3832, 0x01, 0 },/* fsin */
+ { 0x3833, 0x1A, 0 },
+ { 0x3834, 0x03, 0 },
+ { 0x3835, 0x48, 0 },
+ { 0x302E, 0x01, 0 },
+};
+
+static inline struct sensor_data *subdev_to_sensor_data(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct sensor_data, subdev);
+}
+
+static inline int ov10635_read_reg(struct sensor_data *max9286_data, int index,
+ unsigned short reg, unsigned char *val)
+{
+ unsigned char u8_buf[2] = { 0 };
+ unsigned int buf_len = 2;
+ int retry, timeout = 10;
+ unsigned char u8_val = 0;
+
+ u8_buf[0] = (reg >> 8) & 0xFF;
+ u8_buf[1] = reg & 0xFF;
+
+ max9286_data->i2c_client->addr = ADDR_OV_SENSOR + index;
+
+ for (retry = 0; retry < timeout; retry++) {
+ if (i2c_master_send(max9286_data->i2c_client, u8_buf, buf_len) < 0) {
+ dev_dbg(&max9286_data->i2c_client->dev,
+ "%s:read reg error on send: reg=0x%x, retry = %d.\n", __func__, reg, retry);
+ msleep(5);
+ continue;
+ }
+ if (i2c_master_recv(max9286_data->i2c_client, &u8_val, 1) != 1) {
+ dev_dbg(&max9286_data->i2c_client->dev,
+ "%s:read reg error on recv: reg=0x%x, retry = %d.\n", __func__, reg, retry);
+ msleep(5);
+ continue;
+ }
+ break;
+ }
+
+ if (retry >= timeout) {
+ dev_info(&max9286_data->i2c_client->dev,
+ "%s:read reg error: reg=0x%x.\n", __func__, reg);
+ return -1;
+ }
+
+ *val = u8_val;
+
+ return u8_val;
+}
+
+static inline int ov10635_write_reg(struct sensor_data *max9286_data, int index,
+ unsigned short reg, unsigned char val)
+{
+ unsigned char u8_buf[3] = { 0 };
+ unsigned int buf_len = 3;
+ int retry, timeout = 10;
+
+ u8_buf[0] = (reg >> 8) & 0xFF;
+ u8_buf[1] = reg & 0xFF;
+ u8_buf[2] = val;
+
+ max9286_data->i2c_client->addr = ADDR_OV_SENSOR + index;
+ for (retry = 0; retry < timeout; retry++) {
+ if (i2c_master_send(max9286_data->i2c_client, u8_buf, buf_len) < 0) {
+ dev_dbg(&max9286_data->i2c_client->dev,
+ "%s:write reg error: reg=0x%x, val=0x%x, retry = %d.\n", __func__, reg, val, retry);
+ msleep(5);
+ continue;
+ }
+ break;
+ }
+
+ if (retry >= timeout) {
+ dev_info(&max9286_data->i2c_client->dev,
+ "%s:write reg error: reg=0x%x, val=0x%x.\n", __func__, reg, val);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ov10635_check_device(struct sensor_data *max9286_data, int index)
+{
+ unsigned char reg = 0;
+
+ ov10635_read_reg(max9286_data, index, OV10635_REG_PID, &reg);
+ if (reg != 0xA6) {
+ dev_err(&max9286_data->i2c_client->dev,
+ "%s: OV10635 hasn't been found, reg[0x%x] = 0x%x., index=%d\n",
+ __func__, OV10635_REG_PID, reg, index);
+ return -1;
+ }
+ ov10635_read_reg(max9286_data, index, OV10635_REG_VER, &reg);
+ if (reg != 0x35) {
+ dev_err(&max9286_data->i2c_client->dev,
+ "%s: OV10635 hasn't been found, reg[0x%x] = 0x%x.\n", __func__, OV10635_REG_VER, reg);
+ return -1;
+ }
+ dev_info(&max9286_data->i2c_client->dev, "%s: OV10635 index=%d was found.\n", __func__, index);
+
+ return 0;
+}
+
+static int ov10635_initialize(struct sensor_data *max9286_data, int index)
+{
+ int i, array_size;
+ int retval;
+
+ dev_info(&max9286_data->i2c_client->dev, "%s: index = %d.\n", __func__, index);
+ array_size = ARRAY_SIZE(ov10635_init_data);
+ for (i = 0; i < array_size; i++) {
+ retval = ov10635_write_reg(max9286_data, index,
+ ov10635_init_data[i].reg_addr, ov10635_init_data[i].val);
+ if (retval < 0)
+ break;
+ if (ov10635_init_data[i].delay_ms != 0)
+ msleep(ov10635_init_data[i].delay_ms);
+ }
+
+ return 0;
+}
+
+static inline int max9271_read_reg(struct sensor_data *max9286_data, int index, u8 reg)
+{
+ int val;
+ int retry, timeout = 10;
+
+ max9286_data->i2c_client->addr = ADDR_MAX9271 + index;
+ for (retry = 0; retry < timeout; retry++) {
+ val = i2c_smbus_read_byte_data(max9286_data->i2c_client, reg);
+ if (val < 0)
+ msleep(5);
+ else
+ break;
+ }
+
+ if (retry >= timeout) {
+ dev_info(&max9286_data->i2c_client->dev,
+ "%s:read reg error: reg=%2x\n", __func__, reg);
+ return -1;
+ }
+
+ return val;
+}
+
+static int max9271_write_reg(struct sensor_data *max9286_data, int index, u8 reg, u8 val)
+{
+ s32 ret;
+ int retry, timeout = 10;
+
+ max9286_data->i2c_client->addr = ADDR_MAX9271 + index;
+ for (retry = 0; retry < timeout; retry++) {
+ ret = i2c_smbus_write_byte_data(max9286_data->i2c_client, reg, val);
+ if (val < 0)
+ msleep(5);
+ else
+ break;
+ }
+ dev_dbg(&max9286_data->i2c_client->dev,
+ "%s: addr %02x reg %02x val %02x\n",
+ __func__, max9286_data->i2c_client->addr, reg, val);
+
+ if (retry >= timeout) {
+ dev_info(&max9286_data->i2c_client->dev,
+ "%s:write reg error:reg=%2x,val=%2x\n", __func__,
+ reg, val);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*! Read one register from a MAX9286 i2c slave device.
+ *
+ * @param *reg register in the device we wish to access.
+ *
+ * @return 0 if success, an error code otherwise.
+ */
+static inline int max9286_read_reg(struct sensor_data *max9286_data, u8 reg)
+{
+ int val;
+
+ max9286_data->i2c_client->addr = ADDR_MAX9286;
+ val = i2c_smbus_read_byte_data(max9286_data->i2c_client, reg);
+ if (val < 0) {
+ dev_info(&max9286_data->i2c_client->dev,
+ "%s:read reg error: reg=%2x\n", __func__, reg);
+ return -1;
+ }
+ return val;
+}
+
+/*! Write one register of a MAX9286 i2c slave device.
+ *
+ * @param *reg register in the device we wish to access.
+ *
+ * @return 0 if success, an error code otherwise.
+ */
+static int max9286_write_reg(struct sensor_data *max9286_data, u8 reg, u8 val)
+{
+ s32 ret;
+
+ max9286_data->i2c_client->addr = ADDR_MAX9286;
+ ret = i2c_smbus_write_byte_data(max9286_data->i2c_client, reg, val);
+
+ dev_dbg(&max9286_data->i2c_client->dev,
+ "%s: addr %02x reg %02x val %02x\n",
+ __func__, max9286_data->i2c_client->addr, reg, val);
+
+ if (ret < 0) {
+ dev_info(&max9286_data->i2c_client->dev,
+ "%s:write reg error:reg=%2x,val=%2x\n", __func__,
+ reg, val);
+ return -1;
+ }
+ return 0;
+}
+
+#ifdef debug
+static void max9271_dump_registers(struct sensor_data *max9286_data, int index)
+{
+ unsigned char i;
+ printk("max9271_dump_registers: index = %d.\r\n", index);
+ for (i = 0; i < 0x20; i++)
+ printk("MAX9271 Reg 0x%02x = 0x%x.\r\n", i, max9271_read_reg(max9286_data, index, i));
+}
+
+static void max9286_dump_registers(struct sensor_data *max9286_data)
+{
+ unsigned char i;
+ printk("Dump MAX9286 registers:\r\n");
+ for (i = 0; i < 0x72; i++)
+ printk("MAX9286 Reg 0x%02x = 0x%x.\r\n", i, max9286_read_reg(max9286_data, i));
+}
+#else
+static void max9271_dump_registers(struct sensor_data *max9286_data, int index)
+{
+}
+#endif
+
+static int max9286_hardware_preinit(struct sensor_data *max9286_data)
+{
+ u8 reg;
+
+ dev_info(&max9286_data->i2c_client->dev, "In %s()\n", __func__);
+
+ /* Disable CSI Output */
+ max9286_write_reg(max9286_data, 0x15, 0x03);
+
+ /* Enable PRBS test */
+ max9286_write_reg(max9286_data, 0x0E, 0x5F);
+ msleep(10);
+
+ /* Enable Custom Reverse Channel & First Pulse Length STEP 1 */
+ max9286_write_reg(max9286_data, 0x3F, 0x4F);
+ msleep(2); /* STEP 2 */
+
+ /* Reverse Channel Amplitude to mid level and transition time */
+ max9286_write_reg(max9286_data, 0x3B, 0x1E); /* STEP 3 */
+ msleep(2); /* STEP 4 */
+
+ /* Enable MAX9271 Configuration Link */
+ max9271_write_reg(max9286_data, 0, 0x04, 0x43); /* STEP 5 */
+ msleep(2); /* STEP 6 */
+
+ /* Increase serializer reverse channel input thresholds */
+ max9271_write_reg(max9286_data, 0, 0x08, 0x01); /* STEP 7 */
+ msleep(2); /* STEP 8 */
+
+ /* Reverse Channel Amplitude level */
+ max9286_write_reg(max9286_data, 0x3B, 0x19); /* STEP 9 */
+ msleep(5); /* STEP 10 */
+
+ /* Set YUV422 8 bits mode, Double Data Rate, 4 data lane */
+ max9286_write_reg(max9286_data, 0x12, 0xF3); /* STEP 12 */
+
+ max9286_write_reg(max9286_data, 0x01, 0x02); /* STEP 13 */
+ /* Enable All Link 0-3 */
+ max9286_write_reg(max9286_data, 0x00, 0xef); /* STEP 14 */
+
+ /* Frame Sync */
+ /* Automatic Mode */
+ max9286_write_reg(max9286_data, 0x01, 0x02);/* STEP 13 */
+ msleep(200);
+ /* Detect link */
+ max9286_data->sensor_num = 0;
+ reg = max9286_read_reg(max9286_data, 0x49);
+ max9286_data->sensor_is_there = ((reg >> 4) & 0xF) | (reg & 0xF);
+ if (max9286_data->sensor_is_there & (0x1 << 0))
+ max9286_data->sensor_num += 1;
+ if (max9286_data->sensor_is_there & (0x1 << 1))
+ max9286_data->sensor_num += 1;
+ if (max9286_data->sensor_is_there & (0x1 << 2))
+ max9286_data->sensor_num += 1;
+ if (max9286_data->sensor_is_there & (0x1 << 3))
+ max9286_data->sensor_num += 1;
+ pr_info("max9286_mipi: reg = 0x%02x.\n", reg);
+ pr_info("max9286_mipi: sensor number = %d.\n", max9286_data->sensor_num);
+
+ if (max9286_data->sensor_num == 0) {
+ pr_err("%s: no camera connected.\n", __func__);
+ return -1;
+ }
+ return 0;
+
+}
+
+static void max9286_camera_reorder(struct sensor_data *max9286_data)
+{
+ u8 reg;
+
+ reg = 0xE4;
+ if (max9286_data->sensor_num == 1) {
+ switch (max9286_data->sensor_is_there) {
+ case 0x8:
+ reg = 0x27;
+ break;
+ case 0x4:
+ reg = 0xC6;
+ break;
+ case 0x2:
+ reg = 0xE1;
+ break;
+ case 0x1:
+ default:
+ reg = 0xE4;
+ break;
+ }
+ } else if (max9286_data->sensor_num == 2) {
+ switch (max9286_data->sensor_is_there) {
+ case 0xC:
+ reg = 0x4E;
+ break;
+ case 0xA:
+ reg = 0x72;
+ break;
+ case 0x9:
+ reg = 0x78;
+ break;
+ case 0x6:
+ reg = 0xD2;
+ break;
+ case 0x5:
+ reg = 0xD8;
+ break;
+ case 0x3:
+ default:
+ reg = 0xE4;
+ break;
+ }
+ } else if (max9286_data->sensor_num == 3) {
+ switch (max9286_data->sensor_is_there) {
+ case 0xE:
+ reg = 0x93;
+ break;
+ case 0xD:
+ reg = 0x9C;
+ break;
+ case 0xB:
+ reg = 0xB4;
+ break;
+ case 0x7:
+ default:
+ reg = 0xE4;
+ break;
+ }
+ }
+ max9286_write_reg(max9286_data, 0x0B, reg);
+}
+
+static int max9286_hardware_init(struct sensor_data *max9286_data)
+{
+ int retval = 0;
+ int i;
+ u8 reg, sensor_addr = 0;
+
+ dev_info(&max9286_data->i2c_client->dev, "In %s()\n", __func__);
+
+ /* Disable PRBS test */
+ max9286_write_reg(max9286_data, 0x0E, 0x50);
+
+ /* reorder camera */
+ max9286_camera_reorder(max9286_data);
+
+ /* Enable all links */
+ reg = 0xE0 | max9286_data->sensor_is_there;
+ max9286_write_reg(max9286_data, 0x00, reg);
+
+ /* Set up links */
+ sensor_addr = ADDR_OV_SENSOR;
+ max9271_write_reg(max9286_data, 0, 0x07, 0x84);
+ /* STEP 15-46 */
+ reg = 0;
+ for (i = 1; i <= MAX9271_MAX_SENSOR_NUM; i++) {
+ if (((0x1 << (i - 1)) & max9286_data->sensor_is_there) == 0)
+ continue;
+
+ /* Enable Link control channel */
+ reg |= (0x11 << (i - 1));
+ max9286_write_reg(max9286_data, 0x0A, reg);/* STEP 15 */
+
+ /* Set MAX9271 new address for link 0 */
+ max9271_write_reg(max9286_data, 0, 0x00, (ADDR_MAX9271 + i) << 1);
+ msleep(2);
+
+ max9271_write_reg(max9286_data, i, 0x01, ADDR_MAX9286 << 1);
+ max9271_write_reg(max9286_data, i, 0x09, (sensor_addr + i) << 1);
+ max9271_write_reg(max9286_data, i, 0x0A, sensor_addr << 1);
+ max9271_write_reg(max9286_data, i, 0x0B, ADDR_MAX9271_ALL << 1);
+ max9271_write_reg(max9286_data, i, 0x0C, (ADDR_MAX9271 + i) << 1);
+
+ msleep(1);
+ pr_info("max9286_mipi: initialized sensor = 0x%02x.\n", i);
+ max9271_dump_registers(max9286_data, i);
+ }
+ max9286_write_reg(max9286_data, 0x0A, reg);
+ max9286_write_reg(max9286_data, 0x0A, reg);
+
+ /* Disable Local Auto I2C ACK */
+ max9286_write_reg(max9286_data, 0x34, 0x36); /* STEP 48 */
+
+ /* Initialize Camera Sensor */
+ /* STEP 49 */
+ if (max9286_data->sensor_is_there & (0x1 << 0)) {
+ retval = ov10635_check_device(max9286_data, 1);
+ if (retval < 0)
+ return retval;
+ ov10635_initialize(max9286_data, 0);
+ }
+
+ if (max9286_data->sensor_is_there & (0x1 << 1)) {
+ retval = ov10635_check_device(max9286_data, 2);
+ if (retval < 0)
+ return retval;
+ ov10635_initialize(max9286_data, 1);
+ }
+
+ if (max9286_data->sensor_is_there & (0x1 << 2)) {
+ ov10635_check_device(max9286_data, 3);
+ if (retval < 0)
+ return retval;
+ ov10635_initialize(max9286_data, 2);
+ }
+
+ if (max9286_data->sensor_is_there & (0x1 << 3)) {
+ retval = ov10635_check_device(max9286_data, 4);
+ if (retval < 0)
+ return retval;
+ ov10635_initialize(max9286_data, 3);
+ }
+
+ /* Enable Local Auto I2C ACK */
+ max9286_write_reg(max9286_data, 0x34, 0xB6); /* STEP 50 */
+
+ /* MAX9271: Enable Serial Links and Disable Configuration Link */
+ max9271_write_reg(max9286_data, ADDR_MAX9271_ALL - ADDR_MAX9271, 0x04, 0x83); /* STEP 51 */
+ /* Wait for more than 2 frame time */
+ msleep(1000); /* STEP 52 */
+
+ /* Enable CSI output, set virtual channel according to the link number */
+ max9286_write_reg(max9286_data, 0x15, 0x9B); /* STEP 52 */
+ msleep(10);
+ return retval;
+}
+
+static int max9286_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+ struct sensor_data *max9286_data = subdev_to_sensor_data(sd);
+ int ret = 0;
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cparm->capability = max9286_data->streamcap.capability;
+ cparm->timeperframe = max9286_data->streamcap.timeperframe;
+ cparm->capturemode = max9286_data->streamcap.capturemode;
+ ret = 0;
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ ret = -EINVAL;
+ break;
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible. If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ */
+static int max9286_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct sensor_data *max9286_data = subdev_to_sensor_data(sd);
+ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+ enum ov10635_frame_rate frame_rate;
+ u32 tgt_fps;
+ int ret = 0;
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ /* Check that the new frame rate is allowed. */
+ if ((timeperframe->numerator == 0) ||
+ (timeperframe->denominator == 0)) {
+ timeperframe->denominator = DEFAULT_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps > MAX_FPS) {
+ timeperframe->denominator = MAX_FPS;
+ timeperframe->numerator = 1;
+ } else if (tgt_fps < MIN_FPS) {
+ timeperframe->denominator = MIN_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ /* Actual frame rate we use */
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps == 30)
+ frame_rate = OV10635_30_FPS;
+
+ if (frame_rate != OV10635_30_FPS) {
+ pr_err(" The camera %d frame rate is not supported!\n", frame_rate);
+ return -EINVAL;
+ }
+
+ /* TODO Reserved to extension */
+
+ max9286_data->streamcap.timeperframe = *timeperframe;
+ max9286_data->streamcap.capturemode = a->parm.capture.capturemode;
+
+
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ pr_debug(" type is not "\
+ "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n",
+ a->type);
+ ret = -EINVAL;
+ break;
+
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int max9286_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct sensor_data *max9286_data = subdev_to_sensor_data(sd);
+
+ code->code = max9286_data->format.code;
+ return 0;
+}
+
+/*!
+ * max9286_enum_framesizes - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int max9286_enum_framesizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct sensor_data *max9286_data = subdev_to_sensor_data(sd);
+
+ if (fse->index > 1)
+ return -EINVAL;
+
+ fse->max_width = max9286_data->format.width;
+ fse->min_width = fse->max_width;
+
+ fse->max_height = max9286_data->format.height;
+ fse->min_height = fse->max_height;
+ return 0;
+}
+static int max9286_enum_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ if (fie->index < 0 || fie->index > 8)
+ return -EINVAL;
+
+ if (fie->width == 0 || fie->height == 0 ||
+ fie->code == 0) {
+ pr_warning("Please assign pixel format, width and height.\n");
+ return -EINVAL;
+ }
+
+ fie->interval.numerator = 1;
+
+ /* TODO Reserved to extension */
+
+ fie->interval.denominator = 30;
+ return 0;
+}
+
+static int max9286_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct sensor_data *max9286_data = subdev_to_sensor_data(sd);
+ struct v4l2_mbus_framefmt *mf = &fmt->format;
+
+ if (fmt->pad)
+ return -EINVAL;
+
+ mf->code = max9286_data->format.code;
+ mf->width = max9286_data->format.width;
+ mf->height = max9286_data->format.height;
+ mf->colorspace = max9286_data->format.colorspace;
+ mf->field = max9286_data->format.field;
+
+ return 0;
+}
+
+static int max9286_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ return 0;
+}
+
+static int max9286_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_frame_desc *fd)
+{
+ return 0;
+}
+
+static int max9286_set_frame_desc(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_frame_desc *fd)
+{
+ return 0;
+}
+
+static int max9286_set_power(struct v4l2_subdev *sd, int on)
+{
+ return 0;
+}
+
+static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct sensor_data *max9286_data = subdev_to_sensor_data(sd);
+
+ dev_dbg(sd->dev, "%s\n", __func__);
+ if (enable) {
+ if (!max9286_data->running) {
+ /* Enable CSI output, set virtual channel according to the link number */
+ max9286_write_reg(max9286_data, 0x15, 0x9B);
+ }
+ max9286_data->running++;
+
+ } else {
+
+ if (max9286_data->running) {
+ /* Disable CSI Output */
+ max9286_write_reg(max9286_data, 0x15, 0x03);
+ }
+ max9286_data->running--;
+ }
+
+ return 0;
+}
+
+static int max9286_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops max9286_pad_ops = {
+ .enum_mbus_code = max9286_enum_mbus_code,
+ .enum_frame_size = max9286_enum_framesizes,
+ .enum_frame_interval = max9286_enum_frame_interval,
+ .get_fmt = max9286_get_fmt,
+ .set_fmt = max9286_set_fmt,
+ .get_frame_desc = max9286_get_frame_desc,
+ .set_frame_desc = max9286_set_frame_desc,
+};
+
+static const struct v4l2_subdev_core_ops max9286_core_ops = {
+ .s_power = max9286_set_power,
+};
+
+static const struct v4l2_subdev_video_ops max9286_video_ops = {
+ .s_parm = max9286_s_parm,
+ .g_parm = max9286_g_parm,
+ .s_stream = max9286_s_stream,
+};
+
+static const struct v4l2_subdev_ops max9286_subdev_ops = {
+ .core = &max9286_core_ops,
+ .pad = &max9286_pad_ops,
+ .video = &max9286_video_ops,
+};
+
+static const struct media_entity_operations max9286_sd_media_ops = {
+ .link_setup = max9286_link_setup,
+};
+
+/*!
+ * max9286 I2C probe function
+ *
+ * @param adapter struct i2c_adapter *
+ * @return Error code indicating success or failure
+ */
+static int max9286_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct sensor_data *max9286_data;
+ struct v4l2_subdev *sd;
+ int retval;
+
+ max9286_data = devm_kzalloc(dev, sizeof(*max9286_data), GFP_KERNEL);
+ if (!max9286_data)
+ return -ENOMEM;
+
+ /* Set initial values for the sensor struct. */
+ max9286_data->sensor_clk = devm_clk_get(dev, "capture_mclk");
+ if (IS_ERR(max9286_data->sensor_clk)) {
+ /* assuming clock enabled by default */
+ max9286_data->sensor_clk = NULL;
+ dev_err(dev, "clock-frequency missing or invalid\n");
+ return PTR_ERR(max9286_data->sensor_clk);
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk",
+ &(max9286_data->mclk));
+ if (retval) {
+ dev_err(dev, "mclk missing or invalid\n");
+ return retval;
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk_source",
+ (u32 *)&(max9286_data->mclk_source));
+ if (retval) {
+ dev_err(dev, "mclk_source missing or invalid\n");
+ return retval;
+ }
+
+ /* request power down pin */
+ max9286_data->pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+ if (!gpio_is_valid(max9286_data->pwn_gpio)) {
+ dev_err(dev, "no sensor pwdn pin available\n");
+ return -ENODEV;
+ }
+ retval = devm_gpio_request_one(dev, max9286_data->pwn_gpio, GPIOF_OUT_INIT_HIGH,
+ "max9286_pwd");
+ if (retval < 0)
+ return retval;
+
+ clk_prepare_enable(max9286_data->sensor_clk);
+
+ max9286_data->i2c_client = client;
+ max9286_data->format.code = MEDIA_BUS_FMT_YUYV8_1X16;
+ max9286_data->format.width = g_max9286_width;
+ max9286_data->format.height = g_max9286_height;
+ max9286_data->format.colorspace = V4L2_COLORSPACE_JPEG;
+ /*****************************************
+ * Pass mipi phy clock rate Mbps
+ * fcsi2 = PCLk * WIDTH * CHANNELS / LANES
+ * fsci2 = 72MPCLK * 8 bit * 4 channels / 4 lanes
+ ****************************************/
+ max9286_data->format.reserved[0] = 72 * 8;
+ max9286_data->format.field = V4L2_FIELD_NONE;
+ max9286_data->streamcap.capturemode = 0;
+ max9286_data->streamcap.timeperframe.denominator = 30;
+ max9286_data->streamcap.timeperframe.numerator = 1;
+ max9286_data->is_mipi = 1;
+
+ retval = max9286_read_reg(max9286_data, 0x1e);
+ if (retval != 0x40) {
+ pr_warning("max9286 is not found, chip id reg 0x1e = 0x%x.\n", retval);
+ clk_disable_unprepare(max9286_data->sensor_clk);
+ devm_gpio_free(dev, max9286_data->pwn_gpio);
+ return -ENODEV;
+ }
+
+ max9286_hardware_preinit(max9286_data);
+
+ if (max9286_data->sensor_num == 0) {
+ pr_warning("cameras are not found,\n");
+ clk_disable_unprepare(max9286_data->sensor_clk);
+ devm_gpio_free(dev, max9286_data->pwn_gpio);
+ return -ENODEV;
+ }
+
+ max9286_data->streamcap.capability = V4L2_CAP_TIMEPERFRAME;
+ max9286_data->streamcap.timeperframe.denominator = 30;
+ max9286_data->streamcap.timeperframe.numerator = 1;
+ max9286_data->v_channel = 0;
+ max9286_data->cap_mode.clip_top = 0;
+ max9286_data->cap_mode.clip_left = 0;
+
+ max9286_data->cap_mode.clip_height = 800;
+ max9286_data->cap_mode.clip_width = 1280;
+
+ max9286_data->cap_mode.hlen = max9286_data->cap_mode.clip_width;
+
+ max9286_data->cap_mode.hfp = 0;
+ max9286_data->cap_mode.hbp = 0;
+ max9286_data->cap_mode.hsync = 625;
+ max9286_data->cap_mode.vlen = 800;
+ max9286_data->cap_mode.vfp = 0;
+ max9286_data->cap_mode.vbp = 0;
+ max9286_data->cap_mode.vsync = 40;
+ max9286_data->cap_mode.vlen1 = 0;
+ max9286_data->cap_mode.vfp1 = 0;
+ max9286_data->cap_mode.vbp1 = 0;
+ max9286_data->cap_mode.vsync1 = 0;
+ max9286_data->cap_mode.pixelclock = 27000000;
+
+ sd = &max9286_data->subdev;
+ v4l2_i2c_subdev_init(sd, client, &max9286_subdev_ops);
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ max9286_data->pads[MIPI_CSI2_SENS_VC0_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ max9286_data->pads[MIPI_CSI2_SENS_VC1_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ max9286_data->pads[MIPI_CSI2_SENS_VC2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ max9286_data->pads[MIPI_CSI2_SENS_VC3_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ retval = media_entity_pads_init(&sd->entity, MIPI_CSI2_SENS_VCX_PADS_NUM,
+ max9286_data->pads);
+ if (retval < 0)
+ return retval;
+
+ max9286_data->subdev.entity.ops = &max9286_sd_media_ops;
+ retval = v4l2_async_register_subdev(&max9286_data->subdev);
+ if (retval < 0) {
+ dev_err(&client->dev,
+ "%s--Async register failed, ret=%d\n", __func__, retval);
+ media_entity_cleanup(&sd->entity);
+ }
+
+ retval = max9286_hardware_init(max9286_data);
+ if (retval < 0) {
+ dev_err(&client->dev, "camera init failed\n");
+ clk_disable_unprepare(max9286_data->sensor_clk);
+ media_entity_cleanup(&sd->entity);
+ v4l2_async_unregister_subdev(sd);
+ return retval;
+ }
+
+ max9286_data->running = 0;
+
+ /* Disable CSI Output */
+ max9286_write_reg(max9286_data, 0x15, 0x03);
+
+ dev_info(&max9286_data->i2c_client->dev,
+ "max9286_mipi is found, name %s\n", sd->name);
+ return retval;
+}
+
+/*!
+ * max9286 I2C detach function
+ *
+ * @param client struct i2c_client *
+ * @return Error code indicating success or failure
+ */
+static int max9286_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct sensor_data *max9286_data = subdev_to_sensor_data(sd);
+
+ clk_disable_unprepare(max9286_data->sensor_clk);
+ media_entity_cleanup(&sd->entity);
+ v4l2_async_unregister_subdev(sd);
+
+ return 0;
+}
+static const struct i2c_device_id max9286_id[] = {
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, max9286_id);
+
+static const struct of_device_id max9286_of_match[] = {
+ { .compatible = "maxim,max9286_mipi" },
+ { /* sentinel */ }
+};
+
+static struct i2c_driver max9286_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "max9286_mipi",
+ .of_match_table = of_match_ptr(max9286_of_match),
+ },
+ .probe = max9286_probe,
+ .remove = max9286_remove,
+ .id_table = max9286_id,
+};
+
+module_i2c_driver(max9286_i2c_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MAX9286 GSML Deserializer Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("CSI");
diff --git a/drivers/media/platform/imx8/mxc-isi-cap.c b/drivers/media/platform/imx8/mxc-isi-cap.c
new file mode 100644
index 000000000000..3efda6c026e5
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-isi-cap.c
@@ -0,0 +1,1669 @@
+/*
+ * Copyright 2017-2018 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/of_graph.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+#include <soc/imx8/sc/sci.h>
+
+#include "mxc-isi-core.h"
+#include "mxc-isi-hw.h"
+#include "mxc-media-dev.h"
+
+struct mxc_isi_fmt mxc_isi_out_formats[] = {
+ {
+ .name = "RGB565",
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .depth = { 16 },
+ .color = MXC_ISI_OUT_FMT_RGB565,
+ .memplanes = 1,
+ .colplanes = 1,
+ .mbus_code = MEDIA_BUS_FMT_RGB565_1X16,
+ }, {
+ .name = "RGB24",
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .depth = { 32 },
+ .color = MXC_ISI_OUT_FMT_XRGB32,
+ .memplanes = 1,
+ .colplanes = 1,
+ .mbus_code = MEDIA_BUS_FMT_RGB888_1X24,
+ }, {
+ .name = "RGB32",
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .depth = { 32 },
+ .color = MXC_ISI_OUT_FMT_XRGB32,
+ .memplanes = 1,
+ .colplanes = 1,
+ .mbus_code = MEDIA_BUS_FMT_RGB888_1X24,
+ }, {
+ .name = "BGR24",
+ .fourcc = V4L2_PIX_FMT_BGR24,
+ .depth = { 32 },
+ .color = MXC_ISI_OUT_FMT_XBGR32,
+ .memplanes = 1,
+ .colplanes = 1,
+ .mbus_code = MEDIA_BUS_FMT_BGR888_1X24,
+ }, {
+ .name = "ARGB32",
+ .fourcc = V4L2_PIX_FMT_ARGB32,
+ .depth = { 32 },
+ .color = MXC_ISI_OUT_FMT_ARGB32,
+ .memplanes = 1,
+ .colplanes = 1,
+ .mbus_code = MEDIA_BUS_FMT_ARGB8888_1X32,
+ }, {
+ .name = "YUYV-16",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = { 16 },
+ .color = MXC_ISI_OUT_FMT_YUV422_1P8P,
+ .memplanes = 1,
+ .colplanes = 1,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16,
+ }, {
+ .name = "YUV32 (X-Y-U-V)",
+ .fourcc = V4L2_PIX_FMT_YUV32,
+ .depth = { 32 },
+ .color = MXC_ISI_OUT_FMT_YUV444_1P8,
+ .memplanes = 1,
+ .colplanes = 1,
+ .mbus_code = MEDIA_BUS_FMT_AYUV8_1X32,
+ }, {
+ .name = "NV12 (YUYV)",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .depth = { 8, 8 },
+ .color = MXC_ISI_OUT_FMT_YUV420_2P8P,
+ .memplanes = 2,
+ .colplanes = 2,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16,
+ }
+};
+
+struct mxc_isi_fmt mxc_isi_src_formats[] = {
+ /* Pixel link input format */
+ {
+ .name = "RGB32",
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .depth = { 32 },
+ .memplanes = 1,
+ .colplanes = 1,
+ }, {
+ .name = "YUV32 (X-Y-U-V)",
+ .fourcc = V4L2_PIX_FMT_YUV32,
+ .depth = { 32 },
+ .memplanes = 1,
+ .colplanes = 1,
+ }
+};
+
+struct mxc_isi_fmt mxc_isi_m2m_in_formats[] = {
+ {
+ .name = "RGB565",
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .depth = { 16 },
+ .color = MXC_ISI_M2M_IN_FMT_RGB565,
+ .memplanes = 1,
+ .colplanes = 1,
+ }, {
+ .name = "YUV 4:2:2 packed, YCbYCr",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = { 16 },
+ .color = MXC_ISI_M2M_IN_FMT_YUV422_1P8P,
+ .memplanes = 1,
+ .colplanes = 1,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16,
+ },
+};
+
+struct mxc_isi_fmt *mxc_isi_get_format(unsigned int index)
+{
+ return &mxc_isi_out_formats[index];
+}
+
+/**
+ * mxc_isi_find_format - lookup mxc_isi color format by fourcc or media bus format
+ */
+struct mxc_isi_fmt *mxc_isi_find_format(const u32 *pixelformat,
+ const u32 *mbus_code, int index)
+{
+ struct mxc_isi_fmt *fmt, *def_fmt = NULL;
+ unsigned int i;
+ int id = 0;
+
+ if (index >= (int)ARRAY_SIZE(mxc_isi_out_formats))
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(mxc_isi_out_formats); i++) {
+ fmt = &mxc_isi_out_formats[i];
+ if (pixelformat && fmt->fourcc == *pixelformat)
+ return fmt;
+ if (mbus_code && fmt->mbus_code == *mbus_code)
+ return fmt;
+ if (index == id)
+ def_fmt = fmt;
+ id++;
+ }
+ return def_fmt;
+}
+
+struct mxc_isi_fmt *mxc_isi_get_src_fmt(struct v4l2_subdev_format *sd_fmt)
+{
+ u32 index;
+
+ /* two fmt RGB32 and YUV444 from pixellink */
+ if (sd_fmt->format.code == MEDIA_BUS_FMT_YUYV8_1X16 ||
+ sd_fmt->format.code == MEDIA_BUS_FMT_YVYU8_2X8 ||
+ sd_fmt->format.code == MEDIA_BUS_FMT_AYUV8_1X32 ||
+ sd_fmt->format.code == MEDIA_BUS_FMT_UYVY8_2X8)
+ index = 1;
+ else
+ index = 0;
+ return &mxc_isi_src_formats[index];
+}
+
+/*
+ * mxc_isi_pipeline_enable() - Enable streaming on a pipeline
+ *
+ */
+static int mxc_isi_pipeline_enable(struct mxc_isi_dev *mxc_isi, bool enable)
+{
+ struct media_entity *entity = &mxc_isi->isi_cap.vdev.entity;
+ struct media_device *mdev = entity->graph_obj.mdev;
+ struct media_entity_graph graph;
+ struct v4l2_subdev *subdev;
+ int ret = 0;
+
+ mutex_lock(&mdev->graph_mutex);
+
+ ret = media_entity_graph_walk_init(&graph, entity->graph_obj.mdev);
+ if (ret) {
+ mutex_unlock(&mdev->graph_mutex);
+ return ret;
+ }
+ media_entity_graph_walk_start(&graph, entity);
+
+ while ((entity = media_entity_graph_walk_next(&graph))) {
+ if (entity == NULL) {
+ dev_dbg(&mxc_isi->pdev->dev,
+ "%s ,entity is NULL\n", __func__);
+ continue;
+ }
+
+ if (!is_media_entity_v4l2_subdev(entity)) {
+ dev_dbg(&mxc_isi->pdev->dev,
+ "%s ,entity is no v4l2, %s\n", __func__, entity->name);
+ continue;
+ }
+
+ subdev = media_entity_to_v4l2_subdev(entity);
+ if (subdev == NULL) {
+ dev_dbg(&mxc_isi->pdev->dev,
+ "%s ,%s,subdev is NULL\n", __func__, entity->name);
+ continue;
+ }
+
+ ret = v4l2_subdev_call(subdev, video, s_stream, enable);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ dev_err(&mxc_isi->pdev->dev,
+ "%s ,subdev %s s_stream failed\n", __func__, subdev->name);
+ break;
+ }
+ }
+ mutex_unlock(&mdev->graph_mutex);
+ media_entity_graph_walk_cleanup(&graph);
+
+ return ret;
+}
+
+static int mxc_isi_update_buf_paddr(struct mxc_isi_buffer *buf, int memplanes)
+{
+ struct frame_addr *paddr = &buf->paddr;
+ struct vb2_buffer *vb2 = &buf->v4l2_buf.vb2_buf;
+ int ret = 0;
+
+ /* support one plane now */
+ paddr->cb = 0;
+ paddr->cr = 0;
+
+ switch (memplanes) {
+ case 3:
+ paddr->cr = vb2_dma_contig_plane_dma_addr(vb2, 2);
+ case 2:
+ paddr->cb = vb2_dma_contig_plane_dma_addr(vb2, 1);
+ case 1:
+ paddr->y = vb2_dma_contig_plane_dma_addr(vb2, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+void mxc_isi_frame_write_done(struct mxc_isi_dev *mxc_isi)
+{
+ struct mxc_isi_buffer *buf;
+ struct vb2_buffer *vb2;
+
+ /* Retrun if no pending buffer */
+ if (!list_empty(&mxc_isi->isi_cap.out_active)) {
+
+ buf = list_first_entry(&mxc_isi->isi_cap.out_active,
+ struct mxc_isi_buffer, list);
+
+ list_del(&buf->list);
+ buf->v4l2_buf.vb2_buf.timestamp = ktime_get_ns();
+ buf->v4l2_buf.sequence = mxc_isi->isi_cap.frame_count++;
+ vb2_buffer_done(&buf->v4l2_buf.vb2_buf, VB2_BUF_STATE_DONE);
+ }
+
+ if (!list_empty(&mxc_isi->isi_cap.out_pending)) {
+
+ /* ISI channel output buffer */
+ buf = list_first_entry(&mxc_isi->isi_cap.out_pending,
+ struct mxc_isi_buffer, list);
+ list_del(&buf->list);
+
+ buf->v4l2_buf.sequence = mxc_isi->isi_cap.frame_count;
+ mxc_isi_channel_set_outbuf(mxc_isi, buf);
+ vb2 = &buf->v4l2_buf.vb2_buf;
+ vb2->state = VB2_BUF_STATE_ACTIVE;
+ list_add_tail(&buf->list, &mxc_isi->isi_cap.out_active);
+ }
+}
+
+static int cap_vb2_queue_setup(struct vb2_queue *q,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], struct device *alloc_devs[])
+{
+ struct mxc_isi_dev *mxc_isi = q->drv_priv;
+ struct mxc_isi_frame *dst_f = &mxc_isi->isi_cap.dst_f;
+ struct mxc_isi_fmt *fmt = dst_f->fmt;
+ unsigned long wh;
+ int i;
+
+ if (fmt == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < fmt->memplanes; i++)
+ alloc_devs[i] = &mxc_isi->pdev->dev;
+
+ wh = dst_f->width * dst_f->height;
+
+ *num_planes = fmt->memplanes;
+
+ for (i = 0; i < fmt->memplanes; i++) {
+ unsigned int size = (wh * fmt->depth[i]) / 8;
+
+ if (i == 1 && fmt->fourcc == V4L2_PIX_FMT_NV12)
+ size >>= 1;
+ sizes[i] = max_t(u32, size, dst_f->sizeimage[i]);
+ }
+ dev_dbg(&mxc_isi->pdev->dev, "%s, buf_n=%d, size=%d\n",
+ __func__, *num_buffers, sizes[0]);
+
+ return 0;
+}
+
+static int cap_vb2_buffer_prepare(struct vb2_buffer *vb2)
+{
+ struct vb2_queue *q = vb2->vb2_queue;
+ struct mxc_isi_dev *mxc_isi = q->drv_priv;
+ struct mxc_isi_frame *dst_f = &mxc_isi->isi_cap.dst_f;
+ int i;
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s\n", __func__);
+
+ if (mxc_isi->isi_cap.dst_f.fmt == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < dst_f->fmt->memplanes; i++) {
+ unsigned long size = dst_f->sizeimage[i];
+
+ if (vb2_plane_size(vb2, i) < size) {
+ v4l2_err(&mxc_isi->isi_cap.vdev,
+ "User buffer too small (%ld < %ld)\n",
+ vb2_plane_size(vb2, i), size);
+ return -EINVAL;
+ }
+#if 0 //debug only
+ if (vb2_plane_vaddr(vb2, i))
+ memset((void *)vb2_plane_vaddr(vb2, i), 0xaa,
+ vb2_get_plane_payload(vb2, i));
+#endif
+ vb2_set_plane_payload(vb2, i, size);
+ }
+
+ return 0;
+}
+
+static void cap_vb2_buffer_queue(struct vb2_buffer *vb2)
+{
+ struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb2);
+ struct mxc_isi_buffer *buf
+ = container_of(v4l2_buf, struct mxc_isi_buffer, v4l2_buf);
+ struct mxc_isi_dev *mxc_isi = vb2_get_drv_priv(vb2->vb2_queue);
+ unsigned long flags;
+
+ spin_lock_irqsave(&mxc_isi->slock, flags);
+
+ mxc_isi_update_buf_paddr(buf, mxc_isi->isi_cap.dst_f.fmt->mdataplanes);
+ list_add_tail(&buf->list, &mxc_isi->isi_cap.out_pending);
+
+ spin_unlock_irqrestore(&mxc_isi->slock, flags);
+}
+
+
+static int cap_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct mxc_isi_dev *mxc_isi = q->drv_priv;
+ struct mxc_isi_buffer *buf;
+ struct vb2_buffer *vb2;
+ unsigned long flags;
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s\n", __func__);
+
+ spin_lock_irqsave(&mxc_isi->slock, flags);
+
+ mxc_isi->isi_cap.frame_count = 0;
+
+ /* ISI channel output buffer 1 */
+ buf = list_first_entry(&mxc_isi->isi_cap.out_pending,
+ struct mxc_isi_buffer, list);
+ buf->v4l2_buf.sequence = 0;
+ mxc_isi_channel_set_outbuf(mxc_isi, buf);
+ vb2 = &buf->v4l2_buf.vb2_buf;
+ vb2->state = VB2_BUF_STATE_ACTIVE;
+ list_move_tail(mxc_isi->isi_cap.out_pending.next, &mxc_isi->isi_cap.out_active);
+
+ /* ISI channel output buffer 2 */
+ buf = list_first_entry(&mxc_isi->isi_cap.out_pending,
+ struct mxc_isi_buffer, list);
+ buf->v4l2_buf.sequence = 1;
+ mxc_isi_channel_set_outbuf(mxc_isi, buf);
+ vb2 = &buf->v4l2_buf.vb2_buf;
+ vb2->state = VB2_BUF_STATE_ACTIVE;
+ list_move_tail(mxc_isi->isi_cap.out_pending.next, &mxc_isi->isi_cap.out_active);
+ spin_unlock_irqrestore(&mxc_isi->slock, flags);
+
+ return 0;
+}
+
+
+static void cap_vb2_stop_streaming(struct vb2_queue *q)
+{
+ struct mxc_isi_dev *mxc_isi = q->drv_priv;
+ struct mxc_isi_buffer *buf, *tmp;
+ unsigned long flags;
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s\n", __func__);
+
+ mxc_isi_channel_disable(mxc_isi);
+
+ spin_lock_irqsave(&mxc_isi->slock, flags);
+
+ while (!list_empty(&mxc_isi->isi_cap.out_active)) {
+ buf = list_entry(mxc_isi->isi_cap.out_active.next, struct mxc_isi_buffer, list);
+
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->v4l2_buf.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+
+ while (!list_empty(&mxc_isi->isi_cap.out_pending)) {
+ buf = list_entry(mxc_isi->isi_cap.out_pending.next, struct mxc_isi_buffer, list);
+
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->v4l2_buf.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+
+ list_for_each_entry_safe(buf, tmp,
+ &mxc_isi->isi_cap.out_active, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->v4l2_buf.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+
+ list_for_each_entry_safe(buf, tmp,
+ &mxc_isi->isi_cap.out_pending, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->v4l2_buf.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+
+ INIT_LIST_HEAD(&mxc_isi->isi_cap.out_active);
+ INIT_LIST_HEAD(&mxc_isi->isi_cap.out_pending);
+
+ spin_unlock_irqrestore(&mxc_isi->slock, flags);
+}
+
+static struct vb2_ops mxc_cap_vb2_qops = {
+ .queue_setup = cap_vb2_queue_setup,
+ .buf_prepare = cap_vb2_buffer_prepare,
+ .buf_queue = cap_vb2_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = cap_vb2_start_streaming,
+ .stop_streaming = cap_vb2_stop_streaming,
+};
+
+/*
+ * V4L2 controls handling
+ */
+#define ctrl_to_mxc_isi(__ctrl) \
+ container_of((__ctrl)->handler, struct mxc_isi_dev, ctrls.handler)
+
+static int mxc_isi_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mxc_isi_dev *mxc_isi = ctrl_to_mxc_isi(ctrl);
+ unsigned long flags;
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s\n", __func__);
+
+ if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+ return 0;
+
+ spin_lock_irqsave(&mxc_isi->slock, flags);
+
+ switch (ctrl->id) {
+ case V4L2_CID_HFLIP:
+ mxc_isi->hflip = ctrl->val;
+ break;
+
+ case V4L2_CID_VFLIP:
+ mxc_isi->vflip = ctrl->val;
+ break;
+
+ case V4L2_CID_ALPHA_COMPONENT:
+ mxc_isi->alpha = ctrl->val;
+ break;
+ }
+
+ spin_unlock_irqrestore(&mxc_isi->slock, flags);
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops mxc_isi_ctrl_ops = {
+ .s_ctrl = mxc_isi_s_ctrl,
+};
+
+int mxc_isi_ctrls_create(struct mxc_isi_dev *mxc_isi)
+{
+ struct mxc_isi_ctrls *ctrls = &mxc_isi->ctrls;
+ struct v4l2_ctrl_handler *handler = &ctrls->handler;
+
+ if (mxc_isi->ctrls.ready)
+ return 0;
+
+ v4l2_ctrl_handler_init(handler, 4);
+
+ ctrls->hflip = v4l2_ctrl_new_std(handler, &mxc_isi_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ ctrls->vflip = v4l2_ctrl_new_std(handler, &mxc_isi_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ ctrls->alpha = v4l2_ctrl_new_std(handler, &mxc_isi_ctrl_ops,
+ V4L2_CID_ALPHA_COMPONENT, 0, 0xff, 1, 0);
+
+ if (!handler->error)
+ ctrls->ready = true;
+
+ return handler->error;
+}
+
+void mxc_isi_ctrls_delete(struct mxc_isi_dev *mxc_isi)
+{
+ struct mxc_isi_ctrls *ctrls = &mxc_isi->ctrls;
+
+ if (ctrls->ready) {
+ v4l2_ctrl_handler_free(&ctrls->handler);
+ ctrls->ready = false;
+ ctrls->alpha = NULL;
+ }
+}
+
+static struct media_pad *mxc_isi_get_remote_source_pad(struct mxc_isi_dev *mxc_isi)
+{
+ struct mxc_isi_cap_dev *isi_cap = &mxc_isi->isi_cap;
+ struct v4l2_subdev *subdev = &isi_cap->sd;
+ struct media_pad *sink_pad, *source_pad;
+ int i;
+
+ while (1) {
+ source_pad = NULL;
+ for (i = 0; i < subdev->entity.num_pads; i++) {
+ sink_pad = &subdev->entity.pads[i];
+
+ if (sink_pad->flags & MEDIA_PAD_FL_SINK) {
+ source_pad = media_entity_remote_pad(sink_pad);
+ if (source_pad)
+ break;
+ }
+ }
+ /* return first pad point in the loop */
+ return source_pad;
+ }
+
+ if (i == subdev->entity.num_pads)
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
+
+ return NULL;
+}
+
+static int mxc_isi_capture_open(struct file *file)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct media_pad *source_pad;
+ struct v4l2_subdev *sd;
+ struct device *dev = &mxc_isi->pdev->dev;
+ int ret = -EBUSY;
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s, ISI%d\n", __func__, mxc_isi->id);
+
+
+ /* Get remote source pad */
+ source_pad = mxc_isi_get_remote_source_pad(mxc_isi);
+ if (source_pad == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sd == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&mxc_isi->lock);
+ ret = v4l2_fh_open(file);
+ mutex_unlock(&mxc_isi->lock);
+
+ pm_runtime_get_sync(dev);
+
+ ret = v4l2_subdev_call(sd, core, s_power, 1);
+ if (ret) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, Call subdev s_power fail!\n", __func__);
+ pm_runtime_put(dev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mxc_isi_capture_release(struct file *file)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct media_pad *source_pad;
+ struct v4l2_subdev *sd;
+ struct device *dev = &mxc_isi->pdev->dev;
+ int ret;
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s\n", __func__);
+
+ /* Get remote source pad */
+ source_pad = mxc_isi_get_remote_source_pad(mxc_isi);
+ if (source_pad == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ ret = -EINVAL;
+ goto label;
+ }
+
+ /* Get remote source pad subdev */
+ sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sd == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ ret = -EINVAL;
+ goto label;
+ }
+
+ mutex_lock(&mxc_isi->lock);
+ ret = _vb2_fop_release(file, NULL);
+ if (ret) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s fail\n", __func__);
+ mutex_unlock(&mxc_isi->lock);
+ goto label;
+ }
+ mutex_unlock(&mxc_isi->lock);
+
+ mxc_isi_channel_deinit(mxc_isi);
+
+ ret = v4l2_subdev_call(sd, core, s_power, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s s_power fail\n", __func__);
+ goto label;
+ }
+
+label:
+ pm_runtime_put(dev);
+ return (ret) ? ret : 0;
+}
+
+static const struct v4l2_file_operations mxc_isi_capture_fops = {
+ .owner = THIS_MODULE,
+ .open = mxc_isi_capture_open,
+ .release = mxc_isi_capture_release,
+ .poll = vb2_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vb2_fop_mmap,
+};
+
+/*
+ * Format and crop negotiation helpers
+ */
+
+/*
+ * The video node ioctl operations
+ */
+static int mxc_isi_cap_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+
+ strlcpy(cap->driver, MXC_ISI_DRIVER_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, MXC_ISI_DRIVER_NAME, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s.%d",
+ dev_name(&mxc_isi->pdev->dev), mxc_isi->id);
+
+ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+ return 0;
+}
+
+static int mxc_isi_cap_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct mxc_isi_fmt *fmt;
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s\n", __func__);
+ if (f->index >= (int)ARRAY_SIZE(mxc_isi_out_formats))
+ return -EINVAL;
+
+ fmt = &mxc_isi_out_formats[f->index];
+ if (!fmt)
+ return -EINVAL;
+
+ strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+
+ f->pixelformat = fmt->fourcc;
+
+ return 0;
+}
+
+static int mxc_isi_cap_g_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+ struct mxc_isi_frame *dst_f = &mxc_isi->isi_cap.dst_f;
+ int i;
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s\n", __func__);
+
+ pix->width = dst_f->o_width;
+ pix->height = dst_f->o_height;
+ pix->field = V4L2_FIELD_NONE;
+ pix->pixelformat = dst_f->fmt->fourcc;
+ pix->colorspace = V4L2_COLORSPACE_JPEG;
+ pix->num_planes = dst_f->fmt->memplanes;
+
+ for (i = 0; i < pix->num_planes; ++i) {
+ pix->plane_fmt[i].bytesperline = dst_f->bytesperline[i];
+ pix->plane_fmt[i].sizeimage = dst_f->sizeimage[i];
+ }
+ return 0;
+}
+
+
+static int mxc_isi_cap_try_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+ struct mxc_isi_fmt *fmt;
+ int i;
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s\n", __func__);
+
+ for (i = 0; i < ARRAY_SIZE(mxc_isi_out_formats); i++) {
+ fmt = &mxc_isi_out_formats[i];
+ if (fmt->fourcc == pix->pixelformat)
+ break;
+ }
+ if (i >= ARRAY_SIZE(mxc_isi_out_formats)) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, format is not support!\n", __func__);
+ return -EINVAL;
+ }
+
+ if (pix->width <= 0 || pix->height <= 0) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, width %d, height %d is not valid\n",
+ __func__, pix->width, pix->height);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Update input frame size and formate */
+static int mxc_isi_source_fmt_init(struct mxc_isi_dev *mxc_isi)
+{
+ struct mxc_isi_frame *src_f = &mxc_isi->isi_cap.src_f;
+ struct v4l2_subdev_format src_fmt;
+ struct media_pad *source_pad;
+ struct v4l2_subdev *src_sd;
+ int ret;
+
+ /* Get remote source pad */
+ source_pad = mxc_isi_get_remote_source_pad(mxc_isi);
+ if (source_pad == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ src_sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (src_sd == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ src_fmt.pad = source_pad->index;
+ src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(src_sd, pad, get_fmt, NULL, &src_fmt);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, get remote fmt faile!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Pixel link master will transfer format to RGB32 or YUV32 */
+ src_f->fmt = mxc_isi_get_src_fmt(&src_fmt);
+
+ set_frame_bounds(src_f, src_fmt.format.width, src_fmt.format.height);
+
+ return 0;
+}
+
+static int mxc_isi_cap_s_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+ struct mxc_isi_frame *dst_f = &mxc_isi->isi_cap.dst_f;
+ struct mxc_isi_fmt *fmt;
+ int bpl;
+ int i;
+
+ /* Step1: Check format with output support format list.
+ * Step2: Update output frame information.
+ * Step3: Checkout the format whether is supported by remote subdev
+ * Step3.1: If Yes, call remote subdev set_fmt.
+ * Step3.2: If NO, call remote subdev get_fmt.
+ * Step4: Update input frame information.
+ * Step5: Update mxc isi channel configuration.
+ * */
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s, fmt=0x%X\n", __func__, pix->pixelformat);
+ if (vb2_is_busy(&mxc_isi->isi_cap.vb2_q)) {
+ return -EBUSY;
+ }
+
+ /* Check out put format */
+ for (i = 0; i < ARRAY_SIZE(mxc_isi_out_formats); i++) {
+ fmt = &mxc_isi_out_formats[i];
+ if (pix && fmt->fourcc == pix->pixelformat)
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(mxc_isi_out_formats)) {
+ dev_dbg(&mxc_isi->pdev->dev, "%s, format is not support!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* update out put frame size and formate */
+ if (pix->height <= 0 || pix->width <= 0)
+ return -EINVAL;
+
+ dst_f->fmt = fmt;
+ dst_f->height = pix->height;
+ dst_f->width = pix->width;
+
+ pix->num_planes = fmt->memplanes;
+
+ for (i = 0; i < pix->num_planes; i++) {
+ bpl = pix->plane_fmt[i].bytesperline;
+
+ if ((bpl == 0) || (bpl / (fmt->depth[i] >> 3)) < pix->width)
+ pix->plane_fmt[i].bytesperline =
+ (pix->width * fmt->depth[i]) >> 3;
+
+ if (pix->plane_fmt[i].sizeimage == 0) {
+
+ if ((i == 1) && (pix->pixelformat == V4L2_PIX_FMT_NV12))
+ pix->plane_fmt[i].sizeimage =
+ (pix->width * (pix->height >> 1) * fmt->depth[i] >> 3);
+ else
+ pix->plane_fmt[i].sizeimage = (pix->width * pix->height *
+ fmt->depth[i] >> 3);
+ }
+ }
+
+ if (pix->num_planes > 1) {
+ for (i = 0; i < pix->num_planes; i++) {
+ dst_f->bytesperline[i] = pix->plane_fmt[i].bytesperline;
+ dst_f->sizeimage[i] = pix->plane_fmt[i].sizeimage;
+ }
+ } else {
+ dst_f->bytesperline[0] = dst_f->width * dst_f->fmt->depth[0] / 8;
+ dst_f->sizeimage[0] = dst_f->height * dst_f->bytesperline[0];
+ }
+
+ set_frame_bounds(dst_f, pix->width, pix->height);
+
+ mxc_isi_source_fmt_init(mxc_isi);
+
+ mxc_isi_channel_init(mxc_isi);
+ /* configure mxc isi channel */
+ mxc_isi_channel_config(mxc_isi);
+
+ return 0;
+}
+
+static int mxc_isi_cap_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ int ret;
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s\n", __func__);
+
+ if (mxc_isi->interface[IN_PORT] == ISI_INPUT_INTERFACE_HDMI) {
+ mxc_isi_channel_enable(mxc_isi);
+ ret = vb2_ioctl_streamon(file, priv, type);
+ mxc_isi_pipeline_enable(mxc_isi, 1);
+ } else {
+ mxc_isi_pipeline_enable(mxc_isi, 1);
+ ret = vb2_ioctl_streamon(file, priv, type);
+ mxc_isi_channel_enable(mxc_isi);
+ }
+
+ return ret;
+}
+
+static int mxc_isi_cap_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ int ret;
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s\n", __func__);
+
+ if (mxc_isi->interface[IN_PORT] == ISI_INPUT_INTERFACE_HDMI) {
+ mxc_isi_channel_disable(mxc_isi);
+ ret = vb2_ioctl_streamoff(file, priv, type);
+ mxc_isi_pipeline_enable(mxc_isi, 0);
+ } else {
+ mxc_isi_pipeline_enable(mxc_isi, 0);
+ ret = vb2_ioctl_streamoff(file, priv, type);
+ mxc_isi_channel_disable(mxc_isi);
+ }
+
+ return ret;
+}
+
+static int mxc_isi_cap_g_selection(struct file *file, void *fh,
+ struct v4l2_selection *s)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct mxc_isi_frame *f = &mxc_isi->isi_cap.src_f;
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s\n", __func__);
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ f = &mxc_isi->isi_cap.dst_f;
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = f->o_width;
+ s->r.height = f->o_height;
+ return 0;
+
+ case V4L2_SEL_TGT_COMPOSE:
+ f = &mxc_isi->isi_cap.dst_f;
+ case V4L2_SEL_TGT_CROP:
+ s->r.left = f->h_off;
+ s->r.top = f->v_off;
+ s->r.width = f->width;
+ s->r.height = f->height;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
+{
+ if (a->left < b->left || a->top < b->top)
+ return 0;
+
+ if (a->left + a->width > b->left + b->width)
+ return 0;
+
+ if (a->top + a->height > b->top + b->height)
+ return 0;
+
+ return 1;
+}
+static int mxc_isi_cap_s_selection(struct file *file, void *fh,
+ struct v4l2_selection *s)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct mxc_isi_frame *f;
+ struct v4l2_rect rect = s->r;
+ unsigned long flags;
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s\n", __func__);
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ if (s->target == V4L2_SEL_TGT_COMPOSE)
+ f = &mxc_isi->isi_cap.dst_f;
+ else if (s->target == V4L2_SEL_TGT_CROP)
+ f = &mxc_isi->isi_cap.src_f;
+ else
+ return -EINVAL;
+
+ if (s->flags & V4L2_SEL_FLAG_LE &&
+ !enclosed_rectangle(&rect, &s->r))
+ return -ERANGE;
+
+ if (s->flags & V4L2_SEL_FLAG_GE &&
+ !enclosed_rectangle(&s->r, &rect))
+ return -ERANGE;
+
+ s->r = rect;
+ spin_lock_irqsave(&mxc_isi->slock, flags);
+ set_frame_crop(f, s->r.left, s->r.top, s->r.width,
+ s->r.height);
+ spin_unlock_irqrestore(&mxc_isi->slock, flags);
+
+ return 0;
+}
+
+static int mxc_isi_cap_g_chip_ident(struct file *file, void *fb,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ struct device_node *local, *remote, *endpoint;
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd;
+ struct media_pad *source_pad;
+
+ source_pad = mxc_isi_get_remote_source_pad(mxc_isi);
+ if (source_pad == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sd == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ local = dev_of_node(sd->dev);
+ if (!local) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, Get device node fail\n", __func__);
+ return -ENODEV;
+ }
+
+ endpoint = of_graph_get_endpoint_by_regs(local, -1, -1);
+ if (!endpoint) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No %s endpoint\n",
+ __func__, local->name);
+ return -ENODEV;
+ }
+
+ remote = of_graph_get_remote_port_parent(endpoint);
+ if (!remote) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s No remote port for %s\n",
+ __func__, endpoint->name);
+ return -ENODEV;
+ }
+
+ sprintf(chip->match.name, "imx8_%s_%d", remote->name, vdev->num);
+
+ return 0;
+}
+
+static int mxc_isi_cap_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct v4l2_subdev *sd;
+ struct media_pad *source_pad;
+
+ source_pad = mxc_isi_get_remote_source_pad(mxc_isi);
+ if (source_pad == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sd == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+ return v4l2_subdev_call(sd, video, g_parm, a);
+}
+
+static int mxc_isi_cap_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *a)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct v4l2_subdev *sd;
+ struct media_pad *source_pad;
+
+ source_pad = mxc_isi_get_remote_source_pad(mxc_isi);
+ if (source_pad == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sd == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+ return v4l2_subdev_call(sd, video, s_parm, a);
+}
+
+static int mxc_isi_cap_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct v4l2_subdev *sd;
+ struct mxc_isi_fmt *fmt;
+ struct media_pad *source_pad;
+ struct v4l2_subdev_frame_size_enum fse = {
+ .index = fsize->index,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ int ret;
+
+ fmt = mxc_isi_find_format(&fsize->pixel_format, NULL, 0);
+ if (!fmt || fmt->fourcc != fsize->pixel_format)
+ return -EINVAL;
+ fse.code = fmt->mbus_code;
+
+ source_pad = mxc_isi_get_remote_source_pad(mxc_isi);
+ if (source_pad == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sd == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ if (sd == NULL) {
+ v4l2_err(&mxc_isi->isi_cap.sd, "Can't find subdev\n");
+ return -ENODEV;
+ }
+
+ ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse);
+ if (ret)
+ 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_STEPWISE;
+ 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 mxc_isi_cap_enum_frameintervals(struct file *file, void *fh,
+ struct v4l2_frmivalenum *interval)
+{
+ struct mxc_isi_dev *mxc_isi = video_drvdata(file);
+ struct v4l2_subdev *sd;
+ struct mxc_isi_fmt *fmt;
+ struct media_pad *source_pad;
+ struct v4l2_subdev_frame_interval_enum fie = {
+ .index = interval->index,
+ .width = interval->width,
+ .height = interval->height,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ int ret;
+
+ fmt = mxc_isi_find_format(&interval->pixel_format, NULL, 0);
+ if (!fmt || fmt->fourcc != interval->pixel_format)
+ return -EINVAL;
+ fie.code = fmt->mbus_code;
+
+ source_pad = mxc_isi_get_remote_source_pad(mxc_isi);
+ if (source_pad == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sd == NULL) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = v4l2_subdev_call(sd, pad, enum_frame_interval, NULL, &fie);
+ if (ret)
+ return ret;
+
+ interval->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ interval->discrete = fie.interval;
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops mxc_isi_capture_ioctl_ops = {
+ .vidioc_querycap = mxc_isi_cap_querycap,
+
+ .vidioc_enum_fmt_vid_cap_mplane = mxc_isi_cap_enum_fmt_mplane,
+ .vidioc_try_fmt_vid_cap_mplane = mxc_isi_cap_try_fmt_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = mxc_isi_cap_s_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = mxc_isi_cap_g_fmt_mplane,
+
+ .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_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+
+ .vidioc_streamon = mxc_isi_cap_streamon,
+ .vidioc_streamoff = mxc_isi_cap_streamoff,
+
+ .vidioc_g_selection = mxc_isi_cap_g_selection,
+ .vidioc_s_selection = mxc_isi_cap_s_selection,
+ .vidioc_g_chip_ident = mxc_isi_cap_g_chip_ident,
+
+ .vidioc_g_parm = mxc_isi_cap_g_parm,
+ .vidioc_s_parm = mxc_isi_cap_s_parm,
+
+ .vidioc_enum_framesizes = mxc_isi_cap_enum_framesizes,
+ .vidioc_enum_frameintervals = mxc_isi_cap_enum_frameintervals,
+};
+
+/* Capture subdev media entity operations */
+static int mxc_isi_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct mxc_isi_dev *mxc_isi = v4l2_get_subdevdata(sd);
+
+ if (WARN_ON(mxc_isi == NULL))
+ return 0;
+
+ if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+ return 0;
+ }
+ /* TODO */
+ /* Add ISI source and sink pad link configuration */
+ if (local->flags & MEDIA_PAD_FL_SOURCE) {
+ switch (local->index) {
+ case MXC_ISI_SD_PAD_SOURCE_DC0:
+ case MXC_ISI_SD_PAD_SOURCE_DC1:
+ break;
+ case MXC_ISI_SD_PAD_SOURCE_MEM:
+ break;
+ default:
+ dev_err(&mxc_isi->pdev->dev, "%s invalid source pad\n", __func__);
+ return -EINVAL;
+ }
+ } else if (local->flags & MEDIA_PAD_FL_SINK) {
+ switch (local->index) {
+ case MXC_ISI_SD_PAD_SINK_MIPI0_VC0:
+ case MXC_ISI_SD_PAD_SINK_MIPI0_VC1:
+ case MXC_ISI_SD_PAD_SINK_MIPI0_VC2:
+ case MXC_ISI_SD_PAD_SINK_MIPI0_VC3:
+ case MXC_ISI_SD_PAD_SINK_MIPI1_VC0:
+ case MXC_ISI_SD_PAD_SINK_MIPI1_VC1:
+ case MXC_ISI_SD_PAD_SINK_MIPI1_VC2:
+ case MXC_ISI_SD_PAD_SINK_MIPI1_VC3:
+ case MXC_ISI_SD_PAD_SINK_HDMI:
+ case MXC_ISI_SD_PAD_SINK_DC0:
+ case MXC_ISI_SD_PAD_SINK_DC1:
+ case MXC_ISI_SD_PAD_SINK_MEM:
+ case MXC_ISI_SD_PAD_SINK_PARALLEL_CSI:
+ break;
+ default:
+ dev_err(&mxc_isi->pdev->dev, "%s invalid sink pad\n", __func__);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static const struct media_entity_operations mxc_isi_sd_media_ops = {
+ .link_setup = mxc_isi_link_setup,
+};
+
+static int mxc_isi_subdev_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ return 0;
+}
+
+static int mxc_isi_subdev_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct mxc_isi_dev *mxc_isi = v4l2_get_subdevdata(sd);
+ struct mxc_isi_frame *f;
+ struct v4l2_mbus_framefmt *mf;
+
+ mutex_lock(&mxc_isi->lock);
+
+ switch (fmt->pad) {
+ case MXC_ISI_SD_PAD_SOURCE_MEM:
+ case MXC_ISI_SD_PAD_SOURCE_DC0:
+ case MXC_ISI_SD_PAD_SOURCE_DC1:
+ f = &mxc_isi->isi_cap.dst_f;
+ break;
+ case MXC_ISI_SD_PAD_SINK_MIPI0_VC0:
+ case MXC_ISI_SD_PAD_SINK_MIPI0_VC1:
+ case MXC_ISI_SD_PAD_SINK_MIPI0_VC2:
+ case MXC_ISI_SD_PAD_SINK_MIPI0_VC3:
+ case MXC_ISI_SD_PAD_SINK_MIPI1_VC0:
+ case MXC_ISI_SD_PAD_SINK_MIPI1_VC1:
+ case MXC_ISI_SD_PAD_SINK_MIPI1_VC2:
+ case MXC_ISI_SD_PAD_SINK_MIPI1_VC3:
+ case MXC_ISI_SD_PAD_SINK_HDMI:
+ case MXC_ISI_SD_PAD_SINK_DC0:
+ case MXC_ISI_SD_PAD_SINK_DC1:
+ case MXC_ISI_SD_PAD_SINK_MEM:
+ f = &mxc_isi->isi_cap.src_f;
+ break;
+ default:
+ mutex_unlock(&mxc_isi->lock);
+ v4l2_err(mxc_isi->v4l2_dev, "%s, Pad is not support now!\n", __func__);
+ return -1;
+ }
+
+ if (!WARN_ON(f->fmt == NULL))
+ mf->code = f->fmt->mbus_code;
+
+ /* Source/Sink pads crop rectangle size */
+ mf->width = f->width;
+ mf->height = f->height;
+
+ mutex_unlock(&mxc_isi->lock);
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+ return 0;
+}
+
+static int mxc_isi_subdev_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct mxc_isi_dev *mxc_isi = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *mf = &fmt->format;
+ struct mxc_isi_frame *dst_f = &mxc_isi->isi_cap.dst_f;
+ struct mxc_isi_fmt *out_fmt;
+ int i;
+
+ if (fmt->pad < MXC_ISI_SD_PAD_SOURCE_MEM &&
+ vb2_is_busy(&mxc_isi->isi_cap.vb2_q))
+ return -EBUSY;
+
+ for (i = 0; i < ARRAY_SIZE(mxc_isi_out_formats); i++) {
+ out_fmt = &mxc_isi_out_formats[i];
+ if (mf->code == out_fmt->mbus_code)
+ break;
+ }
+ if (i >= ARRAY_SIZE(mxc_isi_out_formats)) {
+ v4l2_err(mxc_isi->v4l2_dev, "%s, format is not support!\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&mxc_isi->lock);
+ /* update out put frame size and formate */
+ dst_f->fmt = &mxc_isi_out_formats[i];
+ set_frame_bounds(dst_f, mf->width, mf->height);
+ mutex_unlock(&mxc_isi->lock);
+
+ dev_dbg(&mxc_isi->pdev->dev, "pad%d: code: 0x%x, %dx%d",
+ fmt->pad, mf->code, mf->width, mf->height);
+
+ return 0;
+}
+
+static int mxc_isi_subdev_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ struct mxc_isi_dev *mxc_isi = v4l2_get_subdevdata(sd);
+ struct mxc_isi_frame *f = &mxc_isi->isi_cap.src_f;
+ struct v4l2_rect *r = &sel->r;
+ struct v4l2_rect *try_sel;
+
+ mutex_lock(&mxc_isi->lock);
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ f = &mxc_isi->isi_cap.dst_f;
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ r->width = f->o_width;
+ r->height = f->o_height;
+ r->left = 0;
+ r->top = 0;
+ mutex_unlock(&mxc_isi->lock);
+ return 0;
+
+ case V4L2_SEL_TGT_CROP:
+ try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+ break;
+ case V4L2_SEL_TGT_COMPOSE:
+ try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
+ f = &mxc_isi->isi_cap.dst_f;
+ break;
+ default:
+ mutex_unlock(&mxc_isi->lock);
+ return -EINVAL;
+ }
+
+ if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+ sel->r = *try_sel;
+ } else {
+ r->left = f->h_off;
+ r->top = f->v_off;
+ r->width = f->width;
+ r->height = f->height;
+ }
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s, target %#x: l:%d, t:%d, %dx%d, f_w: %d, f_h: %d",
+ __func__, sel->pad, r->left, r->top, r->width, r->height,
+ f->c_width, f->c_height);
+
+ mutex_unlock(&mxc_isi->lock);
+ return 0;
+}
+
+static int mxc_isi_subdev_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ struct mxc_isi_dev *mxc_isi = v4l2_get_subdevdata(sd);
+ struct mxc_isi_frame *f = &mxc_isi->isi_cap.src_f;
+ struct v4l2_rect *r = &sel->r;
+ struct v4l2_rect *try_sel;
+ unsigned long flags;
+
+ mutex_lock(&mxc_isi->lock);
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad);
+ break;
+ case V4L2_SEL_TGT_COMPOSE:
+ try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad);
+ f = &mxc_isi->isi_cap.dst_f;
+ break;
+ default:
+ mutex_unlock(&mxc_isi->lock);
+ return -EINVAL;
+ }
+
+ if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+ *try_sel = sel->r;
+ } else {
+ spin_lock_irqsave(&mxc_isi->slock, flags);
+ set_frame_crop(f, r->left, r->top, r->width, r->height);
+ spin_unlock_irqrestore(&mxc_isi->slock, flags);
+ }
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s, target %#x: (%d,%d)/%dx%d", __func__,
+ sel->target, r->left, r->top, r->width, r->height);
+
+ mutex_unlock(&mxc_isi->lock);
+
+ return 0;
+}
+
+static struct v4l2_subdev_pad_ops mxc_isi_subdev_pad_ops = {
+ .enum_mbus_code = mxc_isi_subdev_enum_mbus_code,
+ .get_selection = mxc_isi_subdev_get_selection,
+ .set_selection = mxc_isi_subdev_set_selection,
+ .get_fmt = mxc_isi_subdev_get_fmt,
+ .set_fmt = mxc_isi_subdev_set_fmt,
+};
+
+static struct v4l2_subdev_ops mxc_isi_subdev_ops = {
+ .pad = &mxc_isi_subdev_pad_ops,
+};
+
+static int mxc_isi_register_cap_device(struct mxc_isi_dev *mxc_isi,
+ struct v4l2_device *v4l2_dev)
+{
+ struct video_device *vdev = &mxc_isi->isi_cap.vdev;
+ struct vb2_queue *q = &mxc_isi->isi_cap.vb2_q;
+ struct mxc_isi_cap_dev *isi_cap = &mxc_isi->isi_cap;
+ int ret = -ENOMEM;
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s\n", __func__);
+ memset(vdev, 0, sizeof(*vdev));
+ snprintf(vdev->name, sizeof(vdev->name), "mxc_isi.%d.capture", mxc_isi->id);
+
+ vdev->fops = &mxc_isi_capture_fops;
+ vdev->ioctl_ops = &mxc_isi_capture_ioctl_ops;
+ vdev->v4l2_dev = v4l2_dev;
+ vdev->minor = -1;
+ vdev->release = video_device_release_empty;
+ vdev->queue = q;
+ vdev->lock = &mxc_isi->lock;
+
+ video_set_drvdata(vdev, mxc_isi);
+
+ INIT_LIST_HEAD(&mxc_isi->isi_cap.out_pending);
+ INIT_LIST_HEAD(&mxc_isi->isi_cap.out_active);
+
+ memset(q, 0, sizeof(*q));
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ q->drv_priv = mxc_isi;
+ q->ops = &mxc_cap_vb2_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->buf_struct_size = sizeof(struct mxc_isi_buffer);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &mxc_isi->lock;
+
+ ret = vb2_queue_init(q);
+ if (ret)
+ goto err_free_ctx;
+
+ /* Default configuration */
+ isi_cap->dst_f.width = 1280;
+ isi_cap->dst_f.height = 800;
+ isi_cap->dst_f.fmt = &mxc_isi_out_formats[0];;
+ isi_cap->src_f.fmt = isi_cap->dst_f.fmt;
+
+ isi_cap->cap_pad.flags = MEDIA_PAD_FL_SINK;
+ vdev->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
+ ret = media_entity_pads_init(&vdev->entity, 1, &isi_cap->cap_pad);
+ if (ret)
+ goto err_free_ctx;
+
+ ret = mxc_isi_ctrls_create(mxc_isi);
+ if (ret)
+ goto err_me_cleanup;
+
+ ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+ if (ret)
+ goto err_ctrl_free;
+
+ vdev->ctrl_handler = &mxc_isi->ctrls.handler;
+ v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
+ vdev->name, video_device_node_name(vdev));
+
+ return 0;
+
+err_ctrl_free:
+ mxc_isi_ctrls_delete(mxc_isi);
+err_me_cleanup:
+ media_entity_cleanup(&vdev->entity);
+err_free_ctx:
+ return ret;
+}
+
+static int mxc_isi_capture_subdev_registered(struct v4l2_subdev *sd)
+{
+ struct mxc_isi_dev *mxc_isi = v4l2_get_subdevdata(sd);
+ int ret;
+
+ if (mxc_isi == NULL)
+ return -ENXIO;
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s\n", __func__);
+#if 0
+ if (mxc_isi->id == 0) {
+ /* ISI channel 0 support source input image from memory */
+ ret = mxc_isi_register_m2m_device(mxc_isi, sd->v4l2_dev);
+ if (ret < 0)
+ return ret;
+ }
+#endif
+
+ ret = mxc_isi_register_cap_device(mxc_isi, sd->v4l2_dev);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static void mxc_isi_capture_subdev_unregistered(struct v4l2_subdev *sd)
+{
+ struct mxc_isi_dev *mxc_isi = v4l2_get_subdevdata(sd);
+ struct video_device *vdev;
+
+ if (mxc_isi == NULL)
+ return;
+
+ dev_dbg(&mxc_isi->pdev->dev, "%s\n", __func__);
+ mutex_lock(&mxc_isi->lock);
+
+ vdev = &mxc_isi->isi_cap.vdev;
+ if (video_is_registered(vdev)) {
+ video_unregister_device(vdev);
+ mxc_isi_ctrls_delete(mxc_isi);
+ media_entity_cleanup(&vdev->entity);
+ }
+
+ mutex_unlock(&mxc_isi->lock);
+}
+
+static const struct v4l2_subdev_internal_ops mxc_isi_capture_sd_internal_ops = {
+ .registered = mxc_isi_capture_subdev_registered,
+ .unregistered = mxc_isi_capture_subdev_unregistered,
+};
+
+int mxc_isi_initialize_capture_subdev(struct mxc_isi_dev *mxc_isi)
+{
+ struct v4l2_subdev *sd = &mxc_isi->isi_cap.sd;
+ int ret;
+
+ v4l2_subdev_init(sd, &mxc_isi_subdev_ops);
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(sd->name, sizeof(sd->name), "mxc_isi.%d", mxc_isi->id);
+
+ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
+
+ /* ISI Sink pads */
+ mxc_isi->isi_cap.sd_pads[MXC_ISI_SD_PAD_SINK_MIPI0_VC0].flags = MEDIA_PAD_FL_SINK;
+ mxc_isi->isi_cap.sd_pads[MXC_ISI_SD_PAD_SINK_MIPI0_VC1].flags = MEDIA_PAD_FL_SINK;
+ mxc_isi->isi_cap.sd_pads[MXC_ISI_SD_PAD_SINK_MIPI0_VC2].flags = MEDIA_PAD_FL_SINK;
+ mxc_isi->isi_cap.sd_pads[MXC_ISI_SD_PAD_SINK_MIPI0_VC3].flags = MEDIA_PAD_FL_SINK;
+ mxc_isi->isi_cap.sd_pads[MXC_ISI_SD_PAD_SINK_MIPI1_VC0].flags = MEDIA_PAD_FL_SINK;
+ mxc_isi->isi_cap.sd_pads[MXC_ISI_SD_PAD_SINK_MIPI1_VC1].flags = MEDIA_PAD_FL_SINK;
+ mxc_isi->isi_cap.sd_pads[MXC_ISI_SD_PAD_SINK_MIPI1_VC2].flags = MEDIA_PAD_FL_SINK;
+ mxc_isi->isi_cap.sd_pads[MXC_ISI_SD_PAD_SINK_MIPI1_VC3].flags = MEDIA_PAD_FL_SINK;
+ mxc_isi->isi_cap.sd_pads[MXC_ISI_SD_PAD_SINK_DC0].flags = MEDIA_PAD_FL_SINK;
+ mxc_isi->isi_cap.sd_pads[MXC_ISI_SD_PAD_SINK_DC1].flags = MEDIA_PAD_FL_SINK;
+ mxc_isi->isi_cap.sd_pads[MXC_ISI_SD_PAD_SINK_HDMI].flags = MEDIA_PAD_FL_SINK;
+ mxc_isi->isi_cap.sd_pads[MXC_ISI_SD_PAD_SINK_MEM].flags = MEDIA_PAD_FL_SINK;
+ mxc_isi->isi_cap.sd_pads[MXC_ISI_SD_PAD_SINK_PARALLEL_CSI].flags = MEDIA_PAD_FL_SINK;
+
+ /* ISI source pads */
+ mxc_isi->isi_cap.sd_pads[MXC_ISI_SD_PAD_SOURCE_MEM].flags = MEDIA_PAD_FL_SOURCE;
+ mxc_isi->isi_cap.sd_pads[MXC_ISI_SD_PAD_SOURCE_DC0].flags = MEDIA_PAD_FL_SOURCE;
+ mxc_isi->isi_cap.sd_pads[MXC_ISI_SD_PAD_SOURCE_DC1].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&sd->entity, MXC_ISI_SD_PADS_NUM,
+ mxc_isi->isi_cap.sd_pads);
+ if (ret)
+ return ret;
+
+ sd->entity.ops = &mxc_isi_sd_media_ops;
+ sd->internal_ops = &mxc_isi_capture_sd_internal_ops;
+ v4l2_set_subdevdata(sd, mxc_isi);
+
+ return 0;
+}
+
+void mxc_isi_unregister_capture_subdev(struct mxc_isi_dev *mxc_isi)
+{
+ struct v4l2_subdev *sd = &mxc_isi->isi_cap.sd;
+
+ v4l2_device_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_set_subdevdata(sd, NULL);
+}
diff --git a/drivers/media/platform/imx8/mxc-isi-core.c b/drivers/media/platform/imx8/mxc-isi-core.c
new file mode 100644
index 000000000000..b72eadd093f0
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-isi-core.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2017-2018 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include "mxc-media-dev.h"
+
+static irqreturn_t mxc_isi_irq_handler(int irq, void *priv)
+{
+ struct mxc_isi_dev *mxc_isi = priv;
+ struct device *dev = &mxc_isi->pdev->dev;
+ u32 status;
+
+ spin_lock(&mxc_isi->slock);
+
+ status = mxc_isi_get_irq_status(mxc_isi);
+ mxc_isi_clean_irq_status(mxc_isi, status);
+
+ if (status & CHNL_STS_FRM_STRD_MASK)
+ mxc_isi_frame_write_done(mxc_isi);
+
+ if (status & (CHNL_STS_AXI_WR_ERR_Y_MASK |
+ CHNL_STS_AXI_WR_ERR_U_MASK |
+ CHNL_STS_AXI_WR_ERR_V_MASK))
+ dev_dbg(dev, "%s, IRQ AXI Error stat=0x%X\n", __func__, status);
+ if (status & (CHNL_STS_OFLW_PANIC_Y_BUF_MASK |
+ CHNL_STS_OFLW_PANIC_U_BUF_MASK |
+ CHNL_STS_OFLW_PANIC_V_BUF_MASK))
+ dev_dbg(dev, "%s, IRQ Panic OFLW Error stat=0x%X\n", __func__, status);
+ if (status & (CHNL_STS_OFLW_Y_BUF_MASK |
+ CHNL_STS_OFLW_U_BUF_MASK |
+ CHNL_STS_OFLW_V_BUF_MASK))
+ dev_dbg(dev, "%s, IRQ OFLW Error stat=0x%X\n", __func__, status);
+ if (status & (CHNL_STS_EXCS_OFLW_Y_BUF_MASK |
+ CHNL_STS_EXCS_OFLW_U_BUF_MASK |
+ CHNL_STS_EXCS_OFLW_V_BUF_MASK))
+ dev_dbg(dev, "%s, IRQ EXCS OFLW Error stat=0x%X\n", __func__, status);
+
+ spin_unlock(&mxc_isi->slock);
+ return IRQ_HANDLED;
+}
+
+/**
+ * mxc_isi_adjust_mplane_format - adjust bytesperline or sizeimage
+ */
+void mxc_isi_adjust_mplane_format(struct mxc_isi_fmt *fmt, u32 width, u32 height,
+ struct v4l2_pix_format_mplane *pix)
+{
+ u32 bytesperline = 0;
+ int i;
+
+ pix->colorspace = V4L2_COLORSPACE_JPEG;
+ pix->field = V4L2_FIELD_NONE;
+ pix->num_planes = fmt->memplanes;
+ pix->pixelformat = fmt->fourcc;
+ pix->height = height;
+ pix->width = width;
+
+ for (i = 0; i < pix->num_planes; ++i) {
+ struct v4l2_plane_pix_format *plane_fmt = &pix->plane_fmt[i];
+ u32 bpl = plane_fmt->bytesperline;
+
+ if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width))
+ bpl = pix->width; /* Planar */
+
+ if (fmt->colplanes == 1 && /* Packed */
+ (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width))
+ bpl = (pix->width * fmt->depth[0]) / 8;
+
+ if (i == 0)
+ bytesperline = bpl;
+ else if (i == 1 && fmt->memplanes == 3)
+ bytesperline /= 2;
+
+ plane_fmt->bytesperline = bytesperline;
+ plane_fmt->sizeimage = max((pix->width * pix->height *
+ fmt->depth[i]) / 8, plane_fmt->sizeimage);
+ }
+}
+
+static int mxc_isi_parse_dt(struct mxc_isi_dev *mxc_isi)
+{
+ struct device *dev = &mxc_isi->pdev->dev;
+ struct device_node *node = dev->of_node;
+ int ret = 0;
+
+ mxc_isi->id = of_alias_get_id(node, "isi");
+
+ ret = of_property_read_u32_array(node, "interface",
+ mxc_isi->interface, 3);
+ if (ret < 0)
+ return ret;
+
+ mxc_isi->parallel_csi = of_property_read_bool(node, "parallel_csi");
+
+ dev_dbg(dev, "%s, isi_%d,interface(%d, %d, %d)\n", __func__, mxc_isi->id,
+ mxc_isi->interface[0], mxc_isi->interface[1], mxc_isi->interface[2]);
+
+ mxc_isi->chain_buf = of_property_read_bool(node, "fsl,chain_buf");
+ return 0;
+}
+
+static int mxc_isi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mxc_isi_dev *mxc_isi;
+ struct resource *res;
+ int ret = 0;
+
+ mxc_isi = devm_kzalloc(dev, sizeof(*mxc_isi), GFP_KERNEL);
+ if (!mxc_isi)
+ return -ENOMEM;
+
+ mxc_isi->pdev = pdev;
+
+ ret = mxc_isi_parse_dt(mxc_isi);
+ if (ret < 0)
+ return ret;
+
+ if (mxc_isi->id >= MXC_ISI_MAX_DEVS || mxc_isi->id < 0) {
+ dev_err(dev, "Invalid driver data or device id (%d)\n",
+ mxc_isi->id);
+ return -EINVAL;
+ }
+
+ init_waitqueue_head(&mxc_isi->irq_queue);
+ spin_lock_init(&mxc_isi->slock);
+ mutex_init(&mxc_isi->lock);
+
+ mxc_isi->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(mxc_isi->clk)) {
+ dev_err(dev, "failed to get isi clk\n");
+ return PTR_ERR(mxc_isi->clk);
+ }
+ ret = clk_prepare(mxc_isi->clk);
+ if (ret < 0) {
+ dev_err(dev, "%s, prepare clk error\n", __func__);
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mxc_isi->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(mxc_isi->regs)) {
+ dev_err(dev, "Failed to get ISI register map\n");
+ return PTR_ERR(mxc_isi->regs);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(dev, "Failed to get IRQ resource\n");
+ return -ENXIO;
+ }
+
+ ret = devm_request_irq(dev, res->start, mxc_isi_irq_handler,
+ 0, dev_name(dev), mxc_isi);
+ if (ret < 0) {
+ dev_err(dev, "failed to install irq (%d)\n", ret);
+ return -EINVAL;
+ }
+
+ ret = mxc_isi_initialize_capture_subdev(mxc_isi);
+ if (ret < 0) {
+ dev_err(dev, "failed to init cap subdev (%d)\n", ret);
+ return -EINVAL;
+ }
+
+ platform_set_drvdata(pdev, mxc_isi);
+
+ ret = clk_enable(mxc_isi->clk);
+ if (ret < 0) {
+ dev_err(dev, "%s, enable clk error\n", __func__);
+ goto err_sclk;
+ }
+
+ mxc_isi_channel_set_chain_buf(mxc_isi);
+ clk_disable_unprepare(mxc_isi->clk);
+
+ pm_runtime_enable(dev);
+
+ dev_dbg(dev, "mxc_isi.%d registered successfully\n", mxc_isi->id);
+
+ return 0;
+
+err_sclk:
+ mxc_isi_unregister_capture_subdev(mxc_isi);
+ return ret;
+}
+
+static int mxc_isi_remove(struct platform_device *pdev)
+{
+ struct mxc_isi_dev *mxc_isi = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+
+ mxc_isi_unregister_capture_subdev(mxc_isi);
+ pm_runtime_disable(dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mxc_isi_pm_suspend(struct device *dev)
+{
+ return pm_runtime_force_suspend(dev);
+}
+
+static int mxc_isi_pm_resume(struct device *dev)
+{
+ return pm_runtime_force_resume(dev);
+}
+#endif
+
+static int mxc_isi_runtime_suspend(struct device *dev)
+{
+ struct mxc_isi_dev *mxc_isi = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(mxc_isi->clk);
+ return 0;
+}
+
+static int mxc_isi_runtime_resume(struct device *dev)
+{
+ struct mxc_isi_dev *mxc_isi = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(mxc_isi->clk);
+ if (ret)
+ dev_err(dev, "%s clk enable fail\n", __func__);
+
+ return (ret) ? ret : 0;
+}
+
+static const struct dev_pm_ops mxc_isi_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mxc_isi_pm_suspend, mxc_isi_pm_resume)
+ SET_RUNTIME_PM_OPS(mxc_isi_runtime_suspend, mxc_isi_runtime_resume, NULL)
+};
+
+static const struct of_device_id mxc_isi_of_match[] = {
+ {.compatible = "fsl,imx8-isi",},
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mxc_isi_of_match);
+
+static struct platform_driver mxc_isi_driver = {
+ .probe = mxc_isi_probe,
+ .remove = mxc_isi_remove,
+ .driver = {
+ .of_match_table = mxc_isi_of_match,
+ .name = MXC_ISI_DRIVER_NAME,
+ .pm = &mxc_isi_pm_ops,
+ }
+};
+
+module_platform_driver(mxc_isi_driver);
diff --git a/drivers/media/platform/imx8/mxc-isi-core.h b/drivers/media/platform/imx8/mxc-isi-core.h
new file mode 100644
index 000000000000..ebb1e0927647
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-isi-core.h
@@ -0,0 +1,324 @@
+/*
+ * Copyright 2017-2018 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef MXC_ISI_CORE_H_
+#define MXC_ISI_CORE_H_
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define MXC_ISI_DRIVER_NAME "mxc-isi"
+#define MXC_ISI_MAX_DEVS 8
+
+#define ISI_OF_NODE_NAME "isi"
+
+#define MXC_ISI_SD_PAD_SINK_MIPI0_VC0 0
+#define MXC_ISI_SD_PAD_SINK_MIPI0_VC1 1
+#define MXC_ISI_SD_PAD_SINK_MIPI0_VC2 2
+#define MXC_ISI_SD_PAD_SINK_MIPI0_VC3 3
+#define MXC_ISI_SD_PAD_SINK_MIPI1_VC0 4
+#define MXC_ISI_SD_PAD_SINK_MIPI1_VC1 5
+#define MXC_ISI_SD_PAD_SINK_MIPI1_VC2 6
+#define MXC_ISI_SD_PAD_SINK_MIPI1_VC3 7
+#if 0
+#define MXC_ISI_SD_PAD_SINK_MIPI_CSI0 0
+#define MXC_ISI_SD_PAD_SINK_MIPI_CSI1 1
+#endif
+#define MXC_ISI_SD_PAD_SINK_DC0 8
+#define MXC_ISI_SD_PAD_SINK_DC1 9
+#define MXC_ISI_SD_PAD_SINK_HDMI 10
+#define MXC_ISI_SD_PAD_SINK_MEM 11
+#define MXC_ISI_SD_PAD_SOURCE_MEM 12
+#define MXC_ISI_SD_PAD_SOURCE_DC0 13
+#define MXC_ISI_SD_PAD_SOURCE_DC1 14
+#define MXC_ISI_SD_PAD_SINK_PARALLEL_CSI 15
+#define MXC_ISI_SD_PADS_NUM 16
+
+#define MXC_MAX_PLANES 3
+
+enum isi_input_interface {
+ ISI_INPUT_INTERFACE_DC0 = 0,
+ ISI_INPUT_INTERFACE_DC1,
+ ISI_INPUT_INTERFACE_MIPI0_CSI2,
+ ISI_INPUT_INTERFACE_MIPI1_CSI2,
+ ISI_INPUT_INTERFACE_HDMI,
+ ISI_INPUT_INTERFACE_MEM,
+ ISI_INPUT_INTERFACE_PARALLEL_CSI,
+ ISI_INPUT_INTERFACE_MAX,
+};
+
+enum isi_input_sub_interface {
+ ISI_INPUT_SUB_INTERFACE_VC0 = 0,
+ ISI_INPUT_SUB_INTERFACE_VC1,
+ ISI_INPUT_SUB_INTERFACE_VC2,
+ ISI_INPUT_SUB_INTERFACE_VC3,
+};
+
+enum isi_output_interface {
+ ISI_OUTPUT_INTERFACE_DC0 = 0,
+ ISI_OUTPUT_INTERFACE_DC1,
+ ISI_OUTPUT_INTERFACE_MEM,
+ ISI_OUTPUT_INTERFACE_MAX,
+};
+
+enum {
+ IN_PORT,
+ SUB_IN_PORT,
+ OUT_PORT,
+ MAX_PORTS,
+};
+
+enum mxc_isi_out_fmt {
+ MXC_ISI_OUT_FMT_RGBA32 = 0x0,
+ MXC_ISI_OUT_FMT_ABGR32,
+ MXC_ISI_OUT_FMT_ARGB32,
+ MXC_ISI_OUT_FMT_RGBX32,
+ MXC_ISI_OUT_FMT_XBGR32,
+ MXC_ISI_OUT_FMT_XRGB32,
+ MXC_ISI_OUT_FMT_RGB32P,
+ MXC_ISI_OUT_FMT_BGR32P,
+ MXC_ISI_OUT_FMT_A2BGR10,
+ MXC_ISI_OUT_FMT_A2RGB10,
+ MXC_ISI_OUT_FMT_RGB565,
+ MXC_ISI_OUT_FMT_RAW8,
+ MXC_ISI_OUT_FMT_RAW10,
+ MXC_ISI_OUT_FMT_RAW10P,
+ MXC_ISI_OUT_FMT_RAW12,
+ MXC_ISI_OUT_FMT_RAW16,
+ MXC_ISI_OUT_FMT_YUV444_1P8P,
+ MXC_ISI_OUT_FMT_YUV444_2P8P,
+ MXC_ISI_OUT_FMT_YUV444_3P8P,
+ MXC_ISI_OUT_FMT_YUV444_1P8,
+ MXC_ISI_OUT_FMT_YUV444_1P10,
+ MXC_ISI_OUT_FMT_YUV444_2P10,
+ MXC_ISI_OUT_FMT_YUV444_3P10,
+ MXC_ISI_OUT_FMT_YUV444_1P10P = 0x18,
+ MXC_ISI_OUT_FMT_YUV444_2P10P,
+ MXC_ISI_OUT_FMT_YUV444_3P10P,
+ MXC_ISI_OUT_FMT_YUV444_1P12 = 0x1C,
+ MXC_ISI_OUT_FMT_YUV444_2P12,
+ MXC_ISI_OUT_FMT_YUV444_3P12,
+ MXC_ISI_OUT_FMT_YUV422_1P8P = 0x20,
+ MXC_ISI_OUT_FMT_YUV422_2P8P,
+ MXC_ISI_OUT_FMT_YUV422_3P8P,
+ MXC_ISI_OUT_FMT_YUV422_1P10 = 0x24,
+ MXC_ISI_OUT_FMT_YUV422_2P10,
+ MXC_ISI_OUT_FMT_YUV422_3P10,
+ MXC_ISI_OUT_FMT_YUV422_1P10P = 0x28,
+ MXC_ISI_OUT_FMT_YUV422_2P10P,
+ MXC_ISI_OUT_FMT_YUV422_3P10P,
+ MXC_ISI_OUT_FMT_YUV422_1P12 = 0x2C,
+ MXC_ISI_OUT_FMT_YUV422_2P12,
+ MXC_ISI_OUT_FMT_YUV422_3P12,
+ MXC_ISI_OUT_FMT_YUV420_2P8P = 0x31,
+ MXC_ISI_OUT_FMT_YUV420_3P8P,
+ MXC_ISI_OUT_FMT_YUV420_2P10 = 0x35,
+ MXC_ISI_OUT_FMT_YUV420_3P10,
+ MXC_ISI_OUT_FMT_YUV420_2P10P = 0x39,
+ MXC_ISI_OUT_FMT_YUV420_3P10P,
+ MXC_ISI_OUT_FMT_YUV420_2P12 = 0x3D,
+ MXC_ISI_OUT_FMT_YUV420_3P12,
+};
+
+enum mxc_isi_in_fmt {
+ MXC_ISI_IN_FMT_BGR8P = 0x0,
+};
+
+enum mxc_isi_m2m_in_fmt {
+ MXC_ISI_M2M_IN_FMT_BGR8P = 0x0,
+ MXC_ISI_M2M_IN_FMT_RGB8P,
+ MXC_ISI_M2M_IN_FMT_XRGB8,
+ MXC_ISI_M2M_IN_FMT_RGBX8,
+ MXC_ISI_M2M_IN_FMT_XBGR8,
+ MXC_ISI_M2M_IN_FMT_RGB565,
+ MXC_ISI_M2M_IN_FMT_A2BGR10,
+ MXC_ISI_M2M_IN_FMT_A2RGB10,
+ MXC_ISI_M2M_IN_FMT_YUV444_1P8P,
+ MXC_ISI_M2M_IN_FMT_YUV444_1P10,
+ MXC_ISI_M2M_IN_FMT_YUV444_1P10P,
+ MXC_ISI_M2M_IN_FMT_YUV444_1P12,
+ MXC_ISI_M2M_IN_FMT_YUV444_1P8,
+ MXC_ISI_M2M_IN_FMT_YUV422_1P8P,
+ MXC_ISI_M2M_IN_FMT_YUV422_1P10,
+ MXC_ISI_M2M_IN_FMT_YUV422_1P10P,
+};
+
+struct mxc_isi_fmt {
+ char *name;
+ u32 mbus_code;
+ u32 fourcc;
+ u32 color;
+ u16 memplanes;
+ u16 colplanes;
+ u8 colorspace;
+ u8 depth[MXC_MAX_PLANES];
+ u16 mdataplanes;
+ u16 flags;
+};
+
+struct mxc_isi_ctrls {
+ struct v4l2_ctrl_handler handler;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *alpha;
+ bool ready;
+};
+
+/**
+ * struct addr - physical address set for DMA
+ * @y: luminance plane physical address
+ * @cb: Cb plane physical address
+ * @cr: Cr plane physical address
+ */
+struct frame_addr {
+ u32 y;
+ u32 cb;
+ u32 cr;
+};
+
+/**
+ * struct mxc_isi_frame - source/target frame properties
+ * o_width: original image width from sensor
+ * o_height: original image height from sensor
+ * c_width: crop image width set by g_selection
+ * c_height: crop image height set by g_selection
+ * h_off: crop horizontal pixel offset
+ * v_off: crop vertical pixel offset
+ * width: out image pixel width
+ * height: out image pixel weight
+ * bytesperline: bytesperline value for each plane
+ * paddr: image frame buffer physical addresses
+ * fmt: color format pointer
+ */
+struct mxc_isi_frame {
+ u32 o_width;
+ u32 o_height;
+ u32 c_width;
+ u32 c_height;
+ u32 h_off;
+ u32 v_off;
+ u32 width;
+ u32 height;
+ unsigned int sizeimage[MXC_MAX_PLANES];
+ unsigned int bytesperline[MXC_MAX_PLANES];
+ struct mxc_isi_fmt *fmt;
+};
+
+struct mxc_isi_roi_alpha {
+ u8 alpha;
+ struct v4l2_rect rect;
+};
+
+struct mxc_isi_buffer {
+ struct vb2_v4l2_buffer v4l2_buf;
+ struct list_head list;
+ struct frame_addr paddr;
+};
+
+struct mxc_isi_m2m_dev {
+ struct video_device vdev;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct v4l2_fh fh;
+
+ struct mxc_isi_frame src_f;
+ struct mxc_isi_frame dst_f;
+};
+
+struct mxc_isi_cap_dev {
+ struct v4l2_subdev sd;
+ struct video_device vdev;
+ struct v4l2_fh fh;
+ struct media_pad cap_pad;
+ struct media_pad sd_pads[MXC_ISI_SD_PADS_NUM];
+ struct vb2_queue vb2_q;
+ struct list_head out_pending;
+ struct list_head out_active;
+
+ struct mxc_isi_frame src_f;
+ struct mxc_isi_frame dst_f;
+ u32 frame_count;
+
+ u32 buf_index;
+
+};
+
+struct mxc_isi_dev {
+ spinlock_t slock;
+ struct mutex lock;
+ wait_queue_head_t irq_queue;
+
+ int id;
+ void __iomem *regs;
+ unsigned long state;
+
+ struct platform_device *pdev;
+ struct v4l2_device *v4l2_dev;
+ struct mxc_isi_m2m_dev m2m;
+ struct mxc_isi_cap_dev isi_cap;
+ struct clk *clk;
+
+ u32 interface[MAX_PORTS];
+ u32 flags;
+ u8 chain_buf;
+
+ /* scale factor */
+ u32 xfactor;
+ u32 yfactor;
+ u32 pre_dec_x;
+ u32 pre_dec_y;
+
+ unsigned int hflip:1;
+ unsigned int vflip:1;
+
+ unsigned int cscen:1;
+ unsigned int scale:1;
+ unsigned int alphaen:1;
+ unsigned int crop:1;
+ unsigned int deinterlace:1;
+ unsigned int parallel_csi:1;
+
+ struct mxc_isi_ctrls ctrls;
+ u8 alpha; /* goable alpha */
+ struct mxc_isi_roi_alpha alpha_roi[5]; /* ROI alpha */
+};
+
+static inline void set_frame_bounds(struct mxc_isi_frame *f, u32 width, u32 height)
+{
+ f->o_width = width;
+ f->o_height = height;
+ f->c_width = width;
+ f->c_height = height;
+ f->width = width;
+ f->height = height;
+}
+
+static inline void set_frame_out(struct mxc_isi_frame *f, u32 width, u32 height)
+{
+ f->c_width = width;
+ f->c_height = height;
+ f->width = width;
+ f->height = height;
+}
+
+static inline void set_frame_crop(struct mxc_isi_frame *f,
+ u32 left, u32 top, u32 width, u32 height)
+{
+ f->h_off = left;
+ f->v_off = top;
+ f->c_width = width;
+ f->c_height = height;
+}
+
+#endif
diff --git a/drivers/media/platform/imx8/mxc-isi-hw.c b/drivers/media/platform/imx8/mxc-isi-hw.c
new file mode 100644
index 000000000000..18750776a94f
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-isi-hw.c
@@ -0,0 +1,599 @@
+/*
+ * Copyright 2017-2018 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <soc/imx8/sc/sci.h>
+#include <dt-bindings/pinctrl/pads-imx8qxp.h>
+
+#include "mxc-isi-hw.h"
+#define ISI_DOWNSCALE_THRESHOLD 0x4000
+
+#ifdef DEBUG
+void dump_isi_regs(struct mxc_isi_dev *mxc_isi)
+{
+ struct device *dev = &mxc_isi->pdev->dev;
+
+ dev_dbg(dev, "ISI CHNLC register dump, isi%d\n", mxc_isi->id);
+ dev_dbg(dev, "CHNL_CTRL 0x0h = 0x%8x\n", readl(mxc_isi->regs + 0x0));
+ dev_dbg(dev, "CHNL_IMG_CTRL 0x4h = 0x%8x\n", readl(mxc_isi->regs + 0x4));
+ dev_dbg(dev, "CHNL_OUT_BUF_CTRL 0x8h = 0x%8x\n", readl(mxc_isi->regs + 0x8));
+ dev_dbg(dev, "CHNL_IMG_CFG 0xCh = 0x%8x\n", readl(mxc_isi->regs + 0xC));
+ dev_dbg(dev, "CHNL_IER 0x10h = 0x%8x\n", readl(mxc_isi->regs + 0x10));
+ dev_dbg(dev, "CHNL_STS 0x14h = 0x%8x\n", readl(mxc_isi->regs + 0x14));
+ dev_dbg(dev, "CHNL_SCALE_FACTOR 0x18h = 0x%8x\n", readl(mxc_isi->regs + 0x18));
+ dev_dbg(dev, "CHNL_SCALE_OFFSET 0x1Ch = 0x%8x\n", readl(mxc_isi->regs + 0x1C));
+ dev_dbg(dev, "CHNL_CROP_ULC 0x20h = 0x%8x\n", readl(mxc_isi->regs + 0x20));
+ dev_dbg(dev, "CHNL_CROP_LRC 0x24h = 0x%8x\n", readl(mxc_isi->regs + 0x24));
+ dev_dbg(dev, "CHNL_CSC_COEFF0 0x28h = 0x%8x\n", readl(mxc_isi->regs + 0x28));
+ dev_dbg(dev, "CHNL_CSC_COEFF1 0x2Ch = 0x%8x\n", readl(mxc_isi->regs + 0x2C));
+ dev_dbg(dev, "CHNL_CSC_COEFF2 0x30h = 0x%8x\n", readl(mxc_isi->regs + 0x30));
+ dev_dbg(dev, "CHNL_CSC_COEFF3 0x34h = 0x%8x\n", readl(mxc_isi->regs + 0x34));
+ dev_dbg(dev, "CHNL_CSC_COEFF4 0x38h = 0x%8x\n", readl(mxc_isi->regs + 0x38));
+ dev_dbg(dev, "CHNL_CSC_COEFF5 0x3Ch = 0x%8x\n", readl(mxc_isi->regs + 0x3C));
+ dev_dbg(dev, "CHNL_ROI_0_ALPHA 0x40h = 0x%8x\n", readl(mxc_isi->regs + 0x40));
+ dev_dbg(dev, "CHNL_ROI_0_ULC 0x44h = 0x%8x\n", readl(mxc_isi->regs + 0x44));
+ dev_dbg(dev, "CHNL_ROI_0_LRC 0x48h = 0x%8x\n", readl(mxc_isi->regs + 0x48));
+ dev_dbg(dev, "CHNL_ROI_1_ALPHA 0x4Ch = 0x%8x\n", readl(mxc_isi->regs + 0x4C));
+ dev_dbg(dev, "CHNL_ROI_1_ULC 0x50h = 0x%8x\n", readl(mxc_isi->regs + 0x50));
+ dev_dbg(dev, "CHNL_ROI_1_LRC 0x54h = 0x%8x\n", readl(mxc_isi->regs + 0x54));
+ dev_dbg(dev, "CHNL_ROI_2_ALPHA 0x58h = 0x%8x\n", readl(mxc_isi->regs + 0x58));
+ dev_dbg(dev, "CHNL_ROI_2_ULC 0x5Ch = 0x%8x\n", readl(mxc_isi->regs + 0x5C));
+ dev_dbg(dev, "CHNL_ROI_2_LRC 0x60h = 0x%8x\n", readl(mxc_isi->regs + 0x60));
+ dev_dbg(dev, "CHNL_ROI_3_ALPHA 0x64h = 0x%8x\n", readl(mxc_isi->regs + 0x64));
+ dev_dbg(dev, "CHNL_ROI_3_ULC 0x68h = 0x%8x\n", readl(mxc_isi->regs + 0x68));
+ dev_dbg(dev, "CHNL_ROI_3_LRC 0x6Ch = 0x%8x\n", readl(mxc_isi->regs + 0x6C));
+ dev_dbg(dev, "CHNL_OUT_BUF1_ADDR_Y 0x70h = 0x%8x\n", readl(mxc_isi->regs + 0x70));
+ dev_dbg(dev, "CHNL_OUT_BUF1_ADDR_U 0x74h = 0x%8x\n", readl(mxc_isi->regs + 0x74));
+ dev_dbg(dev, "CHNL_OUT_BUF1_ADDR_V 0x78h = 0x%8x\n", readl(mxc_isi->regs + 0x78));
+ dev_dbg(dev, "CHNL_OUT_BUF_PITCH 0x7Ch = 0x%8x\n", readl(mxc_isi->regs + 0x7C));
+ dev_dbg(dev, "CHNL_IN_BUF_ADDR 0x80h = 0x%8x\n", readl(mxc_isi->regs + 0x80));
+ dev_dbg(dev, "CHNL_IN_BUF_PITCH 0x84h = 0x%8x\n", readl(mxc_isi->regs + 0x84));
+ dev_dbg(dev, "CHNL_MEM_RD_CTRL 0x88h = 0x%8x\n", readl(mxc_isi->regs + 0x88));
+ dev_dbg(dev, "CHNL_OUT_BUF2_ADDR_Y 0x8Ch = 0x%8x\n", readl(mxc_isi->regs + 0x8C));
+ dev_dbg(dev, "CHNL_OUT_BUF2_ADDR_U 0x90h = 0x%8x\n", readl(mxc_isi->regs + 0x90));
+ dev_dbg(dev, "CHNL_OUT_BUF2_ADDR_V 0x94h = 0x%8x\n", readl(mxc_isi->regs + 0x94));
+}
+#else
+void dump_isi_regs(struct mxc_isi_dev *mxc_isi)
+{
+}
+#endif
+
+static const u32 coeffs[2][6] = {
+ /* A2,A1, B1, A3, B3, B2, C2, C1, D1, C3, D3, D2 */
+ /* YUV2RGB */
+ { 0x0000012A, 0x012A0198, 0x0730079C, 0x0204012A, 0x01F00000, 0x01800180 },
+ /* RGB->YUV */
+ { 0x0096004D, 0x05DA001D, 0x007005B6, 0x057C009E, 0x000005E6, 0x00000000 },
+};
+
+static void printk_pixelformat(char *prefix, int val)
+{
+ printk("%s %c%c%c%c\n", prefix ? prefix : "pixelformat",
+ val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, (val >> 24) & 0xff);
+}
+
+static bool is_rgb(u32 pix_fmt)
+{
+ if ((pix_fmt == V4L2_PIX_FMT_RGB565) ||
+ (pix_fmt == V4L2_PIX_FMT_RGB24) ||
+ (pix_fmt == V4L2_PIX_FMT_RGB32) ||
+ (pix_fmt == V4L2_PIX_FMT_BGR24) ||
+ (pix_fmt == V4L2_PIX_FMT_ARGB32)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static bool is_yuv(u32 pix_fmt)
+{
+ if ((pix_fmt == V4L2_PIX_FMT_YUYV) ||
+ (pix_fmt == V4L2_PIX_FMT_YUV32) ||
+ (pix_fmt == V4L2_PIX_FMT_NV12)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void mxc_isi_channel_set_outbuf(struct mxc_isi_dev *mxc_isi, struct mxc_isi_buffer *buf)
+{
+ struct vb2_buffer *vb2_buf = &buf->v4l2_buf.vb2_buf;
+ struct frame_addr *paddr = &buf->paddr;
+ u32 framecount = buf->v4l2_buf.sequence;
+ int val = 0;
+
+ paddr->y = vb2_dma_contig_plane_dma_addr(vb2_buf, 0);
+
+ if (vb2_buf->num_planes == 2)
+ paddr->cb = vb2_dma_contig_plane_dma_addr(vb2_buf, 1);
+ if (vb2_buf->num_planes == 3) {
+ paddr->cb = vb2_dma_contig_plane_dma_addr(vb2_buf, 1);
+ paddr->cr = vb2_dma_contig_plane_dma_addr(vb2_buf, 2);
+ }
+
+ val = readl(mxc_isi->regs + CHNL_OUT_BUF_CTRL);
+ if (framecount % 2 == 1) {
+ writel(paddr->y, mxc_isi->regs + CHNL_OUT_BUF2_ADDR_Y);
+ writel(paddr->cb, mxc_isi->regs + CHNL_OUT_BUF2_ADDR_U);
+ writel(paddr->cr, mxc_isi->regs + CHNL_OUT_BUF2_ADDR_V);
+ val ^= CHNL_OUT_BUF_CTRL_LOAD_BUF2_ADDR_MASK;
+ } else {
+ writel(paddr->y, mxc_isi->regs + CHNL_OUT_BUF1_ADDR_Y);
+ writel(paddr->cb, mxc_isi->regs + CHNL_OUT_BUF1_ADDR_U);
+ writel(paddr->cr, mxc_isi->regs + CHNL_OUT_BUF1_ADDR_V);
+ val ^= CHNL_OUT_BUF_CTRL_LOAD_BUF1_ADDR_MASK;
+ }
+ writel(val, mxc_isi->regs + CHNL_OUT_BUF_CTRL);
+}
+
+void mxc_isi_channel_hw_reset(struct mxc_isi_dev *mxc_isi)
+{
+ sc_ipc_t ipcHndl;
+ sc_err_t sciErr;
+ uint32_t mu_id;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("Cannot obtain MU ID\n");
+ return;
+ }
+
+ sciErr = sc_ipc_open(&ipcHndl, mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return;
+ }
+
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_ISI_CH0, SC_PM_PW_MODE_OFF);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("sc_misc_MIPI reset failed! (sciError = %d)\n", sciErr);
+
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_ISI_CH0, SC_PM_PW_MODE_ON);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("sc_misc_MIPI reset failed! (sciError = %d)\n", sciErr);
+
+ udelay(500);
+
+ sc_ipc_close(mu_id);
+}
+
+void mxc_isi_channel_sw_reset(struct mxc_isi_dev *mxc_isi)
+{
+ u32 val;
+
+ val = readl(mxc_isi->regs + CHNL_CTRL);
+ val |= CHNL_CTRL_SW_RST;
+ writel(val, mxc_isi->regs + CHNL_CTRL);
+ mdelay(5);
+ val &= ~CHNL_CTRL_SW_RST;
+ writel(val, mxc_isi->regs + CHNL_CTRL);
+}
+
+void mxc_isi_channel_source_config(struct mxc_isi_dev *mxc_isi)
+{
+ u32 val;
+
+ val = readl(mxc_isi->regs + CHNL_CTRL);
+ val &= ~(CHNL_CTRL_MIPI_VC_ID_MASK |
+ CHNL_CTRL_SRC_INPUT_MASK | CHNL_CTRL_SRC_TYPE_MASK);
+
+ switch (mxc_isi->interface[IN_PORT]) {
+ case ISI_INPUT_INTERFACE_MIPI0_CSI2:
+ val |= CHNL_CTRL_SRC_INPUT_MIPI0;
+ if (mxc_isi->interface[SUB_IN_PORT] <= CHNL_CTRL_MIPI_VC_ID_VC3 &&
+ mxc_isi->interface[SUB_IN_PORT] >= CHNL_CTRL_MIPI_VC_ID_VC0)
+ val |= (mxc_isi->interface[SUB_IN_PORT] << CHNL_CTRL_MIPI_VC_ID_OFFSET);
+ break;
+ case ISI_INPUT_INTERFACE_MIPI1_CSI2:
+ val |= CHNL_CTRL_SRC_INPUT_MIPI1;
+ if (mxc_isi->interface[SUB_IN_PORT] <= CHNL_CTRL_MIPI_VC_ID_VC3 &&
+ mxc_isi->interface[SUB_IN_PORT] >= CHNL_CTRL_MIPI_VC_ID_VC0)
+ val |= (mxc_isi->interface[SUB_IN_PORT] << CHNL_CTRL_MIPI_VC_ID_OFFSET);
+ break;
+ case ISI_INPUT_INTERFACE_DC0:
+ val |= CHNL_CTRL_SRC_INPUT_DC0;
+ break;
+ case ISI_INPUT_INTERFACE_DC1:
+ val |= CHNL_CTRL_SRC_INPUT_DC1;
+ break;
+ case ISI_INPUT_INTERFACE_HDMI:
+ val |= CHNL_CTRL_SRC_INPUT_HDMI;
+ break;
+ case ISI_INPUT_INTERFACE_PARALLEL_CSI:
+ val |= CHNL_CTRL_SRC_INPUT_CSI;
+ break;
+ case ISI_INPUT_INTERFACE_MEM:
+ val |= CHNL_CTRL_SRC_INPUT_MEMORY;
+ val |= (CHNL_CTRL_SRC_TYPE_MEMORY << CHNL_CTRL_SRC_TYPE_OFFSET);
+ break;
+ default:
+ dev_err(&mxc_isi->pdev->dev, "invalid interface\n");
+ break;
+ }
+
+ writel(val, mxc_isi->regs + CHNL_CTRL);
+}
+
+void mxc_isi_channel_set_flip(struct mxc_isi_dev *mxc_isi)
+{
+ u32 val;
+
+ val = readl(mxc_isi->regs + CHNL_IMG_CTRL);
+ val &= ~(CHNL_IMG_CTRL_VFLIP_EN_MASK | CHNL_IMG_CTRL_HFLIP_EN_MASK);
+
+ if (mxc_isi->vflip)
+ val |= (CHNL_IMG_CTRL_VFLIP_EN_ENABLE << CHNL_IMG_CTRL_VFLIP_EN_OFFSET);
+ if (mxc_isi->hflip)
+ val |= (CHNL_IMG_CTRL_HFLIP_EN_ENABLE << CHNL_IMG_CTRL_HFLIP_EN_OFFSET);
+
+ writel(val, mxc_isi->regs + CHNL_IMG_CTRL);
+}
+
+void mxc_isi_channel_set_csc(struct mxc_isi_dev *mxc_isi)
+{
+ struct mxc_isi_fmt *dst_fmt = mxc_isi->isi_cap.dst_f.fmt;
+ struct mxc_isi_fmt *src_fmt = mxc_isi->isi_cap.src_f.fmt;
+ u32 val, csc = 0;
+
+ val = readl(mxc_isi->regs + CHNL_IMG_CTRL);
+ val &= ~(CHNL_IMG_CTRL_FORMAT_MASK |
+ CHNL_IMG_CTRL_YCBCR_MODE_MASK |
+ CHNL_IMG_CTRL_CSC_BYPASS_MASK |
+ CHNL_IMG_CTRL_CSC_MODE_MASK);
+
+ /* set outbuf format */
+ val |= dst_fmt->color << CHNL_IMG_CTRL_FORMAT_OFFSET;
+
+ mxc_isi->cscen = 1;
+
+ if (is_yuv(src_fmt->fourcc) && is_rgb(dst_fmt->fourcc)) {
+ /* YUV2RGB */
+ csc = YUV2RGB;
+ /* YCbCr enable??? */
+ val |= (CHNL_IMG_CTRL_CSC_MODE_YCBCR2RGB << CHNL_IMG_CTRL_CSC_MODE_OFFSET);
+ val |= (CHNL_IMG_CTRL_YCBCR_MODE_ENABLE << CHNL_IMG_CTRL_YCBCR_MODE_OFFSET);
+ } else if (is_rgb(src_fmt->fourcc) && is_yuv(dst_fmt->fourcc)) {
+ /* RGB2YUV */
+ csc = RGB2YUV;
+ val |= (CHNL_IMG_CTRL_CSC_MODE_RGB2YUV << CHNL_IMG_CTRL_CSC_MODE_OFFSET);
+ } else {
+ /* Bypass CSC */
+ printk("bypass csc\n");
+ mxc_isi->cscen = 0;
+ val |= CHNL_IMG_CTRL_CSC_BYPASS_ENABLE;
+ }
+
+ printk_pixelformat("input fmt", src_fmt->fourcc);
+ printk_pixelformat("output fmt", dst_fmt->fourcc);
+
+ if (mxc_isi->cscen) {
+ writel(coeffs[csc][0], mxc_isi->regs + CHNL_CSC_COEFF0);
+ writel(coeffs[csc][1], mxc_isi->regs + CHNL_CSC_COEFF1);
+ writel(coeffs[csc][2], mxc_isi->regs + CHNL_CSC_COEFF2);
+ writel(coeffs[csc][3], mxc_isi->regs + CHNL_CSC_COEFF3);
+ writel(coeffs[csc][4], mxc_isi->regs + CHNL_CSC_COEFF4);
+ writel(coeffs[csc][5], mxc_isi->regs + CHNL_CSC_COEFF5);
+ }
+
+ writel(val, mxc_isi->regs + CHNL_IMG_CTRL);
+}
+void mxc_isi_channel_set_alpha_roi0(struct mxc_isi_dev *mxc_isi,
+ struct v4l2_rect *rect)
+{
+ u32 val0, val1;
+ val0 = (rect->left << 16) | rect->top;
+ writel(val0, mxc_isi->regs + CHNL_ROI_0_ULC);
+ val1 = (rect->width << 16) | rect->height;
+ writel(val0 + val1, mxc_isi->regs + CHNL_ROI_0_LRC);
+}
+
+void mxc_isi_channel_set_alpha(struct mxc_isi_dev *mxc_isi)
+{
+ u32 val;
+
+ val = readl(mxc_isi->regs + CHNL_IMG_CTRL);
+ val &= ~(CHNL_IMG_CTRL_GBL_ALPHA_VAL_MASK | CHNL_IMG_CTRL_GBL_ALPHA_EN_MASK);
+ val |= ((mxc_isi->alpha << CHNL_IMG_CTRL_GBL_ALPHA_VAL_OFFSET) |
+ (CHNL_IMG_CTRL_GBL_ALPHA_EN_ENABLE << CHNL_IMG_CTRL_GBL_ALPHA_EN_OFFSET));
+
+ writel(val, mxc_isi->regs + CHNL_IMG_CTRL);
+}
+
+void mxc_isi_channel_set_chain_buf(struct mxc_isi_dev *mxc_isi)
+{
+ u32 val;
+
+ if (mxc_isi->chain_buf) {
+ printk("%s\n", __func__);
+ val = readl(mxc_isi->regs + CHNL_CTRL);
+ val &= ~CHNL_CTRL_CHAIN_BUF_MASK;
+ val |= (CHNL_CTRL_CHAIN_BUF_2_CHAIN << CHNL_CTRL_CHAIN_BUF_OFFSET);
+
+ writel(val, mxc_isi->regs + CHNL_CTRL);
+ }
+}
+
+void mxc_isi_channel_deinterlace_init(struct mxc_isi_dev *mxc_isi)
+{
+ /* Config for Blending deinterlace */
+}
+
+void mxc_isi_channel_set_deinterlace(struct mxc_isi_dev *mxc_isi)
+{
+ /* de-interlacing method
+ * Weaving-------------Yes
+ * Line Doubling-------No
+ * Blending -----------TODO*/
+ u32 val;
+
+ val = readl(mxc_isi->regs + CHNL_IMG_CTRL);
+ val &= ~CHNL_IMG_CTRL_DEINT_MASK;
+ if (mxc_isi->deinterlace)
+ val |= mxc_isi->deinterlace << CHNL_IMG_CTRL_DEINT_OFFSET;
+ if (mxc_isi->deinterlace == CHNL_IMG_CTRL_DEINT_LDOUBLE_ODD_EVEN ||
+ mxc_isi->deinterlace == CHNL_IMG_CTRL_DEINT_LDOUBLE_EVEN_ODD)
+ mxc_isi_channel_deinterlace_init(mxc_isi);
+
+ writel(val, mxc_isi->regs + CHNL_IMG_CTRL);
+}
+
+void mxc_isi_channel_set_crop(struct mxc_isi_dev *mxc_isi)
+{
+ struct mxc_isi_frame *src_f = &mxc_isi->isi_cap.src_f;
+ struct v4l2_rect crop;
+ u32 val, val0, val1, temp;
+
+ val = readl(mxc_isi->regs + CHNL_IMG_CTRL);
+ val &= ~CHNL_IMG_CTRL_CROP_EN_MASK;
+
+ if ((src_f->o_height == src_f->height) &&
+ (src_f->o_width == src_f->width)) {
+ mxc_isi->crop = 0;
+ writel(val, mxc_isi->regs + CHNL_IMG_CTRL);
+ return;
+ }
+
+ if (mxc_isi->scale) {
+ temp = (src_f->h_off << 12) / mxc_isi->xfactor;
+ crop.left = temp >> mxc_isi->pre_dec_x;
+ temp = (src_f->v_off << 12) / mxc_isi->yfactor;
+ crop.top = temp >> mxc_isi->pre_dec_y;
+ temp = (src_f->width << 12) / mxc_isi->xfactor;
+ crop.width = temp >> mxc_isi->pre_dec_x;
+ temp = (src_f->height << 12) / mxc_isi->yfactor;
+ crop.height = temp >> mxc_isi->pre_dec_y;
+ } else {
+ crop.left = src_f->h_off;
+ crop.top = src_f->v_off;
+ crop.width = src_f->width;
+ crop.height = src_f->height;
+ }
+
+ mxc_isi->crop = 1;
+ val |= (CHNL_IMG_CTRL_CROP_EN_ENABLE << CHNL_IMG_CTRL_CROP_EN_OFFSET);
+ val0 = crop.top | (crop.left << CHNL_CROP_ULC_X_OFFSET);
+ val1 = crop.height | (crop.width << CHNL_CROP_LRC_X_OFFSET);
+
+ writel(val0, mxc_isi->regs + CHNL_CROP_ULC);
+ writel((val1 + val0), mxc_isi->regs + CHNL_CROP_LRC);
+ writel(val, mxc_isi->regs + CHNL_IMG_CTRL);
+}
+
+void mxc_isi_channel_set_scaling(struct mxc_isi_dev *mxc_isi)
+{
+ struct mxc_isi_frame *dst_f = &mxc_isi->isi_cap.dst_f;
+ struct mxc_isi_frame *src_f = &mxc_isi->isi_cap.src_f;
+ u32 decx, decy;
+ u32 xscale, yscale;
+ u32 xdec = 0, ydec = 0;
+ u32 val0, val1;
+
+ if (dst_f->height == src_f->height ||
+ dst_f->width == src_f->width) {
+ mxc_isi->scale = 0;
+ dev_dbg(&mxc_isi->pdev->dev, "%s: no scale\n", __func__);
+ return;
+ }
+
+ dev_info(&mxc_isi->pdev->dev, "input_size(%d,%d), output_size(%d,%d)\n",
+ src_f->width, src_f->height, dst_f->width, dst_f->height);
+
+ mxc_isi->scale = 1;
+
+ decx = src_f->width / dst_f->width;
+ decy = src_f->height / dst_f->height;
+
+ if (decx > 1) {
+ /* Down */
+ if (decx >= 2 && decx < 4) {
+ decx = 2;
+ xdec = 1;
+ } else if (decx >= 4 && decx < 8) {
+ decx = 4;
+ xdec = 2;
+ } else if (decx >= 8) {
+ decx = 8;
+ xdec = 3;
+ }
+ xscale = src_f->width * 0x1000 / (dst_f->width * decx);
+ } else
+ /* Up */
+ xscale = src_f->width * 0x1000 / dst_f->width;
+
+ if (decy > 1) {
+ if (decy >= 2 && decy < 4) {
+ decy = 2;
+ ydec = 1;
+ } else if (decy >= 4 && decy < 8) {
+ decy = 4;
+ ydec = 2;
+ } else if (decy >= 8) {
+ decy = 8;
+ ydec = 3;
+ }
+ yscale = src_f->height * 0x1000 / (dst_f->height * decy);
+ } else
+ yscale = src_f->height * 0x1000 / dst_f->height;
+
+ val0 = readl(mxc_isi->regs + CHNL_IMG_CTRL);
+ val0 |= CHNL_IMG_CTRL_YCBCR_MODE_MASK;//YCbCr Sandor???
+ val0 &= ~(CHNL_IMG_CTRL_DEC_X_MASK | CHNL_IMG_CTRL_DEC_Y_MASK);
+ val0 |= (xdec << CHNL_IMG_CTRL_DEC_X_OFFSET) |
+ (ydec << CHNL_IMG_CTRL_DEC_Y_OFFSET);
+ writel(val0, mxc_isi->regs + CHNL_IMG_CTRL);
+
+ if (xscale > ISI_DOWNSCALE_THRESHOLD)
+ xscale = ISI_DOWNSCALE_THRESHOLD;
+ if (yscale > ISI_DOWNSCALE_THRESHOLD)
+ yscale = ISI_DOWNSCALE_THRESHOLD;
+
+ val1 = xscale | (yscale << CHNL_SCALE_FACTOR_Y_SCALE_OFFSET);
+
+ writel(val1, mxc_isi->regs + CHNL_SCALE_FACTOR);
+ writel(0, mxc_isi->regs + CHNL_SCALE_OFFSET);
+
+ return;
+}
+
+void mxc_isi_channel_init(struct mxc_isi_dev *mxc_isi)
+{
+ u32 val;
+
+ /* hw reset */
+ mxc_isi_channel_hw_reset(mxc_isi);
+
+ /* sw reset */
+ mxc_isi_channel_sw_reset(mxc_isi);
+
+ /* Init channel clk first */
+ val = readl(mxc_isi->regs + CHNL_CTRL);
+ val |= (CHNL_CTRL_CLK_EN_ENABLE << CHNL_CTRL_CLK_EN_OFFSET);
+ writel(val, mxc_isi->regs + CHNL_CTRL);
+}
+
+void mxc_isi_channel_deinit(struct mxc_isi_dev *mxc_isi)
+{
+ u32 val;
+
+ /* sw reset */
+ mxc_isi_channel_sw_reset(mxc_isi);
+
+ /* deinit channel clk first */
+ val = (CHNL_CTRL_CLK_EN_ENABLE << CHNL_CTRL_CLK_EN_OFFSET);
+ writel(val, mxc_isi->regs + CHNL_CTRL);
+}
+
+void mxc_isi_channel_config(struct mxc_isi_dev *mxc_isi)
+{
+ struct mxc_isi_frame *dst_f = &mxc_isi->isi_cap.dst_f;
+ struct mxc_isi_frame *src_f = &mxc_isi->isi_cap.src_f;
+ u32 val;
+
+ /* config output frame size and format */
+ val = src_f->o_width | (src_f->o_height << CHNL_IMG_CFG_HEIGHT_OFFSET);
+ writel(val, mxc_isi->regs + CHNL_IMG_CFG);
+
+ /* check csc and scaling */
+ mxc_isi_channel_set_csc(mxc_isi);
+
+ mxc_isi_channel_set_scaling(mxc_isi);
+
+ /* select the source input / src type / virtual channel for mipi*/
+ mxc_isi_channel_source_config(mxc_isi);
+
+ /* line pitch */
+ val = dst_f->bytesperline[0];
+ writel(val, mxc_isi->regs + CHNL_OUT_BUF_PITCH);
+
+ /* TODO */
+#if 0
+ mxc_isi_channel_set_crop(mxc_isi);
+
+ mxc_isi_channel_set_flip(mxc_isi);
+ if (mxc_isi->alphaen)
+ mxc_isi_channel_set_alpha(mxc_isi);
+
+#endif
+
+ val = readl(mxc_isi->regs + CHNL_CTRL);
+ val &= ~CHNL_CTRL_CHNL_BYPASS_MASK;
+
+ /* Bypass channel */
+ if (!mxc_isi->cscen && !mxc_isi->scale)
+ val |= (CHNL_CTRL_CHNL_BYPASS_ENABLE << CHNL_CTRL_CHNL_BYPASS_OFFSET);
+
+ writel(val, mxc_isi->regs + CHNL_CTRL);
+}
+
+void mxc_isi_channel_enable(struct mxc_isi_dev *mxc_isi)
+{
+ u32 val;
+
+ val = readl(mxc_isi->regs + CHNL_CTRL);
+ val |= (CHNL_CTRL_CHNL_EN_ENABLE << CHNL_CTRL_CHNL_EN_OFFSET);
+ val |= 0xff << CHNL_CTRL_BLANK_PXL_OFFSET;
+ writel(val, mxc_isi->regs + CHNL_CTRL);
+
+ mxc_isi_enable_irq(mxc_isi);
+ msleep(300);
+ dump_isi_regs(mxc_isi);
+}
+
+void mxc_isi_channel_disable(struct mxc_isi_dev *mxc_isi)
+{
+ u32 val;
+
+ mxc_isi_disable_irq(mxc_isi);
+
+ val = readl(mxc_isi->regs + CHNL_CTRL);
+ val &= ~(CHNL_CTRL_CHNL_EN_MASK | CHNL_CTRL_CLK_EN_MASK);
+ val |= (CHNL_CTRL_CHNL_EN_DISABLE << CHNL_CTRL_CHNL_EN_OFFSET);
+ val |= (CHNL_CTRL_CLK_EN_DISABLE << CHNL_CTRL_CLK_EN_OFFSET);
+ writel(val, mxc_isi->regs + CHNL_CTRL);
+}
+
+void mxc_isi_enable_irq(struct mxc_isi_dev *mxc_isi)
+{
+ u32 val;
+
+ val = CHNL_IER_FRM_RCVD_EN_MASK |
+ CHNL_IER_OFLW_Y_BUF_EN_MASK |
+ CHNL_IER_AXI_WR_ERR_U_EN_MASK |
+ CHNL_IER_AXI_WR_ERR_V_EN_MASK |
+ CHNL_IER_AXI_WR_ERR_Y_EN_MASK |
+ CHNL_IER_OFLW_PANIC_V_BUF_EN_MASK |
+ CHNL_IER_EXCS_OFLW_V_BUF_EN_MASK |
+ CHNL_IER_OFLW_V_BUF_EN_MASK |
+ CHNL_IER_OFLW_PANIC_U_BUF_EN_MASK |
+ CHNL_IER_EXCS_OFLW_U_BUF_EN_MASK |
+ CHNL_IER_OFLW_U_BUF_EN_MASK |
+ CHNL_IER_OFLW_PANIC_Y_BUF_EN_MASK |
+ CHNL_IER_EXCS_OFLW_Y_BUF_EN_MASK |
+ CHNL_IER_OFLW_Y_BUF_EN_MASK;
+
+ writel(val, mxc_isi->regs + CHNL_IER);
+}
+
+void mxc_isi_disable_irq(struct mxc_isi_dev *mxc_isi)
+{
+ writel(0, mxc_isi->regs + CHNL_CTRL);
+}
+
+u32 mxc_isi_get_irq_status(struct mxc_isi_dev *mxc_isi)
+{
+ return readl(mxc_isi->regs + CHNL_STS);
+}
+
+void mxc_isi_clean_irq_status(struct mxc_isi_dev *mxc_isi, u32 val)
+{
+ writel(val, mxc_isi->regs + CHNL_STS);
+}
diff --git a/drivers/media/platform/imx8/mxc-isi-hw.h b/drivers/media/platform/imx8/mxc-isi-hw.h
new file mode 100644
index 000000000000..737008b41fd0
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-isi-hw.h
@@ -0,0 +1,484 @@
+/*
+ * Copyright 2017-2018 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef MXC_ISI_HW_H_
+#define MXC_ISI_HW_H_
+
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+
+#include "mxc-isi-core.h"
+
+/* ISI Registers Define */
+/* Channel Control Register */
+#define CHNL_CTRL 0x0
+#define CHNL_CTRL_CHNL_EN_OFFSET 31
+#define CHNL_CTRL_CHNL_EN_MASK 0x80000000
+#define CHNL_CTRL_CHNL_EN_DISABLE 0
+#define CHNL_CTRL_CHNL_EN_ENABLE 1
+#define CHNL_CTRL_CLK_EN_OFFSET 30
+#define CHNL_CTRL_CLK_EN_MASK 0x40000000
+#define CHNL_CTRL_CLK_EN_DISABLE 0
+#define CHNL_CTRL_CLK_EN_ENABLE 1
+#define CHNL_CTRL_CHNL_BYPASS_OFFSET 29
+#define CHNL_CTRL_CHNL_BYPASS_MASK 0x20000000
+#define CHNL_CTRL_CHNL_BYPASS_ENABLE 1
+#define CHNL_CTRL_CHAIN_BUF_OFFSET 25
+#define CHNL_CTRL_CHAIN_BUF_MASK 0x60000
+#define CHNL_CTRL_CHAIN_BUF_NO_CHAIN 0
+#define CHNL_CTRL_CHAIN_BUF_2_CHAIN 1
+#define CHNL_CTRL_SW_RST_OFFSET 24
+#define CHNL_CTRL_SW_RST_MASK 0x1000000
+#define CHNL_CTRL_SW_RST 0x1000000
+#define CHNL_CTRL_BLANK_PXL_OFFSET 16
+#define CHNL_CTRL_MIPI_VC_ID_OFFSET 6
+#define CHNL_CTRL_MIPI_VC_ID_MASK 0xc0
+#define CHNL_CTRL_MIPI_VC_ID_VC0 0
+#define CHNL_CTRL_MIPI_VC_ID_VC1 1
+#define CHNL_CTRL_MIPI_VC_ID_VC2 2
+#define CHNL_CTRL_MIPI_VC_ID_VC3 3
+#define CHNL_CTRL_SRC_TYPE_OFFSET 4
+#define CHNL_CTRL_SRC_TYPE_MASK 0x10
+#define CHNL_CTRL_SRC_TYPE_DEVICE 0
+#define CHNL_CTRL_SRC_TYPE_MEMORY 1
+#define CHNL_CTRL_SRC_INPUT_OFFSET 0
+#define CHNL_CTRL_SRC_INPUT_MASK 0x7
+#define CHNL_CTRL_SRC_INPUT_DC0 0
+#define CHNL_CTRL_SRC_INPUT_DC1 1
+#define CHNL_CTRL_SRC_INPUT_MIPI0 2
+#define CHNL_CTRL_SRC_INPUT_MIPI1 3
+#define CHNL_CTRL_SRC_INPUT_HDMI 4
+#define CHNL_CTRL_SRC_INPUT_CSI 4
+#define CHNL_CTRL_SRC_INPUT_MEMORY 5
+
+/* Channel Image Control Register */
+#define CHNL_IMG_CTRL 0x4
+#define CHNL_IMG_CTRL_FORMAT_OFFSET 24
+#define CHNL_IMG_CTRL_FORMAT_MASK 0x3F000000
+#define CHNL_IMG_CTRL_GBL_ALPHA_VAL_OFFSET 16
+#define CHNL_IMG_CTRL_GBL_ALPHA_VAL_MASK 0xFF0000
+#define CHNL_IMG_CTRL_GBL_ALPHA_EN_OFFSET 15
+#define CHNL_IMG_CTRL_GBL_ALPHA_EN_ENABLE 1
+#define CHNL_IMG_CTRL_GBL_ALPHA_EN_MASK 0x8000
+#define CHNL_IMG_CTRL_DEINT_OFFSET 12
+#define CHNL_IMG_CTRL_DEINT_MASK 0x7000
+#define CHNL_IMG_CTRL_DEINT_WEAVE_ODD_EVEN 2
+#define CHNL_IMG_CTRL_DEINT_WEAVE_EVEN_ODD 3
+#define CHNL_IMG_CTRL_DEINT_BLEND_ODD_EVEN 4
+#define CHNL_IMG_CTRL_DEINT_BLEND_EVEN_ODD 5
+#define CHNL_IMG_CTRL_DEINT_LDOUBLE_ODD_EVEN 6
+#define CHNL_IMG_CTRL_DEINT_LDOUBLE_EVEN_ODD 7
+#define CHNL_IMG_CTRL_DEC_X_OFFSET 10
+#define CHNL_IMG_CTRL_DEC_X_MASK 0xC00
+#define CHNL_IMG_CTRL_DEC_X_0 0
+#define CHNL_IMG_CTRL_DEC_X_2 1
+#define CHNL_IMG_CTRL_DEC_X_4 2
+#define CHNL_IMG_CTRL_DEC_X_8 3
+#define CHNL_IMG_CTRL_DEC_Y_OFFSET 8
+#define CHNL_IMG_CTRL_DEC_Y_MASK 0x300
+#define CHNL_IMG_CTRL_DEC_Y_0 0
+#define CHNL_IMG_CTRL_DEC_Y_2 1
+#define CHNL_IMG_CTRL_DEC_Y_4 2
+#define CHNL_IMG_CTRL_DEC_Y_8 3
+#define CHNL_IMG_CTRL_CROP_EN_OFFSET 7
+#define CHNL_IMG_CTRL_CROP_EN_MASK 0x80
+#define CHNL_IMG_CTRL_CROP_EN_ENABLE 1
+#define CHNL_IMG_CTRL_VFLIP_EN_OFFSET 6
+#define CHNL_IMG_CTRL_VFLIP_EN_MASK 0x40
+#define CHNL_IMG_CTRL_VFLIP_EN_ENABLE 1
+#define CHNL_IMG_CTRL_HFLIP_EN_OFFSET 5
+#define CHNL_IMG_CTRL_HFLIP_EN_MASK 0x20
+#define CHNL_IMG_CTRL_HFLIP_EN_ENABLE 1
+#define CHNL_IMG_CTRL_YCBCR_MODE_OFFSET 3
+#define CHNL_IMG_CTRL_YCBCR_MODE_MASK 0x8
+#define CHNL_IMG_CTRL_YCBCR_MODE_ENABLE 1
+#define CHNL_IMG_CTRL_CSC_MODE_OFFSET 1
+#define CHNL_IMG_CTRL_CSC_MODE_MASK 0x6
+#define CHNL_IMG_CTRL_CSC_MODE_YUV2RGB 0
+#define CHNL_IMG_CTRL_CSC_MODE_YCBCR2RGB 1
+#define CHNL_IMG_CTRL_CSC_MODE_RGB2YUV 2
+#define CHNL_IMG_CTRL_CSC_MODE_RGB2YCBCR 3
+#define CHNL_IMG_CTRL_CSC_BYPASS_OFFSET 0
+#define CHNL_IMG_CTRL_CSC_BYPASS_MASK 0x1
+#define CHNL_IMG_CTRL_CSC_BYPASS_ENABLE 0x1
+
+/* Channel Output Buffer Control Register */
+#define CHNL_OUT_BUF_CTRL 0x8
+#define CHNL_OUT_BUF_CTRL_LOAD_BUF2_ADDR_OFFSET 15
+#define CHNL_OUT_BUF_CTRL_LOAD_BUF2_ADDR_MASK 0x8000
+#define CHNL_OUT_BUF_CTRL_LOAD_BUF1_ADDR_OFFSET 14
+#define CHNL_OUT_BUF_CTRL_LOAD_BUF1_ADDR_MASK 0x4000
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_V_OFFSET 6
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_V_MASK 0xC0
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_V_NO_PANIC 0
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_V_PANIC_25 1
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_V_PANIC_50 2
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_V_PANIC_75 3
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_U_OFFSET 3
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_U_MASK 0x18
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_U_NO_PANIC 0
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_U_PANIC_25 1
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_U_PANIC_50 2
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_U_PANIC_75 3
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_Y_OFFSET 0
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_Y_MASK 0x3
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_Y_NO_PANIC 0
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_Y_PANIC_25 1
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_Y_PANIC_50 2
+#define CHNL_OUT_BUF_CTRL_OFLW_PANIC_SET_THD_Y_PANIC_75 3
+
+/* Channel Image Configuration */
+#define CHNL_IMG_CFG 0xC
+#define CHNL_IMG_CFG_HEIGHT_OFFSET 16
+#define CHNL_IMG_CFG_HEIGHT_MASK 0x1FFF0000
+#define CHNL_IMG_CFG_WIDTH_OFFSET 0
+#define CHNL_IMG_CFG_WIDTH_MASK 0x1FFF
+
+/* Channel Interrupt Enable Register */
+#define CHNL_IER 0x10
+#define CHNL_IER_MEM_RD_DONE_EN_OFFSET 31
+#define CHNL_IER_MEM_RD_DONE_EN_MASK 0x80000000
+#define CHNL_IER_MEM_RD_DONE_EN_ENABLE 1
+#define CHNL_IER_LINE_RCVD_EN_OFFSET 30
+#define CHNL_IER_LINE_RCVD_EN_MASK 0x40000000
+#define CHNL_IER_LINE_RCVD_EN_ENABLE 1
+#define CHNL_IER_FRM_RCVD_EN_OFFSET 29
+#define CHNL_IER_FRM_RCVD_EN_MASK 0x20000000
+#define CHNL_IER_FRM_RCVD_EN_ENABLE 1
+#define CHNL_IER_AXI_WR_ERR_V_EN_OFFSET 28
+#define CHNL_IER_AXI_WR_ERR_V_EN_MASK 0x10000000
+#define CHNL_IER_AXI_WR_ERR_V_EN_ENABLE 1
+#define CHNL_IER_AXI_WR_ERR_U_EN_OFFSET 27
+#define CHNL_IER_AXI_WR_ERR_U_EN_MASK 0x8000000
+#define CHNL_IER_AXI_WR_ERR_U_EN_ENABLE 1
+#define CHNL_IER_AXI_WR_ERR_Y_EN_OFFSET 26
+#define CHNL_IER_AXI_WR_ERR_Y_EN_MASK 0x4000000
+#define CHNL_IER_AXI_WR_ERR_Y_EN_ENABLE 1
+#define CHNL_IER_AXI_RD_ERR_EN_OFFSET 25
+#define CHNL_IER_AXI_RD_ERR_EN_MASK 0x2000000
+#define CHNL_IER_AXI_RD_ERR_EN_ENABLE 1
+#define CHNL_IER_OFLW_PANIC_V_BUF_EN_OFFSET 24
+#define CHNL_IER_OFLW_PANIC_V_BUF_EN_MASK 0x1000000
+#define CHNL_IER_OFLW_PANIC_V_BUF_EN_ENABLE 1
+#define CHNL_IER_EXCS_OFLW_V_BUF_EN_OFFSET 23
+#define CHNL_IER_EXCS_OFLW_V_BUF_EN_MASK 0x800000
+#define CHNL_IER_EXCS_OFLW_V_BUF_EN_ENABLE 1
+#define CHNL_IER_OFLW_V_BUF_EN_OFFSET 22
+#define CHNL_IER_OFLW_V_BUF_EN_MASK 0x400000
+#define CHNL_IER_OFLW_V_BUF_EN_ENABLE 1
+#define CHNL_IER_OFLW_PANIC_U_BUF_EN_OFFSET 21
+#define CHNL_IER_OFLW_PANIC_U_BUF_EN_MASK 0x200000
+#define CHNL_IER_OFLW_PANIC_U_BUF_EN_ENABLE 1
+#define CHNL_IER_EXCS_OFLW_U_BUF_EN_OFFSET 20
+#define CHNL_IER_EXCS_OFLW_U_BUF_EN_MASK 0x100000
+#define CHNL_IER_EXCS_OFLW_U_BUF_EN_ENABLE 1
+#define CHNL_IER_OFLW_U_BUF_EN_OFFSET 19
+#define CHNL_IER_OFLW_U_BUF_EN_MASK 0x80000
+#define CHNL_IER_OFLW_U_BUF_EN_ENABLE 1
+#define CHNL_IER_OFLW_PANIC_Y_BUF_EN_OFFSET 18
+#define CHNL_IER_OFLW_PANIC_Y_BUF_EN_MASK 0x40000
+#define CHNL_IER_OFLW_PANIC_Y_BUF_EN_ENABLE 1
+#define CHNL_IER_EXCS_OFLW_Y_BUF_EN_OFFSET 17
+#define CHNL_IER_EXCS_OFLW_Y_BUF_EN_MASK 0x20000
+#define CHNL_IER_EXCS_OFLW_Y_BUF_EN_ENABLE 1
+#define CHNL_IER_OFLW_Y_BUF_EN_OFFSET 16
+#define CHNL_IER_OFLW_Y_BUF_EN_MASK 0x10000
+#define CHNL_IER_OFLW_Y_BUF_EN_ENABLE 1
+
+/* Channel Status Register */
+#define CHNL_STS 0x14
+#define CHNL_STS_MEM_RD_DONE_OFFSET 31
+#define CHNL_STS_MEM_RD_DONE_MASK 0x80000000
+#define CHNL_STS_MEM_RD_DONE_ENABLE 1
+#define CHNL_STS_LINE_STRD_OFFSET 30
+#define CHNL_STS_LINE_STRD_MASK 0x40000000
+#define CHNL_STS_LINE_STRD_ENABLE 1
+#define CHNL_STS_FRM_STRD_OFFSET 29
+#define CHNL_STS_FRM_STRD_MASK 0x20000000
+#define CHNL_STS_FRM_STRD_ENABLE 1
+#define CHNL_STS_AXI_WR_ERR_V_OFFSET 28
+#define CHNL_STS_AXI_WR_ERR_V_MASK 0x10000000
+#define CHNL_STS_AXI_WR_ERR_V_ENABLE 1
+#define CHNL_STS_AXI_WR_ERR_U_OFFSET 27
+#define CHNL_STS_AXI_WR_ERR_U_MASK 0x8000000
+#define CHNL_STS_AXI_WR_ERR_U_ENABLE 1
+#define CHNL_STS_AXI_WR_ERR_Y_OFFSET 26
+#define CHNL_STS_AXI_WR_ERR_Y_MASK 0x4000000
+#define CHNL_STS_AXI_WR_ERR_Y_ENABLE 1
+#define CHNL_STS_AXI_RD_ERR_OFFSET 25
+#define CHNL_STS_AXI_RD_ERR_MASK 0x2000000
+#define CHNL_STS_AXI_RD_ERR_ENABLE 1
+#define CHNL_STS_OFLW_PANIC_V_BUF_OFFSET 24
+#define CHNL_STS_OFLW_PANIC_V_BUF_MASK 0x1000000
+#define CHNL_STS_OFLW_PANIC_V_BUF_ENABLE 1
+#define CHNL_STS_EXCS_OFLW_V_BUF_OFFSET 23
+#define CHNL_STS_EXCS_OFLW_V_BUF_MASK 0x800000
+#define CHNL_STS_EXCS_OFLW_V_BUF_ENABLE 1
+#define CHNL_STS_OFLW_V_BUF_OFFSET 22
+#define CHNL_STS_OFLW_V_BUF_MASK 0x400000
+#define CHNL_STS_OFLW_V_BUF_ENABLE 1
+#define CHNL_STS_OFLW_PANIC_U_BUF_OFFSET 21
+#define CHNL_STS_OFLW_PANIC_U_BUF_MASK 0x200000
+#define CHNL_STS_OFLW_PANIC_U_BUF_ENABLE 1
+#define CHNL_STS_EXCS_OFLW_U_BUF_OFFSET 20
+#define CHNL_STS_EXCS_OFLW_U_BUF_MASK 0x100000
+#define CHNL_STS_EXCS_OFLW_U_BUF_ENABLE 1
+#define CHNL_STS_OFLW_U_BUF_OFFSET 19
+#define CHNL_STS_OFLW_U_BUF_MASK 0x80000
+#define CHNL_STS_OFLW_U_BUF_ENABLE 1
+#define CHNL_STS_OFLW_PANIC_Y_BUF_OFFSET 18
+#define CHNL_STS_OFLW_PANIC_Y_BUF_MASK 0x40000
+#define CHNL_STS_OFLW_PANIC_Y_BUF_ENABLE 1
+#define CHNL_STS_EXCS_OFLW_Y_BUF_OFFSET 17
+#define CHNL_STS_EXCS_OFLW_Y_BUF_MASK 0x20000
+#define CHNL_STS_EXCS_OFLW_Y_BUF_ENABLE 1
+#define CHNL_STS_OFLW_Y_BUF_OFFSET 16
+#define CHNL_STS_OFLW_Y_BUF_MASK 0x10000
+#define CHNL_STS_OFLW_Y_BUF_ENABLE 1
+#define CHNL_STS_OFLW_BYTES_OFFSET 0
+#define CHNL_STS_OFLW_BYTES_MASK 0xFF
+
+/* Channel Scale Factor Register */
+#define CHNL_SCALE_FACTOR 0x18
+#define CHNL_SCALE_FACTOR_Y_SCALE_OFFSET 16
+#define CHNL_SCALE_FACTOR_Y_SCALE_MASK 0x3FFF0000
+#define CHNL_SCALE_FACTOR_X_SCALE_OFFSET 0
+#define CHNL_SCALE_FACTOR_X_SCALE_MASK 0x3FFF
+
+/* Channel Scale Offset Register */
+#define CHNL_SCALE_OFFSET 0x1C
+#define CHNL_SCALE_OFFSET_Y_SCALE_OFFSET 16
+#define CHNL_SCALE_OFFSET_Y_SCALE_MASK 0xFFF0000
+#define CHNL_SCALE_OFFSET_X_SCALE_OFFSET 0
+#define CHNL_SCALE_OFFSET_X_SCALE_MASK 0xFFF
+
+/* Channel Crop Upper Left Corner Coordinate Register */
+#define CHNL_CROP_ULC 0x20
+#define CHNL_CROP_ULC_X_OFFSET 16
+#define CHNL_CROP_ULC_X_MASK 0xFFF0000
+#define CHNL_CROP_ULC_Y_OFFSET 0
+#define CHNL_CROP_ULC_Y_MASK 0xFFF
+
+/* Channel Crop Lower Right Corner Coordinate Register */
+#define CHNL_CROP_LRC 0x24
+#define CHNL_CROP_LRC_X_OFFSET 16
+#define CHNL_CROP_LRC_X_MASK 0xFFF0000
+#define CHNL_CROP_LRC_Y_OFFSET 0
+#define CHNL_CROP_LRC_Y_MASK 0xFFF
+
+/* Channel Color Space Conversion Coefficient Register 0 */
+#define CHNL_CSC_COEFF0 0x28
+#define CHNL_CSC_COEFF0_A2_OFFSET 16
+#define CHNL_CSC_COEFF0_A2_MASK 0x7FF0000
+#define CHNL_CSC_COEFF0_A1_OFFSET 0
+#define CHNL_CSC_COEFF0_A1_MASK 0x7FF
+
+
+/* Channel Color Space Conversion Coefficient Register 1 */
+#define CHNL_CSC_COEFF1 0x2C
+#define CHNL_CSC_COEFF1_B1_OFFSET 16
+#define CHNL_CSC_COEFF1_B1_MASK 0x7FF0000
+#define CHNL_CSC_COEFF1_A3_OFFSET 0
+#define CHNL_CSC_COEFF1_A3_MASK 0x7FF
+
+/* Channel Color Space Conversion Coefficient Register 2 */
+#define CHNL_CSC_COEFF2 0x30
+#define CHNL_CSC_COEFF2_B3_OFFSET 16
+#define CHNL_CSC_COEFF2_B3_MASK 0x7FF0000
+#define CHNL_CSC_COEFF2_B2_OFFSET 0
+#define CHNL_CSC_COEFF2_B2_MASK 0x7FF
+
+/* Channel Color Space Conversion Coefficient Register 3 */
+#define CHNL_CSC_COEFF3 0x34
+#define CHNL_CSC_COEFF3_C2_OFFSET 16
+#define CHNL_CSC_COEFF3_C2_MASK 0x7FF0000
+#define CHNL_CSC_COEFF3_C1_OFFSET 0
+#define CHNL_CSC_COEFF3_C1_MASK 0x7FF
+
+/* Channel Color Space Conversion Coefficient Register 4 */
+#define CHNL_CSC_COEFF4 0x38
+#define CHNL_CSC_COEFF4_D1_OFFSET 16
+#define CHNL_CSC_COEFF4_D1_MASK 0x1FF0000
+#define CHNL_CSC_COEFF4_C3_OFFSET 0
+#define CHNL_CSC_COEFF4_C3_MASK 0x7FF
+
+/* Channel Color Space Conversion Coefficient Register 5 */
+#define CHNL_CSC_COEFF5 0x3C
+#define CHNL_CSC_COEFF5_D3_OFFSET 16
+#define CHNL_CSC_COEFF5_D3_MASK 0x1FF0000
+#define CHNL_CSC_COEFF5_D2_OFFSET 0
+#define CHNL_CSC_COEFF5_D2_MASK 0x1FF
+
+/* Channel Alpha Value Register for ROI 0 */
+#define CHNL_ROI_0_ALPHA 0x40
+#define CHNL_ROI_0_ALPHA_OFFSET 24
+#define CHNL_ROI_0_ALPHA_MASK 0xFF000000
+#define CHNL_ROI_0_ALPHA_EN_OFFSET 16
+#define CHNL_ROI_0_ALPHA_EN_MASK 0x10000
+
+/* Channel Upper Left Coordinate Register for ROI 0 */
+#define CHNL_ROI_0_ULC 0x44
+#define CHNL_ROI_0_ULC_X_OFFSET 16
+#define CHNL_ROI_0_ULC_X_MASK 0xFFF0000
+#define CHNL_ROI_0_ULC_Y_OFFSET 0
+#define CHNL_ROI_0_ULC_Y_MASK 0xFFF
+
+/* Channel Lower Right Coordinate Register for ROI 0 */
+#define CHNL_ROI_0_LRC 0x48
+#define CHNL_ROI_0_LRC_X_OFFSET 16
+#define CHNL_ROI_0_LRC_X_MASK 0xFFF0000
+#define CHNL_ROI_0_LRC_Y_OFFSET 0
+#define CHNL_ROI_0_LRC_Y_MASK 0xFFF
+
+/* Channel Alpha Value Register for ROI 1 */
+#define CHNL_ROI_1_ALPHA 0x4C
+#define CHNL_ROI_1_ALPHA_OFFSET 24
+#define CHNL_ROI_1_ALPHA_MASK 0xFF000000
+#define CHNL_ROI_1_ALPHA_EN_OFFSET 16
+#define CHNL_ROI_1_ALPHA_EN_MASK 0x10000
+
+/* Channel Upper Left Coordinate Register for ROI 1 */
+#define CHNL_ROI_1_ULC 0x50
+#define CHNL_ROI_1_ULC_X_OFFSET 16
+#define CHNL_ROI_1_ULC_X_MASK 0xFFF0000
+#define CHNL_ROI_1_ULC_Y_OFFSET 0
+#define CHNL_ROI_1_ULC_Y_MASK 0xFFF
+
+/* Channel Lower Right Coordinate Register for ROI 1 */
+#define CHNL_ROI_1_LRC 0x54
+#define CHNL_ROI_1_LRC_X_OFFSET 16
+#define CHNL_ROI_1_LRC_X_MASK 0xFFF0000
+#define CHNL_ROI_1_LRC_Y_OFFSET 0
+#define CHNL_ROI_1_LRC_Y_MASK 0xFFF
+
+/* Channel Alpha Value Register for ROI 2 */
+#define CHNL_ROI_2_ALPHA 0x58
+#define CHNL_ROI_2_ALPHA_OFFSET 24
+#define CHNL_ROI_2_ALPHA_MASK 0xFF000000
+#define CHNL_ROI_2_ALPHA_EN_OFFSET 16
+#define CHNL_ROI_2_ALPHA_EN_MASK 0x10000
+
+/* Channel Upper Left Coordinate Register for ROI 2 */
+#define CHNL_ROI_2_ULC 0x5C
+#define CHNL_ROI_2_ULC_X_OFFSET 16
+#define CHNL_ROI_2_ULC_X_MASK 0xFFF0000
+#define CHNL_ROI_2_ULC_Y_OFFSET 0
+#define CHNL_ROI_2_ULC_Y_MASK 0xFFF
+
+/* Channel Lower Right Coordinate Register for ROI 2 */
+#define CHNL_ROI_2_LRC 0x60
+#define CHNL_ROI_2_LRC_X_OFFSET 16
+#define CHNL_ROI_2_LRC_X_MASK 0xFFF0000
+#define CHNL_ROI_2_LRC_Y_OFFSET 0
+#define CHNL_ROI_2_LRC_Y_MASK 0xFFF
+
+/* Channel Alpha Value Register for ROI 3 */
+#define CHNL_ROI_3_ALPHA 0x64
+#define CHNL_ROI_3_ALPHA_OFFSET 24
+#define CHNL_ROI_3_ALPHA_MASK 0xFF000000
+#define CHNL_ROI_3_ALPHA_EN_OFFSET 16
+#define CHNL_ROI_3_ALPHA_EN_MASK 0x10000
+
+/* Channel Upper Left Coordinate Register for ROI 3 */
+#define CHNL_ROI_3_ULC 0x68
+#define CHNL_ROI_3_ULC_X_OFFSET 16
+#define CHNL_ROI_3_ULC_X_MASK 0xFFF0000
+#define CHNL_ROI_3_ULC_Y_OFFSET 0
+#define CHNL_ROI_3_ULC_Y_MASK 0xFFF
+
+/* Channel Lower Right Coordinate Register for ROI 3 */
+#define CHNL_ROI_3_LRC 0x6C
+#define CHNL_ROI_3_LRC_X_OFFSET 16
+#define CHNL_ROI_3_LRC_X_MASK 0xFFF0000
+#define CHNL_ROI_3_LRC_Y_OFFSET 0
+#define CHNL_ROI_3_LRC_Y_MASK 0xFFF
+
+/* Channel RGB or Luma (Y) Output Buffer 1 Address */
+#define CHNL_OUT_BUF1_ADDR_Y 0x70
+
+/* Channel Chroma (U/Cb/UV/CbCr) Output Buffer 1 Address */
+#define CHNL_OUT_BUF1_ADDR_U 0x74
+
+/* Channel Chroma (V/Cr) Output Buffer 1 Address */
+#define CHNL_OUT_BUF1_ADDR_V 0x78
+
+/* Channel Output Buffer Pitch */
+#define CHNL_OUT_BUF_PITCH 0x7C
+#define CHNL_OUT_BUF_PITCH_LINE_PITCH_OFFSET 0
+#define CHNL_OUT_BUF_PITCH_LINE_PITCH_MASK 0xFFFF
+
+/* Channel Input Buffer Address */
+#define CHNL_IN_BUF_ADDR 0x80
+
+/* Channel Input Buffer Pitch */
+#define CHNL_IN_BUF_PITCH 0x84
+#define CHNL_IN_BUF_PITCH_FRM_PITCH_OFFSET 16
+#define CHNL_IN_BUF_PITCH_FRM_PITCH_MASK 0xFFFF0000
+#define CHNL_IN_BUF_PITCH_LINE_PITCH_OFFSET 0
+#define CHNL_IN_BUF_PITCH_LINE_PITCH_MASK 0xFFFF
+
+/* Channel Memory Read Control */
+#define CHNL_MEM_RD_CTRL 0x88
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_OFFSET 28
+#define CHNL_MEM_RD_CTRL_IMG_TYPE_MASK 0xF0000000
+#define CHNL_MEM_RD_CTRL_READ_MEM_OFFSET 0
+#define CHNL_MEM_RD_CTRL_READ_MEM_MASK 1
+#define CHNL_MEM_RD_CTRL_READ_MEM_ENABLE 1
+
+/* Channel RGB or Luma (Y) Output Buffer 2 Address */
+#define CHNL_OUT_BUF2_ADDR_Y 0x8C
+
+/* Channel Chroma (U/Cb/UV/CbCr) Output Buffer 2 Address */
+#define CHNL_OUT_BUF2_ADDR_U 0x90
+
+/* Channel Chroma (V/Cr) Output Buffer 2 Address */
+#define CHNL_OUT_BUF2_ADDR_V 0x94
+
+enum isi_csi_coeff {
+ YUV2RGB = 0,
+ RGB2YUV,
+};
+
+
+void mxc_isi_channel_init(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_deinit(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_config(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_enable(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_disable(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_set_outbuf(struct mxc_isi_dev *mxc_isi, struct mxc_isi_buffer *buf);
+void mxc_isi_frame_write_done(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_frame_read_done(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_set_deinterlace(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_sw_reset(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_hw_reset(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_source_config(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_set_flip(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_set_csc(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_set_alpha_roi0(struct mxc_isi_dev *mxc_isi, struct v4l2_rect *rect);
+void mxc_isi_channel_set_alpha(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_set_chain_buf(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_set_deinterlace(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_set_crop(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_set_memory_image(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_channel_set_scaler(struct mxc_isi_dev *mxc_isi);
+
+void mxc_isi_clean_irq_status(struct mxc_isi_dev *mxc_isi, u32 val);
+u32 mxc_isi_get_irq_status(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_enable_irq(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_disable_irq(struct mxc_isi_dev *mxc_isi);
+
+void dump_isi_regs(struct mxc_isi_dev *mxc_isi);
+#endif /* MXC_ISI_HW_H_ */
diff --git a/drivers/media/platform/imx8/mxc-jpeg-hw.c b/drivers/media/platform/imx8/mxc-jpeg-hw.c
new file mode 100644
index 000000000000..2263ec426790
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-jpeg-hw.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2018 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/delay.h>
+#include <media/videobuf2-core.h>
+#include "mxc-jpeg-hw.h"
+
+#define print_wrapper_reg(dev, base_address, reg_offset)\
+ internal_print_wrapper_reg(dev, (base_address), #reg_offset,\
+ (reg_offset))
+#define internal_print_wrapper_reg(dev, base_address, reg_name, reg_offset) {\
+ int val;\
+ val = readl((base_address) + (reg_offset));\
+ dev_dbg(dev, "Wrapper reg %s = 0x%x\n", reg_name, val);\
+}
+
+void print_descriptor_info(struct device *dev, struct mxc_jpeg_desc *desc)
+{
+ dev_dbg(dev, " MXC JPEG NEXT_DESCPT_PTR 0x%x\n",
+ desc->next_descpt_ptr);
+ dev_dbg(dev, " MXC JPEG BUF_BASE0 0x%x\n", desc->buf_base0);
+ dev_dbg(dev, " MXC JPEG BUF_BASE1 0x%x\n", desc->buf_base1);
+ dev_dbg(dev, " MXC JPEG LINE_PITCH %d\n", desc->line_pitch);
+ dev_dbg(dev, " MXC JPEG STM_BUFBASE 0x%x\n", desc->stm_bufbase);
+ dev_dbg(dev, " MXC JPEG STM_BUFSIZE %d\n", desc->stm_bufsize);
+ dev_dbg(dev, " MXC JPEG IMGSIZE %x (%d x %d)\n", desc->imgsize,
+ desc->imgsize >> 16, desc->imgsize & 0xFFFF);
+ dev_dbg(dev, " MXC JPEG STM_CTRL 0x%x\n", desc->stm_ctrl);
+}
+
+void print_cast_status(struct device *dev, void __iomem *reg, unsigned int mode)
+{
+ dev_dbg(dev, "CAST IP status regs:\n");
+ print_wrapper_reg(dev, reg, CAST_STATUS0);
+ print_wrapper_reg(dev, reg, CAST_STATUS1);
+ print_wrapper_reg(dev, reg, CAST_STATUS2);
+ print_wrapper_reg(dev, reg, CAST_STATUS3);
+ print_wrapper_reg(dev, reg, CAST_STATUS4);
+ print_wrapper_reg(dev, reg, CAST_STATUS5);
+ print_wrapper_reg(dev, reg, CAST_STATUS6);
+ print_wrapper_reg(dev, reg, CAST_STATUS7);
+ print_wrapper_reg(dev, reg, CAST_STATUS8);
+ print_wrapper_reg(dev, reg, CAST_STATUS9);
+ print_wrapper_reg(dev, reg, CAST_STATUS10);
+ print_wrapper_reg(dev, reg, CAST_STATUS11);
+ print_wrapper_reg(dev, reg, CAST_STATUS12);
+ print_wrapper_reg(dev, reg, CAST_STATUS13);
+ if (mode == MXC_JPEG_DECODE)
+ return;
+ print_wrapper_reg(dev, reg, CAST_STATUS14);
+ print_wrapper_reg(dev, reg, CAST_STATUS15);
+ print_wrapper_reg(dev, reg, CAST_STATUS16);
+ print_wrapper_reg(dev, reg, CAST_STATUS17);
+ print_wrapper_reg(dev, reg, CAST_STATUS18);
+ print_wrapper_reg(dev, reg, CAST_STATUS19);
+}
+
+void print_wrapper_info(struct device *dev, void __iomem *reg)
+{
+ dev_dbg(dev, "Wrapper regs:\n");
+ print_wrapper_reg(dev, reg, GLB_CTRL);
+ print_wrapper_reg(dev, reg, COM_STATUS);
+ print_wrapper_reg(dev, reg, BUF_BASE0);
+ print_wrapper_reg(dev, reg, BUF_BASE1);
+ print_wrapper_reg(dev, reg, LINE_PITCH);
+ print_wrapper_reg(dev, reg, STM_BUFBASE);
+ print_wrapper_reg(dev, reg, STM_BUFSIZE);
+ print_wrapper_reg(dev, reg, IMGSIZE);
+ print_wrapper_reg(dev, reg, STM_CTRL);
+}
+
+void mxc_jpeg_enable_irq(void __iomem *reg, int slot)
+{
+ writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN));
+}
+
+void mxc_jpeg_sw_reset(void __iomem *reg)
+{
+ /*
+ * engine soft reset, internal state machine reset
+ * this will not reset registers, however, it seems
+ * the registers may remain inconsistent with the internal state
+ * so, on purpose, at least let GLB_CTRL bits clear after this reset
+ */
+ writel(GLB_CTRL_SFT_RST, reg + GLB_CTRL);
+}
+
+u32 mxc_jpeg_get_offset(void __iomem *reg, int slot)
+{
+ return readl(reg + MXC_SLOT_OFFSET(slot, SLOT_BUF_PTR));
+}
+
+void mxc_jpeg_go_enc(struct device *dev, void __iomem *reg)
+{
+ dev_dbg(dev, "CAST Encoder GO...\n");
+ /*
+ * "Config_Mode" enabled, "Config_Mode auto clear enabled",
+ * "GO" enabled, "GO bit auto clear" enabled
+ */
+ writel(0x1e0, reg + CAST_MODE);
+
+ /* all markers and segments */
+ writel(0x3ff, reg + CAST_CFG_MODE);
+
+ /* quality factor */
+ writel(0x4b, reg + CAST_QUALITY);
+}
+
+void wait_frmdone(struct device *dev, void __iomem *reg)
+{
+ u32 regval = 0;
+
+ do {
+ regval = readl(reg + MXC_SLOT_OFFSET(0, SLOT_STATUS));
+ } while (!(regval & SLOTa_STATUS_FRMDONE));
+
+ writel(regval, reg + MXC_SLOT_OFFSET(0, SLOT_STATUS)); /* w1c */
+
+ dev_dbg(dev, "Received FRMDONE\n");
+ if (regval & SLOTa_STATUS_ENC_CONFIG_ERR)
+ dev_info(dev, "SLOTa_STATUS_ENC_CONFIG_ERR\n");
+}
+
+int mxc_jpeg_enable(void __iomem *reg)
+{
+ u32 regval;
+
+ writel(GLB_CTRL_JPG_EN, reg + GLB_CTRL);
+ regval = readl(reg);
+ return regval;
+}
+
+void mxc_jpeg_go_dec(struct device *dev, void __iomem *reg)
+{
+ dev_dbg(dev, "CAST Decoder GO...\n");
+ writel(MXC_DEC_EXIT_IDLE_MODE, reg + CAST_CTRL);
+}
+
+int mxc_jpeg_get_slot(void __iomem *reg)
+{
+ int slot_val;
+ int i = 0;
+ int tmp = GLB_CTRL_SLOT_EN(0);
+
+ /* currently enabled slots */
+ slot_val = readl(reg + GLB_CTRL) & 0xF0;
+
+ for (; tmp != tmp << 4; tmp = tmp << 1) {
+ if ((slot_val & tmp) == 0)
+ /* first free slot */
+ return i;
+ ++i;
+ }
+ return -EINVAL;
+}
+
+void mxc_jpeg_enable_slot(void __iomem *reg, int slot)
+{
+ u32 regval;
+
+ regval = readl(reg + GLB_CTRL);
+ writel(GLB_CTRL_SLOT_EN(slot) | regval, reg + GLB_CTRL);
+}
+
+void mxc_jpeg_set_l_endian(void __iomem *reg, int le)
+{
+ u32 regval;
+
+ regval = readl(reg + GLB_CTRL);
+ regval &= ~GLB_CTRL_L_ENDIAN(1); /* clear */
+ writel(GLB_CTRL_L_ENDIAN(le) | regval, reg + GLB_CTRL); /* set */
+}
+
+void mxc_jpeg_set_config_mode(void __iomem *reg, int config_mode)
+{
+ u32 regval;
+
+ regval = readl(reg + STM_CTRL);
+ regval &= ~STM_CTRL_CONFIG_MOD(1);
+ writel(STM_CTRL_CONFIG_MOD(config_mode) | regval, reg + STM_CTRL);
+}
+
+int mxc_jpeg_set_params(struct mxc_jpeg_desc *desc, u32 bufsize,
+ u16 out_pitch, u32 format)
+{
+ desc->line_pitch = out_pitch;
+ desc->stm_bufsize = bufsize;
+ switch (format) {
+ case V4L2_PIX_FMT_YUV32:
+ desc->stm_ctrl |= MXC_JPEG_YUV444 << 3;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ desc->stm_ctrl |= MXC_JPEG_YUV422 << 3;
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ desc->stm_ctrl |= MXC_JPEG_RGB << 3;
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+void mxc_jpeg_set_bufsize(struct mxc_jpeg_desc *desc, u32 bufsize)
+{
+ desc->stm_bufsize = bufsize;
+}
+
+void mxc_jpeg_set_res(struct mxc_jpeg_desc *desc, u16 w, u16 h)
+{
+ desc->imgsize = w << 16 | h;
+}
+
+
+void mxc_jpeg_set_line_pitch(struct mxc_jpeg_desc *desc, u32 line_pitch)
+{
+ desc->line_pitch = line_pitch;
+}
+
+void mxc_jpeg_set_desc(u32 desc, void __iomem *reg, int slot)
+{
+ writel(desc | MXC_NXT_DESCPT_EN,
+ reg + MXC_SLOT_OFFSET(slot, SLOT_NXT_DESCPT_PTR));
+}
+
+void mxc_jpeg_set_regs_from_desc(struct mxc_jpeg_desc *desc, void __iomem *reg)
+{
+ writel(desc->buf_base0, reg + BUF_BASE0);
+ writel(desc->buf_base1, reg + BUF_BASE1);
+ writel(desc->line_pitch, reg + LINE_PITCH);
+ writel(desc->stm_bufbase, reg + STM_BUFBASE);
+ writel(desc->stm_bufsize, reg + STM_BUFSIZE);
+ writel(desc->imgsize, reg + IMGSIZE);
+ writel(desc->stm_ctrl, reg + STM_CTRL);
+}
diff --git a/drivers/media/platform/imx8/mxc-jpeg-hw.h b/drivers/media/platform/imx8/mxc-jpeg-hw.h
new file mode 100644
index 000000000000..ce158c8cc8cc
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-jpeg-hw.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2018 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef _MXC_JPEG_HW_H
+#define _MXC_JPEG_HW_H
+
+#define MXC_JPEG_DECODE 0
+#define MXC_JPEG_ENCODE 1
+
+/* JPEG Decoder/Encoder Wrapper Register Map */
+#define GLB_CTRL 0x0
+#define COM_STATUS 0x4
+#define BUF_BASE0 0x14
+#define BUF_BASE1 0x18
+#define LINE_PITCH 0x1C
+#define STM_BUFBASE 0x20
+#define STM_BUFSIZE 0x24
+#define IMGSIZE 0x28
+#define STM_CTRL 0x2C
+
+/* CAST JPEG-Decoder/Encoder Status Register Map (read-only)*/
+#define CAST_STATUS0 0x100
+#define CAST_STATUS1 0x104
+#define CAST_STATUS2 0x108
+#define CAST_STATUS3 0x10c
+#define CAST_STATUS4 0x110
+#define CAST_STATUS5 0x114
+#define CAST_STATUS6 0x118
+#define CAST_STATUS7 0x11c
+#define CAST_STATUS8 0x120
+#define CAST_STATUS9 0x124
+#define CAST_STATUS10 0x128
+#define CAST_STATUS11 0x12c
+#define CAST_STATUS12 0x130
+#define CAST_STATUS13 0x134
+/* the following are for encoder only */
+#define CAST_STATUS14 0x138
+#define CAST_STATUS15 0x13c
+#define CAST_STATUS16 0x140
+#define CAST_STATUS17 0x144
+#define CAST_STATUS18 0x148
+#define CAST_STATUS19 0x14c
+
+/* CAST JPEG-Decoder Control Register Map (write-only) */
+#define CAST_CTRL CAST_STATUS13
+
+/* CAST JPEG-Encoder Control Register Map (write-only) */
+#define CAST_MODE CAST_STATUS0
+#define CAST_CFG_MODE CAST_STATUS1
+#define CAST_QUALITY CAST_STATUS2
+#define CAST_RSVD CAST_STATUS3
+#define CAST_REC_REGS_SEL CAST_STATUS4
+#define CAST_LUMTH CAST_STATUS5
+#define CAST_CHRTH CAST_STATUS6
+#define CAST_NOMFRSIZE_LO CAST_STATUS7
+#define CAST_NOMFRSIZE_HI CAST_STATUS8
+#define CAST_OFBSIZE_LO CAST_STATUS9
+#define CAST_OFBSIZE_HI CAST_STATUS10
+
+#define MXC_MAX_SLOTS 1 /* TODO use all 4 slots*/
+/* JPEG-Decoder Wrapper Slot Registers 0..3 */
+#define SLOT_BASE 0x10000
+#define SLOT_STATUS 0x0
+#define SLOT_IRQ_EN 0x4
+#define SLOT_BUF_PTR 0x8
+#define SLOT_CUR_DESCPT_PTR 0xC
+#define SLOT_NXT_DESCPT_PTR 0x10
+#define MXC_SLOT_OFFSET(slot, offset) ((SLOT_BASE * (slot + 1)) + offset)
+
+/* GLB_CTRL fields */
+#define GLB_CTRL_JPG_EN 0x1
+#define GLB_CTRL_SFT_RST (0x1 << 1)
+#define GLB_CTRL_DEC_GO (0x1 << 2)
+#define GLB_CTRL_L_ENDIAN(le) ((le) << 3)
+#define GLB_CTRL_SLOT_EN(slot) (0x1 << (slot + 4))
+
+/* STM_CTRL fields */
+#define STM_CTRL_PIXEL_PRECISION (0x1 << 2)
+#define STM_CTRL_IMAGE_FORMAT(img_fmt) ((img_fmt) << 3)
+#define STM_CTRL_BITBUF_PTR_CLR(clr) ((clr) << 7)
+#define STM_CTRL_AUTO_START(go) ((go) << 8)
+#define STM_CTRL_CONFIG_MOD(mod) ((mod) << 9)
+
+/* SLOTa_STATUS fields TBD */
+#define SLOTa_STATUS_FRMDONE (0x1 << 3)
+#define SLOTa_STATUS_ENC_CONFIG_ERR (0x1 << 8)
+
+/* SLOTa_IRQ_EN fields TBD */
+
+#define MXC_NXT_DESCPT_EN 0x1
+#define MXC_DEC_EXIT_IDLE_MODE 0x4
+
+/* JPEG-Decoder Wrapper - STM_CTRL Register Fields */
+#define MXC_PIXEL_PRECISION(precision) ((precision)/8 << 2)
+enum mxc_jpeg_image_format {
+ MXC_JPEG_YUV420 = 0x0, /* 2 Plannar, Y=1st plane UV=2nd plane */
+ MXC_JPEG_YUV422 = 0x1, /* 1 Plannar, YUYV sequence */
+ MXC_JPEG_RGB = 0x2, /* RGBRGB packed format */
+ MXC_JPEG_YUV444 = 0x3, /* 1 Plannar, YUVYUV sequence */
+ MXC_JPEG_GRAY = 0x4, /* Y8 or Y12 or Single Component */
+ MXC_JPEG_RESERVED = 0x5,
+ MXC_JPEG_ARGB = 0x6,
+};
+
+
+#include "mxc-jpeg.h"
+void print_descriptor_info(struct device *dev, struct mxc_jpeg_desc *desc);
+void print_cast_status(struct device *dev, void __iomem *reg,
+ unsigned int mode);
+void print_wrapper_info(struct device *dev, void __iomem *reg);
+void mxc_jpeg_sw_reset(void __iomem *reg);
+int mxc_jpeg_enable(void __iomem *reg);
+void wait_frmdone(struct device *dev, void __iomem *reg);
+void mxc_jpeg_go_enc(struct device *dev, void __iomem *reg);
+void mxc_jpeg_go_dec(struct device *dev, void __iomem *reg);
+int mxc_jpeg_get_slot(void __iomem *reg);
+u32 mxc_jpeg_get_offset(void __iomem *reg, int slot);
+void mxc_jpeg_enable_slot(void __iomem *reg, int slot);
+void mxc_jpeg_set_l_endian(void __iomem *reg, int le);
+void mxc_jpeg_enable_irq(void __iomem *reg, int slot);
+int mxc_jpeg_set_input(void __iomem *reg, u32 in_buf, u32 bufsize);
+int mxc_jpeg_set_output(void __iomem *reg, u16 out_pitch, u32 out_buf,
+ u16 w, u16 h);
+void mxc_jpeg_set_config_mode(void __iomem *reg, int config_mode);
+int mxc_jpeg_set_params(struct mxc_jpeg_desc *desc, u32 bufsize, u16
+ out_pitch, u32 format);
+void mxc_jpeg_set_bufsize(struct mxc_jpeg_desc *desc, u32 bufsize);
+void mxc_jpeg_set_res(struct mxc_jpeg_desc *desc, u16 w, u16 h);
+void mxc_jpeg_set_line_pitch(struct mxc_jpeg_desc *desc, u32 line_pitch);
+void mxc_jpeg_set_desc(u32 desc, void __iomem *reg, int slot);
+void mxc_jpeg_set_regs_from_desc(struct mxc_jpeg_desc *desc, void __iomem *reg);
+#endif
diff --git a/drivers/media/platform/imx8/mxc-jpeg.c b/drivers/media/platform/imx8/mxc-jpeg.c
new file mode 100644
index 000000000000..4d203a6ea96d
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-jpeg.c
@@ -0,0 +1,1358 @@
+/*
+ * Copyright 2018 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/irqreturn.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/string.h>
+
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "mxc-jpeg-hw.h"
+#include "mxc-jpeg.h"
+
+static struct mxc_jpeg_fmt mxc_formats[] = {
+ {
+ .name = "JPEG",
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .colplanes = 1,
+ .flags = MXC_JPEG_FMT_TYPE_ENC,
+ },
+ {
+ .name = "RGB32",
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .depth = 32,
+ .colplanes = 1,
+ .h_align = 0,
+ .v_align = 0,
+ .flags = MXC_JPEG_FMT_TYPE_RAW,
+ },
+ {
+ .name = "YUV422",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ .colplanes = 1,
+ .h_align = 2,
+ .v_align = 0,
+ .flags = MXC_JPEG_FMT_TYPE_RAW,
+ },
+ {
+ .name = "YUV444",
+ .fourcc = V4L2_PIX_FMT_YUV32,
+ .depth = 32,
+ .colplanes = 1,
+ .h_align = 0,
+ .v_align = 0,
+ .flags = MXC_JPEG_FMT_TYPE_RAW,
+ },
+};
+
+static const struct of_device_id mxc_jpeg_match[] = {
+ {
+ .compatible = "fsl,imx8-jpgdec",
+ .data = (void *)MXC_JPEG_DECODE,
+ },
+ {
+ .compatible = "fsl,imx8-jpgenc",
+ .data = (void *)MXC_JPEG_ENCODE,
+ },
+ { },
+};
+
+static const unsigned char hactbl[615] = {
+0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A,
+0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00,
+0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xFF,
+0xDB, 0x00, 0x84, 0x00, 0x10, 0x0B, 0x0C,
+0x0E, 0x0C, 0x0A, 0x10, 0x0E, 0x0D, 0x0E,
+0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1A,
+0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
+0x1D, 0x28, 0x3A, 0x33, 0x3D, 0x3C, 0x39,
+0x33, 0x38, 0x37, 0x40, 0x48, 0x5C, 0x4E,
+0x40, 0x44, 0x57, 0x45, 0x37, 0x38, 0x50,
+0x6D, 0x51, 0x57, 0x5F, 0x62, 0x67, 0x68,
+0x67, 0x3E, 0x4D, 0x71, 0x79, 0x70, 0x64,
+0x78, 0x5C, 0x65, 0x67, 0x63, 0x01, 0x11,
+0x12, 0x12, 0x18, 0x15, 0x18, 0x2F, 0x1A,
+0x1A, 0x2F, 0x63, 0x42, 0x38, 0x42, 0x63,
+0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0x40,
+0x00, 0x40, 0x03, 0x01, 0x21, 0x00, 0x02,
+0x11, 0x01, 0x03, 0x11, 0x01, 0xFF, 0xC4,
+0x01, 0xA2, 0x00, 0x00, 0x01, 0x05, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+0x09, 0x0A, 0x0B, 0x10, 0x00, 0x02, 0x01,
+0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05,
+0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 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,
+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,
+0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
+0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
+0x0B, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04,
+0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04,
+0x00, 0x01, 0x02, 0x77, 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, 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, 0xFF, 0xDD,
+0x00, 0x04, 0x00, 0x20, 0xFF, 0xDA, 0x00,
+0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
+0x11, 0x00, 0x3F, 0x00, 0xFF, 0xD9
+};
+
+static void print_buf(struct device *dev, struct vb2_buffer *buf)
+{
+ void *testaddri;
+ char *data;
+ u32 dma_addr;
+
+ testaddri = vb2_plane_vaddr(buf, 0);
+ dma_addr = vb2_dma_contig_plane_dma_addr(buf, 0);
+ data = (char *)testaddri;
+
+ /* print just the first 4 bytes from the beginning of the buffer */
+ dev_dbg(dev, "vaddr=%p dma_addr=%x: %x %x %x %x ...\n",
+ testaddri, dma_addr,
+ data[0], data[1], data[2], data[3]);
+}
+
+#define MXC_NUM_FORMATS ARRAY_SIZE(mxc_formats)
+static inline u32 mxc_jpeg_align(u32 val, u32 align)
+{
+ return (val + align - 1) & ~(align - 1);
+}
+
+
+static inline struct mxc_jpeg_ctx *mxc_jpeg_fh_to_ctx(struct v4l2_fh *fh)
+{
+ return container_of(fh, struct mxc_jpeg_ctx, fh);
+}
+
+
+static int enum_fmt(struct mxc_jpeg_fmt *mxc_formats, int n,
+ struct v4l2_fmtdesc *f, u32 type)
+{
+ int i, num = 0;
+
+ for (i = 0; i < n; ++i) {
+ if (mxc_formats[i].flags == 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;
+ }
+ }
+
+ /* Format not found */
+ if (i >= n)
+ return -EINVAL;
+
+ strlcpy(f->description, mxc_formats[i].name, sizeof(f->description));
+ f->pixelformat = mxc_formats[i].fourcc;
+
+ return 0;
+}
+
+static void mxc_jpeg_addrs(struct mxc_jpeg_desc *desc,
+ struct vb2_buffer *b_base0_buf,
+ struct vb2_buffer *bufbase_buf, int offset)
+{
+ desc->buf_base0 = vb2_dma_contig_plane_dma_addr(b_base0_buf, 0);
+ desc->buf_base1 = 0; /* TODO for YUV420*/
+ desc->stm_bufbase = vb2_dma_contig_plane_dma_addr(bufbase_buf, 0) +
+ offset;
+}
+
+static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
+{
+ struct mxc_jpeg_dev *jpeg = priv;
+ struct mxc_jpeg_ctx *ctx;
+ void __iomem *reg = jpeg->base_reg;
+ struct device *dev = jpeg->dev;
+ struct vb2_buffer *src_buf, *dst_buf;
+ u32 dec_ret;
+ int slot = 0; /* TODO remove hardcoded slot 0 */
+
+ spin_lock(&jpeg->hw_lock);
+
+ ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
+ if (!ctx) {
+ dev_err(dev,
+ "Instance released before the end of transaction.\n");
+ goto job_unlock;
+ }
+ if (ctx->aborting) {
+ dev_dbg(dev, "Aborting current job\n");
+ mxc_jpeg_sw_reset(reg);
+ goto job_finish;
+ }
+
+ dec_ret = readl(reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS));
+ writel(dec_ret, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS)); /* w1c */
+ if (!(dec_ret & SLOTa_STATUS_FRMDONE))
+ goto job_unlock;
+
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+
+ if (ctx->mode == MXC_JPEG_ENCODE
+ && ctx->enc_state == MXC_JPEG_ENC_CONF) {
+ ctx->enc_state = MXC_JPEG_ENC_DONE;
+ if (dec_ret & SLOTa_STATUS_ENC_CONFIG_ERR) {
+ dev_err(dev, "Encoder config finished with errors.\n");
+ goto job_finish;
+ }
+
+ dev_dbg(dev, "Encoder config finished. Start encoding...\n");
+ goto job_unlock;
+ }
+ if (ctx->mode == MXC_JPEG_ENCODE)
+ dev_dbg(dev, "Encoding finished\n");
+ else
+ dev_dbg(dev, "Decoding finished\n");
+
+ /* short preview of the results */
+ dev_dbg(dev, "src_buf preview: ");
+ print_buf(dev, src_buf);
+ dev_dbg(dev, "dst_buf preview: ");
+ print_buf(dev, dst_buf);
+
+ v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), VB2_BUF_STATE_DONE);
+job_finish:
+ v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+job_unlock:
+ spin_unlock(&jpeg->hw_lock);
+ return IRQ_HANDLED;
+}
+
+static void mxc_jpeg_config_dec_desc(struct vb2_buffer *out_buf,
+ int slot,
+ struct mxc_jpeg_dev *jpeg,
+ struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf)
+{
+ void __iomem *reg = jpeg->base_reg;
+ struct mxc_jpeg_desc *desc = jpeg->slot_data[slot].desc;
+ dma_addr_t desc_handle = jpeg->slot_data[slot].desc_handle;
+
+ mxc_jpeg_addrs(desc, dst_buf, src_buf, 0);
+ mxc_jpeg_set_bufsize(desc,
+ mxc_jpeg_align(vb2_plane_size(src_buf, 0), 1024));
+ print_descriptor_info(jpeg->dev, desc);
+
+ /* validate the decoding descriptor */
+ mxc_jpeg_set_desc(desc_handle, reg, slot);
+}
+
+static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf,
+ int slot,
+ struct mxc_jpeg_dev *jpeg,
+ struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf)
+{
+ void __iomem *reg = jpeg->base_reg;
+ struct mxc_jpeg_desc *desc = jpeg->slot_data[slot].desc;
+ struct mxc_jpeg_desc *cfg_desc = jpeg->slot_data[slot].cfg_desc;
+ dma_addr_t desc_handle = jpeg->slot_data[slot].desc_handle;
+ dma_addr_t cfg_desc_handle = jpeg->slot_data[slot].cfg_desc_handle;
+
+
+ /* chain the config descriptor with the encoding descriptor */
+ cfg_desc->next_descpt_ptr = desc_handle | MXC_NXT_DESCPT_EN;
+
+ cfg_desc->buf_base0 = jpeg->slot_data[slot].cfg_stream_handle;
+ cfg_desc->buf_base1 = 0;
+ cfg_desc->line_pitch = 0;
+ cfg_desc->stm_bufbase = 0;
+ cfg_desc->stm_bufsize = 0x2000;
+ cfg_desc->imgsize = 0;
+ cfg_desc->stm_ctrl = STM_CTRL_CONFIG_MOD(1);
+
+ desc->next_descpt_ptr = 0; /* end of chain */
+ mxc_jpeg_addrs(desc, src_buf, dst_buf, 0);
+ /* TODO remove hardcodings*/
+ mxc_jpeg_set_bufsize(desc, 0x1000);
+ mxc_jpeg_set_res(desc, 64, 64);
+ mxc_jpeg_set_line_pitch(desc, 64 * 2);
+ desc->stm_ctrl = STM_CTRL_CONFIG_MOD(0) |
+ STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV422);
+
+ dev_dbg(jpeg->dev, "cfg_desc - 0x%llx:\n", cfg_desc_handle);
+ print_descriptor_info(jpeg->dev, cfg_desc);
+ dev_dbg(jpeg->dev, "enc desc - 0x%llx:\n", desc_handle);
+ print_descriptor_info(jpeg->dev, desc);
+ print_wrapper_info(jpeg->dev, reg);
+ print_cast_status(jpeg->dev, reg, MXC_JPEG_ENCODE);
+
+ /* validate the configuration descriptor */
+ mxc_jpeg_set_desc(cfg_desc_handle, reg, slot);
+}
+
+static void mxc_jpeg_device_run(void *priv)
+{
+ struct mxc_jpeg_ctx *ctx = priv;
+ struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
+ void __iomem *reg = jpeg->base_reg;
+ struct device *dev = jpeg->dev;
+ struct vb2_buffer *src_buf, *dst_buf;
+ unsigned long flags;
+ int slot = 0;
+
+ spin_lock_irqsave(&ctx->mxc_jpeg->hw_lock, flags);
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ if (!src_buf || !dst_buf) {
+ dev_err(dev, "Null src or dst buf\n");
+ goto end;
+ }
+
+ mxc_jpeg_sw_reset(reg);
+ mxc_jpeg_enable(reg);
+ mxc_jpeg_set_l_endian(reg, 1);
+
+ slot = 0; /* TODO get slot */
+ mxc_jpeg_enable_slot(reg, slot);
+ mxc_jpeg_enable_irq(reg, slot);
+
+ if (ctx->mode == MXC_JPEG_ENCODE) {
+ dev_dbg(dev, "Encoding on slot %d\n", slot);
+ ctx->enc_state = MXC_JPEG_ENC_CONF;
+ mxc_jpeg_config_enc_desc(dst_buf, slot, jpeg, src_buf, dst_buf);
+ mxc_jpeg_go_enc(dev, reg);
+ } else {
+ dev_dbg(dev, "Decoding on slot %d\n", slot);
+ mxc_jpeg_config_dec_desc(dst_buf, slot, jpeg, src_buf, dst_buf);
+ mxc_jpeg_go_dec(dev, reg);
+ }
+end:
+ spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
+}
+
+static int mxc_jpeg_job_ready(void *priv)
+{
+ struct mxc_jpeg_ctx *ctx = priv;
+ unsigned int num_src_bufs_ready;
+ unsigned int num_dst_bufs_ready;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctx->mxc_jpeg->hw_lock, flags);
+
+ num_src_bufs_ready = v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx);
+ num_dst_bufs_ready = v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx);
+
+ spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
+
+ if (num_src_bufs_ready >= 1 && num_dst_bufs_ready >= 1)
+ return 1;
+ return 0;
+}
+static void mxc_jpeg_job_abort(void *priv)
+{
+ struct mxc_jpeg_ctx *ctx = priv;
+
+ ctx->aborting = 1;
+ dev_dbg(ctx->mxc_jpeg->dev, "Abort requested\n");
+}
+
+static struct mxc_jpeg_q_data *mxc_jpeg_get_q_data(struct mxc_jpeg_ctx *ctx,
+ enum v4l2_buf_type type)
+{
+ if (V4L2_TYPE_IS_OUTPUT(type))
+ return &ctx->out_q;
+ return &ctx->cap_q;
+}
+
+static int mxc_jpeg_queue_setup(struct vb2_queue *q,
+ unsigned int *num_buffers,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ struct device *alloc_ctxs[])
+{
+ struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+ struct mxc_jpeg_q_data *q_data = NULL;
+
+ q_data = mxc_jpeg_get_q_data(ctx, q->type);
+ if (!q_data)
+ return -EINVAL;
+ *num_planes = 1;
+ sizes[0] = 10;
+
+ if (q_data->sizeimage[0] > 0)
+ sizes[0] = q_data->sizeimage[0];
+
+ return 0;
+}
+static int mxc_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+ int ret;
+
+ dev_dbg(ctx->mxc_jpeg->dev, "Start streaming\n");
+ ret = pm_runtime_get_sync(ctx->mxc_jpeg->dev);
+ return ret > 0 ? 0 : ret;
+}
+
+static void mxc_jpeg_stop_streaming(struct vb2_queue *q)
+{
+ struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+
+ dev_dbg(ctx->mxc_jpeg->dev, "Stop streaming\n");
+ pm_runtime_put_sync(&ctx->mxc_jpeg->pdev->dev);
+}
+struct mxc_jpeg_stream {
+ u8 *addr;
+ u32 loc;
+ u32 end;
+};
+static u8 get_byte(struct mxc_jpeg_stream *stream)
+{
+ u8 ret;
+
+ if (stream->loc >= stream->end)
+ return -1;
+ ret = stream->addr[stream->loc];
+ stream->loc++;
+ return ret;
+}
+
+static void _bswap16(u16 *a)
+{
+ *a = ((*a & 0x00FF) << 8) | ((*a & 0xFF00) >> 8);
+}
+
+static u8 get_sof(struct device *dev,
+ struct mxc_jpeg_stream *stream,
+ struct mxc_jpeg_sof *sof)
+{
+ int i;
+
+ if (stream->loc + sizeof(struct mxc_jpeg_sof) >= stream->end)
+ return -1;
+ memcpy(sof, &stream->addr[stream->loc], sizeof(struct mxc_jpeg_sof));
+ _bswap16(&sof->length);
+ _bswap16(&sof->height);
+ _bswap16(&sof->width);
+ dev_info(dev, "JPEG SOF: precision=%d\n", sof->precision);
+ dev_info(dev, "JPEG SOF: height=%d, width=%d\n",
+ sof->height, sof->width);
+ for (i = 0; i < sof->components_no; i++) {
+ dev_info(dev, "JPEG SOF: comp_id=%d, H=0x%x, V=0x%x\n",
+ sof->comp[i].id, sof->comp[i].v, sof->comp[i].h);
+ }
+ return 0;
+}
+
+static enum mxc_jpeg_image_format mxc_jpeg_get_image_format(
+ struct device *dev,
+ const struct mxc_jpeg_sof *sof)
+{
+ if (sof->components_no == 1) {
+ dev_info(dev, "IMAGE_FORMAT is: MXC_JPEG_GRAY\n");
+ return MXC_JPEG_GRAY;
+ }
+ if (sof->components_no == 3) {
+ if (sof->comp[0].h == 2 && sof->comp[0].v == 2 &&
+ sof->comp[1].h == 1 && sof->comp[1].v == 1 &&
+ sof->comp[2].h == 1 && sof->comp[2].v == 1){
+ dev_info(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV420\n");
+ return MXC_JPEG_YUV420;
+ }
+ if (sof->comp[0].h == 2 && sof->comp[0].v == 1 &&
+ sof->comp[1].h == 1 && sof->comp[1].v == 1 &&
+ sof->comp[2].h == 1 && sof->comp[2].v == 1){
+ dev_info(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV422\n");
+ return MXC_JPEG_YUV422;
+ }
+ if (sof->comp[0].h == 1 && sof->comp[0].v == 1 &&
+ sof->comp[1].h == 1 && sof->comp[1].v == 1 &&
+ sof->comp[2].h == 1 && sof->comp[2].v == 1){
+ dev_info(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV444\n");
+ return MXC_JPEG_YUV444;
+ }
+ }
+ dev_info(dev, "IMAGE_FORMAT is: MXC_JPEG_RESERVED\n");
+ return MXC_JPEG_RESERVED;
+}
+
+static u32 mxc_jpeg_get_line_pitch(
+ struct device *dev,
+ const struct mxc_jpeg_sof *sof,
+ enum mxc_jpeg_image_format img_fmt)
+{
+ u32 line_pitch;
+
+ switch (img_fmt) {
+ case MXC_JPEG_YUV420:
+ line_pitch = sof->width * (sof->precision/8) * 1;
+ break;
+ case MXC_JPEG_YUV422:
+ line_pitch = sof->width * (sof->precision/8) * 2;
+ break;
+ case MXC_JPEG_RGB:
+ line_pitch = sof->width * (sof->precision/8) * 3;
+ break;
+ case MXC_JPEG_YUV444:
+ line_pitch = sof->width * (sof->precision/8) * 3;
+ break;
+ case MXC_JPEG_GRAY:
+ line_pitch = sof->width * (sof->precision/8) * 1;
+ break;
+ default:
+ line_pitch = sof->width * (sof->precision/8) * 3;
+ break;
+ }
+ dev_info(dev, "line_pitch = %d\n", line_pitch);
+ return line_pitch;
+}
+
+static int mxc_jpeg_parse(struct device *dev,
+ struct mxc_jpeg_desc *desc, u8 *src_addr, u32 size)
+{
+ struct mxc_jpeg_stream stream;
+ bool notfound = true;
+ struct mxc_jpeg_sof sof;
+ int byte;
+ enum mxc_jpeg_image_format img_fmt;
+
+ memset(&sof, 0, sizeof(struct mxc_jpeg_sof));
+ stream.addr = src_addr;
+ stream.end = size;
+ stream.loc = 0;
+ while (notfound) {
+ byte = get_byte(&stream);
+ if (byte == -1)
+ return -EINVAL;
+ if (byte != 0xff)
+ continue;
+ do {
+ byte = get_byte(&stream);
+ } while (byte == 0xff);
+ if (byte == -1)
+ return false;
+ if (byte == 0)
+ continue;
+ switch (byte) {
+ case SOF2:
+ case SOF0:
+ if (get_sof(dev, &stream, &sof) == -1)
+ break;
+ notfound = false;
+ break;
+ default:
+ notfound = true;
+ }
+ }
+ if (sof.width % 8 != 0 || sof.height % 8 != 0) {
+ dev_info(dev, "JPEG width or height not multiple of 8: %dx%d\n",
+ sof.width, sof.height);
+ return -EINVAL;
+ }
+ if (sof.width > 0x2000 || sof.height > 0x2000) {
+ dev_info(dev, "JPEG width or height should be <= 8192: %dx%d\n",
+ sof.width, sof.height);
+ return -EINVAL;
+ }
+ desc->imgsize = sof.width << 16 | sof.height;
+ dev_info(dev, "JPEG imgsize = 0x%x (%dx%d)\n", desc->imgsize,
+ sof.width, sof.height);
+ img_fmt = mxc_jpeg_get_image_format(dev, &sof);
+ desc->stm_ctrl |= STM_CTRL_IMAGE_FORMAT(img_fmt);
+ desc->line_pitch = mxc_jpeg_get_line_pitch(dev, &sof, img_fmt);
+ return 0;
+}
+
+static void mxc_jpeg_buf_queue(struct vb2_buffer *vb)
+{
+ int ret;
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ int slot = 0; /* TODO get slot*/
+
+ if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ goto end;
+
+ if (ctx->mode != MXC_JPEG_DECODE)
+ goto end;
+ ret = mxc_jpeg_parse(ctx->mxc_jpeg->dev,
+ ctx->mxc_jpeg->slot_data[slot].desc,
+ (u8 *)vb2_plane_vaddr(vb, 0),
+ vb2_get_plane_payload(vb, 0));
+ if (ret) {
+ v4l2_err(&ctx->mxc_jpeg->v4l2_dev,
+ "driver does not support this resolution\n");
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+ return;
+ }
+
+ if (ctx->state == MXC_JPEG_INIT) {
+ struct vb2_queue *dst_vq = v4l2_m2m_get_vq(
+ ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ static const struct v4l2_event ev_src_ch = {
+ .type = V4L2_EVENT_SOURCE_CHANGE,
+ .u.src_change.changes =
+ V4L2_EVENT_SRC_CH_RESOLUTION,
+ };
+
+ v4l2_event_queue_fh(&ctx->fh, &ev_src_ch);
+ if (vb2_is_streaming(dst_vq))
+ ctx->state = MXC_JPEG_RUNNING;
+ }
+
+end:
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb)
+{
+ struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct mxc_jpeg_q_data *q_data = NULL;
+
+ q_data = mxc_jpeg_get_q_data(ctx, vb->vb2_queue->type);
+ if (!q_data)
+ return -EINVAL;
+
+ vb2_set_plane_payload(vb, 0, q_data->sizeimage[0]);
+ return 0;
+}
+
+static void mxc_jpeg_buf_clean(struct vb2_buffer *vb)
+{
+ return;
+}
+
+static const struct vb2_ops mxc_jpeg_qops = {
+ .queue_setup = mxc_jpeg_queue_setup,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .buf_prepare = mxc_jpeg_buf_prepare,
+ .buf_cleanup = mxc_jpeg_buf_clean,
+ .start_streaming = mxc_jpeg_start_streaming,
+ .stop_streaming = mxc_jpeg_stop_streaming,
+ .buf_queue = mxc_jpeg_buf_queue,
+};
+static int mxc_jpeg_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct mxc_jpeg_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->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->ops = &mxc_jpeg_qops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->lock = &ctx->mxc_jpeg->lock;
+ src_vq->dev = ctx->mxc_jpeg->dev;
+
+ 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->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->ops = &mxc_jpeg_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->lock = &ctx->mxc_jpeg->lock;
+ dst_vq->dev = ctx->mxc_jpeg->dev;
+
+ ret = vb2_queue_init(dst_vq);
+ return ret;
+}
+
+static struct mxc_jpeg_fmt *mxc_jpeg_find_format(struct mxc_jpeg_ctx *ctx,
+ u32 pixelformat,
+ unsigned int fmt_type)
+{
+ unsigned int k, fmt_flag;
+
+ fmt_flag = fmt_type;
+
+ if (ctx->mode == MXC_JPEG_ENCODE)
+ fmt_flag = (fmt_type == MXC_JPEG_FMT_TYPE_RAW) ?
+ MXC_JPEG_FMT_TYPE_ENC :
+ MXC_JPEG_FMT_TYPE_RAW;
+
+ for (k = 0; k < MXC_JPEG_NUM_FORMATS; k++) {
+ struct mxc_jpeg_fmt *fmt = &mxc_formats[k];
+
+ if (fmt->fourcc == pixelformat && fmt->flags == fmt_flag)
+ return fmt;
+ }
+ return NULL;
+}
+
+static int mxc_jpeg_alloc_slot_data(struct mxc_jpeg_dev *jpeg)
+{
+ int slot;
+
+ for (slot = 0; slot < MXC_MAX_SLOTS; slot++) {
+ /* allocate descriptor for decoding/encoding phase */
+ jpeg->slot_data[slot].desc = dma_zalloc_coherent(jpeg->dev,
+ sizeof(struct mxc_jpeg_desc),
+ &(jpeg->slot_data[slot].desc_handle), 0);
+ if (!jpeg->slot_data[slot].desc)
+ goto err;
+ dev_dbg(jpeg->dev, "Descriptor for dec/enc: %p 0x%llx\n",
+ jpeg->slot_data[slot].desc,
+ jpeg->slot_data[slot].desc_handle);
+
+ /* allocate descriptor for configuration phase (encoder only) */
+ jpeg->slot_data[slot].cfg_desc = dma_zalloc_coherent(jpeg->dev,
+ sizeof(struct mxc_jpeg_desc),
+ &jpeg->slot_data[slot].cfg_desc_handle, 0);
+ if (!jpeg->slot_data[slot].cfg_desc)
+ goto err;
+ dev_dbg(jpeg->dev, "Descriptor for config phase: %p 0x%llx\n",
+ jpeg->slot_data[slot].cfg_desc,
+ jpeg->slot_data[slot].cfg_desc_handle);
+
+ /* allocate configuration stream */
+ jpeg->slot_data[slot].cfg_stream_vaddr = dma_zalloc_coherent(
+ jpeg->dev,
+ sizeof(hactbl),
+ &jpeg->slot_data[slot].cfg_stream_handle, 0);
+ if (!jpeg->slot_data[slot].cfg_stream_vaddr)
+ goto err;
+ dev_dbg(jpeg->dev, "Configuration stream: %p 0x%llx\n",
+ jpeg->slot_data[slot].cfg_stream_vaddr,
+ jpeg->slot_data[slot].cfg_stream_handle);
+
+ /* initial set-up for configuration stream
+ * TODO: fixup the sizes, currently harcoded to 64x64)
+ */
+ memcpy(jpeg->slot_data[slot].cfg_stream_vaddr,
+ &hactbl, sizeof(hactbl));
+ }
+ return 0;
+err:
+ dev_err(jpeg->dev, "Could not allocate descriptors\n");
+ return 1;
+}
+
+static int mxc_jpeg_free_slot_data(struct mxc_jpeg_dev *jpeg)
+{
+ int slot;
+
+ for (slot = 0; slot < MXC_MAX_SLOTS; slot++) {
+ /* free descriptor for decoding/encoding phase */
+ dma_free_coherent(jpeg->dev, sizeof(struct mxc_jpeg_desc),
+ jpeg->slot_data[slot].desc,
+ jpeg->slot_data[slot].desc_handle);
+
+ /* free descriptor for configuration phase (encoder only) */
+ dma_free_coherent(jpeg->dev, sizeof(struct mxc_jpeg_desc),
+ jpeg->slot_data[slot].cfg_desc,
+ jpeg->slot_data[slot].cfg_desc_handle);
+
+ /* free configuration stream */
+ dma_free_coherent(jpeg->dev, sizeof(hactbl),
+ jpeg->slot_data[slot].cfg_stream_vaddr,
+ jpeg->slot_data[slot].cfg_stream_handle);
+ }
+ return 0;
+}
+
+static int mxc_jpeg_open(struct file *file)
+{
+ struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file);
+ struct video_device *mxc_vfd = video_devdata(file);
+ struct mxc_jpeg_ctx *ctx;
+ struct mxc_jpeg_fmt *out_fmt, *cap_fmt;
+ int ret = 0;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ if (mutex_lock_interruptible(&mxc_jpeg->lock)) {
+ ret = -ERESTARTSYS;
+ goto free;
+ }
+
+ pm_runtime_get_sync(mxc_jpeg->dev);
+
+ v4l2_fh_init(&ctx->fh, mxc_vfd);
+ file->private_data = &ctx->fh;
+ v4l2_fh_add(&ctx->fh);
+
+ ctx->mxc_jpeg = mxc_jpeg;
+ if (mxc_jpeg->mode == MXC_JPEG_ENCODE) {
+ ctx->mode = MXC_JPEG_ENCODE;
+ cap_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB24,
+ MXC_JPEG_FMT_TYPE_ENC);
+ out_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
+ MXC_JPEG_FMT_TYPE_RAW);
+ } else {
+ ctx->mode = MXC_JPEG_DECODE;
+ out_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB24,
+ MXC_JPEG_FMT_TYPE_RAW);
+ cap_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
+ MXC_JPEG_FMT_TYPE_ENC);
+ }
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(mxc_jpeg->m2m_dev, ctx,
+ mxc_jpeg_queue_init);
+ ctx->out_q.fmt = out_fmt;
+ ctx->cap_q.fmt = cap_fmt;
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ ret = PTR_ERR(ctx->fh.m2m_ctx);
+ goto error;
+ }
+
+ if (mxc_jpeg_alloc_slot_data(mxc_jpeg))
+ goto error;
+
+ mutex_unlock(&mxc_jpeg->lock);
+ return 0;
+
+error:
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ mutex_unlock(&mxc_jpeg->lock);
+free:
+ kfree(ctx);
+ return ret;
+}
+
+static int mxc_jpeg_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file);
+
+ strlcpy(cap->driver, MXC_JPEG_NAME " decoder", sizeof(cap->driver));
+ strlcpy(cap->card, MXC_JPEG_NAME " decoder", sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+ dev_name(mxc_jpeg->dev));
+ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+ return 0;
+}
+static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+
+ if (ctx->mode == MXC_JPEG_ENCODE)
+ return enum_fmt(mxc_formats, MXC_NUM_FORMATS, f,
+ MXC_IN_FORMAT);
+ else
+ return enum_fmt(mxc_formats, MXC_NUM_FORMATS, f,
+ MXC_OUT_FORMAT);
+}
+
+static int mxc_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+
+ if (ctx->mode == MXC_JPEG_DECODE)
+ return enum_fmt(mxc_formats, MXC_NUM_FORMATS, f,
+ MXC_IN_FORMAT);
+ else
+ return enum_fmt(mxc_formats, MXC_NUM_FORMATS, f,
+ MXC_OUT_FORMAT);
+}
+
+static void mxc_jpeg_bound_align_image(u32 *w, unsigned int wmin,
+ unsigned int wmax, unsigned int walign,
+ u32 *h, unsigned int hmin,
+ unsigned int hmax, unsigned int halign)
+{
+ int width, height, w_step, h_step;
+
+ width = *w;
+ height = *h;
+ w_step = 1 << walign;
+ h_step = 1 << halign;
+
+ v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
+ if (*w < width && (*w + w_step) <= wmax)
+ *w += w_step;
+ if (*h < height && (*h + h_step) <= hmax)
+ *h += h_step;
+}
+static int mxc_jpeg_try_fmt(struct v4l2_format *f, struct mxc_jpeg_fmt *fmt,
+ struct mxc_jpeg_ctx *ctx, int q_type)
+{
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[0];
+ u32 stride, h;
+
+ memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
+ pix_mp->field = V4L2_FIELD_NONE;
+ pix_mp->num_planes = fmt->colplanes;
+ pix_mp->pixelformat = fmt->fourcc;
+
+ if (q_type == MXC_JPEG_FMT_TYPE_ENC && ctx->mode == MXC_JPEG_DECODE) {
+ struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[0];
+
+ mxc_jpeg_bound_align_image(&pix_mp->width,
+ MXC_JPEG_MIN_WIDTH,
+ MXC_JPEG_MAX_WIDTH,
+ MXC_JPEG_MIN_WIDTH,
+ &pix_mp->height,
+ MXC_JPEG_MIN_HEIGHT,
+ MXC_JPEG_MAX_HEIGHT,
+ MXC_JPEG_MIN_WIDTH);
+
+ memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
+ pfmt->bytesperline = 0;
+ /* Source size must be aligned to 128 */
+ pfmt->sizeimage = mxc_jpeg_align(pfmt->sizeimage, 128);
+ if (pfmt->sizeimage == 0)
+ pfmt->sizeimage = MXC_JPEG_DEFAULT_SIZEIMAGE;
+ return 0;
+ }
+
+ /* type is MXC_JPEG_FMT_TYPE_RAW */
+ mxc_jpeg_bound_align_image(&pix_mp->width, MXC_JPEG_MIN_WIDTH,
+ MXC_JPEG_MAX_WIDTH, MXC_JPEG_MIN_WIDTH,
+ &pix_mp->height, MXC_JPEG_MIN_HEIGHT,
+ MXC_JPEG_MAX_HEIGHT, MXC_JPEG_MIN_WIDTH);
+
+ pfmt = &pix_mp->plane_fmt[0];
+ stride = pix_mp->width * 3;
+ h = pix_mp->height;
+ memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
+ pfmt->bytesperline = stride;
+ pfmt->sizeimage = stride * h;
+
+ return 0;
+}
+static int mxc_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+ struct mxc_jpeg_fmt *fmt;
+
+ fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat,
+ MXC_JPEG_FMT_TYPE_RAW);
+ return mxc_jpeg_try_fmt(f, fmt, ctx, MXC_JPEG_FMT_TYPE_RAW);
+}
+static int mxc_jpeg_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+ struct mxc_jpeg_fmt *fmt;
+
+ fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat,
+ MXC_JPEG_FMT_TYPE_ENC);
+ return mxc_jpeg_try_fmt(f, fmt, ctx, MXC_JPEG_FMT_TYPE_ENC);
+}
+static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx,
+ struct v4l2_format *f)
+{
+ struct vb2_queue *vq;
+ struct mxc_jpeg_q_data *q_data = NULL;
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
+ unsigned int f_type;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ q_data = mxc_jpeg_get_q_data(ctx, f->type);
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&jpeg->v4l2_dev, "queue busy\n");
+ return -EBUSY;
+ }
+
+ f_type = f->type;
+
+ q_data->fmt = mxc_jpeg_find_format(ctx, pix_mp->pixelformat, f_type);
+ q_data->w = pix_mp->width;
+ q_data->h = pix_mp->height;
+ q_data->bytesperline[0] = pix_mp->plane_fmt[0].bytesperline;
+ q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage;
+
+ return 0;
+}
+static int mxc_jpeg_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ int ret;
+
+ ret = mxc_jpeg_try_fmt_vid_cap(file, priv, f);
+ if (ret)
+ return ret;
+
+ return mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f);
+}
+static int mxc_jpeg_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ int ret;
+
+ ret = mxc_jpeg_try_fmt_vid_out(file, priv, f);
+ if (ret)
+ return ret;
+
+ return mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f);
+}
+static int mxc_jpeg_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return 0;
+}
+static int mxc_jpeg_g_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return 0;
+}
+
+static int mxc_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct v4l2_fh *fh = file->private_data;
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+ struct vb2_queue *vq;
+ struct vb2_buffer *vb;
+
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ goto end;
+
+ vq = v4l2_m2m_get_vq(fh->m2m_ctx, buf->type);
+ if (buf->index >= vq->num_buffers) {
+ dev_err(ctx->mxc_jpeg->dev, "buffer index out of range\n");
+ return -EINVAL;
+ }
+
+ vb = vq->bufs[buf->index];
+end:
+ return v4l2_m2m_qbuf(file, fh->m2m_ctx, buf);
+}
+
+static const struct v4l2_ioctl_ops mxc_jpeg_ioctl_ops = {
+ .vidioc_querycap = mxc_jpeg_querycap,
+ .vidioc_enum_fmt_vid_cap = mxc_jpeg_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_out = mxc_jpeg_enum_fmt_vid_out,
+
+ .vidioc_try_fmt_vid_cap = mxc_jpeg_try_fmt_vid_cap,
+ .vidioc_try_fmt_vid_out = mxc_jpeg_try_fmt_vid_out,
+
+ .vidioc_s_fmt_vid_cap = mxc_jpeg_s_fmt_vid_cap,
+ .vidioc_s_fmt_vid_out = mxc_jpeg_s_fmt_vid_out,
+
+ .vidioc_g_fmt_vid_cap = mxc_jpeg_g_fmt_vid_cap,
+ .vidioc_g_fmt_vid_out = mxc_jpeg_g_fmt_vid_out,
+
+ .vidioc_qbuf = mxc_jpeg_qbuf,
+
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+};
+
+static int mxc_jpeg_release(struct file *file)
+{
+ struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file);
+ struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(file->private_data);
+
+ mutex_lock(&mxc_jpeg->lock);
+ mxc_jpeg_free_slot_data(mxc_jpeg);
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ kfree(ctx);
+ mutex_unlock(&mxc_jpeg->lock);
+
+ pm_runtime_put_sync(mxc_jpeg->dev);
+ return 0;
+}
+
+static const struct v4l2_file_operations mxc_jpeg_fops = {
+ .owner = THIS_MODULE,
+ .open = mxc_jpeg_open,
+ .release = mxc_jpeg_release,
+ .poll = v4l2_m2m_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+static struct v4l2_m2m_ops mxc_jpeg_m2m_ops = {
+ .device_run = mxc_jpeg_device_run,
+ .job_ready = mxc_jpeg_job_ready,
+ .job_abort = mxc_jpeg_job_abort,
+};
+
+static int mxc_jpeg_probe(struct platform_device *pdev)
+{
+ struct mxc_jpeg_dev *jpeg;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int dec_irq;
+ int ret;
+ int mode;
+ const struct of_device_id *of_id;
+
+ of_id = of_match_node(mxc_jpeg_match, dev->of_node);
+ mode = (int)(u64) of_id->data;
+
+ jpeg = devm_kzalloc(dev, sizeof(struct mxc_jpeg_dev), GFP_KERNEL);
+ if (!jpeg)
+ return -ENOMEM;
+
+ mutex_init(&jpeg->lock);
+ spin_lock_init(&jpeg->hw_lock);
+
+ if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
+ dev_err(&pdev->dev, "No suitable DMA available.\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dec_irq = platform_get_irq(pdev, 0);
+ if (!res || dec_irq < 0) {
+ dev_err(&pdev->dev, "Failed to get dec_irq %d.\n", dec_irq);
+ ret = -EINVAL;
+ goto err_irq;
+ }
+ ret = devm_request_irq(&pdev->dev, dec_irq, mxc_jpeg_dec_irq, 0,
+ pdev->name, jpeg);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request dec_irq %d (%d)\n",
+ dec_irq, ret);
+ ret = -EINVAL;
+ goto err_irq;
+ }
+ jpeg->base_reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(jpeg->base_reg))
+ return PTR_ERR(jpeg->base_reg);
+
+ jpeg->pdev = pdev;
+ jpeg->dev = dev;
+ jpeg->mode = mode;
+
+ /* Start clock */
+ jpeg->clk_ipg = devm_clk_get(dev, "ipg");
+ if (IS_ERR(jpeg->clk_ipg)) {
+ dev_err(dev, "failed to get clock: ipg\n");
+ goto err_clk;
+ }
+
+ jpeg->clk_per = devm_clk_get(dev, "per");
+ if (IS_ERR(jpeg->clk_per)) {
+ dev_err(dev, "failed to get clock: per\n");
+ goto err_clk;
+ }
+
+ /* v4l2 */
+ ret = v4l2_device_register(dev, &jpeg->v4l2_dev);
+ if (ret) {
+ dev_err(dev, "failed to register v4l2 device\n");
+ goto err_register;
+ }
+ jpeg->m2m_dev = v4l2_m2m_init(&mxc_jpeg_m2m_ops);
+ if (IS_ERR(jpeg->m2m_dev)) {
+ dev_err(dev, "failed to register v4l2 device\n");
+ goto err_m2m;
+ }
+
+ jpeg->dec_vdev = video_device_alloc();
+ if (!jpeg->dec_vdev) {
+ dev_err(dev, "failed to register v4l2 device\n");
+ goto err_vdev_alloc;
+ }
+ if (mode == MXC_JPEG_ENCODE)
+ snprintf(jpeg->dec_vdev->name,
+ sizeof(jpeg->dec_vdev->name),
+ "%s-enc", MXC_JPEG_M2M_NAME);
+ else
+ snprintf(jpeg->dec_vdev->name,
+ sizeof(jpeg->dec_vdev->name),
+ "%s-dec", MXC_JPEG_M2M_NAME);
+
+ jpeg->dec_vdev->fops = &mxc_jpeg_fops;
+ jpeg->dec_vdev->ioctl_ops = &mxc_jpeg_ioctl_ops;
+ jpeg->dec_vdev->minor = -1;
+ jpeg->dec_vdev->release = video_device_release;
+ jpeg->dec_vdev->lock = &jpeg->lock; /* lock for ioctl serialization*/
+ jpeg->dec_vdev->v4l2_dev = &jpeg->v4l2_dev;
+ jpeg->dec_vdev->vfl_dir = VFL_DIR_M2M;
+ jpeg->dec_vdev->device_caps = V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_M2M;
+
+ ret = video_register_device(jpeg->dec_vdev, VFL_TYPE_GRABBER, -1);
+ if (ret) {
+ dev_err(dev, "failed to register video device\n");
+ goto err_vdev_register;
+ }
+ video_set_drvdata(jpeg->dec_vdev, jpeg);
+ if (mode == MXC_JPEG_ENCODE)
+ v4l2_info(&jpeg->v4l2_dev,
+ "encoder device registered as /dev/video%d (%d,%d)\n",
+ jpeg->dec_vdev->num, VIDEO_MAJOR,
+ jpeg->dec_vdev->minor);
+ else
+ v4l2_info(&jpeg->v4l2_dev,
+ "decoder device registered as /dev/video%d (%d,%d)\n",
+ jpeg->dec_vdev->num, VIDEO_MAJOR,
+ jpeg->dec_vdev->minor);
+
+ platform_set_drvdata(pdev, jpeg);
+ pm_runtime_enable(dev);
+ return 0;
+
+err_vdev_register:
+ video_device_release(jpeg->dec_vdev);
+
+err_vdev_alloc:
+ v4l2_m2m_release(jpeg->m2m_dev);
+
+err_m2m:
+ v4l2_device_unregister(&jpeg->v4l2_dev);
+
+err_register:
+err_irq:
+err_clk:
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int mxc_jpeg_runtime_resume(struct device *dev)
+{
+ struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(jpeg->clk_ipg);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable clock: ipg\n");
+ goto err_clk;
+ }
+
+ ret = clk_prepare_enable(jpeg->clk_per);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable clock: per\n");
+ goto err_clk;
+ }
+
+ return 0;
+
+err_clk:
+ return ret;
+}
+
+static int mxc_jpeg_runtime_suspend(struct device *dev)
+{
+ struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(jpeg->clk_ipg);
+ clk_disable_unprepare(jpeg->clk_per);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops mxc_jpeg_pm_ops = {
+ SET_RUNTIME_PM_OPS(mxc_jpeg_runtime_suspend,
+ mxc_jpeg_runtime_resume, NULL)
+};
+
+static int mxc_jpeg_remove(struct platform_device *pdev)
+{
+ struct mxc_jpeg_dev *jpeg = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+ video_unregister_device(jpeg->dec_vdev);
+ video_device_release(jpeg->dec_vdev);
+ v4l2_m2m_release(jpeg->m2m_dev);
+ v4l2_device_unregister(&jpeg->v4l2_dev);
+
+ return 0;
+}
+
+MODULE_DEVICE_TABLE(of, mxc_jpeg_match);
+
+static struct platform_driver mxc_jpeg_driver = {
+ .probe = mxc_jpeg_probe,
+ .remove = mxc_jpeg_remove,
+ .driver = {
+ .name = "mxc-jpeg",
+ .of_match_table = mxc_jpeg_match,
+ .pm = &mxc_jpeg_pm_ops,
+ },
+};
+module_platform_driver(mxc_jpeg_driver);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/imx8/mxc-jpeg.h b/drivers/media/platform/imx8/mxc-jpeg.h
new file mode 100644
index 000000000000..d2eb0521321d
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-jpeg.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2018 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+
+#ifndef _MXC_JPEG_CORE_H
+#define _MXC_JPEG_CORE_H
+
+#define MXC_JPEG_M2M_NAME "mxc-jpeg"
+#define MXC_JPEG_NAME "mxc-jpeg"
+#define MXC_IN_FORMAT 0
+#define MXC_OUT_FORMAT 1
+#define MXC_JPEG_INIT 0
+#define MXC_JPEG_RUNNING 1
+#define MXC_JPEG_FMT_TYPE_ENC 0
+#define MXC_JPEG_FMT_TYPE_RAW 1
+#define MXC_JPEG_NUM_FORMATS 4
+#define MXC_JPEG_MIN_HEIGHT 0x8
+#define MXC_JPEG_MIN_WIDTH 0x8
+#define MXC_JPEG_MAX_HEIGHT 0x2000
+#define MXC_JPEG_MAX_WIDTH 0x2000
+#define MXC_JPEG_DEFAULT_SIZEIMAGE 10000
+#define MXC_JPEG_ENC_CONF 1
+#define MXC_JPEG_ENC_DONE 0
+#define SOF0 0xC0
+#define SOF2 0xC2
+#define MXC_JPEG_ENC_CONF_DONE 1
+
+
+/**
+ * struct jpeg_fmt - driver's internal color format data
+ * @name: format description
+ * @fourcc: fourcc code, 0 if not applicable
+ * @depth: number of bits per pixel
+ * @colplanes: number of color planes (1 for packed formats)
+ * @h_align: horizontal alignment order (align to 2^h_align)
+ * @v_align: vertical alignment order (align to 2^v_align)
+ * @flags: flags describing format applicability
+ */
+struct mxc_jpeg_fmt {
+ char *name;
+ u32 fourcc;
+ int depth;
+ int colplanes;
+ int memplanes;
+ int h_align;
+ int v_align;
+ int subsampling;
+ u32 flags;
+};
+struct mxc_jpeg_desc {
+ u32 next_descpt_ptr;
+ u32 buf_base0;
+ u32 buf_base1;
+ u32 line_pitch;
+ u32 stm_bufbase;
+ u32 stm_bufsize;
+ u32 imgsize;
+ u32 stm_ctrl;
+} __packed;
+
+struct mxc_jpeg_q_data {
+ struct mxc_jpeg_fmt *fmt;
+ u32 sizeimage[1];
+ u32 bytesperline[2];
+ int w;
+ int h;
+ u32 stride;
+};
+struct mxc_jpeg_ctx {
+ struct mxc_jpeg_dev *mxc_jpeg;
+ struct mxc_jpeg_q_data out_q;
+ struct mxc_jpeg_q_data cap_q;
+ struct v4l2_rect crop_rect;
+ unsigned long state;
+ struct v4l2_fh fh;
+ unsigned int mode;
+ unsigned int enc_state;
+ unsigned int aborting;
+};
+
+struct mxc_jpeg_slot_data {
+ int used;
+ struct mxc_jpeg_desc *desc; // enc/dec descriptor
+ struct mxc_jpeg_desc *cfg_desc; // configuration descriptor
+ void *cfg_stream_vaddr; // configuration bitstream virtual address
+ int flags;
+ dma_addr_t desc_handle;
+ dma_addr_t cfg_desc_handle; // configuration descriptor dma address
+ dma_addr_t cfg_stream_handle; // configuration bitstream dma address
+};
+
+struct mxc_jpeg_dev {
+ spinlock_t hw_lock;
+ unsigned int mode;
+ struct mutex lock;
+ bool enc;
+ bool dec;
+ struct clk *clk_ipg;
+ struct clk *clk_per;
+ struct platform_device *pdev;
+ struct device *dev;
+ void __iomem *base_reg;
+ void __iomem *enc_reg;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct video_device *dec_vdev;
+ unsigned int irq;
+ int id;
+
+ struct mxc_jpeg_slot_data slot_data[MXC_MAX_SLOTS];
+};
+
+/* JPEG Start Of Frame marker fields*/
+struct mxc_jpeg_sof_comp {
+ u8 id; /*component id*/
+ u8 v :4; /* vertical sampling*/
+ u8 h :4; /* horizontal sampling*/
+ u8 quantization_table_no;
+} __packed;
+
+struct mxc_jpeg_sof {
+ u16 length;
+ u8 precision;
+ u16 height, width;
+ u8 components_no;
+ struct mxc_jpeg_sof_comp comp[3];
+} __packed;
+
+#endif
diff --git a/drivers/media/platform/imx8/mxc-media-dev.c b/drivers/media/platform/imx8/mxc-media-dev.c
new file mode 100644
index 000000000000..ff20a9b8e520
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-media-dev.c
@@ -0,0 +1,710 @@
+/*
+ * Copyright 2017-2018 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/bug.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-of.h>
+#include <media/media-device.h>
+
+#include "mxc-media-dev.h"
+#include "mxc-isi-core.h"
+#include "mxc-mipi-csi2.h"
+#include "mxc-parallel-csi.h"
+
+/*create default links between registered entities */
+static int mxc_md_create_links(struct mxc_md *mxc_md)
+{
+ struct media_entity *source, *sink;
+ struct mxc_isi_dev *mxc_isi;
+ struct mxc_sensor_info *sensor;
+ struct mxc_mipi_csi2_dev *mipi_csi2;
+ struct mxc_parallel_csi_dev *pcsidev;
+ int i, j, ret = 0;
+ u16 source_pad, sink_pad;
+ u32 flags;
+ u32 mipi_vc = 0;
+
+ /* Create links between each ISI's subdev and video node */
+ flags = MEDIA_LNK_FL_ENABLED;
+ for (i = 0; i < MXC_ISI_MAX_DEVS; i++) {
+ mxc_isi = mxc_md->mxc_isi[i];
+ if (!mxc_isi)
+ continue;
+
+ /* Connect ISI source to video device */
+ source = &mxc_isi->isi_cap.sd.entity;
+ sink = &mxc_isi->isi_cap.vdev.entity;
+ sink_pad = 0;
+
+ switch (mxc_isi->interface[OUT_PORT]) {
+ case ISI_OUTPUT_INTERFACE_DC0:
+ source_pad = MXC_ISI_SD_PAD_SOURCE_DC0;
+ break;
+ case ISI_OUTPUT_INTERFACE_DC1:
+ source_pad = MXC_ISI_SD_PAD_SOURCE_DC1;
+ break;
+ case ISI_OUTPUT_INTERFACE_MEM:
+ source_pad = MXC_ISI_SD_PAD_SOURCE_MEM;
+ break;
+ default:
+ v4l2_err(&mxc_md->v4l2_dev, "Wrong output interface: %x\n",
+ mxc_isi->interface[OUT_PORT]);
+ return -EINVAL;
+ }
+
+ ret = media_create_pad_link(source, source_pad,
+ sink, sink_pad, flags);
+ if (ret) {
+ v4l2_err(&mxc_md->v4l2_dev, "Failed created link [%s] %c> [%s]\n",
+ source->name, flags ? '=' : '-', sink->name);
+ break;
+ }
+
+ /* Notify capture subdev entity ,ISI cap link setup */
+ ret = media_entity_call(source, link_setup, &source->pads[source_pad],
+ &sink->pads[sink_pad], flags);
+ if (ret) {
+ v4l2_err(&mxc_md->v4l2_dev, "failed call link_setup [%s] %c> [%s]\n",
+ source->name, flags ? '=' : '-', sink->name);
+ break;
+ }
+
+ v4l2_info(&mxc_md->v4l2_dev, "created link [%s] %c> [%s]\n",
+ source->name, flags ? '=' : '-', sink->name);
+
+ /* Connect MIPI/HDMI/Mem source to ISI sink */
+ sink = &mxc_isi->isi_cap.sd.entity;
+
+ switch (mxc_isi->interface[IN_PORT]) {
+
+ case ISI_INPUT_INTERFACE_MIPI0_CSI2:
+ if (mxc_md->mipi_csi2[0] == NULL)
+ continue;
+ source = &mxc_md->mipi_csi2[0]->sd.entity;
+
+ switch (mxc_isi->interface[SUB_IN_PORT]) {
+ case ISI_INPUT_SUB_INTERFACE_VC1:
+ source_pad = MXC_MIPI_CSI2_VC1_PAD_SOURCE;
+ sink_pad = MXC_ISI_SD_PAD_SINK_MIPI0_VC1;
+ break;
+ case ISI_INPUT_SUB_INTERFACE_VC2:
+ source_pad = MXC_MIPI_CSI2_VC2_PAD_SOURCE;
+ sink_pad = MXC_ISI_SD_PAD_SINK_MIPI0_VC2;
+ break;
+ case ISI_INPUT_SUB_INTERFACE_VC3:
+ source_pad = MXC_MIPI_CSI2_VC3_PAD_SOURCE;
+ sink_pad = MXC_ISI_SD_PAD_SINK_MIPI0_VC3;
+ break;
+ default:
+ source_pad = MXC_MIPI_CSI2_VC0_PAD_SOURCE;
+ sink_pad = MXC_ISI_SD_PAD_SINK_MIPI0_VC0;
+ break;
+ }
+ break;
+
+ case ISI_INPUT_INTERFACE_MIPI1_CSI2:
+ if (mxc_md->mipi_csi2[1] == NULL)
+ continue;
+ source = &mxc_md->mipi_csi2[1]->sd.entity;
+
+ switch (mxc_isi->interface[SUB_IN_PORT]) {
+ case ISI_INPUT_SUB_INTERFACE_VC1:
+ source_pad = MXC_MIPI_CSI2_VC1_PAD_SOURCE;
+ sink_pad = MXC_ISI_SD_PAD_SINK_MIPI1_VC1;
+ break;
+ case ISI_INPUT_SUB_INTERFACE_VC2:
+ source_pad = MXC_MIPI_CSI2_VC2_PAD_SOURCE;
+ sink_pad = MXC_ISI_SD_PAD_SINK_MIPI1_VC2;
+ break;
+ case ISI_INPUT_SUB_INTERFACE_VC3:
+ source_pad = MXC_MIPI_CSI2_VC3_PAD_SOURCE;
+ sink_pad = MXC_ISI_SD_PAD_SINK_MIPI1_VC3;
+ break;
+ default:
+ source_pad = MXC_MIPI_CSI2_VC0_PAD_SOURCE;
+ sink_pad = MXC_ISI_SD_PAD_SINK_MIPI1_VC0;
+ break;
+ }
+ break;
+ case ISI_INPUT_INTERFACE_PARALLEL_CSI:
+ if (mxc_md->pcsidev == NULL)
+ continue;
+ source = &mxc_md->pcsidev->sd.entity;
+ source_pad = MXC_PARALLEL_CSI_PAD_SOURCE;
+ sink_pad = MXC_ISI_SD_PAD_SINK_PARALLEL_CSI;
+ break;
+
+ case ISI_INPUT_INTERFACE_HDMI:
+ if (mxc_md->hdmi_rx == NULL)
+ continue;
+ source = &mxc_md->hdmi_rx->sd.entity;
+ source_pad = MXC_HDMI_RX_PAD_SOURCE;
+ sink_pad = MXC_ISI_SD_PAD_SINK_HDMI;
+ break;
+
+ case ISI_INPUT_INTERFACE_DC0:
+ case ISI_INPUT_INTERFACE_DC1:
+ case ISI_INPUT_INTERFACE_MEM:
+ default:
+ v4l2_err(&mxc_md->v4l2_dev, "Not support input interface: %x\n",
+ mxc_isi->interface[IN_PORT]);
+ return -EINVAL;
+ }
+ /* Create link MIPI/HDMI to ISI */
+ ret = media_create_pad_link(source, source_pad, sink, sink_pad, flags);
+ if (ret) {
+ v4l2_err(&mxc_md->v4l2_dev, "created link [%s] %c> [%s] fail\n",
+ source->name, flags ? '=' : '-', sink->name);
+ break;
+ }
+
+ /* Notify ISI subdev entity */
+ ret = media_entity_call(sink, link_setup, &sink->pads[sink_pad],
+ &source->pads[source_pad], 0);
+ if (ret)
+ break;
+
+ /* Notify MIPI/HDMI entity */
+ ret = media_entity_call(source, link_setup, &source->pads[source_pad],
+ &sink->pads[sink_pad], 0);
+ if (ret)
+ break;
+
+ v4l2_info(&mxc_md->v4l2_dev, "created link [%s] %c> [%s]\n",
+ source->name, flags ? '=' : '-', sink->name);
+ }
+
+ /* Connect MIPI Sensor to MIPI CSI2 */
+ for (i = 0; i < mxc_md->num_sensors; i++) {
+ sensor = &mxc_md->sensor[i];
+ if (sensor == NULL || sensor->sd == NULL)
+ continue;
+
+ if (mxc_md->parallel_csi && !sensor->mipi_mode) {
+ pcsidev = mxc_md->pcsidev;
+ if (pcsidev == NULL)
+ continue;
+ source = &sensor->sd->entity;
+ sink = &pcsidev->sd.entity;
+
+ source_pad = 0;
+ sink_pad = MXC_PARALLEL_CSI_PAD_SINK;
+
+ ret = media_create_pad_link(source, source_pad, sink, sink_pad,
+ MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+
+ /* Notify MIPI subdev entity */
+ ret = media_entity_call(sink, link_setup, &sink->pads[sink_pad],
+ &source->pads[source_pad], 0);
+ if (ret)
+ return ret;
+
+ /* Notify MIPI sensor subdev entity */
+ ret = media_entity_call(source, link_setup, &source->pads[source_pad],
+ &sink->pads[sink_pad], 0);
+ if (ret)
+ return ret;
+ v4l2_info(&mxc_md->v4l2_dev, "created link [%s] => [%s]\n",
+ sensor->sd->entity.name, pcsidev->sd.entity.name);
+ } else if (mxc_md->mipi_csi2) {
+ mipi_csi2 = mxc_md->mipi_csi2[sensor->id];
+ if (mipi_csi2 == NULL)
+ continue;
+ source = &sensor->sd->entity;
+ sink = &mipi_csi2->sd.entity;
+
+ source_pad = 0; /* sensor source pad: MIPI_CSI2_SENS_VC0_PAD_SOURCE */
+ sink_pad = source_pad; /* mipi sink pad: MXC_MIPI_CSI2_VC0_PAD_SINK; */
+
+ if (mipi_csi2->vchannel == true)
+ mipi_vc = 4;
+ else
+ mipi_vc = 1;
+
+ for (j = 0; j < mipi_vc; j++) {
+ ret = media_create_pad_link(source, source_pad + j, sink, sink_pad + j,
+ MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+
+ /* Notify MIPI subdev entity */
+ ret = media_entity_call(sink, link_setup, &sink->pads[sink_pad + j],
+ &source->pads[source_pad + j], 0);
+ if (ret)
+ return ret;
+
+ /* Notify MIPI sensor subdev entity */
+ ret = media_entity_call(source, link_setup, &source->pads[source_pad + j],
+ &sink->pads[sink_pad + j], 0);
+ if (ret)
+ return ret;
+ }
+ v4l2_info(&mxc_md->v4l2_dev, "created link [%s] => [%s]\n",
+ sensor->sd->entity.name, mipi_csi2->sd.entity.name);
+ }
+ }
+ dev_info(&mxc_md->pdev->dev, "%s\n", __func__);
+ return 0;
+}
+
+static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_subdev *asd)
+{
+ struct mxc_md *mxc_md = notifier_to_mxc_md(notifier);
+ struct mxc_sensor_info *sensor = NULL;
+ int i;
+
+ dev_dbg(&mxc_md->pdev->dev, "%s\n", __func__);
+ /* Find platform data for this sensor subdev */
+ for (i = 0; i < ARRAY_SIZE(mxc_md->sensor); i++) {
+ if (mxc_md->sensor[i].asd.match.of.node == sd->dev->of_node)
+ sensor = &mxc_md->sensor[i];
+ }
+
+ if (sensor == NULL)
+ return -EINVAL;
+
+ sd->grp_id = GRP_ID_MXC_SENSOR;
+
+ sensor->sd = sd;
+
+ mxc_md->num_sensors++;
+
+ v4l2_info(&mxc_md->v4l2_dev, "Registered sensor subdevice: %s (%d)\n",
+ sd->name, mxc_md->num_sensors);
+
+ return 0;
+}
+
+static int subdev_notifier_complete(struct v4l2_async_notifier *notifier)
+{
+ struct mxc_md *mxc_md = notifier_to_mxc_md(notifier);
+ int ret;
+
+ dev_dbg(&mxc_md->pdev->dev, "%s\n", __func__);
+ mutex_lock(&mxc_md->media_dev.graph_mutex);
+
+ ret = mxc_md_create_links(mxc_md);
+ if (ret < 0)
+ goto unlock;
+
+ ret = v4l2_device_register_subdev_nodes(&mxc_md->v4l2_dev);
+unlock:
+ mutex_unlock(&mxc_md->media_dev.graph_mutex);
+ if (ret < 0) {
+ v4l2_err(&mxc_md->v4l2_dev, "%s error exit\n", __func__);
+ return ret;
+ }
+
+ return media_device_register(&mxc_md->media_dev);
+}
+
+
+/**
+ * mxc_sensor_notify - v4l2_device notification from a sensor subdev
+ */
+void mxc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification,
+ void *arg)
+{
+ return;
+}
+
+/* Register mipi sensor / Parallel CSI / HDMI Rx sub-devices */
+static int register_sensor_entities(struct mxc_md *mxc_md)
+{
+ struct device_node *parent = mxc_md->pdev->dev.of_node;
+ struct device_node *node, *ep, *rem;
+ struct v4l2_of_endpoint endpoint;
+ int index = 0;
+
+ mxc_md->num_sensors = 0;
+
+ /* Attach sensors linked to MIPI CSI2 / paralle csi / HDMI Rx */
+ for_each_available_child_of_node(parent, node) {
+ struct device_node *port;
+
+ if (!of_node_cmp(node->name, "hdmi_rx")) {
+ mxc_md->sensor[index].asd.match_type = V4L2_ASYNC_MATCH_OF;
+ mxc_md->sensor[index].asd.match.of.node = node;
+ mxc_md->async_subdevs[index] = &mxc_md->sensor[index].asd;
+
+ mxc_md->num_sensors++;
+ index++;
+ continue;
+ }
+
+ if (of_node_cmp(node->name, "csi") &&
+ of_node_cmp(node->name, "pcsi"))
+ continue;
+
+ if (!of_device_is_available(node))
+ continue;
+
+ /* csi2 node have only port */
+ port = of_get_next_child(node, NULL);
+ if (!port)
+ continue;
+
+ /* port can have only endpoint */
+ ep = of_get_next_child(port, NULL);
+ if (!ep)
+ return -EINVAL;
+
+ v4l2_of_parse_endpoint(ep, &endpoint);
+ if (WARN_ON(endpoint.base.port >= MXC_MAX_SENSORS)) {
+ v4l2_err(&mxc_md->v4l2_dev, "Failed to get sensor endpoint\n");
+ return -EINVAL;
+ }
+
+ mxc_md->sensor[index].id = endpoint.base.port;
+
+ if (!of_node_cmp(node->name, "csi"))
+ mxc_md->sensor[index].mipi_mode = true;
+
+ /* remote port---sensor node */
+ rem = of_graph_get_remote_port_parent(ep);
+ of_node_put(ep);
+ if (rem == NULL) {
+ v4l2_info(&mxc_md->v4l2_dev, "Remote device at %s not found\n",
+ ep->full_name);
+ continue;
+ }
+
+ mxc_md->sensor[index].asd.match_type = V4L2_ASYNC_MATCH_OF;
+ mxc_md->sensor[index].asd.match.of.node = rem;
+ mxc_md->async_subdevs[index] = &mxc_md->sensor[index].asd;
+
+ mxc_md->num_sensors++;
+
+ index++;
+ }
+
+ return 0;
+}
+
+static int register_isi_entity(struct mxc_md *mxc_md, struct mxc_isi_dev *mxc_isi)
+{
+ struct v4l2_subdev *sd = &mxc_isi->isi_cap.sd;
+ int ret;
+
+ dev_dbg(&mxc_md->pdev->dev, "%s\n", __func__);
+ if (WARN_ON(mxc_isi->id >= MXC_ISI_MAX_DEVS || mxc_md->mxc_isi[mxc_isi->id]))
+ return -EBUSY;
+
+ sd->grp_id = GRP_ID_MXC_ISI;
+
+ ret = v4l2_device_register_subdev(&mxc_md->v4l2_dev, sd);
+ if (!ret)
+ mxc_md->mxc_isi[mxc_isi->id] = mxc_isi;
+ else
+ v4l2_err(&mxc_md->v4l2_dev, "Failed to register ISI.%d (%d)\n",
+ mxc_isi->id, ret);
+ return ret;
+}
+
+static int register_mipi_csi2_entity(struct mxc_md *mxc_md,
+ struct mxc_mipi_csi2_dev *mipi_csi2)
+{
+ struct v4l2_subdev *sd = &mipi_csi2->sd;
+ int ret;
+
+ if (WARN_ON(mipi_csi2->id >= MXC_MIPI_CSI2_MAX_DEVS))
+ return -ENOENT;
+
+ sd->grp_id = GRP_ID_MXC_MIPI_CSI2;
+ ret = v4l2_device_register_subdev(&mxc_md->v4l2_dev, sd);
+ if (!ret)
+ mxc_md->mipi_csi2[mipi_csi2->id] = mipi_csi2;
+ else
+ v4l2_err(&mxc_md->v4l2_dev,
+ "Failed to register MIPI-CSIS.%d (%d)\n", mipi_csi2->id, ret);
+ return ret;
+}
+
+static int register_parallel_csi_entity(struct mxc_md *mxc_md,
+ struct mxc_parallel_csi_dev *pcsidev)
+{
+ struct v4l2_subdev *sd = &pcsidev->sd;
+ int ret;
+
+ sd->grp_id = GRP_ID_MXC_PARALLEL_CSI;
+ ret = v4l2_device_register_subdev(&mxc_md->v4l2_dev, sd);
+ if (!ret)
+ mxc_md->pcsidev = pcsidev;
+ else
+ v4l2_err(&mxc_md->v4l2_dev,
+ "Failed to register PARALLEL CSI ret=(%d)\n", ret);
+ return ret;
+}
+
+static int register_hdmi_rx_entity(struct mxc_md *mxc_md,
+ struct mxc_hdmi_rx_dev *hdmi_rx)
+{
+ struct v4l2_subdev *sd = &hdmi_rx->sd;;
+
+ dev_dbg(&mxc_md->pdev->dev, "%s\n", __func__);
+ sd->grp_id = GRP_ID_MXC_HDMI_RX;
+ mxc_md->hdmi_rx = hdmi_rx;
+
+ return 0;
+}
+
+static int mxc_md_register_platform_entity(struct mxc_md *mxc_md,
+ struct platform_device *pdev,
+ int plat_entity)
+{
+ struct device *dev = &pdev->dev;
+ int ret = -EPROBE_DEFER;
+ void *drvdata;
+
+ /* Lock to ensure dev->driver won't change. */
+ device_lock(dev);
+
+ if (!dev->driver || !try_module_get(dev->driver->owner))
+ goto dev_unlock;
+
+ drvdata = dev_get_drvdata(dev);
+ /* Some subdev didn't probe successfully id drvdata is NULL */
+ if (drvdata) {
+ switch (plat_entity) {
+ case IDX_ISI:
+ ret = register_isi_entity(mxc_md, drvdata);
+ break;
+ case IDX_MIPI_CSI2:
+ ret = register_mipi_csi2_entity(mxc_md, drvdata);
+ break;
+ case IDX_PARALLEL_CSI:
+ ret = register_parallel_csi_entity(mxc_md, drvdata);
+ break;
+ case IDX_HDMI_RX:
+ ret = register_hdmi_rx_entity(mxc_md, drvdata);
+ break;
+ default:
+ ret = -ENODEV;
+ }
+ }
+ module_put(dev->driver->owner);
+
+dev_unlock:
+ device_unlock(dev);
+ if (ret == -EPROBE_DEFER)
+ dev_info(&mxc_md->pdev->dev, "deferring %s device registration\n",
+ dev_name(dev));
+ else if (ret < 0)
+ dev_err(&mxc_md->pdev->dev, "%s device registration failed (%d)\n",
+ dev_name(dev), ret);
+
+ return ret;
+}
+
+/* Register ISI, MIPI CSI2 and HDMI Rx Media entities */
+static int mxc_md_register_platform_entities(struct mxc_md *mxc_md,
+ struct device_node *parent)
+{
+ struct device_node *node;
+ int ret = 0;
+
+ for_each_available_child_of_node(parent, node) {
+ struct platform_device *pdev;
+ int plat_entity = -1;
+
+ pdev = of_find_device_by_node(node);
+ if (!pdev)
+ continue;
+
+ /* If driver of any entity isn't ready try all again later. */
+ if (!strcmp(node->name, ISI_OF_NODE_NAME))
+ plat_entity = IDX_ISI;
+ else if (!strcmp(node->name, MIPI_CSI2_OF_NODE_NAME))
+ plat_entity = IDX_MIPI_CSI2;
+ else if (!strcmp(node->name, PARALLEL_CSI_OF_NODE_NAME))
+ plat_entity = IDX_PARALLEL_CSI;
+ else if (!strcmp(node->name, MXC_HDMI_RX_NODE_NAME))
+ plat_entity = IDX_HDMI_RX;
+
+ if (plat_entity >= 0)
+ ret = mxc_md_register_platform_entity(mxc_md, pdev,
+ plat_entity);
+ put_device(&pdev->dev);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+static void mxc_md_unregister_entities(struct mxc_md *mxc_md)
+{
+ int i;
+
+ for (i = 0; i < MXC_ISI_MAX_DEVS; i++) {
+ struct mxc_isi_dev *dev = mxc_md->mxc_isi[i];
+ if (dev == NULL)
+ continue;
+ v4l2_device_unregister_subdev(&dev->isi_cap.sd);
+ mxc_md->mxc_isi[i] = NULL;
+ }
+ for (i = 0; i < MXC_MIPI_CSI2_MAX_DEVS; i++) {
+ if (mxc_md->mipi_csi2[i] == NULL)
+ continue;
+ v4l2_device_unregister_subdev(&mxc_md->mipi_csi2[i]->sd);
+ mxc_md->mipi_csi2[i] = NULL;
+ }
+
+ if (mxc_md->pcsidev) {
+ v4l2_device_unregister_subdev(&mxc_md->pcsidev->sd);
+ mxc_md->pcsidev = NULL;
+ }
+
+ v4l2_info(&mxc_md->v4l2_dev, "Unregistered all entities\n");
+}
+
+static int mxc_md_link_notify(struct media_link *link, unsigned int flags,
+ unsigned int notification)
+{
+ return 0;
+}
+
+static const struct media_device_ops mxc_md_ops = {
+ .link_notify = mxc_md_link_notify,
+};
+
+
+static int mxc_md_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct v4l2_device *v4l2_dev;
+ struct mxc_md *mxc_md;
+ int ret;
+
+ mxc_md = devm_kzalloc(dev, sizeof(*mxc_md), GFP_KERNEL);
+ if (!mxc_md)
+ return -ENOMEM;
+
+ mxc_md->pdev = pdev;
+ platform_set_drvdata(pdev, mxc_md);
+
+ mxc_md->parallel_csi = of_property_read_bool(dev->of_node, "parallel_csi");
+
+ /* register media device */
+ strlcpy(mxc_md->media_dev.model, "FSL Capture Media Deivce",
+ sizeof(mxc_md->media_dev.model));
+ mxc_md->media_dev.ops = &mxc_md_ops;
+ mxc_md->media_dev.dev = dev;
+
+ /* register v4l2 device */
+ v4l2_dev = &mxc_md->v4l2_dev;
+ v4l2_dev->mdev = &mxc_md->media_dev;
+ v4l2_dev->notify = mxc_sensor_notify;
+ strlcpy(v4l2_dev->name, "mx8-img-md", sizeof(v4l2_dev->name));
+
+ media_device_init(&mxc_md->media_dev);
+
+ ret = v4l2_device_register(dev, &mxc_md->v4l2_dev);
+ if (ret < 0) {
+ v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret);
+ goto err_md;
+ }
+
+ ret = mxc_md_register_platform_entities(mxc_md, dev->of_node);
+ if (ret < 0)
+ goto err_v4l2_dev;
+
+ ret = register_sensor_entities(mxc_md);
+ if (ret < 0)
+ goto err_m_ent;
+
+ if (mxc_md->num_sensors > 0) {
+ mxc_md->subdev_notifier.subdevs = mxc_md->async_subdevs;
+ mxc_md->subdev_notifier.num_subdevs = mxc_md->num_sensors;
+ mxc_md->subdev_notifier.bound = subdev_notifier_bound;
+ mxc_md->subdev_notifier.complete = subdev_notifier_complete;
+ mxc_md->num_sensors = 0;
+
+ ret = v4l2_async_notifier_register(&mxc_md->v4l2_dev,
+ &mxc_md->subdev_notifier);
+ if (ret < 0) {
+ dev_warn(&mxc_md->pdev->dev, "Sensor register failed\n");
+ goto err_m_ent;
+ }
+ }
+
+ return 0;
+
+err_m_ent:
+ mxc_md_unregister_entities(mxc_md);
+err_v4l2_dev:
+ v4l2_device_unregister(&mxc_md->v4l2_dev);
+err_md:
+ media_device_cleanup(&mxc_md->media_dev);
+ return ret;
+}
+
+static int mxc_md_remove(struct platform_device *pdev)
+{
+ struct mxc_md *mxc_md = platform_get_drvdata(pdev);
+
+ if (!mxc_md)
+ return 0;
+
+ v4l2_async_notifier_unregister(&mxc_md->subdev_notifier);
+
+ v4l2_device_unregister(&mxc_md->v4l2_dev);
+ mxc_md_unregister_entities(mxc_md);
+ media_device_unregister(&mxc_md->media_dev);
+ media_device_cleanup(&mxc_md->media_dev);
+
+ return 0;
+}
+
+static const struct of_device_id mxc_md_of_match[] = {
+ { .compatible = "fsl,mxc-md",},
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mxc_md_of_match);
+
+
+static struct platform_driver mxc_md_driver = {
+ .driver = {
+ .name = MXC_MD_DRIVER_NAME,
+ .of_match_table = mxc_md_of_match,
+ },
+ .probe = mxc_md_probe,
+ .remove = mxc_md_remove,
+};
+
+module_platform_driver(mxc_md_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC Media Device driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" MXC_MD_DRIVER_NAME);
diff --git a/drivers/media/platform/imx8/mxc-media-dev.h b/drivers/media/platform/imx8/mxc-media-dev.h
new file mode 100644
index 000000000000..abcd6548a984
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-media-dev.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2017 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef MXC_MEDIA_DEV_H_
+#define MXC_MEDIA_DEV_H_
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/list.h>
+#include <linux/mfd/syscon.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <media/media-device.h>
+#include <media/media-entity.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+
+#include "mxc-mipi-csi2.h"
+#include "mxc-isi-core.h"
+#include "mxc-isi-hw.h"
+#include "hdmi/mxc-hdmi-rx.h"
+
+#define MXC_MD_DRIVER_NAME "mxc-md"
+#define MXC_MAX_SENSORS 3
+
+#define MJPEG_DEC_OF_NODE_NAME "jpegdec"
+#define MJPEG_ENC_OF_NODE_NAME "jpegenc"
+
+/*
+ * The subdevices' group IDs.
+ */
+#define GRP_ID_MXC_SENSOR (1 << 8)
+#define GRP_ID_MXC_ISI (1 << 9)
+#define GRP_ID_MXC_MIPI_CSI2 (1 << 11)
+#define GRP_ID_MXC_HDMI_RX (1 << 12)
+#define GRP_ID_MXC_MJPEG_DEC (1 << 13)
+#define GRP_ID_MXC_MJPEG_ENC (1 << 14)
+#define GRP_ID_MXC_PARALLEL_CSI (1 << 15)
+
+enum mxc_subdev_index {
+ IDX_SENSOR,
+ IDX_ISI,
+ IDX_MIPI_CSI2,
+ IDX_HDMI_RX,
+ IDX_MJPEG_ENC,
+ IDX_MJPEG_DEC,
+ IDX_PARALLEL_CSI,
+ IDX_MAX,
+};
+
+struct mxc_sensor_info {
+ int id;
+ struct v4l2_subdev *sd;
+ struct v4l2_async_subdev asd;
+ bool mipi_mode;
+ /* struct mxc_isi_dev *host; */
+};
+
+struct mxc_mjpeg_dec{
+ struct v4l2_device *v4l2_dev;
+ struct v4l2_subdev sd;
+};
+
+struct mxc_mjpeg_enc{
+ struct v4l2_device *v4l2_dev;
+ struct v4l2_subdev sd;
+};
+
+struct mxc_md {
+ struct mxc_isi_dev *mxc_isi[MXC_ISI_MAX_DEVS];
+ struct mxc_hdmi_rx_dev *hdmi_rx;
+ struct mxc_parallel_csi_dev *pcsidev;
+ struct mxc_mipi_csi2_dev *mipi_csi2[MXC_MIPI_CSI2_MAX_DEVS];
+ struct mxc_sensor_info sensor[MXC_MAX_SENSORS];
+ struct mxc_mjpeg_dec *mjpeg_dec;
+ struct mxc_mjpeg_enc *mjpeg_enc;
+
+ int num_sensors;
+ bool parallel_csi;
+
+ struct media_device media_dev;
+ struct v4l2_device v4l2_dev;
+ struct platform_device *pdev;
+
+ struct v4l2_async_notifier subdev_notifier;
+ struct v4l2_async_subdev *async_subdevs[MXC_MAX_SENSORS];
+};
+
+static inline struct mxc_md *notifier_to_mxc_md(struct v4l2_async_notifier *n)
+{
+ return container_of(n, struct mxc_md, subdev_notifier);
+};
+
+int mxc_isi_initialize_capture_subdev(struct mxc_isi_dev *mxc_isi);
+void mxc_isi_unregister_capture_subdev(struct mxc_isi_dev *mxc_isi);
+int mxc_isi_register_m2m_device(struct mxc_isi_dev *mxc_isi,
+ struct v4l2_device *v4l2_dev);
+void mxc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification,
+ void *arg);
+void mxc_isi_unregister_m2m_device(struct mxc_isi_dev *mxc_isi);
+int mxc_isi_register_driver(void);
+void mxc_isi_unregister_driver(void);
+#endif
diff --git a/drivers/media/platform/imx8/mxc-mipi-csi2.c b/drivers/media/platform/imx8/mxc-mipi-csi2.c
new file mode 100644
index 000000000000..a236bbbe541e
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-mipi-csi2.c
@@ -0,0 +1,875 @@
+/*
+ * Copyright 2017-2018 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/memory.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-of.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+#include <soc/imx8/sc/sci.h>
+
+#include "mxc-mipi-csi2.h"
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+/* 0~ 80Mbps: 0xB
+ * 80~250Mbps: 0x8
+ * 250~1.5Gbps: 0x6*/
+static u8 rxhs_settle[3] = {0xB, 0x8, 0x6};
+
+static struct mxc_mipi_csi2_dev *sd_to_mxc_mipi_csi2_dev(struct v4l2_subdev *sdev)
+{
+ return container_of(sdev, struct mxc_mipi_csi2_dev, sd);
+}
+
+/****************************************
+ * rxhs-settle calculate
+ * UI = 1000 / mipi csi phy clock
+ * THS-SETTLE_mim = 85ns + 6 * UI
+ * THS-SETTLE_max = 145ns +10 * UI
+ * PRG_RXHS_SETTLE = THS-SETTLE / (Tperiod of RxClk_ESC) + 1
+ ****************************************/
+static int calc_hs_settle(struct mxc_mipi_csi2_dev *csi2dev, u32 dphy_clk)
+{
+ u32 esc_rate;
+ u32 hs_settle;
+ u32 rxhs_settle;
+
+ esc_rate = clk_get_rate(csi2dev->clk_esc) / 1000000;
+ hs_settle = 115 + 8 * 1000 / dphy_clk;
+ rxhs_settle = hs_settle / (1000 / esc_rate) - 1;
+ return rxhs_settle;
+}
+
+#ifdef debug
+static void mxc_mipi_csi2_reg_dump(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ printk("MIPI CSI2 HC register dump, mipi csi%d\n", csi2dev->id);
+ printk("MIPI CSI2 HC num of lanes 0x100 = 0x%x\n", readl(csi2dev->base_regs + 0x100));
+ printk("MIPI CSI2 HC dis lanes 0x104 = 0x%x\n", readl(csi2dev->base_regs + 0x104));
+ printk("MIPI CSI2 HC BIT ERR 0x108 = 0x%x\n", readl(csi2dev->base_regs + 0x108));
+ printk("MIPI CSI2 HC IRQ STATUS 0x10C = 0x%x\n", readl(csi2dev->base_regs + 0x10C));
+ printk("MIPI CSI2 HC IRQ MASK 0x110 = 0x%x\n", readl(csi2dev->base_regs + 0x110));
+ printk("MIPI CSI2 HC ULPS STATUS 0x114 = 0x%x\n", readl(csi2dev->base_regs + 0x114));
+ printk("MIPI CSI2 HC DPHY ErrSotHS 0x118 = 0x%x\n", readl(csi2dev->base_regs + 0x118));
+ printk("MIPI CSI2 HC DPHY ErrSotSync 0x11c = 0x%x\n", readl(csi2dev->base_regs + 0x11c));
+ printk("MIPI CSI2 HC DPHY ErrEsc 0x120 = 0x%x\n", readl(csi2dev->base_regs + 0x120));
+ printk("MIPI CSI2 HC DPHY ErrSyncEsc 0x124 = 0x%x\n", readl(csi2dev->base_regs + 0x124));
+ printk("MIPI CSI2 HC DPHY ErrControl 0x128 = 0x%x\n", readl(csi2dev->base_regs + 0x128));
+ printk("MIPI CSI2 HC DISABLE_PAYLOAD 0x12C = 0x%x\n", readl(csi2dev->base_regs + 0x12C));
+ printk("MIPI CSI2 HC DISABLE_PAYLOAD 0x130 = 0x%x\n", readl(csi2dev->base_regs + 0x130));
+ printk("MIPI CSI2 HC IGNORE_VC 0x180 = 0x%x\n", readl(csi2dev->base_regs + 0x180));
+ printk("MIPI CSI2 HC VID_VC 0x184 = 0x%x\n", readl(csi2dev->base_regs + 0x184));
+ printk("MIPI CSI2 HC FIFO_SEND_LEVEL 0x188 = 0x%x\n", readl(csi2dev->base_regs + 0x188));
+ printk("MIPI CSI2 HC VID_VSYNC 0x18C = 0x%x\n", readl(csi2dev->base_regs + 0x18C));
+ printk("MIPI CSI2 HC VID_SYNC_FP 0x190 = 0x%x\n", readl(csi2dev->base_regs + 0x190));
+ printk("MIPI CSI2 HC VID_HSYNC 0x194 = 0x%x\n", readl(csi2dev->base_regs + 0x194));
+ printk("MIPI CSI2 HC VID_HSYNC_BP 0x198 = 0x%x\n", readl(csi2dev->base_regs + 0x198));
+ printk("MIPI CSI2 CSR register dump\n");
+ printk("MIPI CSI2 CSR PLM_CTRL 0x000 = 0x%x\n", readl(csi2dev->csr_regs + 0x000));
+ printk("MIPI CSI2 CSR PHY_CTRL 0x004 = 0x%x\n", readl(csi2dev->csr_regs + 0x004));
+ printk("MIPI CSI2 CSR PHY_Status 0x008 = 0x%x\n", readl(csi2dev->csr_regs + 0x008));
+ printk("MIPI CSI2 CSR PHY_Test_Status 0x010 = 0x%x\n", readl(csi2dev->csr_regs + 0x010));
+ printk("MIPI CSI2 CSR PHY_Test_Status 0x014 = 0x%x\n", readl(csi2dev->csr_regs + 0x014));
+ printk("MIPI CSI2 CSR PHY_Test_Status 0x018 = 0x%x\n", readl(csi2dev->csr_regs + 0x018));
+ printk("MIPI CSI2 CSR PHY_Test_Status 0x01C = 0x%x\n", readl(csi2dev->csr_regs + 0x01C));
+ printk("MIPI CSI2 CSR PHY_Test_Status 0x020 = 0x%x\n", readl(csi2dev->csr_regs + 0x020));
+ printk("MIPI CSI2 CSR VC Interlaced 0x030 = 0x%x\n", readl(csi2dev->csr_regs + 0x030));
+ printk("MIPI CSI2 CSR Data Type Dis 0x038 = 0x%x\n", readl(csi2dev->csr_regs + 0x038));
+ printk("MIPI CSI2 CSR 420 1st type 0x040 = 0x%x\n", readl(csi2dev->csr_regs + 0x040));
+ printk("MIPI CSI2 CSR Ctr_Ck_Rst_Ctr 0x044 = 0x%x\n", readl(csi2dev->csr_regs + 0x044));
+ printk("MIPI CSI2 CSR Stream Fencing 0x048 = 0x%x\n", readl(csi2dev->csr_regs + 0x048));
+ printk("MIPI CSI2 CSR Stream Fencing 0x04C = 0x%x\n", readl(csi2dev->csr_regs + 0x04C));
+}
+#else
+static void mxc_mipi_csi2_reg_dump(struct mxc_mipi_csi2_dev *csi2dev)
+{
+}
+#endif
+
+static void mipi_sc_fw_init(struct mxc_mipi_csi2_dev *csi2dev, char enable)
+{
+ sc_ipc_t ipcHndl;
+ sc_err_t sciErr;
+ sc_rsrc_t rsrc_id;
+ uint32_t mu_id;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("Cannot obtain MU ID\n");
+ return;
+ }
+
+ sciErr = sc_ipc_open(&ipcHndl, mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return;
+ }
+
+ if (csi2dev->id == 1)
+ rsrc_id = SC_R_CSI_1;
+ else
+ rsrc_id = SC_R_CSI_0;
+
+ sciErr = sc_misc_set_control(ipcHndl, rsrc_id, SC_C_MIPI_RESET, enable);
+ if (sciErr != SC_ERR_NONE)
+ pr_err("sc_misc_MIPI reset failed! (sciError = %d)\n", sciErr);
+
+ msleep(10);
+
+ sc_ipc_close(mu_id);
+}
+
+static void mxc_mipi_csi2_reset(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ u32 val;
+
+ /* Reset MIPI CSI */
+ val = CSI2SS_CTRL_CLK_RESET_EN | CSI2SS_CTRL_CLK_RESET_CLK_OFF;
+ writel(val, csi2dev->csr_regs + CSI2SS_CTRL_CLK_RESET);
+}
+
+static void mxc_mipi_csi2_enable(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ u32 val = 0;
+
+ val = readl(csi2dev->csr_regs + CSI2SS_PLM_CTRL);
+ while (val & CSI2SS_PLM_CTRL_PL_CLK_RUN) {
+ msleep(10);
+ val = readl(csi2dev->csr_regs + CSI2SS_PLM_CTRL);
+ printk("Waiting pl clk running, val=0x%x\n", val);
+ }
+
+ /* Enable Pixel link Master*/
+ val = readl(csi2dev->csr_regs + CSI2SS_PLM_CTRL);
+ val |= CSI2SS_PLM_CTRL_ENABLE_PL;
+ writel(val, csi2dev->csr_regs + CSI2SS_PLM_CTRL);
+
+ val |= CSI2SS_PLM_CTRL_VALID_OVERRIDE;
+ writel(val, csi2dev->csr_regs + CSI2SS_PLM_CTRL);
+
+ /* PHY Enable */
+ val = readl(csi2dev->csr_regs + CSI2SS_PHY_CTRL);
+ val &= ~(CSI2SS_PHY_CTRL_PD_MASK | CSI2SS_PLM_CTRL_POLARITY_MASK);
+ writel(val, csi2dev->csr_regs + CSI2SS_PHY_CTRL);
+
+ /* Deassert reset */
+ writel(1, csi2dev->csr_regs + CSI2SS_CTRL_CLK_RESET);
+}
+
+static void mxc_mipi_csi2_disable(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ /* Disable Data lanes */
+ writel(0xf, csi2dev->base_regs + CSI2RX_CFG_DISABLE_DATA_LANES);
+
+ /* Disable Pixel Link */
+ writel(0, csi2dev->csr_regs + CSI2SS_PLM_CTRL);
+
+ /* Disable PHY */
+ writel(0, csi2dev->csr_regs + CSI2SS_PHY_CTRL);
+
+ /* Reset */
+ writel(2, csi2dev->csr_regs + CSI2SS_CTRL_CLK_RESET);
+}
+
+static void mxc_mipi_csi2_csr_config(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ u32 val;
+
+ /* format */
+ val = 0;
+ writel(val, csi2dev->csr_regs + CSI2SS_DATA_TYPE);
+
+ /* polarity */
+ val = readl(csi2dev->csr_regs + CSI2SS_PLM_CTRL);
+ val &= ~(CSI2SS_PLM_CTRL_VSYNC_OVERRIDE |
+ CSI2SS_PLM_CTRL_HSYNC_OVERRIDE |
+ CSI2SS_PLM_CTRL_VALID_OVERRIDE |
+ CSI2SS_PLM_CTRL_POLARITY_MASK);
+
+ writel(val, csi2dev->csr_regs + CSI2SS_PLM_CTRL);
+
+ val = CSI2SS_PHY_CTRL_RX_ENABLE |
+ CSI2SS_PHY_CTRL_DDRCLK_EN << CSI2SS_PHY_CTRL_DDRCLK_EN_OFFSET |
+ CSI2SS_PHY_CTRL_CONT_CLK_MODE << CSI2SS_PHY_CTRL_CONT_CLK_MODE_OFFSET |
+ csi2dev->hs_settle << CSI2SS_PHY_CTRL_RX_HS_SETTLE_OFFSET |
+ CSI2SS_PHY_CTRL_PD << CSI2SS_PHY_CTRL_PD_OFFSET |
+ CSI2SS_PHY_CTRL_RTERM_SEL << CSI2SS_PHY_CTRL_RTERM_SEL_OFFSET |
+ CSI2SS_PHY_CTRL_AUTO_PD_EN << CSI2SS_PHY_CTRL_AUTO_PD_EN_OFFSET;
+
+ writel(val, csi2dev->csr_regs + CSI2SS_PHY_CTRL);
+}
+
+static void mxc_mipi_csi2_hc_config(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ u32 val0, val1;
+ u32 i;
+
+ val0 = 0;
+
+ /* Lanes */
+ writel(csi2dev->num_lanes - 1, csi2dev->base_regs + CSI2RX_CFG_NUM_LANES);
+
+ for (i = 0; i < csi2dev->num_lanes; i++)
+ val0 |= (1 << (csi2dev->data_lanes[i] - 1));
+
+ val1 = 0xF & ~val0;
+ writel(val1, csi2dev->base_regs + CSI2RX_CFG_DISABLE_DATA_LANES);
+
+ /* Mask interrupt */
+ writel(0x1FF, csi2dev->base_regs + CSI2RX_IRQ_MASK);
+
+ /* vid_vc */
+ writel(3, csi2dev->base_regs + 0x184);
+}
+
+static struct media_pad *mxc_csi2_get_remote_sensor_pad(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ struct v4l2_subdev *subdev = &csi2dev->sd;
+ struct media_pad *sink_pad, *source_pad;
+ int i;
+
+ while (1) {
+ source_pad = NULL;
+ for (i = 0; i < subdev->entity.num_pads; i++) {
+ sink_pad = &subdev->entity.pads[i];
+
+ if (sink_pad->flags & MEDIA_PAD_FL_SINK) {
+ source_pad = media_entity_remote_pad(sink_pad);
+ if (source_pad)
+ break;
+ }
+ }
+ /* return first pad point in the loop */
+ return source_pad;
+ }
+
+ if (i == subdev->entity.num_pads)
+ v4l2_err(&csi2dev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+
+ return NULL;
+}
+
+static int mxc_csi2_get_sensor_fmt(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ struct v4l2_mbus_framefmt *mf = &csi2dev->format;
+ struct v4l2_subdev *sen_sd;
+ struct media_pad *source_pad;
+ struct v4l2_subdev_format src_fmt;
+ int ret;
+
+ /* Get remote source pad */
+ source_pad = mxc_csi2_get_remote_sensor_pad(csi2dev);
+ if (source_pad == NULL) {
+ v4l2_err(&csi2dev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sen_sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sen_sd == NULL) {
+ v4l2_err(&csi2dev->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ src_fmt.pad = source_pad->index;
+ ret = v4l2_subdev_call(sen_sd, pad, get_fmt, NULL, &src_fmt);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return -EINVAL;
+
+ /* Update input frame size and formate */
+ memcpy(mf, &src_fmt.format, sizeof(struct v4l2_mbus_framefmt));
+
+ dev_dbg(&csi2dev->pdev->dev, "width=%d, height=%d, fmt.code=0x%x\n", mf->width, mf->height, mf->code);
+
+ /* Get rxhs settle */
+ if (src_fmt.format.reserved[0] != 0)
+ csi2dev->hs_settle = calc_hs_settle(csi2dev, src_fmt.format.reserved[0]);
+ else if (src_fmt.format.reserved[1] != 0)
+ csi2dev->hs_settle = src_fmt.format.reserved[1];
+ else {
+ if (src_fmt.format.height * src_fmt.format.width > 1024 * 768)
+ csi2dev->hs_settle = rxhs_settle[2];
+ else if (src_fmt.format.height * src_fmt.format.width < 480 * 320)
+ csi2dev->hs_settle = rxhs_settle[0];
+ else
+ csi2dev->hs_settle = rxhs_settle[1];
+ }
+
+ return 0;
+}
+
+static int mipi_csi2_clk_init(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ struct device *dev = &csi2dev->pdev->dev;
+
+ csi2dev->clk_apb = devm_clk_get(dev, "clk_apb");
+ if (IS_ERR(csi2dev->clk_apb)) {
+ dev_err(dev, "failed to get csi apb clk\n");
+ return PTR_ERR(csi2dev->clk_apb);
+ }
+
+ csi2dev->clk_core = devm_clk_get(dev, "clk_core");
+ if (IS_ERR(csi2dev->clk_core)) {
+ dev_err(dev, "failed to get csi core clk\n");
+ return PTR_ERR(csi2dev->clk_core);
+ }
+
+ csi2dev->clk_esc = devm_clk_get(dev, "clk_esc");
+ if (IS_ERR(csi2dev->clk_esc)) {
+ dev_err(dev, "failed to get csi esc clk\n");
+ return PTR_ERR(csi2dev->clk_esc);
+ }
+
+ csi2dev->clk_pxl = devm_clk_get(dev, "clk_pxl");
+ if (IS_ERR(csi2dev->clk_pxl)) {
+ dev_err(dev, "failed to get csi pixel link clk\n");
+ return PTR_ERR(csi2dev->clk_pxl);
+ }
+
+ return 0;
+}
+
+static int mipi_csi2_clk_enable(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ struct device *dev = &csi2dev->pdev->dev;
+ int ret;
+
+ ret = clk_prepare_enable(csi2dev->clk_apb);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk_apb error\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(csi2dev->clk_core);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk_core error\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(csi2dev->clk_esc);
+ if (ret < 0) {
+ dev_err(dev, "%s, prepare clk_esc error\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(csi2dev->clk_pxl);
+ if (ret < 0) {
+ dev_err(dev, "%s, prepare clk_pxl error\n", __func__);
+ return ret;
+ }
+
+ return ret;
+}
+
+static void mipi_csi2_clk_disable(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ clk_disable_unprepare(csi2dev->clk_apb);
+ clk_disable_unprepare(csi2dev->clk_core);
+ clk_disable_unprepare(csi2dev->clk_esc);
+ clk_disable_unprepare(csi2dev->clk_pxl);
+}
+
+static int mipi_csi2_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+/* mipi csi2 subdev media entity operations */
+static int mipi_csi2_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ /* TODO */
+ /* Add MIPI source and sink pad link configuration */
+ if (local->flags & MEDIA_PAD_FL_SOURCE) {
+ switch (local->index) {
+ case MXC_MIPI_CSI2_VC0_PAD_SOURCE:
+ case MXC_MIPI_CSI2_VC1_PAD_SOURCE:
+ case MXC_MIPI_CSI2_VC2_PAD_SOURCE:
+ case MXC_MIPI_CSI2_VC3_PAD_SOURCE:
+ break;
+ default:
+ return 0;
+ }
+ } else if (local->flags & MEDIA_PAD_FL_SINK) {
+ switch (local->index) {
+ case MXC_MIPI_CSI2_VC0_PAD_SINK:
+ case MXC_MIPI_CSI2_VC1_PAD_SINK:
+ case MXC_MIPI_CSI2_VC2_PAD_SINK:
+ case MXC_MIPI_CSI2_VC3_PAD_SINK:
+ break;
+ default:
+ return 0;
+ }
+ }
+ return 0;
+}
+
+static const struct media_entity_operations mipi_csi2_sd_media_ops = {
+ .link_setup = mipi_csi2_link_setup,
+};
+
+/*
+ * V4L2 subdev operations
+ */
+static int mipi_csi2_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct media_pad *source_pad;
+ struct v4l2_subdev *sen_sd;
+
+ /* Get remote source pad */
+ source_pad = mxc_csi2_get_remote_sensor_pad(csi2dev);
+ if (source_pad == NULL) {
+ v4l2_err(&csi2dev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sen_sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sen_sd == NULL) {
+ v4l2_err(&csi2dev->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+ return v4l2_subdev_call(sen_sd, core, s_power, on);
+}
+
+static int mipi_csi2_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct media_pad *source_pad;
+ struct v4l2_subdev *sen_sd;
+
+ /* Get remote source pad */
+ source_pad = mxc_csi2_get_remote_sensor_pad(csi2dev);
+ if (source_pad == NULL) {
+ v4l2_err(&csi2dev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sen_sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sen_sd == NULL) {
+ v4l2_err(&csi2dev->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+ return v4l2_subdev_call(sen_sd, video, s_parm, a);
+}
+
+static int mipi_csi2_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct media_pad *source_pad;
+ struct v4l2_subdev *sen_sd;
+
+ /* Get remote source pad */
+ source_pad = mxc_csi2_get_remote_sensor_pad(csi2dev);
+ if (source_pad == NULL) {
+ v4l2_err(&csi2dev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sen_sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sen_sd == NULL) {
+ v4l2_err(&csi2dev->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ return v4l2_subdev_call(sen_sd, video, g_parm, a);
+}
+
+static int mipi_csi2_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct device *dev = &csi2dev->pdev->dev;
+ int ret = 0;
+
+ dev_dbg(&csi2dev->pdev->dev, "%s: %d, csi2dev: 0x%x\n",
+ __func__, enable, csi2dev->flags);
+
+ if (enable) {
+ pm_runtime_get_sync(dev);
+ if (!csi2dev->running) {
+ mxc_csi2_get_sensor_fmt(csi2dev);
+ mxc_mipi_csi2_hc_config(csi2dev);
+ mxc_mipi_csi2_reset(csi2dev);
+ mxc_mipi_csi2_csr_config(csi2dev);
+ mxc_mipi_csi2_enable(csi2dev);
+ mxc_mipi_csi2_reg_dump(csi2dev);
+ }
+ csi2dev->running++;
+ } else {
+
+ if (csi2dev->running)
+ mxc_mipi_csi2_disable(csi2dev);
+ csi2dev->running--;
+ pm_runtime_put(dev);
+ }
+
+ return ret;
+}
+
+static int mipi_csi2_enum_framesizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct media_pad *source_pad;
+ struct v4l2_subdev *sen_sd;
+
+ /* Get remote source pad */
+ source_pad = mxc_csi2_get_remote_sensor_pad(csi2dev);
+ if (source_pad == NULL) {
+ v4l2_err(&csi2dev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sen_sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sen_sd == NULL) {
+ v4l2_err(&csi2dev->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ return v4l2_subdev_call(sen_sd, pad, enum_frame_size, NULL, fse);
+}
+
+static int mipi_csi2_enum_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct media_pad *source_pad;
+ struct v4l2_subdev *sen_sd;
+
+ /* Get remote source pad */
+ source_pad = mxc_csi2_get_remote_sensor_pad(csi2dev);
+ if (source_pad == NULL) {
+ v4l2_err(&csi2dev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sen_sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sen_sd == NULL) {
+ v4l2_err(&csi2dev->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ return v4l2_subdev_call(sen_sd, pad, enum_frame_interval, NULL, fie);
+}
+
+static int mipi_csi2_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct v4l2_mbus_framefmt *mf = &fmt->format;
+
+ mxc_csi2_get_sensor_fmt(csi2dev);
+
+ memcpy(mf, &csi2dev->format, sizeof(struct v4l2_mbus_framefmt));
+ /* Source/Sink pads crop rectangle size */
+
+ return 0;
+}
+
+static int mipi_csi2_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops mipi_csi2_sd_internal_ops = {
+ .open = mipi_csi2_open,
+};
+
+static struct v4l2_subdev_pad_ops mipi_csi2_pad_ops = {
+ .enum_frame_size = mipi_csi2_enum_framesizes,
+ .enum_frame_interval = mipi_csi2_enum_frame_interval,
+ .get_fmt = mipi_csi2_get_fmt,
+ .set_fmt = mipi_csi2_set_fmt,
+};
+
+static struct v4l2_subdev_core_ops mipi_csi2_core_ops = {
+ .s_power = mipi_csi2_s_power,
+};
+
+static struct v4l2_subdev_video_ops mipi_csi2_video_ops = {
+ .s_parm = mipi_csi2_s_parm,
+ .g_parm = mipi_csi2_g_parm,
+ .s_stream = mipi_csi2_s_stream,
+};
+
+static struct v4l2_subdev_ops mipi_csi2_subdev_ops = {
+ .core = &mipi_csi2_core_ops,
+ .video = &mipi_csi2_video_ops,
+ .pad = &mipi_csi2_pad_ops,
+};
+static int mipi_csi2_parse_dt(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ struct device *dev = &csi2dev->pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct v4l2_of_endpoint endpoint;
+ u32 i;
+
+ csi2dev->id = of_alias_get_id(node, "csi");
+
+ csi2dev->vchannel = of_property_read_bool(node, "virtual-channel");
+
+ node = of_graph_get_next_endpoint(node, NULL);
+ if (!node) {
+ dev_err(dev, "No port node at %s\n", node->full_name);
+ return -EINVAL;
+ }
+
+ /* Get port node */
+ v4l2_of_parse_endpoint(node, &endpoint);
+
+ csi2dev->num_lanes = endpoint.bus.mipi_csi2.num_data_lanes;
+ for (i = 0; i < 4; i++)
+ csi2dev->data_lanes[i] = endpoint.bus.mipi_csi2.data_lanes[i];
+
+ of_node_put(node);
+
+ return 0;
+}
+
+static int mipi_csi2_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *mem_res;
+ struct mxc_mipi_csi2_dev *csi2dev;
+ int ret = -ENOMEM;
+
+ dev_info(&pdev->dev, "%s\n", __func__);
+ csi2dev = devm_kzalloc(dev, sizeof(*csi2dev), GFP_KERNEL);
+ if (!csi2dev)
+ return -ENOMEM;
+
+ csi2dev->pdev = pdev;
+ mutex_init(&csi2dev->lock);
+
+ ret = mipi_csi2_parse_dt(csi2dev);
+ if (ret < 0)
+ return -EINVAL ;
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ csi2dev->base_regs = devm_ioremap_resource(dev, mem_res);
+ if (IS_ERR(csi2dev->base_regs)) {
+ dev_err(dev, "Failed to get mipi csi2 HC register\n");
+ return PTR_ERR(csi2dev->base_regs);
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ csi2dev->csr_regs = devm_ioremap_resource(dev, mem_res);
+ if (IS_ERR(csi2dev->csr_regs)) {
+ dev_err(dev, "Failed to get mipi CSR register\n");
+ return PTR_ERR(csi2dev->csr_regs);
+ }
+
+ ret = mipi_csi2_clk_init(csi2dev);
+ if (ret < 0)
+ return -EINVAL ;
+
+ v4l2_subdev_init(&csi2dev->sd, &mipi_csi2_subdev_ops);
+
+ csi2dev->sd.owner = THIS_MODULE;
+ snprintf(csi2dev->sd.name, sizeof(csi2dev->sd.name), "%s.%d",
+ MXC_MIPI_CSI2_SUBDEV_NAME, csi2dev->id);
+
+ csi2dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ csi2dev->sd.entity.function = MEDIA_ENT_F_IO_V4L;
+
+ csi2dev->sd.dev = dev;
+
+ csi2dev->pads[MXC_MIPI_CSI2_VC0_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ csi2dev->pads[MXC_MIPI_CSI2_VC1_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ csi2dev->pads[MXC_MIPI_CSI2_VC2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ csi2dev->pads[MXC_MIPI_CSI2_VC3_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ csi2dev->pads[MXC_MIPI_CSI2_VC0_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ csi2dev->pads[MXC_MIPI_CSI2_VC1_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ csi2dev->pads[MXC_MIPI_CSI2_VC2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ csi2dev->pads[MXC_MIPI_CSI2_VC3_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&csi2dev->sd.entity,
+ MXC_MIPI_CSI2_VCX_PADS_NUM, csi2dev->pads);
+ if (ret < 0)
+ goto e_clkdis;
+
+ csi2dev->sd.entity.ops = &mipi_csi2_sd_media_ops;
+
+ /* This allows to retrieve the platform device id by the host driver */
+ v4l2_set_subdevdata(&csi2dev->sd, pdev);
+
+ /* .. and a pointer to the subdev. */
+ platform_set_drvdata(pdev, csi2dev);
+
+ mipi_sc_fw_init(csi2dev, 1);
+
+ csi2dev->running = 0;
+ csi2dev->flags = MXC_MIPI_CSI2_PM_POWERED;
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+
+ ret = mipi_csi2_clk_enable(csi2dev);
+ if (ret < 0)
+ goto e_clkdis;
+
+ dev_info(&pdev->dev, "lanes: %d, name: %s\n",
+ csi2dev->num_lanes, csi2dev->sd.name);
+ pm_runtime_put_sync(dev);
+
+ return 0;
+
+e_clkdis:
+ media_entity_cleanup(&csi2dev->sd.entity);
+ return ret;
+}
+
+static int mipi_csi2_remove(struct platform_device *pdev)
+{
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+
+ pm_runtime_get_sync(&pdev->dev);
+ mipi_sc_fw_init(csi2dev, 0);
+ media_entity_cleanup(&csi2dev->sd.entity);
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static int mipi_csi2_suspend(struct device *dev, bool runtime)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = dev_get_drvdata(dev);
+ struct v4l2_subdev *sd = &csi2dev->sd;
+
+ mutex_lock(&csi2dev->lock);
+ if (csi2dev->flags & MXC_MIPI_CSI2_PM_POWERED) {
+ if (csi2dev->running)
+ mipi_csi2_s_stream(sd, false);
+
+ mipi_csi2_clk_disable(csi2dev);
+ csi2dev->flags &= ~MXC_MIPI_CSI2_PM_POWERED;
+
+ if (runtime)
+ csi2dev->flags |= MXC_MIPI_CSI2_RUNTIME_SUSPENDED;
+ else
+ csi2dev->flags |= MXC_MIPI_CSI2_PM_SUSPENDED;
+ }
+ mutex_unlock(&csi2dev->lock);
+ return 0;
+}
+
+static int mipi_csi2_resume(struct device *dev, bool runtime)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = dev_get_drvdata(dev);
+ struct v4l2_subdev *sd = &csi2dev->sd;
+ int ret;
+
+ mutex_lock(&csi2dev->lock);
+ if (!(csi2dev->flags & MXC_MIPI_CSI2_RUNTIME_SUSPENDED) &&
+ !(csi2dev->flags & MXC_MIPI_CSI2_PM_SUSPENDED)) {
+ mutex_unlock(&csi2dev->lock);
+ return 0;
+ }
+
+ if (!(csi2dev->flags & MXC_MIPI_CSI2_PM_POWERED)) {
+ ret = mipi_csi2_clk_enable(csi2dev);
+ if (ret < 0) {
+ mutex_unlock(&csi2dev->lock);
+ dev_err(dev, "%s:%d fail\n", __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ if (csi2dev->running)
+ mipi_csi2_s_stream(sd, true);
+
+ csi2dev->flags |= MXC_MIPI_CSI2_PM_POWERED;
+ if (runtime)
+ csi2dev->flags &= ~MXC_MIPI_CSI2_RUNTIME_SUSPENDED;
+ else
+ csi2dev->flags &= ~MXC_MIPI_CSI2_PM_SUSPENDED;
+ }
+ mutex_unlock(&csi2dev->lock);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mipi_csi2_pm_suspend(struct device *dev)
+{
+ return mipi_csi2_suspend(dev, false);
+}
+
+static int mipi_csi2_pm_resume(struct device *dev)
+{
+ return mipi_csi2_resume(dev, false);
+}
+#endif
+
+static int mipi_csi2_runtime_suspend(struct device *dev)
+{
+ return mipi_csi2_suspend(dev, true);
+}
+static int mipi_csi2_runtime_resume(struct device *dev)
+{
+ return mipi_csi2_resume(dev, true);
+}
+
+static const struct dev_pm_ops mipi_csi_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mipi_csi2_pm_suspend, mipi_csi2_pm_resume)
+ SET_RUNTIME_PM_OPS(mipi_csi2_runtime_suspend, mipi_csi2_runtime_resume, NULL)
+};
+
+static const struct of_device_id mipi_csi2_of_match[] = {
+ { .compatible = "fsl,mxc-mipi-csi2",},
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mipi_csi2_of_match);
+
+
+static struct platform_driver mipi_csi2_driver = {
+ .driver = {
+ .name = MXC_MIPI_CSI2_DRIVER_NAME,
+ .of_match_table = mipi_csi2_of_match,
+ .pm = &mipi_csi_pm_ops,
+ },
+ .probe = mipi_csi2_probe,
+ .remove = mipi_csi2_remove,
+};
+
+module_platform_driver(mipi_csi2_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC MIPI CSI2 driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" MXC_MIPI_CSI2_DRIVER_NAME);
diff --git a/drivers/media/platform/imx8/mxc-mipi-csi2.h b/drivers/media/platform/imx8/mxc-mipi-csi2.h
new file mode 100644
index 000000000000..ed01adc1958b
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-mipi-csi2.h
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2017 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef MXC_MIPI_CSI2_H_
+#define MXC_MIPI_CSI2_H_
+
+#include <media/v4l2-device.h>
+
+#define MXC_MIPI_CSI2_DRIVER_NAME "mxc-mipi-csi2"
+#define MXC_MIPI_CSI2_SUBDEV_NAME MXC_MIPI_CSI2_DRIVER_NAME
+#define MXC_MIPI_CSI2_MAX_DEVS 2
+#define MXC_MIPI_CSI2_MAX_LANES 4
+
+#define MIPI_CSI2_OF_NODE_NAME "csi"
+
+#define MXC_MIPI_CSI2_VC0_PAD_SINK 0
+#define MXC_MIPI_CSI2_VC1_PAD_SINK 1
+#define MXC_MIPI_CSI2_VC2_PAD_SINK 2
+#define MXC_MIPI_CSI2_VC3_PAD_SINK 3
+
+#define MXC_MIPI_CSI2_VC0_PAD_SOURCE 4
+#define MXC_MIPI_CSI2_VC1_PAD_SOURCE 5
+#define MXC_MIPI_CSI2_VC2_PAD_SOURCE 6
+#define MXC_MIPI_CSI2_VC3_PAD_SOURCE 7
+#define MXC_MIPI_CSI2_VCX_PADS_NUM 8
+
+/* Subsystem CSR */
+#define CSI2SS_BASE_OFFSET 0x0
+
+#define CSI2SS_PLM_CTRL (CSI2SS_BASE_OFFSET + 0x0)
+#define CSI2SS_PLM_CTRL_PL_CLK_RUN 0x80000000
+#define CSI2SS_PLM_CTRL_VSYNC_OVERRIDE 0x200
+#define CSI2SS_PLM_CTRL_HSYNC_OVERRIDE 0x400
+#define CSI2SS_PLM_CTRL_VALID_OVERRIDE 0x800
+#define CSI2SS_PLM_CTRL_POLARITY_MASK 0x1000
+#define CSI2SS_PLM_CTRL_POLARITY_HIGH 0x1000
+#define CSI2SS_PLM_CTRL_POLARITY_LOW 0x0
+#define CSI2SS_PLM_CTRL_ENABLE_PL 1
+#define CSI2SS_PLM_CTRL_ENABLE_PL_OFFSET 0
+#define CSI2SS_PLM_CTRL_ENABLE_PL_MASK 1
+
+#define CSI2SS_PHY_CTRL (CSI2SS_BASE_OFFSET + 0x4)
+#define CSI2SS_PHY_CTRL_PD 1
+#define CSI2SS_PHY_CTRL_PD_OFFSET 22
+#define CSI2SS_PHY_CTRL_PD_MASK 0x400000
+#define CSI2SS_PHY_CTRL_RTERM_SEL 1
+#define CSI2SS_PHY_CTRL_RTERM_SEL_OFFSET 21
+#define CSI2SS_PHY_CTRL_RTERM_SEL_MASK 0x200000
+#define CSI2SS_PHY_CTRL_RX_HS_SETTLE_OFFSET 4
+#define CSI2SS_PHY_CTRL_RX_HS_SETTLE_MASK 0x3F0
+#define CSI2SS_PHY_CTRL_CONT_CLK_MODE 1
+#define CSI2SS_PHY_CTRL_CONT_CLK_MODE_OFFSET 3
+#define CSI2SS_PHY_CTRL_CONT_CLK_MODE_MASK 0x8
+#define CSI2SS_PHY_CTRL_DDRCLK_EN 1
+#define CSI2SS_PHY_CTRL_DDRCLK_EN_OFFSET 2
+#define CSI2SS_PHY_CTRL_DDRCLK_EN_MASK 0x4
+#define CSI2SS_PHY_CTRL_AUTO_PD_EN 1
+#define CSI2SS_PHY_CTRL_AUTO_PD_EN_OFFSET 1
+#define CSI2SS_PHY_CTRL_AUTO_PD_EN_MASK 0x2
+#define CSI2SS_PHY_CTRL_RX_ENABLE 1
+#define CSI2SS_PHY_CTRL_RX_ENABLE_OFFSET 0
+#define CSI2SS_PHY_CTRL_RX_ENABLE_MASK 0x1
+
+#define CSI2SS_PHY_STATUS (CSI2SS_BASE_OFFSET + 0x8)
+#define CSI2SS_PHY_TEST_STATUS (CSI2SS_BASE_OFFSET + 0x10)
+#define CSI2SS_PHY_TEST_STATUS_D0 (CSI2SS_BASE_OFFSET + 0x14)
+#define CSI2SS_PHY_TEST_STATUS_D1 (CSI2SS_BASE_OFFSET + 0x18)
+#define CSI2SS_PHY_TEST_STATUS_D2 (CSI2SS_BASE_OFFSET + 0x1C)
+#define CSI2SS_PHY_TEST_STATUS_D3 (CSI2SS_BASE_OFFSET + 0x20)
+
+#define CSI2SS_VC_INTERLACED (CSI2SS_BASE_OFFSET + 0x30)
+#define CSI2SS_VC_INTERLACED_VC0 1
+#define CSI2SS_VC_INTERLACED_VC1 2
+#define CSI2SS_VC_INTERLACED_VC2 4
+#define CSI2SS_VC_INTERLACED_VC3 8
+#define CSI2SS_VC_INTERLACED_OFFSET 0
+#define CSI2SS_VC_INTERLACED_MASK 0xF
+
+#define CSI2SS_DATA_TYPE (CSI2SS_BASE_OFFSET + 0x38)
+#define CSI2SS_DATA_TYPE_LEGACY_YUV420_8BIT (1 << 2)
+#define CSI2SS_DATA_TYPE_YUV422_8BIT (1 << 6)
+#define CSI2SS_DATA_TYPE_YUV422_10BIT (1 << 7)
+#define CSI2SS_DATA_TYPE_RGB444 (1 << 8)
+#define CSI2SS_DATA_TYPE_RGB555 (1 << 9)
+#define CSI2SS_DATA_TYPE_RGB565 (1 << 10)
+#define CSI2SS_DATA_TYPE_RGB666 (1 << 11)
+#define CSI2SS_DATA_TYPE_RGB888 (1 << 12)
+#define CSI2SS_DATA_TYPE_RAW6 (1 << 16)
+#define CSI2SS_DATA_TYPE_RAW8 (1 << 18)
+#define CSI2SS_DATA_TYPE_RAW10 (1 << 19)
+#define CSI2SS_DATA_TYPE_RAW12 (1 << 20)
+#define CSI2SS_DATA_TYPE_RAW14 (1 << 21)
+
+#define CSI2SS_YUV420_1ST_LINE_DATA_TYPE (CSI2SS_BASE_OFFSET + 0x40)
+#define CSI2SS_YUV420_1ST_LINE_DATA_TYPE_ODD 0
+#define CSI2SS_YUV420_1ST_LINE_DATA_TYPE_EVEN 1
+#define CSI2SS_YUV420_1ST_LINE_DATA_TYPE_OFFSET 0
+#define CSI2SS_YUV420_1ST_LINE_DATA_TYPE_MASK 1
+
+#define CSI2SS_CTRL_CLK_RESET (CSI2SS_BASE_OFFSET + 0x44)
+#define CSI2SS_CTRL_CLK_RESET_EN 1
+#define CSI2SS_CTRL_CLK_RESET_OFFSET 0
+#define CSI2SS_CTRL_CLK_RESET_MASK 1
+#define CSI2SS_CTRL_CLK_RESET_CLK_OFF 1
+#define CSI2SS_CTRL_CLK_RESET_CLK_OFFSET 1
+#define CSI2SS_CTRL_CLK_RESET_CLK_MASK 0x1
+
+#define CSI2SS_STREAM_FENCE_CTRL (CSI2SS_BASE_OFFSET + 0x48)
+#define CSI2SS_STREAM_FENCE_VC0 1
+#define CSI2SS_STREAM_FENCE_VC1 2
+#define CSI2SS_STREAM_FENCE_VC2 4
+#define CSI2SS_STREAM_FENCE_VC3 8
+#define CSI2SS_STREAM_FENCE_CTRL_OFFSET 0
+#define CSI2SS_STREAM_FENCE_CTRL_MASK 0xF
+
+#define CSI2SS_STREAM_FENCE_STATUS (CSI2SS_BASE_OFFSET + 0x4C)
+
+/* CSI-2 controller CSR */
+#define CSI2RX_BASE_OFFSET (0x100)
+
+#define CSI2RX_CFG_NUM_LANES (CSI2RX_BASE_OFFSET + 0x0)
+#define CSI2RX_CFG_NUM_LANES_OFFSET 0
+#define CSI2RX_CFG_NUM_LANES_MASK 0x3
+
+#define CSI2RX_CFG_DISABLE_DATA_LANES (CSI2RX_BASE_OFFSET + 0x4)
+#define CSI2RX_CFG_DISABLE_DATA_LANES_3 8
+#define CSI2RX_CFG_DISABLE_DATA_LANES_2 4
+#define CSI2RX_CFG_DISABLE_DATA_LANES_1 2
+#define CSI2RX_CFG_DISABLE_DATA_LANES_0 1
+#define CSI2RX_CFG_DISABLE_DATA_LANES_OFFSET 0
+#define CSI2RX_CFG_DISABLE_DATA_LANES_MASK 0xF
+
+#define CSI2RX_BIT_ERR (CSI2RX_BASE_OFFSET + 0x8)
+
+#define CSI2RX_IRQ_STATUS (CSI2RX_BASE_OFFSET + 0xC)
+#define CSI2RX_IRQ_STATUS_CRC_ERROR 0x1
+#define CSI2RX_IRQ_STATUS_1BIT_CRC_ERROR 0x2
+#define CSI2RX_IRQ_STATUS_2BIT_CRC_ERROR 0x4
+#define CSI2RX_IRQ_STATUS_ULPS_CHANGE 0x8
+#define CSI2RX_IRQ_STATUS_DPHY_ERRSOTHS 0x10
+#define CSI2RX_IRQ_STATUS_DPHY_ERRSOTSYNC_HS 0x20
+#define CSI2RX_IRQ_STATUS_DPHY_ERRESC 0x40
+#define CSI2RX_IRQ_STATUS_DPHY_ERRSYNCESC 0x80
+#define CSI2RX_IRQ_STATUS_DPHY_ERRCTRL 0x100
+
+#define CSI2RX_IRQ_MASK (CSI2RX_BASE_OFFSET + 0x10)
+#define CSI2RX_IRQ_MASK_CRC_ERROR 0x1
+#define CSI2RX_IRQ_MASK_1BIT_CRC_ERROR 0x2
+#define CSI2RX_IRQ_MASK_2BIT_CRC_ERROR 0x4
+#define CSI2RX_IRQ_MASK_ULPS_CHANGE 0x8
+#define CSI2RX_IRQ_MASK_DPHY_ERRSOTHS 0x10
+#define CSI2RX_IRQ_MASK_DPHY_ERRSOTSYNC_HS 0x20
+#define CSI2RX_IRQ_MASK_DPHY_ERRESC 0x40
+#define CSI2RX_IRQ_MASK_DPHY_ERRSYNCESC 0x80
+#define CSI2RX_IRQ_MASK_DPHY_ERRCTRL 0x100
+
+#define CSI2RX_ULPS_STATUS (CSI2RX_BASE_OFFSET + 0x14)
+#define CSI2RX_ULPS_STATUS_CLK_LANE_ULPS 0x1
+#define CSI2RX_ULPS_STATUS_DAT_LANE0_ULPS 0x2
+#define CSI2RX_ULPS_STATUS_DAT_LANE1_ULPS 0x4
+#define CSI2RX_ULPS_STATUS_DAT_LANE2_ULPS 0x8
+#define CSI2RX_ULPS_STATUS_DAT_LANE3_ULPS 0x10
+#define CSI2RX_ULPS_STATUS_CLK_LANE_MARK 0x20
+#define CSI2RX_ULPS_STATUS_DAT_LANE0_MARK 0x40
+#define CSI2RX_ULPS_STATUS_DAT_LANE1_MARK 0x80
+#define CSI2RX_ULPS_STATUS_DAT_LANE2_MARK 0x100
+#define CSI2RX_ULPS_STATUS_DAT_LANE3_MARK 0x200
+
+#define CSI2RX_PPI_ERRSOT_HS (CSI2RX_BASE_OFFSET + 0x18)
+#define CSI2RX_PPI_ERRSOT_HS_DAT_LANE0 0x1
+#define CSI2RX_PPI_ERRSOT_HS_DAT_LANE1 0x2
+#define CSI2RX_PPI_ERRSOT_HS_DAT_LANE2 0x4
+#define CSI2RX_PPI_ERRSOT_HS_DAT_LANE3 0x8
+
+#define CSI2RX_PPI_ERRSOTSYNC_HS (CSI2RX_BASE_OFFSET + 0x1C)
+#define CSI2RX_PPI_ERRSOTSYNC_HS_DAT_LANE0 0x1
+#define CSI2RX_PPI_ERRSOTSYNC_HS_DAT_LANE1 0x2
+#define CSI2RX_PPI_ERRSOTSYNC_HS_DAT_LANE2 0x4
+#define CSI2RX_PPI_ERRSOTSYNC_HS_DAT_LANE3 0x8
+
+#define CSI2RX_PPI_ERRESC (CSI2RX_BASE_OFFSET + 0x20)
+#define CSI2RX_PPI_ERRESC_DAT_LANE0 0x1
+#define CSI2RX_PPI_ERRESC_DAT_LANE1 0x2
+#define CSI2RX_PPI_ERRESC_DAT_LANE2 0x4
+#define CSI2RX_PPI_ERRESC_DAT_LANE3 0x8
+
+#define CSI2RX_PPI_ERRSYNCESC (CSI2RX_BASE_OFFSET + 0x24)
+#define CSI2RX_PPI_ERRSYNCESC_DAT_LANE0 0x1
+#define CSI2RX_PPI_ERRSYNCESC_DAT_LANE1 0x2
+#define CSI2RX_PPI_ERRSYNCESC_DAT_LANE2 0x4
+#define CSI2RX_PPI_ERRSYNCESC_DAT_LANE3 0x8
+
+#define CSI2RX_PPI_ERRCONTROL (CSI2RX_BASE_OFFSET + 0x28)
+#define CSI2RX_PPI_ERRCONTROL_DAT_LANE0 0x1
+#define CSI2RX_PPI_ERRCONTROL_DAT_LANE1 0x2
+#define CSI2RX_PPI_ERRCONTROL_DAT_LANE2 0x4
+#define CSI2RX_PPI_ERRCONTROL_DAT_LANE3 0x8
+
+#define CSI2RX_CFG_DISABLE_PAYLOAD_0 (CSI2RX_BASE_OFFSET + 0x2C)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_LEGACY_YUV420_8BIT (1 << 10)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_YUV422_8BIT (1 << 14)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_YUV422_10BIT (1 << 15)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RGB444 (1 << 16)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RGB555 (1 << 17)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RGB565 (1 << 18)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RGB666 (1 << 19)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RGB888 (1 << 20)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RAW6 (1 << 24)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RAW7 (1 << 25)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RAW8 (1 << 26)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RAW10 (1 << 27)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RAW12 (1 << 28)
+#define CSI2RX_CFG_DISABLE_PAYLOAD_TYPE_RAW14 (1 << 29)
+
+#define CSI2RX_CFG_DISABLE_PAYLOAD_1 (CSI2RX_BASE_OFFSET + 0x30)
+
+struct csis_hw_reset {
+ struct regmap *src;
+ u8 req_src;
+ u8 rst_val;
+};
+struct csis_phy_gpr {
+ struct regmap *gpr;
+ u8 req_src;
+};
+
+struct mxc_mipi_csi2_dev {
+ struct v4l2_device v4l2_dev;
+ struct v4l2_subdev sd;
+ struct v4l2_subdev *sensor_sd;
+
+ struct media_pad pads[MXC_MIPI_CSI2_VCX_PADS_NUM];
+ struct v4l2_mbus_framefmt format;
+
+ void __iomem *csr_regs;
+ void __iomem *base_regs;
+ struct platform_device *pdev;
+ u32 flags;
+ int irq;
+
+ struct clk *clk_apb;
+ struct clk *clk_core;
+ struct clk *clk_esc;
+ struct clk *clk_pxl;
+
+ struct csis_hw_reset hw_reset;
+ struct csis_phy_gpr phy_gpr;
+
+ struct v4l2_async_subdev asd;
+ struct v4l2_async_notifier subdev_notifier;
+ struct v4l2_async_subdev *async_subdevs[2];
+
+ struct mutex lock;
+
+ int id;
+ u32 hs_settle;
+ u32 send_level;
+ u32 num_lanes;
+ u8 data_lanes[4];
+ u8 vchannel;
+ u8 running;
+};
+
+enum mxc_mipi_csi2_pm_state {
+ MXC_MIPI_CSI2_PM_POWERED = 0x1,
+ MXC_MIPI_CSI2_PM_SUSPENDED = 0x2,
+ MXC_MIPI_CSI2_RUNTIME_SUSPENDED = 0x4,
+};
+
+#endif
diff --git a/drivers/media/platform/imx8/mxc-mipi-csi2_yav.c b/drivers/media/platform/imx8/mxc-mipi-csi2_yav.c
new file mode 100644
index 000000000000..950b1d3149fd
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-mipi-csi2_yav.c
@@ -0,0 +1,749 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/memory.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-of.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+
+#include "mxc-mipi-csi2.h"
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+#define MXC_MIPI_CSI2_YAV_DRIVER_NAME "mxc-mipi-csi2_yav"
+#define MXC_MIPI_CSI2_YAV_SUBDEV_NAME MXC_MIPI_CSI2_DRIVER_NAME
+
+#define GPR_CSI2_1_RX_ENABLE BIT(13)
+#define GPR_CSI2_1_VID_INTFC_ENB BIT(12)
+#define GPR_CSI2_1_PD_RX BIT(11)
+#define GPR_CSI2_1_HSEL BIT(10)
+#define GPR_CSI2_1_AUTO_PD_EN BIT(9)
+#define GPR_CSI2_1_CONT_CLK_MODE BIT(8)
+#define GPR_CSI2_1_S_PRG_RXHS_SETTLE(x) (((x) & 0x3F) << 2)
+#define GPR_CSI2_1_RX_RCAL (3)
+
+static u8 rxhs_settle[2] = { 0x14, 0x9 };
+
+static struct mxc_mipi_csi2_dev *sd_to_mxc_mipi_csi2_dev(struct v4l2_subdev
+ *sdev)
+{
+ return container_of(sdev, struct mxc_mipi_csi2_dev, sd);
+}
+
+#ifdef debug
+static void mxc_mipi_csi2_reg_dump(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ printk("MIPI CSI2 HC register dump, mipi csi%d\n", csi2dev->id);
+ printk("MIPI CSI2 HC num of lanes 0x100 = 0x%x\n",
+ readl(csi2dev->base_regs + 0x100));
+ printk("MIPI CSI2 HC dis lanes 0x104 = 0x%x\n",
+ readl(csi2dev->base_regs + 0x104));
+ printk("MIPI CSI2 HC BIT ERR 0x108 = 0x%x\n",
+ readl(csi2dev->base_regs + 0x108));
+ printk("MIPI CSI2 HC IRQ STATUS 0x10C = 0x%x\n",
+ readl(csi2dev->base_regs + 0x10C));
+ printk("MIPI CSI2 HC IRQ MASK 0x110 = 0x%x\n",
+ readl(csi2dev->base_regs + 0x110));
+ printk("MIPI CSI2 HC ULPS STATUS 0x114 = 0x%x\n",
+ readl(csi2dev->base_regs + 0x114));
+ printk("MIPI CSI2 HC DPHY ErrSotHS 0x118 = 0x%x\n",
+ readl(csi2dev->base_regs + 0x118));
+ printk("MIPI CSI2 HC DPHY ErrSotSync 0x11c = 0x%x\n",
+ readl(csi2dev->base_regs + 0x11c));
+ printk("MIPI CSI2 HC DPHY ErrEsc 0x120 = 0x%x\n",
+ readl(csi2dev->base_regs + 0x120));
+ printk("MIPI CSI2 HC DPHY ErrSyncEsc 0x124 = 0x%x\n",
+ readl(csi2dev->base_regs + 0x124));
+ printk("MIPI CSI2 HC DPHY ErrControl 0x128 = 0x%x\n",
+ readl(csi2dev->base_regs + 0x128));
+ printk("MIPI CSI2 HC DISABLE_PAYLOAD 0x12C = 0x%x\n",
+ readl(csi2dev->base_regs + 0x12C));
+ printk("MIPI CSI2 HC DISABLE_PAYLOAD 0x130 = 0x%x\n",
+ readl(csi2dev->base_regs + 0x130));
+ printk("MIPI CSI2 HC IGNORE_VC 0x180 = 0x%x\n",
+ readl(csi2dev->base_regs + 0x180));
+ printk("MIPI CSI2 HC VID_VC 0x184 = 0x%x\n",
+ readl(csi2dev->base_regs + 0x184));
+ printk("MIPI CSI2 HC FIFO_SEND_LEVEL 0x188 = 0x%x\n",
+ readl(csi2dev->base_regs + 0x188));
+ printk("MIPI CSI2 HC VID_VSYNC 0x18C = 0x%x\n",
+ readl(csi2dev->base_regs + 0x18C));
+ printk("MIPI CSI2 HC VID_SYNC_FP 0x190 = 0x%x\n",
+ readl(csi2dev->base_regs + 0x190));
+ printk("MIPI CSI2 HC VID_HSYNC 0x194 = 0x%x\n",
+ readl(csi2dev->base_regs + 0x194));
+ printk("MIPI CSI2 HC VID_HSYNC_BP 0x198 = 0x%x\n",
+ readl(csi2dev->base_regs + 0x198));
+}
+#else
+static void mxc_mipi_csi2_reg_dump(struct mxc_mipi_csi2_dev *csi2dev)
+{
+}
+#endif
+
+static int mxc_mipi_csi2_phy_reset(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ struct device *dev = &csi2dev->pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *node;
+ phandle phandle;
+ u32 out_val[3];
+ int ret;
+
+ ret = of_property_read_u32_array(np, "csis-phy-reset", out_val, 3);
+ if (ret) {
+ dev_info(dev, "no csis-hw-reset property found\n");
+ } else {
+ phandle = *out_val;
+
+ node = of_find_node_by_phandle(phandle);
+ if (!node) {
+ dev_dbg(dev, "not find src node by phandle\n");
+ ret = PTR_ERR(node);
+ }
+ csi2dev->hw_reset.src = syscon_node_to_regmap(node);
+ if (IS_ERR(csi2dev->hw_reset.src)) {
+ dev_err(dev, "failed to get src regmap\n");
+ ret = PTR_ERR(csi2dev->hw_reset.src);
+ }
+ of_node_put(node);
+ if (ret < 0)
+ return ret;
+
+ csi2dev->hw_reset.req_src = out_val[1];
+ csi2dev->hw_reset.rst_val = out_val[2];
+
+ /* reset mipi phy */
+ regmap_update_bits(csi2dev->hw_reset.src,
+ csi2dev->hw_reset.req_src,
+ csi2dev->hw_reset.rst_val,
+ csi2dev->hw_reset.rst_val);
+ msleep(20);
+ }
+
+ return ret;
+}
+
+static int mxc_mipi_csi2_phy_gpr(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ struct device *dev = &csi2dev->pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *node;
+ phandle phandle;
+ u32 out_val[2];
+ int ret;
+
+ ret = of_property_read_u32_array(np, "phy-gpr", out_val, 2);
+ if (ret) {
+ dev_dbg(dev, "no phy-gpr property found\n");
+ } else {
+ phandle = *out_val;
+
+ node = of_find_node_by_phandle(phandle);
+ if (!node) {
+ dev_dbg(dev, "not find gpr node by phandle\n");
+ ret = PTR_ERR(node);
+ }
+ csi2dev->phy_gpr.gpr = syscon_node_to_regmap(node);
+ if (IS_ERR(csi2dev->phy_gpr.gpr)) {
+ dev_err(dev, "failed to get gpr regmap\n");
+ ret = PTR_ERR(csi2dev->phy_gpr.gpr);
+ }
+ of_node_put(node);
+ if (ret < 0)
+ return ret;
+
+ csi2dev->phy_gpr.req_src = out_val[1];
+
+ regmap_update_bits(csi2dev->phy_gpr.gpr,
+ csi2dev->phy_gpr.req_src,
+ 0x3FFF,
+ GPR_CSI2_1_RX_ENABLE |
+ GPR_CSI2_1_VID_INTFC_ENB |
+ GPR_CSI2_1_HSEL |
+ GPR_CSI2_1_CONT_CLK_MODE |
+ GPR_CSI2_1_S_PRG_RXHS_SETTLE(csi2dev->
+ hs_settle));
+ }
+
+ return ret;
+}
+
+static void mxc_mipi_csi2_enable(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ mxc_mipi_csi2_phy_gpr(csi2dev);
+}
+
+static void mxc_mipi_csi2_disable(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ /* Disable Data lanes */
+ writel(0xf, csi2dev->base_regs + CSI2RX_CFG_DISABLE_DATA_LANES);
+}
+
+static void mxc_mipi_csi2_hc_config(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ u32 val0, val1;
+ u32 i;
+
+ val0 = 0;
+
+ /* Lanes */
+ writel(csi2dev->num_lanes - 1,
+ csi2dev->base_regs + CSI2RX_CFG_NUM_LANES);
+
+ for (i = 0; i < csi2dev->num_lanes; i++)
+ val0 |= (1 << (csi2dev->data_lanes[i] - 1));
+
+ val1 = 0xF & ~val0;
+ writel(val1, csi2dev->base_regs + CSI2RX_CFG_DISABLE_DATA_LANES);
+
+ /* Mask interrupt */
+ writel(0x1FF, csi2dev->base_regs + CSI2RX_IRQ_MASK);
+
+ writel(1, csi2dev->base_regs + 0x180);
+ /* vid_vc */
+ writel(1, csi2dev->base_regs + 0x184);
+ writel(csi2dev->send_level, csi2dev->base_regs + 0x188);
+}
+
+static int mipi_csi2_clk_init(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ struct device *dev = &csi2dev->pdev->dev;
+
+ csi2dev->clk_apb = devm_clk_get(dev, "clk_apb");
+ if (IS_ERR(csi2dev->clk_apb)) {
+ dev_err(dev, "failed to get csi apb clk\n");
+ return PTR_ERR(csi2dev->clk_apb);
+ }
+
+ csi2dev->clk_core = devm_clk_get(dev, "clk_core");
+ if (IS_ERR(csi2dev->clk_core)) {
+ dev_err(dev, "failed to get csi core clk\n");
+ return PTR_ERR(csi2dev->clk_core);
+ }
+
+ csi2dev->clk_esc = devm_clk_get(dev, "clk_esc");
+ if (IS_ERR(csi2dev->clk_esc)) {
+ dev_err(dev, "failed to get csi esc clk\n");
+ return PTR_ERR(csi2dev->clk_esc);
+ }
+
+ csi2dev->clk_pxl = devm_clk_get(dev, "clk_pxl");
+ if (IS_ERR(csi2dev->clk_pxl)) {
+ dev_err(dev, "failed to get csi pixel link clk\n");
+ return PTR_ERR(csi2dev->clk_pxl);
+ }
+
+ return 0;
+}
+
+static int mipi_csi2_clk_enable(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ struct device *dev = &csi2dev->pdev->dev;
+ int ret;
+
+ ret = clk_prepare_enable(csi2dev->clk_apb);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk_apb error\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(csi2dev->clk_core);
+ if (ret < 0) {
+ dev_err(dev, "%s, pre clk_core error\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(csi2dev->clk_esc);
+ if (ret < 0) {
+ dev_err(dev, "%s, prepare clk_esc error\n", __func__);
+ return ret;
+ }
+ ret = clk_prepare_enable(csi2dev->clk_pxl);
+ if (ret < 0) {
+ dev_err(dev, "%s, prepare clk_pxl error\n", __func__);
+ return ret;
+ }
+ return ret;
+}
+
+static void mipi_csi2_clk_disable(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ clk_disable_unprepare(csi2dev->clk_apb);
+ clk_disable_unprepare(csi2dev->clk_core);
+ clk_disable_unprepare(csi2dev->clk_esc);
+ clk_disable_unprepare(csi2dev->clk_pxl);
+}
+
+static int mipi_csi2_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+/*
+ * V4L2 subdev operations
+ */
+static int mipi_csi2_s_power(struct v4l2_subdev *sd, int on)
+{
+ return 0;
+}
+
+static int mipi_csi2_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct device *dev = &csi2dev->pdev->dev;
+ struct v4l2_subdev *sensor_sd = csi2dev->sensor_sd;
+ int ret = 0;
+
+ dev_dbg(&csi2dev->pdev->dev, "%s: %d, csi2dev: 0x%x\n",
+ __func__, enable, csi2dev->flags);
+
+ if (enable) {
+ if (!csi2dev->running) {
+ pm_runtime_get_sync(dev);
+ mxc_mipi_csi2_phy_reset(csi2dev);
+ mxc_mipi_csi2_hc_config(csi2dev);
+ mxc_mipi_csi2_enable(csi2dev);
+ mxc_mipi_csi2_reg_dump(csi2dev);
+ }
+ v4l2_subdev_call(sensor_sd, video, s_stream, true);
+ csi2dev->running++;
+
+ } else {
+
+ v4l2_subdev_call(sensor_sd, video, s_stream, false);
+ csi2dev->running--;
+ if (!csi2dev->running) {
+ pm_runtime_put(dev);
+ mxc_mipi_csi2_disable(csi2dev);
+ }
+ }
+
+ return ret;
+}
+
+static int mipi_csis_enum_framesizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct v4l2_subdev *sensor_sd = csi2dev->sensor_sd;
+
+ return v4l2_subdev_call(sensor_sd, pad, enum_frame_size, NULL, fse);
+}
+
+static int mipi_csis_enum_frameintervals(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum
+ *fie)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct v4l2_subdev *sensor_sd = csi2dev->sensor_sd;
+
+ return v4l2_subdev_call(sensor_sd, pad, enum_frame_interval, NULL, fie);
+}
+
+static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct v4l2_subdev *sensor_sd = csi2dev->sensor_sd;
+
+ return v4l2_subdev_call(sensor_sd, pad, enum_mbus_code, NULL, code);
+}
+
+static int mipi_csi2_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct v4l2_subdev *sensor_sd = csi2dev->sensor_sd;
+
+ if (fmt->pad)
+ return -EINVAL;
+
+ return v4l2_subdev_call(sensor_sd, pad, get_fmt, NULL, fmt);
+}
+
+static int mipi_csi2_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct v4l2_subdev *sensor_sd = csi2dev->sensor_sd;
+
+ if (fmt->pad)
+ return -EINVAL;
+
+ if (fmt->format.width * fmt->format.height > 720 * 480) {
+ csi2dev->hs_settle = rxhs_settle[1];
+ csi2dev->send_level = 0x300;
+ } else {
+ csi2dev->hs_settle = rxhs_settle[0];
+ csi2dev->send_level = 0x240;
+ }
+
+ return v4l2_subdev_call(sensor_sd, pad, set_fmt, NULL, fmt);
+}
+
+static int mipi_csis_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct v4l2_subdev *sensor_sd = csi2dev->sensor_sd;
+
+ return v4l2_subdev_call(sensor_sd, video, s_parm, a);
+}
+
+static int mipi_csis_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+ struct v4l2_subdev *sensor_sd = csi2dev->sensor_sd;
+
+ return v4l2_subdev_call(sensor_sd, video, g_parm, a);
+}
+
+static const struct v4l2_subdev_internal_ops mipi_csi2_sd_internal_ops = {
+ .open = mipi_csi2_open,
+};
+
+static struct v4l2_subdev_pad_ops mipi_csi2_pad_ops = {
+ .enum_frame_size = mipi_csis_enum_framesizes,
+ .enum_frame_interval = mipi_csis_enum_frameintervals,
+ .enum_mbus_code = mipi_csis_enum_mbus_code,
+ .get_fmt = mipi_csi2_get_fmt,
+ .set_fmt = mipi_csi2_set_fmt,
+};
+
+static struct v4l2_subdev_core_ops mipi_csi2_core_ops = {
+ .s_power = mipi_csi2_s_power,
+};
+
+static struct v4l2_subdev_video_ops mipi_csi2_video_ops = {
+ .s_stream = mipi_csi2_s_stream,
+
+ .s_parm = mipi_csis_s_parm,
+ .g_parm = mipi_csis_g_parm,
+};
+
+static struct v4l2_subdev_ops mipi_csi2_subdev_ops = {
+ .core = &mipi_csi2_core_ops,
+ .video = &mipi_csi2_video_ops,
+ .pad = &mipi_csi2_pad_ops,
+};
+
+static int mipi_csi2_parse_dt(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ struct device *dev = &csi2dev->pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct v4l2_of_endpoint endpoint;
+ u32 i;
+
+ csi2dev->id = of_alias_get_id(node, "csi");
+
+ csi2dev->vchannel = of_property_read_bool(node, "virtual-channel");
+
+ node = of_graph_get_next_endpoint(node, NULL);
+ if (!node) {
+ dev_err(dev, "No port node at %s\n", node->full_name);
+ return -EINVAL;
+ }
+
+ /* Get port node */
+ v4l2_of_parse_endpoint(node, &endpoint);
+
+ csi2dev->num_lanes = endpoint.bus.mipi_csi2.num_data_lanes;
+ for (i = 0; i < csi2dev->num_lanes; i++)
+ csi2dev->data_lanes[i] = endpoint.bus.mipi_csi2.data_lanes[i];
+
+ of_node_put(node);
+
+ return 0;
+}
+
+static inline struct mxc_mipi_csi2_dev
+*notifier_to_mipi_dev(struct v4l2_async_notifier *n)
+{
+ return container_of(n, struct mxc_mipi_csi2_dev, subdev_notifier);
+}
+
+static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = notifier_to_mipi_dev(notifier);
+
+ /* Find platform data for this sensor subdev */
+ if (csi2dev->asd.match.of.node == subdev->dev->of_node)
+ csi2dev->sensor_sd = subdev;
+
+ if (subdev == NULL)
+ return -EINVAL;
+
+ v4l2_info(&csi2dev->v4l2_dev, "Registered sensor subdevice: %s\n",
+ subdev->name);
+
+ return 0;
+}
+
+static int mipi_csis_subdev_host(struct mxc_mipi_csi2_dev *csi2dev)
+{
+ struct device *dev = &csi2dev->pdev->dev;
+ struct device_node *parent = dev->of_node;
+ struct device_node *node, *port, *rem;
+ int ret;
+
+ /* Attach sensors linked to csi receivers */
+ for_each_available_child_of_node(parent, node) {
+ if (of_node_cmp(node->name, "port"))
+ continue;
+
+ /* The csi node can have only port subnode. */
+ port = of_get_next_child(node, NULL);
+ if (!port)
+ continue;
+ rem = of_graph_get_remote_port_parent(port);
+ of_node_put(port);
+ if (rem == NULL) {
+ v4l2_info(&csi2dev->v4l2_dev,
+ "Remote device at %s not found\n",
+ port->full_name);
+ return -1;
+ } else
+ v4l2_info(&csi2dev->v4l2_dev,
+ "Remote device at %s XXX found\n",
+ port->full_name);
+
+ csi2dev->asd.match_type = V4L2_ASYNC_MATCH_OF;
+ csi2dev->asd.match.of.node = rem;
+ csi2dev->async_subdevs[0] = &csi2dev->asd;
+
+ of_node_put(rem);
+ break;
+ }
+
+ csi2dev->subdev_notifier.subdevs = csi2dev->async_subdevs;
+ csi2dev->subdev_notifier.num_subdevs = 1;
+ csi2dev->subdev_notifier.bound = subdev_notifier_bound;
+
+ ret = v4l2_async_notifier_register(&csi2dev->v4l2_dev,
+ &csi2dev->subdev_notifier);
+ if (ret)
+ dev_err(dev,
+ "Error register async notifier regoster, ret %d\n",
+ ret);
+
+ return ret;
+}
+
+static int mipi_csi2_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *mem_res;
+ struct mxc_mipi_csi2_dev *csi2dev;
+ int ret = -ENOMEM;
+
+ dev_info(&pdev->dev, "%s\n", __func__);
+ csi2dev = devm_kzalloc(dev, sizeof(*csi2dev), GFP_KERNEL);
+ if (!csi2dev)
+ return -ENOMEM;
+
+ csi2dev->pdev = pdev;
+
+ ret = mipi_csi2_parse_dt(csi2dev);
+ if (ret < 0)
+ return -EINVAL;
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ csi2dev->base_regs = devm_ioremap_resource(dev, mem_res);
+ if (IS_ERR(csi2dev->base_regs)) {
+ dev_err(dev, "Failed to get mipi csi2 HC register\n");
+ return PTR_ERR(csi2dev->base_regs);
+ }
+
+ ret = mipi_csi2_clk_init(csi2dev);
+ if (ret < 0)
+ return -EINVAL;
+
+ v4l2_subdev_init(&csi2dev->sd, &mipi_csi2_subdev_ops);
+
+ csi2dev->sd.owner = THIS_MODULE;
+ snprintf(csi2dev->sd.name, sizeof(csi2dev->sd.name), "%s.%d",
+ MXC_MIPI_CSI2_YAV_SUBDEV_NAME, csi2dev->id);
+
+ csi2dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ csi2dev->sd.dev = &pdev->dev;
+
+ /* First register a v4l2 device */
+ ret = v4l2_device_register(dev, &csi2dev->v4l2_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to register v4l2 device.\n");
+ return -EINVAL;
+ }
+ ret = v4l2_async_register_subdev(&csi2dev->sd);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "%s--Async register faialed, ret=%d\n",
+ __func__, ret);
+ goto e_v4l_dev;
+ }
+
+ ret = mipi_csis_subdev_host(csi2dev);
+ if (ret < 0)
+ goto e_clkdis;
+
+ /* This allows to retrieve the platform device id by the host driver */
+ v4l2_set_subdevdata(&csi2dev->sd, pdev);
+
+ /* .. and a pointer to the subdev. */
+ platform_set_drvdata(pdev, csi2dev);
+
+ ret = mipi_csi2_clk_enable(csi2dev);
+ if (ret < 0)
+ goto e_clkdis;
+
+ dev_info(&pdev->dev, "lanes: %d, name: %s\n",
+ csi2dev->num_lanes, csi2dev->sd.name);
+
+ csi2dev->running = 0;
+ csi2dev->flags = MXC_MIPI_CSI2_PM_POWERED;
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+
+e_clkdis:
+ v4l2_async_unregister_subdev(&csi2dev->sd);
+e_v4l_dev:
+ v4l2_device_unregister(&csi2dev->v4l2_dev);
+ return ret;
+}
+
+static int mipi_csi2_remove(struct platform_device *pdev)
+{
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct mxc_mipi_csi2_dev *csi2dev = sd_to_mxc_mipi_csi2_dev(sd);
+
+ mipi_csi2_clk_disable(csi2dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static int mipi_csi2_pm_runtime_resume(struct device *dev)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = dev_get_drvdata(dev);
+ int ret;
+
+ ret = mipi_csi2_clk_enable(csi2dev);
+ if (ret < 0) {
+ dev_info(dev, "%s:%d fail\n", __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static int mipi_csi2_runtime_pm_suspend(struct device *dev)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = dev_get_drvdata(dev);
+
+ mipi_csi2_clk_disable(csi2dev);
+
+ return 0;
+}
+
+static int mipi_csi2_pm_suspend(struct device *dev)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = dev_get_drvdata(dev);
+
+ if (csi2dev->flags & MXC_MIPI_CSI2_PM_SUSPENDED)
+ return 0;
+
+ if (csi2dev->running) {
+ dev_warn(dev, "running, prevent entering suspend.\n");
+ return -EAGAIN;
+ }
+ mipi_csi2_clk_disable(csi2dev);
+ csi2dev->flags &= ~MXC_MIPI_CSI2_PM_POWERED;
+ csi2dev->flags |= MXC_MIPI_CSI2_PM_SUSPENDED;
+
+ return 0;
+}
+
+static int mipi_csi2_pm_resume(struct device *dev)
+{
+ struct mxc_mipi_csi2_dev *csi2dev = dev_get_drvdata(dev);
+ int ret;
+
+ if (csi2dev->flags & MXC_MIPI_CSI2_PM_POWERED)
+ return 0;
+
+ ret = mipi_csi2_clk_enable(csi2dev);
+ if (ret < 0) {
+ dev_info(dev, "%s:%d fail\n", __func__, __LINE__);
+ return -EAGAIN;
+ }
+
+ csi2dev->flags |= MXC_MIPI_CSI2_PM_POWERED;
+ csi2dev->flags &= ~MXC_MIPI_CSI2_PM_SUSPENDED;
+
+ return 0;
+}
+
+static const struct dev_pm_ops mipi_csi_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mipi_csi2_pm_suspend, mipi_csi2_pm_resume)
+ SET_RUNTIME_PM_OPS(mipi_csi2_runtime_pm_suspend,
+ mipi_csi2_pm_runtime_resume,
+ NULL)
+};
+
+static const struct of_device_id mipi_csi2_of_match[] = {
+ {.compatible = "fsl,mxc-mipi-csi2_yav",},
+ { /* sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, mipi_csi2_of_match);
+
+static struct platform_driver mipi_csi2_driver = {
+ .driver = {
+ .name = MXC_MIPI_CSI2_YAV_DRIVER_NAME,
+ .of_match_table = mipi_csi2_of_match,
+ .pm = &mipi_csi_pm_ops,
+ },
+ .probe = mipi_csi2_probe,
+ .remove = mipi_csi2_remove,
+};
+
+module_platform_driver(mipi_csi2_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC MIPI CSI2 driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" MXC_MIPI_CSI2_YAV_DRIVER_NAME);
diff --git a/drivers/media/platform/imx8/mxc-parallel-csi.c b/drivers/media/platform/imx8/mxc-parallel-csi.c
new file mode 100644
index 000000000000..c7872c89e508
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-parallel-csi.c
@@ -0,0 +1,723 @@
+/*
+ * Copyright 2018 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#define DEBUG
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/memory.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-of.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+#include <soc/imx8/sc/sci.h>
+#include <dt-bindings/pinctrl/pads-imx8qxp.h>
+#include <linux/init.h>
+
+#include "mxc-parallel-csi.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+static int format;
+module_param(format, int, 0644);
+MODULE_PARM_DESC(format, "Format level (0-2)");
+
+#ifdef DEBUG
+static void mxc_pcsi_regs_dump(struct mxc_parallel_csi_dev *pcsidev)
+{
+ struct device *dev = &pcsidev->pdev->dev;
+
+ dev_dbg(dev, "HW_IF_CTRL_REG = 0x%08x\n",
+ readl(pcsidev->csr_regs + IF_CTRL_REG));
+ dev_dbg(dev, "HW_CSI_CTRL_REG = 0x%08x\n",
+ readl(pcsidev->csr_regs + CSI_CTRL_REG));
+ dev_dbg(dev, "HW_CSI_STATUS = 0x%08x\n",
+ readl(pcsidev->csr_regs + CSI_STATUS));
+ dev_dbg(dev, "HW_CSI_CTRL_REG1 = 0x%08x\n",
+ readl(pcsidev->csr_regs + CSI_CTRL_REG1));
+}
+#else
+static void mxc_pcsi_regs_dump(struct mxc_parallel_csi_dev *pcsidev) { }
+#endif
+
+static struct mxc_parallel_csi_dev *sd_to_mxc_pcsi_dev(struct v4l2_subdev *sdev)
+{
+ return container_of(sdev, struct mxc_parallel_csi_dev, sd);
+}
+
+static int mxc_pcsi_clk_get(struct mxc_parallel_csi_dev *pcsidev)
+{
+ struct device *dev = &pcsidev->pdev->dev;
+
+ pcsidev->clk_pixel = devm_clk_get(dev, "pixel");
+ if (IS_ERR(pcsidev->clk_pixel)) {
+ dev_info(dev, "%s failed to get parallel csi pixel clk\n", __func__);
+ return PTR_ERR(pcsidev->clk_pixel);
+ }
+
+ pcsidev->clk_ipg = devm_clk_get(dev, "ipg");
+ if (IS_ERR(pcsidev->clk_ipg)) {
+ dev_info(dev, "%s failed to get parallel ipg pixel clk\n", __func__);
+ return PTR_ERR(pcsidev->clk_ipg);
+ }
+
+ return 0;
+}
+
+static int mxc_pcsi_clk_enable(struct mxc_parallel_csi_dev *pcsidev)
+{
+ struct device *dev = &pcsidev->pdev->dev;
+ int ret;
+
+ if (pcsidev->clk_enable)
+ return 0;
+
+ ret = clk_prepare_enable(pcsidev->clk_pixel);
+ if (ret < 0) {
+ dev_info(dev, "%s, enable pixel clk error\n", __func__);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(pcsidev->clk_ipg);
+ if (ret < 0) {
+ dev_info(dev, "%s, enable ipg clk error\n", __func__);
+ return ret;
+ }
+
+ pcsidev->clk_enable = true;
+
+ return 0;
+}
+
+static void mxc_pcsi_clk_disable(struct mxc_parallel_csi_dev *pcsidev)
+{
+ if (!pcsidev->clk_enable)
+ return;
+
+ clk_disable_unprepare(pcsidev->clk_pixel);
+ clk_disable_unprepare(pcsidev->clk_ipg);
+
+ pcsidev->clk_enable = false;
+}
+
+static void mxc_pcsi_sw_reset(struct mxc_parallel_csi_dev *pcsidev)
+{
+ u32 val;
+
+ /* Softwaret Reset */
+ val = CSI_CTRL_REG_SOFTRST;
+ writel(val, pcsidev->csr_regs + CSI_CTRL_REG_SET);
+
+ msleep(1);
+ writel(val, pcsidev->csr_regs + CSI_CTRL_REG_CLR);
+}
+
+static void mxc_pcsi_csr_config(struct mxc_parallel_csi_dev *pcsidev)
+{
+ u32 val;
+
+ /* Software Reset */
+ mxc_pcsi_sw_reset(pcsidev);
+
+ /* Config PL Data Type */
+ val = IF_CTRL_REG_DATA_TYPE(DATA_TYPE_OUT_YUV444);
+ writel(val, pcsidev->csr_regs + IF_CTRL_REG_SET);
+
+ /* Enable sync Force */
+ val = (CSI_CTRL_REG_HSYNC_FORCE_EN | CSI_CTRL_REG_VSYNC_FORCE_EN);
+ writel(val, pcsidev->csr_regs + CSI_CTRL_REG_SET);
+
+ /* Enable Pixel Link */
+ val = IF_CTRL_REG_PL_ENABLE;
+ writel(val , pcsidev->csr_regs + IF_CTRL_REG_SET);
+
+ /* Enable Pixel Link */
+ val = IF_CTRL_REG_PL_VALID;
+ writel(val , pcsidev->csr_regs + IF_CTRL_REG_SET);
+
+ /* Config CTRL REG */
+ val = readl(pcsidev->csr_regs + CSI_CTRL_REG);
+ val |= (
+ CSI_CTRL_REG_DATA_TYPE_IN(DATA_TYPE_IN_YVYU_8BITS) |
+ CSI_CTRL_REG_HSYNC_POL |
+ CSI_CTRL_REG_MASK_VSYNC_COUNTER(3) |
+ CSI_CTRL_REG_HSYNC_PULSE(2));
+
+ if (pcsidev->uv_swap)
+ val |= CSI_CTRL_REG_UV_SWAP_EN;
+
+ if (pcsidev->mode & GATE_CLOCK_MODE)
+ val |= CSI_CTRL_REG_GCLK_MODE_EN;
+ else if (pcsidev->mode & CCIR_MODE) {
+ val |= (CSI_CTRL_REG_CCIR_EN |
+ CSI_CTRL_REG_CCIR_VSYNC_RESET_EN |
+ CSI_CTRL_REG_CCIR_EXT_VSYNC_EN |
+ CSI_CTRL_REG_CCIR_ECC_ERR_CORRECT_EN);
+ }
+
+ writel(val, pcsidev->csr_regs + CSI_CTRL_REG);
+}
+
+static void mxc_pcsi_config_ctrl_reg1(struct mxc_parallel_csi_dev *pcsidev)
+{
+ struct device *dev = &pcsidev->pdev->dev;
+ u32 val;
+
+ if (pcsidev->format.width <= 0 || pcsidev->format.height <= 0) {
+ dev_dbg(dev, "%s width/height invalid\n", __func__);
+ return;
+ }
+
+ /* Config Pixel Width */
+ val = (CSI_CTRL_REG1_PIXEL_WIDTH(pcsidev->format.width - 1) |
+ CSI_CTRL_REG1_VSYNC_PULSE(pcsidev->format.width << 1));
+ writel(val, pcsidev->csr_regs + CSI_CTRL_REG1);
+
+}
+
+static void mxc_pcsi_enable_csi(struct mxc_parallel_csi_dev *pcsidev)
+{
+ u32 val;
+
+ /* Enable CSI */
+ val = CSI_CTRL_REG_CSI_EN;
+ writel(val, pcsidev->csr_regs + CSI_CTRL_REG_SET);
+
+ /* Disable SYNC Force */
+ val = (CSI_CTRL_REG_HSYNC_FORCE_EN | CSI_CTRL_REG_VSYNC_FORCE_EN);
+ writel(val, pcsidev->csr_regs + CSI_CTRL_REG_CLR);
+}
+
+static void mxc_pcsi_disable_csi(struct mxc_parallel_csi_dev *pcsidev)
+{
+ u32 val;
+
+ /* Enable Sync Force */
+ val = (CSI_CTRL_REG_HSYNC_FORCE_EN | CSI_CTRL_REG_VSYNC_FORCE_EN);
+ writel(val, pcsidev->csr_regs + CSI_CTRL_REG_SET);
+
+ /* Disable CSI */
+ val = CSI_CTRL_REG_CSI_EN;
+ writel(val, pcsidev->csr_regs + CSI_CTRL_REG_CLR);
+
+ /* Disable Pixel Link */
+ val = IF_CTRL_REG_PL_VALID | IF_CTRL_REG_PL_ENABLE;
+ writel(val , pcsidev->csr_regs + IF_CTRL_REG_CLR);
+}
+
+static struct media_pad *mxc_pcsi_get_remote_sensor_pad(
+ struct mxc_parallel_csi_dev *pcsidev)
+{
+ struct v4l2_subdev *subdev = &pcsidev->sd;
+ struct media_pad *sink_pad, *source_pad;
+ int i;
+
+ while (1) {
+ source_pad = NULL;
+ for (i = 0; i < subdev->entity.num_pads; i++) {
+ sink_pad = &subdev->entity.pads[i];
+
+ if (sink_pad->flags & MEDIA_PAD_FL_SINK) {
+ source_pad = media_entity_remote_pad(sink_pad);
+ if (source_pad)
+ break;
+ }
+ }
+ /* return first pad point in the loop */
+ return source_pad;
+ }
+
+ if (i == subdev->entity.num_pads)
+ v4l2_err(&pcsidev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+
+ return NULL;
+}
+
+static int mxc_pcsi_get_sensor_fmt(struct mxc_parallel_csi_dev *pcsidev)
+{
+ struct v4l2_mbus_framefmt *mf = &pcsidev->format;
+ struct v4l2_subdev *sen_sd;
+ struct media_pad *source_pad;
+ struct v4l2_subdev_format src_fmt;
+ int ret;
+
+ /* Get remote source pad */
+ source_pad = mxc_pcsi_get_remote_sensor_pad(pcsidev);
+ if (source_pad == NULL) {
+ v4l2_err(&pcsidev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sen_sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sen_sd == NULL) {
+ v4l2_err(&pcsidev->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ src_fmt.pad = source_pad->index;
+ ret = v4l2_subdev_call(sen_sd, pad, get_fmt, NULL, &src_fmt);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return -EINVAL;
+
+ /* Update input frame size and formate */
+ memcpy(mf, &src_fmt.format, sizeof(struct v4l2_mbus_framefmt));
+
+ if (mf->code == MEDIA_BUS_FMT_YUYV8_2X8)
+ pcsidev->uv_swap = 1;
+
+ dev_dbg(&pcsidev->pdev->dev, "width=%d, height=%d, fmt.code=0x%x\n", mf->width, mf->height, mf->code);
+
+ return 0;
+}
+
+static int mxc_pcsi_enum_framesizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct mxc_parallel_csi_dev *pcsidev = sd_to_mxc_pcsi_dev(sd);
+ struct media_pad *source_pad;
+ struct v4l2_subdev *sen_sd;
+
+ /* Get remote source pad */
+ source_pad = mxc_pcsi_get_remote_sensor_pad(pcsidev);
+ if (source_pad == NULL) {
+ v4l2_err(&pcsidev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sen_sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sen_sd == NULL) {
+ v4l2_err(&pcsidev->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ return v4l2_subdev_call(sen_sd, pad, enum_frame_size, NULL, fse);
+}
+
+static int mxc_pcsi_enum_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ struct mxc_parallel_csi_dev *pcsidev = sd_to_mxc_pcsi_dev(sd);
+ struct media_pad *source_pad;
+ struct v4l2_subdev *sen_sd;
+
+ /* Get remote source pad */
+ source_pad = mxc_pcsi_get_remote_sensor_pad(pcsidev);
+ if (source_pad == NULL) {
+ v4l2_err(&pcsidev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sen_sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sen_sd == NULL) {
+ v4l2_err(&pcsidev->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ return v4l2_subdev_call(sen_sd, pad, enum_frame_interval, NULL, fie);
+}
+
+static int mxc_pcsi_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct mxc_parallel_csi_dev *pcsidev = sd_to_mxc_pcsi_dev(sd);
+ struct v4l2_mbus_framefmt *mf = &fmt->format;
+
+ mxc_pcsi_get_sensor_fmt(pcsidev);
+
+ memcpy(mf, &pcsidev->format, sizeof(struct v4l2_mbus_framefmt));
+ /* Source/Sink pads crop rectangle size */
+
+ return 0;
+}
+
+static int mxc_pcsi_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ return 0;
+}
+
+static int mxc_pcsi_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct mxc_parallel_csi_dev *pcsidev = sd_to_mxc_pcsi_dev(sd);
+ struct media_pad *source_pad;
+ struct v4l2_subdev *sen_sd;
+
+ /* Get remote source pad */
+ source_pad = mxc_pcsi_get_remote_sensor_pad(pcsidev);
+ if (source_pad == NULL) {
+ v4l2_err(&pcsidev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sen_sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sen_sd == NULL) {
+ v4l2_err(&pcsidev->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ return v4l2_subdev_call(sen_sd, core, s_power, on);
+}
+
+static int mxc_pcsi_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct mxc_parallel_csi_dev *pcsidev = sd_to_mxc_pcsi_dev(sd);
+ struct media_pad *source_pad;
+ struct v4l2_subdev *sen_sd;
+
+ /* Get remote source pad */
+ source_pad = mxc_pcsi_get_remote_sensor_pad(pcsidev);
+ if (source_pad == NULL) {
+ v4l2_err(&pcsidev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sen_sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sen_sd == NULL) {
+ v4l2_err(&pcsidev->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+
+ return v4l2_subdev_call(sen_sd, video, s_parm, a);
+}
+
+static int mxc_pcsi_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct mxc_parallel_csi_dev *pcsidev = sd_to_mxc_pcsi_dev(sd);
+ struct media_pad *source_pad;
+ struct v4l2_subdev *sen_sd;
+
+ /* Get remote source pad */
+ source_pad = mxc_pcsi_get_remote_sensor_pad(pcsidev);
+ if (source_pad == NULL) {
+ v4l2_err(&pcsidev->v4l2_dev, "%s, No remote pad found!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Get remote source pad subdev */
+ sen_sd = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (sen_sd == NULL) {
+ v4l2_err(&pcsidev->v4l2_dev, "%s, No remote subdev found!\n", __func__);
+ return -EINVAL;
+ }
+ return v4l2_subdev_call(sen_sd, video, g_parm, a);
+}
+
+static int mxc_pcsi_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct mxc_parallel_csi_dev *pcsidev = sd_to_mxc_pcsi_dev(sd);
+ struct device *dev = &pcsidev->pdev->dev;
+
+ dev_dbg(dev, "%s: %d, pcsidev: 0x%d\n", __func__, __LINE__, enable);
+
+ if (enable) {
+ pm_runtime_get_sync(dev);
+ if (!pcsidev->running) {
+ mxc_pcsi_get_sensor_fmt(pcsidev);
+ mxc_pcsi_csr_config(pcsidev);
+ mxc_pcsi_config_ctrl_reg1(pcsidev);
+ mxc_pcsi_enable_csi(pcsidev);
+ mxc_pcsi_regs_dump(pcsidev);
+ }
+ pcsidev->running++;
+ } else {
+ if (pcsidev->running)
+ mxc_pcsi_disable_csi(pcsidev);
+ pcsidev->running--;
+ pm_runtime_put(dev);
+ }
+
+ return 0;
+}
+
+static int mxc_pcsi_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct platform_device *pdev = v4l2_get_subdevdata(sd);
+
+ if (local->flags & MEDIA_PAD_FL_SOURCE) {
+ switch (local->index) {
+ case MXC_PARALLEL_CSI_PAD_SOURCE:
+ break;
+ default:
+ dev_err(&pdev->dev, "%s invalid source pad\n", __func__);
+ return -EINVAL;
+ }
+ } else if (local->flags & MEDIA_PAD_FL_SINK) {
+ switch (local->index) {
+ case MXC_PARALLEL_CSI_PAD_SINK:
+ break;
+ default:
+ dev_err(&pdev->dev, "%s invalid sink pad\n", __func__);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static struct v4l2_subdev_pad_ops pcsi_pad_ops = {
+ .enum_frame_size = mxc_pcsi_enum_framesizes,
+ .enum_frame_interval = mxc_pcsi_enum_frame_interval,
+ .get_fmt = mxc_pcsi_get_fmt,
+ .set_fmt = mxc_pcsi_set_fmt,
+};
+
+static struct v4l2_subdev_core_ops pcsi_core_ops = {
+ .s_power = mxc_pcsi_s_power,
+};
+
+static struct v4l2_subdev_video_ops pcsi_video_ops = {
+ .s_parm = mxc_pcsi_s_parm,
+ .g_parm = mxc_pcsi_g_parm,
+ .s_stream = mxc_pcsi_s_stream,
+};
+
+static struct v4l2_subdev_ops pcsi_subdev_ops = {
+ .core = &pcsi_core_ops,
+ .video = &pcsi_video_ops,
+ .pad = &pcsi_pad_ops,
+};
+static const struct media_entity_operations mxc_pcsi_sd_media_ops = {
+ .link_setup = mxc_pcsi_link_setup,
+};
+
+static int mxc_parallel_csi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *mem_res;
+ struct mxc_parallel_csi_dev *pcsidev;
+ int ret;
+
+ pcsidev = devm_kzalloc(dev, sizeof(*pcsidev), GFP_KERNEL);
+ if (!pcsidev)
+ return -ENOMEM;
+
+ pcsidev->pdev = pdev;
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pcsidev->csr_regs = devm_ioremap_resource(dev, mem_res);
+ if (IS_ERR(pcsidev->csr_regs)) {
+ dev_dbg(dev, "Failed to get parallel CSI CSR register\n");
+ return PTR_ERR(pcsidev->csr_regs);
+ }
+
+ ret = mxc_pcsi_clk_get(pcsidev);
+ if (ret < 0)
+ return ret;
+
+ v4l2_subdev_init(&pcsidev->sd, &pcsi_subdev_ops);
+
+ pcsidev->mode = GATE_CLOCK_MODE;
+
+ pcsidev->sd.owner = THIS_MODULE;
+ sprintf(pcsidev->sd.name, "%s", MXC_PARALLEL_CSI_SUBDEV_NAME);
+
+ pcsidev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ pcsidev->sd.entity.function = MEDIA_ENT_F_IO_V4L;
+
+ pcsidev->sd.dev = dev;
+
+ pcsidev->pads[MXC_PARALLEL_CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ pcsidev->pads[MXC_PARALLEL_CSI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&pcsidev->sd.entity,
+ MXC_PARALLEL_CSI_PADS_NUM, pcsidev->pads);
+ if (ret < 0)
+ goto e_clkdis;
+
+ pcsidev->sd.entity.ops = &mxc_pcsi_sd_media_ops;
+
+ v4l2_set_subdevdata(&pcsidev->sd, pdev);
+
+ platform_set_drvdata(pdev, pcsidev);
+
+ pcsidev->running = 0;
+ pm_runtime_enable(dev);
+
+ dev_info(dev, "%s probe successfully\n", __func__);
+ return 0;
+
+e_clkdis:
+ media_entity_cleanup(&pcsidev->sd.entity);
+ return ret;
+}
+
+static int mxc_parallel_csi_remove(struct platform_device *pdev)
+{
+ struct mxc_parallel_csi_dev *pcsidev =
+ (struct mxc_parallel_csi_dev *)platform_get_drvdata(pdev);
+
+ pm_runtime_get_sync(&pdev->dev);
+ media_entity_cleanup(&pcsidev->sd.entity);
+ mxc_pcsi_clk_disable(pcsidev);
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static void parallel_csi_power_control(sc_pm_power_mode_t mode)
+{
+ sc_ipc_t ipcHndl;
+ sc_err_t sciErr;
+ uint32_t mu_id;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("Cannot obtain MU ID\n");
+ return;
+ }
+
+ sciErr = sc_ipc_open(&ipcHndl, mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+ return;
+ }
+
+ sc_pm_set_resource_power_mode(ipcHndl, SC_R_PI_0, mode);
+
+ if (sciErr != SC_ERR_NONE)
+ pr_err("Set CI_PI resouce power mode failed! (sciError = %d)\n", sciErr);
+
+ msleep(10);
+
+ sc_ipc_close(mu_id);
+}
+
+static int parallel_csi_pm_suspend(struct device *dev)
+{
+ return pm_runtime_force_suspend(dev);
+}
+
+static int parallel_csi_pm_resume(struct device *dev)
+{
+ struct mxc_parallel_csi_dev *pcsidev = dev_get_drvdata(dev);
+ int ret;
+
+ /* Power off CI_PI before set clock parent */
+ parallel_csi_power_control(SC_PM_PW_MODE_OFF);
+
+ pcsidev->clk_div = devm_clk_get(dev, "div");
+ if (IS_ERR(pcsidev->clk_div)) {
+ dev_err(dev, "%s: Get div clk fail\n", __func__);
+ return PTR_ERR(pcsidev->clk_div);
+ }
+
+ pcsidev->clk_sel = devm_clk_get(dev, "sel");
+ if (IS_ERR(pcsidev->clk_sel)) {
+ dev_err(dev, "%s: Get sel clk fail\n", __func__);
+ return PTR_ERR(pcsidev->clk_sel);
+ }
+
+ pcsidev->clk_dpll = devm_clk_get(dev, "dpll");
+ if (IS_ERR(pcsidev->clk_dpll)) {
+ dev_err(dev, "%s: Get DPLL clk fail\n", __func__);
+ return PTR_ERR(pcsidev->clk_dpll);
+ }
+
+ ret = clk_set_parent(pcsidev->clk_sel, pcsidev->clk_dpll);
+ if (ret < 0) {
+ dev_err(dev, "sel clk set parent fail\n");
+ return ret;
+ }
+
+ /* 160MHz for pixel and per clock */
+ ret = clk_set_rate(pcsidev->clk_div, 160000000);
+ if (ret < 0) {
+ dev_err(dev, "div clk set rate fail\n");
+ return ret;
+ }
+
+ /* Release parent clocks */
+ devm_clk_put(dev, pcsidev->clk_dpll);
+ devm_clk_put(dev, pcsidev->clk_sel);
+ devm_clk_put(dev, pcsidev->clk_div);
+
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+
+static int parallel_csi_runtime_suspend(struct device *dev)
+{
+ struct mxc_parallel_csi_dev *pcsidev = dev_get_drvdata(dev);
+
+ mxc_pcsi_clk_disable(pcsidev);
+
+ return 0;
+}
+
+static int parallel_csi_runtime_resume(struct device *dev)
+{
+ struct mxc_parallel_csi_dev *pcsidev = dev_get_drvdata(dev);
+ int ret;
+
+ ret = mxc_pcsi_clk_enable(pcsidev);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static const struct dev_pm_ops parallel_csi_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(parallel_csi_pm_suspend, parallel_csi_pm_resume)
+ SET_RUNTIME_PM_OPS(parallel_csi_runtime_suspend,
+ parallel_csi_runtime_resume, NULL)
+};
+
+static const struct of_device_id parallel_csi_of_match[] = {
+ { .compatible = "fsl,mxc-parallel-csi",},
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, parallel_csi_of_match);
+
+
+static struct platform_driver parallel_csi_driver = {
+ .driver = {
+ .name = MXC_PARALLEL_CSI_DRIVER_NAME,
+ .of_match_table = parallel_csi_of_match,
+ .pm = &parallel_csi_pm_ops,
+ },
+ .probe = mxc_parallel_csi_probe,
+ .remove = mxc_parallel_csi_remove,
+};
+
+module_platform_driver(parallel_csi_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC PARALLEL CSI driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" MXC_PARALLEL_CSI_DRIVER_NAME);
diff --git a/drivers/media/platform/imx8/mxc-parallel-csi.h b/drivers/media/platform/imx8/mxc-parallel-csi.h
new file mode 100644
index 000000000000..49b1fbfab07a
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-parallel-csi.h
@@ -0,0 +1,170 @@
+
+/*
+ * Copyright 2018 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef MXC_PARALLEL_CSI_H_
+#define MXC_PARALLEL_CSI_H_
+
+#include <media/v4l2-device.h>
+
+#define MXC_PARALLEL_CSI_DRIVER_NAME "mxc-parallel-csi"
+#define MXC_PARALLEL_CSI_SUBDEV_NAME MXC_PARALLEL_CSI_DRIVER_NAME
+
+#define PARALLEL_CSI_OF_NODE_NAME "pcsi"
+#define BIT_U(nr) (1U << (nr))
+
+#define MXC_PARALLEL_CSI_PAD_SOURCE 0
+#define MXC_PARALLEL_CSI_PAD_SINK 1
+#define MXC_PARALLEL_CSI_PADS_NUM 2
+
+#define CI_PI_BASE_OFFSET 0x0U
+
+/* CI_PI INTERFACE Control */
+#define IF_CTRL_REG (CI_PI_BASE_OFFSET + 0x00)
+#define IF_CTRL_REG_PL_ENABLE BIT_U(0)
+#define IF_CTRL_REG_PL_VALID BIT_U(1)
+#define IF_CTRL_REG_PL_ADDR(x) (((x) & 0x7U) << 2)
+#define IF_CTRL_REG_IF_FORCE(x) (((x) & 0x7U) << 5)
+#define IF_CTRL_REG_DATA_TYPE_SEL BIT_U(8)
+#define IF_CTRL_REG_DATA_TYPE(x) (((x) & 0x1FU) << 9)
+
+#define DATA_TYPE_OUT_NULL (0x00)
+#define DATA_TYPE_OUT_RGB (0x04)
+#define DATA_TYPE_OUT_YUV444 (0x08)
+#define DATA_TYPE_OUT_YYU420_ODD (0x10)
+#define DATA_TYPE_OUT_YYU420_EVEN (0x12)
+#define DATA_TYPE_OUT_YYY_ODD (0x18)
+#define DATA_TYPE_OUT_UYVY_EVEN (0x1A)
+#define DATA_TYPE_OUT_RAW (0x1C)
+
+#define IF_CTRL_REG_IF_FORCE_HSYNV_OVERRIDE 0x4
+#define IF_CTRL_REG_IF_FORCE_VSYNV_OVERRIDE 0x2
+#define IF_CTRL_REG_IF_FORCE_DATA_ENABLE_OVERRIDE 0x1
+
+#define IF_CTRL_REG_SET (CI_PI_BASE_OFFSET + 0x04)
+#define IF_CTRL_REG_CLR (CI_PI_BASE_OFFSET + 0x08)
+#define IF_CTRL_REG_TOG (CI_PI_BASE_OFFSET + 0x0C)
+
+/* CSI INTERFACE CONTROL REG */
+#define CSI_CTRL_REG (CI_PI_BASE_OFFSET + 0x10)
+#define CSI_CTRL_REG_CSI_EN BIT_U(0)
+#define CSI_CTRL_REG_PIXEL_CLK_POL BIT_U(1)
+#define CSI_CTRL_REG_HSYNC_POL BIT_U(2)
+#define CSI_CTRL_REG_VSYNC_POL BIT_U(3)
+#define CSI_CTRL_REG_DE_POL BIT_U(4)
+#define CSI_CTRL_REG_PIXEL_DATA_POL BIT_U(5)
+#define CSI_CTRL_REG_CCIR_EXT_VSYNC_EN BIT_U(6)
+#define CSI_CTRL_REG_CCIR_EN BIT_U(7)
+#define CSI_CTRL_REG_CCIR_VIDEO_MODE BIT_U(8)
+#define CSI_CTRL_REG_CCIR_NTSC_EN BIT_U(9)
+#define CSI_CTRL_REG_CCIR_VSYNC_RESET_EN BIT_U(10)
+#define CSI_CTRL_REG_CCIR_ECC_ERR_CORRECT_EN BIT_U(11)
+#define CSI_CTRL_REG_HSYNC_FORCE_EN BIT_U(12)
+#define CSI_CTRL_REG_VSYNC_FORCE_EN BIT_U(13)
+#define CSI_CTRL_REG_GCLK_MODE_EN BIT_U(14)
+#define CSI_CTRL_REG_VALID_SEL BIT_U(15)
+#define CSI_CTRL_REG_RAW_OUT_SEL BIT_U(16)
+#define CSI_CTRL_REG_HSYNC_OUT_SEL BIT_U(17)
+#define CSI_CTRL_REG_HSYNC_PULSE(x) (((x) & 0x7U) << 19)
+#define CSI_CTRL_REG_UV_SWAP_EN BIT_U(22)
+#define CSI_CTRL_REG_DATA_TYPE_IN(x) (((x) & 0xFU) << 23)
+#define CSI_CTRL_REG_MASK_VSYNC_COUNTER(x) (((x) & 0x3U) << 27)
+#define CSI_CTRL_REG_SOFTRST BIT_U(31)
+
+#define DATA_TYPE_IN_UYVY_BT656_8BITS 0x0
+#define DATA_TYPE_IN_UYVY_BT656_10BITS 0x1
+#define DATA_TYPE_IN_RGB_8BITS 0x2
+#define DATA_TYPE_IN_BGR_8BITS 0x3
+#define DATA_TYPE_IN_RGB_24BITS 0x4
+#define DATA_TYPE_IN_YVYU_8BITS 0x5
+#define DATA_TYPE_IN_YUV_8BITS 0x6
+#define DATA_TYPE_IN_YVYU_16BITS 0x7
+#define DATA_TYPE_IN_YUV_24BITS 0x8
+#define DATA_TYPE_IN_BAYER_8BITS 0x9
+#define DATA_TYPE_IN_BAYER_10BITS 0xA
+#define DATA_TYPE_IN_BAYER_12BITS 0xB
+#define DATA_TYPE_IN_BAYER_16BITS 0xC
+
+#define CSI_CTRL_REG_SET (CI_PI_BASE_OFFSET + 0x14)
+#define CSI_CTRL_REG_CLR (CI_PI_BASE_OFFSET + 0x18)
+#define CSI_CTRL_REG_TOG (CI_PI_BASE_OFFSET + 0x1C)
+
+/* CSI interface Status */
+#define CSI_STATUS (CI_PI_BASE_OFFSET + 0x20)
+#define CSI_STATUS_FIELD_TOGGLE BIT_U(0)
+#define CSI_STATUS_ECC_ERROR BIT_U(1)
+
+#define CSI_STATUS_SET (CI_PI_BASE_OFFSET + 0x24)
+#define CSI_STATUS_CLR (CI_PI_BASE_OFFSET + 0x28)
+#define CSI_STATUS_TOG (CI_PI_BASE_OFFSET + 0x2C)
+
+/* CSI INTERFACE CONTROL REG1 */
+#define CSI_CTRL_REG1 (CI_PI_BASE_OFFSET + 0x30)
+#define CSI_CTRL_REG1_PIXEL_WIDTH(v) (((v) & 0xFFFFU) << 0)
+#define CSI_CTRL_REG1_VSYNC_PULSE(v) (((v) & 0xFFFFU) << 16)
+
+#define CSI_CTRL_REG1_SET (CI_PI_BASE_OFFSET + 0x34)
+#define CSI_CTRL_REG1_CLR (CI_PI_BASE_OFFSET + 0x38)
+#define CSI_CTRL_REG1_TOG (CI_PI_BASE_OFFSET + 0x3C)
+
+/***********************************************************/
+#define LPCG_BASE (void __iomem *)0x58263000
+#define LPCG_LIS_CLK (0x00)
+#define LPCG_CSR_CLK (0x04)
+#define LPCG_GPIO_CLK (0x08)
+#define LPCG_PWM_CLK (0x0c)
+#define LPCG_I2C_CLK (0x10)
+#define LPCG_CSI_INTERFACE_CLK (0x18)
+#define LPCG_CSI_MCLK (0x1c)
+/***********************************************************/
+
+//#define CSI_INTERFACE_CCIR656 1
+
+struct mxc_parallel_csi_dev {
+ struct v4l2_device v4l2_dev;
+ struct v4l2_subdev sd;
+ struct v4l2_subdev *sensor_sd;
+
+ struct media_pad pads[MXC_PARALLEL_CSI_PADS_NUM];
+ struct v4l2_mbus_framefmt format;
+
+ void __iomem *csr_regs;
+ void __iomem *lpcg_regs;
+ struct platform_device *pdev;
+ u32 flags;
+ int irq;
+
+ struct clk *clk_ipg;
+ struct clk *clk_pixel;
+ struct clk *clk_sel;
+ struct clk *clk_div;
+ struct clk *clk_dpll;
+
+ bool clk_enable;
+
+ struct v4l2_async_subdev asd;
+ struct v4l2_async_notifier subdev_notifier;
+ struct v4l2_async_subdev *async_subdevs[2];
+
+ struct mutex lock;
+
+ u8 running;
+ u8 mode;
+ u8 uv_swap;
+ u8 tvdec;
+};
+#endif
+
+enum {
+ GATE_CLOCK_MODE = 0x01,
+ CCIR_MODE = 0x02,
+};
diff --git a/drivers/media/platform/imx8/ov5640_mipi_v3.c b/drivers/media/platform/imx8/ov5640_mipi_v3.c
new file mode 100644
index 000000000000..0dfdbece3c0c
--- /dev/null
+++ b/drivers/media/platform/imx8/ov5640_mipi_v3.c
@@ -0,0 +1,1446 @@
+/*
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2018 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#define OV5640_VOLTAGE_ANALOG 2800000
+#define OV5640_VOLTAGE_DIGITAL_CORE 1500000
+#define OV5640_VOLTAGE_DIGITAL_IO 1800000
+
+#define MIN_FPS 15
+#define MAX_FPS 30
+#define DEFAULT_FPS 30
+
+#define OV5640_XCLK_MIN 6000000
+#define OV5640_XCLK_MAX 24000000
+
+#define OV5640_CHIP_ID_HIGH_BYTE 0x300A
+#define OV5640_CHIP_ID_LOW_BYTE 0x300B
+
+#define OV5640_SENS_PAD_SOURCE 0
+#define OV5640_SENS_PADS_NUM 1
+
+enum ov5640_mode {
+ ov5640_mode_MIN = 0,
+ ov5640_mode_VGA_640_480 = 0,
+ ov5640_mode_QVGA_320_240 = 1,
+ ov5640_mode_480_272 = 2,
+ ov5640_mode_720P_1280_720 = 3,
+ ov5640_mode_1080P_1920_1080 = 4,
+ ov5640_mode_MAX = 4
+};
+
+enum ov5640_frame_rate {
+ ov5640_15_fps,
+ ov5640_30_fps
+};
+
+static int ov5640_framerates[] = {
+ [ov5640_15_fps] = 15,
+ [ov5640_30_fps] = 30,
+};
+
+struct ov5640_datafmt {
+ u32 code;
+ enum v4l2_colorspace colorspace;
+};
+
+struct reg_value {
+ u16 u16RegAddr;
+ u8 u8Val;
+ u8 u8Mask;
+ u32 u32Delay_ms;
+};
+
+struct ov5640_mode_info {
+ enum ov5640_mode mode;
+ u32 width;
+ u32 height;
+ struct reg_value *init_data_ptr;
+ u32 init_data_size;
+};
+
+struct ov5640_pll_info {
+ enum ov5640_mode mode;
+ struct reg_value *init_data_ptr;
+ u32 init_data_size;
+};
+
+struct ov5640_hs_info {
+ u32 width;
+ u32 height;
+ u32 frame_rate;
+ u32 val;
+};
+
+struct ov5640 {
+ struct v4l2_subdev subdev;
+ struct i2c_client *i2c_client;
+ struct v4l2_pix_format pix;
+ const struct ov5640_datafmt *fmt;
+ struct v4l2_captureparm streamcap;
+ struct media_pad pads[OV5640_SENS_PADS_NUM];
+ bool on;
+
+ /* control settings */
+ int brightness;
+ int hue;
+ int contrast;
+ int saturation;
+ int red;
+ int green;
+ int blue;
+ int ae_mode;
+
+ u32 mclk;
+ u8 mclk_source;
+ struct clk *sensor_clk;
+ int csi;
+
+ void (*io_init)(struct ov5640 *);
+ int pwn_gpio, rst_gpio;
+};
+
+static struct reg_value ov5640_init_parm[] = {
+ {0x3008, 0x42, 0, 0},
+
+ /* System setting.0*/
+ {0x3103, 0x03, 0, 0},
+ {0x3000, 0x00, 0, 0},
+ {0x3004, 0xff, 0, 0},
+ {0x3002, 0x1c, 0, 0},
+ {0x3006, 0xc3, 0, 0},
+ {0x302e, 0x08, 0, 0},
+ {0x3037, 0x13, 0, 0},
+ {0x3108, 0x01, 0, 0},
+ {0x3618, 0x00, 0, 0},
+ {0x3612, 0x29, 0, 0},
+ {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0},
+ {0x370c, 0x03, 0, 0},
+ {0x3820, 0x41, 0, 0},
+ {0x3821, 0x07, 0, 0},
+ {0x3630, 0x36, 0, 0},
+ {0x3631, 0x0e, 0, 0},
+ {0x3632, 0xe2, 0, 0},
+ {0x3633, 0x12, 0, 0},
+ {0x3621, 0xe0, 0, 0},
+ {0x3704, 0xa0, 0, 0},
+ {0x3703, 0x5a, 0, 0},
+ {0x3715, 0x78, 0, 0},
+ {0x3717, 0x01, 0, 0},
+ {0x370b, 0x60, 0, 0},
+ {0x3705, 0x1a, 0, 0},
+ {0x3905, 0x02, 0, 0},
+ {0x3906, 0x10, 0, 0},
+ {0x3901, 0x0a, 0, 0},
+ {0x3731, 0x12, 0, 0},
+ {0x3600, 0x08, 0, 0},
+ {0x3601, 0x33, 0, 0},
+ {0x302d, 0x60, 0, 0},
+ {0x3620, 0x52, 0, 0},
+ {0x371b, 0x20, 0, 0},
+ {0x471c, 0x50, 0, 0},
+ {0x3a13, 0x43, 0, 0},
+ {0x3a18, 0x00, 0, 0},
+ {0x3a19, 0x7c, 0, 0},
+ {0x3635, 0x13, 0, 0},
+ {0x3636, 0x03, 0, 0},
+ {0x3634, 0x40, 0, 0},
+ {0x3622, 0x01, 0, 0},
+ {0x3c01, 0x00, 0, 0},
+ {0x3a00, 0x58, 0, 0},
+ {0x4001, 0x02, 0, 0},
+ {0x4004, 0x02, 0, 0},
+ {0x4005, 0x1a, 0, 0},
+ {0x5001, 0xa3, 0, 0},
+
+ /* AEC */
+ {0x3a0f, 0x30, 0, 0},
+ {0x3a10, 0x28, 0, 0},
+ {0x3a1b, 0x30, 0, 0},
+ {0x3a1e, 0x26, 0, 0},
+ {0x3a11, 0x60, 0, 0},
+ {0x3a1f, 0x14, 0, 0},
+
+ /* AWB */
+ {0x5180, 0xff, 0, 0},
+ {0x5181, 0xf2, 0, 0},
+ {0x5182, 0x00, 0, 0},
+ {0x5183, 0x14, 0, 0},
+ {0x5184, 0x25, 0, 0},
+ {0x5185, 0x24, 0, 0},
+ {0x5186, 0x09, 0, 0},
+ {0x5187, 0x09, 0, 0},
+ {0x5188, 0x09, 0, 0},
+ {0x5189, 0x88, 0, 0},
+ {0x518a, 0x54, 0, 0},
+ {0x518b, 0xee, 0, 0},
+ {0x518c, 0xb2, 0, 0},
+ {0x518d, 0x50, 0, 0},
+ {0x518e, 0x34, 0, 0},
+ {0x518f, 0x6b, 0, 0},
+ {0x5190, 0x46, 0, 0},
+ {0x5191, 0xf8, 0, 0},
+ {0x5192, 0x04, 0, 0},
+ {0x5193, 0x70, 0, 0},
+ {0x5194, 0xf0, 0, 0},
+ {0x5195, 0xf0, 0, 0},
+ {0x5196, 0x03, 0, 0},
+ {0x5197, 0x01, 0, 0},
+ {0x5198, 0x04, 0, 0},
+ {0x5199, 0x6c, 0, 0},
+ {0x519a, 0x04, 0, 0},
+ {0x519b, 0x00, 0, 0},
+ {0x519c, 0x09, 0, 0},
+ {0x519d, 0x2b, 0, 0},
+ {0x519e, 0x38, 0, 0},
+
+ /* Color Matrix */
+ {0x5381, 0x1e, 0, 0},
+ {0x5382, 0x5b, 0, 0},
+ {0x5383, 0x08, 0, 0},
+ {0x5384, 0x0a, 0, 0},
+ {0x5385, 0x7e, 0, 0},
+ {0x5386, 0x88, 0, 0},
+ {0x5387, 0x7c, 0, 0},
+ {0x5388, 0x6c, 0, 0},
+ {0x5389, 0x10, 0, 0},
+ {0x538a, 0x01, 0, 0},
+ {0x538b, 0x98, 0, 0},
+
+ /* sharp */
+ {0x5300, 0x08, 0, 0},
+ {0x5301, 0x30, 0, 0},
+ {0x5302, 0x10, 0, 0},
+ {0x5303, 0x00, 0, 0},
+ {0x5304, 0x08, 0, 0},
+ {0x5305, 0x30, 0, 0},
+ {0x5306, 0x08, 0, 0},
+ {0x5307, 0x16, 0, 0},
+ {0x5309, 0x08, 0, 0},
+ {0x530a, 0x30, 0, 0},
+ {0x530b, 0x04, 0, 0},
+ {0x530c, 0x06, 0, 0},
+
+ /* Gamma */
+ {0x5480, 0x01, 0, 0},
+ {0x5481, 0x08, 0, 0},
+ {0x5482, 0x14, 0, 0},
+ {0x5483, 0x28, 0, 0},
+ {0x5484, 0x51, 0, 0},
+ {0x5485, 0x65, 0, 0},
+ {0x5486, 0x71, 0, 0},
+ {0x5487, 0x7d, 0, 0},
+ {0x5488, 0x87, 0, 0},
+ {0x5489, 0x91, 0, 0},
+ {0x548a, 0x9a, 0, 0},
+ {0x548b, 0xaa, 0, 0},
+ {0x548c, 0xb8, 0, 0},
+ {0x548d, 0xcd, 0, 0},
+ {0x548e, 0xdd, 0, 0},
+ {0x548f, 0xea, 0, 0},
+ {0x5490, 0x1d, 0, 0},
+
+ /* UV adjust. */
+ {0x5580, 0x02, 0, 0},
+ {0x5583, 0x40, 0, 0},
+ {0x5584, 0x10, 0, 0},
+ {0x5589, 0x10, 0, 0},
+ {0x558a, 0x00, 0, 0},
+ {0x558b, 0xf8, 0, 0},
+
+ /* Lens correction0 */
+ {0x5800, 0x23, 0, 0},
+ {0x5801, 0x14, 0, 0},
+ {0x5802, 0x0f, 0, 0},
+ {0x5803, 0x0f, 0, 0},
+ {0x5804, 0x12, 0, 0},
+ {0x5805, 0x26, 0, 0},
+ {0x5806, 0x0c, 0, 0},
+ {0x5807, 0x08, 0, 0},
+ {0x5808, 0x05, 0, 0},
+ {0x5809, 0x05, 0, 0},
+ {0x580a, 0x08, 0, 0},
+ {0x580b, 0x0d, 0, 0},
+ {0x580c, 0x08, 0, 0},
+ {0x580d, 0x03, 0, 0},
+ {0x580e, 0x00, 0, 0},
+ {0x580f, 0x00, 0, 0},
+ {0x5810, 0x03, 0, 0},
+ {0x5811, 0x09, 0, 0},
+ {0x5812, 0x07, 0, 0},
+ {0x5813, 0x03, 0, 0},
+ {0x5814, 0x00, 0, 0},
+ {0x5815, 0x01, 0, 0},
+ {0x5816, 0x03, 0, 0},
+ {0x5817, 0x08, 0, 0},
+ {0x5818, 0x0d, 0, 0},
+ {0x5819, 0x08, 0, 0},
+ {0x581a, 0x05, 0, 0},
+ {0x581b, 0x06, 0, 0},
+ {0x581c, 0x08, 0, 0},
+ {0x581d, 0x0e, 0, 0},
+ {0x581e, 0x29, 0, 0},
+ {0x581f, 0x17, 0, 0},
+ {0x5820, 0x11, 0, 0},
+ {0x5821, 0x11, 0, 0},
+ {0x5822, 0x15, 0, 0},
+ {0x5823, 0x28, 0, 0},
+ {0x5824, 0x46, 0, 0},
+ {0x5825, 0x26, 0, 0},
+ {0x5826, 0x08, 0, 0},
+ {0x5827, 0x26, 0, 0},
+ {0x5828, 0x64, 0, 0},
+ {0x5829, 0x26, 0, 0},
+ {0x582a, 0x24, 0, 0},
+ {0x582b, 0x22, 0, 0},
+ {0x582c, 0x24, 0, 0},
+ {0x582d, 0x24, 0, 0},
+ {0x582e, 0x06, 0, 0},
+ {0x582f, 0x22, 0, 0},
+ {0x5830, 0x40, 0, 0},
+ {0x5831, 0x42, 0, 0},
+ {0x5832, 0x24, 0, 0},
+ {0x5833, 0x26, 0, 0},
+ {0x5834, 0x24, 0, 0},
+ {0x5835, 0x22, 0, 0},
+ {0x5836, 0x22, 0, 0},
+ {0x5837, 0x26, 0, 0},
+ {0x5838, 0x44, 0, 0},
+ {0x5839, 0x24, 0, 0},
+ {0x583a, 0x26, 0, 0},
+ {0x583b, 0x28, 0, 0},
+ {0x583c, 0x42, 0, 0},
+ {0x583d, 0xce, 0, 0},
+ };
+
+static struct reg_value ov5640_setting_VGA_640_480[] = {
+ {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0},
+ {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0},
+ {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0},
+ {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0},
+ {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0},
+ {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0},
+};
+
+static struct reg_value ov5640_setting_QVGA_320_240[] = {
+ {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0},
+ {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0},
+ {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0},
+ {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0},
+ {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0},
+ {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0},
+ {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0},
+};
+
+static struct reg_value ov5640_setting_480_272[] = {
+ {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0},
+ {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0},
+ {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, {0x3808, 0x01, 0, 0},
+ {0x3809, 0xE0, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0x10, 0, 0},
+ {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, {0x380e, 0x02, 0, 0},
+ {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0},
+ {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0},
+};
+
+static struct reg_value ov5640_setting_720P_1280_720[] = {
+ {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0},
+ {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0},
+ {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, {0x3808, 0x05, 0, 0},
+ {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, {0x380b, 0xd0, 0, 0},
+ {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, {0x380e, 0x02, 0, 0},
+ {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0},
+ {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0},
+};
+
+static struct reg_value ov5640_setting_1080P_1920_1080[] = {
+ {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
+ {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
+ {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0},
+ {0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0},
+ {0x380f, 0x60, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0},
+ {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, {0x3814, 0x11, 0, 0},
+ {0x3815, 0x11, 0, 0},
+};
+
+/* MIPI */
+static struct reg_value ov5640_mipi_pll_VGA_30fps_640_480[] = {
+ {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x4837, 0x0a, 0, 0},
+};
+
+static struct reg_value ov5640_mipi_pll_VGA_15fps_640_480[] = {
+ {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x4837, 0x0a, 0, 0},
+};
+
+static struct reg_value ov5640_mipi_pll_QVGA_30fps_320_240[] = {
+ {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x4837, 0x22, 0, 0},
+};
+
+static struct reg_value ov5640_mipi_pll_QVGA_15fps_320_240[] = {
+ {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x4837, 0x0a, 0, 0},
+};
+
+static struct reg_value ov5640_mipi_pll_30fps_480_272[] = {
+ {0x3035, 0x21, 0, 0}, {0x3036, 0x69, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x3824, 0x04, 0, 0}, {0x4837, 0x16, 0, 0},
+};
+
+static struct reg_value ov5640_mipi_pll_15fps_480_272[] = {
+ {0x3035, 0x41, 0, 0}, {0x3036, 0x69, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x3824, 0x04, 0, 0}, {0x4837, 0x16, 0, 0},
+};
+
+static struct reg_value ov5640_mipi_pll_720P_30fps_1280_720[] = {
+ {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x3824, 0x04, 0, 0}, {0x4837, 0x0a, 0, 0},
+};
+
+static struct reg_value ov5640_mipi_pll_720P_15fps_1280_720[] = {
+ {0x3035, 0x41, 0, 0}, {0x3036, 0x54, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x3824, 0x04, 0, 0}, {0x4837, 0x0a, 0, 0},
+};
+
+static struct reg_value ov5640_mipi_pll_1080P_15fps_1920_1080[] = {
+ {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x3824, 0x04, 0, 0}, {0x4837, 0x0a, 0, 0},
+};
+
+static struct ov5640_mode_info ov5640_mode_info_data[ov5640_mode_MAX + 1] = {
+ {ov5640_mode_VGA_640_480, 640, 480, ov5640_setting_VGA_640_480,
+ ARRAY_SIZE(ov5640_setting_VGA_640_480)},
+
+ {ov5640_mode_QVGA_320_240, 320, 240, ov5640_setting_QVGA_320_240,
+ ARRAY_SIZE(ov5640_setting_QVGA_320_240)},
+
+ {ov5640_mode_480_272, 480, 272, ov5640_setting_480_272,
+ ARRAY_SIZE(ov5640_setting_480_272)},
+
+ {ov5640_mode_720P_1280_720, 1280, 720, ov5640_setting_720P_1280_720,
+ ARRAY_SIZE(ov5640_setting_720P_1280_720)},
+
+ {ov5640_mode_1080P_1920_1080, 1920, 1080, ov5640_setting_1080P_1920_1080,
+ ARRAY_SIZE(ov5640_setting_1080P_1920_1080)},
+};
+
+static struct reg_value ov5640_mipi_config[] = {
+ {0x302C, 0xc2, 0, 0}, /* Driver Capability */
+
+ {0x4300, 0x3F, 0, 0}, /* YUV422 YVYU */
+ {0x501f, 0x00, 0, 0}, /* YUV422 YVYU */
+
+ {0x3034, 0x18, 0, 0}, /* MIPI 8bits mode */
+ {0x3017, 0x00, 0, 0},
+ {0x3018, 0x00, 0, 0},
+
+ {0x300e, 0x45, 0, 0}, /* MIPI mode */
+ {0x4800, 0x04, 0, 0},
+
+ {0x4740, 0x23, 0, 0}, /* BIT5: Pixel BIT1: HSYNC BIT0: VSYNC */
+ /* 1: hight level */
+ /* 0: low level valid */
+ {0x5000, 0xa7, 0, 0},
+};
+
+static struct ov5640_hs_info hs_setting[] = {
+ {1920, 1080, 30, 0x0B},
+ {1920, 1080, 15, 0x10},
+ {1280, 720, 30, 0x11},
+ {1280, 720, 15, 0x16},
+ {640, 480, 30, 0x1E},
+ {640, 480, 15, 0x23},
+ {320, 240, 30, 0x1E},
+ {320, 240, 15, 0x23},
+};
+
+static struct ov5640_pll_info ov5640_mipi_pll_info_data[2][ov5640_mode_MAX + 1] = {
+ {
+ {ov5640_mode_VGA_640_480, ov5640_mipi_pll_VGA_15fps_640_480,
+ ARRAY_SIZE(ov5640_mipi_pll_VGA_15fps_640_480)},
+
+ {ov5640_mode_QVGA_320_240, ov5640_mipi_pll_QVGA_15fps_320_240,
+ ARRAY_SIZE(ov5640_mipi_pll_QVGA_15fps_320_240)},
+
+ {ov5640_mode_480_272, ov5640_mipi_pll_15fps_480_272,
+ ARRAY_SIZE(ov5640_mipi_pll_15fps_480_272)},
+
+ {ov5640_mode_720P_1280_720, ov5640_mipi_pll_720P_15fps_1280_720,
+ ARRAY_SIZE(ov5640_mipi_pll_720P_15fps_1280_720)},
+
+ {ov5640_mode_1080P_1920_1080, ov5640_mipi_pll_1080P_15fps_1920_1080,
+ ARRAY_SIZE(ov5640_mipi_pll_1080P_15fps_1920_1080)},
+ },
+
+ {
+ {ov5640_mode_VGA_640_480, ov5640_mipi_pll_VGA_30fps_640_480,
+ ARRAY_SIZE(ov5640_mipi_pll_VGA_30fps_640_480)},
+
+ {ov5640_mode_QVGA_320_240, ov5640_mipi_pll_QVGA_30fps_320_240,
+ ARRAY_SIZE(ov5640_mipi_pll_QVGA_30fps_320_240)},
+
+ {ov5640_mode_480_272, ov5640_mipi_pll_30fps_480_272,
+ ARRAY_SIZE(ov5640_mipi_pll_30fps_480_272)},
+
+ {ov5640_mode_720P_1280_720, ov5640_mipi_pll_720P_30fps_1280_720,
+ ARRAY_SIZE(ov5640_mipi_pll_720P_30fps_1280_720)},
+ },
+};
+
+static struct regulator *io_regulator;
+static struct regulator *core_regulator;
+static struct regulator *analog_regulator;
+
+static int ov5640_probe(struct i2c_client *adapter,
+ const struct i2c_device_id *device_id);
+static int ov5640_remove(struct i2c_client *client);
+
+static s32 ov5640_read_reg(struct ov5640 *sensor, u16 reg, u8 *val);
+static s32 ov5640_write_reg(struct ov5640 *sensor, u16 reg, u8 val);
+
+static const struct i2c_device_id ov5640_id[] = {
+ {"ov5640_mipi_v3", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, ov5640_id);
+
+static struct i2c_driver ov5640_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ov5640_mipi_v3",
+ },
+ .probe = ov5640_probe,
+ .remove = ov5640_remove,
+ .id_table = ov5640_id,
+};
+
+static const struct ov5640_datafmt ov5640_colour_fmts[] = {
+ {MEDIA_BUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
+ {MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
+};
+
+static struct ov5640 *to_ov5640(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct ov5640, subdev);
+}
+
+static uint16_t find_hs_configure(struct ov5640 *sensor)
+{
+ struct device *dev = &sensor->i2c_client->dev;
+ struct v4l2_fract *timeperframe = &sensor->streamcap.timeperframe;
+ struct v4l2_pix_format *pix = &sensor->pix;
+ u32 frame_rate = timeperframe->denominator / timeperframe->numerator;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hs_setting); i++) {
+ if (hs_setting[i].width == pix->width &&
+ hs_setting[i].height == pix->height &&
+ hs_setting[i].frame_rate == frame_rate)
+ return hs_setting[i].val;
+ }
+
+ if (i == ARRAY_SIZE(hs_setting))
+ dev_err(dev, "%s can not find hs configure\n", __func__);
+
+ return -EINVAL;
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct ov5640_datafmt
+ *ov5640_find_datafmt(u32 code)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ov5640_colour_fmts); i++)
+ if (ov5640_colour_fmts[i].code == code)
+ return ov5640_colour_fmts + i;
+
+ return NULL;
+}
+
+static inline void ov5640_power_down(struct ov5640 *sensor, int enable)
+{
+ gpio_set_value_cansleep(sensor->pwn_gpio, enable);
+
+ udelay(2000);
+}
+
+static inline void ov5640_reset(struct ov5640 *sensor)
+{
+ gpio_set_value_cansleep(sensor->pwn_gpio, 1);
+ gpio_set_value_cansleep(sensor->rst_gpio, 0);
+ udelay(5000);
+
+ gpio_set_value_cansleep(sensor->pwn_gpio, 0);
+ udelay(1000);
+
+ gpio_set_value_cansleep(sensor->rst_gpio, 1);
+ msleep(20);
+}
+
+static int ov5640_regulator_enable(struct device *dev)
+{
+ int ret = 0;
+
+ io_regulator = devm_regulator_get(dev, "DOVDD");
+ if (!IS_ERR(io_regulator)) {
+ regulator_set_voltage(io_regulator,
+ OV5640_VOLTAGE_DIGITAL_IO,
+ OV5640_VOLTAGE_DIGITAL_IO);
+ ret = regulator_enable(io_regulator);
+ if (ret) {
+ dev_err(dev, "set io voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set io voltage ok\n");
+ }
+ } else {
+ io_regulator = NULL;
+ dev_warn(dev, "cannot get io voltage\n");
+ }
+
+ core_regulator = devm_regulator_get(dev, "DVDD");
+ if (!IS_ERR(core_regulator)) {
+ regulator_set_voltage(core_regulator,
+ OV5640_VOLTAGE_DIGITAL_CORE,
+ OV5640_VOLTAGE_DIGITAL_CORE);
+ ret = regulator_enable(core_regulator);
+ if (ret) {
+ dev_err(dev, "set core voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set core voltage ok\n");
+ }
+ } else {
+ core_regulator = NULL;
+ dev_warn(dev, "cannot get core voltage\n");
+ }
+
+ analog_regulator = devm_regulator_get(dev, "AVDD");
+ if (!IS_ERR(analog_regulator)) {
+ regulator_set_voltage(analog_regulator,
+ OV5640_VOLTAGE_ANALOG,
+ OV5640_VOLTAGE_ANALOG);
+ ret = regulator_enable(analog_regulator);
+ if (ret)
+ dev_err(dev, "set analog voltage failed\n");
+ else
+ dev_dbg(dev, "set analog voltage ok\n");
+ } else {
+ analog_regulator = NULL;
+ dev_warn(dev, "cannot get analog voltage\n");
+ }
+
+ return ret;
+}
+
+static s32 ov5640_write_reg(struct ov5640 *sensor, u16 reg, u8 val)
+{
+ struct device *dev = &sensor->i2c_client->dev;
+ u8 au8Buf[3] = {0};
+
+ au8Buf[0] = reg >> 8;
+ au8Buf[1] = reg & 0xff;
+ au8Buf[2] = val;
+
+ if (i2c_master_send(sensor->i2c_client, au8Buf, 3) < 0) {
+ dev_err(dev, "Write reg error: reg=%x, val=%x\n", reg, val);
+ return -1;
+ }
+
+ return 0;
+}
+
+static s32 ov5640_read_reg(struct ov5640 *sensor, u16 reg, u8 *val)
+{
+ struct device *dev = &sensor->i2c_client->dev;
+ u8 au8RegBuf[2] = {0};
+ u8 u8RdVal = 0;
+
+ au8RegBuf[0] = reg >> 8;
+ au8RegBuf[1] = reg & 0xff;
+
+ if (i2c_master_send(sensor->i2c_client, au8RegBuf, 2) != 2) {
+ dev_err(dev, "Read reg error: reg=%x\n", reg);
+ return -1;
+ }
+
+ if (i2c_master_recv(sensor->i2c_client, &u8RdVal, 1) != 1) {
+ dev_err(dev, "Read reg error: reg=%x, val=%x\n", reg, u8RdVal);
+ return -1;
+ }
+
+ *val = u8RdVal;
+
+ return u8RdVal;
+}
+
+static int ov5640_set_clk_rate(struct ov5640 *sensor)
+{
+ u32 tgt_xclk; /* target xclk */
+ int ret;
+
+ /* mclk */
+ tgt_xclk = sensor->mclk;
+ tgt_xclk = min_t(u32, tgt_xclk, (u32)OV5640_XCLK_MAX);
+ tgt_xclk = max_t(u32, tgt_xclk, (u32)OV5640_XCLK_MIN);
+ sensor->mclk = tgt_xclk;
+
+ pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000);
+ ret = clk_set_rate(sensor->sensor_clk, sensor->mclk);
+ if (ret < 0)
+ pr_debug("set rate filed, rate=%d\n", sensor->mclk);
+ return ret;
+}
+
+/* download ov5640 settings to sensor through i2c */
+static int ov5640_download_firmware(struct ov5640 *sensor,
+ struct reg_value *pModeSetting, s32 ArySize)
+{
+ register u32 Delay_ms = 0;
+ register u16 RegAddr = 0;
+ register u8 Mask = 0;
+ register u8 Val = 0;
+ u8 RegVal = 0;
+ int i, retval = 0;
+
+ for (i = 0; i < ArySize; ++i, ++pModeSetting) {
+ Delay_ms = pModeSetting->u32Delay_ms;
+ RegAddr = pModeSetting->u16RegAddr;
+ Val = pModeSetting->u8Val;
+ Mask = pModeSetting->u8Mask;
+
+ if (Mask) {
+ retval = ov5640_read_reg(sensor, RegAddr, &RegVal);
+ if (retval < 0)
+ goto err;
+
+ RegVal &= ~(u8)Mask;
+ Val &= Mask;
+ Val |= RegVal;
+ }
+
+ retval = ov5640_write_reg(sensor, RegAddr, Val);
+ if (retval < 0)
+ goto err;
+
+ if (Delay_ms)
+ msleep(Delay_ms);
+ }
+err:
+ return retval;
+}
+
+static void ov5640_soft_reset(struct ov5640 *sensor)
+{
+ /* sysclk from pad */
+ ov5640_write_reg(sensor, 0x3103, 0x11);
+
+ /* software reset */
+ ov5640_write_reg(sensor, 0x3008, 0x82);
+
+ /* delay at least 5ms */
+ msleep(10);
+}
+
+static int ov5640_config_init(struct ov5640 *sensor)
+{
+ struct reg_value *pModeSetting = NULL;
+ int ArySize = 0, retval = 0;
+
+ /* Configure ov5640 initial parm */
+ pModeSetting = ov5640_init_parm;
+ ArySize = ARRAY_SIZE(ov5640_init_parm);
+
+ retval = ov5640_download_firmware(sensor, pModeSetting, ArySize);
+ if (retval < 0)
+ return retval;
+
+ return 0;
+}
+
+static int ov5640_config_resolution(struct ov5640 *sensor,
+ enum ov5640_mode mode)
+{
+ struct reg_value *pModeSetting = NULL;
+ int ArySize = 0, retval = 0;
+
+ if (mode < ov5640_mode_MIN || mode > ov5640_mode_MAX)
+ return -EINVAL;
+
+ if (mode == ov5640_mode_1080P_1920_1080) {
+ ov5640_write_reg(sensor, 0x3709, 0x12);
+ ov5640_write_reg(sensor, 0x3821, 0x06);
+ }
+
+ if (mode == ov5640_mode_480_272) {
+ mode = ov5640_mode_VGA_640_480;
+ pr_warn("Not support 480*272, change to 640*480\n");
+ }
+
+ /* Configure ov5640 initial parm */
+ pModeSetting = ov5640_mode_info_data[mode].init_data_ptr;
+ ArySize = ov5640_mode_info_data[mode].init_data_size;
+
+ retval = ov5640_download_firmware(sensor, pModeSetting, ArySize);
+ if (retval < 0)
+ return retval;
+
+ return 0;
+}
+
+static int ov5640_config_others(struct ov5640 *sensor,
+ enum ov5640_frame_rate rate, enum ov5640_mode mode)
+{
+ struct reg_value *pModeSetting = NULL;
+ int ArySize = 0, retval = 0;
+
+ if (mode < ov5640_mode_MIN || mode > ov5640_mode_MAX)
+ return -EINVAL;
+
+ mode = (mode == ov5640_mode_480_272) ?
+ ov5640_mode_VGA_640_480 : mode;
+ pModeSetting = ov5640_mipi_pll_info_data[rate][mode].init_data_ptr;
+ ArySize = ov5640_mipi_pll_info_data[rate][mode].init_data_size;
+ retval = ov5640_download_firmware(sensor, pModeSetting, ArySize);
+ if (retval < 0)
+ return retval;
+
+ /* Configure ov5640 initial parm */
+ pModeSetting = ov5640_mipi_config;
+ ArySize = ARRAY_SIZE(ov5640_mipi_config);
+ retval = ov5640_download_firmware(sensor, pModeSetting, ArySize);
+ if (retval < 0)
+ return retval;
+
+ return 0;
+}
+
+static void ov5640_start(struct ov5640 *sensor)
+{
+ ov5640_write_reg(sensor, 0x3008, 0x02);
+ ov5640_write_reg(sensor, 0x3008, 0x02);
+ udelay(1000);
+}
+
+static int ov5640_change_mode(struct ov5640 *sensor,
+ enum ov5640_frame_rate rate, enum ov5640_mode mode)
+{
+ int retval;
+
+ if (mode == ov5640_mode_1080P_1920_1080 && rate != ov5640_15_fps) {
+ pr_warn("1080P only suppoert 15fps frame rate\n");
+ rate = ov5640_15_fps;
+ }
+
+ retval = ov5640_config_resolution(sensor, mode);
+ if (retval < 0) {
+ pr_err("%s config resolution fail\n", __func__);
+ return -EINVAL;
+ }
+
+ retval = ov5640_config_others(sensor, rate, mode);
+ if (retval < 0) {
+ pr_err("%s config others fail\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int init_device(struct ov5640 *sensor)
+{
+ int retval;
+
+ ov5640_soft_reset(sensor);
+ retval = ov5640_config_init(sensor);
+ if (retval < 0)
+ return retval;
+
+ retval = ov5640_config_resolution(sensor, ov5640_mode_VGA_640_480);
+ if (retval < 0)
+ return retval;
+
+ retval = ov5640_config_others(sensor, ov5640_30_fps,
+ ov5640_mode_VGA_640_480);
+ if (retval < 0)
+ return retval;
+
+ ov5640_start(sensor);
+
+ return 0;
+}
+
+static void ov5640_stop(struct ov5640 *sensor)
+{
+ ov5640_write_reg(sensor, 0x3008, 0x42);
+ udelay(1000);
+}
+
+/*!
+ * ov5640_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @on: indicates power mode (on or off)
+ *
+ * Turns the power on or off, depending on the value of on and returns the
+ * appropriate error code.
+ */
+static int ov5640_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+
+ if (on)
+ clk_prepare_enable(sensor->sensor_clk);
+ else
+ clk_disable_unprepare(sensor->sensor_clk);
+
+ sensor->on = on;
+ return 0;
+}
+
+/*!
+ * ov5640_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 sub device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ov5640_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+ int ret = 0;
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cparm->capability = sensor->streamcap.capability;
+ cparm->timeperframe = sensor->streamcap.timeperframe;
+ cparm->capturemode = sensor->streamcap.capturemode;
+ ret = 0;
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ ret = -EINVAL;
+ break;
+
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * ov5460_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 sub device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible. If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ */
+static int ov5640_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+ u32 tgt_fps; /* target frames per secound */
+ enum ov5640_frame_rate frame_rate;
+ enum ov5640_mode mode = a->parm.capture.capturemode;
+ int ret = 0;
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ /* Check that the new frame rate is allowed. */
+ if ((timeperframe->numerator == 0) ||
+ (timeperframe->denominator == 0)) {
+ timeperframe->denominator = DEFAULT_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps > MAX_FPS) {
+ timeperframe->denominator = MAX_FPS;
+ timeperframe->numerator = 1;
+ } else if (tgt_fps < MIN_FPS) {
+ timeperframe->denominator = MIN_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ if (mode == ov5640_mode_1080P_1920_1080 && tgt_fps != 15) {
+ pr_warn("1080P only suppoert 15fps frame rate\n");
+ timeperframe->denominator = 15;
+ timeperframe->numerator = 1;
+ }
+
+ /* Actual frame rate we use */
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps == 30)
+ frame_rate = ov5640_30_fps;
+ else if (tgt_fps == 15)
+ frame_rate = ov5640_15_fps;
+ else {
+ pr_err(" The camera frame rate is not supported!\n");
+ goto error;
+ }
+
+ ret = ov5640_change_mode(sensor, frame_rate, mode);
+ if (ret < 0)
+ goto error;
+
+ sensor->streamcap.timeperframe = *timeperframe;
+ sensor->streamcap.capturemode = mode;
+ sensor->pix.width = ov5640_mode_info_data[mode].width;
+ sensor->pix.height = ov5640_mode_info_data[mode].height;
+
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ pr_debug(" type is not V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n",
+ a->type);
+ ret = -EINVAL;
+ break;
+
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+error:
+ return ret;
+}
+
+static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+
+ if (enable)
+ ov5640_start(sensor);
+ else
+ ov5640_stop(sensor);
+
+ sensor->on = enable;
+ 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;
+ const struct ov5640_datafmt *fmt = ov5640_find_datafmt(mf->code);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+
+ if (format->pad)
+ return -EINVAL;
+
+ if (!fmt) {
+ mf->code = ov5640_colour_fmts[1].code;
+ mf->colorspace = ov5640_colour_fmts[1].colorspace;
+ }
+
+ mf->field = V4L2_FIELD_NONE;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+ return 0;
+
+ sensor->fmt = fmt;
+
+ 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 *sensor = to_ov5640(client);
+ /*const struct ov5640_datafmt *fmt = sensor->fmt;*/
+
+ if (format->pad)
+ return -EINVAL;
+
+ memset(mf, 0, sizeof(struct v4l2_mbus_framefmt));
+
+ mf->code = ov5640_colour_fmts[1].code;
+ mf->colorspace = ov5640_colour_fmts[1].colorspace;
+ mf->width = sensor->pix.width;
+ mf->height = sensor->pix.height;
+ mf->field = V4L2_FIELD_NONE;
+ mf->reserved[1] = find_hs_configure(sensor);
+
+ dev_dbg(&client->dev, "%s code=0x%x, w/h=(%d,%d), colorspace=%d, field=%d\n",
+ __func__, mf->code, mf->width, mf->height, mf->colorspace, mf->field);
+
+ return 0;
+}
+
+static int ov5640_enum_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(ov5640_colour_fmts))
+ return -EINVAL;
+
+ code->code = ov5640_colour_fmts[code->index].code;
+ return 0;
+}
+
+/*!
+ * ov5640_enum_framesizes - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ov5640_enum_framesizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index > ov5640_mode_MAX)
+ return -EINVAL;
+
+ fse->max_width = ov5640_mode_info_data[fse->index].width;
+ fse->min_width = fse->max_width;
+ fse->max_height = ov5640_mode_info_data[fse->index].height;
+ fse->min_height = fse->max_height;
+ return 0;
+}
+
+/*!
+ * ov5640_enum_frameintervals - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMEINTERVALS ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ov5640_enum_frameintervals(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ int i, j, count;
+
+ if (fie->index < 0 || fie->index > ov5640_mode_MAX)
+ return -EINVAL;
+
+ if (fie->width == 0 || fie->height == 0 ||
+ fie->code == 0) {
+ pr_warn("Please assign pixel format, width and height.\n");
+ return -EINVAL;
+ }
+
+ fie->interval.numerator = 1;
+
+ count = 0;
+ for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
+ for (j = 0; j < (ov5640_mode_MAX + 1); j++) {
+ if (fie->width == ov5640_mode_info_data[j].width
+ && fie->height == ov5640_mode_info_data[j].height
+ && ov5640_mode_info_data[j].init_data_ptr != NULL) {
+ count++;
+ }
+ if (fie->index == (count - 1)) {
+ fie->interval.denominator = ov5640_framerates[i];
+ if (ov5640_mode_info_data[j].mode ==
+ ov5640_mode_1080P_1920_1080)
+ fie->interval.denominator = ov5640_framerates[0];
+ return 0;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int ov5640_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops ov5640_subdev_video_ops = {
+ .g_parm = ov5640_g_parm,
+ .s_parm = ov5640_s_parm,
+ .s_stream = ov5640_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ov5640_subdev_pad_ops = {
+ .enum_frame_size = ov5640_enum_framesizes,
+ .enum_frame_interval = ov5640_enum_frameintervals,
+ .enum_mbus_code = ov5640_enum_code,
+ .set_fmt = ov5640_set_fmt,
+ .get_fmt = ov5640_get_fmt,
+};
+
+static struct v4l2_subdev_core_ops ov5640_subdev_core_ops = {
+ .s_power = ov5640_s_power,
+};
+
+static struct v4l2_subdev_ops ov5640_subdev_ops = {
+ .core = &ov5640_subdev_core_ops,
+ .video = &ov5640_subdev_video_ops,
+ .pad = &ov5640_subdev_pad_ops,
+};
+
+static const struct media_entity_operations ov5640_sd_media_ops = {
+ .link_setup = ov5640_link_setup,
+};
+
+/*!
+ * ov5640 I2C probe function
+ *
+ * @param adapter struct i2c_adapter *
+ * @return Error code indicating success or failure
+ */
+static int ov5640_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pinctrl *pinctrl;
+ struct device *dev = &client->dev;
+ struct v4l2_subdev *sd;
+ int retval;
+ u8 chip_id_high, chip_id_low;
+ struct ov5640 *sensor;
+
+ sensor = kmalloc(sizeof(*sensor), GFP_KERNEL);
+ /* Set initial values for the sensor struct. */
+ memset(sensor, 0, sizeof(*sensor));
+
+ /* ov5640 pinctrl */
+ pinctrl = devm_pinctrl_get_select_default(dev);
+ if (IS_ERR(pinctrl)) {
+ dev_err(dev, "setup pinctrl failed\n");
+ return PTR_ERR(pinctrl);
+ }
+
+ /* request power down pin */
+ sensor->pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+ if (!gpio_is_valid(sensor->pwn_gpio))
+ dev_warn(dev, "No sensor pwdn pin available");
+ else {
+ retval = devm_gpio_request_one(dev, sensor->pwn_gpio,
+ GPIOF_OUT_INIT_HIGH, "ov5640_mipi_pwdn");
+ if (retval < 0) {
+ dev_warn(dev, "Failed to set power pin\n");
+ dev_warn(dev, "retval=%d\n", retval);
+ return retval;
+ }
+ }
+
+ /* request reset pin */
+ sensor->rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0);
+ if (!gpio_is_valid(sensor->rst_gpio))
+ dev_warn(dev, "No sensor reset pin available");
+ else {
+ retval = devm_gpio_request_one(dev, sensor->rst_gpio,
+ GPIOF_OUT_INIT_HIGH, "ov5640_mipi_reset");
+ if (retval < 0) {
+ dev_warn(dev, "Failed to set reset pin\n");
+ return retval;
+ }
+ }
+
+ /* Set initial values for the sensor struct. */
+ sensor->sensor_clk = devm_clk_get(dev, "csi_mclk");
+ if (IS_ERR(sensor->sensor_clk)) {
+ /* assuming clock enabled by default */
+ sensor->sensor_clk = NULL;
+ dev_err(dev, "clock-frequency missing or invalid\n");
+ return PTR_ERR(sensor->sensor_clk);
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk",
+ &(sensor->mclk));
+ if (retval) {
+ dev_err(dev, "mclk missing or invalid\n");
+ return retval;
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk_source",
+ (u32 *) &(sensor->mclk_source));
+ if (retval) {
+ dev_err(dev, "mclk_source missing or invalid\n");
+ return retval;
+ }
+
+ retval = of_property_read_u32(dev->of_node, "csi_id",
+ &(sensor->csi));
+ if (retval) {
+ dev_err(dev, "csi id missing or invalid\n");
+ return retval;
+ }
+
+ /* Set mclk rate before clk on */
+ ov5640_set_clk_rate(sensor);
+
+ retval = clk_prepare_enable(sensor->sensor_clk);
+ if (retval < 0) {
+ dev_err(dev, "%s: enable sensor clk fail\n", __func__);
+ return -EINVAL;
+ }
+
+ sensor->io_init = ov5640_reset;
+ sensor->i2c_client = client;
+
+ sensor->pix.pixelformat = V4L2_PIX_FMT_UYVY;
+ sensor->pix.width = ov5640_mode_info_data[0].width;
+ sensor->pix.height = ov5640_mode_info_data[0].height;
+ sensor->streamcap.capability = V4L2_MODE_HIGHQUALITY |
+ V4L2_CAP_TIMEPERFRAME;
+ sensor->streamcap.capturemode = 0;
+ sensor->streamcap.timeperframe.denominator = DEFAULT_FPS;
+ sensor->streamcap.timeperframe.numerator = 1;
+
+ ov5640_regulator_enable(&client->dev);
+
+ ov5640_reset(sensor);
+
+ retval = ov5640_read_reg(sensor, OV5640_CHIP_ID_HIGH_BYTE,
+ &chip_id_high);
+ if (retval < 0 || chip_id_high != 0x56) {
+ clk_disable_unprepare(sensor->sensor_clk);
+ pr_warn("camera ov5640 is not found\n");
+ return -ENODEV;
+ }
+ retval = ov5640_read_reg(sensor, OV5640_CHIP_ID_LOW_BYTE,
+ &chip_id_low);
+ if (retval < 0 || chip_id_low != 0x40) {
+ clk_disable_unprepare(sensor->sensor_clk);
+ pr_warn("camera ov5640 is not found\n");
+ return -ENODEV;
+ }
+
+ retval = init_device(sensor);
+ if (retval < 0) {
+ clk_disable_unprepare(sensor->sensor_clk);
+ pr_warn("camera ov5640 init fail\n");
+ return -ENODEV;
+ }
+
+ sd = &sensor->subdev;
+ v4l2_i2c_subdev_init(sd, client, &ov5640_subdev_ops);
+
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ sensor->pads[OV5640_SENS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ retval = media_entity_pads_init(&sd->entity, OV5640_SENS_PADS_NUM,
+ sensor->pads);
+ sd->entity.ops = &ov5640_sd_media_ops;
+ if (retval < 0)
+ return retval;
+
+ retval = v4l2_async_register_subdev(sd);
+ if (retval < 0) {
+ dev_err(&client->dev,
+ "%s--Async register failed, ret=%d\n", __func__, retval);
+ media_entity_cleanup(&sd->entity);
+ }
+
+ clk_disable_unprepare(sensor->sensor_clk);
+
+ pr_info("%s camera mipi ov5640, is found\n", __func__);
+ return retval;
+}
+
+/*!
+ * ov5640 I2C detach function
+ *
+ * @param client struct i2c_client *
+ * @return Error code indicating success or failure
+ */
+static int ov5640_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov5640 *sensor = to_ov5640(client);
+
+ v4l2_async_unregister_subdev(sd);
+
+ clk_unprepare(sensor->sensor_clk);
+
+ ov5640_power_down(sensor, 1);
+
+ if (analog_regulator)
+ regulator_disable(analog_regulator);
+
+ if (core_regulator)
+ regulator_disable(core_regulator);
+
+ if (io_regulator)
+ regulator_disable(io_regulator);
+
+ return 0;
+}
+
+module_i2c_driver(ov5640_i2c_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("OV5640 Camera Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("3.0");
+MODULE_ALIAS("MIPI CSI");
diff --git a/drivers/media/platform/imx8/ov5640_v3.c b/drivers/media/platform/imx8/ov5640_v3.c
new file mode 100644
index 000000000000..69145bce3d6d
--- /dev/null
+++ b/drivers/media/platform/imx8/ov5640_v3.c
@@ -0,0 +1,1409 @@
+/*
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2018 NXP
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#define OV5640_VOLTAGE_ANALOG 2800000
+#define OV5640_VOLTAGE_DIGITAL_CORE 1500000
+#define OV5640_VOLTAGE_DIGITAL_IO 1800000
+
+#define MIN_FPS 15
+#define MAX_FPS 30
+#define DEFAULT_FPS 30
+
+#define OV5640_XCLK_MIN 6000000
+#define OV5640_XCLK_MAX 24000000
+
+#define OV5640_CHIP_ID_HIGH_BYTE 0x300A
+#define OV5640_CHIP_ID_LOW_BYTE 0x300B
+
+#define OV5640_SENS_PAD_SOURCE 0
+#define OV5640_SENS_PADS_NUM 1
+
+enum ov5640_mode {
+ ov5640_mode_MIN = 0,
+ ov5640_mode_VGA_640_480 = 0,
+ ov5640_mode_QVGA_320_240 = 1,
+ ov5640_mode_480_272 = 2,
+ ov5640_mode_720P_1280_720 = 3,
+ ov5640_mode_1080P_1920_1080 = 4,
+ ov5640_mode_MAX = 4
+};
+
+enum ov5640_frame_rate {
+ ov5640_15_fps,
+ ov5640_30_fps
+};
+
+static int ov5640_framerates[] = {
+ [ov5640_15_fps] = 15,
+ [ov5640_30_fps] = 30,
+};
+
+struct ov5640_datafmt {
+ u32 code;
+ enum v4l2_colorspace colorspace;
+};
+
+struct reg_value {
+ u16 u16RegAddr;
+ u8 u8Val;
+ u8 u8Mask;
+ u32 u32Delay_ms;
+};
+
+struct ov5640_mode_info {
+ enum ov5640_mode mode;
+ u32 width;
+ u32 height;
+ struct reg_value *init_data_ptr;
+ u32 init_data_size;
+};
+
+struct ov5640_pll_info {
+ enum ov5640_mode mode;
+ struct reg_value *init_data_ptr;
+ u32 init_data_size;
+};
+
+struct ov5640_hs_info {
+ u32 width;
+ u32 height;
+ u32 frame_rate;
+ u32 val;
+};
+
+struct ov5640 {
+ struct v4l2_subdev subdev;
+ struct i2c_client *i2c_client;
+ struct v4l2_pix_format pix;
+ const struct ov5640_datafmt *fmt;
+ struct v4l2_captureparm streamcap;
+ struct media_pad pads[OV5640_SENS_PADS_NUM];
+ bool on;
+
+ /* control settings */
+ int brightness;
+ int hue;
+ int contrast;
+ int saturation;
+ int red;
+ int green;
+ int blue;
+ int ae_mode;
+
+ u32 mclk;
+ u8 mclk_source;
+ struct clk *sensor_clk;
+ int csi;
+
+ void (*io_init)(void);
+};
+
+/*!
+ * Maintains the information on the current state of the sesor.
+ */
+static struct ov5640 ov5640_data;
+static int pwn_gpio, rst_gpio;
+
+static struct reg_value ov5640_init_parm[] = {
+ {0x3008, 0x42, 0, 0},
+
+ /* System setting.0*/
+ {0x3103, 0x03, 0, 0},
+ {0x3000, 0x00, 0, 0},
+ {0x3004, 0xff, 0, 0},
+ {0x3002, 0x1c, 0, 0},
+ {0x3006, 0xc3, 0, 0},
+ {0x302e, 0x08, 0, 0},
+ {0x3037, 0x13, 0, 0},
+ {0x3108, 0x01, 0, 0},
+ {0x3618, 0x00, 0, 0},
+ {0x3612, 0x29, 0, 0},
+ {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0},
+ {0x370c, 0x03, 0, 0},
+ {0x3820, 0x41, 0, 0},
+ {0x3821, 0x07, 0, 0},
+ {0x3630, 0x36, 0, 0},
+ {0x3631, 0x0e, 0, 0},
+ {0x3632, 0xe2, 0, 0},
+ {0x3633, 0x12, 0, 0},
+ {0x3621, 0xe0, 0, 0},
+ {0x3704, 0xa0, 0, 0},
+ {0x3703, 0x5a, 0, 0},
+ {0x3715, 0x78, 0, 0},
+ {0x3717, 0x01, 0, 0},
+ {0x370b, 0x60, 0, 0},
+ {0x3705, 0x1a, 0, 0},
+ {0x3905, 0x02, 0, 0},
+ {0x3906, 0x10, 0, 0},
+ {0x3901, 0x0a, 0, 0},
+ {0x3731, 0x12, 0, 0},
+ {0x3600, 0x08, 0, 0},
+ {0x3601, 0x33, 0, 0},
+ {0x302d, 0x60, 0, 0},
+ {0x3620, 0x52, 0, 0},
+ {0x371b, 0x20, 0, 0},
+ {0x471c, 0x50, 0, 0},
+ {0x3a13, 0x43, 0, 0},
+ {0x3a18, 0x00, 0, 0},
+ {0x3a19, 0x7c, 0, 0},
+ {0x3635, 0x13, 0, 0},
+ {0x3636, 0x03, 0, 0},
+ {0x3634, 0x40, 0, 0},
+ {0x3622, 0x01, 0, 0},
+ {0x3c01, 0x00, 0, 0},
+ {0x3a00, 0x58, 0, 0},
+ {0x4001, 0x02, 0, 0},
+ {0x4004, 0x02, 0, 0},
+ {0x4005, 0x1a, 0, 0},
+ {0x5001, 0xa3, 0, 0},
+
+ /* AEC */
+ {0x3a0f, 0x30, 0, 0},
+ {0x3a10, 0x28, 0, 0},
+ {0x3a1b, 0x30, 0, 0},
+ {0x3a1e, 0x26, 0, 0},
+ {0x3a11, 0x60, 0, 0},
+ {0x3a1f, 0x14, 0, 0},
+
+ /* AWB */
+ {0x5180, 0xff, 0, 0},
+ {0x5181, 0xf2, 0, 0},
+ {0x5182, 0x00, 0, 0},
+ {0x5183, 0x14, 0, 0},
+ {0x5184, 0x25, 0, 0},
+ {0x5185, 0x24, 0, 0},
+ {0x5186, 0x09, 0, 0},
+ {0x5187, 0x09, 0, 0},
+ {0x5188, 0x09, 0, 0},
+ {0x5189, 0x88, 0, 0},
+ {0x518a, 0x54, 0, 0},
+ {0x518b, 0xee, 0, 0},
+ {0x518c, 0xb2, 0, 0},
+ {0x518d, 0x50, 0, 0},
+ {0x518e, 0x34, 0, 0},
+ {0x518f, 0x6b, 0, 0},
+ {0x5190, 0x46, 0, 0},
+ {0x5191, 0xf8, 0, 0},
+ {0x5192, 0x04, 0, 0},
+ {0x5193, 0x70, 0, 0},
+ {0x5194, 0xf0, 0, 0},
+ {0x5195, 0xf0, 0, 0},
+ {0x5196, 0x03, 0, 0},
+ {0x5197, 0x01, 0, 0},
+ {0x5198, 0x04, 0, 0},
+ {0x5199, 0x6c, 0, 0},
+ {0x519a, 0x04, 0, 0},
+ {0x519b, 0x00, 0, 0},
+ {0x519c, 0x09, 0, 0},
+ {0x519d, 0x2b, 0, 0},
+ {0x519e, 0x38, 0, 0},
+
+ /* Color Matrix */
+ {0x5381, 0x1e, 0, 0},
+ {0x5382, 0x5b, 0, 0},
+ {0x5383, 0x08, 0, 0},
+ {0x5384, 0x0a, 0, 0},
+ {0x5385, 0x7e, 0, 0},
+ {0x5386, 0x88, 0, 0},
+ {0x5387, 0x7c, 0, 0},
+ {0x5388, 0x6c, 0, 0},
+ {0x5389, 0x10, 0, 0},
+ {0x538a, 0x01, 0, 0},
+ {0x538b, 0x98, 0, 0},
+
+ /* sharp */
+ {0x5300, 0x08, 0, 0},
+ {0x5301, 0x30, 0, 0},
+ {0x5302, 0x10, 0, 0},
+ {0x5303, 0x00, 0, 0},
+ {0x5304, 0x08, 0, 0},
+ {0x5305, 0x30, 0, 0},
+ {0x5306, 0x08, 0, 0},
+ {0x5307, 0x16, 0, 0},
+ {0x5309, 0x08, 0, 0},
+ {0x530a, 0x30, 0, 0},
+ {0x530b, 0x04, 0, 0},
+ {0x530c, 0x06, 0, 0},
+
+ /* Gamma */
+ {0x5480, 0x01, 0, 0},
+ {0x5481, 0x08, 0, 0},
+ {0x5482, 0x14, 0, 0},
+ {0x5483, 0x28, 0, 0},
+ {0x5484, 0x51, 0, 0},
+ {0x5485, 0x65, 0, 0},
+ {0x5486, 0x71, 0, 0},
+ {0x5487, 0x7d, 0, 0},
+ {0x5488, 0x87, 0, 0},
+ {0x5489, 0x91, 0, 0},
+ {0x548a, 0x9a, 0, 0},
+ {0x548b, 0xaa, 0, 0},
+ {0x548c, 0xb8, 0, 0},
+ {0x548d, 0xcd, 0, 0},
+ {0x548e, 0xdd, 0, 0},
+ {0x548f, 0xea, 0, 0},
+ {0x5490, 0x1d, 0, 0},
+
+ /* UV adjust. */
+ {0x5580, 0x02, 0, 0},
+ {0x5583, 0x40, 0, 0},
+ {0x5584, 0x10, 0, 0},
+ {0x5589, 0x10, 0, 0},
+ {0x558a, 0x00, 0, 0},
+ {0x558b, 0xf8, 0, 0},
+
+ /* Lens correction0 */
+ {0x5800, 0x23, 0, 0},
+ {0x5801, 0x14, 0, 0},
+ {0x5802, 0x0f, 0, 0},
+ {0x5803, 0x0f, 0, 0},
+ {0x5804, 0x12, 0, 0},
+ {0x5805, 0x26, 0, 0},
+ {0x5806, 0x0c, 0, 0},
+ {0x5807, 0x08, 0, 0},
+ {0x5808, 0x05, 0, 0},
+ {0x5809, 0x05, 0, 0},
+ {0x580a, 0x08, 0, 0},
+ {0x580b, 0x0d, 0, 0},
+ {0x580c, 0x08, 0, 0},
+ {0x580d, 0x03, 0, 0},
+ {0x580e, 0x00, 0, 0},
+ {0x580f, 0x00, 0, 0},
+ {0x5810, 0x03, 0, 0},
+ {0x5811, 0x09, 0, 0},
+ {0x5812, 0x07, 0, 0},
+ {0x5813, 0x03, 0, 0},
+ {0x5814, 0x00, 0, 0},
+ {0x5815, 0x01, 0, 0},
+ {0x5816, 0x03, 0, 0},
+ {0x5817, 0x08, 0, 0},
+ {0x5818, 0x0d, 0, 0},
+ {0x5819, 0x08, 0, 0},
+ {0x581a, 0x05, 0, 0},
+ {0x581b, 0x06, 0, 0},
+ {0x581c, 0x08, 0, 0},
+ {0x581d, 0x0e, 0, 0},
+ {0x581e, 0x29, 0, 0},
+ {0x581f, 0x17, 0, 0},
+ {0x5820, 0x11, 0, 0},
+ {0x5821, 0x11, 0, 0},
+ {0x5822, 0x15, 0, 0},
+ {0x5823, 0x28, 0, 0},
+ {0x5824, 0x46, 0, 0},
+ {0x5825, 0x26, 0, 0},
+ {0x5826, 0x08, 0, 0},
+ {0x5827, 0x26, 0, 0},
+ {0x5828, 0x64, 0, 0},
+ {0x5829, 0x26, 0, 0},
+ {0x582a, 0x24, 0, 0},
+ {0x582b, 0x22, 0, 0},
+ {0x582c, 0x24, 0, 0},
+ {0x582d, 0x24, 0, 0},
+ {0x582e, 0x06, 0, 0},
+ {0x582f, 0x22, 0, 0},
+ {0x5830, 0x40, 0, 0},
+ {0x5831, 0x42, 0, 0},
+ {0x5832, 0x24, 0, 0},
+ {0x5833, 0x26, 0, 0},
+ {0x5834, 0x24, 0, 0},
+ {0x5835, 0x22, 0, 0},
+ {0x5836, 0x22, 0, 0},
+ {0x5837, 0x26, 0, 0},
+ {0x5838, 0x44, 0, 0},
+ {0x5839, 0x24, 0, 0},
+ {0x583a, 0x26, 0, 0},
+ {0x583b, 0x28, 0, 0},
+ {0x583c, 0x42, 0, 0},
+ {0x583d, 0xce, 0, 0},
+};
+
+static struct reg_value ov5640_setting_VGA_640_480[] = {
+ {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0},
+ {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0},
+ {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0},
+ {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0},
+ {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0},
+ {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0},
+};
+
+static struct reg_value ov5640_setting_QVGA_320_240[] = {
+ {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0},
+ {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0},
+ {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0},
+ {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0},
+ {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0},
+ {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0},
+ {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0},
+};
+
+static struct reg_value ov5640_setting_480_272[] = {
+ {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0},
+ {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0},
+ {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, {0x3808, 0x01, 0, 0},
+ {0x3809, 0xE0, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0x10, 0, 0},
+ {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, {0x380e, 0x02, 0, 0},
+ {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0},
+ {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0},
+};
+
+static struct reg_value ov5640_setting_720P_1280_720[] = {
+ {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0},
+ {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0},
+ {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, {0x3808, 0x05, 0, 0},
+ {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, {0x380b, 0xd0, 0, 0},
+ {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, {0x380e, 0x02, 0, 0},
+ {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0},
+ {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0},
+};
+
+static struct reg_value ov5640_setting_1080P_1920_1080[] = {
+ {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
+ {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
+ {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0},
+ {0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0},
+ {0x380f, 0x60, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0},
+ {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, {0x3814, 0x11, 0, 0},
+ {0x3815, 0x11, 0, 0},
+};
+
+/* DVP */
+static struct reg_value ov5640_pll_VGA_30fps_640_480[] = {
+ {0x3035, 0x11, 0, 0}, {0x3036, 0x46, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x4837, 0x22, 0, 0},
+};
+
+static struct reg_value ov5640_pll_VGA_15fps_640_480[] = {
+ {0x3035, 0x21, 0, 0}, {0x3036, 0x46, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x4837, 0x22, 0, 0},
+};
+
+static struct reg_value ov5640_pll_QVGA_30fps_320_240[] = {
+ {0x3035, 0x11, 0, 0}, {0x3036, 0x46, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x4837, 0x22, 0, 0},
+};
+
+static struct reg_value ov5640_pll_QVGA_15fps_320_240[] = {
+ {0x3035, 0x21, 0, 0}, {0x3036, 0x46, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x4837, 0x22, 0, 0},
+};
+
+static struct reg_value ov5640_pll_30fps_480_272[] = {
+ {0x3035, 0x21, 0, 0}, {0x3036, 0x69, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x3824, 0x04, 0, 0}, {0x4837, 0x16, 0, 0},
+};
+
+static struct reg_value ov5640_pll_15fps_480_272[] = {
+ {0x3035, 0x41, 0, 0}, {0x3036, 0x69, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x3824, 0x04, 0, 0}, {0x4837, 0x16, 0, 0},
+};
+
+static struct reg_value ov5640_pll_720P_30fps_1280_720[] = {
+ {0x3035, 0x21, 0, 0}, {0x3036, 0x69, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x3824, 0x04, 0, 0}, {0x4837, 0x16, 0, 0},
+};
+
+static struct reg_value ov5640_pll_720P_15fps_1280_720[] = {
+ {0x3035, 0x41, 0, 0}, {0x3036, 0x69, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x3824, 0x04, 0, 0}, {0x4837, 0x16, 0, 0},
+};
+
+static struct reg_value ov5640_pll_1080P_15fps_1920_1080[] = {
+ {0x3035, 0x21, 0, 0}, {0x3036, 0x69, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x3824, 0x04, 0, 0}, {0x4837, 0x16, 0, 0},
+};
+
+static struct reg_value ov5640_config[] = {
+ {0x302C, 0xc2, 0, 0}, /* Driver Capability */
+
+ {0x4300, 0x31, 0, 0}, /* YUV422 YVYU */
+ {0x501f, 0x00, 0, 0}, /* YUV422 YVYU */
+
+ {0x3034, 0x1a, 0, 0}, /* Inerface 10bits mode */
+ {0x3017, 0xFF, 0, 0},
+ {0x3018, 0xFF, 0, 0},
+
+ {0x300e, 0x58, 0, 0}, /* DVP mode */
+ {0x4740, 0x23, 0, 0}, /* BIT5: Pixel BIT1: HSYNC BIT0: VSYNC
+ 1: hight level
+ 0: low level valid*/
+ {0x5000, 0xa7, 0, 0},
+};
+
+static struct ov5640_mode_info ov5640_mode_info_data[ov5640_mode_MAX + 1] = {
+ {ov5640_mode_VGA_640_480, 640, 480, ov5640_setting_VGA_640_480,
+ ARRAY_SIZE(ov5640_setting_VGA_640_480)},
+
+ {ov5640_mode_QVGA_320_240, 320, 240, ov5640_setting_QVGA_320_240,
+ ARRAY_SIZE(ov5640_setting_QVGA_320_240)},
+
+ {ov5640_mode_480_272, 480, 272, ov5640_setting_480_272,
+ ARRAY_SIZE(ov5640_setting_480_272)},
+
+ {ov5640_mode_720P_1280_720, 1280, 720, ov5640_setting_720P_1280_720,
+ ARRAY_SIZE(ov5640_setting_720P_1280_720)},
+
+ {ov5640_mode_1080P_1920_1080, 1920, 1080, ov5640_setting_1080P_1920_1080,
+ ARRAY_SIZE(ov5640_setting_1080P_1920_1080)},
+};
+
+static struct ov5640_pll_info ov5640_pll_info_data[2][ov5640_mode_MAX + 1] = {
+ {
+ {ov5640_mode_VGA_640_480, ov5640_pll_VGA_15fps_640_480,
+ ARRAY_SIZE(ov5640_pll_VGA_15fps_640_480)},
+
+ {ov5640_mode_QVGA_320_240, ov5640_pll_QVGA_15fps_320_240,
+ ARRAY_SIZE(ov5640_pll_QVGA_15fps_320_240)},
+
+ {ov5640_mode_480_272, ov5640_pll_15fps_480_272,
+ ARRAY_SIZE(ov5640_pll_15fps_480_272)},
+
+ {ov5640_mode_720P_1280_720, ov5640_pll_720P_15fps_1280_720,
+ ARRAY_SIZE(ov5640_pll_720P_15fps_1280_720)},
+
+ {ov5640_mode_1080P_1920_1080, ov5640_pll_1080P_15fps_1920_1080,
+ ARRAY_SIZE(ov5640_pll_1080P_15fps_1920_1080)},
+ },
+
+ {
+ {ov5640_mode_VGA_640_480, ov5640_pll_VGA_30fps_640_480,
+ ARRAY_SIZE(ov5640_pll_VGA_30fps_640_480)},
+
+ {ov5640_mode_QVGA_320_240, ov5640_pll_QVGA_30fps_320_240,
+ ARRAY_SIZE(ov5640_pll_QVGA_30fps_320_240)},
+
+ {ov5640_mode_480_272, ov5640_pll_30fps_480_272,
+ ARRAY_SIZE(ov5640_pll_30fps_480_272)},
+
+ {ov5640_mode_720P_1280_720, ov5640_pll_720P_30fps_1280_720,
+ ARRAY_SIZE(ov5640_pll_720P_30fps_1280_720)},
+ },
+};
+
+static struct regulator *io_regulator;
+static struct regulator *core_regulator;
+static struct regulator *analog_regulator;
+
+static int ov5640_probe(struct i2c_client *adapter,
+ const struct i2c_device_id *device_id);
+static int ov5640_remove(struct i2c_client *client);
+
+static s32 ov5640_read_reg(u16 reg, u8 *val);
+static s32 ov5640_write_reg(u16 reg, u8 val);
+
+static const struct i2c_device_id ov5640_id[] = {
+ {"ov5640_v3", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, ov5640_id);
+
+static struct i2c_driver ov5640_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ov5640_v3",
+ },
+ .probe = ov5640_probe,
+ .remove = ov5640_remove,
+ .id_table = ov5640_id,
+};
+
+static const struct ov5640_datafmt ov5640_colour_fmts[] = {
+ {MEDIA_BUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
+ {MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
+};
+
+static struct ov5640 *to_ov5640(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct ov5640, subdev);
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct ov5640_datafmt
+ *ov5640_find_datafmt(u32 code)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ov5640_colour_fmts); i++)
+ if (ov5640_colour_fmts[i].code == code)
+ return ov5640_colour_fmts + i;
+
+ return NULL;
+}
+
+static inline void ov5640_power_down(int enable)
+{
+ gpio_set_value_cansleep(pwn_gpio, enable);
+
+ msleep(2);
+}
+
+static inline void ov5640_reset(void)
+{
+ gpio_set_value_cansleep(pwn_gpio, 1);
+ gpio_set_value_cansleep(rst_gpio, 0);
+ msleep(5);
+
+ gpio_set_value_cansleep(pwn_gpio, 0);
+ msleep(1);
+
+ gpio_set_value_cansleep(rst_gpio, 1);
+ msleep(20);
+}
+
+static int ov5640_regulator_enable(struct device *dev)
+{
+ int ret = 0;
+
+ io_regulator = devm_regulator_get(dev, "DOVDD");
+ if (!IS_ERR(io_regulator)) {
+ regulator_set_voltage(io_regulator,
+ OV5640_VOLTAGE_DIGITAL_IO,
+ OV5640_VOLTAGE_DIGITAL_IO);
+ ret = regulator_enable(io_regulator);
+ if (ret) {
+ dev_err(dev, "set io voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set io voltage ok\n");
+ }
+ } else {
+ io_regulator = NULL;
+ dev_warn(dev, "cannot get io voltage\n");
+ }
+
+ core_regulator = devm_regulator_get(dev, "DVDD");
+ if (!IS_ERR(core_regulator)) {
+ regulator_set_voltage(core_regulator,
+ OV5640_VOLTAGE_DIGITAL_CORE,
+ OV5640_VOLTAGE_DIGITAL_CORE);
+ ret = regulator_enable(core_regulator);
+ if (ret) {
+ dev_err(dev, "set core voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set core voltage ok\n");
+ }
+ } else {
+ core_regulator = NULL;
+ dev_warn(dev, "cannot get core voltage\n");
+ }
+
+ analog_regulator = devm_regulator_get(dev, "AVDD");
+ if (!IS_ERR(analog_regulator)) {
+ regulator_set_voltage(analog_regulator,
+ OV5640_VOLTAGE_ANALOG,
+ OV5640_VOLTAGE_ANALOG);
+ ret = regulator_enable(analog_regulator);
+ if (ret) {
+ dev_err(dev, "set analog voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set analog voltage ok\n");
+ }
+ } else {
+ analog_regulator = NULL;
+ dev_warn(dev, "cannot get analog voltage\n");
+ }
+
+ return ret;
+}
+
+static s32 ov5640_write_reg(u16 reg, u8 val)
+{
+ u8 au8Buf[3] = {0};
+
+ au8Buf[0] = reg >> 8;
+ au8Buf[1] = reg & 0xff;
+ au8Buf[2] = val;
+
+ if (i2c_master_send(ov5640_data.i2c_client, au8Buf, 3) < 0) {
+ pr_err("%s:write reg error:reg=%x,val=%x\n",
+ __func__, reg, val);
+ return -1;
+ }
+
+ return 0;
+}
+
+static s32 ov5640_read_reg(u16 reg, u8 *val)
+{
+ u8 au8RegBuf[2] = {0};
+ u8 u8RdVal = 0;
+
+ au8RegBuf[0] = reg >> 8;
+ au8RegBuf[1] = reg & 0xff;
+
+ if (2 != i2c_master_send(ov5640_data.i2c_client, au8RegBuf, 2)) {
+ pr_err("%s:write reg error:reg=%x\n",
+ __func__, reg);
+ return -1;
+ }
+
+ if (1 != i2c_master_recv(ov5640_data.i2c_client, &u8RdVal, 1)) {
+ pr_err("%s:read reg error:reg=%x,val=%x\n",
+ __func__, reg, u8RdVal);
+ return -1;
+ }
+
+ *val = u8RdVal;
+
+ return u8RdVal;
+}
+
+static int ov5640_set_clk_rate(void)
+{
+ u32 tgt_xclk; /* target xclk */
+ int ret;
+
+ /* mclk */
+ tgt_xclk = ov5640_data.mclk;
+ tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX);
+ tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN);
+ ov5640_data.mclk = tgt_xclk;
+
+ pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000);
+ ret = clk_set_rate(ov5640_data.sensor_clk, ov5640_data.mclk);
+ if (ret < 0)
+ pr_debug("set rate filed, rate=%d\n", ov5640_data.mclk);
+ return ret;
+}
+
+/* download ov5640 settings to sensor through i2c */
+static int ov5640_download_firmware(struct reg_value *pModeSetting, s32 ArySize)
+{
+ register u32 Delay_ms = 0;
+ register u16 RegAddr = 0;
+ register u8 Mask = 0;
+ register u8 Val = 0;
+ u8 RegVal = 0;
+ int i, retval = 0;
+
+ for (i = 0; i < ArySize; ++i, ++pModeSetting) {
+ Delay_ms = pModeSetting->u32Delay_ms;
+ RegAddr = pModeSetting->u16RegAddr;
+ Val = pModeSetting->u8Val;
+ Mask = pModeSetting->u8Mask;
+
+ if (Mask) {
+ retval = ov5640_read_reg(RegAddr, &RegVal);
+ if (retval < 0)
+ goto err;
+
+ RegVal &= ~(u8)Mask;
+ Val &= Mask;
+ Val |= RegVal;
+ }
+
+ retval = ov5640_write_reg(RegAddr, Val);
+ if (retval < 0)
+ goto err;
+
+ if (Delay_ms)
+ msleep(Delay_ms);
+ }
+err:
+ return retval;
+}
+
+static void ov5640_soft_reset(void)
+{
+ /* sysclk from pad */
+ ov5640_write_reg(0x3103, 0x11);
+
+ /* software reset */
+ ov5640_write_reg(0x3008, 0x82);
+
+ /* delay at least 5ms */
+ msleep(10);
+}
+
+static int ov5640_config_init(void)
+{
+ struct reg_value *pModeSetting = NULL;
+ int ArySize = 0, retval = 0;
+
+ /* Configure ov5640 initial parm */
+ pModeSetting = ov5640_init_parm;
+ ArySize = ARRAY_SIZE(ov5640_init_parm);
+
+ retval = ov5640_download_firmware(pModeSetting, ArySize);
+ if (retval < 0)
+ return retval;
+
+ return 0;
+}
+
+static int ov5640_config_resolution(enum ov5640_mode mode)
+{
+ struct reg_value *pModeSetting = NULL;
+ int ArySize = 0, retval = 0;
+
+ if (mode < ov5640_mode_MIN || mode > ov5640_mode_MAX)
+ return -EINVAL;
+
+ if (mode == ov5640_mode_1080P_1920_1080) {
+ ov5640_write_reg(0x3709, 0x12);
+ ov5640_write_reg(0x3821, 0x06);
+ }
+
+ /* Configure ov5640 initial parm */
+ pModeSetting = ov5640_mode_info_data[mode].init_data_ptr;
+ ArySize = ov5640_mode_info_data[mode].init_data_size;
+
+ retval = ov5640_download_firmware(pModeSetting, ArySize);
+ if (retval < 0)
+ return retval;
+
+ return 0;
+}
+
+static int ov5640_config_others(enum ov5640_frame_rate rate,
+ enum ov5640_mode mode)
+{
+ struct reg_value *pModeSetting = NULL;
+ int ArySize = 0, retval = 0;
+
+ if (mode < ov5640_mode_MIN || mode > ov5640_mode_MAX)
+ return -EINVAL;
+
+ pModeSetting = ov5640_pll_info_data[rate][mode].init_data_ptr;
+ ArySize = ov5640_pll_info_data[rate][mode].init_data_size;
+ retval = ov5640_download_firmware(pModeSetting, ArySize);
+ if (retval < 0)
+ return retval;
+
+ /* Configure ov5640 initial parm */
+ pModeSetting = ov5640_config;
+ ArySize = ARRAY_SIZE(ov5640_config);
+ retval = ov5640_download_firmware(pModeSetting, ArySize);
+ if (retval < 0)
+ return retval;
+
+ return 0;
+}
+
+static void ov5640_start(void)
+{
+ ov5640_write_reg(0x3008, 0x02);
+ ov5640_write_reg(0x3008, 0x02);
+ msleep(1);
+}
+
+static int ov5640_change_mode(enum ov5640_frame_rate rate,
+ enum ov5640_mode mode)
+{
+ int retval;
+
+ if (mode == ov5640_mode_1080P_1920_1080 && rate != ov5640_15_fps) {
+ pr_warning("1080P only suppoert 15fps frame rate\n");
+ rate = ov5640_15_fps;
+ }
+
+ retval = ov5640_config_resolution(mode);
+ if (retval < 0) {
+ pr_err("%s config resolution fail\n", __func__);
+ return -EINVAL;
+ }
+
+ retval = ov5640_config_others(rate, mode);
+ if (retval < 0) {
+ pr_err("%s config others fail\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int init_device(void)
+{
+ int retval;
+
+ ov5640_soft_reset();
+ retval = ov5640_config_init();
+ if (retval < 0)
+ return retval;
+
+ retval = ov5640_config_resolution(ov5640_mode_VGA_640_480);
+ if (retval < 0)
+ return retval;
+
+ retval = ov5640_config_others(ov5640_30_fps, ov5640_mode_VGA_640_480);
+ if (retval < 0)
+ return retval;
+
+ ov5640_start();
+
+ return 0;
+}
+
+static void ov5640_stop(void)
+{
+ ov5640_write_reg(0x3008, 0x42);
+ msleep(1);
+}
+
+/*!
+ * ov5640_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @on: indicates power mode (on or off)
+ *
+ * Turns the power on or off, depending on the value of on and returns the
+ * appropriate error code.
+ */
+static int ov5640_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+
+ if (on)
+ clk_prepare_enable(ov5640_data.sensor_clk);
+ else
+ clk_disable_unprepare(ov5640_data.sensor_clk);
+
+ sensor->on = on;
+ return 0;
+}
+
+/*!
+ * ov5640_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 sub device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ov5640_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+ int ret = 0;
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cparm->capability = sensor->streamcap.capability;
+ cparm->timeperframe = sensor->streamcap.timeperframe;
+ cparm->capturemode = sensor->streamcap.capturemode;
+ ret = 0;
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ ret = -EINVAL;
+ break;
+
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * ov5460_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 sub device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible. If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ */
+static int ov5640_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+ u32 tgt_fps; /* target frames per secound */
+ enum ov5640_frame_rate frame_rate;
+ enum ov5640_mode mode = a->parm.capture.capturemode;
+ int ret = 0;
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ /* Check that the new frame rate is allowed. */
+ if ((timeperframe->numerator == 0) ||
+ (timeperframe->denominator == 0)) {
+ timeperframe->denominator = DEFAULT_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps > MAX_FPS) {
+ timeperframe->denominator = MAX_FPS;
+ timeperframe->numerator = 1;
+ } else if (tgt_fps < MIN_FPS) {
+ timeperframe->denominator = MIN_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ if (mode == ov5640_mode_1080P_1920_1080 && tgt_fps != 15) {
+ pr_warning("1080P only suppoert 15fps frame rate\n");
+ timeperframe->denominator = 15;
+ timeperframe->numerator = 1;
+ }
+
+ /* Actual frame rate we use */
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps == 30)
+ frame_rate = ov5640_30_fps;
+ else if (tgt_fps == 15)
+ frame_rate = ov5640_15_fps;
+ else {
+ pr_err(" The camera frame rate is not supported!\n");
+ goto error;
+ }
+
+ ret = ov5640_change_mode(frame_rate, mode);
+ if (ret < 0)
+ goto error;
+
+ sensor->streamcap.timeperframe = *timeperframe;
+ sensor->streamcap.capturemode = mode;
+ sensor->pix.width = ov5640_mode_info_data[mode].width;
+ sensor->pix.height = ov5640_mode_info_data[mode].height;
+
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ pr_debug(" type is not " \
+ "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n",
+ a->type);
+ ret = -EINVAL;
+ break;
+
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+error:
+ return ret;
+}
+
+static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+
+ if (enable)
+ ov5640_start();
+ else
+ ov5640_stop();
+
+ sensor->on = enable;
+ 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;
+ const struct ov5640_datafmt *fmt = ov5640_find_datafmt(mf->code);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+
+ if (format->pad)
+ return -EINVAL;
+
+ if (!fmt) {
+ mf->code = ov5640_colour_fmts[0].code;
+ mf->colorspace = ov5640_colour_fmts[0].colorspace;
+ }
+
+ mf->field = V4L2_FIELD_NONE;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+ return 0;
+
+ sensor->fmt = fmt;
+
+ 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 *sensor = to_ov5640(client);
+ /*const struct ov5640_datafmt *fmt = sensor->fmt;*/
+
+ if (format->pad)
+ return -EINVAL;
+
+ memset(mf, 0, sizeof(struct v4l2_mbus_framefmt));
+
+ mf->code = ov5640_colour_fmts[0].code;
+ mf->colorspace = ov5640_colour_fmts[0].colorspace;
+ mf->width = sensor->pix.width;
+ mf->height = sensor->pix.height;
+ mf->field = V4L2_FIELD_NONE;
+ mf->reserved[1] = 0;
+
+ dev_dbg(&client->dev, "%s code=0x%x, w/h=(%d,%d), colorspace=%d, field=%d\n",
+ __func__, mf->code, mf->width, mf->height, mf->colorspace, mf->field);
+
+ return 0;
+}
+
+static int ov5640_enum_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(ov5640_colour_fmts))
+ return -EINVAL;
+
+ code->code = ov5640_colour_fmts[code->index].code;
+ return 0;
+}
+
+/*!
+ * ov5640_enum_framesizes - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ov5640_enum_framesizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index > ov5640_mode_MAX)
+ return -EINVAL;
+
+ fse->max_width = ov5640_mode_info_data[fse->index].width;
+ fse->min_width = fse->max_width;
+ fse->max_height = ov5640_mode_info_data[fse->index].height;
+ fse->min_height = fse->max_height;
+ return 0;
+}
+
+/*!
+ * ov5640_enum_frameintervals - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMEINTERVALS ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ov5640_enum_frameintervals(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ int i, j, count;
+
+ if (fie->index < 0 || fie->index > ov5640_mode_MAX)
+ return -EINVAL;
+
+ if (fie->width == 0 || fie->height == 0 ||
+ fie->code == 0) {
+ pr_warning("Please assign pixel format, width and height.\n");
+ return -EINVAL;
+ }
+
+ fie->interval.numerator = 1;
+
+ count = 0;
+ for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
+ for (j = 0; j < (ov5640_mode_MAX + 1); j++) {
+ if (fie->width == ov5640_mode_info_data[j].width
+ && fie->height == ov5640_mode_info_data[j].height
+ && ov5640_mode_info_data[j].init_data_ptr != NULL) {
+ count++;
+ }
+ if (fie->index == (count - 1)) {
+ fie->interval.denominator = ov5640_framerates[i];
+ if (ov5640_mode_info_data[j].mode ==
+ ov5640_mode_1080P_1920_1080)
+ fie->interval.denominator = ov5640_framerates[0];
+ return 0;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int ov5640_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops ov5640_subdev_video_ops = {
+ .g_parm = ov5640_g_parm,
+ .s_parm = ov5640_s_parm,
+ .s_stream = ov5640_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ov5640_subdev_pad_ops = {
+ .enum_frame_size = ov5640_enum_framesizes,
+ .enum_frame_interval = ov5640_enum_frameintervals,
+ .enum_mbus_code = ov5640_enum_code,
+ .set_fmt = ov5640_set_fmt,
+ .get_fmt = ov5640_get_fmt,
+};
+
+static struct v4l2_subdev_core_ops ov5640_subdev_core_ops = {
+ .s_power = ov5640_s_power,
+};
+
+static struct v4l2_subdev_ops ov5640_subdev_ops = {
+ .core = &ov5640_subdev_core_ops,
+ .video = &ov5640_subdev_video_ops,
+ .pad = &ov5640_subdev_pad_ops,
+};
+
+static const struct media_entity_operations ov5640_sd_media_ops = {
+ .link_setup = ov5640_link_setup,
+};
+
+/*!
+ * ov5640 I2C probe function
+ *
+ * @param adapter struct i2c_adapter *
+ * @return Error code indicating success or failure
+ */
+static int ov5640_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pinctrl *pinctrl;
+ struct device *dev = &client->dev;
+ struct v4l2_subdev *sd;
+ int retval;
+ u8 chip_id_high, chip_id_low;
+
+ /* ov5640 pinctrl */
+ pinctrl = devm_pinctrl_get_select_default(dev);
+ if (IS_ERR(pinctrl)) {
+ dev_err(dev, "setup pinctrl failed\n");
+ return PTR_ERR(pinctrl);
+ }
+
+ /* request power down pin */
+ pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+ if (!gpio_is_valid(pwn_gpio)) {
+ dev_err(dev, "no sensor pwdn pin available\n");
+ return -ENODEV;
+ }
+ retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH,
+ "ov5640_pwdn");
+ if (retval < 0)
+ return retval;
+
+ /* request reset pin */
+ rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0);
+ if (!gpio_is_valid(rst_gpio)) {
+ dev_err(dev, "no sensor reset pin available\n");
+ devm_gpio_free(dev, rst_gpio);
+ return -EINVAL;
+ }
+ retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_LOW,
+ "ov5640_reset");
+ if (retval < 0) {
+ devm_gpio_free(dev, pwn_gpio);
+ return retval;
+ }
+
+ /* Set initial values for the sensor struct. */
+ memset(&ov5640_data, 0, sizeof(ov5640_data));
+ ov5640_data.sensor_clk = devm_clk_get(dev, "csi_mclk");
+ if (IS_ERR(ov5640_data.sensor_clk)) {
+ dev_err(dev, "get mclk failed\n");
+ devm_gpio_free(dev, pwn_gpio);
+ devm_gpio_free(dev, rst_gpio);
+ return PTR_ERR(ov5640_data.sensor_clk);
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk",
+ &ov5640_data.mclk);
+ if (retval) {
+ dev_err(dev, "mclk frequency is invalid\n");
+ return retval;
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk_source",
+ (u32 *) &(ov5640_data.mclk_source));
+ if (retval) {
+ dev_err(dev, "mclk_source invalid\n");
+ return retval;
+ }
+
+ retval = of_property_read_u32(dev->of_node, "csi_id",
+ &(ov5640_data.csi));
+ if (retval) {
+ dev_err(dev, "csi_id invalid\n");
+ return retval;
+ }
+
+ /* Set mclk rate before clk on */
+ ov5640_set_clk_rate();
+
+ retval = clk_prepare_enable(ov5640_data.sensor_clk);
+ if (retval < 0) {
+ dev_err(dev, "%s: enable sensor clk fail\n", __func__);
+ return -EINVAL;
+ }
+
+ ov5640_data.io_init = ov5640_reset;
+ ov5640_data.i2c_client = client;
+
+ ov5640_data.pix.pixelformat = V4L2_PIX_FMT_YVYU;
+ ov5640_data.pix.width = ov5640_mode_info_data[0].width;
+ ov5640_data.pix.height = ov5640_mode_info_data[0].height;
+ ov5640_data.streamcap.capability = V4L2_MODE_HIGHQUALITY |
+ V4L2_CAP_TIMEPERFRAME;
+ ov5640_data.streamcap.capturemode = 0;
+ ov5640_data.streamcap.timeperframe.denominator = DEFAULT_FPS;
+ ov5640_data.streamcap.timeperframe.numerator = 1;
+
+ ov5640_regulator_enable(&client->dev);
+
+ ov5640_reset();
+
+ retval = ov5640_read_reg(OV5640_CHIP_ID_HIGH_BYTE, &chip_id_high);
+ if (retval < 0 || chip_id_high != 0x56) {
+ clk_disable_unprepare(ov5640_data.sensor_clk);
+ pr_warning("camera ov5640 is not found\n");
+ return -ENODEV;
+ }
+ retval = ov5640_read_reg(OV5640_CHIP_ID_LOW_BYTE, &chip_id_low);
+ if (retval < 0 || chip_id_low != 0x40) {
+ clk_disable_unprepare(ov5640_data.sensor_clk);
+ pr_warning("camera ov5640 is not found\n");
+ return -ENODEV;
+ }
+
+ retval = init_device();
+ if (retval < 0) {
+ clk_disable_unprepare(ov5640_data.sensor_clk);
+ pr_warning("camera ov5640 init fail\n");
+ return -ENODEV;
+ }
+
+ sd = &ov5640_data.subdev;
+ v4l2_i2c_subdev_init(sd, client, &ov5640_subdev_ops);
+
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ov5640_data.pads[OV5640_SENS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ retval = media_entity_pads_init(&sd->entity, OV5640_SENS_PADS_NUM,
+ ov5640_data.pads);
+ sd->entity.ops = &ov5640_sd_media_ops;
+ if (retval < 0)
+ return retval;
+
+ retval = v4l2_async_register_subdev(sd);
+ if (retval < 0) {
+ dev_err(&client->dev,
+ "%s--Async register failed, ret=%d\n", __func__, retval);
+ media_entity_cleanup(&sd->entity);
+ }
+
+ clk_disable_unprepare(ov5640_data.sensor_clk);
+
+ pr_info("%s camera ov5640, is found\n", __func__);
+ return retval;
+}
+
+/*!
+ * ov5640 I2C detach function
+ *
+ * @param client struct i2c_client *
+ * @return Error code indicating success or failure
+ */
+static int ov5640_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_async_unregister_subdev(sd);
+
+ clk_unprepare(ov5640_data.sensor_clk);
+
+ ov5640_power_down(1);
+
+ if (analog_regulator)
+ regulator_disable(analog_regulator);
+
+ if (core_regulator)
+ regulator_disable(core_regulator);
+
+ if (io_regulator)
+ regulator_disable(io_regulator);
+
+ return 0;
+}
+
+module_i2c_driver(ov5640_i2c_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("OV5640 Camera Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("3.0");
+MODULE_ALIAS("CSI");
diff --git a/drivers/media/platform/mxc/capture/Kconfig b/drivers/media/platform/mxc/capture/Kconfig
new file mode 100644
index 000000000000..2aa4e1505735
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/Kconfig
@@ -0,0 +1,124 @@
+if VIDEO_MXC_CAPTURE
+
+config VIDEO_V4L2_MXC_INT_DEVICE
+ tristate
+
+config VIDEO_MXC_CSI_CAMERA
+ tristate "CSI camera support"
+ depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2
+ ---help---
+ This is the video4linux2 capture driver based on CSI module.
+
+config MXC_VADC
+ tristate "mxc VADC support"
+ depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2
+ ---help---
+ If you plan to use the VADC with your MXC system, say Y here.
+
+config MXC_MIPI_CSI
+ tristate "mxc mipi csi driver"
+ depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2
+ ---help---
+ This is a V4L2 driver for i.MX7D SoC MIPI-CSI2 receiver devices.
+
+menu "MXC Camera/V4L2 PRP Features support"
+config VIDEO_MXC_IPU_CAMERA
+ bool
+ select VIDEO_V4L2_MXC_INT_DEVICE
+ depends on VIDEO_MXC_CAPTURE && MXC_IPU
+ default y
+
+config MXC_CAMERA_OV5640
+ tristate "OmniVision ov5640 camera support"
+ depends on !VIDEO_MXC_EMMA_CAMERA && I2C
+ depends on VIDEO_V4L2_MXC_INT_DEVICE
+ ---help---
+ If you plan to use the ov5640 Camera with your MXC system, say Y here.
+
+config MXC_CAMERA_OV5640_V2
+ tristate "OmniVision ov5640 camera support"
+ depends on VIDEO_MXC_CAPTURE && I2C
+ ---help---
+ If you plan to use the ov5640 Camera with your MXC system, say Y here.
+
+config MXC_CAMERA_OV5642
+ tristate "OmniVision ov5642 camera support"
+ depends on !VIDEO_MXC_EMMA_CAMERA && I2C
+ depends on VIDEO_V4L2_MXC_INT_DEVICE
+ ---help---
+ If you plan to use the ov5642 Camera with your MXC system, say Y here.
+
+config MXC_CAMERA_OV5640_MIPI
+ tristate "OmniVision ov5640 camera support using mipi"
+ depends on !VIDEO_MXC_EMMA_CAMERA && I2C && MXC_MIPI_CSI2
+ depends on VIDEO_V4L2_MXC_INT_DEVICE
+ ---help---
+ If you plan to use the ov5640 Camera with mipi interface in your MXC system, say Y here.
+
+config MXC_CAMERA_OV5640_MIPI_V2
+ tristate "OmniVision ov5640 camera support using mipi"
+ depends on MXC_MIPI_CSI && I2C
+ ---help---
+ If you plan to use the ov5640 Camera with mipi interface in your MXC system, say Y here.
+
+config MXC_CAMERA_OV5647_MIPI
+ tristate "OmniVision ov5647 camera support using mipi"
+ depends on MXC_MIPI_CSI && I2C
+ ---help---
+ If you plan to use the ov5647 Camera with mipi interface in your MXC system, say Y here.
+
+config MXC_TVIN_ADV7180
+ tristate "Analog Device adv7180 TV Decoder Input support"
+ depends on !VIDEO_MXC_EMMA_CAMERA && I2C
+ depends on VIDEO_V4L2_MXC_INT_DEVICE
+ ---help---
+ If you plan to use the adv7180 video decoder with your MXC system, say Y here.
+
+choice
+ prompt "Select Overlay Rounting"
+ default MXC_IPU_DEVICE_QUEUE_SDC
+ depends on VIDEO_MXC_IPU_CAMERA && FB_MXC_SYNC_PANEL
+
+config MXC_IPU_DEVICE_QUEUE_SDC
+ tristate "Queue ipu device for overlay library"
+ depends on VIDEO_MXC_IPU_CAMERA
+ ---help---
+ Use case CSI->MEM->IPU DEVICE->SDC:
+ Images from sensor will be frist recieved in memory,then
+ queue to ipu device for processing if needed, and displaying
+ it on synchronous display with SDC use case.
+
+config MXC_IPU_PRP_VF_SDC
+ bool "Pre-Processor VF SDC library"
+ depends on VIDEO_MXC_IPU_CAMERA
+ ---help---
+ Use case PRP_VF_SDC:
+ Preprocessing image from smart sensor for viewfinder and
+ displaying it on synchronous display with SDC use case.
+ If SDC BG is selected, Rotation will not be supported.
+ CSI -> IC (PRP VF) -> MEM
+ MEM -> IC (ROT) -> MEM
+ MEM -> SDC (FG/BG)
+
+endchoice
+
+config MXC_IPU_PRP_ENC
+ tristate "Pre-processor Encoder library"
+ depends on VIDEO_MXC_IPU_CAMERA
+ default y
+ ---help---
+ Use case PRP_ENC:
+ Preprocessing image from smart sensor for encoder.
+ CSI -> IC (PRP ENC) -> MEM
+
+config MXC_IPU_CSI_ENC
+ tristate "IPU CSI Encoder library"
+ depends on VIDEO_MXC_IPU_CAMERA
+ default y
+ ---help---
+ Use case IPU_CSI_ENC:
+ Get raw image with CSI from smart sensor for encoder.
+ CSI -> MEM
+endmenu
+
+endif
diff --git a/drivers/media/platform/mxc/capture/Makefile b/drivers/media/platform/mxc/capture/Makefile
new file mode 100644
index 000000000000..e6e4b99f9435
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/Makefile
@@ -0,0 +1,38 @@
+ifeq ($(CONFIG_VIDEO_MXC_IPU_CAMERA),y)
+ obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc_v4l2_capture.o
+ obj-$(CONFIG_MXC_IPU_PRP_VF_SDC) += ipu_prp_vf_sdc.o ipu_prp_vf_sdc_bg.o
+ obj-$(CONFIG_MXC_IPU_DEVICE_QUEUE_SDC) += ipu_fg_overlay_sdc.o ipu_bg_overlay_sdc.o
+ obj-$(CONFIG_MXC_IPU_PRP_ENC) += ipu_prp_enc.o ipu_still.o
+ obj-$(CONFIG_MXC_IPU_CSI_ENC) += ipu_csi_enc.o ipu_still.o
+endif
+
+obj-$(CONFIG_VIDEO_MXC_CSI_CAMERA) += mx6s_capture.o
+obj-$(CONFIG_MXC_VADC) += mxc_vadc.o
+obj-$(CONFIG_MXC_MIPI_CSI) += mxc_mipi_csi.o
+
+# Used for iMX 6QDL
+ov5640_camera_int-objs := ov5640.o
+obj-$(CONFIG_MXC_CAMERA_OV5640) += ov5640_camera_int.o
+
+# Used for iMX 6UL/ULL/SX/SL/SLL
+ov5640_camera_v2-objs := ov5640_v2.o
+obj-$(CONFIG_MXC_CAMERA_OV5640_V2) += ov5640_camera_v2.o
+
+ov5642_camera-objs := ov5642.o
+obj-$(CONFIG_MXC_CAMERA_OV5642) += ov5642_camera.o
+
+# Used for iMX 6QDL/DQSCM
+ov5640_camera_mipi_int-objs := ov5640_mipi.o
+obj-$(CONFIG_MXC_CAMERA_OV5640_MIPI) += ov5640_camera_mipi_int.o
+
+# Used for iMX 7D
+ov5640_camera_mipi_v2-objs := ov5640_mipi_v2.o
+obj-$(CONFIG_MXC_CAMERA_OV5640_MIPI_V2) += ov5640_camera_mipi_v2.o
+
+ov5647_camera_mipi-objs := ov5647_mipi.o
+obj-$(CONFIG_MXC_CAMERA_OV5647_MIPI) += ov5647_camera_mipi.o
+
+adv7180_tvin-objs := adv7180.o
+obj-$(CONFIG_MXC_TVIN_ADV7180) += adv7180_tvin.o
+
+obj-$(CONFIG_VIDEO_V4L2_MXC_INT_DEVICE) += v4l2-int-device.o
diff --git a/drivers/media/platform/mxc/capture/adv7180.c b/drivers/media/platform/mxc/capture/adv7180.c
new file mode 100644
index 000000000000..abd615927a48
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/adv7180.c
@@ -0,0 +1,1380 @@
+/*
+ * Copyright 2005-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file adv7180.c
+ *
+ * @brief Analog Device ADV7180 video decoder functions
+ *
+ * @ingroup Camera
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-chip-ident.h>
+#include "v4l2-int-device.h"
+#include "mxc_v4l2_capture.h"
+
+#define ADV7180_VOLTAGE_ANALOG 1800000
+#define ADV7180_VOLTAGE_DIGITAL_CORE 1800000
+#define ADV7180_VOLTAGE_DIGITAL_IO 3300000
+#define ADV7180_VOLTAGE_PLL 1800000
+
+static struct regulator *dvddio_regulator;
+static struct regulator *dvdd_regulator;
+static struct regulator *avdd_regulator;
+static struct regulator *pvdd_regulator;
+static int pwn_gpio;
+
+static int adv7180_probe(struct i2c_client *adapter,
+ const struct i2c_device_id *id);
+static int adv7180_detach(struct i2c_client *client);
+
+static const struct i2c_device_id adv7180_id[] = {
+ {"adv7180", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, adv7180_id);
+
+static struct i2c_driver adv7180_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "adv7180",
+ },
+ .probe = adv7180_probe,
+ .remove = adv7180_detach,
+ .id_table = adv7180_id,
+};
+
+/*!
+ * Maintains the information on the current state of the sensor.
+ */
+struct sensor {
+ struct sensor_data sen;
+ v4l2_std_id std_id;
+} adv7180_data;
+
+
+/*! List of input video formats supported. The video formats is corresponding
+ * with v4l2 id in video_fmt_t
+ */
+typedef enum {
+ ADV7180_NTSC = 0, /*!< Locked on (M) NTSC video signal. */
+ ADV7180_PAL, /*!< (B, G, H, I, N)PAL video signal. */
+ ADV7180_NOT_LOCKED, /*!< Not locked on a signal. */
+} video_fmt_idx;
+
+/*! Number of video standards supported (including 'not locked' signal). */
+#define ADV7180_STD_MAX (ADV7180_PAL + 1)
+
+/*! Video format structure. */
+typedef struct {
+ int v4l2_id; /*!< Video for linux ID. */
+ char name[16]; /*!< Name (e.g., "NTSC", "PAL", etc.) */
+ u16 raw_width; /*!< Raw width. */
+ u16 raw_height; /*!< Raw height. */
+ u16 active_width; /*!< Active width. */
+ u16 active_height; /*!< Active height. */
+ int frame_rate; /*!< Frame rate. */
+} video_fmt_t;
+
+/*! Description of video formats supported.
+ *
+ * PAL: raw=720x625, active=720x576.
+ * NTSC: raw=720x525, active=720x480.
+ */
+static video_fmt_t video_fmts[] = {
+ { /*! NTSC */
+ .v4l2_id = V4L2_STD_NTSC,
+ .name = "NTSC",
+ .raw_width = 720, /* SENS_FRM_WIDTH */
+ .raw_height = 525, /* SENS_FRM_HEIGHT */
+ .active_width = 720, /* ACT_FRM_WIDTH plus 1 */
+ .active_height = 480, /* ACT_FRM_WIDTH plus 1 */
+ .frame_rate = 30,
+ },
+ { /*! (B, G, H, I, N) PAL */
+ .v4l2_id = V4L2_STD_PAL,
+ .name = "PAL",
+ .raw_width = 720,
+ .raw_height = 625,
+ .active_width = 720,
+ .active_height = 576,
+ .frame_rate = 25,
+ },
+ { /*! Unlocked standard */
+ .v4l2_id = V4L2_STD_ALL,
+ .name = "Autodetect",
+ .raw_width = 720,
+ .raw_height = 625,
+ .active_width = 720,
+ .active_height = 576,
+ .frame_rate = 0,
+ },
+};
+
+/*!* Standard index of ADV7180. */
+static video_fmt_idx video_idx = ADV7180_PAL;
+
+/*! @brief This mutex is used to provide mutual exclusion.
+ *
+ * Create a mutex that can be used to provide mutually exclusive
+ * read/write access to the globally accessible data structures
+ * and variables that were defined above.
+ */
+static DEFINE_MUTEX(mutex);
+
+#define IF_NAME "adv7180"
+#define ADV7180_INPUT_CTL 0x00 /* Input Control */
+#define ADV7180_STATUS_1 0x10 /* Status #1 */
+#define ADV7180_BRIGHTNESS 0x0a /* Brightness */
+#define ADV7180_IDENT 0x11 /* IDENT */
+#define ADV7180_VSYNC_FIELD_CTL_1 0x31 /* VSYNC Field Control #1 */
+#define ADV7180_MANUAL_WIN_CTL 0x3d /* Manual Window Control */
+#define ADV7180_SD_SATURATION_CB 0xe3 /* SD Saturation Cb */
+#define ADV7180_SD_SATURATION_CR 0xe4 /* SD Saturation Cr */
+#define ADV7180_PWR_MNG 0x0f /* Power Management */
+
+/* supported controls */
+/* This hasn't been fully implemented yet.
+ * This is how it should work, though. */
+static struct v4l2_queryctrl adv7180_qctrl[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0, /* check this value */
+ .maximum = 255, /* check this value */
+ .step = 1, /* check this value */
+ .default_value = 127, /* check this value */
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0, /* check this value */
+ .maximum = 255, /* check this value */
+ .step = 0x1, /* check this value */
+ .default_value = 127, /* check this value */
+ .flags = 0,
+ }
+};
+
+static inline void adv7180_power_down(int enable)
+{
+ gpio_set_value_cansleep(pwn_gpio, !enable);
+ msleep(2);
+}
+
+static int adv7180_regulator_enable(struct device *dev)
+{
+ int ret = 0;
+
+ dvddio_regulator = devm_regulator_get(dev, "DOVDD");
+
+ if (!IS_ERR(dvddio_regulator)) {
+ regulator_set_voltage(dvddio_regulator,
+ ADV7180_VOLTAGE_DIGITAL_IO,
+ ADV7180_VOLTAGE_DIGITAL_IO);
+ ret = regulator_enable(dvddio_regulator);
+ if (ret) {
+ dev_err(dev, "set io voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set io voltage ok\n");
+ }
+ } else {
+ dev_warn(dev, "cannot get io voltage\n");
+ }
+
+ dvdd_regulator = devm_regulator_get(dev, "DVDD");
+ if (!IS_ERR(dvdd_regulator)) {
+ regulator_set_voltage(dvdd_regulator,
+ ADV7180_VOLTAGE_DIGITAL_CORE,
+ ADV7180_VOLTAGE_DIGITAL_CORE);
+ ret = regulator_enable(dvdd_regulator);
+ if (ret) {
+ dev_err(dev, "set core voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set core voltage ok\n");
+ }
+ } else {
+ dev_warn(dev, "cannot get core voltage\n");
+ }
+
+ avdd_regulator = devm_regulator_get(dev, "AVDD");
+ if (!IS_ERR(avdd_regulator)) {
+ regulator_set_voltage(avdd_regulator,
+ ADV7180_VOLTAGE_ANALOG,
+ ADV7180_VOLTAGE_ANALOG);
+ ret = regulator_enable(avdd_regulator);
+ if (ret) {
+ dev_err(dev, "set analog voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set analog voltage ok\n");
+ }
+ } else {
+ dev_warn(dev, "cannot get analog voltage\n");
+ }
+
+ pvdd_regulator = devm_regulator_get(dev, "PVDD");
+ if (!IS_ERR(pvdd_regulator)) {
+ regulator_set_voltage(pvdd_regulator,
+ ADV7180_VOLTAGE_PLL,
+ ADV7180_VOLTAGE_PLL);
+ ret = regulator_enable(pvdd_regulator);
+ if (ret) {
+ dev_err(dev, "set pll voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set pll voltage ok\n");
+ }
+ } else {
+ dev_warn(dev, "cannot get pll voltage\n");
+ }
+
+ return ret;
+}
+
+
+/***********************************************************************
+ * I2C transfert.
+ ***********************************************************************/
+
+/*! Read one register from a ADV7180 i2c slave device.
+ *
+ * @param *reg register in the device we wish to access.
+ *
+ * @return 0 if success, an error code otherwise.
+ */
+static inline int adv7180_read(u8 reg)
+{
+ int val;
+
+ val = i2c_smbus_read_byte_data(adv7180_data.sen.i2c_client, reg);
+ if (val < 0) {
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ "%s:read reg error: reg=%2x\n", __func__, reg);
+ return -1;
+ }
+ return val;
+}
+
+/*! Write one register of a ADV7180 i2c slave device.
+ *
+ * @param *reg register in the device we wish to access.
+ *
+ * @return 0 if success, an error code otherwise.
+ */
+static int adv7180_write_reg(u8 reg, u8 val)
+{
+ s32 ret;
+
+ ret = i2c_smbus_write_byte_data(adv7180_data.sen.i2c_client, reg, val);
+ if (ret < 0) {
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ "%s:write reg error:reg=%2x,val=%2x\n", __func__,
+ reg, val);
+ return -1;
+ }
+ return 0;
+}
+
+/***********************************************************************
+ * mxc_v4l2_capture interface.
+ ***********************************************************************/
+
+/*!
+ * Return attributes of current video standard.
+ * Since this device autodetects the current standard, this function also
+ * sets the values that need to be changed if the standard changes.
+ * There is no set std equivalent function.
+ *
+ * @return None.
+ */
+static void adv7180_get_std(v4l2_std_id *std)
+{
+ int status_1, standard, idx;
+ bool locked;
+
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180_get_std\n");
+
+ status_1 = adv7180_read(ADV7180_STATUS_1);
+ locked = status_1 & 0x1;
+ standard = status_1 & 0x70;
+
+ mutex_lock(&mutex);
+ *std = V4L2_STD_ALL;
+ idx = ADV7180_NOT_LOCKED;
+ if (locked) {
+ if (standard == 0x40) {
+ *std = V4L2_STD_PAL;
+ idx = ADV7180_PAL;
+ } else if (standard == 0) {
+ *std = V4L2_STD_NTSC;
+ idx = ADV7180_NTSC;
+ }
+ }
+ mutex_unlock(&mutex);
+
+ /* This assumes autodetect which this device uses. */
+ if (*std != adv7180_data.std_id) {
+ video_idx = idx;
+ adv7180_data.std_id = *std;
+ adv7180_data.sen.pix.width = video_fmts[video_idx].raw_width;
+ adv7180_data.sen.pix.height = video_fmts[video_idx].raw_height;
+ }
+}
+
+/***********************************************************************
+ * IOCTL Functions from v4l2_int_ioctl_desc.
+ ***********************************************************************/
+
+/*!
+ * ioctl_g_ifparm - V4L2 sensor interface handler for vidioc_int_g_ifparm_num
+ * s: pointer to standard V4L2 device structure
+ * p: pointer to standard V4L2 vidioc_int_g_ifparm_num ioctl structure
+ *
+ * Gets slave interface parameters.
+ * Calculates the required xclk value to support the requested
+ * clock parameters in p. This value is returned in the p
+ * parameter.
+ *
+ * vidioc_int_g_ifparm returns platform-specific information about the
+ * interface settings used by the sensor.
+ *
+ * Called on open.
+ */
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_g_ifparm\n");
+
+ if (s == NULL) {
+ pr_err(" ERROR!! no slave device set!\n");
+ return -1;
+ }
+
+ /* Initialize structure to 0s then set any non-0 values. */
+ memset(p, 0, sizeof(*p));
+ p->if_type = V4L2_IF_TYPE_BT656; /* This is the only possibility. */
+ p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT;
+ p->u.bt656.nobt_hs_inv = 1;
+ p->u.bt656.bt_sync_correct = 1;
+
+ /* ADV7180 has a dedicated clock so no clock settings needed. */
+
+ return 0;
+}
+
+/*!
+ * Sets the camera power.
+ *
+ * s pointer to the camera device
+ * on if 1, power is to be turned on. 0 means power is to be turned off
+ *
+ * ioctl_s_power - V4L2 sensor interface handler for vidioc_int_s_power_num
+ * @s: pointer to standard V4L2 device structure
+ * @on: power state to which device is to be set
+ *
+ * Sets devices power state to requrested state, if possible.
+ * This is called on open, close, suspend and resume.
+ */
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
+{
+ struct sensor *sensor = s->priv;
+
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_s_power\n");
+
+ if (on && !sensor->sen.on) {
+ if (adv7180_write_reg(ADV7180_PWR_MNG, 0x04) != 0)
+ return -EIO;
+
+ /*
+ * FIXME:Additional 400ms to wait the chip to be stable?
+ * This is a workaround for preview scrolling issue.
+ */
+ msleep(400);
+ } else if (!on && sensor->sen.on) {
+ if (adv7180_write_reg(ADV7180_PWR_MNG, 0x24) != 0)
+ return -EIO;
+ }
+
+ sensor->sen.on = on;
+
+ return 0;
+}
+
+/*!
+ * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+ struct sensor *sensor = s->priv;
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_g_parm\n");
+
+ switch (a->type) {
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ pr_debug(" type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cparm->capability = sensor->sen.streamcap.capability;
+ cparm->timeperframe = sensor->sen.streamcap.timeperframe;
+ cparm->capturemode = sensor->sen.streamcap.capturemode;
+ break;
+
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ break;
+
+ default:
+ pr_debug("ioctl_g_parm:type is unknown %d\n", a->type);
+ break;
+ }
+
+ return 0;
+}
+
+/*!
+ * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible. If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ *
+ * This driver cannot change these settings.
+ */
+static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_s_parm\n");
+
+ switch (a->type) {
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ break;
+
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ break;
+ }
+
+ return 0;
+}
+
+/*!
+ * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 v4l2_format structure
+ *
+ * Returns the sensor's current pixel format in the v4l2_format
+ * parameter.
+ */
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+{
+ struct sensor *sensor = s->priv;
+
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_g_fmt_cap\n");
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ pr_debug(" Returning size of %dx%d\n",
+ sensor->sen.pix.width, sensor->sen.pix.height);
+ f->fmt.pix = sensor->sen.pix;
+ break;
+
+ case V4L2_BUF_TYPE_PRIVATE: {
+ v4l2_std_id std;
+ adv7180_get_std(&std);
+ f->fmt.pix.pixelformat = (u32)std;
+ }
+ break;
+
+ default:
+ f->fmt.pix = sensor->sen.pix;
+ break;
+ }
+
+ return 0;
+}
+
+/*!
+ * ioctl_queryctrl - V4L2 sensor interface handler for VIDIOC_QUERYCTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @qc: standard V4L2 VIDIOC_QUERYCTRL ioctl structure
+ *
+ * If the requested control is supported, returns the control information
+ * from the video_control[] array. Otherwise, returns -EINVAL if the
+ * control is not supported.
+ */
+static int ioctl_queryctrl(struct v4l2_int_device *s,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_queryctrl\n");
+
+ for (i = 0; i < ARRAY_SIZE(adv7180_qctrl); i++)
+ if (qc->id && qc->id == adv7180_qctrl[i].id) {
+ memcpy(qc, &(adv7180_qctrl[i]),
+ sizeof(*qc));
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/*!
+ * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure
+ *
+ * If the requested control is supported, returns the control's current
+ * value from the video_control[] array. Otherwise, returns -EINVAL
+ * if the control is not supported.
+ */
+static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
+{
+ int ret = 0;
+ int sat = 0;
+
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_g_ctrl\n");
+
+ switch (vc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_BRIGHTNESS\n");
+ adv7180_data.sen.brightness = adv7180_read(ADV7180_BRIGHTNESS);
+ vc->value = adv7180_data.sen.brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_CONTRAST\n");
+ vc->value = adv7180_data.sen.contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_SATURATION\n");
+ sat = adv7180_read(ADV7180_SD_SATURATION_CB);
+ adv7180_data.sen.saturation = sat;
+ vc->value = adv7180_data.sen.saturation;
+ break;
+ case V4L2_CID_HUE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_HUE\n");
+ vc->value = adv7180_data.sen.hue;
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_AUTO_WHITE_BALANCE\n");
+ break;
+ case V4L2_CID_DO_WHITE_BALANCE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_DO_WHITE_BALANCE\n");
+ break;
+ case V4L2_CID_RED_BALANCE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_RED_BALANCE\n");
+ vc->value = adv7180_data.sen.red;
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_BLUE_BALANCE\n");
+ vc->value = adv7180_data.sen.blue;
+ break;
+ case V4L2_CID_GAMMA:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_GAMMA\n");
+ break;
+ case V4L2_CID_EXPOSURE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_EXPOSURE\n");
+ vc->value = adv7180_data.sen.ae_mode;
+ break;
+ case V4L2_CID_AUTOGAIN:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_AUTOGAIN\n");
+ break;
+ case V4L2_CID_GAIN:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_GAIN\n");
+ break;
+ case V4L2_CID_HFLIP:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_HFLIP\n");
+ break;
+ case V4L2_CID_VFLIP:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_VFLIP\n");
+ break;
+ default:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " Default case\n");
+ vc->value = 0;
+ ret = -EPERM;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure
+ *
+ * If the requested control is supported, sets the control's current
+ * value in HW (and updates the video_control[] array). Otherwise,
+ * returns -EINVAL if the control is not supported.
+ */
+static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
+{
+ int retval = 0;
+ u8 tmp;
+
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_s_ctrl\n");
+
+ switch (vc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_BRIGHTNESS\n");
+ tmp = vc->value;
+ adv7180_write_reg(ADV7180_BRIGHTNESS, tmp);
+ adv7180_data.sen.brightness = vc->value;
+ break;
+ case V4L2_CID_CONTRAST:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_CONTRAST\n");
+ break;
+ case V4L2_CID_SATURATION:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_SATURATION\n");
+ tmp = vc->value;
+ adv7180_write_reg(ADV7180_SD_SATURATION_CB, tmp);
+ adv7180_write_reg(ADV7180_SD_SATURATION_CR, tmp);
+ adv7180_data.sen.saturation = vc->value;
+ break;
+ case V4L2_CID_HUE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_HUE\n");
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_AUTO_WHITE_BALANCE\n");
+ break;
+ case V4L2_CID_DO_WHITE_BALANCE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_DO_WHITE_BALANCE\n");
+ break;
+ case V4L2_CID_RED_BALANCE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_RED_BALANCE\n");
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_BLUE_BALANCE\n");
+ break;
+ case V4L2_CID_GAMMA:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_GAMMA\n");
+ break;
+ case V4L2_CID_EXPOSURE:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_EXPOSURE\n");
+ break;
+ case V4L2_CID_AUTOGAIN:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_AUTOGAIN\n");
+ break;
+ case V4L2_CID_GAIN:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_GAIN\n");
+ break;
+ case V4L2_CID_HFLIP:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_HFLIP\n");
+ break;
+ case V4L2_CID_VFLIP:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " V4L2_CID_VFLIP\n");
+ break;
+ default:
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ " Default case\n");
+ retval = -EPERM;
+ break;
+ }
+
+ return retval;
+}
+
+/*!
+ * ioctl_enum_framesizes - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ioctl_enum_framesizes(struct v4l2_int_device *s,
+ struct v4l2_frmsizeenum *fsize)
+{
+ if (fsize->index >= 1)
+ return -EINVAL;
+
+ fsize->discrete.width = video_fmts[video_idx].active_width;
+ fsize->discrete.height = video_fmts[video_idx].active_height;
+
+ return 0;
+}
+
+/*!
+ * ioctl_enum_frameintervals - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMEINTERVALS ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ioctl_enum_frameintervals(struct v4l2_int_device *s,
+ struct v4l2_frmivalenum *fival)
+{
+ video_fmt_t fmt;
+ int i;
+
+ if (fival->index != 0)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(video_fmts) - 1; i++) {
+ fmt = video_fmts[i];
+ if (fival->width == fmt.active_width &&
+ fival->height == fmt.active_height) {
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->discrete.numerator = 1;
+ fival->discrete.denominator = fmt.frame_rate;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/*!
+ * ioctl_g_chip_ident - V4L2 sensor interface handler for
+ * VIDIOC_DBG_G_CHIP_IDENT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @id: pointer to int
+ *
+ * Return 0.
+ */
+static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id)
+{
+ ((struct v4l2_dbg_chip_ident *)id)->match.type =
+ V4L2_CHIP_MATCH_I2C_DRIVER;
+ strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name,
+ "adv7180_decoder");
+ ((struct v4l2_dbg_chip_ident *)id)->ident = V4L2_IDENT_ADV7180;
+
+ return 0;
+}
+
+/*!
+ * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT
+ * @s: pointer to standard V4L2 device structure
+ */
+static int ioctl_init(struct v4l2_int_device *s)
+{
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_init\n");
+ return 0;
+}
+
+/*!
+ * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialise the device when slave attaches to the master.
+ */
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_dev_init\n");
+ return 0;
+}
+
+/*!
+ * This structure defines all the ioctls for this module.
+ */
+static struct v4l2_int_ioctl_desc adv7180_ioctl_desc[] = {
+
+ {vidioc_int_dev_init_num, (v4l2_int_ioctl_func*)ioctl_dev_init},
+
+ /*!
+ * Delinitialise the dev. at slave detach.
+ * The complement of ioctl_dev_init.
+ */
+/* {vidioc_int_dev_exit_num, (v4l2_int_ioctl_func *)ioctl_dev_exit}, */
+
+ {vidioc_int_s_power_num, (v4l2_int_ioctl_func*)ioctl_s_power},
+ {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func*)ioctl_g_ifparm},
+/* {vidioc_int_g_needs_reset_num,
+ (v4l2_int_ioctl_func *)ioctl_g_needs_reset}, */
+/* {vidioc_int_reset_num, (v4l2_int_ioctl_func *)ioctl_reset}, */
+ {vidioc_int_init_num, (v4l2_int_ioctl_func*)ioctl_init},
+
+ /*!
+ * VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type.
+ */
+/* {vidioc_int_enum_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap}, */
+
+ /*!
+ * VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type.
+ * This ioctl is used to negotiate the image capture size and
+ * pixel format without actually making it take effect.
+ */
+/* {vidioc_int_try_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_try_fmt_cap}, */
+
+ {vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func*)ioctl_g_fmt_cap},
+
+ /*!
+ * If the requested format is supported, configures the HW to use that
+ * format, returns error code if format not supported or HW can't be
+ * correctly configured.
+ */
+/* {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_fmt_cap}, */
+
+ {vidioc_int_g_parm_num, (v4l2_int_ioctl_func*)ioctl_g_parm},
+ {vidioc_int_s_parm_num, (v4l2_int_ioctl_func*)ioctl_s_parm},
+ {vidioc_int_queryctrl_num, (v4l2_int_ioctl_func*)ioctl_queryctrl},
+ {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func*)ioctl_g_ctrl},
+ {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func*)ioctl_s_ctrl},
+ {vidioc_int_enum_framesizes_num,
+ (v4l2_int_ioctl_func *)ioctl_enum_framesizes},
+ {vidioc_int_enum_frameintervals_num,
+ (v4l2_int_ioctl_func *)
+ ioctl_enum_frameintervals},
+ {vidioc_int_g_chip_ident_num,
+ (v4l2_int_ioctl_func *)ioctl_g_chip_ident},
+};
+
+static struct v4l2_int_slave adv7180_slave = {
+ .ioctls = adv7180_ioctl_desc,
+ .num_ioctls = ARRAY_SIZE(adv7180_ioctl_desc),
+};
+
+static struct v4l2_int_device adv7180_int_device = {
+ .module = THIS_MODULE,
+ .name = "adv7180",
+ .type = v4l2_int_type_slave,
+ .u = {
+ .slave = &adv7180_slave,
+ },
+};
+
+
+/***********************************************************************
+ * I2C client and driver.
+ ***********************************************************************/
+
+/*! ADV7180 Reset function.
+ *
+ * @return None.
+ */
+static void adv7180_hard_reset(bool cvbs)
+{
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ "In adv7180:adv7180_hard_reset\n");
+
+ if (cvbs) {
+ /* Set CVBS input on AIN1 */
+ adv7180_write_reg(ADV7180_INPUT_CTL, 0x00);
+ } else {
+ /*
+ * Set YPbPr input on AIN1,4,5 and normal
+ * operations(autodection of all stds).
+ */
+ adv7180_write_reg(ADV7180_INPUT_CTL, 0x09);
+ }
+
+ /* Datasheet recommends */
+ adv7180_write_reg(0x01, 0xc8);
+ adv7180_write_reg(0x02, 0x04);
+ adv7180_write_reg(0x03, 0x00);
+ adv7180_write_reg(0x04, 0x45);
+ adv7180_write_reg(0x05, 0x00);
+ adv7180_write_reg(0x06, 0x02);
+ adv7180_write_reg(0x07, 0x7F);
+ adv7180_write_reg(0x08, 0x80);
+ adv7180_write_reg(0x0A, 0x00);
+ adv7180_write_reg(0x0B, 0x00);
+ adv7180_write_reg(0x0C, 0x36);
+ adv7180_write_reg(0x0D, 0x7C);
+ adv7180_write_reg(0x0E, 0x00);
+ adv7180_write_reg(0x0F, 0x00);
+ adv7180_write_reg(0x13, 0x00);
+ adv7180_write_reg(0x14, 0x12);
+ adv7180_write_reg(0x15, 0x00);
+ adv7180_write_reg(0x16, 0x00);
+ adv7180_write_reg(0x17, 0x01);
+ adv7180_write_reg(0x18, 0x93);
+ adv7180_write_reg(0xF1, 0x19);
+ adv7180_write_reg(0x1A, 0x00);
+ adv7180_write_reg(0x1B, 0x00);
+ adv7180_write_reg(0x1C, 0x00);
+ adv7180_write_reg(0x1D, 0x40);
+ adv7180_write_reg(0x1E, 0x00);
+ adv7180_write_reg(0x1F, 0x00);
+ adv7180_write_reg(0x20, 0x00);
+ adv7180_write_reg(0x21, 0x00);
+ adv7180_write_reg(0x22, 0x00);
+ adv7180_write_reg(0x23, 0xC0);
+ adv7180_write_reg(0x24, 0x00);
+ adv7180_write_reg(0x25, 0x00);
+ adv7180_write_reg(0x26, 0x00);
+ adv7180_write_reg(0x27, 0x58);
+ adv7180_write_reg(0x28, 0x00);
+ adv7180_write_reg(0x29, 0x00);
+ adv7180_write_reg(0x2A, 0x00);
+ adv7180_write_reg(0x2B, 0xE1);
+ adv7180_write_reg(0x2C, 0xAE);
+ adv7180_write_reg(0x2D, 0xF4);
+ adv7180_write_reg(0x2E, 0x00);
+ adv7180_write_reg(0x2F, 0xF0);
+ adv7180_write_reg(0x30, 0x00);
+ adv7180_write_reg(0x31, 0x12);
+ adv7180_write_reg(0x32, 0x41);
+ adv7180_write_reg(0x33, 0x84);
+ adv7180_write_reg(0x34, 0x00);
+ adv7180_write_reg(0x35, 0x02);
+ adv7180_write_reg(0x36, 0x00);
+ adv7180_write_reg(0x37, 0x01);
+ adv7180_write_reg(0x38, 0x80);
+ adv7180_write_reg(0x39, 0xC0);
+ adv7180_write_reg(0x3A, 0x10);
+ adv7180_write_reg(0x3B, 0x05);
+ adv7180_write_reg(0x3C, 0x58);
+ adv7180_write_reg(0x3D, 0xB2);
+ adv7180_write_reg(0x3E, 0x64);
+ adv7180_write_reg(0x3F, 0xE4);
+ adv7180_write_reg(0x40, 0x90);
+ adv7180_write_reg(0x41, 0x01);
+ adv7180_write_reg(0x42, 0x7E);
+ adv7180_write_reg(0x43, 0xA4);
+ adv7180_write_reg(0x44, 0xFF);
+ adv7180_write_reg(0x45, 0xB6);
+ adv7180_write_reg(0x46, 0x12);
+ adv7180_write_reg(0x48, 0x00);
+ adv7180_write_reg(0x49, 0x00);
+ adv7180_write_reg(0x4A, 0x00);
+ adv7180_write_reg(0x4B, 0x00);
+ adv7180_write_reg(0x4C, 0x00);
+ adv7180_write_reg(0x4D, 0xEF);
+ adv7180_write_reg(0x4E, 0x08);
+ adv7180_write_reg(0x4F, 0x08);
+ adv7180_write_reg(0x50, 0x08);
+ adv7180_write_reg(0x51, 0x24);
+ adv7180_write_reg(0x52, 0x0B);
+ adv7180_write_reg(0x53, 0x4E);
+ adv7180_write_reg(0x54, 0x80);
+ adv7180_write_reg(0x55, 0x00);
+ adv7180_write_reg(0x56, 0x10);
+ adv7180_write_reg(0x57, 0x00);
+ adv7180_write_reg(0x58, 0x00);
+ adv7180_write_reg(0x59, 0x00);
+ adv7180_write_reg(0x5A, 0x00);
+ adv7180_write_reg(0x5B, 0x00);
+ adv7180_write_reg(0x5C, 0x00);
+ adv7180_write_reg(0x5D, 0x00);
+ adv7180_write_reg(0x5E, 0x00);
+ adv7180_write_reg(0x5F, 0x00);
+ adv7180_write_reg(0x60, 0x00);
+ adv7180_write_reg(0x61, 0x00);
+ adv7180_write_reg(0x62, 0x20);
+ adv7180_write_reg(0x63, 0x00);
+ adv7180_write_reg(0x64, 0x00);
+ adv7180_write_reg(0x65, 0x00);
+ adv7180_write_reg(0x66, 0x00);
+ adv7180_write_reg(0x67, 0x03);
+ adv7180_write_reg(0x68, 0x01);
+ adv7180_write_reg(0x69, 0x00);
+ adv7180_write_reg(0x6A, 0x00);
+ adv7180_write_reg(0x6B, 0xC0);
+ adv7180_write_reg(0x6C, 0x00);
+ adv7180_write_reg(0x6D, 0x00);
+ adv7180_write_reg(0x6E, 0x00);
+ adv7180_write_reg(0x6F, 0x00);
+ adv7180_write_reg(0x70, 0x00);
+ adv7180_write_reg(0x71, 0x00);
+ adv7180_write_reg(0x72, 0x00);
+ adv7180_write_reg(0x73, 0x10);
+ adv7180_write_reg(0x74, 0x04);
+ adv7180_write_reg(0x75, 0x01);
+ adv7180_write_reg(0x76, 0x00);
+ adv7180_write_reg(0x77, 0x3F);
+ adv7180_write_reg(0x78, 0xFF);
+ adv7180_write_reg(0x79, 0xFF);
+ adv7180_write_reg(0x7A, 0xFF);
+ adv7180_write_reg(0x7B, 0x1E);
+ adv7180_write_reg(0x7C, 0xC0);
+ adv7180_write_reg(0x7D, 0x00);
+ adv7180_write_reg(0x7E, 0x00);
+ adv7180_write_reg(0x7F, 0x00);
+ adv7180_write_reg(0x80, 0x00);
+ adv7180_write_reg(0x81, 0xC0);
+ adv7180_write_reg(0x82, 0x04);
+ adv7180_write_reg(0x83, 0x00);
+ adv7180_write_reg(0x84, 0x0C);
+ adv7180_write_reg(0x85, 0x02);
+ adv7180_write_reg(0x86, 0x03);
+ adv7180_write_reg(0x87, 0x63);
+ adv7180_write_reg(0x88, 0x5A);
+ adv7180_write_reg(0x89, 0x08);
+ adv7180_write_reg(0x8A, 0x10);
+ adv7180_write_reg(0x8B, 0x00);
+ adv7180_write_reg(0x8C, 0x40);
+ adv7180_write_reg(0x8D, 0x00);
+ adv7180_write_reg(0x8E, 0x40);
+ adv7180_write_reg(0x8F, 0x00);
+ adv7180_write_reg(0x90, 0x00);
+ adv7180_write_reg(0x91, 0x50);
+ adv7180_write_reg(0x92, 0x00);
+ adv7180_write_reg(0x93, 0x00);
+ adv7180_write_reg(0x94, 0x00);
+ adv7180_write_reg(0x95, 0x00);
+ adv7180_write_reg(0x96, 0x00);
+ adv7180_write_reg(0x97, 0xF0);
+ adv7180_write_reg(0x98, 0x00);
+ adv7180_write_reg(0x99, 0x00);
+ adv7180_write_reg(0x9A, 0x00);
+ adv7180_write_reg(0x9B, 0x00);
+ adv7180_write_reg(0x9C, 0x00);
+ adv7180_write_reg(0x9D, 0x00);
+ adv7180_write_reg(0x9E, 0x00);
+ adv7180_write_reg(0x9F, 0x00);
+ adv7180_write_reg(0xA0, 0x00);
+ adv7180_write_reg(0xA1, 0x00);
+ adv7180_write_reg(0xA2, 0x00);
+ adv7180_write_reg(0xA3, 0x00);
+ adv7180_write_reg(0xA4, 0x00);
+ adv7180_write_reg(0xA5, 0x00);
+ adv7180_write_reg(0xA6, 0x00);
+ adv7180_write_reg(0xA7, 0x00);
+ adv7180_write_reg(0xA8, 0x00);
+ adv7180_write_reg(0xA9, 0x00);
+ adv7180_write_reg(0xAA, 0x00);
+ adv7180_write_reg(0xAB, 0x00);
+ adv7180_write_reg(0xAC, 0x00);
+ adv7180_write_reg(0xAD, 0x00);
+ adv7180_write_reg(0xAE, 0x60);
+ adv7180_write_reg(0xAF, 0x00);
+ adv7180_write_reg(0xB0, 0x00);
+ adv7180_write_reg(0xB1, 0x60);
+ adv7180_write_reg(0xB2, 0x1C);
+ adv7180_write_reg(0xB3, 0x54);
+ adv7180_write_reg(0xB4, 0x00);
+ adv7180_write_reg(0xB5, 0x00);
+ adv7180_write_reg(0xB6, 0x00);
+ adv7180_write_reg(0xB7, 0x13);
+ adv7180_write_reg(0xB8, 0x03);
+ adv7180_write_reg(0xB9, 0x33);
+ adv7180_write_reg(0xBF, 0x02);
+ adv7180_write_reg(0xC0, 0x00);
+ adv7180_write_reg(0xC1, 0x00);
+ adv7180_write_reg(0xC2, 0x00);
+ adv7180_write_reg(0xC3, 0x00);
+ adv7180_write_reg(0xC4, 0x00);
+ adv7180_write_reg(0xC5, 0x81);
+ adv7180_write_reg(0xC6, 0x00);
+ adv7180_write_reg(0xC7, 0x00);
+ adv7180_write_reg(0xC8, 0x00);
+ adv7180_write_reg(0xC9, 0x04);
+ adv7180_write_reg(0xCC, 0x69);
+ adv7180_write_reg(0xCD, 0x00);
+ adv7180_write_reg(0xCE, 0x01);
+ adv7180_write_reg(0xCF, 0xB4);
+ adv7180_write_reg(0xD0, 0x00);
+ adv7180_write_reg(0xD1, 0x10);
+ adv7180_write_reg(0xD2, 0xFF);
+ adv7180_write_reg(0xD3, 0xFF);
+ adv7180_write_reg(0xD4, 0x7F);
+ adv7180_write_reg(0xD5, 0x7F);
+ adv7180_write_reg(0xD6, 0x3E);
+ adv7180_write_reg(0xD7, 0x08);
+ adv7180_write_reg(0xD8, 0x3C);
+ adv7180_write_reg(0xD9, 0x08);
+ adv7180_write_reg(0xDA, 0x3C);
+ adv7180_write_reg(0xDB, 0x9B);
+ adv7180_write_reg(0xDC, 0xAC);
+ adv7180_write_reg(0xDD, 0x4C);
+ adv7180_write_reg(0xDE, 0x00);
+ adv7180_write_reg(0xDF, 0x00);
+ adv7180_write_reg(0xE0, 0x14);
+ adv7180_write_reg(0xE1, 0x80);
+ adv7180_write_reg(0xE2, 0x80);
+ adv7180_write_reg(0xE3, 0x80);
+ adv7180_write_reg(0xE4, 0x80);
+ adv7180_write_reg(0xE5, 0x25);
+ adv7180_write_reg(0xE6, 0x44);
+ adv7180_write_reg(0xE7, 0x63);
+ adv7180_write_reg(0xE8, 0x65);
+ adv7180_write_reg(0xE9, 0x14);
+ adv7180_write_reg(0xEA, 0x63);
+ adv7180_write_reg(0xEB, 0x55);
+ adv7180_write_reg(0xEC, 0x55);
+ adv7180_write_reg(0xEE, 0x00);
+ adv7180_write_reg(0xEF, 0x4A);
+ adv7180_write_reg(0xF0, 0x44);
+ adv7180_write_reg(0xF1, 0x0C);
+ adv7180_write_reg(0xF2, 0x32);
+ adv7180_write_reg(0xF3, 0x00);
+ adv7180_write_reg(0xF4, 0x3F);
+ adv7180_write_reg(0xF5, 0xE0);
+ adv7180_write_reg(0xF6, 0x69);
+ adv7180_write_reg(0xF7, 0x10);
+ adv7180_write_reg(0xF8, 0x00);
+ adv7180_write_reg(0xF9, 0x03);
+ adv7180_write_reg(0xFA, 0xFA);
+ adv7180_write_reg(0xFB, 0x40);
+}
+
+/*! ADV7180 I2C attach function.
+ *
+ * @param *adapter struct i2c_adapter *.
+ *
+ * @return Error code indicating success or failure.
+ */
+
+/*!
+ * ADV7180 I2C probe function.
+ * Function set in i2c_driver struct.
+ * Called by insmod.
+ *
+ * @param *adapter I2C adapter descriptor.
+ *
+ * @return Error code indicating success or failure.
+ */
+static int adv7180_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int rev_id;
+ int ret = 0;
+ u32 cvbs = true;
+ struct pinctrl *pinctrl;
+ struct device *dev = &client->dev;
+
+ printk(KERN_ERR"DBG sensor data is at %p\n", &adv7180_data);
+
+ /* ov5640 pinctrl */
+ pinctrl = devm_pinctrl_get_select_default(dev);
+ if (IS_ERR(pinctrl)) {
+ dev_err(dev, "setup pinctrl failed\n");
+ return PTR_ERR(pinctrl);
+ }
+
+ /* request power down pin */
+ pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+ if (!gpio_is_valid(pwn_gpio)) {
+ dev_err(dev, "no sensor pwdn pin available\n");
+ return -ENODEV;
+ }
+ ret = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH,
+ "adv7180_pwdn");
+ if (ret < 0) {
+ dev_err(dev, "no power pin available!\n");
+ return ret;
+ }
+
+ adv7180_regulator_enable(dev);
+
+ adv7180_power_down(0);
+
+ msleep(1);
+
+ /* Set initial values for the sensor struct. */
+ memset(&adv7180_data, 0, sizeof(adv7180_data));
+ adv7180_data.sen.i2c_client = client;
+ adv7180_data.sen.streamcap.timeperframe.denominator = 30;
+ adv7180_data.sen.streamcap.timeperframe.numerator = 1;
+ adv7180_data.std_id = V4L2_STD_ALL;
+ video_idx = ADV7180_NOT_LOCKED;
+ adv7180_data.sen.pix.width = video_fmts[video_idx].raw_width;
+ adv7180_data.sen.pix.height = video_fmts[video_idx].raw_height;
+ adv7180_data.sen.pix.pixelformat = V4L2_PIX_FMT_UYVY; /* YUV422 */
+ adv7180_data.sen.pix.priv = 1; /* 1 is used to indicate TV in */
+ adv7180_data.sen.on = true;
+
+ adv7180_data.sen.sensor_clk = devm_clk_get(dev, "csi_mclk");
+ if (IS_ERR(adv7180_data.sen.sensor_clk)) {
+ dev_err(dev, "get mclk failed\n");
+ return PTR_ERR(adv7180_data.sen.sensor_clk);
+ }
+
+ ret = of_property_read_u32(dev->of_node, "mclk",
+ &adv7180_data.sen.mclk);
+ if (ret) {
+ dev_err(dev, "mclk frequency is invalid\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(
+ dev->of_node, "mclk_source",
+ (u32 *) &(adv7180_data.sen.mclk_source));
+ if (ret) {
+ dev_err(dev, "mclk_source invalid\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "csi_id",
+ &(adv7180_data.sen.csi));
+ if (ret) {
+ dev_err(dev, "csi_id invalid\n");
+ return ret;
+ }
+
+ clk_prepare_enable(adv7180_data.sen.sensor_clk);
+
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ "%s:adv7180 probe i2c address is 0x%02X\n",
+ __func__, adv7180_data.sen.i2c_client->addr);
+
+ /*! Read the revision ID of the tvin chip */
+ rev_id = adv7180_read(ADV7180_IDENT);
+ dev_dbg(dev,
+ "%s:Analog Device adv7%2X0 detected!\n", __func__,
+ rev_id);
+
+ ret = of_property_read_u32(dev->of_node, "cvbs", &(cvbs));
+ if (ret) {
+ dev_err(dev, "cvbs setting is not found\n");
+ cvbs = true;
+ }
+
+ /*! ADV7180 initialization. */
+ adv7180_hard_reset(cvbs);
+
+ pr_debug(" type is %d (expect %d)\n",
+ adv7180_int_device.type, v4l2_int_type_slave);
+ pr_debug(" num ioctls is %d\n",
+ adv7180_int_device.u.slave->num_ioctls);
+
+ /* This function attaches this structure to the /dev/video0 device.
+ * The pointer in priv points to the adv7180_data structure here.*/
+ adv7180_int_device.priv = &adv7180_data;
+ ret = v4l2_int_device_register(&adv7180_int_device);
+
+ clk_disable_unprepare(adv7180_data.sen.sensor_clk);
+
+ return ret;
+}
+
+/*!
+ * ADV7180 I2C detach function.
+ * Called on rmmod.
+ *
+ * @param *client struct i2c_client*.
+ *
+ * @return Error code indicating success or failure.
+ */
+static int adv7180_detach(struct i2c_client *client)
+{
+ dev_dbg(&adv7180_data.sen.i2c_client->dev,
+ "%s:Removing %s video decoder @ 0x%02X from adapter %s\n",
+ __func__, IF_NAME, client->addr << 1, client->adapter->name);
+
+ /* Power down via i2c */
+ adv7180_write_reg(ADV7180_PWR_MNG, 0x24);
+
+ if (dvddio_regulator)
+ regulator_disable(dvddio_regulator);
+
+ if (dvdd_regulator)
+ regulator_disable(dvdd_regulator);
+
+ if (avdd_regulator)
+ regulator_disable(avdd_regulator);
+
+ if (pvdd_regulator)
+ regulator_disable(pvdd_regulator);
+
+ v4l2_int_device_unregister(&adv7180_int_device);
+
+ return 0;
+}
+
+/*!
+ * ADV7180 init function.
+ * Called on insmod.
+ *
+ * @return Error code indicating success or failure.
+ */
+static __init int adv7180_init(void)
+{
+ u8 err = 0;
+
+ pr_debug("In adv7180_init\n");
+
+ /* Tells the i2c driver what functions to call for this driver. */
+ err = i2c_add_driver(&adv7180_i2c_driver);
+ if (err != 0)
+ pr_err("%s:driver registration failed, error=%d\n",
+ __func__, err);
+
+ return err;
+}
+
+/*!
+ * ADV7180 cleanup function.
+ * Called on rmmod.
+ *
+ * @return Error code indicating success or failure.
+ */
+static void __exit adv7180_clean(void)
+{
+ dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180_clean\n");
+ i2c_del_driver(&adv7180_i2c_driver);
+}
+
+module_init(adv7180_init);
+module_exit(adv7180_clean);
+
+MODULE_AUTHOR("Freescale Semiconductor");
+MODULE_DESCRIPTION("Anolog Device ADV7180 video decoder driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c b/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c
new file mode 100644
index 000000000000..193cbd5ec0f7
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c
@@ -0,0 +1,552 @@
+
+/*
+ * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_bg_overlay_sdc_bg.c
+ *
+ * @brief IPU Use case for PRP-VF back-ground
+ *
+ * @ingroup IPU
+ */
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+#include <linux/ipu.h>
+#include <linux/mipi_csi2.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+static int csi_buffer_num;
+static u32 bpp, csi_mem_bufsize = 3;
+static u32 out_format;
+static struct ipu_soc *disp_ipu;
+static u32 offset;
+
+static void csi_buf_work_func(struct work_struct *work)
+{
+ int err = 0;
+ cam_data *cam =
+ container_of(work, struct _cam_data, csi_work_struct);
+
+ struct ipu_task task;
+ memset(&task, 0, sizeof(task));
+
+ if (csi_buffer_num)
+ task.input.paddr = cam->vf_bufs[0];
+ else
+ task.input.paddr = cam->vf_bufs[1];
+ task.input.width = cam->crop_current.width;
+ task.input.height = cam->crop_current.height;
+ task.input.format = IPU_PIX_FMT_UYVY;
+
+ task.output.paddr = offset;
+ task.output.width = cam->overlay_fb->var.xres;
+ task.output.height = cam->overlay_fb->var.yres;
+ task.output.format = out_format;
+ task.output.rotate = cam->rotation;
+ task.output.crop.pos.x = cam->win.w.left;
+ task.output.crop.pos.y = cam->win.w.top;
+ if (cam->win.w.width > 1024 || cam->win.w.height > 1024) {
+ task.output.crop.w = cam->overlay_fb->var.xres;
+ task.output.crop.h = cam->overlay_fb->var.yres;
+ } else {
+ task.output.crop.w = cam->win.w.width;
+ task.output.crop.h = cam->win.w.height;
+ }
+again:
+ err = ipu_check_task(&task);
+ if (err != IPU_CHECK_OK) {
+ if (err > IPU_CHECK_ERR_MIN) {
+ if (err == IPU_CHECK_ERR_SPLIT_INPUTW_OVER) {
+ task.input.crop.w -= 8;
+ goto again;
+ }
+ if (err == IPU_CHECK_ERR_SPLIT_INPUTH_OVER) {
+ task.input.crop.h -= 8;
+ goto again;
+ }
+ if (err == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) {
+ task.output.width -= 8;
+ task.output.crop.w = task.output.width;
+ goto again;
+ }
+ if (err == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) {
+ task.output.height -= 8;
+ task.output.crop.h = task.output.height;
+ goto again;
+ }
+ printk(KERN_ERR "check ipu taks fail\n");
+ return;
+ }
+ printk(KERN_ERR "check ipu taks fail\n");
+ return;
+ }
+ err = ipu_queue_task(&task);
+ if (err < 0)
+ printk(KERN_ERR "queue ipu task error\n");
+}
+
+static void get_disp_ipu(cam_data *cam)
+{
+ if (cam->output > 2)
+ disp_ipu = ipu_get_soc(1); /* using DISP4 */
+ else
+ disp_ipu = ipu_get_soc(0);
+}
+
+
+/*!
+ * csi ENC callback function.
+ *
+ * @param irq int irq line
+ * @param dev_id void * device id
+ *
+ * @return status IRQ_HANDLED for handled
+ */
+static irqreturn_t csi_enc_callback(int irq, void *dev_id)
+{
+ cam_data *cam = (cam_data *) dev_id;
+ ipu_channel_t chan = (irq == IPU_IRQ_CSI0_OUT_EOF) ?
+ CSI_MEM0 : CSI_MEM1;
+
+ ipu_select_buffer(cam->ipu, chan,
+ IPU_OUTPUT_BUFFER, csi_buffer_num);
+ schedule_work(&cam->csi_work_struct);
+ csi_buffer_num = (csi_buffer_num == 0) ? 1 : 0;
+ return IRQ_HANDLED;
+}
+
+static int csi_enc_setup(cam_data *cam)
+{
+ ipu_channel_params_t params;
+ u32 pixel_fmt;
+ int err = 0, sensor_protocol = 0;
+ ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+ void *mipi_csi2_info;
+ int ipu_id;
+ int csi_id;
+#endif
+
+ if (!cam) {
+ printk(KERN_ERR "cam private is NULL\n");
+ return -ENXIO;
+ }
+
+ memset(&params, 0, sizeof(ipu_channel_params_t));
+ params.csi_mem.csi = cam->csi;
+
+ sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi);
+ switch (sensor_protocol) {
+ case IPU_CSI_CLK_MODE_GATED_CLK:
+ case IPU_CSI_CLK_MODE_NONGATED_CLK:
+ case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+ case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+ case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+ params.csi_mem.interlaced = false;
+ break;
+ case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+ case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+ case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+ params.csi_mem.interlaced = true;
+ break;
+ default:
+ printk(KERN_ERR "sensor protocol unsupported\n");
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+ mipi_csi2_info = mipi_csi2_get_info();
+
+ if (mipi_csi2_info) {
+ if (mipi_csi2_get_status(mipi_csi2_info)) {
+ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+ if (cam->ipu == ipu_get_soc(ipu_id)
+ && cam->csi == csi_id) {
+ params.csi_mem.mipi_en = true;
+ params.csi_mem.mipi_vc =
+ mipi_csi2_get_virtual_channel(mipi_csi2_info);
+ params.csi_mem.mipi_id =
+ mipi_csi2_get_datatype(mipi_csi2_info);
+
+ mipi_csi2_pixelclk_enable(mipi_csi2_info);
+ } else {
+ params.csi_mem.mipi_en = false;
+ params.csi_mem.mipi_vc = 0;
+ params.csi_mem.mipi_id = 0;
+ }
+ } else {
+ params.csi_mem.mipi_en = false;
+ params.csi_mem.mipi_vc = 0;
+ params.csi_mem.mipi_id = 0;
+ }
+ }
+#endif
+
+ if (cam->vf_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->vf_bufs_size[0],
+ cam->vf_bufs_vaddr[0],
+ (dma_addr_t) cam->vf_bufs[0]);
+ }
+ if (cam->vf_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->vf_bufs_size[1],
+ cam->vf_bufs_vaddr[1],
+ (dma_addr_t) cam->vf_bufs[1]);
+ }
+ csi_mem_bufsize =
+ cam->crop_current.width * cam->crop_current.height * 2;
+ cam->vf_bufs_size[0] = PAGE_ALIGN(csi_mem_bufsize);
+ cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
+ cam->vf_bufs_size[0],
+ (dma_addr_t *) &
+ cam->vf_bufs[0],
+ GFP_DMA |
+ GFP_KERNEL);
+ if (cam->vf_bufs_vaddr[0] == NULL) {
+ printk(KERN_ERR "Error to allocate vf buffer\n");
+ err = -ENOMEM;
+ goto out_2;
+ }
+ cam->vf_bufs_size[1] = PAGE_ALIGN(csi_mem_bufsize);
+ cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
+ cam->vf_bufs_size[1],
+ (dma_addr_t *) &
+ cam->vf_bufs[1],
+ GFP_DMA |
+ GFP_KERNEL);
+ if (cam->vf_bufs_vaddr[1] == NULL) {
+ printk(KERN_ERR "Error to allocate vf buffer\n");
+ err = -ENOMEM;
+ goto out_1;
+ }
+ pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]);
+
+ err = ipu_init_channel(cam->ipu, chan, &params);
+ if (err != 0) {
+ printk(KERN_ERR "ipu_init_channel %d\n", err);
+ goto out_1;
+ }
+
+ pixel_fmt = IPU_PIX_FMT_UYVY;
+ err = ipu_init_channel_buffer(
+ cam->ipu, chan, IPU_OUTPUT_BUFFER, pixel_fmt,
+ cam->crop_current.width, cam->crop_current.height,
+ cam->crop_current.width, IPU_ROTATE_NONE,
+ cam->vf_bufs[0], cam->vf_bufs[1], 0,
+ cam->offset.u_offset, cam->offset.u_offset);
+ if (err != 0) {
+ printk(KERN_ERR "CSI_MEM output buffer\n");
+ goto out_1;
+ }
+ err = ipu_enable_channel(cam->ipu, chan);
+ if (err < 0) {
+ printk(KERN_ERR "ipu_enable_channel CSI_MEM\n");
+ goto out_1;
+ }
+
+ csi_buffer_num = 0;
+
+ ipu_select_buffer(cam->ipu, chan, IPU_OUTPUT_BUFFER, 0);
+ ipu_select_buffer(cam->ipu, chan, IPU_OUTPUT_BUFFER, 1);
+ return err;
+out_1:
+ if (cam->vf_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->vf_bufs_size[0],
+ cam->vf_bufs_vaddr[0],
+ (dma_addr_t) cam->vf_bufs[0]);
+ cam->vf_bufs_vaddr[0] = NULL;
+ cam->vf_bufs[0] = 0;
+ }
+ if (cam->vf_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->vf_bufs_size[1],
+ cam->vf_bufs_vaddr[1],
+ (dma_addr_t) cam->vf_bufs[1]);
+ cam->vf_bufs_vaddr[1] = NULL;
+ cam->vf_bufs[1] = 0;
+ }
+out_2:
+ return err;
+}
+
+/*!
+ * Enable encoder task
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int csi_enc_enabling_tasks(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ int err = 0;
+
+ ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi);
+ err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi,
+ csi_enc_callback, 0, "Mxc Camera", cam);
+ if (err != 0) {
+ printk(KERN_ERR "Error registering CSI_OUT_EOF irq\n");
+ return err;
+ }
+
+ INIT_WORK(&cam->csi_work_struct, csi_buf_work_func);
+
+ err = csi_enc_setup(cam);
+ if (err != 0) {
+ printk(KERN_ERR "csi_enc_setup %d\n", err);
+ goto out1;
+ }
+
+ return err;
+out1:
+ ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, cam);
+ return err;
+}
+
+/*!
+ * bg_overlay_start - start the overlay task
+ *
+ * @param private cam_data * mxc v4l2 main structure
+ *
+ */
+static int bg_overlay_start(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ int err = 0;
+
+ if (!cam) {
+ printk(KERN_ERR "private is NULL\n");
+ return -EIO;
+ }
+
+ if (cam->overlay_active == true) {
+ pr_debug("already start.\n");
+ return 0;
+ }
+
+ get_disp_ipu(cam);
+
+ out_format = cam->v4l2_fb.fmt.pixelformat;
+ if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) {
+ bpp = 3, csi_mem_bufsize = 3;
+ pr_info("BGR24\n");
+ } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) {
+ bpp = 2, csi_mem_bufsize = 2;
+ pr_info("RGB565\n");
+ } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) {
+ bpp = 4, csi_mem_bufsize = 4;
+ pr_info("BGR32\n");
+ } else {
+ printk(KERN_ERR
+ "unsupported fix format from the framebuffer.\n");
+ return -EINVAL;
+ }
+
+ offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top +
+ csi_mem_bufsize * cam->win.w.left;
+
+ if (cam->v4l2_fb.base == 0)
+ printk(KERN_ERR "invalid frame buffer address.\n");
+ else
+ offset += (u32) cam->v4l2_fb.base;
+
+ csi_mem_bufsize = cam->win.w.width * cam->win.w.height
+ * csi_mem_bufsize;
+
+ err = csi_enc_enabling_tasks(cam);
+ if (err != 0) {
+ printk(KERN_ERR "Error csi enc enable fail\n");
+ return err;
+ }
+
+ cam->overlay_active = true;
+ return err;
+}
+
+/*!
+ * bg_overlay_stop - stop the overlay task
+ *
+ * @param private cam_data * mxc v4l2 main structure
+ *
+ */
+static int bg_overlay_stop(void *private)
+{
+ int err = 0;
+ cam_data *cam = (cam_data *) private;
+ ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
+#ifdef CONFIG_MXC_MIPI_CSI2
+ void *mipi_csi2_info;
+ int ipu_id;
+ int csi_id;
+#endif
+
+ if (cam->overlay_active == false)
+ return 0;
+
+ err = ipu_disable_channel(cam->ipu, chan, true);
+
+ ipu_uninit_channel(cam->ipu, chan);
+
+ csi_buffer_num = 0;
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+ mipi_csi2_info = mipi_csi2_get_info();
+
+ if (mipi_csi2_info) {
+ if (mipi_csi2_get_status(mipi_csi2_info)) {
+ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+ if (cam->ipu == ipu_get_soc(ipu_id)
+ && cam->csi == csi_id)
+ mipi_csi2_pixelclk_disable(mipi_csi2_info);
+ }
+ }
+#endif
+
+ flush_work(&cam->csi_work_struct);
+ cancel_work_sync(&cam->csi_work_struct);
+
+ if (cam->vf_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->vf_bufs_size[0],
+ cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
+ cam->vf_bufs_vaddr[0] = NULL;
+ cam->vf_bufs[0] = 0;
+ }
+ if (cam->vf_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->vf_bufs_size[1],
+ cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
+ cam->vf_bufs_vaddr[1] = NULL;
+ cam->vf_bufs[1] = 0;
+ }
+ if (cam->rot_vf_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->rot_vf_buf_size[0],
+ cam->rot_vf_bufs_vaddr[0],
+ cam->rot_vf_bufs[0]);
+ cam->rot_vf_bufs_vaddr[0] = NULL;
+ cam->rot_vf_bufs[0] = 0;
+ }
+ if (cam->rot_vf_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->rot_vf_buf_size[1],
+ cam->rot_vf_bufs_vaddr[1],
+ cam->rot_vf_bufs[1]);
+ cam->rot_vf_bufs_vaddr[1] = NULL;
+ cam->rot_vf_bufs[1] = 0;
+ }
+
+ cam->overlay_active = false;
+ return err;
+}
+
+/*!
+ * Enable csi
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int bg_overlay_enable_csi(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+
+ return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int bg_overlay_disable_csi(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+
+ /* free csi eof irq firstly.
+ * when disable csi, wait for idmac eof.
+ * it requests eof irq again */
+ ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, cam);
+
+ return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select bg as the working path
+ *
+ * @param private cam_data * mxc v4l2 main structure
+ *
+ * @return status
+ */
+int bg_overlay_sdc_select(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+
+ if (cam) {
+ cam->vf_start_sdc = bg_overlay_start;
+ cam->vf_stop_sdc = bg_overlay_stop;
+ cam->vf_enable_csi = bg_overlay_enable_csi;
+ cam->vf_disable_csi = bg_overlay_disable_csi;
+ cam->overlay_active = false;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(bg_overlay_sdc_select);
+
+/*!
+ * function to de-select bg as the working path
+ *
+ * @param private cam_data * mxc v4l2 main structure
+ *
+ * @return status
+ */
+int bg_overlay_sdc_deselect(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+
+ if (cam) {
+ cam->vf_start_sdc = NULL;
+ cam->vf_stop_sdc = NULL;
+ cam->vf_enable_csi = NULL;
+ cam->vf_disable_csi = NULL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(bg_overlay_sdc_deselect);
+
+/*!
+ * Init background overlay task.
+ *
+ * @return Error code indicating success or failure
+ */
+__init int bg_overlay_sdc_init(void)
+{
+ return 0;
+}
+
+/*!
+ * Deinit background overlay task.
+ *
+ * @return Error code indicating success or failure
+ */
+void __exit bg_overlay_sdc_exit(void)
+{
+}
+
+module_init(bg_overlay_sdc_init);
+module_exit(bg_overlay_sdc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/ipu_csi_enc.c b/drivers/media/platform/mxc/capture/ipu_csi_enc.c
new file mode 100644
index 000000000000..3a824a9659e7
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/ipu_csi_enc.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright 2009-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_csi_enc.c
+ *
+ * @brief CSI Use case for video capture
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/ipu.h>
+#include <linux/mipi_csi2.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+#ifdef CAMERA_DBG
+ #define CAMERA_TRACE(x) (printk)x
+#else
+ #define CAMERA_TRACE(x)
+#endif
+
+/*
+ * Function definitions
+ */
+
+/*!
+ * csi ENC callback function.
+ *
+ * @param irq int irq line
+ * @param dev_id void * device id
+ *
+ * @return status IRQ_HANDLED for handled
+ */
+static irqreturn_t csi_enc_callback(int irq, void *dev_id)
+{
+ cam_data *cam = (cam_data *) dev_id;
+
+ if (cam->enc_callback == NULL)
+ return IRQ_HANDLED;
+
+ cam->enc_callback(irq, dev_id);
+ return IRQ_HANDLED;
+}
+
+/*!
+ * CSI ENC enable channel setup function
+ *
+ * @param cam struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int csi_enc_setup(cam_data *cam)
+{
+ ipu_channel_params_t params;
+ u32 pixel_fmt;
+ int err = 0, sensor_protocol = 0;
+ dma_addr_t dummy = cam->dummy_frame.buffer.m.offset;
+ ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
+#ifdef CONFIG_MXC_MIPI_CSI2
+ void *mipi_csi2_info;
+ int ipu_id;
+ int csi_id;
+#endif
+
+ CAMERA_TRACE("In csi_enc_setup\n");
+ if (!cam) {
+ printk(KERN_ERR "cam private is NULL\n");
+ return -ENXIO;
+ }
+
+ memset(&params, 0, sizeof(ipu_channel_params_t));
+ params.csi_mem.csi = cam->csi;
+
+ sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi);
+ switch (sensor_protocol) {
+ case IPU_CSI_CLK_MODE_GATED_CLK:
+ case IPU_CSI_CLK_MODE_NONGATED_CLK:
+ case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+ case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+ case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+ params.csi_mem.interlaced = false;
+ break;
+ case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+ case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+ case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+ params.csi_mem.interlaced = true;
+ break;
+ default:
+ printk(KERN_ERR "sensor protocol unsupported\n");
+ return -EINVAL;
+ }
+
+ if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+ pixel_fmt = IPU_PIX_FMT_YUV420P;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420)
+ pixel_fmt = IPU_PIX_FMT_YVU420P;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P)
+ pixel_fmt = IPU_PIX_FMT_YUV422P;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
+ pixel_fmt = IPU_PIX_FMT_UYVY;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
+ pixel_fmt = IPU_PIX_FMT_YUYV;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12)
+ pixel_fmt = IPU_PIX_FMT_NV12;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24)
+ pixel_fmt = IPU_PIX_FMT_BGR24;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24)
+ pixel_fmt = IPU_PIX_FMT_RGB24;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565)
+ pixel_fmt = IPU_PIX_FMT_RGB565;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32)
+ pixel_fmt = IPU_PIX_FMT_BGR32;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32)
+ pixel_fmt = IPU_PIX_FMT_RGB32;
+ else {
+ printk(KERN_ERR "format not supported\n");
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+ mipi_csi2_info = mipi_csi2_get_info();
+
+ if (mipi_csi2_info) {
+ if (mipi_csi2_get_status(mipi_csi2_info)) {
+ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+ if (cam->ipu == ipu_get_soc(ipu_id)
+ && cam->csi == csi_id) {
+ params.csi_mem.mipi_en = true;
+ params.csi_mem.mipi_vc =
+ mipi_csi2_get_virtual_channel(mipi_csi2_info);
+ params.csi_mem.mipi_id =
+ mipi_csi2_get_datatype(mipi_csi2_info);
+
+ mipi_csi2_pixelclk_enable(mipi_csi2_info);
+ } else {
+ params.csi_mem.mipi_en = false;
+ params.csi_mem.mipi_vc = 0;
+ params.csi_mem.mipi_id = 0;
+ }
+ } else {
+ params.csi_mem.mipi_en = false;
+ params.csi_mem.mipi_vc = 0;
+ params.csi_mem.mipi_id = 0;
+ }
+ }
+#endif
+
+ err = ipu_init_channel(cam->ipu, chan, &params);
+ if (err != 0) {
+ printk(KERN_ERR "ipu_init_channel %d\n", err);
+ return err;
+ }
+
+ err = ipu_init_channel_buffer(cam->ipu,
+ chan,
+ IPU_OUTPUT_BUFFER,
+ pixel_fmt, cam->v2f.fmt.pix.width,
+ cam->v2f.fmt.pix.height,
+ cam->v2f.fmt.pix.bytesperline,
+ IPU_ROTATE_NONE,
+ dummy, dummy, 0,
+ cam->offset.u_offset,
+ cam->offset.v_offset);
+ if (err != 0) {
+ printk(KERN_ERR "CSI_MEM output buffer\n");
+ return err;
+ }
+ err = ipu_enable_channel(cam->ipu, chan);
+ if (err < 0) {
+ printk(KERN_ERR "ipu_enable_channel CSI_MEM\n");
+ return err;
+ }
+
+ return err;
+}
+
+/*!
+ * function to update physical buffer address for encorder IDMA channel
+ *
+ * @param *private pointer to the cam_data structure
+ * @param eba physical buffer address for encorder IDMA channel
+ *
+ * @return status
+ */
+static int csi_enc_eba_update(void *private, dma_addr_t eba)
+{
+ int err = 0;
+ cam_data *cam = (cam_data *) private;
+ struct ipu_soc *ipu = cam->ipu;
+ int *buffer_num = &cam->ping_pong_csi;
+ ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
+
+ pr_debug("eba %x\n", eba);
+ err = ipu_update_channel_buffer(ipu, chan, IPU_OUTPUT_BUFFER,
+ *buffer_num, eba);
+ if (err != 0) {
+ ipu_clear_buffer_ready(ipu, chan, IPU_OUTPUT_BUFFER,
+ *buffer_num);
+
+ err = ipu_update_channel_buffer(ipu, chan,
+ IPU_OUTPUT_BUFFER, *buffer_num, eba);
+ if (err != 0) {
+ pr_err("ERROR: v4l2 capture: fail to update "
+ "buf%d\n", *buffer_num);
+ return err;
+ }
+ }
+
+ ipu_select_buffer(ipu, chan, IPU_OUTPUT_BUFFER, *buffer_num);
+
+ *buffer_num = (*buffer_num == 0) ? 1 : 0;
+
+ return 0;
+}
+
+/*!
+ * Enable encoder task
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int csi_enc_enabling_tasks(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ int err = 0;
+ uint32_t irq = (cam->csi == 0) ?
+ IPU_IRQ_CSI0_OUT_EOF : IPU_IRQ_CSI1_OUT_EOF;
+
+ CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n");
+
+ cam->dummy_frame.vaddress = dma_alloc_coherent(0,
+ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
+ &cam->dummy_frame.paddress,
+ GFP_DMA | GFP_KERNEL);
+ if (cam->dummy_frame.vaddress == 0) {
+ pr_err("ERROR: v4l2 capture: Allocate dummy frame "
+ "failed.\n");
+ return -ENOBUFS;
+ }
+ cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE;
+ cam->dummy_frame.buffer.length =
+ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
+ cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress;
+
+ ipu_clear_irq(cam->ipu, irq);
+ err = ipu_request_irq(
+ cam->ipu, irq, csi_enc_callback, 0, "Mxc Camera", cam);
+ if (err != 0) {
+ printk(KERN_ERR "Error registering rot irq\n");
+ return err;
+ }
+
+ err = csi_enc_setup(cam);
+ if (err != 0) {
+ printk(KERN_ERR "csi_enc_setup %d\n", err);
+ return err;
+ }
+
+ return err;
+}
+
+/*!
+ * Disable encoder task
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return int
+ */
+static int csi_enc_disabling_tasks(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ int err = 0;
+ ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
+#ifdef CONFIG_MXC_MIPI_CSI2
+ void *mipi_csi2_info;
+ int ipu_id;
+ int csi_id;
+#endif
+
+ err = ipu_disable_channel(cam->ipu, chan, true);
+
+ ipu_uninit_channel(cam->ipu, chan);
+
+ if (cam->dummy_frame.vaddress != 0) {
+ dma_free_coherent(0, cam->dummy_frame.buffer.length,
+ cam->dummy_frame.vaddress,
+ cam->dummy_frame.paddress);
+ cam->dummy_frame.vaddress = 0;
+ }
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+ mipi_csi2_info = mipi_csi2_get_info();
+
+ if (mipi_csi2_info) {
+ if (mipi_csi2_get_status(mipi_csi2_info)) {
+ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+ if (cam->ipu == ipu_get_soc(ipu_id)
+ && cam->csi == csi_id)
+ mipi_csi2_pixelclk_disable(mipi_csi2_info);
+ }
+ }
+#endif
+
+ return err;
+}
+
+/*!
+ * Enable csi
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int csi_enc_enable_csi(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+
+ return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int csi_enc_disable_csi(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ uint32_t irq = (cam->csi == 0) ?
+ IPU_IRQ_CSI0_OUT_EOF : IPU_IRQ_CSI1_OUT_EOF;
+
+ /* free csi eof irq firstly.
+ * when disable csi, wait for idmac eof.
+ * it requests eof irq again */
+ ipu_free_irq(cam->ipu, irq, cam);
+
+ return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select CSI ENC as the working path
+ *
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return int
+ */
+int csi_enc_select(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ int err = 0;
+
+ if (cam) {
+ cam->enc_update_eba = csi_enc_eba_update;
+ cam->enc_enable = csi_enc_enabling_tasks;
+ cam->enc_disable = csi_enc_disabling_tasks;
+ cam->enc_enable_csi = csi_enc_enable_csi;
+ cam->enc_disable_csi = csi_enc_disable_csi;
+ } else {
+ err = -EIO;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(csi_enc_select);
+
+/*!
+ * function to de-select CSI ENC as the working path
+ *
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return int
+ */
+int csi_enc_deselect(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ int err = 0;
+
+ if (cam) {
+ cam->enc_update_eba = NULL;
+ cam->enc_enable = NULL;
+ cam->enc_disable = NULL;
+ cam->enc_enable_csi = NULL;
+ cam->enc_disable_csi = NULL;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(csi_enc_deselect);
+
+/*!
+ * Init the Encorder channels
+ *
+ * @return Error code indicating success or failure
+ */
+__init int csi_enc_init(void)
+{
+ return 0;
+}
+
+/*!
+ * Deinit the Encorder channels
+ *
+ */
+void __exit csi_enc_exit(void)
+{
+}
+
+module_init(csi_enc_init);
+module_exit(csi_enc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("CSI ENC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c b/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c
new file mode 100644
index 000000000000..4d6b1365bb0d
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c
@@ -0,0 +1,638 @@
+/*
+ * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+/* * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_foreground_sdc.c
+ *
+ * @brief IPU Use case for PRP-VF
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/console.h>
+#include <linux/ipu.h>
+#include <linux/mxcfb.h>
+#include <linux/mipi_csi2.h>
+
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+#ifdef CAMERA_DBG
+ #define CAMERA_TRACE(x) (printk)x
+#else
+ #define CAMERA_TRACE(x)
+#endif
+
+static int csi_buffer_num, buffer_num;
+static u32 csi_mem_bufsize;
+static struct ipu_soc *disp_ipu;
+static struct fb_info *fbi;
+static struct fb_var_screeninfo fbvar;
+static u32 vf_out_format;
+static void csi_buf_work_func(struct work_struct *work)
+{
+ int err = 0;
+ cam_data *cam =
+ container_of(work, struct _cam_data, csi_work_struct);
+
+ struct ipu_task task;
+ memset(&task, 0, sizeof(task));
+
+ if (csi_buffer_num)
+ task.input.paddr = cam->vf_bufs[0];
+ else
+ task.input.paddr = cam->vf_bufs[1];
+ task.input.width = cam->crop_current.width;
+ task.input.height = cam->crop_current.height;
+ task.input.format = IPU_PIX_FMT_NV12;
+
+ if (buffer_num == 0)
+ task.output.paddr = fbi->fix.smem_start +
+ (fbi->fix.line_length * fbvar.yres);
+ else
+ task.output.paddr = fbi->fix.smem_start;
+ task.output.width = cam->win.w.width;
+ task.output.height = cam->win.w.height;
+ task.output.format = vf_out_format;
+ task.output.rotate = cam->rotation;
+again:
+ err = ipu_check_task(&task);
+ if (err != IPU_CHECK_OK) {
+ if (err > IPU_CHECK_ERR_MIN) {
+ if (err == IPU_CHECK_ERR_SPLIT_INPUTW_OVER) {
+ task.input.crop.w -= 8;
+ goto again;
+ }
+ if (err == IPU_CHECK_ERR_SPLIT_INPUTH_OVER) {
+ task.input.crop.h -= 8;
+ goto again;
+ }
+ if (err == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) {
+ task.output.width -= 8;
+ task.output.crop.w = task.output.width;
+ goto again;
+ }
+ if (err == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) {
+ task.output.height -= 8;
+ task.output.crop.h = task.output.height;
+ goto again;
+ }
+ printk(KERN_ERR "check ipu taks fail\n");
+ return;
+ }
+ printk(KERN_ERR "check ipu taks fail\n");
+ return;
+ }
+ err = ipu_queue_task(&task);
+ if (err < 0)
+ printk(KERN_ERR "queue ipu task error\n");
+ ipu_select_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER, buffer_num);
+ buffer_num = (buffer_num == 0) ? 1 : 0;
+}
+
+static void get_disp_ipu(cam_data *cam)
+{
+ if (cam->output > 2)
+ disp_ipu = ipu_get_soc(1); /* using DISP4 */
+ else
+ disp_ipu = ipu_get_soc(0);
+}
+
+/*!
+ * csi ENC callback function.
+ *
+ * @param irq int irq line
+ * @param dev_id void * device id
+ *
+ * @return status IRQ_HANDLED for handled
+ */
+static irqreturn_t csi_enc_callback(int irq, void *dev_id)
+{
+ cam_data *cam = (cam_data *) dev_id;
+ ipu_channel_t chan = (irq == IPU_IRQ_CSI0_OUT_EOF) ?
+ CSI_MEM0 : CSI_MEM1;
+
+ ipu_select_buffer(cam->ipu, chan,
+ IPU_OUTPUT_BUFFER, csi_buffer_num);
+
+ if ((cam->crop_current.width != cam->win.w.width) ||
+ (cam->crop_current.height != cam->win.w.height) ||
+ (vf_out_format != IPU_PIX_FMT_NV12) ||
+ (cam->rotation >= IPU_ROTATE_VERT_FLIP))
+ schedule_work(&cam->csi_work_struct);
+ csi_buffer_num = (csi_buffer_num == 0) ? 1 : 0;
+ return IRQ_HANDLED;
+}
+
+static int csi_enc_setup(cam_data *cam)
+{
+ ipu_channel_params_t params;
+ int err = 0, sensor_protocol = 0;
+ ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
+#ifdef CONFIG_MXC_MIPI_CSI2
+ void *mipi_csi2_info;
+ int ipu_id;
+ int csi_id;
+#endif
+
+ CAMERA_TRACE("In csi_enc_setup\n");
+ if (!cam) {
+ printk(KERN_ERR "cam private is NULL\n");
+ return -ENXIO;
+ }
+
+ memset(&params, 0, sizeof(ipu_channel_params_t));
+ params.csi_mem.csi = cam->csi;
+
+ sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi);
+ switch (sensor_protocol) {
+ case IPU_CSI_CLK_MODE_GATED_CLK:
+ case IPU_CSI_CLK_MODE_NONGATED_CLK:
+ case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE:
+ case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR:
+ case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR:
+ params.csi_mem.interlaced = false;
+ break;
+ case IPU_CSI_CLK_MODE_CCIR656_INTERLACED:
+ case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR:
+ case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR:
+ params.csi_mem.interlaced = true;
+ break;
+ default:
+ printk(KERN_ERR "sensor protocol unsupported\n");
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+ mipi_csi2_info = mipi_csi2_get_info();
+
+ if (mipi_csi2_info) {
+ if (mipi_csi2_get_status(mipi_csi2_info)) {
+ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+ if (cam->ipu == ipu_get_soc(ipu_id)
+ && cam->csi == csi_id) {
+ params.csi_mem.mipi_en = true;
+ params.csi_mem.mipi_vc =
+ mipi_csi2_get_virtual_channel(mipi_csi2_info);
+ params.csi_mem.mipi_id =
+ mipi_csi2_get_datatype(mipi_csi2_info);
+
+ mipi_csi2_pixelclk_enable(mipi_csi2_info);
+ } else {
+ params.csi_mem.mipi_en = false;
+ params.csi_mem.mipi_vc = 0;
+ params.csi_mem.mipi_id = 0;
+ }
+ } else {
+ params.csi_mem.mipi_en = false;
+ params.csi_mem.mipi_vc = 0;
+ params.csi_mem.mipi_id = 0;
+ }
+ }
+#endif
+
+ if (cam->vf_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->vf_bufs_size[0],
+ cam->vf_bufs_vaddr[0],
+ (dma_addr_t) cam->vf_bufs[0]);
+ }
+ if (cam->vf_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->vf_bufs_size[1],
+ cam->vf_bufs_vaddr[1],
+ (dma_addr_t) cam->vf_bufs[1]);
+ }
+ csi_mem_bufsize = cam->crop_current.width *
+ cam->crop_current.height * 3/2;
+ cam->vf_bufs_size[0] = PAGE_ALIGN(csi_mem_bufsize);
+ cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
+ cam->vf_bufs_size[0],
+ (dma_addr_t *) &
+ cam->vf_bufs[0],
+ GFP_DMA |
+ GFP_KERNEL);
+ if (cam->vf_bufs_vaddr[0] == NULL) {
+ printk(KERN_ERR "Error to allocate vf buffer\n");
+ err = -ENOMEM;
+ goto out_2;
+ }
+ cam->vf_bufs_size[1] = PAGE_ALIGN(csi_mem_bufsize);
+ cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
+ cam->vf_bufs_size[1],
+ (dma_addr_t *) &
+ cam->vf_bufs[1],
+ GFP_DMA |
+ GFP_KERNEL);
+ if (cam->vf_bufs_vaddr[1] == NULL) {
+ printk(KERN_ERR "Error to allocate vf buffer\n");
+ err = -ENOMEM;
+ goto out_1;
+ }
+ pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]);
+
+ err = ipu_init_channel(cam->ipu, chan, &params);
+ if (err != 0) {
+ printk(KERN_ERR "ipu_init_channel %d\n", err);
+ goto out_1;
+ }
+
+ if ((cam->crop_current.width == cam->win.w.width) &&
+ (cam->crop_current.height == cam->win.w.height) &&
+ (vf_out_format == IPU_PIX_FMT_NV12) &&
+ (cam->rotation < IPU_ROTATE_VERT_FLIP)) {
+ err = ipu_init_channel_buffer(cam->ipu, chan,
+ IPU_OUTPUT_BUFFER, IPU_PIX_FMT_NV12,
+ cam->crop_current.width,
+ cam->crop_current.height,
+ cam->crop_current.width, IPU_ROTATE_NONE,
+ fbi->fix.smem_start +
+ (fbi->fix.line_length * fbvar.yres),
+ fbi->fix.smem_start, 0,
+ cam->offset.u_offset, cam->offset.u_offset);
+ } else {
+ err = ipu_init_channel_buffer(cam->ipu, chan,
+ IPU_OUTPUT_BUFFER, IPU_PIX_FMT_NV12,
+ cam->crop_current.width,
+ cam->crop_current.height,
+ cam->crop_current.width, IPU_ROTATE_NONE,
+ cam->vf_bufs[0], cam->vf_bufs[1], 0,
+ cam->offset.u_offset, cam->offset.u_offset);
+ }
+ if (err != 0) {
+ printk(KERN_ERR "CSI_MEM output buffer\n");
+ goto out_1;
+ }
+ err = ipu_enable_channel(cam->ipu, chan);
+ if (err < 0) {
+ printk(KERN_ERR "ipu_enable_channel CSI_MEM\n");
+ goto out_1;
+ }
+
+ csi_buffer_num = 0;
+
+ ipu_select_buffer(cam->ipu, chan, IPU_OUTPUT_BUFFER, 0);
+ ipu_select_buffer(cam->ipu, chan, IPU_OUTPUT_BUFFER, 1);
+ return err;
+out_1:
+ if (cam->vf_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->vf_bufs_size[0],
+ cam->vf_bufs_vaddr[0],
+ (dma_addr_t) cam->vf_bufs[0]);
+ cam->vf_bufs_vaddr[0] = NULL;
+ cam->vf_bufs[0] = 0;
+ }
+ if (cam->vf_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->vf_bufs_size[1],
+ cam->vf_bufs_vaddr[1],
+ (dma_addr_t) cam->vf_bufs[1]);
+ cam->vf_bufs_vaddr[1] = NULL;
+ cam->vf_bufs[1] = 0;
+ }
+out_2:
+ return err;
+}
+
+/*!
+ * Enable encoder task
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int csi_enc_enabling_tasks(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ int err = 0;
+ CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n");
+
+ ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi);
+ err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi,
+ csi_enc_callback, 0, "Mxc Camera", cam);
+ if (err != 0) {
+ printk(KERN_ERR "Error registering CSI_OUT_EOF irq\n");
+ return err;
+ }
+
+ INIT_WORK(&cam->csi_work_struct, csi_buf_work_func);
+
+ err = csi_enc_setup(cam);
+ if (err != 0) {
+ printk(KERN_ERR "csi_enc_setup %d\n", err);
+ goto out1;
+ }
+
+ return err;
+out1:
+ ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, cam);
+ return err;
+}
+
+/*
+ * Function definitions
+ */
+
+/*!
+ * foreground_start - start the vf task
+ *
+ * @param private cam_data * mxc v4l2 main structure
+ *
+ */
+static int foreground_start(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ int err = 0, i = 0, screen_size;
+ char *base;
+
+ if (!cam) {
+ printk(KERN_ERR "private is NULL\n");
+ return -EIO;
+ }
+
+ if (cam->overlay_active == true) {
+ pr_debug("already started.\n");
+ return 0;
+ }
+
+ get_disp_ipu(cam);
+
+ for (i = 0; i < num_registered_fb; i++) {
+ char *idstr = registered_fb[i]->fix.id;
+ if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
+ ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
+ fbi = registered_fb[i];
+ break;
+ }
+ }
+
+ if (fbi == NULL) {
+ printk(KERN_ERR "DISP FG fb not found\n");
+ return -EPERM;
+ }
+
+ fbvar = fbi->var;
+
+ /* Store the overlay frame buffer's original std */
+ cam->fb_origin_std = fbvar.nonstd;
+
+ if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) {
+ /* Use DP to do CSC so that we can get better performance */
+ vf_out_format = IPU_PIX_FMT_NV12;
+ fbvar.nonstd = vf_out_format;
+ } else {
+ vf_out_format = IPU_PIX_FMT_RGB565;
+ fbvar.nonstd = 0;
+ }
+
+ fbvar.bits_per_pixel = 16;
+ fbvar.xres = fbvar.xres_virtual = cam->win.w.width;
+ fbvar.yres = cam->win.w.height;
+ fbvar.yres_virtual = cam->win.w.height * 2;
+ fbvar.yoffset = 0;
+ fbvar.vmode &= ~FB_VMODE_YWRAP;
+ fbvar.accel_flags = FB_ACCEL_DOUBLE_FLAG;
+ fbvar.activate |= FB_ACTIVATE_FORCE;
+ fb_set_var(fbi, &fbvar);
+
+ ipu_disp_set_window_pos(disp_ipu, MEM_FG_SYNC, cam->win.w.left,
+ cam->win.w.top);
+
+ /* Fill black color for framebuffer */
+ base = (char *) fbi->screen_base;
+ screen_size = fbi->var.xres * fbi->var.yres;
+ if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) {
+ memset(base, 0, screen_size);
+ base += screen_size;
+ for (i = 0; i < screen_size / 2; i++, base++)
+ *base = 0x80;
+ } else {
+ for (i = 0; i < screen_size * 2; i++, base++)
+ *base = 0x00;
+ }
+
+ console_lock();
+ fb_blank(fbi, FB_BLANK_UNBLANK);
+ console_unlock();
+
+ /* correct display ch buffer address */
+ ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
+ 0, fbi->fix.smem_start +
+ (fbi->fix.line_length * fbvar.yres));
+ ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
+ 1, fbi->fix.smem_start);
+
+ err = csi_enc_enabling_tasks(cam);
+ if (err != 0) {
+ printk(KERN_ERR "Error csi enc enable fail\n");
+ return err;
+ }
+
+ cam->overlay_active = true;
+ return err;
+
+}
+
+/*!
+ * foreground_stop - stop the vf task
+ *
+ * @param private cam_data * mxc v4l2 main structure
+ *
+ */
+static int foreground_stop(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ int err = 0, i = 0;
+ struct fb_info *fbi = NULL;
+ struct fb_var_screeninfo fbvar;
+ ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1;
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+ void *mipi_csi2_info;
+ int ipu_id;
+ int csi_id;
+#endif
+
+ if (cam->overlay_active == false)
+ return 0;
+
+ err = ipu_disable_channel(cam->ipu, chan, true);
+
+ ipu_uninit_channel(cam->ipu, chan);
+
+ csi_buffer_num = 0;
+ buffer_num = 0;
+
+ for (i = 0; i < num_registered_fb; i++) {
+ char *idstr = registered_fb[i]->fix.id;
+ if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
+ ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
+ fbi = registered_fb[i];
+ break;
+ }
+ }
+
+ if (fbi == NULL) {
+ printk(KERN_ERR "DISP FG fb not found\n");
+ return -EPERM;
+ }
+
+ console_lock();
+ fb_blank(fbi, FB_BLANK_POWERDOWN);
+ console_unlock();
+
+ /* Set the overlay frame buffer std to what it is used to be */
+ fbvar = fbi->var;
+ fbvar.accel_flags = FB_ACCEL_TRIPLE_FLAG;
+ fbvar.nonstd = cam->fb_origin_std;
+ fbvar.activate |= FB_ACTIVATE_FORCE;
+ fb_set_var(fbi, &fbvar);
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+ mipi_csi2_info = mipi_csi2_get_info();
+
+ if (mipi_csi2_info) {
+ if (mipi_csi2_get_status(mipi_csi2_info)) {
+ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+ if (cam->ipu == ipu_get_soc(ipu_id)
+ && cam->csi == csi_id)
+ mipi_csi2_pixelclk_disable(mipi_csi2_info);
+ }
+ }
+#endif
+
+ flush_work(&cam->csi_work_struct);
+ cancel_work_sync(&cam->csi_work_struct);
+
+ if (cam->vf_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->vf_bufs_size[0],
+ cam->vf_bufs_vaddr[0],
+ (dma_addr_t) cam->vf_bufs[0]);
+ cam->vf_bufs_vaddr[0] = NULL;
+ cam->vf_bufs[0] = 0;
+ }
+ if (cam->vf_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->vf_bufs_size[1],
+ cam->vf_bufs_vaddr[1],
+ (dma_addr_t) cam->vf_bufs[1]);
+ cam->vf_bufs_vaddr[1] = NULL;
+ cam->vf_bufs[1] = 0;
+ }
+
+ cam->overlay_active = false;
+ return err;
+}
+
+/*!
+ * Enable csi
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int foreground_enable_csi(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+
+ return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int foreground_disable_csi(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+
+ /* free csi eof irq firstly.
+ * when disable csi, wait for idmac eof.
+ * it requests eof irq again */
+ ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, cam);
+
+ return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select foreground as the working path
+ *
+ * @param private cam_data * mxc v4l2 main structure
+ *
+ * @return status
+ */
+int foreground_sdc_select(void *private)
+{
+ cam_data *cam;
+ int err = 0;
+ if (private) {
+ cam = (cam_data *) private;
+ cam->vf_start_sdc = foreground_start;
+ cam->vf_stop_sdc = foreground_stop;
+ cam->vf_enable_csi = foreground_enable_csi;
+ cam->vf_disable_csi = foreground_disable_csi;
+ cam->overlay_active = false;
+ } else
+ err = -EIO;
+
+ return err;
+}
+EXPORT_SYMBOL(foreground_sdc_select);
+
+/*!
+ * function to de-select foreground as the working path
+ *
+ * @param private cam_data * mxc v4l2 main structure
+ *
+ * @return int
+ */
+int foreground_sdc_deselect(void *private)
+{
+ cam_data *cam;
+
+ if (private) {
+ cam = (cam_data *) private;
+ cam->vf_start_sdc = NULL;
+ cam->vf_stop_sdc = NULL;
+ cam->vf_enable_csi = NULL;
+ cam->vf_disable_csi = NULL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(foreground_sdc_deselect);
+
+/*!
+ * Init viewfinder task.
+ *
+ * @return Error code indicating success or failure
+ */
+__init int foreground_sdc_init(void)
+{
+ return 0;
+}
+
+/*!
+ * Deinit viewfinder task.
+ *
+ * @return Error code indicating success or failure
+ */
+void __exit foreground_sdc_exit(void)
+{
+}
+
+module_init(foreground_sdc_init);
+module_exit(foreground_sdc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP VF SDC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/ipu_prp_enc.c b/drivers/media/platform/mxc/capture/ipu_prp_enc.c
new file mode 100644
index 000000000000..1e4420b952f8
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/ipu_prp_enc.c
@@ -0,0 +1,597 @@
+/*
+ * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_prp_enc.c
+ *
+ * @brief IPU Use case for PRP-ENC
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/ipu.h>
+#include <linux/mipi_csi2.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+#ifdef CAMERA_DBG
+ #define CAMERA_TRACE(x) (printk)x
+#else
+ #define CAMERA_TRACE(x)
+#endif
+
+static ipu_rotate_mode_t grotation = IPU_ROTATE_NONE;
+
+/*
+ * Function definitions
+ */
+
+/*!
+ * IPU ENC callback function.
+ *
+ * @param irq int irq line
+ * @param dev_id void * device id
+ *
+ * @return status IRQ_HANDLED for handled
+ */
+static irqreturn_t prp_enc_callback(int irq, void *dev_id)
+{
+ cam_data *cam = (cam_data *) dev_id;
+
+ if (cam->enc_callback == NULL)
+ return IRQ_HANDLED;
+
+ cam->enc_callback(irq, dev_id);
+
+ return IRQ_HANDLED;
+}
+
+/*!
+ * PrpENC enable channel setup function
+ *
+ * @param cam struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int prp_enc_setup(cam_data *cam)
+{
+ ipu_channel_params_t enc;
+ int err = 0;
+ dma_addr_t dummy = cam->dummy_frame.buffer.m.offset;
+#ifdef CONFIG_MXC_MIPI_CSI2
+ void *mipi_csi2_info;
+ int ipu_id;
+ int csi_id;
+#endif
+
+ CAMERA_TRACE("In prp_enc_setup\n");
+ if (!cam) {
+ printk(KERN_ERR "cam private is NULL\n");
+ return -ENXIO;
+ }
+ memset(&enc, 0, sizeof(ipu_channel_params_t));
+
+ ipu_csi_get_window_size(cam->ipu, &enc.csi_prp_enc_mem.in_width,
+ &enc.csi_prp_enc_mem.in_height, cam->csi);
+
+ enc.csi_prp_enc_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY;
+ enc.csi_prp_enc_mem.out_width = cam->v2f.fmt.pix.width;
+ enc.csi_prp_enc_mem.out_height = cam->v2f.fmt.pix.height;
+ enc.csi_prp_enc_mem.csi = cam->csi;
+ if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+ enc.csi_prp_enc_mem.out_width = cam->v2f.fmt.pix.height;
+ enc.csi_prp_enc_mem.out_height = cam->v2f.fmt.pix.width;
+ }
+
+ if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
+ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUV420P;
+ pr_info("YUV420\n");
+ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) {
+ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YVU420P;
+ pr_info("YVU420\n");
+ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) {
+ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUV422P;
+ pr_info("YUV422P\n");
+ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) {
+ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUYV;
+ pr_info("YUYV\n");
+ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) {
+ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_UYVY;
+ pr_info("UYVY\n");
+ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) {
+ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_NV12;
+ pr_info("NV12\n");
+ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) {
+ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_BGR24;
+ pr_info("BGR24\n");
+ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
+ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB24;
+ pr_info("RGB24\n");
+ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) {
+ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB565;
+ pr_info("RGB565\n");
+ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) {
+ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_BGR32;
+ pr_info("BGR32\n");
+ } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32) {
+ enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB32;
+ pr_info("RGB32\n");
+ } else {
+ printk(KERN_ERR "format not supported\n");
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+ mipi_csi2_info = mipi_csi2_get_info();
+
+ if (mipi_csi2_info) {
+ if (mipi_csi2_get_status(mipi_csi2_info)) {
+ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+ if (cam->ipu == ipu_get_soc(ipu_id)
+ && cam->csi == csi_id) {
+ enc.csi_prp_enc_mem.mipi_en = true;
+ enc.csi_prp_enc_mem.mipi_vc =
+ mipi_csi2_get_virtual_channel(mipi_csi2_info);
+ enc.csi_prp_enc_mem.mipi_id =
+ mipi_csi2_get_datatype(mipi_csi2_info);
+
+ mipi_csi2_pixelclk_enable(mipi_csi2_info);
+ } else {
+ enc.csi_prp_enc_mem.mipi_en = false;
+ enc.csi_prp_enc_mem.mipi_vc = 0;
+ enc.csi_prp_enc_mem.mipi_id = 0;
+ }
+ } else {
+ enc.csi_prp_enc_mem.mipi_en = false;
+ enc.csi_prp_enc_mem.mipi_vc = 0;
+ enc.csi_prp_enc_mem.mipi_id = 0;
+ }
+ }
+#endif
+
+ err = ipu_init_channel(cam->ipu, CSI_PRP_ENC_MEM, &enc);
+ if (err != 0) {
+ printk(KERN_ERR "ipu_init_channel %d\n", err);
+ return err;
+ }
+
+ grotation = cam->rotation;
+ if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+ if (cam->rot_enc_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->rot_enc_buf_size[0],
+ cam->rot_enc_bufs_vaddr[0],
+ cam->rot_enc_bufs[0]);
+ }
+ if (cam->rot_enc_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->rot_enc_buf_size[1],
+ cam->rot_enc_bufs_vaddr[1],
+ cam->rot_enc_bufs[1]);
+ }
+ cam->rot_enc_buf_size[0] =
+ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
+ cam->rot_enc_bufs_vaddr[0] =
+ (void *)dma_alloc_coherent(0, cam->rot_enc_buf_size[0],
+ &cam->rot_enc_bufs[0],
+ GFP_DMA | GFP_KERNEL);
+ if (!cam->rot_enc_bufs_vaddr[0]) {
+ printk(KERN_ERR "alloc enc_bufs0\n");
+ return -ENOMEM;
+ }
+ cam->rot_enc_buf_size[1] =
+ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
+ cam->rot_enc_bufs_vaddr[1] =
+ (void *)dma_alloc_coherent(0, cam->rot_enc_buf_size[1],
+ &cam->rot_enc_bufs[1],
+ GFP_DMA | GFP_KERNEL);
+ if (!cam->rot_enc_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->rot_enc_buf_size[0],
+ cam->rot_enc_bufs_vaddr[0],
+ cam->rot_enc_bufs[0]);
+ cam->rot_enc_bufs_vaddr[0] = NULL;
+ cam->rot_enc_bufs[0] = 0;
+ printk(KERN_ERR "alloc enc_bufs1\n");
+ return -ENOMEM;
+ }
+
+ err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_ENC_MEM,
+ IPU_OUTPUT_BUFFER,
+ enc.csi_prp_enc_mem.out_pixel_fmt,
+ enc.csi_prp_enc_mem.out_width,
+ enc.csi_prp_enc_mem.out_height,
+ enc.csi_prp_enc_mem.out_width,
+ IPU_ROTATE_NONE,
+ cam->rot_enc_bufs[0],
+ cam->rot_enc_bufs[1], 0, 0, 0);
+ if (err != 0) {
+ printk(KERN_ERR "CSI_PRP_ENC_MEM err\n");
+ return err;
+ }
+
+ err = ipu_init_channel(cam->ipu, MEM_ROT_ENC_MEM, NULL);
+ if (err != 0) {
+ printk(KERN_ERR "MEM_ROT_ENC_MEM channel err\n");
+ return err;
+ }
+
+ err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_ENC_MEM,
+ IPU_INPUT_BUFFER,
+ enc.csi_prp_enc_mem.out_pixel_fmt,
+ enc.csi_prp_enc_mem.out_width,
+ enc.csi_prp_enc_mem.out_height,
+ enc.csi_prp_enc_mem.out_width,
+ cam->rotation,
+ cam->rot_enc_bufs[0],
+ cam->rot_enc_bufs[1], 0, 0, 0);
+ if (err != 0) {
+ printk(KERN_ERR "MEM_ROT_ENC_MEM input buffer\n");
+ return err;
+ }
+
+ err =
+ ipu_init_channel_buffer(cam->ipu, MEM_ROT_ENC_MEM,
+ IPU_OUTPUT_BUFFER,
+ enc.csi_prp_enc_mem.out_pixel_fmt,
+ enc.csi_prp_enc_mem.out_height,
+ enc.csi_prp_enc_mem.out_width,
+ cam->v2f.fmt.pix.bytesperline /
+ bytes_per_pixel(enc.csi_prp_enc_mem.
+ out_pixel_fmt),
+ IPU_ROTATE_NONE,
+ dummy, dummy, 0,
+ cam->offset.u_offset,
+ cam->offset.v_offset);
+ if (err != 0) {
+ printk(KERN_ERR "MEM_ROT_ENC_MEM output buffer\n");
+ return err;
+ }
+
+ err = ipu_link_channels(cam->ipu,
+ CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM);
+ if (err < 0) {
+ printk(KERN_ERR
+ "link CSI_PRP_ENC_MEM-MEM_ROT_ENC_MEM\n");
+ return err;
+ }
+
+ err = ipu_enable_channel(cam->ipu, CSI_PRP_ENC_MEM);
+ if (err < 0) {
+ printk(KERN_ERR "ipu_enable_channel CSI_PRP_ENC_MEM\n");
+ return err;
+ }
+ err = ipu_enable_channel(cam->ipu, MEM_ROT_ENC_MEM);
+ if (err < 0) {
+ printk(KERN_ERR "ipu_enable_channel MEM_ROT_ENC_MEM\n");
+ return err;
+ }
+
+ ipu_select_buffer(cam->ipu, CSI_PRP_ENC_MEM,
+ IPU_OUTPUT_BUFFER, 0);
+ ipu_select_buffer(cam->ipu, CSI_PRP_ENC_MEM,
+ IPU_OUTPUT_BUFFER, 1);
+ } else {
+ err =
+ ipu_init_channel_buffer(cam->ipu, CSI_PRP_ENC_MEM,
+ IPU_OUTPUT_BUFFER,
+ enc.csi_prp_enc_mem.out_pixel_fmt,
+ enc.csi_prp_enc_mem.out_width,
+ enc.csi_prp_enc_mem.out_height,
+ cam->v2f.fmt.pix.bytesperline /
+ bytes_per_pixel(enc.csi_prp_enc_mem.
+ out_pixel_fmt),
+ cam->rotation,
+ dummy, dummy, 0,
+ cam->offset.u_offset,
+ cam->offset.v_offset);
+ if (err != 0) {
+ printk(KERN_ERR "CSI_PRP_ENC_MEM output buffer\n");
+ return err;
+ }
+ err = ipu_enable_channel(cam->ipu, CSI_PRP_ENC_MEM);
+ if (err < 0) {
+ printk(KERN_ERR "ipu_enable_channel CSI_PRP_ENC_MEM\n");
+ return err;
+ }
+ }
+
+ return err;
+}
+
+/*!
+ * function to update physical buffer address for encorder IDMA channel
+ *
+ * @param private pointer to cam_data structure
+ * @param eba physical buffer address for encorder IDMA channel
+ *
+ * @return status
+ */
+static int prp_enc_eba_update(void *private, dma_addr_t eba)
+{
+ int err = 0;
+ cam_data *cam = (cam_data *) private;
+ struct ipu_soc *ipu = cam->ipu;
+ int *buffer_num = &cam->ping_pong_csi;
+
+ pr_debug("eba %x\n", eba);
+ if (grotation >= IPU_ROTATE_90_RIGHT) {
+ err = ipu_update_channel_buffer(ipu, MEM_ROT_ENC_MEM,
+ IPU_OUTPUT_BUFFER, *buffer_num,
+ eba);
+ } else {
+ err = ipu_update_channel_buffer(ipu, CSI_PRP_ENC_MEM,
+ IPU_OUTPUT_BUFFER, *buffer_num,
+ eba);
+ }
+ if (err != 0) {
+ if (grotation >= IPU_ROTATE_90_RIGHT) {
+ ipu_clear_buffer_ready(ipu, MEM_ROT_ENC_MEM,
+ IPU_OUTPUT_BUFFER,
+ *buffer_num);
+ err = ipu_update_channel_buffer(ipu, MEM_ROT_ENC_MEM,
+ IPU_OUTPUT_BUFFER,
+ *buffer_num,
+ eba);
+ } else {
+ ipu_clear_buffer_ready(ipu, CSI_PRP_ENC_MEM,
+ IPU_OUTPUT_BUFFER,
+ *buffer_num);
+ err = ipu_update_channel_buffer(ipu, CSI_PRP_ENC_MEM,
+ IPU_OUTPUT_BUFFER,
+ *buffer_num,
+ eba);
+ }
+
+ if (err != 0) {
+ pr_err("ERROR: v4l2 capture: fail to update "
+ "buf%d\n", *buffer_num);
+ return err;
+ }
+ }
+
+ if (grotation >= IPU_ROTATE_90_RIGHT) {
+ ipu_select_buffer(ipu, MEM_ROT_ENC_MEM, IPU_OUTPUT_BUFFER,
+ *buffer_num);
+ } else {
+ ipu_select_buffer(ipu, CSI_PRP_ENC_MEM, IPU_OUTPUT_BUFFER,
+ *buffer_num);
+ }
+
+ *buffer_num = (*buffer_num == 0) ? 1 : 0;
+ return 0;
+}
+
+/*!
+ * Enable encoder task
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int prp_enc_enabling_tasks(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ int err = 0;
+ CAMERA_TRACE("IPU:In prp_enc_enabling_tasks\n");
+
+ cam->dummy_frame.vaddress = dma_alloc_coherent(0,
+ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
+ &cam->dummy_frame.paddress,
+ GFP_DMA | GFP_KERNEL);
+ if (cam->dummy_frame.vaddress == 0) {
+ pr_err("ERROR: v4l2 capture: Allocate dummy frame "
+ "failed.\n");
+ return -ENOBUFS;
+ }
+ cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE;
+ cam->dummy_frame.buffer.length =
+ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
+ cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress;
+
+ if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+ err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_ENC_ROT_OUT_EOF,
+ prp_enc_callback, 0, "Mxc Camera", cam);
+ } else {
+ err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_ENC_OUT_EOF,
+ prp_enc_callback, 0, "Mxc Camera", cam);
+ }
+ if (err != 0) {
+ printk(KERN_ERR "Error registering rot irq\n");
+ return err;
+ }
+
+ err = prp_enc_setup(cam);
+ if (err != 0) {
+ printk(KERN_ERR "prp_enc_setup %d\n", err);
+ return err;
+ }
+
+ return err;
+}
+
+/*!
+ * Disable encoder task
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return int
+ */
+static int prp_enc_disabling_tasks(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ int err = 0;
+#ifdef CONFIG_MXC_MIPI_CSI2
+ void *mipi_csi2_info;
+ int ipu_id;
+ int csi_id;
+#endif
+
+ if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+ ipu_free_irq(cam->ipu, IPU_IRQ_PRP_ENC_ROT_OUT_EOF, cam);
+ ipu_unlink_channels(cam->ipu, CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM);
+ }
+
+ err = ipu_disable_channel(cam->ipu, CSI_PRP_ENC_MEM, true);
+ if (cam->rotation >= IPU_ROTATE_90_RIGHT)
+ err |= ipu_disable_channel(cam->ipu, MEM_ROT_ENC_MEM, true);
+
+ ipu_uninit_channel(cam->ipu, CSI_PRP_ENC_MEM);
+ if (cam->rotation >= IPU_ROTATE_90_RIGHT)
+ ipu_uninit_channel(cam->ipu, MEM_ROT_ENC_MEM);
+
+ if (cam->dummy_frame.vaddress != 0) {
+ dma_free_coherent(0, cam->dummy_frame.buffer.length,
+ cam->dummy_frame.vaddress,
+ cam->dummy_frame.paddress);
+ cam->dummy_frame.vaddress = 0;
+ }
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+ mipi_csi2_info = mipi_csi2_get_info();
+
+ if (mipi_csi2_info) {
+ if (mipi_csi2_get_status(mipi_csi2_info)) {
+ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+ if (cam->ipu == ipu_get_soc(ipu_id)
+ && cam->csi == csi_id)
+ mipi_csi2_pixelclk_disable(mipi_csi2_info);
+ }
+ }
+#endif
+
+ return err;
+}
+
+/*!
+ * Enable csi
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int prp_enc_enable_csi(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+
+ return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int prp_enc_disable_csi(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+
+ /* free csi eof irq firstly.
+ * when disable csi, wait for idmac eof.
+ * it requests eof irq again */
+ if (cam->rotation < IPU_ROTATE_90_RIGHT)
+ ipu_free_irq(cam->ipu, IPU_IRQ_PRP_ENC_OUT_EOF, cam);
+
+ return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select PRP-ENC as the working path
+ *
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return int
+ */
+int prp_enc_select(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ int err = 0;
+
+ if (cam) {
+ cam->enc_update_eba = prp_enc_eba_update;
+ cam->enc_enable = prp_enc_enabling_tasks;
+ cam->enc_disable = prp_enc_disabling_tasks;
+ cam->enc_enable_csi = prp_enc_enable_csi;
+ cam->enc_disable_csi = prp_enc_disable_csi;
+ } else {
+ err = -EIO;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(prp_enc_select);
+
+/*!
+ * function to de-select PRP-ENC as the working path
+ *
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return int
+ */
+int prp_enc_deselect(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ int err = 0;
+
+ if (cam) {
+ cam->enc_update_eba = NULL;
+ cam->enc_enable = NULL;
+ cam->enc_disable = NULL;
+ cam->enc_enable_csi = NULL;
+ cam->enc_disable_csi = NULL;
+ if (cam->rot_enc_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->rot_enc_buf_size[0],
+ cam->rot_enc_bufs_vaddr[0],
+ cam->rot_enc_bufs[0]);
+ cam->rot_enc_bufs_vaddr[0] = NULL;
+ cam->rot_enc_bufs[0] = 0;
+ }
+ if (cam->rot_enc_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->rot_enc_buf_size[1],
+ cam->rot_enc_bufs_vaddr[1],
+ cam->rot_enc_bufs[1]);
+ cam->rot_enc_bufs_vaddr[1] = NULL;
+ cam->rot_enc_bufs[1] = 0;
+ }
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(prp_enc_deselect);
+
+/*!
+ * Init the Encorder channels
+ *
+ * @return Error code indicating success or failure
+ */
+__init int prp_enc_init(void)
+{
+ return 0;
+}
+
+/*!
+ * Deinit the Encorder channels
+ *
+ */
+void __exit prp_enc_exit(void)
+{
+}
+
+module_init(prp_enc_init);
+module_exit(prp_enc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP ENC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/ipu_prp_sw.h b/drivers/media/platform/mxc/capture/ipu_prp_sw.h
new file mode 100644
index 000000000000..be02ab061e20
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/ipu_prp_sw.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_prp_sw.h
+ *
+ * @brief This file contains the IPU PRP use case driver header.
+ *
+ * @ingroup IPU
+ */
+
+#ifndef _INCLUDE_IPU__PRP_SW_H_
+#define _INCLUDE_IPU__PRP_SW_H_
+
+int csi_enc_select(void *private);
+int csi_enc_deselect(void *private);
+int prp_enc_select(void *private);
+int prp_enc_deselect(void *private);
+#ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+int prp_vf_sdc_select(void *private);
+int prp_vf_sdc_deselect(void *private);
+int prp_vf_sdc_select_bg(void *private);
+int prp_vf_sdc_deselect_bg(void *private);
+#else
+int foreground_sdc_select(void *private);
+int foreground_sdc_deselect(void *private);
+int bg_overlay_sdc_select(void *private);
+int bg_overlay_sdc_deselect(void *private);
+#endif
+int prp_still_select(void *private);
+int prp_still_deselect(void *private);
+
+#endif
diff --git a/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c b/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c
new file mode 100644
index 000000000000..b9610f1ed820
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c
@@ -0,0 +1,582 @@
+/*
+ * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+/* * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_prp_vf_sdc.c
+ *
+ * @brief IPU Use case for PRP-VF
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/console.h>
+#include <linux/ipu.h>
+#include <linux/module.h>
+#include <linux/mxcfb.h>
+#include <mach/hardware.h>
+#include <mach/mipi_csi2.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+static int buffer_num;
+static struct ipu_soc *disp_ipu;
+
+static void get_disp_ipu(cam_data *cam)
+{
+ if (cam->output > 2)
+ disp_ipu = ipu_get_soc(1); /* using DISP4 */
+ else
+ disp_ipu = ipu_get_soc(0);
+}
+
+static irqreturn_t prpvf_rot_eof_callback(int irq, void *dev_id)
+{
+ cam_data *cam = dev_id;
+ pr_debug("buffer_num %d\n", buffer_num);
+
+ if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
+ ipu_select_buffer(disp_ipu, MEM_FG_SYNC,
+ IPU_INPUT_BUFFER, buffer_num);
+ buffer_num = (buffer_num == 0) ? 1 : 0;
+ ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
+ IPU_OUTPUT_BUFFER, buffer_num);
+ } else {
+ ipu_select_buffer(disp_ipu, MEM_FG_SYNC,
+ IPU_INPUT_BUFFER, buffer_num);
+ buffer_num = (buffer_num == 0) ? 1 : 0;
+ ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
+ IPU_OUTPUT_BUFFER, buffer_num);
+ }
+ return IRQ_HANDLED;
+}
+/*
+ * Function definitions
+ */
+
+/*!
+ * prpvf_start - start the vf task
+ *
+ * @param private cam_data * mxc v4l2 main structure
+ *
+ */
+static int prpvf_start(void *private)
+{
+ struct fb_var_screeninfo fbvar;
+ struct fb_info *fbi = NULL;
+ cam_data *cam = (cam_data *) private;
+ ipu_channel_params_t vf;
+ u32 vf_out_format = 0;
+ u32 size = 2, temp = 0;
+ int err = 0, i = 0;
+ short *tmp, color;
+#ifdef CONFIG_MXC_MIPI_CSI2
+ void *mipi_csi2_info;
+ int ipu_id;
+ int csi_id;
+#endif
+
+ if (!cam) {
+ printk(KERN_ERR "private is NULL\n");
+ return -EIO;
+ }
+
+ if (cam->overlay_active == true) {
+ pr_debug("already started.\n");
+ return 0;
+ }
+
+ get_disp_ipu(cam);
+
+ for (i = 0; i < num_registered_fb; i++) {
+ char *idstr = registered_fb[i]->fix.id;
+ if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
+ ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
+ fbi = registered_fb[i];
+ break;
+ }
+ }
+
+ if (fbi == NULL) {
+ printk(KERN_ERR "DISP FG fb not found\n");
+ return -EPERM;
+ }
+
+ fbvar = fbi->var;
+
+ /* Store the overlay frame buffer's original std */
+ cam->fb_origin_std = fbvar.nonstd;
+
+ if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) {
+ /* Use DP to do CSC so that we can get better performance */
+ vf_out_format = IPU_PIX_FMT_UYVY;
+ fbvar.nonstd = vf_out_format;
+ color = 0x80;
+ } else {
+ vf_out_format = IPU_PIX_FMT_RGB565;
+ fbvar.nonstd = 0;
+ color = 0x0;
+ }
+
+ fbvar.bits_per_pixel = 16;
+ fbvar.xres = fbvar.xres_virtual = cam->win.w.width;
+ fbvar.yres = cam->win.w.height;
+ fbvar.yres_virtual = cam->win.w.height * 2;
+ fbvar.yoffset = 0;
+ fbvar.accel_flags = FB_ACCEL_DOUBLE_FLAG;
+ fbvar.activate |= FB_ACTIVATE_FORCE;
+ fb_set_var(fbi, &fbvar);
+
+ ipu_disp_set_window_pos(disp_ipu, MEM_FG_SYNC, cam->win.w.left,
+ cam->win.w.top);
+
+ /* Fill black color for framebuffer */
+ tmp = (short *) fbi->screen_base;
+ for (i = 0; i < (fbi->fix.line_length * fbi->var.yres)/2;
+ i++, tmp++)
+ *tmp = color;
+
+ console_lock();
+ fb_blank(fbi, FB_BLANK_UNBLANK);
+ console_unlock();
+
+ /* correct display ch buffer address */
+ ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
+ 0, fbi->fix.smem_start +
+ (fbi->fix.line_length * fbvar.yres));
+ ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER,
+ 1, fbi->fix.smem_start);
+
+ memset(&vf, 0, sizeof(ipu_channel_params_t));
+ ipu_csi_get_window_size(cam->ipu, &vf.csi_prp_vf_mem.in_width,
+ &vf.csi_prp_vf_mem.in_height, cam->csi);
+ vf.csi_prp_vf_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY;
+ vf.csi_prp_vf_mem.out_width = cam->win.w.width;
+ vf.csi_prp_vf_mem.out_height = cam->win.w.height;
+ vf.csi_prp_vf_mem.csi = cam->csi;
+ if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
+ vf.csi_prp_vf_mem.out_width = cam->win.w.height;
+ vf.csi_prp_vf_mem.out_height = cam->win.w.width;
+ }
+ vf.csi_prp_vf_mem.out_pixel_fmt = vf_out_format;
+ size = cam->win.w.width * cam->win.w.height * size;
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+ mipi_csi2_info = mipi_csi2_get_info();
+
+ if (mipi_csi2_info) {
+ if (mipi_csi2_get_status(mipi_csi2_info)) {
+ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+ if (cam->ipu == ipu_get_soc(ipu_id)
+ && cam->csi == csi_id) {
+ vf.csi_prp_vf_mem.mipi_en = true;
+ vf.csi_prp_vf_mem.mipi_vc =
+ mipi_csi2_get_virtual_channel(mipi_csi2_info);
+ vf.csi_prp_vf_mem.mipi_id =
+ mipi_csi2_get_datatype(mipi_csi2_info);
+
+ mipi_csi2_pixelclk_enable(mipi_csi2_info);
+ } else {
+ vf.csi_prp_vf_mem.mipi_en = false;
+ vf.csi_prp_vf_mem.mipi_vc = 0;
+ vf.csi_prp_vf_mem.mipi_id = 0;
+ }
+ } else {
+ vf.csi_prp_vf_mem.mipi_en = false;
+ vf.csi_prp_vf_mem.mipi_vc = 0;
+ vf.csi_prp_vf_mem.mipi_id = 0;
+ }
+ }
+#endif
+
+ err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf);
+ if (err != 0)
+ goto out_5;
+
+ if (cam->vf_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->vf_bufs_size[0],
+ cam->vf_bufs_vaddr[0],
+ (dma_addr_t) cam->vf_bufs[0]);
+ }
+ if (cam->vf_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->vf_bufs_size[1],
+ cam->vf_bufs_vaddr[1],
+ (dma_addr_t) cam->vf_bufs[1]);
+ }
+ cam->vf_bufs_size[0] = PAGE_ALIGN(size);
+ cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
+ cam->vf_bufs_size[0],
+ (dma_addr_t *) &
+ cam->vf_bufs[0],
+ GFP_DMA |
+ GFP_KERNEL);
+ if (cam->vf_bufs_vaddr[0] == NULL) {
+ printk(KERN_ERR "Error to allocate vf buffer\n");
+ err = -ENOMEM;
+ goto out_4;
+ }
+ cam->vf_bufs_size[1] = PAGE_ALIGN(size);
+ cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
+ cam->vf_bufs_size[1],
+ (dma_addr_t *) &
+ cam->vf_bufs[1],
+ GFP_DMA |
+ GFP_KERNEL);
+ if (cam->vf_bufs_vaddr[1] == NULL) {
+ printk(KERN_ERR "Error to allocate vf buffer\n");
+ err = -ENOMEM;
+ goto out_3;
+ }
+ pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]);
+
+ if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
+ err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
+ IPU_OUTPUT_BUFFER,
+ vf_out_format,
+ vf.csi_prp_vf_mem.out_width,
+ vf.csi_prp_vf_mem.out_height,
+ vf.csi_prp_vf_mem.out_width,
+ IPU_ROTATE_NONE,
+ cam->vf_bufs[0], cam->vf_bufs[1],
+ 0, 0, 0);
+ if (err != 0)
+ goto out_3;
+
+ err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL);
+ if (err != 0) {
+ printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n");
+ goto out_3;
+ }
+
+ err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
+ IPU_INPUT_BUFFER,
+ vf_out_format,
+ vf.csi_prp_vf_mem.out_width,
+ vf.csi_prp_vf_mem.out_height,
+ vf.csi_prp_vf_mem.out_width,
+ cam->vf_rotation,
+ cam->vf_bufs[0],
+ cam->vf_bufs[1],
+ 0, 0, 0);
+ if (err != 0) {
+ printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n");
+ goto out_2;
+ }
+
+ if (cam->vf_rotation < IPU_ROTATE_90_RIGHT) {
+ temp = vf.csi_prp_vf_mem.out_width;
+ vf.csi_prp_vf_mem.out_width =
+ vf.csi_prp_vf_mem.out_height;
+ vf.csi_prp_vf_mem.out_height = temp;
+ }
+
+ err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
+ IPU_OUTPUT_BUFFER,
+ vf_out_format,
+ vf.csi_prp_vf_mem.out_height,
+ vf.csi_prp_vf_mem.out_width,
+ vf.csi_prp_vf_mem.out_height,
+ IPU_ROTATE_NONE,
+ fbi->fix.smem_start +
+ (fbi->fix.line_length *
+ fbi->var.yres),
+ fbi->fix.smem_start, 0, 0, 0);
+
+ if (err != 0) {
+ printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
+ goto out_2;
+ }
+
+ ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF);
+ err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF,
+ prpvf_rot_eof_callback,
+ 0, "Mxc Camera", cam);
+ if (err < 0) {
+ printk(KERN_ERR "Error request irq:IPU_IRQ_PRP_VF_ROT_OUT_EOF\n");
+ goto out_2;
+ }
+
+ err = ipu_link_channels(cam->ipu,
+ CSI_PRP_VF_MEM, MEM_ROT_VF_MEM);
+ if (err < 0) {
+ printk(KERN_ERR
+ "Error link CSI_PRP_VF_MEM-MEM_ROT_VF_MEM\n");
+ goto out_1;
+ }
+
+ ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
+ ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM);
+
+ ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
+ IPU_OUTPUT_BUFFER, 0);
+ ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
+ IPU_OUTPUT_BUFFER, 1);
+ ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
+ IPU_OUTPUT_BUFFER, 0);
+ } else {
+ err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
+ IPU_OUTPUT_BUFFER,
+ vf_out_format, cam->win.w.width,
+ cam->win.w.height,
+ cam->win.w.width,
+ cam->vf_rotation,
+ fbi->fix.smem_start +
+ (fbi->fix.line_length *
+ fbi->var.yres),
+ fbi->fix.smem_start, 0, 0, 0);
+ if (err != 0) {
+ printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n");
+ goto out_4;
+ }
+ ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF);
+ err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF,
+ prpvf_rot_eof_callback,
+ 0, "Mxc Camera", cam);
+ if (err < 0) {
+ printk(KERN_ERR "Error request irq:IPU_IRQ_PRP_VF_OUT_EOF\n");
+ goto out_4;
+ }
+
+ ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
+
+ ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
+ IPU_OUTPUT_BUFFER, 0);
+ }
+
+ cam->overlay_active = true;
+ return err;
+
+out_1:
+ ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL);
+out_2:
+ if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP)
+ ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
+out_3:
+ if (cam->vf_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->vf_bufs_size[0],
+ cam->vf_bufs_vaddr[0],
+ (dma_addr_t) cam->vf_bufs[0]);
+ cam->vf_bufs_vaddr[0] = NULL;
+ cam->vf_bufs[0] = 0;
+ }
+ if (cam->vf_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->vf_bufs_size[1],
+ cam->vf_bufs_vaddr[1],
+ (dma_addr_t) cam->vf_bufs[1]);
+ cam->vf_bufs_vaddr[1] = NULL;
+ cam->vf_bufs[1] = 0;
+ }
+out_4:
+ ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
+out_5:
+ return err;
+}
+
+/*!
+ * prpvf_stop - stop the vf task
+ *
+ * @param private cam_data * mxc v4l2 main structure
+ *
+ */
+static int prpvf_stop(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ int err = 0, i = 0;
+ struct fb_info *fbi = NULL;
+ struct fb_var_screeninfo fbvar;
+#ifdef CONFIG_MXC_MIPI_CSI2
+ void *mipi_csi2_info;
+ int ipu_id;
+ int csi_id;
+#endif
+
+ if (cam->overlay_active == false)
+ return 0;
+
+ for (i = 0; i < num_registered_fb; i++) {
+ char *idstr = registered_fb[i]->fix.id;
+ if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) ||
+ ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) {
+ fbi = registered_fb[i];
+ break;
+ }
+ }
+
+ if (fbi == NULL) {
+ printk(KERN_ERR "DISP FG fb not found\n");
+ return -EPERM;
+ }
+
+ if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
+ ipu_unlink_channels(cam->ipu, CSI_PRP_VF_MEM, MEM_ROT_VF_MEM);
+ ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF, cam);
+ }
+ buffer_num = 0;
+
+ ipu_disable_channel(cam->ipu, CSI_PRP_VF_MEM, true);
+
+ if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) {
+ ipu_disable_channel(cam->ipu, MEM_ROT_VF_MEM, true);
+ ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
+ }
+ ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
+
+ console_lock();
+ fb_blank(fbi, FB_BLANK_POWERDOWN);
+ console_unlock();
+
+ /* Set the overlay frame buffer std to what it is used to be */
+ fbvar = fbi->var;
+ fbvar.accel_flags = FB_ACCEL_TRIPLE_FLAG;
+ fbvar.nonstd = cam->fb_origin_std;
+ fbvar.activate |= FB_ACTIVATE_FORCE;
+ fb_set_var(fbi, &fbvar);
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+ mipi_csi2_info = mipi_csi2_get_info();
+
+ if (mipi_csi2_info) {
+ if (mipi_csi2_get_status(mipi_csi2_info)) {
+ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+ if (cam->ipu == ipu_get_soc(ipu_id)
+ && cam->csi == csi_id)
+ mipi_csi2_pixelclk_disable(mipi_csi2_info);
+ }
+ }
+#endif
+
+ if (cam->vf_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->vf_bufs_size[0],
+ cam->vf_bufs_vaddr[0],
+ (dma_addr_t) cam->vf_bufs[0]);
+ cam->vf_bufs_vaddr[0] = NULL;
+ cam->vf_bufs[0] = 0;
+ }
+ if (cam->vf_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->vf_bufs_size[1],
+ cam->vf_bufs_vaddr[1],
+ (dma_addr_t) cam->vf_bufs[1]);
+ cam->vf_bufs_vaddr[1] = NULL;
+ cam->vf_bufs[1] = 0;
+ }
+
+ cam->overlay_active = false;
+ return err;
+}
+
+/*!
+ * Enable csi
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int prp_vf_enable_csi(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+
+ return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int prp_vf_disable_csi(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+
+ /* free csi eof irq firstly.
+ * when disable csi, wait for idmac eof.
+ * it requests eof irq again */
+ if (cam->vf_rotation < IPU_ROTATE_VERT_FLIP)
+ ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, cam);
+
+ return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select PRP-VF as the working path
+ *
+ * @param private cam_data * mxc v4l2 main structure
+ *
+ * @return status
+ */
+int prp_vf_sdc_select(void *private)
+{
+ cam_data *cam;
+ int err = 0;
+ if (private) {
+ cam = (cam_data *) private;
+ cam->vf_start_sdc = prpvf_start;
+ cam->vf_stop_sdc = prpvf_stop;
+ cam->vf_enable_csi = prp_vf_enable_csi;
+ cam->vf_disable_csi = prp_vf_disable_csi;
+ cam->overlay_active = false;
+ } else
+ err = -EIO;
+
+ return err;
+}
+EXPORT_SYMBOL(prp_vf_sdc_select);
+
+/*!
+ * function to de-select PRP-VF as the working path
+ *
+ * @param private cam_data * mxc v4l2 main structure
+ *
+ * @return int
+ */
+int prp_vf_sdc_deselect(void *private)
+{
+ cam_data *cam;
+
+ if (private) {
+ cam = (cam_data *) private;
+ cam->vf_start_sdc = NULL;
+ cam->vf_stop_sdc = NULL;
+ cam->vf_enable_csi = NULL;
+ cam->vf_disable_csi = NULL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(prp_vf_sdc_deselect);
+
+/*!
+ * Init viewfinder task.
+ *
+ * @return Error code indicating success or failure
+ */
+__init int prp_vf_sdc_init(void)
+{
+ return 0;
+}
+
+/*!
+ * Deinit viewfinder task.
+ *
+ * @return Error code indicating success or failure
+ */
+void __exit prp_vf_sdc_exit(void)
+{
+}
+
+module_init(prp_vf_sdc_init);
+module_exit(prp_vf_sdc_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP VF SDC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c b/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c
new file mode 100644
index 000000000000..a24d82dfca63
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_prp_vf_sdc_bg.c
+ *
+ * @brief IPU Use case for PRP-VF back-ground
+ *
+ * @ingroup IPU
+ */
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+#include <linux/ipu.h>
+#include <linux/module.h>
+#include <mach/mipi_csi2.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+static int buffer_num;
+static int buffer_ready;
+static struct ipu_soc *disp_ipu;
+
+static void get_disp_ipu(cam_data *cam)
+{
+ if (cam->output > 2)
+ disp_ipu = ipu_get_soc(1); /* using DISP4 */
+ else
+ disp_ipu = ipu_get_soc(0);
+}
+
+/*
+ * Function definitions
+ */
+
+/*!
+ * SDC V-Sync callback function.
+ *
+ * @param irq int irq line
+ * @param dev_id void * device id
+ *
+ * @return status IRQ_HANDLED for handled
+ */
+static irqreturn_t prpvf_sdc_vsync_callback(int irq, void *dev_id)
+{
+ cam_data *cam = dev_id;
+ if (buffer_ready > 0) {
+ ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
+ IPU_OUTPUT_BUFFER, 0);
+ buffer_ready--;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*!
+ * VF EOF callback function.
+ *
+ * @param irq int irq line
+ * @param dev_id void * device id
+ *
+ * @return status IRQ_HANDLED for handled
+ */
+static irqreturn_t prpvf_vf_eof_callback(int irq, void *dev_id)
+{
+ cam_data *cam = dev_id;
+ pr_debug("buffer_ready %d buffer_num %d\n", buffer_ready, buffer_num);
+
+ ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM,
+ IPU_INPUT_BUFFER, buffer_num);
+ buffer_num = (buffer_num == 0) ? 1 : 0;
+ ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM,
+ IPU_OUTPUT_BUFFER, buffer_num);
+ buffer_ready++;
+ return IRQ_HANDLED;
+}
+
+/*!
+ * prpvf_start - start the vf task
+ *
+ * @param private cam_data * mxc v4l2 main structure
+ *
+ */
+static int prpvf_start(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ ipu_channel_params_t vf;
+ u32 format;
+ u32 offset;
+ u32 bpp, size = 3;
+ int err = 0;
+#ifdef CONFIG_MXC_MIPI_CSI2
+ void *mipi_csi2_info;
+ int ipu_id;
+ int csi_id;
+#endif
+
+ if (!cam) {
+ printk(KERN_ERR "private is NULL\n");
+ return -EIO;
+ }
+
+ if (cam->overlay_active == true) {
+ pr_debug("already start.\n");
+ return 0;
+ }
+
+ get_disp_ipu(cam);
+
+ format = cam->v4l2_fb.fmt.pixelformat;
+ if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) {
+ bpp = 3, size = 3;
+ pr_info("BGR24\n");
+ } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) {
+ bpp = 2, size = 2;
+ pr_info("RGB565\n");
+ } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) {
+ bpp = 4, size = 4;
+ pr_info("BGR32\n");
+ } else {
+ printk(KERN_ERR
+ "unsupported fix format from the framebuffer.\n");
+ return -EINVAL;
+ }
+
+ offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top +
+ size * cam->win.w.left;
+
+ if (cam->v4l2_fb.base == 0)
+ printk(KERN_ERR "invalid frame buffer address.\n");
+ else
+ offset += (u32) cam->v4l2_fb.base;
+
+ memset(&vf, 0, sizeof(ipu_channel_params_t));
+ ipu_csi_get_window_size(cam->ipu, &vf.csi_prp_vf_mem.in_width,
+ &vf.csi_prp_vf_mem.in_height, cam->csi);
+ vf.csi_prp_vf_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY;
+ vf.csi_prp_vf_mem.out_width = cam->win.w.width;
+ vf.csi_prp_vf_mem.out_height = cam->win.w.height;
+ vf.csi_prp_vf_mem.csi = cam->csi;
+ if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
+ vf.csi_prp_vf_mem.out_width = cam->win.w.height;
+ vf.csi_prp_vf_mem.out_height = cam->win.w.width;
+ }
+ vf.csi_prp_vf_mem.out_pixel_fmt = format;
+ size = cam->win.w.width * cam->win.w.height * size;
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+ mipi_csi2_info = mipi_csi2_get_info();
+
+ if (mipi_csi2_info) {
+ if (mipi_csi2_get_status(mipi_csi2_info)) {
+ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+ if (cam->ipu == ipu_get_soc(ipu_id)
+ && cam->csi == csi_id) {
+ vf.csi_prp_vf_mem.mipi_en = true;
+ vf.csi_prp_vf_mem.mipi_vc =
+ mipi_csi2_get_virtual_channel(mipi_csi2_info);
+ vf.csi_prp_vf_mem.mipi_id =
+ mipi_csi2_get_datatype(mipi_csi2_info);
+
+ mipi_csi2_pixelclk_enable(mipi_csi2_info);
+ } else {
+ vf.csi_prp_vf_mem.mipi_en = false;
+ vf.csi_prp_vf_mem.mipi_vc = 0;
+ vf.csi_prp_vf_mem.mipi_id = 0;
+ }
+ } else {
+ vf.csi_prp_vf_mem.mipi_en = false;
+ vf.csi_prp_vf_mem.mipi_vc = 0;
+ vf.csi_prp_vf_mem.mipi_id = 0;
+ }
+ }
+#endif
+
+ err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf);
+ if (err != 0)
+ goto out_4;
+
+ if (cam->vf_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->vf_bufs_size[0],
+ cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
+ }
+ if (cam->vf_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->vf_bufs_size[1],
+ cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
+ }
+ cam->vf_bufs_size[0] = PAGE_ALIGN(size);
+ cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0,
+ cam->vf_bufs_size[0],
+ &cam->vf_bufs[0],
+ GFP_DMA |
+ GFP_KERNEL);
+ if (cam->vf_bufs_vaddr[0] == NULL) {
+ printk(KERN_ERR "Error to allocate vf buffer\n");
+ err = -ENOMEM;
+ goto out_3;
+ }
+ cam->vf_bufs_size[1] = PAGE_ALIGN(size);
+ cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0,
+ cam->vf_bufs_size[1],
+ &cam->vf_bufs[1],
+ GFP_DMA |
+ GFP_KERNEL);
+ if (cam->vf_bufs_vaddr[1] == NULL) {
+ printk(KERN_ERR "Error to allocate vf buffer\n");
+ err = -ENOMEM;
+ goto out_3;
+ }
+
+ err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM,
+ IPU_OUTPUT_BUFFER,
+ format, vf.csi_prp_vf_mem.out_width,
+ vf.csi_prp_vf_mem.out_height,
+ vf.csi_prp_vf_mem.out_width,
+ IPU_ROTATE_NONE,
+ cam->vf_bufs[0],
+ cam->vf_bufs[1],
+ 0, 0, 0);
+ if (err != 0) {
+ printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n");
+ goto out_3;
+ }
+ err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL);
+ if (err != 0) {
+ printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n");
+ goto out_3;
+ }
+
+ err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
+ IPU_INPUT_BUFFER,
+ format, vf.csi_prp_vf_mem.out_width,
+ vf.csi_prp_vf_mem.out_height,
+ vf.csi_prp_vf_mem.out_width,
+ cam->vf_rotation,
+ cam->vf_bufs[0],
+ cam->vf_bufs[1],
+ 0, 0, 0);
+ if (err != 0) {
+ printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n");
+ goto out_2;
+ }
+
+ if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) {
+ err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
+ IPU_OUTPUT_BUFFER,
+ format,
+ vf.csi_prp_vf_mem.out_height,
+ vf.csi_prp_vf_mem.out_width,
+ cam->overlay_fb->var.xres * bpp,
+ IPU_ROTATE_NONE,
+ offset, 0, 0, 0, 0);
+
+ if (err != 0) {
+ printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
+ goto out_2;
+ }
+ } else {
+ err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM,
+ IPU_OUTPUT_BUFFER,
+ format,
+ vf.csi_prp_vf_mem.out_width,
+ vf.csi_prp_vf_mem.out_height,
+ cam->overlay_fb->var.xres * bpp,
+ IPU_ROTATE_NONE,
+ offset, 0, 0, 0, 0);
+ if (err != 0) {
+ printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n");
+ goto out_2;
+ }
+ }
+
+ ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF);
+ err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF,
+ prpvf_vf_eof_callback,
+ 0, "Mxc Camera", cam);
+ if (err != 0) {
+ printk(KERN_ERR
+ "Error registering IPU_IRQ_PRP_VF_OUT_EOF irq.\n");
+ goto out_2;
+ }
+
+ ipu_clear_irq(disp_ipu, IPU_IRQ_BG_SF_END);
+ err = ipu_request_irq(disp_ipu, IPU_IRQ_BG_SF_END,
+ prpvf_sdc_vsync_callback,
+ 0, "Mxc Camera", cam);
+ if (err != 0) {
+ printk(KERN_ERR "Error registering IPU_IRQ_BG_SF_END irq.\n");
+ goto out_1;
+ }
+
+ ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM);
+ ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM);
+
+ buffer_num = 0;
+ buffer_ready = 0;
+ ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, 0);
+
+ cam->overlay_active = true;
+ return err;
+
+out_1:
+ ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL);
+out_2:
+ ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
+out_3:
+ ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
+out_4:
+ if (cam->vf_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->vf_bufs_size[0],
+ cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
+ cam->vf_bufs_vaddr[0] = NULL;
+ cam->vf_bufs[0] = 0;
+ }
+ if (cam->vf_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->vf_bufs_size[1],
+ cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
+ cam->vf_bufs_vaddr[1] = NULL;
+ cam->vf_bufs[1] = 0;
+ }
+ if (cam->rot_vf_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->rot_vf_buf_size[0],
+ cam->rot_vf_bufs_vaddr[0],
+ cam->rot_vf_bufs[0]);
+ cam->rot_vf_bufs_vaddr[0] = NULL;
+ cam->rot_vf_bufs[0] = 0;
+ }
+ if (cam->rot_vf_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->rot_vf_buf_size[1],
+ cam->rot_vf_bufs_vaddr[1],
+ cam->rot_vf_bufs[1]);
+ cam->rot_vf_bufs_vaddr[1] = NULL;
+ cam->rot_vf_bufs[1] = 0;
+ }
+ return err;
+}
+
+/*!
+ * prpvf_stop - stop the vf task
+ *
+ * @param private cam_data * mxc v4l2 main structure
+ *
+ */
+static int prpvf_stop(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+#ifdef CONFIG_MXC_MIPI_CSI2
+ void *mipi_csi2_info;
+ int ipu_id;
+ int csi_id;
+#endif
+
+ if (cam->overlay_active == false)
+ return 0;
+
+ ipu_free_irq(disp_ipu, IPU_IRQ_BG_SF_END, cam);
+
+ ipu_disable_channel(cam->ipu, CSI_PRP_VF_MEM, true);
+ ipu_disable_channel(cam->ipu, MEM_ROT_VF_MEM, true);
+ ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM);
+ ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM);
+
+#ifdef CONFIG_MXC_MIPI_CSI2
+ mipi_csi2_info = mipi_csi2_get_info();
+
+ if (mipi_csi2_info) {
+ if (mipi_csi2_get_status(mipi_csi2_info)) {
+ ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info);
+ csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info);
+
+ if (cam->ipu == ipu_get_soc(ipu_id)
+ && cam->csi == csi_id)
+ mipi_csi2_pixelclk_disable(mipi_csi2_info);
+ }
+ }
+#endif
+
+ if (cam->vf_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->vf_bufs_size[0],
+ cam->vf_bufs_vaddr[0], cam->vf_bufs[0]);
+ cam->vf_bufs_vaddr[0] = NULL;
+ cam->vf_bufs[0] = 0;
+ }
+ if (cam->vf_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->vf_bufs_size[1],
+ cam->vf_bufs_vaddr[1], cam->vf_bufs[1]);
+ cam->vf_bufs_vaddr[1] = NULL;
+ cam->vf_bufs[1] = 0;
+ }
+ if (cam->rot_vf_bufs_vaddr[0]) {
+ dma_free_coherent(0, cam->rot_vf_buf_size[0],
+ cam->rot_vf_bufs_vaddr[0],
+ cam->rot_vf_bufs[0]);
+ cam->rot_vf_bufs_vaddr[0] = NULL;
+ cam->rot_vf_bufs[0] = 0;
+ }
+ if (cam->rot_vf_bufs_vaddr[1]) {
+ dma_free_coherent(0, cam->rot_vf_buf_size[1],
+ cam->rot_vf_bufs_vaddr[1],
+ cam->rot_vf_bufs[1]);
+ cam->rot_vf_bufs_vaddr[1] = NULL;
+ cam->rot_vf_bufs[1] = 0;
+ }
+
+ buffer_num = 0;
+ buffer_ready = 0;
+ cam->overlay_active = false;
+ return 0;
+}
+
+/*!
+ * Enable csi
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int prp_vf_enable_csi(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+
+ return ipu_enable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * Disable csi
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int prp_vf_disable_csi(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+
+ /* free csi eof irq firstly.
+ * when disable csi, wait for idmac eof.
+ * it requests eof irq again */
+ ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, cam);
+
+ return ipu_disable_csi(cam->ipu, cam->csi);
+}
+
+/*!
+ * function to select PRP-VF as the working path
+ *
+ * @param private cam_data * mxc v4l2 main structure
+ *
+ * @return status
+ */
+int prp_vf_sdc_select_bg(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+
+ if (cam) {
+ cam->vf_start_sdc = prpvf_start;
+ cam->vf_stop_sdc = prpvf_stop;
+ cam->vf_enable_csi = prp_vf_enable_csi;
+ cam->vf_disable_csi = prp_vf_disable_csi;
+ cam->overlay_active = false;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(prp_vf_sdc_select_bg);
+
+/*!
+ * function to de-select PRP-VF as the working path
+ *
+ * @param private cam_data * mxc v4l2 main structure
+ *
+ * @return status
+ */
+int prp_vf_sdc_deselect_bg(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+
+ if (cam) {
+ cam->vf_start_sdc = NULL;
+ cam->vf_stop_sdc = NULL;
+ cam->vf_enable_csi = NULL;
+ cam->vf_disable_csi = NULL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(prp_vf_sdc_deselect_bg);
+
+/*!
+ * Init viewfinder task.
+ *
+ * @return Error code indicating success or failure
+ */
+__init int prp_vf_sdc_init_bg(void)
+{
+ return 0;
+}
+
+/*!
+ * Deinit viewfinder task.
+ *
+ * @return Error code indicating success or failure
+ */
+void __exit prp_vf_sdc_exit_bg(void)
+{
+}
+
+module_init(prp_vf_sdc_init_bg);
+module_exit(prp_vf_sdc_exit_bg);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/ipu_still.c b/drivers/media/platform/mxc/capture/ipu_still.c
new file mode 100644
index 000000000000..b18c3cf873cc
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/ipu_still.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_still.c
+ *
+ * @brief IPU Use case for still image capture
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/module.h>
+#include <linux/semaphore.h>
+#include <linux/sched.h>
+#include <linux/ipu.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+static int callback_eof_flag;
+#ifndef CONFIG_MXC_IPU_V1
+static int buffer_num;
+#endif
+
+#ifdef CONFIG_MXC_IPU_V1
+static int callback_flag;
+/*
+ * Function definitions
+ */
+/*!
+ * CSI EOF callback function.
+ *
+ * @param irq int irq line
+ * @param dev_id void * device id
+ *
+ * @return status IRQ_HANDLED for handled
+ */
+static irqreturn_t prp_csi_eof_callback(int irq, void *dev_id)
+{
+ cam_data *cam = devid;
+ ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
+ callback_flag%2 ? 1 : 0);
+ if (callback_flag == 0)
+ ipu_enable_channel(cam->ipu, CSI_MEM);
+
+ callback_flag++;
+ return IRQ_HANDLED;
+}
+#endif
+
+/*!
+ * CSI callback function.
+ *
+ * @param irq int irq line
+ * @param dev_id void * device id
+ *
+ * @return status IRQ_HANDLED for handled
+ */
+static irqreturn_t prp_still_callback(int irq, void *dev_id)
+{
+ cam_data *cam = (cam_data *) dev_id;
+
+ callback_eof_flag++;
+ if (callback_eof_flag < 5) {
+#ifndef CONFIG_MXC_IPU_V1
+ buffer_num = (buffer_num == 0) ? 1 : 0;
+ ipu_select_buffer(cam->ipu, CSI_MEM,
+ IPU_OUTPUT_BUFFER, buffer_num);
+#endif
+ } else {
+ cam->still_counter++;
+ wake_up_interruptible(&cam->still_queue);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*!
+ * start csi->mem task
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int prp_still_start(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ u32 pixel_fmt;
+ int err;
+ ipu_channel_params_t params;
+
+ if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+ pixel_fmt = IPU_PIX_FMT_YUV420P;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12)
+ pixel_fmt = IPU_PIX_FMT_NV12;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P)
+ pixel_fmt = IPU_PIX_FMT_YUV422P;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
+ pixel_fmt = IPU_PIX_FMT_UYVY;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
+ pixel_fmt = IPU_PIX_FMT_YUYV;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24)
+ pixel_fmt = IPU_PIX_FMT_BGR24;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24)
+ pixel_fmt = IPU_PIX_FMT_RGB24;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565)
+ pixel_fmt = IPU_PIX_FMT_RGB565;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32)
+ pixel_fmt = IPU_PIX_FMT_BGR32;
+ else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32)
+ pixel_fmt = IPU_PIX_FMT_RGB32;
+ else {
+ printk(KERN_ERR "format not supported\n");
+ return -EINVAL;
+ }
+
+ memset(&params, 0, sizeof(params));
+ err = ipu_init_channel(cam->ipu, CSI_MEM, &params);
+ if (err != 0)
+ return err;
+
+ err = ipu_init_channel_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER,
+ pixel_fmt, cam->v2f.fmt.pix.width,
+ cam->v2f.fmt.pix.height,
+ cam->v2f.fmt.pix.width, IPU_ROTATE_NONE,
+ cam->still_buf[0], cam->still_buf[1], 0,
+ 0, 0);
+ if (err != 0)
+ return err;
+
+#ifdef CONFIG_MXC_IPU_V1
+ ipu_clear_irq(IPU_IRQ_SENSOR_OUT_EOF);
+ err = ipu_request_irq(IPU_IRQ_SENSOR_OUT_EOF, prp_still_callback,
+ 0, "Mxc Camera", cam);
+ if (err != 0) {
+ printk(KERN_ERR "Error registering irq.\n");
+ return err;
+ }
+ callback_flag = 0;
+ callback_eof_flag = 0;
+ ipu_clear_irq(IPU_IRQ_SENSOR_EOF);
+ err = ipu_request_irq(IPU_IRQ_SENSOR_EOF, prp_csi_eof_callback,
+ 0, "Mxc Camera", cam);
+ if (err != 0) {
+ printk(KERN_ERR "Error IPU_IRQ_SENSOR_EOF\n");
+ return err;
+ }
+#else
+ callback_eof_flag = 0;
+ buffer_num = 0;
+
+ ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF);
+ err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF,
+ prp_still_callback,
+ 0, "Mxc Camera", cam);
+ if (err != 0) {
+ printk(KERN_ERR "Error registering irq.\n");
+ return err;
+ }
+
+ ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 0);
+ ipu_enable_channel(cam->ipu, CSI_MEM);
+ ipu_enable_csi(cam->ipu, cam->csi);
+#endif
+
+ return err;
+}
+
+/*!
+ * stop csi->mem encoder task
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+static int prp_still_stop(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ int err = 0;
+
+#ifdef CONFIG_MXC_IPU_V1
+ ipu_free_irq(IPU_IRQ_SENSOR_EOF, NULL);
+ ipu_free_irq(IPU_IRQ_SENSOR_OUT_EOF, cam);
+#else
+ ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam);
+#endif
+
+ ipu_disable_csi(cam->ipu, cam->csi);
+ ipu_disable_channel(cam->ipu, CSI_MEM, true);
+ ipu_uninit_channel(cam->ipu, CSI_MEM);
+
+ return err;
+}
+
+/*!
+ * function to select CSI_MEM as the working path
+ *
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+int prp_still_select(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+
+ if (cam) {
+ cam->csi_start = prp_still_start;
+ cam->csi_stop = prp_still_stop;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(prp_still_select);
+
+/*!
+ * function to de-select CSI_MEM as the working path
+ *
+ * @param private struct cam_data * mxc capture instance
+ *
+ * @return status
+ */
+int prp_still_deselect(void *private)
+{
+ cam_data *cam = (cam_data *) private;
+ int err = 0;
+
+ err = prp_still_stop(cam);
+
+ if (cam) {
+ cam->csi_start = NULL;
+ cam->csi_stop = NULL;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(prp_still_deselect);
+
+/*!
+ * Init the Encorder channels
+ *
+ * @return Error code indicating success or failure
+ */
+__init int prp_still_init(void)
+{
+ return 0;
+}
+
+/*!
+ * Deinit the Encorder channels
+ *
+ */
+void __exit prp_still_exit(void)
+{
+}
+
+module_init(prp_still_init);
+module_exit(prp_still_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("IPU PRP STILL IMAGE Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/mx6s_capture.c b/drivers/media/platform/mxc/capture/mx6s_capture.c
new file mode 100644
index 000000000000..6c1cbbb11073
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/mx6s_capture.c
@@ -0,0 +1,2007 @@
+/*
+ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file mx6s_csi.c
+ *
+ * @brief mx6sx CMOS Sensor interface functions
+ *
+ * @ingroup CSI
+ */
+#include <asm/dma.h>
+#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/gcd.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/media-bus-format.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-of.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define MX6S_CAM_DRV_NAME "mx6s-csi"
+#define MX6S_CAM_VERSION "0.0.1"
+#define MX6S_CAM_DRIVER_DESCRIPTION "i.MX6S_CSI"
+
+#define MAX_VIDEO_MEM 64
+
+/* reset values */
+#define CSICR1_RESET_VAL 0x40000800
+#define CSICR2_RESET_VAL 0x0
+#define CSICR3_RESET_VAL 0x0
+
+/* csi control reg 1 */
+#define BIT_SWAP16_EN (0x1 << 31)
+#define BIT_EXT_VSYNC (0x1 << 30)
+#define BIT_EOF_INT_EN (0x1 << 29)
+#define BIT_PRP_IF_EN (0x1 << 28)
+#define BIT_CCIR_MODE (0x1 << 27)
+#define BIT_COF_INT_EN (0x1 << 26)
+#define BIT_SF_OR_INTEN (0x1 << 25)
+#define BIT_RF_OR_INTEN (0x1 << 24)
+#define BIT_SFF_DMA_DONE_INTEN (0x1 << 22)
+#define BIT_STATFF_INTEN (0x1 << 21)
+#define BIT_FB2_DMA_DONE_INTEN (0x1 << 20)
+#define BIT_FB1_DMA_DONE_INTEN (0x1 << 19)
+#define BIT_RXFF_INTEN (0x1 << 18)
+#define BIT_SOF_POL (0x1 << 17)
+#define BIT_SOF_INTEN (0x1 << 16)
+#define BIT_MCLKDIV (0xF << 12)
+#define BIT_HSYNC_POL (0x1 << 11)
+#define BIT_CCIR_EN (0x1 << 10)
+#define BIT_MCLKEN (0x1 << 9)
+#define BIT_FCC (0x1 << 8)
+#define BIT_PACK_DIR (0x1 << 7)
+#define BIT_CLR_STATFIFO (0x1 << 6)
+#define BIT_CLR_RXFIFO (0x1 << 5)
+#define BIT_GCLK_MODE (0x1 << 4)
+#define BIT_INV_DATA (0x1 << 3)
+#define BIT_INV_PCLK (0x1 << 2)
+#define BIT_REDGE (0x1 << 1)
+#define BIT_PIXEL_BIT (0x1 << 0)
+
+#define SHIFT_MCLKDIV 12
+
+/* control reg 3 */
+#define BIT_FRMCNT (0xFFFF << 16)
+#define BIT_FRMCNT_RST (0x1 << 15)
+#define BIT_DMA_REFLASH_RFF (0x1 << 14)
+#define BIT_DMA_REFLASH_SFF (0x1 << 13)
+#define BIT_DMA_REQ_EN_RFF (0x1 << 12)
+#define BIT_DMA_REQ_EN_SFF (0x1 << 11)
+#define BIT_STATFF_LEVEL (0x7 << 8)
+#define BIT_HRESP_ERR_EN (0x1 << 7)
+#define BIT_RXFF_LEVEL (0x7 << 4)
+#define BIT_TWO_8BIT_SENSOR (0x1 << 3)
+#define BIT_ZERO_PACK_EN (0x1 << 2)
+#define BIT_ECC_INT_EN (0x1 << 1)
+#define BIT_ECC_AUTO_EN (0x1 << 0)
+
+#define SHIFT_FRMCNT 16
+#define SHIFT_RXFIFO_LEVEL 4
+
+/* csi status reg */
+#define BIT_ADDR_CH_ERR_INT (0x1 << 28)
+#define BIT_FIELD0_INT (0x1 << 27)
+#define BIT_FIELD1_INT (0x1 << 26)
+#define BIT_SFF_OR_INT (0x1 << 25)
+#define BIT_RFF_OR_INT (0x1 << 24)
+#define BIT_DMA_TSF_DONE_SFF (0x1 << 22)
+#define BIT_STATFF_INT (0x1 << 21)
+#define BIT_DMA_TSF_DONE_FB2 (0x1 << 20)
+#define BIT_DMA_TSF_DONE_FB1 (0x1 << 19)
+#define BIT_RXFF_INT (0x1 << 18)
+#define BIT_EOF_INT (0x1 << 17)
+#define BIT_SOF_INT (0x1 << 16)
+#define BIT_F2_INT (0x1 << 15)
+#define BIT_F1_INT (0x1 << 14)
+#define BIT_COF_INT (0x1 << 13)
+#define BIT_HRESP_ERR_INT (0x1 << 7)
+#define BIT_ECC_INT (0x1 << 1)
+#define BIT_DRDY (0x1 << 0)
+
+/* csi control reg 18 */
+#define BIT_CSI_ENABLE (0x1 << 31)
+#define BIT_MIPI_DATA_FORMAT_RAW8 (0x2a << 25)
+#define BIT_MIPI_DATA_FORMAT_RAW10 (0x2b << 25)
+#define BIT_MIPI_DATA_FORMAT_YUV422_8B (0x1e << 25)
+#define BIT_MIPI_DATA_FORMAT_MASK (0x3F << 25)
+#define BIT_MIPI_DATA_FORMAT_OFFSET 25
+#define BIT_DATA_FROM_MIPI (0x1 << 22)
+#define BIT_MIPI_YU_SWAP (0x1 << 21)
+#define BIT_MIPI_DOUBLE_CMPNT (0x1 << 20)
+#define BIT_BASEADDR_CHG_ERR_EN (0x1 << 9)
+#define BIT_BASEADDR_SWITCH_SEL (0x1 << 5)
+#define BIT_BASEADDR_SWITCH_EN (0x1 << 4)
+#define BIT_PARALLEL24_EN (0x1 << 3)
+#define BIT_DEINTERLACE_EN (0x1 << 2)
+#define BIT_TVDECODER_IN_EN (0x1 << 1)
+#define BIT_NTSC_EN (0x1 << 0)
+
+#define CSI_MCLK_VF 1
+#define CSI_MCLK_ENC 2
+#define CSI_MCLK_RAW 4
+#define CSI_MCLK_I2C 8
+
+#define CSI_CSICR1 0x0
+#define CSI_CSICR2 0x4
+#define CSI_CSICR3 0x8
+#define CSI_STATFIFO 0xC
+#define CSI_CSIRXFIFO 0x10
+#define CSI_CSIRXCNT 0x14
+#define CSI_CSISR 0x18
+
+#define CSI_CSIDBG 0x1C
+#define CSI_CSIDMASA_STATFIFO 0x20
+#define CSI_CSIDMATS_STATFIFO 0x24
+#define CSI_CSIDMASA_FB1 0x28
+#define CSI_CSIDMASA_FB2 0x2C
+#define CSI_CSIFBUF_PARA 0x30
+#define CSI_CSIIMAG_PARA 0x34
+
+#define CSI_CSICR18 0x48
+#define CSI_CSICR19 0x4c
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+#define MX6SX_MAX_SENSORS 1
+
+struct csi_signal_cfg_t {
+ unsigned data_width:3;
+ unsigned clk_mode:2;
+ unsigned ext_vsync:1;
+ unsigned Vsync_pol:1;
+ unsigned Hsync_pol:1;
+ unsigned pixclk_pol:1;
+ unsigned data_pol:1;
+ unsigned sens_clksrc:1;
+};
+
+struct csi_config_t {
+ /* control reg 1 */
+ unsigned int swap16_en:1;
+ unsigned int ext_vsync:1;
+ unsigned int eof_int_en:1;
+ unsigned int prp_if_en:1;
+ unsigned int ccir_mode:1;
+ unsigned int cof_int_en:1;
+ unsigned int sf_or_inten:1;
+ unsigned int rf_or_inten:1;
+ unsigned int sff_dma_done_inten:1;
+ unsigned int statff_inten:1;
+ unsigned int fb2_dma_done_inten:1;
+ unsigned int fb1_dma_done_inten:1;
+ unsigned int rxff_inten:1;
+ unsigned int sof_pol:1;
+ unsigned int sof_inten:1;
+ unsigned int mclkdiv:4;
+ unsigned int hsync_pol:1;
+ unsigned int ccir_en:1;
+ unsigned int mclken:1;
+ unsigned int fcc:1;
+ unsigned int pack_dir:1;
+ unsigned int gclk_mode:1;
+ unsigned int inv_data:1;
+ unsigned int inv_pclk:1;
+ unsigned int redge:1;
+ unsigned int pixel_bit:1;
+
+ /* control reg 3 */
+ unsigned int frmcnt:16;
+ unsigned int frame_reset:1;
+ unsigned int dma_reflash_rff:1;
+ unsigned int dma_reflash_sff:1;
+ unsigned int dma_req_en_rff:1;
+ unsigned int dma_req_en_sff:1;
+ unsigned int statff_level:3;
+ unsigned int hresp_err_en:1;
+ unsigned int rxff_level:3;
+ unsigned int two_8bit_sensor:1;
+ unsigned int zero_pack_en:1;
+ unsigned int ecc_int_en:1;
+ unsigned int ecc_auto_en:1;
+ /* fifo counter */
+ unsigned int rxcnt;
+};
+
+/*
+ * Basic structures
+ */
+struct mx6s_fmt {
+ char name[32];
+ u32 fourcc; /* v4l2 format id */
+ u32 pixelformat;
+ u32 mbus_code;
+ int bpp;
+};
+
+static struct mx6s_fmt formats[] = {
+ {
+ .name = "UYVY-16",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .bpp = 2,
+ }, {
+ .name = "YUYV-16",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .bpp = 2,
+ }, {
+ .name = "YUV32 (X-Y-U-V)",
+ .fourcc = V4L2_PIX_FMT_YUV32,
+ .pixelformat = V4L2_PIX_FMT_YUV32,
+ .mbus_code = MEDIA_BUS_FMT_AYUV8_1X32,
+ .bpp = 4,
+ }, {
+ .name = "RAWRGB8 (SBGGR8)",
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .pixelformat = V4L2_PIX_FMT_SBGGR8,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .bpp = 1,
+ }
+};
+
+struct mx6s_buf_internal {
+ struct list_head queue;
+ int bufnum;
+ bool discard;
+};
+
+/* buffer for one video frame */
+struct mx6s_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct vb2_v4l2_buffer vb;
+ struct mx6s_buf_internal internal;
+};
+
+struct mx6s_csi_mux {
+ struct regmap *gpr;
+ u8 req_gpr;
+ u8 req_bit;
+};
+
+struct mx6s_csi_dev {
+ struct device *dev;
+ struct video_device *vdev;
+ struct v4l2_subdev *sd;
+ struct v4l2_device v4l2_dev;
+
+ struct vb2_queue vb2_vidq;
+ struct v4l2_ctrl_handler ctrl_handler;
+
+ struct mutex lock;
+ spinlock_t slock;
+
+ /* clock */
+ struct clk *clk_disp_axi;
+ struct clk *clk_disp_dcic;
+ struct clk *clk_csi_mclk;
+
+ void __iomem *regbase;
+ int irq;
+
+ u32 type;
+ u32 bytesperline;
+ v4l2_std_id std;
+ struct mx6s_fmt *fmt;
+ struct v4l2_pix_format pix;
+ u32 mbus_code;
+
+ unsigned int frame_count;
+
+ struct list_head capture;
+ struct list_head active_bufs;
+ struct list_head discard;
+
+ void *discard_buffer;
+ dma_addr_t discard_buffer_dma;
+ size_t discard_size;
+ struct mx6s_buf_internal buf_discard[2];
+
+ struct v4l2_async_subdev asd;
+ struct v4l2_async_notifier subdev_notifier;
+ struct v4l2_async_subdev *async_subdevs[2];
+
+ bool csi_mipi_mode;
+ bool csi_two_8bit_sensor_mode;
+ const bool *rx_fifo_rst;
+ struct mx6s_csi_mux csi_mux;
+};
+
+static const struct of_device_id mx6s_csi_dt_ids[];
+
+static inline int csi_read(struct mx6s_csi_dev *csi, unsigned int offset)
+{
+ return __raw_readl(csi->regbase + offset);
+}
+static inline void csi_write(struct mx6s_csi_dev *csi, unsigned int value,
+ unsigned int offset)
+{
+ __raw_writel(value, csi->regbase + offset);
+}
+
+static inline struct mx6s_csi_dev
+ *notifier_to_mx6s_dev(struct v4l2_async_notifier *n)
+{
+ return container_of(n, struct mx6s_csi_dev, subdev_notifier);
+}
+
+struct mx6s_fmt *format_by_fourcc(int fourcc)
+{
+ int i;
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].pixelformat == fourcc)
+ return formats + i;
+ }
+
+ pr_err("unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
+ return NULL;
+}
+
+struct mx6s_fmt *format_by_mbus(u32 code)
+{
+ int i;
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].mbus_code == code)
+ return formats + i;
+ }
+
+ pr_err("unknown mbus:0x%x\n", code);
+ return NULL;
+}
+
+static struct mx6s_buffer *mx6s_ibuf_to_buf(struct mx6s_buf_internal *int_buf)
+{
+ return container_of(int_buf, struct mx6s_buffer, internal);
+}
+
+void csi_clk_enable(struct mx6s_csi_dev *csi_dev)
+{
+ clk_prepare_enable(csi_dev->clk_disp_axi);
+ clk_prepare_enable(csi_dev->clk_disp_dcic);
+ clk_prepare_enable(csi_dev->clk_csi_mclk);
+}
+
+void csi_clk_disable(struct mx6s_csi_dev *csi_dev)
+{
+ clk_disable_unprepare(csi_dev->clk_csi_mclk);
+ clk_disable_unprepare(csi_dev->clk_disp_dcic);
+ clk_disable_unprepare(csi_dev->clk_disp_axi);
+}
+
+static void csihw_reset(struct mx6s_csi_dev *csi_dev)
+{
+ __raw_writel(__raw_readl(csi_dev->regbase + CSI_CSICR3)
+ | BIT_FRMCNT_RST,
+ csi_dev->regbase + CSI_CSICR3);
+
+ __raw_writel(CSICR1_RESET_VAL, csi_dev->regbase + CSI_CSICR1);
+ __raw_writel(CSICR2_RESET_VAL, csi_dev->regbase + CSI_CSICR2);
+ __raw_writel(CSICR3_RESET_VAL, csi_dev->regbase + CSI_CSICR3);
+}
+
+static void csisw_reset(struct mx6s_csi_dev *csi_dev)
+{
+ int cr1, cr3, cr18, isr;
+
+ /* Disable csi */
+ cr18 = csi_read(csi_dev, CSI_CSICR18);
+ cr18 &= ~BIT_CSI_ENABLE;
+ csi_write(csi_dev, cr18, CSI_CSICR18);
+
+ /* Clear RX FIFO */
+ cr1 = csi_read(csi_dev, CSI_CSICR1);
+ csi_write(csi_dev, cr1 & ~BIT_FCC, CSI_CSICR1);
+ cr1 = csi_read(csi_dev, CSI_CSICR1);
+ csi_write(csi_dev, cr1 | BIT_CLR_RXFIFO, CSI_CSICR1);
+
+ /* DMA reflash */
+ cr3 = csi_read(csi_dev, CSI_CSICR3);
+ cr3 |= BIT_DMA_REFLASH_RFF | BIT_FRMCNT_RST;
+ csi_write(csi_dev, cr3, CSI_CSICR3);
+
+ msleep(2);
+
+ cr1 = csi_read(csi_dev, CSI_CSICR1);
+ csi_write(csi_dev, cr1 | BIT_FCC, CSI_CSICR1);
+
+ isr = csi_read(csi_dev, CSI_CSISR);
+ csi_write(csi_dev, isr, CSI_CSISR);
+
+ /* Ensable csi */
+ cr18 |= BIT_CSI_ENABLE;
+ csi_write(csi_dev, cr18, CSI_CSICR18);
+}
+
+/*!
+ * csi_init_interface
+ * Init csi interface
+ */
+static void csi_init_interface(struct mx6s_csi_dev *csi_dev)
+{
+ unsigned int val = 0;
+ unsigned int imag_para;
+
+ val |= BIT_SOF_POL;
+ val |= BIT_REDGE;
+ val |= BIT_GCLK_MODE;
+ val |= BIT_HSYNC_POL;
+ val |= BIT_FCC;
+ val |= 1 << SHIFT_MCLKDIV;
+ val |= BIT_MCLKEN;
+ __raw_writel(val, csi_dev->regbase + CSI_CSICR1);
+
+ imag_para = (640 << 16) | 960;
+ __raw_writel(imag_para, csi_dev->regbase + CSI_CSIIMAG_PARA);
+
+ val = BIT_DMA_REFLASH_RFF;
+ __raw_writel(val, csi_dev->regbase + CSI_CSICR3);
+}
+
+static void csi_enable_int(struct mx6s_csi_dev *csi_dev, int arg)
+{
+ unsigned long cr1 = __raw_readl(csi_dev->regbase + CSI_CSICR1);
+
+ cr1 |= BIT_SOF_INTEN;
+ cr1 |= BIT_RFF_OR_INT;
+ if (arg == 1) {
+ /* still capture needs DMA intterrupt */
+ cr1 |= BIT_FB1_DMA_DONE_INTEN;
+ cr1 |= BIT_FB2_DMA_DONE_INTEN;
+ }
+ __raw_writel(cr1, csi_dev->regbase + CSI_CSICR1);
+}
+
+static void csi_disable_int(struct mx6s_csi_dev *csi_dev)
+{
+ unsigned long cr1 = __raw_readl(csi_dev->regbase + CSI_CSICR1);
+
+ cr1 &= ~BIT_SOF_INTEN;
+ cr1 &= ~BIT_RFF_OR_INT;
+ cr1 &= ~BIT_FB1_DMA_DONE_INTEN;
+ cr1 &= ~BIT_FB2_DMA_DONE_INTEN;
+ __raw_writel(cr1, csi_dev->regbase + CSI_CSICR1);
+}
+
+static void csi_enable(struct mx6s_csi_dev *csi_dev, int arg)
+{
+ unsigned long cr = __raw_readl(csi_dev->regbase + CSI_CSICR18);
+
+ if (arg == 1)
+ cr |= BIT_CSI_ENABLE;
+ else
+ cr &= ~BIT_CSI_ENABLE;
+ __raw_writel(cr, csi_dev->regbase + CSI_CSICR18);
+}
+
+static void csi_buf_stride_set(struct mx6s_csi_dev *csi_dev, u32 stride)
+{
+ __raw_writel(stride, csi_dev->regbase + CSI_CSIFBUF_PARA);
+}
+
+static void csi_deinterlace_enable(struct mx6s_csi_dev *csi_dev, bool enable)
+{
+ unsigned long cr18 = __raw_readl(csi_dev->regbase + CSI_CSICR18);
+
+ if (enable == true)
+ cr18 |= BIT_DEINTERLACE_EN;
+ else
+ cr18 &= ~BIT_DEINTERLACE_EN;
+
+ __raw_writel(cr18, csi_dev->regbase + CSI_CSICR18);
+}
+
+static void csi_deinterlace_mode(struct mx6s_csi_dev *csi_dev, int mode)
+{
+ unsigned long cr18 = __raw_readl(csi_dev->regbase + CSI_CSICR18);
+
+ if (mode == V4L2_STD_NTSC)
+ cr18 |= BIT_NTSC_EN;
+ else
+ cr18 &= ~BIT_NTSC_EN;
+
+ __raw_writel(cr18, csi_dev->regbase + CSI_CSICR18);
+}
+
+static void csi_tvdec_enable(struct mx6s_csi_dev *csi_dev, bool enable)
+{
+ unsigned long cr18 = __raw_readl(csi_dev->regbase + CSI_CSICR18);
+ unsigned long cr1 = __raw_readl(csi_dev->regbase + CSI_CSICR1);
+
+ if (enable == true) {
+ cr18 |= (BIT_TVDECODER_IN_EN |
+ BIT_BASEADDR_SWITCH_EN |
+ BIT_BASEADDR_SWITCH_SEL |
+ BIT_BASEADDR_CHG_ERR_EN);
+ cr1 |= BIT_CCIR_MODE;
+ cr1 &= ~(BIT_SOF_POL | BIT_REDGE);
+ } else {
+ cr18 &= ~(BIT_TVDECODER_IN_EN |
+ BIT_BASEADDR_SWITCH_EN |
+ BIT_BASEADDR_SWITCH_SEL |
+ BIT_BASEADDR_CHG_ERR_EN);
+ cr1 &= ~BIT_CCIR_MODE;
+ cr1 |= BIT_SOF_POL | BIT_REDGE;
+ }
+
+ __raw_writel(cr18, csi_dev->regbase + CSI_CSICR18);
+ __raw_writel(cr1, csi_dev->regbase + CSI_CSICR1);
+}
+
+static void csi_dmareq_rff_enable(struct mx6s_csi_dev *csi_dev)
+{
+ unsigned long cr3 = __raw_readl(csi_dev->regbase + CSI_CSICR3);
+ unsigned long cr2 = __raw_readl(csi_dev->regbase + CSI_CSICR2);
+
+ /* Burst Type of DMA Transfer from RxFIFO. INCR16 */
+ cr2 |= 0xC0000000;
+
+ cr3 |= BIT_DMA_REQ_EN_RFF;
+ cr3 |= BIT_HRESP_ERR_EN;
+ cr3 &= ~BIT_RXFF_LEVEL;
+ cr3 |= 0x2 << 4;
+ if (csi_dev->csi_two_8bit_sensor_mode)
+ cr3 |= BIT_TWO_8BIT_SENSOR;
+
+ __raw_writel(cr3, csi_dev->regbase + CSI_CSICR3);
+ __raw_writel(cr2, csi_dev->regbase + CSI_CSICR2);
+}
+
+static void csi_dmareq_rff_disable(struct mx6s_csi_dev *csi_dev)
+{
+ unsigned long cr3 = __raw_readl(csi_dev->regbase + CSI_CSICR3);
+
+ cr3 &= ~BIT_DMA_REQ_EN_RFF;
+ cr3 &= ~BIT_HRESP_ERR_EN;
+ __raw_writel(cr3, csi_dev->regbase + CSI_CSICR3);
+}
+
+static void csi_set_imagpara(struct mx6s_csi_dev *csi,
+ int width, int height)
+{
+ int imag_para = 0;
+ unsigned long cr3 = __raw_readl(csi->regbase + CSI_CSICR3);
+
+ imag_para = (width << 16) | height;
+ __raw_writel(imag_para, csi->regbase + CSI_CSIIMAG_PARA);
+
+ /* reflash the embeded DMA controller */
+ __raw_writel(cr3 | BIT_DMA_REFLASH_RFF, csi->regbase + CSI_CSICR3);
+}
+
+static void csi_error_recovery(struct mx6s_csi_dev *csi_dev)
+{
+ u32 cr1, cr3, cr18;
+ /* software reset */
+
+ /* Disable csi */
+ cr18 = csi_read(csi_dev, CSI_CSICR18);
+ cr18 &= ~BIT_CSI_ENABLE;
+ csi_write(csi_dev, cr18, CSI_CSICR18);
+
+ /* Clear RX FIFO */
+ cr1 = csi_read(csi_dev, CSI_CSICR1);
+ csi_write(csi_dev, cr1 & ~BIT_FCC, CSI_CSICR1);
+ cr1 = csi_read(csi_dev, CSI_CSICR1);
+ csi_write(csi_dev, cr1 | BIT_CLR_RXFIFO, CSI_CSICR1);
+
+ cr1 = csi_read(csi_dev, CSI_CSICR1);
+ csi_write(csi_dev, cr1 | BIT_FCC, CSI_CSICR1);
+
+ /* DMA reflash */
+ cr3 = csi_read(csi_dev, CSI_CSICR3);
+ cr3 |= BIT_DMA_REFLASH_RFF;
+ csi_write(csi_dev, cr3, CSI_CSICR3);
+
+ /* Ensable csi */
+ cr18 |= BIT_CSI_ENABLE;
+ csi_write(csi_dev, cr18, CSI_CSICR18);
+}
+
+/*
+ * Videobuf operations
+ */
+static int mx6s_videobuf_setup(struct vb2_queue *vq,
+ unsigned int *count, unsigned int *num_planes,
+ unsigned int sizes[], struct device *alloc_devs[])
+{
+ struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vq);
+
+ dev_dbg(csi_dev->dev, "count=%d, size=%d\n", *count, sizes[0]);
+
+ alloc_devs[0] = csi_dev->dev;
+
+ sizes[0] = csi_dev->pix.sizeimage;
+
+ pr_debug("size=%d\n", sizes[0]);
+ if (0 == *count)
+ *count = 32;
+ if (!*num_planes &&
+ sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024)
+ *count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0];
+
+ *num_planes = 1;
+
+ return 0;
+}
+
+static int mx6s_videobuf_prepare(struct vb2_buffer *vb)
+{
+ struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vb->vb2_queue);
+ int ret = 0;
+
+ dev_dbg(csi_dev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
+
+#ifdef DEBUG
+ /*
+ * This can be useful if you want to see if we actually fill
+ * the buffer with something
+ */
+ if (vb2_plane_vaddr(vb, 0))
+ memset((void *)vb2_plane_vaddr(vb, 0),
+ 0xaa, vb2_get_plane_payload(vb, 0));
+#endif
+
+ vb2_set_plane_payload(vb, 0, csi_dev->pix.sizeimage);
+ if (vb2_plane_vaddr(vb, 0) &&
+ vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ return 0;
+
+out:
+ return ret;
+}
+
+static void mx6s_videobuf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct mx6s_buffer *buf = container_of(vbuf, struct mx6s_buffer, vb);
+ unsigned long flags;
+
+ dev_dbg(csi_dev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+ vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
+
+ spin_lock_irqsave(&csi_dev->slock, flags);
+
+ list_add_tail(&buf->internal.queue, &csi_dev->capture);
+
+ spin_unlock_irqrestore(&csi_dev->slock, flags);
+}
+
+static void mx6s_update_csi_buf(struct mx6s_csi_dev *csi_dev,
+ unsigned long phys, int bufnum)
+{
+ if (bufnum == 1)
+ csi_write(csi_dev, phys, CSI_CSIDMASA_FB2);
+ else
+ csi_write(csi_dev, phys, CSI_CSIDMASA_FB1);
+}
+
+static void mx6s_csi_init(struct mx6s_csi_dev *csi_dev)
+{
+ csi_clk_enable(csi_dev);
+ csihw_reset(csi_dev);
+ csi_init_interface(csi_dev);
+ csi_dmareq_rff_disable(csi_dev);
+}
+
+static void mx6s_csi_deinit(struct mx6s_csi_dev *csi_dev)
+{
+ csihw_reset(csi_dev);
+ csi_init_interface(csi_dev);
+ csi_dmareq_rff_disable(csi_dev);
+ csi_clk_disable(csi_dev);
+}
+
+static int mx6s_csi_enable(struct mx6s_csi_dev *csi_dev)
+{
+ struct v4l2_pix_format *pix = &csi_dev->pix;
+ unsigned long flags;
+ unsigned long val;
+ int timeout, timeout2;
+
+ csisw_reset(csi_dev);
+
+ if (pix->field == V4L2_FIELD_INTERLACED)
+ csi_tvdec_enable(csi_dev, true);
+
+ /* For mipi csi input only */
+ if (csi_dev->csi_mipi_mode == true) {
+ csi_dmareq_rff_enable(csi_dev);
+ csi_enable_int(csi_dev, 1);
+ csi_enable(csi_dev, 1);
+ return 0;
+ }
+
+ local_irq_save(flags);
+ for (timeout = 10000000; timeout > 0; timeout--) {
+ if (csi_read(csi_dev, CSI_CSISR) & BIT_SOF_INT) {
+ val = csi_read(csi_dev, CSI_CSICR3);
+ csi_write(csi_dev, val | BIT_DMA_REFLASH_RFF,
+ CSI_CSICR3);
+ /* Wait DMA reflash done */
+ for (timeout2 = 1000000; timeout2 > 0; timeout2--) {
+ if (csi_read(csi_dev, CSI_CSICR3) &
+ BIT_DMA_REFLASH_RFF)
+ cpu_relax();
+ else
+ break;
+ }
+ if (timeout2 <= 0) {
+ pr_err("timeout when wait for reflash done.\n");
+ local_irq_restore(flags);
+ return -ETIME;
+ }
+ /* For imx6sl csi, DMA FIFO will auto start when sensor ready to work,
+ * so DMA should enable right after FIFO reset, otherwise dma will lost data
+ * and image will split.
+ */
+ csi_dmareq_rff_enable(csi_dev);
+ csi_enable_int(csi_dev, 1);
+ csi_enable(csi_dev, 1);
+ break;
+ } else
+ cpu_relax();
+ }
+ if (timeout <= 0) {
+ pr_err("timeout when wait for SOF\n");
+ local_irq_restore(flags);
+ return -ETIME;
+ }
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+static void mx6s_csi_disable(struct mx6s_csi_dev *csi_dev)
+{
+ struct v4l2_pix_format *pix = &csi_dev->pix;
+
+ csi_dmareq_rff_disable(csi_dev);
+ csi_disable_int(csi_dev);
+
+ /* set CSI_CSIDMASA_FB1 and CSI_CSIDMASA_FB2 to default value */
+ csi_write(csi_dev, 0, CSI_CSIDMASA_FB1);
+ csi_write(csi_dev, 0, CSI_CSIDMASA_FB2);
+
+ csi_buf_stride_set(csi_dev, 0);
+
+ if (pix->field == V4L2_FIELD_INTERLACED) {
+ csi_deinterlace_enable(csi_dev, false);
+ csi_tvdec_enable(csi_dev, false);
+ }
+
+ csi_enable(csi_dev, 0);
+}
+
+static int mx6s_configure_csi(struct mx6s_csi_dev *csi_dev)
+{
+ struct v4l2_pix_format *pix = &csi_dev->pix;
+ u32 cr1, cr18;
+ u32 width;
+
+ if (pix->field == V4L2_FIELD_INTERLACED) {
+ csi_deinterlace_enable(csi_dev, true);
+ csi_buf_stride_set(csi_dev, csi_dev->pix.width);
+ csi_deinterlace_mode(csi_dev, csi_dev->std);
+ } else {
+ csi_deinterlace_enable(csi_dev, false);
+ csi_buf_stride_set(csi_dev, 0);
+ }
+
+ switch (csi_dev->fmt->pixelformat) {
+ case V4L2_PIX_FMT_YUV32:
+ case V4L2_PIX_FMT_SBGGR8:
+ width = pix->width;
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YUYV:
+ if (csi_dev->csi_mipi_mode == true)
+ width = pix->width;
+ else
+ /* For parallel 8-bit sensor input */
+ width = pix->width * 2;
+ break;
+ default:
+ pr_debug(" case not supported\n");
+ return -EINVAL;
+ }
+ csi_set_imagpara(csi_dev, width, pix->height);
+
+ if (csi_dev->csi_mipi_mode == true) {
+ cr1 = csi_read(csi_dev, CSI_CSICR1);
+ cr1 &= ~BIT_GCLK_MODE;
+ csi_write(csi_dev, cr1, CSI_CSICR1);
+
+ cr18 = csi_read(csi_dev, CSI_CSICR18);
+ cr18 &= BIT_MIPI_DATA_FORMAT_MASK;
+ cr18 |= BIT_DATA_FROM_MIPI;
+
+ switch (csi_dev->fmt->pixelformat) {
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YUYV:
+ cr18 |= BIT_MIPI_DATA_FORMAT_YUV422_8B;
+ break;
+ case V4L2_PIX_FMT_SBGGR8:
+ cr18 |= BIT_MIPI_DATA_FORMAT_RAW8;
+ break;
+ default:
+ pr_debug(" fmt not supported\n");
+ return -EINVAL;
+ }
+
+ csi_write(csi_dev, cr18, CSI_CSICR18);
+ }
+ return 0;
+}
+
+static int mx6s_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vq);
+ struct vb2_buffer *vb;
+ struct mx6s_buffer *buf;
+ unsigned long phys;
+ unsigned long flags;
+
+ if (count < 2)
+ return -ENOBUFS;
+
+ /*
+ * I didn't manage to properly enable/disable
+ * a per frame basis during running transfers,
+ * thus we allocate a buffer here and use it to
+ * discard frames when no buffer is available.
+ * Feel free to work on this ;)
+ */
+ csi_dev->discard_size = csi_dev->pix.sizeimage;
+ csi_dev->discard_buffer = dma_alloc_coherent(csi_dev->v4l2_dev.dev,
+ PAGE_ALIGN(csi_dev->discard_size),
+ &csi_dev->discard_buffer_dma,
+ GFP_DMA | GFP_KERNEL);
+ if (!csi_dev->discard_buffer)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&csi_dev->slock, flags);
+
+ csi_dev->buf_discard[0].discard = true;
+ list_add_tail(&csi_dev->buf_discard[0].queue,
+ &csi_dev->discard);
+
+ csi_dev->buf_discard[1].discard = true;
+ list_add_tail(&csi_dev->buf_discard[1].queue,
+ &csi_dev->discard);
+
+ /* csi buf 0 */
+ buf = list_first_entry(&csi_dev->capture, struct mx6s_buffer,
+ internal.queue);
+ buf->internal.bufnum = 0;
+ vb = &buf->vb.vb2_buf;
+ vb->state = VB2_BUF_STATE_ACTIVE;
+
+ phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+
+ mx6s_update_csi_buf(csi_dev, phys, buf->internal.bufnum);
+ list_move_tail(csi_dev->capture.next, &csi_dev->active_bufs);
+
+ /* csi buf 1 */
+ buf = list_first_entry(&csi_dev->capture, struct mx6s_buffer,
+ internal.queue);
+ buf->internal.bufnum = 1;
+ vb = &buf->vb.vb2_buf;
+ vb->state = VB2_BUF_STATE_ACTIVE;
+
+ phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+ mx6s_update_csi_buf(csi_dev, phys, buf->internal.bufnum);
+ list_move_tail(csi_dev->capture.next, &csi_dev->active_bufs);
+
+ spin_unlock_irqrestore(&csi_dev->slock, flags);
+
+ return mx6s_csi_enable(csi_dev);
+}
+
+static void mx6s_stop_streaming(struct vb2_queue *vq)
+{
+ struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vq);
+ unsigned long flags;
+ struct mx6s_buffer *buf, *tmp;
+ void *b;
+
+ mx6s_csi_disable(csi_dev);
+
+ spin_lock_irqsave(&csi_dev->slock, flags);
+
+ list_for_each_entry_safe(buf, tmp,
+ &csi_dev->active_bufs, internal.queue) {
+ list_del_init(&buf->internal.queue);
+ if (buf->vb.vb2_buf.state == VB2_BUF_STATE_ACTIVE)
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+
+ list_for_each_entry_safe(buf, tmp,
+ &csi_dev->capture, internal.queue) {
+ list_del_init(&buf->internal.queue);
+ if (buf->vb.vb2_buf.state == VB2_BUF_STATE_ACTIVE)
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+
+ INIT_LIST_HEAD(&csi_dev->capture);
+ INIT_LIST_HEAD(&csi_dev->active_bufs);
+ INIT_LIST_HEAD(&csi_dev->discard);
+
+ b = csi_dev->discard_buffer;
+ csi_dev->discard_buffer = NULL;
+
+ spin_unlock_irqrestore(&csi_dev->slock, flags);
+
+ dma_free_coherent(csi_dev->v4l2_dev.dev,
+ csi_dev->discard_size, b,
+ csi_dev->discard_buffer_dma);
+}
+
+static struct vb2_ops mx6s_videobuf_ops = {
+ .queue_setup = mx6s_videobuf_setup,
+ .buf_prepare = mx6s_videobuf_prepare,
+ .buf_queue = mx6s_videobuf_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = mx6s_start_streaming,
+ .stop_streaming = mx6s_stop_streaming,
+};
+
+static void mx6s_csi_frame_done(struct mx6s_csi_dev *csi_dev,
+ int bufnum, bool err)
+{
+ struct mx6s_buf_internal *ibuf;
+ struct mx6s_buffer *buf;
+ struct vb2_buffer *vb;
+ unsigned long phys;
+ unsigned int phys_fb1;
+ unsigned int phys_fb2;
+
+ ibuf = list_first_entry(&csi_dev->active_bufs, struct mx6s_buf_internal,
+ queue);
+
+ if (ibuf->discard) {
+ /*
+ * Discard buffer must not be returned to user space.
+ * Just return it to the discard queue.
+ */
+ list_move_tail(csi_dev->active_bufs.next, &csi_dev->discard);
+ } else {
+ buf = mx6s_ibuf_to_buf(ibuf);
+
+ vb = &buf->vb.vb2_buf;
+ phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+ if (bufnum == 1) {
+ phys_fb2 = csi_read(csi_dev, CSI_CSIDMASA_FB2);
+ if (phys_fb2 != (u32)phys) {
+ dev_err(csi_dev->dev, "%lx != %x\n", phys,
+ phys_fb2);
+ }
+ } else {
+ phys_fb1 = csi_read(csi_dev, CSI_CSIDMASA_FB1);
+ if (phys_fb1 != (u32)phys) {
+ dev_err(csi_dev->dev, "%lx != %x\n", phys,
+ phys_fb1);
+ }
+ }
+ dev_dbg(csi_dev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb,
+ vb2_plane_vaddr(vb, 0),
+ vb2_get_plane_payload(vb, 0));
+
+ list_del_init(&buf->internal.queue);
+ vb->timestamp =ktime_get_ns();
+ to_vb2_v4l2_buffer(vb)->sequence = csi_dev->frame_count;
+ if (err)
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+ else
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ }
+
+ csi_dev->frame_count++;
+
+ /* Config discard buffer to active_bufs */
+ if (list_empty(&csi_dev->capture)) {
+ if (list_empty(&csi_dev->discard)) {
+ dev_warn(csi_dev->dev,
+ "%s: trying to access empty discard list\n",
+ __func__);
+ return;
+ }
+
+ ibuf = list_first_entry(&csi_dev->discard,
+ struct mx6s_buf_internal, queue);
+ ibuf->bufnum = bufnum;
+
+ list_move_tail(csi_dev->discard.next, &csi_dev->active_bufs);
+
+ mx6s_update_csi_buf(csi_dev,
+ csi_dev->discard_buffer_dma, bufnum);
+ return;
+ }
+
+ buf = list_first_entry(&csi_dev->capture, struct mx6s_buffer,
+ internal.queue);
+
+ buf->internal.bufnum = bufnum;
+
+ list_move_tail(csi_dev->capture.next, &csi_dev->active_bufs);
+
+ vb = &buf->vb.vb2_buf;
+ vb->state = VB2_BUF_STATE_ACTIVE;
+
+ phys = vb2_dma_contig_plane_dma_addr(vb, 0);
+ mx6s_update_csi_buf(csi_dev, phys, bufnum);
+}
+
+static irqreturn_t mx6s_csi_irq_handler(int irq, void *data)
+{
+ struct mx6s_csi_dev *csi_dev = data;
+ unsigned long status;
+ u32 cr3, cr18;
+
+ spin_lock(&csi_dev->slock);
+
+ status = csi_read(csi_dev, CSI_CSISR);
+ csi_write(csi_dev, status, CSI_CSISR);
+
+ if (list_empty(&csi_dev->active_bufs)) {
+ dev_warn(csi_dev->dev,
+ "%s: called while active list is empty\n",
+ __func__);
+
+ spin_unlock(&csi_dev->slock);
+ return IRQ_HANDLED;
+ }
+
+ if (status & BIT_RFF_OR_INT) {
+ dev_warn(csi_dev->dev, "%s Rx fifo overflow\n", __func__);
+ if (*csi_dev->rx_fifo_rst)
+ csi_error_recovery(csi_dev);
+ }
+
+ if (status & BIT_HRESP_ERR_INT) {
+ dev_warn(csi_dev->dev, "%s Hresponse error detected\n",
+ __func__);
+ csi_error_recovery(csi_dev);
+ }
+
+ if (status & BIT_ADDR_CH_ERR_INT) {
+ /* Disable csi */
+ cr18 = csi_read(csi_dev, CSI_CSICR18);
+ cr18 &= ~BIT_CSI_ENABLE;
+ csi_write(csi_dev, cr18, CSI_CSICR18);
+
+ /* DMA reflash */
+ cr3 = csi_read(csi_dev, CSI_CSICR3);
+ cr3 |= BIT_DMA_REFLASH_RFF;
+ csi_write(csi_dev, cr3, CSI_CSICR3);
+
+ /* Ensable csi */
+ cr18 |= BIT_CSI_ENABLE;
+ csi_write(csi_dev, cr18, CSI_CSICR18);
+
+ pr_debug("base address switching Change Err.\n");
+ }
+
+ if ((status & BIT_DMA_TSF_DONE_FB1) &&
+ (status & BIT_DMA_TSF_DONE_FB2)) {
+ /* For both FB1 and FB2 interrupter bits set case,
+ * CSI DMA is work in one of FB1 and FB2 buffer,
+ * but software can not know the state.
+ * Skip it to avoid base address updated
+ * when csi work in field0 and field1 will write to
+ * new base address.
+ * PDM TKT230775 */
+ pr_debug("Skip two frames\n");
+ } else if (status & BIT_DMA_TSF_DONE_FB1) {
+ mx6s_csi_frame_done(csi_dev, 0, false);
+ } else if (status & BIT_DMA_TSF_DONE_FB2) {
+ mx6s_csi_frame_done(csi_dev, 1, false);
+ }
+
+ spin_unlock(&csi_dev->slock);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * File operations for the device
+ */
+static int mx6s_csi_open(struct file *file)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+ struct vb2_queue *q = &csi_dev->vb2_vidq;
+ int ret = 0;
+
+ file->private_data = csi_dev;
+
+ if (mutex_lock_interruptible(&csi_dev->lock))
+ return -ERESTARTSYS;
+
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->drv_priv = csi_dev;
+ q->ops = &mx6s_videobuf_ops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->buf_struct_size = sizeof(struct mx6s_buffer);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &csi_dev->lock;
+
+ ret = vb2_queue_init(q);
+ if (ret < 0)
+ goto unlock;
+
+ pm_runtime_get_sync(csi_dev->dev);
+
+ request_bus_freq(BUS_FREQ_HIGH);
+
+ v4l2_subdev_call(sd, core, s_power, 1);
+ mx6s_csi_init(csi_dev);
+
+ mutex_unlock(&csi_dev->lock);
+
+ return ret;
+unlock:
+ mutex_unlock(&csi_dev->lock);
+ return ret;
+}
+
+static int mx6s_csi_close(struct file *file)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+
+ mutex_lock(&csi_dev->lock);
+
+ vb2_queue_release(&csi_dev->vb2_vidq);
+
+ mx6s_csi_deinit(csi_dev);
+ v4l2_subdev_call(sd, core, s_power, 0);
+
+ mutex_unlock(&csi_dev->lock);
+
+ file->private_data = NULL;
+
+ release_bus_freq(BUS_FREQ_HIGH);
+
+ pm_runtime_put_sync_suspend(csi_dev->dev);
+ return 0;
+}
+
+static ssize_t mx6s_csi_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ int ret;
+
+ dev_dbg(csi_dev->dev, "read called, buf %p\n", buf);
+
+ mutex_lock(&csi_dev->lock);
+ ret = vb2_read(&csi_dev->vb2_vidq, buf, count, ppos,
+ file->f_flags & O_NONBLOCK);
+ mutex_unlock(&csi_dev->lock);
+ return ret;
+}
+
+static int mx6s_csi_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ int ret;
+
+ if (mutex_lock_interruptible(&csi_dev->lock))
+ return -ERESTARTSYS;
+ ret = vb2_mmap(&csi_dev->vb2_vidq, vma);
+ mutex_unlock(&csi_dev->lock);
+
+ pr_debug("vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+ ret);
+
+ return ret;
+}
+
+static struct v4l2_file_operations mx6s_csi_fops = {
+ .owner = THIS_MODULE,
+ .open = mx6s_csi_open,
+ .release = mx6s_csi_close,
+ .read = mx6s_csi_read,
+ .poll = vb2_fop_poll,
+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .mmap = mx6s_csi_mmap,
+};
+
+/*
+ * Video node IOCTLs
+ */
+static int mx6s_vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ if (inp->index != 0)
+ return -EINVAL;
+
+ /* default is camera */
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ strcpy(inp->name, "Camera");
+
+ return 0;
+}
+
+static int mx6s_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+
+ return 0;
+}
+
+static int mx6s_vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int mx6s_vidioc_querystd(struct file *file, void *priv, v4l2_std_id *a)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+
+ return v4l2_subdev_call(sd, video, querystd, a);
+}
+
+static int mx6s_vidioc_s_std(struct file *file, void *priv, v4l2_std_id a)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+
+ return v4l2_subdev_call(sd, video, s_std, a);
+}
+
+static int mx6s_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *a)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+
+ return v4l2_subdev_call(sd, video, g_std, a);
+}
+
+static int mx6s_vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ WARN_ON(priv != file->private_data);
+
+ return vb2_reqbufs(&csi_dev->vb2_vidq, p);
+}
+
+static int mx6s_vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ int ret;
+
+ WARN_ON(priv != file->private_data);
+
+ ret = vb2_querybuf(&csi_dev->vb2_vidq, p);
+
+ if (!ret) {
+ /* return physical address */
+ struct vb2_buffer *vb = csi_dev->vb2_vidq.bufs[p->index];
+ if (p->flags & V4L2_BUF_FLAG_MAPPED)
+ p->m.offset = vb2_dma_contig_plane_dma_addr(vb, 0);
+ }
+ return ret;
+}
+
+static int mx6s_vidioc_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ WARN_ON(priv != file->private_data);
+
+ return vb2_qbuf(&csi_dev->vb2_vidq, p);
+}
+
+static int mx6s_vidioc_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ WARN_ON(priv != file->private_data);
+
+ return vb2_dqbuf(&csi_dev->vb2_vidq, p, file->f_flags & O_NONBLOCK);
+}
+
+static int mx6s_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+ struct v4l2_subdev_mbus_code_enum code = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .index = f->index,
+ };
+ struct mx6s_fmt *fmt;
+ int ret;
+
+ WARN_ON(priv != file->private_data);
+
+ ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code);
+ if (ret < 0) {
+ /* no more formats */
+ dev_dbg(csi_dev->dev, "No more fmt\n");
+ return -EINVAL;
+ }
+
+ fmt = format_by_mbus(code.code);
+ if (!fmt) {
+ dev_err(csi_dev->dev, "mbus (0x%08x) invalid.\n", code.code);
+ return -EINVAL;
+ }
+
+ strlcpy(f->description, fmt->name, sizeof(f->description));
+ f->pixelformat = fmt->pixelformat;
+
+ return 0;
+}
+
+static int mx6s_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_subdev_format format = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ struct mx6s_fmt *fmt;
+ int ret;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (!fmt) {
+ dev_err(csi_dev->dev, "Fourcc format (0x%08x) invalid.",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ if (f->fmt.pix.width == 0 || f->fmt.pix.height == 0) {
+ dev_err(csi_dev->dev, "width %d, height %d is too small.\n",
+ f->fmt.pix.width, f->fmt.pix.height);
+ return -EINVAL;
+ }
+
+ v4l2_fill_mbus_format(&format.format, pix, fmt->mbus_code);
+ ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format);
+ v4l2_fill_pix_format(pix, &format.format);
+
+ if (pix->field != V4L2_FIELD_INTERLACED)
+ pix->field = V4L2_FIELD_NONE;
+
+ pix->sizeimage = fmt->bpp * pix->height * pix->width;
+ pix->bytesperline = fmt->bpp * pix->width;
+
+ return ret;
+}
+
+/*
+ * The real work of figuring out a workable format.
+ */
+
+static int mx6s_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ int ret;
+
+ ret = mx6s_vidioc_try_fmt_vid_cap(file, csi_dev, f);
+ if (ret < 0)
+ return ret;
+
+ csi_dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ csi_dev->mbus_code = csi_dev->fmt->mbus_code;
+ csi_dev->pix.width = f->fmt.pix.width;
+ csi_dev->pix.height = f->fmt.pix.height;
+ csi_dev->pix.sizeimage = f->fmt.pix.sizeimage;
+ csi_dev->pix.field = f->fmt.pix.field;
+ csi_dev->type = f->type;
+ dev_dbg(csi_dev->dev, "set to pixelformat '%4.6s'\n",
+ (char *)&csi_dev->fmt->name);
+
+ /* Config csi */
+ mx6s_configure_csi(csi_dev);
+
+ return 0;
+}
+
+static int mx6s_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ WARN_ON(priv != file->private_data);
+
+ f->fmt.pix = csi_dev->pix;
+
+ return 0;
+}
+
+static int mx6s_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ WARN_ON(priv != file->private_data);
+
+ /* cap->name is set by the friendly caller:-> */
+ strlcpy(cap->driver, MX6S_CAM_DRV_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, MX6S_CAM_DRIVER_DESCRIPTION, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+ dev_name(csi_dev->dev));
+
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+static int mx6s_vidioc_expbuf(struct file *file, void *priv,
+ struct v4l2_exportbuffer *eb)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ if (eb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return vb2_expbuf(&csi_dev->vb2_vidq, eb);
+
+ return -EINVAL;
+}
+
+static int mx6s_vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type i)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+ int ret;
+
+ WARN_ON(priv != file->private_data);
+
+ if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ ret = vb2_streamon(&csi_dev->vb2_vidq, i);
+ if (!ret)
+ v4l2_subdev_call(sd, video, s_stream, 1);
+
+ return ret;
+}
+
+static int mx6s_vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type i)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+
+ WARN_ON(priv != file->private_data);
+
+ if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ /*
+ * This calls buf_release from host driver's videobuf_queue_ops for all
+ * remaining buffers. When the last buffer is freed, stop capture
+ */
+ vb2_streamoff(&csi_dev->vb2_vidq, i);
+
+ v4l2_subdev_call(sd, video, s_stream, 0);
+
+ return 0;
+}
+
+static int mx6s_vidioc_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *a)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ dev_dbg(csi_dev->dev, "VIDIOC_CROPCAP not implemented\n");
+
+ return 0;
+}
+
+static int mx6s_vidioc_g_crop(struct file *file, void *priv,
+ struct v4l2_crop *a)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ dev_dbg(csi_dev->dev, "VIDIOC_G_CROP not implemented\n");
+
+ return 0;
+}
+
+static int mx6s_vidioc_s_crop(struct file *file, void *priv,
+ const struct v4l2_crop *a)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ dev_dbg(csi_dev->dev, "VIDIOC_S_CROP not implemented\n");
+
+ return 0;
+}
+
+static int mx6s_vidioc_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *a)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+
+ return v4l2_subdev_call(sd, video, g_parm, a);
+}
+
+static int mx6s_vidioc_s_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *a)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+
+ return v4l2_subdev_call(sd, video, s_parm, a);
+}
+
+static int mx6s_vidioc_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+ struct mx6s_fmt *fmt;
+ struct v4l2_subdev_frame_size_enum fse = {
+ .index = fsize->index,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ int ret;
+
+ fmt = format_by_fourcc(fsize->pixel_format);
+ if (fmt->pixelformat != fsize->pixel_format)
+ return -EINVAL;
+ fse.code = fmt->mbus_code;
+
+ ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse);
+ if (ret)
+ 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_DISCRETE;
+ 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 mx6s_vidioc_enum_frameintervals(struct file *file, void *priv,
+ struct v4l2_frmivalenum *interval)
+{
+ struct mx6s_csi_dev *csi_dev = video_drvdata(file);
+ struct v4l2_subdev *sd = csi_dev->sd;
+ struct mx6s_fmt *fmt;
+ struct v4l2_subdev_frame_interval_enum fie = {
+ .index = interval->index,
+ .width = interval->width,
+ .height = interval->height,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ int ret;
+
+ fmt = format_by_fourcc(interval->pixel_format);
+ if (fmt->pixelformat != interval->pixel_format)
+ return -EINVAL;
+ fie.code = fmt->mbus_code;
+
+ ret = v4l2_subdev_call(sd, pad, enum_frame_interval, NULL, &fie);
+ if (ret)
+ return ret;
+ interval->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ interval->discrete = fie.interval;
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops mx6s_csi_ioctl_ops = {
+ .vidioc_querycap = mx6s_vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = mx6s_vidioc_enum_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = mx6s_vidioc_try_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = mx6s_vidioc_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = mx6s_vidioc_s_fmt_vid_cap,
+ .vidioc_cropcap = mx6s_vidioc_cropcap,
+ .vidioc_s_crop = mx6s_vidioc_s_crop,
+ .vidioc_g_crop = mx6s_vidioc_g_crop,
+ .vidioc_reqbufs = mx6s_vidioc_reqbufs,
+ .vidioc_querybuf = mx6s_vidioc_querybuf,
+ .vidioc_qbuf = mx6s_vidioc_qbuf,
+ .vidioc_dqbuf = mx6s_vidioc_dqbuf,
+ .vidioc_g_std = mx6s_vidioc_g_std,
+ .vidioc_s_std = mx6s_vidioc_s_std,
+ .vidioc_querystd = mx6s_vidioc_querystd,
+ .vidioc_enum_input = mx6s_vidioc_enum_input,
+ .vidioc_g_input = mx6s_vidioc_g_input,
+ .vidioc_s_input = mx6s_vidioc_s_input,
+ .vidioc_expbuf = mx6s_vidioc_expbuf,
+ .vidioc_streamon = mx6s_vidioc_streamon,
+ .vidioc_streamoff = mx6s_vidioc_streamoff,
+ .vidioc_g_parm = mx6s_vidioc_g_parm,
+ .vidioc_s_parm = mx6s_vidioc_s_parm,
+ .vidioc_enum_framesizes = mx6s_vidioc_enum_framesizes,
+ .vidioc_enum_frameintervals = mx6s_vidioc_enum_frameintervals,
+};
+
+static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct mx6s_csi_dev *csi_dev = notifier_to_mx6s_dev(notifier);
+
+ /* Find platform data for this sensor subdev */
+ if (csi_dev->asd.match.of.node == subdev->dev->of_node)
+ csi_dev->sd = subdev;
+
+ if (subdev == NULL)
+ return -EINVAL;
+
+ v4l2_info(&csi_dev->v4l2_dev, "Registered sensor subdevice: %s\n",
+ subdev->name);
+
+ return 0;
+}
+
+static int mx6s_csi_mode_sel(struct mx6s_csi_dev *csi_dev)
+{
+ struct device_node *np = csi_dev->dev->of_node;
+ struct device_node *node;
+ phandle phandle;
+ u32 out_val[3];
+ int ret = 0;
+
+ if (of_get_property(np, "fsl,mipi-mode", NULL))
+ csi_dev->csi_mipi_mode = true;
+ else {
+ csi_dev->csi_mipi_mode = false;
+ return ret;
+ }
+
+ ret = of_property_read_u32_array(np, "csi-mux-mipi", out_val, 3);
+ if (ret) {
+ dev_dbg(csi_dev->dev, "no csi-mux-mipi property found\n");
+ } else {
+ phandle = *out_val;
+
+ node = of_find_node_by_phandle(phandle);
+ if (!node) {
+ dev_dbg(csi_dev->dev, "not find gpr node by phandle\n");
+ ret = PTR_ERR(node);
+ }
+ csi_dev->csi_mux.gpr = syscon_node_to_regmap(node);
+ if (IS_ERR(csi_dev->csi_mux.gpr)) {
+ dev_err(csi_dev->dev, "failed to get gpr regmap\n");
+ ret = PTR_ERR(csi_dev->csi_mux.gpr);
+ }
+ of_node_put(node);
+ if (ret < 0)
+ return ret;
+
+ csi_dev->csi_mux.req_gpr = out_val[1];
+ csi_dev->csi_mux.req_bit = out_val[2];
+
+ regmap_update_bits(csi_dev->csi_mux.gpr, csi_dev->csi_mux.req_gpr,
+ 1 << csi_dev->csi_mux.req_bit, 1 << csi_dev->csi_mux.req_bit);
+ }
+ return ret;
+}
+
+static int mx6s_csi_two_8bit_sensor_mode_sel(struct mx6s_csi_dev *csi_dev)
+{
+ struct device_node *np = csi_dev->dev->of_node;
+
+ if (of_get_property(np, "fsl,two-8bit-sensor-mode", NULL))
+ csi_dev->csi_two_8bit_sensor_mode = true;
+ else {
+ csi_dev->csi_two_8bit_sensor_mode = false;
+ }
+
+ return 0;
+}
+
+static int mx6sx_register_subdevs(struct mx6s_csi_dev *csi_dev)
+{
+ struct device_node *parent = csi_dev->dev->of_node;
+ struct device_node *node, *port, *rem;
+ int ret;
+
+ /* Attach sensors linked to csi receivers */
+ for_each_available_child_of_node(parent, node) {
+ if (of_node_cmp(node->name, "port"))
+ continue;
+
+ /* The csi node can have only port subnode. */
+ port = of_get_next_child(node, NULL);
+ if (!port)
+ continue;
+ rem = of_graph_get_remote_port_parent(port);
+ of_node_put(port);
+ if (rem == NULL) {
+ v4l2_info(&csi_dev->v4l2_dev,
+ "Remote device at %s not found\n",
+ port->full_name);
+ return -1;
+ }
+
+ csi_dev->asd.match_type = V4L2_ASYNC_MATCH_OF;
+ csi_dev->asd.match.of.node = rem;
+ csi_dev->async_subdevs[0] = &csi_dev->asd;
+
+ of_node_put(rem);
+ break;
+ }
+
+ csi_dev->subdev_notifier.subdevs = csi_dev->async_subdevs;
+ csi_dev->subdev_notifier.num_subdevs = 1;
+ csi_dev->subdev_notifier.bound = subdev_notifier_bound;
+
+ ret = v4l2_async_notifier_register(&csi_dev->v4l2_dev,
+ &csi_dev->subdev_notifier);
+ if (ret)
+ dev_err(csi_dev->dev,
+ "Error register async notifier regoster\n");
+
+ return ret;
+}
+
+static int mx6s_csi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *of_id;
+ struct mx6s_csi_dev *csi_dev;
+ struct video_device *vdev;
+ struct resource *res;
+ int ret = 0;
+
+ dev_dbg(dev, "initialising\n");
+
+ /* Prepare our private structure */
+ csi_dev = devm_kzalloc(dev, sizeof(struct mx6s_csi_dev), GFP_ATOMIC);
+ if (!csi_dev) {
+ dev_err(dev, "Can't allocate private structure\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ csi_dev->irq = platform_get_irq(pdev, 0);
+ if (res == NULL || csi_dev->irq < 0) {
+ dev_err(dev, "Missing platform resources data\n");
+ return -ENODEV;
+ }
+
+ csi_dev->regbase = devm_ioremap_resource(dev, res);
+ if (IS_ERR(csi_dev->regbase)) {
+ dev_err(dev, "Failed platform resources map\n");
+ return -ENODEV;
+ }
+
+ /* init video dma queues */
+ INIT_LIST_HEAD(&csi_dev->capture);
+ INIT_LIST_HEAD(&csi_dev->active_bufs);
+ INIT_LIST_HEAD(&csi_dev->discard);
+
+ csi_dev->clk_disp_axi = devm_clk_get(dev, "disp-axi");
+ if (IS_ERR(csi_dev->clk_disp_axi)) {
+ dev_err(dev, "Could not get csi axi clock\n");
+ return -ENODEV;
+ }
+
+ csi_dev->clk_disp_dcic = devm_clk_get(dev, "disp_dcic");
+ if (IS_ERR(csi_dev->clk_disp_dcic)) {
+ dev_err(dev, "Could not get disp dcic clock\n");
+ return -ENODEV;
+ }
+
+ csi_dev->clk_csi_mclk = devm_clk_get(dev, "csi_mclk");
+ if (IS_ERR(csi_dev->clk_csi_mclk)) {
+ dev_err(dev, "Could not get csi mclk clock\n");
+ return -ENODEV;
+ }
+
+ csi_dev->dev = dev;
+
+ mx6s_csi_mode_sel(csi_dev);
+ mx6s_csi_two_8bit_sensor_mode_sel(csi_dev);
+
+ of_id = of_match_node(mx6s_csi_dt_ids, csi_dev->dev->of_node);
+ if (!of_id)
+ return -EINVAL;
+ csi_dev->rx_fifo_rst = of_id->data;
+
+ snprintf(csi_dev->v4l2_dev.name,
+ sizeof(csi_dev->v4l2_dev.name), "CSI");
+
+ ret = v4l2_device_register(dev, &csi_dev->v4l2_dev);
+ if (ret < 0) {
+ dev_err(dev, "v4l2_device_register() failed: %d\n", ret);
+ return -ENODEV;
+ }
+
+ /* initialize locks */
+ mutex_init(&csi_dev->lock);
+ spin_lock_init(&csi_dev->slock);
+
+ /* Allocate memory for video device */
+ vdev = video_device_alloc();
+ if (vdev == NULL) {
+ ret = -ENOMEM;
+ goto err_vdev;
+ }
+
+ snprintf(vdev->name, sizeof(vdev->name), "mx6s-csi");
+
+ vdev->v4l2_dev = &csi_dev->v4l2_dev;
+ vdev->fops = &mx6s_csi_fops;
+ vdev->ioctl_ops = &mx6s_csi_ioctl_ops;
+ vdev->release = video_device_release;
+ vdev->lock = &csi_dev->lock;
+
+ vdev->queue = &csi_dev->vb2_vidq;
+
+ csi_dev->vdev = vdev;
+
+ video_set_drvdata(csi_dev->vdev, csi_dev);
+ mutex_lock(&csi_dev->lock);
+
+ ret = video_register_device(csi_dev->vdev, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ video_device_release(csi_dev->vdev);
+ mutex_unlock(&csi_dev->lock);
+ goto err_vdev;
+ }
+
+ /* install interrupt handler */
+ if (devm_request_irq(dev, csi_dev->irq, mx6s_csi_irq_handler,
+ 0, "csi", (void *)csi_dev)) {
+ mutex_unlock(&csi_dev->lock);
+ dev_err(dev, "Request CSI IRQ failed.\n");
+ ret = -ENODEV;
+ goto err_irq;
+ }
+
+ mutex_unlock(&csi_dev->lock);
+
+ ret = mx6sx_register_subdevs(csi_dev);
+ if (ret < 0)
+ goto err_irq;
+
+ pm_runtime_enable(csi_dev->dev);
+ return 0;
+
+err_irq:
+ video_unregister_device(csi_dev->vdev);
+err_vdev:
+ v4l2_device_unregister(&csi_dev->v4l2_dev);
+ return ret;
+}
+
+static int mx6s_csi_remove(struct platform_device *pdev)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+ struct mx6s_csi_dev *csi_dev =
+ container_of(v4l2_dev, struct mx6s_csi_dev, v4l2_dev);
+
+ v4l2_async_notifier_unregister(&csi_dev->subdev_notifier);
+
+ video_unregister_device(csi_dev->vdev);
+ v4l2_device_unregister(&csi_dev->v4l2_dev);
+
+ pm_runtime_disable(csi_dev->dev);
+ return 0;
+}
+
+static int mx6s_csi_runtime_suspend(struct device *dev)
+{
+ dev_dbg(dev, "csi v4l2 busfreq high release.\n");
+ return 0;
+}
+
+static int mx6s_csi_runtime_resume(struct device *dev)
+{
+ dev_dbg(dev, "csi v4l2 busfreq high request.\n");
+ return 0;
+}
+
+static const struct dev_pm_ops mx6s_csi_pm_ops = {
+ SET_RUNTIME_PM_OPS(mx6s_csi_runtime_suspend, mx6s_csi_runtime_resume, NULL)
+};
+
+static const u8 mx6s_fifo_rst = true;
+static const u8 mx6sl_fifo_rst = false;
+
+static const struct of_device_id mx6s_csi_dt_ids[] = {
+ { .compatible = "fsl,imx6s-csi",
+ .data = &mx6s_fifo_rst,
+ },
+ { .compatible = "fsl,imx6sl-csi",
+ .data = &mx6sl_fifo_rst,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mx6s_csi_dt_ids);
+
+static struct platform_driver mx6s_csi_driver = {
+ .driver = {
+ .name = MX6S_CAM_DRV_NAME,
+ .of_match_table = of_match_ptr(mx6s_csi_dt_ids),
+ .pm = &mx6s_csi_pm_ops,
+ },
+ .probe = mx6s_csi_probe,
+ .remove = mx6s_csi_remove,
+};
+
+module_platform_driver(mx6s_csi_driver);
+
+MODULE_DESCRIPTION("i.MX6Sx SoC Camera Host driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(MX6S_CAM_VERSION);
diff --git a/drivers/media/platform/mxc/capture/mxc_mipi_csi.c b/drivers/media/platform/mxc/capture/mxc_mipi_csi.c
new file mode 100644
index 000000000000..202618af4c6d
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/mxc_mipi_csi.c
@@ -0,0 +1,1307 @@
+/*
+ * Freescale i.MX7 SoC series MIPI-CSI V3.3 receiver driver
+ *
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+/*
+ * Samsung S5P/EXYNOS SoC series MIPI-CSI receiver driver
+ *
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-of.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+#define CSIS_DRIVER_NAME "mxc_mipi-csi"
+#define CSIS_SUBDEV_NAME CSIS_DRIVER_NAME
+#define CSIS_MAX_ENTITIES 2
+#define CSIS0_MAX_LANES 4
+#define CSIS1_MAX_LANES 2
+
+#define MIPI_CSIS_DEF_PIX_WIDTH 640
+#define MIPI_CSIS_DEF_PIX_HEIGHT 480
+
+/* Register map definition */
+
+/* CSIS version */
+#define MIPI_CSIS_VERSION 0x00
+
+/* CSIS common control */
+#define MIPI_CSIS_CMN_CTRL 0x04
+#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW (1 << 16)
+#define MIPI_CSIS_CMN_CTRL_INTER_MODE (1 << 10)
+#define MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET 8
+#define MIPI_CSIS_CMN_CTRL_LANE_NR_MASK (3 << 8)
+#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL (1 << 2)
+#define MIPI_CSIS_CMN_CTRL_RESET (1 << 1)
+#define MIPI_CSIS_CMN_CTRL_ENABLE (1 << 0)
+
+/* CSIS clock control */
+#define MIPI_CSIS_CLK_CTRL 0x08
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH3(x) (x << 28)
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH2(x) (x << 24)
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH1(x) (x << 20)
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(x) (x << 16)
+#define MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK (0xf << 4)
+#define MIPI_CSIS_CLK_CTRL_WCLK_SRC (1 << 0)
+
+/* CSIS Interrupt mask */
+#define MIPI_CSIS_INTMSK 0x10
+#define MIPI_CSIS_INTMSK_EVEN_BEFORE (1 << 31)
+#define MIPI_CSIS_INTMSK_EVEN_AFTER (1 << 30)
+#define MIPI_CSIS_INTMSK_ODD_BEFORE (1 << 29)
+#define MIPI_CSIS_INTMSK_ODD_AFTER (1 << 28)
+#define MIPI_CSIS_INTMSK_FRAME_START (1 << 24)
+#define MIPI_CSIS_INTMSK_FRAME_END (1 << 20)
+#define MIPI_CSIS_INTMSK_ERR_SOT_HS (1 << 16)
+#define MIPI_CSIS_INTMSK_ERR_LOST_FS (1 << 12)
+#define MIPI_CSIS_INTMSK_ERR_LOST_FE (1 << 8)
+#define MIPI_CSIS_INTMSK_ERR_OVER (1 << 4)
+#define MIPI_CSIS_INTMSK_ERR_WRONG_CFG (1 << 3)
+#define MIPI_CSIS_INTMSK_ERR_ECC (1 << 2)
+#define MIPI_CSIS_INTMSK_ERR_CRC (1 << 1)
+#define MIPI_CSIS_INTMSK_ERR_UNKNOWN (1 << 0)
+
+/* CSIS Interrupt source */
+#define MIPI_CSIS_INTSRC 0x14
+#define MIPI_CSIS_INTSRC_EVEN_BEFORE (1 << 31)
+#define MIPI_CSIS_INTSRC_EVEN_AFTER (1 << 30)
+#define MIPI_CSIS_INTSRC_EVEN (0x3 << 30)
+#define MIPI_CSIS_INTSRC_ODD_BEFORE (1 << 29)
+#define MIPI_CSIS_INTSRC_ODD_AFTER (1 << 28)
+#define MIPI_CSIS_INTSRC_ODD (0x3 << 28)
+#define MIPI_CSIS_INTSRC_NON_IMAGE_DATA (0xf << 28)
+#define MIPI_CSIS_INTSRC_FRAME_START (1 << 24)
+#define MIPI_CSIS_INTSRC_FRAME_END (1 << 20)
+#define MIPI_CSIS_INTSRC_ERR_SOT_HS (1 << 16)
+#define MIPI_CSIS_INTSRC_ERR_LOST_FS (1 << 12)
+#define MIPI_CSIS_INTSRC_ERR_LOST_FE (1 << 8)
+#define MIPI_CSIS_INTSRC_ERR_OVER (1 << 4)
+#define MIPI_CSIS_INTSRC_ERR_WRONG_CFG (1 << 3)
+#define MIPI_CSIS_INTSRC_ERR_ECC (1 << 2)
+#define MIPI_CSIS_INTSRC_ERR_CRC (1 << 1)
+#define MIPI_CSIS_INTSRC_ERR_UNKNOWN (1 << 0)
+#define MIPI_CSIS_INTSRC_ERRORS 0xfffff
+
+/* D-PHY status control */
+#define MIPI_CSIS_DPHYSTATUS 0x20
+#define MIPI_CSIS_DPHYSTATUS_ULPS_DAT (1 << 8)
+#define MIPI_CSIS_DPHYSTATUS_STOPSTATE_DAT (1 << 4)
+#define MIPI_CSIS_DPHYSTATUS_ULPS_CLK (1 << 1)
+#define MIPI_CSIS_DPHYSTATUS_STOPSTATE_CLK (1 << 0)
+
+/* D-PHY common control */
+#define MIPI_CSIS_DPHYCTRL 0x24
+#define MIPI_CSIS_DPHYCTRL_HSS_MASK (0xff << 24)
+#define MIPI_CSIS_DPHYCTRL_HSS_OFFSET 24
+#define MIPI_CSIS_DPHYCTRL_SCLKS_MASK (0x3 << 22)
+#define MIPI_CSIS_DPHYCTRL_SCLKS_OFFSET 22
+#define MIPI_CSIS_DPHYCTRL_DPDN_SWAP_CLK (1 << 6)
+#define MIPI_CSIS_DPHYCTRL_DPDN_SWAP_DAT (1 << 5)
+#define MIPI_CSIS_DPHYCTRL_ENABLE_DAT (1 << 1)
+#define MIPI_CSIS_DPHYCTRL_ENABLE_CLK (1 << 0)
+#define MIPI_CSIS_DPHYCTRL_ENABLE (0x1f << 0)
+
+/* D-PHY Master and Slave Control register Low */
+#define MIPI_CSIS_DPHYBCTRL_L 0x30
+/* D-PHY Master and Slave Control register High */
+#define MIPI_CSIS_DPHYBCTRL_H 0x34
+/* D-PHY Slave Control register Low */
+#define MIPI_CSIS_DPHYSCTRL_L 0x38
+/* D-PHY Slave Control register High */
+#define MIPI_CSIS_DPHYSCTRL_H 0x3c
+
+
+/* ISP Configuration register */
+#define MIPI_CSIS_ISPCONFIG_CH0 0x40
+#define MIPI_CSIS_ISPCONFIG_CH1 0x50
+#define MIPI_CSIS_ISPCONFIG_CH2 0x60
+#define MIPI_CSIS_ISPCONFIG_CH3 0x70
+
+#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP_MSK (0xff << 24)
+#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP(x) (x << 24)
+#define MIPI_CSIS_ISPCFG_DOUBLE_CMPNT (1 << 12)
+#define MIPI_CSIS_ISPCFG_ALIGN_32BIT (1 << 11)
+#define MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT (0x1e << 2)
+#define MIPI_CSIS_ISPCFG_FMT_RAW8 (0x2a << 2)
+#define MIPI_CSIS_ISPCFG_FMT_RAW10 (0x2b << 2)
+#define MIPI_CSIS_ISPCFG_FMT_RAW12 (0x2c << 2)
+/* User defined formats, x = 1...4 */
+#define MIPI_CSIS_ISPCFG_FMT_USER(x) ((0x30 + x - 1) << 2)
+#define MIPI_CSIS_ISPCFG_FMT_MASK (0x3f << 2)
+
+/* ISP Image Resolution register */
+#define MIPI_CSIS_ISPRESOL_CH0 0x44
+#define MIPI_CSIS_ISPRESOL_CH1 0x54
+#define MIPI_CSIS_ISPRESOL_CH2 0x64
+#define MIPI_CSIS_ISPRESOL_CH3 0x74
+#define CSIS_MAX_PIX_WIDTH 0xffff
+#define CSIS_MAX_PIX_HEIGHT 0xffff
+
+/* ISP SYNC register */
+#define MIPI_CSIS_ISPSYNC_CH0 0x48
+#define MIPI_CSIS_ISPSYNC_CH1 0x58
+#define MIPI_CSIS_ISPSYNC_CH2 0x68
+#define MIPI_CSIS_ISPSYNC_CH3 0x78
+
+#define MIPI_CSIS_ISPSYNC_HSYNC_LINTV_OFFSET 18
+#define MIPI_CSIS_ISPSYNC_VSYNC_SINTV_OFFSET 12
+#define MIPI_CSIS_ISPSYNC_VSYNC_EINTV_OFFSET 0
+
+/* Non-image packet data buffers */
+#define MIPI_CSIS_PKTDATA_ODD 0x2000
+#define MIPI_CSIS_PKTDATA_EVEN 0x3000
+#define MIPI_CSIS_PKTDATA_SIZE SZ_4K
+
+#define MIPI_CSIS_MISC 0x8008
+
+#define DEFAULT_SCLK_CSIS_FREQ 166000000UL
+
+enum {
+ ST_POWERED = 1,
+ ST_STREAMING = 2,
+ ST_SUSPENDED = 4,
+};
+
+struct mipi_csis_event {
+ u32 mask;
+ const char * const name;
+ unsigned int counter;
+};
+
+static const struct mipi_csis_event mipi_csis_events[] = {
+ /* Errors */
+ { MIPI_CSIS_INTSRC_ERR_SOT_HS, "SOT Error" },
+ { MIPI_CSIS_INTSRC_ERR_LOST_FS, "Lost Frame Start Error" },
+ { MIPI_CSIS_INTSRC_ERR_LOST_FE, "Lost Frame End Error" },
+ { MIPI_CSIS_INTSRC_ERR_OVER, "FIFO Overflow Error" },
+ { MIPI_CSIS_INTSRC_ERR_ECC, "ECC Error" },
+ { MIPI_CSIS_INTSRC_ERR_CRC, "CRC Error" },
+ { MIPI_CSIS_INTSRC_ERR_UNKNOWN, "Unknown Error" },
+ /* Non-image data receive events */
+ { MIPI_CSIS_INTSRC_EVEN_BEFORE, "Non-image data before even frame" },
+ { MIPI_CSIS_INTSRC_EVEN_AFTER, "Non-image data after even frame" },
+ { MIPI_CSIS_INTSRC_ODD_BEFORE, "Non-image data before odd frame" },
+ { MIPI_CSIS_INTSRC_ODD_AFTER, "Non-image data after odd frame" },
+ /* Frame start/end */
+ { MIPI_CSIS_INTSRC_FRAME_START, "Frame Start" },
+ { MIPI_CSIS_INTSRC_FRAME_END, "Frame End" },
+};
+#define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events)
+
+struct csis_pktbuf {
+ u32 *data;
+ unsigned int len;
+};
+
+struct csis_hw_reset {
+ struct regmap *src;
+ u8 req_src;
+ u8 rst_bit;
+};
+
+/**
+ * struct csi_state - the driver's internal state data structure
+ * @lock: mutex serializing the subdev and power management operations,
+ * protecting @format and @flags members
+ * @sd: v4l2_subdev associated with CSIS device instance
+ * @index: the hardware instance index
+ * @pdev: CSIS platform device
+ * @phy: pointer to the CSIS generic PHY
+ * @regs: mmaped I/O registers memory
+ * @supplies: CSIS regulator supplies
+ * @clock: CSIS clocks
+ * @irq: requested s5p-mipi-csis irq number
+ * @flags: the state variable for power and streaming control
+ * @clock_frequency: device bus clock frequency
+ * @hs_settle: HS-RX settle time
+ * @clk_settle: Clk settle time
+ * @num_lanes: number of MIPI-CSI data lanes used
+ * @max_num_lanes: maximum number of MIPI-CSI data lanes supported
+ * @wclk_ext: CSI wrapper clock: 0 - bus clock, 1 - external SCLK_CAM
+ * @csis_fmt: current CSIS pixel format
+ * @format: common media bus format for the source and sink pad
+ * @slock: spinlock protecting structure members below
+ * @pkt_buf: the frame embedded (non-image) data buffer
+ * @events: MIPI-CSIS event (error) counters
+ */
+struct csi_state {
+ struct mutex lock;
+ struct device *dev;
+ struct v4l2_subdev mipi_sd;
+ struct v4l2_subdev *sensor_sd;
+ struct v4l2_device v4l2_dev;
+
+ u8 index;
+ struct platform_device *pdev;
+ struct phy *phy;
+ void __iomem *regs;
+ struct clk *mipi_clk;
+ struct clk *phy_clk;
+ struct clk *disp_axi;
+ struct clk *disp_apb;
+ int irq;
+ u32 flags;
+
+ u32 clk_frequency;
+ u32 hs_settle;
+ u32 clk_settle;
+ u32 num_lanes;
+ u32 max_num_lanes;
+ u8 wclk_ext;
+
+ const struct csis_pix_format *csis_fmt;
+ struct v4l2_mbus_framefmt format;
+
+ spinlock_t slock;
+ struct csis_pktbuf pkt_buf;
+ struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS];
+
+ struct v4l2_async_subdev asd;
+ struct v4l2_async_notifier subdev_notifier;
+ struct v4l2_async_subdev *async_subdevs[2];
+
+ struct csis_hw_reset hw_reset;
+ struct regulator *mipi_phy_regulator;
+};
+
+/**
+ * struct csis_pix_format - CSIS pixel format description
+ * @pix_width_alignment: horizontal pixel alignment, width will be
+ * multiple of 2^pix_width_alignment
+ * @code: corresponding media bus code
+ * @fmt_reg: MIPI_CSIS_CONFIG register value
+ * @data_alignment: MIPI-CSI data alignment in bits
+ */
+struct csis_pix_format {
+ unsigned int pix_width_alignment;
+ u32 code;
+ u32 fmt_reg;
+ u8 data_alignment;
+};
+
+static const struct csis_pix_format mipi_csis_formats[] = {
+ {
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .fmt_reg = MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT,
+ .data_alignment = 16,
+ }, {
+ .code = MEDIA_BUS_FMT_VYUY8_2X8,
+ .fmt_reg = MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT,
+ .data_alignment = 16,
+ }, {
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8,
+ .data_alignment = 8,
+ }
+};
+
+typedef int (*mipi_csis_phy_reset_t)(struct csi_state *state);
+
+#define mipi_csis_write(__csis, __r, __v) writel(__v, __csis->regs + __r)
+#define mipi_csis_read(__csis, __r) readl(__csis->regs + __r)
+
+static struct csi_state *mipi_sd_to_csi_state(struct v4l2_subdev *sdev)
+{
+ return container_of(sdev, struct csi_state, mipi_sd);
+}
+
+static inline struct csi_state
+ *notifier_to_mipi_dev(struct v4l2_async_notifier *n)
+{
+ return container_of(n, struct csi_state, subdev_notifier);
+}
+
+static const struct csis_pix_format *find_csis_format(u32 code)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mipi_csis_formats); i++)
+ if (code == mipi_csis_formats[i].code)
+ return &mipi_csis_formats[i];
+ return NULL;
+}
+
+static void mipi_csis_enable_interrupts(struct csi_state *state, bool on)
+{
+ u32 val = mipi_csis_read(state, MIPI_CSIS_INTMSK);
+ if (on)
+ val |= 0xf00fffff;
+ else
+ val &= ~0xf00fffff;
+ mipi_csis_write(state, MIPI_CSIS_INTMSK, val);
+}
+
+static void mipi_csis_sw_reset(struct csi_state *state)
+{
+ u32 val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
+
+ mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val | MIPI_CSIS_CMN_CTRL_RESET);
+ udelay(10);
+}
+
+static int mipi_csis_phy_init(struct csi_state *state)
+{
+ int ret;
+
+ state->mipi_phy_regulator = devm_regulator_get(state->dev,
+ "mipi-phy");
+
+ ret = regulator_set_voltage(state->mipi_phy_regulator,
+ 1000000, 1000000);
+
+ return ret;
+}
+
+static int mipi_csis_phy_reset_mx8mm(struct csi_state *state)
+{
+ struct device_node *np;
+ void __iomem *reg;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-csi");
+ if (WARN_ON(!np))
+ return -ENXIO;
+
+ reg = of_iomap(np, 0);
+
+ writel(0, reg + MIPI_CSIS_MISC);
+ usleep_range(10, 20);
+ writel(0x30000, reg + MIPI_CSIS_MISC);
+ usleep_range(10, 20);
+
+ return 0;
+}
+
+static int mipi_csis_phy_reset(struct csi_state *state)
+{
+ struct device_node *np = state->dev->of_node;
+ struct device_node *node;
+ phandle phandle;
+ u32 out_val[3];
+ int ret;
+
+ ret = of_property_read_u32_array(np, "csis-phy-reset", out_val, 3);
+ if (ret) {
+ dev_dbg(state->dev, "no csis-hw-reset property found\n");
+ } else {
+ phandle = *out_val;
+
+ node = of_find_node_by_phandle(phandle);
+ if (!node) {
+ dev_dbg(state->dev, "not find src node by phandle\n");
+ ret = PTR_ERR(node);
+ }
+ state->hw_reset.src = syscon_node_to_regmap(node);
+ if (IS_ERR(state->hw_reset.src)) {
+ dev_err(state->dev, "failed to get src regmap\n");
+ ret = PTR_ERR(state->hw_reset.src);
+ }
+ of_node_put(node);
+ if (ret < 0)
+ return ret;
+
+ state->hw_reset.req_src = out_val[1];
+ state->hw_reset.rst_bit = out_val[2];
+
+ /* reset mipi phy */
+ regmap_update_bits(state->hw_reset.src, state->hw_reset.req_src,
+ 1 << state->hw_reset.rst_bit, 1 << state->hw_reset.rst_bit);
+ msleep(20);
+ regmap_update_bits(state->hw_reset.src, state->hw_reset.req_src,
+ 1 << state->hw_reset.rst_bit, 0);
+
+ }
+ return ret;
+}
+
+static void mipi_csis_system_enable(struct csi_state *state, int on)
+{
+ u32 val, mask;
+
+ val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
+ if (on)
+ val |= MIPI_CSIS_CMN_CTRL_ENABLE;
+ else
+ val &= ~MIPI_CSIS_CMN_CTRL_ENABLE;
+ mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val);
+
+ val = mipi_csis_read(state, MIPI_CSIS_DPHYCTRL);
+ val &= ~MIPI_CSIS_DPHYCTRL_ENABLE;
+ if (on) {
+ mask = (1 << (state->num_lanes + 1)) - 1;
+ val |= (mask & MIPI_CSIS_DPHYCTRL_ENABLE);
+ }
+ mipi_csis_write(state, MIPI_CSIS_DPHYCTRL, val);
+}
+
+/* Called with the state.lock mutex held */
+static void __mipi_csis_set_format(struct csi_state *state)
+{
+ struct v4l2_mbus_framefmt *mf = &state->format;
+ u32 val;
+
+ v4l2_dbg(1, debug, &state->mipi_sd, "fmt: %#x, %d x %d\n",
+ mf->code, mf->width, mf->height);
+
+ /* Color format */
+ val = mipi_csis_read(state, MIPI_CSIS_ISPCONFIG_CH0);
+ val = (val & ~MIPI_CSIS_ISPCFG_FMT_MASK) | state->csis_fmt->fmt_reg;
+ mipi_csis_write(state, MIPI_CSIS_ISPCONFIG_CH0, val);
+
+ /* Pixel resolution */
+ val = mf->width | (mf->height << 16);
+ mipi_csis_write(state, MIPI_CSIS_ISPRESOL_CH0, val);
+}
+
+static void mipi_csis_set_hsync_settle(struct csi_state *state,
+ int hs_settle, int clk_settle)
+{
+ u32 val = mipi_csis_read(state, MIPI_CSIS_DPHYCTRL);
+
+ val = (val & ~MIPI_CSIS_DPHYCTRL_HSS_MASK) |
+ (hs_settle << 24) | (clk_settle << 22);
+
+ mipi_csis_write(state, MIPI_CSIS_DPHYCTRL, val);
+}
+
+static void mipi_csis_set_params(struct csi_state *state)
+{
+ u32 val;
+
+ val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
+ val &= ~MIPI_CSIS_CMN_CTRL_LANE_NR_MASK;
+ val |= (state->num_lanes - 1) << MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET;
+ mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val);
+
+ __mipi_csis_set_format(state);
+
+ mipi_csis_set_hsync_settle(state, state->hs_settle, state->clk_settle);
+
+ val = mipi_csis_read(state, MIPI_CSIS_ISPCONFIG_CH0);
+ if (state->csis_fmt->data_alignment == 32)
+ val |= MIPI_CSIS_ISPCFG_ALIGN_32BIT;
+ else /* Normal output */
+ val &= ~MIPI_CSIS_ISPCFG_ALIGN_32BIT;
+ mipi_csis_write(state, MIPI_CSIS_ISPCONFIG_CH0, val);
+
+ val = (0 << MIPI_CSIS_ISPSYNC_HSYNC_LINTV_OFFSET) |
+ (0 << MIPI_CSIS_ISPSYNC_VSYNC_SINTV_OFFSET) |
+ (0 << MIPI_CSIS_ISPSYNC_VSYNC_EINTV_OFFSET);
+ mipi_csis_write(state, MIPI_CSIS_ISPSYNC_CH0, val);
+
+ val = mipi_csis_read(state, MIPI_CSIS_CLK_CTRL);
+ val &= ~MIPI_CSIS_CLK_CTRL_WCLK_SRC;
+ if (state->wclk_ext)
+ val |= MIPI_CSIS_CLK_CTRL_WCLK_SRC;
+ val |= MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(15);
+ val &= ~MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK;
+ mipi_csis_write(state, MIPI_CSIS_CLK_CTRL, val);
+
+ mipi_csis_write(state, MIPI_CSIS_DPHYBCTRL_L, 0x1f4);
+ mipi_csis_write(state, MIPI_CSIS_DPHYBCTRL_H, 0);
+
+ /* Update the shadow register. */
+ val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
+ mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW |
+ MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL);
+}
+
+static void mipi_csis_clk_enable(struct csi_state *state)
+{
+ clk_prepare_enable(state->mipi_clk);
+ clk_prepare_enable(state->phy_clk);
+ if (state->disp_axi)
+ clk_prepare_enable(state->disp_axi);
+ if (state->disp_apb)
+ clk_prepare_enable(state->disp_apb);
+}
+
+static void mipi_csis_clk_disable(struct csi_state *state)
+{
+ clk_disable_unprepare(state->mipi_clk);
+ clk_disable_unprepare(state->phy_clk);
+ if (state->disp_axi)
+ clk_disable_unprepare(state->disp_axi);
+ if (state->disp_apb)
+ clk_disable_unprepare(state->disp_apb);
+}
+
+static int mipi_csis_clk_get(struct csi_state *state)
+{
+ struct device *dev = &state->pdev->dev;
+ int ret = true;
+
+ state->mipi_clk = devm_clk_get(dev, "mipi_clk");
+ if (IS_ERR(state->mipi_clk)) {
+ dev_err(dev, "Could not get mipi csi clock\n");
+ return -ENODEV;
+ }
+
+ state->phy_clk = devm_clk_get(dev, "phy_clk");
+ if (IS_ERR(state->phy_clk)) {
+ dev_err(dev, "Could not get mipi phy clock\n");
+ return -ENODEV;
+ }
+
+ state->disp_axi = devm_clk_get(dev, "disp_axi");
+ if (IS_ERR(state->disp_axi)) {
+ dev_warn(dev, "Could not get disp_axi clock\n");
+ state->disp_axi = NULL;
+ }
+
+ state->disp_apb = devm_clk_get(dev, "disp_apb");
+ if (IS_ERR(state->disp_apb)) {
+ dev_warn(dev, "Could not get disp apb clock\n");
+ state->disp_apb = NULL;
+ }
+
+ /* Set clock rate */
+ if (state->clk_frequency)
+ ret = clk_set_rate(state->mipi_clk,
+ state->clk_frequency);
+ else
+ dev_WARN(dev, "No clock frequency specified!\n");
+ if (ret < 0) {
+ dev_err(dev, "set rate filed, rate=%d\n", state->clk_frequency);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static void dump_regs(struct csi_state *state, const char *label)
+{
+ struct {
+ u32 offset;
+ const char * const name;
+ } registers[] = {
+ { 0x00, "CTRL" },
+ { 0x04, "DPHYCTRL" },
+ { 0x08, "CONFIG" },
+ { 0x0c, "DPHYSTS" },
+ { 0x10, "INTMSK" },
+ { 0x2c, "RESOL" },
+ { 0x38, "SDW_CONFIG" },
+ };
+ u32 i;
+
+ v4l2_info(&state->mipi_sd, "--- %s ---\n", label);
+
+ for (i = 0; i < ARRAY_SIZE(registers); i++) {
+ u32 cfg = mipi_csis_read(state, registers[i].offset);
+ v4l2_info(&state->mipi_sd, "%10s: 0x%08x\n", registers[i].name, cfg);
+ }
+}
+
+static void mipi_csis_start_stream(struct csi_state *state)
+{
+ mipi_csis_sw_reset(state);
+ mipi_csis_set_params(state);
+ mipi_csis_system_enable(state, true);
+ mipi_csis_enable_interrupts(state, true);
+}
+
+static void mipi_csis_stop_stream(struct csi_state *state)
+{
+ mipi_csis_enable_interrupts(state, false);
+ mipi_csis_system_enable(state, false);
+}
+
+static void mipi_csis_clear_counters(struct csi_state *state)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&state->slock, flags);
+ for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++)
+ state->events[i].counter = 0;
+ spin_unlock_irqrestore(&state->slock, flags);
+}
+
+static void mipi_csis_log_counters(struct csi_state *state, bool non_errors)
+{
+ int i = non_errors ? MIPI_CSIS_NUM_EVENTS : MIPI_CSIS_NUM_EVENTS - 4;
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->slock, flags);
+
+ for (i--; i >= 0; i--) {
+ if (state->events[i].counter > 0 || debug)
+ v4l2_info(&state->mipi_sd, "%s events: %d\n",
+ state->events[i].name,
+ state->events[i].counter);
+ }
+ spin_unlock_irqrestore(&state->slock, flags);
+}
+
+/*
+ * V4L2 subdev operations
+ */
+static int mipi_csis_s_power(struct v4l2_subdev *mipi_sd, int on)
+{
+ struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+ struct device *dev = &state->pdev->dev;
+
+ v4l2_subdev_call(state->sensor_sd, core, s_power, on);
+
+ if (on)
+ return pm_runtime_get_sync(dev);
+
+ return pm_runtime_put_sync(dev);
+}
+
+static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable)
+{
+ struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, mipi_sd, "%s: %d, state: 0x%x\n",
+ __func__, enable, state->flags);
+
+ if (enable) {
+ mipi_csis_clear_counters(state);
+ ret = pm_runtime_get_sync(&state->pdev->dev);
+ if (ret && ret != 1)
+ return ret;
+ }
+
+ mutex_lock(&state->lock);
+ if (enable) {
+ if (state->flags & ST_SUSPENDED) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+ mipi_csis_start_stream(state);
+ v4l2_subdev_call(state->sensor_sd, video, s_stream, true);
+ state->flags |= ST_STREAMING;
+ } else {
+ v4l2_subdev_call(state->sensor_sd, video, s_stream, false);
+ mipi_csis_stop_stream(state);
+ state->flags &= ~ST_STREAMING;
+ if (debug > 0)
+ mipi_csis_log_counters(state, true);
+ }
+unlock:
+ mutex_unlock(&state->lock);
+ if (!enable)
+ pm_runtime_put(&state->pdev->dev);
+
+ return ret == 1 ? 0 : ret;
+}
+
+static int mipi_csis_enum_mbus_code(struct v4l2_subdev *mipi_sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+ struct v4l2_subdev *sensor_sd = state->sensor_sd;
+ struct csis_pix_format const *csis_fmt;
+ int ret;
+
+ ret = v4l2_subdev_call(sensor_sd, pad, enum_mbus_code, NULL, code);
+ if (ret < 0)
+ return -EINVAL;
+
+ csis_fmt = find_csis_format(code->code);
+ if (csis_fmt == NULL) {
+ dev_err(state->dev, "format not match\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+ struct v4l2_subdev *sensor_sd = state->sensor_sd;
+ struct csis_pix_format const *csis_fmt;
+ struct v4l2_mbus_framefmt *mf = &format->format;
+
+ if (format->pad)
+ return -EINVAL;
+
+ csis_fmt = find_csis_format(mf->code);
+ if (csis_fmt == NULL)
+ csis_fmt = &mipi_csis_formats[0];
+
+ v4l2_subdev_call(sensor_sd, pad, set_fmt, NULL, format);
+
+ mf->code = csis_fmt->code;
+ v4l_bound_align_image(&mf->width, 1, CSIS_MAX_PIX_WIDTH,
+ csis_fmt->pix_width_alignment,
+ &mf->height, 1, CSIS_MAX_PIX_HEIGHT, 1,
+ 0);
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+ return 0;
+
+ state->format.code = mf->code;
+ state->format.width = mf->width;
+ state->format.height = mf->height;
+
+ mutex_lock(&state->lock);
+ state->csis_fmt = csis_fmt;
+ mutex_unlock(&state->lock);
+
+ return 0;
+}
+
+static int mipi_csis_get_fmt(struct v4l2_subdev *mipi_sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+ struct v4l2_subdev *sensor_sd = state->sensor_sd;
+
+ if (format->pad)
+ return -EINVAL;
+
+ return v4l2_subdev_call(sensor_sd, pad, get_fmt, NULL, format);
+}
+
+static int mipi_csis_s_rx_buffer(struct v4l2_subdev *mipi_sd, void *buf,
+ unsigned int *size)
+{
+ struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+ unsigned long flags;
+
+ *size = min_t(unsigned int, *size, MIPI_CSIS_PKTDATA_SIZE);
+
+ spin_lock_irqsave(&state->slock, flags);
+ state->pkt_buf.data = buf;
+ state->pkt_buf.len = *size;
+ spin_unlock_irqrestore(&state->slock, flags);
+
+ return 0;
+}
+
+static int mipi_csis_s_parm(struct v4l2_subdev *mipi_sd, struct v4l2_streamparm *a)
+{
+ struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+ struct v4l2_subdev *sensor_sd = state->sensor_sd;
+
+ return v4l2_subdev_call(sensor_sd, video, s_parm, a);
+}
+
+static int mipi_csis_g_parm(struct v4l2_subdev *mipi_sd, struct v4l2_streamparm *a)
+{
+ struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+ struct v4l2_subdev *sensor_sd = state->sensor_sd;
+
+ return v4l2_subdev_call(sensor_sd, video, g_parm, a);
+}
+
+static int mipi_csis_enum_framesizes(struct v4l2_subdev *mipi_sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+ struct v4l2_subdev *sensor_sd = state->sensor_sd;
+
+ return v4l2_subdev_call(sensor_sd, pad, enum_frame_size, NULL, fse);
+}
+
+static int mipi_csis_enum_frameintervals(struct v4l2_subdev *mipi_sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+ struct v4l2_subdev *sensor_sd = state->sensor_sd;
+
+ return v4l2_subdev_call(sensor_sd, pad, enum_frame_interval, NULL, fie);
+}
+
+static int mipi_csis_log_status(struct v4l2_subdev *mipi_sd)
+{
+ struct csi_state *state = mipi_sd_to_csi_state(mipi_sd);
+
+ mutex_lock(&state->lock);
+ mipi_csis_log_counters(state, true);
+ if (debug && (state->flags & ST_POWERED))
+ dump_regs(state, __func__);
+ mutex_unlock(&state->lock);
+ return 0;
+}
+
+static struct v4l2_subdev_core_ops mipi_csis_core_ops = {
+ .s_power = mipi_csis_s_power,
+ .log_status = mipi_csis_log_status,
+};
+
+static struct v4l2_subdev_video_ops mipi_csis_video_ops = {
+ .s_rx_buffer = mipi_csis_s_rx_buffer,
+ .s_stream = mipi_csis_s_stream,
+
+ .s_parm = mipi_csis_s_parm,
+ .g_parm = mipi_csis_g_parm,
+};
+
+static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = {
+ .enum_frame_size = mipi_csis_enum_framesizes,
+ .enum_frame_interval = mipi_csis_enum_frameintervals,
+ .enum_mbus_code = mipi_csis_enum_mbus_code,
+ .get_fmt = mipi_csis_get_fmt,
+ .set_fmt = mipi_csis_set_fmt,
+};
+
+static struct v4l2_subdev_ops mipi_csis_subdev_ops = {
+ .core = &mipi_csis_core_ops,
+ .video = &mipi_csis_video_ops,
+ .pad = &mipi_csis_pad_ops,
+};
+
+static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
+{
+ struct csi_state *state = dev_id;
+ struct csis_pktbuf *pktbuf = &state->pkt_buf;
+ unsigned long flags;
+ u32 status;
+
+ status = mipi_csis_read(state, MIPI_CSIS_INTSRC);
+
+ spin_lock_irqsave(&state->slock, flags);
+
+ if ((status & MIPI_CSIS_INTSRC_NON_IMAGE_DATA) && pktbuf->data) {
+ u32 offset;
+
+ if (status & MIPI_CSIS_INTSRC_EVEN)
+ offset = MIPI_CSIS_PKTDATA_EVEN;
+ else
+ offset = MIPI_CSIS_PKTDATA_ODD;
+
+ memcpy(pktbuf->data, state->regs + offset, pktbuf->len);
+ pktbuf->data = NULL;
+ rmb();
+ }
+
+ /* Update the event/error counters */
+ if ((status & MIPI_CSIS_INTSRC_ERRORS) || debug) {
+ int i;
+ for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) {
+ if (!(status & state->events[i].mask))
+ continue;
+ state->events[i].counter++;
+ v4l2_dbg(2, debug, &state->mipi_sd, "%s: %d\n",
+ state->events[i].name,
+ state->events[i].counter);
+ }
+ v4l2_dbg(2, debug, &state->mipi_sd, "status: %08x\n", status);
+ }
+ spin_unlock_irqrestore(&state->slock, flags);
+
+ mipi_csis_write(state, MIPI_CSIS_INTSRC, status);
+ return IRQ_HANDLED;
+}
+
+static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct csi_state *state = notifier_to_mipi_dev(notifier);
+
+ /* Find platform data for this sensor subdev */
+ if (state->asd.match.of.node == subdev->dev->of_node)
+ state->sensor_sd = subdev;
+
+ if (subdev == NULL)
+ return -EINVAL;
+
+ v4l2_info(&state->v4l2_dev, "Registered sensor subdevice: %s\n",
+ subdev->name);
+
+ return 0;
+}
+
+static int mipi_csis_parse_dt(struct platform_device *pdev,
+ struct csi_state *state)
+{
+ struct device_node *node = pdev->dev.of_node;
+
+ if (of_property_read_u32(node, "clock-frequency",
+ &state->clk_frequency))
+ state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ;
+ if (of_property_read_u32(node, "bus-width",
+ &state->max_num_lanes))
+ return -EINVAL;
+
+ node = of_graph_get_next_endpoint(node, NULL);
+ if (!node) {
+ dev_err(&pdev->dev, "No port node at %s\n",
+ pdev->dev.of_node->full_name);
+ return -EINVAL;
+ }
+
+ /* Get MIPI CSI-2 bus configration from the endpoint node. */
+ of_property_read_u32(node, "csis-hs-settle",
+ &state->hs_settle);
+
+ of_property_read_u32(node, "csis-clk-settle",
+ &state->clk_settle);
+ state->wclk_ext = of_property_read_bool(node,
+ "csis-wclk");
+
+ of_property_read_u32(node, "data-lanes",
+ &state->num_lanes);
+ of_node_put(node);
+
+ return 0;
+}
+
+static int mipi_csis_pm_resume(struct device *dev, bool runtime);
+static const struct of_device_id mipi_csis_of_match[];
+
+/* register parent dev */
+static int mipi_csis_subdev_host(struct csi_state *state)
+{
+ struct device_node *parent = state->dev->of_node;
+ struct device_node *node, *port, *rem;
+ int ret;
+
+ /* Attach sensors linked to csi receivers */
+ for_each_available_child_of_node(parent, node) {
+ if (of_node_cmp(node->name, "port"))
+ continue;
+
+ /* The csi node can have only port subnode. */
+ port = of_get_next_child(node, NULL);
+ if (!port)
+ continue;
+ rem = of_graph_get_remote_port_parent(port);
+ of_node_put(port);
+ if (rem == NULL) {
+ v4l2_info(&state->v4l2_dev,
+ "Remote device at %s not found\n",
+ port->full_name);
+ return -1;
+ }
+
+ state->asd.match_type = V4L2_ASYNC_MATCH_OF;
+ state->asd.match.of.node = rem;
+ state->async_subdevs[0] = &state->asd;
+
+ of_node_put(rem);
+ break;
+ }
+
+ state->subdev_notifier.subdevs = state->async_subdevs;
+ state->subdev_notifier.num_subdevs = 1;
+ state->subdev_notifier.bound = subdev_notifier_bound;
+
+ ret = v4l2_async_notifier_register(&state->v4l2_dev,
+ &state->subdev_notifier);
+ if (ret)
+ dev_err(state->dev,
+ "Error register async notifier regoster\n");
+
+ return ret;
+}
+
+/* init subdev */
+static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd,
+ struct platform_device *pdev,
+ const struct v4l2_subdev_ops *ops)
+{
+ struct csi_state *state = platform_get_drvdata(pdev);
+ int ret = 0;
+
+ v4l2_subdev_init(mipi_sd, ops);
+ mipi_sd->owner = THIS_MODULE;
+ snprintf(mipi_sd->name, sizeof(mipi_sd->name), "%s.%d",
+ CSIS_SUBDEV_NAME, state->index);
+ mipi_sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ mipi_sd->dev = &pdev->dev;
+
+ state->csis_fmt = &mipi_csis_formats[0];
+ state->format.code = mipi_csis_formats[0].code;
+ state->format.width = MIPI_CSIS_DEF_PIX_WIDTH;
+ state->format.height = MIPI_CSIS_DEF_PIX_HEIGHT;
+
+ /* This allows to retrieve the platform device id by the host driver */
+ v4l2_set_subdevdata(mipi_sd, pdev);
+
+ ret = v4l2_async_register_subdev(mipi_sd);
+ if (ret < 0)
+ dev_err(&pdev->dev, "%s--Async register faialed, ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int mipi_csis_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct v4l2_subdev *mipi_sd;
+ struct resource *mem_res;
+ struct csi_state *state;
+ const struct of_device_id *of_id;
+ mipi_csis_phy_reset_t phy_reset_fn;
+ int ret = -ENOMEM;
+
+ state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ mutex_init(&state->lock);
+ spin_lock_init(&state->slock);
+
+ state->pdev = pdev;
+ mipi_sd = &state->mipi_sd;
+ state->dev = dev;
+
+ ret = mipi_csis_parse_dt(pdev, state);
+ if (ret < 0)
+ return ret;
+
+ if (state->num_lanes == 0 || state->num_lanes > state->max_num_lanes) {
+ dev_err(dev, "Unsupported number of data lanes: %d (max. %d)\n",
+ state->num_lanes, state->max_num_lanes);
+ return -EINVAL;
+ }
+
+ mipi_csis_phy_init(state);
+ of_id = of_match_node(mipi_csis_of_match, dev->of_node);
+ if (!of_id || !of_id->data)
+ return -EINVAL;
+
+ phy_reset_fn = of_id->data;
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ state->regs = devm_ioremap_resource(dev, mem_res);
+ if (IS_ERR(state->regs))
+ return PTR_ERR(state->regs);
+
+ state->irq = platform_get_irq(pdev, 0);
+ if (state->irq < 0) {
+ dev_err(dev, "Failed to get irq\n");
+ return state->irq;
+ }
+
+ ret = mipi_csis_clk_get(state);
+ if (ret < 0)
+ return ret;
+
+ mipi_csis_clk_enable(state);
+
+ phy_reset_fn(state);
+
+ ret = devm_request_irq(dev, state->irq, mipi_csis_irq_handler,
+ 0, dev_name(dev), state);
+ if (ret) {
+ dev_err(dev, "Interrupt request failed\n");
+ goto e_clkdis;
+ }
+
+ /* First register a v4l2 device */
+ ret = v4l2_device_register(dev, &state->v4l2_dev);
+ if (ret) {
+ v4l2_err(dev->driver,
+ "Unable to register v4l2 device.\n");
+ goto e_clkdis;
+ }
+ v4l2_info(&state->v4l2_dev, "mipi csi v4l2 device registered\n");
+
+ /* .. and a pointer to the subdev. */
+ platform_set_drvdata(pdev, state);
+
+ ret = mipi_csis_subdev_init(&state->mipi_sd, pdev, &mipi_csis_subdev_ops);
+ if (ret < 0)
+ goto e_sd_mipi;
+
+ memcpy(state->events, mipi_csis_events, sizeof(state->events));
+
+ /* subdev host register */
+ ret = mipi_csis_subdev_host(state);
+ if (ret < 0)
+ goto e_sd_host;
+
+ pm_runtime_enable(dev);
+ if (!pm_runtime_enabled(dev)) {
+ ret = mipi_csis_pm_resume(dev, true);
+ if (ret < 0)
+ goto e_sd_host;
+ }
+
+ dev_info(&pdev->dev,
+ "lanes: %d, hs_settle: %d, clk_settle: %d, wclk: %d, freq: %u\n",
+ state->num_lanes, state->hs_settle, state->clk_settle,
+ state->wclk_ext, state->clk_frequency);
+ return 0;
+
+e_sd_host:
+ v4l2_async_notifier_unregister(&state->subdev_notifier);
+ v4l2_device_unregister(&state->v4l2_dev);
+e_sd_mipi:
+ v4l2_async_unregister_subdev(&state->mipi_sd);
+e_clkdis:
+ mipi_csis_clk_disable(state);
+ return ret;
+}
+
+static int mipi_csis_pm_suspend(struct device *dev, bool runtime)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct csi_state *state = platform_get_drvdata(pdev);
+ struct v4l2_subdev *mipi_sd = &state->mipi_sd;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, mipi_sd, "%s: flags: 0x%x\n",
+ __func__, state->flags);
+
+ mutex_lock(&state->lock);
+ if (state->flags & ST_POWERED) {
+ mipi_csis_stop_stream(state);
+ ret = regulator_disable(state->mipi_phy_regulator);
+ if (ret)
+ goto unlock;
+ mipi_csis_clk_disable(state);
+ state->flags &= ~ST_POWERED;
+ if (!runtime)
+ state->flags |= ST_SUSPENDED;
+ }
+ unlock:
+ mutex_unlock(&state->lock);
+ return ret ? -EAGAIN : 0;
+}
+
+static int mipi_csis_pm_resume(struct device *dev, bool runtime)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct csi_state *state = platform_get_drvdata(pdev);
+ struct v4l2_subdev *mipi_sd = &state->mipi_sd;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, mipi_sd, "%s: flags: 0x%x\n",
+ __func__, state->flags);
+
+ mutex_lock(&state->lock);
+ if (!runtime && !(state->flags & ST_SUSPENDED))
+ goto unlock;
+
+ if (!(state->flags & ST_POWERED)) {
+ ret = regulator_enable(state->mipi_phy_regulator);
+ if (!ret) {
+ state->flags |= ST_POWERED;
+ } else {
+ goto unlock;
+ }
+ mipi_csis_clk_enable(state);
+ }
+ if (state->flags & ST_STREAMING)
+ mipi_csis_start_stream(state);
+
+ state->flags &= ~ST_SUSPENDED;
+ unlock:
+ mutex_unlock(&state->lock);
+ return ret ? -EAGAIN : 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mipi_csis_suspend(struct device *dev)
+{
+ return mipi_csis_pm_suspend(dev, false);
+}
+
+static int mipi_csis_resume(struct device *dev)
+{
+ return mipi_csis_pm_resume(dev, false);
+}
+#endif
+
+static int mipi_csis_runtime_suspend(struct device *dev)
+{
+ return mipi_csis_pm_suspend(dev, true);
+}
+
+static int mipi_csis_runtime_resume(struct device *dev)
+{
+ return mipi_csis_pm_resume(dev, true);
+}
+
+static int mipi_csis_remove(struct platform_device *pdev)
+{
+ struct csi_state *state = platform_get_drvdata(pdev);
+
+ v4l2_async_unregister_subdev(&state->mipi_sd);
+ v4l2_async_notifier_unregister(&state->subdev_notifier);
+ v4l2_device_unregister(&state->v4l2_dev);
+
+ pm_runtime_disable(&pdev->dev);
+ mipi_csis_pm_suspend(&pdev->dev, true);
+ mipi_csis_clk_disable(state);
+ pm_runtime_set_suspended(&pdev->dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops mipi_csis_pm_ops = {
+ SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume,
+ NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume)
+};
+
+static const struct of_device_id mipi_csis_of_match[] = {
+ { .compatible = "fsl,imx7d-mipi-csi",
+ .data = (void *)&mipi_csis_phy_reset,
+ },
+ { .compatible = "fsl,imx8mm-mipi-csi",
+ .data = (void *)&mipi_csis_phy_reset_mx8mm,
+ },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mipi_csis_of_match);
+
+static struct platform_driver mipi_csis_driver = {
+ .probe = mipi_csis_probe,
+ .remove = mipi_csis_remove,
+ .driver = {
+ .of_match_table = mipi_csis_of_match,
+ .name = CSIS_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = &mipi_csis_pm_ops,
+ },
+};
+
+module_platform_driver(mipi_csis_driver);
+
+MODULE_DESCRIPTION("Freescale MIPI-CSI2 receiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c b/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c
new file mode 100644
index 000000000000..3d7adecaa325
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c
@@ -0,0 +1,3148 @@
+/*
+ * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file drivers/media/video/mxc/capture/mxc_v4l2_capture.c
+ *
+ * @brief Mxc Video For Linux 2 driver
+ *
+ * @ingroup MXC_V4L2_CAPTURE
+ */
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/semaphore.h>
+#include <linux/pagemap.h>
+#include <linux/vmalloc.h>
+#include <linux/types.h>
+#include <linux/fb.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/mxcfb.h>
+#include <linux/of_device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include "v4l2-int-device.h"
+#include <linux/fsl_devices.h>
+#include "mxc_v4l2_capture.h"
+#include "ipu_prp_sw.h"
+
+#define init_MUTEX(sem) sema_init(sem, 1)
+
+static struct platform_device_id imx_v4l2_devtype[] = {
+ {
+ .name = "v4l2-capture-imx5",
+ .driver_data = IMX5_V4L2,
+ }, {
+ .name = "v4l2-capture-imx6",
+ .driver_data = IMX6_V4L2,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(platform, imx_v4l2_devtype);
+
+static const struct of_device_id mxc_v4l2_dt_ids[] = {
+ {
+ .compatible = "fsl,imx6q-v4l2-capture",
+ .data = &imx_v4l2_devtype[IMX6_V4L2],
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, mxc_v4l2_dt_ids);
+
+static int video_nr = -1;
+
+/*! This data is used for the output to the display. */
+#define MXC_V4L2_CAPTURE_NUM_OUTPUTS 6
+#define MXC_V4L2_CAPTURE_NUM_INPUTS 2
+static struct v4l2_output mxc_capture_outputs[MXC_V4L2_CAPTURE_NUM_OUTPUTS] = {
+ {
+ .index = 0,
+ .name = "DISP3 BG",
+ .type = V4L2_OUTPUT_TYPE_ANALOG,
+ .audioset = 0,
+ .modulator = 0,
+ .std = V4L2_STD_UNKNOWN,
+ },
+ {
+ .index = 1,
+ .name = "DISP3 BG - DI1",
+ .type = V4L2_OUTPUT_TYPE_ANALOG,
+ .audioset = 0,
+ .modulator = 0,
+ .std = V4L2_STD_UNKNOWN,
+ },
+ {
+ .index = 2,
+ .name = "DISP3 FG",
+ .type = V4L2_OUTPUT_TYPE_ANALOG,
+ .audioset = 0,
+ .modulator = 0,
+ .std = V4L2_STD_UNKNOWN,
+ },
+ {
+ .index = 3,
+ .name = "DISP4 BG",
+ .type = V4L2_OUTPUT_TYPE_ANALOG,
+ .audioset = 0,
+ .modulator = 0,
+ .std = V4L2_STD_UNKNOWN,
+ },
+ {
+ .index = 4,
+ .name = "DISP4 BG - DI1",
+ .type = V4L2_OUTPUT_TYPE_ANALOG,
+ .audioset = 0,
+ .modulator = 0,
+ .std = V4L2_STD_UNKNOWN,
+ },
+ {
+ .index = 5,
+ .name = "DISP4 FG",
+ .type = V4L2_OUTPUT_TYPE_ANALOG,
+ .audioset = 0,
+ .modulator = 0,
+ .std = V4L2_STD_UNKNOWN,
+ },
+};
+
+static struct v4l2_input mxc_capture_inputs[MXC_V4L2_CAPTURE_NUM_INPUTS] = {
+ {
+ .index = 0,
+ .name = "CSI IC MEM",
+ .type = V4L2_INPUT_TYPE_CAMERA,
+ .audioset = 0,
+ .tuner = 0,
+ .std = V4L2_STD_UNKNOWN,
+ .status = 0,
+ },
+ {
+ .index = 1,
+ .name = "CSI MEM",
+ .type = V4L2_INPUT_TYPE_CAMERA,
+ .audioset = 0,
+ .tuner = 0,
+ .std = V4L2_STD_UNKNOWN,
+ .status = V4L2_IN_ST_NO_POWER,
+ },
+};
+
+/*! List of TV input video formats supported. The video formats is corresponding
+ * to the v4l2_id in video_fmt_t.
+ * Currently, only PAL and NTSC is supported. Needs to be expanded in the
+ * future.
+ */
+typedef enum {
+ TV_NTSC = 0, /*!< Locked on (M) NTSC video signal. */
+ TV_PAL, /*!< (B, G, H, I, N)PAL video signal. */
+ TV_NOT_LOCKED, /*!< Not locked on a signal. */
+} video_fmt_idx;
+
+/*! Number of video standards supported (including 'not locked' signal). */
+#define TV_STD_MAX (TV_NOT_LOCKED + 1)
+
+/*! Video format structure. */
+typedef struct {
+ int v4l2_id; /*!< Video for linux ID. */
+ char name[16]; /*!< Name (e.g., "NTSC", "PAL", etc.) */
+ u16 raw_width; /*!< Raw width. */
+ u16 raw_height; /*!< Raw height. */
+ u16 active_width; /*!< Active width. */
+ u16 active_height; /*!< Active height. */
+ u16 active_top; /*!< Active top. */
+ u16 active_left; /*!< Active left. */
+} video_fmt_t;
+
+/*!
+ * Description of video formats supported.
+ *
+ * PAL: raw=720x625, active=720x576.
+ * NTSC: raw=720x525, active=720x480.
+ */
+static video_fmt_t video_fmts[] = {
+ { /*! NTSC */
+ .v4l2_id = V4L2_STD_NTSC,
+ .name = "NTSC",
+ .raw_width = 720, /* SENS_FRM_WIDTH */
+ .raw_height = 525, /* SENS_FRM_HEIGHT */
+ .active_width = 720, /* ACT_FRM_WIDTH */
+ .active_height = 480, /* ACT_FRM_HEIGHT */
+ .active_top = 13,
+ .active_left = 0,
+ },
+ { /*! (B, G, H, I, N) PAL */
+ .v4l2_id = V4L2_STD_PAL,
+ .name = "PAL",
+ .raw_width = 720,
+ .raw_height = 625,
+ .active_width = 720,
+ .active_height = 576,
+ .active_top = 0,
+ .active_left = 0,
+ },
+ { /*! Unlocked standard */
+ .v4l2_id = V4L2_STD_ALL,
+ .name = "Autodetect",
+ .raw_width = 720,
+ .raw_height = 625,
+ .active_width = 720,
+ .active_height = 576,
+ .active_top = 0,
+ .active_left = 0,
+ },
+};
+
+/*!* Standard index of TV. */
+static video_fmt_idx video_index = TV_NOT_LOCKED;
+
+static int mxc_v4l2_master_attach(struct v4l2_int_device *slave);
+static void mxc_v4l2_master_detach(struct v4l2_int_device *slave);
+static int start_preview(cam_data *cam);
+static int stop_preview(cam_data *cam);
+
+/*! Information about this driver. */
+static struct v4l2_int_master mxc_v4l2_master = {
+ .attach = mxc_v4l2_master_attach,
+ .detach = mxc_v4l2_master_detach,
+};
+
+/***************************************************************************
+ * Functions for handling Frame buffers.
+ **************************************************************************/
+
+/*!
+ * Free frame buffers
+ *
+ * @param cam Structure cam_data *
+ *
+ * @return status 0 success.
+ */
+static int mxc_free_frame_buf(cam_data *cam)
+{
+ int i;
+
+ pr_debug("MVC: In mxc_free_frame_buf\n");
+
+ for (i = 0; i < FRAME_NUM; i++) {
+ if (cam->frame[i].vaddress != 0) {
+ dma_free_coherent(0, cam->frame[i].buffer.length,
+ cam->frame[i].vaddress,
+ cam->frame[i].paddress);
+ cam->frame[i].vaddress = 0;
+ }
+ }
+
+ return 0;
+}
+
+/*!
+ * Allocate frame buffers
+ *
+ * @param cam Structure cam_data*
+ * @param count int number of buffer need to allocated
+ *
+ * @return status -0 Successfully allocated a buffer, -ENOBUFS failed.
+ */
+static int mxc_allocate_frame_buf(cam_data *cam, int count)
+{
+ int i;
+
+ pr_debug("In MVC:mxc_allocate_frame_buf - size=%d\n",
+ cam->v2f.fmt.pix.sizeimage);
+
+ for (i = 0; i < count; i++) {
+ cam->frame[i].vaddress =
+ dma_alloc_coherent(0,
+ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
+ &cam->frame[i].paddress,
+ GFP_DMA | GFP_KERNEL);
+ if (cam->frame[i].vaddress == 0) {
+ pr_err("ERROR: v4l2 capture: "
+ "mxc_allocate_frame_buf failed.\n");
+ mxc_free_frame_buf(cam);
+ return -ENOBUFS;
+ }
+ cam->frame[i].buffer.index = i;
+ cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED;
+ cam->frame[i].buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cam->frame[i].buffer.length =
+ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
+ cam->frame[i].buffer.memory = V4L2_MEMORY_MMAP;
+ cam->frame[i].buffer.m.offset = cam->frame[i].paddress;
+ cam->frame[i].index = i;
+ }
+
+ return 0;
+}
+
+/*!
+ * Free frame buffers status
+ *
+ * @param cam Structure cam_data *
+ *
+ * @return none
+ */
+static void mxc_free_frames(cam_data *cam)
+{
+ int i;
+
+ pr_debug("In MVC:mxc_free_frames\n");
+
+ for (i = 0; i < FRAME_NUM; i++)
+ cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED;
+
+ cam->enc_counter = 0;
+ INIT_LIST_HEAD(&cam->ready_q);
+ INIT_LIST_HEAD(&cam->working_q);
+ INIT_LIST_HEAD(&cam->done_q);
+}
+
+/*!
+ * Return the buffer status
+ *
+ * @param cam Structure cam_data *
+ * @param buf Structure v4l2_buffer *
+ *
+ * @return status 0 success, EINVAL failed.
+ */
+static int mxc_v4l2_buffer_status(cam_data *cam, struct v4l2_buffer *buf)
+{
+ pr_debug("In MVC:mxc_v4l2_buffer_status\n");
+
+ if (buf->index < 0 || buf->index >= FRAME_NUM) {
+ pr_err("ERROR: v4l2 capture: mxc_v4l2_buffer_status buffers "
+ "not allocated\n");
+ return -EINVAL;
+ }
+
+ memcpy(buf, &(cam->frame[buf->index].buffer), sizeof(*buf));
+ return 0;
+}
+
+static int mxc_v4l2_release_bufs(cam_data *cam)
+{
+ pr_debug("In MVC:mxc_v4l2_release_bufs\n");
+ return 0;
+}
+
+static int mxc_v4l2_prepare_bufs(cam_data *cam, struct v4l2_buffer *buf)
+{
+ pr_debug("In MVC:mxc_v4l2_prepare_bufs\n");
+
+ if (buf->index < 0 || buf->index >= FRAME_NUM || buf->length <
+ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage)) {
+ pr_err("ERROR: v4l2 capture: mxc_v4l2_prepare_bufs buffers "
+ "not allocated,index=%d, length=%d\n", buf->index,
+ buf->length);
+ return -EINVAL;
+ }
+
+ cam->frame[buf->index].buffer.index = buf->index;
+ cam->frame[buf->index].buffer.flags = V4L2_BUF_FLAG_MAPPED;
+ cam->frame[buf->index].buffer.length = buf->length;
+ cam->frame[buf->index].buffer.m.offset = cam->frame[buf->index].paddress
+ = buf->m.offset;
+ cam->frame[buf->index].buffer.type = buf->type;
+ cam->frame[buf->index].buffer.memory = V4L2_MEMORY_USERPTR;
+ cam->frame[buf->index].index = buf->index;
+
+ return 0;
+}
+
+/***************************************************************************
+ * Functions for handling the video stream.
+ **************************************************************************/
+
+/*!
+ * Indicates whether the palette is supported.
+ *
+ * @param palette V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_BGR24 or V4L2_PIX_FMT_BGR32
+ *
+ * @return 0 if failed
+ */
+static inline int valid_mode(u32 palette)
+{
+ return ((palette == V4L2_PIX_FMT_RGB565) ||
+ (palette == V4L2_PIX_FMT_BGR24) ||
+ (palette == V4L2_PIX_FMT_RGB24) ||
+ (palette == V4L2_PIX_FMT_BGR32) ||
+ (palette == V4L2_PIX_FMT_RGB32) ||
+ (palette == V4L2_PIX_FMT_YUV422P) ||
+ (palette == V4L2_PIX_FMT_UYVY) ||
+ (palette == V4L2_PIX_FMT_YUYV) ||
+ (palette == V4L2_PIX_FMT_YUV420) ||
+ (palette == V4L2_PIX_FMT_YVU420) ||
+ (palette == V4L2_PIX_FMT_NV12));
+}
+
+/*!
+ * Start the encoder job
+ *
+ * @param cam structure cam_data *
+ *
+ * @return status 0 Success
+ */
+static int mxc_streamon(cam_data *cam)
+{
+ struct mxc_v4l_frame *frame;
+ unsigned long lock_flags;
+ int err = 0;
+
+ pr_debug("In MVC:mxc_streamon\n");
+
+ if (NULL == cam) {
+ pr_err("ERROR! cam parameter is NULL\n");
+ return -1;
+ }
+
+ if (cam->capture_on) {
+ pr_err("ERROR: v4l2 capture: Capture stream has been turned "
+ " on\n");
+ return -1;
+ }
+
+ if (list_empty(&cam->ready_q)) {
+ pr_err("ERROR: v4l2 capture: mxc_streamon buffer has not been "
+ "queued yet\n");
+ return -EINVAL;
+ }
+ if (cam->enc_update_eba &&
+ cam->ready_q.prev == cam->ready_q.next) {
+ pr_err("ERROR: v4l2 capture: mxc_streamon buffer need "
+ "ping pong at least two buffers\n");
+ return -EINVAL;
+ }
+
+ cam->capture_pid = current->pid;
+
+ if (cam->overlay_on == true)
+ stop_preview(cam);
+
+ if (cam->enc_enable) {
+ err = cam->enc_enable(cam);
+ if (err != 0)
+ return err;
+ }
+
+ spin_lock_irqsave(&cam->queue_int_lock, lock_flags);
+ cam->ping_pong_csi = 0;
+ cam->local_buf_num = 0;
+ if (cam->enc_update_eba) {
+ frame =
+ list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue);
+ list_del(cam->ready_q.next);
+ list_add_tail(&frame->queue, &cam->working_q);
+ frame->ipu_buf_num = cam->ping_pong_csi;
+ err = cam->enc_update_eba(cam, frame->buffer.m.offset);
+
+ frame =
+ list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue);
+ list_del(cam->ready_q.next);
+ list_add_tail(&frame->queue, &cam->working_q);
+ frame->ipu_buf_num = cam->ping_pong_csi;
+ err |= cam->enc_update_eba(cam, frame->buffer.m.offset);
+ spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags);
+ } else {
+ spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags);
+ return -EINVAL;
+ }
+
+ if (cam->overlay_on == true)
+ start_preview(cam);
+
+ if (cam->enc_enable_csi) {
+ err = cam->enc_enable_csi(cam);
+ if (err != 0)
+ return err;
+ }
+
+ cam->capture_on = true;
+
+ return err;
+}
+
+/*!
+ * Shut down the encoder job
+ *
+ * @param cam structure cam_data *
+ *
+ * @return status 0 Success
+ */
+static int mxc_streamoff(cam_data *cam)
+{
+ int err = 0;
+
+ pr_debug("In MVC:mxc_streamoff\n");
+
+ if (cam->capture_on == false)
+ return 0;
+
+ /* For both CSI--MEM and CSI--IC--MEM
+ * 1. wait for idmac eof
+ * 2. disable csi first
+ * 3. disable idmac
+ * 4. disable smfc (CSI--MEM channel)
+ */
+ if (mxc_capture_inputs[cam->current_input].name != NULL) {
+ if (cam->enc_disable_csi) {
+ err = cam->enc_disable_csi(cam);
+ if (err != 0)
+ return err;
+ }
+ if (cam->enc_disable) {
+ err = cam->enc_disable(cam);
+ if (err != 0)
+ return err;
+ }
+ }
+
+ mxc_free_frames(cam);
+ mxc_capture_inputs[cam->current_input].status |= V4L2_IN_ST_NO_POWER;
+ cam->capture_on = false;
+ return err;
+}
+
+/*!
+ * Valid and adjust the overlay window size, position
+ *
+ * @param cam structure cam_data *
+ * @param win struct v4l2_window *
+ *
+ * @return 0
+ */
+static int verify_preview(cam_data *cam, struct v4l2_window *win)
+{
+ int i = 0, width_bound = 0, height_bound = 0;
+ int *width, *height;
+ unsigned int ipu_ch = CHAN_NONE;
+ struct fb_info *bg_fbi = NULL, *fbi = NULL;
+ bool foregound_fb = false;
+ mm_segment_t old_fs;
+
+ pr_debug("In MVC: verify_preview\n");
+
+ do {
+ fbi = (struct fb_info *)registered_fb[i];
+ if (fbi == NULL) {
+ pr_err("ERROR: verify_preview frame buffer NULL.\n");
+ return -1;
+ }
+
+ /* Which DI supports 2 layers? */
+ if (((strncmp(fbi->fix.id, "DISP3 BG", 8) == 0) &&
+ (cam->output < 3)) ||
+ ((strncmp(fbi->fix.id, "DISP4 BG", 8) == 0) &&
+ (cam->output >= 3))) {
+ if (fbi->fbops->fb_ioctl) {
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_IPU_CHAN,
+ (unsigned long)&ipu_ch);
+ set_fs(old_fs);
+ }
+ if (ipu_ch == MEM_BG_SYNC) {
+ bg_fbi = fbi;
+ pr_debug("Found background frame buffer.\n");
+ }
+ }
+
+ /* Found the frame buffer to preview on. */
+ if (strcmp(fbi->fix.id,
+ mxc_capture_outputs[cam->output].name) == 0) {
+ if (((strcmp(fbi->fix.id, "DISP3 FG") == 0) &&
+ (cam->output < 3)) ||
+ ((strcmp(fbi->fix.id, "DISP4 FG") == 0) &&
+ (cam->output >= 3)))
+ foregound_fb = true;
+
+ cam->overlay_fb = fbi;
+ break;
+ }
+ } while (++i < FB_MAX);
+
+ if (foregound_fb) {
+ width_bound = bg_fbi->var.xres;
+ height_bound = bg_fbi->var.yres;
+
+ if (win->w.width + win->w.left > bg_fbi->var.xres ||
+ win->w.height + win->w.top > bg_fbi->var.yres) {
+ pr_err("ERROR: FG window position exceeds.\n");
+ return -1;
+ }
+ } else {
+ /* 4 bytes alignment for BG */
+ width_bound = cam->overlay_fb->var.xres;
+ height_bound = cam->overlay_fb->var.yres;
+
+ if (cam->overlay_fb->var.bits_per_pixel == 24)
+ win->w.left -= win->w.left % 4;
+ else if (cam->overlay_fb->var.bits_per_pixel == 16)
+ win->w.left -= win->w.left % 2;
+
+ if (win->w.width + win->w.left > cam->overlay_fb->var.xres)
+ win->w.width = cam->overlay_fb->var.xres - win->w.left;
+ if (win->w.height + win->w.top > cam->overlay_fb->var.yres)
+ win->w.height = cam->overlay_fb->var.yres - win->w.top;
+ }
+
+ /* stride line limitation */
+ win->w.height -= win->w.height % 8;
+ win->w.width -= win->w.width % 8;
+
+ if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+ height = &win->w.width;
+ width = &win->w.height;
+ } else {
+ width = &win->w.width;
+ height = &win->w.height;
+ }
+
+ if (*width == 0 || *height == 0) {
+ pr_err("ERROR: v4l2 capture: width or height"
+ " too small.\n");
+ return -EINVAL;
+ }
+
+ if ((cam->crop_bounds.width / *width > 8) ||
+ ((cam->crop_bounds.width / *width == 8) &&
+ (cam->crop_bounds.width % *width))) {
+ *width = cam->crop_bounds.width / 8;
+ if (*width % 8)
+ *width += 8 - *width % 8;
+ if (*width + win->w.left > width_bound) {
+ pr_err("ERROR: v4l2 capture: width exceeds "
+ "resize limit.\n");
+ return -1;
+ }
+ pr_err("ERROR: v4l2 capture: width exceeds limit. "
+ "Resize to %d.\n",
+ *width);
+ }
+
+ if ((cam->crop_bounds.height / *height > 8) ||
+ ((cam->crop_bounds.height / *height == 8) &&
+ (cam->crop_bounds.height % *height))) {
+ *height = cam->crop_bounds.height / 8;
+ if (*height % 8)
+ *height += 8 - *height % 8;
+ if (*height + win->w.top > height_bound) {
+ pr_err("ERROR: v4l2 capture: height exceeds "
+ "resize limit.\n");
+ return -1;
+ }
+ pr_err("ERROR: v4l2 capture: height exceeds limit "
+ "resize to %d.\n",
+ *height);
+ }
+
+ return 0;
+}
+
+/*!
+ * start the viewfinder job
+ *
+ * @param cam structure cam_data *
+ *
+ * @return status 0 Success
+ */
+static int start_preview(cam_data *cam)
+{
+ int err = 0;
+
+ pr_debug("MVC: start_preview\n");
+
+ if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY)
+ #ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+ err = prp_vf_sdc_select(cam);
+ #else
+ err = foreground_sdc_select(cam);
+ #endif
+ else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY)
+ #ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+ err = prp_vf_sdc_select_bg(cam);
+ #else
+ err = bg_overlay_sdc_select(cam);
+ #endif
+ if (err != 0)
+ return err;
+
+ if (cam->vf_start_sdc) {
+ err = cam->vf_start_sdc(cam);
+ if (err != 0)
+ return err;
+ }
+
+ if (cam->vf_enable_csi)
+ err = cam->vf_enable_csi(cam);
+
+ pr_debug("End of %s: v2f pix widthxheight %d x %d\n",
+ __func__,
+ cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height);
+ pr_debug("End of %s: crop_bounds widthxheight %d x %d\n",
+ __func__,
+ cam->crop_bounds.width, cam->crop_bounds.height);
+ pr_debug("End of %s: crop_defrect widthxheight %d x %d\n",
+ __func__,
+ cam->crop_defrect.width, cam->crop_defrect.height);
+ pr_debug("End of %s: crop_current widthxheight %d x %d\n",
+ __func__,
+ cam->crop_current.width, cam->crop_current.height);
+
+ return err;
+}
+
+/*!
+ * shut down the viewfinder job
+ *
+ * @param cam structure cam_data *
+ *
+ * @return status 0 Success
+ */
+static int stop_preview(cam_data *cam)
+{
+ int err = 0;
+
+ if (cam->vf_disable_csi) {
+ err = cam->vf_disable_csi(cam);
+ if (err != 0)
+ return err;
+ }
+
+ if (cam->vf_stop_sdc) {
+ err = cam->vf_stop_sdc(cam);
+ if (err != 0)
+ return err;
+ }
+
+ if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY)
+ #ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+ err = prp_vf_sdc_deselect(cam);
+ #else
+ err = foreground_sdc_deselect(cam);
+ #endif
+ else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY)
+ #ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+ err = prp_vf_sdc_deselect_bg(cam);
+ #else
+ err = bg_overlay_sdc_deselect(cam);
+ #endif
+
+ return err;
+}
+
+/***************************************************************************
+ * VIDIOC Functions.
+ **************************************************************************/
+
+/*!
+ * V4L2 - mxc_v4l2_g_fmt function
+ *
+ * @param cam structure cam_data *
+ *
+ * @param f structure v4l2_format *
+ *
+ * @return status 0 success, EINVAL failed
+ */
+static int mxc_v4l2_g_fmt(cam_data *cam, struct v4l2_format *f)
+{
+ int retval = 0;
+
+ pr_debug("In MVC: mxc_v4l2_g_fmt type=%d\n", f->type);
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ pr_debug(" type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+ f->fmt.pix = cam->v2f.fmt.pix;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ pr_debug(" type is V4L2_BUF_TYPE_VIDEO_OVERLAY\n");
+ f->fmt.win = cam->win;
+ break;
+ default:
+ pr_debug(" type is invalid\n");
+ retval = -EINVAL;
+ }
+
+ pr_debug("End of %s: v2f pix widthxheight %d x %d\n",
+ __func__,
+ cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height);
+ pr_debug("End of %s: crop_bounds widthxheight %d x %d\n",
+ __func__,
+ cam->crop_bounds.width, cam->crop_bounds.height);
+ pr_debug("End of %s: crop_defrect widthxheight %d x %d\n",
+ __func__,
+ cam->crop_defrect.width, cam->crop_defrect.height);
+ pr_debug("End of %s: crop_current widthxheight %d x %d\n",
+ __func__,
+ cam->crop_current.width, cam->crop_current.height);
+
+ return retval;
+}
+
+/*!
+ * V4L2 - mxc_v4l2_s_fmt function
+ *
+ * @param cam structure cam_data *
+ *
+ * @param f structure v4l2_format *
+ *
+ * @return status 0 success, EINVAL failed
+ */
+static int mxc_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f)
+{
+ int retval = 0;
+ int size = 0;
+ int bytesperline = 0;
+ int *width, *height;
+
+ pr_debug("In MVC: mxc_v4l2_s_fmt\n");
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ pr_debug(" type=V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+ if (!valid_mode(f->fmt.pix.pixelformat)) {
+ pr_err("ERROR: v4l2 capture: mxc_v4l2_s_fmt: format "
+ "not supported\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Force the capture window resolution to be crop bounds
+ * for CSI MEM input mode.
+ */
+ if (strcmp(mxc_capture_inputs[cam->current_input].name,
+ "CSI MEM") == 0) {
+ f->fmt.pix.width = cam->crop_current.width;
+ f->fmt.pix.height = cam->crop_current.height;
+ }
+
+ if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
+ height = &f->fmt.pix.width;
+ width = &f->fmt.pix.height;
+ } else {
+ width = &f->fmt.pix.width;
+ height = &f->fmt.pix.height;
+ }
+
+ /* stride line limitation */
+ *width -= *width % 8;
+ *height -= *height % 8;
+
+ if (*width == 0 || *height == 0) {
+ pr_err("ERROR: v4l2 capture: width or height"
+ " too small.\n");
+ return -EINVAL;
+ }
+
+ if ((cam->crop_current.width / *width > 8) ||
+ ((cam->crop_current.width / *width == 8) &&
+ (cam->crop_current.width % *width))) {
+ *width = cam->crop_current.width / 8;
+ if (*width % 8)
+ *width += 8 - *width % 8;
+ pr_err("ERROR: v4l2 capture: width exceeds limit "
+ "resize to %d.\n",
+ *width);
+ }
+
+ if ((cam->crop_current.height / *height > 8) ||
+ ((cam->crop_current.height / *height == 8) &&
+ (cam->crop_current.height % *height))) {
+ *height = cam->crop_current.height / 8;
+ if (*height % 8)
+ *height += 8 - *height % 8;
+ pr_err("ERROR: v4l2 capture: height exceeds limit "
+ "resize to %d.\n",
+ *height);
+ }
+
+ switch (f->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB565:
+ size = f->fmt.pix.width * f->fmt.pix.height * 2;
+ bytesperline = f->fmt.pix.width * 2;
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ size = f->fmt.pix.width * f->fmt.pix.height * 3;
+ bytesperline = f->fmt.pix.width * 3;
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ size = f->fmt.pix.width * f->fmt.pix.height * 3;
+ bytesperline = f->fmt.pix.width * 3;
+ break;
+ case V4L2_PIX_FMT_BGR32:
+ size = f->fmt.pix.width * f->fmt.pix.height * 4;
+ bytesperline = f->fmt.pix.width * 4;
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ size = f->fmt.pix.width * f->fmt.pix.height * 4;
+ bytesperline = f->fmt.pix.width * 4;
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ size = f->fmt.pix.width * f->fmt.pix.height * 2;
+ bytesperline = f->fmt.pix.width;
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YUYV:
+ size = f->fmt.pix.width * f->fmt.pix.height * 2;
+ bytesperline = f->fmt.pix.width * 2;
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ size = f->fmt.pix.width * f->fmt.pix.height * 3 / 2;
+ bytesperline = f->fmt.pix.width;
+ break;
+ case V4L2_PIX_FMT_NV12:
+ size = f->fmt.pix.width * f->fmt.pix.height * 3 / 2;
+ bytesperline = f->fmt.pix.width;
+ break;
+ default:
+ break;
+ }
+
+ if (f->fmt.pix.bytesperline < bytesperline)
+ f->fmt.pix.bytesperline = bytesperline;
+ else
+ bytesperline = f->fmt.pix.bytesperline;
+
+ if (f->fmt.pix.sizeimage < size)
+ f->fmt.pix.sizeimage = size;
+ else
+ size = f->fmt.pix.sizeimage;
+
+ cam->v2f.fmt.pix = f->fmt.pix;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ pr_debug(" type=V4L2_BUF_TYPE_VIDEO_OVERLAY\n");
+ retval = verify_preview(cam, &f->fmt.win);
+ cam->win = f->fmt.win;
+ break;
+ default:
+ retval = -EINVAL;
+ }
+
+ pr_debug("End of %s: v2f pix widthxheight %d x %d\n",
+ __func__,
+ cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height);
+ pr_debug("End of %s: crop_bounds widthxheight %d x %d\n",
+ __func__,
+ cam->crop_bounds.width, cam->crop_bounds.height);
+ pr_debug("End of %s: crop_defrect widthxheight %d x %d\n",
+ __func__,
+ cam->crop_defrect.width, cam->crop_defrect.height);
+ pr_debug("End of %s: crop_current widthxheight %d x %d\n",
+ __func__,
+ cam->crop_current.width, cam->crop_current.height);
+
+ return retval;
+}
+
+/*!
+ * get control param
+ *
+ * @param cam structure cam_data *
+ *
+ * @param c structure v4l2_control *
+ *
+ * @return status 0 success, EINVAL failed
+ */
+static int mxc_v4l2_g_ctrl(cam_data *cam, struct v4l2_control *c)
+{
+ int status = 0;
+
+ pr_debug("In MVC:mxc_v4l2_g_ctrl\n");
+
+ /* probably don't need to store the values that can be retrieved,
+ * locally, but they are for now. */
+ switch (c->id) {
+ case V4L2_CID_HFLIP:
+ /* This is handled in the ipu. */
+ if (cam->rotation == IPU_ROTATE_HORIZ_FLIP)
+ c->value = 1;
+ break;
+ case V4L2_CID_VFLIP:
+ /* This is handled in the ipu. */
+ if (cam->rotation == IPU_ROTATE_VERT_FLIP)
+ c->value = 1;
+ break;
+ case V4L2_CID_MXC_ROT:
+ /* This is handled in the ipu. */
+ c->value = cam->rotation;
+ break;
+ case V4L2_CID_BRIGHTNESS:
+ if (cam->sensor) {
+ c->value = cam->bright;
+ status = vidioc_int_g_ctrl(cam->sensor, c);
+ cam->bright = c->value;
+ } else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ status = -ENODEV;
+ }
+ break;
+ case V4L2_CID_HUE:
+ if (cam->sensor) {
+ c->value = cam->hue;
+ status = vidioc_int_g_ctrl(cam->sensor, c);
+ cam->hue = c->value;
+ } else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ status = -ENODEV;
+ }
+ break;
+ case V4L2_CID_CONTRAST:
+ if (cam->sensor) {
+ c->value = cam->contrast;
+ status = vidioc_int_g_ctrl(cam->sensor, c);
+ cam->contrast = c->value;
+ } else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ status = -ENODEV;
+ }
+ break;
+ case V4L2_CID_SATURATION:
+ if (cam->sensor) {
+ c->value = cam->saturation;
+ status = vidioc_int_g_ctrl(cam->sensor, c);
+ cam->saturation = c->value;
+ } else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ status = -ENODEV;
+ }
+ break;
+ case V4L2_CID_RED_BALANCE:
+ if (cam->sensor) {
+ c->value = cam->red;
+ status = vidioc_int_g_ctrl(cam->sensor, c);
+ cam->red = c->value;
+ } else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ status = -ENODEV;
+ }
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ if (cam->sensor) {
+ c->value = cam->blue;
+ status = vidioc_int_g_ctrl(cam->sensor, c);
+ cam->blue = c->value;
+ } else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ status = -ENODEV;
+ }
+ break;
+ case V4L2_CID_BLACK_LEVEL:
+ if (cam->sensor) {
+ c->value = cam->ae_mode;
+ status = vidioc_int_g_ctrl(cam->sensor, c);
+ cam->ae_mode = c->value;
+ } else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ status = -ENODEV;
+ }
+ break;
+ default:
+ pr_err("ERROR: v4l2 capture: unsupported ioctrl!\n");
+ }
+
+ return status;
+}
+
+/*!
+ * V4L2 - set_control function
+ * V4L2_CID_PRIVATE_BASE is the extention for IPU preprocessing.
+ * 0 for normal operation
+ * 1 for vertical flip
+ * 2 for horizontal flip
+ * 3 for horizontal and vertical flip
+ * 4 for 90 degree rotation
+ * @param cam structure cam_data *
+ *
+ * @param c structure v4l2_control *
+ *
+ * @return status 0 success, EINVAL failed
+ */
+static int mxc_v4l2_s_ctrl(cam_data *cam, struct v4l2_control *c)
+{
+ int i, ret = 0;
+ int tmp_rotation = IPU_ROTATE_NONE;
+ struct sensor_data *sensor_data;
+
+ pr_debug("In MVC:mxc_v4l2_s_ctrl\n");
+
+ switch (c->id) {
+ case V4L2_CID_HFLIP:
+ /* This is done by the IPU */
+ if (c->value == 1) {
+ if ((cam->rotation != IPU_ROTATE_VERT_FLIP) &&
+ (cam->rotation != IPU_ROTATE_180))
+ cam->rotation = IPU_ROTATE_HORIZ_FLIP;
+ else
+ cam->rotation = IPU_ROTATE_180;
+ } else {
+ if (cam->rotation == IPU_ROTATE_HORIZ_FLIP)
+ cam->rotation = IPU_ROTATE_NONE;
+ if (cam->rotation == IPU_ROTATE_180)
+ cam->rotation = IPU_ROTATE_VERT_FLIP;
+ }
+ break;
+ case V4L2_CID_VFLIP:
+ /* This is done by the IPU */
+ if (c->value == 1) {
+ if ((cam->rotation != IPU_ROTATE_HORIZ_FLIP) &&
+ (cam->rotation != IPU_ROTATE_180))
+ cam->rotation = IPU_ROTATE_VERT_FLIP;
+ else
+ cam->rotation = IPU_ROTATE_180;
+ } else {
+ if (cam->rotation == IPU_ROTATE_VERT_FLIP)
+ cam->rotation = IPU_ROTATE_NONE;
+ if (cam->rotation == IPU_ROTATE_180)
+ cam->rotation = IPU_ROTATE_HORIZ_FLIP;
+ }
+ break;
+ case V4L2_CID_MXC_ROT:
+ case V4L2_CID_MXC_VF_ROT:
+ /* This is done by the IPU */
+ switch (c->value) {
+ case V4L2_MXC_ROTATE_NONE:
+ tmp_rotation = IPU_ROTATE_NONE;
+ break;
+ case V4L2_MXC_ROTATE_VERT_FLIP:
+ tmp_rotation = IPU_ROTATE_VERT_FLIP;
+ break;
+ case V4L2_MXC_ROTATE_HORIZ_FLIP:
+ tmp_rotation = IPU_ROTATE_HORIZ_FLIP;
+ break;
+ case V4L2_MXC_ROTATE_180:
+ tmp_rotation = IPU_ROTATE_180;
+ break;
+ case V4L2_MXC_ROTATE_90_RIGHT:
+ tmp_rotation = IPU_ROTATE_90_RIGHT;
+ break;
+ case V4L2_MXC_ROTATE_90_RIGHT_VFLIP:
+ tmp_rotation = IPU_ROTATE_90_RIGHT_VFLIP;
+ break;
+ case V4L2_MXC_ROTATE_90_RIGHT_HFLIP:
+ tmp_rotation = IPU_ROTATE_90_RIGHT_HFLIP;
+ break;
+ case V4L2_MXC_ROTATE_90_LEFT:
+ tmp_rotation = IPU_ROTATE_90_LEFT;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ #ifdef CONFIG_MXC_IPU_PRP_VF_SDC
+ if (c->id == V4L2_CID_MXC_VF_ROT)
+ cam->vf_rotation = tmp_rotation;
+ else
+ cam->rotation = tmp_rotation;
+ #else
+ cam->rotation = tmp_rotation;
+ #endif
+
+ break;
+ case V4L2_CID_HUE:
+ if (cam->sensor) {
+ cam->hue = c->value;
+ ret = vidioc_int_s_ctrl(cam->sensor, c);
+ } else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ ret = -ENODEV;
+ }
+ break;
+ case V4L2_CID_CONTRAST:
+ if (cam->sensor) {
+ cam->contrast = c->value;
+ ret = vidioc_int_s_ctrl(cam->sensor, c);
+ } else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ ret = -ENODEV;
+ }
+ break;
+ case V4L2_CID_BRIGHTNESS:
+ if (cam->sensor) {
+ cam->bright = c->value;
+ ret = vidioc_int_s_ctrl(cam->sensor, c);
+ } else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ ret = -ENODEV;
+ }
+ break;
+ case V4L2_CID_SATURATION:
+ if (cam->sensor) {
+ cam->saturation = c->value;
+ ret = vidioc_int_s_ctrl(cam->sensor, c);
+ } else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ ret = -ENODEV;
+ }
+ break;
+ case V4L2_CID_RED_BALANCE:
+ if (cam->sensor) {
+ cam->red = c->value;
+ ret = vidioc_int_s_ctrl(cam->sensor, c);
+ } else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ ret = -ENODEV;
+ }
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ if (cam->sensor) {
+ cam->blue = c->value;
+ ret = vidioc_int_s_ctrl(cam->sensor, c);
+ } else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ ret = -ENODEV;
+ }
+ break;
+ case V4L2_CID_EXPOSURE:
+ if (cam->sensor) {
+ cam->ae_mode = c->value;
+ ret = vidioc_int_s_ctrl(cam->sensor, c);
+ } else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ ret = -ENODEV;
+ }
+ break;
+ case V4L2_CID_MXC_FLASH:
+#ifdef CONFIG_MXC_IPU_V1
+ ipu_csi_flash_strobe(true);
+#endif
+ break;
+ case V4L2_CID_MXC_SWITCH_CAM:
+ if (cam->sensor == cam->all_sensors[c->value])
+ break;
+
+ /* power down other cameraes before enable new one */
+ for (i = 0; i < cam->sensor_index; i++) {
+ if (i != c->value) {
+ vidioc_int_dev_exit(cam->all_sensors[i]);
+ vidioc_int_s_power(cam->all_sensors[i], 0);
+ if (cam->mclk_on[cam->mclk_source]) {
+ ipu_csi_enable_mclk_if(cam->ipu,
+ CSI_MCLK_I2C,
+ cam->mclk_source,
+ false, false);
+ cam->mclk_on[cam->mclk_source] =
+ false;
+ }
+ }
+ }
+ sensor_data = cam->all_sensors[c->value]->priv;
+ if (sensor_data->io_init)
+ sensor_data->io_init();
+ cam->sensor = cam->all_sensors[c->value];
+ cam->mclk_source = sensor_data->mclk_source;
+ ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_I2C,
+ cam->mclk_source, true, true);
+ cam->mclk_on[cam->mclk_source] = true;
+ vidioc_int_s_power(cam->sensor, 1);
+ vidioc_int_dev_init(cam->sensor);
+ break;
+ default:
+ pr_debug(" default case\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * V4L2 - mxc_v4l2_s_param function
+ * Allows setting of capturemode and frame rate.
+ *
+ * @param cam structure cam_data *
+ * @param parm structure v4l2_streamparm *
+ *
+ * @return status 0 success, EINVAL failed
+ */
+static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm)
+{
+ struct v4l2_ifparm ifparm;
+ struct v4l2_format cam_fmt;
+ struct v4l2_streamparm currentparm;
+ ipu_csi_signal_cfg_t csi_param;
+ u32 current_fps, parm_fps;
+ int err = 0;
+
+ pr_debug("In mxc_v4l2_s_param\n");
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ pr_err(KERN_ERR "mxc_v4l2_s_param invalid type\n");
+ return -EINVAL;
+ }
+
+ /* Stop the viewfinder */
+ if (cam->overlay_on == true)
+ stop_preview(cam);
+
+ currentparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ /* First check that this device can support the changes requested. */
+ err = vidioc_int_g_parm(cam->sensor, &currentparm);
+ if (err) {
+ pr_err("%s: vidioc_int_g_parm returned an error %d\n",
+ __func__, err);
+ goto exit;
+ }
+
+ current_fps = currentparm.parm.capture.timeperframe.denominator
+ / currentparm.parm.capture.timeperframe.numerator;
+ parm_fps = parm->parm.capture.timeperframe.denominator
+ / parm->parm.capture.timeperframe.numerator;
+
+ pr_debug(" Current capabilities are %x\n",
+ currentparm.parm.capture.capability);
+ pr_debug(" Current capturemode is %d change to %d\n",
+ currentparm.parm.capture.capturemode,
+ parm->parm.capture.capturemode);
+ pr_debug(" Current framerate is %d change to %d\n",
+ current_fps, parm_fps);
+
+ /* This will change any camera settings needed. */
+ err = vidioc_int_s_parm(cam->sensor, parm);
+ if (err) {
+ pr_err("%s: vidioc_int_s_parm returned an error %d\n",
+ __func__, err);
+ goto exit;
+ }
+
+ /* If resolution changed, need to re-program the CSI */
+ /* Get new values. */
+ vidioc_int_g_ifparm(cam->sensor, &ifparm);
+
+ csi_param.data_width = 0;
+ csi_param.clk_mode = 0;
+ csi_param.ext_vsync = 0;
+ csi_param.Vsync_pol = 0;
+ csi_param.Hsync_pol = 0;
+ csi_param.pixclk_pol = 0;
+ csi_param.data_pol = 0;
+ csi_param.sens_clksrc = 0;
+ csi_param.pack_tight = 0;
+ csi_param.force_eof = 0;
+ csi_param.data_en_pol = 0;
+ csi_param.data_fmt = 0;
+ csi_param.csi = cam->csi;
+ csi_param.mclk = 0;
+
+ pr_debug(" clock_curr=mclk=%d\n", ifparm.u.bt656.clock_curr);
+ if (ifparm.u.bt656.clock_curr == 0)
+ csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
+ else
+ csi_param.clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
+
+ csi_param.pixclk_pol = ifparm.u.bt656.latch_clk_inv;
+
+ if (ifparm.u.bt656.mode == V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT) {
+ csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
+ } else if (ifparm.u.bt656.mode
+ == V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT) {
+ csi_param.data_width = IPU_CSI_DATA_WIDTH_10;
+ } else {
+ csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
+ }
+
+ csi_param.Vsync_pol = ifparm.u.bt656.nobt_vs_inv;
+ csi_param.Hsync_pol = ifparm.u.bt656.nobt_hs_inv;
+ csi_param.ext_vsync = ifparm.u.bt656.bt_sync_correct;
+
+ /* if the capturemode changed, the size bounds will have changed. */
+ cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt);
+ pr_debug(" g_fmt_cap returns widthxheight of input as %d x %d\n",
+ cam_fmt.fmt.pix.width, cam_fmt.fmt.pix.height);
+
+ csi_param.data_fmt = cam_fmt.fmt.pix.pixelformat;
+
+ cam->crop_bounds.top = cam->crop_bounds.left = 0;
+ cam->crop_bounds.width = cam_fmt.fmt.pix.width;
+ cam->crop_bounds.height = cam_fmt.fmt.pix.height;
+
+ /*
+ * Set the default current cropped resolution to be the same with
+ * the cropping boundary(except for tvin module).
+ */
+ if (cam->device_type != 1) {
+ cam->crop_current.width = cam->crop_bounds.width;
+ cam->crop_current.height = cam->crop_bounds.height;
+ }
+
+ /* This essentially loses the data at the left and bottom of the image
+ * giving a digital zoom image, if crop_current is less than the full
+ * size of the image. */
+ ipu_csi_set_window_size(cam->ipu, cam->crop_current.width,
+ cam->crop_current.height, cam->csi);
+ ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left,
+ cam->crop_current.top,
+ cam->csi);
+ ipu_csi_init_interface(cam->ipu, cam->crop_bounds.width,
+ cam->crop_bounds.height,
+ cam_fmt.fmt.pix.pixelformat, csi_param);
+
+
+exit:
+ if (cam->overlay_on == true)
+ start_preview(cam);
+
+ return err;
+}
+
+/*!
+ * V4L2 - mxc_v4l2_s_std function
+ *
+ * Sets the TV standard to be used.
+ *
+ * @param cam structure cam_data *
+ * @param parm structure v4l2_streamparm *
+ *
+ * @return status 0 success, EINVAL failed
+ */
+static int mxc_v4l2_s_std(cam_data *cam, v4l2_std_id e)
+{
+ pr_debug("In mxc_v4l2_s_std %Lx\n", e);
+
+ if (e == V4L2_STD_PAL) {
+ pr_debug(" Setting standard to PAL %Lx\n", V4L2_STD_PAL);
+ cam->standard.id = V4L2_STD_PAL;
+ video_index = TV_PAL;
+ } else if (e == V4L2_STD_NTSC) {
+ pr_debug(" Setting standard to NTSC %Lx\n",
+ V4L2_STD_NTSC);
+ /* Get rid of the white dot line in NTSC signal input */
+ cam->standard.id = V4L2_STD_NTSC;
+ video_index = TV_NTSC;
+ } else {
+ cam->standard.id = V4L2_STD_ALL;
+ video_index = TV_NOT_LOCKED;
+ pr_err("ERROR: unrecognized std! %Lx (PAL=%Lx, NTSC=%Lx\n",
+ e, V4L2_STD_PAL, V4L2_STD_NTSC);
+ }
+
+ cam->standard.index = video_index;
+ strcpy(cam->standard.name, video_fmts[video_index].name);
+ cam->crop_bounds.width = video_fmts[video_index].raw_width;
+ cam->crop_bounds.height = video_fmts[video_index].raw_height;
+ cam->crop_current.width = video_fmts[video_index].active_width;
+ cam->crop_current.height = video_fmts[video_index].active_height;
+ cam->crop_current.top = video_fmts[video_index].active_top;
+ cam->crop_current.left = video_fmts[video_index].active_left;
+
+ return 0;
+}
+
+/*!
+ * V4L2 - mxc_v4l2_g_std function
+ *
+ * Gets the TV standard from the TV input device.
+ *
+ * @param cam structure cam_data *
+ *
+ * @param e structure v4l2_streamparm *
+ *
+ * @return status 0 success, EINVAL failed
+ */
+static int mxc_v4l2_g_std(cam_data *cam, v4l2_std_id *e)
+{
+ struct v4l2_format tv_fmt;
+
+ pr_debug("In mxc_v4l2_g_std\n");
+
+ if (cam->device_type == 1) {
+ /* Use this function to get what the TV-In device detects the
+ * format to be. pixelformat is used to return the std value
+ * since the interface has no vidioc_g_std.*/
+ tv_fmt.type = V4L2_BUF_TYPE_PRIVATE;
+ vidioc_int_g_fmt_cap(cam->sensor, &tv_fmt);
+
+ /* If the TV-in automatically detects the standard, then if it
+ * changes, the settings need to change. */
+ if (cam->standard_autodetect) {
+ if (cam->standard.id != tv_fmt.fmt.pix.pixelformat) {
+ pr_debug("MVC: mxc_v4l2_g_std: "
+ "Changing standard\n");
+ mxc_v4l2_s_std(cam, tv_fmt.fmt.pix.pixelformat);
+ }
+ }
+
+ *e = tv_fmt.fmt.pix.pixelformat;
+ }
+
+ return 0;
+}
+
+/*!
+ * Dequeue one V4L capture buffer
+ *
+ * @param cam structure cam_data *
+ * @param buf structure v4l2_buffer *
+ *
+ * @return status 0 success, EINVAL invalid frame number,
+ * ETIME timeout, ERESTARTSYS interrupted by user
+ */
+static int mxc_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf)
+{
+ int retval = 0;
+ struct mxc_v4l_frame *frame;
+ unsigned long lock_flags;
+
+ pr_debug("In MVC:mxc_v4l_dqueue\n");
+
+ if (!wait_event_interruptible_timeout(cam->enc_queue,
+ cam->enc_counter != 0,
+ 10 * HZ)) {
+ pr_err("ERROR: v4l2 capture: mxc_v4l_dqueue timeout "
+ "enc_counter %x\n",
+ cam->enc_counter);
+ return -ETIME;
+ } else if (signal_pending(current)) {
+ pr_err("ERROR: v4l2 capture: mxc_v4l_dqueue() "
+ "interrupt received\n");
+ return -ERESTARTSYS;
+ }
+
+ if (down_interruptible(&cam->busy_lock))
+ return -EBUSY;
+
+ spin_lock_irqsave(&cam->dqueue_int_lock, lock_flags);
+ cam->enc_counter--;
+
+ frame = list_entry(cam->done_q.next, struct mxc_v4l_frame, queue);
+ list_del(cam->done_q.next);
+ if (frame->buffer.flags & V4L2_BUF_FLAG_DONE) {
+ frame->buffer.flags &= ~V4L2_BUF_FLAG_DONE;
+ } else if (frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) {
+ pr_err("ERROR: v4l2 capture: VIDIOC_DQBUF: "
+ "Buffer not filled.\n");
+ frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED;
+ retval = -EINVAL;
+ } else if ((frame->buffer.flags & 0x7) == V4L2_BUF_FLAG_MAPPED) {
+ pr_err("ERROR: v4l2 capture: VIDIOC_DQBUF: "
+ "Buffer not queued.\n");
+ retval = -EINVAL;
+ }
+
+ cam->frame[frame->index].buffer.field = cam->device_type ?
+ V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE;
+
+ buf->bytesused = cam->v2f.fmt.pix.sizeimage;
+ buf->index = frame->index;
+ buf->flags = frame->buffer.flags;
+ buf->m = cam->frame[frame->index].buffer.m;
+ buf->timestamp = cam->frame[frame->index].buffer.timestamp;
+ buf->field = cam->frame[frame->index].buffer.field;
+ spin_unlock_irqrestore(&cam->dqueue_int_lock, lock_flags);
+
+ up(&cam->busy_lock);
+ return retval;
+}
+
+/*!
+ * V4L interface - open function
+ *
+ * @param file structure file *
+ *
+ * @return status 0 success, ENODEV invalid device instance,
+ * ENODEV timeout, ERESTARTSYS interrupted by user
+ */
+static int mxc_v4l_open(struct file *file)
+{
+ struct v4l2_ifparm ifparm;
+ struct v4l2_format cam_fmt;
+ ipu_csi_signal_cfg_t csi_param;
+ struct video_device *dev = video_devdata(file);
+ cam_data *cam = video_get_drvdata(dev);
+ int err = 0;
+ struct sensor_data *sensor;
+
+ pr_debug("\nIn MVC: mxc_v4l_open\n");
+ pr_debug(" device name is %s\n", dev->name);
+
+ if (!cam) {
+ pr_err("ERROR: v4l2 capture: Internal error, "
+ "cam_data not found!\n");
+ return -EBADF;
+ }
+
+ if (cam->sensor == NULL ||
+ cam->sensor->type != v4l2_int_type_slave) {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ return -EAGAIN;
+ }
+
+ sensor = cam->sensor->priv;
+ if (!sensor) {
+ pr_err("%s: Internal error, sensor_data is not found!\n",
+ __func__);
+ return -EBADF;
+ }
+
+ down(&cam->busy_lock);
+ err = 0;
+ if (signal_pending(current))
+ goto oops;
+
+ if (cam->open_count++ == 0) {
+ wait_event_interruptible(cam->power_queue,
+ cam->low_power == false);
+
+ if (strcmp(mxc_capture_inputs[cam->current_input].name,
+ "CSI MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE)
+ err = csi_enc_select(cam);
+#endif
+ } else if (strcmp(mxc_capture_inputs[cam->current_input].name,
+ "CSI IC MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE)
+ err = prp_enc_select(cam);
+#endif
+ }
+
+ cam->enc_counter = 0;
+ INIT_LIST_HEAD(&cam->ready_q);
+ INIT_LIST_HEAD(&cam->working_q);
+ INIT_LIST_HEAD(&cam->done_q);
+
+ vidioc_int_g_ifparm(cam->sensor, &ifparm);
+
+ csi_param.sens_clksrc = 0;
+
+ csi_param.clk_mode = 0;
+ csi_param.data_pol = 0;
+ csi_param.ext_vsync = 0;
+
+ csi_param.pack_tight = 0;
+ csi_param.force_eof = 0;
+ csi_param.data_en_pol = 0;
+
+ csi_param.mclk = ifparm.u.bt656.clock_curr;
+
+ csi_param.pixclk_pol = ifparm.u.bt656.latch_clk_inv;
+
+ if (ifparm.u.bt656.mode
+ == V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT)
+ csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
+ else if (ifparm.u.bt656.mode
+ == V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT)
+ csi_param.data_width = IPU_CSI_DATA_WIDTH_10;
+ else
+ csi_param.data_width = IPU_CSI_DATA_WIDTH_8;
+
+
+ csi_param.Vsync_pol = ifparm.u.bt656.nobt_vs_inv;
+ csi_param.Hsync_pol = ifparm.u.bt656.nobt_hs_inv;
+
+ csi_param.csi = cam->csi;
+
+ cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt);
+
+ /* Reset the sizes. Needed to prevent carryover of last
+ * operation.*/
+ cam->crop_bounds.top = cam->crop_bounds.left = 0;
+ cam->crop_bounds.width = cam_fmt.fmt.pix.width;
+ cam->crop_bounds.height = cam_fmt.fmt.pix.height;
+
+ /* This also is the max crop size for this device. */
+ cam->crop_defrect.top = cam->crop_defrect.left = 0;
+ cam->crop_defrect.width = cam_fmt.fmt.pix.width;
+ cam->crop_defrect.height = cam_fmt.fmt.pix.height;
+
+ /* At this point, this is also the current image size. */
+ cam->crop_current.top = cam->crop_current.left = 0;
+ cam->crop_current.width = cam_fmt.fmt.pix.width;
+ cam->crop_current.height = cam_fmt.fmt.pix.height;
+
+ pr_debug("End of %s: v2f pix widthxheight %d x %d\n",
+ __func__,
+ cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height);
+ pr_debug("End of %s: crop_bounds widthxheight %d x %d\n",
+ __func__,
+ cam->crop_bounds.width, cam->crop_bounds.height);
+ pr_debug("End of %s: crop_defrect widthxheight %d x %d\n",
+ __func__,
+ cam->crop_defrect.width, cam->crop_defrect.height);
+ pr_debug("End of %s: crop_current widthxheight %d x %d\n",
+ __func__,
+ cam->crop_current.width, cam->crop_current.height);
+
+ csi_param.data_fmt = cam_fmt.fmt.pix.pixelformat;
+ pr_debug("On Open: Input to ipu size is %d x %d\n",
+ cam_fmt.fmt.pix.width, cam_fmt.fmt.pix.height);
+ ipu_csi_set_window_size(cam->ipu, cam->crop_current.width,
+ cam->crop_current.height,
+ cam->csi);
+ ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left,
+ cam->crop_current.top,
+ cam->csi);
+ ipu_csi_init_interface(cam->ipu, cam->crop_bounds.width,
+ cam->crop_bounds.height,
+ cam_fmt.fmt.pix.pixelformat,
+ csi_param);
+ clk_prepare_enable(sensor->sensor_clk);
+ vidioc_int_s_power(cam->sensor, 1);
+ vidioc_int_init(cam->sensor);
+ vidioc_int_dev_init(cam->sensor);
+ }
+
+ file->private_data = dev;
+
+oops:
+ up(&cam->busy_lock);
+ return err;
+}
+
+/*!
+ * V4L interface - close function
+ *
+ * @param file struct file *
+ *
+ * @return 0 success
+ */
+static int mxc_v4l_close(struct file *file)
+{
+ struct video_device *dev = video_devdata(file);
+ int err = 0;
+ cam_data *cam = video_get_drvdata(dev);
+ struct sensor_data *sensor;
+ pr_debug("In MVC:mxc_v4l_close\n");
+
+ if (!cam) {
+ pr_err("ERROR: v4l2 capture: Internal error, "
+ "cam_data not found!\n");
+ return -EBADF;
+ }
+
+ if (!cam->sensor) {
+ pr_err("%s: Internal error, camera is not found!\n",
+ __func__);
+ return -EBADF;
+ }
+
+ sensor = cam->sensor->priv;
+ if (!sensor) {
+ pr_err("%s: Internal error, sensor_data is not found!\n",
+ __func__);
+ return -EBADF;
+ }
+
+ down(&cam->busy_lock);
+
+ /* for the case somebody hit the ctrl C */
+ if (cam->overlay_pid == current->pid && cam->overlay_on) {
+ err = stop_preview(cam);
+ cam->overlay_on = false;
+ }
+ if (cam->capture_pid == current->pid) {
+ err |= mxc_streamoff(cam);
+ wake_up_interruptible(&cam->enc_queue);
+ }
+
+ if (--cam->open_count == 0) {
+ vidioc_int_s_power(cam->sensor, 0);
+ clk_disable_unprepare(sensor->sensor_clk);
+ wait_event_interruptible(cam->power_queue,
+ cam->low_power == false);
+ pr_debug("mxc_v4l_close: release resource\n");
+
+ if (strcmp(mxc_capture_inputs[cam->current_input].name,
+ "CSI MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE)
+ err |= csi_enc_deselect(cam);
+#endif
+ } else if (strcmp(mxc_capture_inputs[cam->current_input].name,
+ "CSI IC MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE)
+ err |= prp_enc_deselect(cam);
+#endif
+ }
+
+ mxc_free_frame_buf(cam);
+ file->private_data = NULL;
+
+ /* capture off */
+ wake_up_interruptible(&cam->enc_queue);
+ mxc_free_frames(cam);
+ cam->enc_counter++;
+ }
+
+ up(&cam->busy_lock);
+
+ return err;
+}
+
+#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC) || \
+ defined(CONFIG_MXC_IPU_PRP_ENC_MODULE) || \
+ defined(CONFIG_MXC_IPU_CSI_ENC_MODULE)
+/*
+ * V4L interface - read function
+ *
+ * @param file struct file *
+ * @param read buf char *
+ * @param count size_t
+ * @param ppos structure loff_t *
+ *
+ * @return bytes read
+ */
+static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count,
+ loff_t *ppos)
+{
+ int err = 0;
+ u8 *v_address[2];
+ struct video_device *dev = video_devdata(file);
+ cam_data *cam = video_get_drvdata(dev);
+
+ if (down_interruptible(&cam->busy_lock))
+ return -EINTR;
+
+ /* Stop the viewfinder */
+ if (cam->overlay_on == true)
+ stop_preview(cam);
+
+ v_address[0] = dma_alloc_coherent(0,
+ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
+ &cam->still_buf[0],
+ GFP_DMA | GFP_KERNEL);
+
+ v_address[1] = dma_alloc_coherent(0,
+ PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
+ &cam->still_buf[1],
+ GFP_DMA | GFP_KERNEL);
+
+ if (!v_address[0] || !v_address[1]) {
+ err = -ENOBUFS;
+ goto exit0;
+ }
+
+ err = prp_still_select(cam);
+ if (err != 0) {
+ err = -EIO;
+ goto exit0;
+ }
+
+ cam->still_counter = 0;
+ err = cam->csi_start(cam);
+ if (err != 0) {
+ err = -EIO;
+ goto exit1;
+ }
+
+ if (!wait_event_interruptible_timeout(cam->still_queue,
+ cam->still_counter != 0,
+ 10 * HZ)) {
+ pr_err("ERROR: v4l2 capture: mxc_v4l_read timeout counter %x\n",
+ cam->still_counter);
+ err = -ETIME;
+ goto exit1;
+ }
+ err = copy_to_user(buf, v_address[1], cam->v2f.fmt.pix.sizeimage);
+
+exit1:
+ prp_still_deselect(cam);
+
+exit0:
+ if (v_address[0] != 0)
+ dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address[0],
+ cam->still_buf[0]);
+ if (v_address[1] != 0)
+ dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address[1],
+ cam->still_buf[1]);
+
+ cam->still_buf[0] = cam->still_buf[1] = 0;
+
+ if (cam->overlay_on == true)
+ start_preview(cam);
+
+ up(&cam->busy_lock);
+ if (err < 0)
+ return err;
+
+ return cam->v2f.fmt.pix.sizeimage - err;
+}
+#endif
+
+/*!
+ * V4L interface - ioctl function
+ *
+ * @param file struct file*
+ *
+ * @param ioctlnr unsigned int
+ *
+ * @param arg void*
+ *
+ * @return 0 success, ENODEV for invalid device instance,
+ * -1 for other errors.
+ */
+static long mxc_v4l_do_ioctl(struct file *file,
+ unsigned int ioctlnr, void *arg)
+{
+ struct video_device *dev = video_devdata(file);
+ cam_data *cam = video_get_drvdata(dev);
+ int retval = 0;
+ unsigned long lock_flags;
+
+ pr_debug("In MVC: mxc_v4l_do_ioctl %x\n", ioctlnr);
+ wait_event_interruptible(cam->power_queue, cam->low_power == false);
+ /* make this _really_ smp-safe */
+ if (ioctlnr != VIDIOC_DQBUF)
+ if (down_interruptible(&cam->busy_lock))
+ return -EBUSY;
+
+ switch (ioctlnr) {
+ /*!
+ * V4l2 VIDIOC_QUERYCAP ioctl
+ */
+ case VIDIOC_QUERYCAP: {
+ struct v4l2_capability *cap = arg;
+ pr_debug(" case VIDIOC_QUERYCAP\n");
+ strcpy(cap->driver, "mxc_v4l2");
+ cap->version = KERNEL_VERSION(0, 1, 11);
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_VIDEO_OVERLAY |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+ cap->card[0] = '\0';
+ cap->bus_info[0] = '\0';
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_G_FMT ioctl
+ */
+ case VIDIOC_G_FMT: {
+ struct v4l2_format *gf = arg;
+ pr_debug(" case VIDIOC_G_FMT\n");
+ retval = mxc_v4l2_g_fmt(cam, gf);
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_S_DEST_CROP ioctl
+ */
+ case VIDIOC_S_DEST_CROP: {
+ struct v4l2_mxc_dest_crop *of = arg;
+ pr_debug(" case VIDIOC_S_DEST_CROP\n");
+ cam->offset.u_offset = of->offset.u_offset;
+ cam->offset.v_offset = of->offset.v_offset;
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_S_FMT ioctl
+ */
+ case VIDIOC_S_FMT: {
+ struct v4l2_format *sf = arg;
+ pr_debug(" case VIDIOC_S_FMT\n");
+ retval = mxc_v4l2_s_fmt(cam, sf);
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_REQBUFS ioctl
+ */
+ case VIDIOC_REQBUFS: {
+ struct v4l2_requestbuffers *req = arg;
+ pr_debug(" case VIDIOC_REQBUFS\n");
+
+ if (req->count > FRAME_NUM) {
+ pr_err("ERROR: v4l2 capture: VIDIOC_REQBUFS: "
+ "not enough buffers\n");
+ req->count = FRAME_NUM;
+ }
+
+ if ((req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
+ pr_err("ERROR: v4l2 capture: VIDIOC_REQBUFS: "
+ "wrong buffer type\n");
+ retval = -EINVAL;
+ break;
+ }
+
+ mxc_streamoff(cam);
+ if (req->memory & V4L2_MEMORY_MMAP) {
+ mxc_free_frame_buf(cam);
+ retval = mxc_allocate_frame_buf(cam, req->count);
+ }
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_QUERYBUF ioctl
+ */
+ case VIDIOC_QUERYBUF: {
+ struct v4l2_buffer *buf = arg;
+ int index = buf->index;
+ pr_debug(" case VIDIOC_QUERYBUF\n");
+
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ pr_err("ERROR: v4l2 capture: "
+ "VIDIOC_QUERYBUFS: "
+ "wrong buffer type\n");
+ retval = -EINVAL;
+ break;
+ }
+
+ if (buf->memory & V4L2_MEMORY_MMAP) {
+ memset(buf, 0, sizeof(buf));
+ buf->index = index;
+ }
+
+ down(&cam->param_lock);
+ if (buf->memory & V4L2_MEMORY_USERPTR) {
+ mxc_v4l2_release_bufs(cam);
+ retval = mxc_v4l2_prepare_bufs(cam, buf);
+ }
+
+ if (buf->memory & V4L2_MEMORY_MMAP)
+ retval = mxc_v4l2_buffer_status(cam, buf);
+ up(&cam->param_lock);
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_QBUF ioctl
+ */
+ case VIDIOC_QBUF: {
+ struct v4l2_buffer *buf = arg;
+ int index = buf->index;
+ pr_debug(" case VIDIOC_QBUF\n");
+
+ spin_lock_irqsave(&cam->queue_int_lock, lock_flags);
+ if ((cam->frame[index].buffer.flags & 0x7) ==
+ V4L2_BUF_FLAG_MAPPED) {
+ cam->frame[index].buffer.flags |=
+ V4L2_BUF_FLAG_QUEUED;
+ list_add_tail(&cam->frame[index].queue,
+ &cam->ready_q);
+ } else if (cam->frame[index].buffer.
+ flags & V4L2_BUF_FLAG_QUEUED) {
+ pr_err("ERROR: v4l2 capture: VIDIOC_QBUF: "
+ "buffer already queued\n");
+ retval = -EINVAL;
+ } else if (cam->frame[index].buffer.
+ flags & V4L2_BUF_FLAG_DONE) {
+ pr_err("ERROR: v4l2 capture: VIDIOC_QBUF: "
+ "overwrite done buffer.\n");
+ cam->frame[index].buffer.flags &=
+ ~V4L2_BUF_FLAG_DONE;
+ cam->frame[index].buffer.flags |=
+ V4L2_BUF_FLAG_QUEUED;
+ retval = -EINVAL;
+ }
+
+ buf->flags = cam->frame[index].buffer.flags;
+ spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags);
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_DQBUF ioctl
+ */
+ case VIDIOC_DQBUF: {
+ struct v4l2_buffer *buf = arg;
+ pr_debug(" case VIDIOC_DQBUF\n");
+
+ if ((cam->enc_counter == 0) &&
+ (file->f_flags & O_NONBLOCK)) {
+ retval = -EAGAIN;
+ break;
+ }
+
+ retval = mxc_v4l_dqueue(cam, buf);
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_STREAMON ioctl
+ */
+ case VIDIOC_STREAMON: {
+ pr_debug(" case VIDIOC_STREAMON\n");
+ retval = mxc_streamon(cam);
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_STREAMOFF ioctl
+ */
+ case VIDIOC_STREAMOFF: {
+ pr_debug(" case VIDIOC_STREAMOFF\n");
+ retval = mxc_streamoff(cam);
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_G_CTRL ioctl
+ */
+ case VIDIOC_G_CTRL: {
+ pr_debug(" case VIDIOC_G_CTRL\n");
+ retval = mxc_v4l2_g_ctrl(cam, arg);
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_S_CTRL ioctl
+ */
+ case VIDIOC_S_CTRL: {
+ pr_debug(" case VIDIOC_S_CTRL\n");
+ retval = mxc_v4l2_s_ctrl(cam, arg);
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_CROPCAP ioctl
+ */
+ case VIDIOC_CROPCAP: {
+ struct v4l2_cropcap *cap = arg;
+ pr_debug(" case VIDIOC_CROPCAP\n");
+ if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {
+ retval = -EINVAL;
+ break;
+ }
+ cap->bounds = cam->crop_bounds;
+ cap->defrect = cam->crop_defrect;
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_G_CROP ioctl
+ */
+ case VIDIOC_G_CROP: {
+ struct v4l2_crop *crop = arg;
+ pr_debug(" case VIDIOC_G_CROP\n");
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {
+ retval = -EINVAL;
+ break;
+ }
+ crop->c = cam->crop_current;
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_S_CROP ioctl
+ */
+ case VIDIOC_S_CROP: {
+ struct v4l2_crop *crop = arg;
+ struct v4l2_rect *b = &cam->crop_bounds;
+ pr_debug(" case VIDIOC_S_CROP\n");
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {
+ retval = -EINVAL;
+ break;
+ }
+
+ crop->c.top = (crop->c.top < b->top) ? b->top
+ : crop->c.top;
+ if (crop->c.top > b->top + b->height)
+ crop->c.top = b->top + b->height - 1;
+ if (crop->c.height > b->top + b->height - crop->c.top)
+ crop->c.height =
+ b->top + b->height - crop->c.top;
+
+ crop->c.left = (crop->c.left < b->left) ? b->left
+ : crop->c.left;
+ if (crop->c.left > b->left + b->width)
+ crop->c.left = b->left + b->width - 1;
+ if (crop->c.width > b->left - crop->c.left + b->width)
+ crop->c.width =
+ b->left - crop->c.left + b->width;
+
+ crop->c.width -= crop->c.width % 8;
+ crop->c.left -= crop->c.left % 4;
+ cam->crop_current = crop->c;
+
+ pr_debug(" Cropping Input to ipu size %d x %d\n",
+ cam->crop_current.width,
+ cam->crop_current.height);
+ ipu_csi_set_window_size(cam->ipu, cam->crop_current.width,
+ cam->crop_current.height,
+ cam->csi);
+ ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left,
+ cam->crop_current.top,
+ cam->csi);
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_OVERLAY ioctl
+ */
+ case VIDIOC_OVERLAY: {
+ int *on = arg;
+ pr_debug(" VIDIOC_OVERLAY on=%d\n", *on);
+ if (*on) {
+ cam->overlay_on = true;
+ cam->overlay_pid = current->pid;
+ retval = start_preview(cam);
+ }
+ if (!*on) {
+ retval = stop_preview(cam);
+ cam->overlay_on = false;
+ }
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_G_FBUF ioctl
+ */
+ case VIDIOC_G_FBUF: {
+ struct v4l2_framebuffer *fb = arg;
+ pr_debug(" case VIDIOC_G_FBUF\n");
+ *fb = cam->v4l2_fb;
+ fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY;
+ break;
+ }
+
+ /*!
+ * V4l2 VIDIOC_S_FBUF ioctl
+ */
+ case VIDIOC_S_FBUF: {
+ struct v4l2_framebuffer *fb = arg;
+ pr_debug(" case VIDIOC_S_FBUF\n");
+ cam->v4l2_fb = *fb;
+ break;
+ }
+
+ case VIDIOC_G_PARM: {
+ struct v4l2_streamparm *parm = arg;
+ pr_debug(" case VIDIOC_G_PARM\n");
+ if (cam->sensor)
+ retval = vidioc_int_g_parm(cam->sensor, parm);
+ else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ retval = -ENODEV;
+ }
+ break;
+ }
+
+ case VIDIOC_S_PARM: {
+ struct v4l2_streamparm *parm = arg;
+ pr_debug(" case VIDIOC_S_PARM\n");
+ if (cam->sensor)
+ retval = mxc_v4l2_s_param(cam, parm);
+ else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ retval = -ENODEV;
+ }
+ break;
+ }
+
+ /* linux v4l2 bug, kernel c0485619 user c0405619 */
+ case VIDIOC_ENUMSTD: {
+ struct v4l2_standard *e = arg;
+ pr_debug(" case VIDIOC_ENUMSTD\n");
+ *e = cam->standard;
+ break;
+ }
+
+ case VIDIOC_G_STD: {
+ v4l2_std_id *e = arg;
+ pr_debug(" case VIDIOC_G_STD\n");
+ if (cam->sensor)
+ retval = mxc_v4l2_g_std(cam, e);
+ else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ retval = -ENODEV;
+ }
+ break;
+ }
+
+ case VIDIOC_S_STD: {
+ v4l2_std_id *e = arg;
+ pr_debug(" case VIDIOC_S_STD\n");
+ retval = mxc_v4l2_s_std(cam, *e);
+
+ break;
+ }
+
+ case VIDIOC_ENUMOUTPUT: {
+ struct v4l2_output *output = arg;
+ pr_debug(" case VIDIOC_ENUMOUTPUT\n");
+ if (output->index >= MXC_V4L2_CAPTURE_NUM_OUTPUTS) {
+ retval = -EINVAL;
+ break;
+ }
+ *output = mxc_capture_outputs[output->index];
+
+ break;
+ }
+ case VIDIOC_G_OUTPUT: {
+ int *p_output_num = arg;
+ pr_debug(" case VIDIOC_G_OUTPUT\n");
+ *p_output_num = cam->output;
+ break;
+ }
+
+ case VIDIOC_S_OUTPUT: {
+ int *p_output_num = arg;
+ pr_debug(" case VIDIOC_S_OUTPUT\n");
+ if (*p_output_num >= MXC_V4L2_CAPTURE_NUM_OUTPUTS) {
+ retval = -EINVAL;
+ break;
+ }
+ cam->output = *p_output_num;
+ break;
+ }
+
+ case VIDIOC_ENUMINPUT: {
+ struct v4l2_input *input = arg;
+ pr_debug(" case VIDIOC_ENUMINPUT\n");
+ if (input->index >= MXC_V4L2_CAPTURE_NUM_INPUTS) {
+ retval = -EINVAL;
+ break;
+ }
+ *input = mxc_capture_inputs[input->index];
+ break;
+ }
+
+ case VIDIOC_G_INPUT: {
+ int *index = arg;
+ pr_debug(" case VIDIOC_G_INPUT\n");
+ *index = cam->current_input;
+ break;
+ }
+
+ case VIDIOC_S_INPUT: {
+ int *index = arg;
+ pr_debug(" case VIDIOC_S_INPUT\n");
+ if (*index >= MXC_V4L2_CAPTURE_NUM_INPUTS) {
+ retval = -EINVAL;
+ break;
+ }
+
+ if (*index == cam->current_input)
+ break;
+
+ if ((mxc_capture_inputs[cam->current_input].status &
+ V4L2_IN_ST_NO_POWER) == 0) {
+ retval = mxc_streamoff(cam);
+ if (retval)
+ break;
+ mxc_capture_inputs[cam->current_input].status |=
+ V4L2_IN_ST_NO_POWER;
+ }
+
+ if (strcmp(mxc_capture_inputs[*index].name, "CSI MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE)
+ retval = csi_enc_select(cam);
+ if (retval)
+ break;
+#endif
+ } else if (strcmp(mxc_capture_inputs[*index].name,
+ "CSI IC MEM") == 0) {
+#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE)
+ retval = prp_enc_select(cam);
+ if (retval)
+ break;
+#endif
+ }
+
+ mxc_capture_inputs[*index].status &= ~V4L2_IN_ST_NO_POWER;
+ cam->current_input = *index;
+ break;
+ }
+ case VIDIOC_ENUM_FMT: {
+ struct v4l2_fmtdesc *f = arg;
+ if (cam->sensor)
+ retval = vidioc_int_enum_fmt_cap(cam->sensor, f);
+ else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ retval = -ENODEV;
+ }
+ break;
+ }
+ case VIDIOC_ENUM_FRAMESIZES: {
+ struct v4l2_frmsizeenum *fsize = arg;
+ if (cam->sensor)
+ retval = vidioc_int_enum_framesizes(cam->sensor, fsize);
+ else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ retval = -ENODEV;
+ }
+ break;
+ }
+ case VIDIOC_ENUM_FRAMEINTERVALS: {
+ struct v4l2_frmivalenum *fival = arg;
+ if (cam->sensor) {
+ retval = vidioc_int_enum_frameintervals(cam->sensor,
+ fival);
+ } else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ retval = -ENODEV;
+ }
+ break;
+ }
+ case VIDIOC_DBG_G_CHIP_IDENT: {
+ struct v4l2_dbg_chip_ident *p = arg;
+ p->ident = V4L2_IDENT_NONE;
+ p->revision = 0;
+ if (cam->sensor)
+ retval = vidioc_int_g_chip_ident(cam->sensor, (int *)p);
+ else {
+ pr_err("ERROR: v4l2 capture: slave not found!\n");
+ retval = -ENODEV;
+ }
+ break;
+ }
+ case VIDIOC_TRY_FMT:
+ case VIDIOC_QUERYCTRL:
+ case VIDIOC_G_TUNER:
+ case VIDIOC_S_TUNER:
+ case VIDIOC_G_FREQUENCY:
+ case VIDIOC_S_FREQUENCY:
+ default:
+ pr_debug(" case default or not supported\n");
+ retval = -EINVAL;
+ break;
+ }
+
+ if (ioctlnr != VIDIOC_DQBUF)
+ up(&cam->busy_lock);
+ return retval;
+}
+
+/*
+ * V4L interface - ioctl function
+ *
+ * @return None
+ */
+static long mxc_v4l_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ pr_debug("In MVC:mxc_v4l_ioctl\n");
+ return video_usercopy(file, cmd, arg, mxc_v4l_do_ioctl);
+}
+
+/*!
+ * V4L interface - mmap function
+ *
+ * @param file structure file *
+ *
+ * @param vma structure vm_area_struct *
+ *
+ * @return status 0 Success, EINTR busy lock error, ENOBUFS remap_page error
+ */
+static int mxc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct video_device *dev = video_devdata(file);
+ unsigned long size;
+ int res = 0;
+ cam_data *cam = video_get_drvdata(dev);
+
+ pr_debug("In MVC:mxc_mmap\n");
+ pr_debug(" pgoff=0x%lx, start=0x%lx, end=0x%lx\n",
+ vma->vm_pgoff, vma->vm_start, vma->vm_end);
+
+ /* make this _really_ smp-safe */
+ if (down_interruptible(&cam->busy_lock))
+ return -EINTR;
+
+ size = vma->vm_end - vma->vm_start;
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ if (remap_pfn_range(vma, vma->vm_start,
+ vma->vm_pgoff, size, vma->vm_page_prot)) {
+ pr_err("ERROR: v4l2 capture: mxc_mmap: "
+ "remap_pfn_range failed\n");
+ res = -ENOBUFS;
+ goto mxc_mmap_exit;
+ }
+
+ vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
+
+mxc_mmap_exit:
+ up(&cam->busy_lock);
+ return res;
+}
+
+/*!
+ * V4L interface - poll function
+ *
+ * @param file structure file *
+ *
+ * @param wait structure poll_table_struct *
+ *
+ * @return status POLLIN | POLLRDNORM
+ */
+static unsigned int mxc_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct video_device *dev = video_devdata(file);
+ cam_data *cam = video_get_drvdata(dev);
+ wait_queue_head_t *queue = NULL;
+ int res = POLLIN | POLLRDNORM;
+
+ pr_debug("In MVC:mxc_poll\n");
+
+ if (down_interruptible(&cam->busy_lock))
+ return -EINTR;
+
+ queue = &cam->enc_queue;
+ poll_wait(file, queue, wait);
+
+ up(&cam->busy_lock);
+
+ return res;
+}
+
+/*!
+ * This structure defines the functions to be called in this driver.
+ */
+static struct v4l2_file_operations mxc_v4l_fops = {
+ .owner = THIS_MODULE,
+ .open = mxc_v4l_open,
+ .release = mxc_v4l_close,
+ .read = mxc_v4l_read,
+ .unlocked_ioctl = mxc_v4l_ioctl,
+ .mmap = mxc_mmap,
+ .poll = mxc_poll,
+};
+
+static struct video_device mxc_v4l_template = {
+ .name = "Mxc Camera",
+ .fops = &mxc_v4l_fops,
+ .release = video_device_release,
+};
+
+/*!
+ * This function can be used to release any platform data on closing.
+ */
+static void camera_platform_release(struct device *device)
+{
+}
+
+/*!
+ * Camera V4l2 callback function.
+ *
+ * @param mask u32
+ *
+ * @param dev void device structure
+ *
+ * @return status
+ */
+static void camera_callback(u32 mask, void *dev)
+{
+ struct mxc_v4l_frame *done_frame;
+ struct mxc_v4l_frame *ready_frame;
+ struct timeval cur_time;
+
+ cam_data *cam = (cam_data *) dev;
+ if (cam == NULL)
+ return;
+
+ pr_debug("In MVC:camera_callback\n");
+
+ spin_lock(&cam->queue_int_lock);
+ spin_lock(&cam->dqueue_int_lock);
+ if (!list_empty(&cam->working_q)) {
+ do_gettimeofday(&cur_time);
+
+ done_frame = list_entry(cam->working_q.next,
+ struct mxc_v4l_frame,
+ queue);
+
+ if (done_frame->ipu_buf_num != cam->local_buf_num)
+ goto next;
+
+ /*
+ * Set the current time to done frame buffer's
+ * timestamp. Users can use this information to judge
+ * the frame's usage.
+ */
+ done_frame->buffer.timestamp = cur_time;
+
+ if (done_frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) {
+ done_frame->buffer.flags |= V4L2_BUF_FLAG_DONE;
+ done_frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED;
+
+ /* Added to the done queue */
+ list_del(cam->working_q.next);
+ list_add_tail(&done_frame->queue, &cam->done_q);
+
+ /* Wake up the queue */
+ cam->enc_counter++;
+ wake_up_interruptible(&cam->enc_queue);
+ } else
+ pr_err("ERROR: v4l2 capture: camera_callback: "
+ "buffer not queued\n");
+ }
+
+next:
+ if (!list_empty(&cam->ready_q)) {
+ ready_frame = list_entry(cam->ready_q.next,
+ struct mxc_v4l_frame,
+ queue);
+ if (cam->enc_update_eba)
+ if (cam->enc_update_eba(
+ cam,
+ ready_frame->buffer.m.offset) == 0) {
+ list_del(cam->ready_q.next);
+ list_add_tail(&ready_frame->queue,
+ &cam->working_q);
+ ready_frame->ipu_buf_num = cam->local_buf_num;
+ }
+ } else {
+ if (cam->enc_update_eba)
+ cam->enc_update_eba(
+ cam, cam->dummy_frame.buffer.m.offset);
+ }
+
+ cam->local_buf_num = (cam->local_buf_num == 0) ? 1 : 0;
+ spin_unlock(&cam->dqueue_int_lock);
+ spin_unlock(&cam->queue_int_lock);
+
+ return;
+}
+
+/*!
+ * initialize cam_data structure
+ *
+ * @param cam structure cam_data *
+ *
+ * @return status 0 Success
+ */
+static int init_camera_struct(cam_data *cam, struct platform_device *pdev)
+{
+ const struct of_device_id *of_id =
+ of_match_device(mxc_v4l2_dt_ids, &pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
+ int ipu_id, csi_id, mclk_source;
+ int ret = 0;
+ struct v4l2_device *v4l2_dev;
+
+ pr_debug("In MVC: init_camera_struct\n");
+
+ ret = of_property_read_u32(np, "ipu_id", &ipu_id);
+ if (ret) {
+ dev_err(&pdev->dev, "ipu_id missing or invalid\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "csi_id", &csi_id);
+ if (ret) {
+ dev_err(&pdev->dev, "csi_id missing or invalid\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "mclk_source", &mclk_source);
+ if (ret) {
+ dev_err(&pdev->dev, "sensor mclk missing or invalid\n");
+ return ret;
+ }
+
+ /* Default everything to 0 */
+ memset(cam, 0, sizeof(cam_data));
+
+ /* get devtype to distinguish if the cpu is imx5 or imx6
+ * IMX5_V4L2 specify the cpu is imx5
+ * IMX6_V4L2 specify the cpu is imx6q or imx6sdl
+ */
+ if (of_id)
+ pdev->id_entry = of_id->data;
+ cam->devtype = pdev->id_entry->driver_data;
+
+ cam->ipu = ipu_get_soc(ipu_id);
+ if (cam->ipu == NULL) {
+ pr_err("ERROR: v4l2 capture: failed to get ipu\n");
+ return -EINVAL;
+ } else if (cam->ipu == ERR_PTR(-ENODEV)) {
+ pr_err("ERROR: v4l2 capture: get invalid ipu\n");
+ return -ENODEV;
+ }
+
+ init_MUTEX(&cam->param_lock);
+ init_MUTEX(&cam->busy_lock);
+
+ cam->video_dev = video_device_alloc();
+ if (cam->video_dev == NULL)
+ return -ENODEV;
+
+ *(cam->video_dev) = mxc_v4l_template;
+
+ video_set_drvdata(cam->video_dev, cam);
+ dev_set_drvdata(&pdev->dev, (void *)cam);
+ cam->video_dev->minor = -1;
+
+ v4l2_dev = kzalloc(sizeof(*v4l2_dev), GFP_KERNEL);
+ if (!v4l2_dev) {
+ dev_err(&pdev->dev, "failed to allocate v4l2_dev structure\n");
+ video_device_release(cam->video_dev);
+ return -ENOMEM;
+ }
+
+ if (v4l2_device_register(&pdev->dev, v4l2_dev) < 0) {
+ dev_err(&pdev->dev, "register v4l2 device failed\n");
+ video_device_release(cam->video_dev);
+ kfree(v4l2_dev);
+ return -ENODEV;
+ }
+ cam->video_dev->v4l2_dev = v4l2_dev;
+
+ init_waitqueue_head(&cam->enc_queue);
+ init_waitqueue_head(&cam->still_queue);
+
+ /* setup cropping */
+ cam->crop_bounds.left = 0;
+ cam->crop_bounds.width = 640;
+ cam->crop_bounds.top = 0;
+ cam->crop_bounds.height = 480;
+ cam->crop_current = cam->crop_defrect = cam->crop_bounds;
+ ipu_csi_set_window_size(cam->ipu, cam->crop_current.width,
+ cam->crop_current.height, cam->csi);
+ ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left,
+ cam->crop_current.top, cam->csi);
+ cam->streamparm.parm.capture.capturemode = 0;
+
+ cam->standard.index = 0;
+ cam->standard.id = V4L2_STD_UNKNOWN;
+ cam->standard.frameperiod.denominator = 30;
+ cam->standard.frameperiod.numerator = 1;
+ cam->standard.framelines = 480;
+ cam->standard_autodetect = true;
+ cam->streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cam->streamparm.parm.capture.timeperframe = cam->standard.frameperiod;
+ cam->streamparm.parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+ cam->overlay_on = false;
+ cam->capture_on = false;
+ cam->v4l2_fb.flags = V4L2_FBUF_FLAG_OVERLAY;
+
+ cam->v2f.fmt.pix.sizeimage = 352 * 288 * 3 / 2;
+ cam->v2f.fmt.pix.bytesperline = 288 * 3 / 2;
+ cam->v2f.fmt.pix.width = 288;
+ cam->v2f.fmt.pix.height = 352;
+ cam->v2f.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+ cam->win.w.width = 160;
+ cam->win.w.height = 160;
+ cam->win.w.left = 0;
+ cam->win.w.top = 0;
+
+ cam->ipu_id = ipu_id;
+ cam->csi = csi_id;
+ cam->mclk_source = mclk_source;
+ cam->mclk_on[cam->mclk_source] = false;
+
+ cam->enc_callback = camera_callback;
+ init_waitqueue_head(&cam->power_queue);
+ spin_lock_init(&cam->queue_int_lock);
+ spin_lock_init(&cam->dqueue_int_lock);
+
+ cam->self = kmalloc(sizeof(struct v4l2_int_device), GFP_KERNEL);
+ cam->self->module = THIS_MODULE;
+ sprintf(cam->self->name, "mxc_v4l2_cap%d", cam->csi);
+ cam->self->type = v4l2_int_type_master;
+ cam->self->u.master = &mxc_v4l2_master;
+
+ return 0;
+}
+
+static ssize_t show_streaming(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct video_device *video_dev = container_of(dev,
+ struct video_device, dev);
+ cam_data *cam = video_get_drvdata(video_dev);
+
+ if (cam->capture_on)
+ return sprintf(buf, "stream on\n");
+ else
+ return sprintf(buf, "stream off\n");
+}
+static DEVICE_ATTR(fsl_v4l2_capture_property, S_IRUGO, show_streaming, NULL);
+
+static ssize_t show_overlay(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct video_device *video_dev = container_of(dev,
+ struct video_device, dev);
+ cam_data *cam = video_get_drvdata(video_dev);
+
+ if (cam->overlay_on)
+ return sprintf(buf, "overlay on\n");
+ else
+ return sprintf(buf, "overlay off\n");
+}
+static DEVICE_ATTR(fsl_v4l2_overlay_property, S_IRUGO, show_overlay, NULL);
+
+static ssize_t show_csi(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct video_device *video_dev = container_of(dev,
+ struct video_device, dev);
+ cam_data *cam = video_get_drvdata(video_dev);
+
+ return sprintf(buf, "ipu%d_csi%d\n", cam->ipu_id, cam->csi);
+}
+static DEVICE_ATTR(fsl_csi_property, S_IRUGO, show_csi, NULL);
+
+/*!
+ * This function is called to probe the devices if registered.
+ *
+ * @param pdev the device structure used to give information on which device
+ * to probe
+ *
+ * @return The function returns 0 on success and -1 on failure.
+ */
+static int mxc_v4l2_probe(struct platform_device *pdev)
+{
+ /* Create cam and initialize it. */
+ cam_data *cam = kmalloc(sizeof(cam_data), GFP_KERNEL);
+ if (cam == NULL) {
+ pr_err("ERROR: v4l2 capture: failed to register camera\n");
+ return -1;
+ }
+
+ init_camera_struct(cam, pdev);
+ pdev->dev.release = camera_platform_release;
+
+ /* Set up the v4l2 device and register it*/
+ cam->self->priv = cam;
+ v4l2_int_device_register(cam->self);
+
+ /* register v4l video device */
+ if (video_register_device(cam->video_dev, VFL_TYPE_GRABBER, video_nr)
+ < 0) {
+ kfree(cam);
+ cam = NULL;
+ pr_err("ERROR: v4l2 capture: video_register_device failed\n");
+ return -1;
+ }
+ pr_debug(" Video device registered: %s #%d\n",
+ cam->video_dev->name, cam->video_dev->minor);
+
+ if (device_create_file(&cam->video_dev->dev,
+ &dev_attr_fsl_v4l2_capture_property))
+ dev_err(&pdev->dev, "Error on creating sysfs file"
+ " for capture\n");
+
+ if (device_create_file(&cam->video_dev->dev,
+ &dev_attr_fsl_v4l2_overlay_property))
+ dev_err(&pdev->dev, "Error on creating sysfs file"
+ " for overlay\n");
+
+ if (device_create_file(&cam->video_dev->dev,
+ &dev_attr_fsl_csi_property))
+ dev_err(&pdev->dev, "Error on creating sysfs file"
+ " for csi number\n");
+
+ return 0;
+}
+
+/*!
+ * This function is called to remove the devices when device unregistered.
+ *
+ * @param pdev the device structure used to give information on which device
+ * to remove
+ *
+ * @return The function returns 0 on success and -1 on failure.
+ */
+static int mxc_v4l2_remove(struct platform_device *pdev)
+{
+ cam_data *cam = (cam_data *)platform_get_drvdata(pdev);
+ if (cam->open_count) {
+ pr_err("ERROR: v4l2 capture:camera open "
+ "-- setting ops to NULL\n");
+ return -EBUSY;
+ } else {
+ struct v4l2_device *v4l2_dev = cam->video_dev->v4l2_dev;
+ device_remove_file(&cam->video_dev->dev,
+ &dev_attr_fsl_v4l2_capture_property);
+ device_remove_file(&cam->video_dev->dev,
+ &dev_attr_fsl_v4l2_overlay_property);
+ device_remove_file(&cam->video_dev->dev,
+ &dev_attr_fsl_csi_property);
+
+ pr_info("V4L2 freeing image input device\n");
+ v4l2_int_device_unregister(cam->self);
+ video_unregister_device(cam->video_dev);
+
+ mxc_free_frame_buf(cam);
+ kfree(cam);
+
+ v4l2_device_unregister(v4l2_dev);
+ kfree(v4l2_dev);
+ }
+
+ pr_info("V4L2 unregistering video\n");
+ return 0;
+}
+
+/*!
+ * This function is called to put the sensor in a low power state.
+ * Refer to the document driver-model/driver.txt in the kernel source tree
+ * for more information.
+ *
+ * @param pdev the device structure used to give information on which I2C
+ * to suspend
+ * @param state the power state the device is entering
+ *
+ * @return The function returns 0 on success and -1 on failure.
+ */
+static int mxc_v4l2_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ cam_data *cam = platform_get_drvdata(pdev);
+
+ pr_debug("In MVC:mxc_v4l2_suspend\n");
+
+ if (cam == NULL)
+ return -1;
+
+ down(&cam->busy_lock);
+
+ cam->low_power = true;
+
+ if (cam->overlay_on == true)
+ stop_preview(cam);
+ if (cam->capture_on == true) {
+ if (cam->enc_disable_csi)
+ cam->enc_disable_csi(cam);
+
+ if (cam->enc_disable)
+ cam->enc_disable(cam);
+ }
+
+ if (cam->sensor && cam->open_count) {
+ if (cam->mclk_on[cam->mclk_source]) {
+ ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_I2C,
+ cam->mclk_source,
+ false, false);
+ cam->mclk_on[cam->mclk_source] = false;
+ }
+ vidioc_int_s_power(cam->sensor, 0);
+ }
+
+ up(&cam->busy_lock);
+
+ return 0;
+}
+
+/*!
+ * This function is called to bring the sensor back from a low power state.
+ * Refer to the document driver-model/driver.txt in the kernel source tree
+ * for more information.
+ *
+ * @param pdev the device structure
+ *
+ * @return The function returns 0 on success and -1 on failure
+ */
+static int mxc_v4l2_resume(struct platform_device *pdev)
+{
+ cam_data *cam = platform_get_drvdata(pdev);
+
+ pr_debug("In MVC:mxc_v4l2_resume\n");
+
+ if (cam == NULL)
+ return -1;
+
+ down(&cam->busy_lock);
+
+ cam->low_power = false;
+ wake_up_interruptible(&cam->power_queue);
+
+ if (cam->sensor && cam->open_count) {
+ vidioc_int_s_power(cam->sensor, 1);
+
+ if (!cam->mclk_on[cam->mclk_source]) {
+ ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_I2C,
+ cam->mclk_source,
+ true, true);
+ cam->mclk_on[cam->mclk_source] = true;
+ }
+ }
+
+ if (cam->overlay_on == true)
+ start_preview(cam);
+ if (cam->capture_on == true) {
+ if (cam->enc_enable)
+ cam->enc_enable(cam);
+
+ if (cam->enc_enable_csi)
+ cam->enc_enable_csi(cam);
+ }
+
+ up(&cam->busy_lock);
+
+ return 0;
+}
+
+/*!
+ * This structure contains pointers to the power management callback functions.
+ */
+static struct platform_driver mxc_v4l2_driver = {
+ .driver = {
+ .name = "mxc_v4l2_capture",
+ .owner = THIS_MODULE,
+ .of_match_table = mxc_v4l2_dt_ids,
+ },
+ .id_table = imx_v4l2_devtype,
+ .probe = mxc_v4l2_probe,
+ .remove = mxc_v4l2_remove,
+ .suspend = mxc_v4l2_suspend,
+ .resume = mxc_v4l2_resume,
+ .shutdown = NULL,
+};
+
+/*!
+ * Initializes the camera driver.
+ */
+static int mxc_v4l2_master_attach(struct v4l2_int_device *slave)
+{
+ cam_data *cam = slave->u.slave->master->priv;
+ struct v4l2_format cam_fmt;
+ int i;
+ struct sensor_data *sdata = slave->priv;
+
+ pr_debug("In MVC: mxc_v4l2_master_attach\n");
+ pr_debug(" slave.name = %s\n", slave->name);
+ pr_debug(" master.name = %s\n", slave->u.slave->master->name);
+
+ if (slave == NULL) {
+ pr_err("ERROR: v4l2 capture: slave parameter not valid.\n");
+ return -1;
+ }
+
+ if (sdata->csi != cam->csi) {
+ pr_debug("%s: csi doesn't match\n", __func__);
+ return -1;
+ }
+
+ cam->sensor = slave;
+
+ if (cam->sensor_index < MXC_SENSOR_NUM) {
+ cam->all_sensors[cam->sensor_index] = slave;
+ cam->sensor_index++;
+ } else {
+ pr_err("ERROR: v4l2 capture: slave number exceeds "
+ "the maximum.\n");
+ return -1;
+ }
+
+ for (i = 0; i < cam->sensor_index; i++) {
+ vidioc_int_dev_exit(cam->all_sensors[i]);
+ vidioc_int_s_power(cam->all_sensors[i], 0);
+ }
+
+ cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt);
+
+ /* Used to detect TV in (type 1) vs. camera (type 0)*/
+ cam->device_type = cam_fmt.fmt.pix.priv;
+
+ /* Set the input size to the ipu for this device */
+ cam->crop_bounds.top = cam->crop_bounds.left = 0;
+ cam->crop_bounds.width = cam_fmt.fmt.pix.width;
+ cam->crop_bounds.height = cam_fmt.fmt.pix.height;
+
+ /* This also is the max crop size for this device. */
+ cam->crop_defrect.top = cam->crop_defrect.left = 0;
+ cam->crop_defrect.width = cam_fmt.fmt.pix.width;
+ cam->crop_defrect.height = cam_fmt.fmt.pix.height;
+
+ /* At this point, this is also the current image size. */
+ cam->crop_current.top = cam->crop_current.left = 0;
+ cam->crop_current.width = cam_fmt.fmt.pix.width;
+ cam->crop_current.height = cam_fmt.fmt.pix.height;
+
+ pr_debug("End of %s: v2f pix widthxheight %d x %d\n",
+ __func__,
+ cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height);
+ pr_debug("End of %s: crop_bounds widthxheight %d x %d\n",
+ __func__,
+ cam->crop_bounds.width, cam->crop_bounds.height);
+ pr_debug("End of %s: crop_defrect widthxheight %d x %d\n",
+ __func__,
+ cam->crop_defrect.width, cam->crop_defrect.height);
+ pr_debug("End of %s: crop_current widthxheight %d x %d\n",
+ __func__,
+ cam->crop_current.width, cam->crop_current.height);
+
+ return 0;
+}
+
+/*!
+ * Disconnects the camera driver.
+ */
+static void mxc_v4l2_master_detach(struct v4l2_int_device *slave)
+{
+ unsigned int i;
+ cam_data *cam = slave->u.slave->master->priv;
+
+ pr_debug("In MVC:mxc_v4l2_master_detach\n");
+
+ if (cam->sensor_index > 1) {
+ for (i = 0; i < cam->sensor_index; i++) {
+ if (cam->all_sensors[i] != slave)
+ continue;
+ /* Move all the sensors behind this
+ * sensor one step forward
+ */
+ for (; i <= MXC_SENSOR_NUM - 2; i++)
+ cam->all_sensors[i] = cam->all_sensors[i+1];
+ break;
+ }
+ /* Point current sensor to the last one */
+ cam->sensor = cam->all_sensors[cam->sensor_index - 2];
+ } else
+ cam->sensor = NULL;
+
+ cam->sensor_index--;
+ vidioc_int_dev_exit(slave);
+}
+
+/*!
+ * Entry point for the V4L2
+ *
+ * @return Error code indicating success or failure
+ */
+static __init int camera_init(void)
+{
+ u8 err = 0;
+
+ pr_debug("In MVC:camera_init\n");
+
+ /* Register the device driver structure. */
+ err = platform_driver_register(&mxc_v4l2_driver);
+ if (err != 0) {
+ pr_err("ERROR: v4l2 capture:camera_init: "
+ "platform_driver_register failed.\n");
+ return err;
+ }
+
+ return err;
+}
+
+/*!
+ * Exit and cleanup for the V4L2
+ */
+static void __exit camera_exit(void)
+{
+ pr_debug("In MVC: camera_exit\n");
+
+ platform_driver_unregister(&mxc_v4l2_driver);
+}
+
+module_init(camera_init);
+module_exit(camera_exit);
+
+module_param(video_nr, int, 0444);
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("V4L2 capture driver for Mxc based cameras");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("video");
diff --git a/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h b/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h
new file mode 100644
index 000000000000..f6717752d4b9
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @defgroup MXC_V4L2_CAPTURE MXC V4L2 Video Capture Driver
+ */
+/*!
+ * @file mxc_v4l2_capture.h
+ *
+ * @brief mxc V4L2 capture device API Header file
+ *
+ * It include all the defines for frame operations, also three structure defines
+ * use case ops structure, common v4l2 driver structure and frame structure.
+ *
+ * @ingroup MXC_V4L2_CAPTURE
+ */
+#ifndef __MXC_V4L2_CAPTURE_H__
+#define __MXC_V4L2_CAPTURE_H__
+
+#include <linux/uaccess.h>
+#include <linux/list.h>
+#include <linux/mxc_v4l2.h>
+#include <linux/completion.h>
+#include <linux/dmaengine.h>
+#include <linux/pxp_dma.h>
+#include <linux/ipu-v3.h>
+#include <linux/platform_data/dma-imx.h>
+
+#include <media/v4l2-dev.h>
+#include "v4l2-int-device.h"
+
+
+#define FRAME_NUM 10
+#define MXC_SENSOR_NUM 2
+
+enum imx_v4l2_devtype {
+ IMX5_V4L2,
+ IMX6_V4L2,
+};
+
+/*!
+ * v4l2 frame structure.
+ */
+struct mxc_v4l_frame {
+ u32 paddress;
+ void *vaddress;
+ int count;
+ int width;
+ int height;
+
+ struct v4l2_buffer buffer;
+ struct list_head queue;
+ int index;
+ union {
+ int ipu_buf_num;
+ int csi_buf_num;
+ };
+};
+
+/* Only for old version. Will go away soon. */
+typedef struct {
+ u8 clk_mode;
+ u8 ext_vsync;
+ u8 Vsync_pol;
+ u8 Hsync_pol;
+ u8 pixclk_pol;
+ u8 data_pol;
+ u8 data_width;
+ u8 pack_tight;
+ u8 force_eof;
+ u8 data_en_pol;
+ u16 width;
+ u16 height;
+ u32 pixel_fmt;
+ u32 mclk;
+ u16 active_width;
+ u16 active_height;
+} sensor_interface;
+
+/* Sensor control function */
+/* Only for old version. Will go away soon. */
+struct camera_sensor {
+ void (*set_color) (int bright, int saturation, int red, int green,
+ int blue);
+ void (*get_color) (int *bright, int *saturation, int *red, int *green,
+ int *blue);
+ void (*set_ae_mode) (int ae_mode);
+ void (*get_ae_mode) (int *ae_mode);
+ sensor_interface *(*config) (int *frame_rate, int high_quality);
+ sensor_interface *(*reset) (void);
+ void (*get_std) (v4l2_std_id *std);
+ void (*set_std) (v4l2_std_id std);
+ unsigned int csi;
+};
+
+/*!
+ * common v4l2 driver structure.
+ */
+typedef struct _cam_data {
+ struct video_device *video_dev;
+ int device_type;
+
+ /* semaphore guard against SMP multithreading */
+ struct semaphore busy_lock;
+
+ int open_count;
+
+ /* params lock for this camera */
+ struct semaphore param_lock;
+
+ /* Encoder */
+ struct list_head ready_q;
+ struct list_head done_q;
+ struct list_head working_q;
+ int ping_pong_csi;
+ spinlock_t queue_int_lock;
+ spinlock_t dqueue_int_lock;
+ struct mxc_v4l_frame frame[FRAME_NUM];
+ struct mxc_v4l_frame dummy_frame;
+ wait_queue_head_t enc_queue;
+ int enc_counter;
+ dma_addr_t rot_enc_bufs[2];
+ void *rot_enc_bufs_vaddr[2];
+ int rot_enc_buf_size[2];
+ enum v4l2_buf_type type;
+
+ /* still image capture */
+ wait_queue_head_t still_queue;
+ int still_counter;
+ dma_addr_t still_buf[2];
+ void *still_buf_vaddr;
+
+ /* overlay */
+ struct v4l2_window win;
+ struct v4l2_framebuffer v4l2_fb;
+ dma_addr_t vf_bufs[2];
+ void *vf_bufs_vaddr[2];
+ int vf_bufs_size[2];
+ dma_addr_t rot_vf_bufs[2];
+ void *rot_vf_bufs_vaddr[2];
+ int rot_vf_buf_size[2];
+ bool overlay_active;
+ int output;
+ struct fb_info *overlay_fb;
+ int fb_origin_std;
+ struct work_struct csi_work_struct;
+
+ /* v4l2 format */
+ struct v4l2_format v2f;
+ struct v4l2_format input_fmt; /* camera in */
+ bool bswapenable;
+ int rotation; /* for IPUv1 and IPUv3, this means encoder rotation */
+ int vf_rotation; /* viewfinder rotation only for IPUv1 and IPUv3 */
+ struct v4l2_mxc_offset offset;
+
+ /* V4l2 control bit */
+ int bright;
+ int hue;
+ int contrast;
+ int saturation;
+ int red;
+ int green;
+ int blue;
+ int ae_mode;
+
+ /* standard */
+ struct v4l2_streamparm streamparm;
+ struct v4l2_standard standard;
+ bool standard_autodetect;
+
+ /* crop */
+ struct v4l2_rect crop_bounds;
+ struct v4l2_rect crop_defrect;
+ struct v4l2_rect crop_current;
+
+ int (*enc_update_eba) (void *private, dma_addr_t eba);
+ int (*enc_enable) (void *private);
+ int (*enc_disable) (void *private);
+ int (*enc_enable_csi) (void *private);
+ int (*enc_disable_csi) (void *private);
+ void (*enc_callback) (u32 mask, void *dev);
+ int (*vf_start_adc) (void *private);
+ int (*vf_stop_adc) (void *private);
+ int (*vf_start_sdc) (void *private);
+ int (*vf_stop_sdc) (void *private);
+ int (*vf_enable_csi) (void *private);
+ int (*vf_disable_csi) (void *private);
+ int (*csi_start) (void *private);
+ int (*csi_stop) (void *private);
+
+ /* misc status flag */
+ bool overlay_on;
+ bool capture_on;
+ int overlay_pid;
+ int capture_pid;
+ bool low_power;
+ wait_queue_head_t power_queue;
+ unsigned int ipu_id;
+ unsigned int csi;
+ u8 mclk_source;
+ bool mclk_on[2]; /* two mclk sources at most now */
+ int current_input;
+
+ int local_buf_num;
+
+ /* camera sensor interface */
+ struct camera_sensor *cam_sensor; /* old version */
+ struct v4l2_int_device *all_sensors[MXC_SENSOR_NUM];
+ struct v4l2_int_device *sensor;
+ struct v4l2_int_device *self;
+ int sensor_index;
+ void *ipu;
+ void *csi_soc;
+ enum imx_v4l2_devtype devtype;
+
+ /* v4l2 buf elements related to PxP DMA */
+ struct completion pxp_tx_cmpl;
+ struct pxp_channel *pxp_chan;
+ struct pxp_config_data pxp_conf;
+ struct dma_async_tx_descriptor *txd;
+ dma_cookie_t cookie;
+ struct scatterlist sg[2];
+} cam_data;
+
+struct sensor_data {
+ const struct ov5642_platform_data *platform_data;
+ struct v4l2_int_device *v4l2_int_device;
+ struct i2c_client *i2c_client;
+ struct v4l2_pix_format pix;
+ struct v4l2_captureparm streamcap;
+ bool on;
+
+ /* control settings */
+ int brightness;
+ int hue;
+ int contrast;
+ int saturation;
+ int red;
+ int green;
+ int blue;
+ int ae_mode;
+
+ u32 mclk;
+ u8 mclk_source;
+ struct clk *sensor_clk;
+ int csi;
+
+ void (*io_init)(void);
+};
+
+void set_mclk_rate(uint32_t *p_mclk_freq, uint32_t csi);
+#endif /* __MXC_V4L2_CAPTURE_H__ */
diff --git a/drivers/media/platform/mxc/capture/mxc_vadc.c b/drivers/media/platform/mxc/capture/mxc_vadc.c
new file mode 100644
index 000000000000..2a844ca8ab5d
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/mxc_vadc.c
@@ -0,0 +1,830 @@
+/*
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/media-bus-format.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include "mxc_vadc.h"
+
+/* Resource names for the VADC driver. */
+#define VAFE_REGS_ADDR_RES_NAME "vadc-vafe"
+#define VDEC_REGS_ADDR_RES_NAME "vadc-vdec"
+
+#define reg32_write(addr, val) __raw_writel(val, addr)
+#define reg32_read(addr) __raw_readl(addr)
+#define reg32setbit(addr, bitpos) \
+ reg32_write((addr), (reg32_read((addr)) | (1<<(bitpos))))
+
+#define reg32clrbit(addr, bitpos) \
+ reg32_write((addr), (reg32_read((addr)) & (0xFFFFFFFF ^ (1<<(bitpos)))))
+
+#define GPC_CNTR 0x00
+#define IMX6SX_GPC_CNTR_VADC_ANALOG_OFF_MASK BIT(17)
+#define IMX6SX_GPC_CNTR_VADC_POWER_DOWN_MASK BIT(18)
+
+void __iomem *vafe_regbase;
+void __iomem *vdec_regbase;
+
+
+/* List of input video formats supported. The video formats is corresponding
+ * with v4l2 id in video_fmt
+ */
+enum video_fmt_idx {
+ VADC_NTSC = 0, /* Locked on (M) NTSC video signal. */
+ VADC_PAL, /* (B, G, H, I, N)PAL video signal. */
+};
+
+/* Number of video standards supported (including 'not locked' signal). */
+#define VADC_STD_MAX (VADC_PAL + 1)
+
+/* Video format structure. */
+struct video_fmt{
+ v4l2_std_id v4l2_std; /* Video for linux ID. */
+ char name[16]; /* Name (e.g., "NTSC", "PAL", etc.) */
+ u16 raw_width; /* Raw width. */
+ u16 raw_height; /* Raw height. */
+ u16 active_width; /* Active width. */
+ u16 active_height; /* Active height. */
+ u16 framerates;
+};
+
+/*
+ * Maintains the information on the current state of the sensor.
+ */
+struct vadc_state {
+ struct v4l2_device v4l2_dev;
+ struct v4l2_subdev sd;
+ struct video_fmt *fmt;
+
+ struct clk *vadc_clk;
+ struct clk *csi_clk;
+ struct regmap *gpr;
+ void __iomem *gpc_reg;
+
+ u32 vadc_in;
+ u32 csi_id;
+};
+
+static int vadc_querystd(struct v4l2_subdev *sd, v4l2_std_id *std);
+
+/* Description of video formats supported.
+ *
+ * PAL: raw=720x625, active=720x576.
+ * NTSC: raw=720x525, active=720x480.
+ */
+static struct video_fmt video_fmts[] = {
+ /* NTSC */
+ {
+ .v4l2_std = V4L2_STD_NTSC,
+ .name = "NTSC",
+ .raw_width = 720,
+ .raw_height = 525,
+ .active_width = 720,
+ .active_height = 480,
+ .framerates = 30,
+ },
+ /* (B, G, H, I, N) PAL */
+ {
+ .v4l2_std = V4L2_STD_PAL,
+ .name = "PAL",
+ .raw_width = 720,
+ .raw_height = 625,
+ .active_width = 720,
+ .active_height = 576,
+ .framerates = 25,
+ },
+};
+
+static void afe_voltage_clampingmode(void)
+{
+ reg32_write(AFE_CLAMP, 0x07);
+ reg32_write(AFE_CLMPAMP, 0x60);
+ reg32_write(AFE_CLMPDAT, 0xF0);
+}
+
+static void afe_alwayson_clampingmode(void)
+{
+ reg32_write(AFE_CLAMP, 0x15);
+ reg32_write(AFE_CLMPDAT, 0x08);
+ reg32_write(AFE_CLMPAMP, 0x00);
+}
+
+static void afe_init(void)
+{
+ pr_debug("%s\n", __func__);
+
+ reg32_write(AFE_PDBUF, 0x1f);
+ reg32_write(AFE_PDADC, 0x0f);
+ reg32_write(AFE_PDSARH, 0x01);
+ reg32_write(AFE_PDSARL, 0xff);
+ reg32_write(AFE_PDADCRFH, 0x01);
+ reg32_write(AFE_PDADCRFL, 0xff);
+ reg32_write(AFE_ICTRL, 0x3a);
+ reg32_write(AFE_ICTLSTG, 0x1e);
+
+ reg32_write(AFE_RCTRLSTG, 0x1e);
+ reg32_write(AFE_INPBUF, 0x035);
+ reg32_write(AFE_INPFLT, 0x02);
+ reg32_write(AFE_ADCDGN, 0x40);
+ reg32_write(AFE_TSTSEL, 0x10);
+
+ reg32_write(AFE_ACCTST, 0x07);
+
+ reg32_write(AFE_BGREG, 0x08);
+
+ reg32_write(AFE_ADCGN, 0x09);
+
+ /* set current controlled clamping
+ * always on, low current */
+ reg32_write(AFE_CLAMP, 0x11);
+ reg32_write(AFE_CLMPAMP, 0x08);
+}
+
+static void vdec_mode_timing_init(int std)
+{
+ if (std == V4L2_STD_NTSC) {
+ /* NTSC 720x480 */
+ reg32_write(VDEC_HACTS, 0x66);
+ reg32_write(VDEC_HACTE, 0x24);
+
+ reg32_write(VDEC_VACTS, 0x29);
+ reg32_write(VDEC_VACTE, 0x04);
+
+ /* set V Position */
+ reg32_write(VDEC_VRTPOS, 0x2);
+ } else if (std == V4L2_STD_PAL) {
+ /* PAL 720x576 */
+ reg32_write(VDEC_HACTS, 0x66);
+ reg32_write(VDEC_HACTE, 0x24);
+
+ reg32_write(VDEC_VACTS, 0x29);
+ reg32_write(VDEC_VACTE, 0x04);
+
+ /* set V Position */
+ reg32_write(VDEC_VRTPOS, 0x6);
+ } else
+ pr_debug("Error not support video mode\n");
+
+ /* set H Position */
+ reg32_write(VDEC_HZPOS, 0x60);
+
+ /* set H ignore start */
+ reg32_write(VDEC_HSIGS, 0xf8);
+
+ /* set H ignore end */
+ reg32_write(VDEC_HSIGE, 0x18);
+}
+
+/*
+* vdec_init()
+* Initialises the VDEC registers
+* Returns: nothing
+*/
+static void vdec_init(struct vadc_state *vadc)
+{
+ v4l2_std_id std;
+
+ pr_debug("%s\n", __func__);
+
+ /* Get work mode PAL or NTSC */
+ vadc_querystd(&vadc->sd, &std);
+
+ vdec_mode_timing_init(std);
+
+ /* vcr detect threshold high, automatic detections */
+ reg32_write(VDEC_VSCON2, 0);
+
+ reg32_write(VDEC_BASE + 0x110, 0x01);
+
+ /* set the noramp mode on the Hloop PLL. */
+ reg32_write(VDEC_BASE+(0x14*4), 0x10);
+
+ /* set the YC relative delay.*/
+ reg32_write(VDEC_YCDEL, 0x90);
+
+ /* setup the Hpll */
+ reg32_write(VDEC_BASE+(0x13*4), 0x13);
+
+ /* setup the 2d comb */
+ /* set the gain of the Hdetail output to 3
+ * set the notch alpha gain to 1 */
+ reg32_write(VDEC_CFC2, 0x34);
+
+ /* setup various 2d comb bits.*/
+ reg32_write(VDEC_BASE+(0x02*4), 0x01);
+ reg32_write(VDEC_BASE+(0x03*4), 0x18);
+ reg32_write(VDEC_BASE+(0x04*4), 0x34);
+
+ /* set the start of the burst gate */
+ reg32_write(VDEC_BRSTGT, 0x30);
+
+ /* set 1f motion gain */
+ reg32_write(VDEC_BASE+(0x0f*4), 0x20);
+
+ /* set the 1F chroma motion detector thresh
+ * for colour reverse detection */
+ reg32_write(VDEC_THSH1, 0x02);
+ reg32_write(VDEC_BASE+(0x4a*4), 0x20);
+ reg32_write(VDEC_BASE+(0x4b*4), 0x08);
+
+ reg32_write(VDEC_BASE+(0x4c*4), 0x08);
+
+ /* set the threshold for the narrow/wide adaptive chroma BW */
+ reg32_write(VDEC_BASE+(0x20*4), 0x20);
+
+ /* turn up the colour with the new colour gain reg */
+ /* hue: */
+ reg32_write(VDEC_HUE, 0x00);
+
+ /* cbgain: 22 B4 */
+ reg32_write(VDEC_CBGN, 0xb4);
+ /* cr gain 80 */
+ reg32_write(VDEC_CRGN, 0x80);
+ /* luma gain (contrast) */
+ reg32_write(VDEC_CNTR, 0x80);
+
+ /* setup the signed black level register, brightness */
+ reg32_write(VDEC_BRT, 0x00);
+
+ /* filter the standard detection
+ * enable the comb for the ntsc443 */
+ reg32_write(VDEC_STDDBG, 0x20);
+
+ /* setup chroma kill thresh for no chroma */
+ reg32_write(VDEC_CHBTH, 0x0);
+
+ /* set chroma loop to wider BW
+ * no set it to normal BW. i fixed the bw problem.*/
+ reg32_write(VDEC_YCDEL, 0x00);
+
+ /* set the compensation in the chroma loop for the Hloop
+ * set the ratio for the nonarithmetic 3d comb modes.*/
+ reg32_write(VDEC_BASE + (0x1d*4), 0x90);
+
+ /* set the threshold for the nonarithmetic mode for the 2d comb
+ * the higher the value the more Fc Fh offset
+ * we will tolerate before turning off the comb. */
+ reg32_write(VDEC_BASE + (0x33*4), 0xa0);
+
+ /* setup the bluescreen output colour */
+ reg32_write(VDEC_BASE + (0x3d*4), 35);
+ reg32_write(VDEC_BLSCRCR, 114);
+ reg32_write(VDEC_BLSCRCB, 212);
+
+ /* disable the active blanking */
+ reg32_write(VDEC_BASE + (0x15*4), 0x02);
+
+ /* setup the luma agc for automatic gain. */
+ reg32_write(VDEC_LMAGC2, 0x5e);
+ reg32_write(VDEC_LMAGC1, 0x81);
+
+ /* setup chroma agc */
+ reg32_write(VDEC_CHAGC2, 0xa0);
+ reg32_write(VDEC_CHAGC1, 0x01);
+
+ /* setup the MV thresh lower nibble
+ * setup the sync top cap, upper nibble */
+ reg32_write(VDEC_BASE + (0x3a*4), 0x80);
+ reg32_write(VDEC_SHPIMP, 0x00);
+
+ /* setup the vsync block */
+ reg32_write(VDEC_VSCON1, 0x87);
+
+ /* set the nosignal threshold
+ * set the vsync threshold */
+ reg32_write(VDEC_VSSGTH, 0x35);
+
+ /* set length for min hphase filter
+ * (or saturate limit if saturate is chosen) */
+ reg32_write(VDEC_BASE + (0x45*4), 0x40);
+
+ /* enable the internal resampler,
+ * select min filter not saturate for
+ * hphase noise filter for vcr detect.
+ * enable vcr pause mode different field lengths */
+ reg32_write(VDEC_BASE + (0x46*4), 0x90);
+
+ /* disable VCR detection, lock to the Hsync rather than the Vsync */
+ reg32_write(VDEC_VSCON2, 0x04);
+
+ /* set tiplevel goal for dc clamp. */
+ reg32_write(VDEC_BASE + (0x3c*4), 0xB0);
+
+ /* override SECAM detection and force SECAM off */
+ reg32_write(VDEC_BASE + (0x2f*4), 0x20);
+
+ /* Set r3d_hardblend in 3D control2 reg */
+ reg32_write(VDEC_BASE + (0x0c*4), 0x04);
+}
+
+/* set Input selector & input pull-downs */
+static void vadc_s_routing(int vadc_in)
+{
+ switch (vadc_in) {
+ case 0:
+ reg32_write(AFE_INPFLT, 0x02);
+ reg32_write(AFE_OFFDRV, 0x00);
+ reg32_write(AFE_INPCONFIG, 0x1e);
+ break;
+ case 1:
+ reg32_write(AFE_INPFLT, 0x02);
+ reg32_write(AFE_OFFDRV, 0x00);
+ reg32_write(AFE_INPCONFIG, 0x2d);
+ break;
+ case 2:
+ reg32_write(AFE_INPFLT, 0x02);
+ reg32_write(AFE_OFFDRV, 0x00);
+ reg32_write(AFE_INPCONFIG, 0x4b);
+ break;
+ case 3:
+ reg32_write(AFE_INPFLT, 0x02);
+ reg32_write(AFE_OFFDRV, 0x00);
+ reg32_write(AFE_INPCONFIG, 0x87);
+ break;
+ default:
+ pr_debug("error video input %d\n", vadc_in);
+ }
+}
+
+static void vadc_power_up(struct vadc_state *state)
+{
+ /* Power on vadc analog */
+ reg32clrbit(state->gpc_reg + GPC_CNTR, 17);
+
+ /* Power down vadc ext power */
+ reg32clrbit(state->gpc_reg + GPC_CNTR, 18);
+
+ /* software reset afe */
+ regmap_update_bits(state->gpr, IOMUXC_GPR1,
+ IMX6SX_GPR1_VADC_SW_RST_MASK,
+ IMX6SX_GPR1_VADC_SW_RST_RESET);
+
+ msleep(10);
+
+ /* clock config for vadc */
+ reg32_write(VDEC_BASE + 0x320, 0xe3);
+ reg32_write(VDEC_BASE + 0x324, 0x38);
+ reg32_write(VDEC_BASE + 0x328, 0x8e);
+ reg32_write(VDEC_BASE + 0x32c, 0x23);
+
+ /* Release reset bit */
+ regmap_update_bits(state->gpr, IOMUXC_GPR1,
+ IMX6SX_GPR1_VADC_SW_RST_MASK,
+ IMX6SX_GPR1_VADC_SW_RST_RELEASE);
+
+ /* Power on vadc ext power */
+ reg32setbit(state->gpc_reg + GPC_CNTR, 18);
+}
+
+static void vadc_power_down(struct vadc_state *state)
+{
+ /* Power down vadc analog */
+ reg32setbit(state->gpc_reg + GPC_CNTR, 17);
+
+ /* Power down vadc ext power */
+ reg32clrbit(state->gpc_reg + GPC_CNTR, 18);
+
+}
+static void vadc_init(struct vadc_state *vadc)
+{
+ pr_debug("%s\n", __func__);
+
+ vadc_power_up(vadc);
+
+ afe_init();
+
+ /* select Video Input 0-3 */
+ vadc_s_routing(vadc->vadc_in);
+
+ afe_voltage_clampingmode();
+
+ vdec_init(vadc);
+
+ /*
+ * current control loop will move sinewave input off below
+ * the bottom of the signal range visible
+ * when the testbus is viewed as magnitude,
+ * so have to break before this point while capturing ENOB data:
+ */
+ afe_alwayson_clampingmode();
+}
+
+static inline struct vadc_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct vadc_state, sd);
+}
+
+static int vadc_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ struct vadc_state *state = to_state(sd);
+
+ *std = state->fmt->v4l2_std;
+ return 0;
+}
+
+/*!
+ * Return attributes of current video standard.
+ * Since this device autodetects the current standard, this function also
+ * sets the values that need to be changed if the standard changes.
+ * There is no set std equivalent function.
+ *
+ * @return None.
+ */
+static int vadc_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ struct vadc_state *state = to_state(sd);
+ int mod;
+ int idx;
+ int i;
+
+ /* Read auto mode detected result */
+ printk(KERN_INFO"wait vadc auto detect video mode....\n");
+ for (i = 0; i < 10; i++) {
+ msleep(200);
+ mod = reg32_read(VDEC_VIDMOD);
+ /* Check video signal states */
+ if ((mod & VDEC_VIDMOD_SIGNAL_MASK)
+ == VDEC_VIDMOD_SIGNAL_DETECT)
+ break;
+ }
+ if (i == 10)
+ printk(KERN_INFO"Timeout detect video signal mod=0x%x\n", mod);
+
+ if ((mod & VDEC_VIDMOD_PAL_MASK) || (mod & VDEC_VIDMOD_M625_MASK))
+ idx = VADC_PAL;
+ else
+ idx = VADC_NTSC;
+
+ *std = video_fmts[idx].v4l2_std;
+ state->fmt = &video_fmts[idx];
+
+ printk(KERN_INFO"video mode %s\n", video_fmts[idx].name);
+ return 0;
+}
+
+static int vadc_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ /* support only one format */
+ if (code->pad || code->index >= 1)
+ return -EINVAL;
+
+ code->code = MEDIA_BUS_FMT_AYUV8_1X32;
+ return 0;
+}
+
+static int vadc_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct vadc_state *state = to_state(sd);
+ struct v4l2_mbus_framefmt *fmt = &format->format;
+
+ if (format->pad)
+ return -EINVAL;
+
+ fmt->code = MEDIA_BUS_FMT_AYUV8_1X32;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt->field = V4L2_FIELD_INTERLACED;
+ fmt->width = 720;
+ fmt->height = state->fmt->v4l2_std & V4L2_STD_NTSC ? 480 : 576;
+
+ return 0;
+}
+
+static int vadc_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ return vadc_get_fmt(sd, cfg, format);
+}
+
+static int vadc_enum_framesizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct vadc_state *state = to_state(sd);
+ if (fse->index >= 1)
+ return -EINVAL;
+
+ fse->min_width = state->fmt->active_width;
+ fse->max_width = state->fmt->active_width;
+ fse->min_height = state->fmt->active_height;
+ fse->max_height = state->fmt->active_height;
+
+ return 0;
+}
+static int vadc_enum_frameintervals(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ struct vadc_state *state = to_state(sd);
+
+ if (fie->index < 0 || fie->index >= 1)
+ return -EINVAL;
+
+ fie->interval.numerator = 1;
+
+ fie->interval.denominator = state->fmt->framerates;
+
+ return 0;
+}
+
+static int vadc_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+ struct vadc_state *state = to_state(sd);
+
+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (parms->parm.capture.timeperframe.denominator
+ != state->fmt->framerates)
+ parms->parm.capture.timeperframe.denominator
+ = state->fmt->framerates;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops vadc_video_ops = {
+ .querystd = vadc_querystd,
+ .s_parm = vadc_s_parm,
+ .g_std = vadc_g_std,
+};
+
+
+static const struct v4l2_subdev_pad_ops vadc_pad_ops = {
+ .get_fmt = vadc_get_fmt,
+ .set_fmt = vadc_set_fmt,
+ .enum_mbus_code = vadc_enum_mbus_code,
+ .enum_frame_size = vadc_enum_framesizes,
+ .enum_frame_interval = vadc_enum_frameintervals,
+};
+
+static const struct v4l2_subdev_ops vadc_ops = {
+ .video = &vadc_video_ops,
+ .pad = &vadc_pad_ops,
+};
+
+static const struct of_device_id fsl_vadc_dt_ids[] = {
+ { .compatible = "fsl,imx6sx-vadc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_vadc_dt_ids);
+
+static int vadc_of_init(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *gpc_np;
+ struct vadc_state *state = platform_get_drvdata(pdev);
+ int csi_id;
+ int ret;
+
+ /* Get csi_id to setting vadc to csi mux in gpr */
+ ret = of_property_read_u32(np, "csi_id", &csi_id);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read of property csi_id\n");
+ return ret;
+ }
+
+ state->csi_id = csi_id;
+
+ /* remap GPR register */
+ state->gpr = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "gpr");
+ if (IS_ERR(state->gpr)) {
+ dev_dbg(&pdev->dev, "can not get gpr\n");
+ return -ENOMEM;
+ }
+
+ /* Configuration vadc-to-csi 0 or 1 */
+ if (csi_id) {
+ regmap_update_bits(state->gpr, IOMUXC_GPR5,
+ IMX6SX_GPR5_CSI2_MUX_CTRL_MASK,
+ IMX6SX_GPR5_CSI2_MUX_CTRL_CVD);
+ } else {
+ regmap_update_bits(state->gpr, IOMUXC_GPR5,
+ IMX6SX_GPR5_CSI1_MUX_CTRL_MASK,
+ IMX6SX_GPR5_CSI1_MUX_CTRL_CVD);
+ }
+
+ /* Get default vadc_in number */
+ ret = of_property_read_u32(np, "vadc_in", &state->vadc_in);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read of property vadc_in\n");
+ return ret;
+ }
+
+ /* map GPC register */
+ gpc_np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc");
+ state->gpc_reg = of_iomap(gpc_np, 0);
+ if (!state->gpc_reg) {
+ dev_err(&pdev->dev, "ioremap failed with gpc base\n");
+ goto error;
+ }
+
+ return ret;
+
+error:
+ iounmap(state->gpc_reg);
+ return ret;
+}
+
+static void vadc_v4l2_subdev_init(struct v4l2_subdev *sd,
+ struct platform_device *pdev,
+ const struct v4l2_subdev_ops *ops)
+{
+ struct vadc_state *state = platform_get_drvdata(pdev);
+ int ret = 0;
+
+ v4l2_subdev_init(sd, ops);
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->owner = pdev->dev.driver->owner;
+ sd->dev = &pdev->dev;
+
+ /* initialize name */
+ snprintf(sd->name, sizeof(sd->name), "%s",
+ pdev->dev.driver->name);
+
+ v4l2_set_subdevdata(sd, state);
+
+ ret = v4l2_async_register_subdev(sd);
+ if (ret < 0)
+ dev_err(&pdev->dev, "%s--Async register faialed, ret=%d\n", __func__, ret);
+}
+
+static int vadc_probe(struct platform_device *pdev)
+{
+ struct vadc_state *state;
+ struct v4l2_subdev *sd;
+ struct resource *res;
+ int ret = 0;
+
+ state = devm_kzalloc(&pdev->dev, sizeof(struct vadc_state), GFP_KERNEL);
+ if (!state) {
+ dev_err(&pdev->dev, "Cannot allocate device data\n");
+ return -ENOMEM;
+ }
+
+ /* Set initial values for the sensor struct. */
+ state->fmt = &video_fmts[VADC_NTSC];
+
+ sd = &state->sd;
+
+ /* map vafe address */
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, VAFE_REGS_ADDR_RES_NAME);
+ if (!res) {
+ dev_err(&pdev->dev, "No vafe base address found.\n");
+ return -ENOMEM;
+ }
+ vafe_regbase = devm_ioremap_resource(&pdev->dev, res);
+ if (!vafe_regbase) {
+ dev_err(&pdev->dev, "ioremap failed with vafe base\n");
+ return -ENOMEM;
+ }
+
+ /* map vdec address */
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, VDEC_REGS_ADDR_RES_NAME);
+ if (!res) {
+ dev_err(&pdev->dev, "No vdec base address found.\n");
+ return -ENODEV;
+ }
+ vdec_regbase = devm_ioremap_resource(&pdev->dev, res);
+ if (!vdec_regbase) {
+ dev_err(&pdev->dev, "ioremap failed with vdec base\n");
+ return -ENOMEM;
+ }
+
+ /* Get clock */
+ state->vadc_clk = devm_clk_get(&pdev->dev, "vadc");
+ if (IS_ERR(state->vadc_clk)) {
+ ret = PTR_ERR(state->vadc_clk);
+ return ret;
+ }
+
+ state->csi_clk = devm_clk_get(&pdev->dev, "csi");
+ if (IS_ERR(state->csi_clk)) {
+ ret = PTR_ERR(state->csi_clk);
+ return ret;
+ }
+
+ /* clock */
+ clk_prepare_enable(state->csi_clk);
+ clk_prepare_enable(state->vadc_clk);
+
+ platform_set_drvdata(pdev, state);
+
+ vadc_v4l2_subdev_init(sd, pdev, &vadc_ops);
+
+ pm_runtime_enable(&pdev->dev);
+
+ pm_runtime_get_sync(&pdev->dev);
+ /* Init VADC */
+ ret = vadc_of_init(pdev);
+ if (ret < 0)
+ goto err;
+ vadc_init(state);
+
+ pr_info("vadc driver loaded\n");
+
+ return 0;
+err:
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ v4l2_async_unregister_subdev(&state->sd);
+ clk_disable_unprepare(state->csi_clk);
+ clk_disable_unprepare(state->vadc_clk);
+ return ret;
+}
+
+static int vadc_remove(struct platform_device *pdev)
+{
+ struct vadc_state *state = platform_get_drvdata(pdev);
+
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ v4l2_async_unregister_subdev(&state->sd);
+ clk_disable_unprepare(state->csi_clk);
+ clk_disable_unprepare(state->vadc_clk);
+
+ vadc_power_down(state);
+ return true;
+}
+
+static int vadc_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct vadc_state *state = platform_get_drvdata(pdev);
+
+ clk_disable(state->csi_clk);
+ clk_disable(state->vadc_clk);
+
+ vadc_power_down(state);
+
+ return 0;
+}
+
+static int vadc_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct vadc_state *state = platform_get_drvdata(pdev);
+
+ clk_enable(state->csi_clk);
+ clk_enable(state->vadc_clk);
+
+ vadc_init(state);
+ return 0;
+}
+
+static const struct dev_pm_ops vadc_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(vadc_suspend, vadc_resume)
+};
+
+static struct platform_driver vadc_driver = {
+ .driver = {
+ .name = "fsl_vadc",
+ .of_match_table = of_match_ptr(fsl_vadc_dt_ids),
+ .pm = &vadc_pm_ops,
+ },
+ .probe = vadc_probe,
+ .remove = vadc_remove,
+};
+
+module_platform_driver(vadc_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("fsl VADC/VDEC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/mxc_vadc.h b/drivers/media/platform/mxc/capture/mxc_vadc.h
new file mode 100644
index 000000000000..d5c1389cbc58
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/mxc_vadc.h
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 MXC_VDEC_H
+#define MXC_VDEC_H
+
+/*** define base address ***/
+#define VDEC_BASE vdec_regbase
+#define AFE_BASE vafe_regbase
+
+/* AFE - Register offsets */
+#define AFE_BLOCK_ID_OFFSET 0x00000000
+#define AFE_PDBUF_OFFSET 0x00000004
+#define AFE_SWRST_OFFSET 0x00000008
+#define AFE_TSTSEL_OFFSET 0x0000000c
+#define AFE_TSTMSC_OFFSET 0x00000010
+#define AFE_ENPADIO_OFFSET 0x00000014
+#define AFE_BGREG_OFFSET 0x00000018
+#define AFE_ACCESSAR_ID_OFFSET 0x00000400
+#define AFE_PDADC_OFFSET 0x00000404
+#define AFE_PDSARH_OFFSET 0x00000408
+#define AFE_PDSARL_OFFSET 0x0000040C
+#define AFE_PDADCRFH_OFFSET 0x00000410
+#define AFE_PDADCRFL_OFFSET 0x00000414
+#define AFE_ACCTST_OFFSET 0x00000418
+#define AFE_ADCGN_OFFSET 0x0000041C
+#define AFE_ICTRL_OFFSET 0x00000420
+#define AFE_ICTLSTG_OFFSET 0x00000424
+#define AFE_RCTRLSTG_OFFSET 0x00000428
+#define AFE_TCTRLSTG_OFFSET 0x0000042c
+#define AFE_REFMOD_OFFSET 0x00000430
+#define AFE_REFTRIML_OFFSET 0x00000434
+#define AFE_REFTRIMH_OFFSET 0x00000438
+#define AFE_ADCR_OFFSET 0x0000043c
+#define AFE_DUMMY0_OFFSET 0x00000440
+#define AFE_DUMMY1_OFFSET 0x00000444
+#define AFE_DUMMY2_OFFSET 0x00000448
+#define AFE_DACAMP_OFFSET 0x0000044c
+#define AFE_CLMPTST_OFFSET 0x00000450
+#define AFE_CLMPDAT_OFFSET 0x00000454
+#define AFE_CLMPAMP_OFFSET 0x00000458
+#define AFE_CLAMP_OFFSET 0x0000045c
+#define AFE_INPBUF_OFFSET 0x00000460
+#define AFE_INPFLT_OFFSET 0x00000464
+#define AFE_ADCDGN_OFFSET 0x00000468
+#define AFE_OFFDRV_OFFSET 0x0000046c
+#define AFE_INPCONFIG_OFFSET 0x00000470
+#define AFE_PROGDELAY_OFFSET 0x00000474
+#define AFE_ADCOMT_OFFSET 0x00000478
+#define AFE_ALGDELAY_OFFSET 0x0000047c
+#define AFE_ACC_ID_OFFSET 0x00000800
+#define AFE_ACCSTA_OFFSET 0x00000804
+#define AFE_ACCNOSLI_OFFSET 0x00000808
+#define AFE_ACCCALCON_OFFSET 0x0000080c
+#define AFE_BWEWRICTRL_OFFSET 0x00000810
+#define AFE_SELSLI_OFFSET 0x00000814
+#define AFE_SELBYT_OFFSET 0x00000818
+#define AFE_REDVAL_OFFSET 0x00000820
+#define AFE_WRIBYT_OFFSET 0x00000824
+
+/* AFE Register per module */
+#define AFE_BLOCK_ID (AFE_BASE + AFE_BLOCK_ID_OFFSET)
+#define AFE_PDBUF (AFE_BASE + AFE_PDBUF_OFFSET)
+#define AFE_SWRST (AFE_BASE + AFE_SWRST_OFFSET)
+#define AFE_TSTSEL (AFE_BASE + AFE_TSTSEL_OFFSET)
+#define AFE_TSTMSC (AFE_BASE + AFE_TSTMSC_OFFSET)
+#define AFE_ENPADIO (AFE_BASE + AFE_ENPADIO_OFFSET)
+#define AFE_BGREG (AFE_BASE + AFE_BGREG_OFFSET)
+#define AFE_ACCESSAR_ID (AFE_BASE + AFE_ACCESSAR_ID_OFFSET)
+#define AFE_PDADC (AFE_BASE + AFE_PDADC_OFFSET)
+#define AFE_PDSARH (AFE_BASE + AFE_PDSARH_OFFSET)
+#define AFE_PDSARL (AFE_BASE + AFE_PDSARL_OFFSET)
+#define AFE_PDADCRFH (AFE_BASE + AFE_PDADCRFH_OFFSET)
+#define AFE_PDADCRFL (AFE_BASE + AFE_PDADCRFL_OFFSET)
+#define AFE_ACCTST (AFE_BASE + AFE_ACCTST_OFFSET)
+#define AFE_ADCGN (AFE_BASE + AFE_ADCGN_OFFSET)
+#define AFE_ICTRL (AFE_BASE + AFE_ICTRL_OFFSET)
+#define AFE_ICTLSTG (AFE_BASE + AFE_ICTLSTG_OFFSET)
+#define AFE_RCTRLSTG (AFE_BASE + AFE_RCTRLSTG_OFFSET)
+#define AFE_TCTRLSTG (AFE_BASE + AFE_TCTRLSTG_OFFSET)
+#define AFE_REFMOD (AFE_BASE + AFE_REFMOD_OFFSET)
+#define AFE_REFTRIML (AFE_BASE + AFE_REFTRIML_OFFSET)
+#define AFE_REFTRIMH (AFE_BASE + AFE_REFTRIMH_OFFSET)
+#define AFE_ADCR (AFE_BASE + AFE_ADCR_OFFSET)
+#define AFE_DUMMY0 (AFE_BASE + AFE_DUMMY0_OFFSET)
+#define AFE_DUMMY1 (AFE_BASE + AFE_DUMMY1_OFFSET)
+#define AFE_DUMMY2 (AFE_BASE + AFE_DUMMY2_OFFSET)
+#define AFE_DACAMP (AFE_BASE + AFE_DACAMP_OFFSET)
+#define AFE_CLMPTST (AFE_BASE + AFE_CLMPTST_OFFSET)
+#define AFE_CLMPDAT (AFE_BASE + AFE_CLMPDAT_OFFSET)
+#define AFE_CLMPAMP (AFE_BASE + AFE_CLMPAMP_OFFSET)
+#define AFE_CLAMP (AFE_BASE + AFE_CLAMP_OFFSET)
+#define AFE_INPBUF (AFE_BASE + AFE_INPBUF_OFFSET)
+#define AFE_INPFLT (AFE_BASE + AFE_INPFLT_OFFSET)
+#define AFE_ADCDGN (AFE_BASE + AFE_ADCDGN_OFFSET)
+#define AFE_OFFDRV (AFE_BASE + AFE_OFFDRV_OFFSET)
+#define AFE_INPCONFIG (AFE_BASE + AFE_INPCONFIG_OFFSET)
+#define AFE_PROGDELAY (AFE_BASE + AFE_PROGDELAY_OFFSET)
+#define AFE_ADCOMT (AFE_BASE + AFE_ADCOMT_OFFSET)
+#define AFE_ALGDELAY (AFE_BASE + AFE_ALGDELAY_OFFSET)
+#define AFE_ACC_ID (AFE_BASE + AFE_ACC_ID_OFFSET)
+#define AFE_ACCSTA (AFE_BASE + AFE_ACCSTA_OFFSET)
+#define AFE_ACCNOSLI (AFE_BASE + AFE_ACCNOSLI_OFFSET)
+#define AFE_ACCCALCON (AFE_BASE + AFE_ACCCALCON_OFFSET)
+#define AFE_BWEWRICTRL (AFE_BASE + AFE_BWEWRICTRL_OFFSET)
+#define AFE_SELSLI (AFE_BASE + AFE_SELSLI_OFFSET)
+#define AFE_SELBYT (AFE_BASE + AFE_SELBYT_OFFSET)
+#define AFE_REDVAL (AFE_BASE + AFE_REDVAL_OFFSET)
+#define AFE_WRIBYT (AFE_BASE + AFE_WRIBYT_OFFSET)
+
+/* VDEC - Register offsets */
+#define VDEC_CFC1_OFFSET 0x00000000
+#define VDEC_CFC2_OFFSET 0x00000004
+#define VDEC_BRSTGT_OFFSET 0x00000024
+#define VDEC_HZPOS_OFFSET 0x00000040
+#define VDEC_VRTPOS_OFFSET 0x00000044
+#define VDEC_HVSHIFT_OFFSET 0x00000054
+#define VDEC_HSIGS_OFFSET 0x00000058
+#define VDEC_HSIGE_OFFSET 0x0000005C
+#define VDEC_VSCON1_OFFSET 0x00000060
+#define VDEC_VSCON2_OFFSET 0x00000064
+#define VDEC_YCDEL_OFFSET 0x0000006C
+#define VDEC_AFTCLP_OFFSET 0x00000070
+#define VDEC_DCOFF_OFFSET 0x00000078
+#define VDEC_CSID_OFFSET 0x00000084
+#define VDEC_CBGN_OFFSET 0x00000088
+#define VDEC_CRGN_OFFSET 0x0000008C
+#define VDEC_CNTR_OFFSET 0x00000090
+#define VDEC_BRT_OFFSET 0x00000094
+#define VDEC_HUE_OFFSET 0x00000098
+#define VDEC_CHBTH_OFFSET 0x0000009C
+#define VDEC_SHPIMP_OFFSET 0x000000A4
+#define VDEC_CHPLLIM_OFFSET 0x000000A8
+#define VDEC_VIDMOD_OFFSET 0x000000AC
+#define VDEC_VIDSTS_OFFSET 0x000000B0
+#define VDEC_NOISE_OFFSET 0x000000B4
+#define VDEC_STDDBG_OFFSET 0x000000B8
+#define VDEC_MANOVR_OFFSET 0x000000BC
+#define VDEC_VSSGTH_OFFSET 0x000000C8
+#define VDEC_DBGFBH_OFFSET 0x000000D0
+#define VDEC_DBGFBL_OFFSET 0x000000D4
+#define VDEC_HACTS_OFFSET 0x000000D8
+#define VDEC_HACTE_OFFSET 0x000000DC
+#define VDEC_VACTS_OFFSET 0x000000E0
+#define VDEC_VACTE_OFFSET 0x000000E4
+#define VDEC_HSTIP_OFFSET 0x000000EC
+#define VDEC_BLSCRY_OFFSET 0x000000F4
+#define VDEC_BLSCRCR_OFFSET 0x000000F8
+#define VDEC_BLSCRCB_OFFSET 0x000000FC
+#define VDEC_LMAGC1_OFFSET 0x00000100
+#define VDEC_LMAGC2_OFFSET 0x00000104
+#define VDEC_CHAGC1_OFFSET 0x00000108
+#define VDEC_CHAGC2_OFFSET 0x0000010C
+#define VDEC_MINTH_OFFSET 0x00000114
+#define VDEC_VFRQOH_OFFSET 0x0000011C
+#define VDEC_VFRQOL_OFFSET 0x00000120
+#define VDEC_THSH1_OFFSET 0x00000124
+#define VDEC_THSH2_OFFSET 0x00000128
+#define VDEC_NCHTH_OFFSET 0x0000012C
+#define VDEC_TH1F_OFFSET 0x00000130
+
+/* VDEC Register per module */
+#define VDEC_CFC1 (VDEC_BASE + VDEC_CFC1_OFFSET)
+#define VDEC_CFC2 (VDEC_BASE + VDEC_CFC2_OFFSET)
+#define VDEC_BRSTGT (VDEC_BASE + VDEC_BRSTGT_OFFSET)
+#define VDEC_HZPOS (VDEC_BASE + VDEC_HZPOS_OFFSET)
+#define VDEC_VRTPOS (VDEC_BASE + VDEC_VRTPOS_OFFSET)
+#define VDEC_HVSHIFT (VDEC_BASE + VDEC_HVSHIFT_OFFSET)
+#define VDEC_HSIGS (VDEC_BASE + VDEC_HSIGS_OFFSET)
+#define VDEC_HSIGE (VDEC_BASE + VDEC_HSIGE_OFFSET)
+#define VDEC_VSCON1 (VDEC_BASE + VDEC_VSCON1_OFFSET)
+#define VDEC_VSCON2 (VDEC_BASE + VDEC_VSCON2_OFFSET)
+#define VDEC_YCDEL (VDEC_BASE + VDEC_YCDEL_OFFSET)
+#define VDEC_AFTCLP (VDEC_BASE + VDEC_AFTCLP_OFFSET)
+#define VDEC_DCOFF (VDEC_BASE + VDEC_DCOFF_OFFSET)
+#define VDEC_CSID (VDEC_BASE + VDEC_CSID_OFFSET)
+#define VDEC_CBGN (VDEC_BASE + VDEC_CBGN_OFFSET)
+#define VDEC_CRGN (VDEC_BASE + VDEC_CRGN_OFFSET)
+#define VDEC_CNTR (VDEC_BASE + VDEC_CNTR_OFFSET)
+#define VDEC_BRT (VDEC_BASE + VDEC_BRT_OFFSET)
+#define VDEC_HUE (VDEC_BASE + VDEC_HUE_OFFSET)
+#define VDEC_CHBTH (VDEC_BASE + VDEC_CHBTH_OFFSET)
+#define VDEC_SHPIMP (VDEC_BASE + VDEC_SHPIMP_OFFSET)
+#define VDEC_CHPLLIM (VDEC_BASE + VDEC_CHPLLIM_OFFSET)
+#define VDEC_VIDMOD (VDEC_BASE + VDEC_VIDMOD_OFFSET)
+#define VDEC_VIDSTS (VDEC_BASE + VDEC_VIDSTS_OFFSET)
+#define VDEC_NOISE (VDEC_BASE + VDEC_NOISE_OFFSET)
+#define VDEC_STDDBG (VDEC_BASE + VDEC_STDDBG_OFFSET)
+#define VDEC_MANOVR (VDEC_BASE + VDEC_MANOVR_OFFSET)
+#define VDEC_VSSGTH (VDEC_BASE + VDEC_VSSGTH_OFFSET)
+#define VDEC_DBGFBH (VDEC_BASE + VDEC_DBGFBH_OFFSET)
+#define VDEC_DBGFBL (VDEC_BASE + VDEC_DBGFBL_OFFSET)
+#define VDEC_HACTS (VDEC_BASE + VDEC_HACTS_OFFSET)
+#define VDEC_HACTE (VDEC_BASE + VDEC_HACTE_OFFSET)
+#define VDEC_VACTS (VDEC_BASE + VDEC_VACTS_OFFSET)
+#define VDEC_VACTE (VDEC_BASE + VDEC_VACTE_OFFSET)
+#define VDEC_HSTIP (VDEC_BASE + VDEC_HSTIP_OFFSET)
+#define VDEC_BLSCRY (VDEC_BASE + VDEC_BLSCRY_OFFSET)
+#define VDEC_BLSCRCR (VDEC_BASE + VDEC_BLSCRCR_OFFSET)
+#define VDEC_BLSCRCB (VDEC_BASE + VDEC_BLSCRCB_OFFSET)
+#define VDEC_LMAGC1 (VDEC_BASE + VDEC_LMAGC1_OFFSET)
+#define VDEC_LMAGC2 (VDEC_BASE + VDEC_LMAGC2_OFFSET)
+#define VDEC_CHAGC1 (VDEC_BASE + VDEC_CHAGC1_OFFSET)
+#define VDEC_CHAGC2 (VDEC_BASE + VDEC_CHAGC2_OFFSET)
+#define VDEC_MINTH (VDEC_BASE + VDEC_MINTH_OFFSET)
+#define VDEC_VFRQOH (VDEC_BASE + VDEC_VFRQOH_OFFSET)
+#define VDEC_VFRQOL (VDEC_BASE + VDEC_VFRQOL_OFFSET)
+#define VDEC_THSH1 (VDEC_BASE + VDEC_THSH1_OFFSET)
+#define VDEC_THSH2 (VDEC_BASE + VDEC_THSH2_OFFSET)
+#define VDEC_NCHTH (VDEC_BASE + VDEC_NCHTH_OFFSET)
+#define VDEC_TH1F (VDEC_BASE + VDEC_TH1F_OFFSET)
+
+#define VDEC_VIDMOD_SIGNAL_MASK 0x0F
+#define VDEC_VIDMOD_SIGNAL_DETECT 0x0F
+
+#define VDEC_VIDMOD_M625_SHIFT 4
+#define VDEC_VIDMOD_M625_MASK (1 << VDEC_VIDMOD_M625_SHIFT)
+
+#define VDEC_VIDMOD_PAL_SHIFT 7
+#define VDEC_VIDMOD_PAL_MASK (1 << VDEC_VIDMOD_PAL_SHIFT)
+/*** define base address ***/
+
+#endif
diff --git a/drivers/media/platform/mxc/capture/ov5640.c b/drivers/media/platform/mxc/capture/ov5640.c
new file mode 100644
index 000000000000..ec8b8090201d
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/ov5640.c
@@ -0,0 +1,1950 @@
+/*
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-chip-ident.h>
+#include "v4l2-int-device.h"
+#include "mxc_v4l2_capture.h"
+
+#define OV5640_VOLTAGE_ANALOG 2800000
+#define OV5640_VOLTAGE_DIGITAL_CORE 1500000
+#define OV5640_VOLTAGE_DIGITAL_IO 1800000
+
+#define MIN_FPS 15
+#define MAX_FPS 30
+#define DEFAULT_FPS 30
+
+#define OV5640_XCLK_MIN 6000000
+#define OV5640_XCLK_MAX 24000000
+
+#define OV5640_CHIP_ID_HIGH_BYTE 0x300A
+#define OV5640_CHIP_ID_LOW_BYTE 0x300B
+
+enum ov5640_mode {
+ ov5640_mode_MIN = 0,
+ ov5640_mode_VGA_640_480 = 0,
+ ov5640_mode_QVGA_320_240 = 1,
+ ov5640_mode_NTSC_720_480 = 2,
+ ov5640_mode_PAL_720_576 = 3,
+ ov5640_mode_720P_1280_720 = 4,
+ ov5640_mode_1080P_1920_1080 = 5,
+ ov5640_mode_QSXGA_2592_1944 = 6,
+ ov5640_mode_QCIF_176_144 = 7,
+ ov5640_mode_XGA_1024_768 = 8,
+ ov5640_mode_MAX = 8
+};
+
+enum ov5640_frame_rate {
+ ov5640_15_fps,
+ ov5640_30_fps
+};
+
+static int ov5640_framerates[] = {
+ [ov5640_15_fps] = 15,
+ [ov5640_30_fps] = 30,
+};
+
+struct reg_value {
+ u16 u16RegAddr;
+ u8 u8Val;
+ u8 u8Mask;
+ u32 u32Delay_ms;
+};
+
+struct ov5640_mode_info {
+ enum ov5640_mode mode;
+ u32 width;
+ u32 height;
+ struct reg_value *init_data_ptr;
+ u32 init_data_size;
+};
+
+/*!
+ * Maintains the information on the current state of the sesor.
+ */
+static struct sensor_data ov5640_data;
+static int pwn_gpio, rst_gpio;
+static int prev_sysclk;
+static int AE_Target = 52, night_mode;
+static int prev_HTS;
+static int AE_high, AE_low;
+
+static struct reg_value ov5640_global_init_setting[] = {
+ {0x3008, 0x42, 0, 0},
+ {0x3103, 0x03, 0, 0}, {0x3017, 0xff, 0, 0}, {0x3018, 0xff, 0, 0},
+ {0x3034, 0x1a, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0},
+ {0x3630, 0x36, 0, 0}, {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0},
+ {0x3633, 0x12, 0, 0}, {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0},
+ {0x3703, 0x5a, 0, 0}, {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0},
+ {0x370b, 0x60, 0, 0}, {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0},
+ {0x3906, 0x10, 0, 0}, {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0},
+ {0x3600, 0x08, 0, 0}, {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0},
+ {0x3620, 0x52, 0, 0}, {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0},
+ {0x3a13, 0x43, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0},
+ {0x3635, 0x13, 0, 0}, {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0},
+ {0x3622, 0x01, 0, 0}, {0x3c01, 0x34, 0, 0}, {0x3c04, 0x28, 0, 0},
+ {0x3c05, 0x98, 0, 0}, {0x3c06, 0x00, 0, 0}, {0x3c07, 0x07, 0, 0},
+ {0x3c08, 0x00, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0},
+ {0x3c0b, 0x40, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0},
+ {0x3812, 0x00, 0, 0}, {0x3708, 0x64, 0, 0}, {0x4001, 0x02, 0, 0},
+ {0x4005, 0x1a, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3004, 0xff, 0, 0},
+ {0x300e, 0x58, 0, 0}, {0x302e, 0x00, 0, 0}, {0x4300, 0x30, 0, 0},
+ {0x501f, 0x00, 0, 0}, {0x440e, 0x00, 0, 0}, {0x5000, 0xa7, 0, 0},
+ {0x3008, 0x02, 0, 0},
+};
+
+static struct reg_value ov5640_init_setting_30fps_VGA[] = {
+ {0x3008, 0x42, 0, 0},
+ {0x3103, 0x03, 0, 0}, {0x3017, 0xff, 0, 0}, {0x3018, 0xff, 0, 0},
+ {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, {0x3036, 0x46, 0, 0},
+ {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0},
+ {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
+ {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
+ {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
+ {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
+ {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
+ {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
+ {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
+ {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
+ {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
+ {0x3c01, 0x34, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
+ {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
+ {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x300e, 0x58, 0, 0}, {0x302e, 0x00, 0, 0}, {0x4300, 0x30, 0, 0},
+ {0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0},
+ {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5000, 0xa7, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0xf2, 0, 0},
+ {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0},
+ {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, {0x5187, 0x09, 0, 0},
+ {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, {0x518a, 0x54, 0, 0},
+ {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x50, 0, 0},
+ {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, {0x5190, 0x46, 0, 0},
+ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0},
+ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x6c, 0, 0},
+ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x09, 0, 0},
+ {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, {0x5381, 0x1e, 0, 0},
+ {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, {0x5384, 0x0a, 0, 0},
+ {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, {0x5387, 0x7c, 0, 0},
+ {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, {0x538a, 0x01, 0, 0},
+ {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, {0x5301, 0x30, 0, 0},
+ {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, {0x5304, 0x08, 0, 0},
+ {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, {0x5307, 0x16, 0, 0},
+ {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, {0x530b, 0x04, 0, 0},
+ {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, {0x5481, 0x08, 0, 0},
+ {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, {0x5484, 0x51, 0, 0},
+ {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, {0x5487, 0x7d, 0, 0},
+ {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, {0x548a, 0x9a, 0, 0},
+ {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, {0x548d, 0xcd, 0, 0},
+ {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, {0x5490, 0x1d, 0, 0},
+ {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x10, 0, 0},
+ {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, {0x558b, 0xf8, 0, 0},
+ {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, {0x5802, 0x0f, 0, 0},
+ {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, {0x5805, 0x26, 0, 0},
+ {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, {0x5808, 0x05, 0, 0},
+ {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, {0x580b, 0x0d, 0, 0},
+ {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, {0x580e, 0x00, 0, 0},
+ {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, {0x5811, 0x09, 0, 0},
+ {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x00, 0, 0},
+ {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, {0x5817, 0x08, 0, 0},
+ {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, {0x581a, 0x05, 0, 0},
+ {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, {0x581d, 0x0e, 0, 0},
+ {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, {0x5820, 0x11, 0, 0},
+ {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, {0x5823, 0x28, 0, 0},
+ {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, {0x5826, 0x08, 0, 0},
+ {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, {0x5829, 0x26, 0, 0},
+ {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, {0x582c, 0x24, 0, 0},
+ {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, {0x582f, 0x22, 0, 0},
+ {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, {0x5832, 0x24, 0, 0},
+ {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, {0x5835, 0x22, 0, 0},
+ {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, {0x5838, 0x44, 0, 0},
+ {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, {0x583b, 0x28, 0, 0},
+ {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, {0x5025, 0x00, 0, 0},
+ {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, {0x3a1b, 0x30, 0, 0},
+ {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x14, 0, 0},
+ {0x3008, 0x02, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_VGA_640_480[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0},
+ {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_VGA_640_480[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0},
+ {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_QVGA_320_240[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0},
+ {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QVGA_320_240[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0},
+ {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_NTSC_720_480[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0},
+ {0x3807, 0xd4, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0},
+ {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_NTSC_720_480[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0},
+ {0x3807, 0xd4, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0},
+ {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_PAL_720_576[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x60, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x09, 0, 0}, {0x3805, 0x7e, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0},
+ {0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_PAL_720_576[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x60, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x09, 0, 0}, {0x3805, 0x7e, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0},
+ {0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_720P_1280_720[] = {
+ {0x3035, 0x21, 0, 0}, {0x3036, 0x69, 0, 0}, {0x3c07, 0x07, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
+ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+ {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0},
+ {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3813, 0x04, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3709, 0x52, 0, 0},
+ {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe0, 0, 0},
+ {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe0, 0, 0}, {0x4004, 0x02, 0, 0},
+ {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x4837, 0x16, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
+ {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_720P_1280_720[] = {
+ {0x3035, 0x41, 0, 0}, {0x3036, 0x69, 0, 0}, {0x3c07, 0x07, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
+ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+ {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0},
+ {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3813, 0x04, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3709, 0x52, 0, 0},
+ {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe0, 0, 0},
+ {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe0, 0, 0}, {0x4004, 0x02, 0, 0},
+ {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x4837, 0x16, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
+ {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_QCIF_176_144[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0},
+ {0x380a, 0x00, 0, 0}, {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QCIF_176_144[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0},
+ {0x380a, 0x00, 0, 0}, {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_XGA_1024_768[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0},
+ {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x20, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x01, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_XGA_1024_768[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0},
+ {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x20, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x01, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+
+static struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = {
+ {0x3c07, 0x07, 0, 0}, {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0},
+ {0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0xee, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x05, 0, 0},
+ {0x3807, 0xc3, 0, 0}, {0x3808, 0x07, 0, 0}, {0x3809, 0x80, 0, 0},
+ {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, {0x380c, 0x0b, 0, 0},
+ {0x380d, 0x1c, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0},
+ {0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x2b, 0, 0},
+ {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x07, 0, 0},
+ {0x3a03, 0xae, 0, 0}, {0x3a14, 0x07, 0, 0}, {0x3a15, 0xae, 0, 0},
+ {0x4004, 0x06, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x02, 0, 0}, {0x4407, 0x0c, 0, 0}, {0x460b, 0x37, 0, 0},
+ {0x460c, 0x20, 0, 0}, {0x4837, 0x2c, 0, 0}, {0x3824, 0x01, 0, 0},
+ {0x5001, 0x83, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = {
+ {0x3c07, 0x07, 0, 0}, {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0},
+ {0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9f, 0, 0}, {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0},
+ {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0},
+ {0x380d, 0x1c, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0},
+ {0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x2b, 0, 0},
+ {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x07, 0, 0},
+ {0x3a03, 0xae, 0, 0}, {0x3a14, 0x07, 0, 0}, {0x3a15, 0xae, 0, 0},
+ {0x4004, 0x06, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x02, 0, 0}, {0x4407, 0x0c, 0, 0}, {0x460b, 0x37, 0, 0},
+ {0x460c, 0x20, 0, 0}, {0x4837, 0x2c, 0, 0}, {0x3824, 0x01, 0, 0},
+ {0x5001, 0x83, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = {
+ {
+ {ov5640_mode_VGA_640_480, 640, 480,
+ ov5640_setting_15fps_VGA_640_480,
+ ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)},
+ {ov5640_mode_QVGA_320_240, 320, 240,
+ ov5640_setting_15fps_QVGA_320_240,
+ ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)},
+ {ov5640_mode_NTSC_720_480, 720, 480,
+ ov5640_setting_15fps_NTSC_720_480,
+ ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)},
+ {ov5640_mode_PAL_720_576, 720, 576,
+ ov5640_setting_15fps_PAL_720_576,
+ ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)},
+ {ov5640_mode_720P_1280_720, 1280, 720,
+ ov5640_setting_15fps_720P_1280_720,
+ ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)},
+ {ov5640_mode_1080P_1920_1080, 1920, 1080,
+ ov5640_setting_15fps_1080P_1920_1080,
+ ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)},
+ {ov5640_mode_QSXGA_2592_1944, 2592, 1944,
+ ov5640_setting_15fps_QSXGA_2592_1944,
+ ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)},
+ {ov5640_mode_QCIF_176_144, 176, 144,
+ ov5640_setting_15fps_QCIF_176_144,
+ ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)},
+ {ov5640_mode_XGA_1024_768, 1024, 768,
+ ov5640_setting_15fps_XGA_1024_768,
+ ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)},
+ },
+ {
+ {ov5640_mode_VGA_640_480, 640, 480,
+ ov5640_setting_30fps_VGA_640_480,
+ ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)},
+ {ov5640_mode_QVGA_320_240, 320, 240,
+ ov5640_setting_30fps_QVGA_320_240,
+ ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)},
+ {ov5640_mode_NTSC_720_480, 720, 480,
+ ov5640_setting_30fps_NTSC_720_480,
+ ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)},
+ {ov5640_mode_PAL_720_576, 720, 576,
+ ov5640_setting_30fps_PAL_720_576,
+ ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)},
+ {ov5640_mode_720P_1280_720, 1280, 720,
+ ov5640_setting_30fps_720P_1280_720,
+ ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)},
+ {ov5640_mode_1080P_1920_1080, 0, 0, NULL, 0},
+ {ov5640_mode_QSXGA_2592_1944, 0, 0, NULL, 0},
+ {ov5640_mode_QCIF_176_144, 176, 144,
+ ov5640_setting_30fps_QCIF_176_144,
+ ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)},
+ {ov5640_mode_XGA_1024_768, 1024, 768,
+ ov5640_setting_30fps_XGA_1024_768,
+ ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)},
+ },
+};
+
+static struct regulator *io_regulator;
+static struct regulator *core_regulator;
+static struct regulator *analog_regulator;
+
+static int ov5640_probe(struct i2c_client *adapter,
+ const struct i2c_device_id *device_id);
+static int ov5640_remove(struct i2c_client *client);
+
+static s32 ov5640_read_reg(u16 reg, u8 *val);
+static s32 ov5640_write_reg(u16 reg, u8 val);
+
+static const struct i2c_device_id ov5640_id[] = {
+ {"ov564x", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, ov5640_id);
+
+static struct i2c_driver ov5640_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ov564x",
+ },
+ .probe = ov5640_probe,
+ .remove = ov5640_remove,
+ .id_table = ov5640_id,
+};
+
+static inline void ov5640_power_down(int enable)
+{
+ gpio_set_value(pwn_gpio, enable);
+
+ msleep(2);
+}
+
+static inline void ov5640_reset(void)
+{
+ /* camera reset */
+ gpio_set_value(rst_gpio, 1);
+
+ /* camera power down */
+ gpio_set_value(pwn_gpio, 1);
+ msleep(5);
+ gpio_set_value(pwn_gpio, 0);
+ msleep(5);
+ gpio_set_value(rst_gpio, 0);
+ msleep(1);
+ gpio_set_value(rst_gpio, 1);
+ msleep(5);
+ gpio_set_value(pwn_gpio, 1);
+}
+
+static int ov5640_regulator_enable(struct device *dev)
+{
+ int ret = 0;
+
+ io_regulator = devm_regulator_get(dev, "DOVDD");
+ if (!IS_ERR(io_regulator)) {
+ regulator_set_voltage(io_regulator,
+ OV5640_VOLTAGE_DIGITAL_IO,
+ OV5640_VOLTAGE_DIGITAL_IO);
+ ret = regulator_enable(io_regulator);
+ if (ret) {
+ dev_err(dev, "set io voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set io voltage ok\n");
+ }
+ } else {
+ io_regulator = NULL;
+ dev_warn(dev, "cannot get io voltage\n");
+ }
+
+ core_regulator = devm_regulator_get(dev, "DVDD");
+ if (!IS_ERR(core_regulator)) {
+ regulator_set_voltage(core_regulator,
+ OV5640_VOLTAGE_DIGITAL_CORE,
+ OV5640_VOLTAGE_DIGITAL_CORE);
+ ret = regulator_enable(core_regulator);
+ if (ret) {
+ dev_err(dev, "set core voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set core voltage ok\n");
+ }
+ } else {
+ core_regulator = NULL;
+ dev_warn(dev, "cannot get core voltage\n");
+ }
+
+ analog_regulator = devm_regulator_get(dev, "AVDD");
+ if (!IS_ERR(analog_regulator)) {
+ regulator_set_voltage(analog_regulator,
+ OV5640_VOLTAGE_ANALOG,
+ OV5640_VOLTAGE_ANALOG);
+ ret = regulator_enable(analog_regulator);
+ if (ret) {
+ dev_err(dev, "set analog voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set analog voltage ok\n");
+ }
+ } else {
+ analog_regulator = NULL;
+ dev_warn(dev, "cannot get analog voltage\n");
+ }
+
+ return ret;
+}
+
+static s32 ov5640_write_reg(u16 reg, u8 val)
+{
+ u8 au8Buf[3] = {0};
+
+ au8Buf[0] = reg >> 8;
+ au8Buf[1] = reg & 0xff;
+ au8Buf[2] = val;
+
+ if (i2c_master_send(ov5640_data.i2c_client, au8Buf, 3) < 0) {
+ pr_err("%s:write reg error:reg=%x,val=%x\n",
+ __func__, reg, val);
+ return -1;
+ }
+
+ return 0;
+}
+
+static s32 ov5640_read_reg(u16 reg, u8 *val)
+{
+ u8 au8RegBuf[2] = {0};
+ u8 u8RdVal = 0;
+
+ au8RegBuf[0] = reg >> 8;
+ au8RegBuf[1] = reg & 0xff;
+
+ if (2 != i2c_master_send(ov5640_data.i2c_client, au8RegBuf, 2)) {
+ pr_err("%s:write reg error:reg=%x\n",
+ __func__, reg);
+ return -1;
+ }
+
+ if (1 != i2c_master_recv(ov5640_data.i2c_client, &u8RdVal, 1)) {
+ pr_err("%s:read reg error:reg=%x,val=%x\n",
+ __func__, reg, u8RdVal);
+ return -1;
+ }
+
+ *val = u8RdVal;
+
+ return u8RdVal;
+}
+
+static void ov5640_soft_reset(void)
+{
+ /* sysclk from pad */
+ ov5640_write_reg(0x3103, 0x11);
+
+ /* software reset */
+ ov5640_write_reg(0x3008, 0x82);
+
+ /* delay at least 5ms */
+ msleep(10);
+}
+
+/* set sensor driver capability
+ * 0x302c[7:6] - strength
+ 00 - 1x
+ 01 - 2x
+ 10 - 3x
+ 11 - 4x
+ */
+static int ov5640_driver_capability(int strength)
+{
+ u8 temp = 0;
+
+ if (strength > 4 || strength < 1) {
+ pr_err("The valid driver capability of ov5640 is 1x~4x\n");
+ return -EINVAL;
+ }
+
+ ov5640_read_reg(0x302c, &temp);
+
+ temp &= ~0xc0; /* clear [7:6] */
+ temp |= ((strength - 1) << 6); /* set [7:6] */
+
+ ov5640_write_reg(0x302c, temp);
+
+ return 0;
+}
+
+/* calculate sysclk */
+static int ov5640_get_sysclk(void)
+{
+ int xvclk = ov5640_data.mclk / 10000;
+ int sysclk;
+ int temp1, temp2;
+ int Multiplier, PreDiv, VCO, SysDiv, Pll_rdiv, Bit_div2x, sclk_rdiv;
+ int sclk_rdiv_map[] = {1, 2, 4, 8};
+ u8 regval = 0;
+
+ temp1 = ov5640_read_reg(0x3034, &regval);
+ temp2 = temp1 & 0x0f;
+ if (temp2 == 8 || temp2 == 10) {
+ Bit_div2x = temp2 / 2;
+ } else {
+ pr_err("ov5640: unsupported bit mode %d\n", temp2);
+ return -1;
+ }
+
+ temp1 = ov5640_read_reg(0x3035, &regval);
+ SysDiv = temp1 >> 4;
+ if (SysDiv == 0)
+ SysDiv = 16;
+
+ temp1 = ov5640_read_reg(0x3036, &regval);
+ Multiplier = temp1;
+ temp1 = ov5640_read_reg(0x3037, &regval);
+ PreDiv = temp1 & 0x0f;
+ Pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
+
+ temp1 = ov5640_read_reg(0x3108, &regval);
+ temp2 = temp1 & 0x03;
+
+ sclk_rdiv = sclk_rdiv_map[temp2];
+ VCO = xvclk * Multiplier / PreDiv;
+ sysclk = VCO / SysDiv / Pll_rdiv * 2 / Bit_div2x / sclk_rdiv;
+
+ return sysclk;
+}
+
+/* read HTS from register settings */
+static int ov5640_get_HTS(void)
+{
+ int HTS;
+ u8 temp = 0;
+
+ HTS = ov5640_read_reg(0x380c, &temp);
+ HTS = (HTS<<8) + ov5640_read_reg(0x380d, &temp);
+ return HTS;
+}
+
+/* read VTS from register settings */
+static int ov5640_get_VTS(void)
+{
+ int VTS;
+ u8 temp = 0;
+
+ VTS = ov5640_read_reg(0x380e, &temp);
+ VTS = (VTS<<8) + ov5640_read_reg(0x380f, &temp);
+
+ return VTS;
+}
+
+/* write VTS to registers */
+static int ov5640_set_VTS(int VTS)
+{
+ int temp;
+
+ temp = VTS & 0xff;
+ ov5640_write_reg(0x380f, temp);
+
+ temp = VTS>>8;
+ ov5640_write_reg(0x380e, temp);
+ return 0;
+}
+
+/* read shutter, in number of line period */
+static int ov5640_get_shutter(void)
+{
+ int shutter;
+ u8 regval;
+
+ shutter = (ov5640_read_reg(0x03500, &regval) & 0x0f);
+
+ shutter = (shutter<<8) + ov5640_read_reg(0x3501, &regval);
+ shutter = (shutter<<4) + (ov5640_read_reg(0x3502, &regval)>>4);
+
+ return shutter;
+}
+
+/* write shutter, in number of line period */
+static int ov5640_set_shutter(int shutter)
+{
+ int temp;
+
+ shutter = shutter & 0xffff;
+ temp = shutter & 0x0f;
+ temp = temp<<4;
+ ov5640_write_reg(0x3502, temp);
+
+ temp = shutter & 0xfff;
+ temp = temp>>4;
+ ov5640_write_reg(0x3501, temp);
+
+ temp = shutter>>12;
+ ov5640_write_reg(0x3500, temp);
+
+ return 0;
+}
+
+/* read gain, 16 = 1x */
+static int ov5640_get_gain16(void)
+{
+ int gain16;
+ u8 regval;
+
+ gain16 = ov5640_read_reg(0x350a, &regval) & 0x03;
+ gain16 = (gain16<<8) + ov5640_read_reg(0x350b, &regval);
+
+ return gain16;
+}
+
+/* write gain, 16 = 1x */
+static int ov5640_set_gain16(int gain16)
+{
+ int temp;
+
+ gain16 = gain16 & 0x3ff;
+ temp = gain16 & 0xff;
+
+ ov5640_write_reg(0x350b, temp);
+ temp = gain16>>8;
+
+ ov5640_write_reg(0x350a, temp);
+ return 0;
+}
+
+/* get banding filter value */
+static int ov5640_get_light_freq(void)
+{
+ int temp, temp1, light_frequency;
+ u8 regval;
+
+ temp = ov5640_read_reg(0x3c01, &regval);
+ if (temp & 0x80) {
+ /* manual */
+ temp1 = ov5640_read_reg(0x3c00, &regval);
+ if (temp1 & 0x04) {
+ /* 50Hz */
+ light_frequency = 50;
+ } else {
+ /* 60Hz */
+ light_frequency = 60;
+ }
+ } else {
+ /* auto */
+ temp1 = ov5640_read_reg(0x3c0c, &regval);
+ if (temp1 & 0x01) {
+ /* 50Hz */
+ light_frequency = 50;
+ } else {
+ /* 60Hz */
+ light_frequency = 60;
+ }
+ }
+
+ return light_frequency;
+}
+
+static void ov5640_set_bandingfilter(void)
+{
+ int prev_VTS;
+ int band_step60, max_band60, band_step50, max_band50;
+
+ /* read preview PCLK */
+ prev_sysclk = ov5640_get_sysclk();
+
+ /* read preview HTS */
+ prev_HTS = ov5640_get_HTS();
+
+ /* read preview VTS */
+ prev_VTS = ov5640_get_VTS();
+
+ /* calculate banding filter */
+ /* 60Hz */
+ band_step60 = prev_sysclk * 100/prev_HTS * 100/120;
+ ov5640_write_reg(0x3a0a, (band_step60 >> 8));
+ ov5640_write_reg(0x3a0b, (band_step60 & 0xff));
+
+ max_band60 = (int)((prev_VTS-4)/band_step60);
+ ov5640_write_reg(0x3a0d, max_band60);
+
+ /* 50Hz */
+ band_step50 = prev_sysclk * 100/prev_HTS;
+ ov5640_write_reg(0x3a08, (band_step50 >> 8));
+ ov5640_write_reg(0x3a09, (band_step50 & 0xff));
+
+ max_band50 = (int)((prev_VTS-4)/band_step50);
+ ov5640_write_reg(0x3a0e, max_band50);
+}
+
+/* stable in high */
+static int ov5640_set_AE_target(int target)
+{
+ int fast_high, fast_low;
+
+ AE_low = target * 23 / 25; /* 0.92 */
+ AE_high = target * 27 / 25; /* 1.08 */
+ fast_high = AE_high << 1;
+
+ if (fast_high > 255)
+ fast_high = 255;
+ fast_low = AE_low >> 1;
+
+ ov5640_write_reg(0x3a0f, AE_high);
+ ov5640_write_reg(0x3a10, AE_low);
+ ov5640_write_reg(0x3a1b, AE_high);
+ ov5640_write_reg(0x3a1e, AE_low);
+ ov5640_write_reg(0x3a11, fast_high);
+ ov5640_write_reg(0x3a1f, fast_low);
+
+ return 0;
+}
+
+/* enable = 0 to turn off night mode
+ enable = 1 to turn on night mode */
+static int ov5640_set_night_mode(int enable)
+{
+ u8 mode;
+
+ ov5640_read_reg(0x3a00, &mode);
+
+ if (enable) {
+ /* night mode on */
+ mode |= 0x04;
+ ov5640_write_reg(0x3a00, mode);
+ } else {
+ /* night mode off */
+ mode &= 0xfb;
+ ov5640_write_reg(0x3a00, mode);
+ }
+
+ return 0;
+}
+
+/* enable = 0 to turn off AEC/AGC
+ enable = 1 to turn on AEC/AGC */
+static void ov5640_turn_on_AE_AG(int enable)
+{
+ u8 ae_ag_ctrl;
+
+ ov5640_read_reg(0x3503, &ae_ag_ctrl);
+ if (enable) {
+ /* turn on auto AE/AG */
+ ae_ag_ctrl = ae_ag_ctrl & ~(0x03);
+ } else {
+ /* turn off AE/AG */
+ ae_ag_ctrl = ae_ag_ctrl | 0x03;
+ }
+ ov5640_write_reg(0x3503, ae_ag_ctrl);
+}
+
+/* download ov5640 settings to sensor through i2c */
+static int ov5640_download_firmware(struct reg_value *pModeSetting, s32 ArySize)
+{
+ register u32 Delay_ms = 0;
+ register u16 RegAddr = 0;
+ register u8 Mask = 0;
+ register u8 Val = 0;
+ u8 RegVal = 0;
+ int i, retval = 0;
+
+ for (i = 0; i < ArySize; ++i, ++pModeSetting) {
+ Delay_ms = pModeSetting->u32Delay_ms;
+ RegAddr = pModeSetting->u16RegAddr;
+ Val = pModeSetting->u8Val;
+ Mask = pModeSetting->u8Mask;
+
+ if (Mask) {
+ retval = ov5640_read_reg(RegAddr, &RegVal);
+ if (retval < 0)
+ goto err;
+
+ RegVal &= ~(u8)Mask;
+ Val &= Mask;
+ Val |= RegVal;
+ }
+
+ retval = ov5640_write_reg(RegAddr, Val);
+ if (retval < 0)
+ goto err;
+
+ if (Delay_ms)
+ msleep(Delay_ms);
+ }
+err:
+ return retval;
+}
+
+static int ov5640_init_mode(void)
+{
+ struct reg_value *pModeSetting = NULL;
+ int ArySize = 0, retval = 0;
+
+ ov5640_soft_reset();
+
+ pModeSetting = ov5640_global_init_setting;
+ ArySize = ARRAY_SIZE(ov5640_global_init_setting);
+ retval = ov5640_download_firmware(pModeSetting, ArySize);
+ if (retval < 0)
+ goto err;
+
+ pModeSetting = ov5640_init_setting_30fps_VGA;
+ ArySize = ARRAY_SIZE(ov5640_init_setting_30fps_VGA);
+ retval = ov5640_download_firmware(pModeSetting, ArySize);
+ if (retval < 0)
+ goto err;
+
+ /* change driver capability to 2x according to validation board.
+ * if the image is not stable, please increase the driver strength.
+ */
+ ov5640_driver_capability(2);
+ ov5640_set_bandingfilter();
+ ov5640_set_AE_target(AE_Target);
+ ov5640_set_night_mode(night_mode);
+
+ /* skip 9 vysnc: start capture at 10th vsync */
+ msleep(300);
+
+ /* turn off night mode */
+ night_mode = 0;
+ ov5640_data.pix.width = 640;
+ ov5640_data.pix.height = 480;
+err:
+ return retval;
+}
+
+/* change to or back to subsampling mode set the mode directly
+ * image size below 1280 * 960 is subsampling mode */
+static int ov5640_change_mode_direct(enum ov5640_frame_rate frame_rate,
+ enum ov5640_mode mode)
+{
+ struct reg_value *pModeSetting = NULL;
+ s32 ArySize = 0;
+ int retval = 0;
+
+ if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) {
+ pr_err("Wrong ov5640 mode detected!\n");
+ return -1;
+ }
+
+ pModeSetting = ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+ ArySize =
+ ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+ ov5640_data.pix.width = ov5640_mode_info_data[frame_rate][mode].width;
+ ov5640_data.pix.height = ov5640_mode_info_data[frame_rate][mode].height;
+
+ if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 ||
+ pModeSetting == NULL || ArySize == 0)
+ return -EINVAL;
+
+ /* set ov5640 to subsampling mode */
+ retval = ov5640_download_firmware(pModeSetting, ArySize);
+
+ /* turn on AE AG for subsampling mode, in case the firmware didn't */
+ ov5640_turn_on_AE_AG(1);
+
+ /* calculate banding filter */
+ ov5640_set_bandingfilter();
+
+ /* set AE target */
+ ov5640_set_AE_target(AE_Target);
+
+ /* update night mode setting */
+ ov5640_set_night_mode(night_mode);
+
+ /* skip 9 vysnc: start capture at 10th vsync */
+ if (mode == ov5640_mode_XGA_1024_768 && frame_rate == ov5640_30_fps) {
+ pr_warning("ov5640: actual frame rate of XGA is 22.5fps\n");
+ /* 1/22.5 * 9*/
+ msleep(400);
+ return retval;
+ }
+
+ if (frame_rate == ov5640_15_fps) {
+ /* 1/15 * 9*/
+ msleep(600);
+ } else if (frame_rate == ov5640_30_fps) {
+ /* 1/30 * 9*/
+ msleep(300);
+ }
+
+ return retval;
+}
+
+/* change to scaling mode go through exposure calucation
+ * image size above 1280 * 960 is scaling mode */
+static int ov5640_change_mode_exposure_calc(enum ov5640_frame_rate frame_rate,
+ enum ov5640_mode mode)
+{
+ int prev_shutter, prev_gain16, average;
+ int cap_shutter, cap_gain16;
+ int cap_sysclk, cap_HTS, cap_VTS;
+ int light_freq, cap_bandfilt, cap_maxband;
+ long cap_gain16_shutter;
+ u8 temp;
+ struct reg_value *pModeSetting = NULL;
+ s32 ArySize = 0;
+ int retval = 0;
+
+ /* check if the input mode and frame rate is valid */
+ pModeSetting =
+ ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+ ArySize =
+ ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+ ov5640_data.pix.width =
+ ov5640_mode_info_data[frame_rate][mode].width;
+ ov5640_data.pix.height =
+ ov5640_mode_info_data[frame_rate][mode].height;
+
+ if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 ||
+ pModeSetting == NULL || ArySize == 0)
+ return -EINVAL;
+
+ /* read preview shutter */
+ prev_shutter = ov5640_get_shutter();
+
+ /* read preview gain */
+ prev_gain16 = ov5640_get_gain16();
+
+ /* get average */
+ average = ov5640_read_reg(0x56a1, &temp);
+
+ /* turn off night mode for capture */
+ ov5640_set_night_mode(0);
+
+ /* turn off overlay */
+ ov5640_write_reg(0x3022, 0x06);
+
+ /* Write capture setting */
+ retval = ov5640_download_firmware(pModeSetting, ArySize);
+ if (retval < 0)
+ goto err;
+
+ /* turn off AE AG when capture image. */
+ ov5640_turn_on_AE_AG(0);
+
+ /* read capture VTS */
+ cap_VTS = ov5640_get_VTS();
+ cap_HTS = ov5640_get_HTS();
+ cap_sysclk = ov5640_get_sysclk();
+
+ /* calculate capture banding filter */
+ light_freq = ov5640_get_light_freq();
+ if (light_freq == 60) {
+ /* 60Hz */
+ cap_bandfilt = cap_sysclk * 100 / cap_HTS * 100 / 120;
+ } else {
+ /* 50Hz */
+ cap_bandfilt = cap_sysclk * 100 / cap_HTS;
+ }
+ cap_maxband = (int)((cap_VTS - 4)/cap_bandfilt);
+ /* calculate capture shutter/gain16 */
+ if (average > AE_low && average < AE_high) {
+ /* in stable range */
+ cap_gain16_shutter =
+ prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk *
+ prev_HTS/cap_HTS * AE_Target / average;
+ } else {
+ cap_gain16_shutter =
+ prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk *
+ prev_HTS/cap_HTS;
+ }
+
+ /* gain to shutter */
+ if (cap_gain16_shutter < (cap_bandfilt * 16)) {
+ /* shutter < 1/100 */
+ cap_shutter = cap_gain16_shutter/16;
+ if (cap_shutter < 1)
+ cap_shutter = 1;
+ cap_gain16 = cap_gain16_shutter/cap_shutter;
+ if (cap_gain16 < 16)
+ cap_gain16 = 16;
+ } else {
+ if (cap_gain16_shutter > (cap_bandfilt*cap_maxband*16)) {
+ /* exposure reach max */
+ cap_shutter = cap_bandfilt*cap_maxband;
+ cap_gain16 = cap_gain16_shutter / cap_shutter;
+ } else {
+ /* 1/100 < cap_shutter =< max, cap_shutter = n/100 */
+ cap_shutter =
+ ((int)(cap_gain16_shutter/16/cap_bandfilt))
+ * cap_bandfilt;
+ cap_gain16 = cap_gain16_shutter / cap_shutter;
+ }
+ }
+
+ /* write capture gain */
+ ov5640_set_gain16(cap_gain16);
+
+ /* write capture shutter */
+ if (cap_shutter > (cap_VTS - 4)) {
+ cap_VTS = cap_shutter + 4;
+ ov5640_set_VTS(cap_VTS);
+ }
+
+ ov5640_set_shutter(cap_shutter);
+
+ /* skip 2 vysnc: start capture at 3rd vsync
+ * frame rate of QSXGA and 1080P is 7.5fps: 1/7.5 * 2
+ */
+ pr_warning("ov5640: the actual frame rate of %s is 7.5fps\n",
+ mode == ov5640_mode_1080P_1920_1080 ? "1080P" : "QSXGA");
+ msleep(267);
+err:
+ return retval;
+}
+
+static int ov5640_change_mode(enum ov5640_frame_rate frame_rate,
+ enum ov5640_mode mode)
+{
+ int retval = 0;
+
+ if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) {
+ pr_err("Wrong ov5640 mode detected!\n");
+ return -1;
+ }
+
+ if (mode == ov5640_mode_1080P_1920_1080 ||
+ mode == ov5640_mode_QSXGA_2592_1944) {
+ /* change to scaling mode go through exposure calucation
+ * image size above 1280 * 960 is scaling mode */
+ retval = ov5640_change_mode_exposure_calc(frame_rate, mode);
+ } else {
+ /* change back to subsampling modem download firmware directly
+ * image size below 1280 * 960 is subsampling mode */
+ retval = ov5640_change_mode_direct(frame_rate, mode);
+ }
+
+ return retval;
+}
+
+/* --------------- IOCTL functions from v4l2_int_ioctl_desc --------------- */
+
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+ if (s == NULL) {
+ pr_err(" ERROR!! no slave device set!\n");
+ return -1;
+ }
+
+ memset(p, 0, sizeof(*p));
+ p->u.bt656.clock_curr = ov5640_data.mclk;
+ pr_debug(" clock_curr=mclk=%d\n", ov5640_data.mclk);
+ p->if_type = V4L2_IF_TYPE_BT656;
+ p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT;
+ p->u.bt656.clock_min = OV5640_XCLK_MIN;
+ p->u.bt656.clock_max = OV5640_XCLK_MAX;
+ p->u.bt656.bt_sync_correct = 1; /* Indicate external vsync */
+
+ return 0;
+}
+
+/*!
+ * ioctl_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @on: indicates power mode (on or off)
+ *
+ * Turns the power on or off, depending on the value of on and returns the
+ * appropriate error code.
+ */
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
+{
+ struct sensor_data *sensor = s->priv;
+
+ if (on && !sensor->on) {
+ if (io_regulator)
+ if (regulator_enable(io_regulator) != 0)
+ return -EIO;
+ if (core_regulator)
+ if (regulator_enable(core_regulator) != 0)
+ return -EIO;
+ if (analog_regulator)
+ if (regulator_enable(analog_regulator) != 0)
+ return -EIO;
+ /* Make sure power on */
+ ov5640_power_down(0);
+ } else if (!on && sensor->on) {
+ if (analog_regulator)
+ regulator_disable(analog_regulator);
+ if (core_regulator)
+ regulator_disable(core_regulator);
+ if (io_regulator)
+ regulator_disable(io_regulator);
+
+ ov5640_power_down(1);
+}
+
+ sensor->on = on;
+
+ return 0;
+}
+
+/*!
+ * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+ struct sensor_data *sensor = s->priv;
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+ int ret = 0;
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cparm->capability = sensor->streamcap.capability;
+ cparm->timeperframe = sensor->streamcap.timeperframe;
+ cparm->capturemode = sensor->streamcap.capturemode;
+ ret = 0;
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ ret = -EINVAL;
+ break;
+
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible. If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ */
+static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+ struct sensor_data *sensor = s->priv;
+ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+ u32 tgt_fps; /* target frames per secound */
+ enum ov5640_frame_rate frame_rate;
+ int ret = 0;
+
+ /* Make sure power on */
+ ov5640_power_down(0);
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ /* Check that the new frame rate is allowed. */
+ if ((timeperframe->numerator == 0) ||
+ (timeperframe->denominator == 0)) {
+ timeperframe->denominator = DEFAULT_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps > MAX_FPS) {
+ timeperframe->denominator = MAX_FPS;
+ timeperframe->numerator = 1;
+ } else if (tgt_fps < MIN_FPS) {
+ timeperframe->denominator = MIN_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ /* Actual frame rate we use */
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps == 15)
+ frame_rate = ov5640_15_fps;
+ else if (tgt_fps == 30)
+ frame_rate = ov5640_30_fps;
+ else {
+ pr_err(" The camera frame rate is not supported!\n");
+ return -EINVAL;
+ }
+
+ ret = ov5640_change_mode(frame_rate,
+ a->parm.capture.capturemode);
+ if (ret < 0)
+ return ret;
+
+ sensor->streamcap.timeperframe = *timeperframe;
+ sensor->streamcap.capturemode = a->parm.capture.capturemode;
+
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ pr_debug(" type is not " \
+ "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n",
+ a->type);
+ ret = -EINVAL;
+ break;
+
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 v4l2_format structure
+ *
+ * Returns the sensor's current pixel format in the v4l2_format
+ * parameter.
+ */
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+{
+ struct sensor_data *sensor = s->priv;
+
+ f->fmt.pix = sensor->pix;
+
+ return 0;
+}
+
+/*!
+ * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure
+ *
+ * If the requested control is supported, returns the control's current
+ * value from the video_control[] array. Otherwise, returns -EINVAL
+ * if the control is not supported.
+ */
+static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
+{
+ int ret = 0;
+
+ switch (vc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ vc->value = ov5640_data.brightness;
+ break;
+ case V4L2_CID_HUE:
+ vc->value = ov5640_data.hue;
+ break;
+ case V4L2_CID_CONTRAST:
+ vc->value = ov5640_data.contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ vc->value = ov5640_data.saturation;
+ break;
+ case V4L2_CID_RED_BALANCE:
+ vc->value = ov5640_data.red;
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ vc->value = ov5640_data.blue;
+ break;
+ case V4L2_CID_EXPOSURE:
+ vc->value = ov5640_data.ae_mode;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+/*!
+ * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure
+ *
+ * If the requested control is supported, sets the control's current
+ * value in HW (and updates the video_control[] array). Otherwise,
+ * returns -EINVAL if the control is not supported.
+ */
+static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
+{
+ int retval = 0;
+
+ pr_debug("In ov5640:ioctl_s_ctrl %d\n",
+ vc->id);
+
+ switch (vc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ break;
+ case V4L2_CID_CONTRAST:
+ break;
+ case V4L2_CID_SATURATION:
+ break;
+ case V4L2_CID_HUE:
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ break;
+ case V4L2_CID_DO_WHITE_BALANCE:
+ break;
+ case V4L2_CID_RED_BALANCE:
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ break;
+ case V4L2_CID_GAMMA:
+ break;
+ case V4L2_CID_EXPOSURE:
+ break;
+ case V4L2_CID_AUTOGAIN:
+ break;
+ case V4L2_CID_GAIN:
+ break;
+ case V4L2_CID_HFLIP:
+ break;
+ case V4L2_CID_VFLIP:
+ break;
+ default:
+ retval = -EPERM;
+ break;
+ }
+
+ return retval;
+}
+
+/*!
+ * ioctl_enum_framesizes - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ioctl_enum_framesizes(struct v4l2_int_device *s,
+ struct v4l2_frmsizeenum *fsize)
+{
+ if (fsize->index > ov5640_mode_MAX)
+ return -EINVAL;
+
+ fsize->pixel_format = ov5640_data.pix.pixelformat;
+ fsize->discrete.width =
+ max(ov5640_mode_info_data[0][fsize->index].width,
+ ov5640_mode_info_data[1][fsize->index].width);
+ fsize->discrete.height =
+ max(ov5640_mode_info_data[0][fsize->index].height,
+ ov5640_mode_info_data[1][fsize->index].height);
+ return 0;
+}
+
+/*!
+ * ioctl_enum_frameintervals - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMEINTERVALS ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ioctl_enum_frameintervals(struct v4l2_int_device *s,
+ struct v4l2_frmivalenum *fival)
+{
+ int i, j, count;
+
+ if (fival->index < 0 || fival->index > ov5640_mode_MAX)
+ return -EINVAL;
+
+ if (fival->width == 0 || fival->height == 0 ||
+ fival->pixel_format == 0) {
+ pr_warning("Please assign pixelformat, width and height.\n");
+ return -EINVAL;
+ }
+
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->discrete.numerator = 1;
+
+ count = 0;
+ for (i = 0; i < ARRAY_SIZE(ov5640_mode_info_data); i++) {
+ for (j = 0; j < (ov5640_mode_MAX + 1); j++) {
+ if (fival->pixel_format == ov5640_data.pix.pixelformat
+ && fival->width == ov5640_mode_info_data[i][j].width
+ && fival->height == ov5640_mode_info_data[i][j].height
+ && ov5640_mode_info_data[i][j].init_data_ptr != NULL) {
+ count++;
+ }
+ if (fival->index == (count - 1)) {
+ fival->discrete.denominator =
+ ov5640_framerates[i];
+ return 0;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+/*!
+ * ioctl_g_chip_ident - V4L2 sensor interface handler for
+ * VIDIOC_DBG_G_CHIP_IDENT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @id: pointer to int
+ *
+ * Return 0.
+ */
+static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id)
+{
+ ((struct v4l2_dbg_chip_ident *)id)->match.type =
+ V4L2_CHIP_MATCH_I2C_DRIVER;
+ strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name, "ov5640_camera");
+
+ return 0;
+}
+
+/*!
+ * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT
+ * @s: pointer to standard V4L2 device structure
+ */
+static int ioctl_init(struct v4l2_int_device *s)
+{
+
+ return 0;
+}
+
+/*!
+ * ioctl_enum_fmt_cap - V4L2 sensor interface handler for VIDIOC_ENUM_FMT
+ * @s: pointer to standard V4L2 device structure
+ * @fmt: pointer to standard V4L2 fmt description structure
+ *
+ * Return 0.
+ */
+static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_fmtdesc *fmt)
+{
+ if (fmt->index > ov5640_mode_MAX)
+ return -EINVAL;
+
+ fmt->pixelformat = ov5640_data.pix.pixelformat;
+
+ return 0;
+}
+
+/*!
+ * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialise the device when slave attaches to the master.
+ */
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+ struct sensor_data *sensor = s->priv;
+ u32 tgt_xclk; /* target xclk */
+ u32 tgt_fps; /* target frames per secound */
+ enum ov5640_frame_rate frame_rate;
+ int ret;
+
+ ov5640_data.on = true;
+
+ /* mclk */
+ tgt_xclk = ov5640_data.mclk;
+ tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX);
+ tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN);
+ ov5640_data.mclk = tgt_xclk;
+
+ pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000);
+ clk_set_rate(ov5640_data.sensor_clk, ov5640_data.mclk);
+
+ /* Default camera frame rate is set in probe */
+ tgt_fps = sensor->streamcap.timeperframe.denominator /
+ sensor->streamcap.timeperframe.numerator;
+
+ if (tgt_fps == 15)
+ frame_rate = ov5640_15_fps;
+ else if (tgt_fps == 30)
+ frame_rate = ov5640_30_fps;
+ else
+ return -EINVAL; /* Only support 15fps or 30fps now. */
+
+ ret = ov5640_init_mode();
+ return ret;
+}
+
+/*!
+ * ioctl_dev_exit - V4L2 sensor interface handler for vidioc_int_dev_exit_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Delinitialise the device when slave detaches to the master.
+ */
+static int ioctl_dev_exit(struct v4l2_int_device *s)
+{
+ return 0;
+}
+
+/*!
+ * This structure defines all the ioctls for this module and links them to the
+ * enumeration.
+ */
+static struct v4l2_int_ioctl_desc ov5640_ioctl_desc[] = {
+ { vidioc_int_dev_init_num,
+ (v4l2_int_ioctl_func *)ioctl_dev_init },
+ { vidioc_int_dev_exit_num,
+ ioctl_dev_exit},
+ { vidioc_int_s_power_num,
+ (v4l2_int_ioctl_func *)ioctl_s_power },
+ { vidioc_int_g_ifparm_num,
+ (v4l2_int_ioctl_func *)ioctl_g_ifparm },
+ { vidioc_int_init_num,
+ (v4l2_int_ioctl_func *)ioctl_init },
+ { vidioc_int_enum_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap },
+ { vidioc_int_g_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_g_fmt_cap },
+ { vidioc_int_g_parm_num,
+ (v4l2_int_ioctl_func *)ioctl_g_parm },
+ { vidioc_int_s_parm_num,
+ (v4l2_int_ioctl_func *)ioctl_s_parm },
+ { vidioc_int_g_ctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_g_ctrl },
+ { vidioc_int_s_ctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_s_ctrl },
+ { vidioc_int_enum_framesizes_num,
+ (v4l2_int_ioctl_func *)ioctl_enum_framesizes },
+ { vidioc_int_enum_frameintervals_num,
+ (v4l2_int_ioctl_func *)ioctl_enum_frameintervals },
+ { vidioc_int_g_chip_ident_num,
+ (v4l2_int_ioctl_func *)ioctl_g_chip_ident },
+};
+
+static struct v4l2_int_slave ov5640_slave = {
+ .ioctls = ov5640_ioctl_desc,
+ .num_ioctls = ARRAY_SIZE(ov5640_ioctl_desc),
+};
+
+static struct v4l2_int_device ov5640_int_device = {
+ .module = THIS_MODULE,
+ .name = "ov564x",
+ .type = v4l2_int_type_slave,
+ .u = {
+ .slave = &ov5640_slave,
+ },
+};
+
+/*!
+ * ov5640 I2C probe function
+ *
+ * @param adapter struct i2c_adapter *
+ * @return Error code indicating success or failure
+ */
+static int ov5640_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pinctrl *pinctrl;
+ struct device *dev = &client->dev;
+ int retval;
+ u8 chip_id_high, chip_id_low;
+
+ /* ov5640 pinctrl */
+ pinctrl = devm_pinctrl_get_select_default(dev);
+ if (IS_ERR(pinctrl)) {
+ dev_err(dev, "setup pinctrl failed\n");
+ return PTR_ERR(pinctrl);
+ }
+
+ /* request power down pin */
+ pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+ if (!gpio_is_valid(pwn_gpio)) {
+ dev_err(dev, "no sensor pwdn pin available\n");
+ return -ENODEV;
+ }
+ retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH,
+ "ov5640_pwdn");
+ if (retval < 0)
+ return retval;
+
+ /* request reset pin */
+ rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0);
+ if (!gpio_is_valid(rst_gpio)) {
+ dev_err(dev, "no sensor reset pin available\n");
+ return -EINVAL;
+ }
+ retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH,
+ "ov5640_reset");
+ if (retval < 0)
+ return retval;
+
+ /* Set initial values for the sensor struct. */
+ memset(&ov5640_data, 0, sizeof(ov5640_data));
+ ov5640_data.sensor_clk = devm_clk_get(dev, "csi_mclk");
+ if (IS_ERR(ov5640_data.sensor_clk)) {
+ dev_err(dev, "get mclk failed\n");
+ return PTR_ERR(ov5640_data.sensor_clk);
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk",
+ &ov5640_data.mclk);
+ if (retval) {
+ dev_err(dev, "mclk frequency is invalid\n");
+ return retval;
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk_source",
+ (u32 *) &(ov5640_data.mclk_source));
+ if (retval) {
+ dev_err(dev, "mclk_source invalid\n");
+ return retval;
+ }
+
+ retval = of_property_read_u32(dev->of_node, "csi_id",
+ &(ov5640_data.csi));
+ if (retval) {
+ dev_err(dev, "csi_id invalid\n");
+ return retval;
+ }
+
+ clk_prepare_enable(ov5640_data.sensor_clk);
+
+ ov5640_data.io_init = ov5640_reset;
+ ov5640_data.i2c_client = client;
+ ov5640_data.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ ov5640_data.pix.width = 640;
+ ov5640_data.pix.height = 480;
+ ov5640_data.streamcap.capability = V4L2_MODE_HIGHQUALITY |
+ V4L2_CAP_TIMEPERFRAME;
+ ov5640_data.streamcap.capturemode = 0;
+ ov5640_data.streamcap.timeperframe.denominator = DEFAULT_FPS;
+ ov5640_data.streamcap.timeperframe.numerator = 1;
+
+ ov5640_regulator_enable(&client->dev);
+
+ ov5640_reset();
+
+ ov5640_power_down(0);
+
+ retval = ov5640_read_reg(OV5640_CHIP_ID_HIGH_BYTE, &chip_id_high);
+ if (retval < 0 || chip_id_high != 0x56) {
+ clk_disable_unprepare(ov5640_data.sensor_clk);
+ pr_warning("camera ov5640 is not found\n");
+ return -ENODEV;
+ }
+ retval = ov5640_read_reg(OV5640_CHIP_ID_LOW_BYTE, &chip_id_low);
+ if (retval < 0 || chip_id_low != 0x40) {
+ clk_disable_unprepare(ov5640_data.sensor_clk);
+ pr_warning("camera ov5640 is not found\n");
+ return -ENODEV;
+ }
+
+ ov5640_power_down(1);
+
+ clk_disable_unprepare(ov5640_data.sensor_clk);
+
+ ov5640_int_device.priv = &ov5640_data;
+ retval = v4l2_int_device_register(&ov5640_int_device);
+
+ pr_info("camera ov5640 is found\n");
+ return retval;
+}
+
+/*!
+ * ov5640 I2C detach function
+ *
+ * @param client struct i2c_client *
+ * @return Error code indicating success or failure
+ */
+static int ov5640_remove(struct i2c_client *client)
+{
+ v4l2_int_device_unregister(&ov5640_int_device);
+
+ if (analog_regulator)
+ regulator_disable(analog_regulator);
+
+ if (core_regulator)
+ regulator_disable(core_regulator);
+
+ if (io_regulator)
+ regulator_disable(io_regulator);
+
+ return 0;
+}
+
+module_i2c_driver(ov5640_i2c_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("OV5640 Camera Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("CSI");
diff --git a/drivers/media/platform/mxc/capture/ov5640_mipi.c b/drivers/media/platform/mxc/capture/ov5640_mipi.c
new file mode 100644
index 000000000000..0d146b534f61
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/ov5640_mipi.c
@@ -0,0 +1,2142 @@
+/*
+ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/i2c.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/fsl_devices.h>
+#include <linux/mipi_csi2.h>
+#include <media/v4l2-chip-ident.h>
+#include "v4l2-int-device.h"
+#include "mxc_v4l2_capture.h"
+
+#define OV5640_VOLTAGE_ANALOG 2800000
+#define OV5640_VOLTAGE_DIGITAL_CORE 1500000
+#define OV5640_VOLTAGE_DIGITAL_IO 1800000
+
+#define MIN_FPS 15
+#define MAX_FPS 30
+#define DEFAULT_FPS 30
+
+#define OV5640_XCLK_MIN 6000000
+#define OV5640_XCLK_MAX 24000000
+
+#define OV5640_CHIP_ID_HIGH_BYTE 0x300A
+#define OV5640_CHIP_ID_LOW_BYTE 0x300B
+
+enum ov5640_mode {
+ ov5640_mode_MIN = 0,
+ ov5640_mode_VGA_640_480 = 0,
+ ov5640_mode_QVGA_320_240 = 1,
+ ov5640_mode_NTSC_720_480 = 2,
+ ov5640_mode_PAL_720_576 = 3,
+ ov5640_mode_720P_1280_720 = 4,
+ ov5640_mode_1080P_1920_1080 = 5,
+ ov5640_mode_QSXGA_2592_1944 = 6,
+ ov5640_mode_QCIF_176_144 = 7,
+ ov5640_mode_XGA_1024_768 = 8,
+ ov5640_mode_MAX = 8,
+ ov5640_mode_INIT = 0xff, /*only for sensor init*/
+};
+
+enum ov5640_frame_rate {
+ ov5640_15_fps,
+ ov5640_30_fps
+};
+
+static int ov5640_framerates[] = {
+ [ov5640_15_fps] = 15,
+ [ov5640_30_fps] = 30,
+};
+
+/* image size under 1280 * 960 are SUBSAMPLING
+ * image size upper 1280 * 960 are SCALING
+ */
+enum ov5640_downsize_mode {
+ SUBSAMPLING,
+ SCALING,
+};
+
+struct reg_value {
+ u16 u16RegAddr;
+ u8 u8Val;
+ u8 u8Mask;
+ u32 u32Delay_ms;
+};
+
+struct ov5640_mode_info {
+ enum ov5640_mode mode;
+ enum ov5640_downsize_mode dn_mode;
+ u32 width;
+ u32 height;
+ struct reg_value *init_data_ptr;
+ u32 init_data_size;
+};
+
+/*!
+ * Maintains the information on the current state of the sesor.
+ */
+static struct sensor_data ov5640_data;
+static int pwn_gpio, rst_gpio;
+
+static struct reg_value ov5640_init_setting_30fps_VGA[] = {
+
+ {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
+ {0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0},
+ {0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0},
+ {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0},
+ {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
+ {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
+ {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
+ {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
+ {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
+ {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
+ {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
+ {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
+ {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
+ {0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
+ {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
+ {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x300e, 0x45, 0, 0}, {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
+ {0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0},
+ {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x4837, 0x0a, 0, 0}, {0x4800, 0x04, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
+ {0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
+ {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
+ {0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
+ {0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
+ {0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
+ {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
+ {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
+ {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
+ {0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
+ {0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
+ {0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
+ {0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
+ {0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
+ {0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
+ {0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
+ {0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
+ {0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
+ {0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
+ {0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
+ {0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
+ {0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
+ {0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
+ {0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
+ {0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
+ {0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
+ {0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
+ {0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
+ {0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
+ {0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
+ {0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
+ {0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
+ {0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
+ {0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
+ {0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
+ {0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
+ {0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
+ {0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
+ {0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
+ {0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
+ {0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
+ {0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
+ {0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
+ {0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
+ {0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
+ {0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
+ {0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
+ {0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
+ {0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
+ {0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
+};
+
+static struct reg_value ov5640_setting_30fps_VGA_640_480[] = {
+
+ {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_VGA_640_480[] = {
+ {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_XGA_1024_768[] = {
+
+ {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0},
+ {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0},
+ {0x380b, 0x00, 0, 0}, {0x3035, 0x12, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_XGA_1024_768[] = {
+ {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3808, 0x04, 0, 0},
+ {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_QVGA_320_240[] = {
+ {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0},
+ {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QVGA_320_240[] = {
+ {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0},
+ {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_QCIF_176_144[] = {
+ {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0},
+ {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+static struct reg_value ov5640_setting_15fps_QCIF_176_144[] = {
+ {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0},
+ {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_NTSC_720_480[] = {
+ {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0},
+ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_NTSC_720_480[] = {
+ {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0},
+ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_PAL_720_576[] = {
+ {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0},
+ {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_PAL_720_576[] = {
+ {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0},
+ {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_720P_1280_720[] = {
+ {0x3008, 0x42, 0, 0},
+ {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
+ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+ {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0},
+ {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
+ {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
+ {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
+ {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, {0x4005, 0x1a, 0, 0},
+ {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_720P_1280_720[] = {
+ {0x3035, 0x41, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
+ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+ {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0},
+ {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
+ {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
+ {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
+ {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = {
+ {0x3008, 0x42, 0, 0},
+ {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0},
+ {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
+ {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0},
+ {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+ {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
+ {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x11, 0, 0},
+ {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
+ {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
+ {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0},
+ {0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0},
+ {0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
+ {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
+ {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
+ {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0},
+ {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
+ {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0},
+ {0x3503, 0, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = {
+ {0x3008, 0x42, 0, 0},
+ {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0},
+ {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
+ {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0},
+ {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+ {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
+ {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x54, 0, 1}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
+ {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
+ {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0},
+ {0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0},
+ {0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
+ {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
+ {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
+ {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0},
+ {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
+ {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = {
+ {0x4202, 0x0f, 0, 0}, /* stream off the sensor */
+ {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, /*disable flip*/
+ {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0},
+ {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
+ {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0},
+ {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+ {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
+ {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
+ {0x4202, 0x00, 0, 0}, /* stream on the sensor */
+};
+
+static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = {
+ {
+ {ov5640_mode_VGA_640_480, SUBSAMPLING, 640, 480,
+ ov5640_setting_15fps_VGA_640_480,
+ ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)},
+ {ov5640_mode_QVGA_320_240, SUBSAMPLING, 320, 240,
+ ov5640_setting_15fps_QVGA_320_240,
+ ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)},
+ {ov5640_mode_NTSC_720_480, SUBSAMPLING, 720, 480,
+ ov5640_setting_15fps_NTSC_720_480,
+ ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)},
+ {ov5640_mode_PAL_720_576, SUBSAMPLING, 720, 576,
+ ov5640_setting_15fps_PAL_720_576,
+ ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)},
+ {ov5640_mode_720P_1280_720, SUBSAMPLING, 1280, 720,
+ ov5640_setting_15fps_720P_1280_720,
+ ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)},
+ {ov5640_mode_1080P_1920_1080, SCALING, 1920, 1080,
+ ov5640_setting_15fps_1080P_1920_1080,
+ ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)},
+ {ov5640_mode_QSXGA_2592_1944, SCALING, 2592, 1944,
+ ov5640_setting_15fps_QSXGA_2592_1944,
+ ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)},
+ {ov5640_mode_QCIF_176_144, SUBSAMPLING, 176, 144,
+ ov5640_setting_15fps_QCIF_176_144,
+ ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)},
+ {ov5640_mode_XGA_1024_768, SUBSAMPLING, 1024, 768,
+ ov5640_setting_15fps_XGA_1024_768,
+ ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)},
+ },
+ {
+ {ov5640_mode_VGA_640_480, SUBSAMPLING, 640, 480,
+ ov5640_setting_30fps_VGA_640_480,
+ ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)},
+ {ov5640_mode_QVGA_320_240, SUBSAMPLING, 320, 240,
+ ov5640_setting_30fps_QVGA_320_240,
+ ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)},
+ {ov5640_mode_NTSC_720_480, SUBSAMPLING, 720, 480,
+ ov5640_setting_30fps_NTSC_720_480,
+ ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)},
+ {ov5640_mode_PAL_720_576, SUBSAMPLING, 720, 576,
+ ov5640_setting_30fps_PAL_720_576,
+ ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)},
+ {ov5640_mode_720P_1280_720, SUBSAMPLING, 1280, 720,
+ ov5640_setting_30fps_720P_1280_720,
+ ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)},
+ {ov5640_mode_1080P_1920_1080, SCALING, 1920, 1080,
+ ov5640_setting_30fps_1080P_1920_1080,
+ ARRAY_SIZE(ov5640_setting_30fps_1080P_1920_1080)},
+ {ov5640_mode_QSXGA_2592_1944, -1, 0, 0, NULL, 0},
+ {ov5640_mode_QCIF_176_144, SUBSAMPLING, 176, 144,
+ ov5640_setting_30fps_QCIF_176_144,
+ ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)},
+ {ov5640_mode_XGA_1024_768, SUBSAMPLING, 1024, 768,
+ ov5640_setting_30fps_XGA_1024_768,
+ ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)},
+ },
+};
+
+static struct regulator *io_regulator;
+static struct regulator *core_regulator;
+static struct regulator *analog_regulator;
+static struct regulator *gpo_regulator;
+
+static int ov5640_probe(struct i2c_client *adapter,
+ const struct i2c_device_id *device_id);
+static int ov5640_remove(struct i2c_client *client);
+
+static s32 ov5640_read_reg(u16 reg, u8 *val);
+static s32 ov5640_write_reg(u16 reg, u8 val);
+
+static const struct i2c_device_id ov5640_id[] = {
+ {"ov564x_mipi", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, ov5640_id);
+
+static struct i2c_driver ov5640_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ov564x_mipi",
+ },
+ .probe = ov5640_probe,
+ .remove = ov5640_remove,
+ .id_table = ov5640_id,
+};
+
+static void ov5640_standby(s32 enable)
+{
+ if (enable)
+ gpio_set_value(pwn_gpio, 1);
+ else
+ gpio_set_value(pwn_gpio, 0);
+
+ msleep(100);
+}
+
+static void ov5640_reset(void)
+{
+ /* camera reset */
+ gpio_set_value(rst_gpio, 1);
+
+ /* camera power dowmn */
+ gpio_set_value(pwn_gpio, 1);
+ msleep(5);
+
+ gpio_set_value(pwn_gpio, 0);
+ msleep(5);
+
+ gpio_set_value(rst_gpio, 0);
+ msleep(1);
+
+ gpio_set_value(rst_gpio, 1);
+ msleep(5);
+
+ gpio_set_value(pwn_gpio, 1);
+}
+
+static int ov5640_power_on(struct device *dev)
+{
+ int ret = 0;
+
+ io_regulator = devm_regulator_get(dev, "DOVDD");
+ if (!IS_ERR(io_regulator)) {
+ regulator_set_voltage(io_regulator,
+ OV5640_VOLTAGE_DIGITAL_IO,
+ OV5640_VOLTAGE_DIGITAL_IO);
+ ret = regulator_enable(io_regulator);
+ if (ret) {
+ pr_err("%s:io set voltage error\n", __func__);
+ return ret;
+ } else {
+ dev_dbg(dev,
+ "%s:io set voltage ok\n", __func__);
+ }
+ } else {
+ pr_err("%s: cannot get io voltage error\n", __func__);
+ io_regulator = NULL;
+ }
+
+ core_regulator = devm_regulator_get(dev, "DVDD");
+ if (!IS_ERR(core_regulator)) {
+ regulator_set_voltage(core_regulator,
+ OV5640_VOLTAGE_DIGITAL_CORE,
+ OV5640_VOLTAGE_DIGITAL_CORE);
+ ret = regulator_enable(core_regulator);
+ if (ret) {
+ pr_err("%s:core set voltage error\n", __func__);
+ return ret;
+ } else {
+ dev_dbg(dev,
+ "%s:core set voltage ok\n", __func__);
+ }
+ } else {
+ core_regulator = NULL;
+ pr_err("%s: cannot get core voltage error\n", __func__);
+ }
+
+ analog_regulator = devm_regulator_get(dev, "AVDD");
+ if (!IS_ERR(analog_regulator)) {
+ regulator_set_voltage(analog_regulator,
+ OV5640_VOLTAGE_ANALOG,
+ OV5640_VOLTAGE_ANALOG);
+ ret = regulator_enable(analog_regulator);
+ if (ret) {
+ pr_err("%s:analog set voltage error\n",
+ __func__);
+ return ret;
+ } else {
+ dev_dbg(dev,
+ "%s:analog set voltage ok\n", __func__);
+ }
+ } else {
+ analog_regulator = NULL;
+ pr_err("%s: cannot get analog voltage error\n", __func__);
+ }
+
+ return ret;
+}
+
+static s32 ov5640_write_reg(u16 reg, u8 val)
+{
+ u8 au8Buf[3] = {0};
+
+ au8Buf[0] = reg >> 8;
+ au8Buf[1] = reg & 0xff;
+ au8Buf[2] = val;
+
+ if (i2c_master_send(ov5640_data.i2c_client, au8Buf, 3) < 0) {
+ pr_err("%s:write reg error:reg=%x,val=%x\n",
+ __func__, reg, val);
+ return -1;
+ }
+
+ return 0;
+}
+
+static s32 ov5640_read_reg(u16 reg, u8 *val)
+{
+ u8 au8RegBuf[2] = {0};
+ u8 u8RdVal = 0;
+
+ au8RegBuf[0] = reg >> 8;
+ au8RegBuf[1] = reg & 0xff;
+
+ if (2 != i2c_master_send(ov5640_data.i2c_client, au8RegBuf, 2)) {
+ pr_err("%s:write reg error:reg=%x\n",
+ __func__, reg);
+ return -1;
+ }
+
+ if (1 != i2c_master_recv(ov5640_data.i2c_client, &u8RdVal, 1)) {
+ pr_err("%s:read reg error:reg=%x,val=%x\n",
+ __func__, reg, u8RdVal);
+ return -1;
+ }
+
+ *val = u8RdVal;
+
+ return u8RdVal;
+}
+
+static int prev_sysclk, prev_HTS;
+static int AE_low, AE_high, AE_Target = 52;
+
+static void OV5640_stream_on(void)
+{
+ ov5640_write_reg(0x4202, 0x00);
+}
+
+static void OV5640_stream_off(void)
+{
+ ov5640_write_reg(0x4202, 0x0f);
+}
+
+
+static int OV5640_get_sysclk(void)
+{
+ /* calculate sysclk */
+ int xvclk = ov5640_data.mclk / 10000;
+ int temp1, temp2;
+ int Multiplier, PreDiv, VCO, SysDiv, Pll_rdiv;
+ int Bit_div2x = 1, sclk_rdiv, sysclk;
+ u8 temp;
+
+ int sclk_rdiv_map[] = {1, 2, 4, 8};
+
+ temp1 = ov5640_read_reg(0x3034, &temp);
+ temp2 = temp1 & 0x0f;
+ if (temp2 == 8 || temp2 == 10)
+ Bit_div2x = temp2 / 2;
+
+ temp1 = ov5640_read_reg(0x3035, &temp);
+ SysDiv = temp1>>4;
+ if (SysDiv == 0)
+ SysDiv = 16;
+
+ temp1 = ov5640_read_reg(0x3036, &temp);
+ Multiplier = temp1;
+
+ temp1 = ov5640_read_reg(0x3037, &temp);
+ PreDiv = temp1 & 0x0f;
+ Pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
+
+ temp1 = ov5640_read_reg(0x3108, &temp);
+ temp2 = temp1 & 0x03;
+ sclk_rdiv = sclk_rdiv_map[temp2];
+
+ VCO = xvclk * Multiplier / PreDiv;
+
+ sysclk = VCO / SysDiv / Pll_rdiv * 2 / Bit_div2x / sclk_rdiv;
+
+ return sysclk;
+}
+
+static void OV5640_set_night_mode(void)
+{
+ /* read HTS from register settings */
+ u8 mode;
+
+ ov5640_read_reg(0x3a00, &mode);
+ mode &= 0xfb;
+ ov5640_write_reg(0x3a00, mode);
+}
+
+static int OV5640_get_HTS(void)
+{
+ /* read HTS from register settings */
+ int HTS;
+ u8 temp;
+
+ HTS = ov5640_read_reg(0x380c, &temp);
+ HTS = (HTS<<8) + ov5640_read_reg(0x380d, &temp);
+
+ return HTS;
+}
+
+static int OV5640_get_VTS(void)
+{
+ /* read VTS from register settings */
+ int VTS;
+ u8 temp;
+
+ /* total vertical size[15:8] high byte */
+ VTS = ov5640_read_reg(0x380e, &temp);
+
+ VTS = (VTS<<8) + ov5640_read_reg(0x380f, &temp);
+
+ return VTS;
+}
+
+static int OV5640_set_VTS(int VTS)
+{
+ /* write VTS to registers */
+ int temp;
+
+ temp = VTS & 0xff;
+ ov5640_write_reg(0x380f, temp);
+
+ temp = VTS>>8;
+ ov5640_write_reg(0x380e, temp);
+
+ return 0;
+}
+
+static int OV5640_get_shutter(void)
+{
+ /* read shutter, in number of line period */
+ int shutter;
+ u8 temp;
+
+ shutter = (ov5640_read_reg(0x03500, &temp) & 0x0f);
+ shutter = (shutter<<8) + ov5640_read_reg(0x3501, &temp);
+ shutter = (shutter<<4) + (ov5640_read_reg(0x3502, &temp)>>4);
+
+ return shutter;
+}
+
+static int OV5640_set_shutter(int shutter)
+{
+ /* write shutter, in number of line period */
+ int temp;
+
+ shutter = shutter & 0xffff;
+
+ temp = shutter & 0x0f;
+ temp = temp<<4;
+ ov5640_write_reg(0x3502, temp);
+
+ temp = shutter & 0xfff;
+ temp = temp>>4;
+ ov5640_write_reg(0x3501, temp);
+
+ temp = shutter>>12;
+ ov5640_write_reg(0x3500, temp);
+
+ return 0;
+}
+
+static int OV5640_get_gain16(void)
+{
+ /* read gain, 16 = 1x */
+ int gain16;
+ u8 temp;
+
+ gain16 = ov5640_read_reg(0x350a, &temp) & 0x03;
+ gain16 = (gain16<<8) + ov5640_read_reg(0x350b, &temp);
+
+ return gain16;
+}
+
+static int OV5640_set_gain16(int gain16)
+{
+ /* write gain, 16 = 1x */
+ u8 temp;
+ gain16 = gain16 & 0x3ff;
+
+ temp = gain16 & 0xff;
+ ov5640_write_reg(0x350b, temp);
+
+ temp = gain16>>8;
+ ov5640_write_reg(0x350a, temp);
+
+ return 0;
+}
+
+static int OV5640_get_light_freq(void)
+{
+ /* get banding filter value */
+ int temp, temp1, light_freq = 0;
+ u8 tmp;
+
+ temp = ov5640_read_reg(0x3c01, &tmp);
+
+ if (temp & 0x80) {
+ /* manual */
+ temp1 = ov5640_read_reg(0x3c00, &tmp);
+ if (temp1 & 0x04) {
+ /* 50Hz */
+ light_freq = 50;
+ } else {
+ /* 60Hz */
+ light_freq = 60;
+ }
+ } else {
+ /* auto */
+ temp1 = ov5640_read_reg(0x3c0c, &tmp);
+ if (temp1 & 0x01) {
+ /* 50Hz */
+ light_freq = 50;
+ } else {
+ /* 60Hz */
+ }
+ }
+ return light_freq;
+}
+
+static void OV5640_set_bandingfilter(void)
+{
+ int prev_VTS;
+ int band_step60, max_band60, band_step50, max_band50;
+
+ /* read preview PCLK */
+ prev_sysclk = OV5640_get_sysclk();
+ /* read preview HTS */
+ prev_HTS = OV5640_get_HTS();
+
+ /* read preview VTS */
+ prev_VTS = OV5640_get_VTS();
+
+ /* calculate banding filter */
+ /* 60Hz */
+ band_step60 = prev_sysclk * 100/prev_HTS * 100/120;
+ ov5640_write_reg(0x3a0a, (band_step60 >> 8));
+ ov5640_write_reg(0x3a0b, (band_step60 & 0xff));
+
+ max_band60 = (int)((prev_VTS-4)/band_step60);
+ ov5640_write_reg(0x3a0d, max_band60);
+
+ /* 50Hz */
+ band_step50 = prev_sysclk * 100/prev_HTS;
+ ov5640_write_reg(0x3a08, (band_step50 >> 8));
+ ov5640_write_reg(0x3a09, (band_step50 & 0xff));
+
+ max_band50 = (int)((prev_VTS-4)/band_step50);
+ ov5640_write_reg(0x3a0e, max_band50);
+}
+
+static int OV5640_set_AE_target(int target)
+{
+ /* stable in high */
+ int fast_high, fast_low;
+ AE_low = target * 23 / 25; /* 0.92 */
+ AE_high = target * 27 / 25; /* 1.08 */
+
+ fast_high = AE_high<<1;
+ if (fast_high > 255)
+ fast_high = 255;
+
+ fast_low = AE_low >> 1;
+
+ ov5640_write_reg(0x3a0f, AE_high);
+ ov5640_write_reg(0x3a10, AE_low);
+ ov5640_write_reg(0x3a1b, AE_high);
+ ov5640_write_reg(0x3a1e, AE_low);
+ ov5640_write_reg(0x3a11, fast_high);
+ ov5640_write_reg(0x3a1f, fast_low);
+
+ return 0;
+}
+
+static void OV5640_turn_on_AE_AG(int enable)
+{
+ u8 ae_ag_ctrl;
+
+ ov5640_read_reg(0x3503, &ae_ag_ctrl);
+ if (enable) {
+ /* turn on auto AE/AG */
+ ae_ag_ctrl = ae_ag_ctrl & ~(0x03);
+ } else {
+ /* turn off AE/AG */
+ ae_ag_ctrl = ae_ag_ctrl | 0x03;
+ }
+ ov5640_write_reg(0x3503, ae_ag_ctrl);
+}
+
+static bool binning_on(void)
+{
+ u8 temp;
+ ov5640_read_reg(0x3821, &temp);
+ temp &= 0xfe;
+ if (temp)
+ return true;
+ else
+ return false;
+}
+
+static void ov5640_set_virtual_channel(int channel)
+{
+ u8 channel_id;
+
+ ov5640_read_reg(0x4814, &channel_id);
+ channel_id &= ~(3 << 6);
+ ov5640_write_reg(0x4814, channel_id | (channel << 6));
+}
+
+/* download ov5640 settings to sensor through i2c */
+static int ov5640_download_firmware(struct reg_value *pModeSetting, s32 ArySize)
+{
+ register u32 Delay_ms = 0;
+ register u16 RegAddr = 0;
+ register u8 Mask = 0;
+ register u8 Val = 0;
+ u8 RegVal = 0;
+ int i, retval = 0;
+
+ for (i = 0; i < ArySize; ++i, ++pModeSetting) {
+ Delay_ms = pModeSetting->u32Delay_ms;
+ RegAddr = pModeSetting->u16RegAddr;
+ Val = pModeSetting->u8Val;
+ Mask = pModeSetting->u8Mask;
+
+ if (Mask) {
+ retval = ov5640_read_reg(RegAddr, &RegVal);
+ if (retval < 0)
+ goto err;
+
+ RegVal &= ~(u8)Mask;
+ Val &= Mask;
+ Val |= RegVal;
+ }
+
+ retval = ov5640_write_reg(RegAddr, Val);
+ if (retval < 0)
+ goto err;
+
+ if (Delay_ms)
+ msleep(Delay_ms);
+ }
+err:
+ return retval;
+}
+
+/* sensor changes between scaling and subsampling
+ * go through exposure calcualtion
+ */
+static int ov5640_change_mode_exposure_calc(enum ov5640_frame_rate frame_rate,
+ enum ov5640_mode mode)
+{
+ struct reg_value *pModeSetting = NULL;
+ s32 ArySize = 0;
+ u8 average;
+ int prev_shutter, prev_gain16;
+ int cap_shutter, cap_gain16;
+ int cap_sysclk, cap_HTS, cap_VTS;
+ int light_freq, cap_bandfilt, cap_maxband;
+ long cap_gain16_shutter;
+ int retval = 0;
+
+ /* check if the input mode and frame rate is valid */
+ pModeSetting =
+ ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+ ArySize =
+ ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+ ov5640_data.pix.width =
+ ov5640_mode_info_data[frame_rate][mode].width;
+ ov5640_data.pix.height =
+ ov5640_mode_info_data[frame_rate][mode].height;
+
+ if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 ||
+ pModeSetting == NULL || ArySize == 0)
+ return -EINVAL;
+
+ /* auto focus */
+ /* OV5640_auto_focus();//if no af function, just skip it */
+
+ /* turn off AE/AG */
+ OV5640_turn_on_AE_AG(0);
+
+ /* read preview shutter */
+ prev_shutter = OV5640_get_shutter();
+ if ((binning_on()) && (mode != ov5640_mode_720P_1280_720)
+ && (mode != ov5640_mode_1080P_1920_1080))
+ prev_shutter *= 2;
+
+ /* read preview gain */
+ prev_gain16 = OV5640_get_gain16();
+
+ /* get average */
+ ov5640_read_reg(0x56a1, &average);
+
+ /* turn off night mode for capture */
+ OV5640_set_night_mode();
+
+ /* turn off overlay */
+ /* ov5640_write_reg(0x3022, 0x06);//if no af function, just skip it */
+
+ OV5640_stream_off();
+
+ /* Write capture setting */
+ retval = ov5640_download_firmware(pModeSetting, ArySize);
+ if (retval < 0)
+ goto err;
+
+ /* read capture VTS */
+ cap_VTS = OV5640_get_VTS();
+ cap_HTS = OV5640_get_HTS();
+ cap_sysclk = OV5640_get_sysclk();
+
+ /* calculate capture banding filter */
+ light_freq = OV5640_get_light_freq();
+ if (light_freq == 60) {
+ /* 60Hz */
+ cap_bandfilt = cap_sysclk * 100 / cap_HTS * 100 / 120;
+ } else {
+ /* 50Hz */
+ cap_bandfilt = cap_sysclk * 100 / cap_HTS;
+ }
+ cap_maxband = (int)((cap_VTS - 4)/cap_bandfilt);
+
+ /* calculate capture shutter/gain16 */
+ if (average > AE_low && average < AE_high) {
+ /* in stable range */
+ cap_gain16_shutter =
+ prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk
+ * prev_HTS/cap_HTS * AE_Target / average;
+ } else {
+ cap_gain16_shutter =
+ prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk
+ * prev_HTS/cap_HTS;
+ }
+
+ /* gain to shutter */
+ if (cap_gain16_shutter < (cap_bandfilt * 16)) {
+ /* shutter < 1/100 */
+ cap_shutter = cap_gain16_shutter/16;
+ if (cap_shutter < 1)
+ cap_shutter = 1;
+
+ cap_gain16 = cap_gain16_shutter/cap_shutter;
+ if (cap_gain16 < 16)
+ cap_gain16 = 16;
+ } else {
+ if (cap_gain16_shutter >
+ (cap_bandfilt * cap_maxband * 16)) {
+ /* exposure reach max */
+ cap_shutter = cap_bandfilt * cap_maxband;
+ cap_gain16 = cap_gain16_shutter / cap_shutter;
+ } else {
+ /* 1/100 < (cap_shutter = n/100) =< max */
+ cap_shutter =
+ ((int) (cap_gain16_shutter/16 / cap_bandfilt))
+ *cap_bandfilt;
+ cap_gain16 = cap_gain16_shutter / cap_shutter;
+ }
+ }
+
+ /* write capture gain */
+ OV5640_set_gain16(cap_gain16);
+
+ /* write capture shutter */
+ if (cap_shutter > (cap_VTS - 4)) {
+ cap_VTS = cap_shutter + 4;
+ OV5640_set_VTS(cap_VTS);
+ }
+ OV5640_set_shutter(cap_shutter);
+
+ OV5640_stream_on();
+
+err:
+ return retval;
+}
+
+/* if sensor changes inside scaling or subsampling
+ * change mode directly
+ * */
+static int ov5640_change_mode_direct(enum ov5640_frame_rate frame_rate,
+ enum ov5640_mode mode)
+{
+ struct reg_value *pModeSetting = NULL;
+ s32 ArySize = 0;
+ int retval = 0;
+
+ /* check if the input mode and frame rate is valid */
+ pModeSetting =
+ ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+ ArySize =
+ ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+ ov5640_data.pix.width =
+ ov5640_mode_info_data[frame_rate][mode].width;
+ ov5640_data.pix.height =
+ ov5640_mode_info_data[frame_rate][mode].height;
+
+ if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 ||
+ pModeSetting == NULL || ArySize == 0)
+ return -EINVAL;
+
+ /* turn off AE/AG */
+ OV5640_turn_on_AE_AG(0);
+
+ OV5640_stream_off();
+
+ /* Write capture setting */
+ retval = ov5640_download_firmware(pModeSetting, ArySize);
+ if (retval < 0)
+ goto err;
+
+ OV5640_stream_on();
+
+ OV5640_turn_on_AE_AG(1);
+
+err:
+ return retval;
+}
+
+static int ov5640_init_mode(enum ov5640_frame_rate frame_rate,
+ enum ov5640_mode mode, enum ov5640_mode orig_mode)
+{
+ struct reg_value *pModeSetting = NULL;
+ s32 ArySize = 0;
+ int retval = 0;
+ void *mipi_csi2_info;
+ u32 mipi_reg, msec_wait4stable = 0;
+ enum ov5640_downsize_mode dn_mode, orig_dn_mode;
+
+ if ((mode > ov5640_mode_MAX || mode < ov5640_mode_MIN)
+ && (mode != ov5640_mode_INIT)) {
+ pr_err("Wrong ov5640 mode detected!\n");
+ return -1;
+ }
+
+ mipi_csi2_info = mipi_csi2_get_info();
+
+ /* initial mipi dphy */
+ if (!mipi_csi2_info) {
+ printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
+ __func__, __FILE__);
+ return -1;
+ }
+
+ if (!mipi_csi2_get_status(mipi_csi2_info))
+ mipi_csi2_enable(mipi_csi2_info);
+
+ if (!mipi_csi2_get_status(mipi_csi2_info)) {
+ pr_err("Can not enable mipi csi2 driver!\n");
+ return -1;
+ }
+
+ mipi_csi2_set_lanes(mipi_csi2_info);
+
+ /*Only reset MIPI CSI2 HW at sensor initialize*/
+ if (mode == ov5640_mode_INIT)
+ mipi_csi2_reset(mipi_csi2_info);
+
+ if (ov5640_data.pix.pixelformat == V4L2_PIX_FMT_UYVY)
+ mipi_csi2_set_datatype(mipi_csi2_info, MIPI_DT_YUV422);
+ else if (ov5640_data.pix.pixelformat == V4L2_PIX_FMT_RGB565)
+ mipi_csi2_set_datatype(mipi_csi2_info, MIPI_DT_RGB565);
+ else
+ pr_err("currently this sensor format can not be supported!\n");
+
+ dn_mode = ov5640_mode_info_data[frame_rate][mode].dn_mode;
+ orig_dn_mode = ov5640_mode_info_data[frame_rate][orig_mode].dn_mode;
+ if (mode == ov5640_mode_INIT) {
+ pModeSetting = ov5640_init_setting_30fps_VGA;
+ ArySize = ARRAY_SIZE(ov5640_init_setting_30fps_VGA);
+
+ ov5640_data.pix.width = 640;
+ ov5640_data.pix.height = 480;
+ retval = ov5640_download_firmware(pModeSetting, ArySize);
+ if (retval < 0)
+ goto err;
+
+ pModeSetting = ov5640_setting_30fps_VGA_640_480;
+ ArySize = ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480);
+ retval = ov5640_download_firmware(pModeSetting, ArySize);
+ } else if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
+ (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
+ /* change between subsampling and scaling
+ * go through exposure calucation */
+ retval = ov5640_change_mode_exposure_calc(frame_rate, mode);
+ } else {
+ /* change inside subsampling or scaling
+ * download firmware directly */
+ retval = ov5640_change_mode_direct(frame_rate, mode);
+ }
+
+ if (retval < 0)
+ goto err;
+
+ OV5640_set_AE_target(AE_Target);
+ OV5640_get_light_freq();
+ OV5640_set_bandingfilter();
+ ov5640_set_virtual_channel(ov5640_data.csi);
+
+ /* add delay to wait for sensor stable */
+ if (mode == ov5640_mode_QSXGA_2592_1944) {
+ /* dump the first two frames: 1/7.5*2
+ * the frame rate of QSXGA is 7.5fps */
+ msec_wait4stable = 267;
+ } else if (frame_rate == ov5640_15_fps) {
+ /* dump the first nine frames: 1/15*9 */
+ msec_wait4stable = 600;
+ } else if (frame_rate == ov5640_30_fps) {
+ /* dump the first nine frames: 1/30*9 */
+ msec_wait4stable = 300;
+ }
+ msleep(msec_wait4stable);
+
+ if (mipi_csi2_info) {
+ unsigned int i;
+
+ i = 0;
+
+ /* wait for mipi sensor ready */
+ mipi_reg = mipi_csi2_dphy_status(mipi_csi2_info);
+ while ((mipi_reg == 0x200) && (i < 10)) {
+ mipi_reg = mipi_csi2_dphy_status(mipi_csi2_info);
+ i++;
+ msleep(10);
+ }
+
+ if (i >= 10) {
+ pr_err("mipi csi2 can not receive sensor clk!\n");
+ return -1;
+ }
+
+ i = 0;
+
+ /* wait for mipi stable */
+ mipi_reg = mipi_csi2_get_error1(mipi_csi2_info);
+ while ((mipi_reg != 0x0) && (i < 10)) {
+ mipi_reg = mipi_csi2_get_error1(mipi_csi2_info);
+ i++;
+ msleep(10);
+ }
+
+ if (i >= 10) {
+ pr_err("mipi csi2 can not reveive data correctly!\n");
+ return -1;
+ }
+ }
+err:
+ return retval;
+}
+
+/* --------------- IOCTL functions from v4l2_int_ioctl_desc --------------- */
+
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+ if (s == NULL) {
+ pr_err(" ERROR!! no slave device set!\n");
+ return -1;
+ }
+
+ memset(p, 0, sizeof(*p));
+ p->u.bt656.clock_curr = ov5640_data.mclk;
+ pr_debug(" clock_curr=mclk=%d\n", ov5640_data.mclk);
+ p->if_type = V4L2_IF_TYPE_BT656;
+ p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT;
+ p->u.bt656.clock_min = OV5640_XCLK_MIN;
+ p->u.bt656.clock_max = OV5640_XCLK_MAX;
+ p->u.bt656.bt_sync_correct = 1; /* Indicate external vsync */
+
+ return 0;
+}
+
+/*!
+ * ioctl_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @on: indicates power mode (on or off)
+ *
+ * Turns the power on or off, depending on the value of on and returns the
+ * appropriate error code.
+ */
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
+{
+ struct sensor_data *sensor = s->priv;
+
+ if (on && !sensor->on) {
+ if (io_regulator)
+ if (regulator_enable(io_regulator) != 0)
+ return -EIO;
+ if (core_regulator)
+ if (regulator_enable(core_regulator) != 0)
+ return -EIO;
+ if (gpo_regulator)
+ if (regulator_enable(gpo_regulator) != 0)
+ return -EIO;
+ if (analog_regulator)
+ if (regulator_enable(analog_regulator) != 0)
+ return -EIO;
+ /* Make sure power on */
+ ov5640_standby(0);
+ } else if (!on && sensor->on) {
+ if (analog_regulator)
+ regulator_disable(analog_regulator);
+ if (core_regulator)
+ regulator_disable(core_regulator);
+ if (io_regulator)
+ regulator_disable(io_regulator);
+ if (gpo_regulator)
+ regulator_disable(gpo_regulator);
+
+ ov5640_standby(1);
+ }
+
+ sensor->on = on;
+
+ return 0;
+}
+
+/*!
+ * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+ struct sensor_data *sensor = s->priv;
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+ int ret = 0;
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cparm->capability = sensor->streamcap.capability;
+ cparm->timeperframe = sensor->streamcap.timeperframe;
+ cparm->capturemode = sensor->streamcap.capturemode;
+ ret = 0;
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ ret = -EINVAL;
+ break;
+
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible. If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ */
+static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+ struct sensor_data *sensor = s->priv;
+ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+ u32 tgt_fps; /* target frames per secound */
+ enum ov5640_frame_rate frame_rate;
+ enum ov5640_mode orig_mode;
+ int ret = 0;
+
+ /* Make sure power on */
+ ov5640_standby(0);
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ /* Check that the new frame rate is allowed. */
+ if ((timeperframe->numerator == 0) ||
+ (timeperframe->denominator == 0)) {
+ timeperframe->denominator = DEFAULT_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps > MAX_FPS) {
+ timeperframe->denominator = MAX_FPS;
+ timeperframe->numerator = 1;
+ } else if (tgt_fps < MIN_FPS) {
+ timeperframe->denominator = MIN_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ /* Actual frame rate we use */
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps == 15)
+ frame_rate = ov5640_15_fps;
+ else if (tgt_fps == 30)
+ frame_rate = ov5640_30_fps;
+ else {
+ pr_err(" The camera frame rate is not supported!\n");
+ return -EINVAL;
+ }
+
+ orig_mode = sensor->streamcap.capturemode;
+ ret = ov5640_init_mode(frame_rate,
+ (u32)a->parm.capture.capturemode, orig_mode);
+ if (ret < 0)
+ return ret;
+
+ sensor->streamcap.timeperframe = *timeperframe;
+ sensor->streamcap.capturemode =
+ (u32)a->parm.capture.capturemode;
+
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ pr_debug(" type is not " \
+ "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n",
+ a->type);
+ ret = -EINVAL;
+ break;
+
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 v4l2_format structure
+ *
+ * Returns the sensor's current pixel format in the v4l2_format
+ * parameter.
+ */
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+{
+ struct sensor_data *sensor = s->priv;
+
+ f->fmt.pix = sensor->pix;
+
+ return 0;
+}
+
+/*!
+ * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure
+ *
+ * If the requested control is supported, returns the control's current
+ * value from the video_control[] array. Otherwise, returns -EINVAL
+ * if the control is not supported.
+ */
+static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
+{
+ int ret = 0;
+
+ switch (vc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ vc->value = ov5640_data.brightness;
+ break;
+ case V4L2_CID_HUE:
+ vc->value = ov5640_data.hue;
+ break;
+ case V4L2_CID_CONTRAST:
+ vc->value = ov5640_data.contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ vc->value = ov5640_data.saturation;
+ break;
+ case V4L2_CID_RED_BALANCE:
+ vc->value = ov5640_data.red;
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ vc->value = ov5640_data.blue;
+ break;
+ case V4L2_CID_EXPOSURE:
+ vc->value = ov5640_data.ae_mode;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+/*!
+ * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure
+ *
+ * If the requested control is supported, sets the control's current
+ * value in HW (and updates the video_control[] array). Otherwise,
+ * returns -EINVAL if the control is not supported.
+ */
+static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
+{
+ int retval = 0;
+
+ pr_debug("In ov5640:ioctl_s_ctrl %d\n",
+ vc->id);
+
+ switch (vc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ break;
+ case V4L2_CID_CONTRAST:
+ break;
+ case V4L2_CID_SATURATION:
+ break;
+ case V4L2_CID_HUE:
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ break;
+ case V4L2_CID_DO_WHITE_BALANCE:
+ break;
+ case V4L2_CID_RED_BALANCE:
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ break;
+ case V4L2_CID_GAMMA:
+ break;
+ case V4L2_CID_EXPOSURE:
+ break;
+ case V4L2_CID_AUTOGAIN:
+ break;
+ case V4L2_CID_GAIN:
+ break;
+ case V4L2_CID_HFLIP:
+ break;
+ case V4L2_CID_VFLIP:
+ break;
+ default:
+ retval = -EPERM;
+ break;
+ }
+
+ return retval;
+}
+
+/*!
+ * ioctl_enum_framesizes - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ioctl_enum_framesizes(struct v4l2_int_device *s,
+ struct v4l2_frmsizeenum *fsize)
+{
+ if (fsize->index > ov5640_mode_MAX)
+ return -EINVAL;
+
+ fsize->pixel_format = ov5640_data.pix.pixelformat;
+ fsize->discrete.width =
+ max(ov5640_mode_info_data[0][fsize->index].width,
+ ov5640_mode_info_data[1][fsize->index].width);
+ fsize->discrete.height =
+ max(ov5640_mode_info_data[0][fsize->index].height,
+ ov5640_mode_info_data[1][fsize->index].height);
+ return 0;
+}
+
+/*!
+ * ioctl_enum_frameintervals - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMEINTERVALS ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ioctl_enum_frameintervals(struct v4l2_int_device *s,
+ struct v4l2_frmivalenum *fival)
+{
+ int i, j, count = 0;
+
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->discrete.numerator = 1;
+
+ for (i = 0; i < ARRAY_SIZE(ov5640_mode_info_data); i++)
+ for (j = 0; j < (ov5640_mode_MAX + 1); j++)
+ if (fival->pixel_format == ov5640_data.pix.pixelformat
+ && fival->width == ov5640_mode_info_data[i][j].width
+ && fival->height == ov5640_mode_info_data[i][j].height
+ && ov5640_mode_info_data[i][j].init_data_ptr != NULL
+ && fival->index == count++) {
+ fival->discrete.denominator =
+ ov5640_framerates[i];
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/*!
+ * ioctl_g_chip_ident - V4L2 sensor interface handler for
+ * VIDIOC_DBG_G_CHIP_IDENT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @id: pointer to int
+ *
+ * Return 0.
+ */
+static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id)
+{
+ ((struct v4l2_dbg_chip_ident *)id)->match.type =
+ V4L2_CHIP_MATCH_I2C_DRIVER;
+ strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name,
+ "ov5640_mipi_camera");
+
+ return 0;
+}
+
+/*!
+ * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT
+ * @s: pointer to standard V4L2 device structure
+ */
+static int ioctl_init(struct v4l2_int_device *s)
+{
+
+ return 0;
+}
+
+/*!
+ * ioctl_enum_fmt_cap - V4L2 sensor interface handler for VIDIOC_ENUM_FMT
+ * @s: pointer to standard V4L2 device structure
+ * @fmt: pointer to standard V4L2 fmt description structure
+ *
+ * Return 0.
+ */
+static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_fmtdesc *fmt)
+{
+ if (fmt->index > ov5640_mode_MAX)
+ return -EINVAL;
+
+ fmt->pixelformat = ov5640_data.pix.pixelformat;
+
+ return 0;
+}
+
+/*!
+ * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialise the device when slave attaches to the master.
+ */
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+ struct sensor_data *sensor = s->priv;
+ u32 tgt_xclk; /* target xclk */
+ u32 tgt_fps; /* target frames per secound */
+ int ret;
+ enum ov5640_frame_rate frame_rate;
+ void *mipi_csi2_info;
+
+ ov5640_data.on = true;
+
+ /* mclk */
+ tgt_xclk = ov5640_data.mclk;
+ tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX);
+ tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN);
+ ov5640_data.mclk = tgt_xclk;
+
+ pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000);
+
+ /* Default camera frame rate is set in probe */
+ tgt_fps = sensor->streamcap.timeperframe.denominator /
+ sensor->streamcap.timeperframe.numerator;
+
+ if (tgt_fps == 15)
+ frame_rate = ov5640_15_fps;
+ else if (tgt_fps == 30)
+ frame_rate = ov5640_30_fps;
+ else
+ return -EINVAL; /* Only support 15fps or 30fps now. */
+
+ mipi_csi2_info = mipi_csi2_get_info();
+
+ /* enable mipi csi2 */
+ if (mipi_csi2_info)
+ mipi_csi2_enable(mipi_csi2_info);
+ else {
+ printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n",
+ __func__, __FILE__);
+ return -EPERM;
+ }
+
+ ret = ov5640_init_mode(frame_rate, ov5640_mode_INIT, ov5640_mode_INIT);
+
+ return ret;
+}
+
+/*!
+ * ioctl_dev_exit - V4L2 sensor interface handler for vidioc_int_dev_exit_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Delinitialise the device when slave detaches to the master.
+ */
+static int ioctl_dev_exit(struct v4l2_int_device *s)
+{
+ void *mipi_csi2_info;
+
+ mipi_csi2_info = mipi_csi2_get_info();
+
+ /* disable mipi csi2 */
+ if (mipi_csi2_info)
+ if (mipi_csi2_get_status(mipi_csi2_info))
+ mipi_csi2_disable(mipi_csi2_info);
+
+ return 0;
+}
+
+/*!
+ * This structure defines all the ioctls for this module and links them to the
+ * enumeration.
+ */
+static struct v4l2_int_ioctl_desc ov5640_ioctl_desc[] = {
+ {vidioc_int_dev_init_num, (v4l2_int_ioctl_func *) ioctl_dev_init},
+ {vidioc_int_dev_exit_num, ioctl_dev_exit},
+ {vidioc_int_s_power_num, (v4l2_int_ioctl_func *) ioctl_s_power},
+ {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func *) ioctl_g_ifparm},
+/* {vidioc_int_g_needs_reset_num,
+ (v4l2_int_ioctl_func *)ioctl_g_needs_reset}, */
+/* {vidioc_int_reset_num, (v4l2_int_ioctl_func *)ioctl_reset}, */
+ {vidioc_int_init_num, (v4l2_int_ioctl_func *) ioctl_init},
+ {vidioc_int_enum_fmt_cap_num,
+ (v4l2_int_ioctl_func *) ioctl_enum_fmt_cap},
+/* {vidioc_int_try_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_try_fmt_cap}, */
+ {vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func *) ioctl_g_fmt_cap},
+/* {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *) ioctl_s_fmt_cap}, */
+ {vidioc_int_g_parm_num, (v4l2_int_ioctl_func *) ioctl_g_parm},
+ {vidioc_int_s_parm_num, (v4l2_int_ioctl_func *) ioctl_s_parm},
+/* {vidioc_int_queryctrl_num, (v4l2_int_ioctl_func *)ioctl_queryctrl}, */
+ {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func *) ioctl_g_ctrl},
+ {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *) ioctl_s_ctrl},
+ {vidioc_int_enum_framesizes_num,
+ (v4l2_int_ioctl_func *) ioctl_enum_framesizes},
+ {vidioc_int_enum_frameintervals_num,
+ (v4l2_int_ioctl_func *) ioctl_enum_frameintervals},
+ {vidioc_int_g_chip_ident_num,
+ (v4l2_int_ioctl_func *) ioctl_g_chip_ident},
+};
+
+static struct v4l2_int_slave ov5640_slave = {
+ .ioctls = ov5640_ioctl_desc,
+ .num_ioctls = ARRAY_SIZE(ov5640_ioctl_desc),
+};
+
+static struct v4l2_int_device ov5640_int_device = {
+ .module = THIS_MODULE,
+ .name = "ov564x",
+ .type = v4l2_int_type_slave,
+ .u = {
+ .slave = &ov5640_slave,
+ },
+};
+
+/*!
+ * ov5640 I2C probe function
+ *
+ * @param adapter struct i2c_adapter *
+ * @return Error code indicating success or failure
+ */
+static int ov5640_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ int retval;
+ u8 chip_id_high, chip_id_low;
+
+ /* request power down pin */
+ pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+ if (!gpio_is_valid(pwn_gpio)) {
+ dev_warn(dev, "no sensor pwdn pin available");
+ return -EINVAL;
+ }
+ retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH,
+ "ov5640_mipi_pwdn");
+ if (retval < 0)
+ return retval;
+
+ /* request reset pin */
+ rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0);
+ if (!gpio_is_valid(rst_gpio)) {
+ dev_warn(dev, "no sensor reset pin available");
+ return -EINVAL;
+ }
+ retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH,
+ "ov5640_mipi_reset");
+ if (retval < 0)
+ return retval;
+
+ /* Set initial values for the sensor struct. */
+ memset(&ov5640_data, 0, sizeof(ov5640_data));
+ ov5640_data.sensor_clk = devm_clk_get(dev, "csi_mclk");
+ if (IS_ERR(ov5640_data.sensor_clk)) {
+ /* assuming clock enabled by default */
+ ov5640_data.sensor_clk = NULL;
+ dev_err(dev, "clock-frequency missing or invalid\n");
+ return PTR_ERR(ov5640_data.sensor_clk);
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk",
+ &(ov5640_data.mclk));
+ if (retval) {
+ dev_err(dev, "mclk missing or invalid\n");
+ return retval;
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk_source",
+ (u32 *) &(ov5640_data.mclk_source));
+ if (retval) {
+ dev_err(dev, "mclk_source missing or invalid\n");
+ return retval;
+ }
+
+ retval = of_property_read_u32(dev->of_node, "csi_id",
+ &(ov5640_data.csi));
+ if (retval) {
+ dev_err(dev, "csi id missing or invalid\n");
+ return retval;
+ }
+
+ clk_prepare_enable(ov5640_data.sensor_clk);
+
+ ov5640_data.io_init = ov5640_reset;
+ ov5640_data.i2c_client = client;
+ ov5640_data.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+ ov5640_data.pix.width = 640;
+ ov5640_data.pix.height = 480;
+ ov5640_data.streamcap.capability = V4L2_MODE_HIGHQUALITY |
+ V4L2_CAP_TIMEPERFRAME;
+ ov5640_data.streamcap.capturemode = 0;
+ ov5640_data.streamcap.timeperframe.denominator = DEFAULT_FPS;
+ ov5640_data.streamcap.timeperframe.numerator = 1;
+
+ ov5640_power_on(dev);
+
+ ov5640_reset();
+
+ ov5640_standby(0);
+
+ retval = ov5640_read_reg(OV5640_CHIP_ID_HIGH_BYTE, &chip_id_high);
+ if (retval < 0 || chip_id_high != 0x56) {
+ pr_warning("camera ov5640_mipi is not found\n");
+ clk_disable_unprepare(ov5640_data.sensor_clk);
+ return -ENODEV;
+ }
+ retval = ov5640_read_reg(OV5640_CHIP_ID_LOW_BYTE, &chip_id_low);
+ if (retval < 0 || chip_id_low != 0x40) {
+ pr_warning("camera ov5640_mipi is not found\n");
+ clk_disable_unprepare(ov5640_data.sensor_clk);
+ return -ENODEV;
+ }
+
+ ov5640_standby(1);
+
+ ov5640_int_device.priv = &ov5640_data;
+ retval = v4l2_int_device_register(&ov5640_int_device);
+
+ clk_disable_unprepare(ov5640_data.sensor_clk);
+
+ pr_info("camera ov5640_mipi is found\n");
+ return retval;
+}
+
+/*!
+ * ov5640 I2C detach function
+ *
+ * @param client struct i2c_client *
+ * @return Error code indicating success or failure
+ */
+static int ov5640_remove(struct i2c_client *client)
+{
+ v4l2_int_device_unregister(&ov5640_int_device);
+
+ if (gpo_regulator)
+ regulator_disable(gpo_regulator);
+
+ if (analog_regulator)
+ regulator_disable(analog_regulator);
+
+ if (core_regulator)
+ regulator_disable(core_regulator);
+
+ if (io_regulator)
+ regulator_disable(io_regulator);
+
+ return 0;
+}
+
+/*!
+ * ov5640 init function
+ * Called by insmod ov5640_camera.ko.
+ *
+ * @return Error code indicating success or failure
+ */
+static __init int ov5640_init(void)
+{
+ u8 err;
+
+ err = i2c_add_driver(&ov5640_i2c_driver);
+ if (err != 0)
+ pr_err("%s:driver registration failed, error=%d\n",
+ __func__, err);
+
+ return err;
+}
+
+/*!
+ * OV5640 cleanup function
+ * Called on rmmod ov5640_camera.ko
+ *
+ * @return Error code indicating success or failure
+ */
+static void __exit ov5640_clean(void)
+{
+ i2c_del_driver(&ov5640_i2c_driver);
+}
+
+module_init(ov5640_init);
+module_exit(ov5640_clean);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("OV5640 MIPI Camera Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("CSI");
diff --git a/drivers/media/platform/mxc/capture/ov5640_mipi_v2.c b/drivers/media/platform/mxc/capture/ov5640_mipi_v2.c
new file mode 100644
index 000000000000..9e89d42608aa
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/ov5640_mipi_v2.c
@@ -0,0 +1,1788 @@
+/*
+ * Copyright (C) 2011-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/i2c.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#define OV5640_VOLTAGE_ANALOG 2800000
+#define OV5640_VOLTAGE_DIGITAL_CORE 1500000
+#define OV5640_VOLTAGE_DIGITAL_IO 1800000
+
+#define MIN_FPS 15
+#define MAX_FPS 30
+#define DEFAULT_FPS 30
+
+#define OV5640_XCLK_MIN 6000000
+#define OV5640_XCLK_MAX 24000000
+#define OV5640_XCLK_20MHZ 20000000
+
+#define OV5640_CHIP_ID_HIGH_BYTE 0x300A
+#define OV5640_CHIP_ID_LOW_BYTE 0x300B
+
+#define DEFAULT_SCCB_ID 0x78
+
+enum ov5640_mode {
+ ov5640_mode_MIN = 0,
+ ov5640_mode_VGA_640_480 = 0,
+ ov5640_mode_NTSC_720_480 = 1,
+ ov5640_mode_720P_1280_720 = 2,
+ ov5640_mode_1080P_1920_1080 = 3,
+ ov5640_mode_QSXGA_2592_1944 = 4,
+ ov5640_mode_MAX = 5,
+ ov5640_mode_INIT = 0xff, /*only for sensor init*/
+};
+
+enum ov5640_frame_rate {
+ ov5640_15_fps,
+ ov5640_30_fps
+};
+
+static int ov5640_framerates[] = {
+ [ov5640_15_fps] = 15,
+ [ov5640_30_fps] = 30,
+};
+
+struct ov5640_datafmt {
+ u32 code;
+ enum v4l2_colorspace colorspace;
+};
+
+/* image size under 1280 * 960 are SUBSAMPLING
+ * image size upper 1280 * 960 are SCALING
+ */
+enum ov5640_downsize_mode {
+ SUBSAMPLING,
+ SCALING,
+};
+
+struct reg_value {
+ u16 u16RegAddr;
+ u8 u8Val;
+ u8 u8Mask;
+ u32 u32Delay_ms;
+};
+
+struct ov5640_mode_info {
+ enum ov5640_mode mode;
+ enum ov5640_downsize_mode dn_mode;
+ u32 width;
+ u32 height;
+ struct reg_value *init_data_ptr;
+ u32 init_data_size;
+};
+
+struct ov5640 {
+ struct v4l2_subdev subdev;
+ struct i2c_client *i2c_client;
+ struct v4l2_pix_format pix;
+ const struct ov5640_datafmt *fmt;
+ struct v4l2_captureparm streamcap;
+ bool on;
+
+ /* control settings */
+ int brightness;
+ int hue;
+ int contrast;
+ int saturation;
+ int red;
+ int green;
+ int blue;
+ int ae_mode;
+
+ u32 mclk;
+ u8 mclk_source;
+ struct clk *sensor_clk;
+ int csi;
+
+ void (*io_init)(struct ov5640 *);
+ int pwn_gpio, rst_gpio;
+};
+
+struct ov5640_res {
+ int width;
+ int height;
+};
+
+/*!
+ * Maintains the information on the current state of the sesor.
+ */
+
+
+struct ov5640_res ov5640_valid_res[] = {
+ [0] = {640, 480},
+ [1] = {720, 480},
+ [2] = {1280, 720},
+ [3] = {1920, 1080},
+ [4] = {2592, 1944},
+};
+
+static struct reg_value ov5640_init_setting_30fps_VGA[] = {
+
+ {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
+ {0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0},
+ {0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0},
+ {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0},
+ {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
+ {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
+ {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
+ {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
+ {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
+ {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
+ {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
+ {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
+ {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
+ {0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
+ {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
+ {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x300e, 0x45, 0, 0}, {0x302e, 0x08, 0, 0}, {0x4300, 0x30, 0, 0},
+ {0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0},
+ {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x4837, 0x0a, 0, 0}, {0x4800, 0x04, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
+ {0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
+ {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
+ {0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
+ {0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
+ {0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
+ {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
+ {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
+ {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
+ {0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
+ {0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
+ {0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
+ {0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
+ {0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
+ {0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
+ {0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
+ {0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
+ {0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
+ {0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
+ {0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
+ {0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
+ {0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
+ {0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
+ {0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
+ {0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
+ {0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
+ {0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
+ {0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
+ {0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
+ {0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
+ {0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
+ {0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
+ {0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
+ {0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
+ {0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
+ {0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
+ {0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
+ {0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
+ {0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
+ {0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
+ {0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
+ {0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
+ {0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
+ {0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
+ {0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
+ {0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
+ {0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
+ {0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
+ {0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
+ {0x3a1f, 0x14, 0, 0}, {0x3008, 0x42, 0, 0}, {0x3c00, 0x04, 0, 300},
+};
+
+static struct reg_value ov5640_setting_30fps_VGA_640_480[] = {
+ {0x3008, 0x42, 0, 0},
+ {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+ {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_NTSC_720_480[] = {
+ {0x3008, 0x42, 0, 0},
+ {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0},
+ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
+ {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_720P_1280_720[] = {
+ {0x3008, 0x42, 0, 0},
+ {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
+ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+ {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0},
+ {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
+ {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
+ {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
+ {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, {0x4005, 0x1a, 0, 0},
+ {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = {
+ {0x3008, 0x42, 0, 0},
+ {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0},
+ {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
+ {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0},
+ {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+ {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
+ {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x11, 0, 0},
+ {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
+ {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
+ {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0},
+ {0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0},
+ {0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
+ {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
+ {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
+ {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0},
+ {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
+ {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0},
+ {0x3503, 0, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = {
+ {0x3008, 0x42, 0, 0},
+ {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, /*disable flip*/
+ {0x3035, 0x11, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0},
+ {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
+ {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0},
+ {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+ {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
+ {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, {0x3008, 0x02, 0, 0},
+};
+
+static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = {
+ {
+ {ov5640_mode_VGA_640_480, -1, 0, 0, NULL, 0},
+ {ov5640_mode_NTSC_720_480, -1, 0, 0, NULL, 0},
+ {ov5640_mode_720P_1280_720, -1, 0, 0, NULL, 0},
+ {ov5640_mode_1080P_1920_1080, -1, 0, 0, NULL, 0},
+ {ov5640_mode_QSXGA_2592_1944, SCALING, 2592, 1944,
+ ov5640_setting_15fps_QSXGA_2592_1944,
+ ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)},
+ },
+ {
+ {ov5640_mode_VGA_640_480, SUBSAMPLING, 640, 480,
+ ov5640_setting_30fps_VGA_640_480,
+ ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)},
+ {ov5640_mode_NTSC_720_480, SUBSAMPLING, 720, 480,
+ ov5640_setting_30fps_NTSC_720_480,
+ ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)},
+ {ov5640_mode_720P_1280_720, SUBSAMPLING, 1280, 720,
+ ov5640_setting_30fps_720P_1280_720,
+ ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)},
+ {ov5640_mode_1080P_1920_1080, SCALING, 1920, 1080,
+ ov5640_setting_30fps_1080P_1920_1080,
+ ARRAY_SIZE(ov5640_setting_30fps_1080P_1920_1080)},
+ {ov5640_mode_QSXGA_2592_1944, -1, 0, 0, NULL, 0},
+ },
+};
+
+static struct regulator *io_regulator;
+static struct regulator *core_regulator;
+static struct regulator *analog_regulator;
+static struct regulator *gpo_regulator;
+static DEFINE_MUTEX(ov5640_mutex);
+
+static int ov5640_probe(struct i2c_client *adapter,
+ const struct i2c_device_id *device_id);
+static int ov5640_remove(struct i2c_client *client);
+
+static s32 ov5640_read_reg(struct ov5640 *sensor, u16 reg, u8 *val);
+static s32 ov5640_write_reg(struct ov5640 *sensor, u16 reg, u8 val);
+
+static const struct i2c_device_id ov5640_id[] = {
+ {"ov5640_mipi", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, ov5640_id);
+
+static struct i2c_driver ov5640_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ov5640_mipi",
+ },
+ .probe = ov5640_probe,
+ .remove = ov5640_remove,
+ .id_table = ov5640_id,
+};
+
+static const struct ov5640_datafmt ov5640_colour_fmts[] = {
+ {MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+};
+
+static int get_capturemode(int width, int height)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ov5640_valid_res); i++) {
+ if ((ov5640_valid_res[i].width == width) &&
+ (ov5640_valid_res[i].height == height))
+ return i;
+ }
+
+ return -1;
+}
+
+static struct ov5640 *to_ov5640(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct ov5640, subdev);
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct ov5640_datafmt
+ *ov5640_find_datafmt(u32 code)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ov5640_colour_fmts); i++)
+ if (ov5640_colour_fmts[i].code == code)
+ return ov5640_colour_fmts + i;
+
+ return NULL;
+}
+
+static inline void ov5640_power_down(struct ov5640 *sensor, int enable)
+{
+ if (sensor->pwn_gpio < 0)
+ return;
+
+ if (!enable)
+ gpio_set_value_cansleep(sensor->pwn_gpio, 0);
+ else
+ gpio_set_value_cansleep(sensor->pwn_gpio, 1);
+
+ msleep(2);
+}
+
+static int ov5640_update_slave_id(struct ov5640 *sensor)
+{
+ struct device *dev = &sensor->i2c_client->dev;
+ u8 slave_id;
+ struct i2c_client *tmp_client;
+ s32 retval;
+
+ if (sensor->i2c_client->addr << 1 == DEFAULT_SCCB_ID)
+ return 0; /* nothing to do */
+
+ /* Change camera i2c slave address */
+ slave_id = (u8)(sensor->i2c_client->addr << 1); /* new slave id*/
+ tmp_client = sensor->i2c_client;
+
+ sensor->i2c_client =
+ i2c_new_dummy(tmp_client->adapter, DEFAULT_SCCB_ID >> 1);
+ if (!sensor->i2c_client) {
+ dev_err(dev, "Failed to communicate on 0x%x\n",
+ DEFAULT_SCCB_ID);
+ return -1;
+ }
+
+ retval = ov5640_write_reg(sensor, 0x3100, slave_id);
+ i2c_unregister_device(sensor->i2c_client);
+ sensor->i2c_client = tmp_client;
+ if (retval != 0) {
+ dev_err(dev, "Failed to update SCCB_ID to 0x%x\n", slave_id);
+ return -1;
+ }
+
+ ov5640_read_reg(sensor, 0x3100, &slave_id);
+ dev_dbg(dev, "Updated SCCB_ID 0x%x\n", slave_id);
+
+ return 0;
+}
+
+static void ov5640_reset(struct ov5640 *sensor)
+{
+ if (sensor->rst_gpio < 0 || sensor->pwn_gpio < 0)
+ return;
+
+ /* camera reset */
+ gpio_set_value(sensor->rst_gpio, 1);
+
+ /* camera power dowmn */
+ gpio_set_value(sensor->pwn_gpio, 1);
+ msleep(5);
+
+ gpio_set_value(sensor->rst_gpio, 0);
+ msleep(1);
+
+ gpio_set_value(sensor->pwn_gpio, 0);
+ msleep(5);
+
+ gpio_set_value(sensor->rst_gpio, 1);
+ msleep(5);
+}
+
+static int ov5640_regulator_enable(struct device *dev)
+{
+ int ret = 0;
+
+ io_regulator = devm_regulator_get(dev, "DOVDD");
+ if (!IS_ERR(io_regulator)) {
+ regulator_set_voltage(io_regulator,
+ OV5640_VOLTAGE_DIGITAL_IO,
+ OV5640_VOLTAGE_DIGITAL_IO);
+ ret = regulator_enable(io_regulator);
+ if (ret) {
+ pr_err("%s:io set voltage error\n", __func__);
+ return ret;
+ } else {
+ dev_dbg(dev,
+ "%s:io set voltage ok\n", __func__);
+ }
+ } else {
+ pr_err("%s: cannot get io voltage error\n", __func__);
+ io_regulator = NULL;
+ }
+
+ core_regulator = devm_regulator_get(dev, "DVDD");
+ if (!IS_ERR(core_regulator)) {
+ regulator_set_voltage(core_regulator,
+ OV5640_VOLTAGE_DIGITAL_CORE,
+ OV5640_VOLTAGE_DIGITAL_CORE);
+ ret = regulator_enable(core_regulator);
+ if (ret) {
+ pr_err("%s:core set voltage error\n", __func__);
+ return ret;
+ } else {
+ dev_dbg(dev,
+ "%s:core set voltage ok\n", __func__);
+ }
+ } else {
+ core_regulator = NULL;
+ pr_err("%s: cannot get core voltage error\n", __func__);
+ }
+
+ analog_regulator = devm_regulator_get(dev, "AVDD");
+ if (!IS_ERR(analog_regulator)) {
+ regulator_set_voltage(analog_regulator,
+ OV5640_VOLTAGE_ANALOG,
+ OV5640_VOLTAGE_ANALOG);
+ ret = regulator_enable(analog_regulator);
+ if (ret) {
+ pr_err("%s:analog set voltage error\n",
+ __func__);
+ return ret;
+ } else {
+ dev_dbg(dev,
+ "%s:analog set voltage ok\n", __func__);
+ }
+ } else {
+ analog_regulator = NULL;
+ pr_err("%s: cannot get analog voltage error\n", __func__);
+ }
+
+ return ret;
+}
+
+static s32 ov5640_write_reg(struct ov5640 *sensor, u16 reg, u8 val)
+{
+ struct device *dev = &sensor->i2c_client->dev;
+ u8 au8Buf[3] = {0};
+
+ au8Buf[0] = reg >> 8;
+ au8Buf[1] = reg & 0xff;
+ au8Buf[2] = val;
+
+ if (i2c_master_send(sensor->i2c_client, au8Buf, 3) < 0) {
+ dev_err(dev, "Write reg error: reg=%x, val=%x\n", reg, val);
+ return -1;
+ }
+
+ return 0;
+}
+
+static s32 ov5640_read_reg(struct ov5640 *sensor, u16 reg, u8 *val)
+{
+ struct device *dev = &sensor->i2c_client->dev;
+ u8 au8RegBuf[2] = {0};
+ u8 u8RdVal = 0;
+
+ au8RegBuf[0] = reg >> 8;
+ au8RegBuf[1] = reg & 0xff;
+
+ if (i2c_master_send(sensor->i2c_client, au8RegBuf, 2) != 2) {
+ dev_err(dev, "Read reg error: reg=%x\n", reg);
+ return -1;
+ }
+
+ if (i2c_master_recv(sensor->i2c_client, &u8RdVal, 1) != 1) {
+ dev_err(dev, "Read reg error: reg=%x, val=%x\n", reg, u8RdVal);
+ return -1;
+ }
+
+ *val = u8RdVal;
+
+ return u8RdVal;
+}
+
+static int prev_sysclk, prev_HTS;
+static int AE_low, AE_high, AE_Target = 52;
+
+static void OV5640_stream_on(struct ov5640 *sensor)
+{
+ ov5640_write_reg(sensor, 0x4202, 0x00);
+}
+
+static void OV5640_stream_off(struct ov5640 *sensor)
+{
+ ov5640_write_reg(sensor, 0x4202, 0x0f);
+ ov5640_write_reg(sensor, 0x3008, 0x42);
+}
+
+static int OV5640_get_sysclk(struct ov5640 *sensor)
+{
+ /* calculate sysclk */
+ int xvclk = sensor->mclk / 10000;
+ int temp1, temp2;
+ int Multiplier, PreDiv, VCO, SysDiv, Pll_rdiv;
+ int Bit_div2x = 1, sclk_rdiv, sysclk;
+ u8 temp;
+
+ int sclk_rdiv_map[] = {1, 2, 4, 8};
+
+ temp1 = ov5640_read_reg(sensor, 0x3034, &temp);
+ temp2 = temp1 & 0x0f;
+ if (temp2 == 8 || temp2 == 10)
+ Bit_div2x = temp2 / 2;
+
+ temp1 = ov5640_read_reg(sensor, 0x3035, &temp);
+ SysDiv = temp1>>4;
+ if (SysDiv == 0)
+ SysDiv = 16;
+
+ temp1 = ov5640_read_reg(sensor, 0x3036, &temp);
+ Multiplier = temp1;
+
+ temp1 = ov5640_read_reg(sensor, 0x3037, &temp);
+ PreDiv = temp1 & 0x0f;
+ Pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
+
+ temp1 = ov5640_read_reg(sensor, 0x3108, &temp);
+ temp2 = temp1 & 0x03;
+ sclk_rdiv = sclk_rdiv_map[temp2];
+
+ VCO = xvclk * Multiplier / PreDiv;
+
+ sysclk = VCO / SysDiv / Pll_rdiv * 2 / Bit_div2x / sclk_rdiv;
+
+ return sysclk;
+}
+
+static void OV5640_set_night_mode(struct ov5640 *sensor)
+{
+ /* read HTS from register settings */
+ u8 mode;
+
+ ov5640_read_reg(sensor, 0x3a00, &mode);
+ mode &= 0xfb;
+ ov5640_write_reg(sensor, 0x3a00, mode);
+}
+
+static int OV5640_get_HTS(struct ov5640 *sensor)
+{
+ /* read HTS from register settings */
+ int HTS;
+ u8 temp;
+
+ HTS = ov5640_read_reg(sensor, 0x380c, &temp);
+ HTS = (HTS<<8) + ov5640_read_reg(sensor, 0x380d, &temp);
+
+ return HTS;
+}
+
+static int OV5640_get_VTS(struct ov5640 *sensor)
+{
+ /* read VTS from register settings */
+ int VTS;
+ u8 temp;
+
+ /* total vertical size[15:8] high byte */
+ VTS = ov5640_read_reg(sensor, 0x380e, &temp);
+
+ VTS = (VTS<<8) + ov5640_read_reg(sensor, 0x380f, &temp);
+
+ return VTS;
+}
+
+static int OV5640_set_VTS(struct ov5640 *sensor, int VTS)
+{
+ /* write VTS to registers */
+ int temp;
+
+ temp = VTS & 0xff;
+ ov5640_write_reg(sensor, 0x380f, temp);
+
+ temp = VTS>>8;
+ ov5640_write_reg(sensor, 0x380e, temp);
+
+ return 0;
+}
+
+static int OV5640_get_shutter(struct ov5640 *sensor)
+{
+ /* read shutter, in number of line period */
+ int shutter;
+ u8 temp;
+
+ shutter = (ov5640_read_reg(sensor, 0x03500, &temp) & 0x0f);
+ shutter = (shutter<<8) + ov5640_read_reg(sensor, 0x3501, &temp);
+ shutter = (shutter<<4) + (ov5640_read_reg(sensor, 0x3502, &temp)>>4);
+
+ return shutter;
+}
+
+static int OV5640_set_shutter(struct ov5640 *sensor, int shutter)
+{
+ /* write shutter, in number of line period */
+ int temp;
+
+ shutter = shutter & 0xffff;
+
+ temp = shutter & 0x0f;
+ temp = temp<<4;
+ ov5640_write_reg(sensor, 0x3502, temp);
+
+ temp = shutter & 0xfff;
+ temp = temp>>4;
+ ov5640_write_reg(sensor, 0x3501, temp);
+
+ temp = shutter>>12;
+ ov5640_write_reg(sensor, 0x3500, temp);
+
+ return 0;
+}
+
+
+static int OV5640_get_gain16(struct ov5640 *sensor)
+{
+ /* read gain, 16 = 1x */
+ int gain16;
+ u8 temp;
+
+ gain16 = ov5640_read_reg(sensor, 0x350a, &temp) & 0x03;
+ gain16 = (gain16<<8) + ov5640_read_reg(sensor, 0x350b, &temp);
+
+ return gain16;
+}
+
+static int OV5640_set_gain16(struct ov5640 *sensor, int gain16)
+{
+ /* write gain, 16 = 1x */
+ u8 temp;
+ gain16 = gain16 & 0x3ff;
+
+ temp = gain16 & 0xff;
+ ov5640_write_reg(sensor, 0x350b, temp);
+
+ temp = gain16>>8;
+ ov5640_write_reg(sensor, 0x350a, temp);
+
+ return 0;
+}
+
+static int OV5640_get_light_freq(struct ov5640 *sensor)
+{
+ /* get banding filter value */
+ int temp, temp1, light_freq = 0;
+ u8 tmp;
+
+ temp = ov5640_read_reg(sensor, 0x3c01, &tmp);
+
+ if (temp & 0x80) {
+ /* manual */
+ temp1 = ov5640_read_reg(sensor, 0x3c00, &tmp);
+ if (temp1 & 0x04) {
+ /* 50Hz */
+ light_freq = 50;
+ } else {
+ /* 60Hz */
+ light_freq = 60;
+ }
+ } else {
+ /* auto */
+ temp1 = ov5640_read_reg(sensor, 0x3c0c, &tmp);
+ if (temp1 & 0x01) {
+ /* 50Hz */
+ light_freq = 50;
+ } else {
+ /* 60Hz */
+ }
+ }
+ return light_freq;
+}
+
+static void OV5640_set_bandingfilter(struct ov5640 *sensor)
+{
+ int prev_VTS;
+ int band_step60, max_band60, band_step50, max_band50;
+
+ /* read preview PCLK */
+ prev_sysclk = OV5640_get_sysclk(sensor);
+ /* read preview HTS */
+ prev_HTS = OV5640_get_HTS(sensor);
+
+ /* read preview VTS */
+ prev_VTS = OV5640_get_VTS(sensor);
+
+ /* calculate banding filter */
+ /* 60Hz */
+ band_step60 = prev_sysclk * 100/prev_HTS * 100/120;
+ ov5640_write_reg(sensor, 0x3a0a, (band_step60 >> 8));
+ ov5640_write_reg(sensor, 0x3a0b, (band_step60 & 0xff));
+
+ max_band60 = (int)((prev_VTS-4)/band_step60);
+ ov5640_write_reg(sensor, 0x3a0d, max_band60);
+
+ /* 50Hz */
+ band_step50 = prev_sysclk * 100/prev_HTS;
+ ov5640_write_reg(sensor, 0x3a08, (band_step50 >> 8));
+ ov5640_write_reg(sensor, 0x3a09, (band_step50 & 0xff));
+
+ max_band50 = (int)((prev_VTS-4)/band_step50);
+ ov5640_write_reg(sensor, 0x3a0e, max_band50);
+}
+
+static int OV5640_set_AE_target(struct ov5640 *sensor, int target)
+{
+ /* stable in high */
+ int fast_high, fast_low;
+ AE_low = target * 23 / 25; /* 0.92 */
+ AE_high = target * 27 / 25; /* 1.08 */
+
+ fast_high = AE_high<<1;
+ if (fast_high > 255)
+ fast_high = 255;
+
+ fast_low = AE_low >> 1;
+
+ ov5640_write_reg(sensor, 0x3a0f, AE_high);
+ ov5640_write_reg(sensor, 0x3a10, AE_low);
+ ov5640_write_reg(sensor, 0x3a1b, AE_high);
+ ov5640_write_reg(sensor, 0x3a1e, AE_low);
+ ov5640_write_reg(sensor, 0x3a11, fast_high);
+ ov5640_write_reg(sensor, 0x3a1f, fast_low);
+
+ return 0;
+}
+
+static void OV5640_turn_on_AE_AG(struct ov5640 *sensor, int enable)
+{
+ u8 ae_ag_ctrl;
+
+ ov5640_read_reg(sensor, 0x3503, &ae_ag_ctrl);
+ if (enable) {
+ /* turn on auto AE/AG */
+ ae_ag_ctrl = ae_ag_ctrl & ~(0x03);
+ } else {
+ /* turn off AE/AG */
+ ae_ag_ctrl = ae_ag_ctrl | 0x03;
+ }
+ ov5640_write_reg(sensor, 0x3503, ae_ag_ctrl);
+}
+
+static bool binning_on(struct ov5640 *sensor)
+{
+ u8 temp;
+ ov5640_read_reg(sensor, 0x3821, &temp);
+ temp &= 0xfe;
+ if (temp)
+ return true;
+ else
+ return false;
+}
+
+static void ov5640_set_virtual_channel(struct ov5640 *sensor, int channel)
+{
+ u8 channel_id;
+
+ ov5640_read_reg(sensor, 0x4814, &channel_id);
+ channel_id &= ~(3 << 6);
+ ov5640_write_reg(sensor, 0x4814, channel_id | (channel << 6));
+}
+
+/* download ov5640 settings to sensor through i2c */
+static int ov5640_download_firmware(struct ov5640 *sensor,
+ struct reg_value *pModeSetting,
+ s32 ArySize)
+{
+ register u32 Delay_ms = 0;
+ register u16 RegAddr = 0;
+ register u8 Mask = 0;
+ register u8 Val = 0;
+ u8 RegVal = 0;
+ int i, retval = 0;
+
+ for (i = 0; i < ArySize; ++i, ++pModeSetting) {
+ Delay_ms = pModeSetting->u32Delay_ms;
+ RegAddr = pModeSetting->u16RegAddr;
+ Val = pModeSetting->u8Val;
+ Mask = pModeSetting->u8Mask;
+
+ if (Mask) {
+ retval = ov5640_read_reg(sensor, RegAddr, &RegVal);
+ if (retval < 0)
+ goto err;
+
+ RegVal &= ~(u8)Mask;
+ Val &= Mask;
+ Val |= RegVal;
+ }
+
+ retval = ov5640_write_reg(sensor, RegAddr, Val);
+ if (retval < 0)
+ goto err;
+
+ if (Delay_ms)
+ msleep(Delay_ms);
+ }
+err:
+ return retval;
+}
+
+/* sensor changes between scaling and subsampling
+ * go through exposure calcualtion
+ */
+static int ov5640_change_mode_exposure_calc(struct ov5640 *sensor,
+ enum ov5640_frame_rate frame_rate,
+ enum ov5640_mode mode)
+{
+ struct reg_value *pModeSetting = NULL;
+ s32 ArySize = 0;
+ u8 average;
+ int prev_shutter, prev_gain16;
+ int cap_shutter, cap_gain16;
+ int cap_sysclk, cap_HTS, cap_VTS;
+ int light_freq, cap_bandfilt, cap_maxband;
+ long cap_gain16_shutter;
+ int retval = 0;
+
+ /* check if the input mode and frame rate is valid */
+ pModeSetting =
+ ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+ ArySize =
+ ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+ sensor->pix.width =
+ ov5640_mode_info_data[frame_rate][mode].width;
+ sensor->pix.height =
+ ov5640_mode_info_data[frame_rate][mode].height;
+
+ if (sensor->pix.width == 0 || sensor->pix.height == 0 ||
+ pModeSetting == NULL || ArySize == 0)
+ return -EINVAL;
+
+ /* auto focus */
+ /* OV5640_auto_focus();//if no af function, just skip it */
+
+ /* turn off AE/AG */
+ OV5640_turn_on_AE_AG(sensor, 0);
+
+ /* read preview shutter */
+ prev_shutter = OV5640_get_shutter(sensor);
+ if ((binning_on(sensor)) && (mode != ov5640_mode_720P_1280_720)
+ && (mode != ov5640_mode_1080P_1920_1080))
+ prev_shutter *= 2;
+
+ /* read preview gain */
+ prev_gain16 = OV5640_get_gain16(sensor);
+
+ /* get average */
+ ov5640_read_reg(sensor, 0x56a1, &average);
+
+ /* turn off night mode for capture */
+ OV5640_set_night_mode(sensor);
+
+ /* turn off overlay */
+ /* ov5640_write_reg(0x3022, 0x06);//if no af function, just skip it */
+
+ OV5640_stream_off(sensor);
+
+ /* Write capture setting */
+ retval = ov5640_download_firmware(sensor, pModeSetting, ArySize);
+ if (retval < 0)
+ goto err;
+
+ /* read capture VTS */
+ cap_VTS = OV5640_get_VTS(sensor);
+ cap_HTS = OV5640_get_HTS(sensor);
+ cap_sysclk = OV5640_get_sysclk(sensor);
+
+ /* calculate capture banding filter */
+ light_freq = OV5640_get_light_freq(sensor);
+ if (light_freq == 60) {
+ /* 60Hz */
+ cap_bandfilt = cap_sysclk * 100 / cap_HTS * 100 / 120;
+ } else {
+ /* 50Hz */
+ cap_bandfilt = cap_sysclk * 100 / cap_HTS;
+ }
+ cap_maxband = (int)((cap_VTS - 4)/cap_bandfilt);
+
+ /* calculate capture shutter/gain16 */
+ if (average > AE_low && average < AE_high) {
+ /* in stable range */
+ cap_gain16_shutter =
+ prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk
+ * prev_HTS/cap_HTS * AE_Target / average;
+ } else {
+ cap_gain16_shutter =
+ prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk
+ * prev_HTS/cap_HTS;
+ }
+
+ /* gain to shutter */
+ if (cap_gain16_shutter < (cap_bandfilt * 16)) {
+ /* shutter < 1/100 */
+ cap_shutter = cap_gain16_shutter/16;
+ if (cap_shutter < 1)
+ cap_shutter = 1;
+
+ cap_gain16 = cap_gain16_shutter/cap_shutter;
+ if (cap_gain16 < 16)
+ cap_gain16 = 16;
+ } else {
+ if (cap_gain16_shutter >
+ (cap_bandfilt * cap_maxband * 16)) {
+ /* exposure reach max */
+ cap_shutter = cap_bandfilt * cap_maxband;
+ cap_gain16 = cap_gain16_shutter / cap_shutter;
+ } else {
+ /* 1/100 < (cap_shutter = n/100) =< max */
+ cap_shutter =
+ ((int) (cap_gain16_shutter/16 / cap_bandfilt))
+ *cap_bandfilt;
+ cap_gain16 = cap_gain16_shutter / cap_shutter;
+ }
+ }
+
+ /* write capture gain */
+ OV5640_set_gain16(sensor, cap_gain16);
+
+ /* write capture shutter */
+ if (cap_shutter > (cap_VTS - 4)) {
+ cap_VTS = cap_shutter + 4;
+ OV5640_set_VTS(sensor, cap_VTS);
+ }
+ OV5640_set_shutter(sensor, cap_shutter);
+
+err:
+ return retval;
+}
+
+/* if sensor changes inside scaling or subsampling
+ * change mode directly
+ * */
+static int ov5640_change_mode_direct(struct ov5640 *sensor,
+ enum ov5640_frame_rate frame_rate,
+ enum ov5640_mode mode)
+{
+ struct reg_value *pModeSetting = NULL;
+ s32 ArySize = 0;
+ int retval = 0;
+
+ /* check if the input mode and frame rate is valid */
+ pModeSetting =
+ ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+ ArySize =
+ ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+ sensor->pix.width =
+ ov5640_mode_info_data[frame_rate][mode].width;
+ sensor->pix.height =
+ ov5640_mode_info_data[frame_rate][mode].height;
+
+ if (sensor->pix.width == 0 || sensor->pix.height == 0 ||
+ pModeSetting == NULL || ArySize == 0)
+ return -EINVAL;
+
+ /* turn off AE/AG */
+ OV5640_turn_on_AE_AG(sensor, 0);
+
+ OV5640_stream_off(sensor);
+
+ /* Write capture setting */
+ retval = ov5640_download_firmware(sensor, pModeSetting, ArySize);
+ if (retval < 0)
+ goto err;
+
+ OV5640_turn_on_AE_AG(sensor, 1);
+
+err:
+ return retval;
+}
+
+static int ov5640_init_mode(struct ov5640 *sensor,
+ enum ov5640_frame_rate frame_rate,
+ enum ov5640_mode mode, enum ov5640_mode orig_mode)
+{
+ struct device *dev = &sensor->i2c_client->dev;
+ struct reg_value *pModeSetting = NULL;
+ s32 ArySize = 0;
+ int retval = 0;
+ u32 msec_wait4stable = 0;
+ enum ov5640_downsize_mode dn_mode, orig_dn_mode;
+
+ if ((mode > ov5640_mode_MAX || mode < ov5640_mode_MIN)
+ && (mode != ov5640_mode_INIT)) {
+ dev_err(dev, "Wrong ov5640 mode detected!\n");
+ return -1;
+ }
+
+ dn_mode = ov5640_mode_info_data[frame_rate][mode].dn_mode;
+ orig_dn_mode = ov5640_mode_info_data[frame_rate][orig_mode].dn_mode;
+ if (mode == ov5640_mode_INIT) {
+ pModeSetting = ov5640_init_setting_30fps_VGA;
+ ArySize = ARRAY_SIZE(ov5640_init_setting_30fps_VGA);
+
+ sensor->pix.width = 640;
+ sensor->pix.height = 480;
+ retval = ov5640_download_firmware(sensor, pModeSetting,
+ ArySize);
+ if (retval < 0)
+ goto err;
+
+ pModeSetting = ov5640_setting_30fps_VGA_640_480;
+ ArySize = ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480);
+ retval = ov5640_download_firmware(sensor, pModeSetting,
+ ArySize);
+ } else if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
+ (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
+ /* change between subsampling and scaling
+ * go through exposure calucation */
+ retval = ov5640_change_mode_exposure_calc(sensor,
+ frame_rate, mode);
+ } else {
+ /* change inside subsampling or scaling
+ * download firmware directly */
+ retval = ov5640_change_mode_direct(sensor, frame_rate, mode);
+ }
+
+ if (retval < 0)
+ goto err;
+
+ OV5640_set_AE_target(sensor, AE_Target);
+ OV5640_get_light_freq(sensor);
+ OV5640_set_bandingfilter(sensor);
+ ov5640_set_virtual_channel(sensor, sensor->csi);
+
+ /* add delay to wait for sensor stable */
+ if (mode == ov5640_mode_QSXGA_2592_1944) {
+ /* dump the first two frames: 1/7.5*2
+ * the frame rate of QSXGA is 7.5fps */
+ msec_wait4stable = 267;
+ } else {
+ /* dump the first eighteen frames: 1/30*18 */
+ msec_wait4stable = 600;
+ }
+ msleep(msec_wait4stable);
+
+err:
+ return retval;
+}
+
+/*!
+ * ov5640_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @on: indicates power mode (on or off)
+ *
+ * Turns the power on or off, depending on the value of on and returns the
+ * appropriate error code.
+ */
+static int ov5640_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+
+ if (on && !sensor->on) {
+ if (io_regulator)
+ if (regulator_enable(io_regulator) != 0)
+ return -EIO;
+ if (core_regulator)
+ if (regulator_enable(core_regulator) != 0)
+ return -EIO;
+ if (gpo_regulator)
+ if (regulator_enable(gpo_regulator) != 0)
+ return -EIO;
+ if (analog_regulator)
+ if (regulator_enable(analog_regulator) != 0)
+ return -EIO;
+ } else if (!on && sensor->on) {
+ if (analog_regulator)
+ regulator_disable(analog_regulator);
+ if (core_regulator)
+ regulator_disable(core_regulator);
+ if (io_regulator)
+ regulator_disable(io_regulator);
+ if (gpo_regulator)
+ regulator_disable(gpo_regulator);
+ }
+
+ sensor->on = on;
+
+ return 0;
+}
+
+/*!
+ * ov5640_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 sub device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ov5640_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+ struct device *dev = &sensor->i2c_client->dev;
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+ int ret = 0;
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cparm->capability = sensor->streamcap.capability;
+ cparm->timeperframe = sensor->streamcap.timeperframe;
+ cparm->capturemode = sensor->streamcap.capturemode;
+ ret = 0;
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ ret = -EINVAL;
+ break;
+
+ default:
+ dev_warn(dev, "Type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * ov5460_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 sub device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible. If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ */
+static int ov5640_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+ struct device *dev = &sensor->i2c_client->dev;
+ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+ u32 tgt_fps; /* target frames per secound */
+ enum ov5640_frame_rate frame_rate;
+ enum ov5640_mode orig_mode;
+ int ret = 0;
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ /* Check that the new frame rate is allowed. */
+ if ((timeperframe->numerator == 0) ||
+ (timeperframe->denominator == 0)) {
+ timeperframe->denominator = DEFAULT_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps > MAX_FPS) {
+ timeperframe->denominator = MAX_FPS;
+ timeperframe->numerator = 1;
+ } else if (tgt_fps < MIN_FPS) {
+ timeperframe->denominator = MIN_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ /* Actual frame rate we use */
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps == 15)
+ frame_rate = ov5640_15_fps;
+ else if (tgt_fps == 30)
+ frame_rate = ov5640_30_fps;
+ else {
+ dev_warn(dev,
+ "The camera frame rate is not supported!\n");
+ return -EINVAL;
+ }
+
+ orig_mode = sensor->streamcap.capturemode;
+ ret = ov5640_init_mode(sensor, frame_rate,
+ (u32)a->parm.capture.capturemode, orig_mode);
+ if (ret < 0)
+ return ret;
+
+ sensor->streamcap.timeperframe = *timeperframe;
+ sensor->streamcap.capturemode =
+ (u32)a->parm.capture.capturemode;
+
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ dev_warn(dev, "Type is not V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n",
+ a->type);
+ ret = -EINVAL;
+ break;
+
+ default:
+ dev_warn(dev, "Type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+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;
+ const struct ov5640_datafmt *fmt = ov5640_find_datafmt(mf->code);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+ int capturemode;
+
+ if (!fmt) {
+ mf->code = ov5640_colour_fmts[0].code;
+ mf->colorspace = ov5640_colour_fmts[0].colorspace;
+ }
+
+ mf->field = V4L2_FIELD_NONE;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+ return 0;
+
+ sensor->fmt = fmt;
+
+ capturemode = get_capturemode(mf->width, mf->height);
+ if (capturemode >= 0) {
+ sensor->streamcap.capturemode = capturemode;
+ sensor->pix.width = mf->width;
+ sensor->pix.height = mf->height;
+ return 0;
+ }
+
+ dev_err(&client->dev, "Set format failed %d, %d\n",
+ fmt->code, fmt->colorspace);
+ return -EINVAL;
+}
+
+
+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 *sensor = to_ov5640(client);
+ const struct ov5640_datafmt *fmt = sensor->fmt;
+
+ if (format->pad)
+ return -EINVAL;
+
+ mf->code = fmt->code;
+ mf->colorspace = fmt->colorspace;
+ mf->field = V4L2_FIELD_NONE;
+
+ mf->width = sensor->pix.width;
+ mf->height = sensor->pix.height;
+
+ 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 >= ARRAY_SIZE(ov5640_colour_fmts))
+ return -EINVAL;
+
+ code->code = ov5640_colour_fmts[code->index].code;
+ return 0;
+}
+
+/*!
+ * ov5640_enum_framesizes - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ov5640_enum_framesizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index > ov5640_mode_MAX)
+ return -EINVAL;
+
+ fse->max_width =
+ max(ov5640_mode_info_data[0][fse->index].width,
+ ov5640_mode_info_data[1][fse->index].width);
+ fse->min_width = fse->max_width;
+ fse->max_height =
+ max(ov5640_mode_info_data[0][fse->index].height,
+ ov5640_mode_info_data[1][fse->index].height);
+ fse->min_height = fse->max_height;
+ return 0;
+}
+
+/*!
+ * ov5640_enum_frameintervals - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMEINTERVALS ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ov5640_enum_frameintervals(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct device *dev = &client->dev;
+ int i, j, count = 0;
+
+ if (fie->index < 0 || fie->index > ov5640_mode_MAX)
+ return -EINVAL;
+
+ if (fie->width == 0 || fie->height == 0 ||
+ fie->code == 0) {
+ dev_warn(dev, "Please assign pixel format, width and height\n");
+ return -EINVAL;
+ }
+
+ fie->interval.numerator = 1;
+
+ count = 0;
+ for (i = 0; i < ARRAY_SIZE(ov5640_mode_info_data); i++) {
+ for (j = 0; j < (ov5640_mode_MAX + 1); j++) {
+ if (fie->width == ov5640_mode_info_data[i][j].width
+ && fie->height == ov5640_mode_info_data[i][j].height
+ && ov5640_mode_info_data[i][j].init_data_ptr != NULL) {
+ count++;
+ }
+ if (fie->index == (count - 1)) {
+ fie->interval.denominator =
+ ov5640_framerates[i];
+ return 0;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+/*!
+ * dev_init - V4L2 sensor init
+ * @s: pointer to standard V4L2 device structure
+ *
+ */
+static int init_device(struct ov5640 *sensor)
+{
+ struct device *dev = &sensor->i2c_client->dev;
+ u32 tgt_xclk; /* target xclk */
+ u32 tgt_fps; /* target frames per secound */
+ enum ov5640_frame_rate frame_rate;
+ int ret;
+
+ sensor->on = true;
+
+ /* mclk */
+ tgt_xclk = sensor->mclk;
+ tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX);
+ tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN);
+ sensor->mclk = tgt_xclk;
+
+ dev_dbg(dev, "Setting mclk to %d MHz\n", tgt_xclk / 1000000);
+
+ /* Default camera frame rate is set in probe */
+ tgt_fps = sensor->streamcap.timeperframe.denominator /
+ sensor->streamcap.timeperframe.numerator;
+
+ if (tgt_fps == 15)
+ frame_rate = ov5640_15_fps;
+ else if (tgt_fps == 30)
+ frame_rate = ov5640_30_fps;
+ else
+ return -EINVAL; /* Only support 15fps or 30fps now. */
+
+ ret = ov5640_init_mode(sensor, frame_rate, ov5640_mode_INIT,
+ ov5640_mode_INIT);
+
+ return ret;
+}
+
+static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+ struct device *dev = &sensor->i2c_client->dev;
+
+ dev_info(dev, "s_stream: %d\n", enable);
+ if (enable)
+ OV5640_stream_on(sensor);
+ else
+ OV5640_stream_off(sensor);
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops ov5640_subdev_video_ops = {
+ .g_parm = ov5640_g_parm,
+ .s_parm = ov5640_s_parm,
+ .s_stream = ov5640_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ov5640_subdev_pad_ops = {
+ .enum_frame_size = ov5640_enum_framesizes,
+ .enum_frame_interval = ov5640_enum_frameintervals,
+ .enum_mbus_code = ov5640_enum_mbus_code,
+ .set_fmt = ov5640_set_fmt,
+ .get_fmt = ov5640_get_fmt,
+};
+
+static struct v4l2_subdev_core_ops ov5640_subdev_core_ops = {
+ .s_power = ov5640_s_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ov5640_get_register,
+ .s_register = ov5640_set_register,
+#endif
+};
+
+static struct v4l2_subdev_ops ov5640_subdev_ops = {
+ .core = &ov5640_subdev_core_ops,
+ .video = &ov5640_subdev_video_ops,
+ .pad = &ov5640_subdev_pad_ops,
+};
+
+static void ov5640_adjust_setting_20mhz(void)
+{
+ struct reg_value *regsetting;
+ int i, array_size;
+
+ /* adjust for INIT mode */
+ regsetting = ov5640_init_setting_30fps_VGA;
+ array_size = ARRAY_SIZE(ov5640_init_setting_30fps_VGA);
+
+ for (i = 0; i < array_size; i++, regsetting++)
+ if (regsetting->u16RegAddr == 0x3037)
+ regsetting->u8Val = 0x17;
+}
+
+/*!
+ * ov5640 I2C probe function
+ *
+ * @param adapter struct i2c_adapter *
+ * @return Error code indicating success or failure
+ */
+static int ov5640_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pinctrl *pinctrl;
+ struct device *dev = &client->dev;
+ int retval;
+ u8 chip_id_high, chip_id_low;
+ struct ov5640 *sensor;
+
+ sensor = kmalloc(sizeof(*sensor), GFP_KERNEL);
+ /* Set initial values for the sensor struct. */
+ memset(sensor, 0, sizeof(*sensor));
+
+ /* ov5640 pinctrl */
+ pinctrl = devm_pinctrl_get_select_default(dev);
+ if (IS_ERR(pinctrl))
+ dev_warn(dev, "No pin available\n");
+
+ /* request power down pin */
+ sensor->pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+ if (!gpio_is_valid(sensor->pwn_gpio))
+ dev_warn(dev, "No sensor pwdn pin available");
+ else {
+ retval = devm_gpio_request_one(dev, sensor->pwn_gpio,
+ GPIOF_OUT_INIT_HIGH, "ov5640_mipi_pwdn");
+ if (retval < 0) {
+ dev_warn(dev, "Failed to set power pin\n");
+ dev_warn(dev, "retval=%d\n", retval);
+ return retval;
+ }
+ }
+
+ /* request reset pin */
+ sensor->rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0);
+ if (!gpio_is_valid(sensor->rst_gpio))
+ dev_warn(dev, "No sensor reset pin available");
+ else {
+ retval = devm_gpio_request_one(dev, sensor->rst_gpio,
+ GPIOF_OUT_INIT_HIGH, "ov5640_mipi_reset");
+ if (retval < 0) {
+ dev_warn(dev, "Failed to set reset pin\n");
+ return retval;
+ }
+ }
+
+
+ sensor->sensor_clk = devm_clk_get(dev, "csi_mclk");
+ if (IS_ERR(sensor->sensor_clk)) {
+ /* assuming clock enabled by default */
+ sensor->sensor_clk = NULL;
+ dev_err(dev, "clock-frequency missing or invalid\n");
+ return PTR_ERR(sensor->sensor_clk);
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk",
+ &(sensor->mclk));
+ if (retval) {
+ dev_err(dev, "mclk missing or invalid\n");
+ return retval;
+ }
+
+ if (sensor->mclk == OV5640_XCLK_20MHZ)
+ ov5640_adjust_setting_20mhz();
+
+ retval = of_property_read_u32(dev->of_node, "mclk_source",
+ (u32 *) &(sensor->mclk_source));
+ if (retval) {
+ dev_err(dev, "mclk_source missing or invalid\n");
+ return retval;
+ }
+
+ retval = of_property_read_u32(dev->of_node, "csi_id",
+ &(sensor->csi));
+ if (retval) {
+ dev_err(dev, "csi id missing or invalid\n");
+ return retval;
+ }
+
+ clk_prepare_enable(sensor->sensor_clk);
+
+ sensor->io_init = ov5640_reset;
+ sensor->i2c_client = client;
+ sensor->pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ sensor->pix.width = 640;
+ sensor->pix.height = 480;
+ sensor->streamcap.capability = V4L2_MODE_HIGHQUALITY |
+ V4L2_CAP_TIMEPERFRAME;
+ sensor->streamcap.capturemode = 0;
+ sensor->streamcap.timeperframe.denominator = DEFAULT_FPS;
+ sensor->streamcap.timeperframe.numerator = 1;
+
+ ov5640_regulator_enable(&client->dev);
+
+ mutex_lock(&ov5640_mutex);
+ {
+ ov5640_reset(sensor);
+ ov5640_power_down(sensor, 0);
+ retval = ov5640_update_slave_id(sensor);
+ }
+ mutex_unlock(&ov5640_mutex);
+ if (retval < 0) {
+ clk_disable_unprepare(sensor->sensor_clk);
+ return -ENODEV;
+ }
+
+ retval = ov5640_read_reg(sensor, OV5640_CHIP_ID_HIGH_BYTE,
+ &chip_id_high);
+ if (retval < 0 || chip_id_high != 0x56) {
+ dev_warn(dev, "Camera is not found\n");
+ clk_disable_unprepare(sensor->sensor_clk);
+ return -ENODEV;
+ }
+ retval = ov5640_read_reg(sensor, OV5640_CHIP_ID_LOW_BYTE, &chip_id_low);
+ if (retval < 0 || chip_id_low != 0x40) {
+ dev_warn(dev, "Camera is not found\n");
+ clk_disable_unprepare(sensor->sensor_clk);
+ return -ENODEV;
+ }
+
+
+ retval = init_device(sensor);
+ if (retval < 0) {
+ clk_disable_unprepare(sensor->sensor_clk);
+ dev_warn(dev, "Camera init failed\n");
+ ov5640_power_down(sensor, 1);
+ return retval;
+ }
+
+ v4l2_i2c_subdev_init(&sensor->subdev, client, &ov5640_subdev_ops);
+
+ sensor->subdev.grp_id = 678;
+ retval = v4l2_async_register_subdev(&sensor->subdev);
+ if (retval < 0)
+ dev_err(&client->dev, "Async register failed, ret=%d\n",
+ retval);
+
+ OV5640_stream_off(sensor);
+ dev_info(dev, "Camera is found\n");
+ return retval;
+}
+
+/*!
+ * ov5640 I2C detach function
+ *
+ * @param client struct i2c_client *
+ * @return Error code indicating success or failure
+ */
+static int ov5640_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov5640 *sensor = to_ov5640(client);
+
+ v4l2_async_unregister_subdev(sd);
+
+ clk_disable_unprepare(sensor->sensor_clk);
+
+ ov5640_power_down(sensor, 1);
+
+ if (gpo_regulator)
+ regulator_disable(gpo_regulator);
+
+ if (analog_regulator)
+ regulator_disable(analog_regulator);
+
+ if (core_regulator)
+ regulator_disable(core_regulator);
+
+ if (io_regulator)
+ regulator_disable(io_regulator);
+
+ return 0;
+}
+
+module_i2c_driver(ov5640_i2c_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("OV5640 MIPI Camera Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("CSI");
diff --git a/drivers/media/platform/mxc/capture/ov5640_v2.c b/drivers/media/platform/mxc/capture/ov5640_v2.c
new file mode 100644
index 000000000000..70e2a8321fd0
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/ov5640_v2.c
@@ -0,0 +1,1895 @@
+/*
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#define OV5640_VOLTAGE_ANALOG 2800000
+#define OV5640_VOLTAGE_DIGITAL_CORE 1500000
+#define OV5640_VOLTAGE_DIGITAL_IO 1800000
+
+#define MIN_FPS 15
+#define MAX_FPS 30
+#define DEFAULT_FPS 30
+
+#define OV5640_XCLK_MIN 6000000
+#define OV5640_XCLK_MAX 24000000
+
+#define OV5640_CHIP_ID_HIGH_BYTE 0x300A
+#define OV5640_CHIP_ID_LOW_BYTE 0x300B
+
+enum ov5640_mode {
+ ov5640_mode_MIN = 0,
+ ov5640_mode_VGA_640_480 = 0,
+ ov5640_mode_QVGA_320_240 = 1,
+ ov5640_mode_NTSC_720_480 = 2,
+ ov5640_mode_PAL_720_576 = 3,
+ ov5640_mode_720P_1280_720 = 4,
+ ov5640_mode_1080P_1920_1080 = 5,
+ ov5640_mode_QSXGA_2592_1944 = 6,
+ ov5640_mode_QCIF_176_144 = 7,
+ ov5640_mode_XGA_1024_768 = 8,
+ ov5640_mode_MAX = 8
+};
+
+enum ov5640_frame_rate {
+ ov5640_15_fps,
+ ov5640_30_fps
+};
+
+static int ov5640_framerates[] = {
+ [ov5640_15_fps] = 15,
+ [ov5640_30_fps] = 30,
+};
+
+struct ov5640_datafmt {
+ u32 code;
+ enum v4l2_colorspace colorspace;
+};
+
+struct reg_value {
+ u16 u16RegAddr;
+ u8 u8Val;
+ u8 u8Mask;
+ u32 u32Delay_ms;
+};
+
+struct ov5640_mode_info {
+ enum ov5640_mode mode;
+ u32 width;
+ u32 height;
+ struct reg_value *init_data_ptr;
+ u32 init_data_size;
+};
+
+struct ov5640 {
+ struct v4l2_subdev subdev;
+ struct i2c_client *i2c_client;
+ struct v4l2_pix_format pix;
+ const struct ov5640_datafmt *fmt;
+ struct v4l2_captureparm streamcap;
+ bool on;
+
+ /* control settings */
+ int brightness;
+ int hue;
+ int contrast;
+ int saturation;
+ int red;
+ int green;
+ int blue;
+ int ae_mode;
+
+ u32 mclk;
+ u8 mclk_source;
+ struct clk *sensor_clk;
+ int csi;
+
+ void (*io_init)(void);
+};
+
+/*!
+ * Maintains the information on the current state of the sesor.
+ */
+static struct ov5640 ov5640_data;
+static int pwn_gpio, rst_gpio;
+static int prev_sysclk;
+static int AE_Target = 52, night_mode;
+static int prev_HTS;
+static int AE_high, AE_low;
+
+static struct reg_value ov5640_global_init_setting[] = {
+ {0x3008, 0x42, 0, 0},
+ {0x3103, 0x03, 0, 0}, {0x3017, 0xff, 0, 0}, {0x3018, 0xff, 0, 0},
+ {0x3034, 0x1a, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0},
+ {0x3630, 0x36, 0, 0}, {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0},
+ {0x3633, 0x12, 0, 0}, {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0},
+ {0x3703, 0x5a, 0, 0}, {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0},
+ {0x370b, 0x60, 0, 0}, {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0},
+ {0x3906, 0x10, 0, 0}, {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0},
+ {0x3600, 0x08, 0, 0}, {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0},
+ {0x3620, 0x52, 0, 0}, {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0},
+ {0x3a13, 0x43, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0},
+ {0x3635, 0x13, 0, 0}, {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0},
+ {0x3622, 0x01, 0, 0}, {0x3c01, 0x34, 0, 0}, {0x3c04, 0x28, 0, 0},
+ {0x3c05, 0x98, 0, 0}, {0x3c06, 0x00, 0, 0}, {0x3c07, 0x07, 0, 0},
+ {0x3c08, 0x00, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0},
+ {0x3c0b, 0x40, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0},
+ {0x3812, 0x00, 0, 0}, {0x3708, 0x64, 0, 0}, {0x4001, 0x02, 0, 0},
+ {0x4005, 0x1a, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3004, 0xff, 0, 0},
+ {0x300e, 0x58, 0, 0}, {0x302e, 0x00, 0, 0}, {0x4300, 0x30, 0, 0},
+ {0x501f, 0x00, 0, 0}, {0x440e, 0x00, 0, 0}, {0x5000, 0xa7, 0, 0},
+ {0x3008, 0x02, 0, 0},
+};
+
+static struct reg_value ov5640_init_setting_30fps_VGA[] = {
+ {0x3008, 0x42, 0, 0},
+ {0x3103, 0x03, 0, 0}, {0x3017, 0xff, 0, 0}, {0x3018, 0xff, 0, 0},
+ {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, {0x3036, 0x46, 0, 0},
+ {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0},
+ {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
+ {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
+ {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
+ {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
+ {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
+ {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
+ {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
+ {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
+ {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
+ {0x3c01, 0x34, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
+ {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
+ {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
+ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+ {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
+ {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
+ {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
+ {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x300e, 0x58, 0, 0}, {0x302e, 0x00, 0, 0}, {0x4300, 0x30, 0, 0},
+ {0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0},
+ {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
+ {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5000, 0xa7, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0xf2, 0, 0},
+ {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0},
+ {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, {0x5187, 0x09, 0, 0},
+ {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, {0x518a, 0x54, 0, 0},
+ {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x50, 0, 0},
+ {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, {0x5190, 0x46, 0, 0},
+ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0},
+ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x6c, 0, 0},
+ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x09, 0, 0},
+ {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, {0x5381, 0x1e, 0, 0},
+ {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, {0x5384, 0x0a, 0, 0},
+ {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, {0x5387, 0x7c, 0, 0},
+ {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, {0x538a, 0x01, 0, 0},
+ {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, {0x5301, 0x30, 0, 0},
+ {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, {0x5304, 0x08, 0, 0},
+ {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, {0x5307, 0x16, 0, 0},
+ {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, {0x530b, 0x04, 0, 0},
+ {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, {0x5481, 0x08, 0, 0},
+ {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, {0x5484, 0x51, 0, 0},
+ {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, {0x5487, 0x7d, 0, 0},
+ {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, {0x548a, 0x9a, 0, 0},
+ {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, {0x548d, 0xcd, 0, 0},
+ {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, {0x5490, 0x1d, 0, 0},
+ {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x10, 0, 0},
+ {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, {0x558b, 0xf8, 0, 0},
+ {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, {0x5802, 0x0f, 0, 0},
+ {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, {0x5805, 0x26, 0, 0},
+ {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, {0x5808, 0x05, 0, 0},
+ {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, {0x580b, 0x0d, 0, 0},
+ {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, {0x580e, 0x00, 0, 0},
+ {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, {0x5811, 0x09, 0, 0},
+ {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x00, 0, 0},
+ {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, {0x5817, 0x08, 0, 0},
+ {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, {0x581a, 0x05, 0, 0},
+ {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, {0x581d, 0x0e, 0, 0},
+ {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, {0x5820, 0x11, 0, 0},
+ {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, {0x5823, 0x28, 0, 0},
+ {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, {0x5826, 0x08, 0, 0},
+ {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, {0x5829, 0x26, 0, 0},
+ {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, {0x582c, 0x24, 0, 0},
+ {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, {0x582f, 0x22, 0, 0},
+ {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, {0x5832, 0x24, 0, 0},
+ {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, {0x5835, 0x22, 0, 0},
+ {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, {0x5838, 0x44, 0, 0},
+ {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, {0x583b, 0x28, 0, 0},
+ {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, {0x5025, 0x00, 0, 0},
+ {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, {0x3a1b, 0x30, 0, 0},
+ {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x14, 0, 0},
+ {0x3008, 0x02, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_VGA_640_480[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0},
+ {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_VGA_640_480[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0},
+ {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_QVGA_320_240[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0},
+ {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QVGA_320_240[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0},
+ {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_NTSC_720_480[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0},
+ {0x3807, 0xd4, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0},
+ {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_NTSC_720_480[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0},
+ {0x3807, 0xd4, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0},
+ {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_PAL_720_576[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x60, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x09, 0, 0}, {0x3805, 0x7e, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0},
+ {0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_PAL_720_576[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x60, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x09, 0, 0}, {0x3805, 0x7e, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0},
+ {0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_720P_1280_720[] = {
+ {0x3035, 0x21, 0, 0}, {0x3036, 0x69, 0, 0}, {0x3c07, 0x07, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
+ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+ {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0},
+ {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3813, 0x04, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3709, 0x52, 0, 0},
+ {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe0, 0, 0},
+ {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe0, 0, 0}, {0x4004, 0x02, 0, 0},
+ {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x4837, 0x16, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
+ {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_720P_1280_720[] = {
+ {0x3035, 0x41, 0, 0}, {0x3036, 0x69, 0, 0}, {0x3c07, 0x07, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
+ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+ {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0},
+ {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3813, 0x04, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3709, 0x52, 0, 0},
+ {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe0, 0, 0},
+ {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe0, 0, 0}, {0x4004, 0x02, 0, 0},
+ {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x4837, 0x16, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
+ {0x3503, 0x00, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_QCIF_176_144[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0},
+ {0x380a, 0x00, 0, 0}, {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QCIF_176_144[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0},
+ {0x380a, 0x00, 0, 0}, {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_30fps_XGA_1024_768[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0},
+ {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x20, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x01, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_XGA_1024_768[] = {
+ {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9b, 0, 0}, {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0},
+ {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, {0x380c, 0x07, 0, 0},
+ {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0},
+ {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0},
+ {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0},
+ {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0},
+ {0x460c, 0x20, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x01, 0, 0},
+ {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+
+static struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = {
+ {0x3c07, 0x07, 0, 0}, {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0},
+ {0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0xee, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x05, 0, 0},
+ {0x3807, 0xc3, 0, 0}, {0x3808, 0x07, 0, 0}, {0x3809, 0x80, 0, 0},
+ {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, {0x380c, 0x0b, 0, 0},
+ {0x380d, 0x1c, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0},
+ {0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x2b, 0, 0},
+ {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x07, 0, 0},
+ {0x3a03, 0xae, 0, 0}, {0x3a14, 0x07, 0, 0}, {0x3a15, 0xae, 0, 0},
+ {0x4004, 0x06, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x02, 0, 0}, {0x4407, 0x0c, 0, 0}, {0x460b, 0x37, 0, 0},
+ {0x460c, 0x20, 0, 0}, {0x4837, 0x2c, 0, 0}, {0x3824, 0x01, 0, 0},
+ {0x5001, 0x83, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = {
+ {0x3c07, 0x07, 0, 0}, {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0},
+ {0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0},
+ {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0},
+ {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0},
+ {0x3807, 0x9f, 0, 0}, {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0},
+ {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0},
+ {0x380d, 0x1c, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0},
+ {0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x2b, 0, 0},
+ {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x07, 0, 0},
+ {0x3a03, 0xae, 0, 0}, {0x3a14, 0x07, 0, 0}, {0x3a15, 0xae, 0, 0},
+ {0x4004, 0x06, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0},
+ {0x4713, 0x02, 0, 0}, {0x4407, 0x0c, 0, 0}, {0x460b, 0x37, 0, 0},
+ {0x460c, 0x20, 0, 0}, {0x4837, 0x2c, 0, 0}, {0x3824, 0x01, 0, 0},
+ {0x5001, 0x83, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0},
+};
+
+static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = {
+ {
+ {ov5640_mode_VGA_640_480, 640, 480,
+ ov5640_setting_15fps_VGA_640_480,
+ ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)},
+ {ov5640_mode_QVGA_320_240, 320, 240,
+ ov5640_setting_15fps_QVGA_320_240,
+ ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)},
+ {ov5640_mode_NTSC_720_480, 720, 480,
+ ov5640_setting_15fps_NTSC_720_480,
+ ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)},
+ {ov5640_mode_PAL_720_576, 720, 576,
+ ov5640_setting_15fps_PAL_720_576,
+ ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)},
+ {ov5640_mode_720P_1280_720, 1280, 720,
+ ov5640_setting_15fps_720P_1280_720,
+ ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)},
+ {ov5640_mode_1080P_1920_1080, 1920, 1080,
+ ov5640_setting_15fps_1080P_1920_1080,
+ ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)},
+ {ov5640_mode_QSXGA_2592_1944, 2592, 1944,
+ ov5640_setting_15fps_QSXGA_2592_1944,
+ ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)},
+ {ov5640_mode_QCIF_176_144, 176, 144,
+ ov5640_setting_15fps_QCIF_176_144,
+ ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)},
+ {ov5640_mode_XGA_1024_768, 1024, 768,
+ ov5640_setting_15fps_XGA_1024_768,
+ ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)},
+ },
+ {
+ {ov5640_mode_VGA_640_480, 640, 480,
+ ov5640_setting_30fps_VGA_640_480,
+ ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)},
+ {ov5640_mode_QVGA_320_240, 320, 240,
+ ov5640_setting_30fps_QVGA_320_240,
+ ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)},
+ {ov5640_mode_NTSC_720_480, 720, 480,
+ ov5640_setting_30fps_NTSC_720_480,
+ ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)},
+ {ov5640_mode_PAL_720_576, 720, 576,
+ ov5640_setting_30fps_PAL_720_576,
+ ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)},
+ {ov5640_mode_720P_1280_720, 1280, 720,
+ ov5640_setting_30fps_720P_1280_720,
+ ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)},
+ {ov5640_mode_1080P_1920_1080, 0, 0, NULL, 0},
+ {ov5640_mode_QSXGA_2592_1944, 0, 0, NULL, 0},
+ {ov5640_mode_QCIF_176_144, 176, 144,
+ ov5640_setting_30fps_QCIF_176_144,
+ ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)},
+ {ov5640_mode_XGA_1024_768, 1024, 768,
+ ov5640_setting_30fps_XGA_1024_768,
+ ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)},
+ },
+};
+
+static struct regulator *io_regulator;
+static struct regulator *core_regulator;
+static struct regulator *analog_regulator;
+
+static int ov5640_probe(struct i2c_client *adapter,
+ const struct i2c_device_id *device_id);
+static int ov5640_remove(struct i2c_client *client);
+
+static s32 ov5640_read_reg(u16 reg, u8 *val);
+static s32 ov5640_write_reg(u16 reg, u8 val);
+
+static const struct i2c_device_id ov5640_id[] = {
+ {"ov5640", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, ov5640_id);
+
+static struct i2c_driver ov5640_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ov5640",
+ },
+ .probe = ov5640_probe,
+ .remove = ov5640_remove,
+ .id_table = ov5640_id,
+};
+
+static const struct ov5640_datafmt ov5640_colour_fmts[] = {
+ {MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+};
+
+static struct ov5640 *to_ov5640(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct ov5640, subdev);
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct ov5640_datafmt
+ *ov5640_find_datafmt(u32 code)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ov5640_colour_fmts); i++)
+ if (ov5640_colour_fmts[i].code == code)
+ return ov5640_colour_fmts + i;
+
+ return NULL;
+}
+
+static inline void ov5640_power_down(int enable)
+{
+ gpio_set_value_cansleep(pwn_gpio, enable);
+
+ msleep(2);
+}
+
+static inline void ov5640_reset(void)
+{
+ /* camera reset */
+ gpio_set_value_cansleep(rst_gpio, 1);
+
+ /* camera power down */
+ gpio_set_value_cansleep(pwn_gpio, 1);
+ msleep(5);
+ gpio_set_value_cansleep(pwn_gpio, 0);
+ msleep(5);
+ gpio_set_value_cansleep(rst_gpio, 0);
+ msleep(1);
+ gpio_set_value_cansleep(rst_gpio, 1);
+ msleep(5);
+ gpio_set_value_cansleep(pwn_gpio, 1);
+}
+
+static int ov5640_regulator_enable(struct device *dev)
+{
+ int ret = 0;
+
+ io_regulator = devm_regulator_get(dev, "DOVDD");
+ if (!IS_ERR(io_regulator)) {
+ regulator_set_voltage(io_regulator,
+ OV5640_VOLTAGE_DIGITAL_IO,
+ OV5640_VOLTAGE_DIGITAL_IO);
+ ret = regulator_enable(io_regulator);
+ if (ret) {
+ dev_err(dev, "set io voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set io voltage ok\n");
+ }
+ } else {
+ io_regulator = NULL;
+ dev_warn(dev, "cannot get io voltage\n");
+ }
+
+ core_regulator = devm_regulator_get(dev, "DVDD");
+ if (!IS_ERR(core_regulator)) {
+ regulator_set_voltage(core_regulator,
+ OV5640_VOLTAGE_DIGITAL_CORE,
+ OV5640_VOLTAGE_DIGITAL_CORE);
+ ret = regulator_enable(core_regulator);
+ if (ret) {
+ dev_err(dev, "set core voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set core voltage ok\n");
+ }
+ } else {
+ core_regulator = NULL;
+ dev_warn(dev, "cannot get core voltage\n");
+ }
+
+ analog_regulator = devm_regulator_get(dev, "AVDD");
+ if (!IS_ERR(analog_regulator)) {
+ regulator_set_voltage(analog_regulator,
+ OV5640_VOLTAGE_ANALOG,
+ OV5640_VOLTAGE_ANALOG);
+ ret = regulator_enable(analog_regulator);
+ if (ret) {
+ dev_err(dev, "set analog voltage failed\n");
+ return ret;
+ } else {
+ dev_dbg(dev, "set analog voltage ok\n");
+ }
+ } else {
+ analog_regulator = NULL;
+ dev_warn(dev, "cannot get analog voltage\n");
+ }
+
+ return ret;
+}
+
+static s32 ov5640_write_reg(u16 reg, u8 val)
+{
+ u8 au8Buf[3] = {0};
+
+ au8Buf[0] = reg >> 8;
+ au8Buf[1] = reg & 0xff;
+ au8Buf[2] = val;
+
+ if (i2c_master_send(ov5640_data.i2c_client, au8Buf, 3) < 0) {
+ pr_err("%s:write reg error:reg=%x,val=%x\n",
+ __func__, reg, val);
+ return -1;
+ }
+
+ return 0;
+}
+
+static s32 ov5640_read_reg(u16 reg, u8 *val)
+{
+ u8 au8RegBuf[2] = {0};
+ u8 u8RdVal = 0;
+
+ au8RegBuf[0] = reg >> 8;
+ au8RegBuf[1] = reg & 0xff;
+
+ if (2 != i2c_master_send(ov5640_data.i2c_client, au8RegBuf, 2)) {
+ pr_err("%s:write reg error:reg=%x\n",
+ __func__, reg);
+ return -1;
+ }
+
+ if (1 != i2c_master_recv(ov5640_data.i2c_client, &u8RdVal, 1)) {
+ pr_err("%s:read reg error:reg=%x,val=%x\n",
+ __func__, reg, u8RdVal);
+ return -1;
+ }
+
+ *val = u8RdVal;
+
+ return u8RdVal;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov5640_get_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+ u8 val;
+
+ if (reg->reg & ~0xffff)
+ return -EINVAL;
+
+ reg->size = 1;
+
+ ret = ov5640_read_reg(reg->reg, &val);
+ if (!ret)
+ reg->val = (__u64)val;
+
+ return ret;
+}
+
+static int ov5640_set_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->reg & ~0xffff || reg->val & ~0xff)
+ return -EINVAL;
+
+ return ov5640_write_reg(reg->reg, reg->val);
+}
+#endif
+
+static void ov5640_soft_reset(void)
+{
+ /* sysclk from pad */
+ ov5640_write_reg(0x3103, 0x11);
+
+ /* software reset */
+ ov5640_write_reg(0x3008, 0x82);
+
+ /* delay at least 5ms */
+ msleep(10);
+}
+
+/* set sensor driver capability
+ * 0x302c[7:6] - strength
+ 00 - 1x
+ 01 - 2x
+ 10 - 3x
+ 11 - 4x
+ */
+static int ov5640_driver_capability(int strength)
+{
+ u8 temp = 0;
+
+ if (strength > 4 || strength < 1) {
+ pr_err("The valid driver capability of ov5640 is 1x~4x\n");
+ return -EINVAL;
+ }
+
+ ov5640_read_reg(0x302c, &temp);
+
+ temp &= ~0xc0; /* clear [7:6] */
+ temp |= ((strength - 1) << 6); /* set [7:6] */
+
+ ov5640_write_reg(0x302c, temp);
+
+ return 0;
+}
+
+/* calculate sysclk */
+static int ov5640_get_sysclk(void)
+{
+ int xvclk = ov5640_data.mclk / 10000;
+ int sysclk;
+ int temp1, temp2;
+ int Multiplier, PreDiv, VCO, SysDiv, Pll_rdiv, Bit_div2x, sclk_rdiv;
+ int sclk_rdiv_map[] = {1, 2, 4, 8};
+ u8 regval = 0;
+
+ temp1 = ov5640_read_reg(0x3034, &regval);
+ temp2 = temp1 & 0x0f;
+ if (temp2 == 8 || temp2 == 10) {
+ Bit_div2x = temp2 / 2;
+ } else {
+ pr_err("ov5640: unsupported bit mode %d\n", temp2);
+ return -1;
+ }
+
+ temp1 = ov5640_read_reg(0x3035, &regval);
+ SysDiv = temp1 >> 4;
+ if (SysDiv == 0)
+ SysDiv = 16;
+
+ temp1 = ov5640_read_reg(0x3036, &regval);
+ Multiplier = temp1;
+ temp1 = ov5640_read_reg(0x3037, &regval);
+ PreDiv = temp1 & 0x0f;
+ Pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
+
+ temp1 = ov5640_read_reg(0x3108, &regval);
+ temp2 = temp1 & 0x03;
+
+ sclk_rdiv = sclk_rdiv_map[temp2];
+ VCO = xvclk * Multiplier / PreDiv;
+ sysclk = VCO / SysDiv / Pll_rdiv * 2 / Bit_div2x / sclk_rdiv;
+
+ return sysclk;
+}
+
+/* read HTS from register settings */
+static int ov5640_get_HTS(void)
+{
+ int HTS;
+ u8 temp = 0;
+
+ HTS = ov5640_read_reg(0x380c, &temp);
+ HTS = (HTS<<8) + ov5640_read_reg(0x380d, &temp);
+ return HTS;
+}
+
+/* read VTS from register settings */
+static int ov5640_get_VTS(void)
+{
+ int VTS;
+ u8 temp = 0;
+
+ VTS = ov5640_read_reg(0x380e, &temp);
+ VTS = (VTS<<8) + ov5640_read_reg(0x380f, &temp);
+
+ return VTS;
+}
+
+/* write VTS to registers */
+static int ov5640_set_VTS(int VTS)
+{
+ int temp;
+
+ temp = VTS & 0xff;
+ ov5640_write_reg(0x380f, temp);
+
+ temp = VTS>>8;
+ ov5640_write_reg(0x380e, temp);
+ return 0;
+}
+
+/* read shutter, in number of line period */
+static int ov5640_get_shutter(void)
+{
+ int shutter;
+ u8 regval;
+
+ shutter = (ov5640_read_reg(0x03500, &regval) & 0x0f);
+
+ shutter = (shutter<<8) + ov5640_read_reg(0x3501, &regval);
+ shutter = (shutter<<4) + (ov5640_read_reg(0x3502, &regval)>>4);
+
+ return shutter;
+}
+
+/* write shutter, in number of line period */
+static int ov5640_set_shutter(int shutter)
+{
+ int temp;
+
+ shutter = shutter & 0xffff;
+ temp = shutter & 0x0f;
+ temp = temp<<4;
+ ov5640_write_reg(0x3502, temp);
+
+ temp = shutter & 0xfff;
+ temp = temp>>4;
+ ov5640_write_reg(0x3501, temp);
+
+ temp = shutter>>12;
+ ov5640_write_reg(0x3500, temp);
+
+ return 0;
+}
+
+/* read gain, 16 = 1x */
+static int ov5640_get_gain16(void)
+{
+ int gain16;
+ u8 regval;
+
+ gain16 = ov5640_read_reg(0x350a, &regval) & 0x03;
+ gain16 = (gain16<<8) + ov5640_read_reg(0x350b, &regval);
+
+ return gain16;
+}
+
+/* write gain, 16 = 1x */
+static int ov5640_set_gain16(int gain16)
+{
+ int temp;
+
+ gain16 = gain16 & 0x3ff;
+ temp = gain16 & 0xff;
+
+ ov5640_write_reg(0x350b, temp);
+ temp = gain16>>8;
+
+ ov5640_write_reg(0x350a, temp);
+ return 0;
+}
+
+/* get banding filter value */
+static int ov5640_get_light_freq(void)
+{
+ int temp, temp1, light_frequency;
+ u8 regval;
+
+ temp = ov5640_read_reg(0x3c01, &regval);
+ if (temp & 0x80) {
+ /* manual */
+ temp1 = ov5640_read_reg(0x3c00, &regval);
+ if (temp1 & 0x04) {
+ /* 50Hz */
+ light_frequency = 50;
+ } else {
+ /* 60Hz */
+ light_frequency = 60;
+ }
+ } else {
+ /* auto */
+ temp1 = ov5640_read_reg(0x3c0c, &regval);
+ if (temp1 & 0x01) {
+ /* 50Hz */
+ light_frequency = 50;
+ } else {
+ /* 60Hz */
+ light_frequency = 60;
+ }
+ }
+
+ return light_frequency;
+}
+
+static void ov5640_set_bandingfilter(void)
+{
+ int prev_VTS;
+ int band_step60, max_band60, band_step50, max_band50;
+
+ /* read preview PCLK */
+ prev_sysclk = ov5640_get_sysclk();
+
+ /* read preview HTS */
+ prev_HTS = ov5640_get_HTS();
+
+ /* read preview VTS */
+ prev_VTS = ov5640_get_VTS();
+
+ /* calculate banding filter */
+ /* 60Hz */
+ band_step60 = prev_sysclk * 100/prev_HTS * 100/120;
+ ov5640_write_reg(0x3a0a, (band_step60 >> 8));
+ ov5640_write_reg(0x3a0b, (band_step60 & 0xff));
+
+ max_band60 = (int)((prev_VTS-4)/band_step60);
+ ov5640_write_reg(0x3a0d, max_band60);
+
+ /* 50Hz */
+ band_step50 = prev_sysclk * 100/prev_HTS;
+ ov5640_write_reg(0x3a08, (band_step50 >> 8));
+ ov5640_write_reg(0x3a09, (band_step50 & 0xff));
+
+ max_band50 = (int)((prev_VTS-4)/band_step50);
+ ov5640_write_reg(0x3a0e, max_band50);
+}
+
+/* stable in high */
+static int ov5640_set_AE_target(int target)
+{
+ int fast_high, fast_low;
+
+ AE_low = target * 23 / 25; /* 0.92 */
+ AE_high = target * 27 / 25; /* 1.08 */
+ fast_high = AE_high << 1;
+
+ if (fast_high > 255)
+ fast_high = 255;
+ fast_low = AE_low >> 1;
+
+ ov5640_write_reg(0x3a0f, AE_high);
+ ov5640_write_reg(0x3a10, AE_low);
+ ov5640_write_reg(0x3a1b, AE_high);
+ ov5640_write_reg(0x3a1e, AE_low);
+ ov5640_write_reg(0x3a11, fast_high);
+ ov5640_write_reg(0x3a1f, fast_low);
+
+ return 0;
+}
+
+/* enable = 0 to turn off night mode
+ enable = 1 to turn on night mode */
+static int ov5640_set_night_mode(int enable)
+{
+ u8 mode;
+
+ ov5640_read_reg(0x3a00, &mode);
+
+ if (enable) {
+ /* night mode on */
+ mode |= 0x04;
+ ov5640_write_reg(0x3a00, mode);
+ } else {
+ /* night mode off */
+ mode &= 0xfb;
+ ov5640_write_reg(0x3a00, mode);
+ }
+
+ return 0;
+}
+
+/* enable = 0 to turn off AEC/AGC
+ enable = 1 to turn on AEC/AGC */
+static void ov5640_turn_on_AE_AG(int enable)
+{
+ u8 ae_ag_ctrl;
+
+ ov5640_read_reg(0x3503, &ae_ag_ctrl);
+ if (enable) {
+ /* turn on auto AE/AG */
+ ae_ag_ctrl = ae_ag_ctrl & ~(0x03);
+ } else {
+ /* turn off AE/AG */
+ ae_ag_ctrl = ae_ag_ctrl | 0x03;
+ }
+ ov5640_write_reg(0x3503, ae_ag_ctrl);
+}
+
+/* download ov5640 settings to sensor through i2c */
+static int ov5640_download_firmware(struct reg_value *pModeSetting, s32 ArySize)
+{
+ register u32 Delay_ms = 0;
+ register u16 RegAddr = 0;
+ register u8 Mask = 0;
+ register u8 Val = 0;
+ u8 RegVal = 0;
+ int i, retval = 0;
+
+ for (i = 0; i < ArySize; ++i, ++pModeSetting) {
+ Delay_ms = pModeSetting->u32Delay_ms;
+ RegAddr = pModeSetting->u16RegAddr;
+ Val = pModeSetting->u8Val;
+ Mask = pModeSetting->u8Mask;
+
+ if (Mask) {
+ retval = ov5640_read_reg(RegAddr, &RegVal);
+ if (retval < 0)
+ goto err;
+
+ RegVal &= ~(u8)Mask;
+ Val &= Mask;
+ Val |= RegVal;
+ }
+
+ retval = ov5640_write_reg(RegAddr, Val);
+ if (retval < 0)
+ goto err;
+
+ if (Delay_ms)
+ msleep(Delay_ms);
+ }
+err:
+ return retval;
+}
+
+static int ov5640_init_mode(void)
+{
+ struct reg_value *pModeSetting = NULL;
+ int ArySize = 0, retval = 0;
+
+ ov5640_soft_reset();
+
+ pModeSetting = ov5640_global_init_setting;
+ ArySize = ARRAY_SIZE(ov5640_global_init_setting);
+ retval = ov5640_download_firmware(pModeSetting, ArySize);
+ if (retval < 0)
+ goto err;
+
+ pModeSetting = ov5640_init_setting_30fps_VGA;
+ ArySize = ARRAY_SIZE(ov5640_init_setting_30fps_VGA);
+ retval = ov5640_download_firmware(pModeSetting, ArySize);
+ if (retval < 0)
+ goto err;
+
+ /* change driver capability to 2x according to validation board.
+ * if the image is not stable, please increase the driver strength.
+ */
+ ov5640_driver_capability(2);
+ ov5640_set_bandingfilter();
+ ov5640_set_AE_target(AE_Target);
+ ov5640_set_night_mode(night_mode);
+
+ /* skip 9 vysnc: start capture at 10th vsync */
+ msleep(300);
+
+ /* turn off night mode */
+ night_mode = 0;
+ ov5640_data.pix.width = 640;
+ ov5640_data.pix.height = 480;
+err:
+ return retval;
+}
+
+/* change to or back to subsampling mode set the mode directly
+ * image size below 1280 * 960 is subsampling mode */
+static int ov5640_change_mode_direct(enum ov5640_frame_rate frame_rate,
+ enum ov5640_mode mode)
+{
+ struct reg_value *pModeSetting = NULL;
+ s32 ArySize = 0;
+ int retval = 0;
+
+ if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) {
+ pr_err("Wrong ov5640 mode detected!\n");
+ return -1;
+ }
+
+ pModeSetting = ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+ ArySize =
+ ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+ ov5640_data.pix.width = ov5640_mode_info_data[frame_rate][mode].width;
+ ov5640_data.pix.height = ov5640_mode_info_data[frame_rate][mode].height;
+
+ if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 ||
+ pModeSetting == NULL || ArySize == 0)
+ return -EINVAL;
+
+ /* set ov5640 to subsampling mode */
+ retval = ov5640_download_firmware(pModeSetting, ArySize);
+
+ /* turn on AE AG for subsampling mode, in case the firmware didn't */
+ ov5640_turn_on_AE_AG(1);
+
+ /* calculate banding filter */
+ ov5640_set_bandingfilter();
+
+ /* set AE target */
+ ov5640_set_AE_target(AE_Target);
+
+ /* update night mode setting */
+ ov5640_set_night_mode(night_mode);
+
+ /* skip 9 vysnc: start capture at 10th vsync */
+ if (mode == ov5640_mode_XGA_1024_768 && frame_rate == ov5640_30_fps) {
+ pr_warning("ov5640: actual frame rate of XGA is 22.5fps\n");
+ /* 1/22.5 * 9*/
+ msleep(400);
+ return retval;
+ }
+
+ if (frame_rate == ov5640_15_fps) {
+ /* 1/15 * 9*/
+ msleep(600);
+ } else if (frame_rate == ov5640_30_fps) {
+ /* 1/30 * 9*/
+ msleep(300);
+ }
+
+ return retval;
+}
+
+/* change to scaling mode go through exposure calucation
+ * image size above 1280 * 960 is scaling mode */
+static int ov5640_change_mode_exposure_calc(enum ov5640_frame_rate frame_rate,
+ enum ov5640_mode mode)
+{
+ int prev_shutter, prev_gain16, average;
+ int cap_shutter, cap_gain16;
+ int cap_sysclk, cap_HTS, cap_VTS;
+ int light_freq, cap_bandfilt, cap_maxband;
+ long cap_gain16_shutter;
+ u8 temp;
+ struct reg_value *pModeSetting = NULL;
+ s32 ArySize = 0;
+ int retval = 0;
+
+ /* check if the input mode and frame rate is valid */
+ pModeSetting =
+ ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+ ArySize =
+ ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+ ov5640_data.pix.width =
+ ov5640_mode_info_data[frame_rate][mode].width;
+ ov5640_data.pix.height =
+ ov5640_mode_info_data[frame_rate][mode].height;
+
+ if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 ||
+ pModeSetting == NULL || ArySize == 0)
+ return -EINVAL;
+
+ /* read preview shutter */
+ prev_shutter = ov5640_get_shutter();
+
+ /* read preview gain */
+ prev_gain16 = ov5640_get_gain16();
+
+ /* get average */
+ average = ov5640_read_reg(0x56a1, &temp);
+
+ /* turn off night mode for capture */
+ ov5640_set_night_mode(0);
+
+ /* turn off overlay */
+ ov5640_write_reg(0x3022, 0x06);
+
+ /* Write capture setting */
+ retval = ov5640_download_firmware(pModeSetting, ArySize);
+ if (retval < 0)
+ goto err;
+
+ /* turn off AE AG when capture image. */
+ ov5640_turn_on_AE_AG(0);
+
+ /* read capture VTS */
+ cap_VTS = ov5640_get_VTS();
+ cap_HTS = ov5640_get_HTS();
+ cap_sysclk = ov5640_get_sysclk();
+
+ /* calculate capture banding filter */
+ light_freq = ov5640_get_light_freq();
+ if (light_freq == 60) {
+ /* 60Hz */
+ cap_bandfilt = cap_sysclk * 100 / cap_HTS * 100 / 120;
+ } else {
+ /* 50Hz */
+ cap_bandfilt = cap_sysclk * 100 / cap_HTS;
+ }
+ cap_maxband = (int)((cap_VTS - 4)/cap_bandfilt);
+ /* calculate capture shutter/gain16 */
+ if (average > AE_low && average < AE_high) {
+ /* in stable range */
+ cap_gain16_shutter =
+ prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk *
+ prev_HTS/cap_HTS * AE_Target / average;
+ } else {
+ cap_gain16_shutter =
+ prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk *
+ prev_HTS/cap_HTS;
+ }
+
+ /* gain to shutter */
+ if (cap_gain16_shutter < (cap_bandfilt * 16)) {
+ /* shutter < 1/100 */
+ cap_shutter = cap_gain16_shutter/16;
+ if (cap_shutter < 1)
+ cap_shutter = 1;
+ cap_gain16 = cap_gain16_shutter/cap_shutter;
+ if (cap_gain16 < 16)
+ cap_gain16 = 16;
+ } else {
+ if (cap_gain16_shutter > (cap_bandfilt*cap_maxband*16)) {
+ /* exposure reach max */
+ cap_shutter = cap_bandfilt*cap_maxband;
+ cap_gain16 = cap_gain16_shutter / cap_shutter;
+ } else {
+ /* 1/100 < cap_shutter =< max, cap_shutter = n/100 */
+ cap_shutter =
+ ((int)(cap_gain16_shutter/16/cap_bandfilt))
+ * cap_bandfilt;
+ cap_gain16 = cap_gain16_shutter / cap_shutter;
+ }
+ }
+
+ /* write capture gain */
+ ov5640_set_gain16(cap_gain16);
+
+ /* write capture shutter */
+ if (cap_shutter > (cap_VTS - 4)) {
+ cap_VTS = cap_shutter + 4;
+ ov5640_set_VTS(cap_VTS);
+ }
+
+ ov5640_set_shutter(cap_shutter);
+
+ /* skip 2 vysnc: start capture at 3rd vsync
+ * frame rate of QSXGA and 1080P is 7.5fps: 1/7.5 * 2
+ */
+ pr_warning("ov5640: the actual frame rate of %s is 7.5fps\n",
+ mode == ov5640_mode_1080P_1920_1080 ? "1080P" : "QSXGA");
+ msleep(267);
+err:
+ return retval;
+}
+
+static int ov5640_change_mode(enum ov5640_frame_rate frame_rate,
+ enum ov5640_mode mode)
+{
+ int retval = 0;
+
+ if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) {
+ pr_err("Wrong ov5640 mode detected!\n");
+ return -1;
+ }
+
+ if (mode == ov5640_mode_1080P_1920_1080 ||
+ mode == ov5640_mode_QSXGA_2592_1944) {
+ /* change to scaling mode go through exposure calucation
+ * image size above 1280 * 960 is scaling mode */
+ retval = ov5640_change_mode_exposure_calc(frame_rate, mode);
+ } else {
+ /* change back to subsampling modem download firmware directly
+ * image size below 1280 * 960 is subsampling mode */
+ retval = ov5640_change_mode_direct(frame_rate, mode);
+ }
+
+ return retval;
+}
+
+/*!
+ * ov5640_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @on: indicates power mode (on or off)
+ *
+ * Turns the power on or off, depending on the value of on and returns the
+ * appropriate error code.
+ */
+static int ov5640_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+
+ if (on)
+ clk_enable(ov5640_data.sensor_clk);
+ else
+ clk_disable(ov5640_data.sensor_clk);
+
+ sensor->on = on;
+
+ return 0;
+}
+
+/*!
+ * ov5640_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 sub device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ov5640_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+ int ret = 0;
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cparm->capability = sensor->streamcap.capability;
+ cparm->timeperframe = sensor->streamcap.timeperframe;
+ cparm->capturemode = sensor->streamcap.capturemode;
+ ret = 0;
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ ret = -EINVAL;
+ break;
+
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * ov5460_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 sub device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible. If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ */
+static int ov5640_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+ u32 tgt_fps; /* target frames per secound */
+ enum ov5640_frame_rate frame_rate;
+ int ret = 0;
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ /* Check that the new frame rate is allowed. */
+ if ((timeperframe->numerator == 0) ||
+ (timeperframe->denominator == 0)) {
+ timeperframe->denominator = DEFAULT_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps > MAX_FPS) {
+ timeperframe->denominator = MAX_FPS;
+ timeperframe->numerator = 1;
+ } else if (tgt_fps < MIN_FPS) {
+ timeperframe->denominator = MIN_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ /* Actual frame rate we use */
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps == 15)
+ frame_rate = ov5640_15_fps;
+ else if (tgt_fps == 30)
+ frame_rate = ov5640_30_fps;
+ else {
+ pr_err(" The camera frame rate is not supported!\n");
+ goto error;
+ }
+
+ ret = ov5640_change_mode(frame_rate,
+ a->parm.capture.capturemode);
+ if (ret < 0)
+ goto error;
+
+ sensor->streamcap.timeperframe = *timeperframe;
+ sensor->streamcap.capturemode = a->parm.capture.capturemode;
+
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ pr_debug(" type is not " \
+ "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n",
+ a->type);
+ ret = -EINVAL;
+ break;
+
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+error:
+ return ret;
+}
+
+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;
+ const struct ov5640_datafmt *fmt = ov5640_find_datafmt(mf->code);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5640 *sensor = to_ov5640(client);
+
+ if (format->pad)
+ return -EINVAL;
+
+ if (!fmt) {
+ mf->code = ov5640_colour_fmts[0].code;
+ mf->colorspace = ov5640_colour_fmts[0].colorspace;
+ }
+
+ mf->field = V4L2_FIELD_NONE;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+ return 0;
+
+ sensor->fmt = fmt;
+
+ 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 *sensor = to_ov5640(client);
+ const struct ov5640_datafmt *fmt = sensor->fmt;
+
+ if (format->pad)
+ return -EINVAL;
+
+ mf->code = fmt->code;
+ mf->colorspace = fmt->colorspace;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int ov5640_enum_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(ov5640_colour_fmts))
+ return -EINVAL;
+
+ code->code = ov5640_colour_fmts[code->index].code;
+ return 0;
+}
+
+/*!
+ * ov5640_enum_framesizes - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ov5640_enum_framesizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index > ov5640_mode_MAX)
+ return -EINVAL;
+
+ fse->max_width =
+ max(ov5640_mode_info_data[0][fse->index].width,
+ ov5640_mode_info_data[1][fse->index].width);
+ fse->min_width = fse->max_width;
+ fse->max_height =
+ max(ov5640_mode_info_data[0][fse->index].height,
+ ov5640_mode_info_data[1][fse->index].height);
+ fse->min_height = fse->max_height;
+ return 0;
+}
+
+/*!
+ * ov5640_enum_frameintervals - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMEINTERVALS ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ov5640_enum_frameintervals(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ int i, j, count;
+
+ if (fie->index < 0 || fie->index > ov5640_mode_MAX)
+ return -EINVAL;
+
+ if (fie->width == 0 || fie->height == 0 ||
+ fie->code == 0) {
+ pr_warning("Please assign pixel format, width and height.\n");
+ return -EINVAL;
+ }
+
+ fie->interval.numerator = 1;
+
+ count = 0;
+ for (i = 0; i < ARRAY_SIZE(ov5640_mode_info_data); i++) {
+ for (j = 0; j < (ov5640_mode_MAX + 1); j++) {
+ if (fie->width == ov5640_mode_info_data[i][j].width
+ && fie->height == ov5640_mode_info_data[i][j].height
+ && ov5640_mode_info_data[i][j].init_data_ptr != NULL) {
+ count++;
+ }
+ if (fie->index == (count - 1)) {
+ fie->interval.denominator =
+ ov5640_framerates[i];
+ return 0;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int ov5640_set_clk_rate(void)
+{
+ u32 tgt_xclk; /* target xclk */
+ int ret;
+
+ /* mclk */
+ tgt_xclk = ov5640_data.mclk;
+ tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX);
+ tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN);
+ ov5640_data.mclk = tgt_xclk;
+
+ pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000);
+ ret = clk_set_rate(ov5640_data.sensor_clk, ov5640_data.mclk);
+ if (ret < 0)
+ pr_debug("set rate filed, rate=%d\n", ov5640_data.mclk);
+ return ret;
+}
+
+/*!
+ * dev_init - V4L2 sensor init
+ * @s: pointer to standard V4L2 device structure
+ *
+ */
+static int init_device(void)
+{
+ u32 tgt_xclk; /* target xclk */
+ u32 tgt_fps; /* target frames per secound */
+ enum ov5640_frame_rate frame_rate;
+ int ret;
+
+ ov5640_data.on = true;
+
+ /* mclk */
+ tgt_xclk = ov5640_data.mclk;
+
+ /* Default camera frame rate is set in probe */
+ tgt_fps = ov5640_data.streamcap.timeperframe.denominator /
+ ov5640_data.streamcap.timeperframe.numerator;
+
+ if (tgt_fps == 15)
+ frame_rate = ov5640_15_fps;
+ else if (tgt_fps == 30)
+ frame_rate = ov5640_30_fps;
+ else
+ return -EINVAL; /* Only support 15fps or 30fps now. */
+
+ ret = ov5640_init_mode();
+
+ return ret;
+}
+
+static struct v4l2_subdev_video_ops ov5640_subdev_video_ops = {
+ .g_parm = ov5640_g_parm,
+ .s_parm = ov5640_s_parm,
+};
+
+static const struct v4l2_subdev_pad_ops ov5640_subdev_pad_ops = {
+ .enum_frame_size = ov5640_enum_framesizes,
+ .enum_frame_interval = ov5640_enum_frameintervals,
+ .enum_mbus_code = ov5640_enum_code,
+ .set_fmt = ov5640_set_fmt,
+ .get_fmt = ov5640_get_fmt,
+};
+
+static struct v4l2_subdev_core_ops ov5640_subdev_core_ops = {
+ .s_power = ov5640_s_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ov5640_get_register,
+ .s_register = ov5640_set_register,
+#endif
+};
+
+static struct v4l2_subdev_ops ov5640_subdev_ops = {
+ .core = &ov5640_subdev_core_ops,
+ .video = &ov5640_subdev_video_ops,
+ .pad = &ov5640_subdev_pad_ops,
+};
+
+/*!
+ * ov5640 I2C probe function
+ *
+ * @param adapter struct i2c_adapter *
+ * @return Error code indicating success or failure
+ */
+static int ov5640_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pinctrl *pinctrl;
+ struct device *dev = &client->dev;
+ int retval;
+ u8 chip_id_high, chip_id_low;
+
+ /* ov5640 pinctrl */
+ pinctrl = devm_pinctrl_get_select_default(dev);
+ if (IS_ERR(pinctrl)) {
+ dev_err(dev, "setup pinctrl failed\n");
+ return PTR_ERR(pinctrl);
+ }
+
+ /* request power down pin */
+ pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+ if (!gpio_is_valid(pwn_gpio)) {
+ dev_err(dev, "no sensor pwdn pin available\n");
+ return -ENODEV;
+ }
+ retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH,
+ "ov5640_pwdn");
+ if (retval < 0)
+ return retval;
+
+ /* request reset pin */
+ rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0);
+ if (!gpio_is_valid(rst_gpio)) {
+ dev_err(dev, "no sensor reset pin available\n");
+ return -EINVAL;
+ }
+ retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH,
+ "ov5640_reset");
+ if (retval < 0)
+ return retval;
+
+ /* Set initial values for the sensor struct. */
+ memset(&ov5640_data, 0, sizeof(ov5640_data));
+ ov5640_data.sensor_clk = devm_clk_get(dev, "csi_mclk");
+ if (IS_ERR(ov5640_data.sensor_clk)) {
+ dev_err(dev, "get mclk failed\n");
+ return PTR_ERR(ov5640_data.sensor_clk);
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk",
+ &ov5640_data.mclk);
+ if (retval) {
+ dev_err(dev, "mclk frequency is invalid\n");
+ return retval;
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk_source",
+ (u32 *) &(ov5640_data.mclk_source));
+ if (retval) {
+ dev_err(dev, "mclk_source invalid\n");
+ return retval;
+ }
+
+ retval = of_property_read_u32(dev->of_node, "csi_id",
+ &(ov5640_data.csi));
+ if (retval) {
+ dev_err(dev, "csi_id invalid\n");
+ return retval;
+ }
+
+ /* Set mclk rate before clk on */
+ ov5640_set_clk_rate();
+
+ clk_prepare_enable(ov5640_data.sensor_clk);
+
+ ov5640_data.io_init = ov5640_reset;
+ ov5640_data.i2c_client = client;
+ ov5640_data.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ ov5640_data.pix.width = 640;
+ ov5640_data.pix.height = 480;
+ ov5640_data.streamcap.capability = V4L2_MODE_HIGHQUALITY |
+ V4L2_CAP_TIMEPERFRAME;
+ ov5640_data.streamcap.capturemode = 0;
+ ov5640_data.streamcap.timeperframe.denominator = DEFAULT_FPS;
+ ov5640_data.streamcap.timeperframe.numerator = 1;
+
+ ov5640_regulator_enable(&client->dev);
+
+ ov5640_reset();
+
+ ov5640_power_down(0);
+
+ retval = ov5640_read_reg(OV5640_CHIP_ID_HIGH_BYTE, &chip_id_high);
+ if (retval < 0 || chip_id_high != 0x56) {
+ clk_disable_unprepare(ov5640_data.sensor_clk);
+ pr_warning("camera ov5640 is not found\n");
+ return -ENODEV;
+ }
+ retval = ov5640_read_reg(OV5640_CHIP_ID_LOW_BYTE, &chip_id_low);
+ if (retval < 0 || chip_id_low != 0x40) {
+ clk_disable_unprepare(ov5640_data.sensor_clk);
+ pr_warning("camera ov5640 is not found\n");
+ return -ENODEV;
+ }
+
+ retval = init_device();
+ if (retval < 0) {
+ clk_disable_unprepare(ov5640_data.sensor_clk);
+ pr_warning("camera ov5640 init failed\n");
+ ov5640_power_down(1);
+ return retval;
+ }
+
+ clk_disable(ov5640_data.sensor_clk);
+
+ v4l2_i2c_subdev_init(&ov5640_data.subdev, client, &ov5640_subdev_ops);
+
+ retval = v4l2_async_register_subdev(&ov5640_data.subdev);
+ if (retval < 0)
+ dev_err(&client->dev,
+ "%s--Async register failed, ret=%d\n", __func__, retval);
+
+ pr_info("camera ov5640, is found\n");
+ return retval;
+}
+
+/*!
+ * ov5640 I2C detach function
+ *
+ * @param client struct i2c_client *
+ * @return Error code indicating success or failure
+ */
+static int ov5640_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_async_unregister_subdev(sd);
+
+ clk_unprepare(ov5640_data.sensor_clk);
+
+ ov5640_power_down(1);
+
+ if (analog_regulator)
+ regulator_disable(analog_regulator);
+
+ if (core_regulator)
+ regulator_disable(core_regulator);
+
+ if (io_regulator)
+ regulator_disable(io_regulator);
+
+ return 0;
+}
+
+module_i2c_driver(ov5640_i2c_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("OV5640 Camera Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("CSI");
diff --git a/drivers/media/platform/mxc/capture/ov5642.c b/drivers/media/platform/mxc/capture/ov5642.c
new file mode 100644
index 000000000000..be6122205c18
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/ov5642.c
@@ -0,0 +1,4252 @@
+/*
+ * Copyright (C) 2012-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/i2c.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/fsl_devices.h>
+#include <media/v4l2-chip-ident.h>
+#include "v4l2-int-device.h"
+#include "mxc_v4l2_capture.h"
+
+#define OV5642_VOLTAGE_ANALOG 2800000
+#define OV5642_VOLTAGE_DIGITAL_CORE 1500000
+#define OV5642_VOLTAGE_DIGITAL_IO 1800000
+
+#define MIN_FPS 15
+#define MAX_FPS 30
+#define DEFAULT_FPS 30
+
+#define OV5642_XCLK_MIN 6000000
+#define OV5642_XCLK_MAX 24000000
+
+#define OV5642_CHIP_ID_HIGH_BYTE 0x300A
+#define OV5642_CHIP_ID_LOW_BYTE 0x300B
+
+enum ov5642_mode {
+ ov5642_mode_MIN = 0,
+ ov5642_mode_VGA_640_480 = 0,
+ ov5642_mode_QVGA_320_240 = 1,
+ ov5642_mode_NTSC_720_480 = 2,
+ ov5642_mode_PAL_720_576 = 3,
+ ov5642_mode_720P_1280_720 = 4,
+ ov5642_mode_1080P_1920_1080 = 5,
+ ov5642_mode_QSXGA_2592_1944 = 6,
+ ov5642_mode_QCIF_176_144 = 7,
+ ov5642_mode_XGA_1024_768 = 8,
+ ov5642_mode_MAX = 8
+};
+
+enum ov5642_frame_rate {
+ ov5642_15_fps,
+ ov5642_30_fps
+};
+
+static int ov5642_framerates[] = {
+ [ov5642_15_fps] = 15,
+ [ov5642_30_fps] = 30,
+};
+
+struct reg_value {
+ u16 u16RegAddr;
+ u8 u8Val;
+ u8 u8Mask;
+ u32 u32Delay_ms;
+};
+
+struct ov5642_mode_info {
+ enum ov5642_mode mode;
+ u32 width;
+ u32 height;
+ struct reg_value *init_data_ptr;
+ u32 init_data_size;
+};
+
+/*!
+ * Maintains the information on the current state of the sesor.
+ */
+static struct sensor_data ov5642_data;
+static int pwn_gpio, rst_gpio;
+
+static struct reg_value ov5642_rot_none_VGA[] = {
+ {0x3818, 0xc1, 0x00, 0x00}, {0x3621, 0x87, 0x00, 0x00},
+};
+
+static struct reg_value ov5642_rot_vert_flip_VGA[] = {
+ {0x3818, 0x20, 0xbf, 0x00}, {0x3621, 0x20, 0xff, 0x00},
+};
+
+static struct reg_value ov5642_rot_horiz_flip_VGA[] = {
+ {0x3818, 0x81, 0x00, 0x01}, {0x3621, 0xa7, 0x00, 0x00},
+};
+
+static struct reg_value ov5642_rot_180_VGA[] = {
+ {0x3818, 0x60, 0xff, 0x00}, {0x3621, 0x00, 0xdf, 0x00},
+};
+
+
+static struct reg_value ov5642_rot_none_FULL[] = {
+ {0x3818, 0xc0, 0x00, 0x00}, {0x3621, 0x09, 0x00, 0x00},
+};
+
+static struct reg_value ov5642_rot_vert_flip_FULL[] = {
+ {0x3818, 0x20, 0xbf, 0x01}, {0x3621, 0x20, 0xff, 0x00},
+};
+
+static struct reg_value ov5642_rot_horiz_flip_FULL[] = {
+ {0x3818, 0x80, 0x00, 0x01}, {0x3621, 0x29, 0x00, 0x00},
+};
+
+static struct reg_value ov5642_rot_180_FULL[] = {
+ {0x3818, 0x60, 0xff, 0x00}, {0x3621, 0x00, 0xdf, 0x00},
+};
+
+
+static struct reg_value ov5642_initial_setting[] = {
+ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0},
+ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0},
+ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0},
+ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0},
+ {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x08, 0, 0},
+ {0x3010, 0x00, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0},
+ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0},
+ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0},
+ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0},
+ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0},
+ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0},
+ {0x3606, 0x3f, 0, 0}, {0x3c00, 0x04, 0, 0}, {0x3c01, 0x80, 0, 0},
+ {0x5000, 0x4f, 0, 0}, {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0},
+ {0x5182, 0x00, 0, 0}, {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0},
+ {0x5001, 0xff, 0, 0}, {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0},
+ {0x5505, 0x7f, 0, 0}, {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0},
+ {0x4610, 0x00, 0, 0}, {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0},
+ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+ {0x380b, 0xe0, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0},
+ {0x501f, 0x00, 0, 0}, {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0},
+ {0x3503, 0x07, 0, 0}, {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0},
+ {0x350b, 0x00, 0, 0}, {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0},
+ {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0},
+ {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0},
+ {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0},
+ {0x3801, 0x80, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0},
+ {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0},
+ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0},
+ {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0},
+ {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0},
+ {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0},
+ {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0},
+ {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0},
+ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0},
+ {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0},
+ {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0},
+ {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0},
+ {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0},
+ {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0},
+ {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0},
+ {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0},
+ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0},
+ {0x3a1f, 0x10, 0, 0}, {0x3030, 0x0b, 0, 0}, {0x3a02, 0x00, 0, 0},
+ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0},
+ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0},
+ {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0},
+ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0},
+ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0},
+ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0},
+ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0},
+ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0},
+ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0},
+ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0},
+ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0},
+ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0},
+ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0},
+ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0},
+ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0},
+ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0},
+ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0},
+ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0},
+ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0},
+ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0},
+ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0},
+ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0},
+ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0},
+ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0},
+ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0},
+ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0},
+ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0},
+ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0},
+ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0},
+ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0},
+ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0},
+ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0},
+ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0},
+ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0},
+ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0},
+ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0},
+ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0},
+ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0},
+ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0},
+ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0},
+ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0},
+ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0},
+ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0},
+ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0},
+ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0},
+ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0},
+ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0},
+ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0},
+ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0},
+ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0},
+ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0},
+ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0},
+ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0},
+ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0},
+ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0},
+ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0},
+ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0},
+ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0},
+ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0},
+ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0},
+ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0},
+ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0},
+ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0},
+ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0},
+ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0},
+ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0},
+ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0},
+ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0},
+ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0},
+ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0},
+ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0},
+ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0},
+ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0},
+ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0},
+ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0},
+ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0},
+ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0},
+ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0},
+ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0},
+ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0},
+ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0},
+ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0},
+ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0},
+ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0},
+ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0},
+ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0},
+ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0},
+ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0},
+ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0},
+ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0},
+ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0},
+ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0},
+ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0},
+ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0},
+ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0},
+ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0},
+ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0},
+ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0},
+ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0},
+ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0},
+ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0},
+ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0},
+ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0},
+ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0},
+ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0},
+ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0},
+ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0},
+ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0},
+ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0},
+ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0},
+ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0},
+ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0},
+ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0},
+ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0},
+ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0},
+ {0x302b, 0x00, 0, 300},
+};
+
+static struct reg_value ov5642_setting_15fps_QCIF_176_144[] = {
+ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0},
+ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0},
+ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0},
+ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0},
+ {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x08, 0, 0},
+ {0x3010, 0x10, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0},
+ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0},
+ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0},
+ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0},
+ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0},
+ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0},
+ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0},
+ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0},
+ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0},
+ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0},
+ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0},
+ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0},
+ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0},
+ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3501, 0x1e, 0, 0},
+ {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, {0x380c, 0x0c, 0, 0},
+ {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3818, 0xc1, 0, 0},
+ {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, {0x3801, 0x80, 0, 0},
+ {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0},
+ {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, {0x3804, 0x05, 0, 0},
+ {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0},
+ {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0},
+ {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x05, 0, 0},
+ {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0},
+ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0},
+ {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0},
+ {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, {0x3502, 0x00, 0, 0},
+ {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, {0x3503, 0x00, 0, 0},
+ {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0},
+ {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, {0x528f, 0x10, 0, 0},
+ {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x02, 0, 0},
+ {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, {0x5296, 0x00, 0, 0},
+ {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x02, 0, 0},
+ {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, {0x529c, 0x00, 0, 0},
+ {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x02, 0, 0},
+ {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3c, 0, 0},
+ {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, {0x3a1f, 0x10, 0, 0},
+ {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, {0x3a03, 0x7d, 0, 0},
+ {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, {0x3a15, 0x7d, 0, 0},
+ {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a08, 0x09, 0, 0},
+ {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, {0x3a0b, 0xd0, 0, 0},
+ {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x06, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, {0x401e, 0x20, 0, 0},
+ {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, {0x528a, 0x01, 0, 0},
+ {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, {0x528d, 0x10, 0, 0},
+ {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, {0x5290, 0x30, 0, 0},
+ {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, {0x5294, 0x00, 0, 0},
+ {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, {0x5297, 0x08, 0, 0},
+ {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, {0x529a, 0x00, 0, 0},
+ {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, {0x529d, 0x28, 0, 0},
+ {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, {0x5282, 0x00, 0, 0},
+ {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, {0x5302, 0x00, 0, 0},
+ {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, {0x530d, 0x0c, 0, 0},
+ {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, {0x5310, 0x20, 0, 0},
+ {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, {0x5309, 0x40, 0, 0},
+ {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x00, 0, 0},
+ {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, {0x5315, 0x20, 0, 0},
+ {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, {0x5317, 0x00, 0, 0},
+ {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, {0x5381, 0x00, 0, 0},
+ {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, {0x5384, 0x00, 0, 0},
+ {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, {0x5387, 0x00, 0, 0},
+ {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, {0x538a, 0x00, 0, 0},
+ {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, {0x538d, 0x00, 0, 0},
+ {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, {0x5390, 0x00, 0, 0},
+ {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, {0x5393, 0xa2, 0, 0},
+ {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, {0x5481, 0x21, 0, 0},
+ {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, {0x5484, 0x65, 0, 0},
+ {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, {0x5487, 0x87, 0, 0},
+ {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, {0x548a, 0xaa, 0, 0},
+ {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, {0x548d, 0xdd, 0, 0},
+ {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, {0x5490, 0x05, 0, 0},
+ {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, {0x5493, 0x20, 0, 0},
+ {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, {0x5496, 0x02, 0, 0},
+ {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, {0x5499, 0x86, 0, 0},
+ {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, {0x549c, 0x02, 0, 0},
+ {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, {0x549f, 0x1c, 0, 0},
+ {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, {0x54a2, 0x01, 0, 0},
+ {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, {0x54a5, 0xc5, 0, 0},
+ {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, {0x54a8, 0x01, 0, 0},
+ {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, {0x54ab, 0x41, 0, 0},
+ {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, {0x54ae, 0x00, 0, 0},
+ {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, {0x54b1, 0x20, 0, 0},
+ {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, {0x54b4, 0x00, 0, 0},
+ {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, {0x54b7, 0xdf, 0, 0},
+ {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, {0x3406, 0x00, 0, 0},
+ {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, {0x5182, 0x11, 0, 0},
+ {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0},
+ {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, {0x5188, 0x08, 0, 0},
+ {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, {0x518b, 0xb2, 0, 0},
+ {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, {0x518e, 0x3d, 0, 0},
+ {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0},
+ {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0},
+ {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0},
+ {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, {0x519a, 0x04, 0, 0},
+ {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, {0x519d, 0x82, 0, 0},
+ {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, {0x3a0f, 0x38, 0, 0},
+ {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, {0x3a1e, 0x2e, 0, 0},
+ {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, {0x5688, 0xa6, 0, 0},
+ {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, {0x568b, 0xae, 0, 0},
+ {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, {0x568e, 0x62, 0, 0},
+ {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x40, 0, 0},
+ {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, {0x5800, 0x27, 0, 0},
+ {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, {0x5803, 0x0f, 0, 0},
+ {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, {0x5806, 0x1e, 0, 0},
+ {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, {0x5809, 0x0d, 0, 0},
+ {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, {0x580c, 0x0a, 0, 0},
+ {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, {0x580f, 0x19, 0, 0},
+ {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, {0x5812, 0x04, 0, 0},
+ {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, {0x5815, 0x06, 0, 0},
+ {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, {0x5818, 0x0a, 0, 0},
+ {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, {0x581b, 0x00, 0, 0},
+ {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, {0x581e, 0x08, 0, 0},
+ {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, {0x5821, 0x05, 0, 0},
+ {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, {0x5824, 0x00, 0, 0},
+ {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, {0x5827, 0x0c, 0, 0},
+ {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, {0x582a, 0x06, 0, 0},
+ {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, {0x582d, 0x07, 0, 0},
+ {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, {0x5830, 0x18, 0, 0},
+ {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, {0x5833, 0x0a, 0, 0},
+ {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, {0x5836, 0x15, 0, 0},
+ {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, {0x5839, 0x1f, 0, 0},
+ {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, {0x583c, 0x17, 0, 0},
+ {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, {0x583f, 0x53, 0, 0},
+ {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, {0x5842, 0x0d, 0, 0},
+ {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, {0x5845, 0x09, 0, 0},
+ {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, {0x5848, 0x10, 0, 0},
+ {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, {0x584b, 0x0e, 0, 0},
+ {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, {0x584e, 0x11, 0, 0},
+ {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, {0x5851, 0x0c, 0, 0},
+ {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, {0x5854, 0x10, 0, 0},
+ {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, {0x5857, 0x0b, 0, 0},
+ {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, {0x585a, 0x0d, 0, 0},
+ {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, {0x585d, 0x0c, 0, 0},
+ {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, {0x5860, 0x0c, 0, 0},
+ {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, {0x5863, 0x08, 0, 0},
+ {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, {0x5866, 0x18, 0, 0},
+ {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, {0x5869, 0x19, 0, 0},
+ {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, {0x586c, 0x13, 0, 0},
+ {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, {0x586f, 0x16, 0, 0},
+ {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, {0x5872, 0x10, 0, 0},
+ {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, {0x5875, 0x16, 0, 0},
+ {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, {0x5878, 0x10, 0, 0},
+ {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, {0x587b, 0x14, 0, 0},
+ {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, {0x587e, 0x11, 0, 0},
+ {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, {0x5881, 0x15, 0, 0},
+ {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, {0x5884, 0x15, 0, 0},
+ {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, {0x5887, 0x17, 0, 0},
+ {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, {0x3702, 0x10, 0, 0},
+ {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, {0x370b, 0x40, 0, 0},
+ {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, {0x3632, 0x52, 0, 0},
+ {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, {0x5785, 0x07, 0, 0},
+ {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, {0x3604, 0x48, 0, 0},
+ {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, {0x370f, 0xc0, 0, 0},
+ {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, {0x5007, 0x00, 0, 0},
+ {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, {0x5013, 0x00, 0, 0},
+ {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, {0x5087, 0x00, 0, 0},
+ {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, {0x302b, 0x00, 0, 0},
+ {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0},
+ {0x380b, 0x90, 0, 0}, {0x3a00, 0x78, 0, 0},
+};
+
+static struct reg_value ov5642_setting_30fps_QCIF_176_144[] = {
+ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0},
+ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0},
+ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0},
+ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0},
+ {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x10, 0, 0},
+ {0x3010, 0x10, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0},
+ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0},
+ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0},
+ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0},
+ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0},
+ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0},
+ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0},
+ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0},
+ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0},
+ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0},
+ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0},
+ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0},
+ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0},
+ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3501, 0x1e, 0, 0},
+ {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, {0x380c, 0x0c, 0, 0},
+ {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3818, 0xc1, 0, 0},
+ {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, {0x3801, 0x80, 0, 0},
+ {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0},
+ {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, {0x3804, 0x05, 0, 0},
+ {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0},
+ {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0},
+ {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x05, 0, 0},
+ {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0},
+ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0},
+ {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0},
+ {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, {0x3502, 0x00, 0, 0},
+ {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, {0x3503, 0x00, 0, 0},
+ {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0},
+ {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, {0x528f, 0x10, 0, 0},
+ {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x02, 0, 0},
+ {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, {0x5296, 0x00, 0, 0},
+ {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x02, 0, 0},
+ {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, {0x529c, 0x00, 0, 0},
+ {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x02, 0, 0},
+ {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3c, 0, 0},
+ {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, {0x3a1f, 0x10, 0, 0},
+ {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, {0x3a03, 0x7d, 0, 0},
+ {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, {0x3a15, 0x7d, 0, 0},
+ {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a08, 0x09, 0, 0},
+ {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, {0x3a0b, 0xd0, 0, 0},
+ {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x06, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, {0x401e, 0x20, 0, 0},
+ {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, {0x528a, 0x01, 0, 0},
+ {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, {0x528d, 0x10, 0, 0},
+ {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, {0x5290, 0x30, 0, 0},
+ {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, {0x5294, 0x00, 0, 0},
+ {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, {0x5297, 0x08, 0, 0},
+ {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, {0x529a, 0x00, 0, 0},
+ {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, {0x529d, 0x28, 0, 0},
+ {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, {0x5282, 0x00, 0, 0},
+ {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, {0x5302, 0x00, 0, 0},
+ {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, {0x530d, 0x0c, 0, 0},
+ {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, {0x5310, 0x20, 0, 0},
+ {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, {0x5309, 0x40, 0, 0},
+ {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x00, 0, 0},
+ {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, {0x5315, 0x20, 0, 0},
+ {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, {0x5317, 0x00, 0, 0},
+ {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, {0x5381, 0x00, 0, 0},
+ {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, {0x5384, 0x00, 0, 0},
+ {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, {0x5387, 0x00, 0, 0},
+ {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, {0x538a, 0x00, 0, 0},
+ {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, {0x538d, 0x00, 0, 0},
+ {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, {0x5390, 0x00, 0, 0},
+ {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, {0x5393, 0xa2, 0, 0},
+ {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, {0x5481, 0x21, 0, 0},
+ {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, {0x5484, 0x65, 0, 0},
+ {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, {0x5487, 0x87, 0, 0},
+ {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, {0x548a, 0xaa, 0, 0},
+ {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, {0x548d, 0xdd, 0, 0},
+ {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, {0x5490, 0x05, 0, 0},
+ {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, {0x5493, 0x20, 0, 0},
+ {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, {0x5496, 0x02, 0, 0},
+ {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, {0x5499, 0x86, 0, 0},
+ {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, {0x549c, 0x02, 0, 0},
+ {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, {0x549f, 0x1c, 0, 0},
+ {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, {0x54a2, 0x01, 0, 0},
+ {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, {0x54a5, 0xc5, 0, 0},
+ {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, {0x54a8, 0x01, 0, 0},
+ {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, {0x54ab, 0x41, 0, 0},
+ {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, {0x54ae, 0x00, 0, 0},
+ {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, {0x54b1, 0x20, 0, 0},
+ {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, {0x54b4, 0x00, 0, 0},
+ {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, {0x54b7, 0xdf, 0, 0},
+ {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, {0x3406, 0x00, 0, 0},
+ {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, {0x5182, 0x11, 0, 0},
+ {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0},
+ {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, {0x5188, 0x08, 0, 0},
+ {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, {0x518b, 0xb2, 0, 0},
+ {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, {0x518e, 0x3d, 0, 0},
+ {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0},
+ {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0},
+ {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0},
+ {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, {0x519a, 0x04, 0, 0},
+ {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, {0x519d, 0x82, 0, 0},
+ {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, {0x3a0f, 0x38, 0, 0},
+ {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, {0x3a1e, 0x2e, 0, 0},
+ {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, {0x5688, 0xa6, 0, 0},
+ {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, {0x568b, 0xae, 0, 0},
+ {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, {0x568e, 0x62, 0, 0},
+ {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x40, 0, 0},
+ {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, {0x5800, 0x27, 0, 0},
+ {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, {0x5803, 0x0f, 0, 0},
+ {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, {0x5806, 0x1e, 0, 0},
+ {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, {0x5809, 0x0d, 0, 0},
+ {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, {0x580c, 0x0a, 0, 0},
+ {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, {0x580f, 0x19, 0, 0},
+ {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, {0x5812, 0x04, 0, 0},
+ {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, {0x5815, 0x06, 0, 0},
+ {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, {0x5818, 0x0a, 0, 0},
+ {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, {0x581b, 0x00, 0, 0},
+ {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, {0x581e, 0x08, 0, 0},
+ {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, {0x5821, 0x05, 0, 0},
+ {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, {0x5824, 0x00, 0, 0},
+ {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, {0x5827, 0x0c, 0, 0},
+ {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, {0x582a, 0x06, 0, 0},
+ {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, {0x582d, 0x07, 0, 0},
+ {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, {0x5830, 0x18, 0, 0},
+ {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, {0x5833, 0x0a, 0, 0},
+ {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, {0x5836, 0x15, 0, 0},
+ {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, {0x5839, 0x1f, 0, 0},
+ {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, {0x583c, 0x17, 0, 0},
+ {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, {0x583f, 0x53, 0, 0},
+ {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, {0x5842, 0x0d, 0, 0},
+ {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, {0x5845, 0x09, 0, 0},
+ {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, {0x5848, 0x10, 0, 0},
+ {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, {0x584b, 0x0e, 0, 0},
+ {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, {0x584e, 0x11, 0, 0},
+ {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, {0x5851, 0x0c, 0, 0},
+ {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, {0x5854, 0x10, 0, 0},
+ {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, {0x5857, 0x0b, 0, 0},
+ {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, {0x585a, 0x0d, 0, 0},
+ {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, {0x585d, 0x0c, 0, 0},
+ {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, {0x5860, 0x0c, 0, 0},
+ {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, {0x5863, 0x08, 0, 0},
+ {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, {0x5866, 0x18, 0, 0},
+ {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, {0x5869, 0x19, 0, 0},
+ {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, {0x586c, 0x13, 0, 0},
+ {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, {0x586f, 0x16, 0, 0},
+ {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, {0x5872, 0x10, 0, 0},
+ {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, {0x5875, 0x16, 0, 0},
+ {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, {0x5878, 0x10, 0, 0},
+ {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, {0x587b, 0x14, 0, 0},
+ {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, {0x587e, 0x11, 0, 0},
+ {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, {0x5881, 0x15, 0, 0},
+ {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, {0x5884, 0x15, 0, 0},
+ {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, {0x5887, 0x17, 0, 0},
+ {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, {0x3702, 0x10, 0, 0},
+ {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, {0x370b, 0x40, 0, 0},
+ {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, {0x3632, 0x52, 0, 0},
+ {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, {0x5785, 0x07, 0, 0},
+ {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, {0x3604, 0x48, 0, 0},
+ {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, {0x370f, 0xc0, 0, 0},
+ {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, {0x5007, 0x00, 0, 0},
+ {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, {0x5013, 0x00, 0, 0},
+ {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, {0x5087, 0x00, 0, 0},
+ {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, {0x302b, 0x00, 0, 0},
+ {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0},
+ {0x380b, 0x90, 0, 0}, {0x3a00, 0x78, 0, 0},
+};
+
+static struct reg_value ov5642_setting_15fps_QSXGA_2592_1944[] = {
+ {0x3503, 0x07, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0},
+ {0x3002, 0x00, 0, 0}, {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0},
+ {0x3005, 0xff, 0, 0}, {0x3006, 0xff, 0, 0}, {0x3007, 0x3f, 0, 0},
+ {0x3011, 0x08, 0, 0}, {0x3010, 0x10, 0, 0}, {0x3818, 0xc0, 0, 0},
+ {0x3621, 0x09, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0},
+ {0x3602, 0xe4, 0, 0}, {0x3612, 0xac, 0, 0}, {0x3613, 0x44, 0, 0},
+ {0x3622, 0x60, 0, 0}, {0x3623, 0x22, 0, 0}, {0x3604, 0x48, 0, 0},
+ {0x3705, 0xda, 0, 0}, {0x370a, 0x80, 0, 0}, {0x3801, 0x95, 0, 0},
+ {0x3803, 0x0e, 0, 0}, {0x3804, 0x0a, 0, 0}, {0x3805, 0x20, 0, 0},
+ {0x3806, 0x07, 0, 0}, {0x3807, 0x98, 0, 0}, {0x3808, 0x0a, 0, 0},
+ {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0},
+ {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, {0x380e, 0x07, 0, 0},
+ {0x380f, 0xd0, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3815, 0x44, 0, 0},
+ {0x3824, 0x11, 0, 0}, {0x3825, 0xac, 0, 0}, {0x3827, 0x0c, 0, 0},
+ {0x3a00, 0x78, 0, 0}, {0x3a0d, 0x10, 0, 0}, {0x3a0e, 0x0d, 0, 0},
+ {0x5682, 0x0a, 0, 0}, {0x5683, 0x20, 0, 0}, {0x5686, 0x07, 0, 0},
+ {0x5687, 0x98, 0, 0}, {0x5001, 0xff, 0, 0}, {0x589b, 0x00, 0, 0},
+ {0x589a, 0xc0, 0, 0}, {0x4407, 0x04, 0, 0}, {0x3008, 0x02, 0, 0},
+ {0x460b, 0x37, 0, 0}, {0x460c, 0x22, 0, 0}, {0x471d, 0x05, 0, 0},
+ {0x4713, 0x03, 0, 0}, {0x471c, 0xd0, 0, 0}, {0x3815, 0x01, 0, 0},
+ {0x501f, 0x00, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3819, 0x80, 0, 0},
+ {0x5002, 0xe0, 0, 0}, {0x530a, 0x01, 0, 0}, {0x530d, 0x10, 0, 0},
+ {0x530c, 0x04, 0, 0}, {0x5312, 0x20, 0, 0}, {0x5282, 0x01, 0, 0},
+ {0x3010, 0x10, 0, 0}, {0x3012, 0x00, 0, 0},
+};
+
+
+static struct reg_value ov5642_setting_VGA_2_QVGA[] = {
+ {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0},
+ {0x380b, 0xf0, 0, 0}, {0x3815, 0x04, 0, 0},
+};
+
+static struct reg_value ov5642_setting_QSXGA_2_VGA[] = {
+ {0x3503, 0x00, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0},
+ {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0},
+ {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0},
+ {0x3010, 0x00, 0, 0}, {0x3818, 0xc1, 0, 0}, {0x3621, 0x87, 0, 0},
+ {0x350c, 0x03, 0, 0}, {0x350d, 0xe8, 0, 0}, {0x3602, 0xfc, 0, 0},
+ {0x3612, 0xff, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3622, 0x60, 0, 0},
+ {0x3623, 0x01, 0, 0}, {0x3604, 0x48, 0, 0}, {0x3705, 0xdb, 0, 0},
+ {0x370a, 0x81, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0},
+ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x3806, 0x03, 0, 0},
+ {0x3807, 0xc0, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0},
+ {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x0c, 0, 0},
+ {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0},
+ {0x3810, 0x40, 0, 0}, {0x3815, 0x04, 0, 0}, {0x3824, 0x11, 0, 0},
+ {0x3825, 0xb4, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x5682, 0x05, 0, 0},
+ {0x5683, 0x00, 0, 0}, {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0},
+ {0x5001, 0xff, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0},
+ {0x4407, 0x0c, 0, 0}, {0x3008, 0x02, 0, 0}, {0x460b, 0x37, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x471d, 0x05, 0, 0}, {0x4713, 0x02, 0, 0},
+ {0x471c, 0xd0, 0, 0}, {0x3815, 0x04, 0, 0}, {0x501f, 0x00, 0, 0},
+ {0x3002, 0x5c, 0, 0}, {0x3819, 0x80, 0, 0}, {0x5002, 0xe0, 0, 0},
+ {0x530a, 0x01, 0, 0}, {0x530d, 0x0c, 0, 0}, {0x530c, 0x00, 0, 0},
+ {0x5312, 0x40, 0, 0}, {0x5282, 0x00, 0, 0},
+ {0x3012, 0x02, 0, 0}, {0x3010, 0x00, 0, 0},
+};
+
+static struct reg_value ov5642_setting_30fps_VGA_640_480[] = {
+ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0},
+ {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0},
+ {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0},
+ {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0},
+ {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0},
+ {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0},
+ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0},
+ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0},
+ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0},
+ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0},
+ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0},
+ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0},
+ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0},
+ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0},
+ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0},
+ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0},
+ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0},
+ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0},
+ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0},
+ {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0},
+ {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x03, 0, 0},
+ {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0},
+ {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0},
+ {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x80, 0, 0},
+ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0},
+ {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0},
+ {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0},
+ {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0},
+ {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0},
+ {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0},
+ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0},
+ {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0},
+ {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0},
+ {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0},
+ {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0},
+ {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0},
+ {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0},
+ {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0},
+ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0},
+ {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0},
+ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0},
+ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0},
+ {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0},
+ {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0},
+ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0},
+ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0},
+ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0},
+ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0},
+ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0},
+ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0},
+ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0},
+ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0},
+ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0},
+ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0},
+ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0},
+ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0},
+ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0},
+ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0},
+ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0},
+ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0},
+ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0},
+ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0},
+ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0},
+ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0},
+ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0},
+ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0},
+ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0},
+ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0},
+ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0},
+ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0},
+ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0},
+ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0},
+ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0},
+ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0},
+ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0},
+ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0},
+ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0},
+ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0},
+ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0},
+ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0},
+ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0},
+ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0},
+ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0},
+ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0},
+ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0},
+ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0},
+ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0},
+ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0},
+ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0},
+ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0},
+ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0},
+ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0},
+ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0},
+ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0},
+ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0},
+ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0},
+ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0},
+ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0},
+ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0},
+ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0},
+ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0},
+ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0},
+ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0},
+ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0},
+ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0},
+ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0},
+ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0},
+ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0},
+ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0},
+ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0},
+ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0},
+ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0},
+ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0},
+ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0},
+ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0},
+ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0},
+ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0},
+ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0},
+ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0},
+ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0},
+ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0},
+ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0},
+ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0},
+ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0},
+ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0},
+ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0},
+ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0},
+ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0},
+ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0},
+ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0},
+ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0},
+ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0},
+ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0},
+ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0},
+ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0},
+ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0},
+ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0},
+ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0},
+ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0},
+ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0},
+ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0},
+ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0},
+ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0},
+ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0},
+ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0},
+ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0},
+ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0},
+ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0},
+ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0},
+ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0},
+ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0},
+ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0},
+ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0},
+ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0},
+ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0},
+ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0},
+ {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0},
+};
+
+static struct reg_value ov5642_setting_15fps_VGA_640_480[] = {
+ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0},
+ {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0},
+ {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0},
+ {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0},
+ {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0},
+ {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0},
+ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0},
+ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0},
+ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0},
+ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0},
+ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0},
+ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0},
+ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0},
+ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0},
+ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0},
+ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0},
+ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0},
+ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0},
+ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0},
+ {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0},
+ {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x07, 0, 0},
+ {0x380f, 0xd0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0},
+ {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0},
+ {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x80, 0, 0},
+ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0},
+ {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0},
+ {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0},
+ {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0},
+ {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0},
+ {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0},
+ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0},
+ {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0},
+ {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0},
+ {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0},
+ {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0},
+ {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0},
+ {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0},
+ {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0},
+ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0},
+ {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0},
+ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0},
+ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0},
+ {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0},
+ {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0},
+ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0},
+ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0},
+ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0},
+ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0},
+ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0},
+ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0},
+ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0},
+ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0},
+ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0},
+ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0},
+ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0},
+ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0},
+ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0},
+ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0},
+ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0},
+ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0},
+ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0},
+ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0},
+ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0},
+ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0},
+ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0},
+ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0},
+ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0},
+ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0},
+ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0},
+ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0},
+ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0},
+ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0},
+ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0},
+ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0},
+ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0},
+ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0},
+ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0},
+ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0},
+ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0},
+ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0},
+ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0},
+ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0},
+ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0},
+ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0},
+ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0},
+ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0},
+ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0},
+ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0},
+ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0},
+ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0},
+ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0},
+ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0},
+ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0},
+ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0},
+ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0},
+ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0},
+ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0},
+ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0},
+ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0},
+ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0},
+ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0},
+ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0},
+ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0},
+ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0},
+ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0},
+ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0},
+ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0},
+ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0},
+ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0},
+ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0},
+ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0},
+ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0},
+ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0},
+ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0},
+ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0},
+ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0},
+ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0},
+ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0},
+ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0},
+ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0},
+ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0},
+ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0},
+ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0},
+ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0},
+ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0},
+ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0},
+ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0},
+ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0},
+ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0},
+ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0},
+ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0},
+ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0},
+ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0},
+ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0},
+ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0},
+ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0},
+ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0},
+ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0},
+ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0},
+ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0},
+ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0},
+ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0},
+ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0},
+ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0},
+ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0},
+ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0},
+ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0},
+ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0},
+ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0},
+ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0},
+ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0},
+ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0},
+ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0},
+ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0},
+ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0},
+ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0},
+ {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0},
+};
+
+
+static struct reg_value ov5642_setting_30fps_XGA_1024_768[] = {
+ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0},
+ {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0},
+ {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0},
+ {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0},
+ {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0},
+ {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0},
+ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0},
+ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0},
+ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0},
+ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0},
+ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0},
+ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0},
+ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0},
+ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0},
+ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0},
+ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0},
+ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0},
+ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0},
+ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0},
+ {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0},
+ {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x03, 0, 0},
+ {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0},
+ {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0},
+ {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x80, 0, 0},
+ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0},
+ {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0},
+ {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0},
+ {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0},
+ {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0},
+ {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0},
+ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0},
+ {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0},
+ {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0},
+ {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0},
+ {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0},
+ {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0},
+ {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0},
+ {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0},
+ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0},
+ {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0},
+ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0},
+ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0},
+ {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0},
+ {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0},
+ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0},
+ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0},
+ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0},
+ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0},
+ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0},
+ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0},
+ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0},
+ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0},
+ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0},
+ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0},
+ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0},
+ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0},
+ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0},
+ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0},
+ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0},
+ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0},
+ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0},
+ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0},
+ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0},
+ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0},
+ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0},
+ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0},
+ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0},
+ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0},
+ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0},
+ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0},
+ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0},
+ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0},
+ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0},
+ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0},
+ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0},
+ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0},
+ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0},
+ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0},
+ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0},
+ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0},
+ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0},
+ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0},
+ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0},
+ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0},
+ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0},
+ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0},
+ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0},
+ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0},
+ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0},
+ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0},
+ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0},
+ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0},
+ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0},
+ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0},
+ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0},
+ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0},
+ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0},
+ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0},
+ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0},
+ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0},
+ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0},
+ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0},
+ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0},
+ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0},
+ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0},
+ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0},
+ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0},
+ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0},
+ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0},
+ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0},
+ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0},
+ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0},
+ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0},
+ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0},
+ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0},
+ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0},
+ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0},
+ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0},
+ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0},
+ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0},
+ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0},
+ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0},
+ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0},
+ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0},
+ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0},
+ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0},
+ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0},
+ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0},
+ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0},
+ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0},
+ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0},
+ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0},
+ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0},
+ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0},
+ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0},
+ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0},
+ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0},
+ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0},
+ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0},
+ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0},
+ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0},
+ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0},
+ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0},
+ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0},
+ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0},
+ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0},
+ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0},
+ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0},
+ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0},
+ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0},
+ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0},
+ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0},
+ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0},
+ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0},
+ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0},
+ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0},
+ {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0},
+ {0x380b, 0x00, 0, 0}, {0x3815, 0x02, 0, 0}, {0x302c, 0x60, 0x60, 0},
+};
+
+static struct reg_value ov5642_setting_15fps_XGA_1024_768[] = {
+ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0},
+ {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0},
+ {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0},
+ {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0},
+ {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0},
+ {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0},
+ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0},
+ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0},
+ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0},
+ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0},
+ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0},
+ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0},
+ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0},
+ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0},
+ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0},
+ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0},
+ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0},
+ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0},
+ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0},
+ {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0},
+ {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x07, 0, 0},
+ {0x380f, 0xd0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0},
+ {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0},
+ {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x80, 0, 0},
+ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0},
+ {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0},
+ {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0},
+ {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0},
+ {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0},
+ {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0},
+ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0},
+ {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0},
+ {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0},
+ {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0},
+ {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0},
+ {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0},
+ {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0},
+ {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0},
+ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0},
+ {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0},
+ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0},
+ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0},
+ {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0},
+ {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0},
+ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0},
+ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0},
+ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0},
+ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0},
+ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0},
+ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0},
+ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0},
+ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0},
+ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0},
+ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0},
+ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0},
+ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0},
+ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0},
+ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0},
+ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0},
+ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0},
+ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0},
+ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0},
+ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0},
+ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0},
+ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0},
+ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0},
+ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0},
+ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0},
+ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0},
+ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0},
+ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0},
+ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0},
+ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0},
+ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0},
+ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0},
+ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0},
+ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0},
+ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0},
+ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0},
+ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0},
+ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0},
+ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0},
+ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0},
+ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0},
+ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0},
+ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0},
+ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0},
+ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0},
+ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0},
+ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0},
+ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0},
+ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0},
+ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0},
+ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0},
+ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0},
+ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0},
+ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0},
+ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0},
+ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0},
+ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0},
+ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0},
+ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0},
+ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0},
+ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0},
+ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0},
+ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0},
+ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0},
+ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0},
+ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0},
+ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0},
+ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0},
+ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0},
+ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0},
+ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0},
+ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0},
+ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0},
+ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0},
+ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0},
+ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0},
+ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0},
+ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0},
+ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0},
+ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0},
+ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0},
+ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0},
+ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0},
+ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0},
+ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0},
+ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0},
+ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0},
+ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0},
+ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0},
+ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0},
+ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0},
+ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0},
+ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0},
+ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0},
+ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0},
+ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0},
+ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0},
+ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0},
+ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0},
+ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0},
+ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0},
+ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0},
+ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0},
+ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0},
+ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0},
+ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0},
+ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0},
+ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0},
+ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0},
+ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0},
+ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0},
+ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0},
+ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0},
+ {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0},
+ {0x380b, 0x00, 0, 0}, {0x3815, 0x02, 0, 0}, {0x302c, 0x60, 0x60, 0},
+};
+
+static struct reg_value ov5642_setting_30fps_QVGA_320_240[] = {
+ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0},
+ {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0},
+ {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0},
+ {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0},
+ {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0},
+ {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0},
+ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0},
+ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0},
+ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0},
+ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0},
+ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0},
+ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0},
+ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0},
+ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0},
+ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0},
+ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0},
+ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0},
+ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0},
+ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0},
+ {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0},
+ {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x03, 0, 0},
+ {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0},
+ {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0},
+ {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x80, 0, 0},
+ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0},
+ {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0},
+ {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0},
+ {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0},
+ {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0},
+ {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0},
+ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0},
+ {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0},
+ {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0},
+ {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0},
+ {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0},
+ {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0},
+ {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0},
+ {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0},
+ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0},
+ {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0},
+ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0},
+ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0},
+ {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0},
+ {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0},
+ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0},
+ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0},
+ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0},
+ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0},
+ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0},
+ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0},
+ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0},
+ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0},
+ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0},
+ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0},
+ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0},
+ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0},
+ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0},
+ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0},
+ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0},
+ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0},
+ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0},
+ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0},
+ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0},
+ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0},
+ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0},
+ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0},
+ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0},
+ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0},
+ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0},
+ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0},
+ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0},
+ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0},
+ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0},
+ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0},
+ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0},
+ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0},
+ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0},
+ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0},
+ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0},
+ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0},
+ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0},
+ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0},
+ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0},
+ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0},
+ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0},
+ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0},
+ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0},
+ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0},
+ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0},
+ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0},
+ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0},
+ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0},
+ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0},
+ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0},
+ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0},
+ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0},
+ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0},
+ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0},
+ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0},
+ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0},
+ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0},
+ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0},
+ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0},
+ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0},
+ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0},
+ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0},
+ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0},
+ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0},
+ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0},
+ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0},
+ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0},
+ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0},
+ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0},
+ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0},
+ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0},
+ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0},
+ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0},
+ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0},
+ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0},
+ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0},
+ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0},
+ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0},
+ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0},
+ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0},
+ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0},
+ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0},
+ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0},
+ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0},
+ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0},
+ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0},
+ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0},
+ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0},
+ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0},
+ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0},
+ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0},
+ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0},
+ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0},
+ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0},
+ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0},
+ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0},
+ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0},
+ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0},
+ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0},
+ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0},
+ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0},
+ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0},
+ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0},
+ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0},
+ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0},
+ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0},
+ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0},
+ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0},
+ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0},
+ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0},
+ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0},
+ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0},
+ {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3808, 0x01, 0, 0},
+ {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0},
+};
+
+static struct reg_value ov5642_setting_30fps_NTSC_720_480[] = {
+ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0},
+ {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0},
+ {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0},
+ {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0},
+ {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0},
+ {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0},
+ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0},
+ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0},
+ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0},
+ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0},
+ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0},
+ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0},
+ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0},
+ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0},
+ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0},
+ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0},
+ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0},
+ {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0},
+ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0},
+ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0},
+ {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0},
+ {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x03, 0, 0},
+ {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0},
+ {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0},
+ {0x3803, 0x08, 0, 0}, {0x3827, 0x3c, 0, 0}, {0x3810, 0x80, 0, 0},
+ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0},
+ {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0x58, 0, 0},
+ {0x5686, 0x03, 0, 0}, {0x5687, 0x58, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0},
+ {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0},
+ {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0},
+ {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0},
+ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0},
+ {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0},
+ {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0},
+ {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0},
+ {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0},
+ {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0},
+ {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0},
+ {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0},
+ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0},
+ {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0},
+ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0},
+ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0},
+ {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0},
+ {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0},
+ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0},
+ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0},
+ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0},
+ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0},
+ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0},
+ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0},
+ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0},
+ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0},
+ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0},
+ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0},
+ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0},
+ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0},
+ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0},
+ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0},
+ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0},
+ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0},
+ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0},
+ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0},
+ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0},
+ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0},
+ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0},
+ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0},
+ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0},
+ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0},
+ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0},
+ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0},
+ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0},
+ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0},
+ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0},
+ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0},
+ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0},
+ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0},
+ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0},
+ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0},
+ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0},
+ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0},
+ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0},
+ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0},
+ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0},
+ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0},
+ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0},
+ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0},
+ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0},
+ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0},
+ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0},
+ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0},
+ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0},
+ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0},
+ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0},
+ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0},
+ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0},
+ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0},
+ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0},
+ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0},
+ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0},
+ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0},
+ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0},
+ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0},
+ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0},
+ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0},
+ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0},
+ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0},
+ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0},
+ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0},
+ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0},
+ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0},
+ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0},
+ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0},
+ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0},
+ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0},
+ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0},
+ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0},
+ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0},
+ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0},
+ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0},
+ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0},
+ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0},
+ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0},
+ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0},
+ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0},
+ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0},
+ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0},
+ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0},
+ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0},
+ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0},
+ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0},
+ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0},
+ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0},
+ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0},
+ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0},
+ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0},
+ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0},
+ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0},
+ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0},
+ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0},
+ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0},
+ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0},
+ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0},
+ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0},
+ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0},
+ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0},
+ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0},
+ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0},
+ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0},
+ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0},
+ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0},
+ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0},
+ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0},
+ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0},
+ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0},
+ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0},
+ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0},
+ {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x302c, 0x60, 0x60, 0},
+};
+
+static struct reg_value ov5642_setting_30fps_PAL_720_576[] = {
+ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0},
+ {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0},
+ {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0},
+ {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0},
+ {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0},
+ {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0},
+ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0},
+ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0},
+ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0},
+ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0},
+ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0},
+ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0},
+ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0},
+ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0},
+ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0},
+ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0},
+ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0},
+ {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0},
+ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0},
+ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xd8, 0, 0},
+ {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0},
+ {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x03, 0, 0},
+ {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0},
+ {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0},
+ {0x3803, 0x08, 0, 0}, {0x3827, 0x3c, 0, 0}, {0x3810, 0x80, 0, 0},
+ {0x3804, 0x04, 0, 0}, {0x3805, 0xb0, 0, 0}, {0x5682, 0x04, 0, 0},
+ {0x5683, 0xb0, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0x58, 0, 0},
+ {0x5686, 0x03, 0, 0}, {0x5687, 0x58, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0},
+ {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0},
+ {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0},
+ {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0},
+ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0},
+ {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0},
+ {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0},
+ {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0},
+ {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0},
+ {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0},
+ {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0},
+ {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0},
+ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0},
+ {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0},
+ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0},
+ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0},
+ {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0},
+ {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0},
+ {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0},
+ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0},
+ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0},
+ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0},
+ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0},
+ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0},
+ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0},
+ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0},
+ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0},
+ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0},
+ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0},
+ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0},
+ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0},
+ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0},
+ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0},
+ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0},
+ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0},
+ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0},
+ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0},
+ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0},
+ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0},
+ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0},
+ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0},
+ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0},
+ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0},
+ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0},
+ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0},
+ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0},
+ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0},
+ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0},
+ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0},
+ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0},
+ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0},
+ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0},
+ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0},
+ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0},
+ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0},
+ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0},
+ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0},
+ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0},
+ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0},
+ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0},
+ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0},
+ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0},
+ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0},
+ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0},
+ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0},
+ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0},
+ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0},
+ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0},
+ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0},
+ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0},
+ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0},
+ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0},
+ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0},
+ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0},
+ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0},
+ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0},
+ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0},
+ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0},
+ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0},
+ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0},
+ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0},
+ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0},
+ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0},
+ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0},
+ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0},
+ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0},
+ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0},
+ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0},
+ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0},
+ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0},
+ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0},
+ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0},
+ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0},
+ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0},
+ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0},
+ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0},
+ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0},
+ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0},
+ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0},
+ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0},
+ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0},
+ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0},
+ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0},
+ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0},
+ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0},
+ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0},
+ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0},
+ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0},
+ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0},
+ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0},
+ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0},
+ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0},
+ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0},
+ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0},
+ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0},
+ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0},
+ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0},
+ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0},
+ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0},
+ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0},
+ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0},
+ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0},
+ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0},
+ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0},
+ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0},
+ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0},
+ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0},
+ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0},
+ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0},
+ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0},
+ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0},
+ {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x302c, 0x60, 0x60, 0},
+};
+
+static struct reg_value ov5642_setting_15fps_720P_1280_720[] = {
+ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0},
+ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0},
+ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x00, 0, 0},
+ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3030, 0x2b, 0, 0},
+ {0x3011, 0x08, 0, 0}, {0x3010, 0x10, 0, 0}, {0x3604, 0x60, 0, 0},
+ {0x3622, 0x60, 0, 0}, {0x3621, 0x09, 0, 0}, {0x3709, 0x00, 0, 0},
+ {0x4000, 0x21, 0, 0}, {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0},
+ {0x3605, 0x04, 0, 0}, {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0},
+ {0x300d, 0x22, 0, 0}, {0x3623, 0x22, 0, 0}, {0x5000, 0x4f, 0, 0},
+ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0},
+ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5500, 0x0a, 0, 0},
+ {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, {0x5080, 0x08, 0, 0},
+ {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, {0x471d, 0x05, 0, 0},
+ {0x4708, 0x06, 0, 0}, {0x370c, 0xa0, 0, 0}, {0x3808, 0x0a, 0, 0},
+ {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0},
+ {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, {0x380e, 0x07, 0, 0},
+ {0x380f, 0xd0, 0, 0}, {0x5687, 0x94, 0, 0}, {0x501f, 0x00, 0, 0},
+ {0x5000, 0x4f, 0, 0}, {0x5001, 0xcf, 0, 0}, {0x4300, 0x30, 0, 0},
+ {0x4300, 0x30, 0, 0}, {0x460b, 0x35, 0, 0}, {0x471d, 0x00, 0, 0},
+ {0x3002, 0x0c, 0, 0}, {0x3002, 0x00, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x471c, 0x50, 0, 0}, {0x4721, 0x02, 0, 0}, {0x4402, 0x90, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x3815, 0x44, 0, 0}, {0x3503, 0x07, 0, 0},
+ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3818, 0xc8, 0, 0}, {0x3801, 0x88, 0, 0}, {0x3824, 0x11, 0, 0},
+ {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x04, 0, 0}, {0x3a13, 0x30, 0, 0},
+ {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0},
+ {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0},
+ {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, {0x3a0d, 0x08, 0, 0},
+ {0x3a0e, 0x06, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0},
+ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x00, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x32, 0, 0},
+ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x32, 0, 0}, {0x3a11, 0x80, 0, 0},
+ {0x3a1f, 0x20, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0},
+ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0},
+ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a08, 0x09, 0, 0}, {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0},
+ {0x3a0b, 0xd0, 0, 0}, {0x3a0d, 0x10, 0, 0}, {0x3a0e, 0x0d, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x589b, 0x00, 0, 0},
+ {0x589a, 0xc0, 0, 0}, {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0},
+ {0x401c, 0x06, 0, 0}, {0x3825, 0xac, 0, 0}, {0x3827, 0x0c, 0, 0},
+ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0},
+ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0},
+ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0},
+ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0},
+ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0},
+ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0},
+ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0},
+ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0},
+ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0},
+ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0},
+ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0},
+ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0},
+ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0},
+ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0},
+ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0},
+ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0},
+ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0},
+ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0},
+ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0},
+ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0},
+ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0},
+ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0},
+ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0},
+ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0},
+ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0},
+ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0},
+ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0},
+ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0},
+ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0},
+ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0},
+ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0},
+ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0},
+ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0},
+ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0},
+ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0},
+ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0},
+ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0},
+ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0},
+ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0},
+ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0},
+ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0},
+ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0},
+ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0},
+ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0},
+ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0},
+ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0},
+ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0},
+ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0},
+ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0},
+ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0},
+ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0},
+ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0},
+ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0},
+ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0},
+ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0},
+ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0},
+ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0},
+ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0},
+ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0},
+ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0},
+ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0},
+ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0},
+ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0},
+ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0},
+ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0},
+ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0},
+ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0},
+ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0},
+ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0},
+ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0},
+ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0},
+ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0},
+ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0},
+ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0},
+ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0},
+ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0},
+ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0},
+ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0},
+ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0},
+ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0},
+ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0},
+ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0},
+ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0},
+ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0},
+ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0},
+ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0},
+ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0},
+ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0},
+ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0},
+ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0},
+ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0},
+ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0},
+ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0},
+ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0},
+ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0},
+ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0},
+ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0},
+ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0},
+ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0},
+ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0},
+ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0},
+ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0},
+ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0},
+ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0},
+ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0},
+ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0},
+ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0},
+ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0},
+ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0},
+ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0},
+ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0},
+ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0},
+ {0x302b, 0x00, 0, 0}, {0x3503, 0x07, 0, 0}, {0x3011, 0x08, 0, 0},
+ {0x350c, 0x02, 0, 0}, {0x350d, 0xe4, 0, 0}, {0x3621, 0xc9, 0, 0},
+ {0x370a, 0x81, 0, 0}, {0x3803, 0x08, 0, 0}, {0x3804, 0x05, 0, 0},
+ {0x3805, 0x00, 0, 0}, {0x3806, 0x02, 0, 0}, {0x3807, 0xd0, 0, 0},
+ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+ {0x380b, 0xd0, 0, 0}, {0x380c, 0x08, 0, 0}, {0x380d, 0x72, 0, 0},
+ {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0xc0, 0, 0},
+ {0x3818, 0xc9, 0, 0}, {0x381c, 0x10, 0, 0}, {0x381d, 0xa0, 0, 0},
+ {0x381e, 0x05, 0, 0}, {0x381f, 0xb0, 0, 0}, {0x3820, 0x00, 0, 0},
+ {0x3821, 0x00, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3a08, 0x1b, 0, 0},
+ {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x17, 0, 0}, {0x3a0b, 0x20, 0, 0},
+ {0x3a0d, 0x02, 0, 0}, {0x3a0e, 0x01, 0, 0}, {0x401c, 0x04, 0, 0},
+ {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, {0x5686, 0x02, 0, 0},
+ {0x5687, 0xcc, 0, 0}, {0x5001, 0x7f, 0, 0}, {0x589b, 0x06, 0, 0},
+ {0x589a, 0xc5, 0, 0}, {0x3503, 0x00, 0, 0}, {0x3010, 0x10, 0, 0},
+ {0x460c, 0x20, 0, 0}, {0x460b, 0x37, 0, 0}, {0x471c, 0xd0, 0, 0},
+ {0x471d, 0x05, 0, 0}, {0x3815, 0x01, 0, 0}, {0x3818, 0x00, 0x08, 0},
+ {0x501f, 0x00, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3002, 0x1c, 0, 0},
+ {0x3819, 0x80, 0, 0}, {0x5002, 0xe0, 0, 0}, {0x3010, 0x30, 0, 0},
+ {0x3a08, 0x06, 0, 0}, {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x05, 0, 0},
+ {0x3a0b, 0x50, 0, 0}, {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x07, 0, 0},
+};
+
+static struct reg_value ov5642_setting_30fps_720P_1280_720[] = {
+ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0},
+ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0},
+ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x00, 0, 0},
+ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3030, 0x2b, 0, 0},
+ {0x3011, 0x08, 0, 0}, {0x3010, 0x10, 0, 0}, {0x3604, 0x60, 0, 0},
+ {0x3622, 0x60, 0, 0}, {0x3621, 0x09, 0, 0}, {0x3709, 0x00, 0, 0},
+ {0x4000, 0x21, 0, 0}, {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0},
+ {0x3605, 0x04, 0, 0}, {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0},
+ {0x300d, 0x22, 0, 0}, {0x3623, 0x22, 0, 0}, {0x5000, 0x4f, 0, 0},
+ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0},
+ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5500, 0x0a, 0, 0},
+ {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, {0x5080, 0x08, 0, 0},
+ {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, {0x471d, 0x05, 0, 0},
+ {0x4708, 0x06, 0, 0}, {0x370c, 0xa0, 0, 0}, {0x3808, 0x0a, 0, 0},
+ {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0},
+ {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, {0x380e, 0x07, 0, 0},
+ {0x380f, 0xd0, 0, 0}, {0x5687, 0x94, 0, 0}, {0x501f, 0x00, 0, 0},
+ {0x5000, 0x4f, 0, 0}, {0x5001, 0xcf, 0, 0}, {0x4300, 0x30, 0, 0},
+ {0x4300, 0x30, 0, 0}, {0x460b, 0x35, 0, 0}, {0x471d, 0x00, 0, 0},
+ {0x3002, 0x0c, 0, 0}, {0x3002, 0x00, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x471c, 0x50, 0, 0}, {0x4721, 0x02, 0, 0}, {0x4402, 0x90, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x3815, 0x44, 0, 0}, {0x3503, 0x07, 0, 0},
+ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3818, 0xc8, 0, 0}, {0x3801, 0x88, 0, 0}, {0x3824, 0x11, 0, 0},
+ {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x04, 0, 0}, {0x3a13, 0x30, 0, 0},
+ {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0},
+ {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0},
+ {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, {0x3a0d, 0x08, 0, 0},
+ {0x3a0e, 0x06, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0},
+ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x00, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x32, 0, 0},
+ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x32, 0, 0}, {0x3a11, 0x80, 0, 0},
+ {0x3a1f, 0x20, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0},
+ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0},
+ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a08, 0x09, 0, 0}, {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0},
+ {0x3a0b, 0xd0, 0, 0}, {0x3a0d, 0x10, 0, 0}, {0x3a0e, 0x0d, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x589b, 0x00, 0, 0},
+ {0x589a, 0xc0, 0, 0}, {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0},
+ {0x401c, 0x06, 0, 0}, {0x3825, 0xac, 0, 0}, {0x3827, 0x0c, 0, 0},
+ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0},
+ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0},
+ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0},
+ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0},
+ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0},
+ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0},
+ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0},
+ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0},
+ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0},
+ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0},
+ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0},
+ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0},
+ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0},
+ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0},
+ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0},
+ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0},
+ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0},
+ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0},
+ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0},
+ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0},
+ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0},
+ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0},
+ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0},
+ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0},
+ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0},
+ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0},
+ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0},
+ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0},
+ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0},
+ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0},
+ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0},
+ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0},
+ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0},
+ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0},
+ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0},
+ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0},
+ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0},
+ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0},
+ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0},
+ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0},
+ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0},
+ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0},
+ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0},
+ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0},
+ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0},
+ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0},
+ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0},
+ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0},
+ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0},
+ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0},
+ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0},
+ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0},
+ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0},
+ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0},
+ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0},
+ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0},
+ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0},
+ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0},
+ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0},
+ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0},
+ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0},
+ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0},
+ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0},
+ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0},
+ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0},
+ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0},
+ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0},
+ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0},
+ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0},
+ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0},
+ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0},
+ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0},
+ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0},
+ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0},
+ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0},
+ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0},
+ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0},
+ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0},
+ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0},
+ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0},
+ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0},
+ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0},
+ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0},
+ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0},
+ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0},
+ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0},
+ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0},
+ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0},
+ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0},
+ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0},
+ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0},
+ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0},
+ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0},
+ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0},
+ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0},
+ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0},
+ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0},
+ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0},
+ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0},
+ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0},
+ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0},
+ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0},
+ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0},
+ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0},
+ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0},
+ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0},
+ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0},
+ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0},
+ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0},
+ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0},
+ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0},
+ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0},
+ {0x302b, 0x00, 0, 0}, {0x3503, 0x07, 0, 0}, {0x3011, 0x08, 0, 0},
+ {0x350c, 0x02, 0, 0}, {0x350d, 0xe4, 0, 0}, {0x3621, 0xc9, 0, 0},
+ {0x370a, 0x81, 0, 0}, {0x3803, 0x08, 0, 0}, {0x3804, 0x05, 0, 0},
+ {0x3805, 0x00, 0, 0}, {0x3806, 0x02, 0, 0}, {0x3807, 0xd0, 0, 0},
+ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+ {0x380b, 0xd0, 0, 0}, {0x380c, 0x08, 0, 0}, {0x380d, 0x72, 0, 0},
+ {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0xc0, 0, 0},
+ {0x3818, 0xc9, 0, 0}, {0x381c, 0x10, 0, 0}, {0x381d, 0xa0, 0, 0},
+ {0x381e, 0x05, 0, 0}, {0x381f, 0xb0, 0, 0}, {0x3820, 0x00, 0, 0},
+ {0x3821, 0x00, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3a08, 0x1b, 0, 0},
+ {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x17, 0, 0}, {0x3a0b, 0x20, 0, 0},
+ {0x3a0d, 0x02, 0, 0}, {0x3a0e, 0x01, 0, 0}, {0x401c, 0x04, 0, 0},
+ {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, {0x5686, 0x02, 0, 0},
+ {0x5687, 0xcc, 0, 0}, {0x5001, 0x7f, 0, 0}, {0x589b, 0x06, 0, 0},
+ {0x589a, 0xc5, 0, 0}, {0x3503, 0x00, 0, 0}, {0x3010, 0x10, 0, 0},
+ {0x460c, 0x20, 0, 0}, {0x460b, 0x37, 0, 0}, {0x471c, 0xd0, 0, 0},
+ {0x471d, 0x05, 0, 0}, {0x3815, 0x01, 0, 0}, {0x3818, 0x00, 0x08, 0},
+ {0x501f, 0x00, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3002, 0x1c, 0, 0},
+ {0x3819, 0x80, 0, 0}, {0x5002, 0xe0, 0, 0},
+};
+
+static struct reg_value ov5642_setting_15fps_1080P_1920_1080[] = {
+ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0},
+ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0},
+ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x00, 0, 0},
+ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3030, 0x2b, 0, 0},
+ {0x3011, 0x08, 0, 0}, {0x3010, 0x10, 0, 0}, {0x3604, 0x60, 0, 0},
+ {0x3622, 0x60, 0, 0}, {0x3621, 0x09, 0, 0}, {0x3709, 0x00, 0, 0},
+ {0x4000, 0x21, 0, 0}, {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0},
+ {0x3605, 0x04, 0, 0}, {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0},
+ {0x300d, 0x22, 0, 0}, {0x3623, 0x22, 0, 0}, {0x5000, 0x4f, 0, 0},
+ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0},
+ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5500, 0x0a, 0, 0},
+ {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, {0x5080, 0x08, 0, 0},
+ {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, {0x471d, 0x05, 0, 0},
+ {0x4708, 0x06, 0, 0}, {0x370c, 0xa0, 0, 0}, {0x3808, 0x0a, 0, 0},
+ {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0},
+ {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, {0x380e, 0x07, 0, 0},
+ {0x380f, 0xd0, 0, 0}, {0x5687, 0x94, 0, 0}, {0x501f, 0x00, 0, 0},
+ {0x5000, 0x4f, 0, 0}, {0x5001, 0xcf, 0, 0}, {0x4300, 0x30, 0, 0},
+ {0x4300, 0x30, 0, 0}, {0x460b, 0x35, 0, 0}, {0x471d, 0x00, 0, 0},
+ {0x3002, 0x0c, 0, 0}, {0x3002, 0x00, 0, 0}, {0x4713, 0x03, 0, 0},
+ {0x471c, 0x50, 0, 0}, {0x4721, 0x02, 0, 0}, {0x4402, 0x90, 0, 0},
+ {0x460c, 0x22, 0, 0}, {0x3815, 0x44, 0, 0}, {0x3503, 0x07, 0, 0},
+ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3818, 0xc8, 0, 0}, {0x3801, 0x88, 0, 0}, {0x3824, 0x11, 0, 0},
+ {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x04, 0, 0}, {0x3a13, 0x30, 0, 0},
+ {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0},
+ {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0},
+ {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, {0x3a0d, 0x08, 0, 0},
+ {0x3a0e, 0x06, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0},
+ {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x00, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x32, 0, 0},
+ {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x32, 0, 0}, {0x3a11, 0x80, 0, 0},
+ {0x3a1f, 0x20, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0},
+ {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0},
+ {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0},
+ {0x3a08, 0x09, 0, 0}, {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0},
+ {0x3a0b, 0xd0, 0, 0}, {0x3a0d, 0x10, 0, 0}, {0x3a0e, 0x0d, 0, 0},
+ {0x4407, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x589b, 0x00, 0, 0},
+ {0x589a, 0xc0, 0, 0}, {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0},
+ {0x401c, 0x06, 0, 0}, {0x3825, 0xac, 0, 0}, {0x3827, 0x0c, 0, 0},
+ {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0},
+ {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0},
+ {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0},
+ {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0},
+ {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0},
+ {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0},
+ {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0},
+ {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0},
+ {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0},
+ {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0},
+ {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0},
+ {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0},
+ {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0},
+ {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0},
+ {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0},
+ {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0},
+ {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0},
+ {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0},
+ {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0},
+ {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0},
+ {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0},
+ {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0},
+ {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0},
+ {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0},
+ {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0},
+ {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0},
+ {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0},
+ {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0},
+ {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0},
+ {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0},
+ {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0},
+ {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0},
+ {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0},
+ {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0},
+ {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0},
+ {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0},
+ {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0},
+ {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0},
+ {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0},
+ {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0},
+ {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0},
+ {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0},
+ {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0},
+ {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0},
+ {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0},
+ {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0},
+ {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0},
+ {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0},
+ {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0},
+ {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0},
+ {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0},
+ {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0},
+ {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0},
+ {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0},
+ {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0},
+ {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0},
+ {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0},
+ {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0},
+ {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0},
+ {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0},
+ {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0},
+ {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0},
+ {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0},
+ {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0},
+ {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0},
+ {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0},
+ {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0},
+ {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0},
+ {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0},
+ {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0},
+ {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0},
+ {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0},
+ {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0},
+ {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0},
+ {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0},
+ {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0},
+ {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0},
+ {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0},
+ {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0},
+ {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0},
+ {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0},
+ {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0},
+ {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0},
+ {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0},
+ {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0},
+ {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0},
+ {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0},
+ {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0},
+ {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0},
+ {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0},
+ {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0},
+ {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0},
+ {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0},
+ {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0},
+ {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0},
+ {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0},
+ {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0},
+ {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0},
+ {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0},
+ {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0},
+ {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0},
+ {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0},
+ {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0},
+ {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0},
+ {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0},
+ {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0},
+ {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0},
+ {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0},
+ {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0},
+ {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0},
+ {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0},
+ {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0},
+ {0x302b, 0x00, 0, 0}, {0x3503, 0x07, 0, 0}, {0x3011, 0x07, 0, 0},
+ {0x350c, 0x04, 0, 0}, {0x350d, 0x58, 0, 0}, {0x3801, 0x8a, 0, 0},
+ {0x3803, 0x0a, 0, 0}, {0x3804, 0x07, 0, 0}, {0x3805, 0x80, 0, 0},
+ {0x3806, 0x04, 0, 0}, {0x3807, 0x39, 0, 0}, {0x3808, 0x07, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0},
+ {0x380c, 0x09, 0, 0}, {0x380d, 0xd6, 0, 0}, {0x380e, 0x04, 0, 0},
+ {0x380f, 0x58, 0, 0}, {0x381c, 0x11, 0, 0}, {0x381d, 0xba, 0, 0},
+ {0x381e, 0x04, 0, 0}, {0x381f, 0x48, 0, 0}, {0x3820, 0x04, 0, 0},
+ {0x3821, 0x18, 0, 0}, {0x3a08, 0x14, 0, 0}, {0x3a09, 0xe0, 0, 0},
+ {0x3a0a, 0x11, 0, 0}, {0x3a0b, 0x60, 0, 0}, {0x3a0d, 0x04, 0, 0},
+ {0x3a0e, 0x03, 0, 0}, {0x5682, 0x07, 0, 0}, {0x5683, 0x60, 0, 0},
+ {0x5686, 0x04, 0, 0}, {0x5687, 0x1c, 0, 0}, {0x5001, 0x7f, 0, 0},
+ {0x3503, 0x00, 0, 0}, {0x3010, 0x10, 0, 0}, {0x460c, 0x20, 0, 0},
+ {0x460b, 0x37, 0, 0}, {0x471c, 0xd0, 0, 0}, {0x471d, 0x05, 0, 0},
+ {0x3815, 0x01, 0, 0}, {0x3818, 0x00, 0x08, 0}, {0x501f, 0x00, 0, 0},
+ {0x4300, 0x30, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3819, 0x80, 0, 0},
+ {0x5002, 0xe0, 0, 0},
+};
+
+static struct reg_value ov5642_setting_15fps_QVGA_320_240[] = {
+ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0},
+ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0},
+ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0},
+ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0},
+ {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x08, 0, 0},
+ {0x3010, 0x10, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0},
+ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0},
+ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0},
+ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0},
+ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0},
+ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0},
+ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0},
+ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0},
+ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0},
+ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0},
+ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0},
+ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0},
+ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0},
+ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3501, 0x1e, 0, 0},
+ {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, {0x380c, 0x0c, 0, 0},
+ {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3818, 0xc1, 0, 0},
+ {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, {0x3801, 0x80, 0, 0},
+ {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0},
+ {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, {0x3804, 0x05, 0, 0},
+ {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0},
+ {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0},
+ {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x05, 0, 0},
+ {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0},
+ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0},
+ {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0},
+ {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, {0x3502, 0x00, 0, 0},
+ {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, {0x3503, 0x00, 0, 0},
+ {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0},
+ {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, {0x528f, 0x10, 0, 0},
+ {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x02, 0, 0},
+ {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, {0x5296, 0x00, 0, 0},
+ {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x02, 0, 0},
+ {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, {0x529c, 0x00, 0, 0},
+ {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x02, 0, 0},
+ {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3c, 0, 0},
+ {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, {0x3a1f, 0x10, 0, 0},
+ {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, {0x3a03, 0x7d, 0, 0},
+ {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, {0x3a15, 0x7d, 0, 0},
+ {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a08, 0x09, 0, 0},
+ {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, {0x3a0b, 0xd0, 0, 0},
+ {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x06, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, {0x401e, 0x20, 0, 0},
+ {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, {0x528a, 0x01, 0, 0},
+ {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, {0x528d, 0x10, 0, 0},
+ {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, {0x5290, 0x30, 0, 0},
+ {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, {0x5294, 0x00, 0, 0},
+ {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, {0x5297, 0x08, 0, 0},
+ {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, {0x529a, 0x00, 0, 0},
+ {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, {0x529d, 0x28, 0, 0},
+ {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, {0x5282, 0x00, 0, 0},
+ {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, {0x5302, 0x00, 0, 0},
+ {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, {0x530d, 0x0c, 0, 0},
+ {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, {0x5310, 0x20, 0, 0},
+ {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, {0x5309, 0x40, 0, 0},
+ {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x00, 0, 0},
+ {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, {0x5315, 0x20, 0, 0},
+ {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, {0x5317, 0x00, 0, 0},
+ {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, {0x5381, 0x00, 0, 0},
+ {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, {0x5384, 0x00, 0, 0},
+ {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, {0x5387, 0x00, 0, 0},
+ {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, {0x538a, 0x00, 0, 0},
+ {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, {0x538d, 0x00, 0, 0},
+ {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, {0x5390, 0x00, 0, 0},
+ {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, {0x5393, 0xa2, 0, 0},
+ {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, {0x5481, 0x21, 0, 0},
+ {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, {0x5484, 0x65, 0, 0},
+ {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, {0x5487, 0x87, 0, 0},
+ {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, {0x548a, 0xaa, 0, 0},
+ {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, {0x548d, 0xdd, 0, 0},
+ {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, {0x5490, 0x05, 0, 0},
+ {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, {0x5493, 0x20, 0, 0},
+ {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, {0x5496, 0x02, 0, 0},
+ {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, {0x5499, 0x86, 0, 0},
+ {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, {0x549c, 0x02, 0, 0},
+ {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, {0x549f, 0x1c, 0, 0},
+ {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, {0x54a2, 0x01, 0, 0},
+ {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, {0x54a5, 0xc5, 0, 0},
+ {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, {0x54a8, 0x01, 0, 0},
+ {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, {0x54ab, 0x41, 0, 0},
+ {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, {0x54ae, 0x00, 0, 0},
+ {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, {0x54b1, 0x20, 0, 0},
+ {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, {0x54b4, 0x00, 0, 0},
+ {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, {0x54b7, 0xdf, 0, 0},
+ {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, {0x3406, 0x00, 0, 0},
+ {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, {0x5182, 0x11, 0, 0},
+ {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0},
+ {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, {0x5188, 0x08, 0, 0},
+ {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, {0x518b, 0xb2, 0, 0},
+ {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, {0x518e, 0x3d, 0, 0},
+ {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0},
+ {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0},
+ {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0},
+ {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, {0x519a, 0x04, 0, 0},
+ {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, {0x519d, 0x82, 0, 0},
+ {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, {0x3a0f, 0x38, 0, 0},
+ {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, {0x3a1e, 0x2e, 0, 0},
+ {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, {0x5688, 0xa6, 0, 0},
+ {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, {0x568b, 0xae, 0, 0},
+ {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, {0x568e, 0x62, 0, 0},
+ {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x40, 0, 0},
+ {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, {0x5800, 0x27, 0, 0},
+ {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, {0x5803, 0x0f, 0, 0},
+ {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, {0x5806, 0x1e, 0, 0},
+ {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, {0x5809, 0x0d, 0, 0},
+ {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, {0x580c, 0x0a, 0, 0},
+ {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, {0x580f, 0x19, 0, 0},
+ {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, {0x5812, 0x04, 0, 0},
+ {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, {0x5815, 0x06, 0, 0},
+ {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, {0x5818, 0x0a, 0, 0},
+ {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, {0x581b, 0x00, 0, 0},
+ {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, {0x581e, 0x08, 0, 0},
+ {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, {0x5821, 0x05, 0, 0},
+ {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, {0x5824, 0x00, 0, 0},
+ {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, {0x5827, 0x0c, 0, 0},
+ {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, {0x582a, 0x06, 0, 0},
+ {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, {0x582d, 0x07, 0, 0},
+ {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, {0x5830, 0x18, 0, 0},
+ {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, {0x5833, 0x0a, 0, 0},
+ {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, {0x5836, 0x15, 0, 0},
+ {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, {0x5839, 0x1f, 0, 0},
+ {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, {0x583c, 0x17, 0, 0},
+ {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, {0x583f, 0x53, 0, 0},
+ {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, {0x5842, 0x0d, 0, 0},
+ {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, {0x5845, 0x09, 0, 0},
+ {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, {0x5848, 0x10, 0, 0},
+ {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, {0x584b, 0x0e, 0, 0},
+ {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, {0x584e, 0x11, 0, 0},
+ {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, {0x5851, 0x0c, 0, 0},
+ {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, {0x5854, 0x10, 0, 0},
+ {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, {0x5857, 0x0b, 0, 0},
+ {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, {0x585a, 0x0d, 0, 0},
+ {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, {0x585d, 0x0c, 0, 0},
+ {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, {0x5860, 0x0c, 0, 0},
+ {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, {0x5863, 0x08, 0, 0},
+ {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, {0x5866, 0x18, 0, 0},
+ {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, {0x5869, 0x19, 0, 0},
+ {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, {0x586c, 0x13, 0, 0},
+ {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, {0x586f, 0x16, 0, 0},
+ {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, {0x5872, 0x10, 0, 0},
+ {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, {0x5875, 0x16, 0, 0},
+ {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, {0x5878, 0x10, 0, 0},
+ {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, {0x587b, 0x14, 0, 0},
+ {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, {0x587e, 0x11, 0, 0},
+ {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, {0x5881, 0x15, 0, 0},
+ {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, {0x5884, 0x15, 0, 0},
+ {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, {0x5887, 0x17, 0, 0},
+ {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, {0x3702, 0x10, 0, 0},
+ {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, {0x370b, 0x40, 0, 0},
+ {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, {0x3632, 0x52, 0, 0},
+ {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, {0x5785, 0x07, 0, 0},
+ {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, {0x3604, 0x48, 0, 0},
+ {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, {0x370f, 0xc0, 0, 0},
+ {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, {0x5007, 0x00, 0, 0},
+ {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, {0x5013, 0x00, 0, 0},
+ {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, {0x5087, 0x00, 0, 0},
+ {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, {0x302b, 0x00, 0, 0},
+ {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0},
+ {0x380b, 0xf0, 0, 0}, {0x3a00, 0x78, 0, 0},
+};
+
+static struct reg_value ov5642_setting_15fps_NTSC_720_480[] = {
+ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0},
+ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0},
+ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0},
+ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0},
+ {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x08, 0, 0},
+ {0x3010, 0x10, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0},
+ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0},
+ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0},
+ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0},
+ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0},
+ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0},
+ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0},
+ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0},
+ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0},
+ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0},
+ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0},
+ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0},
+ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0},
+ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3501, 0x1e, 0, 0},
+ {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, {0x380c, 0x0c, 0, 0},
+ {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3818, 0xc1, 0, 0},
+ {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, {0x3801, 0x80, 0, 0},
+ {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0},
+ {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, {0x3804, 0x05, 0, 0},
+ {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0},
+ {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0},
+ {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x05, 0, 0},
+ {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0},
+ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0},
+ {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0},
+ {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, {0x3502, 0x00, 0, 0},
+ {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, {0x3503, 0x00, 0, 0},
+ {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0},
+ {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, {0x528f, 0x10, 0, 0},
+ {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x02, 0, 0},
+ {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, {0x5296, 0x00, 0, 0},
+ {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x02, 0, 0},
+ {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, {0x529c, 0x00, 0, 0},
+ {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x02, 0, 0},
+ {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3c, 0, 0},
+ {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, {0x3a1f, 0x10, 0, 0},
+ {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, {0x3a03, 0x7d, 0, 0},
+ {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, {0x3a15, 0x7d, 0, 0},
+ {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a08, 0x09, 0, 0},
+ {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, {0x3a0b, 0xd0, 0, 0},
+ {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x06, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, {0x401e, 0x20, 0, 0},
+ {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, {0x528a, 0x01, 0, 0},
+ {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, {0x528d, 0x10, 0, 0},
+ {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, {0x5290, 0x30, 0, 0},
+ {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, {0x5294, 0x00, 0, 0},
+ {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, {0x5297, 0x08, 0, 0},
+ {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, {0x529a, 0x00, 0, 0},
+ {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, {0x529d, 0x28, 0, 0},
+ {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, {0x5282, 0x00, 0, 0},
+ {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, {0x5302, 0x00, 0, 0},
+ {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, {0x530d, 0x0c, 0, 0},
+ {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, {0x5310, 0x20, 0, 0},
+ {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, {0x5309, 0x40, 0, 0},
+ {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x00, 0, 0},
+ {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, {0x5315, 0x20, 0, 0},
+ {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, {0x5317, 0x00, 0, 0},
+ {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, {0x5381, 0x00, 0, 0},
+ {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, {0x5384, 0x00, 0, 0},
+ {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, {0x5387, 0x00, 0, 0},
+ {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, {0x538a, 0x00, 0, 0},
+ {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, {0x538d, 0x00, 0, 0},
+ {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, {0x5390, 0x00, 0, 0},
+ {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, {0x5393, 0xa2, 0, 0},
+ {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, {0x5481, 0x21, 0, 0},
+ {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, {0x5484, 0x65, 0, 0},
+ {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, {0x5487, 0x87, 0, 0},
+ {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, {0x548a, 0xaa, 0, 0},
+ {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, {0x548d, 0xdd, 0, 0},
+ {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, {0x5490, 0x05, 0, 0},
+ {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, {0x5493, 0x20, 0, 0},
+ {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, {0x5496, 0x02, 0, 0},
+ {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, {0x5499, 0x86, 0, 0},
+ {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, {0x549c, 0x02, 0, 0},
+ {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, {0x549f, 0x1c, 0, 0},
+ {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, {0x54a2, 0x01, 0, 0},
+ {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, {0x54a5, 0xc5, 0, 0},
+ {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, {0x54a8, 0x01, 0, 0},
+ {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, {0x54ab, 0x41, 0, 0},
+ {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, {0x54ae, 0x00, 0, 0},
+ {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, {0x54b1, 0x20, 0, 0},
+ {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, {0x54b4, 0x00, 0, 0},
+ {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, {0x54b7, 0xdf, 0, 0},
+ {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, {0x3406, 0x00, 0, 0},
+ {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, {0x5182, 0x11, 0, 0},
+ {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0},
+ {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, {0x5188, 0x08, 0, 0},
+ {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, {0x518b, 0xb2, 0, 0},
+ {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, {0x518e, 0x3d, 0, 0},
+ {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0},
+ {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0},
+ {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0},
+ {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, {0x519a, 0x04, 0, 0},
+ {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, {0x519d, 0x82, 0, 0},
+ {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, {0x3a0f, 0x38, 0, 0},
+ {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, {0x3a1e, 0x2e, 0, 0},
+ {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, {0x5688, 0xa6, 0, 0},
+ {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, {0x568b, 0xae, 0, 0},
+ {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, {0x568e, 0x62, 0, 0},
+ {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x40, 0, 0},
+ {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, {0x5800, 0x27, 0, 0},
+ {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, {0x5803, 0x0f, 0, 0},
+ {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, {0x5806, 0x1e, 0, 0},
+ {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, {0x5809, 0x0d, 0, 0},
+ {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, {0x580c, 0x0a, 0, 0},
+ {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, {0x580f, 0x19, 0, 0},
+ {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, {0x5812, 0x04, 0, 0},
+ {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, {0x5815, 0x06, 0, 0},
+ {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, {0x5818, 0x0a, 0, 0},
+ {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, {0x581b, 0x00, 0, 0},
+ {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, {0x581e, 0x08, 0, 0},
+ {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, {0x5821, 0x05, 0, 0},
+ {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, {0x5824, 0x00, 0, 0},
+ {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, {0x5827, 0x0c, 0, 0},
+ {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, {0x582a, 0x06, 0, 0},
+ {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, {0x582d, 0x07, 0, 0},
+ {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, {0x5830, 0x18, 0, 0},
+ {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, {0x5833, 0x0a, 0, 0},
+ {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, {0x5836, 0x15, 0, 0},
+ {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, {0x5839, 0x1f, 0, 0},
+ {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, {0x583c, 0x17, 0, 0},
+ {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, {0x583f, 0x53, 0, 0},
+ {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, {0x5842, 0x0d, 0, 0},
+ {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, {0x5845, 0x09, 0, 0},
+ {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, {0x5848, 0x10, 0, 0},
+ {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, {0x584b, 0x0e, 0, 0},
+ {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, {0x584e, 0x11, 0, 0},
+ {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, {0x5851, 0x0c, 0, 0},
+ {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, {0x5854, 0x10, 0, 0},
+ {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, {0x5857, 0x0b, 0, 0},
+ {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, {0x585a, 0x0d, 0, 0},
+ {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, {0x585d, 0x0c, 0, 0},
+ {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, {0x5860, 0x0c, 0, 0},
+ {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, {0x5863, 0x08, 0, 0},
+ {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, {0x5866, 0x18, 0, 0},
+ {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, {0x5869, 0x19, 0, 0},
+ {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, {0x586c, 0x13, 0, 0},
+ {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, {0x586f, 0x16, 0, 0},
+ {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, {0x5872, 0x10, 0, 0},
+ {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, {0x5875, 0x16, 0, 0},
+ {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, {0x5878, 0x10, 0, 0},
+ {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, {0x587b, 0x14, 0, 0},
+ {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, {0x587e, 0x11, 0, 0},
+ {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, {0x5881, 0x15, 0, 0},
+ {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, {0x5884, 0x15, 0, 0},
+ {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, {0x5887, 0x17, 0, 0},
+ {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, {0x3702, 0x10, 0, 0},
+ {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, {0x370b, 0x40, 0, 0},
+ {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, {0x3632, 0x52, 0, 0},
+ {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, {0x5785, 0x07, 0, 0},
+ {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, {0x3604, 0x48, 0, 0},
+ {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, {0x370f, 0xc0, 0, 0},
+ {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, {0x5007, 0x00, 0, 0},
+ {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, {0x5013, 0x00, 0, 0},
+ {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, {0x5087, 0x00, 0, 0},
+ {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, {0x302b, 0x00, 0, 0},
+ {0x3824, 0x11, 0, 0}, {0x3825, 0xb4, 0, 0}, {0x3826, 0x00, 0, 0},
+ {0x3827, 0x3d, 0, 0}, {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, {0x3808, 0x02, 0, 0},
+ {0x3809, 0xd0, 0, 0}, {0x380A, 0x01, 0, 0}, {0x380B, 0xe0, 0, 0},
+ {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x3806, 0x03, 0, 0},
+ {0x3807, 0x55, 0, 0}, {0x5686, 0x03, 0, 0}, {0x5687, 0x55, 0, 0},
+ {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0},
+};
+
+static struct reg_value ov5642_setting_15fps_PAL_720_576[] = {
+ {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0},
+ {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0},
+ {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0},
+ {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0},
+ {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x08, 0, 0},
+ {0x3010, 0x10, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0},
+ {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0},
+ {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0},
+ {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0},
+ {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0},
+ {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0},
+ {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0},
+ {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0},
+ {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0},
+ {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0},
+ {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0},
+ {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0},
+ {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0},
+ {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0},
+ {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0},
+ {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0},
+ {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3501, 0x1e, 0, 0},
+ {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, {0x380c, 0x0c, 0, 0},
+ {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3818, 0xc1, 0, 0},
+ {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, {0x3801, 0x80, 0, 0},
+ {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0},
+ {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, {0x3804, 0x05, 0, 0},
+ {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0},
+ {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0},
+ {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x05, 0, 0},
+ {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0},
+ {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0},
+ {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0},
+ {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, {0x3502, 0x00, 0, 0},
+ {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, {0x3503, 0x00, 0, 0},
+ {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0},
+ {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, {0x528f, 0x10, 0, 0},
+ {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x02, 0, 0},
+ {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, {0x5296, 0x00, 0, 0},
+ {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x02, 0, 0},
+ {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, {0x529c, 0x00, 0, 0},
+ {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x02, 0, 0},
+ {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3c, 0, 0},
+ {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, {0x3a1f, 0x10, 0, 0},
+ {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, {0x3a03, 0x7d, 0, 0},
+ {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, {0x3a15, 0x7d, 0, 0},
+ {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a08, 0x09, 0, 0},
+ {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, {0x3a0b, 0xd0, 0, 0},
+ {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x06, 0, 0}, {0x5193, 0x70, 0, 0},
+ {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, {0x401e, 0x20, 0, 0},
+ {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, {0x528a, 0x01, 0, 0},
+ {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, {0x528d, 0x10, 0, 0},
+ {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, {0x5290, 0x30, 0, 0},
+ {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, {0x5294, 0x00, 0, 0},
+ {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, {0x5297, 0x08, 0, 0},
+ {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, {0x529a, 0x00, 0, 0},
+ {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, {0x529d, 0x28, 0, 0},
+ {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, {0x5282, 0x00, 0, 0},
+ {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, {0x5302, 0x00, 0, 0},
+ {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, {0x530d, 0x0c, 0, 0},
+ {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, {0x5310, 0x20, 0, 0},
+ {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, {0x5309, 0x40, 0, 0},
+ {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x00, 0, 0},
+ {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, {0x5315, 0x20, 0, 0},
+ {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, {0x5317, 0x00, 0, 0},
+ {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, {0x5381, 0x00, 0, 0},
+ {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, {0x5384, 0x00, 0, 0},
+ {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, {0x5387, 0x00, 0, 0},
+ {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, {0x538a, 0x00, 0, 0},
+ {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, {0x538d, 0x00, 0, 0},
+ {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, {0x5390, 0x00, 0, 0},
+ {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, {0x5393, 0xa2, 0, 0},
+ {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, {0x5481, 0x21, 0, 0},
+ {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, {0x5484, 0x65, 0, 0},
+ {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, {0x5487, 0x87, 0, 0},
+ {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, {0x548a, 0xaa, 0, 0},
+ {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, {0x548d, 0xdd, 0, 0},
+ {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, {0x5490, 0x05, 0, 0},
+ {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, {0x5493, 0x20, 0, 0},
+ {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, {0x5496, 0x02, 0, 0},
+ {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, {0x5499, 0x86, 0, 0},
+ {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, {0x549c, 0x02, 0, 0},
+ {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, {0x549f, 0x1c, 0, 0},
+ {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, {0x54a2, 0x01, 0, 0},
+ {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, {0x54a5, 0xc5, 0, 0},
+ {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, {0x54a8, 0x01, 0, 0},
+ {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, {0x54ab, 0x41, 0, 0},
+ {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, {0x54ae, 0x00, 0, 0},
+ {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, {0x54b1, 0x20, 0, 0},
+ {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, {0x54b4, 0x00, 0, 0},
+ {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, {0x54b7, 0xdf, 0, 0},
+ {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, {0x3406, 0x00, 0, 0},
+ {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, {0x5182, 0x11, 0, 0},
+ {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0},
+ {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, {0x5188, 0x08, 0, 0},
+ {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, {0x518b, 0xb2, 0, 0},
+ {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, {0x518e, 0x3d, 0, 0},
+ {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0},
+ {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0},
+ {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0},
+ {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, {0x519a, 0x04, 0, 0},
+ {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, {0x519d, 0x82, 0, 0},
+ {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, {0x3a0f, 0x38, 0, 0},
+ {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, {0x3a1e, 0x2e, 0, 0},
+ {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, {0x5688, 0xa6, 0, 0},
+ {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, {0x568b, 0xae, 0, 0},
+ {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, {0x568e, 0x62, 0, 0},
+ {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x40, 0, 0},
+ {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, {0x5800, 0x27, 0, 0},
+ {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, {0x5803, 0x0f, 0, 0},
+ {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, {0x5806, 0x1e, 0, 0},
+ {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, {0x5809, 0x0d, 0, 0},
+ {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, {0x580c, 0x0a, 0, 0},
+ {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, {0x580f, 0x19, 0, 0},
+ {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, {0x5812, 0x04, 0, 0},
+ {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, {0x5815, 0x06, 0, 0},
+ {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, {0x5818, 0x0a, 0, 0},
+ {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, {0x581b, 0x00, 0, 0},
+ {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, {0x581e, 0x08, 0, 0},
+ {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, {0x5821, 0x05, 0, 0},
+ {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, {0x5824, 0x00, 0, 0},
+ {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, {0x5827, 0x0c, 0, 0},
+ {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, {0x582a, 0x06, 0, 0},
+ {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, {0x582d, 0x07, 0, 0},
+ {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, {0x5830, 0x18, 0, 0},
+ {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, {0x5833, 0x0a, 0, 0},
+ {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, {0x5836, 0x15, 0, 0},
+ {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, {0x5839, 0x1f, 0, 0},
+ {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, {0x583c, 0x17, 0, 0},
+ {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, {0x583f, 0x53, 0, 0},
+ {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, {0x5842, 0x0d, 0, 0},
+ {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, {0x5845, 0x09, 0, 0},
+ {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, {0x5848, 0x10, 0, 0},
+ {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, {0x584b, 0x0e, 0, 0},
+ {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, {0x584e, 0x11, 0, 0},
+ {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, {0x5851, 0x0c, 0, 0},
+ {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, {0x5854, 0x10, 0, 0},
+ {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, {0x5857, 0x0b, 0, 0},
+ {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, {0x585a, 0x0d, 0, 0},
+ {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, {0x585d, 0x0c, 0, 0},
+ {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, {0x5860, 0x0c, 0, 0},
+ {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, {0x5863, 0x08, 0, 0},
+ {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, {0x5866, 0x18, 0, 0},
+ {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, {0x5869, 0x19, 0, 0},
+ {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, {0x586c, 0x13, 0, 0},
+ {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, {0x586f, 0x16, 0, 0},
+ {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, {0x5872, 0x10, 0, 0},
+ {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, {0x5875, 0x16, 0, 0},
+ {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, {0x5878, 0x10, 0, 0},
+ {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, {0x587b, 0x14, 0, 0},
+ {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, {0x587e, 0x11, 0, 0},
+ {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, {0x5881, 0x15, 0, 0},
+ {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, {0x5884, 0x15, 0, 0},
+ {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, {0x5887, 0x17, 0, 0},
+ {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, {0x3702, 0x10, 0, 0},
+ {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, {0x370b, 0x40, 0, 0},
+ {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, {0x3632, 0x52, 0, 0},
+ {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, {0x5785, 0x07, 0, 0},
+ {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, {0x3604, 0x48, 0, 0},
+ {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, {0x370f, 0xc0, 0, 0},
+ {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, {0x5007, 0x00, 0, 0},
+ {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, {0x5013, 0x00, 0, 0},
+ {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, {0x5087, 0x00, 0, 0},
+ {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, {0x302b, 0x00, 0, 0},
+ {0x3824, 0x11, 0, 0}, {0x3825, 0xdc, 0, 0}, {0x3826, 0x00, 0, 0},
+ {0x3827, 0x08, 0, 0}, {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, {0x3808, 0x02, 0, 0},
+ {0x3809, 0xd0, 0, 0}, {0x380A, 0x02, 0, 0}, {0x380B, 0x40, 0, 0},
+ {0x3804, 0x04, 0, 0}, {0x3805, 0xb0, 0, 0}, {0x3806, 0x03, 0, 0},
+ {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0}, {0x5687, 0xc0, 0, 0},
+ {0x5682, 0x04, 0, 0}, {0x5683, 0xb0, 0, 0},
+};
+
+static struct ov5642_mode_info ov5642_mode_info_data[2][ov5642_mode_MAX + 1] = {
+ {
+ {ov5642_mode_VGA_640_480, 640, 480,
+ ov5642_setting_15fps_VGA_640_480,
+ ARRAY_SIZE(ov5642_setting_15fps_VGA_640_480)},
+ {ov5642_mode_QVGA_320_240, 320, 240,
+ ov5642_setting_15fps_QVGA_320_240,
+ ARRAY_SIZE(ov5642_setting_15fps_QVGA_320_240)},
+ {ov5642_mode_NTSC_720_480, 720, 480,
+ ov5642_setting_15fps_NTSC_720_480,
+ ARRAY_SIZE(ov5642_setting_15fps_NTSC_720_480)},
+ {ov5642_mode_PAL_720_576, 720, 576,
+ ov5642_setting_15fps_PAL_720_576,
+ ARRAY_SIZE(ov5642_setting_15fps_PAL_720_576)},
+ {ov5642_mode_720P_1280_720, 1280, 720,
+ ov5642_setting_15fps_720P_1280_720,
+ ARRAY_SIZE(ov5642_setting_15fps_720P_1280_720)},
+ {ov5642_mode_1080P_1920_1080, 1920, 1080,
+ ov5642_setting_15fps_1080P_1920_1080,
+ ARRAY_SIZE(ov5642_setting_15fps_1080P_1920_1080)},
+ {ov5642_mode_QSXGA_2592_1944, 2592, 1944,
+ ov5642_setting_15fps_QSXGA_2592_1944,
+ ARRAY_SIZE(ov5642_setting_15fps_QSXGA_2592_1944)},
+ {ov5642_mode_QCIF_176_144, 176, 144,
+ ov5642_setting_15fps_QCIF_176_144,
+ ARRAY_SIZE(ov5642_setting_15fps_QCIF_176_144)},
+ {ov5642_mode_XGA_1024_768, 1024, 768,
+ ov5642_setting_15fps_XGA_1024_768,
+ ARRAY_SIZE(ov5642_setting_15fps_XGA_1024_768)},
+ },
+ {
+ {ov5642_mode_VGA_640_480, 640, 480,
+ ov5642_setting_30fps_VGA_640_480,
+ ARRAY_SIZE(ov5642_setting_30fps_VGA_640_480)},
+ {ov5642_mode_QVGA_320_240, 320, 240,
+ ov5642_setting_30fps_QVGA_320_240,
+ ARRAY_SIZE(ov5642_setting_30fps_QVGA_320_240)},
+ {ov5642_mode_NTSC_720_480, 720, 480,
+ ov5642_setting_30fps_NTSC_720_480,
+ ARRAY_SIZE(ov5642_setting_30fps_NTSC_720_480)},
+ {ov5642_mode_PAL_720_576, 720, 576,
+ ov5642_setting_30fps_PAL_720_576,
+ ARRAY_SIZE(ov5642_setting_30fps_PAL_720_576)},
+ {ov5642_mode_720P_1280_720, 1280, 720,
+ ov5642_setting_30fps_720P_1280_720,
+ ARRAY_SIZE(ov5642_setting_30fps_720P_1280_720)},
+ {ov5642_mode_1080P_1920_1080, 0, 0, NULL, 0},
+ {ov5642_mode_QSXGA_2592_1944, 0, 0, NULL, 0},
+ {ov5642_mode_QCIF_176_144, 176, 144,
+ ov5642_setting_30fps_QCIF_176_144,
+ ARRAY_SIZE(ov5642_setting_30fps_QCIF_176_144)},
+ {ov5642_mode_XGA_1024_768, 1024, 768,
+ ov5642_setting_30fps_XGA_1024_768,
+ ARRAY_SIZE(ov5642_setting_30fps_XGA_1024_768)},
+ },
+};
+
+static struct regulator *io_regulator;
+static struct regulator *core_regulator;
+static struct regulator *analog_regulator;
+static struct regulator *gpo_regulator;
+
+static int ov5642_probe(struct i2c_client *adapter,
+ const struct i2c_device_id *device_id);
+static int ov5642_remove(struct i2c_client *client);
+
+static s32 ov5642_read_reg(u16 reg, u8 *val);
+static s32 ov5642_write_reg(u16 reg, u8 val);
+
+static const struct i2c_device_id ov5642_id[] = {
+ {"ov5642", 0},
+ {"ov564x", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, ov5642_id);
+
+static struct i2c_driver ov5642_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ov5642",
+ },
+ .probe = ov5642_probe,
+ .remove = ov5642_remove,
+ .id_table = ov5642_id,
+};
+
+static void ov5642_standby(s32 enable)
+{
+ if (enable)
+ gpio_set_value(pwn_gpio, 1);
+ else
+ gpio_set_value(pwn_gpio, 0);
+
+ msleep(2);
+}
+
+static void ov5642_reset(void)
+{
+ /* camera reset */
+ gpio_set_value(rst_gpio, 1);
+
+ /* camera power down */
+ gpio_set_value(pwn_gpio, 1);
+ msleep(5);
+
+ gpio_set_value(pwn_gpio, 0);
+ msleep(5);
+
+ gpio_set_value(rst_gpio, 0);
+ msleep(1);
+
+ gpio_set_value(rst_gpio, 1);
+ msleep(5);
+
+ gpio_set_value(pwn_gpio, 1);
+}
+
+static int ov5642_power_on(struct device *dev)
+{
+ int ret = 0;
+
+ io_regulator = devm_regulator_get(dev, "DOVDD");
+ if (!IS_ERR(io_regulator)) {
+ regulator_set_voltage(io_regulator,
+ OV5642_VOLTAGE_DIGITAL_IO,
+ OV5642_VOLTAGE_DIGITAL_IO);
+ ret = regulator_enable(io_regulator);
+ if (ret) {
+ pr_err("%s:io set voltage error\n", __func__);
+ return ret;
+ } else {
+ dev_dbg(dev,
+ "%s:io set voltage ok\n", __func__);
+ }
+ } else {
+ pr_err("%s: cannot get io voltage error\n", __func__);
+ io_regulator = NULL;
+ }
+
+ core_regulator = devm_regulator_get(dev, "DVDD");
+ if (!IS_ERR(core_regulator)) {
+ regulator_set_voltage(core_regulator,
+ OV5642_VOLTAGE_DIGITAL_CORE,
+ OV5642_VOLTAGE_DIGITAL_CORE);
+ ret = regulator_enable(core_regulator);
+ if (ret) {
+ pr_err("%s:core set voltage error\n", __func__);
+ return ret;
+ } else {
+ dev_dbg(dev,
+ "%s:core set voltage ok\n", __func__);
+ }
+ } else {
+ core_regulator = NULL;
+ pr_err("%s: cannot get core voltage error\n", __func__);
+ }
+
+ analog_regulator = devm_regulator_get(dev, "AVDD");
+ if (!IS_ERR(analog_regulator)) {
+ regulator_set_voltage(analog_regulator,
+ OV5642_VOLTAGE_ANALOG,
+ OV5642_VOLTAGE_ANALOG);
+ ret = regulator_enable(analog_regulator);
+ if (ret) {
+ pr_err("%s:analog set voltage error\n",
+ __func__);
+ return ret;
+ } else {
+ dev_dbg(dev,
+ "%s:analog set voltage ok\n", __func__);
+ }
+ } else {
+ analog_regulator = NULL;
+ pr_err("%s: cannot get analog voltage error\n", __func__);
+ }
+
+ return ret;
+}
+
+static s32 ov5642_write_reg(u16 reg, u8 val)
+{
+ u8 au8Buf[3] = {0};
+
+ au8Buf[0] = reg >> 8;
+ au8Buf[1] = reg & 0xff;
+ au8Buf[2] = val;
+
+ if (i2c_master_send(ov5642_data.i2c_client, au8Buf, 3) < 0) {
+ pr_err("%s:write reg error:reg=%x,val=%x\n",
+ __func__, reg, val);
+ return -1;
+ }
+
+ return 0;
+}
+
+static s32 ov5642_read_reg(u16 reg, u8 *val)
+{
+ u8 au8RegBuf[2] = {0};
+ u8 u8RdVal = 0;
+
+ au8RegBuf[0] = reg >> 8;
+ au8RegBuf[1] = reg & 0xff;
+
+ if (2 != i2c_master_send(ov5642_data.i2c_client, au8RegBuf, 2)) {
+ pr_err("%s:write reg error:reg=%x\n",
+ __func__, reg);
+ return -1;
+ }
+
+ if (1 != i2c_master_recv(ov5642_data.i2c_client, &u8RdVal, 1)) {
+ pr_err("%s:read reg error:reg=%x,val=%x\n",
+ __func__, reg, u8RdVal);
+ return -1;
+ }
+
+ *val = u8RdVal;
+
+ return u8RdVal;
+}
+
+static int ov5642_set_rot_mode(struct reg_value *rot_mode)
+{
+ s32 i = 0;
+ s32 iModeSettingArySize = 2;
+ register u32 Delay_ms = 0;
+ register u16 RegAddr = 0;
+ register u8 Mask = 0;
+ register u8 Val = 0;
+ u8 RegVal = 0;
+ int retval = 0;
+ for (i = 0; i < iModeSettingArySize; ++i, ++rot_mode) {
+ Delay_ms = rot_mode->u32Delay_ms;
+ RegAddr = rot_mode->u16RegAddr;
+ Val = rot_mode->u8Val;
+ Mask = rot_mode->u8Mask;
+
+ if (Mask) {
+ retval = ov5642_read_reg(RegAddr, &RegVal);
+ if (retval < 0) {
+ pr_err("%s, read reg 0x%x failed\n",
+ __func__, RegAddr);
+ goto err;
+ }
+
+ Val |= RegVal;
+ Val &= Mask;
+ }
+
+ retval = ov5642_write_reg(RegAddr, Val);
+ if (retval < 0) {
+ pr_err("%s, write reg 0x%x failed\n",
+ __func__, RegAddr);
+ goto err;
+ }
+
+ if (Delay_ms)
+ mdelay(Delay_ms);
+ }
+err:
+ return retval;
+}
+static int ov5642_init_mode(enum ov5642_frame_rate frame_rate,
+ enum ov5642_mode mode);
+static int ov5642_write_snapshot_para(enum ov5642_frame_rate frame_rate,
+ enum ov5642_mode mode);
+static int ov5642_change_mode(enum ov5642_frame_rate new_frame_rate,
+ enum ov5642_frame_rate old_frame_rate,
+ enum ov5642_mode new_mode,
+ enum ov5642_mode orig_mode)
+{
+ struct reg_value *pModeSetting = NULL;
+ s32 i = 0;
+ s32 iModeSettingArySize = 0;
+ register u32 Delay_ms = 0;
+ register u16 RegAddr = 0;
+ register u8 Mask = 0;
+ register u8 Val = 0;
+ u8 RegVal = 0;
+ int retval = 0;
+
+ if (new_mode > ov5642_mode_MAX || new_mode < ov5642_mode_MIN) {
+ pr_err("Wrong ov5642 mode detected!\n");
+ return -1;
+ }
+
+ if ((new_frame_rate == old_frame_rate) &&
+ (new_mode == ov5642_mode_VGA_640_480) &&
+ (orig_mode == ov5642_mode_QSXGA_2592_1944)) {
+ pModeSetting = ov5642_setting_QSXGA_2_VGA;
+ iModeSettingArySize = ARRAY_SIZE(ov5642_setting_QSXGA_2_VGA);
+ ov5642_data.pix.width = 640;
+ ov5642_data.pix.height = 480;
+ } else if ((new_frame_rate == old_frame_rate) &&
+ (new_mode == ov5642_mode_QVGA_320_240) &&
+ (orig_mode == ov5642_mode_VGA_640_480)) {
+ pModeSetting = ov5642_setting_VGA_2_QVGA;
+ iModeSettingArySize = ARRAY_SIZE(ov5642_setting_VGA_2_QVGA);
+ ov5642_data.pix.width = 320;
+ ov5642_data.pix.height = 240;
+ } else {
+ retval = ov5642_write_snapshot_para(new_frame_rate, new_mode);
+ goto err;
+ }
+
+ if (ov5642_data.pix.width == 0 || ov5642_data.pix.height == 0 ||
+ pModeSetting == NULL || iModeSettingArySize == 0)
+ return -EINVAL;
+
+ for (i = 0; i < iModeSettingArySize; ++i, ++pModeSetting) {
+ Delay_ms = pModeSetting->u32Delay_ms;
+ RegAddr = pModeSetting->u16RegAddr;
+ Val = pModeSetting->u8Val;
+ Mask = pModeSetting->u8Mask;
+
+ if (Mask) {
+ retval = ov5642_read_reg(RegAddr, &RegVal);
+ if (retval < 0) {
+ pr_err("read reg error addr=0x%x", RegAddr);
+ goto err;
+ }
+
+ RegVal &= ~(u8)Mask;
+ Val &= Mask;
+ Val |= RegVal;
+ }
+
+ retval = ov5642_write_reg(RegAddr, Val);
+ if (retval < 0) {
+ pr_err("write reg error addr=0x%x", RegAddr);
+ goto err;
+ }
+
+ if (Delay_ms)
+ msleep(Delay_ms);
+ }
+err:
+ return retval;
+}
+static int ov5642_init_mode(enum ov5642_frame_rate frame_rate,
+ enum ov5642_mode mode)
+{
+ struct reg_value *pModeSetting = NULL;
+ s32 i = 0;
+ s32 iModeSettingArySize = 0;
+ register u32 Delay_ms = 0;
+ register u16 RegAddr = 0;
+ register u8 Mask = 0;
+ register u8 Val = 0;
+ u8 RegVal = 0;
+ int retval = 0;
+
+ if (mode > ov5642_mode_MAX || mode < ov5642_mode_MIN) {
+ pr_err("Wrong ov5642 mode detected!\n");
+ return -1;
+ }
+
+ pModeSetting = ov5642_mode_info_data[frame_rate][mode].init_data_ptr;
+ iModeSettingArySize =
+ ov5642_mode_info_data[frame_rate][mode].init_data_size;
+
+ ov5642_data.pix.width = ov5642_mode_info_data[frame_rate][mode].width;
+ ov5642_data.pix.height = ov5642_mode_info_data[frame_rate][mode].height;
+
+ if (ov5642_data.pix.width == 0 || ov5642_data.pix.height == 0 ||
+ pModeSetting == NULL || iModeSettingArySize == 0)
+ return -EINVAL;
+
+ for (i = 0; i < iModeSettingArySize; ++i, ++pModeSetting) {
+ Delay_ms = pModeSetting->u32Delay_ms;
+ RegAddr = pModeSetting->u16RegAddr;
+ Val = pModeSetting->u8Val;
+ Mask = pModeSetting->u8Mask;
+
+ if (Mask) {
+ retval = ov5642_read_reg(RegAddr, &RegVal);
+ if (retval < 0) {
+ pr_err("read reg error addr=0x%x", RegAddr);
+ goto err;
+ }
+
+ RegVal &= ~(u8)Mask;
+ Val &= Mask;
+ Val |= RegVal;
+ }
+
+ retval = ov5642_write_reg(RegAddr, Val);
+ if (retval < 0) {
+ pr_err("write reg error addr=0x%x", RegAddr);
+ goto err;
+ }
+
+ if (Delay_ms)
+ msleep(Delay_ms);
+ }
+err:
+ return retval;
+}
+
+static int ov5642_write_snapshot_para(enum ov5642_frame_rate frame_rate,
+ enum ov5642_mode mode)
+{
+ int ret = 0;
+ bool m_60Hz = false;
+ u16 cap_frame_rate = 50;
+ u16 g_prev_frame_rate = 225;
+
+ u8 ev_low, ev_mid, ev_high;
+ u8 ret_l, ret_m, ret_h, gain, lines_10ms;
+ u16 ulcap_ev, icap_gain, prev_maxlines;
+ u32 ulcap_ev_gain, cap_maxlines, g_prev_ev;
+
+ ov5642_write_reg(0x3503, 0x07);
+
+ ret_h = ret_m = ret_l = 0;
+ g_prev_ev = 0;
+ ov5642_read_reg(0x3500, &ret_h);
+ ov5642_read_reg(0x3501, &ret_m);
+ ov5642_read_reg(0x3502, &ret_l);
+ g_prev_ev = (ret_h << 12) + (ret_m << 4) + (ret_l >> 4);
+
+ ret_h = ret_m = ret_l = 0;
+ prev_maxlines = 0;
+ ov5642_read_reg(0x380e, &ret_h);
+ ov5642_read_reg(0x380f, &ret_l);
+ prev_maxlines = (ret_h << 8) + ret_l;
+ /*Read back AGC Gain for preview*/
+ gain = 0;
+ ov5642_read_reg(0x350b, &gain);
+
+ ret = ov5642_init_mode(frame_rate, mode);
+ if (ret < 0)
+ return ret;
+
+ ret_h = ret_m = ret_l = 0;
+ ov5642_read_reg(0x380e, &ret_h);
+ ov5642_read_reg(0x380f, &ret_l);
+ cap_maxlines = (ret_h << 8) + ret_l;
+ if (m_60Hz == true)
+ lines_10ms = cap_frame_rate * cap_maxlines/12000;
+ else
+ lines_10ms = cap_frame_rate * cap_maxlines/10000;
+
+ if (prev_maxlines == 0)
+ prev_maxlines = 1;
+
+ ulcap_ev = (g_prev_ev*(cap_frame_rate)*(cap_maxlines))/
+ (((prev_maxlines)*(g_prev_frame_rate)));
+ icap_gain = (gain & 0x0f) + 16;
+ if (gain & 0x10)
+ icap_gain = icap_gain << 1;
+
+ if (gain & 0x20)
+ icap_gain = icap_gain << 1;
+
+ if (gain & 0x40)
+ icap_gain = icap_gain << 1;
+
+ if (gain & 0x80)
+ icap_gain = icap_gain << 1;
+
+ ulcap_ev_gain = 2 * ulcap_ev * icap_gain;
+
+ if (ulcap_ev_gain < cap_maxlines*16) {
+ ulcap_ev = ulcap_ev_gain/16;
+ if (ulcap_ev > lines_10ms) {
+ ulcap_ev /= lines_10ms;
+ ulcap_ev *= lines_10ms;
+ }
+ } else
+ ulcap_ev = cap_maxlines;
+
+ if (ulcap_ev == 0)
+ ulcap_ev = 1;
+
+ icap_gain = (ulcap_ev_gain*2/ulcap_ev + 1)/2;
+ ev_low = ((unsigned char)ulcap_ev)<<4;
+ ev_mid = (unsigned char)(ulcap_ev >> 4) & 0xff;
+ ev_high = (unsigned char)(ulcap_ev >> 12);
+
+ gain = 0;
+ if (icap_gain > 31) {
+ gain |= 0x10;
+ icap_gain = icap_gain >> 1;
+ }
+ if (icap_gain > 31) {
+ gain |= 0x20;
+ icap_gain = icap_gain >> 1;
+ }
+ if (icap_gain > 31) {
+ gain |= 0x40;
+ icap_gain = icap_gain >> 1;
+ }
+ if (icap_gain > 31) {
+ gain |= 0x80;
+ icap_gain = icap_gain >> 1;
+ }
+ if (icap_gain > 16)
+ gain |= ((icap_gain - 16) & 0x0f);
+
+ if (gain == 0x10)
+ gain = 0x11;
+
+ ov5642_write_reg(0x350b, gain);
+ ov5642_write_reg(0x3502, ev_low);
+ ov5642_write_reg(0x3501, ev_mid);
+ ov5642_write_reg(0x3500, ev_high);
+ msleep(500);
+
+ return ret ;
+}
+
+
+/* --------------- IOCTL functions from v4l2_int_ioctl_desc --------------- */
+
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+ if (s == NULL) {
+ pr_err(" ERROR!! no slave device set!\n");
+ return -1;
+ }
+
+ memset(p, 0, sizeof(*p));
+ p->u.bt656.clock_curr = ov5642_data.mclk;
+ pr_debug(" clock_curr=mclk=%d\n", ov5642_data.mclk);
+ p->if_type = V4L2_IF_TYPE_BT656;
+ p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT;
+ p->u.bt656.clock_min = OV5642_XCLK_MIN;
+ p->u.bt656.clock_max = OV5642_XCLK_MAX;
+ p->u.bt656.bt_sync_correct = 1; /* Indicate external vsync */
+
+ return 0;
+}
+
+/*!
+ * ioctl_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @on: indicates power mode (on or off)
+ *
+ * Turns the power on or off, depending on the value of on and returns the
+ * appropriate error code.
+ */
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
+{
+ struct sensor_data *sensor = s->priv;
+
+ if (on && !sensor->on) {
+ if (io_regulator)
+ if (regulator_enable(io_regulator) != 0)
+ return -EIO;
+ if (core_regulator)
+ if (regulator_enable(core_regulator) != 0)
+ return -EIO;
+ if (gpo_regulator)
+ if (regulator_enable(gpo_regulator) != 0)
+ return -EIO;
+ if (analog_regulator)
+ if (regulator_enable(analog_regulator) != 0)
+ return -EIO;
+ /* Make sure power on */
+ ov5642_standby(0);
+ } else if (!on && sensor->on) {
+ if (analog_regulator)
+ regulator_disable(analog_regulator);
+ if (core_regulator)
+ regulator_disable(core_regulator);
+ if (io_regulator)
+ regulator_disable(io_regulator);
+ if (gpo_regulator)
+ regulator_disable(gpo_regulator);
+
+ ov5642_standby(1);
+ }
+
+ sensor->on = on;
+
+ return 0;
+}
+
+/*!
+ * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+ struct sensor_data *sensor = s->priv;
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+ int ret = 0;
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cparm->capability = sensor->streamcap.capability;
+ cparm->timeperframe = sensor->streamcap.timeperframe;
+ cparm->capturemode = sensor->streamcap.capturemode;
+ ret = 0;
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ ret = -EINVAL;
+ break;
+
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible. If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ */
+static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a)
+{
+ struct sensor_data *sensor = s->priv;
+ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+ u32 tgt_fps, old_fps; /* target frames per secound */
+ enum ov5642_frame_rate new_frame_rate, old_frame_rate;
+ int ret = 0;
+
+ /* Make sure power on */
+ ov5642_standby(0);
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ /* Check that the new frame rate is allowed. */
+ if ((timeperframe->numerator == 0) ||
+ (timeperframe->denominator == 0)) {
+ timeperframe->denominator = DEFAULT_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps > MAX_FPS) {
+ timeperframe->denominator = MAX_FPS;
+ timeperframe->numerator = 1;
+ } else if (tgt_fps < MIN_FPS) {
+ timeperframe->denominator = MIN_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ /* Actual frame rate we use */
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps == 15)
+ new_frame_rate = ov5642_15_fps;
+ else if (tgt_fps == 30)
+ new_frame_rate = ov5642_30_fps;
+ else {
+ pr_err(" The camera frame rate is not supported!\n");
+ return -EINVAL;
+ }
+
+ if (sensor->streamcap.timeperframe.numerator != 0)
+ old_fps = sensor->streamcap.timeperframe.denominator /
+ sensor->streamcap.timeperframe.numerator;
+ else
+ old_fps = 30;
+
+ if (old_fps == 15)
+ old_frame_rate = ov5642_15_fps;
+ else if (old_fps == 30)
+ old_frame_rate = ov5642_30_fps;
+ else {
+ pr_warning(" No valid frame rate set!\n");
+ old_frame_rate = ov5642_30_fps;
+ }
+
+ ret = ov5642_change_mode(new_frame_rate, old_frame_rate,
+ a->parm.capture.capturemode,
+ sensor->streamcap.capturemode);
+ if (ret < 0)
+ return ret;
+
+ sensor->streamcap.timeperframe = *timeperframe;
+ sensor->streamcap.capturemode =
+ (u32)a->parm.capture.capturemode;
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ pr_debug(" type is not " \
+ "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n",
+ a->type);
+ ret = -EINVAL;
+ break;
+
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap
+ * @s: pointer to standard V4L2 device structure
+ * @f: pointer to standard V4L2 v4l2_format structure
+ *
+ * Returns the sensor's current pixel format in the v4l2_format
+ * parameter.
+ */
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)
+{
+ struct sensor_data *sensor = s->priv;
+
+ f->fmt.pix = sensor->pix;
+
+ return 0;
+}
+
+/*!
+ * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure
+ *
+ * If the requested control is supported, returns the control's current
+ * value from the video_control[] array. Otherwise, returns -EINVAL
+ * if the control is not supported.
+ */
+static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
+{
+ int ret = 0;
+
+ switch (vc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ vc->value = ov5642_data.brightness;
+ break;
+ case V4L2_CID_HUE:
+ vc->value = ov5642_data.hue;
+ break;
+ case V4L2_CID_CONTRAST:
+ vc->value = ov5642_data.contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ vc->value = ov5642_data.saturation;
+ break;
+ case V4L2_CID_RED_BALANCE:
+ vc->value = ov5642_data.red;
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ vc->value = ov5642_data.blue;
+ break;
+ case V4L2_CID_EXPOSURE:
+ vc->value = ov5642_data.ae_mode;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+/*!
+ * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure
+ *
+ * If the requested control is supported, sets the control's current
+ * value in HW (and updates the video_control[] array). Otherwise,
+ * returns -EINVAL if the control is not supported.
+ */
+static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc)
+{
+ int retval = 0;
+ struct sensor_data *sensor = s->priv;
+ __u32 captureMode = sensor->streamcap.capturemode;
+ struct reg_value *rot_mode = NULL;
+
+ pr_debug("In ov5642:ioctl_s_ctrl %d\n",
+ vc->id);
+
+ switch (vc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ break;
+ case V4L2_CID_CONTRAST:
+ break;
+ case V4L2_CID_SATURATION:
+ break;
+ case V4L2_CID_HUE:
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ break;
+ case V4L2_CID_DO_WHITE_BALANCE:
+ break;
+ case V4L2_CID_RED_BALANCE:
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ break;
+ case V4L2_CID_GAMMA:
+ break;
+ case V4L2_CID_EXPOSURE:
+ break;
+ case V4L2_CID_AUTOGAIN:
+ break;
+ case V4L2_CID_GAIN:
+ break;
+ case V4L2_CID_HFLIP:
+ break;
+ case V4L2_CID_VFLIP:
+ break;
+ case V4L2_CID_MXC_ROT:
+ case V4L2_CID_MXC_VF_ROT:
+ switch (vc->value) {
+ case V4L2_MXC_ROTATE_NONE:
+ if (captureMode == ov5642_mode_QSXGA_2592_1944)
+ rot_mode = ov5642_rot_none_FULL;
+ else
+ rot_mode = ov5642_rot_none_VGA;
+
+ if (ov5642_set_rot_mode(rot_mode))
+ retval = -EPERM;
+ break;
+ case V4L2_MXC_ROTATE_VERT_FLIP:
+ if (captureMode == ov5642_mode_QSXGA_2592_1944)
+ rot_mode = ov5642_rot_vert_flip_FULL;
+ else
+ rot_mode = ov5642_rot_vert_flip_VGA ;
+
+ if (ov5642_set_rot_mode(rot_mode))
+ retval = -EPERM;
+ break;
+ case V4L2_MXC_ROTATE_HORIZ_FLIP:
+ if (captureMode == ov5642_mode_QSXGA_2592_1944)
+ rot_mode = ov5642_rot_horiz_flip_FULL;
+ else
+ rot_mode = ov5642_rot_horiz_flip_VGA;
+
+ if (ov5642_set_rot_mode(rot_mode))
+ retval = -EPERM;
+ break;
+ case V4L2_MXC_ROTATE_180:
+ if (captureMode == ov5642_mode_QSXGA_2592_1944)
+ rot_mode = ov5642_rot_180_FULL;
+ else
+ rot_mode = ov5642_rot_180_VGA;
+
+ if (ov5642_set_rot_mode(rot_mode))
+ retval = -EPERM;
+ break;
+ default:
+ retval = -EPERM;
+ break;
+ }
+ break;
+ default:
+ retval = -EPERM;
+ break;
+ }
+
+ return retval;
+}
+
+/*!
+ * ioctl_enum_framesizes - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ioctl_enum_framesizes(struct v4l2_int_device *s,
+ struct v4l2_frmsizeenum *fsize)
+{
+ if (fsize->index > ov5642_mode_MAX)
+ return -EINVAL;
+
+ fsize->pixel_format = ov5642_data.pix.pixelformat;
+ fsize->discrete.width =
+ max(ov5642_mode_info_data[0][fsize->index].width,
+ ov5642_mode_info_data[1][fsize->index].width);
+ fsize->discrete.height =
+ max(ov5642_mode_info_data[0][fsize->index].height,
+ ov5642_mode_info_data[1][fsize->index].height);
+ return 0;
+}
+
+/*!
+ * ioctl_enum_frameintervals - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMEINTERVALS ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ioctl_enum_frameintervals(struct v4l2_int_device *s,
+ struct v4l2_frmivalenum *fival)
+{
+ int i, j, count;
+
+ if (fival->index < 0 || fival->index > ov5642_mode_MAX)
+ return -EINVAL;
+
+ if (fival->pixel_format == 0 || fival->width == 0 ||
+ fival->height == 0) {
+ pr_warning("Please assign pixelformat, width and height.\n");
+ return -EINVAL;
+ }
+
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->discrete.numerator = 1;
+
+ count = 0;
+ for (i = 0; i < ARRAY_SIZE(ov5642_mode_info_data); i++) {
+ for (j = 0; j < (ov5642_mode_MAX + 1); j++) {
+ if (fival->pixel_format == ov5642_data.pix.pixelformat
+ && fival->width == ov5642_mode_info_data[i][j].width
+ && fival->height == ov5642_mode_info_data[i][j].height
+ && ov5642_mode_info_data[i][j].init_data_ptr != NULL) {
+ count++;
+ }
+ if (fival->index == (count - 1)) {
+ fival->discrete.denominator =
+ ov5642_framerates[i];
+ return 0;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+/*!
+ * ioctl_g_chip_ident - V4L2 sensor interface handler for
+ * VIDIOC_DBG_G_CHIP_IDENT ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @id: pointer to int
+ *
+ * Return 0.
+ */
+static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id)
+{
+ ((struct v4l2_dbg_chip_ident *)id)->match.type =
+ V4L2_CHIP_MATCH_I2C_DRIVER;
+ strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name, "ov5642_camera");
+
+ return 0;
+}
+
+/*!
+ * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT
+ * @s: pointer to standard V4L2 device structure
+ */
+static int ioctl_init(struct v4l2_int_device *s)
+{
+
+ return 0;
+}
+
+/*!
+ * ioctl_enum_fmt_cap - V4L2 sensor interface handler for VIDIOC_ENUM_FMT
+ * @s: pointer to standard V4L2 device structure
+ * @fmt: pointer to standard V4L2 fmt description structure
+ *
+ * Return 0.
+ */
+static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_fmtdesc *fmt)
+{
+ if (fmt->index > 0) /* only 1 pixelformat support so far */
+ return -EINVAL;
+
+ fmt->pixelformat = ov5642_data.pix.pixelformat;
+
+ return 0;
+}
+
+/*!
+ * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialise the device when slave attaches to the master.
+ */
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+ struct reg_value *pModeSetting = NULL;
+ s32 i = 0;
+ s32 iModeSettingArySize = 0;
+ register u32 Delay_ms = 0;
+ register u16 RegAddr = 0;
+ register u8 Mask = 0;
+ register u8 Val = 0;
+ u8 RegVal = 0;
+ int retval = 0;
+
+ struct sensor_data *sensor = s->priv;
+ u32 tgt_xclk; /* target xclk */
+ u32 tgt_fps; /* target frames per secound */
+ enum ov5642_frame_rate frame_rate;
+
+ ov5642_data.on = true;
+
+ /* mclk */
+ tgt_xclk = ov5642_data.mclk;
+ tgt_xclk = min(tgt_xclk, (u32)OV5642_XCLK_MAX);
+ tgt_xclk = max(tgt_xclk, (u32)OV5642_XCLK_MIN);
+ ov5642_data.mclk = tgt_xclk;
+
+ pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000);
+
+ /* Default camera frame rate is set in probe */
+ tgt_fps = sensor->streamcap.timeperframe.denominator /
+ sensor->streamcap.timeperframe.numerator;
+
+ if (tgt_fps == 15)
+ frame_rate = ov5642_15_fps;
+ else if (tgt_fps == 30)
+ frame_rate = ov5642_30_fps;
+ else
+ return -EINVAL; /* Only support 15fps or 30fps now. */
+
+ pModeSetting = ov5642_initial_setting;
+ iModeSettingArySize = ARRAY_SIZE(ov5642_initial_setting);
+
+ for (i = 0; i < iModeSettingArySize; ++i, ++pModeSetting) {
+ Delay_ms = pModeSetting->u32Delay_ms;
+ RegAddr = pModeSetting->u16RegAddr;
+ Val = pModeSetting->u8Val;
+ Mask = pModeSetting->u8Mask;
+ if (Mask) {
+ retval = ov5642_read_reg(RegAddr, &RegVal);
+ if (retval < 0)
+ goto err;
+
+ RegVal &= ~(u8)Mask;
+ Val &= Mask;
+ Val |= RegVal;
+ }
+
+ retval = ov5642_write_reg(RegAddr, Val);
+ if (retval < 0)
+ goto err;
+
+ if (Delay_ms)
+ msleep(Delay_ms);
+ }
+err:
+ return retval;
+}
+
+/*!
+ * ioctl_dev_exit - V4L2 sensor interface handler for vidioc_int_dev_exit_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Delinitialise the device when slave detaches to the master.
+ */
+static int ioctl_dev_exit(struct v4l2_int_device *s)
+{
+ return 0;
+}
+
+/*!
+ * This structure defines all the ioctls for this module and links them to the
+ * enumeration.
+ */
+static struct v4l2_int_ioctl_desc ov5642_ioctl_desc[] = {
+ { vidioc_int_dev_init_num,
+ (v4l2_int_ioctl_func *)ioctl_dev_init },
+ { vidioc_int_dev_exit_num, ioctl_dev_exit},
+ { vidioc_int_s_power_num,
+ (v4l2_int_ioctl_func *)ioctl_s_power },
+ { vidioc_int_g_ifparm_num,
+ (v4l2_int_ioctl_func *)ioctl_g_ifparm },
+/* { vidioc_int_g_needs_reset_num,
+ (v4l2_int_ioctl_func *)ioctl_g_needs_reset }, */
+/* { vidioc_int_reset_num,
+ (v4l2_int_ioctl_func *)ioctl_reset }, */
+ { vidioc_int_init_num,
+ (v4l2_int_ioctl_func *)ioctl_init },
+ { vidioc_int_enum_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap },
+/* { vidioc_int_try_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_try_fmt_cap }, */
+ { vidioc_int_g_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_g_fmt_cap },
+/* { vidioc_int_s_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_s_fmt_cap }, */
+ { vidioc_int_g_parm_num,
+ (v4l2_int_ioctl_func *)ioctl_g_parm },
+ { vidioc_int_s_parm_num,
+ (v4l2_int_ioctl_func *)ioctl_s_parm },
+/* { vidioc_int_queryctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_queryctrl }, */
+ { vidioc_int_g_ctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_g_ctrl },
+ { vidioc_int_s_ctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_s_ctrl },
+ { vidioc_int_enum_framesizes_num,
+ (v4l2_int_ioctl_func *)ioctl_enum_framesizes },
+ { vidioc_int_enum_frameintervals_num,
+ (v4l2_int_ioctl_func *)ioctl_enum_frameintervals },
+ { vidioc_int_g_chip_ident_num,
+ (v4l2_int_ioctl_func *)ioctl_g_chip_ident },
+};
+
+static struct v4l2_int_slave ov5642_slave = {
+ .ioctls = ov5642_ioctl_desc,
+ .num_ioctls = ARRAY_SIZE(ov5642_ioctl_desc),
+};
+
+static struct v4l2_int_device ov5642_int_device = {
+ .module = THIS_MODULE,
+ .name = "ov5642",
+ .type = v4l2_int_type_slave,
+ .u = {
+ .slave = &ov5642_slave,
+ },
+};
+
+/*!
+ * ov5642 I2C probe function
+ *
+ * @param adapter struct i2c_adapter *
+ * @return Error code indicating success or failure
+ */
+static int ov5642_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pinctrl *pinctrl;
+ struct device *dev = &client->dev;
+ int retval;
+ u8 chip_id_high, chip_id_low;
+
+ /* ov5642 pinctrl */
+ pinctrl = devm_pinctrl_get_select_default(dev);
+ if (IS_ERR(pinctrl)) {
+ dev_err(dev, "ov5642 setup pinctrl failed!");
+ return PTR_ERR(pinctrl);
+ }
+
+ /* request power down pin */
+ pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+ if (!gpio_is_valid(pwn_gpio)) {
+ dev_warn(dev, "no sensor pwdn pin available");
+ return -EINVAL;
+ }
+ retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH,
+ "ov5642_pwdn");
+ if (retval < 0)
+ return retval;
+
+ /* request reset pin */
+ rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0);
+ if (!gpio_is_valid(rst_gpio)) {
+ dev_warn(dev, "no sensor reset pin available");
+ return -EINVAL;
+ }
+ retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH,
+ "ov5642_reset");
+ if (retval < 0)
+ return retval;
+
+ /* Set initial values for the sensor struct. */
+ memset(&ov5642_data, 0, sizeof(ov5642_data));
+ ov5642_data.sensor_clk = devm_clk_get(dev, "csi_mclk");
+ if (IS_ERR(ov5642_data.sensor_clk)) {
+ /* assuming clock enabled by default */
+ ov5642_data.sensor_clk = NULL;
+ dev_err(dev, "clock-frequency missing or invalid\n");
+ return PTR_ERR(ov5642_data.sensor_clk);
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk",
+ (u32 *) &(ov5642_data.mclk));
+ if (retval) {
+ dev_err(dev, "mclk missing or invalid\n");
+ return retval;
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk_source",
+ (u32 *) &(ov5642_data.mclk_source));
+ if (retval) {
+ dev_err(dev, "mclk_source missing or invalid\n");
+ return retval;
+ }
+
+ retval = of_property_read_u32(dev->of_node, "csi_id",
+ &(ov5642_data.csi));
+ if (retval) {
+ dev_err(dev, "csi_id missing or invalid\n");
+ return retval;
+ }
+
+ clk_prepare_enable(ov5642_data.sensor_clk);
+
+ ov5642_data.io_init = ov5642_reset;
+ ov5642_data.i2c_client = client;
+ ov5642_data.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ ov5642_data.pix.width = 640;
+ ov5642_data.pix.height = 480;
+ ov5642_data.streamcap.capability = V4L2_MODE_HIGHQUALITY |
+ V4L2_CAP_TIMEPERFRAME;
+ ov5642_data.streamcap.capturemode = 0;
+ ov5642_data.streamcap.timeperframe.denominator = DEFAULT_FPS;
+ ov5642_data.streamcap.timeperframe.numerator = 1;
+
+ ov5642_power_on(&client->dev);
+
+ ov5642_reset();
+
+ ov5642_standby(0);
+
+ retval = ov5642_read_reg(OV5642_CHIP_ID_HIGH_BYTE, &chip_id_high);
+ if (retval < 0 || chip_id_high != 0x56) {
+ pr_warning("camera ov5642 is not found\n");
+ clk_disable_unprepare(ov5642_data.sensor_clk);
+ return -ENODEV;
+ }
+ retval = ov5642_read_reg(OV5642_CHIP_ID_LOW_BYTE, &chip_id_low);
+ if (retval < 0 || chip_id_low != 0x42) {
+ pr_warning("camera ov5642 is not found\n");
+ clk_disable_unprepare(ov5642_data.sensor_clk);
+ return -ENODEV;
+ }
+
+ ov5642_standby(1);
+
+ ov5642_int_device.priv = &ov5642_data;
+ retval = v4l2_int_device_register(&ov5642_int_device);
+
+ clk_disable_unprepare(ov5642_data.sensor_clk);
+
+ pr_info("camera ov5642 is found\n");
+ return retval;
+}
+
+/*!
+ * ov5642 I2C detach function
+ *
+ * @param client struct i2c_client *
+ * @return Error code indicating success or failure
+ */
+static int ov5642_remove(struct i2c_client *client)
+{
+ v4l2_int_device_unregister(&ov5642_int_device);
+
+ if (gpo_regulator)
+ regulator_disable(gpo_regulator);
+
+ if (analog_regulator)
+ regulator_disable(analog_regulator);
+
+ if (core_regulator)
+ regulator_disable(core_regulator);
+
+ if (io_regulator)
+ regulator_disable(io_regulator);
+
+ return 0;
+}
+
+/*!
+ * ov5642 init function
+ * Called by insmod ov5642_camera.ko.
+ *
+ * @return Error code indicating success or failure
+ */
+static __init int ov5642_init(void)
+{
+ u8 err;
+
+ err = i2c_add_driver(&ov5642_i2c_driver);
+ if (err != 0)
+ pr_err("%s:driver registration failed, error=%d\n",
+ __func__, err);
+
+ return err;
+}
+
+/*!
+ * OV5642 cleanup function
+ * Called on rmmod ov5642_camera.ko
+ *
+ * @return Error code indicating success or failure
+ */
+static void __exit ov5642_clean(void)
+{
+ i2c_del_driver(&ov5642_i2c_driver);
+}
+
+module_init(ov5642_init);
+module_exit(ov5642_clean);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("OV5642 Camera Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("CSI");
diff --git a/drivers/media/platform/mxc/capture/ov5647_mipi.c b/drivers/media/platform/mxc/capture/ov5647_mipi.c
new file mode 100644
index 000000000000..109f77438f51
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/ov5647_mipi.c
@@ -0,0 +1,1721 @@
+/*
+ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/i2c.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#define OV5647_VOLTAGE_ANALOG 2800000
+#define OV5647_VOLTAGE_DIGITAL_CORE 1500000
+#define OV5647_VOLTAGE_DIGITAL_IO 1800000
+
+#define MIN_FPS 15
+#define MAX_FPS 30
+#define DEFAULT_FPS 30
+
+#define OV5647_XCLK_MIN 6000000
+#define OV5647_XCLK_MAX 24000000
+
+#define OV5647_CHIP_ID_HIGH_BYTE 0x300A
+#define OV5647_CHIP_ID_LOW_BYTE 0x300B
+
+enum ov5647_mode {
+ ov5647_mode_MIN = 0,
+ ov5647_mode_VGA_640_480 = 0,
+ ov5647_mode_720P_1280_720 = 1,
+ ov5647_mode_1080P_1920_1080 = 2,
+ ov5647_mode_QSXGA_2592_1944 = 3,
+ ov5647_mode_MAX = 3,
+ ov5647_mode_INIT = 0xff, /*only for sensor init*/
+};
+
+enum ov5647_frame_rate {
+ ov5647_15_fps,
+ ov5647_30_fps
+};
+
+static int ov5647_framerates[] = {
+ [ov5647_15_fps] = 15,
+ [ov5647_30_fps] = 30,
+};
+
+struct ov5647_datafmt {
+ u32 code;
+ enum v4l2_colorspace colorspace;
+};
+
+/* image size under 1280 * 960 are SUBSAMPLING
+ * image size upper 1280 * 960 are SCALING
+ */
+enum ov5647_downsize_mode {
+ SUBSAMPLING,
+ SCALING,
+};
+
+struct reg_value {
+ u16 u16RegAddr;
+ u8 u8Val;
+ u8 u8Mask;
+ u32 u32Delay_ms;
+};
+
+struct ov5647_mode_info {
+ enum ov5647_mode mode;
+ enum ov5647_downsize_mode dn_mode;
+ u32 width;
+ u32 height;
+ struct reg_value *init_data_ptr;
+ u32 init_data_size;
+};
+
+struct otp_struct {
+ int customer_id;
+ int module_integrator_id;
+ int lens_id;
+ int rg_ratio;
+ int bg_ratio;
+ int user_data[3];
+ int light_rg;
+ int light_bg;
+};
+
+struct ov5647 {
+ struct v4l2_subdev subdev;
+ struct i2c_client *i2c_client;
+ struct v4l2_pix_format pix;
+ const struct ov5647_datafmt *fmt;
+ struct v4l2_captureparm streamcap;
+ bool on;
+
+ /* control settings */
+ int brightness;
+ int hue;
+ int contrast;
+ int saturation;
+ int red;
+ int green;
+ int blue;
+ int ae_mode;
+
+ u32 mclk;
+ u8 mclk_source;
+ struct clk *sensor_clk;
+ int csi;
+
+ void (*io_init)(void);
+};
+/*!
+ * Maintains the information on the current state of the sesor.
+ */
+static struct ov5647 ov5647_data;
+static int pwn_gpio, rst_gpio;
+static int prev_sysclk, prev_HTS;
+static int AE_low, AE_high, AE_Target = 52;
+
+/* R/G and B/G of typical camera module is defined here,
+ * the typical camera module is selected by CameraAnalyzer. */
+static int RG_Ratio_Typical = 0x70;
+static int BG_Ratio_Typical = 0x70;
+
+
+static struct reg_value ov5647_init_setting[] = {
+
+ {0x0100, 0x00, 0, 0}, {0x3035, 0x11, 0, 0},
+ {0x3036, 0x69, 0, 0}, {0x303c, 0x11, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x370c, 0x0f, 0, 0}, {0x3612, 0x59, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x5000, 0x06, 0, 0}, {0x5002, 0x40, 0, 0},
+ {0x5003, 0x08, 0, 0}, {0x5a00, 0x08, 0, 0}, {0x3000, 0xff, 0, 0},
+ {0x3001, 0xff, 0, 0}, {0x3002, 0xff, 0, 0}, {0x301d, 0xf0, 0, 0},
+ {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3c01, 0x80, 0, 0},
+ {0x3b07, 0x0c, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
+ {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3814, 0x31, 0, 0},
+ {0x3815, 0x31, 0, 0}, {0x3708, 0x64, 0, 0}, {0x3709, 0x52, 0, 0},
+ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0},
+ {0x380b, 0xc0, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x18, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x0e, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x27, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x95, 0, 0},
+ {0x3630, 0x2e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x23, 0, 0},
+ {0x3634, 0x44, 0, 0}, {0x3620, 0x64, 0, 0}, {0x3621, 0xe0, 0, 0},
+ {0x3600, 0x37, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
+ {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x3731, 0x02, 0, 0},
+ {0x370b, 0x60, 0, 0}, {0x3705, 0x1a, 0, 0}, {0x3f05, 0x02, 0, 0},
+ {0x3f06, 0x10, 0, 0}, {0x3f01, 0x0a, 0, 0}, {0x3a08, 0x01, 0, 0},
+ {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0},
+ {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0f, 0x58, 0, 0},
+ {0x3a10, 0x50, 0, 0}, {0x3a1b, 0x58, 0, 0}, {0x3a1e, 0x50, 0, 0},
+ {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x28, 0, 0}, {0x4001, 0x02, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x4000, 0x09, 0, 0}, {0x4050, 0x6e, 0, 0},
+ {0x4051, 0x8f, 0, 0}, {0x4837, 0x17, 0, 0}, {0x3503, 0x03, 0, 0},
+ {0x3501, 0x44, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350a, 0x00, 0, 0},
+ {0x350b, 0x7f, 0, 0}, {0x5001, 0x01, 0, 0}, {0x5002, 0x41, 0, 0},
+ {0x5180, 0x08, 0, 0}, {0x5186, 0x04, 0, 0}, {0x5187, 0x00, 0, 0},
+ {0x5188, 0x04, 0, 0}, {0x5189, 0x00, 0, 0}, {0x518a, 0x04, 0, 0},
+ {0x518b, 0x00, 0, 0}, {0x5000, 0x86, 0, 0}, {0x5800, 0x11, 0, 0},
+ {0x5801, 0x0a, 0, 0}, {0x5802, 0x09, 0, 0}, {0x5803, 0x09, 0, 0},
+ {0x5804, 0x0a, 0, 0}, {0x5805, 0x0f, 0, 0}, {0x5806, 0x07, 0, 0},
+ {0x5807, 0x05, 0, 0}, {0x5808, 0x03, 0, 0}, {0x5809, 0x03, 0, 0},
+ {0x580a, 0x05, 0, 0}, {0x580b, 0x07, 0, 0}, {0x580c, 0x05, 0, 0},
+ {0x580d, 0x02, 0, 0}, {0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0},
+ {0x5810, 0x02, 0, 0}, {0x5811, 0x05, 0, 0}, {0x5812, 0x05, 0, 0},
+ {0x5813, 0x02, 0, 0}, {0x5814, 0x00, 0, 0}, {0x5815, 0x00, 0, 0},
+ {0x5816, 0x01, 0, 0}, {0x5817, 0x05, 0, 0}, {0x5818, 0x08, 0, 0},
+ {0x5819, 0x05, 0, 0}, {0x581a, 0x03, 0, 0}, {0x581b, 0x03, 0, 0},
+ {0x581c, 0x04, 0, 0}, {0x581d, 0x07, 0, 0}, {0x581e, 0x10, 0, 0},
+ {0x581f, 0x0b, 0, 0}, {0x5820, 0x09, 0, 0}, {0x5821, 0x09, 0, 0},
+ {0x5822, 0x09, 0, 0}, {0x5823, 0x0e, 0, 0}, {0x5824, 0x28, 0, 0},
+ {0x5825, 0x1a, 0, 0}, {0x5826, 0x1a, 0, 0}, {0x5827, 0x1a, 0, 0},
+ {0x5828, 0x46, 0, 0}, {0x5829, 0x2a, 0, 0}, {0x582a, 0x26, 0, 0},
+ {0x582b, 0x44, 0, 0}, {0x582c, 0x26, 0, 0}, {0x582d, 0x2a, 0, 0},
+ {0x582e, 0x28, 0, 0}, {0x582f, 0x42, 0, 0}, {0x5830, 0x40, 0, 0},
+ {0x5831, 0x42, 0, 0}, {0x5832, 0x28, 0, 0}, {0x5833, 0x0a, 0, 0},
+ {0x5834, 0x16, 0, 0}, {0x5835, 0x44, 0, 0}, {0x5836, 0x26, 0, 0},
+ {0x5837, 0x2a, 0, 0}, {0x5838, 0x28, 0, 0}, {0x5839, 0x0a, 0, 0},
+ {0x583a, 0x0a, 0, 0}, {0x583b, 0x0a, 0, 0}, {0x583c, 0x26, 0, 0},
+ {0x583d, 0xbe, 0, 0}, {0x0100, 0x01, 0, 0}, {0x3000, 0x00, 0, 0},
+ {0x3001, 0x00, 0, 0}, {0x3002, 0x00, 0, 0}, {0x3017, 0xe0, 0, 0},
+ {0x301c, 0xfc, 0, 0}, {0x3636, 0x06, 0, 0}, {0x3016, 0x08, 0, 0},
+ {0x3827, 0xec, 0, 0}, {0x3018, 0x44, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3106, 0xf5, 0, 0}, {0x3034, 0x18, 0, 0}, {0x301c, 0xf8, 0, 0},
+};
+
+static struct reg_value ov5647_setting_60fps_VGA_640_480[] = {
+ {0x0100, 0x00, 0, 0}, {0x3035, 0x11, 0, 0},
+ {0x3036, 0x46, 0, 0}, {0x303c, 0x11, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3820, 0x41, 0, 0}, {0x370c, 0x0f, 0, 0}, {0x3612, 0x59, 0, 0},
+ {0x3618, 0x00, 0, 0}, {0x5000, 0x06, 0, 0}, {0x5002, 0x40, 0, 0},
+ {0x5003, 0x08, 0, 0}, {0x5a00, 0x08, 0, 0}, {0x3000, 0xff, 0, 0},
+ {0x3001, 0xff, 0, 0}, {0x3002, 0xff, 0, 0}, {0x301d, 0xf0, 0, 0},
+ {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3c01, 0x80, 0, 0},
+ {0x3b07, 0x0c, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x3c, 0, 0},
+ {0x380e, 0x01, 0, 0}, {0x380f, 0xf8, 0, 0}, {0x3814, 0x71, 0, 0},
+ {0x3815, 0x71, 0, 0}, {0x3708, 0x64, 0, 0}, {0x3709, 0x52, 0, 0},
+ {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
+ {0x380b, 0xe0, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x10, 0, 0},
+ {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
+ {0x3805, 0x2f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
+ {0x3630, 0x2e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x23, 0, 0},
+ {0x3634, 0x44, 0, 0}, {0x3620, 0x64, 0, 0}, {0x3621, 0xe0, 0, 0},
+ {0x3600, 0x37, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
+ {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x3731, 0x02, 0, 0},
+ {0x370b, 0x60, 0, 0}, {0x3705, 0x1a, 0, 0}, {0x3f05, 0x02, 0, 0},
+ {0x3f06, 0x10, 0, 0}, {0x3f01, 0x0a, 0, 0}, {0x3a08, 0x01, 0, 0},
+ {0x3a09, 0x2e, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xfb, 0, 0},
+ {0x3a0d, 0x02, 0, 0}, {0x3a0e, 0x01, 0, 0}, {0x3a0f, 0x58, 0, 0},
+ {0x3a10, 0x50, 0, 0}, {0x3a1b, 0x58, 0, 0}, {0x3a1e, 0x50, 0, 0},
+ {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x28, 0, 0}, {0x4001, 0x02, 0, 0},
+ {0x4004, 0x02, 0, 0}, {0x4000, 0x09, 0, 0}, {0x4050, 0x6e, 0, 0},
+ {0x4051, 0x8f, 0, 0}, {0x0100, 0x01, 0, 0}, {0x3000, 0x00, 0, 0},
+ {0x3001, 0x00, 0, 0}, {0x3002, 0x00, 0, 0}, {0x3017, 0xe0, 0, 0},
+ {0x301c, 0xfc, 0, 0}, {0x3636, 0x06, 0, 0}, {0x3016, 0x08, 0, 0},
+ {0x3827, 0xec, 0, 0}, {0x3018, 0x44, 0, 0}, {0x3035, 0x21, 0, 0},
+ {0x3106, 0xf5, 0, 0}, {0x3034, 0x18, 0, 0}, {0x301c, 0xf8, 0, 0},
+};
+
+static struct reg_value ov5647_setting_30fps_720P_1280_720[] = {
+ {0x0100, 0x00, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0},
+ {0x3612, 0x59, 0, 0}, {0x3618, 0x00, 0, 0}, {0x380c, 0x09, 0, 0},
+ {0x380d, 0xe8, 0, 0}, {0x380e, 0x04, 0, 0}, {0x380f, 0x50, 0, 0},
+ {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3709, 0x52, 0, 0},
+ {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
+ {0x380b, 0xd0, 0, 0}, {0x3801, 0x18, 0, 0}, {0x3802, 0x00, 0, 0},
+ {0x3803, 0xf8, 0, 0}, {0x3804, 0x0a, 0, 0}, {0x3805, 0x27, 0, 0},
+ {0x3806, 0x06, 0, 0}, {0x3807, 0xa7, 0, 0}, {0x3a09, 0xbe, 0, 0},
+ {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x74, 0, 0}, {0x3a0d, 0x02, 0, 0},
+ {0x3a0e, 0x01, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4005, 0x18, 0, 0},
+ {0x0100, 0x01, 0, 0},
+};
+
+static struct reg_value ov5647_setting_30fps_1080P_1920_1080[] = {
+ {0x0100, 0x00, 0, 0}, {0x3820, 0x00, 0, 0}, {0x3821, 0x06, 0, 0},
+ {0x3612, 0x5b, 0, 0}, {0x3618, 0x04, 0, 0}, {0x380c, 0x09, 0, 0},
+ {0x380d, 0xe8, 0, 0}, {0x380e, 0x04, 0, 0}, {0x380f, 0x50, 0, 0},
+ {0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3709, 0x12, 0, 0},
+ {0x3808, 0x07, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0},
+ {0x380b, 0x38, 0, 0}, {0x3801, 0x5c, 0, 0}, {0x3802, 0x01, 0, 0},
+ {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xe3, 0, 0},
+ {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3a09, 0x4b, 0, 0},
+ {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x13, 0, 0}, {0x3a0d, 0x04, 0, 0},
+ {0x3a0e, 0x03, 0, 0}, {0x4004, 0x04, 0, 0}, {0x4005, 0x18, 0, 0},
+ {0x0100, 0x01, 0, 0},
+};
+
+static struct reg_value ov5647_setting_15fps_QSXGA_2592_1944[] = {
+ {0x0100, 0x00, 0, 0}, {0x3820, 0x00, 0, 0}, {0x3821, 0x06, 0, 0},
+ {0x3612, 0x5b, 0, 0}, {0x3618, 0x04, 0, 0}, {0x380c, 0x0b, 0, 0},
+ {0x380d, 0x10, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb8, 0, 0},
+ {0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3709, 0x12, 0, 0},
+ {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0},
+ {0x380b, 0x98, 0, 0}, {0x3801, 0x0c, 0, 0}, {0x3802, 0x00, 0, 0},
+ {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, {0x3805, 0x33, 0, 0},
+ {0x3806, 0x07, 0, 0}, {0x3807, 0xa3, 0, 0}, {0x3a09, 0x28, 0, 0},
+ {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0d, 0x08, 0, 0},
+ {0x3a0e, 0x06, 0, 0}, {0x4004, 0x04, 0, 0}, {0x4005, 0x1a, 0, 0},
+ {0x0100, 0x01, 0, 0},
+};
+
+static struct ov5647_mode_info ov5647_mode_info_data[2][ov5647_mode_MAX + 1] = {
+ {
+ {ov5647_mode_VGA_640_480, -1, 0, 0, NULL, 0},
+ {ov5647_mode_720P_1280_720, -1, 0, 0, NULL, 0},
+ {ov5647_mode_1080P_1920_1080, -1, 0, 0, NULL, 0},
+ {ov5647_mode_QSXGA_2592_1944, SCALING, 2592, 1944,
+ ov5647_setting_15fps_QSXGA_2592_1944,
+ ARRAY_SIZE(ov5647_setting_15fps_QSXGA_2592_1944)},
+ },
+ {
+ /* Actually VGA working in 60fps mode */
+ {ov5647_mode_VGA_640_480, SUBSAMPLING, 640, 480,
+ ov5647_setting_60fps_VGA_640_480,
+ ARRAY_SIZE(ov5647_setting_60fps_VGA_640_480)},
+ {ov5647_mode_720P_1280_720, SUBSAMPLING, 1280, 720,
+ ov5647_setting_30fps_720P_1280_720,
+ ARRAY_SIZE(ov5647_setting_30fps_720P_1280_720)},
+ {ov5647_mode_1080P_1920_1080, SCALING, 1920, 1080,
+ ov5647_setting_30fps_1080P_1920_1080,
+ ARRAY_SIZE(ov5647_setting_30fps_1080P_1920_1080)},
+ {ov5647_mode_QSXGA_2592_1944, -1, 0, 0, NULL, 0},
+ },
+};
+
+static struct regulator *io_regulator;
+static struct regulator *core_regulator;
+static struct regulator *analog_regulator;
+static struct regulator *gpo_regulator;
+
+static int ov5647_probe(struct i2c_client *adapter,
+ const struct i2c_device_id *device_id);
+static int ov5647_remove(struct i2c_client *client);
+
+static s32 ov5647_read_reg(u16 reg, u8 *val);
+static s32 ov5647_write_reg(u16 reg, u8 val);
+
+static const struct i2c_device_id ov5647_id[] = {
+ {"ov5647_mipi", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, ov5647_id);
+
+static struct i2c_driver ov5647_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ov5647_mipi",
+ },
+ .probe = ov5647_probe,
+ .remove = ov5647_remove,
+ .id_table = ov5647_id,
+};
+
+static const struct ov5647_datafmt ov5647_colour_fmts[] = {
+ {MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_JPEG},
+};
+
+static struct ov5647 *to_ov5647(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct ov5647, subdev);
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct ov5647_datafmt
+ *ov5647_find_datafmt(u32 code)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ov5647_colour_fmts); i++)
+ if (ov5647_colour_fmts[i].code == code)
+ return ov5647_colour_fmts + i;
+
+ return NULL;
+}
+
+static inline void ov5647_power_down(int enable)
+{
+ if (pwn_gpio < 0)
+ return;
+
+ /* 19x19 pwdn pin invert by mipi daughter card */
+ if (!enable)
+ gpio_set_value_cansleep(pwn_gpio, 1);
+ else
+ gpio_set_value_cansleep(pwn_gpio, 0);
+
+ msleep(2);
+}
+
+static void ov5647_reset(void)
+{
+ if (rst_gpio < 0 || pwn_gpio < 0)
+ return;
+
+ /* camera reset */
+ gpio_set_value_cansleep(rst_gpio, 1);
+
+ /* camera power dowmn */
+ gpio_set_value_cansleep(pwn_gpio, 1);
+ msleep(5);
+
+ gpio_set_value_cansleep(pwn_gpio, 0);
+ msleep(5);
+
+ gpio_set_value_cansleep(rst_gpio, 0);
+ msleep(1);
+
+ gpio_set_value_cansleep(rst_gpio, 1);
+ msleep(5);
+
+ gpio_set_value_cansleep(pwn_gpio, 1);
+}
+
+static int ov5647_regulator_enable(struct device *dev)
+{
+ int ret = 0;
+
+ io_regulator = devm_regulator_get(dev, "DOVDD");
+ if (!IS_ERR(io_regulator)) {
+ regulator_set_voltage(io_regulator,
+ OV5647_VOLTAGE_DIGITAL_IO,
+ OV5647_VOLTAGE_DIGITAL_IO);
+ ret = regulator_enable(io_regulator);
+ if (ret) {
+ pr_err("%s:io set voltage error\n", __func__);
+ return ret;
+ } else {
+ dev_dbg(dev,
+ "%s:io set voltage ok\n", __func__);
+ }
+ } else {
+ pr_err("%s: cannot get io voltage error\n", __func__);
+ io_regulator = NULL;
+ }
+
+ core_regulator = devm_regulator_get(dev, "DVDD");
+ if (!IS_ERR(core_regulator)) {
+ regulator_set_voltage(core_regulator,
+ OV5647_VOLTAGE_DIGITAL_CORE,
+ OV5647_VOLTAGE_DIGITAL_CORE);
+ ret = regulator_enable(core_regulator);
+ if (ret) {
+ pr_err("%s:core set voltage error\n", __func__);
+ return ret;
+ } else {
+ dev_dbg(dev,
+ "%s:core set voltage ok\n", __func__);
+ }
+ } else {
+ core_regulator = NULL;
+ pr_err("%s: cannot get core voltage error\n", __func__);
+ }
+
+ analog_regulator = devm_regulator_get(dev, "AVDD");
+ if (!IS_ERR(analog_regulator)) {
+ regulator_set_voltage(analog_regulator,
+ OV5647_VOLTAGE_ANALOG,
+ OV5647_VOLTAGE_ANALOG);
+ ret = regulator_enable(analog_regulator);
+ if (ret) {
+ pr_err("%s:analog set voltage error\n",
+ __func__);
+ return ret;
+ } else {
+ dev_dbg(dev,
+ "%s:analog set voltage ok\n", __func__);
+ }
+ } else {
+ analog_regulator = NULL;
+ pr_err("%s: cannot get analog voltage error\n", __func__);
+ }
+
+ return ret;
+}
+
+static s32 ov5647_write_reg(u16 reg, u8 val)
+{
+ u8 au8Buf[3] = {0};
+
+ au8Buf[0] = reg >> 8;
+ au8Buf[1] = reg & 0xff;
+ au8Buf[2] = val;
+
+ if (i2c_master_send(ov5647_data.i2c_client, au8Buf, 3) < 0) {
+ pr_err("%s:write reg error:reg=%x,val=%x\n",
+ __func__, reg, val);
+ return -1;
+ }
+
+ return 0;
+}
+
+static s32 ov5647_read_reg(u16 reg, u8 *val)
+{
+ u8 au8RegBuf[2] = {0};
+ u8 u8RdVal = 0;
+
+ au8RegBuf[0] = reg >> 8;
+ au8RegBuf[1] = reg & 0xff;
+
+ if (2 != i2c_master_send(ov5647_data.i2c_client, au8RegBuf, 2)) {
+ pr_err("%s:write reg error:reg=%x\n",
+ __func__, reg);
+ return -1;
+ }
+
+ if (1 != i2c_master_recv(ov5647_data.i2c_client, &u8RdVal, 1)) {
+ pr_err("%s:read reg error:reg=%x,val=%x\n",
+ __func__, reg, u8RdVal);
+ return -1;
+ }
+
+ *val = u8RdVal;
+
+ return u8RdVal;
+}
+
+/* index: index of otp group. (0, 1, 2)
+ * return:
+ * 0, group index is empty
+ * 1, group index has invalid data
+ * 2, group index has valid data */
+static int ov5647_check_otp(int index)
+{
+ int i;
+ int address;
+ u8 temp;
+
+ /* read otp into buffer */
+ ov5647_write_reg(0x3d21, 0x01);
+ msleep(20);
+ address = 0x3d05 + index * 9;
+ temp = ov5647_read_reg(address, &temp);
+
+ /* disable otp read */
+ ov5647_write_reg(0x3d21, 0x00);
+
+ /* clear otp buffer */
+ for (i = 0; i < 32; i++)
+ ov5647_write_reg(0x3d00 + i, 0x00);
+
+ if (!temp)
+ return 0;
+ else if ((!(temp & 0x80)) && (temp & 0x7f))
+ return 2;
+ else
+ return 1;
+}
+
+/* index: index of otp group. (0, 1, 2)
+ * return: 0 */
+static int ov5647_read_otp(int index, struct otp_struct *otp_ptr)
+{
+ int i;
+ int address;
+ u8 temp;
+
+ /* read otp into buffer */
+ ov5647_write_reg(0x3d21, 0x01);
+ msleep(2);
+ address = 0x3d05 + index * 9;
+ temp = ov5647_read_reg(address, &temp);
+ (*otp_ptr).customer_id = temp & 0x7f;
+
+ (*otp_ptr).module_integrator_id = ov5647_read_reg(address, &temp);
+ (*otp_ptr).lens_id = ov5647_read_reg(address + 1, &temp);
+ (*otp_ptr).rg_ratio = ov5647_read_reg(address + 2, &temp);
+ (*otp_ptr).bg_ratio = ov5647_read_reg(address + 3, &temp);
+ (*otp_ptr).user_data[0] = ov5647_read_reg(address + 4, &temp);
+ (*otp_ptr).user_data[1] = ov5647_read_reg(address + 5, &temp);
+ (*otp_ptr).user_data[2] = ov5647_read_reg(address + 6, &temp);
+ (*otp_ptr).light_rg = ov5647_read_reg(address + 7, &temp);
+ (*otp_ptr).light_bg = ov5647_read_reg(address + 8, &temp);
+
+ /* disable otp read */
+ ov5647_write_reg(0x3d21, 0x00);
+
+ /* clear otp buffer */
+ for (i = 0; i < 32; i++)
+ ov5647_write_reg(0x3d00 + i, 0x00);
+
+ return 0;
+}
+
+/* R_gain, sensor red gain of AWB, 0x400 =1
+ * G_gain, sensor green gain of AWB, 0x400 =1
+ * B_gain, sensor blue gain of AWB, 0x400 =1
+ * return 0 */
+static int ov5647_update_awb_gain(int R_gain, int G_gain, int B_gain)
+{
+ if (R_gain > 0x400) {
+ ov5647_write_reg(0x5186, R_gain >> 8);
+ ov5647_write_reg(0x5187, R_gain & 0x00ff);
+ }
+ if (G_gain > 0x400) {
+ ov5647_write_reg(0x5188, G_gain >> 8);
+ ov5647_write_reg(0x5189, G_gain & 0x00ff);
+ }
+ if (B_gain > 0x400) {
+ ov5647_write_reg(0x518a, B_gain >> 8);
+ ov5647_write_reg(0x518b, B_gain & 0x00ff);
+ }
+
+ return 0;
+}
+
+/* call this function after OV5647 initialization
+ * return value:
+ * 0 update success
+ * 1 no OTP */
+static int ov5647_update_otp(void)
+{
+ struct otp_struct current_otp;
+ int i;
+ int otp_index;
+ int temp;
+ int R_gain, G_gain, B_gain, G_gain_R, G_gain_B;
+ int rg, bg;
+
+ /* R/G and B/G of current camera module is read out from sensor OTP
+ * check first OTP with valid data */
+ for (i = 0; i < 3; i++) {
+ temp = ov5647_check_otp(i);
+ if (temp == 2) {
+ otp_index = i;
+ break;
+ }
+ }
+ if (i == 3) {
+ /* no valid wb OTP data */
+ printk(KERN_WARNING "No valid wb otp data\n");
+ return 1;
+ }
+
+ ov5647_read_otp(otp_index, &current_otp);
+ if (current_otp.light_rg == 0)
+ rg = current_otp.rg_ratio;
+ else
+ rg = current_otp.rg_ratio * (current_otp.light_rg + 128) / 256;
+
+ if (current_otp.light_bg == 0)
+ bg = current_otp.bg_ratio;
+ else
+ bg = current_otp.bg_ratio * (current_otp.light_bg + 128) / 256;
+
+ /* calculate G gain
+ * 0x400 = 1x gain */
+ if (bg < BG_Ratio_Typical) {
+ if (rg < RG_Ratio_Typical) {
+ /* current_otp.bg_ratio < BG_Ratio_typical &&
+ * current_otp.rg_ratio < RG_Ratio_typical */
+ G_gain = 0x400;
+ B_gain = 0x400 * BG_Ratio_Typical / bg;
+ R_gain = 0x400 * RG_Ratio_Typical / rg;
+ } else {
+ /* current_otp.bg_ratio < BG_Ratio_typical &&
+ * current_otp.rg_ratio >= RG_Ratio_typical */
+ R_gain = 0x400;
+ G_gain = 0x400 * rg / RG_Ratio_Typical;
+ B_gain = G_gain * BG_Ratio_Typical / bg;
+ }
+ } else {
+ if (rg < RG_Ratio_Typical) {
+ /* current_otp.bg_ratio >= BG_Ratio_typical &&
+ * current_otp.rg_ratio < RG_Ratio_typical */
+ B_gain = 0x400;
+ G_gain = 0x400 * bg / BG_Ratio_Typical;
+ R_gain = G_gain * RG_Ratio_Typical / rg;
+ } else {
+ /* current_otp.bg_ratio >= BG_Ratio_typical &&
+ * current_otp.rg_ratio >= RG_Ratio_typical */
+ G_gain_B = 0x400 * bg / BG_Ratio_Typical;
+ G_gain_R = 0x400 * rg / RG_Ratio_Typical;
+ if (G_gain_B > G_gain_R) {
+ B_gain = 0x400;
+ G_gain = G_gain_B;
+ R_gain = G_gain * RG_Ratio_Typical / rg;
+ } else {
+ R_gain = 0x400;
+ G_gain = G_gain_R;
+ B_gain = G_gain * BG_Ratio_Typical / bg;
+ }
+ }
+ }
+ ov5647_update_awb_gain(R_gain, G_gain, B_gain);
+ return 0;
+}
+
+static void ov5647_stream_on(void)
+{
+ ov5647_write_reg(0x4202, 0x00);
+}
+
+static void ov5647_stream_off(void)
+{
+ ov5647_write_reg(0x4202, 0x0f);
+ /* both clock and data lane in LP00 */
+ ov5647_write_reg(0x0100, 0x00);
+}
+
+static int ov5647_get_sysclk(void)
+{
+ /* calculate sysclk */
+ int xvclk = ov5647_data.mclk / 10000;
+ int sysclk, temp1, temp2;
+ int pre_div02x, div_cnt7b, sdiv0, pll_rdiv, bit_div2x, sclk_div, VCO;
+ int pre_div02x_map[] = {2, 2, 4, 6, 8, 3, 12, 5, 16, 2, 2, 2, 2, 2, 2, 2};
+ int sdiv0_map[] = {16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+ int pll_rdiv_map[] = {1, 2};
+ int bit_div2x_map[] = {2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 5, 2, 2, 2, 2, 2};
+ int sclk_div_map[] = {1, 2, 4, 1};
+ u8 temp;
+
+ temp1 = ov5647_read_reg(0x3037, &temp);
+ temp2 = temp1 & 0x0f;
+ pre_div02x = pre_div02x_map[temp2];
+ temp2 = (temp1 >> 4) & 0x01;
+ pll_rdiv = pll_rdiv_map[temp2];
+ temp1 = ov5647_read_reg(0x3036, &temp);
+
+ div_cnt7b = temp1;
+
+ VCO = xvclk * 2 / pre_div02x * div_cnt7b;
+ temp1 = ov5647_read_reg(0x3035, &temp);
+ temp2 = temp1 >> 4;
+ sdiv0 = sdiv0_map[temp2];
+ temp1 = ov5647_read_reg(0x3034, &temp);
+ temp2 = temp1 & 0x0f;
+ bit_div2x = bit_div2x_map[temp2];
+ temp1 = ov5647_read_reg(0x3106, &temp);
+ temp2 = (temp1 >> 2) & 0x03;
+ sclk_div = sclk_div_map[temp2];
+ sysclk = VCO * 2 / sdiv0 / pll_rdiv / bit_div2x / sclk_div;
+ return sysclk;
+}
+
+static void ov5647_set_night_mode(void)
+{
+ /* read HTS from register settings */
+ u8 mode;
+
+ ov5647_read_reg(0x3a00, &mode);
+ mode &= 0xfb;
+ ov5647_write_reg(0x3a00, mode);
+}
+
+static int ov5647_get_HTS(void)
+{
+ /* read HTS from register settings */
+ int HTS;
+ u8 temp;
+
+ HTS = ov5647_read_reg(0x380c, &temp);
+ HTS = (HTS << 8) + ov5647_read_reg(0x380d, &temp);
+
+ return HTS;
+}
+
+static int ov5647_soft_reset(void)
+{
+ /* soft reset ov5647 */
+
+ ov5647_write_reg(0x0103, 0x1);
+ msleep(5);
+
+ return 0;
+}
+
+static int ov5647_get_VTS(void)
+{
+ /* read VTS from register settings */
+ int VTS;
+ u8 temp;
+
+ /* total vertical size[15:8] high byte */
+ VTS = ov5647_read_reg(0x380e, &temp);
+
+ VTS = (VTS << 8) + ov5647_read_reg(0x380f, &temp);
+
+ return VTS;
+}
+
+static int ov5647_set_VTS(int VTS)
+{
+ /* write VTS to registers */
+ int temp;
+
+ temp = VTS & 0xff;
+ ov5647_write_reg(0x380f, temp);
+
+ temp = VTS >> 8;
+ ov5647_write_reg(0x380e, temp);
+
+ return 0;
+}
+
+static int ov5647_get_shutter(void)
+{
+ /* read shutter, in number of line period */
+ int shutter;
+ u8 temp;
+
+ shutter = (ov5647_read_reg(0x03500, &temp) & 0x0f);
+ shutter = (shutter << 8) + ov5647_read_reg(0x3501, &temp);
+ shutter = (shutter << 4) + (ov5647_read_reg(0x3502, &temp)>>4);
+
+ return shutter;
+}
+
+static int ov5647_set_shutter(int shutter)
+{
+ /* write shutter, in number of line period */
+ int temp;
+
+ shutter = shutter & 0xffff;
+
+ temp = shutter & 0x0f;
+ temp = temp << 4;
+ ov5647_write_reg(0x3502, temp);
+
+ temp = shutter & 0xfff;
+ temp = temp >> 4;
+ ov5647_write_reg(0x3501, temp);
+
+ temp = shutter >> 12;
+ ov5647_write_reg(0x3500, temp);
+
+ return 0;
+}
+
+static int ov5647_get_gain16(void)
+{
+ /* read gain, 16 = 1x */
+ int gain16;
+ u8 temp;
+
+ gain16 = ov5647_read_reg(0x350a, &temp) & 0x03;
+ gain16 = (gain16 << 8) + ov5647_read_reg(0x350b, &temp);
+
+ return gain16;
+}
+
+static int ov5647_set_gain16(int gain16)
+{
+ /* write gain, 16 = 1x */
+ u8 temp;
+ gain16 = gain16 & 0x3ff;
+
+ temp = gain16 & 0xff;
+ ov5647_write_reg(0x350b, temp);
+
+ temp = gain16 >> 8;
+ ov5647_write_reg(0x350a, temp);
+
+ return 0;
+}
+
+static int ov5647_get_light_freq(void)
+{
+ /* get banding filter value */
+ int temp, temp1, light_freq = 0;
+ u8 tmp;
+
+ temp = ov5647_read_reg(0x3c01, &tmp);
+
+ if (temp & 0x80) {
+ /* manual */
+ temp1 = ov5647_read_reg(0x3c00, &tmp);
+ if (temp1 & 0x04) {
+ /* 50Hz */
+ light_freq = 50;
+ } else {
+ /* 60Hz */
+ light_freq = 60;
+ }
+ } else {
+ /* auto */
+ temp1 = ov5647_read_reg(0x3c0c, &tmp);
+ if (temp1 & 0x01) {
+ /* 50Hz */
+ light_freq = 50;
+ } else {
+ /* 60Hz */
+ }
+ }
+ return light_freq;
+}
+
+static void ov5647_set_bandingfilter(void)
+{
+ int prev_VTS;
+ int band_step60, max_band60, band_step50, max_band50;
+
+ /* read preview PCLK */
+ prev_sysclk = ov5647_get_sysclk();
+ /* read preview HTS */
+ prev_HTS = ov5647_get_HTS();
+
+ /* read preview VTS */
+ prev_VTS = ov5647_get_VTS();
+
+ /* calculate banding filter */
+ /* 60Hz */
+ band_step60 = prev_sysclk * 100/prev_HTS * 100/120;
+ ov5647_write_reg(0x3a0a, (band_step60 >> 8));
+ ov5647_write_reg(0x3a0b, (band_step60 & 0xff));
+
+ max_band60 = (int)((prev_VTS-4)/band_step60);
+ ov5647_write_reg(0x3a0d, max_band60);
+
+ /* 50Hz */
+ band_step50 = prev_sysclk * 100/prev_HTS;
+ ov5647_write_reg(0x3a08, (band_step50 >> 8));
+ ov5647_write_reg(0x3a09, (band_step50 & 0xff));
+
+ max_band50 = (int)((prev_VTS-4)/band_step50);
+ ov5647_write_reg(0x3a0e, max_band50);
+}
+
+static int ov5647_set_AE_target(int target)
+{
+ /* stable in high */
+ int fast_high, fast_low;
+ AE_low = target * 23 / 25; /* 0.92 */
+ AE_high = target * 27 / 25; /* 1.08 */
+
+ fast_high = AE_high<<1;
+ if (fast_high > 255)
+ fast_high = 255;
+
+ fast_low = AE_low >> 1;
+
+ ov5647_write_reg(0x3a0f, AE_high);
+ ov5647_write_reg(0x3a10, AE_low);
+ ov5647_write_reg(0x3a1b, AE_high);
+ ov5647_write_reg(0x3a1e, AE_low);
+ ov5647_write_reg(0x3a11, fast_high);
+ ov5647_write_reg(0x3a1f, fast_low);
+
+ return 0;
+}
+
+static void ov5647_turn_on_AE_AG(int enable)
+{
+ u8 ae_ag_ctrl;
+
+ ov5647_read_reg(0x3503, &ae_ag_ctrl);
+ if (enable) {
+ /* turn on auto AE/AG */
+ ae_ag_ctrl = ae_ag_ctrl & ~(0x03);
+ } else {
+ /* turn off AE/AG */
+ ae_ag_ctrl = ae_ag_ctrl | 0x03;
+ }
+ ov5647_write_reg(0x3503, ae_ag_ctrl);
+}
+
+static void ov5647_set_virtual_channel(int channel)
+{
+ u8 channel_id;
+
+ ov5647_read_reg(0x4814, &channel_id);
+ channel_id &= ~(3 << 6);
+ ov5647_write_reg(0x4814, channel_id | (channel << 6));
+}
+
+/* download ov5647 settings to sensor through i2c */
+static int ov5647_download_firmware(struct reg_value *pModeSetting, s32 ArySize)
+{
+ register u32 Delay_ms = 0;
+ register u16 RegAddr = 0;
+ register u8 Mask = 0;
+ register u8 Val = 0;
+ u8 RegVal = 0;
+ int i, retval = 0;
+
+ for (i = 0; i < ArySize; ++i, ++pModeSetting) {
+ Delay_ms = pModeSetting->u32Delay_ms;
+ RegAddr = pModeSetting->u16RegAddr;
+ Val = pModeSetting->u8Val;
+ Mask = pModeSetting->u8Mask;
+
+ if (Mask) {
+ retval = ov5647_read_reg(RegAddr, &RegVal);
+ if (retval < 0)
+ goto err;
+
+ RegVal &= ~(u8)Mask;
+ Val &= Mask;
+ Val |= RegVal;
+ }
+
+ retval = ov5647_write_reg(RegAddr, Val);
+ if (retval < 0)
+ goto err;
+
+ if (Delay_ms)
+ msleep(Delay_ms);
+ }
+err:
+ return retval;
+}
+
+/* sensor changes between scaling and subsampling
+ * go through exposure calcualtion
+ */
+static int ov5647_change_mode_exposure_calc(enum ov5647_frame_rate frame_rate,
+ enum ov5647_mode mode)
+{
+ struct reg_value *pModeSetting = NULL;
+ s32 ArySize = 0;
+ int pre_shutter, pre_gain16;
+ int cap_shutter, cap_gain16;
+ int pre_sysclk, pre_HTS;
+ int cap_sysclk, cap_HTS, cap_VTS;
+ long cap_gain16_shutter;
+ int retval = 0;
+
+ /* check if the input mode and frame rate is valid */
+ pModeSetting =
+ ov5647_mode_info_data[frame_rate][mode].init_data_ptr;
+ ArySize =
+ ov5647_mode_info_data[frame_rate][mode].init_data_size;
+
+ ov5647_data.pix.width =
+ ov5647_mode_info_data[frame_rate][mode].width;
+ ov5647_data.pix.height =
+ ov5647_mode_info_data[frame_rate][mode].height;
+
+ if (ov5647_data.pix.width == 0 || ov5647_data.pix.height == 0 ||
+ pModeSetting == NULL || ArySize == 0)
+ return -EINVAL;
+
+ ov5647_stream_off();
+
+ /* turn off night mode for capture */
+ ov5647_set_night_mode();
+
+ pre_shutter = ov5647_get_shutter();
+ pre_gain16 = ov5647_get_gain16();
+ pre_HTS = ov5647_get_HTS();
+ pre_sysclk = ov5647_get_sysclk();
+
+ /* Write capture setting */
+ retval = ov5647_download_firmware(pModeSetting, ArySize);
+ if (retval < 0)
+ goto err;
+
+ /* read capture VTS */
+ cap_VTS = ov5647_get_VTS();
+ cap_HTS = ov5647_get_HTS();
+ cap_sysclk = ov5647_get_sysclk();
+
+ /* calculate capture shutter/gain16 */
+ cap_shutter = pre_shutter * cap_sysclk/pre_sysclk * pre_HTS / cap_HTS;
+
+ if (cap_shutter < 16) {
+ cap_gain16_shutter = pre_shutter * pre_gain16 *
+ cap_sysclk / pre_sysclk * pre_HTS / cap_HTS;
+ cap_shutter = ((int)(cap_gain16_shutter / 16));
+ if (cap_shutter < 1)
+ cap_shutter = 1;
+ cap_gain16 = ((int)(cap_gain16_shutter / cap_shutter));
+ if (cap_gain16 < 16)
+ cap_gain16 = 16;
+ } else
+ cap_gain16 = pre_gain16;
+
+ /* gain to shutter */
+ while ((cap_gain16 > 32) &&
+ (cap_shutter < ((int)((cap_VTS - 4) / 2)))) {
+ cap_gain16 = cap_gain16 / 2;
+ cap_shutter = cap_shutter * 2;
+ }
+ /* write capture gain */
+ ov5647_set_gain16(cap_gain16);
+
+ /* write capture shutter */
+ if (cap_shutter > (cap_VTS - 4)) {
+ cap_VTS = cap_shutter + 4;
+ ov5647_set_VTS(cap_VTS);
+ }
+ ov5647_set_shutter(cap_shutter);
+
+err:
+ return retval;
+}
+
+/* if sensor changes inside scaling or subsampling
+ * change mode directly
+ * */
+static int ov5647_change_mode_direct(enum ov5647_frame_rate frame_rate,
+ enum ov5647_mode mode)
+{
+ struct reg_value *pModeSetting = NULL;
+ s32 ArySize = 0;
+ int retval = 0;
+
+ /* check if the input mode and frame rate is valid */
+ pModeSetting =
+ ov5647_mode_info_data[frame_rate][mode].init_data_ptr;
+ ArySize =
+ ov5647_mode_info_data[frame_rate][mode].init_data_size;
+
+ ov5647_data.pix.width =
+ ov5647_mode_info_data[frame_rate][mode].width;
+ ov5647_data.pix.height =
+ ov5647_mode_info_data[frame_rate][mode].height;
+
+ if (ov5647_data.pix.width == 0 || ov5647_data.pix.height == 0 ||
+ pModeSetting == NULL || ArySize == 0)
+ return -EINVAL;
+
+ /* turn off AE/AG */
+ ov5647_turn_on_AE_AG(0);
+
+ ov5647_stream_off();
+
+ /* Write capture setting */
+ retval = ov5647_download_firmware(pModeSetting, ArySize);
+ if (retval < 0)
+ goto err;
+
+ ov5647_turn_on_AE_AG(1);
+
+err:
+ return retval;
+}
+
+static int ov5647_init_mode(enum ov5647_frame_rate frame_rate,
+ enum ov5647_mode mode, enum ov5647_mode orig_mode)
+{
+ struct reg_value *pModeSetting = NULL;
+ s32 ArySize = 0;
+ int retval = 0;
+ u32 msec_wait4stable = 0;
+ enum ov5647_downsize_mode dn_mode, orig_dn_mode;
+
+ if ((mode > ov5647_mode_MAX || mode < ov5647_mode_MIN)
+ && (mode != ov5647_mode_INIT)) {
+ pr_err("Wrong ov5647 mode detected!\n");
+ return -1;
+ }
+
+ dn_mode = ov5647_mode_info_data[frame_rate][mode].dn_mode;
+ orig_dn_mode = ov5647_mode_info_data[frame_rate][orig_mode].dn_mode;
+ if (mode == ov5647_mode_INIT) {
+ ov5647_soft_reset();
+ pModeSetting = ov5647_init_setting;
+ ArySize = ARRAY_SIZE(ov5647_init_setting);
+ retval = ov5647_download_firmware(pModeSetting, ArySize);
+ if (retval < 0)
+ goto err;
+ pModeSetting = ov5647_setting_60fps_VGA_640_480;
+ ArySize = ARRAY_SIZE(ov5647_setting_60fps_VGA_640_480);
+ retval = ov5647_download_firmware(pModeSetting, ArySize);
+
+ ov5647_data.pix.width = 640;
+ ov5647_data.pix.height = 480;
+ } else if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
+ (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
+ /* change between subsampling and scaling
+ * go through exposure calucation */
+ retval = ov5647_change_mode_exposure_calc(frame_rate, mode);
+ } else {
+ /* change inside subsampling or scaling
+ * download firmware directly */
+ retval = ov5647_change_mode_direct(frame_rate, mode);
+ }
+
+ if (retval < 0)
+ goto err;
+
+ ov5647_set_AE_target(AE_Target);
+ ov5647_get_light_freq();
+ ov5647_set_bandingfilter();
+ ov5647_set_virtual_channel(ov5647_data.csi);
+
+ /* add delay to wait for sensor stable */
+ if (mode == ov5647_mode_QSXGA_2592_1944) {
+ /* dump the first two frames: 1/7.5*2
+ * the frame rate of QSXGA is 7.5fps */
+ msec_wait4stable = 267;
+ } else if (frame_rate == ov5647_15_fps) {
+ /* dump the first nine frames: 1/15*9 */
+ msec_wait4stable = 600;
+ } else if (frame_rate == ov5647_30_fps) {
+ /* dump the first nine frames: 1/30*9 */
+ msec_wait4stable = 300;
+ }
+ msleep(msec_wait4stable);
+
+err:
+ return retval;
+}
+
+/*!
+ * ov5647_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @on: indicates power mode (on or off)
+ *
+ * Turns the power on or off, depending on the value of on and returns the
+ * appropriate error code.
+ */
+static int ov5647_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5647 *sensor = to_ov5647(client);
+
+ if (on && !sensor->on) {
+ if (io_regulator)
+ if (regulator_enable(io_regulator) != 0)
+ return -EIO;
+ if (core_regulator)
+ if (regulator_enable(core_regulator) != 0)
+ return -EIO;
+ if (gpo_regulator)
+ if (regulator_enable(gpo_regulator) != 0)
+ return -EIO;
+ if (analog_regulator)
+ if (regulator_enable(analog_regulator) != 0)
+ return -EIO;
+ } else if (!on && sensor->on) {
+ if (analog_regulator)
+ regulator_disable(analog_regulator);
+ if (core_regulator)
+ regulator_disable(core_regulator);
+ if (io_regulator)
+ regulator_disable(io_regulator);
+ if (gpo_regulator)
+ regulator_disable(gpo_regulator);
+ }
+
+ sensor->on = on;
+
+ return 0;
+}
+
+/*!
+ * ov5647_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
+ * @s: pointer to standard V4L2 sub device structure
+ * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
+ *
+ * Returns the sensor's video CAPTURE parameters.
+ */
+static int ov5647_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5647 *sensor = to_ov5647(client);
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+ int ret = 0;
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cparm->capability = sensor->streamcap.capability;
+ cparm->timeperframe = sensor->streamcap.timeperframe;
+ cparm->capturemode = sensor->streamcap.capturemode;
+ ret = 0;
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ ret = -EINVAL;
+ break;
+
+ default:
+ pr_debug(" type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * ov5460_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl
+ * @s: pointer to standard V4L2 sub device structure
+ * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
+ *
+ * Configures the sensor to use the input parameters, if possible. If
+ * not possible, reverts to the old parameters and returns the
+ * appropriate error code.
+ */
+static int ov5647_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5647 *sensor = to_ov5647(client);
+ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+ u32 tgt_fps; /* target frames per secound */
+ enum ov5647_frame_rate frame_rate;
+ enum ov5647_mode orig_mode;
+ int ret = 0;
+
+ /* Make sure power on */
+ ov5647_power_down(0);
+
+ switch (a->type) {
+ /* This is the only case currently handled. */
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ /* Check that the new frame rate is allowed. */
+ if ((timeperframe->numerator == 0) ||
+ (timeperframe->denominator == 0)) {
+ timeperframe->denominator = DEFAULT_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps > MAX_FPS) {
+ timeperframe->denominator = MAX_FPS;
+ timeperframe->numerator = 1;
+ } else if (tgt_fps < MIN_FPS) {
+ timeperframe->denominator = MIN_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ /* Actual frame rate we use */
+ tgt_fps = timeperframe->denominator /
+ timeperframe->numerator;
+
+ if (tgt_fps == 15)
+ frame_rate = ov5647_15_fps;
+ else if (tgt_fps == 30)
+ frame_rate = ov5647_30_fps;
+ else {
+ pr_err(" The camera frame rate is not supported!\n");
+ return -EINVAL;
+ }
+
+ orig_mode = sensor->streamcap.capturemode;
+ ret = ov5647_init_mode(frame_rate,
+ (u32)a->parm.capture.capturemode, orig_mode);
+ if (ret < 0)
+ return ret;
+
+ sensor->streamcap.timeperframe = *timeperframe;
+ sensor->streamcap.capturemode =
+ (u32)a->parm.capture.capturemode;
+
+ break;
+
+ /* These are all the possible cases. */
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ pr_debug("type is not " \
+ "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n",
+ a->type);
+ ret = -EINVAL;
+ break;
+
+ default:
+ pr_debug("type is unknown - %d\n", a->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int ov5647_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct v4l2_mbus_framefmt *mf = &format->format;
+ const struct ov5647_datafmt *fmt = ov5647_find_datafmt(mf->code);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5647 *sensor = to_ov5647(client);
+
+ if (!fmt) {
+ mf->code = ov5647_colour_fmts[0].code;
+ mf->colorspace = ov5647_colour_fmts[0].colorspace;
+ }
+
+ mf->field = V4L2_FIELD_NONE;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+ return 0;
+
+ sensor->fmt = fmt;
+
+ return 0;
+}
+
+static int ov5647_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 ov5647 *sensor = to_ov5647(client);
+ const struct ov5647_datafmt *fmt = sensor->fmt;
+
+ if (format->pad)
+ return -EINVAL;
+
+ mf->code = fmt->code;
+ mf->colorspace = fmt->colorspace;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int ov5647_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(ov5647_colour_fmts))
+ return -EINVAL;
+
+ code->code = ov5647_colour_fmts[code->index].code;
+ return 0;
+}
+
+/*!
+ * ov5647_enum_framesizes - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMESIZES ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ov5647_enum_framesizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index > ov5647_mode_MAX)
+ return -EINVAL;
+
+ fse->max_width =
+ max(ov5647_mode_info_data[0][fse->index].width,
+ ov5647_mode_info_data[1][fse->index].width);
+ fse->min_width = fse->max_width;
+ fse->max_height =
+ max(ov5647_mode_info_data[0][fse->index].height,
+ ov5647_mode_info_data[1][fse->index].height);
+ fse->min_height = fse->max_height;
+ return 0;
+}
+
+/*!
+ * ov5647_enum_frameintervals - V4L2 sensor interface handler for
+ * VIDIOC_ENUM_FRAMEINTERVALS ioctl
+ * @s: pointer to standard V4L2 device structure
+ * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure
+ *
+ * Return 0 if successful, otherwise -EINVAL.
+ */
+static int ov5647_enum_frameintervals(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ int i, j, count;
+
+ if (fie->index < 0 || fie->index > ov5647_mode_MAX)
+ return -EINVAL;
+
+ if (fie->width == 0 || fie->height == 0 ||
+ fie->code == 0) {
+ pr_warning("Please assign pixel format, width and height.\n");
+ return -EINVAL;
+ }
+
+ fie->interval.numerator = 1;
+
+ count = 0;
+ for (i = 0; i < ARRAY_SIZE(ov5647_mode_info_data); i++) {
+ for (j = 0; j < (ov5647_mode_MAX + 1); j++) {
+ if (fie->width == ov5647_mode_info_data[i][j].width
+ && fie->height == ov5647_mode_info_data[i][j].height
+ && ov5647_mode_info_data[i][j].init_data_ptr != NULL) {
+ count++;
+ }
+ if (fie->index == (count - 1)) {
+ fie->interval.denominator =
+ ov5647_framerates[i];
+ return 0;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+/*!
+ * dev_init - V4L2 sensor init
+ * @s: pointer to standard V4L2 device structure
+ *
+ */
+static int init_device(void)
+{
+ u32 tgt_xclk; /* target xclk */
+ u32 tgt_fps; /* target frames per secound */
+ enum ov5647_frame_rate frame_rate;
+ int ret;
+
+ ov5647_data.on = true;
+
+ /* mclk */
+ tgt_xclk = ov5647_data.mclk;
+ tgt_xclk = min(tgt_xclk, (u32)OV5647_XCLK_MAX);
+ tgt_xclk = max(tgt_xclk, (u32)OV5647_XCLK_MIN);
+ ov5647_data.mclk = tgt_xclk;
+
+ pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000);
+
+ /* Default camera frame rate is set in probe */
+ tgt_fps = ov5647_data.streamcap.timeperframe.denominator /
+ ov5647_data.streamcap.timeperframe.numerator;
+
+ if (tgt_fps == 15)
+ frame_rate = ov5647_15_fps;
+ else if (tgt_fps == 30)
+ frame_rate = ov5647_30_fps;
+ else
+ return -EINVAL; /* Only support 15fps or 30fps now. */
+
+ ret = ov5647_init_mode(frame_rate, ov5647_mode_INIT, ov5647_mode_INIT);
+
+ ov5647_update_otp();
+ return ret;
+}
+
+static int ov5647_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ if (enable)
+ ov5647_stream_on();
+ else
+ ov5647_stream_off();
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops ov5647_subdev_video_ops = {
+ .g_parm = ov5647_g_parm,
+ .s_parm = ov5647_s_parm,
+ .s_stream = ov5647_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
+ .enum_frame_size = ov5647_enum_framesizes,
+ .enum_frame_interval = ov5647_enum_frameintervals,
+ .enum_mbus_code = ov5647_enum_mbus_code,
+ .set_fmt = ov5647_set_fmt,
+ .get_fmt = ov5647_get_fmt,
+};
+
+static struct v4l2_subdev_core_ops ov5647_subdev_core_ops = {
+ .s_power = ov5647_s_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ov5647_get_register,
+ .s_register = ov5647_set_register,
+#endif
+};
+
+static struct v4l2_subdev_ops ov5647_subdev_ops = {
+ .core = &ov5647_subdev_core_ops,
+ .video = &ov5647_subdev_video_ops,
+ .pad = &ov5647_subdev_pad_ops,
+};
+
+
+/*!
+ * ov5647 I2C probe function
+ *
+ * @param adapter struct i2c_adapter *
+ * @return Error code indicating success or failure
+ */
+static int ov5647_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pinctrl *pinctrl;
+ struct device *dev = &client->dev;
+ int retval;
+ u8 chip_id_high, chip_id_low;
+
+ /* ov5647 pinctrl */
+ pinctrl = devm_pinctrl_get_select_default(dev);
+ if (IS_ERR(pinctrl)) {
+ dev_warn(dev, "no pin available\n");
+ }
+
+
+ /* request power down pin */
+ pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);
+ if (!gpio_is_valid(pwn_gpio)) {
+ dev_warn(dev, "no sensor pwdn pin available\n");
+ pwn_gpio = -1;
+ } else {
+ retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH,
+ "ov5647_mipi_pwdn");
+ if (retval < 0) {
+ dev_warn(dev, "Failed to set power pin\n");
+ return retval;
+ }
+ }
+
+ /* request reset pin */
+ rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0);
+ if (!gpio_is_valid(rst_gpio)) {
+ dev_warn(dev, "no sensor reset pin available\n");
+ rst_gpio = -1;
+ } else {
+ retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH,
+ "ov5647_mipi_reset");
+ if (retval < 0) {
+ dev_warn(dev, "Failed to set reset pin\n");
+ return retval;
+ }
+ }
+
+ /* Set initial values for the sensor struct. */
+ memset(&ov5647_data, 0, sizeof(ov5647_data));
+ ov5647_data.sensor_clk = devm_clk_get(dev, "csi_mclk");
+ if (IS_ERR(ov5647_data.sensor_clk)) {
+ /* assuming clock enabled by default */
+ ov5647_data.sensor_clk = NULL;
+ dev_err(dev, "clock-frequency missing or invalid\n");
+ return PTR_ERR(ov5647_data.sensor_clk);
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk",
+ &(ov5647_data.mclk));
+ if (retval) {
+ dev_err(dev, "mclk missing or invalid\n");
+ return retval;
+ }
+
+ retval = of_property_read_u32(dev->of_node, "mclk_source",
+ (u32 *) &(ov5647_data.mclk_source));
+ if (retval) {
+ dev_err(dev, "mclk_source missing or invalid\n");
+ return retval;
+ }
+
+ retval = of_property_read_u32(dev->of_node, "csi_id",
+ &(ov5647_data.csi));
+ if (retval) {
+ dev_err(dev, "csi id missing or invalid\n");
+ return retval;
+ }
+
+ clk_prepare_enable(ov5647_data.sensor_clk);
+
+ ov5647_data.io_init = ov5647_reset;
+ ov5647_data.i2c_client = client;
+ ov5647_data.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
+ ov5647_data.pix.width = 640;
+ ov5647_data.pix.height = 480;
+ ov5647_data.streamcap.capability = V4L2_MODE_HIGHQUALITY |
+ V4L2_CAP_TIMEPERFRAME;
+ ov5647_data.streamcap.capturemode = 0;
+ ov5647_data.streamcap.timeperframe.denominator = DEFAULT_FPS;
+ ov5647_data.streamcap.timeperframe.numerator = 1;
+
+ ov5647_regulator_enable(&client->dev);
+
+ ov5647_reset();
+
+ ov5647_power_down(0);
+
+ retval = ov5647_read_reg(OV5647_CHIP_ID_HIGH_BYTE, &chip_id_high);
+ if (retval < 0 || chip_id_high != 0x56) {
+ pr_warning("camera ov5647_mipi is not found\n");
+ clk_disable_unprepare(ov5647_data.sensor_clk);
+ return -ENODEV;
+ }
+ retval = ov5647_read_reg(OV5647_CHIP_ID_LOW_BYTE, &chip_id_low);
+ if (retval < 0 || chip_id_low != 0x47) {
+ pr_warning("camera ov5647_mipi is not found\n");
+ clk_disable_unprepare(ov5647_data.sensor_clk);
+ return -ENODEV;
+ }
+
+ retval = init_device();
+ if (retval < 0) {
+ clk_disable_unprepare(ov5647_data.sensor_clk);
+ pr_warning("camera ov5647 init failed\n");
+ ov5647_power_down(1);
+ return retval;
+ }
+
+ v4l2_i2c_subdev_init(&ov5647_data.subdev, client, &ov5647_subdev_ops);
+
+ ov5647_data.subdev.grp_id = 678;
+ retval = v4l2_async_register_subdev(&ov5647_data.subdev);
+ if (retval < 0)
+ dev_err(&client->dev,
+ "%s--Async register failed, ret=%d\n", __func__, retval);
+
+ ov5647_stream_off();
+ pr_info("camera ov5647_mipi is found\n");
+ return retval;
+}
+
+/*!
+ * ov5647 I2C detach function
+ *
+ * @param client struct i2c_client *
+ * @return Error code indicating success or failure
+ */
+static int ov5647_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_async_unregister_subdev(sd);
+
+ clk_disable_unprepare(ov5647_data.sensor_clk);
+
+ ov5647_power_down(1);
+
+ if (gpo_regulator)
+ regulator_disable(gpo_regulator);
+
+ if (analog_regulator)
+ regulator_disable(analog_regulator);
+
+ if (core_regulator)
+ regulator_disable(core_regulator);
+
+ if (io_regulator)
+ regulator_disable(io_regulator);
+
+ return 0;
+}
+
+module_i2c_driver(ov5647_i2c_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("OV5647 MIPI Camera Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("CSI");
diff --git a/drivers/media/platform/mxc/capture/v4l2-int-device.c b/drivers/media/platform/mxc/capture/v4l2-int-device.c
new file mode 100644
index 000000000000..e49da150f887
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/v4l2-int-device.c
@@ -0,0 +1,165 @@
+/*
+ * drivers/media/video/v4l2-int-device.c
+ *
+ * V4L2 internal ioctl interface.
+ *
+ * Copyright 2005-2014 Freescale Semiconductor, Inc.
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/sort.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+#include "v4l2-int-device.h"
+
+static DEFINE_MUTEX(mutex);
+static LIST_HEAD(int_list);
+
+void v4l2_int_device_try_attach_all(void)
+{
+ struct v4l2_int_device *m, *s;
+
+ list_for_each_entry(m, &int_list, head) {
+ if (m->type != v4l2_int_type_master)
+ continue;
+
+ list_for_each_entry(s, &int_list, head) {
+ if (s->type != v4l2_int_type_slave)
+ continue;
+
+ /* Slave is connected? */
+ if (s->u.slave->master)
+ continue;
+
+ /* Slave wants to attach to master? */
+ if (s->u.slave->attach_to[0] != 0
+ && strncmp(m->name, s->u.slave->attach_to,
+ V4L2NAMESIZE))
+ continue;
+
+ if (!try_module_get(m->module))
+ continue;
+
+ s->u.slave->master = m;
+ if (m->u.master->attach(s)) {
+ s->u.slave->master = NULL;
+ module_put(m->module);
+ continue;
+ }
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(v4l2_int_device_try_attach_all);
+
+static int ioctl_sort_cmp(const void *a, const void *b)
+{
+ const struct v4l2_int_ioctl_desc *d1 = a, *d2 = b;
+
+ if (d1->num > d2->num)
+ return 1;
+
+ if (d1->num < d2->num)
+ return -1;
+
+ return 0;
+}
+
+int v4l2_int_device_register(struct v4l2_int_device *d)
+{
+ if (d->type == v4l2_int_type_slave)
+ sort(d->u.slave->ioctls, d->u.slave->num_ioctls,
+ sizeof(struct v4l2_int_ioctl_desc),
+ &ioctl_sort_cmp, NULL);
+ mutex_lock(&mutex);
+ list_add(&d->head, &int_list);
+ v4l2_int_device_try_attach_all();
+ mutex_unlock(&mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_int_device_register);
+
+void v4l2_int_device_unregister(struct v4l2_int_device *d)
+{
+ mutex_lock(&mutex);
+ list_del(&d->head);
+ if (d->type == v4l2_int_type_slave
+ && d->u.slave->master != NULL) {
+ d->u.slave->master->u.master->detach(d);
+ module_put(d->u.slave->master->module);
+ d->u.slave->master = NULL;
+ }
+ mutex_unlock(&mutex);
+}
+EXPORT_SYMBOL_GPL(v4l2_int_device_unregister);
+
+/* Adapted from search_extable in extable.c. */
+static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd,
+ v4l2_int_ioctl_func *no_such_ioctl)
+{
+ const struct v4l2_int_ioctl_desc *first = slave->ioctls;
+ const struct v4l2_int_ioctl_desc *last =
+ first + slave->num_ioctls - 1;
+
+ while (first <= last) {
+ const struct v4l2_int_ioctl_desc *mid;
+
+ mid = (last - first) / 2 + first;
+
+ if (mid->num < cmd)
+ first = mid + 1;
+ else if (mid->num > cmd)
+ last = mid - 1;
+ else
+ return mid->func;
+ }
+
+ return no_such_ioctl;
+}
+
+static int no_such_ioctl_0(struct v4l2_int_device *d)
+{
+ return -ENOIOCTLCMD;
+}
+
+int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd)
+{
+ return ((v4l2_int_ioctl_func_0 *)
+ find_ioctl(d->u.slave, cmd,
+ (v4l2_int_ioctl_func *)no_such_ioctl_0))(d);
+}
+EXPORT_SYMBOL_GPL(v4l2_int_ioctl_0);
+
+static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg)
+{
+ return -ENOIOCTLCMD;
+}
+
+int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg)
+{
+ return ((v4l2_int_ioctl_func_1 *)
+ find_ioctl(d->u.slave, cmd,
+ (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg);
+}
+EXPORT_SYMBOL_GPL(v4l2_int_ioctl_1);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/capture/v4l2-int-device.h b/drivers/media/platform/mxc/capture/v4l2-int-device.h
new file mode 100644
index 000000000000..810d87f28794
--- /dev/null
+++ b/drivers/media/platform/mxc/capture/v4l2-int-device.h
@@ -0,0 +1,309 @@
+/*
+ * include/media/v4l2-int-device.h
+ *
+ * V4L2 internal ioctl interface.
+ *
+ * Copyright 2005-2014 Freescale Semiconductor, Inc.
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef V4L2_INT_DEVICE_H
+#define V4L2_INT_DEVICE_H
+
+#include <media/v4l2-common.h>
+
+#define V4L2NAMESIZE 32
+
+/*
+ *
+ * The internal V4L2 device interface core.
+ *
+ */
+
+enum v4l2_int_type {
+ v4l2_int_type_master = 1,
+ v4l2_int_type_slave
+};
+
+struct module;
+
+struct v4l2_int_device;
+
+struct v4l2_int_master {
+ int (*attach)(struct v4l2_int_device *slave);
+ void (*detach)(struct v4l2_int_device *slave);
+};
+
+typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *);
+typedef int (v4l2_int_ioctl_func_0)(struct v4l2_int_device *);
+typedef int (v4l2_int_ioctl_func_1)(struct v4l2_int_device *, void *);
+
+struct v4l2_int_ioctl_desc {
+ int num;
+ v4l2_int_ioctl_func *func;
+};
+
+struct v4l2_int_slave {
+ /* Don't touch master. */
+ struct v4l2_int_device *master;
+
+ char attach_to[V4L2NAMESIZE];
+
+ int num_ioctls;
+ struct v4l2_int_ioctl_desc *ioctls;
+};
+
+struct v4l2_int_device {
+ /* Don't touch head. */
+ struct list_head head;
+
+ struct module *module;
+
+ char name[V4L2NAMESIZE];
+
+ enum v4l2_int_type type;
+ union {
+ struct v4l2_int_master *master;
+ struct v4l2_int_slave *slave;
+ } u;
+
+ void *priv;
+};
+
+void v4l2_int_device_try_attach_all(void);
+
+int v4l2_int_device_register(struct v4l2_int_device *d);
+void v4l2_int_device_unregister(struct v4l2_int_device *d);
+
+int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd);
+int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg);
+
+/*
+ *
+ * Types and definitions for IOCTL commands.
+ *
+ */
+
+enum v4l2_power {
+ V4L2_POWER_OFF = 0,
+ V4L2_POWER_ON,
+ V4L2_POWER_STANDBY,
+};
+
+/* Slave interface type. */
+enum v4l2_if_type {
+ /*
+ * Parallel 8-, 10- or 12-bit interface, used by for example
+ * on certain image sensors.
+ */
+ V4L2_IF_TYPE_BT656,
+};
+
+enum v4l2_if_type_bt656_mode {
+ /*
+ * Modes without Bt synchronisation codes. Separate
+ * synchronisation signal lines are used.
+ */
+ V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT,
+ V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT,
+ V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT,
+ /*
+ * Use Bt synchronisation codes. The vertical and horizontal
+ * synchronisation is done based on synchronisation codes.
+ */
+ V4L2_IF_TYPE_BT656_MODE_BT_8BIT,
+ V4L2_IF_TYPE_BT656_MODE_BT_10BIT,
+};
+
+struct v4l2_if_type_bt656 {
+ /*
+ * 0: Frame begins when vsync is high.
+ * 1: Frame begins when vsync changes from low to high.
+ */
+ unsigned frame_start_on_rising_vs:1;
+ /* Use Bt synchronisation codes for sync correction. */
+ unsigned bt_sync_correct:1;
+ /* Swap every two adjacent image data elements. */
+ unsigned swap:1;
+ /* Inverted latch clock polarity from slave. */
+ unsigned latch_clk_inv:1;
+ /* Hs polarity. 0 is active high, 1 active low. */
+ unsigned nobt_hs_inv:1;
+ /* Vs polarity. 0 is active high, 1 active low. */
+ unsigned nobt_vs_inv:1;
+ enum v4l2_if_type_bt656_mode mode;
+ /* Minimum accepted bus clock for slave (in Hz). */
+ u32 clock_min;
+ /* Maximum accepted bus clock for slave. */
+ u32 clock_max;
+ /*
+ * Current wish of the slave. May only change in response to
+ * ioctls that affect image capture.
+ */
+ u32 clock_curr;
+};
+
+struct v4l2_ifparm {
+ enum v4l2_if_type if_type;
+ union {
+ struct v4l2_if_type_bt656 bt656;
+ } u;
+};
+
+/* IOCTL command numbers. */
+enum v4l2_int_ioctl_num {
+ /*
+ *
+ * "Proper" V4L ioctls, as in struct video_device.
+ *
+ */
+ vidioc_int_enum_fmt_cap_num = 1,
+ vidioc_int_g_fmt_cap_num,
+ vidioc_int_s_fmt_cap_num,
+ vidioc_int_try_fmt_cap_num,
+ vidioc_int_queryctrl_num,
+ vidioc_int_g_ctrl_num,
+ vidioc_int_s_ctrl_num,
+ vidioc_int_cropcap_num,
+ vidioc_int_g_crop_num,
+ vidioc_int_s_crop_num,
+ vidioc_int_g_parm_num,
+ vidioc_int_s_parm_num,
+ vidioc_int_querystd_num,
+ vidioc_int_s_std_num,
+ vidioc_int_s_video_routing_num,
+
+ /*
+ *
+ * Strictly internal ioctls.
+ *
+ */
+ /* Initialise the device when slave attaches to the master. */
+ vidioc_int_dev_init_num = 1000,
+ /* Delinitialise the device at slave detach. */
+ vidioc_int_dev_exit_num,
+ /* Set device power state. */
+ vidioc_int_s_power_num,
+ /*
+ * Get slave private data, e.g. platform-specific slave
+ * configuration used by the master.
+ */
+ vidioc_int_g_priv_num,
+ /* Get slave interface parameters. */
+ vidioc_int_g_ifparm_num,
+ /* Does the slave need to be reset after VIDIOC_DQBUF? */
+ vidioc_int_g_needs_reset_num,
+ vidioc_int_enum_framesizes_num,
+ vidioc_int_enum_frameintervals_num,
+
+ /*
+ *
+ * VIDIOC_INT_* ioctls.
+ *
+ */
+ /* VIDIOC_INT_RESET */
+ vidioc_int_reset_num,
+ /* VIDIOC_INT_INIT */
+ vidioc_int_init_num,
+ /* VIDIOC_DBG_G_CHIP_IDENT */
+ vidioc_int_g_chip_ident_num,
+
+ /*
+ *
+ * Start of private ioctls.
+ *
+ */
+ vidioc_int_priv_start_num = 2000,
+};
+
+/*
+ *
+ * IOCTL wrapper functions for better type checking.
+ *
+ */
+
+#define V4L2_INT_WRAPPER_0(name) \
+ static inline int vidioc_int_##name(struct v4l2_int_device *d) \
+ { \
+ return v4l2_int_ioctl_0(d, vidioc_int_##name##_num); \
+ } \
+ \
+ static inline struct v4l2_int_ioctl_desc \
+ vidioc_int_##name##_cb(int (*func) \
+ (struct v4l2_int_device *)) \
+ { \
+ struct v4l2_int_ioctl_desc desc; \
+ \
+ desc.num = vidioc_int_##name##_num; \
+ desc.func = (v4l2_int_ioctl_func *)func; \
+ \
+ return desc; \
+ }
+
+#define V4L2_INT_WRAPPER_1(name, arg_type, asterisk) \
+ static inline int vidioc_int_##name(struct v4l2_int_device *d, \
+ arg_type asterisk arg) \
+ { \
+ return v4l2_int_ioctl_1(d, vidioc_int_##name##_num, \
+ (void *)(unsigned long)arg); \
+ } \
+ \
+ static inline struct v4l2_int_ioctl_desc \
+ vidioc_int_##name##_cb(int (*func) \
+ (struct v4l2_int_device *, \
+ arg_type asterisk)) \
+ { \
+ struct v4l2_int_ioctl_desc desc; \
+ \
+ desc.num = vidioc_int_##name##_num; \
+ desc.func = (v4l2_int_ioctl_func *)func; \
+ \
+ return desc; \
+ }
+
+V4L2_INT_WRAPPER_1(enum_fmt_cap, struct v4l2_fmtdesc, *);
+V4L2_INT_WRAPPER_1(g_fmt_cap, struct v4l2_format, *);
+V4L2_INT_WRAPPER_1(s_fmt_cap, struct v4l2_format, *);
+V4L2_INT_WRAPPER_1(try_fmt_cap, struct v4l2_format, *);
+V4L2_INT_WRAPPER_1(queryctrl, struct v4l2_queryctrl, *);
+V4L2_INT_WRAPPER_1(g_ctrl, struct v4l2_control, *);
+V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *);
+V4L2_INT_WRAPPER_1(cropcap, struct v4l2_cropcap, *);
+V4L2_INT_WRAPPER_1(g_crop, struct v4l2_crop, *);
+V4L2_INT_WRAPPER_1(s_crop, struct v4l2_crop, *);
+V4L2_INT_WRAPPER_1(g_parm, struct v4l2_streamparm, *);
+V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *);
+V4L2_INT_WRAPPER_1(querystd, v4l2_std_id, *);
+V4L2_INT_WRAPPER_1(s_std, v4l2_std_id, *);
+V4L2_INT_WRAPPER_1(s_video_routing, struct v4l2_routing, *);
+
+V4L2_INT_WRAPPER_0(dev_init);
+V4L2_INT_WRAPPER_0(dev_exit);
+V4L2_INT_WRAPPER_1(s_power, enum v4l2_power, /*dummy arg*/);
+V4L2_INT_WRAPPER_1(g_priv, void, *);
+V4L2_INT_WRAPPER_1(g_ifparm, struct v4l2_ifparm, *);
+V4L2_INT_WRAPPER_1(g_needs_reset, void, *);
+V4L2_INT_WRAPPER_1(enum_framesizes, struct v4l2_frmsizeenum, *);
+V4L2_INT_WRAPPER_1(enum_frameintervals, struct v4l2_frmivalenum, *);
+
+V4L2_INT_WRAPPER_0(reset);
+V4L2_INT_WRAPPER_0(init);
+V4L2_INT_WRAPPER_1(g_chip_ident, int, *);
+
+#endif
diff --git a/drivers/media/platform/mxc/output/Kconfig b/drivers/media/platform/mxc/output/Kconfig
new file mode 100644
index 000000000000..237f8a88b5cb
--- /dev/null
+++ b/drivers/media/platform/mxc/output/Kconfig
@@ -0,0 +1,16 @@
+config VIDEO_MXC_IPU_OUTPUT
+ tristate "IPU v4l2 output support"
+ depends on VIDEO_MXC_OUTPUT && MXC_IPU
+ ---help---
+ This is the video4linux2 driver for IPU post processing video output.
+
+config VIDEO_MXC_PXP_V4L2
+ tristate "MXC PxP V4L2 driver"
+ depends on VIDEO_DEV && VIDEO_V4L2
+ select VIDEOBUF_DMA_CONTIG
+ ---help---
+ This is a video4linux driver for the Freescale PxP
+ (Pixel Pipeline). This module supports output overlay of
+ the MXC framebuffer on a video stream.
+
+ To compile this driver as a module, choose M here.
diff --git a/drivers/media/platform/mxc/output/Makefile b/drivers/media/platform/mxc/output/Makefile
new file mode 100644
index 000000000000..88f1a9fb735d
--- /dev/null
+++ b/drivers/media/platform/mxc/output/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VIDEO_MXC_IPU_OUTPUT) += mxc_vout.o
+obj-$(CONFIG_VIDEO_MXC_PXP_V4L2) += mxc_pxp_v4l2.o
diff --git a/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c b/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c
new file mode 100644
index 000000000000..16da4d3e3347
--- /dev/null
+++ b/drivers/media/platform/mxc/output/mxc_pxp_v4l2.c
@@ -0,0 +1,1346 @@
+/*
+ * Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ *
+ */
+/*
+ * Based on STMP378X PxP driver
+ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+#include <linux/dmaengine.h>
+#include <linux/pxp_dma.h>
+#include <linux/delay.h>
+#include <linux/console.h>
+#include <linux/mxcfb.h>
+#include <linux/platform_data/dma-imx.h>
+
+#include <media/videobuf-dma-contig.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+
+#include "mxc_pxp_v4l2.h"
+
+#define PXP_DRIVER_NAME "pxp-v4l2"
+#define PXP_DRIVER_MAJOR 2
+#define PXP_DRIVER_MINOR 0
+
+#define PXP_DEF_BUFS 2
+#define PXP_MIN_PIX 8
+
+#define V4L2_OUTPUT_TYPE_INTERNAL 4
+
+static int video_nr = -1; /* -1 ==> auto assign */
+static struct pxp_data_format pxp_s0_formats[] = {
+ {
+ .name = "24-bit RGB",
+ .bpp = 4,
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ }, {
+ .name = "16-bit RGB 5:6:5",
+ .bpp = 2,
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ }, {
+ .name = "16-bit RGB 5:5:5",
+ .bpp = 2,
+ .fourcc = V4L2_PIX_FMT_RGB555,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ }, {
+ .name = "YUV 4:2:0 Planar",
+ .bpp = 2,
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ }, {
+ .name = "YUV 4:2:2 Planar",
+ .bpp = 2,
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ }, {
+ .name = "UYVY",
+ .bpp = 2,
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ }, {
+ .name = "YUYV",
+ .bpp = 2,
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ }, {
+ .name = "YUV32",
+ .bpp = 4,
+ .fourcc = V4L2_PIX_FMT_YUV32,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+};
+
+static unsigned int v4l2_fmt_to_pxp_fmt(u32 v4l2_pix_fmt)
+{
+ u32 pxp_fmt = 0;
+
+ if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB24)
+ pxp_fmt = PXP_PIX_FMT_XRGB32;
+ else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB565)
+ pxp_fmt = PXP_PIX_FMT_RGB565;
+ else if (v4l2_pix_fmt == V4L2_PIX_FMT_RGB555)
+ pxp_fmt = PXP_PIX_FMT_RGB555;
+ else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV420)
+ pxp_fmt = PXP_PIX_FMT_YUV420P;
+ else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV422P)
+ pxp_fmt = PXP_PIX_FMT_YUV422P;
+ else if (v4l2_pix_fmt == V4L2_PIX_FMT_UYVY)
+ pxp_fmt = PXP_PIX_FMT_UYVY;
+ else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUV32)
+ pxp_fmt = PXP_PIX_FMT_VUY444;
+ else if (v4l2_pix_fmt == V4L2_PIX_FMT_YUYV)
+ pxp_fmt = PXP_PIX_FMT_YUYV;
+
+ return pxp_fmt;
+}
+struct v4l2_queryctrl pxp_controls[] = {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Horizontal Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vertical Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_PRIVATE_BASE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Rotation",
+ .minimum = 0,
+ .maximum = 270,
+ .step = 90,
+ .default_value = 0,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_PRIVATE_BASE + 1,
+ .name = "Background Color",
+ .minimum = 0,
+ .maximum = 0xFFFFFF,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }, {
+ .id = V4L2_CID_PRIVATE_BASE + 2,
+ .name = "Set S0 Chromakey",
+ .minimum = -1,
+ .maximum = 0xFFFFFF,
+ .step = 1,
+ .default_value = -1,
+ .flags = 0,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }, {
+ .id = V4L2_CID_PRIVATE_BASE + 3,
+ .name = "YUV Colorspace",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },
+};
+
+static void free_dma_buf(struct pxps *pxp, struct dma_mem *buf)
+{
+ dma_free_coherent(&pxp->pdev->dev, buf->size, buf->vaddr, buf->paddr);
+ dev_dbg(&pxp->pdev->dev,
+ "free dma size:0x%x, paddr:0x%x\n",
+ buf->size, buf->paddr);
+ memset(buf, 0, sizeof(*buf));
+}
+
+static int alloc_dma_buf(struct pxps *pxp, struct dma_mem *buf)
+{
+
+ buf->vaddr = dma_alloc_coherent(&pxp->pdev->dev, buf->size, &buf->paddr,
+ GFP_DMA | GFP_KERNEL);
+ if (!buf->vaddr) {
+ dev_err(&pxp->pdev->dev,
+ "cannot get dma buf size:0x%x\n", buf->size);
+ return -ENOMEM;
+ }
+ dev_dbg(&pxp->pdev->dev,
+ "alloc dma buf size:0x%x, paddr:0x%x\n", buf->size, buf->paddr);
+ return 0;
+}
+
+/* callback function */
+static void video_dma_done(void *arg)
+{
+ struct pxp_tx_desc *tx_desc = to_tx_desc(arg);
+ struct dma_chan *chan = tx_desc->txd.chan;
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+ struct pxps *pxp = pxp_chan->client;
+ struct videobuf_buffer *vb;
+
+ dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n",
+ tx_desc->txd.cookie,
+ pxp->active ? sg_dma_address(&pxp->active->sg[0]) : 0);
+
+ spin_lock(&pxp->lock);
+ if (pxp->active) {
+ vb = &pxp->active->vb;
+
+ list_del_init(&vb->queue);
+ vb->state = VIDEOBUF_DONE;
+ do_gettimeofday(&vb->ts);
+ vb->field_count++;
+ wake_up(&vb->done);
+ }
+
+ if (list_empty(&pxp->outq)) {
+ pxp->active = NULL;
+ spin_unlock(&pxp->lock);
+
+ return;
+ }
+
+ pxp->active = list_entry(pxp->outq.next,
+ struct pxp_buffer, vb.queue);
+ pxp->active->vb.state = VIDEOBUF_ACTIVE;
+ spin_unlock(&pxp->lock);
+}
+
+static bool chan_filter(struct dma_chan *chan, void *arg)
+{
+ if (imx_dma_is_pxp(chan))
+ return true;
+ else
+ return false;
+}
+
+static int acquire_dma_channel(struct pxps *pxp)
+{
+ dma_cap_mask_t mask;
+ struct dma_chan *chan;
+ struct pxp_channel **pchan = &pxp->pxp_channel[0];
+
+ if (*pchan) {
+ struct videobuf_buffer *vb, *_vb;
+ dma_release_channel(&(*pchan)->dma_chan);
+ *pchan = NULL;
+ pxp->active = NULL;
+ list_for_each_entry_safe(vb, _vb, &pxp->outq, queue) {
+ list_del_init(&vb->queue);
+ vb->state = VIDEOBUF_ERROR;
+ wake_up(&vb->done);
+ }
+ }
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_PRIVATE, mask);
+ chan = dma_request_channel(mask, chan_filter, NULL);
+ if (!chan)
+ return -EBUSY;
+
+ *pchan = to_pxp_channel(chan);
+ (*pchan)->client = pxp;
+
+ return 0;
+}
+
+static int _get_fbinfo(struct fb_info **fbi)
+{
+ int i;
+ for (i = 0; i < num_registered_fb; i++) {
+ char *idstr = registered_fb[i]->fix.id;
+ if (strncmp(idstr, "mxs", 3) == 0) {
+ *fbi = registered_fb[i];
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+static int pxp_set_fbinfo(struct pxps *pxp)
+{
+ struct v4l2_framebuffer *fb = &pxp->fb;
+ int err;
+
+ err = _get_fbinfo(&pxp->fbi);
+ if (err)
+ return err;
+
+ fb->fmt.width = pxp->fbi->var.xres;
+ fb->fmt.height = pxp->fbi->var.yres;
+ pxp->pxp_conf.out_param.stride = pxp->fbi->var.xres;
+ if (pxp->fbi->var.bits_per_pixel == 16)
+ fb->fmt.pixelformat = V4L2_PIX_FMT_RGB565;
+ else
+ fb->fmt.pixelformat = V4L2_PIX_FMT_RGB24;
+
+ fb->base = (void *)pxp->fbi->fix.smem_start;
+
+ return 0;
+}
+
+static int _get_cur_fb_blank(struct pxps *pxp)
+{
+ struct fb_info *fbi;
+ mm_segment_t old_fs;
+ int err = 0;
+
+ err = _get_fbinfo(&fbi);
+ if (err)
+ return err;
+
+ if (fbi->fbops->fb_ioctl) {
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ err = fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_BLANK,
+ (unsigned int)(&pxp->fb_blank));
+ set_fs(old_fs);
+ }
+
+ return err;
+}
+
+static int pxp_show_buf(struct pxps *pxp, unsigned long paddr)
+{
+ struct fb_info *fbi = pxp->fbi;
+ int ret = -EINVAL;
+
+ if (paddr == 0) {
+ dev_err(&pxp->pdev->dev, "Invalid paddr\n");
+ return ret;
+ }
+
+ console_lock();
+ fbi->fix.smem_start = paddr;
+ ret = fb_pan_display(fbi, &fbi->var);
+ console_unlock();
+
+ return ret;
+}
+
+static int set_fb_blank(int blank)
+{
+ struct fb_info *fbi;
+ int err = 0;
+
+ err = _get_fbinfo(&fbi);
+ if (err)
+ return err;
+
+ console_lock();
+ fb_blank(fbi, blank);
+ console_unlock();
+
+ return err;
+}
+
+static int pxp_set_cstate(struct pxps *pxp, struct v4l2_control *vc)
+{
+
+ if (vc->id == V4L2_CID_HFLIP) {
+ pxp->pxp_conf.proc_data.hflip = vc->value;
+ } else if (vc->id == V4L2_CID_VFLIP) {
+ pxp->pxp_conf.proc_data.vflip = vc->value;
+ } else if (vc->id == V4L2_CID_PRIVATE_BASE) {
+ if (vc->value % 90)
+ return -ERANGE;
+ pxp->pxp_conf.proc_data.rotate = vc->value;
+ } else if (vc->id == V4L2_CID_PRIVATE_BASE + 1) {
+ pxp->pxp_conf.proc_data.bgcolor = vc->value;
+ } else if (vc->id == V4L2_CID_PRIVATE_BASE + 2) {
+ pxp->pxp_conf.s0_param.color_key = vc->value;
+ } else if (vc->id == V4L2_CID_PRIVATE_BASE + 3) {
+ pxp->pxp_conf.proc_data.yuv = vc->value;
+ }
+
+ return 0;
+}
+
+static int pxp_get_cstate(struct pxps *pxp, struct v4l2_control *vc)
+{
+ if (vc->id == V4L2_CID_HFLIP)
+ vc->value = pxp->pxp_conf.proc_data.hflip;
+ else if (vc->id == V4L2_CID_VFLIP)
+ vc->value = pxp->pxp_conf.proc_data.vflip;
+ else if (vc->id == V4L2_CID_PRIVATE_BASE)
+ vc->value = pxp->pxp_conf.proc_data.rotate;
+ else if (vc->id == V4L2_CID_PRIVATE_BASE + 1)
+ vc->value = pxp->pxp_conf.proc_data.bgcolor;
+ else if (vc->id == V4L2_CID_PRIVATE_BASE + 2)
+ vc->value = pxp->pxp_conf.s0_param.color_key;
+ else if (vc->id == V4L2_CID_PRIVATE_BASE + 3)
+ vc->value = pxp->pxp_conf.proc_data.yuv;
+
+ return 0;
+}
+
+static int pxp_enumoutput(struct file *file, void *fh,
+ struct v4l2_output *o)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+ if (o->index > 1)
+ return -EINVAL;
+
+ memset(o, 0, sizeof(struct v4l2_output));
+ if (o->index == 0) {
+ strcpy(o->name, "PxP Display Output");
+ pxp->output = 0;
+ } else {
+ strcpy(o->name, "PxP Virtual Output");
+ pxp->output = 1;
+ }
+ o->type = V4L2_OUTPUT_TYPE_INTERNAL;
+ o->std = 0;
+ o->reserved[0] = pxp->outbuf.paddr;
+
+ return 0;
+}
+
+static int pxp_g_output(struct file *file, void *fh,
+ unsigned int *i)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+ *i = pxp->output;
+
+ return 0;
+}
+
+static int pxp_s_output(struct file *file, void *fh,
+ unsigned int i)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+ struct v4l2_pix_format *fmt = (struct v4l2_pix_format*)(&pxp->fb.fmt);
+ u32 size;
+ int ret, bpp;
+
+ if (i > 1)
+ return -EINVAL;
+
+ /* Output buffer is same format as fbdev */
+ if (fmt->pixelformat == V4L2_PIX_FMT_RGB24 ||
+ fmt->pixelformat == V4L2_PIX_FMT_YUV32)
+ bpp = 4;
+ else
+ bpp = 2;
+
+ size = fmt->width * fmt->height * bpp;
+ if (size > pxp->outbuf.size) {
+ if (pxp->outbuf.vaddr)
+ free_dma_buf(pxp, &pxp->outbuf);
+ pxp->outbuf.size = size;
+ ret = alloc_dma_buf(pxp, &pxp->outbuf);
+ if (ret < 0)
+ return ret;
+ }
+ memset(pxp->outbuf.vaddr, 0x0, pxp->outbuf.size);
+
+ pxp->pxp_conf.out_param.width = fmt->width;
+ pxp->pxp_conf.out_param.height = fmt->height;
+ if (fmt->pixelformat == V4L2_PIX_FMT_RGB24)
+ pxp->pxp_conf.out_param.pixel_fmt = PXP_PIX_FMT_XRGB32;
+ else
+ pxp->pxp_conf.out_param.pixel_fmt = PXP_PIX_FMT_RGB565;
+
+ return 0;
+}
+
+static int pxp_enum_fmt_video_output(struct file *file, void *fh,
+ struct v4l2_fmtdesc *fmt)
+{
+ enum v4l2_buf_type type = fmt->type;
+ unsigned int index = fmt->index;
+
+ if (fmt->index >= ARRAY_SIZE(pxp_s0_formats))
+ return -EINVAL;
+
+ memset(fmt, 0, sizeof(struct v4l2_fmtdesc));
+ fmt->index = index;
+ fmt->type = type;
+ fmt->pixelformat = pxp_s0_formats[index].fourcc;
+ strcpy(fmt->description, pxp_s0_formats[index].name);
+
+ return 0;
+}
+
+static int pxp_g_fmt_video_output(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format *pf = &f->fmt.pix;
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+ struct pxp_data_format *fmt = pxp->s0_fmt;
+
+ pf->width = pxp->pxp_conf.s0_param.width;
+ pf->height = pxp->pxp_conf.s0_param.height;
+ pf->pixelformat = fmt->fourcc;
+ pf->field = V4L2_FIELD_NONE;
+ pf->bytesperline = fmt->bpp * pf->width;
+ pf->sizeimage = pf->bytesperline * pf->height;
+ pf->colorspace = fmt->colorspace;
+ pf->priv = 0;
+
+ return 0;
+}
+
+static struct pxp_data_format *pxp_get_format(struct v4l2_format *f)
+{
+ struct pxp_data_format *fmt;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pxp_s0_formats); i++) {
+ fmt = &pxp_s0_formats[i];
+ if (fmt->fourcc == f->fmt.pix.pixelformat)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(pxp_s0_formats))
+ return NULL;
+
+ return &pxp_s0_formats[i];
+}
+
+static int pxp_try_fmt_video_output(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ int w = f->fmt.pix.width;
+ int h = f->fmt.pix.height;
+ struct pxp_data_format *fmt = pxp_get_format(f);
+
+ if (!fmt)
+ return -EINVAL;
+
+ w = min(w, 2040);
+ w = max(w, 8);
+ h = min(h, 2040);
+ h = max(h, 8);
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix.width = w;
+ f->fmt.pix.height = h;
+ f->fmt.pix.pixelformat = fmt->fourcc;
+
+ return 0;
+}
+
+static int pxp_s_fmt_video_output(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+ struct v4l2_pix_format *pf = &f->fmt.pix;
+ int ret;
+
+ ret = acquire_dma_channel(pxp);
+ if (ret < 0)
+ return ret;
+
+ ret = pxp_try_fmt_video_output(file, fh, f);
+ if (ret == 0) {
+ pxp->s0_fmt = pxp_get_format(f);
+ pxp->pxp_conf.s0_param.pixel_fmt =
+ v4l2_fmt_to_pxp_fmt(pxp->s0_fmt->fourcc);
+ pxp->pxp_conf.s0_param.width = pf->width;
+ pxp->pxp_conf.s0_param.height = pf->height;
+ }
+
+
+ return ret;
+}
+
+static int pxp_g_fmt_output_overlay(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+ struct v4l2_window *wf = &f->fmt.win;
+
+ memset(wf, 0, sizeof(struct v4l2_window));
+ wf->chromakey = pxp->s1_chromakey;
+ wf->global_alpha = pxp->global_alpha;
+ wf->field = V4L2_FIELD_NONE;
+ wf->clips = NULL;
+ wf->clipcount = 0;
+ wf->bitmap = NULL;
+ wf->w.left = pxp->pxp_conf.proc_data.srect.left;
+ wf->w.top = pxp->pxp_conf.proc_data.srect.top;
+ wf->w.width = pxp->pxp_conf.proc_data.srect.width;
+ wf->w.height = pxp->pxp_conf.proc_data.srect.height;
+
+ return 0;
+}
+
+static int pxp_try_fmt_output_overlay(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+ struct v4l2_window *wf = &f->fmt.win;
+ struct v4l2_rect srect;
+ u32 s1_chromakey = wf->chromakey;
+ u8 global_alpha = wf->global_alpha;
+
+ memcpy(&srect, &(wf->w), sizeof(struct v4l2_rect));
+
+ pxp_g_fmt_output_overlay(file, fh, f);
+
+ wf->chromakey = s1_chromakey;
+ wf->global_alpha = global_alpha;
+
+ /* Constrain parameters to the input buffer */
+ wf->w.left = srect.left;
+ wf->w.top = srect.top;
+ wf->w.width = min(srect.width,
+ ((__u32)pxp->pxp_conf.s0_param.width - wf->w.left));
+ wf->w.height = min(srect.height,
+ ((__u32)pxp->pxp_conf.s0_param.height - wf->w.top));
+
+ return 0;
+}
+
+static int pxp_s_fmt_output_overlay(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+ struct v4l2_window *wf = &f->fmt.win;
+ int ret = pxp_try_fmt_output_overlay(file, fh, f);
+
+ if (ret == 0) {
+ pxp->global_alpha = wf->global_alpha;
+ pxp->s1_chromakey = wf->chromakey;
+ pxp->pxp_conf.proc_data.srect.left = wf->w.left;
+ pxp->pxp_conf.proc_data.srect.top = wf->w.top;
+ pxp->pxp_conf.proc_data.srect.width = wf->w.width;
+ pxp->pxp_conf.proc_data.srect.height = wf->w.height;
+ pxp->pxp_conf.ol_param[0].global_alpha = pxp->global_alpha;
+ pxp->pxp_conf.ol_param[0].color_key = pxp->s1_chromakey;
+ pxp->pxp_conf.ol_param[0].color_key_enable =
+ pxp->s1_chromakey_state;
+ }
+
+ return ret;
+}
+
+static int pxp_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *r)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+ return videobuf_reqbufs(&pxp->s0_vbq, r);
+}
+
+static int pxp_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ int ret;
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+ ret = videobuf_querybuf(&pxp->s0_vbq, b);
+ if (!ret) {
+ struct videobuf_buffer *vb = pxp->s0_vbq.bufs[b->index];
+ if (b->flags & V4L2_BUF_FLAG_MAPPED)
+ b->m.offset = videobuf_to_dma_contig(vb);
+ }
+
+ return ret;
+}
+
+static int pxp_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+ return videobuf_qbuf(&pxp->s0_vbq, b);
+}
+
+static int pxp_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+ return videobuf_dqbuf(&pxp->s0_vbq, b, file->f_flags & O_NONBLOCK);
+}
+
+static int pxp_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type t)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+ int ret = 0;
+
+ if (t != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ _get_cur_fb_blank(pxp);
+ set_fb_blank(FB_BLANK_UNBLANK);
+
+ ret = videobuf_streamon(&pxp->s0_vbq);
+
+ if (!ret && (pxp->output == 0))
+ pxp_show_buf(pxp, pxp->outbuf.paddr);
+
+ return ret;
+}
+
+static int pxp_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type t)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+ int ret = 0;
+
+ if ((t != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+ return -EINVAL;
+
+ ret = videobuf_streamoff(&pxp->s0_vbq);
+
+ pxp_show_buf(pxp, (unsigned long)pxp->fb.base);
+
+ if (pxp->fb_blank)
+ set_fb_blank(FB_BLANK_POWERDOWN);
+
+ return ret;
+}
+
+static int pxp_buf_setup(struct videobuf_queue *q,
+ unsigned int *count, unsigned *size)
+{
+ struct pxps *pxp = q->priv_data;
+
+ *size = pxp->pxp_conf.s0_param.width *
+ pxp->pxp_conf.s0_param.height * pxp->s0_fmt->bpp;
+
+ if (0 == *count)
+ *count = PXP_DEF_BUFS;
+
+ return 0;
+}
+
+static void pxp_buf_free(struct videobuf_queue *q, struct pxp_buffer *buf)
+{
+ struct videobuf_buffer *vb = &buf->vb;
+
+ BUG_ON(in_interrupt());
+
+ pr_debug("%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ vb, vb->baddr, vb->bsize);
+
+ /*
+ * This waits until this buffer is out of danger, i.e., until it is no
+ * longer in STATE_QUEUED or STATE_ACTIVE
+ */
+ videobuf_waiton(q, vb, 0, 0);
+
+ videobuf_dma_contig_free(q, vb);
+ buf->txd = NULL;
+
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int pxp_buf_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct pxps *pxp = q->priv_data;
+ struct pxp_config_data *pxp_conf = &pxp->pxp_conf;
+ struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+ struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb);
+ struct pxp_tx_desc *desc;
+ int ret = 0;
+ int i, length;
+
+ if (!pxp->outbuf.paddr) {
+ dev_err(&pxp->pdev->dev, "Not allocate memory for "
+ "PxP Out buffer?\n");
+ return -ENOMEM;
+ }
+
+ vb->width = pxp->pxp_conf.s0_param.width;
+ vb->height = pxp->pxp_conf.s0_param.height;
+ vb->size = vb->width * vb->height * pxp->s0_fmt->bpp;
+ vb->field = V4L2_FIELD_NONE;
+ if (vb->state != VIDEOBUF_NEEDS_INIT)
+ pxp_buf_free(q, buf);
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ struct pxp_channel *pchan = pxp->pxp_channel[0];
+ struct scatterlist *sg = &buf->sg[0];
+
+ /* This actually (allocates and) maps buffers */
+ ret = videobuf_iolock(q, vb, NULL);
+ if (ret) {
+ pr_err("fail to call videobuf_iolock, ret = %d\n", ret);
+ goto fail;
+ }
+
+ /*
+ * sg[0] for input(S0)
+ * Sg[1] for output
+ */
+ sg_init_table(sg, 3);
+
+ buf->txd = pchan->dma_chan.device->device_prep_slave_sg(
+ &pchan->dma_chan, sg, 3, DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT, NULL);
+ if (!buf->txd) {
+ ret = -EIO;
+ goto fail;
+ }
+
+ buf->txd->callback_param = buf->txd;
+ buf->txd->callback = video_dma_done;
+
+ desc = to_tx_desc(buf->txd);
+ length = desc->len;
+ for (i = 0; i < length; i++) {
+ if (i == 0) {/* S0 */
+ memcpy(&desc->proc_data, proc_data,
+ sizeof(struct pxp_proc_data));
+ pxp_conf->s0_param.paddr =
+ videobuf_to_dma_contig(vb);
+ memcpy(&desc->layer_param.s0_param,
+ &pxp_conf->s0_param,
+ sizeof(struct pxp_layer_param));
+ } else if (i == 1) { /* Output */
+ /* we should always pass the output
+ * width and height which is the value
+ * after been rotated.
+ */
+ pxp_conf->out_param.width =
+ pxp->fb.fmt.width;
+ pxp_conf->out_param.height =
+ pxp->fb.fmt.height;
+
+ pxp_conf->out_param.paddr = pxp->outbuf.paddr;
+ memcpy(&desc->layer_param.out_param,
+ &pxp_conf->out_param,
+ sizeof(struct pxp_layer_param));
+ } else if (pxp_conf->ol_param[0].combine_enable) {
+ /* Overlay */
+ pxp_conf->ol_param[0].paddr =
+ (dma_addr_t)pxp->fb.base;
+ pxp_conf->ol_param[0].width = pxp->fb.fmt.width;
+ pxp_conf->ol_param[0].height =
+ pxp->fb.fmt.height;
+ pxp_conf->ol_param[0].pixel_fmt =
+ pxp_conf->out_param.pixel_fmt;
+ memcpy(&desc->layer_param.ol_param,
+ &pxp_conf->ol_param[0],
+ sizeof(struct pxp_layer_param));
+ }
+
+ desc = desc->next;
+ }
+
+ vb->state = VIDEOBUF_PREPARED;
+ }
+
+ return 0;
+
+fail:
+ pxp_buf_free(q, buf);
+ return ret;
+}
+
+
+static void pxp_buf_queue(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct pxps *pxp = q->priv_data;
+ struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb);
+ struct dma_async_tx_descriptor *txd = buf->txd;
+ struct pxp_channel *pchan = pxp->pxp_channel[0];
+ dma_cookie_t cookie;
+
+ BUG_ON(!irqs_disabled());
+
+ list_add_tail(&vb->queue, &pxp->outq);
+
+ if (!pxp->active) {
+ pxp->active = buf;
+ vb->state = VIDEOBUF_ACTIVE;
+ } else {
+ vb->state = VIDEOBUF_QUEUED;
+ }
+
+ spin_unlock_irq(&pxp->lock);
+
+ cookie = txd->tx_submit(txd);
+ dev_dbg(&pxp->pdev->dev, "Submitted cookie %d DMA 0x%08x\n",
+ cookie, sg_dma_address(&buf->sg[0]));
+ mdelay(5);
+ /* trigger ePxP */
+ dma_async_issue_pending(&pchan->dma_chan);
+
+ spin_lock_irq(&pxp->lock);
+
+ if (cookie >= 0)
+ return;
+
+ /* Submit error */
+ pr_err("%s: Submit error\n", __func__);
+ vb->state = VIDEOBUF_PREPARED;
+
+ list_del_init(&vb->queue);
+
+ if (pxp->active == buf)
+ pxp->active = NULL;
+}
+
+static void pxp_buf_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct pxps *pxp = q->priv_data;
+ struct pxp_buffer *buf = container_of(vb, struct pxp_buffer, vb);
+ unsigned long flags;
+
+ spin_lock_irqsave(&pxp->lock, flags);
+ if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
+ !list_empty(&vb->queue)) {
+ vb->state = VIDEOBUF_ERROR;
+
+ list_del_init(&vb->queue);
+ if (pxp->active == buf)
+ pxp->active = NULL;
+ }
+ spin_unlock_irqrestore(&pxp->lock, flags);
+
+ pxp_buf_free(q, buf);
+}
+
+static struct videobuf_queue_ops pxp_vbq_ops = {
+ .buf_setup = pxp_buf_setup,
+ .buf_prepare = pxp_buf_prepare,
+ .buf_queue = pxp_buf_queue,
+ .buf_release = pxp_buf_release,
+};
+
+static int pxp_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+ memset(cap, 0, sizeof(*cap));
+ strcpy(cap->driver, "pxp");
+ strcpy(cap->card, "pxp");
+ strlcpy(cap->bus_info, dev_name(&pxp->pdev->dev),
+ sizeof(cap->bus_info));
+
+ cap->version = (PXP_DRIVER_MAJOR << 8) + PXP_DRIVER_MINOR;
+
+ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT |
+ V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+ return 0;
+}
+
+static int pxp_g_fbuf(struct file *file, void *priv,
+ struct v4l2_framebuffer *fb)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+ memset(fb, 0, sizeof(*fb));
+
+ fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
+ V4L2_FBUF_CAP_CHROMAKEY |
+ V4L2_FBUF_CAP_LOCAL_ALPHA |
+ V4L2_FBUF_CAP_GLOBAL_ALPHA;
+
+ if (pxp->global_alpha_state)
+ fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
+ if (pxp->s1_chromakey_state)
+ fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+
+ return 0;
+}
+
+static int pxp_s_fbuf(struct file *file, void *priv,
+ const struct v4l2_framebuffer *fb)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+ pxp->overlay_state =
+ (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0;
+ pxp->global_alpha_state =
+ (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
+ pxp->s1_chromakey_state =
+ (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
+
+ pxp->pxp_conf.ol_param[0].combine_enable = pxp->overlay_state;
+ pxp->pxp_conf.ol_param[0].global_alpha_enable = pxp->global_alpha_state;
+
+ return 0;
+}
+
+static int pxp_g_crop(struct file *file, void *fh,
+ struct v4l2_crop *c)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+ if (c->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY)
+ return -EINVAL;
+
+ c->c.left = pxp->pxp_conf.proc_data.drect.left;
+ c->c.top = pxp->pxp_conf.proc_data.drect.top;
+ c->c.width = pxp->pxp_conf.proc_data.drect.width;
+ c->c.height = pxp->pxp_conf.proc_data.drect.height;
+
+ return 0;
+}
+
+static int pxp_s_crop(struct file *file, void *fh,
+ const struct v4l2_crop *c)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+ int l = c->c.left;
+ int t = c->c.top;
+ int w = c->c.width;
+ int h = c->c.height;
+ int fbw = pxp->fb.fmt.width;
+ int fbh = pxp->fb.fmt.height;
+
+ if (c->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY)
+ return -EINVAL;
+
+ /* Constrain parameters to FB limits */
+ w = min(w, fbw);
+ w = max(w, PXP_MIN_PIX);
+ h = min(h, fbh);
+ h = max(h, PXP_MIN_PIX);
+
+ /* Round up values to PxP pixel block */
+ l = roundup(l, PXP_MIN_PIX);
+ t = roundup(t, PXP_MIN_PIX);
+ w = roundup(w, PXP_MIN_PIX);
+ h = roundup(h, PXP_MIN_PIX);
+
+ if ((l + w) > fbw)
+ l = 0;
+ if ((t + h) > fbh)
+ t = 0;
+
+ pxp->pxp_conf.proc_data.drect.left = l;
+ pxp->pxp_conf.proc_data.drect.top = t;
+ pxp->pxp_conf.proc_data.drect.width = w;
+ pxp->pxp_conf.proc_data.drect.height = h;
+
+ memset(pxp->outbuf.vaddr, 0x0, pxp->outbuf.size);
+
+ return 0;
+}
+
+static int pxp_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
+ if (qc->id && qc->id == pxp_controls[i].id) {
+ memcpy(qc, &(pxp_controls[i]), sizeof(*qc));
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int pxp_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *vc)
+{
+ int i;
+
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
+ if (vc->id == pxp_controls[i].id)
+ return pxp_get_cstate(pxp, vc);
+
+ return -EINVAL;
+}
+
+static int pxp_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *vc)
+{
+ int i;
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+ for (i = 0; i < ARRAY_SIZE(pxp_controls); i++)
+ if (vc->id == pxp_controls[i].id) {
+ if (vc->value < pxp_controls[i].minimum ||
+ vc->value > pxp_controls[i].maximum)
+ return -ERANGE;
+ return pxp_set_cstate(pxp, vc);
+ }
+
+ memset(pxp->outbuf.vaddr, 0x0, pxp->outbuf.size);
+
+ return -EINVAL;
+}
+
+void pxp_release(struct video_device *vfd)
+{
+ struct pxps *pxp = video_get_drvdata(vfd);
+
+ spin_lock(&pxp->lock);
+ video_device_release(vfd);
+ spin_unlock(&pxp->lock);
+}
+
+static int pxp_open(struct file *file)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+ int ret = 0;
+
+ mutex_lock(&pxp->mutex);
+ pxp->users++;
+
+ if (pxp->users > 1) {
+ pxp->users--;
+ ret = -EBUSY;
+ goto out;
+ }
+out:
+ mutex_unlock(&pxp->mutex);
+ if (ret)
+ return ret;
+
+ ret = pxp_set_fbinfo(pxp);
+ if (ret) {
+ dev_err(&pxp->pdev->dev, "failed to call pxp_set_fbinfo\n");
+ return ret;
+ }
+
+ videobuf_queue_dma_contig_init(&pxp->s0_vbq,
+ &pxp_vbq_ops,
+ &pxp->pdev->dev,
+ &pxp->lock,
+ V4L2_BUF_TYPE_VIDEO_OUTPUT,
+ V4L2_FIELD_NONE,
+ sizeof(struct pxp_buffer),
+ pxp,
+ NULL);
+ dev_dbg(&pxp->pdev->dev, "call pxp_open\n");
+
+ return 0;
+}
+
+static int pxp_close(struct file *file)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+
+ pxp_streamoff(file, NULL, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ videobuf_stop(&pxp->s0_vbq);
+ videobuf_mmap_free(&pxp->s0_vbq);
+ pxp->active = NULL;
+
+ mutex_lock(&pxp->mutex);
+ pxp->users--;
+ mutex_unlock(&pxp->mutex);
+
+ return 0;
+}
+
+static int pxp_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct pxps *pxp = video_get_drvdata(video_devdata(file));
+ int ret;
+
+ ret = videobuf_mmap_mapper(&pxp->s0_vbq, vma);
+
+ return ret;
+}
+
+static const struct v4l2_file_operations pxp_fops = {
+ .owner = THIS_MODULE,
+ .open = pxp_open,
+ .release = pxp_close,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = pxp_mmap,
+};
+
+static const struct v4l2_ioctl_ops pxp_ioctl_ops = {
+ .vidioc_querycap = pxp_querycap,
+
+ .vidioc_reqbufs = pxp_reqbufs,
+ .vidioc_querybuf = pxp_querybuf,
+ .vidioc_qbuf = pxp_qbuf,
+ .vidioc_dqbuf = pxp_dqbuf,
+
+ .vidioc_streamon = pxp_streamon,
+ .vidioc_streamoff = pxp_streamoff,
+
+ .vidioc_enum_output = pxp_enumoutput,
+ .vidioc_g_output = pxp_g_output,
+ .vidioc_s_output = pxp_s_output,
+
+ .vidioc_enum_fmt_vid_out = pxp_enum_fmt_video_output,
+ .vidioc_try_fmt_vid_out = pxp_try_fmt_video_output,
+ .vidioc_g_fmt_vid_out = pxp_g_fmt_video_output,
+ .vidioc_s_fmt_vid_out = pxp_s_fmt_video_output,
+
+ .vidioc_try_fmt_vid_out_overlay = pxp_try_fmt_output_overlay,
+ .vidioc_g_fmt_vid_out_overlay = pxp_g_fmt_output_overlay,
+ .vidioc_s_fmt_vid_out_overlay = pxp_s_fmt_output_overlay,
+
+ .vidioc_g_fbuf = pxp_g_fbuf,
+ .vidioc_s_fbuf = pxp_s_fbuf,
+
+ .vidioc_g_crop = pxp_g_crop,
+ .vidioc_s_crop = pxp_s_crop,
+
+ .vidioc_queryctrl = pxp_queryctrl,
+ .vidioc_g_ctrl = pxp_g_ctrl,
+ .vidioc_s_ctrl = pxp_s_ctrl,
+};
+
+static const struct video_device pxp_template = {
+ .name = "PxP",
+ .vfl_type = V4L2_CAP_VIDEO_OUTPUT |
+ V4L2_CAP_VIDEO_OVERLAY |
+ V4L2_CAP_STREAMING,
+ .vfl_dir = VFL_DIR_TX,
+ .fops = &pxp_fops,
+ .release = pxp_release,
+ .minor = -1,
+ .ioctl_ops = &pxp_ioctl_ops,
+};
+
+static const struct of_device_id imx_pxpv4l2_dt_ids[] = {
+ { .compatible = "fsl,imx6sl-pxp-v4l2", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_pxpv4l2_dt_ids);
+
+static int pxp_probe(struct platform_device *pdev)
+{
+ struct pxps *pxp;
+ struct v4l2_device *v4l2_dev;
+ int err = 0;
+
+ pxp = kzalloc(sizeof(*pxp), GFP_KERNEL);
+ if (!pxp) {
+ dev_err(&pdev->dev, "failed to allocate control object\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ dev_set_drvdata(&pdev->dev, pxp);
+
+ v4l2_dev = kzalloc(sizeof(*v4l2_dev), GFP_KERNEL);
+ if (!v4l2_dev) {
+ dev_err(&pdev->dev, "failed to allocate v4l2_dev structure\n");
+ err = -ENOMEM;
+ goto freeirq;
+ }
+
+ err = v4l2_device_register(&pdev->dev, v4l2_dev);
+ if (err) {
+ dev_err(&pdev->dev, "register v4l2 device failed\n");
+ goto freev4l2;
+ }
+
+ INIT_LIST_HEAD(&pxp->outq);
+ spin_lock_init(&pxp->lock);
+ mutex_init(&pxp->mutex);
+
+ pxp->pdev = pdev;
+
+ pxp->vdev = video_device_alloc();
+ if (!pxp->vdev) {
+ dev_err(&pdev->dev, "video_device_alloc() failed\n");
+ err = -ENOMEM;
+ goto relv4l2;
+ }
+
+ memcpy(pxp->vdev, &pxp_template, sizeof(pxp_template));
+ pxp->vdev->v4l2_dev = v4l2_dev;
+ video_set_drvdata(pxp->vdev, pxp);
+
+ err = video_register_device(pxp->vdev, VFL_TYPE_GRABBER, video_nr);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register video device\n");
+ goto freevdev;
+ }
+
+ dev_info(&pdev->dev, "initialized\n");
+
+exit:
+ return err;
+
+freevdev:
+ video_device_release(pxp->vdev);
+relv4l2:
+ v4l2_device_unregister(v4l2_dev);
+freev4l2:
+ kfree(v4l2_dev);
+freeirq:
+ kfree(pxp);
+
+ return err;
+}
+
+static int pxp_remove(struct platform_device *pdev)
+{
+ struct pxps *pxp = platform_get_drvdata(pdev);
+ struct v4l2_device *v4l2_dev = pxp->vdev->v4l2_dev;
+
+ video_unregister_device(pxp->vdev);
+ video_device_release(pxp->vdev);
+ v4l2_device_unregister(v4l2_dev);
+ kfree(v4l2_dev);
+
+ free_dma_buf(pxp, &pxp->outbuf);
+
+ kfree(pxp);
+
+ return 0;
+}
+
+static struct platform_driver pxp_driver = {
+ .driver = {
+ .name = PXP_DRIVER_NAME,
+ .of_match_table = of_match_ptr(imx_pxpv4l2_dt_ids),
+ },
+ .probe = pxp_probe,
+ .remove = pxp_remove,
+};
+
+module_platform_driver(pxp_driver);
+
+module_param(video_nr, int, 0444);
+MODULE_DESCRIPTION("MXC PxP V4L2 driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h b/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h
new file mode 100644
index 000000000000..8abb4c17f3fd
--- /dev/null
+++ b/drivers/media/platform/mxc/output/mxc_pxp_v4l2.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2010-2014 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ *
+ */
+/*
+ * Based on STMP378X PxP driver
+ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+#ifndef _MXC_PXP_V4L2_H
+#define _MXC_PXP_V4L2_H
+
+#include <linux/dmaengine.h>
+#include <linux/pxp_dma.h>
+
+struct pxp_buffer {
+ /* Must be first! */
+ struct videobuf_buffer vb;
+
+ /* One descriptor per scatterlist (per frame) */
+ struct dma_async_tx_descriptor *txd;
+
+ struct scatterlist sg[3];
+};
+
+struct dma_mem {
+ void *vaddr;
+ dma_addr_t paddr;
+ size_t size;
+};
+
+struct pxps {
+ struct platform_device *pdev;
+
+ spinlock_t lock;
+ struct mutex mutex;
+ int users;
+
+ struct video_device *vdev;
+
+ struct videobuf_queue s0_vbq;
+ struct pxp_buffer *active;
+ struct list_head outq;
+ struct pxp_channel *pxp_channel[1]; /* We need 1 channel */
+ struct pxp_config_data pxp_conf;
+ struct dma_mem outbuf;
+
+ int output;
+
+ /* Current S0 configuration */
+ struct pxp_data_format *s0_fmt;
+
+ struct fb_info *fbi;
+ struct v4l2_framebuffer fb;
+
+ /* Output overlay support */
+ int overlay_state;
+ int global_alpha_state;
+ u8 global_alpha;
+ int s1_chromakey_state;
+ u32 s1_chromakey;
+
+ int fb_blank;
+};
+
+struct pxp_data_format {
+ char *name;
+ unsigned int bpp;
+ u32 fourcc;
+ enum v4l2_colorspace colorspace;
+};
+
+#endif
diff --git a/drivers/media/platform/mxc/output/mxc_vout.c b/drivers/media/platform/mxc/output/mxc_vout.c
new file mode 100644
index 000000000000..f1ee36d65c89
--- /dev/null
+++ b/drivers/media/platform/mxc/output/mxc_vout.c
@@ -0,0 +1,2331 @@
+/*
+ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/console.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/ipu-v3.h>
+#include <linux/module.h>
+#include <linux/mxcfb.h>
+#include <linux/mxc_v4l2.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/vmalloc.h>
+
+#include <media/videobuf-dma-contig.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+
+#define UYVY_BLACK (0x00800080)
+#define RGB_BLACK (0x0)
+#define UV_BLACK (0x80)
+#define Y_BLACK (0x0)
+
+#define MAX_FB_NUM 6
+#define FB_BUFS 3
+#define VDOA_FB_BUFS (FB_BUFS - 1)
+#define VALID_HEIGHT_1080P (1080)
+#define FRAME_HEIGHT_1080P (1088)
+#define FRAME_WIDTH_1080P (1920)
+#define CHECK_TILED_1080P_DISPLAY(vout) \
+ ((((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12) || \
+ ((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12F)) &&\
+ ((vout)->task.input.width == FRAME_WIDTH_1080P) && \
+ ((vout)->task.input.height == FRAME_HEIGHT_1080P) && \
+ ((vout)->task.input.crop.w == FRAME_WIDTH_1080P) && \
+ (((vout)->task.input.crop.h == FRAME_HEIGHT_1080P) || \
+ ((vout)->task.input.crop.h == VALID_HEIGHT_1080P)) && \
+ ((vout)->task.output.width == FRAME_WIDTH_1080P) && \
+ ((vout)->task.output.height == VALID_HEIGHT_1080P) && \
+ ((vout)->task.output.crop.w == FRAME_WIDTH_1080P) && \
+ ((vout)->task.output.crop.h == VALID_HEIGHT_1080P))
+#define CHECK_TILED_1080P_STREAM(vout) \
+ ((((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12) || \
+ ((vout)->task.input.format == IPU_PIX_FMT_TILED_NV12F)) &&\
+ ((vout)->task.input.width == FRAME_WIDTH_1080P) && \
+ ((vout)->task.input.crop.w == FRAME_WIDTH_1080P) && \
+ ((vout)->task.input.height == FRAME_HEIGHT_1080P) && \
+ ((vout)->task.input.crop.h == FRAME_HEIGHT_1080P))
+#define IS_PLANAR_PIXEL_FORMAT(format) \
+ (format == IPU_PIX_FMT_NV12 || \
+ format == IPU_PIX_FMT_YUV420P2 || \
+ format == IPU_PIX_FMT_YUV420P || \
+ format == IPU_PIX_FMT_YVU420P || \
+ format == IPU_PIX_FMT_YUV422P || \
+ format == IPU_PIX_FMT_YVU422P || \
+ format == IPU_PIX_FMT_YUV444P)
+
+#define NSEC_PER_FRAME_30FPS (33333333)
+
+struct mxc_vout_fb {
+ char *name;
+ int ipu_id;
+ struct v4l2_rect crop_bounds;
+ unsigned int disp_fmt;
+ bool disp_support_csc;
+ bool disp_support_windows;
+};
+
+struct dma_mem {
+ void *vaddr;
+ dma_addr_t paddr;
+ size_t size;
+};
+
+struct mxc_vout_output {
+ int open_cnt;
+ struct fb_info *fbi;
+ unsigned long fb_smem_start;
+ unsigned long fb_smem_len;
+ struct video_device *vfd;
+ struct mutex mutex;
+ struct mutex task_lock;
+ struct mutex accs_lock;
+ enum v4l2_buf_type type;
+
+ struct videobuf_queue vbq;
+ spinlock_t vbq_lock;
+
+ struct list_head queue_list;
+ struct list_head active_list;
+
+ struct v4l2_rect crop_bounds;
+ unsigned int disp_fmt;
+ struct mxcfb_pos win_pos;
+ bool disp_support_windows;
+ bool disp_support_csc;
+
+ bool fmt_init;
+ bool release;
+ bool linear_bypass_pp;
+ bool vdoa_1080p;
+ bool tiled_bypass_pp;
+ struct v4l2_rect in_rect;
+ struct ipu_task task;
+ struct ipu_task vdoa_task;
+ struct dma_mem vdoa_work;
+ struct dma_mem vdoa_output[VDOA_FB_BUFS];
+
+ bool timer_stop;
+ struct hrtimer timer;
+ struct workqueue_struct *v4l_wq;
+ struct work_struct disp_work;
+ unsigned long frame_count;
+ unsigned long vdi_frame_cnt;
+ ktime_t start_ktime;
+
+ int ctrl_rotate;
+ int ctrl_vflip;
+ int ctrl_hflip;
+
+ dma_addr_t disp_bufs[FB_BUFS];
+
+ struct videobuf_buffer *pre1_vb;
+ struct videobuf_buffer *pre2_vb;
+
+ bool input_crop;
+};
+
+struct mxc_vout_dev {
+ struct device *dev;
+ struct v4l2_device v4l2_dev;
+ struct mxc_vout_output *out[MAX_FB_NUM];
+ int out_num;
+};
+
+/* Driver Configuration macros */
+#define VOUT_NAME "mxc_vout"
+
+/* Variables configurable through module params*/
+static int debug;
+static int vdi_rate_double;
+static int video_nr = 16;
+
+static int mxc_vidioc_s_input_crop(struct mxc_vout_output *vout,
+ const struct v4l2_crop *crop);
+static int mxc_vidioc_g_input_crop(struct mxc_vout_output *vout,
+ struct v4l2_crop *crop);
+/* Module parameters */
+module_param(video_nr, int, S_IRUGO);
+MODULE_PARM_DESC(video_nr, "video device numbers");
+module_param(debug, int, 0600);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+module_param(vdi_rate_double, int, 0600);
+MODULE_PARM_DESC(vdi_rate_double, "vdi frame rate double on/off");
+
+static const struct v4l2_fmtdesc mxc_formats[] = {
+ {
+ .description = "RGB565",
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ },
+ {
+ .description = "BGR24",
+ .pixelformat = V4L2_PIX_FMT_BGR24,
+ },
+ {
+ .description = "RGB24",
+ .pixelformat = V4L2_PIX_FMT_RGB24,
+ },
+ {
+ .description = "RGB32",
+ .pixelformat = V4L2_PIX_FMT_RGB32,
+ },
+ {
+ .description = "BGR32",
+ .pixelformat = V4L2_PIX_FMT_BGR32,
+ },
+ {
+ .description = "NV12",
+ .pixelformat = V4L2_PIX_FMT_NV12,
+ },
+ {
+ .description = "UYVY",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ },
+ {
+ .description = "YUYV",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ },
+ {
+ .description = "YUV422 planar",
+ .pixelformat = V4L2_PIX_FMT_YUV422P,
+ },
+ {
+ .description = "YUV444",
+ .pixelformat = V4L2_PIX_FMT_YUV444,
+ },
+ {
+ .description = "YUV420",
+ .pixelformat = V4L2_PIX_FMT_YUV420,
+ },
+ {
+ .description = "YVU420",
+ .pixelformat = V4L2_PIX_FMT_YVU420,
+ },
+ {
+ .description = "TILED NV12P",
+ .pixelformat = IPU_PIX_FMT_TILED_NV12,
+ },
+ {
+ .description = "TILED NV12F",
+ .pixelformat = IPU_PIX_FMT_TILED_NV12F,
+ },
+ {
+ .description = "YUV444 planar",
+ .pixelformat = IPU_PIX_FMT_YUV444P,
+ },
+};
+
+#define NUM_MXC_VOUT_FORMATS (ARRAY_SIZE(mxc_formats))
+
+#define DEF_INPUT_WIDTH 320
+#define DEF_INPUT_HEIGHT 240
+
+static int mxc_vidioc_streamoff(struct file *file, void *fh,
+ enum v4l2_buf_type i);
+
+static struct mxc_vout_fb g_fb_setting[MAX_FB_NUM];
+static int config_disp_output(struct mxc_vout_output *vout);
+static void release_disp_output(struct mxc_vout_output *vout);
+
+static DEFINE_MUTEX(gfb_mutex);
+static DEFINE_MUTEX(gfbi_mutex);
+
+static unsigned int get_frame_size(struct mxc_vout_output *vout)
+{
+ unsigned int size;
+
+ if (IPU_PIX_FMT_TILED_NV12 == vout->task.input.format)
+ size = TILED_NV12_FRAME_SIZE(vout->task.input.width,
+ vout->task.input.height);
+ else if (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format) {
+ size = TILED_NV12_FRAME_SIZE(vout->task.input.width,
+ vout->task.input.height/2);
+ size *= 2;
+ } else
+ size = vout->task.input.width * vout->task.input.height *
+ fmt_to_bpp(vout->task.input.format)/8;
+
+ return size;
+}
+
+static void free_dma_buf(struct mxc_vout_output *vout, struct dma_mem *buf)
+{
+ dma_free_coherent(vout->vbq.dev, buf->size, buf->vaddr, buf->paddr);
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "free dma size:0x%x, paddr:0x%x\n",
+ buf->size, buf->paddr);
+ memset(buf, 0, sizeof(*buf));
+}
+
+static int alloc_dma_buf(struct mxc_vout_output *vout, struct dma_mem *buf)
+{
+
+ buf->vaddr = dma_alloc_coherent(vout->vbq.dev, buf->size, &buf->paddr,
+ GFP_DMA | GFP_KERNEL);
+ if (!buf->vaddr) {
+ v4l2_err(vout->vfd->v4l2_dev,
+ "cannot get dma buf size:0x%x\n", buf->size);
+ return -ENOMEM;
+ }
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "alloc dma buf size:0x%x, paddr:0x%x\n", buf->size, buf->paddr);
+ return 0;
+}
+
+static ipu_channel_t get_ipu_channel(struct fb_info *fbi)
+{
+ ipu_channel_t ipu_ch = CHAN_NONE;
+ mm_segment_t old_fs;
+
+ if (fbi->fbops->fb_ioctl) {
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_IPU_CHAN,
+ (unsigned long)&ipu_ch);
+ set_fs(old_fs);
+ }
+
+ return ipu_ch;
+}
+
+static unsigned int get_ipu_fmt(struct fb_info *fbi)
+{
+ mm_segment_t old_fs;
+ unsigned int fb_fmt = 0;
+
+ if (fbi->fbops->fb_ioctl) {
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ fbi->fbops->fb_ioctl(fbi, MXCFB_GET_DIFMT,
+ (unsigned long)&fb_fmt);
+ set_fs(old_fs);
+ }
+
+ return fb_fmt;
+}
+
+static void update_display_setting(void)
+{
+ int i;
+ struct fb_info *fbi;
+ struct v4l2_rect bg_crop_bounds[2];
+
+ mutex_lock(&gfb_mutex);
+ for (i = 0; i < num_registered_fb; i++) {
+ fbi = registered_fb[i];
+
+ memset(&g_fb_setting[i], 0, sizeof(struct mxc_vout_fb));
+
+ if (!strncmp(fbi->fix.id, "DISP3", 5))
+ g_fb_setting[i].ipu_id = 0;
+ else
+ g_fb_setting[i].ipu_id = 1;
+
+ g_fb_setting[i].name = fbi->fix.id;
+ g_fb_setting[i].crop_bounds.left = 0;
+ g_fb_setting[i].crop_bounds.top = 0;
+ g_fb_setting[i].crop_bounds.width = fbi->var.xres;
+ g_fb_setting[i].crop_bounds.height = fbi->var.yres;
+ g_fb_setting[i].disp_fmt = get_ipu_fmt(fbi);
+
+ if (get_ipu_channel(fbi) == MEM_BG_SYNC) {
+ bg_crop_bounds[g_fb_setting[i].ipu_id] =
+ g_fb_setting[i].crop_bounds;
+ g_fb_setting[i].disp_support_csc = true;
+ } else if (get_ipu_channel(fbi) == MEM_FG_SYNC) {
+ g_fb_setting[i].disp_support_csc = true;
+ g_fb_setting[i].disp_support_windows = true;
+ }
+ }
+
+ for (i = 0; i < num_registered_fb; i++) {
+ fbi = registered_fb[i];
+
+ if (get_ipu_channel(fbi) == MEM_FG_SYNC)
+ g_fb_setting[i].crop_bounds =
+ bg_crop_bounds[g_fb_setting[i].ipu_id];
+ }
+ mutex_unlock(&gfb_mutex);
+}
+
+/* called after g_fb_setting filled by update_display_setting */
+static int update_setting_from_fbi(struct mxc_vout_output *vout,
+ struct fb_info *fbi)
+{
+ int i;
+ bool found = false;
+
+ mutex_lock(&gfbi_mutex);
+
+ update_display_setting();
+
+ for (i = 0; i < MAX_FB_NUM; i++) {
+ if (g_fb_setting[i].name) {
+ if (!strcmp(fbi->fix.id, g_fb_setting[i].name)) {
+ vout->crop_bounds = g_fb_setting[i].crop_bounds;
+ vout->disp_fmt = g_fb_setting[i].disp_fmt;
+ vout->disp_support_csc =
+ g_fb_setting[i].disp_support_csc;
+ vout->disp_support_windows =
+ g_fb_setting[i].disp_support_windows;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ v4l2_err(vout->vfd->v4l2_dev, "can not find output\n");
+ mutex_unlock(&gfbi_mutex);
+ return -EINVAL;
+ }
+ strlcpy(vout->vfd->name, fbi->fix.id, sizeof(vout->vfd->name));
+
+ memset(&vout->task, 0, sizeof(struct ipu_task));
+
+ vout->task.input.width = DEF_INPUT_WIDTH;
+ vout->task.input.height = DEF_INPUT_HEIGHT;
+ vout->task.input.crop.pos.x = 0;
+ vout->task.input.crop.pos.y = 0;
+ vout->task.input.crop.w = DEF_INPUT_WIDTH;
+ vout->task.input.crop.h = DEF_INPUT_HEIGHT;
+ vout->input_crop = false;
+
+ vout->task.output.width = vout->crop_bounds.width;
+ vout->task.output.height = vout->crop_bounds.height;
+ vout->task.output.crop.pos.x = 0;
+ vout->task.output.crop.pos.y = 0;
+ vout->task.output.crop.w = vout->crop_bounds.width;
+ vout->task.output.crop.h = vout->crop_bounds.height;
+ if (colorspaceofpixel(vout->disp_fmt) == YUV_CS)
+ vout->task.output.format = IPU_PIX_FMT_UYVY;
+ else
+ vout->task.output.format = IPU_PIX_FMT_RGB565;
+
+ mutex_unlock(&gfbi_mutex);
+ return 0;
+}
+
+static inline unsigned long get_jiffies(struct timeval *t)
+{
+ struct timeval cur;
+
+ if (t->tv_usec >= 1000000) {
+ t->tv_sec += t->tv_usec / 1000000;
+ t->tv_usec = t->tv_usec % 1000000;
+ }
+
+ do_gettimeofday(&cur);
+ if ((t->tv_sec < cur.tv_sec)
+ || ((t->tv_sec == cur.tv_sec) && (t->tv_usec < cur.tv_usec)))
+ return jiffies;
+
+ if (t->tv_usec < cur.tv_usec) {
+ cur.tv_sec = t->tv_sec - cur.tv_sec - 1;
+ cur.tv_usec = t->tv_usec + 1000000 - cur.tv_usec;
+ } else {
+ cur.tv_sec = t->tv_sec - cur.tv_sec;
+ cur.tv_usec = t->tv_usec - cur.tv_usec;
+ }
+
+ return jiffies + timeval_to_jiffies(&cur);
+}
+
+static bool deinterlace_3_field(struct mxc_vout_output *vout)
+{
+ return (vout->task.input.deinterlace.enable &&
+ (vout->task.input.deinterlace.motion != HIGH_MOTION));
+}
+
+static int set_field_fmt(struct mxc_vout_output *vout, enum v4l2_field field)
+{
+ struct ipu_deinterlace *deinterlace = &vout->task.input.deinterlace;
+
+ switch (field) {
+ /* Images are in progressive format, not interlaced */
+ case V4L2_FIELD_NONE:
+ case V4L2_FIELD_ANY:
+ deinterlace->enable = false;
+ deinterlace->field_fmt = 0;
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "Progressive frame.\n");
+ break;
+ case V4L2_FIELD_INTERLACED_TB:
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "Enable deinterlace TB.\n");
+ deinterlace->enable = true;
+ deinterlace->field_fmt = IPU_DEINTERLACE_FIELD_TOP;
+ break;
+ case V4L2_FIELD_INTERLACED_BT:
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "Enable deinterlace BT.\n");
+ deinterlace->enable = true;
+ deinterlace->field_fmt = IPU_DEINTERLACE_FIELD_BOTTOM;
+ break;
+ default:
+ v4l2_err(vout->vfd->v4l2_dev,
+ "field format:%d not supported yet!\n", field);
+ return -EINVAL;
+ }
+
+ if (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format) {
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "tiled fmt enable deinterlace.\n");
+ deinterlace->enable = true;
+ }
+
+ if (deinterlace->enable && vdi_rate_double)
+ deinterlace->field_fmt |= IPU_DEINTERLACE_RATE_EN;
+
+ return 0;
+}
+
+static bool is_pp_bypass(struct mxc_vout_output *vout)
+{
+ if ((IPU_PIX_FMT_TILED_NV12 == vout->task.input.format) ||
+ (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format))
+ return false;
+ if ((vout->task.input.width == vout->task.output.width) &&
+ (vout->task.input.height == vout->task.output.height) &&
+ (vout->task.input.crop.w == vout->task.output.crop.w) &&
+ (vout->task.input.crop.h == vout->task.output.crop.h) &&
+ (vout->task.output.rotate < IPU_ROTATE_HORIZ_FLIP) &&
+ !vout->task.input.deinterlace.enable) {
+ if (vout->disp_support_csc)
+ return true;
+ else if (!need_csc(vout->task.input.format, vout->disp_fmt))
+ return true;
+ /*
+ * input crop show to full output which can show based on
+ * xres_virtual/yres_virtual
+ */
+ } else if ((vout->task.input.crop.w == vout->task.output.crop.w) &&
+ (vout->task.output.crop.w == vout->task.output.width) &&
+ (vout->task.input.crop.h == vout->task.output.crop.h) &&
+ (vout->task.output.crop.h ==
+ vout->task.output.height) &&
+ (vout->task.output.rotate < IPU_ROTATE_HORIZ_FLIP) &&
+ !vout->task.input.deinterlace.enable) {
+ if (vout->disp_support_csc)
+ return true;
+ else if (!need_csc(vout->task.input.format, vout->disp_fmt))
+ return true;
+ }
+ return false;
+}
+
+static void setup_buf_timer(struct mxc_vout_output *vout,
+ struct videobuf_buffer *vb)
+{
+ ktime_t expiry_time, now;
+
+ /* if timestamp is 0, then default to 30fps */
+ if ((vb->ts.tv_sec == 0) && (vb->ts.tv_usec == 0))
+ expiry_time = ktime_add_ns(vout->start_ktime,
+ NSEC_PER_FRAME_30FPS * vout->frame_count);
+ else
+ expiry_time = timeval_to_ktime(vb->ts);
+
+ now = hrtimer_cb_get_time(&vout->timer);
+ if ((now.tv64 > expiry_time.tv64)) {
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "warning: timer timeout already expired.\n");
+ expiry_time = now;
+ }
+
+ hrtimer_start(&vout->timer, expiry_time, HRTIMER_MODE_ABS);
+
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "timer handler next "
+ "schedule: %lldnsecs\n", expiry_time.tv64);
+}
+
+static int show_buf(struct mxc_vout_output *vout, int idx,
+ struct ipu_pos *ipos)
+{
+ struct fb_info *fbi = vout->fbi;
+ struct fb_var_screeninfo var;
+ int ret;
+ u32 fb_base = 0;
+
+ memcpy(&var, &fbi->var, sizeof(var));
+
+ if (vout->linear_bypass_pp || vout->tiled_bypass_pp) {
+ /*
+ * crack fb base
+ * NOTE: should not do other fb operation during v4l2
+ */
+ console_lock();
+ fb_base = fbi->fix.smem_start;
+ fbi->fix.smem_start = vout->task.output.paddr;
+ fbi->var.yoffset = ipos->y + 1;
+ var.xoffset = ipos->x;
+ var.yoffset = ipos->y;
+ var.vmode |= FB_VMODE_YWRAP;
+ ret = fb_pan_display(fbi, &var);
+ fbi->fix.smem_start = fb_base;
+ console_unlock();
+ } else {
+ console_lock();
+ var.yoffset = idx * fbi->var.yres;
+ var.vmode &= ~FB_VMODE_YWRAP;
+ ret = fb_pan_display(fbi, &var);
+ console_unlock();
+ }
+
+ return ret;
+}
+
+static void disp_work_func(struct work_struct *work)
+{
+ struct mxc_vout_output *vout =
+ container_of(work, struct mxc_vout_output, disp_work);
+ struct videobuf_queue *q = &vout->vbq;
+ struct videobuf_buffer *vb, *vb_next = NULL;
+ unsigned long flags = 0;
+ struct ipu_pos ipos;
+ int ret = 0;
+ u32 in_fmt = 0, in_width = 0, in_height = 0;
+ u32 vdi_cnt = 0;
+ u32 vdi_frame;
+ u32 index = 0;
+ u32 ocrop_h = 0;
+ u32 o_height = 0;
+ u32 tiled_interlaced = 0;
+ bool tiled_fmt = false;
+
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "disp work begin one frame\n");
+
+ spin_lock_irqsave(q->irqlock, flags);
+
+ if (list_empty(&vout->active_list)) {
+ v4l2_warn(vout->vfd->v4l2_dev,
+ "no entry in active_list, should not be here\n");
+ spin_unlock_irqrestore(q->irqlock, flags);
+ return;
+ }
+
+ vb = list_first_entry(&vout->active_list,
+ struct videobuf_buffer, queue);
+ ret = set_field_fmt(vout, vb->field);
+ if (ret < 0) {
+ spin_unlock_irqrestore(q->irqlock, flags);
+ return;
+ }
+ if (deinterlace_3_field(vout)) {
+ if (list_is_singular(&vout->active_list)) {
+ if (list_empty(&vout->queue_list)) {
+ vout->timer_stop = true;
+ spin_unlock_irqrestore(q->irqlock, flags);
+ v4l2_warn(vout->vfd->v4l2_dev,
+ "no enough entry for 3 fields "
+ "deinterlacer\n");
+ return;
+ }
+
+ /*
+ * We need to use the next vb even if it is
+ * not on the active list.
+ */
+ vb_next = list_first_entry(&vout->queue_list,
+ struct videobuf_buffer, queue);
+ } else
+ vb_next = list_first_entry(vout->active_list.next,
+ struct videobuf_buffer, queue);
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "cur field_fmt:%d, next field_fmt:%d.\n",
+ vb->field, vb_next->field);
+ /* repeat the last field during field format changing */
+ if ((vb->field != vb_next->field) &&
+ (vb_next->field != V4L2_FIELD_NONE))
+ vb_next = vb;
+ }
+
+ spin_unlock_irqrestore(q->irqlock, flags);
+
+vdi_frame_rate_double:
+ mutex_lock(&vout->task_lock);
+
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "v4l2 frame_cnt:%ld, vb_field:%d, fmt:%d\n",
+ vout->frame_count, vb->field,
+ vout->task.input.deinterlace.field_fmt);
+ if (vb->memory == V4L2_MEMORY_USERPTR)
+ vout->task.input.paddr = vb->baddr;
+ else
+ vout->task.input.paddr = videobuf_to_dma_contig(vb);
+
+ if (vout->task.input.deinterlace.field_fmt & IPU_DEINTERLACE_RATE_EN)
+ index = vout->vdi_frame_cnt % FB_BUFS;
+ else
+ index = vout->frame_count % FB_BUFS;
+ if (vout->linear_bypass_pp) {
+ vout->task.output.paddr = vout->task.input.paddr;
+ ipos.x = vout->task.input.crop.pos.x;
+ ipos.y = vout->task.input.crop.pos.y;
+ } else {
+ if (deinterlace_3_field(vout)) {
+ if (vb->memory == V4L2_MEMORY_USERPTR)
+ vout->task.input.paddr_n = vb_next->baddr;
+ else
+ vout->task.input.paddr_n =
+ videobuf_to_dma_contig(vb_next);
+ }
+ vout->task.output.paddr = vout->disp_bufs[index];
+ if (vout->vdoa_1080p) {
+ o_height = vout->task.output.height;
+ ocrop_h = vout->task.output.crop.h;
+ vout->task.output.height = FRAME_HEIGHT_1080P;
+ vout->task.output.crop.h = FRAME_HEIGHT_1080P;
+ }
+ tiled_fmt =
+ (IPU_PIX_FMT_TILED_NV12 == vout->task.input.format) ||
+ (IPU_PIX_FMT_TILED_NV12F == vout->task.input.format);
+ if (vout->tiled_bypass_pp) {
+ ipos.x = vout->task.input.crop.pos.x;
+ ipos.y = vout->task.input.crop.pos.y;
+ } else if (tiled_fmt) {
+ vout->vdoa_task.input.paddr = vout->task.input.paddr;
+ if (deinterlace_3_field(vout))
+ vout->vdoa_task.input.paddr_n =
+ vout->task.input.paddr_n;
+ vout->vdoa_task.output.paddr = vout->vdoa_work.paddr;
+ ret = ipu_queue_task(&vout->vdoa_task);
+ if (ret < 0) {
+ mutex_unlock(&vout->task_lock);
+ goto err;
+ }
+ vout->task.input.paddr = vout->vdoa_task.output.paddr;
+ in_fmt = vout->task.input.format;
+ in_width = vout->task.input.width;
+ in_height = vout->task.input.height;
+ vout->task.input.format = vout->vdoa_task.output.format;
+ vout->task.input.width = vout->vdoa_task.output.width;
+ vout->task.input.height = vout->vdoa_task.output.height;
+ if (vout->task.input.deinterlace.enable) {
+ tiled_interlaced = 1;
+ vout->task.input.deinterlace.enable = 0;
+ }
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "tiled queue task\n");
+ }
+ ret = ipu_queue_task(&vout->task);
+ if ((!vout->tiled_bypass_pp) && tiled_fmt) {
+ vout->task.input.format = in_fmt;
+ vout->task.input.width = in_width;
+ vout->task.input.height = in_height;
+ }
+ if (tiled_interlaced)
+ vout->task.input.deinterlace.enable = 1;
+ if (ret < 0) {
+ mutex_unlock(&vout->task_lock);
+ goto err;
+ }
+ if (vout->vdoa_1080p) {
+ vout->task.output.crop.h = ocrop_h;
+ vout->task.output.height = o_height;
+ }
+ }
+
+ mutex_unlock(&vout->task_lock);
+
+ ret = show_buf(vout, index, &ipos);
+ if (ret < 0)
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "show buf with ret %d\n", ret);
+
+ if (vout->task.input.deinterlace.field_fmt & IPU_DEINTERLACE_RATE_EN) {
+ vdi_frame = vout->task.input.deinterlace.field_fmt
+ & IPU_DEINTERLACE_RATE_FRAME1;
+ if (vdi_frame)
+ vout->task.input.deinterlace.field_fmt &=
+ ~IPU_DEINTERLACE_RATE_FRAME1;
+ else
+ vout->task.input.deinterlace.field_fmt |=
+ IPU_DEINTERLACE_RATE_FRAME1;
+ vout->vdi_frame_cnt++;
+ vdi_cnt++;
+ if (vdi_cnt < IPU_DEINTERLACE_MAX_FRAME)
+ goto vdi_frame_rate_double;
+ }
+ spin_lock_irqsave(q->irqlock, flags);
+
+ list_del(&vb->queue);
+
+ /*
+ * The videobuf before the last one has been shown. Set
+ * VIDEOBUF_DONE state here to avoid tearing issue in ic bypass
+ * case, which makes sure a buffer being shown will not be
+ * dequeued to be overwritten. It also brings side-effect that
+ * the last 2 buffers can not be dequeued correctly, apps need
+ * to take care of it.
+ */
+ if (vout->pre2_vb) {
+ vout->pre2_vb->state = VIDEOBUF_DONE;
+ wake_up_interruptible(&vout->pre2_vb->done);
+ vout->pre2_vb = NULL;
+ }
+
+ if (vout->linear_bypass_pp) {
+ vout->pre2_vb = vout->pre1_vb;
+ vout->pre1_vb = vb;
+ } else {
+ if (vout->pre1_vb) {
+ vout->pre1_vb->state = VIDEOBUF_DONE;
+ wake_up_interruptible(&vout->pre1_vb->done);
+ vout->pre1_vb = NULL;
+ }
+ vb->state = VIDEOBUF_DONE;
+ wake_up_interruptible(&vb->done);
+ }
+
+ vout->frame_count++;
+
+ /* pick next queue buf to setup timer */
+ if (list_empty(&vout->queue_list))
+ vout->timer_stop = true;
+ else {
+ vb = list_first_entry(&vout->queue_list,
+ struct videobuf_buffer, queue);
+ setup_buf_timer(vout, vb);
+ }
+
+ spin_unlock_irqrestore(q->irqlock, flags);
+
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev, "disp work finish one frame\n");
+
+ return;
+err:
+ v4l2_err(vout->vfd->v4l2_dev, "display work fail ret = %d\n", ret);
+ vout->timer_stop = true;
+ vb->state = VIDEOBUF_ERROR;
+ return;
+}
+
+static enum hrtimer_restart mxc_vout_timer_handler(struct hrtimer *timer)
+{
+ struct mxc_vout_output *vout = container_of(timer,
+ struct mxc_vout_output,
+ timer);
+ struct videobuf_queue *q = &vout->vbq;
+ struct videobuf_buffer *vb;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(q->irqlock, flags);
+
+ /*
+ * put first queued entry into active, if previous entry did not
+ * finish, setup current entry's timer again.
+ */
+ if (list_empty(&vout->queue_list)) {
+ spin_unlock_irqrestore(q->irqlock, flags);
+ return HRTIMER_NORESTART;
+ }
+
+ /* move videobuf from queued list to active list */
+ vb = list_first_entry(&vout->queue_list,
+ struct videobuf_buffer, queue);
+ list_del(&vb->queue);
+ list_add_tail(&vb->queue, &vout->active_list);
+
+ if (queue_work(vout->v4l_wq, &vout->disp_work) == 0) {
+ v4l2_warn(vout->vfd->v4l2_dev,
+ "disp work was in queue already, queue buf again next time\n");
+ list_del(&vb->queue);
+ list_add(&vb->queue, &vout->queue_list);
+ spin_unlock_irqrestore(q->irqlock, flags);
+ return HRTIMER_NORESTART;
+ }
+
+ vb->state = VIDEOBUF_ACTIVE;
+
+ spin_unlock_irqrestore(q->irqlock, flags);
+
+ return HRTIMER_NORESTART;
+}
+
+/* Video buffer call backs */
+
+/*
+ * Buffer setup function is called by videobuf layer when REQBUF ioctl is
+ * called. This is used to setup buffers and return size and count of
+ * buffers allocated. After the call to this buffer, videobuf layer will
+ * setup buffer queue depending on the size and count of buffers
+ */
+static int mxc_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
+ unsigned int *size)
+{
+ struct mxc_vout_output *vout = q->priv_data;
+ unsigned int frame_size;
+
+ if (!vout)
+ return -EINVAL;
+
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type)
+ return -EINVAL;
+
+ frame_size = get_frame_size(vout);
+ *size = PAGE_ALIGN(frame_size);
+
+ return 0;
+}
+
+/*
+ * This function will be called when VIDIOC_QBUF ioctl is called.
+ * It prepare buffers before give out for the display. This function
+ * converts user space virtual address into physical address if userptr memory
+ * exchange mechanism is used.
+ */
+static int mxc_vout_buffer_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ vb->state = VIDEOBUF_PREPARED;
+ return 0;
+}
+
+/*
+ * Buffer queue funtion will be called from the videobuf layer when _QBUF
+ * ioctl is called. It is used to enqueue buffer, which is ready to be
+ * displayed.
+ * This function is protected by q->irqlock.
+ */
+static void mxc_vout_buffer_queue(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct mxc_vout_output *vout = q->priv_data;
+ struct videobuf_buffer *active_vb;
+
+ list_add_tail(&vb->queue, &vout->queue_list);
+ vb->state = VIDEOBUF_QUEUED;
+
+ if (vout->timer_stop) {
+ if (deinterlace_3_field(vout) &&
+ !list_empty(&vout->active_list)) {
+ active_vb = list_first_entry(&vout->active_list,
+ struct videobuf_buffer, queue);
+ setup_buf_timer(vout, active_vb);
+ } else {
+ setup_buf_timer(vout, vb);
+ }
+ vout->timer_stop = false;
+ }
+}
+
+/*
+ * Buffer release function is called from videobuf layer to release buffer
+ * which are already allocated
+ */
+static void mxc_vout_buffer_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int mxc_vout_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ int ret;
+ struct mxc_vout_output *vout = file->private_data;
+
+ if (!vout)
+ return -ENODEV;
+
+ ret = videobuf_mmap_mapper(&vout->vbq, vma);
+ if (ret < 0)
+ v4l2_err(vout->vfd->v4l2_dev,
+ "offset invalid [offset=0x%lx]\n",
+ (vma->vm_pgoff << PAGE_SHIFT));
+
+ return ret;
+}
+
+static int mxc_vout_release(struct file *file)
+{
+ unsigned int ret = 0;
+ struct videobuf_queue *q;
+ struct mxc_vout_output *vout = file->private_data;
+
+ if (!vout)
+ return 0;
+
+ mutex_lock(&vout->accs_lock);
+ if (--vout->open_cnt == 0) {
+ q = &vout->vbq;
+ if (q->streaming)
+ mxc_vidioc_streamoff(file, vout, vout->type);
+ else {
+ release_disp_output(vout);
+ videobuf_queue_cancel(q);
+ }
+ destroy_workqueue(vout->v4l_wq);
+ ret = videobuf_mmap_free(q);
+ }
+
+ mutex_unlock(&vout->accs_lock);
+ return ret;
+}
+
+static long mxc_vout_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct mxc_vout_output *vout = file->private_data;
+ struct v4l2_crop crop;
+ int ret;
+
+ switch (cmd) {
+ case VIDIOC_S_INPUT_CROP:
+ if (copy_from_user(&crop, (void __user *)arg, sizeof(struct v4l2_crop)))
+ return -EFAULT;
+ ret = mxc_vidioc_s_input_crop(vout, &crop);
+ break;
+ case VIDIOC_G_INPUT_CROP:
+ mxc_vidioc_g_input_crop(vout, &crop);
+ ret = copy_from_user((void __user *)arg, &crop, sizeof(struct v4l2_crop));
+ break;
+ default:
+ ret = video_ioctl2(file, cmd, arg);
+ }
+ return ret;
+}
+
+static int mxc_vout_open(struct file *file)
+{
+ struct mxc_vout_output *vout = NULL;
+ int ret = 0;
+
+ vout = video_drvdata(file);
+
+ if (vout == NULL)
+ return -ENODEV;
+
+ mutex_lock(&vout->accs_lock);
+ if (vout->open_cnt++ == 0) {
+ vout->ctrl_rotate = 0;
+ vout->ctrl_vflip = 0;
+ vout->ctrl_hflip = 0;
+ ret = update_setting_from_fbi(vout, vout->fbi);
+ if (ret < 0)
+ goto err;
+
+ vout->v4l_wq = create_singlethread_workqueue("v4l2q");
+ if (!vout->v4l_wq) {
+ v4l2_err(vout->vfd->v4l2_dev,
+ "Could not create work queue\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ INIT_WORK(&vout->disp_work, disp_work_func);
+
+ INIT_LIST_HEAD(&vout->queue_list);
+ INIT_LIST_HEAD(&vout->active_list);
+
+ vout->fmt_init = false;
+ vout->frame_count = 0;
+ vout->vdi_frame_cnt = 0;
+
+ vout->win_pos.x = 0;
+ vout->win_pos.y = 0;
+ vout->release = true;
+ }
+
+ file->private_data = vout;
+
+err:
+ mutex_unlock(&vout->accs_lock);
+ return ret;
+}
+
+/*
+ * V4L2 ioctls
+ */
+static int mxc_vidioc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct mxc_vout_output *vout = fh;
+
+ strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, vout->vfd->name, sizeof(cap->card));
+ cap->bus_info[0] = '\0';
+ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+ return 0;
+}
+
+static int mxc_vidioc_enum_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_fmtdesc *fmt)
+{
+ if (fmt->index >= NUM_MXC_VOUT_FORMATS)
+ return -EINVAL;
+
+ strlcpy(fmt->description, mxc_formats[fmt->index].description,
+ sizeof(fmt->description));
+ fmt->pixelformat = mxc_formats[fmt->index].pixelformat;
+
+ return 0;
+}
+
+static int mxc_vidioc_g_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct mxc_vout_output *vout = fh;
+
+ f->fmt.pix.width = vout->task.input.width;
+ f->fmt.pix.height = vout->task.input.height;
+ f->fmt.pix.pixelformat = vout->task.input.format;
+ f->fmt.pix.sizeimage = get_frame_size(vout);
+
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "frame_size:0x%x, pix_fmt:0x%x\n",
+ f->fmt.pix.sizeimage,
+ vout->task.input.format);
+
+ return 0;
+}
+
+static inline int ipu_try_task(struct mxc_vout_output *vout)
+{
+ int ret;
+ struct ipu_task *task = &vout->task;
+
+again:
+ ret = ipu_check_task(task);
+ if (ret != IPU_CHECK_OK) {
+ if (ret > IPU_CHECK_ERR_MIN) {
+ if (ret == IPU_CHECK_ERR_SPLIT_INPUTW_OVER ||
+ ret == IPU_CHECK_ERR_W_DOWNSIZE_OVER) {
+ task->input.crop.w -= 8;
+ goto again;
+ }
+ if (ret == IPU_CHECK_ERR_SPLIT_INPUTH_OVER ||
+ ret == IPU_CHECK_ERR_H_DOWNSIZE_OVER) {
+ task->input.crop.h -= 8;
+ goto again;
+ }
+ if (ret == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) {
+ if (vout->disp_support_windows) {
+ task->output.width -= 8;
+ task->output.crop.w =
+ task->output.width;
+ } else
+ task->output.crop.w -= 8;
+ goto again;
+ }
+ if (ret == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) {
+ if (vout->disp_support_windows) {
+ task->output.height -= 8;
+ task->output.crop.h =
+ task->output.height;
+ } else
+ task->output.crop.h -= 8;
+ goto again;
+ }
+ ret = -EINVAL;
+ }
+ } else
+ ret = 0;
+
+ return ret;
+}
+
+static inline int vdoaipu_try_task(struct mxc_vout_output *vout)
+{
+ int ret;
+ int is_1080p_stream;
+ int in_width, in_height;
+ size_t size;
+ struct ipu_task *ipu_task = &vout->task;
+ struct ipu_crop *icrop = &ipu_task->input.crop;
+ struct ipu_task *vdoa_task = &vout->vdoa_task;
+ u32 deinterlace = 0;
+ u32 in_fmt;
+
+ if (vout->task.input.deinterlace.enable)
+ deinterlace = 1;
+
+ memset(vdoa_task, 0, sizeof(*vdoa_task));
+ vdoa_task->output.format = IPU_PIX_FMT_NV12;
+ memcpy(&vdoa_task->input, &ipu_task->input,
+ sizeof(ipu_task->input));
+ if ((icrop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN) ||
+ (icrop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN)) {
+ vdoa_task->input.crop.w =
+ ALIGN(icrop->w, IPU_PIX_FMT_TILED_NV12_MBALIGN);
+ vdoa_task->input.crop.h =
+ ALIGN(icrop->h, IPU_PIX_FMT_TILED_NV12_MBALIGN);
+ }
+ vdoa_task->output.width = vdoa_task->input.crop.w;
+ vdoa_task->output.height = vdoa_task->input.crop.h;
+ vdoa_task->output.crop.w = vdoa_task->input.crop.w;
+ vdoa_task->output.crop.h = vdoa_task->input.crop.h;
+
+ size = PAGE_ALIGN(vdoa_task->input.crop.w *
+ vdoa_task->input.crop.h *
+ fmt_to_bpp(vdoa_task->output.format)/8);
+ if (size > vout->vdoa_work.size) {
+ if (vout->vdoa_work.vaddr)
+ free_dma_buf(vout, &vout->vdoa_work);
+ vout->vdoa_work.size = size;
+ ret = alloc_dma_buf(vout, &vout->vdoa_work);
+ if (ret < 0)
+ return ret;
+ }
+ ret = ipu_check_task(vdoa_task);
+ if (ret != IPU_CHECK_OK)
+ return -EINVAL;
+
+ is_1080p_stream = CHECK_TILED_1080P_STREAM(vout);
+ if (is_1080p_stream)
+ ipu_task->input.crop.h = VALID_HEIGHT_1080P;
+ in_fmt = ipu_task->input.format;
+ in_width = ipu_task->input.width;
+ in_height = ipu_task->input.height;
+ ipu_task->input.format = vdoa_task->output.format;
+ ipu_task->input.height = vdoa_task->output.height;
+ ipu_task->input.width = vdoa_task->output.width;
+ if (deinterlace)
+ ipu_task->input.deinterlace.enable = 0;
+ ret = ipu_try_task(vout);
+ if (deinterlace)
+ ipu_task->input.deinterlace.enable = 1;
+ ipu_task->input.format = in_fmt;
+ ipu_task->input.width = in_width;
+ ipu_task->input.height = in_height;
+
+ return ret;
+}
+
+static int mxc_vout_try_task(struct mxc_vout_output *vout)
+{
+ int ret = 0;
+ struct ipu_output *output = &vout->task.output;
+ struct ipu_input *input = &vout->task.input;
+ struct ipu_crop *crop = &input->crop;
+ u32 o_height = 0;
+ u32 ocrop_h = 0;
+ bool tiled_fmt = false;
+ bool tiled_need_pp = false;
+
+ vout->vdoa_1080p = CHECK_TILED_1080P_DISPLAY(vout);
+ if (vout->vdoa_1080p) {
+ input->crop.h = FRAME_HEIGHT_1080P;
+ o_height = output->height;
+ ocrop_h = output->crop.h;
+ output->height = FRAME_HEIGHT_1080P;
+ output->crop.h = FRAME_HEIGHT_1080P;
+ }
+
+ if ((IPU_PIX_FMT_TILED_NV12 == input->format) ||
+ (IPU_PIX_FMT_TILED_NV12F == input->format)) {
+ if ((input->width % IPU_PIX_FMT_TILED_NV12_MBALIGN) ||
+ (input->height % IPU_PIX_FMT_TILED_NV12_MBALIGN) ||
+ (crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN) ||
+ (crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN)) {
+ v4l2_err(vout->vfd->v4l2_dev,
+ "ERR: tiled fmt needs 16 pixel align.\n");
+ return -EINVAL;
+ }
+ if ((crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN) ||
+ (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+ tiled_need_pp = true;
+ } else {
+ crop->w -= crop->w % 8;
+ crop->h -= crop->h % 8;
+ }
+ /* assume task.output already set by S_CROP */
+ vout->linear_bypass_pp = is_pp_bypass(vout);
+ if (vout->linear_bypass_pp) {
+ v4l2_info(vout->vfd->v4l2_dev, "Bypass IC.\n");
+ output->format = input->format;
+ } else {
+ /* if need CSC, choose IPU-DP or IPU_IC do it */
+ if (vout->disp_support_csc) {
+ if (colorspaceofpixel(input->format) == YUV_CS)
+ output->format = IPU_PIX_FMT_UYVY;
+ else
+ output->format = IPU_PIX_FMT_RGB565;
+ } else {
+ if (colorspaceofpixel(vout->disp_fmt) == YUV_CS)
+ output->format = IPU_PIX_FMT_UYVY;
+ else
+ output->format = IPU_PIX_FMT_RGB565;
+ }
+
+ vout->tiled_bypass_pp = false;
+ if ((IPU_PIX_FMT_TILED_NV12 == input->format) ||
+ (IPU_PIX_FMT_TILED_NV12F == input->format)) {
+ /* check resize/rotate/flip, or csc task */
+ if (!(tiled_need_pp ||
+ (IPU_ROTATE_NONE != output->rotate) ||
+ (input->crop.w != output->crop.w) ||
+ (input->crop.h != output->crop.h) ||
+ (!vout->disp_support_csc &&
+ (colorspaceofpixel(vout->disp_fmt) == RGB_CS)))
+ ) {
+ /* IC bypass */
+ output->format = IPU_PIX_FMT_NV12;
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "tiled bypass pp\n");
+ vout->tiled_bypass_pp = true;
+ }
+ tiled_fmt = true;
+ }
+
+ if ((!vout->tiled_bypass_pp) && tiled_fmt)
+ ret = vdoaipu_try_task(vout);
+ else
+ ret = ipu_try_task(vout);
+ }
+
+ if (vout->vdoa_1080p) {
+ output->height = o_height;
+ output->crop.h = ocrop_h;
+ }
+
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "icrop.w:%u, icrop.h:%u, iw:%u, ih:%u,"
+ "ocrop.w:%u, ocrop.h:%u, ow:%u, oh:%u\n",
+ input->crop.w, input->crop.h,
+ input->width, input->height,
+ output->crop.w, output->crop.h,
+ output->width, output->height);
+ return ret;
+}
+
+static int mxc_vout_try_format(struct mxc_vout_output *vout,
+ struct v4l2_format *f)
+{
+ int ret = 0;
+
+ if ((f->fmt.pix.field != V4L2_FIELD_NONE) &&
+ (IPU_PIX_FMT_TILED_NV12 == vout->task.input.format)) {
+ v4l2_err(vout->vfd->v4l2_dev,
+ "progressive tiled fmt should used V4L2_FIELD_NONE!\n");
+ return -EINVAL;
+ }
+
+ if (vout->input_crop == false) {
+ vout->task.input.crop.pos.x = 0;
+ vout->task.input.crop.pos.y = 0;
+ vout->task.input.crop.w = f->fmt.pix.width;
+ vout->task.input.crop.h = f->fmt.pix.height;
+ }
+
+ vout->task.input.width = f->fmt.pix.width;
+ vout->task.input.height = f->fmt.pix.height;
+ vout->task.input.format = f->fmt.pix.pixelformat;
+
+ ret = set_field_fmt(vout, f->fmt.pix.field);
+ if (ret < 0)
+ return ret;
+
+ ret = mxc_vout_try_task(vout);
+ if (!ret) {
+ f->fmt.pix.width = vout->task.input.crop.w;
+ f->fmt.pix.height = vout->task.input.crop.h;
+ }
+
+ return ret;
+}
+
+static bool mxc_vout_need_fb_reconfig(struct mxc_vout_output *vout,
+ struct mxc_vout_output *pre_vout)
+{
+ if (!vout->vbq.streaming)
+ return false;
+
+ if (vout->tiled_bypass_pp)
+ return true;
+
+ if (vout->linear_bypass_pp != pre_vout->linear_bypass_pp)
+ return true;
+
+ /* cropped output resolution or format are changed */
+ if (vout->task.output.format != pre_vout->task.output.format ||
+ vout->task.output.crop.w != pre_vout->task.output.crop.w ||
+ vout->task.output.crop.h != pre_vout->task.output.crop.h)
+ return true;
+
+ /* overlay: window position or resolution are changed */
+ if (vout->disp_support_windows &&
+ (vout->win_pos.x != pre_vout->win_pos.x ||
+ vout->win_pos.y != pre_vout->win_pos.y ||
+ vout->task.output.width != pre_vout->task.output.width ||
+ vout->task.output.height != pre_vout->task.output.height))
+ return true;
+
+ /* background: cropped position is changed */
+ if (!vout->disp_support_windows &&
+ (vout->task.output.crop.pos.x !=
+ pre_vout->task.output.crop.pos.x ||
+ vout->task.output.crop.pos.y !=
+ pre_vout->task.output.crop.pos.y))
+ return true;
+
+ return false;
+}
+
+static int mxc_vidioc_s_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct mxc_vout_output *vout = fh;
+ int ret = 0;
+
+ if (vout->vbq.streaming)
+ return -EBUSY;
+
+ mutex_lock(&vout->task_lock);
+ ret = mxc_vout_try_format(vout, f);
+ if (ret >= 0)
+ vout->fmt_init = true;
+ mutex_unlock(&vout->task_lock);
+
+ return ret;
+}
+
+static int mxc_vidioc_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cropcap)
+{
+ struct mxc_vout_output *vout = fh;
+
+ if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ cropcap->bounds = vout->crop_bounds;
+ cropcap->defrect = vout->crop_bounds;
+
+ return 0;
+}
+
+static int mxc_vidioc_g_crop(struct file *file, void *fh,
+ struct v4l2_crop *crop)
+{
+ struct mxc_vout_output *vout = fh;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ if (vout->disp_support_windows) {
+ crop->c.left = vout->win_pos.x;
+ crop->c.top = vout->win_pos.y;
+ crop->c.width = vout->task.output.width;
+ crop->c.height = vout->task.output.height;
+ } else {
+ if (vout->task.output.crop.w && vout->task.output.crop.h) {
+ crop->c.left = vout->task.output.crop.pos.x;
+ crop->c.top = vout->task.output.crop.pos.y;
+ crop->c.width = vout->task.output.crop.w;
+ crop->c.height = vout->task.output.crop.h;
+ } else {
+ crop->c.left = 0;
+ crop->c.top = 0;
+ crop->c.width = vout->task.output.width;
+ crop->c.height = vout->task.output.height;
+ }
+ }
+
+ return 0;
+}
+
+static int mxc_vidioc_s_crop(struct file *file, void *fh,
+ const struct v4l2_crop *crop)
+{
+ struct mxc_vout_output *vout = fh, *pre_vout;
+ struct v4l2_rect *b = &vout->crop_bounds;
+ struct v4l2_crop fix_up_crop;
+ int ret = 0;
+
+ memcpy(&fix_up_crop, crop, sizeof(*crop));
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ if (crop->c.width < 0 || crop->c.height < 0)
+ return -EINVAL;
+
+ if (crop->c.width == 0)
+ fix_up_crop.c.width = b->width - b->left;
+ if (crop->c.height == 0)
+ fix_up_crop.c.height = b->height - b->top;
+
+ if (crop->c.top < b->top)
+ fix_up_crop.c.top = b->top;
+ if (crop->c.top >= b->top + b->height)
+ fix_up_crop.c.top = b->top + b->height - 1;
+ if (crop->c.height > b->top - crop->c.top + b->height)
+ fix_up_crop.c.height =
+ b->top - fix_up_crop.c.top + b->height;
+
+ if (crop->c.left < b->left)
+ fix_up_crop.c.left = b->left;
+ if (crop->c.left >= b->left + b->width)
+ fix_up_crop.c.left = b->left + b->width - 1;
+ if (crop->c.width > b->left - crop->c.left + b->width)
+ fix_up_crop.c.width =
+ b->left - fix_up_crop.c.left + b->width;
+
+ /* stride line limitation */
+ fix_up_crop.c.height -= fix_up_crop.c.height % 8;
+ fix_up_crop.c.width -= fix_up_crop.c.width % 8;
+ if ((fix_up_crop.c.width <= 0) || (fix_up_crop.c.height <= 0) ||
+ ((fix_up_crop.c.left + fix_up_crop.c.width) >
+ (b->left + b->width)) ||
+ ((fix_up_crop.c.top + fix_up_crop.c.height) >
+ (b->top + b->height))) {
+ v4l2_err(vout->vfd->v4l2_dev, "s_crop err: %d, %d, %d, %d",
+ fix_up_crop.c.left, fix_up_crop.c.top,
+ fix_up_crop.c.width, fix_up_crop.c.height);
+ return -EINVAL;
+ }
+
+ /* the same setting, return */
+ if (vout->disp_support_windows) {
+ if ((vout->win_pos.x == fix_up_crop.c.left) &&
+ (vout->win_pos.y == fix_up_crop.c.top) &&
+ (vout->task.output.crop.w == fix_up_crop.c.width) &&
+ (vout->task.output.crop.h == fix_up_crop.c.height))
+ return 0;
+ } else {
+ if ((vout->task.output.crop.pos.x == fix_up_crop.c.left) &&
+ (vout->task.output.crop.pos.y == fix_up_crop.c.top) &&
+ (vout->task.output.crop.w == fix_up_crop.c.width) &&
+ (vout->task.output.crop.h == fix_up_crop.c.height))
+ return 0;
+ }
+
+ pre_vout = vmalloc(sizeof(*pre_vout));
+ if (!pre_vout)
+ return -ENOMEM;
+
+ /* wait current work finish */
+ if (vout->vbq.streaming)
+ flush_workqueue(vout->v4l_wq);
+
+ mutex_lock(&vout->task_lock);
+
+ memcpy(pre_vout, vout, sizeof(*vout));
+
+ if (vout->disp_support_windows) {
+ vout->task.output.crop.pos.x = 0;
+ vout->task.output.crop.pos.y = 0;
+ vout->win_pos.x = fix_up_crop.c.left;
+ vout->win_pos.y = fix_up_crop.c.top;
+ vout->task.output.width = fix_up_crop.c.width;
+ vout->task.output.height = fix_up_crop.c.height;
+ } else {
+ vout->task.output.crop.pos.x = fix_up_crop.c.left;
+ vout->task.output.crop.pos.y = fix_up_crop.c.top;
+ }
+
+ vout->task.output.crop.w = fix_up_crop.c.width;
+ vout->task.output.crop.h = fix_up_crop.c.height;
+
+ /*
+ * must S_CROP before S_FMT, for fist time S_CROP, will not check
+ * ipu task, it will check in S_FMT, after S_FMT, S_CROP should
+ * check ipu task too.
+ */
+ if (vout->fmt_init) {
+ memcpy(&vout->task.input.crop, &vout->in_rect,
+ sizeof(vout->in_rect));
+ ret = mxc_vout_try_task(vout);
+ if (ret < 0) {
+ v4l2_err(vout->vfd->v4l2_dev,
+ "vout check task failed\n");
+ memcpy(vout, pre_vout, sizeof(*vout));
+ goto done;
+ }
+
+ if (mxc_vout_need_fb_reconfig(vout, pre_vout)) {
+ ret = config_disp_output(vout);
+ if (ret < 0)
+ v4l2_err(vout->vfd->v4l2_dev,
+ "Config display output failed\n");
+ }
+ }
+
+done:
+ vfree(pre_vout);
+ mutex_unlock(&vout->task_lock);
+
+ return ret;
+}
+
+static int mxc_vidioc_queryctrl(struct file *file, void *fh,
+ struct v4l2_queryctrl *ctrl)
+{
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_ROTATE:
+ ret = v4l2_ctrl_query_fill(ctrl, 0, 270, 90, 0);
+ break;
+ case V4L2_CID_VFLIP:
+ ret = v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0);
+ break;
+ case V4L2_CID_HFLIP:
+ ret = v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0);
+ break;
+ case V4L2_CID_MXC_MOTION:
+ ret = v4l2_ctrl_query_fill(ctrl, 0, 2, 1, 0);
+ break;
+ default:
+ ctrl->name[0] = '\0';
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int mxc_vidioc_g_ctrl(struct file *file, void *fh,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct mxc_vout_output *vout = fh;
+
+ switch (ctrl->id) {
+ case V4L2_CID_ROTATE:
+ ctrl->value = vout->ctrl_rotate;
+ break;
+ case V4L2_CID_VFLIP:
+ ctrl->value = vout->ctrl_vflip;
+ break;
+ case V4L2_CID_HFLIP:
+ ctrl->value = vout->ctrl_hflip;
+ break;
+ case V4L2_CID_MXC_MOTION:
+ if (vout->task.input.deinterlace.enable)
+ ctrl->value = vout->task.input.deinterlace.motion;
+ else
+ ctrl->value = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static void setup_task_rotation(struct mxc_vout_output *vout)
+{
+ if (vout->ctrl_rotate == 0) {
+ if (vout->ctrl_vflip && vout->ctrl_hflip)
+ vout->task.output.rotate = IPU_ROTATE_180;
+ else if (vout->ctrl_vflip)
+ vout->task.output.rotate = IPU_ROTATE_VERT_FLIP;
+ else if (vout->ctrl_hflip)
+ vout->task.output.rotate = IPU_ROTATE_HORIZ_FLIP;
+ else
+ vout->task.output.rotate = IPU_ROTATE_NONE;
+ } else if (vout->ctrl_rotate == 90) {
+ if (vout->ctrl_vflip && vout->ctrl_hflip)
+ vout->task.output.rotate = IPU_ROTATE_90_LEFT;
+ else if (vout->ctrl_vflip)
+ vout->task.output.rotate = IPU_ROTATE_90_RIGHT_VFLIP;
+ else if (vout->ctrl_hflip)
+ vout->task.output.rotate = IPU_ROTATE_90_RIGHT_HFLIP;
+ else
+ vout->task.output.rotate = IPU_ROTATE_90_RIGHT;
+ } else if (vout->ctrl_rotate == 180) {
+ if (vout->ctrl_vflip && vout->ctrl_hflip)
+ vout->task.output.rotate = IPU_ROTATE_NONE;
+ else if (vout->ctrl_vflip)
+ vout->task.output.rotate = IPU_ROTATE_HORIZ_FLIP;
+ else if (vout->ctrl_hflip)
+ vout->task.output.rotate = IPU_ROTATE_VERT_FLIP;
+ else
+ vout->task.output.rotate = IPU_ROTATE_180;
+ } else if (vout->ctrl_rotate == 270) {
+ if (vout->ctrl_vflip && vout->ctrl_hflip)
+ vout->task.output.rotate = IPU_ROTATE_90_RIGHT;
+ else if (vout->ctrl_vflip)
+ vout->task.output.rotate = IPU_ROTATE_90_RIGHT_HFLIP;
+ else if (vout->ctrl_hflip)
+ vout->task.output.rotate = IPU_ROTATE_90_RIGHT_VFLIP;
+ else
+ vout->task.output.rotate = IPU_ROTATE_90_LEFT;
+ }
+}
+
+static int mxc_vidioc_s_ctrl(struct file *file, void *fh,
+ struct v4l2_control *ctrl)
+{
+ int ret = 0;
+ struct mxc_vout_output *vout = fh, *pre_vout;
+
+ pre_vout = vmalloc(sizeof(*pre_vout));
+ if (!pre_vout)
+ return -ENOMEM;
+
+ /* wait current work finish */
+ if (vout->vbq.streaming)
+ flush_workqueue(vout->v4l_wq);
+
+ mutex_lock(&vout->task_lock);
+
+ memcpy(pre_vout, vout, sizeof(*vout));
+
+ switch (ctrl->id) {
+ case V4L2_CID_ROTATE:
+ {
+ vout->ctrl_rotate = (ctrl->value/90) * 90;
+ if (vout->ctrl_rotate > 270)
+ vout->ctrl_rotate = 270;
+ setup_task_rotation(vout);
+ break;
+ }
+ case V4L2_CID_VFLIP:
+ {
+ vout->ctrl_vflip = ctrl->value;
+ setup_task_rotation(vout);
+ break;
+ }
+ case V4L2_CID_HFLIP:
+ {
+ vout->ctrl_hflip = ctrl->value;
+ setup_task_rotation(vout);
+ break;
+ }
+ case V4L2_CID_MXC_MOTION:
+ {
+ vout->task.input.deinterlace.motion = ctrl->value;
+ break;
+ }
+ default:
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (vout->fmt_init) {
+ memcpy(&vout->task.input.crop, &vout->in_rect,
+ sizeof(vout->in_rect));
+ ret = mxc_vout_try_task(vout);
+ if (ret < 0) {
+ v4l2_err(vout->vfd->v4l2_dev,
+ "vout check task failed\n");
+ memcpy(vout, pre_vout, sizeof(*vout));
+ goto done;
+ }
+
+ if (mxc_vout_need_fb_reconfig(vout, pre_vout)) {
+ ret = config_disp_output(vout);
+ if (ret < 0)
+ v4l2_err(vout->vfd->v4l2_dev,
+ "Config display output failed\n");
+ }
+ }
+
+done:
+ vfree(pre_vout);
+ mutex_unlock(&vout->task_lock);
+
+ return ret;
+}
+
+static int mxc_vidioc_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *req)
+{
+ int ret = 0;
+ struct mxc_vout_output *vout = fh;
+ struct videobuf_queue *q = &vout->vbq;
+
+ if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ /* should not be here after streaming, videobuf_reqbufs will control */
+ mutex_lock(&vout->task_lock);
+
+ ret = videobuf_reqbufs(q, req);
+
+ mutex_unlock(&vout->task_lock);
+ return ret;
+}
+
+static int mxc_vidioc_querybuf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ int ret;
+ struct mxc_vout_output *vout = fh;
+
+ ret = videobuf_querybuf(&vout->vbq, b);
+ if (!ret) {
+ /* return physical address */
+ struct videobuf_buffer *vb = vout->vbq.bufs[b->index];
+ if (b->flags & V4L2_BUF_FLAG_MAPPED)
+ b->m.offset = videobuf_to_dma_contig(vb);
+ }
+
+ return ret;
+}
+
+static int mxc_vidioc_qbuf(struct file *file, void *fh,
+ struct v4l2_buffer *buffer)
+{
+ struct mxc_vout_output *vout = fh;
+
+ return videobuf_qbuf(&vout->vbq, buffer);
+}
+
+static int mxc_vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+ struct mxc_vout_output *vout = fh;
+
+ if (!vout->vbq.streaming)
+ return -EINVAL;
+
+ if (file->f_flags & O_NONBLOCK)
+ return videobuf_dqbuf(&vout->vbq, (struct v4l2_buffer *)b, 1);
+ else
+ return videobuf_dqbuf(&vout->vbq, (struct v4l2_buffer *)b, 0);
+}
+
+static int mxc_vidioc_s_input_crop(struct mxc_vout_output *vout,
+ const struct v4l2_crop *crop)
+{
+ int ret = 0;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ if (crop->c.width < 0 || crop->c.height < 0)
+ return -EINVAL;
+
+ vout->task.input.crop.pos.x = crop->c.left;
+ vout->task.input.crop.pos.y = crop->c.top;
+ vout->task.input.crop.w = crop->c.width;
+ vout->task.input.crop.h = crop->c.height;
+
+ vout->input_crop = true;
+ memcpy(&vout->in_rect, &vout->task.input.crop, sizeof(vout->in_rect));
+
+ return ret;
+}
+
+static int mxc_vidioc_g_input_crop(struct mxc_vout_output *vout,
+ struct v4l2_crop *crop)
+{
+ int ret = 0;
+
+ crop->c.left = vout->task.input.crop.pos.x;
+ crop->c.top = vout->task.input.crop.pos.y;
+ crop->c.width = vout->task.input.crop.w;
+ crop->c.height = vout->task.input.crop.h;
+
+ return ret;
+}
+
+static int set_window_position(struct mxc_vout_output *vout,
+ struct mxcfb_pos *pos)
+{
+ struct fb_info *fbi = vout->fbi;
+ mm_segment_t old_fs;
+ int ret = 0;
+
+ if (vout->disp_support_windows) {
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = fbi->fbops->fb_ioctl(fbi, MXCFB_SET_OVERLAY_POS,
+ (unsigned long)pos);
+ set_fs(old_fs);
+ }
+
+ return ret;
+}
+
+static int config_disp_output(struct mxc_vout_output *vout)
+{
+ struct dma_mem *buf = NULL;
+ struct fb_info *fbi = vout->fbi;
+ struct fb_var_screeninfo var;
+ struct mxcfb_pos pos;
+ int i, fb_num, ret;
+ u32 fb_base;
+ u32 size;
+ u32 display_buf_size;
+ u32 *pixel = NULL;
+ u32 color;
+ int j;
+
+ memcpy(&var, &fbi->var, sizeof(var));
+ fb_base = fbi->fix.smem_start;
+
+ var.xres = vout->task.output.width;
+ var.yres = vout->task.output.height;
+ if (vout->linear_bypass_pp || vout->tiled_bypass_pp) {
+ fb_num = 1;
+ /* input crop */
+ if (vout->task.input.width > vout->task.output.width)
+ var.xres_virtual = vout->task.input.width;
+ else
+ var.xres_virtual = var.xres;
+ if (vout->task.input.height > vout->task.output.height)
+ var.yres_virtual = vout->task.input.height;
+ else
+ var.yres_virtual = var.yres;
+ var.rotate = vout->task.output.rotate;
+ var.vmode |= FB_VMODE_YWRAP;
+ } else {
+ fb_num = FB_BUFS;
+ var.xres_virtual = var.xres;
+ var.yres_virtual = fb_num * var.yres;
+ var.vmode &= ~FB_VMODE_YWRAP;
+ }
+ var.bits_per_pixel = fmt_to_bpp(vout->task.output.format);
+ var.nonstd = vout->task.output.format;
+
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "set display fb to %d %d\n",
+ var.xres, var.yres);
+
+ /*
+ * To setup the overlay fb from scratch without
+ * the last time overlay fb position or resolution's
+ * impact, we take the following steps:
+ * - blank fb
+ * - set fb position to the starting point
+ * - reconfigure fb
+ * - set fb position to a specific point
+ * - unblank fb
+ * This procedure applies to non-overlay fbs as well.
+ */
+ console_lock();
+ fbi->flags |= FBINFO_MISC_USEREVENT;
+ fb_blank(fbi, FB_BLANK_POWERDOWN);
+ fbi->flags &= ~FBINFO_MISC_USEREVENT;
+ console_unlock();
+
+ pos.x = 0;
+ pos.y = 0;
+ ret = set_window_position(vout, &pos);
+ if (ret < 0) {
+ v4l2_err(vout->vfd->v4l2_dev, "failed to set fb position "
+ "to starting point\n");
+ return ret;
+ }
+
+ /* Init display channel through fb API */
+ var.yoffset = 0;
+ var.activate |= FB_ACTIVATE_FORCE;
+ console_lock();
+ fbi->flags |= FBINFO_MISC_USEREVENT;
+ ret = fb_set_var(fbi, &var);
+ fbi->flags &= ~FBINFO_MISC_USEREVENT;
+ console_unlock();
+ if (ret < 0) {
+ v4l2_err(vout->vfd->v4l2_dev,
+ "ERR:%s fb_set_var ret:%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = set_window_position(vout, &vout->win_pos);
+ if (ret < 0) {
+ v4l2_err(vout->vfd->v4l2_dev, "failed to set fb position\n");
+ return ret;
+ }
+
+ if (vout->linear_bypass_pp || vout->tiled_bypass_pp)
+ display_buf_size = fbi->fix.line_length * fbi->var.yres_virtual;
+ else
+ display_buf_size = fbi->fix.line_length * fbi->var.yres;
+ for (i = 0; i < fb_num; i++)
+ vout->disp_bufs[i] = fbi->fix.smem_start + i * display_buf_size;
+ if (vout->tiled_bypass_pp) {
+ size = PAGE_ALIGN(vout->task.input.crop.w *
+ vout->task.input.crop.h *
+ fmt_to_bpp(vout->task.output.format)/8);
+ if (size > vout->vdoa_output[0].size) {
+ for (i = 0; i < VDOA_FB_BUFS; i++) {
+ buf = &vout->vdoa_output[i];
+ if (buf->vaddr)
+ free_dma_buf(vout, buf);
+ buf->size = size;
+ ret = alloc_dma_buf(vout, buf);
+ if (ret < 0)
+ goto err;
+ }
+ }
+ for (i = fb_num; i < (fb_num + VDOA_FB_BUFS); i++)
+ vout->disp_bufs[i] =
+ vout->vdoa_output[i - fb_num].paddr;
+ }
+ vout->fb_smem_len = fbi->fix.smem_len;
+ vout->fb_smem_start = fbi->fix.smem_start;
+ if (fb_base != fbi->fix.smem_start) {
+ v4l2_dbg(1, debug, vout->vfd->v4l2_dev,
+ "realloc fb mem size:0x%x@0x%lx,old paddr @0x%x\n",
+ fbi->fix.smem_len, fbi->fix.smem_start, fb_base);
+ }
+
+ /* fill black when video config changed */
+ color = colorspaceofpixel(vout->task.output.format) == YUV_CS ?
+ UYVY_BLACK : RGB_BLACK;
+ if (IS_PLANAR_PIXEL_FORMAT(vout->task.output.format)) {
+ size = display_buf_size * 8 /
+ fmt_to_bpp(vout->task.output.format);
+ memset(fbi->screen_base, Y_BLACK, size);
+ memset(fbi->screen_base + size, UV_BLACK,
+ display_buf_size - size);
+ } else {
+ pixel = (u32 *)fbi->screen_base;
+ for (i = 0; i < ((display_buf_size * fb_num) >> 2); i++)
+ *pixel++ = color;
+ }
+ console_lock();
+ fbi->flags |= FBINFO_MISC_USEREVENT;
+ ret = fb_blank(fbi, FB_BLANK_UNBLANK);
+ fbi->flags &= ~FBINFO_MISC_USEREVENT;
+ console_unlock();
+ vout->release = false;
+
+ return ret;
+err:
+ for (j = i - 1; j >= 0; j--) {
+ buf = &vout->vdoa_output[j];
+ if (buf->vaddr)
+ free_dma_buf(vout, buf);
+ }
+ return ret;
+}
+
+static inline void wait_for_vsync(struct mxc_vout_output *vout)
+{
+ struct fb_info *fbi = vout->fbi;
+ mm_segment_t old_fs;
+
+ if (fbi->fbops->fb_ioctl) {
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ fbi->fbops->fb_ioctl(fbi, MXCFB_WAIT_FOR_VSYNC,
+ (unsigned long)NULL);
+ set_fs(old_fs);
+ }
+
+ return;
+}
+
+static void release_disp_output(struct mxc_vout_output *vout)
+{
+ struct fb_info *fbi = vout->fbi;
+ struct mxcfb_pos pos;
+
+ if (vout->release)
+ return;
+ console_lock();
+ fbi->flags |= FBINFO_MISC_USEREVENT;
+ fb_blank(fbi, FB_BLANK_POWERDOWN);
+ fbi->flags &= ~FBINFO_MISC_USEREVENT;
+ console_unlock();
+
+ /* restore pos to 0,0 avoid fb pan display hang? */
+ pos.x = 0;
+ pos.y = 0;
+ set_window_position(vout, &pos);
+
+ if (get_ipu_channel(fbi) == MEM_BG_SYNC) {
+ console_lock();
+ fbi->fix.smem_start = vout->disp_bufs[0];
+ fbi->flags |= FBINFO_MISC_USEREVENT;
+ fb_blank(fbi, FB_BLANK_UNBLANK);
+ fbi->flags &= ~FBINFO_MISC_USEREVENT;
+ console_unlock();
+
+ }
+
+ vout->release = true;
+}
+
+static int mxc_vidioc_streamon(struct file *file, void *fh,
+ enum v4l2_buf_type i)
+{
+ struct mxc_vout_output *vout = fh;
+ struct videobuf_queue *q = &vout->vbq;
+ int ret;
+
+ if (q->streaming) {
+ v4l2_err(vout->vfd->v4l2_dev,
+ "video output already run\n");
+ ret = -EBUSY;
+ goto done;
+ }
+
+ if (deinterlace_3_field(vout) && list_is_singular(&q->stream)) {
+ v4l2_err(vout->vfd->v4l2_dev,
+ "deinterlacing: need queue 2 frame before streamon\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = config_disp_output(vout);
+ if (ret < 0) {
+ v4l2_err(vout->vfd->v4l2_dev,
+ "Config display output failed\n");
+ goto done;
+ }
+
+ hrtimer_init(&vout->timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
+ vout->timer.function = mxc_vout_timer_handler;
+ vout->timer_stop = true;
+ vout->frame_count = 0;
+ vout->vdi_frame_cnt = 0;
+
+ vout->start_ktime = hrtimer_cb_get_time(&vout->timer);
+
+ vout->pre1_vb = NULL;
+ vout->pre2_vb = NULL;
+
+ ret = videobuf_streamon(q);
+done:
+ return ret;
+}
+
+static int mxc_vidioc_streamoff(struct file *file, void *fh,
+ enum v4l2_buf_type i)
+{
+ struct mxc_vout_output *vout = fh;
+ struct videobuf_queue *q = &vout->vbq;
+ int ret = 0;
+
+ if (q->streaming) {
+ flush_workqueue(vout->v4l_wq);
+
+ hrtimer_cancel(&vout->timer);
+
+ /*
+ * Wait for 2 vsyncs to make sure
+ * frames are drained on triple
+ * buffer.
+ */
+ wait_for_vsync(vout);
+ wait_for_vsync(vout);
+
+ release_disp_output(vout);
+
+ ret = videobuf_streamoff(&vout->vbq);
+ }
+ INIT_LIST_HEAD(&vout->queue_list);
+ INIT_LIST_HEAD(&vout->active_list);
+
+ return ret;
+}
+
+static const struct v4l2_ioctl_ops mxc_vout_ioctl_ops = {
+ .vidioc_querycap = mxc_vidioc_querycap,
+ .vidioc_enum_fmt_vid_out = mxc_vidioc_enum_fmt_vid_out,
+ .vidioc_g_fmt_vid_out = mxc_vidioc_g_fmt_vid_out,
+ .vidioc_s_fmt_vid_out = mxc_vidioc_s_fmt_vid_out,
+ .vidioc_cropcap = mxc_vidioc_cropcap,
+ .vidioc_g_crop = mxc_vidioc_g_crop,
+ .vidioc_s_crop = mxc_vidioc_s_crop,
+ .vidioc_queryctrl = mxc_vidioc_queryctrl,
+ .vidioc_g_ctrl = mxc_vidioc_g_ctrl,
+ .vidioc_s_ctrl = mxc_vidioc_s_ctrl,
+ .vidioc_reqbufs = mxc_vidioc_reqbufs,
+ .vidioc_querybuf = mxc_vidioc_querybuf,
+ .vidioc_qbuf = mxc_vidioc_qbuf,
+ .vidioc_dqbuf = mxc_vidioc_dqbuf,
+ .vidioc_streamon = mxc_vidioc_streamon,
+ .vidioc_streamoff = mxc_vidioc_streamoff,
+};
+
+static const struct v4l2_file_operations mxc_vout_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = mxc_vout_ioctl,
+ .mmap = mxc_vout_mmap,
+ .open = mxc_vout_open,
+ .release = mxc_vout_release,
+};
+
+static struct video_device mxc_vout_template = {
+ .name = "MXC Video Output",
+ .fops = &mxc_vout_fops,
+ .ioctl_ops = &mxc_vout_ioctl_ops,
+ .release = video_device_release,
+};
+
+static struct videobuf_queue_ops mxc_vout_vbq_ops = {
+ .buf_setup = mxc_vout_buffer_setup,
+ .buf_prepare = mxc_vout_buffer_prepare,
+ .buf_release = mxc_vout_buffer_release,
+ .buf_queue = mxc_vout_buffer_queue,
+};
+
+static void mxc_vout_free_output(struct mxc_vout_dev *dev)
+{
+ int i;
+ int j;
+ struct mxc_vout_output *vout;
+ struct video_device *vfd;
+
+ for (i = 0; i < dev->out_num; i++) {
+ vout = dev->out[i];
+ vfd = vout->vfd;
+ if (vout->vdoa_work.vaddr)
+ free_dma_buf(vout, &vout->vdoa_work);
+ for (j = 0; j < VDOA_FB_BUFS; j++) {
+ if (vout->vdoa_output[j].vaddr)
+ free_dma_buf(vout, &vout->vdoa_output[j]);
+ }
+ if (vfd) {
+ if (!video_is_registered(vfd))
+ video_device_release(vfd);
+ else
+ video_unregister_device(vfd);
+ }
+ kfree(vout);
+ }
+}
+
+static int mxc_vout_setup_output(struct mxc_vout_dev *dev)
+{
+ struct videobuf_queue *q;
+ struct fb_info *fbi;
+ struct mxc_vout_output *vout;
+ int i, ret = 0;
+
+ update_display_setting();
+
+ /* all output/overlay based on fb */
+ for (i = 0; i < num_registered_fb; i++) {
+ fbi = registered_fb[i];
+
+ vout = kzalloc(sizeof(struct mxc_vout_output), GFP_KERNEL);
+ if (!vout) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ dev->out[dev->out_num] = vout;
+ dev->out_num++;
+
+ vout->fbi = fbi;
+ vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ vout->vfd = video_device_alloc();
+ if (!vout->vfd) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ *vout->vfd = mxc_vout_template;
+ vout->vfd->v4l2_dev = &dev->v4l2_dev;
+ vout->vfd->lock = &vout->mutex;
+ vout->vfd->vfl_dir = VFL_DIR_TX;
+
+ mutex_init(&vout->mutex);
+ mutex_init(&vout->task_lock);
+ mutex_init(&vout->accs_lock);
+
+ strlcpy(vout->vfd->name, fbi->fix.id, sizeof(vout->vfd->name));
+
+ video_set_drvdata(vout->vfd, vout);
+
+ if (video_register_device(vout->vfd,
+ VFL_TYPE_GRABBER, video_nr + i) < 0) {
+ ret = -ENODEV;
+ break;
+ }
+
+ q = &vout->vbq;
+ q->dev = dev->dev;
+ spin_lock_init(&vout->vbq_lock);
+ videobuf_queue_dma_contig_init(q, &mxc_vout_vbq_ops, q->dev,
+ &vout->vbq_lock, vout->type, V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), vout, NULL);
+
+ v4l2_info(vout->vfd->v4l2_dev, "V4L2 device registered as %s\n",
+ video_device_node_name(vout->vfd));
+
+ }
+
+ return ret;
+}
+
+static int mxc_vout_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct mxc_vout_dev *dev;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->dev = &pdev->dev;
+ dev->dev->dma_mask = kmalloc(sizeof(*dev->dev->dma_mask), GFP_KERNEL);
+ *dev->dev->dma_mask = DMA_BIT_MASK(32);
+ dev->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ ret = v4l2_device_register(dev->dev, &dev->v4l2_dev);
+ if (ret) {
+ dev_err(dev->dev, "v4l2_device_register failed\n");
+ goto free_dev;
+ }
+
+ ret = mxc_vout_setup_output(dev);
+ if (ret < 0)
+ goto rel_vdev;
+
+ return 0;
+
+rel_vdev:
+ mxc_vout_free_output(dev);
+ v4l2_device_unregister(&dev->v4l2_dev);
+free_dev:
+ kfree(dev);
+ return ret;
+}
+
+static int mxc_vout_remove(struct platform_device *pdev)
+{
+ struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
+ struct mxc_vout_dev *dev = container_of(v4l2_dev, struct
+ mxc_vout_dev, v4l2_dev);
+
+ mxc_vout_free_output(dev);
+ v4l2_device_unregister(v4l2_dev);
+ kfree(dev);
+ return 0;
+}
+
+static const struct of_device_id mxc_v4l2_dt_ids[] = {
+ { .compatible = "fsl,mxc_v4l2_output", },
+ { /* sentinel */ }
+};
+
+static struct platform_driver mxc_vout_driver = {
+ .driver = {
+ .name = "mxc_v4l2_output",
+ .of_match_table = mxc_v4l2_dt_ids,
+ },
+ .probe = mxc_vout_probe,
+ .remove = mxc_vout_remove,
+};
+
+static int __init mxc_vout_init(void)
+{
+ if (platform_driver_register(&mxc_vout_driver) != 0) {
+ printk(KERN_ERR VOUT_NAME ":Could not register Video driver\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void mxc_vout_cleanup(void)
+{
+ platform_driver_unregister(&mxc_vout_driver);
+}
+
+module_init(mxc_vout_init);
+module_exit(mxc_vout_cleanup);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("V4L2-driver for MXC video output");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c
index 271f725b17e8..1ed7a15dd360 100644
--- a/drivers/media/radio/radio-si476x.c
+++ b/drivers/media/radio/radio-si476x.c
@@ -775,7 +775,8 @@ static int si476x_radio_s_hw_freq_seek(struct file *file, void *priv,
rangelow = si476x_to_v4l2(radio->core, rangelow);
else
goto unlock;
- }
+ } else
+ rangelow = seek->rangelow;
if (!seek->rangehigh) {
err = regmap_read(radio->core->regmap,
SI476X_PROP_SEEK_BAND_TOP,
@@ -784,7 +785,8 @@ static int si476x_radio_s_hw_freq_seek(struct file *file, void *priv,
rangehigh = si476x_to_v4l2(radio->core, rangehigh);
else
goto unlock;
- }
+ } else
+ rangehigh = seek->rangehigh;
if (rangelow > rangehigh) {
err = -EINVAL;
@@ -1008,6 +1010,14 @@ static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl)
}
break;
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->val)
+ retval = regmap_write(radio->core->regmap,
+ SI476X_PROP_AUDIO_MUTE, 3);
+ else
+ retval = regmap_write(radio->core->regmap,
+ SI476X_PROP_AUDIO_MUTE, 0);
+ break;
default:
retval = -EINVAL;
break;
@@ -1527,6 +1537,16 @@ static int si476x_radio_probe(struct platform_device *pdev)
goto exit;
}
+ ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &si476x_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE,
+ 0, 1, 1, 0);
+ rval = radio->ctrl_handler.error;
+ if (ctrl == NULL && rval) {
+ dev_err(&pdev->dev, "Could not initialize V4L2_CID_AUDIO_MUTE control %d\n",
+ rval);
+ goto exit;
+ }
+
if (si476x_core_has_diversity(radio->core)) {
si476x_ctrls[SI476X_IDX_DIVERSITY_MODE].def =
si476x_phase_diversity_mode_to_idx(radio->core->diversity_mode);
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 5bada202b2d3..76996b516406 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -220,7 +220,14 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
v4l2_async_cleanup(sd);
/* If we handled USB devices, we'd have to lock the parent too */
+ /*
+ * If anyone calls v4l2_async_notifier_unregister() recursively from
+ * device_release_driver(), code will deadlock at list_lock,
+ * so unlock list_lock when device_release_driver() called.
+ */
+ mutex_unlock(&list_lock);
device_release_driver(d);
+ mutex_lock(&list_lock);
if (notifier->unbind)
notifier->unbind(notifier, sd, sd->asd);
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 8be561ab2615..206cff6b0c97 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -360,6 +360,34 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
if (lock)
mutex_unlock(lock);
+ } else if (vdev->fops->ioctl) {
+ /* This code path is a replacement for the BKL. It is a major
+ * hack but it will have to do for those drivers that are not
+ * yet converted to use unlocked_ioctl.
+ *
+ * All drivers implement struct v4l2_device, so we use the
+ * lock defined there to serialize the ioctls.
+ *
+ * However, if the driver sleeps, then it blocks all ioctls
+ * since the lock is still held. This is very common for
+ * VIDIOC_DQBUF since that normally waits for a frame to arrive.
+ * As a result any other ioctl calls will proceed very, very
+ * slowly since each call will have to wait for the VIDIOC_QBUF
+ * to finish. Things that should take 0.01s may now take 10-20
+ * seconds.
+ *
+ * The workaround is to *not* take the lock for VIDIOC_DQBUF.
+ * This actually works OK for videobuf-based drivers, since
+ * videobuf will take its own internal lock.
+ */
+ struct mutex *m = &vdev->v4l2_dev->ioctl_lock;
+
+ if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m))
+ return -ERESTARTSYS;
+ if (video_is_registered(vdev))
+ ret = vdev->fops->ioctl(filp, cmd, arg);
+ if (cmd != VIDIOC_DQBUF)
+ mutex_unlock(m);
} else
ret = -ENOTTY;
@@ -567,6 +595,7 @@ static void determine_valid_ioctls(struct video_device *vdev)
set_bit(_IOC_NR(VIDIOC_DBG_G_REGISTER), valid_ioctls);
set_bit(_IOC_NR(VIDIOC_DBG_S_REGISTER), valid_ioctls);
#endif
+ SET_VALID_IOCTL(ops, VIDIOC_DBG_G_CHIP_IDENT, vidioc_g_chip_ident);
/* yes, really vidioc_subscribe_event */
SET_VALID_IOCTL(ops, VIDIOC_DQEVENT, vidioc_subscribe_event);
SET_VALID_IOCTL(ops, VIDIOC_SUBSCRIBE_EVENT, vidioc_subscribe_event);
diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c
index 62bbed76dbbc..e4d15ee44a6d 100644
--- a/drivers/media/v4l2-core/v4l2-device.c
+++ b/drivers/media/v4l2-core/v4l2-device.c
@@ -37,6 +37,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
INIT_LIST_HEAD(&v4l2_dev->subdevs);
spin_lock_init(&v4l2_dev->lock);
+ mutex_init(&v4l2_dev->ioctl_lock);
v4l2_prio_init(&v4l2_dev->prio);
kref_init(&v4l2_dev->ref);
get_device(dev);
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 4510e8a37244..74f657b050be 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -28,6 +28,8 @@
#include <media/v4l2-device.h>
#include <media/videobuf2-v4l2.h>
#include <media/v4l2-mc.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/videobuf2-core.h>
#include <trace/events/v4l2.h>
@@ -653,6 +655,20 @@ static void v4l_print_decoder_cmd(const void *arg, bool write_only)
pr_info("pts=%llu\n", p->stop.pts);
}
+static void v4l_print_dbg_chip_ident(const void *arg, bool write_only)
+{
+ const struct v4l2_dbg_chip_ident *p = arg;
+
+ pr_cont("type=%u, ", p->match.type);
+ if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ pr_cont("name=%.*s, ",
+ (int)sizeof(p->match.name), p->match.name);
+ else
+ pr_cont("addr=%u, ", p->match.addr);
+ pr_cont("chip_ident=%u, revision=0x%x\n",
+ p->ident, p->revision);
+}
+
static void v4l_print_dbg_chip_info(const void *arg, bool write_only)
{
const struct v4l2_dbg_chip_info *p = arg;
@@ -1288,9 +1304,12 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_SE401: descr = "GSPCA SE401"; break;
case V4L2_PIX_FMT_S5C_UYVY_JPG: descr = "S5C73MX interleaved UYVY/JPEG"; break;
default:
- WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat);
- if (fmt->description[0])
+ if (!fmt->description[0])
+ WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat);
+ else {
+ pr_debug("Custom device pixelformat 0x%08x '%s'\n", fmt->pixelformat, fmt->description);
return;
+ }
flags = 0;
snprintf(fmt->description, sz, "%c%c%c%c%s",
(char)(fmt->pixelformat & 0x7f),
@@ -2312,6 +2331,18 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops,
#endif
}
+static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh, void *arg)
+{
+ struct v4l2_dbg_chip_ident *p = arg;
+
+ p->ident = V4L2_IDENT_NONE;
+ p->revision = 0;
+ if (p->match.type == V4L2_CHIP_MATCH_SUBDEV)
+ return -EINVAL;
+ return ops->vidioc_g_chip_ident(file, fh, p);
+}
+
static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
@@ -2566,6 +2597,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
IOCTL_INFO_STD(VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd, v4l_print_decoder_cmd, 0),
IOCTL_INFO_FNC(VIDIOC_DBG_S_REGISTER, v4l_dbg_s_register, v4l_print_dbg_register, 0),
IOCTL_INFO_FNC(VIDIOC_DBG_G_REGISTER, v4l_dbg_g_register, v4l_print_dbg_register, 0),
+ IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_IDENT, v4l_dbg_g_chip_ident, v4l_print_dbg_chip_ident, 0),
IOCTL_INFO_FNC(VIDIOC_S_HW_FREQ_SEEK, v4l_s_hw_freq_seek, v4l_print_hw_freq_seek, INFO_FL_PRIO),
IOCTL_INFO_STD(VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings, v4l_print_dv_timings, INFO_FL_PRIO | INFO_FL_CLEAR(v4l2_dv_timings, bt.flags)),
IOCTL_INFO_STD(VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings, v4l_print_dv_timings, 0),
diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c
index def84753c4c3..793a281d0dc2 100644
--- a/drivers/media/v4l2-core/videobuf-core.c
+++ b/drivers/media/v4l2-core/videobuf-core.c
@@ -594,6 +594,13 @@ int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b)
buf->baddr != b->m.userptr)
q->ops->buf_release(q, buf);
buf->baddr = b->m.userptr;
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT
+ || q->type == V4L2_BUF_TYPE_VBI_OUTPUT
+ || q->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT
+ || q->type == V4L2_BUF_TYPE_SDR_OUTPUT) {
+ buf->field = b->field;
+ buf->ts = b->timestamp;
+ }
break;
case V4L2_MEMORY_OVERLAY:
buf->boff = b->m.offset;
diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c
index aacf584f2a42..f3512404bc52 100644
--- a/drivers/memstick/core/ms_block.c
+++ b/drivers/memstick/core/ms_block.c
@@ -2006,7 +2006,7 @@ static int msb_prepare_req(struct request_queue *q, struct request *req)
blk_dump_rq_flags(req, "MS unsupported request");
return BLKPREP_KILL;
}
- req->cmd_flags |= REQ_DONTPREP;
+ req->rq_flags |= RQF_DONTPREP;
return BLKPREP_OK;
}
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index c1472275fe57..fa0746d182ff 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -834,7 +834,7 @@ static int mspro_block_prepare_req(struct request_queue *q, struct request *req)
return BLKPREP_KILL;
}
- req->cmd_flags |= REQ_DONTPREP;
+ req->rq_flags |= RQF_DONTPREP;
return BLKPREP_OK;
}
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index c6df6442ba2b..07ab86a3a318 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -335,6 +335,27 @@ config MFD_MX25_TSADC
i.MX25 processors. They consist of a conversion queue for general
purpose ADC and a queue for Touchscreens.
+config MFD_MXC_HDMI
+ tristate "Freescale HDMI Core"
+ select MFD_CORE
+ help
+ This is the core driver for the Freescale i.MX6 on-chip HDMI.
+ This MFD driver connects with the video and audio drivers for HDMI.
+
+config MFD_PF1550
+ tristate "Freescale Semiconductor PF1550 PMIC Support"
+ depends on I2C=y
+ select MFD_CORE
+ select REGMAP_I2C
+ select REGMAP_IRQ
+ help
+ Say yes here to add support for Freescale Semiconductor PF1550.
+ This is a companion Power Management IC with regulators, ONKEY,
+ and charger control on chip.
+ This driver provides common support for accessing the device;
+ additional drivers must be enabled in order to use the functionality
+ of the device.
+
config MFD_HI6421_PMIC
tristate "HiSilicon Hi6421 PMU/Codec IC"
depends on OF
@@ -560,6 +581,14 @@ config MFD_MAX14577
additional drivers must be enabled in order to use the functionality
of the device.
+config MFD_MAX17135
+ tristate "Maxim MAX17135 EPD PMIC core"
+ depends on I2C
+
+ help
+ This is the MAX17135 PMIC support. It includes
+ core support for communication with the MAX17135 chip.
+
config MFD_MAX77620
bool "Maxim Semiconductor MAX77620 and MAX20024 PMIC Support"
depends on I2C=y
@@ -1607,6 +1636,14 @@ config MFD_STW481X
in various ST Microelectronics and ST-Ericsson embedded
Nomadik series.
+config MFD_BD71837
+ bool "BD71837 Power Management chip"
+ depends on I2C=y
+ select MFD_CORE
+ help
+ if you say yes here you get support for the BD71837
+ Power Management chips.
+
menu "Multimedia Capabilities Port drivers"
depends on ARCH_SA1100
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 9834e669d985..41d6c3edcfaf 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -94,6 +94,8 @@ obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
obj-$(CONFIG_MFD_MC13XXX_SPI) += mc13xxx-spi.o
obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o
+obj-$(CONFIG_MFD_PF1550) += pf1550.o
+
obj-$(CONFIG_MFD_CORE) += mfd-core.o
obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o
@@ -132,6 +134,7 @@ obj-$(CONFIG_MFD_DA9063) += da9063.o
obj-$(CONFIG_MFD_DA9150) += da9150-core.o
obj-$(CONFIG_MFD_MAX14577) += max14577.o
+obj-$(CONFIG_MFD_MAX17135) += max17135-core.o
obj-$(CONFIG_MFD_MAX77620) += max77620.o
obj-$(CONFIG_MFD_MAX77686) += max77686.o
obj-$(CONFIG_MFD_MAX77693) += max77693.o
@@ -204,6 +207,7 @@ obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o
obj-$(CONFIG_MFD_DLN2) += dln2.o
obj-$(CONFIG_MFD_RT5033) += rt5033.o
obj-$(CONFIG_MFD_SKY81452) += sky81452.o
+obj-$(CONFIG_MFD_MXC_HDMI) += mxc-hdmi-core.o
intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o
intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC) += intel_soc_pmic_bxtwc.o
@@ -211,3 +215,4 @@ obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
obj-$(CONFIG_MFD_MT6397) += mt6397-core.o
obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
+obj-$(CONFIG_MFD_BD71837) += bd71837.o
diff --git a/drivers/mfd/bd71837.c b/drivers/mfd/bd71837.c
new file mode 100644
index 000000000000..1f24d0784bb2
--- /dev/null
+++ b/drivers/mfd/bd71837.c
@@ -0,0 +1,308 @@
+/*
+ * @file bd71837.c -- ROHM BD71837MWV mfd driver
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * @author: cpham2403@gmail.com
+ * Copyright 2017.
+ */
+#define DEBUG
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/gpio.h>
+#include <linux/regmap.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/bd71837.h>
+
+/* Default enable debug message All Level */
+unsigned int bd71837_debug_mask = BD71837_DBG0;
+
+/** @brief bd71837 irq resource */
+static struct resource pmic_resources[] = {
+ // irq# 0
+ {
+ .start = BD71837_IRQ,
+ .end = BD71837_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+/** @brief bd71837 multi function cells */
+static struct mfd_cell bd71837_mfd_cells[] = {
+ {
+ .name = "bd71837-pmic",
+ .num_resources = ARRAY_SIZE(pmic_resources),
+ .resources = &pmic_resources[0],
+ },
+};
+
+/** @brief bd71837 irqs */
+static const struct regmap_irq bd71837_irqs[] = {
+ [BD71837_IRQ] = {
+ .mask = BD71837_INT_MASK,
+ .reg_offset = 0,
+ },
+};
+
+/** @brief bd71837 irq chip definition */
+static struct regmap_irq_chip bd71837_irq_chip = {
+ .name = "bd71837",
+ .irqs = bd71837_irqs,
+ .num_irqs = ARRAY_SIZE(bd71837_irqs),
+ .num_regs = 1,
+ .irq_reg_stride = 1,
+ .status_base = BD71837_REG_IRQ,
+ .mask_base = BD71837_REG_MIRQ,
+ .mask_invert = true,
+ // .ack_base = BD71837_REG_IRQ,
+};
+
+/** @brief bd71837 irq initialize
+ * @param bd71837 bd71837 device to init
+ * @param bdinfo platform init data
+ * @retval 0 probe success
+ * @retval negative error number
+ */
+static int bd71837_irq_init(struct bd71837 *bd71837, struct bd71837_board *bdinfo)
+{
+ int irq;
+ int ret = 0;
+
+ if (!bdinfo) {
+ dev_warn(bd71837->dev, "No interrupt support, no pdata\n");
+ return -EINVAL;
+ }
+
+ dev_info(bd71837->dev, "gpio_intr = %d \n", bdinfo->gpio_intr);
+ irq = gpio_to_irq(bdinfo->gpio_intr);
+
+ bd71837->chip_irq = irq;
+ dev_info(bd71837->dev, "chip_irq=%d \n", bd71837->chip_irq);
+ ret = regmap_add_irq_chip(bd71837->regmap, bd71837->chip_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_FALLING, bdinfo->irq_base,
+ &bd71837_irq_chip, &bd71837->irq_data);
+ if (ret < 0) {
+ dev_warn(bd71837->dev, "Failed to add irq_chip %d\n", ret);
+ }
+ return ret;
+}
+
+/** @brief bd71837 irq initialize
+ * @param bd71837 bd71837 device to init
+ * @retval 0 probe success
+ * @retval negative error number
+ */
+static int bd71837_irq_exit(struct bd71837 *bd71837)
+{
+ if (bd71837->chip_irq > 0)
+ regmap_del_irq_chip(bd71837->chip_irq, bd71837->irq_data);
+ return 0;
+}
+
+/** @brief check whether volatile register
+ * @param dev kernel device pointer
+ * @param reg register index
+ */
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ // struct bd71837 *bd71837 = dev_get_drvdata(dev);
+
+ /*
+ * Caching all regulator registers.
+ */
+ return true;
+}
+
+/** @brief regmap configures */
+static const struct regmap_config bd71837_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_reg = is_volatile_reg,
+ .max_register = BD71837_MAX_REGISTER - 1,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+#ifdef CONFIG_OF
+static struct of_device_id bd71837_of_match[] = {
+ { .compatible = "rohm,bd71837", .data = (void *)0},
+ { },
+};
+MODULE_DEVICE_TABLE(of, bd71837_of_match);
+
+
+/** @brief parse device tree data of bd71837
+ * @param client client object provided by system
+ * @param chip_id return chip id back to caller
+ * @return board initialize data
+ */
+static struct bd71837_board *bd71837_parse_dt(struct i2c_client *client,
+ int *chip_id)
+{
+ struct device_node *np = client->dev.of_node;
+ struct bd71837_board *board_info;
+ unsigned int prop;
+ const struct of_device_id *match;
+ int r = 0;
+
+ match = of_match_device(bd71837_of_match, &client->dev);
+ if (!match) {
+ dev_err(&client->dev, "Failed to find matching dt id\n");
+ return NULL;
+ }
+
+ chip_id = (int *)match->data;
+
+ board_info = devm_kzalloc(&client->dev, sizeof(*board_info),
+ GFP_KERNEL);
+ if (!board_info) {
+ dev_err(&client->dev, "Failed to allocate pdata\n");
+ return NULL;
+ }
+
+ board_info->gpio_intr = of_get_named_gpio(np, "gpio_intr", 0);
+ if (!gpio_is_valid(board_info->gpio_intr)) {
+ dev_err(&client->dev, "no pmic intr pin available\n");
+ goto err_intr;
+ }
+
+ r = of_property_read_u32(np, "irq_base", &prop);
+ if (!r) {
+ board_info->irq_base = prop;
+ } else {
+ board_info->irq_base = -1;
+ }
+
+ return board_info;
+
+err_intr:
+ devm_kfree(&client->dev, board_info);
+ return NULL;
+}
+#endif
+
+/** @brief probe bd71837 device
+ * @param i2c client object provided by system
+ * @param id chip id
+ * @retval 0 probe success
+ * @retval negative error number
+ */
+static int bd71837_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct bd71837 *bd71837;
+ struct bd71837_board *pmic_plat_data;
+ struct bd71837_board *of_pmic_plat_data = NULL;
+ int chip_id = id->driver_data;
+ int ret = 0;
+
+ pmic_plat_data = dev_get_platdata(&i2c->dev);
+
+ if (!pmic_plat_data && i2c->dev.of_node) {
+ pmic_plat_data = bd71837_parse_dt(i2c, &chip_id);
+ of_pmic_plat_data = pmic_plat_data;
+ }
+
+ if (!pmic_plat_data)
+ return -EINVAL;
+
+ bd71837 = kzalloc(sizeof(struct bd71837), GFP_KERNEL);
+ if (bd71837 == NULL)
+ return -ENOMEM;
+
+ bd71837->of_plat_data = of_pmic_plat_data;
+ i2c_set_clientdata(i2c, bd71837);
+ bd71837->dev = &i2c->dev;
+ bd71837->i2c_client = i2c;
+ bd71837->id = chip_id;
+ mutex_init(&bd71837->io_mutex);
+
+ bd71837->regmap = devm_regmap_init_i2c(i2c, &bd71837_regmap_config);
+ if (IS_ERR(bd71837->regmap)) {
+ ret = PTR_ERR(bd71837->regmap);
+ dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = bd71837_reg_read(bd71837, BD71837_REG_REV);
+ if (ret < 0) {
+ dev_err(bd71837->dev, "%s(): Read BD71837_REG_DEVICE failed!\n", __func__);
+ goto err;
+ }
+ dev_info(bd71837->dev, "Device ID=0x%X\n", ret);
+
+ bd71837_irq_init(bd71837, of_pmic_plat_data);
+
+ ret = mfd_add_devices(bd71837->dev, -1,
+ bd71837_mfd_cells, ARRAY_SIZE(bd71837_mfd_cells),
+ NULL, 0,
+ regmap_irq_get_domain(bd71837->irq_data));
+ if (ret < 0)
+ goto err;
+
+ return ret;
+
+err:
+ mfd_remove_devices(bd71837->dev);
+ kfree(bd71837);
+ return ret;
+}
+
+/** @brief remove bd71837 device
+ * @param i2c client object provided by system
+ * @return 0
+ */
+static int bd71837_i2c_remove(struct i2c_client *i2c)
+{
+ struct bd71837 *bd71837 = i2c_get_clientdata(i2c);
+
+ bd71837_irq_exit(bd71837);
+ mfd_remove_devices(bd71837->dev);
+ kfree(bd71837);
+
+ return 0;
+}
+
+static const struct i2c_device_id bd71837_i2c_id[] = {
+ { "bd71837", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, bd71837_i2c_id);
+
+static struct i2c_driver bd71837_i2c_driver = {
+ .driver = {
+ .name = "bd71837",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(bd71837_of_match),
+ },
+ .probe = bd71837_i2c_probe,
+ .remove = bd71837_i2c_remove,
+ .id_table = bd71837_i2c_id,
+};
+
+static int __init bd71837_i2c_init(void)
+{
+ return i2c_add_driver(&bd71837_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(bd71837_i2c_init);
+
+static void __exit bd71837_i2c_exit(void)
+{
+ i2c_del_driver(&bd71837_i2c_driver);
+}
+module_exit(bd71837_i2c_exit);
+
+MODULE_AUTHOR("Cong Pham <cpham2403@gmail.com>");
+MODULE_DESCRIPTION("BD71837 chip multi-function driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/max17135-core.c b/drivers/mfd/max17135-core.c
new file mode 100644
index 000000000000..f663f8068067
--- /dev/null
+++ b/drivers/mfd/max17135-core.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ *
+ */
+
+/*!
+ * @file pmic/core/max17135.c
+ * @brief This file contains MAX17135 specific PMIC code. This implementaion
+ * may differ for each PMIC chip.
+ *
+ * @ingroup PMIC_CORE
+ */
+
+/*
+ * Includes
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/uaccess.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
+#include <linux/pmic_status.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/max17135.h>
+#include <asm/mach-types.h>
+
+static int max17135_detect(struct i2c_client *client,
+ struct i2c_board_info *info);
+struct i2c_client *max17135_client;
+static struct regulator *gpio_regulator;
+
+static struct mfd_cell max17135_devs[] = {
+ { .name = "max17135-pmic", },
+ { .name = "max17135-sns", },
+};
+
+static const unsigned short normal_i2c[] = {0x48, I2C_CLIENT_END};
+
+int max17135_reg_read(int reg_num, unsigned int *reg_val)
+{
+ int result;
+
+ if (max17135_client == NULL)
+ return PMIC_ERROR;
+
+ if ((reg_num == REG_MAX17135_EXT_TEMP) ||
+ (reg_num == REG_MAX17135_INT_TEMP)) {
+ result = i2c_smbus_read_word_data(max17135_client, reg_num);
+ if (result < 0) {
+ dev_err(&max17135_client->dev,
+ "Unable to read MAX17135 register via I2C\n");
+ return PMIC_ERROR;
+ }
+ /* Swap bytes for dword read */
+ result = (result >> 8) | ((result & 0xFF) << 8);
+ } else {
+ result = i2c_smbus_read_byte_data(max17135_client, reg_num);
+ if (result < 0) {
+ dev_err(&max17135_client->dev,
+ "Unable to read MAX17135 register via I2C\n");
+ return PMIC_ERROR;
+ }
+ }
+
+ *reg_val = result;
+ return PMIC_SUCCESS;
+}
+
+int max17135_reg_write(int reg_num, const unsigned int reg_val)
+{
+ int result;
+
+ if (max17135_client == NULL)
+ return PMIC_ERROR;
+
+ result = i2c_smbus_write_byte_data(max17135_client, reg_num, reg_val);
+ if (result < 0) {
+ dev_err(&max17135_client->dev,
+ "Unable to write MAX17135 register via I2C\n");
+ return PMIC_ERROR;
+ }
+
+ return PMIC_SUCCESS;
+}
+
+#ifdef CONFIG_OF
+static struct max17135_platform_data *max17135_i2c_parse_dt_pdata(
+ struct device *dev)
+{
+ struct max17135_platform_data *pdata;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(dev, "could not allocate memory for pdata\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return pdata;
+}
+#else
+static struct max17135_platform_data *max17135_i2c_parse_dt_pdata(
+ struct device *dev)
+{
+ return NULL;
+}
+#endif /* !CONFIG_OF */
+
+static int max17135_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct max17135 *max17135;
+ struct max17135_platform_data *pdata = client->dev.platform_data;
+ struct device_node *np = client->dev.of_node;
+ int ret = 0;
+
+ if (!np)
+ return -ENODEV;
+
+ gpio_regulator = devm_regulator_get(&client->dev, "SENSOR");
+ if (!IS_ERR(gpio_regulator)) {
+ ret = regulator_enable(gpio_regulator);
+ if (ret) {
+ dev_err(&client->dev, "gpio set voltage error\n");
+ return ret;
+ }
+ }
+
+ /* Create the PMIC data structure */
+ max17135 = kzalloc(sizeof(struct max17135), GFP_KERNEL);
+ if (max17135 == NULL)
+ return -ENOMEM;
+
+ /* Initialize the PMIC data structure */
+ i2c_set_clientdata(client, max17135);
+ max17135->dev = &client->dev;
+ max17135->i2c_client = client;
+
+ max17135_client = client;
+ ret = max17135_detect(client, NULL);
+ if (ret)
+ goto err1;
+
+ mfd_add_devices(max17135->dev, -1, max17135_devs,
+ ARRAY_SIZE(max17135_devs),
+ NULL, 0, NULL);
+
+ if (max17135->dev->of_node) {
+ pdata = max17135_i2c_parse_dt_pdata(max17135->dev);
+ if (IS_ERR(pdata)) {
+ ret = PTR_ERR(pdata);
+ goto err2;
+ }
+
+ }
+ max17135->pdata = pdata;
+
+ dev_info(&client->dev, "PMIC MAX17135 for eInk display\n");
+
+ return ret;
+err2:
+ mfd_remove_devices(max17135->dev);
+err1:
+ kfree(max17135);
+
+ return ret;
+}
+
+
+static int max17135_remove(struct i2c_client *i2c)
+{
+ struct max17135 *max17135 = i2c_get_clientdata(i2c);
+
+ mfd_remove_devices(max17135->dev);
+ return 0;
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int max17135_detect(struct i2c_client *client,
+ struct i2c_board_info *info)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ u8 chip_rev, chip_id;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ /* detection */
+ if (i2c_smbus_read_byte_data(client,
+ REG_MAX17135_PRODUCT_REV) != 0) {
+ dev_err(&adapter->dev,
+ "Max17135 PMIC not found!\n");
+ return -ENODEV;
+ }
+
+ /* identification */
+ chip_rev = i2c_smbus_read_byte_data(client,
+ REG_MAX17135_PRODUCT_REV);
+ chip_id = i2c_smbus_read_byte_data(client,
+ REG_MAX17135_PRODUCT_ID);
+
+ if (chip_rev != 0x00 || chip_id != 0x4D) { /* identification failed */
+ dev_info(&adapter->dev,
+ "Unsupported chip (man_id=0x%02X, "
+ "chip_id=0x%02X).\n", chip_rev, chip_id);
+ return -ENODEV;
+ }
+
+ if (info)
+ strlcpy(info->type, "max17135_sensor", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static const struct i2c_device_id max17135_id[] = {
+ { "max17135", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max17135_id);
+
+static const struct of_device_id max17135_dt_ids[] = {
+ {
+ .compatible = "maxim,max17135",
+ .data = (void *) &max17135_id[0],
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, max17135_dt_ids);
+
+
+static struct i2c_driver max17135_driver = {
+ .driver = {
+ .name = "max17135",
+ .owner = THIS_MODULE,
+ .of_match_table = max17135_dt_ids,
+ },
+ .probe = max17135_probe,
+ .remove = max17135_remove,
+ .id_table = max17135_id,
+ .detect = max17135_detect,
+ .address_list = &normal_i2c[0],
+};
+
+static int __init max17135_init(void)
+{
+ return i2c_add_driver(&max17135_driver);
+}
+
+static void __exit max17135_exit(void)
+{
+ i2c_del_driver(&max17135_driver);
+}
+
+/*
+ * Module entry points
+ */
+subsys_initcall(max17135_init);
+module_exit(max17135_exit);
diff --git a/drivers/mfd/mxc-hdmi-core.c b/drivers/mfd/mxc-hdmi-core.c
new file mode 100644
index 000000000000..6435b3d7fd60
--- /dev/null
+++ b/drivers/mfd/mxc-hdmi-core.c
@@ -0,0 +1,821 @@
+/*
+ * Copyright (C) 2011-2016 Freescale Semiconductor, Inc.
+
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
+#include <asm/mach-types.h>
+
+#include <video/mxc_hdmi.h>
+#include <linux/ipu-v3.h>
+#include <video/mxc_edid.h>
+#include "../mxc/ipu3/ipu_prv.h"
+#include <linux/mfd/mxc-hdmi-core.h>
+#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mfd/mxc-hdmi-core.h>
+
+struct mxc_hdmi_data {
+ struct platform_device *pdev;
+ unsigned long __iomem *reg_base;
+ unsigned long reg_phys_base;
+ struct device *dev;
+};
+
+static void __iomem *hdmi_base;
+static struct clk *isfr_clk;
+static struct clk *iahb_clk;
+static struct clk *mipi_core_clk;
+static spinlock_t irq_spinlock;
+static spinlock_t edid_spinlock;
+static unsigned int sample_rate;
+static unsigned long pixel_clk_rate;
+static struct clk *pixel_clk;
+static int hdmi_ratio;
+int mxc_hdmi_ipu_id;
+int mxc_hdmi_disp_id;
+static struct mxc_edid_cfg hdmi_core_edid_cfg;
+static int hdmi_core_init;
+static unsigned int hdmi_dma_running;
+static struct snd_pcm_substream *hdmi_audio_stream_playback;
+static unsigned int hdmi_cable_state;
+static unsigned int hdmi_blank_state;
+static unsigned int hdmi_abort_state;
+static spinlock_t hdmi_audio_lock, hdmi_blank_state_lock, hdmi_cable_state_lock;
+
+unsigned int hdmi_set_cable_state(unsigned int state)
+{
+ unsigned long flags;
+ struct snd_pcm_substream *substream = hdmi_audio_stream_playback;
+
+ spin_lock_irqsave(&hdmi_cable_state_lock, flags);
+ hdmi_cable_state = state;
+ spin_unlock_irqrestore(&hdmi_cable_state_lock, flags);
+
+#ifndef CONFIG_MFD_MXC_HDMI_ANDROID
+ if (check_hdmi_state() && substream && hdmi_abort_state) {
+ hdmi_abort_state = 0;
+ substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
+ }
+#endif
+ return 0;
+}
+EXPORT_SYMBOL(hdmi_set_cable_state);
+
+unsigned int hdmi_set_blank_state(unsigned int state)
+{
+ unsigned long flags;
+ struct snd_pcm_substream *substream = hdmi_audio_stream_playback;
+
+ spin_lock_irqsave(&hdmi_blank_state_lock, flags);
+ hdmi_blank_state = state;
+ spin_unlock_irqrestore(&hdmi_blank_state_lock, flags);
+
+#ifndef CONFIG_MFD_MXC_HDMI_ANDROID
+ if (check_hdmi_state() && substream && hdmi_abort_state) {
+ hdmi_abort_state = 0;
+ substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
+ }
+#endif
+
+ return 0;
+}
+EXPORT_SYMBOL(hdmi_set_blank_state);
+
+#ifdef CONFIG_SND_SOC_IMX_HDMI_DMA
+static void hdmi_audio_abort_stream(struct snd_pcm_substream *substream)
+{
+ unsigned long flags;
+
+ snd_pcm_stream_lock_irqsave(substream, flags);
+
+#ifndef CONFIG_MFD_MXC_HDMI_ANDROID
+ if (snd_pcm_running(substream)) {
+ hdmi_abort_state = 1;
+ substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
+ }
+#else
+ if (snd_pcm_running(substream))
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
+#endif
+
+ snd_pcm_stream_unlock_irqrestore(substream, flags);
+}
+
+int mxc_hdmi_abort_stream(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&hdmi_audio_lock, flags);
+ if (hdmi_audio_stream_playback)
+ hdmi_audio_abort_stream(hdmi_audio_stream_playback);
+ spin_unlock_irqrestore(&hdmi_audio_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(mxc_hdmi_abort_stream);
+#else
+int mxc_hdmi_abort_stream(void)
+{
+ return 0;
+}
+EXPORT_SYMBOL(mxc_hdmi_abort_stream);
+#endif
+
+int check_hdmi_state(void)
+{
+ unsigned long flags1, flags2;
+ unsigned int ret;
+
+ spin_lock_irqsave(&hdmi_cable_state_lock, flags1);
+ spin_lock_irqsave(&hdmi_blank_state_lock, flags2);
+
+ ret = hdmi_cable_state && hdmi_blank_state;
+
+ spin_unlock_irqrestore(&hdmi_blank_state_lock, flags2);
+ spin_unlock_irqrestore(&hdmi_cable_state_lock, flags1);
+
+ return ret;
+}
+EXPORT_SYMBOL(check_hdmi_state);
+
+#ifdef CONFIG_SND_SOC_IMX_HDMI_DMA
+int mxc_hdmi_register_audio(struct snd_pcm_substream *substream)
+{
+ unsigned long flags, flags1;
+ int ret = 0;
+
+ if (!substream)
+ return -EINVAL;
+
+ snd_pcm_stream_lock_irqsave(substream, flags);
+
+ if (check_hdmi_state()) {
+ spin_lock_irqsave(&hdmi_audio_lock, flags1);
+ if (hdmi_audio_stream_playback) {
+ pr_err("%s unconsist hdmi auido stream!\n", __func__);
+ ret = -EINVAL;
+ }
+ hdmi_audio_stream_playback = substream;
+ hdmi_abort_state = 0;
+ spin_unlock_irqrestore(&hdmi_audio_lock, flags1);
+ } else
+ ret = -EINVAL;
+
+ snd_pcm_stream_unlock_irqrestore(substream, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(mxc_hdmi_register_audio);
+#endif
+
+void mxc_hdmi_unregister_audio(struct snd_pcm_substream *substream)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&hdmi_audio_lock, flags);
+ hdmi_audio_stream_playback = NULL;
+ hdmi_abort_state = 0;
+ spin_unlock_irqrestore(&hdmi_audio_lock, flags);
+}
+EXPORT_SYMBOL(mxc_hdmi_unregister_audio);
+
+u8 hdmi_readb(unsigned int reg)
+{
+ u8 value;
+
+ value = __raw_readb(hdmi_base + reg);
+
+ return value;
+}
+EXPORT_SYMBOL(hdmi_readb);
+
+#ifdef DEBUG
+static bool overflow_lo;
+static bool overflow_hi;
+
+bool hdmi_check_overflow(void)
+{
+ u8 val, lo, hi;
+
+ val = hdmi_readb(HDMI_IH_FC_STAT2);
+ lo = (val & HDMI_IH_FC_STAT2_LOW_PRIORITY_OVERFLOW) != 0;
+ hi = (val & HDMI_IH_FC_STAT2_HIGH_PRIORITY_OVERFLOW) != 0;
+
+ if ((lo != overflow_lo) || (hi != overflow_hi)) {
+ pr_debug("%s LowPriority=%d HighPriority=%d <=======================\n",
+ __func__, lo, hi);
+ overflow_lo = lo;
+ overflow_hi = hi;
+ return true;
+ }
+ return false;
+}
+#else
+bool hdmi_check_overflow(void)
+{
+ return false;
+}
+#endif
+EXPORT_SYMBOL(hdmi_check_overflow);
+
+void hdmi_writeb(u8 value, unsigned int reg)
+{
+ hdmi_check_overflow();
+ __raw_writeb(value, hdmi_base + reg);
+ hdmi_check_overflow();
+}
+EXPORT_SYMBOL(hdmi_writeb);
+
+void hdmi_mask_writeb(u8 data, unsigned int reg, u8 shift, u8 mask)
+{
+ u8 value = hdmi_readb(reg) & ~mask;
+ value |= (data << shift) & mask;
+ hdmi_writeb(value, reg);
+}
+EXPORT_SYMBOL(hdmi_mask_writeb);
+
+unsigned int hdmi_read4(unsigned int reg)
+{
+ /* read a four byte address from registers */
+ return (hdmi_readb(reg + 3) << 24) |
+ (hdmi_readb(reg + 2) << 16) |
+ (hdmi_readb(reg + 1) << 8) |
+ hdmi_readb(reg);
+}
+EXPORT_SYMBOL(hdmi_read4);
+
+void hdmi_write4(unsigned int value, unsigned int reg)
+{
+ /* write a four byte address to hdmi regs */
+ hdmi_writeb(value & 0xff, reg);
+ hdmi_writeb((value >> 8) & 0xff, reg + 1);
+ hdmi_writeb((value >> 16) & 0xff, reg + 2);
+ hdmi_writeb((value >> 24) & 0xff, reg + 3);
+}
+EXPORT_SYMBOL(hdmi_write4);
+
+static void initialize_hdmi_ih_mutes(void)
+{
+ u8 ih_mute;
+
+ /*
+ * Boot up defaults are:
+ * HDMI_IH_MUTE = 0x03 (disabled)
+ * HDMI_IH_MUTE_* = 0x00 (enabled)
+ */
+
+ /* Disable top level interrupt bits in HDMI block */
+ ih_mute = hdmi_readb(HDMI_IH_MUTE) |
+ HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
+ HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
+
+ hdmi_writeb(ih_mute, HDMI_IH_MUTE);
+
+ /* by default mask all interrupts */
+ hdmi_writeb(0xff, HDMI_VP_MASK);
+ hdmi_writeb(0xff, HDMI_FC_MASK0);
+ hdmi_writeb(0xff, HDMI_FC_MASK1);
+ hdmi_writeb(0xff, HDMI_FC_MASK2);
+ hdmi_writeb(0xff, HDMI_PHY_MASK0);
+ hdmi_writeb(0xff, HDMI_PHY_I2CM_INT_ADDR);
+ hdmi_writeb(0xff, HDMI_PHY_I2CM_CTLINT_ADDR);
+ hdmi_writeb(0xff, HDMI_AUD_INT);
+ hdmi_writeb(0xff, HDMI_AUD_SPDIFINT);
+ hdmi_writeb(0xff, HDMI_AUD_HBR_MASK);
+ hdmi_writeb(0xff, HDMI_GP_MASK);
+ hdmi_writeb(0xff, HDMI_A_APIINTMSK);
+ hdmi_writeb(0xff, HDMI_CEC_MASK);
+ hdmi_writeb(0xff, HDMI_I2CM_INT);
+ hdmi_writeb(0xff, HDMI_I2CM_CTLINT);
+
+ /* Disable interrupts in the IH_MUTE_* registers */
+ hdmi_writeb(0xff, HDMI_IH_MUTE_FC_STAT0);
+ hdmi_writeb(0xff, HDMI_IH_MUTE_FC_STAT1);
+ hdmi_writeb(0xff, HDMI_IH_MUTE_FC_STAT2);
+ hdmi_writeb(0xff, HDMI_IH_MUTE_AS_STAT0);
+ hdmi_writeb(0xff, HDMI_IH_MUTE_PHY_STAT0);
+ hdmi_writeb(0xff, HDMI_IH_MUTE_I2CM_STAT0);
+ hdmi_writeb(0xff, HDMI_IH_MUTE_CEC_STAT0);
+ hdmi_writeb(0xff, HDMI_IH_MUTE_VP_STAT0);
+ hdmi_writeb(0xff, HDMI_IH_MUTE_I2CMPHY_STAT0);
+ hdmi_writeb(0xff, HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+
+ /* Enable top level interrupt bits in HDMI block */
+ ih_mute &= ~(HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
+ HDMI_IH_MUTE_MUTE_ALL_INTERRUPT);
+ hdmi_writeb(ih_mute, HDMI_IH_MUTE);
+}
+
+static void hdmi_set_clock_regenerator_n(unsigned int value)
+{
+ u8 val;
+
+ if (!hdmi_dma_running) {
+ hdmi_writeb(value & 0xff, HDMI_AUD_N1);
+ hdmi_writeb(0, HDMI_AUD_N2);
+ hdmi_writeb(0, HDMI_AUD_N3);
+ }
+
+ hdmi_writeb(value & 0xff, HDMI_AUD_N1);
+ hdmi_writeb((value >> 8) & 0xff, HDMI_AUD_N2);
+ hdmi_writeb((value >> 16) & 0x0f, HDMI_AUD_N3);
+
+ /* nshift factor = 0 */
+ val = hdmi_readb(HDMI_AUD_CTS3);
+ val &= ~HDMI_AUD_CTS3_N_SHIFT_MASK;
+ hdmi_writeb(val, HDMI_AUD_CTS3);
+}
+
+static void hdmi_set_clock_regenerator_cts(unsigned int cts)
+{
+ u8 val;
+
+ if (!hdmi_dma_running) {
+ hdmi_writeb(cts & 0xff, HDMI_AUD_CTS1);
+ hdmi_writeb(0, HDMI_AUD_CTS2);
+ hdmi_writeb(0, HDMI_AUD_CTS3);
+ }
+
+ /* Must be set/cleared first */
+ val = hdmi_readb(HDMI_AUD_CTS3);
+ val &= ~HDMI_AUD_CTS3_CTS_MANUAL;
+ hdmi_writeb(val, HDMI_AUD_CTS3);
+
+ hdmi_writeb(cts & 0xff, HDMI_AUD_CTS1);
+ hdmi_writeb((cts >> 8) & 0xff, HDMI_AUD_CTS2);
+ hdmi_writeb(((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
+ HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
+}
+
+static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk,
+ unsigned int ratio)
+{
+ unsigned int n = (128 * freq) / 1000;
+
+ switch (freq) {
+ case 32000:
+ if (pixel_clk == 25174000)
+ n = (ratio == 150) ? 9152 : 4576;
+ else if (pixel_clk == 27020000)
+ n = (ratio == 150) ? 8192 : 4096;
+ else if (pixel_clk == 74170000 || pixel_clk == 148350000)
+ n = 11648;
+ else if (pixel_clk == 297000000)
+ n = (ratio == 150) ? 6144 : 3072;
+ else
+ n = 4096;
+ break;
+
+ case 44100:
+ if (pixel_clk == 25174000)
+ n = 7007;
+ else if (pixel_clk == 74170000)
+ n = 17836;
+ else if (pixel_clk == 148350000)
+ n = (ratio == 150) ? 17836 : 8918;
+ else if (pixel_clk == 297000000)
+ n = (ratio == 150) ? 9408 : 4704;
+ else
+ n = 6272;
+ break;
+
+ case 48000:
+ if (pixel_clk == 25174000)
+ n = (ratio == 150) ? 9152 : 6864;
+ else if (pixel_clk == 27020000)
+ n = (ratio == 150) ? 8192 : 6144;
+ else if (pixel_clk == 74170000)
+ n = 11648;
+ else if (pixel_clk == 148350000)
+ n = (ratio == 150) ? 11648 : 5824;
+ else if (pixel_clk == 297000000)
+ n = (ratio == 150) ? 10240 : 5120;
+ else
+ n = 6144;
+ break;
+
+ case 88200:
+ n = hdmi_compute_n(44100, pixel_clk, ratio) * 2;
+ break;
+
+ case 96000:
+ n = hdmi_compute_n(48000, pixel_clk, ratio) * 2;
+ break;
+
+ case 176400:
+ n = hdmi_compute_n(44100, pixel_clk, ratio) * 4;
+ break;
+
+ case 192000:
+ n = hdmi_compute_n(48000, pixel_clk, ratio) * 4;
+ break;
+
+ default:
+ break;
+ }
+
+ return n;
+}
+
+static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
+ unsigned int ratio)
+{
+ unsigned int cts = 0;
+ switch (freq) {
+ case 32000:
+ if (pixel_clk == 297000000) {
+ cts = 222750;
+ break;
+ } else if (pixel_clk == 25174000) {
+ cts = 28125;
+ break;
+ }
+ case 48000:
+ case 96000:
+ case 192000:
+ switch (pixel_clk) {
+ case 25200000:
+ case 27000000:
+ case 54000000:
+ case 74250000:
+ case 148500000:
+ cts = pixel_clk / 1000;
+ break;
+ case 297000000:
+ cts = 247500;
+ break;
+ case 25174000:
+ cts = 28125l;
+ break;
+ /*
+ * All other TMDS clocks are not supported by
+ * DWC_hdmi_tx. The TMDS clocks divided or
+ * multiplied by 1,001 coefficients are not
+ * supported.
+ */
+ default:
+ break;
+ }
+ break;
+ case 44100:
+ case 88200:
+ case 176400:
+ switch (pixel_clk) {
+ case 25200000:
+ cts = 28000;
+ break;
+ case 25174000:
+ cts = 31250;
+ break;
+ case 27000000:
+ cts = 30000;
+ break;
+ case 54000000:
+ cts = 60000;
+ break;
+ case 74250000:
+ cts = 82500;
+ break;
+ case 148500000:
+ cts = 165000;
+ break;
+ case 297000000:
+ cts = 247500;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ if (ratio == 100)
+ return cts;
+ else
+ return (cts * ratio) / 100;
+}
+
+static void hdmi_set_clk_regenerator(void)
+{
+ unsigned int clk_n, clk_cts;
+
+ clk_n = hdmi_compute_n(sample_rate, pixel_clk_rate, hdmi_ratio);
+ clk_cts = hdmi_compute_cts(sample_rate, pixel_clk_rate, hdmi_ratio);
+
+ if (clk_cts == 0) {
+ pr_debug("%s: pixel clock not supported: %d\n",
+ __func__, (int)pixel_clk_rate);
+ return;
+ }
+
+ pr_debug("%s: samplerate=%d ratio=%d pixelclk=%d N=%d cts=%d\n",
+ __func__, sample_rate, hdmi_ratio, (int)pixel_clk_rate,
+ clk_n, clk_cts);
+
+ hdmi_set_clock_regenerator_cts(clk_cts);
+ hdmi_set_clock_regenerator_n(clk_n);
+}
+
+static int hdmi_core_get_of_property(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int err;
+ int ipu_id, disp_id;
+
+ err = of_property_read_u32(np, "ipu_id", &ipu_id);
+ if (err) {
+ dev_dbg(&pdev->dev, "get of property ipu_id fail\n");
+ return err;
+ }
+ err = of_property_read_u32(np, "disp_id", &disp_id);
+ if (err) {
+ dev_dbg(&pdev->dev, "get of property disp_id fail\n");
+ return err;
+ }
+
+ mxc_hdmi_ipu_id = ipu_id;
+ mxc_hdmi_disp_id = disp_id;
+
+ return err;
+}
+
+/* Need to run this before phy is enabled the first time to prevent
+ * overflow condition in HDMI_IH_FC_STAT2 */
+void hdmi_init_clk_regenerator(void)
+{
+ if (pixel_clk_rate == 0) {
+ pixel_clk_rate = 74250000;
+ hdmi_set_clk_regenerator();
+ }
+}
+EXPORT_SYMBOL(hdmi_init_clk_regenerator);
+
+void hdmi_clk_regenerator_update_pixel_clock(u32 pixclock)
+{
+
+ if (!pixclock)
+ return;
+ /* Translate pixel clock in ps (pico seconds) to Hz */
+ pixel_clk_rate = PICOS2KHZ(pixclock) * 1000UL;
+ hdmi_set_clk_regenerator();
+}
+EXPORT_SYMBOL(hdmi_clk_regenerator_update_pixel_clock);
+
+void hdmi_set_dma_mode(unsigned int dma_running)
+{
+ hdmi_dma_running = dma_running;
+ hdmi_set_clk_regenerator();
+}
+EXPORT_SYMBOL(hdmi_set_dma_mode);
+
+void hdmi_set_sample_rate(unsigned int rate)
+{
+ sample_rate = rate;
+}
+EXPORT_SYMBOL(hdmi_set_sample_rate);
+
+void hdmi_set_edid_cfg(struct mxc_edid_cfg *cfg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&edid_spinlock, flags);
+ memcpy(&hdmi_core_edid_cfg, cfg, sizeof(struct mxc_edid_cfg));
+ spin_unlock_irqrestore(&edid_spinlock, flags);
+}
+EXPORT_SYMBOL(hdmi_set_edid_cfg);
+
+void hdmi_get_edid_cfg(struct mxc_edid_cfg *cfg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&edid_spinlock, flags);
+ memcpy(cfg, &hdmi_core_edid_cfg, sizeof(struct mxc_edid_cfg));
+ spin_unlock_irqrestore(&edid_spinlock, flags);
+}
+EXPORT_SYMBOL(hdmi_get_edid_cfg);
+
+void hdmi_set_registered(int registered)
+{
+ hdmi_core_init = registered;
+}
+EXPORT_SYMBOL(hdmi_set_registered);
+
+int hdmi_get_registered(void)
+{
+ return hdmi_core_init;
+}
+EXPORT_SYMBOL(hdmi_get_registered);
+
+static int mxc_hdmi_core_probe(struct platform_device *pdev)
+{
+ struct mxc_hdmi_data *hdmi_data;
+ struct resource *res;
+ unsigned long flags;
+ int ret = 0;
+
+#ifdef DEBUG
+ overflow_lo = false;
+ overflow_hi = false;
+#endif
+
+ hdmi_core_init = 0;
+ hdmi_dma_running = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOENT;
+
+ ret = hdmi_core_get_of_property(pdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "get hdmi of property fail\n");
+ return -ENOENT;
+ }
+
+ hdmi_data = devm_kzalloc(&pdev->dev, sizeof(struct mxc_hdmi_data), GFP_KERNEL);
+ if (!hdmi_data) {
+ dev_err(&pdev->dev, "Couldn't allocate mxc hdmi mfd device\n");
+ return -ENOMEM;
+ }
+ hdmi_data->pdev = pdev;
+
+ pixel_clk = NULL;
+ sample_rate = 48000;
+ pixel_clk_rate = 0;
+ hdmi_ratio = 100;
+
+ spin_lock_init(&irq_spinlock);
+ spin_lock_init(&edid_spinlock);
+
+
+ spin_lock_init(&hdmi_cable_state_lock);
+ spin_lock_init(&hdmi_blank_state_lock);
+ spin_lock_init(&hdmi_audio_lock);
+
+ spin_lock_irqsave(&hdmi_cable_state_lock, flags);
+ hdmi_cable_state = 0;
+ spin_unlock_irqrestore(&hdmi_cable_state_lock, flags);
+
+ spin_lock_irqsave(&hdmi_blank_state_lock, flags);
+ hdmi_blank_state = 0;
+ spin_unlock_irqrestore(&hdmi_blank_state_lock, flags);
+
+ spin_lock_irqsave(&hdmi_audio_lock, flags);
+ hdmi_audio_stream_playback = NULL;
+ hdmi_abort_state = 0;
+ spin_unlock_irqrestore(&hdmi_audio_lock, flags);
+
+ mipi_core_clk = clk_get(&hdmi_data->pdev->dev, "mipi_core");
+ if (IS_ERR(mipi_core_clk)) {
+ ret = PTR_ERR(mipi_core_clk);
+ dev_err(&hdmi_data->pdev->dev,
+ "Unable to get mipi core clk: %d\n", ret);
+ goto eclkg;
+ }
+
+ ret = clk_prepare_enable(mipi_core_clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Cannot enable mipi core clock: %d\n", ret);
+ goto eclke;
+ }
+
+ isfr_clk = clk_get(&hdmi_data->pdev->dev, "hdmi_isfr");
+ if (IS_ERR(isfr_clk)) {
+ ret = PTR_ERR(isfr_clk);
+ dev_err(&hdmi_data->pdev->dev,
+ "Unable to get HDMI isfr clk: %d\n", ret);
+ goto eclkg1;
+ }
+
+ ret = clk_prepare_enable(isfr_clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Cannot enable HDMI clock: %d\n", ret);
+ goto eclke1;
+ }
+
+ pr_debug("%s isfr_clk:%d\n", __func__,
+ (int)clk_get_rate(isfr_clk));
+
+ iahb_clk = clk_get(&hdmi_data->pdev->dev, "hdmi_iahb");
+ if (IS_ERR(iahb_clk)) {
+ ret = PTR_ERR(iahb_clk);
+ dev_err(&hdmi_data->pdev->dev,
+ "Unable to get HDMI iahb clk: %d\n", ret);
+ goto eclkg2;
+ }
+
+ ret = clk_prepare_enable(iahb_clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Cannot enable HDMI clock: %d\n", ret);
+ goto eclke2;
+ }
+
+ hdmi_data->reg_phys_base = res->start;
+ if (!request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev))) {
+ dev_err(&pdev->dev, "request_mem_region failed\n");
+ ret = -EBUSY;
+ goto emem;
+ }
+
+ hdmi_data->reg_base = ioremap(res->start, resource_size(res));
+ if (!hdmi_data->reg_base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto eirq;
+ }
+ hdmi_base = hdmi_data->reg_base;
+
+ pr_debug("\n%s hdmi hw base = 0x%08x\n\n", __func__, (int)res->start);
+
+ initialize_hdmi_ih_mutes();
+
+ /* Disable HDMI clocks until video/audio sub-drivers are initialized */
+ clk_disable_unprepare(isfr_clk);
+ clk_disable_unprepare(iahb_clk);
+ clk_disable_unprepare(mipi_core_clk);
+
+ /* Replace platform data coming in with a local struct */
+ platform_set_drvdata(pdev, hdmi_data);
+
+ return ret;
+
+eirq:
+ release_mem_region(res->start, resource_size(res));
+emem:
+ clk_disable_unprepare(iahb_clk);
+eclke2:
+ clk_put(iahb_clk);
+eclkg2:
+ clk_disable_unprepare(isfr_clk);
+eclke1:
+ clk_put(isfr_clk);
+eclkg1:
+ clk_disable_unprepare(mipi_core_clk);
+eclke:
+ clk_put(mipi_core_clk);
+eclkg:
+ return ret;
+}
+
+
+static int __exit mxc_hdmi_core_remove(struct platform_device *pdev)
+{
+ struct mxc_hdmi_data *hdmi_data = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ iounmap(hdmi_data->reg_base);
+ release_mem_region(res->start, resource_size(res));
+
+ return 0;
+}
+
+static const struct of_device_id imx_hdmi_dt_ids[] = {
+ { .compatible = "fsl,imx6q-hdmi-core", },
+ { .compatible = "fsl,imx6dl-hdmi-core", },
+ { /* sentinel */ }
+};
+
+static struct platform_driver mxc_hdmi_core_driver = {
+ .driver = {
+ .name = "mxc_hdmi_core",
+ .of_match_table = imx_hdmi_dt_ids,
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(mxc_hdmi_core_remove),
+};
+
+static int __init mxc_hdmi_core_init(void)
+{
+ return platform_driver_probe(&mxc_hdmi_core_driver,
+ mxc_hdmi_core_probe);
+}
+
+static void __exit mxc_hdmi_core_exit(void)
+{
+ platform_driver_unregister(&mxc_hdmi_core_driver);
+}
+
+subsys_initcall(mxc_hdmi_core_init);
+module_exit(mxc_hdmi_core_exit);
+
+MODULE_DESCRIPTION("Core driver for Freescale i.Mx on-chip HDMI");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/pf1550.c b/drivers/mfd/pf1550.c
new file mode 100644
index 000000000000..44c92f466a99
--- /dev/null
+++ b/drivers/mfd/pf1550.c
@@ -0,0 +1,311 @@
+/*
+ * pf1550.c - mfd core driver for the PF1550
+ *
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Robin Gong <yibin.gong@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * This driver is based on max77693.c
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/pf1550.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+static const struct mfd_cell pf1550_devs[] = {
+ {
+ .name = "pf1550-regulator",
+ .of_compatible = "fsl,pf1550-regulator",
+ },
+ {
+ .name = "pf1550-onkey",
+ .of_compatible = "fsl,pf1550-onkey",
+ },
+ {
+ .name = "pf1550-charger",
+ .of_compatible = "fsl,pf1550-charger",
+ },
+};
+
+static const struct regmap_config pf1550_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = PF1550_PMIC_REG_END,
+};
+
+static const struct regmap_irq pf1550_regulator_irqs[] = {
+ { .reg_offset = 0, .mask = PMIC_IRQ_SW1_LS, },
+ { .reg_offset = 0, .mask = PMIC_IRQ_SW2_LS, },
+ { .reg_offset = 0, .mask = PMIC_IRQ_SW3_LS, },
+
+ { .reg_offset = 3, .mask = PMIC_IRQ_SW1_HS, },
+ { .reg_offset = 3, .mask = PMIC_IRQ_SW2_HS, },
+ { .reg_offset = 3, .mask = PMIC_IRQ_SW3_HS, },
+
+ { .reg_offset = 16, .mask = PMIC_IRQ_LDO1_FAULT, },
+ { .reg_offset = 16, .mask = PMIC_IRQ_LDO2_FAULT, },
+ { .reg_offset = 16, .mask = PMIC_IRQ_LDO3_FAULT, },
+
+ { .reg_offset = 22, .mask = PMIC_IRQ_TEMP_110, },
+ { .reg_offset = 22, .mask = PMIC_IRQ_TEMP_125, },
+};
+
+static const struct regmap_irq_chip pf1550_regulator_irq_chip = {
+ .name = "pf1550-regulator",
+ .status_base = PF1550_PMIC_REG_SW_INT_STAT0,
+ .mask_base = PF1550_PMIC_REG_SW_INT_MASK0,
+ .mask_invert = false,
+ .num_regs = 23,
+ .irqs = pf1550_regulator_irqs,
+ .num_irqs = ARRAY_SIZE(pf1550_regulator_irqs),
+};
+
+static const struct regmap_irq pf1550_onkey_irqs[] = {
+ { .reg_offset = 0, .mask = ONKEY_IRQ_PUSHI, },
+ { .reg_offset = 0, .mask = ONKEY_IRQ_1SI, },
+ { .reg_offset = 0, .mask = ONKEY_IRQ_2SI, },
+ { .reg_offset = 0, .mask = ONKEY_IRQ_3SI, },
+ { .reg_offset = 0, .mask = ONKEY_IRQ_4SI, },
+ { .reg_offset = 0, .mask = ONKEY_IRQ_8SI, },
+};
+
+static const struct regmap_irq_chip pf1550_onkey_irq_chip = {
+ .name = "pf1550-onkey",
+ .status_base = PF1550_PMIC_REG_ONKEY_INT_STAT0,
+ .ack_base = PF1550_PMIC_REG_ONKEY_INT_STAT0,
+ .mask_base = PF1550_PMIC_REG_ONKEY_INT_MASK0,
+ .mask_invert = false,
+ .use_ack = 1,
+ .init_ack_masked = 1,
+ .num_regs = 1,
+ .irqs = pf1550_onkey_irqs,
+ .num_irqs = ARRAY_SIZE(pf1550_onkey_irqs),
+};
+
+static const struct regmap_irq pf1550_charger_irqs[] = {
+ { .reg_offset = 0, .mask = CHARG_IRQ_BAT2SOCI, },
+ { .reg_offset = 0, .mask = CHARG_IRQ_BATI, },
+ { .reg_offset = 0, .mask = CHARG_IRQ_CHGI, },
+ { .reg_offset = 0, .mask = CHARG_IRQ_VBUSI, },
+ { .reg_offset = 0, .mask = CHARG_IRQ_THMI, },
+};
+
+static const struct regmap_irq_chip pf1550_charger_irq_chip = {
+ .name = "pf1550-charger",
+ .status_base = PF1550_CHARG_REG_CHG_INT,
+ .mask_base = PF1550_CHARG_REG_CHG_INT_MASK,
+ .mask_invert = false,
+ .num_regs = 1,
+ .irqs = pf1550_charger_irqs,
+ .num_irqs = ARRAY_SIZE(pf1550_charger_irqs),
+};
+
+int pf1550_read_otp(struct pf1550_dev *pf1550, unsigned int index,
+ unsigned int *val)
+{
+ int ret = 0;
+
+ ret = regmap_write(pf1550->regmap, PF1550_PMIC_REG_KEY, 0x15);
+ if (ret)
+ goto read_err;
+ ret = regmap_write(pf1550->regmap, PF1550_CHARG_REG_CHGR_KEY2, 0x50);
+ if (ret)
+ goto read_err;
+ ret = regmap_write(pf1550->regmap, PF1550_TEST_REG_KEY3, 0xAB);
+ if (ret)
+ goto read_err;
+ ret = regmap_write(pf1550->regmap, PF1550_TEST_REG_FMRADDR, index);
+ if (ret)
+ goto read_err;
+ ret = regmap_read(pf1550->regmap, PF1550_TEST_REG_FMRDATA, val);
+ if (ret)
+ goto read_err;
+
+ return 0;
+
+read_err:
+ dev_err(pf1550->dev, "read otp reg %x found!\n", index);
+ return ret;
+}
+
+static int pf1550_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct pf1550_dev *pf1550;
+ unsigned int reg_data = 0;
+ int ret = 0;
+
+ pf1550 = devm_kzalloc(&i2c->dev,
+ sizeof(struct pf1550_dev), GFP_KERNEL);
+ if (!pf1550)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, pf1550);
+ pf1550->dev = &i2c->dev;
+ pf1550->i2c = i2c;
+ pf1550->irq = i2c->irq;
+
+ pf1550->regmap = devm_regmap_init_i2c(i2c, &pf1550_regmap_config);
+ if (IS_ERR(pf1550->regmap)) {
+ ret = PTR_ERR(pf1550->regmap);
+ dev_err(pf1550->dev, "failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = regmap_read(pf1550->regmap, PF1550_PMIC_REG_DEVICE_ID, &reg_data);
+ if (ret < 0 || reg_data != 0x7c) {
+ dev_err(pf1550->dev, "device not found!\n");
+ return ret;
+ }
+
+ pf1550->type = PF1550;
+ dev_info(pf1550->dev, "pf1550 found.\n");
+
+ ret = regmap_add_irq_chip(pf1550->regmap, pf1550->irq,
+ IRQF_ONESHOT | IRQF_SHARED |
+ IRQF_TRIGGER_FALLING, 0,
+ &pf1550_regulator_irq_chip,
+ &pf1550->irq_data_regulator);
+ if (ret) {
+ dev_err(pf1550->dev, "failed to add irq1 chip: %d\n", ret);
+ goto err_regulator_irq;
+ }
+
+ ret = regmap_add_irq_chip(pf1550->regmap, pf1550->irq,
+ IRQF_ONESHOT | IRQF_SHARED |
+ IRQF_TRIGGER_FALLING, 0,
+ &pf1550_onkey_irq_chip,
+ &pf1550->irq_data_onkey);
+ if (ret) {
+ dev_err(pf1550->dev, "failed to add irq3 chip: %d\n", ret);
+ goto err_onkey_irq;
+ }
+
+ ret = regmap_add_irq_chip(pf1550->regmap, pf1550->irq,
+ IRQF_ONESHOT | IRQF_SHARED |
+ IRQF_TRIGGER_FALLING, 0,
+ &pf1550_charger_irq_chip,
+ &pf1550->irq_data_charger);
+ if (ret) {
+ dev_err(pf1550->dev, "failed to add irq4 chip: %d\n", ret);
+ goto err_charger_irq;
+ }
+
+ ret = mfd_add_devices(pf1550->dev, -1, pf1550_devs,
+ ARRAY_SIZE(pf1550_devs), NULL, 0, NULL);
+ if (ret < 0)
+ goto err_mfd;
+
+ return ret;
+
+err_mfd:
+ mfd_remove_devices(pf1550->dev);
+err_charger_irq:
+ regmap_del_irq_chip(pf1550->irq, pf1550->irq_data_charger);
+err_onkey_irq:
+ regmap_del_irq_chip(pf1550->irq, pf1550->irq_data_regulator);
+err_regulator_irq:
+ return ret;
+}
+
+static int pf1550_i2c_remove(struct i2c_client *i2c)
+{
+ struct pf1550_dev *pf1550 = i2c_get_clientdata(i2c);
+
+ mfd_remove_devices(pf1550->dev);
+
+ regmap_del_irq_chip(pf1550->irq, pf1550->irq_data_regulator);
+ regmap_del_irq_chip(pf1550->irq, pf1550->irq_data_onkey);
+ regmap_del_irq_chip(pf1550->irq, pf1550->irq_data_charger);
+
+ return 0;
+}
+
+static const struct i2c_device_id pf1550_i2c_id[] = {
+ { "pf1550", PF1550 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pf1550_i2c_id);
+
+static int pf1550_suspend(struct device *dev)
+{
+ struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct pf1550_dev *pf1550 = i2c_get_clientdata(i2c);
+
+ if (device_may_wakeup(dev)) {
+ enable_irq_wake(pf1550->irq);
+ disable_irq(pf1550->irq);
+ }
+
+ return 0;
+}
+
+static int pf1550_resume(struct device *dev)
+{
+ struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+ struct pf1550_dev *pf1550 = i2c_get_clientdata(i2c);
+
+ if (device_may_wakeup(dev)) {
+ disable_irq_wake(pf1550->irq);
+ enable_irq(pf1550->irq);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops pf1550_pm = {
+ .suspend = pf1550_suspend,
+ .resume = pf1550_resume,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id pf1550_dt_match[] = {
+ { .compatible = "fsl,pf1550" },
+ {},
+};
+#endif
+
+static struct i2c_driver pf1550_i2c_driver = {
+ .driver = {
+ .name = "pf1550",
+ .owner = THIS_MODULE,
+ .pm = &pf1550_pm,
+ .of_match_table = of_match_ptr(pf1550_dt_match),
+ },
+ .probe = pf1550_i2c_probe,
+ .remove = pf1550_i2c_remove,
+ .id_table = pf1550_i2c_id,
+};
+
+static int __init pf1550_i2c_init(void)
+{
+ return i2c_add_driver(&pf1550_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(pf1550_i2c_init);
+
+static void __exit pf1550_i2c_exit(void)
+{
+ i2c_del_driver(&pf1550_i2c_driver);
+}
+module_exit(pf1550_i2c_exit);
+
+MODULE_DESCRIPTION("Freescale PF1550 multi-function core driver");
+MODULE_AUTHOR("Robin Gong <yibin.gong@freescale.com>");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c
index c180b7533bba..3caa23990414 100644
--- a/drivers/mfd/si476x-i2c.c
+++ b/drivers/mfd/si476x-i2c.c
@@ -303,7 +303,7 @@ int si476x_core_set_power_state(struct si476x_core *core,
*/
udelay(100);
- err = si476x_core_start(core, false);
+ err = si476x_core_start(core, true);
if (err < 0)
goto disable_regulators;
@@ -312,7 +312,7 @@ int si476x_core_set_power_state(struct si476x_core *core,
case SI476X_POWER_DOWN:
core->power_state = next_state;
- err = si476x_core_stop(core, false);
+ err = si476x_core_stop(core, true);
if (err < 0)
core->power_state = SI476X_POWER_INCONSISTENT;
disable_regulators:
@@ -740,8 +740,15 @@ static int si476x_core_probe(struct i2c_client *client,
memcpy(&core->pinmux, &pdata->pinmux,
sizeof(struct si476x_pinmux));
} else {
- dev_err(&client->dev, "No platform data provided\n");
- return -EINVAL;
+ dev_warn(&client->dev, "Using default platform data.\n");
+ core->power_up_parameters.xcload = 0x28;
+ core->power_up_parameters.func = SI476X_FUNC_FM_RECEIVER;
+ core->power_up_parameters.freq = SI476X_FREQ_37P209375_MHZ;
+ core->diversity_mode = SI476X_PHDIV_DISABLED;
+ core->pinmux.dclk = SI476X_DCLK_DAUDIO;
+ core->pinmux.dfs = SI476X_DFS_DAUDIO;
+ core->pinmux.dout = SI476X_DOUT_I2S_OUTPUT;
+ core->pinmux.xout = SI476X_XOUT_TRISTATE;
}
core->supplies[0].supply = "vd";
@@ -800,12 +807,19 @@ static int si476x_core_probe(struct i2c_client *client,
core->chip_id = id->driver_data;
+ /* Power down si476x first */
+ core->power_state = SI476X_POWER_UP_FULL;
+ si476x_core_set_power_state(core, SI476X_POWER_DOWN);
+
rval = si476x_core_get_revision_info(core);
if (rval < 0) {
rval = -ENODEV;
goto free_kfifo;
}
+ if (of_property_read_bool(client->dev.of_node, "revision-a10"))
+ core->revision = SI476X_REVISION_A10;
+
cell_num = 0;
cell = &core->cells[SI476X_RADIO_CELL];
@@ -821,6 +835,7 @@ static int si476x_core_probe(struct i2c_client *client,
core->pinmux.xout == SI476X_XOUT_TRISTATE) {
cell = &core->cells[SI476X_CODEC_CELL];
cell->name = "si476x-codec";
+ cell->of_compatible = "si476x-codec";
cell_num++;
}
#endif
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 64971baf11fa..1a1cd2e7c590 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -335,6 +335,26 @@ config ISL29020
This driver can also be built as a module. If so, the module
will be called isl29020.
+config SENSORS_FXOS8700
+ tristate "Freescale FXOS8700 M+G combo sensor"
+ depends on I2C && SYSFS
+ help
+ If you say yes here you get support for the Freescale FXOS8700
+ m+g combo sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called fxos8700.
+
+config SENSORS_FXAS2100X
+ tristate "Freescale FXAS2100X gyroscope sensor"
+ depends on I2C && SYSFS
+ help
+ If you say yes here you get support for the Freescale FXAS2100X
+ gyroscope sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called fxas2100x.
+
config SENSORS_TSL2550
tristate "Taos TSL2550 ambient light sensor"
depends on I2C && SYSFS
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 2bf79ba4a39e..528c53850ca0 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -16,6 +16,8 @@ obj-$(CONFIG_TIFM_CORE) += tifm_core.o
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
obj-$(CONFIG_PHANTOM) += phantom.o
obj-$(CONFIG_QCOM_COINCELL) += qcom-coincell.o
+obj-$(CONFIG_SENSORS_FXOS8700) += fxos8700.o
+obj-$(CONFIG_SENSORS_FXAS2100X) += fxas2100x.o
obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o
obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o
obj-$(CONFIG_SGI_IOC4) += ioc4.o
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 5afe4cd16569..67eb81aecfe4 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -249,7 +249,7 @@ static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
u32 val;
memset(chip, 0, sizeof(*chip));
- strncpy(chip->name, "at25", sizeof(chip->name));
+ strlcpy(chip->name, "at25", sizeof(chip->name));
if (device_property_read_u32(dev, "size", &val) == 0 ||
device_property_read_u32(dev, "at25,byte-len", &val) == 0) {
diff --git a/drivers/misc/fxas2100x.c b/drivers/misc/fxas2100x.c
new file mode 100644
index 000000000000..04541cfb5d14
--- /dev/null
+++ b/drivers/misc/fxas2100x.c
@@ -0,0 +1,628 @@
+/*
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/pm.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/input-polldev.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+
+#define SENSOR_IOCTL_BASE 'S'
+#define SENSOR_GET_MODEL_NAME _IOR(SENSOR_IOCTL_BASE, 0, char *)
+#define SENSOR_GET_POWER_STATUS _IOR(SENSOR_IOCTL_BASE, 2, int)
+#define SENSOR_SET_POWER_STATUS _IOR(SENSOR_IOCTL_BASE, 3, int)
+#define SENSOR_GET_DELAY_TIME _IOR(SENSOR_IOCTL_BASE, 4, int)
+#define SENSOR_SET_DELAY_TIME _IOR(SENSOR_IOCTL_BASE, 5, int)
+#define SENSOR_GET_RAW_DATA _IOR(SENSOR_IOCTL_BASE, 6, short[3])
+
+#define FXAS2100X_I2C_ADDR 0x20
+#define FXAS21000_CHIP_ID 0xD1
+#define FXAS21002_CHID_ID_1 0xD6
+#define FXAS21002_CHID_ID_2 0xD7
+
+#define FXAS2100X_POSITION_DEFAULT 2
+#define FXAS2100X_DELAY_DEFAULT 200
+
+#define FXAS2100X_STATUS_ZYXDR 0x08
+#define FXAS2100X_BUF_SIZE 6
+
+#define FXAS2100X_POLL_INTERVAL 400
+#define FXAS2100X_POLL_MAX 800
+#define FXAS2100X_POLL_MIN 200
+#define ABSMIN_GYRO_VAL -32768
+#define ABSMAX_GYRO_VAL 32768
+
+#define FXAS2100X_DRIVER "fxas2100x"
+
+/* register enum for fxas2100x registers */
+enum {
+ FXAS2100X_STATUS = 0x00,
+ FXAS2100X_OUT_X_MSB,
+ FXAS2100X_OUT_X_LSB,
+ FXAS2100X_OUT_Y_MSB,
+ FXAS2100X_OUT_Y_LSB,
+ FXAS2100X_OUT_Z_MSB,
+ FXAS2100X_OUT_Z_LSB,
+ FXAS2100X_DR_STATUS,
+ FXAS2100X_F_STATUS,
+ FXAS2100X_F_SETUP,
+ FXAS2100X_F_EVENT,
+ FXAS2100X_INT_SRC_FLAG,
+ FXAS2100X_WHO_AM_I,
+ FXAS2100X_CTRL_REG0,
+ FXAS2100X_RT_CFG,
+ FXAS2100X_RT_SRC,
+ FXAS2100X_RT_THS,
+ FXAS2100X_RT_COUNT,
+ FXAS2100X_TEMP,
+ FXAS2100X_CTRL_REG1,
+ FXAS2100X_CTRL_REG2,
+ FXAS2100X_CTRL_REG3, /* fxos21002 special */
+ FXAS2100X_REG_END,
+};
+
+enum {
+ STANDBY = 0,
+ ACTIVED,
+};
+
+struct fxas2100x_data_axis {
+ short x;
+ short y;
+ short z;
+};
+
+struct fxas2100x_data {
+ struct i2c_client *client;
+ struct input_polled_dev *input_polled;
+ atomic_t active;
+ atomic_t active_poll;
+ atomic_t delay;
+ atomic_t position;
+ u8 chip_id;
+};
+
+static struct fxas2100x_data *g_fxas2100x_data;
+
+static int fxas2100x_position_setting[8][3][3] = {
+ { {0, -1, 0}, {1, 0, 0}, {0, 0, 1} },
+ { {-1, 0, 0}, {0, -1, 0}, {0, 0, 1} },
+ { {0, 1, 0}, {-1, 0, 0}, {0, 0, 1} },
+ { {1, 0, 0}, {0, 1, 0}, {0, 0, 1} },
+ { {0, -1, 0}, {-1, 0, 0}, {0, 0, -1} },
+ { {-1, 0, 0}, {0, 1, 0}, {0, 0, -1} },
+ { {0, 1, 0}, {1, 0, 0}, {0, 0, -1} },
+ { {1, 0, 0}, {0, -1, 0}, {0, 0, -1} },
+};
+
+static int fxas2100x_data_convert(struct fxas2100x_data *pdata,
+ struct fxas2100x_data_axis *axis_data)
+{
+ short rawdata[3], data[3];
+ int i, j;
+ int position = atomic_read(&pdata->position);
+
+ if (position < 0 || position > 7)
+ position = 0;
+ rawdata[0] = axis_data->x;
+ rawdata[1] = axis_data->y;
+ rawdata[2] = axis_data->z;
+ for (i = 0; i < 3; i++) {
+ data[i] = 0;
+ for (j = 0; j < 3; j++)
+ data[i] += rawdata[j] * fxas2100x_position_setting[position][i][j];
+ }
+ axis_data->x = data[0];
+ axis_data->y = data[1];
+ axis_data->z = data[2];
+ return 0;
+}
+
+static int fxas2100x_device_init(struct i2c_client *client)
+{
+ int result;
+ u8 val;
+ struct device_node *np = client->dev.of_node;
+
+ struct fxas2100x_data *pdata = i2c_get_clientdata(client);
+ if (pdata->chip_id == FXAS21000_CHIP_ID)
+ val = (0x01 << 2); /* fxas21000 dr 200HZ */
+ else
+ val = (0x02 << 2); /* fxas21002 dr 200HZ */
+ result = i2c_smbus_write_byte_data(client, FXAS2100X_CTRL_REG1, val);
+ if (result < 0)
+ goto out;
+
+ /* set interrupt pin as open-drain */
+ if (of_get_property(np, "interrupt-open-drain", NULL)) {
+ result = i2c_smbus_write_byte_data(client, FXAS2100X_CTRL_REG2, 0x01);
+ if (result < 0)
+ goto out;
+ }
+
+ atomic_set(&pdata->active, STANDBY);
+ return 0;
+out:
+ dev_err(&client->dev, "error when init fxas2100x:(%d)", result);
+ return result;
+}
+
+static int fxas2100x_change_mode(struct i2c_client *client, int mode)
+{
+ u8 val;
+ int ret;
+ if (mode == ACTIVED) {
+ val = i2c_smbus_read_byte_data(client, FXAS2100X_CTRL_REG1);
+ val &= ~0x03;
+ val |= 0x02;
+ /* set bit 1 */
+ ret = i2c_smbus_write_byte_data(client, FXAS2100X_CTRL_REG1, val);
+ } else {
+ val = i2c_smbus_read_byte_data(client, FXAS2100X_CTRL_REG1);
+ val &= (~0x03);
+ /* clear bit 0,1 */
+ ret = i2c_smbus_write_byte_data(client, FXAS2100X_CTRL_REG1, val);
+ }
+ return ret;
+}
+
+static int fxas2100x_set_delay(struct i2c_client *client, int delay)
+{
+ return 0;
+}
+
+static int fxas2100x_device_stop(struct i2c_client *client)
+{
+ u8 val;
+ val = i2c_smbus_read_byte_data(client, FXAS2100X_CTRL_REG1);
+ val &= ~0x03;
+ i2c_smbus_write_byte_data(client, FXAS2100X_CTRL_REG1, val);
+ return 0;
+}
+
+static int fxas2100x_read_data(struct fxas2100x_data *pdata,
+ struct fxas2100x_data_axis *data)
+{
+ struct i2c_client * client = pdata->client;
+ int x, y, z;
+ u8 tmp_data[FXAS2100X_BUF_SIZE];
+ int ret;
+
+ ret = i2c_smbus_read_i2c_block_data(client, FXAS2100X_OUT_X_MSB,
+ FXAS2100X_BUF_SIZE, tmp_data);
+ if (ret < FXAS2100X_BUF_SIZE) {
+ dev_err(&client->dev, "i2c block read failed\n");
+ return -EIO;
+ }
+ data->x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1];
+ data->y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3];
+ data->z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5];
+ if (pdata->chip_id == FXAS21000_CHIP_ID) {
+ x = data->x;
+ y = data->y;
+ z = data->z;
+ x = x * 4 / 5;
+ y = y * 4 / 5;
+ z = z * 4 / 5;
+ data->x = x;
+ data->y = y;
+ data->z = z;
+ }
+
+ return 0;
+}
+
+/* fxas2100x miscdevice */
+static long fxas2100x_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct fxas2100x_data *pdata = file->private_data;
+ void __user *argp = (void __user *)arg;
+ struct fxas2100x_data_axis data;
+ long ret = 0;
+ short sdata[3];
+ int enable;
+ int delay;
+
+ if (!pdata) {
+ printk(KERN_ERR "FXAS2100X struct datt point is NULL.");
+ return -EFAULT;
+ }
+
+ switch (cmd) {
+ case SENSOR_GET_MODEL_NAME:
+ if (copy_to_user(argp, "FXAS2100X GYRO", strlen("FXAS2100X GYRO") + 1)) {
+ printk(KERN_ERR "SENSOR_GET_MODEL_NAME copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ break;
+ case SENSOR_GET_POWER_STATUS:
+ enable = atomic_read(&pdata->active);
+ if (copy_to_user(argp, &enable, sizeof(int))) {
+ printk(KERN_ERR "SENSOR_SET_POWER_STATUS copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ break;
+ case SENSOR_SET_POWER_STATUS:
+ if (copy_from_user(&enable, argp, sizeof(int))) {
+ printk(KERN_ERR "SENSOR_SET_POWER_STATUS copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ if (pdata->client) {
+ ret = fxas2100x_change_mode(pdata->client, enable ? ACTIVED : STANDBY);
+ if (!ret)
+ atomic_set(&pdata->active, enable);
+ }
+ break;
+ case SENSOR_GET_DELAY_TIME:
+ delay = atomic_read(&pdata->delay);
+ if (copy_to_user(argp, &delay, sizeof(delay))) {
+ printk(KERN_ERR "SENSOR_GET_DELAY_TIME copy_to_user failed.");
+ return -EFAULT;
+ }
+ break;
+ case SENSOR_SET_DELAY_TIME:
+ if (copy_from_user(&delay, argp, sizeof(int))) {
+ printk(KERN_ERR "SENSOR_GET_DELAY_TIME copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ if (pdata->client && delay > 0 && delay <= 500) {
+ ret = fxas2100x_set_delay(pdata->client, delay);
+ if (!ret)
+ atomic_set(&pdata->delay, delay);
+ }
+ break;
+ case SENSOR_GET_RAW_DATA:
+ ret = fxas2100x_read_data(pdata, &data);
+ if (!ret) {
+ fxas2100x_data_convert(pdata, &data);
+ sdata[0] = data.x;
+ sdata[1] = data.y;
+ sdata[2] = data.z;
+ if (copy_to_user(argp, sdata, sizeof(sdata))) {
+ printk(KERN_ERR "SENSOR_GET_RAW_DATA copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ }
+ break;
+ default:
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static int fxas2100x_open(struct inode *inode, struct file *file)
+{
+ file->private_data = g_fxas2100x_data;
+ return nonseekable_open(inode, file);
+}
+
+static int fxas2100x_release(struct inode *inode, struct file *file)
+{
+ /* note: releasing the wdt in NOWAYOUT-mode does not stop it */
+ return 0;
+}
+
+static const struct file_operations fxas2100x_fops = {
+ .owner = THIS_MODULE,
+ .open = fxas2100x_open,
+ .release = fxas2100x_release,
+ .unlocked_ioctl = fxas2100x_ioctl,
+};
+
+static struct miscdevice fxas2100x_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "FreescaleGyroscope",
+ .fops = &fxas2100x_fops,
+};
+
+static ssize_t fxas2100x_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fxas2100x_data *pdata = g_fxas2100x_data;
+ int enable = 0;
+ enable = atomic_read(&pdata->active);
+ return sprintf(buf, "%d\n", enable);
+}
+
+static ssize_t fxas2100x_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fxas2100x_data *pdata = g_fxas2100x_data;
+ struct i2c_client *client = pdata->client;
+ int ret;
+ unsigned long enable;
+
+ if (kstrtoul(buf, 10, &enable) < 0)
+ return -EINVAL;
+
+ enable = (enable > 0) ? 1 : 0;
+ ret = fxas2100x_change_mode(client, (enable > 0 ? ACTIVED : STANDBY));
+ if (!ret) {
+ atomic_set(&pdata->active, enable);
+ atomic_set(&pdata->active_poll, enable);
+ dev_err(dev, "mma enable setting active \n");
+ }
+ return count;
+}
+
+static ssize_t fxas2100x_poll_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fxas2100x_data *pdata = g_fxas2100x_data;
+ int delay = 0;
+
+ delay = atomic_read(&pdata->delay);
+ return sprintf(buf, "%d\n", delay);
+}
+
+static ssize_t fxas2100x_poll_delay_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fxas2100x_data *pdata = g_fxas2100x_data;
+ struct i2c_client *client = pdata->client;
+ int ret;
+ int delay;
+
+ delay = simple_strtoul(buf, NULL, 10);
+ ret = fxas2100x_set_delay(client, delay);
+ if (!ret)
+ atomic_set(&pdata->delay, delay);
+ return count;
+}
+
+static ssize_t fxas2100x_position_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fxas2100x_data *pdata = g_fxas2100x_data;
+ int position = 0;
+
+ position = atomic_read(&pdata->position);
+ return sprintf(buf, "%d\n", position);
+}
+
+static ssize_t fxas2100x_position_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fxas2100x_data *pdata = g_fxas2100x_data;
+ int position;
+
+ position = simple_strtoul(buf, NULL, 10);
+ atomic_set(&pdata->position, position);
+ return count;
+}
+
+static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, fxas2100x_enable_show, fxas2100x_enable_store);
+static DEVICE_ATTR(poll_delay, S_IWUSR | S_IRUGO, fxas2100x_poll_delay_show, fxas2100x_poll_delay_store);
+static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, fxas2100x_position_show, fxas2100x_position_store);
+
+static struct attribute *fxas2100x_attributes[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_poll_delay.attr,
+ &dev_attr_position.attr,
+ NULL
+};
+
+static const struct attribute_group fxas2100x_attr_group = {
+ .attrs = fxas2100x_attributes,
+};
+
+static void fxas2100x_poll(struct input_polled_dev *dev)
+{
+ struct fxas2100x_data *pdata = g_fxas2100x_data;
+ struct input_dev *idev = pdata->input_polled->input;
+ struct fxas2100x_data_axis data;
+ int ret;
+
+ if (!(atomic_read(&pdata->active_poll)))
+ return;
+
+ ret = fxas2100x_read_data(pdata, &data);
+ if (!ret) {
+ fxas2100x_data_convert(pdata, &data);
+ input_report_abs(idev, ABS_X, data.x);
+ input_report_abs(idev, ABS_Y, data.y);
+ input_report_abs(idev, ABS_Z, data.z);
+ input_sync(idev);
+ }
+}
+
+static int fxas2100x_register_polled_device(struct fxas2100x_data *pdata)
+{
+ struct input_polled_dev *ipoll_dev;
+ struct input_dev *idev;
+ int error;
+
+ ipoll_dev = input_allocate_polled_device();
+ if (!ipoll_dev)
+ return -ENOMEM;
+
+ ipoll_dev->private = pdata;
+ ipoll_dev->poll = fxas2100x_poll;
+ ipoll_dev->poll_interval = FXAS2100X_POLL_INTERVAL;
+ ipoll_dev->poll_interval_min = FXAS2100X_POLL_MIN;
+ ipoll_dev->poll_interval_max = FXAS2100X_POLL_MAX;
+ idev = ipoll_dev->input;
+ idev->name = FXAS2100X_DRIVER;
+ idev->id.bustype = BUS_I2C;
+ idev->dev.parent = &pdata->client->dev;
+
+ idev->evbit[0] = BIT_MASK(EV_ABS);
+ input_set_abs_params(idev, ABS_X, ABSMIN_GYRO_VAL, ABSMAX_GYRO_VAL, 0, 0);
+ input_set_abs_params(idev, ABS_Y, ABSMIN_GYRO_VAL, ABSMAX_GYRO_VAL, 0, 0);
+ input_set_abs_params(idev, ABS_Z, ABSMIN_GYRO_VAL, ABSMAX_GYRO_VAL, 0, 0);
+
+ error = input_register_polled_device(ipoll_dev);
+ if (error) {
+ input_free_polled_device(ipoll_dev);
+ return error;
+ }
+
+ pdata->input_polled = ipoll_dev;
+ return 0;
+}
+
+static int fxas2100x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int result, chip_id;
+ struct fxas2100x_data *pdata;
+ struct i2c_adapter *adapter;
+
+ adapter = to_i2c_adapter(client->dev.parent);
+ result = i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA);
+ if (!result)
+ goto err_out;
+
+ chip_id = i2c_smbus_read_byte_data(client, FXAS2100X_WHO_AM_I);
+ if (chip_id != FXAS21000_CHIP_ID && chip_id != FXAS21002_CHID_ID_1 &&
+ chip_id != FXAS21002_CHID_ID_2) {
+ dev_err(&client->dev,
+ "read chip ID 0x%x is not equal to 0x%x for fxas21000 or 0x%x/0x%x fxas21002!\n",
+ chip_id, FXAS21000_CHIP_ID, FXAS21002_CHID_ID_1, FXAS21002_CHID_ID_2);
+ result = -EINVAL;
+ goto err_out;
+ }
+
+ pdata = kzalloc(sizeof(struct fxas2100x_data), GFP_KERNEL);
+ if (!pdata) {
+ result = -ENOMEM;
+ dev_err(&client->dev, "alloc data memory error!\n");
+ goto err_out;
+ }
+
+ /* Initialize the FXAS2100X chip */
+ g_fxas2100x_data = pdata;
+ pdata->client = client;
+ pdata->chip_id = chip_id;
+ atomic_set(&pdata->delay, FXAS2100X_DELAY_DEFAULT);
+ atomic_set(&pdata->position, FXAS2100X_POSITION_DEFAULT);
+ i2c_set_clientdata(client, pdata);
+ result = misc_register(&fxas2100x_device);
+ if (result != 0) {
+ dev_err(&client->dev, "register acc miscdevice error");
+ goto err_regsiter_misc;
+ }
+
+ /* for debug */
+ if (client->irq <= 0) {
+ result = fxas2100x_register_polled_device(g_fxas2100x_data);
+ if (result)
+ dev_err(&client->dev,
+ "IRQ GPIO conf. error %d, error %d\n",
+ client->irq, result);
+ }
+
+ result = sysfs_create_group(&fxas2100x_device.this_device->kobj,
+ &fxas2100x_attr_group);
+ if (result) {
+ dev_err(&client->dev, "create device file failed!\n");
+ result = -EINVAL;
+ goto err_create_sysfs;
+ }
+ fxas2100x_device_init(client);
+ dev_info(&client->dev, "fxas2100x device driver probe successfully\n");
+ return 0;
+err_create_sysfs:
+ misc_deregister(&fxas2100x_device);
+err_regsiter_misc:
+ kfree(pdata);
+err_out:
+ return result;
+}
+
+static int fxas2100x_remove(struct i2c_client *client)
+{
+ struct fxas2100x_data *pdata = i2c_get_clientdata(client);
+ fxas2100x_device_stop(client);
+ if (client->irq <= 0) {
+ input_unregister_polled_device(pdata->input_polled);
+ input_free_polled_device(pdata->input_polled);
+ }
+ misc_deregister(&fxas2100x_device);
+ if (pdata != NULL)
+ kfree(pdata);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fxas2100x_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fxas2100x_data *pdata = i2c_get_clientdata(client);
+
+ if (atomic_read(&pdata->active))
+ fxas2100x_device_stop(client);
+ return 0;
+}
+
+static int fxas2100x_resume(struct device *dev)
+{
+ int val = 0;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fxas2100x_data *pdata = i2c_get_clientdata(client);
+
+ if (atomic_read(&pdata->active)) {
+ val = i2c_smbus_read_byte_data(client, FXAS2100X_CTRL_REG1);
+ val &= ~0x03;
+ val |= 0x02;
+ i2c_smbus_write_byte_data(client, FXAS2100X_CTRL_REG1, val);
+ }
+ return 0;
+
+}
+#endif
+
+static const struct i2c_device_id fxas2100x_id[] = {
+ { "fxas2100x", 0 },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, fxas2100x_id);
+
+static SIMPLE_DEV_PM_OPS(fxas2100x_pm_ops, fxas2100x_suspend, fxas2100x_resume);
+static struct i2c_driver fxas2100x_driver = {
+ .driver = {
+ .name = FXAS2100X_DRIVER,
+ .owner = THIS_MODULE,
+ .pm = &fxas2100x_pm_ops,
+ },
+ .probe = fxas2100x_probe,
+ .remove = fxas2100x_remove,
+ .id_table = fxas2100x_id,
+};
+
+module_i2c_driver(fxas2100x_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("FXAS2100X 3-Axis Gyrosope Sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/fxos8700.c b/drivers/misc/fxos8700.c
new file mode 100644
index 000000000000..e9a07113281f
--- /dev/null
+++ b/drivers/misc/fxos8700.c
@@ -0,0 +1,978 @@
+/*
+ * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/pm.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/input-polldev.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+
+/*register define*/
+#define FXOS8700_STATUS 0x00
+#define FXOS8700_OUT_X_MSB 0x01
+#define FXOS8700_OUT_X_LSB 0x02
+#define FXOS8700_OUT_Y_MSB 0x03
+#define FXOS8700_OUT_Y_LSB 0x04
+#define FXOS8700_OUT_Z_MSB 0x05
+#define FXOS8700_OUT_Z_LSB 0x06
+#define FXOS8700_F_SETUP 0x09
+#define FXOS8700_TRIG_CFG 0x0a
+#define FXOS8700_SYSMOD 0x0B
+#define FXOS8700_INT_SOURCE 0x0c
+#define FXOS8700_WHO_AM_I 0x0d
+#define FXOS8700_XYZ_DATA_CFG 0x0e
+#define FXOS8700_HP_FILTER_CUTOFF 0x0f
+#define FXOS8700_PL_STATUS 0x10
+#define FXOS8700_PL_CFG 0x11
+#define FXOS8700_PL_COUNT 0x12
+#define FXOS8700_PL_BF_ZCOMP 0x13
+#define FXOS8700_PL_P_L_THS_REG 0x14
+#define FXOS8700_FFMT_CFG 0x15
+#define FXOS8700_FFMT_SRC 0x16
+#define FXOS8700_FFMT_THS 0x17
+#define FXOS8700_FFMT_COUNT 0x18
+#define FXOS8700_TRANSIDENT1_CFG 0x1d
+#define FXOS8700_TRANSIDENT1_SRC 0x1e
+#define FXOS8700_TRANSIDENT1_THS 0x1f
+#define FXOS8700_TRANSIDENT1_COUNT 0x20
+#define FXOS8700_PULSE_CFG 0x21
+#define FXOS8700_PULSE_SRC 0x22
+#define FXOS8700_PULSE_THSX 0x23
+#define FXOS8700_PULSE_THSY 0x24
+#define FXOS8700_PULSE_THSZ 0x25
+#define FXOS8700_PULSE_TMLT 0x26
+#define FXOS8700_PULSE_LTCY 0x27
+#define FXOS8700_PULSE_WIND 0x28
+#define FXOS8700_ATSLP_COUNT 0x29
+#define FXOS8700_CTRL_REG1 0x2a
+#define FXOS8700_CTRL_REG2 0x2b
+#define FXOS8700_CTRL_REG3 0x2c
+#define FXOS8700_CTRL_REG4 0x2d
+#define FXOS8700_CTRL_REG5 0x2e
+#define FXOS8700_OFF_X 0x2f
+#define FXOS8700_OFF_Y 0x30
+#define FXOS8700_OFF_Z 0x31
+#define FXOS8700_M_DR_STATUS 0x32
+#define FXOS8700_M_OUT_X_MSB 0x33
+#define FXOS8700_M_OUT_X_LSB 0x34
+#define FXOS8700_M_OUT_Y_MSB 0x35
+#define FXOS8700_M_OUT_Y_LSB 0x36
+#define FXOS8700_M_OUT_Z_MSB 0x37
+#define FXOS8700_M_OUT_Z_LSB 0x38
+#define FXOS8700_CMP_X_MSB 0x39
+#define FXOS8700_CMP_X_LSB 0x3a
+#define FXOS8700_CMP_Y_MSB 0x3b
+#define FXOS8700_CMP_Y_LSB 0x3c
+#define FXOS8700_CMP_Z_MSB 0x3d
+#define FXOS8700_CMP_Z_LSB 0x3e
+#define FXOS8700_M_OFF_X_MSB 0x3f
+#define FXOS8700_M_OFF_X_LSB 0x40
+#define FXOS8700_M_OFF_Y_MSB 0x41
+#define FXOS8700_M_OFF_Y_LSB 0x42
+#define FXOS8700_M_OFF_Z_MSB 0x43
+#define FXOS8700_M_OFF_Z_LSB 0x44
+#define FXOS8700_MAX_X_MSB 0x45
+#define FXOS8700_MAX_X_LSB 0x46
+#define FXOS8700_MAX_Y_MSB 0x47
+#define FXOS8700_MAX_Y_LSB 0x48
+#define FXOS8700_MAX_Z_MSB 0x49
+#define FXOS8700_MAX_Z_LSB 0x4a
+#define FXOS8700_MIN_X_MSB 0x4b
+#define FXOS8700_MIN_X_LSB 0x4c
+#define FXOS8700_MIN_Y_MSB 0x4d
+#define FXOS8700_MIN_Y_LSB 0x4e
+#define FXOS8700_MIN_Z_MSB 0x4f
+#define FXOS8700_MIN_Z_LSB 0x50
+#define FXOS8700_M_TEMP 0x51
+#define FXOS8700_MAG_THS_CFG 0x52
+#define FXOS8700_MAG_THS_SRC 0x53
+#define FXOS8700_MAG_THS_THS_X1 0x54
+#define FXOS8700_MAG_THS_THS_X0 0x55
+#define FXOS8700_MAG_THS_THS_Y1 0x56
+#define FXOS8700_MAG_THS_THS_Y0 0x57
+#define FXOS8700_MAG_THS_THS_Z1 0x58
+#define FXOS8700_MAG_THS_THS_Z0 0x59
+#define FXOS8700_MAG_THS_CUNT 0x5a
+#define FXOS8700_M_CTRL_REG1 0x5b
+#define FXOS8700_M_CTRL_REG2 0x5c
+#define FXOS8700_M_CTRL_REG3 0x5d
+#define FXOS8700_M_INT_SOURCE 0x5e
+#define FXOS8700_G_VECM_CFG 0x5f
+#define FXOS8700_G_VECM_THS_MSB 0x60
+#define FXOS8700_G_VECM_THS_LSB 0x61
+#define FXOS8700_G_VECM_CNT 0x62
+#define FXOS8700_G_VECM_INITX_MSB 0x63
+#define FXOS8700_G_VECM_INITX_LSB 0x64
+#define FXOS8700_G_VECM_INITY_MSB 0x65
+#define FXOS8700_G_VECM_INITY_LSB 0x66
+#define FXOS8700_G_VECM_INITZ_MSB 0x67
+#define FXOS8700_G_VECM_INITZ_LSB 0x68
+#define FXOS8700_M_VECM_CFG 0x69
+#define FXOS8700_M_VECM_THS_MSB 0x6a
+#define FXOS8700_M_VECM_THS_LSB 0x6b
+#define FXOS8700_M_VECM_CNT 0x6d
+#define FXOS8700_M_VECM_INITX_MSB 0x6d
+#define FXOS8700_M_VECM_INITX_LSB 0x6e
+#define FXOS8700_M_VECM_INITY_MSB 0x6f
+#define FXOS8700_M_VECM_INITY_LSB 0x70
+#define FXOS8700_M_VECM_INITZ_MSB 0x71
+#define FXOS8700_M_VECM_INITZ_LSB 0x72
+#define FXOS8700_G_FFMT_THS_X1 0x73
+#define FXOS8700_G_FFMT_THS_X0 0x74
+#define FXOS8700_G_FFMT_THS_Y1 0x75
+#define FXOS8700_G_FFMT_THS_Y0 0x76
+#define FXOS8700_G_FFMT_THS_Z1 0x77
+#define FXOS8700_G_FFMT_THS_Z0 0x78
+#define FXOS8700_G_TRAN_INIT_MSB 0x79
+#define FXOS8700_G_TRAN_INIT_LSB_X 0x7a
+#define FXOS8700_G_TRAN_INIT_LSB_Y 0x7b
+#define FXOS8700_G_TRAN_INIT_LSB_Z 0x7d
+#define FXOS8700_TM_NVM_LOCK 0x7e
+#define FXOS8700_NVM_DATA0_35 0x80
+#define FXOS8700_NVM_DATA_BNK3 0xa4
+#define FXOS8700_NVM_DATA_BNK2 0xa5
+#define FXOS8700_NVM_DATA_BNK1 0xa6
+#define FXOS8700_NVM_DATA_BNK0 0xa7
+
+#define SENSOR_IOCTL_BASE 'S'
+#define SENSOR_GET_MODEL_NAME _IOR(SENSOR_IOCTL_BASE, 0, char *)
+#define SENSOR_GET_POWER_STATUS _IOR(SENSOR_IOCTL_BASE, 2, int)
+#define SENSOR_SET_POWER_STATUS _IOR(SENSOR_IOCTL_BASE, 3, int)
+#define SENSOR_GET_DELAY_TIME _IOR(SENSOR_IOCTL_BASE, 4, int)
+#define SENSOR_SET_DELAY_TIME _IOR(SENSOR_IOCTL_BASE, 5, int)
+#define SENSOR_GET_RAW_DATA _IOR(SENSOR_IOCTL_BASE, 6, short[3])
+
+#define FXOS8700_I2C_ADDR 0x1E
+#define FXOS8700_DEVICE_ID 0xC7
+#define FXOS8700_PRE_DEVICE_ID 0xC4
+#define FXOS8700_DATA_BUF_SIZE 6
+#define FXOS8700_DELAY_DEFAULT 200 /* msecs */
+#define FXOS8700_POSITION_DEFAULT 1 /* msecs */
+
+#define FXOS8700_TYPE_ACC 0x00
+#define FXOS8700_TYPE_MAG 0x01
+#define FXOS8700_STANDBY 0x00
+#define FXOS8700_ACTIVED 0x01
+
+#define ABS_STATUS ABS_WHEEL
+#define FXOS8700_DRIVER "fxos8700"
+
+#define ABSMAX_ACC_VAL 0x01FF
+#define ABSMIN_ACC_VAL -(ABSMAX_ACC_VAL)
+#define FXOS8700_POLL_INTERVAL 400
+#define FXOS8700_POLL_MAX 800
+#define FXOS8700_POLL_MIN 100
+
+enum { MODE_2G = 0, MODE_4G, MODE_8G,
+};
+
+struct fxos8700_data_axis {
+ short x;
+ short y;
+ short z;
+};
+
+struct fxos8700_data {
+ struct i2c_client *client;
+ struct input_polled_dev *input_polled;
+ struct miscdevice *acc_miscdev;
+ struct miscdevice *mag_miscdev;
+ atomic_t acc_delay;
+ atomic_t mag_delay;
+ atomic_t acc_active;
+ atomic_t acc_active_poll;
+ atomic_t mag_active_poll;
+ atomic_t mag_active;
+ atomic_t position;
+ atomic_t range;
+};
+
+static struct fxos8700_data *g_fxos8700_data;
+static int fxos8700_position_settings[8][3][3] = {
+ { { 0, -1, 0}, { 1, 0, 0}, {0, 0, 1} },
+ { {-1, 0, 0}, { 0, -1, 0}, {0, 0, 1} },
+ { { 0, 1, 0}, {-1, 0, 0}, {0, 0, 1} },
+ { { 1, 0, 0}, { 0, 1, 0}, {0, 0, 1} },
+ { { 0, -1, 0}, {-1, 0, 0}, {0, 0, -1} },
+ { {-1, 0, 0}, { 0, 1, 0}, {0, 0, -1} },
+ { { 0, 1, 0}, { 1, 0, 0}, {0, 0, -1} },
+ { { 1, 0, 0}, { 0, -1, 0}, {0, 0, -1} },
+};
+
+static int fxos8700_data_convert(struct fxos8700_data_axis *axis_data, int position)
+{
+ short rawdata[3], data[3];
+ int i, j;
+ if (position < 0 || position > 7)
+ position = 0;
+ rawdata[0] = axis_data->x;
+ rawdata[1] = axis_data->y;
+ rawdata[2] = axis_data->z;
+ for (i = 0; i < 3 ; i++) {
+ data[i] = 0;
+ for (j = 0; j < 3; j++)
+ data[i] += rawdata[j] * fxos8700_position_settings[position][i][j];
+ }
+
+ axis_data->x = data[0];
+ axis_data->y = data[1];
+ axis_data->z = data[2];
+ return 0;
+}
+
+static int fxos8700_change_mode(struct i2c_client *client, int type, int active)
+{
+ u8 data;
+ int acc_act, mag_act;
+ struct fxos8700_data *pdata = i2c_get_clientdata(client);
+
+ acc_act = atomic_read(&pdata->acc_active);
+ mag_act = atomic_read(&pdata->mag_active);
+ data = i2c_smbus_read_byte_data(client, FXOS8700_CTRL_REG1);
+ if (type == FXOS8700_TYPE_ACC)
+ acc_act = active;
+ else
+ mag_act = active;
+ if (acc_act == FXOS8700_ACTIVED || mag_act == FXOS8700_ACTIVED)
+ data |= 0x01;
+ else
+ data &= ~0x01;
+ i2c_smbus_write_byte_data(client, FXOS8700_CTRL_REG1, data);
+
+ return 0;
+}
+
+static int fxos8700_change_range(struct i2c_client *client, int range)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, FXOS8700_XYZ_DATA_CFG, range);
+
+ return ret;
+}
+static int fxos8700_set_odr(struct i2c_client *client, int type, int delay)
+{
+ return 0;
+}
+
+static int fxos8700_device_init(struct i2c_client *client)
+{
+ int result;
+ struct device_node *np = client->dev.of_node;
+ struct fxos8700_data *pdata = i2c_get_clientdata(client);
+
+ /* set interrupt pin as open-drain */
+ if (of_get_property(np, "interrupt-open-drain", NULL)) {
+ result = i2c_smbus_write_byte_data(client, FXOS8700_CTRL_REG3, 0x01);
+ if (result < 0)
+ goto out;
+ }
+
+ /* standby mode */
+ result = i2c_smbus_write_byte_data(client, FXOS8700_CTRL_REG1, 0x00);
+ if (result < 0)
+ goto out;
+ result = i2c_smbus_write_byte_data(client, FXOS8700_M_CTRL_REG1, 0x1F);
+ if (result < 0)
+ goto out;
+ result = i2c_smbus_write_byte_data(client, FXOS8700_M_CTRL_REG2, 0x5c);
+ if (result < 0)
+ goto out;
+ result = i2c_smbus_write_byte_data(client, FXOS8700_CTRL_REG1, 0x03 << 3);
+ if (result < 0)
+ goto out;
+ result = i2c_smbus_write_byte_data(client, FXOS8700_XYZ_DATA_CFG,
+ MODE_2G);
+ if (result < 0)
+ goto out;
+
+ atomic_set(&pdata->acc_active, FXOS8700_STANDBY);
+ atomic_set(&pdata->mag_active, FXOS8700_STANDBY);
+ atomic_set(&pdata->position, FXOS8700_POSITION_DEFAULT);
+ atomic_set(&pdata->range, MODE_2G);
+ return 0;
+out:
+ dev_err(&client->dev, "Error when init fxos8700 device:(%d)", result);
+ return result;
+}
+
+static int fxos8700_device_stop(struct i2c_client *client)
+{
+ i2c_smbus_write_byte_data(client, FXOS8700_CTRL_REG1, 0x00);
+ return 0;
+}
+
+static int
+fxos8700_read_data(struct i2c_client *client, struct fxos8700_data_axis *data, int type)
+{
+ u8 tmp_data[FXOS8700_DATA_BUF_SIZE];
+ int ret;
+ u8 reg;
+
+ if (type == FXOS8700_TYPE_ACC)
+ reg = FXOS8700_OUT_X_MSB;
+ else
+ reg = FXOS8700_M_OUT_X_MSB;
+
+ ret = i2c_smbus_read_i2c_block_data(client, reg, FXOS8700_DATA_BUF_SIZE, tmp_data);
+ if (ret < FXOS8700_DATA_BUF_SIZE) {
+ dev_err(&client->dev, "i2c block read %s failed\n",
+ (type == FXOS8700_TYPE_ACC ? "acc" : "mag"));
+ return -EIO;
+ }
+ data->x = ((tmp_data[0] << 8) & 0xff00) | tmp_data[1];
+ data->y = ((tmp_data[2] << 8) & 0xff00) | tmp_data[3];
+ data->z = ((tmp_data[4] << 8) & 0xff00) | tmp_data[5];
+ return 0;
+}
+
+static long fxos8700_acc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct fxos8700_data *pdata = file->private_data;
+ void __user *argp = (void __user *)arg;
+ struct fxos8700_data_axis data;
+ long ret = 0;
+ short sdata[3];
+ int enable;
+ int delay;
+ int position;
+
+ if (!pdata) {
+ printk(KERN_ERR "fxos8700 struct datt point is NULL.");
+ return -EFAULT;
+ }
+
+ switch (cmd) {
+ case SENSOR_GET_MODEL_NAME:
+ if (copy_to_user(argp, "FXOS8700 ACC", strlen("FXOS8700 ACC") + 1)) {
+ printk(KERN_ERR "SENSOR_GET_MODEL_NAME copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ break;
+ case SENSOR_GET_POWER_STATUS:
+ enable = atomic_read(&pdata->acc_active);
+ if (copy_to_user(argp, &enable, sizeof(int))) {
+ printk(KERN_ERR "SENSOR_SET_POWER_STATUS copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ break;
+ case SENSOR_SET_POWER_STATUS:
+ if (copy_from_user(&enable, argp, sizeof(int))) {
+ printk(KERN_ERR "SENSOR_SET_POWER_STATUS copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ if (pdata->client) {
+ ret = fxos8700_change_mode(pdata->client, FXOS8700_TYPE_ACC,
+ enable ? FXOS8700_ACTIVED : FXOS8700_STANDBY);
+ if (!ret)
+ atomic_set(&pdata->acc_active, enable);
+ }
+ break;
+ case SENSOR_GET_DELAY_TIME:
+ delay = atomic_read(&pdata->acc_delay);
+ if (copy_to_user(argp, &delay, sizeof(delay))) {
+ printk(KERN_ERR "SENSOR_GET_DELAY_TIME copy_to_user failed.");
+ return -EFAULT;
+ }
+ break;
+ case SENSOR_SET_DELAY_TIME:
+ if (copy_from_user(&delay, argp, sizeof(int))) {
+ printk(KERN_ERR "SENSOR_SET_DELAY_TIME copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ if (pdata->client && delay > 0 && delay <= 500) {
+ ret = fxos8700_set_odr(pdata->client, FXOS8700_TYPE_ACC, delay);
+ if (!ret)
+ atomic_set(&pdata->acc_delay, delay);
+ }
+ break;
+ case SENSOR_GET_RAW_DATA:
+ position = atomic_read(&pdata->position);
+ ret = fxos8700_read_data(pdata->client, &data, FXOS8700_TYPE_ACC);
+ if (!ret) {
+ fxos8700_data_convert(&data, position);
+ sdata[0] = data.x;
+ sdata[1] = data.y;
+ sdata[2] = data.z;
+ if (copy_to_user(argp, sdata, sizeof(sdata))) {
+ printk(KERN_ERR "SENSOR_GET_RAW_DATA copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ }
+ break;
+ default:
+ ret = -1;
+ }
+ return ret;
+}
+
+static int fxos8700_acc_open(struct inode *inode, struct file *file)
+{
+ file->private_data = g_fxos8700_data;
+ return nonseekable_open(inode, file);
+}
+
+static int fxos8700_acc_release(struct inode *inode, struct file *file)
+{
+ /* note: releasing the wdt in NOWAYOUT-mode does not stop it */
+ return 0;
+}
+
+static const struct file_operations fxos8700_acc_fops = {
+ .owner = THIS_MODULE,
+ .open = fxos8700_acc_open,
+ .release = fxos8700_acc_release,
+ .unlocked_ioctl = fxos8700_acc_ioctl,
+};
+
+/* mag char miscdevice */
+static long fxos8700_mag_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct fxos8700_data *pdata = file->private_data;
+ void __user *argp = (void __user *)arg;
+ struct fxos8700_data_axis data;
+ long ret = 0;
+ short sdata[3];
+ int enable;
+ int delay;
+ int position;
+
+ if (!pdata) {
+ printk(KERN_ERR "fxos8700 struct datt point is NULL.");
+ return -EFAULT;
+ }
+
+ switch (cmd) {
+ case SENSOR_GET_MODEL_NAME:
+ if (copy_to_user(argp, "FXOS8700 MAG", strlen("FXOS8700 MAG") + 1)) {
+ printk(KERN_ERR "SENSOR_GET_MODEL_NAME copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ break;
+ case SENSOR_GET_POWER_STATUS:
+ enable = atomic_read(&pdata->mag_active);
+ if (copy_to_user(argp, &enable, sizeof(int))) {
+ printk(KERN_ERR "SENSOR_SET_POWER_STATUS copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ break;
+ case SENSOR_SET_POWER_STATUS:
+ if (copy_from_user(&enable, argp, sizeof(int))) {
+ printk(KERN_ERR "SENSOR_SET_POWER_STATUS copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ if (pdata->client) {
+ ret = fxos8700_change_mode(pdata->client, FXOS8700_TYPE_MAG,
+ enable ? FXOS8700_ACTIVED : FXOS8700_STANDBY);
+ if (!ret)
+ atomic_set(&pdata->mag_active, enable);
+ }
+ break;
+ case SENSOR_GET_DELAY_TIME:
+ delay = atomic_read(&pdata->mag_delay);
+ if (copy_to_user(argp, &delay, sizeof(delay))) {
+ printk(KERN_ERR "SENSOR_GET_DELAY_TIME copy_to_user failed.");
+ return -EFAULT;
+ }
+ break;
+ case SENSOR_SET_DELAY_TIME:
+ if (copy_from_user(&delay, argp, sizeof(int))) {
+ printk(KERN_ERR "SENSOR_SET_DELAY_TIME copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ if (pdata->client && delay > 0 && delay <= 500) {
+ ret = fxos8700_set_odr(pdata->client, FXOS8700_TYPE_MAG, delay);
+ if (!ret)
+ atomic_set(&pdata->mag_delay, delay);
+ }
+ break;
+ case SENSOR_GET_RAW_DATA:
+ position = atomic_read(&pdata->position);
+ ret = fxos8700_read_data(pdata->client, &data, FXOS8700_TYPE_MAG);
+ if (!ret) {
+ fxos8700_data_convert(&data, position);
+ sdata[0] = data.x;
+ sdata[1] = data.y;
+ sdata[2] = data.z;
+ if (copy_to_user(argp, sdata, sizeof(sdata))) {
+ printk(KERN_ERR "SENSOR_GET_RAW_DATA copy_to_user failed.");
+ ret = -EFAULT;
+ }
+ }
+ break;
+ default:
+ ret = -1;
+ }
+ return ret;
+}
+
+static int fxos8700_mag_open(struct inode *inode, struct file *file)
+{
+ file->private_data = g_fxos8700_data;
+ return nonseekable_open(inode, file);
+}
+
+static int fxos8700_mag_release(struct inode *inode, struct file *file)
+{
+ /* note: releasing the wdt in NOWAYOUT-mode does not stop it */
+ return 0;
+}
+
+static const struct file_operations fxos8700_mag_fops = {
+ .owner = THIS_MODULE,
+ .open = fxos8700_mag_open,
+ .release = fxos8700_mag_release,
+ .unlocked_ioctl = fxos8700_mag_ioctl,
+};
+
+static struct miscdevice fxos8700_acc_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "FreescaleAccelerometer",
+ .fops = &fxos8700_acc_fops,
+};
+
+static struct miscdevice fxos8700_mag_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "FreescaleMagnetometer",
+ .fops = &fxos8700_mag_fops,
+};
+
+static ssize_t fxos8700_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct miscdevice *misc_dev = dev_get_drvdata(dev);
+ struct fxos8700_data *pdata = g_fxos8700_data;
+ int enable = 0;
+
+ if (pdata->acc_miscdev == misc_dev)
+ enable = atomic_read(&pdata->acc_active);
+ if (pdata->mag_miscdev == misc_dev)
+ enable = atomic_read(&pdata->mag_active);
+
+ return sprintf(buf, "%d\n", enable);
+}
+
+static ssize_t fxos8700_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct miscdevice *misc_dev = dev_get_drvdata(dev);
+ struct fxos8700_data *pdata = g_fxos8700_data;
+ struct i2c_client *client = pdata->client;
+ unsigned long enable;
+ int type;
+ int ret;
+
+ if (kstrtoul(buf, 10, &enable) < 0)
+ return -EINVAL;
+
+ if (misc_dev == pdata->acc_miscdev)
+ type = FXOS8700_TYPE_ACC;
+ if (misc_dev == pdata->mag_miscdev)
+ type = FXOS8700_TYPE_MAG;
+ enable = (enable > 0 ? FXOS8700_ACTIVED : FXOS8700_STANDBY);
+ ret = fxos8700_change_mode(client, type, enable);
+ if (!ret) {
+ if (type == FXOS8700_TYPE_ACC) {
+ atomic_set(&pdata->acc_active, enable);
+ atomic_set(&pdata->acc_active_poll, enable);
+ } else {
+ atomic_set(&pdata->mag_active, enable);
+ atomic_set(&pdata->mag_active_poll, enable);
+ }
+ }
+ return count;
+}
+
+static ssize_t fxos8700_poll_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct miscdevice *misc_dev = dev_get_drvdata(dev);
+ struct fxos8700_data *pdata = g_fxos8700_data;
+ int poll_delay = 0;
+
+ if (pdata->acc_miscdev == misc_dev)
+ poll_delay = atomic_read(&pdata->acc_delay);
+ if (pdata->mag_miscdev == misc_dev)
+ poll_delay = atomic_read(&pdata->mag_delay);
+
+ return sprintf(buf, "%d\n", poll_delay);
+}
+
+
+static ssize_t fxos8700_poll_delay_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct miscdevice *misc_dev = dev_get_drvdata(dev);
+ struct fxos8700_data *pdata = g_fxos8700_data;
+ struct i2c_client *client = pdata->client;
+ unsigned long delay;
+ int type;
+ int ret;
+
+ if (kstrtoul(buf, 10, &delay) < 0)
+ return -EINVAL;
+
+ if (misc_dev == pdata->acc_miscdev)
+ type = FXOS8700_TYPE_ACC;
+ if (misc_dev == pdata->mag_miscdev)
+ type = FXOS8700_TYPE_MAG;
+ ret = fxos8700_set_odr(client, type, delay);
+ if (!ret) {
+ if (type == FXOS8700_TYPE_ACC)
+ atomic_set(&pdata->acc_delay, delay);
+ else
+ atomic_set(&pdata->mag_delay, delay);
+ }
+ return count;
+}
+
+static ssize_t fxos8700_position_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fxos8700_data *pdata = g_fxos8700_data;
+ unsigned long position = atomic_read(&pdata->position);
+
+ return sprintf(buf, "%ld\n", position);
+}
+
+static ssize_t fxos8700_position_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long position;
+ struct fxos8700_data *pdata = g_fxos8700_data;
+
+ if (kstrtoul(buf, 10, &position) < 0)
+ return -EINVAL;
+
+ atomic_set(&pdata->position, position);
+ return count;
+}
+
+static ssize_t fxos8700_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fxos8700_data *pdata = g_fxos8700_data;
+ unsigned long range = atomic_read(&pdata->range);
+
+ return sprintf(buf, "%ld\n", range);
+}
+
+static ssize_t fxos8700_range_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long range;
+ struct fxos8700_data *pdata = g_fxos8700_data;
+ struct i2c_client *client = pdata->client;
+ int ret;
+
+ if (kstrtoul(buf, 10, &range) < 0)
+ return -EINVAL;
+
+ if (range == atomic_read(&pdata->range))
+ return count;
+
+ if (atomic_read(&pdata->acc_active) | atomic_read(&pdata->mag_active))
+ printk(KERN_INFO "Pls set the sensor standby and then actived\n");
+ ret = fxos8700_change_range(client, range);
+ if (!ret)
+ atomic_set(&pdata->range, range);
+
+ return count;
+}
+
+static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, fxos8700_enable_show, fxos8700_enable_store);
+static DEVICE_ATTR(poll_delay, S_IWUSR | S_IRUGO, fxos8700_poll_delay_show, fxos8700_poll_delay_store);
+static DEVICE_ATTR(position, S_IWUSR | S_IRUGO, fxos8700_position_show, fxos8700_position_store);
+static DEVICE_ATTR(range, S_IWUSR | S_IRUGO, fxos8700_range_show, fxos8700_range_store);
+
+static struct attribute *fxos8700_attributes[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_poll_delay.attr,
+ &dev_attr_position.attr,
+ &dev_attr_range.attr,
+ NULL
+};
+
+static const struct attribute_group fxos8700_attr_group = {
+ .attrs = fxos8700_attributes,
+};
+
+static int fxos8700_register_sysfs_device(struct fxos8700_data *pdata)
+{
+ struct miscdevice *misc_dev = NULL;
+ int err = -1;
+
+ /* register sysfs for acc */
+ misc_dev = pdata->acc_miscdev;
+ err = sysfs_create_group(&misc_dev->this_device->kobj, &fxos8700_attr_group);
+ if (err)
+ goto out;
+
+ /* register sysfs for mag */
+ misc_dev = pdata->mag_miscdev;
+ err = sysfs_create_group(&misc_dev->this_device->kobj, &fxos8700_attr_group);
+ if (err)
+ goto err_register_sysfs;
+ return 0;
+err_register_sysfs:
+ misc_dev = pdata->acc_miscdev;
+ sysfs_remove_group(&misc_dev->this_device->kobj, &fxos8700_attr_group);
+ printk("reigster mag sysfs error\n");
+out:
+ printk("reigster acc sysfs error\n");
+ return err;
+}
+
+static int fxos8700_unregister_sysfs_device(struct fxos8700_data *pdata)
+{
+ struct miscdevice *misc_dev;
+ misc_dev = pdata->acc_miscdev;
+ sysfs_remove_group(&misc_dev->this_device->kobj, &fxos8700_attr_group);
+
+ misc_dev = pdata->mag_miscdev;
+ sysfs_remove_group(&misc_dev->this_device->kobj, &fxos8700_attr_group);
+ return 0;
+}
+
+static void fxos8700_report(struct input_polled_dev *dev, int type)
+{
+ struct fxos8700_data_axis data;
+ struct fxos8700_data *pdata = g_fxos8700_data;
+ struct input_dev *idev = pdata->input_polled->input;
+ int position;
+ int ret;
+
+ position = atomic_read(&pdata->position);
+ ret = fxos8700_read_data(pdata->client, &data, type);
+ if (!ret) {
+ fxos8700_data_convert(&data, position);
+ input_report_abs(idev, ABS_X, data.x);
+ input_report_abs(idev, ABS_Y, data.y);
+ input_report_abs(idev, ABS_Z, data.z);
+ input_sync(idev);
+ }
+}
+
+static void fxos8700_poll(struct input_polled_dev *dev)
+{
+ struct fxos8700_data *pdata = g_fxos8700_data;
+ int type;
+
+ if (!(atomic_read(&pdata->acc_active_poll) ||
+ atomic_read(&pdata->mag_active_poll)))
+ return;
+
+ if (atomic_read(&pdata->acc_active_poll))
+ type = FXOS8700_TYPE_ACC;
+ if (atomic_read(&pdata->mag_active_poll))
+ type =FXOS8700_TYPE_MAG;
+ fxos8700_report(dev, type);
+}
+
+static int fxo8700_register_polled_device(struct fxos8700_data *pdata)
+{
+ struct input_polled_dev *ipoll_dev;
+ struct input_dev *idev;
+ int error;
+
+ ipoll_dev = input_allocate_polled_device();
+ if (!ipoll_dev)
+ return -ENOMEM;
+
+ ipoll_dev->private = pdata;
+ ipoll_dev->poll = fxos8700_poll;
+ ipoll_dev->poll_interval = FXOS8700_POLL_INTERVAL;
+ ipoll_dev->poll_interval_min = FXOS8700_POLL_MIN;
+ ipoll_dev->poll_interval_max = FXOS8700_POLL_MAX;
+ idev = ipoll_dev->input;
+ idev->name = FXOS8700_DRIVER;
+ idev->id.bustype = BUS_I2C;
+ idev->dev.parent = &pdata->client->dev;
+
+ idev->evbit[0] = BIT_MASK(EV_ABS);
+ input_set_abs_params(idev, ABS_X, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
+ input_set_abs_params(idev, ABS_Y, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
+ input_set_abs_params(idev, ABS_Z, ABSMIN_ACC_VAL, ABSMAX_ACC_VAL, 0, 0);
+
+ error = input_register_polled_device(ipoll_dev);
+ if (error) {
+ input_free_polled_device(ipoll_dev);
+ return error;
+ }
+
+ pdata->input_polled = ipoll_dev;
+
+ return 0;
+}
+
+static int fxos8700_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int result, client_id;
+ struct fxos8700_data *pdata;
+ struct i2c_adapter *adapter;
+
+ adapter = to_i2c_adapter(client->dev.parent);
+ result = i2c_check_functionality(adapter,
+ I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA);
+ if (!result)
+ goto err_out;
+
+ client_id = i2c_smbus_read_byte_data(client, FXOS8700_WHO_AM_I);
+ if (client_id != FXOS8700_DEVICE_ID && client_id != FXOS8700_PRE_DEVICE_ID) {
+ dev_err(&client->dev,
+ "read chip ID 0x%x is not equal to 0x%x or 0x%x\n",
+ result, FXOS8700_DEVICE_ID, FXOS8700_PRE_DEVICE_ID);
+ result = -EINVAL;
+ goto err_out;
+ }
+ pdata = kzalloc(sizeof(struct fxos8700_data), GFP_KERNEL);
+ if (!pdata) {
+ result = -ENOMEM;
+ dev_err(&client->dev, "alloc data memory error!\n");
+ goto err_out;
+ }
+ g_fxos8700_data = pdata;
+ pdata->client = client;
+ atomic_set(&pdata->acc_delay, FXOS8700_DELAY_DEFAULT);
+ atomic_set(&pdata->mag_delay, FXOS8700_DELAY_DEFAULT);
+ i2c_set_clientdata(client, pdata);
+
+ result = misc_register(&fxos8700_acc_device);
+ if (result != 0) {
+ printk(KERN_ERR "register acc miscdevice error");
+ goto err_regsiter_acc_misc;
+ }
+ pdata->acc_miscdev = &fxos8700_acc_device;
+
+ result = misc_register(&fxos8700_mag_device);
+ if (result != 0) {
+ printk(KERN_ERR "register acc miscdevice error");
+ goto err_regsiter_mag_misc;
+ }
+ pdata->mag_miscdev = &fxos8700_mag_device;
+
+ /* for debug */
+ if (client->irq <= 0) {
+ result = fxo8700_register_polled_device(g_fxos8700_data);
+ if (result)
+ dev_err(&client->dev,
+ "IRQ GPIO conf. error %d, error %d\n",
+ client->irq, result);
+ }
+
+ result = fxos8700_register_sysfs_device(pdata);
+ if (result) {
+ dev_err(&client->dev, "create device file failed!\n");
+ result = -EINVAL;
+ goto err_register_sys;
+ }
+ fxos8700_device_init(client);
+ printk("fxos8700 device driver probe successfully");
+ return 0;
+err_register_sys:
+ misc_deregister(&fxos8700_mag_device);
+ pdata->mag_miscdev = NULL;
+err_regsiter_mag_misc:
+ misc_deregister(&fxos8700_acc_device);
+ pdata->acc_miscdev = NULL;
+err_regsiter_acc_misc:
+ i2c_set_clientdata(client, NULL);
+ kfree(pdata);
+err_out:
+ return result;
+}
+
+static int fxos8700_remove(struct i2c_client *client)
+{
+ struct fxos8700_data *pdata = i2c_get_clientdata(client);
+ if (!pdata)
+ return 0;
+ fxos8700_device_stop(client);
+ if (client->irq <= 0) {
+ input_unregister_polled_device(pdata->input_polled);
+ input_free_polled_device(pdata->input_polled);
+ }
+ fxos8700_unregister_sysfs_device(pdata);
+ misc_deregister(&fxos8700_acc_device);
+ misc_deregister(&fxos8700_mag_device);
+ kfree(pdata);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fxos8700_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fxos8700_data *pdata = i2c_get_clientdata(client);
+ if (atomic_read(&pdata->acc_active) || atomic_read(&pdata->mag_active))
+ fxos8700_device_stop(client);
+ return 0;
+}
+
+static int fxos8700_resume(struct device *dev)
+{
+ int ret = 0;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fxos8700_data *pdata = i2c_get_clientdata(client);
+ if (atomic_read(&pdata->acc_active))
+ fxos8700_change_mode(client, FXOS8700_TYPE_ACC, FXOS8700_ACTIVED);
+ if (atomic_read(&pdata->mag_active))
+ fxos8700_change_mode(client, FXOS8700_TYPE_MAG, FXOS8700_ACTIVED);
+ return ret;
+}
+#endif
+
+static const struct i2c_device_id fxos8700_id[] = {
+ {"fxos8700", 0},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, fxos8700_id);
+
+static SIMPLE_DEV_PM_OPS(fxos8700_pm_ops, fxos8700_suspend, fxos8700_resume);
+static struct i2c_driver fxos8700_driver = {
+ .driver = {
+ .name = FXOS8700_DRIVER,
+ .owner = THIS_MODULE,
+ .pm = &fxos8700_pm_ops,
+ },
+ .probe = fxos8700_probe,
+ .remove = fxos8700_remove,
+ .id_table = fxos8700_id,
+};
+
+module_i2c_driver(fxos8700_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("FXOS8700 6-Axis Acc and Mag Combo Sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c
index f84b53d6ce50..6c02b3dba583 100644
--- a/drivers/misc/sram.c
+++ b/drivers/misc/sram.c
@@ -26,7 +26,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
-#define SRAM_GRANULARITY 32
+#define SRAM_GRANULARITY 4096
struct sram_partition {
void __iomem *base;
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index f2eeb38efa65..7e803fc454d1 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -23,8 +23,6 @@ if MMC
source "drivers/mmc/core/Kconfig"
-source "drivers/mmc/card/Kconfig"
-
source "drivers/mmc/host/Kconfig"
endif # MMC
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 400756ec7c49..416b6d1c9ec6 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -5,5 +5,4 @@
subdir-ccflags-$(CONFIG_MMC_DEBUG) := -DDEBUG
obj-$(CONFIG_MMC) += core/
-obj-$(CONFIG_MMC) += card/
obj-$(subst m,y,$(CONFIG_MMC)) += host/
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
deleted file mode 100644
index 5562308699bc..000000000000
--- a/drivers/mmc/card/Kconfig
+++ /dev/null
@@ -1,70 +0,0 @@
-#
-# MMC/SD card drivers
-#
-
-comment "MMC/SD/SDIO Card Drivers"
-
-config MMC_BLOCK
- tristate "MMC block device driver"
- depends on BLOCK
- default y
- help
- Say Y here to enable the MMC block device driver support.
- This provides a block device driver, which you can use to
- mount the filesystem. Almost everyone wishing MMC support
- should say Y or M here.
-
-config MMC_BLOCK_MINORS
- int "Number of minors per block device"
- depends on MMC_BLOCK
- range 4 256
- default 8
- help
- Number of minors per block device. One is needed for every
- partition on the disk (plus one for the whole disk).
-
- Number of total MMC minors available is 256, so your number
- of supported block devices will be limited to 256 divided
- by this number.
-
- Default is 8 to be backwards compatible with previous
- hardwired device numbering.
-
- If unsure, say 8 here.
-
-config MMC_BLOCK_BOUNCE
- bool "Use bounce buffer for simple hosts"
- depends on MMC_BLOCK
- default y
- help
- SD/MMC is a high latency protocol where it is crucial to
- send large requests in order to get high performance. Many
- controllers, however, are restricted to continuous memory
- (i.e. they can't do scatter-gather), something the kernel
- rarely can provide.
-
- Say Y here to help these restricted hosts by bouncing
- requests back and forth from a large buffer. You will get
- a big performance gain at the cost of up to 64 KiB of
- physical memory.
-
- If unsure, say Y here.
-
-config SDIO_UART
- tristate "SDIO UART/GPS class support"
- depends on TTY
- help
- SDIO function driver for SDIO cards that implements the UART
- class, as well as the GPS class which appears like a UART.
-
-config MMC_TEST
- tristate "MMC host test driver"
- help
- Development driver that performs a series of reads and writes
- to a memory card in order to expose certain well known bugs
- in host controllers. The tests are executed by writing to the
- "test" file in debugfs under each card. Note that whatever is
- on your card will be overwritten by these tests.
-
- This driver is only of interest to those developing or
- testing a host driver. Most people should say N here.
diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile
deleted file mode 100644
index c73b406a06cd..000000000000
--- a/drivers/mmc/card/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Makefile for MMC/SD card drivers
-#
-
-obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
-mmc_block-objs := block.o queue.o
-obj-$(CONFIG_MMC_TEST) += mmc_test.o
-
-obj-$(CONFIG_SDIO_UART) += sdio_uart.o
-
diff --git a/drivers/mmc/card/block.h b/drivers/mmc/card/block.h
deleted file mode 100644
index cdabb2ee74be..000000000000
--- a/drivers/mmc/card/block.h
+++ /dev/null
@@ -1 +0,0 @@
-int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req);
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
deleted file mode 100644
index 8037f73a109a..000000000000
--- a/drivers/mmc/card/queue.c
+++ /dev/null
@@ -1,557 +0,0 @@
-/*
- * linux/drivers/mmc/card/queue.c
- *
- * Copyright (C) 2003 Russell King, All Rights Reserved.
- * Copyright 2006-2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/blkdev.h>
-#include <linux/freezer.h>
-#include <linux/kthread.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-
-#include "queue.h"
-#include "block.h"
-
-#define MMC_QUEUE_BOUNCESZ 65536
-
-/*
- * Prepare a MMC request. This just filters out odd stuff.
- */
-static int mmc_prep_request(struct request_queue *q, struct request *req)
-{
- struct mmc_queue *mq = q->queuedata;
-
- /*
- * We only like normal block requests and discards.
- */
- if (req->cmd_type != REQ_TYPE_FS && req_op(req) != REQ_OP_DISCARD &&
- req_op(req) != REQ_OP_SECURE_ERASE) {
- blk_dump_rq_flags(req, "MMC bad request");
- return BLKPREP_KILL;
- }
-
- if (mq && (mmc_card_removed(mq->card) || mmc_access_rpmb(mq)))
- return BLKPREP_KILL;
-
- req->cmd_flags |= REQ_DONTPREP;
-
- return BLKPREP_OK;
-}
-
-static int mmc_queue_thread(void *d)
-{
- struct mmc_queue *mq = d;
- struct request_queue *q = mq->queue;
-
- current->flags |= PF_MEMALLOC;
-
- down(&mq->thread_sem);
- do {
- struct request *req = NULL;
-
- spin_lock_irq(q->queue_lock);
- set_current_state(TASK_INTERRUPTIBLE);
- req = blk_fetch_request(q);
- mq->mqrq_cur->req = req;
- spin_unlock_irq(q->queue_lock);
-
- if (req || mq->mqrq_prev->req) {
- bool req_is_special = mmc_req_is_special(req);
-
- set_current_state(TASK_RUNNING);
- mmc_blk_issue_rq(mq, req);
- cond_resched();
- if (mq->flags & MMC_QUEUE_NEW_REQUEST) {
- mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
- continue; /* fetch again */
- }
-
- /*
- * Current request becomes previous request
- * and vice versa.
- * In case of special requests, current request
- * has been finished. Do not assign it to previous
- * request.
- */
- if (req_is_special)
- mq->mqrq_cur->req = NULL;
-
- mq->mqrq_prev->brq.mrq.data = NULL;
- mq->mqrq_prev->req = NULL;
- swap(mq->mqrq_prev, mq->mqrq_cur);
- } else {
- if (kthread_should_stop()) {
- set_current_state(TASK_RUNNING);
- break;
- }
- up(&mq->thread_sem);
- schedule();
- down(&mq->thread_sem);
- }
- } while (1);
- up(&mq->thread_sem);
-
- return 0;
-}
-
-/*
- * Generic MMC request handler. This is called for any queue on a
- * particular host. When the host is not busy, we look for a request
- * on any queue on this host, and attempt to issue it. This may
- * not be the queue we were asked to process.
- */
-static void mmc_request_fn(struct request_queue *q)
-{
- struct mmc_queue *mq = q->queuedata;
- struct request *req;
- unsigned long flags;
- struct mmc_context_info *cntx;
-
- if (!mq) {
- while ((req = blk_fetch_request(q)) != NULL) {
- req->cmd_flags |= REQ_QUIET;
- __blk_end_request_all(req, -EIO);
- }
- return;
- }
-
- cntx = &mq->card->host->context_info;
- if (!mq->mqrq_cur->req && mq->mqrq_prev->req) {
- /*
- * New MMC request arrived when MMC thread may be
- * blocked on the previous request to be complete
- * with no current request fetched
- */
- spin_lock_irqsave(&cntx->lock, flags);
- if (cntx->is_waiting_last_req) {
- cntx->is_new_req = true;
- wake_up_interruptible(&cntx->wait);
- }
- spin_unlock_irqrestore(&cntx->lock, flags);
- } else if (!mq->mqrq_cur->req && !mq->mqrq_prev->req)
- wake_up_process(mq->thread);
-}
-
-static struct scatterlist *mmc_alloc_sg(int sg_len, int *err)
-{
- struct scatterlist *sg;
-
- sg = kmalloc(sizeof(struct scatterlist)*sg_len, GFP_KERNEL);
- if (!sg)
- *err = -ENOMEM;
- else {
- *err = 0;
- sg_init_table(sg, sg_len);
- }
-
- return sg;
-}
-
-static void mmc_queue_setup_discard(struct request_queue *q,
- struct mmc_card *card)
-{
- unsigned max_discard;
-
- max_discard = mmc_calc_max_discard(card);
- if (!max_discard)
- return;
-
- queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
- blk_queue_max_discard_sectors(q, max_discard);
- if (card->erased_byte == 0 && !mmc_can_discard(card))
- q->limits.discard_zeroes_data = 1;
- q->limits.discard_granularity = card->pref_erase << 9;
- /* granularity must not be greater than max. discard */
- if (card->pref_erase > max_discard)
- q->limits.discard_granularity = 0;
- if (mmc_can_secure_erase_trim(card))
- queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, q);
-}
-
-/**
- * mmc_init_queue - initialise a queue structure.
- * @mq: mmc queue
- * @card: mmc card to attach this queue
- * @lock: queue lock
- * @subname: partition subname
- *
- * Initialise a MMC card request queue.
- */
-int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
- spinlock_t *lock, const char *subname)
-{
- struct mmc_host *host = card->host;
- u64 limit = BLK_BOUNCE_HIGH;
- int ret;
- struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
- struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
-
- if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
- limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
-
- mq->card = card;
- mq->queue = blk_init_queue(mmc_request_fn, lock);
- if (!mq->queue)
- return -ENOMEM;
-
- mq->mqrq_cur = mqrq_cur;
- mq->mqrq_prev = mqrq_prev;
- mq->queue->queuedata = mq;
-
- blk_queue_prep_rq(mq->queue, mmc_prep_request);
- queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
- queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, mq->queue);
- if (mmc_can_erase(card))
- mmc_queue_setup_discard(mq->queue, card);
-
-#ifdef CONFIG_MMC_BLOCK_BOUNCE
- if (host->max_segs == 1) {
- unsigned int bouncesz;
-
- bouncesz = MMC_QUEUE_BOUNCESZ;
-
- if (bouncesz > host->max_req_size)
- bouncesz = host->max_req_size;
- if (bouncesz > host->max_seg_size)
- bouncesz = host->max_seg_size;
- if (bouncesz > (host->max_blk_count * 512))
- bouncesz = host->max_blk_count * 512;
-
- if (bouncesz > 512) {
- mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
- if (!mqrq_cur->bounce_buf) {
- pr_warn("%s: unable to allocate bounce cur buffer\n",
- mmc_card_name(card));
- } else {
- mqrq_prev->bounce_buf =
- kmalloc(bouncesz, GFP_KERNEL);
- if (!mqrq_prev->bounce_buf) {
- pr_warn("%s: unable to allocate bounce prev buffer\n",
- mmc_card_name(card));
- kfree(mqrq_cur->bounce_buf);
- mqrq_cur->bounce_buf = NULL;
- }
- }
- }
-
- if (mqrq_cur->bounce_buf && mqrq_prev->bounce_buf) {
- blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
- blk_queue_max_hw_sectors(mq->queue, bouncesz / 512);
- blk_queue_max_segments(mq->queue, bouncesz / 512);
- blk_queue_max_segment_size(mq->queue, bouncesz);
-
- mqrq_cur->sg = mmc_alloc_sg(1, &ret);
- if (ret)
- goto cleanup_queue;
-
- mqrq_cur->bounce_sg =
- mmc_alloc_sg(bouncesz / 512, &ret);
- if (ret)
- goto cleanup_queue;
-
- mqrq_prev->sg = mmc_alloc_sg(1, &ret);
- if (ret)
- goto cleanup_queue;
-
- mqrq_prev->bounce_sg =
- mmc_alloc_sg(bouncesz / 512, &ret);
- if (ret)
- goto cleanup_queue;
- }
- }
-#endif
-
- if (!mqrq_cur->bounce_buf && !mqrq_prev->bounce_buf) {
- blk_queue_bounce_limit(mq->queue, limit);
- blk_queue_max_hw_sectors(mq->queue,
- min(host->max_blk_count, host->max_req_size / 512));
- blk_queue_max_segments(mq->queue, host->max_segs);
- blk_queue_max_segment_size(mq->queue, host->max_seg_size);
-
- mqrq_cur->sg = mmc_alloc_sg(host->max_segs, &ret);
- if (ret)
- goto cleanup_queue;
-
-
- mqrq_prev->sg = mmc_alloc_sg(host->max_segs, &ret);
- if (ret)
- goto cleanup_queue;
- }
-
- sema_init(&mq->thread_sem, 1);
-
- mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s",
- host->index, subname ? subname : "");
-
- if (IS_ERR(mq->thread)) {
- ret = PTR_ERR(mq->thread);
- goto free_bounce_sg;
- }
-
- return 0;
- free_bounce_sg:
- kfree(mqrq_cur->bounce_sg);
- mqrq_cur->bounce_sg = NULL;
- kfree(mqrq_prev->bounce_sg);
- mqrq_prev->bounce_sg = NULL;
-
- cleanup_queue:
- kfree(mqrq_cur->sg);
- mqrq_cur->sg = NULL;
- kfree(mqrq_cur->bounce_buf);
- mqrq_cur->bounce_buf = NULL;
-
- kfree(mqrq_prev->sg);
- mqrq_prev->sg = NULL;
- kfree(mqrq_prev->bounce_buf);
- mqrq_prev->bounce_buf = NULL;
-
- blk_cleanup_queue(mq->queue);
- return ret;
-}
-
-void mmc_cleanup_queue(struct mmc_queue *mq)
-{
- struct request_queue *q = mq->queue;
- unsigned long flags;
- struct mmc_queue_req *mqrq_cur = mq->mqrq_cur;
- struct mmc_queue_req *mqrq_prev = mq->mqrq_prev;
-
- /* Make sure the queue isn't suspended, as that will deadlock */
- mmc_queue_resume(mq);
-
- /* Then terminate our worker thread */
- kthread_stop(mq->thread);
-
- /* Empty the queue */
- spin_lock_irqsave(q->queue_lock, flags);
- q->queuedata = NULL;
- blk_start_queue(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
-
- kfree(mqrq_cur->bounce_sg);
- mqrq_cur->bounce_sg = NULL;
-
- kfree(mqrq_cur->sg);
- mqrq_cur->sg = NULL;
-
- kfree(mqrq_cur->bounce_buf);
- mqrq_cur->bounce_buf = NULL;
-
- kfree(mqrq_prev->bounce_sg);
- mqrq_prev->bounce_sg = NULL;
-
- kfree(mqrq_prev->sg);
- mqrq_prev->sg = NULL;
-
- kfree(mqrq_prev->bounce_buf);
- mqrq_prev->bounce_buf = NULL;
-
- mq->card = NULL;
-}
-EXPORT_SYMBOL(mmc_cleanup_queue);
-
-int mmc_packed_init(struct mmc_queue *mq, struct mmc_card *card)
-{
- struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
- struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
- int ret = 0;
-
-
- mqrq_cur->packed = kzalloc(sizeof(struct mmc_packed), GFP_KERNEL);
- if (!mqrq_cur->packed) {
- pr_warn("%s: unable to allocate packed cmd for mqrq_cur\n",
- mmc_card_name(card));
- ret = -ENOMEM;
- goto out;
- }
-
- mqrq_prev->packed = kzalloc(sizeof(struct mmc_packed), GFP_KERNEL);
- if (!mqrq_prev->packed) {
- pr_warn("%s: unable to allocate packed cmd for mqrq_prev\n",
- mmc_card_name(card));
- kfree(mqrq_cur->packed);
- mqrq_cur->packed = NULL;
- ret = -ENOMEM;
- goto out;
- }
-
- INIT_LIST_HEAD(&mqrq_cur->packed->list);
- INIT_LIST_HEAD(&mqrq_prev->packed->list);
-
-out:
- return ret;
-}
-
-void mmc_packed_clean(struct mmc_queue *mq)
-{
- struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
- struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
-
- kfree(mqrq_cur->packed);
- mqrq_cur->packed = NULL;
- kfree(mqrq_prev->packed);
- mqrq_prev->packed = NULL;
-}
-
-/**
- * mmc_queue_suspend - suspend a MMC request queue
- * @mq: MMC queue to suspend
- *
- * Stop the block request queue, and wait for our thread to
- * complete any outstanding requests. This ensures that we
- * won't suspend while a request is being processed.
- */
-void mmc_queue_suspend(struct mmc_queue *mq)
-{
- struct request_queue *q = mq->queue;
- unsigned long flags;
-
- if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
- mq->flags |= MMC_QUEUE_SUSPENDED;
-
- spin_lock_irqsave(q->queue_lock, flags);
- blk_stop_queue(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
-
- down(&mq->thread_sem);
- }
-}
-
-/**
- * mmc_queue_resume - resume a previously suspended MMC request queue
- * @mq: MMC queue to resume
- */
-void mmc_queue_resume(struct mmc_queue *mq)
-{
- struct request_queue *q = mq->queue;
- unsigned long flags;
-
- if (mq->flags & MMC_QUEUE_SUSPENDED) {
- mq->flags &= ~MMC_QUEUE_SUSPENDED;
-
- up(&mq->thread_sem);
-
- spin_lock_irqsave(q->queue_lock, flags);
- blk_start_queue(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
- }
-}
-
-static unsigned int mmc_queue_packed_map_sg(struct mmc_queue *mq,
- struct mmc_packed *packed,
- struct scatterlist *sg,
- enum mmc_packed_type cmd_type)
-{
- struct scatterlist *__sg = sg;
- unsigned int sg_len = 0;
- struct request *req;
-
- if (mmc_packed_wr(cmd_type)) {
- unsigned int hdr_sz = mmc_large_sector(mq->card) ? 4096 : 512;
- unsigned int max_seg_sz = queue_max_segment_size(mq->queue);
- unsigned int len, remain, offset = 0;
- u8 *buf = (u8 *)packed->cmd_hdr;
-
- remain = hdr_sz;
- do {
- len = min(remain, max_seg_sz);
- sg_set_buf(__sg, buf + offset, len);
- offset += len;
- remain -= len;
- sg_unmark_end(__sg++);
- sg_len++;
- } while (remain);
- }
-
- list_for_each_entry(req, &packed->list, queuelist) {
- sg_len += blk_rq_map_sg(mq->queue, req, __sg);
- __sg = sg + (sg_len - 1);
- sg_unmark_end(__sg++);
- }
- sg_mark_end(sg + (sg_len - 1));
- return sg_len;
-}
-
-/*
- * Prepare the sg list(s) to be handed of to the host driver
- */
-unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
-{
- unsigned int sg_len;
- size_t buflen;
- struct scatterlist *sg;
- enum mmc_packed_type cmd_type;
- int i;
-
- cmd_type = mqrq->cmd_type;
-
- if (!mqrq->bounce_buf) {
- if (mmc_packed_cmd(cmd_type))
- return mmc_queue_packed_map_sg(mq, mqrq->packed,
- mqrq->sg, cmd_type);
- else
- return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
- }
-
- BUG_ON(!mqrq->bounce_sg);
-
- if (mmc_packed_cmd(cmd_type))
- sg_len = mmc_queue_packed_map_sg(mq, mqrq->packed,
- mqrq->bounce_sg, cmd_type);
- else
- sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
-
- mqrq->bounce_sg_len = sg_len;
-
- buflen = 0;
- for_each_sg(mqrq->bounce_sg, sg, sg_len, i)
- buflen += sg->length;
-
- sg_init_one(mqrq->sg, mqrq->bounce_buf, buflen);
-
- return 1;
-}
-
-/*
- * If writing, bounce the data to the buffer before the request
- * is sent to the host driver
- */
-void mmc_queue_bounce_pre(struct mmc_queue_req *mqrq)
-{
- if (!mqrq->bounce_buf)
- return;
-
- if (rq_data_dir(mqrq->req) != WRITE)
- return;
-
- sg_copy_to_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
- mqrq->bounce_buf, mqrq->sg[0].length);
-}
-
-/*
- * If reading, bounce the data from the buffer after the request
- * has been handled by the host driver
- */
-void mmc_queue_bounce_post(struct mmc_queue_req *mqrq)
-{
- if (!mqrq->bounce_buf)
- return;
-
- if (rq_data_dir(mqrq->req) != READ)
- return;
-
- sg_copy_from_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
- mqrq->bounce_buf, mqrq->sg[0].length);
-}
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
deleted file mode 100644
index 342f1e3f301e..000000000000
--- a/drivers/mmc/card/queue.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef MMC_QUEUE_H
-#define MMC_QUEUE_H
-
-static inline bool mmc_req_is_special(struct request *req)
-{
- return req &&
- (req_op(req) == REQ_OP_FLUSH ||
- req_op(req) == REQ_OP_DISCARD ||
- req_op(req) == REQ_OP_SECURE_ERASE);
-}
-
-struct request;
-struct task_struct;
-
-struct mmc_blk_request {
- struct mmc_request mrq;
- struct mmc_command sbc;
- struct mmc_command cmd;
- struct mmc_command stop;
- struct mmc_data data;
- int retune_retry_done;
-};
-
-enum mmc_packed_type {
- MMC_PACKED_NONE = 0,
- MMC_PACKED_WRITE,
-};
-
-#define mmc_packed_cmd(type) ((type) != MMC_PACKED_NONE)
-#define mmc_packed_wr(type) ((type) == MMC_PACKED_WRITE)
-
-struct mmc_packed {
- struct list_head list;
- __le32 cmd_hdr[1024];
- unsigned int blocks;
- u8 nr_entries;
- u8 retries;
- s16 idx_failure;
-};
-
-struct mmc_queue_req {
- struct request *req;
- struct mmc_blk_request brq;
- struct scatterlist *sg;
- char *bounce_buf;
- struct scatterlist *bounce_sg;
- unsigned int bounce_sg_len;
- struct mmc_async_req mmc_active;
- enum mmc_packed_type cmd_type;
- struct mmc_packed *packed;
-};
-
-struct mmc_queue {
- struct mmc_card *card;
- struct task_struct *thread;
- struct semaphore thread_sem;
- unsigned int flags;
-#define MMC_QUEUE_SUSPENDED (1 << 0)
-#define MMC_QUEUE_NEW_REQUEST (1 << 1)
- void *data;
- struct request_queue *queue;
- struct mmc_queue_req mqrq[2];
- struct mmc_queue_req *mqrq_cur;
- struct mmc_queue_req *mqrq_prev;
-};
-
-extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
- const char *);
-extern void mmc_cleanup_queue(struct mmc_queue *);
-extern void mmc_queue_suspend(struct mmc_queue *);
-extern void mmc_queue_resume(struct mmc_queue *);
-
-extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
- struct mmc_queue_req *);
-extern void mmc_queue_bounce_pre(struct mmc_queue_req *);
-extern void mmc_queue_bounce_post(struct mmc_queue_req *);
-
-extern int mmc_packed_init(struct mmc_queue *, struct mmc_card *);
-extern void mmc_packed_clean(struct mmc_queue *);
-
-extern int mmc_access_rpmb(struct mmc_queue *);
-
-#endif
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index 250f223aaa80..ea5a69b4897f 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -22,3 +22,51 @@ config PWRSEQ_SIMPLE
This driver can also be built as a module. If so, the module
will be called pwrseq_simple.
+
+config MMC_BLOCK
+ tristate "MMC block device driver"
+ depends on BLOCK
+ default y
+ help
+ Say Y here to enable the MMC block device driver support.
+ This provides a block device driver, which you can use to
+ mount the filesystem. Almost everyone wishing MMC support
+ should say Y or M here.
+
+config MMC_BLOCK_MINORS
+ int "Number of minors per block device"
+ depends on MMC_BLOCK
+ range 4 256
+ default 8
+ help
+ Number of minors per block device. One is needed for every
+ partition on the disk (plus one for the whole disk).
+
+ Number of total MMC minors available is 256, so your number
+ of supported block devices will be limited to 256 divided
+ by this number.
+
+ Default is 8 to be backwards compatible with previous
+ hardwired device numbering.
+
+ If unsure, say 8 here.
+
+config SDIO_UART
+ tristate "SDIO UART/GPS class support"
+ depends on TTY
+ help
+ SDIO function driver for SDIO cards that implements the UART
+ class, as well as the GPS class which appears like a UART.
+
+config MMC_TEST
+ tristate "MMC host test driver"
+ help
+ Development driver that performs a series of reads and writes
+ to a memory card in order to expose certain well known bugs
+ in host controllers. The tests are executed by writing to the
+ "test" file in debugfs under each card. Note that whatever is
+ on your card will be overwritten by these tests.
+
+ This driver is only of interest to those developing or
+ testing a host driver. Most people should say N here.
+
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
index f007151dfdc6..449dba872734 100644
--- a/drivers/mmc/core/Makefile
+++ b/drivers/mmc/core/Makefile
@@ -7,8 +7,12 @@ mmc_core-y := core.o bus.o host.o \
mmc.o mmc_ops.o sd.o sd_ops.o \
sdio.o sdio_ops.o sdio_bus.o \
sdio_cis.o sdio_io.o sdio_irq.o \
- quirks.o slot-gpio.o
+ slot-gpio.o
mmc_core-$(CONFIG_OF) += pwrseq.o
obj-$(CONFIG_PWRSEQ_SIMPLE) += pwrseq_simple.o
obj-$(CONFIG_PWRSEQ_EMMC) += pwrseq_emmc.o
mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o
+obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
+mmc_block-objs := block.o queue.o
+obj-$(CONFIG_MMC_TEST) += mmc_test.o
+obj-$(CONFIG_SDIO_UART) += sdio_uart.o
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/core/block.c
index 709a872ed484..2f7465723b14 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/core/block.c
@@ -36,6 +36,7 @@
#include <linux/compat.h>
#include <linux/pm_runtime.h>
#include <linux/idr.h>
+#include <linux/ioprio.h>
#include <linux/mmc/ioctl.h>
#include <linux/mmc/card.h>
@@ -47,6 +48,13 @@
#include "queue.h"
#include "block.h"
+#include "core.h"
+#include "card.h"
+#include "host.h"
+#include "bus.h"
+#include "mmc_ops.h"
+#include "quirks.h"
+#include "sd_ops.h"
MODULE_ALIAS("mmc:block");
#ifdef MODULE_PARAM_PREFIX
@@ -54,21 +62,12 @@ MODULE_ALIAS("mmc:block");
#endif
#define MODULE_PARAM_PREFIX "mmcblk."
-#define INAND_CMD38_ARG_EXT_CSD 113
-#define INAND_CMD38_ARG_ERASE 0x00
-#define INAND_CMD38_ARG_TRIM 0x01
-#define INAND_CMD38_ARG_SECERASE 0x80
-#define INAND_CMD38_ARG_SECTRIM1 0x81
-#define INAND_CMD38_ARG_SECTRIM2 0x88
#define MMC_BLK_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
#define MMC_SANITIZE_REQ_TIMEOUT 240000
#define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16)
#define mmc_req_rel_wr(req) ((req->cmd_flags & REQ_FUA) && \
(rq_data_dir(req) == WRITE))
-#define PACKED_CMD_VER 0x01
-#define PACKED_CMD_WR 0x02
-
static DEFINE_MUTEX(block_mutex);
/*
@@ -87,7 +86,6 @@ static int max_devices;
#define MAX_DEVICES 256
static DEFINE_IDA(mmc_blk_ida);
-static DEFINE_SPINLOCK(mmc_blk_lock);
/*
* There is one mmc_blk_data per slot.
@@ -102,7 +100,6 @@ struct mmc_blk_data {
unsigned int flags;
#define MMC_BLK_CMD23 (1 << 0) /* Can do SET_BLOCK_COUNT for multiblock */
#define MMC_BLK_REL_WR (1 << 1) /* MMC Reliable write support */
-#define MMC_BLK_PACKED_CMD (1 << 2) /* MMC packed command support */
unsigned int usage;
unsigned int read_only;
@@ -112,6 +109,7 @@ struct mmc_blk_data {
#define MMC_BLK_WRITE BIT(1)
#define MMC_BLK_DISCARD BIT(2)
#define MMC_BLK_SECDISCARD BIT(3)
+#define MMC_BLK_CQE_RECOVERY BIT(4)
/*
* Only set in main mmc_blk_data associated
@@ -126,12 +124,6 @@ struct mmc_blk_data {
static DEFINE_MUTEX(open_lock);
-enum {
- MMC_PACKED_NR_IDX = -1,
- MMC_PACKED_NR_ZERO,
- MMC_PACKED_NR_SINGLE,
-};
-
module_param(perdev_minors, int, 0444);
MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
@@ -139,17 +131,6 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
struct mmc_blk_data *md);
static int get_card_status(struct mmc_card *card, u32 *status, int retries);
-static inline void mmc_blk_clear_packed(struct mmc_queue_req *mqrq)
-{
- struct mmc_packed *packed = mqrq->packed;
-
- mqrq->cmd_type = MMC_PACKED_NONE;
- packed->nr_entries = MMC_PACKED_NR_ZERO;
- packed->idx_failure = MMC_PACKED_NR_IDX;
- packed->retries = 0;
- packed->blocks = 0;
-}
-
static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
{
struct mmc_blk_data *md;
@@ -178,11 +159,7 @@ static void mmc_blk_put(struct mmc_blk_data *md)
if (md->usage == 0) {
int devidx = mmc_get_devidx(md->disk);
blk_cleanup_queue(md->queue.queue);
-
- spin_lock(&mmc_blk_lock);
- ida_remove(&mmc_blk_ida, devidx);
- spin_unlock(&mmc_blk_lock);
-
+ ida_simple_remove(&mmc_blk_ida, devidx);
put_disk(md->disk);
kfree(md);
}
@@ -463,12 +440,12 @@ out:
static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
struct mmc_blk_ioc_data *idata)
{
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
- struct mmc_request mrq = {NULL};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
+ struct mmc_request mrq = {};
struct scatterlist sg;
int err;
- int is_rpmb = false;
+ bool is_rpmb = false;
u32 status = 0;
if (!card || !md || !idata)
@@ -746,10 +723,41 @@ static const struct block_device_operations mmc_bdops = {
#endif
};
+static int mmc_blk_part_switch_pre(struct mmc_card *card,
+ unsigned int part_type)
+{
+ int ret = 0;
+
+ if (part_type == EXT_CSD_PART_CONFIG_ACC_RPMB) {
+ if (card->ext_csd.cmdq_en) {
+ ret = mmc_cmdq_disable(card);
+ if (ret)
+ return ret;
+ }
+ mmc_retune_pause(card->host);
+ }
+
+ return ret;
+}
+
+static int mmc_blk_part_switch_post(struct mmc_card *card,
+ unsigned int part_type)
+{
+ int ret = 0;
+
+ if (part_type == EXT_CSD_PART_CONFIG_ACC_RPMB) {
+ mmc_retune_unpause(card->host);
+ if (card->reenable_cmdq && !card->ext_csd.cmdq_en)
+ ret = mmc_cmdq_enable(card);
+ }
+
+ return ret;
+}
+
static inline int mmc_blk_part_switch(struct mmc_card *card,
struct mmc_blk_data *md)
{
- int ret;
+ int ret = 0;
struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev);
if (main_md->part_curr == md->part_type)
@@ -758,8 +766,9 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
if (mmc_card_mmc(card)) {
u8 part_config = card->ext_csd.part_config;
- if (md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB)
- mmc_retune_pause(card->host);
+ ret = mmc_blk_part_switch_pre(card, md->part_type);
+ if (ret)
+ return ret;
part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
part_config |= md->part_type;
@@ -768,30 +777,28 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
EXT_CSD_PART_CONFIG, part_config,
card->ext_csd.part_time);
if (ret) {
- if (md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB)
- mmc_retune_unpause(card->host);
+ mmc_blk_part_switch_post(card, md->part_type);
return ret;
}
card->ext_csd.part_config = part_config;
- if (main_md->part_curr == EXT_CSD_PART_CONFIG_ACC_RPMB)
- mmc_retune_unpause(card->host);
+ ret = mmc_blk_part_switch_post(card, main_md->part_curr);
}
main_md->part_curr = md->part_type;
- return 0;
+ return ret;
}
-static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
+static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks)
{
int err;
u32 result;
__be32 *blocks;
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
struct scatterlist sg;
@@ -801,9 +808,9 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err)
- return (u32)-1;
+ return err;
if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
- return (u32)-1;
+ return -EIO;
memset(&cmd, 0, sizeof(struct mmc_command));
@@ -823,7 +830,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
blocks = kmalloc(4, GFP_KERNEL);
if (!blocks)
- return (u32)-1;
+ return -ENOMEM;
sg_init_one(&sg, blocks, 4);
@@ -833,14 +840,16 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
kfree(blocks);
if (cmd.error || data.error)
- result = (u32)-1;
+ return -EIO;
- return result;
+ *written_blocks = result;
+
+ return 0;
}
static int get_card_status(struct mmc_card *card, u32 *status, int retries)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int err;
cmd.opcode = MMC_SEND_STATUS;
@@ -854,7 +863,7 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries)
}
static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
- bool hw_busy_detect, struct request *req, int *gen_err)
+ bool hw_busy_detect, struct request *req, bool *gen_err)
{
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
int err = 0;
@@ -871,7 +880,7 @@ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
if (status & R1_ERROR) {
pr_err("%s: %s: error sending status cmd, status %#x\n",
req->rq_disk->disk_name, __func__, status);
- *gen_err = 1;
+ *gen_err = true;
}
/* We may rely on the host hw to handle busy detection.*/
@@ -902,10 +911,10 @@ static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
}
static int send_stop(struct mmc_card *card, unsigned int timeout_ms,
- struct request *req, int *gen_err, u32 *stop_status)
+ struct request *req, bool *gen_err, u32 *stop_status)
{
struct mmc_host *host = card->host;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int err;
bool use_r1b_resp = rq_data_dir(req) == WRITE;
@@ -940,7 +949,7 @@ static int send_stop(struct mmc_card *card, unsigned int timeout_ms,
(*stop_status & R1_ERROR)) {
pr_err("%s: %s: general error sending stop command, resp %#x\n",
req->rq_disk->disk_name, __func__, *stop_status);
- *gen_err = 1;
+ *gen_err = true;
}
return card_busy_detect(card, timeout_ms, use_r1b_resp, req, gen_err);
@@ -1014,7 +1023,7 @@ static int mmc_blk_cmd_error(struct request *req, const char *name, int error,
* Otherwise we don't understand what happened, so abort.
*/
static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
- struct mmc_blk_request *brq, int *ecc_err, int *gen_err)
+ struct mmc_blk_request *brq, bool *ecc_err, bool *gen_err)
{
bool prev_cmd_status_valid = true;
u32 status, stop_status = 0;
@@ -1053,7 +1062,7 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
if ((status & R1_CARD_ECC_FAILED) ||
(brq->stop.resp[0] & R1_CARD_ECC_FAILED) ||
(brq->cmd.resp[0] & R1_CARD_ECC_FAILED))
- *ecc_err = 1;
+ *ecc_err = true;
/* Flag General errors */
if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ)
@@ -1062,7 +1071,7 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
pr_err("%s: %s: general error sending stop or status command, stop cmd response %#x, card status %#x\n",
req->rq_disk->disk_name, __func__,
brq->stop.resp[0], status);
- *gen_err = 1;
+ *gen_err = true;
}
/*
@@ -1085,7 +1094,7 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
}
if (stop_status & R1_CARD_ECC_FAILED)
- *ecc_err = 1;
+ *ecc_err = true;
}
/* Check for set block count errors */
@@ -1154,7 +1163,7 @@ static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type)
int mmc_access_rpmb(struct mmc_queue *mq)
{
- struct mmc_blk_data *md = mq->data;
+ struct mmc_blk_data *md = mq->blkdata;
/*
* If this is a RPMB partition access, return ture
*/
@@ -1164,16 +1173,16 @@ int mmc_access_rpmb(struct mmc_queue *mq)
return false;
}
-static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
+static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
{
- struct mmc_blk_data *md = mq->data;
+ struct mmc_blk_data *md = mq->blkdata;
struct mmc_card *card = md->queue.card;
unsigned int from, nr, arg;
int err = 0, type = MMC_BLK_DISCARD;
if (!mmc_can_erase(card)) {
err = -EOPNOTSUPP;
- goto out;
+ goto fail;
}
from = blk_rq_pos(req);
@@ -1185,32 +1194,29 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
arg = MMC_TRIM_ARG;
else
arg = MMC_ERASE_ARG;
-retry:
- if (card->quirks & MMC_QUIRK_INAND_CMD38) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- INAND_CMD38_ARG_EXT_CSD,
- arg == MMC_TRIM_ARG ?
- INAND_CMD38_ARG_TRIM :
- INAND_CMD38_ARG_ERASE,
- 0);
- if (err)
- goto out;
- }
- err = mmc_erase(card, from, nr, arg);
-out:
- if (err == -EIO && !mmc_blk_reset(md, card->host, type))
- goto retry;
+ do {
+ err = 0;
+ if (card->quirks & MMC_QUIRK_INAND_CMD38) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ INAND_CMD38_ARG_EXT_CSD,
+ arg == MMC_TRIM_ARG ?
+ INAND_CMD38_ARG_TRIM :
+ INAND_CMD38_ARG_ERASE,
+ 0);
+ }
+ if (!err)
+ err = mmc_erase(card, from, nr, arg);
+ } while (err == -EIO && !mmc_blk_reset(md, card->host, type));
if (!err)
mmc_blk_reset_success(md, type);
+fail:
blk_end_request(req, err, blk_rq_bytes(req));
-
- return err ? 0 : 1;
}
-static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
+static void mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
struct request *req)
{
- struct mmc_blk_data *md = mq->data;
+ struct mmc_blk_data *md = mq->blkdata;
struct mmc_card *card = md->queue.card;
unsigned int from, nr, arg;
int err = 0, type = MMC_BLK_SECDISCARD;
@@ -1270,13 +1276,11 @@ out_retry:
mmc_blk_reset_success(md, type);
out:
blk_end_request(req, err, blk_rq_bytes(req));
-
- return err ? 0 : 1;
}
-static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
+static void mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
{
- struct mmc_blk_data *md = mq->data;
+ struct mmc_blk_data *md = mq->blkdata;
struct mmc_card *card = md->queue.card;
int ret = 0;
@@ -1285,8 +1289,6 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
ret = -EIO;
blk_end_request_all(req, ret);
-
- return ret ? 0 : 1;
}
/*
@@ -1302,7 +1304,7 @@ static inline void mmc_apply_rel_rw(struct mmc_blk_request *brq,
{
if (!(card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN)) {
/* Legacy mode imposes restrictions on transfers. */
- if (!IS_ALIGNED(brq->cmd.arg, card->ext_csd.rel_sectors))
+ if (!IS_ALIGNED(blk_rq_pos(req), card->ext_csd.rel_sectors))
brq->data.blocks = 1;
if (brq->data.blocks > card->ext_csd.rel_sectors)
@@ -1320,15 +1322,16 @@ static inline void mmc_apply_rel_rw(struct mmc_blk_request *brq,
R1_CC_ERROR | /* Card controller error */ \
R1_ERROR) /* General/unknown error */
-static int mmc_blk_err_check(struct mmc_card *card,
- struct mmc_async_req *areq)
+static enum mmc_blk_status mmc_blk_err_check(struct mmc_card *card,
+ struct mmc_async_req *areq)
{
struct mmc_queue_req *mq_mrq = container_of(areq, struct mmc_queue_req,
- mmc_active);
+ areq);
struct mmc_blk_request *brq = &mq_mrq->brq;
struct request *req = mq_mrq->req;
int need_retune = card->host->need_retune;
- int ecc_err = 0, gen_err = 0;
+ bool ecc_err = false;
+ bool gen_err = false;
/*
* sbc.error indicates a problem with the set block count
@@ -1378,7 +1381,7 @@ static int mmc_blk_err_check(struct mmc_card *card,
pr_err("%s: %s: general error sending stop command, stop cmd response %#x\n",
req->rq_disk->disk_name, __func__,
brq->stop.resp[0]);
- gen_err = 1;
+ gen_err = true;
}
err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, false, req,
@@ -1419,98 +1422,57 @@ static int mmc_blk_err_check(struct mmc_card *card,
if (!brq->data.bytes_xfered)
return MMC_BLK_RETRY;
- if (mmc_packed_cmd(mq_mrq->cmd_type)) {
- if (unlikely(brq->data.blocks << 9 != brq->data.bytes_xfered))
- return MMC_BLK_PARTIAL;
- else
- return MMC_BLK_SUCCESS;
- }
-
if (blk_rq_bytes(req) != brq->data.bytes_xfered)
return MMC_BLK_PARTIAL;
return MMC_BLK_SUCCESS;
}
-static int mmc_blk_packed_err_check(struct mmc_card *card,
- struct mmc_async_req *areq)
+static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
+ int disable_multi, bool *do_rel_wr_p,
+ bool *do_data_tag_p)
{
- struct mmc_queue_req *mq_rq = container_of(areq, struct mmc_queue_req,
- mmc_active);
- struct request *req = mq_rq->req;
- struct mmc_packed *packed = mq_rq->packed;
- int err, check, status;
- u8 *ext_csd;
-
- packed->retries--;
- check = mmc_blk_err_check(card, areq);
- err = get_card_status(card, &status, 0);
- if (err) {
- pr_err("%s: error %d sending status command\n",
- req->rq_disk->disk_name, err);
- return MMC_BLK_ABORT;
- }
-
- if (status & R1_EXCEPTION_EVENT) {
- err = mmc_get_ext_csd(card, &ext_csd);
- if (err) {
- pr_err("%s: error %d sending ext_csd\n",
- req->rq_disk->disk_name, err);
- return MMC_BLK_ABORT;
- }
-
- if ((ext_csd[EXT_CSD_EXP_EVENTS_STATUS] &
- EXT_CSD_PACKED_FAILURE) &&
- (ext_csd[EXT_CSD_PACKED_CMD_STATUS] &
- EXT_CSD_PACKED_GENERIC_ERROR)) {
- if (ext_csd[EXT_CSD_PACKED_CMD_STATUS] &
- EXT_CSD_PACKED_INDEXED_ERROR) {
- packed->idx_failure =
- ext_csd[EXT_CSD_PACKED_FAILURE_INDEX] - 1;
- check = MMC_BLK_PARTIAL;
- }
- pr_err("%s: packed cmd failed, nr %u, sectors %u, "
- "failure index: %d\n",
- req->rq_disk->disk_name, packed->nr_entries,
- packed->blocks, packed->idx_failure);
- }
- kfree(ext_csd);
- }
-
- return check;
-}
-
-static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
- struct mmc_card *card,
- int disable_multi,
- struct mmc_queue *mq)
-{
- u32 readcmd, writecmd;
+ struct mmc_blk_data *md = mq->blkdata;
+ struct mmc_card *card = md->queue.card;
struct mmc_blk_request *brq = &mqrq->brq;
struct request *req = mqrq->req;
- struct mmc_blk_data *md = mq->data;
- bool do_data_tag;
+ bool do_rel_wr, do_data_tag;
/*
* Reliable writes are used to implement Forced Unit Access and
* are supported only on MMCs.
*/
- bool do_rel_wr = (req->cmd_flags & REQ_FUA) &&
- (rq_data_dir(req) == WRITE) &&
- (md->flags & MMC_BLK_REL_WR);
+ do_rel_wr = (req->cmd_flags & REQ_FUA) &&
+ rq_data_dir(req) == WRITE &&
+ (md->flags & MMC_BLK_REL_WR);
memset(brq, 0, sizeof(struct mmc_blk_request));
- brq->mrq.cmd = &brq->cmd;
+
brq->mrq.data = &brq->data;
+ brq->mrq.tag = req->tag;
- brq->cmd.arg = blk_rq_pos(req);
- if (!mmc_card_blockaddr(card))
- brq->cmd.arg <<= 9;
- brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
- brq->data.blksz = 512;
brq->stop.opcode = MMC_STOP_TRANSMISSION;
brq->stop.arg = 0;
+
+ if (rq_data_dir(req) == READ) {
+ brq->data.flags = MMC_DATA_READ;
+ brq->stop.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+ } else {
+ brq->data.flags = MMC_DATA_WRITE;
+ brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ }
+
+ brq->data.blksz = 512;
brq->data.blocks = blk_rq_sectors(req);
+ brq->data.blk_addr = blk_rq_pos(req);
+
+ /*
+ * The command queue supports 2 priorities: "high" (1) and "simple" (0).
+ * The eMMC will give "high" priority tasks priority over "simple"
+ * priority tasks. Here we give priority to IOPRIO_CLASS_RT.
+ */
+ if (IOPRIO_PRIO_CLASS(req_get_ioprio(req)) == IOPRIO_CLASS_RT)
+ brq->data.flags |= MMC_DATA_PRIO;
/*
* The block layer doesn't support all sector count
@@ -1540,75 +1502,23 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
brq->data.blocks);
}
- if (brq->data.blocks > 1 || do_rel_wr) {
- /* SPI multiblock writes terminate using a special
- * token, not a STOP_TRANSMISSION request.
- */
- if (!mmc_host_is_spi(card->host) ||
- rq_data_dir(req) == READ)
- brq->mrq.stop = &brq->stop;
- readcmd = MMC_READ_MULTIPLE_BLOCK;
- writecmd = MMC_WRITE_MULTIPLE_BLOCK;
- } else {
- brq->mrq.stop = NULL;
- readcmd = MMC_READ_SINGLE_BLOCK;
- writecmd = MMC_WRITE_BLOCK;
- }
- if (rq_data_dir(req) == READ) {
- brq->cmd.opcode = readcmd;
- brq->data.flags = MMC_DATA_READ;
- if (brq->mrq.stop)
- brq->stop.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 |
- MMC_CMD_AC;
- } else {
- brq->cmd.opcode = writecmd;
- brq->data.flags = MMC_DATA_WRITE;
- if (brq->mrq.stop)
- brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B |
- MMC_CMD_AC;
- }
-
- if (do_rel_wr)
+ if (do_rel_wr) {
mmc_apply_rel_rw(brq, card, req);
+ brq->data.flags |= MMC_DATA_REL_WR;
+ }
/*
* Data tag is used only during writing meta data to speed
* up write and any subsequent read of this meta data
*/
- do_data_tag = (card->ext_csd.data_tag_unit_size) &&
- (req->cmd_flags & REQ_META) &&
- (rq_data_dir(req) == WRITE) &&
- ((brq->data.blocks * brq->data.blksz) >=
- card->ext_csd.data_tag_unit_size);
+ do_data_tag = card->ext_csd.data_tag_unit_size &&
+ (req->cmd_flags & REQ_META) &&
+ (rq_data_dir(req) == WRITE) &&
+ ((brq->data.blocks * brq->data.blksz) >=
+ card->ext_csd.data_tag_unit_size);
- /*
- * Pre-defined multi-block transfers are preferable to
- * open ended-ones (and necessary for reliable writes).
- * However, it is not sufficient to just send CMD23,
- * and avoid the final CMD12, as on an error condition
- * CMD12 (stop) needs to be sent anyway. This, coupled
- * with Auto-CMD23 enhancements provided by some
- * hosts, means that the complexity of dealing
- * with this is best left to the host. If CMD23 is
- * supported by card and host, we'll fill sbc in and let
- * the host deal with handling it correctly. This means
- * that for hosts that don't expose MMC_CAP_CMD23, no
- * change of behavior will be observed.
- *
- * N.B: Some MMC cards experience perf degradation.
- * We'll avoid using CMD23-bounded multiblock writes for
- * these, while retaining features like reliable writes.
- */
- if ((md->flags & MMC_BLK_CMD23) && mmc_op_multi(brq->cmd.opcode) &&
- (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23) ||
- do_data_tag)) {
- brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
- brq->sbc.arg = brq->data.blocks |
- (do_rel_wr ? (1 << 31) : 0) |
- (do_data_tag ? (1 << 29) : 0);
- brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
- brq->mrq.sbc = &brq->sbc;
- }
+ if (do_data_tag)
+ brq->data.flags |= MMC_DATA_DAT_TAG;
mmc_set_data_timeout(&brq->data, card);
@@ -1634,236 +1544,270 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
brq->data.sg_len = i;
}
- mqrq->mmc_active.mrq = &brq->mrq;
- mqrq->mmc_active.err_check = mmc_blk_err_check;
+ mqrq->areq.mrq = &brq->mrq;
mmc_queue_bounce_pre(mqrq);
+
+ if (do_rel_wr_p)
+ *do_rel_wr_p = do_rel_wr;
+
+ if (do_data_tag_p)
+ *do_data_tag_p = do_data_tag;
}
-static inline u8 mmc_calc_packed_hdr_segs(struct request_queue *q,
- struct mmc_card *card)
+#define MMC_CQE_RETRIES 2
+
+void mmc_blk_cqe_complete_rq(struct request *req)
{
- unsigned int hdr_sz = mmc_large_sector(card) ? 4096 : 512;
- unsigned int max_seg_sz = queue_max_segment_size(q);
- unsigned int len, nr_segs = 0;
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_request *mrq = &mqrq->brq.mrq;
+ struct request_queue *q = req->q;
+ struct mmc_queue *mq = q->queuedata;
+ struct mmc_host *host = mq->card->host;
+ unsigned long flags;
+ bool put_card;
+ int err;
- do {
- len = min(hdr_sz, max_seg_sz);
- hdr_sz -= len;
- nr_segs++;
- } while (hdr_sz);
+ mmc_cqe_post_req(host, mrq);
- return nr_segs;
+ spin_lock_irqsave(q->queue_lock, flags);
+
+ mq->cqe_in_flight[mmc_cqe_issue_type(host, req)] -= 1;
+
+ put_card = mmc_cqe_tot_in_flight(mq) == 0;
+
+ if (mrq->cmd && mrq->cmd->error)
+ err = mrq->cmd->error;
+ else if (mrq->data && mrq->data->error)
+ err = mrq->data->error;
+ else
+ err = 0;
+
+ if (err) {
+ if (mqrq->retries++ < MMC_CQE_RETRIES)
+ blk_requeue_request(q, req);
+ else
+ __blk_end_request_all(req, -EIO);
+ } else if (mrq->data) {
+ if (__blk_end_request(req, 0, mrq->data->bytes_xfered))
+ blk_requeue_request(q, req);
+ } else {
+ __blk_end_request_all(req, 0);
+ }
+
+ mmc_cqe_kick_queue(mq);
+
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ if (put_card)
+ mmc_put_card(mq->card);
}
-static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req)
+void mmc_blk_cqe_recovery(struct mmc_queue *mq)
{
- struct request_queue *q = mq->queue;
struct mmc_card *card = mq->card;
- struct request *cur = req, *next = NULL;
- struct mmc_blk_data *md = mq->data;
- struct mmc_queue_req *mqrq = mq->mqrq_cur;
- bool en_rel_wr = card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN;
- unsigned int req_sectors = 0, phys_segments = 0;
- unsigned int max_blk_count, max_phys_segs;
- bool put_back = true;
- u8 max_packed_rw = 0;
- u8 reqs = 0;
+ struct mmc_host *host = card->host;
+ int err;
- /*
- * We don't need to check packed for any further
- * operation of packed stuff as we set MMC_PACKED_NONE
- * and return zero for reqs if geting null packed. Also
- * we clean the flag of MMC_BLK_PACKED_CMD to avoid doing
- * it again when removing blk req.
- */
- if (!mqrq->packed) {
- md->flags &= (~MMC_BLK_PACKED_CMD);
- goto no_packed;
- }
+ mmc_get_card(card);
- if (!(md->flags & MMC_BLK_PACKED_CMD))
- goto no_packed;
+ pr_debug("%s: CQE recovery start\n", mmc_hostname(host));
- if ((rq_data_dir(cur) == WRITE) &&
- mmc_host_packed_wr(card->host))
- max_packed_rw = card->ext_csd.max_packed_writes;
+ mq->cqe_in_recovery = true;
- if (max_packed_rw == 0)
- goto no_packed;
+ err = mmc_cqe_recovery(host);
+ if (err)
+ mmc_blk_reset(mq->blkdata, host, MMC_BLK_CQE_RECOVERY);
+ else
+ mmc_blk_reset_success(mq->blkdata, MMC_BLK_CQE_RECOVERY);
- if (mmc_req_rel_wr(cur) &&
- (md->flags & MMC_BLK_REL_WR) && !en_rel_wr)
- goto no_packed;
+ mq->cqe_in_recovery = false;
- if (mmc_large_sector(card) &&
- !IS_ALIGNED(blk_rq_sectors(cur), 8))
- goto no_packed;
+ pr_debug("%s: CQE recovery done\n", mmc_hostname(host));
- mmc_blk_clear_packed(mqrq);
+ mmc_put_card(card);
+}
- max_blk_count = min(card->host->max_blk_count,
- card->host->max_req_size >> 9);
- if (unlikely(max_blk_count > 0xffff))
- max_blk_count = 0xffff;
+static void mmc_blk_cqe_req_done(struct mmc_request *mrq)
+{
+ struct mmc_queue_req *mqrq = container_of(mrq, struct mmc_queue_req,
+ brq.mrq);
+ struct request *req = mqrq->req;
+ struct request_queue *q = req->q;
+ struct mmc_queue *mq = q->queuedata;
- max_phys_segs = queue_max_segments(q);
- req_sectors += blk_rq_sectors(cur);
- phys_segments += cur->nr_phys_segments;
+ /*
+ * Block layer timeouts race with completions which means the normal
+ * completion path cannot be used during recovery.
+ */
+ if (mq->cqe_in_recovery)
+ mmc_blk_cqe_complete_rq(req);
+ else
+ blk_complete_request(req);
+}
- if (rq_data_dir(cur) == WRITE) {
- req_sectors += mmc_large_sector(card) ? 8 : 1;
- phys_segments += mmc_calc_packed_hdr_segs(q, card);
- }
+static int mmc_blk_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+ mrq->done = mmc_blk_cqe_req_done;
+ return mmc_cqe_start_req(host, mrq);
+}
- do {
- if (reqs >= max_packed_rw - 1) {
- put_back = false;
- break;
- }
+static struct mmc_request *mmc_blk_cqe_prep_dcmd(struct mmc_queue_req *mqrq,
+ struct request *req)
+{
+ struct mmc_blk_request *brq = &mqrq->brq;
- spin_lock_irq(q->queue_lock);
- next = blk_fetch_request(q);
- spin_unlock_irq(q->queue_lock);
- if (!next) {
- put_back = false;
- break;
- }
+ memset(brq, 0, sizeof(*brq));
- if (mmc_large_sector(card) &&
- !IS_ALIGNED(blk_rq_sectors(next), 8))
- break;
+ brq->mrq.cmd = &brq->cmd;
+ brq->mrq.tag = req->tag;
- if (req_op(next) == REQ_OP_DISCARD ||
- req_op(next) == REQ_OP_SECURE_ERASE ||
- req_op(next) == REQ_OP_FLUSH)
- break;
+ return &brq->mrq;
+}
- if (rq_data_dir(cur) != rq_data_dir(next))
- break;
+static int mmc_blk_cqe_issue_flush(struct mmc_queue *mq, struct request *req)
+{
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_request *mrq = mmc_blk_cqe_prep_dcmd(mqrq, req);
- if (mmc_req_rel_wr(next) &&
- (md->flags & MMC_BLK_REL_WR) && !en_rel_wr)
- break;
+ mrq->cmd->opcode = MMC_SWITCH;
+ mrq->cmd->arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+ (EXT_CSD_FLUSH_CACHE << 16) |
+ (1 << 8) |
+ EXT_CSD_CMD_SET_NORMAL;
+ mrq->cmd->flags = MMC_CMD_AC | MMC_RSP_R1B;
- req_sectors += blk_rq_sectors(next);
- if (req_sectors > max_blk_count)
- break;
+ return mmc_blk_cqe_start_req(mq->card->host, mrq);
+}
- phys_segments += next->nr_phys_segments;
- if (phys_segments > max_phys_segs)
- break;
+static int mmc_blk_cqe_issue_rw_rq(struct mmc_queue *mq, struct request *req)
+{
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
- list_add_tail(&next->queuelist, &mqrq->packed->list);
- cur = next;
- reqs++;
- } while (1);
+ mmc_blk_data_prep(mq, mqrq, 0, NULL, NULL);
- if (put_back) {
- spin_lock_irq(q->queue_lock);
- blk_requeue_request(q, next);
- spin_unlock_irq(q->queue_lock);
- }
+ return mmc_blk_cqe_start_req(mq->card->host, &mqrq->brq.mrq);
+}
- if (reqs > 0) {
- list_add(&req->queuelist, &mqrq->packed->list);
- mqrq->packed->nr_entries = ++reqs;
- mqrq->packed->retries = reqs;
- return reqs;
- }
+enum mmc_issued mmc_blk_cqe_issue_rq(struct mmc_queue *mq, struct request *req)
+{
+ struct mmc_blk_data *md = mq->blkdata;
+ struct mmc_card *card = md->queue.card;
+ struct mmc_host *host = card->host;
+ int ret;
-no_packed:
- mqrq->cmd_type = MMC_PACKED_NONE;
- return 0;
+ ret = mmc_blk_part_switch(card, md);
+ if (ret)
+ return MMC_REQ_FAILED_TO_START;
+
+ switch (mmc_cqe_issue_type(host, req)) {
+ case MMC_ISSUE_SYNC:
+ ret = host->cqe_ops->cqe_wait_for_idle(host);
+ if (ret)
+ return MMC_REQ_BUSY;
+ if (req && req_op(req) == REQ_OP_DISCARD) {
+ mmc_blk_issue_discard_rq(mq, req);
+ } else if (req && req_op(req) == REQ_OP_SECURE_ERASE) {
+ mmc_blk_issue_secdiscard_rq(mq, req);
+ } else if (req && req_op(req) == REQ_OP_FLUSH) {
+ mmc_blk_issue_flush(mq, req);
+ } else {
+ WARN_ON_ONCE(1);
+ return MMC_REQ_FAILED_TO_START;
+ }
+ return MMC_REQ_FINISHED;
+ case MMC_ISSUE_DCMD:
+ case MMC_ISSUE_ASYNC:
+ if (req && req_op(req) == REQ_OP_FLUSH) {
+ ret = mmc_blk_cqe_issue_flush(mq, req);
+ } else if (req && ((req_op(req) == REQ_OP_READ) || (req_op(req) == REQ_OP_WRITE))) {
+ ret = mmc_blk_cqe_issue_rw_rq(mq, req);
+ } else {
+ WARN_ON_ONCE(1);
+ ret = -EINVAL;
+ }
+ if (!ret)
+ return MMC_REQ_STARTED;
+ return ret == -EBUSY ? MMC_REQ_BUSY : MMC_REQ_FAILED_TO_START;
+ default:
+ WARN_ON_ONCE(1);
+ return MMC_REQ_FAILED_TO_START;
+ }
}
-static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
- struct mmc_card *card,
- struct mmc_queue *mq)
+static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
+ struct mmc_card *card,
+ int disable_multi,
+ struct mmc_queue *mq)
{
+ u32 readcmd, writecmd;
struct mmc_blk_request *brq = &mqrq->brq;
struct request *req = mqrq->req;
- struct request *prq;
- struct mmc_blk_data *md = mq->data;
- struct mmc_packed *packed = mqrq->packed;
+ struct mmc_blk_data *md = mq->blkdata;
bool do_rel_wr, do_data_tag;
- __le32 *packed_cmd_hdr;
- u8 hdr_blocks;
- u8 i = 1;
-
- mqrq->cmd_type = MMC_PACKED_WRITE;
- packed->blocks = 0;
- packed->idx_failure = MMC_PACKED_NR_IDX;
-
- packed_cmd_hdr = packed->cmd_hdr;
- memset(packed_cmd_hdr, 0, sizeof(packed->cmd_hdr));
- packed_cmd_hdr[0] = cpu_to_le32((packed->nr_entries << 16) |
- (PACKED_CMD_WR << 8) | PACKED_CMD_VER);
- hdr_blocks = mmc_large_sector(card) ? 8 : 1;
- /*
- * Argument for each entry of packed group
- */
- list_for_each_entry(prq, &packed->list, queuelist) {
- do_rel_wr = mmc_req_rel_wr(prq) && (md->flags & MMC_BLK_REL_WR);
- do_data_tag = (card->ext_csd.data_tag_unit_size) &&
- (prq->cmd_flags & REQ_META) &&
- (rq_data_dir(prq) == WRITE) &&
- blk_rq_bytes(prq) >= card->ext_csd.data_tag_unit_size;
- /* Argument of CMD23 */
- packed_cmd_hdr[(i * 2)] = cpu_to_le32(
- (do_rel_wr ? MMC_CMD23_ARG_REL_WR : 0) |
- (do_data_tag ? MMC_CMD23_ARG_TAG_REQ : 0) |
- blk_rq_sectors(prq));
- /* Argument of CMD18 or CMD25 */
- packed_cmd_hdr[((i * 2)) + 1] = cpu_to_le32(
- mmc_card_blockaddr(card) ?
- blk_rq_pos(prq) : blk_rq_pos(prq) << 9);
- packed->blocks += blk_rq_sectors(prq);
- i++;
- }
+ mmc_blk_data_prep(mq, mqrq, disable_multi, &do_rel_wr, &do_data_tag);
- memset(brq, 0, sizeof(struct mmc_blk_request));
brq->mrq.cmd = &brq->cmd;
- brq->mrq.data = &brq->data;
- brq->mrq.sbc = &brq->sbc;
- brq->mrq.stop = &brq->stop;
-
- brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
- brq->sbc.arg = MMC_CMD23_ARG_PACKED | (packed->blocks + hdr_blocks);
- brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
- brq->cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK;
brq->cmd.arg = blk_rq_pos(req);
if (!mmc_card_blockaddr(card))
brq->cmd.arg <<= 9;
brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
- brq->data.blksz = 512;
- brq->data.blocks = packed->blocks + hdr_blocks;
- brq->data.flags = MMC_DATA_WRITE;
-
- brq->stop.opcode = MMC_STOP_TRANSMISSION;
- brq->stop.arg = 0;
- brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-
- mmc_set_data_timeout(&brq->data, card);
-
- brq->data.sg = mqrq->sg;
- brq->data.sg_len = mmc_queue_map_sg(mq, mqrq);
+ if (brq->data.blocks > 1 || do_rel_wr) {
+ /* SPI multiblock writes terminate using a special
+ * token, not a STOP_TRANSMISSION request.
+ */
+ if (!mmc_host_is_spi(card->host) ||
+ rq_data_dir(req) == READ)
+ brq->mrq.stop = &brq->stop;
+ readcmd = MMC_READ_MULTIPLE_BLOCK;
+ writecmd = MMC_WRITE_MULTIPLE_BLOCK;
+ } else {
+ brq->mrq.stop = NULL;
+ readcmd = MMC_READ_SINGLE_BLOCK;
+ writecmd = MMC_WRITE_BLOCK;
+ }
+ brq->cmd.opcode = rq_data_dir(req) == READ ? readcmd : writecmd;
- mqrq->mmc_active.mrq = &brq->mrq;
- mqrq->mmc_active.err_check = mmc_blk_packed_err_check;
+ /*
+ * Pre-defined multi-block transfers are preferable to
+ * open ended-ones (and necessary for reliable writes).
+ * However, it is not sufficient to just send CMD23,
+ * and avoid the final CMD12, as on an error condition
+ * CMD12 (stop) needs to be sent anyway. This, coupled
+ * with Auto-CMD23 enhancements provided by some
+ * hosts, means that the complexity of dealing
+ * with this is best left to the host. If CMD23 is
+ * supported by card and host, we'll fill sbc in and let
+ * the host deal with handling it correctly. This means
+ * that for hosts that don't expose MMC_CAP_CMD23, no
+ * change of behavior will be observed.
+ *
+ * N.B: Some MMC cards experience perf degradation.
+ * We'll avoid using CMD23-bounded multiblock writes for
+ * these, while retaining features like reliable writes.
+ */
+ if ((md->flags & MMC_BLK_CMD23) && mmc_op_multi(brq->cmd.opcode) &&
+ (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23) ||
+ do_data_tag)) {
+ brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
+ brq->sbc.arg = brq->data.blocks |
+ (do_rel_wr ? (1 << 31) : 0) |
+ (do_data_tag ? (1 << 29) : 0);
+ brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ brq->mrq.sbc = &brq->sbc;
+ }
- mmc_queue_bounce_pre(mqrq);
+ mqrq->areq.err_check = mmc_blk_err_check;
}
-static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
- struct mmc_blk_request *brq, struct request *req,
- int ret)
+static bool mmc_blk_rw_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
+ struct mmc_blk_request *brq, struct request *req,
+ bool old_req_pending)
{
- struct mmc_queue_req *mq_rq;
- mq_rq = container_of(brq, struct mmc_queue_req, brq);
+ bool req_pending;
/*
* If this is an SD card and we're writing, we can first
@@ -1875,136 +1819,113 @@ static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
*/
if (mmc_card_sd(card)) {
u32 blocks;
+ int err;
- blocks = mmc_sd_num_wr_blocks(card);
- if (blocks != (u32)-1) {
- ret = blk_end_request(req, 0, blocks << 9);
- }
+ err = mmc_sd_num_wr_blocks(card, &blocks);
+ if (err)
+ req_pending = old_req_pending;
+ else
+ req_pending = blk_end_request(req, 0, blocks << 9);
} else {
- if (!mmc_packed_cmd(mq_rq->cmd_type))
- ret = blk_end_request(req, 0, brq->data.bytes_xfered);
+ req_pending = blk_end_request(req, 0, brq->data.bytes_xfered);
}
- return ret;
+ return req_pending;
}
-static int mmc_blk_end_packed_req(struct mmc_queue_req *mq_rq)
+static void mmc_blk_rw_cmd_abort(struct mmc_queue *mq, struct mmc_card *card,
+ struct request *req,
+ struct mmc_queue_req *mqrq)
{
- struct request *prq;
- struct mmc_packed *packed = mq_rq->packed;
- int idx = packed->idx_failure, i = 0;
- int ret = 0;
-
- while (!list_empty(&packed->list)) {
- prq = list_entry_rq(packed->list.next);
- if (idx == i) {
- /* retry from error index */
- packed->nr_entries -= idx;
- mq_rq->req = prq;
- ret = 1;
-
- if (packed->nr_entries == MMC_PACKED_NR_SINGLE) {
- list_del_init(&prq->queuelist);
- mmc_blk_clear_packed(mq_rq);
- }
- return ret;
- }
- list_del_init(&prq->queuelist);
- blk_end_request(prq, 0, blk_rq_bytes(prq));
- i++;
- }
-
- mmc_blk_clear_packed(mq_rq);
- return ret;
-}
-
-static void mmc_blk_abort_packed_req(struct mmc_queue_req *mq_rq)
-{
- struct request *prq;
- struct mmc_packed *packed = mq_rq->packed;
-
- while (!list_empty(&packed->list)) {
- prq = list_entry_rq(packed->list.next);
- list_del_init(&prq->queuelist);
- blk_end_request(prq, -EIO, blk_rq_bytes(prq));
- }
-
- mmc_blk_clear_packed(mq_rq);
+ if (mmc_card_removed(card))
+ req->rq_flags |= RQF_QUIET;
+ while (blk_end_request(req, -EIO, blk_rq_cur_bytes(req)));
+ mq->qcnt--;
}
-static void mmc_blk_revert_packed_req(struct mmc_queue *mq,
- struct mmc_queue_req *mq_rq)
+/**
+ * mmc_blk_rw_try_restart() - tries to restart the current async request
+ * @mq: the queue with the card and host to restart
+ * @req: a new request that want to be started after the current one
+ */
+static void mmc_blk_rw_try_restart(struct mmc_queue *mq, struct request *req,
+ struct mmc_queue_req *mqrq)
{
- struct request *prq;
- struct request_queue *q = mq->queue;
- struct mmc_packed *packed = mq_rq->packed;
+ if (!req)
+ return;
- while (!list_empty(&packed->list)) {
- prq = list_entry_rq(packed->list.prev);
- if (prq->queuelist.prev != &packed->list) {
- list_del_init(&prq->queuelist);
- spin_lock_irq(q->queue_lock);
- blk_requeue_request(mq->queue, prq);
- spin_unlock_irq(q->queue_lock);
- } else {
- list_del_init(&prq->queuelist);
- }
- }
-
- mmc_blk_clear_packed(mq_rq);
+ /*
+ * If the card was removed, just cancel everything and return.
+ */
+ if (mmc_card_removed(mq->card)) {
+ req->rq_flags |= RQF_QUIET;
+ blk_end_request_all(req, -EIO);
+ mq->qcnt--; /* FIXME: just set to 0? */
+ return;
+ }
+ /* Else proceed and try to restart the current async request */
+ mmc_blk_rw_rq_prep(mqrq, mq->card, 0, mq);
+ mmc_start_areq(mq->card->host, &mqrq->areq, NULL);
}
-static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
+static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req)
{
- struct mmc_blk_data *md = mq->data;
+ struct mmc_blk_data *md = mq->blkdata;
struct mmc_card *card = md->queue.card;
- struct mmc_blk_request *brq = &mq->mqrq_cur->brq;
- int ret = 1, disable_multi = 0, retry = 0, type, retune_retry_done = 0;
+ struct mmc_blk_request *brq;
+ int disable_multi = 0, retry = 0, type, retune_retry_done = 0;
enum mmc_blk_status status;
+ struct mmc_queue_req *mqrq_cur = NULL;
struct mmc_queue_req *mq_rq;
- struct request *req = rqc;
- struct mmc_async_req *areq;
- const u8 packed_nr = 2;
- u8 reqs = 0;
+ struct request *old_req;
+ struct mmc_async_req *new_areq;
+ struct mmc_async_req *old_areq;
+ bool req_pending = true;
- if (!rqc && !mq->mqrq_prev->req)
- return 0;
+ if (new_req) {
+ mqrq_cur = req_to_mmc_queue_req(new_req);
+ mq->qcnt++;
+ }
- if (rqc)
- reqs = mmc_blk_prep_packed_list(mq, rqc);
+ if (!mq->qcnt)
+ return;
do {
- if (rqc) {
+ if (new_req) {
/*
* When 4KB native sector is enabled, only 8 blocks
* multiple read or write is allowed
*/
if (mmc_large_sector(card) &&
- !IS_ALIGNED(blk_rq_sectors(rqc), 8)) {
+ !IS_ALIGNED(blk_rq_sectors(new_req), 8)) {
pr_err("%s: Transfer size is not 4KB sector size aligned\n",
- req->rq_disk->disk_name);
- mq_rq = mq->mqrq_cur;
- goto cmd_abort;
+ new_req->rq_disk->disk_name);
+ mmc_blk_rw_cmd_abort(mq, card, new_req, mqrq_cur);
+ return;
}
- if (reqs >= packed_nr)
- mmc_blk_packed_hdr_wrq_prep(mq->mqrq_cur,
- card, mq);
- else
- mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
- areq = &mq->mqrq_cur->mmc_active;
+ mmc_blk_rw_rq_prep(mqrq_cur, card, 0, mq);
+ new_areq = &mqrq_cur->areq;
} else
- areq = NULL;
- areq = mmc_start_req(card->host, areq, (int *) &status);
- if (!areq) {
- if (status == MMC_BLK_NEW_REQUEST)
- mq->flags |= MMC_QUEUE_NEW_REQUEST;
- return 0;
+ new_areq = NULL;
+
+ old_areq = mmc_start_areq(card->host, new_areq, &status);
+ if (!old_areq) {
+ /*
+ * We have just put the first request into the pipeline
+ * and there is nothing more to do until it is
+ * complete.
+ */
+ return;
}
- mq_rq = container_of(areq, struct mmc_queue_req, mmc_active);
+ /*
+ * An asynchronous request has been completed and we proceed
+ * to handle the result of it.
+ */
+ mq_rq = container_of(old_areq, struct mmc_queue_req, areq);
brq = &mq_rq->brq;
- req = mq_rq->req;
- type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
+ old_req = mq_rq->req;
+ type = rq_data_dir(old_req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
mmc_queue_bounce_post(mq_rq);
switch (status) {
@@ -2015,33 +1936,36 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
*/
mmc_blk_reset_success(md, type);
- if (mmc_packed_cmd(mq_rq->cmd_type)) {
- ret = mmc_blk_end_packed_req(mq_rq);
- break;
- } else {
- ret = blk_end_request(req, 0,
- brq->data.bytes_xfered);
- }
-
+ req_pending = blk_end_request(old_req, 0,
+ brq->data.bytes_xfered);
/*
* If the blk_end_request function returns non-zero even
* though all data has been transferred and no errors
* were returned by the host controller, it's a bug.
*/
- if (status == MMC_BLK_SUCCESS && ret) {
+ if (status == MMC_BLK_SUCCESS && req_pending) {
pr_err("%s BUG rq_tot %d d_xfer %d\n",
- __func__, blk_rq_bytes(req),
+ __func__, blk_rq_bytes(old_req),
brq->data.bytes_xfered);
- rqc = NULL;
- goto cmd_abort;
+ mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq);
+ return;
}
break;
case MMC_BLK_CMD_ERR:
- ret = mmc_blk_cmd_err(md, card, brq, req, ret);
- if (mmc_blk_reset(md, card->host, type))
- goto cmd_abort;
- if (!ret)
- goto start_new_req;
+ req_pending = mmc_blk_rw_cmd_err(md, card, brq, old_req, req_pending);
+ if (mmc_blk_reset(md, card->host, type)) {
+ if (req_pending)
+ mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq);
+ else
+ mq->qcnt--;
+ mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
+ return;
+ }
+ if (!req_pending) {
+ mq->qcnt--;
+ mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
+ return;
+ }
break;
case MMC_BLK_RETRY:
retune_retry_done = brq->retune_retry_done;
@@ -2051,23 +1975,27 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
case MMC_BLK_ABORT:
if (!mmc_blk_reset(md, card->host, type))
break;
- goto cmd_abort;
+ mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq);
+ mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
+ return;
case MMC_BLK_DATA_ERR: {
int err;
err = mmc_blk_reset(md, card->host, type);
if (!err)
break;
- if (err == -ENODEV ||
- mmc_packed_cmd(mq_rq->cmd_type))
- goto cmd_abort;
+ if (err == -ENODEV) {
+ mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq);
+ mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
+ return;
+ }
/* Fall through */
}
case MMC_BLK_ECC_ERR:
if (brq->data.blocks > 1) {
/* Redo read one sector at a time */
pr_warn("%s: retrying using single block read\n",
- req->rq_disk->disk_name);
+ old_req->rq_disk->disk_name);
disable_multi = 1;
break;
}
@@ -2076,85 +2004,49 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
* time, so we only reach here after trying to
* read a single sector.
*/
- ret = blk_end_request(req, -EIO,
- brq->data.blksz);
- if (!ret)
- goto start_new_req;
+ req_pending = blk_end_request(old_req, -EIO,
+ brq->data.blksz);
+ if (!req_pending) {
+ mq->qcnt--;
+ mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
+ return;
+ }
break;
case MMC_BLK_NOMEDIUM:
- goto cmd_abort;
+ mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq);
+ mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
+ return;
default:
pr_err("%s: Unhandled return value (%d)",
- req->rq_disk->disk_name, status);
- goto cmd_abort;
- }
-
- if (ret) {
- if (mmc_packed_cmd(mq_rq->cmd_type)) {
- if (!mq_rq->packed->retries)
- goto cmd_abort;
- mmc_blk_packed_hdr_wrq_prep(mq_rq, card, mq);
- mmc_start_req(card->host,
- &mq_rq->mmc_active, NULL);
- } else {
-
- /*
- * In case of a incomplete request
- * prepare it again and resend.
- */
- mmc_blk_rw_rq_prep(mq_rq, card,
- disable_multi, mq);
- mmc_start_req(card->host,
- &mq_rq->mmc_active, NULL);
- }
- mq_rq->brq.retune_retry_done = retune_retry_done;
+ old_req->rq_disk->disk_name, status);
+ mmc_blk_rw_cmd_abort(mq, card, old_req, mq_rq);
+ mmc_blk_rw_try_restart(mq, new_req, mqrq_cur);
+ return;
}
- } while (ret);
-
- return 1;
- cmd_abort:
- if (mmc_packed_cmd(mq_rq->cmd_type)) {
- mmc_blk_abort_packed_req(mq_rq);
- } else {
- if (mmc_card_removed(card))
- req->cmd_flags |= REQ_QUIET;
- while (ret)
- ret = blk_end_request(req, -EIO,
- blk_rq_cur_bytes(req));
- }
-
- start_new_req:
- if (rqc) {
- if (mmc_card_removed(card)) {
- rqc->cmd_flags |= REQ_QUIET;
- blk_end_request_all(rqc, -EIO);
- } else {
+ if (req_pending) {
/*
- * If current request is packed, it needs to put back.
+ * In case of a incomplete request
+ * prepare it again and resend.
*/
- if (mmc_packed_cmd(mq->mqrq_cur->cmd_type))
- mmc_blk_revert_packed_req(mq, mq->mqrq_cur);
-
- mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
- mmc_start_req(card->host,
- &mq->mqrq_cur->mmc_active, NULL);
+ mmc_blk_rw_rq_prep(mq_rq, card,
+ disable_multi, mq);
+ mmc_start_areq(card->host,
+ &mq_rq->areq, NULL);
+ mq_rq->brq.retune_retry_done = retune_retry_done;
}
- }
+ } while (req_pending);
- return 0;
+ mq->qcnt--;
}
-int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
{
int ret;
- struct mmc_blk_data *md = mq->data;
+ struct mmc_blk_data *md = mq->blkdata;
struct mmc_card *card = md->queue.card;
- struct mmc_host *host = card->host;
- unsigned long flags;
- bool req_is_special = mmc_req_is_special(req);
- if (req && !mq->mqrq_prev->req)
+ if (req && !mq->qcnt)
/* claim host only for the first request */
mmc_get_card(card);
@@ -2163,45 +2055,32 @@ int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
if (req) {
blk_end_request_all(req, -EIO);
}
- ret = 0;
goto out;
}
- mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
if (req && req_op(req) == REQ_OP_DISCARD) {
/* complete ongoing async transfer before issuing discard */
- if (card->host->areq)
+ if (mq->qcnt)
mmc_blk_issue_rw_rq(mq, NULL);
- ret = mmc_blk_issue_discard_rq(mq, req);
+ mmc_blk_issue_discard_rq(mq, req);
} else if (req && req_op(req) == REQ_OP_SECURE_ERASE) {
/* complete ongoing async transfer before issuing secure erase*/
- if (card->host->areq)
+ if (mq->qcnt)
mmc_blk_issue_rw_rq(mq, NULL);
- ret = mmc_blk_issue_secdiscard_rq(mq, req);
+ mmc_blk_issue_secdiscard_rq(mq, req);
} else if (req && req_op(req) == REQ_OP_FLUSH) {
/* complete ongoing async transfer before issuing flush */
- if (card->host->areq)
+ if (mq->qcnt)
mmc_blk_issue_rw_rq(mq, NULL);
- ret = mmc_blk_issue_flush(mq, req);
+ mmc_blk_issue_flush(mq, req);
} else {
- if (!req && host->areq) {
- spin_lock_irqsave(&host->context_info.lock, flags);
- host->context_info.is_waiting_last_req = true;
- spin_unlock_irqrestore(&host->context_info.lock, flags);
- }
- ret = mmc_blk_issue_rw_rq(mq, req);
+ mmc_blk_issue_rw_rq(mq, req);
+ card->host->context_info.is_waiting_last_req = false;
}
out:
- if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) || req_is_special)
- /*
- * Release host when there are no more requests
- * and after special request(discard, flush) is done.
- * In case sepecial request, there is no reentry to
- * the 'mmc_blk_issue_rq' with 'mqrq_prev->req'.
- */
+ if (!mq->qcnt)
mmc_put_card(card);
- return ret;
}
static inline int mmc_blk_readonly(struct mmc_card *card)
@@ -2220,23 +2099,9 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
struct mmc_blk_data *md;
int devidx, ret;
-again:
- if (!ida_pre_get(&mmc_blk_ida, GFP_KERNEL))
- return ERR_PTR(-ENOMEM);
-
- spin_lock(&mmc_blk_lock);
- ret = ida_get_new(&mmc_blk_ida, &devidx);
- spin_unlock(&mmc_blk_lock);
-
- if (ret == -EAGAIN)
- goto again;
- else if (ret)
- return ERR_PTR(ret);
-
- if (devidx >= max_devices) {
- ret = -ENOSPC;
- goto out;
- }
+ devidx = ida_simple_get(&mmc_blk_ida, 0, max_devices, GFP_KERNEL);
+ if (devidx < 0)
+ return ERR_PTR(devidx);
md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
if (!md) {
@@ -2262,11 +2127,11 @@ again:
INIT_LIST_HEAD(&md->part);
md->usage = 1;
- ret = mmc_init_queue(&md->queue, card, &md->lock, subname);
+ ret = mmc_init_queue(&md->queue, card, &md->lock, subname, area_type);
if (ret)
goto err_putdisk;
- md->queue.data = md;
+ md->queue.blkdata = md;
md->disk->major = MMC_BLOCK_MAJOR;
md->disk->first_minor = devidx * perdev_minors;
@@ -2318,14 +2183,6 @@ again:
blk_queue_write_cache(md->queue.queue, true, true);
}
- if (mmc_card_mmc(card) &&
- (area_type == MMC_BLK_DATA_AREA_MAIN) &&
- (md->flags & MMC_BLK_CMD23) &&
- card->ext_csd.packed_event_en) {
- if (!mmc_packed_init(&md->queue, card))
- md->flags |= MMC_BLK_PACKED_CMD;
- }
-
return md;
err_putdisk:
@@ -2333,9 +2190,7 @@ again:
err_kfree:
kfree(md);
out:
- spin_lock(&mmc_blk_lock);
- ida_remove(&mmc_blk_ida, devidx);
- spin_unlock(&mmc_blk_lock);
+ ida_simple_remove(&mmc_blk_ida, devidx);
return ERR_PTR(ret);
}
@@ -2428,9 +2283,11 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
* from being accepted.
*/
card = md->queue.card;
+ spin_lock_irq(md->queue.queue->queue_lock);
+ queue_flag_set(QUEUE_FLAG_BYPASS, md->queue.queue);
+ spin_unlock_irq(md->queue.queue->queue_lock);
+ blk_set_queue_dying(md->queue.queue);
mmc_cleanup_queue(&md->queue);
- if (md->flags & MMC_BLK_PACKED_CMD)
- mmc_packed_clean(&md->queue);
if (md->disk->flags & GENHD_FL_UP) {
device_remove_file(disk_to_dev(md->disk), &md->force_ro);
if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
@@ -2502,80 +2359,6 @@ force_ro_fail:
return ret;
}
-static const struct mmc_fixup blk_fixups[] =
-{
- MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk,
- MMC_QUIRK_INAND_CMD38),
- MMC_FIXUP("SEM04G", CID_MANFID_SANDISK, 0x100, add_quirk,
- MMC_QUIRK_INAND_CMD38),
- MMC_FIXUP("SEM08G", CID_MANFID_SANDISK, 0x100, add_quirk,
- MMC_QUIRK_INAND_CMD38),
- MMC_FIXUP("SEM16G", CID_MANFID_SANDISK, 0x100, add_quirk,
- MMC_QUIRK_INAND_CMD38),
- MMC_FIXUP("SEM32G", CID_MANFID_SANDISK, 0x100, add_quirk,
- MMC_QUIRK_INAND_CMD38),
-
- /*
- * Some MMC cards experience performance degradation with CMD23
- * instead of CMD12-bounded multiblock transfers. For now we'll
- * black list what's bad...
- * - Certain Toshiba cards.
- *
- * N.B. This doesn't affect SD cards.
- */
- MMC_FIXUP("SDMB-32", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_BLK_NO_CMD23),
- MMC_FIXUP("SDM032", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_BLK_NO_CMD23),
- MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_BLK_NO_CMD23),
- MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_BLK_NO_CMD23),
- MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_BLK_NO_CMD23),
-
- /*
- * Some MMC cards need longer data read timeout than indicated in CSD.
- */
- MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc,
- MMC_QUIRK_LONG_READ_TIME),
- MMC_FIXUP("008GE0", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_LONG_READ_TIME),
-
- /*
- * On these Samsung MoviNAND parts, performing secure erase or
- * secure trim can result in unrecoverable corruption due to a
- * firmware bug.
- */
- MMC_FIXUP("M8G2FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
- MMC_FIXUP("MAG4FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
- MMC_FIXUP("MBG8FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
- MMC_FIXUP("MCGAFA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
- MMC_FIXUP("VAL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
- MMC_FIXUP("VYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
- MMC_FIXUP("KYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
- MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
-
- /*
- * On Some Kingston eMMCs, performing trim can result in
- * unrecoverable data conrruption occasionally due to a firmware bug.
- */
- MMC_FIXUP("V10008", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_TRIM_BROKEN),
- MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_TRIM_BROKEN),
-
- END_FIXUP
-};
-
static int mmc_blk_probe(struct mmc_card *card)
{
struct mmc_blk_data *md, *part_md;
@@ -2587,7 +2370,7 @@ static int mmc_blk_probe(struct mmc_card *card)
if (!(card->csd.cmdclass & CCC_BLOCK_READ))
return -ENODEV;
- mmc_fixup_device(card, blk_fixups);
+ mmc_fixup_device(card, mmc_blk_fixups);
md = mmc_blk_alloc(card);
if (IS_ERR(md))
diff --git a/drivers/mmc/core/block.h b/drivers/mmc/core/block.h
new file mode 100644
index 000000000000..d7b3d7008b00
--- /dev/null
+++ b/drivers/mmc/core/block.h
@@ -0,0 +1,16 @@
+#ifndef _MMC_CORE_BLOCK_H
+#define _MMC_CORE_BLOCK_H
+
+struct mmc_queue;
+struct request;
+
+void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req);
+
+enum mmc_issued;
+
+enum mmc_issued mmc_blk_cqe_issue_rq(struct mmc_queue *mq,
+ struct request *req);
+void mmc_blk_cqe_complete_rq(struct request *rq);
+void mmc_blk_cqe_recovery(struct mmc_queue *mq);
+
+#endif
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 60ebe5b4500b..7586ff2ad1f1 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -23,6 +23,8 @@
#include <linux/mmc/host.h>
#include "core.h"
+#include "card.h"
+#include "host.h"
#include "sdio_cis.h"
#include "bus.h"
@@ -370,10 +372,17 @@ int mmc_add_card(struct mmc_card *card)
*/
void mmc_remove_card(struct mmc_card *card)
{
+ struct mmc_host *host = card->host;
+
#ifdef CONFIG_DEBUG_FS
mmc_remove_card_debugfs(card);
#endif
+ if (host->cqe_enabled) {
+ host->cqe_ops->cqe_disable(host);
+ host->cqe_enabled = false;
+ }
+
if (mmc_card_present(card)) {
if (mmc_host_is_spi(card->host)) {
pr_info("%s: SPI card removed\n",
diff --git a/drivers/mmc/core/bus.h b/drivers/mmc/core/bus.h
index 00a19710b6b4..72b0ef03f10a 100644
--- a/drivers/mmc/core/bus.h
+++ b/drivers/mmc/core/bus.h
@@ -11,6 +11,11 @@
#ifndef _MMC_CORE_BUS_H
#define _MMC_CORE_BUS_H
+#include <linux/device.h>
+
+struct mmc_host;
+struct mmc_card;
+
#define MMC_DEV_ATTR(name, fmt, args...) \
static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \
{ \
@@ -27,5 +32,14 @@ void mmc_remove_card(struct mmc_card *card);
int mmc_register_bus(void);
void mmc_unregister_bus(void);
-#endif
+struct mmc_driver {
+ struct device_driver drv;
+ int (*probe)(struct mmc_card *card);
+ void (*remove)(struct mmc_card *card);
+ void (*shutdown)(struct mmc_card *card);
+};
+int mmc_register_driver(struct mmc_driver *drv);
+void mmc_unregister_driver(struct mmc_driver *drv);
+
+#endif
diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h
new file mode 100644
index 000000000000..f06cd91964ce
--- /dev/null
+++ b/drivers/mmc/core/card.h
@@ -0,0 +1,221 @@
+/*
+ * Private header for the mmc subsystem
+ *
+ * Copyright (C) 2016 Linaro Ltd
+ *
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef _MMC_CORE_CARD_H
+#define _MMC_CORE_CARD_H
+
+#include <linux/mmc/card.h>
+
+#define mmc_card_name(c) ((c)->cid.prod_name)
+#define mmc_card_id(c) (dev_name(&(c)->dev))
+#define mmc_dev_to_card(d) container_of(d, struct mmc_card, dev)
+
+/* Card states */
+#define MMC_STATE_PRESENT (1<<0) /* present in sysfs */
+#define MMC_STATE_READONLY (1<<1) /* card is read-only */
+#define MMC_STATE_BLOCKADDR (1<<2) /* card uses block-addressing */
+#define MMC_CARD_SDXC (1<<3) /* card is SDXC */
+#define MMC_CARD_REMOVED (1<<4) /* card has been removed */
+#define MMC_STATE_DOING_BKOPS (1<<5) /* card is doing BKOPS */
+#define MMC_STATE_SUSPENDED (1<<6) /* card is suspended */
+
+#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
+#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
+#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR)
+#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
+#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
+#define mmc_card_doing_bkops(c) ((c)->state & MMC_STATE_DOING_BKOPS)
+#define mmc_card_suspended(c) ((c)->state & MMC_STATE_SUSPENDED)
+
+#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
+#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
+#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
+#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
+#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
+#define mmc_card_set_doing_bkops(c) ((c)->state |= MMC_STATE_DOING_BKOPS)
+#define mmc_card_clr_doing_bkops(c) ((c)->state &= ~MMC_STATE_DOING_BKOPS)
+#define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
+#define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
+
+/*
+ * The world is not perfect and supplies us with broken mmc/sdio devices.
+ * For at least some of these bugs we need a work-around.
+ */
+struct mmc_fixup {
+ /* CID-specific fields. */
+ const char *name;
+
+ /* Valid revision range */
+ u64 rev_start, rev_end;
+
+ unsigned int manfid;
+ unsigned short oemid;
+
+ /* SDIO-specific fields. You can use SDIO_ANY_ID here of course */
+ u16 cis_vendor, cis_device;
+
+ /* for MMC cards */
+ unsigned int ext_csd_rev;
+
+ void (*vendor_fixup)(struct mmc_card *card, int data);
+ int data;
+};
+
+#define CID_MANFID_ANY (-1u)
+#define CID_OEMID_ANY ((unsigned short) -1)
+#define CID_NAME_ANY (NULL)
+
+#define EXT_CSD_REV_ANY (-1u)
+
+#define CID_MANFID_SANDISK 0x2
+#define CID_MANFID_TOSHIBA 0x11
+#define CID_MANFID_MICRON 0x13
+#define CID_MANFID_SAMSUNG 0x15
+#define CID_MANFID_KINGSTON 0x70
+#define CID_MANFID_HYNIX 0x90
+
+#define END_FIXUP { NULL }
+
+#define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end, \
+ _cis_vendor, _cis_device, \
+ _fixup, _data, _ext_csd_rev) \
+ { \
+ .name = (_name), \
+ .manfid = (_manfid), \
+ .oemid = (_oemid), \
+ .rev_start = (_rev_start), \
+ .rev_end = (_rev_end), \
+ .cis_vendor = (_cis_vendor), \
+ .cis_device = (_cis_device), \
+ .vendor_fixup = (_fixup), \
+ .data = (_data), \
+ .ext_csd_rev = (_ext_csd_rev), \
+ }
+
+#define MMC_FIXUP_REV(_name, _manfid, _oemid, _rev_start, _rev_end, \
+ _fixup, _data, _ext_csd_rev) \
+ _FIXUP_EXT(_name, _manfid, \
+ _oemid, _rev_start, _rev_end, \
+ SDIO_ANY_ID, SDIO_ANY_ID, \
+ _fixup, _data, _ext_csd_rev) \
+
+#define MMC_FIXUP(_name, _manfid, _oemid, _fixup, _data) \
+ MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data, \
+ EXT_CSD_REV_ANY)
+
+#define MMC_FIXUP_EXT_CSD_REV(_name, _manfid, _oemid, _fixup, _data, \
+ _ext_csd_rev) \
+ MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data, \
+ _ext_csd_rev)
+
+#define SDIO_FIXUP(_vendor, _device, _fixup, _data) \
+ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY, \
+ CID_OEMID_ANY, 0, -1ull, \
+ _vendor, _device, \
+ _fixup, _data, EXT_CSD_REV_ANY) \
+
+#define cid_rev(hwrev, fwrev, year, month) \
+ (((u64) hwrev) << 40 | \
+ ((u64) fwrev) << 32 | \
+ ((u64) year) << 16 | \
+ ((u64) month))
+
+#define cid_rev_card(card) \
+ cid_rev(card->cid.hwrev, \
+ card->cid.fwrev, \
+ card->cid.year, \
+ card->cid.month)
+
+/*
+ * Unconditionally quirk add/remove.
+ */
+static inline void __maybe_unused add_quirk(struct mmc_card *card, int data)
+{
+ card->quirks |= data;
+}
+
+static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
+{
+ card->quirks &= ~data;
+}
+
+/*
+ * Quirk add/remove for MMC products.
+ */
+static inline void __maybe_unused add_quirk_mmc(struct mmc_card *card, int data)
+{
+ if (mmc_card_mmc(card))
+ card->quirks |= data;
+}
+
+static inline void __maybe_unused remove_quirk_mmc(struct mmc_card *card,
+ int data)
+{
+ if (mmc_card_mmc(card))
+ card->quirks &= ~data;
+}
+
+/*
+ * Quirk add/remove for SD products.
+ */
+static inline void __maybe_unused add_quirk_sd(struct mmc_card *card, int data)
+{
+ if (mmc_card_sd(card))
+ card->quirks |= data;
+}
+
+static inline void __maybe_unused remove_quirk_sd(struct mmc_card *card,
+ int data)
+{
+ if (mmc_card_sd(card))
+ card->quirks &= ~data;
+}
+
+static inline int mmc_card_lenient_fn0(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_LENIENT_FN0;
+}
+
+static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
+}
+
+static inline int mmc_card_disable_cd(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_DISABLE_CD;
+}
+
+static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF;
+}
+
+static inline int mmc_card_broken_byte_mode_512(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_BROKEN_BYTE_MODE_512;
+}
+
+static inline int mmc_card_long_read_time(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_LONG_READ_TIME;
+}
+
+static inline int mmc_card_broken_irq_polling(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_BROKEN_IRQ_POLLING;
+}
+
+static inline int mmc_card_broken_hpi(const struct mmc_card *c)
+{
+ return c->quirks & MMC_QUIRK_BROKEN_HPI;
+}
+
+#endif
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index cff5829790c9..f57d97ff41f0 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -40,6 +40,7 @@
#include <trace/events/mmc.h>
#include "core.h"
+#include "card.h"
#include "bus.h"
#include "host.h"
#include "sdio_bus.h"
@@ -63,6 +64,8 @@
static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
+static int __mmc_max_reserved_idx = -1;
+
/*
* Enabling software CRCs on the data blocks can be a significant (30%)
* performance cost, and for other reasons may not always be desired.
@@ -171,14 +174,16 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
trace_mmc_request_done(host, mrq);
- if (err && cmd->retries && !mmc_card_removed(host->card)) {
- /*
- * Request starter must handle retries - see
- * mmc_wait_for_req_done().
- */
- if (mrq->done)
- mrq->done(mrq);
- } else {
+ /*
+ * We list various conditions for the command to be considered
+ * properly done:
+ *
+ * - There was no error, OK fine then
+ * - We are not doing some kind of retry
+ * - The card was removed (...so just complete everything no matter
+ * if there are errors or retries)
+ */
+ if (!err || !cmd->retries || mmc_card_removed(host->card)) {
mmc_should_fail_request(host, mrq);
if (!host->ongoing_mrq)
@@ -210,10 +215,13 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
mrq->stop->resp[0], mrq->stop->resp[1],
mrq->stop->resp[2], mrq->stop->resp[3]);
}
-
- if (mrq->done)
- mrq->done(mrq);
}
+ /*
+ * Request starter must handle retries - see
+ * mmc_wait_for_req_done().
+ */
+ if (mrq->done)
+ mrq->done(mrq);
}
EXPORT_SYMBOL(mmc_request_done);
@@ -233,8 +241,10 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
/*
* For sdio rw commands we must wait for card busy otherwise some
* sdio devices won't work properly.
+ * And bypass I/O abort, reset and bus suspend operations.
*/
- if (mmc_is_io_op(mrq->cmd->opcode) && host->ops->card_busy) {
+ if (sdio_is_io_busy(mrq->cmd->opcode, mrq->cmd->arg) &&
+ host->ops->card_busy) {
int tries = 500; /* Wait aprox 500ms at maximum */
while (host->ops->card_busy(host) && --tries)
@@ -258,29 +268,29 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
trace_mmc_request_start(host, mrq);
+ if (host->cqe_on)
+ host->cqe_ops->cqe_off(host);
+
host->ops->request(host, mrq);
}
-static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
+static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq,
+ bool cqe)
{
-#ifdef CONFIG_MMC_DEBUG
- unsigned int i, sz;
- struct scatterlist *sg;
-#endif
- mmc_retune_hold(host);
-
- if (mmc_card_removed(host->card))
- return -ENOMEDIUM;
-
if (mrq->sbc) {
pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n",
mmc_hostname(host), mrq->sbc->opcode,
mrq->sbc->arg, mrq->sbc->flags);
}
- pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
- mmc_hostname(host), mrq->cmd->opcode,
- mrq->cmd->arg, mrq->cmd->flags);
+ if (mrq->cmd) {
+ pr_debug("%s: starting %sCMD%u arg %08x flags %08x\n",
+ mmc_hostname(host), cqe ? "CQE direct " : "",
+ mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags);
+ } else if (cqe) {
+ pr_debug("%s: starting CQE transfer for tag %d blkaddr %u\n",
+ mmc_hostname(host), mrq->tag, mrq->data->blk_addr);
+ }
if (mrq->data) {
pr_debug("%s: blksz %d blocks %d flags %08x "
@@ -296,29 +306,36 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mmc_hostname(host), mrq->stop->opcode,
mrq->stop->arg, mrq->stop->flags);
}
+}
- WARN_ON(!host->claimed);
+static int mmc_mrq_prep(struct mmc_host *host, struct mmc_request *mrq)
+{
+#ifdef CONFIG_MMC_DEBUG
+ unsigned int i, sz;
+ struct scatterlist *sg;
+#endif
- mrq->cmd->error = 0;
- mrq->cmd->mrq = mrq;
+ if (mrq->cmd) {
+ mrq->cmd->error = 0;
+ mrq->cmd->mrq = mrq;
+ mrq->cmd->data = mrq->data;
+ }
if (mrq->sbc) {
mrq->sbc->error = 0;
mrq->sbc->mrq = mrq;
}
if (mrq->data) {
- BUG_ON(mrq->data->blksz > host->max_blk_size);
- BUG_ON(mrq->data->blocks > host->max_blk_count);
- BUG_ON(mrq->data->blocks * mrq->data->blksz >
- host->max_req_size);
-
+ if (mrq->data->blksz > host->max_blk_size ||
+ mrq->data->blocks > host->max_blk_count ||
+ mrq->data->blocks * mrq->data->blksz > host->max_req_size)
+ return -EINVAL;
#ifdef CONFIG_MMC_DEBUG
sz = 0;
for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i)
sz += sg->length;
- BUG_ON(sz != mrq->data->blocks * mrq->data->blksz);
+ if (sz != mrq->data->blocks * mrq->data->blksz)
+ return -EINVAL;
#endif
-
- mrq->cmd->data = mrq->data;
mrq->data->error = 0;
mrq->data->mrq = mrq;
if (mrq->stop) {
@@ -327,6 +344,27 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mrq->stop->mrq = mrq;
}
}
+
+ return 0;
+}
+
+static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
+{
+ int err;
+
+ mmc_retune_hold(host);
+
+ if (mmc_card_removed(host->card))
+ return -ENOMEDIUM;
+
+ mmc_mrq_pr_debug(host, mrq, false);
+
+ WARN_ON(!host->claimed);
+
+ err = mmc_mrq_prep(host, mrq);
+ if (err)
+ return err;
+
led_trigger_event(host->led, LED_FULL);
__mmc_start_request(host, mrq);
@@ -349,8 +387,6 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
int timeout;
bool use_busy_signal;
- BUG_ON(!card);
-
if (!card->ext_csd.man_bkops_en || mmc_card_doing_bkops(card))
return;
@@ -380,7 +416,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
mmc_retune_hold(card->host);
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BKOPS_START, 1, timeout,
+ EXT_CSD_BKOPS_START, 1, timeout, 0,
use_busy_signal, true, false);
if (err) {
pr_warn("%s: Error %d starting bkops\n",
@@ -486,63 +522,6 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
return err;
}
-/*
- * mmc_wait_for_data_req_done() - wait for request completed
- * @host: MMC host to prepare the command.
- * @mrq: MMC request to wait for
- *
- * Blocks MMC context till host controller will ack end of data request
- * execution or new request notification arrives from the block layer.
- * Handles command retries.
- *
- * Returns enum mmc_blk_status after checking errors.
- */
-static int mmc_wait_for_data_req_done(struct mmc_host *host,
- struct mmc_request *mrq,
- struct mmc_async_req *next_req)
-{
- struct mmc_command *cmd;
- struct mmc_context_info *context_info = &host->context_info;
- int err;
- unsigned long flags;
-
- while (1) {
- wait_event_interruptible(context_info->wait,
- (context_info->is_done_rcv ||
- context_info->is_new_req));
- spin_lock_irqsave(&context_info->lock, flags);
- context_info->is_waiting_last_req = false;
- spin_unlock_irqrestore(&context_info->lock, flags);
- if (context_info->is_done_rcv) {
- context_info->is_done_rcv = false;
- context_info->is_new_req = false;
- cmd = mrq->cmd;
-
- if (!cmd->error || !cmd->retries ||
- mmc_card_removed(host->card)) {
- err = host->areq->err_check(host->card,
- host->areq);
- break; /* return err */
- } else {
- mmc_retune_recheck(host);
- pr_info("%s: req failed (CMD%u): %d, retrying...\n",
- mmc_hostname(host),
- cmd->opcode, cmd->error);
- cmd->retries--;
- cmd->error = 0;
- __mmc_start_request(host, mrq);
- continue; /* wait for done/new event again */
- }
- } else if (context_info->is_new_req) {
- context_info->is_new_req = false;
- if (!next_req)
- return MMC_BLK_NEW_REQUEST;
- }
- }
- mmc_retune_release(host);
- return err;
-}
-
void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
{
struct mmc_command *cmd;
@@ -586,6 +565,139 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
}
EXPORT_SYMBOL(mmc_wait_for_req_done);
+int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+ int err;
+
+ /* Caller must hold retuning while CQE is in use */
+ err = mmc_retune(host);
+ if (err)
+ goto out_err;
+
+ mrq->host = host;
+
+ mmc_mrq_pr_debug(host, mrq, true);
+
+ err = mmc_mrq_prep(host, mrq);
+ if (err)
+ goto out_err;
+
+ err = host->cqe_ops->cqe_request(host, mrq);
+ if (err)
+ goto out_err;
+
+ trace_mmc_request_start(host, mrq);
+
+ return 0;
+
+out_err:
+ if (mrq->cmd) {
+ pr_debug("%s: failed to start CQE direct CMD%u, error %d\n",
+ mmc_hostname(host), mrq->cmd->opcode, err);
+ } else {
+ pr_debug("%s: failed to start CQE transfer for tag %d, error %d\n",
+ mmc_hostname(host), mrq->tag, err);
+ }
+ return err;
+}
+EXPORT_SYMBOL(mmc_cqe_start_req);
+
+static void __mmc_cqe_request_done(struct mmc_host *host,
+ struct mmc_request *mrq)
+{
+ mmc_should_fail_request(host, mrq);
+
+ /* Flag re-tuning needed on CRC errors */
+ if ((mrq->cmd && mrq->cmd->error == -EILSEQ) ||
+ (mrq->data && mrq->data->error == -EILSEQ))
+ mmc_retune_needed(host);
+
+ trace_mmc_request_done(host, mrq);
+
+ if (mrq->cmd) {
+ pr_debug("%s: CQE req done (direct CMD%u): %d\n",
+ mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->error);
+ } else {
+ pr_debug("%s: CQE transfer done tag %d\n",
+ mmc_hostname(host), mrq->tag);
+ }
+
+ if (mrq->data) {
+ pr_debug("%s: %d bytes transferred: %d\n",
+ mmc_hostname(host),
+ mrq->data->bytes_xfered, mrq->data->error);
+ }
+}
+
+/**
+ * mmc_cqe_request_done - CQE has finished processing an MMC request
+ * @host: MMC host which completed request
+ * @mrq: MMC request which completed
+ *
+ * CQE drivers should call this function when they have completed
+ * their processing of a request.
+ */
+void mmc_cqe_request_done(struct mmc_host *host, struct mmc_request *mrq)
+{
+ __mmc_cqe_request_done(host, mrq);
+
+ mrq->done(mrq);
+}
+EXPORT_SYMBOL(mmc_cqe_request_done);
+
+/**
+ * mmc_cqe_post_req - CQE post process of a completed MMC request
+ * @host: MMC host
+ * @mrq: MMC request to be processed
+ */
+void mmc_cqe_post_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+ if (host->cqe_ops->cqe_post_req)
+ host->cqe_ops->cqe_post_req(host, mrq);
+}
+EXPORT_SYMBOL(mmc_cqe_post_req);
+
+/* Arbitrary 1 second timeout */
+#define MMC_CQE_RECOVERY_TIMEOUT 1000
+
+int mmc_cqe_recovery(struct mmc_host *host)
+{
+ struct mmc_command cmd;
+ int err;
+
+ mmc_retune_hold_now(host);
+
+ /*
+ * Recovery is expected seldom, if at all, but it reduces performance,
+ * so make sure it is not completely silent.
+ */
+ pr_warn("%s: running CQE recovery\n", mmc_hostname(host));
+
+ host->cqe_ops->cqe_recovery_start(host);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = MMC_STOP_TRANSMISSION,
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC,
+ cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */
+ cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT,
+ mmc_wait_for_cmd(host, &cmd, 0);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = MMC_CMDQ_TASK_MGMT;
+ cmd.arg = 1; /* Discard entire queue */
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */
+ cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT,
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+
+ host->cqe_ops->cqe_recovery_finish(host);
+
+ mmc_retune_release(host);
+
+ return err;
+}
+EXPORT_SYMBOL(mmc_cqe_recovery);
+
/**
* mmc_is_req_done - Determine if a 'cap_cmd_during_tfr' request is done
* @host: MMC host
@@ -611,18 +723,15 @@ EXPORT_SYMBOL(mmc_is_req_done);
* mmc_pre_req - Prepare for a new request
* @host: MMC host to prepare command
* @mrq: MMC request to prepare for
- * @is_first_req: true if there is no previous started request
- * that may run in parellel to this call, otherwise false
*
* mmc_pre_req() is called in prior to mmc_start_req() to let
* host prepare for the new request. Preparation of a request may be
* performed while another request is running on the host.
*/
-static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
- bool is_first_req)
+static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq)
{
if (host->ops->pre_req)
- host->ops->pre_req(host, mrq, is_first_req);
+ host->ops->pre_req(host, mrq);
}
/**
@@ -642,10 +751,71 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
}
/**
- * mmc_start_req - start a non-blocking request
+ * mmc_finalize_areq() - finalize an asynchronous request
+ * @host: MMC host to finalize any ongoing request on
+ *
+ * Returns the status of the ongoing asynchronous request, but
+ * MMC_BLK_SUCCESS if no request was going on.
+ */
+static enum mmc_blk_status mmc_finalize_areq(struct mmc_host *host)
+{
+ struct mmc_context_info *context_info = &host->context_info;
+ enum mmc_blk_status status;
+
+ if (!host->areq)
+ return MMC_BLK_SUCCESS;
+
+ while (1) {
+ wait_event_interruptible(context_info->wait,
+ (context_info->is_done_rcv ||
+ context_info->is_new_req));
+
+ if (context_info->is_done_rcv) {
+ struct mmc_command *cmd;
+
+ context_info->is_done_rcv = false;
+ cmd = host->areq->mrq->cmd;
+
+ if (!cmd->error || !cmd->retries ||
+ mmc_card_removed(host->card)) {
+ status = host->areq->err_check(host->card,
+ host->areq);
+ break; /* return status */
+ } else {
+ mmc_retune_recheck(host);
+ pr_info("%s: req failed (CMD%u): %d, retrying...\n",
+ mmc_hostname(host),
+ cmd->opcode, cmd->error);
+ cmd->retries--;
+ cmd->error = 0;
+ __mmc_start_request(host, host->areq->mrq);
+ continue; /* wait for done/new event again */
+ }
+ }
+
+ return MMC_BLK_NEW_REQUEST;
+ }
+
+ mmc_retune_release(host);
+
+ /*
+ * Check BKOPS urgency for each R1 response
+ */
+ if (host->card && mmc_card_mmc(host->card) &&
+ ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) ||
+ (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) &&
+ (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) {
+ mmc_start_bkops(host->card, true);
+ }
+
+ return status;
+}
+
+/**
+ * mmc_start_areq - start an asynchronous request
* @host: MMC host to start command
- * @areq: async request to start
- * @error: out parameter returns 0 for success, otherwise non zero
+ * @areq: asynchronous request to start
+ * @ret_stat: out parameter for status
*
* Start a new MMC custom command request for a host.
* If there is on ongoing async request wait for completion
@@ -657,68 +827,47 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
* return the completed request. If there is no ongoing request, NULL
* is returned without waiting. NULL is not an error condition.
*/
-struct mmc_async_req *mmc_start_req(struct mmc_host *host,
- struct mmc_async_req *areq, int *error)
+struct mmc_async_req *mmc_start_areq(struct mmc_host *host,
+ struct mmc_async_req *areq,
+ enum mmc_blk_status *ret_stat)
{
- int err = 0;
+ enum mmc_blk_status status;
int start_err = 0;
- struct mmc_async_req *data = host->areq;
+ struct mmc_async_req *previous = host->areq;
/* Prepare a new request */
if (areq)
- mmc_pre_req(host, areq->mrq, !host->areq);
+ mmc_pre_req(host, areq->mrq);
- if (host->areq) {
- err = mmc_wait_for_data_req_done(host, host->areq->mrq, areq);
- if (err == MMC_BLK_NEW_REQUEST) {
- if (error)
- *error = err;
- /*
- * The previous request was not completed,
- * nothing to return
- */
- return NULL;
- }
- /*
- * Check BKOPS urgency for each R1 response
- */
- if (host->card && mmc_card_mmc(host->card) &&
- ((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) ||
- (mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) &&
- (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) {
+ /* Finalize previous request */
+ status = mmc_finalize_areq(host);
+ if (ret_stat)
+ *ret_stat = status;
- /* Cancel the prepared request */
- if (areq)
- mmc_post_req(host, areq->mrq, -EINVAL);
-
- mmc_start_bkops(host->card, true);
-
- /* prepare the request again */
- if (areq)
- mmc_pre_req(host, areq->mrq, !host->areq);
- }
- }
+ /* The previous request is still going on... */
+ if (status == MMC_BLK_NEW_REQUEST)
+ return NULL;
- if (!err && areq)
+ /* Fine so far, start the new request! */
+ if (status == MMC_BLK_SUCCESS && areq)
start_err = __mmc_start_data_req(host, areq->mrq);
+ /* Postprocess the old request at this point */
if (host->areq)
mmc_post_req(host, host->areq->mrq, 0);
- /* Cancel a prepared request if it was not started. */
- if ((err || start_err) && areq)
+ /* Cancel a prepared request if it was not started. */
+ if ((status != MMC_BLK_SUCCESS || start_err) && areq)
mmc_post_req(host, areq->mrq, -EINVAL);
- if (err)
+ if (status != MMC_BLK_SUCCESS)
host->areq = NULL;
else
host->areq = areq;
- if (error)
- *error = err;
- return data;
+ return previous;
}
-EXPORT_SYMBOL(mmc_start_req);
+EXPORT_SYMBOL(mmc_start_areq);
/**
* mmc_wait_for_req - start a request and wait for completion
@@ -754,8 +903,6 @@ int mmc_interrupt_hpi(struct mmc_card *card)
u32 status;
unsigned long prg_wait;
- BUG_ON(!card);
-
if (!card->ext_csd.hpi_en) {
pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host));
return 1;
@@ -820,7 +967,7 @@ EXPORT_SYMBOL(mmc_interrupt_hpi);
*/
int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
{
- struct mmc_request mrq = {NULL};
+ struct mmc_request mrq = {};
WARN_ON(!host->claimed);
@@ -850,7 +997,6 @@ int mmc_stop_bkops(struct mmc_card *card)
{
int err = 0;
- BUG_ON(!card);
err = mmc_interrupt_hpi(card);
/*
@@ -1164,6 +1310,9 @@ int mmc_execute_tuning(struct mmc_card *card)
if (!host->ops->execute_tuning)
return 0;
+ if (host->cqe_on)
+ host->cqe_ops->cqe_off(host);
+
if (mmc_card_mmc(card))
opcode = MMC_SEND_TUNING_BLOCK_HS200;
else
@@ -1203,6 +1352,9 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
*/
void mmc_set_initial_state(struct mmc_host *host)
{
+ if (host->cqe_on)
+ host->cqe_ops->cqe_off(host);
+
mmc_retune_disable(host);
if (mmc_host_is_spi(host))
@@ -1644,7 +1796,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
return ocr;
}
-int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
{
int err = 0;
int old_signal_voltage = host->ios.signal_voltage;
@@ -1660,21 +1812,12 @@ int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
}
-int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
+int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int err = 0;
u32 clock;
- BUG_ON(!host);
-
- /*
- * Send CMD11 only if the request is to switch the card to
- * 1.8V signalling.
- */
- if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
- return __mmc_set_signal_voltage(host, signal_voltage);
-
/*
* If we cannot switch voltages, return failure so the caller
* can continue without UHS mode
@@ -1713,7 +1856,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
host->ios.clock = 0;
mmc_set_ios(host);
- if (__mmc_set_signal_voltage(host, signal_voltage)) {
+ if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) {
/*
* Voltages may not have been switched, but we've already
* sent CMD11, so a power cycle is required anyway
@@ -1822,11 +1965,11 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
mmc_set_initial_state(host);
/* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
- if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330) == 0)
+ if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330))
dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
- else if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180) == 0)
+ else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
- else if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120) == 0)
+ else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
/*
@@ -1884,9 +2027,7 @@ void mmc_power_cycle(struct mmc_host *host, u32 ocr)
*/
static void __mmc_release_bus(struct mmc_host *host)
{
- BUG_ON(!host);
- BUG_ON(host->bus_refs);
- BUG_ON(!host->bus_dead);
+ WARN_ON(!host->bus_dead);
host->bus_ops = NULL;
}
@@ -1926,15 +2067,12 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
{
unsigned long flags;
- BUG_ON(!host);
- BUG_ON(!ops);
-
WARN_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
- BUG_ON(host->bus_ops);
- BUG_ON(host->bus_refs);
+ WARN_ON(host->bus_ops);
+ WARN_ON(host->bus_refs);
host->bus_ops = ops;
host->bus_refs = 1;
@@ -1950,8 +2088,6 @@ void mmc_detach_bus(struct mmc_host *host)
{
unsigned long flags;
- BUG_ON(!host);
-
WARN_ON(!host->claimed);
WARN_ON(!host->bus_ops);
@@ -2152,7 +2288,7 @@ static unsigned int mmc_erase_timeout(struct mmc_card *card,
static int mmc_do_erase(struct mmc_card *card, unsigned int from,
unsigned int to, unsigned int arg)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
unsigned int qty = 0, busy_timeout = 0;
bool use_r1b_resp = false;
unsigned long timeout;
@@ -2572,9 +2708,15 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
}
EXPORT_SYMBOL(mmc_calc_max_discard);
+bool mmc_card_is_blockaddr(struct mmc_card *card)
+{
+ return card ? mmc_card_blockaddr(card) : false;
+}
+EXPORT_SYMBOL(mmc_card_is_blockaddr);
+
int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
if (mmc_card_blockaddr(card) || mmc_card_ddr52(card) ||
mmc_card_hs400(card) || mmc_card_hs400es(card))
@@ -2590,7 +2732,7 @@ EXPORT_SYMBOL(mmc_set_blocklen);
int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
bool is_rel_write)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
cmd.opcode = MMC_SET_BLOCK_COUNT;
cmd.arg = blockcount & 0x0000FFFF;
@@ -2603,6 +2745,8 @@ EXPORT_SYMBOL(mmc_set_blockcount);
static void mmc_hw_reset_for_init(struct mmc_host *host)
{
+ mmc_pwrseq_reset(host);
+
if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
return;
host->ops->hw_reset(host);
@@ -2824,15 +2968,15 @@ void mmc_start_host(struct mmc_host *host)
host->rescan_disable = 0;
host->ios.power_mode = MMC_POWER_UNDEFINED;
- mmc_claim_host(host);
- if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)
- mmc_power_off(host);
- else
+ if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) {
+ mmc_claim_host(host);
mmc_power_up(host, host->ocr_avail);
- mmc_release_host(host);
+ mmc_release_host(host);
+ }
mmc_gpiod_request_cd_irq(host);
- _mmc_detect_change(host, 0, false);
+ if (!(host->caps2 & MMC_CAP2_CD_POST))
+ _mmc_detect_change(host, 0, false);
}
void mmc_stop_host(struct mmc_host *host)
@@ -2865,8 +3009,6 @@ void mmc_stop_host(struct mmc_host *host)
}
mmc_bus_put(host);
- BUG_ON(host->card);
-
mmc_claim_host(host);
mmc_power_off(host);
mmc_release_host(host);
@@ -3027,17 +3169,52 @@ void mmc_unregister_pm_notifier(struct mmc_host *host)
*/
void mmc_init_context_info(struct mmc_host *host)
{
- spin_lock_init(&host->context_info.lock);
host->context_info.is_new_req = false;
host->context_info.is_done_rcv = false;
host->context_info.is_waiting_last_req = false;
init_waitqueue_head(&host->context_info.wait);
}
+/*
+ * mmc_first_nonreserved_index() - get the first index that
+ * is not reserved
+ */
+int mmc_first_nonreserved_index(void)
+{
+ return __mmc_max_reserved_idx + 1;
+}
+EXPORT_SYMBOL(mmc_first_nonreserved_index);
+
+/*
+ * mmc_get_reserved_index() - get the index reserved for this host
+ * Return: The index reserved for this host or negative error value
+ * if no index is reserved for this host
+ */
+int mmc_get_reserved_index(struct mmc_host *host)
+{
+ return of_alias_get_id(host->parent->of_node, "mmc");
+}
+EXPORT_SYMBOL(mmc_get_reserved_index);
+
+static void mmc_of_reserve_idx(void)
+{
+ int max;
+
+ max = of_alias_max_index("mmc");
+ if (max < 0)
+ return;
+
+ __mmc_max_reserved_idx = max;
+ pr_debug("MMC: reserving %d slots for of aliases\n",
+ __mmc_max_reserved_idx + 1);
+}
+
static int __init mmc_init(void)
{
int ret;
+ mmc_of_reserve_idx();
+
ret = mmc_register_bus();
if (ret)
return ret;
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 0fa86a2afc26..222f588706e7 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -12,6 +12,11 @@
#define _MMC_CORE_CORE_H
#include <linux/delay.h>
+#include <linux/sched.h>
+
+struct mmc_host;
+struct mmc_card;
+struct mmc_request;
#define MMC_CMD_RETRIES 3
@@ -43,8 +48,8 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz);
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
-int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr);
-int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
+int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr);
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
@@ -69,11 +74,14 @@ void mmc_start_host(struct mmc_host *host);
void mmc_stop_host(struct mmc_host *host);
int _mmc_detect_card_removed(struct mmc_host *host);
+int mmc_detect_card_removed(struct mmc_host *host);
int mmc_attach_mmc(struct mmc_host *host);
int mmc_attach_sd(struct mmc_host *host);
int mmc_attach_sdio(struct mmc_host *host);
+int mmc_first_nonreserved_index(void);
+int mmc_get_reserved_index(struct mmc_host *host);
/* Module parameters */
extern bool use_spi_crc;
@@ -98,5 +106,38 @@ static inline void mmc_register_pm_notifier(struct mmc_host *host) { }
static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { }
#endif
-#endif
+void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq);
+bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq);
+
+int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
+ unsigned int arg);
+int mmc_can_erase(struct mmc_card *card);
+int mmc_can_trim(struct mmc_card *card);
+int mmc_can_discard(struct mmc_card *card);
+int mmc_can_sanitize(struct mmc_card *card);
+int mmc_can_secure_erase_trim(struct mmc_card *card);
+int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
+ unsigned int nr);
+unsigned int mmc_calc_max_discard(struct mmc_card *card);
+
+int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
+int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
+ bool is_rel_write);
+
+int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
+void mmc_release_host(struct mmc_host *host);
+void mmc_get_card(struct mmc_card *card);
+void mmc_put_card(struct mmc_card *card);
+
+/**
+ * mmc_claim_host - exclusively claim a host
+ * @host: mmc host to claim
+ *
+ * Claim a host for a set of operations.
+ */
+static inline void mmc_claim_host(struct mmc_host *host)
+{
+ __mmc_claim_host(host, NULL);
+}
+#endif
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index c8451ce557ae..23ec9d371f87 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -20,6 +20,8 @@
#include <linux/mmc/host.h>
#include "core.h"
+#include "card.h"
+#include "host.h"
#include "mmc_ops.h"
#ifdef CONFIG_FAIL_MMC_REQUEST
@@ -56,6 +58,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
struct mmc_ios *ios = &host->ios;
const char *str;
+ if (host->card)
+ mmc_get_card(host->card);
+
seq_printf(s, "clock:\t\t%u Hz\n", ios->clock);
if (host->actual_clock)
seq_printf(s, "actual clock:\t%u Hz\n", host->actual_clock);
@@ -192,6 +197,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
}
seq_printf(s, "driver type:\t%u (%s)\n", ios->drv_type, str);
+ if (host->card)
+ mmc_put_card(host->card);
+
return 0;
}
@@ -211,7 +219,11 @@ static int mmc_clock_opt_get(void *data, u64 *val)
{
struct mmc_host *host = data;
+ if (host->card)
+ mmc_get_card(host->card);
*val = host->ios.clock;
+ if (host->card)
+ mmc_put_card(host->card);
return 0;
}
@@ -321,7 +333,11 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
for (i = 0; i < 512; i++)
n += sprintf(buf + n, "%02x", ext_csd[i]);
n += sprintf(buf + n, "\n");
- BUG_ON(n != EXT_CSD_STR_LEN);
+
+ if (n != EXT_CSD_STR_LEN) {
+ err = -EINVAL;
+ goto out_free;
+ }
filp->private_data = buf;
kfree(ext_csd);
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 848b3453517e..aa4afba7ab1e 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -30,18 +30,16 @@
#include "host.h"
#include "slot-gpio.h"
#include "pwrseq.h"
+#include "sdio_ops.h"
#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
static DEFINE_IDA(mmc_host_ida);
-static DEFINE_SPINLOCK(mmc_host_lock);
static void mmc_host_classdev_release(struct device *dev)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
- spin_lock(&mmc_host_lock);
- ida_remove(&mmc_host_ida, host->index);
- spin_unlock(&mmc_host_lock);
+ ida_simple_remove(&mmc_host_ida, host->index);
kfree(host);
}
@@ -113,6 +111,12 @@ void mmc_retune_hold(struct mmc_host *host)
host->hold_retune += 1;
}
+void mmc_retune_hold_now(struct mmc_host *host)
+{
+ host->retune_now = 0;
+ host->hold_retune += 1;
+}
+
void mmc_retune_release(struct mmc_host *host)
{
if (host->hold_retune)
@@ -228,6 +232,8 @@ int mmc_of_parse(struct mmc_host *host)
/* Parse Card Detection */
if (device_property_read_bool(dev, "non-removable")) {
host->caps |= MMC_CAP_NONREMOVABLE;
+ if (device_property_read_bool(dev, "cd-post"))
+ host->caps2 |= MMC_CAP2_CD_POST;
} else {
cd_cap_invert = device_property_read_bool(dev, "cd-inverted");
@@ -299,6 +305,10 @@ int mmc_of_parse(struct mmc_host *host)
if (device_property_read_bool(dev, "wakeup-source") ||
device_property_read_bool(dev, "enable-sdio-wakeup")) /* legacy */
host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
+ if (device_property_read_bool(dev, "pm-ignore-notify"))
+ host->pm_caps |= MMC_PM_IGNORE_PM_NOTIFY;
+ if (device_property_read_bool(dev, "mmc-ddr-3_3v"))
+ host->caps |= MMC_CAP_3_3V_DDR;
if (device_property_read_bool(dev, "mmc-ddr-1_8v"))
host->caps |= MMC_CAP_1_8V_DDR;
if (device_property_read_bool(dev, "mmc-ddr-1_2v"))
@@ -343,6 +353,7 @@ EXPORT_SYMBOL(mmc_of_parse);
struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{
int err;
+ int alias_id;
struct mmc_host *host;
host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
@@ -351,27 +362,25 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
/* scanning will be enabled when we're ready */
host->rescan_disable = 1;
+ host->parent = dev;
-again:
- if (!ida_pre_get(&mmc_host_ida, GFP_KERNEL)) {
+ alias_id = mmc_get_reserved_index(host);
+ if (alias_id >= 0)
+ err = ida_simple_get(&mmc_host_ida, alias_id,
+ alias_id + 1, GFP_KERNEL);
+ else
+ err = ida_simple_get(&mmc_host_ida,
+ mmc_first_nonreserved_index(),
+ 0, GFP_KERNEL);
+ if (err < 0) {
kfree(host);
return NULL;
}
- spin_lock(&mmc_host_lock);
- err = ida_get_new(&mmc_host_ida, &host->index);
- spin_unlock(&mmc_host_lock);
-
- if (err == -EAGAIN) {
- goto again;
- } else if (err) {
- kfree(host);
- return NULL;
- }
+ host->index = err;
dev_set_name(&host->class_dev, "mmc%d", host->index);
- host->parent = dev;
host->class_dev.parent = dev;
host->class_dev.class = &mmc_host_class;
device_initialize(&host->class_dev);
@@ -385,6 +394,7 @@ again:
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
+ INIT_DELAYED_WORK(&host->sdio_irq_work, sdio_irq_work);
setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host);
/*
@@ -429,7 +439,8 @@ int mmc_add_host(struct mmc_host *host)
#endif
mmc_start_host(host);
- mmc_register_pm_notifier(host);
+ if (!(host->pm_caps& MMC_PM_IGNORE_PM_NOTIFY))
+ mmc_register_pm_notifier(host);
return 0;
}
@@ -446,7 +457,8 @@ EXPORT_SYMBOL(mmc_add_host);
*/
void mmc_remove_host(struct mmc_host *host)
{
- mmc_unregister_pm_notifier(host);
+ if (!(host->pm_caps& MMC_PM_IGNORE_PM_NOTIFY))
+ mmc_unregister_pm_notifier(host);
mmc_stop_host(host);
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index 992bf5397633..77d6f60d1bf9 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -10,6 +10,7 @@
*/
#ifndef _MMC_CORE_HOST_H
#define _MMC_CORE_HOST_H
+
#include <linux/mmc/host.h>
int mmc_register_host_class(void);
@@ -18,8 +19,56 @@ void mmc_unregister_host_class(void);
void mmc_retune_enable(struct mmc_host *host);
void mmc_retune_disable(struct mmc_host *host);
void mmc_retune_hold(struct mmc_host *host);
+void mmc_retune_hold_now(struct mmc_host *host);
void mmc_retune_release(struct mmc_host *host);
int mmc_retune(struct mmc_host *host);
+void mmc_retune_pause(struct mmc_host *host);
+void mmc_retune_unpause(struct mmc_host *host);
+
+static inline void mmc_retune_recheck(struct mmc_host *host)
+{
+ if (host->hold_retune <= 1)
+ host->retune_now = 1;
+}
+
+static inline int mmc_host_cmd23(struct mmc_host *host)
+{
+ return host->caps & MMC_CAP_CMD23;
+}
+
+static inline int mmc_boot_partition_access(struct mmc_host *host)
+{
+ return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC);
+}
+
+static inline int mmc_host_uhs(struct mmc_host *host)
+{
+ return host->caps &
+ (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
+ MMC_CAP_UHS_DDR50);
+}
+
+static inline bool mmc_card_hs200(struct mmc_card *card)
+{
+ return card->host->ios.timing == MMC_TIMING_MMC_HS200;
+}
+
+static inline bool mmc_card_ddr52(struct mmc_card *card)
+{
+ return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
+}
+
+static inline bool mmc_card_hs400(struct mmc_card *card)
+{
+ return card->host->ios.timing == MMC_TIMING_MMC_HS400;
+}
+
+static inline bool mmc_card_hs400es(struct mmc_card *card)
+{
+ return card->host->ios.enhanced_strobe;
+}
+
#endif
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 0c6de9f12ee8..4f814d230849 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -21,10 +21,13 @@
#include <linux/mmc/mmc.h>
#include "core.h"
+#include "card.h"
#include "host.h"
#include "bus.h"
#include "mmc_ops.h"
+#include "quirks.h"
#include "sd_ops.h"
+#include "pwrseq.h"
#define DEFAULT_CMD6_TIMEOUT_MS 500
@@ -47,17 +50,6 @@ static const unsigned int tacc_mant[] = {
35, 40, 45, 50, 55, 60, 70, 80,
};
-static const struct mmc_fixup mmc_ext_csd_fixups[] = {
- /*
- * Certain Hynix eMMC 4.41 cards might get broken when HPI feature
- * is used so disable the HPI feature for such buggy cards.
- */
- MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX,
- 0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5),
-
- END_FIXUP
-};
-
#define UNSTUFF_BITS(resp,start,size) \
({ \
const int __size = size; \
@@ -212,7 +204,7 @@ static void mmc_select_card_type(struct mmc_card *card)
avail_type |= EXT_CSD_CARD_TYPE_HS_52;
}
- if (caps & MMC_CAP_1_8V_DDR &&
+ if (caps & (MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR) &&
card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
@@ -307,6 +299,18 @@ static void mmc_manage_enhanced_area(struct mmc_card *card, u8 *ext_csd)
}
}
+static void mmc_part_add(struct mmc_card *card, unsigned int size,
+ unsigned int part_cfg, char *name, int idx, bool ro,
+ int area_type)
+{
+ card->part[card->nr_parts].size = size;
+ card->part[card->nr_parts].part_cfg = part_cfg;
+ sprintf(card->part[card->nr_parts].name, name, idx);
+ card->part[card->nr_parts].force_ro = ro;
+ card->part[card->nr_parts].area_type = area_type;
+ card->nr_parts++;
+}
+
static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd)
{
int idx;
@@ -530,8 +534,14 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
EXT_CSD_MANUAL_BKOPS_MASK);
card->ext_csd.raw_bkops_status =
ext_csd[EXT_CSD_BKOPS_STATUS];
- if (!card->ext_csd.man_bkops_en)
- pr_debug("%s: MAN_BKOPS_EN bit is not set\n",
+ if (card->ext_csd.man_bkops_en)
+ pr_debug("%s: MAN_BKOPS_EN bit is set\n",
+ mmc_hostname(card->host));
+ card->ext_csd.auto_bkops_en =
+ (ext_csd[EXT_CSD_BKOPS_EN] &
+ EXT_CSD_AUTO_BKOPS_MASK);
+ if (card->ext_csd.auto_bkops_en)
+ pr_debug("%s: AUTO_BKOPS_EN bit is set\n",
mmc_hostname(card->host));
}
@@ -617,6 +627,30 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
card->ext_csd.ffu_capable =
(ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) &&
!(ext_csd[EXT_CSD_FW_CONFIG] & 0x1);
+
+ card->ext_csd.pre_eol_info = ext_csd[EXT_CSD_PRE_EOL_INFO];
+ card->ext_csd.device_life_time_est_typ_a =
+ ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_A];
+ card->ext_csd.device_life_time_est_typ_b =
+ ext_csd[EXT_CSD_DEVICE_LIFE_TIME_EST_TYP_B];
+ }
+
+ /* eMMC v5.1 or later */
+ if (card->ext_csd.rev >= 8) {
+ card->ext_csd.cmdq_support = ext_csd[EXT_CSD_CMDQ_SUPPORT] &
+ EXT_CSD_CMDQ_SUPPORTED;
+ card->ext_csd.cmdq_depth = (ext_csd[EXT_CSD_CMDQ_DEPTH] &
+ EXT_CSD_CMDQ_DEPTH_MASK) + 1;
+ /* Exclude inefficiently small queue depths */
+ if (card->ext_csd.cmdq_depth <= 2) {
+ card->ext_csd.cmdq_support = false;
+ card->ext_csd.cmdq_depth = 0;
+ }
+ if (card->ext_csd.cmdq_support) {
+ pr_debug("%s: Command Queue supported depth %u\n",
+ mmc_hostname(card->host),
+ card->ext_csd.cmdq_depth);
+ }
}
out:
return err;
@@ -746,6 +780,10 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
MMC_DEV_ATTR(prv, "0x%x\n", card->cid.prv);
+MMC_DEV_ATTR(pre_eol_info, "%02x\n", card->ext_csd.pre_eol_info);
+MMC_DEV_ATTR(life_time, "0x%02x 0x%02x\n",
+ card->ext_csd.device_life_time_est_typ_a,
+ card->ext_csd.device_life_time_est_typ_b);
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
card->ext_csd.enhanced_area_offset);
@@ -753,6 +791,7 @@ MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
MMC_DEV_ATTR(ocr, "0x%08x\n", card->ocr);
+MMC_DEV_ATTR(cmdq_en, "%d\n", card->ext_csd.cmdq_en);
static ssize_t mmc_fwrev_show(struct device *dev,
struct device_attribute *attr,
@@ -799,6 +838,8 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_name.attr,
&dev_attr_oemid.attr,
&dev_attr_prv.attr,
+ &dev_attr_pre_eol_info.attr,
+ &dev_attr_life_time.attr,
&dev_attr_serial.attr,
&dev_attr_enhanced_area_offset.attr,
&dev_attr_enhanced_area_size.attr,
@@ -806,6 +847,7 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_rel_sectors.attr,
&dev_attr_ocr.attr,
&dev_attr_dsr.attr,
+ &dev_attr_cmdq_en.attr,
NULL,
};
ATTRIBUTE_GROUPS(mmc_std);
@@ -1003,19 +1045,6 @@ static int mmc_select_bus_width(struct mmc_card *card)
return err;
}
-/* Caller must hold re-tuning */
-static int mmc_switch_status(struct mmc_card *card)
-{
- u32 status;
- int err;
-
- err = mmc_send_status(card, &status);
- if (err)
- return err;
-
- return mmc_switch_status_error(card->host, status);
-}
-
/*
* Switch to the high-speed mode
*/
@@ -1025,13 +1054,8 @@ static int mmc_select_hs(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
- card->ext_csd.generic_cmd6_time,
- true, false, true);
- if (!err) {
- mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
- err = mmc_switch_status(card);
- }
-
+ card->ext_csd.generic_cmd6_time, MMC_TIMING_MMC_HS,
+ true, true, true);
if (err)
pr_warn("%s: switch to high-speed failed, err:%d\n",
mmc_hostname(card->host), err);
@@ -1058,10 +1082,12 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BUS_WIDTH,
- ext_csd_bits,
- card->ext_csd.generic_cmd6_time);
+ err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH,
+ ext_csd_bits,
+ card->ext_csd.generic_cmd6_time,
+ MMC_TIMING_MMC_DDR52,
+ true, true, true);
if (err) {
pr_err("%s: switch to bus width %d ddr failed\n",
mmc_hostname(host), 1 << bus_width);
@@ -1093,19 +1119,19 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
*
* WARNING: eMMC rules are NOT the same as SD DDR
*/
- err = -EINVAL;
- if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
- err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+ if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+ if (!err)
+ return 0;
+ }
- if (err && (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_8V))
- err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+ if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_8V &&
+ host->caps & MMC_CAP_1_8V_DDR)
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
/* make sure vccq is 3.3v after switching disaster */
if (err)
- err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330);
-
- if (!err)
- mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330);
return err;
}
@@ -1128,7 +1154,7 @@ static int mmc_select_hs400(struct mmc_card *card)
val = EXT_CSD_TIMING_HS;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
- card->ext_csd.generic_cmd6_time,
+ card->ext_csd.generic_cmd6_time, 0,
true, false, true);
if (err) {
pr_err("%s: switch to high-speed from hs200 failed, err:%d\n",
@@ -1163,7 +1189,7 @@ static int mmc_select_hs400(struct mmc_card *card)
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
- card->ext_csd.generic_cmd6_time,
+ card->ext_csd.generic_cmd6_time, 0,
true, false, true);
if (err) {
pr_err("%s: switch to hs400 failed, err:%d\n",
@@ -1206,7 +1232,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
/* Switch HS400 to HS DDR */
val = EXT_CSD_TIMING_HS;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
- val, card->ext_csd.generic_cmd6_time,
+ val, card->ext_csd.generic_cmd6_time, 0,
true, false, true);
if (err)
goto out_err;
@@ -1220,7 +1246,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
/* Switch HS DDR to HS */
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
EXT_CSD_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time,
- true, false, true);
+ 0, true, false, true);
if (err)
goto out_err;
@@ -1234,14 +1260,19 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
val = EXT_CSD_TIMING_HS200 |
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
- val, card->ext_csd.generic_cmd6_time,
+ val, card->ext_csd.generic_cmd6_time, 0,
true, false, true);
if (err)
goto out_err;
mmc_set_timing(host, MMC_TIMING_MMC_HS200);
- err = mmc_switch_status(card);
+ /*
+ * For HS200, CRC errors are not a reliable way to know the switch
+ * failed. If there really is a problem, we would expect tuning will
+ * fail and the result ends up the same.
+ */
+ err = __mmc_switch_status(card, false);
if (err)
goto out_err;
@@ -1284,10 +1315,10 @@ static int mmc_select_hs400es(struct mmc_card *card)
}
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_2V)
- err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V)
- err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
/* If fails try again during next card power cycle */
if (err)
@@ -1298,16 +1329,23 @@ static int mmc_select_hs400es(struct mmc_card *card)
goto out_err;
/* Switch card to HS mode */
- err = mmc_select_hs(card);
- if (err)
+ err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
+ card->ext_csd.generic_cmd6_time, 0,
+ true, false, true);
+ if (err) {
+ pr_err("%s: switch to hs for hs400es failed, err:%d\n",
+ mmc_hostname(host), err);
goto out_err;
+ }
- mmc_set_clock(host, card->ext_csd.hs_max_dtr);
-
+ mmc_set_timing(host, MMC_TIMING_MMC_HS);
err = mmc_switch_status(card);
if (err)
goto out_err;
+ mmc_set_clock(host, card->ext_csd.hs_max_dtr);
+
/* Switch card to DDR with strobe bit */
val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
@@ -1327,7 +1365,7 @@ static int mmc_select_hs400es(struct mmc_card *card)
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
- card->ext_csd.generic_cmd6_time,
+ card->ext_csd.generic_cmd6_time, 0,
true, false, true);
if (err) {
pr_err("%s: switch to hs400es failed, err:%d\n",
@@ -1371,10 +1409,10 @@ static int mmc_select_hs200(struct mmc_card *card)
old_signal_voltage = host->ios.signal_voltage;
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
- err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
- err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
/* If fails try again during next card power cycle */
if (err)
@@ -1392,14 +1430,20 @@ static int mmc_select_hs200(struct mmc_card *card)
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
- card->ext_csd.generic_cmd6_time,
+ card->ext_csd.generic_cmd6_time, 0,
true, false, true);
if (err)
goto err;
old_timing = host->ios.timing;
mmc_set_timing(host, MMC_TIMING_MMC_HS200);
- err = mmc_switch_status(card);
+ /*
+ * For HS200, CRC errors are not a reliable way to know the
+ * switch failed. If there really is a problem, we would expect
+ * tuning will fail and the result ends up the same.
+ */
+ err = __mmc_switch_status(card, false);
+
/*
* mmc_select_timing() assumes timing has not changed if
* it is a switch error.
@@ -1410,7 +1454,7 @@ static int mmc_select_hs200(struct mmc_card *card)
err:
if (err) {
/* fall back to the old signal voltage, if fails report error */
- if (__mmc_set_signal_voltage(host, old_signal_voltage))
+ if (mmc_set_signal_voltage(host, old_signal_voltage))
err = -EIO;
pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
@@ -1482,7 +1526,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
u32 cid[4];
u32 rocr;
- BUG_ON(!host);
WARN_ON(!host->claimed);
/* Set correct bus mode for MMC before attempting init */
@@ -1749,13 +1792,48 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
}
}
+ /* Enable Command Queue if supported */
+ card->ext_csd.cmdq_en = false;
+ if (card->ext_csd.cmdq_support && host->caps2 & MMC_CAP2_CQE) {
+ err = mmc_cmdq_enable(card);
+ if (err && err != -EBADMSG)
+ goto free_card;
+ if (err) {
+ pr_warn("%s: Enabling CMDQ failed\n",
+ mmc_hostname(card->host));
+ card->ext_csd.cmdq_support = false;
+ card->ext_csd.cmdq_depth = 0;
+ err = 0;
+ }
+ }
+ /*
+ * In some cases (e.g. RPMB or mmc_test), the Command Queue must be
+ * disabled for a time, so a flag is needed to indicate to re-enable the
+ * Command Queue.
+ */
+ card->reenable_cmdq = card->ext_csd.cmdq_en;
+
+ if (card->ext_csd.cmdq_en && (host->caps2 & MMC_CAP2_CQE) &&
+ !host->cqe_enabled) {
+ err = host->cqe_ops->cqe_enable(host, card);
+ if (err) {
+ pr_err("%s: Failed to enable CQE, error %d\n",
+ mmc_hostname(host), err);
+ } else {
+ host->cqe_enabled = true;
+ pr_info("%s: Command Queue Engine enabled\n",
+ mmc_hostname(host));
+ }
+ }
+
/*
* The mandatory minimum values are defined for packed command.
* read: 5, write: 3
*/
if (card->ext_csd.max_packed_writes >= 3 &&
card->ext_csd.max_packed_reads >= 5 &&
- host->caps2 & MMC_CAP2_PACKED_CMD) {
+ host->caps2 & MMC_CAP2_PACKED_CMD &&
+ !card->ext_csd.cmdq_en) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_EXP_EVENTS_CTRL,
EXT_CSD_PACKED_EVENT_EN,
@@ -1791,7 +1869,7 @@ static int mmc_can_sleep(struct mmc_card *card)
static int mmc_sleep(struct mmc_host *host)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
struct mmc_card *card = host->card;
unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000);
int err;
@@ -1856,7 +1934,7 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_POWER_OFF_NOTIFICATION,
- notify_type, timeout, true, false, false);
+ notify_type, timeout, 0, true, false, false);
if (err)
pr_err("%s: Power Off Notification timed out, %u\n",
mmc_hostname(card->host), timeout);
@@ -1872,9 +1950,6 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
*/
static void mmc_remove(struct mmc_host *host)
{
- BUG_ON(!host);
- BUG_ON(!host->card);
-
mmc_remove_card(host->card);
host->card = NULL;
}
@@ -1894,9 +1969,6 @@ static void mmc_detect(struct mmc_host *host)
{
int err;
- BUG_ON(!host);
- BUG_ON(!host->card);
-
mmc_get_card(host->card);
/*
@@ -1922,9 +1994,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
unsigned int notify_type = is_suspend ? EXT_CSD_POWER_OFF_SHORT :
EXT_CSD_POWER_OFF_LONG;
- BUG_ON(!host);
- BUG_ON(!host->card);
-
mmc_claim_host(host);
if (mmc_card_suspended(host->card))
@@ -1981,9 +2050,6 @@ static int _mmc_resume(struct mmc_host *host)
{
int err = 0;
- BUG_ON(!host);
- BUG_ON(!host->card);
-
mmc_claim_host(host);
if (!mmc_card_suspended(host->card))
@@ -2092,6 +2158,7 @@ static int mmc_reset(struct mmc_host *host)
} else {
/* Do a brute force power cycle */
mmc_power_cycle(host, card->ocr);
+ mmc_pwrseq_reset(host);
}
return mmc_init_card(host, card->ocr, card);
}
@@ -2116,7 +2183,6 @@ int mmc_attach_mmc(struct mmc_host *host)
int err;
u32 ocr, rocr;
- BUG_ON(!host);
WARN_ON(!host->claimed);
/* Set correct bus mode for MMC before attempting attach */
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index ad6e9798e949..bd6dfd425b7c 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -54,21 +54,15 @@ static const u8 tuning_blk_pattern_8bit[] = {
0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
};
-static inline int __mmc_send_status(struct mmc_card *card, u32 *status,
- bool ignore_crc)
+int mmc_send_status(struct mmc_card *card, u32 *status)
{
int err;
- struct mmc_command cmd = {0};
-
- BUG_ON(!card);
- BUG_ON(!card->host);
+ struct mmc_command cmd = {};
cmd.opcode = MMC_SEND_STATUS;
if (!mmc_host_is_spi(card->host))
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
- if (ignore_crc)
- cmd.flags &= ~MMC_RSP_CRC;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err)
@@ -83,16 +77,9 @@ static inline int __mmc_send_status(struct mmc_card *card, u32 *status,
return 0;
}
-int mmc_send_status(struct mmc_card *card, u32 *status)
-{
- return __mmc_send_status(card, status, false);
-}
-
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{
- struct mmc_command cmd = {0};
-
- BUG_ON(!host);
+ struct mmc_command cmd = {};
cmd.opcode = MMC_SELECT_CARD;
@@ -109,7 +96,6 @@ static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
int mmc_select_card(struct mmc_card *card)
{
- BUG_ON(!card);
return _mmc_select_card(card->host, card);
}
@@ -129,7 +115,7 @@ int mmc_deselect_cards(struct mmc_host *host)
*/
int mmc_set_dsr(struct mmc_host *host)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
cmd.opcode = MMC_SET_DSR;
@@ -142,7 +128,7 @@ int mmc_set_dsr(struct mmc_host *host)
int mmc_go_idle(struct mmc_host *host)
{
int err;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
/*
* Non-SPI hosts need to prevent chipselect going active during
@@ -178,11 +164,9 @@ int mmc_go_idle(struct mmc_host *host)
int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int i, err = 0;
- BUG_ON(!host);
-
cmd.opcode = MMC_SEND_OP_COND;
cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
@@ -219,10 +203,7 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
{
int err;
- struct mmc_command cmd = {0};
-
- BUG_ON(!host);
- BUG_ON(!cid);
+ struct mmc_command cmd = {};
cmd.opcode = MMC_ALL_SEND_CID;
cmd.arg = 0;
@@ -239,10 +220,7 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
int mmc_set_relative_addr(struct mmc_card *card)
{
- struct mmc_command cmd = {0};
-
- BUG_ON(!card);
- BUG_ON(!card->host);
+ struct mmc_command cmd = {};
cmd.opcode = MMC_SET_RELATIVE_ADDR;
cmd.arg = card->rca << 16;
@@ -255,10 +233,7 @@ static int
mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
{
int err;
- struct mmc_command cmd = {0};
-
- BUG_ON(!host);
- BUG_ON(!cxd);
+ struct mmc_command cmd = {};
cmd.opcode = opcode;
cmd.arg = arg;
@@ -281,9 +256,9 @@ static int
mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
u32 opcode, void *buf, unsigned len)
{
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
struct scatterlist sg;
mrq.cmd = &cmd;
@@ -330,7 +305,7 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
int mmc_send_csd(struct mmc_card *card, u32 *csd)
{
int ret, i;
- u32 *csd_tmp;
+ __be32 *csd_tmp;
if (!mmc_host_is_spi(card->host))
return mmc_send_cxd_native(card->host, card->rca << 16,
@@ -344,7 +319,7 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd)
if (ret)
goto err;
- for (i = 0;i < 4;i++)
+ for (i = 0; i < 4; i++)
csd[i] = be32_to_cpu(csd_tmp[i]);
err:
@@ -355,7 +330,7 @@ err:
int mmc_send_cid(struct mmc_host *host, u32 *cid)
{
int ret, i;
- u32 *cid_tmp;
+ __be32 *cid_tmp;
if (!mmc_host_is_spi(host)) {
if (!host->card)
@@ -372,7 +347,7 @@ int mmc_send_cid(struct mmc_host *host, u32 *cid)
if (ret)
goto err;
- for (i = 0;i < 4;i++)
+ for (i = 0; i < 4; i++)
cid[i] = be32_to_cpu(cid_tmp[i]);
err:
@@ -412,7 +387,7 @@ EXPORT_SYMBOL_GPL(mmc_get_ext_csd);
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int err;
cmd.opcode = MMC_SPI_READ_OCR;
@@ -427,7 +402,7 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int err;
cmd.opcode = MMC_SPI_CRC_ON_OFF;
@@ -440,7 +415,7 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
return err;
}
-int mmc_switch_status_error(struct mmc_host *host, u32 status)
+static int mmc_switch_status_error(struct mmc_host *host, u32 status)
{
if (mmc_host_is_spi(host)) {
if (status & R1_SPI_ILLEGAL_COMMAND)
@@ -455,6 +430,85 @@ int mmc_switch_status_error(struct mmc_host *host, u32 status)
return 0;
}
+/* Caller must hold re-tuning */
+int __mmc_switch_status(struct mmc_card *card, bool crc_err_fatal)
+{
+ u32 status;
+ int err;
+
+ err = mmc_send_status(card, &status);
+ if (!crc_err_fatal && err == -EILSEQ)
+ return 0;
+ if (err)
+ return err;
+
+ return mmc_switch_status_error(card->host, status);
+}
+
+int mmc_switch_status(struct mmc_card *card)
+{
+ return __mmc_switch_status(card, true);
+}
+
+static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
+ bool send_status, bool retry_crc_err)
+{
+ struct mmc_host *host = card->host;
+ int err;
+ unsigned long timeout;
+ u32 status = 0;
+ bool expired = false;
+ bool busy = false;
+
+ /* We have an unspecified cmd timeout, use the fallback value. */
+ if (!timeout_ms)
+ timeout_ms = MMC_OPS_TIMEOUT_MS;
+
+ /*
+ * In cases when not allowed to poll by using CMD13 or because we aren't
+ * capable of polling by using ->card_busy(), then rely on waiting the
+ * stated timeout to be sufficient.
+ */
+ if (!send_status && !host->ops->card_busy) {
+ mmc_delay(timeout_ms);
+ return 0;
+ }
+
+ timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1;
+ do {
+ /*
+ * Due to the possibility of being preempted while polling,
+ * check the expiration time first.
+ */
+ expired = time_after(jiffies, timeout);
+
+ if (host->ops->card_busy) {
+ busy = host->ops->card_busy(host);
+ } else {
+ err = mmc_send_status(card, &status);
+ if (retry_crc_err && err == -EILSEQ) {
+ busy = true;
+ } else if (err) {
+ return err;
+ } else {
+ err = mmc_switch_status_error(host, status);
+ if (err)
+ return err;
+ busy = R1_CURRENT_STATE(status) == R1_STATE_PRG;
+ }
+ }
+
+ /* Timeout if the device still remains busy. */
+ if (expired && busy) {
+ pr_err("%s: Card stuck being busy! %s\n",
+ mmc_hostname(host), __func__);
+ return -ETIMEDOUT;
+ }
+ } while (busy);
+
+ return 0;
+}
+
/**
* __mmc_switch - modify EXT_CSD register
* @card: the MMC card associated with the data transfer
@@ -463,24 +517,22 @@ int mmc_switch_status_error(struct mmc_host *host, u32 status)
* @value: value to program into EXT_CSD register
* @timeout_ms: timeout (ms) for operation performed by register write,
* timeout of zero implies maximum possible timeout
+ * @timing: new timing to change to
* @use_busy_signal: use the busy signal as response type
* @send_status: send status cmd to poll for busy
- * @ignore_crc: ignore CRC errors when sending status cmd to poll for busy
+ * @retry_crc_err: retry when CRC errors when polling with CMD13 for busy
*
* Modifies the EXT_CSD register for selected card.
*/
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
- unsigned int timeout_ms, bool use_busy_signal, bool send_status,
- bool ignore_crc)
+ unsigned int timeout_ms, unsigned char timing,
+ bool use_busy_signal, bool send_status, bool retry_crc_err)
{
struct mmc_host *host = card->host;
int err;
- struct mmc_command cmd = {0};
- unsigned long timeout;
- u32 status = 0;
+ struct mmc_command cmd = {};
bool use_r1b_resp = use_busy_signal;
- bool expired = false;
- bool busy = false;
+ unsigned char old_timing = host->ios.timing;
mmc_retune_hold(host);
@@ -522,62 +574,32 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
if (!use_busy_signal)
goto out;
- /*
- * CRC errors shall only be ignored in cases were CMD13 is used to poll
- * to detect busy completion.
- */
- if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
- ignore_crc = false;
-
- /* We have an unspecified cmd timeout, use the fallback value. */
- if (!timeout_ms)
- timeout_ms = MMC_OPS_TIMEOUT_MS;
+ /*If SPI or used HW busy detection above, then we don't need to poll. */
+ if (((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) ||
+ mmc_host_is_spi(host))
+ goto out_tim;
- /* Must check status to be sure of no errors. */
- timeout = jiffies + msecs_to_jiffies(timeout_ms) + 1;
- do {
- /*
- * Due to the possibility of being preempted after
- * sending the status command, check the expiration
- * time first.
- */
- expired = time_after(jiffies, timeout);
- if (send_status) {
- err = __mmc_send_status(card, &status, ignore_crc);
- if (err)
- goto out;
- }
- if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
- break;
- if (host->ops->card_busy) {
- if (!host->ops->card_busy(host))
- break;
- busy = true;
- }
- if (mmc_host_is_spi(host))
- break;
+ /* Let's try to poll to find out when the command is completed. */
+ err = mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err);
+ if (err)
+ goto out;
- /*
- * We are not allowed to issue a status command and the host
- * does'nt support MMC_CAP_WAIT_WHILE_BUSY, then we can only
- * rely on waiting for the stated timeout to be sufficient.
- */
- if (!send_status && !host->ops->card_busy) {
- mmc_delay(timeout_ms);
- goto out;
- }
+out_tim:
+ /* Switch to new timing before check switch status. */
+ if (timing)
+ mmc_set_timing(host, timing);
- /* Timeout if the device never leaves the program state. */
- if (expired &&
- (R1_CURRENT_STATE(status) == R1_STATE_PRG || busy)) {
- pr_err("%s: Card stuck in programming state! %s\n",
- mmc_hostname(host), __func__);
- err = -ETIMEDOUT;
- goto out;
- }
- } while (R1_CURRENT_STATE(status) == R1_STATE_PRG || busy);
+ /*
+ * WORKAROUND: for Sandisk eMMC cards, it might need certain delay
+ * before sending CMD13 after CMD6
+ */
+ mdelay(1);
- err = mmc_switch_status_error(host, status);
+ if (send_status) {
+ err = mmc_switch_status(card);
+ if (err && timing)
+ mmc_set_timing(host, old_timing);
+ }
out:
mmc_retune_release(host);
@@ -587,16 +609,16 @@ out:
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms)
{
- return __mmc_switch(card, set, index, value, timeout_ms, true, true,
- false);
+ return __mmc_switch(card, set, index, value, timeout_ms, 0,
+ true, true, false);
}
EXPORT_SYMBOL_GPL(mmc_switch);
int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error)
{
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
struct scatterlist sg;
struct mmc_ios *ios = &host->ios;
const u8 *tuning_block_pattern;
@@ -661,13 +683,38 @@ out:
}
EXPORT_SYMBOL_GPL(mmc_send_tuning);
+int mmc_abort_tuning(struct mmc_host *host, u32 opcode)
+{
+ struct mmc_command cmd = {};
+
+ /*
+ * eMMC specification specifies that CMD12 can be used to stop a tuning
+ * command, but SD specification does not, so do nothing unless it is
+ * eMMC.
+ */
+ if (opcode != MMC_SEND_TUNING_BLOCK_HS200)
+ return 0;
+
+ cmd.opcode = MMC_STOP_TRANSMISSION;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+
+ /*
+ * For drivers that override R1 to R1b, set an arbitrary timeout based
+ * on the tuning timeout i.e. 150ms.
+ */
+ cmd.busy_timeout = 150;
+
+ return mmc_wait_for_cmd(host, &cmd, 0);
+}
+EXPORT_SYMBOL_GPL(mmc_abort_tuning);
+
static int
mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
u8 len)
{
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
struct scatterlist sg;
u8 *data_buf;
u8 *test_buf;
@@ -761,7 +808,7 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width)
int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
unsigned int opcode;
int err;
@@ -797,3 +844,31 @@ int mmc_can_ext_csd(struct mmc_card *card)
{
return (card && card->csd.mmca_vsn > CSD_SPEC_VER_3);
}
+
+static int mmc_cmdq_switch(struct mmc_card *card, bool enable)
+{
+ u8 val = enable ? EXT_CSD_CMDQ_MODE_ENABLED : 0;
+ int err;
+
+ if (!card->ext_csd.cmdq_support)
+ return -EOPNOTSUPP;
+
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_CMDQ_MODE_EN,
+ val, card->ext_csd.generic_cmd6_time);
+ if (!err)
+ card->ext_csd.cmdq_en = enable;
+
+ return err;
+}
+
+int mmc_cmdq_enable(struct mmc_card *card)
+{
+ return mmc_cmdq_switch(card, true);
+}
+EXPORT_SYMBOL_GPL(mmc_cmdq_enable);
+
+int mmc_cmdq_disable(struct mmc_card *card)
+{
+ return mmc_cmdq_switch(card, false);
+}
+EXPORT_SYMBOL_GPL(mmc_cmdq_disable);
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index f1b8e81aaa28..978bd2e60f8a 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -12,6 +12,11 @@
#ifndef _MMC_MMC_OPS_H
#define _MMC_MMC_OPS_H
+#include <linux/types.h>
+
+struct mmc_host;
+struct mmc_card;
+
int mmc_select_card(struct mmc_card *card);
int mmc_deselect_cards(struct mmc_host *host);
int mmc_set_dsr(struct mmc_host *host);
@@ -26,11 +31,23 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
int mmc_bus_test(struct mmc_card *card, u8 bus_width);
int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
+int mmc_interrupt_hpi(struct mmc_card *card);
int mmc_can_ext_csd(struct mmc_card *card);
-int mmc_switch_status_error(struct mmc_host *host, u32 status);
+int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
+int mmc_switch_status(struct mmc_card *card);
+int __mmc_switch_status(struct mmc_card *card, bool crc_err_fatal);
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
- unsigned int timeout_ms, bool use_busy_signal, bool send_status,
- bool ignore_crc);
+ unsigned int timeout_ms, unsigned char timing,
+ bool use_busy_signal, bool send_status, bool retry_crc_err);
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
+ unsigned int timeout_ms);
+int mmc_stop_bkops(struct mmc_card *card);
+int mmc_read_bkops_status(struct mmc_card *card);
+void mmc_start_bkops(struct mmc_card *card, bool from_exception);
+int mmc_can_reset(struct mmc_card *card);
+int mmc_flush_cache(struct mmc_card *card);
+int mmc_cmdq_enable(struct mmc_card *card);
+int mmc_cmdq_disable(struct mmc_card *card);
#endif
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/core/mmc_test.c
index df382be62634..fd1b4b8510b9 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/core/mmc_test.c
@@ -1,6 +1,4 @@
/*
- * linux/drivers/mmc/card/mmc_test.c
- *
* Copyright 2007-2008 Pierre Ossman
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +22,12 @@
#include <linux/seq_file.h>
#include <linux/module.h>
+#include "core.h"
+#include "card.h"
+#include "host.h"
+#include "bus.h"
+#include "mmc_ops.h"
+
#define RESULT_OK 0
#define RESULT_FAIL 1
#define RESULT_UNSUP_HOST 2
@@ -214,7 +218,8 @@ static void mmc_test_prepare_mrq(struct mmc_test_card *test,
struct mmc_request *mrq, struct scatterlist *sg, unsigned sg_len,
unsigned dev_addr, unsigned blocks, unsigned blksz, int write)
{
- BUG_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop);
+ if (WARN_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop))
+ return;
if (blocks > 1) {
mrq->cmd->opcode = write ?
@@ -261,7 +266,7 @@ static int mmc_test_busy(struct mmc_command *cmd)
static int mmc_test_wait_busy(struct mmc_test_card *test)
{
int ret, busy;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
busy = 0;
do {
@@ -278,8 +283,7 @@ static int mmc_test_wait_busy(struct mmc_test_card *test)
if (!busy && mmc_test_busy(&cmd)) {
busy = 1;
if (test->card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
- pr_info("%s: Warning: Host did not "
- "wait for busy state to end.\n",
+ pr_info("%s: Warning: Host did not wait for busy state to end.\n",
mmc_hostname(test->card->host));
}
} while (mmc_test_busy(&cmd));
@@ -293,10 +297,10 @@ static int mmc_test_wait_busy(struct mmc_test_card *test)
static int mmc_test_buffer_transfer(struct mmc_test_card *test,
u8 *buffer, unsigned addr, unsigned blksz, int write)
{
- struct mmc_request mrq = {0};
- struct mmc_command cmd = {0};
- struct mmc_command stop = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_command stop = {};
+ struct mmc_data data = {};
struct scatterlist sg;
@@ -358,12 +362,11 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
if (max_segs > max_page_cnt)
max_segs = max_page_cnt;
- mem = kzalloc(sizeof(struct mmc_test_mem), GFP_KERNEL);
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
if (!mem)
return NULL;
- mem->arr = kzalloc(sizeof(struct mmc_test_pages) * max_segs,
- GFP_KERNEL);
+ mem->arr = kcalloc(max_segs, sizeof(*mem->arr), GFP_KERNEL);
if (!mem->arr)
goto out_free;
@@ -547,7 +550,7 @@ static void mmc_test_save_transfer_result(struct mmc_test_card *test,
if (!test->gr)
return;
- tr = kmalloc(sizeof(struct mmc_test_transfer_result), GFP_KERNEL);
+ tr = kmalloc(sizeof(*tr), GFP_KERNEL);
if (!tr)
return;
@@ -642,11 +645,11 @@ static int __mmc_test_prepare(struct mmc_test_card *test, int write)
if (write)
memset(test->buffer, 0xDF, 512);
else {
- for (i = 0;i < 512;i++)
+ for (i = 0; i < 512; i++)
test->buffer[i] = i;
}
- for (i = 0;i < BUFFER_SIZE / 512;i++) {
+ for (i = 0; i < BUFFER_SIZE / 512; i++) {
ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1);
if (ret)
return ret;
@@ -675,7 +678,7 @@ static int mmc_test_cleanup(struct mmc_test_card *test)
memset(test->buffer, 0, 512);
- for (i = 0;i < BUFFER_SIZE / 512;i++) {
+ for (i = 0; i < BUFFER_SIZE / 512; i++) {
ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1);
if (ret)
return ret;
@@ -694,7 +697,8 @@ static int mmc_test_cleanup(struct mmc_test_card *test)
static void mmc_test_prepare_broken_mrq(struct mmc_test_card *test,
struct mmc_request *mrq, int write)
{
- BUG_ON(!mrq || !mrq->cmd || !mrq->data);
+ if (WARN_ON(!mrq || !mrq->cmd || !mrq->data))
+ return;
if (mrq->data->blocks > 1) {
mrq->cmd->opcode = write ?
@@ -714,7 +718,8 @@ static int mmc_test_check_result(struct mmc_test_card *test,
{
int ret;
- BUG_ON(!mrq || !mrq->cmd || !mrq->data);
+ if (WARN_ON(!mrq || !mrq->cmd || !mrq->data))
+ return -EINVAL;
ret = 0;
@@ -736,15 +741,28 @@ static int mmc_test_check_result(struct mmc_test_card *test,
return ret;
}
-static int mmc_test_check_result_async(struct mmc_card *card,
+static enum mmc_blk_status mmc_test_check_result_async(struct mmc_card *card,
struct mmc_async_req *areq)
{
struct mmc_test_async_req *test_async =
container_of(areq, struct mmc_test_async_req, areq);
+ int ret;
mmc_test_wait_busy(test_async->test);
- return mmc_test_check_result(test_async->test, areq->mrq);
+ /*
+ * FIXME: this would earlier just casts a regular error code,
+ * either of the kernel type -ERRORCODE or the local test framework
+ * RESULT_* errorcode, into an enum mmc_blk_status and return as
+ * result check. Instead, convert it to some reasonable type by just
+ * returning either MMC_BLK_SUCCESS or MMC_BLK_CMD_ERR.
+ * If possible, a reasonable error code should be returned.
+ */
+ ret = mmc_test_check_result(test_async->test, areq->mrq);
+ if (ret)
+ return MMC_BLK_CMD_ERR;
+
+ return MMC_BLK_SUCCESS;
}
/*
@@ -755,7 +773,8 @@ static int mmc_test_check_broken_result(struct mmc_test_card *test,
{
int ret;
- BUG_ON(!mrq || !mrq->cmd || !mrq->data);
+ if (WARN_ON(!mrq || !mrq->cmd || !mrq->data))
+ return -EINVAL;
ret = 0;
@@ -817,6 +836,7 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
struct mmc_async_req *done_areq;
struct mmc_async_req *cur_areq = &test_areq[0].areq;
struct mmc_async_req *other_areq = &test_areq[1].areq;
+ enum mmc_blk_status status;
int i;
int ret = RESULT_OK;
@@ -834,10 +854,12 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
for (i = 0; i < count; i++) {
mmc_test_prepare_mrq(test, cur_areq->mrq, sg, sg_len, dev_addr,
blocks, blksz, write);
- done_areq = mmc_start_req(test->card->host, cur_areq, &ret);
+ done_areq = mmc_start_areq(test->card->host, cur_areq, &status);
- if (ret || (!done_areq && i > 0))
+ if (status != MMC_BLK_SUCCESS || (!done_areq && i > 0)) {
+ ret = RESULT_FAIL;
goto err;
+ }
if (done_areq) {
if (done_areq->mrq == &mrq2)
@@ -851,7 +873,9 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
dev_addr += blocks;
}
- done_areq = mmc_start_req(test->card->host, NULL, &ret);
+ done_areq = mmc_start_areq(test->card->host, NULL, &status);
+ if (status != MMC_BLK_SUCCESS)
+ ret = RESULT_FAIL;
return ret;
err:
@@ -865,10 +889,10 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test,
struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
unsigned blocks, unsigned blksz, int write)
{
- struct mmc_request mrq = {0};
- struct mmc_command cmd = {0};
- struct mmc_command stop = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_command stop = {};
+ struct mmc_data data = {};
mrq.cmd = &cmd;
mrq.data = &data;
@@ -890,10 +914,10 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test,
static int mmc_test_broken_transfer(struct mmc_test_card *test,
unsigned blocks, unsigned blksz, int write)
{
- struct mmc_request mrq = {0};
- struct mmc_command cmd = {0};
- struct mmc_command stop = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_command stop = {};
+ struct mmc_data data = {};
struct scatterlist sg;
@@ -926,7 +950,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
unsigned long flags;
if (write) {
- for (i = 0;i < blocks * blksz;i++)
+ for (i = 0; i < blocks * blksz; i++)
test->scratch[i] = i;
} else {
memset(test->scratch, 0, BUFFER_SIZE);
@@ -960,7 +984,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
memset(test->buffer, 0, sectors * 512);
- for (i = 0;i < sectors;i++) {
+ for (i = 0; i < sectors; i++) {
ret = mmc_test_buffer_transfer(test,
test->buffer + i * 512,
dev_addr + i, 512, 0);
@@ -968,12 +992,12 @@ static int mmc_test_transfer(struct mmc_test_card *test,
return ret;
}
- for (i = 0;i < blocks * blksz;i++) {
+ for (i = 0; i < blocks * blksz; i++) {
if (test->buffer[i] != (u8)i)
return RESULT_FAIL;
}
- for (;i < sectors * 512;i++) {
+ for (; i < sectors * 512; i++) {
if (test->buffer[i] != 0xDF)
return RESULT_FAIL;
}
@@ -981,7 +1005,7 @@ static int mmc_test_transfer(struct mmc_test_card *test,
local_irq_save(flags);
sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
local_irq_restore(flags);
- for (i = 0;i < blocks * blksz;i++) {
+ for (i = 0; i < blocks * blksz; i++) {
if (test->scratch[i] != (u8)i)
return RESULT_FAIL;
}
@@ -1066,7 +1090,7 @@ static int mmc_test_multi_write(struct mmc_test_card *test)
sg_init_one(&sg, test->buffer, size);
- return mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
+ return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1);
}
static int mmc_test_multi_read(struct mmc_test_card *test)
@@ -1087,7 +1111,7 @@ static int mmc_test_multi_read(struct mmc_test_card *test)
sg_init_one(&sg, test->buffer, size);
- return mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
+ return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0);
}
static int mmc_test_pow2_write(struct mmc_test_card *test)
@@ -1098,7 +1122,7 @@ static int mmc_test_pow2_write(struct mmc_test_card *test)
if (!test->card->csd.write_partial)
return RESULT_UNSUP_CARD;
- for (i = 1; i < 512;i <<= 1) {
+ for (i = 1; i < 512; i <<= 1) {
sg_init_one(&sg, test->buffer, i);
ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1);
if (ret)
@@ -1116,7 +1140,7 @@ static int mmc_test_pow2_read(struct mmc_test_card *test)
if (!test->card->csd.read_partial)
return RESULT_UNSUP_CARD;
- for (i = 1; i < 512;i <<= 1) {
+ for (i = 1; i < 512; i <<= 1) {
sg_init_one(&sg, test->buffer, i);
ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0);
if (ret)
@@ -1134,7 +1158,7 @@ static int mmc_test_weird_write(struct mmc_test_card *test)
if (!test->card->csd.write_partial)
return RESULT_UNSUP_CARD;
- for (i = 3; i < 512;i += 7) {
+ for (i = 3; i < 512; i += 7) {
sg_init_one(&sg, test->buffer, i);
ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1);
if (ret)
@@ -1152,7 +1176,7 @@ static int mmc_test_weird_read(struct mmc_test_card *test)
if (!test->card->csd.read_partial)
return RESULT_UNSUP_CARD;
- for (i = 3; i < 512;i += 7) {
+ for (i = 3; i < 512; i += 7) {
sg_init_one(&sg, test->buffer, i);
ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0);
if (ret)
@@ -1211,7 +1235,7 @@ static int mmc_test_align_multi_write(struct mmc_test_card *test)
for (i = 1; i < TEST_ALIGN_END; i++) {
sg_init_one(&sg, test->buffer + i, size);
- ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
+ ret = mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1);
if (ret)
return ret;
}
@@ -1238,7 +1262,7 @@ static int mmc_test_align_multi_read(struct mmc_test_card *test)
for (i = 1; i < TEST_ALIGN_END; i++) {
sg_init_one(&sg, test->buffer + i, size);
- ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
+ ret = mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0);
if (ret)
return ret;
}
@@ -1337,7 +1361,7 @@ static int mmc_test_multi_write_high(struct mmc_test_card *test)
sg_init_table(&sg, 1);
sg_set_page(&sg, test->highmem, size, 0);
- return mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
+ return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 1);
}
static int mmc_test_multi_read_high(struct mmc_test_card *test)
@@ -1359,7 +1383,7 @@ static int mmc_test_multi_read_high(struct mmc_test_card *test)
sg_init_table(&sg, 1);
sg_set_page(&sg, test->highmem, size, 0);
- return mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
+ return mmc_test_transfer(test, &sg, 1, 0, size / 512, 512, 0);
}
#else
@@ -1513,7 +1537,7 @@ static int mmc_test_area_cleanup(struct mmc_test_card *test)
/*
* Initialize an area for testing large transfers. The test area is set to the
- * middle of the card because cards may have different charateristics at the
+ * middle of the card because cards may have different characteristics at the
* front (for FAT file system optimization). Optionally, the area is erased
* (if the card supports it) which may improve write performance. Optionally,
* the area is filled with data for subsequent read tests.
@@ -1559,7 +1583,7 @@ static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill)
if (!t->mem)
return -ENOMEM;
- t->sg = kmalloc(sizeof(struct scatterlist) * t->max_segs, GFP_KERNEL);
+ t->sg = kmalloc_array(t->max_segs, sizeof(*t->sg), GFP_KERNEL);
if (!t->sg) {
ret = -ENOMEM;
goto out_free;
@@ -2127,7 +2151,7 @@ static int mmc_test_rw_multiple_sg_len(struct mmc_test_card *test,
int i;
for (i = 0 ; i < rw->len && ret == 0; i++) {
- ret = mmc_test_rw_multiple(test, rw, 512*1024, rw->size,
+ ret = mmc_test_rw_multiple(test, rw, 512 * 1024, rw->size,
rw->sg_len[i]);
if (ret)
break;
@@ -2351,6 +2375,7 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
struct mmc_request *mrq;
unsigned long timeout;
bool expired = false;
+ enum mmc_blk_status blkstat = MMC_BLK_SUCCESS;
int ret = 0, cmd_ret;
u32 status = 0;
int count = 0;
@@ -2378,9 +2403,11 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
/* Start ongoing data request */
if (use_areq) {
- mmc_start_req(host, &test_areq.areq, &ret);
- if (ret)
+ mmc_start_areq(host, &test_areq.areq, &blkstat);
+ if (blkstat != MMC_BLK_SUCCESS) {
+ ret = RESULT_FAIL;
goto out_free;
+ }
} else {
mmc_wait_for_req(host, mrq);
}
@@ -2413,10 +2440,13 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
} while (repeat_cmd && R1_CURRENT_STATE(status) != R1_STATE_TRAN);
/* Wait for data request to complete */
- if (use_areq)
- mmc_start_req(host, NULL, &ret);
- else
+ if (use_areq) {
+ mmc_start_areq(host, NULL, &blkstat);
+ if (blkstat != MMC_BLK_SUCCESS)
+ ret = RESULT_FAIL;
+ } else {
mmc_wait_for_req_done(test->card->host, mrq);
+ }
/*
* For cap_cmd_during_tfr request, upper layer must send stop if
@@ -2928,7 +2958,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
mmc_claim_host(test->card->host);
- for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
+ for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++) {
struct mmc_test_general_result *gr;
if (testcase && ((i + 1) != testcase))
@@ -2941,16 +2971,14 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
if (mmc_test_cases[i].prepare) {
ret = mmc_test_cases[i].prepare(test);
if (ret) {
- pr_info("%s: Result: Prepare "
- "stage failed! (%d)\n",
+ pr_info("%s: Result: Prepare stage failed! (%d)\n",
mmc_hostname(test->card->host),
ret);
continue;
}
}
- gr = kzalloc(sizeof(struct mmc_test_general_result),
- GFP_KERNEL);
+ gr = kzalloc(sizeof(*gr), GFP_KERNEL);
if (gr) {
INIT_LIST_HEAD(&gr->tr_lst);
@@ -2979,13 +3007,11 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
mmc_hostname(test->card->host));
break;
case RESULT_UNSUP_HOST:
- pr_info("%s: Result: UNSUPPORTED "
- "(by host)\n",
+ pr_info("%s: Result: UNSUPPORTED (by host)\n",
mmc_hostname(test->card->host));
break;
case RESULT_UNSUP_CARD:
- pr_info("%s: Result: UNSUPPORTED "
- "(by card)\n",
+ pr_info("%s: Result: UNSUPPORTED (by card)\n",
mmc_hostname(test->card->host));
break;
default:
@@ -3000,8 +3026,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
if (mmc_test_cases[i].cleanup) {
ret = mmc_test_cases[i].cleanup(test);
if (ret) {
- pr_info("%s: Warning: Cleanup "
- "stage failed! (%d)\n",
+ pr_info("%s: Warning: Cleanup stage failed! (%d)\n",
mmc_hostname(test->card->host),
ret);
}
@@ -3087,7 +3112,7 @@ static ssize_t mtf_test_write(struct file *file, const char __user *buf,
if (ret)
return ret;
- test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL);
+ test = kzalloc(sizeof(*test), GFP_KERNEL);
if (!test)
return -ENOMEM;
@@ -3137,9 +3162,9 @@ static int mtf_testlist_show(struct seq_file *sf, void *data)
mutex_lock(&mmc_test_lock);
- seq_printf(sf, "0:\tRun all tests\n");
+ seq_puts(sf, "0:\tRun all tests\n");
for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++)
- seq_printf(sf, "%d:\t%s\n", i+1, mmc_test_cases[i].name);
+ seq_printf(sf, "%d:\t%s\n", i + 1, mmc_test_cases[i].name);
mutex_unlock(&mmc_test_lock);
@@ -3192,7 +3217,7 @@ static int __mmc_test_register_dbgfs_file(struct mmc_card *card,
return -ENODEV;
}
- df = kmalloc(sizeof(struct mmc_test_dbgfs_file), GFP_KERNEL);
+ df = kmalloc(sizeof(*df), GFP_KERNEL);
if (!df) {
debugfs_remove(file);
dev_err(&card->dev,
@@ -3240,6 +3265,14 @@ static int mmc_test_probe(struct mmc_card *card)
if (ret)
return ret;
+ if (card->ext_csd.cmdq_en) {
+ mmc_claim_host(card->host);
+ ret = mmc_cmdq_disable(card);
+ mmc_release_host(card->host);
+ if (ret)
+ return ret;
+ }
+
dev_info(&card->dev, "Card claimed for testing.\n");
return 0;
@@ -3247,6 +3280,11 @@ static int mmc_test_probe(struct mmc_card *card)
static void mmc_test_remove(struct mmc_card *card)
{
+ if (card->reenable_cmdq) {
+ mmc_claim_host(card->host);
+ mmc_cmdq_enable(card);
+ mmc_release_host(card->host);
+ }
mmc_test_free_result(card);
mmc_test_free_dbgfs_file(card);
}
diff --git a/drivers/mmc/core/pwrseq.c b/drivers/mmc/core/pwrseq.c
index 9386c4771814..e3ad30fa8307 100644
--- a/drivers/mmc/core/pwrseq.c
+++ b/drivers/mmc/core/pwrseq.c
@@ -76,6 +76,14 @@ void mmc_pwrseq_power_off(struct mmc_host *host)
pwrseq->ops->power_off(host);
}
+void mmc_pwrseq_reset(struct mmc_host *host)
+{
+ struct mmc_pwrseq *pwrseq = host->pwrseq;
+
+ if (pwrseq && pwrseq->ops->reset)
+ pwrseq->ops->reset(host);
+}
+
void mmc_pwrseq_free(struct mmc_host *host)
{
struct mmc_pwrseq *pwrseq = host->pwrseq;
diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h
index d69e751f148b..819386f4ec61 100644
--- a/drivers/mmc/core/pwrseq.h
+++ b/drivers/mmc/core/pwrseq.h
@@ -8,12 +8,17 @@
#ifndef _MMC_CORE_PWRSEQ_H
#define _MMC_CORE_PWRSEQ_H
-#include <linux/mmc/host.h>
+#include <linux/types.h>
+
+struct mmc_host;
+struct device;
+struct module;
struct mmc_pwrseq_ops {
void (*pre_power_on)(struct mmc_host *host);
void (*post_power_on)(struct mmc_host *host);
void (*power_off)(struct mmc_host *host);
+ void (*reset)(struct mmc_host *host);
};
struct mmc_pwrseq {
@@ -32,6 +37,7 @@ int mmc_pwrseq_alloc(struct mmc_host *host);
void mmc_pwrseq_pre_power_on(struct mmc_host *host);
void mmc_pwrseq_post_power_on(struct mmc_host *host);
void mmc_pwrseq_power_off(struct mmc_host *host);
+void mmc_pwrseq_reset(struct mmc_host *host);
void mmc_pwrseq_free(struct mmc_host *host);
#else
@@ -45,6 +51,7 @@ static inline int mmc_pwrseq_alloc(struct mmc_host *host) { return 0; }
static inline void mmc_pwrseq_pre_power_on(struct mmc_host *host) {}
static inline void mmc_pwrseq_post_power_on(struct mmc_host *host) {}
static inline void mmc_pwrseq_power_off(struct mmc_host *host) {}
+static inline void mmc_pwrseq_reset(struct mmc_host *host) {}
static inline void mmc_pwrseq_free(struct mmc_host *host) {}
#endif
diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c
index adc9c0c614fb..efb8a7965dd4 100644
--- a/drivers/mmc/core/pwrseq_emmc.c
+++ b/drivers/mmc/core/pwrseq_emmc.c
@@ -56,7 +56,7 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
}
static const struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
- .post_power_on = mmc_pwrseq_emmc_reset,
+ .reset = mmc_pwrseq_emmc_reset,
};
static int mmc_pwrseq_emmc_probe(struct platform_device *pdev)
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
index 8cd9ddf1fab9..a8b9fee4d62a 100644
--- a/drivers/mmc/core/pwrseq_simple.c
+++ b/drivers/mmc/core/pwrseq_simple.c
@@ -27,6 +27,7 @@ struct mmc_pwrseq_simple {
struct mmc_pwrseq pwrseq;
bool clk_enabled;
u32 post_power_on_delay_ms;
+ u32 power_off_delay_us;
struct clk *ext_clk;
struct gpio_descs *reset_gpios;
};
@@ -82,6 +83,10 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
+ if (pwrseq->power_off_delay_us)
+ usleep_range(pwrseq->power_off_delay_us,
+ 2 * pwrseq->power_off_delay_us);
+
if (!IS_ERR(pwrseq->ext_clk) && pwrseq->clk_enabled) {
clk_disable_unprepare(pwrseq->ext_clk);
pwrseq->clk_enabled = false;
@@ -123,6 +128,8 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
device_property_read_u32(dev, "post-power-on-delay-ms",
&pwrseq->post_power_on_delay_ms);
+ device_property_read_u32(dev, "power-off-delay-us",
+ &pwrseq->power_off_delay_us);
pwrseq->pwrseq.dev = dev;
pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c
new file mode 100644
index 000000000000..0c9eace1ff31
--- /dev/null
+++ b/drivers/mmc/core/queue.c
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2003 Russell King, All Rights Reserved.
+ * Copyright 2006-2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/freezer.h>
+#include <linux/kthread.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+
+#include "queue.h"
+#include "block.h"
+#include "core.h"
+#include "card.h"
+
+#define MMC_QUEUE_BOUNCESZ 65536
+
+/*
+ * Prepare a MMC request. This just filters out odd stuff.
+ */
+static int mmc_prep_request(struct request_queue *q, struct request *req)
+{
+ struct mmc_queue *mq = q->queuedata;
+
+ if (mq && (mmc_card_removed(mq->card) || mmc_access_rpmb(mq)))
+ return BLKPREP_KILL;
+
+ req->rq_flags |= RQF_DONTPREP;
+ req_to_mmc_queue_req(req)->retries = 0;
+
+ return BLKPREP_OK;
+}
+
+static void mmc_cqe_request_fn(struct request_queue *q)
+{
+ struct mmc_queue *mq = q->queuedata;
+ struct request *req;
+
+ if (!mq) {
+ while ((req = blk_fetch_request(q)) != NULL) {
+ req->rq_flags |= RQF_QUIET;
+ __blk_end_request_all(req, -EIO);
+ }
+ return;
+ }
+
+ if (mq->asleep && !mq->cqe_busy)
+ wake_up_process(mq->thread);
+}
+
+static inline bool mmc_cqe_dcmd_busy(struct mmc_queue *mq)
+{
+ /* Allow only 1 DCMD at a time */
+ return mq->cqe_in_flight[MMC_ISSUE_DCMD];
+}
+
+void mmc_cqe_kick_queue(struct mmc_queue *mq)
+{
+ if ((mq->cqe_busy & MMC_CQE_DCMD_BUSY) && !mmc_cqe_dcmd_busy(mq))
+ mq->cqe_busy &= ~MMC_CQE_DCMD_BUSY;
+
+ mq->cqe_busy &= ~MMC_CQE_QUEUE_FULL;
+
+ if (mq->asleep && !mq->cqe_busy)
+ __blk_run_queue(mq->queue);
+}
+
+static inline bool mmc_cqe_can_dcmd(struct mmc_host *host)
+{
+ return host->caps2 & MMC_CAP2_CQE_DCMD;
+}
+
+enum mmc_issue_type mmc_cqe_issue_type(struct mmc_host *host,
+ struct request *req)
+{
+ if (req && ((req_op(req) == REQ_OP_DISCARD) || (req_op(req) == REQ_OP_SECURE_ERASE))) {
+ return MMC_ISSUE_SYNC;
+ } else if (req && req_op(req) == REQ_OP_FLUSH) {
+ return mmc_cqe_can_dcmd(host) ? MMC_ISSUE_DCMD : MMC_ISSUE_SYNC;
+ } else {
+ return MMC_ISSUE_ASYNC;
+ }
+}
+
+static void __mmc_cqe_recovery_notifier(struct mmc_queue *mq)
+{
+ if (!mq->cqe_recovery_needed) {
+ mq->cqe_recovery_needed = true;
+ wake_up_process(mq->thread);
+ }
+}
+
+static void mmc_cqe_recovery_notifier(struct mmc_host *host,
+ struct mmc_request *mrq)
+{
+ struct mmc_queue_req *mqrq = container_of(mrq, struct mmc_queue_req,
+ brq.mrq);
+ struct request *req = mqrq->req;
+ struct request_queue *q = req->q;
+ struct mmc_queue *mq = q->queuedata;
+ unsigned long flags;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ __mmc_cqe_recovery_notifier(mq);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
+static int mmc_cqe_thread(void *d)
+{
+ struct mmc_queue *mq = d;
+ struct request_queue *q = mq->queue;
+ struct mmc_card *card = mq->card;
+ struct mmc_host *host = card->host;
+ unsigned long flags;
+ int get_put = 0;
+
+ current->flags |= PF_MEMALLOC;
+
+ down(&mq->thread_sem);
+ spin_lock_irqsave(q->queue_lock, flags);
+ while (1) {
+ struct request *req = NULL;
+ enum mmc_issue_type issue_type;
+ bool retune_ok = false;
+
+ if (mq->cqe_recovery_needed) {
+ spin_unlock_irqrestore(q->queue_lock, flags);
+ mmc_blk_cqe_recovery(mq);
+ spin_lock_irqsave(q->queue_lock, flags);
+ mq->cqe_recovery_needed = false;
+ }
+
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (!kthread_should_stop())
+ req = blk_peek_request(q);
+
+ if (req) {
+ issue_type = mmc_cqe_issue_type(host, req);
+ switch (issue_type) {
+ case MMC_ISSUE_DCMD:
+ if (mmc_cqe_dcmd_busy(mq)) {
+ mq->cqe_busy |= MMC_CQE_DCMD_BUSY;
+ req = NULL;
+ break;
+ }
+ /* Fall through */
+ case MMC_ISSUE_ASYNC:
+ if (blk_queue_start_tag(q, req)) {
+ mq->cqe_busy |= MMC_CQE_QUEUE_FULL;
+ req = NULL;
+ }
+ break;
+ default:
+ /*
+ * Timeouts are handled by mmc core, so set a
+ * large value to avoid races.
+ */
+ req->timeout = 600 * HZ;
+ blk_start_request(req);
+ break;
+ }
+ if (req) {
+ mq->cqe_in_flight[issue_type] += 1;
+ if (mmc_cqe_tot_in_flight(mq) == 1)
+ get_put += 1;
+ if (mmc_cqe_qcnt(mq) == 1)
+ retune_ok = true;
+ }
+ }
+
+ mq->asleep = !req;
+
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ if (req) {
+ enum mmc_issued issued;
+
+ set_current_state(TASK_RUNNING);
+
+ if (get_put) {
+ get_put = 0;
+ mmc_get_card(card);
+ }
+
+ if (host->need_retune && retune_ok &&
+ !host->hold_retune)
+ host->retune_now = true;
+ else
+ host->retune_now = false;
+
+ issued = mmc_blk_cqe_issue_rq(mq, req);
+
+ cond_resched();
+
+ spin_lock_irqsave(q->queue_lock, flags);
+
+ switch (issued) {
+ case MMC_REQ_STARTED:
+ break;
+ case MMC_REQ_BUSY:
+ blk_requeue_request(q, req);
+ goto finished;
+ case MMC_REQ_FAILED_TO_START:
+ __blk_end_request_all(req, -EIO);
+ /* Fall through */
+ case MMC_REQ_FINISHED:
+finished:
+ mq->cqe_in_flight[issue_type] -= 1;
+ if (mmc_cqe_tot_in_flight(mq) == 0)
+ get_put = -1;
+ }
+ } else {
+ if (get_put < 0) {
+ get_put = 0;
+ mmc_put_card(card);
+ }
+ /*
+ * Do not stop with requests in flight in case recovery
+ * is needed.
+ */
+ if (kthread_should_stop() &&
+ !mmc_cqe_tot_in_flight(mq)) {
+ set_current_state(TASK_RUNNING);
+ break;
+ }
+ up(&mq->thread_sem);
+ schedule();
+ down(&mq->thread_sem);
+ spin_lock_irqsave(q->queue_lock, flags);
+ }
+ } /* loop */
+ up(&mq->thread_sem);
+
+ return 0;
+}
+
+static enum blk_eh_timer_return __mmc_cqe_timed_out(struct request *req)
+{
+ struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
+ struct mmc_request *mrq = &mqrq->brq.mrq;
+ struct mmc_queue *mq = req->q->queuedata;
+ struct mmc_host *host = mq->card->host;
+ enum mmc_issue_type issue_type = mmc_cqe_issue_type(host, req);
+ bool recovery_needed = false;
+
+ switch (issue_type) {
+ case MMC_ISSUE_ASYNC:
+ case MMC_ISSUE_DCMD:
+ if (host->cqe_ops->cqe_timeout(host, mrq, &recovery_needed)) {
+ if (recovery_needed)
+ __mmc_cqe_recovery_notifier(mq);
+ return BLK_EH_RESET_TIMER;
+ }
+ /* No timeout */
+ return BLK_EH_HANDLED;
+ default:
+ /* Timeout is handled by mmc core */
+ return BLK_EH_RESET_TIMER;
+ }
+}
+
+static enum blk_eh_timer_return mmc_cqe_timed_out(struct request *req)
+{
+ struct mmc_queue *mq = req->q->queuedata;
+
+ if (mq->cqe_recovery_needed)
+ return BLK_EH_RESET_TIMER;
+
+ return __mmc_cqe_timed_out(req);
+}
+
+static int mmc_queue_thread(void *d)
+{
+ struct mmc_queue *mq = d;
+ struct request_queue *q = mq->queue;
+ struct mmc_context_info *cntx = &mq->card->host->context_info;
+
+ current->flags |= PF_MEMALLOC;
+
+ down(&mq->thread_sem);
+ do {
+ struct request *req;
+
+ spin_lock_irq(q->queue_lock);
+ set_current_state(TASK_INTERRUPTIBLE);
+ req = blk_fetch_request(q);
+ mq->asleep = false;
+ cntx->is_waiting_last_req = false;
+ cntx->is_new_req = false;
+ if (!req) {
+ /*
+ * Dispatch queue is empty so set flags for
+ * mmc_request_fn() to wake us up.
+ */
+ if (mq->qcnt)
+ cntx->is_waiting_last_req = true;
+ else
+ mq->asleep = true;
+ }
+ spin_unlock_irq(q->queue_lock);
+
+ if (req || mq->qcnt) {
+ set_current_state(TASK_RUNNING);
+ mmc_blk_issue_rq(mq, req);
+ cond_resched();
+ } else {
+ if (kthread_should_stop()) {
+ set_current_state(TASK_RUNNING);
+ break;
+ }
+ up(&mq->thread_sem);
+ schedule();
+ down(&mq->thread_sem);
+ }
+ } while (1);
+ up(&mq->thread_sem);
+
+ return 0;
+}
+
+/*
+ * Generic MMC request handler. This is called for any queue on a
+ * particular host. When the host is not busy, we look for a request
+ * on any queue on this host, and attempt to issue it. This may
+ * not be the queue we were asked to process.
+ */
+static void mmc_request_fn(struct request_queue *q)
+{
+ struct mmc_queue *mq = q->queuedata;
+ struct request *req;
+ struct mmc_context_info *cntx;
+
+ if (!mq) {
+ while ((req = blk_fetch_request(q)) != NULL) {
+ req->rq_flags |= RQF_QUIET;
+ __blk_end_request_all(req, -EIO);
+ }
+ return;
+ }
+
+ cntx = &mq->card->host->context_info;
+
+ if (cntx->is_waiting_last_req) {
+ cntx->is_new_req = true;
+ wake_up_interruptible(&cntx->wait);
+ }
+
+ if (mq->asleep)
+ wake_up_process(mq->thread);
+}
+
+static struct scatterlist *mmc_alloc_sg(int sg_len, gfp_t gfp)
+{
+ struct scatterlist *sg;
+
+ sg = kmalloc_array(sg_len, sizeof(*sg), gfp);
+ if (sg)
+ sg_init_table(sg, sg_len);
+
+ return sg;
+}
+
+static void mmc_queue_setup_discard(struct request_queue *q,
+ struct mmc_card *card)
+{
+ unsigned max_discard;
+
+ max_discard = mmc_calc_max_discard(card);
+ if (!max_discard)
+ return;
+
+ queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
+ blk_queue_max_discard_sectors(q, max_discard);
+ if (card->erased_byte == 0 && !mmc_can_discard(card))
+ q->limits.discard_zeroes_data = 1;
+ q->limits.discard_granularity = card->pref_erase << 9;
+ /* granularity must not be greater than max. discard */
+ if (card->pref_erase > max_discard)
+ q->limits.discard_granularity = 0;
+ if (mmc_can_secure_erase_trim(card))
+ queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, q);
+}
+
+static unsigned int mmc_queue_calc_bouncesz(struct mmc_host *host)
+{
+ unsigned int bouncesz = MMC_QUEUE_BOUNCESZ;
+
+ if (host->max_segs != 1 || (host->caps & MMC_CAP_NO_BOUNCE_BUFF))
+ return 0;
+
+ if (bouncesz > host->max_req_size)
+ bouncesz = host->max_req_size;
+ if (bouncesz > host->max_seg_size)
+ bouncesz = host->max_seg_size;
+ if (bouncesz > host->max_blk_count * 512)
+ bouncesz = host->max_blk_count * 512;
+
+ if (bouncesz <= 512)
+ return 0;
+
+ return bouncesz;
+}
+
+/**
+ * mmc_init_request() - initialize the MMC-specific per-request data
+ * @q: the request queue
+ * @req: the request
+ * @gfp: memory allocation policy
+ */
+static int mmc_init_request(struct request_queue *q, struct request *req,
+ gfp_t gfp)
+{
+ struct mmc_queue_req *mq_rq = req_to_mmc_queue_req(req);
+ struct mmc_queue *mq = q->queuedata;
+ struct mmc_card *card = mq->card;
+ struct mmc_host *host = card->host;
+
+ mq_rq->req = req;
+
+ if (card->bouncesz) {
+ mq_rq->bounce_buf = kmalloc(card->bouncesz, gfp);
+ if (!mq_rq->bounce_buf)
+ return -ENOMEM;
+ if (card->bouncesz > 512) {
+ mq_rq->sg = mmc_alloc_sg(1, gfp);
+ if (!mq_rq->sg)
+ return -ENOMEM;
+ mq_rq->bounce_sg = mmc_alloc_sg(card->bouncesz / 512,
+ gfp);
+ if (!mq_rq->bounce_sg)
+ return -ENOMEM;
+ }
+ } else {
+ mq_rq->bounce_buf = NULL;
+ mq_rq->bounce_sg = NULL;
+ mq_rq->sg = mmc_alloc_sg(host->max_segs, gfp);
+ if (!mq_rq->sg)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void mmc_exit_request(struct request_queue *q, struct request *req)
+{
+ struct mmc_queue_req *mq_rq = req_to_mmc_queue_req(req);
+
+ /* It is OK to kfree(NULL) so this will be smooth */
+ kfree(mq_rq->bounce_sg);
+ mq_rq->bounce_sg = NULL;
+
+ kfree(mq_rq->bounce_buf);
+ mq_rq->bounce_buf = NULL;
+
+ kfree(mq_rq->sg);
+ mq_rq->sg = NULL;
+
+ mq_rq->req = NULL;
+}
+
+/**
+ * mmc_init_queue - initialise a queue structure.
+ * @mq: mmc queue
+ * @card: mmc card to attach this queue
+ * @lock: queue lock
+ * @subname: partition subname
+ *
+ * Initialise a MMC card request queue.
+ */
+int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
+ spinlock_t *lock, const char *subname, int area_type)
+{
+ struct mmc_host *host = card->host;
+ u64 limit = BLK_BOUNCE_HIGH;
+ int ret = -ENOMEM;
+ bool use_cqe = host->cqe_enabled && area_type != MMC_BLK_DATA_AREA_RPMB;
+
+ if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
+ limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
+
+ /*
+ * mmc_init_request() depends on card->bouncesz so it must be calculated
+ * before blk_init_allocated_queue() starts allocating requests.
+ */
+ card->bouncesz = mmc_queue_calc_bouncesz(host);
+
+ mq->card = card;
+ mq->queue = blk_alloc_queue(GFP_KERNEL);
+ if (!mq->queue)
+ return -ENOMEM;
+ mq->queue->queue_lock = lock;
+ mq->queue->request_fn = use_cqe ? mmc_cqe_request_fn : mmc_request_fn;
+ mq->queue->init_rq_fn = mmc_init_request;
+ mq->queue->exit_rq_fn = mmc_exit_request;
+ mq->queue->cmd_size = sizeof(struct mmc_queue_req);
+ mq->queue->queuedata = mq;
+ mq->qcnt = 0;
+ ret = blk_init_allocated_queue(mq->queue);
+ if (ret) {
+ blk_cleanup_queue(mq->queue);
+ return ret;
+ }
+
+ if (use_cqe) {
+ int q_depth = card->ext_csd.cmdq_depth;
+
+ if (q_depth > host->cqe_qdepth)
+ q_depth = host->cqe_qdepth;
+
+ ret = blk_queue_init_tags(mq->queue, q_depth, NULL,
+ BLK_TAG_ALLOC_FIFO);
+ if (ret)
+ goto cleanup_queue;
+
+ blk_queue_softirq_done(mq->queue, mmc_blk_cqe_complete_rq);
+ blk_queue_rq_timed_out(mq->queue, mmc_cqe_timed_out);
+ blk_queue_rq_timeout(mq->queue, 60 * HZ);
+
+ host->cqe_recovery_notifier = mmc_cqe_recovery_notifier;
+ }
+
+ blk_queue_prep_rq(mq->queue, mmc_prep_request);
+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
+ queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, mq->queue);
+ if (mmc_can_erase(card))
+ mmc_queue_setup_discard(mq->queue, card);
+
+ if (card->bouncesz) {
+ blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
+ blk_queue_max_hw_sectors(mq->queue, card->bouncesz / 512);
+ blk_queue_max_segments(mq->queue, card->bouncesz / 512);
+ blk_queue_max_segment_size(mq->queue, card->bouncesz);
+ } else {
+ blk_queue_bounce_limit(mq->queue, limit);
+ blk_queue_max_hw_sectors(mq->queue,
+ min(host->max_blk_count, host->max_req_size / 512));
+ blk_queue_max_segments(mq->queue, host->max_segs);
+ blk_queue_max_segment_size(mq->queue, host->max_seg_size);
+ }
+
+ sema_init(&mq->thread_sem, 1);
+
+ mq->thread = kthread_run(use_cqe ? mmc_cqe_thread : mmc_queue_thread,
+ mq, "mmcqd/%d%s", host->index,
+ subname ? subname : "");
+ if (IS_ERR(mq->thread)) {
+ ret = PTR_ERR(mq->thread);
+ goto cleanup_queue;
+ }
+
+ return 0;
+
+cleanup_queue:
+ blk_cleanup_queue(mq->queue);
+ return ret;
+}
+
+void mmc_cleanup_queue(struct mmc_queue *mq)
+{
+ struct request_queue *q = mq->queue;
+ unsigned long flags;
+
+ /* Make sure the queue isn't suspended, as that will deadlock */
+ mmc_queue_resume(mq);
+
+ /* Then terminate our worker thread */
+ kthread_stop(mq->thread);
+
+ /* Empty the queue */
+ spin_lock_irqsave(q->queue_lock, flags);
+ q->queuedata = NULL;
+ blk_start_queue(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ mq->card = NULL;
+}
+EXPORT_SYMBOL(mmc_cleanup_queue);
+
+/**
+ * mmc_queue_suspend - suspend a MMC request queue
+ * @mq: MMC queue to suspend
+ *
+ * Stop the block request queue, and wait for our thread to
+ * complete any outstanding requests. This ensures that we
+ * won't suspend while a request is being processed.
+ */
+void mmc_queue_suspend(struct mmc_queue *mq)
+{
+ struct request_queue *q = mq->queue;
+ unsigned long flags;
+
+ if (!mq->suspended) {
+ mq->suspended |= true;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ blk_stop_queue(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ down(&mq->thread_sem);
+ }
+}
+
+/**
+ * mmc_queue_resume - resume a previously suspended MMC request queue
+ * @mq: MMC queue to resume
+ */
+void mmc_queue_resume(struct mmc_queue *mq)
+{
+ struct request_queue *q = mq->queue;
+ unsigned long flags;
+
+ if (mq->suspended) {
+ mq->suspended = false;
+
+ up(&mq->thread_sem);
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ blk_start_queue(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+ }
+}
+
+/*
+ * Prepare the sg list(s) to be handed of to the host driver
+ */
+unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
+{
+ unsigned int sg_len;
+ size_t buflen;
+ struct scatterlist *sg;
+ int i;
+
+ if (!mqrq->bounce_buf)
+ return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
+
+ sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
+
+ mqrq->bounce_sg_len = sg_len;
+
+ buflen = 0;
+ for_each_sg(mqrq->bounce_sg, sg, sg_len, i)
+ buflen += sg->length;
+
+ sg_init_one(mqrq->sg, mqrq->bounce_buf, buflen);
+
+ return 1;
+}
+
+/*
+ * If writing, bounce the data to the buffer before the request
+ * is sent to the host driver
+ */
+void mmc_queue_bounce_pre(struct mmc_queue_req *mqrq)
+{
+ if (!mqrq->bounce_buf)
+ return;
+
+ if (rq_data_dir(mqrq->req) != WRITE)
+ return;
+
+ sg_copy_to_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
+ mqrq->bounce_buf, mqrq->sg[0].length);
+}
+
+/*
+ * If reading, bounce the data from the buffer after the request
+ * has been handled by the host driver
+ */
+void mmc_queue_bounce_post(struct mmc_queue_req *mqrq)
+{
+ if (!mqrq->bounce_buf)
+ return;
+
+ if (rq_data_dir(mqrq->req) != READ)
+ return;
+
+ sg_copy_from_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
+ mqrq->bounce_buf, mqrq->sg[0].length);
+}
diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h
new file mode 100644
index 000000000000..45c4e0ab3b5e
--- /dev/null
+++ b/drivers/mmc/core/queue.h
@@ -0,0 +1,115 @@
+#ifndef MMC_QUEUE_H
+#define MMC_QUEUE_H
+
+#include <linux/types.h>
+#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
+#include <linux/mmc/core.h>
+#include <linux/mmc/host.h>
+
+enum mmc_issued {
+ MMC_REQ_STARTED,
+ MMC_REQ_BUSY,
+ MMC_REQ_FAILED_TO_START,
+ MMC_REQ_FINISHED,
+};
+
+enum mmc_issue_type {
+ MMC_ISSUE_SYNC,
+ MMC_ISSUE_DCMD,
+ MMC_ISSUE_ASYNC,
+ MMC_ISSUE_MAX,
+};
+
+static inline struct mmc_queue_req *req_to_mmc_queue_req(struct request *rq)
+{
+ return blk_mq_rq_to_pdu(rq);
+}
+
+static inline bool mmc_req_is_special(struct request *req)
+{
+ return req &&
+ (req_op(req) == REQ_OP_FLUSH ||
+ req_op(req) == REQ_OP_DISCARD ||
+ req_op(req) == REQ_OP_SECURE_ERASE);
+}
+
+struct task_struct;
+struct mmc_blk_data;
+
+struct mmc_blk_request {
+ struct mmc_request mrq;
+ struct mmc_command sbc;
+ struct mmc_command cmd;
+ struct mmc_command stop;
+ struct mmc_data data;
+ int retune_retry_done;
+};
+
+struct mmc_queue_req {
+ struct request *req;
+ struct mmc_blk_request brq;
+ struct scatterlist *sg;
+ char *bounce_buf;
+ struct scatterlist *bounce_sg;
+ unsigned int bounce_sg_len;
+ struct mmc_async_req areq;
+ int retries;
+};
+
+struct mmc_queue {
+ struct mmc_card *card;
+ struct task_struct *thread;
+ struct semaphore thread_sem;
+ bool suspended;
+ bool asleep;
+ struct mmc_blk_data *blkdata;
+ struct request_queue *queue;
+ /*
+ * FIXME: this counter is not a very reliable way of keeping
+ * track of how many requests that are ongoing. Switch to just
+ * letting the block core keep track of requests and per-request
+ * associated mmc_queue_req data.
+ */
+ int qcnt;
+ /* Following are defined for a Command Queue Engine */
+ int cqe_in_flight[MMC_ISSUE_MAX];
+ unsigned int cqe_busy;
+ bool cqe_recovery_needed;
+ bool cqe_in_recovery;
+#define MMC_CQE_DCMD_BUSY BIT(0)
+#define MMC_CQE_QUEUE_FULL BIT(1)
+};
+
+extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
+ const char *, int);
+extern void mmc_cleanup_queue(struct mmc_queue *);
+extern void mmc_queue_suspend(struct mmc_queue *);
+extern void mmc_queue_resume(struct mmc_queue *);
+
+extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
+ struct mmc_queue_req *);
+extern void mmc_queue_bounce_pre(struct mmc_queue_req *);
+extern void mmc_queue_bounce_post(struct mmc_queue_req *);
+
+extern int mmc_access_rpmb(struct mmc_queue *);
+
+void mmc_cqe_kick_queue(struct mmc_queue *mq);
+
+enum mmc_issue_type mmc_cqe_issue_type(struct mmc_host *host,
+ struct request *req);
+
+static inline int mmc_cqe_tot_in_flight(struct mmc_queue *mq)
+{
+ return mq->cqe_in_flight[MMC_ISSUE_SYNC] +
+ mq->cqe_in_flight[MMC_ISSUE_DCMD] +
+ mq->cqe_in_flight[MMC_ISSUE_ASYNC];
+}
+
+static inline int mmc_cqe_qcnt(struct mmc_queue *mq)
+{
+ return mq->cqe_in_flight[MMC_ISSUE_DCMD] +
+ mq->cqe_in_flight[MMC_ISSUE_ASYNC];
+}
+
+#endif
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
deleted file mode 100644
index ca9cade317c7..000000000000
--- a/drivers/mmc/core/quirks.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * This file contains work-arounds for many known SD/MMC
- * and SDIO hardware bugs.
- *
- * Copyright (c) 2011 Andrei Warkentin <andreiw@motorola.com>
- * Copyright (c) 2011 Pierre Tardy <tardyp@gmail.com>
- * Inspired from pci fixup code:
- * Copyright (c) 1999 Martin Mares <mj@ucw.cz>
- *
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio_ids.h>
-
-#ifndef SDIO_VENDOR_ID_TI
-#define SDIO_VENDOR_ID_TI 0x0097
-#endif
-
-#ifndef SDIO_DEVICE_ID_TI_WL1271
-#define SDIO_DEVICE_ID_TI_WL1271 0x4076
-#endif
-
-#ifndef SDIO_VENDOR_ID_STE
-#define SDIO_VENDOR_ID_STE 0x0020
-#endif
-
-#ifndef SDIO_DEVICE_ID_STE_CW1200
-#define SDIO_DEVICE_ID_STE_CW1200 0x2280
-#endif
-
-#ifndef SDIO_DEVICE_ID_MARVELL_8797_F0
-#define SDIO_DEVICE_ID_MARVELL_8797_F0 0x9128
-#endif
-
-static const struct mmc_fixup mmc_fixup_methods[] = {
- SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
- add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
-
- SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
- add_quirk, MMC_QUIRK_DISABLE_CD),
-
- SDIO_FIXUP(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200,
- add_quirk, MMC_QUIRK_BROKEN_BYTE_MODE_512),
-
- SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_F0,
- add_quirk, MMC_QUIRK_BROKEN_IRQ_POLLING),
-
- END_FIXUP
-};
-
-void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
-{
- const struct mmc_fixup *f;
- u64 rev = cid_rev_card(card);
-
- /* Non-core specific workarounds. */
- if (!table)
- table = mmc_fixup_methods;
-
- for (f = table; f->vendor_fixup; f++) {
- if ((f->manfid == CID_MANFID_ANY ||
- f->manfid == card->cid.manfid) &&
- (f->oemid == CID_OEMID_ANY ||
- f->oemid == card->cid.oemid) &&
- (f->name == CID_NAME_ANY ||
- !strncmp(f->name, card->cid.prod_name,
- sizeof(card->cid.prod_name))) &&
- (f->cis_vendor == card->cis.vendor ||
- f->cis_vendor == (u16) SDIO_ANY_ID) &&
- (f->cis_device == card->cis.device ||
- f->cis_device == (u16) SDIO_ANY_ID) &&
- (f->ext_csd_rev == EXT_CSD_REV_ANY ||
- f->ext_csd_rev == card->ext_csd.rev) &&
- rev >= f->rev_start && rev <= f->rev_end) {
- dev_dbg(&card->dev, "calling %pf\n", f->vendor_fixup);
- f->vendor_fixup(card, f->data);
- }
- }
-}
-EXPORT_SYMBOL(mmc_fixup_device);
diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h
new file mode 100644
index 000000000000..fb725934fa21
--- /dev/null
+++ b/drivers/mmc/core/quirks.h
@@ -0,0 +1,148 @@
+/*
+ * This file contains work-arounds for many known SD/MMC
+ * and SDIO hardware bugs.
+ *
+ * Copyright (c) 2011 Andrei Warkentin <andreiw@motorola.com>
+ * Copyright (c) 2011 Pierre Tardy <tardyp@gmail.com>
+ * Inspired from pci fixup code:
+ * Copyright (c) 1999 Martin Mares <mj@ucw.cz>
+ *
+ */
+
+#include <linux/mmc/sdio_ids.h>
+
+#include "card.h"
+
+static const struct mmc_fixup mmc_blk_fixups[] = {
+#define INAND_CMD38_ARG_EXT_CSD 113
+#define INAND_CMD38_ARG_ERASE 0x00
+#define INAND_CMD38_ARG_TRIM 0x01
+#define INAND_CMD38_ARG_SECERASE 0x80
+#define INAND_CMD38_ARG_SECTRIM1 0x81
+#define INAND_CMD38_ARG_SECTRIM2 0x88
+ /* CMD38 argument is passed through EXT_CSD[113] */
+ MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk,
+ MMC_QUIRK_INAND_CMD38),
+ MMC_FIXUP("SEM04G", CID_MANFID_SANDISK, 0x100, add_quirk,
+ MMC_QUIRK_INAND_CMD38),
+ MMC_FIXUP("SEM08G", CID_MANFID_SANDISK, 0x100, add_quirk,
+ MMC_QUIRK_INAND_CMD38),
+ MMC_FIXUP("SEM16G", CID_MANFID_SANDISK, 0x100, add_quirk,
+ MMC_QUIRK_INAND_CMD38),
+ MMC_FIXUP("SEM32G", CID_MANFID_SANDISK, 0x100, add_quirk,
+ MMC_QUIRK_INAND_CMD38),
+
+ /*
+ * Some MMC cards experience performance degradation with CMD23
+ * instead of CMD12-bounded multiblock transfers. For now we'll
+ * black list what's bad...
+ * - Certain Toshiba cards.
+ *
+ * N.B. This doesn't affect SD cards.
+ */
+ MMC_FIXUP("SDMB-32", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_BLK_NO_CMD23),
+ MMC_FIXUP("SDM032", CID_MANFID_SANDISK, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_BLK_NO_CMD23),
+ MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_BLK_NO_CMD23),
+ MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_BLK_NO_CMD23),
+ MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_BLK_NO_CMD23),
+
+ /*
+ * Some MMC cards need longer data read timeout than indicated in CSD.
+ */
+ MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc,
+ MMC_QUIRK_LONG_READ_TIME),
+ MMC_FIXUP("008GE0", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_LONG_READ_TIME),
+
+ /*
+ * On these Samsung MoviNAND parts, performing secure erase or
+ * secure trim can result in unrecoverable corruption due to a
+ * firmware bug.
+ */
+ MMC_FIXUP("M8G2FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+ MMC_FIXUP("MAG4FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+ MMC_FIXUP("MBG8FA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+ MMC_FIXUP("MCGAFA", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+ MMC_FIXUP("VAL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+ MMC_FIXUP("VYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+ MMC_FIXUP("KYL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+ MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_SEC_ERASE_TRIM_BROKEN),
+
+ /*
+ * On Some Kingston eMMCs, performing trim can result in
+ * unrecoverable data conrruption occasionally due to a firmware bug.
+ */
+ MMC_FIXUP("V10008", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_TRIM_BROKEN),
+ MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_TRIM_BROKEN),
+
+ END_FIXUP
+};
+
+static const struct mmc_fixup mmc_ext_csd_fixups[] = {
+ /*
+ * Certain Hynix eMMC 4.41 cards might get broken when HPI feature
+ * is used so disable the HPI feature for such buggy cards.
+ */
+ MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX,
+ 0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5),
+
+ END_FIXUP
+};
+
+static const struct mmc_fixup sdio_fixup_methods[] = {
+ SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
+ add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
+
+ SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
+ add_quirk, MMC_QUIRK_DISABLE_CD),
+
+ SDIO_FIXUP(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200,
+ add_quirk, MMC_QUIRK_BROKEN_BYTE_MODE_512),
+
+ SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_F0,
+ add_quirk, MMC_QUIRK_BROKEN_IRQ_POLLING),
+
+ END_FIXUP
+};
+
+static inline void mmc_fixup_device(struct mmc_card *card,
+ const struct mmc_fixup *table)
+{
+ const struct mmc_fixup *f;
+ u64 rev = cid_rev_card(card);
+
+ for (f = table; f->vendor_fixup; f++) {
+ if ((f->manfid == CID_MANFID_ANY ||
+ f->manfid == card->cid.manfid) &&
+ (f->oemid == CID_OEMID_ANY ||
+ f->oemid == card->cid.oemid) &&
+ (f->name == CID_NAME_ANY ||
+ !strncmp(f->name, card->cid.prod_name,
+ sizeof(card->cid.prod_name))) &&
+ (f->cis_vendor == card->cis.vendor ||
+ f->cis_vendor == (u16) SDIO_ANY_ID) &&
+ (f->cis_device == card->cis.device ||
+ f->cis_device == (u16) SDIO_ANY_ID) &&
+ (f->ext_csd_rev == EXT_CSD_REV_ANY ||
+ f->ext_csd_rev == card->ext_csd.rev) &&
+ rev >= f->rev_start && rev <= f->rev_end) {
+ dev_dbg(&card->dev, "calling %pf\n", f->vendor_fixup);
+ f->vendor_fixup(card, f->data);
+ }
+ }
+}
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index f09148a4ab55..009e1cf3435c 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -22,6 +22,8 @@
#include <linux/mmc/sd.h>
#include "core.h"
+#include "card.h"
+#include "host.h"
#include "bus.h"
#include "mmc_ops.h"
#include "sd.h"
@@ -223,7 +225,7 @@ static int mmc_decode_scr(struct mmc_card *card)
static int mmc_read_ssr(struct mmc_card *card)
{
unsigned int au, es, et, eo;
- u32 *raw_ssr;
+ __be32 *raw_ssr;
int i;
if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
@@ -485,6 +487,13 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
else {
mmc_set_timing(card->host, timing);
mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
+
+ /*
+ * FIXME: Sandisk SD3.0 cards DDR50 mode requires such
+ * delay to get stable, without this delay we may encounter
+ * CRC errors after switch to DDR50 mode
+ */
+ mmc_delay(100);
}
return 0;
@@ -786,8 +795,7 @@ try_again:
*/
if (!mmc_host_is_spi(host) && rocr &&
((*rocr & 0x41000000) == 0x41000000)) {
- err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
- pocr);
+ err = mmc_set_uhs_voltage(host, pocr);
if (err == -EAGAIN) {
retries--;
goto try_again;
@@ -852,7 +860,7 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
/*
* Fetch SCR from card.
*/
- err = mmc_app_send_scr(card, card->raw_scr);
+ err = mmc_app_send_scr(card);
if (err)
return err;
@@ -935,7 +943,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
u32 cid[4];
u32 rocr = 0;
- BUG_ON(!host);
WARN_ON(!host->claimed);
err = mmc_sd_get_cid(host, ocr, cid, &rocr);
@@ -1051,9 +1058,6 @@ free_card:
*/
static void mmc_sd_remove(struct mmc_host *host)
{
- BUG_ON(!host);
- BUG_ON(!host->card);
-
mmc_remove_card(host->card);
host->card = NULL;
}
@@ -1073,9 +1077,6 @@ static void mmc_sd_detect(struct mmc_host *host)
{
int err;
- BUG_ON(!host);
- BUG_ON(!host->card);
-
mmc_get_card(host->card);
/*
@@ -1099,9 +1100,6 @@ static int _mmc_sd_suspend(struct mmc_host *host)
{
int err = 0;
- BUG_ON(!host);
- BUG_ON(!host->card);
-
mmc_claim_host(host);
if (mmc_card_suspended(host->card))
@@ -1144,9 +1142,6 @@ static int _mmc_sd_resume(struct mmc_host *host)
{
int err = 0;
- BUG_ON(!host);
- BUG_ON(!host->card);
-
mmc_claim_host(host);
if (!mmc_card_suspended(host->card))
@@ -1229,7 +1224,6 @@ int mmc_attach_sd(struct mmc_host *host)
int err;
u32 ocr, rocr;
- BUG_ON(!host);
WARN_ON(!host->claimed);
err = mmc_send_app_op_cond(host, 0, &ocr);
diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
index aab824a9a7f3..1ada9808c329 100644
--- a/drivers/mmc/core/sd.h
+++ b/drivers/mmc/core/sd.h
@@ -1,10 +1,13 @@
#ifndef _MMC_CORE_SD_H
#define _MMC_CORE_SD_H
-#include <linux/mmc/card.h>
+#include <linux/types.h>
extern struct device_type sd_type;
+struct mmc_host;
+struct mmc_card;
+
int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr);
int mmc_sd_get_csd(struct mmc_host *host, struct mmc_card *card);
void mmc_decode_cid(struct mmc_card *card);
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 16b774c18e75..47056d8d1bac 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -25,10 +25,10 @@
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
{
int err;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
- BUG_ON(!host);
- BUG_ON(card && (card->host != host));
+ if (WARN_ON(card && card->host != host))
+ return -EINVAL;
cmd.opcode = MMC_APP_CMD;
@@ -68,12 +68,12 @@ EXPORT_SYMBOL_GPL(mmc_app_cmd);
int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
struct mmc_command *cmd, int retries)
{
- struct mmc_request mrq = {NULL};
+ struct mmc_request mrq = {};
int i, err;
- BUG_ON(!cmd);
- BUG_ON(retries < 0);
+ if (retries < 0)
+ retries = MMC_CMD_RETRIES;
err = -EIO;
@@ -120,10 +120,7 @@ EXPORT_SYMBOL(mmc_wait_for_app_cmd);
int mmc_app_set_bus_width(struct mmc_card *card, int width)
{
- struct mmc_command cmd = {0};
-
- BUG_ON(!card);
- BUG_ON(!card->host);
+ struct mmc_command cmd = {};
cmd.opcode = SD_APP_SET_BUS_WIDTH;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
@@ -144,11 +141,9 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width)
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int i, err = 0;
- BUG_ON(!host);
-
cmd.opcode = SD_APP_OP_COND;
if (mmc_host_is_spi(host))
cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */
@@ -190,7 +185,7 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int err;
static const u8 test_pattern = 0xAA;
u8 result_pattern;
@@ -222,10 +217,7 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
{
int err;
- struct mmc_command cmd = {0};
-
- BUG_ON(!host);
- BUG_ON(!rca);
+ struct mmc_command cmd = {};
cmd.opcode = SD_SEND_RELATIVE_ADDR;
cmd.arg = 0;
@@ -240,18 +232,14 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
return 0;
}
-int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
+int mmc_app_send_scr(struct mmc_card *card)
{
int err;
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
struct scatterlist sg;
- void *data_buf;
-
- BUG_ON(!card);
- BUG_ON(!card->host);
- BUG_ON(!scr);
+ __be32 *scr;
/* NOTE: caller guarantees scr is heap-allocated */
@@ -262,8 +250,8 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
/* dma onto stack is unsafe/nonportable, but callers to this
* routine normally provide temporary on-stack buffers ...
*/
- data_buf = kmalloc(sizeof(card->raw_scr), GFP_KERNEL);
- if (data_buf == NULL)
+ scr = kmalloc(sizeof(card->raw_scr), GFP_KERNEL);
+ if (!scr)
return -ENOMEM;
mrq.cmd = &cmd;
@@ -279,37 +267,33 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
data.sg = &sg;
data.sg_len = 1;
- sg_init_one(&sg, data_buf, 8);
+ sg_init_one(&sg, scr, 8);
mmc_set_data_timeout(&data, card);
mmc_wait_for_req(card->host, &mrq);
- memcpy(scr, data_buf, sizeof(card->raw_scr));
- kfree(data_buf);
+ card->raw_scr[0] = be32_to_cpu(scr[0]);
+ card->raw_scr[1] = be32_to_cpu(scr[1]);
+
+ kfree(scr);
if (cmd.error)
return cmd.error;
if (data.error)
return data.error;
- scr[0] = be32_to_cpu(scr[0]);
- scr[1] = be32_to_cpu(scr[1]);
-
return 0;
}
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
u8 value, u8 *resp)
{
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
struct scatterlist sg;
- BUG_ON(!card);
- BUG_ON(!card->host);
-
/* NOTE: caller guarantees resp is heap-allocated */
mode = !!mode;
@@ -347,15 +331,11 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
int mmc_app_sd_status(struct mmc_card *card, void *ssr)
{
int err;
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
struct scatterlist sg;
- BUG_ON(!card);
- BUG_ON(!card->host);
- BUG_ON(!ssr);
-
/* NOTE: caller guarantees ssr is heap-allocated */
err = mmc_app_cmd(card->host, card);
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
index ffc2305d905f..0e6c3d51e66d 100644
--- a/drivers/mmc/core/sd_ops.h
+++ b/drivers/mmc/core/sd_ops.h
@@ -12,14 +12,23 @@
#ifndef _MMC_SD_OPS_H
#define _MMC_SD_OPS_H
+#include <linux/types.h>
+
+struct mmc_card;
+struct mmc_host;
+struct mmc_command;
+
int mmc_app_set_bus_width(struct mmc_card *card, int width);
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca);
-int mmc_app_send_scr(struct mmc_card *card, u32 *scr);
+int mmc_app_send_scr(struct mmc_card *card);
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
u8 value, u8 *resp);
int mmc_app_sd_status(struct mmc_card *card, void *ssr);
+int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
+int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
+ struct mmc_command *cmd, int retries);
#endif
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index bd44ba8116d1..f106dd06ab7a 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -20,7 +20,10 @@
#include <linux/mmc/sdio_ids.h>
#include "core.h"
+#include "card.h"
+#include "host.h"
#include "bus.h"
+#include "quirks.h"
#include "sd.h"
#include "sdio_bus.h"
#include "mmc_ops.h"
@@ -63,7 +66,8 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn)
int ret;
struct sdio_func *func;
- BUG_ON(fn > SDIO_MAX_FUNCS);
+ if (WARN_ON(fn > SDIO_MAX_FUNCS))
+ return -EINVAL;
func = sdio_alloc_func(card);
if (IS_ERR(func))
@@ -540,6 +544,15 @@ out:
return err;
}
+static void mmc_sdio_resend_if_cond(struct mmc_host *host,
+ struct mmc_card *card)
+{
+ sdio_reset(host);
+ mmc_go_idle(host);
+ mmc_send_if_cond(host, host->ocr_avail);
+ mmc_remove_card(card);
+}
+
/*
* Handle the detection and initialisation of a card.
*
@@ -555,7 +568,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
u32 rocr = 0;
u32 ocr_card = ocr;
- BUG_ON(!host);
WARN_ON(!host->claimed);
/* to query card if 1.8V signalling is supported */
@@ -624,24 +636,21 @@ try_again:
* to switch to 1.8V signaling level. No 1.8v signalling if
* UHS mode is not enabled to maintain compatibility and some
* systems that claim 1.8v signalling in fact do not support
- * it.
+ * it. Per SDIO spec v3, section 3.1.2, if the voltage is already
+ * 1.8v, the card sets S18A to 0 in the R4 response. So it will
+ * fails to check rocr & R4_18V_PRESENT, but we still need to
+ * try to init uhs card. sdio_read_cccr will take over this task
+ * to make sure which speed mode should work.
*/
if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) {
- err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
- ocr_card);
+ err = mmc_set_uhs_voltage(host, ocr_card);
if (err == -EAGAIN) {
- sdio_reset(host);
- mmc_go_idle(host);
- mmc_send_if_cond(host, host->ocr_avail);
- mmc_remove_card(card);
+ mmc_sdio_resend_if_cond(host, card);
retries--;
goto try_again;
} else if (err) {
ocr &= ~R4_18V_PRESENT;
}
- err = 0;
- } else {
- ocr &= ~R4_18V_PRESENT;
}
/*
@@ -698,11 +707,20 @@ try_again:
}
/*
- * Read the common registers.
+ * Read the common registers. Note that we should try to
+ * validate whether UHS would work or not.
*/
err = sdio_read_cccr(card, ocr);
- if (err)
- goto remove;
+ if (err) {
+ mmc_sdio_resend_if_cond(host, card);
+ if (ocr & R4_18V_PRESENT) {
+ /* Retry init sequence, but without R4_18V_PRESENT. */
+ retries = 0;
+ goto try_again;
+ } else {
+ goto remove;
+ }
+ }
/*
* Read the common CIS tuples.
@@ -721,7 +739,7 @@ try_again:
card = oldcard;
}
card->ocr = ocr_card;
- mmc_fixup_device(card, NULL);
+ mmc_fixup_device(card, sdio_fixup_methods);
if (card->type == MMC_TYPE_SD_COMBO) {
err = mmc_sd_setup_card(host, card, oldcard != NULL);
@@ -784,6 +802,37 @@ err:
return err;
}
+int sdio_reset_comm(struct mmc_card *card)
+{
+ struct mmc_host *host = card->host;
+ u32 ocr;
+ u32 rocr;
+ int err;
+
+ 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;
+ rocr = mmc_select_voltage(host, ocr);
+ if (!rocr) {
+ err = -EINVAL;
+ goto err;
+ }
+ err = mmc_sdio_init_card(host, rocr, card, 0);
+ if (err)
+ goto err;
+ mmc_release_host(host);
+ return 0;
+err:
+ pr_err("%s: Error resetting SDIO communications (%d)\n",
+ mmc_hostname(host), err);
+ mmc_release_host(host);
+ return err;
+}
+EXPORT_SYMBOL(sdio_reset_comm);
+
/*
* Host is being removed. Free up the current card.
*/
@@ -791,9 +840,6 @@ static void mmc_sdio_remove(struct mmc_host *host)
{
int i;
- BUG_ON(!host);
- BUG_ON(!host->card);
-
for (i = 0;i < host->card->sdio_funcs;i++) {
if (host->card->sdio_func[i]) {
sdio_remove_func(host->card->sdio_func[i]);
@@ -802,9 +848,22 @@ static void mmc_sdio_remove(struct mmc_host *host)
}
mmc_remove_card(host->card);
+ /* clear rescan_entered in case force remove */
+ host->rescan_entered = 0;
host->card = NULL;
}
+void mmc_sdio_force_remove(struct mmc_host *host)
+{
+ mmc_sdio_remove(host);
+
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_power_off(host);
+ mmc_release_host(host);
+}
+EXPORT_SYMBOL_GPL(mmc_sdio_force_remove);
+
/*
* Card detection - card is alive.
*/
@@ -820,9 +879,6 @@ static void mmc_sdio_detect(struct mmc_host *host)
{
int err;
- BUG_ON(!host);
- BUG_ON(!host->card);
-
/* Make sure card is powered before detecting it */
if (host->caps & MMC_CAP_POWER_OFF_CARD) {
err = pm_runtime_get_sync(&host->card->dev);
@@ -916,9 +972,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
{
int err = 0;
- BUG_ON(!host);
- BUG_ON(!host->card);
-
/* Basic card reinitialization. */
mmc_claim_host(host);
@@ -970,9 +1023,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
{
int ret;
- BUG_ON(!host);
- BUG_ON(!host->card);
-
mmc_claim_host(host);
/*
@@ -1063,7 +1113,6 @@ int mmc_attach_sdio(struct mmc_host *host)
u32 ocr, rocr;
struct mmc_card *card;
- BUG_ON(!host);
WARN_ON(!host->claimed);
err = mmc_send_io_op_cond(host, 0, &ocr);
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index d56a3b6c2fb9..2b32b88949ba 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -25,6 +25,7 @@
#include <linux/of.h>
#include "core.h"
+#include "card.h"
#include "sdio_cis.h"
#include "sdio_bus.h"
diff --git a/drivers/mmc/core/sdio_bus.h b/drivers/mmc/core/sdio_bus.h
index 567a76821ba7..b69a2540a076 100644
--- a/drivers/mmc/core/sdio_bus.h
+++ b/drivers/mmc/core/sdio_bus.h
@@ -11,6 +11,9 @@
#ifndef _MMC_CORE_SDIO_BUS_H
#define _MMC_CORE_SDIO_BUS_H
+struct mmc_card;
+struct sdio_func;
+
struct sdio_func *sdio_alloc_func(struct mmc_card *card);
int sdio_add_func(struct sdio_func *func);
void sdio_remove_func(struct sdio_func *func);
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
index dcb3dee59fa5..f8c372839d24 100644
--- a/drivers/mmc/core/sdio_cis.c
+++ b/drivers/mmc/core/sdio_cis.c
@@ -262,7 +262,8 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
else
prev = &card->tuples;
- BUG_ON(*prev);
+ if (*prev)
+ return -EINVAL;
do {
unsigned char tpl_code, tpl_link;
diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h
index 4d903c2e425e..16aa563faa00 100644
--- a/drivers/mmc/core/sdio_cis.h
+++ b/drivers/mmc/core/sdio_cis.h
@@ -14,6 +14,9 @@
#ifndef _MMC_SDIO_CIS_H
#define _MMC_SDIO_CIS_H
+struct mmc_card;
+struct sdio_func;
+
int sdio_read_common_cis(struct mmc_card *card);
void sdio_free_common_cis(struct mmc_card *card);
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
index 406e5f037e32..d40744bbafa9 100644
--- a/drivers/mmc/core/sdio_io.c
+++ b/drivers/mmc/core/sdio_io.c
@@ -16,6 +16,8 @@
#include <linux/mmc/sdio_func.h>
#include "sdio_ops.h"
+#include "core.h"
+#include "card.h"
/**
* sdio_claim_host - exclusively claim a bus for a certain SDIO function
@@ -371,19 +373,16 @@ u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret)
u8 val;
if (!func) {
- *err_ret = -EINVAL;
+ if (err_ret)
+ *err_ret = -EINVAL;
return 0xFF;
}
- if (err_ret)
- *err_ret = 0;
-
ret = mmc_io_rw_direct(func->card, 0, func->num, addr, 0, &val);
- if (ret) {
- if (err_ret)
- *err_ret = ret;
+ if (err_ret)
+ *err_ret = ret;
+ if (ret)
return 0xFF;
- }
return val;
}
@@ -405,7 +404,8 @@ void sdio_writeb(struct sdio_func *func, u8 b, unsigned int addr, int *err_ret)
int ret;
if (!func) {
- *err_ret = -EINVAL;
+ if (err_ret)
+ *err_ret = -EINVAL;
return;
}
@@ -439,7 +439,7 @@ u8 sdio_writeb_readb(struct sdio_func *func, u8 write_byte,
if (err_ret)
*err_ret = ret;
if (ret)
- val = 0xff;
+ return 0xff;
return val;
}
@@ -527,15 +527,11 @@ u16 sdio_readw(struct sdio_func *func, unsigned int addr, int *err_ret)
{
int ret;
- if (err_ret)
- *err_ret = 0;
-
ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 2);
- if (ret) {
- if (err_ret)
- *err_ret = ret;
+ if (err_ret)
+ *err_ret = ret;
+ if (ret)
return 0xFFFF;
- }
return le16_to_cpup((__le16 *)func->tmpbuf);
}
@@ -579,15 +575,11 @@ u32 sdio_readl(struct sdio_func *func, unsigned int addr, int *err_ret)
{
int ret;
- if (err_ret)
- *err_ret = 0;
-
ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 4);
- if (ret) {
- if (err_ret)
- *err_ret = ret;
+ if (err_ret)
+ *err_ret = ret;
+ if (ret)
return 0xFFFFFFFF;
- }
return le32_to_cpup((__le32 *)func->tmpbuf);
}
@@ -633,19 +625,16 @@ unsigned char sdio_f0_readb(struct sdio_func *func, unsigned int addr,
unsigned char val;
if (!func) {
- *err_ret = -EINVAL;
+ if (err_ret)
+ *err_ret = -EINVAL;
return 0xFF;
}
- if (err_ret)
- *err_ret = 0;
-
ret = mmc_io_rw_direct(func->card, 0, 0, addr, 0, &val);
- if (ret) {
- if (err_ret)
- *err_ret = ret;
+ if (err_ret)
+ *err_ret = ret;
+ if (ret)
return 0xFF;
- }
return val;
}
@@ -671,7 +660,8 @@ void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
int ret;
if (!func) {
- *err_ret = -EINVAL;
+ if (err_ret)
+ *err_ret = -EINVAL;
return;
}
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 91bbbfb29f3f..882742ef11bd 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -27,6 +27,8 @@
#include <linux/mmc/sdio_func.h>
#include "sdio_ops.h"
+#include "core.h"
+#include "card.h"
static int process_sdio_pending_irqs(struct mmc_host *host)
{
@@ -92,12 +94,30 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
void sdio_run_irqs(struct mmc_host *host)
{
mmc_claim_host(host);
- host->sdio_irq_pending = true;
- process_sdio_pending_irqs(host);
+ if (host->sdio_irqs) {
+ host->sdio_irq_pending = true;
+ process_sdio_pending_irqs(host);
+ if (host->ops->ack_sdio_irq)
+ host->ops->ack_sdio_irq(host);
+ }
mmc_release_host(host);
}
EXPORT_SYMBOL_GPL(sdio_run_irqs);
+void sdio_irq_work(struct work_struct *work)
+{
+ struct mmc_host *host =
+ container_of(work, struct mmc_host, sdio_irq_work.work);
+
+ sdio_run_irqs(host);
+}
+
+void sdio_signal_irq(struct mmc_host *host)
+{
+ queue_delayed_work(system_wq, &host->sdio_irq_work, 0);
+}
+EXPORT_SYMBOL_GPL(sdio_signal_irq);
+
static int sdio_irq_thread(void *_host)
{
struct mmc_host *host = _host;
@@ -214,7 +234,9 @@ static int sdio_card_irq_put(struct mmc_card *card)
struct mmc_host *host = card->host;
WARN_ON(!host->claimed);
- BUG_ON(host->sdio_irqs < 1);
+
+ if (host->sdio_irqs < 1)
+ return -EINVAL;
if (!--host->sdio_irqs) {
if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
@@ -261,8 +283,8 @@ int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
int ret;
unsigned char reg;
- BUG_ON(!func);
- BUG_ON(!func->card);
+ if (!func)
+ return -EINVAL;
pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func));
@@ -304,8 +326,8 @@ int sdio_release_irq(struct sdio_func *func)
int ret;
unsigned char reg;
- BUG_ON(!func);
- BUG_ON(!func->card);
+ if (!func)
+ return -EINVAL;
pr_debug("SDIO: Disabling IRQ for %s...\n", sdio_func_id(func));
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
index 90fe5545c677..abaaba38514f 100644
--- a/drivers/mmc/core/sdio_ops.c
+++ b/drivers/mmc/core/sdio_ops.c
@@ -21,7 +21,7 @@
int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int i, err = 0;
cmd.opcode = SD_IO_SEND_OP_COND;
@@ -66,7 +66,7 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
unsigned addr, u8 in, u8 *out)
{
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
int err;
if (fn > 7)
@@ -118,9 +118,9 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
{
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
+ struct mmc_request mrq = {};
+ struct mmc_command cmd = {};
+ struct mmc_data data = {};
struct scatterlist sg, *sg_ptr;
struct sg_table sgtable;
unsigned int nents, left_size, i;
@@ -152,7 +152,7 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
left_size = data.blksz * data.blocks;
- nents = (left_size - 1) / seg_size + 1;
+ nents = DIV_ROUND_UP(left_size, seg_size);
if (nents > 1) {
if (sg_alloc_table(&sgtable, nents, GFP_KERNEL))
return -ENOMEM;
@@ -161,10 +161,9 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
data.sg_len = nents;
for_each_sg(data.sg, sg_ptr, data.sg_len, i) {
- sg_set_page(sg_ptr, virt_to_page(buf + (i * seg_size)),
- min(seg_size, left_size),
- offset_in_page(buf + (i * seg_size)));
- left_size = left_size - seg_size;
+ sg_set_buf(sg_ptr, buf + i * seg_size,
+ min(seg_size, left_size));
+ left_size -= seg_size;
}
} else {
data.sg = &sg;
diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h
index 5660c7f459e9..96945cafbf0b 100644
--- a/drivers/mmc/core/sdio_ops.h
+++ b/drivers/mmc/core/sdio_ops.h
@@ -12,18 +12,31 @@
#ifndef _MMC_SDIO_OPS_H
#define _MMC_SDIO_OPS_H
+#include <linux/types.h>
#include <linux/mmc/sdio.h>
+struct mmc_host;
+struct mmc_card;
+struct work_struct;
+
int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
unsigned addr, u8 in, u8* out);
int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz);
int sdio_reset(struct mmc_host *host);
+unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz);
+void sdio_irq_work(struct work_struct *work);
-static inline bool mmc_is_io_op(u32 opcode)
+static inline bool sdio_is_io_busy(u32 opcode, u32 arg)
{
- return opcode == SD_IO_RW_DIRECT || opcode == SD_IO_RW_EXTENDED;
+ u32 addr;
+
+ addr = (arg >> 9) & 0x1FFFF;
+
+ return (opcode == SD_IO_RW_EXTENDED ||
+ (opcode == SD_IO_RW_DIRECT &&
+ !(addr == SDIO_CCCR_ABORT || addr == SDIO_CCCR_SUSPEND)));
}
#endif
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/core/sdio_uart.c
index 5af6fb9a9ce2..d3c91f412b69 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/core/sdio_uart.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/card/sdio_uart.c - SDIO UART/GPS driver
+ * SDIO UART/GPS driver
*
* Based on drivers/serial/8250.c and drivers/serial/serial_core.c
* by Russell King.
@@ -135,8 +135,6 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port)
{
struct sdio_func *func;
- BUG_ON(sdio_uart_table[port->index] != port);
-
spin_lock(&sdio_uart_table_lock);
sdio_uart_table[port->index] = NULL;
spin_unlock(&sdio_uart_table_lock);
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c
index 27117ba47073..babe591aea96 100644
--- a/drivers/mmc/core/slot-gpio.c
+++ b/drivers/mmc/core/slot-gpio.c
@@ -258,6 +258,14 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
}
EXPORT_SYMBOL(mmc_gpiod_request_cd);
+bool mmc_can_gpio_cd(struct mmc_host *host)
+{
+ struct mmc_gpio *ctx = host->slot.handler_priv;
+
+ return ctx->cd_gpio ? true : false;
+}
+EXPORT_SYMBOL(mmc_can_gpio_cd);
+
/**
* mmc_gpiod_request_ro - request a gpio descriptor for write protection
* @host: mmc host
diff --git a/drivers/mmc/core/slot-gpio.h b/drivers/mmc/core/slot-gpio.h
index 8c1854dc5d58..a06fd843f025 100644
--- a/drivers/mmc/core/slot-gpio.h
+++ b/drivers/mmc/core/slot-gpio.h
@@ -8,6 +8,8 @@
#ifndef _MMC_CORE_SLOTGPIO_H
#define _MMC_CORE_SLOTGPIO_H
+struct mmc_host;
+
int mmc_gpio_alloc(struct mmc_host *host);
#endif
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 5274f503a39a..6aa184237adf 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -178,9 +178,10 @@ config MMC_SDHCI_CNS3XXX
config MMC_SDHCI_ESDHC_IMX
tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller"
- depends on ARCH_MXC
+ depends on ARCH_MXC || ARCH_MXC_ARM64 || COMPILE_TEST
depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS
+ select MMC_CQHCI
help
This selects the Freescale eSDHC/uSDHC controller support
found on i.MX25, i.MX35 i.MX5x and i.MX6x.
@@ -764,6 +765,19 @@ config MMC_SUNXI
This selects support for the SD/MMC Host Controller on
Allwinner sunxi SoCs.
+config MMC_CQHCI
+ tristate "Command Queue Host Controller Interface support"
+ depends on HAS_DMA
+ help
+ This selects the Command Queue Host Controller Interface (CQHCI)
+ support present in host controllers of Qualcomm Technologies, Inc
+ amongst others.
+ This controller supports eMMC devices with command queue support.
+
+ If you have a controller with this interface, say Y or M here.
+
+ If unsure, say N.
+
config MMC_TOSHIBA_PCI
tristate "Toshiba Type A SD/MMC Card Interface Driver"
depends on PCI
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index e2bdaaf43184..17fe3718d755 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o
obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o
obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o
obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o
+obj-$(CONFIG_MMC_CQHCI) += cqhci.o
ifeq ($(CONFIG_CB710_DEBUG),y)
CFLAGS-cb710-mmc += -DDEBUG
diff --git a/drivers/mmc/host/android-goldfish.c b/drivers/mmc/host/android-goldfish.c
index dca5518b0139..e90d99f517d1 100644
--- a/drivers/mmc/host/android-goldfish.c
+++ b/drivers/mmc/host/android-goldfish.c
@@ -212,10 +212,7 @@ static void goldfish_mmc_xfer_done(struct goldfish_mmc_host *host,
if (host->dma_in_use) {
enum dma_data_direction dma_data_dir;
- if (data->flags & MMC_DATA_WRITE)
- dma_data_dir = DMA_TO_DEVICE;
- else
- dma_data_dir = DMA_FROM_DEVICE;
+ dma_data_dir = mmc_get_dma_dir(data);
if (dma_data_dir == DMA_FROM_DEVICE) {
/*
@@ -390,10 +387,7 @@ static void goldfish_mmc_prepare_data(struct goldfish_mmc_host *host,
*/
sg_len = (data->blocks == 1) ? 1 : data->sg_len;
- if (data->flags & MMC_DATA_WRITE)
- dma_data_dir = DMA_TO_DEVICE;
- else
- dma_data_dir = DMA_FROM_DEVICE;
+ dma_data_dir = mmc_get_dma_dir(data);
host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
sg_len, dma_data_dir);
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 0ad8ef565b74..388e4a3f13e6 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -954,8 +954,7 @@ static void atmci_pdc_cleanup(struct atmel_mci *host)
if (data)
dma_unmap_sg(&host->pdev->dev,
data->sg, data->sg_len,
- ((data->flags & MMC_DATA_WRITE)
- ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+ mmc_get_dma_dir(data));
}
/*
@@ -993,8 +992,7 @@ static void atmci_dma_cleanup(struct atmel_mci *host)
if (data)
dma_unmap_sg(host->dma.chan->device->dev,
data->sg, data->sg_len,
- ((data->flags & MMC_DATA_WRITE)
- ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+ mmc_get_dma_dir(data));
}
/*
@@ -1095,7 +1093,6 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
{
u32 iflags, tmp;
unsigned int sg_len;
- enum dma_data_direction dir;
int i;
data->error = -EINPROGRESS;
@@ -1107,13 +1104,10 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
/* Enable pdc mode */
atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCMODE);
- if (data->flags & MMC_DATA_READ) {
- dir = DMA_FROM_DEVICE;
+ if (data->flags & MMC_DATA_READ)
iflags |= ATMCI_ENDRX | ATMCI_RXBUFF;
- } else {
- dir = DMA_TO_DEVICE;
+ else
iflags |= ATMCI_ENDTX | ATMCI_TXBUFE | ATMCI_BLKE;
- }
/* Set BLKLEN */
tmp = atmci_readl(host, ATMCI_MR);
@@ -1123,7 +1117,8 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
/* Configure PDC */
host->data_size = data->blocks * data->blksz;
- sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir);
+ sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len,
+ mmc_get_dma_dir(data));
if ((!host->caps.has_rwproof)
&& (host->data->flags & MMC_DATA_WRITE)) {
@@ -1135,9 +1130,8 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
}
if (host->data_size)
- atmci_pdc_set_both_buf(host,
- ((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT));
-
+ atmci_pdc_set_both_buf(host, data->flags & MMC_DATA_READ ?
+ XFER_RECEIVE : XFER_TRANSMIT);
return iflags;
}
@@ -1148,7 +1142,6 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
struct dma_async_tx_descriptor *desc;
struct scatterlist *sg;
unsigned int i;
- enum dma_data_direction direction;
enum dma_transfer_direction slave_dirn;
unsigned int sglen;
u32 maxburst;
@@ -1186,12 +1179,10 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
return -ENODEV;
if (data->flags & MMC_DATA_READ) {
- direction = DMA_FROM_DEVICE;
host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM;
maxburst = atmci_convert_chksize(host,
host->dma_conf.src_maxburst);
} else {
- direction = DMA_TO_DEVICE;
host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV;
maxburst = atmci_convert_chksize(host,
host->dma_conf.dst_maxburst);
@@ -1202,7 +1193,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
ATMCI_DMAEN);
sglen = dma_map_sg(chan->device->dev, data->sg,
- data->sg_len, direction);
+ data->sg_len, mmc_get_dma_dir(data));
dmaengine_slave_config(chan, &host->dma_conf);
desc = dmaengine_prep_slave_sg(chan,
@@ -1217,7 +1208,8 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
return iflags;
unmap_exit:
- dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, direction);
+ dma_unmap_sg(chan->device->dev, data->sg, data->sg_len,
+ mmc_get_dma_dir(data));
return -ENOMEM;
}
diff --git a/drivers/mmc/host/cqhci.c b/drivers/mmc/host/cqhci.c
new file mode 100644
index 000000000000..4b0dfa06cf67
--- /dev/null
+++ b/drivers/mmc/host/cqhci.c
@@ -0,0 +1,1148 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/highmem.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/scatterlist.h>
+#include <linux/platform_device.h>
+#include <linux/ktime.h>
+
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+
+#include "cqhci.h"
+
+#define DCMD_SLOT 31
+#define NUM_SLOTS 32
+
+struct cqhci_slot {
+ struct mmc_request *mrq;
+ unsigned int flags;
+#define CQHCI_EXTERNAL_TIMEOUT BIT(0)
+#define CQHCI_COMPLETED BIT(1)
+#define CQHCI_HOST_CRC BIT(2)
+#define CQHCI_HOST_TIMEOUT BIT(3)
+#define CQHCI_HOST_OTHER BIT(4)
+};
+
+static inline u8 *get_desc(struct cqhci_host *cq_host, u8 tag)
+{
+ return cq_host->desc_base + (tag * cq_host->slot_sz);
+}
+
+static inline u8 *get_link_desc(struct cqhci_host *cq_host, u8 tag)
+{
+ u8 *desc = get_desc(cq_host, tag);
+
+ return desc + cq_host->task_desc_len;
+}
+
+static inline dma_addr_t get_trans_desc_dma(struct cqhci_host *cq_host, u8 tag)
+{
+ return cq_host->trans_desc_dma_base +
+ (cq_host->mmc->max_segs * tag *
+ cq_host->trans_desc_len);
+}
+
+static inline u8 *get_trans_desc(struct cqhci_host *cq_host, u8 tag)
+{
+ return cq_host->trans_desc_base +
+ (cq_host->trans_desc_len * cq_host->mmc->max_segs * tag);
+}
+
+static void setup_trans_desc(struct cqhci_host *cq_host, u8 tag)
+{
+ u8 *link_temp;
+ dma_addr_t trans_temp;
+
+ link_temp = get_link_desc(cq_host, tag);
+ trans_temp = get_trans_desc_dma(cq_host, tag);
+
+ memset(link_temp, 0, cq_host->link_desc_len);
+ if (cq_host->link_desc_len > 8)
+ *(link_temp + 8) = 0;
+
+ if (tag == DCMD_SLOT) {
+ *link_temp = CQHCI_VALID(0) | CQHCI_ACT(0) | CQHCI_END(1);
+ return;
+ }
+
+ *link_temp = CQHCI_VALID(1) | CQHCI_ACT(0x6) | CQHCI_END(0);
+
+ if (cq_host->dma64) {
+ __le64 *data_addr = (__le64 __force *)(link_temp + 4);
+
+ data_addr[0] = cpu_to_le64(trans_temp);
+ } else {
+ __le32 *data_addr = (__le32 __force *)(link_temp + 4);
+
+ data_addr[0] = cpu_to_le32(trans_temp);
+ }
+}
+
+static void cqhci_set_irqs(struct cqhci_host *cq_host, u32 set)
+{
+ cqhci_writel(cq_host, set, CQHCI_ISTE);
+ cqhci_writel(cq_host, set, CQHCI_ISGE);
+}
+
+#define DRV_NAME "cqhci"
+
+#define CQHCI_DUMP(f, x...) \
+ pr_err("%s: " DRV_NAME ": " f, mmc_hostname(mmc), ## x)
+
+static void cqhci_dumpregs(struct cqhci_host *cq_host)
+{
+ struct mmc_host *mmc = cq_host->mmc;
+
+ CQHCI_DUMP("============ CQHCI REGISTER DUMP ===========\n");
+
+ CQHCI_DUMP("Caps: 0x%08x | Version: 0x%08x\n",
+ cqhci_readl(cq_host, CQHCI_CAP),
+ cqhci_readl(cq_host, CQHCI_VER));
+ CQHCI_DUMP("Config: 0x%08x | Control: 0x%08x\n",
+ cqhci_readl(cq_host, CQHCI_CFG),
+ cqhci_readl(cq_host, CQHCI_CTL));
+ CQHCI_DUMP("Int stat: 0x%08x | Int enab: 0x%08x\n",
+ cqhci_readl(cq_host, CQHCI_IS),
+ cqhci_readl(cq_host, CQHCI_ISTE));
+ CQHCI_DUMP("Int sig: 0x%08x | Int Coal: 0x%08x\n",
+ cqhci_readl(cq_host, CQHCI_ISGE),
+ cqhci_readl(cq_host, CQHCI_IC));
+ CQHCI_DUMP("TDL base: 0x%08x | TDL up32: 0x%08x\n",
+ cqhci_readl(cq_host, CQHCI_TDLBA),
+ cqhci_readl(cq_host, CQHCI_TDLBAU));
+ CQHCI_DUMP("Doorbell: 0x%08x | TCN: 0x%08x\n",
+ cqhci_readl(cq_host, CQHCI_TDBR),
+ cqhci_readl(cq_host, CQHCI_TCN));
+ CQHCI_DUMP("Dev queue: 0x%08x | Dev Pend: 0x%08x\n",
+ cqhci_readl(cq_host, CQHCI_DQS),
+ cqhci_readl(cq_host, CQHCI_DPT));
+ CQHCI_DUMP("Task clr: 0x%08x | SSC1: 0x%08x\n",
+ cqhci_readl(cq_host, CQHCI_TCLR),
+ cqhci_readl(cq_host, CQHCI_SSC1));
+ CQHCI_DUMP("SSC2: 0x%08x | DCMD rsp: 0x%08x\n",
+ cqhci_readl(cq_host, CQHCI_SSC2),
+ cqhci_readl(cq_host, CQHCI_CRDCT));
+ CQHCI_DUMP("RED mask: 0x%08x | TERRI: 0x%08x\n",
+ cqhci_readl(cq_host, CQHCI_RMEM),
+ cqhci_readl(cq_host, CQHCI_TERRI));
+ CQHCI_DUMP("Resp idx: 0x%08x | Resp arg: 0x%08x\n",
+ cqhci_readl(cq_host, CQHCI_CRI),
+ cqhci_readl(cq_host, CQHCI_CRA));
+
+ if (cq_host->ops->dumpregs)
+ cq_host->ops->dumpregs(mmc);
+ else
+ CQHCI_DUMP(": ===========================================\n");
+}
+
+/**
+ * The allocated descriptor table for task, link & transfer descritors
+ * looks like:
+ * |----------|
+ * |task desc | |->|----------|
+ * |----------| | |trans desc|
+ * |link desc-|->| |----------|
+ * |----------| .
+ * . .
+ * no. of slots max-segs
+ * . |----------|
+ * |----------|
+ * The idea here is to create the [task+trans] table and mark & point the
+ * link desc to the transfer desc table on a per slot basis.
+ */
+static int cqhci_host_alloc_tdl(struct cqhci_host *cq_host)
+{
+ int i = 0;
+
+ /* task descriptor can be 64/128 bit irrespective of arch */
+ if (cq_host->caps & CQHCI_TASK_DESC_SZ_128) {
+ cqhci_writel(cq_host, cqhci_readl(cq_host, CQHCI_CFG) |
+ CQHCI_TASK_DESC_SZ, CQHCI_CFG);
+ cq_host->task_desc_len = 16;
+ } else {
+ cq_host->task_desc_len = 8;
+ }
+
+ /*
+ * 96 bits length of transfer desc instead of 128 bits which means
+ * ADMA would expect next valid descriptor at the 96th bit
+ * or 128th bit
+ */
+ if (cq_host->dma64) {
+ if (cq_host->quirks & CQHCI_QUIRK_SHORT_TXFR_DESC_SZ)
+ cq_host->trans_desc_len = 12;
+ else
+ cq_host->trans_desc_len = 16;
+ cq_host->link_desc_len = 16;
+ } else {
+ cq_host->trans_desc_len = 8;
+ cq_host->link_desc_len = 8;
+ }
+
+ /* total size of a slot: 1 task & 1 transfer (link) */
+ cq_host->slot_sz = cq_host->task_desc_len + cq_host->link_desc_len;
+
+ cq_host->desc_size = cq_host->slot_sz * cq_host->num_slots;
+
+ cq_host->data_size = cq_host->trans_desc_len * cq_host->mmc->max_segs *
+ (cq_host->num_slots - 1);
+
+ pr_debug("%s: cqhci: desc_size: %zu data_sz: %zu slot-sz: %d\n",
+ mmc_hostname(cq_host->mmc), cq_host->desc_size, cq_host->data_size,
+ cq_host->slot_sz);
+
+ /*
+ * allocate a dma-mapped chunk of memory for the descriptors
+ * allocate a dma-mapped chunk of memory for link descriptors
+ * setup each link-desc memory offset per slot-number to
+ * the descriptor table.
+ */
+ cq_host->desc_base = dmam_alloc_coherent(mmc_dev(cq_host->mmc),
+ cq_host->desc_size,
+ &cq_host->desc_dma_base,
+ GFP_KERNEL);
+ cq_host->trans_desc_base = dmam_alloc_coherent(mmc_dev(cq_host->mmc),
+ cq_host->data_size,
+ &cq_host->trans_desc_dma_base,
+ GFP_KERNEL);
+ if (!cq_host->desc_base || !cq_host->trans_desc_base)
+ return -ENOMEM;
+
+ pr_debug("%s: cqhci: desc-base: 0x%p trans-base: 0x%p\n desc_dma 0x%llx trans_dma: 0x%llx\n",
+ mmc_hostname(cq_host->mmc), cq_host->desc_base, cq_host->trans_desc_base,
+ (unsigned long long)cq_host->desc_dma_base,
+ (unsigned long long)cq_host->trans_desc_dma_base);
+
+ for (; i < (cq_host->num_slots); i++)
+ setup_trans_desc(cq_host, i);
+
+ return 0;
+}
+
+static void __cqhci_enable(struct cqhci_host *cq_host)
+{
+ struct mmc_host *mmc = cq_host->mmc;
+ u32 cqcfg;
+
+ cqcfg = cqhci_readl(cq_host, CQHCI_CFG);
+
+ /* Configuration must not be changed while enabled */
+ if (cqcfg & CQHCI_ENABLE) {
+ cqcfg &= ~CQHCI_ENABLE;
+ cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
+ }
+
+ cqcfg &= ~(CQHCI_DCMD | CQHCI_TASK_DESC_SZ);
+
+ if (mmc->caps2 & MMC_CAP2_CQE_DCMD)
+ cqcfg |= CQHCI_DCMD;
+
+ if (cq_host->caps & CQHCI_TASK_DESC_SZ_128)
+ cqcfg |= CQHCI_TASK_DESC_SZ;
+
+ cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
+
+ cqhci_writel(cq_host, lower_32_bits(cq_host->desc_dma_base),
+ CQHCI_TDLBA);
+ cqhci_writel(cq_host, upper_32_bits(cq_host->desc_dma_base),
+ CQHCI_TDLBAU);
+
+ cqhci_writel(cq_host, cq_host->rca, CQHCI_SSC2);
+
+ cqhci_set_irqs(cq_host, 0);
+
+ cqcfg |= CQHCI_ENABLE;
+
+ cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
+
+ mmc->cqe_on = true;
+
+ if (cq_host->ops->enable)
+ cq_host->ops->enable(mmc);
+
+ /* Ensure all writes are done before interrupts are enabled */
+ wmb();
+
+ cqhci_set_irqs(cq_host, CQHCI_IS_MASK);
+
+ cq_host->activated = true;
+}
+
+static void __cqhci_disable(struct cqhci_host *cq_host)
+{
+ u32 cqcfg;
+
+ cqcfg = cqhci_readl(cq_host, CQHCI_CFG);
+ cqcfg &= ~CQHCI_ENABLE;
+ cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
+
+ cq_host->mmc->cqe_on = false;
+
+ cq_host->activated = false;
+}
+
+int cqhci_suspend(struct mmc_host *mmc)
+{
+ struct cqhci_host *cq_host = mmc->cqe_private;
+
+ if (cq_host->enabled)
+ __cqhci_disable(cq_host);
+
+ return 0;
+}
+EXPORT_SYMBOL(cqhci_suspend);
+
+int cqhci_resume(struct mmc_host *mmc)
+{
+ /* Re-enable is done upon first request */
+ return 0;
+}
+EXPORT_SYMBOL(cqhci_resume);
+
+static int cqhci_enable(struct mmc_host *mmc, struct mmc_card *card)
+{
+ struct cqhci_host *cq_host = mmc->cqe_private;
+ int err;
+
+ if (cq_host->enabled)
+ return 0;
+
+ cq_host->rca = card->rca;
+
+ err = cqhci_host_alloc_tdl(cq_host);
+ if (err)
+ return err;
+
+ __cqhci_enable(cq_host);
+
+ cq_host->enabled = true;
+
+#ifdef DEBUG
+ cqhci_dumpregs(cq_host);
+#endif
+ return 0;
+}
+
+/* CQHCI is idle and should halt immediately, so set a small timeout */
+#define CQHCI_OFF_TIMEOUT 100
+
+static void cqhci_off(struct mmc_host *mmc)
+{
+ struct cqhci_host *cq_host = mmc->cqe_private;
+ ktime_t timeout;
+ bool timed_out;
+ u32 reg;
+
+ if (!cq_host->enabled || !mmc->cqe_on || cq_host->recovery_halt)
+ return;
+
+ if (cq_host->ops->disable)
+ cq_host->ops->disable(mmc, false);
+
+ cqhci_writel(cq_host, CQHCI_HALT, CQHCI_CTL);
+
+ timeout = ktime_add_us(ktime_get(), CQHCI_OFF_TIMEOUT);
+ while (1) {
+ timed_out = ktime_compare(ktime_get(), timeout) > 0;
+ reg = cqhci_readl(cq_host, CQHCI_CTL);
+ if ((reg & CQHCI_HALT) || timed_out)
+ break;
+ }
+
+ if (timed_out)
+ pr_err("%s: cqhci: CQE stuck on\n", mmc_hostname(mmc));
+ else
+ pr_debug("%s: cqhci: CQE off\n", mmc_hostname(mmc));
+
+ mmc->cqe_on = false;
+}
+
+static void cqhci_disable(struct mmc_host *mmc)
+{
+ struct cqhci_host *cq_host = mmc->cqe_private;
+
+ if (!cq_host->enabled)
+ return;
+
+ cqhci_off(mmc);
+
+ __cqhci_disable(cq_host);
+
+ dmam_free_coherent(mmc_dev(mmc), cq_host->data_size,
+ cq_host->trans_desc_base,
+ cq_host->trans_desc_dma_base);
+
+ dmam_free_coherent(mmc_dev(mmc), cq_host->desc_size,
+ cq_host->desc_base,
+ cq_host->desc_dma_base);
+
+ cq_host->trans_desc_base = NULL;
+ cq_host->desc_base = NULL;
+
+ cq_host->enabled = false;
+}
+
+static void cqhci_prep_task_desc(struct mmc_request *mrq,
+ u64 *data, bool intr)
+{
+ u32 req_flags = mrq->data->flags;
+
+ *data = CQHCI_VALID(1) |
+ CQHCI_END(1) |
+ CQHCI_INT(intr) |
+ CQHCI_ACT(0x5) |
+ CQHCI_FORCED_PROG(!!(req_flags & MMC_DATA_FORCED_PRG)) |
+ CQHCI_DATA_TAG(!!(req_flags & MMC_DATA_DAT_TAG)) |
+ CQHCI_DATA_DIR(!!(req_flags & MMC_DATA_READ)) |
+ CQHCI_PRIORITY(!!(req_flags & MMC_DATA_PRIO)) |
+ CQHCI_QBAR(!!(req_flags & MMC_DATA_QBR)) |
+ CQHCI_REL_WRITE(!!(req_flags & MMC_DATA_REL_WR)) |
+ CQHCI_BLK_COUNT(mrq->data->blocks) |
+ CQHCI_BLK_ADDR((u64)mrq->data->blk_addr);
+
+ pr_debug("%s: cqhci: tag %d task descriptor 0x016%llx\n",
+ mmc_hostname(mrq->host), mrq->tag, (unsigned long long)*data);
+}
+
+static int cqhci_dma_map(struct mmc_host *host, struct mmc_request *mrq)
+{
+ int sg_count;
+ struct mmc_data *data = mrq->data;
+
+ if (!data)
+ return -EINVAL;
+
+ sg_count = dma_map_sg(mmc_dev(host), data->sg,
+ data->sg_len,
+ (data->flags & MMC_DATA_WRITE) ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ if (!sg_count) {
+ pr_err("%s: sg-len: %d\n", __func__, data->sg_len);
+ return -ENOMEM;
+ }
+
+ return sg_count;
+}
+
+static void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len,
+ bool end, bool dma64)
+{
+ __le32 *attr = (__le32 __force *)desc;
+
+ *attr = (CQHCI_VALID(1) |
+ CQHCI_END(end ? 1 : 0) |
+ CQHCI_INT(0) |
+ CQHCI_ACT(0x4) |
+ CQHCI_DAT_LENGTH(len));
+
+ if (dma64) {
+ __le64 *dataddr = (__le64 __force *)(desc + 4);
+ dataddr[0] = cpu_to_le64(addr);
+ } else {
+ __le32 *dataddr = (__le32 __force *)(desc + 4);
+ dataddr[0] = cpu_to_le32(addr);
+ }
+}
+
+static int cqhci_prep_tran_desc(struct mmc_request *mrq,
+ struct cqhci_host *cq_host, int tag)
+{
+ struct mmc_data *data = mrq->data;
+ int i, sg_count, len;
+ bool end = false;
+ bool dma64 = cq_host->dma64;
+ dma_addr_t addr;
+ u8 *desc;
+ struct scatterlist *sg;
+
+ sg_count = cqhci_dma_map(mrq->host, mrq);
+ if (sg_count < 0) {
+ pr_err("%s: %s: unable to map sg lists, %d\n",
+ mmc_hostname(mrq->host), __func__, sg_count);
+ return sg_count;
+ }
+
+ desc = get_trans_desc(cq_host, tag);
+
+ for_each_sg(data->sg, sg, sg_count, i) {
+ addr = sg_dma_address(sg);
+ len = sg_dma_len(sg);
+
+ if ((i+1) == sg_count)
+ end = true;
+ cqhci_set_tran_desc(desc, addr, len, end, dma64);
+ desc += cq_host->trans_desc_len;
+ }
+
+ return 0;
+}
+
+static void cqhci_prep_dcmd_desc(struct mmc_host *mmc,
+ struct mmc_request *mrq)
+{
+ u64 *task_desc = NULL;
+ u64 data = 0;
+ u8 resp_type;
+ u8 *desc;
+ __le64 *dataddr;
+ struct cqhci_host *cq_host = mmc->cqe_private;
+ u8 timing;
+
+ if (!(mrq->cmd->flags & MMC_RSP_PRESENT)) {
+ resp_type = 0x0;
+ timing = 0x1;
+ } else {
+ if (mrq->cmd->flags & MMC_RSP_R1B) {
+ resp_type = 0x3;
+ timing = 0x0;
+ } else {
+ resp_type = 0x2;
+ timing = 0x1;
+ }
+ }
+
+ task_desc = (__le64 __force *)get_desc(cq_host, cq_host->dcmd_slot);
+ memset(task_desc, 0, cq_host->task_desc_len);
+ data |= (CQHCI_VALID(1) |
+ CQHCI_END(1) |
+ CQHCI_INT(1) |
+ CQHCI_QBAR(1) |
+ CQHCI_ACT(0x5) |
+ CQHCI_CMD_INDEX(mrq->cmd->opcode) |
+ CQHCI_CMD_TIMING(timing) | CQHCI_RESP_TYPE(resp_type));
+ *task_desc |= data;
+ desc = (u8 *)task_desc;
+ pr_debug("%s: cqhci: dcmd: cmd: %d timing: %d resp: %d\n",
+ mmc_hostname(mmc), mrq->cmd->opcode, timing, resp_type);
+ dataddr = (__le64 __force *)(desc + 4);
+ dataddr[0] = cpu_to_le64((u64)mrq->cmd->arg);
+
+}
+
+static void cqhci_post_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+ struct mmc_data *data = mrq->data;
+
+ if (data) {
+ dma_unmap_sg(mmc_dev(host), data->sg, data->sg_len,
+ (data->flags & MMC_DATA_READ) ?
+ DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ }
+}
+
+static inline int cqhci_tag(struct mmc_request *mrq)
+{
+ return mrq->cmd ? DCMD_SLOT : mrq->tag;
+}
+
+static int cqhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ int err = 0;
+ u64 data = 0;
+ u64 *task_desc = NULL;
+ int tag = cqhci_tag(mrq);
+ struct cqhci_host *cq_host = mmc->cqe_private;
+ unsigned long flags;
+
+ if (!cq_host->enabled) {
+ pr_err("%s: cqhci: not enabled\n", mmc_hostname(mmc));
+ return -EINVAL;
+ }
+
+ /* First request after resume has to re-enable */
+ if (!cq_host->activated)
+ __cqhci_enable(cq_host);
+
+ if (!mmc->cqe_on) {
+ cqhci_writel(cq_host, 0, CQHCI_CTL);
+ mmc->cqe_on = true;
+ pr_debug("%s: cqhci: CQE on\n", mmc_hostname(mmc));
+ if (cqhci_readl(cq_host, CQHCI_CTL) && CQHCI_HALT) {
+ pr_err("%s: cqhci: CQE failed to exit halt state\n",
+ mmc_hostname(mmc));
+ }
+ if (cq_host->ops->enable)
+ cq_host->ops->enable(mmc);
+ }
+
+ if (mrq->data) {
+ task_desc = (__le64 __force *)get_desc(cq_host, tag);
+ cqhci_prep_task_desc(mrq, &data, 1);
+ *task_desc = cpu_to_le64(data);
+ err = cqhci_prep_tran_desc(mrq, cq_host, tag);
+ if (err) {
+ pr_err("%s: cqhci: failed to setup tx desc: %d\n",
+ mmc_hostname(mmc), err);
+ return err;
+ }
+ } else {
+ cqhci_prep_dcmd_desc(mmc, mrq);
+ }
+
+ spin_lock_irqsave(&cq_host->lock, flags);
+
+ if (cq_host->recovery_halt) {
+ err = -EBUSY;
+ goto out_unlock;
+ }
+
+ cq_host->slot[tag].mrq = mrq;
+ cq_host->slot[tag].flags = 0;
+
+ cq_host->qcnt += 1;
+
+ cqhci_writel(cq_host, 1 << tag, CQHCI_TDBR);
+ if (!(cqhci_readl(cq_host, CQHCI_TDBR) & (1 << tag)))
+ pr_debug("%s: cqhci: doorbell not set for tag %d\n",
+ mmc_hostname(mmc), tag);
+out_unlock:
+ spin_unlock_irqrestore(&cq_host->lock, flags);
+
+ if (err)
+ cqhci_post_req(mmc, mrq);
+
+ return err;
+}
+
+static void cqhci_recovery_needed(struct mmc_host *mmc, struct mmc_request *mrq,
+ bool notify)
+{
+ struct cqhci_host *cq_host = mmc->cqe_private;
+
+ if (!cq_host->recovery_halt) {
+ cq_host->recovery_halt = true;
+ pr_debug("%s: cqhci: recovery needed\n", mmc_hostname(mmc));
+ wake_up(&cq_host->wait_queue);
+ if (notify && mmc->cqe_recovery_notifier)
+ mmc->cqe_recovery_notifier(mmc, mrq);
+ }
+}
+
+static unsigned int cqhci_error_flags(int error1, int error2)
+{
+ int error = error1 ? error1 : error2;
+
+ switch (error) {
+ case -EILSEQ:
+ return CQHCI_HOST_CRC;
+ case -ETIMEDOUT:
+ return CQHCI_HOST_TIMEOUT;
+ default:
+ return CQHCI_HOST_OTHER;
+ }
+}
+
+static void cqhci_error_irq(struct mmc_host *mmc, u32 status, int cmd_error,
+ int data_error)
+{
+ struct cqhci_host *cq_host = mmc->cqe_private;
+ struct cqhci_slot *slot;
+ u32 terri;
+ int tag;
+
+ spin_lock(&cq_host->lock);
+
+ terri = cqhci_readl(cq_host, CQHCI_TERRI);
+
+ pr_debug("%s: cqhci: error IRQ status: 0x%08x cmd error %d data error %d TERRI: 0x%08x\n",
+ mmc_hostname(mmc), status, cmd_error, data_error, terri);
+
+ /* Forget about errors when recovery has already been triggered */
+ if (cq_host->recovery_halt)
+ goto out_unlock;
+
+ if (!cq_host->qcnt) {
+ WARN_ONCE(1, "%s: cqhci: error when idle. IRQ status: 0x%08x cmd error %d data error %d TERRI: 0x%08x\n",
+ mmc_hostname(mmc), status, cmd_error, data_error,
+ terri);
+ goto out_unlock;
+ }
+
+ if (CQHCI_TERRI_C_VALID(terri)) {
+ tag = CQHCI_TERRI_C_TASK(terri);
+ slot = &cq_host->slot[tag];
+ if (slot->mrq) {
+ slot->flags = cqhci_error_flags(cmd_error, data_error);
+ cqhci_recovery_needed(mmc, slot->mrq, true);
+ }
+ }
+
+ if (CQHCI_TERRI_D_VALID(terri)) {
+ tag = CQHCI_TERRI_D_TASK(terri);
+ slot = &cq_host->slot[tag];
+ if (slot->mrq) {
+ slot->flags = cqhci_error_flags(data_error, cmd_error);
+ cqhci_recovery_needed(mmc, slot->mrq, true);
+ }
+ }
+
+ if (!cq_host->recovery_halt) {
+ /*
+ * The only way to guarantee forward progress is to mark at
+ * least one task in error, so if none is indicated, pick one.
+ */
+ for (tag = 0; tag < NUM_SLOTS; tag++) {
+ slot = &cq_host->slot[tag];
+ if (!slot->mrq)
+ continue;
+ slot->flags = cqhci_error_flags(data_error, cmd_error);
+ cqhci_recovery_needed(mmc, slot->mrq, true);
+ break;
+ }
+ }
+
+out_unlock:
+ spin_unlock(&cq_host->lock);
+}
+
+static void cqhci_finish_mrq(struct mmc_host *mmc, unsigned int tag)
+{
+ struct cqhci_host *cq_host = mmc->cqe_private;
+ struct cqhci_slot *slot = &cq_host->slot[tag];
+ struct mmc_request *mrq = slot->mrq;
+ struct mmc_data *data;
+
+ if (!mrq) {
+ WARN_ONCE(1, "%s: cqhci: spurious TCN for tag %d\n",
+ mmc_hostname(mmc), tag);
+ return;
+ }
+
+ /* No completions allowed during recovery */
+ if (cq_host->recovery_halt) {
+ slot->flags |= CQHCI_COMPLETED;
+ return;
+ }
+
+ slot->mrq = NULL;
+
+ cq_host->qcnt -= 1;
+
+ data = mrq->data;
+ if (data) {
+ if (data->error)
+ data->bytes_xfered = 0;
+ else
+ data->bytes_xfered = data->blksz * data->blocks;
+ }
+
+ mmc_cqe_request_done(mmc, mrq);
+}
+
+irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error,
+ int data_error)
+{
+ u32 status;
+ unsigned long tag = 0, comp_status;
+ struct cqhci_host *cq_host = mmc->cqe_private;
+
+ status = cqhci_readl(cq_host, CQHCI_IS);
+ cqhci_writel(cq_host, status, CQHCI_IS);
+
+ pr_debug("%s: cqhci: IRQ status: 0x%08x\n", mmc_hostname(mmc), status);
+
+ if ((status & CQHCI_IS_RED) || cmd_error || data_error)
+ cqhci_error_irq(mmc, status, cmd_error, data_error);
+
+ if (status & CQHCI_IS_TCC) {
+ /* read TCN and complete the request */
+ comp_status = cqhci_readl(cq_host, CQHCI_TCN);
+ cqhci_writel(cq_host, comp_status, CQHCI_TCN);
+ pr_debug("%s: cqhci: TCN: 0x%08lx\n",
+ mmc_hostname(mmc), comp_status);
+
+ spin_lock(&cq_host->lock);
+
+ for_each_set_bit(tag, &comp_status, cq_host->num_slots) {
+ /* complete the corresponding mrq */
+ pr_debug("%s: cqhci: completing tag %lu\n",
+ mmc_hostname(mmc), tag);
+ cqhci_finish_mrq(mmc, tag);
+ }
+
+ if (cq_host->waiting_for_idle && !cq_host->qcnt) {
+ cq_host->waiting_for_idle = false;
+ wake_up(&cq_host->wait_queue);
+ }
+
+ spin_unlock(&cq_host->lock);
+ }
+
+ if (status & CQHCI_IS_TCL)
+ wake_up(&cq_host->wait_queue);
+
+ if (status & CQHCI_IS_HAC)
+ wake_up(&cq_host->wait_queue);
+
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(cqhci_irq);
+
+static bool cqhci_is_idle(struct cqhci_host *cq_host, int *ret)
+{
+ unsigned long flags;
+ bool is_idle;
+
+ spin_lock_irqsave(&cq_host->lock, flags);
+ is_idle = !cq_host->qcnt || cq_host->recovery_halt;
+ *ret = cq_host->recovery_halt ? -EBUSY : 0;
+ cq_host->waiting_for_idle = !is_idle;
+ spin_unlock_irqrestore(&cq_host->lock, flags);
+
+ return is_idle;
+}
+
+static int cqhci_wait_for_idle(struct mmc_host *mmc)
+{
+ struct cqhci_host *cq_host = mmc->cqe_private;
+ int ret;
+
+ wait_event(cq_host->wait_queue, cqhci_is_idle(cq_host, &ret));
+
+ return ret;
+}
+
+static bool cqhci_timeout(struct mmc_host *mmc, struct mmc_request *mrq,
+ bool *recovery_needed)
+{
+ struct cqhci_host *cq_host = mmc->cqe_private;
+ int tag = cqhci_tag(mrq);
+ struct cqhci_slot *slot = &cq_host->slot[tag];
+ unsigned long flags;
+ bool timed_out;
+
+ spin_lock_irqsave(&cq_host->lock, flags);
+ timed_out = slot->mrq == mrq;
+ if (timed_out) {
+ slot->flags |= CQHCI_EXTERNAL_TIMEOUT;
+ cqhci_recovery_needed(mmc, mrq, false);
+ *recovery_needed = cq_host->recovery_halt;
+ }
+ spin_unlock_irqrestore(&cq_host->lock, flags);
+
+ if (timed_out) {
+ pr_err("%s: cqhci: timeout for tag %d\n",
+ mmc_hostname(mmc), tag);
+ cqhci_dumpregs(cq_host);
+ }
+
+ return timed_out;
+}
+
+static bool cqhci_tasks_cleared(struct cqhci_host *cq_host)
+{
+ return !(cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_CLEAR_ALL_TASKS);
+}
+
+static bool cqhci_clear_all_tasks(struct mmc_host *mmc, unsigned int timeout)
+{
+ struct cqhci_host *cq_host = mmc->cqe_private;
+ bool ret;
+ u32 ctl;
+
+ cqhci_set_irqs(cq_host, CQHCI_IS_TCL);
+
+ ctl = cqhci_readl(cq_host, CQHCI_CTL);
+ ctl |= CQHCI_CLEAR_ALL_TASKS;
+ cqhci_writel(cq_host, ctl, CQHCI_CTL);
+
+ wait_event_timeout(cq_host->wait_queue, cqhci_tasks_cleared(cq_host),
+ msecs_to_jiffies(timeout) + 1);
+
+ cqhci_set_irqs(cq_host, 0);
+
+ ret = cqhci_tasks_cleared(cq_host);
+
+ if (!ret)
+ pr_debug("%s: cqhci: Failed to clear tasks\n",
+ mmc_hostname(mmc));
+
+ return ret;
+}
+
+static bool cqhci_halted(struct cqhci_host *cq_host)
+{
+ return cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT;
+}
+
+static bool cqhci_halt(struct mmc_host *mmc, unsigned int timeout)
+{
+ struct cqhci_host *cq_host = mmc->cqe_private;
+ bool ret;
+ u32 ctl;
+
+ if (cqhci_halted(cq_host))
+ return true;
+
+ cqhci_set_irqs(cq_host, CQHCI_IS_HAC);
+
+ ctl = cqhci_readl(cq_host, CQHCI_CTL);
+ ctl |= CQHCI_HALT;
+ cqhci_writel(cq_host, ctl, CQHCI_CTL);
+
+ wait_event_timeout(cq_host->wait_queue, cqhci_halted(cq_host),
+ msecs_to_jiffies(timeout) + 1);
+
+ cqhci_set_irqs(cq_host, 0);
+
+ ret = cqhci_halted(cq_host);
+
+ if (!ret)
+ pr_debug("%s: cqhci: Failed to halt\n", mmc_hostname(mmc));
+
+ return ret;
+}
+
+/*
+ * After halting we expect to be able to use the command line. We interpret the
+ * failure to halt to mean the data lines might still be in use (and the upper
+ * layers will need to send a STOP command), so we set the timeout based on a
+ * generous command timeout.
+ */
+#define CQHCI_START_HALT_TIMEOUT 5
+
+static void cqhci_recovery_start(struct mmc_host *mmc)
+{
+ struct cqhci_host *cq_host = mmc->cqe_private;
+
+ pr_debug("%s: cqhci: %s\n", mmc_hostname(mmc), __func__);
+
+ WARN_ON(!cq_host->recovery_halt);
+
+ cqhci_halt(mmc, CQHCI_START_HALT_TIMEOUT);
+
+ if (cq_host->ops->disable)
+ cq_host->ops->disable(mmc, true);
+
+ mmc->cqe_on = false;
+}
+
+static int cqhci_error_from_flags(unsigned int flags)
+{
+ if (!flags)
+ return 0;
+
+ /* CRC errors might indicate re-tuning so prefer to report that */
+ if (flags & CQHCI_HOST_CRC)
+ return -EILSEQ;
+
+ if (flags & (CQHCI_EXTERNAL_TIMEOUT | CQHCI_HOST_TIMEOUT))
+ return -ETIMEDOUT;
+
+ return -EIO;
+}
+
+static void cqhci_recover_mrq(struct cqhci_host *cq_host, unsigned int tag)
+{
+ struct cqhci_slot *slot = &cq_host->slot[tag];
+ struct mmc_request *mrq = slot->mrq;
+ struct mmc_data *data;
+
+ if (!mrq)
+ return;
+
+ slot->mrq = NULL;
+
+ cq_host->qcnt -= 1;
+
+ data = mrq->data;
+ if (data) {
+ data->bytes_xfered = 0;
+ data->error = cqhci_error_from_flags(slot->flags);
+ } else {
+ mrq->cmd->error = cqhci_error_from_flags(slot->flags);
+ }
+
+ mmc_cqe_request_done(cq_host->mmc, mrq);
+}
+
+static void cqhci_recover_mrqs(struct cqhci_host *cq_host)
+{
+ int i;
+
+ for (i = 0; i < cq_host->num_slots; i++)
+ cqhci_recover_mrq(cq_host, i);
+}
+
+/*
+ * By now the command and data lines should be unused so there is no reason for
+ * CQHCI to take a long time to halt, but if it doesn't halt there could be
+ * problems clearing tasks, so be generous.
+ */
+#define CQHCI_FINISH_HALT_TIMEOUT 20
+
+/* CQHCI could be expected to clear it's internal state pretty quickly */
+#define CQHCI_CLEAR_TIMEOUT 20
+
+static void cqhci_recovery_finish(struct mmc_host *mmc)
+{
+ struct cqhci_host *cq_host = mmc->cqe_private;
+ unsigned long flags;
+ u32 cqcfg;
+ bool ok;
+
+ pr_debug("%s: cqhci: %s\n", mmc_hostname(mmc), __func__);
+
+ WARN_ON(!cq_host->recovery_halt);
+
+ ok = cqhci_halt(mmc, CQHCI_FINISH_HALT_TIMEOUT);
+
+ if (!cqhci_clear_all_tasks(mmc, CQHCI_CLEAR_TIMEOUT))
+ ok = false;
+
+ /*
+ * The specification contradicts itself, by saying that tasks cannot be
+ * cleared if CQHCI does not halt, but if CQHCI does not halt, it should
+ * be disabled/re-enabled, but not to disable before clearing tasks.
+ * Have a go anyway.
+ */
+ if (!ok) {
+ pr_debug("%s: cqhci: disable / re-enable\n", mmc_hostname(mmc));
+ cqcfg = cqhci_readl(cq_host, CQHCI_CFG);
+ cqcfg &= ~CQHCI_ENABLE;
+ cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
+ cqcfg |= CQHCI_ENABLE;
+ cqhci_writel(cq_host, cqcfg, CQHCI_CFG);
+ /* Be sure that there are no tasks */
+ ok = cqhci_halt(mmc, CQHCI_FINISH_HALT_TIMEOUT);
+ if (!cqhci_clear_all_tasks(mmc, CQHCI_CLEAR_TIMEOUT))
+ ok = false;
+ WARN_ON(!ok);
+ }
+
+ cqhci_recover_mrqs(cq_host);
+
+ WARN_ON(cq_host->qcnt);
+
+ spin_lock_irqsave(&cq_host->lock, flags);
+ cq_host->qcnt = 0;
+ cq_host->recovery_halt = false;
+ mmc->cqe_on = false;
+ spin_unlock_irqrestore(&cq_host->lock, flags);
+
+ /* Ensure all writes are done before interrupts are re-enabled */
+ wmb();
+
+ cqhci_writel(cq_host, CQHCI_IS_HAC | CQHCI_IS_TCL, CQHCI_IS);
+
+ cqhci_set_irqs(cq_host, CQHCI_IS_MASK);
+
+ pr_debug("%s: cqhci: recovery done\n", mmc_hostname(mmc));
+}
+
+static const struct mmc_cqe_ops cqhci_cqe_ops = {
+ .cqe_enable = cqhci_enable,
+ .cqe_disable = cqhci_disable,
+ .cqe_request = cqhci_request,
+ .cqe_post_req = cqhci_post_req,
+ .cqe_off = cqhci_off,
+ .cqe_wait_for_idle = cqhci_wait_for_idle,
+ .cqe_timeout = cqhci_timeout,
+ .cqe_recovery_start = cqhci_recovery_start,
+ .cqe_recovery_finish = cqhci_recovery_finish,
+};
+
+struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev)
+{
+ struct cqhci_host *cq_host;
+ struct resource *cqhci_memres = NULL;
+
+ /* check and setup CMDQ interface */
+ cqhci_memres = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "cqhci_mem");
+ if (!cqhci_memres) {
+ dev_dbg(&pdev->dev, "CMDQ not supported\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ cq_host = devm_kzalloc(&pdev->dev, sizeof(*cq_host), GFP_KERNEL);
+ if (!cq_host)
+ return ERR_PTR(-ENOMEM);
+ cq_host->mmio = devm_ioremap(&pdev->dev,
+ cqhci_memres->start,
+ resource_size(cqhci_memres));
+ if (!cq_host->mmio) {
+ dev_err(&pdev->dev, "failed to remap cqhci regs\n");
+ return ERR_PTR(-EBUSY);
+ }
+ dev_dbg(&pdev->dev, "CMDQ ioremap: done\n");
+
+ return cq_host;
+}
+EXPORT_SYMBOL(cqhci_pltfm_init);
+
+static unsigned int cqhci_ver_major(struct cqhci_host *cq_host)
+{
+ return CQHCI_VER_MAJOR(cqhci_readl(cq_host, CQHCI_VER));
+}
+
+static unsigned int cqhci_ver_minor(struct cqhci_host *cq_host)
+{
+ u32 ver = cqhci_readl(cq_host, CQHCI_VER);
+
+ return CQHCI_VER_MINOR1(ver) * 10 + CQHCI_VER_MINOR2(ver);
+}
+
+int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc,
+ bool dma64)
+{
+ int err;
+
+ cq_host->dma64 = dma64;
+ cq_host->mmc = mmc;
+ cq_host->mmc->cqe_private = cq_host;
+
+ cq_host->num_slots = NUM_SLOTS;
+ cq_host->dcmd_slot = DCMD_SLOT;
+
+ mmc->cqe_ops = &cqhci_cqe_ops;
+
+ mmc->cqe_qdepth = NUM_SLOTS;
+ if (mmc->caps2 & MMC_CAP2_CQE_DCMD)
+ mmc->cqe_qdepth -= 1;
+
+ cq_host->slot = devm_kcalloc(mmc_dev(mmc), cq_host->num_slots,
+ sizeof(*cq_host->slot), GFP_KERNEL);
+ if (!cq_host->slot) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ spin_lock_init(&cq_host->lock);
+
+ init_completion(&cq_host->halt_comp);
+ init_waitqueue_head(&cq_host->wait_queue);
+
+ pr_info("%s: CQHCI version %u.%02u\n",
+ mmc_hostname(mmc), cqhci_ver_major(cq_host),
+ cqhci_ver_minor(cq_host));
+
+ return 0;
+
+out_err:
+ pr_err("%s: CQHCI version %u.%02u failed to initialize, error %d\n",
+ mmc_hostname(mmc), cqhci_ver_major(cq_host),
+ cqhci_ver_minor(cq_host), err);
+ return err;
+}
+EXPORT_SYMBOL(cqhci_init);
+
+MODULE_AUTHOR("Venkat Gopalakrishnan <venkatg@codeaurora.org>");
+MODULE_DESCRIPTION("Command Queue Host Controller Interface driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/cqhci.h b/drivers/mmc/host/cqhci.h
new file mode 100644
index 000000000000..2d39d361b322
--- /dev/null
+++ b/drivers/mmc/host/cqhci.h
@@ -0,0 +1,240 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef LINUX_MMC_CQHCI_H
+#define LINUX_MMC_CQHCI_H
+
+#include <linux/compiler.h>
+#include <linux/bitops.h>
+#include <linux/spinlock_types.h>
+#include <linux/types.h>
+#include <linux/completion.h>
+#include <linux/wait.h>
+#include <linux/irqreturn.h>
+#include <asm/io.h>
+
+/* registers */
+/* version */
+#define CQHCI_VER 0x00
+#define CQHCI_VER_MAJOR(x) (((x) & GENMASK(11, 8)) >> 8)
+#define CQHCI_VER_MINOR1(x) (((x) & GENMASK(7, 4)) >> 4)
+#define CQHCI_VER_MINOR2(x) ((x) & GENMASK(3, 0))
+
+/* capabilities */
+#define CQHCI_CAP 0x04
+/* configuration */
+#define CQHCI_CFG 0x08
+#define CQHCI_DCMD 0x00001000
+#define CQHCI_TASK_DESC_SZ 0x00000100
+#define CQHCI_ENABLE 0x00000001
+
+/* control */
+#define CQHCI_CTL 0x0C
+#define CQHCI_CLEAR_ALL_TASKS 0x00000100
+#define CQHCI_HALT 0x00000001
+
+/* interrupt status */
+#define CQHCI_IS 0x10
+#define CQHCI_IS_HAC BIT(0)
+#define CQHCI_IS_TCC BIT(1)
+#define CQHCI_IS_RED BIT(2)
+#define CQHCI_IS_TCL BIT(3)
+
+#define CQHCI_IS_MASK (CQHCI_IS_TCC | CQHCI_IS_RED)
+
+/* interrupt status enable */
+#define CQHCI_ISTE 0x14
+
+/* interrupt signal enable */
+#define CQHCI_ISGE 0x18
+
+/* interrupt coalescing */
+#define CQHCI_IC 0x1C
+#define CQHCI_IC_ENABLE BIT(31)
+#define CQHCI_IC_RESET BIT(16)
+#define CQHCI_IC_ICCTHWEN BIT(15)
+#define CQHCI_IC_ICCTH(x) ((x & 0x1F) << 8)
+#define CQHCI_IC_ICTOVALWEN BIT(7)
+#define CQHCI_IC_ICTOVAL(x) (x & 0x7F)
+
+/* task list base address */
+#define CQHCI_TDLBA 0x20
+
+/* task list base address upper */
+#define CQHCI_TDLBAU 0x24
+
+/* door-bell */
+#define CQHCI_TDBR 0x28
+
+/* task completion notification */
+#define CQHCI_TCN 0x2C
+
+/* device queue status */
+#define CQHCI_DQS 0x30
+
+/* device pending tasks */
+#define CQHCI_DPT 0x34
+
+/* task clear */
+#define CQHCI_TCLR 0x38
+
+/* send status config 1 */
+#define CQHCI_SSC1 0x40
+
+/* send status config 2 */
+#define CQHCI_SSC2 0x44
+
+/* response for dcmd */
+#define CQHCI_CRDCT 0x48
+
+/* response mode error mask */
+#define CQHCI_RMEM 0x50
+
+/* task error info */
+#define CQHCI_TERRI 0x54
+
+#define CQHCI_TERRI_C_INDEX(x) ((x) & GENMASK(5, 0))
+#define CQHCI_TERRI_C_TASK(x) (((x) & GENMASK(12, 8)) >> 8)
+#define CQHCI_TERRI_C_VALID(x) ((x) & BIT(15))
+#define CQHCI_TERRI_D_INDEX(x) (((x) & GENMASK(21, 16)) >> 16)
+#define CQHCI_TERRI_D_TASK(x) (((x) & GENMASK(28, 24)) >> 24)
+#define CQHCI_TERRI_D_VALID(x) ((x) & BIT(31))
+
+/* command response index */
+#define CQHCI_CRI 0x58
+
+/* command response argument */
+#define CQHCI_CRA 0x5C
+
+#define CQHCI_INT_ALL 0xF
+#define CQHCI_IC_DEFAULT_ICCTH 31
+#define CQHCI_IC_DEFAULT_ICTOVAL 1
+
+/* attribute fields */
+#define CQHCI_VALID(x) ((x & 1) << 0)
+#define CQHCI_END(x) ((x & 1) << 1)
+#define CQHCI_INT(x) ((x & 1) << 2)
+#define CQHCI_ACT(x) ((x & 0x7) << 3)
+
+/* data command task descriptor fields */
+#define CQHCI_FORCED_PROG(x) ((x & 1) << 6)
+#define CQHCI_CONTEXT(x) ((x & 0xF) << 7)
+#define CQHCI_DATA_TAG(x) ((x & 1) << 11)
+#define CQHCI_DATA_DIR(x) ((x & 1) << 12)
+#define CQHCI_PRIORITY(x) ((x & 1) << 13)
+#define CQHCI_QBAR(x) ((x & 1) << 14)
+#define CQHCI_REL_WRITE(x) ((x & 1) << 15)
+#define CQHCI_BLK_COUNT(x) ((x & 0xFFFF) << 16)
+#define CQHCI_BLK_ADDR(x) ((x & 0xFFFFFFFF) << 32)
+
+/* direct command task descriptor fields */
+#define CQHCI_CMD_INDEX(x) ((x & 0x3F) << 16)
+#define CQHCI_CMD_TIMING(x) ((x & 1) << 22)
+#define CQHCI_RESP_TYPE(x) ((x & 0x3) << 23)
+
+/* transfer descriptor fields */
+#define CQHCI_DAT_LENGTH(x) ((x & 0xFFFF) << 16)
+#define CQHCI_DAT_ADDR_LO(x) ((x & 0xFFFFFFFF) << 32)
+#define CQHCI_DAT_ADDR_HI(x) ((x & 0xFFFFFFFF) << 0)
+
+struct cqhci_host_ops;
+struct mmc_host;
+struct cqhci_slot;
+
+struct cqhci_host {
+ const struct cqhci_host_ops *ops;
+ void __iomem *mmio;
+ struct mmc_host *mmc;
+
+ spinlock_t lock;
+
+ /* relative card address of device */
+ unsigned int rca;
+
+ /* 64 bit DMA */
+ bool dma64;
+ int num_slots;
+ int qcnt;
+
+ u32 dcmd_slot;
+ u32 caps;
+#define CQHCI_TASK_DESC_SZ_128 0x1
+
+ u32 quirks;
+#define CQHCI_QUIRK_SHORT_TXFR_DESC_SZ 0x1
+
+ bool enabled;
+ bool halted;
+ bool init_done;
+ bool activated;
+ bool waiting_for_idle;
+ bool recovery_halt;
+
+ size_t desc_size;
+ size_t data_size;
+
+ u8 *desc_base;
+
+ /* total descriptor size */
+ u8 slot_sz;
+
+ /* 64/128 bit depends on CQHCI_CFG */
+ u8 task_desc_len;
+
+ /* 64 bit on 32-bit arch, 128 bit on 64-bit */
+ u8 link_desc_len;
+
+ u8 *trans_desc_base;
+ /* same length as transfer descriptor */
+ u8 trans_desc_len;
+
+ dma_addr_t desc_dma_base;
+ dma_addr_t trans_desc_dma_base;
+
+ struct completion halt_comp;
+ wait_queue_head_t wait_queue;
+ struct cqhci_slot *slot;
+};
+
+struct cqhci_host_ops {
+ void (*dumpregs)(struct mmc_host *mmc);
+ void (*write_l)(struct cqhci_host *host, u32 val, int reg);
+ u32 (*read_l)(struct cqhci_host *host, int reg);
+ void (*enable)(struct mmc_host *mmc);
+ void (*disable)(struct mmc_host *mmc, bool recovery);
+};
+
+static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg)
+{
+ if (unlikely(host->ops->write_l))
+ host->ops->write_l(host, val, reg);
+ else
+ writel_relaxed(val, host->mmio + reg);
+}
+
+static inline u32 cqhci_readl(struct cqhci_host *host, int reg)
+{
+ if (unlikely(host->ops->read_l))
+ return host->ops->read_l(host, reg);
+ else
+ return readl_relaxed(host->mmio + reg);
+}
+
+struct platform_device;
+
+irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error,
+ int data_error);
+int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc, bool dma64);
+struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev);
+int cqhci_suspend(struct mmc_host *mmc);
+int cqhci_resume(struct mmc_host *mmc);
+
+#endif
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 8fa478c3b0db..affa9fc92c1b 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -35,6 +35,7 @@
#include <linux/mmc/mmc.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/interrupt.h>
#include <linux/platform_data/mmc-davinci.h>
@@ -476,18 +477,14 @@ static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host,
int ret = 0;
host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- ((data->flags & MMC_DATA_WRITE)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE));
+ mmc_get_dma_dir(data));
/* no individual DMA segment should need a partial FIFO */
for (i = 0; i < host->sg_len; i++) {
if (sg_dma_len(data->sg + i) & mask) {
dma_unmap_sg(mmc_dev(host->mmc),
- data->sg, data->sg_len,
- (data->flags & MMC_DATA_WRITE)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
+ data->sg, data->sg_len,
+ mmc_get_dma_dir(data));
return -1;
}
}
@@ -800,9 +797,7 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data)
davinci_abort_dma(host);
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- (data->flags & MMC_DATA_WRITE)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
+ mmc_get_dma_dir(data));
host->do_dma = false;
}
host->data_dir = DAVINCI_MMC_DATADIR_NONE;
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index e10a00d0d44d..ba5fdd696ddb 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -397,14 +397,6 @@ static void dw_mci_stop_dma(struct dw_mci *host)
set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
}
-static int dw_mci_get_dma_dir(struct mmc_data *data)
-{
- if (data->flags & MMC_DATA_WRITE)
- return DMA_TO_DEVICE;
- else
- return DMA_FROM_DEVICE;
-}
-
static void dw_mci_dma_cleanup(struct dw_mci *host)
{
struct mmc_data *data = host->data;
@@ -414,7 +406,7 @@ static void dw_mci_dma_cleanup(struct dw_mci *host)
dma_unmap_sg(host->dev,
data->sg,
data->sg_len,
- dw_mci_get_dma_dir(data));
+ mmc_get_dma_dir(data));
}
static void dw_mci_idmac_reset(struct dw_mci *host)
@@ -874,7 +866,7 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host,
sg_len = dma_map_sg(host->dev,
data->sg,
data->sg_len,
- dw_mci_get_dma_dir(data));
+ mmc_get_dma_dir(data));
if (sg_len == 0)
return -EINVAL;
@@ -885,8 +877,7 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host,
}
static void dw_mci_pre_req(struct mmc_host *mmc,
- struct mmc_request *mrq,
- bool is_first_req)
+ struct mmc_request *mrq)
{
struct dw_mci_slot *slot = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
@@ -917,7 +908,7 @@ static void dw_mci_post_req(struct mmc_host *mmc,
dma_unmap_sg(slot->host->dev,
data->sg,
data->sg_len,
- dw_mci_get_dma_dir(data));
+ mmc_get_dma_dir(data));
data->host_cookie = 0;
}
diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
index 1752007397f9..9bb5d9c8eace 100644
--- a/drivers/mmc/host/jz4740_mmc.c
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -200,11 +200,6 @@ free_master_write:
return -ENODEV;
}
-static inline int jz4740_mmc_get_dma_dir(struct mmc_data *data)
-{
- return (data->flags & MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-}
-
static inline struct dma_chan *jz4740_mmc_get_dma_chan(struct jz4740_mmc_host *host,
struct mmc_data *data)
{
@@ -215,7 +210,7 @@ static void jz4740_mmc_dma_unmap(struct jz4740_mmc_host *host,
struct mmc_data *data)
{
struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
- enum dma_data_direction dir = jz4740_mmc_get_dma_dir(data);
+ enum dma_data_direction dir = mmc_get_dma_dir(data);
dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
}
@@ -227,7 +222,7 @@ static int jz4740_mmc_prepare_dma_data(struct jz4740_mmc_host *host,
struct dma_chan *chan)
{
struct jz4740_mmc_host_next *next_data = &host->next_data;
- enum dma_data_direction dir = jz4740_mmc_get_dma_dir(data);
+ enum dma_data_direction dir = mmc_get_dma_dir(data);
int sg_len;
if (!next && data->host_cookie &&
@@ -320,8 +315,7 @@ dma_unmap:
}
static void jz4740_mmc_pre_request(struct mmc_host *mmc,
- struct mmc_request *mrq,
- bool is_first_req)
+ struct mmc_request *mrq)
{
struct jz4740_mmc_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index e77d79c8cd9f..476e53d30128 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -888,10 +888,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
u32 clock_rate;
unsigned long timeout;
- if (data->flags & MMC_DATA_READ)
- direction = DMA_FROM_DEVICE;
- else
- direction = DMA_TO_DEVICE;
+ direction = mmc_get_dma_dir(data);
mmc_spi_setup_data_message(host, multiple, direction);
t = &host->t;
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index df990bb8c873..fd0465533976 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -492,6 +492,7 @@ static void mmci_dma_data_error(struct mmci_host *host)
{
dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n");
dmaengine_terminate_all(host->dma_current);
+ host->dma_in_progress = false;
host->dma_current = NULL;
host->dma_desc_current = NULL;
host->data->host_cookie = 0;
@@ -500,17 +501,14 @@ static void mmci_dma_data_error(struct mmci_host *host)
static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
{
struct dma_chan *chan;
- enum dma_data_direction dir;
- if (data->flags & MMC_DATA_READ) {
- dir = DMA_FROM_DEVICE;
+ if (data->flags & MMC_DATA_READ)
chan = host->dma_rx_channel;
- } else {
- dir = DMA_TO_DEVICE;
+ else
chan = host->dma_tx_channel;
- }
- dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
+ dma_unmap_sg(chan->device->dev, data->sg, data->sg_len,
+ mmc_get_dma_dir(data));
}
static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data)
@@ -550,6 +548,7 @@ static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data)
mmci_dma_release(host);
}
+ host->dma_in_progress = false;
host->dma_current = NULL;
host->dma_desc_current = NULL;
}
@@ -572,17 +571,14 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
struct dma_chan *chan;
struct dma_device *device;
struct dma_async_tx_descriptor *desc;
- enum dma_data_direction buffer_dirn;
int nr_sg;
unsigned long flags = DMA_CTRL_ACK;
if (data->flags & MMC_DATA_READ) {
conf.direction = DMA_DEV_TO_MEM;
- buffer_dirn = DMA_FROM_DEVICE;
chan = host->dma_rx_channel;
} else {
conf.direction = DMA_MEM_TO_DEV;
- buffer_dirn = DMA_TO_DEVICE;
chan = host->dma_tx_channel;
}
@@ -595,7 +591,8 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
return -EINVAL;
device = chan->device;
- nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len, buffer_dirn);
+ nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len,
+ mmc_get_dma_dir(data));
if (nr_sg == 0)
return -EINVAL;
@@ -614,7 +611,8 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
return 0;
unmap_exit:
- dma_unmap_sg(device->dev, data->sg, data->sg_len, buffer_dirn);
+ dma_unmap_sg(device->dev, data->sg, data->sg_len,
+ mmc_get_dma_dir(data));
return -ENOMEM;
}
@@ -650,6 +648,7 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
dev_vdbg(mmc_dev(host->mmc),
"Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n",
data->sg_len, data->blksz, data->blocks, data->flags);
+ host->dma_in_progress = true;
dmaengine_submit(host->dma_desc_current);
dma_async_issue_pending(host->dma_current);
@@ -684,8 +683,7 @@ static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data)
next->dma_chan = NULL;
}
-static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq,
- bool is_first_req)
+static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct mmci_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
@@ -726,8 +724,10 @@ static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq,
if (host->dma_desc_current == next->dma_desc)
host->dma_desc_current = NULL;
- if (host->dma_current == next->dma_chan)
+ if (host->dma_current == next->dma_chan) {
+ host->dma_in_progress = false;
host->dma_current = NULL;
+ }
next->dma_desc = NULL;
next->dma_chan = NULL;
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index a1f5e4f49e2a..f914b69fba92 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -238,8 +238,9 @@ struct mmci_host {
struct dma_chan *dma_tx_channel;
struct dma_async_tx_descriptor *dma_desc_current;
struct mmci_host_next next_data;
+ bool dma_in_progress;
-#define dma_inprogress(host) ((host)->dma_current)
+#define dma_inprogress(host) ((host)->dma_in_progress)
#else
#define dma_inprogress(host) (0)
#endif
diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c
index bbad309679cf..d4dc55ac7dea 100644
--- a/drivers/mmc/host/moxart-mmc.c
+++ b/drivers/mmc/host/moxart-mmc.c
@@ -256,7 +256,7 @@ static void moxart_dma_complete(void *param)
static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host)
{
- u32 len, dir_data, dir_slave;
+ u32 len, dir_slave;
long dma_time;
struct dma_async_tx_descriptor *desc = NULL;
struct dma_chan *dma_chan;
@@ -266,16 +266,14 @@ static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host)
if (data->flags & MMC_DATA_WRITE) {
dma_chan = host->dma_chan_tx;
- dir_data = DMA_TO_DEVICE;
dir_slave = DMA_MEM_TO_DEV;
} else {
dma_chan = host->dma_chan_rx;
- dir_data = DMA_FROM_DEVICE;
dir_slave = DMA_DEV_TO_MEM;
}
len = dma_map_sg(dma_chan->device->dev, data->sg,
- data->sg_len, dir_data);
+ data->sg_len, mmc_get_dma_dir(data));
if (len > 0) {
desc = dmaengine_prep_slave_sg(dma_chan, data->sg,
@@ -301,7 +299,7 @@ static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host)
dma_unmap_sg(dma_chan->device->dev,
data->sg, data->sg_len,
- dir_data);
+ mmc_get_dma_dir(data));
}
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 6f9535e5e584..7360a7be1654 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -28,6 +28,7 @@
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/interrupt.h>
#include <linux/mmc/card.h>
#include <linux/mmc/core.h>
@@ -461,11 +462,9 @@ static void msdc_prepare_data(struct msdc_host *host, struct mmc_request *mrq)
struct mmc_data *data = mrq->data;
if (!(data->host_cookie & MSDC_PREPARE_FLAG)) {
- bool read = (data->flags & MMC_DATA_READ) != 0;
-
data->host_cookie |= MSDC_PREPARE_FLAG;
data->sg_count = dma_map_sg(host->dev, data->sg, data->sg_len,
- read ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ mmc_get_dma_dir(data));
}
}
@@ -477,10 +476,8 @@ static void msdc_unprepare_data(struct msdc_host *host, struct mmc_request *mrq)
return;
if (data->host_cookie & MSDC_PREPARE_FLAG) {
- bool read = (data->flags & MMC_DATA_READ) != 0;
-
dma_unmap_sg(host->dev, data->sg, data->sg_len,
- read ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ mmc_get_dma_dir(data));
data->host_cookie &= ~MSDC_PREPARE_FLAG;
}
}
@@ -927,8 +924,7 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq)
msdc_start_command(host, mrq, mrq->cmd);
}
-static void msdc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
- bool is_first_req)
+static void msdc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct msdc_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c
index 42296e55b9de..58d74b8d6c79 100644
--- a/drivers/mmc/host/mvsdio.c
+++ b/drivers/mmc/host/mvsdio.c
@@ -125,10 +125,10 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data)
return 1;
} else {
dma_addr_t phys_addr;
- int dma_dir = (data->flags & MMC_DATA_READ) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE;
- host->sg_frags = dma_map_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, dma_dir);
+
+ host->sg_frags = dma_map_sg(mmc_dev(host->mmc),
+ data->sg, data->sg_len,
+ mmc_get_dma_dir(data));
phys_addr = sg_dma_address(data->sg);
mvsd_write(MVSD_SYS_ADDR_LOW, (u32)phys_addr & 0xffff);
mvsd_write(MVSD_SYS_ADDR_HI, (u32)phys_addr >> 16);
@@ -294,8 +294,7 @@ static u32 mvsd_finish_data(struct mvsd_host *host, struct mmc_data *data,
host->pio_size = 0;
} else {
dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_frags,
- (data->flags & MMC_DATA_READ) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ mmc_get_dma_dir(data));
}
if (err_status & MVSD_ERR_DATA_TIMEOUT)
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index f7d1c8c4e5ad..37d3399a2290 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -935,15 +935,6 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
}
-static int
-omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data)
-{
- if (data->flags & MMC_DATA_WRITE)
- return DMA_TO_DEVICE;
- else
- return DMA_FROM_DEVICE;
-}
-
static struct dma_chan *omap_hsmmc_get_dma_chan(struct omap_hsmmc_host *host,
struct mmc_data *data)
{
@@ -1055,7 +1046,7 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
dmaengine_terminate_all(chan);
dma_unmap_sg(chan->device->dev,
host->data->sg, host->data->sg_len,
- omap_hsmmc_get_dma_dir(host, host->data));
+ mmc_get_dma_dir(host->data));
host->data->host_cookie = 0;
}
@@ -1350,7 +1341,7 @@ static void omap_hsmmc_dma_callback(void *param)
if (!data->host_cookie)
dma_unmap_sg(chan->device->dev,
data->sg, data->sg_len,
- omap_hsmmc_get_dma_dir(host, data));
+ mmc_get_dma_dir(data));
req_in_progress = host->req_in_progress;
host->dma_ch = -1;
@@ -1383,7 +1374,7 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
/* Check if next job is already prepared */
if (next || data->host_cookie != host->next_data.cookie) {
dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len,
- omap_hsmmc_get_dma_dir(host, data));
+ mmc_get_dma_dir(data));
} else {
dma_len = host->next_data.dma_len;
@@ -1560,13 +1551,12 @@ static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
struct dma_chan *c = omap_hsmmc_get_dma_chan(host, data);
dma_unmap_sg(c->device->dev, data->sg, data->sg_len,
- omap_hsmmc_get_dma_dir(host, data));
+ mmc_get_dma_dir(data));
data->host_cookie = 0;
}
}
-static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
- bool is_first_req)
+static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct omap_hsmmc_host *host = mmc_priv(mmc);
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index c763b404510f..59ab194cb009 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -702,7 +702,11 @@ static int pxamci_probe(struct platform_device *pdev)
pxamci_init_ocr(host);
- mmc->caps = 0;
+ /*
+ * This architecture used to disable bounce buffers through its
+ * defconfig, now it is done at runtime as a host property.
+ */
+ mmc->caps = MMC_CAP_NO_BOUNCE_BUFF;
host->cmdat = 0;
if (!cpu_is_pxa25x()) {
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index 3ccaa1415f33..41b57713b620 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -190,8 +190,7 @@ static int sd_pre_dma_transfer(struct realtek_pci_sdmmc *host,
return using_cookie;
}
-static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
- bool is_first_req)
+static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct realtek_pci_sdmmc *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
@@ -708,7 +707,7 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host,
u8 opcode, u8 sample_point)
{
int err;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
err = sd_change_phase(host, sample_point, true);
if (err < 0)
diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c
index 6e9c0f8fddb1..bbb959cb5612 100644
--- a/drivers/mmc/host/rtsx_usb_sdmmc.c
+++ b/drivers/mmc/host/rtsx_usb_sdmmc.c
@@ -682,7 +682,7 @@ static int sd_tuning_rx_cmd(struct rtsx_usb_sdmmc *host,
u8 opcode, u8 sample_point)
{
int err;
- struct mmc_command cmd = {0};
+ struct mmc_command cmd = {};
err = sd_change_phase(host, sample_point, 0);
if (err)
diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c
index 8f27fe35e8af..7e6f44b59b7f 100644
--- a/drivers/mmc/host/s3cmci.c
+++ b/drivers/mmc/host/s3cmci.c
@@ -1105,7 +1105,7 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)
conf.direction = DMA_MEM_TO_DEV;
dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ mmc_get_dma_dir(data));
dmaengine_slave_config(host->dma, &conf);
desc = dmaengine_prep_slave_sg(host->dma, data->sg, data->sg_len,
@@ -1122,7 +1122,7 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)
unmap_exit:
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ mmc_get_dma_dir(data));
return -ENOMEM;
}
diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index 80918abfc468..94fe5780cd00 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -523,8 +523,12 @@ static int sdhci_acpi_remove(struct platform_device *pdev)
static int sdhci_acpi_suspend(struct device *dev)
{
struct sdhci_acpi_host *c = dev_get_drvdata(dev);
+ struct sdhci_host *host = c->host;
- return sdhci_suspend_host(c->host);
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+
+ return sdhci_suspend_host(host);
}
static int sdhci_acpi_resume(struct device *dev)
@@ -543,8 +547,12 @@ static int sdhci_acpi_resume(struct device *dev)
static int sdhci_acpi_runtime_suspend(struct device *dev)
{
struct sdhci_acpi_host *c = dev_get_drvdata(dev);
+ struct sdhci_host *host = c->host;
+
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
- return sdhci_runtime_suspend_host(c->host);
+ return sdhci_runtime_suspend_host(host);
}
static int sdhci_acpi_runtime_resume(struct device *dev)
diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c
index 159f6f64c68e..242c5dc7a81e 100644
--- a/drivers/mmc/host/sdhci-brcmstb.c
+++ b/drivers/mmc/host/sdhci-brcmstb.c
@@ -29,6 +29,9 @@ static int sdhci_brcmstb_suspend(struct device *dev)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
int res;
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+
res = sdhci_suspend_host(host);
if (res)
return res;
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 445fc47dc3e7..9299bc91de97 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -11,12 +11,14 @@
* the Free Software Foundation; either version 2 of the License.
*/
+#include <linux/busfreq-imx.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/module.h>
+#include <linux/pm_qos.h>
#include <linux/slab.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
@@ -30,6 +32,7 @@
#include <linux/pm_runtime.h>
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
+#include "cqhci.h"
#define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f
#define ESDHC_CTRL_D3CD 0x08
@@ -49,6 +52,7 @@
#define ESDHC_MIX_CTRL_AUTO_TUNE_EN (1 << 24)
#define ESDHC_MIX_CTRL_FBCLK_SEL (1 << 25)
#define ESDHC_MIX_CTRL_HS400_EN (1 << 26)
+#define ESDHC_MIX_CTRL_HS400_ES (1 << 27)
/* Bits 3 and 6 are not SDHCI standard definitions */
#define ESDHC_MIX_CTRL_SDHCI_MASK 0xb7
/* Tuning bits */
@@ -69,12 +73,17 @@
#define ESDHC_STROBE_DLL_CTRL 0x70
#define ESDHC_STROBE_DLL_CTRL_ENABLE (1 << 0)
#define ESDHC_STROBE_DLL_CTRL_RESET (1 << 1)
+#define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT 0x7
#define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT 3
+#define ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT (4 << 20)
#define ESDHC_STROBE_DLL_STATUS 0x74
#define ESDHC_STROBE_DLL_STS_REF_LOCK (1 << 1)
#define ESDHC_STROBE_DLL_STS_SLV_LOCK 0x1
+#define ESDHC_VEND_SPEC2 0xc8
+#define ESDHC_VEND_SPEC2_EN_BUSY_IRQ (1 << 8)
+
#define ESDHC_TUNING_CTRL 0xcc
#define ESDHC_STD_TUNING_EN (1 << 24)
/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
@@ -102,6 +111,9 @@
*/
#define ESDHC_INT_VENDOR_SPEC_DMA_ERR (1 << 28)
+/* the address offset of CQHCI */
+#define ESDHC_CQHCI_ADDR_OFFSET 0x100
+
/*
* The CMDTYPE of the CMD register (offset 0xE) should be set to
* "11" when the STOP CMD12 is issued on imx53 to abort one
@@ -141,8 +153,37 @@
/* The IP supports HS400 mode */
#define ESDHC_FLAG_HS400 BIT(9)
-/* A higher clock ferquency than this rate requires strobell dll control */
-#define ESDHC_STROBE_DLL_CLK_FREQ 100000000
+/* The IP state got lost in low power mode */
+#define ESDHC_FLAG_STATE_LOST_IN_LPMODE BIT(10)
+
+/* The IP has errata ERR010450
+ * uSDHC: Due to the I/O timing limit, for SDR mode, SD card clock can't
+ * exceed 150MHz, for DDR mode, SD card clock can't exceed 45MHz.
+ */
+#define ESDHC_FLAG_ERR010450 BIT(11)
+/* need request bus freq during low power */
+#define ESDHC_FLAG_BUSFREQ BIT(12)
+/* need request pmqos during low power */
+#define ESDHC_FLAG_PMQOS BIT(13)
+/* The IP supports HS400ES mode */
+#define ESDHC_FLAG_HS400_ES BIT(14)
+/* The IP lost clock rate in PM_RUNTIME */
+#define ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME BIT(15)
+/* The IP has Host Controller Interface for Command Queuing */
+#define ESDHC_FLAG_CQHCI BIT(16)
+
+static struct mmc_host *wifi_mmc_host;
+void wifi_card_detect(bool on)
+{
+ WARN_ON(!wifi_mmc_host);
+ if (on) {
+ mmc_detect_change(wifi_mmc_host, 0);
+ } else {
+ if (wifi_mmc_host->card)
+ mmc_sdio_force_remove(wifi_mmc_host);
+ }
+}
+EXPORT_SYMBOL(wifi_card_detect);
struct esdhc_soc_data {
u32 flags;
@@ -171,18 +212,46 @@ static struct esdhc_soc_data usdhc_imx6q_data = {
static struct esdhc_soc_data usdhc_imx6sl_data = {
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_ERR004536
- | ESDHC_FLAG_HS200,
+ | ESDHC_FLAG_HS200 | ESDHC_FLAG_BUSFREQ,
};
static struct esdhc_soc_data usdhc_imx6sx_data = {
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
- | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200,
+ | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
+ | ESDHC_FLAG_STATE_LOST_IN_LPMODE
+ | ESDHC_FLAG_BUSFREQ,
+};
+
+static struct esdhc_soc_data usdhc_imx6ull_data = {
+ .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
+ | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
+ | ESDHC_FLAG_STATE_LOST_IN_LPMODE
+ | ESDHC_FLAG_ERR010450
+ | ESDHC_FLAG_BUSFREQ,
};
static struct esdhc_soc_data usdhc_imx7d_data = {
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
- | ESDHC_FLAG_HS400,
+ | ESDHC_FLAG_HS400 | ESDHC_FLAG_STATE_LOST_IN_LPMODE
+ | ESDHC_FLAG_BUSFREQ,
+};
+
+static struct esdhc_soc_data usdhc_imx7ulp_data = {
+ .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
+ | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
+ | ESDHC_FLAG_HS400
+ | ESDHC_FLAG_STATE_LOST_IN_LPMODE
+ | ESDHC_FLAG_PMQOS,
+};
+
+static struct esdhc_soc_data usdhc_imx8qm_data = {
+ .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
+ | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
+ | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
+ | ESDHC_FLAG_CQHCI
+ | ESDHC_FLAG_STATE_LOST_IN_LPMODE
+ | ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME,
};
struct pltfm_imx_data {
@@ -202,6 +271,7 @@ struct pltfm_imx_data {
WAIT_FOR_INT, /* sent CMD12, waiting for response INT */
} multiblock_status;
u32 is_ddr;
+ struct pm_qos_request pm_qos_req;
};
static const struct platform_device_id imx_esdhc_devtype[] = {
@@ -228,7 +298,10 @@ static const struct of_device_id imx_esdhc_dt_ids[] = {
{ .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data, },
{ .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, },
{ .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, },
+ { .compatible = "fsl,imx6ull-usdhc", .data = &usdhc_imx6ull_data, },
{ .compatible = "fsl,imx7d-usdhc", .data = &usdhc_imx7d_data, },
+ { .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, },
+ { .compatible = "fsl,imx8qm-usdhc", .data = &usdhc_imx8qm_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
@@ -609,6 +682,13 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
mask = 0xffff & ~(ESDHC_CTRL_BUSWIDTH_MASK | ESDHC_CTRL_D3CD);
esdhc_clrset_le(host, mask, new_val, reg);
+
+ /*
+ * The imx6q ROM code will change the default watermark
+ * level setting to something insane. Change it back here.
+ */
+ if (esdhc_is_usdhc(imx_data))
+ writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL);
return;
}
esdhc_clrset_le(host, 0xff, val, reg);
@@ -680,6 +760,13 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
| ESDHC_CLOCK_MASK);
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+ if (imx_data->socdata->flags & ESDHC_FLAG_ERR010450) {
+ if (imx_data->is_ddr)
+ clock = clock > 45000000 ? 45000000 : clock;
+ else
+ clock = clock > 150000000 ? 150000000 : clock;
+ }
+
while (host_clock / pre_div / 16 > clock && pre_div < 256)
pre_div *= 2;
@@ -813,6 +900,19 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
return ret;
}
+static void esdhc_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ u32 m;
+
+ m = readl(host->ioaddr + ESDHC_MIX_CTRL);
+ if (ios->enhanced_strobe)
+ m |= ESDHC_MIX_CTRL_HS400_ES;
+ else
+ m &= ~ESDHC_MIX_CTRL_HS400_ES;
+ writel(m, host->ioaddr + ESDHC_MIX_CTRL);
+}
+
static int esdhc_change_pinstate(struct sdhci_host *host,
unsigned int uhs)
{
@@ -853,39 +953,68 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
* CLK generated by host. Host receive the data which is aligned to the
* edge of data_strobe line. Due to the time delay between CLK line and
* data_strobe line, if the delay time is larger than one clock cycle,
- * then CLK and data_strobe line will misaligned, read error shows up.
- * So when the CLK is higher than 100MHz, each clock cycle is short enough,
- * host should config the delay target.
+ * then CLK and data_strobe line will be misaligned, read error shows up.
*/
static void esdhc_set_strobe_dll(struct sdhci_host *host)
{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
u32 v;
+ u32 strobe_delay;
- if (host->mmc->actual_clock > ESDHC_STROBE_DLL_CLK_FREQ) {
- /* disable clock before enabling strobe dll */
- writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) &
- ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
- host->ioaddr + ESDHC_VENDOR_SPEC);
+ /* disable clock before enabling strobe dll */
+ writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) &
+ ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
+ host->ioaddr + ESDHC_VENDOR_SPEC);
- /* force a reset on strobe dll */
- writel(ESDHC_STROBE_DLL_CTRL_RESET,
- host->ioaddr + ESDHC_STROBE_DLL_CTRL);
- /*
- * enable strobe dll ctrl and adjust the delay target
- * for the uSDHC loopback read clock
- */
- v = ESDHC_STROBE_DLL_CTRL_ENABLE |
- (7 << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT);
- writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL);
- /* wait 1us to make sure strobe dll status register stable */
- udelay(1);
- v = readl(host->ioaddr + ESDHC_STROBE_DLL_STATUS);
- if (!(v & ESDHC_STROBE_DLL_STS_REF_LOCK))
- dev_warn(mmc_dev(host->mmc),
- "warning! HS400 strobe DLL status REF not lock!\n");
- if (!(v & ESDHC_STROBE_DLL_STS_SLV_LOCK))
+ /* force a reset on strobe dll */
+ writel(ESDHC_STROBE_DLL_CTRL_RESET,
+ host->ioaddr + ESDHC_STROBE_DLL_CTRL);
+ /* clear the reset bit on strobe dll before any setting */
+ writel(0, host->ioaddr + ESDHC_STROBE_DLL_CTRL);
+
+ /*
+ * enable strobe dll ctrl and adjust the delay target
+ * for the uSDHC loopback read clock
+ */
+ if (imx_data->boarddata.strobe_dll_delay_target)
+ strobe_delay = imx_data->boarddata.strobe_dll_delay_target;
+ else
+ strobe_delay = ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT;
+ v = ESDHC_STROBE_DLL_CTRL_ENABLE |
+ ESDHC_STROBE_DLL_CTRL_SLV_UPDATE_INT_DEFAULT |
+ (strobe_delay << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT);
+ writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL);
+ /* wait 5us to make sure strobe dll status register stable */
+ udelay(5);
+ v = readl(host->ioaddr + ESDHC_STROBE_DLL_STATUS);
+ if (!(v & ESDHC_STROBE_DLL_STS_REF_LOCK))
+ dev_warn(mmc_dev(host->mmc),
+ "warning! HS400 strobe DLL status REF not lock!\n");
+ if (!(v & ESDHC_STROBE_DLL_STS_SLV_LOCK))
dev_warn(mmc_dev(host->mmc),
"warning! HS400 strobe DLL status SLV not lock!\n");
+}
+
+static void esdhc_reset_tuning(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
+ u16 ctrl;
+
+ /* Rest the tuning circurt */
+ if (esdhc_is_usdhc(imx_data)) {
+ if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
+ ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL);
+ ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
+ ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL;
+ writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL);
+ writel(0 << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
+ } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
+ ctrl = readl(host->ioaddr + SDHCI_ACMD12_ERR);
+ ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
+ writel(ctrl, host->ioaddr + SDHCI_ACMD12_ERR);
+ }
}
}
@@ -906,6 +1035,8 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
case MMC_TIMING_UHS_SDR25:
case MMC_TIMING_UHS_SDR50:
case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_SD_HS:
+ case MMC_TIMING_MMC_HS:
case MMC_TIMING_MMC_HS200:
writel(m, host->ioaddr + ESDHC_MIX_CTRL);
break;
@@ -932,6 +1063,9 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
host->ops->set_clock(host, host->clock);
esdhc_set_strobe_dll(host);
break;
+ case MMC_TIMING_LEGACY:
+ esdhc_reset_tuning(host);
+ break;
}
esdhc_change_pinstate(host, timing);
@@ -965,6 +1099,19 @@ static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
SDHCI_TIMEOUT_CONTROL);
}
+static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask)
+{
+ int cmd_error = 0;
+ int data_error = 0;
+
+ if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
+ return intmask;
+
+ cqhci_irq(host->mmc, intmask, cmd_error, data_error);
+
+ return 0;
+}
+
static struct sdhci_ops sdhci_esdhc_ops = {
.read_l = esdhc_readl_le,
.read_w = esdhc_readw_le,
@@ -981,6 +1128,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.set_bus_width = esdhc_pltfm_set_bus_width,
.set_uhs_signaling = esdhc_set_uhs_signaling,
.reset = esdhc_reset,
+ .irq = esdhc_cqhci_irq,
};
static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
@@ -1028,6 +1176,23 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
/* disable DLL_CTRL delay line settings */
writel(0x0, host->ioaddr + ESDHC_DLL_CTRL);
+ /*
+ * For the case of command with busy, if set the bit
+ * ESDHC_VEND_SPEC2_EN_BUSY_IRQ, USDHC will generate a
+ * transfer complete interrupt when busy is deasserted.
+ * When CQHCI use DCMD to send a CMD need R1b respons,
+ * CQHCI require to set ESDHC_VEND_SPEC2_EN_BUSY_IRQ,
+ * otherwise DCMD will always meet timeout waiting for
+ * hardware interrupt issue.
+ */
+ if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) {
+ tmp = readl(host->ioaddr + ESDHC_VEND_SPEC2);
+ tmp |= ESDHC_VEND_SPEC2_EN_BUSY_IRQ;
+ writel(tmp, host->ioaddr + ESDHC_VEND_SPEC2);
+
+ host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
+ }
+
if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
tmp = readl(host->ioaddr + ESDHC_TUNING_CTRL);
tmp |= ESDHC_STD_TUNING_EN |
@@ -1047,6 +1212,55 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
}
}
+static void esdhc_cqe_enable(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ u32 reg;
+ u16 mode;
+ int count = 10;
+
+ /*
+ * CQE gets stuck if it sees Buffer Read Enable bit set, which can be
+ * the case after tuning, so ensure the buffer is drained.
+ */
+ reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
+ while (reg & SDHCI_DATA_AVAILABLE) {
+ sdhci_readl(host, SDHCI_BUFFER);
+ reg = sdhci_readl(host, SDHCI_PRESENT_STATE);
+ if (count-- == 0) {
+ dev_warn(mmc_dev(host->mmc),
+ "CQE may get stuck because the Buffer Read Enable bit is set\n");
+ break;
+ }
+ mdelay(1);
+ }
+
+ /*
+ * Runtime resume will reset the entire host controller, which
+ * will also clear the DMAEN/BCEN of register ESDHC_MIX_CTRL.
+ * Here set DMAEN and BCEN when enable CMDQ.
+ */
+ mode = sdhci_readw(host, SDHCI_TRANSFER_MODE);
+ if (host->flags & SDHCI_REQ_USE_DMA)
+ mode |= SDHCI_TRNS_DMA;
+ if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE))
+ mode |= SDHCI_TRNS_BLK_CNT_EN;
+ sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
+
+ sdhci_cqe_enable(mmc);
+}
+
+static void esdhc_sdhci_dumpregs(struct mmc_host *mmc)
+{
+ sdhci_dumpregs(mmc_priv(mmc));
+}
+
+static const struct cqhci_host_ops esdhc_cqhci_ops = {
+ .enable = esdhc_cqe_enable,
+ .disable = sdhci_cqe_disable,
+ .dumpregs = esdhc_sdhci_dumpregs,
+};
+
#ifdef CONFIG_OF
static int
sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
@@ -1067,6 +1281,8 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step);
of_property_read_u32(np, "fsl,tuning-start-tap",
&boarddata->tuning_start_tap);
+ of_property_read_u32(np, "fsl,strobe-dll-delay-target",
+ &boarddata->strobe_dll_delay_target);
if (of_find_property(np, "no-1-8-v", NULL))
boarddata->support_vsel = false;
@@ -1106,6 +1322,12 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
if (mmc_gpio_get_cd(host->mmc) >= 0)
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+ if (of_get_property(np, "wifi-host", NULL)) {
+ wifi_mmc_host = host->mmc;
+ host->quirks2 |= SDHCI_QUIRK2_SDIO_IRQ_THREAD;
+ dev_info(mmc_dev(host->mmc), "assigned as wifi host\n");
+ }
+
return 0;
}
#else
@@ -1189,6 +1411,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
of_match_device(imx_esdhc_dt_ids, &pdev->dev);
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_host *host;
+ struct cqhci_host *cq_host;
int err;
struct pltfm_imx_data *imx_data;
@@ -1224,6 +1447,14 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
pltfm_host->clk = imx_data->clk_per;
pltfm_host->clock = clk_get_rate(pltfm_host->clk);
+
+ if (imx_data->socdata->flags & ESDHC_FLAG_BUSFREQ)
+ request_bus_freq(BUS_FREQ_HIGH);
+
+ if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
+ pm_qos_add_request(&imx_data->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, 0);
+
clk_prepare_enable(imx_data->clk_per);
clk_prepare_enable(imx_data->clk_ipg);
clk_prepare_enable(imx_data->clk_ahb);
@@ -1231,14 +1462,15 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
imx_data->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(imx_data->pinctrl)) {
err = PTR_ERR(imx_data->pinctrl);
- goto disable_clk;
+ dev_warn(mmc_dev(host->mmc), "could not get pinctrl\n");
+ imx_data->pins_default = ERR_PTR(-EINVAL);
+ } else {
+ imx_data->pins_default = pinctrl_lookup_state(imx_data->pinctrl,
+ PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(imx_data->pins_default))
+ dev_warn(mmc_dev(host->mmc), "could not get default state\n");
}
- imx_data->pins_default = pinctrl_lookup_state(imx_data->pinctrl,
- PINCTRL_STATE_DEFAULT);
- if (IS_ERR(imx_data->pins_default))
- dev_warn(mmc_dev(host->mmc), "could not get default state\n");
-
if (imx_data->socdata->flags & ESDHC_FLAG_ENGCM07207)
/* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK
@@ -1247,6 +1479,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
if (esdhc_is_usdhc(imx_data)) {
host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
host->mmc->caps |= MMC_CAP_1_8V_DDR;
+
if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200))
host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
@@ -1266,6 +1499,28 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
host->quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400;
+ if (imx_data->socdata->flags & ESDHC_FLAG_HS400_ES) {
+ host->mmc->caps2 |= MMC_CAP2_HS400_ES;
+ host->mmc_host_ops.hs400_enhanced_strobe =
+ esdhc_hs400_enhanced_strobe;
+ }
+
+ if (imx_data->socdata->flags & ESDHC_FLAG_CQHCI) {
+ host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
+ cq_host = devm_kzalloc(&pdev->dev, sizeof(*cq_host), GFP_KERNEL);
+ if (IS_ERR(cq_host)) {
+ err = PTR_ERR(cq_host);
+ goto disable_clk;
+ }
+
+ cq_host->mmio = host->ioaddr + ESDHC_CQHCI_ADDR_OFFSET;
+ cq_host->ops = &esdhc_cqhci_ops;
+
+ err = cqhci_init(cq_host, host->mmc, false);
+ if (err)
+ goto disable_clk;
+ }
+
if (of_id)
err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data);
else
@@ -1275,6 +1530,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
sdhci_esdhc_imx_hwinit(host);
+ device_set_wakeup_capable(&pdev->dev, 1);
+
err = sdhci_add_host(host);
if (err)
goto disable_clk;
@@ -1291,6 +1548,11 @@ disable_clk:
clk_disable_unprepare(imx_data->clk_per);
clk_disable_unprepare(imx_data->clk_ipg);
clk_disable_unprepare(imx_data->clk_ahb);
+ if (imx_data->socdata->flags & ESDHC_FLAG_BUSFREQ)
+ release_bus_freq(BUS_FREQ_HIGH);
+
+ if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
+ pm_qos_remove_request(&imx_data->pm_qos_req);
free_sdhci:
sdhci_pltfm_free(pdev);
return err;
@@ -1303,6 +1565,9 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+ if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
+ pm_qos_remove_request(&imx_data->pm_qos_req);
+
pm_runtime_get_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
@@ -1312,6 +1577,8 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
clk_disable_unprepare(imx_data->clk_per);
clk_disable_unprepare(imx_data->clk_ipg);
clk_disable_unprepare(imx_data->clk_ahb);
+ if (imx_data->socdata->flags & ESDHC_FLAG_BUSFREQ)
+ release_bus_freq(BUS_FREQ_HIGH);
sdhci_pltfm_free(pdev);
@@ -1322,18 +1589,75 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
static int sdhci_esdhc_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
+ int ret;
+
+ pm_runtime_get_sync(dev);
+
+ if (host->mmc->caps2 & MMC_CAP2_CQE) {
+ ret = cqhci_suspend(host->mmc);
+ if (ret)
+ return ret;
+ }
+
+ if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) &&
+ (host->tuning_mode != SDHCI_TUNING_MODE_1)) {
+ mmc_retune_timer_stop(host->mmc);
+ mmc_retune_needed(host->mmc);
+ }
+
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+
+ ret = sdhci_suspend_host(host);
+
+ pinctrl_pm_select_sleep_state(dev);
- return sdhci_suspend_host(host);
+ if (!sdhci_sdio_irq_enabled(host)) {
+ clk_disable_unprepare(imx_data->clk_per);
+ clk_disable_unprepare(imx_data->clk_ipg);
+ }
+ clk_disable_unprepare(imx_data->clk_ahb);
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+
+ return ret;
}
static int sdhci_esdhc_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
+ int ret;
+
+ if (!sdhci_sdio_irq_enabled(host)) {
+ clk_prepare_enable(imx_data->clk_per);
+ clk_prepare_enable(imx_data->clk_ipg);
+ }
+ clk_prepare_enable(imx_data->clk_ahb);
+
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ pinctrl_pm_select_default_state(dev);
/* re-initialize hw state in case it's lost in low power mode */
sdhci_esdhc_imx_hwinit(host);
- return sdhci_resume_host(host);
+ ret = sdhci_resume_host(host);
+ if (ret)
+ return ret;
+
+ if (host->mmc->caps2 & MMC_CAP2_CQE)
+ ret = cqhci_resume(host->mmc);
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return ret;
}
#endif
@@ -1345,14 +1669,29 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev)
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
int ret;
+ if (host->mmc->caps2 & MMC_CAP2_CQE) {
+ ret = cqhci_suspend(host->mmc);
+ if (ret)
+ return ret;
+ }
+
ret = sdhci_runtime_suspend_host(host);
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+
if (!sdhci_sdio_irq_enabled(host)) {
clk_disable_unprepare(imx_data->clk_per);
clk_disable_unprepare(imx_data->clk_ipg);
}
clk_disable_unprepare(imx_data->clk_ahb);
+ if (imx_data->socdata->flags & ESDHC_FLAG_BUSFREQ)
+ release_bus_freq(BUS_FREQ_HIGH);
+
+ if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
+ pm_qos_remove_request(&imx_data->pm_qos_req);
+
return ret;
}
@@ -1361,6 +1700,17 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
+ int ret;
+
+ if (imx_data->socdata->flags & ESDHC_FLAG_BUSFREQ)
+ request_bus_freq(BUS_FREQ_HIGH);
+
+ if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
+ pm_qos_add_request(&imx_data->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, 0);
+
+ if (imx_data->socdata->flags & ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME)
+ clk_set_rate(imx_data->clk_per, pltfm_host->clock);
if (!sdhci_sdio_irq_enabled(host)) {
clk_prepare_enable(imx_data->clk_per);
@@ -1368,7 +1718,14 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
}
clk_prepare_enable(imx_data->clk_ahb);
- return sdhci_runtime_resume_host(host);
+ ret = sdhci_runtime_resume_host(host);
+ if (ret)
+ return ret;
+
+ if (host->mmc->caps2 & MMC_CAP2_CQE)
+ ret = cqhci_resume(host->mmc);
+
+ return ret;
}
#endif
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index de132e281753..8cd8449c7bc5 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -24,30 +24,31 @@
SDHCI_QUIRK_PIO_NEEDS_DELAY | \
SDHCI_QUIRK_NO_HISPD_BIT)
-#define ESDHC_PROCTL 0x28
-
-#define ESDHC_SYSTEM_CONTROL 0x2c
-#define ESDHC_CLOCK_MASK 0x0000fff0
-#define ESDHC_PREDIV_SHIFT 8
-#define ESDHC_DIVIDER_SHIFT 4
-#define ESDHC_CLOCK_PEREN 0x00000004
-#define ESDHC_CLOCK_HCKEN 0x00000002
-#define ESDHC_CLOCK_IPGEN 0x00000001
-
/* pltfm-specific */
#define ESDHC_HOST_CONTROL_LE 0x20
/*
- * P2020 interpretation of the SDHCI_HOST_CONTROL register
+ * eSDHC register definition
*/
-#define ESDHC_CTRL_4BITBUS (0x1 << 1)
-#define ESDHC_CTRL_8BITBUS (0x2 << 1)
-#define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1)
-
-/* OF-specific */
-#define ESDHC_DMA_SYSCTL 0x40c
-#define ESDHC_DMA_SNOOP 0x00000040
-#define ESDHC_HOST_CONTROL_RES 0x01
+/* Protocol Control Register */
+#define ESDHC_PROCTL 0x28
+#define ESDHC_CTRL_4BITBUS (0x1 << 1)
+#define ESDHC_CTRL_8BITBUS (0x2 << 1)
+#define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1)
+#define ESDHC_HOST_CONTROL_RES 0x01
+
+/* System Control Register */
+#define ESDHC_SYSTEM_CONTROL 0x2c
+#define ESDHC_CLOCK_MASK 0x0000fff0
+#define ESDHC_PREDIV_SHIFT 8
+#define ESDHC_DIVIDER_SHIFT 4
+#define ESDHC_CLOCK_PEREN 0x00000004
+#define ESDHC_CLOCK_HCKEN 0x00000002
+#define ESDHC_CLOCK_IPGEN 0x00000001
+
+/* Control Register for DMA transfer */
+#define ESDHC_DMA_SYSCTL 0x40c
+#define ESDHC_DMA_SNOOP 0x00000040
#endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index 1cfd7f900339..ea6b36c88ae7 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -157,21 +157,6 @@ static int sdhci_arasan_syscon_write(struct sdhci_host *host,
return ret;
}
-static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
-{
- unsigned long freq;
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-
- /* SDHCI timeout clock is in kHz */
- freq = DIV_ROUND_UP(clk_get_rate(pltfm_host->clk), 1000);
-
- /* or in MHz */
- if (host->caps & SDHCI_TIMEOUT_CLK_UNIT)
- freq = DIV_ROUND_UP(freq, 1000);
-
- return freq;
-}
-
static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -194,9 +179,7 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
* through low speeds without power cycling.
*/
sdhci_set_clock(host, host->max_clk);
- spin_unlock_irq(&host->lock);
phy_power_on(sdhci_arasan->phy);
- spin_lock_irq(&host->lock);
sdhci_arasan->is_phy_on = true;
/*
@@ -215,18 +198,14 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
}
if (ctrl_phy && sdhci_arasan->is_phy_on) {
- spin_unlock_irq(&host->lock);
phy_power_off(sdhci_arasan->phy);
- spin_lock_irq(&host->lock);
sdhci_arasan->is_phy_on = false;
}
sdhci_set_clock(host, clock);
if (ctrl_phy) {
- spin_unlock_irq(&host->lock);
phy_power_on(sdhci_arasan->phy);
- spin_lock_irq(&host->lock);
sdhci_arasan->is_phy_on = true;
}
}
@@ -286,7 +265,7 @@ static int sdhci_arasan_voltage_switch(struct mmc_host *mmc,
static struct sdhci_ops sdhci_arasan_ops = {
.set_clock = sdhci_arasan_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
- .get_timeout_clock = sdhci_arasan_get_timeout_clock,
+ .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_arasan_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
@@ -315,6 +294,9 @@ static int sdhci_arasan_suspend(struct device *dev)
struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
int ret;
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+
ret = sdhci_suspend_host(host);
if (ret)
return ret;
diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c
index 83b84ffec27d..e4018f62ba7f 100644
--- a/drivers/mmc/host/sdhci-of-at91.c
+++ b/drivers/mmc/host/sdhci-of-at91.c
@@ -157,6 +157,9 @@ static int sdhci_at91_runtime_suspend(struct device *dev)
ret = sdhci_runtime_suspend_host(host);
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+
clk_disable_unprepare(priv->gck);
clk_disable_unprepare(priv->hclock);
clk_disable_unprepare(priv->mainck);
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index a51d636c2312..45066dbf257d 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -517,6 +517,9 @@ static int esdhc_of_suspend(struct device *dev)
esdhc_proctl = sdhci_readl(host, SDHCI_HOST_CONTROL);
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+
return sdhci_suspend_host(host);
}
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index cfb794766fea..5c9cd6041d01 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -35,10 +35,6 @@
static int sdhci_pci_enable_dma(struct sdhci_host *host);
static void sdhci_pci_set_bus_width(struct sdhci_host *host, int width);
static void sdhci_pci_hw_reset(struct sdhci_host *host);
-static int sdhci_pci_select_drive_strength(struct sdhci_host *host,
- struct mmc_card *card,
- unsigned int max_dtr, int host_drv,
- int card_drv, int *drv_type);
/*****************************************************************************\
* *
@@ -438,7 +434,6 @@ static const struct sdhci_ops sdhci_intel_byt_ops = {
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.hw_reset = sdhci_pci_hw_reset,
- .select_drive_strength = sdhci_pci_select_drive_strength,
};
static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
@@ -1451,20 +1446,6 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)
slot->hw_reset(host);
}
-static int sdhci_pci_select_drive_strength(struct sdhci_host *host,
- struct mmc_card *card,
- unsigned int max_dtr, int host_drv,
- int card_drv, int *drv_type)
-{
- struct sdhci_pci_slot *slot = sdhci_priv(host);
-
- if (!slot->select_drive_strength)
- return 0;
-
- return slot->select_drive_strength(host, card, max_dtr, host_drv,
- card_drv, drv_type);
-}
-
static const struct sdhci_ops sdhci_pci_ops = {
.set_clock = sdhci_set_clock,
.enable_dma = sdhci_pci_enable_dma,
@@ -1472,7 +1453,6 @@ static const struct sdhci_ops sdhci_pci_ops = {
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.hw_reset = sdhci_pci_hw_reset,
- .select_drive_strength = sdhci_pci_select_drive_strength,
};
/*****************************************************************************\
@@ -1487,6 +1467,7 @@ static int sdhci_pci_suspend(struct device *dev)
struct pci_dev *pdev = to_pci_dev(dev);
struct sdhci_pci_chip *chip;
struct sdhci_pci_slot *slot;
+ struct sdhci_host *host;
mmc_pm_flag_t slot_pm_flags;
mmc_pm_flag_t pm_flags = 0;
int i, ret;
@@ -1500,14 +1481,19 @@ static int sdhci_pci_suspend(struct device *dev)
if (!slot)
continue;
- ret = sdhci_suspend_host(slot->host);
+ host = slot->host;
+
+ if (chip->pm_retune && host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+
+ ret = sdhci_suspend_host(host);
if (ret)
goto err_pci_suspend;
- slot_pm_flags = slot->host->mmc->pm_flags;
+ slot_pm_flags = host->mmc->pm_flags;
if (slot_pm_flags & MMC_PM_WAKE_SDIO_IRQ)
- sdhci_enable_irq_wakeups(slot->host);
+ sdhci_enable_irq_wakeups(host);
pm_flags |= slot_pm_flags;
}
@@ -1571,6 +1557,7 @@ static int sdhci_pci_runtime_suspend(struct device *dev)
struct pci_dev *pdev = to_pci_dev(dev);
struct sdhci_pci_chip *chip;
struct sdhci_pci_slot *slot;
+ struct sdhci_host *host;
int i, ret;
chip = pci_get_drvdata(pdev);
@@ -1582,10 +1569,15 @@ static int sdhci_pci_runtime_suspend(struct device *dev)
if (!slot)
continue;
- ret = sdhci_runtime_suspend_host(slot->host);
+ host = slot->host;
+ ret = sdhci_runtime_suspend_host(host);
if (ret)
goto err_pci_runtime_suspend;
+
+ if (chip->rpm_retune &&
+ host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
}
if (chip->fixes && chip->fixes->suspend) {
@@ -1871,6 +1863,8 @@ static int sdhci_pci_probe(struct pci_dev *pdev,
chip->allow_runtime_pm = chip->fixes->allow_runtime_pm;
}
chip->num_slots = slots;
+ chip->pm_retune = true;
+ chip->rpm_retune = true;
pci_set_drvdata(pdev, chip);
diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h
index 6bccf56bc5ff..9eca92ddedec 100644
--- a/drivers/mmc/host/sdhci-pci.h
+++ b/drivers/mmc/host/sdhci-pci.h
@@ -83,10 +83,6 @@ struct sdhci_pci_slot {
bool cd_override_level;
void (*hw_reset)(struct sdhci_host *host);
- int (*select_drive_strength)(struct sdhci_host *host,
- struct mmc_card *card,
- unsigned int max_dtr, int host_drv,
- int card_drv, int *drv_type);
};
struct sdhci_pci_chip {
@@ -95,6 +91,8 @@ struct sdhci_pci_chip {
unsigned int quirks;
unsigned int quirks2;
bool allow_runtime_pm;
+ bool pm_retune;
+ bool rpm_retune;
const struct sdhci_pci_fixes *fixes;
int num_slots; /* Slots on controller */
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index ad49bfaf5bf8..2883e3e0eff8 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -2,7 +2,7 @@
* sdhci-pltfm.c Support for SDHCI platform devices
* Copyright (c) 2009 Intel Corporation
*
- * Copyright (c) 2007, 2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2007, 2011, 2015 Freescale Semiconductor, Inc.
* Copyright (c) 2009 MontaVista Software, Inc.
*
* Authors: Xiaobo Xie <X.Xie@freescale.com>
@@ -212,14 +212,23 @@ EXPORT_SYMBOL_GPL(sdhci_pltfm_unregister);
static int sdhci_pltfm_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
+ int ret;
- return sdhci_suspend_host(host);
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+
+ ret = sdhci_suspend_host(host);
+ pinctrl_pm_select_sleep_state(dev);
+
+ return ret;
}
static int sdhci_pltfm_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
+ pinctrl_pm_select_default_state(dev);
+
return sdhci_resume_host(host);
}
#endif
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index 3280f2077959..957839d0fe37 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -106,7 +106,7 @@ extern unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host);
static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
{
- return (void *)host->private;
+ return host->private;
}
extern const struct dev_pm_ops sdhci_pltfm_pmops;
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index d0f5c05fbc19..ce53b858bd31 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -323,11 +323,8 @@ static void pxav3_set_power(struct sdhci_host *host, unsigned char mode,
if (host->pwr == 0)
vdd = 0;
- if (!IS_ERR(mmc->supply.vmmc)) {
- spin_unlock_irq(&host->lock);
+ if (!IS_ERR(mmc->supply.vmmc))
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
- spin_lock_irq(&host->lock);
- }
}
static const struct sdhci_ops pxav3_sdhci_ops = {
@@ -529,6 +526,8 @@ static int sdhci_pxav3_suspend(struct device *dev)
struct sdhci_host *host = dev_get_drvdata(dev);
pm_runtime_get_sync(dev);
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
ret = sdhci_suspend_host(host);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
@@ -562,6 +561,9 @@ static int sdhci_pxav3_runtime_suspend(struct device *dev)
if (ret)
return ret;
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+
clk_disable_unprepare(pxa->clk_io);
if (!IS_ERR(pxa->clk_core))
clk_disable_unprepare(pxa->clk_core);
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 784c5a848fb4..623b0f71ab5e 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -318,9 +318,7 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
clk &= ~SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
- spin_unlock_irq(&host->lock);
ret = clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
- spin_lock_irq(&host->lock);
if (ret != 0) {
dev_err(dev, "%s: failed to set clock rate %uHz\n",
mmc_hostname(host->mmc), clock);
@@ -672,6 +670,9 @@ static int sdhci_s3c_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+
return sdhci_suspend_host(host);
}
@@ -693,6 +694,9 @@ static int sdhci_s3c_runtime_suspend(struct device *dev)
ret = sdhci_runtime_suspend_host(host);
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+
if (ourhost->cur_clk >= 0)
clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]);
clk_disable_unprepare(busclk);
diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c
index 5d068639dd3f..c251c6c0a112 100644
--- a/drivers/mmc/host/sdhci-sirf.c
+++ b/drivers/mmc/host/sdhci-sirf.c
@@ -237,6 +237,9 @@ static int sdhci_sirf_suspend(struct device *dev)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
int ret;
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+
ret = sdhci_suspend_host(host);
if (ret)
return ret;
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index 255a896769b8..8c0f88428556 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -165,6 +165,9 @@ static int sdhci_suspend(struct device *dev)
struct spear_sdhci *sdhci = sdhci_priv(host);
int ret;
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+
ret = sdhci_suspend_host(host);
if (!ret)
clk_disable(sdhci->clk);
diff --git a/drivers/mmc/host/sdhci-st.c b/drivers/mmc/host/sdhci-st.c
index ed92ce729dde..819626cd771b 100644
--- a/drivers/mmc/host/sdhci-st.c
+++ b/drivers/mmc/host/sdhci-st.c
@@ -465,8 +465,12 @@ static int sdhci_st_suspend(struct device *dev)
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);
- int ret = sdhci_suspend_host(host);
+ int ret;
+
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+ ret = sdhci_suspend_host(host);
if (ret)
goto out;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 6bf58d27b6fc..efe4c8ae9d61 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -14,6 +14,7 @@
*/
#include <linux/delay.h>
+#include <linux/ktime.h>
#include <linux/highmem.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -22,6 +23,7 @@
#include <linux/scatterlist.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
+#include <linux/of.h>
#include <linux/leds.h>
@@ -36,7 +38,10 @@
#define DRIVER_NAME "sdhci"
#define DBG(f, x...) \
- pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
+ pr_debug("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
+
+#define SDHCI_DUMP(f, x...) \
+ pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
#define MAX_TUNING_LOOP 40
@@ -47,61 +52,68 @@ static void sdhci_finish_data(struct sdhci_host *);
static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
-static void sdhci_dumpregs(struct sdhci_host *host)
-{
- pr_err(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
- mmc_hostname(host->mmc));
-
- pr_err(DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n",
- sdhci_readl(host, SDHCI_DMA_ADDRESS),
- sdhci_readw(host, SDHCI_HOST_VERSION));
- pr_err(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n",
- sdhci_readw(host, SDHCI_BLOCK_SIZE),
- sdhci_readw(host, SDHCI_BLOCK_COUNT));
- pr_err(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
- sdhci_readl(host, SDHCI_ARGUMENT),
- sdhci_readw(host, SDHCI_TRANSFER_MODE));
- pr_err(DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n",
- sdhci_readl(host, SDHCI_PRESENT_STATE),
- sdhci_readb(host, SDHCI_HOST_CONTROL));
- pr_err(DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n",
- sdhci_readb(host, SDHCI_POWER_CONTROL),
- sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL));
- pr_err(DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n",
- sdhci_readb(host, SDHCI_WAKE_UP_CONTROL),
- sdhci_readw(host, SDHCI_CLOCK_CONTROL));
- pr_err(DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n",
- sdhci_readb(host, SDHCI_TIMEOUT_CONTROL),
- sdhci_readl(host, SDHCI_INT_STATUS));
- pr_err(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
- sdhci_readl(host, SDHCI_INT_ENABLE),
- sdhci_readl(host, SDHCI_SIGNAL_ENABLE));
- pr_err(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
- sdhci_readw(host, SDHCI_ACMD12_ERR),
- sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
- pr_err(DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n",
- sdhci_readl(host, SDHCI_CAPABILITIES),
- sdhci_readl(host, SDHCI_CAPABILITIES_1));
- pr_err(DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n",
- sdhci_readw(host, SDHCI_COMMAND),
- sdhci_readl(host, SDHCI_MAX_CURRENT));
- pr_err(DRIVER_NAME ": Host ctl2: 0x%08x\n",
- sdhci_readw(host, SDHCI_HOST_CONTROL2));
+void sdhci_dumpregs(struct sdhci_host *host)
+{
+ SDHCI_DUMP("============ SDHCI REGISTER DUMP ===========\n");
+
+ SDHCI_DUMP("Sys addr: 0x%08x | Version: 0x%08x\n",
+ sdhci_readl(host, SDHCI_DMA_ADDRESS),
+ sdhci_readw(host, SDHCI_HOST_VERSION));
+ SDHCI_DUMP("Blk size: 0x%08x | Blk cnt: 0x%08x\n",
+ sdhci_readw(host, SDHCI_BLOCK_SIZE),
+ sdhci_readw(host, SDHCI_BLOCK_COUNT));
+ SDHCI_DUMP("Argument: 0x%08x | Trn mode: 0x%08x\n",
+ sdhci_readl(host, SDHCI_ARGUMENT),
+ sdhci_readw(host, SDHCI_TRANSFER_MODE));
+ SDHCI_DUMP("Present: 0x%08x | Host ctl: 0x%08x\n",
+ sdhci_readl(host, SDHCI_PRESENT_STATE),
+ sdhci_readb(host, SDHCI_HOST_CONTROL));
+ SDHCI_DUMP("Power: 0x%08x | Blk gap: 0x%08x\n",
+ sdhci_readb(host, SDHCI_POWER_CONTROL),
+ sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL));
+ SDHCI_DUMP("Wake-up: 0x%08x | Clock: 0x%08x\n",
+ sdhci_readb(host, SDHCI_WAKE_UP_CONTROL),
+ sdhci_readw(host, SDHCI_CLOCK_CONTROL));
+ SDHCI_DUMP("Timeout: 0x%08x | Int stat: 0x%08x\n",
+ sdhci_readb(host, SDHCI_TIMEOUT_CONTROL),
+ sdhci_readl(host, SDHCI_INT_STATUS));
+ SDHCI_DUMP("Int enab: 0x%08x | Sig enab: 0x%08x\n",
+ sdhci_readl(host, SDHCI_INT_ENABLE),
+ sdhci_readl(host, SDHCI_SIGNAL_ENABLE));
+ SDHCI_DUMP("AC12 err: 0x%08x | Slot int: 0x%08x\n",
+ sdhci_readw(host, SDHCI_ACMD12_ERR),
+ sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
+ SDHCI_DUMP("Caps: 0x%08x | Caps_1: 0x%08x\n",
+ sdhci_readl(host, SDHCI_CAPABILITIES),
+ sdhci_readl(host, SDHCI_CAPABILITIES_1));
+ SDHCI_DUMP("Cmd: 0x%08x | Max curr: 0x%08x\n",
+ sdhci_readw(host, SDHCI_COMMAND),
+ sdhci_readl(host, SDHCI_MAX_CURRENT));
+ SDHCI_DUMP("Resp[0]: 0x%08x | Resp[1]: 0x%08x\n",
+ sdhci_readl(host, SDHCI_RESPONSE),
+ sdhci_readl(host, SDHCI_RESPONSE + 4));
+ SDHCI_DUMP("Resp[2]: 0x%08x | Resp[3]: 0x%08x\n",
+ sdhci_readl(host, SDHCI_RESPONSE + 8),
+ sdhci_readl(host, SDHCI_RESPONSE + 12));
+ SDHCI_DUMP("Host ctl2: 0x%08x\n",
+ sdhci_readw(host, SDHCI_HOST_CONTROL2));
if (host->flags & SDHCI_USE_ADMA) {
- if (host->flags & SDHCI_USE_64_BIT_DMA)
- pr_err(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n",
- readl(host->ioaddr + SDHCI_ADMA_ERROR),
- readl(host->ioaddr + SDHCI_ADMA_ADDRESS_HI),
- readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
- else
- pr_err(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
- readl(host->ioaddr + SDHCI_ADMA_ERROR),
- readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
+ if (host->flags & SDHCI_USE_64_BIT_DMA) {
+ SDHCI_DUMP("ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n",
+ sdhci_readl(host, SDHCI_ADMA_ERROR),
+ sdhci_readl(host, SDHCI_ADMA_ADDRESS_HI),
+ sdhci_readl(host, SDHCI_ADMA_ADDRESS));
+ } else {
+ SDHCI_DUMP("ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
+ sdhci_readl(host, SDHCI_ADMA_ERROR),
+ sdhci_readl(host, SDHCI_ADMA_ADDRESS));
+ }
}
- pr_err(DRIVER_NAME ": ===========================================\n");
+ SDHCI_DUMP("============================================\n");
}
+EXPORT_SYMBOL_GPL(sdhci_dumpregs);
/*****************************************************************************\
* *
@@ -117,9 +129,10 @@ static inline bool sdhci_data_line_cmd(struct mmc_command *cmd)
static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
{
u32 present;
+ int gpio_cd = mmc_gpio_get_cd(host->mmc);
if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) ||
- !mmc_card_is_removable(host->mmc))
+ !mmc_card_is_removable(host->mmc) || (gpio_cd >= 0))
return;
if (enable) {
@@ -164,7 +177,7 @@ static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
void sdhci_reset(struct sdhci_host *host, u8 mask)
{
- unsigned long timeout;
+ ktime_t timeout;
sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
@@ -176,18 +189,17 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
}
/* Wait max 100 ms */
- timeout = 100;
+ timeout = ktime_add_ms(ktime_get(), 100);
/* hw clears the bit when it's done */
while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
- if (timeout == 0) {
+ if (ktime_after(ktime_get(), timeout)) {
pr_err("%s: Reset 0x%x never completed.\n",
mmc_hostname(host->mmc), (int)mask);
sdhci_dumpregs(host);
return;
}
- timeout--;
- mdelay(1);
+ udelay(10);
}
}
EXPORT_SYMBOL_GPL(sdhci_reset);
@@ -214,15 +226,8 @@ static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
}
}
-static void sdhci_init(struct sdhci_host *host, int soft)
+static void sdhci_set_default_irqs(struct sdhci_host *host)
{
- struct mmc_host *mmc = host->mmc;
-
- if (soft)
- sdhci_do_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
- else
- sdhci_do_reset(host, SDHCI_RESET_ALL);
-
host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT |
SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC |
@@ -235,6 +240,20 @@ static void sdhci_init(struct sdhci_host *host, int soft)
sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+}
+
+static void sdhci_init(struct sdhci_host *host, int soft)
+{
+ struct mmc_host *mmc = host->mmc;
+
+ if (soft)
+ sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+ else
+ sdhci_do_reset(host, SDHCI_RESET_ALL);
+
+ sdhci_set_default_irqs(host);
+
+ host->cqe_on = false;
if (soft) {
/* force clock reconfiguration */
@@ -484,8 +503,7 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host,
return data->sg_count;
sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- data->flags & MMC_DATA_WRITE ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ mmc_get_dma_dir(data));
if (sg_count == 0)
return -ENOSPC;
@@ -658,7 +676,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
{
u8 count;
- struct mmc_data *data = cmd->data;
+ struct mmc_data *data;
unsigned target_timeout, current_timeout;
/*
@@ -670,6 +688,12 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
return 0xE;
+ /* Unspecified command, assume max */
+ if (cmd == NULL)
+ return 0xE;
+
+ data = cmd->data;
+
/* Unspecified timeout, assume max */
if (!data && !cmd->busy_timeout)
return 0xE;
@@ -714,8 +738,8 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
}
if (count >= 0xF) {
- DBG("%s: Too large timeout 0x%x requested for CMD%d!\n",
- mmc_hostname(host->mmc), count, cmd->opcode);
+ DBG("Too large timeout 0x%x requested for CMD%d!\n",
+ count, cmd->opcode);
count = 0xE;
}
@@ -1343,42 +1367,47 @@ clock_set:
}
EXPORT_SYMBOL_GPL(sdhci_calc_clk);
-void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+void sdhci_enable_clk(struct sdhci_host *host, u16 clk)
{
- u16 clk;
- unsigned long timeout;
-
- host->mmc->actual_clock = 0;
-
- sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
-
- if (clock == 0)
- return;
-
- clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
+ ktime_t timeout;
clk |= SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
/* Wait max 20 ms */
- timeout = 20;
+ timeout = ktime_add_ms(ktime_get(), 20);
while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
& SDHCI_CLOCK_INT_STABLE)) {
- if (timeout == 0) {
+ if (ktime_after(ktime_get(), timeout)) {
pr_err("%s: Internal clock never stabilised.\n",
mmc_hostname(host->mmc));
sdhci_dumpregs(host);
return;
}
- timeout--;
spin_unlock_irq(&host->lock);
- usleep_range(900, 1100);
+ udelay(10);
spin_lock_irq(&host->lock);
}
clk |= SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
}
+EXPORT_SYMBOL_GPL(sdhci_enable_clk);
+
+void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ u16 clk;
+
+ host->mmc->actual_clock = 0;
+
+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+
+ if (clock == 0)
+ return;
+
+ clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock);
+ sdhci_enable_clk(host, clk);
+}
EXPORT_SYMBOL_GPL(sdhci_set_clock);
static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
@@ -1386,9 +1415,7 @@ static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
{
struct mmc_host *mmc = host->mmc;
- spin_unlock_irq(&host->lock);
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
- spin_lock_irq(&host->lock);
if (mode != MMC_POWER_OFF)
sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
@@ -1572,16 +1599,15 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
}
EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
-static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct sdhci_host *host = mmc_priv(mmc);
- unsigned long flags;
u8 ctrl;
- spin_lock_irqsave(&host->lock, flags);
+ if (ios->power_mode == MMC_POWER_UNDEFINED)
+ return;
if (host->flags & SDHCI_DEVICE_DEAD) {
- spin_unlock_irqrestore(&host->lock, flags);
if (!IS_ERR(mmc->supply.vmmc) &&
ios->power_mode == MMC_POWER_OFF)
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
@@ -1632,7 +1658,14 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
if ((ios->timing == MMC_TIMING_SD_HS ||
- ios->timing == MMC_TIMING_MMC_HS)
+ ios->timing == MMC_TIMING_MMC_HS ||
+ ios->timing == MMC_TIMING_MMC_HS400 ||
+ ios->timing == MMC_TIMING_MMC_HS200 ||
+ ios->timing == MMC_TIMING_MMC_DDR52 ||
+ ios->timing == MMC_TIMING_UHS_SDR50 ||
+ ios->timing == MMC_TIMING_UHS_SDR104 ||
+ ios->timing == MMC_TIMING_UHS_DDR50 ||
+ ios->timing == MMC_TIMING_UHS_SDR25)
&& !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT))
ctrl |= SDHCI_CTRL_HISPD;
else
@@ -1641,16 +1674,6 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (host->version >= SDHCI_SPEC_300) {
u16 clk, ctrl_2;
- /* In case of UHS-I modes, set High Speed Enable */
- if ((ios->timing == MMC_TIMING_MMC_HS400) ||
- (ios->timing == MMC_TIMING_MMC_HS200) ||
- (ios->timing == MMC_TIMING_MMC_DDR52) ||
- (ios->timing == MMC_TIMING_UHS_SDR50) ||
- (ios->timing == MMC_TIMING_UHS_SDR104) ||
- (ios->timing == MMC_TIMING_UHS_DDR50) ||
- (ios->timing == MMC_TIMING_UHS_SDR25))
- ctrl |= SDHCI_CTRL_HISPD;
-
if (!host->preset_enabled) {
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
/*
@@ -1730,8 +1753,8 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
}
+EXPORT_SYMBOL_GPL(sdhci_set_ios);
static int sdhci_get_cd(struct mmc_host *mmc)
{
@@ -1825,7 +1848,7 @@ static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
}
}
-static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
+void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
{
struct sdhci_host *host = mmc_priv(mmc);
unsigned long flags;
@@ -1845,9 +1868,10 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
if (!enable)
pm_runtime_put_noidle(host->mmc->parent);
}
+EXPORT_SYMBOL_GPL(sdhci_enable_sdio_irq);
-static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
- struct mmc_ios *ios)
+int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
+ struct mmc_ios *ios)
{
struct sdhci_host *host = mmc_priv(mmc);
u16 ctrl;
@@ -1939,6 +1963,7 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
return 0;
}
}
+EXPORT_SYMBOL_GPL(sdhci_start_signal_voltage_switch);
static int sdhci_card_busy(struct mmc_host *mmc)
{
@@ -1963,64 +1988,9 @@ static int sdhci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
return 0;
}
-static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+static void sdhci_start_tuning(struct sdhci_host *host)
{
- struct sdhci_host *host = mmc_priv(mmc);
u16 ctrl;
- int tuning_loop_counter = MAX_TUNING_LOOP;
- int err = 0;
- unsigned long flags;
- unsigned int tuning_count = 0;
- bool hs400_tuning;
-
- spin_lock_irqsave(&host->lock, flags);
-
- hs400_tuning = host->flags & SDHCI_HS400_TUNING;
- host->flags &= ~SDHCI_HS400_TUNING;
-
- if (host->tuning_mode == SDHCI_TUNING_MODE_1)
- tuning_count = host->tuning_count;
-
- /*
- * The Host Controller needs tuning in case of SDR104 and DDR50
- * mode, and for SDR50 mode when Use Tuning for SDR50 is set in
- * the Capabilities register.
- * If the Host Controller supports the HS200 mode then the
- * tuning function has to be executed.
- */
- switch (host->timing) {
- /* HS400 tuning is done in HS200 mode */
- case MMC_TIMING_MMC_HS400:
- err = -EINVAL;
- goto out_unlock;
-
- case MMC_TIMING_MMC_HS200:
- /*
- * Periodic re-tuning for HS400 is not expected to be needed, so
- * disable it here.
- */
- if (hs400_tuning)
- tuning_count = 0;
- break;
-
- case MMC_TIMING_UHS_SDR104:
- case MMC_TIMING_UHS_DDR50:
- break;
-
- case MMC_TIMING_UHS_SDR50:
- if (host->flags & SDHCI_SDR50_NEEDS_TUNING)
- break;
- /* FALLTHROUGH */
-
- default:
- goto out_unlock;
- }
-
- if (host->ops->platform_execute_tuning) {
- spin_unlock_irqrestore(&host->lock, flags);
- err = host->ops->platform_execute_tuning(host, opcode);
- return err;
- }
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
ctrl |= SDHCI_CTRL_EXEC_TUNING;
@@ -2040,151 +2010,217 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
*/
sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);
+}
+
+static void sdhci_end_tuning(struct sdhci_host *host)
+{
+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+}
+
+static void sdhci_reset_tuning(struct sdhci_host *host)
+{
+ u16 ctrl;
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ ctrl &= ~SDHCI_CTRL_TUNED_CLK;
+ ctrl &= ~SDHCI_CTRL_EXEC_TUNING;
+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+}
+
+static void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode)
+{
+ sdhci_reset_tuning(host);
+
+ sdhci_do_reset(host, SDHCI_RESET_CMD);
+ sdhci_do_reset(host, SDHCI_RESET_DATA);
+
+ sdhci_end_tuning(host);
+
+ mmc_abort_tuning(host->mmc, opcode);
+}
+
+/*
+ * We use sdhci_send_tuning() because mmc_send_tuning() is not a good fit. SDHCI
+ * tuning command does not have a data payload (or rather the hardware does it
+ * automatically) so mmc_send_tuning() will return -EIO. Also the tuning command
+ * interrupt setup is different to other commands and there is no timeout
+ * interrupt so special handling is needed.
+ */
+static void sdhci_send_tuning(struct sdhci_host *host, u32 opcode)
+{
+ struct mmc_host *mmc = host->mmc;
+ struct mmc_command cmd = {};
+ struct mmc_request mrq = {};
+ unsigned long flags;
+ u8 ctrl;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ cmd.opcode = opcode;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.mrq = &mrq;
+
+ mrq.cmd = &cmd;
/*
- * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
- * of loops reaches 40 times.
+ * In response to CMD19, the card sends 64 bytes of tuning
+ * block to the Host Controller. So we set the block size
+ * to 64 here.
*/
- do {
- struct mmc_command cmd = {0};
- struct mmc_request mrq = {NULL};
-
- cmd.opcode = opcode;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
- cmd.retries = 0;
- cmd.data = NULL;
- cmd.mrq = &mrq;
- cmd.error = 0;
-
- if (tuning_loop_counter-- == 0)
- break;
-
- mrq.cmd = &cmd;
+ if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200 &&
+ mmc->ios.bus_width == MMC_BUS_WIDTH_8)
+ sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128), SDHCI_BLOCK_SIZE);
+ else
+ sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE);
- /*
- * In response to CMD19, the card sends 64 bytes of tuning
- * block to the Host Controller. So we set the block size
- * to 64 here.
- */
- if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) {
- if (mmc->ios.bus_width == MMC_BUS_WIDTH_8)
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128),
- SDHCI_BLOCK_SIZE);
- else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4)
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
- SDHCI_BLOCK_SIZE);
- } else {
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
- SDHCI_BLOCK_SIZE);
- }
+ /*
+ * The tuning block is sent by the card to the host controller.
+ * So we set the TRNS_READ bit in the Transfer Mode register.
+ * This also takes care of setting DMA Enable and Multi Block
+ * Select in the same register to 0.
+ */
+ sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
- /*
- * The tuning block is sent by the card to the host controller.
- * So we set the TRNS_READ bit in the Transfer Mode register.
- * This also takes care of setting DMA Enable and Multi Block
- * Select in the same register to 0.
- */
- sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
+ /*
+ * DMA already disabled, so clear the DMA Select here.
+ * Otherwise, if use ADMA2, even disable DMA, some
+ * controllers like i.MX usdhc will still prefetch the
+ * ADMA script when send tuning command, which will cause
+ * IOMMU report lack of TLB mapping error
+ */
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+ ctrl &= ~SDHCI_CTRL_DMA_MASK;
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- sdhci_send_command(host, &cmd);
+ sdhci_send_command(host, &cmd);
- host->cmd = NULL;
- sdhci_del_timer(host, &mrq);
+ host->cmd = NULL;
- spin_unlock_irqrestore(&host->lock, flags);
- /* Wait for Buffer Read Ready interrupt */
- wait_event_timeout(host->buf_ready_int,
- (host->tuning_done == 1),
- msecs_to_jiffies(50));
- spin_lock_irqsave(&host->lock, flags);
+ sdhci_del_timer(host, &mrq);
- if (!host->tuning_done) {
- pr_info(DRIVER_NAME ": Timeout waiting for Buffer Read Ready interrupt during tuning procedure, falling back to fixed sampling clock\n");
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- ctrl &= ~SDHCI_CTRL_TUNED_CLK;
- ctrl &= ~SDHCI_CTRL_EXEC_TUNING;
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+ host->tuning_done = 0;
- sdhci_do_reset(host, SDHCI_RESET_CMD);
- sdhci_do_reset(host, SDHCI_RESET_DATA);
+ mmiowb();
+ spin_unlock_irqrestore(&host->lock, flags);
- err = -EIO;
+ /* Wait for Buffer Read Ready interrupt */
+ wait_event_timeout(host->buf_ready_int, (host->tuning_done == 1),
+ msecs_to_jiffies(50));
- if (cmd.opcode != MMC_SEND_TUNING_BLOCK_HS200)
- goto out;
+}
- sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+static void __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
+{
+ int i;
- spin_unlock_irqrestore(&host->lock, flags);
+ /*
+ * Issue opcode repeatedly till Execute Tuning is set to 0 or the number
+ * of loops reaches 40 times.
+ */
+ for (i = 0; i < MAX_TUNING_LOOP; i++) {
+ u16 ctrl;
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = MMC_STOP_TRANSMISSION;
- cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
- cmd.busy_timeout = 50;
- mmc_wait_for_cmd(mmc, &cmd, 0);
+ sdhci_send_tuning(host, opcode);
- spin_lock_irqsave(&host->lock, flags);
+ if (!host->tuning_done) {
+ pr_info("%s: Tuning timeout, falling back to fixed sampling clock\n",
+ mmc_hostname(host->mmc));
+ sdhci_abort_tuning(host, opcode);
+ return;
+ }
- goto out;
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (!(ctrl & SDHCI_CTRL_EXEC_TUNING)) {
+ if (ctrl & SDHCI_CTRL_TUNED_CLK) {
+ /*
+ * need to wait some time, make sure sd/mmc fininsh
+ * send out tuning data, otherwise, the sd/mmc can't
+ * response to any command when the card still out
+ * put the tuning data.
+ */
+ mdelay(1);
+ return; /* Success! */
+ }
+ break;
}
- host->tuning_done = 0;
+ mdelay(1);
+ }
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ pr_info("%s: Tuning failed, falling back to fixed sampling clock\n",
+ mmc_hostname(host->mmc));
+ sdhci_reset_tuning(host);
+}
- /* eMMC spec does not require a delay between tuning cycles */
- if (opcode == MMC_SEND_TUNING_BLOCK)
- mdelay(1);
- } while (ctrl & SDHCI_CTRL_EXEC_TUNING);
+int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ int err = 0;
+ unsigned int tuning_count = 0;
+ bool hs400_tuning;
+
+ hs400_tuning = host->flags & SDHCI_HS400_TUNING;
+
+ if (host->tuning_mode == SDHCI_TUNING_MODE_1)
+ tuning_count = host->tuning_count;
/*
- * The Host Driver has exhausted the maximum number of loops allowed,
- * so use fixed sampling frequency.
+ * The Host Controller needs tuning in case of SDR104 and DDR50
+ * mode, and for SDR50 mode when Use Tuning for SDR50 is set in
+ * the Capabilities register.
+ * If the Host Controller supports the HS200 mode then the
+ * tuning function has to be executed.
*/
- if (tuning_loop_counter < 0) {
- ctrl &= ~SDHCI_CTRL_TUNED_CLK;
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
- }
- if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
- pr_info(DRIVER_NAME ": Tuning procedure failed, falling back to fixed sampling clock\n");
- err = -EIO;
- }
+ switch (host->timing) {
+ /* HS400 tuning is done in HS200 mode */
+ case MMC_TIMING_MMC_HS400:
+ err = -EINVAL;
+ goto out;
-out:
- if (tuning_count) {
+ case MMC_TIMING_MMC_HS200:
/*
- * In case tuning fails, host controllers which support
- * re-tuning can try tuning again at a later time, when the
- * re-tuning timer expires. So for these controllers, we
- * return 0. Since there might be other controllers who do not
- * have this capability, we return error for them.
+ * Periodic re-tuning for HS400 is not expected to be needed, so
+ * disable it here.
*/
- err = 0;
+ if (hs400_tuning)
+ tuning_count = 0;
+ break;
+
+ case MMC_TIMING_UHS_SDR104:
+ break;
+
+ case MMC_TIMING_UHS_SDR50:
+ if (host->flags & SDHCI_SDR50_NEEDS_TUNING)
+ break;
+ /* FALLTHROUGH */
+
+ case MMC_TIMING_UHS_DDR50:
+ if (host->flags & SDHCI_DDR50_NEEDS_TUNING)
+ break;
+ /* FALLTHROUGH */
+
+ default:
+ goto out;
}
- host->mmc->retune_period = err ? 0 : tuning_count;
+ if (host->ops->platform_execute_tuning) {
+ err = host->ops->platform_execute_tuning(host, opcode);
+ goto out;
+ }
- sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
-out_unlock:
- spin_unlock_irqrestore(&host->lock, flags);
- return err;
-}
+ host->mmc->retune_period = tuning_count;
-static int sdhci_select_drive_strength(struct mmc_card *card,
- unsigned int max_dtr, int host_drv,
- int card_drv, int *drv_type)
-{
- struct sdhci_host *host = mmc_priv(card->host);
+ sdhci_start_tuning(host);
- if (!host->ops->select_drive_strength)
- return 0;
+ __sdhci_execute_tuning(host, opcode);
- return host->ops->select_drive_strength(host, card, max_dtr, host_drv,
- card_drv, drv_type);
+ sdhci_end_tuning(host);
+out:
+ host->flags &= ~SDHCI_HS400_TUNING;
+
+ return err;
}
+EXPORT_SYMBOL_GPL(sdhci_execute_tuning);
static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
{
@@ -2223,14 +2259,12 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
if (data->host_cookie != COOKIE_UNMAPPED)
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- data->flags & MMC_DATA_WRITE ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ mmc_get_dma_dir(data));
data->host_cookie = COOKIE_UNMAPPED;
}
-static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
- bool is_first_req)
+static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct sdhci_host *host = mmc_priv(mmc);
@@ -2300,7 +2334,6 @@ static const struct mmc_host_ops sdhci_ops = {
.start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
.prepare_hs400_tuning = sdhci_prepare_hs400_tuning,
.execute_tuning = sdhci_execute_tuning,
- .select_drive_strength = sdhci_select_drive_strength,
.card_event = sdhci_card_event,
.card_busy = sdhci_card_busy,
};
@@ -2342,8 +2375,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
if (data && data->host_cookie == COOKIE_MAPPED) {
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- (data->flags & MMC_DATA_READ) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ mmc_get_dma_dir(data));
data->host_cookie = COOKIE_UNMAPPED;
}
}
@@ -2508,7 +2540,6 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
#ifdef CONFIG_MMC_DEBUG
static void sdhci_adma_show_error(struct sdhci_host *host)
{
- const char *name = mmc_hostname(host->mmc);
void *desc = host->adma_table;
sdhci_dumpregs(host);
@@ -2517,14 +2548,14 @@ static void sdhci_adma_show_error(struct sdhci_host *host)
struct sdhci_adma2_64_desc *dma_desc = desc;
if (host->flags & SDHCI_USE_64_BIT_DMA)
- DBG("%s: %p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
- name, desc, le32_to_cpu(dma_desc->addr_hi),
+ DBG("%p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
+ desc, le32_to_cpu(dma_desc->addr_hi),
le32_to_cpu(dma_desc->addr_lo),
le16_to_cpu(dma_desc->len),
le16_to_cpu(dma_desc->cmd));
else
- DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
- name, desc, le32_to_cpu(dma_desc->addr_lo),
+ DBG("%p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
+ desc, le32_to_cpu(dma_desc->addr_lo),
le16_to_cpu(dma_desc->len),
le16_to_cpu(dma_desc->cmd));
@@ -2640,10 +2671,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
SDHCI_DEFAULT_BOUNDARY_SIZE;
host->data->bytes_xfered = dmanow - dmastart;
- DBG("%s: DMA base 0x%08x, transferred 0x%06x bytes,"
- " next 0x%08x\n",
- mmc_hostname(host->mmc), dmastart,
- host->data->bytes_xfered, dmanow);
+ DBG("DMA base 0x%08x, transferred 0x%06x bytes, next 0x%08x\n",
+ dmastart, host->data->bytes_xfered, dmanow);
sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
}
@@ -2668,6 +2697,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
struct sdhci_host *host = dev_id;
u32 intmask, mask, unexpected = 0;
int max_loops = 16;
+ int cardint = 0;
spin_lock(&host->lock);
@@ -2683,14 +2713,19 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
}
do {
+ DBG("IRQ status 0x%08x\n", intmask);
+
+ if (host->ops->irq) {
+ intmask = host->ops->irq(host, intmask);
+ if (!intmask)
+ goto cont;
+ }
+
/* Clear selected interrupts. */
mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
SDHCI_INT_BUS_POWER);
sdhci_writel(host, mask, SDHCI_INT_STATUS);
- DBG("*** %s got interrupt: 0x%08x\n",
- mmc_hostname(host->mmc), intmask);
-
if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
SDHCI_CARD_PRESENT;
@@ -2736,9 +2771,13 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
if ((intmask & SDHCI_INT_CARD_INT) &&
(host->ier & SDHCI_INT_CARD_INT)) {
- sdhci_enable_sdio_irq_nolock(host, false);
- host->thread_isr |= SDHCI_INT_CARD_INT;
- result = IRQ_WAKE_THREAD;
+ if (host->mmc->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD) {
+ sdhci_enable_sdio_irq_nolock(host, false);
+ host->thread_isr |= SDHCI_INT_CARD_INT;
+ result = IRQ_WAKE_THREAD;
+ } else {
+ cardint = 1;
+ }
}
intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
@@ -2750,7 +2789,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
unexpected |= intmask;
sdhci_writel(host, intmask, SDHCI_INT_STATUS);
}
-
+cont:
if (result == IRQ_NONE)
result = IRQ_HANDLED;
@@ -2765,6 +2804,9 @@ out:
sdhci_dumpregs(host);
}
+ if (cardint && host->mmc->sdio_irqs)
+ mmc_signal_sdio_irq(host->mmc);
+
return result;
}
@@ -2787,12 +2829,13 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
}
if (isr & SDHCI_INT_CARD_INT) {
- sdio_run_irqs(host->mmc);
-
- spin_lock_irqsave(&host->lock, flags);
- if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
- sdhci_enable_sdio_irq_nolock(host, true);
- spin_unlock_irqrestore(&host->lock, flags);
+ if (host->mmc->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD) {
+ sdio_run_irqs(host->mmc);
+ spin_lock_irqsave(&host->lock, flags);
+ if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
+ sdhci_enable_sdio_irq_nolock(host, true);
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
}
return isr ? IRQ_HANDLED : IRQ_NONE;
@@ -2815,6 +2858,7 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
*/
void sdhci_enable_irq_wakeups(struct sdhci_host *host)
{
+ int gpio_cd = mmc_gpio_get_cd(host->mmc);
u8 val;
u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE
| SDHCI_WAKE_ON_INT;
@@ -2824,7 +2868,8 @@ void sdhci_enable_irq_wakeups(struct sdhci_host *host)
val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL);
val |= mask ;
/* Avoid fake wake up */
- if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) {
+ if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION ||
+ (gpio_cd >= 0)) {
val &= ~(SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE);
irq_val &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
}
@@ -2849,14 +2894,12 @@ int sdhci_suspend_host(struct sdhci_host *host)
sdhci_disable_card_detection(host);
mmc_retune_timer_stop(host->mmc);
- if (host->tuning_mode != SDHCI_TUNING_MODE_3)
- mmc_retune_needed(host->mmc);
if (!device_may_wakeup(mmc_dev(host->mmc))) {
host->ier = 0;
sdhci_writel(host, 0, SDHCI_INT_ENABLE);
sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
- free_irq(host->irq, host);
+ disable_irq(host->irq);
} else {
sdhci_enable_irq_wakeups(host);
enable_irq_wake(host->irq);
@@ -2869,7 +2912,6 @@ EXPORT_SYMBOL_GPL(sdhci_suspend_host);
int sdhci_resume_host(struct sdhci_host *host)
{
struct mmc_host *mmc = host->mmc;
- int ret = 0;
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
if (host->ops->enable_dma)
@@ -2889,11 +2931,7 @@ int sdhci_resume_host(struct sdhci_host *host)
}
if (!device_may_wakeup(mmc_dev(host->mmc))) {
- ret = request_threaded_irq(host->irq, sdhci_irq,
- sdhci_thread_irq, IRQF_SHARED,
- mmc_hostname(host->mmc), host);
- if (ret)
- return ret;
+ enable_irq(host->irq);
} else {
sdhci_disable_irq_wakeups(host);
disable_irq_wake(host->irq);
@@ -2901,7 +2939,7 @@ int sdhci_resume_host(struct sdhci_host *host)
sdhci_enable_card_detection(host);
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(sdhci_resume_host);
@@ -2911,8 +2949,6 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
unsigned long flags;
mmc_retune_timer_stop(host->mmc);
- if (host->tuning_mode != SDHCI_TUNING_MODE_3)
- mmc_retune_needed(host->mmc);
spin_lock_irqsave(&host->lock, flags);
host->ier &= SDHCI_INT_CARD_INT;
@@ -2943,22 +2979,24 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
sdhci_init(host, 0);
- /* Force clock and power re-program */
- host->pwr = 0;
- host->clock = 0;
- mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
- mmc->ops->set_ios(mmc, &mmc->ios);
+ if (mmc->ios.power_mode != MMC_POWER_UNDEFINED) {
+ /* Force clock and power re-program */
+ host->pwr = 0;
+ host->clock = 0;
+ mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
+ mmc->ops->set_ios(mmc, &mmc->ios);
- if ((host_flags & SDHCI_PV_ENABLED) &&
- !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
- spin_lock_irqsave(&host->lock, flags);
- sdhci_enable_preset_value(host, true);
- spin_unlock_irqrestore(&host->lock, flags);
- }
+ if ((host_flags & SDHCI_PV_ENABLED) &&
+ !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
+ spin_lock_irqsave(&host->lock, flags);
+ sdhci_enable_preset_value(host, true);
+ spin_unlock_irqrestore(&host->lock, flags);
+ }
- if ((mmc->caps2 & MMC_CAP2_HS400_ES) &&
- mmc->ops->hs400_enhanced_strobe)
- mmc->ops->hs400_enhanced_strobe(mmc, &mmc->ios);
+ if ((mmc->caps2 & MMC_CAP2_HS400_ES) &&
+ mmc->ops->hs400_enhanced_strobe)
+ mmc->ops->hs400_enhanced_strobe(mmc, &mmc->ios);
+ }
spin_lock_irqsave(&host->lock, flags);
@@ -2981,6 +3019,119 @@ EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host);
/*****************************************************************************\
* *
+ * Command Queue Engine (CQE) helpers *
+ * *
+\*****************************************************************************/
+
+void sdhci_cqe_enable(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ unsigned long flags;
+ u8 ctrl;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+ ctrl &= ~SDHCI_CTRL_DMA_MASK;
+ if (host->flags & SDHCI_USE_64_BIT_DMA)
+ ctrl |= SDHCI_CTRL_ADMA64;
+ else
+ ctrl |= SDHCI_CTRL_ADMA32;
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+
+ sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, 512),
+ SDHCI_BLOCK_SIZE);
+
+ /* Set maximum timeout */
+ sdhci_set_timeout(host, NULL);
+
+ host->ier = host->cqe_ier;
+
+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+
+ host->cqe_on = true;
+
+ pr_debug("%s: sdhci: CQE on, IRQ mask %#x, IRQ status %#x\n",
+ mmc_hostname(mmc), host->ier,
+ sdhci_readl(host, SDHCI_INT_STATUS));
+
+ mmiowb();
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+EXPORT_SYMBOL_GPL(sdhci_cqe_enable);
+
+void sdhci_cqe_disable(struct mmc_host *mmc, bool recovery)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ sdhci_set_default_irqs(host);
+
+ host->cqe_on = false;
+
+ if (recovery) {
+ sdhci_do_reset(host, SDHCI_RESET_CMD);
+ sdhci_do_reset(host, SDHCI_RESET_DATA);
+ }
+
+ pr_debug("%s: sdhci: CQE off, IRQ mask %#x, IRQ status %#x\n",
+ mmc_hostname(mmc), host->ier,
+ sdhci_readl(host, SDHCI_INT_STATUS));
+
+ mmiowb();
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+EXPORT_SYMBOL_GPL(sdhci_cqe_disable);
+
+bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
+ int *data_error)
+{
+ u32 mask;
+
+ if (!host->cqe_on)
+ return false;
+
+ if (intmask & (SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC))
+ *cmd_error = -EILSEQ;
+ else if (intmask & SDHCI_INT_TIMEOUT)
+ *cmd_error = -ETIMEDOUT;
+ else
+ *cmd_error = 0;
+
+ if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC))
+ *data_error = -EILSEQ;
+ else if (intmask & SDHCI_INT_DATA_TIMEOUT)
+ *data_error = -ETIMEDOUT;
+ else if (intmask & SDHCI_INT_ADMA_ERROR)
+ *data_error = -EIO;
+ else
+ *data_error = 0;
+
+ /* Clear selected interrupts. */
+ mask = intmask & host->cqe_ier;
+ sdhci_writel(host, mask, SDHCI_INT_STATUS);
+
+ if (intmask & SDHCI_INT_BUS_POWER)
+ pr_err("%s: Card is consuming too much power!\n",
+ mmc_hostname(host->mmc));
+
+ intmask &= ~(host->cqe_ier | SDHCI_INT_ERROR);
+ if (intmask) {
+ sdhci_writel(host, intmask, SDHCI_INT_STATUS);
+ pr_err("%s: CQE: Unexpected interrupt 0x%08x.\n",
+ mmc_hostname(host->mmc), intmask);
+ sdhci_dumpregs(host);
+ }
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(sdhci_cqe_irq);
+
+/*****************************************************************************\
+ * *
* Device allocation/registration *
* *
\*****************************************************************************/
@@ -3004,6 +3155,9 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
host->flags = SDHCI_SIGNALING_330;
+ host->cqe_ier = SDHCI_CQE_INT_MASK;
+ host->cqe_err_ier = SDHCI_CQE_INT_ERR_MASK;
+
return host;
}
@@ -3042,6 +3196,8 @@ static int sdhci_set_dma_mask(struct sdhci_host *host)
void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps, u32 *caps1)
{
u16 v;
+ u64 dt_caps_mask = 0;
+ u64 dt_caps = 0;
if (host->read_caps)
return;
@@ -3056,24 +3212,42 @@ void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps, u32 *caps1)
sdhci_do_reset(host, SDHCI_RESET_ALL);
+ of_property_read_u64(mmc_dev(host->mmc)->of_node,
+ "sdhci-caps-mask", &dt_caps_mask);
+ of_property_read_u64(mmc_dev(host->mmc)->of_node,
+ "sdhci-caps", &dt_caps);
+
v = ver ? *ver : sdhci_readw(host, SDHCI_HOST_VERSION);
host->version = (v & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
if (host->quirks & SDHCI_QUIRK_MISSING_CAPS)
return;
- host->caps = caps ? *caps : sdhci_readl(host, SDHCI_CAPABILITIES);
+ if (caps) {
+ host->caps = *caps;
+ } else {
+ host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+ host->caps &= ~lower_32_bits(dt_caps_mask);
+ host->caps |= lower_32_bits(dt_caps);
+ }
if (host->version < SDHCI_SPEC_300)
return;
- host->caps1 = caps1 ? *caps1 : sdhci_readl(host, SDHCI_CAPABILITIES_1);
+ if (caps1) {
+ host->caps1 = *caps1;
+ } else {
+ host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
+ host->caps1 &= ~upper_32_bits(dt_caps_mask);
+ host->caps1 |= upper_32_bits(dt_caps);
+ }
}
EXPORT_SYMBOL_GPL(__sdhci_read_caps);
int sdhci_setup_host(struct sdhci_host *host)
{
struct mmc_host *mmc;
+ struct device *dev;
u32 max_current_caps;
unsigned int ocr_avail;
unsigned int override_timeout_clk;
@@ -3085,6 +3259,7 @@ int sdhci_setup_host(struct sdhci_host *host)
return -EINVAL;
mmc = host->mmc;
+ dev = mmc_dev(mmc);
/*
* If there are external regulators, get them. Note this must be done
@@ -3267,20 +3442,22 @@ int sdhci_setup_host(struct sdhci_host *host)
if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
host->timeout_clk = (host->caps & SDHCI_TIMEOUT_CLK_MASK) >>
SDHCI_TIMEOUT_CLK_SHIFT;
+
+ if (host->caps & SDHCI_TIMEOUT_CLK_UNIT)
+ host->timeout_clk *= 1000;
+
if (host->timeout_clk == 0) {
- if (host->ops->get_timeout_clock) {
- host->timeout_clk =
- host->ops->get_timeout_clock(host);
- } else {
+ if (!host->ops->get_timeout_clock) {
pr_err("%s: Hardware doesn't specify timeout clock frequency.\n",
mmc_hostname(mmc));
ret = -ENODEV;
goto undma;
}
- }
- if (host->caps & SDHCI_TIMEOUT_CLK_UNIT)
- host->timeout_clk *= 1000;
+ host->timeout_clk =
+ DIV_ROUND_UP(host->ops->get_timeout_clock(host),
+ 1000);
+ }
if (override_timeout_clk)
host->timeout_clk = override_timeout_clk;
@@ -3291,7 +3468,8 @@ int sdhci_setup_host(struct sdhci_host *host)
}
mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
- mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
+ if (!(host->quirks2 & SDHCI_QUIRK2_SDIO_IRQ_THREAD))
+ mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
host->flags |= SDHCI_AUTO_CMD12;
@@ -3302,9 +3480,9 @@ int sdhci_setup_host(struct sdhci_host *host)
!(host->flags & SDHCI_USE_SDMA)) &&
!(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) {
host->flags |= SDHCI_AUTO_CMD23;
- DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));
+ DBG("Auto-CMD23 available\n");
} else {
- DBG("%s: Auto-CMD23 unavailable\n", mmc_hostname(mmc));
+ DBG("Auto-CMD23 unavailable\n");
}
/*
@@ -3323,11 +3501,6 @@ int sdhci_setup_host(struct sdhci_host *host)
if (host->caps & SDHCI_CAN_DO_HISPD)
mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
- if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
- mmc_card_is_removable(mmc) &&
- mmc_gpio_get_cd(host->mmc) < 0)
- mmc->caps |= MMC_CAP_NEEDS_POLL;
-
if (!IS_ERR(mmc->supply.vqmmc)) {
ret = regulator_enable(mmc->supply.vqmmc);
@@ -3353,6 +3526,7 @@ int sdhci_setup_host(struct sdhci_host *host)
if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) {
host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
SDHCI_SUPPORT_DDR50);
+ mmc->caps2 |= MMC_CAP2_DDR52_3_3V;
}
/* Any UHS-I mode in caps implies SDR12 and SDR25 support. */
@@ -3492,10 +3666,11 @@ int sdhci_setup_host(struct sdhci_host *host)
goto unreg;
}
- if ((mmc->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+ if (((mmc->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR)) ||
- (mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V)))
+ (mmc->caps2 & (MMC_CAP2_HS200_1_8V_SDR | MMC_CAP2_HS400_1_8V))) &&
+ !(mmc->caps2 & MMC_CAP2_DDR52_3_3V))
host->flags |= SDHCI_SIGNALING_180;
if (mmc->caps2 & MMC_CAP2_HSX00_1_2V)
@@ -3527,10 +3702,20 @@ int sdhci_setup_host(struct sdhci_host *host)
* be larger than 64 KiB though.
*/
if (host->flags & SDHCI_USE_ADMA) {
- if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC)
+ if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC) {
mmc->max_seg_size = 65535;
- else
+
+ /*
+ * send the ADMA limitation to IOMMU. In default,
+ * the max segment size of IOMMU is 64KB, this exceed
+ * the ADMA max segment limitation, which is 65535.
+ */
+ dev->dma_parms = devm_kzalloc(dev,
+ sizeof(*dev->dma_parms), GFP_KERNEL);
+ dma_set_max_seg_size(dev, SZ_64K - 1);
+ } else {
mmc->max_seg_size = 65536;
+ }
} else {
mmc->max_seg_size = mmc->max_req_size;
}
@@ -3575,6 +3760,22 @@ undma:
}
EXPORT_SYMBOL_GPL(sdhci_setup_host);
+void sdhci_cleanup_host(struct sdhci_host *host)
+{
+ struct mmc_host *mmc = host->mmc;
+
+ if (!IS_ERR(mmc->supply.vqmmc))
+ regulator_disable(mmc->supply.vqmmc);
+
+ if (host->align_buffer)
+ dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
+ host->adma_table_sz, host->align_buffer,
+ host->align_addr);
+ host->adma_table = NULL;
+ host->align_buffer = NULL;
+}
+EXPORT_SYMBOL_GPL(sdhci_cleanup_host);
+
int __sdhci_add_host(struct sdhci_host *host)
{
struct mmc_host *mmc = host->mmc;
@@ -3639,16 +3840,6 @@ unirq:
untasklet:
tasklet_kill(&host->finish_tasklet);
- if (!IS_ERR(mmc->supply.vqmmc))
- regulator_disable(mmc->supply.vqmmc);
-
- if (host->align_buffer)
- dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
- host->adma_table_sz, host->align_buffer,
- host->align_addr);
- host->adma_table = NULL;
- host->align_buffer = NULL;
-
return ret;
}
EXPORT_SYMBOL_GPL(__sdhci_add_host);
@@ -3661,7 +3852,16 @@ int sdhci_add_host(struct sdhci_host *host)
if (ret)
return ret;
- return __sdhci_add_host(host);
+ ret = __sdhci_add_host(host);
+ if (ret)
+ goto cleanup;
+
+ return 0;
+
+cleanup:
+ sdhci_cleanup_host(host);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(sdhci_add_host);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 2570455b219a..8095203e6e59 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -17,6 +17,8 @@
#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/io.h>
+#include <linux/leds.h>
+#include <linux/interrupt.h>
#include <linux/mmc/host.h>
@@ -132,6 +134,7 @@
#define SDHCI_INT_CARD_REMOVE 0x00000080
#define SDHCI_INT_CARD_INT 0x00000100
#define SDHCI_INT_RETUNE 0x00001000
+#define SDHCI_INT_CQE 0x00004000
#define SDHCI_INT_ERROR 0x00008000
#define SDHCI_INT_TIMEOUT 0x00010000
#define SDHCI_INT_CRC 0x00020000
@@ -156,6 +159,13 @@
SDHCI_INT_BLK_GAP)
#define SDHCI_INT_ALL_MASK ((unsigned int)-1)
+#define SDHCI_CQE_INT_ERR_MASK ( \
+ SDHCI_INT_ADMA_ERROR | SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | \
+ SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | \
+ SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT)
+
+#define SDHCI_CQE_INT_MASK (SDHCI_CQE_INT_ERR_MASK | SDHCI_INT_CQE)
+
#define SDHCI_ACMD12_ERR 0x3C
#define SDHCI_HOST_CONTROL2 0x3E
@@ -425,6 +435,9 @@ struct sdhci_host {
#define SDHCI_QUIRK2_ACMD23_BROKEN (1<<14)
/* Broken Clock divider zero in controller */
#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15)
+/* Host or Card can't support no thread sdio irq */
+#define SDHCI_QUIRK2_SDIO_IRQ_THREAD (1<<16)
+
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
@@ -449,6 +462,7 @@ struct sdhci_host {
#define SDHCI_REQ_USE_DMA (1<<2) /* Use DMA for this req. */
#define SDHCI_DEVICE_DEAD (1<<3) /* Device unresponsive */
#define SDHCI_SDR50_NEEDS_TUNING (1<<4) /* SDR50 needs tuning */
+#define SDHCI_DDR50_NEEDS_TUNING (1<<5) /* DDR50 needs tuning */
#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */
#define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */
#define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */
@@ -516,6 +530,10 @@ struct sdhci_host {
/* cached registers */
u32 ier;
+ bool cqe_on; /* CQE is operating */
+ u32 cqe_ier; /* CQE interrupt mask */
+ u32 cqe_err_ier; /* CQE error interrupt mask */
+
wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */
unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */
@@ -542,9 +560,12 @@ struct sdhci_ops {
void (*set_power)(struct sdhci_host *host, unsigned char mode,
unsigned short vdd);
+ u32 (*irq)(struct sdhci_host *host, u32 intmask);
+
int (*enable_dma)(struct sdhci_host *host);
unsigned int (*get_max_clock)(struct sdhci_host *host);
unsigned int (*get_min_clock)(struct sdhci_host *host);
+ /* get_timeout_clock should return clk rate in unit of Hz */
unsigned int (*get_timeout_clock)(struct sdhci_host *host);
unsigned int (*get_max_timeout_count)(struct sdhci_host *host);
void (*set_timeout)(struct sdhci_host *host,
@@ -560,10 +581,6 @@ struct sdhci_ops {
void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
void (*card_event)(struct sdhci_host *host);
void (*voltage_switch)(struct sdhci_host *host);
- int (*select_drive_strength)(struct sdhci_host *host,
- struct mmc_card *card,
- unsigned int max_dtr, int host_drv,
- int card_drv, int *drv_type);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
@@ -650,24 +667,23 @@ static inline u8 sdhci_readb(struct sdhci_host *host, int reg)
#endif /* CONFIG_MMC_SDHCI_IO_ACCESSORS */
-extern struct sdhci_host *sdhci_alloc_host(struct device *dev,
- size_t priv_size);
-extern void sdhci_free_host(struct sdhci_host *host);
+struct sdhci_host *sdhci_alloc_host(struct device *dev, size_t priv_size);
+void sdhci_free_host(struct sdhci_host *host);
static inline void *sdhci_priv(struct sdhci_host *host)
{
- return (void *)host->private;
+ return host->private;
}
-extern void sdhci_card_detect(struct sdhci_host *host);
-extern void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps,
- u32 *caps1);
-extern int sdhci_setup_host(struct sdhci_host *host);
-extern int __sdhci_add_host(struct sdhci_host *host);
-extern int sdhci_add_host(struct sdhci_host *host);
-extern void sdhci_remove_host(struct sdhci_host *host, int dead);
-extern void sdhci_send_command(struct sdhci_host *host,
- struct mmc_command *cmd);
+void sdhci_card_detect(struct sdhci_host *host);
+void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps,
+ u32 *caps1);
+int sdhci_setup_host(struct sdhci_host *host);
+void sdhci_cleanup_host(struct sdhci_host *host);
+int __sdhci_add_host(struct sdhci_host *host);
+int sdhci_add_host(struct sdhci_host *host);
+void sdhci_remove_host(struct sdhci_host *host, int dead);
+void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
static inline void sdhci_read_caps(struct sdhci_host *host)
{
@@ -682,6 +698,7 @@ static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host)
u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
unsigned int *actual_clock);
void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
+void sdhci_enable_clk(struct sdhci_host *host, u16 clk);
void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
unsigned short vdd);
void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
@@ -689,13 +706,25 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
void sdhci_set_bus_width(struct sdhci_host *host, int width);
void sdhci_reset(struct sdhci_host *host, u8 mask);
void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
+int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
+void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
+int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
+ struct mmc_ios *ios);
+void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable);
#ifdef CONFIG_PM
-extern int sdhci_suspend_host(struct sdhci_host *host);
-extern int sdhci_resume_host(struct sdhci_host *host);
-extern void sdhci_enable_irq_wakeups(struct sdhci_host *host);
-extern int sdhci_runtime_suspend_host(struct sdhci_host *host);
-extern int sdhci_runtime_resume_host(struct sdhci_host *host);
+int sdhci_suspend_host(struct sdhci_host *host);
+int sdhci_resume_host(struct sdhci_host *host);
+void sdhci_enable_irq_wakeups(struct sdhci_host *host);
+int sdhci_runtime_suspend_host(struct sdhci_host *host);
+int sdhci_runtime_resume_host(struct sdhci_host *host);
#endif
+void sdhci_cqe_enable(struct mmc_host *mmc);
+void sdhci_cqe_disable(struct mmc_host *mmc, bool recovery);
+bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
+ int *data_error);
+
+void sdhci_dumpregs(struct sdhci_host *host);
+
#endif /* __SDHCI_HW_H */
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
index c0a5c676d0e8..9168012ff8ac 100644
--- a/drivers/mmc/host/sunxi-mmc.c
+++ b/drivers/mmc/host/sunxi-mmc.c
@@ -378,14 +378,6 @@ static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
wmb();
}
-static enum dma_data_direction sunxi_mmc_get_dma_dir(struct mmc_data *data)
-{
- if (data->flags & MMC_DATA_WRITE)
- return DMA_TO_DEVICE;
- else
- return DMA_FROM_DEVICE;
-}
-
static int sunxi_mmc_map_dma(struct sunxi_mmc_host *host,
struct mmc_data *data)
{
@@ -393,7 +385,7 @@ static int sunxi_mmc_map_dma(struct sunxi_mmc_host *host,
struct scatterlist *sg;
dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- sunxi_mmc_get_dma_dir(data));
+ mmc_get_dma_dir(data));
if (dma_len == 0) {
dev_err(mmc_dev(host->mmc), "dma_map_sg failed\n");
return -ENOMEM;
@@ -544,7 +536,7 @@ static irqreturn_t sunxi_mmc_finalize_request(struct sunxi_mmc_host *host)
rval |= SDXC_FIFO_RESET;
mmc_writel(host, REG_GCTRL, rval);
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- sunxi_mmc_get_dma_dir(data));
+ mmc_get_dma_dir(data));
}
mmc_writel(host, REG_RINTR, 0xffff);
@@ -998,7 +990,7 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
if (data)
dma_unmap_sg(mmc_dev(mmc), data->sg, data->sg_len,
- sunxi_mmc_get_dma_dir(data));
+ mmc_get_dma_dir(data));
dev_err(mmc_dev(mmc), "request already pending\n");
mrq->cmd->error = -EBUSY;
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 8e126afd988c..eb1deadf0c27 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -24,6 +24,7 @@
#include <linux/pagemap.h>
#include <linux/scatterlist.h>
#include <linux/spinlock.h>
+#include <linux/interrupt.h>
#define CTL_SD_CMD 0x00
#define CTL_ARG_REG 0x04
diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c
index 63fac78b3d46..6380044c0628 100644
--- a/drivers/mmc/host/via-sdmmc.c
+++ b/drivers/mmc/host/via-sdmmc.c
@@ -13,6 +13,7 @@
#include <linux/dma-mapping.h>
#include <linux/highmem.h>
#include <linux/delay.h>
+#include <linux/interrupt.h>
#include <linux/mmc/host.h>
diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c
index 5af00559e9d6..21ebba88679c 100644
--- a/drivers/mmc/host/wmt-sdmmc.c
+++ b/drivers/mmc/host/wmt-sdmmc.c
@@ -20,6 +20,7 @@
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/gpio.h>
+#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_address.h>
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 99bb9a1f6e16..f46b1ccff165 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -30,7 +30,7 @@ obj-$(CONFIG_MTD_SWAP) += mtdswap.o
nftl-objs := nftlcore.o nftlmount.o
inftl-objs := inftlcore.o inftlmount.o
+obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/
obj-y += chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/
-obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/
obj-$(CONFIG_MTD_UBI) += ubi/
diff --git a/drivers/mtd/nand/gpmi-nand/bch-regs.h b/drivers/mtd/nand/gpmi-nand/bch-regs.h
index 05bb91f2f4c4..bebe633d191c 100644
--- a/drivers/mtd/nand/gpmi-nand/bch-regs.h
+++ b/drivers/mtd/nand/gpmi-nand/bch-regs.h
@@ -1,7 +1,7 @@
/*
* Freescale GPMI NAND Flash Driver
*
- * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright 2008-2015 Freescale Semiconductor, Inc.
* Copyright 2008 Embedded Alley Solutions, Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -30,7 +30,13 @@
#define BM_BCH_CTRL_COMPLETE_IRQ (1 << 0)
#define HW_BCH_STATUS0 0x00000010
+
#define HW_BCH_MODE 0x00000020
+#define BP_BCH_MODE_ERASE_THRESHOLD 0
+#define BM_BCH_MODE_ERASE_THRESHOLD (0xff << BP_BCH_MODE_ERASE_THRESHOLD)
+#define BF_BCH_MODE_ERASE_THRESHOLD(v) \
+ (((v) << BP_BCH_MODE_ERASE_THRESHOLD) & BM_BCH_MODE_ERASE_THRESHOLD)
+
#define HW_BCH_ENCODEPTR 0x00000030
#define HW_BCH_DATAPTR 0x00000040
#define HW_BCH_METAPTR 0x00000050
@@ -54,7 +60,7 @@
#define MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0 11
#define MX6Q_BM_BCH_FLASH0LAYOUT0_ECC0 (0x1f << MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0)
#define BF_BCH_FLASH0LAYOUT0_ECC0(v, x) \
- (GPMI_IS_MX6(x) \
+ ((GPMI_IS_MX6(x) || GPMI_IS_MX7(x) || GPMI_IS_MX8(x)) \
? (((v) << MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0) \
& MX6Q_BM_BCH_FLASH0LAYOUT0_ECC0) \
: (((v) << BP_BCH_FLASH0LAYOUT0_ECC0) \
@@ -65,7 +71,7 @@
#define MX6Q_BM_BCH_FLASH0LAYOUT0_GF_13_14 \
(0x1 << MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14)
#define BF_BCH_FLASH0LAYOUT0_GF(v, x) \
- ((GPMI_IS_MX6(x) && ((v) == 14)) \
+ (((GPMI_IS_MX6(x) || GPMI_IS_MX7(x) || GPMI_IS_MX8(x)) && ((v) == 14))\
? (((1) << MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14) \
& MX6Q_BM_BCH_FLASH0LAYOUT0_GF_13_14) \
: 0 \
@@ -77,7 +83,7 @@
#define MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE \
(0x3ff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)
#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v, x) \
- (GPMI_IS_MX6(x) \
+ ((GPMI_IS_MX6(x) || GPMI_IS_MX7(x) || GPMI_IS_MX8(x)) \
? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) \
: ((v) & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) \
)
@@ -96,7 +102,7 @@
#define MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN 11
#define MX6Q_BM_BCH_FLASH0LAYOUT1_ECCN (0x1f << MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN)
#define BF_BCH_FLASH0LAYOUT1_ECCN(v, x) \
- (GPMI_IS_MX6(x) \
+ ((GPMI_IS_MX6(x) || GPMI_IS_MX7(x) || GPMI_IS_MX8(x)) \
? (((v) << MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN) \
& MX6Q_BM_BCH_FLASH0LAYOUT1_ECCN) \
: (((v) << BP_BCH_FLASH0LAYOUT1_ECCN) \
@@ -107,7 +113,7 @@
#define MX6Q_BM_BCH_FLASH0LAYOUT1_GF_13_14 \
(0x1 << MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14)
#define BF_BCH_FLASH0LAYOUT1_GF(v, x) \
- ((GPMI_IS_MX6(x) && ((v) == 14)) \
+ (((GPMI_IS_MX6(x) || GPMI_IS_MX7(x) || GPMI_IS_MX8(x)) && ((v) == 14))\
? (((1) << MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14) \
& MX6Q_BM_BCH_FLASH0LAYOUT1_GF_13_14) \
: 0 \
@@ -119,10 +125,14 @@
#define MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE \
(0x3ff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE)
#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v, x) \
- (GPMI_IS_MX6(x) \
+ ((GPMI_IS_MX6(x) || GPMI_IS_MX7(x) || GPMI_IS_MX8(x)) \
? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) \
: ((v) & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) \
)
#define HW_BCH_VERSION 0x00000160
+#define HW_BCH_DEBUG1 0x00000170
+#define BP_BCH_DEBUG1_ERASED_ZERO_COUNT 0
+#define BM_BCH_DEBUG1_ERASED_ZERO_COUNT \
+ (0x1ff << BP_BCH_DEBUG1_ERASED_ZERO_COUNT)
#endif
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
index 141bd70a49c2..b9843a6b6127 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c
@@ -1,8 +1,9 @@
/*
* Freescale GPMI NAND Flash Driver
*
- * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
* Copyright (C) 2008 Embedded Alley Solutions, Inc.
+ * Copyright (C) 2008-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,11 +22,17 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/debugfs.h>
+
#include "gpmi-nand.h"
#include "gpmi-regs.h"
#include "bch-regs.h"
+/* export the bch geometry to dbgfs */
+static struct debugfs_blob_wrapper dbg_bch_geo;
+
static struct timing_threshod timing_default_threshold = {
.max_data_setup_cycles = (BM_GPMI_TIMING0_DATA_SETUP >>
BP_GPMI_TIMING0_DATA_SETUP),
@@ -124,7 +131,7 @@ error:
return -ETIMEDOUT;
}
-static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v)
+int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v)
{
struct clk *clk;
int ret;
@@ -151,17 +158,17 @@ err_clk:
return ret;
}
-#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true)
-#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false)
-
int gpmi_init(struct gpmi_nand_data *this)
{
struct resources *r = &this->resources;
int ret;
- ret = gpmi_enable_clk(this);
- if (ret)
+ ret = pm_runtime_get_sync(this->dev);
+ if (ret < 0) {
+ dev_err(this->dev, "Failed to enable clock\n");
return ret;
+ }
+
ret = gpmi_reset_block(r->gpmi_regs, false);
if (ret)
goto err_out;
@@ -194,10 +201,10 @@ int gpmi_init(struct gpmi_nand_data *this)
*/
writel(BM_GPMI_CTRL1_DECOUPLE_CS, r->gpmi_regs + HW_GPMI_CTRL1_SET);
- gpmi_disable_clk(this);
- return 0;
err_out:
- gpmi_disable_clk(this);
+ pm_runtime_mark_last_busy(this->dev);
+ pm_runtime_put_autosuspend(this->dev);
+
return ret;
}
@@ -226,7 +233,8 @@ void gpmi_dump_info(struct gpmi_nand_data *this)
"ECC Strength : %u\n"
"Page Size in Bytes : %u\n"
"Metadata Size in Bytes : %u\n"
- "ECC Chunk Size in Bytes: %u\n"
+ "ECC Chunk0 Size in Bytes: %u\n"
+ "ECC Chunkn Size in Bytes: %u\n"
"ECC Chunk Count : %u\n"
"Payload Size in Bytes : %u\n"
"Auxiliary Size in Bytes: %u\n"
@@ -237,7 +245,8 @@ void gpmi_dump_info(struct gpmi_nand_data *this)
geo->ecc_strength,
geo->page_size,
geo->metadata_size,
- geo->ecc_chunk_size,
+ geo->ecc_chunk0_size,
+ geo->ecc_chunkn_size,
geo->ecc_chunk_count,
geo->payload_size,
geo->auxiliary_size,
@@ -246,13 +255,43 @@ void gpmi_dump_info(struct gpmi_nand_data *this)
geo->block_mark_bit_offset);
}
+int bch_create_debugfs(struct gpmi_nand_data *this)
+{
+ struct bch_geometry *bch_geo = &this->bch_geometry;
+ struct dentry *dbg_root;
+
+ dbg_root = debugfs_create_dir("gpmi-nand", NULL);
+ if (!dbg_root) {
+ dev_err(this->dev, "failed to create debug directory\n");
+ return -EINVAL;
+ }
+
+ dbg_bch_geo.data = (void *)bch_geo;
+ dbg_bch_geo.size = sizeof(struct bch_geometry);
+ if (!debugfs_create_blob("bch_geometry", S_IRUGO,
+ dbg_root, &dbg_bch_geo)) {
+ dev_err(this->dev, "failed to create debug bch geometry\n");
+ return -EINVAL;
+ }
+
+ /* create raw mode flag */
+ if (!debugfs_create_file("raw_mode", S_IRUGO,
+ dbg_root, NULL, NULL)) {
+ dev_err(this->dev, "failed to create raw mode flag\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/* Configures the geometry for BCH. */
int bch_set_geometry(struct gpmi_nand_data *this)
{
struct resources *r = &this->resources;
struct bch_geometry *bch_geo = &this->bch_geometry;
unsigned int block_count;
- unsigned int block_size;
+ unsigned int block0_size;
+ unsigned int blockn_size;
unsigned int metadata_size;
unsigned int ecc_strength;
unsigned int page_size;
@@ -263,15 +302,18 @@ int bch_set_geometry(struct gpmi_nand_data *this)
return !0;
block_count = bch_geo->ecc_chunk_count - 1;
- block_size = bch_geo->ecc_chunk_size;
+ block0_size = bch_geo->ecc_chunk0_size;
+ blockn_size = bch_geo->ecc_chunkn_size;
metadata_size = bch_geo->metadata_size;
ecc_strength = bch_geo->ecc_strength >> 1;
page_size = bch_geo->page_size;
gf_len = bch_geo->gf_len;
- ret = gpmi_enable_clk(this);
- if (ret)
+ ret = pm_runtime_get_sync(this->dev);
+ if (ret < 0) {
+ dev_err(this->dev, "Failed to enable clock\n");
return ret;
+ }
/*
* Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
@@ -290,15 +332,20 @@ int bch_set_geometry(struct gpmi_nand_data *this)
| BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size)
| BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this)
| BF_BCH_FLASH0LAYOUT0_GF(gf_len, this)
- | BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size, this),
+ | BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block0_size, this),
r->bch_regs + HW_BCH_FLASH0LAYOUT0);
writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size)
| BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this)
| BF_BCH_FLASH0LAYOUT1_GF(gf_len, this)
- | BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this),
+ | BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(blockn_size, this),
r->bch_regs + HW_BCH_FLASH0LAYOUT1);
+ /* Set erase threshold to ecc strength for mx6ul, mx6qp and mx7 */
+ if (GPMI_IS_MX6QP(this) || GPMI_IS_MX7(this) || GPMI_IS_MX6UL(this))
+ writel(BF_BCH_MODE_ERASE_THRESHOLD(ecc_strength),
+ r->bch_regs + HW_BCH_MODE);
+
/* Set *all* chip selects to use layout 0. */
writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT);
@@ -306,10 +353,10 @@ int bch_set_geometry(struct gpmi_nand_data *this)
writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
r->bch_regs + HW_BCH_CTRL_SET);
- gpmi_disable_clk(this);
- return 0;
err_out:
- gpmi_disable_clk(this);
+ pm_runtime_mark_last_busy(this->dev);
+ pm_runtime_put_autosuspend(this->dev);
+
return ret;
}
@@ -948,9 +995,14 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode)
nand->select_chip(mtd, -1);
+ pm_runtime_get_sync(this->dev);
+ clk_disable_unprepare(r->clock[0]);
/* [3] set the main IO clock, 100MHz for mode 5, 80MHz for mode 4. */
rate = (mode == 5) ? 100000000 : 80000000;
clk_set_rate(r->clock[0], rate);
+ clk_prepare_enable(r->clock[0]);
+ pm_runtime_mark_last_busy(this->dev);
+ pm_runtime_put_autosuspend(this->dev);
/* Let the gpmi_begin() re-compute the timing again. */
this->flags &= ~GPMI_TIMING_INIT_OK;
@@ -973,7 +1025,8 @@ int gpmi_extra_init(struct gpmi_nand_data *this)
struct nand_chip *chip = &this->nand;
/* Enable the asynchronous EDO feature. */
- if (GPMI_IS_MX6(this) && chip->onfi_version) {
+ if ((GPMI_IS_MX6(this) || GPMI_IS_MX7(this) || GPMI_IS_MX8(this))
+ && chip->onfi_version) {
int mode = onfi_get_async_timing_mode(chip);
/* We only support the timing mode 4 and mode 5. */
@@ -1001,9 +1054,9 @@ void gpmi_begin(struct gpmi_nand_data *this)
int ret;
/* Enable the clock. */
- ret = gpmi_enable_clk(this);
- if (ret) {
- dev_err(this->dev, "We failed in enable the clk\n");
+ ret = pm_runtime_get_sync(this->dev);
+ if (ret < 0) {
+ dev_err(this->dev, "Failed to enable clock\n");
goto err_out;
}
@@ -1075,7 +1128,8 @@ err_out:
void gpmi_end(struct gpmi_nand_data *this)
{
- gpmi_disable_clk(this);
+ pm_runtime_mark_last_busy(this->dev);
+ pm_runtime_put_autosuspend(this->dev);
}
/* Clears a BCH interrupt. */
@@ -1095,12 +1149,13 @@ int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip)
if (GPMI_IS_MX23(this)) {
mask = MX23_BM_GPMI_DEBUG_READY0 << chip;
reg = readl(r->gpmi_regs + HW_GPMI_DEBUG);
- } else if (GPMI_IS_MX28(this) || GPMI_IS_MX6(this)) {
+ } else if (GPMI_IS_MX28(this) || GPMI_IS_MX6(this) ||
+ GPMI_IS_MX7(this) || GPMI_IS_MX8(this)) {
/*
* In the imx6, all the ready/busy pins are bound
* together. So we only need to check chip 0.
*/
- if (GPMI_IS_MX6(this))
+ if (GPMI_IS_MX6(this) || GPMI_IS_MX7(this) || GPMI_IS_MX8(this))
chip = 0;
/* MX28 shares the same R/B register as MX6Q. */
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index d9dab4275859..9446a1f9a539 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -1,7 +1,7 @@
/*
* Freescale GPMI NAND Flash Driver
*
- * Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
+ * Copyright (C) 2010-2016 Freescale Semiconductor, Inc.
* Copyright (C) 2008 Embedded Alley Solutions, Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,8 @@
#include <linux/mtd/partitions.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/busfreq-imx.h>
+#include <linux/pm_runtime.h>
#include "gpmi-nand.h"
#include "bch-regs.h"
@@ -33,6 +35,8 @@
#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "bch"
#define GPMI_NAND_BCH_INTERRUPT_RES_NAME "bch"
+#define GPMI_RPM_TIMEOUT 50 /* ms */
+
/* add our owner bbt descriptor */
static uint8_t scan_ff_pattern[] = { 0xff };
static struct nand_bbt_descr gpmi_bbt_descr = {
@@ -104,12 +108,42 @@ static const struct gpmi_devdata gpmi_devdata_imx6q = {
.max_chain_delay = 12,
};
+static const struct gpmi_devdata gpmi_devdata_imx6qp = {
+ .type = IS_MX6QP,
+ .bch_max_ecc_strength = 40,
+ .max_chain_delay = 12,
+};
+
static const struct gpmi_devdata gpmi_devdata_imx6sx = {
.type = IS_MX6SX,
.bch_max_ecc_strength = 62,
.max_chain_delay = 12,
};
+static const struct gpmi_devdata gpmi_devdata_imx7d = {
+ .type = IS_MX7D,
+ .bch_max_ecc_strength = 62,
+ .max_chain_delay = 12,
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx6ul = {
+ .type = IS_MX6UL,
+ .bch_max_ecc_strength = 40,
+ .max_chain_delay = 12,
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx6ull = {
+ .type = IS_MX6ULL,
+ .bch_max_ecc_strength = 40,
+ .max_chain_delay = 12,
+};
+
+static const struct gpmi_devdata gpmi_devdata_imx8qxp = {
+ .type = IS_MX8QXP,
+ .bch_max_ecc_strength = 62,
+ .max_chain_delay = 12,
+};
+
static irqreturn_t bch_irq(int irq, void *cookie)
{
struct gpmi_nand_data *this = cookie;
@@ -163,6 +197,36 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
return geo->ecc_strength <= this->devdata->bch_max_ecc_strength;
}
+static inline bool bbm_in_data_chunk(struct gpmi_nand_data *this,
+ unsigned int *chunk_num)
+{
+ struct bch_geometry *geo = &this->bch_geometry;
+ struct mtd_info *mtd = &this->nand.mtd;
+ unsigned int i, j;
+
+ if (geo->ecc_chunk0_size != geo->ecc_chunkn_size) {
+ dev_err(this->dev, "The size of chunk0 must equal to chunkn\n");
+ return false;
+ }
+
+ i = (mtd->writesize * 8 - geo->metadata_size * 8) /
+ (geo->gf_len * geo->ecc_strength +
+ geo->ecc_chunkn_size * 8);
+
+ j = (mtd->writesize * 8 - geo->metadata_size * 8) -
+ (geo->gf_len * geo->ecc_strength +
+ geo->ecc_chunkn_size * 8) * i;
+
+ if (j < geo->ecc_chunkn_size * 8) {
+ *chunk_num = i+1;
+ dev_dbg(this->dev, "Set ecc to %d and bbm in chunk %d\n",
+ geo->ecc_strength, *chunk_num);
+ return true;
+ }
+
+ return false;
+}
+
/*
* If we can get the ECC information from the nand chip, we do not
* need to calculate them ourselves.
@@ -192,13 +256,14 @@ static int set_geometry_by_ecc_info(struct gpmi_nand_data *this)
chip->ecc_strength_ds, chip->ecc_step_ds);
return -EINVAL;
}
- geo->ecc_chunk_size = chip->ecc_step_ds;
+ geo->ecc_chunk0_size = chip->ecc_step_ds;
+ geo->ecc_chunkn_size = chip->ecc_step_ds;
geo->ecc_strength = round_up(chip->ecc_strength_ds, 2);
if (!gpmi_check_ecc(this))
return -EINVAL;
/* Keep the C >= O */
- if (geo->ecc_chunk_size < mtd->oobsize) {
+ if (geo->ecc_chunkn_size < mtd->oobsize) {
dev_err(this->dev,
"unsupported nand chip. ecc size: %d, oob size : %d\n",
chip->ecc_step_ds, mtd->oobsize);
@@ -208,7 +273,7 @@ static int set_geometry_by_ecc_info(struct gpmi_nand_data *this)
/* The default value, see comment in the legacy_set_geometry(). */
geo->metadata_size = 10;
- geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
+ geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunkn_size;
/*
* Now, the NAND chip with 2K page(data chunk is 512byte) shows below:
@@ -280,6 +345,132 @@ static int set_geometry_by_ecc_info(struct gpmi_nand_data *this)
return 0;
}
+static int set_geometry_for_large_oob(struct gpmi_nand_data *this)
+{
+ struct bch_geometry *geo = &this->bch_geometry;
+ struct mtd_info *mtd = &this->nand.mtd;
+ struct nand_chip *chip = mtd_to_nand(mtd);
+ unsigned int block_mark_bit_offset;
+ unsigned int max_ecc;
+ unsigned int bbm_chunk;
+ unsigned int i;
+
+
+ /* sanity check for the minimum ecc nand required */
+ if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
+ return -EINVAL;
+ geo->ecc_strength = chip->ecc_strength_ds;
+
+ /* check if platform can support this nand */
+ if (!gpmi_check_ecc(this)) {
+ dev_err(this->dev,
+ "unsupported NAND chip,\
+ minimum ecc required %d\n"
+ , geo->ecc_strength);
+ return -EINVAL;
+ }
+
+ /* calculate the maximum ecc platform can support*/
+ geo->metadata_size = 10;
+ geo->gf_len = 14;
+ geo->ecc_chunk0_size = 1024;
+ geo->ecc_chunkn_size = 1024;
+ geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunkn_size;
+ max_ecc = min(get_ecc_strength(this),
+ this->devdata->bch_max_ecc_strength);
+
+ /* search a supported ecc strength that makes bbm */
+ /* located in data chunk */
+ geo->ecc_strength = chip->ecc_strength_ds;
+ while (!(geo->ecc_strength > max_ecc)) {
+ if (bbm_in_data_chunk(this, &bbm_chunk))
+ goto geo_setting;
+ geo->ecc_strength += 2;
+ }
+
+ /* if none of them works, keep using the minimum ecc */
+ /* nand required but changing ecc page layout */
+ geo->ecc_strength = chip->ecc_strength_ds;
+ /* add extra ecc for meta data */
+ geo->ecc_chunk0_size = 0;
+ geo->ecc_chunk_count = (mtd->writesize / geo->ecc_chunkn_size) + 1;
+ geo->ecc_for_meta = 1;
+ /* check if oob can afford this extra ecc chunk */
+ if (mtd->oobsize * 8 < geo->metadata_size * 8 +
+ geo->gf_len * geo->ecc_strength
+ * geo->ecc_chunk_count) {
+ dev_err(this->dev, "unsupported NAND chip with new layout\n");
+ return -EINVAL;
+ }
+
+ /* calculate in which chunk bbm located */
+ bbm_chunk = (mtd->writesize * 8 - geo->metadata_size * 8 -
+ geo->gf_len * geo->ecc_strength) /
+ (geo->gf_len * geo->ecc_strength +
+ geo->ecc_chunkn_size * 8) + 1;
+
+geo_setting:
+
+ geo->page_size = mtd->writesize + geo->metadata_size +
+ (geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
+ geo->payload_size = mtd->writesize;
+
+ /*
+ * The auxiliary buffer contains the metadata and the ECC status. The
+ * metadata is padded to the nearest 32-bit boundary. The ECC status
+ * contains one byte for every ECC chunk, and is also padded to the
+ * nearest 32-bit boundary.
+ */
+ geo->auxiliary_status_offset = ALIGN(geo->metadata_size, 4);
+ geo->auxiliary_size = ALIGN(geo->metadata_size, 4)
+ + ALIGN(geo->ecc_chunk_count, 4);
+
+ if (!this->swap_block_mark)
+ return 0;
+
+ /* calculate the number of ecc chunk behind the bbm */
+ i = (mtd->writesize / geo->ecc_chunkn_size) - bbm_chunk + 1;
+
+ block_mark_bit_offset = mtd->writesize * 8 -
+ (geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - i)
+ + geo->metadata_size * 8);
+
+ geo->block_mark_byte_offset = block_mark_bit_offset / 8;
+ geo->block_mark_bit_offset = block_mark_bit_offset % 8;
+
+ dev_dbg(this->dev, "BCH Geometry :\n"
+ "GF length : %u\n"
+ "ECC Strength : %u\n"
+ "Page Size in Bytes : %u\n"
+ "Metadata Size in Bytes : %u\n"
+ "ECC Chunk0 Size in Bytes: %u\n"
+ "ECC Chunkn Size in Bytes: %u\n"
+ "ECC Chunk Count : %u\n"
+ "Payload Size in Bytes : %u\n"
+ "Auxiliary Size in Bytes: %u\n"
+ "Auxiliary Status Offset: %u\n"
+ "Block Mark Byte Offset : %u\n"
+ "Block Mark Bit Offset : %u\n"
+ "Block Mark in chunk : %u\n"
+ "Ecc for Meta data : %u\n",
+ geo->gf_len,
+ geo->ecc_strength,
+ geo->page_size,
+ geo->metadata_size,
+ geo->ecc_chunk0_size,
+ geo->ecc_chunkn_size,
+ geo->ecc_chunk_count,
+ geo->payload_size,
+ geo->auxiliary_size,
+ geo->auxiliary_status_offset,
+ geo->block_mark_byte_offset,
+ geo->block_mark_bit_offset,
+ bbm_chunk,
+ geo->ecc_for_meta);
+
+ return 0;
+}
+
static int legacy_set_geometry(struct gpmi_nand_data *this)
{
struct bch_geometry *geo = &this->bch_geometry;
@@ -299,20 +490,22 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
geo->gf_len = 13;
/* The default for chunk size. */
- geo->ecc_chunk_size = 512;
- while (geo->ecc_chunk_size < mtd->oobsize) {
- geo->ecc_chunk_size *= 2; /* keep C >= O */
+ geo->ecc_chunk0_size = 512;
+ geo->ecc_chunkn_size = 512;
+ while (geo->ecc_chunkn_size < mtd->oobsize) {
+ geo->ecc_chunk0_size *= 2; /* keep C >= O */
+ geo->ecc_chunkn_size *= 2; /* keep C >= O */
geo->gf_len = 14;
}
- geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
+ geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunkn_size;
/* We use the same ECC strength for all chunks. */
geo->ecc_strength = get_ecc_strength(this);
if (!gpmi_check_ecc(this)) {
dev_err(this->dev,
"ecc strength: %d cannot be supported by the controller (%d)\n"
- "try to use minimum ecc strength that NAND chip required\n",
+ "try to use maximum ecc strength that NAND chip required\n",
geo->ecc_strength,
this->devdata->bch_max_ecc_strength);
return -EINVAL;
@@ -394,11 +587,26 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
int common_nfc_set_geometry(struct gpmi_nand_data *this)
{
- if ((of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc"))
- || legacy_set_geometry(this))
- return set_geometry_by_ecc_info(this);
+ struct mtd_info *mtd = &this->nand.mtd;
+ struct nand_chip *chip = mtd_to_nand(mtd);
- return 0;
+ if (chip->ecc_strength_ds > this->devdata->bch_max_ecc_strength) {
+ dev_err(this->dev,
+ "unsupported NAND chip, minimum ecc required %d\n"
+ , chip->ecc_strength_ds);
+ return -EINVAL;
+ }
+
+ if ((!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0) &&
+ (mtd->oobsize < 1024)) || this->legacy_bch_geometry) {
+ dev_warn(this->dev, "use legacy bch geometry\n");
+ return legacy_set_geometry(this);
+ }
+
+ if (mtd->oobsize > 1024 || chip->ecc_step_ds < mtd->oobsize)
+ return set_geometry_for_large_oob(this);
+
+ return set_geometry_by_ecc_info(this);
}
struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
@@ -582,6 +790,9 @@ static int acquire_dma_channels(struct gpmi_nand_data *this)
{
struct platform_device *pdev = this->pdev;
struct dma_chan *dma_chan;
+ struct device_node *np = pdev->dev.of_node;
+
+ of_dma_configure(&pdev->dev, np);
/* request dma channel */
dma_chan = dma_request_slave_channel(&pdev->dev, "rx-tx");
@@ -602,6 +813,14 @@ static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = {
"gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
};
+static char *extra_clks_for_mx7d[GPMI_CLK_MAX] = {
+ "gpmi_bch_apb",
+};
+
+static char *extra_clks_for_mx8qxp[GPMI_CLK_MAX] = {
+ "gpmi_apb", "gpmi_bch", "gpmi_apb_bch",
+};
+
static int gpmi_get_clks(struct gpmi_nand_data *this)
{
struct resources *r = &this->resources;
@@ -619,6 +838,11 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
/* Get extra clocks */
if (GPMI_IS_MX6(this))
extra_clks = extra_clks_for_mx6q;
+ if (GPMI_IS_MX7(this))
+ extra_clks = extra_clks_for_mx7d;
+ if (GPMI_IS_MX8(this))
+ extra_clks = extra_clks_for_mx8qxp;
+
if (!extra_clks)
return 0;
@@ -635,7 +859,7 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
r->clock[i] = clk;
}
- if (GPMI_IS_MX6(this))
+ if (GPMI_IS_MX6(this) || GPMI_IS_MX7(this) || GPMI_IS_MX8(this))
/*
* Set the default value for the gpmi clock.
*
@@ -651,6 +875,15 @@ err_clock:
return err;
}
+static int init_rpm(struct gpmi_nand_data *this)
+{
+ pm_runtime_enable(this->dev);
+ pm_runtime_set_autosuspend_delay(this->dev, GPMI_RPM_TIMEOUT);
+ pm_runtime_use_autosuspend(this->dev);
+
+ return 0;
+}
+
static int acquire_resources(struct gpmi_nand_data *this)
{
int ret;
@@ -667,13 +900,10 @@ static int acquire_resources(struct gpmi_nand_data *this)
if (ret)
goto exit_regs;
- ret = acquire_dma_channels(this);
- if (ret)
- goto exit_regs;
-
ret = gpmi_get_clks(this);
if (ret)
goto exit_clock;
+
return 0;
exit_clock:
@@ -1026,6 +1256,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
{
struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry;
+ void __iomem *bch_regs = this->resources.bch_regs;
void *payload_virt;
dma_addr_t payload_phys;
void *auxiliary_virt;
@@ -1034,6 +1265,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
unsigned char *status;
unsigned int max_bitflips = 0;
int ret;
+ int flag = 0;
dev_dbg(this->dev, "page number is : %d\n", page);
ret = read_page_prepare(this, buf, nfc_geo->payload_size,
@@ -1068,8 +1300,16 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
payload_virt, payload_phys);
for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) {
- if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED))
+ if (*status == STATUS_GOOD)
+ continue;
+
+ if (*status == STATUS_ERASED) {
+ if (GPMI_IS_MX6QP(this) || GPMI_IS_MX7(this) ||
+ GPMI_IS_MX6UL(this))
+ if (readl(bch_regs + HW_BCH_DEBUG1))
+ flag = 1;
continue;
+ }
if (*status == STATUS_UNCORRECTABLE) {
int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
@@ -1080,7 +1320,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
/* Read ECC bytes into our internal raw_buffer */
offset = nfc_geo->metadata_size * 8;
- offset += ((8 * nfc_geo->ecc_chunk_size) + eccbits) * (i + 1);
+ offset += ((8 * nfc_geo->ecc_chunkn_size) + eccbits) * (i + 1);
offset -= eccbits;
bitoffset = offset % 8;
eccbytes = DIV_ROUND_UP(offset + eccbits, 8);
@@ -1117,16 +1357,16 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
if (i == 0) {
/* The first block includes metadata */
flips = nand_check_erased_ecc_chunk(
- buf + i * nfc_geo->ecc_chunk_size,
- nfc_geo->ecc_chunk_size,
+ buf + i * nfc_geo->ecc_chunkn_size,
+ nfc_geo->ecc_chunkn_size,
eccbuf, eccbytes,
auxiliary_virt,
nfc_geo->metadata_size,
nfc_geo->ecc_strength);
} else {
flips = nand_check_erased_ecc_chunk(
- buf + i * nfc_geo->ecc_chunk_size,
- nfc_geo->ecc_chunk_size,
+ buf + i * nfc_geo->ecc_chunkn_size,
+ nfc_geo->ecc_chunkn_size,
eccbuf, eccbytes,
NULL, 0,
nfc_geo->ecc_strength);
@@ -1165,6 +1405,10 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
}
+ /* if bitflip occurred in erased page, change data to all 0xff */
+ if (flag)
+ memset(buf, 0xff, nfc_geo->payload_size);
+
return max_bitflips;
}
@@ -1209,9 +1453,23 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
}
}
+ /*
+ * if there is an ECC dedicate for meta:
+ * - need to add an extra ECC size when calculating col and page_size,
+ * if the meta size is NOT zero.
+ *
+ * - chunk0 size need to set to the same size as other chunks,
+ * if the meta size is zero.
+ */
+
meta = geo->metadata_size;
if (first) {
- col = meta + (size + ecc_parity_size) * first;
+ if (geo->ecc_for_meta)
+ col = meta + ecc_parity_size
+ + (size + ecc_parity_size) * first;
+ else
+ col = meta + (size + ecc_parity_size) * first;
+
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);
meta = 0;
@@ -1224,21 +1482,37 @@ static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
/* change the BCH registers and bch_geometry{} */
n = last - first + 1;
- page_size = meta + (size + ecc_parity_size) * n;
+
+ if (geo->ecc_for_meta && meta)
+ page_size = meta + ecc_parity_size
+ + (size + ecc_parity_size) * n;
+ else
+ page_size = meta + (size + ecc_parity_size) * n;
r1_new &= ~(BM_BCH_FLASH0LAYOUT0_NBLOCKS |
BM_BCH_FLASH0LAYOUT0_META_SIZE);
- r1_new |= BF_BCH_FLASH0LAYOUT0_NBLOCKS(n - 1)
+ r1_new |= BF_BCH_FLASH0LAYOUT0_NBLOCKS(
+ (geo->ecc_for_meta && meta) ? n : n - 1)
| BF_BCH_FLASH0LAYOUT0_META_SIZE(meta);
+
+ /* set chunk0 size if meta size is 0 */
+ if (!meta) {
+ if (GPMI_IS_MX6(this) || GPMI_IS_MX7(this) || GPMI_IS_MX8(this))
+ r1_new &= ~MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE;
+ else
+ r1_new &= ~BM_BCH_FLASH0LAYOUT0_DATA0_SIZE;
+ r1_new |= BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(size, this);
+ }
writel(r1_new, bch_regs + HW_BCH_FLASH0LAYOUT0);
r2_new &= ~BM_BCH_FLASH0LAYOUT1_PAGE_SIZE;
r2_new |= BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size);
writel(r2_new, bch_regs + HW_BCH_FLASH0LAYOUT1);
- geo->ecc_chunk_count = n;
+ geo->ecc_chunk_count = (geo->ecc_for_meta && meta) ? n + 1 : n;
geo->payload_size = n * size;
geo->page_size = page_size;
+ geo->metadata_size = meta;
geo->auxiliary_status_offset = ALIGN(meta, 4);
dev_dbg(this->dev, "page:%d(%d:%d)%d, chunk:(%d:%d), BCH PG size:%d\n",
@@ -1460,7 +1734,7 @@ static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
{
struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry;
- int eccsize = nfc_geo->ecc_chunk_size;
+ int eccsize = nfc_geo->ecc_chunkn_size;
int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
u8 *tmp_buf = this->raw_buffer;
size_t src_bit_off;
@@ -1468,6 +1742,7 @@ static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
size_t oob_byte_off;
uint8_t *oob = chip->oob_poi;
int step;
+ int ecc_chunk_count;
chip->read_buf(mtd, tmp_buf,
mtd->writesize + mtd->oobsize);
@@ -1495,9 +1770,21 @@ static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
oob_bit_off = nfc_geo->metadata_size * 8;
src_bit_off = oob_bit_off;
+ ecc_chunk_count = nfc_geo->ecc_chunk_count;
+ /* if bch requires dedicate ecc for meta */
+ if (nfc_geo->ecc_for_meta) {
+ if (oob_required)
+ gpmi_copy_bits(oob, oob_bit_off,
+ tmp_buf, src_bit_off,
+ eccbits);
+
+ src_bit_off += eccbits;
+ oob_bit_off += eccbits;
+ ecc_chunk_count = nfc_geo->ecc_chunk_count - 1;
+ }
/* Extract interleaved payload data and ECC bits */
- for (step = 0; step < nfc_geo->ecc_chunk_count; step++) {
+ for (step = 0; step < ecc_chunk_count; step++) {
if (buf)
gpmi_copy_bits(buf, step * eccsize * 8,
tmp_buf, src_bit_off,
@@ -1505,7 +1792,7 @@ static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
src_bit_off += eccsize * 8;
/* Align last ECC block to align a byte boundary */
- if (step == nfc_geo->ecc_chunk_count - 1 &&
+ if (step == ecc_chunk_count - 1 &&
(oob_bit_off + eccbits) % 8)
eccbits += 8 - ((oob_bit_off + eccbits) % 8);
@@ -1549,7 +1836,7 @@ static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
{
struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry;
- int eccsize = nfc_geo->ecc_chunk_size;
+ int eccsize = nfc_geo->ecc_chunkn_size;
int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
u8 *tmp_buf = this->raw_buffer;
uint8_t *oob = chip->oob_poi;
@@ -1557,6 +1844,7 @@ static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
size_t oob_bit_off;
size_t oob_byte_off;
int step;
+ int ecc_chunk_count;
/*
* Initialize all bits to 1 in case we don't have a buffer for the
@@ -1573,16 +1861,28 @@ static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
memcpy(tmp_buf, oob, nfc_geo->metadata_size);
oob_bit_off = nfc_geo->metadata_size * 8;
dst_bit_off = oob_bit_off;
+ ecc_chunk_count = nfc_geo->ecc_chunk_count;
+
+ /* if bch requires dedicate ecc for meta */
+ if (nfc_geo->ecc_for_meta) {
+ if (oob_required)
+ gpmi_copy_bits(tmp_buf, dst_bit_off,
+ oob, oob_bit_off, eccbits);
+
+ dst_bit_off += eccbits;
+ oob_bit_off += eccbits;
+ ecc_chunk_count = nfc_geo->ecc_chunk_count - 1;
+ }
/* Interleave payload data and ECC bits */
- for (step = 0; step < nfc_geo->ecc_chunk_count; step++) {
+ for (step = 0; step < ecc_chunk_count; step++) {
if (buf)
gpmi_copy_bits(tmp_buf, dst_bit_off,
buf, step * eccsize * 8, eccsize * 8);
dst_bit_off += eccsize * 8;
/* Align last ECC block to align a byte boundary */
- if (step == nfc_geo->ecc_chunk_count - 1 &&
+ if (step == ecc_chunk_count - 1 &&
(oob_bit_off + eccbits) % 8)
eccbits += 8 - ((oob_bit_off + eccbits) % 8);
@@ -1872,7 +2172,7 @@ static int mx23_boot_init(struct gpmi_nand_data *this)
*/
chipnr = block >> (chip->chip_shift - chip->phys_erase_shift);
page = block << (chip->phys_erase_shift - chip->page_shift);
- byte = block << chip->phys_erase_shift;
+ byte = (loff_t) block << chip->phys_erase_shift;
/* Send the command to read the conventional block mark. */
chip->select_chip(mtd, chipnr);
@@ -1947,6 +2247,11 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
if (ret)
return ret;
+ /* Save the geometry to debugfs*/
+ ret = bch_create_debugfs(this);
+ if (ret)
+ return ret;
+
/* Init the nand_ecc_ctrl{} */
ecc->read_page = gpmi_ecc_read_page;
ecc->write_page = gpmi_ecc_write_page;
@@ -1957,7 +2262,7 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
ecc->read_oob_raw = gpmi_ecc_read_oob_raw;
ecc->write_oob_raw = gpmi_ecc_write_oob_raw;
ecc->mode = NAND_ECC_HW;
- ecc->size = bch_geo->ecc_chunk_size;
+ ecc->size = bch_geo->ecc_chunkn_size;
ecc->strength = bch_geo->ecc_strength;
mtd_set_ooblayout(mtd, &gpmi_ooblayout_ops);
@@ -1966,7 +2271,7 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
* (1) the chip is imx6, and
* (2) the size of the ECC parity is byte aligned.
*/
- if (GPMI_IS_MX6(this) &&
+ if ((GPMI_IS_MX6(this) || GPMI_IS_MX7(this) || GPMI_IS_MX8(this)) &&
((bch_geo->gf_len * bch_geo->ecc_strength) % 8) == 0) {
ecc->read_subpage = gpmi_ecc_read_subpage;
chip->options |= NAND_SUBPAGE_READ;
@@ -2022,7 +2327,8 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
if (ret)
goto err_out;
- ret = nand_scan_ident(mtd, GPMI_IS_MX6(this) ? 2 : 1, NULL);
+ ret = nand_scan_ident(mtd, GPMI_IS_MX6(this) || GPMI_IS_MX7(this)\
+ || GPMI_IS_MX8(this) ? 2 : 1, NULL);
if (ret)
goto err_out;
@@ -2032,6 +2338,10 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
if (of_property_read_bool(this->dev->of_node,
"fsl,no-blockmark-swap"))
this->swap_block_mark = false;
+
+ if (of_property_read_bool(this->dev->of_node,
+ "fsl,legacy-bch-geometry"))
+ this->legacy_bch_geometry = true;
}
dev_dbg(this->dev, "Blockmark swapping %sabled\n",
this->swap_block_mark ? "en" : "dis");
@@ -2075,9 +2385,24 @@ static const struct of_device_id gpmi_nand_id_table[] = {
.compatible = "fsl,imx6q-gpmi-nand",
.data = &gpmi_devdata_imx6q,
}, {
+ .compatible = "fsl,imx6qp-gpmi-nand",
+ .data = (void *)&gpmi_devdata_imx6qp,
+ }, {
.compatible = "fsl,imx6sx-gpmi-nand",
.data = &gpmi_devdata_imx6sx,
- }, {}
+ }, {
+ .compatible = "fsl,imx6ul-gpmi-nand",
+ .data = (void *)&gpmi_devdata_imx6ul,
+ }, {
+ .compatible = "fsl,imx7d-gpmi-nand",
+ .data = (void *)&gpmi_devdata_imx7d,
+ }, {
+ .compatible = "fsl,imx6ull-gpmi-nand",
+ .data = (void *)&gpmi_devdata_imx6ull,
+ }, {
+ .compatible = "fsl,imx8qxp-gpmi-nand",
+ .data = (void *)&gpmi_devdata_imx8qxp,
+ }, { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
@@ -2107,6 +2432,10 @@ static int gpmi_nand_probe(struct platform_device *pdev)
if (ret)
goto exit_acquire_resources;
+ ret = init_rpm(this);
+ if (ret)
+ goto exit_nfc_init;
+
ret = init_hardware(this);
if (ret)
goto exit_nfc_init;
@@ -2131,6 +2460,7 @@ static int gpmi_nand_remove(struct platform_device *pdev)
struct gpmi_nand_data *this = platform_get_drvdata(pdev);
gpmi_nand_exit(this);
+ pm_runtime_disable(this->dev);
release_resources(this);
return 0;
}
@@ -2138,10 +2468,12 @@ static int gpmi_nand_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int gpmi_pm_suspend(struct device *dev)
{
- struct gpmi_nand_data *this = dev_get_drvdata(dev);
+ int ret;
- release_dma_channels(this);
- return 0;
+ pinctrl_pm_select_sleep_state(dev);
+ ret = pm_runtime_force_suspend(dev);
+
+ return ret;
}
static int gpmi_pm_resume(struct device *dev)
@@ -2149,9 +2481,14 @@ static int gpmi_pm_resume(struct device *dev)
struct gpmi_nand_data *this = dev_get_drvdata(dev);
int ret;
- ret = acquire_dma_channels(this);
- if (ret < 0)
+ /* enable clock, acquire dma */
+ ret = pm_runtime_force_resume(dev);
+ if (ret) {
+ dev_err(this->dev, "Error in resume: %d\n", ret);
return ret;
+ }
+
+ pinctrl_pm_select_default_state(dev);
/* re-init the GPMI registers */
this->flags &= ~GPMI_TIMING_INIT_OK;
@@ -2175,7 +2512,40 @@ static int gpmi_pm_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
+#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true)
+#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false)
+
+int gpmi_runtime_suspend(struct device *dev)
+{
+ struct gpmi_nand_data *this = dev_get_drvdata(dev);
+
+ gpmi_disable_clk(this);
+ release_bus_freq(BUS_FREQ_HIGH);
+ release_dma_channels(this);
+
+ return 0;
+}
+
+int gpmi_runtime_resume(struct device *dev)
+{
+ struct gpmi_nand_data *this = dev_get_drvdata(dev);
+ int ret;
+
+ ret = gpmi_enable_clk(this);
+ if (ret)
+ return ret;
+
+ request_bus_freq(BUS_FREQ_HIGH);
+
+ ret = acquire_dma_channels(this);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static const struct dev_pm_ops gpmi_pm_ops = {
+ SET_RUNTIME_PM_OPS(gpmi_runtime_suspend, gpmi_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(gpmi_pm_suspend, gpmi_pm_resume)
};
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
index 4e49a1f5fa27..f92616b99871 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h
@@ -1,7 +1,7 @@
/*
* Freescale GPMI NAND Flash Driver
*
- * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2010-2016 Freescale Semiconductor, Inc.
* Copyright (C) 2008 Embedded Alley Solutions, Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -39,9 +39,9 @@ struct resources {
* @page_size: The size, in bytes, of a physical page, including
* both data and OOB.
* @metadata_size: The size, in bytes, of the metadata.
- * @ecc_chunk_size: The size, in bytes, of a single ECC chunk. Note
- * the first chunk in the page includes both data and
- * metadata, so it's a bit larger than this value.
+ * @ecc_chunk0_size: The size, in bytes, of a first ECC chunk.
+ * @ecc_chunkn_size: The size, in bytes, of a single ECC chunk after
+ * the first chunk in the page.
* @ecc_chunk_count: The number of ECC chunks in the page,
* @payload_size: The size, in bytes, of the payload buffer.
* @auxiliary_size: The size, in bytes, of the auxiliary buffer.
@@ -51,19 +51,23 @@ struct resources {
* which the underlying physical block mark appears.
* @block_mark_bit_offset: The bit offset into the ECC-based page view at
* which the underlying physical block mark appears.
+ * @ecc_for_meta: The flag to indicate if there is a dedicate ecc
+ * for meta.
*/
struct bch_geometry {
unsigned int gf_len;
unsigned int ecc_strength;
unsigned int page_size;
unsigned int metadata_size;
- unsigned int ecc_chunk_size;
+ unsigned int ecc_chunk0_size;
+ unsigned int ecc_chunkn_size;
unsigned int ecc_chunk_count;
unsigned int payload_size;
unsigned int auxiliary_size;
unsigned int auxiliary_status_offset;
unsigned int block_mark_byte_offset;
unsigned int block_mark_bit_offset;
+ unsigned int ecc_for_meta; /* ECC for meta data */
};
/**
@@ -123,7 +127,12 @@ enum gpmi_type {
IS_MX23,
IS_MX28,
IS_MX6Q,
- IS_MX6SX
+ IS_MX6QP,
+ IS_MX6SX,
+ IS_MX7D,
+ IS_MX6UL,
+ IS_MX6ULL,
+ IS_MX8QXP,
};
struct gpmi_devdata {
@@ -189,6 +198,8 @@ struct gpmi_nand_data {
dma_addr_t auxiliary_phys;
void *raw_buffer;
+ /* legacy bch geometry flag */
+ bool legacy_bch_geometry;
/* DMA channels */
#define DMA_CHANS 8
@@ -275,10 +286,12 @@ extern int start_dma_with_bch_irq(struct gpmi_nand_data *,
struct dma_async_tx_descriptor *);
/* GPMI-NAND helper function library */
+extern int __gpmi_enable_clk(struct gpmi_nand_data *, bool v);
extern int gpmi_init(struct gpmi_nand_data *);
extern int gpmi_extra_init(struct gpmi_nand_data *);
extern void gpmi_clear_bch(struct gpmi_nand_data *);
extern void gpmi_dump_info(struct gpmi_nand_data *);
+extern int bch_create_debugfs(struct gpmi_nand_data *);
extern int bch_set_geometry(struct gpmi_nand_data *);
extern int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip);
extern int gpmi_send_command(struct gpmi_nand_data *);
@@ -304,7 +317,15 @@ void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
#define GPMI_IS_MX23(x) ((x)->devdata->type == IS_MX23)
#define GPMI_IS_MX28(x) ((x)->devdata->type == IS_MX28)
#define GPMI_IS_MX6Q(x) ((x)->devdata->type == IS_MX6Q)
+#define GPMI_IS_MX6QP(x) ((x)->devdata->type == IS_MX6QP)
#define GPMI_IS_MX6SX(x) ((x)->devdata->type == IS_MX6SX)
-
-#define GPMI_IS_MX6(x) (GPMI_IS_MX6Q(x) || GPMI_IS_MX6SX(x))
+#define GPMI_IS_MX7D(x) ((x)->devdata->type == IS_MX7D)
+#define GPMI_IS_MX6UL(x) ((x)->devdata->type == IS_MX6UL)
+#define GPMI_IS_MX6ULL(x) ((x)->devdata->type == IS_MX6ULL)
+#define GPMI_IS_MX8QXP(x) ((x)->devdata->type == IS_MX8QXP)
+
+#define GPMI_IS_MX6(x) (GPMI_IS_MX6Q(x) || GPMI_IS_MX6QP(x)\
+ || GPMI_IS_MX6SX(x) || GPMI_IS_MX6UL(x) || GPMI_IS_MX6ULL(x))
+#define GPMI_IS_MX7(x) (GPMI_IS_MX7D(x))
+#define GPMI_IS_MX8(x) (GPMI_IS_MX8QXP(x))
#endif
diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index 4a682ee0f632..a7b644e8eb32 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -76,4 +76,10 @@ config SPI_NXP_SPIFI
Flash. Enable this option if you have a device with a SPIFI
controller and want to access the Flash as a mtd device.
+config SPI_FSL_FLEXSPI
+ tristate "Freescale Flex SPI controller"
+ help
+ This enables support for the Flex SPI controller in master mode.
+ We only connect the NOR to this controller now.
+
endif # MTD_SPI_NOR
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index 121695e83542..5bace3c031ab 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o
obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o
obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o
obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o
+obj-$(CONFIG_SPI_FSL_FLEXSPI) += fsl-flexspi.o
diff --git a/drivers/mtd/spi-nor/fsl-flexspi.c b/drivers/mtd/spi-nor/fsl-flexspi.c
new file mode 100644
index 000000000000..1aff05fd7459
--- /dev/null
+++ b/drivers/mtd/spi-nor/fsl-flexspi.c
@@ -0,0 +1,1471 @@
+/*
+ * Freescale FlexSPI driver.
+ *
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/completion.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/spi-nor.h>
+#include <linux/mutex.h>
+#include <linux/pm_qos.h>
+#include <linux/pci.h>
+#include <soc/imx8/sc/sci.h>
+#include <linux/pm_runtime.h>
+
+/* Board only enabled up to Quad mode, not Octal*/
+#define FLEXSPI_QUIRK_QUAD_ONLY (1 << 0)
+
+/* runtime pm timeout */
+#define FSL_FLEXSPI_RPM_TIMEOUT 50 /* 50ms */
+
+/* The registers */
+#define FLEXSPI_MCR0 0x00
+#define FLEXSPI_MCR0_AHB_TIMEOUT_SHIFT 24
+#define FLEXSPI_MCR0_AHB_TIMEOUT_MASK (0xFF << FLEXSPI_MCR0_AHB_TIMEOUT_SHIFT)
+#define FLEXSPI_MCR0_IP_TIMEOUT_SHIFT 16
+#define FLEXSPI_MCR0_IP_TIMEOUT_MASK (0xFF << FLEXSPI_MCR0_IP_TIMEOUT_SHIFT)
+#define FLEXSPI_MCR0_LEARN_EN_SHIFT 15
+#define FLEXSPI_MCR0_LEARN_EN_MASK (1 << FLEXSPI_MCR0_LEARN_EN_SHIFT)
+#define FLEXSPI_MCR0_SCRFRUN_EN_SHIFT 14
+#define FLEXSPI_MCR0_SCRFRUN_EN_MASK (1 << FLEXSPI_MCR0_SCRFRUN_EN_SHIFT)
+#define FLEXSPI_MCR0_OCTCOMB_EN_SHIFT 13
+#define FLEXSPI_MCR0_OCTCOMB_EN_MASK (1 << FLEXSPI_MCR0_OCTCOMB_EN_SHIFT)
+#define FLEXSPI_MCR0_DOZE_EN_SHIFT 12
+#define FLEXSPI_MCR0_DOZE_EN_MASK (1 << FLEXSPI_MCR0_DOZE_EN_SHIFT)
+#define FLEXSPI_MCR0_HSEN_SHIFT 11
+#define FLEXSPI_MCR0_HSEN_MASK (1 << FLEXSPI_MCR0_HSEN_SHIFT)
+#define FLEXSPI_MCR0_SERCLKDIV_SHIFT 8
+#define FLEXSPI_MCR0_SERCLKDIV_MASK (7 << FLEXSPI_MCR0_SERCLKDIV_SHIFT)
+#define FLEXSPI_MCR0_ATDF_EN_SHIFT 7
+#define FLEXSPI_MCR0_ATDF_EN_MASK (1 << FLEXSPI_MCR0_ATDF_EN_SHIFT)
+#define FLEXSPI_MCR0_ARDF_EN_SHIFT 6
+#define FLEXSPI_MCR0_ARDF_EN_MASK (1 << FLEXSPI_MCR0_ARDF_EN_SHIFT)
+#define FLEXSPI_MCR0_RXCLKSRC_SHIFT 4
+#define FLEXSPI_MCR0_RXCLKSRC_MASK (3 << FLEXSPI_MCR0_RXCLKSRC_SHIFT)
+#define FLEXSPI_MCR0_END_CFG_SHIFT 2
+#define FLEXSPI_MCR0_END_CFG_MASK (3 << FLEXSPI_MCR0_END_CFG_SHIFT)
+#define FLEXSPI_MCR0_MDIS_SHIFT 1
+#define FLEXSPI_MCR0_MDIS_MASK (1 << FLEXSPI_MCR0_MDIS_SHIFT)
+#define FLEXSPI_MCR0_SWRST_SHIFT 0
+#define FLEXSPI_MCR0_SWRST_MASK (1 << FLEXSPI_MCR0_SWRST_SHIFT)
+
+#define FLEXSPI_MCR1 0x04
+#define FLEXSPI_MCR1_SEQ_TIMEOUT_SHIFT 16
+#define FLEXSPI_MCR1_SEQ_TIMEOUT_MASK \
+ (0xFFFF << FLEXSPI_MCR1_SEQ_TIMEOUT_SHIFT)
+#define FLEXSPI_MCR1_AHB_TIMEOUT_SHIFT 0
+#define FLEXSPI_MCR1_AHB_TIMEOUT_MASK \
+ (0xFFFF << FLEXSPI_MCR1_AHB_TIMEOUT_SHIFT)
+
+#define FLEXSPI_MCR2 0x08
+#define FLEXSPI_MCR2_IDLE_WAIT_SHIFT 24
+#define FLEXSPI_MCR2_IDLE_WAIT_MASK (0xFF << FLEXSPI_MCR2_IDLE_WAIT_SHIFT)
+#define FLEXSPI_MCR2_SAMEFLASH_SHIFT 15
+#define FLEXSPI_MCR2_SAMEFLASH_MASK (1 << FLEXSPI_MCR2_SAMEFLASH_SHIFT)
+#define FLEXSPI_MCR2_CLRLRPHS_SHIFT 14
+#define FLEXSPI_MCR2_CLRLRPHS_MASK (1 << FLEXSPI_MCR2_CLRLRPHS_SHIFT)
+#define FLEXSPI_MCR2_ABRDATSZ_SHIFT 8
+#define FLEXSPI_MCR2_ABRDATSZ_MASK (1 << FLEXSPI_MCR2_ABRDATSZ_SHIFT)
+#define FLEXSPI_MCR2_ABRLEARN_SHIFT 7
+#define FLEXSPI_MCR2_ABRLEARN_MASK (1 << FLEXSPI_MCR2_ABRLEARN_SHIFT)
+#define FLEXSPI_MCR2_ABR_READ_SHIFT 6
+#define FLEXSPI_MCR2_ABR_READ_MASK (1 << FLEXSPI_MCR2_ABR_READ_SHIFT)
+#define FLEXSPI_MCR2_ABRWRITE_SHIFT 5
+#define FLEXSPI_MCR2_ABRWRITE_MASK (1 << FLEXSPI_MCR2_ABRWRITE_SHIFT)
+#define FLEXSPI_MCR2_ABRDUMMY_SHIFT 4
+#define FLEXSPI_MCR2_ABRDUMMY_MASK (1 << FLEXSPI_MCR2_ABRDUMMY_SHIFT)
+#define FLEXSPI_MCR2_ABR_MODE_SHIFT 3
+#define FLEXSPI_MCR2_ABR_MODE_MASK (1 << FLEXSPI_MCR2_ABR_MODE_SHIFT)
+#define FLEXSPI_MCR2_ABRCADDR_SHIFT 2
+#define FLEXSPI_MCR2_ABRCADDR_MASK (1 << FLEXSPI_MCR2_ABRCADDR_SHIFT)
+#define FLEXSPI_MCR2_ABRRADDR_SHIFT 1
+#define FLEXSPI_MCR2_ABRRADDR_MASK (1 << FLEXSPI_MCR2_ABRRADDR_SHIFT)
+#define FLEXSPI_MCR2_ABR_CMD_SHIFT 0
+#define FLEXSPI_MCR2_ABR_CMD_MASK (1 << FLEXSPI_MCR2_ABR_CMD_SHIFT)
+
+#define FLEXSPI_AHBCR 0x0c
+#define FLEXSPI_AHBCR_RDADDROPT_SHIFT 6
+#define FLEXSPI_AHBCR_RDADDROPT_MASK (1 << FLEXSPI_AHBCR_RDADDROPT_SHIFT)
+#define FLEXSPI_AHBCR_PREF_EN_SHIFT 5
+#define FLEXSPI_AHBCR_PREF_EN_MASK (1 << FLEXSPI_AHBCR_PREF_EN_SHIFT)
+#define FLEXSPI_AHBCR_BUFF_EN_SHIFT 4
+#define FLEXSPI_AHBCR_BUFF_EN_MASK (1 << FLEXSPI_AHBCR_BUFF_EN_SHIFT)
+#define FLEXSPI_AHBCR_CACH_EN_SHIFT 3
+#define FLEXSPI_AHBCR_CACH_EN_MASK (1 << FLEXSPI_AHBCR_CACH_EN_SHIFT)
+#define FLEXSPI_AHBCR_CLRTXBUF_SHIFT 2
+#define FLEXSPI_AHBCR_CLRTXBUF_MASK (1 << FLEXSPI_AHBCR_CLRTXBUF_SHIFT)
+#define FLEXSPI_AHBCR_CLRRXBUF_SHIFT 1
+#define FLEXSPI_AHBCR_CLRRXBUF_MASK (1 << FLEXSPI_AHBCR_CLRRXBUF_SHIFT)
+#define FLEXSPI_AHBCR_PAR_EN_SHIFT 0
+#define FLEXSPI_AHBCR_PAR_EN_MASK (1 << FLEXSPI_AHBCR_PAR_EN_SHIFT)
+
+#define FLEXSPI_INTEN 0x10
+#define FLEXSPI_INTEN_SCLKSBWR_SHIFT 9
+#define FLEXSPI_INTEN_SCLKSBWR_MASK (1 << FLEXSPI_INTEN_SCLKSBWR_SHIFT)
+#define FLEXSPI_INTEN_SCLKSBRD_SHIFT 8
+#define FLEXSPI_INTEN_SCLKSBRD_MASK (1 << FLEXSPI_INTEN_SCLKSBRD_SHIFT)
+#define FLEXSPI_INTEN_DATALRNFL_SHIFT 7
+#define FLEXSPI_INTEN_DATALRNFL_MASK (1 << FLEXSPI_INTEN_DATALRNFL_SHIFT)
+#define FLEXSPI_INTEN_IPTXWE_SHIFT 6
+#define FLEXSPI_INTEN_IPTXWE_MASK (1 << FLEXSPI_INTEN_IPTXWE_SHIFT)
+#define FLEXSPI_INTEN_IPRXWA_SHIFT 5
+#define FLEXSPI_INTEN_IPRXWA_MASK (1 << FLEXSPI_INTEN_IPRXWA_SHIFT)
+#define FLEXSPI_INTEN_AHBCMDERR_SHIFT 4
+#define FLEXSPI_INTEN_AHBCMDERR_MASK (1 << FLEXSPI_INTEN_AHBCMDERR_SHIFT)
+#define FLEXSPI_INTEN_IPCMDERR_SHIFT 3
+#define FLEXSPI_INTEN_IPCMDERR_MASK (1 << FLEXSPI_INTEN_IPCMDERR_SHIFT)
+#define FLEXSPI_INTEN_AHBCMDGE_SHIFT 2
+#define FLEXSPI_INTEN_AHBCMDGE_MASK (1 << FLEXSPI_INTEN_AHBCMDGE_SHIFT)
+#define FLEXSPI_INTEN_IPCMDGE_SHIFT 1
+#define FLEXSPI_INTEN_IPCMDGE_MASK (1 << FLEXSPI_INTEN_IPCMDGE_SHIFT)
+#define FLEXSPI_INTEN_IPCMDDONE_SHIFT 0
+#define FLEXSPI_INTEN_IPCMDDONE_MASK (1 << FLEXSPI_INTEN_IPCMDDONE_SHIFT)
+
+#define FLEXSPI_INTR 0x14
+#define FLEXSPI_INTR_SCLKSBWR_SHIFT 9
+#define FLEXSPI_INTR_SCLKSBWR_MASK (1 << FLEXSPI_INTR_SCLKSBWR_SHIFT)
+#define FLEXSPI_INTR_SCLKSBRD_SHIFT 8
+#define FLEXSPI_INTR_SCLKSBRD_MASK (1 << FLEXSPI_INTR_SCLKSBRD_SHIFT)
+#define FLEXSPI_INTR_DATALRNFL_SHIFT 7
+#define FLEXSPI_INTR_DATALRNFL_MASK (1 << FLEXSPI_INTR_DATALRNFL_SHIFT)
+#define FLEXSPI_INTR_IPTXWE_SHIFT 6
+#define FLEXSPI_INTR_IPTXWE_MASK (1 << FLEXSPI_INTR_IPTXWE_SHIFT)
+#define FLEXSPI_INTR_IPRXWA_SHIFT 5
+#define FLEXSPI_INTR_IPRXWA_MASK (1 << FLEXSPI_INTR_IPRXWA_SHIFT)
+#define FLEXSPI_INTR_AHBCMDERR_SHIFT 4
+#define FLEXSPI_INTR_AHBCMDERR_MASK (1 << FLEXSPI_INTR_AHBCMDERR_SHIFT)
+#define FLEXSPI_INTR_IPCMDERR_SHIFT 3
+#define FLEXSPI_INTR_IPCMDERR_MASK (1 << FLEXSPI_INTR_IPCMDERR_SHIFT)
+#define FLEXSPI_INTR_AHBCMDGE_SHIFT 2
+#define FLEXSPI_INTR_AHBCMDGE_MASK (1 << FLEXSPI_INTR_AHBCMDGE_SHIFT)
+#define FLEXSPI_INTR_IPCMDGE_SHIFT 1
+#define FLEXSPI_INTR_IPCMDGE_MASK (1 << FLEXSPI_INTR_IPCMDGE_SHIFT)
+#define FLEXSPI_INTR_IPCMDDONE_SHIFT 0
+#define FLEXSPI_INTR_IPCMDDONE_MASK (1 << FLEXSPI_INTR_IPCMDDONE_SHIFT)
+
+#define FLEXSPI_LUTKEY 0x18
+#define FLEXSPI_LUTKEY_VALUE 0x5AF05AF0
+
+#define FLEXSPI_LCKCR 0x1C
+#define FLEXSPI_LCKER_LOCK 0x1
+#define FLEXSPI_LCKER_UNLOCK 0x2
+
+#define FLEXSPI_BUFXCR_INVALID_MSTRID 0xe
+#define FLEXSPI_AHBRX_BUF0CR0 0x20
+#define FLEXSPI_AHBRX_BUF1CR0 0x24
+#define FLEXSPI_AHBRX_BUF2CR0 0x28
+#define FLEXSPI_AHBRX_BUF3CR0 0x2C
+#define FLEXSPI_AHBRX_BUF4CR0 0x30
+#define FLEXSPI_AHBRX_BUF5CR0 0x34
+#define FLEXSPI_AHBRX_BUF6CR0 0x38
+#define FLEXSPI_AHBRX_BUF7CR0 0x3C
+#define FLEXSPI_AHBRXBUF0CR7_PREF_SHIFT 31
+#define FLEXSPI_AHBRXBUF0CR7_PREF_MASK (1 << FLEXSPI_AHBRXBUF0CR7_PREF_SHIFT)
+
+#define FLEXSPI_AHBRX_BUF0CR1 0x40
+#define FLEXSPI_AHBRX_BUF1CR1 0x44
+#define FLEXSPI_AHBRX_BUF2CR1 0x48
+#define FLEXSPI_AHBRX_BUF3CR1 0x4C
+#define FLEXSPI_AHBRX_BUF4CR1 0x50
+#define FLEXSPI_AHBRX_BUF5CR1 0x54
+#define FLEXSPI_AHBRX_BUF6CR1 0x58
+#define FLEXSPI_AHBRX_BUF7CR1 0x5C
+#define FLEXSPI_BUFXCR1_MSID_SHIFT 0
+#define FLEXSPI_BUFXCR1_MSID_MASK (0xF << FLEXSPI_BUFXCR1_MSID_SHIFT)
+#define FLEXSPI_BUFXCR1_PRIO_SHIFT 8
+#define FLEXSPI_BUFXCR1_PRIO_MASK (0x7 << FLEXSPI_BUFXCR1_PRIO_SHIFT)
+
+#define FLEXSPI_FLSHA1CR0 0x60
+#define FLEXSPI_FLSHA2CR0 0x64
+#define FLEXSPI_FLSHB1CR0 0x68
+#define FLEXSPI_FLSHB2CR0 0x6C
+#define FLEXSPI_FLSHXCR0_SZ_SHIFT 10
+#define FLEXSPI_FLSHXCR0_SZ_MASK (0x3FFFFF << FLEXSPI_FLSHXCR0_SZ_SHIFT)
+
+#define FLEXSPI_FLSHA1CR1 0x70
+#define FLEXSPI_FLSHA2CR1 0x74
+#define FLEXSPI_FLSHB1CR1 0x78
+#define FLEXSPI_FLSHB2CR1 0x7C
+#define FLEXSPI_FLSHXCR1_CSINTR_SHIFT 16
+#define FLEXSPI_FLSHXCR1_CSINTR_MASK \
+ (0xFFFF << FLEXSPI_FLSHXCR1_CSINTR_SHIFT)
+#define FLEXSPI_FLSHXCR1_CAS_SHIFT 11
+#define FLEXSPI_FLSHXCR1_CAS_MASK (0xF << FLEXSPI_FLSHXCR1_CAS_SHIFT)
+#define FLEXSPI_FLSHXCR1_WA_SHIFT 10
+#define FLEXSPI_FLSHXCR1_WA_MASK (1 << FLEXSPI_FLSHXCR1_WA_SHIFT)
+#define FLEXSPI_FLSHXCR1_TCSH_SHIFT 5
+#define FLEXSPI_FLSHXCR1_TCSH_MASK (0x1F << FLEXSPI_FLSHXCR1_TCSH_SHIFT)
+#define FLEXSPI_FLSHXCR1_TCSS_SHIFT 0
+#define FLEXSPI_FLSHXCR1_TCSS_MASK (0x1F << FLEXSPI_FLSHXCR1_TCSS_SHIFT)
+
+#define FLEXSPI_FLSHA1CR2 0x80
+#define FLEXSPI_FLSHA2CR2 0x84
+#define FLEXSPI_FLSHB1CR2 0x88
+#define FLEXSPI_FLSHB2CR2 0x8C
+#define FLEXSPI_FLSHXCR2_CLRINSP_SHIFT 24
+#define FLEXSPI_FLSHXCR2_CLRINSP_MASK (1 << FLEXSPI_FLSHXCR2_CLRINSP_SHIFT)
+#define FLEXSPI_FLSHXCR2_AWRWAIT_SHIFT 16
+#define FLEXSPI_FLSHXCR2_AWRWAIT_MASK (0xFF << FLEXSPI_FLSHXCR2_AWRWAIT_SHIFT)
+#define FLEXSPI_FLSHXCR2_AWRSEQN_SHIFT 13
+#define FLEXSPI_FLSHXCR2_AWRSEQN_MASK (0x7 << FLEXSPI_FLSHXCR2_AWRSEQN_SHIFT)
+#define FLEXSPI_FLSHXCR2_AWRSEQI_SHIFT 8
+#define FLEXSPI_FLSHXCR2_AWRSEQI_MASK (0xF << FLEXSPI_FLSHXCR2_AWRSEQI_SHIFT)
+#define FLEXSPI_FLSHXCR2_ARDSEQN_SHIFT 5
+#define FLEXSPI_FLSHXCR2_ARDSEQN_MASK (0x7 << FLEXSPI_FLSHXCR2_ARDSEQN_SHIFT)
+#define FLEXSPI_FLSHXCR2_ARDSEQI_SHIFT 0
+#define FLEXSPI_FLSHXCR2_ARDSEQI_MASK (0xF << FLEXSPI_FLSHXCR2_ARDSEQI_SHIFT)
+
+#define FLEXSPI_IPCR0 0xA0
+
+#define FLEXSPI_IPCR1 0xA4
+#define FLEXSPI_IPCR1_IPAREN_SHIFT 31
+#define FLEXSPI_IPCR1_IPAREN_MASK (1 << FLEXSPI_IPCR1_IPAREN_SHIFT)
+#define FLEXSPI_IPCR1_SEQNUM_SHIFT 24
+#define FLEXSPI_IPCR1_SEQNUM_MASK (0xF << FLEXSPI_IPCR1_SEQNUM_SHIFT)
+#define FLEXSPI_IPCR1_SEQID_SHIFT 16
+#define FLEXSPI_IPCR1_SEQID_MASK (0xF << FLEXSPI_IPCR1_SEQID_SHIFT)
+#define FLEXSPI_IPCR1_IDATSZ_SHIFT 0
+#define FLEXSPI_IPCR1_IDATSZ_MASK (0xFFFF << FLEXSPI_IPCR1_IDATSZ_SHIFT)
+
+#define FLEXSPI_IPCMD 0xB0
+#define FLEXSPI_IPCMD_TRG_SHIFT 0
+#define FLEXSPI_IPCMD_TRG_MASK (1 << FLEXSPI_IPCMD_TRG_SHIFT)
+
+#define FLEXSPI_DLPR 0xB4
+
+#define FLEXSPI_IPRXFCR 0xB8
+#define FLEXSPI_IPRXFCR_CLR_SHIFT 0
+#define FLEXSPI_IPRXFCR_CLR_MASK (1 << FLEXSPI_IPRXFCR_CLR_SHIFT)
+#define FLEXSPI_IPRXFCR_DMA_EN_SHIFT 1
+#define FLEXSPI_IPRXFCR_DMA_EN_MASK (1 << FLEXSPI_IPRXFCR_DMA_EN_SHIFT)
+#define FLEXSPI_IPRXFCR_WMRK_SHIFT 2
+#define FLEXSPI_IPRXFCR_WMRK_MASK (0x1F << FLEXSPI_IPRXFCR_WMRK_SHIFT)
+
+#define FLEXSPI_IPTXFCR 0xBC
+#define FLEXSPI_IPTXFCR_CLR_SHIFT 0
+#define FLEXSPI_IPTXFCR_CLR_MASK (1 << FLEXSPI_IPTXFCR_CLR_SHIFT)
+#define FLEXSPI_IPTXFCR_DMA_EN_SHIFT 1
+#define FLEXSPI_IPTXFCR_DMA_EN_MASK (1 << FLEXSPI_IPTXFCR_DMA_EN_SHIFT)
+#define FLEXSPI_IPTXFCR_WMRK_SHIFT 2
+#define FLEXSPI_IPTXFCR_WMRK_MASK (0x1F << FLEXSPI_IPTXFCR_WMRK_SHIFT)
+
+#define FLEXSPI_STS0 0xE0
+#define FLEXSPI_STS0_DLPHA_SHIFT 9
+#define FLEXSPI_STS0_DLPHA_MASK (0x1F << FLEXSPI_STS0_DLPHA_SHIFT)
+#define FLEXSPI_STS0_DLPHB_SHIFT 4
+#define FLEXSPI_STS0_DLPHB_MASK (0x1F << FLEXSPI_STS0_DLPHB_SHIFT)
+#define FLEXSPI_STS0_CMD_SRC_SHIFT 2
+#define FLEXSPI_STS0_CMD_SRC_MASK (3 << FLEXSPI_STS0_CMD_SRC_SHIFT)
+#define FLEXSPI_STS0_ARB_IDLE_SHIFT 1
+#define FLEXSPI_STS0_ARB_IDLE_MASK (1 << FLEXSPI_STS0_ARB_IDLE_SHIFT)
+#define FLEXSPI_STS0_SEQ_IDLE_SHIFT 0
+#define FLEXSPI_STS0_SEQ_IDLE_MASK (1 << FLEXSPI_STS0_SEQ_IDLE_SHIFT)
+
+#define FLEXSPI_STS1 0xE4
+#define FLEXSPI_STS1_IP_ERRCD_SHIFT 24
+#define FLEXSPI_STS1_IP_ERRCD_MASK (0xF << FLEXSPI_STS1_IP_ERRCD_SHIFT)
+#define FLEXSPI_STS1_IP_ERRID_SHIFT 16
+#define FLEXSPI_STS1_IP_ERRID_MASK (0xF << FLEXSPI_STS1_IP_ERRID_SHIFT)
+#define FLEXSPI_STS1_AHB_ERRCD_SHIFT 8
+#define FLEXSPI_STS1_AHB_ERRCD_MASK (0xF << FLEXSPI_STS1_AHB_ERRCD_SHIFT)
+#define FLEXSPI_STS1_AHB_ERRID_SHIFT 0
+#define FLEXSPI_STS1_AHB_ERRID_MASK (0xF << FLEXSPI_STS1_AHB_ERRID_SHIFT)
+
+#define FLEXSPI_AHBSPNST 0xEC
+#define FLEXSPI_AHBSPNST_DATLFT_SHIFT 16
+#define FLEXSPI_AHBSPNST_DATLFT_MASK \
+ (0xFFFF << FLEXSPI_AHBSPNST_DATLFT_SHIFT)
+#define FLEXSPI_AHBSPNST_BUFID_SHIFT 1
+#define FLEXSPI_AHBSPNST_BUFID_MASK (7 << FLEXSPI_AHBSPNST_BUFID_SHIFT)
+#define FLEXSPI_AHBSPNST_ACTIVE_SHIFT 0
+#define FLEXSPI_AHBSPNST_ACTIVE_MASK (1 << FLEXSPI_AHBSPNST_ACTIVE_SHIFT)
+
+#define FLEXSPI_IPRXFSTS 0xF0
+#define FLEXSPI_IPRXFSTS_RDCNTR_SHIFT 16
+#define FLEXSPI_IPRXFSTS_RDCNTR_MASK \
+ (0xFFFF << FLEXSPI_IPRXFSTS_RDCNTR_SHIFT)
+#define FLEXSPI_IPRXFSTS_FILL_SHIFT 0
+#define FLEXSPI_IPRXFSTS_FILL_MASK (0xFF << FLEXSPI_IPRXFSTS_FILL_SHIFT)
+
+#define FLEXSPI_IPTXFSTS 0xF4
+#define FLEXSPI_IPTXFSTS_WRCNTR_SHIFT 16
+#define FLEXSPI_IPTXFSTS_WRCNTR_MASK \
+ (0xFFFF << FLEXSPI_IPTXFSTS_WRCNTR_SHIFT)
+#define FLEXSPI_IPTXFSTS_FILL_SHIFT 0
+#define FLEXSPI_IPTXFSTS_FILL_MASK (0xFF << FLEXSPI_IPTXFSTS_FILL_SHIFT)
+
+#define FLEXSPI_RFDR 0x100
+#define FLEXSPI_TFDR 0x180
+
+#define FLEXSPI_LUT_BASE 0x200
+
+/* register map end */
+
+/*
+ * The definition of the LUT register shows below:
+ *
+ * ---------------------------------------------------
+ * | INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 |
+ * ---------------------------------------------------
+ */
+#define OPRND0_SHIFT 0
+#define PAD0_SHIFT 8
+#define INSTR0_SHIFT 10
+#define OPRND1_SHIFT 16
+
+/* Instruction set for the LUT register. */
+
+#define LUT_STOP 0x00
+#define LUT_CMD 0x01
+#define LUT_ADDR 0x02
+#define LUT_CADDR_SDR 0x03
+#define LUT_MODE 0x04
+#define LUT_MODE2 0x05
+#define LUT_MODE4 0x06
+#define LUT_MODE8 0x07
+#define LUT_FSL_WRITE 0x08
+#define LUT_FSL_READ 0x09
+#define LUT_LEARN_SDR 0x0A
+#define LUT_DATSZ_SDR 0x0B
+#define LUT_DUMMY 0x0C
+#define LUT_DUMMY_RWDS_SDR 0x0D
+#define LUT_JMP_ON_CS 0x1F
+#define LUT_CMD_DDR 0x21
+#define LUT_ADDR_DDR 0x22
+#define LUT_CADDR_DDR 0x23
+#define LUT_MODE_DDR 0x24
+#define LUT_MODE2_DDR 0x25
+#define LUT_MODE4_DDR 0x26
+#define LUT_MODE8_DDR 0x27
+#define LUT_WRITE_DDR 0x28
+#define LUT_READ_DDR 0x29
+#define LUT_LEARN_DDR 0x2A
+#define LUT_DATSZ_DDR 0x2B
+#define LUT_DUMMY_DDR 0x2C
+#define LUT_DUMMY_RWDS_DDR 0x2D
+
+
+/*
+ * The PAD definitions for LUT register.
+ *
+ * The pad stands for the lines number of IO[0:3].
+ * For example, the Quad read need four IO lines, so you should
+ * set LUT_PAD4 which means we use four IO lines.
+ */
+#define LUT_PAD1 0
+#define LUT_PAD2 1
+#define LUT_PAD4 2
+#define LUT_PAD8 3
+
+/* Oprands for the LUT register. */
+#define ADDR24BIT 0x18
+#define ADDR32BIT 0x20
+
+/* Macros for constructing the LUT register. */
+#define LUT0(ins, pad, opr) \
+ (((opr) << OPRND0_SHIFT) | ((LUT_##pad) << PAD0_SHIFT) | \
+ ((LUT_##ins) << INSTR0_SHIFT))
+
+#define LUT1(ins, pad, opr) (LUT0(ins, pad, opr) << OPRND1_SHIFT)
+
+/* other macros for LUT register. */
+#define FLEXSPI_LUT(x) (FLEXSPI_LUT_BASE + (x) * 4)
+#define FLEXSPI_LUT_NUM 64
+
+/* SEQID -- we can have 16 seqids at most. */
+#define SEQID_QUAD_READ 0
+#define SEQID_WREN 1
+#define SEQID_WRDI 2
+#define SEQID_RDSR 3
+#define SEQID_SE 4
+#define SEQID_CHIP_ERASE 5
+#define SEQID_PP 6
+#define SEQID_RDID 7
+#define SEQID_WRSR 8
+#define SEQID_RDCR 9
+#define SEQID_EN4B 10
+#define SEQID_BRWR 11
+#define SEQID_RD_EVCR 12
+#define SEQID_WD_EVCR 13
+
+#define FLEXSPI_MIN_IOMAP SZ_4M
+
+enum fsl_flexspi_devtype {
+ FSL_FLEXSPI_IMX8QM,
+ FSL_FLEXSPI_IMX8QXP,
+ FSL_FLEXSPI_IMX8MM,
+};
+
+struct fsl_flexspi_devtype_data {
+ enum fsl_flexspi_devtype devtype;
+ int rxfifo;
+ int txfifo;
+ int ahb_buf_size;
+ int driver_data;
+};
+
+static struct fsl_flexspi_devtype_data imx8qm_data = {
+ .devtype = FSL_FLEXSPI_IMX8QM,
+ .rxfifo = 1024,
+ .txfifo = 1024,
+ .ahb_buf_size = 2048,
+ .driver_data = 0,
+};
+
+static struct fsl_flexspi_devtype_data imx8qxp_data = {
+ .devtype = FSL_FLEXSPI_IMX8QXP,
+ .rxfifo = 1024,
+ .txfifo = 1024,
+ .ahb_buf_size = 2048,
+ .driver_data = 0,
+};
+
+static struct fsl_flexspi_devtype_data imx8mm_data = {
+ .devtype = FSL_FLEXSPI_IMX8MM,
+ .rxfifo = 1024,
+ .txfifo = 1024,
+ .ahb_buf_size = 2048,
+ .driver_data = FLEXSPI_QUIRK_QUAD_ONLY,
+};
+
+#define FSL_FLEXSPI_MAX_CHIP 4
+struct fsl_flexspi {
+ struct mtd_info mtd[FSL_FLEXSPI_MAX_CHIP];
+ struct spi_nor nor[FSL_FLEXSPI_MAX_CHIP];
+ void __iomem *iobase;
+ void __iomem *ahb_addr;
+ u32 memmap_phy;
+ u32 memmap_offs;
+ u32 memmap_len;
+ struct clk *clk;
+ struct device *dev;
+ struct completion c;
+ struct fsl_flexspi_devtype_data *devtype_data;
+ u32 nor_size;
+ u32 nor_num;
+ u32 clk_rate;
+ unsigned int chip_base_addr; /* We may support two chips. */
+ bool has_second_chip;
+ u32 ddr_smp;
+ struct mutex lock;
+ struct pm_qos_request pm_qos_req;
+
+#define FLEXSPI_INITILIZED (1 << 0)
+ int flags;
+};
+
+static inline int fsl_flexspi_quad_only(struct fsl_flexspi *flex)
+{
+ return flex->devtype_data->driver_data & FLEXSPI_QUIRK_QUAD_ONLY;
+}
+
+static inline void fsl_flexspi_unlock_lut(struct fsl_flexspi *flex)
+{
+ writel(FLEXSPI_LUTKEY_VALUE, flex->iobase + FLEXSPI_LUTKEY);
+ writel(FLEXSPI_LCKER_UNLOCK, flex->iobase + FLEXSPI_LCKCR);
+}
+
+static inline void fsl_flexspi_lock_lut(struct fsl_flexspi *flex)
+{
+ writel(FLEXSPI_LUTKEY_VALUE, flex->iobase + FLEXSPI_LUTKEY);
+ writel(FLEXSPI_LCKER_LOCK, flex->iobase + FLEXSPI_LCKCR);
+}
+
+static irqreturn_t fsl_flexspi_irq_handler(int irq, void *dev_id)
+{
+ struct fsl_flexspi *flex = dev_id;
+ u32 reg;
+
+ reg = readl(flex->iobase + FLEXSPI_INTR);
+ writel(FLEXSPI_INTR_IPCMDDONE_MASK, flex->iobase + FLEXSPI_INTR);
+ if (reg & FLEXSPI_INTR_IPCMDDONE_MASK)
+ complete(&flex->c);
+
+ return IRQ_HANDLED;
+}
+
+static void fsl_flexspi_init_lut(struct fsl_flexspi *flex)
+{
+ void __iomem *base = flex->iobase;
+ struct spi_nor *nor = &flex->nor[0];
+ u8 addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT;
+ u32 lut_base;
+ u8 op, dm;
+ int i;
+
+ fsl_flexspi_unlock_lut(flex);
+
+ /* Clear all the LUT table */
+ for (i = 0; i < FLEXSPI_LUT_NUM; i++)
+ writel(0, base + FLEXSPI_LUT_BASE + i * 4);
+
+ /* Quad Read and DDR Quad Read*/
+ lut_base = SEQID_QUAD_READ * 4;
+ op = nor->read_opcode;
+ dm = nor->read_dummy;
+
+ /* Normal read */
+ if (op == SPINOR_OP_READ) {
+ writel(LUT0(CMD, PAD1, op) |
+ LUT1(ADDR, PAD1, addrlen),
+ base + FLEXSPI_LUT(lut_base));
+
+ writel(LUT0(FSL_READ, PAD1, 0),
+ base + FLEXSPI_LUT(lut_base + 1));
+ }
+
+ /* Octal DDR read */
+ if (op == SPINOR_OP_READ_1_1_8_D) {
+ writel(LUT0(CMD, PAD1, op) |
+ LUT1(ADDR_DDR, PAD1, addrlen),
+ base + FLEXSPI_LUT(lut_base));
+
+ writel(LUT0(DUMMY_DDR, PAD8, dm * 2)
+ | LUT1(READ_DDR, PAD8, 0),
+ base + FLEXSPI_LUT(lut_base + 1));
+
+ }
+
+ if (nor->flash_read == SPI_NOR_QUAD) {
+ if (op == SPINOR_OP_READ_1_1_4 || op == SPINOR_OP_READ4_1_1_4) {
+ /* read mode : 1-1-4 */
+ writel(LUT0(CMD, PAD1, op) | LUT1(ADDR, PAD1, addrlen),
+ base + FLEXSPI_LUT(lut_base));
+
+ writel(LUT0(DUMMY, PAD1, dm) |
+ LUT1(FSL_READ, PAD4, 0),
+ base + FLEXSPI_LUT(lut_base + 1));
+ } else {
+ dev_err(nor->dev, "Unsupported opcode : 0x%.2x\n", op);
+ }
+ } else if (nor->flash_read == SPI_NOR_DDR_QUAD) {
+ if (op == SPINOR_OP_READ_1_4_4_D ||
+ op == SPINOR_OP_READ4_1_4_4_D) {
+ /* read mode : 1-4-4, such as Spansion s25fl128s. */
+ writel(LUT0(CMD_DDR, PAD1, op)
+ | LUT1(ADDR_DDR, PAD4, addrlen),
+ base + FLEXSPI_LUT(lut_base));
+
+ writel(LUT0(MODE_DDR, PAD4, 0xff)
+ | LUT1(DUMMY, PAD1, dm),
+ base + FLEXSPI_LUT(lut_base + 1));
+
+ writel(LUT0(READ_DDR, PAD4, 0)
+ | LUT1(JMP_ON_CS, PAD1, 0),
+ base + FLEXSPI_LUT(lut_base + 2));
+ } else if (op == SPINOR_OP_READ_1_1_4_D) {
+ /* read mode : 1-1-4, such as Micron N25Q256A. */
+ writel(LUT0(CMD, PAD1, op)
+ | LUT1(ADDR_DDR, PAD1, addrlen),
+ base + FLEXSPI_LUT(lut_base));
+
+ writel(LUT0(DUMMY_DDR, PAD4, 2 * dm)
+ | LUT1(READ_DDR, PAD4, 0),
+ base + FLEXSPI_LUT(lut_base + 1));
+
+ writel(LUT0(JMP_ON_CS, PAD1, 0),
+ base + FLEXSPI_LUT(lut_base + 2));
+ } else {
+ dev_err(nor->dev, "Unsupported opcode : 0x%.2x\n", op);
+ }
+ }
+
+ /* Write enable */
+ lut_base = SEQID_WREN * 4;
+ writel(LUT0(CMD, PAD1, SPINOR_OP_WREN), base + FLEXSPI_LUT(lut_base));
+
+ /* Page Program */
+ lut_base = SEQID_PP * 4;
+ writel(LUT0(CMD, PAD1, nor->program_opcode) | LUT1(ADDR, PAD1, addrlen),
+ base + FLEXSPI_LUT(lut_base));
+ writel(LUT0(FSL_WRITE, PAD1, 0), base + FLEXSPI_LUT(lut_base + 1));
+
+ /* Read Status */
+ lut_base = SEQID_RDSR * 4;
+ writel(LUT0(CMD, PAD1, SPINOR_OP_RDSR) | LUT1(FSL_READ, PAD1, 0x1),
+ base + FLEXSPI_LUT(lut_base));
+
+ /* Erase a sector */
+ lut_base = SEQID_SE * 4;
+ writel(LUT0(CMD, PAD1, nor->erase_opcode) | LUT1(ADDR, PAD1, addrlen),
+ base + FLEXSPI_LUT(lut_base));
+
+ /* Erase the whole chip */
+ lut_base = SEQID_CHIP_ERASE * 4;
+ writel(LUT0(CMD, PAD1, SPINOR_OP_CHIP_ERASE),
+ base + FLEXSPI_LUT(lut_base));
+
+ /* READ ID */
+ lut_base = SEQID_RDID * 4;
+ writel(LUT0(CMD, PAD1, SPINOR_OP_RDID) | LUT1(FSL_READ, PAD1, 0x8),
+ base + FLEXSPI_LUT(lut_base));
+
+ /* Write Register */
+ lut_base = SEQID_WRSR * 4;
+ writel(LUT0(CMD, PAD1, SPINOR_OP_WRSR) | LUT1(FSL_WRITE, PAD1, 0x2),
+ base + FLEXSPI_LUT(lut_base));
+
+ /* Read Configuration Register */
+ lut_base = SEQID_RDCR * 4;
+ writel(LUT0(CMD, PAD1, SPINOR_OP_RDCR) | LUT1(FSL_READ, PAD1, 0x1),
+ base + FLEXSPI_LUT(lut_base));
+
+ /* Write disable */
+ lut_base = SEQID_WRDI * 4;
+ writel(LUT0(CMD, PAD1, SPINOR_OP_WRDI), base + FLEXSPI_LUT(lut_base));
+
+ /* Enter 4 Byte Mode (Micron) */
+ lut_base = SEQID_EN4B * 4;
+ writel(LUT0(CMD, PAD1, SPINOR_OP_EN4B), base + FLEXSPI_LUT(lut_base));
+
+ /* Enter 4 Byte Mode (Spansion) */
+ lut_base = SEQID_BRWR * 4;
+ writel(LUT0(CMD, PAD1, SPINOR_OP_BRWR), base + FLEXSPI_LUT(lut_base));
+
+ /* Read EVCR register */
+ lut_base = SEQID_RD_EVCR * 4;
+ writel(LUT0(CMD, PAD1, SPINOR_OP_RD_EVCR),
+ base + FLEXSPI_LUT(lut_base));
+
+ /* Write EVCR register */
+ lut_base = SEQID_WD_EVCR * 4;
+ writel(LUT0(CMD, PAD1, SPINOR_OP_WD_EVCR),
+ base + FLEXSPI_LUT(lut_base));
+ fsl_flexspi_lock_lut(flex);
+}
+
+/* Get the SEQID for the command */
+static int fsl_flexspi_get_seqid(struct fsl_flexspi *flex, u8 cmd)
+{
+
+ switch (cmd) {
+ case SPINOR_OP_READ_1_1_4_D:
+ case SPINOR_OP_READ_1_1_8_D:
+ case SPINOR_OP_READ_1_4_4_D:
+ case SPINOR_OP_READ4_1_4_4_D:
+ case SPINOR_OP_READ4_1_1_4:
+ case SPINOR_OP_READ_1_1_4:
+ case SPINOR_OP_READ4:
+ case SPINOR_OP_READ:
+ return SEQID_QUAD_READ;
+ case SPINOR_OP_WREN:
+ return SEQID_WREN;
+ case SPINOR_OP_WRDI:
+ return SEQID_WRDI;
+ case SPINOR_OP_RDSR:
+ return SEQID_RDSR;
+ case SPINOR_OP_BE_4K:
+ case SPINOR_OP_SE:
+ return SEQID_SE;
+ case SPINOR_OP_CHIP_ERASE:
+ return SEQID_CHIP_ERASE;
+ case SPINOR_OP_PP:
+ return SEQID_PP;
+ case SPINOR_OP_RDID:
+ return SEQID_RDID;
+ case SPINOR_OP_WRSR:
+ return SEQID_WRSR;
+ case SPINOR_OP_RDCR:
+ return SEQID_RDCR;
+ case SPINOR_OP_EN4B:
+ return SEQID_EN4B;
+ case SPINOR_OP_BRWR:
+ return SEQID_BRWR;
+ case SPINOR_OP_RD_EVCR:
+ return SEQID_RD_EVCR;
+ case SPINOR_OP_WD_EVCR:
+ return SEQID_WD_EVCR;
+ default:
+ dev_err(flex->dev, "Unsupported cmd 0x%.2x\n", cmd);
+ break;
+ }
+ return -EINVAL;
+}
+
+static int
+fsl_flexspi_runcmd(struct fsl_flexspi *flex, u8 cmd, unsigned int addr, int len)
+{
+ void __iomem *base = flex->iobase;
+ int seqid;
+ int seqnum = 0;
+ u32 reg;
+ int err;
+
+ init_completion(&flex->c);
+ dev_dbg(flex->dev, "to 0x%.8x:0x%.8x, len:%d, cmd:%.2x\n",
+ flex->chip_base_addr, addr, len, cmd);
+
+ /* write address */
+ writel(flex->chip_base_addr + addr, base + FLEXSPI_IPCR0);
+
+ seqid = fsl_flexspi_get_seqid(flex, cmd);
+
+ writel((seqnum << FLEXSPI_IPCR1_SEQNUM_SHIFT) |
+ (seqid << FLEXSPI_IPCR1_SEQID_SHIFT) | len,
+ base + FLEXSPI_IPCR1);
+
+ /* wait till controller is idle */
+ do {
+ reg = readl(base + FLEXSPI_STS0);
+ if ((reg & FLEXSPI_STS0_ARB_IDLE_MASK) &&
+ (reg & FLEXSPI_STS0_SEQ_IDLE_MASK))
+ break;
+ udelay(1);
+ } while (1);
+
+ /* trigger the LUT now */
+ writel(1, base + FLEXSPI_IPCMD);
+
+ /* Wait for the interrupt. */
+ if (!wait_for_completion_timeout(&flex->c, msecs_to_jiffies(1000))) {
+ dev_dbg(flex->dev,
+ "cmd 0x%.2x timeout, addr@%.8x, Status0:0x%.8x, Status1:0x%.8x\n",
+ cmd, addr, readl(base + FLEXSPI_STS0),
+ readl(base + FLEXSPI_STS1));
+ err = -ETIMEDOUT;
+ } else {
+ err = 0;
+ }
+
+ return err;
+}
+
+/* Read out the data from the FLEXSPI_RBDR buffer registers. */
+static void fsl_flexspi_read_data(struct fsl_flexspi *flex, int len, u8 *rxbuf)
+{
+ /* u64 tmp; */
+ int i = 0;
+ int size;
+
+ /* invalid RXFIFO first */
+ writel(FLEXSPI_IPRXFCR_CLR_MASK, flex->iobase + FLEXSPI_IPRXFCR);
+ while (len > 0) {
+
+ size = len / 8;
+
+ for (i = 0; i < size; ++i) {
+ /* Wait for RXFIFO available*/
+ while (!(readl(flex->iobase + FLEXSPI_INTR)
+ & FLEXSPI_INTR_IPRXWA_MASK))
+ ;
+
+ /* read 64 bit data once */
+ memcpy(rxbuf, flex->iobase + FLEXSPI_RFDR, 8);
+ rxbuf += 8;
+
+ /* move the FIFO pointer */
+ writel(FLEXSPI_INTR_IPRXWA_MASK,
+ flex->iobase + FLEXSPI_INTR);
+ len -= 8;
+ }
+
+ size = len % 8;
+
+ if (size) {
+ /* Wait for RXFIFO available*/
+ while (!(readl(flex->iobase + FLEXSPI_INTR)
+ & FLEXSPI_INTR_IPRXWA_MASK))
+ ;
+
+ memcpy(rxbuf, flex->iobase + FLEXSPI_RFDR, size);
+ len -= size;
+ }
+
+ writel(FLEXSPI_INTR_IPRXWA_MASK,
+ flex->iobase + FLEXSPI_INTR);
+
+ /* invalid the RXFIFO */
+ writel(FLEXSPI_IPRXFCR_CLR_MASK,
+ flex->iobase + FLEXSPI_IPRXFCR);
+ }
+}
+
+/*
+ * If we have changed the content of the flash by writing or erasing,
+ * we need to invalidate the AHB buffer. If we do not do so, we may read out
+ * the wrong data. The spec tells us reset the AHB domain and Serial Flash
+ * domain at the same time.
+ */
+static inline void fsl_flexspi_invalid(struct fsl_flexspi *flex)
+{
+ u32 reg;
+
+ reg = readl(flex->iobase + FLEXSPI_MCR0);
+ writel(reg | FLEXSPI_MCR0_SWRST_MASK, flex->iobase + FLEXSPI_MCR0);
+
+ /*
+ * The minimum delay : 1 AHB + 2 SFCK clocks.
+ * Delay 1 us is enough.
+ */
+ while (readl(flex->iobase + FLEXSPI_MCR0) & FLEXSPI_MCR0_SWRST_MASK)
+ ;
+
+}
+
+static ssize_t fsl_flexspi_nor_write(struct fsl_flexspi *flex,
+ struct spi_nor *nor, u8 opcode,
+ unsigned int to, u32 *txbuf,
+ unsigned int count)
+{
+ int ret, i;
+ int size;
+
+ dev_dbg(flex->dev, "nor write to 0x%.8x:0x%.8x, len : %d\n",
+ flex->chip_base_addr, to, count);
+
+ /* clear the TX FIFO. */
+ writel(FLEXSPI_IPTXFCR_CLR_MASK, flex->iobase + FLEXSPI_IPTXFCR);
+
+ size = count / 8;
+ for (i = 0; i < size; i++) {
+ /* Wait for TXFIFO empty*/
+ while (!(readl(flex->iobase + FLEXSPI_INTR)
+ & FLEXSPI_INTR_IPTXWE_MASK))
+ ;
+
+ memcpy(flex->iobase + FLEXSPI_TFDR, txbuf, 8);
+ txbuf += 2;
+ writel(FLEXSPI_INTR_IPTXWE_MASK, flex->iobase + FLEXSPI_INTR);
+ }
+
+ size = count % 8;
+ if (size) {
+ /* Wait for TXFIFO empty*/
+ while (!(readl(flex->iobase + FLEXSPI_INTR)
+ & FLEXSPI_INTR_IPTXWE_MASK))
+ ;
+
+ memcpy(flex->iobase + FLEXSPI_TFDR, txbuf, size);
+ writel(FLEXSPI_INTR_IPTXWE_MASK, flex->iobase + FLEXSPI_INTR);
+ }
+
+ /* Trigger it */
+ ret = fsl_flexspi_runcmd(flex, opcode, to, count);
+
+ if (ret == 0)
+ return count;
+
+ return ret;
+}
+
+static void fsl_flexspi_set_map_addr(struct fsl_flexspi *flex)
+{
+ int nor_size = flex->nor_size >> 10;
+ void __iomem *base = flex->iobase;
+
+ writel(nor_size, base + FLEXSPI_FLSHA1CR0);
+ writel(nor_size * 2, base + FLEXSPI_FLSHA2CR0);
+ writel(nor_size * 3, base + FLEXSPI_FLSHB1CR0);
+ writel(nor_size * 4, base + FLEXSPI_FLSHB2CR0);
+}
+
+/*
+ * There are two different ways to read out the data from the flash:
+ * the "IP Command Read" and the "AHB Command Read".
+ *
+ * The IC guy suggests we use the "AHB Command Read" which is faster
+ * then the "IP Command Read". (What's more is that there is a bug in
+ * the "IP Command Read" in the Vybrid.)
+ *
+ * After we set up the registers for the "AHB Command Read", we can use
+ * the memcpy to read the data directly. A "missed" access to the buffer
+ * causes the controller to clear the buffer, and use the sequence pointed
+ * by the FLEXSPI_BFGENCR[SEQID] to initiate a read from the flash.
+ */
+static void fsl_flexspi_init_ahb_read(struct fsl_flexspi *flex)
+{
+ void __iomem *base = flex->iobase;
+ struct spi_nor *nor = &flex->nor[0];
+ /* u32 reg, reg2; */
+ int seqid;
+ int i;
+
+ /* AHB configuration for access buffer 0/1/2 .*/
+ for (i = 0; i < 7; i++)
+ writel(0, base + FLEXSPI_AHBRX_BUF0CR0 + 4 * i);
+ /*
+ * Set ADATSZ with the maximum AHB buffer size to improve the
+ * read performance.
+ */
+ writel((flex->devtype_data->ahb_buf_size / 8 |
+ FLEXSPI_AHBRXBUF0CR7_PREF_MASK),
+ base + FLEXSPI_AHBRX_BUF7CR0);
+
+ /* prefetch and no start address alignment limitation */
+ writel(FLEXSPI_AHBCR_PREF_EN_MASK | FLEXSPI_AHBCR_RDADDROPT_MASK,
+ base + FLEXSPI_AHBCR);
+
+ /* Set the default lut sequence for AHB Read. */
+ seqid = fsl_flexspi_get_seqid(flex, nor->read_opcode);
+ writel(seqid, flex->iobase + FLEXSPI_FLSHA1CR2);
+}
+
+/* This function was used to prepare and enable QSPI clock */
+static int fsl_flexspi_clk_prep_enable(struct fsl_flexspi *flex)
+{
+ int ret;
+
+ ret = clk_prepare_enable(flex->clk);
+ if (ret) {
+ dev_err(flex->dev, "failed to enable the clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+/* This function was used to disable and unprepare QSPI clock */
+static void fsl_flexspi_clk_disable_unprep(struct fsl_flexspi *flex)
+{
+ clk_disable_unprepare(flex->clk);
+}
+
+static int fsl_flexspi_init_rpm(struct fsl_flexspi *flex)
+{
+ struct device *dev = flex->dev;
+
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, FSL_FLEXSPI_RPM_TIMEOUT);
+ pm_runtime_use_autosuspend(dev);
+
+ return 0;
+}
+
+/* We use this function to do some basic init for spi_nor_scan(). */
+static int fsl_flexspi_nor_setup(struct fsl_flexspi *flex)
+{
+ void __iomem *base = flex->iobase;
+ u32 reg;
+ int ret;
+
+ ret = pm_runtime_get_sync(flex->dev);
+ if (ret < 0) {
+ dev_err(flex->dev, "Failed to enable clock %d\n", __LINE__);
+ return ret;
+ }
+
+ /* Reset the module */
+ writel(FLEXSPI_MCR0_SWRST_MASK, base + FLEXSPI_MCR0);
+ do {
+ udelay(1);
+ } while (0x1 & readl(base + FLEXSPI_MCR0));
+
+ /* Disable the module */
+ writel(FLEXSPI_MCR0_MDIS_MASK, base + FLEXSPI_MCR0);
+
+ /* enable module */
+ writel(FLEXSPI_MCR0_AHB_TIMEOUT_MASK | FLEXSPI_MCR0_IP_TIMEOUT_MASK |
+ FLEXSPI_MCR0_OCTCOMB_EN_MASK, base + FLEXSPI_MCR0);
+
+ /* Read the register value */
+ reg = readl(base + FLEXSPI_MCR0);
+
+ /* Init the LUT table. */
+ fsl_flexspi_init_lut(flex);
+
+ /* enable the interrupt */
+ writel(FLEXSPI_INTEN_IPCMDDONE_MASK, flex->iobase + FLEXSPI_INTEN);
+
+ pm_runtime_mark_last_busy(flex->dev);
+ pm_runtime_put_autosuspend(flex->dev);
+
+ return 0;
+}
+
+static int fsl_flexspi_nor_setup_last(struct fsl_flexspi *flex)
+{
+ unsigned long rate = flex->clk_rate;
+ int ret;
+
+ ret = pm_runtime_get_sync(flex->dev);
+ if (ret < 0) {
+ dev_err(flex->dev, "Failed to enable clock %d\n", __LINE__);
+ return ret;
+ }
+
+ /* disable and unprepare clock to avoid glitch pass to controller */
+ fsl_flexspi_clk_disable_unprep(flex);
+
+ ret = clk_set_rate(flex->clk, rate);
+ if (ret)
+ return ret;
+
+ ret = fsl_flexspi_clk_prep_enable(flex);
+ if (ret)
+ return ret;
+
+ /* Init the LUT table again. */
+ fsl_flexspi_init_lut(flex);
+
+ /* Init for AHB read */
+ fsl_flexspi_init_ahb_read(flex);
+
+ pm_runtime_mark_last_busy(flex->dev);
+ pm_runtime_put_autosuspend(flex->dev);
+
+ return 0;
+}
+
+static void fsl_flexspi_set_base_addr(struct fsl_flexspi *flex,
+ struct spi_nor *nor)
+{
+ flex->chip_base_addr = flex->nor_size * (nor - flex->nor);
+}
+
+static int fsl_flexspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
+ int len)
+{
+ int ret;
+ struct fsl_flexspi *flex = nor->priv;
+
+ ret = fsl_flexspi_runcmd(flex, opcode, 0, len);
+ if (ret)
+ return ret;
+
+ fsl_flexspi_read_data(flex, len, buf);
+ return 0;
+}
+
+static int fsl_flexspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
+ int len)
+{
+ struct fsl_flexspi *flex = nor->priv;
+ int ret;
+
+ if (!buf) {
+ ret = fsl_flexspi_runcmd(flex, opcode, 0, 1);
+ if (ret)
+ return ret;
+
+ if (opcode == SPINOR_OP_CHIP_ERASE)
+ fsl_flexspi_invalid(flex);
+
+ } else if (len > 0) {
+ ret = fsl_flexspi_nor_write(flex, nor, opcode, 0,
+ (u32 *)buf, len);
+ } else {
+ dev_err(flex->dev, "invalid cmd %d\n", opcode);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static ssize_t fsl_flexspi_write(struct spi_nor *nor, loff_t to,
+ size_t len, const u_char *buf)
+{
+ struct fsl_flexspi *flex = nor->priv;
+
+ ssize_t ret = fsl_flexspi_nor_write(flex, nor, nor->program_opcode, to,
+ (u32 *)buf, len);
+
+ /* invalid the data in the AHB buffer. */
+ fsl_flexspi_invalid(flex);
+ return ret;
+}
+
+static ssize_t fsl_flexspi_read(struct spi_nor *nor, loff_t from,
+ size_t len, u_char *buf)
+{
+ struct fsl_flexspi *flex = nor->priv;
+ int i, j;
+
+ /* if necessary,ioremap buffer before AHB read, */
+ if (!flex->ahb_addr) {
+ flex->memmap_offs = flex->chip_base_addr + from;
+ flex->memmap_len = len > FLEXSPI_MIN_IOMAP ?
+ len : FLEXSPI_MIN_IOMAP;
+
+ flex->ahb_addr = ioremap_nocache(
+ flex->memmap_phy + flex->memmap_offs,
+ flex->memmap_len);
+ if (!flex->ahb_addr) {
+ dev_err(flex->dev, "ioremap failed\n");
+ return -ENOMEM;
+ }
+ /* ioremap if the data requested is out of range */
+ } else if (flex->chip_base_addr + from < flex->memmap_offs
+ || flex->chip_base_addr + from + len >
+ flex->memmap_offs + flex->memmap_len) {
+ iounmap(flex->ahb_addr);
+
+ flex->memmap_offs = flex->chip_base_addr + from;
+ flex->memmap_len = len > FLEXSPI_MIN_IOMAP ?
+ len : FLEXSPI_MIN_IOMAP;
+ flex->ahb_addr = ioremap_nocache(
+ flex->memmap_phy + flex->memmap_offs,
+ flex->memmap_len);
+ if (!flex->ahb_addr) {
+ dev_err(flex->dev, "ioremap failed\n");
+ return -ENOMEM;
+ }
+ }
+
+ /* For non-8-byte alignment cases */
+ if (from % 8) {
+ j = 8 - (from & 0x7);
+ for (i = 0; i < j; ++i) {
+ memcpy(buf + i, flex->ahb_addr + flex->chip_base_addr
+ + from - flex->memmap_offs + i, 1);
+ }
+ memcpy(buf + j, flex->ahb_addr + flex->chip_base_addr + from
+ - flex->memmap_offs + j, len - j);
+ } else {
+ /* Read out the data directly from the AHB buffer.*/
+ memcpy(buf, flex->ahb_addr + flex->chip_base_addr + from
+ - flex->memmap_offs, len);
+ }
+
+ return len;
+}
+
+static int fsl_flexspi_erase(struct spi_nor *nor, loff_t offs)
+{
+ struct fsl_flexspi *flex = nor->priv;
+ int ret;
+
+ dev_dbg(nor->dev, "%dKiB at 0x%08x:0x%08x\n",
+ nor->mtd.erasesize / 1024, flex->chip_base_addr, (u32)offs);
+
+ ret = fsl_flexspi_runcmd(flex, nor->erase_opcode, offs, 0);
+ if (ret)
+ return ret;
+
+ fsl_flexspi_invalid(flex);
+ return 0;
+}
+
+static int fsl_flexspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
+{
+ struct fsl_flexspi *flex = nor->priv;
+ int ret;
+
+ mutex_lock(&flex->lock);
+
+ ret = pm_runtime_get_sync(flex->dev);
+ if (ret < 0) {
+ dev_err(flex->dev, "Failed to enable clock %d\n", __LINE__);
+ goto err_mutex;
+ }
+
+ fsl_flexspi_set_base_addr(flex, nor);
+ return 0;
+
+err_mutex:
+ mutex_unlock(&flex->lock);
+ return ret;
+}
+
+static void fsl_flexspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
+{
+ struct fsl_flexspi *flex = nor->priv;
+
+ pm_runtime_mark_last_busy(flex->dev);
+ pm_runtime_put_autosuspend(flex->dev);
+ mutex_unlock(&flex->lock);
+}
+
+static const struct of_device_id fsl_flexspi_dt_ids[] = {
+ { .compatible = "fsl,imx8qm-flexspi", .data = (void *)&imx8qm_data, },
+ { .compatible = "fsl,imx8qxp-flexspi", .data = (void *)&imx8qxp_data, },
+ { .compatible = "fsl,imx8mm-flexspi", .data = (void *)&imx8mm_data, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_flexspi_dt_ids);
+
+static int fsl_flexspi_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct fsl_flexspi *flex;
+ struct resource *res;
+ struct spi_nor *nor;
+ struct mtd_info *mtd;
+ int ret, i = 0;
+
+ const struct of_device_id *of_id =
+ of_match_device(fsl_flexspi_dt_ids, &pdev->dev);
+
+ flex = devm_kzalloc(dev, sizeof(*flex), GFP_KERNEL);
+ if (!flex)
+ return -ENOMEM;
+
+ flex->nor_num = of_get_child_count(dev->of_node);
+ if (!flex->nor_num || flex->nor_num > 4)
+ return -ENODEV;
+
+ flex->dev = dev;
+ flex->devtype_data = (struct fsl_flexspi_devtype_data *)of_id->data;
+ platform_set_drvdata(pdev, flex);
+ dev_set_drvdata(dev, flex);
+
+ /* find the resources */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "FlexSPI");
+ if (!res) {
+ dev_err(dev, "FlexSPI get resource IORESOURCE_MEM failed\n");
+ return -ENODEV;
+ }
+
+ flex->iobase = devm_ioremap_resource(dev, res);
+ if (IS_ERR(flex->iobase))
+ return PTR_ERR(flex->iobase);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "FlexSPI-memory");
+ if (!res) {
+ dev_err(dev,
+ "FlexSPI-memory get resource IORESOURCE_MEM failed\n");
+ return -ENODEV;
+ }
+
+ if (!devm_request_mem_region(dev, res->start, resource_size(res),
+ res->name)) {
+ dev_err(dev, "can't request region for resource %pR\n", res);
+ return -EBUSY;
+ }
+
+ flex->memmap_phy = res->start;
+
+ /* find the clocks */
+ flex->clk = devm_clk_get(dev, "fspi");
+ if (IS_ERR(flex->clk))
+ return PTR_ERR(flex->clk);
+
+ /* find ddrsmp value */
+ ret = of_property_read_u32(dev->of_node, "ddrsmp",
+ &flex->ddr_smp);
+ if (ret)
+ flex->ddr_smp = 0;
+
+ /* enable the clock */
+ ret = fsl_flexspi_init_rpm(flex);
+ if (ret) {
+ dev_err(dev, "can not enable the clock\n");
+ goto clk_failed;
+ }
+
+ /* find the irq */
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(dev, "failed to get the irq: %d\n", ret);
+ goto clk_failed;
+ }
+
+ ret = devm_request_irq(dev, ret,
+ fsl_flexspi_irq_handler, 0, pdev->name, flex);
+ if (ret) {
+ dev_err(dev, "failed to request irq: %d\n", ret);
+ goto clk_failed;
+ }
+
+ ret = fsl_flexspi_nor_setup(flex);
+ if (ret)
+ goto clk_failed;
+
+ if (of_get_property(np, "fsl,qspi-has-second-chip", NULL))
+ flex->has_second_chip = true;
+
+ mutex_init(&flex->lock);
+
+ /* iterate the subnodes. */
+ for_each_available_child_of_node(dev->of_node, np) {
+ enum read_mode mode = SPI_NOR_DDR_QUAD;
+ u32 dummy = 0;
+
+ /* skip the holes */
+ if (!flex->has_second_chip)
+ i *= 2;
+
+ nor = &flex->nor[i];
+ mtd = &nor->mtd;
+
+ nor->dev = dev;
+ spi_nor_set_flash_node(nor, np);
+ nor->priv = flex;
+
+ /* fill the hooks */
+ nor->read_reg = fsl_flexspi_read_reg;
+ nor->write_reg = fsl_flexspi_write_reg;
+ nor->read = fsl_flexspi_read;
+ nor->write = fsl_flexspi_write;
+ nor->erase = fsl_flexspi_erase;
+
+ nor->prepare = fsl_flexspi_prep;
+ nor->unprepare = fsl_flexspi_unprep;
+
+ ret = of_property_read_u32(np, "spi-max-frequency",
+ &flex->clk_rate);
+ if (ret < 0)
+ goto mutex_failed;
+
+ /* Can we enable the DDR Quad Read? */
+ ret = of_property_read_u32(np, "spi-nor,ddr-quad-read-dummy",
+ &dummy);
+ if (!ret && dummy > 0)
+ mode = fsl_flexspi_quad_only(flex) ?
+ SPI_NOR_DDR_QUAD : SPI_NOR_DDR_OCTAL;
+
+ /* set the chip address for READID */
+ fsl_flexspi_set_base_addr(flex, nor);
+
+
+ ret = spi_nor_scan(nor, NULL, mode);
+ if (ret)
+ goto mutex_failed;
+
+ ret = mtd_device_register(mtd, NULL, 0);
+ if (ret)
+ goto mutex_failed;
+
+ /* Set the correct NOR size now. */
+ if (flex->nor_size == 0) {
+ flex->nor_size = mtd->size;
+
+ /* Map the SPI NOR to accessiable address */
+ fsl_flexspi_set_map_addr(flex);
+ }
+
+ /*
+ * The TX FIFO is 64 bytes in the Vybrid, but the Page Program
+ * may writes 265 bytes per time. The write is working in the
+ * unit of the TX FIFO, not in the unit of the SPI NOR's page
+ * size.
+ *
+ * So shrink the spi_nor->page_size if it is larger then the
+ * TX FIFO.
+ */
+ if (nor->page_size > flex->devtype_data->txfifo)
+ nor->page_size = flex->devtype_data->txfifo;
+
+ i++;
+ }
+
+ /* finish the rest init. */
+ ret = fsl_flexspi_nor_setup_last(flex);
+ if (ret)
+ goto last_init_failed;
+
+ /* indicate the controller has been initialized */
+ flex->flags |= FLEXSPI_INITILIZED;
+
+ return 0;
+
+last_init_failed:
+ for (i = 0; i < flex->nor_num; i++) {
+ /* skip the holes */
+ if (!flex->has_second_chip)
+ i *= 2;
+ mtd_device_unregister(&flex->mtd[i]);
+ }
+mutex_failed:
+ mutex_destroy(&flex->lock);
+clk_failed:
+ dev_err(dev, "Freescale FlexSPI probe failed\n");
+ return ret;
+}
+
+static int fsl_flexspi_remove(struct platform_device *pdev)
+{
+ struct fsl_flexspi *flex = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < flex->nor_num; i++) {
+ /* skip the holes */
+ if (!flex->has_second_chip)
+ i *= 2;
+ mtd_device_unregister(&flex->nor[i].mtd);
+ }
+
+ /* disable the hardware */
+ writel(FLEXSPI_MCR0_MDIS_MASK, flex->iobase + FLEXSPI_MCR0);
+
+ pm_runtime_disable(flex->dev);
+
+ mutex_destroy(&flex->lock);
+
+ if (flex->ahb_addr)
+ iounmap(flex->ahb_addr);
+
+ return 0;
+}
+
+static int fsl_flexspi_initialized(struct fsl_flexspi *flex)
+{
+ return flex->flags & FLEXSPI_INITILIZED;
+}
+
+static int fsl_flexspi_need_reinit(struct fsl_flexspi *flex)
+{
+ /* we always use the controller in combination mode, so we check this */
+ /* register bit to determine if the controller once lost power, such as */
+ /* suspend/resume, and need to be re-init */
+
+ return !(readl(flex->iobase + FLEXSPI_MCR0) & FLEXSPI_MCR0_OCTCOMB_EN_MASK);
+}
+
+int fsl_flexspi_runtime_suspend(struct device *dev)
+{
+ struct fsl_flexspi *flex = dev_get_drvdata(dev);
+
+ fsl_flexspi_clk_disable_unprep(flex);
+
+ return 0;
+}
+
+int fsl_flexspi_runtime_resume(struct device *dev)
+{
+ struct fsl_flexspi *flex = dev_get_drvdata(dev);
+
+ fsl_flexspi_clk_prep_enable(flex);
+
+ if (fsl_flexspi_initialized(flex) &&
+ fsl_flexspi_need_reinit(flex)) {
+ fsl_flexspi_nor_setup(flex);
+ fsl_flexspi_set_map_addr(flex);
+ fsl_flexspi_nor_setup_last(flex);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops fsl_flexspi_pm_ops = {
+ SET_RUNTIME_PM_OPS(fsl_flexspi_runtime_suspend, fsl_flexspi_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+};
+
+static struct platform_driver fsl_flexspi_driver = {
+ .driver = {
+ .name = "fsl-flexspi",
+ .bus = &platform_bus_type,
+ .pm = &fsl_flexspi_pm_ops,
+ .of_match_table = fsl_flexspi_dt_ids,
+ },
+ .probe = fsl_flexspi_probe,
+ .remove = fsl_flexspi_remove,
+};
+module_platform_driver(fsl_flexspi_driver);
+
+
+MODULE_DESCRIPTION("Freescale FlexSPI Controller Driver");
+MODULE_AUTHOR("Freescale Semiconductor Inc.");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
index 5c82e4ef1904..640eb1010dfc 100644
--- a/drivers/mtd/spi-nor/fsl-quadspi.c
+++ b/drivers/mtd/spi-nor/fsl-quadspi.c
@@ -1,7 +1,8 @@
/*
* Freescale QuadSPI driver.
*
- * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ * Copyright (C) 2013-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -41,9 +42,14 @@
#define QUADSPI_QUIRK_TKT253890 (1 << 2)
/* Controller cannot wake up from wait mode, TKT245618 */
#define QUADSPI_QUIRK_TKT245618 (1 << 3)
+/* Need low level code to control the clock */
+#define QUADSPI_QUIRK_LL_CLK (1 << 4)
/* The registers */
#define QUADSPI_MCR 0x00
+#define MX6SX_QUADSPI_MCR_TX_DDR_DELAY_EN_SHIFT 29
+#define MX6SX_QUADSPI_MCR_TX_DDR_DELAY_EN_MASK \
+ (1 << MX6SX_QUADSPI_MCR_TX_DDR_DELAY_EN_SHIFT)
#define QUADSPI_MCR_RESERVED_SHIFT 16
#define QUADSPI_MCR_RESERVED_MASK (0xF << QUADSPI_MCR_RESERVED_SHIFT)
#define QUADSPI_MCR_MDIS_SHIFT 14
@@ -61,6 +67,11 @@
#define QUADSPI_MCR_SWRSTSD_SHIFT 0
#define QUADSPI_MCR_SWRSTSD_MASK (1 << QUADSPI_MCR_SWRSTSD_SHIFT)
+#define QUADSPI_FLSHCR 0x0c
+#define QUADSPI_FLSHCR_TDH_SHIFT 16
+#define QUADSPI_FLSHCR_TDH_MASK (3 << QUADSPI_FLSHCR_TDH_SHIFT)
+#define QUADSPI_FLSHCR_TDH_DDR_EN (1 << QUADSPI_FLSHCR_TDH_SHIFT)
+
#define QUADSPI_IPCR 0x08
#define QUADSPI_IPCR_SEQID_SHIFT 24
#define QUADSPI_IPCR_SEQID_MASK (0xF << QUADSPI_IPCR_SEQID_SHIFT)
@@ -205,15 +216,49 @@
#define SEQID_RDCR 9
#define SEQID_EN4B 10
#define SEQID_BRWR 11
+#define SEQID_RD_EVCR 12
+#define SEQID_WD_EVCR 13
+
+/* last two lut slots for dynamic luts*/
+#define SEQID_DYNAMIC_CMD0 14
+#define SEQID_DYNAMIC_CMD1 15
+
+#define QUADSPI_MIN_IOMAP SZ_4M
-#define QUADSPI_MIN_IOMAP SZ_4M
+/* dynamic lut configs */
+#define MAX_LUT_REGS 4
+struct lut_desc {
+ u8 cmd;
+ u32 lut[MAX_LUT_REGS];
+};
+/*
+ * define two lut_des in the struct because many commands use in pairs.
+ * To add a single command, just leave the second desc as blank.
+ */
+struct lut_desc_pair {
+ struct lut_desc lut_desc0;
+ struct lut_desc lut_desc1;
+};
+
+struct lut_desc_pair current_lut_pair;
+
+static const struct lut_desc_pair dynamic_lut_table[] = {
+ /* VCR RD/WR pair */
+ { {SPINOR_OP_RD_VCR, {LUT0(CMD, PAD1, SPINOR_OP_RD_EVCR) |
+ LUT1(FSL_READ, PAD1, 0x1)} },
+ {SPINOR_OP_WR_VCR, {LUT0(CMD, PAD1, SPINOR_OP_WD_EVCR) |
+ LUT1(FSL_WRITE, PAD1, 0x1)} },
+ },
+ {/* sentinel */},
+};
enum fsl_qspi_devtype {
FSL_QUADSPI_VYBRID,
FSL_QUADSPI_IMX6SX,
FSL_QUADSPI_IMX7D,
FSL_QUADSPI_IMX6UL,
FSL_QUADSPI_LS1021A,
+ FSL_QUADSPI_IMX7ULP,
};
struct fsl_qspi_devtype_data {
@@ -267,6 +312,15 @@ static struct fsl_qspi_devtype_data ls1021a_data = {
.driver_data = 0,
};
+static struct fsl_qspi_devtype_data imx7ulp_data = {
+ .devtype = FSL_QUADSPI_IMX7ULP,
+ .rxfifo = 64,
+ .txfifo = 64,
+ .ahb_buf_size = 128,
+ .driver_data = QUADSPI_QUIRK_LL_CLK
+ | QUADSPI_QUIRK_TKT253890
+};
+
#define FSL_QSPI_MAX_CHIP 4
struct fsl_qspi {
struct spi_nor nor[FSL_QSPI_MAX_CHIP];
@@ -285,6 +339,7 @@ struct fsl_qspi {
unsigned int chip_base_addr; /* We may support two chips. */
bool has_second_chip;
bool big_endian;
+ u32 ddr_smp;
struct mutex lock;
struct pm_qos_request pm_qos_req;
};
@@ -309,6 +364,11 @@ static inline int needs_wakeup_wait_mode(struct fsl_qspi *q)
return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT245618;
}
+static inline int needs_ll_handle_clock(struct fsl_qspi *q)
+{
+ return q->devtype_data->driver_data & QUADSPI_QUIRK_LL_CLK;
+}
+
/*
* R/W functions for big- or little-endian registers:
* The qSPI controller's endian is independent of the CPU core's endian.
@@ -372,8 +432,10 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
{
void __iomem *base = q->iobase;
int rxfifo = q->devtype_data->rxfifo;
+ struct spi_nor *nor = &q->nor[0];
+ u8 addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT;
u32 lut_base;
- u8 cmd, addrlen, dummy;
+ u8 op, dm;
int i;
fsl_qspi_unlock_lut(q);
@@ -382,24 +444,57 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
for (i = 0; i < QUADSPI_LUT_NUM; i++)
qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4);
- /* Quad Read */
+ /* Quad Read and DDR Quad Read*/
lut_base = SEQID_QUAD_READ * 4;
-
- if (q->nor_size <= SZ_16M) {
- cmd = SPINOR_OP_READ_1_1_4;
- addrlen = ADDR24BIT;
- dummy = 8;
- } else {
- /* use the 4-byte address */
- cmd = SPINOR_OP_READ_1_1_4;
- addrlen = ADDR32BIT;
- dummy = 8;
- }
-
- qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
+ op = nor->read_opcode;
+ dm = nor->read_dummy;
+ if (nor->flash_read == SPI_NOR_QUAD) {
+ if (op == SPINOR_OP_READ_1_1_4 || op == SPINOR_OP_READ4_1_1_4) {
+ /* read mode : 1-1-4 */
+ qspi_writel(q, LUT0(CMD, PAD1, op) | LUT1(ADDR, PAD1, addrlen),
+ base + QUADSPI_LUT(lut_base));
+
+ qspi_writel(q, LUT0(DUMMY, PAD1, dm) | LUT1(FSL_READ, PAD4, rxfifo),
+ base + QUADSPI_LUT(lut_base + 1));
+ } else {
+ dev_err(nor->dev, "Unsupported opcode : 0x%.2x\n", op);
+ }
+ } else if (nor->flash_read == SPI_NOR_NORMAL) {
+ writel(LUT0(CMD, PAD1, op) | LUT1(ADDR, PAD1, addrlen),
base + QUADSPI_LUT(lut_base));
- qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo),
+ writel(LUT0(FSL_READ, PAD1, rxfifo) | LUT1(JMP_ON_CS, PAD1, 0),
base + QUADSPI_LUT(lut_base + 1));
+ } else if (nor->flash_read == SPI_NOR_DDR_QUAD) {
+ if (op == SPINOR_OP_READ_1_4_4_D ||
+ op == SPINOR_OP_READ4_1_4_4_D) {
+ /* read mode : 1-4-4, such as Spansion s25fl128s. */
+ qspi_writel(q, LUT0(CMD, PAD1, op)
+ | LUT1(ADDR_DDR, PAD4, addrlen),
+ base + QUADSPI_LUT(lut_base));
+
+ qspi_writel(q, LUT0(MODE_DDR, PAD4, 0xff)
+ | LUT1(DUMMY, PAD1, dm),
+ base + QUADSPI_LUT(lut_base + 1));
+
+ qspi_writel(q, LUT0(FSL_READ_DDR, PAD4, rxfifo)
+ | LUT1(JMP_ON_CS, PAD1, 0),
+ base + QUADSPI_LUT(lut_base + 2));
+ } else if (op == SPINOR_OP_READ_1_1_4_D) {
+ /* read mode : 1-1-4, such as Micron N25Q256A. */
+ qspi_writel(q, LUT0(CMD, PAD1, op)
+ | LUT1(ADDR_DDR, PAD1, addrlen),
+ base + QUADSPI_LUT(lut_base));
+
+ qspi_writel(q, LUT0(DUMMY, PAD1, dm)
+ | LUT1(FSL_READ_DDR, PAD4, rxfifo),
+ base + QUADSPI_LUT(lut_base + 1));
+
+ qspi_writel(q, LUT0(JMP_ON_CS, PAD1, 0),
+ base + QUADSPI_LUT(lut_base + 2));
+ } else {
+ dev_err(nor->dev, "Unsupported opcode : 0x%.2x\n", op);
+ }
+ }
/* Write enable */
lut_base = SEQID_WREN * 4;
@@ -408,18 +503,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
/* Page Program */
lut_base = SEQID_PP * 4;
-
- if (q->nor_size <= SZ_16M) {
- cmd = SPINOR_OP_PP;
- addrlen = ADDR24BIT;
- } else {
- /* use the 4-byte address */
- cmd = SPINOR_OP_PP;
- addrlen = ADDR32BIT;
- }
-
- qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
- base + QUADSPI_LUT(lut_base));
+ qspi_writel(q, LUT0(CMD, PAD1, nor->program_opcode) | LUT1(ADDR, PAD1, addrlen),
+ base + QUADSPI_LUT(lut_base));
qspi_writel(q, LUT0(FSL_WRITE, PAD1, 0),
base + QUADSPI_LUT(lut_base + 1));
@@ -431,12 +516,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
/* Erase a sector */
lut_base = SEQID_SE * 4;
-
- cmd = q->nor[0].erase_opcode;
- addrlen = q->nor_size <= SZ_16M ? ADDR24BIT : ADDR32BIT;
-
- qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
- base + QUADSPI_LUT(lut_base));
+ qspi_writel(q, LUT0(CMD, PAD1, nor->erase_opcode) | LUT1(ADDR, PAD1, addrlen),
+ base + QUADSPI_LUT(lut_base));
/* Erase the whole chip */
lut_base = SEQID_CHIP_ERASE * 4;
@@ -476,14 +557,85 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q)
qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_BRWR),
base + QUADSPI_LUT(lut_base));
+ /* Read EVCR register */
+ lut_base = SEQID_RD_EVCR * 4;
+ writel(LUT0(CMD, PAD1, SPINOR_OP_RD_EVCR), base + QUADSPI_LUT(lut_base));
+
+ /* Write EVCR register */
+ lut_base = SEQID_WD_EVCR * 4;
+ writel(LUT0(CMD, PAD1, SPINOR_OP_WD_EVCR), base + QUADSPI_LUT(lut_base));
fsl_qspi_lock_lut(q);
}
+static int fsl_qspi_clk_prep_enable(struct fsl_qspi *q);
+static void fsl_qspi_clk_disable_unprep(struct fsl_qspi *q);
+
+static int fsl_qspi_update_dynamic_lut(struct fsl_qspi *q, int index)
+{
+ void __iomem *base = q->iobase;
+ u32 lut_base;
+ int i;
+ int size;
+
+ fsl_qspi_unlock_lut(q);
+
+ lut_base = SEQID_DYNAMIC_CMD0 * 4;
+ size = ARRAY_SIZE(dynamic_lut_table[index].lut_desc0.lut);
+ for (i = 0; i < size; i++) {
+ writel(dynamic_lut_table[index].lut_desc0.lut[i],
+ base + QUADSPI_LUT(lut_base + i));
+ }
+
+ lut_base = SEQID_DYNAMIC_CMD1 * 4;
+ size = ARRAY_SIZE(dynamic_lut_table[index].lut_desc1.lut);
+ for (i = 0; i < size; i++) {
+ writel(dynamic_lut_table[index].lut_desc1.lut[i],
+ base + QUADSPI_LUT(lut_base + i));
+ }
+
+ fsl_qspi_lock_lut(q);
+
+ return 0;
+}
+
+static int fsl_qspi_search_dynamic_lut(struct fsl_qspi *q, u8 cmd)
+{
+ int i;
+ int ret = 0;
+
+ if (cmd == current_lut_pair.lut_desc0.cmd)
+ return SEQID_DYNAMIC_CMD0;
+ if (cmd == current_lut_pair.lut_desc1.cmd)
+ return SEQID_DYNAMIC_CMD1;
+ for (i = 0; i < ARRAY_SIZE(dynamic_lut_table); i++) {
+ if (cmd == dynamic_lut_table[i].lut_desc0.cmd)
+ ret = SEQID_DYNAMIC_CMD0;
+ if (cmd == dynamic_lut_table[i].lut_desc1.cmd)
+ ret = SEQID_DYNAMIC_CMD1;
+ if (ret) {
+ if (fsl_qspi_update_dynamic_lut(q, i)) {
+ pr_err(" failed to update dynamic lut\n");
+ return 0;
+ }
+ current_lut_pair = dynamic_lut_table[i];
+ return ret;
+ }
+ }
+ return ret;
+}
+
/* Get the SEQID for the command */
static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
{
+ int ret;
+
switch (cmd) {
+ case SPINOR_OP_READ_1_1_4_D:
+ case SPINOR_OP_READ_1_4_4_D:
+ case SPINOR_OP_READ4_1_4_4_D:
+ case SPINOR_OP_READ4_1_1_4:
case SPINOR_OP_READ_1_1_4:
+ case SPINOR_OP_READ:
return SEQID_QUAD_READ;
case SPINOR_OP_WREN:
return SEQID_WREN;
@@ -491,6 +643,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
return SEQID_WRDI;
case SPINOR_OP_RDSR:
return SEQID_RDSR;
+ case SPINOR_OP_BE_4K:
case SPINOR_OP_SE:
return SEQID_SE;
case SPINOR_OP_CHIP_ERASE:
@@ -507,9 +660,16 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
return SEQID_EN4B;
case SPINOR_OP_BRWR:
return SEQID_BRWR;
+ case SPINOR_OP_RD_EVCR:
+ return SEQID_RD_EVCR;
+ case SPINOR_OP_WD_EVCR:
+ return SEQID_WD_EVCR;
default:
if (cmd == q->nor[0].erase_opcode)
return SEQID_SE;
+ ret = fsl_qspi_search_dynamic_lut(q, cmd);
+ if (ret)
+ return ret;
dev_err(q->dev, "Unsupported cmd 0x%.2x\n", cmd);
break;
}
@@ -680,6 +840,8 @@ static void fsl_qspi_set_map_addr(struct fsl_qspi *q)
static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
{
void __iomem *base = q->iobase;
+ struct spi_nor *nor = &q->nor[0];
+ u32 reg, reg2;
int seqid;
/* AHB configuration for access buffer 0/1/2 .*/
@@ -701,9 +863,40 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
qspi_writel(q, 0, base + QUADSPI_BUF2IND);
/* Set the default lut sequence for AHB Read. */
- seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode);
+ seqid = fsl_qspi_get_seqid(q, nor->read_opcode);
qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
q->iobase + QUADSPI_BFGENCR);
+
+ /* enable the DDR quad read */
+ if (nor->flash_read == SPI_NOR_DDR_QUAD) {
+ reg = readl(q->iobase + QUADSPI_MCR);
+
+ /* Firstly, disable the module */
+ qspi_writel(q, reg | QUADSPI_MCR_MDIS_MASK,
+ q->iobase + QUADSPI_MCR);
+
+ /* Set the Sampling Register for DDR */
+ reg2 = readl(q->iobase + QUADSPI_SMPR);
+ reg2 &= ~QUADSPI_SMPR_DDRSMP_MASK;
+ reg2 |= ((q->ddr_smp << QUADSPI_SMPR_DDRSMP_SHIFT) &
+ QUADSPI_SMPR_DDRSMP_MASK);
+ qspi_writel(q, reg2, q->iobase + QUADSPI_SMPR);
+
+ /* Enable the module again (enable the DDR too) */
+ reg |= QUADSPI_MCR_DDR_EN_MASK;
+ if (q->devtype_data->devtype == FSL_QUADSPI_IMX6SX)
+ reg |= MX6SX_QUADSPI_MCR_TX_DDR_DELAY_EN_MASK;
+
+ qspi_writel(q, reg, q->iobase + QUADSPI_MCR);
+
+ if ((q->devtype_data->devtype == FSL_QUADSPI_IMX6UL) ||
+ (q->devtype_data->devtype == FSL_QUADSPI_IMX7D)) {
+ reg = readl(q->iobase + QUADSPI_FLSHCR);
+ reg &= ~QUADSPI_FLSHCR_TDH_MASK;
+ reg |= QUADSPI_FLSHCR_TDH_DDR_EN;
+ qspi_writel(q, reg, q->iobase + QUADSPI_FLSHCR);
+ }
+ }
}
/* This function was used to prepare and enable QSPI clock */
@@ -750,13 +943,21 @@ static int fsl_qspi_nor_setup(struct fsl_qspi *q)
/* the default frequency, we will change it in the future. */
ret = clk_set_rate(q->clk, 66000000);
- if (ret)
+ if (ret && !needs_ll_handle_clock(q))
return ret;
ret = fsl_qspi_clk_prep_enable(q);
if (ret)
return ret;
+ if ((q->devtype_data->devtype == FSL_QUADSPI_IMX6UL) ||
+ (q->devtype_data->devtype == FSL_QUADSPI_IMX7D)) {
+ /* clear the DDR_EN bit for 6UL and 7D */
+ reg = readl(base + QUADSPI_MCR);
+ writel(~(QUADSPI_MCR_DDR_EN_MASK) & reg, base + QUADSPI_MCR);
+ udelay(1);
+ }
+
/* Reset the module */
qspi_writel(q, QUADSPI_MCR_SWRSTSD_MASK | QUADSPI_MCR_SWRSTHD_MASK,
base + QUADSPI_MCR);
@@ -800,7 +1001,7 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q)
fsl_qspi_clk_disable_unprep(q);
ret = clk_set_rate(q->clk, rate);
- if (ret)
+ if (ret && !needs_ll_handle_clock(q))
return ret;
ret = fsl_qspi_clk_prep_enable(q);
@@ -809,6 +1010,7 @@ static int fsl_qspi_nor_setup_last(struct fsl_qspi *q)
/* Init the LUT table again. */
fsl_qspi_init_lut(q);
+ fsl_qspi_update_dynamic_lut(q, 0);
/* Init for AHB read */
fsl_qspi_init_abh_read(q);
@@ -822,6 +1024,8 @@ static const struct of_device_id fsl_qspi_dt_ids[] = {
{ .compatible = "fsl,imx7d-qspi", .data = (void *)&imx7d_data, },
{ .compatible = "fsl,imx6ul-qspi", .data = (void *)&imx6ul_data, },
{ .compatible = "fsl,ls1021a-qspi", .data = (void *)&ls1021a_data, },
+ { .compatible = "fsl,imx6ull-qspi", .data = (void *)&imx6ul_data, },
+ { .compatible = "fsl,imx7ulp-qspi", .data = (void *)&imx7ulp_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids);
@@ -887,6 +1091,7 @@ static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
{
struct fsl_qspi *q = nor->priv;
u8 cmd = nor->read_opcode;
+ int i, j;
/* if necessary,ioremap buffer before AHB read, */
if (!q->ahb_addr) {
@@ -921,9 +1126,20 @@ static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from,
cmd, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
len);
- /* Read out the data directly from the AHB buffer.*/
- memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
- len);
+ /* For non-8-byte alignment cases */
+ if (from % 8) {
+ j = 8 - (from & 0x7);
+ for (i = 0; i < j; ++i) {
+ memcpy(buf + i, q->ahb_addr + q->chip_base_addr + from
+ - q->memmap_offs + i, 1);
+ }
+ memcpy(buf + j, q->ahb_addr + q->chip_base_addr + from
+ - q->memmap_offs + j, len - j);
+ } else {
+ /* Read out the data directly from the AHB buffer.*/
+ memcpy(buf, q->ahb_addr + q->chip_base_addr + from
+ - q->memmap_offs, len);
+ }
return len;
}
@@ -997,6 +1213,10 @@ static int fsl_qspi_probe(struct platform_device *pdev)
/* find the resources */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI");
+ if (!res) {
+ dev_err(dev, "QuadSPI get resource IORESOURCE_MEM failed\n");
+ return -ENODEV;
+ }
q->iobase = devm_ioremap_resource(dev, res);
if (IS_ERR(q->iobase))
return PTR_ERR(q->iobase);
@@ -1004,6 +1224,11 @@ static int fsl_qspi_probe(struct platform_device *pdev)
q->big_endian = of_property_read_bool(np, "big-endian");
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"QuadSPI-memory");
+ if (!res) {
+ dev_err(dev,
+ "QuadSPI-memory get resource IORESOURCE_MEM failed\n");
+ return -ENODEV;
+ }
if (!devm_request_mem_region(dev, res->start, resource_size(res),
res->name)) {
dev_err(dev, "can't request region for resource %pR\n", res);
@@ -1021,6 +1246,12 @@ static int fsl_qspi_probe(struct platform_device *pdev)
if (IS_ERR(q->clk))
return PTR_ERR(q->clk);
+ /* find ddrsmp value */
+ ret = of_property_read_u32(dev->of_node, "ddrsmp",
+ &q->ddr_smp);
+ if (ret)
+ q->ddr_smp = 0;
+
ret = fsl_qspi_clk_prep_enable(q);
if (ret) {
dev_err(dev, "can not enable the clock\n");
@@ -1052,6 +1283,9 @@ static int fsl_qspi_probe(struct platform_device *pdev)
/* iterate the subnodes. */
for_each_available_child_of_node(dev->of_node, np) {
+ enum read_mode mode = SPI_NOR_QUAD;
+ u32 dummy = 0;
+
/* skip the holes */
if (!q->has_second_chip)
i *= 2;
@@ -1078,10 +1312,16 @@ static int fsl_qspi_probe(struct platform_device *pdev)
if (ret < 0)
goto mutex_failed;
+ /* Can we enable the DDR Quad Read? */
+ ret = of_property_read_u32(np, "spi-nor,ddr-quad-read-dummy",
+ &dummy);
+ if (!ret && dummy > 0)
+ mode = SPI_NOR_DDR_QUAD;
+
/* set the chip address for READID */
fsl_qspi_set_base_addr(q, nor);
- ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD);
+ ret = spi_nor_scan(nor, NULL, mode);
if (ret)
goto mutex_failed;
@@ -1162,6 +1402,7 @@ static int fsl_qspi_remove(struct platform_device *pdev)
static int fsl_qspi_suspend(struct platform_device *pdev, pm_message_t state)
{
+ pinctrl_pm_select_sleep_state(&pdev->dev);
return 0;
}
@@ -1170,6 +1411,8 @@ static int fsl_qspi_resume(struct platform_device *pdev)
int ret;
struct fsl_qspi *q = platform_get_drvdata(pdev);
+ pinctrl_pm_select_default_state(&pdev->dev);
+
ret = fsl_qspi_clk_prep_enable(q);
if (ret)
return ret;
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 21dde5249085..d0bb9c1a7b1e 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -3,7 +3,8 @@
* influence from lart.c (Abraham Van Der Merwe) and mtd_dataflash.c
*
* Copyright (C) 2005, Intec Automation Inc.
- * Copyright (C) 2014, Freescale Semiconductor, Inc.
+ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -75,6 +76,8 @@ struct flash_info {
* bit. Must be used with
* SPI_NOR_HAS_LOCK.
*/
+#define SPI_NOR_DDR_QUAD_READ BIT(10) /* Flash supports DDR Quad Read */
+#define SPI_NOR_DDR_OCTAL_READ BIT(11) /* Flash supports DDR Octal Read */
};
#define JEDEC_MFR(info) ((info)->id[0])
@@ -146,9 +149,26 @@ static int read_cr(struct spi_nor *nor)
static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
{
switch (nor->flash_read) {
+ case SPI_NOR_DDR_QUAD:
+ case SPI_NOR_DDR_OCTAL:
+ {
+ struct device_node *np = spi_nor_get_flash_node(nor);
+ u32 dummy;
+
+ /*
+ * The m25p80.c can not support the DDR quad read.
+ * We set the dummy cycles to 8 by default. The SPI NOR
+ * controller driver can set it in its child DT node.
+ * We parse it out here.
+ */
+ if (!of_property_read_u32(np, "spi-nor,ddr-quad-read-dummy",
+ &dummy))
+ return dummy;
+ }
case SPI_NOR_FAST:
case SPI_NOR_DUAL:
case SPI_NOR_QUAD:
+ case SPI_NOR_OCTAL:
return 8;
case SPI_NOR_NORMAL:
return 0;
@@ -198,6 +218,7 @@ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info,
switch (JEDEC_MFR(info)) {
case SNOR_MFR_MICRON:
+ case SNOR_MFR_MICRONO:
/* Some Micron need WREN command; all will accept it */
need_wren = true;
case SNOR_MFR_MACRONIX:
@@ -869,10 +890,12 @@ static const struct flash_info spi_nor_ids[] = {
{ "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) },
{ "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
{ "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
+ { "mx25r6435f", INFO(0xc22817, 0, 64 * 1024, 128, 0) },
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
+ { "mx25l51245g", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_DDR_QUAD_READ) },
{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
{ "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
@@ -882,12 +905,14 @@ static const struct flash_info spi_nor_ids[] = {
{ "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q064a", INFO(0x20bb17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) },
{ "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
+ { "mt25qu256", INFO(0x20bb19, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_DDR_QUAD_READ) },
{ "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
- { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) },
+ { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_DDR_QUAD_READ) },
{ "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
{ "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
{ "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
{ "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
+ {"mt35xu512aba", INFO(0x2c5b1a, 0, 128 * 1024, 512, SECT_4K | SPI_NOR_DDR_OCTAL_READ) },
/* PMC */
{ "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) },
@@ -906,6 +931,7 @@ static const struct flash_info spi_nor_ids[] = {
{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) },
{ "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) },
{ "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
+ { "s25fl128s", INFO(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_QUAD_READ | SPI_NOR_DDR_QUAD_READ) },
{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) },
@@ -1172,9 +1198,6 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
ssize_t written;
page_offset = (to + i) & (nor->page_size - 1);
- WARN_ONCE(page_offset,
- "Writing at offset %zu into a NOR page. Writing partial pages may decrease reliability and increase wear of NOR flash.",
- page_offset);
/* the size of data remaining on the first page */
page_remain = min_t(size_t,
nor->page_size - page_offset, len - i);
@@ -1272,6 +1295,36 @@ static int spansion_quad_enable(struct spi_nor *nor)
return 0;
}
+static int set_ddr_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+{
+ int status;
+
+ switch (JEDEC_MFR(info)) {
+ case CFI_MFR_AMD: /* Spansion, actually */
+ status = spansion_quad_enable(nor);
+ if (status) {
+ dev_err(nor->dev,
+ "Spansion DDR quad-read not enabled\n");
+ return status;
+ }
+ return status;
+ case CFI_MFR_MACRONIX:
+ status = macronix_quad_enable(nor);
+ if (status) {
+ dev_err(nor->dev,
+ "Macronix DDR quad-read not enabled\n");
+ return status;
+ }
+ return status;
+ case CFI_MFR_ST: /* Micron, actually */
+ case CFI_MFR_MICRON: /* Original Micron */
+ /* DTR quad read works with the Extended SPI protocol. */
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
{
int status;
@@ -1285,6 +1338,7 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
}
return status;
case SNOR_MFR_MICRON:
+ case SNOR_MFR_MICRONO:
return 0;
default:
status = spansion_quad_enable(nor);
@@ -1379,7 +1433,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
mtd->_read = spi_nor_read;
/* NOR protection support for STmicro/Micron chips and similar */
- if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
+ if (JEDEC_MFR(info) == SNOR_MFR_MICRON || SNOR_MFR_MICRONO ||
info->flags & SPI_NOR_HAS_LOCK) {
nor->flash_lock = stm_lock;
nor->flash_unlock = stm_unlock;
@@ -1440,8 +1494,18 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
if (info->flags & SPI_NOR_NO_FR)
nor->flash_read = SPI_NOR_NORMAL;
- /* Quad/Dual-read mode takes precedence over fast/normal */
- if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
+ /* DDR Octal/Quad/Dual-read mode takes precedence over fast/normal */
+ if (mode == SPI_NOR_DDR_OCTAL && info->flags & SPI_NOR_DDR_OCTAL_READ) {
+ nor->flash_read = SPI_NOR_DDR_OCTAL;
+ } else if (mode == SPI_NOR_DDR_QUAD &&
+ info->flags & SPI_NOR_DDR_QUAD_READ) {
+ ret = set_ddr_quad_mode(nor, info);
+ if (ret) {
+ dev_err(dev, "DDR quad mode not supported\n");
+ return ret;
+ }
+ nor->flash_read = SPI_NOR_DDR_QUAD;
+ } else if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
ret = set_quad_mode(nor, info);
if (ret) {
dev_err(dev, "quad mode not supported\n");
@@ -1454,6 +1518,23 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
/* Default commands */
switch (nor->flash_read) {
+ case SPI_NOR_DDR_OCTAL:
+ nor->read_opcode = SPINOR_OP_READ_1_1_8_D;
+ break;
+ case SPI_NOR_DDR_QUAD:
+ if (JEDEC_MFR(info) == CFI_MFR_AMD) { /* Spansion */
+ nor->read_opcode = SPINOR_OP_READ_1_4_4_D;
+ } else if (JEDEC_MFR(info) == CFI_MFR_ST) {
+ nor->read_opcode = SPINOR_OP_READ_1_1_4_D;
+ } else if (JEDEC_MFR(info) == CFI_MFR_MICRON) {
+ nor->read_opcode = SPINOR_OP_READ_1_1_4_D;
+ } else if (JEDEC_MFR(info) == CFI_MFR_MACRONIX) {
+ nor->read_opcode = SPINOR_OP_READ_1_4_4_D;
+ } else {
+ dev_err(dev, "DDR Quad Read is not supported.\n");
+ return -EINVAL;
+ }
+ break;
case SPI_NOR_QUAD:
nor->read_opcode = SPINOR_OP_READ_1_1_4;
break;
@@ -1481,6 +1562,13 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) {
/* Dedicated 4-byte command set */
switch (nor->flash_read) {
+ case SPI_NOR_DDR_OCTAL:
+ case SPI_NOR_OCTAL:
+ nor->read_opcode = SPINOR_OP_READ_1_1_8_D;
+ break;
+ case SPI_NOR_DDR_QUAD:
+ nor->read_opcode = SPINOR_OP_READ4_1_4_4_D;
+ break;
case SPI_NOR_QUAD:
nor->read_opcode = SPINOR_OP_READ4_1_1_4;
break;
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index ad2b57c6b13f..35c76e4053f8 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -628,7 +628,7 @@ static int io_init(struct ubi_device *ubi, int max_beb_per1024)
dbg_gen("sizeof(struct ubi_ainf_peb) %zu", sizeof(struct ubi_ainf_peb));
dbg_gen("sizeof(struct ubi_wl_entry) %zu", sizeof(struct ubi_wl_entry));
- if (ubi->mtd->numeraseregions != 0) {
+ if (ubi->mtd->numeraseregions > 1) {
/*
* Some flashes have several erase regions. Different regions
* may have different eraseblock size and other
diff --git a/drivers/mxc/Kconfig b/drivers/mxc/Kconfig
new file mode 100755
index 000000000000..6428e2081e9a
--- /dev/null
+++ b/drivers/mxc/Kconfig
@@ -0,0 +1,47 @@
+# drivers/mxc/Kconfig
+
+if ARCH_MXC || ARCH_MXC_ARM64
+
+menu "MXC support drivers"
+
+#drivers common to MXC and MX8 goes here
+source "drivers/mxc/gpu-viv/Kconfig"
+source "drivers/mxc/hantro/Kconfig"
+source "drivers/mxc/hdp/Kconfig"
+source "drivers/mxc/hdp-cec/Kconfig"
+
+if ARCH_MXC_ARM64
+source "drivers/mxc/hantro_845/Kconfig"
+source "drivers/mxc/hantro_845_h1/Kconfig"
+source "drivers/mxc/vpu-malone/Kconfig"
+source "drivers/mxc/vpu-decoder-b0/Kconfig"
+source "drivers/mxc/vpu-encoder-b0/Kconfig"
+endif
+
+if ARCH_MXC
+config MXC_IPU
+ bool "Image Processing Unit Driver"
+ select MXC_IPU_V3
+ help
+ If you plan to use the Image Processing unit, say
+ Y here. IPU is needed by Framebuffer and V4L2 drivers.
+
+source "drivers/mxc/ipu3/Kconfig"
+source "drivers/mxc/mipi/Kconfig"
+source "drivers/mxc/vpu/Kconfig"
+source "drivers/mxc/hdmi-cec/Kconfig"
+
+endif
+
+config MXC_SIM
+ tristate "MXC SIM support"
+ default n
+ ---help---
+ Say Y to get MXC SIM support.
+
+source "drivers/mxc/sim/Kconfig"
+source "drivers/mxc/mlb/Kconfig"
+
+endmenu
+
+endif
diff --git a/drivers/mxc/Makefile b/drivers/mxc/Makefile
new file mode 100755
index 000000000000..109166cbc1d2
--- /dev/null
+++ b/drivers/mxc/Makefile
@@ -0,0 +1,15 @@
+obj-$(CONFIG_MXC_MLB) += mlb/
+obj-$(CONFIG_MXC_SIM) += sim/
+obj-$(CONFIG_MXC_VPU) += vpu/
+obj-$(CONFIG_MXC_IPU_V3) += ipu3/
+obj-$(CONFIG_MXC_HDMI_CEC) += hdmi-cec/
+obj-$(CONFIG_MXC_GPU_VIV) += gpu-viv/
+obj-$(CONFIG_MXC_MIPI_CSI2) += mipi/
+obj-$(CONFIG_MXC_HANTRO) += hantro/
+obj-$(CONFIG_MXC_HANTRO_845) += hantro_845/
+obj-$(CONFIG_MXC_HANTRO_845_H1) += hantro_845_h1/
+obj-$(CONFIG_MXC_VPU_MALONE) += vpu-malone/
+obj-$(CONFIG_MX8_HDP) += hdp/
+obj-$(CONFIG_IMX_HDP_CEC) += hdp-cec/
+obj-$(CONFIG_MXC_VPU_DECODER) += vpu-decoder-b0/
+obj-$(CONFIG_MXC_VPU_ENCODER) += vpu-encoder-b0/
diff --git a/drivers/mxc/gpu-viv/Kbuild b/drivers/mxc/gpu-viv/Kbuild
new file mode 100644
index 000000000000..cf795c61c8ac
--- /dev/null
+++ b/drivers/mxc/gpu-viv/Kbuild
@@ -0,0 +1,334 @@
+##############################################################################
+#
+# The MIT License (MIT)
+#
+# Copyright (c) 2014 - 2018 Vivante Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+#
+##############################################################################
+#
+# The GPL License (GPL)
+#
+# Copyright (C) 2014 - 2018 Vivante Corporation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+##############################################################################
+#
+# Note: This software is released under dual MIT and GPL licenses. A
+# recipient may use this file under the terms of either the MIT license or
+# GPL License. If you wish to use only one license not the other, you can
+# indicate your decision by deleting one of the above license notices in your
+# version of this file.
+#
+##############################################################################
+
+
+#
+# Linux build file for kernel HAL driver.
+#
+AQROOT := $(srctree)/drivers/mxc/gpu-viv
+
+include $(AQROOT)/config
+
+soc_vendor := $(firstword $(subst -, ,$(SOC_PLATFORM)))
+soc_board := $(lastword $(subst -, ,$(SOC_PLATFORM)))
+
+KERNEL_DIR ?= $(TOOL_DIR)/kernel
+
+OS_KERNEL_DIR := hal/os/linux/kernel
+ARCH_KERNEL_DIR := hal/kernel/arch
+ARCH_VG_KERNEL_DIR := hal/kernel/archvg
+HAL_KERNEL_DIR := hal/kernel
+TA_DIR := hal/security_v1
+HOST := $(shell hostname)
+
+# Include platform config if exists.
+-include $(AQROOT)/$(OS_KERNEL_DIR)/platform/$(soc_vendor)/gc_hal_kernel_platform_$(soc_board).config
+
+MODULE_NAME ?= galcore
+CUSTOMER_ALLOCATOR_OBJS ?=
+ALLOCATOR_ARRAY_H_LOCATION ?= $(OS_KERNEL_DIR)/allocator/default/
+
+EXTRA_CFLAGS += -Werror
+
+OBJS := $(OS_KERNEL_DIR)/gc_hal_kernel_device.o \
+ $(OS_KERNEL_DIR)/gc_hal_kernel_linux.o \
+ $(OS_KERNEL_DIR)/gc_hal_kernel_math.o \
+ $(OS_KERNEL_DIR)/gc_hal_kernel_os.o \
+ $(OS_KERNEL_DIR)/gc_hal_kernel_debugfs.o \
+ $(OS_KERNEL_DIR)/gc_hal_kernel_allocator.o \
+ $(OS_KERNEL_DIR)/allocator/default/gc_hal_kernel_allocator_user_memory.o \
+ $(OS_KERNEL_DIR)/allocator/default/gc_hal_kernel_allocator_dma.o \
+ $(OS_KERNEL_DIR)/allocator/default/gc_hal_kernel_allocator_gfp.o \
+ $(OS_KERNEL_DIR)/allocator/default/gc_hal_kernel_allocator_reserved_mem.o \
+ $(OS_KERNEL_DIR)/gc_hal_kernel_driver.o \
+ $(OS_KERNEL_DIR)/platform/$(soc_vendor)/gc_hal_kernel_platform_$(soc_board).o
+
+ifneq ($(CONFIG_DMA_SHARED_BUFFER),)
+OBJS += $(OS_KERNEL_DIR)/allocator/default/gc_hal_kernel_allocator_dmabuf.o
+endif
+
+ifneq ($(CONFIG_IOMMU_SUPPORT),)
+OBJS += $(OS_KERNEL_DIR)/gc_hal_kernel_iommu.o
+endif
+
+ifneq ($(CONFIG_DRM),)
+OBJS += $(OS_KERNEL_DIR)/gc_hal_kernel_drm.o
+endif
+
+OBJS += $(HAL_KERNEL_DIR)/gc_hal_kernel.o \
+ $(HAL_KERNEL_DIR)/gc_hal_kernel_command.o \
+ $(HAL_KERNEL_DIR)/gc_hal_kernel_async_command.o \
+ $(HAL_KERNEL_DIR)/gc_hal_kernel_db.o \
+ $(HAL_KERNEL_DIR)/gc_hal_kernel_debug.o \
+ $(HAL_KERNEL_DIR)/gc_hal_kernel_event.o \
+ $(HAL_KERNEL_DIR)/gc_hal_kernel_heap.o \
+ $(HAL_KERNEL_DIR)/gc_hal_kernel_mmu.o \
+ $(HAL_KERNEL_DIR)/gc_hal_kernel_video_memory.o \
+ $(HAL_KERNEL_DIR)/gc_hal_kernel_power.o \
+ $(HAL_KERNEL_DIR)/gc_hal_kernel_security_v1.o
+
+OBJS += $(ARCH_KERNEL_DIR)/gc_hal_kernel_context.o \
+ $(ARCH_KERNEL_DIR)/gc_hal_kernel_hardware.o
+
+ifeq ($(VIVANTE_ENABLE_3D), 1)
+OBJS += $(ARCH_KERNEL_DIR)/gc_hal_kernel_recorder.o
+endif
+
+ifneq ($(CONFIG_ARM64),)
+VIVANTE_ENABLE_VG=0
+endif
+
+ifeq ($(VIVANTE_ENABLE_VG), 1)
+OBJS +=\
+ $(HAL_KERNEL_DIR)/gc_hal_kernel_vg.o\
+ $(HAL_KERNEL_DIR)/gc_hal_kernel_command_vg.o\
+ $(HAL_KERNEL_DIR)/gc_hal_kernel_interrupt_vg.o\
+ $(HAL_KERNEL_DIR)/gc_hal_kernel_mmu_vg.o\
+ $(ARCH_VG_KERNEL_DIR)/gc_hal_kernel_hardware_command_vg.o\
+ $(ARCH_VG_KERNEL_DIR)/gc_hal_kernel_hardware_vg.o
+endif
+
+ifneq ($(CONFIG_SYNC),)
+EXTRA_CFLAGS += -Idrivers/staging/android
+
+OBJS += $(OS_KERNEL_DIR)/gc_hal_kernel_sync.o
+else
+ ifneq ($(CONFIG_SYNC_FILE),)
+ OBJS += $(OS_KERNEL_DIR)/gc_hal_kernel_sync.o
+ endif
+endif
+
+ifeq ($(SECURITY), 1)
+OBJS += $(OS_KERNEL_DIR)/gc_hal_kernel_security_channel.o \
+ $(HAL_KERNEL_DIR)/gc_hal_kernel_security.o
+endif
+
+ifneq ($(CUSTOMER_ALLOCATOR_OBJS),)
+OBJS += $(CUSTOMER_ALLOCATOR_OBJS)
+endif
+
+OBJS += $(OS_KERNEL_DIR)/gc_hal_kernel_security_channel_emulator.o \
+ $(TA_DIR)/gc_hal_ta.o \
+ $(TA_DIR)/gc_hal_ta_hardware.o \
+ $(TA_DIR)/gc_hal_ta_mmu.o \
+ $(TA_DIR)/os/emulator/gc_hal_ta_emulator.o
+
+ifeq ($(KERNELRELEASE), )
+
+.PHONY: all clean install
+
+# Define targets.
+all:
+ @$(MAKE) V=$(V) ARCH=$(ARCH_TYPE) -C $(KERNEL_DIR) SUBDIRS=`pwd` modules
+
+clean:
+ @rm -rf $(OBJS)
+ @rm -rf modules.order Module.symvers .tmp_versions
+ @find $(AQROOT) -name ".gc_*.cmd" | xargs rm -f
+
+install: all
+ @mkdir -p $(SDK_DIR)/drivers
+ @cp $(MODULE_NAME).ko $(SDK_DIR)/drivers
+
+else
+
+
+EXTRA_CFLAGS += -DLINUX -DDRIVER
+
+ifeq ($(FLAREON),1)
+EXTRA_CFLAGS += -DFLAREON
+endif
+
+ifeq ($(DEBUG), 1)
+EXTRA_CFLAGS += -DDBG=1 -DDEBUG -D_DEBUG
+else
+EXTRA_CFLAGS += -DDBG=0
+endif
+
+ifeq ($(NO_DMA_COHERENT), 1)
+EXTRA_CFLAGS += -DNO_DMA_COHERENT
+endif
+
+ifeq ($(CONFIG_DOVE_GPU), 1)
+EXTRA_CFLAGS += -DCONFIG_DOVE_GPU=1
+endif
+
+ifneq ($(USE_PLATFORM_DRIVER), 0)
+EXTRA_CFLAGS += -DUSE_PLATFORM_DRIVER=1
+else
+EXTRA_CFLAGS += -DUSE_PLATFORM_DRIVER=0
+endif
+
+EXTRA_CFLAGS += -DVIVANTE_PROFILER=1
+EXTRA_CFLAGS += -DVIVANTE_PROFILER_CONTEXT=1
+
+ifeq ($(ENABLE_GPU_CLOCK_BY_DRIVER), 1)
+EXTRA_CFLAGS += -DENABLE_GPU_CLOCK_BY_DRIVER=1
+else
+EXTRA_CFLAGS += -DENABLE_GPU_CLOCK_BY_DRIVER=0
+endif
+
+ifeq ($(USE_NEW_LINUX_SIGNAL), 1)
+EXTRA_CFLAGS += -DUSE_NEW_LINUX_SIGNAL=1
+else
+EXTRA_CFLAGS += -DUSE_NEW_LINUX_SIGNAL=0
+endif
+
+ifeq ($(USE_LINUX_PCIE), 1)
+EXTRA_CFLAGS += -DUSE_LINUX_PCIE=1
+else
+EXTRA_CFLAGS += -DUSE_LINUX_PCIE=0
+endif
+
+ifeq ($(FORCE_ALL_VIDEO_MEMORY_CACHED), 1)
+EXTRA_CFLAGS += -DgcdPAGED_MEMORY_CACHEABLE=1
+else
+EXTRA_CFLAGS += -DgcdPAGED_MEMORY_CACHEABLE=0
+endif
+
+ifeq ($(NONPAGED_MEMORY_CACHEABLE), 1)
+EXTRA_CFLAGS += -DgcdNONPAGED_MEMORY_CACHEABLE=1
+else
+EXTRA_CFLAGS += -DgcdNONPAGED_MEMORY_CACHEABLE=0
+endif
+
+ifeq ($(NONPAGED_MEMORY_BUFFERABLE), 1)
+EXTRA_CFLAGS += -DgcdNONPAGED_MEMORY_BUFFERABLE=1
+else
+EXTRA_CFLAGS += -DgcdNONPAGED_MEMORY_BUFFERABLE=0
+endif
+
+ifeq ($(CACHE_FUNCTION_UNIMPLEMENTED), 1)
+EXTRA_CFLAGS += -DgcdCACHE_FUNCTION_UNIMPLEMENTED=1
+else
+EXTRA_CFLAGS += -DgcdCACHE_FUNCTION_UNIMPLEMENTED=0
+endif
+
+ifeq ($(VIVANTE_ENABLE_3D),0)
+EXTRA_CFLAGS += -DgcdENABLE_3D=0
+else
+EXTRA_CFLAGS += -DgcdENABLE_3D=1
+endif
+
+ifeq ($(VIVANTE_ENABLE_2D),0)
+EXTRA_CFLAGS += -DgcdENABLE_2D=0
+else
+EXTRA_CFLAGS += -DgcdENABLE_2D=1
+endif
+
+ifeq ($(VIVANTE_ENABLE_VG),0)
+EXTRA_CFLAGS += -DgcdENABLE_VG=0
+else
+EXTRA_CFLAGS += -DgcdENABLE_VG=1
+endif
+
+ifeq ($(USE_BANK_ALIGNMENT), 1)
+ EXTRA_CFLAGS += -DgcdENABLE_BANK_ALIGNMENT=1
+ ifneq ($(BANK_BIT_START), 0)
+ ifneq ($(BANK_BIT_END), 0)
+ EXTRA_CFLAGS += -DgcdBANK_BIT_START=$(BANK_BIT_START)
+ EXTRA_CFLAGS += -DgcdBANK_BIT_END=$(BANK_BIT_END)
+ endif
+ endif
+
+ ifneq ($(BANK_CHANNEL_BIT), 0)
+ EXTRA_CFLAGS += -DgcdBANK_CHANNEL_BIT=$(BANK_CHANNEL_BIT)
+ endif
+endif
+
+ifeq ($(FPGA_BUILD), 1)
+EXTRA_CFLAGS += -DgcdFPGA_BUILD=1
+else
+EXTRA_CFLAGS += -DgcdFPGA_BUILD=0
+endif
+
+ifeq ($(SECURITY), 1)
+EXTRA_CFLAGS += -DgcdSECURITY=1
+endif
+
+ifneq ($(CONFIG_DRM), )
+ ifneq ($(CONFIG_ANDROID),)
+ EXTRA_CFLAGS += -DgcdENABLE_DRM=$(VIVANTE_ENABLE_DRM)
+ else
+ EXTRA_CFLAGS += -DgcdENABLE_DRM=0
+ endif
+else
+EXTRA_CFLAGS += -DgcdENABLE_DRM=0
+endif
+
+EXTRA_CFLAGS += -I$(AQROOT)/hal/kernel/inc
+EXTRA_CFLAGS += -I$(AQROOT)/hal/kernel
+EXTRA_CFLAGS += -I$(AQROOT)/hal/kernel/arch
+EXTRA_CFLAGS += -I$(AQROOT)/hal/kernel/inc
+EXTRA_CFLAGS += -I$(AQROOT)/hal/os/linux/kernel
+EXTRA_CFLAGS += -I$(AQROOT)/$(ALLOCATOR_ARRAY_H_LOCATION)
+EXTRA_CFLAGS += -I$(AQROOT)/hal/security_v1/
+
+ifneq ($(CONFIG_ARM), )
+EXTRA_CFLAGS += -Iarch/arm/mm
+endif
+
+ifeq ($(VIVANTE_ENABLE_VG), 1)
+EXTRA_CFLAGS += -I$(AQROOT)/hal/kernel/archvg
+endif
+
+EXTRA_CFLAGS += -DHOST=\"$(HOST)\"
+
+EXTRA_CFLAGS += -DgcdENABLE_TRUST_APPLICATION=1
+
+obj-$(CONFIG_MXC_GPU_VIV) = $(MODULE_NAME).o
+
+$(MODULE_NAME)-objs = $(OBJS)
+
+endif
diff --git a/drivers/mxc/gpu-viv/Kconfig b/drivers/mxc/gpu-viv/Kconfig
new file mode 100644
index 000000000000..d1fcd69b2845
--- /dev/null
+++ b/drivers/mxc/gpu-viv/Kconfig
@@ -0,0 +1,11 @@
+menu "MXC Vivante GPU support"
+ depends on SOC_IMX6 || ARCH_FSL_IMX8QM
+
+config MXC_GPU_VIV
+ tristate "MXC Vivante GPU support"
+ default y
+
+ ---help---
+ Say Y to get the GPU driver support.
+
+endmenu
diff --git a/drivers/mxc/gpu-viv/config b/drivers/mxc/gpu-viv/config
new file mode 100644
index 000000000000..9873ae29c580
--- /dev/null
+++ b/drivers/mxc/gpu-viv/config
@@ -0,0 +1,74 @@
+##############################################################################
+#
+# The MIT License (MIT)
+#
+# Copyright (c) 2014 - 2018 Vivante Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+#
+##############################################################################
+#
+# The GPL License (GPL)
+#
+# Copyright (C) 2014 - 2018 Vivante Corporation
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+##############################################################################
+#
+# Note: This software is released under dual MIT and GPL licenses. A
+# recipient may use this file under the terms of either the MIT license or
+# GPL License. If you wish to use only one license not the other, you can
+# indicate your decision by deleting one of the above license notices in your
+# version of this file.
+#
+##############################################################################
+
+
+ARCH_TYPE ?= arm
+SDK_DIR ?= $(AQROOT)/build/sdk
+VIVANTE_ENABLE_3D ?= 1
+VIVANTE_ENABLE_2D ?= 1
+VIVANTE_ENABLE_VG ?= 1
+VIVANTE_ENABLE_DRM ?= 1
+NO_DMA_COHERENT ?= 0
+USE_PLATFORM_DRIVER ?= 1
+ENABLE_GPU_CLOCK_BY_DRIVER ?= 0
+FORCE_ALL_VIDEO_MEMORY_CACHED ?= 0
+NONPAGED_MEMORY_CACHEABLE ?= 0
+NONPAGED_MEMORY_BUFFERABLE ?= 1
+CACHE_FUNCTION_UNIMPLEMENTED ?= 0
+USE_BANK_ALIGNMENT ?= 1
+BANK_BIT_START ?= 13
+BANK_BIT_END ?= 15
+BANK_CHANNEL_BIT ?= 12
+SECURITY ?= 0
+SOC_PLATFORM ?= freescale-imx
diff --git a/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_context.c b/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_context.c
new file mode 100644
index 000000000000..5293deaf8b31
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_context.c
@@ -0,0 +1,3638 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_context.h"
+#include "gc_hal_kernel_buffer.h"
+
+/******************************************************************************\
+******************************** Debugging Macro *******************************
+\******************************************************************************/
+
+/* Zone used for header/footer. */
+#define _GC_OBJ_ZONE gcvZONE_HARDWARE
+
+
+/******************************************************************************\
+************************** Context State Buffer Helpers ************************
+\******************************************************************************/
+
+#define _STATE(reg) \
+ _State(\
+ Context, index, \
+ reg ## _Address >> 2, \
+ reg ## _ResetValue, \
+ reg ## _Count, \
+ gcvFALSE, gcvFALSE \
+ )
+
+#define _STATE_COUNT(reg, count) \
+ _State(\
+ Context, index, \
+ reg ## _Address >> 2, \
+ reg ## _ResetValue, \
+ count, \
+ gcvFALSE, gcvFALSE \
+ )
+
+#define _STATE_COUNT_OFFSET(reg, offset, count) \
+ _State(\
+ Context, index, \
+ (reg ## _Address >> 2) + offset, \
+ reg ## _ResetValue, \
+ count, \
+ gcvFALSE, gcvFALSE \
+ )
+
+#define _STATE_MIRROR_COUNT(reg, mirror, count) \
+ _StateMirror(\
+ Context, \
+ reg ## _Address >> 2, \
+ count, \
+ mirror ## _Address >> 2 \
+ )
+
+#define _STATE_HINT(reg) \
+ _State(\
+ Context, index, \
+ reg ## _Address >> 2, \
+ reg ## _ResetValue, \
+ reg ## _Count, \
+ gcvFALSE, gcvTRUE \
+ )
+
+#define _STATE_HINT_BLOCK(reg, block, count) \
+ _State(\
+ Context, index, \
+ (reg ## _Address >> 2) + (block << reg ## _BLK), \
+ reg ## _ResetValue, \
+ count, \
+ gcvFALSE, gcvTRUE \
+ )
+
+#define _STATE_COUNT_OFFSET_HINT(reg, offset, count) \
+ _State(\
+ Context, index, \
+ (reg ## _Address >> 2) + offset, \
+ reg ## _ResetValue, \
+ count, \
+ gcvFALSE, gcvTRUE \
+ )
+
+#define _STATE_X(reg) \
+ _State(\
+ Context, index, \
+ reg ## _Address >> 2, \
+ reg ## _ResetValue, \
+ reg ## _Count, \
+ gcvTRUE, gcvFALSE \
+ )
+
+#define _STATE_INIT_VALUE(reg, value) \
+ _State(\
+ Context, index, \
+ reg ## _Address >> 2, \
+ value, \
+ reg ## _Count, \
+ gcvFALSE, gcvFALSE \
+ )
+
+#define _CLOSE_RANGE() \
+ _TerminateStateBlock(Context, index)
+
+#define _ENABLE(reg, field) \
+ do \
+ { \
+ if (gcmVERIFYFIELDVALUE(data, reg, MASK_ ## field, ENABLED)) \
+ { \
+ enable |= gcmFIELDMASK(reg, field); \
+ } \
+ } \
+ while (gcvFALSE)
+
+#define _BLOCK_COUNT(reg) \
+ ((reg ## _Count) >> (reg ## _BLK))
+
+
+/******************************************************************************\
+*********************** Support Functions and Definitions **********************
+\******************************************************************************/
+
+#define gcdSTATE_MASK \
+ (gcmSETFIELDVALUE(0, AQ_COMMAND_NOP_COMMAND, OPCODE, NOP) | 0xC0FFEE)
+
+#if gcdENABLE_3D
+static gctUINT32
+_TerminateStateBlock(
+ IN gckCONTEXT Context,
+ IN gctUINT32 Index
+ )
+{
+ gctUINT32_PTR buffer;
+ gctUINT32 align;
+
+ /* Determine if we need alignment. */
+ align = (Index & 1) ? 1 : 0;
+
+ /* Address correct index. */
+ buffer = (Context->buffer == gcvNULL)
+ ? gcvNULL
+ : Context->buffer->logical;
+
+ /* Flush the current state block; make sure no pairing with the states
+ to follow happens. */
+ if (align && (buffer != gcvNULL))
+ {
+ buffer[Index] = 0xDEADDEAD;
+ }
+
+ /* Reset last address. */
+ Context->lastAddress = ~0U;
+
+ /* Return alignment requirement. */
+ return align;
+}
+#endif
+
+
+#if gcdENABLE_3D
+static gctUINT32
+_FlushPipe(
+ IN gckCONTEXT Context,
+ IN gctUINT32 Index,
+ IN gcePIPE_SELECT Pipe
+ )
+{
+ gctUINT32 flushSlots;
+ gctBOOL txCacheFix;
+ gctBOOL fcFlushStall;
+ gctBOOL iCacheInvalidate;
+ gctBOOL halti5;
+ gctBOOL snapPages;
+ gctBOOL hwTFB;
+ gctBOOL blt;
+ gctBOOL peTSFlush;
+
+ txCacheFix
+ = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_TEX_CACHE_FLUSH_FIX);
+
+ fcFlushStall
+ = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_FC_FLUSH_STALL);
+
+ iCacheInvalidate
+ = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_SHADER_HAS_INSTRUCTION_CACHE);
+
+ halti5
+ = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_HALTI5);
+
+ snapPages
+ = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_SNAPPAGE_CMD_FIX) &&
+ gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_SNAPPAGE_CMD);
+
+
+ hwTFB
+ = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_HW_TFB);
+
+ blt
+ = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_BLT_ENGINE);
+
+ peTSFlush
+ = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_PE_TILE_CACHE_FLUSH_FIX);
+
+ flushSlots = blt ? 10 : 6;
+
+ if (Pipe == gcvPIPE_3D)
+ {
+ if (!txCacheFix)
+ {
+ /* Semaphore stall */
+ flushSlots += blt ? 8 : 4;
+ }
+
+ /* VST cache */
+ flushSlots += 2;
+ }
+
+ if (fcFlushStall)
+ {
+ /* Flush tile status cache. */
+ flushSlots += blt ? ((!peTSFlush) ? 14 :10) : 6;
+ }
+
+ if (iCacheInvalidate && !halti5)
+ {
+ flushSlots += blt ? 16 : 12;
+ }
+
+ if (hwTFB)
+ {
+ flushSlots += 2;
+ }
+
+ /* Snap pages */
+ if (snapPages)
+ {
+ flushSlots += 2;
+ }
+
+ if (Context->buffer != gcvNULL)
+ {
+ gctUINT32_PTR buffer;
+
+ /* Address correct index. */
+ buffer = Context->buffer->logical + Index;
+
+ if (Pipe == gcvPIPE_3D && !txCacheFix)
+ {
+ if (blt)
+ {
+ /* Semaphore from FE to BLT. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* Stall from FE to BLT. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+ }
+ else
+ {
+ /* Semaphore from FE to PE. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* Stall from FE to PE. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+ }
+ }
+
+ /* Flush the current pipe. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = (Pipe == gcvPIPE_2D)
+ ? ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ? 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+ : ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ? 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ? 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ? 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:10) - (0 ? 10:10) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 10:10) - (0 ?
+ 10:10) + 1))))))) << (0 ? 10:10))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 10:10) - (0 ? 10:10) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 10:10) - (0 ?
+ 10:10) + 1))))))) << (0 ? 10:10)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ? 11:11) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ? 11:11))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ? 11:11) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ? 11:11)));
+
+ if (hwTFB)
+ {
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x7003) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer++
+ = 0x12345678;
+ }
+
+ /* Flush VST in separate cmd. */
+ if (Pipe == gcvPIPE_3D)
+ {
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ? 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)));
+ }
+
+ /* Semaphore from FE to PE. */
+ if (blt)
+ {
+ /* Semaphore from FE to BLT. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* Stall from FE to BLT. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+ }
+ else
+ {
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* Stall from FE to PE. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+ }
+
+ if (fcFlushStall)
+ {
+ if (!peTSFlush && blt)
+ {
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502B) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+ }
+ else
+ {
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0594) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+ }
+
+ /* Semaphore from FE to PE. */
+ if (blt)
+ {
+ /* Semaphore from FE to BLT. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* Stall from FE to BLT. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+ }
+ else
+ {
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* Stall from FE to PE. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+ }
+ }
+
+ if (iCacheInvalidate && !halti5)
+ {
+ /* Invalidate I$ after pipe is stalled */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0218) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x021A) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ? 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 4:4) - (0 ?
+ 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0218) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x021A) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ? 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 5:5) - (0 ?
+ 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5)));
+
+ /* Semaphore from FE to PE. */
+ if (blt)
+ {
+ /* Semaphore from FE to BLT. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* Stall from FE to BLT. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+ }
+ else
+ {
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* Stall from FE to PE. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+ }
+ }
+
+ if (snapPages)
+ {
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x13 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x04 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)));
+
+ *buffer++
+ = 0;
+ }
+ }
+
+ /* Number of slots taken by flushing pipe. */
+ return flushSlots;
+}
+#endif
+
+#if gcdENABLE_3D
+static gctUINT32
+_SemaphoreStall(
+ IN gckCONTEXT Context,
+ IN gctUINT32 Index
+ )
+{
+ gctBOOL blt = gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_BLT_ENGINE);
+ if (Context->buffer != gcvNULL)
+ {
+ gctUINT32_PTR buffer;
+
+ /* Address correct index. */
+ buffer = Context->buffer->logical + Index;
+
+ if (blt)
+ {
+ /* Semaphore from FE to BLT. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* Stall from FE to BLT. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+ }
+ else
+ {
+ /* Semaphore from FE to PE. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* Stall from FE to PE. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *buffer
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+ }
+ }
+
+ /* Semaphore/stall takes 4 slots. */
+ return (blt ? 8 : 4);
+}
+#endif
+
+#if (gcdENABLE_3D || gcdENABLE_2D)
+static gctUINT32
+_SwitchPipe(
+ IN gckCONTEXT Context,
+ IN gctUINT32 Index,
+ IN gcePIPE_SELECT Pipe
+ )
+{
+ gctUINT32 slots = 2;
+
+ if (Context->buffer != gcvNULL)
+ {
+ gctUINT32_PTR buffer;
+
+ /* Address correct index. */
+ buffer = Context->buffer->logical + Index;
+
+ /* LoadState(AQPipeSelect, 1), pipe. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E00) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer
+ = (Pipe == gcvPIPE_2D)
+ ? 0x1
+ : 0x0;
+ }
+
+ Context->pipeSelectBytes = slots * gcmSIZEOF(gctUINT32);
+
+ return slots;
+}
+#endif
+
+#if gcdENABLE_3D
+static gctUINT32
+_State(
+ IN gckCONTEXT Context,
+ IN gctUINT32 Index,
+ IN gctUINT32 Address,
+ IN gctUINT32 Value,
+ IN gctUINT32 Size,
+ IN gctBOOL FixedPoint,
+ IN gctBOOL Hinted
+ )
+{
+ gctUINT32_PTR buffer;
+ gctUINT32 align;
+ gctUINT32 i;
+
+ /* Determine if we need alignment. */
+ align = (Index & 1) ? 1 : 0;
+
+ /* Address correct index. */
+ buffer = (Context->buffer == gcvNULL)
+ ? gcvNULL
+ : Context->buffer->logical;
+
+ if ((buffer == gcvNULL) && (Address + Size > Context->maxState))
+ {
+ /* Determine maximum state. */
+ Context->maxState = Address + Size;
+ }
+
+ if (buffer == gcvNULL)
+ {
+ /* Update number of states. */
+ Context->numStates += Size;
+ }
+
+ /* Do we need a new entry? */
+ if ((Address != Context->lastAddress) || (FixedPoint != Context->lastFixed))
+ {
+ if (buffer != gcvNULL)
+ {
+ if (align)
+ {
+ /* Add filler. */
+ buffer[Index++] = 0xDEADDEAD;
+ }
+
+ /* LoadState(Address, Count). */
+ gcmkASSERT((Index & 1) == 0);
+
+ if (FixedPoint)
+ {
+ buffer[Index]
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ? 26:26) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ? 26:26))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ? 26:26) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ? 26:26)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (Size) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+ }
+ else
+ {
+ buffer[Index]
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ? 26:26) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ? 26:26))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ? 26:26) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ? 26:26)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (Size) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+ }
+
+ /* Walk all the states. */
+ for (i = 0; i < (gctUINT32)Size; i += 1)
+ {
+ /* Set state to uninitialized value. */
+ buffer[Index + 1 + i] = Value;
+
+ /* Set index in state mapping table. */
+ Context->map[Address + i].index = (gctUINT)Index + 1 + i;
+
+#if gcdSECURE_USER
+ /* Save hint. */
+ if (Context->hint != gcvNULL)
+ {
+ Context->hint[Address + i] = Hinted;
+ }
+#endif
+ }
+ }
+
+ /* Save information for this LoadState. */
+ Context->lastIndex = (gctUINT)Index;
+ Context->lastAddress = Address + (gctUINT32)Size;
+ Context->lastSize = Size;
+ Context->lastFixed = FixedPoint;
+
+ /* Return size for load state. */
+ return align + 1 + Size;
+ }
+
+ /* Append this state to the previous one. */
+ if (buffer != gcvNULL)
+ {
+ /* Update last load state. */
+ buffer[Context->lastIndex] =
+ ((((gctUINT32) (buffer[Context->lastIndex])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (Context->lastSize + Size) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ /* Walk all the states. */
+ for (i = 0; i < (gctUINT32)Size; i += 1)
+ {
+ /* Set state to uninitialized value. */
+ buffer[Index + i] = Value;
+
+ /* Set index in state mapping table. */
+ Context->map[Address + i].index = (gctUINT)Index + i;
+
+#if gcdSECURE_USER
+ /* Save hint. */
+ if (Context->hint != gcvNULL)
+ {
+ Context->hint[Address + i] = Hinted;
+ }
+#endif
+ }
+ }
+
+ /* Update last address and size. */
+ Context->lastAddress += (gctUINT32)Size;
+ Context->lastSize += Size;
+
+ /* Return number of slots required. */
+ return Size;
+}
+
+static gctUINT32
+_StateMirror(
+ IN gckCONTEXT Context,
+ IN gctUINT32 Address,
+ IN gctUINT32 Size,
+ IN gctUINT32 AddressMirror
+ )
+{
+ gctUINT32 i;
+
+ /* Process when buffer is set. */
+ if (Context->buffer != gcvNULL)
+ {
+ /* Walk all states. */
+ for (i = 0; i < Size; i++)
+ {
+ /* Copy the mapping address. */
+ Context->map[Address + i].index =
+ Context->map[AddressMirror + i].index;
+
+#if gcdSECURE_USER
+ Context->hint[Address + i] =
+ Context->hint[AddressMirror + i];
+#endif
+ }
+ }
+
+ /* Return the number of required maps. */
+ return Size;
+}
+#endif
+
+#if (gcdENABLE_3D || gcdENABLE_2D)
+static gceSTATUS
+_InitializeContextBuffer(
+ IN gckCONTEXT Context
+ )
+{
+ gctUINT32_PTR buffer;
+ gctUINT32 index;
+
+#if gcdENABLE_3D
+ gctBOOL halti0, halti1, halti2, halti3, halti4, halti5;
+ gctUINT i;
+ gctUINT vertexUniforms, fragmentUniforms, vsConstBase, psConstBase, constMax;
+ gctBOOL unifiedUniform;
+ gctBOOL hasGS, hasTS;
+ gctBOOL genericAttrib;
+ gctBOOL hasICache;
+ gctBOOL hasICachePrefetch;
+ gctUINT numRT = 0;
+ gctUINT numSamplers = 32;
+ gctBOOL hasTXdesc;
+ gctBOOL hasSecurity;
+ gctBOOL hasRobustness;
+ gctBOOL multiCoreBlockSetCfg2;
+#endif
+
+ gckHARDWARE hardware;
+
+ gcmkHEADER();
+
+ hardware = Context->hardware;
+
+ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+ /* Reset the buffer index. */
+ index = 0;
+
+ /* Reset the last state address. */
+ Context->lastAddress = ~0U;
+
+ /* Get the buffer pointer. */
+ buffer = (Context->buffer == gcvNULL)
+ ? gcvNULL
+ : Context->buffer->logical;
+
+
+ /**************************************************************************/
+ /* Build 2D states. *******************************************************/
+
+
+#if gcdENABLE_3D
+ /**************************************************************************/
+ /* Build 3D states. *******************************************************/
+
+ halti0 = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_HALTI0);
+ halti1 = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_HALTI1);
+ halti2 = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_HALTI2);
+ halti3 = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_HALTI3);
+ halti4 = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_HALTI4);
+ halti5 = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_HALTI5);
+ hasGS = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_GEOMETRY_SHADER);
+ hasTS = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TESSELLATION);
+ genericAttrib = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_GENERIC_ATTRIB);
+ hasICache = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_SHADER_HAS_INSTRUCTION_CACHE);
+ hasTXdesc = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TX_DESCRIPTOR);
+ hasSecurity = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_SECURITY);
+ hasRobustness = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_ROBUSTNESS);
+ hasICachePrefetch = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_SH_INSTRUCTION_PREFETCH);
+ multiCoreBlockSetCfg2 = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_MULTI_CORE_BLOCK_SET_CONFIG2);
+
+ /* Multi render target. */
+ if (halti2 ||
+ (Context->hardware->identity.chipModel == gcv900 && Context->hardware->identity.chipRevision == 0x5250)
+ )
+ {
+ numRT = 8;
+ }
+ else if (halti0)
+ {
+ numRT = 4;
+ }
+ else
+ {
+ numRT = 1;
+ }
+
+ if (hasGS && hasTS)
+ {
+ numSamplers = 80;
+ }
+
+ /* Query how many uniforms can support. */
+ {if (Context->hardware->identity.numConstants > 256){ unifiedUniform = gcvTRUE;
+if (halti5){ vsConstBase = 0xD000;
+ psConstBase = 0xD800;
+}else{ vsConstBase = 0xC000;
+ psConstBase = 0xC000;
+}if ((Context->hardware->identity.chipModel == gcv880) && ((Context->hardware->identity.chipRevision & 0xfff0) == 0x5120)){ vertexUniforms = 512;
+ fragmentUniforms = 64;
+ constMax = 576;
+}else{ vertexUniforms = gcmMIN(512, Context->hardware->identity.numConstants - 64);
+ fragmentUniforms = gcmMIN(512, Context->hardware->identity.numConstants - 64);
+ constMax = Context->hardware->identity.numConstants;
+}}else if (Context->hardware->identity.numConstants == 256){ if (Context->hardware->identity.chipModel == gcv2000 && (Context->hardware->identity.chipRevision == 0x5118 || Context->hardware->identity.chipRevision == 0x5140)) { unifiedUniform = gcvFALSE;
+ vsConstBase = 0x1400;
+ psConstBase = 0x1C00;
+ vertexUniforms = 256;
+ fragmentUniforms = 64;
+ constMax = 320;
+ } else { unifiedUniform = gcvFALSE;
+ vsConstBase = 0x1400;
+ psConstBase = 0x1C00;
+ vertexUniforms = 256;
+ fragmentUniforms = 256;
+ constMax = 512;
+ }}else{ unifiedUniform = gcvFALSE;
+ vsConstBase = 0x1400;
+ psConstBase = 0x1C00;
+ vertexUniforms = 168;
+ fragmentUniforms = 64;
+ constMax = 232;
+}};
+
+
+#if !gcdENABLE_UNIFIED_CONSTANT
+ if (Context->hardware->identity.numConstants > 256)
+ {
+ unifiedUniform = gcvTRUE;
+ }
+ else
+ {
+ unifiedUniform = gcvFALSE;
+ }
+#endif
+
+ /* Store the 3D entry index. */
+ Context->entryOffset3D = (gctUINT)index * gcmSIZEOF(gctUINT32);
+
+ /* Switch to 3D pipe. */
+ index += _SwitchPipe(Context, index, gcvPIPE_3D);
+
+ /* Current context pointer. */
+#if gcdDEBUG
+ index += _State(Context, index, 0x03850 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+#endif
+
+ index += _FlushPipe(Context, index, gcvPIPE_3D);
+
+ /* Global states. */
+ if (hasSecurity)
+ {
+ index += _State(Context, index, 0x03900 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+ index += _State(Context, index, 0x03904 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+
+ index += _State(Context, index, 0x03814 >> 2, 0x00000001, 1, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+ index += _State(Context, index, 0x03818 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0381C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+ if (halti5)
+ {
+ index += _State(Context, index, 0x03888 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x038C0 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x03884 >> 2, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:0) - (0 ? 2:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (hardware->options.uscL1CacheRatio) & ((gctUINT32) ((((1 ?
+ 2:0) - (0 ? 2:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ?
+ 2:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 20:16) - (0 ?
+ 20:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 20:16) - (0 ? 20:16) + 1))))))) << (0 ?
+ 20:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 20:16) - (0 ?
+ 20:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 20:16) - (0 ? 20:16) + 1))))))) << (0 ?
+ 20:16))), 1, gcvFALSE, gcvFALSE);
+ }
+ else
+ {
+ index += _State(Context, index, 0x03820 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x03828 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0382C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x03834 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x03838 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x03854 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+
+ if (hasGS)
+ {
+ index += _State(Context, index, 0x0388C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+
+ index += _State(Context, index, 0x0384C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+ /* Front End states. */
+ if (halti5)
+ {
+ index += _State(Context, index, 0x17800 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+ index += _State(Context, index, 0x007C4 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x17880 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x17900 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x17980 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x17A00 >> 2, 0x3F800000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x007D0 >> 2, 0x00000000, 2, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x007D8 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x17A80 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ }
+ else
+ {
+ index += _State(Context, index, 0x00600 >> 2, 0x00000000, (halti0 ? 16 : 12), gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+ if (genericAttrib)
+ {
+ index += _State(Context, index, 0x006C0 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00700 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00740 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00780 >> 2, 0x3F800000, 16, gcvFALSE, gcvFALSE);
+ }
+ }
+
+ if (halti2 || (Context->hardware->identity.streamCount > 8))
+ {
+ index += _State(Context, index, 0x14600 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14640 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14680 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+ }
+ else if (Context->hardware->identity.streamCount > 1)
+ {
+ index += _State(Context, index, 0x00680 >> 2, 0x00000000, 8, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x006A0 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+ }
+ else
+ {
+ index += _State(Context, index, 0x0064C >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x00650 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+ }
+ index += _State(Context, index, 0x00644 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x00648 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00674 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00678 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0067C >> 2, 0xFFFFFFFF, 1, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+
+ if (hasRobustness)
+ {
+ index += _State(Context, index, 0x146C0 >> 2, 0x00000000, 16, gcvFALSE, gcvTRUE);
+ index += _CLOSE_RANGE();
+ index += _State(Context, index, 0x007F8 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _CLOSE_RANGE();
+ }
+
+ if (halti5)
+ {
+ index += _State(Context, index, 0x008B8 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x15600 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+ else
+ {
+ /* This register is programed by all chips, which program all DECODE_SELECT as VS
+ ** except SAMPLER_DECODE_SELECT.
+ */
+ index += _State(Context, index, 0x00860 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+
+ if (hasICache)
+ {
+ /* I-Cache states. */
+ index += _State(Context, index, 0x00868 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0086C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0304C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01028 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+
+ if (hasICachePrefetch)
+ {
+ if (halti5)
+ {
+ index += _State(Context, index, 0x15604 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x01094 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ }
+ else
+ {
+ index += _State(Context, index, 0x00890 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x0104C >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ }
+ index += _CLOSE_RANGE();
+ }
+ }
+
+ /* Vertex Shader states. */
+ index += _State(Context, index, 0x00804 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00808 >> 2, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:0) - (0 ? 5:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ?
+ 5:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 5:0) - (0 ?
+ 5:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ?
+ 5:0))), 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0080C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00830 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+ if (halti5)
+ {
+ index += _State(Context, index, 0x00898 >> 2, 0x00000000, 2, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x008A0 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00870 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x008A8 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x008C0 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x008E0 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+ }
+ else
+ {
+ index += _State(Context, index, 0x00810 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00820 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE);
+ }
+
+ index += _CLOSE_RANGE();
+
+ /* GS */
+ if (hasGS)
+ {
+ index += _State(Context, index, 0x01100 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01104 >> 2, 0x00000001, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01108 >> 2, 0x01000001, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0110C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01110 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01114 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x0111C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01140 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01144 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01148 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0114C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01154 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01120 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+ }
+
+ /* TCS & TES */
+
+ if (hasTS)
+ {
+ index += _State(Context, index, 0x007C0 >> 2, 0x00000003, 1, gcvFALSE, gcvFALSE);
+
+ index += _State(Context, index, 0x14A14 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14A18 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14A1C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14A40 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14A00 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14A04 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14A08 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x14A10 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14A20 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14A44 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14A4C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+ index += _CLOSE_RANGE();
+
+ index += _State(Context, index, 0x14B18 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14B1C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14B20 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14B04 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14B08 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14B0C >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x14B14 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14B40 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14B24 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14B2C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14B34 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+ index += _State(Context, index, 0x14B00 >> 2, 0x00040000, 1, gcvFALSE, gcvFALSE);
+
+ }
+
+ index += _CLOSE_RANGE();
+
+ /* TFB */
+ if (gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_HW_TFB))
+ {
+ index += _State(Context, index, 0x1C000 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x1C008 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, (0x1C040 >> 2) + (0 << 4), 0x00000000, 4, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x1C080 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x1C0C0 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x1C100 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x1C800 >> 2, 0x00000000, 128*4, gcvFALSE, gcvFALSE);
+
+ index += _State(Context, index, 0x1C014 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _CLOSE_RANGE();
+
+ }
+
+ /* Primitive Assembly states. */
+ index += _State(Context, index, 0x00A00 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+ index += _State(Context, index, 0x00A04 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+ index += _State(Context, index, 0x00A08 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00A0C >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+ index += _State(Context, index, 0x00A10 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+ index += _State(Context, index, 0x00A14 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00A18 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00A1C >> 2, 0x3F000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00A28 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00A2C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00A30 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00A34 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00A38 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00A3C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00A80 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00A84 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+ index += _State(Context, index, 0x00A8C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00A88 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+ if (halti5)
+ {
+ index += _State(Context, index, 0x00AA8 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00A90 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE);
+ }
+ else
+ {
+ index += _State(Context, index, 0x00A40 >> 2, 0x00000000, Context->hardware->identity.varyingsCount, gcvFALSE, gcvFALSE);
+ }
+
+ index += _State(Context, index, 0x03A00 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x03A04 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x03A08 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+ if (multiCoreBlockSetCfg2)
+ {
+ index += _State(Context, index, 0x03A0C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x03A10 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+
+ /* Setup states. */
+ index += _State(Context, index, 0x00C00 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+ index += _State(Context, index, 0x00C04 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+ index += _State(Context, index, 0x00C08 >> 2, 0x45000000, 1, gcvTRUE, gcvFALSE);
+ index += _State(Context, index, 0x00C0C >> 2, 0x45000000, 1, gcvTRUE, gcvFALSE);
+ index += _State(Context, index, 0x00C10 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00C14 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00C18 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00C1C >> 2, 0x42000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00C20 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+ index += _State(Context, index, 0x00C24 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE);
+
+ /* Raster states. */
+ index += _State(Context, index, 0x00E00 >> 2, 0x000000F1, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00E10 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00E04 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00E40 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00E08 >> 2, 0x17000031, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00E24 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00E20 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+ if (halti2)
+ {
+ index += _State(Context, index, 0x00E0C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+
+ if (halti5)
+ {
+ index += _State(Context, index, 0x00E34 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+
+
+ /* Pixel Shader states. */
+ index += _State(Context, index, 0x01004 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01008 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0100C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01010 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01030 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01034 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+ if (halti2)
+ {
+ index += _State(Context, index, 0x01040 >> 2, 0x00000000, 2, gcvFALSE, gcvFALSE);
+ }
+
+ if (numRT == 8)
+ {
+ index += _State(Context, index, 0x0102C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01038 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+
+ if (halti4)
+ {
+ index += _State(Context, index, 0x01054 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+
+ if (halti5)
+ {
+ index += _State(Context, index, 0x01080 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01058 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01098 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+
+
+ index += _CLOSE_RANGE();
+
+ /* Texture states. */
+ if (hasTXdesc)
+ {
+ /* Texture descriptor states */
+ index += _State(Context, index, 0x14C40 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+ index += _State(Context, index, 0x16C00 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x16E00 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x17000 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x17200 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x17400 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+
+ index += _State(Context, index, (0x15C00 >> 2) + (0 << 0), 0x00000000, numSamplers, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x15E00 >> 2, 0x00000000, numSamplers, gcvFALSE, gcvFALSE);
+
+ index += _CLOSE_RANGE();
+
+ _StateMirror(Context, 0x16000 >> 2, numSamplers , 0x16C00 >> 2);
+ _StateMirror(Context, 0x16200 >> 2, numSamplers , 0x16E00 >> 2);
+ _StateMirror(Context, 0x16400 >> 2, numSamplers , 0x17000 >> 2);
+ _StateMirror(Context, 0x16600 >> 2, numSamplers , 0x17200 >> 2);
+ _StateMirror(Context, 0x16800 >> 2, numSamplers , 0x17400 >> 2);
+ _StateMirror(Context, 0x15800 >> 2, numSamplers , 0x15C00 >> 2);
+ _StateMirror(Context, 0x15A00 >> 2, numSamplers , 0x15E00 >> 2);
+ }
+ else
+ {
+ index += _State(Context, index, 0x02000 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x02040 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x02080 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x020C0 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x02100 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x02140 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x02180 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x021C0 >> 2, 0x00321000, 12, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x02200 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x02240 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, (0x02400 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, (0x02440 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, (0x02480 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, (0x024C0 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, (0x02500 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, (0x02540 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, (0x02580 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, (0x025C0 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, (0x02600 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, (0x02640 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, (0x02680 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, (0x026C0 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, (0x02700 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, (0x02740 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE);
+ index += _CLOSE_RANGE();
+
+ if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TEXTURE_LINEAR))
+ {
+ /*
+ * Linear stride LODn will overwrite LOD0 on GC880,GC2000.
+ * And only LOD0 is valid for this register.
+ */
+ gctUINT count = halti1 ? 14 : 1;
+
+ for (i = 0; i < 12; i += 1)
+ {
+ index += _State(Context, index, (0x02C00 >> 2) + i * 16, 0x00000000, count, gcvFALSE, gcvFALSE);
+ }
+ }
+
+ if (halti1)
+ {
+ gctUINT texBlockCount;
+ gctUINT gcregTXLogSizeResetValue;
+
+ /* Enable the integer filter pipe for all texture samplers
+ so that the floating point filter clock will shut off until
+ we start using the floating point filter.
+ */
+ gcregTXLogSizeResetValue = ((((gctUINT32) (0x00000000)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:29) - (0 ? 29:29) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 29:29) - (0 ?
+ 29:29) + 1))))))) << (0 ? 29:29))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 29:29) - (0 ? 29:29) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 29:29) - (0 ?
+ 29:29) + 1))))))) << (0 ? 29:29)));
+
+ /* New texture block. */
+ index += _State(Context, index, 0x10000 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x10080 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x10100 >> 2, gcregTXLogSizeResetValue, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x10180 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x10200 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x10280 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x10300 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x10380 >> 2, 0x00321000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x10400 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x10480 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+
+ if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TX_FILTER))
+ {
+ index += _State(Context, index, 0x12000 >> 2, 0x00000000, 256, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x12400 >> 2, 0x00000000, 256, gcvFALSE, gcvFALSE);
+ }
+
+ texBlockCount = ((512) >> (4));
+
+ for (i = 0; i < texBlockCount; i += 1)
+ {
+ index += _State(Context, index, (0x10800 >> 2) + (i << 4), 0x00000000, 14, gcvFALSE, gcvTRUE);
+ }
+ }
+
+ if (gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_TEX_BASELOD))
+ {
+ index += _State(Context, index, 0x10700 >> 2, 0x00000F00, 32, gcvFALSE, gcvFALSE);
+ }
+
+ if (halti3 ||
+ gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TX_SUPPORT_DEC))
+ {
+ index += _State(Context, index, 0x10780 >> 2, 0x00030000, 32, gcvFALSE, gcvFALSE);
+ }
+
+ if (halti4)
+ {
+ index += _State(Context, index, 0x11200 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x11280 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ }
+
+ if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TX_FRAC_PRECISION_6BIT))
+ {
+ index += _State(Context, index, 0x11000 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x11080 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x11100 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x11180 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x11300 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ }
+
+ /* ASTC */
+ if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TEXTURE_ASTC))
+ {
+ index += _State(Context, index, 0x10500 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x10580 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x10600 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x10680 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE);
+ }
+ }
+
+ if (halti3)
+ {
+ index += _State(Context, index, 0x14C00 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE);
+ }
+
+ /* Thread walker states. */
+ index += _State(Context, index, 0x00900 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00904 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00908 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0090C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00910 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00914 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00918 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00924 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0091C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+ if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_SHADER_ENHANCEMENTS2))
+ {
+ index += _State(Context, index, 0x00940 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00944 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00948 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0094C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00950 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00954 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+
+ if (halti5)
+ {
+ index += _State(Context, index, 0x00958 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0095C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00960 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+
+ index += _CLOSE_RANGE();
+
+ /* VS/PS Start/End PC register */
+ if (halti5)
+ {
+ index += _State(Context, index, 0x00874 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x008BC >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0087C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01090 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+ }
+ else if (hasICache)
+ {
+ /* New Shader instruction PC registers(20bit). */
+ index += _State(Context, index, 0x00874 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00878 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0087C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00880 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+ }
+ else
+ {
+ if (Context->hardware->identity.instructionCount <= 256)
+ {
+ /* old shader instruction PC registers (12bit)*/
+ index += _State(Context, index, 0x00800 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00838 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+
+ index += _State(Context, index, 0x01000 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01018 >> 2, 0x01000000, 1, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+ }
+ else
+ {
+ /* New Shader instruction PC registers (16bit) */
+ index += _State(Context, index, 0x0085C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0101C >> 2, 0x00000100, 1, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+ }
+ }
+
+
+ if (!hasICachePrefetch)
+ {
+ /* This unified one need SELECT bit to steer */
+ if (Context->hardware->identity.instructionCount > 1024)
+ {
+ for (i = 0;
+ i < Context->hardware->identity.instructionCount << 2;
+ i += 256 << 2
+ )
+ {
+ index += _State(Context, index, (0x20000 >> 2) + i, 0x00000000, 256 << 2, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+ }
+ }
+ /* This unified one is steered by base adddress, it's automatical. */
+ else if (Context->hardware->identity.instructionCount > 256)
+ {
+ /* VS instruction memory. */
+ for (i = 0;
+ i < Context->hardware->identity.instructionCount << 2;
+ i += 256 << 2
+ )
+ {
+ index += _State(Context, index, (0x0C000 >> 2) + i, 0x00000000, 256 << 2, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+ }
+
+ _StateMirror(Context, 0x08000 >> 2, Context->hardware->identity.instructionCount << 2 , 0x0C000 >> 2);
+ }
+ /* if (Context->hardware->identity.instructionCount <= 256). This is non-unified one. */
+ else
+ {
+ index += _State(Context, index, 0x04000 >> 2, 0x00000000, 1024, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+ index += _State(Context, index, 0x06000 >> 2, 0x00000000, 1024, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+ }
+ }
+
+ if (unifiedUniform)
+ {
+ gctINT numConstants = Context->hardware->identity.numConstants;
+
+ /* Base Offset register */
+ index += _State(Context, index, 0x01024 >> 2, 0x00000100, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x00864 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+
+ for (i = 0;
+ numConstants > 0;
+ i += 256 << 2,
+ numConstants -= 256
+ )
+ {
+ if (halti5)
+ {
+ if (numConstants >= 256)
+ {
+ index += _State(Context, index, (0x36000 >> 2) + i, 0x00000000, 256 << 2, gcvFALSE, gcvFALSE);
+ }
+ else
+ {
+ index += _State(Context, index, (0x36000 >> 2) + i, 0x00000000, numConstants << 2, gcvFALSE, gcvFALSE);
+ }
+ index += _CLOSE_RANGE();
+ }
+ else
+ {
+ if (numConstants >= 256)
+ {
+ index += _State(Context, index, (0x30000 >> 2) + i, 0x00000000, 256 << 2, gcvFALSE, gcvFALSE);
+ }
+ else
+ {
+ index += _State(Context, index, (0x30000 >> 2) + i, 0x00000000, numConstants << 2, gcvFALSE, gcvFALSE);
+ }
+
+ index += _CLOSE_RANGE();
+ }
+ }
+
+ if (halti5)
+ {
+ _StateMirror(Context, 0x34000 >> 2, Context->hardware->identity.numConstants << 2 , 0x36000 >> 2);
+ }
+ }
+#if gcdENABLE_UNIFIED_CONSTANT
+ else
+#endif
+ {
+ index += _State(Context, index, 0x05000 >> 2, 0x00000000, vertexUniforms * 4, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x07000 >> 2, 0x00000000, fragmentUniforms * 4, gcvFALSE, gcvFALSE);
+ }
+
+ if (halti1)
+ {
+ index += _State(Context, index, 0x00884 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+
+ if (halti5)
+ {
+ index += _State(Context, index, 0x008B0 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+
+ /* Store the index of the "XD" entry. */
+ Context->entryOffsetXDFrom3D = (gctUINT)index * gcmSIZEOF(gctUINT32);
+
+
+ /* Pixel Engine states. */
+ index += _State(Context, index, 0x01400 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01404 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01408 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0140C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01414 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01418 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0141C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01420 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01424 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01428 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x0142C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01434 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01454 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01458 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x014A0 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x014A8 >> 2, 0xFFFFFFFF, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x014AC >> 2, 0xFFFFFFFF, 1, gcvFALSE, gcvFALSE);
+
+ if(gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_HALF_FLOAT_PIPE) )
+ {
+ index += _State(Context, index, 0x014B0 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x014B4 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+ index += _State(Context, index, 0x014A4 >> 2, 0x000E400C, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01580 >> 2, 0x00000000, 3, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x014B8 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+
+ if (halti3)
+ {
+ index += _State(Context, index, 0x0103C >> 2, 0x76543210, 1, gcvFALSE, gcvFALSE);
+ }
+
+ index += _State(Context, index, (0x01460 >> 2) + (0 << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE);
+
+ if (Context->hardware->identity.pixelPipes == 1)
+ {
+ index += _State(Context, index, 0x01430 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x01410 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ }
+
+ if (Context->hardware->identity.pixelPipes > 1 || halti0)
+ {
+ index += _State(Context, index, (0x01480 >> 2) + (0 << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE);
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+ index += _State(Context, index, (0x01500 >> 2) + (i << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE);
+ }
+
+ if (numRT == 8)
+ {
+ for (i = 0; i < 7; i++)
+ {
+ index += _State(Context, index, (0x14800 >> 2) + (i << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE);
+ }
+ index += _State(Context, index, 0x14900 >> 2, 0x00000000, 7, gcvFALSE, gcvFALSE);
+ }
+
+
+ if (halti3)
+ {
+ index += _State(Context, index, 0x014BC >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+
+ if (halti4)
+ {
+ index += _State(Context, index, 0x014C0 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ }
+
+ if (hasGS)
+ {
+ index += _State(Context, index, 0x038A0 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+ }
+
+ if (halti5)
+ {
+ index += _State(Context, index, 0x14920 >> 2, 0x00000000, 7, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14940 >> 2, 0x00000000, 7, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14960 >> 2, 0x00000000, 7, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x14980 >> 2, 0x00000000, 7, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x149A0 >> 2, 0x00000000, 7, gcvFALSE, gcvFALSE);
+ }
+
+ if (hasRobustness)
+ {
+ index += _State(Context, index, 0x149C0 >> 2, 0x00000000, 8, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x014C4 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ }
+
+ /* Memory Controller */
+ index += _State(Context, index, 0x01654 >> 2, 0x00200000, 1, gcvFALSE, gcvFALSE);
+
+ index += _CLOSE_RANGE();
+ index += _State(Context, index, 0x01658 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x0165C >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x01660 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01664 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x01668 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x0166C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01670 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01674 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x016A4 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x016AC >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x016A8 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01720 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x01740 >> 2, 0x00000000, 8, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, 0x01760 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+
+
+ if (halti2)
+ {
+ index += _State(Context, index, 0x01780 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, 0x016BC >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, (0x017A0 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, (0x017C0 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, (0x017E0 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvTRUE);
+ index += _State(Context, index, (0x01A00 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, (0x01A20 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvFALSE);
+ index += _State(Context, index, (0x01A40 >> 2) + 1, 0x00000000, 7, gcvFALSE, gcvFALSE);
+ }
+
+ index += _CLOSE_RANGE();
+
+ if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_BUG_FIXES18))
+ {
+ index += _State(Context, index, 0x03860 >> 2, 0x6, 1, gcvFALSE, gcvFALSE);
+ index += _CLOSE_RANGE();
+ }
+
+ if (halti3)
+ {
+ index += _State(Context, index, 0x01A80 >> 2, 0x00000000, 8, gcvFALSE, gcvTRUE);
+ index += _CLOSE_RANGE();
+ }
+
+ if (hasSecurity || hasRobustness)
+ {
+ index += _State(Context, index, 0x001AC >> 2, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16))), 1, gcvFALSE, gcvFALSE);
+ }
+
+ /* Semaphore/stall. */
+ index += _SemaphoreStall(Context, index);
+#endif
+
+ /**************************************************************************/
+ /* Link to another address. ***********************************************/
+
+ Context->linkIndex3D = (gctUINT)index;
+
+ if (buffer != gcvNULL)
+ {
+ buffer[index + 0]
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ buffer[index + 1]
+ = 0;
+ }
+
+ index += 2;
+
+ /* Store the end of the context buffer. */
+ Context->bufferSize = index * gcmSIZEOF(gctUINT32);
+
+
+ /**************************************************************************/
+ /* Pipe switch for the case where neither 2D nor 3D are used. *************/
+
+ /* Store the 3D entry index. */
+ Context->entryOffsetXDFrom2D = (gctUINT)index * gcmSIZEOF(gctUINT32);
+
+ /* Switch to 3D pipe. */
+ index += _SwitchPipe(Context, index, gcvPIPE_3D);
+
+ /* Store the location of the link. */
+ Context->linkIndexXD = (gctUINT)index;
+
+ if (buffer != gcvNULL)
+ {
+ buffer[index + 0]
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ buffer[index + 1]
+ = 0;
+ }
+
+ index += 2;
+
+
+ /**************************************************************************/
+ /* Save size for buffer. **************************************************/
+
+ Context->totalSize = index * gcmSIZEOF(gctUINT32);
+
+#if gcdENABLE_3D
+ psConstBase = psConstBase;
+ vsConstBase = vsConstBase;
+ constMax = constMax;
+#endif
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+#endif
+
+static gceSTATUS
+_DestroyContext(
+ IN gckCONTEXT Context
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+
+ if (Context != gcvNULL)
+ {
+ gcsCONTEXT_PTR bufferHead;
+
+ /* Free context buffers. */
+ for (bufferHead = Context->buffer; Context->buffer != gcvNULL;)
+ {
+ /* Get a shortcut to the current buffer. */
+ gcsCONTEXT_PTR buffer = Context->buffer;
+
+ /* Get the next buffer. */
+ gcsCONTEXT_PTR next = buffer->next;
+
+ /* Last item? */
+ if (next == bufferHead)
+ {
+ next = gcvNULL;
+ }
+
+ /* Destroy the signal. */
+ if (buffer->signal != gcvNULL)
+ {
+ gcmkONERROR(gckOS_DestroySignal(
+ Context->os, buffer->signal
+ ));
+
+ buffer->signal = gcvNULL;
+ }
+
+ /* Free state delta map. */
+ if (buffer->logical != gcvNULL)
+ {
+ if (Context->hardware->kernel->virtualCommandBuffer)
+ {
+ gcmkONERROR(gckEVENT_DestroyVirtualCommandBuffer(
+ Context->hardware->kernel->eventObj,
+ Context->totalSize,
+ buffer->physical,
+ buffer->logical,
+ gcvKERNEL_PIXEL
+ ));
+ }
+ else
+ {
+ gcmkONERROR(gckEVENT_FreeContiguousMemory(
+ Context->hardware->kernel->eventObj,
+ Context->totalSize,
+ buffer->physical,
+ buffer->logical,
+ gcvKERNEL_PIXEL
+ ));
+ }
+
+ buffer->logical = gcvNULL;
+ }
+
+ /* Free context buffer. */
+ gcmkONERROR(gcmkOS_SAFE_FREE(Context->os, buffer));
+
+ /* Remove from the list. */
+ Context->buffer = next;
+ }
+
+#if gcdSECURE_USER
+ /* Free the hint array. */
+ if (Context->hint != gcvNULL)
+ {
+ gcmkONERROR(gcmkOS_SAFE_FREE(Context->os, Context->hint));
+ }
+#endif
+
+ /* Mark the gckCONTEXT object as unknown. */
+ Context->object.type = gcvOBJ_UNKNOWN;
+
+ /* Free the gckCONTEXT object. */
+ gcmkONERROR(gcmkOS_SAFE_FREE(Context->os, Context));
+ }
+
+OnError:
+ return status;
+}
+
+#if (gcdENABLE_3D || gcdENABLE_2D)
+static gceSTATUS
+_AllocateContextBuffer(
+ IN gckCONTEXT Context,
+ IN gcsCONTEXT_PTR Buffer
+ )
+{
+ gceSTATUS status;
+ gctPOINTER pointer;
+ gctUINT32 address;
+ gctSIZE_T totalSize = Context->totalSize;
+
+ if (Context->hardware->kernel->virtualCommandBuffer)
+ {
+ gcmkONERROR(gckKERNEL_AllocateVirtualCommandBuffer(
+ Context->hardware->kernel,
+ gcvFALSE,
+ &totalSize,
+ &Buffer->physical,
+ &pointer
+ ));
+
+ gcmkONERROR(gckKERNEL_GetGPUAddress(
+ Context->hardware->kernel,
+ pointer,
+ gcvFALSE,
+ Buffer->physical,
+ &address
+ ));
+ }
+ else
+ {
+ gcmkONERROR(gckOS_AllocateContiguous(
+ Context->os,
+ gcvFALSE,
+ &totalSize,
+ &Buffer->physical,
+ &pointer
+ ));
+
+ gcmkONERROR(gckHARDWARE_ConvertLogical(
+ Context->hardware,
+ pointer,
+ gcvFALSE,
+ &address
+ ));
+ }
+
+ Buffer->logical = pointer;
+ Buffer->address = address;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+#endif
+
+/******************************************************************************\
+**************************** Context Management API ****************************
+\******************************************************************************/
+
+/******************************************************************************\
+**
+** gckCONTEXT_Construct
+**
+** Construct a new gckCONTEXT object.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to gckOS object.
+**
+** gctUINT32 ProcessID
+** Current process ID.
+**
+** gckHARDWARE Hardware
+** Pointer to gckHARDWARE object.
+**
+** OUTPUT:
+**
+** gckCONTEXT * Context
+** Pointer to a variable thet will receive the gckCONTEXT object
+** pointer.
+*/
+#if (gcdENABLE_3D || gcdENABLE_2D)
+gceSTATUS
+gckCONTEXT_Construct(
+ IN gckOS Os,
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 ProcessID,
+ OUT gckCONTEXT * Context
+ )
+{
+ gceSTATUS status;
+ gckCONTEXT context = gcvNULL;
+ gctUINT32 allocationSize;
+ gctUINT i;
+ gctPOINTER pointer = gcvNULL;
+
+ gcmkHEADER_ARG("Os=0x%08X Hardware=0x%08X", Os, Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Context != gcvNULL);
+
+
+ /**************************************************************************/
+ /* Allocate and initialize basic fields of gckCONTEXT. ********************/
+
+ /* The context object size. */
+ allocationSize = gcmSIZEOF(struct _gckCONTEXT);
+
+ /* Allocate the object. */
+ gcmkONERROR(gckOS_Allocate(
+ Os, allocationSize, &pointer
+ ));
+
+ context = pointer;
+
+ /* Reset the entire object. */
+ gcmkONERROR(gckOS_ZeroMemory(context, allocationSize));
+
+ /* Initialize the gckCONTEXT object. */
+ context->object.type = gcvOBJ_CONTEXT;
+ context->os = Os;
+ context->hardware = Hardware;
+
+
+#if !gcdENABLE_3D
+ context->entryPipe = gcvPIPE_2D;
+ context->exitPipe = gcvPIPE_2D;
+#elif gcdCMD_NO_2D_CONTEXT
+ context->entryPipe = gcvPIPE_3D;
+ context->exitPipe = gcvPIPE_3D;
+#else
+ context->entryPipe
+ = (((((gctUINT32) (context->hardware->identity.chipFeatures)) >> (0 ? 9:9)) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1)))))) )
+ ? gcvPIPE_2D
+ : gcvPIPE_3D;
+ context->exitPipe = gcvPIPE_3D;
+#endif
+
+ /* Get the command buffer requirements. */
+ gcmkONERROR(gckHARDWARE_QueryCommandBuffer(
+ Hardware,
+ gcvENGINE_RENDER,
+ &context->alignment,
+ &context->reservedHead,
+ gcvNULL
+ ));
+
+ /**************************************************************************/
+ /* Get the size of the context buffer. ************************************/
+
+ gcmkONERROR(_InitializeContextBuffer(context));
+
+ if (context->maxState > 0)
+ {
+ /**************************************************************************/
+ /* Allocate and reset the state mapping table. ****************************/
+ if (context->hardware->kernel->command->stateMap == gcvNULL)
+ {
+ /* Allocate the state mapping table. */
+ gcmkONERROR(gckOS_Allocate(
+ Os,
+ gcmSIZEOF(gcsSTATE_MAP) * context->maxState,
+ &pointer
+ ));
+
+ context->map = pointer;
+
+ /* Zero the state mapping table. */
+ gcmkONERROR(gckOS_ZeroMemory(
+ context->map, gcmSIZEOF(gcsSTATE_MAP) * context->maxState
+ ));
+
+ context->hardware->kernel->command->stateMap = pointer;
+ }
+ else
+ {
+ context->map = context->hardware->kernel->command->stateMap;
+ }
+
+ /**************************************************************************/
+ /* Allocate the hint array. ***********************************************/
+
+#if gcdSECURE_USER
+ /* Allocate hints. */
+ gcmkONERROR(gckOS_Allocate(
+ Os,
+ gcmSIZEOF(gctBOOL) * context->maxState,
+ &pointer
+ ));
+
+ context->hint = pointer;
+#endif
+ }
+
+ /**************************************************************************/
+ /* Allocate the context and state delta buffers. **************************/
+
+ for (i = 0; i < gcdCONTEXT_BUFFER_COUNT; i += 1)
+ {
+ /* Allocate a context buffer. */
+ gcsCONTEXT_PTR buffer;
+
+ /* Allocate the context buffer structure. */
+ gcmkONERROR(gckOS_Allocate(
+ Os,
+ gcmSIZEOF(gcsCONTEXT),
+ &pointer
+ ));
+
+ buffer = pointer;
+
+ /* Reset the context buffer structure. */
+ gcmkVERIFY_OK(gckOS_ZeroMemory(
+ buffer, gcmSIZEOF(gcsCONTEXT)
+ ));
+
+ /* Append to the list. */
+ if (context->buffer == gcvNULL)
+ {
+ buffer->next = buffer;
+ context->buffer = buffer;
+ }
+ else
+ {
+ buffer->next = context->buffer->next;
+ context->buffer->next = buffer;
+ }
+
+ /* Set the number of delta in the order of creation. */
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+ buffer->num = i;
+#endif
+
+ /* Create the busy signal. */
+ gcmkONERROR(gckOS_CreateSignal(
+ Os, gcvFALSE, &buffer->signal
+ ));
+
+ /* Set the signal, buffer is currently not busy. */
+ gcmkONERROR(gckOS_Signal(
+ Os, buffer->signal, gcvTRUE
+ ));
+
+ /* Create a new physical context buffer. */
+ gcmkONERROR(_AllocateContextBuffer(
+ context, buffer
+ ));
+
+ /* Set gckEVENT object pointer. */
+ buffer->eventObj = Hardware->kernel->eventObj;
+
+ /* Set the pointers to the LINK commands. */
+ if (context->linkIndex2D != 0)
+ {
+ buffer->link2D = &buffer->logical[context->linkIndex2D];
+ }
+
+ if (context->linkIndex3D != 0)
+ {
+ buffer->link3D = &buffer->logical[context->linkIndex3D];
+ }
+
+ if (context->linkIndexXD != 0)
+ {
+ gctPOINTER xdLink;
+ gctUINT32 xdEntryAddress;
+ gctUINT32 xdEntrySize;
+ gctUINT32 linkBytes;
+
+ /* Determine LINK parameters. */
+ xdLink
+ = &buffer->logical[context->linkIndexXD];
+
+ xdEntryAddress
+ = buffer->address
+ + context->entryOffsetXDFrom3D;
+
+ xdEntrySize
+ = context->bufferSize
+ - context->entryOffsetXDFrom3D;
+
+ /* Query LINK size. */
+ gcmkONERROR(gckHARDWARE_Link(
+ Hardware, gcvNULL, 0, 0, &linkBytes, gcvNULL, gcvNULL
+ ));
+
+ /* Generate a LINK. */
+ gcmkONERROR(gckHARDWARE_Link(
+ Hardware,
+ xdLink,
+ xdEntryAddress,
+ xdEntrySize,
+ &linkBytes,
+ gcvNULL,
+ gcvNULL
+ ));
+ }
+ }
+
+
+ /**************************************************************************/
+ /* Initialize the context buffers. ****************************************/
+
+ /* Initialize the current context buffer. */
+ gcmkONERROR(_InitializeContextBuffer(context));
+
+ /* Make all created contexts equal. */
+ {
+ gcsCONTEXT_PTR currContext, tempContext;
+
+ /* Set the current context buffer. */
+ currContext = context->buffer;
+
+ /* Get the next context buffer. */
+ tempContext = currContext->next;
+
+ /* Loop through all buffers. */
+ while (tempContext != currContext)
+ {
+ if (tempContext == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+
+ /* Copy the current context. */
+ gckOS_MemCopy(
+ tempContext->logical,
+ currContext->logical,
+ context->totalSize
+ );
+
+ /* Get the next context buffer. */
+ tempContext = tempContext->next;
+ }
+ }
+
+ /* Return pointer to the gckCONTEXT object. */
+ *Context = context;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Context=0x%08X", *Context);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Roll back on error. */
+ gcmkVERIFY_OK(_DestroyContext(context));
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+#endif
+
+/******************************************************************************\
+**
+** gckCONTEXT_Destroy
+**
+** Destroy a gckCONTEXT object.
+**
+** INPUT:
+**
+** gckCONTEXT Context
+** Pointer to an gckCONTEXT object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckCONTEXT_Destroy(
+ IN gckCONTEXT Context
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Context=0x%08X", Context);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Context, gcvOBJ_CONTEXT);
+
+ /* Destroy the context and all related objects. */
+ status = _DestroyContext(Context);
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return status;
+}
+
+/******************************************************************************\
+**
+** gckCONTEXT_Update
+**
+** Merge all pending state delta buffers into the current context buffer.
+**
+** INPUT:
+**
+** gckCONTEXT Context
+** Pointer to an gckCONTEXT object.
+**
+** gctUINT32 ProcessID
+** Current process ID.
+**
+** gcsSTATE_DELTA_PTR StateDelta
+** Pointer to the state delta.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckCONTEXT_Update(
+ IN gckCONTEXT Context,
+ IN gctUINT32 ProcessID,
+ IN gcsSTATE_DELTA_PTR StateDelta
+ )
+{
+#if gcdENABLE_3D
+ gceSTATUS status = gcvSTATUS_OK;
+ gcsSTATE_DELTA _stateDelta;
+ gckKERNEL kernel;
+ gcsCONTEXT_PTR buffer;
+ gcsSTATE_MAP_PTR map;
+ gctBOOL needCopy = gcvFALSE;
+ gcsSTATE_DELTA_PTR uDelta = gcvNULL;
+ gcsSTATE_DELTA_PTR kDelta = gcvNULL;
+ gcsSTATE_DELTA_RECORD_PTR record;
+ gcsSTATE_DELTA_RECORD_PTR recordArray = gcvNULL;
+ gctUINT elementCount;
+ gctUINT address;
+ gctUINT32 mask;
+ gctUINT32 data;
+ gctUINT index;
+ gctUINT i, j;
+ gctUINT32 dirtyRecordArraySize = 0;
+
+#if gcdSECURE_USER
+ gcskSECURE_CACHE_PTR cache;
+#endif
+
+ gcmkHEADER_ARG(
+ "Context=0x%08X ProcessID=%d StateDelta=0x%08X",
+ Context, ProcessID, StateDelta
+ );
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Context, gcvOBJ_CONTEXT);
+
+ /* Get a shortcut to the kernel object. */
+ kernel = Context->hardware->kernel;
+
+ /* Check wehther we need to copy the structures or not. */
+ gcmkONERROR(gckOS_QueryNeedCopy(Context->os, ProcessID, &needCopy));
+
+ /* Get the current context buffer. */
+ buffer = Context->buffer;
+
+ /* Wait until the context buffer becomes available; this will
+ also reset the signal and mark the buffer as busy. */
+ gcmkONERROR(gckOS_WaitSignal(
+ Context->os, buffer->signal, gcvFALSE, gcvINFINITE
+ ));
+
+#if gcdSECURE_USER
+ /* Get the cache form the database. */
+ gcmkONERROR(gckKERNEL_GetProcessDBCache(kernel, ProcessID, &cache));
+#endif
+
+#if gcmIS_DEBUG(gcdDEBUG_CODE) && 1 && gcdENABLE_3D
+ /* Update current context token. */
+ buffer->logical[Context->map[0x0E14].index]
+ = (gctUINT32)gcmPTR2INT32(Context);
+#endif
+
+ if (StateDelta != gcvNULL)
+ {
+ /* Get the state map. */
+ map = Context->map;
+
+ /* Get the first delta item. */
+ uDelta = StateDelta;
+
+ /* Reset the vertex stream count. */
+ elementCount = 0;
+
+ /* Merge all pending deltas. */
+ {
+ /* Get access to the state delta. */
+ gcmkONERROR(gckKERNEL_OpenUserData(
+ kernel, needCopy,
+ &_stateDelta,
+ uDelta, gcmSIZEOF(gcsSTATE_DELTA),
+ (gctPOINTER *) &kDelta
+ ));
+
+ dirtyRecordArraySize
+ = gcmSIZEOF(gcsSTATE_DELTA_RECORD) * kDelta->recordCount;
+
+ if (dirtyRecordArraySize)
+ {
+ /* Get access to the state records. */
+ gcmkONERROR(gckOS_MapUserPointer(
+ kernel->os,
+ gcmUINT64_TO_PTR(kDelta->recordArray),
+ dirtyRecordArraySize,
+ (gctPOINTER *) &recordArray
+ ));
+ }
+
+ /* Merge all pending states. */
+ for (j = 0; j < kDelta->recordCount; j += 1)
+ {
+ if (j >= Context->numStates)
+ {
+ break;
+ }
+
+ /* Get the current state record. */
+ record = &recordArray[j];
+
+ /* Get the state address. */
+ gcmkONERROR(gckOS_ReadMappedPointer(kernel->os, &record->address, &address));
+
+ /* Make sure the state is a part of the mapping table. */
+ if (address >= Context->maxState)
+ {
+ gcmkTRACE(
+ gcvLEVEL_ERROR,
+ "%s(%d): State 0x%04X (0x%04X) is not mapped.\n",
+ __FUNCTION__, __LINE__,
+ address, address << 2
+ );
+
+ continue;
+ }
+
+ /* Get the state index. */
+ index = map[address].index;
+
+ /* Skip the state if not mapped. */
+ if (index == 0)
+ {
+ continue;
+ }
+
+ /* Get the data mask. */
+ gcmkONERROR(gckOS_ReadMappedPointer(kernel->os, &record->mask, &mask));
+
+ /* Get the new data value. */
+ gcmkONERROR(gckOS_ReadMappedPointer(kernel->os, &record->data, &data));
+
+ /* Masked states that are being completly reset or regular states. */
+ if ((mask == 0) || (mask == ~0U))
+ {
+ /* Process special states. */
+ if (address == 0x0595)
+ {
+ /* Force auto-disable to be disabled. */
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ? 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)));
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ? 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)));
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 13:13) - (0 ? 13:13) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 13:13) - (0 ?
+ 13:13) + 1))))))) << (0 ? 13:13))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 13:13) - (0 ? 13:13) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 13:13) - (0 ?
+ 13:13) + 1))))))) << (0 ? 13:13)));
+ }
+
+#if gcdSECURE_USER
+ /* Do we need to convert the logical address? */
+ if (Context->hint[address])
+ {
+ /* Map handle into physical address. */
+ gcmkONERROR(gckKERNEL_MapLogicalToPhysical(
+ kernel, cache, (gctPOINTER) &data
+ ));
+ }
+#endif
+
+ /* Set new data. */
+ buffer->logical[index] = data;
+ }
+
+ /* Masked states that are being set partially. */
+ else
+ {
+ buffer->logical[index]
+ = (~mask & buffer->logical[index])
+ | (mask & data);
+ }
+ }
+
+ /* Get the element count. */
+ if (kDelta->elementCount != 0)
+ {
+ elementCount = kDelta->elementCount;
+ }
+
+ if (dirtyRecordArraySize)
+ {
+ /* Get access to the state records. */
+ gcmkONERROR(gckOS_UnmapUserPointer(
+ kernel->os,
+ gcmUINT64_TO_PTR(kDelta->recordArray),
+ dirtyRecordArraySize,
+ recordArray
+ ));
+
+ recordArray = gcvNULL;
+ }
+
+ /* Close access to the current state delta. */
+ gcmkONERROR(gckKERNEL_CloseUserData(
+ kernel, needCopy,
+ gcvTRUE,
+ uDelta, gcmSIZEOF(gcsSTATE_DELTA),
+ (gctPOINTER *) &kDelta
+ ));
+ }
+
+ /* Hardware disables all input attribute when the attribute 0 is programmed,
+ it then reenables those attributes that were explicitely programmed by
+ the software. Because of this we cannot program the entire array of
+ values, otherwise we'll get all attributes reenabled, but rather program
+ only those that are actully needed by the software.
+ elementCount = attribCount + 1 to make sure 0 is a flag to indicate if UMD
+ touches it.
+ */
+ if (elementCount != 0)
+ {
+ gctUINT base;
+ gctUINT nopCount;
+ gctUINT32_PTR nop;
+ gctUINT fe2vsCount;
+ gctUINT attribCount = elementCount -1;
+ gctUINT32 feAttributeStatgeAddr = 0x0180;
+ if (gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_HALTI5))
+ {
+ fe2vsCount = 32;
+ base = map[0x5E00].index;
+ feAttributeStatgeAddr = 0x5E00;
+ }
+ else if (gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_HALTI0))
+ {
+ fe2vsCount = 16;
+ base = map[0x0180].index;
+ }
+ else
+ {
+ fe2vsCount = 12;
+ base = map[0x0180].index;
+ }
+
+ /* Set the proper state count. */
+ if (attribCount == 0)
+ {
+ gcmkASSERT(gckHARDWARE_IsFeatureAvailable(Context->hardware, gcvFEATURE_ZERO_ATTRIB_SUPPORT));
+
+ buffer->logical[base - 1]
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ? 26:26) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ? 26:26))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ? 26:26) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ? 26:26)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (feAttributeStatgeAddr) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ /* Set the proper state count. */
+ buffer->logical[base + 1] =
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ? 26:26) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ? 26:26))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ? 26:26) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ? 26:26)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x01F2) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+ buffer->logical[base + 2] = 0x1;
+ attribCount = 3;
+ }
+ else
+ {
+ buffer->logical[base - 1]
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:26) - (0 ? 26:26) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ? 26:26))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 26:26) - (0 ? 26:26) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 26:26) - (0 ?
+ 26:26) + 1))))))) << (0 ? 26:26)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (attribCount) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (feAttributeStatgeAddr) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+ }
+
+ /* Determine the number of NOP commands. */
+ nopCount = (fe2vsCount / 2) - (attribCount / 2);
+ /* Determine the location of the first NOP. */
+ nop = &buffer->logical[base + (attribCount | 1)];
+
+ /* Fill the unused space with NOPs. */
+ for (i = 0; i < nopCount; i += 1)
+ {
+ if (nop >= buffer->logical + Context->totalSize)
+ {
+ break;
+ }
+
+ /* Generate a NOP command. */
+ *nop = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ /* Advance. */
+ nop += 2;
+ }
+ }
+ }
+
+ /* Schedule an event to mark the context buffer as available. */
+ gcmkONERROR(gckEVENT_Signal(
+ buffer->eventObj, buffer->signal, gcvKERNEL_PIXEL
+ ));
+
+ /* Advance to the next context buffer. */
+ Context->buffer = buffer->next;
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Get access to the state records. */
+ if (kDelta != gcvNULL && recordArray != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+ kernel->os,
+ gcmUINT64_TO_PTR(kDelta->recordArray),
+ dirtyRecordArraySize,
+ (gctPOINTER *) &recordArray
+ ));
+ }
+
+ /* Close access to the current state delta. */
+ gcmkVERIFY_OK(gckKERNEL_CloseUserData(
+ kernel, needCopy,
+ gcvTRUE,
+ uDelta, gcmSIZEOF(gcsSTATE_DELTA),
+ (gctPOINTER *) &kDelta
+ ));
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+#else
+ return gcvSTATUS_OK;
+#endif
+}
+
+gceSTATUS
+gckCONTEXT_MapBuffer(
+ IN gckCONTEXT Context,
+ OUT gctUINT32 *Physicals,
+ OUT gctUINT64 *Logicals,
+ OUT gctUINT32 *Bytes
+ )
+{
+ gceSTATUS status;
+ int i = 0;
+ gctSIZE_T pageCount;
+ gckVIRTUAL_COMMAND_BUFFER_PTR commandBuffer;
+ gckKERNEL kernel = Context->hardware->kernel;
+ gctPOINTER logical;
+ gctPHYS_ADDR physical;
+
+ gcsCONTEXT_PTR buffer;
+
+ gcmkHEADER();
+
+ gcmkVERIFY_OBJECT(Context, gcvOBJ_CONTEXT);
+
+ buffer = Context->buffer;
+
+ for (i = 0; i < gcdCONTEXT_BUFFER_COUNT; i++)
+ {
+ if (kernel->virtualCommandBuffer)
+ {
+ commandBuffer = (gckVIRTUAL_COMMAND_BUFFER_PTR)buffer->physical;
+ physical = commandBuffer->virtualBuffer.physical;
+
+ gcmkONERROR(gckOS_CreateUserVirtualMapping(
+ kernel->os,
+ physical,
+ Context->totalSize,
+ &logical,
+ &pageCount));
+ }
+ else
+ {
+ physical = buffer->physical;
+
+ gcmkONERROR(gckOS_MapMemory(
+ kernel->os,
+ physical,
+ Context->totalSize,
+ &logical));
+ }
+
+ Physicals[i] = gcmPTR_TO_NAME(physical);
+
+ Logicals[i] = gcmPTR_TO_UINT64(logical);
+
+ buffer = buffer->next;
+ }
+
+ *Bytes = (gctUINT)Context->totalSize;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_context.h b/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_context.h
new file mode 100644
index 000000000000..d92b1e38f5bf
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_context.h
@@ -0,0 +1,188 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_context_h_
+#define __gc_hal_kernel_context_h_
+
+#include "gc_hal_kernel_buffer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Maps state locations within the context buffer. */
+typedef struct _gcsSTATE_MAP * gcsSTATE_MAP_PTR;
+typedef struct _gcsSTATE_MAP
+{
+ /* Index of the state in the context buffer. */
+ gctUINT index;
+
+ /* State mask. */
+ gctUINT32 mask;
+}
+gcsSTATE_MAP;
+
+/* Context buffer. */
+typedef struct _gcsCONTEXT * gcsCONTEXT_PTR;
+typedef struct _gcsCONTEXT
+{
+ /* For debugging: the number of context buffer in the order of creation. */
+ gctUINT num;
+
+ /* Pointer to gckEVENT object. */
+ gckEVENT eventObj;
+
+ /* Context busy signal. */
+ gctSIGNAL signal;
+
+ /* Physical address of the context buffer. */
+ gctPHYS_ADDR physical;
+
+ /* Logical address of the context buffer. */
+ gctUINT32_PTR logical;
+
+ /* Hardware address of the context buffer. */
+ gctUINT32 address;
+
+ /* Pointer to the LINK commands. */
+ gctPOINTER link2D;
+ gctPOINTER link3D;
+
+ /* Next context buffer. */
+ gcsCONTEXT_PTR next;
+}
+gcsCONTEXT;
+
+typedef struct _gcsRECORD_ARRAY_MAP * gcsRECORD_ARRAY_MAP_PTR;
+struct _gcsRECORD_ARRAY_MAP
+{
+ /* User pointer key. */
+ gctUINT64 key;
+
+ /* Kernel memory buffer. */
+ gcsSTATE_DELTA_RECORD_PTR kData;
+
+ /* Next map. */
+ gcsRECORD_ARRAY_MAP_PTR next;
+
+};
+
+#define USE_SW_RESET 1
+
+/* gckCONTEXT structure that hold the current context. */
+struct _gckCONTEXT
+{
+ /* Object. */
+ gcsOBJECT object;
+
+ /* Pointer to gckOS object. */
+ gckOS os;
+
+ /* Pointer to gckHARDWARE object. */
+ gckHARDWARE hardware;
+
+ /* Command buffer alignment. */
+ gctUINT32 alignment;
+ gctUINT32 reservedHead;
+
+ /* Context buffer metrics. */
+ gctSIZE_T maxState;
+ gctUINT32 numStates;
+ gctUINT32 totalSize;
+ gctUINT32 bufferSize;
+ gctUINT32 linkIndex2D;
+ gctUINT32 linkIndex3D;
+ gctUINT32 linkIndexXD;
+ gctUINT32 entryOffset3D;
+ gctUINT32 entryOffsetXDFrom2D;
+ gctUINT32 entryOffsetXDFrom3D;
+
+ /* State mapping. */
+ gcsSTATE_MAP_PTR map;
+
+ /* List of context buffers. */
+ gcsCONTEXT_PTR buffer;
+
+ /* Requested pipe select for context. */
+ gcePIPE_SELECT entryPipe;
+ gcePIPE_SELECT exitPipe;
+
+ /* Variables used for building state buffer. */
+ gctUINT32 lastAddress;
+ gctSIZE_T lastSize;
+ gctUINT32 lastIndex;
+ gctBOOL lastFixed;
+
+ gctUINT32 pipeSelectBytes;
+
+ /* Hint array. */
+#if gcdSECURE_USER
+ gctBOOL_PTR hint;
+#endif
+
+ gcsPROFILER_COUNTERS_PART1 latestProfiler_part1;
+ gcsPROFILER_COUNTERS_PART1 histroyProfiler_part1;
+ gcsPROFILER_COUNTERS_PART1 preProfiler_part1;
+ gcsPROFILER_COUNTERS_PART2 latestProfiler_part2;
+ gcsPROFILER_COUNTERS_PART2 histroyProfiler_part2;
+ gcsPROFILER_COUNTERS_PART2 preProfiler_part2;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_kernel_context_h_ */
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware.c b/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware.c
new file mode 100644
index 000000000000..ca4e96a8a5ef
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware.c
@@ -0,0 +1,13717 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_context.h"
+
+#include "gc_feature_database.h"
+
+#define _GC_OBJ_ZONE gcvZONE_HARDWARE
+
+#define gcmSEMAPHORESTALL(buffer) \
+ do \
+ { \
+ /* Arm the PE-FE Semaphore. */ \
+ *buffer++ \
+ = gcmSETFIELDVALUE(0, AQ_COMMAND_LOAD_STATE_COMMAND, OPCODE, LOAD_STATE) \
+ | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, COUNT, 1) \
+ | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, ADDRESS, 0x0E02); \
+ \
+ *buffer++ \
+ = gcmSETFIELDVALUE(0, AQ_SEMAPHORE, SOURCE, FRONT_END) \
+ | gcmSETFIELDVALUE(0, AQ_SEMAPHORE, DESTINATION, PIXEL_ENGINE);\
+ \
+ /* STALL FE until PE is done flushing. */ \
+ *buffer++ \
+ = gcmSETFIELDVALUE(0, STALL_COMMAND, OPCODE, STALL); \
+ \
+ *buffer++ \
+ = gcmSETFIELDVALUE(0, STALL_STALL, SOURCE, FRONT_END) \
+ | gcmSETFIELDVALUE(0, STALL_STALL, DESTINATION, PIXEL_ENGINE); \
+ } while(0)
+
+typedef struct _gcsiDEBUG_REGISTERS * gcsiDEBUG_REGISTERS_PTR;
+typedef struct _gcsiDEBUG_REGISTERS
+{
+ gctSTRING module;
+ gctUINT index;
+ gctUINT shift;
+ gctUINT data;
+ gctUINT count;
+ gctUINT32 pipeMask;
+ gctUINT32 selectStart;
+}
+gcsiDEBUG_REGISTERS;
+
+typedef struct _gcsFE_STACK
+{
+ gctSTRING name;
+ gctINT count;
+ gctUINT32 highSelect;
+ gctUINT32 lowSelect;
+ gctUINT32 linkSelect;
+ gctUINT32 clear;
+ gctUINT32 next;
+}
+gcsFE_STACK;
+
+/******************************************************************************\
+********************************* Support Code *********************************
+\******************************************************************************/
+static gctBOOL
+_IsHardwareMatch(
+ IN gckHARDWARE Hardware,
+ IN gctINT32 ChipModel,
+ IN gctUINT32 ChipRevision
+ )
+{
+ return ((Hardware->identity.chipModel == ChipModel) &&
+ (Hardware->identity.chipRevision == ChipRevision));
+}
+
+static gceSTATUS
+_ResetGPU(
+ IN gckHARDWARE Hardware,
+ IN gckOS Os,
+ IN gceCORE Core
+ );
+
+static void
+_GetEcoID(
+ IN gckHARDWARE Hardware,
+ IN OUT gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity
+ )
+{
+ gcmkVERIFY_OK(gckOS_ReadRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x000E8,
+ &Identity->ecoID
+ ));
+
+ if (_IsHardwareMatch(Hardware, 0x1000, 0x5037) && (Identity->chipDate == 0x20120617))
+ {
+ Identity->ecoID = 1;
+ }
+
+ if (_IsHardwareMatch(Hardware, 0x320, 0x5303) && (Identity->chipDate == 0x20140511))
+ {
+ Identity->ecoID = 1;
+ }
+
+}
+
+static gceSTATUS
+_IdentifyHardwareByDatabase(
+ IN gckHARDWARE Hardware,
+ IN gckOS Os,
+ IN gceCORE Core,
+ OUT gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity
+ )
+{
+ gceSTATUS status;
+ gctUINT32 chipIdentity;
+ gctUINT32 debugControl0;
+ gctUINT32 chipInfo;
+ gcsFEATURE_DATABASE *database;
+
+ gcmkHEADER_ARG("Os=0x%x", Os);
+
+ /* Get chip date. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00028, &Identity->chipDate));
+
+ /***************************************************************************
+ ** Get chip ID and revision.
+ */
+
+ /* Read chip identity register. */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Os, Core,
+ 0x00018,
+ &chipIdentity));
+
+ /* Special case for older graphic cores. */
+ if (((((gctUINT32) (chipIdentity)) >> (0 ? 31:24) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))))
+ {
+ Identity->chipModel = gcv500;
+ Identity->chipRevision = (((((gctUINT32) (chipIdentity)) >> (0 ? 15:12)) & ((gctUINT32) ((((1 ? 15:12) - (0 ? 15:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:12) - (0 ? 15:12) + 1)))))) );
+ }
+
+ else
+ {
+ /* Read chip identity register. */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Os, Core,
+ 0x00020,
+ (gctUINT32_PTR) &Identity->chipModel));
+
+ if (((Identity->chipModel & 0xFF00) == 0x0400)
+ && (Identity->chipModel != 0x0420)
+ && (Identity->chipModel != 0x0428))
+ {
+ Identity->chipModel = (gceCHIPMODEL) (Identity->chipModel & 0x0400);
+ }
+
+ /* Read CHIP_REV register. */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Os, Core,
+ 0x00024,
+ &Identity->chipRevision));
+
+ if ((Identity->chipModel == gcv300)
+ && (Identity->chipRevision == 0x2201)
+ )
+ {
+ gctUINT32 chipDate;
+ gctUINT32 chipTime;
+
+ /* Read date and time registers. */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Os, Core,
+ 0x00028,
+ &chipDate));
+
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Os, Core,
+ 0x0002C,
+ &chipTime));
+
+ if ((chipDate == 0x20080814) && (chipTime == 0x12051100))
+ {
+ /* This IP has an ECO; put the correct revision in it. */
+ Identity->chipRevision = 0x1051;
+ }
+ }
+
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Os, Core,
+ 0x000A8,
+ &Identity->productID));
+ }
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "Identity: chipModel=%X",
+ Identity->chipModel);
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "Identity: chipRevision=%X",
+ Identity->chipRevision);
+
+ _GetEcoID(Hardware, Identity);
+
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Os, Core,
+ 0x00030,
+ &Identity->customerID));
+
+ /***************************************************************************
+ ** Get chip features.
+ */
+
+ database =
+ Hardware->featureDatabase =
+ gcQueryFeatureDB(
+ Hardware->identity.chipModel,
+ Hardware->identity.chipRevision,
+ Hardware->identity.productID,
+ Hardware->identity.ecoID,
+ Hardware->identity.customerID);
+
+ if (database == gcvNULL)
+ {
+ gcmkPRINT("[galcore]: Feature database is not found,"
+ "chipModel=0x%0x, chipRevision=0x%x, productID=0x%x, ecoID=0x%x, customerID=0x%x",
+ Hardware->identity.chipModel,
+ Hardware->identity.chipRevision,
+ Hardware->identity.productID,
+ Hardware->identity.ecoID,
+ Hardware->identity.customerID);
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+
+ Identity->pixelPipes = database->NumPixelPipes;
+ Identity->resolvePipes = database->NumResolvePipes;
+ Identity->instructionCount = database->InstructionCount;
+ Identity->numConstants = database->NumberOfConstants;
+ Identity->varyingsCount = database->VaryingCount;
+ Identity->gpuCoreCount = database->CoreCount;
+ Identity->streamCount = database->Streams;
+
+ if (Identity->chipModel == gcv320)
+ {
+ gctUINT32 data;
+
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Os,
+ Core,
+ 0x0002C,
+ &data));
+
+ if ((data != 33956864) &&
+ ((Identity->chipRevision == 0x5007) ||
+ (Identity->chipRevision == 0x5220)))
+ {
+ Hardware->maxOutstandingReads = 0xFF &
+ (Identity->chipRevision == 0x5220 ? 8 :
+ (Identity->chipRevision == 0x5007 ? 12 : 0));
+ }
+ }
+
+ if (_IsHardwareMatch(Hardware, gcv880, 0x5107))
+ {
+ Hardware->maxOutstandingReads = 0x00010;
+ }
+
+ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00470, &debugControl0));
+
+ if (debugControl0 & (1 << 16))
+ {
+ Identity->chipFlags |= gcvCHIP_FLAG_MSAA_COHERENCEY_ECO_FIX;
+ }
+
+ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x000A4, &chipInfo));
+
+ if (((((gctUINT32) (chipInfo)) >> (0 ? 21:21) & ((gctUINT32) ((((1 ?
+ 21:21) - (0 ? 21:21) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 21:21) - (0 ?
+ 21:21) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 21:21) - (0 ? 21:21) + 1))))))))
+ {
+ Identity->chipFlags |= gcvCHIP_AXI_BUS128_BITS;
+ }
+
+ /* Success. */
+ gcmkFOOTER();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+_GetHardwareSignature(
+ IN gckHARDWARE Hardware,
+ IN gckOS Os,
+ IN gceCORE Core,
+ OUT gcsHARDWARE_SIGNATURE * Signature
+ )
+{
+ gceSTATUS status;
+
+ gctUINT32 chipIdentity;
+
+ gcmkHEADER_ARG("Os=0x%x", Os);
+
+ /***************************************************************************
+ ** Get chip ID and revision.
+ */
+
+ /* Read chip identity register. */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Os, Core,
+ 0x00018,
+ &chipIdentity));
+
+ /* Special case for older graphic cores. */
+ if (((((gctUINT32) (chipIdentity)) >> (0 ? 31:24) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))))
+ {
+ Signature->chipModel = gcv500;
+ Signature->chipRevision = (((((gctUINT32) (chipIdentity)) >> (0 ? 15:12)) & ((gctUINT32) ((((1 ? 15:12) - (0 ? 15:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:12) - (0 ? 15:12) + 1)))))) );
+ }
+
+ else
+ {
+ /* Read chip identity register. */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Os, Core,
+ 0x00020,
+ (gctUINT32_PTR) &Signature->chipModel));
+
+ /* Read CHIP_REV register. */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Os, Core,
+ 0x00024,
+ &Signature->chipRevision));
+ }
+
+ /***************************************************************************
+ ** Get chip features.
+ */
+
+ /* Read chip feature register. */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Os, Core,
+ 0x0001C,
+ &Signature->chipFeatures));
+
+ if (((Signature->chipModel == gcv500) && (Signature->chipRevision < 2))
+ || ((Signature->chipModel == gcv300) && (Signature->chipRevision < 0x2000))
+ )
+ {
+ /* GC500 rev 1.x and GC300 rev < 2.0 doesn't have these registers. */
+ Signature->chipMinorFeatures = 0;
+ Signature->chipMinorFeatures1 = 0;
+ Signature->chipMinorFeatures2 = 0;
+ }
+ else
+ {
+ /* Read chip minor feature register #0. */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Os, Core,
+ 0x00034,
+ &Signature->chipMinorFeatures));
+
+ if (((((gctUINT32) (Signature->chipMinorFeatures)) >> (0 ? 21:21) & ((gctUINT32) ((((1 ?
+ 21:21) - (0 ? 21:21) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 21:21) - (0 ?
+ 21:21) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 21:21) - (0 ? 21:21) + 1)))))))
+ )
+ {
+ /* Read chip minor features register #1. */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Os, Core,
+ 0x00074,
+ &Signature->chipMinorFeatures1));
+
+ /* Read chip minor features register #2. */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Os, Core,
+ 0x00084,
+ &Signature->chipMinorFeatures2));
+ }
+ else
+ {
+ /* Chip doesn't has minor features register #1 or 2 or 3 or 4 or 5. */
+ Signature->chipMinorFeatures1 = 0;
+ Signature->chipMinorFeatures2 = 0;
+ }
+ }
+
+ /* Success. */
+ gcmkFOOTER();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/* Set to 1 to enable module clock gating debug function.
+* Following options take effect when it is set to 1.
+*/
+#define gcdDEBUG_MODULE_CLOCK_GATING 0
+/* Set to 1 to disable module clock gating of all modules. */
+#define gcdDISABLE_MODULE_CLOCK_GATING 0
+/* Set to 1 to disable module clock gating of each module. */
+#define gcdDISABLE_STARVE_MODULE_CLOCK_GATING 0
+#define gcdDISABLE_FE_CLOCK_GATING 0
+#define gcdDISABLE_PE_CLOCK_GATING 0
+#define gcdDISABLE_SH_CLOCK_GATING 0
+#define gcdDISABLE_PA_CLOCK_GATING 0
+#define gcdDISABLE_SE_CLOCK_GATING 0
+#define gcdDISABLE_RA_CLOCK_GATING 0
+#define gcdDISABLE_RA_EZ_CLOCK_GATING 0
+#define gcdDISABLE_RA_HZ_CLOCK_GATING 0
+#define gcdDISABLE_TX_CLOCK_GATING 0
+#define gcdDISABLE_TFB_CLOCK_GATING 0
+#define gcdDISABLE_GPIPE_CLOCK_GATING 0
+#define gcdDISABLE_BLT_CLOCK_GATING 0
+#define gcdDISABLE_TPG_CLOCK_GATING 0
+#define gcdDISABLE_VX_CLOCK_GATING 0
+
+#if gcdDEBUG_MODULE_CLOCK_GATING
+gceSTATUS
+_ConfigureModuleLevelClockGating(
+ gckHARDWARE Hardware
+ )
+{
+ gctUINT32 data;
+
+ gcmkVERIFY_OK(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00104,
+ &data));
+
+#if gcdDISABLE_FE_CLOCK_GATING
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0)));
+#endif
+
+#if gcdDISABLE_PE_CLOCK_GATING
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ? 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 2:2) - (0 ?
+ 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2)));
+#endif
+
+#if gcdDISABLE_SH_CLOCK_GATING
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ? 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 3:3) - (0 ?
+ 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3)));
+#endif
+
+#if gcdDISABLE_PA_CLOCK_GATING
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ? 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 4:4) - (0 ?
+ 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4)));
+#endif
+
+#if gcdDISABLE_SE_CLOCK_GATING
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ? 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 5:5) - (0 ?
+ 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5)));
+#endif
+
+#if gcdDISABLE_RA_CLOCK_GATING
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ? 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 6:6) - (0 ?
+ 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6)));
+#endif
+
+#if gcdDISABLE_TX_CLOCK_GATING
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ? 7:7) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 7:7) - (0 ?
+ 7:7) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ?
+ 7:7)));
+#endif
+
+#if gcdDISABLE_RA_EZ_CLOCK_GATING
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16)));
+#endif
+
+#if gcdDISABLE_RA_HZ_CLOCK_GATING
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ? 17:17) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ? 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ? 17:17) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ? 17:17)));
+#endif
+
+#if gcdDISABLE_TFB_CLOCK_GATING
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:19) - (0 ? 19:19) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 19:19) - (0 ? 19:19) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ? 19:19)));
+#endif
+
+#if gcdDISABLE_GPIPE_CLOCK_GATING
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 22:22) - (0 ? 22:22) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 22:22) - (0 ?
+ 22:22) + 1))))))) << (0 ? 22:22))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 22:22) - (0 ? 22:22) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 22:22) - (0 ?
+ 22:22) + 1))))))) << (0 ? 22:22)));
+#endif
+
+#if gcdDISABLE_BLT_CLOCK_GATING
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:20) - (0 ? 20:20) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 20:20) - (0 ?
+ 20:20) + 1))))))) << (0 ? 20:20))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 20:20) - (0 ? 20:20) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 20:20) - (0 ?
+ 20:20) + 1))))))) << (0 ? 20:20)));
+#endif
+
+#if gcdDISABLE_TPG_CLOCK_GATING
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 18:18) - (0 ? 18:18) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 18:18) - (0 ?
+ 18:18) + 1))))))) << (0 ? 18:18))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 18:18) - (0 ? 18:18) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 18:18) - (0 ?
+ 18:18) + 1))))))) << (0 ? 18:18)));
+#endif
+
+#if gcdDISABLE_VX_CLOCK_GATING
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 21:21) - (0 ? 21:21) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 21:21) - (0 ?
+ 21:21) + 1))))))) << (0 ? 21:21))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 21:21) - (0 ? 21:21) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 21:21) - (0 ?
+ 21:21) + 1))))))) << (0 ? 21:21)));
+#endif
+
+ gcmkVERIFY_OK(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00104,
+ data));
+
+#if gcdDISABLE_STARVE_MODULE_CLOCK_GATING
+ gcmkVERIFY_OK(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress +
+ 0x00100,
+ &data));
+
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ? 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 2:2) - (0 ?
+ 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2)));
+
+ gcmkVERIFY_OK(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00100,
+ data));
+
+#endif
+
+#if gcdDISABLE_MODULE_CLOCK_GATING
+ gcmkVERIFY_OK(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress +
+ 0x00100,
+ &data));
+
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0)));
+
+
+ gcmkVERIFY_OK(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00100,
+ data));
+#endif
+
+ return gcvSTATUS_OK;
+}
+#endif
+
+#if gcdPOWEROFF_TIMEOUT
+void
+_PowerTimerFunction(
+ gctPOINTER Data
+ )
+{
+ gckHARDWARE hardware = (gckHARDWARE)Data;
+ gcmkVERIFY_OK(
+ gckHARDWARE_SetPowerManagementState(hardware, gcvPOWER_OFF_TIMEOUT));
+}
+#endif
+
+static gceSTATUS
+_VerifyDMA(
+ IN gckOS Os,
+ IN gceCORE Core,
+ gctUINT32_PTR Address1,
+ gctUINT32_PTR Address2,
+ gctUINT32_PTR State1,
+ gctUINT32_PTR State2
+ )
+{
+ gceSTATUS status;
+ gctUINT32 i;
+
+ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00660, State1));
+ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00660, State1));
+ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00664, Address1));
+ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00664, Address1));
+
+ for (i = 0; i < 500; i += 1)
+ {
+ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00660, State2));
+ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00660, State2));
+ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00664, Address2));
+ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00664, Address2));
+
+ if (*Address1 != *Address2)
+ {
+ break;
+ }
+
+ if (*State1 != *State2)
+ {
+ break;
+ }
+ }
+
+OnError:
+ return status;
+}
+
+static gceSTATUS
+_DumpDebugRegisters(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gcsiDEBUG_REGISTERS_PTR Descriptor
+ )
+{
+/* If this value is changed, print formats need to be changed too. */
+#define REG_PER_LINE 8
+ gceSTATUS status = gcvSTATUS_OK;
+ gctUINT32 select;
+ gctUINT i, j, pipe;
+ gctUINT32 datas[REG_PER_LINE];
+ gctUINT32 oldControl, control;
+
+ gcmkHEADER_ARG("Os=0x%X Descriptor=0x%X", Os, Descriptor);
+
+ /* Record control. */
+ gckOS_ReadRegisterEx(Os, Core, 0x0, &oldControl);
+
+ for (pipe = 0; pipe < 2; pipe++)
+ {
+ if (!(Descriptor->pipeMask & (1 << pipe)))
+ {
+ continue;
+ }
+
+ gcmkPRINT_N(8, " %s[%d] debug registers:\n", Descriptor->module, pipe);
+
+ /* Switch pipe. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x0, &control));
+ control &= ~(0xF << 20);
+ control |= (pipe << 20);
+ gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x0, control));
+
+ gcmkASSERT(Descriptor->count % REG_PER_LINE);
+
+ for (i = 0; i < Descriptor->count; i += REG_PER_LINE)
+ {
+ /* Select of first one in the group. */
+ select = i + Descriptor->selectStart;
+
+ /* Read a group of registers. */
+ for (j = 0; j < REG_PER_LINE; j++)
+ {
+ /* Shift select to right position. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, (select + j) << Descriptor->shift));
+ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, Descriptor->data, &datas[j]));
+ }
+
+ gcmkPRINT_N(32, " [%02X] %08X %08X %08X %08X %08X %08X %08X %08X\n",
+ select, datas[0], datas[1], datas[2], datas[3], datas[4], datas[5], datas[6], datas[7]);
+ }
+ }
+
+ /* Restore control. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x0, oldControl));
+
+OnError:
+ /* Return the error. */
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+_DumpLinkStack(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gcsiDEBUG_REGISTERS_PTR Descriptor
+ )
+{
+ /* Get wrptr */
+ gctUINT32 shift = Descriptor->shift;
+ gctUINT32 pointerSelect = 0xE << shift;
+ gctUINT32 pointer, wrPtr, rdPtr, links[16];
+ gctUINT32 stackSize = 16;
+ gctUINT32 oldestPtr = 0;
+ gctUINT32 i;
+
+ gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, pointerSelect));
+ gcmkVERIFY_OK(gckOS_ReadRegisterEx(Os, Core, Descriptor->data, &pointer));
+
+ wrPtr = (pointer & 0xF0) >> 4;
+ rdPtr = pointer & 0xF;
+
+ /* Move rdptr to the oldest one (next one to the latest one. ) */
+ oldestPtr = (wrPtr + 1) % stackSize;
+
+ while (rdPtr != oldestPtr)
+ {
+ gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, 0x0));
+ gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, 0xF << shift));
+
+
+ gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, pointerSelect));
+ gcmkVERIFY_OK(gckOS_ReadRegisterEx(Os, Core, Descriptor->data, &pointer));
+
+ rdPtr = pointer & 0xF;
+ }
+
+ gcmkPRINT(" Link stack:");
+
+ /* Read from stack bottom*/
+ for (i = 0; i < stackSize; i++)
+ {
+ gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, 0xD << shift));
+ gcmkVERIFY_OK(gckOS_ReadRegisterEx(Os, Core, Descriptor->data, &links[i]));
+
+ /* Advance rdPtr. */
+ gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, 0x0));
+ gcmkVERIFY_OK(gckOS_WriteRegisterEx(Os, Core, Descriptor->index, 0xF << shift));
+ }
+
+ /* Print. */
+ for (i = 0; i < stackSize; i += 4)
+ {
+ gcmkPRINT_N(32, " [0x%02X] 0x%08X [0x%02X] 0x%08X [0x%02X] 0x%08X [0x%02X] 0x%08X\n",
+ i, links[i], i + 1, links[i + 1], i + 2, links[i + 2], i + 3, links[i + 3]);
+ }
+
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_DumpFEStack(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gcsiDEBUG_REGISTERS_PTR Descriptor
+ )
+{
+ gctUINT i;
+ gctINT j;
+ gctUINT32 stack[32][2];
+ gctUINT32 link[32];
+
+ static gcsFE_STACK _feStacks[] =
+ {
+ { "PRE_STACK", 32, 0x1A, 0x9A, 0x00, 0x1B, 0x1E },
+ { "CMD_STACK", 32, 0x1C, 0x9C, 0x1E, 0x1D, 0x1E },
+ };
+
+ for (i = 0; i < gcmCOUNTOF(_feStacks); i++)
+ {
+ gckOS_WriteRegisterEx(Os, Core, Descriptor->index, _feStacks[i].clear);
+
+ for (j = 0; j < _feStacks[i].count; j++)
+ {
+ gckOS_WriteRegisterEx(Os, Core, Descriptor->index, _feStacks[i].highSelect);
+
+ gckOS_ReadRegisterEx(Os, Core, Descriptor->data, &stack[j][0]);
+
+ gckOS_WriteRegisterEx(Os, Core, Descriptor->index, _feStacks[i].lowSelect);
+
+ gckOS_ReadRegisterEx(Os, Core, Descriptor->data, &stack[j][1]);
+
+ gckOS_WriteRegisterEx(Os, Core, Descriptor->index, _feStacks[i].next);
+
+ if (_feStacks[i].linkSelect)
+ {
+ gckOS_WriteRegisterEx(Os, Core, Descriptor->index, _feStacks[i].linkSelect);
+
+ gckOS_ReadRegisterEx(Os, Core, Descriptor->data, &link[j]);
+ }
+ }
+
+ gcmkPRINT(" %s:", _feStacks[i].name);
+
+ for (j = 31; j >= 3; j -= 4)
+ {
+ gcmkPRINT(" %08X %08X %08X %08X %08X %08X %08X %08X",
+ stack[j][0], stack[j][1], stack[j - 1][0], stack[j - 1][1],
+ stack[j - 2][0], stack[j - 2][1], stack[j - 3][0], stack[j - 3][1]);
+ }
+
+ if (_feStacks[i].linkSelect)
+ {
+ gcmkPRINT(" LINK_STACK:");
+
+ for (j = 31; j >= 3; j -= 4)
+ {
+ gcmkPRINT(" %08X %08X %08X %08X %08X %08X %08X %08X",
+ link[j], link[j], link[j - 1], link[j - 1],
+ link[j - 2], link[j - 2], link[j - 3], link[j - 3]);
+ }
+ }
+
+ }
+
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_IsGPUPresent(
+ IN gckHARDWARE Hardware
+ )
+{
+ gceSTATUS status;
+ gcsHARDWARE_SIGNATURE signature;
+ gctUINT32 control;
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ &control));
+
+ control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ? 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:1) - (0 ?
+ 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1)));
+ control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0)));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ control));
+
+ gckOS_ZeroMemory((gctPOINTER)&signature, gcmSIZEOF(gcsHARDWARE_SIGNATURE));
+
+ /* Identify the hardware. */
+ gcmkONERROR(_GetHardwareSignature(Hardware,
+ Hardware->os,
+ Hardware->core,
+ &signature));
+
+ /* Check if these are the same values as saved before. */
+ if ((Hardware->signature.chipModel != signature.chipModel)
+ || (Hardware->signature.chipRevision != signature.chipRevision)
+ || (Hardware->signature.chipFeatures != signature.chipFeatures)
+ || (Hardware->signature.chipMinorFeatures != signature.chipMinorFeatures)
+ || (Hardware->signature.chipMinorFeatures1 != signature.chipMinorFeatures1)
+ || (Hardware->signature.chipMinorFeatures2 != signature.chipMinorFeatures2)
+ )
+ {
+ gcmkPRINT("[galcore]: GPU is not present.");
+ gcmkONERROR(gcvSTATUS_GPU_NOT_RESPONDING);
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the error. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+_FlushCache(
+ gckHARDWARE Hardware,
+ gckCOMMAND Command
+ )
+{
+ gceSTATUS status;
+ gctUINT32 bytes, requested;
+ gctPOINTER buffer;
+
+ /* Get the size of the flush command. */
+ gcmkONERROR(gckHARDWARE_Flush(Hardware,
+ gcvFLUSH_ALL,
+ gcvNULL,
+ &requested));
+
+ /* Reserve space in the command queue. */
+ gcmkONERROR(gckCOMMAND_Reserve(Command,
+ requested,
+ &buffer,
+ &bytes));
+
+ /* Append a flush. */
+ gcmkONERROR(gckHARDWARE_Flush(
+ Hardware, gcvFLUSH_ALL, buffer, &bytes
+ ));
+
+ /* Execute the command queue. */
+ gcmkONERROR(gckCOMMAND_Execute(Command, requested));
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+static gctBOOL
+_IsGPUIdle(
+ IN gctUINT32 Idle
+ )
+{
+ return Idle == 0x7FFFFFFF;
+}
+
+gctBOOL
+_QueryFeatureDatabase(
+ IN gckHARDWARE Hardware,
+ IN gceFEATURE Feature
+ )
+{
+ gctBOOL available;
+
+ gcsFEATURE_DATABASE *database = Hardware->featureDatabase;
+
+ gcmkHEADER_ARG("Hardware=0x%x Feature=%d", Hardware, Feature);
+
+ /* Only features needed by common kernel logic added here. */
+ switch (Feature)
+ {
+ case gcvFEATURE_END_EVENT:
+ available = gcvFALSE;
+ break;
+
+ case gcvFEATURE_MC20:
+ available = database->REG_MC20;
+ break;
+
+ case gcvFEATURE_EARLY_Z:
+ available = database->REG_NoEZ == 0;
+ break;
+
+ case gcvFEATURE_HZ:
+ available = database->REG_HierarchicalZ;
+ break;
+
+ case gcvFEATURE_NEW_HZ:
+ available = database->REG_NewHZ;
+ break;
+
+ case gcvFEATURE_FAST_MSAA:
+ available = database->REG_FastMSAA;
+ break;
+
+ case gcvFEATURE_SMALL_MSAA:
+ available = database->REG_SmallMSAA;
+ break;
+
+ case gcvFEATURE_DYNAMIC_FREQUENCY_SCALING:
+ /* This feature doesn't apply for 2D cores. */
+ available = database->REG_DynamicFrequencyScaling && database->REG_Pipe3D;
+
+ if (Hardware->identity.chipModel == gcv1000 &&
+ (Hardware->identity.chipRevision == 0x5039 ||
+ Hardware->identity.chipRevision == 0x5040))
+ {
+ available = gcvFALSE;
+ }
+ break;
+
+ case gcvFEATURE_ACE:
+ available = database->REG_ACE;
+ break;
+
+ case gcvFEATURE_HALTI2:
+ available = database->REG_Halti2;
+ break;
+
+ case gcvFEATURE_PIPE_2D:
+ available = database->REG_Pipe2D;
+ break;
+
+ case gcvFEATURE_PIPE_3D:
+#if gcdENABLE_3D
+ available = database->REG_Pipe3D;
+#else
+ available = gcvFALSE;
+#endif
+ break;
+
+ case gcvFEATURE_FC_FLUSH_STALL:
+ available = database->REG_FcFlushStall;
+ break;
+
+ case gcvFEATURE_BLT_ENGINE:
+ available = database->REG_BltEngine;
+ break;
+
+ case gcvFEATURE_HALTI0:
+ available = database->REG_Halti0;
+ break;
+
+ case gcvFEATURE_FE_ALLOW_STALL_PREFETCH_ENG:
+ available = database->REG_FEAllowStallPrefetchEng;
+ break;
+
+ case gcvFEATURE_MMU:
+ available = database->REG_MMU;
+ break;
+
+ case gcvFEATURE_FENCE_64BIT:
+ available = database->FENCE_64BIT;
+ break;
+
+ case gcvFEATURE_TEX_BASELOD:
+ available = database->REG_Halti2;
+
+ if (_IsHardwareMatch(Hardware, gcv900, 0x5250))
+ {
+ available = gcvTRUE;
+ }
+ break;
+
+ case gcvFEATURE_TEX_CACHE_FLUSH_FIX:
+ available = database->REG_Halti5;
+ break;
+
+ case gcvFEATURE_BUG_FIXES1:
+ available = database->REG_BugFixes1;
+ break;
+
+ case gcvFEATURE_MULTI_SOURCE_BLT:
+ available = database->REG_MultiSourceBlt;
+ break;
+
+ case gcvFEATURE_HALTI5:
+ available = database->REG_Halti5;
+ break;
+
+ case gcvFEATURE_FAST_CLEAR:
+ available = database->REG_FastClear;
+
+ if (Hardware->identity.chipModel == gcv700)
+ {
+ available = gcvFALSE;
+ }
+ break;
+
+ case gcvFEATURE_BUG_FIXES7:
+ available = database->REG_BugFixes7;
+ break;
+
+ case gcvFEATURE_ZCOMPRESSION:
+ available = database->REG_ZCompression;
+ break;
+
+ case gcvFEATURE_SHADER_HAS_INSTRUCTION_CACHE:
+ available = database->REG_InstructionCache;
+ break;
+
+ case gcvFEATURE_YUV420_TILER:
+ available = database->REG_YUV420Tiler;
+ break;
+
+ case gcvFEATURE_2DPE20:
+ available = database->REG_2DPE20;
+ break;
+
+ case gcvFEATURE_DITHER_AND_FILTER_PLUS_ALPHA_2D:
+ available = database->REG_DitherAndFilterPlusAlpha2D;
+ break;
+
+ case gcvFEATURE_ONE_PASS_2D_FILTER:
+ available = database->REG_OnePass2DFilter;
+ break;
+
+ case gcvFEATURE_HALTI1:
+ available = database->REG_Halti1;
+ break;
+
+ case gcvFEATURE_HALTI3:
+ available = database->REG_Halti3;
+ break;
+
+ case gcvFEATURE_HALTI4:
+ available = database->REG_Halti4;
+ break;
+
+ case gcvFEATURE_GEOMETRY_SHADER:
+ available = database->REG_GeometryShader;
+ break;
+
+ case gcvFEATURE_TESSELLATION:
+ available = database->REG_TessellationShaders;
+ break;
+
+ case gcvFEATURE_GENERIC_ATTRIB:
+ available = database->REG_Generics;
+ break;
+
+ case gcvFEATURE_TEXTURE_LINEAR:
+ available = database->REG_LinearTextureSupport;
+ break;
+
+ case gcvFEATURE_TX_FILTER:
+ available = database->REG_TXFilter;
+ break;
+
+ case gcvFEATURE_TX_SUPPORT_DEC:
+ available = database->REG_TXSupportDEC;
+ break;
+
+ case gcvFEATURE_TX_FRAC_PRECISION_6BIT:
+ available = database->REG_TX6bitFrac;
+ break;
+
+ case gcvFEATURE_TEXTURE_ASTC:
+ available = database->REG_TXEnhancements4 && !database->NO_ASTC;
+ break;
+
+ case gcvFEATURE_SHADER_ENHANCEMENTS2:
+ available = database->REG_SHEnhancements2;
+ break;
+
+ case gcvFEATURE_BUG_FIXES18:
+ available = database->REG_BugFixes18;
+ break;
+
+ case gcvFEATURE_64K_L2_CACHE:
+ available = gcvFALSE;
+ break;
+
+ case gcvFEATURE_BUG_FIXES4:
+ available = database->REG_BugFixes4;
+ break;
+
+ case gcvFEATURE_BUG_FIXES12:
+ available = database->REG_BugFixes12;
+ break;
+
+ case gcvFEATURE_HW_TFB:
+ available = database->HWTFB;
+ break;
+
+ case gcvFEATURE_SNAPPAGE_CMD_FIX:
+ available = database->SH_SNAP2PAGE_FIX;
+ break;
+
+ case gcvFEATURE_SECURITY:
+ available = database->SECURITY;
+ break;
+
+ case gcvFEATURE_TX_DESCRIPTOR:
+ available = database->REG_Halti5;
+ break;
+
+ case gcvFEATURE_TX_DESC_CACHE_CLOCKGATE_FIX:
+ available = database->TX_DESC_CACHE_CLOCKGATE_FIX;
+ break;
+
+ case gcvFEATURE_ROBUSTNESS:
+ available = database->ROBUSTNESS;
+ break;
+
+ case gcvFEATURE_SNAPPAGE_CMD:
+ available = database->SNAPPAGE_CMD;
+ break;
+
+ case gcvFEATURE_HALF_FLOAT_PIPE:
+ available = database->REG_HalfFloatPipe;
+ break;
+
+ case gcvFEATURE_SH_INSTRUCTION_PREFETCH:
+ available = database->SH_ICACHE_PREFETCH;
+ break;
+
+ case gcvFEATURE_FE_NEED_DUMMYDRAW:
+ available = database->FE_NEED_DUMMYDRAW;
+ break;
+
+ case gcvFEATURE_DEC300_COMPRESSION:
+ available = database->REG_DEC;
+ break;
+
+ case gcvFEATURE_DEC400_COMPRESSION:
+ available = database->G2D_DEC400;
+ break;
+
+ case gcvFEATURE_TPC_COMPRESSION:
+ available = database->REG_ThirdPartyCompression;
+ break;
+
+ case gcvFEATURE_TPCV11_COMPRESSION:
+ available = database->G2D_3rd_PARTY_COMPRESSION_1_1;
+ break;
+
+ case gcvFEATURE_USC_DEFER_FILL_FIX:
+ available = database->USC_DEFER_FILL_FIX;
+ break;
+
+ case gcvFEATURE_USC:
+ available = database->REG_Halti5;
+ break;
+
+ case gcvFEATURE_RA_CG_FIX:
+ available = database->RA_CG_FIX;
+ break;
+
+ case gcvFEATURE_ZERO_ATTRIB_SUPPORT:
+ available = database->REG_Halti4;
+ break;
+
+ case gcvFEATURE_SH_CLOCK_GATE_FIX:
+ available = database->SH_CLOCK_GATE_FIX;
+ break;
+
+ case gcvFEATURE_GPIPE_CLOCK_GATE_FIX:
+ available = gcvTRUE;
+ break;
+
+ case gcvFEATURE_NEW_GPIPE:
+ available = database->NEW_GPIPE;
+ break;
+
+ case gcvFEATURE_MULTI_CORE_BLOCK_SET_CONFIG2:
+ available = database->MULTI_CORE_BLOCK_SET_CONFIG2;
+ break;
+
+ case gcvFEATURE_SECURITY_AHB:
+ available = database->SECURITY_AHB;
+ break;
+
+ case gcvFEATURE_ASYNC_BLIT:
+ available = database->ASYNC_BLT;
+ break;
+
+ case gcvFEATURE_COMPUTE_ONLY:
+ available = database->COMPUTE_ONLY;
+ break;
+
+ case gcvFEATURE_USC_FULLCACHE_FIX:
+ available = database->USC_FULL_CACHE_FIX;
+ break;
+
+ case gcvFEATURE_PE_TILE_CACHE_FLUSH_FIX:
+ available = database->PE_TILE_CACHE_FLUSH_FIX;
+ break;
+
+ default:
+ gcmkFATAL("Invalid feature has been requested.");
+ available = gcvFALSE;
+ }
+
+ gcmkFOOTER_ARG("%d", available ? gcvSTATUS_TRUE : gcvSTATUS_FALSE);
+ return available;
+}
+
+static void
+_ConfigurePolicyID(
+ IN gckHARDWARE Hardware
+ )
+{
+ gceSTATUS status;
+ gctUINT32 policyID;
+ gctUINT32 auxBit = ~0U;
+ gctUINT32 axiConfig;
+ gckOS os = Hardware->os;
+ gceCORE core = Hardware->core;
+ gctUINT32 i;
+ gctUINT32 offset;
+ gctUINT32 shift;
+ gctUINT32 currentAxiConfig;
+
+ status = gckOS_GetPolicyID(os, gcvSURF_TYPE_UNKNOWN, &policyID, &axiConfig);
+
+ if (status == gcvSTATUS_NOT_SUPPORTED)
+ {
+ /* No customized policyID setting. */
+ return;
+ }
+
+ for (i = 0; i < 16; i++)
+ {
+ /* Mapping 16 surface type.*/
+ status = gckOS_GetPolicyID(os, (gceSURF_TYPE) i, &policyID, &axiConfig);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ if (auxBit == ~0U)
+ {
+ /* There is a customized policyID setting for this type. */
+ auxBit = (policyID >> 4) & 0x1;
+ }
+ else
+ {
+ /* Check whether this bit changes. */
+ if (auxBit != ((policyID >> 4) & 0x1))
+ {
+ gcmkPRINT("[galcore]: AUX_BIT changes");
+ return;
+ }
+ }
+
+ offset = policyID >> 1;
+
+ shift = (policyID & 0x1) * 16;
+
+ axiConfig &= 0xFFFF;
+
+ gcmkVERIFY_OK(gckOS_ReadRegisterEx(
+ os,
+ core,
+ (0x0070 + offset) << 2,
+ &currentAxiConfig
+ ));
+
+ currentAxiConfig |= (axiConfig << shift);
+
+ gcmkVERIFY_OK(gckOS_WriteRegisterEx(
+ os,
+ core,
+ (0x0070 + offset) << 2,
+ currentAxiConfig
+ ));
+ }
+ }
+
+ if (auxBit != ~0U)
+ {
+ gcmkVERIFY_OK(gckOS_WriteRegisterEx(
+ os,
+ core,
+ 0x000EC,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ? 7:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:8) - (0 ?
+ 8:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ?
+ 8:8))) | (((gctUINT32) ((gctUINT32) (auxBit) & ((gctUINT32) ((((1 ? 8:8) - (0 ?
+ 8:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ?
+ 8:8)))
+ ));
+ }
+}
+/****************************
+** Initialise hardware options
+*/
+static void
+_SetHardwareOptions(
+ IN gckHARDWARE Hardware
+ )
+{
+ gceSTATUS status;
+ gcsHAL_QUERY_CHIP_OPTIONS *options = &Hardware->options;
+
+ status = gckOS_QueryOption(Hardware->os, "powerManagement", (gctUINT32*)&options->powerManagement);
+
+ if (status == gcvSTATUS_NOT_SUPPORTED)
+ {
+ /* Enable power management by default. */
+ Hardware->options.powerManagement = gcvTRUE;
+ }
+
+ /* Disable profiler by default */
+ status = gckOS_QueryOption(Hardware->os, "gpuProfiler", (gctUINT32*)&options->gpuProfiler);
+ if (status == gcvSTATUS_NOT_SUPPORTED)
+ {
+ /* Disable profiler by default */
+ Hardware->options.gpuProfiler= gcvFALSE;
+ }
+ gckOS_QueryOption(Hardware->os, "mmu", (gctUINT32_PTR)&options->enableMMU);
+
+ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_USC))
+ {
+ gctUINT L1cacheSize;
+ gcsFEATURE_DATABASE *database = Hardware->featureDatabase;
+
+ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_COMPUTE_ONLY))
+ {
+ L1cacheSize = database->L1CacheSize;
+ }
+ else
+ {
+ gctUINT attribBufSizeInKB;
+ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_TESSELLATION))
+ {
+ /* GS/TS must be bundled. */
+ gcmkASSERT(gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_GEOMETRY_SHADER));
+ attribBufSizeInKB = 42;
+ }
+ else
+ {
+ gcmkASSERT(!gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_GEOMETRY_SHADER));
+ attribBufSizeInKB = 8;
+ }
+ L1cacheSize = database->USC_MAX_PAGES - attribBufSizeInKB;
+ }
+ gcmkASSERT(L1cacheSize);
+ if (L1cacheSize >= database->L1CacheSize)
+ {
+ Hardware->options.uscL1CacheRatio = 0x0;
+ gcmkASSERT(gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_USC_FULLCACHE_FIX));
+ }
+ else
+ {
+ static const gctINT s_uscCacheRatio[] =
+ {
+ 100000,/* 1.0f */
+ 50000, /* 0.5f */
+ 25000, /* 0.25f */
+ 12500, /* 0.125f */
+ 62500, /* 0.0625f */
+ 3125, /* 0.03125f */
+ 75000, /* 0.75f */
+ 0, /*0.0f */
+ };
+ gctINT maxL1cacheSize = L1cacheSize * 100000;
+ gctINT delta = 2147483647; /* start with very big delta */
+ gctINT i = 0;
+ gctINT curIndex = -1;
+ for (; i < gcmCOUNTOF(s_uscCacheRatio); ++i)
+ {
+ gctINT curL1cacheSize = database->L1CacheSize * s_uscCacheRatio[i];
+
+ if ((maxL1cacheSize >= curL1cacheSize) &&
+ ((maxL1cacheSize - curL1cacheSize) < delta))
+ {
+ curIndex = i;
+ delta = maxL1cacheSize - curL1cacheSize;
+ }
+ }
+ gcmkASSERT(-1 != curIndex);
+ Hardware->options.uscL1CacheRatio = curIndex;
+ }
+ }
+
+ options->secureMode = gcvSECURE_NONE;
+
+ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_SECURITY))
+ {
+ gctUINT32 ta = 0;
+
+ gcmkASSERT(gcvSTATUS_TRUE == gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_SECURITY_AHB));
+
+ options->secureMode = gcvSECURE_IN_NORMAL;
+
+ status = gckOS_QueryOption(Hardware->os, "TA", &ta);
+
+ if (gcmIS_SUCCESS(status) && ta)
+ {
+ options->secureMode = gcvSECURE_IN_TA;
+ }
+ }
+ else if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_SECURITY_AHB))
+ {
+ options->secureMode = gcvSECURE_IN_NORMAL;
+ }
+
+ return;
+}
+
+/*
+* State timer helper must be called with powerMutex held.
+*/
+void
+gckSTATETIMER_Reset(
+ IN gcsSTATETIMER * StateTimer,
+ IN gctUINT64 Start
+ )
+{
+ gctUINT64 now;
+
+ if (Start)
+ {
+ now = Start;
+ }
+ else
+ {
+ gckOS_GetProfileTick(&now);
+ }
+
+ StateTimer->recent = StateTimer->start = now;
+
+ gckOS_ZeroMemory(StateTimer->elapse, gcmSIZEOF(StateTimer->elapse));
+}
+
+void
+gckSTATETIMER_Accumulate(
+ IN gcsSTATETIMER * StateTimer,
+ IN gceCHIPPOWERSTATE OldState
+ )
+{
+ gctUINT64 now;
+ gctUINT64 elapse;
+
+ gckOS_GetProfileTick(&now);
+
+ elapse = now - StateTimer->recent;
+
+ StateTimer->recent = now;
+
+ StateTimer->elapse[OldState] += elapse;
+}
+
+void
+gckSTATETIMER_Query(
+ IN gcsSTATETIMER * StateTimer,
+ IN gceCHIPPOWERSTATE State,
+ OUT gctUINT64_PTR Start,
+ OUT gctUINT64_PTR End,
+ OUT gctUINT64_PTR On,
+ OUT gctUINT64_PTR Off,
+ OUT gctUINT64_PTR Idle,
+ OUT gctUINT64_PTR Suspend
+ )
+{
+ *Start = StateTimer->start;
+
+ gckSTATETIMER_Accumulate(StateTimer, State);
+
+ *End = StateTimer->recent;
+
+ *On = StateTimer->elapse[gcvPOWER_ON];
+ *Off = StateTimer->elapse[gcvPOWER_OFF];
+ *Idle = StateTimer->elapse[gcvPOWER_IDLE];
+ *Suspend = StateTimer->elapse[gcvPOWER_SUSPEND];
+
+ gckSTATETIMER_Reset(StateTimer, StateTimer->recent);
+}
+
+/******************************************************************************\
+****************************** gckHARDWARE API code *****************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+** gckHARDWARE_Construct
+**
+** Construct a new gckHARDWARE object.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an initialized gckOS object.
+**
+** gceCORE Core
+** Specified core.
+**
+** OUTPUT:
+**
+** gckHARDWARE * Hardware
+** Pointer to a variable that will hold the pointer to the gckHARDWARE
+** object.
+*/
+gceSTATUS
+gckHARDWARE_Construct(
+ IN gckOS Os,
+ IN gceCORE Core,
+ OUT gckHARDWARE * Hardware
+ )
+{
+ gceSTATUS status;
+ gckHARDWARE hardware = gcvNULL;
+ gctUINT16 data = 0xff00;
+ gctPOINTER pointer = gcvNULL;
+ gctUINT i;
+
+ gcmkHEADER_ARG("Os=0x%x", Os);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Hardware != gcvNULL);
+
+ /* Enable the GPU. */
+ gcmkONERROR(gckOS_SetGPUPower(Os, Core, gcvTRUE, gcvTRUE));
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ Core,
+ 0x00000,
+ 0x00000900));
+
+ /* Allocate the gckHARDWARE object. */
+ gcmkONERROR(gckOS_Allocate(Os,
+ gcmSIZEOF(struct _gckHARDWARE),
+ &pointer));
+
+ gckOS_ZeroMemory(pointer, gcmSIZEOF(struct _gckHARDWARE));
+
+ hardware = (gckHARDWARE) pointer;
+
+ /* Initialize the gckHARDWARE object. */
+ hardware->object.type = gcvOBJ_HARDWARE;
+ hardware->os = Os;
+ hardware->core = Core;
+
+ gcmkONERROR(_GetHardwareSignature(hardware, Os, Core, &hardware->signature));
+
+ /* Identify the hardware. */
+ gcmkONERROR(_IdentifyHardwareByDatabase(hardware, Os, Core, &hardware->identity));
+
+ _SetHardwareOptions(hardware);
+
+ hardware->mmuVersion = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_MMU);
+
+ /* Get the system's physical base address for old MMU */
+ if (hardware->mmuVersion == 0)
+ {
+ gcmkONERROR(gckOS_GetBaseAddress(Os, &hardware->baseAddress));
+ }
+
+ /* Determine the hardware type */
+ if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_PIPE_3D)
+ && gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_PIPE_2D)
+ )
+ {
+ hardware->type = gcvHARDWARE_3D2D;
+ }
+ else
+ if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_PIPE_2D))
+ {
+ hardware->type = gcvHARDWARE_2D;
+ }
+ else
+ {
+ hardware->type = gcvHARDWARE_3D;
+ }
+
+ hardware->powerBaseAddress
+ = ((hardware->identity.chipModel == gcv300)
+ && (hardware->identity.chipRevision < 0x2000))
+ ? 0x0100
+ : 0x0000;
+
+
+ /* _ResetGPU need powerBaseAddress. */
+ status = _ResetGPU(hardware, Os, Core);
+ if (status != gcvSTATUS_OK)
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "_ResetGPU failed: status=%d\n", status);
+ }
+
+#if gcdDEC_ENABLE_AHB
+ gcmkONERROR(gckOS_WriteRegisterEx(Os, gcvCORE_DEC, 0x18180, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 22:22) - (0 ? 22:22) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 22:22) - (0 ?
+ 22:22) + 1))))))) << (0 ? 22:22))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 22:22) - (0 ? 22:22) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 22:22) - (0 ?
+ 22:22) + 1))))))) << (0 ? 22:22)))));
+#endif
+
+ if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_64K_L2_CACHE) == gcvFALSE)
+ {
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ Core,
+ 0x0055C,
+ 0x00FFFFFF));
+ }
+
+ hardware->powerMutex = gcvNULL;
+
+ /* Determine whether bug fixes #1 are present. */
+ hardware->extraEventStates = (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_BUG_FIXES1) == gcvFALSE);
+
+ /* Check if big endian */
+ hardware->bigEndian = (*(gctUINT8 *)&data == 0xff);
+
+ /* Initialize the fast clear. */
+ gcmkONERROR(gckHARDWARE_SetFastClear(hardware, -1, -1));
+
+#if !gcdENABLE_128B_MERGE
+ if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_MULTI_SOURCE_BLT))
+ {
+ /* 128B merge is turned on by default. Disable it. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x00558, 0));
+ }
+#endif
+
+#if (gcdFPGA_BUILD && 1)
+ if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_TPCV11_COMPRESSION))
+ {
+ gctUINT32 data;
+ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00558, &data));
+ data |= 0x1 << 27;
+ gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x00558, data));
+ }
+#endif
+
+ {
+ gctUINT32 value;
+ gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x00090, &value));
+#if gcdDEC_ENABLE_AHB
+ if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_DEC300_COMPRESSION))
+ {
+ value |= ~0xFFFFFFBF;
+ }
+ else
+#endif
+ {
+ value &= 0xFFFFFFBF;
+ }
+ gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x00090, value));
+ }
+
+ /* Set power state to ON. */
+ hardware->chipPowerState = gcvPOWER_ON;
+ hardware->clockState = gcvTRUE;
+ hardware->powerState = gcvTRUE;
+ hardware->lastWaitLink = ~0U;
+ hardware->lastEnd = ~0U;
+ hardware->globalSemaphore = gcvNULL;
+#if gcdENABLE_FSCALE_VAL_ADJUST
+ hardware->powerOnFscaleVal = 64;
+#endif
+
+ gcmkONERROR(gckOS_CreateMutex(Os, &hardware->powerMutex));
+ gcmkONERROR(gckOS_CreateSemaphore(Os, &hardware->globalSemaphore));
+
+#if gcdPOWEROFF_TIMEOUT
+ hardware->powerOffTimeout = gcdPOWEROFF_TIMEOUT;
+
+ gcmkVERIFY_OK(gckOS_CreateTimer(Os,
+ _PowerTimerFunction,
+ (gctPOINTER)hardware,
+ &hardware->powerOffTimer));
+#endif
+
+ for (i = 0; i < gcvENGINE_GPU_ENGINE_COUNT; i++)
+ {
+ gcmkONERROR(gckOS_AtomConstruct(Os, &hardware->pageTableDirty[i]));
+ }
+
+ gcmkONERROR(gckOS_AtomConstruct(Os, &hardware->pendingEvent));
+
+#if defined(LINUX) || defined(__QNXNTO__) || defined(UNDER_CE)
+ if (hardware->mmuVersion)
+ {
+ hardware->stallFEPrefetch
+ = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_FE_ALLOW_STALL_PREFETCH_ENG);
+ }
+ else
+#endif
+ {
+ hardware->stallFEPrefetch = gcvTRUE;
+ }
+
+ hardware->hasAsyncFe
+ = gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_ASYNC_BLIT);
+
+ hardware->minFscaleValue = 1;
+ hardware->waitCount = 200;
+
+ gckSTATETIMER_Reset(&hardware->powerStateTimer, 0);
+
+#if gcdLINK_QUEUE_SIZE
+ gcmkONERROR(gckQUEUE_Allocate(hardware->os, &hardware->linkQueue, gcdLINK_QUEUE_SIZE));
+#endif
+
+ if (hardware->options.secureMode == gcvSECURE_IN_NORMAL)
+ {
+ hardware->pagetableArray.size = 4096;
+
+ gcmkONERROR(gckOS_AllocateNonPagedMemory(
+ hardware->os,
+ gcvFALSE,
+ &hardware->pagetableArray.size,
+ &hardware->pagetableArray.physical,
+ &hardware->pagetableArray.logical
+ ));
+
+ gcmkONERROR(gckOS_GetPhysicalAddress(
+ hardware->os,
+ hardware->pagetableArray.logical,
+ &hardware->pagetableArray.address
+ ));
+ }
+
+ /* Return pointer to the gckHARDWARE object. */
+ *Hardware = hardware;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Hardware=0x%x", *Hardware);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Roll back. */
+ if (hardware != gcvNULL)
+ {
+ /* Turn off the power. */
+ gcmkVERIFY_OK(gckOS_SetGPUPower(Os, Core, gcvFALSE, gcvFALSE));
+
+ if (hardware->globalSemaphore != gcvNULL)
+ {
+ /* Destroy the global semaphore. */
+ gcmkVERIFY_OK(gckOS_DestroySemaphore(Os,
+ hardware->globalSemaphore));
+ }
+
+ if (hardware->powerMutex != gcvNULL)
+ {
+ /* Destroy the power mutex. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Os, hardware->powerMutex));
+ }
+
+#if gcdPOWEROFF_TIMEOUT
+ if (hardware->powerOffTimer != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_StopTimer(Os, hardware->powerOffTimer));
+ gcmkVERIFY_OK(gckOS_DestroyTimer(Os, hardware->powerOffTimer));
+ }
+#endif
+
+ for (i = 0; i < gcvENGINE_GPU_ENGINE_COUNT; i++)
+ {
+ if (hardware->pageTableDirty[i] != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_AtomDestroy(Os, hardware->pageTableDirty[i]));
+ }
+ }
+
+ if (hardware->pendingEvent != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_AtomDestroy(Os, hardware->pendingEvent));
+ }
+
+ if (hardware->pagetableArray.logical != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_FreeNonPagedMemory(
+ Os,
+ hardware->pagetableArray.size,
+ hardware->pagetableArray.physical,
+ hardware->pagetableArray.logical
+ ));
+ }
+
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, hardware));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_Destroy
+**
+** Destroy an gckHARDWARE object.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to the gckHARDWARE object that needs to be destroyed.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckHARDWARE_Destroy(
+ IN gckHARDWARE Hardware
+ )
+{
+ gceSTATUS status;
+ gctUINT i;
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ /* Destroy the power semaphore. */
+ gcmkVERIFY_OK(gckOS_DestroySemaphore(Hardware->os,
+ Hardware->globalSemaphore));
+
+ /* Destroy the power mutex. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Hardware->os, Hardware->powerMutex));
+
+#if gcdPOWEROFF_TIMEOUT
+ gcmkVERIFY_OK(gckOS_StopTimer(Hardware->os, Hardware->powerOffTimer));
+ gcmkVERIFY_OK(gckOS_DestroyTimer(Hardware->os, Hardware->powerOffTimer));
+#endif
+
+ for (i = 0; i < gcvENGINE_GPU_ENGINE_COUNT; i++)
+ {
+ gcmkVERIFY_OK(gckOS_AtomDestroy(Hardware->os, Hardware->pageTableDirty[i]));
+ }
+
+ gcmkVERIFY_OK(gckOS_AtomDestroy(Hardware->os, Hardware->pendingEvent));
+
+#if gcdLINK_QUEUE_SIZE
+ gckQUEUE_Free(Hardware->os, &Hardware->linkQueue);
+#endif
+
+ if (Hardware->pagetableArray.logical != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_FreeNonPagedMemory(
+ Hardware->os,
+ Hardware->pagetableArray.size,
+ Hardware->pagetableArray.physical,
+ Hardware->pagetableArray.logical
+ ));
+ }
+
+ /* Mark the object as unknown. */
+ Hardware->object.type = gcvOBJ_UNKNOWN;
+
+ /* Free the object. */
+ gcmkONERROR(gcmkOS_SAFE_FREE(Hardware->os, Hardware));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_GetType
+**
+** Get the hardware type.
+**
+** INPUT:
+**
+** gckHARDWARE Harwdare
+** Pointer to an gckHARDWARE object.
+**
+** OUTPUT:
+**
+** gceHARDWARE_TYPE * Type
+** Pointer to a variable that receives the type of hardware object.
+*/
+gceSTATUS
+gckHARDWARE_GetType(
+ IN gckHARDWARE Hardware,
+ OUT gceHARDWARE_TYPE * Type
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+ gcmkVERIFY_ARGUMENT(Type != gcvNULL);
+
+ *Type = Hardware->type;
+
+ gcmkFOOTER_ARG("*Type=%d", *Type);
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_InitializeHardware
+**
+** Initialize the hardware.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to the gckHARDWARE object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckHARDWARE_InitializeHardware(
+ IN gckHARDWARE Hardware
+ )
+{
+ gceSTATUS status;
+ gctUINT32 control;
+ gctUINT32 data;
+ gctUINT32 regPMC = 0;
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ /* Disable isolate GPU bit. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ ((((gctUINT32) (0x00000900)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:19) - (0 ? 19:19) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 19:19) - (0 ? 19:19) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ? 19:19)))));
+
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ &control));
+
+ /* Enable debug register. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ? 11:11) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ? 11:11))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ? 11:11) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ? 11:11)))));
+
+ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_SECURITY_AHB) &&
+ (Hardware->options.secureMode == gcvSECURE_IN_NORMAL))
+ {
+ gctUINT32 ahbControl = 0;
+
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x003A8,
+ &ahbControl));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x003A8,
+ ((((gctUINT32) (ahbControl)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ? 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))));
+ }
+
+ /* Reset memory counters. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0003C,
+ ~0U));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0003C,
+ 0));
+
+ if (Hardware->mmuVersion == 0)
+ {
+ /* Program the base addesses. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0041C,
+ Hardware->baseAddress));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00418,
+ Hardware->baseAddress));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00428,
+ Hardware->baseAddress));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00420,
+ Hardware->baseAddress));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00424,
+ Hardware->baseAddress));
+ }
+
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress +
+ 0x00100,
+ &data));
+
+ /* Enable clock gating. */
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0)));
+
+ if ((Hardware->identity.chipRevision == 0x4301)
+ || (Hardware->identity.chipRevision == 0x4302)
+ )
+ {
+ /* Disable stall module level clock gating for 4.3.0.1 and 4.3.0.2
+ ** revisions. */
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ? 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ?
+ 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1)));
+ }
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00100,
+ data));
+
+#if gcdENABLE_3D
+ /* Disable PE clock gating on revs < 5.0 when HZ is present without a
+ ** bug fix. */
+ if ((Hardware->identity.chipRevision < 0x5000)
+ && gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HZ)
+ && !gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_BUG_FIXES4)
+ )
+ {
+ if (regPMC == 0)
+ {
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00104,
+ &regPMC));
+ }
+
+ /* Disable PE clock gating. */
+ regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ? 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 2:2) - (0 ?
+ 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2)));
+ }
+#endif
+
+ if (Hardware->identity.chipModel == gcv4000 &&
+ ((Hardware->identity.chipRevision == 0x5208) || (Hardware->identity.chipRevision == 0x5222)))
+ {
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0010C,
+ ((((gctUINT32) (0x01590880)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:23) - (0 ? 23:23) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:23) - (0 ?
+ 23:23) + 1))))))) << (0 ? 23:23))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 23:23) - (0 ? 23:23) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:23) - (0 ?
+ 23:23) + 1))))))) << (0 ? 23:23)))));
+ }
+
+ if ((Hardware->identity.chipModel == gcv1000 &&
+ (Hardware->identity.chipRevision == 0x5039 ||
+ Hardware->identity.chipRevision == 0x5040))
+ ||
+ (Hardware->identity.chipModel == gcv2000 &&
+ Hardware->identity.chipRevision == 0x5140)
+ )
+ {
+ gctUINT32 pulseEater;
+
+ pulseEater = ((((gctUINT32) (0x01590880)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16)));
+
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0010C,
+ ((((gctUINT32) (pulseEater)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ? 17:17) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ? 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ? 17:17) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ? 17:17)))));
+ }
+
+ if ((gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HALTI2) == gcvSTATUS_FALSE)
+ || (Hardware->identity.chipRevision < 0x5422)
+ )
+ {
+ if (regPMC == 0)
+ {
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00104,
+ &regPMC));
+ }
+
+ regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:15) - (0 ? 15:15) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:15) - (0 ?
+ 15:15) + 1))))))) << (0 ? 15:15))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 15:15) - (0 ? 15:15) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:15) - (0 ?
+ 15:15) + 1))))))) << (0 ? 15:15)));
+ }
+
+ if (_IsHardwareMatch(Hardware, gcv2000, 0x5108))
+ {
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00480,
+ &data));
+
+ /* Set FE bus to one, TX bus to zero */
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ? 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 3:3) - (0 ?
+ 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3)));
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ? 7:7) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 7:7) - (0 ?
+ 7:7) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ?
+ 7:7)));
+
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00480,
+ data));
+ }
+
+ gcmkONERROR(
+ gckHARDWARE_SetMMU(Hardware,
+ Hardware->kernel->mmu->area[0].pageTableLogical));
+
+ if (Hardware->identity.chipModel >= gcv400
+ && Hardware->identity.chipModel != gcv420
+ && !gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_BUG_FIXES12))
+ {
+ if (regPMC == 0)
+ {
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00104,
+ &regPMC));
+ }
+
+ /* Disable PA clock gating. */
+ regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ? 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 4:4) - (0 ?
+ 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4)));
+ }
+
+ /* Limit 2D outstanding request. */
+ if (Hardware->maxOutstandingReads)
+ {
+ gctUINT32 data;
+
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00414,
+ &data));
+
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (Hardware->maxOutstandingReads & 0xFF) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0)));
+
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00414,
+ data));
+ }
+
+ if (_IsHardwareMatch(Hardware, gcv1000, 0x5035))
+ {
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00414,
+ &data));
+
+ /* Disable HZ-L2. */
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ? 12:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ? 12:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ? 12:12)));
+
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00414,
+ data));
+ }
+
+ if (_IsHardwareMatch(Hardware, gcv4000, 0x5222)
+ || _IsHardwareMatch(Hardware, gcv2000, 0x5108)
+ || (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_TX_DESCRIPTOR)
+ && !gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_TX_DESC_CACHE_CLOCKGATE_FIX)
+ )
+ )
+ {
+ if (regPMC == 0)
+ {
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00104,
+ &regPMC));
+ }
+
+ /* Disable TX clock gating. */
+ regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ? 7:7) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 7:7) - (0 ?
+ 7:7) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ?
+ 7:7)));
+ }
+
+ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_NEW_GPIPE) &&
+ !gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_GPIPE_CLOCK_GATE_FIX))
+ {
+ if (regPMC == 0)
+ {
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00104,
+ &regPMC));
+ }
+
+ /* Disable GPIPE clock gating. */
+ regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 22:22) - (0 ? 22:22) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 22:22) - (0 ?
+ 22:22) + 1))))))) << (0 ? 22:22))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 22:22) - (0 ? 22:22) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 22:22) - (0 ?
+ 22:22) + 1))))))) << (0 ? 22:22)));
+ }
+
+ if (_IsHardwareMatch(Hardware, gcv880, 0x5106))
+ {
+ Hardware->kernel->timeOut = 140 * 1000;
+ }
+
+ if (regPMC == 0)
+ {
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00104,
+ &regPMC));
+ }
+
+ /* Disable RA HZ clock gating. */
+ regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ? 17:17) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ? 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ? 17:17) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ? 17:17)));
+
+ /* Disable RA EZ clock gating. */
+ regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16)));
+
+ if ((gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HALTI5)
+ && !gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_RA_CG_FIX)
+ )
+ )
+ {
+ if (regPMC == 0)
+ {
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00104,
+ &regPMC));
+ }
+
+ /* Disable RA clock gating. */
+ regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ? 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 6:6) - (0 ?
+ 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6)));
+ }
+
+ if ((gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HALTI5)
+ && !gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_SH_CLOCK_GATE_FIX)
+ )
+ )
+ {
+ if (regPMC == 0)
+ {
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00104,
+ &regPMC));
+ }
+
+ /* Disable SH clock gating. */
+ regPMC = ((((gctUINT32) (regPMC)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ? 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 3:3) - (0 ?
+ 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3)));
+ }
+
+ if (regPMC != 0)
+ {
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00104,
+ regPMC));
+ }
+
+ if (_IsHardwareMatch(Hardware, gcv2000, 0x5108)
+ || (_IsHardwareMatch(Hardware, gcv2000, 0xffff5450))
+ || _IsHardwareMatch(Hardware, gcv320, 0x5007)
+ || _IsHardwareMatch(Hardware, gcv320, 0x5303)
+ || _IsHardwareMatch(Hardware, gcv880, 0x5106)
+ || _IsHardwareMatch(Hardware, gcv400, 0x4645)
+ )
+ {
+ /* Update GPU AXI cache atttribute. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00008,
+ 0x00002200));
+ }
+
+ if ((Hardware->identity.chipRevision > 0x5420)
+ && gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_PIPE_3D))
+ {
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0010C,
+ &data));
+
+ /* Disable internal DFS. */
+ data =
+#if gcdDVFS
+ ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 18:18) - (0 ? 18:18) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 18:18) - (0 ?
+ 18:18) + 1))))))) << (0 ? 18:18))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 18:18) - (0 ? 18:18) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 18:18) - (0 ?
+ 18:18) + 1))))))) << (0 ? 18:18))) |
+#endif
+ ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16))) |
+ ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ? 17:17) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ? 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ? 17:17) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ? 17:17)));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0010C,
+ data));
+ }
+
+ if (_IsHardwareMatch(Hardware, gcv2500, 0x5422))
+ {
+ gcmkONERROR(gckOS_ReadRegisterEx(
+ Hardware->os, Hardware->core, 0x00090, &data));
+
+ /* AXI switch setup to SPLIT_TO64 mode */
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ? 1:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(
+ Hardware->os, Hardware->core, 0x00090, data));
+ }
+
+ _ConfigurePolicyID(Hardware);
+
+#if gcdDEBUG_MODULE_CLOCK_GATING
+ _ConfigureModuleLevelClockGating(Hardware);
+#endif
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the error. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_QueryMemory
+**
+** Query the amount of memory available on the hardware.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to the gckHARDWARE object.
+**
+** OUTPUT:
+**
+** gctSIZE_T * InternalSize
+** Pointer to a variable that will hold the size of the internal video
+** memory in bytes. If 'InternalSize' is gcvNULL, no information of the
+** internal memory will be returned.
+**
+** gctUINT32 * InternalBaseAddress
+** Pointer to a variable that will hold the hardware's base address for
+** the internal video memory. This pointer cannot be gcvNULL if
+** 'InternalSize' is also non-gcvNULL.
+**
+** gctUINT32 * InternalAlignment
+** Pointer to a variable that will hold the hardware's base address for
+** the internal video memory. This pointer cannot be gcvNULL if
+** 'InternalSize' is also non-gcvNULL.
+**
+** gctSIZE_T * ExternalSize
+** Pointer to a variable that will hold the size of the external video
+** memory in bytes. If 'ExternalSize' is gcvNULL, no information of the
+** external memory will be returned.
+**
+** gctUINT32 * ExternalBaseAddress
+** Pointer to a variable that will hold the hardware's base address for
+** the external video memory. This pointer cannot be gcvNULL if
+** 'ExternalSize' is also non-gcvNULL.
+**
+** gctUINT32 * ExternalAlignment
+** Pointer to a variable that will hold the hardware's base address for
+** the external video memory. This pointer cannot be gcvNULL if
+** 'ExternalSize' is also non-gcvNULL.
+**
+** gctUINT32 * HorizontalTileSize
+** Number of horizontal pixels per tile. If 'HorizontalTileSize' is
+** gcvNULL, no horizontal pixel per tile will be returned.
+**
+** gctUINT32 * VerticalTileSize
+** Number of vertical pixels per tile. If 'VerticalTileSize' is
+** gcvNULL, no vertical pixel per tile will be returned.
+*/
+gceSTATUS
+gckHARDWARE_QueryMemory(
+ IN gckHARDWARE Hardware,
+ OUT gctSIZE_T * InternalSize,
+ OUT gctUINT32 * InternalBaseAddress,
+ OUT gctUINT32 * InternalAlignment,
+ OUT gctSIZE_T * ExternalSize,
+ OUT gctUINT32 * ExternalBaseAddress,
+ OUT gctUINT32 * ExternalAlignment,
+ OUT gctUINT32 * HorizontalTileSize,
+ OUT gctUINT32 * VerticalTileSize
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ if (InternalSize != gcvNULL)
+ {
+ /* No internal memory. */
+ *InternalSize = 0;
+ }
+
+ if (ExternalSize != gcvNULL)
+ {
+ /* No external memory. */
+ *ExternalSize = 0;
+ }
+
+ if (HorizontalTileSize != gcvNULL)
+ {
+ /* 4x4 tiles. */
+ *HorizontalTileSize = 4;
+ }
+
+ if (VerticalTileSize != gcvNULL)
+ {
+ /* 4x4 tiles. */
+ *VerticalTileSize = 4;
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*InternalSize=%lu *InternalBaseAddress=0x%08x "
+ "*InternalAlignment=0x%08x *ExternalSize=%lu "
+ "*ExternalBaseAddress=0x%08x *ExtenalAlignment=0x%08x "
+ "*HorizontalTileSize=%u *VerticalTileSize=%u",
+ gcmOPT_VALUE(InternalSize),
+ gcmOPT_VALUE(InternalBaseAddress),
+ gcmOPT_VALUE(InternalAlignment),
+ gcmOPT_VALUE(ExternalSize),
+ gcmOPT_VALUE(ExternalBaseAddress),
+ gcmOPT_VALUE(ExternalAlignment),
+ gcmOPT_VALUE(HorizontalTileSize),
+ gcmOPT_VALUE(VerticalTileSize));
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_QueryChipIdentity
+**
+** Query the identity of the hardware.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to the gckHARDWARE object.
+**
+** OUTPUT:
+**
+** gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity
+** Pointer to the identity structure.
+**
+*/
+gceSTATUS
+gckHARDWARE_QueryChipIdentity(
+ IN gckHARDWARE Hardware,
+ OUT gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(Identity != gcvNULL);
+
+ *Identity = Hardware->identity;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_QueryChipOptions
+**
+** Query the options of the hardware.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to the gckHARDWARE object.
+**
+** OUTPUT:
+**
+** gcsHAL_QUERY_CHIP_OPTIONS_PTR Options
+** Pointer to the identity structure.
+**
+*/
+gceSTATUS
+gckHARDWARE_QueryChipOptions(
+ IN gckHARDWARE Hardware,
+ OUT gcsHAL_QUERY_CHIP_OPTIONS_PTR Options
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(Options != gcvNULL);
+
+ *Options = Hardware->options;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+
+/*******************************************************************************
+**
+** gckHARDWARE_SplitMemory
+**
+** Split a hardware specific memory address into a pool and offset.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to the gckHARDWARE object.
+**
+** gctUINT32 Address
+** Address in hardware specific format.
+**
+** OUTPUT:
+**
+** gcePOOL * Pool
+** Pointer to a variable that will hold the pool type for the address.
+**
+** gctUINT32 * Offset
+** Pointer to a variable that will hold the offset for the address.
+*/
+gceSTATUS
+gckHARDWARE_SplitMemory(
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 Address,
+ OUT gcePOOL * Pool,
+ OUT gctUINT32 * Offset
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x Addres=0x%08x", Hardware, Address);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(Pool != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Offset != gcvNULL);
+
+ if (Hardware->mmuVersion == 0)
+ {
+ /* Dispatch on memory type. */
+ switch ((((((gctUINT32) (Address)) >> (0 ? 31:31)) & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:31) - (0 ? 31:31) + 1)))))) ))
+ {
+ case 0x0:
+ /* System memory. */
+ *Pool = gcvPOOL_SYSTEM;
+ break;
+
+ case 0x1:
+ /* Virtual memory. */
+ *Pool = gcvPOOL_VIRTUAL;
+ break;
+
+ default:
+ /* Invalid memory type. */
+ gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT);
+ return gcvSTATUS_INVALID_ARGUMENT;
+ }
+
+ /* Return offset of address. */
+ *Offset = (((((gctUINT32) (Address)) >> (0 ? 30:0)) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 30:0) - (0 ? 30:0) + 1)))))) );
+ }
+ else
+ {
+ *Pool = gcvPOOL_SYSTEM;
+ *Offset = Address;
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Pool=%d *Offset=0x%08x", *Pool, *Offset);
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_Execute
+**
+** Kickstart the hardware's command processor with an initialized command
+** buffer.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to the gckHARDWARE object.
+**
+** gctUINT32 Address
+** Hardware address of command buffer.
+**
+** gctSIZE_T Bytes
+** Number of bytes for the prefetch unit (until after the first LINK).
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckHARDWARE_Execute(
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 Address,
+ IN gctSIZE_T Bytes
+ )
+{
+ gceSTATUS status;
+ gctUINT32 control;
+
+ gcmkHEADER_ARG("Hardware=0x%x Address=0x%x Bytes=%lu",
+ Hardware, Address, Bytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ /* Enable all events. */
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00014, ~0U));
+
+ /* Write address register. */
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00654, Address));
+
+ /* Build control register. */
+ control = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) ((Bytes + 7) >> 3) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ /* Set big endian */
+ if (Hardware->bigEndian)
+ {
+ control |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 21:20) - (0 ? 21:20) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 21:20) - (0 ?
+ 21:20) + 1))))))) << (0 ? 21:20))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ?
+ 21:20) - (0 ? 21:20) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 21:20) - (0 ?
+ 21:20) + 1))))))) << (0 ? 21:20)));
+ }
+
+ /* Make sure writing to command buffer and previous AHB register is done. */
+ gcmkONERROR(gckOS_MemoryBarrier(Hardware->os, gcvNULL));
+
+ /* Write control register. */
+ switch (Hardware->options.secureMode)
+ {
+ case gcvSECURE_NONE:
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00658, control));
+ break;
+ case gcvSECURE_IN_NORMAL:
+
+#if defined(__KERNEL__)
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00658, control));
+#endif
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x003A4, control));
+
+ break;
+#if gcdENABLE_TRUST_APPLICATION
+ case gcvSECURE_IN_TA:
+ /* Send message to TA. */
+ gcmkONERROR(gckKERNEL_SecurityStartCommand(Hardware->kernel, Address, (gctUINT32)Bytes));
+ break;
+#endif
+ default:
+ break;
+ }
+
+ /* Increase execute count. */
+ Hardware->executeCount++;
+
+ /* Record last execute address. */
+ Hardware->lastExecuteAddress = Address;
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "Started command buffer @ 0x%08x",
+ Address);
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_WaitLink
+**
+** Append a WAIT/LINK command sequence at the specified location in the command
+** queue.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to an gckHARDWARE object.
+**
+** gctPOINTER Logical
+** Pointer to the current location inside the command queue to append
+** WAIT/LINK command sequence at or gcvNULL just to query the size of the
+** WAIT/LINK command sequence.
+**
+** gctUINT32 Address
+** GPU address of current location inside the command queue.
+**
+** gctUINT32 Offset
+** Offset into command buffer required for alignment.
+**
+** gctSIZE_T * Bytes
+** Pointer to the number of bytes available for the WAIT/LINK command
+** sequence. If 'Logical' is gcvNULL, this argument will be ignored.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that will receive the number of bytes required
+** by the WAIT/LINK command sequence. If 'Bytes' is gcvNULL, nothing will
+** be returned.
+**
+** gctUINT32 * WaitOffset
+** Pointer to a variable that will receive the offset of the WAIT command
+** from the specified logcial pointer.
+** If 'WaitOffset' is gcvNULL nothing will be returned.
+**
+** gctSIZE_T * WaitSize
+** Pointer to a variable that will receive the number of bytes used by
+** the WAIT command. If 'LinkSize' is gcvNULL nothing will be returned.
+*/
+gceSTATUS
+gckHARDWARE_WaitLink(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Address,
+ IN gctUINT32 Offset,
+ IN OUT gctUINT32 * Bytes,
+ OUT gctUINT32 * WaitOffset,
+ OUT gctUINT32 * WaitSize
+ )
+{
+ gceSTATUS status;
+ gctUINT32_PTR logical;
+ gctUINT32 bytes;
+ gctBOOL useL2;
+
+ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Offset=0x%08x *Bytes=%lu",
+ Hardware, Logical, Offset, gcmOPT_VALUE(Bytes));
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT((Logical != gcvNULL) || (Bytes != gcvNULL));
+
+ useL2 = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_64K_L2_CACHE);
+
+ /* Compute number of bytes required. */
+ if (useL2)
+ {
+ bytes = gcmALIGN(Offset + 24, 8) - Offset;
+ }
+ else
+ {
+ bytes = gcmALIGN(Offset + 16, 8) - Offset;
+ }
+
+ /* Cast the input pointer. */
+ logical = (gctUINT32_PTR) Logical;
+
+ if (logical != gcvNULL)
+ {
+ /* Not enough space? */
+ if (*Bytes < bytes)
+ {
+ /* Command queue too small. */
+ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+ }
+
+ gcmkASSERT(Address != ~0U);
+
+ /* Store the WAIT/LINK address. */
+ Hardware->lastWaitLink = Address;
+
+ /* Append WAIT(count). */
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (Hardware->waitCount) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ logical++;
+
+ if (useL2)
+ {
+ /* LoadState(AQFlush, 1), flush. */
+ *logical++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *logical++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ? 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+ }
+
+ /* Append LINK(2, address). */
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (bytes >> 3) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *logical++ = Address;
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "0x%08x: WAIT %u", Address, Hardware->waitCount
+ );
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "0x%08x: LINK 0x%08x, #%lu",
+ Address + 8, Address, bytes
+ );
+
+ if (WaitOffset != gcvNULL)
+ {
+ /* Return the offset pointer to WAIT command. */
+ *WaitOffset = 0;
+ }
+
+ if (WaitSize != gcvNULL)
+ {
+ /* Return number of bytes used by the WAIT command. */
+ if (useL2)
+ {
+ *WaitSize = 16;
+ }
+ else
+ {
+ *WaitSize = 8;
+ }
+ }
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the WAIT/LINK command
+ ** sequence. */
+ *Bytes = bytes;
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Bytes=%lu *WaitOffset=0x%x *WaitSize=%lu",
+ gcmOPT_VALUE(Bytes), gcmOPT_VALUE(WaitOffset),
+ gcmOPT_VALUE(WaitSize));
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_End
+**
+** Append an END command at the specified location in the command queue.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to an gckHARDWARE object.
+**
+** gctPOINTER Logical
+** Pointer to the current location inside the command queue to append
+** END command at or gcvNULL just to query the size of the END command.
+**
+** gctUINT32 Address
+** GPU address of current location inside the command queue.
+**
+** gctSIZE_T * Bytes
+** Pointer to the number of bytes available for the END command. If
+** 'Logical' is gcvNULL, this argument will be ignored.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that will receive the number of bytes required
+** for the END command. If 'Bytes' is gcvNULL, nothing will be returned.
+*/
+gceSTATUS
+gckHARDWARE_End(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Address,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+ gctUINT32 address;
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu",
+ Hardware, Logical, gcmOPT_VALUE(Bytes));
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+ if (Logical != gcvNULL)
+ {
+ if (*Bytes < 8)
+ {
+ /* Command queue too small. */
+ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+ }
+
+ /* Append END. */
+ logical[0] =
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+ /* Record the count of execution which is finised by this END. */
+ logical[1] =
+ Hardware->executeCount;
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: END", Logical);
+
+ /* Make sure the CPU writes out the data to memory. */
+ gcmkONERROR(
+ gckOS_MemoryBarrier(Hardware->os, Logical));
+
+
+ gcmkASSERT(Address != ~0U);
+ address = Address;
+
+ Hardware->lastEnd = address;
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the END command. */
+ *Bytes = 8;
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckHARDWARE_ChipEnable(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gceCORE_3D_MASK ChipEnable,
+ IN OUT gctSIZE_T * Bytes
+ )
+{
+ gckOS os = Hardware->os;
+ gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x ChipEnable=0x%x *Bytes=%lu",
+ Hardware, Logical, ChipEnable, gcmOPT_VALUE(Bytes));
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+ if (Logical != gcvNULL)
+ {
+ if (*Bytes < 8)
+ {
+ /* Command queue too small. */
+ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+ }
+
+ /* Append CHIPENABLE. */
+ gcmkWRITE_MEMORY(
+ logical,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x0D & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | ChipEnable
+ );
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: CHIPENABLE 0x%x", Logical, ChipEnable);
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the CHIPENABLE command. */
+ *Bytes = 8;
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_Nop
+**
+** Append a NOP command at the specified location in the command queue.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to an gckHARDWARE object.
+**
+** gctPOINTER Logical
+** Pointer to the current location inside the command queue to append
+** NOP command at or gcvNULL just to query the size of the NOP command.
+**
+** gctSIZE_T * Bytes
+** Pointer to the number of bytes available for the NOP command. If
+** 'Logical' is gcvNULL, this argument will be ignored.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that will receive the number of bytes required
+** for the NOP command. If 'Bytes' is gcvNULL, nothing will be returned.
+*/
+gceSTATUS
+gckHARDWARE_Nop(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN OUT gctSIZE_T * Bytes
+ )
+{
+ gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu",
+ Hardware, Logical, gcmOPT_VALUE(Bytes));
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+ if (Logical != gcvNULL)
+ {
+ if (*Bytes < 8)
+ {
+ /* Command queue too small. */
+ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+ }
+
+ /* Append NOP. */
+ logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: NOP", Logical);
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the NOP command. */
+ *Bytes = 8;
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_Event
+**
+** Append an EVENT command at the specified location in the command queue.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to an gckHARDWARE object.
+**
+** gctPOINTER Logical
+** Pointer to the current location inside the command queue to append
+** the EVENT command at or gcvNULL just to query the size of the EVENT
+** command.
+**
+** gctUINT8 Event
+** Event ID to program.
+**
+** gceKERNEL_WHERE FromWhere
+** Location of the pipe to send the event.
+**
+** gctSIZE_T * Bytes
+** Pointer to the number of bytes available for the EVENT command. If
+** 'Logical' is gcvNULL, this argument will be ignored.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that will receive the number of bytes required
+** for the EVENT command. If 'Bytes' is gcvNULL, nothing will be
+** returned.
+*/
+gceSTATUS
+gckHARDWARE_Event(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctUINT8 Event,
+ IN gceKERNEL_WHERE FromWhere,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gctUINT size;
+ gctUINT32 destination = 0;
+ gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+ gceSTATUS status;
+ gctBOOL blt;
+ gctBOOL extraEventStates;
+
+ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Event=%u FromWhere=%d *Bytes=%lu",
+ Hardware, Logical, Event, FromWhere, gcmOPT_VALUE(Bytes));
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+ gcmkVERIFY_ARGUMENT(Event < 32);
+
+ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_BLT_ENGINE))
+ {
+ /* Send all event from blt. */
+ if (FromWhere == gcvKERNEL_PIXEL)
+ {
+ FromWhere = gcvKERNEL_BLT;
+ }
+ }
+
+ blt = FromWhere == gcvKERNEL_BLT ? gcvTRUE : gcvFALSE;
+
+ /* Determine the size of the command. */
+
+ extraEventStates = Hardware->extraEventStates && (FromWhere == gcvKERNEL_PIXEL);
+
+ size = extraEventStates
+ ? gcmALIGN(8 + (1 + 5) * 4, 8) /* EVENT + 5 STATES */
+ : 8;
+
+ if (blt)
+ {
+ size += 16;
+ }
+
+ if (Logical != gcvNULL)
+ {
+ if (*Bytes < size)
+ {
+ /* Command queue too small. */
+ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+ }
+
+ switch (FromWhere)
+ {
+ case gcvKERNEL_COMMAND:
+ /* From command processor. */
+ destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ? 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)));
+ break;
+
+ case gcvKERNEL_PIXEL:
+ /* From pixel engine. */
+ destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ? 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+ break;
+
+ case gcvKERNEL_BLT:
+ destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ? 7:7) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7)));
+ break;
+
+ default:
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ if (blt)
+ {
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+ }
+
+ /* Append EVENT(Event, destination). */
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *logical++
+ = ((((gctUINT32) (destination)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (Event) & ((gctUINT32) ((((1 ? 4:0) - (0 ?
+ 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0)));
+
+ if (blt)
+ {
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+ }
+
+
+ /* Make sure the event ID gets written out before GPU can access it. */
+ gcmkONERROR(
+ gckOS_MemoryBarrier(Hardware->os, logical + 1));
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+ {
+ gctPHYS_ADDR_T phys;
+ gckOS_GetPhysicalAddress(Hardware->os, Logical, &phys);
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "0x%08x: EVENT %d", phys, Event);
+ }
+#endif
+
+ /* Append the extra states. These are needed for the chips that do not
+ ** support back-to-back events due to the async interface. The extra
+ ** states add the necessary delay to ensure that event IDs do not
+ ** collide. */
+ if (extraEventStates)
+ {
+ *logical++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0100) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+ *logical++ = 0;
+ *logical++ = 0;
+ *logical++ = 0;
+ *logical++ = 0;
+ *logical++ = 0;
+ }
+
+#if gcdINTERRUPT_STATISTIC
+ if (Event < gcmCOUNTOF(Hardware->kernel->eventObj->queues))
+ {
+ gckOS_AtomSetMask(Hardware->pendingEvent, 1 << Event);
+ }
+#endif
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the EVENT command. */
+ *Bytes = size;
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_PipeSelect
+**
+** Append a PIPESELECT command at the specified location in the command queue.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to an gckHARDWARE object.
+**
+** gctPOINTER Logical
+** Pointer to the current location inside the command queue to append
+** the PIPESELECT command at or gcvNULL just to query the size of the
+** PIPESELECT command.
+**
+** gcePIPE_SELECT Pipe
+** Pipe value to select.
+**
+** gctSIZE_T * Bytes
+** Pointer to the number of bytes available for the PIPESELECT command.
+** If 'Logical' is gcvNULL, this argument will be ignored.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that will receive the number of bytes required
+** for the PIPESELECT command. If 'Bytes' is gcvNULL, nothing will be
+** returned.
+*/
+gceSTATUS
+gckHARDWARE_PipeSelect(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gcePIPE_SELECT Pipe,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Pipe=%d *Bytes=%lu",
+ Hardware, Logical, Pipe, gcmOPT_VALUE(Bytes));
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+ /* Append a PipeSelect. */
+ if (Logical != gcvNULL)
+ {
+ gctUINT32 flush, stall;
+
+ if (*Bytes < 32)
+ {
+ /* Command queue too small. */
+ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+ }
+
+ flush = (Pipe == gcvPIPE_2D)
+ ? ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ? 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+ : ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ? 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)));
+
+ stall = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* LoadState(AQFlush, 1), flush. */
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ logical,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16)))
+ ));
+
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ logical + 1,
+ flush
+ ));
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "0x%x: FLUSH 0x%x", logical, flush);
+
+ /* LoadState(AQSempahore, 1), stall. */
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ logical + 2,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ ));
+
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ logical + 3,
+ stall
+ ));
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "0x%x: SEMAPHORE 0x%x", logical + 2, stall);
+
+ /* Stall, stall. */
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ logical + 4,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ ));
+
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ logical + 5,
+ stall
+ ));
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "0x%x: STALL 0x%x", logical + 4, stall);
+
+ /* LoadState(AQPipeSelect, 1), pipe. */
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ logical + 6,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E00) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16)))
+ ));
+
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ logical + 7,
+ (Pipe == gcvPIPE_2D)
+ ? 0x1
+ : 0x0
+ ));
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "0x%x: PIPE %d", logical + 6, Pipe);
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the PIPESELECT command. */
+ *Bytes = 32;
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_Link
+**
+** Append a LINK command at the specified location in the command queue.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to an gckHARDWARE object.
+**
+** gctPOINTER Logical
+** Pointer to the current location inside the command queue to append
+** the LINK command at or gcvNULL just to query the size of the LINK
+** command.
+**
+** gctUINT32 FetchAddress
+** Hardware address of destination of LINK.
+**
+** gctSIZE_T FetchSize
+** Number of bytes in destination of LINK.
+**
+** gctSIZE_T * Bytes
+** Pointer to the number of bytes available for the LINK command. If
+** 'Logical' is gcvNULL, this argument will be ignored.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that will receive the number of bytes required
+** for the LINK command. If 'Bytes' is gcvNULL, nothing will be returned.
+*/
+gceSTATUS
+gckHARDWARE_Link(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctUINT32 FetchAddress,
+ IN gctUINT32 FetchSize,
+ IN OUT gctUINT32 * Bytes,
+ OUT gctUINT32 * Low,
+ OUT gctUINT32 * High
+ )
+{
+ gceSTATUS status;
+ gctSIZE_T bytes;
+ gctUINT32 link;
+ gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+
+ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x FetchAddress=0x%x FetchSize=%lu "
+ "*Bytes=%lu",
+ Hardware, Logical, FetchAddress, FetchSize,
+ gcmOPT_VALUE(Bytes));
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+ if (Logical != gcvNULL)
+ {
+ if (*Bytes < 8)
+ {
+ /* Command queue too small. */
+ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+ }
+
+ gcmkONERROR(
+ gckOS_WriteMemory(Hardware->os, logical + 1, FetchAddress));
+
+ if (High)
+ {
+ *High = FetchAddress;
+ }
+
+ /* Make sure the address got written before the LINK command. */
+ gcmkONERROR(
+ gckOS_MemoryBarrier(Hardware->os, logical + 1));
+
+ /* Compute number of 64-byte aligned bytes to fetch. */
+ bytes = gcmALIGN(FetchAddress + FetchSize, 64) - FetchAddress;
+
+ /* Append LINK(bytes / 8), FetchAddress. */
+ link = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (bytes >> 3) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ gcmkONERROR(
+ gckOS_WriteMemory(Hardware->os, logical, link));
+
+ if (Low)
+ {
+ *Low = link;
+ }
+
+ /* Memory barrier. */
+ gcmkONERROR(
+ gckOS_MemoryBarrier(Hardware->os, logical));
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the LINK command. */
+ *Bytes = 8;
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckHARDWARE_FenceRender(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctUINT32 FenceAddress,
+ IN gctUINT64 FenceData,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gckOS os = Hardware->os;
+ gctUINT32_PTR logical = (gctUINT32_PTR)Logical;
+
+ gctUINT32 dataLow = (gctUINT32)FenceData;
+ gctUINT32 dataHigh = (gctUINT32)(FenceData >> 32);
+
+ if (logical)
+ {
+ gcmkWRITE_MEMORY(
+ logical,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E1A) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16)))
+ );
+
+ gcmkWRITE_MEMORY(
+ logical,
+ FenceAddress
+ );
+
+ gcmkWRITE_MEMORY(
+ logical,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E26) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16)))
+ );
+
+ gcmkWRITE_MEMORY(
+ logical,
+ dataHigh
+ );
+
+ gcmkWRITE_MEMORY(
+ logical,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E1B) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16)))
+ );
+
+ gcmkWRITE_MEMORY(
+ logical,
+ dataLow
+ );
+ }
+ else
+ {
+ *Bytes = gcdRENDER_FENCE_LENGTH;
+ }
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHARDWARE_FenceBlt(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctUINT32 FenceAddress,
+ IN gctUINT64 FenceData,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gckOS os = Hardware->os;
+ gctUINT32_PTR logical = (gctUINT32_PTR)Logical;
+
+ gctUINT32 dataLow = (gctUINT32)FenceData;
+ gctUINT32 dataHigh = (gctUINT32)(FenceData >> 32);
+
+ if (logical)
+ {
+ gcmkWRITE_MEMORY(
+ logical,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16)))
+ );
+
+ gcmkWRITE_MEMORY(
+ logical,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+ );
+
+ gcmkWRITE_MEMORY(
+ logical,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x5029) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16)))
+ );
+
+ gcmkWRITE_MEMORY(
+ logical,
+ FenceAddress
+ );
+
+ gcmkWRITE_MEMORY(
+ logical,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502D) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16)))
+ );
+
+ gcmkWRITE_MEMORY(
+ logical,
+ dataHigh
+ );
+
+ gcmkWRITE_MEMORY(
+ logical,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502A) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16)))
+ );
+
+ gcmkWRITE_MEMORY(
+ logical,
+ dataLow
+ );
+
+ gcmkWRITE_MEMORY(
+ logical,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16)))
+ );
+
+ gcmkWRITE_MEMORY(
+ logical,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+ );
+ }
+ else
+ {
+ *Bytes = gcdBLT_FENCE_LENGTH;
+ }
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHARDWARE_Fence(
+ IN gckHARDWARE Hardware,
+ IN gceENGINE Engine,
+ IN gctPOINTER Logical,
+ IN gctUINT32 FenceAddress,
+ IN gctUINT64 FenceData,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ if (Engine == gcvENGINE_RENDER)
+ {
+ return gckHARDWARE_FenceRender(Hardware, Logical, FenceAddress, FenceData, Bytes);
+ }
+ else
+ {
+ return gckHARDWARE_FenceBlt(Hardware, Logical, FenceAddress, FenceData, Bytes);
+ }
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_UpdateQueueTail
+**
+** Update the tail of the command queue.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to an gckHARDWARE object.
+**
+** gctPOINTER Logical
+** Logical address of the start of the command queue.
+**
+** gctUINT32 Offset
+** Offset into the command queue of the tail (last command).
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckHARDWARE_UpdateQueueTail(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Offset
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Offset=0x%08x",
+ Hardware, Logical, Offset);
+
+ /* Verify the hardware. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ /* Force a barrier. */
+ gcmkONERROR(
+ gckOS_MemoryBarrier(Hardware->os, Logical));
+
+ /* Notify gckKERNEL object of change. */
+ gcmkONERROR(
+ gckKERNEL_Notify(Hardware->kernel,
+ gcvNOTIFY_COMMAND_QUEUE,
+ gcvFALSE));
+
+ if (status == gcvSTATUS_CHIP_NOT_READY)
+ {
+ gcmkONERROR(gcvSTATUS_DEVICE);
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_ConvertLogical
+**
+** Convert a logical system address into a hardware specific address.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to an gckHARDWARE object.
+**
+** gctPOINTER Logical
+** Logical address to convert.
+**
+** gctBOOL InUserSpace
+** gcvTRUE if the memory in user space.
+**
+** gctUINT32* Address
+** Return hardware specific address.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckHARDWARE_ConvertLogical(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctBOOL InUserSpace,
+ OUT gctUINT32 * Address
+ )
+{
+ gctUINT32 address;
+ gceSTATUS status;
+ gctPHYS_ADDR_T physical;
+
+ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x InUserSpace=%d",
+ Hardware, Logical, InUserSpace);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+ /* Convert logical address into a physical address. */
+ if (InUserSpace)
+ {
+ gcmkONERROR(gckOS_UserLogicalToPhysical(Hardware->os, Logical, &physical));
+ }
+ else
+ {
+ gcmkONERROR(gckOS_GetPhysicalAddress(Hardware->os, Logical, &physical));
+ }
+
+ gcmkSAFECASTPHYSADDRT(address, physical);
+
+ /* For old MMU, get GPU address according to baseAddress. */
+ if (Hardware->mmuVersion == 0)
+ {
+ /* Subtract base address to get a GPU address. */
+ gcmkASSERT(address >= Hardware->baseAddress);
+ address -= Hardware->baseAddress;
+ }
+
+ /* Return hardware specific address. */
+ *Address = (Hardware->mmuVersion == 0)
+ ? ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ? 31:31) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ? 31:31) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ? 31:31)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:0) - (0 ? 30:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ?
+ 30:0))) | (((gctUINT32) ((gctUINT32) (address) & ((gctUINT32) ((((1 ? 30:0) - (0 ?
+ 30:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ?
+ 30:0)))
+ : address;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Address=0x%08x", *Address);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_Interrupt
+**
+** Process an interrupt.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to an gckHARDWARE object.
+**
+** gctBOOL InterruptValid
+** If gcvTRUE, this function will read the interrupt acknowledge
+** register, stores the data, and return whether or not the interrupt
+** is ours or not. If gcvFALSE, this functions will read the interrupt
+** acknowledge register and combine it with any stored value to handle
+** the event notifications.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckHARDWARE_Interrupt(
+ IN gckHARDWARE Hardware,
+ IN gctBOOL InterruptValid
+ )
+{
+ gckEVENT eventObj;
+ gctUINT32 data = 0;
+ gctUINT32 dataEx;
+ gceSTATUS status;
+ gceSTATUS statusEx;
+
+ /* Extract gckEVENT object. */
+ eventObj = Hardware->kernel->eventObj;
+
+ if (InterruptValid)
+ {
+ /*
+ * Notice:
+ * In isr here.
+ * We should return success when either FE or AsyncFE reports correct
+ * interrupts, so that isr can wake up threadRoutine for either FE.
+ * That means, only need return ERROR when both FEs reports ERROR.
+ */
+ /* Read AQIntrAcknowledge register. */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00010,
+ &data));
+
+ if (data == 0)
+ {
+ /* Not our interrupt. */
+ status = gcvSTATUS_NOT_OUR_INTERRUPT;
+ }
+ else
+ {
+#if gcdINTERRUPT_STATISTIC
+ gckOS_AtomClearMask(Hardware->pendingEvent, data);
+#endif
+ /* Inform gckEVENT of the interrupt. */
+ status = gckEVENT_Interrupt(eventObj, data);
+ }
+
+ if (!Hardware->hasAsyncFe)
+ {
+ /* Done. */
+ goto OnError;
+ }
+
+ /* Read BLT interrupt. */
+ statusEx = gckOS_ReadRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x000D4,
+ &dataEx
+ );
+
+ if (gcmIS_ERROR(statusEx))
+ {
+ /*
+ * Do not overwrite status here, so that former status from
+ * AQIntrAck is returned.
+ */
+ goto OnError;
+ }
+
+ /*
+ * This bit looks useless now, we can use this check if this interrupt
+ * is from FE.
+ */
+ dataEx &= ~0x80000000;
+
+ /*
+ * Descriptor fetched, update counter.
+ * We can't do this at dataEx != 0 only, because read HW acknowledge
+ * register will overwrite 0x007E4. If one
+ * interrupt we don't read it, we will miss it for ever.
+ */
+ gckFE_UpdateAvaiable(Hardware, &Hardware->kernel->asyncCommand->fe);
+
+ /* Do not need report NOT_OUT_INTERRUPT error if dataEx is 0. */
+ if (dataEx)
+ {
+ statusEx = gckEVENT_Interrupt(Hardware->kernel->asyncEvent, dataEx);
+
+ if (gcmIS_SUCCESS(statusEx))
+ {
+ /* At least AsyncFE is success, treat all as success. */
+ status = gcvSTATUS_OK;
+ }
+ }
+ }
+ else
+ {
+ /* Handle events. */
+ status = gckEVENT_Notify(eventObj, 0);
+
+ if (Hardware->hasAsyncFe)
+ {
+ status = gckEVENT_Notify(Hardware->kernel->asyncEvent, 0);
+ }
+ }
+
+OnError:
+ /* Return the status. */
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_QueryCommandBuffer
+**
+** Query the command buffer alignment and number of reserved bytes.
+**
+** INPUT:
+**
+** gckHARDWARE Harwdare
+** Pointer to an gckHARDWARE object.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Alignment
+** Pointer to a variable receiving the alignment for each command.
+**
+** gctSIZE_T * ReservedHead
+** Pointer to a variable receiving the number of reserved bytes at the
+** head of each command buffer.
+**
+** gctSIZE_T * ReservedTail
+** Pointer to a variable receiving the number of bytes reserved at the
+** tail of each command buffer.
+*/
+gceSTATUS
+gckHARDWARE_QueryCommandBuffer(
+ IN gckHARDWARE Hardware,
+ IN gceENGINE Engine,
+ OUT gctUINT32 * Alignment,
+ OUT gctUINT32 * ReservedHead,
+ OUT gctUINT32 * ReservedTail
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ if (Alignment != gcvNULL)
+ {
+ /* Align every 8 bytes. */
+ *Alignment = 8;
+ }
+
+ if (ReservedHead != gcvNULL)
+ {
+ /* Reserve space for SelectPipe(). */
+ *ReservedHead = 32;
+ }
+
+ if (ReservedTail != gcvNULL)
+ {
+ if (Engine == gcvENGINE_RENDER)
+ {
+ gcmkFOOTER_NO();
+ return gcvSTATUS_NOT_SUPPORTED;
+ }
+ else
+ {
+ *ReservedTail = gcdBLT_FENCE_LENGTH;
+ }
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Alignment=%lu *ReservedHead=%lu *ReservedTail=%lu",
+ gcmOPT_VALUE(Alignment), gcmOPT_VALUE(ReservedHead),
+ gcmOPT_VALUE(ReservedTail));
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_QuerySystemMemory
+**
+** Query the command buffer alignment and number of reserved bytes.
+**
+** INPUT:
+**
+** gckHARDWARE Harwdare
+** Pointer to an gckHARDWARE object.
+**
+** OUTPUT:
+**
+** gctSIZE_T * SystemSize
+** Pointer to a variable that receives the maximum size of the system
+** memory.
+**
+** gctUINT32 * SystemBaseAddress
+** Poinetr to a variable that receives the base address for system
+** memory.
+*/
+gceSTATUS
+gckHARDWARE_QuerySystemMemory(
+ IN gckHARDWARE Hardware,
+ OUT gctSIZE_T * SystemSize,
+ OUT gctUINT32 * SystemBaseAddress
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ if (SystemSize != gcvNULL)
+ {
+ /* Maximum system memory can be 2GB. */
+ *SystemSize = 1U << 31;
+ }
+
+ if (SystemBaseAddress != gcvNULL)
+ {
+ /* Set system memory base address. */
+ *SystemBaseAddress = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ? 31:31) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ? 31:31) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ? 31:31)));
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*SystemSize=%lu *SystemBaseAddress=%lu",
+ gcmOPT_VALUE(SystemSize), gcmOPT_VALUE(SystemBaseAddress));
+ return gcvSTATUS_OK;
+}
+
+#if gcdENABLE_3D
+/*******************************************************************************
+**
+** gckHARDWARE_QueryShaderCaps
+**
+** Query the shader capabilities.
+**
+** INPUT:
+**
+** Nothing.
+**
+** OUTPUT:
+**
+** gctUINT * VertexUniforms
+** Pointer to a variable receiving the number of uniforms in the vertex
+** shader.
+**
+** gctUINT * FragmentUniforms
+** Pointer to a variable receiving the number of uniforms in the
+** fragment shader.
+**
+** gctBOOL * UnifiedUnforms
+** Pointer to a variable receiving whether the uniformas are unified.
+*/
+gceSTATUS
+gckHARDWARE_QueryShaderCaps(
+ IN gckHARDWARE Hardware,
+ OUT gctUINT * VertexUniforms,
+ OUT gctUINT * FragmentUniforms,
+ OUT gctBOOL * UnifiedUnforms
+ )
+{
+ gctBOOL unifiedConst;
+ gctUINT32 vsConstMax;
+ gctUINT32 psConstMax;
+ gctUINT32 vsConstBase;
+ gctUINT32 psConstBase;
+ gctUINT32 ConstMax;
+ gctBOOL halti5;
+
+ gcmkHEADER_ARG("Hardware=0x%x VertexUniforms=0x%x "
+ "FragmentUniforms=0x%x UnifiedUnforms=0x%x",
+ Hardware, VertexUniforms,
+ FragmentUniforms, UnifiedUnforms);
+
+ halti5 = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HALTI5);
+
+ {if (Hardware->identity.numConstants > 256){ unifiedConst = gcvTRUE;
+if (halti5){ vsConstBase = 0xD000;
+ psConstBase = 0xD800;
+}else{ vsConstBase = 0xC000;
+ psConstBase = 0xC000;
+}if ((Hardware->identity.chipModel == gcv880) && ((Hardware->identity.chipRevision & 0xfff0) == 0x5120)){ vsConstMax = 512;
+ psConstMax = 64;
+ ConstMax = 576;
+}else{ vsConstMax = gcmMIN(512, Hardware->identity.numConstants - 64);
+ psConstMax = gcmMIN(512, Hardware->identity.numConstants - 64);
+ ConstMax = Hardware->identity.numConstants;
+}}else if (Hardware->identity.numConstants == 256){ if (Hardware->identity.chipModel == gcv2000 && (Hardware->identity.chipRevision == 0x5118 || Hardware->identity.chipRevision == 0x5140)) { unifiedConst = gcvFALSE;
+ vsConstBase = 0x1400;
+ psConstBase = 0x1C00;
+ vsConstMax = 256;
+ psConstMax = 64;
+ ConstMax = 320;
+ } else { unifiedConst = gcvFALSE;
+ vsConstBase = 0x1400;
+ psConstBase = 0x1C00;
+ vsConstMax = 256;
+ psConstMax = 256;
+ ConstMax = 512;
+ }}else{ unifiedConst = gcvFALSE;
+ vsConstBase = 0x1400;
+ psConstBase = 0x1C00;
+ vsConstMax = 168;
+ psConstMax = 64;
+ ConstMax = 232;
+}};
+
+
+ if (VertexUniforms != gcvNULL)
+ {
+ /* Return the vs shader const count. */
+ *VertexUniforms = vsConstMax;
+ }
+
+ if (FragmentUniforms != gcvNULL)
+ {
+ /* Return the ps shader const count. */
+ *FragmentUniforms = psConstMax;
+ }
+
+ if (UnifiedUnforms != gcvNULL)
+ {
+ /* Return whether the uniformas are unified. */
+ *UnifiedUnforms = unifiedConst;
+ }
+
+ psConstBase = psConstBase;
+ vsConstBase = vsConstBase;
+ ConstMax = ConstMax;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+#endif
+
+/*******************************************************************************
+**
+** gckHARDWARE_SetMMU
+**
+** Set the page table base address.
+**
+** INPUT:
+**
+** gckHARDWARE Harwdare
+** Pointer to an gckHARDWARE object.
+**
+** gctPOINTER Logical
+** Logical address of the page table.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckHARDWARE_SetMMU(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical
+ )
+{
+ gceSTATUS status;
+ gctUINT32 address = 0;
+ gctUINT32 idle;
+ gctUINT32 timer = 0, delay = 1;
+ gctPHYS_ADDR_T physical;
+
+ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x", Hardware, Logical);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ if (Hardware->mmuVersion == 0)
+ {
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+ /* Convert the logical address into physical address. */
+ gcmkONERROR(gckOS_GetPhysicalAddress(Hardware->os, Logical, &physical));
+
+ gcmkSAFECASTPHYSADDRT(address, physical);
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "Setting page table to 0x%08X",
+ address);
+
+ /* Write the AQMemoryFePageTable register. */
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00400,
+ address));
+
+ /* Write the AQMemoryRaPageTable register. */
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00410,
+ address));
+
+ /* Write the AQMemoryTxPageTable register. */
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00404,
+ address));
+
+
+ /* Write the AQMemoryPePageTable register. */
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00408,
+ address));
+
+ /* Write the AQMemoryPezPageTable register. */
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0040C,
+ address));
+ }
+ else if (Hardware->options.enableMMU &&
+ (Hardware->options.secureMode != gcvSECURE_IN_TA))
+ {
+ gctBOOL hwMmuDisabled = gcvTRUE;
+
+ /* Force Disable MMU to guarantee setup command be read from physical addr */
+ if (Hardware->options.secureMode == gcvSECURE_IN_NORMAL)
+ {
+ gctUINT32 regMmuCtrl = 0;
+ gcmkONERROR(gckOS_ReadRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x00388,
+ &regMmuCtrl
+ ));
+
+ hwMmuDisabled = ((((((gctUINT32) (regMmuCtrl)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ) == 0x1)
+ ? gcvFALSE
+ : gcvTRUE;
+ }
+ else
+ {
+ gctUINT32 regMmuCtrl = 0;
+
+ gcmkONERROR(gckOS_ReadRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x0018C,
+ &regMmuCtrl
+ ));
+
+ hwMmuDisabled = ((((((gctUINT32) (regMmuCtrl)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ) == 0x1)
+ ? gcvFALSE
+ : gcvTRUE;
+ }
+
+ if (hwMmuDisabled)
+ {
+ /* Prepared command sequence contains an END,
+ ** so update lastEnd and store executeCount to END command.
+ */
+ gcsHARDWARE_FUNCTION *function = &Hardware->functions[gcvHARDWARE_FUNCTION_MMU];
+ gctUINT32_PTR endLogical = (gctUINT32_PTR)function->endLogical;
+
+ Hardware->lastEnd = function->endAddress;
+
+ *(endLogical + 1) = Hardware->executeCount + 1;
+
+ if (Hardware->options.secureMode == gcvSECURE_IN_NORMAL)
+ {
+ gctUINT32_PTR safeLogical = Hardware->kernel->mmu->safePageLogical;
+ gctUINT32 extSafeAddress;
+ /* Set up base address of page table array. */
+ gcmkONERROR(gckOS_WriteRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x0038C,
+ (gctUINT32)(Hardware->pagetableArray.address & 0xFFFFFFFF)
+ ));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x00390,
+ (gctUINT32)((Hardware->pagetableArray.address >> 32) & 0xFFFFFFFF)
+ ));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x00394,
+ 1
+ ));
+
+ gcmkONERROR(
+ gckOS_GetPhysicalAddress(Hardware->os, safeLogical, &physical));
+
+ address = (gctUINT32)(physical & 0xFFFFFFFF);
+ extSafeAddress = (gctUINT32)(physical >> 32);
+
+ if (address & 0x3F)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
+ }
+
+ /* more than 40bit physical address */
+ if (extSafeAddress & 0xFFFFFF00)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ gckOS_WriteRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x0039C,
+ address
+ );
+
+ gckOS_WriteRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x00398,
+ address
+ );
+
+ gckOS_WriteRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x003A0,
+ (((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) ((gctUINT32)extSafeAddress) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) &((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ? 31:31) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ? 31:31) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ? 31:31))))
+ | (((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) ((gctUINT32)extSafeAddress) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) &((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:15) - (0 ?
+ 15:15) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:15) - (0 ? 15:15) + 1))))))) << (0 ?
+ 15:15))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 15:15) - (0 ? 15:15) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:15) - (0 ? 15:15) + 1))))))) << (0 ? 15:15))))
+ );
+ }
+
+ /* Execute prepared command sequence. */
+ gcmkONERROR(gckHARDWARE_Execute(
+ Hardware,
+ function->address,
+ function->bytes
+ ));
+
+#if gcdLINK_QUEUE_SIZE
+ {
+ gcuQUEUEDATA data;
+
+ gcmkVERIFY_OK(gckOS_GetProcessID(&data.linkData.pid));
+
+ data.linkData.start = function->address;
+ data.linkData.end = function->address + function->bytes;
+ data.linkData.linkLow = 0;
+ data.linkData.linkHigh = 0;
+
+ gckQUEUE_Enqueue(&Hardware->linkQueue, &data);
+ }
+#endif
+
+ /* Wait until MMU configure finishes. */
+ do
+ {
+ gckOS_Delay(Hardware->os, delay);
+
+ gcmkONERROR(gckOS_ReadRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x00004,
+ &idle));
+
+ timer += delay;
+ delay *= 2;
+
+#if gcdGPU_TIMEOUT
+ if (timer >= Hardware->kernel->timeOut)
+ {
+ gckHARDWARE_DumpGPUState(Hardware);
+ gckCOMMAND_DumpExecutingBuffer(Hardware->kernel->command);
+
+ /* Even if hardware is not reset correctly, let software
+ ** continue to avoid software stuck. Software will timeout again
+ ** and try to recover GPU in next timeout.
+ */
+ gcmkONERROR(gcvSTATUS_DEVICE);
+ }
+#endif
+ }
+ while (!(((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ));
+
+ /* Enable MMU. */
+ if (Hardware->options.secureMode == gcvSECURE_IN_NORMAL)
+ {
+ gcmkONERROR(gckOS_WriteRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x00388,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+ ));
+ }
+ else
+ {
+ gcmkONERROR(gckOS_WriteRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x0018C,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (gcvTRUE) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0)))
+ ));
+ }
+ }
+ }
+
+ /* Return the status. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckHARDWARE_FlushAsyncMMU(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gctUINT32 semaphore, stall;
+ gctUINT32_PTR buffer;
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu",
+ Hardware, Logical, gcmOPT_VALUE(Bytes));
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+ if (Logical != gcvNULL)
+ {
+ buffer = (gctUINT32_PTR) Logical;
+
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ buffer,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16)))
+ ));
+
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ buffer + 1,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+ ));
+
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ buffer + 2,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16)))
+ ));
+
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ buffer + 3,
+ (((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ? 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) & ((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ? 7:7) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))))
+ ));
+
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ buffer + 4,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ ));
+
+ semaphore = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ if (Hardware->stallFEPrefetch)
+ {
+ semaphore |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:28) - (0 ? 29:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 29:28) - (0 ?
+ 29:28) + 1))))))) << (0 ? 29:28))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ?
+ 29:28) - (0 ? 29:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 29:28) - (0 ?
+ 29:28) + 1))))))) << (0 ? 29:28)));
+ }
+
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ buffer + 5,
+ semaphore));
+
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ buffer + 6,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ ));
+
+ stall = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ if (Hardware->stallFEPrefetch)
+ {
+ stall |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:28) - (0 ? 29:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 29:28) - (0 ?
+ 29:28) + 1))))))) << (0 ? 29:28))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ?
+ 29:28) - (0 ? 29:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 29:28) - (0 ?
+ 29:28) + 1))))))) << (0 ? 29:28)));
+ }
+
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ buffer + 7,
+ stall));
+
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ buffer + 8,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16)))
+ ));
+
+ gcmkONERROR(gckOS_WriteMemory(
+ Hardware->os,
+ buffer + 9,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+ ));
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the PIPESELECT command. */
+ *Bytes = 40;
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Success. */
+ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_FlushMMU
+**
+** Flush the page table.
+**
+** INPUT:
+**
+** gckHARDWARE Harwdare
+** Pointer to an gckHARDWARE object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckHARDWARE_FlushMMU(
+ IN gckHARDWARE Hardware
+ )
+{
+ gceSTATUS status;
+ gckCOMMAND command;
+ gctUINT32_PTR buffer;
+ gctUINT32 bufferSize;
+ gctPOINTER pointer = gcvNULL;
+ gctUINT32 flushSize;
+ gctUINT32 count, offset;
+ gctUINT32 address;
+ gctUINT32 semaphore, stall;
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ /* Verify the gckCOMMAND object pointer. */
+ command = Hardware->kernel->command;
+
+ /* Flush the memory controller. */
+ if (Hardware->mmuVersion == 0)
+ {
+ gcmkONERROR(gckCOMMAND_Reserve(
+ command, 8, &pointer, &bufferSize
+ ));
+
+ buffer = (gctUINT32_PTR) pointer;
+
+ buffer[0]
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E04) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ buffer[1]
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ? 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ? 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ? 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ? 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)));
+
+ gcmkONERROR(gckCOMMAND_Execute(command, 8));
+ }
+ else
+ {
+ gctUINT32 prefetchCount = 4;
+ gctBOOL bltEngine = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_BLT_ENGINE);
+
+ flushSize = 10 * 4;
+ offset = 2;
+
+ if (bltEngine)
+ {
+ flushSize += 4 * 4;
+ prefetchCount += 2;
+ }
+
+ gcmkONERROR(gckCOMMAND_Reserve(
+ command, flushSize, &pointer, &bufferSize
+ ));
+
+ buffer = (gctUINT32_PTR) pointer;
+
+ count = ((gctUINT)bufferSize - flushSize + 7) >> 3;
+
+ address = command->address + command->offset;
+
+ /* LINK to next slot to flush FE FIFO. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (prefetchCount) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = address + offset * gcmSIZEOF(gctUINT32);
+
+ /* Flush MMU cache. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer++
+ = (((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ? 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) & ((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ? 7:7) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))));
+
+ if (bltEngine)
+ {
+ /* Blt lock. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+ }
+
+ /* Arm the PE-FE Semaphore. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ semaphore = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)));
+
+ if (Hardware->stallFEPrefetch)
+ {
+ semaphore |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:28) - (0 ? 29:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 29:28) - (0 ?
+ 29:28) + 1))))))) << (0 ? 29:28))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ?
+ 29:28) - (0 ? 29:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 29:28) - (0 ?
+ 29:28) + 1))))))) << (0 ? 29:28)));
+ }
+
+ if (bltEngine)
+ {
+ semaphore |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+ }
+ else
+ {
+ semaphore |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+ }
+
+ *buffer++
+ = semaphore;
+
+ /* STALL FE until PE is done flushing. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ stall = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)));
+
+ if (Hardware->stallFEPrefetch)
+ {
+ stall |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 29:28) - (0 ? 29:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 29:28) - (0 ?
+ 29:28) + 1))))))) << (0 ? 29:28))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ?
+ 29:28) - (0 ? 29:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 29:28) - (0 ?
+ 29:28) + 1))))))) << (0 ? 29:28)));
+ }
+
+ if (bltEngine)
+ {
+ stall |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+ }
+ else
+ {
+ stall |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+ }
+
+ *buffer++
+ = stall;
+
+ if (bltEngine)
+ {
+ /* Blt unlock. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+ }
+
+ /* LINK to next slot to flush FE FIFO. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (count) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = address + flushSize;
+
+ gcmkONERROR(gckCOMMAND_Execute(command, flushSize));
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckHARDWARE_SetMMUStates(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER MtlbAddress,
+ IN gceMMU_MODE Mode,
+ IN gctPOINTER SafeAddress,
+ IN gctPOINTER Logical,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gceSTATUS status;
+ gctUINT32 config, address;
+ gctUINT32 extMtlb, extSafeAddress, configEx = 0;
+ gctPHYS_ADDR_T physical;
+ gctUINT32_PTR buffer;
+ gctBOOL ace;
+ gctUINT32 reserveBytes = 0;
+ gcsMMU_TABLE_ARRAY_ENTRY * entry;
+
+ gctBOOL config2D;
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(Hardware->mmuVersion != 0);
+
+ entry = (gcsMMU_TABLE_ARRAY_ENTRY *) Hardware->pagetableArray.logical;
+
+ ace = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_ACE);
+
+ switch (Hardware->options.secureMode)
+ {
+ case gcvSECURE_IN_NORMAL:
+ reserveBytes = 8 + 4 * 4;
+ break;
+ case gcvSECURE_NONE:
+ reserveBytes = 16 + 4 * 4;
+ if (ace)
+ {
+ reserveBytes += 8;
+ }
+ break;
+ case gcvSECURE_IN_TA:
+ default:
+ gcmkASSERT(gcvFALSE);
+ gcmkPRINT("%s(%d): secureMode is wrong", __FUNCTION__, __LINE__);
+ break;
+ }
+
+ config2D = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_PIPE_3D)
+ && gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_PIPE_2D);
+
+ if (config2D)
+ {
+ reserveBytes +=
+ /* Pipe Select. */
+ 4 * 4
+ /* Configure MMU States. */
+ + 4 * 4
+ /* Semaphore stall */
+ + 4 * 8;
+
+ if (ace)
+ {
+ reserveBytes += 8;
+ }
+ }
+
+ /* Convert logical address into physical address. */
+ gcmkONERROR(
+ gckOS_GetPhysicalAddress(Hardware->os, MtlbAddress, &physical));
+
+ config = (gctUINT32)(physical & 0xFFFFFFFF);
+ extMtlb = (gctUINT32)(physical >> 32);
+
+ /* more than 40bit physical address */
+ if (extMtlb & 0xFFFFFF00)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ gcmkONERROR(
+ gckOS_GetPhysicalAddress(Hardware->os, SafeAddress, &physical));
+
+ address = (gctUINT32)(physical & 0xFFFFFFFF);
+ extSafeAddress = (gctUINT32)(physical >> 32);
+
+ if (address & 0x3F)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
+ }
+
+ /* more than 40bit physical address */
+ if (extSafeAddress & 0xFFFFFF00)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ if (ace)
+ {
+ configEx = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (extSafeAddress) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (extMtlb) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16)));
+ }
+
+ switch (Mode)
+ {
+ case gcvMMU_MODE_1K:
+ if (config & 0x3FF)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
+ }
+
+ config |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ break;
+
+ case gcvMMU_MODE_4K:
+ if (config & 0xFFF)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
+ }
+
+ config |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ break;
+
+ default:
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ if (Logical != gcvNULL)
+ {
+ buffer = Logical;
+
+ if (Hardware->options.secureMode == gcvSECURE_IN_NORMAL)
+ {
+ /* Setup page table array entry. */
+ if (Hardware->bigEndian)
+ {
+ entry->low = gcmBSWAP32(config);
+ entry->high = gcmBSWAP32(extMtlb);
+ }
+ else
+ {
+ entry->low = config;
+ entry->high = extMtlb;
+ }
+
+ /* Setup command buffer to load index 0 of page table array. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x006B) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer++
+ = (((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) &((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 16:16) - (0 ?
+ 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))));
+ }
+ else
+ {
+ gcmkASSERT(Hardware->options.secureMode == gcvSECURE_NONE);
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer++ = config;
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0060) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer++ = address;
+
+ if (ace)
+ {
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0068) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer++
+ = configEx;
+ }
+ }
+
+ do{*buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));} while(0);
+;
+
+
+ if (config2D)
+ {
+ /* LoadState(AQPipeSelect, 1), pipe. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E00) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer++ = 0x1;
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer++ = config;
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0060) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer++ = address;
+
+ if (ace)
+ {
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0068) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer++
+ = configEx;
+ }
+
+ do{*buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));} while(0);
+;
+
+
+ /* LoadState(AQPipeSelect, 1), pipe. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E00) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer++ = 0x0;
+
+ do{*buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))); *buffer++ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));} while(0);
+;
+
+ }
+
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ *Bytes = reserveBytes;
+ }
+
+ /* Return the status. */
+ gcmkFOOTER_NO();
+ return status;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+#if gcdPROCESS_ADDRESS_SPACE
+/*******************************************************************************
+**
+** gckHARDWARE_ConfigMMU
+**
+** Append a MMU Configuration command sequence at the specified location in the command
+** queue. That command sequence consists of mmu configuration, LINK and WAIT/LINK.
+** LINK is fetched and paresed with new mmu configuration.
+**
+** If MMU Configuration is not changed between commit, change last WAIT/LINK to
+** link to ENTRY.
+**
+** -+-----------+-----------+-----------------------------------------
+** | WAIT/LINK | WAIT/LINK |
+** -+-----------+-----------+-----------------------------------------
+** | /|\
+** \|/ |
+** +--------------------+
+** | ENTRY | ... | LINK |
+** +--------------------+
+**
+** If MMU Configuration is changed between commit, change last WAIT/LINK to
+** link to MMU CONFIGURATION command sequence, and there are an EVNET and
+** an END at the end of this command sequence, when interrupt handler
+** receives this event, it will start FE at ENTRY to continue the command
+** buffer execution.
+**
+** -+-----------+-------------------+---------+---------+-----------+--
+** | WAIT/LINK | MMU CONFIGURATION | EVENT | END | WAIT/LINK |
+** -+-----------+-------------------+---------+---------+-----------+--
+** | /|\ /|\
+** +-------------+ |
+** +--------------------+
+** | ENTRY | ... | LINK |
+** +--------------------+
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to an gckHARDWARE object.
+**
+** gctPOINTER Logical
+** Pointer to the current location inside the command queue to append
+** command sequence at or gcvNULL just to query the size of the
+** command sequence.
+**
+** gctPOINTER MtlbLogical
+** Pointer to the current Master TLB.
+**
+** gctUINT32 Offset
+** Offset into command buffer required for alignment.
+**
+** gctSIZE_T * Bytes
+** Pointer to the number of bytes available for the command
+** sequence. If 'Logical' is gcvNULL, this argument will be ignored.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that will receive the number of bytes required
+** by the command sequence. If 'Bytes' is gcvNULL, nothing will
+** be returned.
+**
+** gctUINT32 * WaitLinkOffset
+** Pointer to a variable that will receive the offset of the WAIT/LINK command
+** from the specified logcial pointer.
+** If 'WaitLinkOffset' is gcvNULL nothing will be returned.
+**
+** gctSIZE_T * WaitLinkBytes
+** Pointer to a variable that will receive the number of bytes used by
+** the WAIT command.
+** If 'WaitLinkBytes' is gcvNULL nothing will be returned.
+*/
+gceSTATUS
+gckHARDWARE_ConfigMMU(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctPOINTER MtlbLogical,
+ IN gctUINT32 Offset,
+ IN OUT gctSIZE_T * Bytes,
+ OUT gctSIZE_T * WaitLinkOffset,
+ OUT gctSIZE_T * WaitLinkBytes
+ )
+{
+ gceSTATUS status;
+ gctSIZE_T bytes, bytesAligned;
+ gctUINT32 config;
+ gctUINT32_PTR buffer = (gctUINT32_PTR) Logical;
+ gctPHYS_ADDR_T physical;
+ gctUINT32 address;
+ gctUINT32 event;
+ gctSIZE_T stCmds; /* semaphore stall cmd size */;
+
+ gcmkHEADER_ARG("Hardware=0x%08X Logical=0x%08x MtlbLogical=0x%08X",
+ Hardware, Logical, MtlbLogical);
+
+ stCmds = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_TEX_CACHE_FLUSH_FIX) ? 0 : 4;
+
+ bytes
+ /* Semaphore stall states. */
+ = stCmds * 4
+ /* Flush cache states. */
+ + 20 * 4
+ /* MMU configuration states. */
+ + 6 * 4
+ /* EVENT. */
+ + 2 * 4
+ /* END. */
+ + 2 * 4
+ /* WAIT/LINK. */
+ + 4 * 4;
+
+ /* Compute number of bytes required. */
+ bytesAligned = gcmALIGN(Offset + bytes, 8) - Offset;
+
+ if (buffer != gcvNULL)
+ {
+ if (MtlbLogical == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ /* Get physical address of this command buffer segment. */
+ gcmkONERROR(gckOS_GetPhysicalAddress(Hardware->os, buffer, &physical));
+
+ gcmkSAFECASTPHYSADDRT(address, physical);
+
+ /* Get physical address of Master TLB. */
+ gcmkONERROR(gckOS_GetPhysicalAddress(Hardware->os, MtlbLogical, &physical));
+
+ gcmkSAFECASTPHYSADDRT(config, physical);
+
+ config |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ? 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)));
+
+ if (stCmds)
+ {
+ /* Arm the PE-FE Semaphore. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* STALL FE until PE is done flushing. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+ }
+
+ /* Flush cache. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ? 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ? 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ? 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ? 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ AQ_FLUSH_VSHL1_CACHE) - (0 ? AQ_FLUSH_VSHL1_CACHE) + 1) == 32) ? ~0U : (~(~0U << ((1 ?
+ AQ_FLUSH_VSHL1_CACHE) - (0 ? AQ_FLUSH_VSHL1_CACHE) + 1))))))) << (0 ? AQ_FLUSH_VSHL1_CACHE))) | (((gctUINT32) (AQ_FLUSH_VSHL1_CACHE_ENABLE & ((gctUINT32) ((((1 ?
+ AQ_FLUSH_VSHL1_CACHE) - (0 ? AQ_FLUSH_VSHL1_CACHE) + 1) == 32) ? ~0U : (~(~0U << ((1 ?
+ AQ_FLUSH_VSHL1_CACHE) - (0 ? AQ_FLUSH_VSHL1_CACHE) + 1))))))) << (0 ? AQ_FLUSH_VSHL1_CACHE)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ AQ_FLUSH_PSHL1_CACHE) - (0 ? AQ_FLUSH_PSHL1_CACHE) + 1) == 32) ? ~0U : (~(~0U << ((1 ?
+ AQ_FLUSH_PSHL1_CACHE) - (0 ? AQ_FLUSH_PSHL1_CACHE) + 1))))))) << (0 ? AQ_FLUSH_PSHL1_CACHE))) | (((gctUINT32) (AQ_FLUSH_PSHL1_CACHE_ENABLE & ((gctUINT32) ((((1 ?
+ AQ_FLUSH_PSHL1_CACHE) - (0 ? AQ_FLUSH_PSHL1_CACHE) + 1) == 32) ? ~0U : (~(~0U << ((1 ?
+ AQ_FLUSH_PSHL1_CACHE) - (0 ? AQ_FLUSH_PSHL1_CACHE) + 1))))))) << (0 ? AQ_FLUSH_PSHL1_CACHE)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ? 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+
+ /* Flush VTS in separate command */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ? 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)));
+
+ /* Flush tile status cache. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0594) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ /* Arm the PE-FE Semaphore. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* STALL FE until PE is done flushing. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* LINK to next slot to flush FE FIFO. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = address + (stCmds + 12) * gcmSIZEOF(gctUINT32);
+
+ /* Configure MMU. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer++
+ = (((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ? 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) & ((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ? 7:7) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))));
+
+ /* Arm the PE-FE Semaphore. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* STALL FE until PE is done flushing. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* LINK to next slot to flush FE FIFO. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = physical + (stCmds + 20) * 4;
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer++
+ = config;
+
+ /* Arm the PE-FE Semaphore. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* STALL FE until PE is done flushing. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* Event 29. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ event = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ? 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+ event = ((((gctUINT32) (event)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (29) & ((gctUINT32) ((((1 ? 4:0) - (0 ?
+ 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0)));
+
+ *buffer++
+ = event;
+
+ /* Append END. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ *Bytes = bytesAligned;
+ }
+
+ if (WaitLinkOffset != gcvNULL)
+ {
+ *WaitLinkOffset = bytes - 4 * 4;
+ }
+
+ if (WaitLinkBytes != gcvNULL)
+ {
+ *WaitLinkBytes = 4 * 4;
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+#endif
+
+/*******************************************************************************
+**
+** gckHARDWARE_BuildVirtualAddress
+**
+** Build a virtual address.
+**
+** INPUT:
+**
+** gckHARDWARE Harwdare
+** Pointer to an gckHARDWARE object.
+**
+** gctUINT32 Index
+** Index into page table.
+**
+** gctUINT32 Offset
+** Offset into page.
+**
+** OUTPUT:
+**
+** gctUINT32 * Address
+** Pointer to a variable receiving te hardware address.
+*/
+gceSTATUS
+gckHARDWARE_BuildVirtualAddress(
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 Index,
+ IN gctUINT32 Offset,
+ OUT gctUINT32 * Address
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x Index=%u Offset=%u", Hardware, Index, Offset);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+ /* Build virtual address. */
+ *Address = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ? 31:31) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ? 31:31) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ? 31:31)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 30:0) - (0 ? 30:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ?
+ 30:0))) | (((gctUINT32) ((gctUINT32) (Offset | (Index << 12)) & ((gctUINT32) ((((1 ?
+ 30:0) - (0 ? 30:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ?
+ 30:0)));
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Address=0x%08x", *Address);
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHARDWARE_GetIdle(
+ IN gckHARDWARE Hardware,
+ IN gctBOOL Wait,
+ OUT gctUINT32 * Data
+ )
+{
+ gceSTATUS status;
+ gctUINT32 idle = 0;
+ gctINT retry, poll, pollCount;
+ gctUINT32 address;
+
+ gcmkHEADER_ARG("Hardware=0x%x Wait=%d", Hardware, Wait);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(Data != gcvNULL);
+
+
+ /* If we have to wait, try 100 polls per millisecond. */
+ pollCount = Wait ? 100 : 1;
+
+ /* At most, try for 1 second. */
+ for (retry = 0; retry < 1000; ++retry)
+ {
+ /* If we have to wait, try 100 polls per millisecond. */
+ for (poll = pollCount; poll > 0; --poll)
+ {
+ /* Read register. */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00004, &idle));
+
+ /* Read the current FE address. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00664,
+ &address));
+
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00664,
+ &address));
+
+ /* See if we have to wait for FE idle. */
+ if (_IsGPUIdle(idle)
+ && (address == Hardware->lastEnd + 8)
+ )
+ {
+ /* FE is idle. */
+ break;
+ }
+ }
+
+ /* Check if we need to wait for FE and FE is busy. */
+ if (Wait && !_IsGPUIdle(idle))
+ {
+ /* Wait a little. */
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "%s: Waiting for idle: 0x%08X",
+ __FUNCTION__, idle);
+
+ gcmkVERIFY_OK(gckOS_Delay(Hardware->os, 1));
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ /* Return idle to caller. */
+ *Data = idle;
+
+#if defined(EMULATOR)
+ /* Wait a little while until CModel FE gets END.
+ * END is supposed to be appended by caller.
+ */
+ gckOS_Delay(Hardware->os, 100);
+#endif
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Data=0x%08x", *Data);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/* Flush the caches. */
+gceSTATUS
+gckHARDWARE_Flush(
+ IN gckHARDWARE Hardware,
+ IN gceKERNEL_FLUSH Flush,
+ IN gctPOINTER Logical,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gctUINT32 pipe;
+ gctUINT32 flush = 0;
+ gctUINT32 flushVST = 0;
+ gctBOOL flushTileStatus;
+ gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+ gceSTATUS status;
+ gctBOOL halti5;
+ gctBOOL flushICache;
+ gctBOOL flushTXDescCache;
+ gctBOOL flushTFB;
+ gctBOOL hwTFB;
+ gctBOOL blt;
+ gctBOOL peTSFlush;
+
+ gcmkHEADER_ARG("Hardware=0x%x Flush=0x%x Logical=0x%x *Bytes=%lu",
+ Hardware, Flush, Logical, gcmOPT_VALUE(Bytes));
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ /* Get current pipe. */
+ pipe = Hardware->kernel->command->pipeSelect;
+
+ halti5 = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HALTI5);
+
+ hwTFB = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HW_TFB);
+
+ blt = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_BLT_ENGINE);
+
+ peTSFlush = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_PE_TILE_CACHE_FLUSH_FIX);
+
+ /* Flush tile status cache. */
+ flushTileStatus = Flush & gcvFLUSH_TILE_STATUS;
+
+ /* Flush Icache for halti5 hardware as we dont do it when program or context switches*/
+ flushICache = (Flush & gcvFLUSH_ICACHE) && halti5;
+
+ /* Flush texture descriptor cache */
+ flushTXDescCache = Flush & gcvFLUSH_TXDESC;
+
+ /* Flush USC cache for TFB client */
+ flushTFB = (Flush & gcvFLUSH_TFBHEADER) && hwTFB;
+
+ /* Flush TFB for vertex buffer */
+ if (hwTFB && (Flush & gcvFLUSH_VERTEX))
+ {
+ flushTFB = gcvTRUE;
+ }
+
+ /* Flush 3D color cache. */
+ if ((Flush & gcvFLUSH_COLOR) && (pipe == 0x0))
+ {
+ flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ? 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)));
+ }
+
+ /* Flush 3D depth cache. */
+ if ((Flush & gcvFLUSH_DEPTH) && (pipe == 0x0))
+ {
+ flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+ }
+
+ /* Flush 3D texture cache. */
+ if ((Flush & gcvFLUSH_TEXTURE) && (pipe == 0x0))
+ {
+ flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ? 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)));
+ flushVST = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ? 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)));
+ }
+
+ /* Flush 2D cache. */
+ if ((Flush & gcvFLUSH_2D) && (pipe == 0x1))
+ {
+ flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ? 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)));
+ }
+
+ /* Flush L2 cache. */
+ if ((Flush & gcvFLUSH_L2) && (pipe == 0x0))
+ {
+ flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ? 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)));
+ }
+
+ /* Vertex buffer and texture could be touched by SHL1 for SSBO and image load/store */
+ if ((Flush & (gcvFLUSH_VERTEX | gcvFLUSH_TEXTURE)) && (pipe == 0x0))
+ {
+ flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ? 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 10:10) - (0 ? 10:10) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 10:10) - (0 ?
+ 10:10) + 1))))))) << (0 ? 10:10))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 10:10) - (0 ? 10:10) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 10:10) - (0 ?
+ 10:10) + 1))))))) << (0 ? 10:10)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ? 11:11) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ? 11:11))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ? 11:11) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ? 11:11)));
+ }
+
+ /* See if there is a valid flush. */
+ if ((flush == 0) &&
+ (flushTileStatus == gcvFALSE) &&
+ (flushICache == gcvFALSE) &&
+ (flushTXDescCache == gcvFALSE) &&
+ (flushTFB == gcvFALSE))
+ {
+ if (Bytes != gcvNULL)
+ {
+ /* No bytes required. */
+ *Bytes = 0;
+ }
+ }
+ else
+ {
+ gctUINT32 reserveBytes = 0;
+ gctBOOL txCacheFix = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_TEX_CACHE_FLUSH_FIX)
+ ? gcvTRUE : gcvFALSE;
+
+ /* Determine reserve bytes. */
+ if (!txCacheFix || flushICache || flushTXDescCache)
+ {
+ /* Semaphore/Stall */
+ reserveBytes += blt ? (8 * gcmSIZEOF(gctUINT32)) : (4 * gcmSIZEOF(gctUINT32));
+ }
+
+ if (flush)
+ {
+ reserveBytes += 2 * gcmSIZEOF(gctUINT32);
+ }
+
+ if (flushVST)
+ {
+ reserveBytes += 2 * gcmSIZEOF(gctUINT32);
+ }
+
+ if (flushTileStatus)
+ {
+ reserveBytes += (!peTSFlush && blt) ? 6 * gcmSIZEOF(gctUINT32) : 2 * gcmSIZEOF(gctUINT32);
+ }
+
+ if (flushICache)
+ {
+ reserveBytes += 2 * gcmSIZEOF(gctUINT32);
+ }
+
+ if (flushTXDescCache)
+ {
+ reserveBytes += 2 * gcmSIZEOF(gctUINT32);
+ }
+
+ if (flushTFB)
+ {
+ reserveBytes += 2 * gcmSIZEOF(gctUINT32);
+ }
+
+ /* Semaphore/Stall */
+ reserveBytes += blt ? (8 * gcmSIZEOF(gctUINT32)) : (4 * gcmSIZEOF(gctUINT32));
+
+ /* Copy to command queue. */
+ if (Logical != gcvNULL)
+ {
+ if (*Bytes < reserveBytes)
+ {
+ /* Command queue too small. */
+ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+ }
+
+ if (!txCacheFix || flushICache || flushTXDescCache)
+ {
+ if (blt)
+ {
+ /* Semaphore from FE to BLT. */
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* Stall from FE to BLT. */
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+ }
+ else
+ {
+ /* Semaphore. */
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* Stall. */
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+ }
+ }
+
+ if (flush)
+ {
+ /* Append LOAD_STATE to AQFlush. */
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *logical++ = flush;
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: FLUSH 0x%x", logical - 1, flush);
+ }
+
+ if (flushVST)
+ {
+ /* Append LOAD_STATE to AQFlush. */
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *logical++ = flushVST;
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: FLUSH 0x%x", logical - 1, flush);
+ }
+
+ if (flushTileStatus)
+ {
+ if (!peTSFlush && blt)
+ {
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502B) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+ }
+ else
+ {
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0594) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+ }
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "0x%x: FLUSH TILE STATUS 0x%x", logical - 1, logical[-1]);
+ }
+
+ if (flushICache)
+ {
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x022C) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ? 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ?
+ 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ? 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 2:2) - (0 ?
+ 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ? 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 3:3) - (0 ?
+ 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ? 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 4:4) - (0 ?
+ 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4)));
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "0x%x: FLUSH Icache 0x%x", logical - 1, logical[-1]);
+
+ }
+
+ if (flushTXDescCache)
+ {
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x5311) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:28) - (0 ? 31:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ? 31:28))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 31:28) - (0 ? 31:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ? 31:28)));
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "0x%x: FLUSH Icache 0x%x", logical - 1, logical[-1]);
+
+ }
+
+ if (flushTFB)
+ {
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x7003) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *logical++
+ = 0x12345678;
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "0x%x: FLUSH TFB cache 0x%x", logical - 1, logical[-1]);
+
+ }
+
+ if (blt)
+ {
+ /* Semaphore from FE to BLT. */
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* Stall from FE to BLT. */
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x10 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x502E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+ }
+ else
+ {
+ /* Semaphore. */
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+
+ /* Stall. */
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)));
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8)));
+ }
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* bytes required. */
+ *Bytes = reserveBytes;
+ }
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckHARDWARE_SetFastClear(
+ IN gckHARDWARE Hardware,
+ IN gctINT Enable,
+ IN gctINT Compression
+ )
+{
+#if gcdENABLE_3D
+ gctUINT32 debug;
+ gceSTATUS status;
+ gceCOMPRESSION_OPTION compression = (Compression == -1) ? gcvCOMPRESSION_OPTION_DEFAULT : (gceCOMPRESSION_OPTION)Compression;
+
+ gcmkHEADER_ARG("Hardware=0x%x Enable=%d Compression=%d",
+ Hardware, Enable, Compression);
+
+ /* Only process if fast clear is available. */
+ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_FAST_CLEAR))
+ {
+ if (Enable == -1)
+ {
+ /* Determine automatic value for fast clear. */
+ Enable = ((Hardware->identity.chipModel != gcv500)
+ || (Hardware->identity.chipRevision >= 3)
+ ) ? 1 : 0;
+ }
+
+ if (compression == gcvCOMPRESSION_OPTION_DEFAULT)
+ {
+ /* Determine automatic value for compression. */
+ if (Enable)
+ {
+ if (gcvSTATUS_FALSE == gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_ZCOMPRESSION))
+ {
+ compression &= ~gcvCOMPRESSION_OPTION_DEPTH;
+ }
+ }
+ else
+ {
+ compression = gcvCOMPRESSION_OPTION_NONE;
+ }
+ }
+
+ /* Read AQMemoryDebug register. */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00414, &debug));
+
+ /* Set fast clear bypass. */
+ debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:20) - (0 ? 20:20) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 20:20) - (0 ?
+ 20:20) + 1))))))) << (0 ? 20:20))) | (((gctUINT32) ((gctUINT32) (Enable == 0) & ((gctUINT32) ((((1 ?
+ 20:20) - (0 ? 20:20) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 20:20) - (0 ?
+ 20:20) + 1))))))) << (0 ? 20:20)));
+
+ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_BUG_FIXES7) ||
+ (Hardware->identity.chipModel >= gcv4000))
+ {
+ /* Set compression bypass. */
+ debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 21:21) - (0 ? 21:21) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 21:21) - (0 ?
+ 21:21) + 1))))))) << (0 ? 21:21))) | (((gctUINT32) ((gctUINT32) ((gcvCOMPRESSION_OPTION_NONE == compression) ?
+ 1 : 0) & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0U : (~(~0U << ((1 ?
+ 21:21) - (0 ? 21:21) + 1))))))) << (0 ? 21:21)));
+ }
+
+ /* Write back AQMemoryDebug register. */
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00414,
+ debug));
+
+ /* Store fast clear and comprersison flags. */
+ Hardware->options.allowFastClear = Enable;
+ Hardware->options.allowCompression = compression;
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "FastClear=%d Compression=%d", Enable, Compression);
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+#else
+ return gcvSTATUS_OK;
+#endif
+}
+
+typedef enum
+{
+ gcvPOWER_FLAG_INITIALIZE = 1 << 0,
+ gcvPOWER_FLAG_STALL = 1 << 1,
+ gcvPOWER_FLAG_STOP = 1 << 2,
+ gcvPOWER_FLAG_START = 1 << 3,
+ gcvPOWER_FLAG_RELEASE = 1 << 4,
+ gcvPOWER_FLAG_DELAY = 1 << 5,
+ gcvPOWER_FLAG_SAVE = 1 << 6,
+ gcvPOWER_FLAG_ACQUIRE = 1 << 7,
+ gcvPOWER_FLAG_POWER_OFF = 1 << 8,
+ gcvPOWER_FLAG_CLOCK_OFF = 1 << 9,
+ gcvPOWER_FLAG_CLOCK_ON = 1 << 10,
+}
+gcePOWER_FLAGS;
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+static gctCONST_STRING
+_PowerEnum(gceCHIPPOWERSTATE State)
+{
+ const gctCONST_STRING states[] =
+ {
+ gcmSTRING(gcvPOWER_ON),
+ gcmSTRING(gcvPOWER_OFF),
+ gcmSTRING(gcvPOWER_IDLE),
+ gcmSTRING(gcvPOWER_SUSPEND),
+ gcmSTRING(gcvPOWER_IDLE_BROADCAST),
+ gcmSTRING(gcvPOWER_SUSPEND_BROADCAST),
+ gcmSTRING(gcvPOWER_OFF_BROADCAST),
+ gcmSTRING(gcvPOWER_OFF_TIMEOUT),
+ gcmSTRING(gcvPOWER_ON_AUTO)
+ };
+
+ if ((State >= gcvPOWER_ON) && (State <= gcvPOWER_ON_AUTO))
+ {
+ return states[State - gcvPOWER_ON];
+ }
+
+ return "unknown";
+}
+#endif
+
+/*******************************************************************************
+**
+** gckHARDWARE_SetPowerManagementState
+**
+** Set GPU to a specified power state.
+**
+** INPUT:
+**
+** gckHARDWARE Harwdare
+** Pointer to an gckHARDWARE object.
+**
+** gceCHIPPOWERSTATE State
+** Power State.
+**
+*/
+gceSTATUS
+gckHARDWARE_SetPowerManagementState(
+ IN gckHARDWARE Hardware,
+ IN gceCHIPPOWERSTATE State
+ )
+{
+ gceSTATUS status;
+ gckCOMMAND command = gcvNULL;
+ gckOS os;
+ gctUINT flag, clock;
+ gctBOOL acquired = gcvFALSE;
+ gctBOOL mutexAcquired = gcvFALSE;
+ gctBOOL broadcast = gcvFALSE;
+#if gcdPOWEROFF_TIMEOUT
+ gctBOOL timeout = gcvFALSE;
+ gctBOOL isAfter = gcvFALSE;
+ gctUINT32 currentTime;
+#endif
+ gctUINT32 process, thread;
+ gctBOOL commandStarted = gcvFALSE;
+
+#if gcdENABLE_PROFILING
+ gctUINT64 time, freq, mutexTime, onTime, stallTime, stopTime, delayTime,
+ initTime, offTime, startTime, totalTime;
+#endif
+ gctBOOL global = gcvFALSE;
+ gctBOOL globalAcquired = gcvFALSE;
+
+ /* State transition flags. */
+ static const gctUINT flags[4][4] =
+ {
+ /* gcvPOWER_ON */
+ { /* ON */ 0,
+ /* OFF */ gcvPOWER_FLAG_ACQUIRE |
+ gcvPOWER_FLAG_STALL |
+ gcvPOWER_FLAG_STOP |
+ gcvPOWER_FLAG_POWER_OFF |
+ gcvPOWER_FLAG_CLOCK_OFF,
+ /* IDLE */ gcvPOWER_FLAG_ACQUIRE |
+ gcvPOWER_FLAG_STALL,
+ /* SUSPEND */ gcvPOWER_FLAG_ACQUIRE |
+ gcvPOWER_FLAG_STALL |
+ gcvPOWER_FLAG_STOP |
+ gcvPOWER_FLAG_CLOCK_OFF,
+ },
+
+ /* gcvPOWER_OFF */
+ { /* ON */ gcvPOWER_FLAG_INITIALIZE |
+ gcvPOWER_FLAG_START |
+ gcvPOWER_FLAG_RELEASE |
+ gcvPOWER_FLAG_DELAY,
+ /* OFF */ 0,
+ /* IDLE */ gcvPOWER_FLAG_INITIALIZE |
+ gcvPOWER_FLAG_START |
+ gcvPOWER_FLAG_DELAY,
+ /* SUSPEND */ gcvPOWER_FLAG_INITIALIZE |
+ gcvPOWER_FLAG_CLOCK_OFF,
+ },
+
+ /* gcvPOWER_IDLE */
+ { /* ON */ gcvPOWER_FLAG_RELEASE,
+ /* OFF */ gcvPOWER_FLAG_STOP |
+ gcvPOWER_FLAG_POWER_OFF |
+ gcvPOWER_FLAG_CLOCK_OFF,
+ /* IDLE */ 0,
+ /* SUSPEND */ gcvPOWER_FLAG_STOP |
+ gcvPOWER_FLAG_CLOCK_OFF,
+ },
+
+ /* gcvPOWER_SUSPEND */
+ { /* ON */ gcvPOWER_FLAG_START |
+ gcvPOWER_FLAG_RELEASE |
+ gcvPOWER_FLAG_DELAY |
+ gcvPOWER_FLAG_CLOCK_ON,
+ /* OFF */ gcvPOWER_FLAG_SAVE |
+ gcvPOWER_FLAG_POWER_OFF |
+ gcvPOWER_FLAG_CLOCK_OFF,
+ /* IDLE */ gcvPOWER_FLAG_START |
+ gcvPOWER_FLAG_DELAY |
+ gcvPOWER_FLAG_CLOCK_ON,
+ /* SUSPEND */ 0,
+ },
+ };
+
+ /* Clocks. */
+ static const gctUINT clocks[4] =
+ {
+ /* gcvPOWER_ON */
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) |
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ?
+ 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:1) - (0 ?
+ 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) |
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ?
+ 8:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ?
+ 8:2))) | (((gctUINT32) ((gctUINT32) (64) & ((gctUINT32) ((((1 ? 8:2) - (0 ?
+ 8:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ?
+ 8:2))) |
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ?
+ 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ?
+ 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))),
+
+ /* gcvPOWER_OFF */
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) |
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ?
+ 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ?
+ 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) |
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ?
+ 8:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ?
+ 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ?
+ 8:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ?
+ 8:2))) |
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ?
+ 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ?
+ 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))),
+
+ /* gcvPOWER_IDLE */
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) |
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ?
+ 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:1) - (0 ?
+ 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) |
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ?
+ 8:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ?
+ 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ?
+ 8:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ?
+ 8:2))) |
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ?
+ 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ?
+ 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))),
+
+ /* gcvPOWER_SUSPEND */
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) |
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ?
+ 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ?
+ 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) |
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ?
+ 8:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ?
+ 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ?
+ 8:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ?
+ 8:2))) |
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ?
+ 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ?
+ 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))),
+ };
+
+ gcmkHEADER_ARG("Hardware=0x%x State=%d", Hardware, State);
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "Switching to power state %d(%s)",
+ State, _PowerEnum(State));
+#endif
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ /* Get the gckOS object pointer. */
+ os = Hardware->os;
+ gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+ /* Get the gckCOMMAND object pointer. */
+ gcmkVERIFY_OBJECT(Hardware->kernel, gcvOBJ_KERNEL);
+ command = Hardware->kernel->command;
+ gcmkVERIFY_OBJECT(command, gcvOBJ_COMMAND);
+
+ /* Start profiler. */
+ gcmkPROFILE_INIT(freq, time);
+
+
+ /* Convert the broadcast power state. */
+ switch (State)
+ {
+ case gcvPOWER_IDLE_BROADCAST:
+ /* Convert to IDLE and note we are inside broadcast. */
+ State = gcvPOWER_IDLE;
+ broadcast = gcvTRUE;
+ break;
+
+ case gcvPOWER_SUSPEND_BROADCAST:
+ /* Convert to SUSPEND and note we are inside broadcast. */
+ State = gcvPOWER_SUSPEND;
+ broadcast = gcvTRUE;
+ break;
+
+ case gcvPOWER_OFF_BROADCAST:
+ /* Convert to OFF and note we are inside broadcast. */
+ State = gcvPOWER_OFF;
+ broadcast = gcvTRUE;
+ break;
+
+ case gcvPOWER_ON_AUTO:
+ /* Convert to ON and note we are inside recovery. */
+ State = gcvPOWER_ON;
+ break;
+
+ case gcvPOWER_ON:
+ case gcvPOWER_IDLE:
+ case gcvPOWER_SUSPEND:
+ case gcvPOWER_OFF:
+ /* Mark as global power management. */
+ global = gcvTRUE;
+ break;
+
+#if gcdPOWEROFF_TIMEOUT
+ case gcvPOWER_OFF_TIMEOUT:
+ /* Convert to OFF and note we are inside broadcast. */
+ State = gcvPOWER_OFF;
+ broadcast = gcvTRUE;
+ /* Check time out */
+ timeout = gcvTRUE;
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ if (Hardware->options.powerManagement == gcvFALSE
+ && State != gcvPOWER_ON
+ )
+ {
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+ /* Get current process and thread IDs. */
+ gcmkONERROR(gckOS_GetProcessID(&process));
+ gcmkONERROR(gckOS_GetThreadID(&thread));
+
+ if (broadcast)
+ {
+ /* Try to acquire the power mutex. */
+ status = gckOS_AcquireMutex(os, Hardware->powerMutex, 0);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ mutexAcquired = gcvTRUE;
+ }
+ else if (status == gcvSTATUS_TIMEOUT)
+ {
+ /* Check if we already own this mutex. */
+ if ((Hardware->powerProcess == process)
+ && (Hardware->powerThread == thread)
+ )
+ {
+ /* Bail out on recursive power management. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+ else if (State != gcvPOWER_ON)
+ {
+ /* Called from IST,
+ ** so waiting here will cause deadlock,
+ ** if lock holder call gckCOMMAND_Stall() */
+ status = gcvSTATUS_OK;
+ goto OnError;
+ }
+ }
+ }
+
+ if (!mutexAcquired)
+ {
+ /* Acquire the power mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(os, Hardware->powerMutex, gcvINFINITE));
+ mutexAcquired = gcvTRUE;
+ }
+
+ /* Get time until mtuex acquired. */
+ gcmkPROFILE_QUERY(time, mutexTime);
+
+ Hardware->powerProcess = process;
+ Hardware->powerThread = thread;
+ mutexAcquired = gcvTRUE;
+
+ /* Grab control flags and clock. */
+ flag = flags[Hardware->chipPowerState][State];
+ clock = clocks[State];
+
+#if gcdENABLE_FSCALE_VAL_ADJUST
+ if (State == gcvPOWER_ON)
+ {
+ clock = ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:2) - (0 ? 8:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ?
+ 8:2))) | (((gctUINT32) ((gctUINT32) (Hardware->powerOnFscaleVal) & ((gctUINT32) ((((1 ?
+ 8:2) - (0 ? 8:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ?
+ 8:2)));
+ }
+#endif
+
+ if (State == gcvPOWER_SUSPEND && Hardware->chipPowerState == gcvPOWER_OFF && broadcast)
+ {
+#if gcdPOWER_SUSPEND_WHEN_IDLE
+ /* Do nothing */
+
+ /* Release the power mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+#else
+ /* Clock should be on when switch power from off to suspend */
+ clock = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) |
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ? 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:1) - (0 ?
+ 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) |
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:2) - (0 ? 8:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ?
+ 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ?
+ 8:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ?
+ 8:2))) |
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ? 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ?
+ 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))) ;
+#endif
+ }
+
+#if gcdPOWEROFF_TIMEOUT
+ if (timeout)
+ {
+ gcmkONERROR(gckOS_GetTicks(&currentTime));
+
+ gcmkONERROR(
+ gckOS_TicksAfter(Hardware->powerOffTime, currentTime, &isAfter));
+
+ /* powerOffTime is pushed forward, give up.*/
+ if (isAfter
+ /* Expect a transition start from IDLE or SUSPEND. */
+ || (Hardware->chipPowerState == gcvPOWER_ON)
+ || (Hardware->chipPowerState == gcvPOWER_OFF)
+ )
+ {
+ /* Release the power mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex));
+
+ /* No need to do anything. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "Power Off GPU[%d] at %u [supposed to be at %u]",
+ Hardware->core, currentTime, Hardware->powerOffTime);
+ }
+#endif
+
+ if (flag == 0)
+ {
+ /* Release the power mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex));
+
+ /* No need to do anything. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+ /* If this is an internal power management, we have to check if we can grab
+ ** the global power semaphore. If we cannot, we have to wait until the
+ ** external world changes power management. */
+ if (!global)
+ {
+ /* Try to acquire the global semaphore. */
+ status = gckOS_TryAcquireSemaphore(os, Hardware->globalSemaphore);
+ if (status == gcvSTATUS_TIMEOUT)
+ {
+ if (State == gcvPOWER_IDLE || State == gcvPOWER_SUSPEND)
+ {
+ /* Called from thread routine which should NEVER sleep.*/
+ status = gcvSTATUS_OK;
+ goto OnError;
+ }
+
+ /* Release the power mutex. */
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "Releasing the power mutex.");
+ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex));
+ mutexAcquired = gcvFALSE;
+
+ /* Wait for the semaphore. */
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "Waiting for global semaphore.");
+ gcmkONERROR(gckOS_AcquireSemaphore(os, Hardware->globalSemaphore));
+ globalAcquired = gcvTRUE;
+
+ /* Acquire the power mutex. */
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "Reacquiring the power mutex.");
+ gcmkONERROR(gckOS_AcquireMutex(os,
+ Hardware->powerMutex,
+ gcvINFINITE));
+ mutexAcquired = gcvTRUE;
+
+ /* chipPowerState may be changed by external world during the time
+ ** we give up powerMutex, so updating flag now is necessary. */
+ flag = flags[Hardware->chipPowerState][State];
+
+ if (flag == 0)
+ {
+ gcmkONERROR(gckOS_ReleaseSemaphore(os, Hardware->globalSemaphore));
+ globalAcquired = gcvFALSE;
+
+ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex));
+ mutexAcquired = gcvFALSE;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+ }
+ else
+ {
+ /* Error. */
+ gcmkONERROR(status);
+ }
+
+ /* Release the global semaphore again. */
+ gcmkONERROR(gckOS_ReleaseSemaphore(os, Hardware->globalSemaphore));
+ globalAcquired = gcvFALSE;
+
+ /* Try to acquire the semaphore to make sure commit is not in progress
+ ** Otherwise, we just abort. */
+ if (flag & gcvPOWER_FLAG_ACQUIRE)
+ {
+ /* ON -> Other, boardcast. */
+ /* Try to acquire the power management semaphore. */
+ status = gckOS_TryAcquireSemaphore(os, command->powerSemaphore);
+
+ if (status == gcvSTATUS_OK)
+ {
+ acquired = gcvTRUE;
+
+ /* avoid acquiring again. */
+ flag &= ~gcvPOWER_FLAG_ACQUIRE;
+ }
+ else
+ {
+ /* Not ready to swith. */
+ status = gcvSTATUS_CHIP_NOT_READY;
+ goto OnError;
+ }
+ }
+ }
+ else
+ {
+ if (State == gcvPOWER_OFF || State == gcvPOWER_SUSPEND || State == gcvPOWER_IDLE)
+ {
+ /* Acquire the global semaphore if it has not been acquired. */
+ status = gckOS_TryAcquireSemaphore(os, Hardware->globalSemaphore);
+ if (status == gcvSTATUS_OK)
+ {
+ globalAcquired = gcvTRUE;
+ }
+ else if (status != gcvSTATUS_TIMEOUT)
+ {
+ /* Other errors. */
+ gcmkONERROR(status);
+ }
+ /* Ignore gcvSTATUS_TIMEOUT and leave globalAcquired as gcvFALSE.
+ ** gcvSTATUS_TIMEOUT means global semaphore has already
+ ** been acquired before this operation, so even if we fail,
+ ** we should not release it in our error handling. It should be
+ ** released by the next successful global gcvPOWER_ON. */
+ }
+
+ /* Global power management can't be aborted, so sync with
+ ** proceeding last commit. */
+ if (flag & gcvPOWER_FLAG_ACQUIRE)
+ {
+ /* Acquire the power management semaphore. */
+ gcmkONERROR(gckOS_AcquireSemaphore(os, command->powerSemaphore));
+ acquired = gcvTRUE;
+
+ /* avoid acquiring again. */
+ flag &= ~gcvPOWER_FLAG_ACQUIRE;
+ }
+ }
+
+ if (flag & (gcvPOWER_FLAG_INITIALIZE | gcvPOWER_FLAG_CLOCK_ON))
+ {
+ /* Turn on the power. */
+ gcmkONERROR(gckOS_SetGPUPower(os, Hardware->core, gcvTRUE, gcvTRUE));
+
+ /* Mark clock and power as enabled. */
+ Hardware->clockState = gcvTRUE;
+ Hardware->powerState = gcvTRUE;
+
+ for (;;)
+ {
+ /* Check if GPU is present and awake. */
+ status = _IsGPUPresent(Hardware);
+
+ /* Check if the GPU is not responding. */
+ if (status == gcvSTATUS_GPU_NOT_RESPONDING)
+ {
+ /* Turn off the power and clock. */
+ gcmkONERROR(gckOS_SetGPUPower(os, Hardware->core, gcvFALSE, gcvFALSE));
+
+ Hardware->clockState = gcvFALSE;
+ Hardware->powerState = gcvFALSE;
+
+ /* Wait a little. */
+ gckOS_Delay(os, 1);
+
+ /* Turn on the power and clock. */
+ gcmkONERROR(gckOS_SetGPUPower(os, Hardware->core, gcvTRUE, gcvTRUE));
+
+ Hardware->clockState = gcvTRUE;
+ Hardware->powerState = gcvTRUE;
+
+ /* We need to initialize the hardware and start the command
+ * processor. */
+ flag |= gcvPOWER_FLAG_INITIALIZE | gcvPOWER_FLAG_START;
+ }
+ else
+ {
+ /* Test for error. */
+ gcmkONERROR(status);
+
+ /* Break out of loop. */
+ break;
+ }
+ }
+ }
+
+ /* Get time until powered on. */
+ gcmkPROFILE_QUERY(time, onTime);
+
+ if (flag & gcvPOWER_FLAG_STALL)
+ {
+ gctBOOL idle;
+ gctINT32 atomValue;
+
+ /* For global operation, all pending commits have already been
+ ** blocked by globalSemaphore or powerSemaphore.*/
+ if (!global)
+ {
+ /* Check commit atom. */
+ gcmkONERROR(gckOS_AtomGet(os, command->atomCommit, &atomValue));
+
+ if (atomValue > 0)
+ {
+ /* Commits are pending - abort power management. */
+ status = broadcast ? gcvSTATUS_CHIP_NOT_READY
+ : gcvSTATUS_MORE_DATA;
+ goto OnError;
+ }
+ }
+
+ if (broadcast)
+ {
+ /* Check for idle. */
+ gcmkONERROR(gckHARDWARE_QueryIdle(Hardware, &idle));
+
+ if (!idle)
+ {
+ status = gcvSTATUS_CHIP_NOT_READY;
+ goto OnError;
+ }
+ }
+
+ else
+ {
+ /* Wait to finish all commands. */
+ gcmkONERROR(gckCOMMAND_Stall(command, gcvTRUE));
+
+ for (;;)
+ {
+ gcmkONERROR(gckHARDWARE_QueryIdle(Hardware, &idle));
+
+ if (idle)
+ {
+ break;
+ }
+
+ gcmkVERIFY_OK(gckOS_Delay(Hardware->os, 1));
+ }
+ }
+ }
+
+ /* Get time until stalled. */
+ gcmkPROFILE_QUERY(time, stallTime);
+
+ if (flag & gcvPOWER_FLAG_ACQUIRE)
+ {
+ /* Acquire the power management semaphore. */
+ gcmkONERROR(gckOS_AcquireSemaphore(os, command->powerSemaphore));
+ acquired = gcvTRUE;
+ }
+
+ if (flag & gcvPOWER_FLAG_STOP)
+ {
+ /* Stop the command parser. */
+ gcmkONERROR(gckCOMMAND_Stop(command));
+ }
+
+ /* Flush Cache before Power Off. */
+ if (flag & gcvPOWER_FLAG_POWER_OFF)
+ {
+ if (Hardware->clockState == gcvFALSE)
+ {
+ /* Turn off the GPU power. */
+ gcmkONERROR(
+ gckOS_SetGPUPower(os,
+ Hardware->core,
+ gcvTRUE,
+ gcvTRUE));
+
+ Hardware->clockState = gcvTRUE;
+#if gcdDVFS
+ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_DYNAMIC_FREQUENCY_SCALING) != gcvTRUE)
+#endif
+ {
+ /* Write the clock control register. */
+ gcmkONERROR(gckOS_WriteRegisterEx(os,
+ Hardware->core,
+ 0x00000,
+ clocks[0]));
+
+ /* Done loading the frequency scaler. */
+ gcmkONERROR(gckOS_WriteRegisterEx(os,
+ Hardware->core,
+ 0x00000,
+ ((((gctUINT32) (clocks[0])) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ? 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 9:9) - (0 ?
+ 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9)))));
+ }
+ }
+
+ if(_IsHardwareMatch(Hardware, gcv400, 0x4645))
+ {
+ gcmkONERROR(gckCOMMAND_Start(command));
+
+ gcmkONERROR(_FlushCache(Hardware, command));
+
+ gckOS_Delay(gcvNULL, 1);
+
+ /* Stop the command parser. */
+ gcmkONERROR(gckCOMMAND_Stop(command));
+ }
+ else
+ {
+ gckHARDWARE_ExecuteFunctions(Hardware, gcvHARDWARE_FUNCTION_FLUSH);
+ gckOS_Delay(gcvNULL, 1);
+ }
+
+ flag |= gcvPOWER_FLAG_CLOCK_OFF;
+ }
+
+ /* Get time until stopped. */
+ gcmkPROFILE_QUERY(time, stopTime);
+
+ /* Only process this when hardware is enabled. */
+ if (Hardware->clockState && Hardware->powerState
+#if gcdDVFS
+ /* Don't touch clock control if dynamic frequency scaling is available. */
+ && gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_DYNAMIC_FREQUENCY_SCALING) != gcvTRUE
+#endif
+ )
+ {
+ if (flag & (gcvPOWER_FLAG_POWER_OFF | gcvPOWER_FLAG_CLOCK_OFF))
+ {
+ if (Hardware->identity.chipModel == gcv4000
+ && ((Hardware->identity.chipRevision == 0x5208) || (Hardware->identity.chipRevision == 0x5222)))
+ {
+ clock &= ~2U;
+ }
+ }
+
+ /* Write the clock control register. */
+ gcmkONERROR(gckOS_WriteRegisterEx(os,
+ Hardware->core,
+ 0x00000,
+ clock));
+
+ /* Done loading the frequency scaler. */
+ gcmkONERROR(gckOS_WriteRegisterEx(os,
+ Hardware->core,
+ 0x00000,
+ ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ? 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 9:9) - (0 ?
+ 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9)))));
+ }
+
+ if (flag & gcvPOWER_FLAG_DELAY)
+ {
+ /* Wait for the specified amount of time to settle coming back from
+ ** power-off or suspend state. */
+ gcmkONERROR(gckOS_Delay(os, gcdPOWER_CONTROL_DELAY));
+ }
+
+ /* Get time until delayed. */
+ gcmkPROFILE_QUERY(time, delayTime);
+
+ if (flag & gcvPOWER_FLAG_INITIALIZE)
+ {
+ /* Initialize hardware. */
+ gcmkONERROR(gckHARDWARE_InitializeHardware(Hardware));
+
+ gcmkONERROR(gckHARDWARE_SetFastClear(Hardware,
+ Hardware->options.allowFastClear,
+ Hardware->options.allowCompression));
+
+ /* Force the command queue to reload the next context. */
+ command->currContext = gcvNULL;
+
+ /* Trigger a possible dummy draw. */
+ command->dummyDraw = gcvTRUE;
+ }
+
+ /* Get time until initialized. */
+ gcmkPROFILE_QUERY(time, initTime);
+
+ if (flag & (gcvPOWER_FLAG_POWER_OFF | gcvPOWER_FLAG_CLOCK_OFF))
+ {
+ /* Turn off the GPU power. */
+ gcmkONERROR(
+ gckOS_SetGPUPower(os,
+ Hardware->core,
+ (flag & gcvPOWER_FLAG_CLOCK_OFF) ? gcvFALSE
+ : gcvTRUE,
+ (flag & gcvPOWER_FLAG_POWER_OFF) ? gcvFALSE
+ : gcvTRUE));
+
+ /* Save current hardware power and clock states. */
+ Hardware->clockState = (flag & gcvPOWER_FLAG_CLOCK_OFF) ? gcvFALSE
+ : gcvTRUE;
+ Hardware->powerState = (flag & gcvPOWER_FLAG_POWER_OFF) ? gcvFALSE
+ : gcvTRUE;
+ }
+
+ /* Get time until off. */
+ gcmkPROFILE_QUERY(time, offTime);
+
+ if (flag & gcvPOWER_FLAG_START)
+ {
+ /* Start the command processor. */
+ gcmkONERROR(gckCOMMAND_Start(command));
+ commandStarted = gcvTRUE;
+ }
+
+ /* Get time until started. */
+ gcmkPROFILE_QUERY(time, startTime);
+
+ if (flag & gcvPOWER_FLAG_RELEASE)
+ {
+ /* Release the power management semaphore. */
+ gcmkONERROR(gckOS_ReleaseSemaphore(os, command->powerSemaphore));
+ acquired = gcvFALSE;
+
+ if (global)
+ {
+ /* Verify global semaphore has been acquired already before
+ ** we release it.
+ ** If it was acquired, gckOS_TryAcquireSemaphore will return
+ ** gcvSTATUS_TIMEOUT and we release it. Otherwise, global
+ ** semaphore will be acquried now, but it still is released
+ ** immediately. */
+ status = gckOS_TryAcquireSemaphore(os, Hardware->globalSemaphore);
+ if (status != gcvSTATUS_TIMEOUT)
+ {
+ gcmkONERROR(status);
+ }
+
+ /* Release the global semaphore. */
+ gcmkONERROR(gckOS_ReleaseSemaphore(os, Hardware->globalSemaphore));
+ globalAcquired = gcvFALSE;
+ }
+ }
+
+ gckSTATETIMER_Accumulate(&Hardware->powerStateTimer, Hardware->chipPowerState);
+
+ /* Save the new power state. */
+ Hardware->chipPowerState = State;
+
+#if gcdDVFS
+ if (State == gcvPOWER_ON && Hardware->kernel->dvfs)
+ {
+ gckDVFS_Start(Hardware->kernel->dvfs);
+ }
+#endif
+
+#if gcdPOWEROFF_TIMEOUT
+ /* Reset power off time */
+ gcmkONERROR(gckOS_GetTicks(&currentTime));
+
+ Hardware->powerOffTime = currentTime + Hardware->powerOffTimeout;
+
+ if (State == gcvPOWER_IDLE || State == gcvPOWER_SUSPEND)
+ {
+ /* Start a timer to power off GPU when GPU enters IDLE or SUSPEND. */
+ gcmkVERIFY_OK(gckOS_StartTimer(os,
+ Hardware->powerOffTimer,
+ Hardware->powerOffTimeout));
+ }
+ else
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "Cancel powerOfftimer");
+
+ /* Cancel running timer when GPU enters ON or OFF. */
+ gcmkVERIFY_OK(gckOS_StopTimer(os, Hardware->powerOffTimer));
+ }
+#endif
+
+ /* Release the power mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex));
+
+ /* Get total time. */
+ gcmkPROFILE_QUERY(time, totalTime);
+#if gcdENABLE_PROFILING
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "PROF(%llu): mutex:%llu on:%llu stall:%llu stop:%llu",
+ freq, mutexTime, onTime, stallTime, stopTime);
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ " delay:%llu init:%llu off:%llu start:%llu total:%llu",
+ delayTime, initTime, offTime, startTime, totalTime);
+#endif
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (commandStarted)
+ {
+ gcmkVERIFY_OK(gckCOMMAND_Stop(command));
+ }
+
+ if (acquired)
+ {
+ /* Release semaphore. */
+ gcmkVERIFY_OK(gckOS_ReleaseSemaphore(Hardware->os,
+ command->powerSemaphore));
+ }
+
+ if (globalAcquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseSemaphore(Hardware->os,
+ Hardware->globalSemaphore));
+ }
+
+ if (mutexAcquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_QueryPowerManagementState
+**
+** Get GPU power state.
+**
+** INPUT:
+**
+** gckHARDWARE Harwdare
+** Pointer to an gckHARDWARE object.
+**
+** gceCHIPPOWERSTATE* State
+** Power State.
+**
+*/
+gceSTATUS
+gckHARDWARE_QueryPowerManagementState(
+ IN gckHARDWARE Hardware,
+ OUT gceCHIPPOWERSTATE* State
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(State != gcvNULL);
+
+ /* Return the statue. */
+ *State = Hardware->chipPowerState;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*State=%d", *State);
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_SetPowerManagement
+**
+** Configure GPU power management function.
+** Only used in driver initialization stage.
+**
+** INPUT:
+**
+** gckHARDWARE Harwdare
+** Pointer to an gckHARDWARE object.
+**
+** gctBOOL PowerManagement
+** Power Mangement State.
+**
+*/
+gceSTATUS
+gckHARDWARE_SetPowerManagement(
+ IN gckHARDWARE Hardware,
+ IN gctBOOL PowerManagement
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ if(_IsHardwareMatch(Hardware, gcv7000, 0x6008))
+ {
+ PowerManagement = gcvFALSE;
+ }
+
+ gcmkVERIFY_OK(
+ gckOS_AcquireMutex(Hardware->os, Hardware->powerMutex, gcvINFINITE));
+
+ Hardware->options.powerManagement = PowerManagement;
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_SetGpuProfiler
+**
+** Configure GPU profiler function.
+** Only used in driver initialization stage.
+**
+** INPUT:
+**
+** gckHARDWARE Harwdare
+** Pointer to an gckHARDWARE object.
+**
+** gctBOOL GpuProfiler
+** GOU Profiler State.
+**
+*/
+gceSTATUS
+gckHARDWARE_SetGpuProfiler(
+ IN gckHARDWARE Hardware,
+ IN gctBOOL GpuProfiler
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ if (GpuProfiler == gcvTRUE)
+ {
+ gctUINT32 data = 0;
+
+ /* Need to disable clock gating when doing profiling. */
+ gcmkVERIFY_OK(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress +
+ 0x00100,
+ &data));
+
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0)));
+
+
+ gcmkVERIFY_OK(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00100,
+ data));
+ }
+
+ Hardware->options.gpuProfiler= GpuProfiler;
+
+ if (GpuProfiler == gcvTRUE)
+ {
+ Hardware->waitCount = 200 * 100;
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+#if gcdENABLE_FSCALE_VAL_ADJUST
+gceSTATUS
+gckHARDWARE_SetFscaleValue(
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 FscaleValue
+ )
+{
+ gceSTATUS status;
+ gctUINT32 clock;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Hardware=0x%x FscaleValue=%d", Hardware, FscaleValue);
+
+ gcmkVERIFY_ARGUMENT(FscaleValue > 0 && FscaleValue <= 64);
+
+ gcmkONERROR(
+ gckOS_AcquireMutex(Hardware->os, Hardware->powerMutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ Hardware->powerOnFscaleVal = FscaleValue;
+
+ if (Hardware->chipPowerState == gcvPOWER_ON)
+ {
+ gctUINT32 data;
+
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00104,
+ &data));
+
+ /* Disable all clock gating. */
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00104,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ? 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ?
+ 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ? 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 2:2) - (0 ?
+ 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ? 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 3:3) - (0 ?
+ 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ? 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 4:4) - (0 ?
+ 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ? 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 5:5) - (0 ?
+ 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ? 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 6:6) - (0 ?
+ 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:7) - (0 ? 7:7) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 7:7) - (0 ?
+ 7:7) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ?
+ 7:7)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:8) - (0 ? 8:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ?
+ 8:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:8) - (0 ?
+ 8:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ?
+ 8:8)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ? 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ?
+ 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ? 11:11) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ? 11:11))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ? 11:11) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ? 11:11)))));
+
+ clock = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ? 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:1) - (0 ?
+ 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:2) - (0 ? 8:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ?
+ 8:2))) | (((gctUINT32) ((gctUINT32) (FscaleValue) & ((gctUINT32) ((((1 ?
+ 8:2) - (0 ? 8:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ?
+ 8:2)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ? 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ?
+ 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9)));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ clock));
+
+ /* Done loading the frequency scaler. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ? 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 9:9) - (0 ?
+ 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9)))));
+
+ /* Restore all clock gating. */
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ Hardware->powerBaseAddress
+ + 0x00104,
+ data));
+ }
+
+ gcmkVERIFY(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ gcmkVERIFY(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckHARDWARE_GetFscaleValue(
+ IN gckHARDWARE Hardware,
+ IN gctUINT * FscaleValue,
+ IN gctUINT * MinFscaleValue,
+ IN gctUINT * MaxFscaleValue
+ )
+{
+ *FscaleValue = Hardware->powerOnFscaleVal;
+ *MinFscaleValue = Hardware->minFscaleValue;
+ *MaxFscaleValue = 64;
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHARDWARE_SetMinFscaleValue(
+ IN gckHARDWARE Hardware,
+ IN gctUINT MinFscaleValue
+ )
+{
+ if (MinFscaleValue >= 1 && MinFscaleValue <= 64)
+ {
+ Hardware->minFscaleValue = MinFscaleValue;
+ }
+
+ return gcvSTATUS_OK;
+}
+#endif
+
+#if gcdPOWEROFF_TIMEOUT
+gceSTATUS
+gckHARDWARE_SetPowerOffTimeout(
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 Timeout
+)
+{
+ gcmkHEADER_ARG("Hardware=0x%x Timeout=%d", Hardware, Timeout);
+
+ Hardware->powerOffTimeout = Timeout;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+
+gceSTATUS
+gckHARDWARE_QueryPowerOffTimeout(
+ IN gckHARDWARE Hardware,
+ OUT gctUINT32* Timeout
+)
+{
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ *Timeout = Hardware->powerOffTimeout;
+
+ gcmkFOOTER_ARG("*Timeout=%d", *Timeout);
+ return gcvSTATUS_OK;
+}
+#endif
+
+gceSTATUS
+gckHARDWARE_QueryIdle(
+ IN gckHARDWARE Hardware,
+ OUT gctBOOL_PTR IsIdle
+ )
+{
+ gceSTATUS status;
+ gctUINT32 idle, address;
+ gctBOOL isIdle;
+ gctBOOL hasL2Cache;
+
+#if gcdINTERRUPT_STATISTIC
+ gctINT32 pendingInterrupt;
+#endif
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(IsIdle != gcvNULL);
+
+ /* We are idle when the power is not ON. */
+ if (Hardware->chipPowerState != gcvPOWER_ON)
+ {
+ isIdle = gcvTRUE;
+ }
+
+ else
+ {
+ /* Read idle register. */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00004, &idle));
+
+ /* Pipe must be idle. */
+ if ((idle | (1 << 14)) != 0x7ffffffe)
+ {
+ /* Something is busy. */
+ isIdle = gcvFALSE;
+ }
+
+ else
+ {
+#if gcdSECURITY
+ isIdle = gcvTRUE;
+ address = 0;
+#else
+ /* Read the current FE address. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00664,
+ &address));
+
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00664,
+ &address));
+
+ hasL2Cache = gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_64K_L2_CACHE);
+
+ /* Test if address is inside the last WAIT/LINK sequence. */
+ if ((address >= Hardware->lastWaitLink)
+ && (address <= Hardware->lastWaitLink + (hasL2Cache ? 16 : 8))
+ )
+ {
+ /* FE is in last WAIT/LINK and the pipe is idle. */
+ isIdle = gcvTRUE;
+ }
+ else
+ {
+ /* FE is not in WAIT/LINK yet. */
+ isIdle = gcvFALSE;
+ }
+#endif
+ }
+ }
+
+#if gcdINTERRUPT_STATISTIC
+ gcmkONERROR(gckOS_AtomGet(
+ Hardware->os,
+ Hardware->kernel->eventObj->interruptCount,
+ &pendingInterrupt
+ ));
+
+ if (pendingInterrupt)
+ {
+ isIdle = gcvFALSE;
+ }
+#endif
+
+ *IsIdle = isIdle;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+** Handy macros that will help in reading those debug registers.
+*/
+#define gcmkREAD_DEBUG_REGISTER_PART1(control, block, index, data) \
+ gcmkONERROR(\
+ gckOS_WriteRegisterEx(Hardware->os, \
+ Hardware->core, \
+ GC_DEBUG_CONTROL##control##_Address, \
+ gcmSETFIELD(0, \
+ GC_DEBUG_CONTROL##control, \
+ block, \
+ index))); \
+ gcmkONERROR(\
+ gckOS_ReadRegisterEx(Hardware->os, \
+ Hardware->core, \
+ GC_DEBUG_SIGNALS_##block##_Address, \
+ &profiler_part1->data))
+
+#define gcmkREAD_DEBUG_REGISTER_PART2(control, block, index, data) \
+ gcmkONERROR(\
+ gckOS_WriteRegisterEx(Hardware->os, \
+ Hardware->core, \
+ GC_DEBUG_CONTROL##control##_Address, \
+ gcmSETFIELD(0, \
+ GC_DEBUG_CONTROL##control, \
+ block, \
+ index))); \
+ gcmkONERROR(\
+ gckOS_ReadRegisterEx(Hardware->os, \
+ Hardware->core, \
+ GC_DEBUG_SIGNALS_##block##_Address, \
+ &profiler_part2->data))
+
+#define gcmkREAD_DEBUG_REGISTER_N(control, block, index, data) \
+ gcmkONERROR(\
+ gckOS_WriteRegisterEx(Hardware->os, \
+ Hardware->core, \
+ GC_DEBUG_CONTROL##control##_Address, \
+ gcmSETFIELD(0, \
+ GC_DEBUG_CONTROL##control, \
+ block, \
+ index))); \
+ gcmkONERROR(\
+ gckOS_ReadRegisterEx(Hardware->os, \
+ Hardware->core, \
+ GC_DEBUG_SIGNALS_##block##_Address, \
+ &data))
+
+#define gcmkRESET_DEBUG_REGISTER(control, block, value) \
+ gcmkONERROR(\
+ gckOS_WriteRegisterEx(Hardware->os, \
+ Hardware->core, \
+ GC_DEBUG_CONTROL##control##_Address, \
+ gcmSETFIELD(0, \
+ GC_DEBUG_CONTROL##control, \
+ block, \
+ value))); \
+ gcmkONERROR(\
+ gckOS_WriteRegisterEx(Hardware->os, \
+ Hardware->core, \
+ GC_DEBUG_CONTROL##control##_Address, \
+ gcmSETFIELD(0, \
+ GC_DEBUG_CONTROL##control, \
+ block, \
+ 0)))
+
+static gctUINT32
+CalcDelta(
+ IN gctUINT32 new,
+ IN gctUINT32 old
+ )
+{
+ if (new >= old)
+ {
+ return new - old;
+ }
+ else
+ {
+ return (gctUINT32)((gctUINT64)new + 0x100000000ll - old);
+ }
+}
+
+
+#if USE_SW_RESET
+#define gcmkRESET_PROFILE_DATA_PART1(counterName) \
+ temp = profiler_part1->counterName; \
+ profiler_part1->counterName = CalcDelta(temp, Context->preProfiler_part1.counterName); \
+ Context->preProfiler_part1.counterName = temp
+#endif
+
+#define gcmkUPDATE_PROFILE_DATA_PART1(data) \
+ profilerHistroy_part1->data += profiler_part1->data
+#define gcmkUPDATE_PROFILE_DATA_PART2(data) \
+ profilerHistroy_part2->data += profiler_part2->data
+
+gceSTATUS
+gckHARDWARE_QueryContextProfile(
+ IN gckHARDWARE Hardware,
+ IN gctBOOL Reset,
+ IN gckCONTEXT Context,
+ OUT gcsPROFILER_COUNTERS_PART1 * Counters_part1,
+ OUT gcsPROFILER_COUNTERS_PART2 * Counters_part2
+)
+{
+ gceSTATUS status;
+ gckCOMMAND command = Hardware->kernel->command;
+ gcsPROFILER_COUNTERS_PART1 * profiler_part1 = Counters_part1;
+ gcsPROFILER_COUNTERS_PART2 * profiler_part2 = Counters_part2;
+
+ gcmkHEADER_ARG("Hardware=0x%x Counters_part1=0x%x, Counters_part2=0x%x", Hardware, Counters_part1, Counters_part2);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ if (!Context)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+ /* Acquire the context sequnence mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(
+ command->os, command->mutexContextSeq, gcvINFINITE
+ ));
+
+ /* Read the counters. */
+ if (Counters_part1)
+ {
+ gcmkVERIFY_OK(gckOS_MemCopy(
+ profiler_part1, &Context->histroyProfiler_part1, gcmSIZEOF(gcsPROFILER_COUNTERS_PART1)
+ ));
+ }
+ else if (Counters_part2)
+ {
+ gcmkVERIFY_OK(gckOS_MemCopy(
+ profiler_part2, &Context->histroyProfiler_part2, gcmSIZEOF(gcsPROFILER_COUNTERS_PART2)
+ ));
+ }
+
+ /* Reset counters. */
+ if (Reset)
+ {
+ if (Counters_part1)
+ {
+ gcmkVERIFY_OK(gckOS_ZeroMemory(
+ &Context->histroyProfiler_part1, gcmSIZEOF(gcsPROFILER_COUNTERS_PART1)
+ ));
+ }
+ else if (Counters_part2)
+ {
+ gcmkVERIFY_OK(gckOS_ZeroMemory(
+ &Context->histroyProfiler_part2, gcmSIZEOF(gcsPROFILER_COUNTERS_PART2)
+ ));
+ }
+ }
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(
+ command->os, command->mutexContextSeq
+ ));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckHARDWARE_UpdateContextProfile(
+ IN gckHARDWARE Hardware,
+ IN gckCONTEXT Context
+)
+{
+ gceSTATUS status;
+ gcsPROFILER_COUNTERS_PART1 * profiler_part1 = &Context->latestProfiler_part1;
+ gcsPROFILER_COUNTERS_PART1 * profilerHistroy_part1 = &Context->histroyProfiler_part1;
+ gcsPROFILER_COUNTERS_PART2 * profiler_part2 = &Context->latestProfiler_part2;
+ gcsPROFILER_COUNTERS_PART2 * profilerHistroy_part2 = &Context->histroyProfiler_part2;
+ gceCHIPMODEL chipModel;
+ gctUINT32 chipRevision;
+ gctUINT32 i;
+ gctUINT32 resetValue = 0xF;
+ gctBOOL hasNewCounters = gcvFALSE;
+ gctUINT32 clock;
+ gctUINT32 colorKilled = 0, colorDrawn = 0, depthKilled = 0, depthDrawn = 0;
+ gctUINT32 totalRead, totalWrite;
+ gctUINT32 mc_axi_max_min_latency;
+ gctUINT32 temp;
+ gckCOMMAND command = Hardware->kernel->command;
+ gctBOOL mutexAcquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Hardware=0x%x Context=0x%x", Hardware, Context);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_OBJECT(Context, gcvOBJ_CONTEXT);
+
+ /* Acquire the context sequnence mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(
+ command->os, command->mutexContextSeq, gcvINFINITE
+ ));
+ mutexAcquired = gcvTRUE;
+
+ chipModel = Hardware->identity.chipModel;
+ chipRevision = Hardware->identity.chipRevision;
+ if ((chipModel == gcv5000 && chipRevision == 0x5434) || (chipModel == gcv3000 && chipRevision == 0x5435))
+ {
+ resetValue = 0xFF;
+ hasNewCounters = gcvTRUE;
+ }
+
+ if (chipModel == gcv2100 || chipModel == gcv2000 || chipModel == gcv880)
+ {
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00438,
+ &profiler_part2->hi_total_cycle_count));
+
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00078,
+ &profiler_part2->hi_total_idle_cycle_count));
+ }
+ else
+ {
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00078,
+ &profiler_part2->hi_total_cycle_count));
+
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0007C,
+ &profiler_part2->hi_total_idle_cycle_count));
+ }
+ gcmkUPDATE_PROFILE_DATA_PART2(hi_total_cycle_count);
+ gcmkUPDATE_PROFILE_DATA_PART2(hi_total_idle_cycle_count);
+
+ /* Read clock control register. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ &clock));
+
+ profiler_part2->hi_total_read_8B_count = 0;
+ profiler_part2->hi_total_write_8B_count = 0;
+ profiler_part1->pe0_pixel_count_drawn_by_color_pipe = 0;
+ profiler_part1->pe0_pixel_count_drawn_by_depth_pipe = 0;
+ profiler_part1->pe0_pixel_count_killed_by_color_pipe = 0;
+ profiler_part1->pe0_pixel_count_killed_by_depth_pipe = 0;
+ profiler_part1->pe1_pixel_count_drawn_by_color_pipe = 0;
+ profiler_part1->pe1_pixel_count_drawn_by_depth_pipe = 0;
+ profiler_part1->pe1_pixel_count_killed_by_color_pipe = 0;
+ profiler_part1->pe1_pixel_count_killed_by_depth_pipe = 0;
+
+ /* Walk through all avaiable pixel pipes. */
+ for (i = 0; i < Hardware->identity.pixelPipes; ++i)
+ {
+ /* Select proper pipe. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:20) - (0 ? 23:20) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:20) - (0 ?
+ 23:20) + 1))))))) << (0 ? 23:20))) | (((gctUINT32) ((gctUINT32) (i) & ((gctUINT32) ((((1 ?
+ 23:20) - (0 ? 23:20) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:20) - (0 ?
+ 23:20) + 1))))))) << (0 ? 23:20)))));
+
+ /* BW */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00040,
+ &totalRead));
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00044,
+ &totalWrite));
+
+ profiler_part2->hi_total_read_8B_count += totalRead;
+ profiler_part2->hi_total_write_8B_count += totalWrite;
+
+ /* PE */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16)))));gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454,
+ &colorKilled));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16)))));gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454,
+ &depthKilled));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16)))));gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454,
+ &colorDrawn));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16)))));gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454,
+ &depthDrawn));
+
+ if (i == 0)
+ {
+ profiler_part1->pe0_pixel_count_killed_by_color_pipe = colorKilled;
+ profiler_part1->pe0_pixel_count_killed_by_depth_pipe = depthKilled;
+ profiler_part1->pe0_pixel_count_drawn_by_color_pipe = colorDrawn;
+ profiler_part1->pe0_pixel_count_drawn_by_depth_pipe = depthDrawn;
+ }
+ else if (i == 1)
+ {
+ profiler_part1->pe1_pixel_count_killed_by_color_pipe = colorKilled;
+ profiler_part1->pe1_pixel_count_killed_by_depth_pipe = depthKilled;
+ profiler_part1->pe1_pixel_count_drawn_by_color_pipe = colorDrawn;
+ profiler_part1->pe1_pixel_count_drawn_by_depth_pipe = depthDrawn;
+ }
+ }
+
+ gcmkUPDATE_PROFILE_DATA_PART2(hi_total_read_8B_count);
+ gcmkUPDATE_PROFILE_DATA_PART2(hi_total_write_8B_count);
+#if USE_SW_RESET
+ gcmkRESET_PROFILE_DATA_PART1(pe0_pixel_count_killed_by_color_pipe);
+ gcmkRESET_PROFILE_DATA_PART1(pe0_pixel_count_killed_by_depth_pipe);
+ gcmkRESET_PROFILE_DATA_PART1(pe0_pixel_count_drawn_by_color_pipe);
+ gcmkRESET_PROFILE_DATA_PART1(pe0_pixel_count_drawn_by_depth_pipe);
+ gcmkRESET_PROFILE_DATA_PART1(pe1_pixel_count_killed_by_color_pipe);
+ gcmkRESET_PROFILE_DATA_PART1(pe1_pixel_count_killed_by_depth_pipe);
+ gcmkRESET_PROFILE_DATA_PART1(pe1_pixel_count_drawn_by_color_pipe);
+ gcmkRESET_PROFILE_DATA_PART1(pe1_pixel_count_drawn_by_depth_pipe);
+#endif
+ gcmkUPDATE_PROFILE_DATA_PART1(pe0_pixel_count_killed_by_color_pipe);
+ gcmkUPDATE_PROFILE_DATA_PART1(pe0_pixel_count_killed_by_depth_pipe);
+ gcmkUPDATE_PROFILE_DATA_PART1(pe0_pixel_count_drawn_by_color_pipe);
+ gcmkUPDATE_PROFILE_DATA_PART1(pe0_pixel_count_drawn_by_depth_pipe);
+ gcmkUPDATE_PROFILE_DATA_PART1(pe1_pixel_count_killed_by_color_pipe);
+ gcmkUPDATE_PROFILE_DATA_PART1(pe1_pixel_count_killed_by_depth_pipe);
+ gcmkUPDATE_PROFILE_DATA_PART1(pe1_pixel_count_drawn_by_color_pipe);
+ gcmkUPDATE_PROFILE_DATA_PART1(pe1_pixel_count_drawn_by_depth_pipe);
+
+ /* Reset clock control register. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ clock));
+
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00438, 0));
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00078, 0));
+
+#if !USE_SW_RESET
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16)))
+));
+#endif
+
+ /* FE */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00450, &profiler_part1->fe_draw_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00450, &profiler_part1->fe_out_vertex_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00450, &profiler_part1->fe_cache_miss_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (16) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00450, &profiler_part1->fe_cache_lk_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (17) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00450, &profiler_part1->fe_stall_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (18) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00450, &profiler_part1->fe_process_count));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0)))
+));
+
+ gcmkUPDATE_PROFILE_DATA_PART1(fe_draw_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(fe_out_vertex_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(fe_cache_miss_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(fe_cache_lk_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(fe_process_count);
+
+ /* SH */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->ps_inst_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->ps_rendered_pixel_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->vs_inst_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->vs_rendered_vertice_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->vs_branch_inst_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->vs_texld_inst_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->ps_branch_inst_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (14) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->ps_texld_inst_counter));
+ if (hasNewCounters)
+ {
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (19) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->vs_non_idle_starve_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->vs_starve_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (16) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->vs_stall_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (21) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->vs_process_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (20) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->ps_non_idle_starve_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (17) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->ps_starve_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (18) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->ps_stall_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (22) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->ps_process_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->shader_cycle_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (23) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->tx_non_idle_starve_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (24) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->tx_starve_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (25) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->tx_stall_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (26) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler_part1->tx_process_count));
+ }
+#if USE_SW_RESET
+ gcmkRESET_PROFILE_DATA_PART1(ps_inst_counter);
+ gcmkRESET_PROFILE_DATA_PART1(ps_rendered_pixel_counter);
+ gcmkRESET_PROFILE_DATA_PART1(vs_inst_counter);
+ gcmkRESET_PROFILE_DATA_PART1(vs_rendered_vertice_counter);
+ gcmkRESET_PROFILE_DATA_PART1(vs_branch_inst_counter);
+ gcmkRESET_PROFILE_DATA_PART1(vs_texld_inst_counter);
+ gcmkRESET_PROFILE_DATA_PART1(ps_branch_inst_counter);
+ gcmkRESET_PROFILE_DATA_PART1(ps_texld_inst_counter);
+ if (hasNewCounters)
+ {
+ gcmkRESET_PROFILE_DATA_PART1(vs_non_idle_starve_count);
+ gcmkRESET_PROFILE_DATA_PART1(vs_starve_count);
+ gcmkRESET_PROFILE_DATA_PART1(vs_stall_count);
+ gcmkRESET_PROFILE_DATA_PART1(vs_process_count);
+ gcmkRESET_PROFILE_DATA_PART1(ps_non_idle_starve_count);
+ gcmkRESET_PROFILE_DATA_PART1(ps_starve_count);
+ gcmkRESET_PROFILE_DATA_PART1(ps_stall_count);
+ gcmkRESET_PROFILE_DATA_PART1(ps_process_count);
+ gcmkRESET_PROFILE_DATA_PART1(shader_cycle_count);
+ gcmkRESET_PROFILE_DATA_PART1(tx_non_idle_starve_count);
+ gcmkRESET_PROFILE_DATA_PART1(tx_starve_count);
+ gcmkRESET_PROFILE_DATA_PART1(tx_stall_count);
+ gcmkRESET_PROFILE_DATA_PART1(tx_process_count);
+ }
+#endif
+ gcmkUPDATE_PROFILE_DATA_PART1(ps_inst_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(ps_rendered_pixel_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(vs_inst_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(vs_rendered_vertice_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(vs_branch_inst_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(vs_texld_inst_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(ps_branch_inst_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(ps_texld_inst_counter);
+ if (hasNewCounters)
+ {
+ gcmkUPDATE_PROFILE_DATA_PART1(vs_non_idle_starve_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(vs_starve_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(vs_stall_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(vs_process_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(ps_non_idle_starve_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(ps_starve_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(ps_stall_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(ps_process_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(shader_cycle_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(tx_non_idle_starve_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(tx_starve_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(tx_stall_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(tx_process_count);
+ }
+#if !USE_SW_RESET
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24)))
+));
+#endif
+
+ /* PA */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_input_vtx_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_input_prim_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_output_prim_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_depth_clipped_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_trivial_rejected_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_culled_prim_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_droped_prim_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_frustum_clipped_prim_counter));
+ if (hasNewCounters)
+ {
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_non_idle_starve_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_starve_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (14) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_stall_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler_part1->pa_process_count));
+ }
+#if USE_SW_RESET
+ gcmkRESET_PROFILE_DATA_PART1(pa_input_vtx_counter);
+ gcmkRESET_PROFILE_DATA_PART1(pa_input_prim_counter);
+ gcmkRESET_PROFILE_DATA_PART1(pa_output_prim_counter);
+ gcmkRESET_PROFILE_DATA_PART1(pa_depth_clipped_counter);
+ gcmkRESET_PROFILE_DATA_PART1(pa_trivial_rejected_counter);
+ gcmkRESET_PROFILE_DATA_PART1(pa_culled_prim_counter);
+ gcmkRESET_PROFILE_DATA_PART1(pa_droped_prim_counter);
+ gcmkRESET_PROFILE_DATA_PART1(pa_frustum_clipped_prim_counter);
+ if (hasNewCounters)
+ {
+ gcmkRESET_PROFILE_DATA_PART1(pa_non_idle_starve_count);
+ gcmkRESET_PROFILE_DATA_PART1(pa_starve_count);
+ gcmkRESET_PROFILE_DATA_PART1(pa_stall_count);
+ gcmkRESET_PROFILE_DATA_PART1(pa_process_count);
+ }
+#endif
+ gcmkUPDATE_PROFILE_DATA_PART1(pa_input_vtx_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(pa_input_prim_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(pa_output_prim_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(pa_depth_clipped_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(pa_trivial_rejected_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(pa_culled_prim_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(pa_droped_prim_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(pa_frustum_clipped_prim_counter);
+ if (hasNewCounters)
+ {
+ gcmkUPDATE_PROFILE_DATA_PART1(pa_non_idle_starve_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(pa_starve_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(pa_stall_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(pa_process_count);
+ }
+#if !USE_SW_RESET
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0)))
+));
+#endif
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_clipped_triangle_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (16) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_clipped_line_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (17) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_culled_triangle_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (18) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_culled_lines_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (19) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_trivial_rejected_line_count));
+ if (hasNewCounters)
+ {
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_starve_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_stall_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_receive_triangle_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_send_triangle_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_receive_lines_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_send_lines_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (14) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_process_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (20) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler_part1->se_non_idle_starve_count));
+ }
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8)))
+));
+
+ gcmkUPDATE_PROFILE_DATA_PART1(se_clipped_triangle_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(se_clipped_line_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(se_culled_triangle_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(se_culled_lines_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(se_trivial_rejected_line_count);
+ if (hasNewCounters)
+ {
+ gcmkUPDATE_PROFILE_DATA_PART1(se_starve_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(se_stall_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(se_receive_triangle_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(se_send_triangle_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(se_receive_lines_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(se_send_lines_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(se_process_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(se_non_idle_starve_count);
+ }
+
+ /* RA */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_valid_pixel_count_to_render));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_total_quad_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_valid_quad_count_after_early_z));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_input_prim_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_pipe_cache_miss_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_prefetch_cache_miss_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_eez_culled_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (17) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_pipe_hz_cache_miss_counter));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (18) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_prefetch_hz_cache_miss_counter));
+ if (hasNewCounters)
+ {
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_non_idle_starve_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (14) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_starve_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_stall_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (16) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler_part1->ra_process_count));
+ }
+#if USE_SW_RESET
+ gcmkRESET_PROFILE_DATA_PART1(ra_valid_pixel_count_to_render);
+ gcmkRESET_PROFILE_DATA_PART1(ra_total_quad_count);
+ gcmkRESET_PROFILE_DATA_PART1(ra_valid_quad_count_after_early_z);
+ gcmkRESET_PROFILE_DATA_PART1(ra_input_prim_count);
+ gcmkRESET_PROFILE_DATA_PART1(ra_pipe_cache_miss_counter);
+ gcmkRESET_PROFILE_DATA_PART1(ra_prefetch_cache_miss_counter);
+ gcmkRESET_PROFILE_DATA_PART1(ra_eez_culled_counter);
+ gcmkRESET_PROFILE_DATA_PART1(ra_pipe_hz_cache_miss_counter);
+ gcmkRESET_PROFILE_DATA_PART1(ra_prefetch_hz_cache_miss_counter);
+ if (hasNewCounters)
+ {
+ gcmkRESET_PROFILE_DATA_PART1(ra_non_idle_starve_count);
+ gcmkRESET_PROFILE_DATA_PART1(ra_starve_count);
+ gcmkRESET_PROFILE_DATA_PART1(ra_stall_count);
+ gcmkRESET_PROFILE_DATA_PART1(ra_process_count);
+ }
+#endif
+ gcmkUPDATE_PROFILE_DATA_PART1(ra_valid_pixel_count_to_render);
+ gcmkUPDATE_PROFILE_DATA_PART1(ra_total_quad_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(ra_valid_quad_count_after_early_z);
+ gcmkUPDATE_PROFILE_DATA_PART1(ra_input_prim_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(ra_pipe_cache_miss_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(ra_prefetch_cache_miss_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(ra_eez_culled_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(ra_pipe_hz_cache_miss_counter);
+ gcmkUPDATE_PROFILE_DATA_PART1(ra_prefetch_hz_cache_miss_counter);
+ if (hasNewCounters)
+ {
+ gcmkUPDATE_PROFILE_DATA_PART1(ra_non_idle_starve_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(ra_starve_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(ra_stall_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(ra_process_count);
+ }
+#if !USE_SW_RESET
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16)))
+));
+#endif
+
+ /* TX */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler_part1->tx_total_bilinear_requests));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler_part1->tx_total_trilinear_requests));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler_part1->tx_total_discarded_texture_requests));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler_part1->tx_total_texture_requests));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler_part1->tx_mc0_miss_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler_part1->tx_mc0_request_byte_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler_part1->tx_mc1_miss_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler_part1->tx_mc1_request_byte_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24)))
+));
+
+ gcmkUPDATE_PROFILE_DATA_PART1(tx_total_bilinear_requests);
+ gcmkUPDATE_PROFILE_DATA_PART1(tx_total_trilinear_requests);
+ gcmkUPDATE_PROFILE_DATA_PART1(tx_total_discarded_texture_requests);
+ gcmkUPDATE_PROFILE_DATA_PART1(tx_total_texture_requests);
+ gcmkUPDATE_PROFILE_DATA_PART1(tx_mc0_miss_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(tx_mc0_request_byte_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(tx_mc1_miss_count);
+ gcmkUPDATE_PROFILE_DATA_PART1(tx_mc1_request_byte_count);
+
+ /* MC */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_read_req_8B_from_colorpipe));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_read_req_8B_sentout_from_colorpipe));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_write_req_8B_from_colorpipe));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_read_req_sentout_from_colorpipe));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_write_req_from_colorpipe));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_read_req_8B_from_depthpipe));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_read_req_8B_sentout_from_depthpipe));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_write_req_8B_from_depthpipe));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_read_req_sentout_from_depthpipe));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_write_req_from_depthpipe));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_read_req_8B_from_others));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_write_req_8B_from_others));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (14) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_read_req_from_others));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mcc_total_write_req_from_others));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (21) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_fe_read_bandwidth));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (22) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_mmu_read_bandwidth));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (23) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_blt_read_bandwidth));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (24) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_sh0_read_bandwidth));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (25) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_sh1_read_bandwidth));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (26) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_pe_write_bandwidth));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (27) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_blt_write_bandwidth));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (28) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_sh0_write_bandwidth));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (29) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler_part2->mc_sh1_write_bandwidth));
+
+ /* Reset counters. */
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x0003C, 1));
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x0003C, 0));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0)))
+));
+
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_read_req_8B_from_colorpipe);
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_read_req_8B_sentout_from_colorpipe);
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_write_req_8B_from_colorpipe);
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_read_req_sentout_from_colorpipe);
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_write_req_from_colorpipe);
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_read_req_8B_from_depthpipe);
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_read_req_8B_sentout_from_depthpipe);
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_write_req_8B_from_depthpipe);
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_read_req_sentout_from_depthpipe);
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_write_req_from_depthpipe);
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_read_req_8B_from_others);
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_write_req_8B_from_others);
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_read_req_from_others);
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_total_write_req_from_others);
+ gcmkUPDATE_PROFILE_DATA_PART2(mc_fe_read_bandwidth);
+ gcmkUPDATE_PROFILE_DATA_PART2(mc_mmu_read_bandwidth);
+ gcmkUPDATE_PROFILE_DATA_PART2(mc_blt_read_bandwidth);
+ gcmkUPDATE_PROFILE_DATA_PART2(mc_sh0_read_bandwidth);
+ gcmkUPDATE_PROFILE_DATA_PART2(mc_sh1_read_bandwidth);
+ gcmkUPDATE_PROFILE_DATA_PART2(mc_pe_write_bandwidth);
+ gcmkUPDATE_PROFILE_DATA_PART2(mc_blt_write_bandwidth);
+ gcmkUPDATE_PROFILE_DATA_PART2(mc_sh0_write_bandwidth);
+ gcmkUPDATE_PROFILE_DATA_PART2(mc_sh1_write_bandwidth);
+
+ /* read latency counters */
+ if (hasNewCounters)
+ {
+ /* latency */
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0056C,
+ &mc_axi_max_min_latency));
+
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00570,
+ &profiler_part2->mcc_axi_total_latency));
+
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00574,
+ &profiler_part2->mcc_axi_sample_count));
+
+ /* Reset Latency counters */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00568,
+ 0x10a));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00568,
+ 0xa));
+
+ profiler_part2->mcc_axi_min_latency = (mc_axi_max_min_latency & 0xffff0000) >> 16;
+ profiler_part2->mcc_axi_max_latency = (mc_axi_max_min_latency & 0x0000ffff);
+ if (profiler_part2->mcc_axi_min_latency == 4095)
+ profiler_part2->mcc_axi_min_latency = 0;
+
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_axi_min_latency);
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_axi_max_latency);
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_axi_total_latency);
+ gcmkUPDATE_PROFILE_DATA_PART2(mcc_axi_sample_count);
+ }
+
+ /* HI */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0046C, &profiler_part2->hi0_axi_cycles_read_request_stalled));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0046C, &profiler_part2->hi0_axi_cycles_write_request_stalled));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0046C, &profiler_part2->hi0_axi_cycles_write_data_stalled));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8)))
+));
+
+ gcmkUPDATE_PROFILE_DATA_PART2(hi0_axi_cycles_read_request_stalled);
+ gcmkUPDATE_PROFILE_DATA_PART2(hi0_axi_cycles_write_request_stalled);
+ gcmkUPDATE_PROFILE_DATA_PART2(hi0_axi_cycles_write_data_stalled);
+
+ /* L2 */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_total_axi0_read_request_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_total_axi0_write_request_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_total_axi1_write_request_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_total_read_transactions_request_by_axi0));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_total_read_transactions_request_by_axi1));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_total_write_transactions_request_by_axi0));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_total_write_transactions_request_by_axi1));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (16) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_axi0_minmax_latency));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (17) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_axi0_total_latency));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (18) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_axi0_total_request_count));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (19) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_axi1_minmax_latency));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (20) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_axi1_total_latency));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (21) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00564, &profiler_part2->l2_axi1_total_request_count));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (resetValue) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) ));
+gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16)))
+));
+
+ profiler_part2->l2_axi0_min_latency = (profiler_part2->l2_axi0_minmax_latency & 0xffff0000) >> 16;
+ profiler_part2->l2_axi0_max_latency = (profiler_part2->l2_axi0_minmax_latency & 0x0000ffff);
+ profiler_part2->l2_axi1_min_latency = (profiler_part2->l2_axi0_minmax_latency & 0xffff0000) >> 16;
+ profiler_part2->l2_axi1_max_latency = (profiler_part2->l2_axi0_minmax_latency & 0x0000ffff);
+ gcmkUPDATE_PROFILE_DATA_PART2(l2_total_axi0_read_request_count);
+ gcmkUPDATE_PROFILE_DATA_PART2(l2_total_axi1_read_request_count);
+ gcmkUPDATE_PROFILE_DATA_PART2(l2_total_axi0_write_request_count);
+ gcmkUPDATE_PROFILE_DATA_PART2(l2_total_axi1_write_request_count);
+ gcmkUPDATE_PROFILE_DATA_PART2(l2_total_read_transactions_request_by_axi0);
+ gcmkUPDATE_PROFILE_DATA_PART2(l2_total_read_transactions_request_by_axi1);
+ gcmkUPDATE_PROFILE_DATA_PART2(l2_total_write_transactions_request_by_axi0);
+ gcmkUPDATE_PROFILE_DATA_PART2(l2_total_write_transactions_request_by_axi1);
+ gcmkUPDATE_PROFILE_DATA_PART2(l2_axi0_min_latency);
+ gcmkUPDATE_PROFILE_DATA_PART2(l2_axi0_max_latency);
+ gcmkUPDATE_PROFILE_DATA_PART2(l2_axi0_total_latency);
+ gcmkUPDATE_PROFILE_DATA_PART2(l2_axi0_total_request_count);
+ gcmkUPDATE_PROFILE_DATA_PART2(l2_axi1_min_latency);
+ gcmkUPDATE_PROFILE_DATA_PART2(l2_axi1_max_latency);
+ gcmkUPDATE_PROFILE_DATA_PART2(l2_axi1_total_latency);
+ gcmkUPDATE_PROFILE_DATA_PART2(l2_axi1_total_request_count);
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(
+ command->os, command->mutexContextSeq
+ ));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (mutexAcquired)
+ {
+ gckOS_ReleaseMutex(
+ command->os, command->mutexContextSeq
+ );
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+
+gceSTATUS
+gckHARDWARE_InitProfiler(
+ IN gckHARDWARE Hardware
+ )
+{
+ gceSTATUS status;
+ gctUINT32 control;
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ &control));
+ /* Enable debug register. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:11) - (0 ? 11:11) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ? 11:11))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 11:11) - (0 ? 11:11) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:11) - (0 ?
+ 11:11) + 1))))))) << (0 ? 11:11)))));
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+_ResetGPU(
+ IN gckHARDWARE Hardware,
+ IN gckOS Os,
+ IN gceCORE Core
+ )
+{
+ gctUINT32 control, idle;
+ gceSTATUS status;
+
+ for (;;)
+ {
+ /* Disable clock gating. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ Core,
+ Hardware->powerBaseAddress +
+ 0x00104,
+ 0x00000000));
+
+ control = ((((gctUINT32) (0x01590880)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:17) - (0 ? 17:17) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ? 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 17:17) - (0 ? 17:17) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:17) - (0 ?
+ 17:17) + 1))))))) << (0 ? 17:17)));
+
+ /* Disable pulse-eater. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ Core,
+ 0x0010C,
+ control));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ Core,
+ 0x0010C,
+ ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0)))));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ Core,
+ 0x0010C,
+ control));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ Core,
+ 0x00000,
+ ((((gctUINT32) (0x00000900)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ? 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ?
+ 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9)))));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ Core,
+ 0x00000,
+ 0x00000900));
+
+ /* Wait for clock being stable. */
+ gcmkONERROR(gckOS_Delay(Os, 1));
+
+ /* Isolate the GPU. */
+ control = ((((gctUINT32) (0x00000900)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:19) - (0 ? 19:19) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 19:19) - (0 ? 19:19) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ? 19:19)));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ Core,
+ 0x00000,
+ control));
+
+ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_SECURITY_AHB) &&
+ (Hardware->options.secureMode == gcvSECURE_IN_NORMAL))
+ {
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ Core,
+ 0x003A8,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))));
+ }
+ else
+ {
+ /* Set soft reset. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ Core,
+ 0x00000,
+ ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ? 12:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ? 12:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ? 12:12)))));
+ }
+
+ /* Wait for reset. */
+ gcmkONERROR(gckOS_Delay(Os, 1));
+
+ /* Reset soft reset bit. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ Core,
+ 0x00000,
+ ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ? 12:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ? 12:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ? 12:12)))));
+
+ /* Reset GPU isolation. */
+ control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:19) - (0 ? 19:19) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 19:19) - (0 ? 19:19) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ? 19:19)));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ Core,
+ 0x00000,
+ control));
+
+ /* Read idle register. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Os,
+ Core,
+ 0x00004,
+ &idle));
+
+ if ((((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ) == 0)
+ {
+ continue;
+ }
+
+ /* Read reset register. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Os,
+ Core,
+ 0x00000,
+ &control));
+
+ if (((((((gctUINT32) (control)) >> (0 ? 16:16)) & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1)))))) ) == 0)
+ || ((((((gctUINT32) (control)) >> (0 ? 17:17)) & ((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:17) - (0 ? 17:17) + 1)))))) ) == 0)
+ )
+ {
+ continue;
+ }
+
+ /* GPU is idle. */
+ break;
+ }
+
+ /* Success. */
+ return gcvSTATUS_OK;
+
+OnError:
+
+ /* Return the error. */
+ return status;
+}
+
+gceSTATUS
+gckHARDWARE_Reset(
+ IN gckHARDWARE Hardware
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_OBJECT(Hardware->kernel, gcvOBJ_KERNEL);
+
+ /* Record context ID in debug register before reset. */
+ gcmkONERROR(gckHARDWARE_UpdateContextID(Hardware));
+
+ /* Hardware reset. */
+ status = gckOS_ResetGPU(Hardware->os, Hardware->core);
+
+ if (gcmIS_ERROR(status))
+ {
+ if (Hardware->identity.chipRevision < 0x4600)
+ {
+ /* Not supported - we need the isolation bit. */
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ /* Soft reset. */
+ gcmkONERROR(_ResetGPU(Hardware, Hardware->os, Hardware->core));
+ }
+
+ /* Force the command queue to reload the next context. */
+ Hardware->kernel->command->currContext = gcvNULL;
+
+ /* Initialize hardware. */
+ gcmkONERROR(gckHARDWARE_InitializeHardware(Hardware));
+
+ /* Jump to address into which GPU should run if it doesn't stuck. */
+ gcmkONERROR(gckHARDWARE_Execute(Hardware, Hardware->kernel->restoreAddress, 16));
+
+ gcmkPRINT("[galcore]: recovery done");
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkPRINT("[galcore]: Hardware not reset successfully, give up");
+
+ /* Return the error. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckHARDWARE_GetBaseAddress(
+ IN gckHARDWARE Hardware,
+ OUT gctUINT32_PTR BaseAddress
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(BaseAddress != gcvNULL);
+
+ /* Test if we have a new Memory Controller. */
+ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_MC20))
+ {
+ /* No base address required. */
+ *BaseAddress = 0;
+ }
+ else
+ {
+ /* Get the base address from the OS. */
+ *BaseAddress = Hardware->baseAddress;
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*BaseAddress=0x%08x", *BaseAddress);
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHARDWARE_NeedBaseAddress(
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 State,
+ OUT gctBOOL_PTR NeedBase
+ )
+{
+ gctBOOL need = gcvFALSE;
+
+ gcmkHEADER_ARG("Hardware=0x%x State=0x%08x", Hardware, State);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(NeedBase != gcvNULL);
+
+ /* Make sure this is a load state. */
+ if (((((gctUINT32) (State)) >> (0 ? 31:27) & ((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))))
+ {
+#if gcdENABLE_3D
+ /* Get the state address. */
+ switch ((((((gctUINT32) (State)) >> (0 ? 15:0)) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1)))))) ))
+ {
+ case 0x0596:
+ case 0x0597:
+ case 0x0599:
+ case 0x059A:
+ case 0x05A9:
+ /* These states need a TRUE physical address. */
+ need = gcvTRUE;
+ break;
+ }
+#else
+ /* 2D addresses don't need a base address. */
+#endif
+ }
+
+ /* Return the flag. */
+ *NeedBase = need;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*NeedBase=%d", *NeedBase);
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_IsFeatureAvailable
+**
+** Verifies whether the specified feature is available in hardware.
+**
+** INPUT:
+**
+** gckHARDWARE Hardware
+** Pointer to an gckHARDWARE object.
+**
+** gceFEATURE Feature
+** Feature to be verified.
+*/
+gceSTATUS
+gckHARDWARE_IsFeatureAvailable(
+ IN gckHARDWARE Hardware,
+ IN gceFEATURE Feature
+ )
+{
+ gctBOOL available;
+
+ gcmkHEADER_ARG("Hardware=0x%x Feature=%d", Hardware, Feature);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ available = _QueryFeatureDatabase(Hardware, Feature);
+
+ /* Return result. */
+ gcmkFOOTER_ARG("%d", available ? gcvSTATUS_TRUE : gcvSTATUS_FALSE);
+ return available ? gcvSTATUS_TRUE : gcvSTATUS_FALSE;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_DumpMMUException
+**
+** Dump the MMU debug info on an MMU exception.
+**
+** INPUT:
+**
+** gckHARDWARE Harwdare
+** Pointer to an gckHARDWARE object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckHARDWARE_DumpMMUException(
+ IN gckHARDWARE Hardware
+ )
+{
+ gctUINT32 mmu = 0;
+ gctUINT32 mmuStatus = 0;
+ gctUINT32 address = 0;
+ gctUINT32 i = 0;
+ gctUINT32 mtlb = 0;
+ gctUINT32 stlb = 0;
+ gctUINT32 offset = 0;
+#if gcdPROCESS_ADDRESS_SPACE
+ gcsDATABASE_PTR database;
+#endif
+ gctUINT32 mmuStatusRegAddress;
+ gctUINT32 mmuExceptionAddress;
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+#if gcdENABLE_TRUST_APPLICATION
+ if (Hardware->options.secureMode == gcvSECURE_IN_TA)
+ {
+ gcmkVERIFY_OK(gckKERNEL_SecurityDumpMMUException(Hardware->kernel));
+
+ gckMMU_DumpRecentFreedAddress(Hardware->kernel->mmu);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+ else
+#endif
+ if (Hardware->options.secureMode == gcvSECURE_NONE)
+ {
+ mmuStatusRegAddress = 0x00188;
+ mmuExceptionAddress = 0x00190;
+ }
+ else
+ {
+ mmuStatusRegAddress = 0x00384;
+ mmuExceptionAddress = 0x00380;
+ }
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ gcmkPRINT("GPU[%d](ChipModel=0x%x ChipRevision=0x%x):\n",
+ Hardware->core,
+ Hardware->identity.chipModel,
+ Hardware->identity.chipRevision);
+
+ gcmkPRINT("**************************\n");
+ gcmkPRINT("*** MMU ERROR DUMP ***\n");
+ gcmkPRINT("**************************\n");
+
+
+ gcmkVERIFY_OK(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ mmuStatusRegAddress,
+ &mmuStatus));
+
+ gcmkPRINT(" MMU status = 0x%08X\n", mmuStatus);
+
+ for (i = 0; i < 4; i += 1)
+ {
+ mmu = mmuStatus & 0xF;
+ mmuStatus >>= 4;
+
+ if (mmu == 0)
+ {
+ continue;
+ }
+
+ switch (mmu)
+ {
+ case 1:
+ gcmkPRINT(" MMU%d: slave not present\n", i);
+ break;
+
+ case 2:
+ gcmkPRINT(" MMU%d: page not present\n", i);
+ break;
+
+ case 3:
+ gcmkPRINT(" MMU%d: write violation\n", i);
+ break;
+
+ case 4:
+ gcmkPRINT(" MMU%d: out of bound", i);
+ break;
+
+ case 5:
+ gcmkPRINT(" MMU%d: read security violation", i);
+ break;
+
+ case 6:
+ gcmkPRINT(" MMU%d: write security violation", i);
+ break;
+
+ default:
+ gcmkPRINT(" MMU%d: unknown state\n", i);
+ }
+
+ gcmkVERIFY_OK(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ mmuExceptionAddress + i * 4,
+ &address));
+
+ mtlb = (address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT;
+ stlb = (address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT;
+ offset = address & gcdMMU_OFFSET_4K_MASK;
+
+ gcmkPRINT(" MMU%d: exception address = 0x%08X\n", i, address);
+
+ gcmkPRINT(" MTLB entry = %d\n", mtlb);
+
+ gcmkPRINT(" STLB entry = %d\n", stlb);
+
+ gcmkPRINT(" Offset = 0x%08X (%d)\n", offset, offset);
+
+ gckMMU_DumpPageTableEntry(Hardware->kernel->mmu, address);
+
+#if gcdPROCESS_ADDRESS_SPACE
+ for (i = 0; i < gcmCOUNTOF(Hardware->kernel->db->db); ++i)
+ {
+ for (database = Hardware->kernel->db->db[i];
+ database != gcvNULL;
+ database = database->next)
+ {
+ gcmkPRINT(" database [%d] :", database->processID);
+ gckMMU_DumpPageTableEntry(database->mmu, address);
+ }
+ }
+#endif
+
+ gckMMU_DumpRecentFreedAddress(Hardware->kernel->mmu);
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHARDWARE_HandleFault(
+ IN gckHARDWARE Hardware
+ )
+{
+ gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+ gctUINT32 mmu, mmuStatus, address = gcvINVALID_ADDRESS, i = 0;
+ gctUINT32 mmuStatusRegAddress;
+ gctUINT32 mmuExceptionAddress;
+
+ gcuVIDMEM_NODE_PTR node;
+ gctUINT32 entryValue;
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ if (Hardware->options.secureMode == gcvSECURE_NONE)
+ {
+ mmuStatusRegAddress = 0x00188;
+ mmuExceptionAddress = 0x00190;
+ }
+ else
+ {
+ mmuStatusRegAddress = 0x00384;
+ mmuExceptionAddress = 0x00380;
+ }
+
+ /* Get MMU exception address. */
+#if gcdENABLE_TRUST_APPLICATION
+ if (Hardware->options.secureMode == gcvSECURE_IN_TA)
+ {
+ gckKERNEL_ReadMMUException(Hardware->kernel, &mmuStatus, &address);
+ }
+ else
+#endif
+ {
+ gcmkVERIFY_OK(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ mmuStatusRegAddress,
+ &mmuStatus
+ ));
+
+ gcmkPRINT(" MMU status = 0x%08X\n", mmuStatus);
+
+ for (i = 0; i < 4; i += 1)
+ {
+ mmu = mmuStatus & 0xF;
+ mmuStatus >>= 4;
+
+ if (mmu == 0)
+ {
+ continue;
+ }
+
+ gcmkVERIFY_OK(gckOS_ReadRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ mmuExceptionAddress + i * 4,
+ &address
+ ));
+
+ break;
+ }
+ }
+
+ if (address != gcvINVALID_ADDRESS)
+ {
+ address &= ~gcdMMU_PAGE_4K_MASK;
+
+ /* Try to allocate memory and setup map for exception address. */
+ gcmkONERROR(gckVIDMEM_FindVIDMEM(Hardware->kernel, address, &node, &entryValue));
+
+#if gcdENABLE_TRUST_APPLICATION
+ if (Hardware->options.secureMode == gcvSECURE_IN_TA)
+ {
+ gckKERNEL_HandleMMUException(
+ Hardware->kernel,
+ mmuStatus,
+ entryValue,
+ address
+ );
+ }
+ else
+#endif
+ {
+ gctUINT32_PTR entry;
+
+ /* Setup page table. */
+ gcmkONERROR(gckMMU_GetPageEntry(Hardware->kernel->mmu, address, &entry));
+
+ gckMMU_SetPage(Hardware->kernel->mmu, entryValue, gcvTRUE, entry);
+
+ /* Resume hardware execution. */
+ gcmkVERIFY_OK(gckOS_WriteRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ mmuExceptionAddress + i * 4,
+ *entry
+ ));
+ }
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_DumpGPUState
+**
+** Dump the GPU debug registers.
+**
+** INPUT:
+**
+** gckHARDWARE Harwdare
+** Pointer to an gckHARDWARE object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckHARDWARE_DumpGPUState(
+ IN gckHARDWARE Hardware
+ )
+{
+ static gctCONST_STRING _cmdState[] =
+ {
+ "PAR_IDLE_ST", "PAR_DEC_ST", "PAR_ADR0_ST", "PAR_LOAD0_ST",
+ "PAR_ADR1_ST", "PAR_LOAD1_ST", "PAR_3DADR_ST", "PAR_3DCMD_ST",
+ "PAR_3DCNTL_ST", "PAR_3DIDXCNTL_ST", "PAR_INITREQDMA_ST",
+ "PAR_DRAWIDX_ST", "PAR_DRAW_ST", "PAR_2DRECT0_ST", "PAR_2DRECT1_ST",
+ "PAR_2DDATA0_ST", "PAR_2DDATA1_ST", "PAR_WAITFIFO_ST", "PAR_WAIT_ST",
+ "PAR_LINK_ST", "PAR_END_ST", "PAR_STALL_ST"
+ };
+
+ static gctCONST_STRING _cmdDmaState[] =
+ {
+ "CMD_IDLE_ST", "CMD_START_ST", "CMD_REQ_ST", "CMD_END_ST"
+ };
+
+ static gctCONST_STRING _cmdFetState[] =
+ {
+ "FET_IDLE_ST", "FET_RAMVALID_ST", "FET_VALID_ST"
+ };
+
+ static gctCONST_STRING _reqDmaState[] =
+ {
+ "REQ_IDLE_ST", "REQ_WAITIDX_ST", "REQ_CAL_ST"
+ };
+
+ static gctCONST_STRING _calState[] =
+ {
+ "CAL_IDLE_ST", "CAL_LDADR_ST", "CAL_IDXCALC_ST"
+ };
+
+ static gctCONST_STRING _veReqState[] =
+ {
+ "VER_IDLE_ST", "VER_CKCACHE_ST", "VER_MISS_ST"
+ };
+
+ static gcsiDEBUG_REGISTERS _dbgRegs[] =
+ {
+ { "RA", 0x474, 16, 0x448, 256, 0x1, 0x00 },
+ { "TX", 0x474, 24, 0x44C, 128, 0x1, 0x00 },
+ { "FE", 0x470, 0, 0x450, 256, 0x1, 0x00 },
+ { "PE", 0x470, 16, 0x454, 256, 0x3, 0x00 },
+ { "DE", 0x470, 8, 0x458, 256, 0x1, 0x00 },
+ { "SH", 0x470, 24, 0x45C, 256, 0x1, 0x00 },
+ { "PA", 0x474, 0, 0x460, 256, 0x1, 0x00 },
+ { "SE", 0x474, 8, 0x464, 256, 0x1, 0x00 },
+ { "MC", 0x478, 0, 0x468, 256, 0x3, 0x00 },
+ { "HI", 0x478, 8, 0x46C, 256, 0x1, 0x00 },
+ { "TPG", 0x474, 24, 0x44C, 32, 0x2, 0x80 },
+ { "TFB", 0x474, 24, 0x44C, 32, 0x2, 0xA0 },
+ { "USC", 0x474, 24, 0x44C, 64, 0x2, 0xC0 },
+ { "L2", 0x478, 0, 0x564, 256, 0x1, 0x00 },
+ { "BLT", 0x478, 24, 0x1A4, 256, 0x1, 0x00 }
+ };
+
+ static gctUINT32 _otherRegs[] =
+ {
+ 0x040, 0x044, 0x04C, 0x050, 0x054, 0x058, 0x05C, 0x060,
+ 0x43c, 0x440, 0x444, 0x414, 0x100
+ };
+
+ gceSTATUS status;
+ gckKERNEL kernel = gcvNULL;
+ gctUINT32 idle = 0, axi = 0;
+ gctUINT32 dmaAddress1 = 0, dmaAddress2 = 0;
+ gctUINT32 dmaState1 = 0, dmaState2 = 0;
+ gctUINT32 dmaLow = 0, dmaHigh = 0;
+ gctUINT32 cmdState = 0, cmdDmaState = 0, cmdFetState = 0;
+ gctUINT32 dmaReqState = 0, calState = 0, veReqState = 0;
+ gctUINT i;
+ gctUINT pipe = 0, pixelPipes = 0;
+ gctUINT32 control = 0, oldControl = 0;
+ gckOS os = Hardware->os;
+ gceCORE core = Hardware->core;
+
+ gcmkHEADER_ARG("Hardware=0x%X", Hardware);
+
+ kernel = Hardware->kernel;
+
+ gcmkPRINT_N(12, "GPU[%d](ChipModel=0x%x ChipRevision=0x%x):\n",
+ core,
+ Hardware->identity.chipModel,
+ Hardware->identity.chipRevision);
+
+ pixelPipes = Hardware->identity.pixelPipes
+ ? Hardware->identity.pixelPipes
+ : 1;
+
+ /* Reset register values. */
+ idle = axi =
+ dmaState1 = dmaState2 =
+ dmaAddress1 = dmaAddress2 =
+ dmaLow = dmaHigh = 0;
+
+ /* Verify whether DMA is running. */
+ gcmkONERROR(_VerifyDMA(
+ os, core, &dmaAddress1, &dmaAddress2, &dmaState1, &dmaState2
+ ));
+
+ cmdState = dmaState2 & 0x1F;
+ cmdDmaState = (dmaState2 >> 8) & 0x03;
+ cmdFetState = (dmaState2 >> 10) & 0x03;
+ dmaReqState = (dmaState2 >> 12) & 0x03;
+ calState = (dmaState2 >> 14) & 0x03;
+ veReqState = (dmaState2 >> 16) & 0x03;
+
+ gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x00004, &idle));
+ gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x0000C, &axi));
+ gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x00668, &dmaLow));
+ gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x00668, &dmaLow));
+ gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x0066C, &dmaHigh));
+ gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x0066C, &dmaHigh));
+
+ gcmkPRINT_N(0, "**************************\n");
+ gcmkPRINT_N(0, "*** GPU STATE DUMP ***\n");
+ gcmkPRINT_N(0, "**************************\n");
+
+ gcmkPRINT_N(4, " axi = 0x%08X\n", axi);
+
+ gcmkPRINT_N(4, " idle = 0x%08X\n", idle);
+ if ((idle & 0x00000001) == 0) gcmkPRINT_N(0, " FE not idle\n");
+ if ((idle & 0x00000002) == 0) gcmkPRINT_N(0, " DE not idle\n");
+ if ((idle & 0x00000004) == 0) gcmkPRINT_N(0, " PE not idle\n");
+ if ((idle & 0x00000008) == 0) gcmkPRINT_N(0, " SH not idle\n");
+ if ((idle & 0x00000010) == 0) gcmkPRINT_N(0, " PA not idle\n");
+ if ((idle & 0x00000020) == 0) gcmkPRINT_N(0, " SE not idle\n");
+ if ((idle & 0x00000040) == 0) gcmkPRINT_N(0, " RA not idle\n");
+ if ((idle & 0x00000080) == 0) gcmkPRINT_N(0, " TX not idle\n");
+ if ((idle & 0x00000100) == 0) gcmkPRINT_N(0, " VG not idle\n");
+ if ((idle & 0x00000200) == 0) gcmkPRINT_N(0, " IM not idle\n");
+ if ((idle & 0x00000400) == 0) gcmkPRINT_N(0, " FP not idle\n");
+ if ((idle & 0x00000800) == 0) gcmkPRINT_N(0, " TS not idle\n");
+ if ((idle & 0x00001000) == 0) gcmkPRINT_N(0, " BL not idle\n");
+ if ((idle & 0x00002000) == 0) gcmkPRINT_N(0, " BP not idle\n");
+ if ((idle & 0x00004000) == 0) gcmkPRINT_N(0, " MC not idle\n");
+ if ((idle & 0x80000000) != 0) gcmkPRINT_N(0, " AXI low power mode\n");
+
+ if (
+ (dmaAddress1 == dmaAddress2)
+ && (dmaState1 == dmaState2)
+ )
+ {
+ gcmkPRINT_N(0, " DMA appears to be stuck at this address:\n");
+ gcmkPRINT_N(4, " 0x%08X\n", dmaAddress1);
+ }
+ else
+ {
+ if (dmaAddress1 == dmaAddress2)
+ {
+ gcmkPRINT_N(0, " DMA address is constant, but state is changing:\n");
+ gcmkPRINT_N(4, " 0x%08X\n", dmaState1);
+ gcmkPRINT_N(4, " 0x%08X\n", dmaState2);
+ }
+ else
+ {
+ gcmkPRINT_N(0, " DMA is running; known addresses are:\n");
+ gcmkPRINT_N(4, " 0x%08X\n", dmaAddress1);
+ gcmkPRINT_N(4, " 0x%08X\n", dmaAddress2);
+ }
+ }
+
+ gcmkPRINT_N(4, " dmaLow = 0x%08X\n", dmaLow);
+ gcmkPRINT_N(4, " dmaHigh = 0x%08X\n", dmaHigh);
+ gcmkPRINT_N(4, " dmaState = 0x%08X\n", dmaState2);
+ gcmkPRINT_N(8, " command state = %d (%s)\n", cmdState, _cmdState [cmdState]);
+ gcmkPRINT_N(8, " command DMA state = %d (%s)\n", cmdDmaState, _cmdDmaState[cmdDmaState]);
+ gcmkPRINT_N(8, " command fetch state = %d (%s)\n", cmdFetState, _cmdFetState[cmdFetState]);
+ gcmkPRINT_N(8, " DMA request state = %d (%s)\n", dmaReqState, _reqDmaState[dmaReqState]);
+ gcmkPRINT_N(8, " cal state = %d (%s)\n", calState, _calState [calState]);
+ gcmkPRINT_N(8, " VE request state = %d (%s)\n", veReqState, _veReqState [veReqState]);
+
+ gcmkPRINT_N(0, " Debug registers:\n");
+
+ for (i = 0; i < gcmCOUNTOF(_dbgRegs); i += 1)
+ {
+ gcmkONERROR(_DumpDebugRegisters(os, core, &_dbgRegs[i]));
+ }
+
+ /* Record control. */
+ gckOS_ReadRegisterEx(os, core, 0x0, &oldControl);
+
+ for (pipe = 0; pipe < pixelPipes; pipe++)
+ {
+ gcmkPRINT_N(4, " Other Registers[%d]:\n", pipe);
+
+ /* Switch pipe. */
+ gcmkONERROR(gckOS_ReadRegisterEx(os, core, 0x0, &control));
+ control &= ~(0xF << 20);
+ control |= (pipe << 20);
+ gcmkONERROR(gckOS_WriteRegisterEx(os, core, 0x0, control));
+
+ for (i = 0; i < gcmCOUNTOF(_otherRegs); i += 1)
+ {
+ gctUINT32 read;
+ gcmkONERROR(gckOS_ReadRegisterEx(os, core, _otherRegs[i], &read));
+ gcmkPRINT_N(12, " [0x%04X] 0x%08X\n", _otherRegs[i], read);
+ }
+
+ if (Hardware->mmuVersion)
+ {
+ gcmkPRINT(" MMU status from MC[%d]:", pipe);
+
+ gckHARDWARE_DumpMMUException(Hardware);
+ }
+ }
+
+ /* Restore control. */
+ gcmkONERROR(gckOS_WriteRegisterEx(os, core, 0x0, oldControl));
+
+ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_HALTI0))
+ {
+ /* FE debug register. */
+ gcmkVERIFY_OK(_DumpLinkStack(os, core, &_dbgRegs[2]));
+ }
+
+ _DumpFEStack(os, core, &_dbgRegs[2]);
+
+ gcmkPRINT_N(0, "**************************\n");
+ gcmkPRINT_N(0, "***** SW COUNTERS *****\n");
+ gcmkPRINT_N(0, "**************************\n");
+ gcmkPRINT_N(4, " Execute Count = 0x%08X\n", Hardware->executeCount);
+ gcmkPRINT_N(4, " Execute Addr = 0x%08X\n", Hardware->lastExecuteAddress);
+ gcmkPRINT_N(4, " End Addr = 0x%08X\n", Hardware->lastEnd);
+
+ /* dump stack. */
+ gckOS_DumpCallStack(os);
+
+OnError:
+
+ /* Return the error. */
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+gckHARDWARE_ReadPerformanceRegister(
+ IN gckHARDWARE Hardware,
+ IN gctUINT PerformanceAddress,
+ IN gctUINT IndexAddress,
+ IN gctUINT IndexShift,
+ IN gctUINT Index,
+ OUT gctUINT32_PTR Value
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Hardware=0x%x PerformanceAddress=0x%x IndexAddress=0x%x "
+ "IndexShift=%u Index=%u",
+ Hardware, PerformanceAddress, IndexAddress, IndexShift,
+ Index);
+
+ /* Write the index. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ IndexAddress,
+ Index << IndexShift));
+
+ /* Read the register. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ PerformanceAddress,
+ Value));
+
+ /* Test for reset. */
+ if (Index == 15)
+ {
+ /* Index another register to get out of reset. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, IndexAddress, 0));
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Value=0x%x", *Value);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckHARDWARE_GetFrameInfo(
+ IN gckHARDWARE Hardware,
+ OUT gcsHAL_FRAME_INFO * FrameInfo
+ )
+{
+ gceSTATUS status;
+ gctUINT i, clock;
+ gcsHAL_FRAME_INFO info;
+#if gcdFRAME_DB_RESET
+ gctUINT reset;
+#endif
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Get profile tick. */
+ gcmkONERROR(gckOS_GetProfileTick(&info.ticks));
+
+ /* Read SH counters and reset them. */
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x0045C,
+ 0x00470,
+ 24,
+ 4,
+ &info.shaderCycles));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x0045C,
+ 0x00470,
+ 24,
+ 9,
+ &info.vsInstructionCount));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x0045C,
+ 0x00470,
+ 24,
+ 12,
+ &info.vsTextureCount));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x0045C,
+ 0x00470,
+ 24,
+ 7,
+ &info.psInstructionCount));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x0045C,
+ 0x00470,
+ 24,
+ 14,
+ &info.psTextureCount));
+#if gcdFRAME_DB_RESET
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x0045C,
+ 0x00470,
+ 24,
+ 15,
+ &reset));
+#endif
+
+ /* Read PA counters and reset them. */
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00460,
+ 0x00474,
+ 0,
+ 3,
+ &info.vertexCount));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00460,
+ 0x00474,
+ 0,
+ 4,
+ &info.primitiveCount));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00460,
+ 0x00474,
+ 0,
+ 7,
+ &info.rejectedPrimitives));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00460,
+ 0x00474,
+ 0,
+ 8,
+ &info.culledPrimitives));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00460,
+ 0x00474,
+ 0,
+ 6,
+ &info.clippedPrimitives));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00460,
+ 0x00474,
+ 0,
+ 5,
+ &info.outPrimitives));
+#if gcdFRAME_DB_RESET
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00460,
+ 0x00474,
+ 0,
+ 15,
+ &reset));
+#endif
+
+ /* Read RA counters and reset them. */
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00448,
+ 0x00474,
+ 16,
+ 3,
+ &info.inPrimitives));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00448,
+ 0x00474,
+ 16,
+ 11,
+ &info.culledQuadCount));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00448,
+ 0x00474,
+ 16,
+ 1,
+ &info.totalQuadCount));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00448,
+ 0x00474,
+ 16,
+ 2,
+ &info.quadCount));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00448,
+ 0x00474,
+ 16,
+ 0,
+ &info.totalPixelCount));
+#if gcdFRAME_DB_RESET
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00448,
+ 0x00474,
+ 16,
+ 15,
+ &reset));
+#endif
+
+ /* Read TX counters and reset them. */
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x0044C,
+ 0x00474,
+ 24,
+ 0,
+ &info.bilinearRequests));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x0044C,
+ 0x00474,
+ 24,
+ 1,
+ &info.trilinearRequests));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x0044C,
+ 0x00474,
+ 24,
+ 8,
+ &info.txHitCount));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x0044C,
+ 0x00474,
+ 24,
+ 9,
+ &info.txMissCount));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x0044C,
+ 0x00474,
+ 24,
+ 6,
+ &info.txBytes8));
+#if gcdFRAME_DB_RESET
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x0044C,
+ 0x00474,
+ 24,
+ 15,
+ &reset));
+#endif
+
+ /* Read clock control register. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ &clock));
+
+ /* Walk through all avaiable pixel pipes. */
+ for (i = 0; i < Hardware->identity.pixelPipes; ++i)
+ {
+ /* Select proper pipe. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:20) - (0 ? 23:20) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:20) - (0 ?
+ 23:20) + 1))))))) << (0 ? 23:20))) | (((gctUINT32) ((gctUINT32) (i) & ((gctUINT32) ((((1 ?
+ 23:20) - (0 ? 23:20) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:20) - (0 ?
+ 23:20) + 1))))))) << (0 ? 23:20)))));
+
+ /* Read cycle registers. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00078,
+ &info.cycles[i]));
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0007C,
+ &info.idleCycles[i]));
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00438,
+ &info.mcCycles[i]));
+
+ /* Read bandwidth registers. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0005C,
+ &info.readRequests[i]));
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00040,
+ &info.readBytes8[i]));
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00050,
+ &info.writeRequests[i]));
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00044,
+ &info.writeBytes8[i]));
+
+ /* Read PE counters. */
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00454,
+ 0x00470,
+ 16,
+ 0,
+ &info.colorKilled[i]));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00454,
+ 0x00470,
+ 16,
+ 2,
+ &info.colorDrawn[i]));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00454,
+ 0x00470,
+ 16,
+ 1,
+ &info.depthKilled[i]));
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00454,
+ 0x00470,
+ 16,
+ 3,
+ &info.depthDrawn[i]));
+ }
+
+ /* Zero out remaning reserved counters. */
+ for (; i < 8; ++i)
+ {
+ info.readBytes8[i] = 0;
+ info.writeBytes8[i] = 0;
+ info.cycles[i] = 0;
+ info.idleCycles[i] = 0;
+ info.mcCycles[i] = 0;
+ info.readRequests[i] = 0;
+ info.writeRequests[i] = 0;
+ info.colorKilled[i] = 0;
+ info.colorDrawn[i] = 0;
+ info.depthKilled[i] = 0;
+ info.depthDrawn[i] = 0;
+ }
+
+ /* Reset clock control register. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ clock));
+
+ /* Reset cycle and bandwidth counters. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0003C,
+ 1));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0003C,
+ 0));
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00078,
+ 0));
+
+#if gcdFRAME_DB_RESET
+ /* Reset PE counters. */
+ gcmkONERROR(gckHARDWARE_ReadPerformanceRegister(
+ Hardware,
+ 0x00454,
+ 0x00470,
+ 16,
+ 15,
+ &reset));
+#endif
+
+ /* Copy to user. */
+ gcmkONERROR(gckOS_CopyToUserData(Hardware->os,
+ &info,
+ FrameInfo,
+ gcmSIZEOF(info)));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckHARDWARE_DumpGpuProfile(
+ IN gckHARDWARE Hardware
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+ gctUINT clock, i;
+ gctUINT32 totalRead, totalWrite, read, write;
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Read clock control register. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ &clock));
+
+ totalRead = 0;
+ totalWrite = 0;
+
+ /* Walk through all avaiable pixel pipes. */
+ for (i = 0; i < Hardware->identity.pixelPipes; ++i)
+ {
+ /* Select proper pipe. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:20) - (0 ? 23:20) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:20) - (0 ?
+ 23:20) + 1))))))) << (0 ? 23:20))) | (((gctUINT32) ((gctUINT32) (i) & ((gctUINT32) ((((1 ?
+ 23:20) - (0 ? 23:20) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:20) - (0 ?
+ 23:20) + 1))))))) << (0 ? 23:20)))));
+
+ /* BW */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00040,
+ &read));
+ totalRead += read;
+
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00044,
+ &write));
+ totalWrite += write;
+ }
+
+ gcmkPRINT("==============GPU Profile: read request : %d\n", totalRead);
+ gcmkPRINT("==============GPU Profile: write request: %d\n", totalWrite);
+
+ /* Reset clock control register. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00000,
+ clock));
+ /* Reset counters. */
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x0003C, 1));
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x0003C, 0));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+#if gcdDVFS
+#define READ_FROM_EATER1 0
+
+gceSTATUS
+gckHARDWARE_QueryLoad(
+ IN gckHARDWARE Hardware,
+ OUT gctUINT32 * Load
+ )
+{
+ gctUINT32 debug1;
+ gceSTATUS status;
+ gcmkHEADER_ARG("Hardware=0x%X", Hardware);
+
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(Load != gcvNULL);
+
+ gckOS_AcquireMutex(Hardware->os, Hardware->powerMutex, gcvINFINITE);
+
+ if (Hardware->chipPowerState == gcvPOWER_ON)
+ {
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00110,
+ Load));
+#if READ_FROM_EATER1
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00134,
+ Load));
+#endif
+
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00114,
+ &debug1));
+
+ /* Patch result of 0x110 with result of 0x114. */
+ if ((debug1 & 0xFF) == 1)
+ {
+ *Load &= ~0xFF;
+ *Load |= 1;
+ }
+
+ if (((debug1 & 0xFF00) >> 8) == 1)
+ {
+ *Load &= ~(0xFF << 8);
+ *Load |= 1 << 8;
+ }
+
+ if (((debug1 & 0xFF0000) >> 16) == 1)
+ {
+ *Load &= ~(0xFF << 16);
+ *Load |= 1 << 16;
+ }
+
+ if (((debug1 & 0xFF000000) >> 24) == 1)
+ {
+ *Load &= ~(0xFF << 24);
+ *Load |= 1 << 24;
+ }
+ }
+ else
+ {
+ status = gcvSTATUS_INVALID_REQUEST;
+ }
+
+OnError:
+
+ gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex);
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckHARDWARE_SetDVFSPeroid(
+ IN gckHARDWARE Hardware,
+ OUT gctUINT32 Frequency
+ )
+{
+ gceSTATUS status;
+ gctUINT32 period;
+ gctUINT32 eater;
+
+#if READ_FROM_EATER1
+ gctUINT32 period1;
+ gctUINT32 eater1;
+#endif
+
+ gcmkHEADER_ARG("Hardware=0x%X Frequency=%d", Hardware, Frequency);
+
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ period = 0;
+
+ while((64 << period) < (gcdDVFS_ANAYLSE_WINDOW * Frequency * 1000) )
+ {
+ period++;
+ }
+
+#if READ_FROM_EATER1
+ /*
+ * Peroid = F * 1000 * 1000 / (60 * 16 * 1024);
+ */
+ period1 = Frequency * 6250 / 6114;
+#endif
+
+ gckOS_AcquireMutex(Hardware->os, Hardware->powerMutex, gcvINFINITE);
+
+ if (Hardware->chipPowerState == gcvPOWER_ON)
+ {
+ /* Get current configure. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0010C,
+ &eater));
+
+ /* Change peroid. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0010C,
+ ((((gctUINT32) (eater)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8))) | (((gctUINT32) ((gctUINT32) (period) & ((gctUINT32) ((((1 ? 15:8) - (0 ?
+ 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1))))))) << (0 ?
+ 15:8)))));
+
+#if READ_FROM_EATER1
+ /* Config eater1. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00130,
+ &eater1));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x00130,
+ ((((gctUINT32) (eater1)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:16) - (0 ? 31:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:16) - (0 ?
+ 31:16) + 1))))))) << (0 ? 31:16))) | (((gctUINT32) ((gctUINT32) (period1) & ((gctUINT32) ((((1 ?
+ 31:16) - (0 ? 31:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:16) - (0 ?
+ 31:16) + 1))))))) << (0 ? 31:16)))));
+#endif
+ }
+ else
+ {
+ status = gcvSTATUS_INVALID_REQUEST;
+ }
+
+OnError:
+ gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex);
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckHARDWARE_InitDVFS(
+ IN gckHARDWARE Hardware
+ )
+{
+ gceSTATUS status;
+ gctUINT32 data;
+
+ gcmkHEADER_ARG("Hardware=0x%X", Hardware);
+
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0010C,
+ &data));
+
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16)));
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 18:18) - (0 ? 18:18) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 18:18) - (0 ?
+ 18:18) + 1))))))) << (0 ? 18:18))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 18:18) - (0 ? 18:18) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 18:18) - (0 ?
+ 18:18) + 1))))))) << (0 ? 18:18)));
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:19) - (0 ? 19:19) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 19:19) - (0 ? 19:19) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ? 19:19)));
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:20) - (0 ? 20:20) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 20:20) - (0 ?
+ 20:20) + 1))))))) << (0 ? 20:20))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 20:20) - (0 ? 20:20) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 20:20) - (0 ?
+ 20:20) + 1))))))) << (0 ? 20:20)));
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 23:23) - (0 ? 23:23) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:23) - (0 ?
+ 23:23) + 1))))))) << (0 ? 23:23))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 23:23) - (0 ? 23:23) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:23) - (0 ?
+ 23:23) + 1))))))) << (0 ? 23:23)));
+ data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 22:22) - (0 ? 22:22) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 22:22) - (0 ?
+ 22:22) + 1))))))) << (0 ? 22:22))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 22:22) - (0 ? 22:22) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 22:22) - (0 ?
+ 22:22) + 1))))))) << (0 ? 22:22)));
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "DVFS Configure=0x%X",
+ data);
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os,
+ Hardware->core,
+ 0x0010C,
+ data));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+#endif
+
+/*******************************************************************************
+**
+** gckHARDWARE_PrepareFunctions
+**
+** Generate command buffer snippets which will be used by gckHARDWARE, by which
+** gckHARDWARE can manipulate GPU by FE command without using gckCOMMAND to avoid
+** race condition and deadlock.
+**
+** Notice:
+** 1. Each snippet can only be executed when GPU is idle.
+** 2. Execution is triggered by AHB (0x658)
+** 3. Each snippet followed by END so software can sync with GPU by checking GPU
+** idle
+** 4. It is transparent to gckCOMMAND command buffer.
+**
+** Existing Snippets:
+** 1. MMU Configure
+** For new MMU, after GPU is reset, FE execute this command sequence to enable MMU.
+*/
+gceSTATUS
+gckHARDWARE_PrepareFunctions(
+ gckHARDWARE Hardware
+ )
+{
+ gckOS os;
+ gceSTATUS status;
+ gctUINT32 offset = 0;
+ gctUINT32 endBytes;
+ gctUINT32 flushBytes;
+ gctUINT8_PTR logical;
+ gctUINT32 address;
+ gcsHARDWARE_FUNCTION *function;
+ gceDUMMY_DRAW_TYPE dummyDrawType = gcvDUMMY_DRAW_INVALID;
+
+ gcmkHEADER_ARG("%x", Hardware);
+
+ os = Hardware->os;
+
+ gcmkVERIFY_OK(gckOS_GetPageSize(os, &Hardware->mmuFuncBytes));
+ Hardware->auxFuncBytes = Hardware->mmuFuncBytes;
+
+ gcmkONERROR(gckHARDWARE_End(
+ Hardware,
+ gcvNULL,
+ ~0U,
+ &endBytes
+ ));
+
+ if ((Hardware->mmuVersion > 0) &&
+ Hardware->options.enableMMU &&
+ (Hardware->options.secureMode != gcvSECURE_IN_TA))
+ {
+ gctUINT32 mmuBytes;
+ gctPHYS_ADDR_T physical = 0;
+
+ /* Allocate mmu command buffer within 32bit space */
+ gcmkONERROR(gckOS_AllocateNonPagedMemory(
+ os,
+ gcvFALSE,
+ &Hardware->mmuFuncBytes,
+ &Hardware->mmuFuncPhysical,
+ &Hardware->mmuFuncLogical
+ ));
+
+ gcmkONERROR(gckOS_GetPhysicalAddress(
+ os,
+ Hardware->mmuFuncLogical,
+ &physical
+ ));
+
+ if (physical & 0xFFFFFFFF00000000ULL)
+ {
+ gcmkFATAL("%s(%d): Command buffer physical address (0x%llx) for MMU setup exceeds 32bits",
+ __FUNCTION__, __LINE__, physical);
+ }
+
+ function = &Hardware->functions[gcvHARDWARE_FUNCTION_MMU];
+ function->logical = (gctUINT8_PTR)Hardware->mmuFuncLogical;
+ gcmkSAFECASTPHYSADDRT(function->address, physical);
+
+ gcmkONERROR(gckHARDWARE_SetMMUStates(
+ Hardware,
+ Hardware->kernel->mmu->mtlbLogical,
+ gcvMMU_MODE_4K,
+ Hardware->kernel->mmu->safePageLogical,
+ function->logical,
+ &mmuBytes
+ ));
+
+ function->endAddress = function->address + mmuBytes;
+ function->endLogical = function->logical + mmuBytes;
+
+ gcmkONERROR(gckHARDWARE_End(
+ Hardware,
+ function->endLogical,
+ function->endAddress,
+ &endBytes
+ ));
+
+ function->bytes = mmuBytes + endBytes;
+ }
+
+#if USE_KERNEL_VIRTUAL_BUFFERS
+ if (Hardware->kernel->virtualCommandBuffer)
+ {
+ gcmkONERROR(gckKERNEL_AllocateVirtualCommandBuffer(
+ Hardware->kernel,
+ gcvFALSE,
+ &Hardware->auxFuncBytes,
+ &Hardware->auxFuncPhysical,
+ &Hardware->auxFuncLogical
+ ));
+
+ gcmkONERROR(gckKERNEL_GetGPUAddress(
+ Hardware->kernel,
+ Hardware->auxFuncLogical,
+ gcvFALSE,
+ Hardware->auxFuncPhysical,
+ &Hardware->auxFuncAddress
+ ));
+ }
+ else
+#endif
+ {
+ gctPHYS_ADDR_T physical = 0;
+
+ /* Allocate a command buffer. */
+ gcmkONERROR(gckOS_AllocateNonPagedMemory(
+ os,
+ gcvFALSE,
+ &Hardware->auxFuncBytes,
+ &Hardware->auxFuncPhysical,
+ &Hardware->auxFuncLogical
+ ));
+
+ gcmkONERROR(gckOS_GetPhysicalAddress(
+ os,
+ Hardware->auxFuncLogical,
+ &physical
+ ));
+
+ gcmkSAFECASTPHYSADDRT(Hardware->auxFuncAddress, physical);
+
+ gcmkONERROR(gckMMU_FillFlatMapping(
+ Hardware->kernel->mmu,
+ Hardware->auxFuncAddress,
+ Hardware->auxFuncBytes
+ ));
+ }
+
+ /*
+ ** All cache flush command sequence.
+ */
+ function = &Hardware->functions[gcvHARDWARE_FUNCTION_FLUSH];
+
+ function->logical = logical = (gctUINT8_PTR)Hardware->auxFuncLogical + offset;
+
+ function->address = Hardware->auxFuncAddress + offset;
+
+ /* Get the size of the flush command. */
+ gcmkONERROR(gckHARDWARE_Flush(Hardware, gcvFLUSH_ALL, gcvNULL, &flushBytes));
+
+ /* Append a flush. */
+ gcmkONERROR(gckHARDWARE_Flush(Hardware, gcvFLUSH_ALL, logical, &flushBytes));
+
+ offset += flushBytes;
+
+ logical = (gctUINT8_PTR)Hardware->auxFuncLogical + offset;
+ address = Hardware->auxFuncAddress + offset;
+
+ gcmkONERROR(gckHARDWARE_End(Hardware, logical, address, &endBytes));
+
+#if USE_KERNEL_VIRTUAL_BUFFERS
+ if (Hardware->kernel->virtualCommandBuffer)
+ {
+ gcmkONERROR(gckKERNEL_GetGPUAddress(
+ Hardware->kernel,
+ logical,
+ gcvFALSE,
+ Hardware->auxFuncPhysical,
+ &Hardware->lastEnd
+ ));
+ }
+#endif
+
+ offset += endBytes;
+
+ function->bytes = flushBytes + endBytes;
+
+ function->endAddress = function->address + flushBytes;
+ function->endLogical = function->logical + flushBytes;
+
+ /*
+ ** ASYNC-BLT Engine event command
+ */
+ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_ASYNC_BLIT))
+ {
+ gctUINT8 i;
+ gctUINT32 eventBytes;
+
+ function = &Hardware->functions[gcvHARDWARE_FUNCTION_BLT_EVENT];
+
+ function->logical = logical = (gctUINT8_PTR)Hardware->auxFuncLogical + offset;
+ function->address = Hardware->auxFuncAddress + offset;
+
+ gcmkONERROR(gckHARDWARE_Event(Hardware, gcvNULL, 0, gcvKERNEL_BLT, &eventBytes));
+
+ for (i = 0; i < 29; i++)
+ {
+ gcmkONERROR(gckHARDWARE_Event(
+ Hardware,
+ logical + i * eventBytes,
+ i,
+ gcvKERNEL_BLT,
+ &eventBytes
+ ));
+
+ offset += eventBytes;
+ }
+
+ function->bytes = eventBytes * 29;
+ }
+
+ /************************************************************************************
+ * Dummy draw.
+ */
+ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_FE_NEED_DUMMYDRAW))
+ {
+ dummyDrawType = gcvDUMMY_DRAW_GC400;
+ }
+
+ if (!gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_USC_DEFER_FILL_FIX) &&
+ gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_USC))
+ {
+ dummyDrawType = gcvDUMMY_DRAW_V60;
+ }
+
+ if (dummyDrawType != gcvDUMMY_DRAW_INVALID)
+ {
+ gctUINT32 dummyDrawBytes;
+
+ function = &Hardware->functions[gcvHARDWARE_FUNCTION_DUMMY_DRAW];
+
+ function->logical = logical = (gctUINT8_PTR)Hardware->auxFuncLogical + offset;
+ function->address = Hardware->auxFuncAddress + offset;
+
+ /* Append a dummy draw. */
+ gcmkONERROR(gckHARDWARE_DummyDraw(Hardware, logical, function->address, dummyDrawType, &dummyDrawBytes));
+
+ offset += dummyDrawBytes;
+
+ logical += dummyDrawBytes;
+ address = function->address + dummyDrawBytes;
+
+ gcmkONERROR(gckHARDWARE_End(Hardware, logical, address, &endBytes));
+
+ offset += endBytes;
+
+ function->endAddress = function->address + dummyDrawBytes;
+ function->endLogical = function->logical + dummyDrawBytes;
+
+ function->bytes = dummyDrawBytes + endBytes;
+ }
+ gcmkASSERT(offset < Hardware->auxFuncBytes)
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckHARDWARE_DestroyFunctions(
+ gckHARDWARE Hardware
+ )
+{
+ gcmkHEADER_ARG("%x", Hardware);
+
+ if (Hardware->auxFuncPhysical)
+ {
+#if USE_KERNEL_VIRTUAL_BUFFERS
+ if (Hardware->kernel->virtualCommandBuffer)
+ {
+ gcmkVERIFY_OK(gckKERNEL_FreeVirtualMemory(
+ Hardware->auxFuncPhysical,
+ Hardware->auxFuncLogical,
+ gcvFALSE
+ ));
+ }
+ else
+#endif
+ {
+ gcmkVERIFY_OK(gckOS_FreeNonPagedMemory(
+ Hardware->os,
+ Hardware->auxFuncBytes,
+ Hardware->auxFuncPhysical,
+ Hardware->auxFuncLogical
+ ));
+ }
+ }
+
+ if (Hardware->mmuFuncPhysical)
+ {
+ gcmkVERIFY_OK(gckOS_FreeNonPagedMemory(
+ Hardware->os,
+ Hardware->mmuFuncBytes,
+ Hardware->mmuFuncPhysical,
+ Hardware->mmuFuncLogical
+ ));
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHARDWARE_ExecuteFunctions(
+ IN gckHARDWARE Hardware,
+ IN gceHARDWARE_FUNCTION Function
+ )
+{
+ gceSTATUS status;
+ gctUINT32 idle;
+ gctUINT32 timer = 0, delay = 1;
+ gcsHARDWARE_FUNCTION * function = &Hardware->functions[Function];
+ gctUINT32 address;
+
+#if USE_KERNEL_VIRTUAL_BUFFERS
+ if (Hardware->kernel->virtualCommandBuffer)
+ {
+ address = function->address;
+ }
+ else
+#endif
+ {
+ address = function->address - Hardware->baseAddress;
+ }
+
+ /* Execute prepared command sequence. */
+ gcmkONERROR(gckHARDWARE_Execute(
+ Hardware,
+ address,
+ function->bytes
+ ));
+
+#if gcdLINK_QUEUE_SIZE
+ {
+ gcuQUEUEDATA data;
+
+ gcmkVERIFY_OK(gckOS_GetProcessID(&data.linkData.pid));
+
+ data.linkData.start = address;
+ data.linkData.end = address + function->bytes;
+ data.linkData.linkLow = 0;
+ data.linkData.linkHigh = 0;
+
+ gckQUEUE_Enqueue(&Hardware->linkQueue, &data);
+ }
+#endif
+
+ gcmkDUMPCOMMAND(
+ Hardware->os,
+ function->logical,
+ function->bytes,
+ gcvDUMP_BUFFER_KERNEL,
+ gcvTRUE
+ );
+
+#if gcdDUMP_COMMAND
+ gcmkPRINT("@[kernel.execute]");
+#endif
+
+ /* Wait until GPU idle. */
+ do
+ {
+ gckOS_Delay(Hardware->os, delay);
+
+ gcmkONERROR(gckOS_ReadRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x00004,
+ &idle));
+
+ timer += delay;
+ delay *= 2;
+
+#if gcdGPU_TIMEOUT
+ if (timer >= Hardware->kernel->timeOut)
+ {
+ gckHARDWARE_DumpGPUState(Hardware);
+ gckCOMMAND_DumpExecutingBuffer(Hardware->kernel->command);
+
+ /* Even if hardware is not reset correctly, let software
+ ** continue to avoid software stuck. Software will timeout again
+ ** and try to recover GPU in next timeout.
+ */
+ gcmkONERROR(gcvSTATUS_DEVICE);
+ }
+#endif
+ }
+ while (!_IsGPUIdle(idle));
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+gceSTATUS
+gckHARDWARE_AddressInHardwareFuncions(
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 Address,
+ OUT gctPOINTER *Pointer
+ )
+{
+ if (Address >= Hardware->auxFuncAddress && Address <= Hardware->auxFuncAddress - 1 + Hardware->auxFuncBytes)
+ {
+ *Pointer = (gctUINT8_PTR)Hardware->auxFuncLogical
+ + (Address - Hardware->auxFuncAddress)
+ ;
+
+ return gcvSTATUS_OK;
+ }
+
+ return gcvSTATUS_NOT_FOUND;
+}
+
+gceSTATUS
+gckHARDWARE_QueryStateTimer(
+ IN gckHARDWARE Hardware,
+ OUT gctUINT64_PTR Start,
+ OUT gctUINT64_PTR End,
+ OUT gctUINT64_PTR On,
+ OUT gctUINT64_PTR Off,
+ OUT gctUINT64_PTR Idle,
+ OUT gctUINT64_PTR Suspend
+ )
+{
+ gckOS_AcquireMutex(Hardware->os, Hardware->powerMutex, gcvINFINITE);
+
+ gckSTATETIMER_Query(
+ &Hardware->powerStateTimer, Hardware->chipPowerState, Start, End, On, Off, Idle, Suspend);
+
+ gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex);
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHARDWARE_WaitFence(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctUINT64 FenceData,
+ IN gctUINT32 FenceAddress,
+ OUT gctUINT32 *Bytes
+ )
+{
+ gctUINT32_PTR logical = (gctUINT32_PTR)Logical;
+
+ gctUINT32 dataLow = (gctUINT32)FenceData;
+ gctUINT32 dataHigh = (gctUINT32)(FenceData >> 32);
+
+ if (logical)
+ {
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x01FD) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *logical++
+ = dataHigh;
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x01FA) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *logical++
+ = dataLow;
+
+ *logical++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x0F & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (Hardware->waitCount) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:16) - (0 ? 17:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:16) - (0 ?
+ 17:16) + 1))))))) << (0 ? 17:16))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ?
+ 17:16) - (0 ? 17:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:16) - (0 ?
+ 17:16) + 1))))))) << (0 ? 17:16)));
+
+ *logical++
+ = FenceAddress;
+ }
+ else
+ {
+ *Bytes = 6 * gcmSIZEOF(gctUINT32);
+ }
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHARDWARE_UpdateContextID(
+ IN gckHARDWARE Hardware
+ )
+{
+ static gcsiDEBUG_REGISTERS fe = { "FE", 0x470, 0, 0x450, 256, 0x1, 0x00 };
+ gckOS os = Hardware->os;
+ gceCORE core = Hardware->core;
+ gctUINT32 contextIDLow, contextIDHigh;
+ gceSTATUS status;
+
+ gcmkONERROR(gckOS_WriteRegisterEx(os, core, fe.index, 0x53 << fe.shift));
+ gcmkONERROR(gckOS_ReadRegisterEx(os, core, fe.data, &contextIDLow));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(os, core, fe.index, 0x54 << fe.shift));
+ gcmkONERROR(gckOS_ReadRegisterEx(os, core, fe.data, &contextIDHigh));
+
+ Hardware->contextID = ((gctUINT64)contextIDHigh << 32) + contextIDLow;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+gceSTATUS
+gckFE_Initialize(
+ IN gckHARDWARE Hardware,
+ OUT gckFE FE
+ )
+{
+ gceSTATUS status;
+ gctUINT32 data;
+
+ gcmkHEADER();
+
+ gckOS_ZeroMemory(FE, gcmSIZEOF(gcsFE));
+
+ gcmkVERIFY_OK(gckOS_ReadRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x007E4,
+ &data
+ ));
+
+ gcmkONERROR(gckOS_AtomConstruct(Hardware->os, &FE->freeDscriptors));
+
+ data = (((((gctUINT32) (data)) >> (0 ? 6:0)) & ((gctUINT32) ((((1 ? 6:0) - (0 ? 6:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:0) - (0 ? 6:0) + 1)))))) );
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, _GC_OBJ_ZONE, "free descriptor=%d", data);
+
+ gcmkONERROR(gckOS_AtomSet(Hardware->os, FE->freeDscriptors, data));
+
+ /* Enable interrupts. */
+ gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x000D8, ~0U);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+
+ if (FE->freeDscriptors)
+ {
+ gckOS_AtomDestroy(Hardware->os, FE->freeDscriptors);
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+void
+gckFE_UpdateAvaiable(
+ IN gckHARDWARE Hardware,
+ OUT gckFE FE
+ )
+{
+ gceSTATUS status;
+ gctUINT32 data;
+ gctINT32 oldValue;
+
+ status = gckOS_ReadRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x007E4,
+ &data
+ );
+
+ if (gcmIS_SUCCESS(status))
+ {
+ data = (((((gctUINT32) (data)) >> (0 ? 6:0)) & ((gctUINT32) ((((1 ? 6:0) - (0 ? 6:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:0) - (0 ? 6:0) + 1)))))) );
+
+ while (data--)
+ {
+ gckOS_AtomIncrement(Hardware->os, FE->freeDscriptors, &oldValue);
+ }
+ }
+}
+
+gceSTATUS
+gckFE_ReserveSlot(
+ IN gckHARDWARE Hardware,
+ IN gckFE FE,
+ OUT gctBOOL * Available
+ )
+{
+ gctINT32 oldValue;
+
+ gckOS_AtomDecrement(Hardware->os, FE->freeDscriptors, &oldValue);
+
+ if (oldValue > 0)
+ {
+ /* Get one slot. */
+ *Available = gcvTRUE;
+ }
+ else
+ {
+ /* No available slot, restore decreased one.*/
+ gckOS_AtomIncrement(Hardware->os, FE->freeDscriptors, &oldValue);
+ *Available = gcvFALSE;
+ }
+
+ return gcvSTATUS_OK;
+}
+
+void
+gckFE_Execute(
+ IN gckHARDWARE Hardware,
+ IN gckFE FE,
+ IN gcsFEDescriptor * Desc
+ )
+{
+ gckOS_WriteRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x007DC,
+ Desc->start
+ );
+
+ gckOS_MemoryBarrier(
+ Hardware->os,
+ gcvNULL
+ );
+
+ gckOS_WriteRegisterEx(
+ Hardware->os,
+ Hardware->core,
+ 0x007E0,
+ Desc->end
+ );
+}
+
+gceSTATUS
+gckHARDWARE_DummyDraw(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Address,
+ IN gceDUMMY_DRAW_TYPE DummyDrawType,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gctUINT32 dummyDraw_gc400[] = {
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0193) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ 0x000000,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0194) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ 0,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0180) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ?
+ 3:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ?
+ 3:0))) | (((gctUINT32) (0x8 & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 13:12) - (0 ?
+ 13:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 13:12) - (0 ? 13:12) + 1))))))) << (0 ?
+ 13:12))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ? 13:12) - (0 ?
+ 13:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 13:12) - (0 ? 13:12) + 1))))))) << (0 ?
+ 13:12)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ?
+ 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 23:16) - (0 ?
+ 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ?
+ 23:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:24) - (0 ?
+ 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))) << (0 ?
+ 31:24))) | (((gctUINT32) ((gctUINT32) (4 * gcmSIZEOF(float)) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1))))))) << (0 ? 31:24)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:7) - (0 ?
+ 7:7) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ?
+ 7:7))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E05) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:0) - (0 ?
+ 1:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0202) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:0) - (0 ?
+ 5:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ?
+ 5:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 5:0) - (0 ?
+ 5:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ?
+ 5:0))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0208) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:0) - (0 ?
+ 5:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ?
+ 5:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 5:0) - (0 ?
+ 5:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ?
+ 5:0))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0201) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:0) - (0 ?
+ 5:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ?
+ 5:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 5:0) - (0 ?
+ 5:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ?
+ 5:0))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0204) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:0) - (0 ?
+ 5:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ?
+ 5:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 5:0) - (0 ?
+ 5:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:0) - (0 ? 5:0) + 1))))))) << (0 ?
+ 5:0))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x1000) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ 0x0, 0x0, 0x0, 0x0,
+ 0xDEADDEAD,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0203) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:0) - (0 ?
+ 6:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:0) - (0 ? 6:0) + 1))))))) << (0 ?
+ 6:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 6:0) - (0 ?
+ 6:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:0) - (0 ? 6:0) + 1))))))) << (0 ?
+ 6:0))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x020E) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ 0,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0200) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ 1,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x020C) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ 0x000F003F,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x028C) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ?
+ 11:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ?
+ 11:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 11:8) - (0 ?
+ 11:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ?
+ 11:8))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0500) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:0) - (0 ?
+ 1:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x028D) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 13:12) - (0 ?
+ 13:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 13:12) - (0 ? 13:12) + 1))))))) << (0 ?
+ 13:12))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ? 13:12) - (0 ? 13:12) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 13:12) - (0 ? 13:12) + 1))))))) << (0 ? 13:12)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:8) - (0 ?
+ 9:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:8) - (0 ? 9:8) + 1))))))) << (0 ?
+ 9:8))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 9:8) - (0 ? 9:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:8) - (0 ? 9:8) + 1))))))) << (0 ? 9:8)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 17:16) - (0 ?
+ 17:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:16) - (0 ? 17:16) + 1))))))) << (0 ?
+ 17:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 17:16) - (0 ? 17:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 17:16) - (0 ? 17:16) + 1))))))) << (0 ? 17:16))),
+
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0300) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ 0,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0301) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ 0,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0302) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ 0,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0303) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ 0,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0289) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ?
+ 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ?
+ 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ?
+ 3:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ?
+ 3:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x05 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ?
+ 3:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ?
+ 3:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:0) - (0 ?
+ 23:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:0) - (0 ? 23:0) + 1))))))) << (0 ?
+ 23:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 23:0) - (0 ?
+ 23:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:0) - (0 ? 23:0) + 1))))))) << (0 ?
+ 23:0))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:0) - (0 ?
+ 23:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:0) - (0 ? 23:0) + 1))))))) << (0 ?
+ 23:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 23:0) - (0 ?
+ 23:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:0) - (0 ? 23:0) + 1))))))) << (0 ?
+ 23:0))),
+ };
+
+ gctUINT32 dummyDraw_v60[] = {
+
+ /* Semaphore from FE to PE. */
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ?
+ 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))),
+
+ /* Stall from FE to PE. */
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ?
+ 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x021A) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (0x0) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E06) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:0) - (0 ?
+ 1:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) ((gctUINT32) (0x0) & ((gctUINT32) ((((1 ? 1:0) - (0 ?
+ 1:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ?
+ 1:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 14:12) - (0 ? 14:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 14:12) - (0 ?
+ 14:12) + 1))))))) << (0 ? 14:12))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 14:12) - (0 ? 14:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 14:12) - (0 ?
+ 14:12) + 1))))))) << (0 ? 14:12)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 17:16) - (0 ? 17:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:16) - (0 ?
+ 17:16) + 1))))))) << (0 ? 17:16))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 17:16) - (0 ? 17:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:16) - (0 ?
+ 17:16) + 1))))))) << (0 ? 17:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 7:4) - (0 ? 7:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:4) - (0 ? 7:4) + 1))))))) << (0 ?
+ 7:4))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 7:4) - (0 ?
+ 7:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:4) - (0 ? 7:4) + 1))))))) << (0 ?
+ 7:4))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0401) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ 0x0,
+ 0x2,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ (gctUINT32)~0x0,
+
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x020C) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ 0xffffffff,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E07) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ 2,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E08) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ 2,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0420) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:0) - (0 ?
+ 2:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 2:0) - (0 ?
+ 2:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ?
+ 2:0))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0424) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ 1,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0403) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ 3,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E21) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:0) - (0 ?
+ 2:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ?
+ 2:0))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ? 2:0) - (0 ? 2:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:0) - (0 ? 2:0) + 1))))))) << (0 ? 2:0))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x040A) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ 0,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x2000) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1 << 2) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ 0x07801033,0x3fc00900,0x00000040,0x00390008,
+ (gctUINT32)~0,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x021F) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ 0x0,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0240) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:0) - (0 ?
+ 1:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:4) - (0 ? 6:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:4) - (0 ? 6:4) + 1))))))) << (0 ?
+ 6:4))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 6:4) - (0 ? 6:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:4) - (0 ? 6:4) + 1))))))) << (0 ? 6:4)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:8) - (0 ? 8:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ?
+ 8:8))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 8:8) - (0 ? 8:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ? 8:8)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 26:24) - (0 ? 26:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 26:24) - (0 ?
+ 26:24) + 1))))))) << (0 ? 26:24))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ?
+ 26:24) - (0 ? 26:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 26:24) - (0 ?
+ 26:24) + 1))))))) << (0 ? 26:24))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0241) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (31) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:16) - (0 ? 31:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:16) - (0 ?
+ 31:16) + 1))))))) << (0 ? 31:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 31:16) - (0 ? 31:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:16) - (0 ?
+ 31:16) + 1))))))) << (0 ? 31:16))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0244) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:0) - (0 ?
+ 9:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:0) - (0 ? 9:0) + 1))))))) << (0 ?
+ 9:0))) | (((gctUINT32) ((gctUINT32) (31) & ((gctUINT32) ((((1 ? 9:0) - (0 ?
+ 9:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:0) - (0 ? 9:0) + 1))))))) << (0 ?
+ 9:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:16) - (0 ? 31:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:16) - (0 ?
+ 31:16) + 1))))))) << (0 ? 31:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 31:16) - (0 ? 31:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:16) - (0 ?
+ 31:16) + 1))))))) << (0 ? 31:16))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0247) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+
+ (32+(4*(((gcsFEATURE_DATABASE *)Hardware->featureDatabase)->NumShaderCores)-1))/(4*(((gcsFEATURE_DATABASE *)Hardware->featureDatabase)->NumShaderCores)),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0248) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ 1,
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ?
+ 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))),
+
+ /* Semaphore from FE to PE. */
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ?
+ 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))),
+
+ /* Stall from FE to PE. */
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))),
+
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ?
+ 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))),
+
+ /* Invalidate I cache.*/
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x022C) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))),
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ? 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ?
+ 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ? 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 2:2) - (0 ?
+ 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ? 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 3:3) - (0 ?
+ 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ? 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 4:4) - (0 ?
+ 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))),
+ };
+
+ gctUINT32 bytes = 0;
+ gctUINT32_PTR dummyDraw = gcvNULL;
+
+
+ switch(DummyDrawType)
+ {
+ case gcvDUMMY_DRAW_GC400:
+ dummyDraw = dummyDraw_gc400;
+ bytes = gcmSIZEOF(dummyDraw_gc400);
+ *(dummyDraw + 1) = Address;
+ break;
+ case gcvDUMMY_DRAW_V60:
+ dummyDraw = dummyDraw_v60;
+ bytes = gcmSIZEOF(dummyDraw_v60);
+ break;
+ default:
+ /* other chip no need dummy draw.*/
+ gcmkASSERT(0);
+ break;
+ };
+
+ if (Logical != gcvNULL)
+ {
+ gckOS_MemCopy(Logical, dummyDraw, bytes);
+ }
+
+ *Bytes = bytes;
+
+ return gcvSTATUS_OK;
+}
+
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware.h b/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware.h
new file mode 100644
index 000000000000..5dd2c251c780
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_hardware.h
@@ -0,0 +1,350 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_hardware_h_
+#define __gc_hal_kernel_hardware_h_
+
+#if gcdENABLE_VG
+#include "gc_hal_kernel_hardware_vg.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ gcvHARDWARE_FUNCTION_MMU,
+ gcvHARDWARE_FUNCTION_FLUSH,
+
+ /* BLT engine command sequence. */
+ gcvHARDWARE_FUNCTION_BLT_EVENT,
+ gcvHARDWARE_FUNCTION_DUMMY_DRAW,
+ gcvHARDWARE_FUNCTION_NUM,
+}
+gceHARDWARE_FUNCTION;
+
+
+typedef struct _gcsHARWARE_FUNCTION
+{
+ /* Entry of the function. */
+ gctUINT32 address;
+
+ /* CPU address of the function. */
+ gctUINT8_PTR logical;
+
+ /* Bytes of the function. */
+ gctUINT32 bytes;
+
+ /* Hardware address of END in this function. */
+ gctUINT32 endAddress;
+
+ /* Logical of END in this function. */
+ gctUINT8_PTR endLogical;
+}
+gcsHARDWARE_FUNCTION;
+
+typedef struct _gcsSTATETIMER
+{
+ gctUINT64 start;
+ gctUINT64 recent;
+
+ /* Elapse of each power state. */
+ gctUINT64 elapse[4];
+}
+gcsSTATETIMER;
+
+typedef struct _gcsHARDWARE_SIGNATURE
+{
+ /* Chip model. */
+ gceCHIPMODEL chipModel;
+
+ /* Revision value.*/
+ gctUINT32 chipRevision;
+
+ /* Supported feature fields. */
+ gctUINT32 chipFeatures;
+
+ /* Supported minor feature fields. */
+ gctUINT32 chipMinorFeatures;
+
+ /* Supported minor feature 1 fields. */
+ gctUINT32 chipMinorFeatures1;
+
+ /* Supported minor feature 2 fields. */
+ gctUINT32 chipMinorFeatures2;
+}
+gcsHARDWARE_SIGNATURE;
+
+typedef struct _gcsMMU_TABLE_ARRAY_ENTRY
+{
+ gctUINT32 low;
+ gctUINT32 high;
+}
+gcsMMU_TABLE_ARRAY_ENTRY;
+
+typedef struct _gcsHARDWARE_PAGETABLE_ARRAY
+{
+ /* Number of entries in page table array. */
+ gctUINT num;
+
+ /* Size in bytes of array. */
+ gctSIZE_T size;
+
+ /* Physical address of array. */
+ gctPHYS_ADDR_T address;
+
+ /* Memory descriptor. */
+ gctPHYS_ADDR physical;
+
+ /* Logical address of array. */
+ gctPOINTER logical;
+}
+gcsHARDWARE_PAGETABLE_ARRAY;
+
+/* gckHARDWARE object. */
+struct _gckHARDWARE
+{
+ /* Object. */
+ gcsOBJECT object;
+
+ /* Pointer to gctKERNEL object. */
+ gckKERNEL kernel;
+
+ /* Pointer to gctOS object. */
+ gckOS os;
+
+ /* Core */
+ gceCORE core;
+
+ /* Chip characteristics. */
+ gcsHAL_QUERY_CHIP_IDENTITY identity;
+ gcsHAL_QUERY_CHIP_OPTIONS options;
+ gctUINT32 powerBaseAddress;
+ gctBOOL extraEventStates;
+
+ /* Big endian */
+ gctBOOL bigEndian;
+
+ /* Base address. */
+ gctUINT32 baseAddress;
+
+ /* Chip status */
+ gctPOINTER powerMutex;
+ gctUINT32 powerProcess;
+ gctUINT32 powerThread;
+ gceCHIPPOWERSTATE chipPowerState;
+ gctUINT32 lastWaitLink;
+ gctUINT32 lastEnd;
+ gctBOOL clockState;
+ gctBOOL powerState;
+ gctPOINTER globalSemaphore;
+
+ gctUINT32 mmuVersion;
+
+ /* Type */
+ gceHARDWARE_TYPE type;
+
+#if gcdPOWEROFF_TIMEOUT
+ gctUINT32 powerOffTime;
+ gctUINT32 powerOffTimeout;
+ gctPOINTER powerOffTimer;
+#endif
+
+#if gcdENABLE_FSCALE_VAL_ADJUST
+ gctUINT32 powerOnFscaleVal;
+#endif
+ gctPOINTER pageTableDirty[gcvENGINE_GPU_ENGINE_COUNT];
+
+#if gcdLINK_QUEUE_SIZE
+ struct _gckQUEUE linkQueue;
+#endif
+ gctBOOL stallFEPrefetch;
+
+ gctUINT32 minFscaleValue;
+ gctUINT waitCount;
+
+ gctPOINTER pendingEvent;
+
+ /* Function used by gckHARDWARE. */
+ gctPHYS_ADDR mmuFuncPhysical;
+ gctPOINTER mmuFuncLogical;
+ gctSIZE_T mmuFuncBytes;
+
+ gctPHYS_ADDR auxFuncPhysical;
+ gctPOINTER auxFuncLogical;
+ gctUINT32 auxFuncAddress;
+ gctSIZE_T auxFuncBytes;
+
+ gcsHARDWARE_FUNCTION functions[gcvHARDWARE_FUNCTION_NUM];
+
+ gcsSTATETIMER powerStateTimer;
+ gctUINT32 executeCount;
+ gctUINT32 lastExecuteAddress;
+
+ /* Head for hardware list in gckMMU. */
+ gcsLISTHEAD mmuHead;
+
+ gctPOINTER featureDatabase;
+ gctBOOL hasAsyncFe;
+
+ gcsHARDWARE_SIGNATURE signature;
+
+ gctUINT32 maxOutstandingReads;
+
+ gcsHARDWARE_PAGETABLE_ARRAY pagetableArray;
+
+ gctUINT64 contextID;
+};
+
+typedef struct _gcsFEDescriptor
+{
+ gctUINT32 start;
+ gctUINT32 end;
+}
+gcsFEDescriptor;
+
+typedef struct _gcsFE * gckFE;
+typedef struct _gcsFE
+{
+ gckOS os;
+
+ /* Number of free descriptors. */
+ gctPOINTER freeDscriptors;
+}
+gcsFE;
+
+gceSTATUS
+gckFE_Initialize(
+ IN gckHARDWARE Hardware,
+ OUT gckFE FE
+ );
+
+gceSTATUS
+gckFE_ReserveSlot(
+ IN gckHARDWARE Hardware,
+ IN gckFE FE,
+ OUT gctBOOL * Available
+ );
+
+void
+gckFE_UpdateAvaiable(
+ IN gckHARDWARE Hardware,
+ OUT gckFE FE
+ );
+
+void
+gckFE_Execute(
+ IN gckHARDWARE Hardware,
+ IN gckFE FE,
+ IN gcsFEDescriptor * Desc
+ );
+
+gceSTATUS
+gckHARDWARE_GetBaseAddress(
+ IN gckHARDWARE Hardware,
+ OUT gctUINT32_PTR BaseAddress
+ );
+
+gceSTATUS
+gckHARDWARE_NeedBaseAddress(
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 State,
+ OUT gctBOOL_PTR NeedBase
+ );
+
+gceSTATUS
+gckHARDWARE_GetFrameInfo(
+ IN gckHARDWARE Hardware,
+ OUT gcsHAL_FRAME_INFO * FrameInfo
+ );
+
+gceSTATUS
+gckHARDWARE_DumpGpuProfile(
+ IN gckHARDWARE Hardware
+ );
+
+gceSTATUS
+gckHARDWARE_HandleFault(
+ IN gckHARDWARE Hardware
+ );
+
+gceSTATUS
+gckHARDWARE_ExecuteFunctions(
+ IN gckHARDWARE Hardware,
+ IN gceHARDWARE_FUNCTION Function
+ );
+
+gceSTATUS
+gckHARDWARE_DummyDraw(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Address,
+ IN gceDUMMY_DRAW_TYPE DummyDrawType,
+ IN OUT gctUINT32 * Bytes
+ );
+
+#define gcmkWRITE_MEMORY(logical, data) \
+ do { \
+ gcmkVERIFY_OK(gckOS_WriteMemory(os, logical, data)); \
+ logical++; \
+ }\
+ while (0) ; \
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_kernel_hardware_h_ */
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_recorder.c b/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_recorder.c
new file mode 100644
index 000000000000..b6c2ce05cb15
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/arch/gc_hal_kernel_recorder.c
@@ -0,0 +1,728 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_context.h"
+
+/*
+ * -----------------------
+ * HARDWARE STATE RECORDER
+ * -----------------------
+ *
+ * State mirror buffer is used to 'mirror' hardware states since hardware
+ * states can't be dumpped. It is a context buffer which stores 'global'
+ * context.
+ *
+ * For each commit, state recorder
+ * 1) Records context buffer (if there is) and command buffers in this commit.
+ * 2) Parse those buffers to estimate the state changed.
+ * 3) Stores result to a mirror buffer.
+ *
+ * == Commit 0 ====================================================================
+ *
+ * Context Buffer 0
+ *
+ * Command Buffer 0
+ *
+ * Mirror Buffer 0 <- Context Buffer 0 + Command Buffer 0
+ *
+ * == Commit 1 ====================================================================
+ *
+ * Command Buffer 1
+ *
+ * Mirror Buffer 1 <- Command buffer 1 + Mirror Buffer 0
+ *
+ * == Commit 2 ====================================================================
+ *
+ * Context Buffer 2 (optional)
+ *
+ * Command Buffer 2
+ *
+ * Mirror Buffer 2 <- Command buffer 2 + Context Buffer 2 + Mirror Buffer 1
+ *
+ * == Commit N ====================================================================
+ *
+ * For Commit N, these buffers are needed to reproduce hardware's behavior in
+ * this commit.
+ *
+ * Mirror Buffer [N - 1] : State Mirror accumlated by past commits,
+ * which is used to restore hardware state.
+ * Context Buffer [N] :
+ * Command Buffer [N] : Command buffer executed by hardware in this commit.
+ *
+ * If sequence of states programming matters, hardware's behavior can't be reproduced,
+ * but the state values stored in mirror buffer are assuring.
+ */
+
+/* Queue size. */
+#define gcdNUM_RECORDS 6
+
+typedef struct _gcsPARSER_HANDLER * gckPARSER_HANDLER;
+
+typedef void
+(*HandlerFunction)(
+ IN gckPARSER_HANDLER Handler,
+ IN gctUINT32 Addr,
+ IN gctUINT32 Data
+ );
+
+typedef struct _gcsPARSER_HANDLER
+{
+ gctUINT32 type;
+ gctUINT32 cmd;
+ gctPOINTER private;
+ HandlerFunction function;
+}
+gcsPARSER_HANDLER;
+
+typedef struct _gcsPARSER * gckPARSER;
+typedef struct _gcsPARSER
+{
+ gctUINT8_PTR currentCmdBufferAddr;
+
+ /* Current command. */
+ gctUINT32 lo;
+ gctUINT32 hi;
+
+ gctUINT8 cmdOpcode;
+ gctUINT16 cmdAddr;
+ gctUINT32 cmdSize;
+ gctUINT32 cmdRectCount;
+ gctUINT8 skip;
+ gctUINT32 skipCount;
+
+ gctBOOL allow;
+ gctBOOL stop;
+
+ /* Callback used by parser to handle a command. */
+ gckPARSER_HANDLER commandHandler;
+}
+gcsPARSER;
+
+typedef struct _gcsMIRROR
+{
+ gctUINT32_PTR logical[gcdNUM_RECORDS];
+ gctUINT32 bytes;
+ gcsSTATE_MAP_PTR map;
+ gctSIZE_T maxState;
+}
+gcsMIRROR;
+
+typedef struct _gcsDELTA
+{
+ gctUINT64 commitStamp;
+ gctUINT32_PTR command;
+ gctUINT32 commandBytes;
+ gctUINT32_PTR context;
+ gctUINT32 contextBytes;
+}
+gcsDELTA;
+
+typedef struct _gcsRECORDER
+{
+ gckOS os;
+ gcsMIRROR mirror;
+ gcsDELTA deltas[gcdNUM_RECORDS];
+
+ /* Index of current record. */
+ gctUINT index;
+
+ /* Number of records. */
+ gctUINT num;
+
+ /* Plugin used by gckPARSER. */
+ gcsPARSER_HANDLER recorderHandler;
+ gckPARSER parser;
+}
+gcsRECORDER;
+
+
+/******************************************************************************\
+***************************** Command Buffer Parser ****************************
+\******************************************************************************/
+
+/*
+** Command buffer parser checks command buffer in FE's view to make sure there
+** is no format error.
+**
+** Parser provide a callback mechnisam, so plug-in can be added to implement
+** other functions.
+*/
+
+static void
+_HandleLoadState(
+ IN OUT gckPARSER Parser
+ )
+{
+ gctUINT i;
+ gctUINT32_PTR data = (gctUINT32_PTR)Parser->currentCmdBufferAddr;
+ gctUINT32 cmdAddr = Parser->cmdAddr;
+
+ if (Parser->commandHandler == gcvNULL
+ || Parser->commandHandler->cmd != 0x01
+ )
+ {
+ /* No handler for this command. */
+ return;
+ }
+
+ for (i = 0; i < Parser->cmdSize; i++)
+ {
+ Parser->commandHandler->function(Parser->commandHandler, cmdAddr, *data);
+
+ /* Advance to next state. */
+ cmdAddr++;
+ data++;
+ }
+}
+
+static void
+_GetCommand(
+ IN OUT gckPARSER Parser
+ )
+{
+ gctUINT32 * buffer = (gctUINT32 *)Parser->currentCmdBufferAddr;
+
+ gctUINT16 cmdRectCount;
+ gctUINT16 cmdDataCount;
+
+ Parser->hi = buffer[0];
+ Parser->lo = buffer[1];
+
+ Parser->cmdOpcode = (((((gctUINT32) (Parser->hi)) >> (0 ? 31:27)) & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1)))))) );
+ Parser->cmdRectCount = 1;
+
+ switch (Parser->cmdOpcode)
+ {
+ case 0x01:
+ /* Extract count. */
+ Parser->cmdSize = (((((gctUINT32) (Parser->hi)) >> (0 ? 25:16)) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ? 25:16) + 1)))))) );
+ if (Parser->cmdSize == 0)
+ {
+ /* 0 means 1024. */
+ Parser->cmdSize = 1024;
+ }
+ Parser->skip = (Parser->cmdSize & 0x1) ? 0 : 1;
+
+ /* Extract address. */
+ Parser->cmdAddr = (((((gctUINT32) (Parser->hi)) >> (0 ? 15:0)) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1)))))) );
+
+ Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 4;
+ Parser->skipCount = Parser->cmdSize + Parser->skip;
+ break;
+
+ case 0x05:
+ Parser->cmdSize = 4;
+ Parser->skipCount = gcmALIGN(Parser->cmdSize, 2);
+ break;
+
+ case 0x06:
+ Parser->cmdSize = 5;
+ Parser->skipCount = gcmALIGN(Parser->cmdSize, 2);
+ break;
+
+ case 0x0C:
+ Parser->cmdSize = 3;
+ Parser->skipCount = gcmALIGN(Parser->cmdSize, 2);
+ break;
+
+ case 0x09:
+ Parser->cmdSize = 2;
+ Parser->cmdAddr = 0x0F16;
+ Parser->skipCount = gcmALIGN(Parser->cmdSize, 2);
+ break;
+
+ case 0x04:
+ Parser->cmdSize = 1;
+ Parser->cmdAddr = 0x0F06;
+
+ cmdRectCount = (((((gctUINT32) (Parser->hi)) >> (0 ? 15:8)) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:8) - (0 ? 15:8) + 1)))))) );
+ cmdDataCount = (((((gctUINT32) (Parser->hi)) >> (0 ? 26:16)) & ((gctUINT32) ((((1 ? 26:16) - (0 ? 26:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 26:16) - (0 ? 26:16) + 1)))))) );
+
+ Parser->skipCount = gcmALIGN(Parser->cmdSize, 2)
+ + cmdRectCount * 2
+ + gcmALIGN(cmdDataCount, 2);
+
+ Parser->cmdRectCount = cmdRectCount;
+ break;
+
+ case 0x03:
+ Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 8;
+ Parser->skipCount = 0;
+ break;
+
+ case 0x02:
+ Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 8;
+ Parser->skipCount = 0;
+ break;
+
+ case 0x07:
+ Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr + 8;
+ Parser->skipCount = 0;
+ break;
+
+ case 0x08:
+ /* Commands after LINK isn't executed, skip them. */
+ Parser->stop = gcvTRUE;
+ break;
+
+ default:
+ /* Unknown command is a risk. */
+ Parser->allow = gcvFALSE;
+ break;
+ }
+}
+
+static void
+_ParseCommand(
+ IN OUT gckPARSER Parser
+ )
+{
+ switch(Parser->cmdOpcode)
+ {
+ case 0x01:
+ _HandleLoadState(Parser);
+ break;
+ case 0x05:
+ case 0x06:
+ case 0x0C:
+ break;
+ case 0x04:
+ break;
+ default:
+ break;
+ }
+
+ /* Advance to next command. */
+ Parser->currentCmdBufferAddr = Parser->currentCmdBufferAddr
+ + (Parser->skipCount << 2);
+}
+
+gceSTATUS
+gckPARSER_Parse(
+ IN gckPARSER Parser,
+ IN gctUINT8_PTR Buffer,
+ IN gctUINT32 Bytes
+ )
+{
+ gckPARSER parser = Parser;
+ gctUINT8_PTR end = (gctUINT8_PTR)Buffer + Bytes;
+
+ /* Initialize parser. */
+ parser->currentCmdBufferAddr = (gctUINT8_PTR)Buffer;
+ parser->skip = 0;
+ parser->allow = gcvTRUE;
+ parser->stop = gcvFALSE;
+
+ /* Go through command buffer until reaching the end
+ ** or meeting an error. */
+ do
+ {
+ _GetCommand(parser);
+
+ _ParseCommand(parser);
+ }
+ while ((parser->currentCmdBufferAddr < end)
+ && (parser->allow == gcvTRUE)
+ && (parser->stop == gcvFALSE)
+ );
+
+ if (parser->allow == gcvFALSE)
+ {
+ /* Error detected. */
+ return gcvSTATUS_NOT_SUPPORTED;
+ }
+
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckPARSER_RegisterCommandHandler
+**
+** Register a command handler which will be called when parser get a command.
+**
+*/
+gceSTATUS
+gckPARSER_RegisterCommandHandler(
+ IN gckPARSER Parser,
+ IN gckPARSER_HANDLER Handler
+ )
+{
+ Parser->commandHandler = Handler;
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckPARSER_Construct(
+ IN gckOS Os,
+ IN gckPARSER_HANDLER Handler,
+ OUT gckPARSER * Parser
+ )
+{
+ gceSTATUS status;
+ gckPARSER pointer;
+
+ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsPARSER), (gctPOINTER *)&pointer));
+
+ /* Put it here temp, should have a more general plug-in mechnisam. */
+ pointer->commandHandler = Handler;
+
+ *Parser = pointer;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+void
+gckPARSER_Destroy(
+ IN gckOS Os,
+ IN gckPARSER Parser
+ )
+{
+ gcmkOS_SAFE_FREE(Os, Parser);
+}
+
+/******************************************************************************\
+**************************** Hardware States Recorder **************************
+\******************************************************************************/
+
+static void
+_RecodeState(
+ IN gckPARSER_HANDLER Handler,
+ IN gctUINT32 Addr,
+ IN gctUINT32 Data
+ )
+{
+ gcmkVERIFY_OK(gckRECORDER_UpdateMirror(Handler->private, Addr, Data));
+}
+
+static gctUINT
+_Previous(
+ IN gctUINT Index
+ )
+{
+ if (Index == 0)
+ {
+ return gcdNUM_RECORDS - 1;
+ }
+
+ return Index - 1;
+}
+
+static gctUINT
+_Next(
+ IN gctUINT Index
+ )
+{
+ return (Index + 1) % gcdNUM_RECORDS;
+}
+
+gceSTATUS
+gckRECORDER_Construct(
+ IN gckOS Os,
+ IN gckHARDWARE Hardware,
+ OUT gckRECORDER * Recorder
+ )
+{
+ gceSTATUS status;
+ gckCONTEXT context = gcvNULL;
+ gckRECORDER recorder = gcvNULL;
+ gctSIZE_T mapSize;
+ gctUINT i;
+ gctBOOL virtualCommandBuffer = Hardware->kernel->virtualCommandBuffer;
+
+ /* MMU is not ready now. */
+ Hardware->kernel->virtualCommandBuffer = gcvFALSE;
+
+ gcmkONERROR(gckCONTEXT_Construct(Os, Hardware, 0, &context));
+
+ /* Restore. */
+ Hardware->kernel->virtualCommandBuffer = virtualCommandBuffer;
+
+ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsRECORDER), (gctPOINTER *)&recorder));
+
+ gckOS_ZeroMemory(recorder, gcmSIZEOF(gcsRECORDER));
+
+ /* Copy state map. */
+ recorder->mirror.maxState = context->maxState;
+
+ mapSize = context->maxState * gcmSIZEOF(gcsSTATE_MAP);
+
+ gcmkONERROR(gckOS_Allocate(Os, mapSize, (gctPOINTER *)&recorder->mirror.map));
+
+ gckOS_MemCopy(recorder->mirror.map, context->map, mapSize);
+
+ /* Copy context buffer. */
+ recorder->mirror.bytes = context->totalSize;
+
+ for (i = 0; i < gcdNUM_RECORDS; i++)
+ {
+ gcmkONERROR(gckOS_Allocate(Os, context->totalSize, (gctPOINTER *)&recorder->mirror.logical[i]));
+ gckOS_MemCopy(recorder->mirror.logical[i], context->buffer->logical, context->totalSize);
+ }
+
+ for (i = 0; i < gcdNUM_RECORDS; i++)
+ {
+ gcmkONERROR(gckOS_Allocate(Os, gcdCMD_BUFFER_SIZE, (gctPOINTER *)&recorder->deltas[i].command));
+ gcmkONERROR(gckOS_Allocate(Os, context->totalSize, (gctPOINTER *)&recorder->deltas[i].context));
+ }
+
+ recorder->index = 0;
+ recorder->num = 0;
+
+ /* Initialize Parser plugin. */
+ recorder->recorderHandler.cmd = 0x01;
+ recorder->recorderHandler.private = recorder;
+ recorder->recorderHandler.function = _RecodeState;
+
+ gcmkONERROR(gckPARSER_Construct(Os, &recorder->recorderHandler, &recorder->parser));
+
+ recorder->os = Os;
+
+ *Recorder = recorder;
+
+ gckCONTEXT_Destroy(context);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (context)
+ {
+ gckCONTEXT_Destroy(context);
+ }
+
+ if (recorder)
+ {
+ gckRECORDER_Destory(Os, recorder);
+ }
+
+ return status;
+}
+
+gceSTATUS
+gckRECORDER_Destory(
+ IN gckOS Os,
+ IN gckRECORDER Recorder
+ )
+{
+ gctUINT i;
+
+ if (Recorder->mirror.map)
+ {
+ gcmkOS_SAFE_FREE(Os, Recorder->mirror.map);
+ }
+
+ for (i = 0; i < gcdNUM_RECORDS; i++)
+ {
+ if (Recorder->mirror.logical[i])
+ {
+ gcmkOS_SAFE_FREE(Os, Recorder->mirror.logical[i]);
+ }
+ }
+
+ for (i = 0; i < gcdNUM_RECORDS; i++)
+ {
+ if (Recorder->deltas[i].command)
+ {
+ gcmkOS_SAFE_FREE(Os, Recorder->deltas[i].command);
+ }
+
+ if (Recorder->deltas[i].context)
+ {
+ gcmkOS_SAFE_FREE(Os, Recorder->deltas[i].context);
+ }
+ }
+
+ if (Recorder->parser)
+ {
+ gckPARSER_Destroy(Os, Recorder->parser);
+ }
+
+ gcmkOS_SAFE_FREE(Os, Recorder);
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckRECORDER_UpdateMirror(
+ IN gckRECORDER Recorder,
+ IN gctUINT32 State,
+ IN gctUINT32 Data
+ )
+{
+ gctUINT32 index;
+ gcsSTATE_MAP_PTR map = Recorder->mirror.map;
+ gctUINT32_PTR buffer = Recorder->mirror.logical[Recorder->index];
+
+ if (State >= Recorder->mirror.maxState)
+ {
+ /* Ignore them just like HW does. */
+ return gcvSTATUS_OK;
+ }
+
+ index = map[State].index;
+
+ if (index)
+ {
+ buffer[index] = Data;
+ }
+
+ return gcvSTATUS_OK;
+}
+
+void
+gckRECORDER_AdvanceIndex(
+ IN gckRECORDER Recorder,
+ IN gctUINT64 CommitStamp
+ )
+{
+ /* Get next record. */
+ gctUINT next = (Recorder->index + 1) % gcdNUM_RECORDS;
+
+ /* Record stamp of this commit. */
+ Recorder->deltas[Recorder->index].commitStamp = CommitStamp;
+
+ /* Mirror of next record is mirror of this record and delta in next record. */
+ gckOS_MemCopy(Recorder->mirror.logical[next],
+ Recorder->mirror.logical[Recorder->index], Recorder->mirror.bytes);
+
+ /* Advance to next record. */
+ Recorder->index = next;
+
+ Recorder->num = gcmMIN(Recorder->num + 1, gcdNUM_RECORDS - 1);
+
+
+ /* Reset delta. */
+ Recorder->deltas[Recorder->index].commandBytes = 0;
+ Recorder->deltas[Recorder->index].contextBytes = 0;
+}
+
+void
+gckRECORDER_Record(
+ IN gckRECORDER Recorder,
+ IN gctUINT8_PTR CommandBuffer,
+ IN gctUINT32 CommandBytes,
+ IN gctUINT8_PTR ContextBuffer,
+ IN gctUINT32 ContextBytes
+ )
+{
+ gcsDELTA * delta = &Recorder->deltas[Recorder->index];
+
+ if (CommandBytes != 0xFFFFFFFF)
+ {
+ gckPARSER_Parse(Recorder->parser, CommandBuffer, CommandBytes);
+ gckOS_MemCopy(delta->command, CommandBuffer, CommandBytes);
+ delta->commandBytes = CommandBytes;
+ }
+
+ if (ContextBytes != 0xFFFFFFFF)
+ {
+ gckPARSER_Parse(Recorder->parser, ContextBuffer, ContextBytes);
+ gckOS_MemCopy(delta->context, ContextBuffer, ContextBytes);
+ delta->contextBytes = ContextBytes;
+ }
+}
+
+void
+gckRECORDER_Dump(
+ IN gckRECORDER Recorder
+ )
+{
+ gctUINT last = Recorder->index;
+ gctUINT previous;
+ gctUINT i;
+ gcsMIRROR *mirror = &Recorder->mirror;
+ gcsDELTA *delta;
+ gckOS os = Recorder->os;
+
+ for (i = 0; i < Recorder->num; i++)
+ {
+ last = _Previous(last);
+ }
+
+ for (i = 0; i < Recorder->num; i++)
+ {
+ delta = &Recorder->deltas[last];
+
+ /* Dump record */
+ gcmkPRINT("#[commit %llu]", delta->commitStamp);
+
+ if (delta->commitStamp)
+ {
+ previous = _Previous(last);
+
+ gcmkPRINT("#[mirror]");
+ gckOS_DumpBuffer(os, mirror->logical[previous], mirror->bytes, gcvDUMP_BUFFER_CONTEXT, gcvTRUE);
+ gcmkPRINT("@[kernel.execute]");
+ }
+
+ if (delta->contextBytes)
+ {
+ gckOS_DumpBuffer(os, delta->context, delta->contextBytes, gcvDUMP_BUFFER_CONTEXT, gcvTRUE);
+ gcmkPRINT("@[kernel.execute]");
+ }
+
+ gckOS_DumpBuffer(os, delta->command, delta->commandBytes, gcvDUMP_BUFFER_USER, gcvTRUE);
+ gcmkPRINT("@[kernel.execute]");
+
+ last = _Next(last);
+ }
+}
+
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_command_vg.c b/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_command_vg.c
new file mode 100644
index 000000000000..cfd618c54337
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_command_vg.c
@@ -0,0 +1,1192 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal.h"
+#include "gc_hal_kernel.h"
+
+#if gcdENABLE_VG
+
+#include "gc_hal_kernel_hardware_command_vg.h"
+
+#define _GC_OBJ_ZONE gcvZONE_COMMAND
+
+/******************************************************************************\
+****************************** gckVGCOMMAND API code *****************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+** gckVGCOMMAND_InitializeInfo
+**
+** Initialize architecture dependent command buffer information.
+**
+** INPUT:
+**
+** gckVGCOMMAND Command
+** Pointer to the Command object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckVGCOMMAND_InitializeInfo(
+ IN gckVGCOMMAND Command
+ )
+{
+ gceSTATUS status;
+ gcmkHEADER_ARG("Command=0x%x", Command);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ do
+ {
+ /* Reset interrupts. */
+ Command->info.feBufferInt = -1;
+ Command->info.tsOverflowInt = -1;
+
+ /* Set command buffer attributes. */
+ Command->info.addressAlignment = 64;
+ Command->info.commandAlignment = 8;
+
+ /* Determine command alignment address mask. */
+ Command->info.addressMask = ((((gctUINT32) (Command->info.addressAlignment - 1)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ? 1:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) ((gctUINT32) (0 ) & ((gctUINT32) ((((1 ? 1:0) - (0 ?
+ 1:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ?
+ 1:0)));
+
+ /* Query the number of bytes needed by the STATE command. */
+ gcmkERR_BREAK(gckVGCOMMAND_StateCommand(
+ Command, 0x0, gcvNULL, (gctUINT32)~0, 0,
+ &Command->info.stateCommandSize
+ ));
+
+ /* Query the number of bytes needed by the RESTART command. */
+ gcmkERR_BREAK(gckVGCOMMAND_RestartCommand(
+ Command, gcvNULL, (gctUINT32)~0, 0,
+ &Command->info.restartCommandSize
+ ));
+
+ /* Query the number of bytes needed by the FETCH command. */
+ gcmkERR_BREAK(gckVGCOMMAND_FetchCommand(
+ Command, gcvNULL, (gctUINT32)~0, 0,
+ &Command->info.fetchCommandSize
+ ));
+
+ /* Query the number of bytes needed by the CALL command. */
+ gcmkERR_BREAK(gckVGCOMMAND_CallCommand(
+ Command, gcvNULL, (gctUINT32)~0, 0,
+ &Command->info.callCommandSize
+ ));
+
+ /* Query the number of bytes needed by the RETURN command. */
+ gcmkERR_BREAK(gckVGCOMMAND_ReturnCommand(
+ Command, gcvNULL,
+ &Command->info.returnCommandSize
+ ));
+
+ /* Query the number of bytes needed by the EVENT command. */
+ gcmkERR_BREAK(gckVGCOMMAND_EventCommand(
+ Command, gcvNULL, gcvBLOCK_PIXEL, -1,
+ &Command->info.eventCommandSize
+ ));
+
+ /* Query the number of bytes needed by the END command. */
+ gcmkERR_BREAK(gckVGCOMMAND_EndCommand(
+ Command, gcvNULL, -1,
+ &Command->info.endCommandSize
+ ));
+
+ /* Determine the tail reserve size. */
+ Command->info.staticTailSize = gcmMAX(
+ Command->info.fetchCommandSize,
+ gcmMAX(
+ Command->info.returnCommandSize,
+ Command->info.endCommandSize
+ )
+ );
+
+ /* Determine the maximum tail size. */
+ Command->info.dynamicTailSize
+ = Command->info.staticTailSize
+ + Command->info.eventCommandSize * gcvBLOCK_COUNT;
+ }
+ while (gcvFALSE);
+
+ gcmkFOOTER();
+ /* Return status. */
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckVGCOMMAND_StateCommand
+**
+** Append a STATE command at the specified location in the command buffer.
+**
+** INPUT:
+**
+** gckVGCOMMAND Command
+** Pointer to an gckVGCOMMAND object.
+**
+** gctUINT32 Pipe
+** Harwdare destination pipe.
+**
+** gctPOINTER Logical
+** Pointer to the current location inside the command buffer to append
+** STATE command at or gcvNULL to query the size of the command.
+**
+** gctUINT32 Address
+** Starting register address of the state buffer.
+** If 'Logical' is gcvNULL, this argument is ignored.
+**
+** gctUINT32 Count
+** Number of states in state buffer.
+** If 'Logical' is gcvNULL, this argument is ignored.
+**
+** gctSIZE_T * Bytes
+** Pointer to the number of bytes available for the STATE command.
+** If 'Logical' is gcvNULL, the value from this argument is ignored.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that will receive the number of bytes required
+** for the STATE command. If 'Bytes' is gcvNULL, nothing is returned.
+*/
+gceSTATUS
+gckVGCOMMAND_StateCommand(
+ IN gckVGCOMMAND Command,
+ IN gctUINT32 Pipe,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Address,
+ IN gctUINT32 Count,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gcmkHEADER_ARG("Command=0x%x Pipe=0x%x Logical=0x%x Address=0x%x Count=0x%x Bytes = 0x%x",
+ Command, Pipe, Logical, Address, Count, Bytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ if (Command->fe20)
+ {
+ if (Logical != gcvNULL)
+ {
+ gctUINT32_PTR buffer;
+
+ /* Cast the buffer pointer. */
+ buffer = (gctUINT32_PTR) Logical;
+
+ /* Append STATE. */
+ gckOS_WriteMemory(
+ Command->os,
+ &buffer[0],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:28) - (0 ? 31:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ? 31:28))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ?
+ 31:28) - (0 ? 31:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ? 31:28)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:0) - (0 ? 11:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:0) - (0 ? 11:0) + 1))))))) << (0 ?
+ 11:0))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ? 11:0) - (0 ?
+ 11:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:0) - (0 ? 11:0) + 1))))))) << (0 ?
+ 11:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 27:16) - (0 ? 27:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 27:16) - (0 ?
+ 27:16) + 1))))))) << (0 ? 27:16))) | (((gctUINT32) ((gctUINT32) (Count) & ((gctUINT32) ((((1 ?
+ 27:16) - (0 ? 27:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 27:16) - (0 ?
+ 27:16) + 1))))))) << (0 ? 27:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 13:12) - (0 ? 13:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 13:12) - (0 ?
+ 13:12) + 1))))))) << (0 ? 13:12))) | (((gctUINT32) ((gctUINT32) (Pipe) & ((gctUINT32) ((((1 ?
+ 13:12) - (0 ? 13:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 13:12) - (0 ?
+ 13:12) + 1))))))) << (0 ? 13:12)))
+ );
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the STATE command. */
+ *Bytes = 4 * (Count + 1);
+ }
+ }
+ else
+ {
+ if (Logical != gcvNULL)
+ {
+ gctUINT32_PTR buffer;
+
+ /* Cast the buffer pointer. */
+ buffer = (gctUINT32_PTR) Logical;
+
+ /* Append LOAD_STATE. */
+ gckOS_WriteMemory(
+ Command->os,
+ &buffer[0],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (Count) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ );
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the STATE command. */
+ *Bytes = 4 * (Count + 1);
+ }
+ }
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckVGCOMMAND_RestartCommand
+**
+** Form a RESTART command at the specified location in the command buffer.
+**
+** INPUT:
+**
+** gckVGCOMMAND Command
+** Pointer to an gckVGCOMMAND object.
+**
+** gctPOINTER Logical
+** Pointer to the current location inside the command buffer to append
+** RESTART command at or gcvNULL to query the size of the command.
+**
+** gctUINT32 FetchAddress
+** The address of another command buffer to be executed by this RESTART
+** command. If 'Logical' is gcvNULL, this argument is ignored.
+**
+** gctUINT FetchCount
+** The number of 64-bit data quantities in another command buffer to
+** be executed by this RESTART command. If 'Logical' is gcvNULL, this
+** argument is ignored.
+**
+** gctSIZE_T * Bytes
+** Pointer to the number of bytes available for the RESTART command.
+** If 'Logical' is gcvNULL, the value from this argument is ignored.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that will receive the number of bytes required
+** for the RESTART command. If 'Bytes' is gcvNULL, nothing is returned.
+*/
+gceSTATUS
+gckVGCOMMAND_RestartCommand(
+ IN gckVGCOMMAND Command,
+ IN gctPOINTER Logical,
+ IN gctUINT32 FetchAddress,
+ IN gctUINT FetchCount,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gcmkHEADER_ARG("Command=0x%x Logical=0x%x FetchAddress=0x%x FetchCount=0x%x Bytes = 0x%x",
+ Command, Logical, FetchAddress, FetchCount, Bytes);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ if (Command->fe20)
+ {
+ if (Logical != gcvNULL)
+ {
+ gctUINT32_PTR buffer;
+ gctUINT32 beginEndMark;
+
+ /* Cast the buffer pointer. */
+ buffer = (gctUINT32_PTR) Logical;
+
+ /* Determine Begin/End flag. */
+ beginEndMark = (FetchCount > 0)
+ ? ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 24:24) - (0 ? 24:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 24:24) - (0 ?
+ 24:24) + 1))))))) << (0 ? 24:24))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 24:24) - (0 ? 24:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 24:24) - (0 ?
+ 24:24) + 1))))))) << (0 ? 24:24)))
+ : ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 24:24) - (0 ? 24:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 24:24) - (0 ?
+ 24:24) + 1))))))) << (0 ? 24:24))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 24:24) - (0 ? 24:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 24:24) - (0 ?
+ 24:24) + 1))))))) << (0 ? 24:24)));
+
+ /* Append RESTART. */
+ gckOS_WriteMemory(
+ Command->os,
+ &buffer[0],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:28) - (0 ? 31:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ? 31:28))) | (((gctUINT32) (0x9 & ((gctUINT32) ((((1 ?
+ 31:28) - (0 ? 31:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ? 31:28)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:0) - (0 ? 20:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 20:0) - (0 ? 20:0) + 1))))))) << (0 ?
+ 20:0))) | (((gctUINT32) ((gctUINT32) (FetchCount) & ((gctUINT32) ((((1 ?
+ 20:0) - (0 ? 20:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 20:0) - (0 ? 20:0) + 1))))))) << (0 ?
+ 20:0)))
+ | beginEndMark
+ );
+
+ gckOS_WriteMemory(
+ Command->os,
+ &buffer[1],
+ FetchAddress
+ );
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the RESTART command. */
+ *Bytes = 8;
+ }
+ }
+ else
+ {
+ gcmkFOOTER_NO();
+ return gcvSTATUS_NOT_SUPPORTED;
+ }
+
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckVGCOMMAND_FetchCommand
+**
+** Form a FETCH command at the specified location in the command buffer.
+**
+** INPUT:
+**
+** gckVGCOMMAND Command
+** Pointer to an gckVGCOMMAND object.
+**
+** gctPOINTER Logical
+** Pointer to the current location inside the command buffer to append
+** FETCH command at or gcvNULL to query the size of the command.
+**
+** gctUINT32 FetchAddress
+** The address of another command buffer to be executed by this FETCH
+** command. If 'Logical' is gcvNULL, this argument is ignored.
+**
+** gctUINT FetchCount
+** The number of 64-bit data quantities in another command buffer to
+** be executed by this FETCH command. If 'Logical' is gcvNULL, this
+** argument is ignored.
+**
+** gctSIZE_T * Bytes
+** Pointer to the number of bytes available for the FETCH command.
+** If 'Logical' is gcvNULL, the value from this argument is ignored.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that will receive the number of bytes required
+** for the FETCH command. If 'Bytes' is gcvNULL, nothing is returned.
+*/
+gceSTATUS
+gckVGCOMMAND_FetchCommand(
+ IN gckVGCOMMAND Command,
+ IN gctPOINTER Logical,
+ IN gctUINT32 FetchAddress,
+ IN gctUINT FetchCount,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gcmkHEADER_ARG("Command=0x%x Logical=0x%x FetchAddress=0x%x FetchCount=0x%x Bytes = 0x%x",
+ Command, Logical, FetchAddress, FetchCount, Bytes);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ if (Command->fe20)
+ {
+ if (Logical != gcvNULL)
+ {
+ gctUINT32_PTR buffer;
+
+ /* Cast the buffer pointer. */
+ buffer = (gctUINT32_PTR) Logical;
+
+ /* Append FETCH. */
+ gckOS_WriteMemory(
+ Command->os,
+ &buffer[0],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:28) - (0 ? 31:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ? 31:28))) | (((gctUINT32) (0x5 & ((gctUINT32) ((((1 ?
+ 31:28) - (0 ? 31:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ? 31:28)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:0) - (0 ? 20:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 20:0) - (0 ? 20:0) + 1))))))) << (0 ?
+ 20:0))) | (((gctUINT32) ((gctUINT32) (FetchCount) & ((gctUINT32) ((((1 ?
+ 20:0) - (0 ? 20:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 20:0) - (0 ? 20:0) + 1))))))) << (0 ?
+ 20:0)))
+ );
+
+ gckOS_WriteMemory(
+ Command->os,
+ &buffer[1],
+ gcmkFIXADDRESS(FetchAddress)
+ );
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the FETCH command. */
+ *Bytes = 8;
+ }
+ }
+ else
+ {
+ if (Logical != gcvNULL)
+ {
+ gctUINT32_PTR buffer;
+
+ /* Cast the buffer pointer. */
+ buffer = (gctUINT32_PTR) Logical;
+
+ /* Append LINK. */
+ gckOS_WriteMemory(
+ Command->os,
+ &buffer[0],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (FetchCount) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ );
+
+ gckOS_WriteMemory(
+ Command->os,
+ &buffer[1],
+ gcmkFIXADDRESS(FetchAddress)
+ );
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the LINK command. */
+ *Bytes = 8;
+ }
+ }
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckVGCOMMAND_CallCommand
+**
+** Append a CALL command at the specified location in the command buffer.
+**
+** INPUT:
+**
+** gckVGCOMMAND Command
+** Pointer to an gckVGCOMMAND object.
+**
+** gctPOINTER Logical
+** Pointer to the current location inside the command buffer to append
+** CALL command at or gcvNULL to query the size of the command.
+**
+** gctUINT32 FetchAddress
+** The address of another command buffer to be executed by this CALL
+** command. If 'Logical' is gcvNULL, this argument is ignored.
+**
+** gctUINT FetchCount
+** The number of 64-bit data quantities in another command buffer to
+** be executed by this CALL command. If 'Logical' is gcvNULL, this
+** argument is ignored.
+**
+** gctSIZE_T * Bytes
+** Pointer to the number of bytes available for the CALL command.
+** If 'Logical' is gcvNULL, the value from this argument is ignored.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that will receive the number of bytes required
+** for the CALL command. If 'Bytes' is gcvNULL, nothing is returned.
+*/
+gceSTATUS
+gckVGCOMMAND_CallCommand(
+ IN gckVGCOMMAND Command,
+ IN gctPOINTER Logical,
+ IN gctUINT32 FetchAddress,
+ IN gctUINT FetchCount,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gcmkHEADER_ARG("Command=0x%x Logical=0x%x FetchAddress=0x%x FetchCount=0x%x Bytes = 0x%x",
+ Command, Logical, FetchAddress, FetchCount, Bytes);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ if (Command->fe20)
+ {
+ if (Logical != gcvNULL)
+ {
+ gctUINT32_PTR buffer;
+
+ /* Cast the buffer pointer. */
+ buffer = (gctUINT32_PTR) Logical;
+
+ /* Append CALL. */
+ gckOS_WriteMemory(
+ Command->os,
+ &buffer[0],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:28) - (0 ? 31:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ? 31:28))) | (((gctUINT32) (0x6 & ((gctUINT32) ((((1 ?
+ 31:28) - (0 ? 31:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ? 31:28)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:0) - (0 ? 20:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 20:0) - (0 ? 20:0) + 1))))))) << (0 ?
+ 20:0))) | (((gctUINT32) ((gctUINT32) (FetchCount) & ((gctUINT32) ((((1 ?
+ 20:0) - (0 ? 20:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 20:0) - (0 ? 20:0) + 1))))))) << (0 ?
+ 20:0)))
+ );
+
+ gckOS_WriteMemory(
+ Command->os,
+ &buffer[1],
+ gcmkFIXADDRESS(FetchAddress)
+ );
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the CALL command. */
+ *Bytes = 8;
+ }
+ }
+ else
+ {
+ gcmkFOOTER_NO();
+ return gcvSTATUS_NOT_SUPPORTED;
+ }
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckVGCOMMAND_ReturnCommand
+**
+** Append a RETURN command at the specified location in the command buffer.
+**
+** INPUT:
+**
+** gckVGCOMMAND Command
+** Pointer to an gckVGCOMMAND object.
+**
+** gctPOINTER Logical
+** Pointer to the current location inside the command buffer to append
+** RETURN command at or gcvNULL to query the size of the command.
+**
+** gctSIZE_T * Bytes
+** Pointer to the number of bytes available for the RETURN command.
+** If 'Logical' is gcvNULL, the value from this argument is ignored.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that will receive the number of bytes required
+** for the RETURN command. If 'Bytes' is gcvNULL, nothing is returned.
+*/
+gceSTATUS
+gckVGCOMMAND_ReturnCommand(
+ IN gckVGCOMMAND Command,
+ IN gctPOINTER Logical,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gcmkHEADER_ARG("Command=0x%x Logical=0x%x Bytes = 0x%x",
+ Command, Logical, Bytes);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ if (Command->fe20)
+ {
+ if (Logical != gcvNULL)
+ {
+ gctUINT32_PTR buffer;
+
+ /* Cast the buffer pointer. */
+ buffer = (gctUINT32_PTR) Logical;
+
+ /* Append RETURN. */
+ gckOS_WriteMemory(
+ Command->os,
+ &buffer[0],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:28) - (0 ? 31:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ? 31:28))) | (((gctUINT32) (0x7 & ((gctUINT32) ((((1 ?
+ 31:28) - (0 ? 31:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ? 31:28)))
+ );
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the RETURN command. */
+ *Bytes = 8;
+ }
+ }
+ else
+ {
+ gcmkFOOTER_NO();
+ return gcvSTATUS_NOT_SUPPORTED;
+ }
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckVGCOMMAND_EventCommand
+**
+** Form an EVENT command at the specified location in the command buffer.
+**
+** INPUT:
+**
+** gckVGCOMMAND Command
+** Pointer to the Command object.
+**
+** gctPOINTER Logical
+** Pointer to the current location inside the command buffer to append
+** EVENT command at or gcvNULL to query the size of the command.
+**
+** gctINT32 InterruptId
+** The ID of the interrupt to generate.
+** If 'Logical' is gcvNULL, this argument is ignored.
+**
+** gceBLOCK Block
+** Block that will generate the interrupt.
+**
+** gctSIZE_T * Bytes
+** Pointer to the number of bytes available for the EVENT command.
+** If 'Logical' is gcvNULL, the value from this argument is ignored.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that will receive the number of bytes required
+** for the END command. If 'Bytes' is gcvNULL, nothing is returned.
+*/
+gceSTATUS
+gckVGCOMMAND_EventCommand(
+ IN gckVGCOMMAND Command,
+ IN gctPOINTER Logical,
+ IN gceBLOCK Block,
+ IN gctINT32 InterruptId,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gcmkHEADER_ARG("Command=0x%x Logical=0x%x Block=0x%x InterruptId=0x%x Bytes = 0x%x",
+ Command, Logical, Block, InterruptId, Bytes);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ if (Command->fe20)
+ {
+ typedef struct _gcsEVENTSTATES
+ {
+ /* Chips before VG21 use these values. */
+ gctUINT eventFromFE;
+ gctUINT eventFromPE;
+
+ /* VG21 chips and later use SOURCE field. */
+ gctUINT eventSource;
+ }
+ gcsEVENTSTATES;
+
+ static gcsEVENTSTATES states[] =
+ {
+ /* gcvBLOCK_COMMAND */
+ {
+ (gctUINT)~0,
+ (gctUINT)~0,
+ (gctUINT)~0
+ },
+
+ /* gcvBLOCK_TESSELLATOR */
+ {
+ 0x0,
+ 0x1,
+ 0x10
+ },
+
+ /* gcvBLOCK_TESSELLATOR2 */
+ {
+ 0x0,
+ 0x1,
+ 0x12
+ },
+
+ /* gcvBLOCK_TESSELLATOR3 */
+ {
+ 0x0,
+ 0x1,
+ 0x14
+ },
+
+ /* gcvBLOCK_RASTER */
+ {
+ 0x0,
+ 0x1,
+ 0x07,
+ },
+
+ /* gcvBLOCK_VG */
+ {
+ 0x0,
+ 0x1,
+ 0x0F
+ },
+
+ /* gcvBLOCK_VG2 */
+ {
+ 0x0,
+ 0x1,
+ 0x11
+ },
+
+ /* gcvBLOCK_VG3 */
+ {
+ 0x0,
+ 0x1,
+ 0x13
+ },
+
+ /* gcvBLOCK_PIXEL */
+ {
+ 0x0,
+ 0x1,
+ 0x07
+ },
+ };
+
+ /* Verify block ID. */
+ gcmkVERIFY_ARGUMENT(gcmIS_VALID_INDEX(Block, states));
+
+ if (Logical != gcvNULL)
+ {
+ gctUINT32_PTR buffer;
+
+ /* Verify the event ID. */
+ gcmkVERIFY_ARGUMENT(InterruptId >= 0);
+ gcmkVERIFY_ARGUMENT(InterruptId <= ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))));
+
+ /* Cast the buffer pointer. */
+ buffer = (gctUINT32_PTR) Logical;
+
+ /* Append EVENT. */
+ gckOS_WriteMemory(
+ Command->os,
+ &buffer[0],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:28) - (0 ? 31:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ? 31:28))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ?
+ 31:28) - (0 ? 31:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ? 31:28)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 11:0) - (0 ? 11:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:0) - (0 ? 11:0) + 1))))))) << (0 ?
+ 11:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ? 11:0) - (0 ?
+ 11:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:0) - (0 ? 11:0) + 1))))))) << (0 ?
+ 11:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 27:16) - (0 ? 27:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 27:16) - (0 ?
+ 27:16) + 1))))))) << (0 ? 27:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 27:16) - (0 ? 27:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 27:16) - (0 ?
+ 27:16) + 1))))))) << (0 ? 27:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 13:12) - (0 ? 13:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 13:12) - (0 ?
+ 13:12) + 1))))))) << (0 ? 13:12))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 13:12) - (0 ? 13:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 13:12) - (0 ?
+ 13:12) + 1))))))) << (0 ? 13:12)))
+ );
+
+ /* Determine chip version. */
+ if (Command->vg21)
+ {
+ /* Get the event source for the block. */
+ gctUINT eventSource = states[Block].eventSource;
+
+ /* Supported? */
+ if (eventSource == ~0)
+ {
+ gcmkFOOTER_NO();
+ return gcvSTATUS_NOT_SUPPORTED;
+ }
+
+ buffer[1]
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8))) | (((gctUINT32) ((gctUINT32) (eventSource) & ((gctUINT32) ((((1 ?
+ 12:8) - (0 ? 12:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ?
+ 12:8)));
+ }
+ else
+ {
+ /* Get the event source for the block. */
+ gctUINT eventFromFE = states[Block].eventFromFE;
+ gctUINT eventFromPE = states[Block].eventFromPE;
+
+ /* Supported? */
+ if (eventFromFE == ~0)
+ {
+ gcmkFOOTER_NO();
+ return gcvSTATUS_NOT_SUPPORTED;
+ }
+
+ buffer[1]
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ? 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) ((gctUINT32) (eventFromFE) & ((gctUINT32) ((((1 ?
+ 5:5) - (0 ? 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ? 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) ((gctUINT32) (eventFromPE) & ((gctUINT32) ((((1 ?
+ 6:6) - (0 ? 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6)));
+ }
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Make sure the events are directly supported for the block. */
+ if (states[Block].eventSource == ~0)
+ {
+ gcmkFOOTER_NO();
+ return gcvSTATUS_NOT_SUPPORTED;
+ }
+
+ /* Return number of bytes required by the END command. */
+ *Bytes = 8;
+ }
+ }
+ else
+ {
+ if (Logical != gcvNULL)
+ {
+ gctUINT32_PTR buffer;
+
+ /* Verify the event ID. */
+ gcmkVERIFY_ARGUMENT(InterruptId >= 0);
+ gcmkVERIFY_ARGUMENT(InterruptId <= ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))));
+
+ /* Cast the buffer pointer. */
+ buffer = (gctUINT32_PTR) Logical;
+
+ /* Append EVENT. */
+ gckOS_WriteMemory(
+ Command->os,
+ &buffer[0],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ );
+
+ /* Determine event source. */
+ if (Block == gcvBLOCK_COMMAND)
+ {
+ gckOS_WriteMemory(
+ Command->os,
+ &buffer[1],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 5:5) - (0 ? 5:5) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ?
+ 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5)))
+ );
+ }
+ else
+ {
+ gckOS_WriteMemory(
+ Command->os,
+ &buffer[1],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ? 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)))
+ );
+ }
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the EVENT and END commands. */
+ *Bytes = 8;
+ }
+ }
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckVGCOMMAND_EndCommand
+**
+** Form an END command at the specified location in the command buffer.
+**
+** INPUT:
+**
+** gckVGCOMMAND Command
+** Pointer to the Command object.
+**
+** gctPOINTER Logical
+** Pointer to the current location inside the command buffer to append
+** END command at or gcvNULL to query the size of the command.
+**
+** gctINT32 InterruptId
+** The ID of the interrupt to generate.
+** If 'Logical' is gcvNULL, this argument will be ignored.
+**
+** gctSIZE_T * Bytes
+** Pointer to the number of bytes available for the END command.
+** If 'Logical' is gcvNULL, the value from this argument is ignored.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that will receive the number of bytes required
+** for the END command. If 'Bytes' is gcvNULL, nothing is returned.
+*/
+gceSTATUS
+gckVGCOMMAND_EndCommand(
+ IN gckVGCOMMAND Command,
+ IN gctPOINTER Logical,
+ IN gctINT32 InterruptId,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gcmkHEADER_ARG("Command=0x%x Logical=0x%x InterruptId=0x%x Bytes = 0x%x",
+ Command, Logical, InterruptId, Bytes);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ if (Command->fe20)
+ {
+ if (Logical != gcvNULL)
+ {
+ gctUINT32_PTR buffer;
+
+ /* Verify the event ID. */
+ gcmkVERIFY_ARGUMENT(InterruptId >= 0);
+
+ /* Cast the buffer pointer. */
+ buffer = (gctUINT32_PTR) Logical;
+
+ /* Append END. */
+ gckOS_WriteMemory(
+ Command->os,
+ &buffer[0],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:28) - (0 ? 31:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ? 31:28))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 31:28) - (0 ? 31:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:28) - (0 ?
+ 31:28) + 1))))))) << (0 ? 31:28)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0)))
+ );
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the END command. */
+ *Bytes = 8;
+ }
+ }
+ else
+ {
+ if (Logical != gcvNULL)
+ {
+ gctUINT32_PTR memory;
+
+ /* Verify the event ID. */
+ gcmkVERIFY_ARGUMENT(InterruptId >= 0);
+
+ /* Cast the buffer pointer. */
+ memory = (gctUINT32_PTR) Logical;
+
+ /* Append EVENT. */
+ gckOS_WriteMemory(
+ Command->os,
+ &memory[0],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ );
+
+ gckOS_WriteMemory(
+ Command->os,
+ &memory[1],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0))) | (((gctUINT32) ((gctUINT32) (InterruptId) & ((gctUINT32) ((((1 ?
+ 4:0) - (0 ? 4:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ?
+ 4:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 6:6) - (0 ? 6:6) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ?
+ 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6)))
+ );
+
+ /* Append END. */
+ gckOS_WriteMemory(
+ Command->os,
+ &memory[2],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ );
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the EVENT and END commands. */
+ *Bytes = 16;
+ }
+ }
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+#endif /* gcdENABLE_VG */
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_command_vg.h b/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_command_vg.h
new file mode 100644
index 000000000000..ab495f57b512
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_command_vg.h
@@ -0,0 +1,353 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_hardware_command_vg_h_
+#define __gc_hal_kernel_hardware_command_vg_h_
+
+/******************************************************************************\
+******************* Task and Interrupt Management Structures. ******************
+\******************************************************************************/
+
+/* Task storage header. */
+typedef struct _gcsTASK_STORAGE * gcsTASK_STORAGE_PTR;
+typedef struct _gcsTASK_STORAGE
+{
+ /* Next allocated storage buffer. */
+ gcsTASK_STORAGE_PTR next;
+}
+gcsTASK_STORAGE;
+
+/* Task container header. */
+typedef struct _gcsTASK_CONTAINER * gcsTASK_CONTAINER_PTR;
+typedef struct _gcsTASK_CONTAINER
+{
+ /* The number of tasks left to be processed in the container. */
+ gctINT referenceCount;
+
+ /* Size of the buffer. */
+ gctUINT size;
+
+ /* Link to the previous and the next allocated containers. */
+ gcsTASK_CONTAINER_PTR allocPrev;
+ gcsTASK_CONTAINER_PTR allocNext;
+
+ /* Link to the previous and the next containers in the free list. */
+ gcsTASK_CONTAINER_PTR freePrev;
+ gcsTASK_CONTAINER_PTR freeNext;
+}
+gcsTASK_CONTAINER;
+
+/* Kernel space task master table entry. */
+typedef struct _gcsBLOCK_TASK_ENTRY * gcsBLOCK_TASK_ENTRY_PTR;
+typedef struct _gcsBLOCK_TASK_ENTRY
+{
+ /* Pointer to the current task container for the block. */
+ gcsTASK_CONTAINER_PTR container;
+
+ /* Pointer to the current task data within the container. */
+ gcsTASK_HEADER_PTR task;
+
+ /* Pointer to the last link task within the container. */
+ gcsTASK_LINK_PTR link;
+
+ /* Number of interrupts allocated for this block. */
+ gctUINT interruptCount;
+
+ /* The index of the current interrupt. */
+ gctUINT interruptIndex;
+
+ /* Interrupt semaphore. */
+ gctSEMAPHORE interruptSemaphore;
+
+ /* Interrupt value array. */
+ gctINT32 interruptArray[32];
+}
+gcsBLOCK_TASK_ENTRY;
+
+
+/******************************************************************************\
+********************* Command Queue Management Structures. *********************
+\******************************************************************************/
+
+/* Command queue kernel element pointer. */
+typedef struct _gcsKERNEL_CMDQUEUE * gcsKERNEL_CMDQUEUE_PTR;
+
+/* Command queue object handler function type. */
+typedef gceSTATUS (* gctOBJECT_HANDLER) (
+ gckVGKERNEL Kernel,
+ gcsKERNEL_CMDQUEUE_PTR Entry
+ );
+
+/* Command queue kernel element. */
+typedef struct _gcsKERNEL_CMDQUEUE
+{
+ /* The number of buffers in the queue. */
+ gcsCMDBUFFER_PTR commandBuffer;
+
+ /* Pointer to the object handler function. */
+ gctOBJECT_HANDLER handler;
+}
+gcsKERNEL_CMDQUEUE;
+
+/* Command queue header. */
+typedef struct _gcsKERNEL_QUEUE_HEADER * gcsKERNEL_QUEUE_HEADER_PTR;
+typedef struct _gcsKERNEL_QUEUE_HEADER
+{
+ /* The size of the buffer in bytes. */
+ gctUINT size;
+
+ /* The number of pending entries to be processed. */
+ volatile gctUINT pending;
+
+ /* The current command queue entry. */
+ gcsKERNEL_CMDQUEUE_PTR currentEntry;
+
+ /* Next buffer. */
+ gcsKERNEL_QUEUE_HEADER_PTR next;
+}
+gcsKERNEL_QUEUE_HEADER;
+
+
+/******************************************************************************\
+******************************* gckVGCOMMAND Object *******************************
+\******************************************************************************/
+
+/* gckVGCOMMAND object. */
+struct _gckVGCOMMAND
+{
+ /***************************************************************************
+ ** Object data and pointers.
+ */
+
+ gcsOBJECT object;
+ gckVGKERNEL kernel;
+ gckOS os;
+ gckVGHARDWARE hardware;
+
+ /* Features. */
+ gctBOOL fe20;
+ gctBOOL vg20;
+ gctBOOL vg21;
+
+
+ /***************************************************************************
+ ** Enable command queue dumping.
+ */
+
+ gctBOOL enableDumping;
+
+
+ /***************************************************************************
+ ** Bus Error interrupt.
+ */
+
+ gctINT32 busErrorInt;
+
+
+ /***************************************************************************
+ ** Command buffer information.
+ */
+
+ gcsCOMMAND_BUFFER_INFO info;
+
+
+ /***************************************************************************
+ ** Synchronization objects.
+ */
+
+ gctPOINTER queueMutex;
+ gctPOINTER taskMutex;
+ gctPOINTER commitMutex;
+
+
+ /***************************************************************************
+ ** Task management.
+ */
+
+ /* The head of the storage buffer linked list. */
+ gcsTASK_STORAGE_PTR taskStorage;
+
+ /* Allocation size. */
+ gctUINT taskStorageGranularity;
+ gctUINT taskStorageUsable;
+
+ /* The free container list. */
+ gcsTASK_CONTAINER_PTR taskFreeHead;
+ gcsTASK_CONTAINER_PTR taskFreeTail;
+
+ /* Task table */
+ gcsBLOCK_TASK_ENTRY taskTable[gcvBLOCK_COUNT];
+
+
+ /***************************************************************************
+ ** Command queue.
+ */
+
+ /* Pointer to the allocated queue memory. */
+ gcsKERNEL_QUEUE_HEADER_PTR queue;
+
+ /* Pointer to the current available queue from which new queue entries
+ will be allocated. */
+ gcsKERNEL_QUEUE_HEADER_PTR queueHead;
+
+ /* If different from queueHead, points to the command queue which is
+ currently being executed by the hardware. */
+ gcsKERNEL_QUEUE_HEADER_PTR queueTail;
+
+ /* Points to the queue to merge the tail with when the tail is processed. */
+ gcsKERNEL_QUEUE_HEADER_PTR mergeQueue;
+
+ /* Queue overflow counter. */
+ gctUINT queueOverflow;
+
+
+ /***************************************************************************
+ ** Context.
+ */
+
+ /* Context counter used for unique ID. */
+ gctUINT64 contextCounter;
+
+ /* Current context ID. */
+ gctUINT64 currentContext;
+
+ /* Command queue power semaphore. */
+ gctPOINTER powerSemaphore;
+ gctINT32 powerStallInt;
+ gcsCMDBUFFER_PTR powerStallBuffer;
+ gctSIGNAL powerStallSignal;
+
+};
+
+/******************************************************************************\
+************************ gckVGCOMMAND Object Internal API. ***********************
+\******************************************************************************/
+
+/* Initialize architecture dependent command buffer information. */
+gceSTATUS
+gckVGCOMMAND_InitializeInfo(
+ IN gckVGCOMMAND Command
+ );
+
+/* Form a STATE command at the specified location in the command buffer. */
+gceSTATUS
+gckVGCOMMAND_StateCommand(
+ IN gckVGCOMMAND Command,
+ IN gctUINT32 Pipe,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Address,
+ IN gctUINT32 Count,
+ IN OUT gctUINT32 * Bytes
+ );
+
+/* Form a RESTART command at the specified location in the command buffer. */
+gceSTATUS
+gckVGCOMMAND_RestartCommand(
+ IN gckVGCOMMAND Command,
+ IN gctPOINTER Logical,
+ IN gctUINT32 FetchAddress,
+ IN gctUINT FetchCount,
+ IN OUT gctUINT32 * Bytes
+ );
+
+/* Form a FETCH command at the specified location in the command buffer. */
+gceSTATUS
+gckVGCOMMAND_FetchCommand(
+ IN gckVGCOMMAND Command,
+ IN gctPOINTER Logical,
+ IN gctUINT32 FetchAddress,
+ IN gctUINT FetchCount,
+ IN OUT gctUINT32 * Bytes
+ );
+
+/* Form a CALL command at the specified location in the command buffer. */
+gceSTATUS
+gckVGCOMMAND_CallCommand(
+ IN gckVGCOMMAND Command,
+ IN gctPOINTER Logical,
+ IN gctUINT32 FetchAddress,
+ IN gctUINT FetchCount,
+ IN OUT gctUINT32 * Bytes
+ );
+
+/* Form a RETURN command at the specified location in the command buffer. */
+gceSTATUS
+gckVGCOMMAND_ReturnCommand(
+ IN gckVGCOMMAND Command,
+ IN gctPOINTER Logical,
+ IN OUT gctUINT32 * Bytes
+ );
+
+/* Form an EVENT command at the specified location in the command buffer. */
+gceSTATUS
+gckVGCOMMAND_EventCommand(
+ IN gckVGCOMMAND Command,
+ IN gctPOINTER Logical,
+ IN gceBLOCK Block,
+ IN gctINT32 InterruptId,
+ IN OUT gctUINT32 * Bytes
+ );
+
+/* Form an END command at the specified location in the command buffer. */
+gceSTATUS
+gckVGCOMMAND_EndCommand(
+ IN gckVGCOMMAND Command,
+ IN gctPOINTER Logical,
+ IN gctINT32 InterruptId,
+ IN OUT gctUINT32 * Bytes
+ );
+
+#endif /* __gc_hal_kernel_hardware_command_h_ */
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_vg.c b/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_vg.c
new file mode 100644
index 000000000000..a4f7f7f0a8a1
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_vg.c
@@ -0,0 +1,2302 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_hardware_command_vg.h"
+
+#include "gc_feature_database.h"
+
+#if gcdENABLE_VG
+
+#define _GC_OBJ_ZONE gcvZONE_HARDWARE
+
+typedef enum
+{
+ gcvPOWER_FLAG_INITIALIZE = 1 << 0,
+ gcvPOWER_FLAG_STALL = 1 << 1,
+ gcvPOWER_FLAG_STOP = 1 << 2,
+ gcvPOWER_FLAG_START = 1 << 3,
+ gcvPOWER_FLAG_RELEASE = 1 << 4,
+ gcvPOWER_FLAG_DELAY = 1 << 5,
+ gcvPOWER_FLAG_SAVE = 1 << 6,
+ gcvPOWER_FLAG_ACQUIRE = 1 << 7,
+ gcvPOWER_FLAG_POWER_OFF = 1 << 8,
+ gcvPOWER_FLAG_CLOCK_OFF = 1 << 9,
+ gcvPOWER_FLAG_CLOCK_ON = 1 << 10,
+ gcvPOWER_FLAG_NOP = 1 << 11,
+}
+gcePOWER_FLAGS;
+
+/******************************************************************************\
+********************************* Support Code *********************************
+\******************************************************************************/
+static gceSTATUS
+_ResetGPU(
+ IN gckOS Os
+ )
+{
+ gctUINT32 control, idle;
+ gceSTATUS status;
+
+ /* Read register. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Os,
+ gcvCORE_VG,
+ 0x00000,
+ &control));
+
+ for (;;)
+ {
+ /* Disable clock gating. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ gcvCORE_VG,
+ 0x00104,
+ 0x00000000));
+
+ /* Wait for clock being stable. */
+ gcmkONERROR(gckOS_Delay(Os, 1));
+
+ /* Isolate the GPU. */
+ control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:19) - (0 ? 19:19) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 19:19) - (0 ? 19:19) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ? 19:19)));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ gcvCORE_VG,
+ 0x00000,
+ control));
+
+ /* Set soft reset. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ gcvCORE_VG,
+ 0x00000,
+ ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ? 12:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ? 12:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ? 12:12)))));
+
+ /* Wait for reset. */
+ gcmkONERROR(gckOS_Delay(Os, 1));
+
+ /* Reset soft reset bit. */
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ gcvCORE_VG,
+ 0x00000,
+ ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 12:12) - (0 ? 12:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 12:12) - (0 ? 12:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 12:12) - (0 ?
+ 12:12) + 1))))))) << (0 ? 12:12)))));
+
+ /* Reset GPU isolation. */
+ control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 19:19) - (0 ? 19:19) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ?
+ 19:19) - (0 ? 19:19) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 19:19) - (0 ?
+ 19:19) + 1))))))) << (0 ? 19:19)));
+
+ gcmkONERROR(gckOS_WriteRegisterEx(Os,
+ gcvCORE_VG,
+ 0x00000,
+ control));
+
+ /* Read idle register. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Os,
+ gcvCORE_VG,
+ 0x00004,
+ &idle));
+
+ if ((((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ) == 0)
+ {
+ continue;
+ }
+
+ /* Read reset register. */
+ gcmkONERROR(gckOS_ReadRegisterEx(Os,
+ gcvCORE_VG,
+ 0x00000,
+ &control));
+
+ if (((((((gctUINT32) (control)) >> (0 ? 16:16)) & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1)))))) ) == 0)
+ || ((((((gctUINT32) (control)) >> (0 ? 17:17)) & ((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 17:17) - (0 ? 17:17) + 1)))))) ) == 0)
+ )
+ {
+ continue;
+ }
+
+ /* GPU is idle. */
+ break;
+ }
+
+ /* Success. */
+ return gcvSTATUS_OK;
+
+OnError:
+
+ /* Return the error. */
+ return status;
+}
+
+
+static gceSTATUS
+_IdentifyHardware(
+ IN gckOS Os,
+ IN gckVGHARDWARE Hardware,
+ OUT gceCHIPMODEL * ChipModel,
+ OUT gctUINT32 * ChipRevision,
+ OUT gctUINT32 * ChipFeatures,
+ OUT gctUINT32 * ChipMinorFeatures,
+ OUT gctUINT32 * ChipMinorFeatures2
+ )
+{
+ gceSTATUS status;
+ gctUINT32 chipIdentity;
+
+ do
+ {
+ /* Read chip identity register. */
+ gcmkERR_BREAK(gckOS_ReadRegisterEx(Os, gcvCORE_VG, 0x00018, &chipIdentity));
+
+ /* Special case for older graphic cores. */
+ if (((((gctUINT32) (chipIdentity)) >> (0 ? 31:24) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))))
+ {
+ *ChipModel = gcv500;
+ *ChipRevision = (((((gctUINT32) (chipIdentity)) >> (0 ? 15:12)) & ((gctUINT32) ((((1 ? 15:12) - (0 ? 15:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:12) - (0 ? 15:12) + 1)))))) );
+ }
+
+ else
+ {
+ /* Read chip identity register. */
+ gcmkERR_BREAK(gckOS_ReadRegisterEx(Os, gcvCORE_VG,
+ 0x00020,
+ (gctUINT32 *) ChipModel));
+
+ /* Read CHIP_REV register. */
+ gcmkERR_BREAK(gckOS_ReadRegisterEx(Os, gcvCORE_VG,
+ 0x00024,
+ ChipRevision));
+ }
+
+ /* Read chip feature register. */
+ gcmkERR_BREAK(gckOS_ReadRegisterEx(
+ Os, gcvCORE_VG, 0x0001C, ChipFeatures
+ ));
+
+ /* Read chip minor feature register. */
+ gcmkERR_BREAK(gckOS_ReadRegisterEx(
+ Os, gcvCORE_VG, 0x00034, ChipMinorFeatures
+ ));
+
+ /* Read chip minor feature register #2. */
+ gcmkERR_BREAK(gckOS_ReadRegisterEx(
+ Os, gcvCORE_VG, 0x00074, ChipMinorFeatures2
+ ));
+
+ gcmkERR_BREAK(gckOS_ReadRegisterEx(
+ Os, gcvCORE_VG, 0x000A8, &Hardware->productID
+ ));
+
+ gcmkERR_BREAK(gckOS_ReadRegisterEx(
+ Os, gcvCORE_VG, 0x000E8, &Hardware->ecoID
+ ));
+
+ gcmkERR_BREAK(gckOS_ReadRegisterEx(
+ Os, gcvCORE_VG, 0x00030, &Hardware->customerID
+ ));
+
+ gcmkTRACE(
+ gcvLEVEL_VERBOSE,
+ "ChipModel=0x%08X\n"
+ "ChipRevision=0x%08X\n"
+ "ChipFeatures=0x%08X\n"
+ "ChipMinorFeatures=0x%08X\n"
+ "ChipMinorFeatures2=0x%08X\n",
+ *ChipModel,
+ *ChipRevision,
+ *ChipFeatures,
+ *ChipMinorFeatures,
+ *ChipMinorFeatures2
+ );
+
+ /* Success. */
+ return gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ /* Return the status. */
+ return status;
+}
+
+#if gcdPOWEROFF_TIMEOUT
+void
+_VGPowerTimerFunction(
+ gctPOINTER Data
+ )
+{
+ gckVGHARDWARE hardware = (gckVGHARDWARE)Data;
+ gcmkVERIFY_OK(
+ gckVGHARDWARE_SetPowerManagementState(hardware, gcvPOWER_OFF_TIMEOUT));
+}
+#endif
+
+/******************************************************************************\
+****************************** gckVGHARDWARE API code *****************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+** gckVGHARDWARE_Construct
+**
+** Construct a new gckVGHARDWARE object.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an initialized gckOS object.
+**
+** OUTPUT:
+**
+** gckVGHARDWARE * Hardware
+** Pointer to a variable that will hold the pointer to the gckVGHARDWARE
+** object.
+*/
+gceSTATUS
+gckVGHARDWARE_Construct(
+ IN gckOS Os,
+ OUT gckVGHARDWARE * Hardware
+ )
+{
+ gckVGHARDWARE hardware = gcvNULL;
+ gceSTATUS status;
+ gceCHIPMODEL chipModel;
+ gctUINT32 chipRevision;
+ gctUINT32 chipFeatures;
+ gctUINT32 chipMinorFeatures;
+ gctUINT32 chipMinorFeatures2;
+ gcsFEATURE_DATABASE * database;
+
+ gcmkHEADER_ARG("Os=0x%x Hardware=0x%x ", Os, Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Hardware != gcvNULL);
+
+ do
+ {
+ gcmkERR_BREAK(gckOS_SetGPUPower(Os, gcvCORE_VG, gcvTRUE, gcvTRUE));
+
+ status = _ResetGPU(Os);
+
+ if (status != gcvSTATUS_OK)
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "_ResetGPU failed: status=%d\n", status);
+ }
+
+ /* Allocate the gckVGHARDWARE object. */
+ gcmkERR_BREAK(gckOS_Allocate(Os,
+ gcmSIZEOF(struct _gckVGHARDWARE), (gctPOINTER *) &hardware
+ ));
+
+ /* Identify the hardware. */
+ gcmkERR_BREAK(_IdentifyHardware(Os, hardware,
+ &chipModel, &chipRevision,
+ &chipFeatures, &chipMinorFeatures, &chipMinorFeatures2
+ ));
+
+ /* Initialize the gckVGHARDWARE object. */
+ hardware->object.type = gcvOBJ_HARDWARE;
+ hardware->os = Os;
+
+ /* Set chip identity. */
+ hardware->chipModel = chipModel;
+ hardware->chipRevision = chipRevision;
+ hardware->chipFeatures = chipFeatures;
+ hardware->chipMinorFeatures = chipMinorFeatures;
+ hardware->chipMinorFeatures2 = chipMinorFeatures2;
+
+ hardware->powerMutex = gcvNULL;
+ hardware->chipPowerState = gcvPOWER_ON;
+ hardware->chipPowerStateGlobal = gcvPOWER_ON;
+ hardware->clockState = gcvTRUE;
+ hardware->powerState = gcvTRUE;
+
+#if gcdPOWEROFF_TIMEOUT
+ hardware->powerOffTime = 0;
+ hardware->powerOffTimeout = gcdPOWEROFF_TIMEOUT;
+
+ gcmkVERIFY_OK(gckOS_CreateTimer(Os,
+ _VGPowerTimerFunction,
+ (gctPOINTER)hardware,
+ &hardware->powerOffTimer));
+#endif
+
+ database = hardware->featureDatabase = gcQueryFeatureDB(
+ hardware->chipModel,
+ hardware->chipRevision,
+ hardware->productID,
+ hardware->ecoID,
+ hardware->customerID
+ );
+
+ if (database == gcvNULL)
+ {
+ gcmkPRINT("[galcore]: Feature database is not found,"
+ "chipModel=0x%0x, chipRevision=0x%x, productID=0x%x, ecoID=0x%x",
+ hardware->chipModel,
+ hardware->chipRevision,
+ hardware->productID,
+ hardware->ecoID);
+ /* gcmkERR_BREAK(gcvSTATUS_NOT_FOUND); */
+ }
+
+ /* Determine whether FE 2.0 is present. */
+ hardware->fe20 = ((((gctUINT32) (hardware->chipFeatures)) >> (0 ?
+ 28:28) & ((gctUINT32) ((((1 ? 28:28) - (0 ? 28:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ?
+ 28:28) - (0 ? 28:28) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 28:28) - (0 ?
+ 28:28) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 28:28) - (0 ? 28:28) + 1)))))));
+
+ /* Determine whether VG 2.0 is present. */
+ hardware->vg20 = ((((gctUINT32) (hardware->chipMinorFeatures)) >> (0 ?
+ 13:13) & ((gctUINT32) ((((1 ? 13:13) - (0 ? 13:13) + 1) == 32) ? ~0U : (~(~0U << ((1 ?
+ 13:13) - (0 ? 13:13) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 13:13) - (0 ?
+ 13:13) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 13:13) - (0 ? 13:13) + 1)))))));
+
+ /* Determine whether VG 2.1 is present. */
+ hardware->vg21 = ((((gctUINT32) (hardware->chipMinorFeatures)) >> (0 ?
+ 18:18) & ((gctUINT32) ((((1 ? 18:18) - (0 ? 18:18) + 1) == 32) ? ~0U : (~(~0U << ((1 ?
+ 18:18) - (0 ? 18:18) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 18:18) - (0 ?
+ 18:18) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 18:18) - (0 ? 18:18) + 1)))))));
+
+ /* Determine whether fc is present. */
+ hardware->fc = (((((gctUINT32) (hardware->chipFeatures)) >> (0 ? 0:0 )) & ((gctUINT32) ((((1 ? 0:0 ) - (0 ? 0:0 ) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0 ) - (0 ? 0:0 ) + 1)))))) );
+
+
+ /* Set default event mask. */
+ hardware->eventMask = 0xFFFFFFFF;
+
+ gcmkERR_BREAK(gckOS_AtomConstruct(Os, &hardware->pageTableDirty));
+
+ /* Set fast clear to auto. */
+ gcmkVERIFY_OK(gckVGHARDWARE_SetFastClear(hardware, -1));
+
+ gcmkERR_BREAK(gckOS_CreateMutex(Os, &hardware->powerMutex));
+
+ /* Enable power management by default. */
+ hardware->options.powerManagement = gcvTRUE;
+
+ /* Return pointer to the gckVGHARDWARE object. */
+ *Hardware = hardware;
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+#if gcdPOWEROFF_TIMEOUT
+ if (hardware != gcvNULL && hardware->powerOffTimer != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_StopTimer(Os, hardware->powerOffTimer));
+ gcmkVERIFY_OK(gckOS_DestroyTimer(Os, hardware->powerOffTimer));
+ }
+#endif
+
+ gcmkVERIFY_OK(gckOS_SetGPUPower(Os, gcvCORE_VG, gcvFALSE, gcvFALSE));
+
+ if (hardware != gcvNULL && hardware->pageTableDirty != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_AtomDestroy(Os, hardware->pageTableDirty));
+ }
+
+ if (hardware != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_Free(Os, hardware));
+ }
+
+ gcmkFOOTER();
+ /* Return the status. */
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckVGHARDWARE_Destroy
+**
+** Destroy an gckVGHARDWARE object.
+**
+** INPUT:
+**
+** gckVGHARDWARE Hardware
+** Pointer to the gckVGHARDWARE object that needs to be destroyed.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckVGHARDWARE_Destroy(
+ IN gckVGHARDWARE Hardware
+ )
+{
+ gceSTATUS status;
+ gcmkHEADER_ARG("Hardware=0x%x ", Hardware);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ /* Mark the object as unknown. */
+ Hardware->object.type = gcvOBJ_UNKNOWN;
+
+ if (Hardware->powerMutex != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_DeleteMutex(
+ Hardware->os, Hardware->powerMutex));
+ }
+
+#if gcdPOWEROFF_TIMEOUT
+ gcmkVERIFY_OK(gckOS_StopTimer(Hardware->os, Hardware->powerOffTimer));
+ gcmkVERIFY_OK(gckOS_DestroyTimer(Hardware->os, Hardware->powerOffTimer));
+#endif
+
+ if (Hardware->pageTableDirty != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_AtomDestroy(Hardware->os, Hardware->pageTableDirty));
+ }
+
+ /* Free the object. */
+ status = gckOS_Free(Hardware->os, Hardware);
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckVGHARDWARE_QueryMemory
+**
+** Query the amount of memory available on the hardware.
+**
+** INPUT:
+**
+** gckVGHARDWARE Hardware
+** Pointer to the gckVGHARDWARE object.
+**
+** OUTPUT:
+**
+** gctSIZE_T * InternalSize
+** Pointer to a variable that will hold the size of the internal video
+** memory in bytes. If 'InternalSize' is gcvNULL, no information of the
+** internal memory will be returned.
+**
+** gctUINT32 * InternalBaseAddress
+** Pointer to a variable that will hold the hardware's base address for
+** the internal video memory. This pointer cannot be gcvNULL if
+** 'InternalSize' is also non-gcvNULL.
+**
+** gctUINT32 * InternalAlignment
+** Pointer to a variable that will hold the hardware's base address for
+** the internal video memory. This pointer cannot be gcvNULL if
+** 'InternalSize' is also non-gcvNULL.
+**
+** gctSIZE_T * ExternalSize
+** Pointer to a variable that will hold the size of the external video
+** memory in bytes. If 'ExternalSize' is gcvNULL, no information of the
+** external memory will be returned.
+**
+** gctUINT32 * ExternalBaseAddress
+** Pointer to a variable that will hold the hardware's base address for
+** the external video memory. This pointer cannot be gcvNULL if
+** 'ExternalSize' is also non-gcvNULL.
+**
+** gctUINT32 * ExternalAlignment
+** Pointer to a variable that will hold the hardware's base address for
+** the external video memory. This pointer cannot be gcvNULL if
+** 'ExternalSize' is also non-gcvNULL.
+**
+** gctUINT32 * HorizontalTileSize
+** Number of horizontal pixels per tile. If 'HorizontalTileSize' is
+** gcvNULL, no horizontal pixel per tile will be returned.
+**
+** gctUINT32 * VerticalTileSize
+** Number of vertical pixels per tile. If 'VerticalTileSize' is
+** gcvNULL, no vertical pixel per tile will be returned.
+*/
+gceSTATUS
+gckVGHARDWARE_QueryMemory(
+ IN gckVGHARDWARE Hardware,
+ OUT gctSIZE_T * InternalSize,
+ OUT gctUINT32 * InternalBaseAddress,
+ OUT gctUINT32 * InternalAlignment,
+ OUT gctSIZE_T * ExternalSize,
+ OUT gctUINT32 * ExternalBaseAddress,
+ OUT gctUINT32 * ExternalAlignment,
+ OUT gctUINT32 * HorizontalTileSize,
+ OUT gctUINT32 * VerticalTileSize
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x InternalSize=0x%x InternalBaseAddress=0x%x InternalAlignment=0x%x"
+ "ExternalSize=0x%x ExternalBaseAddress=0x%x ExternalAlignment=0x%x HorizontalTileSize=0x%x VerticalTileSize=0x%x",
+ Hardware, InternalSize, InternalBaseAddress, InternalAlignment,
+ ExternalSize, ExternalBaseAddress, ExternalAlignment, HorizontalTileSize, VerticalTileSize);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ if (InternalSize != gcvNULL)
+ {
+ /* No internal memory. */
+ *InternalSize = 0;
+ }
+
+ if (ExternalSize != gcvNULL)
+ {
+ /* No external memory. */
+ *ExternalSize = 0;
+ }
+
+ if (HorizontalTileSize != gcvNULL)
+ {
+ /* 4x4 tiles. */
+ *HorizontalTileSize = 4;
+ }
+
+ if (VerticalTileSize != gcvNULL)
+ {
+ /* 4x4 tiles. */
+ *VerticalTileSize = 4;
+ }
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckVGHARDWARE_QueryChipIdentity
+**
+** Query the identity of the hardware.
+**
+** INPUT:
+**
+** gckVGHARDWARE Hardware
+** Pointer to the gckVGHARDWARE object.
+**
+** OUTPUT:
+**
+** gceCHIPMODEL * ChipModel
+** If 'ChipModel' is not gcvNULL, the variable it points to will
+** receive the model of the chip.
+**
+** gctUINT32 * ChipRevision
+** If 'ChipRevision' is not gcvNULL, the variable it points to will
+** receive the revision of the chip.
+**
+** gctUINT32 * ChipFeatures
+** If 'ChipFeatures' is not gcvNULL, the variable it points to will
+** receive the feature set of the chip.
+**
+** gctUINT32 * ChipMinorFeatures
+** If 'ChipMinorFeatures' is not gcvNULL, the variable it points to
+** will receive the minor feature set of the chip.
+**
+** gctUINT32 * ChipMinorFeatures2
+** If 'ChipMinorFeatures2' is not gcvNULL, the variable it points to
+** will receive the minor feature set of the chip.
+**
+*/
+gceSTATUS
+gckVGHARDWARE_QueryChipIdentity(
+ IN gckVGHARDWARE Hardware,
+ OUT gceCHIPMODEL * ChipModel,
+ OUT gctUINT32 * ChipRevision,
+ OUT gctUINT32 * ProductID,
+ OUT gctUINT32 * EcoID,
+ OUT gctUINT32* CustomerID,
+ OUT gctUINT32* ChipFeatures,
+ OUT gctUINT32* ChipMinorFeatures,
+ OUT gctUINT32* ChipMinorFeatures2
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x ChipModel=0x%x ChipRevision=0x%x ChipFeatures = 0x%x ChipMinorFeatures = 0x%x ChipMinorFeatures2 = 0x%x",
+ Hardware, ChipModel, ChipRevision, ChipFeatures, ChipMinorFeatures, ChipMinorFeatures2);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ /* Return chip model. */
+ if (ChipModel != gcvNULL)
+ {
+ *ChipModel = Hardware->chipModel;
+ }
+
+ /* Return revision number. */
+ if (ChipRevision != gcvNULL)
+ {
+ *ChipRevision = Hardware->chipRevision;
+ }
+
+ /* Return feature set. */
+ if (ChipFeatures != gcvNULL)
+ {
+ gctUINT32 features = Hardware->chipFeatures;
+
+ if (Hardware->fc)
+ {
+ features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (Hardware->options.allowFastClear) & ((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0)));
+ }
+
+ /* Mark 2D pipe as available for GC500.0 since it did not have this *\
+ \* bit. */
+ if ((Hardware->chipModel == gcv500)
+ && (Hardware->chipRevision == 0)
+ )
+ {
+ features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ? 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9)));
+ }
+
+ /* Mark 2D pipe as available for GC300 since it did not have this *\
+ \* bit. */
+ if (Hardware->chipModel == gcv300)
+ {
+ features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 9:9) - (0 ? 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ?
+ 9:9))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9)));
+ }
+
+ *ChipFeatures = features;
+ }
+
+ /* Return minor feature set. */
+ if (ChipMinorFeatures != gcvNULL)
+ {
+ *ChipMinorFeatures = Hardware->chipMinorFeatures;
+ }
+
+ /* Return minor feature set #2. */
+ if (ChipMinorFeatures2 != gcvNULL)
+ {
+ *ChipMinorFeatures2 = Hardware->chipMinorFeatures2;
+ }
+
+ if (ProductID != gcvNULL)
+ {
+ *ProductID = Hardware->productID;
+ }
+
+ if (EcoID != gcvNULL)
+ {
+ *EcoID = Hardware->ecoID;
+ }
+
+ if (CustomerID != gcvNULL)
+ {
+ *CustomerID = Hardware->customerID;
+ }
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckVGHARDWARE_ConvertFormat
+**
+** Convert an API format to hardware parameters.
+**
+** INPUT:
+**
+** gckVGHARDWARE Hardware
+** Pointer to the gckVGHARDWARE object.
+**
+** gceSURF_FORMAT Format
+** API format to convert.
+**
+** OUTPUT:
+**
+** gctUINT32 * BitsPerPixel
+** Pointer to a variable that will hold the number of bits per pixel.
+**
+** gctUINT32 * BytesPerTile
+** Pointer to a variable that will hold the number of bytes per tile.
+*/
+gceSTATUS
+gckVGHARDWARE_ConvertFormat(
+ IN gckVGHARDWARE Hardware,
+ IN gceSURF_FORMAT Format,
+ OUT gctUINT32 * BitsPerPixel,
+ OUT gctUINT32 * BytesPerTile
+ )
+{
+ gctUINT32 bitsPerPixel;
+ gctUINT32 bytesPerTile;
+
+ gcmkHEADER_ARG("Hardware=0x%x Format=0x%x BitsPerPixel=0x%x BytesPerTile = 0x%x",
+ Hardware, Format, BitsPerPixel, BytesPerTile);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ /* Dispatch on format. */
+ switch (Format)
+ {
+ case gcvSURF_A1:
+ case gcvSURF_L1:
+ /* 1-bpp format. */
+ bitsPerPixel = 1;
+ bytesPerTile = (1 * 4 * 4) / 8;
+ break;
+
+ case gcvSURF_A4:
+ /* 4-bpp format. */
+ bitsPerPixel = 4;
+ bytesPerTile = (4 * 4 * 4) / 8;
+ break;
+
+ case gcvSURF_INDEX8:
+ case gcvSURF_A8:
+ case gcvSURF_L8:
+ /* 8-bpp format. */
+ bitsPerPixel = 8;
+ bytesPerTile = (8 * 4 * 4) / 8;
+ break;
+
+ case gcvSURF_YV12:
+ /* 12-bpp planar YUV formats. */
+ bitsPerPixel = 12;
+ bytesPerTile = (12 * 4 * 4) / 8;
+ break;
+
+ case gcvSURF_NV12:
+ /* 12-bpp planar YUV formats. */
+ bitsPerPixel = 12;
+ bytesPerTile = (12 * 4 * 4) / 8;
+ break;
+
+ /* 4444 variations. */
+ case gcvSURF_X4R4G4B4:
+ case gcvSURF_A4R4G4B4:
+ case gcvSURF_R4G4B4X4:
+ case gcvSURF_R4G4B4A4:
+ case gcvSURF_B4G4R4X4:
+ case gcvSURF_B4G4R4A4:
+ case gcvSURF_X4B4G4R4:
+ case gcvSURF_A4B4G4R4:
+
+ /* 1555 variations. */
+ case gcvSURF_X1R5G5B5:
+ case gcvSURF_A1R5G5B5:
+ case gcvSURF_R5G5B5X1:
+ case gcvSURF_R5G5B5A1:
+ case gcvSURF_X1B5G5R5:
+ case gcvSURF_A1B5G5R5:
+ case gcvSURF_B5G5R5X1:
+ case gcvSURF_B5G5R5A1:
+
+ /* 565 variations. */
+ case gcvSURF_R5G6B5:
+ case gcvSURF_B5G6R5:
+
+ case gcvSURF_A8L8:
+ case gcvSURF_YUY2:
+ case gcvSURF_UYVY:
+ case gcvSURF_D16:
+ /* 16-bpp format. */
+ bitsPerPixel = 16;
+ bytesPerTile = (16 * 4 * 4) / 8;
+ break;
+
+ case gcvSURF_X8R8G8B8:
+ case gcvSURF_A8R8G8B8:
+ case gcvSURF_X8B8G8R8:
+ case gcvSURF_A8B8G8R8:
+ case gcvSURF_R8G8B8X8:
+ case gcvSURF_R8G8B8A8:
+ case gcvSURF_B8G8R8X8:
+ case gcvSURF_B8G8R8A8:
+ case gcvSURF_D32:
+ /* 32-bpp format. */
+ bitsPerPixel = 32;
+ bytesPerTile = (32 * 4 * 4) / 8;
+ break;
+
+ case gcvSURF_D24S8:
+ /* 24-bpp format. */
+ bitsPerPixel = 32;
+ bytesPerTile = (32 * 4 * 4) / 8;
+ break;
+
+ case gcvSURF_DXT1:
+ case gcvSURF_ETC1:
+ bitsPerPixel = 4;
+ bytesPerTile = (4 * 4 * 4) / 8;
+ break;
+
+ case gcvSURF_DXT2:
+ case gcvSURF_DXT3:
+ case gcvSURF_DXT4:
+ case gcvSURF_DXT5:
+ bitsPerPixel = 8;
+ bytesPerTile = (8 * 4 * 4) / 8;
+ break;
+
+ default:
+ /* Invalid format. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_INVALID_ARGUMENT;
+ }
+
+ /* Set the result. */
+ if (BitsPerPixel != gcvNULL)
+ {
+ * BitsPerPixel = bitsPerPixel;
+ }
+
+ if (BytesPerTile != gcvNULL)
+ {
+ * BytesPerTile = bytesPerTile;
+ }
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckVGHARDWARE_SplitMemory
+**
+** Split a hardware specific memory address into a pool and offset.
+**
+** INPUT:
+**
+** gckVGHARDWARE Hardware
+** Pointer to the gckVGHARDWARE object.
+**
+** gctUINT32 Address
+** Address in hardware specific format.
+**
+** OUTPUT:
+**
+** gcePOOL * Pool
+** Pointer to a variable that will hold the pool type for the address.
+**
+** gctUINT32 * Offset
+** Pointer to a variable that will hold the offset for the address.
+*/
+gceSTATUS
+gckVGHARDWARE_SplitMemory(
+ IN gckVGHARDWARE Hardware,
+ IN gctUINT32 Address,
+ OUT gcePOOL * Pool,
+ OUT gctUINT32 * Offset
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x Address=0x%x Pool=0x%x Offset = 0x%x",
+ Hardware, Address, Pool, Offset);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(Pool != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Offset != gcvNULL);
+
+ /* Dispatch on memory type. */
+ switch ((((((gctUINT32) (Address)) >> (0 ? 1:0)) & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1)))))) ))
+ {
+ case 0x0:
+ /* System memory. */
+ *Pool = gcvPOOL_SYSTEM;
+ break;
+
+ case 0x2:
+ /* Virtual memory. */
+ *Pool = gcvPOOL_VIRTUAL;
+ break;
+
+ default:
+ /* Invalid memory type. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_INVALID_ARGUMENT;
+ }
+
+ /* Return offset of address. */
+ *Offset = ((((gctUINT32) (Address)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ? 1:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:0) - (0 ?
+ 1:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ?
+ 1:0)));
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckVGHARDWARE_Execute
+**
+** Kickstart the hardware's command processor with an initialized command
+** buffer.
+**
+** INPUT:
+**
+** gckVGHARDWARE Hardware
+** Pointer to the gckVGHARDWARE object.
+**
+** gctUINT32 Address
+** Address of the command buffer.
+**
+** gctSIZE_T Count
+** Number of command-sized data units to be executed.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckVGHARDWARE_Execute(
+ IN gckVGHARDWARE Hardware,
+ IN gctUINT32 Address,
+ IN gctUINT32 Count
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Hardware=0x%x Address=0x%x Count=0x%x",
+ Hardware, Address, Count);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ do
+ {
+ /* Enable all events. */
+ gcmkERR_BREAK(gckOS_WriteRegisterEx(
+ Hardware->os,
+ gcvCORE_VG,
+ 0x00014,
+ Hardware->eventMask
+ ));
+
+ if (Hardware->fe20)
+ {
+ /* Write address register. */
+ gcmkERR_BREAK(gckOS_WriteRegisterEx(
+ Hardware->os,
+ gcvCORE_VG,
+ 0x00500,
+ gcmkFIXADDRESS(Address)
+ ));
+
+ /* Write control register. */
+ gcmkERR_BREAK(gckOS_WriteRegisterEx(
+ Hardware->os,
+ gcvCORE_VG,
+ 0x00504,
+ Count
+ ));
+ }
+ else
+ {
+ /* Write address register. */
+ gcmkERR_BREAK(gckOS_WriteRegisterEx(
+ Hardware->os,
+ gcvCORE_VG,
+ 0x00654,
+ gcmkFIXADDRESS(Address)
+ ));
+
+ /* Write control register. */
+ gcmkERR_BREAK(gckOS_WriteRegisterEx(
+ Hardware->os,
+ gcvCORE_VG,
+ 0x00658,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16))) |
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (Count) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ ));
+ }
+
+ /* Success. */
+ gcmkFOOTER();
+ return gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+
+ gcmkFOOTER();
+ /* Return the status. */
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckVGHARDWARE_AlignToTile
+**
+** Align the specified width and height to tile boundaries.
+**
+** INPUT:
+**
+** gckVGHARDWARE Hardware
+** Pointer to an gckVGHARDWARE object.
+**
+** gceSURF_TYPE Type
+** Type of alignment.
+**
+** gctUINT32 * Width
+** Pointer to the width to be aligned. If 'Width' is gcvNULL, no width
+** will be aligned.
+**
+** gctUINT32 * Height
+** Pointer to the height to be aligned. If 'Height' is gcvNULL, no height
+** will be aligned.
+**
+** OUTPUT:
+**
+** gctUINT32 * Width
+** Pointer to a variable that will receive the aligned width.
+**
+** gctUINT32 * Height
+** Pointer to a variable that will receive the aligned height.
+*/
+gceSTATUS
+gckVGHARDWARE_AlignToTile(
+ IN gckVGHARDWARE Hardware,
+ IN gceSURF_TYPE Type,
+ IN OUT gctUINT32 * Width,
+ IN OUT gctUINT32 * Height
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x Type=0x%x Width=0x%x Height=0x%x",
+ Hardware, Type, Width, Height);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ if (Width != gcvNULL)
+ {
+ /* Align the width. */
+ *Width = gcmALIGN(*Width, (Type == gcvSURF_TEXTURE) ? 4 : 16);
+ }
+
+ if (Height != gcvNULL)
+ {
+ /* Special case for VG images. */
+ if ((*Height == 0) && (Type == gcvSURF_IMAGE))
+ {
+ *Height = 4;
+ }
+ else
+ {
+ /* Align the height. */
+ *Height = gcmALIGN(*Height, 4);
+ }
+ }
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckVGHARDWARE_ConvertLogical
+**
+** Convert a logical system address into a hardware specific address.
+**
+** INPUT:
+**
+** gckVGHARDWARE Hardware
+** Pointer to an gckVGHARDWARE object.
+**
+** gctPOINTER Logical
+** Logical address to convert.
+**
+** gctBOOL InUserSpace
+** gcvTRUE if the memory in user space.
+**
+** gctUINT32* Address
+** Return hardware specific address.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckVGHARDWARE_ConvertLogical(
+ IN gckVGHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctBOOL InUserSpace,
+ OUT gctUINT32 * Address
+ )
+{
+ gctPHYS_ADDR_T physical;
+ gctUINT32 address;
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x InUserSpace=%d Address=0x%x",
+ Hardware, Logical, InUserSpace, Address);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+ do
+ {
+ /* Convert logical address into a physical address. */
+ if (InUserSpace)
+ {
+ gcmkERR_BREAK(gckOS_UserLogicalToPhysical(
+ Hardware->os, Logical, &physical
+ ));
+ }
+ else
+ {
+ gcmkERR_BREAK(gckOS_GetPhysicalAddress(
+ Hardware->os, Logical, &physical
+ ));
+ }
+
+ gcmkSAFECASTPHYSADDRT(address, physical);
+
+ /* Return hardware specific address. */
+ *Address = ((((gctUINT32) (address)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ? 1:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)));
+
+ /* Success. */
+ gcmkFOOTER();
+ return gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ gcmkFOOTER();
+ /* Return the status. */
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckVGHARDWARE_QuerySystemMemory
+**
+** Query the command buffer alignment and number of reserved bytes.
+**
+** INPUT:
+**
+** gckVGHARDWARE Harwdare
+** Pointer to an gckVGHARDWARE object.
+**
+** OUTPUT:
+**
+** gctSIZE_T * SystemSize
+** Pointer to a variable that receives the maximum size of the system
+** memory.
+**
+** gctUINT32 * SystemBaseAddress
+** Poinetr to a variable that receives the base address for system
+** memory.
+*/
+gceSTATUS gckVGHARDWARE_QuerySystemMemory(
+ IN gckVGHARDWARE Hardware,
+ OUT gctSIZE_T * SystemSize,
+ OUT gctUINT32 * SystemBaseAddress
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x SystemSize=0x%x SystemBaseAddress=0x%x",
+ Hardware, SystemSize, SystemBaseAddress);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ if (SystemSize != gcvNULL)
+ {
+ /* Maximum system memory can be 2GB. */
+ *SystemSize = (gctSIZE_T)(1 << 31);
+ }
+
+ if (SystemBaseAddress != gcvNULL)
+ {
+ /* Set system memory base address. */
+ *SystemBaseAddress = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ? 1:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)));
+ }
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckVGHARDWARE_SetMMU
+**
+** Set the page table base address.
+**
+** INPUT:
+**
+** gckVGHARDWARE Harwdare
+** Pointer to an gckVGHARDWARE object.
+**
+** gctPOINTER Logical
+** Logical address of the page table.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS gckVGHARDWARE_SetMMU(
+ IN gckVGHARDWARE Hardware,
+ IN gctPOINTER Logical
+ )
+{
+ gceSTATUS status;
+ gctUINT32 address = 0;
+
+ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x",
+ Hardware, Logical);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+ do
+ {
+ /* Convert the logical address into an hardware address. */
+ gcmkERR_BREAK(gckVGHARDWARE_ConvertLogical(Hardware, Logical,
+ gcvFALSE, &address));
+
+ /* Write the AQMemoryFePageTable register. */
+ gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG,
+ 0x00400,
+ gcmkFIXADDRESS(address)));
+
+ /* Write the AQMemoryTxPageTable register. */
+ gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG,
+ 0x00404,
+ gcmkFIXADDRESS(address)));
+
+ /* Write the AQMemoryPePageTable register. */
+ gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG,
+ 0x00408,
+ gcmkFIXADDRESS(address)));
+
+ /* Write the AQMemoryPezPageTable register. */
+ gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG,
+ 0x0040C,
+ gcmkFIXADDRESS(address)));
+
+ /* Write the AQMemoryRaPageTable register. */
+ gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG,
+ 0x00410,
+ gcmkFIXADDRESS(address)));
+ }
+ while (gcvFALSE);
+
+ gcmkFOOTER();
+ /* Return the status. */
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckVGHARDWARE_FlushMMU
+**
+** Flush the page table.
+**
+** INPUT:
+**
+** gckVGHARDWARE Harwdare
+** Pointer to an gckVGHARDWARE object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS gckVGHARDWARE_FlushMMU(
+ IN gckVGHARDWARE Hardware
+ )
+{
+ gceSTATUS status;
+ gckVGCOMMAND command;
+
+ gcmkHEADER_ARG("Hardware=0x%x ", Hardware);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ do
+ {
+ gcsCMDBUFFER_PTR commandBuffer;
+ gctUINT32_PTR buffer;
+
+ /* Create a shortcut to the command buffer object. */
+ command = Hardware->kernel->command;
+
+ /* Allocate command buffer space. */
+ gcmkERR_BREAK(gckVGCOMMAND_Allocate(
+ command, 8, &commandBuffer, (gctPOINTER *) &buffer
+ ));
+
+ gckOS_WriteMemory(
+ Hardware->os,
+ &buffer[0],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E04) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)))
+ );
+
+ gckOS_WriteMemory(
+ Hardware->os,
+ &buffer[1],
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:1) - (0 ? 1:1) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ?
+ 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 2:2) - (0 ? 2:2) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ?
+ 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 3:3) - (0 ? 3:3) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ?
+ 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 4:4) - (0 ? 4:4) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ?
+ 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4)))
+ );
+
+ gcmkERR_BREAK(gckVGCOMMAND_Execute(
+ command,
+ commandBuffer
+ ));
+ }
+ while(gcvFALSE);
+
+ gcmkFOOTER();
+ /* Return the status. */
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckVGHARDWARE_BuildVirtualAddress
+**
+** Build a virtual address.
+**
+** INPUT:
+**
+** gckVGHARDWARE Harwdare
+** Pointer to an gckVGHARDWARE object.
+**
+** gctUINT32 Index
+** Index into page table.
+**
+** gctUINT32 Offset
+** Offset into page.
+**
+** OUTPUT:
+**
+** gctUINT32 * Address
+** Pointer to a variable receiving te hardware address.
+*/
+gceSTATUS gckVGHARDWARE_BuildVirtualAddress(
+ IN gckVGHARDWARE Hardware,
+ IN gctUINT32 Index,
+ IN gctUINT32 Offset,
+ OUT gctUINT32 * Address
+ )
+{
+ gctUINT32 address;
+
+ gcmkHEADER_ARG("Hardware=0x%x Index=0x%x Offset=0x%x Address=0x%x",
+ Hardware, Index, Offset, Address);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+ /* Build virtual address. */
+ address = (Index << 12) | Offset;
+
+ /* Set virtual type. */
+ address = ((((gctUINT32) (address)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 1:0) - (0 ? 1:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ?
+ 1:0))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0)));
+
+ /* Set the result. */
+ *Address = address;
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckVGHARDWARE_GetIdle(
+ IN gckVGHARDWARE Hardware,
+ OUT gctUINT32 * Data
+ )
+{
+ gceSTATUS status;
+ gcmkHEADER_ARG("Hardware=0x%x Data=0x%x", Hardware, Data);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(Data != gcvNULL);
+
+ /* Read register and return. */
+ status = gckOS_ReadRegisterEx(Hardware->os, gcvCORE_VG, 0x00004, Data);
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckVGHARDWARE_SetFastClear(
+ IN gckVGHARDWARE Hardware,
+ IN gctINT Enable
+ )
+{
+ gctUINT32 debug;
+ gceSTATUS status;
+
+ if (!Hardware->fc)
+ {
+ return gcvSTATUS_OK;
+ }
+
+ do
+ {
+ if (Enable == -1)
+ {
+ Enable = (Hardware->chipModel > gcv500) ||
+ ((Hardware->chipModel == gcv500) && (Hardware->chipRevision >= 3));
+ }
+
+ gcmkERR_BREAK(gckOS_ReadRegisterEx(Hardware->os, gcvCORE_VG,
+ 0x00414,
+ &debug));
+
+ debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 20:20) - (0 ? 20:20) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 20:20) - (0 ?
+ 20:20) + 1))))))) << (0 ? 20:20))) | (((gctUINT32) ((gctUINT32) (Enable == 0) & ((gctUINT32) ((((1 ?
+ 20:20) - (0 ? 20:20) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 20:20) - (0 ?
+ 20:20) + 1))))))) << (0 ? 20:20)));
+
+#ifdef AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION
+ debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) - (0 ? AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) - (0 ? AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) + 1))))))) << (0 ?
+ AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION))) | (((gctUINT32) ((gctUINT32) (Enable == 0) & ((gctUINT32) ((((1 ?
+ AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) - (0 ? AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) - (0 ? AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION) + 1))))))) << (0 ?
+ AQ_MEMORY_DEBUG_DISABLE_Z_COMPRESSION)));
+#endif
+
+ gcmkERR_BREAK(gckOS_WriteRegisterEx(Hardware->os, gcvCORE_VG,
+ 0x00414,
+ debug));
+
+ Hardware->options.allowFastClear = Enable;
+
+ status = gcvFALSE;
+ }
+ while (gcvFALSE);
+
+ return status;
+}
+
+gceSTATUS
+gckVGHARDWARE_ReadInterrupt(
+ IN gckVGHARDWARE Hardware,
+ OUT gctUINT32_PTR IDs
+ )
+{
+ gceSTATUS status;
+ gcmkHEADER_ARG("Hardware=0x%x IDs=0x%x", Hardware, IDs);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(IDs != gcvNULL);
+
+ /* Read AQIntrAcknowledge register. */
+ status = gckOS_ReadRegisterEx(Hardware->os, gcvCORE_VG,
+ 0x00010,
+ IDs);
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS _CommandStall(
+ gckVGHARDWARE Hardware)
+{
+ gceSTATUS status;
+ gckVGCOMMAND command;
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ do
+ {
+ gctUINT32_PTR buffer;
+ command = Hardware->kernel->command;
+
+ /* Allocate command buffer space. */
+ gcmkERR_BREAK(gckVGCOMMAND_Allocate(
+ command, 8, &command->powerStallBuffer,
+ (gctPOINTER *) &buffer
+ ));
+
+ gcmkERR_BREAK(gckVGCOMMAND_EventCommand(
+ command, buffer, gcvBLOCK_PIXEL,
+ command->powerStallInt, gcvNULL));
+
+ gcmkERR_BREAK(gckVGCOMMAND_Execute(
+ command,
+ command->powerStallBuffer
+ ));
+
+ /* Wait the signal. */
+ gcmkERR_BREAK(gckOS_WaitSignal(
+ command->os,
+ command->powerStallSignal,
+ gcvTRUE,
+ command->kernel->kernel->timeOut));
+
+
+ }
+ while(gcvFALSE);
+
+ gcmkFOOTER();
+ /* Return the status. */
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_SetPowerManagementState
+**
+** Set GPU to a specified power state.
+**
+** INPUT:
+**
+** gckHARDWARE Harwdare
+** Pointer to an gckHARDWARE object.
+**
+** gceCHIPPOWERSTATE State
+** Power State.
+**
+*/
+gceSTATUS
+gckVGHARDWARE_SetPowerManagementState(
+ IN gckVGHARDWARE Hardware,
+ IN gceCHIPPOWERSTATE State
+ )
+{
+ gceSTATUS status;
+ gckVGCOMMAND command = gcvNULL;
+ gckOS os;
+ gctUINT flag/*, clock*/;
+
+ gctBOOL acquired = gcvFALSE;
+ gctBOOL stall = gcvTRUE;
+ gctBOOL commitMutex = gcvFALSE;
+ gctBOOL mutexAcquired = gcvFALSE;
+
+#if gcdPOWEROFF_TIMEOUT
+ gctBOOL timeout = gcvFALSE;
+ gctBOOL isAfter = gcvFALSE;
+ gctUINT32 currentTime;
+#endif
+
+ gctBOOL broadcast = gcvFALSE;
+ gctUINT32 process, thread;
+ gctBOOL global = gcvFALSE;
+
+#if gcdENABLE_PROFILING
+ gctUINT64 time, freq, mutexTime, onTime, stallTime, stopTime, delayTime,
+ initTime, offTime, startTime, totalTime;
+#endif
+
+ /* State transition flags. */
+ static const gctUINT flags[4][4] =
+ {
+ /* gcvPOWER_ON */
+ { /* ON */ 0,
+ /* OFF */ gcvPOWER_FLAG_ACQUIRE |
+ gcvPOWER_FLAG_STALL |
+ gcvPOWER_FLAG_STOP |
+ gcvPOWER_FLAG_POWER_OFF |
+ gcvPOWER_FLAG_CLOCK_OFF,
+ /* IDLE */ gcvPOWER_FLAG_NOP,
+ /* SUSPEND */ gcvPOWER_FLAG_ACQUIRE |
+ gcvPOWER_FLAG_STALL |
+ gcvPOWER_FLAG_STOP |
+ gcvPOWER_FLAG_CLOCK_OFF,
+ },
+
+ /* gcvPOWER_OFF */
+ { /* ON */ gcvPOWER_FLAG_INITIALIZE |
+ gcvPOWER_FLAG_START |
+ gcvPOWER_FLAG_RELEASE |
+ gcvPOWER_FLAG_DELAY,
+ /* OFF */ 0,
+ /* IDLE */ gcvPOWER_FLAG_INITIALIZE |
+ gcvPOWER_FLAG_START |
+ gcvPOWER_FLAG_RELEASE |
+ gcvPOWER_FLAG_DELAY,
+ /* SUSPEND */ gcvPOWER_FLAG_INITIALIZE |
+ gcvPOWER_FLAG_CLOCK_OFF,
+ },
+
+ /* gcvPOWER_IDLE */
+ { /* ON */ gcvPOWER_FLAG_NOP,
+ /* OFF */ gcvPOWER_FLAG_ACQUIRE |
+ gcvPOWER_FLAG_STOP |
+ gcvPOWER_FLAG_POWER_OFF |
+ gcvPOWER_FLAG_CLOCK_OFF,
+ /* IDLE */ 0,
+ /* SUSPEND */ gcvPOWER_FLAG_ACQUIRE |
+ gcvPOWER_FLAG_STOP |
+ gcvPOWER_FLAG_CLOCK_OFF,
+ },
+
+ /* gcvPOWER_SUSPEND */
+ { /* ON */ gcvPOWER_FLAG_START |
+ gcvPOWER_FLAG_RELEASE |
+ gcvPOWER_FLAG_DELAY |
+ gcvPOWER_FLAG_CLOCK_ON,
+ /* OFF */ gcvPOWER_FLAG_SAVE |
+ gcvPOWER_FLAG_POWER_OFF |
+ gcvPOWER_FLAG_CLOCK_OFF,
+ /* IDLE */ gcvPOWER_FLAG_START |
+ gcvPOWER_FLAG_DELAY |
+ gcvPOWER_FLAG_RELEASE |
+ gcvPOWER_FLAG_CLOCK_ON,
+ /* SUSPEND */ 0,
+ },
+ };
+
+ gcmkHEADER_ARG("Hardware=0x%x State=%d", Hardware, State);
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "Switching to power state %d",
+ State);
+#endif
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ /* Get the gckOS object pointer. */
+ os = Hardware->os;
+ gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+ /* Get the gckCOMMAND object pointer. */
+ gcmkVERIFY_OBJECT(Hardware->kernel, gcvOBJ_KERNEL);
+ command = Hardware->kernel->command;
+ gcmkVERIFY_OBJECT(command, gcvOBJ_COMMAND);
+
+ if (Hardware->options.powerManagement == gcvFALSE)
+ {
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+ /* Start profiler. */
+ gcmkPROFILE_INIT(freq, time);
+
+ /* Convert the broadcast power state. */
+ switch (State)
+ {
+ case gcvPOWER_IDLE_BROADCAST:
+ /* Convert to IDLE and note we are inside broadcast. */
+ State = gcvPOWER_IDLE;
+ broadcast = gcvTRUE;
+ break;
+
+ case gcvPOWER_SUSPEND_BROADCAST:
+ /* Convert to SUSPEND and note we are inside broadcast. */
+ State = gcvPOWER_SUSPEND;
+ broadcast = gcvTRUE;
+ break;
+
+ case gcvPOWER_OFF_BROADCAST:
+ /* Convert to OFF and note we are inside broadcast. */
+ State = gcvPOWER_OFF;
+ broadcast = gcvTRUE;
+ break;
+
+ case gcvPOWER_ON_AUTO:
+ /* Convert to ON and note we are inside recovery. */
+ State = gcvPOWER_ON;
+ break;
+
+ case gcvPOWER_ON:
+ case gcvPOWER_IDLE:
+ case gcvPOWER_SUSPEND:
+ case gcvPOWER_OFF:
+ /* Mark as global power management. */
+ global = gcvTRUE;
+ break;
+
+#if gcdPOWEROFF_TIMEOUT
+ case gcvPOWER_OFF_TIMEOUT:
+ /* Convert to OFF and note we are inside broadcast. */
+ State = gcvPOWER_OFF;
+ broadcast = gcvTRUE;
+ /* Check time out */
+ timeout = gcvTRUE;
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ /* Get current process and thread IDs. */
+ gcmkONERROR(gckOS_GetProcessID(&process));
+ gcmkONERROR(gckOS_GetThreadID(&thread));
+
+ /* Acquire the power mutex. */
+ if (broadcast)
+ {
+ /* Try to acquire the power mutex. */
+ status = gckOS_AcquireMutex(os, Hardware->powerMutex, 0);
+
+ if (status == gcvSTATUS_TIMEOUT)
+ {
+ /* Check if we already own this mutex. */
+ if ((Hardware->powerProcess == process)
+ && (Hardware->powerThread == thread)
+ )
+ {
+ /* Bail out on recursive power management. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+ else if (State == gcvPOWER_IDLE)
+ {
+ /* gcvPOWER_IDLE_BROADCAST is from IST,
+ ** so waiting here will cause deadlock,
+ ** if lock holder call gckCOMMAND_Stall() */
+ gcmkONERROR(gcvSTATUS_INVALID_REQUEST);
+ }
+ else
+ {
+ /* Acquire the power mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(os,
+ Hardware->powerMutex,
+ gcvINFINITE));
+ }
+ }
+ }
+ else
+ {
+ /* Acquire the power mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(os, Hardware->powerMutex, gcvINFINITE));
+ }
+
+ /* Get time until mtuex acquired. */
+ gcmkPROFILE_QUERY(time, mutexTime);
+
+ Hardware->powerProcess = process;
+ Hardware->powerThread = thread;
+ mutexAcquired = gcvTRUE;
+
+ /* Grab control flags and clock. */
+ flag = flags[Hardware->chipPowerState][State];
+ /*clock = clocks[State];*/
+
+#if gcdPOWEROFF_TIMEOUT
+ if (timeout)
+ {
+ gcmkONERROR(gckOS_GetTicks(&currentTime));
+
+ gcmkONERROR(
+ gckOS_TicksAfter(Hardware->powerOffTime, currentTime, &isAfter));
+
+ /* powerOffTime is pushed forward, give up.*/
+ if (isAfter
+ /* Expect a transition start from IDLE. */
+ || (Hardware->chipPowerState == gcvPOWER_ON)
+ || (Hardware->chipPowerState == gcvPOWER_OFF)
+ )
+ {
+ /* Release the power mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex));
+
+ /* No need to do anything. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+ }
+#endif
+
+ if (flag == 0)
+ {
+ /* Release the power mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex));
+
+ /* No need to do anything. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+ /* internal power control */
+ if (!global)
+ {
+ if (Hardware->chipPowerStateGlobal == gcvPOWER_OFF)
+ {
+ /* Release the power mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex));
+
+ /* No need to do anything. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+ }
+ else
+ {
+ if (flag & gcvPOWER_FLAG_ACQUIRE)
+ {
+ /* Acquire the power management semaphore. */
+ gcmkONERROR(gckOS_AcquireSemaphore(os, command->powerSemaphore));
+ acquired = gcvTRUE;
+
+ /* avoid acquiring again. */
+ flag &= ~gcvPOWER_FLAG_ACQUIRE;
+ }
+ }
+
+ if (flag & (gcvPOWER_FLAG_INITIALIZE | gcvPOWER_FLAG_CLOCK_ON))
+ {
+ /* Turn on the power. */
+ gcmkONERROR(gckOS_SetGPUPower(os, gcvCORE_VG, gcvTRUE, gcvTRUE));
+
+ /* Mark clock and power as enabled. */
+ Hardware->clockState = gcvTRUE;
+ Hardware->powerState = gcvTRUE;
+ }
+
+ /* Get time until powered on. */
+ gcmkPROFILE_QUERY(time, onTime);
+
+ if ((flag & gcvPOWER_FLAG_STALL) && stall)
+ {
+ /* Acquire the mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(
+ command->os,
+ command->commitMutex,
+ gcvINFINITE
+ ));
+
+ commitMutex = gcvTRUE;
+
+ gcmkONERROR(_CommandStall(Hardware));
+ }
+
+ /* Get time until stalled. */
+ gcmkPROFILE_QUERY(time, stallTime);
+
+ if (flag & gcvPOWER_FLAG_ACQUIRE)
+ {
+ /* Acquire the power management semaphore. */
+ gcmkONERROR(gckOS_AcquireSemaphore(os, command->powerSemaphore));
+
+ acquired = gcvTRUE;
+ }
+
+
+ /* Get time until stopped. */
+ gcmkPROFILE_QUERY(time, stopTime);
+
+
+ if (flag & gcvPOWER_FLAG_DELAY)
+ {
+ /* Wait for the specified amount of time to settle coming back from
+ ** power-off or suspend state. */
+ gcmkONERROR(gckOS_Delay(os, gcdPOWER_CONTROL_DELAY));
+ }
+
+ /* Get time until delayed. */
+ gcmkPROFILE_QUERY(time, delayTime);
+
+ if (flag & gcvPOWER_FLAG_INITIALIZE)
+ {
+
+ /* Initialize GPU here, replaced by InitializeHardware later */
+ gcmkONERROR(gckVGHARDWARE_SetMMU(Hardware, Hardware->kernel->mmu->pageTableLogical));
+ gcmkVERIFY_OK(gckVGHARDWARE_SetFastClear(Hardware, -1));
+
+ /* Force the command queue to reload the next context. */
+ command->currentContext = 0;
+ }
+
+ /* Get time until initialized. */
+ gcmkPROFILE_QUERY(time, initTime);
+
+ if (flag & (gcvPOWER_FLAG_POWER_OFF | gcvPOWER_FLAG_CLOCK_OFF))
+ {
+ /* Turn off the GPU power. */
+ gcmkONERROR(
+ gckOS_SetGPUPower(os,
+ gcvCORE_VG,
+ (flag & gcvPOWER_FLAG_CLOCK_OFF) ? gcvFALSE
+ : gcvTRUE,
+ (flag & gcvPOWER_FLAG_POWER_OFF) ? gcvFALSE
+ : gcvTRUE));
+
+ /* Save current hardware power and clock states. */
+ Hardware->clockState = (flag & gcvPOWER_FLAG_CLOCK_OFF) ? gcvFALSE
+ : gcvTRUE;
+ Hardware->powerState = (flag & gcvPOWER_FLAG_POWER_OFF) ? gcvFALSE
+ : gcvTRUE;
+ }
+
+ /* Get time until off. */
+ gcmkPROFILE_QUERY(time, offTime);
+
+
+ /* Get time until started. */
+ gcmkPROFILE_QUERY(time, startTime);
+
+ if (flag & gcvPOWER_FLAG_RELEASE)
+ {
+ /* Release the power management semaphore. */
+ gcmkONERROR(gckOS_ReleaseSemaphore(os, command->powerSemaphore));
+ acquired = gcvFALSE;
+ }
+
+ /* Save the new power state. */
+ Hardware->chipPowerState = State;
+
+ if (global)
+ {
+ /* Save the new power state. */
+ Hardware->chipPowerStateGlobal = State;
+ }
+
+ if (commitMutex)
+ {
+ /* Acquire the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(
+ command->os,
+ command->commitMutex
+ ));
+ }
+
+#if gcdPOWEROFF_TIMEOUT
+ /* Reset power off time */
+ gcmkONERROR(gckOS_GetTicks(&currentTime));
+
+ Hardware->powerOffTime = currentTime + Hardware->powerOffTimeout;
+
+ if (State == gcvPOWER_IDLE)
+ {
+ /* Start a timer to power off GPU when GPU enters IDLE or SUSPEND. */
+ gcmkVERIFY_OK(gckOS_StartTimer(os,
+ Hardware->powerOffTimer,
+ Hardware->powerOffTimeout));
+ }
+ else
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "Cancel powerOfftimer");
+
+ /* Cancel running timer when GPU enters ON or OFF. */
+ gcmkVERIFY_OK(gckOS_StopTimer(os, Hardware->powerOffTimer));
+ }
+#endif
+
+ /* Release the power mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex));
+
+ /* Get total time. */
+ gcmkPROFILE_QUERY(time, totalTime);
+#if gcdENABLE_PROFILING
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "PROF(%llu): mutex:%llu on:%llu stall:%llu stop:%llu",
+ freq, mutexTime, onTime, stallTime, stopTime);
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ " delay:%llu init:%llu off:%llu start:%llu total:%llu",
+ delayTime, initTime, offTime, startTime, totalTime);
+#endif
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+
+ if (acquired)
+ {
+ /* Release semaphore. */
+ gcmkVERIFY_OK(gckOS_ReleaseSemaphore(Hardware->os,
+ command->powerSemaphore));
+ }
+
+ if (mutexAcquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex));
+ }
+
+ if (commitMutex)
+ {
+ /* Acquire the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(
+ command->os,
+ command->commitMutex
+ ));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHARDWARE_QueryPowerManagementState
+**
+** Get GPU power state.
+**
+** INPUT:
+**
+** gckHARDWARE Harwdare
+** Pointer to an gckHARDWARE object.
+**
+** gceCHIPPOWERSTATE* State
+** Power State.
+**
+*/
+gceSTATUS
+gckVGHARDWARE_QueryPowerManagementState(
+ IN gckVGHARDWARE Hardware,
+ OUT gceCHIPPOWERSTATE* State
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(State != gcvNULL);
+
+ /* Return the statue. */
+ *State = Hardware->chipPowerState;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*State=%d", *State);
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckVGHARDWARE_SetPowerManagement
+**
+** Configure GPU power management function.
+** Only used in driver initialization stage.
+**
+** INPUT:
+**
+** gckVGHARDWARE Harwdare
+** Pointer to an gckHARDWARE object.
+**
+** gctBOOL PowerManagement
+** Power Mangement State.
+**
+*/
+gceSTATUS
+gckVGHARDWARE_SetPowerManagement(
+ IN gckVGHARDWARE Hardware,
+ IN gctBOOL PowerManagement
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ Hardware->options.powerManagement = PowerManagement;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+#if gcdPOWEROFF_TIMEOUT
+gceSTATUS
+gckVGHARDWARE_SetPowerOffTimeout(
+ IN gckVGHARDWARE Hardware,
+ IN gctUINT32 Timeout
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x Timeout=%d", Hardware, Timeout);
+
+ Hardware->powerOffTimeout = Timeout;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+
+gceSTATUS
+gckVGHARDWARE_QueryPowerOffTimeout(
+ IN gckVGHARDWARE Hardware,
+ OUT gctUINT32* Timeout
+ )
+{
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ *Timeout = Hardware->powerOffTimeout;
+
+ gcmkFOOTER_ARG("*Timeout=%d", *Timeout);
+ return gcvSTATUS_OK;
+}
+#endif
+
+gceSTATUS
+gckVGHARDWARE_QueryIdle(
+ IN gckVGHARDWARE Hardware,
+ OUT gctBOOL_PTR IsIdle
+ )
+{
+ gceSTATUS status;
+ gctUINT32 idle;
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(IsIdle != gcvNULL);
+
+ /* We are idle when the power is not ON. */
+ if (Hardware->chipPowerState != gcvPOWER_ON)
+ {
+ *IsIdle = gcvTRUE;
+ }
+
+ else
+ {
+ /* Read idle register. */
+ gcmkONERROR(
+ gckOS_ReadRegisterEx(Hardware->os, gcvCORE_VG, 0x00004, &idle));
+
+ /* Pipe must be idle. */
+ if (((((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ) != 1)
+ || ((((((gctUINT32) (idle)) >> (0 ? 8:8)) & ((gctUINT32) ((((1 ? 8:8) - (0 ? 8:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:8) - (0 ? 8:8) + 1)))))) ) != 1)
+ || ((((((gctUINT32) (idle)) >> (0 ? 9:9)) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 9:9) - (0 ? 9:9) + 1)))))) ) != 1)
+ || ((((((gctUINT32) (idle)) >> (0 ? 10:10)) & ((gctUINT32) ((((1 ? 10:10) - (0 ? 10:10) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 10:10) - (0 ? 10:10) + 1)))))) ) != 1)
+ || ((((((gctUINT32) (idle)) >> (0 ? 11:11)) & ((gctUINT32) ((((1 ? 11:11) - (0 ? 11:11) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 11:11) - (0 ? 11:11) + 1)))))) ) != 1)
+ )
+ {
+ /* Something is busy. */
+ *IsIdle = gcvFALSE;
+ }
+
+ else
+ {
+ *IsIdle = gcvTRUE;
+ }
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+#endif /* gcdENABLE_VG */
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_vg.h b/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_vg.h
new file mode 100644
index 000000000000..236c0afb14e6
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/archvg/gc_hal_kernel_hardware_vg.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_hardware_vg_h_
+#define __gc_hal_kernel_hardware_vg_h_
+
+/* gckHARDWARE object. */
+struct _gckVGHARDWARE
+{
+ /* Object. */
+ gcsOBJECT object;
+
+ /* Pointer to gckKERNEL object. */
+ gckVGKERNEL kernel;
+
+ /* Pointer to gckOS object. */
+ gckOS os;
+
+ /* Chip characteristics. */
+ gceCHIPMODEL chipModel;
+ gctUINT32 chipRevision;
+ gctUINT32 productID;
+ gctUINT32 ecoID;
+ gctUINT32 customerID;
+ gctUINT32 chipFeatures;
+ gctUINT32 chipMinorFeatures;
+ gctUINT32 chipMinorFeatures2;
+
+ /* Features. */
+ gctBOOL fe20;
+ gctBOOL vg20;
+ gctBOOL vg21;
+ gctBOOL fc;
+
+ /* Event mask. */
+ gctUINT32 eventMask;
+
+ gctBOOL clockState;
+ gctBOOL powerState;
+ gctPOINTER powerMutex;
+ gctUINT32 powerProcess;
+ gctUINT32 powerThread;
+ gceCHIPPOWERSTATE chipPowerState;
+ gceCHIPPOWERSTATE chipPowerStateGlobal;
+ gctPOINTER pageTableDirty;
+#if gcdPOWEROFF_TIMEOUT
+ gctUINT32 powerOffTime;
+ gctUINT32 powerOffTimeout;
+ gctPOINTER powerOffTimer;
+#endif
+
+ gcsHAL_QUERY_CHIP_OPTIONS options;
+
+ gctPOINTER featureDatabase;
+};
+
+#endif /* __gc_hal_kernel_hardware_h_ */
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.c
new file mode 100644
index 000000000000..2cdc21f92930
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.c
@@ -0,0 +1,6450 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#if gcdDEC_ENABLE_AHB
+#include "viv_dec300_main.h"
+#endif
+
+#define _GC_OBJ_ZONE gcvZONE_KERNEL
+
+/*******************************************************************************
+***** Version Signature *******************************************************/
+
+#define _gcmTXT2STR(t) #t
+#define gcmTXT2STR(t) _gcmTXT2STR(t)
+const char * _VERSION = "\n\0$VERSION$"
+ gcmTXT2STR(gcvVERSION_MAJOR) "."
+ gcmTXT2STR(gcvVERSION_MINOR) "."
+ gcmTXT2STR(gcvVERSION_PATCH) ":"
+ gcmTXT2STR(gcvVERSION_BUILD) "$\n";
+
+/******************************************************************************\
+******************************* gckKERNEL API Code ******************************
+\******************************************************************************/
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+#define gcmDEFINE2TEXT(d) #d
+gctCONST_STRING _DispatchText[] =
+{
+ gcmDEFINE2TEXT(gcvHAL_QUERY_VIDEO_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_QUERY_CHIP_IDENTITY),
+ gcmDEFINE2TEXT(gcvHAL_ALLOCATE_NON_PAGED_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_FREE_NON_PAGED_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_FREE_CONTIGUOUS_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_ALLOCATE_VIDEO_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_RELEASE_VIDEO_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_MAP_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_UNMAP_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_MAP_USER_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_UNMAP_USER_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_LOCK_VIDEO_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_UNLOCK_VIDEO_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_EVENT_COMMIT),
+ gcmDEFINE2TEXT(gcvHAL_USER_SIGNAL),
+ gcmDEFINE2TEXT(gcvHAL_SIGNAL),
+ gcmDEFINE2TEXT(gcvHAL_WRITE_DATA),
+ gcmDEFINE2TEXT(gcvHAL_COMMIT),
+ gcmDEFINE2TEXT(gcvHAL_STALL),
+ gcmDEFINE2TEXT(gcvHAL_READ_REGISTER),
+ gcmDEFINE2TEXT(gcvHAL_WRITE_REGISTER),
+ gcmDEFINE2TEXT(gcvHAL_GET_PROFILE_SETTING),
+ gcmDEFINE2TEXT(gcvHAL_SET_PROFILE_SETTING),
+ gcmDEFINE2TEXT(gcvHAL_PROFILE_REGISTERS_2D),
+ gcmDEFINE2TEXT(gcvHAL_READ_ALL_PROFILE_REGISTERS_PART1),
+ gcmDEFINE2TEXT(gcvHAL_READ_ALL_PROFILE_REGISTERS_PART2),
+ gcmDEFINE2TEXT(gcvHAL_READ_PROFILER_REGISTER_SETTING),
+ gcmDEFINE2TEXT(gcvHAL_SET_POWER_MANAGEMENT_STATE),
+ gcmDEFINE2TEXT(gcvHAL_QUERY_POWER_MANAGEMENT_STATE),
+ gcmDEFINE2TEXT(gcvHAL_GET_BASE_ADDRESS),
+ gcmDEFINE2TEXT(gcvHAL_SET_IDLE),
+ gcmDEFINE2TEXT(gcvHAL_QUERY_KERNEL_SETTINGS),
+ gcmDEFINE2TEXT(gcvHAL_RESET),
+ gcmDEFINE2TEXT(gcvHAL_MAP_PHYSICAL),
+ gcmDEFINE2TEXT(gcvHAL_DEBUG),
+ gcmDEFINE2TEXT(gcvHAL_CACHE),
+ gcmDEFINE2TEXT(gcvHAL_TIMESTAMP),
+ gcmDEFINE2TEXT(gcvHAL_DATABASE),
+ gcmDEFINE2TEXT(gcvHAL_VERSION),
+ gcmDEFINE2TEXT(gcvHAL_CHIP_INFO),
+ gcmDEFINE2TEXT(gcvHAL_ATTACH),
+ gcmDEFINE2TEXT(gcvHAL_DETACH),
+ gcmDEFINE2TEXT(gcvHAL_SET_TIMEOUT),
+ gcmDEFINE2TEXT(gcvHAL_GET_FRAME_INFO),
+ gcmDEFINE2TEXT(gcvHAL_DUMP_GPU_PROFILE),
+ gcmDEFINE2TEXT(gcvHAL_QUERY_COMMAND_BUFFER),
+ gcmDEFINE2TEXT(gcvHAL_COMMIT_DONE),
+ gcmDEFINE2TEXT(gcvHAL_DUMP_GPU_STATE),
+ gcmDEFINE2TEXT(gcvHAL_DUMP_EVENT),
+ gcmDEFINE2TEXT(gcvHAL_ALLOCATE_VIRTUAL_COMMAND_BUFFER),
+ gcmDEFINE2TEXT(gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER),
+ gcmDEFINE2TEXT(gcvHAL_SET_FSCALE_VALUE),
+ gcmDEFINE2TEXT(gcvHAL_GET_FSCALE_VALUE),
+ gcmDEFINE2TEXT(gcvHAL_EXPORT_VIDEO_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_NAME_VIDEO_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_IMPORT_VIDEO_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_QUERY_RESET_TIME_STAMP),
+ gcmDEFINE2TEXT(gcvHAL_READ_REGISTER_EX),
+ gcmDEFINE2TEXT(gcvHAL_WRITE_REGISTER_EX),
+ gcmDEFINE2TEXT(gcvHAL_CREATE_NATIVE_FENCE),
+ gcmDEFINE2TEXT(gcvHAL_WAIT_NATIVE_FENCE),
+ gcmDEFINE2TEXT(gcvHAL_DESTROY_MMU),
+ gcmDEFINE2TEXT(gcvHAL_SHBUF),
+ gcmDEFINE2TEXT(gcvHAL_GET_GRAPHIC_BUFFER_FD),
+ gcmDEFINE2TEXT(gcvHAL_SET_VIDEO_MEMORY_METADATA),
+ gcmDEFINE2TEXT(gcvHAL_GET_VIDEO_MEMORY_FD),
+ gcmDEFINE2TEXT(gcvHAL_CONFIG_POWER_MANAGEMENT),
+ gcmDEFINE2TEXT(gcvHAL_WRAP_USER_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_WAIT_FENCE),
+#if gcdDEC_ENABLE_AHB
+ gcmDEFINE2TEXT(gcvHAL_DEC300_READ),
+ gcmDEFINE2TEXT(gcvHAL_DEC300_WRITE),
+ gcmDEFINE2TEXT(gcvHAL_DEC300_FLUSH),
+ gcmDEFINE2TEXT(gcvHAL_DEC300_FLUSH_WAIT),
+#endif
+ gcmDEFINE2TEXT(gcvHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY),
+ gcmDEFINE2TEXT(gcvHAL_QUERY_CHIP_OPTION),
+};
+#endif
+
+#if gcdGPU_TIMEOUT && gcdINTERRUPT_STATISTIC
+void
+_MonitorTimerFunction(
+ gctPOINTER Data
+ )
+{
+ gckKERNEL kernel = (gckKERNEL)Data;
+ gctINT32 pendingInterrupt;
+ gctBOOL reset = gcvFALSE;
+ gctINT32 mask;
+ gctUINT32 advance = kernel->timeOut/2;
+
+#if gcdENABLE_VG
+ if (kernel->core == gcvCORE_VG)
+ {
+ return;
+ }
+#endif
+
+ if (kernel->monitorTimerStop)
+ {
+ /* Stop. */
+ return;
+ }
+
+ gckOS_AtomGet(kernel->os, kernel->eventObj->interruptCount, &pendingInterrupt);
+
+ if (pendingInterrupt < 0)
+ {
+ gctINT i = 0 - pendingInterrupt;
+ gctINT pendingMask;
+
+ gcmkVERIFY_OK(gckOS_AtomGet(
+ kernel->os,
+ kernel->hardware->pendingEvent,
+ &pendingMask
+ ));
+
+ gcmkPRINT("[galcore]: Number of pending interrupt is %d mask is %x",
+ pendingInterrupt, pendingMask);
+
+ while (i--)
+ {
+ /* Ignore counting which should not exist. */
+ gckOS_AtomIncrement(kernel->os, kernel->eventObj->interruptCount, &pendingInterrupt);
+ }
+
+ gckOS_AtomGet(kernel->os, kernel->eventObj->interruptCount, &pendingInterrupt);
+ }
+
+ if (kernel->monitoring == gcvFALSE)
+ {
+ if (pendingInterrupt)
+ {
+ /* Begin to mointor GPU state. */
+ kernel->monitoring = gcvTRUE;
+
+ /* Record current state. */
+ kernel->lastCommitStamp = kernel->eventObj->lastCommitStamp;
+ kernel->restoreAddress = kernel->hardware->lastWaitLink;
+ gcmkVERIFY_OK(gckOS_AtomGet(
+ kernel->os,
+ kernel->hardware->pendingEvent,
+ &kernel->restoreMask
+ ));
+
+ /* Clear timeout. */
+ kernel->timer = 0;
+ }
+ }
+ else
+ {
+ if (pendingInterrupt)
+ {
+ gcmkVERIFY_OK(gckOS_AtomGet(
+ kernel->os,
+ kernel->hardware->pendingEvent,
+ &mask
+ ));
+
+ if (kernel->eventObj->lastCommitStamp == kernel->lastCommitStamp
+ && kernel->hardware->lastWaitLink == kernel->restoreAddress
+ && mask == kernel->restoreMask
+ )
+ {
+ /* GPU state is not changed, accumlate timeout. */
+ kernel->timer += advance;
+
+ if (kernel->timer >= kernel->timeOut)
+ {
+ /* GPU stuck, trigger reset. */
+ reset = gcvTRUE;
+ }
+ }
+ else
+ {
+ /* GPU state changed, cancel current timeout.*/
+ kernel->monitoring = gcvFALSE;
+ }
+ }
+ else
+ {
+ /* GPU finish all jobs, cancel current timeout*/
+ kernel->monitoring = gcvFALSE;
+ }
+ }
+
+ if (reset)
+ {
+ gckKERNEL_Recovery(kernel);
+
+ /* Work in this timeout is done. */
+ kernel->monitoring = gcvFALSE;
+ }
+
+ gcmkVERIFY_OK(gckOS_StartTimer(kernel->os, kernel->monitorTimer, advance));
+}
+#endif
+
+#if gcdPROCESS_ADDRESS_SPACE
+gceSTATUS
+_MapCommandBuffer(
+ IN gckKERNEL Kernel
+ )
+{
+ gceSTATUS status;
+ gctUINT32 i;
+ gctPHYS_ADDR_T physical;
+ gctUINT32 address;
+ gckMMU mmu;
+
+ gcmkONERROR(gckKERNEL_GetProcessMMU(Kernel, &mmu));
+
+ for (i = 0; i < gcdCOMMAND_QUEUES; i++)
+ {
+ gcmkONERROR(gckOS_GetPhysicalAddress(
+ Kernel->os,
+ Kernel->command->queues[i].logical,
+ &physical
+ ));
+
+ gcmkSAFECASTPHYSADDRT(address, physical);
+
+ gcmkONERROR(gckMMU_FlatMapping(mmu, address, 1));
+ }
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+#endif
+
+void
+_DumpDriverConfigure(
+ IN gckKERNEL Kernel
+ )
+{
+ gcmkPRINT_N(0, "**************************\n");
+ gcmkPRINT_N(0, "*** GPU DRV CONFIG ***\n");
+ gcmkPRINT_N(0, "**************************\n");
+
+ gcmkPRINT("Galcore version %d.%d.%d.%d\n",
+ gcvVERSION_MAJOR, gcvVERSION_MINOR, gcvVERSION_PATCH, gcvVERSION_BUILD);
+
+ gckOS_DumpParam();
+}
+
+void
+_DumpState(
+ IN gckKERNEL Kernel
+ )
+{
+ /* Dump GPU Debug registers. */
+ gcmkVERIFY_OK(gckHARDWARE_DumpGPUState(Kernel->hardware));
+
+ gcmkVERIFY_OK(gckCOMMAND_DumpExecutingBuffer(Kernel->command));
+
+ /* Dump Pending event. */
+ gcmkVERIFY_OK(gckEVENT_Dump(Kernel->eventObj));
+
+ /* Dump Process DB. */
+ gcmkVERIFY_OK(gckKERNEL_DumpProcessDB(Kernel));
+
+#if gcdRECORD_COMMAND
+ /* Dump record. */
+ gckRECORDER_Dump(Kernel->command->recorder);
+#endif
+}
+
+static gceHARDWARE_TYPE
+_GetHardwareType(
+ IN gckKERNEL Kernel
+ )
+{
+ gceHARDWARE_TYPE type;
+ gcmkHEADER();
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+#if gcdENABLE_VG
+ if (Kernel->vg)
+ {
+ type = gcvHARDWARE_VG;
+ }
+ else
+#endif
+ {
+ type = Kernel->hardware->type;
+ }
+
+ gcmkFOOTER_ARG("type=%d", type);
+ return type;
+}
+
+gceSTATUS
+_SetRecovery(
+ IN gckKERNEL Kernel,
+ IN gctBOOL Recovery,
+ IN gctUINT32 StuckDump
+ )
+{
+ Kernel->recovery = Recovery;
+
+ if (Recovery == gcvFALSE)
+ {
+ /* Dump stuck information if Recovery is disabled. */
+ Kernel->stuckDump = gcmMAX(StuckDump, gcvSTUCK_DUMP_USER_COMMAND);
+ }
+
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_Construct
+**
+** Construct a new gckKERNEL object.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gceCORE Core
+** Specified core.
+**
+** IN gctPOINTER Context
+** Pointer to a driver defined context.
+**
+** IN gckDB SharedDB,
+** Pointer to a shared DB.
+**
+** OUTPUT:
+**
+** gckKERNEL * Kernel
+** Pointer to a variable that will hold the pointer to the gckKERNEL
+** object.
+*/
+
+gceSTATUS
+gckKERNEL_Construct(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctUINT ChipID,
+ IN gctPOINTER Context,
+ IN gckDEVICE Device,
+ IN gckDB SharedDB,
+ OUT gckKERNEL * Kernel
+ )
+{
+ gckKERNEL kernel = gcvNULL;
+ gceSTATUS status;
+ gctSIZE_T i;
+ gctPOINTER pointer = gcvNULL;
+ gctUINT32 recovery;
+ gctUINT32 stuckDump;
+
+ gcmkHEADER_ARG("Os=0x%x Context=0x%x", Os, Context);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Kernel != gcvNULL);
+
+ /* Allocate the gckKERNEL object. */
+ gcmkONERROR(gckOS_Allocate(Os,
+ gcmSIZEOF(struct _gckKERNEL),
+ &pointer));
+
+ /* Zero the object. */
+ gckOS_ZeroMemory(pointer, gcmSIZEOF(struct _gckKERNEL));
+
+ kernel = pointer;
+
+ /* Initialize the gckKERNEL object. */
+ kernel->object.type = gcvOBJ_KERNEL;
+ kernel->os = Os;
+ kernel->core = Core;
+ kernel->device = Device;
+ kernel->chipID = ChipID;
+
+#if gcdENABLE_TRUST_APPLICATION
+ /* Connect to security service for this GPU. */
+ gcmkONERROR(gckKERNEL_SecurityOpen(kernel, kernel->core, &kernel->securityChannel));
+#endif
+
+ if (SharedDB == gcvNULL)
+ {
+ gcmkONERROR(gckOS_Allocate(Os,
+ gcmSIZEOF(struct _gckDB),
+ &pointer));
+
+ kernel->db = pointer;
+ kernel->dbCreated = gcvTRUE;
+ kernel->db->freeDatabase = gcvNULL;
+ kernel->db->freeRecord = gcvNULL;
+ kernel->db->dbMutex = gcvNULL;
+ kernel->db->lastDatabase = gcvNULL;
+ kernel->db->idleTime = 0;
+ kernel->db->lastIdle = 0;
+ kernel->db->lastSlowdown = 0;
+
+ for (i = 0; i < gcmCOUNTOF(kernel->db->db); ++i)
+ {
+ kernel->db->db[i] = gcvNULL;
+ }
+
+ /* Construct a database mutex. */
+ gcmkONERROR(gckOS_CreateMutex(Os, &kernel->db->dbMutex));
+
+ /* Construct a video memory name database. */
+ gcmkONERROR(gckKERNEL_CreateIntegerDatabase(kernel, &kernel->db->nameDatabase));
+
+ /* Construct a video memory name database mutex. */
+ gcmkONERROR(gckOS_CreateMutex(Os, &kernel->db->nameDatabaseMutex));
+
+ /* Construct a pointer name database. */
+ gcmkONERROR(gckKERNEL_CreateIntegerDatabase(kernel, &kernel->db->pointerDatabase));
+
+ /* Construct a pointer name database mutex. */
+ gcmkONERROR(gckOS_CreateMutex(Os, &kernel->db->pointerDatabaseMutex));
+
+ /* Initialize on fault vidmem list. */
+ gcsLIST_Init(&kernel->db->onFaultVidmemList);
+ }
+ else
+ {
+ kernel->db = SharedDB;
+ kernel->dbCreated = gcvFALSE;
+ }
+
+ for (i = 0; i < gcmCOUNTOF(kernel->timers); ++i)
+ {
+ kernel->timers[i].startTime = 0;
+ kernel->timers[i].stopTime = 0;
+ }
+
+ /* Save context. */
+ kernel->context = Context;
+
+ /* Construct atom holding number of clients. */
+ kernel->atomClients = gcvNULL;
+ gcmkONERROR(gckOS_AtomConstruct(Os, &kernel->atomClients));
+
+ kernel->recovery = gcvTRUE;
+ kernel->stuckDump = gcvSTUCK_DUMP_NONE;
+
+ /* Override default recovery and stuckDump setting. */
+ status = gckOS_QueryOption(Os, "recovery", &recovery);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ status = gckOS_QueryOption(Os, "stuckDump", &stuckDump);
+
+ gcmkASSERT(status == gcvSTATUS_OK);
+
+ _SetRecovery(kernel, recovery, stuckDump);
+ }
+
+ /* Need the kernel reference before gckKERNEL_Construct() completes.
+ gckOS_MapPagesEx() is called to map kernel virtual command buffers. */
+ *Kernel = kernel;
+
+ kernel->virtualBufferHead =
+ kernel->virtualBufferTail = gcvNULL;
+
+ gcmkONERROR(
+ gckOS_CreateMutex(Os, (gctPOINTER)&kernel->virtualBufferLock));
+
+#if gcdENABLE_VG
+ kernel->vg = gcvNULL;
+
+ if (Core == gcvCORE_VG)
+ {
+ gctUINT32 contiguousBase;
+ gctUINT32 contiguousSize = 0;
+
+ /* Construct the gckMMU object. */
+ gcmkONERROR(
+ gckVGKERNEL_Construct(Os, Context, kernel, &kernel->vg));
+
+ kernel->timeOut = gcdGPU_TIMEOUT;
+
+ status = gckOS_QueryOption(Os, "contiguousBase", &contiguousBase);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ status = gckOS_QueryOption(Os, "contiguousSize", &contiguousSize);
+ }
+
+ if (gcmIS_SUCCESS(status) && contiguousSize)
+ {
+ gctUINT64 gpuContiguousBase;
+
+ gcmkONERROR(gckOS_CPUPhysicalToGPUPhysical(Os, contiguousBase, &gpuContiguousBase));
+
+ gcmkSAFECASTPHYSADDRT(kernel->contiguousBaseAddress, gpuContiguousBase);
+ }
+ }
+ else
+#endif
+ {
+ /* Construct the gckHARDWARE object. */
+ gcmkONERROR(
+ gckHARDWARE_Construct(Os, kernel->core, &kernel->hardware));
+
+ /* Set pointer to gckKERNEL object in gckHARDWARE object. */
+ kernel->hardware->kernel = kernel;
+
+ kernel->timeOut = kernel->hardware->type == gcvHARDWARE_2D
+ ? gcdGPU_2D_TIMEOUT
+ : gcdGPU_TIMEOUT
+ ;
+
+ /* Initialize virtual command buffer. */
+#if gcdALLOC_CMD_FROM_RESERVE || gcdSECURITY || gcdDISABLE_GPU_VIRTUAL_ADDRESS || !USE_KERNEL_VIRTUAL_BUFFERS
+ kernel->virtualCommandBuffer = gcvFALSE;
+#else
+ kernel->virtualCommandBuffer = kernel->hardware->options.enableMMU;
+#endif
+
+#if gcdSHARED_PAGETABLE
+ /* Construct the gckMMU object. */
+ gcmkONERROR(
+ gckMMU_Construct(kernel, gcdMMU_SIZE, &kernel->mmu));
+#else
+ if (Device == gcvNULL)
+ {
+ /* Construct the gckMMU object. */
+ gcmkONERROR(
+ gckMMU_Construct(kernel, gcdMMU_SIZE, &kernel->mmu));
+ }
+ else
+ {
+ gcmkONERROR(gckDEVICE_GetMMU(Device, kernel->hardware->type, &kernel->mmu));
+
+ if (kernel->mmu == gcvNULL)
+ {
+ gcmkONERROR(
+ gckMMU_Construct(kernel, gcdMMU_SIZE, &kernel->mmu));
+
+ gcmkONERROR(
+ gckDEVICE_SetMMU(Device, kernel->hardware->type, kernel->mmu));
+ }
+ }
+
+ gcmkVERIFY_OK(gckMMU_AttachHardware(kernel->mmu, kernel->hardware));
+#endif
+
+ kernel->contiguousBaseAddress = kernel->mmu->contiguousBaseAddress;
+ kernel->externalBaseAddress = kernel->mmu->externalBaseAddress;
+
+ /* Construct the gckCOMMAND object. */
+ gcmkONERROR(
+ gckCOMMAND_Construct(kernel, &kernel->command));
+
+ if (gckHARDWARE_IsFeatureAvailable(kernel->hardware, gcvFEATURE_ASYNC_BLIT))
+ {
+ /* Construct the gckASYNC_COMMAND object for BLT engine. */
+ gcmkONERROR(gckASYNC_COMMAND_Construct(kernel, &kernel->asyncCommand));
+
+ /* Construct gckEVENT for BLT. */
+ gcmkONERROR(gckEVENT_Construct(kernel, &kernel->asyncEvent));
+
+ kernel->asyncEvent->asyncCommand = kernel->asyncCommand;
+
+ kernel->command->asyncCommand = kernel->asyncCommand;
+ }
+
+ /* Construct the gckEVENT object. */
+ gcmkONERROR(
+ gckEVENT_Construct(kernel, &kernel->eventObj));
+
+ gcmkVERIFY_OK(gckOS_GetTime(&kernel->resetTimeStamp));
+
+ gcmkONERROR(gckHARDWARE_PrepareFunctions(kernel->hardware));
+
+ /* Initialize the hardware. */
+ gcmkONERROR(
+ gckHARDWARE_InitializeHardware(kernel->hardware));
+
+#if gcdDVFS
+ if (gckHARDWARE_IsFeatureAvailable(kernel->hardware,
+ gcvFEATURE_DYNAMIC_FREQUENCY_SCALING))
+ {
+ gcmkONERROR(gckDVFS_Construct(kernel->hardware, &kernel->dvfs));
+ gcmkONERROR(gckDVFS_Start(kernel->dvfs));
+ }
+#endif
+
+#if COMMAND_PROCESSOR_VERSION == 1
+ /* Start the command queue. */
+ gcmkONERROR(gckCOMMAND_Start(kernel->command));
+#endif
+ }
+
+#if VIVANTE_PROFILER
+ /* Initialize profile setting */
+ kernel->profileEnable = gcvFALSE;
+ kernel->profileCleanRegister = gcvTRUE;
+#endif
+
+#if gcdANDROID_NATIVE_FENCE_SYNC
+ gcmkONERROR(gckOS_CreateSyncTimeline(Os, Core, &kernel->timeline));
+#endif
+
+#if gcdSECURITY
+ /* Connect to security service for this GPU. */
+ gcmkONERROR(gckKERNEL_SecurityOpen(kernel, kernel->core, &kernel->securityChannel));
+#endif
+
+#if gcdGPU_TIMEOUT && gcdINTERRUPT_STATISTIC
+ if (kernel->timeOut)
+ {
+ gcmkVERIFY_OK(gckOS_CreateTimer(
+ Os,
+ (gctTIMERFUNCTION)_MonitorTimerFunction,
+ (gctPOINTER)kernel,
+ &kernel->monitorTimer
+ ));
+
+ kernel->monitoring = gcvFALSE;
+
+ kernel->monitorTimerStop = gcvFALSE;
+
+ gcmkVERIFY_OK(gckOS_StartTimer(
+ Os,
+ kernel->monitorTimer,
+ 100
+ ));
+ }
+#endif
+
+ /* Return pointer to the gckKERNEL object. */
+ *Kernel = kernel;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Kernel=0x%x", *Kernel);
+ return gcvSTATUS_OK;
+
+OnError:
+ *Kernel = gcvNULL;
+
+ if (kernel != gcvNULL)
+ {
+ gckKERNEL_Destroy(kernel);
+ }
+
+ /* Return the error. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_Destroy
+**
+** Destroy an gckKERNEL object.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object to destroy.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckKERNEL_Destroy(
+ IN gckKERNEL Kernel
+ )
+{
+ gctSIZE_T i;
+ gcsDATABASE_PTR database, databaseNext;
+ gcsDATABASE_RECORD_PTR record, recordNext;
+
+ gcmkHEADER_ARG("Kernel=0x%x", Kernel);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+#if QNX_SINGLE_THREADED_DEBUGGING
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->debugMutex));
+#endif
+
+ /* Destroy the database. */
+ if (Kernel->dbCreated)
+ {
+ for (i = 0; i < gcmCOUNTOF(Kernel->db->db); ++i)
+ {
+ if (Kernel->db->db[i] != gcvNULL)
+ {
+ gcmkVERIFY_OK(
+ gckKERNEL_DestroyProcessDB(Kernel, Kernel->db->db[i]->processID));
+ }
+ }
+
+ /* Free all databases. */
+ for (database = Kernel->db->freeDatabase;
+ database != gcvNULL;
+ database = databaseNext)
+ {
+ databaseNext = database->next;
+
+ if (database->counterMutex)
+ {
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, database->counterMutex));
+ }
+
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, database));
+ }
+
+ if (Kernel->db->lastDatabase != gcvNULL)
+ {
+ if (Kernel->db->lastDatabase->counterMutex)
+ {
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->lastDatabase->counterMutex));
+ }
+
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, Kernel->db->lastDatabase));
+ }
+
+ /* Free all database records. */
+ for (record = Kernel->db->freeRecord; record != gcvNULL; record = recordNext)
+ {
+ recordNext = record->next;
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, record));
+ }
+
+ if (Kernel->db->dbMutex)
+ {
+ /* Destroy the database mutex. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->dbMutex));
+ }
+
+ if (Kernel->db->nameDatabase)
+ {
+ /* Destroy video memory name database. */
+ gcmkVERIFY_OK(gckKERNEL_DestroyIntegerDatabase(Kernel, Kernel->db->nameDatabase));
+ }
+
+ if (Kernel->db->nameDatabaseMutex)
+ {
+ /* Destroy video memory name database mutex. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->nameDatabaseMutex));
+ }
+
+ if (Kernel->db->pointerDatabase)
+ {
+ /* Destroy id-pointer database. */
+ gcmkVERIFY_OK(gckKERNEL_DestroyIntegerDatabase(Kernel, Kernel->db->pointerDatabase));
+ }
+
+ if (Kernel->db->pointerDatabaseMutex)
+ {
+ /* Destroy id-pointer database mutex. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
+ }
+
+ if (Kernel->db)
+ {
+ /* Destroy the database. */
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, Kernel->db));
+ }
+
+ /* Notify stuck timer to quit. */
+ Kernel->monitorTimerStop = gcvTRUE;
+ }
+
+#if gcdENABLE_VG
+ if (Kernel->vg)
+ {
+ gcmkVERIFY_OK(gckVGKERNEL_Destroy(Kernel->vg));
+ }
+ else
+#endif
+ {
+ if (Kernel->command)
+ {
+ /* Destroy the gckCOMMNAND object. */
+ gcmkVERIFY_OK(gckCOMMAND_Destroy(Kernel->command));
+ }
+
+ if (Kernel->asyncCommand)
+ {
+ gcmkVERIFY_OK(gckASYNC_COMMAND_Destroy(Kernel->asyncCommand));
+ }
+
+ if (Kernel->asyncEvent)
+ {
+ gcmkVERIFY_OK(gckEVENT_Destroy(Kernel->asyncEvent));
+ }
+
+ if (Kernel->eventObj)
+ {
+ /* Destroy the gckEVENT object. */
+ gcmkVERIFY_OK(gckEVENT_Destroy(Kernel->eventObj));
+ }
+
+ gcmkVERIFY_OK(gckHARDWARE_DestroyFunctions(Kernel->hardware));
+
+ if (Kernel->mmu)
+ {
+#if gcdSHARED_PAGETABLE
+ /* Destroy the gckMMU object. */
+ gcmkVERIFY_OK(gckMMU_Destroy(Kernel->mmu));
+#else
+ if (Kernel->mmu->hardware == Kernel->hardware)
+ {
+ /* Destroy the gckMMU object. */
+ gcmkVERIFY_OK(gckMMU_Destroy(Kernel->mmu));
+ }
+#endif
+ }
+
+ if (Kernel->hardware)
+ {
+ /* Destroy the gckHARDWARE object. */
+ gcmkVERIFY_OK(gckHARDWARE_Destroy(Kernel->hardware));
+ }
+ }
+
+ if (Kernel->atomClients)
+ {
+ /* Detsroy the client atom. */
+ gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, Kernel->atomClients));
+ }
+
+ if (Kernel->virtualBufferLock)
+ {
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->virtualBufferLock));
+ }
+
+#if gcdDVFS
+ if (Kernel->dvfs)
+ {
+ gcmkVERIFY_OK(gckDVFS_Stop(Kernel->dvfs));
+ gcmkVERIFY_OK(gckDVFS_Destroy(Kernel->dvfs));
+ }
+#endif
+
+#if gcdANDROID_NATIVE_FENCE_SYNC
+ if (Kernel->timeline)
+ {
+ gcmkVERIFY_OK(gckOS_DestroySyncTimeline(Kernel->os, Kernel->timeline));
+ }
+#endif
+
+#if gcdSECURITY
+ if (Kernel->securityChannel)
+ {
+ gcmkVERIFY_OK(gckKERNEL_SecurityClose(Kernel->securityChannel));
+ }
+#endif
+
+ if (Kernel->monitorTimer)
+ {
+ gcmkVERIFY_OK(gckOS_StopTimer(Kernel->os, Kernel->monitorTimer));
+ gcmkVERIFY_OK(gckOS_DestroyTimer(Kernel->os, Kernel->monitorTimer));
+ }
+
+ /* Mark the gckKERNEL object as unknown. */
+ Kernel->object.type = gcvOBJ_UNKNOWN;
+
+ /* Free the gckKERNEL object. */
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, Kernel));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** _AllocateMemory
+**
+** Private function to walk all required memory pools to allocate the requested
+** amount of video memory.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gcsHAL_INTERFACE * Interface
+** Pointer to a gcsHAL_INTERFACE structure that defines the command to
+** be dispatched.
+**
+** OUTPUT:
+**
+** gcsHAL_INTERFACE * Interface
+** Pointer to a gcsHAL_INTERFACE structure that receives any data to be
+** returned.
+*/
+gceSTATUS
+gckKERNEL_AllocateLinearMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN OUT gcePOOL * Pool,
+ IN gctSIZE_T Bytes,
+ IN gctUINT32 Alignment,
+ IN gceSURF_TYPE Type,
+ IN gctUINT32 Flag,
+ OUT gctUINT32 * Node
+ )
+{
+ gcePOOL pool;
+ gceSTATUS status;
+ gckVIDMEM videoMemory;
+ gctINT loopCount;
+ gcuVIDMEM_NODE_PTR node = gcvNULL;
+ gctBOOL tileStatusInVirtual;
+ gctBOOL contiguous = gcvFALSE;
+ gctBOOL cacheable = gcvFALSE;
+ gctBOOL secure = gcvFALSE;
+ gctBOOL fastPools = gcvFALSE;
+ gctBOOL hasFastPools = gcvFALSE;
+ gctSIZE_T bytes = Bytes;
+ gctUINT32 handle = 0;
+ gceDATABASE_TYPE type;
+
+ gcmkHEADER_ARG("Kernel=0x%x *Pool=%d Bytes=%lu Alignment=%lu Type=%d",
+ Kernel, *Pool, Bytes, Alignment, Type);
+
+ gcmkVERIFY_ARGUMENT(Pool != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Bytes != 0);
+
+ /* Get basic type. */
+ Type &= 0xFF;
+
+ /* Check flags. */
+ contiguous = Flag & gcvALLOC_FLAG_CONTIGUOUS;
+ cacheable = Flag & gcvALLOC_FLAG_CACHEABLE;
+ secure = Flag & gcvALLOC_FLAG_SECURITY;
+ if (Flag & gcvALLOC_FLAG_FAST_POOLS)
+ {
+ fastPools = gcvTRUE;
+ Flag &= ~gcvALLOC_FLAG_FAST_POOLS;
+ }
+
+#if gcdALLOC_ON_FAULT
+ if (Type == gcvSURF_RENDER_TARGET)
+ {
+ Flag |= gcvALLOC_FLAG_ALLOC_ON_FAULT;
+ }
+#endif
+
+ if (Flag & gcvALLOC_FLAG_ALLOC_ON_FAULT)
+ {
+ *Pool = gcvPOOL_VIRTUAL;
+ }
+
+ if (Flag & gcvALLOC_FLAG_DMABUF_EXPORTABLE)
+ {
+ gctSIZE_T pageSize = 0;
+ gckOS_GetPageSize(Kernel->os, &pageSize);
+
+ /* Usually, the exported dmabuf might be later imported to DRM,
+ ** while DRM requires input size to be page aligned.
+ */
+ Bytes = gcmALIGN(Bytes, pageSize);
+ }
+
+AllocateMemory:
+
+ /* Get initial pool. */
+ switch (pool = *Pool)
+ {
+ case gcvPOOL_DEFAULT:
+ case gcvPOOL_LOCAL:
+ pool = gcvPOOL_LOCAL_INTERNAL;
+ loopCount = (gctINT) gcvPOOL_NUMBER_OF_POOLS;
+ break;
+
+ case gcvPOOL_UNIFIED:
+ pool = gcvPOOL_SYSTEM;
+ loopCount = (gctINT) gcvPOOL_NUMBER_OF_POOLS;
+ break;
+
+ case gcvPOOL_CONTIGUOUS:
+ loopCount = (gctINT) gcvPOOL_NUMBER_OF_POOLS;
+ break;
+
+ default:
+ loopCount = 1;
+ break;
+ }
+
+ while (loopCount-- > 0)
+ {
+ if (pool == gcvPOOL_VIRTUAL)
+ {
+ /* Create a gcuVIDMEM_NODE for virtual memory. */
+ gcmkONERROR(
+ gckVIDMEM_ConstructVirtual(Kernel, Flag | gcvALLOC_FLAG_NON_CONTIGUOUS, Bytes, &node));
+
+ bytes = node->Virtual.bytes;
+ node->Virtual.type = Type;
+
+ /* Success. */
+ break;
+ }
+
+ else
+ if (pool == gcvPOOL_CONTIGUOUS)
+ {
+#if gcdCONTIGUOUS_SIZE_LIMIT
+ if (Bytes > gcdCONTIGUOUS_SIZE_LIMIT && contiguous == gcvFALSE)
+ {
+ status = gcvSTATUS_OUT_OF_MEMORY;
+ }
+ else
+#endif
+ {
+ /* Create a gcuVIDMEM_NODE from contiguous memory. */
+ status = gckVIDMEM_ConstructVirtual(
+ Kernel,
+ Flag | gcvALLOC_FLAG_CONTIGUOUS,
+ Bytes,
+ &node);
+ }
+
+ if (gcmIS_SUCCESS(status))
+ {
+ bytes = node->Virtual.bytes;
+ node->Virtual.type = Type;
+
+ /* Memory allocated. */
+ break;
+ }
+ }
+
+ else
+ /* gcvPOOL_SYSTEM can't be cacheable. */
+ if (cacheable == gcvFALSE && secure == gcvFALSE)
+ {
+ /* Get pointer to gckVIDMEM object for pool. */
+ status = gckKERNEL_GetVideoMemoryPool(Kernel, pool, &videoMemory);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ /* Allocate memory. */
+#if defined(gcdLINEAR_SIZE_LIMIT)
+ /* 512 KB */
+ if (Bytes > gcdLINEAR_SIZE_LIMIT)
+ {
+ status = gcvSTATUS_OUT_OF_MEMORY;
+ }
+ else
+#endif
+ {
+ hasFastPools = gcvTRUE;
+ status = gckVIDMEM_AllocateLinear(Kernel,
+ videoMemory,
+ Bytes,
+ Alignment,
+ Type,
+ (*Pool == gcvPOOL_SYSTEM),
+ &node);
+ }
+
+ if (gcmIS_SUCCESS(status))
+ {
+ /* Memory allocated. */
+ node->VidMem.pool = pool;
+ bytes = node->VidMem.bytes;
+ break;
+ }
+ }
+ }
+
+ if (pool == gcvPOOL_LOCAL_INTERNAL)
+ {
+ /* Advance to external memory. */
+ pool = gcvPOOL_LOCAL_EXTERNAL;
+ }
+
+ else
+ if (pool == gcvPOOL_LOCAL_EXTERNAL)
+ {
+ /* Advance to contiguous system memory. */
+ pool = gcvPOOL_SYSTEM;
+ }
+
+ else
+ if (pool == gcvPOOL_SYSTEM)
+ {
+ /* Do not go ahead to try relative slow pools */
+ if (fastPools && hasFastPools)
+ {
+ status = gcvSTATUS_OUT_OF_MEMORY;
+ break;
+ }
+
+ /* Advance to contiguous memory. */
+ pool = gcvPOOL_CONTIGUOUS;
+ }
+
+ else
+ if (pool == gcvPOOL_CONTIGUOUS)
+ {
+#if gcdENABLE_VG
+ if (Kernel->vg)
+ {
+ tileStatusInVirtual = gcvFALSE;
+ }
+ else
+#endif
+ {
+ tileStatusInVirtual =
+ gckHARDWARE_IsFeatureAvailable(Kernel->hardware,
+ gcvFEATURE_MC20);
+ }
+
+ if (Type == gcvSURF_TILE_STATUS && tileStatusInVirtual != gcvTRUE)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ if (contiguous)
+ {
+ break;
+ }
+
+ /* Advance to virtual memory. */
+ pool = gcvPOOL_VIRTUAL;
+ }
+
+ else
+ {
+ /* Out of pools. */
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+ }
+
+ if (node == gcvNULL)
+ {
+ if (contiguous)
+ {
+ /* Broadcast OOM message. */
+ status = gckOS_Broadcast(Kernel->os, Kernel->hardware, gcvBROADCAST_OUT_OF_MEMORY);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ /* Get some memory. */
+ gckOS_Delay(gcvNULL, 1);
+ goto AllocateMemory;
+ }
+ }
+
+ /* Nothing allocated. */
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ /* Allocate handle for this video memory. */
+ gcmkONERROR(
+ gckVIDMEM_NODE_Allocate(Kernel, node, Type, pool, &handle));
+
+ /* Return node and pool used for allocation. */
+ *Node = handle;
+ *Pool = pool;
+
+ /* Encode surface type and pool to database type. */
+ type = gcvDB_VIDEO_MEMORY
+ | (Type << gcdDB_VIDEO_MEMORY_TYPE_SHIFT)
+ | (pool << gcdDB_VIDEO_MEMORY_POOL_SHIFT);
+
+ /* Record in process db. */
+ gcmkONERROR(
+ gckKERNEL_AddProcessDB(Kernel,
+ ProcessID,
+ type,
+ gcmINT2PTR(handle),
+ gcvNULL,
+ bytes));
+
+
+ /* Return status. */
+ gcmkFOOTER_ARG("*Pool=%d *Node=0x%x", *Pool, *Node);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (handle)
+ {
+ /* Destroy handle allocated. */
+ gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(Kernel, ProcessID, handle));
+ }
+
+ if (node)
+ {
+ /* Free video memory allocated. */
+ gcmkVERIFY_OK(gckVIDMEM_Free(Kernel, node));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_ReleaseVideoMemory
+**
+** Release handle of a video memory.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctUINT32 ProcessID
+** ProcessID of current process.
+**
+** gctUINT32 Handle
+** Handle of video memory.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckKERNEL_ReleaseVideoMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctUINT32 Handle
+ )
+{
+ gceSTATUS status;
+ gckVIDMEM_NODE nodeObject;
+ gceDATABASE_TYPE type;
+
+ gcmkHEADER_ARG("Kernel=0x%08X ProcessID=%d Handle=%d",
+ Kernel, ProcessID, Handle);
+
+ gcmkONERROR(
+ gckVIDMEM_HANDLE_Lookup(Kernel, ProcessID, Handle, &nodeObject));
+
+ type = gcvDB_VIDEO_MEMORY
+ | (nodeObject->type << gcdDB_VIDEO_MEMORY_TYPE_SHIFT)
+ | (nodeObject->pool << gcdDB_VIDEO_MEMORY_POOL_SHIFT);
+
+ gcmkONERROR(
+ gckKERNEL_RemoveProcessDB(Kernel,
+ ProcessID,
+ type,
+ gcmINT2PTR(Handle)));
+
+ gckVIDMEM_HANDLE_Dereference(Kernel, ProcessID, Handle);
+
+ gckVIDMEM_NODE_Dereference(Kernel, nodeObject);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_LockVideoMemory
+**
+** Lock a video memory node. It will generate a cpu virtual address used
+** by software and a GPU address used by GPU.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gceCORE Core
+** GPU to which video memory is locked.
+**
+** gcsHAL_INTERFACE * Interface
+** Pointer to a gcsHAL_INTERFACE structure that defines the command to
+** be dispatched.
+**
+** OUTPUT:
+**
+** gcsHAL_INTERFACE * Interface
+** Pointer to a gcsHAL_INTERFACE structure that receives any data to be
+** returned.
+*/
+gceSTATUS
+gckKERNEL_LockVideoMemory(
+ IN gckKERNEL Kernel,
+ IN gceCORE Core,
+ IN gctUINT32 ProcessID,
+ IN gctBOOL FromUser,
+ IN OUT gcsHAL_INTERFACE * Interface
+ )
+{
+ gceSTATUS status;
+ gckVIDMEM_NODE nodeObject = gcvNULL;
+ gcuVIDMEM_NODE_PTR node = gcvNULL;
+ gctBOOL locked = gcvFALSE;
+ gctBOOL asynchronous = gcvFALSE;
+#ifndef __QNXNTO__
+ gctPOINTER pointer = gcvNULL;
+#endif
+
+ gcmkHEADER_ARG("Kernel=0x%08X ProcessID=%d",
+ Kernel, ProcessID);
+
+ gcmkONERROR(
+ gckVIDMEM_HANDLE_LookupAndReference(Kernel,
+ Interface->u.LockVideoMemory.node,
+ &nodeObject));
+
+ node = nodeObject->node;
+
+ Interface->u.LockVideoMemory.gid = 0;
+
+ /* Lock video memory. */
+ gcmkONERROR(
+ gckVIDMEM_Lock(Kernel,
+ nodeObject,
+ Interface->u.LockVideoMemory.cacheable,
+ &Interface->u.LockVideoMemory.address,
+ &Interface->u.LockVideoMemory.gid,
+ &Interface->u.LockVideoMemory.physicalAddress));
+
+ locked = gcvTRUE;
+
+ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
+ {
+ /* Map video memory address into user space. */
+#ifdef __QNXNTO__
+ if (node->VidMem.logical == gcvNULL)
+ {
+ gcmkONERROR(
+ gckKERNEL_MapVideoMemory(Kernel,
+ FromUser,
+ Interface->u.LockVideoMemory.address,
+ ProcessID,
+ node->VidMem.bytes,
+ &node->VidMem.logical));
+ }
+ gcmkASSERT(node->VidMem.logical != gcvNULL);
+
+ Interface->u.LockVideoMemory.memory = gcmPTR_TO_UINT64(node->VidMem.logical);
+#else
+ gcmkONERROR(
+ gckKERNEL_MapVideoMemoryEx(Kernel,
+ Core,
+ FromUser,
+ Interface->u.LockVideoMemory.address,
+ node->VidMem.pool,
+ &pointer));
+
+ Interface->u.LockVideoMemory.memory = gcmPTR_TO_UINT64(pointer);
+#endif
+ }
+ else
+ {
+ Interface->u.LockVideoMemory.memory = gcmPTR_TO_UINT64(node->Virtual.logical);
+
+ /* Success. */
+ status = gcvSTATUS_OK;
+ }
+
+#if gcdPROCESS_ADDRESS_SPACE
+ gcmkONERROR(gckVIDMEM_Node_Lock(
+ Kernel,
+ nodeObject,
+ &Interface->u.LockVideoMemory.address
+ ));
+#endif
+
+
+#if gcdSECURE_USER
+ /* Return logical address as physical address. */
+ Interface->u.LockVideoMemory.address =
+ (gctUINT32)(Interface->u.LockVideoMemory.memory);
+#endif
+ gcmkONERROR(
+ gckKERNEL_AddProcessDB(Kernel,
+ ProcessID, gcvDB_VIDEO_MEMORY_LOCKED,
+ gcmINT2PTR(Interface->u.LockVideoMemory.node),
+ gcvNULL,
+ 0));
+
+ gckVIDMEM_HANDLE_Reference(
+ Kernel, ProcessID, (gctUINT32)Interface->u.LockVideoMemory.node);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (locked)
+ {
+ /* Roll back the lock. */
+ gcmkVERIFY_OK(gckVIDMEM_Unlock(Kernel,
+ nodeObject,
+ gcvSURF_TYPE_UNKNOWN,
+ &asynchronous));
+
+ if (gcvTRUE == asynchronous)
+ {
+ /* Bottom Half */
+ gcmkVERIFY_OK(gckVIDMEM_Unlock(Kernel,
+ nodeObject,
+ gcvSURF_TYPE_UNKNOWN,
+ gcvNULL));
+ }
+ }
+
+ if (nodeObject != gcvNULL)
+ {
+ gckVIDMEM_NODE_Dereference(Kernel, nodeObject);
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_UnlockVideoMemory
+**
+** Unlock a video memory node.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctUINT32 ProcessID
+** ProcessID of current process.
+**
+** gcsHAL_INTERFACE * Interface
+** Pointer to a gcsHAL_INTERFACE structure that defines the command to
+** be dispatched.
+**
+** OUTPUT:
+**
+** gcsHAL_INTERFACE * Interface
+** Pointer to a gcsHAL_INTERFACE structure that receives any data to be
+** returned.
+*/
+gceSTATUS
+gckKERNEL_UnlockVideoMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN OUT gcsHAL_INTERFACE * Interface
+ )
+{
+ gceSTATUS status;
+ gckVIDMEM_NODE nodeObject;
+ gcuVIDMEM_NODE_PTR node;
+ gctSIZE_T bytes;
+
+ gcmkHEADER_ARG("Kernel=0x%08X ProcessID=%d",
+ Kernel, ProcessID);
+
+ Interface->u.UnlockVideoMemory.pool = gcvPOOL_UNKNOWN;
+ Interface->u.UnlockVideoMemory.bytes = 0;
+
+ gcmkONERROR(gckVIDMEM_HANDLE_Lookup(
+ Kernel,
+ ProcessID,
+ (gctUINT32)Interface->u.UnlockVideoMemory.node,
+ &nodeObject));
+
+ node = nodeObject->node;
+ bytes = (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
+ ? node->VidMem.bytes
+ : node->Virtual.bytes;
+
+ /* Unlock video memory. */
+ gcmkONERROR(gckVIDMEM_Unlock(
+ Kernel,
+ nodeObject,
+ Interface->u.UnlockVideoMemory.type,
+ &Interface->u.UnlockVideoMemory.asynchroneous));
+
+#if gcdSECURE_USER
+ /* Flush the translation cache for virtual surfaces. */
+ if (node->VidMem.memory->object.type != gcvOBJ_VIDMEM)
+ {
+ gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(Kernel,
+ cache,
+ node->Virtual.logical,
+ bytes));
+ }
+#endif
+
+ Interface->u.UnlockVideoMemory.pool = nodeObject->pool;
+ Interface->u.UnlockVideoMemory.bytes = (gctUINT)bytes;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_BottomHalfUnlockVideoMemory
+**
+** Unlock video memory from gpu.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctUINT32 ProcessID
+** Process ID owning this memory.
+**
+** gctPOINTER Pointer
+** Video memory to be unlock.
+*/
+gceSTATUS
+gckKERNEL_BottomHalfUnlockVideoMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctUINT32 Node
+ )
+{
+ gceSTATUS status;
+ gckVIDMEM_NODE nodeObject = gcvNULL;
+
+ /* Remove record from process db. */
+ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+ Kernel,
+ ProcessID,
+ gcvDB_VIDEO_MEMORY_LOCKED,
+ gcmINT2PTR(Node)));
+
+ gcmkONERROR(gckVIDMEM_HANDLE_Lookup(
+ Kernel,
+ ProcessID,
+ Node,
+ &nodeObject));
+
+ gckVIDMEM_HANDLE_Dereference(Kernel, ProcessID, Node);
+
+ /* Unlock video memory. */
+ gcmkONERROR(gckVIDMEM_Unlock(
+ Kernel,
+ nodeObject,
+ gcvSURF_TYPE_UNKNOWN,
+ gcvNULL));
+
+ gcmkONERROR(gckVIDMEM_NODE_Dereference(
+ Kernel,
+ nodeObject));
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_SetVidMemMetadata
+**
+** Set/Get metadata to/from gckVIDMEM_NODE object.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctUINT32 ProcessID
+** ProcessID of current process.
+**
+** INOUT:
+**
+** gcsHAL_INTERFACE * Interface
+** Pointer to a interface structure
+*/
+#if defined(CONFIG_DMA_SHARED_BUFFER)
+#include <linux/dma-buf.h>
+
+gceSTATUS
+gckKERNEL_SetVidMemMetadata(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ INOUT gcsHAL_INTERFACE * Interface
+ )
+{
+ gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+ gckVIDMEM_NODE nodeObj = gcvNULL;
+
+ gcmkHEADER_ARG("Kernel=0x%X ProcessID=%d", Kernel, ProcessID);
+
+ gcmkONERROR(gckVIDMEM_HANDLE_Lookup(Kernel, ProcessID, Interface->u.SetVidMemMetadata.node, &nodeObj));
+
+ if (Interface->u.SetVidMemMetadata.readback)
+ {
+ Interface->u.SetVidMemMetadata.ts_fd = nodeObj->metadata.ts_fd;
+ Interface->u.SetVidMemMetadata.fc_enabled = nodeObj->metadata.fc_enabled;
+ Interface->u.SetVidMemMetadata.fc_value = nodeObj->metadata.fc_value;
+ Interface->u.SetVidMemMetadata.fc_value_upper = nodeObj->metadata.fc_value_upper;
+ Interface->u.SetVidMemMetadata.compressed = nodeObj->metadata.compressed;
+ Interface->u.SetVidMemMetadata.compress_format = nodeObj->metadata.compress_format;
+ }
+ else
+ {
+ nodeObj->metadata.ts_fd = Interface->u.SetVidMemMetadata.ts_fd;
+ if (nodeObj->metadata.ts_fd > 0)
+ {
+ nodeObj->metadata.ts_dma_buf = dma_buf_get(nodeObj->metadata.ts_fd);
+ if (IS_ERR(nodeObj->metadata.ts_dma_buf))
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ dma_buf_put(nodeObj->metadata.ts_dma_buf);
+ }
+ nodeObj->metadata.fc_enabled = Interface->u.SetVidMemMetadata.fc_enabled;
+ nodeObj->metadata.fc_value = Interface->u.SetVidMemMetadata.fc_value;
+ nodeObj->metadata.fc_value_upper = Interface->u.SetVidMemMetadata.fc_value_upper;
+ nodeObj->metadata.compressed = Interface->u.SetVidMemMetadata.compressed;
+ nodeObj->metadata.compress_format = Interface->u.SetVidMemMetadata.compress_format;
+ }
+
+ gcmkFOOTER();
+
+OnError:
+ return status;
+}
+
+#else
+
+gceSTATUS
+gckKERNEL_SetVidMemMetadata(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ INOUT gcsHAL_INTERFACE * Interface
+ )
+{
+ gcmkFATAL("The kernel did NOT support CONFIG_DMA_SHARED_BUFFER");
+ return gcvSTATUS_NOT_SUPPORTED;
+}
+#endif
+
+/*******************************************************************************
+**
+** gckKERNEL_QueryVidMemPoolNodes
+**
+** Loop all databases to query used memory nodes of a specific pool.
+**
+** INPUT:
+**
+** Pool The memory pool for query.
+
+** TotalSize Total size of the used contiguous memory.
+**
+** MemoryBlocks Used contiguous memory block info.
+**
+** NumMaxBlock The count of memory blocks array provided by the caller.
+**
+** NumBlocks The actual number of memory blocks returned.
+**
+** OUTPUT:
+**
+** Error status. Should always be gcvSTATUS_SUCCESS since a query should always succeed.
+*/
+gceSTATUS
+gckKERNEL_QueryVidMemPoolNodes(
+ gckKERNEL Kernel,
+ gcePOOL Pool,
+ gctUINT32 * TotalSize,
+ gcsContiguousBlock * MemoryBlocks,
+ gctUINT32 NumMaxBlocks,
+ gctUINT32 * NumBlocks
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+ gctINT i;
+ gctINT bcount;
+ gctUINT32 num_blocks = 0;
+ gctSIZE_T total_size = 0;
+ gckVIDMEM memory;
+ gcuVIDMEM_NODE_PTR nodes, node;
+
+ do
+ {
+ /* Get the heap and nodes. */
+ status = gckKERNEL_GetVideoMemoryPool(Kernel, Pool, &memory);
+ if (status != gcvSTATUS_OK)
+ break;
+
+ status = gckVIDMEM_QueryNodes(Kernel, Pool, &bcount, &nodes);
+ if (status != gcvSTATUS_OK)
+ break;
+
+ /* Iterate all nodes. */
+ for (i = 0; i < bcount; i++)
+ {
+ node = nodes[i].VidMem.next;
+ do
+ {
+ if (node == gcvNULL)
+ {
+ break;
+ }
+
+ /* Is it in the "free" list? */
+ if (node->VidMem.nextFree == gcvNULL)
+ {
+ if (num_blocks < NumMaxBlocks)
+ {
+ MemoryBlocks[num_blocks].ptr = (gctUINT32)node->VidMem.offset + memory->baseAddress;
+ MemoryBlocks[num_blocks].size = node->VidMem.bytes;
+ }
+ total_size += node->VidMem.bytes;
+ num_blocks++;
+ }
+
+ node = node->VidMem.next;
+ } while (node != &nodes[i]);
+ }
+ }
+ while (gcvFALSE);
+
+ if (TotalSize != gcvNULL)
+ *TotalSize = (gctUINT32)total_size;
+
+ if (NumBlocks != gcvNULL)
+ *NumBlocks = num_blocks;
+
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_QueryDatabase(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN OUT gcsHAL_INTERFACE * Interface
+ )
+{
+ gceSTATUS status;
+ gctINT i;
+
+ gceDATABASE_TYPE type[3] = {
+ gcvDB_VIDEO_MEMORY | (gcvPOOL_SYSTEM << gcdDB_VIDEO_MEMORY_POOL_SHIFT),
+ gcvDB_VIDEO_MEMORY | (gcvPOOL_CONTIGUOUS << gcdDB_VIDEO_MEMORY_POOL_SHIFT),
+ gcvDB_VIDEO_MEMORY | (gcvPOOL_VIRTUAL << gcdDB_VIDEO_MEMORY_POOL_SHIFT),
+ };
+
+ gcmkHEADER();
+
+ /* Query video memory. */
+ gcmkONERROR(
+ gckKERNEL_QueryProcessDB(Kernel,
+ Interface->u.Database.processID,
+ !Interface->u.Database.validProcessID,
+ gcvDB_VIDEO_MEMORY,
+ &Interface->u.Database.vidMem));
+
+ /* Query non-paged memory. */
+ gcmkONERROR(
+ gckKERNEL_QueryProcessDB(Kernel,
+ Interface->u.Database.processID,
+ !Interface->u.Database.validProcessID,
+ gcvDB_NON_PAGED,
+ &Interface->u.Database.nonPaged));
+
+ /* Query contiguous memory. */
+ gcmkONERROR(
+ gckKERNEL_QueryProcessDB(Kernel,
+ Interface->u.Database.processID,
+ !Interface->u.Database.validProcessID,
+ gcvDB_CONTIGUOUS,
+ &Interface->u.Database.contiguous));
+
+ /* Query GPU idle time. */
+ gcmkONERROR(
+ gckKERNEL_QueryProcessDB(Kernel,
+ Interface->u.Database.processID,
+ !Interface->u.Database.validProcessID,
+ gcvDB_IDLE,
+ &Interface->u.Database.gpuIdle));
+ for (i = 0; i < 3; i++)
+ {
+ /* Query each video memory pool. */
+ gcmkONERROR(
+ gckKERNEL_QueryProcessDB(Kernel,
+ Interface->u.Database.processID,
+ !Interface->u.Database.validProcessID,
+ type[i],
+ &Interface->u.Database.vidMemPool[i]));
+ }
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+ gckKERNEL_DumpVidMemUsage(Kernel, Interface->u.Database.processID);
+#endif
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_ConfigPowerManagement(
+ IN gckKERNEL Kernel,
+ IN OUT gcsHAL_INTERFACE * Interface
+)
+{
+ gceSTATUS status;
+ gctBOOL enable = Interface->u.ConfigPowerManagement.enable;
+
+ gcmkHEADER();
+
+ gcmkONERROR(gckHARDWARE_SetPowerManagement(Kernel->hardware, enable));
+
+ if (enable == gcvFALSE)
+ {
+ gcmkONERROR(
+ gckHARDWARE_SetPowerManagementState(Kernel->hardware, gcvPOWER_ON));
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_WaitFence(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Handle,
+ IN gctUINT32 TimeOut
+ )
+{
+ gceSTATUS status;
+ gckVIDMEM_NODE node;
+ gctUINT32 processID;
+ gckCOMMAND command = Kernel->command;
+ gckASYNC_COMMAND asyncCommand = Kernel->asyncCommand;
+ gckFENCE fence = gcvNULL;
+ gctUINT i;
+
+ gckOS_GetProcessID(&processID);
+
+ gcmkONERROR(gckVIDMEM_HANDLE_LookupAndReference(Kernel, Handle, &node));
+
+ /* Wait for fence of all engines. */
+ for (i = 0; i < gcvENGINE_GPU_ENGINE_COUNT; i++)
+ {
+ gckFENCE_SYNC sync = &node->sync[i];
+
+ if (i == gcvENGINE_RENDER)
+ {
+ fence = command->fence;
+ }
+ else
+ {
+ fence = asyncCommand->fence;
+ }
+
+ if (sync->commitStamp <= *(gctUINT64_PTR)fence->logical)
+ {
+ continue;
+ }
+ else
+ {
+ gckOS_Signal(Kernel->os, sync->signal, gcvFALSE);
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, &fence->mutex, gcvINFINITE));
+
+ /* Add to waiting list. */
+ gcsLIST_AddTail(&sync->head, &fence->waitingList);
+
+ gcmkASSERT(sync->inList == gcvFALSE);
+
+ sync->inList = gcvTRUE;
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, &fence->mutex));
+
+ /* Wait. */
+ status = gckOS_WaitSignal(Kernel->os, sync->signal, gcvTRUE, TimeOut);
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, &fence->mutex, gcvINFINITE));
+
+ if (sync->inList)
+ {
+ gcsLIST_Del(&sync->head);
+ sync->inList = gcvFALSE;
+ }
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, &fence->mutex));
+ }
+ }
+
+ gckVIDMEM_NODE_Dereference(Kernel, node);
+
+OnError:
+ return status;
+}
+
+#ifdef __linux__
+
+typedef struct _gcsGRRAPHIC_BUFFER_PARCLE
+{
+ gcsFDPRIVATE base;
+ gckKERNEL kernel;
+
+ gckVIDMEM_NODE node[3];
+ gctSHBUF shBuf;
+ gctINT32 signal;
+}
+gcsGRAPHIC_BUFFER_PARCLE;
+
+static void
+_ReleaseGraphicBuffer(
+ gckKERNEL Kernel,
+ gcsGRAPHIC_BUFFER_PARCLE * Parcle
+ )
+{
+ gctUINT i;
+
+ for (i = 0; i < 3; i++)
+ {
+ if (Parcle->node[i])
+ {
+ gckVIDMEM_NODE_Dereference(Kernel, Parcle->node[i]);
+ }
+ }
+
+ if (Parcle->shBuf)
+ {
+ gckKERNEL_DestroyShBuffer(Kernel, Parcle->shBuf);
+ }
+
+ if (Parcle->signal)
+ {
+ gckOS_DestroyUserSignal(Kernel->os, Parcle->signal);
+ }
+
+ gcmkOS_SAFE_FREE(Kernel->os, Parcle);
+}
+
+static gctINT
+_FdReleaseGraphicBuffer(
+ gcsFDPRIVATE_PTR Private
+ )
+{
+ gcsGRAPHIC_BUFFER_PARCLE * parcle = (gcsGRAPHIC_BUFFER_PARCLE *) Private;
+
+ _ReleaseGraphicBuffer(parcle->kernel, parcle);
+ return 0;
+}
+
+static gceSTATUS
+_GetGraphicBufferFd(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctUINT32 Node[3],
+ IN gctUINT64 ShBuf,
+ IN gctUINT64 Signal,
+ OUT gctINT32 * Fd
+ )
+{
+ gceSTATUS status;
+ gctUINT i;
+ gcsGRAPHIC_BUFFER_PARCLE * parcle = gcvNULL;
+
+ gcmkONERROR(gckOS_Allocate(
+ Kernel->os,
+ gcmSIZEOF(gcsGRAPHIC_BUFFER_PARCLE),
+ (gctPOINTER *)&parcle
+ ));
+
+ gckOS_ZeroMemory(parcle, sizeof(gcsGRAPHIC_BUFFER_PARCLE));
+
+ parcle->base.release = _FdReleaseGraphicBuffer;
+ parcle->kernel = Kernel;
+
+ for (i = 0; i < 3; i++)
+ {
+ if (Node[i] != 0)
+ {
+ gcmkONERROR(
+ gckVIDMEM_HANDLE_LookupAndReference(Kernel, Node[i], &parcle->node[i]));
+ }
+ }
+
+ if (ShBuf)
+ {
+ gctSHBUF shBuf = gcmUINT64_TO_PTR(ShBuf);
+
+ gcmkONERROR(gckKERNEL_MapShBuffer(Kernel, shBuf));
+ parcle->shBuf = shBuf;
+ }
+
+ if (Signal)
+ {
+ gctSIGNAL signal = gcmUINT64_TO_PTR(Signal);
+
+ gcmkONERROR(
+ gckOS_MapSignal(Kernel->os,
+ signal,
+ (gctHANDLE)(gctUINTPTR_T)ProcessID,
+ &signal));
+
+ parcle->signal= (gctINT32)Signal;
+ }
+
+ gcmkONERROR(gckOS_GetFd("viv-gr", &parcle->base, Fd));
+
+ return gcvSTATUS_OK;
+
+OnError:
+ if (parcle)
+ {
+ _ReleaseGraphicBuffer(Kernel, parcle);
+ }
+ return status;
+}
+#endif
+
+/*******************************************************************************
+**
+** gckKERNEL_Dispatch
+**
+** Dispatch a command received from the user HAL layer.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctBOOL FromUser
+** whether the call is from the user space.
+**
+** gcsHAL_INTERFACE * Interface
+** Pointer to a gcsHAL_INTERFACE structure that defines the command to
+** be dispatched.
+**
+** OUTPUT:
+**
+** gcsHAL_INTERFACE * Interface
+** Pointer to a gcsHAL_INTERFACE structure that receives any data to be
+** returned.
+*/
+gceSTATUS
+gckKERNEL_Dispatch(
+ IN gckKERNEL Kernel,
+ IN gckDEVICE Device,
+ IN gctBOOL FromUser,
+ IN OUT gcsHAL_INTERFACE * Interface
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+ gctPHYS_ADDR physical = gcvNULL;
+ gctSIZE_T bytes;
+ gctPOINTER logical = gcvNULL;
+#if (gcdENABLE_3D || gcdENABLE_2D)
+ gckCONTEXT context = gcvNULL;
+#endif
+ gckKERNEL kernel = Kernel;
+ gctUINT32 processID;
+#if gcdSECURE_USER
+ gcskSECURE_CACHE_PTR cache;
+ gctPOINTER logical;
+#endif
+ gctUINT64 paddr = gcvINVALID_ADDRESS;
+#if !USE_NEW_LINUX_SIGNAL
+ gctSIGNAL signal;
+#endif
+ gckVIRTUAL_COMMAND_BUFFER_PTR buffer;
+
+ gctBOOL powerMutexAcquired = gcvFALSE;
+ gctBOOL commitMutexAcquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Kernel=0x%x FromUser=%d Interface=0x%x",
+ Kernel, FromUser, Interface);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Interface != gcvNULL);
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL,
+ "Dispatching command %d (%s)",
+ Interface->command, _DispatchText[Interface->command]);
+#endif
+#if QNX_SINGLE_THREADED_DEBUGGING
+ gckOS_AcquireMutex(Kernel->os, Kernel->debugMutex, gcvINFINITE);
+#endif
+
+ /* Get the current process ID. */
+ gcmkONERROR(gckOS_GetProcessID(&processID));
+
+#if gcdSECURE_USER
+ gcmkONERROR(gckKERNEL_GetProcessDBCache(Kernel, processID, &cache));
+#endif
+
+ /* Dispatch on command. */
+ switch (Interface->command)
+ {
+ case gcvHAL_GET_BASE_ADDRESS:
+ /* Get base address. */
+ Interface->u.GetBaseAddress.baseAddress = Kernel->hardware->baseAddress;
+ Interface->u.GetBaseAddress.flatMappingRangeCount = Kernel->mmu->flatMappingRangeCount;
+ if (Kernel->mmu->flatMappingRangeCount)
+ {
+ gckOS_MemCopy(Interface->u.GetBaseAddress.flatMappingRanges, Kernel->mmu->flatMappingRanges,
+ gcmSIZEOF(gcsFLAT_MAPPING_RANGE) * Kernel->mmu->flatMappingRangeCount);
+ }
+ break;
+
+ case gcvHAL_QUERY_VIDEO_MEMORY:
+ /* Query video memory size. */
+ gcmkONERROR(gckKERNEL_QueryVideoMemory(Kernel, Interface));
+ break;
+
+ case gcvHAL_QUERY_CHIP_IDENTITY:
+ /* Query chip identity. */
+ gcmkONERROR(
+ gckHARDWARE_QueryChipIdentity(
+ Kernel->hardware,
+ &Interface->u.QueryChipIdentity));
+ break;
+
+ case gcvHAL_MAP_MEMORY:
+ physical = gcmINT2PTR(Interface->u.MapMemory.physical);
+
+ /* Map memory. */
+ gcmkONERROR(
+ gckKERNEL_MapMemory(Kernel,
+ physical,
+ (gctSIZE_T) Interface->u.MapMemory.bytes,
+ &logical));
+
+ Interface->u.MapMemory.logical = gcmPTR_TO_UINT64(logical);
+
+ gcmkVERIFY_OK(
+ gckKERNEL_AddProcessDB(Kernel,
+ processID, gcvDB_MAP_MEMORY,
+ logical,
+ physical,
+ (gctSIZE_T) Interface->u.MapMemory.bytes));
+ break;
+
+ case gcvHAL_UNMAP_MEMORY:
+ physical = gcmINT2PTR(Interface->u.UnmapMemory.physical);
+
+ gcmkVERIFY_OK(
+ gckKERNEL_RemoveProcessDB(Kernel,
+ processID, gcvDB_MAP_MEMORY,
+ gcmUINT64_TO_PTR(Interface->u.UnmapMemory.logical)));
+
+ /* Unmap memory. */
+ gcmkONERROR(
+ gckKERNEL_UnmapMemory(Kernel,
+ physical,
+ (gctSIZE_T) Interface->u.UnmapMemory.bytes,
+ gcmUINT64_TO_PTR(Interface->u.UnmapMemory.logical),
+ processID));
+ break;
+
+ case gcvHAL_ALLOCATE_NON_PAGED_MEMORY:
+ bytes = (gctSIZE_T) Interface->u.AllocateNonPagedMemory.bytes;
+
+ /* Allocate non-paged memory. */
+ gcmkONERROR(
+ gckOS_AllocateNonPagedMemory(
+ Kernel->os,
+ FromUser,
+ &bytes,
+ &physical,
+ &logical));
+
+ Interface->u.AllocateNonPagedMemory.bytes = bytes;
+ Interface->u.AllocateNonPagedMemory.logical = gcmPTR_TO_UINT64(logical);
+ Interface->u.AllocateNonPagedMemory.physical = gcmPTR_TO_NAME(physical);
+
+ gcmkVERIFY_OK(
+ gckKERNEL_AddProcessDB(Kernel,
+ processID, gcvDB_NON_PAGED,
+ logical,
+ gcmINT2PTR(Interface->u.AllocateNonPagedMemory.physical),
+ bytes));
+ break;
+
+ case gcvHAL_ALLOCATE_VIRTUAL_COMMAND_BUFFER:
+ bytes = (gctSIZE_T) Interface->u.AllocateVirtualCommandBuffer.bytes;
+
+ gcmkONERROR(
+ gckKERNEL_AllocateVirtualCommandBuffer(
+ Kernel,
+ FromUser,
+ &bytes,
+ &physical,
+ &logical));
+
+ Interface->u.AllocateVirtualCommandBuffer.bytes = bytes;
+ Interface->u.AllocateVirtualCommandBuffer.logical = gcmPTR_TO_UINT64(logical);
+ Interface->u.AllocateVirtualCommandBuffer.physical = gcmPTR_TO_NAME(physical);
+
+ gcmkVERIFY_OK(
+ gckKERNEL_AddProcessDB(Kernel,
+ processID, gcvDB_COMMAND_BUFFER,
+ logical,
+ gcmINT2PTR(Interface->u.AllocateVirtualCommandBuffer.physical),
+ bytes));
+ break;
+
+ case gcvHAL_FREE_NON_PAGED_MEMORY:
+ physical = gcmNAME_TO_PTR(Interface->u.FreeNonPagedMemory.physical);
+
+ gcmkVERIFY_OK(
+ gckKERNEL_RemoveProcessDB(Kernel,
+ processID, gcvDB_NON_PAGED,
+ gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical)));
+
+ /* Unmap user logical out of physical memory first. */
+ gcmkONERROR(gckOS_UnmapUserLogical(Kernel->os,
+ physical,
+ (gctSIZE_T) Interface->u.FreeNonPagedMemory.bytes,
+ gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical)));
+
+ /* Free non-paged memory. */
+ gcmkONERROR(
+ gckOS_FreeNonPagedMemory(Kernel->os,
+ (gctSIZE_T) Interface->u.FreeNonPagedMemory.bytes,
+ physical,
+ gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical)));
+
+#if gcdSECURE_USER
+ gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
+ Kernel,
+ cache,
+ gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical),
+ (gctSIZE_T) Interface->u.FreeNonPagedMemory.bytes));
+#endif
+
+ gcmRELEASE_NAME(Interface->u.FreeNonPagedMemory.physical);
+ break;
+
+ case gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY:
+ bytes = (gctSIZE_T) Interface->u.AllocateContiguousMemory.bytes;
+
+ /* Allocate contiguous memory. */
+ gcmkONERROR(gckOS_AllocateContiguous(
+ Kernel->os,
+ FromUser,
+ &bytes,
+ &physical,
+ &logical));
+
+ Interface->u.AllocateContiguousMemory.bytes = bytes;
+ Interface->u.AllocateContiguousMemory.logical = gcmPTR_TO_UINT64(logical);
+ Interface->u.AllocateContiguousMemory.physical = gcmPTR_TO_NAME(physical);
+
+ gcmkONERROR(gckHARDWARE_ConvertLogical(
+ Kernel->hardware,
+ logical,
+ gcvTRUE,
+ &Interface->u.AllocateContiguousMemory.address));
+
+ gcmkVERIFY_OK(gckKERNEL_AddProcessDB(
+ Kernel,
+ processID, gcvDB_CONTIGUOUS,
+ logical,
+ gcmINT2PTR(Interface->u.AllocateContiguousMemory.physical),
+ bytes));
+ break;
+
+ case gcvHAL_FREE_CONTIGUOUS_MEMORY:
+ physical = gcmNAME_TO_PTR(Interface->u.FreeContiguousMemory.physical);
+
+ gcmkVERIFY_OK(
+ gckKERNEL_RemoveProcessDB(Kernel,
+ processID, gcvDB_CONTIGUOUS,
+ gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical)));
+
+ /* Unmap user logical out of physical memory first. */
+ gcmkONERROR(gckOS_UnmapUserLogical(Kernel->os,
+ physical,
+ (gctSIZE_T) Interface->u.FreeContiguousMemory.bytes,
+ gcmUINT64_TO_PTR(Interface->u.FreeContiguousMemory.logical)));
+
+ /* Free contiguous memory. */
+ gcmkONERROR(
+ gckOS_FreeContiguous(Kernel->os,
+ physical,
+ gcmUINT64_TO_PTR(Interface->u.FreeContiguousMemory.logical),
+ (gctSIZE_T) Interface->u.FreeContiguousMemory.bytes));
+
+#if gcdSECURE_USER
+ gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
+ Kernel,
+ cache,
+ gcmUINT64_TO_PTR(Interface->u.FreeContiguousMemory.logical),
+ (gctSIZE_T) Interface->u.FreeContiguousMemory.bytes));
+#endif
+
+ gcmRELEASE_NAME(Interface->u.FreeContiguousMemory.physical);
+ break;
+
+ case gcvHAL_ALLOCATE_VIDEO_MEMORY:
+
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+
+ break;
+
+ case gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY:
+ /* Allocate memory. */
+ gcmkONERROR(
+ gckKERNEL_AllocateLinearMemory(Kernel, processID,
+ &Interface->u.AllocateLinearVideoMemory.pool,
+ Interface->u.AllocateLinearVideoMemory.bytes,
+ Interface->u.AllocateLinearVideoMemory.alignment,
+ Interface->u.AllocateLinearVideoMemory.type,
+ Interface->u.AllocateLinearVideoMemory.flag,
+ &Interface->u.AllocateLinearVideoMemory.node));
+ break;
+
+ case gcvHAL_RELEASE_VIDEO_MEMORY:
+ /* Release video memory. */
+ gcmkONERROR(gckKERNEL_ReleaseVideoMemory(
+ Kernel, processID,
+ (gctUINT32)Interface->u.ReleaseVideoMemory.node
+ ));
+ break;
+
+ case gcvHAL_LOCK_VIDEO_MEMORY:
+ /* Lock video memory. */
+ gcmkONERROR(gckKERNEL_LockVideoMemory(Kernel, Kernel->core, processID, FromUser, Interface));
+ break;
+
+ case gcvHAL_UNLOCK_VIDEO_MEMORY:
+ /* Unlock video memory. */
+ gcmkONERROR(gckKERNEL_UnlockVideoMemory(Kernel, processID, Interface));
+ break;
+
+ case gcvHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY:
+ gcmkERR_BREAK(gckKERNEL_BottomHalfUnlockVideoMemory(Kernel, processID,
+ Interface->u.BottomHalfUnlockVideoMemory.node));
+ break;
+
+ case gcvHAL_EVENT_COMMIT:
+ gcmkONERROR(gckOS_AcquireMutex(Kernel->os,
+ Kernel->device->commitMutex,
+ gcvINFINITE
+ ));
+
+ commitMutexAcquired = gcvTRUE;
+ /* Commit an event queue. */
+ if (Interface->engine == gcvENGINE_BLT)
+ {
+ if (!gckHARDWARE_IsFeatureAvailable(Kernel->hardware, gcvFEATURE_ASYNC_BLIT))
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ gcmkONERROR(gckEVENT_Commit(
+ Kernel->asyncEvent, gcmUINT64_TO_PTR(Interface->u.Event.queue), gcvFALSE));
+ }
+ else
+ {
+ gcmkONERROR(gckEVENT_Commit(
+ Kernel->eventObj, gcmUINT64_TO_PTR(Interface->u.Event.queue), gcvFALSE));
+ }
+
+ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->device->commitMutex));
+ commitMutexAcquired = gcvFALSE;
+ break;
+
+ case gcvHAL_COMMIT:
+ gcmkONERROR(gckOS_AcquireMutex(Kernel->os,
+ Kernel->device->commitMutex,
+ gcvINFINITE
+ ));
+ commitMutexAcquired = gcvTRUE;
+
+ /* Commit a command and context buffer. */
+ if (Interface->engine == gcvENGINE_BLT)
+ {
+ gctUINT64 *commandBuffers = gcmUINT64_TO_PTR(Interface->u.Commit.commandBuffer);
+
+ if (!gckHARDWARE_IsFeatureAvailable(Kernel->hardware, gcvFEATURE_ASYNC_BLIT))
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ gcmkONERROR(gckASYNC_COMMAND_Commit(
+ Kernel->asyncCommand,
+ gcmUINT64_TO_PTR(commandBuffers[0]),
+ gcmUINT64_TO_PTR(Interface->u.Commit.queue)
+ ));
+
+ gcmkONERROR(gckEVENT_Commit(
+ Kernel->asyncEvent,
+ gcmUINT64_TO_PTR(Interface->u.Commit.queue),
+ gcvFALSE
+ ));
+ }
+ else
+ {
+ gctUINT32 i;
+ if (Interface->u.Commit.count > 1 && Interface->engine == gcvENGINE_RENDER)
+ {
+ gctUINT32 i;
+
+ for (i = 0; i < Interface->u.Commit.count; i++)
+ {
+ gceHARDWARE_TYPE type = Interface->hardwareType;
+ gckKERNEL kernel = Device->map[type].kernels[i];
+
+ gcmkONERROR(gckOS_Broadcast(kernel->os,
+ kernel->hardware,
+ gcvBROADCAST_GPU_COMMIT));
+ }
+ }
+
+ status = gckCOMMAND_Commit(Kernel->command,
+ Interface->u.Commit.contexts[0] ?
+ gcmNAME_TO_PTR(Interface->u.Commit.contexts[0]) : gcvNULL,
+ gcmUINT64_TO_PTR(Interface->u.Commit.commandBuffers[0]),
+ gcmUINT64_TO_PTR(Interface->u.Commit.deltas[0]),
+ processID,
+ Interface->u.Commit.shared,
+ Interface->u.Commit.index,
+ &Interface->u.Commit.commitStamp,
+ &Interface->u.Commit.contextSwitched
+ );
+
+ if (status != gcvSTATUS_INTERRUPTED)
+ {
+ gcmkONERROR(status);
+ }
+
+ /* Force an event if powerManagement is on. */
+ status = gckEVENT_Commit(Kernel->eventObj,
+ gcmUINT64_TO_PTR(Interface->u.Commit.queue),
+ Kernel->hardware->options.powerManagement);
+
+ if (status != gcvSTATUS_INTERRUPTED)
+ {
+ gcmkONERROR(status);
+ }
+
+ if (Interface->u.Commit.count > 1 && Interface->engine == gcvENGINE_RENDER)
+ {
+
+ for (i = 1; i < Interface->u.Commit.count; i++)
+ {
+ gceHARDWARE_TYPE type = Interface->hardwareType;
+ gckKERNEL kernel = Device->map[type].kernels[i];
+
+ status = gckCOMMAND_Commit(kernel->command,
+ Interface->u.Commit.contexts[i] ?
+ gcmNAME_TO_PTR(Interface->u.Commit.contexts[i]) : gcvNULL,
+ Interface->u.Commit.commandBuffers[i] ?
+ gcmUINT64_TO_PTR(Interface->u.Commit.commandBuffers[i]) : gcmUINT64_TO_PTR(Interface->u.Commit.commandBuffers[0]),
+ gcmUINT64_TO_PTR(Interface->u.Commit.deltas[i]),
+ processID,
+ Interface->u.Commit.shared,
+ Interface->u.Commit.commandBuffers[i] ?
+ Interface->u.Commit.index : i,
+ &Interface->u.Commit.commitStamp,
+ &Interface->u.Commit.contextSwitched
+ );
+
+ if (status != gcvSTATUS_INTERRUPTED)
+ {
+ gcmkONERROR(status);
+ }
+
+ /* Force an event if powerManagement is on. */
+ status = gckEVENT_Commit(kernel->eventObj,
+ gcvNULL,
+ kernel->hardware->options.powerManagement);
+
+ if (status != gcvSTATUS_INTERRUPTED)
+ {
+ gcmkONERROR(status);
+ }
+ }
+ }
+
+ for (i = 0; i < Interface->u.Commit.count; i++) {
+ gceHARDWARE_TYPE type = Interface->hardwareType;
+ gckKERNEL kernel = Device->map[type].kernels[i];
+
+ if ((kernel->hardware->options.gpuProfiler == gcvTRUE) &&
+ (kernel->profileEnable == gcvTRUE)) {
+ gcmkONERROR(gckCOMMAND_Stall(kernel->command, gcvTRUE));
+
+ if (kernel->command->currContext) {
+ gcmkONERROR(gckHARDWARE_UpdateContextProfile(
+ kernel->hardware,
+ kernel->command->currContext));
+ }
+ }
+ }
+
+ }
+ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->device->commitMutex));
+ commitMutexAcquired = gcvFALSE;
+
+ break;
+
+ case gcvHAL_STALL:
+ /* Stall the command queue. */
+ gcmkONERROR(gckCOMMAND_Stall(Kernel->command, gcvFALSE));
+
+ break;
+
+ case gcvHAL_MAP_USER_MEMORY:
+
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+
+ break;
+
+ case gcvHAL_UNMAP_USER_MEMORY:
+
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+
+ break;
+
+#if !USE_NEW_LINUX_SIGNAL
+ case gcvHAL_USER_SIGNAL:
+ /* Dispatch depends on the user signal subcommands. */
+ switch(Interface->u.UserSignal.command)
+ {
+ case gcvUSER_SIGNAL_CREATE:
+ /* Create a signal used in the user space. */
+ gcmkONERROR(
+ gckOS_CreateUserSignal(Kernel->os,
+ Interface->u.UserSignal.manualReset,
+ &Interface->u.UserSignal.id));
+
+ gcmkVERIFY_OK(
+ gckKERNEL_AddProcessDB(Kernel,
+ processID, gcvDB_SIGNAL,
+ gcmINT2PTR(Interface->u.UserSignal.id),
+ gcvNULL,
+ 0));
+ break;
+
+ case gcvUSER_SIGNAL_DESTROY:
+ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+ Kernel,
+ processID, gcvDB_SIGNAL,
+ gcmINT2PTR(Interface->u.UserSignal.id)));
+
+ /* Destroy the signal. */
+ gcmkONERROR(
+ gckOS_DestroyUserSignal(Kernel->os,
+ Interface->u.UserSignal.id));
+ break;
+
+ case gcvUSER_SIGNAL_SIGNAL:
+ /* Signal the signal. */
+ gcmkONERROR(
+ gckOS_SignalUserSignal(Kernel->os,
+ Interface->u.UserSignal.id,
+ Interface->u.UserSignal.state));
+ break;
+
+ case gcvUSER_SIGNAL_WAIT:
+ /* Wait on the signal. */
+ status = gckOS_WaitUserSignal(Kernel->os,
+ Interface->u.UserSignal.id,
+ Interface->u.UserSignal.wait);
+ break;
+
+ case gcvUSER_SIGNAL_MAP:
+ gcmkONERROR(
+ gckOS_MapSignal(Kernel->os,
+ (gctSIGNAL)(gctUINTPTR_T)Interface->u.UserSignal.id,
+ (gctHANDLE)(gctUINTPTR_T)processID,
+ &signal));
+
+ gcmkVERIFY_OK(
+ gckKERNEL_AddProcessDB(Kernel,
+ processID, gcvDB_SIGNAL,
+ gcmINT2PTR(Interface->u.UserSignal.id),
+ gcvNULL,
+ 0));
+ break;
+
+ case gcvUSER_SIGNAL_UNMAP:
+ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+ Kernel,
+ processID, gcvDB_SIGNAL,
+ gcmINT2PTR(Interface->u.UserSignal.id)));
+
+ /* Destroy the signal. */
+ gcmkONERROR(
+ gckOS_DestroyUserSignal(Kernel->os,
+ Interface->u.UserSignal.id));
+ break;
+
+ default:
+ /* Invalid user signal command. */
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+ break;
+#endif
+
+ case gcvHAL_SET_POWER_MANAGEMENT_STATE:
+ /* Set the power management state. */
+ gcmkONERROR(
+ gckHARDWARE_SetPowerManagementState(
+ Kernel->hardware,
+ Interface->u.SetPowerManagement.state));
+ break;
+
+ case gcvHAL_QUERY_POWER_MANAGEMENT_STATE:
+ /* Chip is not idle. */
+ Interface->u.QueryPowerManagement.isIdle = gcvFALSE;
+
+ /* Query the power management state. */
+ gcmkONERROR(gckHARDWARE_QueryPowerManagementState(
+ Kernel->hardware,
+ &Interface->u.QueryPowerManagement.state));
+
+ /* Query the idle state. */
+ gcmkONERROR(
+ gckHARDWARE_QueryIdle(Kernel->hardware,
+ &Interface->u.QueryPowerManagement.isIdle));
+ break;
+
+ case gcvHAL_READ_REGISTER:
+#if gcdREGISTER_ACCESS_FROM_USER
+ {
+ gceCHIPPOWERSTATE power;
+
+ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->hardware->powerMutex, gcvINFINITE));
+ powerMutexAcquired = gcvTRUE;
+ gcmkONERROR(gckHARDWARE_QueryPowerManagementState(Kernel->hardware,
+ &power));
+ if (power == gcvPOWER_ON)
+ {
+ /* Read a register. */
+ gcmkONERROR(gckOS_ReadRegisterEx(
+ Kernel->os,
+ Kernel->core,
+ Interface->u.ReadRegisterData.address,
+ &Interface->u.ReadRegisterData.data));
+ }
+ else
+ {
+ /* Chip is in power-state. */
+ Interface->u.ReadRegisterData.data = 0;
+ status = gcvSTATUS_CHIP_NOT_READY;
+ }
+ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->hardware->powerMutex));
+ powerMutexAcquired = gcvFALSE;
+ }
+#else
+ /* No access from user land to read registers. */
+ Interface->u.ReadRegisterData.data = 0;
+ status = gcvSTATUS_NOT_SUPPORTED;
+#endif
+ break;
+
+ case gcvHAL_WRITE_REGISTER:
+#if gcdREGISTER_ACCESS_FROM_USER
+ {
+ gceCHIPPOWERSTATE power;
+
+ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->hardware->powerMutex, gcvINFINITE));
+ powerMutexAcquired = gcvTRUE;
+ gcmkONERROR(gckHARDWARE_QueryPowerManagementState(Kernel->hardware,
+ &power));
+ if (power == gcvPOWER_ON)
+ {
+ /* Write a register. */
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Kernel->os,
+ Kernel->core,
+ Interface->u.WriteRegisterData.address,
+ Interface->u.WriteRegisterData.data));
+ }
+ else
+ {
+ /* Chip is in power-state. */
+ Interface->u.WriteRegisterData.data = 0;
+ status = gcvSTATUS_CHIP_NOT_READY;
+ }
+ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->hardware->powerMutex));
+ powerMutexAcquired = gcvFALSE;
+ }
+#else
+ /* No access from user land to write registers. */
+ status = gcvSTATUS_NOT_SUPPORTED;
+#endif
+ break;
+
+ case gcvHAL_READ_ALL_PROFILE_REGISTERS_PART1:
+ /* Read profile data according to the context. */
+ gcmkONERROR(
+ gckHARDWARE_QueryContextProfile(
+ Kernel->hardware,
+ Kernel->profileCleanRegister,
+ gcmNAME_TO_PTR(Interface->u.RegisterProfileData_part1.context),
+ &Interface->u.RegisterProfileData_part1.Counters,
+ gcvNULL));
+ break;
+ case gcvHAL_READ_ALL_PROFILE_REGISTERS_PART2:
+ /* Read profile data according to the context. */
+ gcmkONERROR(
+ gckHARDWARE_QueryContextProfile(
+ Kernel->hardware,
+ Kernel->profileCleanRegister,
+ gcmNAME_TO_PTR(Interface->u.RegisterProfileData_part2.context),
+ gcvNULL,
+ &Interface->u.RegisterProfileData_part2.Counters));
+ break;
+
+ case gcvHAL_GET_PROFILE_SETTING:
+#if VIVANTE_PROFILER
+ /* Get profile setting */
+ Interface->u.GetProfileSetting.enable = Kernel->profileEnable;
+#endif
+
+ status = gcvSTATUS_OK;
+ break;
+
+ case gcvHAL_SET_PROFILE_SETTING:
+#if VIVANTE_PROFILER
+ /* Set profile setting */
+ if(Kernel->hardware->options.gpuProfiler)
+ {
+ Kernel->profileEnable = Interface->u.SetProfileSetting.enable;
+
+ if (Kernel->profileEnable)
+ {
+ gcmkONERROR(gckHARDWARE_InitProfiler(Kernel->hardware));
+ }
+
+ }
+ else
+ {
+ status = gcvSTATUS_NOT_SUPPORTED;
+ break;
+ }
+#endif
+
+ status = gcvSTATUS_OK;
+ break;
+
+ case gcvHAL_READ_PROFILER_REGISTER_SETTING:
+ Kernel->profileCleanRegister = Interface->u.SetProfilerRegisterClear.bclear;
+ status = gcvSTATUS_OK;
+ break;
+
+ case gcvHAL_QUERY_KERNEL_SETTINGS:
+ /* Get kernel settings. */
+ gcmkONERROR(
+ gckKERNEL_QuerySettings(Kernel,
+ &Interface->u.QueryKernelSettings.settings));
+ break;
+
+ case gcvHAL_RESET:
+ /* Reset the hardware. */
+ gcmkONERROR(
+ gckHARDWARE_Reset(Kernel->hardware));
+ break;
+
+ case gcvHAL_DEBUG:
+ /* Set debug level and zones. */
+ if (Interface->u.Debug.set)
+ {
+ gckOS_SetDebugLevel(Interface->u.Debug.level);
+ gckOS_SetDebugZones(Interface->u.Debug.zones,
+ Interface->u.Debug.enable);
+ }
+
+ if (Interface->u.Debug.message[0] != '\0')
+ {
+ /* Print a message to the debugger. */
+ if (Interface->u.Debug.type == gcvMESSAGE_TEXT)
+ {
+ gckOS_DumpBuffer(Kernel->os,
+ Interface->u.Debug.message,
+ gcmSIZEOF(Interface->u.Debug.message),
+ gcvDUMP_BUFFER_FROM_USER,
+ gcvTRUE);
+ }
+ else
+ {
+ gckOS_DumpBuffer(Kernel->os,
+ Interface->u.Debug.message,
+ Interface->u.Debug.messageSize,
+ gcvDUMP_BUFFER_FROM_USER,
+ gcvTRUE);
+ }
+ }
+ status = gcvSTATUS_OK;
+ break;
+
+ case gcvHAL_DUMP_GPU_STATE:
+ {
+ gceCHIPPOWERSTATE power;
+
+ _DumpDriverConfigure(Kernel);
+
+ gcmkONERROR(gckHARDWARE_QueryPowerManagementState(
+ Kernel->hardware,
+ &power
+ ));
+
+ if (power == gcvPOWER_ON)
+ {
+ Interface->u.ReadRegisterData.data = 1;
+
+ _DumpState(Kernel);
+ }
+ else
+ {
+ Interface->u.ReadRegisterData.data = 0;
+ status = gcvSTATUS_CHIP_NOT_READY;
+
+ gcmkPRINT("[galcore]: Can't dump state if GPU isn't POWER ON.");
+ }
+ }
+ break;
+
+ case gcvHAL_DUMP_EVENT:
+ break;
+
+ case gcvHAL_CACHE:
+
+ logical = gcmUINT64_TO_PTR(Interface->u.Cache.logical);
+
+ bytes = (gctSIZE_T) Interface->u.Cache.bytes;
+ switch(Interface->u.Cache.operation)
+ {
+ case gcvCACHE_FLUSH:
+ /* Clean and invalidate the cache. */
+ status = gckOS_CacheFlush(Kernel->os,
+ processID,
+ physical,
+ paddr,
+ logical,
+ bytes);
+ break;
+ case gcvCACHE_CLEAN:
+ /* Clean the cache. */
+ status = gckOS_CacheClean(Kernel->os,
+ processID,
+ physical,
+ paddr,
+ logical,
+ bytes);
+ break;
+ case gcvCACHE_INVALIDATE:
+ /* Invalidate the cache. */
+ status = gckOS_CacheInvalidate(Kernel->os,
+ processID,
+ physical,
+ paddr,
+ logical,
+ bytes);
+ break;
+
+ case gcvCACHE_MEMORY_BARRIER:
+ status = gckOS_MemoryBarrier(Kernel->os,
+ logical);
+ break;
+ default:
+ status = gcvSTATUS_INVALID_ARGUMENT;
+ break;
+ }
+ break;
+
+ case gcvHAL_TIMESTAMP:
+ /* Check for invalid timer. */
+ if ((Interface->u.TimeStamp.timer >= gcmCOUNTOF(Kernel->timers))
+ || (Interface->u.TimeStamp.request != 2))
+ {
+ Interface->u.TimeStamp.timeDelta = 0;
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ /* Return timer results and reset timer. */
+ {
+ gcsTIMER_PTR timer = &(Kernel->timers[Interface->u.TimeStamp.timer]);
+ gctUINT64 timeDelta = 0;
+
+ if (timer->stopTime < timer->startTime )
+ {
+ Interface->u.TimeStamp.timeDelta = 0;
+ gcmkONERROR(gcvSTATUS_TIMER_OVERFLOW);
+ }
+
+ timeDelta = timer->stopTime - timer->startTime;
+
+ /* Check truncation overflow. */
+ Interface->u.TimeStamp.timeDelta = (gctINT32) timeDelta;
+ /*bit0~bit30 is available*/
+ if (timeDelta>>31)
+ {
+ Interface->u.TimeStamp.timeDelta = 0;
+ gcmkONERROR(gcvSTATUS_TIMER_OVERFLOW);
+ }
+
+ status = gcvSTATUS_OK;
+ }
+ break;
+
+ case gcvHAL_DATABASE:
+ gcmkONERROR(gckKERNEL_QueryDatabase(Kernel, processID, Interface));
+ break;
+
+ case gcvHAL_VERSION:
+ Interface->u.Version.major = gcvVERSION_MAJOR;
+ Interface->u.Version.minor = gcvVERSION_MINOR;
+ Interface->u.Version.patch = gcvVERSION_PATCH;
+ Interface->u.Version.build = gcvVERSION_BUILD;
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL,
+ "KERNEL version %d.%d.%d build %u",
+ gcvVERSION_MAJOR, gcvVERSION_MINOR,
+ gcvVERSION_PATCH, gcvVERSION_BUILD);
+#endif
+ break;
+
+ case gcvHAL_CHIP_INFO:
+ /* Only if not support multi-core */
+ Interface->u.ChipInfo.count = 1;
+ Interface->u.ChipInfo.types[0] = Kernel->hardware->type;
+ break;
+
+#if (gcdENABLE_3D || gcdENABLE_2D)
+ case gcvHAL_ATTACH:
+ /* Attach user process. */
+ gcmkONERROR(
+ gckCOMMAND_Attach(Kernel->command,
+ &context,
+ &bytes,
+ &Interface->u.Attach.numStates,
+ processID));
+
+ Interface->u.Attach.maxState = bytes;
+ Interface->u.Attach.context = gcmPTR_TO_NAME(context);
+
+ if (Interface->u.Attach.map == gcvTRUE)
+ {
+ gcmkVERIFY_OK(
+ gckCONTEXT_MapBuffer(context,
+ Interface->u.Attach.physicals,
+ Interface->u.Attach.logicals,
+ &Interface->u.Attach.bytes));
+ }
+
+ gcmkVERIFY_OK(
+ gckKERNEL_AddProcessDB(Kernel,
+ processID, gcvDB_CONTEXT,
+ gcmINT2PTR(Interface->u.Attach.context),
+ gcvNULL,
+ 0));
+ break;
+#endif
+
+ case gcvHAL_DETACH:
+ gcmkVERIFY_OK(
+ gckKERNEL_RemoveProcessDB(Kernel,
+ processID, gcvDB_CONTEXT,
+ gcmINT2PTR(Interface->u.Detach.context)));
+
+ /* Detach user process. */
+ gcmkONERROR(
+ gckCOMMAND_Detach(Kernel->command,
+ gcmNAME_TO_PTR(Interface->u.Detach.context)));
+
+ gcmRELEASE_NAME(Interface->u.Detach.context);
+ break;
+
+ case gcvHAL_GET_FRAME_INFO:
+ gcmkONERROR(gckHARDWARE_GetFrameInfo(
+ Kernel->hardware,
+ gcmUINT64_TO_PTR(Interface->u.GetFrameInfo.frameInfo)));
+ break;
+
+ case gcvHAL_DUMP_GPU_PROFILE:
+ gcmkONERROR(gckHARDWARE_DumpGpuProfile(Kernel->hardware));
+ break;
+
+ case gcvHAL_SET_FSCALE_VALUE:
+#if gcdENABLE_FSCALE_VAL_ADJUST
+ status = gckHARDWARE_SetFscaleValue(Kernel->hardware,
+ Interface->u.SetFscaleValue.value);
+#else
+ status = gcvSTATUS_NOT_SUPPORTED;
+#endif
+ break;
+ case gcvHAL_GET_FSCALE_VALUE:
+#if gcdENABLE_FSCALE_VAL_ADJUST
+ status = gckHARDWARE_GetFscaleValue(Kernel->hardware,
+ &Interface->u.GetFscaleValue.value,
+ &Interface->u.GetFscaleValue.minValue,
+ &Interface->u.GetFscaleValue.maxValue);
+#else
+ status = gcvSTATUS_NOT_SUPPORTED;
+#endif
+ break;
+
+ case gcvHAL_EXPORT_VIDEO_MEMORY:
+ /* Unlock video memory. */
+ gcmkONERROR(gckVIDMEM_NODE_Export(Kernel,
+ Interface->u.ExportVideoMemory.node,
+ Interface->u.ExportVideoMemory.flags,
+ gcvNULL,
+ &Interface->u.ExportVideoMemory.fd));
+ break;
+
+ case gcvHAL_NAME_VIDEO_MEMORY:
+ gcmkONERROR(gckVIDMEM_NODE_Name(Kernel,
+ Interface->u.NameVideoMemory.handle,
+ &Interface->u.NameVideoMemory.name));
+ break;
+
+ case gcvHAL_IMPORT_VIDEO_MEMORY:
+ gcmkONERROR(gckVIDMEM_NODE_Import(Kernel,
+ Interface->u.ImportVideoMemory.name,
+ &Interface->u.ImportVideoMemory.handle));
+
+ gcmkONERROR(
+ gckKERNEL_AddProcessDB(Kernel,
+ processID, gcvDB_VIDEO_MEMORY,
+ gcmINT2PTR(Interface->u.ImportVideoMemory.handle),
+ gcvNULL,
+ 0));
+ break;
+
+ case gcvHAL_SET_VIDEO_MEMORY_METADATA:
+ gcmkONERROR(gckKERNEL_SetVidMemMetadata(Kernel, processID, Interface));
+ break;
+
+ case gcvHAL_GET_VIDEO_MEMORY_FD:
+ gcmkONERROR(gckVIDMEM_NODE_GetFd(
+ Kernel,
+ Interface->u.GetVideoMemoryFd.handle,
+ &Interface->u.GetVideoMemoryFd.fd
+ ));
+
+ /* No need to add it to processDB because OS will release all fds when
+ ** process quits.
+ */
+ break;
+
+ case gcvHAL_QUERY_RESET_TIME_STAMP:
+ Interface->u.QueryResetTimeStamp.timeStamp = Kernel->resetTimeStamp;
+ Interface->u.QueryResetTimeStamp.contextID = Kernel->hardware->contextID;
+ break;
+
+ case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER:
+ buffer = (gckVIRTUAL_COMMAND_BUFFER_PTR)gcmNAME_TO_PTR(Interface->u.FreeVirtualCommandBuffer.physical);
+
+ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+ Kernel,
+ processID,
+ gcvDB_COMMAND_BUFFER,
+ gcmUINT64_TO_PTR(Interface->u.FreeVirtualCommandBuffer.logical)));
+
+ gcmkONERROR(gckOS_DestroyUserVirtualMapping(
+ Kernel->os,
+ buffer->virtualBuffer.physical,
+ (gctSIZE_T)Interface->u.FreeVirtualCommandBuffer.bytes,
+ gcmUINT64_TO_PTR(Interface->u.FreeVirtualCommandBuffer.logical)));
+
+ gcmkONERROR(gckKERNEL_DestroyVirtualCommandBuffer(
+ Kernel,
+ (gctSIZE_T)Interface->u.FreeVirtualCommandBuffer.bytes,
+ (gctPHYS_ADDR)buffer,
+ gcmUINT64_TO_PTR(Interface->u.FreeVirtualCommandBuffer.logical)));
+
+ gcmRELEASE_NAME(Interface->u.FreeVirtualCommandBuffer.physical);
+ break;
+
+#if gcdANDROID_NATIVE_FENCE_SYNC
+ case gcvHAL_CREATE_NATIVE_FENCE:
+ {
+ gctINT fenceFD;
+ gctSIGNAL signal =
+ gcmUINT64_TO_PTR(Interface->u.CreateNativeFence.signal);
+
+ gcmkONERROR(
+ gckOS_CreateNativeFence(Kernel->os,
+ Kernel->timeline,
+ signal,
+ &fenceFD));
+
+ Interface->u.CreateNativeFence.fenceFD = fenceFD;
+ }
+ break;
+
+ case gcvHAL_WAIT_NATIVE_FENCE:
+ {
+ gctINT fenceFD;
+ gctUINT32 timeout;
+
+ fenceFD = Interface->u.WaitNativeFence.fenceFD;
+ timeout = Interface->u.WaitNativeFence.timeout;
+
+ gcmkONERROR(
+ gckOS_WaitNativeFence(Kernel->os,
+ Kernel->timeline,
+ fenceFD,
+ timeout));
+ }
+ break;
+#endif
+
+ case gcvHAL_SHBUF:
+ {
+ gctSHBUF shBuf;
+ gctPOINTER uData;
+ gctUINT32 bytes;
+
+ switch (Interface->u.ShBuf.command)
+ {
+ case gcvSHBUF_CREATE:
+ bytes = Interface->u.ShBuf.bytes;
+
+ /* Create. */
+ gcmkONERROR(gckKERNEL_CreateShBuffer(Kernel, bytes, &shBuf));
+
+ Interface->u.ShBuf.id = gcmPTR_TO_UINT64(shBuf);
+
+ gcmkVERIFY_OK(
+ gckKERNEL_AddProcessDB(Kernel,
+ processID,
+ gcvDB_SHBUF,
+ shBuf,
+ gcvNULL,
+ 0));
+ break;
+
+ case gcvSHBUF_DESTROY:
+ shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id);
+
+ /* Check db first to avoid illegal destroy in the process. */
+ gcmkONERROR(
+ gckKERNEL_RemoveProcessDB(Kernel,
+ processID,
+ gcvDB_SHBUF,
+ shBuf));
+
+ gcmkONERROR(gckKERNEL_DestroyShBuffer(Kernel, shBuf));
+ break;
+
+ case gcvSHBUF_MAP:
+ shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id);
+
+ /* Map for current process access. */
+ gcmkONERROR(gckKERNEL_MapShBuffer(Kernel, shBuf));
+
+ gcmkVERIFY_OK(
+ gckKERNEL_AddProcessDB(Kernel,
+ processID,
+ gcvDB_SHBUF,
+ shBuf,
+ gcvNULL,
+ 0));
+ break;
+
+ case gcvSHBUF_WRITE:
+ shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id);
+ uData = gcmUINT64_TO_PTR(Interface->u.ShBuf.data);
+ bytes = Interface->u.ShBuf.bytes;
+
+ /* Write. */
+ gcmkONERROR(
+ gckKERNEL_WriteShBuffer(Kernel, shBuf, uData, bytes));
+ break;
+
+ case gcvSHBUF_READ:
+ shBuf = gcmUINT64_TO_PTR(Interface->u.ShBuf.id);
+ uData = gcmUINT64_TO_PTR(Interface->u.ShBuf.data);
+ bytes = Interface->u.ShBuf.bytes;
+
+ /* Read. */
+ gcmkONERROR(
+ gckKERNEL_ReadShBuffer(Kernel,
+ shBuf,
+ uData,
+ bytes,
+ &bytes));
+
+ /* Return copied size. */
+ Interface->u.ShBuf.bytes = bytes;
+ break;
+
+ default:
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ break;
+ }
+ }
+ break;
+
+#ifdef __linux__
+ case gcvHAL_GET_GRAPHIC_BUFFER_FD:
+ gcmkONERROR(_GetGraphicBufferFd(
+ Kernel,
+ processID,
+ Interface->u.GetGraphicBufferFd.node,
+ Interface->u.GetGraphicBufferFd.shBuf,
+ Interface->u.GetGraphicBufferFd.signal,
+ &Interface->u.GetGraphicBufferFd.fd
+ ));
+ break;
+#endif
+
+
+ case gcvHAL_CONFIG_POWER_MANAGEMENT:
+ gcmkONERROR(gckKERNEL_ConfigPowerManagement(Kernel, Interface));
+ break;
+
+ case gcvHAL_WRAP_USER_MEMORY:
+ gcmkONERROR(gckVIDMEM_NODE_WrapUserMemory(Kernel,
+ &Interface->u.WrapUserMemory.desc,
+ &Interface->u.WrapUserMemory.node,
+ &Interface->u.WrapUserMemory.bytes));
+
+ gcmkONERROR(
+ gckKERNEL_AddProcessDB(Kernel,
+ processID,
+ gcvDB_VIDEO_MEMORY,
+ gcmINT2PTR(Interface->u.WrapUserMemory.node),
+ gcvNULL,
+ 0));
+ break;
+
+ case gcvHAL_WAIT_FENCE:
+ gcmkONERROR(gckKERNEL_WaitFence(
+ Kernel,
+ Interface->u.WaitFence.handle,
+ Interface->u.WaitFence.timeOut
+ ));
+ break;
+
+#if gcdDEC_ENABLE_AHB
+ case gcvHAL_DEC300_READ:
+ gcmkONERROR(viv_dec300_read(
+ Interface->u.DEC300Read.enable,
+ Interface->u.DEC300Read.readId,
+ Interface->u.DEC300Read.format,
+ Interface->u.DEC300Read.strides,
+ Interface->u.DEC300Read.is3D,
+ Interface->u.DEC300Read.isMSAA,
+ Interface->u.DEC300Read.clearValue,
+ Interface->u.DEC300Read.isTPC,
+ Interface->u.DEC300Read.isTPCCompressed,
+ Interface->u.DEC300Read.surfAddrs,
+ Interface->u.DEC300Read.tileAddrs
+ ));
+ break;
+
+ case gcvHAL_DEC300_WRITE:
+ gcmkONERROR(viv_dec300_write(
+ Interface->u.DEC300Write.enable,
+ Interface->u.DEC300Write.readId,
+ Interface->u.DEC300Write.writeId,
+ Interface->u.DEC300Write.format,
+ Interface->u.DEC300Write.surfAddr,
+ Interface->u.DEC300Write.tileAddr
+ ));
+ break;
+
+ case gcvHAL_DEC300_FLUSH:
+ gcmkONERROR(viv_dec300_flush(0));
+ break;
+
+ case gcvHAL_DEC300_FLUSH_WAIT:
+ gcmkONERROR(viv_dec300_flush_done(&Interface->u.DEC300FlushWait.done));
+ break;
+#endif
+
+
+ case gcvHAL_QUERY_CHIP_OPTION:
+ /* Query chip options. */
+ gcmkONERROR(
+ gckHARDWARE_QueryChipOptions(
+ Kernel->hardware,
+ &Interface->u.QueryChipOptions));
+ break;
+
+ default:
+ /* Invalid command. */
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+OnError:
+ /* Save status. */
+ Interface->status = status;
+
+#if QNX_SINGLE_THREADED_DEBUGGING
+ gckOS_ReleaseMutex(Kernel->os, Kernel->debugMutex);
+#endif
+
+ if (powerMutexAcquired == gcvTRUE)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->hardware->powerMutex));
+ }
+
+ if (commitMutexAcquired == gcvTRUE)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->device->commitMutex));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+** gckKERNEL_AttachProcess
+**
+** Attach or detach a process.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctBOOL Attach
+** gcvTRUE if a new process gets attached or gcFALSE when a process
+** gets detatched.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckKERNEL_AttachProcess(
+ IN gckKERNEL Kernel,
+ IN gctBOOL Attach
+ )
+{
+ gceSTATUS status;
+ gctUINT32 processID;
+
+ gcmkHEADER_ARG("Kernel=0x%x Attach=%d", Kernel, Attach);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+ /* Get current process ID. */
+ gcmkONERROR(gckOS_GetProcessID(&processID));
+
+ gcmkONERROR(gckKERNEL_AttachProcessEx(Kernel, Attach, processID));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+** gckKERNEL_AttachProcessEx
+**
+** Attach or detach a process with the given PID. Can be paired with gckKERNEL_AttachProcess
+** provided the programmer is aware of the consequences.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctBOOL Attach
+** gcvTRUE if a new process gets attached or gcFALSE when a process
+** gets detatched.
+**
+** gctUINT32 PID
+** PID of the process to attach or detach.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckKERNEL_AttachProcessEx(
+ IN gckKERNEL Kernel,
+ IN gctBOOL Attach,
+ IN gctUINT32 PID
+ )
+{
+ gceSTATUS status;
+ gctINT32 old;
+
+ gcmkHEADER_ARG("Kernel=0x%x Attach=%d PID=%d", Kernel, Attach, PID);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+ if (Attach)
+ {
+ /* Increment the number of clients attached. */
+ gcmkONERROR(
+ gckOS_AtomIncrement(Kernel->os, Kernel->atomClients, &old));
+
+ if (old == 0)
+ {
+#if gcdENABLE_VG
+ if (Kernel->vg == gcvNULL)
+#endif
+ {
+ gcmkONERROR(gckOS_Broadcast(Kernel->os,
+ Kernel->hardware,
+ gcvBROADCAST_FIRST_PROCESS));
+ }
+ }
+
+ if (Kernel->dbCreated)
+ {
+ /* Create the process database. */
+ gcmkONERROR(gckKERNEL_CreateProcessDB(Kernel, PID));
+ }
+
+#if gcdPROCESS_ADDRESS_SPACE
+ /* Map kernel command buffer in the process's own MMU. */
+ gcmkONERROR(_MapCommandBuffer(Kernel));
+#endif
+ }
+ else
+ {
+ if (Kernel->dbCreated)
+ {
+ /* Clean up the process database. */
+ gcmkONERROR(gckKERNEL_DestroyProcessDB(Kernel, PID));
+
+ /* Save the last know process ID. */
+ Kernel->db->lastProcessID = PID;
+ }
+
+#if gcdENABLE_VG
+ if (Kernel->vg == gcvNULL)
+#endif
+ {
+ status = gckEVENT_Submit(Kernel->eventObj, gcvTRUE, gcvFALSE);
+
+ if (status == gcvSTATUS_INTERRUPTED && Kernel->eventObj->submitTimer)
+ {
+ gcmkONERROR(gckOS_StartTimer(Kernel->os,
+ Kernel->eventObj->submitTimer,
+ 1));
+ }
+ else
+ {
+ gcmkONERROR(status);
+ }
+ }
+
+ /* Decrement the number of clients attached. */
+ gcmkONERROR(
+ gckOS_AtomDecrement(Kernel->os, Kernel->atomClients, &old));
+
+ if (old == 1)
+ {
+#if gcdENABLE_VG
+ if (Kernel->vg == gcvNULL)
+#endif
+ {
+ /* Last client detached, switch to SUSPEND power state. */
+ gcmkONERROR(gckOS_Broadcast(Kernel->os,
+ Kernel->hardware,
+ gcvBROADCAST_LAST_PROCESS));
+ }
+
+ /* Flush the debug cache. */
+ gcmkDEBUGFLUSH(~0U);
+ }
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+#if gcdSECURE_USER
+gceSTATUS
+gckKERNEL_MapLogicalToPhysical(
+ IN gckKERNEL Kernel,
+ IN gcskSECURE_CACHE_PTR Cache,
+ IN OUT gctPOINTER * Data
+ )
+{
+ gceSTATUS status;
+ static gctBOOL baseAddressValid = gcvFALSE;
+ static gctUINT32 baseAddress;
+ gctBOOL needBase;
+ gcskLOGICAL_CACHE_PTR slot;
+
+ gcmkHEADER_ARG("Kernel=0x%x Cache=0x%x *Data=0x%x",
+ Kernel, Cache, gcmOPT_POINTER(Data));
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+ if (!baseAddressValid)
+ {
+ /* Get base address. */
+ gcmkONERROR(gckHARDWARE_GetBaseAddress(Kernel->hardware, &baseAddress));
+
+ baseAddressValid = gcvTRUE;
+ }
+
+ /* Does this state load need a base address? */
+ gcmkONERROR(gckHARDWARE_NeedBaseAddress(Kernel->hardware,
+ ((gctUINT32_PTR) Data)[-1],
+ &needBase));
+
+#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_LRU
+ {
+ gcskLOGICAL_CACHE_PTR next;
+ gctINT i;
+
+ /* Walk all used cache slots. */
+ for (i = 1, slot = Cache->cache[0].next, next = gcvNULL;
+ (i <= gcdSECURE_CACHE_SLOTS) && (slot->logical != gcvNULL);
+ ++i, slot = slot->next
+ )
+ {
+ if (slot->logical == *Data)
+ {
+ /* Bail out. */
+ next = slot;
+ break;
+ }
+ }
+
+ /* See if we had a miss. */
+ if (next == gcvNULL)
+ {
+ /* Use the tail of the cache. */
+ slot = Cache->cache[0].prev;
+
+ /* Initialize the cache line. */
+ slot->logical = *Data;
+
+ /* Map the logical address to a DMA address. */
+ gcmkONERROR(
+ gckOS_GetPhysicalAddress(Kernel->os, *Data, &slot->dma));
+ }
+
+ /* Move slot to head of list. */
+ if (slot != Cache->cache[0].next)
+ {
+ /* Unlink. */
+ slot->prev->next = slot->next;
+ slot->next->prev = slot->prev;
+
+ /* Move to head of chain. */
+ slot->prev = &Cache->cache[0];
+ slot->next = Cache->cache[0].next;
+ slot->prev->next = slot;
+ slot->next->prev = slot;
+ }
+ }
+#elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_LINEAR
+ {
+ gctINT i;
+ gcskLOGICAL_CACHE_PTR next = gcvNULL;
+ gcskLOGICAL_CACHE_PTR oldestSlot = gcvNULL;
+ slot = gcvNULL;
+
+ if (Cache->cacheIndex != gcvNULL)
+ {
+ /* Walk the cache forwards. */
+ for (i = 1, slot = Cache->cacheIndex;
+ (i <= gcdSECURE_CACHE_SLOTS) && (slot->logical != gcvNULL);
+ ++i, slot = slot->next)
+ {
+ if (slot->logical == *Data)
+ {
+ /* Bail out. */
+ next = slot;
+ break;
+ }
+
+ /* Determine age of this slot. */
+ if ((oldestSlot == gcvNULL)
+ || (oldestSlot->stamp > slot->stamp)
+ )
+ {
+ oldestSlot = slot;
+ }
+ }
+
+ if (next == gcvNULL)
+ {
+ /* Walk the cache backwards. */
+ for (slot = Cache->cacheIndex->prev;
+ (i <= gcdSECURE_CACHE_SLOTS) && (slot->logical != gcvNULL);
+ ++i, slot = slot->prev)
+ {
+ if (slot->logical == *Data)
+ {
+ /* Bail out. */
+ next = slot;
+ break;
+ }
+
+ /* Determine age of this slot. */
+ if ((oldestSlot == gcvNULL)
+ || (oldestSlot->stamp > slot->stamp)
+ )
+ {
+ oldestSlot = slot;
+ }
+ }
+ }
+ }
+
+ /* See if we had a miss. */
+ if (next == gcvNULL)
+ {
+ if (Cache->cacheFree != 0)
+ {
+ slot = &Cache->cache[Cache->cacheFree];
+ gcmkASSERT(slot->logical == gcvNULL);
+
+ ++ Cache->cacheFree;
+ if (Cache->cacheFree >= gcmCOUNTOF(Cache->cache))
+ {
+ Cache->cacheFree = 0;
+ }
+ }
+ else
+ {
+ /* Use the oldest cache slot. */
+ gcmkASSERT(oldestSlot != gcvNULL);
+ slot = oldestSlot;
+
+ /* Unlink from the chain. */
+ slot->prev->next = slot->next;
+ slot->next->prev = slot->prev;
+
+ /* Append to the end. */
+ slot->prev = Cache->cache[0].prev;
+ slot->next = &Cache->cache[0];
+ slot->prev->next = slot;
+ slot->next->prev = slot;
+ }
+
+ /* Initialize the cache line. */
+ slot->logical = *Data;
+
+ /* Map the logical address to a DMA address. */
+ gcmkONERROR(
+ gckOS_GetPhysicalAddress(Kernel->os, *Data, &slot->dma));
+ }
+
+ /* Save time stamp. */
+ slot->stamp = ++ Cache->cacheStamp;
+
+ /* Save current slot for next lookup. */
+ Cache->cacheIndex = slot;
+ }
+#elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
+ {
+ gctINT i;
+ gctUINT32 data = gcmPTR2INT32(*Data);
+ gctUINT32 key, index;
+ gcskLOGICAL_CACHE_PTR hash;
+
+ /* Generate a hash key. */
+ key = (data >> 24) + (data >> 16) + (data >> 8) + data;
+ index = key % gcmCOUNTOF(Cache->hash);
+
+ /* Get the hash entry. */
+ hash = &Cache->hash[index];
+
+ for (slot = hash->nextHash, i = 0;
+ (slot != gcvNULL) && (i < gcdSECURE_CACHE_SLOTS);
+ slot = slot->nextHash, ++i
+ )
+ {
+ if (slot->logical == (*Data))
+ {
+ break;
+ }
+ }
+
+ if (slot == gcvNULL)
+ {
+ /* Grab from the tail of the cache. */
+ slot = Cache->cache[0].prev;
+
+ /* Unlink slot from any hash table it is part of. */
+ if (slot->prevHash != gcvNULL)
+ {
+ slot->prevHash->nextHash = slot->nextHash;
+ }
+ if (slot->nextHash != gcvNULL)
+ {
+ slot->nextHash->prevHash = slot->prevHash;
+ }
+
+ /* Initialize the cache line. */
+ slot->logical = *Data;
+
+ /* Map the logical address to a DMA address. */
+ gcmkONERROR(
+ gckOS_GetPhysicalAddress(Kernel->os, *Data, &slot->dma));
+
+ if (hash->nextHash != gcvNULL)
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL,
+ "Hash Collision: logical=0x%x key=0x%08x",
+ *Data, key);
+ }
+
+ /* Insert the slot at the head of the hash list. */
+ slot->nextHash = hash->nextHash;
+ if (slot->nextHash != gcvNULL)
+ {
+ slot->nextHash->prevHash = slot;
+ }
+ slot->prevHash = hash;
+ hash->nextHash = slot;
+ }
+
+ /* Move slot to head of list. */
+ if (slot != Cache->cache[0].next)
+ {
+ /* Unlink. */
+ slot->prev->next = slot->next;
+ slot->next->prev = slot->prev;
+
+ /* Move to head of chain. */
+ slot->prev = &Cache->cache[0];
+ slot->next = Cache->cache[0].next;
+ slot->prev->next = slot;
+ slot->next->prev = slot;
+ }
+ }
+#elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_TABLE
+ {
+ gctUINT32 index = (gcmPTR2INT32(*Data) % gcdSECURE_CACHE_SLOTS) + 1;
+
+ /* Get cache slot. */
+ slot = &Cache->cache[index];
+
+ /* Check for cache miss. */
+ if (slot->logical != *Data)
+ {
+ /* Initialize the cache line. */
+ slot->logical = *Data;
+
+ /* Map the logical address to a DMA address. */
+ gcmkONERROR(
+ gckOS_GetPhysicalAddress(Kernel->os, *Data, &slot->dma));
+ }
+ }
+#endif
+
+ /* Return DMA address. */
+ *Data = gcmINT2PTR(slot->dma + (needBase ? baseAddress : 0));
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Data=0x%08x", *Data);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_FlushTranslationCache(
+ IN gckKERNEL Kernel,
+ IN gcskSECURE_CACHE_PTR Cache,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ )
+{
+ gctINT i;
+ gcskLOGICAL_CACHE_PTR slot;
+ gctUINT8_PTR ptr;
+
+ gcmkHEADER_ARG("Kernel=0x%x Cache=0x%x Logical=0x%x Bytes=%lu",
+ Kernel, Cache, Logical, Bytes);
+
+ /* Do we need to flush the entire cache? */
+ if (Logical == gcvNULL)
+ {
+ /* Clear all cache slots. */
+ for (i = 1; i <= gcdSECURE_CACHE_SLOTS; ++i)
+ {
+ Cache->cache[i].logical = gcvNULL;
+
+#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
+ Cache->cache[i].nextHash = gcvNULL;
+ Cache->cache[i].prevHash = gcvNULL;
+#endif
+}
+
+#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
+ /* Zero the hash table. */
+ for (i = 0; i < gcmCOUNTOF(Cache->hash); ++i)
+ {
+ Cache->hash[i].nextHash = gcvNULL;
+ }
+#endif
+
+ /* Reset the cache functionality. */
+ Cache->cacheIndex = gcvNULL;
+ Cache->cacheFree = 1;
+ Cache->cacheStamp = 0;
+ }
+
+ else
+ {
+ gctUINT8_PTR low = (gctUINT8_PTR) Logical;
+ gctUINT8_PTR high = low + Bytes;
+
+#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_LRU
+ gcskLOGICAL_CACHE_PTR next;
+
+ /* Walk all used cache slots. */
+ for (i = 1, slot = Cache->cache[0].next;
+ (i <= gcdSECURE_CACHE_SLOTS) && (slot->logical != gcvNULL);
+ ++i, slot = next
+ )
+ {
+ /* Save pointer to next slot. */
+ next = slot->next;
+
+ /* Test if this slot falls within the range to flush. */
+ ptr = (gctUINT8_PTR) slot->logical;
+ if ((ptr >= low) && (ptr < high))
+ {
+ /* Unlink slot. */
+ slot->prev->next = slot->next;
+ slot->next->prev = slot->prev;
+
+ /* Append slot to tail of cache. */
+ slot->prev = Cache->cache[0].prev;
+ slot->next = &Cache->cache[0];
+ slot->prev->next = slot;
+ slot->next->prev = slot;
+
+ /* Mark slot as empty. */
+ slot->logical = gcvNULL;
+ }
+ }
+
+#elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_LINEAR
+ gcskLOGICAL_CACHE_PTR next;
+
+ for (i = 1, slot = Cache->cache[0].next;
+ (i <= gcdSECURE_CACHE_SLOTS) && (slot->logical != gcvNULL);
+ ++i, slot = next)
+ {
+ /* Save pointer to next slot. */
+ next = slot->next;
+
+ /* Test if this slot falls within the range to flush. */
+ ptr = (gctUINT8_PTR) slot->logical;
+ if ((ptr >= low) && (ptr < high))
+ {
+ /* Test if this slot is the current slot. */
+ if (slot == Cache->cacheIndex)
+ {
+ /* Move to next or previous slot. */
+ Cache->cacheIndex = (slot->next->logical != gcvNULL)
+ ? slot->next
+ : (slot->prev->logical != gcvNULL)
+ ? slot->prev
+ : gcvNULL;
+ }
+
+ /* Unlink slot from cache. */
+ slot->prev->next = slot->next;
+ slot->next->prev = slot->prev;
+
+ /* Insert slot to head of cache. */
+ slot->prev = &Cache->cache[0];
+ slot->next = Cache->cache[0].next;
+ slot->prev->next = slot;
+ slot->next->prev = slot;
+
+ /* Mark slot as empty. */
+ slot->logical = gcvNULL;
+ slot->stamp = 0;
+ }
+ }
+
+#elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
+ gctINT j;
+ gcskLOGICAL_CACHE_PTR hash, next;
+
+ /* Walk all hash tables. */
+ for (i = 0, hash = Cache->hash;
+ i < gcmCOUNTOF(Cache->hash);
+ ++i, ++hash)
+ {
+ /* Walk all slots in the hash. */
+ for (j = 0, slot = hash->nextHash;
+ (j < gcdSECURE_CACHE_SLOTS) && (slot != gcvNULL);
+ ++j, slot = next)
+ {
+ /* Save pointer to next slot. */
+ next = slot->next;
+
+ /* Test if this slot falls within the range to flush. */
+ ptr = (gctUINT8_PTR) slot->logical;
+ if ((ptr >= low) && (ptr < high))
+ {
+ /* Unlink slot from hash table. */
+ if (slot->prevHash == hash)
+ {
+ hash->nextHash = slot->nextHash;
+ }
+ else
+ {
+ slot->prevHash->nextHash = slot->nextHash;
+ }
+
+ if (slot->nextHash != gcvNULL)
+ {
+ slot->nextHash->prevHash = slot->prevHash;
+ }
+
+ /* Unlink slot from cache. */
+ slot->prev->next = slot->next;
+ slot->next->prev = slot->prev;
+
+ /* Append slot to tail of cache. */
+ slot->prev = Cache->cache[0].prev;
+ slot->next = &Cache->cache[0];
+ slot->prev->next = slot;
+ slot->next->prev = slot;
+
+ /* Mark slot as empty. */
+ slot->logical = gcvNULL;
+ slot->prevHash = gcvNULL;
+ slot->nextHash = gcvNULL;
+ }
+ }
+ }
+
+#elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_TABLE
+ gctUINT32 index;
+
+ /* Loop while inside the range. */
+ for (i = 1; (low < high) && (i <= gcdSECURE_CACHE_SLOTS); ++i)
+ {
+ /* Get index into cache for this range. */
+ index = (gcmPTR2INT32(low) % gcdSECURE_CACHE_SLOTS) + 1;
+ slot = &Cache->cache[index];
+
+ /* Test if this slot falls within the range to flush. */
+ ptr = (gctUINT8_PTR) slot->logical;
+ if ((ptr >= low) && (ptr < high))
+ {
+ /* Remove entry from cache. */
+ slot->logical = gcvNULL;
+ }
+
+ /* Next block. */
+ low += gcdSECURE_CACHE_SLOTS;
+ }
+#endif
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+#endif
+
+/*******************************************************************************
+**
+** gckKERNEL_Recovery
+**
+** Try to recover the GPU from a fatal error.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckKERNEL_Recovery(
+ IN gckKERNEL Kernel
+ )
+{
+ gceSTATUS status;
+ gckEVENT eventObj;
+ gckHARDWARE hardware;
+#if gcdSECURE_USER
+ gctUINT32 processID;
+ gcskSECURE_CACHE_PTR cache;
+#endif
+ gctUINT32 mask = 0;
+ gctUINT32 i = 0, count = 0;
+#if gcdINTERRUPT_STATISTIC
+ gctINT32 oldValue;
+#endif
+
+ gcmkHEADER_ARG("Kernel=0x%x", Kernel);
+
+ /* Validate the arguemnts. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+ /* Grab gckEVENT object. */
+ eventObj = Kernel->eventObj;
+ gcmkVERIFY_OBJECT(eventObj, gcvOBJ_EVENT);
+
+ /* Grab gckHARDWARE object. */
+ hardware = Kernel->hardware;
+ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+#if gcdSECURE_USER
+ /* Flush the secure mapping cache. */
+ gcmkONERROR(gckOS_GetProcessID(&processID));
+ gcmkONERROR(gckKERNEL_GetProcessDBCache(Kernel, processID, &cache));
+ gcmkONERROR(gckKERNEL_FlushTranslationCache(Kernel, cache, gcvNULL, 0));
+#endif
+
+ if (Kernel->stuckDump == gcvSTUCK_DUMP_NONE)
+ {
+ gcmkPRINT("[galcore]: GPU[%d] hang, automatic recovery.", Kernel->core);
+ }
+ else
+ {
+ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, Kernel->device->stuckDumpMutex, gcvINFINITE));
+
+ _DumpDriverConfigure(Kernel);
+ _DumpState(Kernel);
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->device->stuckDumpMutex));
+ }
+
+ if (Kernel->recovery == gcvFALSE)
+ {
+ gcmkPRINT("[galcore]: Stop driver to keep scene.");
+
+ /* Stop monitor timer. */
+ Kernel->monitorTimerStop = gcvTRUE;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+ /* Issuing a soft reset for the GPU. */
+ gcmkONERROR(gckHARDWARE_Reset(hardware));
+
+ mask = Kernel->restoreMask;
+
+ for (i = 0; i < 32; i++)
+ {
+ if (mask & (1 << i))
+ {
+ count++;
+ }
+ }
+
+ /* Handle all outstanding events now. */
+ gcmkONERROR(gckOS_AtomSet(Kernel->os, eventObj->pending, mask));
+
+#if gcdINTERRUPT_STATISTIC
+ while (count--)
+ {
+ gcmkONERROR(gckOS_AtomDecrement(
+ Kernel->os,
+ eventObj->interruptCount,
+ &oldValue
+ ));
+ }
+
+ gckOS_AtomClearMask(Kernel->hardware->pendingEvent, mask);
+#endif
+
+ gcmkONERROR(gckEVENT_Notify(eventObj, 1));
+
+ gcmkVERIFY_OK(gckOS_GetTime(&Kernel->resetTimeStamp));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_OpenUserData
+**
+** Get access to the user data.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctBOOL NeedCopy
+** The flag indicating whether or not the data should be copied.
+**
+** gctPOINTER StaticStorage
+** Pointer to the kernel storage where the data is to be copied if
+** NeedCopy is gcvTRUE.
+**
+** gctPOINTER UserPointer
+** User pointer to the data.
+**
+** gctSIZE_T Size
+** Size of the data.
+**
+** OUTPUT:
+**
+** gctPOINTER * KernelPointer
+** Pointer to the kernel pointer that will be pointing to the data.
+*/
+gceSTATUS
+gckKERNEL_OpenUserData(
+ IN gckKERNEL Kernel,
+ IN gctBOOL NeedCopy,
+ IN gctPOINTER StaticStorage,
+ IN gctPOINTER UserPointer,
+ IN gctSIZE_T Size,
+ OUT gctPOINTER * KernelPointer
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG(
+ "Kernel=0x%08X NeedCopy=%d StaticStorage=0x%08X "
+ "UserPointer=0x%08X Size=%lu KernelPointer=0x%08X",
+ Kernel, NeedCopy, StaticStorage, UserPointer, Size, KernelPointer
+ );
+
+ /* Validate the arguemnts. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(!NeedCopy || (StaticStorage != gcvNULL));
+ gcmkVERIFY_ARGUMENT(UserPointer != gcvNULL);
+ gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Size > 0);
+
+ if (NeedCopy)
+ {
+ /* Copy the user data to the static storage. */
+ gcmkONERROR(gckOS_CopyFromUserData(
+ Kernel->os, StaticStorage, UserPointer, Size
+ ));
+
+ /* Set the kernel pointer. */
+ * KernelPointer = StaticStorage;
+ }
+ else
+ {
+ gctPOINTER pointer = gcvNULL;
+
+ /* Map the user pointer. */
+ gcmkONERROR(gckOS_MapUserPointer(
+ Kernel->os, UserPointer, Size, &pointer
+ ));
+
+ /* Set the kernel pointer. */
+ * KernelPointer = pointer;
+ }
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_CloseUserData
+**
+** Release resources associated with the user data connection opened by
+** gckKERNEL_OpenUserData.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctBOOL NeedCopy
+** The flag indicating whether or not the data should be copied.
+**
+** gctBOOL FlushData
+** If gcvTRUE, the data is written back to the user.
+**
+** gctPOINTER UserPointer
+** User pointer to the data.
+**
+** gctSIZE_T Size
+** Size of the data.
+**
+** OUTPUT:
+**
+** gctPOINTER * KernelPointer
+** Kernel pointer to the data.
+*/
+gceSTATUS
+gckKERNEL_CloseUserData(
+ IN gckKERNEL Kernel,
+ IN gctBOOL NeedCopy,
+ IN gctBOOL FlushData,
+ IN gctPOINTER UserPointer,
+ IN gctSIZE_T Size,
+ OUT gctPOINTER * KernelPointer
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+ gctPOINTER pointer;
+
+ gcmkHEADER_ARG(
+ "Kernel=0x%08X NeedCopy=%d FlushData=%d "
+ "UserPointer=0x%08X Size=%lu KernelPointer=0x%08X",
+ Kernel, NeedCopy, FlushData, UserPointer, Size, KernelPointer
+ );
+
+ /* Validate the arguemnts. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(UserPointer != gcvNULL);
+ gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Size > 0);
+
+ /* Get a shortcut to the kernel pointer. */
+ pointer = * KernelPointer;
+
+ if (pointer != gcvNULL)
+ {
+ if (NeedCopy)
+ {
+ if (FlushData)
+ {
+ gcmkONERROR(gckOS_CopyToUserData(
+ Kernel->os, * KernelPointer, UserPointer, Size
+ ));
+ }
+ }
+ else
+ {
+ /* Unmap record from kernel memory. */
+ gcmkONERROR(gckOS_UnmapUserPointer(
+ Kernel->os,
+ UserPointer,
+ Size,
+ * KernelPointer
+ ));
+ }
+
+ /* Reset the kernel pointer. */
+ * KernelPointer = gcvNULL;
+ }
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_AllocateVirtualCommandBuffer(
+ IN gckKERNEL Kernel,
+ IN gctBOOL InUserSpace,
+ IN OUT gctSIZE_T * Bytes,
+ OUT gctPHYS_ADDR * Physical,
+ OUT gctPOINTER * Logical
+ )
+{
+ gceSTATUS status;
+ gckOS os = Kernel->os;
+ gckVIRTUAL_COMMAND_BUFFER_PTR buffer;
+
+ gcmkHEADER_ARG("Os=0x%X InUserSpace=%d *Bytes=%lu",
+ os, InUserSpace, gcmOPT_VALUE(Bytes));
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Bytes != gcvNULL);
+ gcmkVERIFY_ARGUMENT(*Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+ gcmkONERROR(
+ gckOS_Allocate(
+ os,
+ sizeof(gckVIRTUAL_COMMAND_BUFFER),
+ (gctPOINTER)&buffer
+ ));
+
+ gcmkONERROR(gckOS_ZeroMemory(buffer, sizeof(gckVIRTUAL_COMMAND_BUFFER)));
+
+ gcmkONERROR(
+ gckKERNEL_AllocateVirtualMemory(
+ Kernel,
+ gcvFALSE,
+ InUserSpace,
+ Bytes,
+ (gctPHYS_ADDR *)&buffer,
+ Logical
+ ));
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(os, Kernel->virtualBufferLock, gcvINFINITE));
+
+ if (Kernel->virtualBufferHead == gcvNULL)
+ {
+ Kernel->virtualBufferHead =
+ Kernel->virtualBufferTail = buffer;
+ }
+ else
+ {
+ buffer->prev = Kernel->virtualBufferTail;
+ Kernel->virtualBufferTail->next = buffer;
+ Kernel->virtualBufferTail = buffer;
+ }
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Kernel->virtualBufferLock));
+
+ *Physical = buffer;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkVERIFY_OK(gckOS_Free(os, buffer));
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_DestroyVirtualCommandBuffer(
+ IN gckKERNEL Kernel,
+ IN gctSIZE_T Bytes,
+ IN gctPHYS_ADDR Physical,
+ IN gctPOINTER Logical
+ )
+{
+ gckOS os;
+ gckKERNEL kernel;
+ gckVIRTUAL_COMMAND_BUFFER_PTR buffer = (gckVIRTUAL_COMMAND_BUFFER_PTR)Physical;
+
+ gcmkHEADER();
+ gcmkVERIFY_ARGUMENT(buffer != gcvNULL);
+
+ kernel = buffer->virtualBuffer.kernel;
+ os = kernel->os;
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(os, kernel->virtualBufferLock, gcvINFINITE));
+
+ if (buffer == kernel->virtualBufferHead)
+ {
+ if ((kernel->virtualBufferHead = buffer->next) == gcvNULL)
+ {
+ kernel->virtualBufferTail = gcvNULL;
+ }
+ }
+ else
+ {
+ buffer->prev->next = buffer->next;
+
+ if (buffer == kernel->virtualBufferTail)
+ {
+ kernel->virtualBufferTail = buffer->prev;
+ }
+ else
+ {
+ buffer->next->prev = buffer->prev;
+ }
+ }
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, kernel->virtualBufferLock));
+
+ gcmkVERIFY_OK(
+ gckKERNEL_FreeVirtualMemory(
+ Physical,
+ Logical,
+ gcvFALSE
+ ));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckKERNEL_AllocateVirtualMemory(
+ IN gckKERNEL Kernel,
+ IN gctBOOL NonPaged,
+ IN gctBOOL InUserSpace,
+ IN OUT gctSIZE_T * Bytes,
+ OUT gctPHYS_ADDR * Physical,
+ OUT gctPOINTER * Logical
+ )
+{
+ gckOS os = Kernel->os;
+ gceSTATUS status;
+ gctPOINTER logical = gcvNULL;
+ gctSIZE_T pageCount;
+ gctSIZE_T bytes = *Bytes;
+ gckVIRTUAL_BUFFER_PTR buffer = gcvNULL;
+ gckMMU mmu = gcvNULL;
+ gctUINT32 flag = gcvALLOC_FLAG_NON_CONTIGUOUS;
+
+ gcmkHEADER_ARG("Os=0x%X InUserSpace=%d *Bytes=%lu",
+ os, InUserSpace, gcmOPT_VALUE(Bytes));
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Bytes != gcvNULL);
+ gcmkVERIFY_ARGUMENT(*Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+ if (*Physical == gcvNULL)
+ {
+ gcmkONERROR(gckOS_Allocate(os,
+ sizeof(gckVIRTUAL_BUFFER),
+ (gctPOINTER)&buffer));
+
+ gcmkONERROR(gckOS_ZeroMemory(buffer, sizeof(gckVIRTUAL_BUFFER)));
+ }
+ else
+ {
+ buffer = *Physical;
+ }
+
+ buffer->bytes = bytes;
+
+ if (NonPaged)
+ {
+ gcmkONERROR(gckOS_AllocateNonPagedMemory(
+ os,
+ InUserSpace,
+ &bytes,
+ &buffer->physical,
+ &logical
+ ));
+ }
+ else
+ {
+ gcmkONERROR(gckOS_AllocatePagedMemoryEx(os,
+ flag,
+ bytes,
+ gcvNULL,
+ &buffer->physical));
+ }
+
+ if (NonPaged)
+ {
+ gctSIZE_T pageSize;
+ gcmkONERROR(gckOS_GetPageSize(os, &pageSize));
+
+ pageCount = (bytes + pageSize - 1) / pageSize;
+
+ if (InUserSpace)
+ {
+ *Logical =
+ buffer->userLogical = logical;
+ }
+ else
+ {
+ *Logical =
+ buffer->kernelLogical = logical;
+ }
+ }
+ else
+ {
+ if (InUserSpace)
+ {
+ gcmkONERROR(gckOS_CreateUserVirtualMapping(os,
+ buffer->physical,
+ bytes,
+ &logical,
+ &pageCount));
+
+ *Logical =
+ buffer->userLogical = logical;
+ }
+ else
+ {
+ gcmkONERROR(gckOS_CreateKernelVirtualMapping(os,
+ buffer->physical,
+ bytes,
+ &logical,
+ &pageCount));
+
+ *Logical =
+ buffer->kernelLogical = logical;
+ }
+
+ }
+
+ buffer->pageCount = pageCount;
+ buffer->kernel = Kernel;
+
+ gcmkONERROR(gckOS_GetProcessID(&buffer->pid));
+
+#if gcdPROCESS_ADDRESS_SPACE
+ gcmkONERROR(gckKERNEL_GetProcessMMU(Kernel, &mmu));
+ buffer->mmu = mmu;
+#else
+ mmu = Kernel->mmu;
+#endif
+
+ gcmkONERROR(gckMMU_AllocatePages(mmu,
+ pageCount,
+ &buffer->pageTable,
+ &buffer->gpuAddress));
+
+#if gcdENABLE_TRUST_APPLICATION
+ if (Kernel->hardware->options.secureMode == gcvSECURE_IN_TA)
+ {
+ gcmkONERROR(gckKERNEL_MapInTrustApplicaiton(
+ Kernel,
+ logical,
+ buffer->physical,
+ buffer->gpuAddress,
+ pageCount
+ ));
+ }
+ else
+#endif
+ {
+ gcmkONERROR(gckOS_MapPagesEx(os,
+ Kernel->core,
+ buffer->physical,
+ pageCount,
+ buffer->gpuAddress,
+ buffer->pageTable,
+ gcvFALSE,
+ gcvSURF_TYPE_UNKNOWN
+ ));
+ }
+
+ gcmkONERROR(gckMMU_Flush(mmu, gcvSURF_INDEX));
+
+ if (*Physical == gcvNULL)
+ *Physical = buffer;
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL,
+ "gpuAddress = %x pageCount = %d kernelLogical = %x userLogical=%x",
+ buffer->gpuAddress, buffer->pageCount,
+ buffer->kernelLogical, buffer->userLogical);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (buffer && buffer->gpuAddress)
+ {
+ gcmkVERIFY_OK(
+ gckMMU_FreePages(mmu, gcvFALSE, buffer->gpuAddress, buffer->pageTable, buffer->pageCount));
+ }
+
+ if (NonPaged && buffer->physical)
+ {
+ gcmkVERIFY_OK(gckOS_FreeNonPagedMemory(
+ os,
+ bytes,
+ buffer->physical,
+ logical
+ ));
+ }
+ else
+ {
+ if (buffer && buffer->userLogical)
+ {
+ gcmkVERIFY_OK(
+ gckOS_DestroyUserVirtualMapping(os,
+ buffer->physical,
+ bytes,
+ (NonPaged ? 0 : buffer->userLogical)));
+ }
+
+ if (buffer && buffer->kernelLogical)
+ {
+ gcmkVERIFY_OK(
+ gckOS_DestroyKernelVirtualMapping(os,
+ buffer->physical,
+ bytes,
+ (NonPaged ? 0 : buffer->kernelLogical)));
+ }
+
+ if (buffer && buffer->physical)
+ {
+ gcmkVERIFY_OK(gckOS_FreePagedMemory(os, buffer->physical, bytes));
+ }
+ }
+
+ if (*Physical == gcvNULL)
+ gcmkVERIFY_OK(gckOS_Free(os, buffer));
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+
+}
+
+gceSTATUS
+gckKERNEL_FreeVirtualMemory(
+ IN gctPHYS_ADDR Physical,
+ IN gctPOINTER Logical,
+ IN gctBOOL NonPaged
+ )
+{
+ gckOS os;
+ gckKERNEL kernel;
+ gckMMU mmu;
+ gckVIRTUAL_BUFFER_PTR buffer = (gckVIRTUAL_BUFFER_PTR)Physical;
+
+ gcmkHEADER();
+ gcmkVERIFY_ARGUMENT(buffer != gcvNULL);
+
+ kernel = buffer->kernel;
+ os = kernel->os;
+
+#if gcdPROCESS_ADDRESS_SPACE
+ gcmkONERROR(gckKERNEL_GetProcessMMU(Kernel, &mmu));
+#else
+ mmu = kernel->mmu;
+#endif
+
+ if (!buffer->userLogical && !NonPaged)
+ {
+ gcmkVERIFY_OK(gckOS_DestroyKernelVirtualMapping(os,
+ buffer->physical,
+ buffer->bytes,
+ Logical));
+ }
+
+ gcmkVERIFY_OK(
+ gckMMU_FreePages(mmu, gcvFALSE, buffer->gpuAddress, buffer->pageTable, buffer->pageCount));
+
+ gcmkVERIFY_OK(gckOS_UnmapPages(os, buffer->pageCount, buffer->gpuAddress));
+
+ if (NonPaged)
+ {
+ gcmkVERIFY_OK(gckOS_FreeNonPagedMemory(
+ os,
+ buffer->bytes,
+ buffer->physical,
+ Logical
+ ));
+ }
+ else
+ {
+ gcmkVERIFY_OK(gckOS_FreePagedMemory(os, buffer->physical, buffer->bytes));
+ }
+
+ gcmkVERIFY_OK(gckOS_Free(os, buffer));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckKERNEL_GetGPUAddress(
+ IN gckKERNEL Kernel,
+ IN gctPOINTER Logical,
+ IN gctBOOL InUserSpace,
+ IN gctPHYS_ADDR Physical,
+ OUT gctUINT32 * Address
+ )
+{
+ gckVIRTUAL_BUFFER_PTR buffer = Physical;
+ gctPOINTER start;
+
+ gcmkHEADER_ARG("Logical = %x InUserSpace=%d.", Logical, InUserSpace);
+
+ if (InUserSpace)
+ {
+ start = buffer->userLogical;
+ }
+ else
+ {
+ start = buffer->kernelLogical;
+ }
+
+ gcmkASSERT(Logical >= start
+ && (Logical < (gctPOINTER)((gctUINT8_PTR)start + buffer->bytes)));
+
+ * Address = buffer->gpuAddress + (gctUINT32)((gctUINT8_PTR)Logical - (gctUINT8_PTR)start);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckKERNEL_QueryGPUAddress(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 GpuAddress,
+ OUT gckVIRTUAL_COMMAND_BUFFER_PTR * Buffer
+ )
+{
+ gckVIRTUAL_COMMAND_BUFFER_PTR buffer;
+ gctUINT32 start;
+ gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, Kernel->virtualBufferLock, gcvINFINITE));
+
+ /* Walk all command buffers. */
+ for (buffer = Kernel->virtualBufferHead; buffer != gcvNULL; buffer = buffer->next)
+ {
+ start = (gctUINT32)buffer->virtualBuffer.gpuAddress;
+
+ if (GpuAddress >= start && GpuAddress <= (start - 1 + buffer->virtualBuffer.pageCount * 4096))
+ {
+ /* Find a range matched. */
+ *Buffer = buffer;
+ status = gcvSTATUS_OK;
+ break;
+ }
+ }
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->virtualBufferLock));
+
+ return status;
+}
+
+static void
+gckQUEUE_Dequeue(
+ IN gckQUEUE LinkQueue
+ )
+{
+ gcmkASSERT(LinkQueue->count == LinkQueue->size);
+
+ LinkQueue->count--;
+ LinkQueue->front = (LinkQueue->front + 1) % gcdLINK_QUEUE_SIZE;
+}
+
+void
+gckQUEUE_Enqueue(
+ IN gckQUEUE LinkQueue,
+ IN gcuQUEUEDATA *Data
+ )
+{
+ gcuQUEUEDATA * datas = LinkQueue->datas;
+
+ if (LinkQueue->count == LinkQueue->size)
+ {
+ gckQUEUE_Dequeue(LinkQueue);
+ }
+
+ gcmkASSERT(LinkQueue->count < LinkQueue->size);
+
+ LinkQueue->count++;
+
+ datas[LinkQueue->rear] = *Data;
+
+ LinkQueue->rear = (LinkQueue->rear + 1) % LinkQueue->size;
+}
+
+void
+gckQUEUE_GetData(
+ IN gckQUEUE LinkQueue,
+ IN gctUINT32 Index,
+ OUT gcuQUEUEDATA ** Data
+ )
+{
+ gcuQUEUEDATA * datas = LinkQueue->datas;
+
+ gcmkASSERT(Index >= 0 && Index < LinkQueue->size);
+
+ *Data = &datas[(Index + LinkQueue->front) % LinkQueue->size];
+}
+
+gceSTATUS
+gckQUEUE_Allocate(
+ IN gckOS Os,
+ IN gckQUEUE Queue,
+ IN gctUINT32 Size
+ )
+{
+ gceSTATUS status;
+
+ gcmkONERROR(gckOS_Allocate(
+ Os,
+ gcmSIZEOF(struct _gckLINKDATA) * Size,
+ (gctPOINTER *)&Queue->datas
+ ));
+
+ Queue->size = Size;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+gceSTATUS
+gckQUEUE_Free(
+ IN gckOS Os,
+ IN gckQUEUE Queue
+ )
+{
+ if (Queue->datas)
+ {
+ gcmkVERIFY_OK(gckOS_Free(Os, (gctPOINTER)Queue->datas));
+ }
+
+ return gcvSTATUS_OK;
+}
+
+/******************************************************************************\
+*************************** Pointer - ID translation ***************************
+\******************************************************************************/
+#define gcdID_TABLE_LENGTH 1024
+typedef struct _gcsINTEGERDB * gckINTEGERDB;
+typedef struct _gcsINTEGERDB
+{
+ gckOS os;
+ gctPOINTER* table;
+ gctPOINTER mutex;
+ gctUINT32 tableLen;
+ gctUINT32 currentID;
+ gctUINT32 unused;
+}
+gcsINTEGERDB;
+
+gceSTATUS
+gckKERNEL_CreateIntegerDatabase(
+ IN gckKERNEL Kernel,
+ OUT gctPOINTER * Database
+ )
+{
+ gceSTATUS status;
+ gckINTEGERDB database = gcvNULL;
+
+ gcmkHEADER_ARG("Kernel=0x%08X Datbase=0x%08X", Kernel, Database);
+
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Database != gcvNULL);
+
+ /* Allocate a database. */
+ gcmkONERROR(gckOS_Allocate(
+ Kernel->os, gcmSIZEOF(gcsINTEGERDB), (gctPOINTER *)&database));
+
+ gcmkONERROR(gckOS_ZeroMemory(database, gcmSIZEOF(gcsINTEGERDB)));
+
+ /* Allocate a pointer table. */
+ gcmkONERROR(gckOS_Allocate(
+ Kernel->os, gcmSIZEOF(gctPOINTER) * gcdID_TABLE_LENGTH, (gctPOINTER *)&database->table));
+
+ gcmkONERROR(gckOS_ZeroMemory(database->table, gcmSIZEOF(gctPOINTER) * gcdID_TABLE_LENGTH));
+
+ /* Allocate a database mutex. */
+ gcmkONERROR(gckOS_CreateMutex(Kernel->os, &database->mutex));
+
+ /* Initialize. */
+ database->currentID = 0;
+ database->unused = gcdID_TABLE_LENGTH;
+ database->os = Kernel->os;
+ database->tableLen = gcdID_TABLE_LENGTH;
+
+ *Database = database;
+
+ gcmkFOOTER_ARG("*Database=0x%08X", *Database);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Rollback. */
+ if (database)
+ {
+ if (database->table)
+ {
+ gcmkOS_SAFE_FREE(Kernel->os, database->table);
+ }
+
+ gcmkOS_SAFE_FREE(Kernel->os, database);
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_DestroyIntegerDatabase(
+ IN gckKERNEL Kernel,
+ IN gctPOINTER Database
+ )
+{
+ gckINTEGERDB database = Database;
+
+ gcmkHEADER_ARG("Kernel=0x%08X Datbase=0x%08X", Kernel, Database);
+
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Database != gcvNULL);
+
+ /* Destroy pointer table. */
+ gcmkOS_SAFE_FREE(Kernel->os, database->table);
+
+ /* Destroy database mutex. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, database->mutex));
+
+ /* Destroy database. */
+ gcmkOS_SAFE_FREE(Kernel->os, database);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckKERNEL_AllocateIntegerId(
+ IN gctPOINTER Database,
+ IN gctPOINTER Pointer,
+ OUT gctUINT32 * Id
+ )
+{
+ gceSTATUS status;
+ gckINTEGERDB database = Database;
+ gctUINT32 i, unused, currentID, tableLen;
+ gctPOINTER * table;
+ gckOS os = database->os;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Database=0x%08X Pointer=0x%08X", Database, Pointer);
+
+ gcmkVERIFY_ARGUMENT(Id != gcvNULL);
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(os, database->mutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ if (database->unused < 1)
+ {
+ /* Extend table. */
+ gcmkONERROR(
+ gckOS_Allocate(os,
+ gcmSIZEOF(gctPOINTER) * (database->tableLen + gcdID_TABLE_LENGTH),
+ (gctPOINTER *)&table));
+
+ gcmkONERROR(gckOS_ZeroMemory(table + database->tableLen,
+ gcmSIZEOF(gctPOINTER) * gcdID_TABLE_LENGTH));
+
+ /* Copy data from old table. */
+ gckOS_MemCopy(table,
+ database->table,
+ database->tableLen * gcmSIZEOF(gctPOINTER));
+
+ gcmkOS_SAFE_FREE(os, database->table);
+
+ /* Update databse with new allocated table. */
+ database->table = table;
+ database->currentID = database->tableLen;
+ database->tableLen += gcdID_TABLE_LENGTH;
+ database->unused += gcdID_TABLE_LENGTH;
+ }
+
+ table = database->table;
+ currentID = database->currentID;
+ tableLen = database->tableLen;
+ unused = database->unused;
+
+ /* Connect id with pointer. */
+ table[currentID] = Pointer;
+
+ *Id = currentID + 1;
+
+ /* Update the currentID. */
+ if (--unused > 0)
+ {
+ for (i = 0; i < tableLen; i++)
+ {
+ if (++currentID >= tableLen)
+ {
+ /* Wrap to the begin. */
+ currentID = 0;
+ }
+
+ if (table[currentID] == gcvNULL)
+ {
+ break;
+ }
+ }
+ }
+
+ database->table = table;
+ database->currentID = currentID;
+ database->tableLen = tableLen;
+ database->unused = unused;
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
+ acquired = gcvFALSE;
+
+ gcmkFOOTER_ARG("*Id=%d", *Id);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_FreeIntegerId(
+ IN gctPOINTER Database,
+ IN gctUINT32 Id
+ )
+{
+ gceSTATUS status;
+ gckINTEGERDB database = Database;
+ gckOS os = database->os;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Database=0x%08X Id=%d", Database, Id);
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(os, database->mutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ if (!(Id > 0 && Id <= database->tableLen))
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+
+ Id -= 1;
+
+ database->table[Id] = gcvNULL;
+
+ if (database->unused++ == 0)
+ {
+ database->currentID = Id;
+ }
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
+ acquired = gcvFALSE;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_QueryIntegerId(
+ IN gctPOINTER Database,
+ IN gctUINT32 Id,
+ OUT gctPOINTER * Pointer
+ )
+{
+ gceSTATUS status;
+ gckINTEGERDB database = Database;
+ gctPOINTER pointer;
+ gckOS os = database->os;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Database=0x%08X Id=%d", Database, Id);
+ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(os, database->mutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ if (!(Id > 0 && Id <= database->tableLen))
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+
+ Id -= 1;
+
+ pointer = database->table[Id];
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
+ acquired = gcvFALSE;
+
+ if (pointer)
+ {
+ *Pointer = pointer;
+ }
+ else
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+
+ gcmkFOOTER_ARG("*Pointer=0x%08X", *Pointer);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, database->mutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+
+gctUINT32
+gckKERNEL_AllocateNameFromPointer(
+ IN gckKERNEL Kernel,
+ IN gctPOINTER Pointer
+ )
+{
+ gceSTATUS status;
+ gctUINT32 name;
+ gctPOINTER database = Kernel->db->pointerDatabase;
+
+ gcmkHEADER_ARG("Kernel=0x%X Pointer=0x%X", Kernel, Pointer);
+
+ gcmkONERROR(
+ gckKERNEL_AllocateIntegerId(database, Pointer, &name));
+
+ gcmkFOOTER_ARG("name=%d", name);
+ return name;
+
+OnError:
+ gcmkFOOTER();
+ return 0;
+}
+
+gctPOINTER
+gckKERNEL_QueryPointerFromName(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Name
+ )
+{
+ gceSTATUS status;
+ gctPOINTER pointer = gcvNULL;
+ gctPOINTER database = Kernel->db->pointerDatabase;
+
+ gcmkHEADER_ARG("Kernel=0x%X Name=%d", Kernel, Name);
+
+ /* Lookup in database to get pointer. */
+ gcmkONERROR(gckKERNEL_QueryIntegerId(database, Name, &pointer));
+
+ gcmkFOOTER_ARG("pointer=0x%X", pointer);
+ return pointer;
+
+OnError:
+ gcmkFOOTER();
+ return gcvNULL;
+}
+
+gceSTATUS
+gckKERNEL_DeleteName(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Name
+ )
+{
+ gctPOINTER database = Kernel->db->pointerDatabase;
+
+ gcmkHEADER_ARG("Kernel=0x%X Name=0x%X", Kernel, Name);
+
+ /* Free name if exists. */
+ gcmkVERIFY_OK(gckKERNEL_FreeIntegerId(database, Name));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+***** Shared Buffer ************************************************************
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** gckKERNEL_CreateShBuffer
+**
+** Create shared buffer.
+** The shared buffer can be used across processes. Other process needs call
+** gckKERNEL_MapShBuffer before use it.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctUINT32 Size
+** Specify the shared buffer size.
+**
+** OUTPUT:
+**
+** gctSHBUF * ShBuf
+** Pointer to hold return shared buffer handle.
+*/
+gceSTATUS
+gckKERNEL_CreateShBuffer(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Size,
+ OUT gctSHBUF * ShBuf
+ )
+{
+ gceSTATUS status;
+ gcsSHBUF_PTR shBuf = gcvNULL;
+
+ gcmkHEADER_ARG("Kernel=0x%X, Size=%u", Kernel, Size);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+ if (Size == 0)
+ {
+ /* Invalid size. */
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+ else if (Size > 1024)
+ {
+ /* Limite shared buffer size. */
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ /* Create a shared buffer structure. */
+ gcmkONERROR(
+ gckOS_Allocate(Kernel->os,
+ sizeof (gcsSHBUF),
+ (gctPOINTER *)&shBuf));
+
+ /* Initialize shared buffer. */
+ shBuf->id = 0;
+ shBuf->reference = gcvNULL;
+ shBuf->size = Size;
+ shBuf->data = gcvNULL;
+
+ /* Allocate integer id for this shared buffer. */
+ gcmkONERROR(
+ gckKERNEL_AllocateIntegerId(Kernel->db->pointerDatabase,
+ shBuf,
+ &shBuf->id));
+
+ /* Allocate atom. */
+ gcmkONERROR(gckOS_AtomConstruct(Kernel->os, &shBuf->reference));
+
+ /* Set default reference count to 1. */
+ gcmkVERIFY_OK(gckOS_AtomSet(Kernel->os, shBuf->reference, 1));
+
+ /* Return integer id. */
+ *ShBuf = (gctSHBUF)(gctUINTPTR_T)shBuf->id;
+
+ gcmkFOOTER_ARG("*ShBuf=%u", shBuf->id);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Error roll back. */
+ if (shBuf != gcvNULL)
+ {
+ if (shBuf->id != 0)
+ {
+ gcmkVERIFY_OK(
+ gckKERNEL_FreeIntegerId(Kernel->db->pointerDatabase,
+ shBuf->id));
+ }
+
+ gcmkOS_SAFE_FREE(Kernel->os, shBuf);
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_DestroyShBuffer
+**
+** Destroy shared buffer.
+** This will decrease reference of specified shared buffer and do actual
+** destroy when no reference on it.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctSHBUF ShBuf
+** Specify the shared buffer to be destroyed.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckKERNEL_DestroyShBuffer(
+ IN gckKERNEL Kernel,
+ IN gctSHBUF ShBuf
+ )
+{
+ gceSTATUS status;
+ gcsSHBUF_PTR shBuf;
+ gctINT32 oldValue = 0;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Kernel=0x%X ShBuf=%u",
+ Kernel, (gctUINT32)(gctUINTPTR_T) ShBuf);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(ShBuf != gcvNULL);
+
+ /* Acquire mutex. */
+ gcmkONERROR(
+ gckOS_AcquireMutex(Kernel->os,
+ Kernel->db->pointerDatabaseMutex,
+ gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Find shared buffer structure. */
+ gcmkONERROR(
+ gckKERNEL_QueryIntegerId(Kernel->db->pointerDatabase,
+ (gctUINT32)(gctUINTPTR_T)ShBuf,
+ (gctPOINTER)&shBuf));
+
+ gcmkASSERT(shBuf->id == (gctUINT32)(gctUINTPTR_T)ShBuf);
+
+ /* Decrease the reference count. */
+ gckOS_AtomDecrement(Kernel->os, shBuf->reference, &oldValue);
+
+ if (oldValue == 1)
+ {
+ /* Free integer id. */
+ gcmkVERIFY_OK(
+ gckKERNEL_FreeIntegerId(Kernel->db->pointerDatabase,
+ shBuf->id));
+
+ /* Free atom. */
+ gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, shBuf->reference));
+
+ if (shBuf->data)
+ {
+ gcmkOS_SAFE_FREE(Kernel->os, shBuf->data);
+ shBuf->data = gcvNULL;
+ }
+
+ /* Free the shared buffer. */
+ gcmkOS_SAFE_FREE(Kernel->os, shBuf);
+ }
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(
+ gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
+ acquired = gcvFALSE;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ /* Release the mutex. */
+ gcmkVERIFY_OK(
+ gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_MapShBuffer
+**
+** Map shared buffer into this process so that it can be used in this process.
+** This will increase reference count on the specified shared buffer.
+** Call gckKERNEL_DestroyShBuffer to dereference.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctSHBUF ShBuf
+** Specify the shared buffer to be mapped.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckKERNEL_MapShBuffer(
+ IN gckKERNEL Kernel,
+ IN gctSHBUF ShBuf
+ )
+{
+ gceSTATUS status;
+ gcsSHBUF_PTR shBuf;
+ gctINT32 oldValue = 0;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Kernel=0x%X ShBuf=%u",
+ Kernel, (gctUINT32)(gctUINTPTR_T) ShBuf);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(ShBuf != gcvNULL);
+
+ /* Acquire mutex. */
+ gcmkONERROR(
+ gckOS_AcquireMutex(Kernel->os,
+ Kernel->db->pointerDatabaseMutex,
+ gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Find shared buffer structure. */
+ gcmkONERROR(
+ gckKERNEL_QueryIntegerId(Kernel->db->pointerDatabase,
+ (gctUINT32)(gctUINTPTR_T)ShBuf,
+ (gctPOINTER)&shBuf));
+
+ gcmkASSERT(shBuf->id == (gctUINT32)(gctUINTPTR_T)ShBuf);
+
+ /* Increase the reference count. */
+ gckOS_AtomIncrement(Kernel->os, shBuf->reference, &oldValue);
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(
+ gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
+ acquired = gcvFALSE;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ /* Release the mutex. */
+ gcmkVERIFY_OK(
+ gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_WriteShBuffer
+**
+** Write user data into shared buffer.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctSHBUF ShBuf
+** Specify the shared buffer to be written to.
+**
+** gctPOINTER UserData
+** User mode pointer to hold the source data.
+**
+** gctUINT32 ByteCount
+** Specify number of bytes to write. If this is larger than
+** shared buffer size, gcvSTATUS_INVALID_ARGUMENT is returned.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckKERNEL_WriteShBuffer(
+ IN gckKERNEL Kernel,
+ IN gctSHBUF ShBuf,
+ IN gctPOINTER UserData,
+ IN gctUINT32 ByteCount
+ )
+{
+ gceSTATUS status;
+ gcsSHBUF_PTR shBuf = gcvNULL;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Kernel=0x%X ShBuf=%u UserData=0x%X ByteCount=%u",
+ Kernel, (gctUINT32)(gctUINTPTR_T) ShBuf, UserData, ByteCount);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(ShBuf != gcvNULL);
+
+ /* Acquire mutex. */
+ gcmkONERROR(
+ gckOS_AcquireMutex(Kernel->os,
+ Kernel->db->pointerDatabaseMutex,
+ gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Find shared buffer structure. */
+ gcmkONERROR(
+ gckKERNEL_QueryIntegerId(Kernel->db->pointerDatabase,
+ (gctUINT32)(gctUINTPTR_T)ShBuf,
+ (gctPOINTER)&shBuf));
+
+ gcmkASSERT(shBuf->id == (gctUINT32)(gctUINTPTR_T)ShBuf);
+
+ if ((ByteCount > shBuf->size) ||
+ (ByteCount == 0) ||
+ (UserData == gcvNULL))
+ {
+ /* Exceeds buffer max size or invalid. */
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ if (shBuf->data == gcvNULL)
+ {
+ /* Allocate buffer data when first time write. */
+ gcmkONERROR(gckOS_Allocate(Kernel->os, ByteCount, &shBuf->data));
+ }
+
+ /* Copy data from user. */
+ gcmkONERROR(
+ gckOS_CopyFromUserData(Kernel->os,
+ shBuf->data,
+ UserData,
+ ByteCount));
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(
+ gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
+ acquired = gcvFALSE;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (shBuf && shBuf->data)
+ {
+ gcmkOS_SAFE_FREE(Kernel->os, shBuf->data);
+ shBuf->data = gcvNULL;
+ }
+
+ if (acquired)
+ {
+ /* Release the mutex. */
+ gcmkVERIFY_OK(
+ gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_ReadShBuffer
+**
+** Read data from shared buffer and copy to user pointer.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctSHBUF ShBuf
+** Specify the shared buffer to be read from.
+**
+** gctPOINTER UserData
+** User mode pointer to save output data.
+**
+** gctUINT32 ByteCount
+** Specify number of bytes to read.
+** If this is larger than shared buffer size, only avaiable bytes are
+** copied. If smaller, copy requested size.
+**
+** OUTPUT:
+**
+** gctUINT32 * BytesRead
+** Pointer to hold how many bytes actually read from shared buffer.
+*/
+gceSTATUS
+gckKERNEL_ReadShBuffer(
+ IN gckKERNEL Kernel,
+ IN gctSHBUF ShBuf,
+ IN gctPOINTER UserData,
+ IN gctUINT32 ByteCount,
+ OUT gctUINT32 * BytesRead
+ )
+{
+ gceSTATUS status;
+ gcsSHBUF_PTR shBuf;
+ gctUINT32 bytes;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Kernel=0x%X ShBuf=%u UserData=0x%X ByteCount=%u",
+ Kernel, (gctUINT32)(gctUINTPTR_T) ShBuf, UserData, ByteCount);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(ShBuf != gcvNULL);
+
+ /* Acquire mutex. */
+ gcmkONERROR(
+ gckOS_AcquireMutex(Kernel->os,
+ Kernel->db->pointerDatabaseMutex,
+ gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Find shared buffer structure. */
+ gcmkONERROR(
+ gckKERNEL_QueryIntegerId(Kernel->db->pointerDatabase,
+ (gctUINT32)(gctUINTPTR_T)ShBuf,
+ (gctPOINTER)&shBuf));
+
+ gcmkASSERT(shBuf->id == (gctUINT32)(gctUINTPTR_T)ShBuf);
+
+ if (shBuf->data == gcvNULL)
+ {
+ *BytesRead = 0;
+
+ /* No data in shared buffer, skip copy. */
+ status = gcvSTATUS_SKIP;
+ goto OnError;
+ }
+ else if (ByteCount == 0)
+ {
+ /* Invalid size to read. */
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ /* Determine bytes to copy. */
+ bytes = (ByteCount < shBuf->size) ? ByteCount : shBuf->size;
+
+ /* Copy data to user. */
+ gcmkONERROR(
+ gckOS_CopyToUserData(Kernel->os,
+ shBuf->data,
+ UserData,
+ bytes));
+
+ /* Return copied size. */
+ *BytesRead = bytes;
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(
+ gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
+ acquired = gcvFALSE;
+
+ gcmkFOOTER_ARG("*BytesRead=%u", bytes);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ /* Release the mutex. */
+ gcmkVERIFY_OK(
+ gckOS_ReleaseMutex(Kernel->os, Kernel->db->pointerDatabaseMutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************\
+*************************** List Helper *****************************************
+\*******************************************************************************/
+
+static void
+_ListAdd(
+ gcsLISTHEAD_PTR New,
+ gcsLISTHEAD_PTR Prev,
+ gcsLISTHEAD_PTR Next
+ )
+{
+ Next->prev = New;
+ New->next = Next;
+ New->prev = Prev;
+ Prev->next = New;
+}
+
+void
+_ListDel(
+ gcsLISTHEAD_PTR Prev,
+ gcsLISTHEAD_PTR Next
+ )
+{
+ Next->prev = Prev;
+ Prev->next = Next;
+}
+
+void
+gcsLIST_Init(
+ gcsLISTHEAD_PTR Node
+ )
+{
+ Node->prev = Node;
+ Node->next = Node;
+}
+
+void
+gcsLIST_Add(
+ gcsLISTHEAD_PTR New,
+ gcsLISTHEAD_PTR Head
+ )
+{
+ _ListAdd(New, Head, Head->next);
+}
+
+void
+gcsLIST_AddTail(
+ gcsLISTHEAD_PTR New,
+ gcsLISTHEAD_PTR Head
+ )
+{
+ _ListAdd(New, Head->prev, Head);
+}
+
+void
+gcsLIST_Del(
+ gcsLISTHEAD_PTR Node
+ )
+{
+ _ListDel(Node->prev, Node->next);
+}
+
+gctBOOL
+gcsLIST_Empty(
+ gcsLISTHEAD_PTR Head
+ )
+{
+ return Head->next == Head;
+}
+
+/*******************************************************************************\
+********************************* Fence *****************************************
+\*******************************************************************************/
+
+gceSTATUS
+gckFENCE_Create(
+ IN gckOS Os,
+ IN gckKERNEL Kernel,
+ OUT gckFENCE * Fence
+ )
+{
+ gceSTATUS status;
+ gckFENCE fence = gcvNULL;
+ gctSIZE_T pageSize = 4096;
+
+ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsFENCE), (gctPOINTER *)&fence));
+ gcmkONERROR(gckOS_ZeroMemory(fence, gcmSIZEOF(gcsFENCE)));
+ gcmkONERROR(gckOS_CreateMutex(Os, (gctPOINTER *)&fence->mutex));
+
+ fence->kernel = Kernel;
+
+#if USE_KERNEL_VIRTUAL_BUFFERS
+ if (Kernel->virtualCommandBuffer)
+ {
+ gcmkONERROR(gckKERNEL_AllocateVirtualMemory(
+ Kernel,
+ gcvFALSE,
+ gcvFALSE,
+ &pageSize,
+ &fence->physical,
+ &fence->logical
+ ));
+
+ gcmkONERROR(gckKERNEL_GetGPUAddress(
+ Kernel,
+ fence->logical,
+ gcvFALSE,
+ fence->physical,
+ &fence->address
+ ));
+ }
+ else
+#endif
+ {
+ gcmkONERROR(gckOS_AllocateNonPagedMemory(
+ Os,
+ gcvFALSE,
+ &pageSize,
+ &fence->physical,
+ &fence->logical
+ ));
+
+ gcmkONERROR(gckHARDWARE_ConvertLogical(
+ Kernel->hardware,
+ fence->logical,
+ gcvFALSE,
+ &fence->address
+ ));
+
+ gcmkONERROR(gckMMU_FillFlatMapping(
+ Kernel->mmu, fence->address, pageSize
+ ));
+ }
+
+ gcsLIST_Init(&fence->waitingList);
+
+ *Fence = fence;
+
+ return gcvSTATUS_OK;
+OnError:
+ if (fence)
+ {
+ gckFENCE_Destory(Os, fence);
+ }
+
+ return status;
+}
+
+gceSTATUS
+gckFENCE_Destory(
+ IN gckOS Os,
+ OUT gckFENCE Fence
+ )
+{
+ if (Fence->mutex)
+ {
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Fence->mutex));
+ }
+
+ if (Fence->logical)
+ {
+#if USE_KERNEL_VIRTUAL_BUFFERS
+ if (Fence->kernel->virtualCommandBuffer)
+ {
+ gcmkVERIFY_OK(gckKERNEL_FreeVirtualMemory(
+ Fence->physical,
+ Fence->logical,
+ gcvFALSE
+ ));
+ }
+ else
+#endif
+ {
+ gcmkVERIFY_OK(gckOS_FreeNonPagedMemory(
+ Os,
+ 4096,
+ Fence->physical,
+ Fence->logical
+ ));
+ }
+ }
+
+ gcmkOS_SAFE_FREE(Os, Fence);
+
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckFENCE_Signal
+**
+** Signal all completed nodes.
+**
+**
+*/
+gceSTATUS
+gckFENCE_Signal(
+ IN gckOS Os,
+ IN gckFENCE Fence
+ )
+{
+ gcsLISTHEAD_PTR list = &Fence->waitingList;
+ gcsLISTHEAD_PTR nodeHead, nodeTemp;
+ gckFENCE_SYNC sync;
+ gckOS os = Os;
+ gctUINT64 stamp = *(gctUINT64 *)Fence->logical;
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(os, Fence->mutex, gcvINFINITE));
+
+ gcmkLIST_FOR_EACH_SAFE(nodeHead, nodeTemp, list)
+ {
+ sync = gcmCONTAINEROF(nodeHead, _gcsFENCE_SYNC, head);
+
+ /* Signal all nodes which are complete. */
+ if (sync->commitStamp <= stamp && sync->inList)
+ {
+ /* Signal. */
+ gckOS_Signal(os, sync->signal, gcvTRUE);
+
+ /* Remove from wait list. */
+ gcsLIST_Del(nodeHead);
+
+ /* Mark node not in waiting list. */
+ sync->inList = gcvFALSE;
+ }
+ }
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Fence->mutex));
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckDEVICE_Construct(
+ IN gckOS Os,
+ OUT gckDEVICE * Device
+ )
+{
+ gceSTATUS status;
+ gckDEVICE device;
+ gctUINT i;
+
+ gcmkHEADER();
+
+ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsDEVICE), (gctPOINTER *)&device));
+
+ for (i = 0; i < gcvCORE_COUNT; i++)
+ {
+ device->coreInfoArray[i].type = gcvHARDWARE_INVALID;
+ }
+ device->defaultHwType = gcvHARDWARE_INVALID;
+
+ gckOS_ZeroMemory(device, gcmSIZEOF(gcsDEVICE));
+
+ gcmkONERROR(gckOS_CreateMutex(Os, &device->stuckDumpMutex));
+ gcmkONERROR(gckOS_CreateMutex(Os, &device->commitMutex));
+
+ device->os = Os;
+
+ *Device = device;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+
+ if (device != gcvNULL)
+ {
+ gckDEVICE_Destroy(Os, device);
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckDEVICE_AddCore(
+ IN gckDEVICE Device,
+ IN gceCORE Core,
+ IN gctUINT ChipID,
+ IN gctPOINTER Context,
+ IN gckKERNEL * Kernel
+ )
+{
+ gceSTATUS status;
+ gcsCORE_INFO * info = Device->coreInfoArray;
+ gceHARDWARE_TYPE type = (gceHARDWARE_TYPE)((gctUINT)gcvHARDWARE_INVALID);
+ gctUINT32 index = Device->coreNum;
+ gctUINT32 i;
+ gcsCORE_LIST *coreList;
+ gceHARDWARE_TYPE kernelType;
+ gceHARDWARE_TYPE defaultHwType;
+ gckKERNEL kernel;
+
+ gcmkASSERT(Device->coreNum < gcvCORE_COUNT);
+
+ if (Core >= gcvCORE_MAJOR && Core <= gcvCORE_3D_MAX)
+ {
+ /* Chip ID is only used for 3D cores. */
+ if (ChipID == gcvCHIP_ID_DEFAULT)
+ {
+ /* Apply default chipID if it is not set. */
+ ChipID = Core;
+ }
+ }
+
+ /* Construct gckKERNEL for this core. */
+ gcmkONERROR(gckKERNEL_Construct(
+ Device->os, Core, ChipID, Context, Device, Device->database, Kernel));
+
+ kernel = *Kernel;
+
+ if (Device->database == gcvNULL)
+ {
+ Device->database = kernel->db;
+ }
+
+ kernelType = _GetHardwareType(kernel);
+
+ if (kernelType >= gcvHARDWARE_NUM_TYPES)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ info[index].type = kernelType;
+ info[index].core = Core;
+ info[index].kernel = kernel;
+ info[index].chipID = ChipID;
+
+ if (index == 0)
+ {
+ /* First core, map all type/core to it. */
+ for (; type != gcvHARDWARE_NUM_TYPES; type = (gceHARDWARE_TYPE)((gctUINT)type + 1))
+ {
+ Device->map[type].num = 0;
+
+ for (i = 0 ; i < 4; i++)
+ {
+ Device->map[type].kernels[i] = kernel;
+ }
+ }
+ }
+
+ /* Get core list of this type. */
+ coreList = &Device->map[kernelType];
+
+ /* Setup gceHARDWARE_TYPE to gceCORE mapping. */
+ coreList->kernels[coreList->num++] = kernel;
+
+ defaultHwType = kernelType;
+ if (kernelType == gcvHARDWARE_3D2D)
+ {
+ coreList = &Device->map[gcvHARDWARE_3D];
+ coreList->kernels[coreList->num++] = kernel;
+ defaultHwType = gcvHARDWARE_3D;
+ }
+
+ /* Advance total core number. */
+ Device->coreNum++;
+
+ /* Default HW type was chosen: 3D > 2D > VG */
+ if (Device->defaultHwType == gcvHARDWARE_INVALID)
+ {
+ Device->defaultHwType = defaultHwType;
+ }
+ else if (Device->defaultHwType > defaultHwType)
+ {
+ Device->defaultHwType = defaultHwType;
+ }
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+gceSTATUS
+gckDEVICE_ChipInfo(
+ IN gckDEVICE Device,
+ IN gcsHAL_INTERFACE_PTR Interface
+ )
+{
+ gctUINT i;
+ gcsCORE_INFO * info = Device->coreInfoArray;
+
+ for (i = 0; i < Device->coreNum; i++)
+ {
+ Interface->u.ChipInfo.types[i] = info[i].type;
+ Interface->u.ChipInfo.ids[i] = info[i].chipID;
+ }
+
+ Interface->u.ChipInfo.count = Device->coreNum;
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckDEVICE_Version(
+ IN gckDEVICE Device,
+ IN gcsHAL_INTERFACE_PTR Interface
+ )
+{
+ Interface->u.Version.major = gcvVERSION_MAJOR;
+ Interface->u.Version.minor = gcvVERSION_MINOR;
+ Interface->u.Version.patch = gcvVERSION_PATCH;
+ Interface->u.Version.build = gcvVERSION_BUILD;
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL,
+ "KERNEL version %d.%d.%d build %u",
+ gcvVERSION_MAJOR, gcvVERSION_MINOR,
+ gcvVERSION_PATCH, gcvVERSION_BUILD);
+#endif
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckDEVICE_Destroy(
+ IN gckOS Os,
+ IN gckDEVICE Device
+ )
+{
+ gctINT i;
+ gcsCORE_INFO * info = Device->coreInfoArray;
+
+ for (i = Device->coreNum - 1; i >= 0 ; i--)
+ {
+ if (info[i].kernel != gcvNULL)
+ {
+ gckKERNEL_Destroy(info[i].kernel);
+ }
+ }
+
+ if (Device->commitMutex)
+ {
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Device->commitMutex));
+ }
+ if (Device->stuckDumpMutex)
+ {
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Device->stuckDumpMutex));
+ }
+
+ gcmkOS_SAFE_FREE(Os, Device);
+
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+gckDEVICE_SetTimeOut(
+ IN gckDEVICE Device,
+ IN gcsHAL_INTERFACE_PTR Interface
+ )
+{
+#if gcdGPU_TIMEOUT
+ gckKERNEL kernel;
+ gctUINT i;
+ gceHARDWARE_TYPE type = Interface->hardwareType;
+ gcsCORE_LIST *coreList;
+
+ coreList = &Device->map[type];
+
+ for (i = 0; i < coreList->num; i++)
+ {
+ kernel = coreList->kernels[i];
+
+ kernel->timeOut = Interface->u.SetTimeOut.timeOut;
+ }
+#endif
+
+ return gcvSTATUS_OK;
+}
+
+
+gceSTATUS
+gckDEVICE_Dispatch(
+ IN gckDEVICE Device,
+ IN gcsHAL_INTERFACE_PTR Interface
+ )
+{
+ gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+ gckKERNEL kernel;
+ gceHARDWARE_TYPE type = Interface->hardwareType;
+ gctUINT32 coreIndex = Interface->coreIndex;
+
+ switch (Interface->command)
+ {
+ case gcvHAL_CHIP_INFO:
+ status = gckDEVICE_ChipInfo(Device, Interface);
+ break;
+
+ case gcvHAL_VERSION:
+ status = gckDEVICE_Version(Device, Interface);
+ break;
+
+ case gcvHAL_SET_TIMEOUT:
+ status = gckDEVICE_SetTimeOut(Device, Interface);
+ break;
+
+ default:
+ status = gcvSTATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (gcmIS_SUCCESS(status))
+ {
+ /* Dispatch handled in this layer. */
+ Interface->status = status;
+ }
+ else
+ {
+ /* Need go through gckKERNEL dispatch. */
+ kernel = Device->map[type].kernels[coreIndex];
+
+
+#if gcdENABLE_VG
+ if (kernel->vg)
+ {
+ status = gckVGKERNEL_Dispatch(kernel, gcvTRUE, Interface);
+ }
+ else
+#endif
+ {
+ status = gckKERNEL_Dispatch(kernel, Device, gcvTRUE, Interface);
+ }
+
+ /* Interface->status is handled in gckKERNEL_Dispatch(). */
+ }
+
+ return status;
+}
+
+gceSTATUS
+gckDEVICE_GetMMU(
+ IN gckDEVICE Device,
+ IN gceHARDWARE_TYPE Type,
+ IN gckMMU *Mmu
+ )
+{
+ gcmkHEADER();
+ gcmkVERIFY_ARGUMENT(Type < gcvHARDWARE_NUM_TYPES);
+
+ *Mmu = Device->mmus[Type];
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckDEVICE_SetMMU(
+ IN gckDEVICE Device,
+ IN gceHARDWARE_TYPE Type,
+ IN gckMMU Mmu
+ )
+{
+ gcmkHEADER();
+ gcmkVERIFY_ARGUMENT(Type < gcvHARDWARE_NUM_TYPES);
+
+ Device->mmus[Type] = Mmu;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckDEVICE_QueryGPUAddress
+**
+** Search GPUAddress in other core's address space, whose type is same as current
+** core. It is used to find correct command buffer which is shared by mulitple
+** core.
+**
+*/
+gceSTATUS
+gckDEVICE_QueryGPUAddress(
+ IN gckDEVICE Device,
+ IN gckKERNEL Kernel,
+ IN gctUINT32 GPUAddress,
+ OUT gckVIRTUAL_COMMAND_BUFFER_PTR * Buffer
+ )
+{
+ gceSTATUS status = gcvSTATUS_NOT_FOUND;
+ gctUINT i;
+ gceHARDWARE_TYPE kernelType;
+
+ kernelType = _GetHardwareType(Kernel);
+
+ if (Device != gcvNULL)
+ {
+ for (i = 0; i < Device->coreNum; i++)
+ {
+ if (Device->coreInfoArray[i].type == kernelType)
+ {
+ /* Search other core's command buffer list whose type is same. */
+ status = gckKERNEL_QueryGPUAddress(
+ Device->coreInfoArray[i].kernel, GPUAddress, Buffer);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ status = gckKERNEL_QueryGPUAddress(Kernel, GPUAddress, Buffer);
+ }
+
+ return status;
+}
+
+#if gcdENABLE_TRUST_APPLICATION
+gceSTATUS
+gckKERNEL_MapInTrustApplicaiton(
+ IN gckKERNEL Kernel,
+ IN gctPOINTER Logical,
+ IN gctPHYS_ADDR Physical,
+ IN gctUINT32 GPUAddress,
+ IN gctSIZE_T PageCount
+ )
+{
+ gceSTATUS status;
+ gctUINT32 * physicalArrayLogical = gcvNULL;
+ gctSIZE_T bytes;
+ gctPOINTER logical = Logical;
+ gctUINT32 i;
+ gctSIZE_T pageSize;
+ gctUINT32 pageMask;
+
+ gcmkHEADER();
+
+ gcmkVERIFY_OK(gckOS_GetPageSize(Kernel->os, &pageSize));
+
+ pageMask = (gctUINT32)pageSize - 1;
+
+ bytes = PageCount * gcmSIZEOF(gctUINT32);
+
+ gcmkONERROR(gckOS_Allocate(
+ Kernel->os,
+ bytes,
+ (gctPOINTER *)&physicalArrayLogical
+ ));
+
+ /* Fill in physical array. */
+ for (i = 0; i < PageCount; i++)
+ {
+ gctPHYS_ADDR_T phys;
+ status = gckOS_PhysicalToPhysicalAddress(
+ Kernel->os,
+ Physical,
+ i * 4096,
+ &phys
+ );
+
+ if (status == gcvSTATUS_NOT_SUPPORTED)
+ {
+ gcmkONERROR(gckOS_GetPhysicalAddress(
+ Kernel->os,
+ logical,
+ &phys
+ ));
+ }
+
+ phys &= ~pageMask;
+
+ gcmkSAFECASTPHYSADDRT(physicalArrayLogical[i], phys);
+
+ logical = (gctUINT8_PTR)logical + 4096;
+ }
+
+ gcmkONERROR(gckKERNEL_SecurityMapMemory(
+ Kernel,
+ physicalArrayLogical,
+ 0,
+ (gctUINT32)PageCount,
+ &GPUAddress
+ ));
+
+ gcmkVERIFY_OK(gckOS_Free(
+ Kernel->os,
+ physicalArrayLogical
+ ))
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if(physicalArrayLogical != gcvNULL)
+ gcmkVERIFY_OK(gckOS_Free(
+ Kernel->os,
+ (gctPOINTER)physicalArrayLogical
+ ));
+ gcmkFOOTER();
+ return status;
+}
+#endif
+
+/*******************************************************************************
+***** Test Code ****************************************************************
+*******************************************************************************/
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.h b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.h
new file mode 100644
index 000000000000..9dac34d2fe8f
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel.h
@@ -0,0 +1,2071 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_h_
+#define __gc_hal_kernel_h_
+
+#include "gc_hal.h"
+#include "gc_hal_kernel_hardware.h"
+#include "gc_hal_driver.h"
+#include "gc_hal_kernel_mutex.h"
+#include "gc_hal_kernel_metadata.h"
+
+#if gcdENABLE_VG
+#include "gc_hal_kernel_vg.h"
+#endif
+
+#if gcdSECURITY || gcdENABLE_TRUST_APPLICATION
+#include "gc_hal_security_interface.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+***** New MMU Defination *******************************************************/
+#define gcdMMU_MTLB_SHIFT 22
+#define gcdMMU_STLB_4K_SHIFT 12
+#define gcdMMU_STLB_64K_SHIFT 16
+
+#define gcdMMU_MTLB_BITS (32 - gcdMMU_MTLB_SHIFT)
+#define gcdMMU_PAGE_4K_BITS gcdMMU_STLB_4K_SHIFT
+#define gcdMMU_STLB_4K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_4K_BITS)
+#define gcdMMU_PAGE_64K_BITS gcdMMU_STLB_64K_SHIFT
+#define gcdMMU_STLB_64K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_64K_BITS)
+
+#define gcdMMU_MTLB_ENTRY_NUM (1 << gcdMMU_MTLB_BITS)
+#define gcdMMU_MTLB_SIZE (gcdMMU_MTLB_ENTRY_NUM << 2)
+#define gcdMMU_STLB_4K_ENTRY_NUM (1 << gcdMMU_STLB_4K_BITS)
+#define gcdMMU_STLB_4K_SIZE (gcdMMU_STLB_4K_ENTRY_NUM << 2)
+#define gcdMMU_PAGE_4K_SIZE (1 << gcdMMU_STLB_4K_SHIFT)
+#define gcdMMU_STLB_64K_ENTRY_NUM (1 << gcdMMU_STLB_64K_BITS)
+#define gcdMMU_STLB_64K_SIZE (gcdMMU_STLB_64K_ENTRY_NUM << 2)
+#define gcdMMU_PAGE_64K_SIZE (1 << gcdMMU_STLB_64K_SHIFT)
+
+#define gcdMMU_MTLB_MASK (~((1U << gcdMMU_MTLB_SHIFT)-1))
+#define gcdMMU_STLB_4K_MASK ((~0U << gcdMMU_STLB_4K_SHIFT) ^ gcdMMU_MTLB_MASK)
+#define gcdMMU_PAGE_4K_MASK (gcdMMU_PAGE_4K_SIZE - 1)
+#define gcdMMU_STLB_64K_MASK ((~((1U << gcdMMU_STLB_64K_SHIFT)-1)) ^ gcdMMU_MTLB_MASK)
+#define gcdMMU_PAGE_64K_MASK (gcdMMU_PAGE_64K_SIZE - 1)
+
+/* Page offset definitions. */
+#define gcdMMU_OFFSET_4K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_STLB_4K_BITS)
+#define gcdMMU_OFFSET_4K_MASK ((1U << gcdMMU_OFFSET_4K_BITS) - 1)
+#define gcdMMU_OFFSET_16K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_STLB_16K_BITS)
+#define gcdMMU_OFFSET_16K_MASK ((1U << gcdMMU_OFFSET_16K_BITS) - 1)
+
+#define gcdMMU_MTLB_ENTRY_HINTS_BITS 6
+#define gcdMMU_MTLB_ENTRY_STLB_MASK (~((1U << gcdMMU_MTLB_ENTRY_HINTS_BITS) - 1))
+
+#define gcdMMU_MTLB_PRESENT 0x00000001
+#define gcdMMU_MTLB_EXCEPTION 0x00000002
+#define gcdMMU_MTLB_4K_PAGE 0x00000000
+
+#define gcdMMU_STLB_PRESENT 0x00000001
+#define gcdMMU_STLB_EXCEPTION 0x00000002
+#define gcdMMU_STLB_4K_PAGE 0x00000000
+
+/*******************************************************************************
+***** Stuck Dump Level ********************************************************/
+
+/* Dump nonthing when stuck happens. */
+#define gcvSTUCK_DUMP_NONE 0
+
+/* Dump GPU state and memory near stuck point. */
+#define gcvSTUCK_DUMP_NEARBY_MEMORY 1
+
+/* Beside gcvSTUCK_DUMP_NEARBY_MEMORY, dump context buffer and user command buffer. */
+#define gcvSTUCK_DUMP_USER_COMMAND 2
+
+/* Beside gcvSTUCK_DUMP_USER_COMMAND, commit will be stall
+** to make sure command causing stuck isn't missed. */
+#define gcvSTUCK_DUMP_STALL_COMMAND 3
+
+/* Beside gcvSTUCK_DUMP_USER_COMMAND, dump kernel command buffer. */
+#define gcvSTUCK_DUMP_ALL_COMMAND 4
+
+/*******************************************************************************
+***** Process Secure Cache ****************************************************/
+
+#define gcdSECURE_CACHE_LRU 1
+#define gcdSECURE_CACHE_LINEAR 2
+#define gcdSECURE_CACHE_HASH 3
+#define gcdSECURE_CACHE_TABLE 4
+
+#define gcvPAGE_TABLE_DIRTY_BIT_OTHER (1 << 0)
+#define gcvPAGE_TABLE_DIRTY_BIT_FE (1 << 1)
+
+typedef struct _gcskLOGICAL_CACHE * gcskLOGICAL_CACHE_PTR;
+typedef struct _gcskLOGICAL_CACHE gcskLOGICAL_CACHE;
+struct _gcskLOGICAL_CACHE
+{
+ /* Logical address. */
+ gctPOINTER logical;
+
+ /* DMAable address. */
+ gctUINT32 dma;
+
+#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
+ /* Pointer to the previous and next hash tables. */
+ gcskLOGICAL_CACHE_PTR nextHash;
+ gcskLOGICAL_CACHE_PTR prevHash;
+#endif
+
+#if gcdSECURE_CACHE_METHOD != gcdSECURE_CACHE_TABLE
+ /* Pointer to the previous and next slot. */
+ gcskLOGICAL_CACHE_PTR next;
+ gcskLOGICAL_CACHE_PTR prev;
+#endif
+
+#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_LINEAR
+ /* Time stamp. */
+ gctUINT64 stamp;
+#endif
+};
+
+typedef struct _gcskSECURE_CACHE * gcskSECURE_CACHE_PTR;
+typedef struct _gcskSECURE_CACHE
+{
+ /* Cache memory. */
+ gcskLOGICAL_CACHE cache[1 + gcdSECURE_CACHE_SLOTS];
+
+ /* Last known index for LINEAR mode. */
+ gcskLOGICAL_CACHE_PTR cacheIndex;
+
+ /* Current free slot for LINEAR mode. */
+ gctUINT32 cacheFree;
+
+ /* Time stamp for LINEAR mode. */
+ gctUINT64 cacheStamp;
+
+#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
+ /* Hash table for HASH mode. */
+ gcskLOGICAL_CACHE hash[256];
+#endif
+}
+gcskSECURE_CACHE;
+
+/*******************************************************************************
+***** Process Database Management *********************************************/
+
+typedef enum _gceDATABASE_TYPE
+{
+ gcvDB_VIDEO_MEMORY = 1, /* Video memory created. */
+ gcvDB_COMMAND_BUFFER, /* Command Buffer. */
+ gcvDB_NON_PAGED, /* Non paged memory. */
+ gcvDB_CONTIGUOUS, /* Contiguous memory. */
+ gcvDB_SIGNAL, /* Signal. */
+ gcvDB_VIDEO_MEMORY_LOCKED, /* Video memory locked. */
+ gcvDB_CONTEXT, /* Context */
+ gcvDB_IDLE, /* GPU idle. */
+ gcvDB_MAP_MEMORY, /* Map memory */
+ gcvDB_MAP_USER_MEMORY, /* Map user memory */
+ gcvDB_SHBUF, /* Shared buffer. */
+
+ gcvDB_NUM_TYPES,
+}
+gceDATABASE_TYPE;
+
+#define gcdDATABASE_TYPE_MASK 0x000000FF
+#define gcdDB_VIDEO_MEMORY_TYPE_MASK 0x0000FF00
+#define gcdDB_VIDEO_MEMORY_TYPE_SHIFT 8
+
+#define gcdDB_VIDEO_MEMORY_POOL_MASK 0x00FF0000
+#define gcdDB_VIDEO_MEMORY_POOL_SHIFT 16
+
+typedef struct _gcsDATABASE_RECORD * gcsDATABASE_RECORD_PTR;
+typedef struct _gcsDATABASE_RECORD
+{
+ /* Pointer to kernel. */
+ gckKERNEL kernel;
+
+ /* Pointer to next database record. */
+ gcsDATABASE_RECORD_PTR next;
+
+ /* Type of record. */
+ gceDATABASE_TYPE type;
+
+ /* Data for record. */
+ gctPOINTER data;
+ gctPHYS_ADDR physical;
+ gctSIZE_T bytes;
+}
+gcsDATABASE_RECORD;
+
+typedef struct _gcsDATABASE * gcsDATABASE_PTR;
+typedef struct _gcsDATABASE
+{
+ /* Pointer to next entry is hash list. */
+ gcsDATABASE_PTR next;
+ gctSIZE_T slot;
+
+ /* Process ID. */
+ gctUINT32 processID;
+
+ /* Open-Close ref count */
+ gctPOINTER refs;
+
+ /* Already mark for delete and cannot reenter */
+ gctBOOL deleted;
+
+ /* Sizes to query. */
+ gcsDATABASE_COUNTERS vidMem;
+ gcsDATABASE_COUNTERS nonPaged;
+ gcsDATABASE_COUNTERS contiguous;
+ gcsDATABASE_COUNTERS mapUserMemory;
+ gcsDATABASE_COUNTERS mapMemory;
+
+ gcsDATABASE_COUNTERS vidMemType[gcvSURF_NUM_TYPES];
+ /* Counter for each video memory pool. */
+ gcsDATABASE_COUNTERS vidMemPool[gcvPOOL_NUMBER_OF_POOLS];
+ gctPOINTER counterMutex;
+
+ /* Idle time management. */
+ gctUINT64 lastIdle;
+ gctUINT64 idle;
+
+ /* Pointer to database. */
+ gcsDATABASE_RECORD_PTR list[48];
+
+#if gcdSECURE_USER
+ /* Secure cache. */
+ gcskSECURE_CACHE cache;
+#endif
+
+ gctPOINTER handleDatabase;
+ gctPOINTER handleDatabaseMutex;
+
+#if gcdPROCESS_ADDRESS_SPACE
+ gckMMU mmu;
+#endif
+}
+gcsDATABASE;
+
+typedef struct _gcsFDPRIVATE * gcsFDPRIVATE_PTR;
+typedef struct _gcsFDPRIVATE
+{
+ gctINT (* release) (gcsFDPRIVATE_PTR Private);
+}
+gcsFDPRIVATE;
+
+typedef struct _gcsRECORDER * gckRECORDER;
+
+
+/* Create a process database that will contain all its allocations. */
+gceSTATUS
+gckKERNEL_CreateProcessDB(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID
+ );
+
+/* Add a record to the process database. */
+gceSTATUS
+gckKERNEL_AddProcessDB(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gceDATABASE_TYPE Type,
+ IN gctPOINTER Pointer,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Size
+ );
+
+/* Remove a record to the process database. */
+gceSTATUS
+gckKERNEL_RemoveProcessDB(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gceDATABASE_TYPE Type,
+ IN gctPOINTER Pointer
+ );
+
+/* Destroy the process database. */
+gceSTATUS
+gckKERNEL_DestroyProcessDB(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID
+ );
+
+/* Find a record to the process database. */
+gceSTATUS
+gckKERNEL_FindProcessDB(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctUINT32 ThreadID,
+ IN gceDATABASE_TYPE Type,
+ IN gctPOINTER Pointer,
+ OUT gcsDATABASE_RECORD_PTR Record
+ );
+
+/* Query the process database. */
+gceSTATUS
+gckKERNEL_QueryProcessDB(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctBOOL LastProcessID,
+ IN gceDATABASE_TYPE Type,
+ OUT gcuDATABASE_INFO * Info
+ );
+
+/* Dump the process database. */
+gceSTATUS
+gckKERNEL_DumpProcessDB(
+ IN gckKERNEL Kernel
+ );
+
+/* Dump the video memory usage for process specified. */
+gceSTATUS
+gckKERNEL_DumpVidMemUsage(
+ IN gckKERNEL Kernel,
+ IN gctINT32 ProcessID
+ );
+
+gceSTATUS
+gckKERNEL_FindDatabase(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctBOOL LastProcessID,
+ OUT gcsDATABASE_PTR * Database
+ );
+
+gceSTATUS
+gckKERNEL_FindHandleDatbase(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ OUT gctPOINTER * HandleDatabase,
+ OUT gctPOINTER * HandleDatabaseMutex
+ );
+
+gceSTATUS
+gckKERNEL_GetProcessMMU(
+ IN gckKERNEL Kernel,
+ OUT gckMMU * Mmu
+ );
+
+gceSTATUS
+gckMMU_FlatMapping(
+ IN gckMMU Mmu,
+ IN gctUINT32 Physical,
+ IN gctUINT32 NumPages
+ );
+
+gceSTATUS
+gckMMU_GetPageEntry(
+ IN gckMMU Mmu,
+ IN gctUINT32 Address,
+ IN gctUINT32_PTR *PageTable
+ );
+
+gceSTATUS
+gckMMU_FreePagesEx(
+ IN gckMMU Mmu,
+ IN gctUINT32 Address,
+ IN gctSIZE_T PageCount
+ );
+
+gceSTATUS
+gckMMU_AttachHardware(
+ IN gckMMU Mmu,
+ IN gckHARDWARE Hardware
+ );
+
+void
+gckMMU_DumpRecentFreedAddress(
+ IN gckMMU Mmu
+ );
+
+gceSTATUS
+gckKERNEL_CreateIntegerDatabase(
+ IN gckKERNEL Kernel,
+ OUT gctPOINTER * Database
+ );
+
+gceSTATUS
+gckKERNEL_DestroyIntegerDatabase(
+ IN gckKERNEL Kernel,
+ IN gctPOINTER Database
+ );
+
+gceSTATUS
+gckKERNEL_AllocateIntegerId(
+ IN gctPOINTER Database,
+ IN gctPOINTER Pointer,
+ OUT gctUINT32 * Id
+ );
+
+gceSTATUS
+gckKERNEL_FreeIntegerId(
+ IN gctPOINTER Database,
+ IN gctUINT32 Id
+ );
+
+gceSTATUS
+gckKERNEL_QueryIntegerId(
+ IN gctPOINTER Database,
+ IN gctUINT32 Id,
+ OUT gctPOINTER * Pointer
+ );
+
+/* Pointer rename */
+gctUINT32
+gckKERNEL_AllocateNameFromPointer(
+ IN gckKERNEL Kernel,
+ IN gctPOINTER Pointer
+ );
+
+gctPOINTER
+gckKERNEL_QueryPointerFromName(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Name
+ );
+
+gceSTATUS
+gckKERNEL_DeleteName(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Name
+ );
+
+#if gcdSECURE_USER
+/* Get secure cache from the process database. */
+gceSTATUS
+gckKERNEL_GetProcessDBCache(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ OUT gcskSECURE_CACHE_PTR * Cache
+ );
+#endif
+
+/*******************************************************************************
+********* Timer Management ****************************************************/
+typedef struct _gcsTIMER * gcsTIMER_PTR;
+typedef struct _gcsTIMER
+{
+ /* Start and Stop time holders. */
+ gctUINT64 startTime;
+ gctUINT64 stopTime;
+}
+gcsTIMER;
+
+/******************************************************************************\
+********************************** Structures **********************************
+\******************************************************************************/
+
+/* gckDB object. */
+struct _gckDB
+{
+ /* Database management. */
+ gcsDATABASE_PTR db[16];
+ gctPOINTER dbMutex;
+ gcsDATABASE_PTR freeDatabase;
+ gcsDATABASE_RECORD_PTR freeRecord;
+ gcsDATABASE_PTR lastDatabase;
+ gctUINT32 lastProcessID;
+ gctUINT64 lastIdle;
+ gctUINT64 idleTime;
+ gctUINT64 lastSlowdown;
+ gctUINT64 lastSlowdownIdle;
+ gctPOINTER nameDatabase;
+ gctPOINTER nameDatabaseMutex;
+
+ gctPOINTER pointerDatabase;
+ gctPOINTER pointerDatabaseMutex;
+
+ gcsLISTHEAD onFaultVidmemList;
+ gctPOINTER onFaultVidmemListMutex;
+};
+
+typedef struct _gckVIRTUAL_BUFFER * gckVIRTUAL_BUFFER_PTR;
+typedef struct _gckVIRTUAL_BUFFER
+{
+ gctPHYS_ADDR physical;
+ gctPOINTER userLogical;
+ gctPOINTER kernelLogical;
+ gctSIZE_T bytes;
+ gctSIZE_T pageCount;
+ gctPOINTER pageTable;
+ gctUINT32 gpuAddress;
+ gctUINT pid;
+ gckKERNEL kernel;
+#if gcdPROCESS_ADDRESS_SPACE
+ gckMMU mmu;
+#endif
+}
+gckVIRTUAL_BUFFER;
+
+typedef struct _gckVIRTUAL_COMMAND_BUFFER * gckVIRTUAL_COMMAND_BUFFER_PTR;
+typedef struct _gckVIRTUAL_COMMAND_BUFFER
+{
+ gckVIRTUAL_BUFFER virtualBuffer;
+ gckVIRTUAL_COMMAND_BUFFER_PTR next;
+ gckVIRTUAL_COMMAND_BUFFER_PTR prev;
+}
+gckVIRTUAL_COMMAND_BUFFER;
+
+/* gckKERNEL object. */
+struct _gckKERNEL
+{
+ /* Object. */
+ gcsOBJECT object;
+
+ /* Pointer to gckOS object. */
+ gckOS os;
+
+ /* Core */
+ gceCORE core;
+
+ /* Pointer to gckHARDWARE object. */
+ gckHARDWARE hardware;
+
+ /* Pointer to gckCOMMAND object. */
+ gckCOMMAND command;
+
+ /* Pointer to gckEVENT object. */
+ gckEVENT eventObj;
+
+ /* Pointer to context. */
+ gctPOINTER context;
+
+ /* Pointer to gckMMU object. */
+ gckMMU mmu;
+
+ /* Arom holding number of clients. */
+ gctPOINTER atomClients;
+
+#if VIVANTE_PROFILER
+ /* Enable profiling */
+ gctBOOL profileEnable;
+ /* Clear profile register or not*/
+ gctBOOL profileCleanRegister;
+#endif
+
+#ifdef QNX_SINGLE_THREADED_DEBUGGING
+ gctPOINTER debugMutex;
+#endif
+
+ /* Database management. */
+ gckDB db;
+ gctBOOL dbCreated;
+
+ gctUINT64 resetTimeStamp;
+
+ /* Pointer to gckEVENT object. */
+ gcsTIMER timers[8];
+ gctUINT32 timeOut;
+
+#if gcdENABLE_VG
+ gckVGKERNEL vg;
+#endif
+
+ /* Virtual command buffer list. */
+ gckVIRTUAL_COMMAND_BUFFER_PTR virtualBufferHead;
+ gckVIRTUAL_COMMAND_BUFFER_PTR virtualBufferTail;
+ gctPOINTER virtualBufferLock;
+
+ /* Enable virtual command buffer. */
+ gctBOOL virtualCommandBuffer;
+
+#if gcdDVFS
+ gckDVFS dvfs;
+#endif
+
+#if gcdANDROID_NATIVE_FENCE_SYNC
+ gctHANDLE timeline;
+#endif
+
+ /* Enable recovery. */
+ gctBOOL recovery;
+
+ /* Level of dump information after stuck. */
+ gctUINT stuckDump;
+
+#if gcdSECURITY || gcdENABLE_TRUST_APPLICATION
+ gctUINT32 securityChannel;
+#endif
+
+ /* Timer to monitor GPU stuck. */
+ gctPOINTER monitorTimer;
+
+ /* Flag to quit monitor timer. */
+ gctBOOL monitorTimerStop;
+
+ /* Monitor states. */
+ gctBOOL monitoring;
+ gctUINT32 lastCommitStamp;
+ gctUINT32 timer;
+ gctUINT32 restoreAddress;
+ gctINT32 restoreMask;
+
+ /* 3DBLIT */
+ gckASYNC_COMMAND asyncCommand;
+ gckEVENT asyncEvent;
+
+ /* Pointer to gckDEVICE object. */
+ gckDEVICE device;
+
+ gctUINT chipID;
+
+ gctUINT32 contiguousBaseAddress;
+ gctUINT32 externalBaseAddress;
+};
+
+struct _FrequencyHistory
+{
+ gctUINT32 frequency;
+ gctUINT32 count;
+};
+
+/* gckDVFS object. */
+struct _gckDVFS
+{
+ gckOS os;
+ gckHARDWARE hardware;
+ gctPOINTER timer;
+ gctUINT32 pollingTime;
+ gctBOOL stop;
+ gctUINT32 totalConfig;
+ gctUINT32 loads[8];
+ gctUINT8 currentScale;
+ struct _FrequencyHistory frequencyHistory[16];
+};
+
+typedef struct _gcsFENCE * gckFENCE;
+typedef struct _gcsFENCE
+{
+ /* Pointer to required object. */
+ gckKERNEL kernel;
+
+ /* Fence location. */
+ gctPHYS_ADDR physical;
+ gctPOINTER logical;
+ gctUINT32 address;
+
+ gcsLISTHEAD waitingList;
+ gctPOINTER mutex;
+}
+gcsFENCE;
+
+/* A sync point attached to fence. */
+typedef struct _gcsFENCE_SYNC * gckFENCE_SYNC;
+typedef struct _gcsFENCE_SYNC
+{
+ /* Stamp of commit access this node. */
+ gctUINT64 commitStamp;
+
+ /* Attach to waiting list. */
+ gcsLISTHEAD head;
+
+ gctPOINTER signal;
+
+ gctBOOL inList;
+}
+gcsFENCE_SYNC;
+
+/* gckCOMMAND object. */
+struct _gckCOMMAND
+{
+ /* Object. */
+ gcsOBJECT object;
+
+ /* Pointer to required object. */
+ gckKERNEL kernel;
+ gckOS os;
+
+ /* Number of bytes per page. */
+ gctUINT32 pageSize;
+
+ /* Current pipe select. */
+ gcePIPE_SELECT pipeSelect;
+
+ /* Command queue running flag. */
+ gctBOOL running;
+
+ /* Idle flag and commit stamp. */
+ gctBOOL idle;
+ gctUINT64 commitStamp;
+
+ /* Command queue mutex. */
+ gctPOINTER mutexQueue;
+
+ /* Context switching mutex. */
+ gctPOINTER mutexContext;
+
+ /* Context sequence mutex. */
+ gctPOINTER mutexContextSeq;
+
+ /* Command queue power semaphore. */
+ gctPOINTER powerSemaphore;
+
+ /* Current command queue. */
+ struct _gcskCOMMAND_QUEUE
+ {
+ gctSIGNAL signal;
+ gctPHYS_ADDR physical;
+ gctPOINTER logical;
+ gctUINT32 address;
+ }
+ queues[gcdCOMMAND_QUEUES];
+
+ gctPHYS_ADDR virtualMemory;
+ gctUINT32 physical;
+ gctPOINTER logical;
+ gctUINT32 address;
+ gctUINT32 offset;
+ gctINT index;
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+ gctUINT wrapCount;
+#endif
+
+ /* The command queue is new. */
+ gctBOOL newQueue;
+
+ /* Context management. */
+ gckCONTEXT currContext;
+ gctPOINTER stateMap;
+
+ /* Pointer to last WAIT command. */
+ gctUINT32 waitPhysical;
+ gctPOINTER waitLogical;
+ gctUINT32 waitAddress;
+ gctUINT32 waitSize;
+
+ /* Command buffer alignment. */
+ gctUINT32 alignment;
+ gctUINT32 reservedHead;
+
+ /* Commit counter. */
+ gctPOINTER atomCommit;
+
+ /* Kernel process ID. */
+ gctUINT32 kernelProcessID;
+
+ /* End Event signal. */
+ gctSIGNAL endEventSignal;
+
+#if gcdSECURE_USER
+ /* Hint array copy buffer. */
+ gctBOOL hintArrayAllocated;
+ gctUINT hintArraySize;
+ gctUINT32_PTR hintArray;
+#endif
+
+#if gcdPROCESS_ADDRESS_SPACE
+ gckMMU currentMmu;
+#endif
+
+#if gcdRECORD_COMMAND
+ gckRECORDER recorder;
+#endif
+
+ gctPOINTER kList;
+
+ gckFENCE fence;
+
+ /* For getting state from async command buffer. */
+ gckASYNC_COMMAND asyncCommand;
+
+ gctBOOL dummyDraw;
+};
+
+typedef struct _gcsEVENT * gcsEVENT_PTR;
+
+/* Structure holding one event to be processed. */
+typedef struct _gcsEVENT
+{
+ /* Pointer to next event in queue. */
+ gcsEVENT_PTR next;
+
+ /* Event information. */
+ gcsHAL_INTERFACE info;
+
+ /* Process ID owning the event. */
+ gctUINT32 processID;
+
+#ifdef __QNXNTO__
+ /* Kernel. */
+ gckKERNEL kernel;
+#endif
+
+ gctBOOL fromKernel;
+}
+gcsEVENT;
+
+/* Structure holding a list of events to be processed by an interrupt. */
+typedef struct _gcsEVENT_QUEUE * gcsEVENT_QUEUE_PTR;
+typedef struct _gcsEVENT_QUEUE
+{
+ /* Time stamp. */
+ gctUINT64 stamp;
+
+ /* Source of the event. */
+ gceKERNEL_WHERE source;
+
+ /* Pointer to head of event queue. */
+ gcsEVENT_PTR head;
+
+ /* Pointer to tail of event queue. */
+ gcsEVENT_PTR tail;
+
+ /* Next list of events. */
+ gcsEVENT_QUEUE_PTR next;
+
+ /* Current commit stamp. */
+ gctUINT64 commitStamp;
+}
+gcsEVENT_QUEUE;
+
+/*
+ gcdREPO_LIST_COUNT defines the maximum number of event queues with different
+ hardware module sources that may coexist at the same time. Only two sources
+ are supported - gcvKERNEL_COMMAND and gcvKERNEL_PIXEL. gcvKERNEL_COMMAND
+ source is used only for managing the kernel command queue and is only issued
+ when the current command queue gets full. Since we commit event queues every
+ time we commit command buffers, in the worst case we can have up to three
+ pending event queues:
+ - gcvKERNEL_PIXEL
+ - gcvKERNEL_COMMAND (queue overflow)
+ - gcvKERNEL_PIXEL
+*/
+#define gcdREPO_LIST_COUNT 3
+
+/* gckEVENT object. */
+struct _gckEVENT
+{
+ /* The object. */
+ gcsOBJECT object;
+
+ /* Pointer to required objects. */
+ gckOS os;
+ gckKERNEL kernel;
+
+ /* Pointer to gckASYNC_COMMAND object. */
+ gckASYNC_COMMAND asyncCommand;
+
+ /* Time stamp. */
+ gctUINT64 stamp;
+ gctUINT32 lastCommitStamp;
+
+ /* Queue mutex. */
+ gctPOINTER eventQueueMutex;
+
+ /* Array of event queues. */
+ gcsEVENT_QUEUE queues[29];
+ gctINT32 freeQueueCount;
+ gctUINT8 lastID;
+
+ /* Pending events. */
+ gctPOINTER pending;
+
+ /* List of free event structures and its mutex. */
+ gcsEVENT_PTR freeEventList;
+ gctSIZE_T freeEventCount;
+ gctPOINTER freeEventMutex;
+
+ /* Event queues. */
+ gcsEVENT_QUEUE_PTR queueHead;
+ gcsEVENT_QUEUE_PTR queueTail;
+ gcsEVENT_QUEUE_PTR freeList;
+ gcsEVENT_QUEUE repoList[gcdREPO_LIST_COUNT];
+ gctPOINTER eventListMutex;
+
+ gctPOINTER submitTimer;
+
+#if gcdINTERRUPT_STATISTIC
+ gctPOINTER interruptCount;
+#endif
+
+ gctINT notifyState;
+};
+
+/* Free all events belonging to a process. */
+gceSTATUS
+gckEVENT_FreeProcess(
+ IN gckEVENT Event,
+ IN gctUINT32 ProcessID
+ );
+
+gceSTATUS
+gckEVENT_Stop(
+ IN gckEVENT Event,
+ IN gctUINT32 ProcessID,
+ IN gctUINT32 Handle,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Address,
+ IN gctSIGNAL Signal,
+ IN OUT gctUINT32 * waitSize
+ );
+
+typedef struct _gcsLOCK_INFO * gcsLOCK_INFO_PTR;
+typedef struct _gcsLOCK_INFO
+{
+ gctUINT32 GPUAddresses[gcdMAX_GPU_COUNT];
+ gctPOINTER pageTables[gcdMAX_GPU_COUNT];
+ gctUINT32 lockeds[gcdMAX_GPU_COUNT];
+ gckKERNEL lockKernels[gcdMAX_GPU_COUNT];
+ gckMMU lockMmus[gcdMAX_GPU_COUNT];
+}
+gcsLOCK_INFO;
+
+typedef struct _gcsGPU_MAP * gcsGPU_MAP_PTR;
+typedef struct _gcsGPU_MAP
+{
+ gctINT pid;
+ gcsLOCK_INFO lockInfo;
+ gcsGPU_MAP_PTR prev;
+ gcsGPU_MAP_PTR next;
+}
+gcsGPU_MAP;
+
+/* gcuVIDMEM_NODE structure. */
+typedef union _gcuVIDMEM_NODE
+{
+ /* Allocated from gckVIDMEM. */
+ struct _gcsVIDMEM_NODE_VIDMEM
+ {
+ /* Owner of this node. */
+ gckVIDMEM memory;
+
+ /* Dual-linked list of nodes. */
+ gcuVIDMEM_NODE_PTR next;
+ gcuVIDMEM_NODE_PTR prev;
+
+ /* Dual linked list of free nodes. */
+ gcuVIDMEM_NODE_PTR nextFree;
+ gcuVIDMEM_NODE_PTR prevFree;
+
+ /* Information for this node. */
+ gctSIZE_T offset;
+ gctSIZE_T bytes;
+ gctUINT32 alignment;
+
+#ifdef __QNXNTO__
+ /* Client virtual address. */
+ gctPOINTER logical;
+#endif
+
+ /* Locked counter. */
+ gctINT32 locked;
+
+ /* Memory pool. */
+ gcePOOL pool;
+ gctUINT32 physical;
+
+ /* Process ID owning this memory. */
+ gctUINT32 processID;
+
+#if gcdENABLE_VG
+ gctPOINTER kernelVirtual;
+#endif
+ }
+ VidMem;
+
+ /* Allocated from gckOS. */
+ struct _gcsVIDMEM_NODE_VIRTUAL
+ {
+ /* Pointer to gckKERNEL object. */
+ gckKERNEL kernel;
+
+ /* Information for this node. */
+ /* Contiguously allocated? */
+ gctBOOL contiguous;
+ /* mdl record pointer... a kmalloc address. Process agnostic. */
+ gctPHYS_ADDR physical;
+ gctSIZE_T bytes;
+ /* do_mmap_pgoff address... mapped per-process. */
+ gctPOINTER logical;
+
+#if gcdENABLE_VG
+ /* Physical address of this node, only meaningful when it is contiguous. */
+ gctUINT64 physicalAddress;
+
+ /* Kernel logical of this node. */
+ gctPOINTER kernelVirtual;
+#endif
+
+ /* Customer private handle */
+ gctUINT32 gid;
+
+ /* Page table information. */
+ /* Used only when node is not contiguous */
+ gctSIZE_T pageCount;
+
+ /* Used only when node is not contiguous */
+ gctPOINTER pageTables[gcdMAX_GPU_COUNT];
+ /* Actual physical address */
+ gctUINT32 addresses[gcdMAX_GPU_COUNT];
+
+ /* Locked counter. */
+ gctINT32 lockeds[gcdMAX_GPU_COUNT];
+
+ /* Surface type. */
+ gceSURF_TYPE type;
+
+ /* Secure GPU virtual address. */
+ gctBOOL secure;
+
+ gctBOOL onFault;
+
+ gcsLISTHEAD head;
+ }
+ Virtual;
+}
+gcuVIDMEM_NODE;
+
+/* gckVIDMEM object. */
+struct _gckVIDMEM
+{
+ /* Object. */
+ gcsOBJECT object;
+
+ /* Pointer to gckOS object. */
+ gckOS os;
+
+ /* mdl record pointer... a kmalloc address. Process agnostic. */
+ gctPHYS_ADDR physical;
+
+ /* Information for this video memory heap. */
+ gctUINT32 baseAddress;
+ gctSIZE_T bytes;
+ gctSIZE_T freeBytes;
+ gctSIZE_T minFreeBytes;
+
+ /* Mapping for each type of surface. */
+ gctINT mapping[gcvSURF_NUM_TYPES];
+
+ /* Sentinel nodes for up to 8 banks. */
+ gcuVIDMEM_NODE sentinel[8];
+
+ /* Allocation threshold. */
+ gctSIZE_T threshold;
+
+ /* The heap mutex. */
+ gctPOINTER mutex;
+};
+
+typedef struct _gcsVIDMEM_NODE
+{
+ _VIV_VIDMEM_METADATA metadata;
+
+ /* Pointer to gcuVIDMEM_NODE. */
+ gcuVIDMEM_NODE_PTR node;
+
+ /* Pointer to gckKERNEL object. */
+ gckKERNEL kernel;
+
+ /* Mutex to protect node. */
+ gctPOINTER mutex;
+
+ /* Reference count. */
+ gctPOINTER reference;
+
+ /* Name for client to import. */
+ gctUINT32 name;
+
+ /* dma_buf */
+ gctPOINTER dmabuf;
+
+#if gcdPROCESS_ADDRESS_SPACE
+ /* Head of mapping list. */
+ gcsGPU_MAP_PTR mapHead;
+
+ /* Tail of mapping list. */
+ gcsGPU_MAP_PTR mapTail;
+
+ gctPOINTER mapMutex;
+#endif
+
+ /* Surface Type. */
+ gceSURF_TYPE type;
+
+ /* Pool from which node is allocated. */
+ gcePOOL pool;
+
+ gcsFENCE_SYNC sync[gcvENGINE_GPU_ENGINE_COUNT];
+
+ /* For DRM usage */
+ gctUINT64 timeStamp;
+ gckVIDMEM_NODE tsNode;
+ gctUINT32 tilingMode;
+ gctUINT32 tsMode;
+ gctUINT64 clearValue;
+}
+gcsVIDMEM_NODE;
+
+typedef struct _gcsVIDMEM_HANDLE * gckVIDMEM_HANDLE;
+typedef struct _gcsVIDMEM_HANDLE
+{
+ /* Pointer to gckVIDMEM_NODE. */
+ gckVIDMEM_NODE node;
+
+ /* Handle for current process. */
+ gctUINT32 handle;
+
+ /* Reference count for this handle. */
+ gctPOINTER reference;
+}
+gcsVIDMEM_HANDLE;
+
+typedef struct _gcsSHBUF * gcsSHBUF_PTR;
+typedef struct _gcsSHBUF
+{
+ /* ID. */
+ gctUINT32 id;
+
+ /* Reference count. */
+ gctPOINTER reference;
+
+ /* Data size. */
+ gctUINT32 size;
+
+ /* Data. */
+ gctPOINTER data;
+}
+gcsSHBUF;
+
+typedef struct _gcsCORE_INFO
+{
+ gceHARDWARE_TYPE type;
+ gceCORE core;
+ gckKERNEL kernel;
+ gctUINT chipID;
+}
+gcsCORE_INFO;
+
+typedef struct _gcsCORE_LIST
+{
+ gckKERNEL kernels[gcvCORE_COUNT];
+ gctUINT32 num;
+}
+gcsCORE_LIST;
+
+/* A gckDEVICE is a group of cores (gckKERNEL in software). */
+typedef struct _gcsDEVICE
+{
+ gcsCORE_INFO coreInfoArray[gcvCORE_COUNT];
+ gctUINT32 coreNum;
+ gcsCORE_LIST map[gcvHARDWARE_NUM_TYPES];
+ gceHARDWARE_TYPE defaultHwType;
+
+ gckOS os;
+
+ /* Process resource database. */
+ gckDB database;
+
+ /* Same hardware type shares one MMU. */
+ gckMMU mmus[gcvHARDWARE_NUM_TYPES];
+
+ /* Mutex to make sure stuck dump for multiple cores doesn't interleave. */
+ gctPOINTER stuckDumpMutex;
+
+ /* Mutex for multi-core combine mode command submission */
+ gctPOINTER commitMutex;
+}
+gcsDEVICE;
+
+gceSTATUS
+gckVIDMEM_HANDLE_Allocate(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM_NODE Node,
+ OUT gctUINT32 * Handle
+ );
+
+gceSTATUS
+gckVIDMEM_HANDLE_Reference(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctUINT32 Handle
+ );
+
+gceSTATUS
+gckVIDMEM_HANDLE_Dereference(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctUINT32 Handle
+ );
+
+gceSTATUS
+gckVIDMEM_NODE_Allocate(
+ IN gckKERNEL Kernel,
+ IN gcuVIDMEM_NODE_PTR VideoNode,
+ IN gceSURF_TYPE Type,
+ IN gcePOOL Pool,
+ IN gctUINT32 * Handle
+ );
+
+gceSTATUS
+gckVIDMEM_Node_Lock(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM_NODE Node,
+ OUT gctUINT32 *Address
+ );
+
+gceSTATUS
+gckVIDMEM_NODE_Unlock(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM_NODE Node,
+ IN gctUINT32 ProcessID
+ );
+
+gceSTATUS
+gckVIDMEM_NODE_Reference(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM_NODE Node
+ );
+
+gceSTATUS
+gckVIDMEM_NODE_Dereference(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM_NODE Node
+ );
+
+gceSTATUS
+gckVIDMEM_NODE_Export(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Handle,
+ IN gctINT32 Flags,
+ OUT gctPOINTER *DmaBuf,
+ OUT gctINT32 *FD
+ );
+
+gceSTATUS
+gckVIDMEM_NODE_Name(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Handle,
+ OUT gctUINT32 * Name
+ );
+
+gceSTATUS
+gckVIDMEM_NODE_Import(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Name,
+ OUT gctUINT32 * Handle
+ );
+
+gceSTATUS
+gckVIDMEM_NODE_GetFd(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Handle,
+ OUT gctINT * Fd
+ );
+
+gceSTATUS
+gckVIDMEM_HANDLE_LookupAndReference(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Handle,
+ OUT gckVIDMEM_NODE * Node
+ );
+
+gceSTATUS
+gckVIDMEM_HANDLE_Lookup(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctUINT32 Handle,
+ OUT gckVIDMEM_NODE * Node
+ );
+
+gceSTATUS
+gckVIDMEM_NODE_WrapUserMemory(
+ IN gckKERNEL Kernel,
+ IN gcsUSER_MEMORY_DESC_PTR Desc,
+ OUT gctUINT32 * Handle,
+ OUT gctUINT64 * Bytes
+ );
+
+gceSTATUS
+gckVIDMEM_FindVIDMEM(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 HardwareAddress,
+ OUT gcuVIDMEM_NODE_PTR * Node,
+ OUT gctUINT32_PTR PageTableEntryValue
+ );
+
+gceSTATUS
+gckVIDMEM_QueryNodes(
+ IN gckKERNEL Kernel,
+ IN gcePOOL Pool,
+ OUT gctINT32 *Count,
+ OUT gcuVIDMEM_NODE_PTR *Nodes
+ );
+
+#if gcdPROCESS_ADDRESS_SPACE
+gceSTATUS
+gckEVENT_DestroyMmu(
+ IN gckEVENT Event,
+ IN gckMMU Mmu,
+ IN gceKERNEL_WHERE FromWhere
+ );
+#endif
+
+typedef struct _gcsADDRESS_AREA * gcsADDRESS_AREA_PTR;
+typedef struct _gcsADDRESS_AREA
+{
+ /* Page table information. */
+ gctSIZE_T pageTableSize;
+ gctPHYS_ADDR pageTablePhysical;
+ gctUINT32_PTR pageTableLogical;
+ gctUINT32 pageTableEntries;
+
+ /* Free entries. */
+ gctUINT32 heapList;
+ gctBOOL freeNodes;
+
+ gctUINT32 dynamicMappingStart;
+ gctUINT32 dynamicMappingEnd;
+
+ gctUINT32_PTR mapLogical;
+}
+gcsADDRESS_AREA;
+
+/* gckMMU object. */
+struct _gckMMU
+{
+ /* The object. */
+ gcsOBJECT object;
+
+ /* Pointer to gckOS object. */
+ gckOS os;
+
+ /* Pointer to gckHARDWARE object. */
+ gckHARDWARE hardware;
+
+ /* The page table mutex. */
+ gctPOINTER pageTableMutex;
+
+ /* Master TLB information. */
+ gctSIZE_T mtlbSize;
+ gctPHYS_ADDR mtlbPhysical;
+ gctUINT32_PTR mtlbLogical;
+ gctUINT32 mtlbEntries;
+
+ gctPOINTER staticSTLB;
+ gctBOOL enabled;
+
+#if gcdPROCESS_ADDRESS_SPACE
+ gctPOINTER pageTableDirty[gcdMAX_GPU_COUNT];
+ gctPOINTER stlbs;
+#endif
+
+ gctPOINTER safePageLogical;
+ gctPHYS_ADDR safePagePhysical;
+ gctUINT32 safeAddress;
+ gctSIZE_T safePageSize;
+
+ /* physBase,physSize flat mapping area. */
+ gctUINT32 flatMappingRangeCount;
+ gcsFLAT_MAPPING_RANGE flatMappingRanges[gcdMAX_FLAT_MAPPING_COUNT];
+
+ /* List of hardware which uses this MMU. */
+ gcsLISTHEAD hardwareList;
+
+ struct _gckQUEUE recentFreedAddresses;
+
+ gcsADDRESS_AREA area[gcvADDRESS_AREA_COUNT];
+
+ gctUINT32 contiguousBaseAddress;
+ gctUINT32 externalBaseAddress;
+};
+
+typedef struct _gcsASYNC_COMMAND
+{
+ gckOS os;
+ gckHARDWARE hardware;
+ gckKERNEL kernel;
+
+ gctPOINTER mutex;
+ gcsFE fe;
+
+ gctUINT32 reservedTail;
+ gctUINT64 commitStamp;
+
+ gckFENCE fence;
+
+ gctPOINTER kList;
+}
+gcsASYNC_COMMAND;
+
+
+gceSTATUS
+gckOS_CreateKernelVirtualMapping(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Logical,
+ OUT gctSIZE_T * PageCount
+ );
+
+gceSTATUS
+gckOS_DestroyKernelVirtualMapping(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical
+ );
+
+gceSTATUS
+gckOS_CreateUserVirtualMapping(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Logical,
+ OUT gctSIZE_T * PageCount
+ );
+
+gceSTATUS
+gckOS_DestroyUserVirtualMapping(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical
+ );
+
+gceSTATUS
+gckOS_GetFd(
+ IN gctSTRING Name,
+ IN gcsFDPRIVATE_PTR Private,
+ OUT gctINT *Fd
+ );
+
+/*******************************************************************************
+**
+** gckOS_ReadMappedPointer
+**
+** Read pointer mapped from user pointer which returned by gckOS_MapUserPointer.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPOINTER Address
+** Pointer returned by gckOS_MapUserPointer.
+**
+** gctUINT32_PTR Data
+** Pointer to hold 32 bits data.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_ReadMappedPointer(
+ IN gckOS Os,
+ IN gctPOINTER Address,
+ IN gctUINT32_PTR Data
+ );
+
+gceSTATUS
+gckKERNEL_AllocateVirtualCommandBuffer(
+ IN gckKERNEL Kernel,
+ IN gctBOOL InUserSpace,
+ IN OUT gctSIZE_T * Bytes,
+ OUT gctPHYS_ADDR * Physical,
+ OUT gctPOINTER * Logical
+ );
+
+gceSTATUS
+gckKERNEL_DestroyVirtualCommandBuffer(
+ IN gckKERNEL Kernel,
+ IN gctSIZE_T Bytes,
+ IN gctPHYS_ADDR Physical,
+ IN gctPOINTER Logical
+ );
+
+gceSTATUS
+gckKERNEL_AllocateVirtualMemory(
+ IN gckKERNEL Kernel,
+ IN gctBOOL NonPaged,
+ IN gctBOOL InUserSpace,
+ IN OUT gctSIZE_T * Bytes,
+ OUT gctPHYS_ADDR * Physical,
+ OUT gctPOINTER * Logical
+ );
+
+gceSTATUS
+gckKERNEL_FreeVirtualMemory(
+ IN gctPHYS_ADDR Physical,
+ IN gctPOINTER Logical,
+ IN gctBOOL NonPaged
+ );
+
+gceSTATUS
+gckKERNEL_GetGPUAddress(
+ IN gckKERNEL Kernel,
+ IN gctPOINTER Logical,
+ IN gctBOOL InUserSpace,
+ IN gctPHYS_ADDR Physical,
+ OUT gctUINT32 * Address
+ );
+
+gceSTATUS
+gckKERNEL_QueryGPUAddress(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 GpuAddress,
+ OUT gckVIRTUAL_COMMAND_BUFFER_PTR * Buffer
+ );
+
+gceSTATUS
+gckKERNEL_AttachProcess(
+ IN gckKERNEL Kernel,
+ IN gctBOOL Attach
+ );
+
+gceSTATUS
+gckKERNEL_AttachProcessEx(
+ IN gckKERNEL Kernel,
+ IN gctBOOL Attach,
+ IN gctUINT32 PID
+ );
+
+#if gcdSECURE_USER
+gceSTATUS
+gckKERNEL_MapLogicalToPhysical(
+ IN gckKERNEL Kernel,
+ IN gcskSECURE_CACHE_PTR Cache,
+ IN OUT gctPOINTER * Data
+ );
+
+gceSTATUS
+gckKERNEL_FlushTranslationCache(
+ IN gckKERNEL Kernel,
+ IN gcskSECURE_CACHE_PTR Cache,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ );
+#endif
+
+gceSTATUS
+gckHARDWARE_QueryIdle(
+ IN gckHARDWARE Hardware,
+ OUT gctBOOL_PTR IsIdle
+ );
+
+gceSTATUS
+gckHARDWARE_WaitFence(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctUINT64 FenceData,
+ IN gctUINT32 FenceAddress,
+ OUT gctUINT32 *Bytes
+ );
+
+gceSTATUS
+gckHARDWARE_AddressInHardwareFuncions(
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 Address,
+ OUT gctPOINTER *Pointer
+ );
+
+gceSTATUS
+gckHARDWARE_UpdateContextID(
+ IN gckHARDWARE Hardware
+ );
+
+#if gcdSECURITY
+gceSTATUS
+gckKERNEL_SecurityOpen(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 GPU,
+ OUT gctUINT32 *Channel
+ );
+
+/*
+** Close a security service channel
+*/
+gceSTATUS
+gckKERNEL_SecurityClose(
+ IN gctUINT32 Channel
+ );
+
+/*
+** Security service interface.
+*/
+gceSTATUS
+gckKERNEL_SecurityCallService(
+ IN gctUINT32 Channel,
+ IN OUT gcsTA_INTERFACE * Interface
+ );
+
+gceSTATUS
+gckKERNEL_SecurityStartCommand(
+ IN gckKERNEL Kernel
+ );
+
+gceSTATUS
+gckKERNEL_SecurityAllocateSecurityMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Bytes,
+ OUT gctUINT32 * Handle
+ );
+
+gceSTATUS
+gckKERNEL_SecurityExecute(
+ IN gckKERNEL Kernel,
+ IN gctPOINTER Buffer,
+ IN gctUINT32 Bytes
+ );
+
+gceSTATUS
+gckKERNEL_SecurityMapMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 *PhysicalArray,
+ IN gctUINT32 PageCount,
+ OUT gctUINT32 * GPUAddress
+ );
+
+gceSTATUS
+gckKERNEL_SecurityUnmapMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 GPUAddress,
+ IN gctUINT32 PageCount
+ );
+
+#endif
+
+#if gcdENABLE_TRUST_APPLICATION
+gceSTATUS
+gckKERNEL_SecurityOpen(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 GPU,
+ OUT gctUINT32 *Channel
+ );
+
+/*
+** Close a security service channel
+*/
+gceSTATUS
+gckKERNEL_SecurityClose(
+ IN gctUINT32 Channel
+ );
+
+/*
+** Security service interface.
+*/
+gceSTATUS
+gckKERNEL_SecurityCallService(
+ IN gctUINT32 Channel,
+ IN OUT gcsTA_INTERFACE * Interface
+ );
+
+gceSTATUS
+gckKERNEL_SecurityStartCommand(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Address,
+ IN gctUINT32 Bytes
+ );
+
+gceSTATUS
+gckKERNEL_SecurityMapMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 *PhysicalArray,
+ IN gctPHYS_ADDR_T Physical,
+ IN gctUINT32 PageCount,
+ OUT gctUINT32 * GPUAddress
+ );
+
+gceSTATUS
+gckKERNEL_SecurityUnmapMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 GPUAddress,
+ IN gctUINT32 PageCount
+ );
+
+gceSTATUS
+gckKERNEL_SecurityDumpMMUException(
+ IN gckKERNEL Kernel
+ );
+
+gceSTATUS
+gckKERNEL_ReadMMUException(
+ IN gckKERNEL Kernel,
+ IN gctUINT32_PTR MMUStatus,
+ IN gctUINT32_PTR MMUException
+ );
+
+gceSTATUS
+gckKERNEL_HandleMMUException(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 MMUStatus,
+ IN gctPHYS_ADDR_T Physical,
+ IN gctUINT32 GPUAddres
+ );
+#endif
+
+gceSTATUS
+gckKERNEL_CreateShBuffer(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Size,
+ OUT gctSHBUF * ShBuf
+ );
+
+gceSTATUS
+gckKERNEL_DestroyShBuffer(
+ IN gckKERNEL Kernel,
+ IN gctSHBUF ShBuf
+ );
+
+gceSTATUS
+gckKERNEL_MapShBuffer(
+ IN gckKERNEL Kernel,
+ IN gctSHBUF ShBuf
+ );
+
+gceSTATUS
+gckKERNEL_WriteShBuffer(
+ IN gckKERNEL Kernel,
+ IN gctSHBUF ShBuf,
+ IN gctPOINTER UserData,
+ IN gctUINT32 ByteCount
+ );
+
+gceSTATUS
+gckKERNEL_ReadShBuffer(
+ IN gckKERNEL Kernel,
+ IN gctSHBUF ShBuf,
+ IN gctPOINTER UserData,
+ IN gctUINT32 ByteCount,
+ OUT gctUINT32 * BytesRead
+ );
+
+
+/******************************************************************************\
+******************************* gckCONTEXT Object *******************************
+\******************************************************************************/
+
+gceSTATUS
+gckCONTEXT_Construct(
+ IN gckOS Os,
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 ProcessID,
+ OUT gckCONTEXT * Context
+ );
+
+gceSTATUS
+gckCONTEXT_Destroy(
+ IN gckCONTEXT Context
+ );
+
+gceSTATUS
+gckCONTEXT_Update(
+ IN gckCONTEXT Context,
+ IN gctUINT32 ProcessID,
+ IN gcsSTATE_DELTA_PTR StateDelta
+ );
+
+gceSTATUS
+gckCONTEXT_MapBuffer(
+ IN gckCONTEXT Context,
+ OUT gctUINT32 *Physicals,
+ OUT gctUINT64 *Logicals,
+ OUT gctUINT32 *Bytes
+ );
+
+void
+gckQUEUE_Enqueue(
+ IN gckQUEUE LinkQueue,
+ IN gcuQUEUEDATA *Data
+ );
+
+void
+gckQUEUE_GetData(
+ IN gckQUEUE LinkQueue,
+ IN gctUINT32 Index,
+ OUT gcuQUEUEDATA ** Data
+ );
+
+gceSTATUS
+gckQUEUE_Allocate(
+ IN gckOS Os,
+ IN gckQUEUE Queue,
+ IN gctUINT32 Size
+ );
+
+gceSTATUS
+gckQUEUE_Free(
+ IN gckOS Os,
+ IN gckQUEUE Queue
+ );
+
+/******************************************************************************\
+****************************** gckRECORDER Object ******************************
+\******************************************************************************/
+gceSTATUS
+gckRECORDER_Construct(
+ IN gckOS Os,
+ IN gckHARDWARE Hardware,
+ OUT gckRECORDER * Recorder
+ );
+
+gceSTATUS
+gckRECORDER_Destory(
+ IN gckOS Os,
+ IN gckRECORDER Recorder
+ );
+
+void
+gckRECORDER_AdvanceIndex(
+ gckRECORDER Recorder,
+ gctUINT64 CommitStamp
+ );
+
+void
+gckRECORDER_Record(
+ gckRECORDER Recorder,
+ gctUINT8_PTR CommandBuffer,
+ gctUINT32 CommandBytes,
+ gctUINT8_PTR ContextBuffer,
+ gctUINT32 ContextBytes
+ );
+
+void
+gckRECORDER_Dump(
+ gckRECORDER Recorder
+ );
+
+gceSTATUS
+gckRECORDER_UpdateMirror(
+ gckRECORDER Recorder,
+ gctUINT32 State,
+ gctUINT32 Data
+ );
+
+/******************************************************************************\
+*************************** gckASYNC_COMMAND Object ****************************
+\******************************************************************************/
+gceSTATUS
+gckASYNC_COMMAND_Construct(
+ IN gckKERNEL Kernel,
+ OUT gckASYNC_COMMAND * Command
+ );
+
+gceSTATUS
+gckASYNC_COMMAND_Destroy(
+ IN gckASYNC_COMMAND Command
+ );
+
+gceSTATUS
+gckASYNC_COMMAND_Commit(
+ IN gckASYNC_COMMAND Command,
+ IN gcoCMDBUF CommandBuffer,
+ IN gcsQUEUE_PTR EventQueue
+ );
+
+gceSTATUS
+gckASYNC_COMMAND_EnterCommit(
+ IN gckASYNC_COMMAND Command
+ );
+
+gceSTATUS
+gckASYNC_COMMAND_ExitCommit(
+ IN gckASYNC_COMMAND Command
+ );
+
+gceSTATUS
+gckASYNC_COMMAND_Execute(
+ IN gckASYNC_COMMAND Command,
+ IN gctUINT32 Start,
+ IN gctUINT32 End
+ );
+
+void
+gcsLIST_Init(
+ gcsLISTHEAD_PTR Node
+ );
+
+void
+gcsLIST_Add(
+ gcsLISTHEAD_PTR New,
+ gcsLISTHEAD_PTR Head
+ );
+
+void
+gcsLIST_AddTail(
+ gcsLISTHEAD_PTR New,
+ gcsLISTHEAD_PTR Head
+ );
+
+void
+gcsLIST_Del(
+ gcsLISTHEAD_PTR Node
+ );
+
+gctBOOL
+gcsLIST_Empty(
+ gcsLISTHEAD_PTR Head
+ );
+
+#define gcmkLIST_FOR_EACH(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+#define gcmkLIST_FOR_EACH_SAFE(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+gceSTATUS
+gckFENCE_Create(
+ IN gckOS Os,
+ IN gckKERNEL Kernel,
+ OUT gckFENCE * Fence
+ );
+
+gceSTATUS
+gckFENCE_Destory(
+ IN gckOS Os,
+ OUT gckFENCE Fence
+ );
+
+gceSTATUS
+gckFENCE_Signal(
+ IN gckOS Os,
+ IN gckFENCE Fence
+ );
+
+gceSTATUS
+gckDEVICE_Construct(
+ IN gckOS Os,
+ OUT gckDEVICE * Device
+ );
+
+gceSTATUS
+gckDEVICE_AddCore(
+ IN gckDEVICE Device,
+ IN gceCORE Core,
+ IN gctUINT chipID,
+ IN gctPOINTER Context,
+ IN gckKERNEL * Kernel
+ );
+
+gceSTATUS
+gckDEVICE_Destroy(
+ IN gckOS Os,
+ IN gckDEVICE Device
+ );
+
+gceSTATUS
+gckDEVICE_Dispatch(
+ IN gckDEVICE Device,
+ IN gcsHAL_INTERFACE_PTR Interface
+ );
+
+gceSTATUS
+gckDEVICE_GetMMU(
+ IN gckDEVICE Device,
+ IN gceHARDWARE_TYPE Type,
+ IN gckMMU *Mmu
+ );
+
+gceSTATUS
+gckDEVICE_SetMMU(
+ IN gckDEVICE Device,
+ IN gceHARDWARE_TYPE Type,
+ IN gckMMU Mmu
+ );
+
+gceSTATUS
+gckDEVICE_QueryGPUAddress(
+ IN gckDEVICE Device,
+ IN gckKERNEL Kernel,
+ IN gctUINT32 GPUAddress,
+ OUT gckVIRTUAL_COMMAND_BUFFER_PTR * Buffer
+ );
+
+#if gcdENABLE_TRUST_APPLICATION
+gceSTATUS
+gckKERNEL_MapInTrustApplicaiton(
+ IN gckKERNEL Kernel,
+ IN gctPOINTER Logical,
+ IN gctPHYS_ADDR Physical,
+ IN gctUINT32 GPUAddress,
+ IN gctSIZE_T PageCount
+ );
+#endif
+
+#if gcdSECURITY || gcdENABLE_TRUST_APPLICATION
+gceSTATUS
+gckOS_OpenSecurityChannel(
+ IN gckOS Os,
+ IN gceCORE Core,
+ OUT gctUINT32 *Channel
+ );
+
+gceSTATUS
+gckOS_CloseSecurityChannel(
+ IN gctUINT32 Channel
+ );
+
+gceSTATUS
+gckOS_CallSecurityService(
+ IN gctUINT32 Channel,
+ IN gcsTA_INTERFACE * Interface
+ );
+
+gceSTATUS
+gckOS_InitSecurityChannel(
+ OUT gctUINT32 Channel
+ );
+
+gceSTATUS
+gckOS_AllocatePageArray(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T PageCount,
+ OUT gctPOINTER * PageArrayLogical,
+ OUT gctPHYS_ADDR * PageArrayPhysical
+ );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_kernel_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_async_command.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_async_command.c
new file mode 100644
index 000000000000..2a0c5547215e
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_async_command.c
@@ -0,0 +1,477 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+#include "gc_hal_kernel_context.h"
+
+#define _GC_OBJ_ZONE gcvZONE_ASYNC_COMMAND
+
+static gceSTATUS
+_HandlePatchList(
+ IN gckASYNC_COMMAND Command,
+ IN gcoCMDBUF CommandBuffer,
+ IN gctBOOL NeedCopy
+ )
+{
+ gceSTATUS status;
+ gcsPATCH_LIST * uList;
+ gcsPATCH_LIST * previous;
+ gcsPATCH_LIST * kList;
+
+ gcmkHEADER_ARG(
+ "Command=0x%x CommandBuffer=0x%x NeedCopy=%d",
+ Command, CommandBuffer, NeedCopy
+ );
+
+ uList = gcmUINT64_TO_PTR(CommandBuffer->patchHead);
+
+ while (uList)
+ {
+ gctUINT i;
+
+ kList = gcvNULL;
+ previous = uList;
+
+ gcmkONERROR(gckKERNEL_OpenUserData(
+ Command->kernel,
+ NeedCopy,
+ Command->kList,
+ uList,
+ gcmSIZEOF(gcsPATCH_LIST),
+ (gctPOINTER *)&kList
+ ));
+
+ for (i = 0; i < kList->count; i++)
+ {
+ gcsPATCH * patch = &kList->patch[i];
+
+ /* Touch video memory node. */
+ gcmkVERIFY_OK(gckVIDMEM_SetCommitStamp(Command->kernel, gcvENGINE_BLT, patch->handle, Command->commitStamp));
+ }
+
+ uList = kList->next;
+
+ gcmkVERIFY_OK(gckKERNEL_CloseUserData(
+ Command->kernel,
+ NeedCopy,
+ gcvFALSE,
+ previous,
+ gcmSIZEOF(gcsPATCH_LIST),
+ (gctPOINTER *)&kList
+ ));
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (kList)
+ {
+ gcmkVERIFY_OK(gckKERNEL_CloseUserData(
+ Command->kernel,
+ NeedCopy,
+ gcvFALSE,
+ previous,
+ gcmSIZEOF(gcsPATCH_LIST),
+ (gctPOINTER *)&kList
+ ));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+
+gceSTATUS
+gckASYNC_COMMAND_Construct(
+ IN gckKERNEL Kernel,
+ OUT gckASYNC_COMMAND * Command
+ )
+{
+ gceSTATUS status;
+ gckASYNC_COMMAND command;
+ gckOS os = Kernel->os;
+
+ gcmkHEADER();
+
+ /* Allocate gckASYNC_COMMAND object. */
+ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsASYNC_COMMAND), (gctPOINTER *)&command));
+
+ gckOS_ZeroMemory(command, gcmSIZEOF(gcsASYNC_COMMAND));
+
+ /* Mutex to protect gckFE. */
+ gcmkONERROR(gckOS_CreateMutex(os, &command->mutex));
+
+ /* Initialize gckFE. */
+ gckFE_Initialize(Kernel->hardware, &command->fe);
+
+ /* Initialize gckASYNC_COMMAND object. */
+ command->os = os;
+ command->kernel = Kernel;
+ command->hardware = Kernel->hardware;
+
+ gcmkVERIFY_OK(gckHARDWARE_QueryCommandBuffer(
+ Kernel->hardware,
+ gcvENGINE_BLT,
+ gcvNULL,
+ gcvNULL,
+ &command->reservedTail
+ ));
+
+ gcmkONERROR(gckFENCE_Create(
+ os, Kernel, &command->fence
+ ));
+
+ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsPATCH_LIST), &command->kList));
+
+ /* Commit stamp start from 1. */
+ command->commitStamp = 1;
+
+ *Command = command;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Rollback. */
+ gckASYNC_COMMAND_Destroy(command);
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckASYNC_COMMAND_Destroy(
+ IN gckASYNC_COMMAND Command
+ )
+{
+ gcmkHEADER();
+
+ if (Command)
+ {
+ if (Command->mutex)
+ {
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutex));
+ }
+
+ if (Command->fence)
+ {
+ gcmkVERIFY_OK(gckFENCE_Destory(Command->os, Command->fence));
+ }
+
+ if (Command->kList)
+ {
+ gcmkOS_SAFE_FREE(Command->os, Command->kList);
+ }
+
+ if (Command->fe.freeDscriptors)
+ {
+ gcmkOS_SAFE_FREE(Command->os, Command->fe.freeDscriptors);
+ }
+
+ gcmkOS_SAFE_FREE(Command->os, Command);
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckASYNC_COMMAND_Commit(
+ IN gckASYNC_COMMAND Command,
+ IN gcoCMDBUF CommandBuffer,
+ IN gcsQUEUE_PTR EventQueue
+ )
+{
+ gceSTATUS status;
+ gctBOOL available = gcvFALSE;
+ gctBOOL acquired = gcvFALSE;
+ gcoCMDBUF commandBufferObject = gcvNULL;
+ struct _gcoCMDBUF _commandBufferObject;
+ gctUINT8_PTR commandBufferLogical;
+ gctUINT8_PTR commandBufferTail;
+ gctUINT commandBufferSize;
+ gctUINT32 commandBufferAddress;
+ gcsFEDescriptor descriptor;
+ gctUINT32 skipFlushBytes;
+ gctUINT32 fenceBytes;
+ gctBOOL needCopy;
+ gctUINT32 oldValue;
+ gctUINT32 flushBytes;
+
+ gcmkHEADER();
+
+ gckOS_QueryNeedCopy(Command->os, 0, &needCopy);
+
+ gcmkVERIFY_OK(_HandlePatchList(Command, CommandBuffer, needCopy));
+
+ /* Open user passed gcoCMDBUF object. */
+ gcmkONERROR(gckKERNEL_OpenUserData(
+ Command->kernel,
+ needCopy,
+ &_commandBufferObject,
+ CommandBuffer,
+ gcmSIZEOF(struct _gcoCMDBUF),
+ (gctPOINTER *)&commandBufferObject
+ ));
+
+ gcmkVERIFY_OBJECT(commandBufferObject, gcvOBJ_COMMANDBUFFER);
+
+ gckHARDWARE_FlushAsyncMMU(Command->hardware, gcvNULL, &flushBytes);
+
+ gcmkONERROR(gckOS_AtomicExchange(Command->os,
+ Command->hardware->pageTableDirty[gcvENGINE_BLT],
+ 0,
+ &oldValue));
+
+ if (oldValue)
+ {
+ commandBufferLogical
+ = (gctUINT8_PTR) gcmUINT64_TO_PTR(commandBufferObject->logical)
+ + commandBufferObject->startOffset;
+
+ gckHARDWARE_FlushAsyncMMU(Command->hardware, commandBufferLogical, &flushBytes);
+
+ skipFlushBytes = 0;
+ }
+ else
+ {
+ skipFlushBytes = flushBytes;
+ }
+
+ /* Compute the command buffer entry and the size. */
+ commandBufferLogical
+ = (gctUINT8_PTR) gcmUINT64_TO_PTR(commandBufferObject->logical)
+ + commandBufferObject->startOffset
+ + skipFlushBytes;
+
+ commandBufferSize
+ = commandBufferObject->offset
+ + Command->reservedTail
+ - commandBufferObject->startOffset
+ - skipFlushBytes;
+
+ commandBufferTail
+ = commandBufferLogical
+ + commandBufferSize
+ - Command->reservedTail;
+
+ /* Get the hardware address. */
+ if (Command->kernel && Command->kernel->virtualCommandBuffer)
+ {
+ gckKERNEL kernel = Command->kernel;
+ gckVIRTUAL_COMMAND_BUFFER_PTR virtualCommandBuffer
+ = gcmNAME_TO_PTR(commandBufferObject->physical);
+
+ if (virtualCommandBuffer == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gcmkONERROR(gckKERNEL_GetGPUAddress(
+ Command->kernel,
+ commandBufferLogical,
+ gcvTRUE,
+ virtualCommandBuffer,
+ &commandBufferAddress
+ ));
+ }
+ else
+ {
+ gcmkONERROR(gckHARDWARE_ConvertLogical(
+ Command->hardware,
+ commandBufferLogical,
+ gcvTRUE,
+ &commandBufferAddress
+ ));
+ }
+
+ gcmkONERROR(gckHARDWARE_Fence(
+ Command->hardware,
+ gcvENGINE_BLT,
+ commandBufferTail,
+ Command->fence->address,
+ Command->commitStamp,
+ &fenceBytes
+ ));
+
+ descriptor.start = commandBufferAddress;
+ descriptor.end = commandBufferAddress + commandBufferSize;
+
+ gcmkDUMPCOMMAND(
+ Command->os,
+ commandBufferLogical,
+ commandBufferSize,
+ gcvDUMP_BUFFER_USER,
+ gcvFALSE
+ );
+
+ gckOS_AcquireMutex(Command->os, Command->mutex, gcvINFINITE);
+ acquired = gcvTRUE;
+
+ /* Acquire a slot. */
+ for(;;)
+ {
+ gcmkONERROR(gckFE_ReserveSlot(Command->hardware, &Command->fe, &available));
+
+ if (available)
+ {
+ break;
+ }
+ else
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, _GC_OBJ_ZONE, "No available slot, have to wait");
+
+ gckOS_Delay(Command->os, 1);
+ }
+ }
+
+ /* Send descriptor. */
+ gckFE_Execute(Command->hardware, &Command->fe, &descriptor);
+
+ Command->commitStamp++;
+
+ gckOS_ReleaseMutex(Command->os, Command->mutex);
+ acquired = gcvFALSE;
+
+ gcmkVERIFY_OK(gckKERNEL_CloseUserData(
+ Command->kernel,
+ needCopy,
+ gcvFALSE,
+ CommandBuffer,
+ gcmSIZEOF(struct _gcoCMDBUF),
+ (gctPOINTER *)&commandBufferObject
+ ));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ gckOS_ReleaseMutex(Command->os, Command->mutex);
+ }
+
+ if (commandBufferObject)
+ {
+ gcmkVERIFY_OK(gckKERNEL_CloseUserData(
+ Command->kernel,
+ needCopy,
+ gcvFALSE,
+ CommandBuffer,
+ gcmSIZEOF(struct _gcoCMDBUF),
+ (gctPOINTER *)&commandBufferObject
+ ));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckASYNC_COMMAND_EnterCommit(
+ IN gckASYNC_COMMAND Command
+ )
+{
+ return gckOS_AcquireMutex(Command->os, Command->mutex, gcvINFINITE);
+}
+
+
+gceSTATUS
+gckASYNC_COMMAND_ExitCommit(
+ IN gckASYNC_COMMAND Command
+ )
+{
+ return gckOS_ReleaseMutex(Command->os, Command->mutex);
+}
+
+gceSTATUS
+gckASYNC_COMMAND_Execute(
+ IN gckASYNC_COMMAND Command,
+ IN gctUINT32 Start,
+ IN gctUINT32 End
+ )
+{
+ gceSTATUS status;
+ gcsFEDescriptor descriptor;
+ gctBOOL available;
+
+ descriptor.start = Start;
+ descriptor.end = End;
+
+ /* Acquire a slot. */
+ for(;;)
+ {
+ gcmkONERROR(gckFE_ReserveSlot(Command->hardware, &Command->fe, &available));
+
+ if (available)
+ {
+ break;
+ }
+ else
+ {
+ gckOS_Delay(Command->os, 1);
+ }
+ }
+
+ /* Send descriptor. */
+ gckFE_Execute(Command->hardware, &Command->fe, &descriptor);
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command.c
new file mode 100644
index 000000000000..2837a1c7a1e2
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command.c
@@ -0,0 +1,3461 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+#include "gc_hal_kernel_context.h"
+
+#define _GC_OBJ_ZONE gcvZONE_COMMAND
+
+/******************************************************************************\
+********************************* Support Code *********************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+** _NewQueue
+**
+** Allocate a new command queue.
+**
+** INPUT:
+**
+** gckCOMMAND Command
+** Pointer to an gckCOMMAND object.
+**
+** gctBOOL Stalled
+** Indicate if hardware is stalled already.
+**
+** OUTPUT:
+**
+** gckCOMMAND Command
+** gckCOMMAND object has been updated with a new command queue.
+*/
+static gceSTATUS
+_NewQueue(
+ IN OUT gckCOMMAND Command,
+ IN gctBOOL Stalled
+ )
+{
+ gceSTATUS status;
+ gctINT currentIndex, newIndex;
+ gctPHYS_ADDR_T physical;
+
+ gcmkHEADER_ARG("Command=0x%x", Command);
+
+ /* Switch to the next command buffer. */
+ currentIndex = Command->index;
+ newIndex = (currentIndex + 1) % gcdCOMMAND_QUEUES;
+
+ /* Wait for availability. */
+#if gcdDUMP_COMMAND
+ gcmkPRINT("@[kernel.waitsignal]");
+#endif
+
+ gcmkONERROR(gckOS_WaitSignal(
+ Command->os,
+ Command->queues[newIndex].signal,
+ gcvFALSE,
+ gcvINFINITE
+ ));
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+ if (newIndex < currentIndex)
+ {
+ Command->wrapCount += 1;
+
+ gcmkTRACE_ZONE_N(
+ gcvLEVEL_INFO, gcvZONE_COMMAND,
+ 2 * 4,
+ "%s(%d): queue array wrapped around.\n",
+ __FUNCTION__, __LINE__
+ );
+ }
+
+ gcmkTRACE_ZONE_N(
+ gcvLEVEL_INFO, gcvZONE_COMMAND,
+ 3 * 4,
+ "%s(%d): total queue wrap arounds %d.\n",
+ __FUNCTION__, __LINE__, Command->wrapCount
+ );
+
+ gcmkTRACE_ZONE_N(
+ gcvLEVEL_INFO, gcvZONE_COMMAND,
+ 3 * 4,
+ "%s(%d): switched to queue %d.\n",
+ __FUNCTION__, __LINE__, newIndex
+ );
+#endif
+
+ /* Update gckCOMMAND object with new command queue. */
+ Command->index = newIndex;
+ Command->newQueue = gcvTRUE;
+ Command->virtualMemory = Command->queues[newIndex].physical;
+ Command->logical = Command->queues[newIndex].logical;
+ Command->address = Command->queues[newIndex].address;
+ Command->offset = 0;
+
+ gcmkONERROR(gckOS_GetPhysicalAddress(
+ Command->os,
+ Command->logical,
+ &physical
+ ));
+
+ gcmkSAFECASTPHYSADDRT(Command->physical, physical);
+
+ if (currentIndex != -1)
+ {
+ if (Stalled)
+ {
+ gckOS_Signal(
+ Command->os,
+ Command->queues[currentIndex].signal,
+ gcvTRUE
+ );
+ }
+ else
+ {
+ /* Mark the command queue as available. */
+ gcmkONERROR(gckEVENT_Signal(
+ Command->kernel->eventObj,
+ Command->queues[currentIndex].signal,
+ gcvKERNEL_COMMAND
+ ));
+ }
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("Command->index=%d", Command->index);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+_IncrementCommitAtom(
+ IN gckCOMMAND Command,
+ IN gctBOOL Increment
+ )
+{
+ gceSTATUS status;
+ gckHARDWARE hardware;
+ gctINT32 atomValue;
+ gctBOOL powerAcquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Command=0x%x", Command);
+
+ /* Extract the gckHARDWARE and gckEVENT objects. */
+ hardware = Command->kernel->hardware;
+ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+ /* Grab the power mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(
+ Command->os, hardware->powerMutex, gcvINFINITE
+ ));
+ powerAcquired = gcvTRUE;
+
+ /* Increment the commit atom. */
+ if (Increment)
+ {
+ gcmkONERROR(gckOS_AtomIncrement(
+ Command->os, Command->atomCommit, &atomValue
+ ));
+ }
+ else
+ {
+ gcmkONERROR(gckOS_AtomDecrement(
+ Command->os, Command->atomCommit, &atomValue
+ ));
+ }
+
+ /* Release the power mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(
+ Command->os, hardware->powerMutex
+ ));
+ powerAcquired = gcvFALSE;
+
+ /* Success. */
+ gcmkFOOTER();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (powerAcquired)
+ {
+ /* Release the power mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(
+ Command->os, hardware->powerMutex
+ ));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+#if gcdSECURE_USER
+static gceSTATUS
+_ProcessHints(
+ IN gckCOMMAND Command,
+ IN gctUINT32 ProcessID,
+ IN gcoCMDBUF CommandBuffer
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+ gckKERNEL kernel;
+ gctBOOL needCopy = gcvFALSE;
+ gcskSECURE_CACHE_PTR cache;
+ gctUINT8_PTR commandBufferLogical;
+ gctUINT8_PTR hintedData;
+ gctUINT32_PTR hintArray;
+ gctUINT i, hintCount;
+
+ gcmkHEADER_ARG(
+ "Command=0x%08X ProcessID=%d CommandBuffer=0x%08X",
+ Command, ProcessID, CommandBuffer
+ );
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ /* Reset state array pointer. */
+ hintArray = gcvNULL;
+
+ /* Get the kernel object. */
+ kernel = Command->kernel;
+
+ /* Get the cache form the database. */
+ gcmkONERROR(gckKERNEL_GetProcessDBCache(kernel, ProcessID, &cache));
+
+ /* Determine the start of the command buffer. */
+ commandBufferLogical
+ = (gctUINT8_PTR) CommandBuffer->logical
+ + CommandBuffer->startOffset;
+
+ /* Determine the number of records in the state array. */
+ hintCount = CommandBuffer->hintArrayTail - CommandBuffer->hintArray;
+
+ /* Check wehther we need to copy the structures or not. */
+ gcmkONERROR(gckOS_QueryNeedCopy(Command->os, ProcessID, &needCopy));
+
+ /* Get access to the state array. */
+ if (needCopy)
+ {
+ gctUINT copySize;
+
+ if (Command->hintArrayAllocated &&
+ (Command->hintArraySize < CommandBuffer->hintArraySize))
+ {
+ gcmkONERROR(gcmkOS_SAFE_FREE(Command->os, gcmUINT64_TO_PTR(Command->hintArray)));
+ Command->hintArraySize = gcvFALSE;
+ }
+
+ if (!Command->hintArrayAllocated)
+ {
+ gctPOINTER pointer = gcvNULL;
+
+ gcmkONERROR(gckOS_Allocate(
+ Command->os,
+ CommandBuffer->hintArraySize,
+ &pointer
+ ));
+
+ Command->hintArray = gcmPTR_TO_UINT64(pointer);
+ Command->hintArrayAllocated = gcvTRUE;
+ Command->hintArraySize = CommandBuffer->hintArraySize;
+ }
+
+ hintArray = gcmUINT64_TO_PTR(Command->hintArray);
+ copySize = hintCount * gcmSIZEOF(gctUINT32);
+
+ gcmkONERROR(gckOS_CopyFromUserData(
+ Command->os,
+ hintArray,
+ gcmUINT64_TO_PTR(CommandBuffer->hintArray),
+ copySize
+ ));
+ }
+ else
+ {
+ gctPOINTER pointer = gcvNULL;
+
+ gcmkONERROR(gckOS_MapUserPointer(
+ Command->os,
+ gcmUINT64_TO_PTR(CommandBuffer->hintArray),
+ CommandBuffer->hintArraySize,
+ &pointer
+ ));
+
+ hintArray = pointer;
+ }
+
+ /* Scan through the buffer. */
+ for (i = 0; i < hintCount; i += 1)
+ {
+ /* Determine the location of the hinted data. */
+ hintedData = commandBufferLogical + hintArray[i];
+
+ /* Map handle into physical address. */
+ gcmkONERROR(gckKERNEL_MapLogicalToPhysical(
+ kernel, cache, (gctPOINTER) hintedData
+ ));
+ }
+
+OnError:
+ /* Get access to the state array. */
+ if (!needCopy && (hintArray != gcvNULL))
+ {
+ gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+ Command->os,
+ gcmUINT64_TO_PTR(CommandBuffer->hintArray),
+ CommandBuffer->hintArraySize,
+ hintArray
+ ));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+#endif
+
+#if !gcdNULL_DRIVER
+static gceSTATUS
+_FlushMMU(
+ IN gckCOMMAND Command
+ )
+{
+#if gcdSECURITY
+ return gcvSTATUS_OK;
+#else
+ gceSTATUS status;
+ gctUINT32 oldValue;
+ gckHARDWARE hardware = Command->kernel->hardware;
+ gctBOOL pause = gcvFALSE;
+
+ gctUINT8_PTR pointer;
+ gctUINT32 address;
+ gctUINT32 eventBytes;
+ gctUINT32 endBytes;
+ gctUINT32 bufferSize;
+ gctUINT32 executeBytes;
+ gctUINT32 waitLinkBytes;
+
+ gcmkONERROR(gckOS_AtomicExchange(Command->os,
+ hardware->pageTableDirty[gcvENGINE_RENDER],
+ 0,
+ &oldValue));
+
+ if (oldValue)
+ {
+ /* Page Table is upated, flush mmu before commit. */
+ gcmkONERROR(gckHARDWARE_FlushMMU(hardware));
+
+ if ((oldValue & gcvPAGE_TABLE_DIRTY_BIT_FE)
+ && (!hardware->stallFEPrefetch)
+ )
+ {
+ pause = gcvTRUE;
+ }
+ }
+
+ if (pause)
+ {
+ /* Query size. */
+ gcmkONERROR(gckHARDWARE_Event(hardware, gcvNULL, 0, gcvKERNEL_PIXEL, &eventBytes));
+ gcmkONERROR(gckHARDWARE_End(hardware, gcvNULL, ~0U, &endBytes));
+
+ executeBytes = eventBytes + endBytes;
+
+ gcmkONERROR(gckHARDWARE_WaitLink(
+ hardware,
+ gcvNULL,
+ ~0U,
+ Command->offset + executeBytes,
+ &waitLinkBytes,
+ gcvNULL,
+ gcvNULL
+ ));
+
+ /* Reserve space. */
+ gcmkONERROR(gckCOMMAND_Reserve(
+ Command,
+ executeBytes,
+ (gctPOINTER *)&pointer,
+ &bufferSize
+ ));
+
+ /* Pointer to reserved address. */
+ address = Command->address + Command->offset;
+
+ /* Append EVENT(29). */
+ gcmkONERROR(gckHARDWARE_Event(
+ hardware,
+ pointer,
+ 29,
+ gcvKERNEL_PIXEL,
+ &eventBytes
+ ));
+
+ /* Append END. */
+ pointer += eventBytes;
+ address += eventBytes;
+
+ gcmkONERROR(gckHARDWARE_End(hardware, pointer, address, &endBytes));
+
+#if USE_KERNEL_VIRTUAL_BUFFERS
+ if (hardware->kernel->virtualCommandBuffer)
+ {
+ gcmkONERROR(gckKERNEL_GetGPUAddress(
+ hardware->kernel,
+ pointer,
+ gcvFALSE,
+ Command->virtualMemory,
+ &hardware->lastEnd
+ ));
+ }
+#endif
+
+ gcmkONERROR(gckCOMMAND_Execute(Command, executeBytes));
+ }
+
+ return gcvSTATUS_OK;
+OnError:
+ return status;
+#endif
+}
+
+static gceSTATUS
+_DummyDraw(
+ IN gckCOMMAND Command
+ )
+{
+#if gcdSECURITY
+ return gcvSTATUS_OK;
+#else
+ gceSTATUS status;
+ gckHARDWARE hardware = Command->kernel->hardware;
+
+ gctUINT8_PTR pointer;
+ gctUINT32 bufferSize;
+
+ gctUINT32 dummyDrawBytes;
+ gceDUMMY_DRAW_TYPE dummyDrawType = gcvDUMMY_DRAW_INVALID;
+
+ if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_FE_NEED_DUMMYDRAW))
+ {
+ dummyDrawType = gcvDUMMY_DRAW_GC400;
+ }
+
+ if (!gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_USC_DEFER_FILL_FIX) &&
+ gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_USC))
+ {
+ dummyDrawType = gcvDUMMY_DRAW_V60;
+ }
+
+ if (dummyDrawType != gcvDUMMY_DRAW_INVALID)
+ {
+ gckHARDWARE_DummyDraw(hardware, gcvNULL, Command->queues[0].address, dummyDrawType, &dummyDrawBytes);
+
+ /* Reserve space. */
+ gcmkONERROR(gckCOMMAND_Reserve(
+ Command,
+ dummyDrawBytes,
+ (gctPOINTER *)&pointer,
+ &bufferSize
+ ));
+
+ gckHARDWARE_DummyDraw(hardware, pointer, Command->queues[0].address, dummyDrawType, &dummyDrawBytes);
+
+ gcmkONERROR(gckCOMMAND_Execute(Command, dummyDrawBytes));
+ }
+
+ return gcvSTATUS_OK;
+OnError:
+ return status;
+#endif
+}
+
+#endif
+
+static void
+_DumpBuffer(
+ IN gctPOINTER Buffer,
+ IN gctUINT32 GpuAddress,
+ IN gctSIZE_T Size
+ )
+{
+ gctSIZE_T i, line, left;
+ gctUINT32_PTR data = Buffer;
+
+ line = Size / 32;
+ left = Size % 32;
+
+ for (i = 0; i < line; i++)
+ {
+ gcmkPRINT("%08X : %08X %08X %08X %08X %08X %08X %08X %08X",
+ GpuAddress, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
+ data += 8;
+ GpuAddress += 8 * 4;
+ }
+
+ switch(left)
+ {
+ case 28:
+ gcmkPRINT("%08X : %08X %08X %08X %08X %08X %08X %08X",
+ GpuAddress, data[0], data[1], data[2], data[3], data[4], data[5], data[6]);
+ break;
+ case 24:
+ gcmkPRINT("%08X : %08X %08X %08X %08X %08X %08X",
+ GpuAddress, data[0], data[1], data[2], data[3], data[4], data[5]);
+ break;
+ case 20:
+ gcmkPRINT("%08X : %08X %08X %08X %08X %08X",
+ GpuAddress, data[0], data[1], data[2], data[3], data[4]);
+ break;
+ case 16:
+ gcmkPRINT("%08X : %08X %08X %08X %08X",
+ GpuAddress, data[0], data[1], data[2], data[3]);
+ break;
+ case 12:
+ gcmkPRINT("%08X : %08X %08X %08X",
+ GpuAddress, data[0], data[1], data[2]);
+ break;
+ case 8:
+ gcmkPRINT("%08X : %08X %08X",
+ GpuAddress, data[0], data[1]);
+ break;
+ case 4:
+ gcmkPRINT("%08X : %08X",
+ GpuAddress, data[0]);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+_DumpKernelCommandBuffer(
+ IN gckCOMMAND Command
+ )
+{
+ gctINT i;
+ gctUINT64 physical = 0;
+ gctUINT32 address;
+ gctPOINTER entry = gcvNULL;
+
+ for (i = 0; i < gcdCOMMAND_QUEUES; i++)
+ {
+ entry = Command->queues[i].logical;
+
+ gckOS_GetPhysicalAddress(Command->os, entry, &physical);
+
+ gcmkPRINT("Kernel command buffer %d\n", i);
+
+ gcmkSAFECASTPHYSADDRT(address, physical);
+
+ _DumpBuffer(entry, address, Command->pageSize);
+ }
+}
+
+#if !gcdNULL_DRIVER
+static gceSTATUS
+_HandlePatchList(
+ IN gckCOMMAND Command,
+ IN gcoCMDBUF CommandBuffer,
+ IN gctBOOL NeedCopy,
+ OUT gctUINT64 *AsyncCommandStamp
+ )
+{
+ gceSTATUS status;
+ gcsPATCH_LIST * uList;
+ gcsPATCH_LIST * previous;
+ gcsPATCH_LIST * kList;
+ gctUINT64 asyncStamp = 0;
+
+ gcmkHEADER_ARG(
+ "Command=0x%x CommandBuffer=0x%x NeedCopy=%d",
+ Command, CommandBuffer, NeedCopy
+ );
+
+ uList = gcmUINT64_TO_PTR(CommandBuffer->patchHead);
+
+ while (uList)
+ {
+ gctUINT i;
+
+ kList = gcvNULL;
+ previous = uList;
+
+ gcmkONERROR(gckKERNEL_OpenUserData(
+ Command->kernel,
+ NeedCopy,
+ Command->kList,
+ uList,
+ gcmSIZEOF(gcsPATCH_LIST),
+ (gctPOINTER *)&kList
+ ));
+
+ for (i = 0; i < kList->count; i++)
+ {
+ gctUINT64 stamp = 0;
+ gcsPATCH * patch = &kList->patch[i];
+
+ /* Touch video memory node. */
+ gcmkVERIFY_OK(gckVIDMEM_SetCommitStamp(Command->kernel, gcvENGINE_RENDER, patch->handle, Command->commitStamp));
+
+ /* Get stamp touched async command buffer. */
+ gcmkVERIFY_OK(gckVIDMEM_GetCommitStamp(Command->kernel, gcvENGINE_BLT, patch->handle, &stamp));
+
+ /* Find latest one. */
+ asyncStamp = gcmMAX(asyncStamp, stamp);
+ }
+
+ uList = kList->next;
+
+ gcmkVERIFY_OK(gckKERNEL_CloseUserData(
+ Command->kernel,
+ NeedCopy,
+ gcvFALSE,
+ previous,
+ gcmSIZEOF(gcsPATCH_LIST),
+ (gctPOINTER *)&kList
+ ));
+ }
+
+ if ((Command->asyncCommand != gcvNULL)
+ && (*(gctUINT64 *)Command->asyncCommand->fence->logical > asyncStamp)
+ )
+ {
+ /* No need to wait for async command buffer. */
+ *AsyncCommandStamp = 0;
+ }
+ else
+ {
+ /* Need to add a fence wait. */
+ *AsyncCommandStamp = asyncStamp;
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (kList)
+ {
+ gcmkVERIFY_OK(gckKERNEL_CloseUserData(
+ Command->kernel,
+ NeedCopy,
+ gcvFALSE,
+ previous,
+ gcmSIZEOF(gcsPATCH_LIST),
+ (gctPOINTER *)&kList
+ ));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+_WaitForAsyncCommandStamp(
+ IN gckCOMMAND Command,
+ IN gctUINT64 Stamp
+ )
+{
+ gctUINT32 bytes;
+ gceSTATUS status;
+ gctUINT32 fenceAddress;
+ gctUINT32 bufferSize;
+ gctPOINTER pointer;
+ gcmkHEADER_ARG("Stamp = 0x%llx", Stamp);
+
+ fenceAddress = Command->asyncCommand->fence->address;
+
+ gcmkONERROR(gckHARDWARE_WaitFence(Command->kernel->hardware,
+ gcvNULL,
+ Stamp,
+ fenceAddress,
+ &bytes
+ ));
+
+ gcmkONERROR(gckCOMMAND_Reserve(
+ Command,
+ bytes,
+ &pointer,
+ &bufferSize
+ ));
+
+ gcmkONERROR(gckHARDWARE_WaitFence(
+ Command->kernel->hardware,
+ pointer,
+ Stamp,
+ fenceAddress,
+ &bytes
+ ));
+
+ gcmkONERROR(gckCOMMAND_Execute(Command, bytes));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+/******************************************************************************\
+**************** Helper functions for parsing gcoCMDBUF ************************
+\******************************************************************************/
+static void
+_GetCMDBUFSize(
+ IN gcoCMDBUF CommandBuffer,
+ OUT gctUINT_PTR CommandBufferSize
+ )
+{
+ *CommandBufferSize
+ = CommandBuffer->offset
+ + CommandBuffer->reservedTail
+ - CommandBuffer->startOffset;
+}
+
+static void
+_GetCMDBUFTail(
+ IN gcoCMDBUF CommandBuffer,
+ OUT gctUINT8_PTR * Tail
+ )
+{
+ gctUINT8_PTR commandBufferLogical;
+ gctUINT commandBufferSize;
+
+ commandBufferLogical
+ = (gctUINT8_PTR) gcmUINT64_TO_PTR(CommandBuffer->logical)
+ + CommandBuffer->startOffset;
+
+ _GetCMDBUFSize(CommandBuffer, &commandBufferSize);
+
+ *Tail
+ = commandBufferLogical
+ + commandBufferSize
+ - CommandBuffer->reservedTail;
+}
+
+static void
+_ParseCMDBUFTail(
+ IN gckHARDWARE Hardware,
+ IN gcoCMDBUF CommandBuffer,
+ OUT gctUINT8_PTR * Fence,
+ OUT gctUINT8_PTR * Link
+ )
+{
+ gctUINT8_PTR tail;
+
+ _GetCMDBUFTail(CommandBuffer, &tail);
+
+ if (gckHARDWARE_IsFeatureAvailable(Hardware, gcvFEATURE_FENCE_64BIT))
+ {
+ *Fence = tail;
+ *Link = tail + gcdRENDER_FENCE_LENGTH;
+ }
+ else
+ {
+ *Fence = gcvNULL;
+ *Link = tail;
+ }
+}
+
+static gceSTATUS
+_GetCMDBUFEntry(
+ IN gckCOMMAND Command,
+ IN gcoCMDBUF CommandBuffer,
+ OUT gctUINT32_PTR EntryAddress,
+ OUT gctUINT32_PTR EntryBytes
+ )
+{
+ gceSTATUS status;
+ gctUINT8_PTR commandBufferLogical;
+ gctUINT commandBufferSize;
+ gckVIRTUAL_COMMAND_BUFFER_PTR virtualCommandBuffer;
+ gctUINT32 commandBufferAddress;
+ gctUINT offset;
+
+ commandBufferLogical
+ = (gctUINT8_PTR) gcmUINT64_TO_PTR(CommandBuffer->logical)
+ + CommandBuffer->startOffset;
+
+ /* Get the hardware address. */
+ if (Command->kernel->virtualCommandBuffer)
+ {
+ gckKERNEL kernel = Command->kernel;
+
+ virtualCommandBuffer = gcmNAME_TO_PTR(CommandBuffer->physical);
+
+ if (virtualCommandBuffer == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gcmkONERROR(gckKERNEL_GetGPUAddress(
+ Command->kernel,
+ commandBufferLogical,
+ gcvTRUE,
+ virtualCommandBuffer,
+ &commandBufferAddress
+ ));
+ }
+ else
+ {
+ gcmkONERROR(gckHARDWARE_ConvertLogical(
+ Command->kernel->hardware,
+ commandBufferLogical,
+ gcvTRUE,
+ &commandBufferAddress
+ ));
+ }
+
+ /* Get offset. */
+ gcmkONERROR(gckHARDWARE_PipeSelect(
+ Command->kernel->hardware, gcvNULL, gcvPIPE_3D, &offset
+ ));
+
+ _GetCMDBUFSize(CommandBuffer, &commandBufferSize);
+
+ *EntryAddress = commandBufferAddress + offset;
+ *EntryBytes = commandBufferSize - offset;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+/*******************************************************************************
+**
+** Link a list of command buffer together to make them atomic.
+** Fence will be added in the last command buffer.
+*/
+static gceSTATUS
+_ProcessUserCommandBufferList(
+ IN gckCOMMAND Command,
+ IN gcoCMDBUF CommandBufferListHead,
+ OUT gcoCMDBUF * CommandBufferListTail
+ )
+{
+ gceSTATUS status;
+ gctBOOL needCopy;
+
+ struct _gcoCMDBUF _commandBufferObject;
+ gcoCMDBUF currentCMDBUF;
+ struct _gcoCMDBUF _nextCMDBUF;
+ gcoCMDBUF currentCMDBUFUser = CommandBufferListHead;
+
+ gckOS_QueryNeedCopy(Command->os, 0, &needCopy);
+
+ /* Open first gcoCMDBUF object as currentCMDBUF. */
+ gcmkONERROR(gckKERNEL_OpenUserData(
+ Command->kernel,
+ needCopy,
+ &_commandBufferObject,
+ currentCMDBUFUser,
+ gcmSIZEOF(struct _gcoCMDBUF),
+ (gctPOINTER *)&currentCMDBUF
+ ));
+
+ /* Iterate the list. */
+ while (currentCMDBUF->nextCMDBUF != 0)
+ {
+ gcoCMDBUF nextCMDBUFUser;
+ gcoCMDBUF nextCMDBUF;
+ gctUINT8_PTR fenceLogical = gcvNULL;
+ gctUINT8_PTR linkLogical;
+ gctUINT32 linkBytes = 8;
+ gctUINT32 linkLow;
+ gctUINT32 linkHigh;
+
+ gctUINT32 entryAddress = 0;
+ gctUINT32 entryBytes = 0;
+
+ nextCMDBUFUser
+ = gcmUINT64_TO_PTR(currentCMDBUF->nextCMDBUF);
+
+ /* Open next gcoCMDBUF object as nextCMDBUF. */
+ gcmkONERROR(gckKERNEL_OpenUserData(
+ Command->kernel,
+ needCopy,
+ &_nextCMDBUF,
+ nextCMDBUFUser,
+ gcmSIZEOF(struct _gcoCMDBUF),
+ (gctPOINTER *)&nextCMDBUF
+ ));
+
+ /* Get the start hardware address of nextCMDBUF. */
+ gcmkONERROR(_GetCMDBUFEntry(Command,
+ nextCMDBUF,
+ &entryAddress,
+ &entryBytes
+ ));
+
+ /* Process current gcoCMDBUF object. */
+ _ParseCMDBUFTail(
+ Command->kernel->hardware,
+ currentCMDBUF,
+ &fenceLogical,
+ &linkLogical
+ );
+
+ /* Don't send fence in the middle of gcoCMDBUF list. */
+ if (fenceLogical != gcvNULL)
+ {
+ gctUINT i = gcdRENDER_FENCE_LENGTH / gcmSIZEOF(gctUINT32) / 2;
+
+ /* Fill NOPs in space reserved for fence. */
+ while (i--)
+ {
+ gctSIZE_T nopBytes = 8;
+ gcmkONERROR(gckHARDWARE_Nop(Command->kernel->hardware, fenceLogical, &nopBytes));
+ fenceLogical += nopBytes;
+ }
+ }
+
+ /* Generate a LINK from the end of current command buffer
+ ** to the start of next command buffer. */
+ gcmkONERROR(gckHARDWARE_Link(
+ Command->kernel->hardware,
+ linkLogical,
+ entryAddress,
+ entryBytes,
+ &linkBytes,
+ &linkLow,
+ &linkHigh
+ ));
+
+ /* Close current gcoCMDBUF object which is processed. */
+ gcmkVERIFY_OK(gckKERNEL_CloseUserData(
+ Command->kernel,
+ needCopy,
+ gcvFALSE,
+ currentCMDBUFUser,
+ gcmSIZEOF(struct _gcoCMDBUF),
+ (gctPOINTER *)&currentCMDBUF
+ ));
+
+ /* Advance to next gcoCMDBUF object. */
+ currentCMDBUFUser = nextCMDBUFUser;
+ currentCMDBUF = nextCMDBUF;
+ }
+
+ gcmkVERIFY_OK(gckKERNEL_CloseUserData(
+ Command->kernel,
+ needCopy,
+ gcvFALSE,
+ currentCMDBUFUser,
+ gcmSIZEOF(struct _gcoCMDBUF),
+ (gctPOINTER *)&currentCMDBUF
+ ));
+
+ /* Return the tail of the list. */
+ *CommandBufferListTail = currentCMDBUFUser;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+#endif
+
+/******************************************************************************\
+****************************** gckCOMMAND API Code ******************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+** gckCOMMAND_Construct
+**
+** Construct a new gckCOMMAND object.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** OUTPUT:
+**
+** gckCOMMAND * Command
+** Pointer to a variable that will hold the pointer to the gckCOMMAND
+** object.
+*/
+gceSTATUS
+gckCOMMAND_Construct(
+ IN gckKERNEL Kernel,
+ OUT gckCOMMAND * Command
+ )
+{
+ gckOS os;
+ gckCOMMAND command = gcvNULL;
+ gceSTATUS status;
+ gctINT i;
+ gctPOINTER pointer = gcvNULL;
+ gctSIZE_T pageSize;
+
+ gcmkHEADER_ARG("Kernel=0x%x", Kernel);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Command != gcvNULL);
+
+ /* Extract the gckOS object. */
+ os = Kernel->os;
+
+ /* Allocate the gckCOMMAND structure. */
+ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckCOMMAND), &pointer));
+ command = pointer;
+
+ /* Reset the entire object. */
+ gcmkONERROR(gckOS_ZeroMemory(command, gcmSIZEOF(struct _gckCOMMAND)));
+
+ /* Initialize the gckCOMMAND object.*/
+ command->object.type = gcvOBJ_COMMAND;
+ command->kernel = Kernel;
+ command->os = os;
+
+ /* Get the command buffer requirements. */
+ gcmkONERROR(gckHARDWARE_QueryCommandBuffer(
+ Kernel->hardware,
+ gcvENGINE_RENDER,
+ &command->alignment,
+ &command->reservedHead,
+ gcvNULL
+ ));
+
+ /* Create the command queue mutex. */
+ gcmkONERROR(gckOS_CreateMutex(os, &command->mutexQueue));
+
+ /* Create the context switching mutex. */
+ gcmkONERROR(gckOS_CreateMutex(os, &command->mutexContext));
+
+ /* Create the context switching mutex. */
+ gcmkONERROR(gckOS_CreateMutex(os, &command->mutexContextSeq));
+
+ /* Create the power management semaphore. */
+ gcmkONERROR(gckOS_CreateSemaphore(os, &command->powerSemaphore));
+
+ /* Create the commit atom. */
+ gcmkONERROR(gckOS_AtomConstruct(os, &command->atomCommit));
+
+ /* Get the page size from teh OS. */
+ gcmkONERROR(gckOS_GetPageSize(os, &pageSize));
+
+ gcmkSAFECASTSIZET(command->pageSize, pageSize);
+
+ /* Get process ID. */
+ gcmkONERROR(gckOS_GetProcessID(&command->kernelProcessID));
+
+ /* Set hardware to pipe 0. */
+ command->pipeSelect = gcvPIPE_INVALID;
+
+ /* Pre-allocate the command queues. */
+ for (i = 0; i < gcdCOMMAND_QUEUES; ++i)
+ {
+#if USE_KERNEL_VIRTUAL_BUFFERS
+ if (Kernel->virtualCommandBuffer)
+ {
+ gcmkONERROR(gckKERNEL_AllocateVirtualCommandBuffer(
+ Kernel,
+ gcvFALSE,
+ &pageSize,
+ &command->queues[i].physical,
+ &command->queues[i].logical
+ ));
+
+ gcmkONERROR(gckKERNEL_GetGPUAddress(
+ Kernel,
+ command->queues[i].logical,
+ gcvFALSE,
+ command->queues[i].physical,
+ &command->queues[i].address
+ ));
+ }
+ else
+#endif
+ {
+ gcmkONERROR(gckOS_AllocateNonPagedMemory(
+ os,
+ gcvFALSE,
+ &pageSize,
+ &command->queues[i].physical,
+ &command->queues[i].logical
+ ));
+
+ gcmkONERROR(gckHARDWARE_ConvertLogical(
+ Kernel->hardware,
+ command->queues[i].logical,
+ gcvFALSE,
+ &command->queues[i].address
+ ));
+
+ gcmkONERROR(gckMMU_FillFlatMapping(
+ Kernel->mmu, command->queues[i].address, pageSize
+ ));
+ }
+
+ gcmkONERROR(gckOS_CreateSignal(
+ os, gcvFALSE, &command->queues[i].signal
+ ));
+
+ gcmkONERROR(gckOS_Signal(
+ os, command->queues[i].signal, gcvTRUE
+ ));
+ }
+
+#if gcdRECORD_COMMAND
+ gcmkONERROR(gckRECORDER_Construct(os, Kernel->hardware, &command->recorder));
+#endif
+
+ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsPATCH_LIST), &command->kList));
+
+ gcmkONERROR(gckFENCE_Create(
+ os, Kernel, &command->fence
+ ));
+
+ /* No command queue in use yet. */
+ command->index = -1;
+ command->logical = gcvNULL;
+ command->newQueue = gcvFALSE;
+
+ /* Command is not yet running. */
+ command->running = gcvFALSE;
+
+ /* Command queue is idle. */
+ command->idle = gcvTRUE;
+
+ /* Commit stamp start from 1. */
+ command->commitStamp = 1;
+
+ /* END event signal not created. */
+ command->endEventSignal = gcvNULL;
+
+ command->dummyDraw = gcvTRUE;
+
+ /* Return pointer to the gckCOMMAND object. */
+ *Command = command;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Command=0x%x", *Command);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Roll back. */
+ if (command != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckCOMMAND_Destroy(command));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckCOMMAND_Destroy
+**
+** Destroy an gckCOMMAND object.
+**
+** INPUT:
+**
+** gckCOMMAND Command
+** Pointer to an gckCOMMAND object to destroy.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckCOMMAND_Destroy(
+ IN gckCOMMAND Command
+ )
+{
+ gctINT i;
+
+ gcmkHEADER_ARG("Command=0x%x", Command);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ /* Stop the command queue. */
+ gcmkVERIFY_OK(gckCOMMAND_Stop(Command));
+
+ for (i = 0; i < gcdCOMMAND_QUEUES; ++i)
+ {
+ if (Command->queues[i].signal)
+ {
+ gcmkVERIFY_OK(gckOS_DestroySignal(
+ Command->os, Command->queues[i].signal
+ ));
+ }
+
+ if (Command->queues[i].logical)
+ {
+#if USE_KERNEL_VIRTUAL_BUFFERS
+ if (Command->kernel->virtualCommandBuffer)
+ {
+ gcmkVERIFY_OK(gckKERNEL_DestroyVirtualCommandBuffer(
+ Command->kernel,
+ Command->pageSize,
+ Command->queues[i].physical,
+ Command->queues[i].logical
+ ));
+ }
+ else
+#endif
+ {
+ gcmkVERIFY_OK(gckOS_FreeNonPagedMemory(
+ Command->os,
+ Command->pageSize,
+ Command->queues[i].physical,
+ Command->queues[i].logical
+ ));
+ }
+ }
+ }
+
+ /* END event signal. */
+ if (Command->endEventSignal != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_DestroySignal(
+ Command->os, Command->endEventSignal
+ ));
+ }
+
+ if (Command->mutexContext)
+ {
+ /* Delete the context switching mutex. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexContext));
+ }
+
+ if (Command->mutexContextSeq != gcvNULL)
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexContextSeq));
+
+ if (Command->mutexQueue)
+ {
+ /* Delete the command queue mutex. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexQueue));
+ }
+
+ if (Command->powerSemaphore)
+ {
+ /* Destroy the power management semaphore. */
+ gcmkVERIFY_OK(gckOS_DestroySemaphore(Command->os, Command->powerSemaphore));
+ }
+
+ if (Command->atomCommit)
+ {
+ /* Destroy the commit atom. */
+ gcmkVERIFY_OK(gckOS_AtomDestroy(Command->os, Command->atomCommit));
+ }
+
+#if gcdSECURE_USER
+ /* Free state array. */
+ if (Command->hintArrayAllocated)
+ {
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Command->os, gcmUINT64_TO_PTR(Command->hintArray)));
+ Command->hintArrayAllocated = gcvFALSE;
+ }
+#endif
+
+#if gcdRECORD_COMMAND
+ gckRECORDER_Destory(Command->os, Command->recorder);
+#endif
+
+ if (Command->stateMap)
+ {
+ gcmkOS_SAFE_FREE(Command->os, Command->stateMap);
+ }
+
+ if (Command->kList)
+ {
+ gcmkOS_SAFE_FREE(Command->os, Command->kList);
+ }
+
+ if (Command->fence)
+ {
+ gcmkVERIFY_OK(gckFENCE_Destory(Command->os, Command->fence));
+ }
+
+ /* Mark object as unknown. */
+ Command->object.type = gcvOBJ_UNKNOWN;
+
+ /* Free the gckCOMMAND object. */
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Command->os, Command));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckCOMMAND_EnterCommit
+**
+** Acquire command queue synchronization objects.
+**
+** INPUT:
+**
+** gckCOMMAND Command
+** Pointer to an gckCOMMAND object to destroy.
+**
+** gctBOOL FromPower
+** Determines whether the call originates from inside the power
+** management or not.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckCOMMAND_EnterCommit(
+ IN gckCOMMAND Command,
+ IN gctBOOL FromPower
+ )
+{
+ gceSTATUS status;
+ gckHARDWARE hardware;
+ gctBOOL atomIncremented = gcvFALSE;
+ gctBOOL semaAcquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Command=0x%x", Command);
+
+ /* Extract the gckHARDWARE and gckEVENT objects. */
+ hardware = Command->kernel->hardware;
+ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+ if (!FromPower)
+ {
+ /* Increment COMMIT atom to let power management know that a commit is
+ ** in progress. */
+ gcmkONERROR(_IncrementCommitAtom(Command, gcvTRUE));
+ atomIncremented = gcvTRUE;
+
+ /* Notify the system the GPU has a commit. */
+ gcmkONERROR(gckOS_Broadcast(Command->os,
+ hardware,
+ gcvBROADCAST_GPU_COMMIT));
+
+ /* Acquire the power management semaphore. */
+ gcmkONERROR(gckOS_AcquireSemaphore(Command->os,
+ Command->powerSemaphore));
+ semaAcquired = gcvTRUE;
+ }
+
+ /* Grab the conmmand queue mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Command->os,
+ Command->mutexQueue,
+ gcvINFINITE));
+
+ /* Success. */
+ gcmkFOOTER();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (semaAcquired)
+ {
+ /* Release the power management semaphore. */
+ gcmkVERIFY_OK(gckOS_ReleaseSemaphore(
+ Command->os, Command->powerSemaphore
+ ));
+ }
+
+ if (atomIncremented)
+ {
+ /* Decrement the commit atom. */
+ gcmkVERIFY_OK(_IncrementCommitAtom(
+ Command, gcvFALSE
+ ));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckCOMMAND_ExitCommit
+**
+** Release command queue synchronization objects.
+**
+** INPUT:
+**
+** gckCOMMAND Command
+** Pointer to an gckCOMMAND object to destroy.
+**
+** gctBOOL FromPower
+** Determines whether the call originates from inside the power
+** management or not.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckCOMMAND_ExitCommit(
+ IN gckCOMMAND Command,
+ IN gctBOOL FromPower
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Command=0x%x", Command);
+
+ /* Release the power mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexQueue));
+
+ if (!FromPower)
+ {
+ /* Release the power management semaphore. */
+ gcmkONERROR(gckOS_ReleaseSemaphore(Command->os,
+ Command->powerSemaphore));
+
+ /* Decrement the commit atom. */
+ gcmkONERROR(_IncrementCommitAtom(Command, gcvFALSE));
+ }
+
+ /* Success. */
+ gcmkFOOTER();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckCOMMAND_Start
+**
+** Start up the command queue.
+**
+** INPUT:
+**
+** gckCOMMAND Command
+** Pointer to an gckCOMMAND object to start.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckCOMMAND_Start(
+ IN gckCOMMAND Command
+ )
+{
+ gceSTATUS status;
+ gckHARDWARE hardware;
+ gctUINT32 waitOffset = 0;
+ gctUINT32 waitLinkBytes;
+ gctPOINTER logical;
+ gctUINT32 physical;
+ gctUINT32 address;
+
+ gcmkHEADER_ARG("Command=0x%x", Command);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ if (Command->running)
+ {
+ /* Command queue already running. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+ /* Extract the gckHARDWARE object. */
+ hardware = Command->kernel->hardware;
+ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+ /* Query the size of WAIT/LINK command sequence. */
+ gcmkONERROR(gckHARDWARE_WaitLink(
+ hardware,
+ gcvNULL,
+ ~0U,
+ Command->offset,
+ &waitLinkBytes,
+ gcvNULL,
+ gcvNULL
+ ));
+
+ if ((Command->pageSize - Command->offset < waitLinkBytes)
+ || (Command->logical == gcvNULL)
+ )
+ {
+ /* Start at beginning of a new queue. */
+ gcmkONERROR(_NewQueue(Command, gcvTRUE));
+ }
+
+ logical = (gctUINT8_PTR) Command->logical + Command->offset;
+ physical = Command->physical + Command->offset;
+ address = Command->address + Command->offset;
+
+ /* Append WAIT/LINK. */
+ gcmkONERROR(gckHARDWARE_WaitLink(
+ hardware,
+ logical,
+ address,
+ 0,
+ &waitLinkBytes,
+ &waitOffset,
+ &Command->waitSize
+ ));
+
+ Command->waitLogical = (gctUINT8_PTR) logical + waitOffset;
+ Command->waitPhysical = physical + waitOffset;
+ Command->waitAddress = address + waitOffset;
+
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ /* Flush the cache for the wait/link. */
+ gcmkONERROR(gckOS_CacheClean(
+ Command->os,
+ Command->kernelProcessID,
+ gcvNULL,
+ physical,
+ logical,
+ waitLinkBytes
+ ));
+#endif
+
+ /* Adjust offset. */
+ Command->offset += waitLinkBytes;
+ Command->newQueue = gcvFALSE;
+
+#if gcdSECURITY
+ /* Start FE by calling security service. */
+ gckKERNEL_SecurityStartCommand(
+ Command->kernel
+ );
+#else
+ /* Enable command processor. */
+ gcmkONERROR(gckHARDWARE_Execute(
+ hardware,
+ address,
+ waitLinkBytes
+ ));
+#endif
+
+ /* Command queue is running. */
+ Command->running = gcvTRUE;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckCOMMAND_Stop
+**
+** Stop the command queue.
+**
+** INPUT:
+**
+** gckCOMMAND Command
+** Pointer to an gckCOMMAND object to stop.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckCOMMAND_Stop(
+ IN gckCOMMAND Command
+ )
+{
+ gckHARDWARE hardware;
+ gceSTATUS status;
+ gctUINT32 idle;
+
+ gcmkHEADER_ARG("Command=0x%x", Command);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ if (!Command->running)
+ {
+ /* Command queue is not running. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+ /* Extract the gckHARDWARE object. */
+ hardware = Command->kernel->hardware;
+ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+ if (gckHARDWARE_IsFeatureAvailable(hardware,
+ gcvFEATURE_END_EVENT) == gcvSTATUS_TRUE)
+ {
+ /* Allocate the signal. */
+ if (Command->endEventSignal == gcvNULL)
+ {
+ gcmkONERROR(gckOS_CreateSignal(Command->os,
+ gcvTRUE,
+ &Command->endEventSignal));
+ }
+
+ /* Append the END EVENT command to trigger the signal. */
+ gcmkONERROR(gckEVENT_Stop(Command->kernel->eventObj,
+ Command->kernelProcessID,
+ Command->waitPhysical,
+ Command->waitLogical,
+ Command->waitAddress,
+ Command->endEventSignal,
+ &Command->waitSize));
+ }
+ else
+ {
+ /* Replace last WAIT with END. */
+ gcmkONERROR(gckHARDWARE_End(
+ hardware,
+ Command->waitLogical,
+ Command->waitAddress,
+ &Command->waitSize
+ ));
+
+#if USE_KERNEL_VIRTUAL_BUFFERS
+ if (hardware->kernel->virtualCommandBuffer)
+ {
+ gcmkONERROR(gckKERNEL_GetGPUAddress(
+ hardware->kernel,
+ Command->waitLogical,
+ gcvFALSE,
+ Command->virtualMemory,
+ &hardware->lastEnd
+ ));
+ }
+#endif
+
+#if gcdSECURITY
+ gcmkONERROR(gckKERNEL_SecurityExecute(
+ Command->kernel, Command->waitLogical, 8
+ ));
+#endif
+
+ /* Update queue tail pointer. */
+ gcmkONERROR(gckHARDWARE_UpdateQueueTail(Command->kernel->hardware,
+ Command->logical,
+ Command->offset));
+
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ /* Flush the cache for the END. */
+ gcmkONERROR(gckOS_CacheClean(
+ Command->os,
+ Command->kernelProcessID,
+ gcvNULL,
+ (gctUINT32)Command->waitPhysical,
+ Command->waitLogical,
+ Command->waitSize
+ ));
+#endif
+
+ /* Wait for idle. */
+ gcmkONERROR(gckHARDWARE_GetIdle(hardware, gcvTRUE, &idle));
+ }
+
+ /* Command queue is no longer running. */
+ Command->running = gcvFALSE;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckCOMMAND_Commit
+**
+** Commit a command buffer to the command queue.
+**
+** INPUT:
+**
+** gckCOMMAND Command
+** Pointer to a gckCOMMAND object.
+**
+** gckCONTEXT Context
+** Pointer to a gckCONTEXT object.
+**
+** gcoCMDBUF CommandBuffer
+** Pointer to a gcoCMDBUF object.
+**
+** gcsSTATE_DELTA_PTR StateDelta
+** Pointer to the state delta.
+**
+** gctUINT32 ProcessID
+** Current process ID.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckCOMMAND_Commit(
+ IN gckCOMMAND Command,
+ IN gckCONTEXT Context,
+ IN gcoCMDBUF CommandBuffer,
+ IN gcsSTATE_DELTA_PTR StateDelta,
+ IN gctUINT32 ProcessID,
+ IN gctBOOL Shared,
+ IN gctUINT32 Index,
+ OUT gctUINT64_PTR CommitStamp,
+ OUT gctBOOL_PTR ContextSwitched
+ )
+{
+ gceSTATUS status;
+ gctBOOL commitEntered = gcvFALSE;
+ gctBOOL contextAcquired = gcvFALSE;
+ gckHARDWARE hardware;
+ gctBOOL needCopy = gcvFALSE;
+ gctBOOL commandBufferMapped = gcvFALSE;
+ gcoCMDBUF commandBufferObject = gcvNULL;
+ gctBOOL stall = gcvFALSE;
+ gctBOOL contextSwitched = gcvFALSE;
+
+#if !gcdNULL_DRIVER
+ gcsCONTEXT_PTR contextBuffer;
+ struct _gcoCMDBUF _commandBufferObject;
+ gctPHYS_ADDR_T commandBufferPhysical;
+ gctUINT8_PTR commandBufferLogical = gcvNULL;
+ gctUINT32 commandBufferAddress = 0;
+ gctUINT8_PTR commandBufferTail = gcvNULL;
+ gctUINT commandBufferSize;
+ gctSIZE_T nopBytes;
+ gctUINT32 pipeBytes;
+ gctUINT32 linkBytes;
+ gctSIZE_T bytes;
+ gctUINT32 offset;
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ gctPHYS_ADDR entryPhysical;
+#endif
+ gctPOINTER entryLogical;
+ gctUINT32 entryAddress;
+ gctUINT32 entryBytes;
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ gctPHYS_ADDR exitPhysical;
+ gctPOINTER exitLogical;
+#endif
+ gctUINT32 exitAddress;
+ gctUINT32 exitBytes;
+ gctUINT32 waitLinkPhysical;
+ gctPOINTER waitLinkLogical;
+ gctUINT32 waitLinkAddress;
+ gctUINT32 waitLinkBytes;
+ gctUINT32 waitOffset;
+ gctUINT32 waitSize;
+
+#ifdef __QNXNTO__
+ gctPOINTER userCommandBufferLogical = gcvNULL;
+ gctBOOL userCommandBufferLogicalMapped = gcvFALSE;
+#endif
+
+#if gcdPROCESS_ADDRESS_SPACE
+ gckMMU mmu;
+ gctUINT32 oldValue;
+#endif
+
+#if gcdDUMP_COMMAND
+ gctPOINTER contextDumpLogical = gcvNULL;
+ gctSIZE_T contextDumpBytes = 0;
+ gctPOINTER bufferDumpLogical = gcvNULL;
+ gctSIZE_T bufferDumpBytes = 0;
+# endif
+ gctUINT32 exitLinkLow = 0, exitLinkHigh = 0;
+ gctUINT32 entryLinkLow = 0, entryLinkHigh = 0;
+ gctUINT32 commandLinkLow = 0, commandLinkHigh = 0;
+
+ gckVIRTUAL_COMMAND_BUFFER_PTR virtualCommandBuffer = gcvNULL;
+ gctUINT64 asyncCommandStamp = 0;
+ gcoCMDBUF lastCommandBuffer = gcvNULL;
+ gctPOINTER pointer = gcvNULL;
+
+#endif
+
+ gcmkHEADER_ARG(
+ "Command=0x%x CommandBuffer=0x%x ProcessID=%d",
+ Command, CommandBuffer, ProcessID
+ );
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+#if !gcdNULL_DRIVER
+ gcmkONERROR(_ProcessUserCommandBufferList(
+ Command,
+ CommandBuffer,
+ &lastCommandBuffer
+ ));
+#endif
+
+#if gcdPROCESS_ADDRESS_SPACE
+ gcmkONERROR(gckKERNEL_GetProcessMMU(Command->kernel, &mmu));
+
+ gcmkONERROR(gckOS_AtomicExchange(Command->os,
+ mmu->pageTableDirty[Command->kernel->core],
+ 0,
+ &oldValue));
+#else
+#endif
+
+ /* Acquire the command queue. */
+ gcmkONERROR(gckCOMMAND_EnterCommit(Command, gcvFALSE));
+ commitEntered = gcvTRUE;
+
+ /* Acquire the context switching mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(
+ Command->os, Command->mutexContext, gcvINFINITE
+ ));
+ contextAcquired = gcvTRUE;
+
+ /* Extract the gckHARDWARE and gckEVENT objects. */
+ hardware = Command->kernel->hardware;
+
+ /* Check wehther we need to copy the structures or not. */
+ gcmkONERROR(gckOS_QueryNeedCopy(Command->os, ProcessID, &needCopy));
+
+#if gcdNULL_DRIVER
+ /* Context switch required? */
+ if ((Context != gcvNULL) && (Command->currContext != Context))
+ {
+ /* Yes, merge in the deltas. */
+ gckCONTEXT_Update(Context, ProcessID, StateDelta);
+
+ /* Update the current context. */
+ Command->currContext = Context;
+
+ contextSwitched = gcvTRUE;
+ }
+#else
+ if (needCopy)
+ {
+ commandBufferObject = &_commandBufferObject;
+
+ gcmkONERROR(gckOS_CopyFromUserData(
+ Command->os,
+ commandBufferObject,
+ CommandBuffer,
+ gcmSIZEOF(struct _gcoCMDBUF)
+ ));
+
+ gcmkVERIFY_OBJECT(commandBufferObject, gcvOBJ_COMMANDBUFFER);
+ }
+ else
+ {
+ gcmkONERROR(gckOS_MapUserPointer(
+ Command->os,
+ CommandBuffer,
+ gcmSIZEOF(struct _gcoCMDBUF),
+ &pointer
+ ));
+
+ commandBufferObject = pointer;
+
+ gcmkVERIFY_OBJECT(commandBufferObject, gcvOBJ_COMMANDBUFFER);
+ commandBufferMapped = gcvTRUE;
+ }
+
+ gcmkONERROR(_HandlePatchList(Command, commandBufferObject, needCopy, &asyncCommandStamp));
+
+ /* Query the size of NOP command. */
+ gcmkONERROR(gckHARDWARE_Nop(
+ hardware, gcvNULL, &nopBytes
+ ));
+
+ /* Query the size of pipe select command sequence. */
+ gcmkONERROR(gckHARDWARE_PipeSelect(
+ hardware, gcvNULL, gcvPIPE_3D, &pipeBytes
+ ));
+
+ /* Query the size of LINK command. */
+ gcmkONERROR(gckHARDWARE_Link(
+ hardware, gcvNULL, 0, 0, &linkBytes, gcvNULL, gcvNULL
+ ));
+
+ /* Compute the command buffer entry and the size. */
+ commandBufferLogical
+ = (gctUINT8_PTR) gcmUINT64_TO_PTR(commandBufferObject->logical)
+ + commandBufferObject->startOffset;
+
+ /* Get the hardware address. */
+ if (Command->kernel->virtualCommandBuffer)
+ {
+ gckKERNEL kernel = Command->kernel;
+
+ virtualCommandBuffer = gcmNAME_TO_PTR(commandBufferObject->physical);
+
+ if (virtualCommandBuffer == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gcmkONERROR(gckKERNEL_GetGPUAddress(
+ Command->kernel,
+ commandBufferLogical,
+ gcvTRUE,
+ virtualCommandBuffer,
+ &commandBufferAddress
+ ));
+ }
+ else
+ {
+ gcmkONERROR(gckHARDWARE_ConvertLogical(
+ hardware,
+ commandBufferLogical,
+ gcvTRUE,
+ &commandBufferAddress
+ ));
+ }
+
+#ifdef __QNXNTO__
+ userCommandBufferLogical = (gctPOINTER) commandBufferLogical;
+
+ gcmkONERROR(gckOS_MapUserPointer(
+ Command->os,
+ userCommandBufferLogical,
+ 0,
+ &pointer));
+
+ commandBufferLogical = pointer;
+
+ userCommandBufferLogicalMapped = gcvTRUE;
+
+ gcmkONERROR(gckOS_GetPhysicalAddress(
+ Command->os,
+ commandBufferLogical,
+ &commandBufferPhysical
+ ));
+#else
+ /* Get the physical address. */
+ gcmkONERROR(gckOS_UserLogicalToPhysical(
+ Command->os,
+ commandBufferLogical,
+ &commandBufferPhysical
+ ));
+#endif
+
+ commandBufferSize
+ = commandBufferObject->offset
+ + commandBufferObject->reservedTail
+ - commandBufferObject->startOffset;
+
+ gcmkONERROR(_FlushMMU(Command));
+
+ if (Command->dummyDraw == gcvTRUE &&
+ Context != gcvNULL)
+ {
+ Command->dummyDraw = gcvFALSE;
+ gcmkONERROR(_DummyDraw(Command));
+ }
+
+ if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_FENCE_64BIT) && asyncCommandStamp != 0)
+ {
+ gcmkONERROR(_WaitForAsyncCommandStamp(Command, asyncCommandStamp));
+ }
+
+ /* Get the current offset. */
+ offset = Command->offset;
+
+ /* Compute number of bytes left in current kernel command queue. */
+ bytes = Command->pageSize - offset;
+
+ /* Query the size of WAIT/LINK command sequence. */
+ gcmkONERROR(gckHARDWARE_WaitLink(
+ hardware,
+ gcvNULL,
+ ~0U,
+ offset,
+ &waitLinkBytes,
+ gcvNULL,
+ gcvNULL
+ ));
+
+ /* Is there enough space in the current command queue? */
+ if (bytes < waitLinkBytes)
+ {
+ /* No, create a new one. */
+ gcmkONERROR(_NewQueue(Command, gcvFALSE));
+
+ /* Get the new current offset. */
+ offset = Command->offset;
+
+ /* Recompute the number of bytes in the new kernel command queue. */
+ bytes = Command->pageSize - offset;
+ gcmkASSERT(bytes >= waitLinkBytes);
+ }
+
+ /* Compute the location if WAIT/LINK command sequence. */
+ waitLinkPhysical = Command->physical + offset;
+ waitLinkLogical = (gctUINT8_PTR) Command->logical + offset;
+ waitLinkAddress = Command->address + offset;
+
+ /* Context switch required? */
+ if (Context == gcvNULL)
+ {
+ /* See if we have to switch pipes for the command buffer. */
+ if (commandBufferObject->entryPipe == Command->pipeSelect)
+ {
+ /* Skip pipe switching sequence. */
+ offset = pipeBytes;
+ }
+ else
+ {
+ /* The current hardware and the entry command buffer pipes
+ ** are different, switch to the correct pipe. */
+ gcmkONERROR(gckHARDWARE_PipeSelect(
+ Command->kernel->hardware,
+ commandBufferLogical,
+ commandBufferObject->entryPipe,
+ &pipeBytes
+ ));
+
+ /* Do not skip pipe switching sequence. */
+ offset = 0;
+ }
+
+ /* Compute the entry. */
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ entryPhysical = (gctUINT8_PTR) commandBufferPhysical + offset;
+#endif
+ entryLogical = commandBufferLogical + offset;
+ entryAddress = commandBufferAddress + offset;
+ entryBytes = commandBufferSize - offset;
+
+ Command->currContext = gcvNULL;
+ }
+#if gcdDEBUG_OPTION && gcdDEBUG_FORCE_CONTEXT_UPDATE
+ else if (1)
+#else
+ else if (Command->currContext != Context)
+#endif
+ {
+ /* Get the current context buffer. */
+ contextBuffer = Context->buffer;
+
+ /* Yes, merge in the deltas. */
+ gcmkONERROR(gckCONTEXT_Update(Context, ProcessID, StateDelta));
+
+ contextSwitched = gcvTRUE;
+
+ /***************************************************************
+ ** SWITCHING CONTEXT.
+ */
+
+ /* Determine context buffer entry offset. */
+ offset = (Command->pipeSelect == gcvPIPE_3D)
+
+ /* Skip pipe switching sequence. */
+ ? Context->entryOffset3D + Context->pipeSelectBytes
+
+ /* Do not skip pipe switching sequence. */
+ : Context->entryOffset3D;
+
+ /* Compute the entry. */
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ entryPhysical = (gctUINT8_PTR) contextBuffer->physical + offset;
+#endif
+ entryLogical = (gctUINT8_PTR) contextBuffer->logical + offset;
+ entryAddress = contextBuffer->address + offset;
+ entryBytes = Context->bufferSize - offset;
+
+ /* See if we have to switch pipes between the context
+ and command buffers. */
+ if (commandBufferObject->entryPipe == gcvPIPE_3D)
+ {
+ /* Skip pipe switching sequence. */
+ offset = pipeBytes;
+ }
+ else
+ {
+ /* The current hardware and the initial context pipes are
+ different, switch to the correct pipe. */
+ gcmkONERROR(gckHARDWARE_PipeSelect(
+ Command->kernel->hardware,
+ commandBufferLogical,
+ commandBufferObject->entryPipe,
+ &pipeBytes
+ ));
+
+ /* Do not skip pipe switching sequence. */
+ offset = 0;
+ }
+
+ /* Generate a LINK from the context buffer to
+ the command buffer. */
+ gcmkONERROR(gckHARDWARE_Link(
+ hardware,
+ contextBuffer->link3D,
+ commandBufferAddress + offset,
+ commandBufferSize - offset,
+ &linkBytes,
+ &commandLinkLow,
+ &commandLinkHigh
+ ));
+
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ /* Flush the context buffer cache. */
+ gcmkONERROR(gckOS_CacheClean(
+ Command->os,
+ Command->kernelProcessID,
+ gcvNULL,
+ (gctUINT32)entryPhysical,
+ entryLogical,
+ entryBytes
+ ));
+#endif
+
+ /* Update the current context. */
+ Command->currContext = Context;
+
+#if gcdDUMP_COMMAND
+ contextDumpLogical = entryLogical;
+ contextDumpBytes = entryBytes;
+#endif
+
+#if gcdSECURITY
+ /* Commit context buffer to trust zone. */
+ gckKERNEL_SecurityExecute(
+ Command->kernel,
+ entryLogical,
+ entryBytes - 8
+ );
+#endif
+
+#if gcdRECORD_COMMAND
+ gckRECORDER_Record(
+ Command->recorder,
+ gcvNULL,
+ 0xFFFFFFFF,
+ entryLogical,
+ entryBytes
+ );
+#endif
+ }
+
+ /* Same context. */
+ else
+ {
+ /* See if we have to switch pipes for the command buffer. */
+ if (commandBufferObject->entryPipe == Command->pipeSelect)
+ {
+ /* Skip pipe switching sequence. */
+ offset = pipeBytes;
+ }
+ else
+ {
+ /* The current hardware and the entry command buffer pipes
+ ** are different, switch to the correct pipe. */
+ gcmkONERROR(gckHARDWARE_PipeSelect(
+ Command->kernel->hardware,
+ commandBufferLogical,
+ commandBufferObject->entryPipe,
+ &pipeBytes
+ ));
+
+ /* Do not skip pipe switching sequence. */
+ offset = 0;
+ }
+
+ /* Compute the entry. */
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ entryPhysical = (gctUINT8_PTR) commandBufferPhysical + offset;
+#endif
+ entryLogical = commandBufferLogical + offset;
+ entryAddress = commandBufferAddress + offset;
+ entryBytes = commandBufferSize - offset;
+ }
+
+#if gcdDUMP_COMMAND
+ bufferDumpLogical = commandBufferLogical + offset;
+ bufferDumpBytes = commandBufferSize - offset;
+#endif
+
+#if gcdSECURE_USER
+ /* Process user hints. */
+ gcmkONERROR(_ProcessHints(Command, ProcessID, commandBufferObject));
+#endif
+
+ /* Determine the location to jump to for the command buffer being
+ ** scheduled. */
+ if (Command->newQueue)
+ {
+ /* New command queue, jump to the beginning of it. */
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ exitPhysical = Command->physical;
+ exitLogical = Command->logical;
+#endif
+ exitAddress = Command->address;
+ exitBytes = Command->offset + waitLinkBytes;
+ }
+ else
+ {
+ /* Still within the preexisting command queue, jump to the new
+ WAIT/LINK command sequence. */
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ exitPhysical = waitLinkPhysical;
+ exitLogical = waitLinkLogical;
+#endif
+ exitAddress = waitLinkAddress;
+ exitBytes = waitLinkBytes;
+ }
+
+ /* Add a new WAIT/LINK command sequence. When the command buffer which is
+ currently being scheduled is fully executed by the GPU, the FE will
+ jump to this WAIT/LINK sequence. */
+ gcmkONERROR(gckHARDWARE_WaitLink(
+ hardware,
+ waitLinkLogical,
+ waitLinkAddress,
+ offset,
+ &waitLinkBytes,
+ &waitOffset,
+ &waitSize
+ ));
+
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ /* Flush the command queue cache. */
+ gcmkONERROR(gckOS_CacheClean(
+ Command->os,
+ Command->kernelProcessID,
+ gcvNULL,
+ (gctUINT32)exitPhysical,
+ exitLogical,
+ exitBytes
+ ));
+#endif
+
+ /* Determine the location of the TAIL in the command buffer. */
+ commandBufferTail
+ = commandBufferLogical
+ + commandBufferSize
+ - commandBufferObject->reservedTail;
+
+ /* Generate command which writes out commit stamp. */
+ if (gckHARDWARE_IsFeatureAvailable(hardware, gcvFEATURE_FENCE_64BIT))
+ {
+ gctUINT32 bytes;
+
+ gcmkONERROR(gckHARDWARE_Fence(
+ hardware,
+ gcvENGINE_RENDER,
+ commandBufferTail,
+ Command->fence->address,
+ Command->commitStamp,
+ &bytes
+ ));
+
+ commandBufferTail += gcdRENDER_FENCE_LENGTH;
+ }
+
+ /* Generate a LINK from the end of the command buffer being scheduled
+ back to the kernel command queue. */
+#if !gcdSECURITY
+ if (Shared == gcvFALSE)
+ {
+ gcmkONERROR(gckHARDWARE_Link(
+ hardware,
+ commandBufferTail,
+ exitAddress,
+ exitBytes,
+ &linkBytes,
+ &exitLinkLow,
+ &exitLinkHigh
+ ));
+ }
+ else
+ {
+ gctUINT8_PTR link = commandBufferTail + Index * 16;
+ gctSIZE_T bytes = 8;
+
+ gcmkONERROR(gckHARDWARE_ChipEnable(
+ hardware,
+ link,
+ (gceCORE_3D_MASK)(1 << hardware->kernel->chipID),
+ &bytes
+ ));
+
+ link += bytes;
+
+ gcmkONERROR(gckHARDWARE_Link(
+ hardware,
+ link,
+ exitAddress,
+ exitBytes,
+ &linkBytes,
+ &exitLinkLow,
+ &exitLinkHigh
+ ));
+
+ link += linkBytes;
+ }
+#endif
+
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ /* Flush the command buffer cache. */
+ gcmkONERROR(gckOS_CacheClean(
+ Command->os,
+ ProcessID,
+ gcvNULL,
+ (gctUINT32)commandBufferPhysical,
+ commandBufferLogical,
+ commandBufferSize
+ ));
+#endif
+
+#if gcdRECORD_COMMAND
+ gckRECORDER_Record(
+ Command->recorder,
+ commandBufferLogical + offset,
+ commandBufferSize - offset,
+ gcvNULL,
+ 0xFFFFFFFF
+ );
+
+ gckRECORDER_AdvanceIndex(Command->recorder, Command->commitStamp);
+#endif
+
+#if gcdSECURITY
+ /* Submit command buffer to trust zone. */
+ gckKERNEL_SecurityExecute(
+ Command->kernel,
+ commandBufferLogical + offset,
+ commandBufferSize - offset - 8
+ );
+#else
+ /* Generate a LINK from the previous WAIT/LINK command sequence to the
+ entry determined above (either the context or the command buffer).
+ This LINK replaces the WAIT instruction from the previous WAIT/LINK
+ pair, therefore we use WAIT metrics for generation of this LINK.
+ This action will execute the entire sequence. */
+ gcmkONERROR(gckHARDWARE_Link(
+ hardware,
+ Command->waitLogical,
+ entryAddress,
+ entryBytes,
+ &Command->waitSize,
+ &entryLinkLow,
+ &entryLinkHigh
+ ));
+#endif
+
+#if gcdLINK_QUEUE_SIZE
+ if (Command->kernel->stuckDump >= gcvSTUCK_DUMP_USER_COMMAND)
+ {
+ gcuQUEUEDATA data;
+
+ gcmkVERIFY_OK(gckOS_GetProcessID(&data.linkData.pid));
+
+ data.linkData.start = entryAddress;
+ data.linkData.end = entryAddress + entryBytes;
+ data.linkData.linkLow = entryLinkLow;
+ data.linkData.linkHigh = entryLinkHigh;
+
+ gckQUEUE_Enqueue(&hardware->linkQueue, &data);
+
+ if (commandBufferAddress + offset != entryAddress)
+ {
+ data.linkData.start = commandBufferAddress + offset;
+ data.linkData.end = commandBufferAddress + commandBufferSize;
+ data.linkData.linkLow = commandLinkLow;
+ data.linkData.linkHigh = commandLinkHigh;
+
+ gckQUEUE_Enqueue(&hardware->linkQueue, &data);
+ }
+
+ if (Command->kernel->stuckDump >= gcvSTUCK_DUMP_ALL_COMMAND)
+ {
+ data.linkData.start = exitAddress;
+ data.linkData.end = exitAddress + exitBytes;
+ data.linkData.linkLow = exitLinkLow;
+ data.linkData.linkHigh = exitLinkHigh;
+
+ /* Dump kernel command.*/
+ gckQUEUE_Enqueue(&hardware->linkQueue, &data);
+ }
+ }
+#endif
+
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ /* Flush the cache for the link. */
+ gcmkONERROR(gckOS_CacheClean(
+ Command->os,
+ Command->kernelProcessID,
+ gcvNULL,
+ (gctUINT32)Command->waitPhysical,
+ Command->waitLogical,
+ Command->waitSize
+ ));
+#endif
+
+ gcmkDUMPCOMMAND(
+ Command->os,
+ Command->waitLogical,
+ Command->waitSize,
+ gcvDUMP_BUFFER_LINK,
+ gcvFALSE
+ );
+
+ gcmkDUMPCOMMAND(
+ Command->os,
+ contextDumpLogical,
+ contextDumpBytes,
+ gcvDUMP_BUFFER_CONTEXT,
+ gcvFALSE
+ );
+
+ gcmkDUMPCOMMAND(
+ Command->os,
+ bufferDumpLogical,
+ bufferDumpBytes,
+ gcvDUMP_BUFFER_USER,
+ gcvFALSE
+ );
+
+ gcmkDUMPCOMMAND(
+ Command->os,
+ waitLinkLogical,
+ waitLinkBytes,
+ gcvDUMP_BUFFER_WAITLINK,
+ gcvFALSE
+ );
+
+ /* Update the current pipe. */
+ Command->pipeSelect = commandBufferObject->exitPipe;
+
+ /* Update command queue offset. */
+ Command->offset += waitLinkBytes;
+ Command->newQueue = gcvFALSE;
+
+ /* Update address of last WAIT. */
+ Command->waitPhysical = waitLinkPhysical + waitOffset;
+ Command->waitLogical = (gctUINT8_PTR)waitLinkLogical + waitOffset;
+ Command->waitAddress = waitLinkAddress + waitOffset;
+ Command->waitSize = waitSize;
+
+ /* Update queue tail pointer. */
+ gcmkONERROR(gckHARDWARE_UpdateQueueTail(
+ hardware, Command->logical, Command->offset
+ ));
+
+#if gcdDUMP_COMMAND
+ gcmkPRINT("@[kernel.commit]");
+#endif
+#endif /* gcdNULL_DRIVER */
+
+ /* Release the context switching mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexContext));
+ contextAcquired = gcvFALSE;
+
+ *CommitStamp = Command->commitStamp;
+ *ContextSwitched = contextSwitched;
+
+ Command->commitStamp++;
+
+ stall = gcvFALSE;
+
+#if gcdLINK_QUEUE_SIZE
+ if (Command->kernel->stuckDump == gcvSTUCK_DUMP_STALL_COMMAND)
+ {
+ if ((Command->commitStamp % (gcdLINK_QUEUE_SIZE/2)) == 0)
+ {
+ /* If only context buffer and command buffer is recorded,
+ ** each commit costs 2 slot in queue, to make sure command
+ ** causing stuck is recorded, number of pending command buffer
+ ** is limited to (gckLINK_QUEUE_SIZE/2)
+ */
+ stall = gcvTRUE;
+ }
+ }
+#endif
+
+ /* Release the command queue. */
+ gcmkONERROR(gckCOMMAND_ExitCommit(Command, gcvFALSE));
+ commitEntered = gcvFALSE;
+
+ if (status == gcvSTATUS_INTERRUPTED)
+ {
+ gcmkTRACE(
+ gcvLEVEL_INFO,
+ "%s(%d): Intterupted in gckEVENT_Submit",
+ __FUNCTION__, __LINE__
+ );
+ status = gcvSTATUS_OK;
+ }
+ else
+ {
+ gcmkONERROR(status);
+ }
+
+#ifdef __QNXNTO__
+ if (userCommandBufferLogicalMapped)
+ {
+ gcmkONERROR(gckOS_UnmapUserPointer(
+ Command->os,
+ userCommandBufferLogical,
+ 0,
+ commandBufferLogical));
+
+ userCommandBufferLogicalMapped = gcvFALSE;
+ }
+#endif
+
+ /* Unmap the command buffer pointer. */
+ if (commandBufferMapped)
+ {
+ gcmkONERROR(gckOS_UnmapUserPointer(
+ Command->os,
+ CommandBuffer,
+ gcmSIZEOF(struct _gcoCMDBUF),
+ commandBufferObject
+ ));
+
+ commandBufferMapped = gcvFALSE;
+ }
+
+ /* Return status. */
+ gcmkFOOTER();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (contextAcquired)
+ {
+ /* Release the context switching mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Command->os, Command->mutexContext));
+ }
+
+ if (commitEntered)
+ {
+ /* Release the command queue mutex. */
+ gcmkVERIFY_OK(gckCOMMAND_ExitCommit(Command, gcvFALSE));
+ }
+
+#ifdef __QNXNTO__
+ if (userCommandBufferLogicalMapped)
+ {
+ gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+ Command->os,
+ userCommandBufferLogical,
+ 0,
+ commandBufferLogical));
+ }
+#endif
+
+ /* Unmap the command buffer pointer. */
+ if (commandBufferMapped)
+ {
+ gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+ Command->os,
+ CommandBuffer,
+ gcmSIZEOF(struct _gcoCMDBUF),
+ commandBufferObject
+ ));
+ }
+
+ /* Return status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckCOMMAND_Reserve
+**
+** Reserve space in the command queue. Also acquire the command queue mutex.
+**
+** INPUT:
+**
+** gckCOMMAND Command
+** Pointer to an gckCOMMAND object.
+**
+** gctSIZE_T RequestedBytes
+** Number of bytes previously reserved.
+**
+** OUTPUT:
+**
+** gctPOINTER * Buffer
+** Pointer to a variable that will receive the address of the reserved
+** space.
+**
+** gctSIZE_T * BufferSize
+** Pointer to a variable that will receive the number of bytes
+** available in the command queue.
+*/
+gceSTATUS
+gckCOMMAND_Reserve(
+ IN gckCOMMAND Command,
+ IN gctUINT32 RequestedBytes,
+ OUT gctPOINTER * Buffer,
+ OUT gctUINT32 * BufferSize
+ )
+{
+ gceSTATUS status;
+ gctUINT32 bytes;
+ gctUINT32 requiredBytes;
+ gctUINT32 requestedAligned;
+
+ gcmkHEADER_ARG("Command=0x%x RequestedBytes=%lu", Command, RequestedBytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ /* Compute aligned number of reuested bytes. */
+ requestedAligned = gcmALIGN(RequestedBytes, Command->alignment);
+
+ /* Another WAIT/LINK command sequence will have to be appended after
+ the requested area being reserved. Compute the number of bytes
+ required for WAIT/LINK at the location after the reserved area. */
+ gcmkONERROR(gckHARDWARE_WaitLink(
+ Command->kernel->hardware,
+ gcvNULL,
+ ~0U,
+ Command->offset + requestedAligned,
+ &requiredBytes,
+ gcvNULL,
+ gcvNULL
+ ));
+
+ /* Compute total number of bytes required. */
+ requiredBytes += requestedAligned;
+
+ /* Compute number of bytes available in command queue. */
+ bytes = Command->pageSize - Command->offset;
+
+ /* Is there enough space in the current command queue? */
+ if (bytes < requiredBytes)
+ {
+ /* Create a new command queue. */
+ gcmkONERROR(_NewQueue(Command, gcvFALSE));
+
+ /* Recompute the number of bytes in the new kernel command queue. */
+ bytes = Command->pageSize - Command->offset;
+
+ /* Still not enough space? */
+ if (bytes < requiredBytes)
+ {
+ /* Rare case, not enough room in command queue. */
+ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+ }
+ }
+
+ /* Return pointer to empty slot command queue. */
+ *Buffer = (gctUINT8 *) Command->logical + Command->offset;
+
+ /* Return number of bytes left in command queue. */
+ *BufferSize = bytes;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Buffer=0x%x *BufferSize=%lu", *Buffer, *BufferSize);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckCOMMAND_Execute
+**
+** Execute a previously reserved command queue by appending a WAIT/LINK command
+** sequence after it and modifying the last WAIT into a LINK command. The
+** command FIFO mutex will be released whether this function succeeds or not.
+**
+** INPUT:
+**
+** gckCOMMAND Command
+** Pointer to an gckCOMMAND object.
+**
+** gctSIZE_T RequestedBytes
+** Number of bytes previously reserved.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckCOMMAND_Execute(
+ IN gckCOMMAND Command,
+ IN gctUINT32 RequestedBytes
+ )
+{
+ gceSTATUS status;
+
+ gctUINT32 waitLinkPhysical;
+ gctUINT8_PTR waitLinkLogical;
+ gctUINT32 waitLinkAddress;
+ gctUINT32 waitLinkOffset;
+ gctUINT32 waitLinkBytes;
+
+ gctUINT32 waitPhysical;
+ gctPOINTER waitLogical;
+ gctUINT32 waitAddress;
+ gctUINT32 waitOffset;
+ gctUINT32 waitBytes;
+
+ gctUINT32 linkLow, linkHigh;
+
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ gctPHYS_ADDR execPhysical;
+#endif
+ gctPOINTER execLogical;
+ gctUINT32 execAddress;
+ gctUINT32 execBytes;
+
+ gcmkHEADER_ARG("Command=0x%x RequestedBytes=%lu", Command, RequestedBytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ /* Compute offset for WAIT/LINK. */
+ waitLinkOffset = Command->offset + RequestedBytes;
+
+ /* Compute number of bytes left in command queue. */
+ waitLinkBytes = Command->pageSize - waitLinkOffset;
+
+ /* Compute the location if WAIT/LINK command sequence. */
+ waitLinkPhysical = Command->physical + waitLinkOffset;
+ waitLinkLogical = (gctUINT8_PTR) Command->logical + waitLinkOffset;
+ waitLinkAddress = Command->address + waitLinkOffset;
+
+ /* Append WAIT/LINK in command queue. */
+ gcmkONERROR(gckHARDWARE_WaitLink(
+ Command->kernel->hardware,
+ waitLinkLogical,
+ waitLinkAddress,
+ waitLinkOffset,
+ &waitLinkBytes,
+ &waitOffset,
+ &waitBytes
+ ));
+
+ /* Compute the location if WAIT command. */
+ waitPhysical = waitLinkPhysical + waitOffset;
+ waitLogical = waitLinkLogical + waitOffset;
+ waitAddress = waitLinkAddress + waitOffset;
+
+ /* Determine the location to jump to for the command buffer being
+ ** scheduled. */
+ if (Command->newQueue)
+ {
+ /* New command queue, jump to the beginning of it. */
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ execPhysical = Command->physical;
+#endif
+ execLogical = Command->logical;
+ execAddress = Command->address;
+ execBytes = waitLinkOffset + waitLinkBytes;
+ }
+ else
+ {
+ /* Still within the preexisting command queue, jump directly to the
+ reserved area. */
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ execPhysical = (gctUINT8 *) Command->physical + Command->offset;
+#endif
+ execLogical = (gctUINT8 *) Command->logical + Command->offset;
+ execAddress = Command->address + Command->offset;
+ execBytes = RequestedBytes + waitLinkBytes;
+ }
+
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ /* Flush the cache. */
+ gcmkONERROR(gckOS_CacheClean(
+ Command->os,
+ Command->kernelProcessID,
+ gcvNULL,
+ (gctUINT32)execPhysical,
+ execLogical,
+ execBytes
+ ));
+#endif
+
+ /* Convert the last WAIT into a LINK. */
+ gcmkONERROR(gckHARDWARE_Link(
+ Command->kernel->hardware,
+ Command->waitLogical,
+ execAddress,
+ execBytes,
+ &Command->waitSize,
+ &linkLow,
+ &linkHigh
+ ));
+
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ /* Flush the cache. */
+ gcmkONERROR(gckOS_CacheClean(
+ Command->os,
+ Command->kernelProcessID,
+ gcvNULL,
+ (gctUINT32)Command->waitPhysical,
+ Command->waitLogical,
+ Command->waitSize
+ ));
+#endif
+
+#if gcdLINK_QUEUE_SIZE
+ if (Command->kernel->stuckDump >= gcvSTUCK_DUMP_ALL_COMMAND)
+ {
+ gcuQUEUEDATA data;
+
+ gcmkVERIFY_OK(gckOS_GetProcessID(&data.linkData.pid));
+
+ data.linkData.start = execAddress;
+ data.linkData.end = execAddress + execBytes;
+ data.linkData.linkLow = linkLow;
+ data.linkData.linkHigh = linkHigh;
+
+ gckQUEUE_Enqueue(&Command->kernel->hardware->linkQueue, &data);
+ }
+#endif
+
+ gcmkDUMPCOMMAND(
+ Command->os,
+ Command->waitLogical,
+ Command->waitSize,
+ gcvDUMP_BUFFER_LINK,
+ gcvFALSE
+ );
+
+ gcmkDUMPCOMMAND(
+ Command->os,
+ execLogical,
+ execBytes,
+ gcvDUMP_BUFFER_KERNEL,
+ gcvFALSE
+ );
+
+ /* Update the pointer to the last WAIT. */
+ Command->waitPhysical = waitPhysical;
+ Command->waitLogical = waitLogical;
+ Command->waitAddress = waitAddress;
+ Command->waitSize = waitBytes;
+
+ /* Update the command queue. */
+ Command->offset += RequestedBytes + waitLinkBytes;
+ Command->newQueue = gcvFALSE;
+
+ /* Update queue tail pointer. */
+ gcmkONERROR(gckHARDWARE_UpdateQueueTail(
+ Command->kernel->hardware, Command->logical, Command->offset
+ ));
+
+#if gcdDUMP_COMMAND
+ gcmkPRINT("@[kernel.execute]");
+#endif
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckCOMMAND_Stall
+**
+** The calling thread will be suspended until the command queue has been
+** completed.
+**
+** INPUT:
+**
+** gckCOMMAND Command
+** Pointer to an gckCOMMAND object.
+**
+** gctBOOL FromPower
+** Determines whether the call originates from inside the power
+** management or not.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckCOMMAND_Stall(
+ IN gckCOMMAND Command,
+ IN gctBOOL FromPower
+ )
+{
+#if gcdNULL_DRIVER
+ /* Do nothing with infinite hardware. */
+ return gcvSTATUS_OK;
+#else
+ gckOS os;
+ gckHARDWARE hardware;
+ gckEVENT eventObject;
+ gceSTATUS status;
+ gctSIGNAL signal = gcvNULL;
+ gctUINT timer = 0;
+
+ gcmkHEADER_ARG("Command=0x%x", Command);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ /* Extract the gckOS object pointer. */
+ os = Command->os;
+ gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+ /* Extract the gckHARDWARE object pointer. */
+ hardware = Command->kernel->hardware;
+ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+ /* Extract the gckEVENT object pointer. */
+ eventObject = Command->kernel->eventObj;
+ gcmkVERIFY_OBJECT(eventObject, gcvOBJ_EVENT);
+
+ /* Allocate the signal. */
+ gcmkONERROR(gckOS_CreateSignal(os, gcvTRUE, &signal));
+
+ /* Append the EVENT command to trigger the signal. */
+ gcmkONERROR(gckEVENT_Signal(eventObject, signal, gcvKERNEL_PIXEL));
+
+ /* Submit the event queue. */
+ gcmkONERROR(gckEVENT_Submit(eventObject, gcvTRUE, FromPower));
+
+#if gcdDUMP_COMMAND
+ gcmkPRINT("@[kernel.stall]");
+#endif
+
+ if (status == gcvSTATUS_CHIP_NOT_READY)
+ {
+ /* Error. */
+ goto OnError;
+ }
+
+ do
+ {
+ /* Wait for the signal. */
+ status = gckOS_WaitSignal(os, signal, !FromPower, gcdGPU_ADVANCETIMER);
+
+ if (status == gcvSTATUS_TIMEOUT)
+ {
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+ gctUINT32 idle;
+
+ /* Read idle register. */
+ gcmkVERIFY_OK(gckHARDWARE_GetIdle(
+ hardware, gcvFALSE, &idle
+ ));
+
+ gcmkTRACE(
+ gcvLEVEL_ERROR,
+ "%s(%d): idle=%08x",
+ __FUNCTION__, __LINE__, idle
+ );
+
+ gcmkVERIFY_OK(gckOS_MemoryBarrier(os, gcvNULL));
+#endif
+
+ /* Advance timer. */
+ timer += gcdGPU_ADVANCETIMER;
+ }
+ else if (status == gcvSTATUS_INTERRUPTED)
+ {
+ gcmkONERROR(gcvSTATUS_INTERRUPTED);
+ }
+
+ }
+ while (gcmIS_ERROR(status));
+
+ /* Bail out on timeout. */
+ if (gcmIS_ERROR(status))
+ {
+ /* Broadcast the stuck GPU. */
+ gcmkONERROR(gckOS_Broadcast(
+ os, hardware, gcvBROADCAST_GPU_STUCK
+ ));
+ }
+
+ /* Delete the signal. */
+ gcmkVERIFY_OK(gckOS_DestroySignal(os, signal));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (signal != gcvNULL)
+ {
+ /* Free the signal. */
+ gcmkVERIFY_OK(gckOS_DestroySignal(os, signal));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+#endif
+}
+
+/*******************************************************************************
+**
+** gckCOMMAND_Attach
+**
+** Attach user process.
+**
+** INPUT:
+**
+** gckCOMMAND Command
+** Pointer to a gckCOMMAND object.
+**
+** gctUINT32 ProcessID
+** Current process ID.
+**
+** OUTPUT:
+**
+** gckCONTEXT * Context
+** Pointer to a variable that will receive a pointer to a new
+** gckCONTEXT object.
+**
+** gctSIZE_T * StateCount
+** Pointer to a variable that will receive the number of states
+** in the context buffer.
+*/
+#if (gcdENABLE_3D || gcdENABLE_2D)
+gceSTATUS
+gckCOMMAND_Attach(
+ IN gckCOMMAND Command,
+ OUT gckCONTEXT * Context,
+ OUT gctSIZE_T * MaxState,
+ OUT gctUINT32 * NumStates,
+ IN gctUINT32 ProcessID
+ )
+{
+ gceSTATUS status;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Command=0x%x", Command);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ /* Acquire the context switching mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(
+ Command->os, Command->mutexContext, gcvINFINITE
+ ));
+ acquired = gcvTRUE;
+
+ /* Construct a gckCONTEXT object. */
+ gcmkONERROR(gckCONTEXT_Construct(
+ Command->os,
+ Command->kernel->hardware,
+ ProcessID,
+ Context
+ ));
+
+ /* Return the number of states in the context. */
+ * MaxState = (* Context)->maxState;
+ * NumStates = (* Context)->numStates;
+
+ /* Release the context switching mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexContext));
+ acquired = gcvFALSE;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Context=0x%x", *Context);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Release mutex. */
+ if (acquired)
+ {
+ /* Release the context switching mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Command->os, Command->mutexContext));
+ acquired = gcvFALSE;
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+#endif
+
+/*******************************************************************************
+**
+** gckCOMMAND_Detach
+**
+** Detach user process.
+**
+** INPUT:
+**
+** gckCOMMAND Command
+** Pointer to a gckCOMMAND object.
+**
+** gckCONTEXT Context
+** Pointer to a gckCONTEXT object to be destroyed.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckCOMMAND_Detach(
+ IN gckCOMMAND Command,
+ IN gckCONTEXT Context
+ )
+{
+ gceSTATUS status;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Command=0x%x Context=0x%x", Command, Context);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ /* Acquire the context switching mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(
+ Command->os, Command->mutexContext, gcvINFINITE
+ ));
+ acquired = gcvTRUE;
+
+ /* Construct a gckCONTEXT object. */
+ gcmkONERROR(gckCONTEXT_Destroy(Context));
+
+ if (Command->currContext == Context)
+ {
+ /* Detach from gckCOMMAND object if the destoryed context is current context. */
+ Command->currContext = gcvNULL;
+ }
+
+ /* Release the context switching mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexContext));
+ acquired = gcvFALSE;
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Release mutex. */
+ if (acquired)
+ {
+ /* Release the context switching mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Command->os, Command->mutexContext));
+ acquired = gcvFALSE;
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckCOMMAND_DumpExecutingBuffer
+**
+** Dump the command buffer which GPU is executing.
+**
+** INPUT:
+**
+** gckCOMMAND Command
+** Pointer to a gckCOMMAND object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckCOMMAND_DumpExecutingBuffer(
+ IN gckCOMMAND Command
+ )
+{
+ gceSTATUS status;
+ gckVIRTUAL_COMMAND_BUFFER_PTR buffer = gcvNULL;
+ gctUINT32 gpuAddress;
+ gctSIZE_T pageCount;
+ gctPOINTER entry = gcvNULL;
+ gckOS os = Command->os;
+ gckKERNEL kernel = Command->kernel;
+ gctUINT32 i;
+ gctUINT32 dumpRear;
+ gckQUEUE queue = &kernel->hardware->linkQueue;
+ gctSIZE_T bytes;
+ gckLINKDATA linkData;
+ gcuQUEUEDATA * queueData;
+ gctUINT32 offset;
+ gctPOINTER entryDump;
+ gctUINT32 pid;
+ gctUINT8 processName[24] = {0};
+ gctPHYS_ADDR_T cpuPhysical;
+
+ gcmkPRINT("**************************\n");
+ gcmkPRINT("**** COMMAND BUF DUMP ****\n");
+ gcmkPRINT("**************************\n");
+
+ gcmkPRINT(" Submitted commit stamp = %lld", Command->commitStamp - 1);
+ gcmkPRINT(" Executed commit stamp = %lld", *(gctUINT64_PTR)Command->fence->logical);
+
+ gcmkVERIFY_OK(gckOS_ReadRegisterEx(os, kernel->core, 0x664, &gpuAddress));
+ gcmkVERIFY_OK(gckOS_ReadRegisterEx(os, kernel->core, 0x664, &gpuAddress));
+
+ gcmkPRINT("DMA Address 0x%08X, memory around:", gpuAddress);
+
+ /* Search and dump memory around DMA address. */
+ if (kernel->virtualCommandBuffer)
+ {
+ status = gckDEVICE_QueryGPUAddress(kernel->device, kernel, gpuAddress, &buffer);
+ }
+ else
+ {
+ status = gcvSTATUS_OK;
+ }
+
+ if (gcmIS_SUCCESS(status))
+ {
+ if (kernel->virtualCommandBuffer)
+ {
+ gcmkVERIFY_OK(gckOS_CreateKernelVirtualMapping(
+ os, buffer->virtualBuffer.physical, buffer->virtualBuffer.bytes, &entry, &pageCount));
+
+ offset = gpuAddress - buffer->virtualBuffer.gpuAddress;
+
+ entryDump = entry;
+
+ /* Dump one pages. */
+ bytes = 4096;
+
+ /* Align to page. */
+ offset &= 0xfffff000;
+
+ /* Kernel address of page where stall point stay. */
+ entryDump = (gctUINT8_PTR)entryDump + offset;
+
+ /* Align to page. */
+ gpuAddress &= 0xfffff000;
+ }
+ else
+ {
+ gcmkVERIFY_OK(gckOS_GPUPhysicalToCPUPhysical(os, gpuAddress, &cpuPhysical));
+
+ gcmkVERIFY_OK(gckOS_MapPhysical(os, (gctUINT32) cpuPhysical, 4096, &entry));
+
+ /* Align to page start. */
+ entryDump = (gctPOINTER)((gctUINTPTR_T)entry & ~0xFFF);
+ gpuAddress = gpuAddress & ~0xFFF;
+ bytes = 4096;
+ }
+
+ gcmkPRINT("User Command Buffer:\n");
+ _DumpBuffer(entryDump, gpuAddress, bytes);
+
+ if (kernel->virtualCommandBuffer)
+ {
+ gcmkVERIFY_OK(gckOS_DestroyKernelVirtualMapping(
+ os, buffer->virtualBuffer.physical, buffer->virtualBuffer.bytes, entry));
+ }
+ else
+ {
+ gcmkVERIFY_OK(gckOS_UnmapPhysical(os, entry, 4096));
+ }
+ }
+ else
+ {
+ _DumpKernelCommandBuffer(Command);
+ }
+
+ /* Dump link queue. */
+ if (queue->count)
+ {
+ gcmkPRINT("Dump Level is %d, dump %d valid record in link queue:",
+ Command->kernel->stuckDump, queue->count);
+
+ dumpRear = queue->count;
+
+ for (i = 0; i < dumpRear; i++)
+ {
+ gckQUEUE_GetData(queue, i, &queueData);
+
+ linkData = &queueData->linkData;
+
+ /* Get gpu address of this command buffer. */
+ gpuAddress = linkData->start;
+ bytes = linkData->end - gpuAddress;
+
+ pid = linkData->pid;
+
+ gckOS_GetProcessNameByPid(pid, 16, processName);
+
+ if (kernel->virtualCommandBuffer)
+ {
+ buffer = gcvNULL;
+
+ /* Get the whole buffer. */
+ status = gckDEVICE_QueryGPUAddress(kernel->device, kernel, gpuAddress, &buffer);
+
+ if (gcmIS_ERROR(status))
+ {
+ /* Get kernel address of kernel command buffer. */
+ status = gckCOMMAND_AddressInKernelCommandBuffer(
+ kernel->command, gpuAddress, &entry);
+
+ if (gcmIS_ERROR(status))
+ {
+ status = gckHARDWARE_AddressInHardwareFuncions(
+ kernel->hardware, gpuAddress, &entry);
+
+ if (gcmIS_ERROR(status))
+ {
+ gcmkPRINT("Buffer [%08X - %08X] not found, may be freed",
+ linkData->start,
+ linkData->end);
+ continue;
+ }
+ }
+
+ offset = 0;
+ gcmkPRINT("Kernel Command Buffer: %08X, %08X", linkData->linkLow, linkData->linkHigh);
+ }
+ else
+ {
+ /* Get kernel logical for dump. */
+ if (buffer->virtualBuffer.kernelLogical)
+ {
+ /* Get kernel logical directly if it is a context buffer. */
+ entry = buffer->virtualBuffer.kernelLogical;
+ gcmkPRINT("Context Buffer: %08X, %08X PID:%d %s",
+ linkData->linkLow, linkData->linkHigh, linkData->pid, processName);
+ }
+ else
+ {
+ /* Make it accessiable by kernel if it is a user command buffer. */
+ gcmkVERIFY_OK(
+ gckOS_CreateKernelVirtualMapping(os,
+ buffer->virtualBuffer.physical,
+ buffer->virtualBuffer.bytes,
+ &entry,
+ &pageCount));
+ gcmkPRINT("User Command Buffer: %08X, %08X PID:%d %s",
+ linkData->linkLow, linkData->linkHigh, linkData->pid, processName);
+ }
+
+ offset = gpuAddress - buffer->virtualBuffer.gpuAddress;
+ }
+
+ /* Dump from the entry. */
+ _DumpBuffer((gctUINT8_PTR)entry + offset, gpuAddress, bytes);
+
+ /* Release kernel logical address if neccessary. */
+ if (buffer && !buffer->virtualBuffer.kernelLogical)
+ {
+ gcmkVERIFY_OK(
+ gckOS_DestroyKernelVirtualMapping(os,
+ buffer->virtualBuffer.physical,
+ buffer->virtualBuffer.bytes,
+ entry));
+ }
+ }
+ else
+ {
+ gcmkVERIFY_OK(gckOS_GPUPhysicalToCPUPhysical(os, gpuAddress, &cpuPhysical));
+
+ gcmkVERIFY_OK(gckOS_MapPhysical(os, (gctUINT32) cpuPhysical, bytes, &entry));
+
+ gcmkPRINT("Command Buffer: %08X, %08X PID:%d %s",
+ linkData->linkLow, linkData->linkHigh, linkData->pid, processName);
+
+ _DumpBuffer((gctUINT8_PTR)entry, gpuAddress, bytes);
+
+ gcmkVERIFY_OK(gckOS_UnmapPhysical(os, entry, bytes));
+ }
+ }
+ }
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckCOMMAND_AddressInKernelCommandBuffer(
+ IN gckCOMMAND Command,
+ IN gctUINT32 Address,
+ OUT gctPOINTER * Pointer
+ )
+{
+ gctINT i;
+
+ for (i = 0; i < gcdCOMMAND_QUEUES; i++)
+ {
+ if ((Address >= Command->queues[i].address)
+ && (Address < (Command->queues[i].address + Command->pageSize))
+ )
+ {
+ *Pointer = (gctUINT8_PTR)Command->queues[i].logical
+ + (Address - Command->queues[i].address)
+ ;
+
+ return gcvSTATUS_OK;
+ }
+ }
+
+ return gcvSTATUS_NOT_FOUND;
+}
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command_vg.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command_vg.c
new file mode 100644
index 000000000000..6167212eff38
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_command_vg.c
@@ -0,0 +1,3948 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#if gcdENABLE_VG
+
+#include "gc_hal_kernel_hardware_command_vg.h"
+
+#define _GC_OBJ_ZONE gcvZONE_COMMAND
+
+#ifdef __QNXNTO__
+extern gceSTATUS
+drv_signal_mgr_add(
+ gctUINT32 Pid,
+ gctINT32 Coid,
+ gctINT32 Rcvid,
+ gctUINT64 Signal,
+ gctPOINTER *Handle);
+#endif
+
+/******************************************************************************\
+*********************************** Debugging **********************************
+\******************************************************************************/
+
+#define gcvDISABLE_TIMEOUT 1
+#define gcvDUMP_COMMAND_BUFFER 0
+#define gcvDUMP_COMMAND_LINES 0
+
+
+#if gcvDEBUG || defined(EMULATOR) || gcvDISABLE_TIMEOUT
+# define gcvQUEUE_TIMEOUT ~0
+#else
+# define gcvQUEUE_TIMEOUT 10
+#endif
+
+
+/******************************************************************************\
+********************************** Definitions *********************************
+\******************************************************************************/
+
+/* Minimum buffer size. */
+#define gcvMINUMUM_BUFFER \
+ gcmSIZEOF(gcsKERNEL_QUEUE_HEADER) + \
+ gcmSIZEOF(gcsKERNEL_CMDQUEUE) * 2
+
+#define gcmDECLARE_INTERRUPT_HANDLER(Block, Number) \
+ static gceSTATUS \
+ _EventHandler_##Block##_##Number( \
+ IN gckVGKERNEL Kernel \
+ )
+
+#define gcmDEFINE_INTERRUPT_HANDLER(Block, Number) \
+ gcmDECLARE_INTERRUPT_HANDLER(Block, Number) \
+ { \
+ return _EventHandler_Block( \
+ Kernel, \
+ &Kernel->command->taskTable[gcvBLOCK_##Block], \
+ gcvFALSE \
+ ); \
+ }
+
+#define gcmDEFINE_INTERRUPT_HANDLER_ENTRY(Block, Number) \
+ { gcvBLOCK_##Block, _EventHandler_##Block##_##Number }
+
+/* Block interrupt handling table entry. */
+typedef struct _gcsBLOCK_INTERRUPT_HANDLER * gcsBLOCK_INTERRUPT_HANDLER_PTR;
+typedef struct _gcsBLOCK_INTERRUPT_HANDLER
+{
+ gceBLOCK block;
+ gctINTERRUPT_HANDLER handler;
+}
+gcsBLOCK_INTERRUPT_HANDLER;
+
+/* Queue control functions. */
+typedef struct _gcsQUEUE_UPDATE_CONTROL * gcsQUEUE_UPDATE_CONTROL_PTR;
+typedef struct _gcsQUEUE_UPDATE_CONTROL
+{
+ gctOBJECT_HANDLER execute;
+ gctOBJECT_HANDLER update;
+ gctOBJECT_HANDLER lastExecute;
+ gctOBJECT_HANDLER lastUpdate;
+}
+gcsQUEUE_UPDATE_CONTROL;
+
+
+/******************************************************************************\
+********************************* Support Code *********************************
+\******************************************************************************/
+static gceSTATUS
+_FlushMMU(
+ IN gckVGCOMMAND Command
+ )
+{
+ gceSTATUS status;
+ gctUINT32 oldValue;
+ gckVGHARDWARE hardware = Command->hardware;
+
+ gcmkONERROR(gckOS_AtomicExchange(Command->os,
+ hardware->pageTableDirty,
+ 0,
+ &oldValue));
+
+ if (oldValue)
+ {
+ /* Page Table is upated, flush mmu before commit. */
+ gcmkONERROR(gckVGHARDWARE_FlushMMU(hardware));
+ }
+
+ return gcvSTATUS_OK;
+OnError:
+ return status;
+}
+
+static gceSTATUS
+_WaitForIdle(
+ IN gckVGCOMMAND Command,
+ IN gcsKERNEL_QUEUE_HEADER_PTR Queue
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+ gctUINT32 idle;
+ gctUINT timeout = 0;
+
+ /* Loop while not idle. */
+ while (Queue->pending)
+ {
+ /* Did we reach the timeout limit? */
+ if (timeout == gcvQUEUE_TIMEOUT)
+ {
+ /* Hardware is probably dead... */
+ return gcvSTATUS_TIMEOUT;
+ }
+
+ /* Sleep for 100ms. */
+ gcmkERR_BREAK(gckOS_Delay(Command->os, 100));
+
+ /* Not the first loop? */
+ if (timeout > 0)
+ {
+ /* Read IDLE register. */
+ gcmkVERIFY_OK(gckVGHARDWARE_GetIdle(Command->hardware, &idle));
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_COMMAND,
+ "%s: timeout, IDLE=%08X\n",
+ __FUNCTION__, idle
+ );
+ }
+
+ /* Increment the timeout counter. */
+ timeout += 1;
+ }
+
+ /* Return status. */
+ return status;
+}
+
+static gctINT32
+_GetNextInterrupt(
+ IN gckVGCOMMAND Command,
+ IN gceBLOCK Block
+ )
+{
+ gctUINT index;
+ gcsBLOCK_TASK_ENTRY_PTR entry;
+ gctINT32 interrupt;
+
+ /* Get the block entry. */
+ entry = &Command->taskTable[Block];
+
+ /* Make sure we have initialized interrupts. */
+ gcmkASSERT(entry->interruptCount > 0);
+
+ /* Decrement the interrupt usage semaphore. */
+ gcmkVERIFY_OK(gckOS_DecrementSemaphore(
+ Command->os, entry->interruptSemaphore
+ ));
+
+ /* Get the value index. */
+ index = entry->interruptIndex;
+
+ /* Get the interrupt value. */
+ interrupt = entry->interruptArray[index];
+
+ /* Must be a valid value. */
+ gcmkASSERT((interrupt >= 0) && (interrupt <= 31));
+
+ /* Advance the index to the next value. */
+ index += 1;
+
+ /* Set the new index. */
+ entry->interruptIndex = (index == entry->interruptCount)
+ ? 0
+ : index;
+
+ /* Return interrupt value. */
+ return interrupt;
+}
+
+
+/******************************************************************************\
+***************************** Task Storage Management **************************
+\******************************************************************************/
+
+/* Minimum task buffer size. */
+#define gcvMIN_TASK_BUFFER \
+( \
+ gcmSIZEOF(gcsTASK_CONTAINER) + 128 \
+)
+
+/* Free list terminator. */
+#define gcvFREE_TASK_TERMINATOR \
+( \
+ (gcsTASK_CONTAINER_PTR) gcmINT2PTR(~0) \
+)
+
+
+/*----------------------------------------------------------------------------*/
+/*------------------- Allocated Task Buffer List Management ------------------*/
+
+static void
+_InsertTaskBuffer(
+ IN gcsTASK_CONTAINER_PTR AddAfter,
+ IN gcsTASK_CONTAINER_PTR Buffer
+ )
+{
+ gcsTASK_CONTAINER_PTR addBefore;
+
+ /* Cannot add before the first buffer. */
+ gcmkASSERT(AddAfter != gcvNULL);
+
+ /* Create a shortcut to the next buffer. */
+ addBefore = AddAfter->allocNext;
+
+ /* Initialize the links. */
+ Buffer->allocPrev = AddAfter;
+ Buffer->allocNext = addBefore;
+
+ /* Link to the previous buffer. */
+ AddAfter->allocNext = Buffer;
+
+ /* Link to the next buffer. */
+ if (addBefore != gcvNULL)
+ {
+ addBefore->allocPrev = Buffer;
+ }
+}
+
+static void
+_RemoveTaskBuffer(
+ IN gcsTASK_CONTAINER_PTR Buffer
+ )
+{
+ gcsTASK_CONTAINER_PTR prev;
+ gcsTASK_CONTAINER_PTR next;
+
+ /* Cannot remove the first buffer. */
+ gcmkASSERT(Buffer->allocPrev != gcvNULL);
+
+ /* Create shortcuts to the previous and next buffers. */
+ prev = Buffer->allocPrev;
+ next = Buffer->allocNext;
+
+ /* Tail buffer? */
+ if (next == gcvNULL)
+ {
+ /* Remove from the list. */
+ prev->allocNext = gcvNULL;
+ }
+
+ /* Buffer from the middle. */
+ else
+ {
+ prev->allocNext = next;
+ next->allocPrev = prev;
+ }
+}
+
+
+/*----------------------------------------------------------------------------*/
+/*--------------------- Free Task Buffer List Management ---------------------*/
+
+static void
+_AppendToFreeList(
+ IN gckVGCOMMAND Command,
+ IN gcsTASK_CONTAINER_PTR Buffer
+ )
+{
+ /* Cannot be a part of the free list already. */
+ gcmkASSERT(Buffer->freePrev == gcvNULL);
+ gcmkASSERT(Buffer->freeNext == gcvNULL);
+
+ /* First buffer to add? */
+ if (Command->taskFreeHead == gcvNULL)
+ {
+ /* Terminate the links. */
+ Buffer->freePrev = gcvFREE_TASK_TERMINATOR;
+ Buffer->freeNext = gcvFREE_TASK_TERMINATOR;
+
+ /* Initialize the list pointer. */
+ Command->taskFreeHead = Command->taskFreeTail = Buffer;
+ }
+
+ /* Not the first, add after the tail. */
+ else
+ {
+ /* Initialize the new tail buffer. */
+ Buffer->freePrev = Command->taskFreeTail;
+ Buffer->freeNext = gcvFREE_TASK_TERMINATOR;
+
+ /* Add after the tail. */
+ Command->taskFreeTail->freeNext = Buffer;
+ Command->taskFreeTail = Buffer;
+ }
+}
+
+static void
+_RemoveFromFreeList(
+ IN gckVGCOMMAND Command,
+ IN gcsTASK_CONTAINER_PTR Buffer
+ )
+{
+ /* Has to be a part of the free list. */
+ gcmkASSERT(Buffer->freePrev != gcvNULL);
+ gcmkASSERT(Buffer->freeNext != gcvNULL);
+
+ /* Head buffer? */
+ if (Buffer->freePrev == gcvFREE_TASK_TERMINATOR)
+ {
+ /* Tail buffer as well? */
+ if (Buffer->freeNext == gcvFREE_TASK_TERMINATOR)
+ {
+ /* Reset the list pointer. */
+ Command->taskFreeHead = Command->taskFreeTail = gcvNULL;
+ }
+
+ /* No, just the head. */
+ else
+ {
+ /* Update the head. */
+ Command->taskFreeHead = Buffer->freeNext;
+
+ /* Terminate the next buffer. */
+ Command->taskFreeHead->freePrev = gcvFREE_TASK_TERMINATOR;
+ }
+ }
+
+ /* Not the head. */
+ else
+ {
+ /* Tail buffer? */
+ if (Buffer->freeNext == gcvFREE_TASK_TERMINATOR)
+ {
+ /* Update the tail. */
+ Command->taskFreeTail = Buffer->freePrev;
+
+ /* Terminate the previous buffer. */
+ Command->taskFreeTail->freeNext = gcvFREE_TASK_TERMINATOR;
+ }
+
+ /* A buffer in the middle. */
+ else
+ {
+ /* Remove the buffer from the list. */
+ Buffer->freePrev->freeNext = Buffer->freeNext;
+ Buffer->freeNext->freePrev = Buffer->freePrev;
+ }
+ }
+
+ /* Reset free list pointers. */
+ Buffer->freePrev = gcvNULL;
+ Buffer->freeNext = gcvNULL;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/*-------------------------- Task Buffer Allocation --------------------------*/
+
+static void
+_SplitTaskBuffer(
+ IN gckVGCOMMAND Command,
+ IN gcsTASK_CONTAINER_PTR Buffer,
+ IN gctUINT Size
+ )
+{
+ /* Determine the size of the new buffer. */
+ gctINT splitBufferSize = Buffer->size - Size;
+ gcmkASSERT(splitBufferSize >= 0);
+
+ /* Is the split buffer big enough to become a separate buffer? */
+ if (splitBufferSize >= gcvMIN_TASK_BUFFER)
+ {
+ /* Place the new path data. */
+ gcsTASK_CONTAINER_PTR splitBuffer = (gcsTASK_CONTAINER_PTR)
+ (
+ (gctUINT8_PTR) Buffer + Size
+ );
+
+ /* Set the trimmed buffer size. */
+ Buffer->size = Size;
+
+ /* Initialize the split buffer. */
+ splitBuffer->referenceCount = 0;
+ splitBuffer->size = splitBufferSize;
+ splitBuffer->freePrev = gcvNULL;
+ splitBuffer->freeNext = gcvNULL;
+
+ /* Link in. */
+ _InsertTaskBuffer(Buffer, splitBuffer);
+ _AppendToFreeList(Command, splitBuffer);
+ }
+}
+
+static gceSTATUS
+_AllocateTaskContainer(
+ IN gckVGCOMMAND Command,
+ IN gctUINT Size,
+ OUT gcsTASK_CONTAINER_PTR * Buffer
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Command=0x%x Size=0x%x, Buffer ==0x%x", Command, Size, Buffer);
+
+ /* Verify arguments. */
+ gcmkVERIFY_ARGUMENT(Buffer != gcvNULL);
+
+ do
+ {
+ gcsTASK_STORAGE_PTR storage;
+ gcsTASK_CONTAINER_PTR buffer;
+
+ /* Adjust the size. */
+ Size += gcmSIZEOF(gcsTASK_CONTAINER);
+
+ /* Adjust the allocation size if not big enough. */
+ if (Size > Command->taskStorageUsable)
+ {
+ Command->taskStorageGranularity
+ = gcmALIGN(Size + gcmSIZEOF(gcsTASK_STORAGE), 1024);
+
+ Command->taskStorageUsable
+ = Command->taskStorageGranularity - gcmSIZEOF(gcsTASK_STORAGE);
+ }
+
+ /* Is there a free buffer available? */
+ else if (Command->taskFreeHead != gcvNULL)
+ {
+ /* Set the initial free buffer. */
+ gcsTASK_CONTAINER_PTR buffer = Command->taskFreeHead;
+
+ do
+ {
+ /* Is the buffer big enough? */
+ if (buffer->size >= Size)
+ {
+ /* Remove the buffer from the free list. */
+ _RemoveFromFreeList(Command, buffer);
+
+ /* Split the buffer. */
+ _SplitTaskBuffer(Command, buffer, Size);
+
+ /* Set the result. */
+ * Buffer = buffer;
+
+ gcmkFOOTER_ARG("*Buffer=0x%x",*Buffer);
+ /* Success. */
+ return gcvSTATUS_OK;
+ }
+
+ /* Get the next free buffer. */
+ buffer = buffer->freeNext;
+ }
+ while (buffer != gcvFREE_TASK_TERMINATOR);
+ }
+
+ /* Allocate a container. */
+ gcmkERR_BREAK(gckOS_Allocate(
+ Command->os,
+ Command->taskStorageGranularity,
+ (gctPOINTER *) &storage
+ ));
+
+ /* Link in the storage buffer. */
+ storage->next = Command->taskStorage;
+ Command->taskStorage = storage;
+
+ /* Place the task buffer. */
+ buffer = (gcsTASK_CONTAINER_PTR) (storage + 1);
+
+ /* Determine the size of the buffer. */
+ buffer->size
+ = Command->taskStorageGranularity
+ - gcmSIZEOF(gcsTASK_STORAGE);
+
+ /* Initialize the task buffer. */
+ buffer->referenceCount = 0;
+ buffer->allocPrev = gcvNULL;
+ buffer->allocNext = gcvNULL;
+ buffer->freePrev = gcvNULL;
+ buffer->freeNext = gcvNULL;
+
+ /* Split the buffer. */
+ _SplitTaskBuffer(Command, buffer, Size);
+
+ /* Set the result. */
+ * Buffer = buffer;
+
+ gcmkFOOTER_ARG("*Buffer=0x%x",*Buffer);
+ /* Success. */
+ return gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ gcmkFOOTER();
+ /* Return status. */
+ return status;
+}
+
+static void
+_FreeTaskContainer(
+ IN gckVGCOMMAND Command,
+ IN gcsTASK_CONTAINER_PTR Buffer
+ )
+{
+ gcsTASK_CONTAINER_PTR prev;
+ gcsTASK_CONTAINER_PTR next;
+ gcsTASK_CONTAINER_PTR merged;
+
+ gctUINT32 mergedSize;
+
+ /* Verify arguments. */
+ gcmkASSERT(Buffer != gcvNULL);
+ gcmkASSERT(Buffer->freePrev == gcvNULL);
+ gcmkASSERT(Buffer->freeNext == gcvNULL);
+
+ /* Get shortcuts to the previous and next path data buffers. */
+ prev = Buffer->allocPrev;
+ next = Buffer->allocNext;
+
+ /* Is the previous path data buffer already free? */
+ if (prev && prev->freeNext)
+ {
+ /* The previous path data buffer is the one that remains. */
+ merged = prev;
+
+ /* Is the next path data buffer already free? */
+ if (next && next->freeNext)
+ {
+ /* Merge all three path data buffers into the previous. */
+ mergedSize = prev->size + Buffer->size + next->size;
+
+ /* Remove the next path data buffer. */
+ _RemoveFromFreeList(Command, next);
+ _RemoveTaskBuffer(next);
+ }
+ else
+ {
+ /* Merge the current path data buffer into the previous. */
+ mergedSize = prev->size + Buffer->size;
+ }
+
+ /* Delete the current path data buffer. */
+ _RemoveTaskBuffer(Buffer);
+
+ /* Set new size. */
+ merged->size = mergedSize;
+ }
+ else
+ {
+ /* The current path data buffer is the one that remains. */
+ merged = Buffer;
+
+ /* Is the next buffer already free? */
+ if (next && next->freeNext)
+ {
+ /* Merge the next into the current. */
+ mergedSize = Buffer->size + next->size;
+
+ /* Remove the next buffer. */
+ _RemoveFromFreeList(Command, next);
+ _RemoveTaskBuffer(next);
+
+ /* Set new size. */
+ merged->size = mergedSize;
+ }
+
+ /* Add the current buffer into the free list. */
+ _AppendToFreeList(Command, merged);
+ }
+}
+
+gceSTATUS
+_RemoveRecordFromProcesDB(
+ IN gckVGCOMMAND Command,
+ IN gcsTASK_HEADER_PTR Task
+ )
+{
+ gceSTATUS status;
+ gcsTASK_PTR task = (gcsTASK_PTR)((gctUINT8_PTR)Task - sizeof(gcsTASK));
+ gcsTASK_FREE_VIDEO_MEMORY_PTR freeVideoMemory;
+ gcsTASK_UNLOCK_VIDEO_MEMORY_PTR unlockVideoMemory;
+ gctINT pid;
+ gctUINT32 size,id;
+ gctUINT32 handle;
+ gckKERNEL kernel = Command->kernel->kernel;
+ gckVIDMEM_NODE unlockNode = gcvNULL;
+ gckVIDMEM_NODE nodeObject = gcvNULL;
+ gceDATABASE_TYPE type;
+
+ /* Get the total size of all tasks. */
+
+ gcmkVERIFY_OK(gckOS_GetProcessID((gctUINT32_PTR)&pid));
+ gcmkVERIFY_OK(gckOS_ReadMappedPointer(Command->os, &task->size, &size));
+
+ do
+ {
+ gcmkVERIFY_OK(gckOS_ReadMappedPointer(Command->os, &Task->id, &id));
+ switch (id)
+ {
+ case gcvTASK_FREE_VIDEO_MEMORY:
+ freeVideoMemory = (gcsTASK_FREE_VIDEO_MEMORY_PTR)Task;
+
+ gcmkVERIFY_OK(gckOS_ReadMappedPointer(Command->os, &freeVideoMemory->node, &handle));
+
+ status = gckVIDMEM_HANDLE_Lookup(
+ Command->kernel->kernel,
+ pid,
+ handle,
+ &nodeObject);
+
+ if (gcmIS_ERROR(status))
+ {
+ return status;
+ }
+
+ gckVIDMEM_HANDLE_Dereference(kernel, pid, handle);
+ gcmkVERIFY_OK(gckOS_WriteMemory(Command->os, &freeVideoMemory->node, gcmALL_TO_UINT32(nodeObject)));
+
+ type = gcvDB_VIDEO_MEMORY
+ | (nodeObject->type << gcdDB_VIDEO_MEMORY_TYPE_SHIFT)
+ | (nodeObject->pool << gcdDB_VIDEO_MEMORY_POOL_SHIFT);
+
+ /* Remove record from process db. */
+ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+ Command->kernel->kernel,
+ pid,
+ type,
+ gcmINT2PTR(handle)));
+
+ /* Advance to next task. */
+ size -= sizeof(gcsTASK_FREE_VIDEO_MEMORY);
+ Task = (gcsTASK_HEADER_PTR)(freeVideoMemory + 1);
+
+ break;
+ case gcvTASK_UNLOCK_VIDEO_MEMORY:
+ unlockVideoMemory = (gcsTASK_UNLOCK_VIDEO_MEMORY_PTR)Task;
+
+ gcmkVERIFY_OK(gckOS_ReadMappedPointer(Command->os, &unlockVideoMemory->node, &handle));
+ /* Remove record from process db. */
+ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+ Command->kernel->kernel,
+ pid,
+ gcvDB_VIDEO_MEMORY_LOCKED,
+ gcmUINT64_TO_PTR(handle)));
+
+
+ status = gckVIDMEM_HANDLE_Lookup(
+ Command->kernel->kernel,
+ pid,
+ handle,
+ &unlockNode);
+
+ if (gcmIS_ERROR(status))
+ {
+ return status;
+ }
+
+ gckVIDMEM_HANDLE_Dereference(kernel, pid, handle);
+ gcmkVERIFY_OK(gckOS_WriteMemory(Command->os, &unlockVideoMemory->node, gcmALL_TO_UINT32(unlockNode)));
+
+ /* Advance to next task. */
+ size -= sizeof(gcsTASK_UNLOCK_VIDEO_MEMORY);
+ Task = (gcsTASK_HEADER_PTR)(unlockVideoMemory + 1);
+
+ break;
+ default:
+ /* Skip the whole task. */
+ size = 0;
+ break;
+ }
+ }
+ while(size);
+
+ return gcvSTATUS_OK;
+}
+
+/******************************************************************************\
+********************************* Task Scheduling ******************************
+\******************************************************************************/
+
+static gceSTATUS
+_ScheduleTasks(
+ IN gckVGCOMMAND Command,
+ IN gcsTASK_MASTER_TABLE_PTR TaskTable,
+ IN gctUINT8_PTR PreviousEnd
+ )
+{
+ gceSTATUS status;
+
+ do
+ {
+ gctINT block;
+ gcsTASK_CONTAINER_PTR container;
+ gcsTASK_MASTER_ENTRY_PTR userTaskEntry;
+ gcsBLOCK_TASK_ENTRY_PTR kernelTaskEntry;
+ gcsTASK_PTR userTask;
+ gcsTASK userTaskObject;
+ gctUINT8_PTR kernelTask;
+ gctINT32 interrupt;
+ gctUINT8_PTR eventCommand;
+ gctBOOL needCopy = gcvFALSE;
+ gctINT pid;
+#ifdef __QNXNTO__
+ gcsTASK_PTR oldUserTask = gcvNULL;
+ gctPOINTER pointer;
+#endif
+
+ /* Nothing to schedule? */
+ if (TaskTable->size == 0)
+ {
+ status = gcvSTATUS_OK;
+ break;
+ }
+
+ /* Acquire the mutex. */
+ gcmkERR_BREAK(gckOS_AcquireMutex(
+ Command->os,
+ Command->taskMutex,
+ gcvINFINITE
+ ));
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ "%s(%d)\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkVERIFY_OK(gckOS_GetProcessID((gctUINT32_PTR)&pid));
+ gcmkVERIFY_OK(gckOS_QueryNeedCopy(Command->os, pid, &needCopy));
+ do
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ " number of tasks scheduled = %d\n"
+ " size of event data in bytes = %d\n",
+ TaskTable->count,
+ TaskTable->size
+ );
+
+ /* Allocate task buffer. */
+ gcmkERR_BREAK(_AllocateTaskContainer(
+ Command,
+ TaskTable->size,
+ &container
+ ));
+
+ /* Determine the task data pointer. */
+ kernelTask = (gctUINT8_PTR) (container + 1);
+
+ /* Initialize the reference count. */
+ container->referenceCount = TaskTable->count;
+
+ /* Process tasks. */
+ for (block = gcvBLOCK_COUNT - 1; block >= 0; block -= 1)
+ {
+ /* Get the current user table entry. */
+ userTaskEntry = &TaskTable->table[block];
+
+ /* Are there tasks scheduled? */
+ if (userTaskEntry->head == gcvNULL)
+ {
+ /* No, skip to the next block. */
+ continue;
+ }
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ " processing tasks for block %d\n",
+ block
+ );
+
+ /* Get the current kernel table entry. */
+ kernelTaskEntry = &Command->taskTable[block];
+
+ /* Are there tasks for the current block scheduled? */
+ if (kernelTaskEntry->container == gcvNULL)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ " first task container for the block added\n",
+ block
+ );
+
+ /* Nothing yet, set the container buffer pointer. */
+ kernelTaskEntry->container = container;
+ kernelTaskEntry->task = (gcsTASK_HEADER_PTR) kernelTask;
+ }
+
+ /* Yes, append to the end. */
+ else
+ {
+ kernelTaskEntry->link->cotainer = container;
+ kernelTaskEntry->link->task = (gcsTASK_HEADER_PTR) kernelTask;
+ }
+
+ /* Set initial task. */
+ userTask = userTaskEntry->head;
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ " copying user tasks over to the kernel\n"
+ );
+
+ /* Copy tasks. */
+ do
+ {
+ gcsTASK_HEADER_PTR taskHeader;
+#ifdef __QNXNTO__
+ oldUserTask = userTask;
+
+ gcmkERR_BREAK(gckOS_MapUserPointer(
+ Command->os,
+ oldUserTask,
+ 0,
+ &pointer));
+
+ userTask = pointer;
+#endif
+ taskHeader = (gcsTASK_HEADER_PTR) (userTask + 1);
+ if(needCopy)
+ {
+ gcmkERR_BREAK(gckOS_CopyFromUserData(
+ Command->os,
+ &userTaskObject,
+ userTask,
+ gcmSIZEOF(gcsTASK)
+ ));
+ userTask = &userTaskObject;
+ }
+
+ gcmkVERIFY_OK(_RemoveRecordFromProcesDB(Command, taskHeader));
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ " task ID = %d, size = %d\n",
+ ((gcsTASK_HEADER_PTR) (userTask + 1))->id,
+ userTask->size
+ );
+
+ /* Copy the task data. */
+ if(needCopy)
+ {
+ gcmkERR_BREAK(gckOS_CopyFromUserData(
+ Command->os,
+ kernelTask,
+ taskHeader,
+ userTask->size
+ ));
+ }
+ else
+ {
+
+ gcmkERR_BREAK(gckOS_MemCopy(
+ kernelTask, taskHeader, userTask->size
+ ));
+ }
+#ifdef __QNXNTO__
+ if (taskHeader->id == gcvTASK_SIGNAL)
+ {
+ gcsTASK_SIGNAL_PTR taskSignal = (gcsTASK_SIGNAL_PTR)kernelTask;
+ gctPOINTER signal;
+ gctUINT32 pid;
+
+ gcmkVERIFY_OK(gckOS_GetProcessID(&pid));
+
+ taskSignal->coid = TaskTable->coid;
+ taskSignal->rcvid = TaskTable->rcvid;
+
+ gcmkERR_BREAK(drv_signal_mgr_add(
+ pid,
+ taskSignal->coid,
+ taskSignal->rcvid,
+ gcmPTR_TO_UINT64(taskSignal->signal),
+ &signal));
+
+ taskSignal->signal = signal;
+ }
+#endif
+
+ /* Advance to the next task. */
+ kernelTask += userTask->size;
+ userTask = userTask->next;
+
+#ifdef __QNXNTO__
+ gcmkERR_BREAK(gckOS_UnmapUserPointer(
+ Command->os,
+ oldUserTask,
+ 0,
+ pointer));
+#endif
+ }
+ while (userTask != gcvNULL);
+
+ /* Update link pointer in the header. */
+ kernelTaskEntry->link = (gcsTASK_LINK_PTR) kernelTask;
+
+ /* Initialize link task. */
+ kernelTaskEntry->link->id = gcvTASK_LINK;
+ kernelTaskEntry->link->cotainer = gcvNULL;
+ kernelTaskEntry->link->task = gcvNULL;
+
+ /* Advance the task data pointer. */
+ kernelTask += gcmSIZEOF(gcsTASK_LINK);
+ }
+ }
+ while (gcvFALSE);
+
+ /* Release the mutex. */
+ gcmkERR_BREAK(gckOS_ReleaseMutex(
+ Command->os,
+ Command->taskMutex
+ ));
+
+ /* Assign interrupts to the blocks. */
+ eventCommand = PreviousEnd;
+
+ for (block = gcvBLOCK_COUNT - 1; block >= 0; block -= 1)
+ {
+ /* Get the current user table entry. */
+ userTaskEntry = &TaskTable->table[block];
+
+ /* Are there tasks scheduled? */
+ if (userTaskEntry->head == gcvNULL)
+ {
+ /* No, skip to the next block. */
+ continue;
+ }
+
+ /* Get the interrupt number. */
+ interrupt = _GetNextInterrupt(Command, block);
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ "%s(%d): block = %d interrupt = %d\n",
+ __FUNCTION__, __LINE__,
+ block, interrupt
+ );
+
+ /* Determine the command position. */
+ eventCommand -= Command->info.eventCommandSize;
+
+ /* Append an EVENT command. */
+ gcmkERR_BREAK(gckVGCOMMAND_EventCommand(
+ Command, eventCommand, block, interrupt, gcvNULL
+ ));
+ }
+ }
+ while (gcvFALSE);
+
+ /* Return status. */
+ return status;
+}
+
+
+/******************************************************************************\
+******************************** Memory Management *****************************
+\******************************************************************************/
+
+static gceSTATUS
+_HardwareToKernel(
+ IN gckOS Os,
+ IN gcuVIDMEM_NODE_PTR Node,
+ IN gctUINT32 Address,
+ OUT gctPOINTER * KernelPointer
+ )
+{
+ gceSTATUS status;
+ gckVIDMEM memory;
+ gctUINT32 offset;
+ gctUINT32 nodePhysical;
+ gctPOINTER *logical;
+ gctSIZE_T bytes;
+ status = gcvSTATUS_OK;
+
+ memory = Node->VidMem.memory;
+
+ if (memory->object.type == gcvOBJ_VIDMEM)
+ {
+ nodePhysical = memory->baseAddress
+ + (gctUINT32)Node->VidMem.offset
+ + Node->VidMem.alignment;
+ bytes = Node->VidMem.bytes;
+ logical = &Node->VidMem.kernelVirtual;
+ }
+ else
+ {
+ gcmkSAFECASTPHYSADDRT(nodePhysical, Node->Virtual.physicalAddress);
+ bytes = Node->Virtual.bytes;
+ logical = &Node->Virtual.kernelVirtual;
+ }
+
+ if (*logical == gcvNULL)
+ {
+ status = gckOS_MapPhysical(Os, nodePhysical, bytes, logical);
+
+ if (gcmkIS_ERROR(status))
+ {
+ return status;
+ }
+ }
+
+ offset = Address - nodePhysical;
+ *KernelPointer = (gctPOINTER)((gctUINT8_PTR)(*logical) + offset);
+
+ /* Return status. */
+ return status;
+}
+
+static gceSTATUS
+_ConvertUserCommandBufferPointer(
+ IN gckVGCOMMAND Command,
+ IN gcsCMDBUFFER_PTR UserCommandBuffer,
+ OUT gcsCMDBUFFER_PTR * KernelCommandBuffer
+ )
+{
+ gceSTATUS status, last;
+ gcsCMDBUFFER_PTR mappedUserCommandBuffer = gcvNULL;
+ gcsCMDBUFFER _CommandBufferObject;
+ gckKERNEL kernel = Command->kernel->kernel;
+ gctUINT32 pid;
+ gckVIDMEM_NODE node;
+ gctBOOL needCopy = gcvFALSE;
+
+ gckOS_GetProcessID(&pid);
+
+ do
+ {
+ gctUINT32 headerAddress;
+
+ gcmkERR_BREAK(gckOS_QueryNeedCopy(Command->os, pid, &needCopy));
+ if(needCopy)
+ {
+ gcmkERR_BREAK(gckOS_CopyFromUserData(
+ Command->os,
+ &_CommandBufferObject,
+ UserCommandBuffer,
+ gcmSIZEOF(gcsCMDBUFFER)
+ ));
+ mappedUserCommandBuffer = &_CommandBufferObject;
+ }
+ else
+ {
+ /* Map the command buffer structure into the kernel space. */
+ gcmkERR_BREAK(gckOS_MapUserPointer(
+ Command->os,
+ UserCommandBuffer,
+ gcmSIZEOF(gcsCMDBUFFER),
+ (gctPOINTER *) &mappedUserCommandBuffer
+ ));
+ }
+ /* Determine the address of the header. */
+ headerAddress
+ = mappedUserCommandBuffer->address
+ - mappedUserCommandBuffer->bufferOffset;
+
+ gcmkERR_BREAK(gckVIDMEM_HANDLE_Lookup(
+ kernel,
+ pid,
+ gcmPTR2INT32(mappedUserCommandBuffer->node),
+ &node));
+
+ /* Translate the logical address to the kernel space. */
+ gcmkERR_BREAK(_HardwareToKernel(
+ Command->os,
+ node->node,
+ headerAddress,
+ (gctPOINTER *) KernelCommandBuffer
+ ));
+ }
+ while (gcvFALSE);
+
+ /* Unmap the user command buffer. */
+ if (mappedUserCommandBuffer != gcvNULL && needCopy == gcvFALSE)
+ {
+ gcmkCHECK_STATUS(gckOS_UnmapUserPointer(
+ Command->os,
+ UserCommandBuffer,
+ gcmSIZEOF(gcsCMDBUFFER),
+ mappedUserCommandBuffer
+ ));
+ }
+
+ /* Return status. */
+ return status;
+}
+
+static gceSTATUS
+_AllocateLinear(
+ IN gckVGCOMMAND Command,
+ IN gctUINT Size,
+ IN gctUINT Alignment,
+ OUT gcuVIDMEM_NODE_PTR * Node,
+ OUT gctUINT32 * Address,
+ OUT gctPOINTER * Logical
+ )
+{
+ gceSTATUS status, last;
+ gctPOINTER logical;
+ gctPHYS_ADDR physical;
+ gctUINT32 address;
+ gctSIZE_T size = Size;
+ gctPHYS_ADDR_T paddr;
+
+ do
+ {
+ gcmkERR_BREAK(gckOS_AllocateContiguous(
+ Command->os,
+ gcvFALSE,
+ &size,
+ &physical,
+ &logical
+ ));
+
+ gcmkERR_BREAK(gckOS_GetPhysicalAddress(Command->os, logical, &paddr));
+
+ gcmkSAFECASTPHYSADDRT(address, paddr);
+
+ /* Set return values. */
+ * Node = physical;
+ * Address = address;
+ * Logical = logical;
+
+ /* Success. */
+ return gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ /* Roll back. */
+ if (physical != gcvNULL)
+ {
+ /* Free the command buffer. */
+ gcmkCHECK_STATUS(gckOS_FreeContiguous(Command->os, physical, logical, size));
+ }
+
+ /* Return status. */
+ return status;
+}
+
+static gceSTATUS
+_FreeLinear(
+ IN gckVGKERNEL Kernel,
+ IN gcuVIDMEM_NODE_PTR Node,
+ IN gctPOINTER Logical
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+
+ do
+ {
+ gcmkERR_BREAK(gckOS_FreeContiguous(Kernel->os, Node, Logical, 1));
+ }
+ while (gcvFALSE);
+
+ /* Return status. */
+ return status;
+}
+
+gceSTATUS
+_AllocateCommandBuffer(
+ IN gckVGCOMMAND Command,
+ IN gctSIZE_T Size,
+ OUT gcsCMDBUFFER_PTR * CommandBuffer
+ )
+{
+ gceSTATUS status, last;
+ gcuVIDMEM_NODE_PTR node = gcvNULL;
+ gcsCMDBUFFER_PTR commandBuffer = gcvNULL;
+
+ do
+ {
+ gctUINT alignedHeaderSize;
+ gctUINT requestedSize;
+ gctUINT allocationSize;
+ gctUINT32 address = 0;
+ gctUINT8_PTR endCommand;
+
+ /* Determine the aligned header size. */
+ alignedHeaderSize
+ = (gctUINT32)gcmALIGN(gcmSIZEOF(gcsCMDBUFFER), Command->info.addressAlignment);
+
+ /* Align the requested size. */
+ requestedSize
+ = (gctUINT32)gcmALIGN(Size, Command->info.commandAlignment);
+
+ /* Determine the size of the buffer to allocate. */
+ allocationSize
+ = alignedHeaderSize
+ + requestedSize
+ + (gctUINT32)Command->info.staticTailSize;
+
+ /* Allocate the command buffer. */
+ gcmkERR_BREAK(_AllocateLinear(
+ Command,
+ allocationSize,
+ Command->info.addressAlignment,
+ &node,
+ &address,
+ (gctPOINTER *) &commandBuffer
+ ));
+
+ /* Initialize the structure. */
+ commandBuffer->completion = gcvVACANT_BUFFER;
+ commandBuffer->node = node;
+ commandBuffer->address = address + alignedHeaderSize;
+ commandBuffer->bufferOffset = alignedHeaderSize;
+ commandBuffer->size = requestedSize;
+ commandBuffer->offset = requestedSize;
+ commandBuffer->nextAllocated = gcvNULL;
+ commandBuffer->nextSubBuffer = gcvNULL;
+
+ /* Determine the data count. */
+ commandBuffer->dataCount
+ = (requestedSize + Command->info.staticTailSize)
+ / Command->info.commandAlignment;
+
+ /* Determine the location of the END command. */
+ endCommand
+ = (gctUINT8_PTR) commandBuffer
+ + alignedHeaderSize
+ + requestedSize;
+
+ /* Append an END command. */
+ gcmkERR_BREAK(gckVGCOMMAND_EndCommand(
+ Command,
+ endCommand,
+ Command->info.feBufferInt,
+ gcvNULL
+ ));
+
+ /* Set the return pointer. */
+ * CommandBuffer = commandBuffer;
+
+ /* Success. */
+ return gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ /* Roll back. */
+ if (node != gcvNULL)
+ {
+ /* Free the command buffer. */
+ gcmkCHECK_STATUS(_FreeLinear(Command->kernel, node, commandBuffer));
+ }
+
+ /* Return status. */
+ return status;
+}
+
+static gceSTATUS
+_FreeCommandBuffer(
+ IN gckVGKERNEL Kernel,
+ IN gcsCMDBUFFER_PTR CommandBuffer
+ )
+{
+ gceSTATUS status;
+
+ /* Free the buffer. */
+ status = _FreeLinear(Kernel, CommandBuffer->node, CommandBuffer);
+
+ /* Return status. */
+ return status;
+}
+
+
+/******************************************************************************\
+****************************** TS Overflow Handler *****************************
+\******************************************************************************/
+
+static gceSTATUS
+_EventHandler_TSOverflow(
+ IN gckVGKERNEL Kernel
+ )
+{
+ gcmkTRACE(
+ gcvLEVEL_ERROR,
+ "%s(%d): **** TS OVERFLOW ENCOUNTERED ****\n",
+ __FUNCTION__, __LINE__
+ );
+
+ return gcvSTATUS_OK;
+}
+
+
+/******************************************************************************\
+****************************** Bus Error Handler *******************************
+\******************************************************************************/
+
+static gceSTATUS
+_EventHandler_BusError(
+ IN gckVGKERNEL Kernel
+ )
+{
+ gcmkTRACE(
+ gcvLEVEL_ERROR,
+ "%s(%d): **** BUS ERROR ENCOUNTERED ****\n",
+ __FUNCTION__, __LINE__
+ );
+
+ return gcvSTATUS_OK;
+}
+
+/******************************************************************************\
+****************************** Power Stall Handler *******************************
+\******************************************************************************/
+
+static gceSTATUS
+_EventHandler_PowerStall(
+ IN gckVGKERNEL Kernel
+ )
+{
+ /* Signal. */
+ return gckOS_Signal(
+ Kernel->os,
+ Kernel->command->powerStallSignal,
+ gcvTRUE);
+}
+
+/******************************************************************************\
+******************************** Task Routines *********************************
+\******************************************************************************/
+
+typedef gceSTATUS (* gctTASKROUTINE) (
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ );
+
+static gceSTATUS
+_TaskLink(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ );
+
+static gceSTATUS
+_TaskCluster(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ );
+
+static gceSTATUS
+_TaskIncrement(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ );
+
+static gceSTATUS
+_TaskDecrement(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ );
+
+static gceSTATUS
+_TaskSignal(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ );
+
+static gceSTATUS
+_TaskLockdown(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ );
+
+static gceSTATUS
+_TaskUnlockVideoMemory(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ );
+
+static gceSTATUS
+_TaskFreeVideoMemory(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ );
+
+static gceSTATUS
+_TaskFreeContiguousMemory(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ );
+
+static gceSTATUS
+_TaskUnmapUserMemory(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ );
+
+static gctTASKROUTINE _taskRoutine[] =
+{
+ _TaskLink, /* gcvTASK_LINK */
+ _TaskCluster, /* gcvTASK_CLUSTER */
+ _TaskIncrement, /* gcvTASK_INCREMENT */
+ _TaskDecrement, /* gcvTASK_DECREMENT */
+ _TaskSignal, /* gcvTASK_SIGNAL */
+ _TaskLockdown, /* gcvTASK_LOCKDOWN */
+ _TaskUnlockVideoMemory, /* gcvTASK_UNLOCK_VIDEO_MEMORY */
+ _TaskFreeVideoMemory, /* gcvTASK_FREE_VIDEO_MEMORY */
+ _TaskFreeContiguousMemory, /* gcvTASK_FREE_CONTIGUOUS_MEMORY */
+ _TaskUnmapUserMemory, /* gcvTASK_UNMAP_USER_MEMORY */
+};
+
+static gceSTATUS
+_TaskLink(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ )
+{
+ /* Cast the task pointer. */
+ gcsTASK_LINK_PTR task = (gcsTASK_LINK_PTR) TaskHeader->task;
+
+ /* Save the pointer to the container. */
+ gcsTASK_CONTAINER_PTR container = TaskHeader->container;
+
+ /* No more tasks in the list? */
+ if (task->task == gcvNULL)
+ {
+ /* Reset the entry. */
+ TaskHeader->container = gcvNULL;
+ TaskHeader->task = gcvNULL;
+ TaskHeader->link = gcvNULL;
+ }
+ else
+ {
+ /* Update the entry. */
+ TaskHeader->container = task->cotainer;
+ TaskHeader->task = task->task;
+ }
+
+ /* Decrement the task buffer reference. */
+ gcmkASSERT(container->referenceCount >= 0);
+ if (container->referenceCount == 0)
+ {
+ /* Free the container. */
+ _FreeTaskContainer(Command, container);
+ }
+
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_TaskCluster(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+
+ /* Cast the task pointer. */
+ gcsTASK_CLUSTER_PTR cluster = (gcsTASK_CLUSTER_PTR) TaskHeader->task;
+
+ /* Get the number of tasks. */
+ gctUINT taskCount = cluster->taskCount;
+
+ /* Advance to the next task. */
+ TaskHeader->task = (gcsTASK_HEADER_PTR) (cluster + 1);
+
+ /* Perform all tasks in the cluster. */
+ while (taskCount)
+ {
+ /* Perform the current task. */
+ gcmkERR_BREAK(_taskRoutine[TaskHeader->task->id](
+ Command,
+ TaskHeader
+ ));
+
+ /* Update the task count. */
+ taskCount -= 1;
+ }
+
+ /* Return status. */
+ return status;
+}
+
+static gceSTATUS
+_TaskIncrement(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ )
+{
+ gceSTATUS status;
+
+ do
+ {
+ /* Cast the task pointer. */
+ gcsTASK_INCREMENT_PTR task = (gcsTASK_INCREMENT_PTR) TaskHeader->task;
+
+ /* Convert physical into logical address. */
+ gctUINT32_PTR logical;
+ gcmkERR_BREAK(gckOS_MapPhysical(
+ Command->os,
+ task->address,
+ gcmSIZEOF(gctUINT32),
+ (gctPOINTER *) &logical
+ ));
+
+ /* Increment data. */
+ (* logical) += 1;
+
+ /* Unmap the physical memory. */
+ gcmkERR_BREAK(gckOS_UnmapPhysical(
+ Command->os,
+ logical,
+ gcmSIZEOF(gctUINT32)
+ ));
+
+ /* Update the reference counter. */
+ TaskHeader->container->referenceCount -= 1;
+
+ /* Update the task pointer. */
+ TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
+ }
+ while (gcvFALSE);
+
+ /* Return status. */
+ return status;
+}
+
+static gceSTATUS
+_TaskDecrement(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ )
+{
+ gceSTATUS status;
+
+ do
+ {
+ /* Cast the task pointer. */
+ gcsTASK_DECREMENT_PTR task = (gcsTASK_DECREMENT_PTR) TaskHeader->task;
+
+ /* Convert physical into logical address. */
+ gctUINT32_PTR logical;
+ gcmkERR_BREAK(gckOS_MapPhysical(
+ Command->os,
+ task->address,
+ gcmSIZEOF(gctUINT32),
+ (gctPOINTER *) &logical
+ ));
+
+ /* Decrement data. */
+ (* logical) -= 1;
+
+ /* Unmap the physical memory. */
+ gcmkERR_BREAK(gckOS_UnmapPhysical(
+ Command->os,
+ logical,
+ gcmSIZEOF(gctUINT32)
+ ));
+
+ /* Update the reference counter. */
+ TaskHeader->container->referenceCount -= 1;
+
+ /* Update the task pointer. */
+ TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
+ }
+ while (gcvFALSE);
+
+ /* Return status. */
+ return status;
+}
+
+static gceSTATUS
+_TaskSignal(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ )
+{
+ gceSTATUS status;
+
+ do
+ {
+ /* Cast the task pointer. */
+ gcsTASK_SIGNAL_PTR task = (gcsTASK_SIGNAL_PTR) TaskHeader->task;
+
+
+ /* Map the signal into kernel space. */
+#ifdef __QNXNTO__
+ status = gckOS_UserSignal(
+ Command->os, task->signal, task->rcvid, task->coid
+ );
+#else
+ status = gckOS_UserSignal(
+ Command->os, task->signal, task->process
+ );
+#endif /* __QNXNTO__ */
+
+ if (gcmIS_ERROR(status))
+ {
+ if (status == gcvSTATUS_NOT_FOUND)
+ {
+ status = gcvSTATUS_OK;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ /* Update the reference counter. */
+ TaskHeader->container->referenceCount -= 1;
+
+ /* Update the task pointer. */
+ TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
+ }
+ while (gcvFALSE);
+
+ /* Return status. */
+ return status;
+}
+
+static gceSTATUS
+_TaskLockdown(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ )
+{
+ gceSTATUS status;
+ gctUINT32_PTR userCounter = gcvNULL;
+ gctUINT32_PTR kernelCounter = gcvNULL;
+ gctSIGNAL signal = gcvNULL;
+
+ do
+ {
+ /* Cast the task pointer. */
+ gcsTASK_LOCKDOWN_PTR task = (gcsTASK_LOCKDOWN_PTR) TaskHeader->task;
+
+ /* Convert physical addresses into logical. */
+ gcmkERR_BREAK(gckOS_MapPhysical(
+ Command->os,
+ task->userCounter,
+ gcmSIZEOF(gctUINT32),
+ (gctPOINTER *) &userCounter
+ ));
+
+ gcmkERR_BREAK(gckOS_MapPhysical(
+ Command->os,
+ task->kernelCounter,
+ gcmSIZEOF(gctUINT32),
+ (gctPOINTER *) &kernelCounter
+ ));
+
+ /* Update the kernel counter. */
+ (* kernelCounter) += 1;
+
+ /* Are the counters equal? */
+ if ((* userCounter) == (* kernelCounter))
+ {
+ /* Map the signal into kernel space. */
+ gcmkERR_BREAK(gckOS_MapSignal(
+ Command->os, task->signal, task->process, &signal
+ ));
+
+ if (signal == gcvNULL)
+ {
+ /* Signal. */
+ gcmkERR_BREAK(gckOS_Signal(
+ Command->os, task->signal, gcvTRUE
+ ));
+ }
+ else
+ {
+ /* Signal. */
+ gcmkERR_BREAK(gckOS_Signal(
+ Command->os, signal, gcvTRUE
+ ));
+ }
+ }
+
+ /* Update the reference counter. */
+ TaskHeader->container->referenceCount -= 1;
+
+ /* Update the task pointer. */
+ TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
+ }
+ while (gcvFALSE);
+
+ /* Destroy the mapped signal. */
+ if (signal != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_DestroySignal(
+ Command->os, signal
+ ));
+ }
+
+ /* Unmap the physical memory. */
+ if (kernelCounter != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_UnmapPhysical(
+ Command->os,
+ kernelCounter,
+ gcmSIZEOF(gctUINT32)
+ ));
+ }
+
+ if (userCounter != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_UnmapPhysical(
+ Command->os,
+ userCounter,
+ gcmSIZEOF(gctUINT32)
+ ));
+ }
+
+ /* Return status. */
+ return status;
+}
+
+static gceSTATUS
+_TaskUnlockVideoMemory(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ )
+{
+ gceSTATUS status;
+
+ do
+ {
+ /* Cast the task pointer. */
+ gcsTASK_UNLOCK_VIDEO_MEMORY_PTR task
+ = (gcsTASK_UNLOCK_VIDEO_MEMORY_PTR) TaskHeader->task;
+
+ /* Unlock video memory. */
+ gcmkERR_BREAK(gckVIDMEM_Unlock(
+ Command->kernel->kernel,
+ (gckVIDMEM_NODE)gcmUINT64_TO_PTR(task->node),
+ gcvSURF_TYPE_UNKNOWN,
+ gcvNULL));
+
+ gcmkERR_BREAK(gckVIDMEM_NODE_Dereference(
+ Command->kernel->kernel,
+ gcmUINT64_TO_PTR(task->node)));
+
+ /* Update the reference counter. */
+ TaskHeader->container->referenceCount -= 1;
+
+ /* Update the task pointer. */
+ TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
+ }
+ while (gcvFALSE);
+
+ /* Return status. */
+ return status;
+}
+
+static gceSTATUS
+_TaskFreeVideoMemory(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ )
+{
+ gceSTATUS status;
+
+ do
+ {
+ /* Cast the task pointer. */
+ gcsTASK_FREE_VIDEO_MEMORY_PTR task
+ = (gcsTASK_FREE_VIDEO_MEMORY_PTR) TaskHeader->task;
+
+ /* Free video memory. */
+ gcmkERR_BREAK(gckVIDMEM_NODE_Dereference(
+ Command->kernel->kernel,
+ gcmINT2PTR(task->node)));
+
+ /* Update the reference counter. */
+ TaskHeader->container->referenceCount -= 1;
+
+ /* Update the task pointer. */
+ TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
+ }
+ while (gcvFALSE);
+
+ /* Return status. */
+ return status;
+}
+
+static gceSTATUS
+_TaskFreeContiguousMemory(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ )
+{
+ gceSTATUS status;
+
+ do
+ {
+ /* Cast the task pointer. */
+ gcsTASK_FREE_CONTIGUOUS_MEMORY_PTR task
+ = (gcsTASK_FREE_CONTIGUOUS_MEMORY_PTR) TaskHeader->task;
+
+ /* Free contiguous memory. */
+ gcmkERR_BREAK(gckOS_FreeContiguous(
+ Command->os, task->physical, task->logical, task->bytes
+ ));
+
+ /* Update the reference counter. */
+ TaskHeader->container->referenceCount -= 1;
+
+ /* Update the task pointer. */
+ TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
+ }
+ while (gcvFALSE);
+
+ /* Return status. */
+ return status;
+}
+
+static gceSTATUS
+_TaskUnmapUserMemory(
+ gckVGCOMMAND Command,
+ gcsBLOCK_TASK_ENTRY_PTR TaskHeader
+ )
+{
+ gceSTATUS status;
+ gctPOINTER info;
+
+ do
+ {
+ /* Cast the task pointer. */
+ gcsTASK_UNMAP_USER_MEMORY_PTR task
+ = (gcsTASK_UNMAP_USER_MEMORY_PTR) TaskHeader->task;
+
+ info = gckKERNEL_QueryPointerFromName(
+ Command->kernel->kernel, gcmALL_TO_UINT32(task->info));
+
+ /* Unmap the user memory. */
+ gcmkERR_BREAK(gckOS_UnmapUserMemory(
+ Command->os, gcvCORE_VG, task->memory, task->size, info, task->address
+ ));
+
+ /* Update the reference counter. */
+ TaskHeader->container->referenceCount -= 1;
+
+ /* Update the task pointer. */
+ TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1);
+ }
+ while (gcvFALSE);
+
+ /* Return status. */
+ return status;
+}
+
+/******************************************************************************\
+************ Hardware Block Interrupt Handlers For Scheduled Events ************
+\******************************************************************************/
+
+static gceSTATUS
+_EventHandler_Block(
+ IN gckVGKERNEL Kernel,
+ IN gcsBLOCK_TASK_ENTRY_PTR TaskHeader,
+ IN gctBOOL ProcessAll
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK, last;
+
+ gcmkHEADER_ARG("Kernel=0x%x TaskHeader=0x%x ProcessAll=0x%x", Kernel, TaskHeader, ProcessAll);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+ if (TaskHeader->task == gcvNULL)
+ {
+ gcmkFOOTER();
+ return gcvSTATUS_OK;
+ }
+
+ do
+ {
+ gckVGCOMMAND command;
+
+ /* Get the command buffer object. */
+ command = Kernel->command;
+
+ /* Increment the interrupt usage semaphore. */
+ gcmkERR_BREAK(gckOS_IncrementSemaphore(
+ command->os, TaskHeader->interruptSemaphore
+ ));
+
+ /* Acquire the mutex. */
+ gcmkERR_BREAK(gckOS_AcquireMutex(
+ command->os,
+ command->taskMutex,
+ gcvINFINITE
+ ));
+
+ /* Verify inputs. */
+ gcmkASSERT(TaskHeader != gcvNULL);
+ gcmkASSERT(TaskHeader->container != gcvNULL);
+ gcmkASSERT(TaskHeader->task != gcvNULL);
+ gcmkASSERT(TaskHeader->link != gcvNULL);
+
+ /* Process tasks. */
+ do
+ {
+ /* Process the current task. */
+ gcmkERR_BREAK(_taskRoutine[TaskHeader->task->id](
+ command,
+ TaskHeader
+ ));
+
+ /* Is the next task is LINK? */
+ if (TaskHeader->task->id == gcvTASK_LINK)
+ {
+ gcmkERR_BREAK(_taskRoutine[TaskHeader->task->id](
+ command,
+ TaskHeader
+ ));
+
+ /* Done. */
+ break;
+ }
+ }
+ while (ProcessAll);
+
+ /* Release the mutex. */
+ gcmkCHECK_STATUS(gckOS_ReleaseMutex(
+ command->os,
+ command->taskMutex
+ ));
+ }
+ while (gcvFALSE);
+
+ gcmkFOOTER();
+ /* Return status. */
+ return status;
+}
+
+gcmDECLARE_INTERRUPT_HANDLER(COMMAND, 0)
+{
+ gceSTATUS status, last;
+
+ gcmkHEADER_ARG("Kernel=0x%x ", Kernel);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+
+ do
+ {
+ gckVGCOMMAND command;
+ gcsKERNEL_QUEUE_HEADER_PTR mergeQueue;
+ gcsKERNEL_QUEUE_HEADER_PTR queueTail;
+ gcsKERNEL_CMDQUEUE_PTR entry;
+ gctUINT entryCount;
+
+ /* Get the command buffer object. */
+ command = Kernel->command;
+
+ /* Acquire the mutex. */
+ gcmkERR_BREAK(gckOS_AcquireMutex(
+ command->os,
+ command->queueMutex,
+ gcvINFINITE
+ ));
+
+ /* Get the current queue. */
+ queueTail = command->queueTail;
+
+ /* Get the current queue entry. */
+ entry = queueTail->currentEntry;
+
+ /* Get the number of entries in the queue. */
+ entryCount = queueTail->pending;
+
+ /* Process all entries. */
+ while (entryCount > 0)
+ {
+ /* Call post-execution function. */
+ status = entry->handler(Kernel, entry);
+
+ /* Failed? */
+ if (gcmkIS_ERROR(status))
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR,
+ gcvZONE_COMMAND,
+ "[%s] line %d: post action failed.\n",
+ __FUNCTION__, __LINE__
+ );
+ }
+
+ /* Executed the next buffer? */
+ if (status == gcvSTATUS_EXECUTED)
+ {
+ /* Update the queue. */
+ queueTail->pending = entryCount;
+ queueTail->currentEntry = entry;
+
+ /* Success. */
+ status = gcvSTATUS_OK;
+
+ /* Break out of the loop. */
+ break;
+ }
+
+ /* Advance to the next entry. */
+ entry += 1;
+ entryCount -= 1;
+
+ /* Last entry? */
+ if (entryCount == 0)
+ {
+ /* Reset the queue to idle. */
+ queueTail->pending = 0;
+
+ /* Get a shortcut to the queue to merge with. */
+ mergeQueue = command->mergeQueue;
+
+ /* Merge the queues if necessary. */
+ if (mergeQueue != queueTail)
+ {
+ gcmkASSERT(mergeQueue < queueTail);
+ gcmkASSERT(mergeQueue->next == queueTail);
+
+ mergeQueue->size
+ += gcmSIZEOF(gcsKERNEL_QUEUE_HEADER)
+ + queueTail->size;
+
+ mergeQueue->next = queueTail->next;
+ }
+
+ /* Advance to the next queue. */
+ queueTail = queueTail->next;
+
+ /* Did it wrap around? */
+ if (command->queue == queueTail)
+ {
+ /* Reset merge queue. */
+ command->mergeQueue = queueTail;
+ }
+
+ /* Set new queue. */
+ command->queueTail = queueTail;
+
+ /* Is the next queue scheduled? */
+ if (queueTail->pending > 0)
+ {
+ gcsCMDBUFFER_PTR commandBuffer;
+
+ /* The first entry must be a command buffer. */
+ commandBuffer = queueTail->currentEntry->commandBuffer;
+
+ /* Start the command processor. */
+ status = gckVGHARDWARE_Execute(
+ command->hardware,
+ commandBuffer->address,
+ commandBuffer->dataCount
+ );
+
+ /* Failed? */
+ if (gcmkIS_ERROR(status))
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR,
+ gcvZONE_COMMAND,
+ "[%s] line %d: failed to start the next queue.\n",
+ __FUNCTION__, __LINE__
+ );
+ }
+ }
+ else
+ {
+ status = gckVGHARDWARE_SetPowerManagementState(
+ Kernel->command->hardware, gcvPOWER_IDLE_BROADCAST
+ );
+ }
+
+ /* Break out of the loop. */
+ break;
+ }
+ }
+
+ /* Release the mutex. */
+ gcmkCHECK_STATUS(gckOS_ReleaseMutex(
+ command->os,
+ command->queueMutex
+ ));
+ }
+ while (gcvFALSE);
+
+
+ gcmkFOOTER();
+ /* Return status. */
+ return status;
+}
+
+/* Define standard block interrupt handlers. */
+gcmDEFINE_INTERRUPT_HANDLER(TESSELLATOR, 0)
+gcmDEFINE_INTERRUPT_HANDLER(VG, 0)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 0)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 1)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 2)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 3)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 4)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 5)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 6)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 7)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 8)
+gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 9)
+
+/* The entries in the array are arranged by event priority. */
+static gcsBLOCK_INTERRUPT_HANDLER _blockHandlers[] =
+{
+ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(TESSELLATOR, 0),
+ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(VG, 0),
+ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 0),
+ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 1),
+ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 2),
+ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 3),
+ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 4),
+ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 5),
+ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 6),
+ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 7),
+ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 8),
+ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 9),
+ gcmDEFINE_INTERRUPT_HANDLER_ENTRY(COMMAND, 0),
+};
+
+
+/******************************************************************************\
+************************* Static Command Buffer Handlers ***********************
+\******************************************************************************/
+
+static gceSTATUS
+_UpdateStaticCommandBuffer(
+ IN gckVGKERNEL Kernel,
+ IN gcsKERNEL_CMDQUEUE_PTR Entry
+ )
+{
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ "%s(%d)\n",
+ __FUNCTION__, __LINE__
+ );
+
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_ExecuteStaticCommandBuffer(
+ IN gckVGKERNEL Kernel,
+ IN gcsKERNEL_CMDQUEUE_PTR Entry
+ )
+{
+ gceSTATUS status;
+
+ do
+ {
+ gcsCMDBUFFER_PTR commandBuffer;
+
+ /* Cast the command buffer header. */
+ commandBuffer = Entry->commandBuffer;
+
+ /* Set to update the command buffer next time. */
+ Entry->handler = _UpdateStaticCommandBuffer;
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ "%s(%d): executing next buffer @ 0x%08X, data count = %d\n",
+ __FUNCTION__, __LINE__,
+ commandBuffer->address,
+ commandBuffer->dataCount
+ );
+
+ /* Start the command processor. */
+ gcmkERR_BREAK(gckVGHARDWARE_Execute(
+ Kernel->hardware,
+ commandBuffer->address,
+ commandBuffer->dataCount
+ ));
+
+ /* Success. */
+ return gcvSTATUS_EXECUTED;
+ }
+ while (gcvFALSE);
+
+ /* Return status. */
+ return status;
+}
+
+static gceSTATUS
+_UpdateLastStaticCommandBuffer(
+ IN gckVGKERNEL Kernel,
+ IN gcsKERNEL_CMDQUEUE_PTR Entry
+ )
+{
+#if gcvDEBUG || gcdFORCE_MESSAGES
+ /* Get the command buffer header. */
+ gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer;
+
+ /* Validate the command buffer. */
+ gcmkASSERT(commandBuffer->completion != gcvNULL);
+ gcmkASSERT(commandBuffer->completion != gcvVACANT_BUFFER);
+
+#endif
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ "%s(%d): processing all tasks scheduled for FE.\n",
+ __FUNCTION__, __LINE__
+ );
+
+ /* Perform scheduled tasks. */
+ return _EventHandler_Block(
+ Kernel,
+ &Kernel->command->taskTable[gcvBLOCK_COMMAND],
+ gcvTRUE
+ );
+}
+
+static gceSTATUS
+_ExecuteLastStaticCommandBuffer(
+ IN gckVGKERNEL Kernel,
+ IN gcsKERNEL_CMDQUEUE_PTR Entry
+ )
+{
+ gceSTATUS status;
+
+ do
+ {
+ /* Cast the command buffer header. */
+ gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer;
+
+ /* Set to update the command buffer next time. */
+ Entry->handler = _UpdateLastStaticCommandBuffer;
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ "%s(%d): executing next buffer @ 0x%08X, data count = %d\n",
+ __FUNCTION__, __LINE__,
+ commandBuffer->address,
+ commandBuffer->dataCount
+ );
+
+ /* Start the command processor. */
+ gcmkERR_BREAK(gckVGHARDWARE_Execute(
+ Kernel->hardware,
+ commandBuffer->address,
+ commandBuffer->dataCount
+ ));
+
+ /* Success. */
+ return gcvSTATUS_EXECUTED;
+ }
+ while (gcvFALSE);
+
+ /* Return status. */
+ return status;
+}
+
+
+/******************************************************************************\
+************************* Dynamic Command Buffer Handlers **********************
+\******************************************************************************/
+
+static gceSTATUS
+_UpdateDynamicCommandBuffer(
+ IN gckVGKERNEL Kernel,
+ IN gcsKERNEL_CMDQUEUE_PTR Entry
+ )
+{
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ "%s(%d)\n",
+ __FUNCTION__, __LINE__
+ );
+
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_ExecuteDynamicCommandBuffer(
+ IN gckVGKERNEL Kernel,
+ IN gcsKERNEL_CMDQUEUE_PTR Entry
+ )
+{
+ gceSTATUS status;
+
+ do
+ {
+ /* Cast the command buffer header. */
+ gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer;
+
+ /* Set to update the command buffer next time. */
+ Entry->handler = _UpdateDynamicCommandBuffer;
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ "%s(%d): executing next buffer @ 0x%08X, data count = %d\n",
+ __FUNCTION__, __LINE__,
+ commandBuffer->address,
+ commandBuffer->dataCount
+ );
+
+ /* Start the command processor. */
+ gcmkERR_BREAK(gckVGHARDWARE_Execute(
+ Kernel->hardware,
+ commandBuffer->address,
+ commandBuffer->dataCount
+ ));
+
+ /* Success. */
+ return gcvSTATUS_EXECUTED;
+ }
+ while (gcvFALSE);
+
+ /* Return status. */
+ return status;
+}
+
+static gceSTATUS
+_UpdateLastDynamicCommandBuffer(
+ IN gckVGKERNEL Kernel,
+ IN gcsKERNEL_CMDQUEUE_PTR Entry
+ )
+{
+#if gcvDEBUG || gcdFORCE_MESSAGES
+ /* Get the command buffer header. */
+ gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer;
+
+ /* Validate the command buffer. */
+ gcmkASSERT(commandBuffer->completion != gcvNULL);
+ gcmkASSERT(commandBuffer->completion != gcvVACANT_BUFFER);
+
+#endif
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ "%s(%d): processing all tasks scheduled for FE.\n",
+ __FUNCTION__, __LINE__
+ );
+
+ /* Perform scheduled tasks. */
+ return _EventHandler_Block(
+ Kernel,
+ &Kernel->command->taskTable[gcvBLOCK_COMMAND],
+ gcvTRUE
+ );
+}
+
+static gceSTATUS
+_ExecuteLastDynamicCommandBuffer(
+ IN gckVGKERNEL Kernel,
+ IN gcsKERNEL_CMDQUEUE_PTR Entry
+ )
+{
+ gceSTATUS status;
+
+ do
+ {
+ /* Cast the command buffer header. */
+ gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer;
+
+ /* Set to update the command buffer next time. */
+ Entry->handler = _UpdateLastDynamicCommandBuffer;
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ "%s(%d): executing next buffer @ 0x%08X, data count = %d\n",
+ __FUNCTION__, __LINE__,
+ commandBuffer->address,
+ commandBuffer->dataCount
+ );
+
+ /* Start the command processor. */
+ gcmkERR_BREAK(gckVGHARDWARE_Execute(
+ Kernel->hardware,
+ commandBuffer->address,
+ commandBuffer->dataCount
+ ));
+
+ /* Success. */
+ return gcvSTATUS_EXECUTED;
+ }
+ while (gcvFALSE);
+
+ /* Return status. */
+ return status;
+}
+
+
+/******************************************************************************\
+********************************* Other Handlers *******************************
+\******************************************************************************/
+
+static gceSTATUS
+_FreeKernelCommandBuffer(
+ IN gckVGKERNEL Kernel,
+ IN gcsKERNEL_CMDQUEUE_PTR Entry
+ )
+{
+ gceSTATUS status;
+
+ /* Free the command buffer. */
+ status = _FreeCommandBuffer(Kernel, Entry->commandBuffer);
+
+ /* Return status. */
+ return status;
+}
+
+
+/******************************************************************************\
+******************************* Queue Management *******************************
+\******************************************************************************/
+
+#if gcvDUMP_COMMAND_BUFFER
+static void
+_DumpCommandQueue(
+ IN gckVGCOMMAND Command,
+ IN gcsKERNEL_QUEUE_HEADER_PTR QueueHeader,
+ IN gctUINT EntryCount
+ )
+{
+ gcsKERNEL_CMDQUEUE_PTR entry;
+ gctUINT queueIndex;
+
+#if defined(gcvCOMMAND_BUFFER_NAME)
+ static gctUINT arrayCount = 0;
+#endif
+
+ /* Is dumpinng enabled? */
+ if (!Commad->enableDumping)
+ {
+ return;
+ }
+
+#if !defined(gcvCOMMAND_BUFFER_NAME)
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_COMMAND,
+ "COMMAND QUEUE DUMP: %d entries\n", EntryCount
+ );
+#endif
+
+ /* Get the pointer to the first entry. */
+ entry = QueueHeader->currentEntry;
+
+ /* Iterate through the queue. */
+ for (queueIndex = 0; queueIndex < EntryCount; queueIndex += 1)
+ {
+ gcsCMDBUFFER_PTR buffer;
+ gctUINT bufferCount;
+ gctUINT bufferIndex;
+ gctUINT i, count;
+ gctUINT size;
+ gctUINT32_PTR data;
+
+#if gcvDUMP_COMMAND_LINES
+ gctUINT lineNumber;
+#endif
+
+#if !defined(gcvCOMMAND_BUFFER_NAME)
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_COMMAND,
+ "ENTRY %d\n", queueIndex
+ );
+#endif
+
+ /* Reset the count. */
+ bufferCount = 0;
+
+ /* Set the initial buffer. */
+ buffer = entry->commandBuffer;
+
+ /* Loop through all subbuffers. */
+ while (buffer)
+ {
+ /* Update the count. */
+ bufferCount += 1;
+
+ /* Advance to the next subbuffer. */
+ buffer = buffer->nextSubBuffer;
+ }
+
+#if !defined(gcvCOMMAND_BUFFER_NAME)
+ if (bufferCount > 1)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO,
+ gcvZONE_COMMAND,
+ " COMMAND BUFFER SET: %d buffers.\n",
+ bufferCount
+ );
+ }
+#endif
+
+ /* Reset the buffer index. */
+ bufferIndex = 0;
+
+ /* Set the initial buffer. */
+ buffer = entry->commandBuffer;
+
+ /* Loop through all subbuffers. */
+ while (buffer)
+ {
+ /* Determine the size of the buffer. */
+ size = buffer->dataCount * Command->info.commandAlignment;
+
+#if !defined(gcvCOMMAND_BUFFER_NAME)
+ /* A single buffer? */
+ if (bufferCount == 1)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO,
+ gcvZONE_COMMAND,
+ " COMMAND BUFFER: count=%d (0x%X), size=%d bytes @ %08X.\n",
+ buffer->dataCount,
+ buffer->dataCount,
+ size,
+ buffer->address
+ );
+ }
+ else
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO,
+ gcvZONE_COMMAND,
+ " COMMAND BUFFER %d: count=%d (0x%X), size=%d bytes @ %08X\n",
+ bufferIndex,
+ buffer->dataCount,
+ buffer->dataCount,
+ size,
+ buffer->address
+ );
+ }
+#endif
+
+ /* Determine the number of double words to print. */
+ count = size / 4;
+
+ /* Determine the buffer location. */
+ data = (gctUINT32_PTR)
+ (
+ (gctUINT8_PTR) buffer + buffer->bufferOffset
+ );
+
+#if defined(gcvCOMMAND_BUFFER_NAME)
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO,
+ gcvZONE_COMMAND,
+ "unsigned int _" gcvCOMMAND_BUFFER_NAME "_%d[] =\n",
+ arrayCount
+ );
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO,
+ gcvZONE_COMMAND,
+ "{\n"
+ );
+
+ arrayCount += 1;
+#endif
+
+#if gcvDUMP_COMMAND_LINES
+ /* Reset the line number. */
+ lineNumber = 0;
+#endif
+
+#if defined(gcvCOMMAND_BUFFER_NAME)
+ count -= 2;
+#endif
+
+ for (i = 0; i < count; i += 1)
+ {
+ if ((i % 8) == 0)
+ {
+#if defined(gcvCOMMAND_BUFFER_NAME)
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, "\t");
+#else
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, " ");
+#endif
+ }
+
+#if gcvDUMP_COMMAND_LINES
+ if (lineNumber == gcvDUMP_COMMAND_LINES)
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, " . . . . . . . . .\n");
+ break;
+ }
+#endif
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, "0x%08X", data[i]);
+
+ if (i + 1 == count)
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, "\n");
+
+#if gcvDUMP_COMMAND_LINES
+ lineNumber += 1;
+#endif
+ }
+ else
+ {
+ if (((i + 1) % 8) == 0)
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, ",\n");
+
+#if gcvDUMP_COMMAND_LINES
+ lineNumber += 1;
+#endif
+ }
+ else
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, ", ");
+ }
+ }
+ }
+
+#if defined(gcvCOMMAND_BUFFER_NAME)
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO,
+ gcvZONE_COMMAND,
+ "};\n\n"
+ );
+#endif
+
+ /* Advance to the next subbuffer. */
+ buffer = buffer->nextSubBuffer;
+ bufferIndex += 1;
+ }
+
+ /* Advance to the next entry. */
+ entry += 1;
+ }
+}
+#endif
+
+static gceSTATUS
+_LockCurrentQueue(
+ IN gckVGCOMMAND Command,
+ OUT gcsKERNEL_CMDQUEUE_PTR * Entries,
+ OUT gctUINT_PTR EntryCount
+ )
+{
+ gceSTATUS status;
+
+ do
+ {
+ gcsKERNEL_QUEUE_HEADER_PTR queueHead;
+
+ /* Get a shortcut to the head of the queue. */
+ queueHead = Command->queueHead;
+
+ /* Is the head buffer still being worked on? */
+ if (queueHead->pending)
+ {
+ /* Increment overflow count. */
+ Command->queueOverflow += 1;
+
+ /* Wait until the head becomes idle. */
+ gcmkERR_BREAK(_WaitForIdle(Command, queueHead));
+ }
+
+ /* Acquire the mutex. */
+ gcmkERR_BREAK(gckOS_AcquireMutex(
+ Command->os,
+ Command->queueMutex,
+ gcvINFINITE
+ ));
+
+ /* Determine the first queue entry. */
+ queueHead->currentEntry = (gcsKERNEL_CMDQUEUE_PTR)
+ (
+ (gctUINT8_PTR) queueHead + gcmSIZEOF(gcsKERNEL_QUEUE_HEADER)
+ );
+
+ /* Set the pointer to the first entry. */
+ * Entries = queueHead->currentEntry;
+
+ /* Determine the number of available entries. */
+ * EntryCount = queueHead->size / gcmSIZEOF(gcsKERNEL_CMDQUEUE);
+
+ /* Success. */
+ return gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ /* Return status. */
+ return status;
+}
+
+static gceSTATUS
+_UnlockCurrentQueue(
+ IN gckVGCOMMAND Command,
+ IN gctUINT EntryCount
+ )
+{
+ gceSTATUS status;
+
+ do
+ {
+#if !gcdENABLE_INFINITE_SPEED_HW
+ gcsKERNEL_QUEUE_HEADER_PTR queueTail;
+ gcsKERNEL_QUEUE_HEADER_PTR queueHead;
+ gcsKERNEL_QUEUE_HEADER_PTR queueNext;
+ gctUINT queueSize;
+ gctUINT newSize;
+ gctUINT unusedSize;
+
+ /* Get shortcut to the head and to the tail of the queue. */
+ queueTail = Command->queueTail;
+ queueHead = Command->queueHead;
+
+ /* Dump the command buffer. */
+#if gcvDUMP_COMMAND_BUFFER
+ _DumpCommandQueue(Command, queueHead, EntryCount);
+#endif
+
+ /* Get a shortcut to the current queue size. */
+ queueSize = queueHead->size;
+
+ /* Determine the new queue size. */
+ newSize = EntryCount * gcmSIZEOF(gcsKERNEL_CMDQUEUE);
+ gcmkASSERT(newSize <= queueSize);
+
+ /* Determine the size of the unused area. */
+ unusedSize = queueSize - newSize;
+
+ /* Is the unused area big enough to become a buffer? */
+ if (unusedSize >= gcvMINUMUM_BUFFER)
+ {
+ gcsKERNEL_QUEUE_HEADER_PTR nextHead;
+
+ /* Place the new header. */
+ nextHead = (gcsKERNEL_QUEUE_HEADER_PTR)
+ (
+ (gctUINT8_PTR) queueHead
+ + gcmSIZEOF(gcsKERNEL_QUEUE_HEADER)
+ + newSize
+ );
+
+ /* Initialize the buffer. */
+ nextHead->size = unusedSize - gcmSIZEOF(gcsKERNEL_QUEUE_HEADER);
+ nextHead->pending = 0;
+
+ /* Link the buffer in. */
+ nextHead->next = queueHead->next;
+ queueHead->next = nextHead;
+ queueNext = nextHead;
+
+ /* Update the size of the current buffer. */
+ queueHead->size = newSize;
+ }
+
+ /* Not big enough. */
+ else
+ {
+ /* Determine the next queue. */
+ queueNext = queueHead->next;
+ }
+
+ /* Mark the buffer as busy. */
+ queueHead->pending = EntryCount;
+
+ /* Advance to the next buffer. */
+ Command->queueHead = queueNext;
+
+ /* Start the command processor if the queue was empty. */
+ if (queueTail == queueHead)
+ {
+ gcsCMDBUFFER_PTR commandBuffer;
+
+ /* The first entry must be a command buffer. */
+ commandBuffer = queueTail->currentEntry->commandBuffer;
+
+ /* Start the command processor. */
+ gcmkERR_BREAK(gckVGHARDWARE_Execute(
+ Command->hardware,
+ commandBuffer->address,
+ commandBuffer->dataCount
+ ));
+ }
+
+ /* The queue was not empty. */
+ else
+ {
+ /* Advance the merge buffer if needed. */
+ if (queueHead == Command->mergeQueue)
+ {
+ Command->mergeQueue = queueNext;
+ }
+ }
+#endif
+
+ /* Release the mutex. */
+ gcmkERR_BREAK(gckOS_ReleaseMutex(
+ Command->os,
+ Command->queueMutex
+ ));
+
+ /* Success. */
+ return gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ /* Return status. */
+ return status;
+}
+
+
+
+/******************************************************************************\
+****************************** gckVGCOMMAND API Code *****************************
+\******************************************************************************/
+gceSTATUS
+gckVGCOMMAND_Construct(
+ IN gckVGKERNEL Kernel,
+ IN gctUINT TaskGranularity,
+ IN gctUINT QueueSize,
+ OUT gckVGCOMMAND * Command
+ )
+{
+ gceSTATUS status, last;
+ gckVGCOMMAND command = gcvNULL;
+ gcsKERNEL_QUEUE_HEADER_PTR queue;
+ gctUINT i, j;
+
+ gcmkHEADER_ARG("Kernel=0x%x TaskGranularity=0x%x QueueSize=0x%x Command=0x%x",
+ Kernel, TaskGranularity, QueueSize, Command);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(QueueSize >= gcvMINUMUM_BUFFER);
+ gcmkVERIFY_ARGUMENT(Command != gcvNULL);
+
+ do
+ {
+ /***********************************************************************
+ ** Generic object initialization.
+ */
+
+ /* Allocate the gckVGCOMMAND structure. */
+ gcmkERR_BREAK(gckOS_Allocate(
+ Kernel->os,
+ gcmSIZEOF(struct _gckVGCOMMAND),
+ (gctPOINTER *) &command
+ ));
+
+ /* Initialize the object. */
+ command->object.type = gcvOBJ_COMMAND;
+
+ /* Set the object pointers. */
+ command->kernel = Kernel;
+ command->os = Kernel->os;
+ command->hardware = Kernel->hardware;
+
+ /* Reset pointers. */
+ command->queue = gcvNULL;
+ command->queueMutex = gcvNULL;
+ command->taskMutex = gcvNULL;
+ command->commitMutex = gcvNULL;
+
+ command->powerStallBuffer = gcvNULL;
+ command->powerStallSignal = gcvNULL;
+ command->powerSemaphore = gcvNULL;
+
+ /* Reset context states. */
+ command->contextCounter = 0;
+ command->currentContext = 0;
+
+ /* Enable command buffer dumping. */
+ command->enableDumping = gcvTRUE;
+
+ /* Set features. */
+ command->fe20 = Kernel->hardware->fe20;
+ command->vg20 = Kernel->hardware->vg20;
+ command->vg21 = Kernel->hardware->vg21;
+
+ /* Reset task table .*/
+ gcmkVERIFY_OK(gckOS_ZeroMemory(
+ command->taskTable, gcmSIZEOF(command->taskTable)
+ ));
+
+ /* Query command buffer attributes. */
+ gcmkERR_BREAK(gckVGCOMMAND_InitializeInfo(command));
+
+ /* Create the control mutexes. */
+ gcmkERR_BREAK(gckOS_CreateMutex(Kernel->os, &command->queueMutex));
+ gcmkERR_BREAK(gckOS_CreateMutex(Kernel->os, &command->taskMutex));
+ gcmkERR_BREAK(gckOS_CreateMutex(Kernel->os, &command->commitMutex));
+
+ /* Create the power management semaphore. */
+ gcmkERR_BREAK(gckOS_CreateSemaphore(Kernel->os,
+ &command->powerSemaphore));
+
+ gcmkERR_BREAK(gckOS_CreateSignal(Kernel->os,
+ gcvFALSE, &command->powerStallSignal));
+
+ /***********************************************************************
+ ** Command queue initialization.
+ */
+
+ /* Allocate the command queue. */
+ gcmkERR_BREAK(gckOS_Allocate(
+ Kernel->os,
+ QueueSize,
+ (gctPOINTER *) &command->queue
+ ));
+
+ /* Initialize the command queue. */
+ queue = command->queue;
+
+ queue->size = QueueSize - gcmSIZEOF(gcsKERNEL_QUEUE_HEADER);
+ queue->pending = 0;
+ queue->next = queue;
+
+ command->queueHead =
+ command->queueTail =
+ command->mergeQueue = command->queue;
+
+ command->queueOverflow = 0;
+
+
+ /***********************************************************************
+ ** Enable TS overflow interrupt.
+ */
+
+ command->info.tsOverflowInt = 0;
+ gcmkERR_BREAK(gckVGINTERRUPT_Enable(
+ Kernel->interrupt,
+ &command->info.tsOverflowInt,
+ _EventHandler_TSOverflow
+ ));
+
+ /* Mask out the interrupt. */
+ /* Kernel->hardware->eventMask &= ~(1 << command->info.tsOverflowInt); */
+
+
+ /***********************************************************************
+ ** Enable Bus Error interrupt.
+ */
+
+ /* Hardwired to bit 31. */
+ command->busErrorInt = 31;
+
+ /* Enable the interrupt. */
+ gcmkERR_BREAK(gckVGINTERRUPT_Enable(
+ Kernel->interrupt,
+ &command->busErrorInt,
+ _EventHandler_BusError
+ ));
+
+
+ command->powerStallInt = 30;
+ /* Enable the interrupt. */
+ gcmkERR_BREAK(gckVGINTERRUPT_Enable(
+ Kernel->interrupt,
+ &command->powerStallInt,
+ _EventHandler_PowerStall
+ ));
+
+ /***********************************************************************
+ ** Task management initialization.
+ */
+
+ command->taskStorage = gcvNULL;
+ command->taskStorageGranularity = TaskGranularity;
+ command->taskStorageUsable = TaskGranularity - gcmSIZEOF(gcsTASK_STORAGE);
+
+ command->taskFreeHead = gcvNULL;
+ command->taskFreeTail = gcvNULL;
+
+ /* Enable block handlers. */
+ for (i = 0; i < gcmCOUNTOF(_blockHandlers); i += 1)
+ {
+ /* Get the target hardware block. */
+ gceBLOCK block = _blockHandlers[i].block;
+
+ /* Get the interrupt array entry. */
+ gcsBLOCK_TASK_ENTRY_PTR entry = &command->taskTable[block];
+
+ /* Determine the interrupt value index. */
+ gctUINT index = entry->interruptCount;
+
+ /* Create the block semaphore. */
+ if (entry->interruptSemaphore == gcvNULL)
+ {
+ gcmkERR_BREAK(gckOS_CreateSemaphoreVG(
+ command->os, &entry->interruptSemaphore
+ ));
+ }
+
+ /* Enable auto-detection. */
+ entry->interruptArray[index] = -1;
+
+ /* Enable interrupt for the block. */
+ gcmkERR_BREAK(gckVGINTERRUPT_Enable(
+ Kernel->interrupt,
+ &entry->interruptArray[index],
+ _blockHandlers[i].handler
+ ));
+
+ /* Update the number of registered interrupts. */
+ entry->interruptCount += 1;
+
+ /* Inrement the semaphore to allow the usage of the registered
+ interrupt. */
+ gcmkERR_BREAK(gckOS_IncrementSemaphore(
+ command->os, entry->interruptSemaphore
+ ));
+
+ }
+
+ /* Error? */
+ if (gcmkIS_ERROR(status))
+ {
+ break;
+ }
+
+ /* Get the FE interrupt. */
+ command->info.feBufferInt
+ = command->taskTable[gcvBLOCK_COMMAND].interruptArray[0];
+
+ /* Return gckVGCOMMAND object pointer. */
+ *Command = command;
+
+ gcmkFOOTER_ARG("*Command=0x%x",*Command);
+ /* Success. */
+ return gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ /* Roll back. */
+ if (command != gcvNULL)
+ {
+ /* Disable block handlers. */
+ for (i = 0; i < gcvBLOCK_COUNT; i += 1)
+ {
+ /* Get the task table entry. */
+ gcsBLOCK_TASK_ENTRY_PTR entry = &command->taskTable[i];
+
+ /* Destroy the semaphore. */
+ if (entry->interruptSemaphore != gcvNULL)
+ {
+ gcmkCHECK_STATUS(gckOS_DestroySemaphore(
+ command->os, entry->interruptSemaphore
+ ));
+ }
+
+ /* Disable all enabled interrupts. */
+ for (j = 0; j < entry->interruptCount; j += 1)
+ {
+ /* Must be a valid value. */
+ gcmkASSERT(entry->interruptArray[j] >= 0);
+ gcmkASSERT(entry->interruptArray[j] <= 31);
+
+ /* Disable the interrupt. */
+ gcmkCHECK_STATUS(gckVGINTERRUPT_Disable(
+ Kernel->interrupt,
+ entry->interruptArray[j]
+ ));
+ }
+ }
+
+ /* Disable the bus error interrupt. */
+ gcmkCHECK_STATUS(gckVGINTERRUPT_Disable(
+ Kernel->interrupt,
+ command->busErrorInt
+ ));
+
+ /* Disable TS overflow interrupt. */
+ if (command->info.tsOverflowInt != -1)
+ {
+ gcmkCHECK_STATUS(gckVGINTERRUPT_Disable(
+ Kernel->interrupt,
+ command->info.tsOverflowInt
+ ));
+ }
+
+ /* Delete the commit mutex. */
+ if (command->commitMutex != gcvNULL)
+ {
+ gcmkCHECK_STATUS(gckOS_DeleteMutex(
+ Kernel->os, command->commitMutex
+ ));
+ }
+
+ /* Delete the command queue mutex. */
+ if (command->taskMutex != gcvNULL)
+ {
+ gcmkCHECK_STATUS(gckOS_DeleteMutex(
+ Kernel->os, command->taskMutex
+ ));
+ }
+
+ /* Delete the command queue mutex. */
+ if (command->queueMutex != gcvNULL)
+ {
+ gcmkCHECK_STATUS(gckOS_DeleteMutex(
+ Kernel->os, command->queueMutex
+ ));
+ }
+
+ /* Delete the command queue. */
+ if (command->queue != gcvNULL)
+ {
+ gcmkCHECK_STATUS(gckOS_Free(
+ Kernel->os, command->queue
+ ));
+ }
+
+ if (command->powerSemaphore != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_DestroySemaphore(
+ Kernel->os, command->powerSemaphore));
+ }
+
+ if (command->powerStallSignal != gcvNULL)
+ {
+ /* Create the power management semaphore. */
+ gcmkVERIFY_OK(gckOS_DestroySignal(
+ Kernel->os,
+ command->powerStallSignal));
+ }
+
+ /* Free the gckVGCOMMAND structure. */
+ gcmkCHECK_STATUS(gckOS_Free(
+ Kernel->os, command
+ ));
+ }
+
+ gcmkFOOTER();
+ /* Return the error. */
+ return status;
+}
+
+gceSTATUS
+gckVGCOMMAND_Destroy(
+ OUT gckVGCOMMAND Command
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+
+ gcmkHEADER_ARG("Command=0x%x", Command);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+
+ do
+ {
+ gctUINT i;
+ gcsTASK_STORAGE_PTR nextStorage;
+
+ if (Command->queueHead != gcvNULL)
+ {
+ /* Wait until the head becomes idle. */
+ gcmkERR_BREAK(_WaitForIdle(Command, Command->queueHead));
+ }
+
+ /* Disable block handlers. */
+ for (i = 0; i < gcvBLOCK_COUNT; i += 1)
+ {
+ /* Get the interrupt array entry. */
+ gcsBLOCK_TASK_ENTRY_PTR entry = &Command->taskTable[i];
+
+ /* Determine the index of the last interrupt in the array. */
+ gctINT index = entry->interruptCount - 1;
+
+ /* Destroy the semaphore. */
+ if (entry->interruptSemaphore != gcvNULL)
+ {
+ gcmkERR_BREAK(gckOS_DestroySemaphore(
+ Command->os, entry->interruptSemaphore
+ ));
+ }
+
+ /* Disable all enabled interrupts. */
+ while (index >= 0)
+ {
+ /* Must be a valid value. */
+ gcmkASSERT(entry->interruptArray[index] >= 0);
+ gcmkASSERT(entry->interruptArray[index] <= 31);
+
+ /* Disable the interrupt. */
+ gcmkERR_BREAK(gckVGINTERRUPT_Disable(
+ Command->kernel->interrupt,
+ entry->interruptArray[index]
+ ));
+
+ /* Update to the next interrupt. */
+ index -= 1;
+ entry->interruptCount -= 1;
+ }
+
+ /* Error? */
+ if (gcmkIS_ERROR(status))
+ {
+ break;
+ }
+ }
+
+ /* Error? */
+ if (gcmkIS_ERROR(status))
+ {
+ break;
+ }
+
+ /* Disable the bus error interrupt. */
+ gcmkERR_BREAK(gckVGINTERRUPT_Disable(
+ Command->kernel->interrupt,
+ Command->busErrorInt
+ ));
+
+ /* Disable TS overflow interrupt. */
+ if (Command->info.tsOverflowInt != -1)
+ {
+ gcmkERR_BREAK(gckVGINTERRUPT_Disable(
+ Command->kernel->interrupt,
+ Command->info.tsOverflowInt
+ ));
+
+ Command->info.tsOverflowInt = -1;
+ }
+
+ /* Delete the commit mutex. */
+ if (Command->commitMutex != gcvNULL)
+ {
+ gcmkERR_BREAK(gckOS_DeleteMutex(
+ Command->os, Command->commitMutex
+ ));
+
+ Command->commitMutex = gcvNULL;
+ }
+
+ /* Delete the command queue mutex. */
+ if (Command->taskMutex != gcvNULL)
+ {
+ gcmkERR_BREAK(gckOS_DeleteMutex(
+ Command->os, Command->taskMutex
+ ));
+
+ Command->taskMutex = gcvNULL;
+ }
+
+ /* Delete the command queue mutex. */
+ if (Command->queueMutex != gcvNULL)
+ {
+ gcmkERR_BREAK(gckOS_DeleteMutex(
+ Command->os, Command->queueMutex
+ ));
+
+ Command->queueMutex = gcvNULL;
+ }
+
+ if (Command->powerSemaphore != gcvNULL)
+ {
+ /* Destroy the power management semaphore. */
+ gcmkERR_BREAK(gckOS_DestroySemaphore(
+ Command->os, Command->powerSemaphore));
+ }
+
+ if (Command->powerStallSignal != gcvNULL)
+ {
+ /* Create the power management semaphore. */
+ gcmkERR_BREAK(gckOS_DestroySignal(
+ Command->os,
+ Command->powerStallSignal));
+ }
+
+ if (Command->queue != gcvNULL)
+ {
+ /* Delete the command queue. */
+ gcmkERR_BREAK(gckOS_Free(
+ Command->os, Command->queue
+ ));
+ }
+
+ /* Destroy all allocated buffers. */
+ while (Command->taskStorage)
+ {
+ /* Copy the buffer pointer. */
+ nextStorage = Command->taskStorage->next;
+
+ /* Free the current container. */
+ gcmkERR_BREAK(gckOS_Free(
+ Command->os, Command->taskStorage
+ ));
+
+ /* Advance to the next one. */
+ Command->taskStorage = nextStorage;
+ }
+
+ /* Error? */
+ if (gcmkIS_ERROR(status))
+ {
+ break;
+ }
+
+ /* Mark the object as unknown. */
+ Command->object.type = gcvOBJ_UNKNOWN;
+
+ /* Free the gckVGCOMMAND structure. */
+ gcmkERR_BREAK(gckOS_Free(Command->os, Command));
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ /* Restore the object type if failed. */
+ Command->object.type = gcvOBJ_COMMAND;
+
+ gcmkFOOTER();
+ /* Return the error. */
+ return status;
+}
+
+gceSTATUS
+gckVGCOMMAND_QueryCommandBuffer(
+ IN gckVGCOMMAND Command,
+ OUT gcsCOMMAND_BUFFER_INFO_PTR Information
+ )
+{
+ gcmkHEADER_ARG("Command=0x%x Information=0x%x", Command, Information);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+ gcmkVERIFY_ARGUMENT(Information != gcvNULL);
+
+ /* Copy the information. */
+ gcmkVERIFY_OK(gckOS_MemCopy(
+ Information, &Command->info, sizeof(gcsCOMMAND_BUFFER_INFO)
+ ));
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckVGCOMMAND_Allocate(
+ IN gckVGCOMMAND Command,
+ IN gctSIZE_T Size,
+ OUT gcsCMDBUFFER_PTR * CommandBuffer,
+ OUT gctPOINTER * Data
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Command=0x%x Size=0x%x CommandBuffer=0x%x Data=0x%x",
+ Command, Size, CommandBuffer, Data);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+ gcmkVERIFY_ARGUMENT(Data != gcvNULL);
+
+ do
+ {
+ /* Allocate the buffer. */
+ gcmkERR_BREAK(_AllocateCommandBuffer(Command, Size, CommandBuffer));
+
+ /* Determine the data pointer. */
+ * Data = (gctUINT8_PTR) (*CommandBuffer) + (* CommandBuffer)->bufferOffset;
+ }
+ while (gcvFALSE);
+
+ gcmkFOOTER();
+ /* Return status. */
+ return status;
+}
+
+gceSTATUS
+gckVGCOMMAND_Free(
+ IN gckVGCOMMAND Command,
+ IN gcsCMDBUFFER_PTR CommandBuffer
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Command=0x%x CommandBuffer=0x%x",
+ Command, CommandBuffer);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+ gcmkVERIFY_ARGUMENT(CommandBuffer != gcvNULL);
+
+ /* Free command buffer. */
+ status = _FreeCommandBuffer(Command->kernel, CommandBuffer);
+
+ gcmkFOOTER();
+ /* Return status. */
+ return status;
+}
+
+gceSTATUS
+gckVGCOMMAND_Execute(
+ IN gckVGCOMMAND Command,
+ IN gcsCMDBUFFER_PTR CommandBuffer
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Command=0x%x CommandBuffer=0x%x",
+ Command, CommandBuffer);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+ gcmkVERIFY_ARGUMENT(CommandBuffer != gcvNULL);
+
+ do
+ {
+ gctUINT queueLength;
+ gcsKERNEL_CMDQUEUE_PTR kernelEntry;
+
+ /* Lock the current queue. */
+ gcmkERR_BREAK(_LockCurrentQueue(
+ Command, &kernelEntry, &queueLength
+ ));
+
+ /* Set the buffer. */
+ kernelEntry->commandBuffer = CommandBuffer;
+ kernelEntry->handler = _FreeKernelCommandBuffer;
+
+ /* Lock the current queue. */
+ gcmkERR_BREAK(_UnlockCurrentQueue(
+ Command, 1
+ ));
+ }
+ while (gcvFALSE);
+
+ gcmkFOOTER();
+ /* Return status. */
+ return status;
+}
+
+gceSTATUS
+gckVGCOMMAND_Commit(
+ IN gckVGCOMMAND Command,
+ IN gcsVGCONTEXT_PTR Context,
+ IN gcsVGCMDQUEUE_PTR Queue,
+ IN gctUINT EntryCount,
+ IN gcsTASK_MASTER_TABLE_PTR TaskTable
+ )
+{
+ /*
+ The first buffer is executed through a direct gckVGHARDWARE_Execute call,
+ therefore only an update is needed after the execution is over. All
+ consequent buffers need to be executed upon the first update call from
+ the FE interrupt handler.
+ */
+ static gcsQUEUE_UPDATE_CONTROL _dynamicBuffer[] =
+ {
+ {
+ _UpdateDynamicCommandBuffer,
+ _UpdateDynamicCommandBuffer,
+ _UpdateLastDynamicCommandBuffer,
+ _UpdateLastDynamicCommandBuffer
+ },
+ {
+ _ExecuteDynamicCommandBuffer,
+ _UpdateDynamicCommandBuffer,
+ _ExecuteLastDynamicCommandBuffer,
+ _UpdateLastDynamicCommandBuffer
+ }
+ };
+
+ static gcsQUEUE_UPDATE_CONTROL _staticBuffer[] =
+ {
+ {
+ _UpdateStaticCommandBuffer,
+ _UpdateStaticCommandBuffer,
+ _UpdateLastStaticCommandBuffer,
+ _UpdateLastStaticCommandBuffer
+ },
+ {
+ _ExecuteStaticCommandBuffer,
+ _UpdateStaticCommandBuffer,
+ _ExecuteLastStaticCommandBuffer,
+ _UpdateLastStaticCommandBuffer
+ }
+ };
+
+ gceSTATUS status, last;
+ struct _gcsTASK_MASTER_TABLE _TaskTable;
+#ifdef __QNXNTO__
+ gcsVGCONTEXT_PTR userContext = gcvNULL;
+ gctBOOL userContextMapped = gcvFALSE;
+ gcsTASK_MASTER_TABLE_PTR userTaskTable = gcvNULL;
+ gctBOOL userTaskTableMapped = gcvFALSE;
+ gctPOINTER pointer = gcvNULL;
+#endif
+ struct _gcsVGCONTEXT _Context;
+ gctBOOL needCopy = gcvFALSE;
+
+ gcmkHEADER_ARG("Command=0x%x Context=0x%x Queue=0x%x EntryCount=0x%x TaskTable=0x%x",
+ Command, Context, Queue, EntryCount, TaskTable);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND);
+ gcmkVERIFY_ARGUMENT(Context != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Queue != gcvNULL);
+ gcmkVERIFY_ARGUMENT(EntryCount > 1);
+
+ do
+ {
+ gctBOOL haveFETasks;
+ gctUINT queueSize = 0;
+ gcsVGCMDQUEUE_PTR mappedQueue=gcvNULL;
+ gcsVGCMDQUEUE_PTR userEntry=gcvNULL;
+ gcsKERNEL_CMDQUEUE_PTR kernelEntry;
+ gcsQUEUE_UPDATE_CONTROL_PTR queueControl;
+ gctUINT currentLength;
+ gctUINT queueLength;
+ gctUINT entriesQueued;
+ gctUINT8_PTR previousEnd;
+ gctBOOL previousDynamic;
+ gctBOOL previousExecuted;
+ gctUINT controlIndex;
+ gctINT pid;
+#ifdef __QNXNTO__
+ /* Map the context into the kernel space. */
+ userContext = Context;
+
+ gcmkERR_BREAK(gckOS_MapUserPointer(
+ Command->os,
+ userContext,
+ gcmSIZEOF(*userContext),
+ &pointer));
+
+ Context = pointer;
+
+ userContextMapped = gcvTRUE;
+
+ /* Map the taskTable into the kernel space. */
+ userTaskTable = TaskTable;
+
+ gcmkERR_BREAK(gckOS_MapUserPointer(
+ Command->os,
+ userTaskTable,
+ gcmSIZEOF(*userTaskTable),
+ &pointer));
+
+ TaskTable = pointer;
+
+ userTaskTableMapped = gcvTRUE;
+
+ /* Update the signal info. */
+ TaskTable->coid = Context->coid;
+ TaskTable->rcvid = Context->rcvid;
+#endif
+
+ gcmkERR_BREAK(gckOS_GetProcessID((gctUINT32_PTR)&pid));
+ gcmkERR_BREAK(gckOS_QueryNeedCopy(Command->os, pid, &needCopy));
+ if(needCopy)
+ {
+ gcmkERR_BREAK(gckOS_CopyFromUserData(
+ Command->os,
+ &_TaskTable,
+ TaskTable,
+ gcmSIZEOF(struct _gcsTASK_MASTER_TABLE)
+ ));
+ TaskTable = &_TaskTable;
+ /* Determine whether there are FE tasks to be performed. */
+ gcmkERR_BREAK(gckOS_CopyFromUserData(
+ Command->os,
+ &_Context,
+ Context,
+ gcmSIZEOF(struct _gcsVGCONTEXT)
+ ));
+ Context = &_Context;
+ }
+
+ gcmkERR_BREAK(gckVGHARDWARE_SetPowerManagementState(
+ Command->hardware, gcvPOWER_ON_AUTO
+ ));
+
+ /* Acquire the power semaphore. */
+ gcmkERR_BREAK(gckOS_AcquireSemaphore(
+ Command->os, Command->powerSemaphore
+ ));
+
+ /* Acquire the mutex. */
+ status = gckOS_AcquireMutex(
+ Command->os,
+ Command->commitMutex,
+ gcvINFINITE
+ );
+
+ if (gcmIS_ERROR(status))
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseSemaphore(
+ Command->os, Command->powerSemaphore));
+ break;
+ }
+
+ do
+ {
+ gcmkERR_BREAK(_FlushMMU(Command));
+
+ /* Assign a context ID if not yet assigned. */
+ if (Context->id == 0)
+ {
+ /* Assign the next context number. */
+ Context->id = ++ Command->contextCounter;
+ /* See if we overflowed. */
+ if (Command->contextCounter == 0)
+ {
+ /* We actually did overflow, wow... */
+ status = gcvSTATUS_OUT_OF_RESOURCES;
+ break;
+ }
+ }
+
+ /* The first entry in the queue is always the context buffer.
+ Verify whether the user context is the same as the current
+ context and if that's the case, skip the first entry. */
+ if (Context->id == Command->currentContext)
+ {
+ /* Same context as before, skip the first entry. */
+ EntryCount -= 1;
+ Queue += 1;
+
+ /* Set the signal to avoid user waiting. */
+#ifdef __QNXNTO__
+ gcmkERR_BREAK(gckOS_UserSignal(
+ Command->os,
+ Context->userSignal,
+ Context->rcvid,
+ Context->coid
+ ));
+#else
+ gcmkERR_BREAK(gckOS_UserSignal(
+ Command->os, Context->signal, Context->process
+ ));
+#endif
+ }
+ else
+ {
+ /* Different user context - keep the first entry.
+ Set the user context as the current one. */
+ Command->currentContext = Context->id;
+ }
+
+ /* Reset pointers. */
+ queueControl = gcvNULL;
+ previousEnd = gcvNULL;
+
+ haveFETasks = (TaskTable->table[gcvBLOCK_COMMAND].head != gcvNULL);
+
+ /* Determine the size of the queue. */
+ queueSize = EntryCount * gcmSIZEOF(gcsVGCMDQUEUE);
+ if(needCopy)
+ {
+ gctPOINTER pointer = gcvNULL;
+ gcmkERR_BREAK(gckOS_Allocate(
+ Command->os,
+ queueSize,
+ &pointer
+ ));
+ userEntry = pointer;
+ mappedQueue = pointer;
+ gcmkERR_BREAK(gckOS_CopyFromUserData(
+ Command->os,
+ userEntry,
+ Queue,
+ queueSize
+ ));
+ }
+ else
+ {
+ /* Map the command queue into the kernel space. */
+ gcmkERR_BREAK(gckOS_MapUserPointer(
+ Command->os,
+ Queue,
+ queueSize,
+ (gctPOINTER *) &mappedQueue
+ ));
+ userEntry = mappedQueue;
+ }
+ /* Set the first entry. */
+
+ /* Process the command queue. */
+ while (EntryCount)
+ {
+ /* Lock the current queue. */
+ gcmkERR_BREAK(_LockCurrentQueue(
+ Command, &kernelEntry, &queueLength
+ ));
+
+ /* Determine the number of entries to process. */
+ currentLength = (queueLength < EntryCount)
+ ? queueLength
+ : EntryCount;
+
+ /* Update the number of the entries left to process. */
+ EntryCount -= currentLength;
+
+ /* Reset previous flags. */
+ previousDynamic = gcvFALSE;
+ previousExecuted = gcvFALSE;
+
+ /* Set the initial control index. */
+ controlIndex = 0;
+
+ /* Process entries. */
+ for (entriesQueued = 0; entriesQueued < currentLength; entriesQueued += 1)
+ {
+ /* Get the kernel pointer to the command buffer header. */
+ gcsCMDBUFFER_PTR commandBuffer = gcvNULL;
+ gcmkERR_BREAK(_ConvertUserCommandBufferPointer(
+ Command,
+ userEntry->commandBuffer,
+ &commandBuffer
+ ));
+
+ /* Is it a dynamic command buffer? */
+ if (userEntry->dynamic)
+ {
+ /* Select dynamic buffer control functions. */
+ queueControl = &_dynamicBuffer[controlIndex];
+ }
+
+ /* No, a static command buffer. */
+ else
+ {
+ /* Select static buffer control functions. */
+ queueControl = &_staticBuffer[controlIndex];
+ }
+
+ /* Set the command buffer pointer to the entry. */
+ kernelEntry->commandBuffer = commandBuffer;
+
+ /* If the previous entry was a dynamic command buffer,
+ link it to the current. */
+ if (previousDynamic)
+ {
+ gcmkERR_BREAK(gckVGCOMMAND_FetchCommand(
+ Command,
+ previousEnd,
+ commandBuffer->address,
+ commandBuffer->dataCount,
+ gcvNULL
+ ));
+
+ /* The buffer will be auto-executed, only need to
+ update it after it has been executed. */
+ kernelEntry->handler = queueControl->update;
+
+ /* The buffer is only being updated. */
+ previousExecuted = gcvFALSE;
+ }
+ else
+ {
+ /* Set the buffer up for execution. */
+ kernelEntry->handler = queueControl->execute;
+
+ /* The buffer is being updated. */
+ previousExecuted = gcvTRUE;
+ }
+
+ /* The current buffer's END command becomes the last END. */
+ previousEnd
+ = ((gctUINT8_PTR) commandBuffer)
+ + commandBuffer->bufferOffset
+ + commandBuffer->dataCount * Command->info.commandAlignment
+ - Command->info.staticTailSize;
+
+ /* Update the last entry info. */
+ previousDynamic = userEntry->dynamic;
+
+ /* Advance entries. */
+ userEntry ++;
+ kernelEntry ++;
+
+ /* Update the control index. */
+ controlIndex = 1;
+ }
+
+ /* If the previous entry was a dynamic command buffer,
+ terminate it with an END. */
+ if (previousDynamic)
+ {
+ gcmkERR_BREAK(gckVGCOMMAND_EndCommand(
+ Command,
+ previousEnd,
+ Command->info.feBufferInt,
+ gcvNULL
+ ));
+ }
+
+ /* Last buffer? */
+ if (EntryCount == 0)
+ {
+ /* Modify the last command buffer's routines to handle
+ tasks if any.*/
+ if (haveFETasks)
+ {
+ if (previousExecuted)
+ {
+ kernelEntry[-1].handler = queueControl->lastExecute;
+ }
+ else
+ {
+ kernelEntry[-1].handler = queueControl->lastUpdate;
+ }
+ }
+
+ /* Release the mutex. */
+ gcmkERR_BREAK(gckOS_ReleaseMutex(
+ Command->os,
+ Command->queueMutex
+ ));
+ /* Schedule tasks. */
+ gcmkERR_BREAK(_ScheduleTasks(Command, TaskTable, previousEnd));
+
+ /* Acquire the mutex. */
+ gcmkERR_BREAK(gckOS_AcquireMutex(
+ Command->os,
+ Command->queueMutex,
+ gcvINFINITE
+ ));
+ }
+
+ /* Unkock and schedule the current queue for execution. */
+ gcmkERR_BREAK(_UnlockCurrentQueue(
+ Command, currentLength
+ ));
+ }
+ }
+ while (gcvFALSE);
+
+ if (mappedQueue)
+ {
+ if(!needCopy)
+ {
+ /* Unmap the user command buffer. */
+ gcmkERR_BREAK(gckOS_UnmapUserPointer(
+ Command->os,
+ Queue,
+ queueSize,
+ mappedQueue
+ ));
+ }
+ else
+ {
+ gcmkERR_BREAK(gckOS_Free(Command->os, mappedQueue));
+ }
+ }
+
+ /* Release the mutex. */
+ gcmkCHECK_STATUS(gckOS_ReleaseMutex(
+ Command->os,
+ Command->commitMutex
+ ));
+
+ gcmkVERIFY_OK(gckOS_ReleaseSemaphore(
+ Command->os, Command->powerSemaphore));
+ }
+ while (gcvFALSE);
+#ifdef __QNXNTO__
+ if (userContextMapped)
+ {
+ /* Unmap the user context. */
+ gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+ Command->os,
+ userContext,
+ gcmSIZEOF(*userContext),
+ Context));
+ }
+
+ if (userTaskTableMapped)
+ {
+ /* Unmap the user taskTable. */
+ gcmkVERIFY_OK(gckOS_UnmapUserPointer(
+ Command->os,
+ userTaskTable,
+ gcmSIZEOF(*userTaskTable),
+ TaskTable));
+ }
+#endif
+
+ gcmkFOOTER();
+ /* Return status. */
+ return status;
+}
+
+#endif /* gcdENABLE_VG */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_db.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_db.c
new file mode 100644
index 000000000000..49c261a633f0
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_db.c
@@ -0,0 +1,1877 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#define _GC_OBJ_ZONE gcvZONE_DATABASE
+
+/*******************************************************************************
+***** Private fuctions ********************************************************/
+
+#define _GetSlot(database, x) \
+ (gctUINT32)(gcmPTR_TO_UINT64(x) % gcmCOUNTOF(database->list))
+
+/*******************************************************************************
+** gckKERNEL_FindDatabase
+**
+** Find a database identified by a process ID and move it to the head of the
+** hash list.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to a gckKERNEL object.
+**
+** gctUINT32 ProcessID
+** ProcessID that identifies the database.
+**
+** gctBOOL LastProcessID
+** gcvTRUE if searching for the last known process ID. gcvFALSE if
+** we need to search for the process ID specified by the ProcessID
+** argument.
+**
+** OUTPUT:
+**
+** gcsDATABASE_PTR * Database
+** Pointer to a variable receiving the database structure pointer on
+** success.
+*/
+gceSTATUS
+gckKERNEL_FindDatabase(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctBOOL LastProcessID,
+ OUT gcsDATABASE_PTR * Database
+ )
+{
+ gceSTATUS status;
+ gcsDATABASE_PTR database, previous;
+ gctSIZE_T slot;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d LastProcessID=%d",
+ Kernel, ProcessID, LastProcessID);
+
+ /* Compute the hash for the database. */
+ slot = ProcessID % gcmCOUNTOF(Kernel->db->db);
+
+ /* Acquire the database mutex. */
+ gcmkONERROR(
+ gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Check whether we are getting the last known database. */
+ if (LastProcessID)
+ {
+ /* Use last database. */
+ database = Kernel->db->lastDatabase;
+
+ if (database == gcvNULL)
+ {
+ /* Database not found. */
+ gcmkONERROR(gcvSTATUS_INVALID_DATA);
+ }
+ }
+ else
+ {
+ /* Walk the hash list. */
+ for (previous = gcvNULL, database = Kernel->db->db[slot];
+ database != gcvNULL;
+ database = database->next)
+ {
+ if (database->processID == ProcessID)
+ {
+ /* Found it! */
+ break;
+ }
+
+ previous = database;
+ }
+
+ if (database == gcvNULL)
+ {
+ /* Database not found. */
+ gcmkONERROR(gcvSTATUS_INVALID_DATA);
+ }
+
+ if (previous != gcvNULL)
+ {
+ /* Move database to the head of the hash list. */
+ previous->next = database->next;
+ database->next = Kernel->db->db[slot];
+ Kernel->db->db[slot] = database;
+ }
+ }
+
+ /* Release the database mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+
+ /* Return the database. */
+ *Database = database;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Database=0x%x", *Database);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ /* Release the database mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+** gckKERNEL_DeinitDatabase
+**
+** De-init a database structure.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to a gckKERNEL object.
+**
+** gcsDATABASE_PTR Database
+** Pointer to the database structure to deinit.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+static gceSTATUS
+gckKERNEL_DeinitDatabase(
+ IN gckKERNEL Kernel,
+ IN gcsDATABASE_PTR Database
+ )
+{
+ gcmkHEADER_ARG("Kernel=0x%x Database=0x%x", Kernel, Database);
+
+ if (Database)
+ {
+ Database->deleted = gcvFALSE;
+
+ /* Destory handle db. */
+ if (Database->refs)
+ {
+ gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, Database->refs));
+ Database->refs = gcvNULL;
+ }
+
+ if (Database->handleDatabase)
+ {
+ gcmkVERIFY_OK(gckKERNEL_DestroyIntegerDatabase(Kernel, Database->handleDatabase));
+ Database->handleDatabase = gcvNULL;
+ }
+
+ if (Database->handleDatabaseMutex)
+ {
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Database->handleDatabaseMutex));
+ Database->handleDatabaseMutex = gcvNULL;
+ }
+
+#if gcdPROCESS_ADDRESS_SPACE
+ if (Database->mmu)
+ {
+ gcmkONERROR(gckEVENT_DestroyMmu(Kernel->eventObj, Database->mmu, gcvKERNEL_PIXEL));
+ Database->mmu = gcvNULL;
+ }
+#endif
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+** gckKERNEL_NewRecord
+**
+** Create a new database record structure and insert it to the head of the
+** database.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to a gckKERNEL object.
+**
+** gcsDATABASE_PTR Database
+** Pointer to a database structure.
+**
+** OUTPUT:
+**
+** gcsDATABASE_RECORD_PTR * Record
+** Pointer to a variable receiving the database record structure
+** pointer on success.
+*/
+static gceSTATUS
+gckKERNEL_NewRecord(
+ IN gckKERNEL Kernel,
+ IN gcsDATABASE_PTR Database,
+ IN gctUINT32 Slot,
+ OUT gcsDATABASE_RECORD_PTR * Record
+ )
+{
+ gceSTATUS status;
+ gctBOOL acquired = gcvFALSE;
+ gcsDATABASE_RECORD_PTR record = gcvNULL;
+
+ gcmkHEADER_ARG("Kernel=0x%x Database=0x%x", Kernel, Database);
+
+ /* Acquire the database mutex. */
+ gcmkONERROR(
+ gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ if (Kernel->db->freeRecord != gcvNULL)
+ {
+ /* Allocate the record from the free list. */
+ record = Kernel->db->freeRecord;
+ Kernel->db->freeRecord = record->next;
+ }
+ else
+ {
+ gctPOINTER pointer = gcvNULL;
+
+ /* Allocate the record from the heap. */
+ gcmkONERROR(gckOS_Allocate(Kernel->os,
+ gcmSIZEOF(gcsDATABASE_RECORD),
+ &pointer));
+
+ record = pointer;
+ }
+
+ /* Insert the record in the database. */
+ record->next = Database->list[Slot];
+ Database->list[Slot] = record;
+
+ /* Release the database mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+
+ /* Return the record. */
+ *Record = record;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Record=0x%x", *Record);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ /* Release the database mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+ }
+ if (record != gcvNULL)
+ {
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, record));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+** gckKERNEL_DeleteRecord
+**
+** Remove a database record from the database and delete its structure.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to a gckKERNEL object.
+**
+** gcsDATABASE_PTR Database
+** Pointer to a database structure.
+**
+** gceDATABASE_TYPE Type
+** Type of the record to remove.
+**
+** gctPOINTER Data
+** Data of the record to remove.
+**
+** OUTPUT:
+**
+** gctSIZE_T_PTR Bytes
+** Pointer to a variable that receives the size of the record deleted.
+** Can be gcvNULL if the size is not required.
+*/
+static gceSTATUS
+gckKERNEL_DeleteRecord(
+ IN gckKERNEL Kernel,
+ IN gcsDATABASE_PTR Database,
+ IN gceDATABASE_TYPE Type,
+ IN gctPOINTER Data,
+ OUT gctSIZE_T_PTR Bytes OPTIONAL
+ )
+{
+ gceSTATUS status;
+ gctBOOL acquired = gcvFALSE;
+ gcsDATABASE_RECORD_PTR record, previous;
+ gctUINT32 slot = _GetSlot(Database, Data);
+
+ gcmkHEADER_ARG("Kernel=0x%x Database=0x%x Type=%d Data=0x%x",
+ Kernel, Database, Type, Data);
+
+ /* Acquire the database mutex. */
+ gcmkONERROR(
+ gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Scan the database for this record. */
+ for (record = Database->list[slot], previous = gcvNULL;
+ record != gcvNULL;
+ record = record->next
+ )
+ {
+ if ((record->type == Type)
+ && (record->data == Data)
+ )
+ {
+ /* Found it! */
+ break;
+ }
+
+ previous = record;
+ }
+
+ if (record == gcvNULL)
+ {
+ /* Ouch! This record is not found? */
+ gcmkONERROR(gcvSTATUS_INVALID_DATA);
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return size of record. */
+ *Bytes = record->bytes;
+ }
+
+ /* Remove record from database. */
+ if (previous == gcvNULL)
+ {
+ Database->list[slot] = record->next;
+ }
+ else
+ {
+ previous->next = record->next;
+ }
+
+ /* Insert record in free list. */
+ record->next = Kernel->db->freeRecord;
+ Kernel->db->freeRecord = record;
+
+ /* Release the database mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ /* Release the database mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+** gckKERNEL_FindRecord
+**
+** Find a database record from the database.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to a gckKERNEL object.
+**
+** gcsDATABASE_PTR Database
+** Pointer to a database structure.
+**
+** gceDATABASE_TYPE Type
+** Type of the record to remove.
+**
+** gctPOINTER Data
+** Data of the record to remove.
+**
+** OUTPUT:
+**
+** gctSIZE_T_PTR Bytes
+** Pointer to a variable that receives the size of the record deleted.
+** Can be gcvNULL if the size is not required.
+*/
+static gceSTATUS
+gckKERNEL_FindRecord(
+ IN gckKERNEL Kernel,
+ IN gcsDATABASE_PTR Database,
+ IN gceDATABASE_TYPE Type,
+ IN gctPOINTER Data,
+ OUT gcsDATABASE_RECORD_PTR Record
+ )
+{
+ gceSTATUS status;
+ gctBOOL acquired = gcvFALSE;
+ gcsDATABASE_RECORD_PTR record;
+ gctUINT32 slot = _GetSlot(Database, Data);
+
+ gcmkHEADER_ARG("Kernel=0x%x Database=0x%x Type=%d Data=0x%x",
+ Kernel, Database, Type, Data);
+
+ /* Acquire the database mutex. */
+ gcmkONERROR(
+ gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Scan the database for this record. */
+ for (record = Database->list[slot];
+ record != gcvNULL;
+ record = record->next
+ )
+ {
+ if ((record->type == Type)
+ && (record->data == Data)
+ )
+ {
+ /* Found it! */
+ break;
+ }
+ }
+
+ if (record == gcvNULL)
+ {
+ /* Ouch! This record is not found? */
+ gcmkONERROR(gcvSTATUS_INVALID_DATA);
+ }
+
+ if (Record != gcvNULL)
+ {
+ /* Return information of record. */
+ gcmkONERROR(
+ gckOS_MemCopy(Record, record, sizeof(gcsDATABASE_RECORD)));
+ }
+
+ /* Release the database mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+
+ /* Success. */
+ gcmkFOOTER_ARG("Record=0x%x", Record);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ /* Release the database mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+***** Public API **************************************************************/
+
+/*******************************************************************************
+** gckKERNEL_CreateProcessDB
+**
+** Create a new process database.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to a gckKERNEL object.
+**
+** gctUINT32 ProcessID
+** Process ID used to identify the database.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckKERNEL_CreateProcessDB(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+ gcsDATABASE_PTR database = gcvNULL;
+ gctPOINTER pointer = gcvNULL;
+ gctBOOL acquired = gcvFALSE;
+ gctSIZE_T slot;
+ gctUINT32 i;
+
+ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
+
+ /* Compute the hash for the database. */
+ slot = ProcessID % gcmCOUNTOF(Kernel->db->db);
+
+ /* Acquire the database mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Walk the hash list. */
+ for (database = Kernel->db->db[slot];
+ database != gcvNULL;
+ database = database->next)
+ {
+ if (database->processID == ProcessID)
+ {
+ gctINT32 oldVal = 0;
+
+ if (database->deleted)
+ {
+ gcmkFATAL("%s(%d): DB of Process=0x%x cannot be reentered since it was in deletion\n",
+ __FUNCTION__, __LINE__, ProcessID);
+ gcmkONERROR(gcvSTATUS_INVALID_REQUEST);
+ }
+
+ gcmkVERIFY_OK(gckOS_AtomIncrement(Kernel->os, database->refs, &oldVal));
+ goto OnExit;
+ }
+ }
+
+ if (Kernel->db->freeDatabase)
+ {
+ /* Allocate a database from the free list. */
+ database = Kernel->db->freeDatabase;
+ Kernel->db->freeDatabase = database->next;
+ }
+ else
+ {
+ /* Allocate a new database from the heap. */
+ gcmkONERROR(gckOS_Allocate(Kernel->os,
+ gcmSIZEOF(gcsDATABASE),
+ &pointer));
+
+ gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsDATABASE));
+
+ database = pointer;
+
+ gcmkONERROR(gckOS_CreateMutex(Kernel->os, &database->counterMutex));
+ }
+
+ /* Initialize the database. */
+ /* Save the hash slot. */
+ database->slot = slot;
+ database->processID = ProcessID;
+ database->vidMem.bytes = 0;
+ database->vidMem.maxBytes = 0;
+ database->vidMem.totalBytes = 0;
+ database->nonPaged.bytes = 0;
+ database->nonPaged.maxBytes = 0;
+ database->nonPaged.totalBytes = 0;
+ database->contiguous.bytes = 0;
+ database->contiguous.maxBytes = 0;
+ database->contiguous.totalBytes = 0;
+ database->mapMemory.bytes = 0;
+ database->mapMemory.maxBytes = 0;
+ database->mapMemory.totalBytes = 0;
+ database->mapUserMemory.bytes = 0;
+ database->mapUserMemory.maxBytes = 0;
+ database->mapUserMemory.totalBytes = 0;
+
+ for (i = 0; i < gcmCOUNTOF(database->list); i++)
+ {
+ database->list[i] = gcvNULL;
+ }
+
+ for (i = 0; i < gcvSURF_NUM_TYPES; i++)
+ {
+ database->vidMemType[i].bytes = 0;
+ database->vidMemType[i].maxBytes = 0;
+ database->vidMemType[i].totalBytes = 0;
+ }
+
+ for (i = 0; i < gcvPOOL_NUMBER_OF_POOLS; i++)
+ {
+ database->vidMemPool[i].bytes = 0;
+ database->vidMemPool[i].maxBytes = 0;
+ database->vidMemPool[i].totalBytes = 0;
+ }
+
+ gcmkASSERT(database->refs == gcvNULL);
+ gcmkONERROR(gckOS_AtomConstruct(Kernel->os, &database->refs));
+ gcmkONERROR(gckOS_AtomSet(Kernel->os, database->refs, 1));
+
+ gcmkASSERT(database->handleDatabase == gcvNULL);
+ gcmkONERROR(gckKERNEL_CreateIntegerDatabase(Kernel, &database->handleDatabase));
+
+ gcmkASSERT(database->handleDatabaseMutex == gcvNULL);
+ gcmkONERROR(gckOS_CreateMutex(Kernel->os, &database->handleDatabaseMutex));
+
+#if gcdPROCESS_ADDRESS_SPACE
+ gcmkASSERT(database->mmu == gcvNULL);
+ gcmkONERROR(gckMMU_Construct(Kernel, gcdMMU_SIZE, &database->mmu));
+#endif
+
+#if gcdSECURE_USER
+ {
+ gctINT idx;
+ gcskSECURE_CACHE * cache = &database->cache;
+
+ /* Setup the linked list of cache nodes. */
+ for (idx = 1; idx <= gcdSECURE_CACHE_SLOTS; ++idx)
+ {
+ cache->cache[idx].logical = gcvNULL;
+
+#if gcdSECURE_CACHE_METHOD != gcdSECURE_CACHE_TABLE
+ cache->cache[idx].prev = &cache->cache[idx - 1];
+ cache->cache[idx].next = &cache->cache[idx + 1];
+# endif
+#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
+ cache->cache[idx].nextHash = gcvNULL;
+ cache->cache[idx].prevHash = gcvNULL;
+# endif
+ }
+
+#if gcdSECURE_CACHE_METHOD != gcdSECURE_CACHE_TABLE
+ /* Setup the head and tail of the cache. */
+ cache->cache[0].next = &cache->cache[1];
+ cache->cache[0].prev = &cache->cache[gcdSECURE_CACHE_SLOTS];
+ cache->cache[0].logical = gcvNULL;
+
+ /* Fix up the head and tail pointers. */
+ cache->cache[0].next->prev = &cache->cache[0];
+ cache->cache[0].prev->next = &cache->cache[0];
+# endif
+
+#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH
+ /* Zero out the hash table. */
+ for (idx = 0; idx < gcmCOUNTOF(cache->hash); ++idx)
+ {
+ cache->hash[idx].logical = gcvNULL;
+ cache->hash[idx].nextHash = gcvNULL;
+ }
+# endif
+
+ /* Initialize cache index. */
+ cache->cacheIndex = gcvNULL;
+ cache->cacheFree = 1;
+ cache->cacheStamp = 0;
+ }
+#endif
+
+ /* Insert the database into the hash. */
+ database->next = Kernel->db->db[slot];
+ Kernel->db->db[slot] = database;
+
+ /* Reset idle timer. */
+ Kernel->db->lastIdle = 0;
+
+OnError:
+ if (gcmIS_ERROR(status))
+ {
+ gcmkVERIFY_OK(gckKERNEL_DeinitDatabase(Kernel, database));
+
+ if (pointer)
+ {
+ gcmkOS_SAFE_FREE(Kernel->os, pointer);
+ }
+ }
+
+OnExit:
+ if (acquired)
+ {
+ /* Release the database mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+** gckKERNEL_AddProcessDB
+**
+** Add a record to a process database.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to a gckKERNEL object.
+**
+** gctUINT32 ProcessID
+** Process ID used to identify the database.
+**
+** gceDATABASE_TYPE TYPE
+** Type of the record to add.
+**
+** gctPOINTER Pointer
+** Data of the record to add.
+**
+** gctPHYS_ADDR Physical
+** Physical address of the record to add.
+**
+** gctSIZE_T Size
+** Size of the record to add.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckKERNEL_AddProcessDB(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gceDATABASE_TYPE Type,
+ IN gctPOINTER Pointer,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Size
+ )
+{
+ gceSTATUS status;
+ gcsDATABASE_PTR database;
+ gcsDATABASE_RECORD_PTR record = gcvNULL;
+ gcsDATABASE_COUNTERS * count;
+ gctUINT32 vidMemType;
+ gcePOOL vidMemPool;
+
+ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x "
+ "Physical=0x%x Size=%lu",
+ Kernel, ProcessID, Type, Pointer, Physical, Size);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+ /* Decode type. */
+ vidMemType = (Type & gcdDB_VIDEO_MEMORY_TYPE_MASK) >> gcdDB_VIDEO_MEMORY_TYPE_SHIFT;
+ vidMemPool = (Type & gcdDB_VIDEO_MEMORY_POOL_MASK) >> gcdDB_VIDEO_MEMORY_POOL_SHIFT;
+
+ Type &= gcdDATABASE_TYPE_MASK;
+
+ /* Special case the idle record. */
+ if (Type == gcvDB_IDLE)
+ {
+ gctUINT64 time;
+
+ /* Get the current profile time. */
+ gcmkONERROR(gckOS_GetProfileTick(&time));
+
+ if ((ProcessID == 0) && (Kernel->db->lastIdle != 0))
+ {
+ /* Out of idle, adjust time it was idle. */
+ Kernel->db->idleTime += time - Kernel->db->lastIdle;
+ Kernel->db->lastIdle = 0;
+ }
+ else if (ProcessID == 1)
+ {
+ /* Save current idle time. */
+ Kernel->db->lastIdle = time;
+ }
+
+#if gcdDYNAMIC_SPEED
+ {
+ /* Test for first call. */
+ if (Kernel->db->lastSlowdown == 0)
+ {
+ /* Save milliseconds. */
+ Kernel->db->lastSlowdown = time;
+ Kernel->db->lastSlowdownIdle = Kernel->db->idleTime;
+ }
+ else
+ {
+ /* Compute ellapsed time in milliseconds. */
+ gctUINT delta = gckOS_ProfileToMS(time - Kernel->db->lastSlowdown);
+
+ /* Test for end of period. */
+ if (delta >= gcdDYNAMIC_SPEED)
+ {
+ /* Compute number of idle milliseconds. */
+ gctUINT idle = gckOS_ProfileToMS(
+ Kernel->db->idleTime - Kernel->db->lastSlowdownIdle);
+
+ /* Broadcast to slow down the GPU. */
+ gcmkONERROR(gckOS_BroadcastCalibrateSpeed(Kernel->os,
+ Kernel->hardware,
+ idle,
+ delta));
+
+ /* Save current time. */
+ Kernel->db->lastSlowdown = time;
+ Kernel->db->lastSlowdownIdle = Kernel->db->idleTime;
+ }
+ }
+ }
+#endif
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+ /* Verify the arguments. */
+ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
+
+ /* Find the database. */
+ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
+
+ /* Create a new record in the database. */
+ gcmkONERROR(gckKERNEL_NewRecord(Kernel, database, _GetSlot(database, Pointer), &record));
+
+ /* Initialize the record. */
+ record->kernel = Kernel;
+ record->type = Type;
+ record->data = Pointer;
+ record->physical = Physical;
+ record->bytes = Size;
+
+ /* Get pointer to counters. */
+ switch (Type)
+ {
+ case gcvDB_VIDEO_MEMORY:
+ count = &database->vidMem;
+ break;
+
+ case gcvDB_NON_PAGED:
+ count = &database->nonPaged;
+ break;
+
+ case gcvDB_CONTIGUOUS:
+ count = &database->contiguous;
+ break;
+
+ case gcvDB_MAP_MEMORY:
+ count = &database->mapMemory;
+ break;
+
+ case gcvDB_MAP_USER_MEMORY:
+ count = &database->mapUserMemory;
+ break;
+
+ default:
+ count = gcvNULL;
+ break;
+ }
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, database->counterMutex, gcvINFINITE));
+
+ if (count != gcvNULL)
+ {
+ /* Adjust counters. */
+ count->totalBytes += Size;
+ count->bytes += Size;
+ count->allocCount++;
+
+ if (count->bytes > count->maxBytes)
+ {
+ count->maxBytes = count->bytes;
+ }
+ }
+
+ if (Type == gcvDB_VIDEO_MEMORY)
+ {
+ count = &database->vidMemType[vidMemType];
+
+ /* Adjust counters. */
+ count->totalBytes += Size;
+ count->bytes += Size;
+ count->allocCount++;
+
+ if (count->bytes > count->maxBytes)
+ {
+ count->maxBytes = count->bytes;
+ }
+
+ count = &database->vidMemPool[vidMemPool];
+
+ /* Adjust counters. */
+ count->totalBytes += Size;
+ count->bytes += Size;
+ count->allocCount++;
+
+ if (count->bytes > count->maxBytes)
+ {
+ count->maxBytes = count->bytes;
+ }
+ }
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, database->counterMutex));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+** gckKERNEL_RemoveProcessDB
+**
+** Remove a record from a process database.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to a gckKERNEL object.
+**
+** gctUINT32 ProcessID
+** Process ID used to identify the database.
+**
+** gceDATABASE_TYPE TYPE
+** Type of the record to remove.
+**
+** gctPOINTER Pointer
+** Data of the record to remove.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckKERNEL_RemoveProcessDB(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gceDATABASE_TYPE Type,
+ IN gctPOINTER Pointer
+ )
+{
+ gceSTATUS status;
+ gcsDATABASE_PTR database;
+ gctSIZE_T bytes = 0;
+ gctUINT32 vidMemType;
+ gcePOOL vidMemPool;
+
+ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x",
+ Kernel, ProcessID, Type, Pointer);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
+
+ /* Decode type. */
+ vidMemType = (Type & gcdDB_VIDEO_MEMORY_TYPE_MASK) >> gcdDB_VIDEO_MEMORY_TYPE_SHIFT;
+ vidMemPool = (Type & gcdDB_VIDEO_MEMORY_POOL_MASK) >> gcdDB_VIDEO_MEMORY_POOL_SHIFT;
+
+ Type &= gcdDATABASE_TYPE_MASK;
+
+ /* Find the database. */
+ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
+
+ /* Delete the record. */
+ gcmkONERROR(
+ gckKERNEL_DeleteRecord(Kernel, database, Type, Pointer, &bytes));
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, database->counterMutex, gcvINFINITE));
+
+ /* Update counters. */
+ switch (Type)
+ {
+ case gcvDB_VIDEO_MEMORY:
+ database->vidMem.bytes -= bytes;
+ database->vidMem.freeCount++;
+ database->vidMemType[vidMemType].bytes -= bytes;
+ database->vidMemType[vidMemType].freeCount++;
+ database->vidMemPool[vidMemPool].bytes -= bytes;
+ database->vidMemPool[vidMemPool].freeCount++;
+ break;
+
+ case gcvDB_NON_PAGED:
+ database->nonPaged.bytes -= bytes;
+ database->nonPaged.freeCount++;
+ break;
+
+ case gcvDB_CONTIGUOUS:
+ database->contiguous.bytes -= bytes;
+ database->contiguous.freeCount++;
+ break;
+
+ case gcvDB_MAP_MEMORY:
+ database->mapMemory.bytes -= bytes;
+ database->mapMemory.freeCount++;
+ break;
+
+ case gcvDB_MAP_USER_MEMORY:
+ database->mapUserMemory.bytes -= bytes;
+ database->mapUserMemory.freeCount++;
+ break;
+
+ default:
+ break;
+ }
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, database->counterMutex));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+** gckKERNEL_FindProcessDB
+**
+** Find a record from a process database.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to a gckKERNEL object.
+**
+** gctUINT32 ProcessID
+** Process ID used to identify the database.
+**
+** gceDATABASE_TYPE TYPE
+** Type of the record to remove.
+**
+** gctPOINTER Pointer
+** Data of the record to remove.
+**
+** OUTPUT:
+**
+** gcsDATABASE_RECORD_PTR Record
+** Copy of record.
+*/
+gceSTATUS
+gckKERNEL_FindProcessDB(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctUINT32 ThreadID,
+ IN gceDATABASE_TYPE Type,
+ IN gctPOINTER Pointer,
+ OUT gcsDATABASE_RECORD_PTR Record
+ )
+{
+ gceSTATUS status;
+ gcsDATABASE_PTR database;
+
+ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x",
+ Kernel, ProcessID, ThreadID, Type, Pointer);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
+
+ /* Find the database. */
+ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
+
+ /* Find the record. */
+ gcmkONERROR(
+ gckKERNEL_FindRecord(Kernel, database, Type, Pointer, Record));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+** gckKERNEL_DestroyProcessDB
+**
+** Destroy a process database. If the database contains any records, the data
+** inside those records will be deleted as well. This aids in the cleanup if
+** a process has died unexpectedly or has memory leaks.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to a gckKERNEL object.
+**
+** gctUINT32 ProcessID
+** Process ID used to identify the database.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckKERNEL_DestroyProcessDB(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+ gckKERNEL kernel = Kernel;
+ gcsDATABASE_PTR previous = gcvNULL;
+ gcsDATABASE_PTR database = gcvNULL;
+ gcsDATABASE_PTR db = gcvNULL;
+ gctBOOL acquired = gcvFALSE;
+ gctSIZE_T slot;
+ gctUINT32 i;
+
+ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+ /* Compute the hash for the database. */
+ slot = ProcessID % gcmCOUNTOF(Kernel->db->db);
+
+ /* Acquire the database mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Walk the hash list. */
+ for (database = Kernel->db->db[slot];
+ database != gcvNULL;
+ database = database->next)
+ {
+ if (database->processID == ProcessID)
+ {
+ break;
+ }
+ }
+
+ if (database)
+ {
+ gctINT32 oldVal = 0;
+ gcmkONERROR(gckOS_AtomDecrement(Kernel->os, database->refs, &oldVal));
+ if (oldVal != 1)
+ {
+ goto OnExit;
+ }
+
+ /* Mark it for delete so disallow reenter until really delete it */
+ gcmkASSERT(!database->deleted);
+ database->deleted = gcvTRUE;
+ }
+ else
+ {
+ gcmkFATAL("%s(%d): DB destroy of Process=0x%x cannot match with creation\n",
+ __FUNCTION__, __LINE__, ProcessID);
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+
+ /* Cannot remove the database from the hash list
+ ** since later records deinit need to access from the hash
+ */
+
+ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+ acquired = gcvFALSE;
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
+ "DB(%d): VidMem: total=%lu max=%lu",
+ ProcessID, database->vidMem.totalBytes,
+ database->vidMem.maxBytes);
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
+ "DB(%d): NonPaged: total=%lu max=%lu",
+ ProcessID, database->nonPaged.totalBytes,
+ database->nonPaged.maxBytes);
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
+ "DB(%d): Contiguous: total=%lu max=%lu",
+ ProcessID, database->contiguous.totalBytes,
+ database->contiguous.maxBytes);
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
+ "DB(%d): Idle time=%llu",
+ ProcessID, Kernel->db->idleTime);
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
+ "DB(%d): Map: total=%lu max=%lu",
+ ProcessID, database->mapMemory.totalBytes,
+ database->mapMemory.maxBytes);
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE,
+ "DB(%d): Map: total=%lu max=%lu",
+ ProcessID, database->mapUserMemory.totalBytes,
+ database->mapUserMemory.maxBytes);
+
+ if (database->list != gcvNULL)
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+ "Process %d has entries in its database:",
+ ProcessID);
+ }
+
+ for (i = 0; i < gcmCOUNTOF(database->list); i++)
+ {
+ gcsDATABASE_RECORD_PTR record, next;
+
+ /* Walk all records. */
+ for (record = database->list[i]; record != gcvNULL; record = next)
+ {
+ gctBOOL asynchronous = gcvTRUE;
+ gckVIDMEM_NODE nodeObject;
+ gctPHYS_ADDR physical;
+ gctUINT32 handle;
+
+ /* Next next record. */
+ next = record->next;
+
+ /* Dispatch on record type. */
+ switch (record->type)
+ {
+ case gcvDB_VIDEO_MEMORY:
+ gcmkERR_BREAK(gckVIDMEM_HANDLE_Lookup(record->kernel,
+ ProcessID,
+ gcmPTR2INT32(record->data),
+ &nodeObject));
+
+ /* Free the video memory. */
+ gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(record->kernel,
+ ProcessID,
+ gcmPTR2INT32(record->data)));
+
+ gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(record->kernel,
+ nodeObject));
+
+ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+ "DB: VIDEO_MEMORY 0x%x (status=%d)",
+ record->data, status);
+ break;
+
+ case gcvDB_NON_PAGED:
+ physical = gcmNAME_TO_PTR(record->physical);
+ /* Unmap user logical memory first. */
+ status = gckOS_UnmapUserLogical(Kernel->os,
+ physical,
+ record->bytes,
+ record->data);
+
+ /* Free the non paged memory. */
+ status = gckEVENT_FreeNonPagedMemory(record->kernel->eventObj,
+ record->bytes,
+ physical,
+ record->data,
+ gcvKERNEL_PIXEL);
+ gcmRELEASE_NAME(record->physical);
+
+ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+ "DB: NON_PAGED 0x%x, bytes=%lu (status=%d)",
+ record->data, record->bytes, status);
+ break;
+
+ case gcvDB_COMMAND_BUFFER:
+ /* Free the command buffer. */
+ status = gckEVENT_DestroyVirtualCommandBuffer(record->kernel->eventObj,
+ record->bytes,
+ gcmNAME_TO_PTR(record->physical),
+ record->data,
+ gcvKERNEL_PIXEL);
+ gcmRELEASE_NAME(record->physical);
+
+ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+ "DB: COMMAND_BUFFER 0x%x, bytes=%lu (status=%d)",
+ record->data, record->bytes, status);
+ break;
+
+ case gcvDB_CONTIGUOUS:
+ physical = gcmNAME_TO_PTR(record->physical);
+ /* Unmap user logical memory first. */
+ status = gckOS_UnmapUserLogical(Kernel->os,
+ physical,
+ record->bytes,
+ record->data);
+
+ /* Free the contiguous memory. */
+ status = gckEVENT_FreeContiguousMemory(record->kernel->eventObj,
+ record->bytes,
+ physical,
+ record->data,
+ gcvKERNEL_PIXEL);
+ gcmRELEASE_NAME(record->physical);
+
+ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+ "DB: CONTIGUOUS 0x%x bytes=%lu (status=%d)",
+ record->data, record->bytes, status);
+ break;
+
+ case gcvDB_SIGNAL:
+#if USE_NEW_LINUX_SIGNAL
+ status = gcvSTATUS_NOT_SUPPORTED;
+#else
+ /* Free the user signal. */
+ status = gckOS_DestroyUserSignal(Kernel->os,
+ gcmPTR2INT32(record->data));
+#endif /* USE_NEW_LINUX_SIGNAL */
+
+ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+ "DB: SIGNAL %d (status=%d)",
+ (gctINT)(gctUINTPTR_T)record->data, status);
+ break;
+
+ case gcvDB_VIDEO_MEMORY_LOCKED:
+ handle = gcmPTR2INT32(record->data);
+
+ gcmkERR_BREAK(gckVIDMEM_HANDLE_Lookup(record->kernel,
+ ProcessID,
+ handle,
+ &nodeObject));
+
+ /* Unlock what we still locked */
+ status = gckVIDMEM_Unlock(record->kernel,
+ nodeObject,
+ nodeObject->type,
+ &asynchronous);
+
+#if gcdENABLE_VG
+ if (record->kernel->core == gcvCORE_VG)
+ {
+ if (gcmIS_SUCCESS(status) && (gcvTRUE == asynchronous))
+ {
+ status = gckVIDMEM_Unlock(record->kernel,
+ nodeObject,
+ nodeObject->type,
+ gcvNULL);
+ }
+
+ gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(record->kernel,
+ ProcessID,
+ handle));
+
+ gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(record->kernel,
+ nodeObject));
+ }
+ else
+#endif
+ {
+ gcmkVERIFY_OK(gckVIDMEM_HANDLE_Dereference(record->kernel,
+ ProcessID,
+ handle));
+
+ if (gcmIS_SUCCESS(status) && (gcvTRUE == asynchronous))
+ {
+ status = gckEVENT_Unlock(record->kernel->eventObj,
+ gcvKERNEL_PIXEL,
+ nodeObject,
+ nodeObject->type);
+ }
+ else
+ {
+ gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(record->kernel,
+ nodeObject));
+ }
+ }
+
+ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+ "DB: VIDEO_MEMORY_LOCKED 0x%x (status=%d)",
+ record->data, status);
+ break;
+
+ case gcvDB_CONTEXT:
+ status = gckCOMMAND_Detach(record->kernel->command, gcmNAME_TO_PTR(record->data));
+ gcmRELEASE_NAME(record->data);
+
+ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+ "DB: CONTEXT 0x%x (status=%d)",
+ record->data, status);
+ break;
+
+ case gcvDB_MAP_MEMORY:
+ /* Unmap memory. */
+ status = gckKERNEL_UnmapMemory(record->kernel,
+ record->physical,
+ record->bytes,
+ record->data,
+ ProcessID);
+
+ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+ "DB: MAP MEMORY %d (status=%d)",
+ gcmPTR2INT32(record->data), status);
+ break;
+
+ case gcvDB_MAP_USER_MEMORY:
+ status = gckOS_UnmapUserMemory(Kernel->os,
+ Kernel->core,
+ record->physical,
+ record->bytes,
+ gcmNAME_TO_PTR(record->data),
+ 0);
+ gcmRELEASE_NAME(record->data);
+
+ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+ "DB: MAP USER MEMORY %d (status=%d)",
+ gcmPTR2INT32(record->data), status);
+ break;
+
+ case gcvDB_SHBUF:
+ /* Free shared buffer. */
+ status = gckKERNEL_DestroyShBuffer(record->kernel,
+ (gctSHBUF) record->data);
+
+ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE,
+ "DB: SHBUF %u (status=%d)",
+ (gctUINT32)(gctUINTPTR_T) record->data, status);
+ break;
+
+ default:
+ gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DATABASE,
+ "DB: Correcupted record=0x%08x type=%d",
+ record, record->type);
+ break;
+ }
+
+ /* Delete the record. */
+ gcmkONERROR(gckKERNEL_DeleteRecord(Kernel,
+ database,
+ record->type,
+ record->data,
+ gcvNULL));
+ }
+ }
+
+ /* Acquire the database mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Walk the hash list. */
+ for (db = Kernel->db->db[slot];
+ db != gcvNULL;
+ db = db->next)
+ {
+ if (db->processID == ProcessID)
+ {
+ break;
+ }
+ previous = db;
+ }
+
+ if (db != database || !db->deleted)
+ {
+ gcmkFATAL("%s(%d): DB of Process=0x%x corrupted after found in deletion\n",
+ __FUNCTION__, __LINE__, ProcessID);
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+
+ /* Remove the database from the hash list. */
+ if (previous)
+ {
+ previous->next = database->next;
+ }
+ else
+ {
+ Kernel->db->db[slot] = database->next;
+ }
+
+ /* Deinit current database. */
+ gcmkVERIFY_OK(gckKERNEL_DeinitDatabase(Kernel, database));
+
+ if (Kernel->db->lastDatabase)
+ {
+ /* Insert last database to the free list. */
+ Kernel->db->lastDatabase->next = Kernel->db->freeDatabase;
+ Kernel->db->freeDatabase = Kernel->db->lastDatabase;
+ }
+
+ /* Update last database to current one. */
+ Kernel->db->lastDatabase = database;
+
+OnError:
+OnExit:
+ if (acquired)
+ {
+ /* Release the database mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+ }
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+** gckKERNEL_QueryProcessDB
+**
+** Query a process database for the current usage of a particular record type.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to a gckKERNEL object.
+**
+** gctUINT32 ProcessID
+** Process ID used to identify the database.
+**
+** gctBOOL LastProcessID
+** gcvTRUE if searching for the last known process ID. gcvFALSE if
+** we need to search for the process ID specified by the ProcessID
+** argument.
+**
+** gceDATABASE_TYPE Type
+** Type of the record to query.
+**
+** OUTPUT:
+**
+** gcuDATABASE_INFO * Info
+** Pointer to a variable that receives the requested information.
+*/
+gceSTATUS
+gckKERNEL_QueryProcessDB(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctBOOL LastProcessID,
+ IN gceDATABASE_TYPE Type,
+ OUT gcuDATABASE_INFO * Info
+ )
+{
+ gceSTATUS status;
+ gcsDATABASE_PTR database;
+ gcePOOL vidMemPool;
+
+ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Info=0x%x",
+ Kernel, ProcessID, Type, Info);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Info != gcvNULL);
+
+ /* Deocde pool. */
+ vidMemPool = (Type & gcdDB_VIDEO_MEMORY_POOL_MASK) >> gcdDB_VIDEO_MEMORY_POOL_SHIFT;
+
+ Type &= gcdDATABASE_TYPE_MASK;
+
+ /* Find the database. */
+ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, LastProcessID, &database));
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, database->counterMutex, gcvINFINITE));
+
+ /* Get pointer to counters. */
+ switch (Type)
+ {
+ case gcvDB_VIDEO_MEMORY:
+ if (vidMemPool != gcvPOOL_UNKNOWN)
+ {
+ gckOS_MemCopy(&Info->counters,
+ &database->vidMemPool[vidMemPool],
+ gcmSIZEOF(database->vidMemPool[vidMemPool]));
+ }
+ else
+ {
+ gckOS_MemCopy(&Info->counters,
+ &database->vidMem,
+ gcmSIZEOF(database->vidMem));
+ }
+ break;
+
+ case gcvDB_NON_PAGED:
+ gckOS_MemCopy(&Info->counters,
+ &database->nonPaged,
+ gcmSIZEOF(database->vidMem));
+ break;
+
+ case gcvDB_CONTIGUOUS:
+ gckOS_MemCopy(&Info->counters,
+ &database->contiguous,
+ gcmSIZEOF(database->vidMem));
+ break;
+
+ case gcvDB_IDLE:
+ Info->time = Kernel->db->idleTime;
+ Kernel->db->idleTime = 0;
+ break;
+
+ case gcvDB_MAP_MEMORY:
+ gckOS_MemCopy(&Info->counters,
+ &database->mapMemory,
+ gcmSIZEOF(database->mapMemory));
+ break;
+
+ case gcvDB_MAP_USER_MEMORY:
+ gckOS_MemCopy(&Info->counters,
+ &database->mapUserMemory,
+ gcmSIZEOF(database->mapUserMemory));
+ break;
+
+ default:
+ break;
+ }
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, database->counterMutex));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_FindHandleDatbase(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ OUT gctPOINTER * HandleDatabase,
+ OUT gctPOINTER * HandleDatabaseMutex
+ )
+{
+ gceSTATUS status;
+ gcsDATABASE_PTR database;
+
+ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d",
+ Kernel, ProcessID);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+ /* Find the database. */
+ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
+
+ *HandleDatabase = database->handleDatabase;
+ *HandleDatabaseMutex = database->handleDatabaseMutex;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+#if gcdPROCESS_ADDRESS_SPACE
+gceSTATUS
+gckKERNEL_GetProcessMMU(
+ IN gckKERNEL Kernel,
+ OUT gckMMU * Mmu
+ )
+{
+ gceSTATUS status;
+ gcsDATABASE_PTR database;
+ gctUINT32 processID;
+
+ gcmkONERROR(gckOS_GetProcessID(&processID));
+
+ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, processID, gcvFALSE, &database));
+
+ *Mmu = database->mmu;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+#endif
+
+#if gcdSECURE_USER
+/*******************************************************************************
+** gckKERNEL_GetProcessDBCache
+**
+** Get teh secure cache from a process database.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to a gckKERNEL object.
+**
+** gctUINT32 ProcessID
+** Process ID used to identify the database.
+**
+** OUTPUT:
+**
+** gcskSECURE_CACHE_PTR * Cache
+** Pointer to a variable that receives the secure cache pointer.
+*/
+gceSTATUS
+gckKERNEL_GetProcessDBCache(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ OUT gcskSECURE_CACHE_PTR * Cache
+ )
+{
+ gceSTATUS status;
+ gcsDATABASE_PTR database;
+
+ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Cache != gcvNULL);
+
+ /* Find the database. */
+ gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
+
+ /* Return the pointer to the cache. */
+ *Cache = &database->cache;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Cache=0x%x", *Cache);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+#endif
+
+gceSTATUS
+gckKERNEL_DumpProcessDB(
+ IN gckKERNEL Kernel
+ )
+{
+ gcsDATABASE_PTR database;
+ gctINT i, pid;
+ gctUINT8 name[24];
+
+ gcmkHEADER_ARG("Kernel=0x%x", Kernel);
+
+ /* Acquire the database mutex. */
+ gcmkVERIFY_OK(
+ gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+
+ gcmkPRINT("**************************\n");
+ gcmkPRINT("*** PROCESS DB DUMP ***\n");
+ gcmkPRINT("**************************\n");
+
+ gcmkPRINT_N(8, "%-8s%s\n", "PID", "NAME");
+ /* Walk the databases. */
+ for (i = 0; i < gcmCOUNTOF(Kernel->db->db); ++i)
+ {
+ for (database = Kernel->db->db[i];
+ database != gcvNULL;
+ database = database->next)
+ {
+ pid = database->processID;
+
+ gcmkVERIFY_OK(gckOS_ZeroMemory(name, gcmSIZEOF(name)));
+
+ gcmkVERIFY_OK(gckOS_GetProcessNameByPid(pid, gcmSIZEOF(name), name));
+
+ gcmkPRINT_N(8, "%-8d%s\n", pid, name);
+ }
+ }
+
+ /* Release the database mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+void
+_DumpCounter(
+ IN gcsDATABASE_COUNTERS * Counter,
+ IN gctCONST_STRING Name
+ )
+{
+ gcmkPRINT("%s:", Name);
+ gcmkPRINT(" Currently allocated : %10lld", Counter->bytes);
+ gcmkPRINT(" Maximum allocated : %10lld", Counter->maxBytes);
+ gcmkPRINT(" Total allocated : %10lld", Counter->totalBytes);
+}
+
+gceSTATUS
+gckKERNEL_DumpVidMemUsage(
+ IN gckKERNEL Kernel,
+ IN gctINT32 ProcessID
+ )
+{
+ gceSTATUS status;
+ gcsDATABASE_PTR database;
+ gcsDATABASE_COUNTERS * counter;
+ gctUINT32 i = 0;
+
+ static gctCONST_STRING surfaceTypes[] = {
+ "UNKNOWN",
+ "INDEX",
+ "VERTEX",
+ "TEXTURE",
+ "RENDER_TARGET",
+ "DEPTH",
+ "BITMAP",
+ "TILE_STATUS",
+ "IMAGE",
+ "MASK",
+ "SCISSOR",
+ "HIERARCHICAL_DEPTH",
+ "ICACHE",
+ "TXDESC",
+ "FENCE",
+ "TFBHEADER",
+ };
+
+ gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d",
+ Kernel, ProcessID);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+ /* Find the database. */
+ gcmkONERROR(
+ gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database));
+
+ gcmkPRINT("VidMem Usage (Process %d):", ProcessID);
+
+ /* Get pointer to counters. */
+ counter = &database->vidMem;
+
+ _DumpCounter(counter, "Total Video Memory");
+
+ for (i = 0; i < gcvSURF_NUM_TYPES; i++)
+ {
+ counter = &database->vidMemType[i];
+
+ _DumpCounter(counter, surfaceTypes[i]);
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_debug.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_debug.c
new file mode 100644
index 000000000000..f526793296d9
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_debug.c
@@ -0,0 +1,2865 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+#include <gc_hal_kernel_debug.h>
+
+/******************************************************************************\
+******************************** Debug Variables *******************************
+\******************************************************************************/
+
+static gceSTATUS _lastError = gcvSTATUS_OK;
+static gctUINT32 _debugLevel = gcvLEVEL_ERROR;
+/*
+_debugZones config value
+Please Reference define in gc_hal_base.h
+*/
+static gctUINT32 _debugZones = gcvZONE_NONE;
+
+/******************************************************************************\
+********************************* Debug Switches *******************************
+\******************************************************************************/
+
+/*
+ gcdBUFFERED_OUTPUT
+
+ When set to non-zero, all output is collected into a buffer with the
+ specified size. Once the buffer gets full, the debug buffer will be
+ printed to the console. gcdBUFFERED_SIZE determines the size of the buffer.
+*/
+#define gcdBUFFERED_OUTPUT 0
+
+/*
+ gcdBUFFERED_SIZE
+
+ When set to non-zero, all output is collected into a buffer with the
+ specified size. Once the buffer gets full, the debug buffer will be
+ printed to the console.
+*/
+#define gcdBUFFERED_SIZE (1024 * 1024 * 2)
+
+/*
+ gcdDMA_BUFFER_COUNT
+
+ If greater then zero, the debugger will attempt to find the command buffer
+ where DMA is currently executing and then print this buffer and
+ (gcdDMA_BUFFER_COUNT - 1) buffers before the current one. If set to zero
+ or the current buffer is not found, all buffers are printed.
+*/
+#define gcdDMA_BUFFER_COUNT 0
+
+/*
+ gcdTHREAD_BUFFERS
+
+ When greater then one, will accumulate messages from the specified number
+ of threads in separate output buffers.
+*/
+#define gcdTHREAD_BUFFERS 1
+
+/*
+ gcdENABLE_OVERFLOW
+
+ When set to non-zero, and the output buffer gets full, instead of being
+ printed, it will be allowed to overflow removing the oldest messages.
+*/
+#define gcdENABLE_OVERFLOW 1
+
+/*
+ gcdSHOW_LINE_NUMBER
+
+ When enabledm each print statement will be preceeded with the current
+ line number.
+*/
+#define gcdSHOW_LINE_NUMBER 0
+
+/*
+ gcdSHOW_PROCESS_ID
+
+ When enabledm each print statement will be preceeded with the current
+ process ID.
+*/
+#define gcdSHOW_PROCESS_ID 0
+
+/*
+ gcdSHOW_THREAD_ID
+
+ When enabledm each print statement will be preceeded with the current
+ thread ID.
+*/
+#define gcdSHOW_THREAD_ID 0
+
+/*
+ gcdSHOW_TIME
+
+ When enabled each print statement will be preceeded with the current
+ high-resolution time.
+*/
+#define gcdSHOW_TIME 0
+
+
+/******************************************************************************\
+****************************** Miscellaneous Macros ****************************
+\******************************************************************************/
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+# define gcmDBGASSERT(Expression, Format, Value) \
+ if (!(Expression)) \
+ { \
+ _DirectPrint( \
+ "*** gcmDBGASSERT ***************************\n" \
+ " function : %s\n" \
+ " line : %d\n" \
+ " expression : " #Expression "\n" \
+ " actual value : " Format "\n", \
+ __FUNCTION__, __LINE__, Value \
+ ); \
+ }
+#else
+# define gcmDBGASSERT(Expression, Format, Value)
+#endif
+
+#define gcmPTRALIGNMENT(Pointer, Alignemnt) \
+( \
+ gcmALIGN(gcmPTR2INT32(Pointer), Alignemnt) - gcmPTR2INT32(Pointer) \
+)
+
+#if gcdALIGNBYSIZE
+# define gcmISALIGNED(Offset, Alignment) \
+ (((Offset) & ((Alignment) - 1)) == 0)
+
+# define gcmkALIGNPTR(Type, Pointer, Alignment) \
+ Pointer = (Type) gcmINT2PTR(gcmALIGN(gcmPTR2INT32(Pointer), Alignment))
+#else
+# define gcmISALIGNED(Offset, Alignment) \
+ gcvTRUE
+
+# define gcmkALIGNPTR(Type, Pointer, Alignment)
+#endif
+
+#define gcmALIGNSIZE(Offset, Size) \
+ ((Size - Offset) + Size)
+
+#define gcdHAVEPREFIX \
+( \
+ gcdSHOW_TIME \
+ || gcdSHOW_LINE_NUMBER \
+ || gcdSHOW_PROCESS_ID \
+ || gcdSHOW_THREAD_ID \
+)
+
+#if gcdHAVEPREFIX
+
+# define gcdOFFSET 0
+
+#if gcdSHOW_TIME
+#if gcmISALIGNED(gcdOFFSET, 8)
+# define gcdTIMESIZE gcmSIZEOF(gctUINT64)
+# elif gcdOFFSET == 4
+# define gcdTIMESIZE gcmALIGNSIZE(4, gcmSIZEOF(gctUINT64))
+# else
+# error "Unexpected offset value."
+# endif
+# undef gcdOFFSET
+# define gcdOFFSET 8
+#if !defined(gcdPREFIX_LEADER)
+# define gcdPREFIX_LEADER gcmSIZEOF(gctUINT64)
+# define gcdTIMEFORMAT "0x%016llX"
+# else
+# define gcdTIMEFORMAT ", 0x%016llX"
+# endif
+# else
+# define gcdTIMESIZE 0
+# define gcdTIMEFORMAT
+# endif
+
+#if gcdSHOW_LINE_NUMBER
+#if gcmISALIGNED(gcdOFFSET, 8)
+# define gcdNUMSIZE gcmSIZEOF(gctUINT64)
+# elif gcdOFFSET == 4
+# define gcdNUMSIZE gcmALIGNSIZE(4, gcmSIZEOF(gctUINT64))
+# else
+# error "Unexpected offset value."
+# endif
+# undef gcdOFFSET
+# define gcdOFFSET 8
+#if !defined(gcdPREFIX_LEADER)
+# define gcdPREFIX_LEADER gcmSIZEOF(gctUINT64)
+# define gcdNUMFORMAT "%8llu"
+# else
+# define gcdNUMFORMAT ", %8llu"
+# endif
+# else
+# define gcdNUMSIZE 0
+# define gcdNUMFORMAT
+# endif
+
+#if gcdSHOW_PROCESS_ID
+#if gcmISALIGNED(gcdOFFSET, 4)
+# define gcdPIDSIZE gcmSIZEOF(gctUINT32)
+# else
+# error "Unexpected offset value."
+# endif
+# undef gcdOFFSET
+# define gcdOFFSET 4
+#if !defined(gcdPREFIX_LEADER)
+# define gcdPREFIX_LEADER gcmSIZEOF(gctUINT32)
+# define gcdPIDFORMAT "pid=%5d"
+# else
+# define gcdPIDFORMAT ", pid=%5d"
+# endif
+# else
+# define gcdPIDSIZE 0
+# define gcdPIDFORMAT
+# endif
+
+#if gcdSHOW_THREAD_ID
+#if gcmISALIGNED(gcdOFFSET, 4)
+# define gcdTIDSIZE gcmSIZEOF(gctUINT32)
+# else
+# error "Unexpected offset value."
+# endif
+# undef gcdOFFSET
+# define gcdOFFSET 4
+#if !defined(gcdPREFIX_LEADER)
+# define gcdPREFIX_LEADER gcmSIZEOF(gctUINT32)
+# define gcdTIDFORMAT "tid=%5d"
+# else
+# define gcdTIDFORMAT ", tid=%5d"
+# endif
+# else
+# define gcdTIDSIZE 0
+# define gcdTIDFORMAT
+# endif
+
+# define gcdPREFIX_SIZE \
+ ( \
+ gcdTIMESIZE \
+ + gcdNUMSIZE \
+ + gcdPIDSIZE \
+ + gcdTIDSIZE \
+ )
+
+ static const char * _prefixFormat =
+ "["
+ gcdTIMEFORMAT
+ gcdNUMFORMAT
+ gcdPIDFORMAT
+ gcdTIDFORMAT
+ "] ";
+
+#else
+
+# define gcdPREFIX_LEADER gcmSIZEOF(gctUINT32)
+# define gcdPREFIX_SIZE 0
+
+#endif
+
+/* Assumed largest variable argument leader size. */
+#define gcdVARARG_LEADER gcmSIZEOF(gctUINT64)
+
+/* Alignnments. */
+#if gcdALIGNBYSIZE
+# define gcdPREFIX_ALIGNMENT gcdPREFIX_LEADER
+# define gcdVARARG_ALIGNMENT gcdVARARG_LEADER
+#else
+# define gcdPREFIX_ALIGNMENT 0
+# define gcdVARARG_ALIGNMENT 0
+#endif
+
+#if gcdBUFFERED_OUTPUT
+# define gcdOUTPUTPREFIX _AppendPrefix
+# define gcdOUTPUTSTRING _AppendString
+# define gcdOUTPUTCOPY _AppendCopy
+# define gcdOUTPUTBUFFER _AppendBuffer
+#else
+# define gcdOUTPUTPREFIX _PrintPrefix
+# define gcdOUTPUTSTRING _PrintString
+# define gcdOUTPUTCOPY _PrintString
+# define gcdOUTPUTBUFFER _PrintBuffer
+#endif
+
+/******************************************************************************\
+****************************** Private Structures ******************************
+\******************************************************************************/
+
+typedef enum _gceBUFITEM
+{
+ gceBUFITEM_NONE,
+ gcvBUFITEM_PREFIX,
+ gcvBUFITEM_STRING,
+ gcvBUFITEM_COPY,
+ gcvBUFITEM_BUFFER
+}
+gceBUFITEM;
+
+/* Common item head/buffer terminator. */
+typedef struct _gcsBUFITEM_HEAD * gcsBUFITEM_HEAD_PTR;
+typedef struct _gcsBUFITEM_HEAD
+{
+ gceBUFITEM type;
+}
+gcsBUFITEM_HEAD;
+
+/* String prefix (for ex. [ 1,tid=0x019A]) */
+typedef struct _gcsBUFITEM_PREFIX * gcsBUFITEM_PREFIX_PTR;
+typedef struct _gcsBUFITEM_PREFIX
+{
+ gceBUFITEM type;
+#if gcdHAVEPREFIX
+ gctPOINTER prefixData;
+#endif
+}
+gcsBUFITEM_PREFIX;
+
+/* Buffered string. */
+typedef struct _gcsBUFITEM_STRING * gcsBUFITEM_STRING_PTR;
+typedef struct _gcsBUFITEM_STRING
+{
+ gceBUFITEM type;
+ gctINT indent;
+ gctCONST_STRING message;
+ gctPOINTER messageData;
+ gctUINT messageDataSize;
+}
+gcsBUFITEM_STRING;
+
+/* Buffered string (copy of the string is included with the record). */
+typedef struct _gcsBUFITEM_COPY * gcsBUFITEM_COPY_PTR;
+typedef struct _gcsBUFITEM_COPY
+{
+ gceBUFITEM type;
+ gctINT indent;
+ gctPOINTER messageData;
+ gctUINT messageDataSize;
+}
+gcsBUFITEM_COPY;
+
+/* Memory buffer. */
+typedef struct _gcsBUFITEM_BUFFER * gcsBUFITEM_BUFFER_PTR;
+typedef struct _gcsBUFITEM_BUFFER
+{
+ gceBUFITEM type;
+ gctINT indent;
+ gceDUMP_BUFFER bufferType;
+
+#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1)
+ gctUINT32 dmaAddress;
+#endif
+
+ gctUINT dataSize;
+ gctUINT32 address;
+#if gcdHAVEPREFIX
+ gctPOINTER prefixData;
+#endif
+}
+gcsBUFITEM_BUFFER;
+
+typedef struct _gcsBUFFERED_OUTPUT * gcsBUFFERED_OUTPUT_PTR;
+typedef struct _gcsBUFFERED_OUTPUT
+{
+#if gcdTHREAD_BUFFERS > 1
+ gctUINT32 threadID;
+#endif
+
+#if gcdSHOW_LINE_NUMBER
+ gctUINT64 lineNumber;
+#endif
+
+ gctINT indent;
+
+#if gcdBUFFERED_OUTPUT
+ gctINT start;
+ gctINT index;
+ gctINT count;
+ gctUINT8 buffer[gcdBUFFERED_SIZE];
+#endif
+
+ gcsBUFFERED_OUTPUT_PTR prev;
+ gcsBUFFERED_OUTPUT_PTR next;
+}
+gcsBUFFERED_OUTPUT;
+
+typedef gctUINT (* gcfPRINTSTRING) (
+ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+ IN gcsBUFITEM_HEAD_PTR Item
+ );
+
+typedef gctINT (* gcfGETITEMSIZE) (
+ IN gcsBUFITEM_HEAD_PTR Item
+ );
+
+/******************************************************************************\
+******************************* Private Variables ******************************
+\******************************************************************************/
+
+static gcsBUFFERED_OUTPUT _outputBuffer[gcdTHREAD_BUFFERS];
+static gcsBUFFERED_OUTPUT_PTR _outputBufferHead = gcvNULL;
+static gcsBUFFERED_OUTPUT_PTR _outputBufferTail = gcvNULL;
+
+/******************************************************************************\
+****************************** Item Size Functions *****************************
+\******************************************************************************/
+
+#if gcdBUFFERED_OUTPUT
+static gctINT
+_GetTerminatorItemSize(
+ IN gcsBUFITEM_HEAD_PTR Item
+ )
+{
+ return gcmSIZEOF(gcsBUFITEM_HEAD);
+}
+
+static gctINT
+_GetPrefixItemSize(
+ IN gcsBUFITEM_HEAD_PTR Item
+ )
+{
+#if gcdHAVEPREFIX
+ gcsBUFITEM_PREFIX_PTR item = (gcsBUFITEM_PREFIX_PTR) Item;
+ gctUINT vlen = ((gctUINT8_PTR) item->prefixData) - ((gctUINT8_PTR) item);
+ return vlen + gcdPREFIX_SIZE;
+#else
+ return gcmSIZEOF(gcsBUFITEM_PREFIX);
+#endif
+}
+
+static gctINT
+_GetStringItemSize(
+ IN gcsBUFITEM_HEAD_PTR Item
+ )
+{
+ gcsBUFITEM_STRING_PTR item = (gcsBUFITEM_STRING_PTR) Item;
+ gctUINT vlen = ((gctUINT8_PTR) item->messageData) - ((gctUINT8_PTR) item);
+ return vlen + item->messageDataSize;
+}
+
+static gctINT
+_GetCopyItemSize(
+ IN gcsBUFITEM_HEAD_PTR Item
+ )
+{
+ gcsBUFITEM_COPY_PTR item = (gcsBUFITEM_COPY_PTR) Item;
+ gctUINT vlen = ((gctUINT8_PTR) item->messageData) - ((gctUINT8_PTR) item);
+ return vlen + item->messageDataSize;
+}
+
+static gctINT
+_GetBufferItemSize(
+ IN gcsBUFITEM_HEAD_PTR Item
+ )
+{
+#if gcdHAVEPREFIX
+ gcsBUFITEM_BUFFER_PTR item = (gcsBUFITEM_BUFFER_PTR) Item;
+ gctUINT vlen = ((gctUINT8_PTR) item->prefixData) - ((gctUINT8_PTR) item);
+ return vlen + gcdPREFIX_SIZE + item->dataSize;
+#else
+ gcsBUFITEM_BUFFER_PTR item = (gcsBUFITEM_BUFFER_PTR) Item;
+ return gcmSIZEOF(gcsBUFITEM_BUFFER) + item->dataSize;
+#endif
+}
+
+static gcfGETITEMSIZE _itemSize[] =
+{
+ _GetTerminatorItemSize,
+ _GetPrefixItemSize,
+ _GetStringItemSize,
+ _GetCopyItemSize,
+ _GetBufferItemSize
+};
+#endif
+
+/******************************************************************************\
+******************************* Printing Functions *****************************
+\******************************************************************************/
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE) || gcdBUFFERED_OUTPUT
+static void
+_DirectPrint(
+ gctCONST_STRING Message,
+ ...
+ )
+{
+ gctINT len;
+ char buffer[768];
+ gctARGUMENTS arguments;
+
+ gcmkARGUMENTS_START(arguments, Message);
+ len = gcmkVSPRINTF(buffer, gcmSIZEOF(buffer), Message, &arguments);
+ gcmkARGUMENTS_END(arguments);
+
+ buffer[len] = '\0';
+ gcmkOUTPUT_STRING(buffer);
+}
+#endif
+
+static int
+_AppendIndent(
+ IN gctINT Indent,
+ IN char * Buffer,
+ IN int BufferSize
+ )
+{
+ gctINT i;
+
+ gctINT len = 0;
+ gctINT indent = Indent % 40;
+
+ for (i = 0; i < indent; i += 1)
+ {
+ Buffer[len++] = ' ';
+ }
+
+ if (indent != Indent)
+ {
+ len += gcmkSPRINTF(
+ Buffer + len, BufferSize - len, " <%d> ", Indent
+ );
+
+ Buffer[len] = '\0';
+ }
+
+ return len;
+}
+
+#if gcdHAVEPREFIX
+static void
+_PrintPrefix(
+ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+ IN gctPOINTER Data
+ )
+{
+ char buffer[768];
+ gctINT len;
+
+ /* Format the string. */
+ len = gcmkVSPRINTF(buffer, gcmSIZEOF(buffer), _prefixFormat, Data);
+ buffer[len] = '\0';
+
+ /* Print the string. */
+ gcmkOUTPUT_STRING(buffer);
+}
+#endif
+
+static void
+_PrintString(
+ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+ IN gctINT Indent,
+ IN gctCONST_STRING Message,
+ IN gctUINT ArgumentSize,
+ IN gctPOINTER Data
+ )
+{
+ char buffer[768];
+ gctINT len;
+
+ /* Append the indent string. */
+ len = _AppendIndent(Indent, buffer, gcmSIZEOF(buffer));
+
+ /* Format the string. */
+ len += gcmkVSPRINTF(buffer + len, gcmSIZEOF(buffer) - len, Message, Data);
+ buffer[len] = '\0';
+
+ /* Add end-of-line if missing. */
+ if (buffer[len - 1] != '\n')
+ {
+ buffer[len++] = '\n';
+ buffer[len] = '\0';
+ }
+
+ /* Print the string. */
+ gcmkOUTPUT_STRING(buffer);
+}
+
+static void
+_PrintBuffer(
+ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+ IN gctINT Indent,
+ IN gctPOINTER PrefixData,
+ IN gctPOINTER Data,
+ IN gctUINT Address,
+ IN gctSIZE_T DataSize,
+ IN gceDUMP_BUFFER Type,
+ IN gctUINT32 DmaAddress
+ )
+{
+ static gctCONST_STRING _titleString[] =
+ {
+ "CONTEXT BUFFER",
+ "USER COMMAND BUFFER",
+ "KERNEL COMMAND BUFFER",
+ "LINK BUFFER",
+ "WAIT LINK BUFFER",
+ ""
+ };
+
+ static const gctINT COLUMN_COUNT = 8;
+
+ gctUINT i, column, address;
+ gctSIZE_T count;
+ gctUINT32_PTR data;
+ gctCHAR buffer[768];
+ gctUINT indent, len;
+ gctBOOL command;
+
+ /* Append space for the prefix. */
+#if gcdHAVEPREFIX
+ indent = gcmkVSPRINTF(buffer, gcmSIZEOF(buffer), _prefixFormat, PrefixData);
+ buffer[indent] = '\0';
+#else
+ indent = 0;
+#endif
+
+ /* Append the indent string. */
+ indent += _AppendIndent(
+ Indent, buffer + indent, gcmSIZEOF(buffer) - indent
+ );
+
+ switch (Type)
+ {
+ case gcvDUMP_BUFFER_CONTEXT:
+ case gcvDUMP_BUFFER_USER:
+ case gcvDUMP_BUFFER_KERNEL:
+ case gcvDUMP_BUFFER_LINK:
+ case gcvDUMP_BUFFER_WAITLINK:
+ /* Form and print the title string. */
+ gcmkSPRINTF2(
+ buffer + indent, gcmSIZEOF(buffer) - indent,
+ "%s%s\n", _titleString[Type],
+ ((DmaAddress >= Address) && (DmaAddress < Address + DataSize))
+ ? " (CURRENT)" : ""
+ );
+
+ gcmkOUTPUT_STRING(buffer);
+
+ /* Terminate the string. */
+ buffer[indent] = '\0';
+
+ /* This is a command buffer. */
+ command = gcvTRUE;
+ break;
+
+ case gcvDUMP_BUFFER_FROM_USER:
+ /* This is not a command buffer. */
+ command = gcvFALSE;
+
+ /* No title. */
+ break;
+
+ default:
+ gcmDBGASSERT(gcvFALSE, "%s", "invalid buffer type");
+
+ /* This is not a command buffer. */
+ command = gcvFALSE;
+ }
+
+ /* Overwrite the prefix with spaces. */
+ for (i = 0; i < indent; i += 1)
+ {
+ buffer[i] = ' ';
+ }
+
+ /* Form and print the opening string. */
+ if (command)
+ {
+ gcmkSPRINTF2(
+ buffer + indent, gcmSIZEOF(buffer) - indent,
+ "@[kernel.command %08X %08X\n", Address, (gctUINT32)DataSize
+ );
+
+ gcmkOUTPUT_STRING(buffer);
+
+ /* Terminate the string. */
+ buffer[indent] = '\0';
+ }
+
+ /* Get initial address. */
+ address = Address;
+
+ /* Cast the data pointer. */
+ data = (gctUINT32_PTR) Data;
+
+ /* Compute the number of double words. */
+ count = DataSize / gcmSIZEOF(gctUINT32);
+
+ /* Print the buffer. */
+ for (i = 0, len = indent, column = 0; i < count; i += 1)
+ {
+ /* Append the address. */
+ if (column == 0)
+ {
+ len += gcmkSPRINTF(
+ buffer + len, gcmSIZEOF(buffer) - len, "0x%08X:", address
+ );
+ }
+
+ /* Append the data value. */
+ len += gcmkSPRINTF2(
+ buffer + len, gcmSIZEOF(buffer) - len, "%c%08X",
+ (address == DmaAddress)? '>' : ' ', data[i]
+ );
+
+ buffer[len] = '\0';
+
+ /* Update the address. */
+ address += gcmSIZEOF(gctUINT32);
+
+ /* Advance column count. */
+ column += 1;
+
+ /* End of line? */
+ if ((column % COLUMN_COUNT) == 0)
+ {
+ /* Append EOL. */
+ gcmkSTRCATSAFE(buffer, gcmSIZEOF(buffer), "\n");
+
+ /* Print the string. */
+ gcmkOUTPUT_STRING(buffer);
+
+ /* Reset. */
+ len = indent;
+ column = 0;
+ }
+ }
+
+ /* Print the last partial string. */
+ if (column != 0)
+ {
+ /* Append EOL. */
+ gcmkSTRCATSAFE(buffer, gcmSIZEOF(buffer), "\n");
+
+ /* Print the string. */
+ gcmkOUTPUT_STRING(buffer);
+ }
+
+ /* Form and print the opening string. */
+ if (command)
+ {
+ buffer[indent] = '\0';
+ gcmkSTRCATSAFE(buffer, gcmSIZEOF(buffer), "] -- command\n");
+ gcmkOUTPUT_STRING(buffer);
+ }
+}
+
+#if gcdBUFFERED_OUTPUT
+static gctUINT
+_PrintNone(
+ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+ IN gcsBUFITEM_HEAD_PTR Item
+ )
+{
+ /* Return the size of the node. */
+ return gcmSIZEOF(gcsBUFITEM_HEAD);
+}
+
+static gctUINT
+_PrintPrefixWrapper(
+ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+ IN gcsBUFITEM_HEAD_PTR Item
+ )
+{
+#if gcdHAVEPREFIX
+ gcsBUFITEM_PREFIX_PTR item;
+ gctUINT vlen;
+
+ /* Get access to the data. */
+ item = (gcsBUFITEM_PREFIX_PTR) Item;
+
+ /* Print the message. */
+ _PrintPrefix(OutputBuffer, item->prefixData);
+
+ /* Compute the size of the variable portion of the structure. */
+ vlen = ((gctUINT8_PTR) item->prefixData) - ((gctUINT8_PTR) item);
+
+ /* Return the size of the node. */
+ return vlen + gcdPREFIX_SIZE;
+#else
+ return gcmSIZEOF(gcsBUFITEM_PREFIX);
+#endif
+}
+
+static gctUINT
+_PrintStringWrapper(
+ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+ IN gcsBUFITEM_HEAD_PTR Item
+ )
+{
+ gcsBUFITEM_STRING_PTR item;
+ gctUINT vlen;
+
+ /* Get access to the data. */
+ item = (gcsBUFITEM_STRING_PTR) Item;
+
+ /* Print the message. */
+ _PrintString(
+ OutputBuffer,
+ item->indent, item->message, item->messageDataSize, item->messageData
+ );
+
+ /* Compute the size of the variable portion of the structure. */
+ vlen = ((gctUINT8_PTR) item->messageData) - ((gctUINT8_PTR) item);
+
+ /* Return the size of the node. */
+ return vlen + item->messageDataSize;
+}
+
+static gctUINT
+_PrintCopyWrapper(
+ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+ IN gcsBUFITEM_HEAD_PTR Item
+ )
+{
+ gcsBUFITEM_COPY_PTR item;
+ gctCONST_STRING message;
+ gctUINT vlen;
+
+ /* Get access to the data. */
+ item = (gcsBUFITEM_COPY_PTR) Item;
+
+ /* Determine the string pointer. */
+ message = (gctCONST_STRING) (item + 1);
+
+ /* Print the message. */
+ _PrintString(
+ OutputBuffer,
+ item->indent, message, item->messageDataSize, item->messageData
+ );
+
+ /* Compute the size of the variable portion of the structure. */
+ vlen = ((gctUINT8_PTR) item->messageData) - ((gctUINT8_PTR) item);
+
+ /* Return the size of the node. */
+ return vlen + item->messageDataSize;
+}
+
+static gctUINT
+_PrintBufferWrapper(
+ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+ IN gcsBUFITEM_HEAD_PTR Item
+ )
+{
+#if gcdHAVEPREFIX
+ gctUINT32 dmaAddress;
+ gcsBUFITEM_BUFFER_PTR item;
+ gctPOINTER data;
+ gctUINT vlen;
+
+ /* Get access to the data. */
+ item = (gcsBUFITEM_BUFFER_PTR) Item;
+
+#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1)
+ dmaAddress = item->dmaAddress;
+#else
+ dmaAddress = 0xFFFFFFFF;
+#endif
+
+ if (dmaAddress != 0)
+ {
+ /* Compute the data address. */
+ data = ((gctUINT8_PTR) item->prefixData) + gcdPREFIX_SIZE;
+
+ /* Print buffer. */
+ _PrintBuffer(
+ OutputBuffer,
+ item->indent, item->prefixData,
+ data, item->address, item->dataSize,
+ item->bufferType, dmaAddress
+ );
+ }
+
+ /* Compute the size of the variable portion of the structure. */
+ vlen = ((gctUINT8_PTR) item->prefixData) - ((gctUINT8_PTR) item);
+
+ /* Return the size of the node. */
+ return vlen + gcdPREFIX_SIZE + item->dataSize;
+#else
+ gctUINT32 dmaAddress;
+ gcsBUFITEM_BUFFER_PTR item;
+
+ /* Get access to the data. */
+ item = (gcsBUFITEM_BUFFER_PTR) Item;
+
+#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1)
+ dmaAddress = item->dmaAddress;
+#else
+ dmaAddress = 0xFFFFFFFF;
+#endif
+
+ if (dmaAddress != 0)
+ {
+ /* Print buffer. */
+ _PrintBuffer(
+ OutputBuffer,
+ item->indent, gcvNULL,
+ item + 1, item->address, item->dataSize,
+ item->bufferType, dmaAddress
+ );
+ }
+
+ /* Return the size of the node. */
+ return gcmSIZEOF(gcsBUFITEM_BUFFER) + item->dataSize;
+#endif
+}
+
+static gcfPRINTSTRING _printArray[] =
+{
+ _PrintNone,
+ _PrintPrefixWrapper,
+ _PrintStringWrapper,
+ _PrintCopyWrapper,
+ _PrintBufferWrapper
+};
+#endif
+
+/******************************************************************************\
+******************************* Private Functions ******************************
+\******************************************************************************/
+
+#if gcdBUFFERED_OUTPUT
+
+#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1)
+static gcsBUFITEM_BUFFER_PTR
+_FindCurrentDMABuffer(
+ gctUINT32 DmaAddress
+ )
+{
+ gctINT i, skip;
+ gcsBUFITEM_HEAD_PTR item;
+ gcsBUFITEM_BUFFER_PTR dmaCurrent;
+
+ /* Reset the current buffer. */
+ dmaCurrent = gcvNULL;
+
+ /* Get the first stored item. */
+ item = (gcsBUFITEM_HEAD_PTR) &_outputBufferHead->buffer[_outputBufferHead->start];
+
+ /* Run through all items. */
+ for (i = 0; i < _outputBufferHead->count; i += 1)
+ {
+ /* Buffer item? */
+ if (item->type == gcvBUFITEM_BUFFER)
+ {
+ gcsBUFITEM_BUFFER_PTR buffer = (gcsBUFITEM_BUFFER_PTR) item;
+
+ if ((DmaAddress >= buffer->address) &&
+ (DmaAddress < buffer->address + buffer->dataSize))
+ {
+ dmaCurrent = buffer;
+ }
+ }
+
+ /* Get the item size and skip it. */
+ skip = (* _itemSize[item->type]) (item);
+ item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip);
+
+ /* End of the buffer? Wrap around. */
+ if (item->type == gceBUFITEM_NONE)
+ {
+ item = (gcsBUFITEM_HEAD_PTR) _outputBufferHead->buffer;
+ }
+ }
+
+ /* Return result. */
+ return dmaCurrent;
+}
+
+static void
+_EnableAllDMABuffers(
+ void
+ )
+{
+ gctINT i, skip;
+ gcsBUFITEM_HEAD_PTR item;
+
+ /* Get the first stored item. */
+ item = (gcsBUFITEM_HEAD_PTR) &_outputBufferHead->buffer[_outputBufferHead->start];
+
+ /* Run through all items. */
+ for (i = 0; i < _outputBufferHead->count; i += 1)
+ {
+ /* Buffer item? */
+ if (item->type == gcvBUFITEM_BUFFER)
+ {
+ gcsBUFITEM_BUFFER_PTR buffer = (gcsBUFITEM_BUFFER_PTR) item;
+
+ /* Enable the buffer. */
+ buffer->dmaAddress = ~0U;
+ }
+
+ /* Get the item size and skip it. */
+ skip = (* _itemSize[item->type]) (item);
+ item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip);
+
+ /* End of the buffer? Wrap around. */
+ if (item->type == gceBUFITEM_NONE)
+ {
+ item = (gcsBUFITEM_HEAD_PTR) _outputBufferHead->buffer;
+ }
+ }
+}
+
+static void
+_EnableDMABuffers(
+ gctUINT32 DmaAddress,
+ gcsBUFITEM_BUFFER_PTR CurrentDMABuffer
+ )
+{
+ gctINT i, skip, index;
+ gcsBUFITEM_HEAD_PTR item;
+ gcsBUFITEM_BUFFER_PTR buffers[gcdDMA_BUFFER_COUNT];
+
+ /* Reset buffer pointers. */
+ gckOS_ZeroMemory(buffers, gcmSIZEOF(buffers));
+
+ /* Set the current buffer index. */
+ index = -1;
+
+ /* Get the first stored item. */
+ item = (gcsBUFITEM_HEAD_PTR) &_outputBufferHead->buffer[_outputBufferHead->start];
+
+ /* Run through all items until the current DMA buffer is found. */
+ for (i = 0; i < _outputBufferHead->count; i += 1)
+ {
+ /* Buffer item? */
+ if (item->type == gcvBUFITEM_BUFFER)
+ {
+ /* Advance the index. */
+ index = (index + 1) % gcdDMA_BUFFER_COUNT;
+
+ /* Add to the buffer array. */
+ buffers[index] = (gcsBUFITEM_BUFFER_PTR) item;
+
+ /* Stop if this is the current DMA buffer. */
+ if ((gcsBUFITEM_BUFFER_PTR) item == CurrentDMABuffer)
+ {
+ break;
+ }
+ }
+
+ /* Get the item size and skip it. */
+ skip = (* _itemSize[item->type]) (item);
+ item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip);
+
+ /* End of the buffer? Wrap around. */
+ if (item->type == gceBUFITEM_NONE)
+ {
+ item = (gcsBUFITEM_HEAD_PTR) _outputBufferHead->buffer;
+ }
+ }
+
+ /* Enable the found buffers. */
+ gcmDBGASSERT(index != -1, "%d", index);
+
+ for (i = 0; i < gcdDMA_BUFFER_COUNT; i += 1)
+ {
+ if (buffers[index] == gcvNULL)
+ {
+ break;
+ }
+
+ buffers[index]->dmaAddress = DmaAddress;
+
+ index -= 1;
+
+ if (index == -1)
+ {
+ index = gcdDMA_BUFFER_COUNT - 1;
+ }
+ }
+}
+#endif
+
+static void
+_Flush(
+ gctUINT32 DmaAddress
+ )
+{
+ gctINT i, skip;
+ gcsBUFITEM_HEAD_PTR item;
+
+ gcsBUFFERED_OUTPUT_PTR outputBuffer = _outputBufferHead;
+
+#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1)
+ if ((outputBuffer != gcvNULL) && (outputBuffer->count != 0))
+ {
+ /* Find the current DMA buffer. */
+ gcsBUFITEM_BUFFER_PTR dmaCurrent = _FindCurrentDMABuffer(DmaAddress);
+
+ /* Was the current buffer found? */
+ if (dmaCurrent == gcvNULL)
+ {
+ /* No, print all buffers. */
+ _EnableAllDMABuffers();
+ }
+ else
+ {
+ /* Yes, enable only specified number of buffers. */
+ _EnableDMABuffers(DmaAddress, dmaCurrent);
+ }
+ }
+#endif
+
+ while (outputBuffer != gcvNULL)
+ {
+ if (outputBuffer->count != 0)
+ {
+ _DirectPrint("********************************************************************************\n");
+ _DirectPrint("FLUSHING DEBUG OUTPUT BUFFER (%d elements).\n", outputBuffer->count);
+ _DirectPrint("********************************************************************************\n");
+
+ item = (gcsBUFITEM_HEAD_PTR) &outputBuffer->buffer[outputBuffer->start];
+
+ for (i = 0; i < outputBuffer->count; i += 1)
+ {
+ skip = (* _printArray[item->type]) (outputBuffer, item);
+
+ item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip);
+
+ if (item->type == gceBUFITEM_NONE)
+ {
+ item = (gcsBUFITEM_HEAD_PTR) outputBuffer->buffer;
+ }
+ }
+
+ outputBuffer->start = 0;
+ outputBuffer->index = 0;
+ outputBuffer->count = 0;
+ }
+
+ outputBuffer = outputBuffer->next;
+ }
+}
+
+static gcsBUFITEM_HEAD_PTR
+_AllocateItem(
+ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+ IN gctINT Size
+ )
+{
+ gctINT skip;
+ gcsBUFITEM_HEAD_PTR item, next;
+
+#if gcdENABLE_OVERFLOW
+ if (
+ (OutputBuffer->index + Size >= gcdBUFFERED_SIZE - gcmSIZEOF(gcsBUFITEM_HEAD))
+ ||
+ (
+ (OutputBuffer->index < OutputBuffer->start) &&
+ (OutputBuffer->index + Size >= OutputBuffer->start)
+ )
+ )
+ {
+ if (OutputBuffer->index + Size >= gcdBUFFERED_SIZE - gcmSIZEOF(gcsBUFITEM_HEAD))
+ {
+ if (OutputBuffer->index < OutputBuffer->start)
+ {
+ item = (gcsBUFITEM_HEAD_PTR) &OutputBuffer->buffer[OutputBuffer->start];
+
+ while (item->type != gceBUFITEM_NONE)
+ {
+ skip = (* _itemSize[item->type]) (item);
+
+ OutputBuffer->start += skip;
+ OutputBuffer->count -= 1;
+
+ item->type = gceBUFITEM_NONE;
+ item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip);
+ }
+
+ OutputBuffer->start = 0;
+ }
+
+ OutputBuffer->index = 0;
+ }
+
+ item = (gcsBUFITEM_HEAD_PTR) &OutputBuffer->buffer[OutputBuffer->start];
+
+ while (OutputBuffer->start - OutputBuffer->index <= Size)
+ {
+ skip = (* _itemSize[item->type]) (item);
+
+ OutputBuffer->start += skip;
+ OutputBuffer->count -= 1;
+
+ item->type = gceBUFITEM_NONE;
+ item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip);
+
+ if (item->type == gceBUFITEM_NONE)
+ {
+ OutputBuffer->start = 0;
+ break;
+ }
+ }
+ }
+#else
+ if (OutputBuffer->index + Size > gcdBUFFERED_SIZE - gcmSIZEOF(gcsBUFITEM_HEAD))
+ {
+ _DirectPrint("\nMessage buffer full; forcing message flush.\n\n");
+ _Flush(~0U);
+ }
+#endif
+
+ item = (gcsBUFITEM_HEAD_PTR) &OutputBuffer->buffer[OutputBuffer->index];
+
+ OutputBuffer->index += Size;
+ OutputBuffer->count += 1;
+
+ next = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + Size);
+ next->type = gceBUFITEM_NONE;
+
+ return item;
+}
+
+#if gcdALIGNBYSIZE
+static void
+_FreeExtraSpace(
+ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+ IN gctPOINTER Item,
+ IN gctINT ItemSize,
+ IN gctINT FreeSize
+ )
+{
+ gcsBUFITEM_HEAD_PTR next;
+
+ OutputBuffer->index -= FreeSize;
+
+ next = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) Item + ItemSize);
+ next->type = gceBUFITEM_NONE;
+}
+#endif
+
+#if gcdHAVEPREFIX
+static void
+_AppendPrefix(
+ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+ IN gctPOINTER Data
+ )
+{
+ gctUINT8_PTR prefixData;
+ gcsBUFITEM_PREFIX_PTR item;
+ gctINT allocSize;
+
+#if gcdALIGNBYSIZE
+ gctUINT alignment;
+ gctINT size, freeSize;
+#endif
+
+ gcmDBGASSERT(Data != gcvNULL, "%p", Data);
+
+ /* Determine the maximum item size. */
+ allocSize
+ = gcmSIZEOF(gcsBUFITEM_PREFIX)
+ + gcdPREFIX_SIZE
+ + gcdPREFIX_ALIGNMENT;
+
+ /* Allocate prefix item. */
+ item = (gcsBUFITEM_PREFIX_PTR) _AllocateItem(OutputBuffer, allocSize);
+
+ /* Compute the initial prefix data pointer. */
+ prefixData = (gctUINT8_PTR) (item + 1);
+
+ /* Align the data pointer as necessary. */
+#if gcdALIGNBYSIZE
+ alignment = gcmPTRALIGNMENT(prefixData, gcdPREFIX_ALIGNMENT);
+ prefixData += alignment;
+#endif
+
+ /* Set item data. */
+ item->type = gcvBUFITEM_PREFIX;
+ item->prefixData = prefixData;
+
+ /* Copy argument value. */
+ gcmkMEMCPY(prefixData, Data, gcdPREFIX_SIZE);
+
+#if gcdALIGNBYSIZE
+ /* Compute the actual node size. */
+ size = gcmSIZEOF(gcsBUFITEM_PREFIX) + gcdPREFIX_SIZE + alignment;
+
+ /* Free extra memory if any. */
+ freeSize = allocSize - size;
+ if (freeSize != 0)
+ {
+ _FreeExtraSpace(OutputBuffer, item, size, freeSize);
+ }
+#endif
+}
+#endif
+
+static void
+_AppendString(
+ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+ IN gctINT Indent,
+ IN gctCONST_STRING Message,
+ IN gctUINT ArgumentSize,
+ IN gctPOINTER Data
+ )
+{
+ gctUINT8_PTR messageData;
+ gcsBUFITEM_STRING_PTR item;
+ gctINT allocSize;
+
+#if gcdALIGNBYSIZE
+ gctUINT alignment;
+ gctINT size, freeSize;
+#endif
+
+ /* Determine the maximum item size. */
+ allocSize
+ = gcmSIZEOF(gcsBUFITEM_STRING)
+ + ArgumentSize
+ + gcdVARARG_ALIGNMENT;
+
+ /* Allocate prefix item. */
+ item = (gcsBUFITEM_STRING_PTR) _AllocateItem(OutputBuffer, allocSize);
+
+ /* Compute the initial message data pointer. */
+ messageData = (gctUINT8_PTR) (item + 1);
+
+ /* Align the data pointer as necessary. */
+#if gcdALIGNBYSIZE
+ alignment = gcmPTRALIGNMENT(messageData, gcdVARARG_ALIGNMENT);
+ messageData += alignment;
+#endif
+
+ /* Set item data. */
+ item->type = gcvBUFITEM_STRING;
+ item->indent = Indent;
+ item->message = Message;
+ item->messageData = messageData;
+ item->messageDataSize = ArgumentSize;
+
+ /* Copy argument value. */
+ if (ArgumentSize != 0)
+ {
+ gcmkMEMCPY(messageData, Data, ArgumentSize);
+ }
+
+#if gcdALIGNBYSIZE
+ /* Compute the actual node size. */
+ size = gcmSIZEOF(gcsBUFITEM_STRING) + ArgumentSize + alignment;
+
+ /* Free extra memory if any. */
+ freeSize = allocSize - size;
+ if (freeSize != 0)
+ {
+ _FreeExtraSpace(OutputBuffer, item, size, freeSize);
+ }
+#endif
+}
+
+static void
+_AppendCopy(
+ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+ IN gctINT Indent,
+ IN gctCONST_STRING Message,
+ IN gctUINT ArgumentSize,
+ IN gctPOINTER Data
+ )
+{
+ gctUINT8_PTR messageData;
+ gcsBUFITEM_COPY_PTR item;
+ gctINT allocSize;
+ gctINT messageLength;
+ gctCONST_STRING message;
+
+#if gcdALIGNBYSIZE
+ gctUINT alignment;
+ gctINT size, freeSize;
+#endif
+
+ /* Get the length of the string. */
+ messageLength = strlen(Message) + 1;
+
+ /* Determine the maximum item size. */
+ allocSize
+ = gcmSIZEOF(gcsBUFITEM_COPY)
+ + messageLength
+ + ArgumentSize
+ + gcdVARARG_ALIGNMENT;
+
+ /* Allocate prefix item. */
+ item = (gcsBUFITEM_COPY_PTR) _AllocateItem(OutputBuffer, allocSize);
+
+ /* Determine the message placement. */
+ message = (gctCONST_STRING) (item + 1);
+
+ /* Compute the initial message data pointer. */
+ messageData = (gctUINT8_PTR) message + messageLength;
+
+ /* Align the data pointer as necessary. */
+#if gcdALIGNBYSIZE
+ if (ArgumentSize == 0)
+ {
+ alignment = 0;
+ }
+ else
+ {
+ alignment = gcmPTRALIGNMENT(messageData, gcdVARARG_ALIGNMENT);
+ messageData += alignment;
+ }
+#endif
+
+ /* Set item data. */
+ item->type = gcvBUFITEM_COPY;
+ item->indent = Indent;
+ item->messageData = messageData;
+ item->messageDataSize = ArgumentSize;
+
+ /* Copy the message. */
+ gcmkMEMCPY((gctPOINTER) message, Message, messageLength);
+
+ /* Copy argument value. */
+ if (ArgumentSize != 0)
+ {
+ gcmkMEMCPY(messageData, Data, ArgumentSize);
+ }
+
+#if gcdALIGNBYSIZE
+ /* Compute the actual node size. */
+ size
+ = gcmSIZEOF(gcsBUFITEM_COPY)
+ + messageLength
+ + ArgumentSize
+ + alignment;
+
+ /* Free extra memory if any. */
+ freeSize = allocSize - size;
+ if (freeSize != 0)
+ {
+ _FreeExtraSpace(OutputBuffer, item, size, freeSize);
+ }
+#endif
+}
+
+static void
+_AppendBuffer(
+ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+ IN gctINT Indent,
+ IN gctPOINTER PrefixData,
+ IN gctPOINTER Data,
+ IN gctUINT Address,
+ IN gctUINT DataSize,
+ IN gceDUMP_BUFFER Type,
+ IN gctUINT32 DmaAddress
+ )
+{
+#if gcdHAVEPREFIX
+ gctUINT8_PTR prefixData;
+ gcsBUFITEM_BUFFER_PTR item;
+ gctINT allocSize;
+ gctPOINTER data;
+
+#if gcdALIGNBYSIZE
+ gctUINT alignment;
+ gctINT size, freeSize;
+#endif
+
+ gcmDBGASSERT(DataSize != 0, "%d", DataSize);
+ gcmDBGASSERT(Data != gcvNULL, "%p", Data);
+
+ /* Determine the maximum item size. */
+ allocSize
+ = gcmSIZEOF(gcsBUFITEM_BUFFER)
+ + gcdPREFIX_SIZE
+ + gcdPREFIX_ALIGNMENT
+ + DataSize;
+
+ /* Allocate prefix item. */
+ item = (gcsBUFITEM_BUFFER_PTR) _AllocateItem(OutputBuffer, allocSize);
+
+ /* Compute the initial prefix data pointer. */
+ prefixData = (gctUINT8_PTR) (item + 1);
+
+#if gcdALIGNBYSIZE
+ /* Align the data pointer as necessary. */
+ alignment = gcmPTRALIGNMENT(prefixData, gcdPREFIX_ALIGNMENT);
+ prefixData += alignment;
+#endif
+
+ /* Set item data. */
+ item->type = gcvBUFITEM_BUFFER;
+ item->indent = Indent;
+ item->bufferType = Type;
+ item->dataSize = DataSize;
+ item->address = Address;
+ item->prefixData = prefixData;
+
+#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1)
+ item->dmaAddress = DmaAddress;
+#endif
+
+ /* Copy prefix data. */
+ gcmkMEMCPY(prefixData, PrefixData, gcdPREFIX_SIZE);
+
+ /* Compute the data pointer. */
+ data = prefixData + gcdPREFIX_SIZE;
+
+ /* Copy argument value. */
+ gcmkMEMCPY(data, Data, DataSize);
+
+#if gcdALIGNBYSIZE
+ /* Compute the actual node size. */
+ size
+ = gcmSIZEOF(gcsBUFITEM_BUFFER)
+ + gcdPREFIX_SIZE
+ + alignment
+ + DataSize;
+
+ /* Free extra memory if any. */
+ freeSize = allocSize - size;
+ if (freeSize != 0)
+ {
+ _FreeExtraSpace(OutputBuffer, item, size, freeSize);
+ }
+#endif
+#else
+ gcsBUFITEM_BUFFER_PTR item;
+ gctINT size;
+
+ gcmDBGASSERT(DataSize != 0, "%d", DataSize);
+ gcmDBGASSERT(Data != gcvNULL, "%p", Data);
+
+ /* Determine the maximum item size. */
+ size = gcmSIZEOF(gcsBUFITEM_BUFFER) + DataSize;
+
+ /* Allocate prefix item. */
+ item = (gcsBUFITEM_BUFFER_PTR) _AllocateItem(OutputBuffer, size);
+
+ /* Set item data. */
+ item->type = gcvBUFITEM_BUFFER;
+ item->indent = Indent;
+ item->dataSize = DataSize;
+ item->address = Address;
+
+ /* Copy argument value. */
+ gcmkMEMCPY(item + 1, Data, DataSize);
+#endif
+}
+#endif
+
+static gcmINLINE void
+_InitBuffers(
+ void
+ )
+{
+ int i;
+
+ if (_outputBufferHead == gcvNULL)
+ {
+ for (i = 0; i < gcdTHREAD_BUFFERS; i += 1)
+ {
+ if (_outputBufferTail == gcvNULL)
+ {
+ _outputBufferHead = &_outputBuffer[i];
+ }
+ else
+ {
+ _outputBufferTail->next = &_outputBuffer[i];
+ }
+
+#if gcdTHREAD_BUFFERS > 1
+ _outputBuffer[i].threadID = ~0U;
+#endif
+
+ _outputBuffer[i].prev = _outputBufferTail;
+ _outputBuffer[i].next = gcvNULL;
+
+ _outputBufferTail = &_outputBuffer[i];
+ }
+ }
+}
+
+static gcmINLINE gcsBUFFERED_OUTPUT_PTR
+_GetOutputBuffer(
+ void
+ )
+{
+ gcsBUFFERED_OUTPUT_PTR outputBuffer;
+
+#if gcdTHREAD_BUFFERS > 1
+ /* Get the current thread ID. */
+ gctUINT32 ThreadID = gcmkGETTHREADID();
+
+ /* Locate the output buffer for the thread. */
+ outputBuffer = _outputBufferHead;
+
+ while (outputBuffer != gcvNULL)
+ {
+ if (outputBuffer->threadID == ThreadID)
+ {
+ break;
+ }
+
+ outputBuffer = outputBuffer->next;
+ }
+
+ /* No matching buffer found? */
+ if (outputBuffer == gcvNULL)
+ {
+ /* Get the tail for the buffer. */
+ outputBuffer = _outputBufferTail;
+
+ /* Move it to the head. */
+ _outputBufferTail = _outputBufferTail->prev;
+ _outputBufferTail->next = gcvNULL;
+
+ outputBuffer->prev = gcvNULL;
+ outputBuffer->next = _outputBufferHead;
+
+ _outputBufferHead->prev = outputBuffer;
+ _outputBufferHead = outputBuffer;
+
+ /* Reset the buffer. */
+ outputBuffer->threadID = ThreadID;
+#if gcdBUFFERED_OUTPUT
+ outputBuffer->start = 0;
+ outputBuffer->index = 0;
+ outputBuffer->count = 0;
+#endif
+#if gcdSHOW_LINE_NUMBER
+ outputBuffer->lineNumber = 0;
+#endif
+ }
+#else
+ outputBuffer = _outputBufferHead;
+#endif
+
+ return outputBuffer;
+}
+
+static gcmINLINE int _GetArgumentSize(
+ IN gctCONST_STRING Message
+ )
+{
+ int i, count;
+
+ gcmDBGASSERT(Message != gcvNULL, "%p", Message);
+
+ for (i = 0, count = 0; Message[i]; i += 1)
+ {
+ if (Message[i] == '%')
+ {
+ count += 1;
+ }
+ }
+
+ return count * gcmSIZEOF(gctUINT32);
+}
+
+#if gcdHAVEPREFIX
+static void
+_InitPrefixData(
+ IN gcsBUFFERED_OUTPUT_PTR OutputBuffer,
+ IN gctPOINTER Data
+ )
+{
+ gctUINT8_PTR data = (gctUINT8_PTR) Data;
+
+#if gcdSHOW_TIME
+ {
+ gctUINT64 time;
+ gckOS_GetProfileTick(&time);
+ gcmkALIGNPTR(gctUINT8_PTR, data, gcmSIZEOF(gctUINT64));
+ * ((gctUINT64_PTR) data) = time;
+ data += gcmSIZEOF(gctUINT64);
+ }
+#endif
+
+#if gcdSHOW_LINE_NUMBER
+ {
+ gcmkALIGNPTR(gctUINT8_PTR, data, gcmSIZEOF(gctUINT64));
+ * ((gctUINT64_PTR) data) = OutputBuffer->lineNumber;
+ data += gcmSIZEOF(gctUINT64);
+ }
+#endif
+
+#if gcdSHOW_PROCESS_ID
+ {
+ gcmkALIGNPTR(gctUINT8_PTR, data, gcmSIZEOF(gctUINT32));
+ * ((gctUINT32_PTR) data) = gcmkGETPROCESSID();
+ data += gcmSIZEOF(gctUINT32);
+ }
+#endif
+
+#if gcdSHOW_THREAD_ID
+ {
+ gcmkALIGNPTR(gctUINT8_PTR, data, gcmSIZEOF(gctUINT32));
+ * ((gctUINT32_PTR) data) = gcmkGETTHREADID();
+ }
+#endif
+}
+#endif
+
+static void
+_Print(
+ IN gctUINT ArgumentSize,
+ IN gctBOOL CopyMessage,
+ IN gctCONST_STRING Message,
+ IN gctARGUMENTS * Arguments
+ )
+{
+ gcsBUFFERED_OUTPUT_PTR outputBuffer;
+ static gcmkDECLARE_MUTEX(lockHandle);
+
+ gcmkMUTEX_LOCK(lockHandle);
+
+ /* Initialize output buffer list. */
+ _InitBuffers();
+
+ /* Locate the proper output buffer. */
+ outputBuffer = _GetOutputBuffer();
+
+ /* Update the line number. */
+#if gcdSHOW_LINE_NUMBER
+ outputBuffer->lineNumber += 1;
+#endif
+
+ /* Print prefix. */
+#if gcdHAVEPREFIX
+ {
+ gctUINT8_PTR alignedPrefixData;
+ gctUINT8 prefixData[gcdPREFIX_SIZE + gcdPREFIX_ALIGNMENT];
+
+ /* Compute aligned pointer. */
+ alignedPrefixData = prefixData;
+ gcmkALIGNPTR(gctUINT8_PTR, alignedPrefixData, gcdPREFIX_ALIGNMENT);
+
+ /* Initialize the prefix data. */
+ _InitPrefixData(outputBuffer, alignedPrefixData);
+
+ /* Print the prefix. */
+ gcdOUTPUTPREFIX(outputBuffer, alignedPrefixData);
+ }
+#endif
+
+ /* Form the indent string. */
+ if (strncmp(Message, "--", 2) == 0)
+ {
+ outputBuffer->indent -= 2;
+ }
+
+ /* Print the message. */
+ if (CopyMessage)
+ {
+ gcdOUTPUTCOPY(
+ outputBuffer, outputBuffer->indent,
+ Message, ArgumentSize, (gctPOINTER) Arguments
+ );
+ }
+ else
+ {
+ gcdOUTPUTSTRING(
+ outputBuffer, outputBuffer->indent,
+ Message, ArgumentSize, ((gctPOINTER) Arguments)
+ );
+ }
+
+ /* Check increasing indent. */
+ if (strncmp(Message, "++", 2) == 0)
+ {
+ outputBuffer->indent += 2;
+ }
+
+ gcmkMUTEX_UNLOCK(lockHandle);
+}
+
+
+/******************************************************************************\
+********************************* Debug Macros *********************************
+\******************************************************************************/
+
+#ifdef __QNXNTO__
+
+extern volatile unsigned g_nQnxInIsrs;
+
+#define gcmDEBUGPRINT(ArgumentSize, CopyMessage, Message) \
+{ \
+ if (atomic_add_value(&g_nQnxInIsrs, 1) == 0) \
+ { \
+ gctARGUMENTS __arguments__; \
+ gcmkARGUMENTS_START(__arguments__, Message); \
+ _Print(ArgumentSize, CopyMessage, Message, &__arguments__); \
+ gcmkARGUMENTS_END(__arguments__); \
+ } \
+ atomic_sub(&g_nQnxInIsrs, 1); \
+}
+
+#else
+
+#define gcmDEBUGPRINT(ArgumentSize, CopyMessage, Message) \
+{ \
+ gctARGUMENTS __arguments__; \
+ gcmkARGUMENTS_START(__arguments__, Message); \
+ _Print(ArgumentSize, CopyMessage, Message, &__arguments__); \
+ gcmkARGUMENTS_END(__arguments__); \
+}
+
+#endif
+
+/******************************************************************************\
+********************************** Debug Code **********************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+** gckOS_Print
+**
+** Send a message to the debugger.
+**
+** INPUT:
+**
+** gctCONST_STRING Message
+** Pointer to message.
+**
+** ...
+** Optional arguments.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+void
+gckOS_Print(
+ IN gctCONST_STRING Message,
+ ...
+ )
+{
+ gcmDEBUGPRINT(_GetArgumentSize(Message), gcvFALSE, Message);
+}
+
+/*******************************************************************************
+**
+** gckOS_PrintN
+**
+** Send a message to the debugger.
+**
+** INPUT:
+**
+** gctUINT ArgumentSize
+** The size of the optional arguments in bytes.
+**
+** gctCONST_STRING Message
+** Pointer to message.
+**
+** ...
+** Optional arguments.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+void
+gckOS_PrintN(
+ IN gctUINT ArgumentSize,
+ IN gctCONST_STRING Message,
+ ...
+ )
+{
+ gcmDEBUGPRINT(ArgumentSize, gcvFALSE, Message);
+}
+
+/*******************************************************************************
+**
+** gckOS_CopyPrint
+**
+** Send a message to the debugger. If in buffered output mode, the entire
+** message will be copied into the buffer instead of using the pointer to
+** the string.
+**
+** INPUT:
+**
+** gctCONST_STRING Message
+** Pointer to message.
+**
+** ...
+** Optional arguments.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+void
+gckOS_CopyPrint(
+ IN gctCONST_STRING Message,
+ ...
+ )
+{
+ gcmDEBUGPRINT(_GetArgumentSize(Message), gcvTRUE, Message);
+}
+
+/*******************************************************************************
+**
+** gckOS_DumpBuffer
+**
+** Print the contents of the specified buffer.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to gckOS object.
+**
+** gctPOINTER Buffer
+** Pointer to the buffer to print.
+**
+** gctUINT Size
+** Size of the buffer.
+**
+** gceDUMP_BUFFER Type
+** Buffer type.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+void
+gckOS_DumpBuffer(
+ IN gckOS Os,
+ IN gctPOINTER Buffer,
+ IN gctSIZE_T Size,
+ IN gceDUMP_BUFFER Type,
+ IN gctBOOL CopyMessage
+ )
+{
+ gctPHYS_ADDR_T physical;
+ gctUINT32 address = 0;
+ gcsBUFFERED_OUTPUT_PTR outputBuffer = gcvNULL;
+ gctCHAR *buffer = (gctCHAR*)Buffer;
+ gctPOINTER pAllocated = gcvNULL;
+ gctPOINTER pMapped = gcvNULL;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ static gcmkDECLARE_MUTEX(lockHandle);
+
+ gcmkMUTEX_LOCK(lockHandle);
+
+ /* Request lock when not coming from user,
+ or coming from user and not yet locked
+ and message is starting with @[. */
+ if (Type == gcvDUMP_BUFFER_FROM_USER)
+ {
+ /* Some format check. */
+ if ((Size > 2)
+ && (buffer[0] == '@' || buffer[0] == '#')
+ && (buffer[1] != '[')
+ )
+ {
+ gcmkMUTEX_UNLOCK(lockHandle);
+
+ /* No error tolerence in parser, so we stop on error to make noise. */
+ for (;;)
+ {
+ gcmkPRINT(
+ "[galcore]: %s(%d): Illegal dump message %s\n",
+ __FUNCTION__, __LINE__,
+ buffer
+ );
+
+ gckOS_Delay(Os, 10 * 1000);
+ }
+ }
+ }
+
+ if (Buffer != gcvNULL)
+ {
+ /* Initialize output buffer list. */
+ _InitBuffers();
+
+ /* Locate the proper output buffer. */
+ outputBuffer = _GetOutputBuffer();
+
+ /* Update the line number. */
+#if gcdSHOW_LINE_NUMBER
+ outputBuffer->lineNumber += 1;
+#endif
+
+ /* Get the physical address of the buffer. */
+ if (Type != gcvDUMP_BUFFER_FROM_USER)
+ {
+ gcmkVERIFY_OK(gckOS_GetPhysicalAddress(Os, Buffer, &physical));
+ gcmkSAFECASTPHYSADDRT(address, physical);
+ }
+ else
+ {
+ address = 0;
+ }
+
+ if (Type == gcvDUMP_BUFFER_USER)
+ {
+ gctBOOL needCopy = gcvTRUE;
+
+ gcmkONERROR(gckOS_QueryNeedCopy(Os, 0, &needCopy));
+
+ if (needCopy)
+ {
+ gcmkONERROR(gckOS_Allocate(
+ Os,
+ Size,
+ &pAllocated
+ ));
+
+ gcmkONERROR(gckOS_CopyFromUserData(
+ Os,
+ pAllocated,
+ Buffer,
+ Size
+ ));
+
+ Buffer = pAllocated;
+ }
+ else
+ {
+ gcmkONERROR(gckOS_MapUserPointer(
+ Os,
+ Buffer,
+ Size,
+ &pMapped
+ ));
+
+ Buffer = pMapped;
+ }
+ }
+
+#if gcdHAVEPREFIX
+ {
+ gctUINT8_PTR alignedPrefixData;
+ gctUINT8 prefixData[gcdPREFIX_SIZE + gcdPREFIX_ALIGNMENT];
+
+ /* Compute aligned pointer. */
+ alignedPrefixData = prefixData;
+ gcmkALIGNPTR(gctUINT8_PTR, alignedPrefixData, gcdPREFIX_ALIGNMENT);
+
+ /* Initialize the prefix data. */
+ _InitPrefixData(outputBuffer, alignedPrefixData);
+
+ /* Print/schedule the buffer. */
+ gcdOUTPUTBUFFER(
+ outputBuffer, outputBuffer->indent,
+ alignedPrefixData, Buffer, address, Size, Type, 0
+ );
+ }
+#else
+ /* Print/schedule the buffer. */
+ if (Type == gcvDUMP_BUFFER_FROM_USER)
+ {
+ gckOS_CopyPrint(Buffer);
+ }
+ else
+ {
+ gcdOUTPUTBUFFER(
+ outputBuffer, outputBuffer->indent,
+ gcvNULL, Buffer, address, Size, Type, 0
+ );
+ }
+#endif
+ }
+
+OnError:
+ gcmkMUTEX_UNLOCK(lockHandle);
+
+ if (pAllocated)
+ {
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, pAllocated));
+ }
+ else if (pMapped)
+ {
+ gckOS_UnmapUserPointer(Os, buffer, Size, pMapped);
+ }
+}
+
+/*******************************************************************************
+**
+** gckOS_DebugTrace
+**
+** Send a leveled message to the debugger.
+**
+** INPUT:
+**
+** gctUINT32 Level
+** Debug level of message.
+**
+** gctCONST_STRING Message
+** Pointer to message.
+**
+** ...
+** Optional arguments.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+void
+gckOS_DebugTrace(
+ IN gctUINT32 Level,
+ IN gctCONST_STRING Message,
+ ...
+ )
+{
+ if (Level > _debugLevel)
+ {
+ return;
+ }
+
+ gcmDEBUGPRINT(_GetArgumentSize(Message), gcvFALSE, Message);
+}
+
+/*******************************************************************************
+**
+** gckOS_DebugTraceN
+**
+** Send a leveled message to the debugger.
+**
+** INPUT:
+**
+** gctUINT32 Level
+** Debug level of message.
+**
+** gctUINT ArgumentSize
+** The size of the optional arguments in bytes.
+**
+** gctCONST_STRING Message
+** Pointer to message.
+**
+** ...
+** Optional arguments.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+void
+gckOS_DebugTraceN(
+ IN gctUINT32 Level,
+ IN gctUINT ArgumentSize,
+ IN gctCONST_STRING Message,
+ ...
+ )
+{
+ if (Level > _debugLevel)
+ {
+ return;
+ }
+
+ gcmDEBUGPRINT(ArgumentSize, gcvFALSE, Message);
+}
+
+/*******************************************************************************
+**
+** gckOS_DebugTraceZone
+**
+** Send a leveled and zoned message to the debugger.
+**
+** INPUT:
+**
+** gctUINT32 Level
+** Debug level for message.
+**
+** gctUINT32 Zone
+** Debug zone for message.
+**
+** gctCONST_STRING Message
+** Pointer to message.
+**
+** ...
+** Optional arguments.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+void
+gckOS_DebugTraceZone(
+ IN gctUINT32 Level,
+ IN gctUINT32 Zone,
+ IN gctCONST_STRING Message,
+ ...
+ )
+{
+ if ((Level > _debugLevel) || !(Zone & _debugZones))
+ {
+ return;
+ }
+
+ gcmDEBUGPRINT(_GetArgumentSize(Message), gcvFALSE, Message);
+}
+
+/*******************************************************************************
+**
+** gckOS_DebugTraceZoneN
+**
+** Send a leveled and zoned message to the debugger.
+**
+** INPUT:
+**
+** gctUINT32 Level
+** Debug level for message.
+**
+** gctUINT32 Zone
+** Debug zone for message.
+**
+** gctUINT ArgumentSize
+** The size of the optional arguments in bytes.
+**
+** gctCONST_STRING Message
+** Pointer to message.
+**
+** ...
+** Optional arguments.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+void
+gckOS_DebugTraceZoneN(
+ IN gctUINT32 Level,
+ IN gctUINT32 Zone,
+ IN gctUINT ArgumentSize,
+ IN gctCONST_STRING Message,
+ ...
+ )
+{
+ if ((Level > _debugLevel) || !(Zone & _debugZones))
+ {
+ return;
+ }
+
+ gcmDEBUGPRINT(ArgumentSize, gcvFALSE, Message);
+}
+
+/*******************************************************************************
+**
+** gckOS_DebugBreak
+**
+** Break into the debugger.
+**
+** INPUT:
+**
+** Nothing.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+void
+gckOS_DebugBreak(
+ void
+ )
+{
+ gckOS_DebugTrace(gcvLEVEL_ERROR, "%s(%d)", __FUNCTION__, __LINE__);
+}
+
+/*******************************************************************************
+**
+** gckOS_DebugFatal
+**
+** Send a message to the debugger and break into the debugger.
+**
+** INPUT:
+**
+** gctCONST_STRING Message
+** Pointer to message.
+**
+** ...
+** Optional arguments.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+void
+gckOS_DebugFatal(
+ IN gctCONST_STRING Message,
+ ...
+ )
+{
+ gcmkPRINT_VERSION();
+ gcmDEBUGPRINT(_GetArgumentSize(Message), gcvFALSE, Message);
+
+ /* Break into the debugger. */
+ gckOS_DebugBreak();
+}
+
+/*******************************************************************************
+**
+** gckOS_SetDebugLevel
+**
+** Set the debug level.
+**
+** INPUT:
+**
+** gctUINT32 Level
+** New debug level.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+void
+gckOS_SetDebugLevel(
+ IN gctUINT32 Level
+ )
+{
+ _debugLevel = Level;
+}
+
+/*******************************************************************************
+**
+** gckOS_SetDebugZone
+**
+** Set the debug zone.
+**
+** INPUT:
+**
+** gctUINT32 Zone
+** New debug zone.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+void
+gckOS_SetDebugZone(
+ IN gctUINT32 Zone
+ )
+{
+ _debugZones = Zone;
+}
+
+/*******************************************************************************
+**
+** gckOS_SetDebugLevelZone
+**
+** Set the debug level and zone.
+**
+** INPUT:
+**
+** gctUINT32 Level
+** New debug level.
+**
+** gctUINT32 Zone
+** New debug zone.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+void
+gckOS_SetDebugLevelZone(
+ IN gctUINT32 Level,
+ IN gctUINT32 Zone
+ )
+{
+ _debugLevel = Level;
+ _debugZones = Zone;
+}
+
+/*******************************************************************************
+**
+** gckOS_SetDebugZones
+**
+** Enable or disable debug zones.
+**
+** INPUT:
+**
+** gctUINT32 Zones
+** Debug zones to enable or disable.
+**
+** gctBOOL Enable
+** Set to gcvTRUE to enable the zones (or the Zones with the current
+** zones) or gcvFALSE to disable the specified Zones.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+void
+gckOS_SetDebugZones(
+ IN gctUINT32 Zones,
+ IN gctBOOL Enable
+ )
+{
+ if (Enable)
+ {
+ /* Enable the zones. */
+ _debugZones |= Zones;
+ }
+ else
+ {
+ /* Disable the zones. */
+ _debugZones &= ~Zones;
+ }
+}
+
+/*******************************************************************************
+**
+** gckOS_Verify
+**
+** Called to verify the result of a function call.
+**
+** INPUT:
+**
+** gceSTATUS Status
+** Function call result.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+void
+gckOS_Verify(
+ IN gceSTATUS status
+ )
+{
+ _lastError = status;
+}
+
+/*******************************************************************************
+**
+** gckOS_DebugFlush
+**
+** Force messages to be flushed out.
+**
+** INPUT:
+**
+** gctCONST_STRING CallerName
+** Name of the caller function.
+**
+** gctUINT LineNumber
+** Line number of the caller.
+**
+** gctUINT32 DmaAddress
+** The current DMA address or ~0U to ignore.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+void
+gckOS_DebugFlush(
+ gctCONST_STRING CallerName,
+ gctUINT LineNumber,
+ gctUINT32 DmaAddress
+ )
+{
+#if gcdBUFFERED_OUTPUT
+ _DirectPrint("\nFlush requested by %s(%d).\n\n", CallerName, LineNumber);
+ _Flush(DmaAddress);
+#endif
+}
+gctCONST_STRING
+gckOS_DebugStatus2Name(
+ gceSTATUS status
+ )
+{
+ switch (status)
+ {
+ case gcvSTATUS_OK:
+ return "gcvSTATUS_OK";
+ case gcvSTATUS_TRUE:
+ return "gcvSTATUS_TRUE";
+ case gcvSTATUS_NO_MORE_DATA:
+ return "gcvSTATUS_NO_MORE_DATA";
+ case gcvSTATUS_CACHED:
+ return "gcvSTATUS_CACHED";
+ case gcvSTATUS_MIPMAP_TOO_LARGE:
+ return "gcvSTATUS_MIPMAP_TOO_LARGE";
+ case gcvSTATUS_NAME_NOT_FOUND:
+ return "gcvSTATUS_NAME_NOT_FOUND";
+ case gcvSTATUS_NOT_OUR_INTERRUPT:
+ return "gcvSTATUS_NOT_OUR_INTERRUPT";
+ case gcvSTATUS_MISMATCH:
+ return "gcvSTATUS_MISMATCH";
+ case gcvSTATUS_MIPMAP_TOO_SMALL:
+ return "gcvSTATUS_MIPMAP_TOO_SMALL";
+ case gcvSTATUS_LARGER:
+ return "gcvSTATUS_LARGER";
+ case gcvSTATUS_SMALLER:
+ return "gcvSTATUS_SMALLER";
+ case gcvSTATUS_CHIP_NOT_READY:
+ return "gcvSTATUS_CHIP_NOT_READY";
+ case gcvSTATUS_NEED_CONVERSION:
+ return "gcvSTATUS_NEED_CONVERSION";
+ case gcvSTATUS_SKIP:
+ return "gcvSTATUS_SKIP";
+ case gcvSTATUS_DATA_TOO_LARGE:
+ return "gcvSTATUS_DATA_TOO_LARGE";
+ case gcvSTATUS_INVALID_CONFIG:
+ return "gcvSTATUS_INVALID_CONFIG";
+ case gcvSTATUS_CHANGED:
+ return "gcvSTATUS_CHANGED";
+ case gcvSTATUS_NOT_SUPPORT_DITHER:
+ return "gcvSTATUS_NOT_SUPPORT_DITHER";
+
+ case gcvSTATUS_INVALID_ARGUMENT:
+ return "gcvSTATUS_INVALID_ARGUMENT";
+ case gcvSTATUS_INVALID_OBJECT:
+ return "gcvSTATUS_INVALID_OBJECT";
+ case gcvSTATUS_OUT_OF_MEMORY:
+ return "gcvSTATUS_OUT_OF_MEMORY";
+ case gcvSTATUS_MEMORY_LOCKED:
+ return "gcvSTATUS_MEMORY_LOCKED";
+ case gcvSTATUS_MEMORY_UNLOCKED:
+ return "gcvSTATUS_MEMORY_UNLOCKED";
+ case gcvSTATUS_HEAP_CORRUPTED:
+ return "gcvSTATUS_HEAP_CORRUPTED";
+ case gcvSTATUS_GENERIC_IO:
+ return "gcvSTATUS_GENERIC_IO";
+ case gcvSTATUS_INVALID_ADDRESS:
+ return "gcvSTATUS_INVALID_ADDRESS";
+ case gcvSTATUS_CONTEXT_LOSSED:
+ return "gcvSTATUS_CONTEXT_LOSSED";
+ case gcvSTATUS_TOO_COMPLEX:
+ return "gcvSTATUS_TOO_COMPLEX";
+ case gcvSTATUS_BUFFER_TOO_SMALL:
+ return "gcvSTATUS_BUFFER_TOO_SMALL";
+ case gcvSTATUS_INTERFACE_ERROR:
+ return "gcvSTATUS_INTERFACE_ERROR";
+ case gcvSTATUS_NOT_SUPPORTED:
+ return "gcvSTATUS_NOT_SUPPORTED";
+ case gcvSTATUS_MORE_DATA:
+ return "gcvSTATUS_MORE_DATA";
+ case gcvSTATUS_TIMEOUT:
+ return "gcvSTATUS_TIMEOUT";
+ case gcvSTATUS_OUT_OF_RESOURCES:
+ return "gcvSTATUS_OUT_OF_RESOURCES";
+ case gcvSTATUS_INVALID_DATA:
+ return "gcvSTATUS_INVALID_DATA";
+ case gcvSTATUS_INVALID_MIPMAP:
+ return "gcvSTATUS_INVALID_MIPMAP";
+ case gcvSTATUS_NOT_FOUND:
+ return "gcvSTATUS_NOT_FOUND";
+ case gcvSTATUS_NOT_ALIGNED:
+ return "gcvSTATUS_NOT_ALIGNED";
+ case gcvSTATUS_INVALID_REQUEST:
+ return "gcvSTATUS_INVALID_REQUEST";
+ case gcvSTATUS_GPU_NOT_RESPONDING:
+ return "gcvSTATUS_GPU_NOT_RESPONDING";
+ case gcvSTATUS_TIMER_OVERFLOW:
+ return "gcvSTATUS_TIMER_OVERFLOW";
+ case gcvSTATUS_VERSION_MISMATCH:
+ return "gcvSTATUS_VERSION_MISMATCH";
+ case gcvSTATUS_LOCKED:
+ return "gcvSTATUS_LOCKED";
+ case gcvSTATUS_INTERRUPTED:
+ return "gcvSTATUS_INTERRUPTED";
+ case gcvSTATUS_DEVICE:
+ return "gcvSTATUS_DEVICE";
+ case gcvSTATUS_NOT_MULTI_PIPE_ALIGNED:
+ return "gcvSTATUS_NOT_MULTI_PIPE_ALIGNED";
+
+ /* Linker errors. */
+ case gcvSTATUS_GLOBAL_TYPE_MISMATCH:
+ return "gcvSTATUS_GLOBAL_TYPE_MISMATCH";
+ case gcvSTATUS_TOO_MANY_ATTRIBUTES:
+ return "gcvSTATUS_TOO_MANY_ATTRIBUTES";
+ case gcvSTATUS_TOO_MANY_UNIFORMS:
+ return "gcvSTATUS_TOO_MANY_UNIFORMS";
+ case gcvSTATUS_TOO_MANY_VARYINGS:
+ return "gcvSTATUS_TOO_MANY_VARYINGS";
+ case gcvSTATUS_UNDECLARED_VARYING:
+ return "gcvSTATUS_UNDECLARED_VARYING";
+ case gcvSTATUS_VARYING_TYPE_MISMATCH:
+ return "gcvSTATUS_VARYING_TYPE_MISMATCH";
+ case gcvSTATUS_MISSING_MAIN:
+ return "gcvSTATUS_MISSING_MAIN";
+ case gcvSTATUS_NAME_MISMATCH:
+ return "gcvSTATUS_NAME_MISMATCH";
+ case gcvSTATUS_INVALID_INDEX:
+ return "gcvSTATUS_INVALID_INDEX";
+ case gcvSTATUS_UNIFORM_MISMATCH:
+ return "gcvSTATUS_UNIFORM_MISMATCH";
+ case gcvSTATUS_UNSAT_LIB_SYMBOL:
+ return "gcvSTATUS_UNSAT_LIB_SYMBOL";
+ case gcvSTATUS_TOO_MANY_SHADERS:
+ return "gcvSTATUS_TOO_MANY_SHADERS";
+ case gcvSTATUS_LINK_INVALID_SHADERS:
+ return "gcvSTATUS_LINK_INVALID_SHADERS";
+ case gcvSTATUS_CS_NO_WORKGROUP_SIZE:
+ return "gcvSTATUS_CS_NO_WORKGROUP_SIZE";
+ case gcvSTATUS_LINK_LIB_ERROR:
+ return "gcvSTATUS_LINK_LIB_ERROR";
+ case gcvSTATUS_SHADER_VERSION_MISMATCH:
+ return "gcvSTATUS_SHADER_VERSION_MISMATCH";
+ case gcvSTATUS_TOO_MANY_INSTRUCTION:
+ return "gcvSTATUS_TOO_MANY_INSTRUCTION";
+ case gcvSTATUS_SSBO_MISMATCH:
+ return "gcvSTATUS_SSBO_MISMATCH";
+ case gcvSTATUS_TOO_MANY_OUTPUT:
+ return "gcvSTATUS_TOO_MANY_OUTPUT";
+ case gcvSTATUS_TOO_MANY_INPUT:
+ return "gcvSTATUS_TOO_MANY_INPUT";
+ case gcvSTATUS_NOT_SUPPORT_CL:
+ return "gcvSTATUS_NOT_SUPPORT_CL";
+ case gcvSTATUS_NOT_SUPPORT_INTEGER:
+ return "gcvSTATUS_NOT_SUPPORT_INTEGER";
+ case gcvSTATUS_UNIFORM_TYPE_MISMATCH:
+ return "gcvSTATUS_UNIFORM_TYPE_MISMATCH";
+ case gcvSTATUS_MISSING_PRIMITIVE_TYPE:
+ return "gcvSTATUS_MISSING_PRIMITIVE_TYPE";
+ case gcvSTATUS_MISSING_OUTPUT_VERTEX_COUNT:
+ return "gcvSTATUS_MISSING_OUTPUT_VERTEX_COUNT";
+ case gcvSTATUS_NON_INVOCATION_ID_AS_INDEX:
+ return "gcvSTATUS_NON_INVOCATION_ID_AS_INDEX";
+ case gcvSTATUS_INPUT_ARRAY_SIZE_MISMATCH:
+ return "gcvSTATUS_INPUT_ARRAY_SIZE_MISMATCH";
+ case gcvSTATUS_OUTPUT_ARRAY_SIZE_MISMATCH:
+ return "gcvSTATUS_OUTPUT_ARRAY_SIZE_MISMATCH";
+
+ /* Compiler errors. */
+ case gcvSTATUS_COMPILER_FE_PREPROCESSOR_ERROR:
+ return "gcvSTATUS_COMPILER_FE_PREPROCESSOR_ERROR";
+ case gcvSTATUS_COMPILER_FE_PARSER_ERROR:
+ return "gcvSTATUS_COMPILER_FE_PARSER_ERROR";
+ default:
+ return "nil";
+ }
+}
+
+/*******************************************************************************
+***** Binary Trace *************************************************************
+*******************************************************************************/
+
+/*******************************************************************************
+** _VerifyMessage
+**
+** Verify a binary trace message, decode it to human readable string and print
+** it.
+**
+** ARGUMENTS:
+**
+** gctCONST_STRING Buffer
+** Pointer to buffer to store.
+**
+** gctSIZE_T Bytes
+** Buffer length.
+*/
+void
+_VerifyMessage(
+ IN gctCONST_STRING Buffer,
+ IN gctSIZE_T Bytes
+ )
+{
+ char arguments[150] = {0};
+ char format[100] = {0};
+
+ gctSTRING function;
+ gctPOINTER args;
+ gctUINT32 numArguments;
+ int i = 0;
+ gctUINT32 functionBytes;
+
+ gcsBINARY_TRACE_MESSAGE_PTR message = (gcsBINARY_TRACE_MESSAGE_PTR)Buffer;
+
+ /* Check signature. */
+ if (message->signature != 0x7FFFFFFF)
+ {
+ gcmkPRINT("Signature error");
+ return;
+ }
+
+ /* Get function name. */
+ function = (gctSTRING)&message->payload;
+ functionBytes = (gctUINT32)strlen(function) + 1;
+
+ /* Get arguments number. */
+ numArguments = message->numArguments;
+
+ /* Get arguments . */
+ args = function + functionBytes;
+
+ /* Prepare format string. */
+ while (numArguments--)
+ {
+ format[i++] = '%';
+ format[i++] = 'x';
+ format[i++] = ' ';
+ }
+
+ format[i] = '\0';
+
+ if (numArguments)
+ {
+ gcmkVSPRINTF(arguments, 150, format, (gctARGUMENTS *) &args);
+ }
+
+ gcmkPRINT("[%d](%d): %s(%d) %s",
+ message->pid,
+ message->tid,
+ function,
+ message->line,
+ arguments);
+}
+
+
+/*******************************************************************************
+** gckOS_WriteToRingBuffer
+**
+** Store a buffer to ring buffer.
+**
+** ARGUMENTS:
+**
+** gctCONST_STRING Buffer
+** Pointer to buffer to store.
+**
+** gctSIZE_T Bytes
+** Buffer length.
+*/
+void
+gckOS_WriteToRingBuffer(
+ IN gctCONST_STRING Buffer,
+ IN gctSIZE_T Bytes
+ )
+{
+
+}
+
+/*******************************************************************************
+** gckOS_BinaryTrace
+**
+** Output a binary trace message.
+**
+** ARGUMENTS:
+**
+** gctCONST_STRING Function
+** Pointer to function name.
+**
+** gctINT Line
+** Line number.
+**
+** gctCONST_STRING Text OPTIONAL
+** Optional pointer to a descriptive text.
+**
+** ...
+** Optional arguments to the descriptive text.
+*/
+void
+gckOS_BinaryTrace(
+ IN gctCONST_STRING Function,
+ IN gctINT Line,
+ IN gctCONST_STRING Text OPTIONAL,
+ ...
+ )
+{
+ static gctUINT32 messageSignature = 0x7FFFFFFF;
+ char buffer[gcdBINARY_TRACE_MESSAGE_SIZE];
+ gctUINT32 numArguments = 0;
+ gctUINT32 functionBytes;
+ gctUINT32 i = 0;
+ gctSTRING payload;
+ gcsBINARY_TRACE_MESSAGE_PTR message = (gcsBINARY_TRACE_MESSAGE_PTR)buffer;
+
+ /* Calculate arguments number. */
+ if (Text)
+ {
+ while (Text[i] != '\0')
+ {
+ if (Text[i] == '%')
+ {
+ numArguments++;
+ }
+ i++;
+ }
+ }
+
+ message->signature = messageSignature;
+ message->pid = gcmkGETPROCESSID();
+ message->tid = gcmkGETTHREADID();
+ message->line = Line;
+ message->numArguments = numArguments;
+
+ payload = (gctSTRING)&message->payload;
+
+ /* Function name. */
+ functionBytes = (gctUINT32)gcmkSTRLEN(Function) + 1;
+ gcmkMEMCPY(payload, Function, functionBytes);
+
+ /* Advance to next payload. */
+ payload += functionBytes;
+
+ /* Arguments value. */
+ if (numArguments)
+ {
+ gctARGUMENTS p;
+ gcmkARGUMENTS_START(p, Text);
+
+ for (i = 0; i < numArguments; ++i)
+ {
+ gctPOINTER value = gcmkARGUMENTS_ARG(p, gctPOINTER);
+ gcmkMEMCPY(payload, &value, gcmSIZEOF(gctPOINTER));
+ payload += gcmSIZEOF(gctPOINTER);
+ }
+
+ gcmkARGUMENTS_END(p);
+ }
+
+ gcmkASSERT(payload - buffer <= gcdBINARY_TRACE_MESSAGE_SIZE);
+
+
+ /* Send buffer to ring buffer. */
+ gckOS_WriteToRingBuffer(buffer, (gctUINT32)(payload - buffer));
+}
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_event.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_event.c
new file mode 100644
index 000000000000..03bd3c724232
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_event.c
@@ -0,0 +1,3070 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+#include "gc_hal_kernel_buffer.h"
+
+#ifdef __QNXNTO__
+#include "gc_hal_kernel_qnx.h"
+#endif
+
+#define _GC_OBJ_ZONE gcvZONE_EVENT
+
+#define gcdEVENT_ALLOCATION_COUNT (4096 / gcmSIZEOF(gcsHAL_INTERFACE))
+#define gcdEVENT_MIN_THRESHOLD 4
+
+/******************************************************************************\
+********************************* Support Code *********************************
+\******************************************************************************/
+
+static gcmINLINE gceSTATUS
+gckEVENT_AllocateQueue(
+ IN gckEVENT Event,
+ OUT gcsEVENT_QUEUE_PTR * Queue
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Event=0x%x", Event);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+ gcmkVERIFY_ARGUMENT(Queue != gcvNULL);
+
+ /* Do we have free queues? */
+ if (Event->freeList == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ /* Move one free queue from the free list. */
+ * Queue = Event->freeList;
+ Event->freeList = Event->freeList->next;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Queue=0x%x", gcmOPT_POINTER(Queue));
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+gckEVENT_FreeQueue(
+ IN gckEVENT Event,
+ OUT gcsEVENT_QUEUE_PTR Queue
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+
+ gcmkHEADER_ARG("Event=0x%x", Event);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+ gcmkVERIFY_ARGUMENT(Queue != gcvNULL);
+
+ /* Move one free queue from the free list. */
+ Queue->next = Event->freeList;
+ Event->freeList = Queue;
+
+ /* Success. */
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+gckEVENT_FreeRecord(
+ IN gckEVENT Event,
+ IN gcsEVENT_PTR Record
+ )
+{
+ gceSTATUS status;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+ gcmkVERIFY_ARGUMENT(Record != gcvNULL);
+
+ /* Acquire the mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Event->os,
+ Event->freeEventMutex,
+ gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Push the record on the free list. */
+ Record->next = Event->freeEventList;
+ Event->freeEventList = Record;
+ Event->freeEventCount += 1;
+
+ /* Release the mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Roll back. */
+ if (acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+gckEVENT_IsEmpty(
+ IN gckEVENT Event,
+ OUT gctBOOL_PTR IsEmpty
+ )
+{
+ gceSTATUS status;
+ gctSIZE_T i;
+
+ gcmkHEADER_ARG("Event=0x%x", Event);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+ gcmkVERIFY_ARGUMENT(IsEmpty != gcvNULL);
+
+ /* Assume the event queue is empty. */
+ *IsEmpty = gcvTRUE;
+
+ /* Walk the event queue. */
+ for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
+ {
+ /* Check whether this event is in use. */
+ if (Event->queues[i].head != gcvNULL)
+ {
+ /* The event is in use, hence the queue is not empty. */
+ *IsEmpty = gcvFALSE;
+ break;
+ }
+ }
+
+ /* Try acquiring the mutex. */
+ status = gckOS_AcquireMutex(Event->os, Event->eventQueueMutex, 0);
+ if (status == gcvSTATUS_TIMEOUT)
+ {
+ /* Timeout - queue is no longer empty. */
+ *IsEmpty = gcvFALSE;
+ }
+ else
+ {
+ /* Bail out on error. */
+ gcmkONERROR(status);
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*IsEmpty=%d", gcmOPT_VALUE(IsEmpty));
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+_TryToIdleGPU(
+ IN gckEVENT Event
+)
+{
+ gceSTATUS status;
+ gctBOOL empty = gcvFALSE, idle = gcvFALSE;
+ gctBOOL powerLocked = gcvFALSE;
+ gckHARDWARE hardware;
+
+ gcmkHEADER_ARG("Event=0x%x", Event);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+
+ /* Grab gckHARDWARE object. */
+ hardware = Event->kernel->hardware;
+ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+ /* Check whether the event queue is empty. */
+ gcmkONERROR(gckEVENT_IsEmpty(Event, &empty));
+
+ if (empty)
+ {
+ status = gckOS_AcquireMutex(hardware->os, hardware->powerMutex, 0);
+ if (status == gcvSTATUS_TIMEOUT)
+ {
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+ powerLocked = gcvTRUE;
+
+ /* Query whether the hardware is idle. */
+ gcmkONERROR(gckHARDWARE_QueryIdle(Event->kernel->hardware, &idle));
+
+ gcmkONERROR(gckOS_ReleaseMutex(hardware->os, hardware->powerMutex));
+ powerLocked = gcvFALSE;
+
+ if (idle)
+ {
+ /* Inform the system of idle GPU. */
+ gcmkONERROR(gckOS_Broadcast(Event->os,
+ Event->kernel->hardware,
+ gcvBROADCAST_GPU_IDLE));
+ }
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (powerLocked)
+ {
+ gcmkONERROR(gckOS_ReleaseMutex(hardware->os, hardware->powerMutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+__RemoveRecordFromProcessDB(
+ IN gckEVENT Event,
+ IN gcsEVENT_PTR Record
+ )
+{
+ gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record);
+ gcmkVERIFY_ARGUMENT(Record != gcvNULL);
+
+ switch (Record->info.command)
+ {
+ case gcvHAL_FREE_NON_PAGED_MEMORY:
+ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+ Event->kernel,
+ Record->processID,
+ gcvDB_NON_PAGED,
+ gcmUINT64_TO_PTR(Record->info.u.FreeNonPagedMemory.logical)));
+ break;
+
+ case gcvHAL_FREE_CONTIGUOUS_MEMORY:
+ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+ Event->kernel,
+ Record->processID,
+ gcvDB_CONTIGUOUS,
+ gcmUINT64_TO_PTR(Record->info.u.FreeContiguousMemory.logical)));
+ break;
+
+ case gcvHAL_UNLOCK_VIDEO_MEMORY:
+ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+ Event->kernel,
+ Record->processID,
+ gcvDB_VIDEO_MEMORY_LOCKED,
+ gcmUINT64_TO_PTR(Record->info.u.UnlockVideoMemory.node)));
+ break;
+
+ case gcvHAL_UNMAP_USER_MEMORY:
+ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+ Event->kernel,
+ Record->processID,
+ gcvDB_MAP_USER_MEMORY,
+ gcmINT2PTR(Record->info.u.UnmapUserMemory.info)));
+ break;
+
+ case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER:
+ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+ Event->kernel,
+ Record->processID,
+ gcvDB_COMMAND_BUFFER,
+ gcmUINT64_TO_PTR(Record->info.u.FreeVirtualCommandBuffer.logical)));
+ break;
+
+ default:
+ break;
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_ReleaseVideoMemoryHandle(
+ IN gckKERNEL Kernel,
+ IN OUT gcsEVENT_PTR Record,
+ IN OUT gcsHAL_INTERFACE * Interface
+ )
+{
+ gceSTATUS status;
+ gckVIDMEM_NODE nodeObject;
+ gctUINT32 handle;
+
+ switch(Interface->command)
+ {
+ case gcvHAL_UNLOCK_VIDEO_MEMORY:
+ handle = (gctUINT32)Interface->u.UnlockVideoMemory.node;
+
+ gcmkONERROR(gckVIDMEM_HANDLE_Lookup(
+ Kernel, Record->processID, handle, &nodeObject));
+
+ Record->info.u.UnlockVideoMemory.node = gcmPTR_TO_UINT64(nodeObject);
+
+ gckVIDMEM_HANDLE_Dereference(Kernel, Record->processID, handle);
+ break;
+
+ default:
+ break;
+ }
+
+ return gcvSTATUS_OK;
+OnError:
+ return status;
+}
+
+/*******************************************************************************
+**
+** _QueryFlush
+**
+** Check the type of surfaces which will be released by current event and
+** determine the cache needed to flush.
+**
+*/
+static gceSTATUS
+_QueryFlush(
+ IN gckEVENT Event,
+ IN gcsEVENT_PTR Record,
+ OUT gceKERNEL_FLUSH *Flush
+ )
+{
+ gceKERNEL_FLUSH flush = 0;
+ gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record);
+ gcmkVERIFY_ARGUMENT(Record != gcvNULL);
+
+ while (Record != gcvNULL)
+ {
+ switch (Record->info.command)
+ {
+ case gcvHAL_UNLOCK_VIDEO_MEMORY:
+ switch(Record->info.u.UnlockVideoMemory.type)
+ {
+ case gcvSURF_TILE_STATUS:
+ flush |= gcvFLUSH_TILE_STATUS;
+ break;
+ case gcvSURF_RENDER_TARGET:
+ flush |= gcvFLUSH_COLOR;
+ break;
+ case gcvSURF_DEPTH:
+ flush |= gcvFLUSH_DEPTH;
+ break;
+ case gcvSURF_TEXTURE:
+ flush |= gcvFLUSH_TEXTURE;
+ break;
+ case gcvSURF_ICACHE:
+ flush |= gcvFLUSH_ICACHE;
+ break;
+ case gcvSURF_TXDESC:
+ flush |= gcvFLUSH_TXDESC;
+ break;
+ case gcvSURF_FENCE:
+ flush |= gcvFLUSH_FENCE;
+ break;
+ case gcvSURF_VERTEX:
+ flush |= gcvFLUSH_VERTEX;
+ break;
+ case gcvSURF_TFBHEADER:
+ flush |= gcvFLUSH_TFBHEADER;
+ break;
+ case gcvSURF_TYPE_UNKNOWN:
+ *Flush = gcvFLUSH_ALL;
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ default:
+ break;
+ }
+ break;
+ case gcvHAL_UNMAP_USER_MEMORY:
+ *Flush = gcvFLUSH_ALL;
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+ default:
+ break;
+ }
+
+ Record = Record->next;
+ }
+
+ *Flush = flush;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+void
+_SubmitTimerFunction(
+ gctPOINTER Data
+ )
+{
+ gckEVENT event = (gckEVENT)Data;
+ gcmkVERIFY_OK(gckEVENT_Submit(event, gcvTRUE, gcvFALSE));
+}
+
+/******************************************************************************\
+******************************* gckEVENT API Code *******************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+** gckEVENT_Construct
+**
+** Construct a new gckEVENT object.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** OUTPUT:
+**
+** gckEVENT * Event
+** Pointer to a variable that receives the gckEVENT object pointer.
+*/
+gceSTATUS
+gckEVENT_Construct(
+ IN gckKERNEL Kernel,
+ OUT gckEVENT * Event
+ )
+{
+ gckOS os;
+ gceSTATUS status;
+ gckEVENT eventObj = gcvNULL;
+ int i;
+ gcsEVENT_PTR record;
+ gctPOINTER pointer = gcvNULL;
+
+ gcmkHEADER_ARG("Kernel=0x%x", Kernel);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Event != gcvNULL);
+
+ /* Extract the pointer to the gckOS object. */
+ os = Kernel->os;
+ gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+ /* Allocate the gckEVENT object. */
+ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckEVENT), &pointer));
+
+ eventObj = pointer;
+
+ /* Reset the object. */
+ gcmkVERIFY_OK(gckOS_ZeroMemory(eventObj, gcmSIZEOF(struct _gckEVENT)));
+
+ /* Initialize the gckEVENT object. */
+ eventObj->object.type = gcvOBJ_EVENT;
+ eventObj->kernel = Kernel;
+ eventObj->os = os;
+
+ /* Create the mutexes. */
+ gcmkONERROR(gckOS_CreateMutex(os, &eventObj->eventQueueMutex));
+ gcmkONERROR(gckOS_CreateMutex(os, &eventObj->freeEventMutex));
+ gcmkONERROR(gckOS_CreateMutex(os, &eventObj->eventListMutex));
+
+ /* Create a bunch of event reccords. */
+ for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; i += 1)
+ {
+ /* Allocate an event record. */
+ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsEVENT), &pointer));
+
+ record = pointer;
+
+ /* Push it on the free list. */
+ record->next = eventObj->freeEventList;
+ eventObj->freeEventList = record;
+ eventObj->freeEventCount += 1;
+ }
+
+ /* Initialize the free list of event queues. */
+ for (i = 0; i < gcdREPO_LIST_COUNT; i += 1)
+ {
+ eventObj->repoList[i].next = eventObj->freeList;
+ eventObj->freeList = &eventObj->repoList[i];
+ }
+
+ eventObj->freeQueueCount = gcmCOUNTOF(eventObj->queues);
+
+ gcmkONERROR(gckOS_AtomConstruct(os, &eventObj->pending));
+
+ gcmkVERIFY_OK(gckOS_CreateTimer(os,
+ _SubmitTimerFunction,
+ (gctPOINTER)eventObj,
+ &eventObj->submitTimer));
+
+#if gcdINTERRUPT_STATISTIC
+ gcmkONERROR(gckOS_AtomConstruct(os, &eventObj->interruptCount));
+ gcmkONERROR(gckOS_AtomSet(os,eventObj->interruptCount, 0));
+#endif
+
+ eventObj->notifyState = -1;
+
+ /* Return pointer to the gckEVENT object. */
+ *Event = eventObj;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Event=0x%x", *Event);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Roll back. */
+ if (eventObj != gcvNULL)
+ {
+ if (eventObj->eventQueueMutex != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->eventQueueMutex));
+ }
+
+ if (eventObj->freeEventMutex != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->freeEventMutex));
+ }
+
+ if (eventObj->eventListMutex != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->eventListMutex));
+ }
+
+ while (eventObj->freeEventList != gcvNULL)
+ {
+ record = eventObj->freeEventList;
+ eventObj->freeEventList = record->next;
+
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, record));
+ }
+
+ if (eventObj->pending != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_AtomDestroy(os, eventObj->pending));
+ }
+
+#if gcdINTERRUPT_STATISTIC
+ if (eventObj->interruptCount)
+ {
+ gcmkVERIFY_OK(gckOS_AtomDestroy(os, eventObj->interruptCount));
+ }
+#endif
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, eventObj));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckEVENT_Destroy
+**
+** Destroy an gckEVENT object.
+**
+** INPUT:
+**
+** gckEVENT Event
+** Pointer to an gckEVENT object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckEVENT_Destroy(
+ IN gckEVENT Event
+ )
+{
+ gcsEVENT_PTR record;
+ gcsEVENT_QUEUE_PTR queue;
+
+ gcmkHEADER_ARG("Event=0x%x", Event);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+
+ if (Event->submitTimer != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_StopTimer(Event->os, Event->submitTimer));
+ gcmkVERIFY_OK(gckOS_DestroyTimer(Event->os, Event->submitTimer));
+ }
+
+ /* Delete the queue mutex. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->eventQueueMutex));
+
+ /* Free all free events. */
+ while (Event->freeEventList != gcvNULL)
+ {
+ record = Event->freeEventList;
+ Event->freeEventList = record->next;
+
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, record));
+ }
+
+ /* Delete the free mutex. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->freeEventMutex));
+
+ /* Free all pending queues. */
+ while (Event->queueHead != gcvNULL)
+ {
+ /* Get the current queue. */
+ queue = Event->queueHead;
+
+ /* Free all pending events. */
+ while (queue->head != gcvNULL)
+ {
+ record = queue->head;
+ queue->head = record->next;
+
+ gcmkTRACE_ZONE_N(
+ gcvLEVEL_WARNING, gcvZONE_EVENT,
+ gcmSIZEOF(record) + gcmSIZEOF(queue->source),
+ "Event record 0x%x is still pending for %d.",
+ record, queue->source
+ );
+
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, record));
+ }
+
+ /* Remove the top queue from the list. */
+ if (Event->queueHead == Event->queueTail)
+ {
+ Event->queueHead =
+ Event->queueTail = gcvNULL;
+ }
+ else
+ {
+ Event->queueHead = Event->queueHead->next;
+ }
+
+ /* Free the queue. */
+ gcmkVERIFY_OK(gckEVENT_FreeQueue(Event, queue));
+ }
+
+ /* Delete the list mutex. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->eventListMutex));
+
+ gcmkVERIFY_OK(gckOS_AtomDestroy(Event->os, Event->pending));
+
+#if gcdINTERRUPT_STATISTIC
+ gcmkVERIFY_OK(gckOS_AtomDestroy(Event->os, Event->interruptCount));
+#endif
+
+ /* Mark the gckEVENT object as unknown. */
+ Event->object.type = gcvOBJ_UNKNOWN;
+
+ /* Free the gckEVENT object. */
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, Event));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckEVENT_GetEvent
+**
+** Reserve the next available hardware event.
+**
+** INPUT:
+**
+** gckEVENT Event
+** Pointer to an gckEVENT object.
+**
+** gctBOOL Wait
+** Set to gcvTRUE to force the function to wait if no events are
+** immediately available.
+**
+** gceKERNEL_WHERE Source
+** Source of the event.
+**
+** OUTPUT:
+**
+** gctUINT8 * EventID
+** Reserved event ID.
+*/
+#define gcdINVALID_EVENT_PTR ((gcsEVENT_PTR)gcvMAXUINTPTR_T)
+
+gceSTATUS
+gckEVENT_GetEvent(
+ IN gckEVENT Event,
+ IN gctBOOL Wait,
+ OUT gctUINT8 * EventID,
+ IN gceKERNEL_WHERE Source
+ )
+{
+ gctINT i, id;
+ gceSTATUS status;
+ gctBOOL acquired = gcvFALSE;
+ gctINT32 free;
+
+ gcmkHEADER_ARG("Event=0x%x Source=%d", Event, Source);
+
+ while (gcvTRUE)
+ {
+ /* Grab the queue mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Event->os,
+ Event->eventQueueMutex,
+ gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Walk through all events. */
+ id = Event->lastID;
+ for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
+ {
+ gctINT nextID = id + 1;
+
+ if (nextID == gcmCOUNTOF(Event->queues))
+ {
+ nextID = 0;
+ }
+
+ if (Event->queues[id].head == gcvNULL)
+ {
+ *EventID = (gctUINT8) id;
+
+ Event->lastID = (gctUINT8) nextID;
+
+ /* Save time stamp of event. */
+ Event->queues[id].head = gcdINVALID_EVENT_PTR;
+ Event->queues[id].stamp = ++(Event->stamp);
+ Event->queues[id].source = Source;
+
+ /* Decrease the number of free events. */
+ free = --Event->freeQueueCount;
+
+ /* Make compiler happy. */
+ free = free;
+
+#if gcdDYNAMIC_SPEED
+ if (free <= gcdDYNAMIC_EVENT_THRESHOLD)
+ {
+ gcmkONERROR(gckOS_BroadcastHurry(
+ Event->os,
+ Event->kernel->hardware,
+ gcdDYNAMIC_EVENT_THRESHOLD - free));
+ }
+#endif
+
+ /* Release the queue mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(Event->os,
+ Event->eventQueueMutex));
+
+ /* Success. */
+ gcmkTRACE_ZONE_N(
+ gcvLEVEL_INFO, gcvZONE_EVENT,
+ gcmSIZEOF(id),
+ "Using id=%d",
+ id
+ );
+
+ gcmkFOOTER_ARG("*EventID=%u", *EventID);
+ return gcvSTATUS_OK;
+ }
+
+ id = nextID;
+ }
+
+#if gcdDYNAMIC_SPEED
+ /* No free events, speed up the GPU right now! */
+ gcmkONERROR(gckOS_BroadcastHurry(Event->os,
+ Event->kernel->hardware,
+ gcdDYNAMIC_EVENT_THRESHOLD));
+#endif
+
+ /* Release the queue mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+ acquired = gcvFALSE;
+
+ /* Fail if wait is not requested. */
+ if (!Wait)
+ {
+ /* Out of resources. */
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ /* Delay a while. */
+ gcmkONERROR(gckOS_Delay(Event->os, 1));
+ }
+
+OnError:
+ if (acquired)
+ {
+ /* Release the queue mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckEVENT_AllocateRecord
+**
+** Allocate a record for the new event.
+**
+** INPUT:
+**
+** gckEVENT Event
+** Pointer to an gckEVENT object.
+**
+** gctBOOL AllocateAllowed
+** State for allocation if out of free events.
+**
+** OUTPUT:
+**
+** gcsEVENT_PTR * Record
+** Allocated event record.
+*/
+static gcmINLINE gceSTATUS
+gckEVENT_AllocateRecord(
+ IN gckEVENT Event,
+ IN gctBOOL AllocateAllowed,
+ OUT gcsEVENT_PTR * Record
+ )
+{
+ gceSTATUS status;
+ gctBOOL acquired = gcvFALSE;
+ gctINT i;
+ gcsEVENT_PTR record;
+ gctPOINTER pointer = gcvNULL;
+
+ gcmkHEADER_ARG("Event=0x%x AllocateAllowed=%d", Event, AllocateAllowed);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+ gcmkVERIFY_ARGUMENT(Record != gcvNULL);
+
+ /* Acquire the mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->freeEventMutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Test if we are below the allocation threshold. */
+ if ( (AllocateAllowed && (Event->freeEventCount < gcdEVENT_MIN_THRESHOLD)) ||
+ (Event->freeEventCount == 0) )
+ {
+ /* Allocate a bunch of records. */
+ for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; i += 1)
+ {
+ /* Allocate an event record. */
+ gcmkONERROR(gckOS_Allocate(Event->os,
+ gcmSIZEOF(gcsEVENT),
+ &pointer));
+
+ record = pointer;
+
+ /* Push it on the free list. */
+ record->next = Event->freeEventList;
+ Event->freeEventList = record;
+ Event->freeEventCount += 1;
+ }
+ }
+
+ *Record = Event->freeEventList;
+ Event->freeEventList = Event->freeEventList->next;
+ Event->freeEventCount -= 1;
+
+ /* Release the mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Record=0x%x", gcmOPT_POINTER(Record));
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Roll back. */
+ if (acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckEVENT_AddList
+**
+** Add a new event to the list of events.
+**
+** INPUT:
+**
+** gckEVENT Event
+** Pointer to an gckEVENT object.
+**
+** gcsHAL_INTERFACE_PTR Interface
+** Pointer to the interface for the event to be added.
+**
+** gceKERNEL_WHERE FromWhere
+** Place in the pipe where the event needs to be generated.
+**
+** gctBOOL AllocateAllowed
+** State for allocation if out of free events.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckEVENT_AddList(
+ IN gckEVENT Event,
+ IN gcsHAL_INTERFACE_PTR Interface,
+ IN gceKERNEL_WHERE FromWhere,
+ IN gctBOOL AllocateAllowed,
+ IN gctBOOL FromKernel
+ )
+{
+ gceSTATUS status;
+ gctBOOL acquired = gcvFALSE;
+ gcsEVENT_PTR record = gcvNULL;
+ gcsEVENT_QUEUE_PTR queue;
+ gckVIRTUAL_COMMAND_BUFFER_PTR buffer;
+ gckKERNEL kernel = Event->kernel;
+
+ gcmkHEADER_ARG("Event=0x%x Interface=0x%x",
+ Event, Interface);
+
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, _GC_OBJ_ZONE,
+ "FromWhere=%d AllocateAllowed=%d",
+ FromWhere, AllocateAllowed);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+ gcmkVERIFY_ARGUMENT(Interface != gcvNULL);
+
+ /* Verify the event command. */
+ gcmkASSERT
+ ( (Interface->command == gcvHAL_FREE_NON_PAGED_MEMORY)
+ || (Interface->command == gcvHAL_FREE_CONTIGUOUS_MEMORY)
+ || (Interface->command == gcvHAL_WRITE_DATA)
+ || (Interface->command == gcvHAL_UNLOCK_VIDEO_MEMORY)
+ || (Interface->command == gcvHAL_SIGNAL)
+ || (Interface->command == gcvHAL_UNMAP_USER_MEMORY)
+ || (Interface->command == gcvHAL_TIMESTAMP)
+ || (Interface->command == gcvHAL_COMMIT_DONE)
+ || (Interface->command == gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER)
+ || (Interface->command == gcvHAL_DESTROY_MMU)
+ );
+
+ /* Validate the source. */
+ if ((FromWhere != gcvKERNEL_COMMAND) && (FromWhere != gcvKERNEL_PIXEL))
+ {
+ /* Invalid argument. */
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ /* Allocate a free record. */
+ gcmkONERROR(gckEVENT_AllocateRecord(Event, AllocateAllowed, &record));
+
+ /* Termninate the record. */
+ record->next = gcvNULL;
+
+ /* Record the committer. */
+ record->fromKernel = FromKernel;
+
+ /* Copy the event interface into the record. */
+ gckOS_MemCopy(&record->info, Interface, gcmSIZEOF(record->info));
+
+ /* Get process ID. */
+ gcmkONERROR(gckOS_GetProcessID(&record->processID));
+
+ if (FromKernel == gcvFALSE)
+ {
+ gcmkONERROR(__RemoveRecordFromProcessDB(Event, record));
+
+ /* Handle is belonged to current process, it must be released now. */
+ status = _ReleaseVideoMemoryHandle(Event->kernel, record, Interface);
+
+ if (gcmIS_ERROR(status))
+ {
+ /* Ingore error because there are other events in the queue. */
+ status = gcvSTATUS_OK;
+ goto OnError;
+ }
+ }
+
+#ifdef __QNXNTO__
+ record->kernel = Event->kernel;
+#endif
+
+ /* Unmap user space logical address.
+ * Linux kernel does not support unmap the memory of other process any more since 3.5.
+ * Let's unmap memory of self process before submit the event to gpu.
+ * */
+ switch(Interface->command)
+ {
+ case gcvHAL_FREE_NON_PAGED_MEMORY:
+ gcmkONERROR(gckOS_UnmapUserLogical(
+ Event->os,
+ gcmNAME_TO_PTR(Interface->u.FreeNonPagedMemory.physical),
+ (gctSIZE_T) Interface->u.FreeNonPagedMemory.bytes,
+ gcmUINT64_TO_PTR(Interface->u.FreeNonPagedMemory.logical)));
+ break;
+ case gcvHAL_FREE_CONTIGUOUS_MEMORY:
+ gcmkONERROR(gckOS_UnmapUserLogical(
+ Event->os,
+ gcmNAME_TO_PTR(Interface->u.FreeContiguousMemory.physical),
+ (gctSIZE_T) Interface->u.FreeContiguousMemory.bytes,
+ gcmUINT64_TO_PTR(Interface->u.FreeContiguousMemory.logical)));
+ break;
+
+ case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER:
+ buffer = (gckVIRTUAL_COMMAND_BUFFER_PTR)gcmNAME_TO_PTR(Interface->u.FreeVirtualCommandBuffer.physical);
+ if (buffer != gcvNULL && buffer->virtualBuffer.userLogical)
+ {
+ gcmkONERROR(gckOS_DestroyUserVirtualMapping(
+ Event->os,
+ buffer->virtualBuffer.physical,
+ (gctSIZE_T) Interface->u.FreeVirtualCommandBuffer.bytes,
+ gcmUINT64_TO_PTR(Interface->u.FreeVirtualCommandBuffer.logical)));
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* Acquire the mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->eventListMutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Do we need to allocate a new queue? */
+ if ((Event->queueTail == gcvNULL) || (Event->queueTail->source < FromWhere))
+ {
+ /* Allocate a new queue. */
+ gcmkONERROR(gckEVENT_AllocateQueue(Event, &queue));
+
+ /* Initialize the queue. */
+ queue->source = FromWhere;
+ queue->head = gcvNULL;
+ queue->next = gcvNULL;
+
+ /* Attach it to the list of allocated queues. */
+ if (Event->queueTail == gcvNULL)
+ {
+ Event->queueHead =
+ Event->queueTail = queue;
+ }
+ else
+ {
+ Event->queueTail->next = queue;
+ Event->queueTail = queue;
+ }
+ }
+ else
+ {
+ queue = Event->queueTail;
+ }
+
+ /* Attach the record to the queue. */
+ if (queue->head == gcvNULL)
+ {
+ queue->head = record;
+ queue->tail = record;
+ }
+ else
+ {
+ queue->tail->next = record;
+ queue->tail = record;
+ }
+
+ /* Release the mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Roll back. */
+ if (acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
+ }
+
+ if (record != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckEVENT_Unlock
+**
+** Schedule an event to unlock virtual memory.
+**
+** INPUT:
+**
+** gckEVENT Event
+** Pointer to an gckEVENT object.
+**
+** gceKERNEL_WHERE FromWhere
+** Place in the pipe where the event needs to be generated.
+**
+** gcuVIDMEM_NODE_PTR Node
+** Pointer to a gcuVIDMEM_NODE union that specifies the virtual memory
+** to unlock.
+**
+** gceSURF_TYPE Type
+** Type of surface to unlock.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckEVENT_Unlock(
+ IN gckEVENT Event,
+ IN gceKERNEL_WHERE FromWhere,
+ IN gctPOINTER Node,
+ IN gceSURF_TYPE Type
+ )
+{
+ gceSTATUS status;
+ gcsHAL_INTERFACE iface;
+
+ gcmkHEADER_ARG("Event=0x%x FromWhere=%d Node=0x%x Type=%d",
+ Event, FromWhere, Node, Type);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+ gcmkVERIFY_ARGUMENT(Node != gcvNULL);
+
+ /* Mark the event as an unlock. */
+ iface.command = gcvHAL_UNLOCK_VIDEO_MEMORY;
+ iface.u.UnlockVideoMemory.node = gcmPTR_TO_UINT64(Node);
+ iface.u.UnlockVideoMemory.type = Type;
+ iface.u.UnlockVideoMemory.asynchroneous = 0;
+
+ /* Append it to the queue. */
+ gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckEVENT_FreeNonPagedMemory
+**
+** Schedule an event to free non-paged memory.
+**
+** INPUT:
+**
+** gckEVENT Event
+** Pointer to an gckEVENT object.
+**
+** gctSIZE_T Bytes
+** Number of bytes of non-paged memory to free.
+**
+** gctPHYS_ADDR Physical
+** Physical address of non-paged memory to free.
+**
+** gctPOINTER Logical
+** Logical address of non-paged memory to free.
+**
+** gceKERNEL_WHERE FromWhere
+** Place in the pipe where the event needs to be generated.
+*/
+gceSTATUS
+gckEVENT_FreeNonPagedMemory(
+ IN gckEVENT Event,
+ IN gctSIZE_T Bytes,
+ IN gctPHYS_ADDR Physical,
+ IN gctPOINTER Logical,
+ IN gceKERNEL_WHERE FromWhere
+ )
+{
+ gceSTATUS status;
+ gcsHAL_INTERFACE iface;
+ gckKERNEL kernel = Event->kernel;
+
+ gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x "
+ "FromWhere=%d",
+ Event, Bytes, Physical, Logical, FromWhere);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+ gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+
+ /* Create an event. */
+ iface.command = gcvHAL_FREE_NON_PAGED_MEMORY;
+ iface.u.FreeNonPagedMemory.bytes = Bytes;
+ iface.u.FreeNonPagedMemory.physical = gcmPTR_TO_NAME(Physical);
+ iface.u.FreeNonPagedMemory.logical = gcmPTR_TO_UINT64(Logical);
+
+ /* Append it to the queue. */
+ gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckEVENT_DestroyVirtualCommandBuffer(
+ IN gckEVENT Event,
+ IN gctSIZE_T Bytes,
+ IN gctPHYS_ADDR Physical,
+ IN gctPOINTER Logical,
+ IN gceKERNEL_WHERE FromWhere
+ )
+{
+ gceSTATUS status;
+ gcsHAL_INTERFACE iface;
+ gckKERNEL kernel = Event->kernel;
+
+ gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x "
+ "FromWhere=%d",
+ Event, Bytes, Physical, Logical, FromWhere);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+ gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+
+ /* Create an event. */
+ iface.command = gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER;
+ iface.u.FreeVirtualCommandBuffer.bytes = Bytes;
+ iface.u.FreeVirtualCommandBuffer.physical = gcmPTR_TO_NAME(Physical);
+ iface.u.FreeVirtualCommandBuffer.logical = gcmPTR_TO_UINT64(Logical);
+
+ /* Append it to the queue. */
+ gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckEVENT_FreeContigiuousMemory
+**
+** Schedule an event to free contiguous memory.
+**
+** INPUT:
+**
+** gckEVENT Event
+** Pointer to an gckEVENT object.
+**
+** gctSIZE_T Bytes
+** Number of bytes of contiguous memory to free.
+**
+** gctPHYS_ADDR Physical
+** Physical address of contiguous memory to free.
+**
+** gctPOINTER Logical
+** Logical address of contiguous memory to free.
+**
+** gceKERNEL_WHERE FromWhere
+** Place in the pipe where the event needs to be generated.
+*/
+gceSTATUS
+gckEVENT_FreeContiguousMemory(
+ IN gckEVENT Event,
+ IN gctSIZE_T Bytes,
+ IN gctPHYS_ADDR Physical,
+ IN gctPOINTER Logical,
+ IN gceKERNEL_WHERE FromWhere
+ )
+{
+ gceSTATUS status;
+ gcsHAL_INTERFACE iface;
+ gckKERNEL kernel = Event->kernel;
+
+ gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x "
+ "FromWhere=%d",
+ Event, Bytes, Physical, Logical, FromWhere);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+ gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+
+ /* Create an event. */
+ iface.command = gcvHAL_FREE_CONTIGUOUS_MEMORY;
+ iface.u.FreeContiguousMemory.bytes = Bytes;
+ iface.u.FreeContiguousMemory.physical = gcmPTR_TO_NAME(Physical);
+ iface.u.FreeContiguousMemory.logical = gcmPTR_TO_UINT64(Logical);
+
+ /* Append it to the queue. */
+ gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckEVENT_Signal
+**
+** Schedule an event to trigger a signal.
+**
+** INPUT:
+**
+** gckEVENT Event
+** Pointer to an gckEVENT object.
+**
+** gctSIGNAL Signal
+** Pointer to the signal to trigger.
+**
+** gceKERNEL_WHERE FromWhere
+** Place in the pipe where the event needs to be generated.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckEVENT_Signal(
+ IN gckEVENT Event,
+ IN gctSIGNAL Signal,
+ IN gceKERNEL_WHERE FromWhere
+ )
+{
+ gceSTATUS status;
+ gcsHAL_INTERFACE iface;
+
+ gcmkHEADER_ARG("Event=0x%x Signal=0x%x FromWhere=%d",
+ Event, Signal, FromWhere);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+ gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
+
+ /* Mark the event as a signal. */
+ iface.command = gcvHAL_SIGNAL;
+ iface.u.Signal.signal = gcmPTR_TO_UINT64(Signal);
+ iface.u.Signal.auxSignal = 0;
+ iface.u.Signal.process = 0;
+
+#ifdef __QNXNTO__
+ iface.u.Signal.coid = 0;
+ iface.u.Signal.rcvid = 0;
+
+ gcmkONERROR(gckOS_SignalPending(Event->os, Signal));
+#endif
+
+ /* Append it to the queue. */
+ gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+#if gcdPROCESS_ADDRESS_SPACE
+gceSTATUS
+gckEVENT_DestroyMmu(
+ IN gckEVENT Event,
+ IN gckMMU Mmu,
+ IN gceKERNEL_WHERE FromWhere
+ )
+{
+ gceSTATUS status;
+ gcsHAL_INTERFACE iface;
+
+ gcmkHEADER_ARG("Event=0x%x FromWhere=%d", Event, FromWhere);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+
+ iface.command = gcvHAL_DESTROY_MMU;
+ iface.u.DestroyMmu.mmu = gcmPTR_TO_UINT64(Mmu);
+
+ /* Append it to the queue. */
+ gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE, gcvTRUE));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+#endif
+
+gceSTATUS
+gckEVENT_SubmitAsync(
+ IN gckEVENT Event,
+ IN gctBOOL Wait,
+ IN gctBOOL FromPower
+ )
+{
+ gceSTATUS status;
+ gctUINT8 id = 0xFF;
+ gcsEVENT_QUEUE_PTR queue;
+ gctBOOL acquired = gcvFALSE;
+ gctBOOL commitEntered = gcvFALSE;
+ gctUINT32 start, end;
+ gctUINT8_PTR startLogical;
+ gctUINT32 eventBytes;
+
+ gckHARDWARE hardware;
+ gckASYNC_COMMAND asyncCommand;
+
+ gcmkHEADER_ARG("Event=0x%x Wait=%d", Event, Wait);
+
+ /* Get gckCOMMAND object. */
+ hardware = Event->kernel->hardware;
+ asyncCommand = Event->asyncCommand;
+
+ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+ /* Are there event queues? */
+ if (Event->queueHead != gcvNULL)
+ {
+ /* Acquire the command queue. */
+ gcmkONERROR(gckASYNC_COMMAND_EnterCommit(asyncCommand));
+ commitEntered = gcvTRUE;
+
+ /* Process all queues. */
+ while (Event->queueHead != gcvNULL)
+ {
+ /* Acquire the list mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Event->os,
+ Event->eventListMutex,
+ gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Get the current queue. */
+ queue = Event->queueHead;
+
+ /* Allocate an event ID. */
+ gcmkONERROR(gckEVENT_GetEvent(Event, Wait, &id, queue->source));
+
+ /* Copy event list to event ID queue. */
+ Event->queues[id].head = queue->head;
+
+ /* Remove the top queue from the list. */
+ if (Event->queueHead == Event->queueTail)
+ {
+ Event->queueHead = gcvNULL;
+ Event->queueTail = gcvNULL;
+ }
+ else
+ {
+ Event->queueHead = Event->queueHead->next;
+ }
+
+ /* Free the queue. */
+ gcmkONERROR(gckEVENT_FreeQueue(Event, queue));
+
+ /* Release the list mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
+ acquired = gcvFALSE;
+
+ gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware, gcvNULL, id, gcvKERNEL_BLT, &eventBytes));
+
+ /* Get command sequence. */
+ start = hardware->functions[gcvHARDWARE_FUNCTION_BLT_EVENT].address + id * eventBytes;
+ end = start + 24;
+
+ startLogical = hardware->functions[gcvHARDWARE_FUNCTION_BLT_EVENT].logical + id * eventBytes;
+
+ gcmkDUMPCOMMAND(
+ Event->os,
+ startLogical,
+ end - start,
+ gcvDUMP_BUFFER_KERNEL,
+ gcvFALSE
+ );
+
+ gcmkONERROR(gckASYNC_COMMAND_Execute(asyncCommand, start, end));
+ }
+
+ /* Release the command queue. */
+ gcmkONERROR(gckASYNC_COMMAND_ExitCommit(asyncCommand));
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ /* Need to unroll the mutex acquire. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
+ }
+
+ if (commitEntered)
+ {
+ /* Release the command queue mutex. */
+ gcmkVERIFY_OK(gckASYNC_COMMAND_ExitCommit(asyncCommand));
+ }
+
+ if (id != 0xFF)
+ {
+ /* Need to unroll the event allocation. */
+ Event->queues[id].head = gcvNULL;
+ }
+
+ if (status == gcvSTATUS_GPU_NOT_RESPONDING)
+ {
+ /* Broadcast GPU stuck. */
+ status = gckOS_Broadcast(Event->os,
+ Event->kernel->hardware,
+ gcvBROADCAST_GPU_STUCK);
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckEVENT_Submit
+**
+** Submit the current event queue to the GPU.
+**
+** INPUT:
+**
+** gckEVENT Event
+** Pointer to an gckEVENT object.
+**
+** gctBOOL Wait
+** Submit requires one vacant event; if Wait is set to not zero,
+** and there are no vacant events at this time, the function will
+** wait until an event becomes vacant so that submission of the
+** queue is successful.
+**
+** gctBOOL FromPower
+** Determines whether the call originates from inside the power
+** management or not.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckEVENT_Submit(
+ IN gckEVENT Event,
+ IN gctBOOL Wait,
+ IN gctBOOL FromPower
+ )
+{
+ gceSTATUS status;
+ gctUINT8 id = 0xFF;
+ gcsEVENT_QUEUE_PTR queue;
+ gctBOOL acquired = gcvFALSE;
+ gckCOMMAND command = gcvNULL;
+ gctBOOL commitEntered = gcvFALSE;
+#if !gcdNULL_DRIVER
+ gctUINT32 bytes;
+ gctPOINTER buffer;
+ gctUINT32 executeBytes;
+ gctUINT32 flushBytes;
+#endif
+
+#if gcdINTERRUPT_STATISTIC
+ gctINT32 oldValue;
+#endif
+
+#if gcdSECURITY
+ gctPOINTER reservedBuffer;
+#endif
+
+ gckHARDWARE hardware;
+
+ gceKERNEL_FLUSH flush = gcvFALSE;
+ gctUINT64 commitStamp;
+
+ gcmkHEADER_ARG("Event=0x%x Wait=%d", Event, Wait);
+
+ /* Get gckCOMMAND object. */
+ command = Event->kernel->command;
+ hardware = Event->kernel->hardware;
+
+ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+ if (Event->asyncCommand)
+ {
+ /* Call async submit path. */
+ gcmkONERROR(gckEVENT_SubmitAsync(Event, Wait, FromPower));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+ gckOS_GetTicks(&Event->lastCommitStamp);
+
+ /* Are there event queues? */
+ if (Event->queueHead != gcvNULL)
+ {
+ /* Acquire the command queue. */
+ gcmkONERROR(gckCOMMAND_EnterCommit(command, FromPower));
+ commitEntered = gcvTRUE;
+
+ /* Get current commit stamp. */
+ commitStamp = Event->kernel->command->commitStamp;
+
+ if (commitStamp)
+ {
+ commitStamp -= 1;
+ }
+
+ /* Process all queues. */
+ while (Event->queueHead != gcvNULL)
+ {
+ /* Acquire the list mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Event->os,
+ Event->eventListMutex,
+ gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Get the current queue. */
+ queue = Event->queueHead;
+
+ /* Allocate an event ID. */
+ gcmkONERROR(gckEVENT_GetEvent(Event, Wait, &id, queue->source));
+
+ /* Copy event list to event ID queue. */
+ Event->queues[id].head = queue->head;
+
+ /* Update current commit stamp. */
+ Event->queues[id].commitStamp = commitStamp;
+
+ /* Remove the top queue from the list. */
+ if (Event->queueHead == Event->queueTail)
+ {
+ Event->queueHead = gcvNULL;
+ Event->queueTail = gcvNULL;
+ }
+ else
+ {
+ Event->queueHead = Event->queueHead->next;
+ }
+
+ /* Free the queue. */
+ gcmkONERROR(gckEVENT_FreeQueue(Event, queue));
+
+ /* Release the list mutex. */
+ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
+ acquired = gcvFALSE;
+
+ /* Determine cache needed to flush. */
+ gcmkVERIFY_OK(_QueryFlush(Event, Event->queues[id].head, &flush));
+
+#if gcdNULL_DRIVER
+#if gcdINTERRUPT_STATISTIC
+ gcmkVERIFY_OK(gckOS_AtomIncrement(
+ Event->os,
+ Event->interruptCount,
+ &oldValue
+ ));
+#endif
+
+ /* Notify immediately on infinite hardware. */
+ gcmkONERROR(gckEVENT_Interrupt(Event, 1 << id));
+
+ gcmkONERROR(gckEVENT_Notify(Event, 0));
+#else
+ /* Get the size of the hardware event. */
+ gcmkONERROR(gckHARDWARE_Event(
+ hardware,
+ gcvNULL,
+ id,
+ Event->queues[id].source,
+ &bytes
+ ));
+
+ /* Get the size of flush command. */
+ gcmkONERROR(gckHARDWARE_Flush(
+ hardware,
+ flush,
+ gcvNULL,
+ &flushBytes
+ ));
+
+ bytes += flushBytes;
+
+ /* Total bytes need to execute. */
+ executeBytes = bytes;
+
+ /* Reserve space in the command queue. */
+ gcmkONERROR(gckCOMMAND_Reserve(command, bytes, &buffer, &bytes));
+#if gcdSECURITY
+ reservedBuffer = buffer;
+#endif
+
+ /* Set the flush in the command queue. */
+ gcmkONERROR(gckHARDWARE_Flush(
+ hardware,
+ flush,
+ buffer,
+ &flushBytes
+ ));
+
+ /* Advance to next command. */
+ buffer = (gctUINT8_PTR)buffer + flushBytes;
+
+ /* Set the hardware event in the command queue. */
+ gcmkONERROR(gckHARDWARE_Event(
+ hardware,
+ buffer,
+ id,
+ Event->queues[id].source,
+ &bytes
+ ));
+
+ /* Advance to next command. */
+ buffer = (gctUINT8_PTR)buffer + bytes;
+
+#if gcdINTERRUPT_STATISTIC
+ gcmkVERIFY_OK(gckOS_AtomIncrement(
+ Event->os,
+ Event->interruptCount,
+ &oldValue
+ ));
+#endif
+
+#if gcdSECURITY
+ gckKERNEL_SecurityExecute(
+ Event->kernel,
+ reservedBuffer,
+ executeBytes
+ );
+#else
+ /* Execute the hardware event. */
+ gcmkONERROR(gckCOMMAND_Execute(command, executeBytes));
+#endif
+#endif
+ }
+
+ /* Release the command queue. */
+ gcmkONERROR(gckCOMMAND_ExitCommit(command, FromPower));
+
+#if !gcdNULL_DRIVER
+ if (!FromPower)
+ {
+ gcmkVERIFY_OK(_TryToIdleGPU(Event));
+ }
+#endif
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ /* Need to unroll the mutex acquire. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex));
+ }
+
+ if (commitEntered)
+ {
+ /* Release the command queue mutex. */
+ gcmkVERIFY_OK(gckCOMMAND_ExitCommit(command, FromPower));
+ }
+
+ if (id != 0xFF)
+ {
+ /* Need to unroll the event allocation. */
+ Event->queues[id].head = gcvNULL;
+ }
+
+ if (status == gcvSTATUS_GPU_NOT_RESPONDING)
+ {
+ /* Broadcast GPU stuck. */
+ status = gckOS_Broadcast(Event->os,
+ Event->kernel->hardware,
+ gcvBROADCAST_GPU_STUCK);
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckEVENT_Commit
+**
+** Commit an event queue from the user.
+**
+** INPUT:
+**
+** gckEVENT Event
+** Pointer to an gckEVENT object.
+**
+** gcsQUEUE_PTR Queue
+** User event queue.
+**
+** gctBOOL Forced
+** Force fire a event. There won't be interrupt if there's no events
+ queued. Force a event by append a dummy one if this parameter is on.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckEVENT_Commit(
+ IN gckEVENT Event,
+ IN gcsQUEUE_PTR Queue,
+ IN gctBOOL Forced
+ )
+{
+ gceSTATUS status;
+ gcsQUEUE_PTR record = gcvNULL, next;
+ gctUINT32 processID;
+ gctBOOL needCopy = gcvFALSE;
+ gctPOINTER pointer = gcvNULL;
+
+ gcmkHEADER_ARG("Event=0x%x Queue=0x%x", Event, Queue);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+
+ /* Get the current process ID. */
+ gcmkONERROR(gckOS_GetProcessID(&processID));
+
+ /* Query if we need to copy the client data. */
+ gcmkONERROR(gckOS_QueryNeedCopy(Event->os, processID, &needCopy));
+
+ /* Loop while there are records in the queue. */
+ while (Queue != gcvNULL)
+ {
+ gcsQUEUE queue;
+
+ if (needCopy)
+ {
+ /* Point to stack record. */
+ record = &queue;
+
+ /* Copy the data from the client. */
+ gcmkONERROR(gckOS_CopyFromUserData(Event->os,
+ record,
+ Queue,
+ gcmSIZEOF(gcsQUEUE)));
+ }
+ else
+ {
+
+ /* Map record into kernel memory. */
+ gcmkONERROR(gckOS_MapUserPointer(Event->os,
+ Queue,
+ gcmSIZEOF(gcsQUEUE),
+ &pointer));
+
+ record = pointer;
+ }
+
+ /* Append event record to event queue. */
+ gcmkONERROR(
+ gckEVENT_AddList(Event, &record->iface, gcvKERNEL_PIXEL, gcvTRUE, gcvFALSE));
+
+ /* Next record in the queue. */
+ next = gcmUINT64_TO_PTR(record->next);
+
+ if (!needCopy)
+ {
+ /* Unmap record from kernel memory. */
+ gcmkONERROR(
+ gckOS_UnmapUserPointer(Event->os,
+ Queue,
+ gcmSIZEOF(gcsQUEUE),
+ (gctPOINTER *) record));
+ record = gcvNULL;
+ }
+
+ Queue = next;
+ }
+
+ if (Forced && Event->queueHead == gcvNULL)
+ {
+ gcsHAL_INTERFACE iface;
+ iface.command = gcvHAL_COMMIT_DONE;
+
+ gcmkONERROR(gckEVENT_AddList(Event, &iface, gcvKERNEL_PIXEL, gcvFALSE, gcvTRUE));
+ }
+
+ /* Submit the event list. */
+ gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE, gcvFALSE));
+
+ /* Success */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (pointer)
+ {
+ /* Roll back. */
+ gcmkVERIFY_OK(gckOS_UnmapUserPointer(Event->os,
+ Queue,
+ gcmSIZEOF(gcsQUEUE),
+ (gctPOINTER*)pointer));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckEVENT_Interrupt
+**
+** Called by the interrupt service routine to store the triggered interrupt
+** mask to be later processed by gckEVENT_Notify.
+**
+** INPUT:
+**
+** gckEVENT Event
+** Pointer to an gckEVENT object.
+**
+** gctUINT32 Data
+** Mask for the 32 interrupts.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckEVENT_Interrupt(
+ IN gckEVENT Event,
+ IN gctUINT32 Data
+ )
+{
+ gcmkHEADER_ARG("Event=0x%x Data=0x%x", Event, Data);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+
+ if (Data & 0x20000000)
+ {
+ gctUINT32 resume;
+ gctUINT32 bytes;
+ gctUINT32 idle;
+ gctUINT32 pageSize = Event->kernel->command->pageSize;
+ Data &= ~0x20000000;
+
+ {
+ /* Make sure FE is idle. */
+ do
+ {
+ gcmkVERIFY_OK(gckOS_ReadRegisterEx(
+ Event->os,
+ Event->kernel->core,
+ 0x4,
+ &idle));
+ }
+ while (idle != 0x7FFFFFFF);
+
+ gcmkVERIFY_OK(gckOS_ReadRegisterEx(
+ Event->os,
+ Event->kernel->core,
+ 0x664,
+ &resume));
+
+ gcmkVERIFY_OK(gckOS_ReadRegisterEx(
+ Event->os,
+ Event->kernel->core,
+ 0x664,
+ &resume));
+
+ gcmkVERIFY_OK(gckHARDWARE_WaitLink(
+ Event->kernel->hardware,
+ gcvNULL,
+ ~0U,
+ resume & (pageSize - 1),
+ &bytes,
+ gcvNULL,
+ gcvNULL
+ ));
+
+ /* Start Command Parser. */
+ gcmkVERIFY_OK(gckHARDWARE_Execute(
+ Event->kernel->hardware,
+ resume,
+ bytes
+ ));
+ }
+ }
+
+ /* Combine current interrupt status with pending flags. */
+ gckOS_AtomSetMask(Event->pending, Data);
+
+#if gcdINTERRUPT_STATISTIC
+ {
+ gctINT j = 0;
+ gctINT32 oldValue;
+
+ for (j = 0; j < gcmCOUNTOF(Event->queues); j++)
+ {
+ if ((Data & (1 << j)))
+ {
+ gcmkVERIFY_OK(gckOS_AtomDecrement(Event->os,
+ Event->interruptCount,
+ &oldValue));
+ }
+ }
+ }
+#endif
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckEVENT_Notify
+**
+** Process all triggered interrupts.
+**
+** INPUT:
+**
+** gckEVENT Event
+** Pointer to an gckEVENT object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckEVENT_Notify(
+ IN gckEVENT Event,
+ IN gctUINT32 IDs
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+ gctINT i;
+ gcsEVENT_QUEUE * queue;
+ gctUINT mask = 0;
+ gctBOOL acquired = gcvFALSE;
+ gctSIGNAL signal;
+ gctUINT pending = 0;
+ gckKERNEL kernel = Event->kernel;
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+ gctINT eventNumber = 0;
+#endif
+#if gcdSECURE_USER
+ gcskSECURE_CACHE_PTR cache;
+ gcuVIDMEM_NODE_PTR node;
+#endif
+ gckVIDMEM_NODE nodeObject;
+
+ gcmkHEADER_ARG("Event=0x%x IDs=0x%x", Event, IDs);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+
+ gcmDEBUG_ONLY(
+ if (IDs != 0)
+ {
+ for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
+ {
+ if (Event->queues[i].head != gcvNULL)
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
+ "Queue(%d): stamp=%llu source=%d",
+ i,
+ Event->queues[i].stamp,
+ Event->queues[i].source);
+ }
+ }
+ }
+ );
+
+ /* Begin of event handling. */
+ Event->notifyState = 0;
+
+ for (;;)
+ {
+ gcsEVENT_PTR record;
+
+ /* Grab the mutex queue. */
+ gcmkONERROR(gckOS_AcquireMutex(Event->os,
+ Event->eventQueueMutex,
+ gcvINFINITE));
+ acquired = gcvTRUE;
+
+ gckOS_AtomGet(Event->os, Event->pending, (gctINT32_PTR)&pending);
+
+ if (pending == 0)
+ {
+ /* Release the mutex queue. */
+ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+ acquired = gcvFALSE;
+
+ /* No more pending interrupts - done. */
+ break;
+ }
+
+ if (pending & 0x80000000)
+ {
+ gcmkPRINT("AXI BUS ERROR");
+ gckHARDWARE_DumpGPUState(Event->kernel->hardware);
+ pending &= 0x7FFFFFFF;
+ }
+
+ if ((pending & 0x40000000) && Event->kernel->hardware->mmuVersion)
+ {
+#if gcdUSE_MMU_EXCEPTION
+#if gcdALLOC_ON_FAULT
+ status = gckHARDWARE_HandleFault(Event->kernel->hardware);
+#endif
+ if (gcmIS_ERROR(status))
+ {
+ /* Dump error is fault can't be handle. */
+ gckHARDWARE_DumpMMUException(Event->kernel->hardware);
+
+ gckHARDWARE_DumpGPUState(Event->kernel->hardware);
+ }
+#endif
+
+ pending &= 0xBFFFFFFF;
+ }
+
+ gcmkTRACE_ZONE_N(
+ gcvLEVEL_INFO, gcvZONE_EVENT,
+ gcmSIZEOF(pending),
+ "Pending interrupts 0x%x",
+ pending
+ );
+
+ queue = gcvNULL;
+
+ gcmDEBUG_ONLY(
+ if (IDs == 0)
+ {
+ for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
+ {
+ if (Event->queues[i].head != gcvNULL)
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
+ "Queue(%d): stamp=%llu source=%d",
+ i,
+ Event->queues[i].stamp,
+ Event->queues[i].source);
+ }
+ }
+ }
+ );
+
+ /* Find the oldest pending interrupt. */
+ for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
+ {
+ if ((Event->queues[i].head != gcvNULL)
+ && (pending & (1 << i))
+ )
+ {
+ if ((queue == gcvNULL)
+ || (Event->queues[i].stamp < queue->stamp)
+ )
+ {
+ queue = &Event->queues[i];
+ mask = 1 << i;
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+ eventNumber = i;
+#endif
+ }
+ }
+ }
+
+ if (queue == gcvNULL)
+ {
+ gcmkTRACE_ZONE_N(
+ gcvLEVEL_ERROR, gcvZONE_EVENT,
+ gcmSIZEOF(pending),
+ "Interrupts 0x%x are not pending.",
+ pending
+ );
+
+ gckOS_AtomClearMask(Event->pending, pending);
+
+ /* Release the mutex queue. */
+ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+ acquired = gcvFALSE;
+ break;
+ }
+
+ /* Check whether there is a missed interrupt. */
+ for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
+ {
+ if ((Event->queues[i].head != gcvNULL)
+ && (Event->queues[i].stamp < queue->stamp)
+ && (Event->queues[i].source <= queue->source)
+ )
+ {
+ gcmkTRACE_N(
+ gcvLEVEL_ERROR,
+ gcmSIZEOF(i) + gcmSIZEOF(Event->queues[i].stamp),
+ "Event %d lost (stamp %llu)",
+ i, Event->queues[i].stamp
+ );
+
+ /* Use this event instead. */
+ queue = &Event->queues[i];
+ mask = 0;
+ }
+ }
+
+ if (mask != 0)
+ {
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+ gcmkTRACE_ZONE_N(
+ gcvLEVEL_INFO, gcvZONE_EVENT,
+ gcmSIZEOF(eventNumber),
+ "Processing interrupt %d",
+ eventNumber
+ );
+#endif
+ }
+
+ gckOS_AtomClearMask(Event->pending, mask);
+
+ if (!gckHARDWARE_IsFeatureAvailable(Event->kernel->hardware, gcvFEATURE_FENCE_64BIT))
+ {
+ /* Write out commit stamp.*/
+ *(gctUINT64 *)(Event->kernel->command->fence->logical) = queue->commitStamp;
+ }
+
+ /* Signal clients waiting for fence. */
+ gcmkVERIFY_OK(gckFENCE_Signal(
+ Event->os,
+ Event->kernel->command->fence
+ ));
+
+ /* Grab the event head. */
+ record = queue->head;
+
+ /* Now quickly clear its event list. */
+ queue->head = gcvNULL;
+
+ /* Increase the number of free events. */
+ Event->freeQueueCount++;
+
+ /* Release the mutex queue. */
+ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+ acquired = gcvFALSE;
+
+ /* Walk all events for this interrupt. */
+ while (record != gcvNULL)
+ {
+ gcsEVENT_PTR recordNext;
+#ifndef __QNXNTO__
+ gctPOINTER logical;
+#endif
+#if gcdSECURE_USER
+ gctSIZE_T bytes;
+#endif
+
+ /* Grab next record. */
+ recordNext = record->next;
+
+#ifdef __QNXNTO__
+ /*
+ * Assign record->processID as the pid for this galcore thread.
+ * Used in the OS calls which do not take a pid.
+ */
+ drv_thread_specific_key_assign(record->processID, 0);
+#endif
+
+#if gcdSECURE_USER
+ /* Get the cache that belongs to this process. */
+ gcmkONERROR(gckKERNEL_GetProcessDBCache(Event->kernel,
+ record->processID,
+ &cache));
+#endif
+
+ gcmkTRACE_ZONE_N(
+ gcvLEVEL_INFO, gcvZONE_EVENT,
+ gcmSIZEOF(record->info.command),
+ "Processing event type: %d",
+ record->info.command
+ );
+
+ switch (record->info.command)
+ {
+ case gcvHAL_FREE_NON_PAGED_MEMORY:
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
+ "gcvHAL_FREE_NON_PAGED_MEMORY: 0x%x",
+ gcmNAME_TO_PTR(record->info.u.FreeNonPagedMemory.physical));
+
+ /* Free non-paged memory. */
+ status = gckOS_FreeNonPagedMemory(
+ Event->os,
+ (gctSIZE_T) record->info.u.FreeNonPagedMemory.bytes,
+ gcmNAME_TO_PTR(record->info.u.FreeNonPagedMemory.physical),
+ gcmUINT64_TO_PTR(record->info.u.FreeNonPagedMemory.logical));
+
+ if (gcmIS_SUCCESS(status))
+ {
+#if gcdSECURE_USER
+ gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
+ Event->kernel,
+ cache,
+ gcmUINT64_TO_PTR(record->record.u.FreeNonPagedMemory.logical),
+ (gctSIZE_T) record->record.u.FreeNonPagedMemory.bytes));
+#endif
+ }
+ gcmRELEASE_NAME(record->info.u.FreeNonPagedMemory.physical);
+ break;
+
+ case gcvHAL_FREE_CONTIGUOUS_MEMORY:
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_EVENT,
+ "gcvHAL_FREE_CONTIGUOUS_MEMORY: 0x%x",
+ gcmNAME_TO_PTR(record->info.u.FreeContiguousMemory.physical));
+
+ /* Unmap the user memory. */
+ status = gckOS_FreeContiguous(
+ Event->os,
+ gcmNAME_TO_PTR(record->info.u.FreeContiguousMemory.physical),
+ gcmUINT64_TO_PTR(record->info.u.FreeContiguousMemory.logical),
+ (gctSIZE_T) record->info.u.FreeContiguousMemory.bytes);
+
+ if (gcmIS_SUCCESS(status))
+ {
+#if gcdSECURE_USER
+ gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
+ Event->kernel,
+ cache,
+ gcmUINT64_TO_PTR(event->event.u.FreeContiguousMemory.logical),
+ (gctSIZE_T) event->event.u.FreeContiguousMemory.bytes));
+#endif
+ }
+ gcmRELEASE_NAME(record->info.u.FreeContiguousMemory.physical);
+ break;
+
+ case gcvHAL_WRITE_DATA:
+#ifndef __QNXNTO__
+ /* Convert physical into logical address. */
+ gcmkERR_BREAK(
+ gckOS_MapPhysical(Event->os,
+ record->info.u.WriteData.address,
+ gcmSIZEOF(gctUINT32),
+ &logical));
+
+ /* Write data. */
+ gcmkERR_BREAK(
+ gckOS_WriteMemory(Event->os,
+ logical,
+ record->info.u.WriteData.data));
+
+ /* Unmap the physical memory. */
+ gcmkERR_BREAK(
+ gckOS_UnmapPhysical(Event->os,
+ logical,
+ gcmSIZEOF(gctUINT32)));
+#else
+ /* Write data. */
+ gcmkERR_BREAK(
+ gckOS_WriteMemory(Event->os,
+ gcmUINT64_TO_PTR(record->info.u.WriteData.address),
+ record->info.u.WriteData.data));
+#endif
+ break;
+
+ case gcvHAL_UNLOCK_VIDEO_MEMORY:
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
+ "gcvHAL_UNLOCK_VIDEO_MEMORY: 0x%x",
+ record->info.u.UnlockVideoMemory.node);
+
+ nodeObject = gcmUINT64_TO_PTR(record->info.u.UnlockVideoMemory.node);
+
+#if gcdSECURE_USER
+ node = nodeObject->node;
+
+ /* Save node information before it disappears. */
+ node = event->event.u.UnlockVideoMemory.node;
+ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
+ {
+ logical = gcvNULL;
+ bytes = 0;
+ }
+ else
+ {
+ logical = node->Virtual.logical;
+ bytes = node->Virtual.bytes;
+ }
+#endif
+
+ /* Unlock. */
+ status = gckVIDMEM_Unlock(
+ Event->kernel,
+ nodeObject,
+ record->info.u.UnlockVideoMemory.type,
+ gcvNULL);
+
+#if gcdSECURE_USER
+ if (gcmIS_SUCCESS(status) && (logical != gcvNULL))
+ {
+ gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache(
+ Event->kernel,
+ cache,
+ logical,
+ bytes));
+ }
+#endif
+
+#if gcdPROCESS_ADDRESS_SPACE
+ gcmkVERIFY_OK(gckVIDMEM_NODE_Unlock(
+ Event->kernel,
+ nodeObject,
+ record->processID
+ ));
+#endif
+
+ status = gckVIDMEM_NODE_Dereference(Event->kernel, nodeObject);
+ break;
+
+ case gcvHAL_SIGNAL:
+ signal = gcmUINT64_TO_PTR(record->info.u.Signal.signal);
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
+ "gcvHAL_SIGNAL: 0x%x",
+ signal);
+
+#ifdef __QNXNTO__
+ if ((record->info.u.Signal.coid == 0)
+ && (record->info.u.Signal.rcvid == 0)
+ )
+ {
+ /* Kernel signal. */
+ gcmkERR_BREAK(
+ gckOS_SignalPulse(Event->os,
+ signal));
+ }
+ else
+ {
+ /* User signal. */
+ gcmkERR_BREAK(
+ gckOS_UserSignal(Event->os,
+ signal,
+ record->info.u.Signal.rcvid,
+ record->info.u.Signal.coid));
+ }
+#else
+ /* Set signal. */
+ if (gcmUINT64_TO_PTR(record->info.u.Signal.process) == gcvNULL)
+ {
+ /* Kernel signal. */
+ gcmkERR_BREAK(
+ gckOS_Signal(Event->os,
+ signal,
+ gcvTRUE));
+ }
+ else
+ {
+ /* User signal. */
+ gcmkERR_BREAK(
+ gckOS_UserSignal(Event->os,
+ signal,
+ gcmUINT64_TO_PTR(record->info.u.Signal.process)));
+ }
+
+ gcmkASSERT(record->info.u.Signal.auxSignal == 0);
+#endif
+ break;
+
+ case gcvHAL_TIMESTAMP:
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
+ "gcvHAL_TIMESTAMP: %d %d",
+ record->info.u.TimeStamp.timer,
+ record->info.u.TimeStamp.request);
+
+ /* Process the timestamp. */
+ switch (record->info.u.TimeStamp.request)
+ {
+ case 0:
+ status = gckOS_GetTime(&Event->kernel->timers[
+ record->info.u.TimeStamp.timer].
+ stopTime);
+ break;
+
+ case 1:
+ status = gckOS_GetTime(&Event->kernel->timers[
+ record->info.u.TimeStamp.timer].
+ startTime);
+ break;
+
+ default:
+ gcmkTRACE_ZONE_N(
+ gcvLEVEL_ERROR, gcvZONE_EVENT,
+ gcmSIZEOF(record->info.u.TimeStamp.request),
+ "Invalid timestamp request: %d",
+ record->info.u.TimeStamp.request
+ );
+
+ status = gcvSTATUS_INVALID_ARGUMENT;
+ break;
+ }
+ break;
+
+ case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER:
+ gcmkVERIFY_OK(
+ gckKERNEL_DestroyVirtualCommandBuffer(Event->kernel,
+ (gctSIZE_T) record->info.u.FreeVirtualCommandBuffer.bytes,
+ gcmNAME_TO_PTR(record->info.u.FreeVirtualCommandBuffer.physical),
+ gcmUINT64_TO_PTR(record->info.u.FreeVirtualCommandBuffer.logical)
+ ));
+ gcmRELEASE_NAME(record->info.u.FreeVirtualCommandBuffer.physical);
+ break;
+
+#if gcdPROCESS_ADDRESS_SPACE
+ case gcvHAL_DESTROY_MMU:
+ status = gckMMU_Destroy(gcmUINT64_TO_PTR(record->info.u.DestroyMmu.mmu));
+ break;
+#endif
+
+ case gcvHAL_COMMIT_DONE:
+ break;
+
+ default:
+ /* Invalid argument. */
+ gcmkTRACE_ZONE_N(
+ gcvLEVEL_ERROR, gcvZONE_EVENT,
+ gcmSIZEOF(record->info.command),
+ "Unknown event type: %d",
+ record->info.command
+ );
+
+ status = gcvSTATUS_INVALID_ARGUMENT;
+ break;
+ }
+
+ /* Make sure there are no errors generated. */
+ if (gcmIS_ERROR(status))
+ {
+ gcmkTRACE_ZONE_N(
+ gcvLEVEL_WARNING, gcvZONE_EVENT,
+ gcmSIZEOF(status),
+ "Event produced status: %d(%s)",
+ status, gckOS_DebugStatus2Name(status));
+ }
+
+ /* Free the event. */
+ gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record));
+
+ /* Advance to next record. */
+ record = recordNext;
+ }
+
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT,
+ "Handled interrupt 0x%x", mask);
+ }
+
+ if (IDs == 0)
+ {
+ gcmkONERROR(_TryToIdleGPU(Event));
+ }
+
+ /* End of event handling. */
+ Event->notifyState = -1;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ /* Release mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+ }
+
+ /* End of event handling. */
+ Event->notifyState = -1;
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+** gckEVENT_FreeProcess
+**
+** Free all events owned by a particular process ID.
+**
+** INPUT:
+**
+** gckEVENT Event
+** Pointer to an gckEVENT object.
+**
+** gctUINT32 ProcessID
+** Process ID of the process to be freed up.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckEVENT_FreeProcess(
+ IN gckEVENT Event,
+ IN gctUINT32 ProcessID
+ )
+{
+ gctSIZE_T i;
+ gctBOOL acquired = gcvFALSE;
+ gcsEVENT_PTR record, next;
+ gceSTATUS status;
+ gcsEVENT_PTR deleteHead, deleteTail;
+
+ gcmkHEADER_ARG("Event=0x%x ProcessID=%d", Event, ProcessID);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+
+ /* Walk through all queues. */
+ for (i = 0; i < gcmCOUNTOF(Event->queues); ++i)
+ {
+ if (Event->queues[i].head != gcvNULL)
+ {
+ /* Grab the event queue mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Event->os,
+ Event->eventQueueMutex,
+ gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Grab the mutex head. */
+ record = Event->queues[i].head;
+ Event->queues[i].head = gcvNULL;
+ Event->queues[i].tail = gcvNULL;
+ deleteHead = gcvNULL;
+ deleteTail = gcvNULL;
+
+ while (record != gcvNULL)
+ {
+ next = record->next;
+ if (record->processID == ProcessID)
+ {
+ if (deleteHead == gcvNULL)
+ {
+ deleteHead = record;
+ }
+ else
+ {
+ deleteTail->next = record;
+ }
+
+ deleteTail = record;
+ }
+ else
+ {
+ if (Event->queues[i].head == gcvNULL)
+ {
+ Event->queues[i].head = record;
+ }
+ else
+ {
+ Event->queues[i].tail->next = record;
+ }
+
+ Event->queues[i].tail = record;
+ }
+
+ record->next = gcvNULL;
+ record = next;
+ }
+
+ /* Release the mutex queue. */
+ gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+ acquired = gcvFALSE;
+
+ /* Loop through the entire list of events. */
+ for (record = deleteHead; record != gcvNULL; record = next)
+ {
+ /* Get the next event record. */
+ next = record->next;
+
+ /* Free the event record. */
+ gcmkONERROR(gckEVENT_FreeRecord(Event, record));
+ }
+ }
+ }
+
+ gcmkONERROR(_TryToIdleGPU(Event));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Release the event queue mutex. */
+ if (acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+** gckEVENT_Stop
+**
+** Stop the hardware using the End event mechanism.
+**
+** INPUT:
+**
+** gckEVENT Event
+** Pointer to an gckEVENT object.
+**
+** gctUINT32 ProcessID
+** Process ID Logical belongs.
+**
+** gctPHYS_ADDR Handle
+** Physical address handle. If gcvNULL it is video memory.
+**
+** gctPOINTER Logical
+** Logical address to flush.
+**
+** gctSIGNAL Signal
+** Pointer to the signal to trigger.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckEVENT_Stop(
+ IN gckEVENT Event,
+ IN gctUINT32 ProcessID,
+ IN gctUINT32 Handle,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Address,
+ IN gctSIGNAL Signal,
+ IN OUT gctUINT32 * waitSize
+ )
+{
+ gceSTATUS status;
+ /* gctSIZE_T waitSize;*/
+ gcsEVENT_PTR record = gcvNULL;
+ gctUINT8 id = 0xFF;
+
+ gcmkHEADER_ARG("Event=0x%x ProcessID=%u Handle=0x%x Logical=0x%x "
+ "Address=0x%x Signal=0x%x",
+ Event, ProcessID, Handle, Logical, Address, Signal);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT);
+
+ /* Submit the current event queue. */
+ gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE, gcvFALSE));
+ gcmkONERROR(gckEVENT_GetEvent(Event, gcvTRUE, &id, gcvKERNEL_PIXEL));
+
+ /* Allocate a record. */
+ gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &record));
+
+ /* Initialize the record. */
+ record->next = gcvNULL;
+ record->processID = ProcessID;
+ record->info.command = gcvHAL_SIGNAL;
+ record->info.u.Signal.signal = gcmPTR_TO_UINT64(Signal);
+#ifdef __QNXNTO__
+ record->info.u.Signal.coid = 0;
+ record->info.u.Signal.rcvid = 0;
+#endif
+ record->info.u.Signal.auxSignal = 0;
+ record->info.u.Signal.process = 0;
+
+ /* Append the record. */
+ Event->queues[id].head = record;
+
+ /* Replace last WAIT with END. */
+ gcmkONERROR(gckHARDWARE_End(
+ Event->kernel->hardware, Logical, Address, waitSize
+ ));
+
+#if USE_KERNEL_VIRTUAL_BUFFERS
+ if (Event->kernel->virtualCommandBuffer)
+ {
+ gcmkONERROR(gckKERNEL_GetGPUAddress(
+ Event->kernel,
+ Logical,
+ gcvFALSE,
+ Event->kernel->command->virtualMemory,
+ &Event->kernel->hardware->lastEnd
+ ));
+ }
+#endif
+
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ /* Flush the cache for the END. */
+ gcmkONERROR(gckOS_CacheClean(
+ Event->os,
+ ProcessID,
+ gcvNULL,
+ (gctUINT32)Handle,
+ Logical,
+ *waitSize
+ ));
+#endif
+
+ /* Wait for the signal. */
+ gcmkONERROR(gckOS_WaitSignal(Event->os, Signal, gcvFALSE, gcvINFINITE));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+static void
+_PrintRecord(
+ gcsEVENT_PTR record
+ )
+{
+ switch (record->info.command)
+ {
+ case gcvHAL_FREE_NON_PAGED_MEMORY:
+ gcmkPRINT(" gcvHAL_FREE_NON_PAGED_MEMORY");
+ break;
+
+ case gcvHAL_FREE_CONTIGUOUS_MEMORY:
+ gcmkPRINT(" gcvHAL_FREE_CONTIGUOUS_MEMORY");
+ break;
+
+ case gcvHAL_WRITE_DATA:
+ gcmkPRINT(" gcvHAL_WRITE_DATA");
+ break;
+
+ case gcvHAL_UNLOCK_VIDEO_MEMORY:
+ gcmkPRINT(" gcvHAL_UNLOCK_VIDEO_MEMORY");
+ break;
+
+ case gcvHAL_SIGNAL:
+ gcmkPRINT(" gcvHAL_SIGNAL process=%d signal=0x%x",
+ record->info.u.Signal.process,
+ record->info.u.Signal.signal);
+ break;
+
+ case gcvHAL_UNMAP_USER_MEMORY:
+ gcmkPRINT(" gcvHAL_UNMAP_USER_MEMORY");
+ break;
+
+ case gcvHAL_TIMESTAMP:
+ gcmkPRINT(" gcvHAL_TIMESTAMP");
+ break;
+
+ case gcvHAL_COMMIT_DONE:
+ gcmkPRINT(" gcvHAL_COMMIT_DONE");
+ break;
+
+ case gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER:
+ gcmkPRINT(" gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER logical=0x%08x",
+ record->info.u.FreeVirtualCommandBuffer.logical);
+ break;
+
+ case gcvHAL_DESTROY_MMU:
+ gcmkPRINT(" gcvHAL_DESTORY_MMU mmu=0x%08x",
+ gcmUINT64_TO_PTR(record->info.u.DestroyMmu.mmu));
+
+ break;
+ default:
+ gcmkPRINT(" Illegal Event %d", record->info.command);
+ break;
+ }
+}
+
+/*******************************************************************************
+** gckEVENT_Dump
+**
+** Dump record in event queue when stuck happens.
+** No protection for the event queue.
+**/
+gceSTATUS
+gckEVENT_Dump(
+ IN gckEVENT Event
+ )
+{
+ gcsEVENT_QUEUE_PTR queueHead = Event->queueHead;
+ gcsEVENT_QUEUE_PTR queue;
+ gcsEVENT_PTR record = gcvNULL;
+ gctINT i;
+#if gcdINTERRUPT_STATISTIC
+ gctINT32 pendingInterrupt;
+ gctUINT32 intrAcknowledge;
+#endif
+ gctINT32 pending;
+
+ gcmkHEADER_ARG("Event=0x%x", Event);
+
+ gcmkPRINT("**************************\n");
+ gcmkPRINT("*** EVENT STATE DUMP ***\n");
+ gcmkPRINT("**************************\n");
+
+ gcmkPRINT(" Unsumbitted Event:");
+ while(queueHead)
+ {
+ queue = queueHead;
+ record = queueHead->head;
+
+ gcmkPRINT(" [%x]:", queue);
+ while(record)
+ {
+ _PrintRecord(record);
+ record = record->next;
+ }
+
+ if (queueHead == Event->queueTail)
+ {
+ queueHead = gcvNULL;
+ }
+ else
+ {
+ queueHead = queueHead->next;
+ }
+ }
+
+ gcmkPRINT(" Untriggered Event:");
+ for (i = 0; i < gcmCOUNTOF(Event->queues); i++)
+ {
+ queue = &Event->queues[i];
+ record = queue->head;
+
+ gcmkPRINT(" [%d]:", i);
+ while(record)
+ {
+ _PrintRecord(record);
+ record = record->next;
+ }
+ }
+
+#if gcdINTERRUPT_STATISTIC
+ gckOS_AtomGet(Event->os, Event->interruptCount, &pendingInterrupt);
+ gcmkPRINT(" Number of Pending Interrupt: %d", pendingInterrupt);
+
+ if (Event->kernel->recovery == 0)
+ {
+ gckOS_ReadRegisterEx(
+ Event->os,
+ Event->kernel->core,
+ 0x10,
+ &intrAcknowledge
+ );
+
+ gcmkPRINT(" INTR_ACKNOWLEDGE=0x%x", intrAcknowledge);
+ }
+#endif
+
+ gcmkPRINT(" Notify State=%d", Event->notifyState);
+
+ gckOS_AtomGet(Event->os, Event->pending, &pending);
+
+ gcmkPRINT(" Pending=0x%x", pending);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_heap.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_heap.c
new file mode 100644
index 000000000000..5c4835abb3e0
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_heap.c
@@ -0,0 +1,892 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+/**
+** @file
+** gckHEAP object for kernel HAL layer. The heap implemented here is an arena-
+** based memory allocation. An arena-based memory heap allocates data quickly
+** from specified arenas and reduces memory fragmentation.
+**
+*/
+#include "gc_hal_kernel_precomp.h"
+
+#define _GC_OBJ_ZONE gcvZONE_HEAP
+
+/*******************************************************************************
+***** Structures ***************************************************************
+*******************************************************************************/
+#define gcdIN_USE ((gcskNODE_PTR)gcvMAXUINTPTR_T)
+
+typedef struct _gcskNODE * gcskNODE_PTR;
+typedef struct _gcskNODE
+{
+ /* Number of byets in node. */
+ gctSIZE_T bytes;
+
+ /* Pointer to next free node, or gcvNULL to mark the node as freed, or
+ ** gcdIN_USE to mark the node as used. */
+ gcskNODE_PTR next;
+
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+ /* Time stamp of allocation. */
+ gctUINT64 timeStamp;
+#endif
+}
+gcskNODE;
+
+typedef struct _gcskHEAP * gcskHEAP_PTR;
+typedef struct _gcskHEAP
+{
+ /* Linked list. */
+ gcskHEAP_PTR next;
+ gcskHEAP_PTR prev;
+
+ /* Heap size. */
+ gctSIZE_T size;
+
+ /* Free list. */
+ gcskNODE_PTR freeList;
+}
+gcskHEAP;
+
+struct _gckHEAP
+{
+ /* Object. */
+ gcsOBJECT object;
+
+ /* Pointer to a gckOS object. */
+ gckOS os;
+
+ /* Locking mutex. */
+ gctPOINTER mutex;
+
+ /* Allocation parameters. */
+ gctSIZE_T allocationSize;
+
+ /* Heap list. */
+ gcskHEAP_PTR heap;
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+ gctUINT64 timeStamp;
+#endif
+
+#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE)
+ /* Profile information. */
+ gctUINT32 allocCount;
+ gctUINT64 allocBytes;
+ gctUINT64 allocBytesMax;
+ gctUINT64 allocBytesTotal;
+ gctUINT32 heapCount;
+ gctUINT32 heapCountMax;
+ gctUINT64 heapMemory;
+ gctUINT64 heapMemoryMax;
+#endif
+};
+
+/*******************************************************************************
+***** Static Support Functions *************************************************
+*******************************************************************************/
+
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+static gctSIZE_T
+_DumpHeap(
+ IN gcskHEAP_PTR Heap
+ )
+{
+ gctPOINTER p;
+ gctSIZE_T leaked = 0;
+
+ /* Start at first node. */
+ for (p = Heap + 1;;)
+ {
+ /* Convert the pointer. */
+ gcskNODE_PTR node = (gcskNODE_PTR) p;
+
+ /* Check if this is a used node. */
+ if (node->next == gcdIN_USE)
+ {
+ /* Print the leaking node. */
+ gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_HEAP,
+ "Detected leaking: node=0x%x bytes=%lu timeStamp=%llu "
+ "(%08X %c%c%c%c)",
+ node, node->bytes, node->timeStamp,
+ ((gctUINT32_PTR) (node + 1))[0],
+ gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[0]),
+ gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[1]),
+ gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[2]),
+ gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[3]));
+
+ /* Add leaking byte count. */
+ leaked += node->bytes;
+ }
+
+ /* Test for end of heap. */
+ if (node->bytes == 0)
+ {
+ break;
+ }
+
+ else
+ {
+ /* Move to next node. */
+ p = (gctUINT8_PTR) node + node->bytes;
+ }
+ }
+
+ /* Return the number of leaked bytes. */
+ return leaked;
+}
+#endif
+
+static gceSTATUS
+_CompactKernelHeap(
+ IN gckHEAP Heap
+ )
+{
+ gcskHEAP_PTR heap, next;
+ gctPOINTER p;
+ gcskHEAP_PTR freeList = gcvNULL;
+
+ gcmkHEADER_ARG("Heap=0x%x", Heap);
+
+ /* Walk all the heaps. */
+ for (heap = Heap->heap; heap != gcvNULL; heap = next)
+ {
+ gcskNODE_PTR lastFree = gcvNULL;
+
+ /* Zero out the free list. */
+ heap->freeList = gcvNULL;
+
+ /* Start at the first node. */
+ for (p = (gctUINT8_PTR) (heap + 1);;)
+ {
+ /* Convert the pointer. */
+ gcskNODE_PTR node = (gcskNODE_PTR) p;
+
+ gcmkASSERT(p <= (gctPOINTER) ((gctUINT8_PTR) (heap + 1) + heap->size));
+
+ /* Test if this node not used. */
+ if (node->next != gcdIN_USE)
+ {
+ /* Test if this is the end of the heap. */
+ if (node->bytes == 0)
+ {
+ break;
+ }
+
+ /* Test of this is the first free node. */
+ else if (lastFree == gcvNULL)
+ {
+ /* Initialzie the free list. */
+ heap->freeList = node;
+ lastFree = node;
+ }
+
+ else
+ {
+ /* Test if this free node is contiguous with the previous
+ ** free node. */
+ if ((gctUINT8_PTR) lastFree + lastFree->bytes == p)
+ {
+ /* Just increase the size of the previous free node. */
+ lastFree->bytes += node->bytes;
+ }
+ else
+ {
+ /* Add to linked list. */
+ lastFree->next = node;
+ lastFree = node;
+ }
+ }
+ }
+
+ /* Move to next node. */
+ p = (gctUINT8_PTR) node + node->bytes;
+ }
+
+ /* Mark the end of the chain. */
+ if (lastFree != gcvNULL)
+ {
+ lastFree->next = gcvNULL;
+ }
+
+ /* Get next heap. */
+ next = heap->next;
+
+ /* Check if the entire heap is free. */
+ if ((heap->freeList != gcvNULL)
+ && (heap->freeList->bytes == heap->size - gcmSIZEOF(gcskNODE))
+ )
+ {
+ /* Remove the heap from the linked list. */
+ if (heap->prev == gcvNULL)
+ {
+ Heap->heap = next;
+ }
+ else
+ {
+ heap->prev->next = next;
+ }
+
+ if (heap->next != gcvNULL)
+ {
+ heap->next->prev = heap->prev;
+ }
+
+#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE)
+ /* Update profiling. */
+ Heap->heapCount -= 1;
+ Heap->heapMemory -= heap->size + gcmSIZEOF(gcskHEAP);
+#endif
+
+ /* Add this heap to the list of heaps that need to be freed. */
+ heap->next = freeList;
+ freeList = heap;
+ }
+ }
+
+ if (freeList != gcvNULL)
+ {
+ /* Release the mutex, remove any chance for a dead lock. */
+ gcmkVERIFY_OK(
+ gckOS_ReleaseMutex(Heap->os, Heap->mutex));
+
+ /* Free all heaps in the free list. */
+ for (heap = freeList; heap != gcvNULL; heap = next)
+ {
+ /* Get pointer to the next heap. */
+ next = heap->next;
+
+ /* Free the heap. */
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HEAP,
+ "Freeing heap 0x%x (%lu bytes)",
+ heap, heap->size + gcmSIZEOF(gcskHEAP));
+ gcmkVERIFY_OK(gckOS_FreeMemory(Heap->os, heap));
+ }
+
+ /* Acquire the mutex again. */
+ gcmkVERIFY_OK(
+ gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE));
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+***** gckHEAP API Code *********************************************************
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** gckHEAP_Construct
+**
+** Construct a new gckHEAP object.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gctSIZE_T AllocationSize
+** Minimum size per arena.
+**
+** OUTPUT:
+**
+** gckHEAP * Heap
+** Pointer to a variable that will hold the pointer to the gckHEAP
+** object.
+*/
+gceSTATUS
+gckHEAP_Construct(
+ IN gckOS Os,
+ IN gctSIZE_T AllocationSize,
+ OUT gckHEAP * Heap
+ )
+{
+ gceSTATUS status;
+ gckHEAP heap = gcvNULL;
+ gctPOINTER pointer = gcvNULL;
+
+ gcmkHEADER_ARG("Os=0x%x AllocationSize=%lu", Os, AllocationSize);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Heap != gcvNULL);
+
+ /* Allocate the gckHEAP object. */
+ gcmkONERROR(gckOS_AllocateMemory(Os,
+ gcmSIZEOF(struct _gckHEAP),
+ &pointer));
+
+ heap = pointer;
+
+ /* Initialize the gckHEAP object. */
+ heap->object.type = gcvOBJ_HEAP;
+ heap->os = Os;
+ heap->allocationSize = AllocationSize;
+ heap->heap = gcvNULL;
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+ heap->timeStamp = 0;
+#endif
+
+#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE)
+ /* Zero the counters. */
+ heap->allocCount = 0;
+ heap->allocBytes = 0;
+ heap->allocBytesMax = 0;
+ heap->allocBytesTotal = 0;
+ heap->heapCount = 0;
+ heap->heapCountMax = 0;
+ heap->heapMemory = 0;
+ heap->heapMemoryMax = 0;
+#endif
+
+ /* Create the mutex. */
+ gcmkONERROR(gckOS_CreateMutex(Os, &heap->mutex));
+
+ /* Return the pointer to the gckHEAP object. */
+ *Heap = heap;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Heap=0x%x", *Heap);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Roll back. */
+ if (heap != gcvNULL)
+ {
+ /* Free the heap structure. */
+ gcmkVERIFY_OK(gckOS_FreeMemory(Os, heap));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHEAP_Destroy
+**
+** Destroy a gckHEAP object.
+**
+** INPUT:
+**
+** gckHEAP Heap
+** Pointer to a gckHEAP object to destroy.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckHEAP_Destroy(
+ IN gckHEAP Heap
+ )
+{
+ gcskHEAP_PTR heap;
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+ gctSIZE_T leaked = 0;
+#endif
+
+ gcmkHEADER_ARG("Heap=0x%x", Heap);
+
+ for (heap = Heap->heap; heap != gcvNULL; heap = Heap->heap)
+ {
+ /* Unlink heap from linked list. */
+ Heap->heap = heap->next;
+
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+ /* Check for leaked memory. */
+ leaked += _DumpHeap(heap);
+#endif
+
+ /* Free the heap. */
+ gcmkVERIFY_OK(gckOS_FreeMemory(Heap->os, heap));
+ }
+
+ /* Free the mutex. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Heap->os, Heap->mutex));
+
+ /* Free the heap structure. */
+ gcmkVERIFY_OK(gckOS_FreeMemory(Heap->os, Heap));
+
+ /* Success. */
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+ gcmkFOOTER_ARG("leaked=%lu", leaked);
+#else
+ gcmkFOOTER_NO();
+#endif
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckHEAP_Allocate
+**
+** Allocate data from the heap.
+**
+** INPUT:
+**
+** gckHEAP Heap
+** Pointer to a gckHEAP object.
+**
+** IN gctSIZE_T Bytes
+** Number of byte to allocate.
+**
+** OUTPUT:
+**
+** gctPOINTER * Memory
+** Pointer to a variable that will hold the address of the allocated
+** memory.
+*/
+gceSTATUS
+gckHEAP_Allocate(
+ IN gckHEAP Heap,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Memory
+ )
+{
+ gctBOOL acquired = gcvFALSE;
+ gcskHEAP_PTR heap;
+ gceSTATUS status;
+ gctSIZE_T bytes;
+ gcskNODE_PTR node, used, prevFree = gcvNULL;
+ gctPOINTER memory = gcvNULL;
+
+ gcmkHEADER_ARG("Heap=0x%x Bytes=%lu", Heap, Bytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
+
+ /* Determine number of bytes required for a node. */
+ bytes = gcmALIGN(Bytes + gcmSIZEOF(gcskNODE), 8);
+
+ /* Acquire the mutex. */
+ gcmkONERROR(
+ gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE));
+
+ acquired = gcvTRUE;
+
+ /* Check if this allocation is bigger than the default allocation size. */
+ if (bytes > Heap->allocationSize - gcmSIZEOF(gcskHEAP) - gcmSIZEOF(gcskNODE))
+ {
+ /* Adjust allocation size. */
+ Heap->allocationSize = bytes * 2;
+ }
+
+ else if (Heap->heap != gcvNULL)
+ {
+ gctINT i;
+
+ /* 2 retries, since we might need to compact. */
+ for (i = 0; i < 2; ++i)
+ {
+ /* Walk all the heaps. */
+ for (heap = Heap->heap; heap != gcvNULL; heap = heap->next)
+ {
+ /* Check if this heap has enough bytes to hold the request. */
+ if (bytes <= heap->size - gcmSIZEOF(gcskNODE))
+ {
+ prevFree = gcvNULL;
+
+ /* Walk the chain of free nodes. */
+ for (node = heap->freeList;
+ node != gcvNULL;
+ node = node->next
+ )
+ {
+ gcmkASSERT(node->next != gcdIN_USE);
+
+ /* Check if this free node has enough bytes. */
+ if (node->bytes >= bytes)
+ {
+ /* Use the node. */
+ goto UseNode;
+ }
+
+ /* Save current free node for linked list management. */
+ prevFree = node;
+ }
+ }
+ }
+
+ if (i == 0)
+ {
+ /* Compact the heap. */
+ gcmkVERIFY_OK(_CompactKernelHeap(Heap));
+
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+ "===== KERNEL HEAP =====");
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+ "Number of allocations : %12u",
+ Heap->allocCount);
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+ "Number of bytes allocated : %12llu",
+ Heap->allocBytes);
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+ "Maximum allocation size : %12llu",
+ Heap->allocBytesMax);
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+ "Total number of bytes allocated : %12llu",
+ Heap->allocBytesTotal);
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+ "Number of heaps : %12u",
+ Heap->heapCount);
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+ "Heap memory in bytes : %12llu",
+ Heap->heapMemory);
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+ "Maximum number of heaps : %12u",
+ Heap->heapCountMax);
+ gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP,
+ "Maximum heap memory in bytes : %12llu",
+ Heap->heapMemoryMax);
+#endif
+ }
+ }
+ }
+
+ /* Release the mutex. */
+ gcmkONERROR(
+ gckOS_ReleaseMutex(Heap->os, Heap->mutex));
+
+ acquired = gcvFALSE;
+
+ /* Allocate a new heap. */
+ gcmkONERROR(
+ gckOS_AllocateMemory(Heap->os,
+ Heap->allocationSize,
+ &memory));
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HEAP,
+ "Allocated heap 0x%x (%lu bytes)",
+ memory, Heap->allocationSize);
+
+ /* Acquire the mutex. */
+ gcmkONERROR(
+ gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE));
+
+ acquired = gcvTRUE;
+
+ /* Use the allocated memory as the heap. */
+ heap = (gcskHEAP_PTR) memory;
+
+ /* Insert this heap to the head of the chain. */
+ heap->next = Heap->heap;
+ heap->prev = gcvNULL;
+ heap->size = Heap->allocationSize - gcmSIZEOF(gcskHEAP);
+
+ if (heap->next != gcvNULL)
+ {
+ heap->next->prev = heap;
+ }
+ Heap->heap = heap;
+
+ /* Mark the end of the heap. */
+ node = (gcskNODE_PTR) ( (gctUINT8_PTR) heap
+ + Heap->allocationSize
+ - gcmSIZEOF(gcskNODE)
+ );
+ node->bytes = 0;
+ node->next = gcvNULL;
+
+ /* Create a free list. */
+ node = (gcskNODE_PTR) (heap + 1);
+ heap->freeList = node;
+
+ /* Initialize the free list. */
+ node->bytes = heap->size - gcmSIZEOF(gcskNODE);
+ node->next = gcvNULL;
+
+ /* No previous free. */
+ prevFree = gcvNULL;
+
+#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE)
+ /* Update profiling. */
+ Heap->heapCount += 1;
+ Heap->heapMemory += Heap->allocationSize;
+
+ if (Heap->heapCount > Heap->heapCountMax)
+ {
+ Heap->heapCountMax = Heap->heapCount;
+ }
+ if (Heap->heapMemory > Heap->heapMemoryMax)
+ {
+ Heap->heapMemoryMax = Heap->heapMemory;
+ }
+#endif
+
+UseNode:
+ /* Verify some stuff. */
+ gcmkASSERT(heap != gcvNULL);
+ gcmkASSERT(node != gcvNULL);
+ gcmkASSERT(node->bytes >= bytes);
+
+ if (heap->prev != gcvNULL)
+ {
+ /* Unlink the heap from the linked list. */
+ heap->prev->next = heap->next;
+ if (heap->next != gcvNULL)
+ {
+ heap->next->prev = heap->prev;
+ }
+
+ /* Move the heap to the front of the list. */
+ heap->next = Heap->heap;
+ heap->prev = gcvNULL;
+ Heap->heap = heap;
+ heap->next->prev = heap;
+ }
+
+ /* Check if there is enough free space left after usage for another free
+ ** node. */
+ if (node->bytes - bytes >= gcmSIZEOF(gcskNODE))
+ {
+ /* Allocated used space from the back of the free list. */
+ used = (gcskNODE_PTR) ((gctUINT8_PTR) node + node->bytes - bytes);
+
+ /* Adjust the number of free bytes. */
+ node->bytes -= bytes;
+ gcmkASSERT(node->bytes >= gcmSIZEOF(gcskNODE));
+ }
+ else
+ {
+ /* Remove this free list from the chain. */
+ if (prevFree == gcvNULL)
+ {
+ heap->freeList = node->next;
+ }
+ else
+ {
+ prevFree->next = node->next;
+ }
+
+ /* Consume the entire free node. */
+ used = (gcskNODE_PTR) node;
+ bytes = node->bytes;
+ }
+
+ /* Mark node as used. */
+ used->bytes = bytes;
+ used->next = gcdIN_USE;
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+ used->timeStamp = ++Heap->timeStamp;
+#endif
+
+#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE)
+ /* Update profile counters. */
+ Heap->allocCount += 1;
+ Heap->allocBytes += bytes;
+ Heap->allocBytesMax = gcmMAX(Heap->allocBytes, Heap->allocBytesMax);
+ Heap->allocBytesTotal += bytes;
+#endif
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(
+ gckOS_ReleaseMutex(Heap->os, Heap->mutex));
+
+ /* Return pointer to memory. */
+ *Memory = used + 1;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Memory=0x%x", *Memory);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ /* Release the mutex. */
+ gcmkVERIFY_OK(
+ gckOS_ReleaseMutex(Heap->os, Heap->mutex));
+ }
+
+ if (memory != gcvNULL)
+ {
+ /* Free the heap memory. */
+ gckOS_FreeMemory(Heap->os, memory);
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckHEAP_Free
+**
+** Free allocated memory from the heap.
+**
+** INPUT:
+**
+** gckHEAP Heap
+** Pointer to a gckHEAP object.
+**
+** IN gctPOINTER Memory
+** Pointer to memory to free.
+**
+** OUTPUT:
+**
+** NOTHING.
+*/
+gceSTATUS
+gckHEAP_Free(
+ IN gckHEAP Heap,
+ IN gctPOINTER Memory
+ )
+{
+ gcskNODE_PTR node;
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Heap=0x%x Memory=0x%x", Heap, Memory);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP);
+ gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
+
+ /* Acquire the mutex. */
+ gcmkONERROR(
+ gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE));
+
+ /* Pointer to structure. */
+ node = (gcskNODE_PTR) Memory - 1;
+
+ /* Mark the node as freed. */
+ node->next = gcvNULL;
+
+#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE)
+ /* Update profile counters. */
+ Heap->allocBytes -= node->bytes;
+#endif
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(
+ gckOS_ReleaseMutex(Heap->os, Heap->mutex));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+#if VIVANTE_PROFILER
+gceSTATUS
+gckHEAP_ProfileStart(
+ IN gckHEAP Heap
+ )
+{
+ gcmkHEADER_ARG("Heap=0x%x", Heap);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP);
+
+ /* Zero the counters. */
+ Heap->allocCount = 0;
+ Heap->allocBytes = 0;
+ Heap->allocBytesMax = 0;
+ Heap->allocBytesTotal = 0;
+ Heap->heapCount = 0;
+ Heap->heapCountMax = 0;
+ Heap->heapMemory = 0;
+ Heap->heapMemoryMax = 0;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckHEAP_ProfileEnd(
+ IN gckHEAP Heap,
+ IN gctCONST_STRING Title
+ )
+{
+ gcmkHEADER_ARG("Heap=0x%x Title=0x%x", Heap, Title);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP);
+ gcmkVERIFY_ARGUMENT(Title != gcvNULL);
+
+ gcmkPRINT("");
+ gcmkPRINT("=====[ HEAP - %s ]=====", Title);
+ gcmkPRINT("Number of allocations : %12u", Heap->allocCount);
+ gcmkPRINT("Number of bytes allocated : %12llu", Heap->allocBytes);
+ gcmkPRINT("Maximum allocation size : %12llu", Heap->allocBytesMax);
+ gcmkPRINT("Total number of bytes allocated : %12llu", Heap->allocBytesTotal);
+ gcmkPRINT("Number of heaps : %12u", Heap->heapCount);
+ gcmkPRINT("Heap memory in bytes : %12llu", Heap->heapMemory);
+ gcmkPRINT("Maximum number of heaps : %12u", Heap->heapCountMax);
+ gcmkPRINT("Maximum heap memory in bytes : %12llu", Heap->heapMemoryMax);
+ gcmkPRINT("==============================================");
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+#endif /* VIVANTE_PROFILER */
+
+/*******************************************************************************
+***** Test Code ****************************************************************
+*******************************************************************************/
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_interrupt_vg.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_interrupt_vg.c
new file mode 100644
index 000000000000..057fad6b559d
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_interrupt_vg.c
@@ -0,0 +1,911 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#if gcdENABLE_VG
+
+/******************************************************************************\
+*********************** Support Functions and Definitions **********************
+\******************************************************************************/
+
+/* Interruot statistics will be accumulated if not zero. */
+#define gcmENABLE_INTERRUPT_STATISTICS 0
+
+#define _GC_OBJ_ZONE gcvZONE_INTERRUPT
+
+/* Object structure. */
+struct _gckVGINTERRUPT
+{
+ /* Object. */
+ gcsOBJECT object;
+
+ /* gckVGKERNEL pointer. */
+ gckVGKERNEL kernel;
+
+ /* gckOS pointer. */
+ gckOS os;
+
+ /* Interrupt handlers. */
+ gctINTERRUPT_HANDLER handlers[32];
+
+ /* Main interrupt handler thread. */
+ gctTHREAD handler;
+ gctBOOL terminate;
+
+ /* Interrupt FIFO. */
+ gctSEMAPHORE fifoValid;
+ gctUINT32 fifo[256];
+ gctUINT fifoItems;
+ gctUINT8 head;
+ gctUINT8 tail;
+
+ /* Interrupt statistics. */
+#if gcmENABLE_INTERRUPT_STATISTICS
+ gctUINT maxFifoItems;
+ gctUINT fifoOverflow;
+ gctUINT maxSimultaneous;
+ gctUINT multipleCount;
+#endif
+};
+
+
+/*******************************************************************************
+**
+** _ProcessInterrupt
+**
+** The interrupt processor.
+**
+** INPUT:
+**
+** ThreadParameter
+** Pointer to the gckVGINTERRUPT object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+#if gcmENABLE_INTERRUPT_STATISTICS
+static void
+_ProcessInterrupt(
+ gckVGINTERRUPT Interrupt,
+ gctUINT_PTR TriggeredCount
+ )
+#else
+static void
+_ProcessInterrupt(
+ gckVGINTERRUPT Interrupt
+ )
+#endif
+{
+ gceSTATUS status;
+ gctUINT32 triggered;
+ gctUINT i;
+
+ /* Advance to the next entry. */
+ Interrupt->tail += 1;
+ Interrupt->fifoItems -= 1;
+
+ /* Get the interrupt value. */
+ triggered = Interrupt->fifo[Interrupt->tail];
+ gcmkASSERT(triggered != 0);
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ "%s: triggered=0x%08X\n",
+ __FUNCTION__,
+ triggered
+ );
+
+ /* Walk through all possible interrupts. */
+ for (i = 0; i < gcmSIZEOF(Interrupt->handlers); i += 1)
+ {
+ /* Test if interrupt happened. */
+ if ((triggered & 1) == 1)
+ {
+#if gcmENABLE_INTERRUPT_STATISTICS
+ if (TriggeredCount != gcvNULL)
+ {
+ (* TriggeredCount) += 1;
+ }
+#endif
+
+ /* Make sure we have valid handler. */
+ if (Interrupt->handlers[i] == gcvNULL)
+ {
+ gcmkTRACE(
+ gcvLEVEL_ERROR,
+ "%s: Interrupt %d isn't registered.\n",
+ __FUNCTION__, i
+ );
+ }
+ else
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ "%s: interrupt=%d\n",
+ __FUNCTION__,
+ i
+ );
+
+ /* Call the handler. */
+ status = Interrupt->handlers[i] (Interrupt->kernel);
+
+ if (gcmkIS_ERROR(status))
+ {
+ /* Failed to signal the semaphore. */
+ gcmkTRACE(
+ gcvLEVEL_ERROR,
+ "%s: Error %d incrementing the semaphore #%d.\n",
+ __FUNCTION__, status, i
+ );
+ }
+ }
+ }
+
+ /* Next interrupt. */
+ triggered >>= 1;
+
+ /* No more interrupts to handle? */
+ if (triggered == 0)
+ {
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** _MainInterruptHandler
+**
+** The main interrupt thread serves the interrupt FIFO and calls registered
+** handlers for the interrupts that occured. The handlers are called in the
+** sequence interrupts occured with the exception when multiple interrupts
+** occured at the same time. In that case the handler calls are "sorted" by
+** the interrupt number therefore giving the interrupts with lower numbers
+** higher priority.
+**
+** INPUT:
+**
+** ThreadParameter
+** Pointer to the gckVGINTERRUPT object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+static gctTHREADFUNCRESULT gctTHREADFUNCTYPE
+_MainInterruptHandler(
+ gctTHREADFUNCPARAMETER ThreadParameter
+ )
+{
+ gceSTATUS status;
+ gckVGINTERRUPT interrupt;
+
+#if gcmENABLE_INTERRUPT_STATISTICS
+ gctUINT count;
+#endif
+
+ /* Cast the object. */
+ interrupt = (gckVGINTERRUPT) ThreadParameter;
+
+ /* Enter the loop. */
+ while (gcvTRUE)
+ {
+ /* Wait for an interrupt. */
+ status = gckOS_DecrementSemaphore(interrupt->os, interrupt->fifoValid);
+
+ /* Error? */
+ if (gcmkIS_ERROR(status))
+ {
+ break;
+ }
+
+ /* System termination request? */
+ if (status == gcvSTATUS_TERMINATE)
+ {
+ break;
+ }
+
+ /* Driver is shutting down? */
+ if (interrupt->terminate)
+ {
+ break;
+ }
+
+#if gcmENABLE_INTERRUPT_STATISTICS
+ /* Reset triggered count. */
+ count = 0;
+
+ /* Process the interrupt. */
+ _ProcessInterrupt(interrupt, &count);
+
+ /* Update conters. */
+ if (count > interrupt->maxSimultaneous)
+ {
+ interrupt->maxSimultaneous = count;
+ }
+
+ if (count > 1)
+ {
+ interrupt->multipleCount += 1;
+ }
+#else
+ /* Process the interrupt. */
+ _ProcessInterrupt(interrupt);
+#endif
+ }
+
+ return 0;
+}
+
+
+/*******************************************************************************
+**
+** _StartInterruptHandler / _StopInterruptHandler
+**
+** Main interrupt handler routine control.
+**
+** INPUT:
+**
+** ThreadParameter
+** Pointer to the gckVGINTERRUPT object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+static gceSTATUS
+_StartInterruptHandler(
+ gckVGINTERRUPT Interrupt
+ )
+{
+ gceSTATUS status, last;
+
+ do
+ {
+ /* Objects must not be already created. */
+ gcmkASSERT(Interrupt->fifoValid == gcvNULL);
+ gcmkASSERT(Interrupt->handler == gcvNULL);
+
+ /* Reset the termination request. */
+ Interrupt->terminate = gcvFALSE;
+
+#if !gcdENABLE_INFINITE_SPEED_HW
+ /* Construct the fifo semaphore. */
+ gcmkERR_BREAK(gckOS_CreateSemaphoreVG(
+ Interrupt->os, &Interrupt->fifoValid
+ ));
+
+ /* Start the interrupt handler thread. */
+ gcmkERR_BREAK(gckOS_StartThread(
+ Interrupt->os,
+ _MainInterruptHandler,
+ Interrupt,
+ &Interrupt->handler
+ ));
+#endif
+
+ /* Success. */
+ return gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ /* Roll back. */
+ if (Interrupt->fifoValid != gcvNULL)
+ {
+ gcmkCHECK_STATUS(gckOS_DestroySemaphore(
+ Interrupt->os, Interrupt->fifoValid
+ ));
+
+ Interrupt->fifoValid = gcvNULL;
+ }
+
+ /* Return the status. */
+ return status;
+}
+
+static gceSTATUS
+_StopInterruptHandler(
+ gckVGINTERRUPT Interrupt
+ )
+{
+ gceSTATUS status;
+
+ do
+ {
+ /* Does the thread exist? */
+ if (Interrupt->handler == gcvNULL)
+ {
+ /* The semaphore must be NULL as well. */
+ gcmkASSERT(Interrupt->fifoValid == gcvNULL);
+
+ /* Success. */
+ status = gcvSTATUS_OK;
+ break;
+ }
+
+ /* The semaphore must exist as well. */
+ gcmkASSERT(Interrupt->fifoValid != gcvNULL);
+
+ /* Set the termination request. */
+ Interrupt->terminate = gcvTRUE;
+
+ /* Unlock the thread. */
+ gcmkERR_BREAK(gckOS_IncrementSemaphore(
+ Interrupt->os, Interrupt->fifoValid
+ ));
+
+ /* Wait until the thread quits. */
+ gcmkERR_BREAK(gckOS_StopThread(
+ Interrupt->os,
+ Interrupt->handler
+ ));
+
+ /* Destroy the semaphore. */
+ gcmkERR_BREAK(gckOS_DestroySemaphore(
+ Interrupt->os, Interrupt->fifoValid
+ ));
+
+ /* Reset handles. */
+ Interrupt->handler = gcvNULL;
+ Interrupt->fifoValid = gcvNULL;
+ }
+ while (gcvFALSE);
+
+ /* Return the status. */
+ return status;
+}
+
+
+/******************************************************************************\
+***************************** Interrupt Object API *****************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+** gckVGINTERRUPT_Construct
+**
+** Construct an interrupt object.
+**
+** INPUT:
+**
+** Kernel
+** Pointer to the gckVGKERNEL object.
+**
+** OUTPUT:
+**
+** Interrupt
+** Pointer to the new gckVGINTERRUPT object.
+*/
+
+gceSTATUS
+gckVGINTERRUPT_Construct(
+ IN gckVGKERNEL Kernel,
+ OUT gckVGINTERRUPT * Interrupt
+ )
+{
+ gceSTATUS status;
+ gckVGINTERRUPT interrupt = gcvNULL;
+
+ gcmkHEADER_ARG("Kernel=0x%x Interrupt=0x%x", Kernel, Interrupt);
+
+ /* Verify argeuments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Interrupt != gcvNULL);
+
+ do
+ {
+ /* Allocate the gckVGINTERRUPT structure. */
+ gcmkERR_BREAK(gckOS_Allocate(
+ Kernel->os,
+ gcmSIZEOF(struct _gckVGINTERRUPT),
+ (gctPOINTER *) &interrupt
+ ));
+
+ /* Reset the object data. */
+ gcmkVERIFY_OK(gckOS_ZeroMemory(
+ interrupt, gcmSIZEOF(struct _gckVGINTERRUPT)
+ ));
+
+ /* Initialize the object. */
+ interrupt->object.type = gcvOBJ_INTERRUPT;
+
+ /* Initialize the object pointers. */
+ interrupt->kernel = Kernel;
+ interrupt->os = Kernel->os;
+
+ /* Initialize the current FIFO position. */
+ interrupt->head = (gctUINT8)~0;
+ interrupt->tail = (gctUINT8)~0;
+
+ /* Start the thread. */
+ gcmkERR_BREAK(_StartInterruptHandler(interrupt));
+
+ /* Return interrupt object. */
+ *Interrupt = interrupt;
+
+ gcmkFOOTER_ARG("*Interrup=0x%x", *Interrupt);
+ /* Success. */
+ return gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ /* Roll back. */
+ if (interrupt != gcvNULL)
+ {
+ /* Free the gckVGINTERRUPT structure. */
+ gcmkVERIFY_OK(gckOS_Free(interrupt->os, interrupt));
+ }
+
+ gcmkFOOTER();
+
+ /* Return the status. */
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** gckVGINTERRUPT_Destroy
+**
+** Destroy an interrupt object.
+**
+** INPUT:
+**
+** Interrupt
+** Pointer to the gckVGINTERRUPT object to destroy.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+gceSTATUS
+gckVGINTERRUPT_Destroy(
+ IN gckVGINTERRUPT Interrupt
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Interrupt=0x%x", Interrupt);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT);
+
+ do
+ {
+ /* Stop the interrupt thread. */
+ gcmkERR_BREAK(_StopInterruptHandler(Interrupt));
+
+ /* Mark the object as unknown. */
+ Interrupt->object.type = gcvOBJ_UNKNOWN;
+
+ /* Free the gckVGINTERRUPT structure. */
+ gcmkERR_BREAK(gckOS_Free(Interrupt->os, Interrupt));
+ }
+ while (gcvFALSE);
+
+ gcmkFOOTER();
+
+ /* Return the status. */
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** gckVGINTERRUPT_DumpState
+**
+** Print the current state of the interrupt manager.
+**
+** INPUT:
+**
+** Interrupt
+** Pointer to a gckVGINTERRUPT object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+#if gcvDEBUG
+gceSTATUS
+gckVGINTERRUPT_DumpState(
+ IN gckVGINTERRUPT Interrupt
+ )
+{
+ gcmkHEADER_ARG("Interrupt=0x%x", Interrupt);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT);
+
+ /* Print the header. */
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ "%s: INTERRUPT OBJECT STATUS\n",
+ __FUNCTION__
+ );
+
+ /* Print statistics. */
+#if gcmENABLE_INTERRUPT_STATISTICS
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ " Maximum number of FIFO items accumulated at a single time: %d\n",
+ Interrupt->maxFifoItems
+ );
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ " Interrupt FIFO overflow happened times: %d\n",
+ Interrupt->fifoOverflow
+ );
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ " Maximum number of interrupts simultaneously generated: %d\n",
+ Interrupt->maxSimultaneous
+ );
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ " Number of times when there were multiple interrupts generated: %d\n",
+ Interrupt->multipleCount
+ );
+#endif
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ " The current number of entries in the FIFO: %d\n",
+ Interrupt->fifoItems
+ );
+
+ /* Print the FIFO contents. */
+ if (Interrupt->fifoItems != 0)
+ {
+ gctUINT8 index;
+ gctUINT8 last;
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ " FIFO current contents:\n"
+ );
+
+ /* Get the current pointers. */
+ index = Interrupt->tail;
+ last = Interrupt->head;
+
+ while (index != last)
+ {
+ /* Advance to the next entry. */
+ index += 1;
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_VERBOSE, gcvZONE_COMMAND,
+ " %d: 0x%08X\n",
+ index, Interrupt->fifo[index]
+ );
+ }
+ }
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+#endif
+
+
+/*******************************************************************************
+**
+** gckVGINTERRUPT_Enable
+**
+** Enable the specified interrupt.
+**
+** INPUT:
+**
+** Interrupt
+** Pointer to a gckVGINTERRUPT object.
+**
+** Id
+** Pointer to the variable that holds the interrupt number to be
+** registered in range 0..31.
+** If the value is less then 0, gckVGINTERRUPT_Enable will attempt
+** to find an unused interrupt. If such interrupt is found, the number
+** will be assigned to the variable if the functuion call succeedes.
+**
+** Handler
+** Pointer to the handler to register for the interrupt.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+gceSTATUS
+gckVGINTERRUPT_Enable(
+ IN gckVGINTERRUPT Interrupt,
+ IN OUT gctINT32_PTR Id,
+ IN gctINTERRUPT_HANDLER Handler
+ )
+{
+ gceSTATUS status;
+ gctINT32 i;
+
+ gcmkHEADER_ARG("Interrupt=0x%x Id=0x%x Handler=0x%x", Interrupt, Id, Handler);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT);
+ gcmkVERIFY_ARGUMENT(Id != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Handler != gcvNULL);
+
+ do
+ {
+ /* See if we need to allocate an ID. */
+ if (*Id < 0)
+ {
+ /* Find the first unused interrupt handler. */
+ for (i = 0; i < gcmCOUNTOF(Interrupt->handlers); ++i)
+ {
+ if (Interrupt->handlers[i] == gcvNULL)
+ {
+ break;
+ }
+ }
+
+ /* No unused innterrupts? */
+ if (i == gcmCOUNTOF(Interrupt->handlers))
+ {
+ status = gcvSTATUS_OUT_OF_RESOURCES;
+ break;
+ }
+
+ /* Update the interrupt ID. */
+ *Id = i;
+ }
+
+ /* Make sure the ID is in range. */
+ else if (*Id >= gcmCOUNTOF(Interrupt->handlers))
+ {
+ status = gcvSTATUS_INVALID_ARGUMENT;
+ break;
+ }
+
+ /* Set interrupt handler. */
+ Interrupt->handlers[*Id] = Handler;
+
+ /* Success. */
+ status = gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ gcmkFOOTER();
+ /* Return the status. */
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** gckVGINTERRUPT_Disable
+**
+** Disable the specified interrupt.
+**
+** INPUT:
+**
+** Interrupt
+** Pointer to a gckVGINTERRUPT object.
+**
+** Id
+** Interrupt number to be disabled in range 0..31.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+gceSTATUS
+gckVGINTERRUPT_Disable(
+ IN gckVGINTERRUPT Interrupt,
+ IN gctINT32 Id
+ )
+{
+ gcmkHEADER_ARG("Interrupt=0x%x Id=0x%x", Interrupt, Id);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT);
+ gcmkVERIFY_ARGUMENT((Id >= 0) && (Id < gcmCOUNTOF(Interrupt->handlers)));
+
+ /* Reset interrupt handler. */
+ Interrupt->handlers[Id] = gcvNULL;
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+
+/*******************************************************************************
+**
+** gckVGINTERRUPT_Enque
+**
+** Read the interrupt status register and put the value in the interrupt FIFO.
+**
+** INPUT:
+**
+** Interrupt
+** Pointer to a gckVGINTERRUPT object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+
+#ifndef __QNXNTO__
+gceSTATUS
+gckVGINTERRUPT_Enque(
+ IN gckVGINTERRUPT Interrupt
+ )
+#else
+gceSTATUS
+gckVGINTERRUPT_Enque(
+ IN gckVGINTERRUPT Interrupt,
+ OUT gckOS *Os,
+ OUT gctSEMAPHORE *Semaphore
+ )
+#endif
+{
+ gceSTATUS status;
+ gctUINT32 triggered;
+
+ gcmkHEADER_ARG("Interrupt=0x%x", Interrupt);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT);
+
+#ifdef __QNXNTO__
+ *Os = gcvNULL;
+ *Semaphore = gcvNULL;
+#endif
+
+ do
+ {
+ /* Read interrupt status register. */
+ gcmkERR_BREAK(gckVGHARDWARE_ReadInterrupt(
+ Interrupt->kernel->hardware, &triggered
+ ));
+
+ /* Mask out TS overflow interrupt */
+ triggered &= 0xfffffffe;
+
+ /* No interrupts to process? */
+ if (triggered == 0)
+ {
+ status = gcvSTATUS_NOT_OUR_INTERRUPT;
+ break;
+ }
+
+ /* FIFO overflow? */
+ if (Interrupt->fifoItems == gcmCOUNTOF(Interrupt->fifo))
+ {
+#if gcmENABLE_INTERRUPT_STATISTICS
+ Interrupt->fifoOverflow += 1;
+#endif
+
+ /* OR the interrupt with the last value in the FIFO. */
+ Interrupt->fifo[Interrupt->head] |= triggered;
+
+ /* Success (kind of). */
+ status = gcvSTATUS_OK;
+ }
+ else
+ {
+ /* Advance to the next entry. */
+ Interrupt->head += 1;
+ Interrupt->fifoItems += 1;
+
+#if gcmENABLE_INTERRUPT_STATISTICS
+ if (Interrupt->fifoItems > Interrupt->maxFifoItems)
+ {
+ Interrupt->maxFifoItems = Interrupt->fifoItems;
+ }
+#endif
+
+ /* Set the new value. */
+ Interrupt->fifo[Interrupt->head] = triggered;
+
+#ifndef __QNXNTO__
+ /* Increment the FIFO semaphore. */
+ gcmkERR_BREAK(gckOS_IncrementSemaphore(
+ Interrupt->os, Interrupt->fifoValid
+ ));
+#else
+ *Os = Interrupt->os;
+ *Semaphore = Interrupt->fifoValid;
+#endif
+
+ /* Windows kills our threads prematurely when the application
+ exists. Verify here that the thread is still alive. */
+ status = gckOS_VerifyThread(Interrupt->os, Interrupt->handler);
+
+ /* Has the thread been prematurely terminated? */
+ if (status != gcvSTATUS_OK)
+ {
+ /* Process all accumulated interrupts. */
+ while (Interrupt->head != Interrupt->tail)
+ {
+#if gcmENABLE_INTERRUPT_STATISTICS
+ /* Process the interrupt. */
+ _ProcessInterrupt(Interrupt, gcvNULL);
+#else
+ /* Process the interrupt. */
+ _ProcessInterrupt(Interrupt);
+#endif
+ }
+
+ /* Set success. */
+ status = gcvSTATUS_OK;
+ }
+ }
+ }
+ while (gcvFALSE);
+
+ gcmkFOOTER();
+ /* Return status. */
+ return status;
+}
+
+#endif /* gcdENABLE_VG */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_metadata.h b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_metadata.h
new file mode 100644
index 000000000000..55dd82393099
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_metadata.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+#ifndef __gc_hal_kernel_metadata_h_
+#define __gc_hal_kernel_metadata_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Macro to combine four characters into a Charcater Code. */
+#define __FOURCC(a, b, c, d) \
+ ((uint32_t)(a) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
+
+#define VIV_VIDMEM_METADATA_MAGIC __FOURCC('v', 'i', 'v', 'm')
+
+/* Metadata for cross-device fd share with additional (ts) info. */
+typedef struct _VIV_VIDMEM_METADATA
+{
+ uint32_t magic;
+
+ int32_t ts_fd;
+ void * ts_dma_buf;
+
+ uint32_t fc_enabled;
+ uint32_t fc_value;
+ uint32_t fc_value_upper;
+
+ uint32_t compressed;
+ uint32_t compress_format;
+} _VIV_VIDMEM_METADATA;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_kernel_metadata_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu.c
new file mode 100644
index 000000000000..d78e78bd698f
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu.c
@@ -0,0 +1,2921 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#define _GC_OBJ_ZONE gcvZONE_MMU
+
+typedef enum _gceMMU_TYPE
+{
+ gcvMMU_USED = (0 << 4),
+ gcvMMU_SINGLE = (1 << 4),
+ gcvMMU_FREE = (2 << 4),
+}
+gceMMU_TYPE;
+
+#define gcmENTRY_TYPE(x) (x & 0xF0)
+
+#define gcmENTRY_COUNT(x) ((x & 0xFFFFFF00) >> 8)
+
+#define gcdMMU_TABLE_DUMP 0
+
+#define gcdVERTEX_START (128 << 10)
+
+typedef struct _gcsMMU_STLB_CHUNK *gcsMMU_STLB_CHUNK_PTR;
+
+typedef struct _gcsMMU_STLB_CHUNK
+{
+ gctPHYS_ADDR physical;
+ gctUINT32_PTR logical;
+ gctSIZE_T size;
+ gctPHYS_ADDR_T physBase;
+ gctSIZE_T pageCount;
+ gctUINT32 mtlbIndex;
+ gctUINT32 mtlbEntryNum;
+ gcsMMU_STLB_CHUNK_PTR next;
+} gcsMMU_STLB_CHUNK;
+
+#if gcdSHARED_PAGETABLE
+typedef struct _gcsSharedPageTable * gcsSharedPageTable_PTR;
+typedef struct _gcsSharedPageTable
+{
+ /* Shared gckMMU object. */
+ gckMMU mmu;
+
+ /* Hardwares which use this shared pagetable. */
+ gckHARDWARE hardwares[gcdMAX_GPU_COUNT];
+
+ /* Number of cores use this shared pagetable. */
+ gctUINT32 reference;
+}
+gcsSharedPageTable;
+
+static gcsSharedPageTable_PTR sharedPageTable = gcvNULL;
+#endif
+
+typedef struct _gcsFreeSpaceNode * gcsFreeSpaceNode_PTR;
+typedef struct _gcsFreeSpaceNode
+{
+ gctUINT32 start;
+ gctINT32 entries;
+}
+gcsFreeSpaceNode;
+
+#if gcdENDIAN_BIG
+
+# define _WritePageEntry(pageEntry, entryValue) \
+ *(gctUINT32_PTR)(pageEntry) = gcmBSWAP32((gctUINT32)(entryValue))
+
+# define _ReadPageEntry(pageEntry) \
+ gcmBSWAP32(*(gctUINT32_PTR)(pageEntry))
+
+#else
+
+# define _WritePageEntry(pageEntry, entryValue) \
+ *(gctUINT32_PTR)(pageEntry) = (gctUINT32)(entryValue)
+
+# define _ReadPageEntry(pageEntry) \
+ *(gctUINT32_PTR)(pageEntry)
+
+#endif
+
+static gceSTATUS
+_FillPageTable(
+ IN gctUINT32_PTR PageTable,
+ IN gctUINT32 PageCount,
+ IN gctUINT32 EntryValue
+)
+{
+ gctUINT i;
+
+ for (i = 0; i < PageCount; i++)
+ {
+ _WritePageEntry(PageTable + i, EntryValue);
+ }
+
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_FillMap(
+ IN gctUINT32_PTR Map,
+ IN gctUINT32 PageCount,
+ IN gctUINT32 EntryValue
+)
+{
+ gctUINT i;
+
+ for (i = 0; i < PageCount; i++)
+ {
+ Map[i] = EntryValue;
+ }
+
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_Link(
+ IN gcsADDRESS_AREA_PTR Area,
+ IN gctUINT32 Index,
+ IN gctUINT32 Next
+ )
+{
+ if (Index >= Area->pageTableEntries)
+ {
+ /* Just move heap pointer. */
+ Area->heapList = Next;
+ }
+ else
+ {
+ /* Address page table. */
+ gctUINT32_PTR map = Area->mapLogical;
+
+ /* Dispatch on node type. */
+ switch (gcmENTRY_TYPE(map[Index]))
+ {
+ case gcvMMU_SINGLE:
+ /* Set single index. */
+ map[Index] = (Next << 8) | gcvMMU_SINGLE;
+ break;
+
+ case gcvMMU_FREE:
+ /* Set index. */
+ map[Index + 1] = Next;
+ break;
+
+ default:
+ gcmkFATAL("MMU table correcupted at index %u!", Index);
+ return gcvSTATUS_HEAP_CORRUPTED;
+ }
+ }
+
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_AddFree(
+ IN gcsADDRESS_AREA_PTR Area,
+ IN gctUINT32 Index,
+ IN gctUINT32 Node,
+ IN gctUINT32 Count
+ )
+{
+ gctUINT32_PTR map = Area->mapLogical;
+
+ if (Count == 1)
+ {
+ /* Initialize a single page node. */
+ map[Node] = (~((1U<<8)-1)) | gcvMMU_SINGLE;
+ }
+ else
+ {
+ /* Initialize the node. */
+ map[Node + 0] = (Count << 8) | gcvMMU_FREE;
+ map[Node + 1] = ~0U;
+ }
+
+ /* Append the node. */
+ return _Link(Area, Index, Node);
+}
+
+static gceSTATUS
+_Collect(
+ IN gcsADDRESS_AREA_PTR Area
+ )
+{
+ gctUINT32_PTR map = Area->mapLogical;
+ gceSTATUS status;
+ gctUINT32 i, previous, start = 0, count = 0;
+
+ previous = Area->heapList = ~0U;
+ Area->freeNodes = gcvFALSE;
+
+ /* Walk the entire page table. */
+ for (i = 0; i < Area->pageTableEntries; ++i)
+ {
+ /* Dispatch based on type of page. */
+ switch (gcmENTRY_TYPE(map[i]))
+ {
+ case gcvMMU_USED:
+ /* Used page, so close any open node. */
+ if (count > 0)
+ {
+ /* Add the node. */
+ gcmkONERROR(_AddFree(Area, previous, start, count));
+
+ /* Reset the node. */
+ previous = start;
+ count = 0;
+ }
+ break;
+
+ case gcvMMU_SINGLE:
+ /* Single free node. */
+ if (count++ == 0)
+ {
+ /* Start a new node. */
+ start = i;
+ }
+ break;
+
+ case gcvMMU_FREE:
+ /* A free node. */
+ if (count == 0)
+ {
+ /* Start a new node. */
+ start = i;
+ }
+
+ /* Advance the count. */
+ count += map[i] >> 8;
+
+ /* Advance the index into the page table. */
+ i += (map[i] >> 8) - 1;
+ break;
+
+ default:
+ gcmkFATAL("MMU page table correcupted at index %u!", i);
+ return gcvSTATUS_HEAP_CORRUPTED;
+ }
+ }
+
+ /* See if we have an open node left. */
+ if (count > 0)
+ {
+ /* Add the node to the list. */
+ gcmkONERROR(_AddFree(Area, previous, start, count));
+ }
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_MMU,
+ "Performed a garbage collection of the MMU heap.");
+
+ /* Success. */
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the staus. */
+ return status;
+}
+
+static gctUINT32
+_SetPage(gctUINT32 PageAddress, gctUINT32 PageAddressExt, gctBOOL Writable)
+{
+ gctUINT32 entry = PageAddress
+ /* AddressExt */
+ | (PageAddressExt << 4)
+ /* Ignore exception */
+ | (0 << 1)
+ /* Present */
+ | (1 << 0);
+
+ if (Writable)
+ {
+ /* writable */
+ entry |= (1 << 2);
+ }
+#if gcdUSE_MMU_EXCEPTION
+ else
+ {
+ /* If this page is read only, set exception bit to make exception happens
+ ** when writing to it. */
+ entry |= gcdMMU_STLB_EXCEPTION;
+ }
+#endif
+
+ return entry;
+}
+
+static gctUINT32
+_MtlbOffset(
+ gctUINT32 Address
+ )
+{
+ return (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT;
+}
+
+gctUINT32
+_AddressToIndex(
+ IN gcsADDRESS_AREA_PTR Area,
+ IN gctUINT32 Address
+ )
+{
+ gctUINT32 mtlbOffset = (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT;
+ gctUINT32 stlbOffset = (Address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT;
+
+ return (mtlbOffset - Area->dynamicMappingStart) * gcdMMU_STLB_4K_ENTRY_NUM + stlbOffset;
+}
+
+static gctUINT32_PTR
+_StlbEntry(
+ gcsADDRESS_AREA_PTR Area,
+ gctUINT32 Address
+ )
+{
+ gctUINT32 index = _AddressToIndex(Area, Address);
+
+ return &Area->pageTableLogical[index];
+}
+
+static gceSTATUS
+_FillFlatMappingInMap(
+ gcsADDRESS_AREA_PTR Area,
+ gctUINT32 Index,
+ gctUINT32 NumPages
+ )
+{
+ gceSTATUS status;
+ gctUINT32 i;
+ gctBOOL gotIt = gcvFALSE;
+ gctUINT32 index = Index;
+ gctUINT32_PTR map = Area->mapLogical;
+ gctUINT32 previous = ~0U;
+
+ /* Find node which contains index. */
+ for (i = 0; !gotIt && (i < Area->pageTableEntries);)
+ {
+ gctUINT32 numPages;
+
+ switch (gcmENTRY_TYPE(map[i]))
+ {
+ case gcvMMU_SINGLE:
+ if (i == index)
+ {
+ gotIt = gcvTRUE;
+ }
+ else
+ {
+ previous = i;
+ i = map[i] >> 8;
+ }
+ break;
+
+ case gcvMMU_FREE:
+ numPages = map[i] >> 8;
+ if (index >= i && index + NumPages - 1 < i + numPages)
+ {
+ gotIt = gcvTRUE;
+ }
+ else
+ {
+ previous = i;
+ i = map[i + 1];
+ }
+ break;
+
+ case gcvMMU_USED:
+ i++;
+ break;
+
+ default:
+ gcmkFATAL("MMU table correcupted at index %u!", index);
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+ }
+
+ switch (gcmENTRY_TYPE(map[i]))
+ {
+ case gcvMMU_SINGLE:
+ /* Unlink single node from free list. */
+ gcmkONERROR(
+ _Link(Area, previous, map[i] >> 8));
+ break;
+
+ case gcvMMU_FREE:
+ /* Split the node. */
+ {
+ gctUINT32 start;
+ gctUINT32 next = map[i+1];
+ gctUINT32 total = map[i] >> 8;
+ gctUINT32 countLeft = index - i;
+ gctUINT32 countRight = total - countLeft - NumPages;
+
+ if (countLeft)
+ {
+ start = i;
+ _AddFree(Area, previous, start, countLeft);
+ previous = start;
+ }
+
+ if (countRight)
+ {
+ start = index + NumPages;
+ _AddFree(Area, previous, start, countRight);
+ previous = start;
+ }
+
+ _Link(Area, previous, next);
+ }
+ break;
+ }
+
+ _FillMap(&map[index], NumPages, gcvMMU_USED);
+
+ return gcvSTATUS_OK;
+OnError:
+ return status;
+}
+
+static gceSTATUS
+_CollectFreeSpace(
+ IN gckMMU Mmu,
+ OUT gcsFreeSpaceNode_PTR *Array,
+ OUT gctINT * Size
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+ gctPOINTER pointer = gcvNULL;
+ gcsFreeSpaceNode_PTR array = gcvNULL;
+ gcsFreeSpaceNode_PTR node = gcvNULL;
+ gctINT size = 0;
+ gctINT i = 0;
+
+ for (i = 0; i < gcdMMU_MTLB_ENTRY_NUM; i++)
+ {
+ if (!Mmu->mtlbLogical[i])
+ {
+ if (!node)
+ {
+ /* This is the first entry of the free space. */
+ node += 1;
+ size++;
+
+ }
+ }
+ else if (node)
+ {
+ /* Reset the start. */
+ node = gcvNULL;
+ }
+ }
+
+ /* Allocate memory for the array. */
+ gcmkONERROR(gckOS_Allocate(Mmu->os,
+ gcmSIZEOF(*array) * size,
+ &pointer));
+
+ array = (gcsFreeSpaceNode_PTR)pointer;
+ node = gcvNULL;
+
+ for (i = 0, size = 0; i < gcdMMU_MTLB_ENTRY_NUM; i++)
+ {
+ if (!Mmu->mtlbLogical[i])
+ {
+ if (!node)
+ {
+ /* This is the first entry of the free space. */
+ node = &array[size++];
+
+ node->start = i;
+ node->entries = 0;
+ }
+
+ node->entries++;
+ }
+ else if (node)
+ {
+ /* Reset the start. */
+ node = gcvNULL;
+ }
+ }
+
+#if gcdMMU_TABLE_DUMP
+ for (i = 0; i < size; i++)
+ {
+ gckOS_Print("%s(%d): [%d]: start=%d, entries=%d.\n",
+ __FUNCTION__, __LINE__,
+ i,
+ array[i].start,
+ array[i].entries);
+ }
+#endif
+
+ *Array = array;
+ *Size = size;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ if (pointer != gcvNULL)
+ {
+ gckOS_Free(Mmu->os, pointer);
+ }
+
+ return status;
+}
+
+gceSTATUS
+_GetMtlbFreeSpace(
+ IN gckMMU Mmu,
+ IN gctUINT32 NumEntries,
+ OUT gctUINT32 *MtlbStart,
+ OUT gctUINT32 *MtlbEnd
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+ gcsFreeSpaceNode_PTR nodeArray = gcvNULL;
+ gctINT i, nodeArraySize = 0;
+ gctINT numEntries = gcdMMU_MTLB_ENTRY_NUM;
+ gctINT32 mStart = -1;
+ gctINT32 mEnd = -1;
+
+ gcmkONERROR(_CollectFreeSpace(Mmu, &nodeArray, &nodeArraySize));
+
+ /* Find the smallest space for NumEntries */
+ for (i = 0; i < nodeArraySize; i++)
+ {
+ if (nodeArray[i].entries < numEntries && NumEntries <= (gctUINT32)nodeArray[i].entries)
+ {
+ numEntries = nodeArray[i].entries;
+
+ mStart = nodeArray[i].start;
+ mEnd = nodeArray[i].start + NumEntries - 1;
+ }
+ }
+
+ if (mStart == -1 && mEnd == -1)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ *MtlbStart = (gctUINT32)mStart;
+ *MtlbEnd = (gctUINT32)mEnd;
+
+OnError:
+ if (nodeArray)
+ {
+ gckOS_Free(Mmu->os, (gctPOINTER)nodeArray);
+ }
+
+ return status;
+}
+
+#if gcdPROCESS_ADDRESS_SPACE
+gctUINT32
+_StlbOffset(
+ gctUINT32 Address
+ )
+{
+ return (Address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT;
+}
+
+static gceSTATUS
+_AllocateStlb(
+ IN gckOS Os,
+ OUT gcsMMU_STLB_PTR *Stlb
+ )
+{
+ gceSTATUS status;
+ gcsMMU_STLB_PTR stlb;
+ gctPOINTER pointer;
+
+ /* Allocate slave TLB record. */
+ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsMMU_STLB), &pointer));
+ stlb = pointer;
+
+ stlb->size = gcdMMU_STLB_4K_SIZE;
+
+ /* Allocate slave TLB entries. */
+ gcmkONERROR(gckOS_AllocateContiguous(
+ Os,
+ gcvFALSE,
+ &stlb->size,
+ &stlb->physical,
+ (gctPOINTER)&stlb->logical
+ ));
+
+ gcmkONERROR(gckOS_GetPhysicalAddress(Os, stlb->logical, &stlb->physBase));
+
+#if gcdUSE_MMU_EXCEPTION
+ _FillPageTable(stlb->logical, stlb->size / 4, gcdMMU_STLB_EXCEPTION);
+#else
+ gckOS_ZeroMemory(stlb->logical, stlb->size);
+#endif
+
+ *Stlb = stlb;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+gceSTATUS
+_SetupProcessAddressSpace(
+ IN gckMMU Mmu
+ )
+{
+ gceSTATUS status;
+ gctINT numEntries = 0;
+ gctUINT32_PTR map;
+
+ numEntries = gcdPROCESS_ADDRESS_SPACE_SIZE
+ /* Address space mapped by one MTLB entry. */
+ / (1 << gcdMMU_MTLB_SHIFT);
+
+ area->dynamicMappingStart = 0;
+
+ area->pageTableSize = numEntries * 4096;
+
+ area->pageTableEntries = area->pageTableSize / gcmSIZEOF(gctUINT32);
+
+ gcmkONERROR(gckOS_Allocate(Mmu->os,
+ area->pageTableSize,
+ (void **)&area->mapLogical));
+
+ /* Initialization. */
+ map = area->mapLogical;
+ map[0] = (area->pageTableEntries << 8) | gcvMMU_FREE;
+ map[1] = ~0U;
+ area->heapList = 0;
+ area->freeNodes = gcvFALSE;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+#else
+static gceSTATUS
+_FillFlatMapping(
+ IN gckMMU Mmu,
+ IN gctUINT64 PhysBase,
+ OUT gctSIZE_T Size,
+ OUT gctUINT32 *GpuBaseAddress
+ )
+{
+ gceSTATUS status;
+ gctUINT32 mtlb;
+ gctUINT32 physBase;
+ gcsADDRESS_AREA_PTR area = &Mmu->area[0];
+
+ /************************ look up existing flat mapping ranges. ****************/
+ gctUINT64 flatBase = PhysBase;
+ gctUINT32 flatSize = (gctUINT32)Size;
+ gctUINT64 base = flatBase;
+ gctUINT32 size = flatSize;
+ gctUINT64 end = base + size;
+ gctUINT32 i;
+
+ for (i = 0; i < Mmu->flatMappingRangeCount; i++)
+ {
+ if (base < Mmu->flatMappingRanges[i].start)
+ {
+ end = gcmMIN(end, Mmu->flatMappingRanges[i].start);
+ flatSize = (gctUINT32) (end - base);
+ }
+ else if (end > Mmu->flatMappingRanges[i].end)
+ {
+ base = gcmMAX(base, Mmu->flatMappingRanges[i].end);
+
+ flatBase = base;
+ flatSize = (gctUINT32) (end - base);
+ }
+ else
+ {
+ /* it is already inside existing flat mapping ranges. */
+ flatSize = 0;
+ }
+
+ if (flatSize == 0)
+ {
+ if (GpuBaseAddress)
+ {
+ *GpuBaseAddress = (gctUINT32) PhysBase;
+ }
+
+ return gcvSTATUS_OK;
+ }
+ }
+
+ Mmu->flatMappingRanges[Mmu->flatMappingRangeCount].start = flatBase;
+ Mmu->flatMappingRanges[Mmu->flatMappingRangeCount].end = flatBase + flatSize;
+ Mmu->flatMappingRangeCount++;
+
+ gcmkASSERT(Mmu->flatMappingRangeCount <= gcdMAX_FLAT_MAPPING_COUNT);
+
+ /* overwrite the orignal parameters */
+ PhysBase = flatBase;
+ physBase = (gctUINT32)flatBase;
+ Size = (gctSIZE_T)flatSize;
+
+ mtlb = _MtlbOffset(physBase);
+
+ /************************ Setup flat mapping in dynamic range. ****************/
+
+ if (area->dynamicMappingStart != gcvINVALID_ADDRESS && mtlb >= area->dynamicMappingStart &&
+ _MtlbOffset(PhysBase + Size - 1) < area->dynamicMappingEnd)
+ {
+ gctUINT32_PTR stlbEntry;
+ gctUINT i;
+
+ stlbEntry = _StlbEntry(area, physBase);
+
+ /* Must be aligned to page. */
+ gcmkASSERT((Size & 0xFFF) == 0);
+
+ for (i = 0; i < (Size / 4096); i++)
+ {
+ /* Flat mapping in page table. */
+ _WritePageEntry(stlbEntry, _SetPage(physBase + i * 4096, 0, gcvTRUE));
+ }
+
+ gcmkSAFECASTSIZET(size, Size);
+
+ /* Flat mapping in map. */
+ _FillFlatMappingInMap(area, _AddressToIndex(area, physBase), size / 4096);
+
+ return gcvSTATUS_OK;
+ }
+
+ /************************ Setup flat mapping in non dynamic range. **************/
+ {
+ gctBOOL mutex = gcvFALSE;
+ gctUINT32 physBaseExt = (gctUINT32) (PhysBase >> 32);
+ gctUINT32 start = physBase & ~gcdMMU_PAGE_64K_MASK;
+ gctUINT32 end = (gctUINT32) (physBase + Size - 1) & ~gcdMMU_PAGE_64K_MASK;
+ gctUINT32 mStart = start >> gcdMMU_MTLB_SHIFT;
+ gctUINT32 mEnd = end >> gcdMMU_MTLB_SHIFT;
+ gctUINT32 sStart = (start & gcdMMU_STLB_64K_MASK) >> gcdMMU_STLB_64K_SHIFT;
+ gctUINT32 sEnd = (end & gcdMMU_STLB_64K_MASK) >> gcdMMU_STLB_64K_SHIFT;
+ gctPHYS_ADDR_T physical;
+ gcsMMU_STLB_CHUNK_PTR newStlbChunk = gcvNULL;
+ gctUINT32 stlbIndex = 0;
+ gctUINT32 totalNewStlbs = 0;
+ gctINT32 firstMtlbEntry = -1;
+ gctUINT32 mtlbCurEntry;
+ gcsMMU_STLB_CHUNK_PTR curStlbChunk = gcvNULL;
+ gctUINT32 seqs[2] = {0, 0};
+ gctUINT32 seqIdx = 0;
+
+ /* Grab the mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
+ mutex = gcvTRUE;
+
+ if (PhysBase + Size - 1 > 0xffffffff)
+ {
+ gctUINT32 mEntries;
+ gctUINT32 sEntries;
+
+ mEntries = (gctUINT32)(Size + (1 << gcdMMU_MTLB_SHIFT) - 1) / (1 << gcdMMU_MTLB_SHIFT);
+
+ gcmkONERROR(_GetMtlbFreeSpace(Mmu, mEntries, &mStart, &mEnd));
+
+ sStart = 0;
+ sEntries = (gctUINT32)(Size + gcdMMU_PAGE_64K_SIZE - 1) / gcdMMU_PAGE_64K_SIZE;
+ sEnd = (sEntries - 1) % gcdMMU_STLB_64K_ENTRY_NUM;
+ }
+
+ if (GpuBaseAddress)
+ {
+ *GpuBaseAddress = (mStart << gcdMMU_MTLB_SHIFT)
+ | (sStart << gcdMMU_STLB_64K_SHIFT)
+ | (physBase & gcdMMU_PAGE_64K_MASK);
+ }
+
+ mtlbCurEntry = mStart;
+
+ /* find all new stlbs, part of new flat mapping range may already have stlbs*/
+ while (mtlbCurEntry <= mEnd)
+ {
+ if (*(Mmu->mtlbLogical + mtlbCurEntry) == 0)
+ {
+ if (seqIdx < 2)
+ {
+ if (seqs[seqIdx] != 2)
+ {
+ seqs[seqIdx] = 1;
+ }
+ else if (seqIdx < 1)
+ {
+ seqs[++seqIdx] = 1;
+ }
+ else
+ {
+ gcmkASSERT(gcvFALSE);
+ }
+ }
+ else if (seqs[1] != 1)
+ {
+ gcmkPRINT("There is a hole in new flat mapping range, which is not correct");
+ }
+ totalNewStlbs++;
+ if (-1 == firstMtlbEntry)
+ {
+ firstMtlbEntry = mtlbCurEntry;
+ }
+ }
+ else
+ {
+ if (seqIdx < 2)
+ {
+ if (seqs[seqIdx] != 1)
+ {
+ seqs[seqIdx] = 2;
+ }
+ else if (seqIdx < 1)
+ {
+ seqs[++seqIdx] = 2;
+ }
+ else
+ {
+ gcmkASSERT(gcvFALSE);
+ }
+ }
+ else if (seqs[1] != 2)
+ {
+ gcmkPRINT("There is a hole in new flat mapping range, which is not correct");
+ }
+ }
+ mtlbCurEntry++;
+ }
+
+ /* Need allocate a new chunk of stlbs */
+ if (totalNewStlbs)
+ {
+ gcmkONERROR(
+ gckOS_Allocate(Mmu->os,
+ sizeof(struct _gcsMMU_STLB_CHUNK),
+ (gctPOINTER *)&newStlbChunk));
+
+ newStlbChunk->mtlbEntryNum = totalNewStlbs;
+ newStlbChunk->next = gcvNULL;
+ newStlbChunk->physical = gcvNULL;
+ newStlbChunk->logical = gcvNULL;
+ newStlbChunk->size = gcdMMU_STLB_64K_SIZE * newStlbChunk->mtlbEntryNum;
+ newStlbChunk->pageCount = 0;
+ newStlbChunk->mtlbIndex = firstMtlbEntry;
+ gcmkONERROR(
+ gckOS_AllocateContiguous(Mmu->os,
+ gcvFALSE,
+ &newStlbChunk->size,
+ &newStlbChunk->physical,
+ (gctPOINTER)&newStlbChunk->logical));
+ gcmkONERROR(gckOS_ZeroMemory(newStlbChunk->logical, newStlbChunk->size));
+
+ gcmkONERROR(gckOS_GetPhysicalAddress(
+ Mmu->os,
+ newStlbChunk->logical,
+ &physical));
+
+ gcmkSAFECASTPHYSADDRT(newStlbChunk->physBase, physical);
+
+ if (newStlbChunk->physBase & (gcdMMU_STLB_64K_SIZE - 1))
+ {
+ gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
+ }
+ }
+
+ while (mStart <= mEnd)
+ {
+ gctUINT32 last = (mStart == mEnd) ? sEnd : (gcdMMU_STLB_64K_ENTRY_NUM - 1);
+ gctPHYS_ADDR_T stlbPhyBase;
+ gctUINT32_PTR stlbLogical;
+
+ gcmkASSERT(mStart < gcdMMU_MTLB_ENTRY_NUM);
+
+ if (*(Mmu->mtlbLogical + mStart) == 0)
+ {
+ gctUINT32 mtlbEntry;
+ curStlbChunk = newStlbChunk;
+ stlbPhyBase = curStlbChunk->physBase + (stlbIndex * gcdMMU_STLB_64K_SIZE);
+ stlbLogical = (gctUINT32_PTR)((gctUINT8_PTR)curStlbChunk->logical + (stlbIndex * gcdMMU_STLB_64K_SIZE));
+ physical = stlbPhyBase
+ /* 64KB page size */
+ | (1 << 2)
+ /* Ignore exception */
+ | (0 << 1)
+ /* Present */
+ | (1 << 0);
+
+ gcmkSAFECASTPHYSADDRT(mtlbEntry, physical);
+
+ _WritePageEntry(Mmu->mtlbLogical + mStart, mtlbEntry);
+
+#if gcdMMU_TABLE_DUMP
+ gckOS_Print("%s(%d): insert MTLB[%d]: %08x\n",
+ __FUNCTION__, __LINE__,
+ mStart,
+ _ReadPageEntry(Mmu->mtlbLogical + mStart));
+#endif
+
+#if gcdMMU_TABLE_DUMP
+ gckOS_Print("%s(%d): STLB: logical:%08x -> physical:%08x\n",
+ __FUNCTION__, __LINE__,
+ stlbLogical,
+ stlbPhyBase);
+#endif
+ ++stlbIndex;
+ }
+ else
+ {
+ gctUINT32 mtlbEntry = _ReadPageEntry(Mmu->mtlbLogical + mStart);
+ gctUINT stlbOffset;
+
+ curStlbChunk = (gcsMMU_STLB_CHUNK_PTR)Mmu->staticSTLB;
+
+ while (curStlbChunk)
+ {
+ if ((mStart >= curStlbChunk->mtlbIndex) &&
+ (mStart < (curStlbChunk->mtlbIndex + curStlbChunk->mtlbEntryNum)))
+ {
+ break;
+ }
+ curStlbChunk = curStlbChunk->next;
+ }
+ gcmkASSERT(curStlbChunk);
+ stlbOffset = mStart - curStlbChunk->mtlbIndex;
+
+ stlbPhyBase = curStlbChunk->physBase + (stlbOffset * gcdMMU_STLB_64K_SIZE);
+ stlbLogical = (gctUINT32_PTR)((gctUINT8_PTR)curStlbChunk->logical + (stlbOffset * gcdMMU_STLB_64K_SIZE));
+ if (stlbPhyBase != (mtlbEntry & gcdMMU_MTLB_ENTRY_STLB_MASK))
+ {
+ gcmkASSERT(0);
+ }
+ }
+
+ while (sStart <= last)
+ {
+ gcmkASSERT(!(start & gcdMMU_PAGE_64K_MASK));
+
+ _WritePageEntry(stlbLogical + sStart, _SetPage(start, physBaseExt, gcvTRUE));
+
+#if gcdMMU_TABLE_DUMP
+ gckOS_Print("%s(%d): insert STLB[%d]: %08x\n",
+ __FUNCTION__, __LINE__,
+ sStart,
+ _ReadPageEntry(stlbLogical + sStart));
+#endif
+ /* next page. */
+ start += gcdMMU_PAGE_64K_SIZE;
+ if (start == 0)
+ {
+ physBaseExt++;
+ }
+ sStart++;
+ curStlbChunk->pageCount++;
+ }
+
+ sStart = 0;
+ ++mStart;
+ }
+
+ gcmkASSERT(totalNewStlbs == stlbIndex);
+
+ if (newStlbChunk)
+ {
+ /* Insert the stlbChunk into staticSTLB. */
+ if (Mmu->staticSTLB == gcvNULL)
+ {
+ Mmu->staticSTLB = newStlbChunk;
+ }
+ else
+ {
+ gcmkASSERT(newStlbChunk != gcvNULL);
+ gcmkASSERT(newStlbChunk->next == gcvNULL);
+ newStlbChunk->next = Mmu->staticSTLB;
+ Mmu->staticSTLB = newStlbChunk;
+ }
+ }
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+
+#if gcdENABLE_TRUST_APPLICATION
+ if (Mmu->hardware->options.secureMode == gcvSECURE_IN_TA)
+ {
+ gckKERNEL_SecurityMapMemory(Mmu->hardware->kernel, gcvNULL, physBase, (gctUINT32)Size/4096, &physBase);
+ }
+#endif
+
+ return gcvSTATUS_OK;
+OnError:
+ /* Roll back the allocation.
+ ** We don't need roll back mtlb programming as gckmONERROR
+ ** is only used during allocation time.
+ */
+ if (newStlbChunk)
+ {
+ if (newStlbChunk->physical)
+ {
+ gcmkVERIFY_OK(
+ gckOS_FreeContiguous(Mmu->os,
+ newStlbChunk->physical,
+ newStlbChunk->logical,
+ newStlbChunk->size));
+ }
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, newStlbChunk));
+ }
+ if (mutex)
+ {
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+ }
+ return status;
+ }
+}
+
+static gceSTATUS
+_SetupAddressArea(
+ IN gckOS Os,
+ IN gcsADDRESS_AREA_PTR Area,
+ IN gctUINT32 NumMTLBEntries
+ )
+{
+ gceSTATUS status;
+ gctUINT32_PTR map;
+
+ gcmkHEADER();
+ Area->pageTableSize = NumMTLBEntries * 4096;
+
+ gcmkSAFECASTSIZET(Area->pageTableEntries, Area->pageTableSize / gcmSIZEOF(gctUINT32));
+
+ gcmkONERROR(gckOS_Allocate(Os, Area->pageTableSize, (void **)&Area->mapLogical));
+
+ /* Initialization. */
+ map = Area->mapLogical;
+ map[0] = (Area->pageTableEntries << 8) | gcvMMU_FREE;
+ map[1] = ~0U;
+ Area->heapList = 0;
+ Area->freeNodes = gcvFALSE;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+_SetupDynamicSpace(
+ IN gckMMU Mmu
+ )
+{
+ gceSTATUS status;
+ gcsFreeSpaceNode_PTR nodeArray = gcvNULL;
+ gctINT i, nodeArraySize = 0;
+ gctPHYS_ADDR_T physical;
+ gctUINT32 address;
+ gctINT numEntries = 0;
+ gctBOOL acquired = gcvFALSE;
+ gctUINT32 mtlbEntry;
+ gcsADDRESS_AREA_PTR area = &Mmu->area[0];
+ gcsADDRESS_AREA_PTR areaSecure = &Mmu->area[gcvADDRESS_AREA_SECURE];
+ gctUINT32 secureAreaSize = 0;
+
+ /* Find all the free address space. */
+ gcmkONERROR(_CollectFreeSpace(Mmu, &nodeArray, &nodeArraySize));
+
+ for (i = 0; i < nodeArraySize; i++)
+ {
+ if (nodeArray[i].entries > numEntries)
+ {
+ area->dynamicMappingStart = nodeArray[i].start;
+ numEntries = nodeArray[i].entries;
+ area->dynamicMappingEnd = area->dynamicMappingStart + numEntries;
+ }
+ }
+
+ gckOS_Free(Mmu->os, (gctPOINTER)nodeArray);
+
+#if gcdENABLE_TRUST_APPLICATION
+ if (gckHARDWARE_IsFeatureAvailable(Mmu->hardware, gcvFEATURE_SECURITY) == gcvSTATUS_TRUE)
+ {
+ secureAreaSize = gcdMMU_SECURE_AREA_SIZE;
+ }
+#endif
+
+ /* Setup secure address area if need. */
+ if (secureAreaSize > 0)
+ {
+ gcmkASSERT(numEntries > (gctINT)secureAreaSize);
+
+ areaSecure->dynamicMappingStart = area->dynamicMappingStart
+ + (numEntries - secureAreaSize);
+
+ gcmkONERROR(_SetupAddressArea(Mmu->os, areaSecure, secureAreaSize));
+
+ numEntries -= secureAreaSize;
+ }
+
+ /* Setup normal address area. */
+ gcmkONERROR(_SetupAddressArea(Mmu->os, area, numEntries));
+
+ /* Construct Slave TLB. */
+ gcmkONERROR(gckOS_AllocateContiguous(Mmu->os,
+ gcvFALSE,
+ &area->pageTableSize,
+ &area->pageTablePhysical,
+ (gctPOINTER)&area->pageTableLogical));
+
+#if gcdUSE_MMU_EXCEPTION
+ gcmkONERROR(_FillPageTable(area->pageTableLogical,
+ area->pageTableEntries,
+ /* Enable exception */
+ 1 << 1));
+#else
+ /* Invalidate all entries. */
+ gcmkONERROR(gckOS_ZeroMemory(area->pageTableLogical,
+ area->pageTableSize));
+#endif
+
+ gcmkONERROR(gckOS_GetPhysicalAddress(Mmu->os,
+ area->pageTableLogical,
+ &physical));
+
+ gcmkSAFECASTPHYSADDRT(address, physical);
+
+ /* Grab the mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Map to Master TLB. */
+ for (i = (gctINT)area->dynamicMappingStart;
+ i < (gctINT)area->dynamicMappingStart + numEntries;
+ i++)
+ {
+ mtlbEntry = address
+ /* 4KB page size */
+ | (0 << 2)
+ /* Ignore exception */
+ | (0 << 1)
+ /* Present */
+ | (1 << 0);
+
+ _WritePageEntry(Mmu->mtlbLogical + i, mtlbEntry);
+
+#if gcdMMU_TABLE_DUMP
+ gckOS_Print("%s(%d): insert MTLB[%d]: %08x\n",
+ __FUNCTION__, __LINE__,
+ i,
+ _ReadPageEntry(Mmu->mtlbLogical + i));
+#endif
+ address += gcdMMU_STLB_4K_SIZE;
+ }
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+
+ return gcvSTATUS_OK;
+
+OnError:
+ if (area->mapLogical)
+ {
+ gcmkVERIFY_OK(
+ gckOS_Free(Mmu->os, (gctPOINTER) area->mapLogical));
+
+
+ gcmkVERIFY_OK(
+ gckOS_FreeContiguous(Mmu->os,
+ area->pageTablePhysical,
+ (gctPOINTER) area->pageTableLogical,
+ area->pageTableSize));
+ }
+
+ if (acquired)
+ {
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+ }
+
+ return status;
+}
+#endif
+
+gctUINT32
+_GetPageCountOfUsedNode(
+ gctUINT32_PTR Node
+ )
+{
+ gctUINT32 count;
+
+ count = gcmENTRY_COUNT(*Node);
+
+ if ((count << 8) == (~((1U<<8)-1)))
+ {
+ count = 1;
+ }
+
+ return count;
+}
+
+static gcsADDRESS_AREA_PTR
+_GetProcessArea(
+ IN gckMMU Mmu,
+ IN gctBOOL Secure
+ )
+{
+ gceADDRESS_AREA area = gcvADDRESS_AREA_NORMAL;
+
+#if gcdENABLE_TRUST_APPLICATION
+ if (Secure == gcvTRUE)
+ {
+ area = gcvADDRESS_AREA_SECURE;
+ }
+#endif
+
+ return &Mmu->area[area];
+}
+
+/*******************************************************************************
+**
+** _Construct
+**
+** Construct a new gckMMU object.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctSIZE_T MmuSize
+** Number of bytes for the page table.
+**
+** OUTPUT:
+**
+** gckMMU * Mmu
+** Pointer to a variable that receives the gckMMU object pointer.
+*/
+gceSTATUS
+_Construct(
+ IN gckKERNEL Kernel,
+ IN gctSIZE_T MmuSize,
+ OUT gckMMU * Mmu
+ )
+{
+ gckOS os;
+ gckHARDWARE hardware;
+ gceSTATUS status;
+ gckMMU mmu = gcvNULL;
+ gctUINT32_PTR map;
+ gctPOINTER pointer = gcvNULL;
+ gctUINT32 physBase;
+ gctUINT32 physSize;
+ gctUINT32 contiguousBase;
+ gctUINT32 contiguousSize = 0;
+ gctUINT32 externalBase;
+ gctUINT32 externalSize = 0;
+ gctUINT32 gpuAddress;
+ gctPHYS_ADDR_T gpuPhysical;
+ gcsADDRESS_AREA_PTR area = gcvNULL;
+
+ gcmkHEADER_ARG("Kernel=0x%x MmuSize=%lu", Kernel, MmuSize);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(MmuSize > 0);
+ gcmkVERIFY_ARGUMENT(Mmu != gcvNULL);
+
+ /* Extract the gckOS object pointer. */
+ os = Kernel->os;
+ gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+ /* Extract the gckHARDWARE object pointer. */
+ hardware = Kernel->hardware;
+ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+ /* Allocate memory for the gckMMU object. */
+ gcmkONERROR(gckOS_Allocate(os, sizeof(struct _gckMMU), &pointer));
+
+ gckOS_ZeroMemory(pointer, sizeof(struct _gckMMU));
+
+ mmu = pointer;
+
+ /* Initialize the gckMMU object. */
+ mmu->object.type = gcvOBJ_MMU;
+ mmu->os = os;
+ mmu->hardware = hardware;
+ mmu->pageTableMutex = gcvNULL;
+ mmu->mtlbLogical = gcvNULL;
+ mmu->staticSTLB = gcvNULL;
+ mmu->enabled = gcvFALSE;
+ gcsLIST_Init(&mmu->hardwareList);
+
+
+ area = &mmu->area[0];
+ area->mapLogical = gcvNULL;
+ area->pageTableLogical = gcvNULL;
+
+ /* Create the page table mutex. */
+ gcmkONERROR(gckOS_CreateMutex(os, &mmu->pageTableMutex));
+
+
+ if (hardware->mmuVersion == 0)
+ {
+ area->pageTableSize = MmuSize;
+
+ /* Construct address space management table. */
+ gcmkONERROR(gckOS_Allocate(mmu->os,
+ area->pageTableSize,
+ &pointer));
+
+ area->mapLogical = pointer;
+
+ /* Construct page table read by GPU. */
+ gcmkONERROR(gckOS_AllocateContiguous(mmu->os,
+ gcvFALSE,
+ &area->pageTableSize,
+ &area->pageTablePhysical,
+ (gctPOINTER)&area->pageTableLogical));
+
+
+ /* Compute number of entries in page table. */
+ gcmkSAFECASTSIZET(area->pageTableEntries, area->pageTableSize / sizeof(gctUINT32));
+
+ /* Mark all pages as free. */
+ map = area->mapLogical;
+
+ _FillPageTable(area->pageTableLogical, area->pageTableEntries, mmu->safeAddress);
+
+ map[0] = (area->pageTableEntries << 8) | gcvMMU_FREE;
+ map[1] = ~0U;
+ area->heapList = 0;
+ area->freeNodes = gcvFALSE;
+
+ status = gckOS_QueryOption(mmu->os, "contiguousBase", &contiguousBase);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ status = gckOS_QueryOption(mmu->os, "contiguousSize", &contiguousSize);
+ }
+
+ if (gcmIS_SUCCESS(status) && contiguousSize)
+ {
+ mmu->contiguousBaseAddress = contiguousBase - Kernel->hardware->baseAddress;
+ }
+
+ }
+ else
+ {
+ /* Allocate the 4K mode MTLB table. */
+ mmu->mtlbSize = gcdMMU_MTLB_SIZE;
+
+ gcmkONERROR(
+ gckOS_AllocateContiguous(os,
+ gcvFALSE,
+ &mmu->mtlbSize,
+ &mmu->mtlbPhysical,
+ &pointer));
+
+ mmu->mtlbLogical = pointer;
+
+ area->dynamicMappingStart = gcvINVALID_ADDRESS;
+
+#if gcdPROCESS_ADDRESS_SPACE
+ _FillPageTable(pointer, mmu->mtlbSize / 4, gcdMMU_MTLB_EXCEPTION);
+
+ /* Allocate a array to store stlbs. */
+ gcmkONERROR(gckOS_Allocate(os, mmu->mtlbSize, &mmu->stlbs));
+
+ gckOS_ZeroMemory(mmu->stlbs, mmu->mtlbSize);
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ gcmkONERROR(gckOS_AtomConstruct(os, &mmu->pageTableDirty[i]));
+ }
+
+ _SetupProcessAddressSpace(mmu);
+
+ /* Map kernel command buffer in MMU. */
+ for (i = 0; i < gcdCOMMAND_QUEUES; i++)
+ {
+ gcmkONERROR(gckOS_GetPhysicalAddress(
+ mmu->os,
+ Kernel->command->queues[i].logical,
+ &gpuPhysical
+ ));
+
+ gcmkSAFECASTPHYSADDRT(gpuAddress, gpuPhysical);
+
+ gcmkONERROR(gckMMU_FlatMapping(mmu, gpuAddress, 1));
+ }
+#else
+ /* Invalid all the entries. */
+ gcmkONERROR(
+ gckOS_ZeroMemory(pointer, mmu->mtlbSize));
+
+ gcmkONERROR(
+ gckOS_QueryOption(mmu->os, "physBase", &physBase));
+
+ gcmkONERROR(
+ gckOS_QueryOption(mmu->os, "physSize", &physSize));
+
+ gcmkONERROR(
+ gckOS_CPUPhysicalToGPUPhysical(mmu->os, physBase, &gpuPhysical));
+
+ gcmkSAFECASTPHYSADDRT(gpuAddress, gpuPhysical);
+
+ if (physSize)
+ {
+ /* Setup user specified flat mapping. */
+ gcmkONERROR(_FillFlatMapping(mmu, gpuAddress, physSize, gcvNULL));
+ }
+
+#ifndef EMULATOR
+ if (!_ReadPageEntry(mmu->mtlbLogical + 0))
+ {
+ gctUINT32 mtlbEntry;
+ /*
+ * Reserved 0~4MB space.
+ * 64KB page size, Ingore exception, Not Present.
+ */
+ mtlbEntry = (1 << 2)
+ | (0 << 1)
+ | (0 << 0);
+
+ _WritePageEntry(mmu->mtlbLogical + 0, mtlbEntry);
+ }
+#endif
+
+ status = gckOS_QueryOption(mmu->os, "contiguousBase", &contiguousBase);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ status = gckOS_QueryOption(mmu->os, "contiguousSize", &contiguousSize);
+ }
+
+ if (gcmIS_SUCCESS(status) && contiguousSize)
+ {
+ gctUINT64 gpuContiguousBase;
+ gctUINT32 contiguousBaseAddress;
+
+ gcmkONERROR(gckOS_CPUPhysicalToGPUPhysical(mmu->os, contiguousBase, &gpuContiguousBase));
+
+ /* Setup flat mapping for reserved memory (VIDMEM). */
+ gcmkONERROR(_FillFlatMapping(mmu, gpuContiguousBase, contiguousSize, &contiguousBaseAddress));
+
+ mmu->contiguousBaseAddress = contiguousBaseAddress;
+ }
+
+ status = gckOS_QueryOption(mmu->os, "externalBase", &externalBase);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ status = gckOS_QueryOption(mmu->os, "externalSize", &externalSize);
+ }
+
+ if (gcmIS_SUCCESS(status) && externalSize)
+ {
+ gctUINT64 gpuExternalBase;
+ gctUINT32 externalBaseAddress;
+
+ gcmkONERROR(gckOS_CPUPhysicalToGPUPhysical(mmu->os, externalBase, &gpuExternalBase));
+
+ /* Setup flat mapping for external memory. */
+ gcmkONERROR(_FillFlatMapping(mmu, gpuExternalBase, externalSize, &externalBaseAddress));
+
+ mmu->externalBaseAddress = externalBaseAddress;
+ }
+
+ gcmkONERROR(_SetupDynamicSpace(mmu));
+#endif
+ }
+
+ mmu->safePageSize = 4096;
+
+ gcmkONERROR(gckOS_AllocateContiguous(
+ os,
+ gcvFALSE,
+ &mmu->safePageSize,
+ &mmu->safePagePhysical,
+ &mmu->safePageLogical
+ ));
+
+ gcmkONERROR(gckOS_GetPhysicalAddress(os,
+ mmu->safePageLogical,
+ &gpuPhysical
+ ));
+
+ gcmkSAFECASTPHYSADDRT(mmu->safeAddress, gpuPhysical);
+
+ gckOS_ZeroMemory(mmu->safePageLogical, mmu->safePageSize);
+
+ gcmkONERROR(gckQUEUE_Allocate(os, &mmu->recentFreedAddresses, 16));
+
+ /* Return the gckMMU object pointer. */
+ *Mmu = mmu;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Mmu=0x%x", *Mmu);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Roll back. */
+ if (mmu != gcvNULL)
+ {
+ if (area != gcvNULL && area->mapLogical != gcvNULL)
+ {
+ gcmkVERIFY_OK(
+ gckOS_Free(os, (gctPOINTER) area->mapLogical));
+
+
+ gcmkVERIFY_OK(
+ gckOS_FreeContiguous(os,
+ area->pageTablePhysical,
+ (gctPOINTER) area->pageTableLogical,
+ area->pageTableSize));
+ }
+
+ if (mmu->mtlbLogical != gcvNULL)
+ {
+ gcmkVERIFY_OK(
+ gckOS_FreeContiguous(os,
+ mmu->mtlbPhysical,
+ (gctPOINTER) mmu->mtlbLogical,
+ mmu->mtlbSize));
+ }
+
+ if (mmu->pageTableMutex != gcvNULL)
+ {
+ /* Delete the mutex. */
+ gcmkVERIFY_OK(
+ gckOS_DeleteMutex(os, mmu->pageTableMutex));
+ }
+
+ gcmkVERIFY_OK(gckQUEUE_Free(os, &mmu->recentFreedAddresses));
+
+ /* Mark the gckMMU object as unknown. */
+ mmu->object.type = gcvOBJ_UNKNOWN;
+
+ /* Free the allocates memory. */
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, mmu));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** _Destroy
+**
+** Destroy a gckMMU object.
+**
+** INPUT:
+**
+** gckMMU Mmu
+** Pointer to an gckMMU object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+_Destroy(
+ IN gckMMU Mmu
+ )
+{
+ gctUINT32 i;
+ gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+
+ while (Mmu->staticSTLB != gcvNULL)
+ {
+ gcsMMU_STLB_CHUNK_PTR pre = Mmu->staticSTLB;
+ Mmu->staticSTLB = pre->next;
+
+ if (pre->physical != gcvNULL)
+ {
+ gcmkVERIFY_OK(
+ gckOS_FreeContiguous(Mmu->os,
+ pre->physical,
+ pre->logical,
+ pre->size));
+ }
+
+ if (pre->mtlbEntryNum != 0)
+ {
+ gctUINT i;
+ for (i = 0; i < pre->mtlbEntryNum; ++i)
+ {
+ _WritePageEntry(Mmu->mtlbLogical + pre->mtlbIndex + i, 0);
+#if gcdMMU_TABLE_DUMP
+ gckOS_Print("%s(%d): clean MTLB[%d]\n",
+ __FUNCTION__, __LINE__,
+ pre->mtlbIndex + i);
+#endif
+ }
+ }
+
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, pre));
+ }
+
+ if (Mmu->hardware->mmuVersion != 0)
+ {
+ gcmkVERIFY_OK(
+ gckOS_FreeContiguous(Mmu->os,
+ Mmu->mtlbPhysical,
+ (gctPOINTER) Mmu->mtlbLogical,
+ Mmu->mtlbSize));
+ }
+
+ for (i = 0; i < gcvADDRESS_AREA_COUNT; i++)
+ {
+ gcsADDRESS_AREA_PTR area = &Mmu->area[i];
+
+ /* Free address space management table. */
+ if (area->mapLogical != gcvNULL)
+ {
+ gcmkVERIFY_OK(
+ gckOS_Free(Mmu->os, (gctPOINTER) area->mapLogical));
+ }
+
+ if (area->pageTableLogical != gcvNULL)
+ {
+ /* Free page table. */
+ gcmkVERIFY_OK(
+ gckOS_FreeContiguous(Mmu->os,
+ area->pageTablePhysical,
+ (gctPOINTER) area->pageTableLogical,
+ area->pageTableSize));
+ }
+ }
+
+ /* Delete the page table mutex. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->pageTableMutex));
+
+#if gcdPROCESS_ADDRESS_SPACE
+ for (i = 0; i < Mmu->mtlbSize / 4; i++)
+ {
+ struct _gcsMMU_STLB_CHUNK *stlb = ((struct _gcsMMU_STLB_CHUNK **)Mmu->stlbs)[i];
+
+ if (stlb)
+ {
+ gcmkVERIFY_OK(gckOS_FreeContiguous(
+ Mmu->os,
+ stlb->physical,
+ stlb->logical,
+ stlb->size));
+
+ gcmkOS_SAFE_FREE(Mmu->os, stlb);
+ }
+ }
+
+ gcmkOS_SAFE_FREE(Mmu->os, Mmu->stlbs);
+#endif
+
+ if (Mmu->safePageLogical != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_FreeContiguous(
+ Mmu->os,
+ Mmu->safePagePhysical,
+ Mmu->safePageLogical,
+ Mmu->safePageSize
+ ));
+ }
+
+ gcmkVERIFY_OK(gckQUEUE_Free(Mmu->os, &Mmu->recentFreedAddresses));
+
+ /* Mark the gckMMU object as unknown. */
+ Mmu->object.type = gcvOBJ_UNKNOWN;
+
+ /* Free the gckMMU object. */
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, Mmu));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+** _AdjstIndex
+**
+** Adjust the index from which we search for a usable node to make sure
+** index allocated is greater than Start.
+*/
+gceSTATUS
+_AdjustIndex(
+ IN gckMMU Mmu,
+ IN gctUINT32 Index,
+ IN gctUINT32 PageCount,
+ IN gctUINT32 Start,
+ OUT gctUINT32 * IndexAdjusted
+ )
+{
+ gceSTATUS status;
+ gctUINT32 index = Index;
+ gcsADDRESS_AREA_PTR area = &Mmu->area[0];
+ gctUINT32_PTR map = area->mapLogical;
+
+ gcmkHEADER();
+
+ for (; index < area->pageTableEntries;)
+ {
+ gctUINT32 result = 0;
+ gctUINT32 nodeSize = 0;
+
+ if (index >= Start)
+ {
+ break;
+ }
+
+ switch (gcmENTRY_TYPE(map[index]))
+ {
+ case gcvMMU_SINGLE:
+ nodeSize = 1;
+ break;
+
+ case gcvMMU_FREE:
+ nodeSize = map[index] >> 8;
+ break;
+
+ default:
+ gcmkFATAL("MMU table correcupted at index %u!", index);
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ if (nodeSize > PageCount)
+ {
+ result = index + (nodeSize - PageCount);
+
+ if (result >= Start)
+ {
+ break;
+ }
+ }
+
+ switch (gcmENTRY_TYPE(map[index]))
+ {
+ case gcvMMU_SINGLE:
+ index = map[index] >> 8;
+ break;
+
+ case gcvMMU_FREE:
+ index = map[index + 1];
+ break;
+
+ default:
+ gcmkFATAL("MMU table correcupted at index %u!", index);
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+ }
+
+ *IndexAdjusted = index;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckMMU_Construct(
+ IN gckKERNEL Kernel,
+ IN gctSIZE_T MmuSize,
+ OUT gckMMU * Mmu
+ )
+{
+#if gcdSHARED_PAGETABLE
+ gceSTATUS status;
+ gctPOINTER pointer;
+
+ gcmkHEADER_ARG("Kernel=0x%08x", Kernel);
+
+ if (sharedPageTable == gcvNULL)
+ {
+ gcmkONERROR(
+ gckOS_Allocate(Kernel->os,
+ sizeof(struct _gcsSharedPageTable),
+ &pointer));
+ sharedPageTable = pointer;
+
+ gcmkONERROR(
+ gckOS_ZeroMemory(sharedPageTable,
+ sizeof(struct _gcsSharedPageTable)));
+
+ gcmkONERROR(_Construct(Kernel, MmuSize, &sharedPageTable->mmu));
+ }
+
+ *Mmu = sharedPageTable->mmu;
+
+ sharedPageTable->hardwares[sharedPageTable->reference] = Kernel->hardware;
+
+ sharedPageTable->reference++;
+
+ gcmkFOOTER_ARG("sharedPageTable->reference=%lu", sharedPageTable->reference);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (sharedPageTable)
+ {
+ if (sharedPageTable->mmu)
+ {
+ gcmkVERIFY_OK(gckMMU_Destroy(sharedPageTable->mmu));
+ }
+
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, sharedPageTable));
+ }
+
+ gcmkFOOTER();
+ return status;
+#else
+ return _Construct(Kernel, MmuSize, Mmu);
+#endif
+}
+
+gceSTATUS
+gckMMU_Destroy(
+ IN gckMMU Mmu
+ )
+{
+#if gcdSHARED_PAGETABLE
+ gckOS os = Mmu->os;
+
+ sharedPageTable->reference--;
+
+ if (sharedPageTable->reference == 0)
+ {
+ if (sharedPageTable->mmu)
+ {
+ gcmkVERIFY_OK(_Destroy(Mmu));
+ }
+
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, sharedPageTable));
+ }
+
+ return gcvSTATUS_OK;
+#else
+ return _Destroy(Mmu);
+#endif
+}
+
+/*******************************************************************************
+**
+** gckMMU_AllocatePages
+**
+** Allocate pages inside the page table.
+**
+** INPUT:
+**
+** gckMMU Mmu
+** Pointer to an gckMMU object.
+**
+** gctSIZE_T PageCount
+** Number of pages to allocate.
+**
+** OUTPUT:
+**
+** gctPOINTER * PageTable
+** Pointer to a variable that receives the base address of the page
+** table.
+**
+** gctUINT32 * Address
+** Pointer to a variable that receives the hardware specific address.
+*/
+gceSTATUS
+_AllocatePages(
+ IN gckMMU Mmu,
+ IN gctSIZE_T PageCount,
+ IN gceSURF_TYPE Type,
+ IN gctBOOL Secure,
+ OUT gctPOINTER * PageTable,
+ OUT gctUINT32 * Address
+ )
+{
+ gceSTATUS status;
+ gctBOOL mutex = gcvFALSE;
+ gctUINT32 index = 0, previous = ~0U, left;
+ gctUINT32_PTR map;
+ gctBOOL gotIt;
+ gctUINT32 address;
+ gctUINT32 pageCount;
+ gcsADDRESS_AREA_PTR area = _GetProcessArea(Mmu, Secure);
+
+ gcmkHEADER_ARG("Mmu=0x%x PageCount=%lu", Mmu, PageCount);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+ gcmkVERIFY_ARGUMENT(PageCount > 0);
+ gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
+
+ if (PageCount > area->pageTableEntries)
+ {
+ /* Not enough pages avaiable. */
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ gcmkSAFECASTSIZET(pageCount, PageCount);
+
+#if gcdBOUNDARY_CHECK
+ /* Extra pages as bounary. */
+ pageCount += gcdBOUNDARY_CHECK * 2;
+#endif
+
+ /* Grab the mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
+ mutex = gcvTRUE;
+
+ /* Cast pointer to page table. */
+ for (map = area->mapLogical, gotIt = gcvFALSE; !gotIt;)
+ {
+ index = area->heapList;
+
+ if ((Mmu->hardware->mmuVersion == 0) && (Type == gcvSURF_VERTEX))
+ {
+ gcmkONERROR(_AdjustIndex(
+ Mmu,
+ index,
+ pageCount,
+ gcdVERTEX_START / gcmSIZEOF(gctUINT32),
+ &index
+ ));
+ }
+
+ /* Walk the heap list. */
+ for (; !gotIt && (index < area->pageTableEntries);)
+ {
+ /* Check the node type. */
+ switch (gcmENTRY_TYPE(map[index]))
+ {
+ case gcvMMU_SINGLE:
+ /* Single odes are valid if we only need 1 page. */
+ if (pageCount == 1)
+ {
+ gotIt = gcvTRUE;
+ }
+ else
+ {
+ /* Move to next node. */
+ previous = index;
+ index = map[index] >> 8;
+ }
+ break;
+
+ case gcvMMU_FREE:
+ /* Test if the node has enough space. */
+ if (pageCount <= (map[index] >> 8))
+ {
+ gotIt = gcvTRUE;
+ }
+ else
+ {
+ /* Move to next node. */
+ previous = index;
+ index = map[index + 1];
+ }
+ break;
+
+ default:
+ gcmkFATAL("MMU table correcupted at index %u!", index);
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+ }
+
+ /* Test if we are out of memory. */
+ if (index >= area->pageTableEntries)
+ {
+ if (area->freeNodes)
+ {
+ /* Time to move out the trash! */
+ gcmkONERROR(_Collect(area));
+
+ /* We are going to search from start, so reset previous to start. */
+ previous = ~0U;
+ }
+ else
+ {
+ /* Out of resources. */
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+ }
+ }
+
+ switch (gcmENTRY_TYPE(map[index]))
+ {
+ case gcvMMU_SINGLE:
+ /* Unlink single node from free list. */
+ gcmkONERROR(
+ _Link(area, previous, map[index] >> 8));
+ break;
+
+ case gcvMMU_FREE:
+ /* Check how many pages will be left. */
+ left = (map[index] >> 8) - pageCount;
+ switch (left)
+ {
+ case 0:
+ /* The entire node is consumed, just unlink it. */
+ gcmkONERROR(
+ _Link(area, previous, map[index + 1]));
+ break;
+
+ case 1:
+ /* One page will remain. Convert the node to a single node and
+ ** advance the index. */
+ map[index] = (map[index + 1] << 8) | gcvMMU_SINGLE;
+ index ++;
+ break;
+
+ default:
+ /* Enough pages remain for a new node. However, we will just adjust
+ ** the size of the current node and advance the index. */
+ map[index] = (left << 8) | gcvMMU_FREE;
+ index += left;
+ break;
+ }
+ break;
+ }
+
+ /* Mark node as used. */
+ gcmkONERROR(_FillMap(&map[index], pageCount, gcvMMU_USED));
+
+#if gcdBOUNDARY_CHECK
+ index += gcdBOUNDARY_CHECK;
+#endif
+
+ /* Record pageCount of allocated node at the beginning of node. */
+ if (pageCount == 1)
+ {
+ map[index] = (~((1U<<8)-1)) | gcvMMU_USED;
+ }
+ else
+ {
+ map[index] = (pageCount << 8) | gcvMMU_USED;
+ }
+
+ if (area->pageTableLogical != gcvNULL)
+ {
+ /* Return pointer to page table. */
+ *PageTable = &area->pageTableLogical[index];
+ }
+ else
+ {
+ /* Page table for secure area is handled in trust application. */
+ *PageTable = gcvNULL;
+ }
+
+ /* Build virtual address. */
+ if (Mmu->hardware->mmuVersion == 0)
+ {
+ gcmkONERROR(
+ gckHARDWARE_BuildVirtualAddress(Mmu->hardware, index, 0, &address));
+ }
+ else
+ {
+ gctUINT32 masterOffset = index / gcdMMU_STLB_4K_ENTRY_NUM
+ + area->dynamicMappingStart;
+ gctUINT32 slaveOffset = index % gcdMMU_STLB_4K_ENTRY_NUM;
+
+ address = (masterOffset << gcdMMU_MTLB_SHIFT)
+ | (slaveOffset << gcdMMU_STLB_4K_SHIFT);
+ }
+
+ if (Address != gcvNULL)
+ {
+ *Address = address;
+ }
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+
+ /* Success. */
+ gcmkFOOTER_ARG("*PageTable=0x%x *Address=%08x",
+ *PageTable, gcmOPT_VALUE(Address));
+ return gcvSTATUS_OK;
+
+OnError:
+
+ if (mutex)
+ {
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckMMU_FreePages
+**
+** Free pages inside the page table.
+**
+** INPUT:
+**
+** gckMMU Mmu
+** Pointer to an gckMMU object.
+**
+** gctPOINTER PageTable
+** Base address of the page table to free.
+**
+** gctSIZE_T PageCount
+** Number of pages to free.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+_FreePages(
+ IN gckMMU Mmu,
+ IN gctBOOL Secure,
+ IN gctUINT32 Address,
+ IN gctPOINTER PageTable,
+ IN gctSIZE_T PageCount
+ )
+{
+ gctUINT32_PTR node;
+ gceSTATUS status;
+ gctBOOL acquired = gcvFALSE;
+ gctUINT32 pageCount;
+ gcuQUEUEDATA data;
+ gcsADDRESS_AREA_PTR area = _GetProcessArea(Mmu, Secure);
+
+ gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=%lu",
+ Mmu, PageTable, PageCount);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+ gcmkVERIFY_ARGUMENT(PageCount > 0);
+
+ gcmkSAFECASTSIZET(pageCount, PageCount);
+
+#if gcdBOUNDARY_CHECK
+ pageCount += gcdBOUNDARY_CHECK * 2;
+#endif
+
+ /* Get the node by index. */
+ node = area->mapLogical + ((gctUINT32_PTR)PageTable - area->pageTableLogical);
+
+ if (pageCount != _GetPageCountOfUsedNode(node))
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_REQUEST);
+ }
+
+#if gcdBOUNDARY_CHECK
+ node -= gcdBOUNDARY_CHECK;
+#endif
+
+ gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ if (Mmu->hardware->mmuVersion == 0)
+ {
+ _FillPageTable(PageTable, pageCount, Mmu->safeAddress);
+ }
+
+ if (pageCount == 1)
+ {
+ /* Single page node. */
+ node[0] = (~((1U<<8)-1)) | gcvMMU_SINGLE;
+
+ if (PageTable != gcvNULL)
+ {
+#if gcdUSE_MMU_EXCEPTION
+ /* Enable exception */
+ _WritePageEntry(PageTable, (1 << 1));
+#else
+ _WritePageEntry(PageTable, 0);
+#endif
+ }
+ }
+ else
+ {
+ /* Mark the node as free. */
+ node[0] = (pageCount << 8) | gcvMMU_FREE;
+ node[1] = ~0U;
+
+ if (PageTable != gcvNULL)
+ {
+#if gcdUSE_MMU_EXCEPTION
+ /* Enable exception */
+ gcmkVERIFY_OK(_FillPageTable(PageTable, (gctUINT32)PageCount, 1 << 1));
+#else
+ gcmkVERIFY_OK(_FillPageTable(PageTable, (gctUINT32)PageCount, 0));
+#endif
+ }
+ }
+
+ /* We have free nodes. */
+ area->freeNodes = gcvTRUE;
+
+ /* Record freed address range. */
+ data.addressData.start = Address;
+ data.addressData.end = Address + (gctUINT32)PageCount * 4096;
+ gckQUEUE_Enqueue(&Mmu->recentFreedAddresses, &data);
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+ acquired = gcvFALSE;
+
+#if gcdENABLE_TRUST_APPLICATION
+ if (Mmu->hardware->options.secureMode == gcvSECURE_IN_TA)
+ {
+ gckKERNEL_SecurityUnmapMemory(Mmu->hardware->kernel, Address, (gctUINT32)PageCount);
+ }
+#endif
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckMMU_AllocatePages(
+ IN gckMMU Mmu,
+ IN gctSIZE_T PageCount,
+ OUT gctPOINTER * PageTable,
+ OUT gctUINT32 * Address
+ )
+{
+ return gckMMU_AllocatePagesEx(
+ Mmu, PageCount, gcvSURF_TYPE_UNKNOWN, gcvFALSE, PageTable, Address);
+}
+
+gceSTATUS
+gckMMU_AllocatePagesEx(
+ IN gckMMU Mmu,
+ IN gctSIZE_T PageCount,
+ IN gceSURF_TYPE Type,
+ IN gctBOOL Secure,
+ OUT gctPOINTER * PageTable,
+ OUT gctUINT32 * Address
+ )
+{
+#if gcdDISABLE_GPU_VIRTUAL_ADDRESS
+ gcmkPRINT("GPU virtual address is disabled.");
+ return gcvSTATUS_NOT_SUPPORTED;
+#else
+ return _AllocatePages(Mmu, PageCount, Type, Secure, PageTable, Address);
+#endif
+}
+
+gceSTATUS
+gckMMU_FreePages(
+ IN gckMMU Mmu,
+ IN gctBOOL Secure,
+ IN gctUINT32 Address,
+ IN gctPOINTER PageTable,
+ IN gctSIZE_T PageCount
+ )
+{
+ return _FreePages(Mmu, Secure, Address, PageTable, PageCount);
+}
+
+gceSTATUS
+gckMMU_SetPage(
+ IN gckMMU Mmu,
+ IN gctPHYS_ADDR_T PageAddress,
+ IN gctBOOL Writable,
+ IN gctUINT32 *PageEntry
+ )
+{
+ gctUINT32 addressExt;
+ gctUINT32 address;
+
+ gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+ gcmkVERIFY_ARGUMENT(PageEntry != gcvNULL);
+ gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFF));
+
+ /* [31:0]. */
+ address = (gctUINT32)(PageAddress & 0xFFFFFFFF);
+ /* [39:32]. */
+ addressExt = (gctUINT32)((PageAddress >> 32) & 0xFF);
+
+ if (Mmu->hardware->mmuVersion == 0)
+ {
+ _WritePageEntry(PageEntry, address);
+ }
+ else
+ {
+ _WritePageEntry(PageEntry, _SetPage(address, addressExt, gcvTRUE));
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+#if gcdPROCESS_ADDRESS_SPACE
+gceSTATUS
+gckMMU_GetPageEntry(
+ IN gckMMU Mmu,
+ IN gctUINT32 Address,
+ IN gctUINT32_PTR *PageTable
+ )
+{
+ gceSTATUS status;
+ struct _gcsMMU_STLB_CHUNK *stlb;
+ struct _gcsMMU_STLB_CHUNK **stlbs = Mmu->stlbs;
+ gctUINT32 offset = _MtlbOffset(Address);
+ gctUINT32 mtlbEntry;
+ gctBOOL ace = gckHARDWARE_IsFeatureAvailable(Mmu->hardware, gcvFEATURE_ACE);
+
+ gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+ gcmkVERIFY_ARGUMENT((Address & 0xFFF) == 0);
+
+ stlb = stlbs[offset];
+
+ if (stlb == gcvNULL)
+ {
+ gcmkONERROR(_AllocateStlb(Mmu->os, &stlb));
+
+ mtlbEntry = stlb->physBase
+ | gcdMMU_MTLB_4K_PAGE
+ | gcdMMU_MTLB_PRESENT
+ ;
+
+ /* Insert Slave TLB address to Master TLB entry.*/
+ _WritePageEntry(Mmu->mtlbLogical + offset, mtlbEntry);
+
+ /* Record stlb. */
+ stlbs[offset] = stlb;
+ }
+
+ *PageTable = &stlb->logical[_StlbOffset(Address)];
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+_CheckMap(
+ IN gckMMU Mmu
+ )
+{
+ gceSTATUS status;
+ gctUINT32_PTR map = area->mapLogical;
+ gctUINT32 index;
+
+ for (index = area->heapList; index < area->pageTableEntries;)
+ {
+ /* Check the node type. */
+ switch (gcmENTRY_TYPE(map[index]))
+ {
+ case gcvMMU_SINGLE:
+ /* Move to next node. */
+ index = map[index] >> 8;
+ break;
+
+ case gcvMMU_FREE:
+ /* Move to next node. */
+ index = map[index + 1];
+ break;
+
+ default:
+ gcmkFATAL("MMU table correcupted at index [%u] = %x!", index, map[index]);
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+ }
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+gceSTATUS
+gckMMU_FlatMapping(
+ IN gckMMU Mmu,
+ IN gctUINT32 Physical,
+ IN gctUINT32 NumPages
+ )
+{
+ gceSTATUS status;
+ gctUINT32 index = _AddressToIndex(Mmu, Physical);
+ gctUINT32 i;
+ gctUINT32_PTR pageTable;
+
+ for (i = 0; i < NumPages; i++)
+ {
+ gckMMU_GetPageEntry(Mmu, Physical + i * 4096, &pageTable);
+
+ _WritePageEntry(pageTable, _SetPage(Physical + i * 4096, 0));
+ }
+
+ gcmkONERROR(_FillFlatMapping(Mmu, PhysBase, Size, gcvNULL));
+
+ return gcvSTATUS_OK;
+
+OnError:
+
+ /* Roll back. */
+ return status;
+}
+
+gceSTATUS
+gckMMU_FreePagesEx(
+ IN gckMMU Mmu,
+ IN gctUINT32 Address,
+ IN gctSIZE_T PageCount
+ )
+{
+ gctUINT32_PTR node;
+ gceSTATUS status;
+
+#if gcdUSE_MMU_EXCEPTION
+ gctUINT32 i;
+ struct _gcsMMU_STLB_CHUNK *stlb;
+ struct _gcsMMU_STLB_CHUNK **stlbs = Mmu->stlbs;
+#endif
+
+ gcmkHEADER_ARG("Mmu=0x%x Address=0x%x PageCount=%lu",
+ Mmu, Address, PageCount);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+ gcmkVERIFY_ARGUMENT(PageCount > 0);
+
+ /* Get the node by index. */
+ node = area->mapLogical + _AddressToIndex(Mmu, Address);
+
+ gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
+
+ if (PageCount == 1)
+ {
+ /* Single page node. */
+ node[0] = (~((1U<<8)-1)) | gcvMMU_SINGLE;
+ }
+ else
+ {
+ /* Mark the node as free. */
+ node[0] = (PageCount << 8) | gcvMMU_FREE;
+ node[1] = ~0U;
+ }
+
+ /* We have free nodes. */
+ area->freeNodes = gcvTRUE;
+
+#if gcdUSE_MMU_EXCEPTION
+ for (i = 0; i < PageCount; i++)
+ {
+ /* Get */
+ stlb = stlbs[_MtlbOffset(Address)];
+
+ /* Enable exception */
+ stlb->logical[_StlbOffset(Address)] = gcdMMU_STLB_EXCEPTION;
+ }
+#endif
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+#endif
+
+gceSTATUS
+gckMMU_Flush(
+ IN gckMMU Mmu,
+ IN gceSURF_TYPE Type
+ )
+{
+#if !gcdPROCESS_ADDRESS_SPACE
+ gckHARDWARE hardware;
+#endif
+ gctUINT32 mask;
+ gctINT i;
+ gctUINT j;
+
+ if (Type == gcvSURF_VERTEX || Type == gcvSURF_INDEX)
+ {
+ mask = gcvPAGE_TABLE_DIRTY_BIT_FE;
+ }
+ else
+ {
+ mask = gcvPAGE_TABLE_DIRTY_BIT_OTHER;
+ }
+
+ i = 0;
+
+#if gcdPROCESS_ADDRESS_SPACE
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ gcmkVERIFY_OK(
+ gckOS_AtomSetMask(Mmu->pageTableDirty[i], mask));
+ }
+#else
+#if gcdSHARED_PAGETABLE
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ hardware = sharedPageTable->hardwares[i];
+ if (hardware)
+ {
+ for (j = 0; j < gcvENGINE_GPU_ENGINE_COUNT; j++)
+ {
+ gcmkVERIFY_OK(gckOS_AtomSetMask(hardware->pageTableDirty[j], mask));
+ }
+ }
+ }
+#else
+ hardware = Mmu->hardware;
+
+ for (j = 0 ; j < gcvENGINE_GPU_ENGINE_COUNT; j++)
+ {
+ gcmkVERIFY_OK(
+ gckOS_AtomSetMask(hardware->pageTableDirty[j], mask));
+ }
+
+ {
+ gcsLISTHEAD_PTR hardwareHead;
+ gcmkLIST_FOR_EACH(hardwareHead, &Mmu->hardwareList)
+ {
+ hardware = gcmCONTAINEROF(hardwareHead, _gckHARDWARE, mmuHead);
+
+ if (hardware != Mmu->hardware)
+ {
+ for (j = 0 ; j < gcvENGINE_GPU_ENGINE_COUNT; j++)
+ {
+ gcmkVERIFY_OK(
+ gckOS_AtomSetMask(hardware->pageTableDirty[j], mask));
+ }
+ }
+ }
+ }
+#endif
+#endif
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckMMU_DumpPageTableEntry(
+ IN gckMMU Mmu,
+ IN gctUINT32 Address
+ )
+{
+#if gcdPROCESS_ADDRESS_SPACE
+ gcsMMU_STLB_PTR *stlbs = Mmu->stlbs;
+ gcsMMU_STLB_PTR stlbDesc = stlbs[_MtlbOffset(Address)];
+#else
+ gctUINT32_PTR pageTable;
+ gctUINT32 index;
+ gctUINT32 mtlb, stlb;
+#endif
+ gcsADDRESS_AREA_PTR area = &Mmu->area[0];
+
+ gcmkHEADER_ARG("Mmu=0x%08X Address=0x%08X", Mmu, Address);
+ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+
+ gcmkASSERT(Mmu->hardware->mmuVersion > 0);
+
+#if gcdPROCESS_ADDRESS_SPACE
+ if (stlbDesc)
+ {
+ gcmkPRINT(" STLB entry = 0x%08X",
+ _ReadPageEntry(&stlbDesc->logical[_StlbOffset(Address)]));
+ }
+ else
+ {
+ gcmkPRINT(" MTLB entry is empty.");
+ }
+#else
+ mtlb = (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT;
+
+ if (mtlb >= area->dynamicMappingStart)
+ {
+ stlb = (Address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT;
+
+ pageTable = area->pageTableLogical;
+
+ index = (mtlb - area->dynamicMappingStart)
+ * gcdMMU_STLB_4K_ENTRY_NUM
+ + stlb;
+
+ gcmkPRINT(" Page table entry = 0x%08X", _ReadPageEntry(pageTable + index));
+ }
+ else
+ {
+ gcsMMU_STLB_CHUNK_PTR stlbChunkObj = Mmu->staticSTLB;
+ gctUINT32 entry = Mmu->mtlbLogical[mtlb];
+
+ stlb = (Address & gcdMMU_STLB_64K_MASK) >> gcdMMU_STLB_64K_SHIFT;
+
+ entry &= 0xFFFFFFF0;
+
+ while (stlbChunkObj)
+ {
+ gctUINT i;
+ gctBOOL found = gcvFALSE;
+ for (i = 0; i < stlbChunkObj->mtlbEntryNum; ++i)
+ {
+ gctPHYS_ADDR_T stlbPhysBase = stlbChunkObj->physBase + (i * gcdMMU_STLB_64K_SIZE);
+ gctUINT32_PTR stlbLogical =
+ (gctUINT32_PTR)((gctUINT8_PTR)stlbChunkObj->logical + (i * gcdMMU_STLB_64K_SIZE));
+ if (entry == stlbPhysBase)
+ {
+ gcmkPRINT(" Page table entry = 0x%08X", stlbLogical[stlb]);
+ found = gcvTRUE;
+ break;
+ }
+ }
+ if (found)
+ break;
+ stlbChunkObj = stlbChunkObj->next;
+ }
+ }
+#endif
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+void
+gckMMU_CheckSaftPage(
+ IN gckMMU Mmu
+ )
+{
+ gctUINT8_PTR safeLogical = Mmu->safePageLogical;
+ gctUINT32 offsets[] = {
+ 0,
+ 64,
+ 128,
+ 256,
+ 2560,
+ 4000
+ };
+
+ gctUINT32 i = 0;
+
+ while (i < gcmCOUNTOF(offsets))
+ {
+ if (safeLogical[offsets[i]] != 0)
+ {
+ gcmkPRINT("%s(%d) safe page is over written [%d] = %x",
+ __FUNCTION__, __LINE__, i, safeLogical[offsets[i]]);
+ }
+ }
+}
+
+void
+gckMMU_DumpAddressSpace(
+ IN gckMMU Mmu
+ )
+{
+ gctUINT i;
+ gctUINT next;
+ gcsADDRESS_AREA_PTR area = &Mmu->area[0];
+ gctUINT32_PTR map = area->mapLogical;
+ gctBOOL used = gcvFALSE;
+ gctUINT32 numPages;
+
+ /* Grab the mutex. */
+ gcmkVERIFY_OK(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE));
+
+ /* Find node which contains index. */
+ for (i = 0; i < area->pageTableEntries; i = next)
+ {
+ switch (gcmENTRY_TYPE(map[i]))
+ {
+ case gcvMMU_SINGLE:
+ numPages = 1;
+ next = i + numPages;
+ used = gcvFALSE;
+ break;
+
+ case gcvMMU_FREE:
+ numPages = map[i] >> 8;
+ next = i + numPages;
+ used = gcvFALSE;
+ break;
+
+ case gcvMMU_USED:
+ numPages = 1;
+ next = i + numPages;
+ used = gcvTRUE;
+ break;
+
+ default:
+ gcmkFATAL("MMU table correcupted at index %u!", i);
+ return;
+ }
+
+ if (!used)
+ {
+ gcmkPRINT("Available Range [%d - %d)", i, i + numPages);
+ }
+ }
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex));
+
+}
+
+void
+gckMMU_DumpRecentFreedAddress(
+ IN gckMMU Mmu
+ )
+{
+ gckQUEUE queue = &Mmu->recentFreedAddresses;
+ gctUINT32 i;
+ gcuQUEUEDATA *data;
+
+ if (queue->count)
+ {
+ gcmkPRINT(" Recent %d freed GPU address ranges:", queue->count);
+
+ for (i = 0; i < queue->count; i++)
+ {
+ gckQUEUE_GetData(queue, i, &data);
+
+ gcmkPRINT(" [%08X - %08X]", data->addressData.start, data->addressData.end);
+ }
+ }
+}
+
+gceSTATUS
+gckMMU_FillFlatMapping(
+ IN gckMMU Mmu,
+ IN gctUINT32 PhysBase,
+ IN gctSIZE_T Size
+ )
+{
+ gceSTATUS status;
+ gckHARDWARE hardware = Mmu->hardware;
+
+ if (hardware->mmuVersion)
+ {
+ gcmkONERROR(_FillFlatMapping(Mmu, PhysBase, Size, gcvNULL));
+ }
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+gceSTATUS
+gckMMU_IsFlatMapped(
+ IN gckMMU Mmu,
+ OUT gctUINT32 Physical,
+ OUT gctBOOL *In
+ )
+{
+ gceSTATUS status;
+ gctUINT32 i;
+ gctBOOL inFlatmapping = gcvFALSE;
+ gcmkHEADER();
+
+ gcmkVERIFY_ARGUMENT(In != gcvNULL);
+
+ if (gckHARDWARE_IsFeatureAvailable(Mmu->hardware, gcvFEATURE_MMU) == gcvFALSE)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ for (i = 0; i < Mmu->flatMappingRangeCount; i++)
+ {
+ if ((Physical >= Mmu->flatMappingRanges[i].start) &&
+ (Physical < Mmu->flatMappingRanges[i].end))
+ {
+ inFlatmapping = gcvTRUE;
+ break;
+ }
+ }
+
+ *In = inFlatmapping;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckMMU_AttachHardware(
+ IN gckMMU Mmu,
+ IN gckHARDWARE Hardware
+ )
+{
+ gcmkHEADER();
+
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, _GC_OBJ_ZONE, "Attach core %d", Hardware->core);
+
+ gcsLIST_Add(&Hardware->mmuHead, &Mmu->hardwareList);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+
+#if !gcdPROCESS_ADDRESS_SPACE
+gceSTATUS
+gckMMU_GetPageEntry(
+ IN gckMMU Mmu,
+ IN gctUINT32 Address,
+ IN gctUINT32_PTR *PageTable
+ )
+{
+ gctUINT32_PTR pageTable;
+ gctUINT32 index;
+ gctUINT32 mtlb, stlb;
+ gcsADDRESS_AREA_PTR area = &Mmu->area[0];
+
+ gcmkHEADER_ARG("Mmu=0x%08X Address=0x%08X", Mmu, Address);
+ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+
+ gcmkASSERT(Mmu->hardware->mmuVersion > 0);
+
+ mtlb = (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT;
+
+ if (mtlb >= area->dynamicMappingStart)
+ {
+ stlb = (Address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT;
+
+ pageTable = area->pageTableLogical;
+
+ index = (mtlb - area->dynamicMappingStart)
+ * gcdMMU_STLB_4K_ENTRY_NUM
+ + stlb;
+
+ *PageTable = pageTable + index;
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+#endif
+
+/******************************************************************************
+****************************** T E S T C O D E ******************************
+******************************************************************************/
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu_vg.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu_vg.c
new file mode 100644
index 000000000000..f6e687b22af2
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_mmu_vg.c
@@ -0,0 +1,556 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#if gcdENABLE_VG
+
+#define _GC_OBJ_ZONE gcvZONE_MMU
+
+/*******************************************************************************
+**
+** gckVGMMU_Construct
+**
+** Construct a new gckVGMMU object.
+**
+** INPUT:
+**
+** gckVGKERNEL Kernel
+** Pointer to an gckVGKERNEL object.
+**
+** gctSIZE_T MmuSize
+** Number of bytes for the page table.
+**
+** OUTPUT:
+**
+** gckVGMMU * Mmu
+** Pointer to a variable that receives the gckVGMMU object pointer.
+*/
+gceSTATUS gckVGMMU_Construct(
+ IN gckVGKERNEL Kernel,
+ IN gctUINT32 MmuSize,
+ OUT gckVGMMU * Mmu
+ )
+{
+ gckOS os;
+ gckVGHARDWARE hardware;
+ gceSTATUS status;
+ gckVGMMU mmu;
+ gctUINT32 * pageTable;
+ gctUINT32 i;
+
+ gcmkHEADER_ARG("Kernel=0x%x MmuSize=0x%x Mmu=0x%x", Kernel, MmuSize, Mmu);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(MmuSize > 0);
+ gcmkVERIFY_ARGUMENT(Mmu != gcvNULL);
+
+ /* Extract the gckOS object pointer. */
+ os = Kernel->os;
+ gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+ /* Extract the gckVGHARDWARE object pointer. */
+ hardware = Kernel->hardware;
+ gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE);
+
+ /* Allocate memory for the gckVGMMU object. */
+ status = gckOS_Allocate(os, sizeof(struct _gckVGMMU), (gctPOINTER *) &mmu);
+
+ if (status < 0)
+ {
+ /* Error. */
+ gcmkFATAL(
+ "%s(%d): could not allocate gckVGMMU object.",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkFOOTER();
+ return status;
+ }
+
+ /* Initialize the gckVGMMU object. */
+ mmu->object.type = gcvOBJ_MMU;
+ mmu->os = os;
+ mmu->hardware = hardware;
+
+ /* Create the mutex. */
+ status = gckOS_CreateMutex(os, &mmu->mutex);
+
+ if (status < 0)
+ {
+ /* Roll back. */
+ mmu->object.type = gcvOBJ_UNKNOWN;
+ gcmkVERIFY_OK(gckOS_Free(os, mmu));
+
+ gcmkFOOTER();
+ /* Error. */
+ return status;
+ }
+
+ /* Allocate the page table. */
+ mmu->pageTableSize = (gctUINT32)MmuSize;
+ status = gckOS_AllocateContiguous(os,
+ gcvFALSE,
+ &mmu->pageTableSize,
+ &mmu->pageTablePhysical,
+ &mmu->pageTableLogical);
+
+ if (status < 0)
+ {
+ /* Roll back. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(os, mmu->mutex));
+
+ mmu->object.type = gcvOBJ_UNKNOWN;
+ gcmkVERIFY_OK(gckOS_Free(os, mmu));
+
+ /* Error. */
+ gcmkFATAL(
+ "%s(%d): could not allocate page table.",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkFOOTER();
+ return status;
+ }
+
+ /* Compute number of entries in page table. */
+ mmu->entryCount = (gctUINT32)mmu->pageTableSize / sizeof(gctUINT32);
+ mmu->entry = 0;
+
+ /* Mark the entire page table as available. */
+ pageTable = (gctUINT32 *) mmu->pageTableLogical;
+ for (i = 0; i < mmu->entryCount; i++)
+ {
+ pageTable[i] = (gctUINT32)~0;
+ }
+
+ /* Set page table address. */
+ status = gckVGHARDWARE_SetMMU(hardware, mmu->pageTableLogical);
+
+ if (status < 0)
+ {
+ /* Free the page table. */
+ gcmkVERIFY_OK(gckOS_FreeContiguous(mmu->os,
+ mmu->pageTablePhysical,
+ mmu->pageTableLogical,
+ mmu->pageTableSize));
+
+ /* Roll back. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(os, mmu->mutex));
+
+ mmu->object.type = gcvOBJ_UNKNOWN;
+ gcmkVERIFY_OK(gckOS_Free(os, mmu));
+
+ /* Error. */
+ gcmkFATAL(
+ "%s(%d): could not program page table.",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkFOOTER();
+ return status;
+ }
+
+ /* Return the gckVGMMU object pointer. */
+ *Mmu = mmu;
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_MMU,
+ "%s(%d): %u entries at %p.(0x%08X)\n",
+ __FUNCTION__, __LINE__,
+ mmu->entryCount,
+ mmu->pageTableLogical,
+ mmu->pageTablePhysical
+ );
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckVGMMU_Destroy
+**
+** Destroy a nAQMMU object.
+**
+** INPUT:
+**
+** gckVGMMU Mmu
+** Pointer to an gckVGMMU object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS gckVGMMU_Destroy(
+ IN gckVGMMU Mmu
+ )
+{
+ gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+
+ /* Free the page table. */
+ gcmkVERIFY_OK(gckOS_FreeContiguous(Mmu->os,
+ Mmu->pageTablePhysical,
+ Mmu->pageTableLogical,
+ Mmu->pageTableSize));
+
+ /* Roll back. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->mutex));
+
+ /* Mark the gckVGMMU object as unknown. */
+ Mmu->object.type = gcvOBJ_UNKNOWN;
+
+ /* Free the gckVGMMU object. */
+ gcmkVERIFY_OK(gckOS_Free(Mmu->os, Mmu));
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckVGMMU_AllocatePages
+**
+** Allocate pages inside the page table.
+**
+** INPUT:
+**
+** gckVGMMU Mmu
+** Pointer to an gckVGMMU object.
+**
+** gctSIZE_T PageCount
+** Number of pages to allocate.
+**
+** OUTPUT:
+**
+** gctPOINTER * PageTable
+** Pointer to a variable that receives the base address of the page
+** table.
+**
+** gctUINT32 * Address
+** Pointer to a variable that receives the hardware specific address.
+*/
+gceSTATUS gckVGMMU_AllocatePages(
+ IN gckVGMMU Mmu,
+ IN gctSIZE_T PageCount,
+ OUT gctPOINTER * PageTable,
+ OUT gctUINT32 * Address
+ )
+{
+ gceSTATUS status;
+ gctUINT32 tail, index, i;
+ gctUINT32 * table;
+ gctBOOL allocated = gcvFALSE;
+
+ gcmkHEADER_ARG("Mmu=0x%x PageCount=0x%x PageTable=0x%x Address=0x%x",
+ Mmu, PageCount, PageTable, Address);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+ gcmkVERIFY_ARGUMENT(PageCount > 0);
+ gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_MMU,
+ "%s(%d): %u pages.\n",
+ __FUNCTION__, __LINE__,
+ PageCount
+ );
+
+ if (PageCount > Mmu->entryCount)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_MMU,
+ "%s(%d): page table too small for %u pages.\n",
+ __FUNCTION__, __LINE__,
+ PageCount
+ );
+
+ gcmkFOOTER_NO();
+ /* Not enough pages avaiable. */
+ return gcvSTATUS_OUT_OF_RESOURCES;
+ }
+
+ /* Grab the mutex. */
+ status = gckOS_AcquireMutex(Mmu->os, Mmu->mutex, gcvINFINITE);
+
+ if (status < 0)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_MMU,
+ "%s(%d): could not acquire mutex.\n"
+ ,__FUNCTION__, __LINE__
+ );
+
+ gcmkFOOTER();
+ /* Error. */
+ return status;
+ }
+
+ /* Compute the tail for this allocation. */
+ tail = Mmu->entryCount - (gctUINT32)PageCount;
+
+ /* Walk all entries until we find enough slots. */
+ for (index = Mmu->entry; index <= tail;)
+ {
+ /* Access page table. */
+ table = (gctUINT32 *) Mmu->pageTableLogical + index;
+
+ /* See if all slots are available. */
+ for (i = 0; i < PageCount; i++, table++)
+ {
+ if (*table != ~0)
+ {
+ /* Start from next slot. */
+ index += i + 1;
+ break;
+ }
+ }
+
+ if (i == PageCount)
+ {
+ /* Bail out if we have enough page entries. */
+ allocated = gcvTRUE;
+ break;
+ }
+ }
+
+ if (!allocated)
+ {
+ if (status >= 0)
+ {
+ /* Walk all entries until we find enough slots. */
+ for (index = 0; index <= tail;)
+ {
+ /* Access page table. */
+ table = (gctUINT32 *) Mmu->pageTableLogical + index;
+
+ /* See if all slots are available. */
+ for (i = 0; i < PageCount; i++, table++)
+ {
+ if (*table != ~0)
+ {
+ /* Start from next slot. */
+ index += i + 1;
+ break;
+ }
+ }
+
+ if (i == PageCount)
+ {
+ /* Bail out if we have enough page entries. */
+ allocated = gcvTRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!allocated && (status >= 0))
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_MMU,
+ "%s(%d): not enough free pages for %u pages.\n",
+ __FUNCTION__, __LINE__,
+ PageCount
+ );
+
+ /* Not enough empty slots available. */
+ status = gcvSTATUS_OUT_OF_RESOURCES;
+ }
+
+ if (status >= 0)
+ {
+ /* Build virtual address. */
+ status = gckVGHARDWARE_BuildVirtualAddress(Mmu->hardware,
+ index,
+ 0,
+ Address);
+
+ if (status >= 0)
+ {
+ /* Update current entry into page table. */
+ Mmu->entry = index + (gctUINT32)PageCount;
+
+ /* Return pointer to page table. */
+ *PageTable = (gctUINT32 *) Mmu->pageTableLogical + index;
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_MMU,
+ "%s(%d): allocated %u pages at index %u (0x%08X) @ %p.\n",
+ __FUNCTION__, __LINE__,
+ PageCount,
+ index,
+ *Address,
+ *PageTable
+ );
+ }
+ }
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->mutex));
+ gcmkFOOTER();
+
+ /* Return status. */
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckVGMMU_FreePages
+**
+** Free pages inside the page table.
+**
+** INPUT:
+**
+** gckVGMMU Mmu
+** Pointer to an gckVGMMU object.
+**
+** gctPOINTER PageTable
+** Base address of the page table to free.
+**
+** gctSIZE_T PageCount
+** Number of pages to free.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS gckVGMMU_FreePages(
+ IN gckVGMMU Mmu,
+ IN gctPOINTER PageTable,
+ IN gctSIZE_T PageCount
+ )
+{
+ gctUINT32 * table;
+
+ gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=0x%x",
+ Mmu, PageTable, PageCount);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+ gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
+ gcmkVERIFY_ARGUMENT(PageCount > 0);
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_MMU,
+ "%s(%d): freeing %u pages at index %u @ %p.\n",
+ __FUNCTION__, __LINE__,
+ PageCount,
+ ((gctUINT32 *) PageTable - (gctUINT32 *) Mmu->pageTableLogical),
+ PageTable
+ );
+
+ /* Convert pointer. */
+ table = (gctUINT32 *) PageTable;
+
+ /* Mark the page table entries as available. */
+ while (PageCount-- > 0)
+ {
+ *table++ = (gctUINT32)~0;
+ }
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckVGMMU_SetPage(
+ IN gckVGMMU Mmu,
+ IN gctUINT32 PageAddress,
+ IN gctUINT32 *PageEntry
+ )
+{
+ gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU);
+ gcmkVERIFY_ARGUMENT(PageEntry != gcvNULL);
+ gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFF));
+
+ *PageEntry = PageAddress;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckVGMMU_Flush(
+ IN gckVGMMU Mmu
+ )
+{
+ gckVGHARDWARE hardware;
+
+ gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+ hardware = Mmu->hardware;
+ gcmkVERIFY_OK(
+ gckOS_AtomSet(hardware->os, hardware->pageTableDirty, 1));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+#endif /* gcdENABLE_VG */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_power.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_power.c
new file mode 100644
index 000000000000..92839cb6227f
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_power.c
@@ -0,0 +1,381 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#define _GC_OBJ_ZONE gcvZONE_POWER
+
+/******************************************************************************\
+************************ Dynamic Voltage Frequency Setting *********************
+\******************************************************************************/
+#if gcdDVFS
+static gctUINT32
+_GetLoadHistory(
+ IN gckDVFS Dvfs,
+ IN gctUINT32 Select,
+ IN gctUINT32 Index
+)
+{
+ return Dvfs->loads[Index];
+}
+
+static void
+_IncreaseScale(
+ IN gckDVFS Dvfs,
+ IN gctUINT32 Load,
+ OUT gctUINT8 *Scale
+ )
+{
+ if (Dvfs->currentScale < 32)
+ {
+ *Scale = Dvfs->currentScale + 8;
+ }
+ else
+ {
+ *Scale = Dvfs->currentScale + 8;
+ *Scale = gcmMIN(64, *Scale);
+ }
+}
+
+static void
+_RecordFrequencyHistory(
+ gckDVFS Dvfs,
+ gctUINT32 Frequency
+ )
+{
+ gctUINT32 i = 0;
+
+ struct _FrequencyHistory *history = Dvfs->frequencyHistory;
+
+ for (i = 0; i < 16; i++)
+ {
+ if (history->frequency == Frequency)
+ {
+ break;
+ }
+
+ if (history->frequency == 0)
+ {
+ history->frequency = Frequency;
+ break;
+ }
+
+ history++;
+ }
+
+ if (i < 16)
+ {
+ history->count++;
+ }
+}
+
+static gctUINT32
+_GetFrequencyHistory(
+ gckDVFS Dvfs,
+ gctUINT32 Frequency
+ )
+{
+ gctUINT32 i = 0;
+
+ struct _FrequencyHistory * history = Dvfs->frequencyHistory;
+
+ for (i = 0; i < 16; i++)
+ {
+ if (history->frequency == Frequency)
+ {
+ break;
+ }
+
+ history++;
+ }
+
+ if (i < 16)
+ {
+ return history->count;
+ }
+
+ return 0;
+}
+
+static void
+_Policy(
+ IN gckDVFS Dvfs,
+ IN gctUINT32 Load,
+ OUT gctUINT8 *Scale
+ )
+{
+ gctUINT8 load[4], nextLoad;
+ gctUINT8 scale;
+
+ /* Last 4 history. */
+ load[0] = (Load & 0xFF);
+ load[1] = (Load & 0xFF00) >> 8;
+ load[2] = (Load & 0xFF0000) >> 16;
+ load[3] = (Load & 0xFF000000) >> 24;
+
+ /* Determine target scale. */
+ if (load[0] > 54)
+ {
+ _IncreaseScale(Dvfs, Load, &scale);
+ }
+ else
+ {
+ nextLoad = (load[0] + load[1] + load[2] + load[3])/4;
+
+ scale = Dvfs->currentScale * (nextLoad) / 54;
+
+ scale = gcmMAX(1, scale);
+ scale = gcmMIN(64, scale);
+ }
+
+ Dvfs->totalConfig++;
+
+ Dvfs->loads[(load[0]-1)/8]++;
+
+ *Scale = scale;
+
+
+ if (Dvfs->totalConfig % 100 == 0)
+ {
+ gcmkPRINT("=======================================================");
+ gcmkPRINT("GPU Load: %-8d %-8d %-8d %-8d %-8d %-8d %-8d %-8d",
+ 8, 16, 24, 32, 40, 48, 56, 64);
+ gcmkPRINT(" %-8d %-8d %-8d %-8d %-8d %-8d %-8d %-8d",
+ _GetLoadHistory(Dvfs,2, 0),
+ _GetLoadHistory(Dvfs,2, 1),
+ _GetLoadHistory(Dvfs,2, 2),
+ _GetLoadHistory(Dvfs,2, 3),
+ _GetLoadHistory(Dvfs,2, 4),
+ _GetLoadHistory(Dvfs,2, 5),
+ _GetLoadHistory(Dvfs,2, 6),
+ _GetLoadHistory(Dvfs,2, 7)
+ );
+
+ gcmkPRINT("Frequency(MHz) %-8d %-8d %-8d %-8d %-8d",
+ 58, 120, 240, 360, 480);
+ gcmkPRINT(" %-8d %-8d %-8d %-8d %-8d",
+ _GetFrequencyHistory(Dvfs, 58),
+ _GetFrequencyHistory(Dvfs,120),
+ _GetFrequencyHistory(Dvfs,240),
+ _GetFrequencyHistory(Dvfs,360),
+ _GetFrequencyHistory(Dvfs,480)
+ );
+ }
+}
+
+static void
+_TimerFunction(
+ gctPOINTER Data
+ )
+{
+ gceSTATUS status;
+ gckDVFS dvfs = (gckDVFS) Data;
+ gckHARDWARE hardware = dvfs->hardware;
+ gctUINT32 value;
+ gctUINT32 frequency;
+ gctUINT8 scale;
+ gctUINT32 t1, t2, consumed;
+
+ gckOS_GetTicks(&t1);
+
+ gcmkONERROR(gckHARDWARE_QueryLoad(hardware, &value));
+
+ /* determine target sacle. */
+ _Policy(dvfs, value, &scale);
+
+ /* Set frequency and voltage. */
+ gcmkONERROR(gckOS_SetGPUFrequency(hardware->os, hardware->core, scale));
+
+ /* Query real frequency. */
+ gcmkONERROR(
+ gckOS_QueryGPUFrequency(hardware->os,
+ hardware->core,
+ &frequency,
+ &dvfs->currentScale));
+
+ _RecordFrequencyHistory(dvfs, frequency);
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_POWER,
+ "Current frequency = %d",
+ frequency);
+
+ /* Set period. */
+ gcmkONERROR(gckHARDWARE_SetDVFSPeroid(hardware, frequency));
+
+OnError:
+ /* Determine next querying time. */
+ gckOS_GetTicks(&t2);
+
+ consumed = gcmMIN(((long)t2 - (long)t1), 5);
+
+ if (dvfs->stop == gcvFALSE)
+ {
+ gcmkVERIFY_OK(gckOS_StartTimer(hardware->os,
+ dvfs->timer,
+ dvfs->pollingTime - consumed));
+ }
+
+ return;
+}
+
+gceSTATUS
+gckDVFS_Construct(
+ IN gckHARDWARE Hardware,
+ OUT gckDVFS * Dvfs
+ )
+{
+ gceSTATUS status;
+ gctPOINTER pointer;
+ gckDVFS dvfs = gcvNULL;
+ gckOS os = Hardware->os;
+
+ gcmkHEADER_ARG("Hardware=0x%X", Hardware);
+
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+ gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL);
+
+ /* Allocate a gckDVFS manager. */
+ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckDVFS), &pointer));
+
+ gckOS_ZeroMemory(pointer, gcmSIZEOF(struct _gckDVFS));
+
+ dvfs = pointer;
+
+ /* Initialization. */
+ dvfs->hardware = Hardware;
+ dvfs->pollingTime = gcdDVFS_POLLING_TIME;
+ dvfs->os = Hardware->os;
+ dvfs->currentScale = 64;
+
+ /* Create a polling timer. */
+ gcmkONERROR(gckOS_CreateTimer(os, _TimerFunction, pointer, &dvfs->timer));
+
+ /* Initialize frequency and voltage adjustment helper. */
+ gcmkONERROR(gckOS_PrepareGPUFrequency(os, Hardware->core));
+
+ /* Return result. */
+ *Dvfs = dvfs;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Roll back. */
+ if (dvfs)
+ {
+ if (dvfs->timer)
+ {
+ gcmkVERIFY_OK(gckOS_DestroyTimer(os, dvfs->timer));
+ }
+
+ gcmkOS_SAFE_FREE(os, dvfs);
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckDVFS_Destroy(
+ IN gckDVFS Dvfs
+ )
+{
+ gcmkHEADER_ARG("Dvfs=0x%X", Dvfs);
+ gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL);
+
+ /* Deinitialize helper fuunction. */
+ gcmkVERIFY_OK(gckOS_FinishGPUFrequency(Dvfs->os, Dvfs->hardware->core));
+
+ /* DestroyTimer. */
+ gcmkVERIFY_OK(gckOS_DestroyTimer(Dvfs->os, Dvfs->timer));
+
+ gcmkOS_SAFE_FREE(Dvfs->os, Dvfs);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckDVFS_Start(
+ IN gckDVFS Dvfs
+ )
+{
+ gcmkHEADER_ARG("Dvfs=0x%X", Dvfs);
+ gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL);
+
+ gckHARDWARE_InitDVFS(Dvfs->hardware);
+
+ Dvfs->stop = gcvFALSE;
+
+ gckOS_StartTimer(Dvfs->os, Dvfs->timer, Dvfs->pollingTime);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckDVFS_Stop(
+ IN gckDVFS Dvfs
+ )
+{
+ gcmkHEADER_ARG("Dvfs=0x%X", Dvfs);
+ gcmkVERIFY_ARGUMENT(Dvfs != gcvNULL);
+
+ Dvfs->stop = gcvTRUE;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+#endif
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_precomp.h b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_precomp.h
new file mode 100644
index 000000000000..ee2b12245e8c
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_precomp.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_precomp_h_
+#define __gc_hal_kernel_precomp_h_
+
+#include "gc_hal.h"
+#include "gc_hal_driver.h"
+#include "gc_hal_kernel.h"
+
+#endif /* __gc_hal_kernel_precomp_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_security.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_security.c
new file mode 100644
index 000000000000..6c169a2a536a
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_security.c
@@ -0,0 +1,284 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+
+
+
+#define _GC_OBJ_ZONE gcvZONE_KERNEL
+
+#if gcdSECURITY
+
+/*
+** Open a security service channel.
+*/
+gceSTATUS
+gckKERNEL_SecurityOpen(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 GPU,
+ OUT gctUINT32 *Channel
+ )
+{
+ gceSTATUS status;
+
+ gcmkONERROR(gckOS_OpenSecurityChannel(Kernel->os, Kernel->core, Channel));
+ gcmkONERROR(gckOS_InitSecurityChannel(*Channel));
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+/*
+** Close a security service channel
+*/
+gceSTATUS
+gckKERNEL_SecurityClose(
+ IN gctUINT32 Channel
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+/*
+** Security service interface.
+*/
+gceSTATUS
+gckKERNEL_SecurityCallService(
+ IN gctUINT32 Channel,
+ IN OUT gcsTA_INTERFACE * Interface
+)
+{
+ gceSTATUS status;
+ gcmkHEADER();
+
+ gcmkVERIFY_ARGUMENT(Interface != gcvNULL);
+
+ gckOS_CallSecurityService(Channel, Interface);
+
+ status = Interface->result;
+
+ gcmkONERROR(status);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityStartCommand(
+ IN gckKERNEL Kernel
+ )
+{
+ gceSTATUS status;
+ gcsTA_INTERFACE iface;
+
+ gcmkHEADER();
+
+ iface.command = KERNEL_START_COMMAND;
+ iface.u.StartCommand.gpu = Kernel->core;
+
+ gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityAllocateSecurityMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Bytes,
+ OUT gctUINT32 * Handle
+ )
+{
+ gceSTATUS status;
+ gcsTA_INTERFACE iface;
+
+ gcmkHEADER();
+
+ iface.command = KERNEL_ALLOCATE_SECRUE_MEMORY;
+ iface.u.AllocateSecurityMemory.bytes = Bytes;
+
+ gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+ *Handle = iface.u.AllocateSecurityMemory.memory_handle;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityExecute(
+ IN gckKERNEL Kernel,
+ IN gctPOINTER Buffer,
+ IN gctUINT32 Bytes
+ )
+{
+ gceSTATUS status;
+#if defined(LINUX)
+ gctPHYS_ADDR_T physical;
+ gctUINT32 address;
+#endif
+ gcsTA_INTERFACE iface;
+
+ gcmkHEADER();
+
+ iface.command = KERNEL_EXECUTE;
+ iface.u.Execute.command_buffer = (gctUINT32 *)Buffer;
+ iface.u.Execute.gpu = Kernel->core;
+ iface.u.Execute.command_buffer_length = Bytes;
+
+#if defined(LINUX)
+ gcmkONERROR(gckOS_GetPhysicalAddress(Kernel->os, Buffer, &physical));
+ gcmkSAFECASTPHYSADDRT(address, physical);
+
+ iface.u.Execute.command_buffer = (gctUINT32 *)address;
+#endif
+
+ gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+ /* Update queue tail pointer. */
+ gcmkONERROR(gckHARDWARE_UpdateQueueTail(
+ Kernel->hardware, 0, 0
+ ));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityMapMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 *PhysicalArray,
+ IN gctUINT32 PageCount,
+ OUT gctUINT32 * GPUAddress
+ )
+{
+ gceSTATUS status;
+ gcsTA_INTERFACE iface;
+#if defined(LINUX)
+ gctPHYS_ADDR_T physical;
+ gctUINT32 address;
+#endif
+
+ gcmkHEADER();
+
+ iface.command = KERNEL_MAP_MEMORY;
+
+#if defined(LINUX)
+ gcmkONERROR(gckOS_GetPhysicalAddress(Kernel->os, PhysicalArray, &physical));
+ gcmkSAFECASTPHYSADDRT(address, physical);
+ iface.u.MapMemory.physicals = (gctUINT32 *)address;
+#endif
+
+ iface.u.MapMemory.pageCount = PageCount;
+
+ gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+ *GPUAddress = iface.u.MapMemory.gpuAddress;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityUnmapMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 GPUAddress,
+ IN gctUINT32 PageCount
+ )
+{
+ gceSTATUS status;
+ gcsTA_INTERFACE iface;
+
+ gcmkHEADER();
+
+ iface.command = KERNEL_UNMAP_MEMORY;
+
+ iface.u.UnmapMemory.gpuAddress = GPUAddress;
+ iface.u.UnmapMemory.pageCount = PageCount;
+
+ gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+#endif
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_security_v1.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_security_v1.c
new file mode 100644
index 000000000000..89a4333f6f2f
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_security_v1.c
@@ -0,0 +1,320 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+
+
+
+#define _GC_OBJ_ZONE gcvZONE_KERNEL
+
+#if gcdENABLE_TRUST_APPLICATION
+
+/*
+** Open a security service channel.
+*/
+gceSTATUS
+gckKERNEL_SecurityOpen(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 GPU,
+ OUT gctUINT32 *Channel
+ )
+{
+ gceSTATUS status;
+
+ gcmkONERROR(gckOS_OpenSecurityChannel(Kernel->os, Kernel->core, Channel));
+ gcmkONERROR(gckOS_InitSecurityChannel(*Channel));
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+/*
+** Close a security service channel
+*/
+gceSTATUS
+gckKERNEL_SecurityClose(
+ IN gctUINT32 Channel
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+/*
+** Security service interface.
+*/
+gceSTATUS
+gckKERNEL_SecurityCallService(
+ IN gctUINT32 Channel,
+ IN OUT gcsTA_INTERFACE * Interface
+)
+{
+ gceSTATUS status;
+ gcmkHEADER();
+
+ gcmkVERIFY_ARGUMENT(Interface != gcvNULL);
+
+ gckOS_CallSecurityService(Channel, Interface);
+
+ status = Interface->result;
+
+ gcmkONERROR(status);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityStartCommand(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Address,
+ IN gctUINT32 Bytes
+ )
+{
+ gceSTATUS status;
+ gcsTA_INTERFACE iface;
+
+ gcmkHEADER();
+
+ iface.command = KERNEL_START_COMMAND;
+ iface.u.StartCommand.gpu = Kernel->core;
+ iface.u.StartCommand.address = Address;
+ iface.u.StartCommand.bytes = Bytes;
+
+ gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityAllocateSecurityMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Bytes,
+ OUT gctUINT32 * Handle
+ )
+{
+ gceSTATUS status;
+ gcsTA_INTERFACE iface;
+
+ gcmkHEADER();
+
+ iface.command = KERNEL_ALLOCATE_SECRUE_MEMORY;
+ iface.u.AllocateSecurityMemory.bytes = Bytes;
+
+ gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+ *Handle = iface.u.AllocateSecurityMemory.memory_handle;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityMapMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 *PhysicalArray,
+ IN gctPHYS_ADDR_T Physical,
+ IN gctUINT32 PageCount,
+ OUT gctUINT32 * GPUAddress
+ )
+{
+ gceSTATUS status;
+ gcsTA_INTERFACE iface;
+
+ gcmkHEADER();
+
+ iface.command = KERNEL_MAP_MEMORY;
+
+ iface.u.MapMemory.physicals = PhysicalArray;
+ iface.u.MapMemory.physical = Physical;
+ iface.u.MapMemory.pageCount = PageCount;
+ iface.u.MapMemory.gpuAddress = *GPUAddress;
+
+ gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_SecurityDumpMMUException(
+ IN gckKERNEL Kernel
+ )
+{
+ gceSTATUS status;
+ gcsTA_INTERFACE iface;
+
+ gcmkHEADER();
+
+ iface.command = KERNEL_DUMP_MMU_EXCEPTION;
+
+ gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+
+
+gceSTATUS
+gckKERNEL_SecurityUnmapMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 GPUAddress,
+ IN gctUINT32 PageCount
+ )
+{
+ gceSTATUS status;
+ gcsTA_INTERFACE iface;
+
+ gcmkHEADER();
+
+ iface.command = KERNEL_UNMAP_MEMORY;
+
+ iface.u.UnmapMemory.gpuAddress = GPUAddress;
+ iface.u.UnmapMemory.pageCount = PageCount;
+
+ gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_ReadMMUException(
+ IN gckKERNEL Kernel,
+ IN gctUINT32_PTR MMUStatus,
+ IN gctUINT32_PTR MMUException
+ )
+{
+ gceSTATUS status;
+ gcsTA_INTERFACE iface;
+
+ gcmkHEADER();
+
+ iface.command = KERNEL_READ_MMU_EXCEPTION;
+
+ gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+ *MMUStatus = iface.u.ReadMMUException.mmuStatus;
+ *MMUException = iface.u.ReadMMUException.mmuException;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_HandleMMUException(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 MMUStatus,
+ IN gctPHYS_ADDR_T Physical,
+ IN gctUINT32 GPUAddress
+ )
+{
+ gceSTATUS status;
+ gcsTA_INTERFACE iface;
+
+ gcmkHEADER();
+
+ iface.command = KERNEL_HANDLE_MMU_EXCEPTION;
+
+ iface.u.HandleMMUException.mmuStatus = MMUStatus;
+ iface.u.HandleMMUException.physical = Physical;
+ iface.u.HandleMMUException.gpuAddress = GPUAddress;
+
+ gcmkONERROR(gckKERNEL_SecurityCallService(Kernel->securityChannel, &iface));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+
+
+
+#endif
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_vg.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_vg.c
new file mode 100644
index 000000000000..93a914c9d79a
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_vg.c
@@ -0,0 +1,643 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#if gcdENABLE_VG
+
+#define _GC_OBJ_ZONE gcvZONE_VG
+
+/******************************************************************************\
+******************************* gckKERNEL API Code ******************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+** gckKERNEL_Construct
+**
+** Construct a new gckKERNEL object.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** IN gctPOINTER Context
+** Pointer to a driver defined context.
+**
+** OUTPUT:
+**
+** gckKERNEL * Kernel
+** Pointer to a variable that will hold the pointer to the gckKERNEL
+** object.
+*/
+gceSTATUS gckVGKERNEL_Construct(
+ IN gckOS Os,
+ IN gctPOINTER Context,
+ IN gckKERNEL inKernel,
+ OUT gckVGKERNEL * Kernel
+ )
+{
+ gceSTATUS status;
+ gckVGKERNEL kernel = gcvNULL;
+
+ gcmkHEADER_ARG("Os=0x%x Context=0x%x", Os, Context);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Kernel != gcvNULL);
+
+ do
+ {
+ /* Allocate the gckKERNEL object. */
+ gcmkERR_BREAK(gckOS_Allocate(
+ Os,
+ sizeof(struct _gckVGKERNEL),
+ (gctPOINTER *) &kernel
+ ));
+
+ /* Initialize the gckKERNEL object. */
+ kernel->object.type = gcvOBJ_KERNEL;
+ kernel->os = Os;
+ kernel->context = Context;
+ kernel->hardware = gcvNULL;
+ kernel->interrupt = gcvNULL;
+ kernel->command = gcvNULL;
+ kernel->mmu = gcvNULL;
+ kernel->kernel = inKernel;
+
+ /* Construct the gckVGHARDWARE object. */
+ gcmkERR_BREAK(gckVGHARDWARE_Construct(
+ Os, &kernel->hardware
+ ));
+
+ /* Set pointer to gckKERNEL object in gckVGHARDWARE object. */
+ kernel->hardware->kernel = kernel;
+
+ /* Construct the gckVGINTERRUPT object. */
+ gcmkERR_BREAK(gckVGINTERRUPT_Construct(
+ kernel, &kernel->interrupt
+ ));
+
+ /* Construct the gckVGCOMMAND object. */
+ gcmkERR_BREAK(gckVGCOMMAND_Construct(
+ kernel, gcmKB2BYTES(8), gcmKB2BYTES(2), &kernel->command
+ ));
+
+ /* Construct the gckVGMMU object. */
+ gcmkERR_BREAK(gckVGMMU_Construct(
+ kernel, gcmKB2BYTES(gcdGC355_VGMMU_MEMORY_SIZE_KB), &kernel->mmu
+ ));
+
+ /* Return pointer to the gckKERNEL object. */
+ *Kernel = kernel;
+
+ gcmkFOOTER_ARG("*Kernel=0x%x", *Kernel);
+ /* Success. */
+ return gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ /* Roll back. */
+ if (kernel != gcvNULL)
+ {
+ if (kernel->mmu != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckVGMMU_Destroy(kernel->mmu));
+ }
+
+ if (kernel->command != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckVGCOMMAND_Destroy(kernel->command));
+ }
+
+ if (kernel->interrupt != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckVGINTERRUPT_Destroy(kernel->interrupt));
+ }
+
+ if (kernel->hardware != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckVGHARDWARE_Destroy(kernel->hardware));
+ }
+
+ gcmkVERIFY_OK(gckOS_Free(Os, kernel));
+ }
+
+ gcmkFOOTER();
+ /* Return status. */
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_Destroy
+**
+** Destroy an gckKERNEL object.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object to destroy.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS gckVGKERNEL_Destroy(
+ IN gckVGKERNEL Kernel
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Kernel=0x%x", Kernel);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+ do
+ {
+ /* Destroy the gckVGMMU object. */
+ if (Kernel->mmu != gcvNULL)
+ {
+ gcmkERR_BREAK(gckVGMMU_Destroy(Kernel->mmu));
+ Kernel->mmu = gcvNULL;
+ }
+
+ /* Destroy the gckVGCOMMAND object. */
+ if (Kernel->command != gcvNULL)
+ {
+ gcmkERR_BREAK(gckVGCOMMAND_Destroy(Kernel->command));
+ Kernel->command = gcvNULL;
+ }
+
+ /* Destroy the gckVGINTERRUPT object. */
+ if (Kernel->interrupt != gcvNULL)
+ {
+ gcmkERR_BREAK(gckVGINTERRUPT_Destroy(Kernel->interrupt));
+ Kernel->interrupt = gcvNULL;
+ }
+
+ /* Destroy the gckVGHARDWARE object. */
+ if (Kernel->hardware != gcvNULL)
+ {
+ gcmkERR_BREAK(gckVGHARDWARE_Destroy(Kernel->hardware));
+ Kernel->hardware = gcvNULL;
+ }
+
+ /* Mark the gckKERNEL object as unknown. */
+ Kernel->object.type = gcvOBJ_UNKNOWN;
+
+ /* Free the gckKERNEL object. */
+ gcmkERR_BREAK(gckOS_Free(Kernel->os, Kernel));
+ }
+ while (gcvFALSE);
+
+ gcmkFOOTER();
+
+ /* Return status. */
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_Dispatch
+**
+** Dispatch a command received from the user HAL layer.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gcsHAL_INTERFACE * Interface
+** Pointer to a gcsHAL_INTERFACE structure that defines the command to
+** be dispatched.
+**
+** OUTPUT:
+**
+** gcsHAL_INTERFACE * Interface
+** Pointer to a gcsHAL_INTERFACE structure that receives any data to be
+** returned.
+*/
+gceSTATUS gckVGKERNEL_Dispatch(
+ IN gckKERNEL Kernel,
+ IN gctBOOL FromUser,
+ IN OUT gcsHAL_INTERFACE * Interface
+ )
+{
+ gceSTATUS status;
+ gcsHAL_INTERFACE * kernelInterface = Interface;
+ gctUINT32 processID;
+ gckKERNEL kernel = Kernel;
+ gctPHYS_ADDR physical = gcvNULL;
+ gctPOINTER logical = gcvNULL;
+ gctSIZE_T bytes = 0;
+ gctBOOL powerMutexAcquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Kernel=0x%x Interface=0x%x ", Kernel, Interface);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Interface != gcvNULL);
+
+ gcmkONERROR(gckOS_GetProcessID(&processID));
+
+ /* Dispatch on command. */
+ switch (Interface->command)
+ {
+ case gcvHAL_QUERY_CHIP_IDENTITY:
+ /* Query chip identity. */
+ gcmkERR_BREAK(gckVGHARDWARE_QueryChipIdentity(
+ Kernel->vg->hardware,
+ &kernelInterface->u.QueryChipIdentity.chipModel,
+ &kernelInterface->u.QueryChipIdentity.chipRevision,
+ &kernelInterface->u.QueryChipIdentity.productID,
+ &kernelInterface->u.QueryChipIdentity.ecoID,
+ &kernelInterface->u.QueryChipIdentity.customerID,
+ &kernelInterface->u.QueryChipIdentity.chipFeatures,
+ &kernelInterface->u.QueryChipIdentity.chipMinorFeatures,
+ &kernelInterface->u.QueryChipIdentity.chipMinorFeatures2
+ ));
+ break;
+
+ case gcvHAL_QUERY_COMMAND_BUFFER:
+ /* Query command buffer information. */
+ gcmkERR_BREAK(gckKERNEL_QueryCommandBuffer(
+ Kernel,
+ &kernelInterface->u.QueryCommandBuffer.information
+ ));
+ break;
+
+ case gcvHAL_ALLOCATE_NON_PAGED_MEMORY:
+ bytes = (gctSIZE_T) kernelInterface->u.AllocateNonPagedMemory.bytes;
+ /* Allocate non-paged memory. */
+ gcmkERR_BREAK(gckOS_AllocateNonPagedMemory(
+ Kernel->os,
+ gcvTRUE,
+ &bytes,
+ &physical,
+ &logical
+ ));
+
+ kernelInterface->u.AllocateNonPagedMemory.bytes = bytes;
+ kernelInterface->u.AllocateNonPagedMemory.logical = gcmPTR_TO_UINT64(logical);
+ kernelInterface->u.AllocateNonPagedMemory.physical = gcmPTR_TO_NAME(physical);
+ break;
+
+ case gcvHAL_FREE_NON_PAGED_MEMORY:
+ physical = gcmNAME_TO_PTR(kernelInterface->u.FreeNonPagedMemory.physical);
+
+ /* Unmap user logical out of physical memory first. */
+ gcmkERR_BREAK(gckOS_UnmapUserLogical(
+ Kernel->os,
+ physical,
+ (gctSIZE_T) kernelInterface->u.FreeNonPagedMemory.bytes,
+ gcmUINT64_TO_PTR(kernelInterface->u.FreeNonPagedMemory.logical)));
+
+
+ /* Free non-paged memory. */
+ gcmkERR_BREAK(gckOS_FreeNonPagedMemory(
+ Kernel->os,
+ (gctSIZE_T) kernelInterface->u.FreeNonPagedMemory.bytes,
+ physical,
+ gcmUINT64_TO_PTR(kernelInterface->u.FreeNonPagedMemory.logical)
+ ));
+
+ gcmRELEASE_NAME(kernelInterface->u.FreeNonPagedMemory.physical);
+ break;
+
+ case gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY:
+ bytes = (gctSIZE_T) kernelInterface->u.AllocateContiguousMemory.bytes;
+ /* Allocate contiguous memory. */
+ gcmkERR_BREAK(gckOS_AllocateContiguous(
+ Kernel->os,
+ gcvTRUE,
+ &bytes,
+ &physical,
+ &logical
+ ));
+
+ kernelInterface->u.AllocateContiguousMemory.bytes = bytes;
+ kernelInterface->u.AllocateContiguousMemory.logical = gcmPTR_TO_UINT64(logical);
+ kernelInterface->u.AllocateContiguousMemory.physical = gcmPTR_TO_NAME(physical);
+ break;
+
+ case gcvHAL_FREE_CONTIGUOUS_MEMORY:
+ physical = gcmNAME_TO_PTR(kernelInterface->u.FreeContiguousMemory.physical);
+ /* Unmap user logical out of physical memory first. */
+ gcmkERR_BREAK(gckOS_UnmapUserLogical(
+ Kernel->os,
+ physical,
+ (gctSIZE_T) kernelInterface->u.FreeContiguousMemory.bytes,
+ gcmUINT64_TO_PTR(kernelInterface->u.FreeContiguousMemory.logical)
+ ));
+
+ /* Free contiguous memory. */
+ gcmkERR_BREAK(gckOS_FreeContiguous(
+ Kernel->os,
+ physical,
+ gcmUINT64_TO_PTR(kernelInterface->u.FreeContiguousMemory.logical),
+ (gctSIZE_T) kernelInterface->u.FreeContiguousMemory.bytes
+ ));
+
+ gcmRELEASE_NAME(kernelInterface->u.FreeContiguousMemory.physical);
+ break;
+
+ case gcvHAL_ALLOCATE_VIDEO_MEMORY:
+ gcmkERR_BREAK(gcvSTATUS_NOT_SUPPORTED);
+ break;
+
+ case gcvHAL_MAP_MEMORY:
+ /* Map memory. */
+ gcmkERR_BREAK(gckKERNEL_MapMemory(
+ Kernel,
+ gcmINT2PTR(kernelInterface->u.MapMemory.physical),
+ (gctSIZE_T) kernelInterface->u.MapMemory.bytes,
+ &logical
+ ));
+ kernelInterface->u.MapMemory.logical = gcmPTR_TO_UINT64(logical);
+ break;
+
+ case gcvHAL_UNMAP_MEMORY:
+ /* Unmap memory. */
+ gcmkERR_BREAK(gckKERNEL_UnmapMemory(
+ Kernel,
+ gcmINT2PTR(kernelInterface->u.MapMemory.physical),
+ (gctSIZE_T) kernelInterface->u.MapMemory.bytes,
+ gcmUINT64_TO_PTR(kernelInterface->u.MapMemory.logical),
+ processID
+ ));
+ break;
+
+ case gcvHAL_MAP_USER_MEMORY:
+
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+
+ break;
+
+ case gcvHAL_UNMAP_USER_MEMORY:
+
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+
+ break;
+
+ case gcvHAL_LOCK_VIDEO_MEMORY:
+ gcmkONERROR(gckKERNEL_LockVideoMemory(Kernel, gcvCORE_VG, processID, FromUser, Interface));
+ break;
+
+ case gcvHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY:
+ gcmkERR_BREAK(gckKERNEL_BottomHalfUnlockVideoMemory(Kernel, processID,
+ kernelInterface->u.BottomHalfUnlockVideoMemory.node));
+ break;
+
+ case gcvHAL_USER_SIGNAL:
+#if !USE_NEW_LINUX_SIGNAL
+ /* Dispatch depends on the user signal subcommands. */
+ switch(Interface->u.UserSignal.command)
+ {
+ case gcvUSER_SIGNAL_CREATE:
+ /* Create a signal used in the user space. */
+ gcmkERR_BREAK(
+ gckOS_CreateUserSignal(Kernel->os,
+ Interface->u.UserSignal.manualReset,
+ &Interface->u.UserSignal.id));
+
+ gcmkVERIFY_OK(
+ gckKERNEL_AddProcessDB(Kernel,
+ processID, gcvDB_SIGNAL,
+ gcmINT2PTR(Interface->u.UserSignal.id),
+ gcvNULL,
+ 0));
+ break;
+
+ case gcvUSER_SIGNAL_DESTROY:
+ gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB(
+ Kernel,
+ processID, gcvDB_SIGNAL,
+ gcmINT2PTR(Interface->u.UserSignal.id)));
+
+ /* Destroy the signal. */
+ gcmkERR_BREAK(
+ gckOS_DestroyUserSignal(Kernel->os,
+ Interface->u.UserSignal.id));
+
+ break;
+
+ case gcvUSER_SIGNAL_SIGNAL:
+ /* Signal the signal. */
+ gcmkERR_BREAK(
+ gckOS_SignalUserSignal(Kernel->os,
+ Interface->u.UserSignal.id,
+ Interface->u.UserSignal.state));
+ break;
+
+ case gcvUSER_SIGNAL_WAIT:
+ /* Wait on the signal. */
+ status = gckOS_WaitUserSignal(Kernel->os,
+ Interface->u.UserSignal.id,
+ Interface->u.UserSignal.wait);
+ break;
+
+ default:
+ /* Invalid user signal command. */
+ gcmkERR_BREAK(gcvSTATUS_INVALID_ARGUMENT);
+ }
+#endif
+ break;
+
+ case gcvHAL_COMMIT:
+ /* Commit a command and context buffer. */
+ gcmkERR_BREAK(gckVGCOMMAND_Commit(
+ Kernel->vg->command,
+ gcmUINT64_TO_PTR(kernelInterface->u.VGCommit.context),
+ gcmUINT64_TO_PTR(kernelInterface->u.VGCommit.queue),
+ kernelInterface->u.VGCommit.entryCount,
+ gcmUINT64_TO_PTR(kernelInterface->u.VGCommit.taskTable)
+ ));
+ break;
+
+ case gcvHAL_GET_BASE_ADDRESS:
+ /* Get base address. */
+ gcmkONERROR(
+ gckOS_GetBaseAddress(Kernel->os,
+ &Interface->u.GetBaseAddress.baseAddress));
+ break;
+
+ case gcvHAL_EVENT_COMMIT:
+ gcmkERR_BREAK(gcvSTATUS_NOT_SUPPORTED);
+ break;
+ case gcvHAL_READ_REGISTER:
+#if gcdREGISTER_ACCESS_FROM_USER
+ {
+ gceCHIPPOWERSTATE power;
+
+ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->vg->hardware->powerMutex, gcvINFINITE));
+ powerMutexAcquired = gcvTRUE;
+ gcmkONERROR(gckVGHARDWARE_QueryPowerManagementState(Kernel->vg->hardware,
+ &power));
+ if (power == gcvPOWER_ON)
+ {
+ /* Read a register. */
+ gcmkONERROR(gckOS_ReadRegisterEx(
+ Kernel->os,
+ Kernel->core,
+ Interface->u.ReadRegisterData.address,
+ &Interface->u.ReadRegisterData.data));
+ }
+ else
+ {
+ /* Chip is in power-state. */
+ Interface->u.ReadRegisterData.data = 0;
+ status = gcvSTATUS_CHIP_NOT_READY;
+ }
+ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->vg->hardware->powerMutex));
+ powerMutexAcquired = gcvFALSE;
+ }
+#else
+ /* No access from user land to read registers. */
+ Interface->u.ReadRegisterData.data = 0;
+ status = gcvSTATUS_NOT_SUPPORTED;
+#endif
+ break;
+
+ case gcvHAL_WRITE_REGISTER:
+#if gcdREGISTER_ACCESS_FROM_USER
+ {
+ gceCHIPPOWERSTATE power;
+
+ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->vg->hardware->powerMutex, gcvINFINITE));
+ powerMutexAcquired = gcvTRUE;
+ gcmkONERROR(gckVGHARDWARE_QueryPowerManagementState(Kernel->vg->hardware,
+ &power));
+ if (power == gcvPOWER_ON)
+ {
+ /* Write a register. */
+ gcmkONERROR(
+ gckOS_WriteRegisterEx(Kernel->os,
+ Kernel->core,
+ Interface->u.WriteRegisterData.address,
+ Interface->u.WriteRegisterData.data));
+ }
+ else
+ {
+ /* Chip is in power-state. */
+ Interface->u.WriteRegisterData.data = 0;
+ status = gcvSTATUS_CHIP_NOT_READY;
+ }
+ gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->vg->hardware->powerMutex));
+ powerMutexAcquired = gcvFALSE;
+ }
+#else
+ /* No access from user land to write registers. */
+ status = gcvSTATUS_NOT_SUPPORTED;
+#endif
+ break;
+ default:
+ /* Invalid command, try gckKERNEL_Dispatch */
+ status = gckKERNEL_Dispatch(Kernel, gcvNULL, gcvTRUE, Interface);
+ }
+
+OnError:
+ /* Save status. */
+ kernelInterface->status = status;
+ if (powerMutexAcquired == gcvTRUE)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->vg->hardware->powerMutex));
+ }
+
+ gcmkFOOTER();
+
+ /* Return the status. */
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_QueryCommandBuffer
+**
+** Query command buffer attributes.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckVGHARDWARE object.
+**
+** OUTPUT:
+**
+** gcsCOMMAND_BUFFER_INFO_PTR Information
+** Pointer to the information structure to receive buffer attributes.
+*/
+gceSTATUS
+gckKERNEL_QueryCommandBuffer(
+ IN gckKERNEL Kernel,
+ OUT gcsCOMMAND_BUFFER_INFO_PTR Information
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Kernel=0x%x *Pool=0x%x",
+ Kernel, Information);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+ /* Get the information. */
+ status = gckVGCOMMAND_QueryCommandBuffer(Kernel->vg->command, Information);
+
+ gcmkFOOTER();
+ /* Return status. */
+ return status;
+}
+
+#endif /* gcdENABLE_VG */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_vg.h b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_vg.h
new file mode 100644
index 000000000000..63da8837d67c
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_vg.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_vg_h_
+#define __gc_hal_kernel_vg_h_
+
+#include "gc_hal.h"
+#include "gc_hal_driver.h"
+#include "gc_hal_kernel_hardware.h"
+
+/******************************************************************************\
+********************************** Structures **********************************
+\******************************************************************************/
+
+/* gckKERNEL object. */
+struct _gckVGKERNEL
+{
+ /* Object. */
+ gcsOBJECT object;
+
+ /* Pointer to gckOS object. */
+ gckOS os;
+
+ /* Pointer to gckHARDWARE object. */
+ gckVGHARDWARE hardware;
+
+ /* Pointer to gckINTERRUPT object. */
+ gckVGINTERRUPT interrupt;
+
+ /* Pointer to gckCOMMAND object. */
+ gckVGCOMMAND command;
+
+ /* Pointer to context. */
+ gctPOINTER context;
+
+ /* Pointer to gckMMU object. */
+ gckVGMMU mmu;
+
+ gckKERNEL kernel;
+};
+
+/* gckMMU object. */
+struct _gckVGMMU
+{
+ /* The object. */
+ gcsOBJECT object;
+
+ /* Pointer to gckOS object. */
+ gckOS os;
+
+ /* Pointer to gckHARDWARE object. */
+ gckVGHARDWARE hardware;
+
+ /* The page table mutex. */
+ gctPOINTER mutex;
+
+ /* Page table information. */
+ gctSIZE_T pageTableSize;
+ gctPHYS_ADDR pageTablePhysical;
+ gctPOINTER pageTableLogical;
+
+ /* Allocation index. */
+ gctUINT32 entryCount;
+ gctUINT32 entry;
+};
+
+#endif /* __gc_hal_kernel_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_video_memory.c b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_video_memory.c
new file mode 100644
index 000000000000..c1b6629a9fcf
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/gc_hal_kernel_video_memory.c
@@ -0,0 +1,3488 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_precomp.h"
+
+#if defined(__QNXNTO__)
+#include <stdlib.h>
+#include <sys/slogcodes.h>
+#include <time.h>
+
+extern unsigned int slogUsageInterval;
+#endif
+
+#define _GC_OBJ_ZONE gcvZONE_VIDMEM
+
+/******************************************************************************\
+******************************* Private Functions ******************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+** _Split
+**
+** Split a node on the required byte boundary.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gcuVIDMEM_NODE_PTR Node
+** Pointer to the node to split.
+**
+** gctSIZE_T Bytes
+** Number of bytes to keep in the node.
+**
+** OUTPUT:
+**
+** Nothing.
+**
+** RETURNS:
+**
+** gctBOOL
+** gcvTRUE if the node was split successfully, or gcvFALSE if there is an
+** error.
+**
+*/
+static gctBOOL
+_Split(
+ IN gckOS Os,
+ IN gcuVIDMEM_NODE_PTR Node,
+ IN gctSIZE_T Bytes
+ )
+{
+ gcuVIDMEM_NODE_PTR node;
+ gctPOINTER pointer = gcvNULL;
+
+ /* Make sure the byte boundary makes sense. */
+ if ((Bytes <= 0) || (Bytes > Node->VidMem.bytes))
+ {
+ return gcvFALSE;
+ }
+
+ /* Allocate a new gcuVIDMEM_NODE object. */
+ if (gcmIS_ERROR(gckOS_Allocate(Os,
+ gcmSIZEOF(gcuVIDMEM_NODE),
+ &pointer)))
+ {
+ /* Error. */
+ return gcvFALSE;
+ }
+
+ node = pointer;
+
+ /* Initialize gcuVIDMEM_NODE structure. */
+ node->VidMem.offset = Node->VidMem.offset + Bytes;
+ node->VidMem.bytes = Node->VidMem.bytes - Bytes;
+ node->VidMem.alignment = 0;
+ node->VidMem.locked = 0;
+ node->VidMem.memory = Node->VidMem.memory;
+ node->VidMem.pool = Node->VidMem.pool;
+ node->VidMem.physical = Node->VidMem.physical;
+#ifdef __QNXNTO__
+ node->VidMem.processID = 0;
+ node->VidMem.logical = gcvNULL;
+#endif
+
+ /* Insert node behind specified node. */
+ node->VidMem.next = Node->VidMem.next;
+ node->VidMem.prev = Node;
+ Node->VidMem.next = node->VidMem.next->VidMem.prev = node;
+
+ /* Insert free node behind specified node. */
+ node->VidMem.nextFree = Node->VidMem.nextFree;
+ node->VidMem.prevFree = Node;
+ Node->VidMem.nextFree = node->VidMem.nextFree->VidMem.prevFree = node;
+
+ /* Adjust size of specified node. */
+ Node->VidMem.bytes = Bytes;
+
+ /* Success. */
+ return gcvTRUE;
+}
+
+/*******************************************************************************
+**
+** _Merge
+**
+** Merge two adjacent nodes together.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gcuVIDMEM_NODE_PTR Node
+** Pointer to the first of the two nodes to merge.
+**
+** OUTPUT:
+**
+** Nothing.
+**
+*/
+static gceSTATUS
+_Merge(
+ IN gckOS Os,
+ IN gcuVIDMEM_NODE_PTR Node
+ )
+{
+ gcuVIDMEM_NODE_PTR node;
+ gceSTATUS status;
+
+ /* Save pointer to next node. */
+ node = Node->VidMem.next;
+
+ /* This is a good time to make sure the heap is not corrupted. */
+ if (Node->VidMem.offset + Node->VidMem.bytes != node->VidMem.offset)
+ {
+ /* Corrupted heap. */
+ gcmkASSERT(
+ Node->VidMem.offset + Node->VidMem.bytes == node->VidMem.offset);
+ return gcvSTATUS_HEAP_CORRUPTED;
+ }
+
+ /* Adjust byte count. */
+ Node->VidMem.bytes += node->VidMem.bytes;
+
+ /* Unlink next node from linked list. */
+ Node->VidMem.next = node->VidMem.next;
+ Node->VidMem.nextFree = node->VidMem.nextFree;
+
+ Node->VidMem.next->VidMem.prev =
+ Node->VidMem.nextFree->VidMem.prevFree = Node;
+
+ /* Free next node. */
+ status = gcmkOS_SAFE_FREE(Os, node);
+ return status;
+}
+
+/******************************************************************************\
+******************************* gckVIDMEM API Code ******************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+** gckVIDMEM_ConstructVirtual
+**
+** Construct a new gcuVIDMEM_NODE union for virtual memory.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctSIZE_T Bytes
+** Number of byte to allocate.
+**
+** OUTPUT:
+**
+** gcuVIDMEM_NODE_PTR * Node
+** Pointer to a variable that receives the gcuVIDMEM_NODE union pointer.
+*/
+gceSTATUS
+gckVIDMEM_ConstructVirtual(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Flag,
+ IN gctSIZE_T Bytes,
+ OUT gcuVIDMEM_NODE_PTR * Node
+ )
+{
+ gckOS os;
+ gceSTATUS status;
+ gcuVIDMEM_NODE_PTR node = gcvNULL;
+ gctPOINTER pointer = gcvNULL;
+ gctINT i;
+
+ gcmkHEADER_ARG("Kernel=0x%x Flag=%x Bytes=%lu", Kernel, Flag, Bytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Node != gcvNULL);
+
+ /* Extract the gckOS object pointer. */
+ os = Kernel->os;
+ gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+ /* Allocate an gcuVIDMEM_NODE union. */
+ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcuVIDMEM_NODE), &pointer));
+
+ node = pointer;
+
+ /* Initialize gcuVIDMEM_NODE union for virtual memory. */
+ node->Virtual.kernel = Kernel;
+ node->Virtual.contiguous = Flag & gcvALLOC_FLAG_CONTIGUOUS;
+ node->Virtual.logical = gcvNULL;
+#if gcdENABLE_VG
+ node->Virtual.kernelVirtual = gcvNULL;
+#endif
+ node->Virtual.secure = (Flag & gcvALLOC_FLAG_SECURITY) != 0;
+ node->Virtual.onFault = (Flag & gcvALLOC_FLAG_ALLOC_ON_FAULT) != 0;
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ node->Virtual.lockeds[i] = 0;
+ node->Virtual.pageTables[i] = gcvNULL;
+ }
+
+ /* Allocate the virtual memory. */
+ gcmkONERROR(
+ gckOS_AllocatePagedMemoryEx(os,
+ Flag,
+ node->Virtual.bytes = Bytes,
+ &node->Virtual.gid,
+ &node->Virtual.physical));
+
+ if (node->Virtual.onFault == gcvTRUE)
+ {
+ gcsLIST_Add(&node->Virtual.head, &Kernel->db->onFaultVidmemList);
+ }
+
+ /* Return pointer to the gcuVIDMEM_NODE union. */
+ *Node = node;
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+ "Created virtual node 0x%x for %u bytes @ 0x%x",
+ node, Bytes, node->Virtual.physical);
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Node=0x%x", *Node);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Roll back. */
+ if (node != gcvNULL)
+ {
+ /* Free the structure. */
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, node));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckVIDMEM_DestroyVirtual
+**
+** Destroy an gcuVIDMEM_NODE union for virtual memory.
+**
+** INPUT:
+**
+** gcuVIDMEM_NODE_PTR Node
+** Pointer to a gcuVIDMEM_NODE union.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckVIDMEM_DestroyVirtual(
+ IN gcuVIDMEM_NODE_PTR Node
+ )
+{
+ gckOS os;
+
+ gcmkHEADER_ARG("Node=0x%x", Node);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Node->Virtual.kernel, gcvOBJ_KERNEL);
+
+ /* Extact the gckOS object pointer. */
+ os = Node->Virtual.kernel->os;
+ gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+ if (Node->Virtual.onFault == gcvTRUE)
+ {
+ gcsLIST_Del(&Node->Virtual.head);
+ }
+
+ /* Delete the gcuVIDMEM_NODE union. */
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, Node));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckVIDMEM_Construct
+**
+** Construct a new gckVIDMEM object.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctUINT32 BaseAddress
+** Base address for the video memory heap.
+**
+** gctSIZE_T Bytes
+** Number of bytes in the video memory heap.
+**
+** gctSIZE_T Threshold
+** Minimum number of bytes beyond am allocation before the node is
+** split. Can be used as a minimum alignment requirement.
+**
+** gctSIZE_T BankSize
+** Number of bytes per physical memory bank. Used by bank
+** optimization.
+**
+** OUTPUT:
+**
+** gckVIDMEM * Memory
+** Pointer to a variable that will hold the pointer to the gckVIDMEM
+** object.
+*/
+gceSTATUS
+gckVIDMEM_Construct(
+ IN gckOS Os,
+ IN gctUINT32 BaseAddress,
+ IN gctSIZE_T Bytes,
+ IN gctSIZE_T Threshold,
+ IN gctSIZE_T BankSize,
+ OUT gckVIDMEM * Memory
+ )
+{
+ gckVIDMEM memory = gcvNULL;
+ gceSTATUS status;
+ gcuVIDMEM_NODE_PTR node;
+ gctINT i, banks = 0;
+ gctPOINTER pointer = gcvNULL;
+ gctUINT32 heapBytes;
+ gctUINT32 bankSize;
+
+ gcmkHEADER_ARG("Os=0x%x BaseAddress=%08x Bytes=%lu Threshold=%lu "
+ "BankSize=%lu",
+ Os, BaseAddress, Bytes, Threshold, BankSize);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
+
+ gcmkSAFECASTSIZET(heapBytes, Bytes);
+ gcmkSAFECASTSIZET(bankSize, BankSize);
+
+ /* Allocate the gckVIDMEM object. */
+ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(struct _gckVIDMEM), &pointer));
+ gckOS_ZeroMemory(pointer, gcmSIZEOF(struct _gckVIDMEM));
+
+ memory = pointer;
+
+ /* Initialize the gckVIDMEM object. */
+ memory->object.type = gcvOBJ_VIDMEM;
+ memory->os = Os;
+
+ /* Set video memory heap information. */
+ memory->baseAddress = BaseAddress;
+ memory->bytes = heapBytes;
+ memory->freeBytes = heapBytes;
+ memory->minFreeBytes = heapBytes;
+ memory->threshold = Threshold;
+ memory->mutex = gcvNULL;
+
+ BaseAddress = 0;
+
+ /* Walk all possible banks. */
+ for (i = 0; i < gcmCOUNTOF(memory->sentinel); ++i)
+ {
+ gctUINT32 bytes;
+
+ if (BankSize == 0)
+ {
+ /* Use all bytes for the first bank. */
+ bytes = heapBytes;
+ }
+ else
+ {
+ /* Compute number of bytes for this bank. */
+ bytes = gcmALIGN(BaseAddress + 1, bankSize) - BaseAddress;
+
+ if (bytes > heapBytes)
+ {
+ /* Make sure we don't exceed the total number of bytes. */
+ bytes = heapBytes;
+ }
+ }
+
+ if (bytes == 0)
+ {
+ /* Mark heap is not used. */
+ memory->sentinel[i].VidMem.next =
+ memory->sentinel[i].VidMem.prev =
+ memory->sentinel[i].VidMem.nextFree =
+ memory->sentinel[i].VidMem.prevFree = gcvNULL;
+ continue;
+ }
+
+ /* Allocate one gcuVIDMEM_NODE union. */
+ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcuVIDMEM_NODE), &pointer));
+
+ node = pointer;
+
+ /* Initialize gcuVIDMEM_NODE union. */
+ node->VidMem.memory = memory;
+
+ node->VidMem.next =
+ node->VidMem.prev =
+ node->VidMem.nextFree =
+ node->VidMem.prevFree = &memory->sentinel[i];
+
+ node->VidMem.offset = BaseAddress;
+ node->VidMem.bytes = bytes;
+ node->VidMem.alignment = 0;
+ node->VidMem.physical = 0;
+ node->VidMem.pool = gcvPOOL_UNKNOWN;
+
+ node->VidMem.locked = 0;
+
+#ifdef __QNXNTO__
+ node->VidMem.processID = 0;
+ node->VidMem.logical = gcvNULL;
+#endif
+
+#if gcdENABLE_VG
+ node->VidMem.kernelVirtual = gcvNULL;
+#endif
+
+ /* Initialize the linked list of nodes. */
+ memory->sentinel[i].VidMem.next =
+ memory->sentinel[i].VidMem.prev =
+ memory->sentinel[i].VidMem.nextFree =
+ memory->sentinel[i].VidMem.prevFree = node;
+
+ /* Mark sentinel. */
+ memory->sentinel[i].VidMem.bytes = 0;
+
+ /* Adjust address for next bank. */
+ BaseAddress += bytes;
+ heapBytes -= bytes;
+ banks ++;
+ }
+
+ /* Assign all the bank mappings. */
+ memory->mapping[gcvSURF_RENDER_TARGET] = banks - 1;
+ memory->mapping[gcvSURF_BITMAP] = banks - 1;
+ if (banks > 1) --banks;
+ memory->mapping[gcvSURF_DEPTH] = banks - 1;
+ memory->mapping[gcvSURF_HIERARCHICAL_DEPTH] = banks - 1;
+ if (banks > 1) --banks;
+ memory->mapping[gcvSURF_TEXTURE] = banks - 1;
+ if (banks > 1) --banks;
+ memory->mapping[gcvSURF_VERTEX] = banks - 1;
+ if (banks > 1) --banks;
+ memory->mapping[gcvSURF_INDEX] = banks - 1;
+ if (banks > 1) --banks;
+ memory->mapping[gcvSURF_TILE_STATUS] = banks - 1;
+ if (banks > 1) --banks;
+ memory->mapping[gcvSURF_TYPE_UNKNOWN] = 0;
+
+#if gcdENABLE_VG
+ memory->mapping[gcvSURF_IMAGE] = 0;
+ memory->mapping[gcvSURF_MASK] = 0;
+ memory->mapping[gcvSURF_SCISSOR] = 0;
+#endif
+ memory->mapping[gcvSURF_ICACHE] = 0;
+ memory->mapping[gcvSURF_TXDESC] = 0;
+ memory->mapping[gcvSURF_FENCE] = 0;
+ memory->mapping[gcvSURF_TFBHEADER] = 0;
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+ "[GALCORE] INDEX: bank %d",
+ memory->mapping[gcvSURF_INDEX]);
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+ "[GALCORE] VERTEX: bank %d",
+ memory->mapping[gcvSURF_VERTEX]);
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+ "[GALCORE] TEXTURE: bank %d",
+ memory->mapping[gcvSURF_TEXTURE]);
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+ "[GALCORE] RENDER_TARGET: bank %d",
+ memory->mapping[gcvSURF_RENDER_TARGET]);
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+ "[GALCORE] DEPTH: bank %d",
+ memory->mapping[gcvSURF_DEPTH]);
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+ "[GALCORE] TILE_STATUS: bank %d",
+ memory->mapping[gcvSURF_TILE_STATUS]);
+
+ /* Allocate the mutex. */
+ gcmkONERROR(gckOS_CreateMutex(Os, &memory->mutex));
+
+ /* Return pointer to the gckVIDMEM object. */
+ *Memory = memory;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Memory=0x%x", *Memory);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Roll back. */
+ if (memory != gcvNULL)
+ {
+ if (memory->mutex != gcvNULL)
+ {
+ /* Delete the mutex. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Os, memory->mutex));
+ }
+
+ for (i = 0; i < banks; ++i)
+ {
+ /* Free the heap. */
+ gcmkASSERT(memory->sentinel[i].VidMem.next != gcvNULL);
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, memory->sentinel[i].VidMem.next));
+ }
+
+ /* Free the object. */
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, memory));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckVIDMEM_Destroy
+**
+** Destroy an gckVIDMEM object.
+**
+** INPUT:
+**
+** gckVIDMEM Memory
+** Pointer to an gckVIDMEM object to destroy.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckVIDMEM_Destroy(
+ IN gckVIDMEM Memory
+ )
+{
+ gcuVIDMEM_NODE_PTR node, next;
+ gctINT i;
+
+ gcmkHEADER_ARG("Memory=0x%x", Memory);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM);
+
+ /* Walk all sentinels. */
+ for (i = 0; i < gcmCOUNTOF(Memory->sentinel); ++i)
+ {
+ /* Bail out of the heap is not used. */
+ if (Memory->sentinel[i].VidMem.next == gcvNULL)
+ {
+ break;
+ }
+
+ /* Walk all the nodes until we reach the sentinel. */
+ for (node = Memory->sentinel[i].VidMem.next;
+ node->VidMem.bytes != 0;
+ node = next)
+ {
+ /* Save pointer to the next node. */
+ next = node->VidMem.next;
+
+ /* Free the node. */
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Memory->os, node));
+ }
+ }
+
+ /* Free the mutex. */
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Memory->os, Memory->mutex));
+
+ /* Mark the object as unknown. */
+ Memory->object.type = gcvOBJ_UNKNOWN;
+
+ /* Free the gckVIDMEM object. */
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Memory->os, Memory));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+#if gcdENABLE_BANK_ALIGNMENT
+
+#if !gcdBANK_BIT_START
+#error gcdBANK_BIT_START not defined.
+#endif
+
+#if !gcdBANK_BIT_END
+#error gcdBANK_BIT_END not defined.
+#endif
+/*******************************************************************************
+** _GetSurfaceBankAlignment
+**
+** Return the required offset alignment required to the make BaseAddress
+** aligned properly.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to gcoOS object.
+**
+** gceSURF_TYPE Type
+** Type of allocation.
+**
+** gctUINT32 BaseAddress
+** Base address of current video memory node.
+**
+** OUTPUT:
+**
+** gctUINT32_PTR AlignmentOffset
+** Pointer to a variable that will hold the number of bytes to skip in
+** the current video memory node in order to make the alignment bank
+** aligned.
+*/
+static gceSTATUS
+_GetSurfaceBankAlignment(
+ IN gckKERNEL Kernel,
+ IN gceSURF_TYPE Type,
+ IN gctUINT32 BaseAddress,
+ OUT gctUINT32_PTR AlignmentOffset
+ )
+{
+ gctUINT32 bank;
+ /* To retrieve the bank. */
+ static const gctUINT32 bankMask = (0xFFFFFFFF << gcdBANK_BIT_START)
+ ^ (0xFFFFFFFF << (gcdBANK_BIT_END + 1));
+
+ /* To retrieve the bank and all the lower bytes. */
+ static const gctUINT32 byteMask = ~(0xFFFFFFFF << (gcdBANK_BIT_END + 1));
+
+ gcmkHEADER_ARG("Type=%d BaseAddress=0x%x ", Type, BaseAddress);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_ARGUMENT(AlignmentOffset != gcvNULL);
+
+ switch (Type)
+ {
+ case gcvSURF_RENDER_TARGET:
+ bank = (BaseAddress & bankMask) >> (gcdBANK_BIT_START);
+
+ /* Align to the first bank. */
+ *AlignmentOffset = (bank == 0) ?
+ 0 :
+ ((1 << (gcdBANK_BIT_END + 1)) + 0) - (BaseAddress & byteMask);
+ break;
+
+ case gcvSURF_DEPTH:
+ bank = (BaseAddress & bankMask) >> (gcdBANK_BIT_START);
+
+ /* Align to the third bank. */
+ *AlignmentOffset = (bank == 2) ?
+ 0 :
+ ((1 << (gcdBANK_BIT_END + 1)) + (2 << gcdBANK_BIT_START)) - (BaseAddress & byteMask);
+
+ /* Minimum 256 byte alignment needed for fast_msaa. */
+ if ((gcdBANK_CHANNEL_BIT > 7) ||
+ ((gckHARDWARE_IsFeatureAvailable(Kernel->hardware, gcvFEATURE_FAST_MSAA) != gcvSTATUS_TRUE) &&
+ (gckHARDWARE_IsFeatureAvailable(Kernel->hardware, gcvFEATURE_SMALL_MSAA) != gcvSTATUS_TRUE)))
+ {
+ /* Add a channel offset at the channel bit. */
+ *AlignmentOffset += (1 << gcdBANK_CHANNEL_BIT);
+ }
+ break;
+
+ default:
+ /* no alignment needed. */
+ *AlignmentOffset = 0;
+ }
+
+ /* Return the status. */
+ gcmkFOOTER_ARG("*AlignmentOffset=%u", *AlignmentOffset);
+ return gcvSTATUS_OK;
+}
+#endif
+
+static gcuVIDMEM_NODE_PTR
+_FindNode(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM Memory,
+ IN gctINT Bank,
+ IN gctSIZE_T Bytes,
+ IN gceSURF_TYPE Type,
+ IN OUT gctUINT32_PTR Alignment
+ )
+{
+ gcuVIDMEM_NODE_PTR node;
+ gctUINT32 alignment;
+
+#if gcdENABLE_BANK_ALIGNMENT
+ gctUINT32 bankAlignment;
+ gceSTATUS status;
+#endif
+
+ if (Memory->sentinel[Bank].VidMem.nextFree == gcvNULL)
+ {
+ /* No free nodes left. */
+ return gcvNULL;
+ }
+
+#if gcdENABLE_BANK_ALIGNMENT
+ /* Walk all free nodes until we have one that is big enough or we have
+ ** reached the sentinel. */
+ for (node = Memory->sentinel[Bank].VidMem.nextFree;
+ node->VidMem.bytes != 0;
+ node = node->VidMem.nextFree)
+ {
+ if (node->VidMem.bytes < Bytes)
+ {
+ continue;
+ }
+
+ gcmkONERROR(_GetSurfaceBankAlignment(
+ Kernel,
+ Type,
+ node->VidMem.memory->baseAddress + node->VidMem.offset,
+ &bankAlignment));
+
+ bankAlignment = gcmALIGN(bankAlignment, *Alignment);
+
+ /* Compute number of bytes to skip for alignment. */
+ alignment = (*Alignment == 0)
+ ? 0
+ : (*Alignment - (node->VidMem.offset % *Alignment));
+
+ if (alignment == *Alignment)
+ {
+ /* Node is already aligned. */
+ alignment = 0;
+ }
+
+ if (node->VidMem.bytes >= Bytes + alignment + bankAlignment)
+ {
+ /* This node is big enough. */
+ *Alignment = alignment + bankAlignment;
+ return node;
+ }
+ }
+#endif
+
+ /* Walk all free nodes until we have one that is big enough or we have
+ reached the sentinel. */
+ for (node = Memory->sentinel[Bank].VidMem.nextFree;
+ node->VidMem.bytes != 0;
+ node = node->VidMem.nextFree)
+ {
+ gctUINT offset;
+
+ gctINT modulo;
+
+ gcmkSAFECASTSIZET(offset, node->VidMem.offset);
+
+ modulo = gckMATH_ModuloInt(offset, *Alignment);
+
+ /* Compute number of bytes to skip for alignment. */
+ alignment = (*Alignment == 0) ? 0 : (*Alignment - modulo);
+
+ if (alignment == *Alignment)
+ {
+ /* Node is already aligned. */
+ alignment = 0;
+ }
+
+ if (node->VidMem.bytes >= Bytes + alignment)
+ {
+ /* This node is big enough. */
+ *Alignment = alignment;
+ return node;
+ }
+ }
+
+#if gcdENABLE_BANK_ALIGNMENT
+OnError:
+#endif
+ /* Not enough memory. */
+ return gcvNULL;
+}
+
+/*******************************************************************************
+**
+** gckVIDMEM_AllocateLinear
+**
+** Allocate linear memory from the gckVIDMEM object.
+**
+** INPUT:
+**
+** gckVIDMEM Memory
+** Pointer to an gckVIDMEM object.
+**
+** gctSIZE_T Bytes
+** Number of bytes to allocate.
+**
+** gctUINT32 Alignment
+** Byte alignment for allocation.
+**
+** gceSURF_TYPE Type
+** Type of surface to allocate (use by bank optimization).
+**
+** gctBOOL Specified
+** If user must use this pool, it should set Specified to gcvTRUE,
+** otherwise allocator may reserve some memory for other usage, such
+** as small block size allocation request.
+**
+** OUTPUT:
+**
+** gcuVIDMEM_NODE_PTR * Node
+** Pointer to a variable that will hold the allocated memory node.
+*/
+gceSTATUS
+gckVIDMEM_AllocateLinear(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM Memory,
+ IN gctSIZE_T Bytes,
+ IN gctUINT32 Alignment,
+ IN gceSURF_TYPE Type,
+ IN gctBOOL Specified,
+ OUT gcuVIDMEM_NODE_PTR * Node
+ )
+{
+ gceSTATUS status;
+ gcuVIDMEM_NODE_PTR node;
+ gctUINT32 alignment;
+ gctINT bank, i;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Memory=0x%x Bytes=%lu Alignment=%u Type=%d",
+ Memory, Bytes, Alignment, Type);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Node != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Type < gcvSURF_NUM_TYPES);
+
+ /* Acquire the mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(Memory->os, Memory->mutex, gcvINFINITE));
+
+ acquired = gcvTRUE;
+#if defined(__QNXNTO__)
+ if (slogUsageInterval > 0) {
+ static gctSIZE_T lowwaterFPC = ~0;
+ static time_t last_slog_time;
+ int do_slog_now = 0;
+ time_t this_slog_time = time(NULL);
+
+ if (Memory->freeBytes < lowwaterFPC) {
+ do_slog_now = 1;
+ lowwaterFPC = Memory->freeBytes;
+ }
+
+ if (abs(this_slog_time - last_slog_time) > slogUsageInterval) {
+ do_slog_now = 1;
+ }
+
+ if (do_slog_now) {
+ last_slog_time = this_slog_time;
+ slogf(_SLOGC_GRAPHICS_GL, _SLOG_INFO, "%s: Memory->freeBytes = %u, lowest Memory->freeBytes = %u",
+ __FUNCTION__, (unsigned) Memory->freeBytes, (unsigned) lowwaterFPC);
+ }
+ }
+#endif
+ if (Bytes > Memory->freeBytes)
+ {
+ /* Not enough memory. */
+ status = gcvSTATUS_OUT_OF_MEMORY;
+ goto OnError;
+ }
+
+#if gcdSMALL_BLOCK_SIZE
+ if ((Memory->freeBytes < (Memory->bytes/gcdRATIO_FOR_SMALL_MEMORY))
+ && (Bytes >= gcdSMALL_BLOCK_SIZE)
+ && (Specified == gcvFALSE)
+ )
+ {
+ /* The left memory is for small memory.*/
+ status = gcvSTATUS_OUT_OF_MEMORY;
+ goto OnError;
+ }
+#endif
+
+ /* Find the default bank for this surface type. */
+ gcmkASSERT((gctINT) Type < gcmCOUNTOF(Memory->mapping));
+ bank = Memory->mapping[Type];
+ alignment = Alignment;
+
+ /* Find a free node in the default bank. */
+ node = _FindNode(Kernel, Memory, bank, Bytes, Type, &alignment);
+
+ /* Out of memory? */
+ if (node == gcvNULL)
+ {
+ /* Walk all lower banks. */
+ for (i = bank - 1; i >= 0; --i)
+ {
+ /* Find a free node inside the current bank. */
+ node = _FindNode(Kernel, Memory, i, Bytes, Type, &alignment);
+ if (node != gcvNULL)
+ {
+ break;
+ }
+ }
+ }
+
+ if (node == gcvNULL)
+ {
+ /* Walk all upper banks. */
+ for (i = bank + 1; i < gcmCOUNTOF(Memory->sentinel); ++i)
+ {
+ if (Memory->sentinel[i].VidMem.nextFree == gcvNULL)
+ {
+ /* Abort when we reach unused banks. */
+ break;
+ }
+
+ /* Find a free node inside the current bank. */
+ node = _FindNode(Kernel, Memory, i, Bytes, Type, &alignment);
+ if (node != gcvNULL)
+ {
+ break;
+ }
+ }
+ }
+
+ if (node == gcvNULL)
+ {
+ /* Out of memory. */
+ status = gcvSTATUS_OUT_OF_MEMORY;
+ goto OnError;
+ }
+
+ /* Do we have an alignment? */
+ if (alignment > 0)
+ {
+ /* Split the node so it is aligned. */
+ if (_Split(Memory->os, node, alignment))
+ {
+ /* Successful split, move to aligned node. */
+ node = node->VidMem.next;
+
+ /* Remove alignment. */
+ alignment = 0;
+ }
+ }
+
+ /* Do we have enough memory after the allocation to split it? */
+ if (node->VidMem.bytes - Bytes > Memory->threshold)
+ {
+ /* Adjust the node size. */
+ _Split(Memory->os, node, Bytes);
+ }
+
+ /* Remove the node from the free list. */
+ node->VidMem.prevFree->VidMem.nextFree = node->VidMem.nextFree;
+ node->VidMem.nextFree->VidMem.prevFree = node->VidMem.prevFree;
+ node->VidMem.nextFree =
+ node->VidMem.prevFree = gcvNULL;
+
+ /* Fill in the information. */
+ node->VidMem.alignment = alignment;
+ node->VidMem.memory = Memory;
+#ifdef __QNXNTO__
+ node->VidMem.logical = gcvNULL;
+ gcmkONERROR(gckOS_GetProcessID(&node->VidMem.processID));
+#endif
+
+ /* Adjust the number of free bytes. */
+ Memory->freeBytes -= node->VidMem.bytes;
+
+ if (Memory->freeBytes < Memory->minFreeBytes)
+ {
+ Memory->minFreeBytes = Memory->freeBytes;
+ }
+
+#if gcdENABLE_VG
+ node->VidMem.kernelVirtual = gcvNULL;
+#endif
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex));
+
+ /* Return the pointer to the node. */
+ *Node = node;
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+ "Allocated %u bytes @ 0x%x [0x%08X]",
+ node->VidMem.bytes, node, node->VidMem.offset);
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Node=0x%x", *Node);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckVIDMEM_Free
+**
+** Free an allocated video memory node.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gcuVIDMEM_NODE_PTR Node
+** Pointer to a gcuVIDMEM_NODE object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckVIDMEM_Free(
+ IN gckKERNEL Kernel,
+ IN gcuVIDMEM_NODE_PTR Node
+ )
+{
+ gceSTATUS status;
+ gckKERNEL kernel = gcvNULL;
+ gckVIDMEM memory = gcvNULL;
+ gcuVIDMEM_NODE_PTR node;
+ gctBOOL mutexAcquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Node=0x%x", Node);
+
+ /* Verify the arguments. */
+ if ((Node == gcvNULL)
+ || (Node->VidMem.memory == gcvNULL)
+ )
+ {
+ /* Invalid object. */
+ gcmkONERROR(gcvSTATUS_INVALID_OBJECT);
+ }
+
+ /**************************** Video Memory ********************************/
+
+ if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
+ {
+ /* Extract pointer to gckVIDMEM object owning the node. */
+ memory = Node->VidMem.memory;
+
+ /* Acquire the mutex. */
+ gcmkONERROR(
+ gckOS_AcquireMutex(memory->os, memory->mutex, gcvINFINITE));
+
+ mutexAcquired = gcvTRUE;
+
+#ifdef __QNXNTO__
+ /* Unmap the video memory. */
+ if (Node->VidMem.logical != gcvNULL)
+ {
+ gckKERNEL_UnmapVideoMemory(
+ Kernel,
+ Node->VidMem.logical,
+ Node->VidMem.processID,
+ Node->VidMem.bytes);
+ Node->VidMem.logical = gcvNULL;
+ }
+
+ /* Reset. */
+ Node->VidMem.processID = 0;
+
+ /* Don't try to re-free an already freed node. */
+ if ((Node->VidMem.nextFree == gcvNULL)
+ && (Node->VidMem.prevFree == gcvNULL)
+ )
+#endif
+ {
+#if gcdENABLE_VG
+ if (Node->VidMem.kernelVirtual)
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+ "%s(%d) Unmap %x from kernel space.",
+ __FUNCTION__, __LINE__,
+ Node->VidMem.kernelVirtual);
+
+ gcmkVERIFY_OK(
+ gckOS_UnmapPhysical(memory->os,
+ Node->VidMem.kernelVirtual,
+ Node->VidMem.bytes));
+
+ Node->VidMem.kernelVirtual = gcvNULL;
+ }
+#endif
+
+ /* Check if Node is already freed. */
+ if (Node->VidMem.nextFree)
+ {
+ /* Node is alread freed. */
+ gcmkONERROR(gcvSTATUS_INVALID_DATA);
+ }
+
+ /* Update the number of free bytes. */
+ memory->freeBytes += Node->VidMem.bytes;
+
+ /* Find the next free node. */
+ for (node = Node->VidMem.next;
+ node != gcvNULL && node->VidMem.nextFree == gcvNULL;
+ node = node->VidMem.next) ;
+
+ /* Insert this node in the free list. */
+ Node->VidMem.nextFree = node;
+ Node->VidMem.prevFree = node->VidMem.prevFree;
+
+ Node->VidMem.prevFree->VidMem.nextFree =
+ node->VidMem.prevFree = Node;
+
+ /* Is the next node a free node and not the sentinel? */
+ if ((Node->VidMem.next == Node->VidMem.nextFree)
+ && (Node->VidMem.next->VidMem.bytes != 0)
+ )
+ {
+ /* Merge this node with the next node. */
+ gcmkONERROR(_Merge(memory->os, node = Node));
+ gcmkASSERT(node->VidMem.nextFree != node);
+ gcmkASSERT(node->VidMem.prevFree != node);
+ }
+
+ /* Is the previous node a free node and not the sentinel? */
+ if ((Node->VidMem.prev == Node->VidMem.prevFree)
+ && (Node->VidMem.prev->VidMem.bytes != 0)
+ )
+ {
+ /* Merge this node with the previous node. */
+ gcmkONERROR(_Merge(memory->os, node = Node->VidMem.prev));
+ gcmkASSERT(node->VidMem.nextFree != node);
+ gcmkASSERT(node->VidMem.prevFree != node);
+ }
+ }
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(memory->os, memory->mutex));
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+ "Node 0x%x is freed.",
+ Node);
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+ /*************************** Virtual Memory *******************************/
+
+ /* Get gckKERNEL object. */
+ kernel = Node->Virtual.kernel;
+
+ /* Verify the gckKERNEL object pointer. */
+ gcmkVERIFY_OBJECT(kernel, gcvOBJ_KERNEL);
+
+#if gcdENABLE_VG
+ if (Node->Virtual.kernelVirtual)
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+ "%s(%d) Unmap %x from kernel space.",
+ __FUNCTION__, __LINE__,
+ Node->Virtual.kernelVirtual);
+
+ gcmkVERIFY_OK(
+ gckOS_UnmapPhysical(kernel->os,
+ Node->Virtual.kernelVirtual,
+ Node->Virtual.bytes));
+
+ Node->Virtual.kernelVirtual = gcvNULL;
+ }
+#endif
+
+ /* Free the virtual memory. */
+ gcmkVERIFY_OK(gckOS_FreePagedMemory(kernel->os,
+ Node->Virtual.physical,
+ Node->Virtual.bytes));
+
+ /* Destroy the gcuVIDMEM_NODE union. */
+ gcmkVERIFY_OK(gckVIDMEM_DestroyVirtual(Node));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (mutexAcquired)
+ {
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(
+ memory->os, memory->mutex
+ ));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+#if !gcdPROCESS_ADDRESS_SPACE
+/*******************************************************************************
+**
+** _NeedVirtualMapping
+**
+** Whether setup GPU page table for video node.
+**
+** INPUT:
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gcuVIDMEM_NODE_PTR Node
+** Pointer to a gcuVIDMEM_NODE union.
+**
+** gceCORE Core
+** Id of current GPU.
+**
+** OUTPUT:
+** gctBOOL * NeedMapping
+** A pointer hold the result whether Node should be mapping.
+*/
+static gceSTATUS
+_NeedVirtualMapping(
+ IN gckKERNEL Kernel,
+ IN gceCORE Core,
+ IN gcuVIDMEM_NODE_PTR Node,
+ OUT gctBOOL * NeedMapping
+)
+{
+ gceSTATUS status;
+ gctPHYS_ADDR_T phys;
+ gctUINT32 address;
+ gctUINT32 end;
+ gcePOOL pool;
+ gctUINT32 offset;
+ gctUINT32 bytes;
+
+ gcmkHEADER_ARG("Node=0x%X", Node);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_ARGUMENT(Kernel != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Node != gcvNULL);
+ gcmkVERIFY_ARGUMENT(NeedMapping != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Core < gcdMAX_GPU_COUNT);
+
+ if (Node->Virtual.contiguous)
+ {
+#if gcdENABLE_VG
+ if (Core == gcvCORE_VG)
+ {
+ *NeedMapping = gcvFALSE;
+ }
+ else
+#endif
+ if (Node->Virtual.secure)
+ {
+ *NeedMapping = gcvTRUE;
+ }
+ else
+ {
+ /* Convert logical address into a physical address. */
+ gcmkONERROR(gckOS_UserLogicalToPhysical(
+ Kernel->os, Node->Virtual.logical, &phys
+ ));
+
+ if (phys > gcvMAXUINT32)
+ {
+ *NeedMapping = gcvTRUE;
+ }
+ else
+ {
+ gcmkSAFECASTPHYSADDRT(address, phys);
+
+ if (!gckHARDWARE_IsFeatureAvailable(Kernel->hardware, gcvFEATURE_MMU))
+ {
+ gcmkASSERT(address >= Kernel->hardware->baseAddress);
+
+ /* Subtract baseAddress to get a GPU address used for programming. */
+ address -= Kernel->hardware->baseAddress;
+
+ /* If part of region is belong to gcvPOOL_VIRTUAL,
+ ** whole region has to be mapped. */
+ gcmkSAFECASTSIZET(bytes, Node->Virtual.bytes);
+ end = address + bytes - 1;
+
+ gcmkONERROR(gckHARDWARE_SplitMemory(
+ Kernel->hardware, end, &pool, &offset
+ ));
+
+ *NeedMapping = (pool == gcvPOOL_VIRTUAL);
+ }
+ else
+ {
+ gctBOOL flatMapped;
+
+ gcmkONERROR(gckMMU_IsFlatMapped(Kernel->mmu, address, &flatMapped));
+
+ *NeedMapping = !flatMapped;
+ }
+ }
+ }
+ }
+ else
+ {
+ *NeedMapping = gcvTRUE;
+ }
+
+ gcmkFOOTER_ARG("*NeedMapping=%d", *NeedMapping);
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+#endif
+
+#if gcdPROCESS_ADDRESS_SPACE
+gcsGPU_MAP_PTR
+_FindGPUMap(
+ IN gcsGPU_MAP_PTR Head,
+ IN gctINT ProcessID
+ )
+{
+ gcsGPU_MAP_PTR map = Head;
+
+ while (map)
+ {
+ if (map->pid == ProcessID)
+ {
+ return map;
+ }
+
+ map = map->next;
+ }
+
+ return gcvNULL;
+}
+
+gcsGPU_MAP_PTR
+_CreateGPUMap(
+ IN gckOS Os,
+ IN gcsGPU_MAP_PTR *Head,
+ IN gcsGPU_MAP_PTR *Tail,
+ IN gctINT ProcessID
+ )
+{
+ gcsGPU_MAP_PTR gpuMap;
+ gctPOINTER pointer = gcvNULL;
+
+ gckOS_Allocate(Os, sizeof(gcsGPU_MAP), &pointer);
+
+ if (pointer == gcvNULL)
+ {
+ return gcvNULL;
+ }
+
+ gpuMap = pointer;
+
+ gckOS_ZeroMemory(pointer, sizeof(gcsGPU_MAP));
+
+ gpuMap->pid = ProcessID;
+
+ if (!*Head)
+ {
+ *Head = *Tail = gpuMap;
+ }
+ else
+ {
+ gpuMap->prev = *Tail;
+ (*Tail)->next = gpuMap;
+ *Tail = gpuMap;
+ }
+
+ return gpuMap;
+}
+
+void
+_DestroyGPUMap(
+ IN gckOS Os,
+ IN gcsGPU_MAP_PTR *Head,
+ IN gcsGPU_MAP_PTR *Tail,
+ IN gcsGPU_MAP_PTR gpuMap
+ )
+{
+
+ if (gpuMap == *Head)
+ {
+ if ((*Head = gpuMap->next) == gcvNULL)
+ {
+ *Tail = gcvNULL;
+ }
+ }
+ else
+ {
+ gpuMap->prev->next = gpuMap->next;
+ if (gpuMap == *Tail)
+ {
+ *Tail = gpuMap->prev;
+ }
+ else
+ {
+ gpuMap->next->prev = gpuMap->prev;
+ }
+ }
+
+ gcmkOS_SAFE_FREE(Os, gpuMap);
+}
+#endif
+
+/*******************************************************************************
+**
+** gckVIDMEM_Lock
+**
+** Lock a video memory node and return its hardware specific address.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gcuVIDMEM_NODE_PTR Node
+** Pointer to a gcuVIDMEM_NODE union.
+**
+** OUTPUT:
+**
+** gctUINT32 * Address
+** Pointer to a variable that will hold the hardware specific address.
+**
+** gctUINT32 * PhysicalAddress
+** Pointer to a variable that will hold the bus address of a contiguous
+** video node.
+*/
+gceSTATUS
+gckVIDMEM_Lock(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM_NODE Node,
+ IN gctBOOL Cacheable,
+ OUT gctUINT32 * Address,
+ OUT gctUINT32 * Gid,
+ OUT gctUINT64 * PhysicalAddress
+ )
+{
+ gceSTATUS status;
+ gctBOOL acquired = gcvFALSE;
+ gctBOOL locked = gcvFALSE;
+ gckOS os = gcvNULL;
+#if !gcdPROCESS_ADDRESS_SPACE
+ gctBOOL needMapping = gcvFALSE;
+#endif
+ gctUINT64 physicalAddress = ~0ULL;
+ gcuVIDMEM_NODE_PTR node = Node->node;
+ gctSIZE_T pageSize;
+ gctUINT32 pageMask;
+
+ gcmkHEADER_ARG("Node=0x%x", Node);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+ /* Extract the gckOS object pointer. */
+ os = Kernel->os;
+ gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+ if ((node == gcvNULL)
+ || (node->VidMem.memory == gcvNULL)
+ )
+ {
+ /* Invalid object. */
+ gcmkONERROR(gcvSTATUS_INVALID_OBJECT);
+ }
+
+ /* Grab the mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(os, Node->mutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /**************************** Video Memory ********************************/
+
+ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
+ {
+ gctUINT32 offset;
+
+ if (Cacheable == gcvTRUE)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_REQUEST);
+ }
+
+ /* Increment the lock count. */
+ node->VidMem.locked ++;
+
+ gcmkSAFECASTSIZET(offset, node->VidMem.offset);
+ physicalAddress = node->VidMem.memory->baseAddress
+ + offset
+ + node->VidMem.alignment;
+
+ if (node->VidMem.pool == gcvPOOL_LOCAL_EXTERNAL)
+ {
+ *Address = Kernel->externalBaseAddress + offset;
+ }
+ else
+ {
+ gcmkASSERT(node->VidMem.pool == gcvPOOL_SYSTEM);
+ *Address = Kernel->contiguousBaseAddress + offset;
+ }
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+ "Locked node 0x%x (%d) @ 0x%08X",
+ node,
+ node->VidMem.locked,
+ *Address);
+ }
+
+ /*************************** Virtual Memory *******************************/
+
+ else
+ {
+
+ *Gid = node->Virtual.gid;
+
+#if gcdPAGED_MEMORY_CACHEABLE
+ /* Force video memory cacheable. */
+ Cacheable = gcvTRUE;
+#endif
+
+ gcmkONERROR(
+ gckOS_LockPages(os,
+ node->Virtual.physical,
+ node->Virtual.bytes,
+ Cacheable,
+ &node->Virtual.logical,
+ &node->Virtual.pageCount));
+
+ gcmkONERROR(gckOS_UserLogicalToPhysical(
+ os,
+ node->Virtual.logical,
+ &physicalAddress
+ ));
+
+#if gcdENABLE_VG
+ node->Virtual.physicalAddress = physicalAddress;
+#endif
+
+#if !gcdPROCESS_ADDRESS_SPACE
+ /* Increment the lock count. */
+ if (node->Virtual.lockeds[Kernel->core] ++ == 0)
+ {
+ locked = gcvTRUE;
+
+ gcmkONERROR(_NeedVirtualMapping(Kernel, Kernel->core, node, &needMapping));
+
+ if (needMapping == gcvFALSE)
+ {
+ /* Get hardware specific address. */
+#if gcdENABLE_VG
+ if (Kernel->vg != gcvNULL)
+ {
+ gcmkONERROR(gckVGHARDWARE_ConvertLogical(
+ Kernel->vg->hardware,
+ node->Virtual.logical,
+ gcvTRUE,
+ &node->Virtual.addresses[Kernel->core]));
+ }
+ else
+#endif
+ {
+ gcmkONERROR(gckHARDWARE_ConvertLogical(
+ Kernel->hardware,
+ node->Virtual.logical,
+ gcvTRUE,
+ &node->Virtual.addresses[Kernel->core]));
+ }
+ }
+ else
+ {
+#if gcdSECURITY
+ gctPHYS_ADDR physicalArrayPhysical;
+ gctPOINTER physicalArrayLogical;
+
+ gcmkONERROR(gckOS_AllocatePageArray(
+ os,
+ node->Virtual.physical,
+ node->Virtual.pageCount,
+ &physicalArrayLogical,
+ &physicalArrayPhysical
+ ));
+
+ gcmkONERROR(gckKERNEL_SecurityMapMemory(
+ Kernel,
+ physicalArrayLogical,
+ node->Virtual.pageCount,
+ &node->Virtual.addresses[Kernel->core]
+ ));
+
+ gcmkONERROR(gckOS_FreeNonPagedMemory(
+ os,
+ 1,
+ physicalArrayPhysical,
+ physicalArrayLogical
+ ));
+#else
+#if gcdENABLE_VG
+ if (Kernel->vg != gcvNULL)
+ {
+ /* Allocate pages inside the MMU. */
+ gcmkONERROR(
+ gckVGMMU_AllocatePages(Kernel->vg->mmu,
+ node->Virtual.pageCount,
+ &node->Virtual.pageTables[Kernel->core],
+ &node->Virtual.addresses[Kernel->core]));
+ }
+ else
+#endif
+ {
+ /* Allocate pages inside the MMU. */
+ gcmkONERROR(
+ gckMMU_AllocatePagesEx(Kernel->mmu,
+ node->Virtual.pageCount,
+ node->Virtual.type,
+ node->Virtual.secure,
+ &node->Virtual.pageTables[Kernel->core],
+ &node->Virtual.addresses[Kernel->core]));
+ }
+
+ if (node->Virtual.onFault != gcvTRUE)
+ {
+#if gcdENABLE_TRUST_APPLICATION
+#if gcdENABLE_VG
+ if (Kernel->core != gcvCORE_VG && Kernel->hardware->options.secureMode == gcvSECURE_IN_TA)
+#else
+ if (Kernel->hardware->options.secureMode == gcvSECURE_IN_TA)
+#endif
+ {
+ gcmkONERROR(gckKERNEL_MapInTrustApplicaiton(
+ Kernel,
+ node->Virtual.logical,
+ node->Virtual.physical,
+ node->Virtual.addresses[Kernel->core],
+ node->Virtual.pageCount
+ ));
+ }
+ else
+#endif
+ {
+ /* Map the pages. */
+ gcmkONERROR(gckOS_MapPagesEx(os,
+ Kernel->core,
+ node->Virtual.physical,
+ node->Virtual.pageCount,
+ node->Virtual.addresses[Kernel->core],
+ node->Virtual.pageTables[Kernel->core],
+ gcvTRUE,
+ node->Virtual.type));
+ }
+ }
+
+#if gcdENABLE_VG
+ if (Kernel->core == gcvCORE_VG)
+ {
+ gcmkONERROR(gckVGMMU_Flush(Kernel->vg->mmu));
+ }
+ else
+#endif
+ {
+ gcmkONERROR(gckMMU_Flush(Kernel->mmu, node->Virtual.type));
+ }
+#endif
+ }
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+ "Mapped virtual node 0x%x to 0x%08X",
+ node,
+ node->Virtual.addresses[Kernel->core]);
+ }
+
+ /* Return hardware address. */
+ *Address = node->Virtual.addresses[Kernel->core];
+
+ if (needMapping == gcvTRUE)
+ {
+
+#if gcdENABLE_VG
+ if (Kernel->core == gcvCORE_VG)
+ {
+ gcmkVERIFY_OK(gckOS_GetPageSize(os, &pageSize));
+ }
+ else
+#endif
+ {
+ pageSize = Kernel->command->pageSize;
+ }
+
+ pageMask = (gctUINT32)pageSize - 1;
+
+ *Address += (gctUINT32)physicalAddress & pageMask;
+
+ /* Need mark invalid address for virtual memory */
+ if (node->Virtual.contiguous == gcvFALSE)
+ {
+ physicalAddress = gcvINVALID_ADDRESS;
+ }
+ }
+#endif
+ }
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mutex));
+
+ *PhysicalAddress = (gctUINT64)physicalAddress;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Address=%08x", *Address);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (locked)
+ {
+ if (node->Virtual.pageTables[Kernel->core] != gcvNULL)
+ {
+#if gcdENABLE_VG
+ if (Kernel->vg != gcvNULL)
+ {
+ /* Free the pages from the MMU. */
+ gcmkVERIFY_OK(
+ gckVGMMU_FreePages(Kernel->vg->mmu,
+ node->Virtual.pageTables[Kernel->core],
+ node->Virtual.pageCount));
+ }
+ else
+#endif
+ {
+ /* Free the pages from the MMU. */
+ gcmkVERIFY_OK(
+ gckMMU_FreePages(Kernel->mmu,
+ node->Virtual.secure,
+ node->Virtual.addresses[Kernel->core],
+ node->Virtual.pageTables[Kernel->core],
+ node->Virtual.pageCount));
+ }
+ node->Virtual.pageTables[Kernel->core] = gcvNULL;
+ }
+
+ /* Unlock the pages. */
+ gcmkVERIFY_OK(
+ gckOS_UnlockPages(os,
+ node->Virtual.physical,
+ node->Virtual.bytes,
+ node->Virtual.logical
+ ));
+
+ node->Virtual.lockeds[Kernel->core]--;
+ }
+
+ if (acquired)
+ {
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mutex));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckVIDMEM_Unlock
+**
+** Unlock a video memory node.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gcuVIDMEM_NODE_PTR Node
+** Pointer to a locked gcuVIDMEM_NODE union.
+**
+** gceSURF_TYPE Type
+** Type of surface to unlock.
+**
+** gctBOOL * Asynchroneous
+** Pointer to a variable specifying whether the surface should be
+** unlocked asynchroneously or not.
+**
+** OUTPUT:
+**
+** gctBOOL * Asynchroneous
+** Pointer to a variable receiving the number of bytes used in the
+** command buffer specified by 'Commands'. If gcvNULL, there is no
+** command buffer.
+*/
+gceSTATUS
+gckVIDMEM_Unlock(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM_NODE Node,
+ IN gceSURF_TYPE Type,
+ IN OUT gctBOOL * Asynchroneous
+ )
+{
+ gceSTATUS status;
+ gckOS os = gcvNULL;
+ gctBOOL acquired = gcvFALSE;
+ gcuVIDMEM_NODE_PTR node = Node->node;
+
+ gcmkHEADER_ARG("Node=0x%x Type=%d *Asynchroneous=%d",
+ Node, Type, gcmOPT_VALUE(Asynchroneous));
+
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+ /* Get the gckOS object pointer. */
+ os = Kernel->os;
+ gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+ /* Verify the arguments. */
+ if ((node == gcvNULL)
+ || (node->VidMem.memory == gcvNULL)
+ )
+ {
+ /* Invalid object. */
+ gcmkONERROR(gcvSTATUS_INVALID_OBJECT);
+ }
+
+ /* Grab the mutex. */
+ gcmkONERROR(gckOS_AcquireMutex(os, Node->mutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /**************************** Video Memory ********************************/
+
+ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
+ {
+ if (node->VidMem.locked <= 0)
+ {
+ /* The surface was not locked. */
+ status = gcvSTATUS_MEMORY_UNLOCKED;
+ goto OnError;
+ }
+
+ if (Asynchroneous != gcvNULL)
+ {
+ /* Schedule an event to sync with GPU. */
+ *Asynchroneous = gcvTRUE;
+ }
+ else
+ {
+ /* Decrement the lock count. */
+ node->VidMem.locked --;
+ }
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+ "Unlocked node 0x%x (%d)",
+ node,
+ node->VidMem.locked);
+ }
+
+ /*************************** Virtual Memory *******************************/
+
+ else
+ {
+
+
+ if (Asynchroneous == gcvNULL)
+ {
+#if !gcdPROCESS_ADDRESS_SPACE
+ if (node->Virtual.lockeds[Kernel->core] == 0)
+ {
+ status = gcvSTATUS_MEMORY_UNLOCKED;
+ goto OnError;
+ }
+
+ /* Decrement lock count. */
+ -- node->Virtual.lockeds[Kernel->core];
+
+ /* See if we can unlock the resources. */
+ if (node->Virtual.lockeds[Kernel->core] == 0)
+ {
+#if gcdSECURITY
+ if (node->Virtual.addresses[Kernel->core] > 0x80000000)
+ {
+ gcmkONERROR(gckKERNEL_SecurityUnmapMemory(
+ Kernel,
+ node->Virtual.addresses[Kernel->core],
+ node->Virtual.pageCount
+ ));
+ }
+#else
+ /* Free the page table. */
+ if (node->Virtual.pageTables[Kernel->core] != gcvNULL)
+ {
+#if gcdENABLE_VG
+ if (Kernel->vg != gcvNULL)
+ {
+ gcmkONERROR(
+ gckVGMMU_FreePages(Kernel->vg->mmu,
+ node->Virtual.pageTables[Kernel->core],
+ node->Virtual.pageCount));
+ }
+ else
+#endif
+ {
+ gcmkONERROR(
+ gckMMU_FreePages(Kernel->mmu,
+ node->Virtual.secure,
+ node->Virtual.addresses[Kernel->core],
+ node->Virtual.pageTables[Kernel->core],
+ node->Virtual.pageCount));
+ }
+
+ gcmkONERROR(gckOS_UnmapPages(
+ Kernel->os,
+ node->Virtual.pageCount,
+ node->Virtual.addresses[Kernel->core]
+ ));
+
+ /* Mark page table as freed. */
+ node->Virtual.pageTables[Kernel->core] = gcvNULL;
+ }
+#endif
+ }
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+ "Unmapped virtual node 0x%x from 0x%08X",
+ node, node->Virtual.addresses[Kernel->core]);
+#endif
+
+ }
+
+ else
+ {
+ gcmkONERROR(
+ gckOS_UnlockPages(os,
+ node->Virtual.physical,
+ node->Virtual.bytes,
+ node->Virtual.logical));
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM,
+ "Scheduled unlock for virtual node 0x%x",
+ node);
+
+ /* Schedule the surface to be unlocked. */
+ *Asynchroneous = gcvTRUE;
+ }
+ }
+
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mutex));
+ acquired = gcvFALSE;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Asynchroneous=%d", gcmOPT_VALUE(Asynchroneous));
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ /* Release the mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mutex));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+#if gcdPROCESS_ADDRESS_SPACE
+gceSTATUS
+gckVIDMEM_Node_Lock(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM_NODE Node,
+ OUT gctUINT32 *Address
+ )
+{
+ gceSTATUS status;
+ gckOS os;
+ gcuVIDMEM_NODE_PTR node = Node->node;
+ gcsGPU_MAP_PTR gpuMap;
+ gctPHYS_ADDR physical = gcvNULL;
+ gctUINT32 phys = gcvINVALID_ADDRESS;
+ gctUINT32 processID;
+ gcsLOCK_INFO_PTR lockInfo;
+ gctUINT32 pageCount;
+ gckMMU mmu;
+ gctUINT32 i;
+ gctUINT32_PTR pageTableEntry;
+ gctUINT32 offset = 0;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Node = %x", Node);
+
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Node != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+ os = Kernel->os;
+ gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+ gcmkONERROR(gckOS_GetProcessID(&processID));
+
+ gcmkONERROR(gckKERNEL_GetProcessMMU(Kernel, &mmu));
+
+ gcmkONERROR(gckOS_AcquireMutex(os, Node->mapMutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Get map information for current process. */
+ gpuMap = _FindGPUMap(Node->mapHead, processID);
+
+ if (gpuMap == gcvNULL)
+ {
+ gpuMap = _CreateGPUMap(os, &Node->mapHead, &Node->mapTail, processID);
+
+ if (gpuMap == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+ }
+
+ lockInfo = &gpuMap->lockInfo;
+
+ if (lockInfo->lockeds[Kernel->core] ++ == 0)
+ {
+ /* Get necessary information. */
+ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
+ {
+ phys = node->VidMem.memory->baseAddress
+ + node->VidMem.offset
+ + node->VidMem.alignment;
+
+ /* GPU page table use 4K page. */
+ pageCount = ((phys + node->VidMem.bytes + 4096 - 1) >> 12)
+ - (phys >> 12);
+
+ offset = phys & 0xFFF;
+ }
+ else
+ {
+ pageCount = node->Virtual.pageCount;
+ physical = node->Virtual.physical;
+ }
+
+ /* Allocate pages inside the MMU. */
+ gcmkONERROR(gckMMU_AllocatePages(
+ mmu,
+ pageCount,
+ &lockInfo->pageTables[Kernel->core],
+ &lockInfo->GPUAddresses[Kernel->core]));
+
+ /* Record MMU from which pages are allocated. */
+ lockInfo->lockMmus[Kernel->core] = mmu;
+
+ pageTableEntry = lockInfo->pageTables[Kernel->core];
+
+ /* Fill page table entries. */
+ if (phys != gcvINVALID_ADDRESS)
+ {
+ gctUINT32 address = lockInfo->GPUAddresses[Kernel->core];
+ for (i = 0; i < pageCount; i++)
+ {
+ gckMMU_GetPageEntry(mmu, address, &pageTableEntry);
+ gckMMU_SetPage(mmu, phys & 0xFFFFF000, pageTableEntry);
+ phys += 4096;
+ address += 4096;
+ pageTableEntry += 1;
+ }
+ }
+ else
+ {
+ gctUINT32 address = lockInfo->GPUAddresses[Kernel->core];
+ gcmkASSERT(physical != gcvNULL);
+ gcmkONERROR(gckOS_MapPagesEx(os,
+ Kernel->core,
+ physical,
+ pageCount,
+ address,
+ pageTableEntry));
+ }
+
+ gcmkONERROR(gckMMU_Flush(mmu, Node->type));
+ }
+
+ *Address = lockInfo->GPUAddresses[Kernel->core] + offset;
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mapMutex));
+ acquired = gcvFALSE;
+
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->mapMutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_Unlock(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM_NODE Node,
+ IN gctUINT32 ProcessID
+ )
+{
+ gceSTATUS status;
+ gcsGPU_MAP_PTR gpuMap;
+ gcsLOCK_INFO_PTR lockInfo;
+ gckMMU mmu;
+ gcuVIDMEM_NODE_PTR node;
+ gctUINT32 pageCount;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Kernel=0x%08X, Node = %x, ProcessID=%d",
+ Kernel, Node, ProcessID);
+
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Node != gcvNULL);
+
+ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Node->mapMutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Get map information for current process. */
+ gpuMap = _FindGPUMap(Node->mapHead, ProcessID);
+
+ if (gpuMap == gcvNULL)
+ {
+ /* No mapping for this process. */
+ gcmkONERROR(gcvSTATUS_INVALID_DATA);
+ }
+
+ lockInfo = &gpuMap->lockInfo;
+
+ if (--lockInfo->lockeds[Kernel->core] == 0)
+ {
+ node = Node->node;
+
+ /* Get necessary information. */
+ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
+ {
+ gctUINT32 phys = node->VidMem.memory->baseAddress
+ + node->VidMem.offset
+ + node->VidMem.alignment;
+
+ /* GPU page table use 4K page. */
+ pageCount = ((phys + node->VidMem.bytes + 4096 - 1) >> 12)
+ - (phys >> 12);
+ }
+ else
+ {
+ pageCount = node->Virtual.pageCount;
+ }
+
+ /* Get MMU which allocates pages. */
+ mmu = lockInfo->lockMmus[Kernel->core];
+
+ /* Free virtual spaces in page table. */
+ gcmkVERIFY_OK(gckMMU_FreePagesEx(
+ mmu,
+ lockInfo->GPUAddresses[Kernel->core],
+ pageCount
+ ));
+
+ _DestroyGPUMap(Kernel->os, &Node->mapHead, &Node->mapTail, gpuMap);
+ }
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Node->mapMutex));
+ acquired = gcvFALSE;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Node->mapMutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+#endif
+
+/*******************************************************************************
+**
+** gckVIDMEM_HANDLE_Allocate
+**
+** Allocate a handle for a gckVIDMEM_NODE object.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gckVIDMEM_NODE Node
+** Pointer to a gckVIDMEM_NODE object.
+**
+** OUTPUT:
+**
+** gctUINT32 * Handle
+** Pointer to a variable receiving a handle represent this
+** gckVIDMEM_NODE in userspace.
+*/
+gceSTATUS
+gckVIDMEM_HANDLE_Allocate(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM_NODE Node,
+ OUT gctUINT32 * Handle
+ )
+{
+ gceSTATUS status;
+ gctUINT32 processID = 0;
+ gctPOINTER pointer = gcvNULL;
+ gctPOINTER handleDatabase = gcvNULL;
+ gctPOINTER mutex = gcvNULL;
+ gctUINT32 handle = 0;
+ gckVIDMEM_HANDLE handleObject = gcvNULL;
+ gckOS os = Kernel->os;
+
+ gcmkHEADER_ARG("Kernel=0x%X, Node=0x%X", Kernel, Node);
+
+ gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+ /* Allocate a gckVIDMEM_HANDLE object. */
+ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsVIDMEM_HANDLE), &pointer));
+
+ gcmkVERIFY_OK(gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsVIDMEM_HANDLE)));
+
+ handleObject = pointer;
+
+ gcmkONERROR(gckOS_AtomConstruct(os, &handleObject->reference));
+
+ /* Set default reference count to 1. */
+ gckOS_AtomSet(os, handleObject->reference, 1);
+
+ gcmkVERIFY_OK(gckOS_GetProcessID(&processID));
+
+ gcmkONERROR(
+ gckKERNEL_FindHandleDatbase(Kernel,
+ processID,
+ &handleDatabase,
+ &mutex));
+
+ /* Allocate a handle for this object. */
+ gcmkONERROR(
+ gckKERNEL_AllocateIntegerId(handleDatabase, handleObject, &handle));
+
+ handleObject->node = Node;
+ handleObject->handle = handle;
+
+ *Handle = handle;
+
+ gcmkFOOTER_ARG("*Handle=%d", *Handle);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (handleObject != gcvNULL)
+ {
+ if (handleObject->reference != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_AtomDestroy(os, handleObject->reference));
+ }
+
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, handleObject));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_Reference(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM_NODE Node
+ )
+{
+ gctINT32 oldValue;
+ gcmkHEADER_ARG("Kernel=0x%X Node=0x%X", Kernel, Node);
+
+ gckOS_AtomIncrement(Kernel->os, Node->reference, &oldValue);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckVIDMEM_HANDLE_Reference(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctUINT32 Handle
+ )
+{
+ gceSTATUS status;
+ gckVIDMEM_HANDLE handleObject = gcvNULL;
+ gctPOINTER database = gcvNULL;
+ gctPOINTER mutex = gcvNULL;
+ gctINT32 oldValue = 0;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Handle=%d PrcoessID=%d", Handle, ProcessID);
+
+ gcmkONERROR(
+ gckKERNEL_FindHandleDatbase(Kernel, ProcessID, &database, &mutex));
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Translate handle to gckVIDMEM_HANDLE object. */
+ gcmkONERROR(
+ gckKERNEL_QueryIntegerId(database, Handle, (gctPOINTER *)&handleObject));
+
+ /* Increase the reference count. */
+ gckOS_AtomIncrement(Kernel->os, handleObject->reference, &oldValue);
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+ acquired = gcvFALSE;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckVIDMEM_HANDLE_Dereference(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctUINT32 Handle
+ )
+{
+ gceSTATUS status;
+ gctPOINTER handleDatabase = gcvNULL;
+ gctPOINTER mutex = gcvNULL;
+ gctINT32 oldValue = 0;
+ gckVIDMEM_HANDLE handleObject = gcvNULL;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Handle=%d PrcoessID=%d", Handle, ProcessID);
+
+ gcmkONERROR(
+ gckKERNEL_FindHandleDatbase(Kernel,
+ ProcessID,
+ &handleDatabase,
+ &mutex));
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Translate handle to gckVIDMEM_HANDLE. */
+ gcmkONERROR(
+ gckKERNEL_QueryIntegerId(handleDatabase, Handle, (gctPOINTER *)&handleObject));
+
+ gckOS_AtomDecrement(Kernel->os, handleObject->reference, &oldValue);
+
+ if (oldValue == 1)
+ {
+ /* Remove handle from database if this is the last reference. */
+ gcmkVERIFY_OK(gckKERNEL_FreeIntegerId(handleDatabase, Handle));
+ }
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+ acquired = gcvFALSE;
+
+ if (oldValue == 1)
+ {
+ gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, handleObject->reference));
+ gcmkOS_SAFE_FREE(Kernel->os, handleObject);
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckVIDMEM_HANDLE_LookupAndReference(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Handle,
+ OUT gckVIDMEM_NODE * Node
+ )
+{
+ gceSTATUS status;
+ gckVIDMEM_HANDLE handleObject = gcvNULL;
+ gckVIDMEM_NODE node = gcvNULL;
+ gctPOINTER database = gcvNULL;
+ gctPOINTER mutex = gcvNULL;
+ gctUINT32 processID = 0;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Kernel=0x%X Handle=%d", Kernel, Handle);
+
+ gckOS_GetProcessID(&processID);
+
+ gcmkONERROR(
+ gckKERNEL_FindHandleDatbase(Kernel, processID, &database, &mutex));
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Translate handle to gckVIDMEM_HANDLE object. */
+ gcmkONERROR(
+ gckKERNEL_QueryIntegerId(database, Handle, (gctPOINTER *)&handleObject));
+
+ /* Get gckVIDMEM_NODE object. */
+ node = handleObject->node;
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+ acquired = gcvFALSE;
+
+ /* Reference this gckVIDMEM_NODE object. */
+ gcmkVERIFY_OK(gckVIDMEM_NODE_Reference(Kernel, node));
+
+ /* Return result. */
+ *Node = node;
+
+ gcmkFOOTER_ARG("*Node=%d", *Node);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckVIDMEM_HANDLE_Lookup(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctUINT32 Handle,
+ OUT gckVIDMEM_NODE * Node
+ )
+{
+ gceSTATUS status;
+ gckVIDMEM_HANDLE handleObject = gcvNULL;
+ gckVIDMEM_NODE node = gcvNULL;
+ gctPOINTER database = gcvNULL;
+ gctPOINTER mutex = gcvNULL;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Kernel=0x%X ProcessID=%d Handle=%d",
+ Kernel, ProcessID, Handle);
+
+ gcmkONERROR(
+ gckKERNEL_FindHandleDatbase(Kernel, ProcessID, &database, &mutex));
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ gcmkONERROR(
+ gckKERNEL_QueryIntegerId(database, Handle, (gctPOINTER *)&handleObject));
+
+ node = handleObject->node;
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+ acquired = gcvFALSE;
+
+ *Node = node;
+
+ gcmkFOOTER_ARG("*Node=%d", *Node);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckVIDMEM_NODE_Allocate
+**
+** Allocate a gckVIDMEM_NODE object.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gcuVIDMEM_NODE_PTR Node
+** Pointer to a gcuVIDMEM_NODE union.
+**
+** OUTPUT:
+**
+** gctUINT32 * Handle
+** Pointer to a variable receiving a handle represent this
+** gckVIDMEM_NODE in userspace.
+*/
+gceSTATUS
+gckVIDMEM_NODE_Allocate(
+ IN gckKERNEL Kernel,
+ IN gcuVIDMEM_NODE_PTR VideoNode,
+ IN gceSURF_TYPE Type,
+ IN gcePOOL Pool,
+ IN gctUINT32 * Handle
+ )
+{
+ gceSTATUS status;
+ gckVIDMEM_NODE node = gcvNULL;
+ gctPOINTER pointer = gcvNULL;
+ gctUINT32 handle = 0;
+ gckOS os = Kernel->os;
+ gctUINT i;
+
+ gcmkHEADER_ARG("Kernel=0x%X VideoNode=0x%X", Kernel, VideoNode);
+
+ /* Construct a node. */
+ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsVIDMEM_NODE), &pointer));
+
+ gcmkVERIFY_OK(gckOS_ZeroMemory(pointer, gcmSIZEOF(gcsVIDMEM_NODE)));
+
+ node = pointer;
+
+ node->metadata.magic = VIV_VIDMEM_METADATA_MAGIC;
+ node->metadata.ts_fd = -1;
+
+ node->node = VideoNode;
+ node->kernel = Kernel;
+ node->type = Type;
+ node->pool = Pool;
+
+#if gcdPROCESS_ADDRESS_SPACE
+ gcmkONERROR(gckOS_CreateMutex(os, &node->mapMutex));
+#endif
+
+ gcmkONERROR(gckOS_AtomConstruct(os, &node->reference));
+
+ gcmkONERROR(gckOS_CreateMutex(os, &node->mutex));
+
+ for (i = 0; i < gcvENGINE_GPU_ENGINE_COUNT; i++)
+ {
+ gcmkONERROR(gckOS_CreateSignal(os, gcvFALSE, &node->sync[i].signal));
+ }
+
+ /* Reference is 1 by default . */
+ gckOS_AtomSet(os, node->reference, 1);
+
+ /* Create a handle to represent this node. */
+ gcmkONERROR(gckVIDMEM_HANDLE_Allocate(Kernel, node, &handle));
+
+ *Handle = handle;
+
+ gcmkFOOTER_ARG("*Handle=%d", *Handle);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (node != gcvNULL)
+ {
+#if gcdPROCESS_ADDRESS_SPACE
+ if (node->mapMutex != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_DeleteMutex(os, node->mapMutex));
+ }
+#endif
+
+ if (node->mutex)
+ {
+ gcmkVERIFY_OK(gckOS_DeleteMutex(os, node->mutex));
+ }
+
+ if (node->reference != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_AtomDestroy(os, node->reference));
+ }
+
+ for (i = 0; i < gcvENGINE_GPU_ENGINE_COUNT; i++)
+ {
+ if (node->sync[i].signal != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_DestroySignal(os, node->sync[i].signal));
+ }
+ }
+
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, node));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_Dereference(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM_NODE Node
+ )
+{
+ gctINT32 oldValue = 0;
+ gctPOINTER database = Kernel->db->nameDatabase;
+ gctPOINTER mutex = Kernel->db->nameDatabaseMutex;
+ gctUINT i;
+
+ gcmkHEADER_ARG("Kernel=0x%X Node=0x%X", Kernel, Node);
+
+ gcmkVERIFY_OK(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
+
+ gcmkVERIFY_OK(gckOS_AtomDecrement(Kernel->os, Node->reference, &oldValue));
+
+ if (oldValue == 1 && Node->name)
+ {
+ /* Free name if exists. */
+ gcmkVERIFY_OK(gckKERNEL_FreeIntegerId(database, Node->name));
+ }
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+
+ if (oldValue == 1)
+ {
+ /* Free gcuVIDMEM_NODE. */
+ gcmkVERIFY_OK(gckVIDMEM_Free(Kernel, Node->node));
+ gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, Node->reference));
+#if gcdPROCESS_ADDRESS_SPACE
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Node->mapMutex));
+#endif
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Node->mutex));
+
+ for (i = 0; i < gcvENGINE_GPU_ENGINE_COUNT; i++)
+ {
+ if (Node->sync[i].signal != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_DestroySignal(Kernel->os, Node->sync[i].signal));
+ }
+ }
+
+ /* Should not cause recursive call since tsNode->tsNode should be NULL */
+ if (Node->tsNode)
+ {
+ gcmkASSERT(!Node->tsNode->tsNode);
+ gckVIDMEM_NODE_Dereference(Kernel, Node->tsNode);
+ }
+
+ gcmkOS_SAFE_FREE(Kernel->os, Node);
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+#if defined(CONFIG_DMA_SHARED_BUFFER)
+
+/*******************************************************************************
+**
+**
+** Code for dma_buf ops
+**
+**
+*******************************************************************************/
+
+#include <linux/slab.h>
+#include <linux/mm_types.h>
+#include <linux/dma-buf.h>
+
+static struct sg_table *_dmabuf_map(struct dma_buf_attachment *attachment,
+ enum dma_data_direction direction)
+{
+ struct sg_table *sgt = gcvNULL;
+ struct dma_buf *dmabuf = attachment->dmabuf;
+ gckVIDMEM_NODE nodeObject = dmabuf->priv;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ do
+ {
+ gcuVIDMEM_NODE_PTR node = nodeObject->node;
+ gctPHYS_ADDR physical = gcvNULL;
+ gctSIZE_T offset = 0;
+ gctSIZE_T bytes = 0;
+
+ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
+ {
+ physical = node->VidMem.memory->physical;
+ offset = node->VidMem.offset;
+ bytes = node->VidMem.bytes;
+ }
+ else
+ {
+ physical = node->Virtual.physical;
+ offset = 0;
+ bytes = node->Virtual.bytes;
+ }
+
+ gcmkERR_BREAK(gckOS_MemoryGetSGT(nodeObject->kernel->os, physical, offset, bytes, (gctPOINTER*)&sgt));
+
+ if (dma_map_sg(attachment->dev, sgt->sgl, sgt->nents, direction) == 0)
+ {
+ sg_free_table(sgt);
+ kfree(sgt);
+ sgt = gcvNULL;
+ gcmkERR_BREAK(gcvSTATUS_GENERIC_IO);
+ }
+ }
+ while (gcvFALSE);
+
+ return sgt;
+}
+
+static void _dmabuf_unmap(struct dma_buf_attachment *attachment,
+ struct sg_table *sgt,
+ enum dma_data_direction direction)
+{
+ dma_unmap_sg(attachment->dev, sgt->sgl, sgt->nents, direction);
+
+ sg_free_table(sgt);
+ kfree(sgt);
+}
+
+static int _dmabuf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
+{
+ gckVIDMEM_NODE nodeObject = dmabuf->priv;
+ gcuVIDMEM_NODE_PTR node = nodeObject->node;
+ gctPHYS_ADDR physical = gcvNULL;
+ gctSIZE_T skipPages = vma->vm_pgoff;
+ gctSIZE_T numPages = PAGE_ALIGN(vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
+ {
+ physical = node->VidMem.memory->physical;
+ skipPages += (node->VidMem.offset >> PAGE_SHIFT);
+ }
+ else
+ {
+ physical = node->Virtual.physical;
+ }
+
+ gcmkONERROR(gckOS_MemoryMmap(nodeObject->kernel->os, physical, skipPages, numPages, vma));
+
+OnError:
+ return gcmIS_ERROR(status) ? -EINVAL : 0;
+}
+
+static void _dmabuf_release(struct dma_buf *dmabuf)
+{
+ gckVIDMEM_NODE nodeObject = dmabuf->priv;
+
+ gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(nodeObject->kernel, nodeObject));
+}
+
+static void *_dmabuf_kmap(struct dma_buf *dmabuf, unsigned long offset)
+{
+ gckVIDMEM_NODE nodeObject = dmabuf->priv;
+ gcuVIDMEM_NODE_PTR node = nodeObject->node;
+ gctINT8_PTR kvaddr = gcvNULL;
+ gctPHYS_ADDR physical = gcvNULL;
+ gctSIZE_T bytes = 0;
+ gctSIZE_T pageCount = 0;
+
+ offset = (offset << PAGE_SHIFT);
+ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
+ {
+ physical = node->VidMem.memory->physical;
+ offset += node->VidMem.offset;
+ bytes = node->VidMem.bytes;
+ }
+ else
+ {
+ physical = node->Virtual.physical;
+ bytes = node->Virtual.bytes;
+ }
+
+ if (gcmIS_SUCCESS(gckOS_CreateKernelVirtualMapping(
+ nodeObject->kernel->os, physical, bytes, (gctPOINTER*)&kvaddr, &pageCount)))
+ {
+ kvaddr += offset;
+ }
+
+ return (gctPOINTER)kvaddr;
+}
+
+static void _dmabuf_kunmap(struct dma_buf *dmabuf, unsigned long offset, void *ptr)
+{
+ gckVIDMEM_NODE nodeObject = dmabuf->priv;
+ gcuVIDMEM_NODE_PTR node = nodeObject->node;
+ gctINT8_PTR kvaddr = (gctINT8_PTR)ptr - (offset << PAGE_SHIFT);
+ gctPHYS_ADDR physical = gcvNULL;
+ gctSIZE_T bytes = 0;
+
+ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
+ {
+ physical = node->VidMem.memory->physical;
+ kvaddr -= node->VidMem.offset;
+ bytes = node->VidMem.bytes;
+ }
+ else
+ {
+ physical = node->Virtual.physical;
+ bytes = node->Virtual.bytes;
+ }
+
+ gcmkVERIFY_OK(gckOS_DestroyKernelVirtualMapping(
+ nodeObject->kernel->os, physical, bytes, (gctPOINTER*)&kvaddr));
+}
+
+static struct dma_buf_ops _dmabuf_ops =
+{
+ .map_dma_buf = _dmabuf_map,
+ .unmap_dma_buf = _dmabuf_unmap,
+ .mmap = _dmabuf_mmap,
+ .release = _dmabuf_release,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0)
+ .map_atomic = _dmabuf_kmap,
+ .unmap_atomic = _dmabuf_kunmap,
+ .map = _dmabuf_kmap,
+ .unmap = _dmabuf_kunmap,
+# else
+ .kmap_atomic = _dmabuf_kmap,
+ .kunmap_atomic = _dmabuf_kunmap,
+ .kmap = _dmabuf_kmap,
+ .kunmap = _dmabuf_kunmap,
+# endif
+};
+#endif
+
+gceSTATUS
+gckVIDMEM_NODE_Export(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Handle,
+ IN gctINT32 Flags,
+ OUT gctPOINTER *DmaBuf,
+ OUT gctINT32 *FD
+ )
+{
+#if defined(CONFIG_DMA_SHARED_BUFFER)
+ gceSTATUS status = gcvSTATUS_OK;
+ gckVIDMEM_NODE nodeObject = gcvNULL;
+ gctUINT32 processID = 0;
+ struct dma_buf *dmabuf = gcvNULL;
+
+ gcmkHEADER_ARG("Kernel=%p Handle=0x%x", Kernel, Handle);
+
+ gckOS_GetProcessID(&processID);
+ gcmkONERROR(gckVIDMEM_HANDLE_Lookup(Kernel, processID, Handle, &nodeObject));
+
+ dmabuf = nodeObject->dmabuf;
+ if (!dmabuf)
+ {
+ gctSIZE_T bytes = 0;
+ gctPHYS_ADDR physical = gcvNULL;
+ gcuVIDMEM_NODE_PTR node = nodeObject->node;
+
+ if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM)
+ {
+ physical = node->VidMem.memory->physical;
+ bytes = node->VidMem.bytes;
+ }
+ else
+ {
+ physical = node->Virtual.physical;
+ bytes = node->Virtual.bytes;
+ }
+
+ /* Donot really get SGT, just check if the allocator support GetSGT. */
+ gcmkONERROR(gckOS_MemoryGetSGT(Kernel->os, physical, 0, 0, NULL));
+
+ {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+ exp_info.ops = &_dmabuf_ops;
+ exp_info.size = bytes;
+ exp_info.flags = Flags;
+ exp_info.priv = nodeObject;
+ dmabuf = dma_buf_export(&exp_info);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
+ dmabuf = dma_buf_export(nodeObject, &_dmabuf_ops, bytes, Flags, NULL);
+#else
+ dmabuf = dma_buf_export(nodeObject, &_dmabuf_ops, bytes, Flags);
+#endif
+ }
+
+ if (IS_ERR(dmabuf))
+ {
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+ /* Reference this gckVIDMEM_NODE object. */
+ gckVIDMEM_NODE_Reference(Kernel, nodeObject);
+ nodeObject->dmabuf = dmabuf;
+ }
+
+ if (DmaBuf)
+ {
+ *DmaBuf = nodeObject->dmabuf;
+ }
+
+ if (FD)
+ {
+ gctINT fd = dma_buf_fd(dmabuf, Flags);
+
+ if (fd < 0)
+ {
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+ *FD = fd;
+ }
+
+OnError:
+ gcmkFOOTER_ARG("*DmaBuf=%p *FD=0x%x", gcmOPT_POINTER(DmaBuf), gcmOPT_VALUE(FD));
+ return status;
+#else
+ gcmkFATAL("The kernel did NOT support CONFIG_DMA_SHARED_BUFFER");
+ return gcvSTATUS_NOT_SUPPORTED;
+#endif
+}
+
+
+/*******************************************************************************
+**
+** gckVIDMEM_NODE_Name
+**
+** Naming a gckVIDMEM_NODE object.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctUINT32 Handle
+** Handle to a gckVIDMEM_NODE object.
+**
+** OUTPUT:
+**
+** gctUINT32 * Name
+** Pointer to a variable receiving a name which can be pass to another
+** process.
+*/
+gceSTATUS
+gckVIDMEM_NODE_Name(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Handle,
+ OUT gctUINT32 * Name
+ )
+{
+ gceSTATUS status;
+ gckVIDMEM_NODE node = gcvNULL;
+ gctUINT32 name = 0;
+ gctUINT32 processID = 0;
+ gctPOINTER database = Kernel->db->nameDatabase;
+ gctPOINTER mutex = Kernel->db->nameDatabaseMutex;
+ gctBOOL acquired = gcvFALSE;
+ gctBOOL referenced = gcvFALSE;
+ gcmkHEADER_ARG("Kernel=0x%X Handle=%d", Kernel, Handle);
+
+ gcmkVERIFY_ARGUMENT(Name != gcvNULL);
+
+ gcmkONERROR(gckOS_GetProcessID(&processID));
+
+ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ gcmkONERROR(gckVIDMEM_HANDLE_LookupAndReference(Kernel, Handle, &node));
+ referenced = gcvTRUE;
+
+ if (node->name == 0)
+ {
+ /* Name this node. */
+ gcmkONERROR(gckKERNEL_AllocateIntegerId(database, node, &name));
+ node->name = name;
+ }
+ else
+ {
+ name = node->name;
+ }
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+ acquired = gcvFALSE;
+
+ gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, node));
+
+ *Name = name;
+
+ gcmkFOOTER_ARG("*Name=%d", *Name);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (referenced)
+ {
+ gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, node));
+ }
+
+ if (acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckVIDMEM_NODE_Import
+**
+** Import a gckVIDMEM_NODE object.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctUINT32 Name
+** Name of a gckVIDMEM_NODE object.
+**
+** OUTPUT:
+**
+** gctUINT32 * Handle
+** Pointer to a variable receiving a handle represent this
+** gckVIDMEM_NODE in userspace.
+*/
+gceSTATUS
+gckVIDMEM_NODE_Import(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Name,
+ OUT gctUINT32 * Handle
+ )
+{
+ gceSTATUS status;
+ gckVIDMEM_NODE node = gcvNULL;
+ gctPOINTER database = Kernel->db->nameDatabase;
+ gctPOINTER mutex = Kernel->db->nameDatabaseMutex;
+ gctBOOL acquired = gcvFALSE;
+ gctBOOL referenced = gcvFALSE;
+
+ gcmkHEADER_ARG("Kernel=0x%X Name=%d", Kernel, Name);
+
+ gcmkONERROR(gckOS_AcquireMutex(Kernel->os, mutex, gcvINFINITE));
+ acquired = gcvTRUE;
+
+ /* Lookup in database to get the node. */
+ gcmkONERROR(gckKERNEL_QueryIntegerId(database, Name, (gctPOINTER *)&node));
+
+ /* Reference the node. */
+ gcmkONERROR(gckVIDMEM_NODE_Reference(Kernel, node));
+ referenced = gcvTRUE;
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+ acquired = gcvFALSE;
+
+ /* Allocate a handle for current process. */
+ gcmkONERROR(gckVIDMEM_HANDLE_Allocate(Kernel, node, Handle));
+
+ gcmkFOOTER_ARG("*Handle=%d", *Handle);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (referenced)
+ {
+ gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, node));
+ }
+
+ if (acquired)
+ {
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, mutex));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+typedef struct _gcsVIDMEM_NODE_FDPRIVATE
+{
+ gcsFDPRIVATE base;
+ gckKERNEL kernel;
+ gckVIDMEM_NODE node;
+}
+gcsVIDMEM_NODE_FDPRIVATE;
+
+
+static gctINT
+_ReleaseFdPrivate(
+ gcsFDPRIVATE_PTR FdPrivate
+ )
+{
+ /* Cast private info. */
+ gcsVIDMEM_NODE_FDPRIVATE * private = (gcsVIDMEM_NODE_FDPRIVATE *) FdPrivate;
+
+ gckVIDMEM_NODE_Dereference(private->kernel, private->node);
+ gckOS_Free(private->kernel->os, private);
+
+ return 0;
+}
+
+
+/*******************************************************************************
+**
+** gckVIDMEM_NODE_GetFd
+**
+** Attach a gckVIDMEM_NODE object to a native fd.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctUINT32 Handle
+** Handle to a gckVIDMEM_NODE object.
+**
+** OUTPUT:
+**
+** gctUINT32 * Fd
+** Pointer to a variable receiving a native fd from os.
+*/
+gceSTATUS
+gckVIDMEM_NODE_GetFd(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Handle,
+ OUT gctINT * Fd
+ )
+{
+ gceSTATUS status;
+ gckVIDMEM_NODE node = gcvNULL;
+ gctBOOL referenced = gcvFALSE;
+ gcsVIDMEM_NODE_FDPRIVATE * fdPrivate = gcvNULL;
+ gcmkHEADER_ARG("Kernel=0x%X Handle=%d", Kernel, Handle);
+
+ /* Query and reference handle. */
+ gcmkONERROR(gckVIDMEM_HANDLE_LookupAndReference(Kernel, Handle, &node));
+ referenced = gcvTRUE;
+
+ /* Allocated fd owns a reference. */
+ gcmkONERROR(gckOS_Allocate(
+ Kernel->os,
+ gcmSIZEOF(gcsVIDMEM_NODE_FDPRIVATE),
+ (gctPOINTER *)&fdPrivate
+ ));
+
+ fdPrivate->base.release = _ReleaseFdPrivate;
+ fdPrivate->kernel = Kernel;
+ fdPrivate->node = node;
+
+ /* Allocated fd owns a reference. */
+ gcmkONERROR(gckOS_GetFd("vidmem", &fdPrivate->base, Fd));
+
+ gcmkFOOTER_ARG("*Fd=%d", *Fd);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (referenced)
+ {
+ gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, node));
+ }
+
+ if (fdPrivate)
+ {
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, fdPrivate));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckVIDMEM_NODE_WrapUserMemory(
+ IN gckKERNEL Kernel,
+ IN gcsUSER_MEMORY_DESC_PTR Desc,
+ OUT gctUINT32 * Handle,
+ OUT gctUINT64 * Bytes
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+ gctBOOL found = gcvFALSE;
+
+ gcmkHEADER_ARG("Kernel=0x%x", Kernel);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Desc);
+ gcmkVERIFY_ARGUMENT(Handle);
+ gcmkVERIFY_ARGUMENT(Bytes);
+
+#if defined(CONFIG_DMA_SHARED_BUFFER)
+ if (Desc->flag & gcvALLOC_FLAG_DMABUF)
+ {
+ struct dma_buf *dmabuf;
+ int fd = (int)Desc->handle;
+
+ if (fd >= 0)
+ {
+ /* Import dma buf handle. */
+ dmabuf = dma_buf_get(fd);
+
+ Desc->handle = -1;
+ Desc->dmabuf = gcmPTR_TO_UINT64(dmabuf);
+
+ dma_buf_put(dmabuf);
+ }
+ else
+ {
+ dmabuf = gcmUINT64_TO_PTR(Desc->dmabuf);
+ }
+
+ if (dmabuf->ops == &_dmabuf_ops)
+ {
+ gctBOOL referenced = gcvFALSE;
+ gckVIDMEM_NODE nodeObject = dmabuf->priv;
+
+ do
+ {
+ /* Reference the node. */
+ gcmkERR_BREAK(gckVIDMEM_NODE_Reference(Kernel, nodeObject));
+ referenced = gcvTRUE;
+ /* Allocate a handle for current process. */
+ gcmkERR_BREAK(gckVIDMEM_HANDLE_Allocate(Kernel, nodeObject, Handle));
+ found = gcvTRUE;
+
+ *Bytes = (gctUINT64)dmabuf->size;
+ }
+ while (gcvFALSE);
+
+ if (gcmIS_ERROR(status) && referenced)
+ {
+ gcmkVERIFY_OK(gckVIDMEM_NODE_Dereference(Kernel, nodeObject));
+ }
+ }
+ }
+#endif
+
+ if (!found)
+ {
+ gckOS os = Kernel->os;
+ gcuVIDMEM_NODE_PTR node = gcvNULL;
+
+ gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+ do {
+ /* Allocate an gcuVIDMEM_NODE union. */
+ gcmkERR_BREAK(gckOS_Allocate(os, gcmSIZEOF(gcuVIDMEM_NODE), (gctPOINTER*)&node));
+ gckOS_ZeroMemory(node, gcmSIZEOF(gcuVIDMEM_NODE));
+
+ /* Initialize gcuVIDMEM_NODE union for virtual memory. */
+ node->Virtual.kernel = Kernel;
+
+ /* Wrap Memory. */
+ gcmkERR_BREAK(gckOS_WrapMemory(os, Desc, &node->Virtual.bytes,
+ &node->Virtual.physical, &node->Virtual.contiguous));
+
+ /* Allocate handle for this video memory. */
+ gcmkERR_BREAK(gckVIDMEM_NODE_Allocate(
+ Kernel,
+ node,
+ gcvSURF_BITMAP,
+ gcvPOOL_VIRTUAL,
+ Handle
+ ));
+
+ *Bytes = (gctUINT64)node->Virtual.bytes;
+ }
+ while (gcvFALSE);
+
+ if (gcmIS_ERROR(status) && node)
+ {
+ /* Free the structure. */
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, node));
+ }
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckVIDMEM_SetCommitStamp(
+ IN gckKERNEL Kernel,
+ IN gceENGINE Engine,
+ IN gctUINT32 Handle,
+ IN gctUINT64 CommitStamp
+ )
+{
+ gceSTATUS status;
+ gckVIDMEM_NODE node;
+ gctUINT32 processID;
+
+ gckOS_GetProcessID(&processID);
+
+ gcmkONERROR(gckVIDMEM_HANDLE_LookupAndReference(Kernel, Handle, &node));
+
+ node->sync[Engine].commitStamp = CommitStamp;
+
+ gckVIDMEM_NODE_Dereference(Kernel, node);
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+gceSTATUS
+gckVIDMEM_GetCommitStamp(
+ IN gckKERNEL Kernel,
+ IN gceENGINE Engine,
+ IN gctUINT32 Handle,
+ OUT gctUINT64_PTR CommitStamp
+ )
+{
+ gceSTATUS status;
+ gckVIDMEM_NODE node;
+ gctUINT32 processID;
+
+ gckOS_GetProcessID(&processID);
+
+ gcmkONERROR(gckVIDMEM_HANDLE_LookupAndReference(Kernel, Handle, &node));
+
+ *CommitStamp = node->sync[Engine].commitStamp;
+
+ gckVIDMEM_NODE_Dereference(Kernel, node);
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+gceSTATUS
+gckVIDMEM_FindVIDMEM(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 HardwareAddress,
+ OUT gcuVIDMEM_NODE_PTR * Node,
+ OUT gctUINT32_PTR PageTableEntryValue
+ )
+{
+ gceSTATUS status = gcvSTATUS_NOT_FOUND;
+ gcuVIDMEM_NODE_PTR node = gcvNULL;
+
+ gcsLISTHEAD_PTR pos;
+
+ gcmkLIST_FOR_EACH(pos, &Kernel->db->onFaultVidmemList)
+ {
+ node = (gcuVIDMEM_NODE_PTR)gcmCONTAINEROF(pos, _gcsVIDMEM_NODE_VIRTUAL, head);
+
+ if (HardwareAddress >= node->Virtual.addresses[Kernel->core]
+ && (HardwareAddress <= node->Virtual.addresses[Kernel->core] - 1 + node->Virtual.bytes)
+ )
+ {
+ *Node = node;
+ status = gcvSTATUS_OK;
+ break;
+ }
+ }
+
+ if (gcmIS_SUCCESS(status))
+ {
+ /* Setup map for fault address. */
+ gctUINT32 offset = HardwareAddress - node->Virtual.addresses[Kernel->core];
+ gctPHYS_ADDR_T physicalAddress;
+
+ offset &= ~gcdMMU_PAGE_4K_MASK;
+
+ gckOS_PhysicalToPhysicalAddress(Kernel->os, node->Virtual.physical, offset, &physicalAddress);
+
+ gcmkSAFECASTPHYSADDRT(*PageTableEntryValue, physicalAddress);
+ }
+
+ return status;
+}
+
+/* Get the nodes of all banks. */
+gceSTATUS
+gckVIDMEM_QueryNodes(
+ IN gckKERNEL Kernel,
+ IN gcePOOL Pool,
+ OUT gctINT32 *Count,
+ OUT gcuVIDMEM_NODE_PTR *Nodes
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+ gckVIDMEM memory = gcvNULL;
+
+ do
+ {
+ status = gckKERNEL_GetVideoMemoryPool(Kernel, Pool, &memory);
+ if (status != gcvSTATUS_OK)
+ break;
+
+ if (memory != gcvNULL)
+ {
+ *Count = gcmCOUNTOF(memory->sentinel);
+ *Nodes = memory->sentinel;
+ }
+ }
+ while (gcvFALSE);
+
+ return status;
+}
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_feature_database.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_feature_database.h
new file mode 100644
index 000000000000..be74a97fb36b
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_feature_database.h
@@ -0,0 +1,68191 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+/*Auto created on 2018-05-02 10:01*/
+#ifndef _gc_feature_database_h_
+#define _gc_feature_database_h_
+
+typedef struct
+{
+ /* Chip ID. */
+ gctUINT32 chipID;
+ gctUINT32 chipVersion;
+ gctUINT32 productID;
+ gctUINT32 ecoID;
+ gctUINT32 customerID;
+ gctUINT32 patchVersion;
+ gctUINT32 formalRelease;
+ gctUINT32 Streams;
+ gctUINT32 TempRegisters;
+ gctUINT32 ThreadCount;
+ gctUINT32 VertexCacheSize;
+ gctUINT32 NumShaderCores;
+ gctUINT32 NumPixelPipes;
+ gctUINT32 VertexOutputBufferSize;
+ gctUINT32 BufferSize;
+ gctUINT32 InstructionCount;
+ gctUINT32 NumberOfConstants;
+ gctUINT32 CoreCount;
+ gctUINT32 VaryingCount;
+ gctUINT32 LocalStorageSize;
+ gctUINT32 L1CacheSize;
+ gctUINT32 InstructionMemorySize;
+ gctUINT32 ShaderPCLength;
+ gctUINT32 NumResolvePipes;
+ gctUINT32 USC_MAX_PAGES;
+ gctUINT32 RESULT_WINDOW_MAX_SIZE;
+ gctUINT32 NNMadPerCore;
+ gctUINT32 NNCoreCount;
+ gctUINT32 NNCoreCount_INT8;
+ gctUINT32 NNCoreCount_INT16;
+ gctUINT32 NNCoreCount_FLOAT16;
+ gctUINT32 NNInputBufferDepth;
+ gctUINT32 NNAccumBufferDepth;
+ gctUINT32 ClusterAliveMask;
+ gctUINT32 TPEngine_PwlLUTCount;
+ gctUINT32 TPEngine_PwlLUTSize;
+ gctUINT32 VIP_SRAM_SIZE;
+ gctUINT32 TPEngine_CoreCount;
+ gctUINT32 AXI_SRAM_SIZE;
+ gctUINT32 NN_INIMAGE_OFFSET_BITS;
+ gctUINT32 REG_FastClear:1;
+ gctUINT32 REG_SpecialAntiAliasing:1;
+ gctUINT32 REG_Pipe3D:1;
+ gctUINT32 REG_DXTTextureCompression:1;
+ gctUINT32 REG_DebugMode:1;
+ gctUINT32 REG_ZCompression:1;
+ gctUINT32 REG_YUV420Filter:1;
+ gctUINT32 REG_MSAA:1;
+ gctUINT32 REG_DC:1;
+ gctUINT32 REG_Pipe2D:1;
+ gctUINT32 REG_ETC1TextureCompression:1;
+ gctUINT32 REG_FastScaler:1;
+ gctUINT32 REG_HighDynamicRange:1;
+ gctUINT32 REG_YUV420Tiler:1;
+ gctUINT32 REG_ModuleCG:1;
+ gctUINT32 REG_MinArea:1;
+ gctUINT32 REG_NoEZ:1;
+ gctUINT32 REG_No422Texture:1;
+ gctUINT32 REG_BufferInterleaving:1;
+ gctUINT32 REG_ByteWrite2D:1;
+ gctUINT32 REG_NoScaler:1;
+ gctUINT32 REG_YUY2Averaging:1;
+ gctUINT32 REG_HalfPECache:1;
+ gctUINT32 REG_HalfTXCache:1;
+ gctUINT32 REG_YUY2RenderTarget:1;
+ gctUINT32 REG_Mem32BitSupport:1;
+ gctUINT32 REG_PipeVG:1;
+ gctUINT32 REG_VGTS:1;
+ gctUINT32 REG_FE20:1;
+ gctUINT32 REG_ByteWrite3D:1;
+ gctUINT32 REG_RsYuvTarget:1;
+ gctUINT32 REG_FE20BitIndex:1;
+ gctUINT32 REG_FlipY:1;
+ gctUINT32 REG_DualReturnBus:1;
+ gctUINT32 REG_EndiannessConfig:1;
+ gctUINT32 REG_Texture8K:1;
+ gctUINT32 REG_CorrectTextureConverter:1;
+ gctUINT32 REG_SpecialMsaaLod:1;
+ gctUINT32 REG_FastClearFlush:1;
+ gctUINT32 REG_2DPE20:1;
+ gctUINT32 REG_CorrectAutoDisable:1;
+ gctUINT32 REG_Render8K:1;
+ gctUINT32 REG_TileStatus2Bits:1;
+ gctUINT32 REG_SeparateTileStatusWhenInterleaved:1;
+ gctUINT32 REG_SuperTiled32x32:1;
+ gctUINT32 REG_VG20:1;
+ gctUINT32 REG_TSExtendedCommands:1;
+ gctUINT32 REG_CompressionFifoFixed:1;
+ gctUINT32 REG_ExtraShaderInstructions0:1;
+ gctUINT32 REG_VGFilter:1;
+ gctUINT32 REG_VG21:1;
+ gctUINT32 REG_ShaderGetsW:1;
+ gctUINT32 REG_ExtraShaderInstructions1:1;
+ gctUINT32 REG_DefaultReg0:1;
+ gctUINT32 REG_MC20:1;
+ gctUINT32 REG_ShaderMSAASideband:1;
+ gctUINT32 REG_BugFixes0:1;
+ gctUINT32 REG_VAA:1;
+ gctUINT32 REG_BypassInMSAA:1;
+ gctUINT32 REG_HierarchicalZ:1;
+ gctUINT32 REG_NewTexture:1;
+ gctUINT32 REG_A8TargetSupport:1;
+ gctUINT32 REG_CorrectStencil:1;
+ gctUINT32 REG_EnhanceVR:1;
+ gctUINT32 REG_RSUVSwizzle:1;
+ gctUINT32 REG_V2Compression:1;
+ gctUINT32 REG_VGDoubleBuffer:1;
+ gctUINT32 REG_BugFixes1:1;
+ gctUINT32 REG_BugFixes2:1;
+ gctUINT32 REG_TextureStride:1;
+ gctUINT32 REG_BugFixes3:1;
+ gctUINT32 REG_CorrectAutoDisable1:1;
+ gctUINT32 REG_AutoRestartTS:1;
+ gctUINT32 REG_BugFixes4:1;
+ gctUINT32 REG_L2Windowing:1;
+ gctUINT32 REG_HalfFloatPipe:1;
+ gctUINT32 REG_PixelDither:1;
+ gctUINT32 REG_TwoStencilReference:1;
+ gctUINT32 REG_ExtendedPixelFormat:1;
+ gctUINT32 REG_CorrectMinMaxDepth:1;
+ gctUINT32 REG_DitherAndFilterPlusAlpha2D:1;
+ gctUINT32 REG_BugFixes5:1;
+ gctUINT32 REG_New2D:1;
+ gctUINT32 REG_NewFloatingPointArithmetic:1;
+ gctUINT32 REG_TextureHorizontalAlignmentSelect:1;
+ gctUINT32 REG_NonPowerOfTwo:1;
+ gctUINT32 REG_LinearTextureSupport:1;
+ gctUINT32 REG_Halti0:1;
+ gctUINT32 REG_CorrectOverflowVG:1;
+ gctUINT32 REG_NegativeLogFix:1;
+ gctUINT32 REG_ResolveOffset:1;
+ gctUINT32 REG_OkToGateAxiClock:1;
+ gctUINT32 REG_MMU:1;
+ gctUINT32 REG_WideLine:1;
+ gctUINT32 REG_BugFixes6:1;
+ gctUINT32 REG_FcFlushStall:1;
+ gctUINT32 REG_LineLoop:1;
+ gctUINT32 REG_LogicOp:1;
+ gctUINT32 REG_SeamlessCubeMap:1;
+ gctUINT32 REG_SuperTiledTexture:1;
+ gctUINT32 REG_LinearPE:1;
+ gctUINT32 REG_RectPrimitive:1;
+ gctUINT32 REG_Composition:1;
+ gctUINT32 REG_CorrectAutoDisableCountWidth:1;
+ gctUINT32 REG_PESwizzle:1;
+ gctUINT32 REG_EndEvent:1;
+ gctUINT32 REG_S1S8:1;
+ gctUINT32 REG_Halti1:1;
+ gctUINT32 REG_RGB888:1;
+ gctUINT32 REG_TX_YUVAssembler:1;
+ gctUINT32 REG_DynamicFrequencyScaling:1;
+ gctUINT32 REG_TXFilter:1;
+ gctUINT32 REG_FullDirectFB:1;
+ gctUINT32 REG_OnePass2DFilter:1;
+ gctUINT32 REG_ThreadWalkerInPS:1;
+ gctUINT32 REG_TileFiller:1;
+ gctUINT32 REG_YUVStandard:1;
+ gctUINT32 REG_MultiSourceBlt:1;
+ gctUINT32 REG_YUVConversion:1;
+ gctUINT32 REG_FlushFixed2D:1;
+ gctUINT32 REG_Interleaver:1;
+ gctUINT32 REG_MixedStreams:1;
+ gctUINT32 REG_L2CacheFor2D420:1;
+ gctUINT32 REG_BugFixes7:1;
+ gctUINT32 REG_NoIndexPattern:1;
+ gctUINT32 REG_TextureTileStatus:1;
+ gctUINT32 REG_DecompressZ16:1;
+ gctUINT32 REG_BugFixes8:1;
+ gctUINT32 REG_DERotationStallFix:1;
+ gctUINT32 REG_OclOnly:1;
+ gctUINT32 REG_NewFeatures0:1;
+ gctUINT32 REG_InstructionCache:1;
+ gctUINT32 REG_GeometryShader:1;
+ gctUINT32 REG_TexCompressionSupertiled:1;
+ gctUINT32 REG_Generics:1;
+ gctUINT32 REG_BugFixes9:1;
+ gctUINT32 REG_FastMSAA:1;
+ gctUINT32 REG_WClip:1;
+ gctUINT32 REG_BugFixes10:1;
+ gctUINT32 REG_UnifiedSamplers:1;
+ gctUINT32 REG_BugFixes11:1;
+ gctUINT32 REG_PerformanceCounters:1;
+ gctUINT32 REG_ExtraShaderInstructions2:1;
+ gctUINT32 REG_BugFixes12:1;
+ gctUINT32 REG_BugFixes13:1;
+ gctUINT32 REG_DEEnhancements1:1;
+ gctUINT32 REG_ACE:1;
+ gctUINT32 REG_TXEnhancements1:1;
+ gctUINT32 REG_SHEnhancements1:1;
+ gctUINT32 REG_SHEnhancements2:1;
+ gctUINT32 REG_PEEnhancements1:1;
+ gctUINT32 REG_DEEnhancements2:1;
+ gctUINT32 REG_BugFixes14:1;
+ gctUINT32 REG_PowerOptimizations0:1;
+ gctUINT32 REG_NewHZ:1;
+ gctUINT32 REG_BugFixes15:1;
+ gctUINT32 REG_DEEnhancements3:1;
+ gctUINT32 REG_SHEnhancements3:1;
+ gctUINT32 REG_SHEnhancements4:1;
+ gctUINT32 REG_TXEnhancements2:1;
+ gctUINT32 REG_FEEnhancements1:1;
+ gctUINT32 REG_PEEnhancements2:1;
+ gctUINT32 REG_PAEnhancements1:1;
+ gctUINT32 REG_DENoGamma:1;
+ gctUINT32 REG_PAEnhancements2:1;
+ gctUINT32 REG_DEEnhancements4:1;
+ gctUINT32 REG_PEEnhancements3:1;
+ gctUINT32 REG_HIEnhancements1:1;
+ gctUINT32 REG_TXEnhancements3:1;
+ gctUINT32 REG_SHEnhancements5:1;
+ gctUINT32 REG_FEEnhancements2:1;
+ gctUINT32 REG_BugFixes16:1;
+ gctUINT32 REG_DEEnhancements5:1;
+ gctUINT32 REG_TXEnhancements4:1;
+ gctUINT32 REG_PEEnhancements4:1;
+ gctUINT32 REG_MCEnhancements1:1;
+ gctUINT32 REG_Halti2:1;
+ gctUINT32 REG_DEMirrorRotate:1;
+ gctUINT32 REG_SmallMSAA:1;
+ gctUINT32 REG_BugFixes17:1;
+ gctUINT32 REG_Rasterizer2:1;
+ gctUINT32 REG_DualPipeOPF:1;
+ gctUINT32 REG_MultiSrcV2:1;
+ gctUINT32 REG_CSCV2:1;
+ gctUINT32 REG_PAEnhancements3:1;
+ gctUINT32 REG_BugFixes18:1;
+ gctUINT32 REG_Compression2D:1;
+ gctUINT32 REG_Probe:1;
+ gctUINT32 REG_MediumPrecision:1;
+ gctUINT32 REG_DESupertile:1;
+ gctUINT32 REG_BugFixes19:1;
+ gctUINT32 REG_SHEnhancements6:1;
+ gctUINT32 REG_SHEnhancements7:1;
+ gctUINT32 REG_BugFixes20:1;
+ gctUINT32 REG_DEAddress40:1;
+ gctUINT32 REG_MiniMMUFix:1;
+ gctUINT32 REG_EEZ:1;
+ gctUINT32 REG_BugFixes21:1;
+ gctUINT32 REG_ExtraVgCaps:1;
+ gctUINT32 REG_MultiSrcV15:1;
+ gctUINT32 REG_BugFixes22:1;
+ gctUINT32 REG_Halti3:1;
+ gctUINT32 REG_TessellationShaders:1;
+ gctUINT32 REG_OPF9Tap:1;
+ gctUINT32 REG_MultiSrcV2StrQuad:1;
+ gctUINT32 REG_SeperateSRCAndDstCache:1;
+ gctUINT32 REG_Halti4:1;
+ gctUINT32 REG_RAWriteDepth:1;
+ gctUINT32 REG_AndroidOnly:1;
+ gctUINT32 REG_HasChipProductReg:1;
+ gctUINT32 REG_TXSupportDEC:1;
+ gctUINT32 REG_S8MSAACompression:1;
+ gctUINT32 REG_BugFixesIn544:1;
+ gctUINT32 REG_L2CacheRemove:1;
+ gctUINT32 REG_FEAllowRndVtxCnt:1;
+ gctUINT32 REG_CubeMapFL28:1;
+ gctUINT32 REG_TX6bitFrac:1;
+ gctUINT32 REG_FEAllowStallPrefetchEng:1;
+ gctUINT32 REG_ThirdPartyCompression:1;
+ gctUINT32 REG_RSS8:1;
+ gctUINT32 REG_MSAACoherencyCheck:1;
+ gctUINT32 REG_Halti5:1;
+ gctUINT32 REG_Evis:1;
+ gctUINT32 REG_BltEngine:1;
+ gctUINT32 REG_BugFixes23:1;
+ gctUINT32 REG_BugFixes24:1;
+ gctUINT32 REG_DEC:1;
+ gctUINT32 REG_VSTileNV12:1;
+ gctUINT32 REG_VSTileNV12_10BIT:1;
+ gctUINT32 RenderTarget8:1;
+ gctUINT32 TxLodFlowCorrection:1;
+ gctUINT32 FaceLod:1;
+ gctUINT32 MultiCoreSemaphoreStallV2:1;
+ gctUINT32 VMSAA:1;
+ gctUINT32 ChipEnableLink:1;
+ gctUINT32 MULTI_SRC_BLT_1_5_ENHANCEMENT:1;
+ gctUINT32 MULTI_SRC_BLT_BILINEAR_FILTER:1;
+ gctUINT32 RA_HZEZ_CLOCK_CONTROL:1;
+ gctUINT32 CACHE128B256BPERLINE:1;
+ gctUINT32 V4Compression:1;
+ gctUINT32 PE2D_MAJOR_SUPER_TILE:1;
+ gctUINT32 PE_32BPC_COLORMASK_FIX:1;
+ gctUINT32 ALPHA_BLENDING_OPT:1;
+ gctUINT32 NEW_GPIPE:1;
+ gctUINT32 PIPELINE_32_ATTRIBUTES:1;
+ gctUINT32 MSAA_SHADING:1;
+ gctUINT32 NO_ANISTRO_FILTER:1;
+ gctUINT32 NO_ASTC:1;
+ gctUINT32 NO_DXT:1;
+ gctUINT32 HWTFB:1;
+ gctUINT32 RA_DEPTH_WRITE_MSAA1X_FIX:1;
+ gctUINT32 EZHZ_CLOCKGATE_FIX:1;
+ gctUINT32 SH_SNAP2PAGE_FIX:1;
+ gctUINT32 SH_HALFDEPENDENCY_FIX:1;
+ gctUINT32 USC_MCFILL_FIX:1;
+ gctUINT32 TPG_TCPERF_FIX:1;
+ gctUINT32 USC_MDFIFO_OVERFLOW_FIX:1;
+ gctUINT32 SH_TEXLD_BARRIER_IN_CS_FIX:1;
+ gctUINT32 RS_NEW_BASEADDR:1;
+ gctUINT32 PE_8bpp_DUALPIPE_FIX:1;
+ gctUINT32 SH_ADVANCED_INSTR:1;
+ gctUINT32 SH_FLAT_INTERPOLATION_DUAL16_FIX:1;
+ gctUINT32 USC_CONTINUOUS_FLUS_FIX:1;
+ gctUINT32 SH_SUPPORT_V4:1;
+ gctUINT32 SH_SUPPORT_ALPHA_KILL:1;
+ gctUINT32 PE_NO_ALPHA_TEST:1;
+ gctUINT32 TX_LOD_NEAREST_SELECT:1;
+ gctUINT32 SH_FIX_LDEXP:1;
+ gctUINT32 SUPPORT_MOVAI:1;
+ gctUINT32 SH_SNAP2PAGE_MAXPAGES_FIX:1;
+ gctUINT32 PE_RGBA16I_FIX:1;
+ gctUINT32 BLT_8bpp_256TILE_FC_FIX:1;
+ gctUINT32 PE_64bit_FENCE_FIX:1;
+ gctUINT32 USC_FULL_CACHE_FIX:1;
+ gctUINT32 TX_YUV_ASSEMBLER_10BIT:1;
+ gctUINT32 FE_32bit_INDEX_FIX:1;
+ gctUINT32 BLT_64bpp_MASKED_CLEAR_FIX:1;
+ gctUINT32 SECURITY:1;
+ gctUINT32 ROBUSTNESS:1;
+ gctUINT32 USC_ATOMIC_FIX:1;
+ gctUINT32 SH_PSO_MSAA1x_FIX:1;
+ gctUINT32 USC_VX_PERF_FIX:1;
+ gctUINT32 EVIS_NO_ABSDIFF:1;
+ gctUINT32 EVIS_NO_BITREPLACE:1;
+ gctUINT32 EVIS_NO_BOXFILTER:1;
+ gctUINT32 EVIS_NO_CORDIAC:1;
+ gctUINT32 EVIS_NO_DP32:1;
+ gctUINT32 EVIS_NO_FILTER:1;
+ gctUINT32 EVIS_NO_IADD:1;
+ gctUINT32 EVIS_NO_SELECTADD:1;
+ gctUINT32 EVIS_LERP_7OUTPUT:1;
+ gctUINT32 EVIS_ACCSQ_8OUTPUT:1;
+ gctUINT32 USC_GOS_ADDR_FIX:1;
+ gctUINT32 TX_8bit_UVFrac:1;
+ gctUINT32 TX_DESC_CACHE_CLOCKGATE_FIX:1;
+ gctUINT32 RSBLT_MSAA_DECOMPRESSION:1;
+ gctUINT32 TX_INTEGER_COORDINATE:1;
+ gctUINT32 DRAWID:1;
+ gctUINT32 PSIO_SAMPLEMASK_IN_R0ZW_FIX:1;
+ gctUINT32 TX_INTEGER_COORDINATE_V2:1;
+ gctUINT32 MULTI_CORE_BLOCK_SET_CONFIG:1;
+ gctUINT32 VG_RESOLVE_ENGINE:1;
+ gctUINT32 VG_PE_COLOR_KEY:1;
+ gctUINT32 VG_IM_INDEX_FORMAT:1;
+ gctUINT32 SNAPPAGE_CMD:1;
+ gctUINT32 SH_NO_INDEX_CONST_ON_A0:1;
+ gctUINT32 SH_NO_ONECONST_LIMIT:1;
+ gctUINT32 SH_IMG_LDST_ON_TEMP:1;
+ gctUINT32 COMPUTE_ONLY:1;
+ gctUINT32 SH_IMG_LDST_CLAMP:1;
+ gctUINT32 SH_ICACHE_ALLOC_COUNT_FIX:1;
+ gctUINT32 SH_ICACHE_PREFETCH:1;
+ gctUINT32 PE2D_SEPARATE_CACHE:1;
+ gctUINT32 VG_AYUV_INPUT_OUTPUT:1;
+ gctUINT32 VG_DOUBLE_IMAGE:1;
+ gctUINT32 VG_RECTANGLE_STRIPE_MODE:1;
+ gctUINT32 VG_MMU:1;
+ gctUINT32 VG_IM_FILTER:1;
+ gctUINT32 VG_IM_YUV_PACKET:1;
+ gctUINT32 VG_IM_YUV_PLANAR:1;
+ gctUINT32 VG_PE_YUV_PACKET:1;
+ gctUINT32 VG_COLOR_PRECISION_8_BIT:1;
+ gctUINT32 PE_MSAA_OQ_FIX:1;
+ gctUINT32 PSIO_MSAA_CL_FIX:1;
+ gctUINT32 USC_DEFER_FILL_FIX:1;
+ gctUINT32 SH_CLOCK_GATE_FIX:1;
+ gctUINT32 FE_NEED_DUMMYDRAW:1;
+ gctUINT32 PE2D_LINEAR_YUV420_OUTPUT:1;
+ gctUINT32 PE2D_LINEAR_YUV420_10BIT:1;
+ gctUINT32 MULTI_CLUSTER:1;
+ gctUINT32 VG_TS_CULLING:1;
+ gctUINT32 VG_FP25:1;
+ gctUINT32 SH_MULTI_WG_PACK:1;
+ gctUINT32 SH_DUAL16_SAMPLEMASK_ZW:1;
+ gctUINT32 TPG_TRIVIAL_MODE_FIX:1;
+ gctUINT32 TX_ASTC_MULTISLICE_FIX:1;
+ gctUINT32 FE_ROBUST_FIX:1;
+ gctUINT32 SH_GPIPE_ACCESS_FULLTEMPS:1;
+ gctUINT32 PSIO_INTERLOCK:1;
+ gctUINT32 PA_WIDELINE_FIX:1;
+ gctUINT32 WIDELINE_HELPER_FIX:1;
+ gctUINT32 G2D_3rd_PARTY_COMPRESSION_1_1:1;
+ gctUINT32 TX_FLUSH_L1CACHE:1;
+ gctUINT32 PE_DITHER_FIX2:1;
+ gctUINT32 G2D_DEC400:1;
+ gctUINT32 SH_TEXLD_U_FIX:1;
+ gctUINT32 MC_FCCACHE_BYTEMASK:1;
+ gctUINT32 SH_MULTI_WG_PACK_FIX:1;
+ gctUINT32 DC_OVERLAY_SCALING:1;
+ gctUINT32 DC_SOURCE_ROTATION:1;
+ gctUINT32 DC_TILED:1;
+ gctUINT32 DC_YUV_L1:1;
+ gctUINT32 DC_D30_OUTPUT:1;
+ gctUINT32 DC_MMU:1;
+ gctUINT32 DC_COMPRESSION:1;
+ gctUINT32 DC_QOS:1;
+ gctUINT32 PE_ADVANCE_BLEND_PART0:1;
+ gctUINT32 FE_PATCHLIST_FETCH_FIX:1;
+ gctUINT32 RA_CG_FIX:1;
+ gctUINT32 EVIS_VX2:1;
+ gctUINT32 NN_FLOAT:1;
+ gctUINT32 DEC400:1;
+ gctUINT32 LS_SUPPORT_PERCOMP_DEPENDENCY:1;
+ gctUINT32 TP_ENGINE:1;
+ gctUINT32 MULTI_CORE_BLOCK_SET_CONFIG2:1;
+ gctUINT32 PE_VMSAA_COVERAGE_CACHE_FIX:1;
+ gctUINT32 SECURITY_AHB:1;
+ gctUINT32 MULTICORE_SEMAPHORESTALL_V3:1;
+ gctUINT32 SMALLBATCH:1;
+ gctUINT32 SH_CMPLX:1;
+ gctUINT32 SH_IDIV0_SWZL_EHS:1;
+ gctUINT32 TX_LERP_LESS_BIT:1;
+ gctUINT32 SH_GM_ENDIAN:1;
+ gctUINT32 SH_GM_USC_UNALLOC:1;
+ gctUINT32 SH_END_OF_BB:1;
+ gctUINT32 VIP_V7:1;
+ gctUINT32 TX_BORDER_CLAMP_FIX:1;
+ gctUINT32 SH_IMG_LD_LASTPIXEL_FIX:1;
+ gctUINT32 ASYNC_BLT:1;
+ gctUINT32 ASYNC_FE_FENCE_FIX:1;
+ gctUINT32 PSCS_THROTTLE:1;
+ gctUINT32 SEPARATE_LS:1;
+ gctUINT32 MCFE:1;
+ gctUINT32 WIDELINE_TRIANGLE_EMU:1;
+ gctUINT32 VG_RESOLUTION_8K:1;
+ gctUINT32 FENCE_32BIT:1;
+ gctUINT32 FENCE_64BIT:1;
+ gctUINT32 NN_INTERLEVE8:1;
+ gctUINT32 TP_REORDER:1;
+ gctUINT32 PE_DEPTH_ONLY_OQFIX:1;
+ gctUINT32 TP_LRN:1;
+ gctUINT32 TX_SEAMLESS_CUBE:1;
+ gctUINT32 TX_SNORM_SUPPORT:1;
+ gctUINT32 TP_MAX_POOLING_STRIDE1:1;
+ gctUINT32 SH_SCATTER_GATHER:1;
+ gctUINT32 HWMANAGED_LS:1;
+ gctUINT32 NN_FP16_ALU:1;
+ gctUINT32 NN_INT16_ALU:1;
+ gctUINT32 TP_ROI_POOLING:1;
+ gctUINT32 NN_ZDP3:1;
+ gctUINT32 NN_ZDP6:1;
+ gctUINT32 NN_XYDP9:1;
+ gctUINT32 NN_INT8_SCALE:1;
+ gctUINT32 NN_POWER_ISOLATION:1;
+ gctUINT32 SWTILING_PHASE1:1;
+ gctUINT32 SH_IMAGE_ENABLE_FIX:1;
+ gctUINT32 TF_QUANTIZATION:1;
+ gctUINT32 MSAA_FRAGMENT_OPERATION:1;
+ gctUINT32 TP_SIMPLE_INT16:1;
+ gctUINT32 TP_REAL_INT16:1;
+ gctUINT32 NN_FIRST_PIXEL_POOLING:1;
+ gctUINT32 SWTILING_PHASE2:1;
+ gctUINT32 VG_FORMAT_ARGB2222:1;
+ gctUINT32 PE_TILE_CACHE_FLUSH_FIX:1;
+ gctUINT32 BLT_YUV_OUTPUT:1;
+ gctUINT32 NN_STRIDE_SUPPORT:1;
+ gctUINT32 NN_XYDP6:1;
+} gcsFEATURE_DATABASE;
+
+static gcsFEATURE_DATABASE gChipInfo[] = {
+ /* dc0000_5550 */
+ {
+ 0x0, /* ChipID */
+ 0x5550, /* ChipRevision */
+ 0x12000000, /* ProductID */
+ 0x0, /* EcoID */
+ 0x300, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x0, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x1, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x1, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x1, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_DC_MMU */
+ 0x1, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x1, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* dc0000_5560 */
+ {
+ 0x0, /* ChipID */
+ 0x5560, /* ChipRevision */
+ 0x2000002, /* ProductID */
+ 0x0, /* EcoID */
+ 0x302, /* CustomerID */
+ 0x3, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x0, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x1, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x1, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x1, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x1, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc200_4650 */
+ {
+ 0x200, /* ChipID */
+ 0x4650, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x0, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x1, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc200_4621 */
+ {
+ 0x200, /* ChipID */
+ 0x4621, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x0, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x0, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x0, /* gcFEATURE_BIT_REG_MMU */
+ 0x0, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x0, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc300_4650 */
+ {
+ 0x300, /* ChipID */
+ 0x4650, /* ChipRevision */
+ 0x5203, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x5, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x1, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc300_4650_guoke */
+ {
+ 0x300, /* ChipID */
+ 0x4650, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x4, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x1, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc300_4_6_6_rc0 */
+ {
+ 0x300, /* ChipID */
+ 0x4660, /* ChipRevision */
+ 0x5203, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x1, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x1, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc320_5007 */
+ {
+ 0x320, /* ChipID */
+ 0x5007, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x8, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x100, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x0, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x0, /* gcFEATURE_BIT_REG_MMU */
+ 0x0, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x0, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc320_5220 */
+ {
+ 0x320, /* ChipID */
+ 0x5220, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc320_5303 */
+ {
+ 0x320, /* ChipID */
+ 0x5303, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc320_5303_1 */
+ {
+ 0x320, /* ChipID */
+ 0x5303, /* ChipRevision */
+ 0x5202, /* ProductID */
+ 0x1, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x4, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc320_5340 */
+ {
+ 0x320, /* ChipID */
+ 0x5340, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x4, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x1, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc320c_5341 */
+ {
+ 0x320, /* ChipID */
+ 0x5341, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0xc, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x1, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x1, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x0, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x0, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x1, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x1, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x1, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc320_5341 */
+ {
+ 0x320, /* ChipID */
+ 0x5341, /* ChipRevision */
+ 0x3202, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc520l_5_3_5_rc0 */
+ {
+ 0x320, /* ChipID */
+ 0x5350, /* ChipRevision */
+ 0x5202, /* ProductID */
+ 0x0, /* EcoID */
+ 0x206, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc355_v121_rc5 */
+ {
+ 0x355, /* ChipID */
+ 0x1215, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x1, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x1, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x1, /* gcFEATURE_BIT_REG_VGTS */
+ 0x1, /* gcFEATURE_BIT_REG_FE20 */
+ 0x0, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x0, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x0, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x0, /* gcFEATURE_BIT_REG_Render8K */
+ 0x0, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x0, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x1, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x0, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x1, /* gcFEATURE_BIT_REG_VG21 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x0, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x0, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x1, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x1, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x0, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x0, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x0, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x0, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x0, /* gcFEATURE_BIT_REG_MMU */
+ 0x0, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x0, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc355_v121x */
+ {
+ 0x355, /* ChipID */
+ 0x1217, /* ChipRevision */
+ 0x3003550, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x1, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x1, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x1, /* gcFEATURE_BIT_REG_VGTS */
+ 0x1, /* gcFEATURE_BIT_REG_FE20 */
+ 0x0, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x0, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x0, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x0, /* gcFEATURE_BIT_REG_Render8K */
+ 0x0, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x0, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x1, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x0, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x1, /* gcFEATURE_BIT_REG_VG21 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x0, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x0, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x1, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x1, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x0, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x0, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x0, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x0, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x0, /* gcFEATURE_BIT_REG_MMU */
+ 0x0, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x1, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x1, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x1, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x1, /* gcFEATURE_BIT_VG_MMU */
+ 0x1, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x1, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x1, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x1, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc355_8Kx8K */
+ {
+ 0x355, /* ChipID */
+ 0x1217, /* ChipRevision */
+ 0x3003550, /* ProductID */
+ 0x0, /* EcoID */
+ 0x407, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x1, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x1, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x1, /* gcFEATURE_BIT_REG_VGTS */
+ 0x1, /* gcFEATURE_BIT_REG_FE20 */
+ 0x0, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x0, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x0, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x0, /* gcFEATURE_BIT_REG_Render8K */
+ 0x0, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x0, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x1, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x0, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x1, /* gcFEATURE_BIT_REG_VG21 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x0, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x0, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x1, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x1, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x0, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x0, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x0, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x0, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x0, /* gcFEATURE_BIT_REG_MMU */
+ 0x0, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x1, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x1, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x1, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x1, /* gcFEATURE_BIT_VG_MMU */
+ 0x1, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x1, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x1, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x1, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x1, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc400_4633 */
+ {
+ 0x400, /* ChipID */
+ 0x4633, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x20, /* gcFEATURE_VALUE_TempRegisters */
+ 0x40, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x80, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x1, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x1, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x0, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x0, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc600_4633 */
+ {
+ 0x600, /* ChipID */
+ 0x4633, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x20, /* gcFEATURE_VALUE_TempRegisters */
+ 0x40, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x80, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x0, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x0, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc400_4645 */
+ {
+ 0x400, /* ChipID */
+ 0x4645, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x4, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x20, /* gcFEATURE_VALUE_TempRegisters */
+ 0x40, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x80, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x240, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x1, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x1, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x0, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc400L_0x465x */
+ {
+ 0x400, /* ChipID */
+ 0x4652, /* ChipRevision */
+ 0x70001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x7, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x20, /* gcFEATURE_VALUE_TempRegisters */
+ 0x40, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x80, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x0, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x1, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x1, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x1, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000nano_0x4652 */
+ {
+ 0x400, /* ChipID */
+ 0x4652, /* ChipRevision */
+ 0x70001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x7, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x20, /* gcFEATURE_VALUE_TempRegisters */
+ 0x40, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x80, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x0, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x1, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x1, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x1, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000nano_0x4652 */
+ {
+ 0x400, /* ChipID */
+ 0x4652, /* ChipRevision */
+ 0x70001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x100, /* CustomerID */
+ 0x9, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x20, /* gcFEATURE_VALUE_TempRegisters */
+ 0x40, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x80, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x0, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x1, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x1, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x1, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc420_5325 */
+ {
+ 0x420, /* ChipID */
+ 0x5325, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x2, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc420_5336 */
+ {
+ 0x420, /* ChipID */
+ 0x5336, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x3, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x1, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x1, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x1, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc420cpd_533rc7a */
+ {
+ 0x420, /* ChipID */
+ 0x5337, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x1, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x1, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x1, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x1, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x1, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc428_5421 */
+ {
+ 0x428, /* ChipID */
+ 0x5421, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x1, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x0, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x1, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x0, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x0, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x0, /* gcFEATURE_BIT_REG_FlipY */
+ 0x0, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x0, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x0, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x0, /* gcFEATURE_BIT_REG_Render8K */
+ 0x0, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x0, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x0, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x0, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x0, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x0, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x0, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x0, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x1, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc428c_5_4_2_rc3a */
+ {
+ 0x428, /* ChipID */
+ 0x5423, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x1, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x0, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x1, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x0, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x0, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x0, /* gcFEATURE_BIT_REG_FlipY */
+ 0x0, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x0, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x0, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x0, /* gcFEATURE_BIT_REG_Render8K */
+ 0x0, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x0, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x0, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x0, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x0, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x0, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x0, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x0, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x1, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x1, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x1, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x1, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x1, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x1, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc520_5341 */
+ {
+ 0x520, /* ChipID */
+ 0x5341, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc520l_5341_rc1b */
+ {
+ 0x520, /* ChipID */
+ 0x5341, /* ChipRevision */
+ 0x5202, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc520_5540_rc0 */
+ {
+ 0x520, /* ChipID */
+ 0x5540, /* ChipRevision */
+ 0x5200, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x0, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x1, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x0, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x0, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x0, /* gcFEATURE_BIT_REG_FlipY */
+ 0x0, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x0, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x0, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x0, /* gcFEATURE_BIT_REG_Render8K */
+ 0x0, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x0, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x0, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x0, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x0, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x0, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x0, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x0, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x1, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x1, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x1, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x1, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x1, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x1, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x1, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x1, /* gcFEATURE_BIT_REG_DEC */
+ 0x1, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc520l_5_3_4_rc2b */
+ {
+ 0x520, /* ChipID */
+ 0x5342, /* ChipRevision */
+ 0x5202, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x2, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x1, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x1, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x1, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x1, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc520c_5_5_0 */
+ {
+ 0x520, /* ChipID */
+ 0x5501, /* ChipRevision */
+ 0x5200, /* ProductID */
+ 0x0, /* EcoID */
+ 0x3, /* CustomerID */
+ 0x2, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x0, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x1, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x1, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x0, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x0, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x0, /* gcFEATURE_BIT_REG_FlipY */
+ 0x0, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x0, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x0, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x0, /* gcFEATURE_BIT_REG_Render8K */
+ 0x0, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x0, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x0, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x0, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x0, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x0, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x0, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x0, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x1, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x1, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x1, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x1, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x1, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x1, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x1, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x1, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x1, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x1, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc520c_5_5_4_rc1 */
+ {
+ 0x520, /* ChipID */
+ 0x5541, /* ChipRevision */
+ 0x5200, /* ProductID */
+ 0x0, /* EcoID */
+ 0x202, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x0, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x1, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x0, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x0, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x0, /* gcFEATURE_BIT_REG_FlipY */
+ 0x0, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x0, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x0, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x0, /* gcFEATURE_BIT_REG_Render8K */
+ 0x0, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x0, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x0, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x0, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x0, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x0, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x0, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x0, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x1, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x1, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x1, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x1, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x1, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x1, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x1, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x1, /* gcFEATURE_BIT_REG_DEC */
+ 0x1, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc520sp_5_5_2_rc0a */
+ {
+ 0x520, /* ChipID */
+ 0x5520, /* ChipRevision */
+ 0x5200, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x1, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x0, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x1, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x1, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x0, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x0, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x0, /* gcFEATURE_BIT_REG_FlipY */
+ 0x0, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x0, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x0, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x0, /* gcFEATURE_BIT_REG_Render8K */
+ 0x0, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x0, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x0, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x0, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x0, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x0, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x0, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x0, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x1, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x1, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x1, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x1, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x1, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x1, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x1, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc520_v552_rc1 */
+ {
+ 0x520, /* ChipID */
+ 0x5521, /* ChipRevision */
+ 0x5200, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x1, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x0, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x1, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x1, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x0, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x0, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x0, /* gcFEATURE_BIT_REG_FlipY */
+ 0x0, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x0, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x0, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x0, /* gcFEATURE_BIT_REG_Render8K */
+ 0x0, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x0, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x0, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x0, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x0, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x0, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x0, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x0, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x1, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x1, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x1, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x1, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x1, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x1, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x1, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc520_5_5_3_rc2a */
+ {
+ 0x520, /* ChipID */
+ 0x5532, /* ChipRevision */
+ 0x5200, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x1, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x0, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x1, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x0, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x0, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x0, /* gcFEATURE_BIT_REG_FlipY */
+ 0x0, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x0, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x0, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x0, /* gcFEATURE_BIT_REG_Render8K */
+ 0x0, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x0, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x0, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x0, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x0, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x0, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x0, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x0, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x1, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x1, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x1, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x1, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x1, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x1, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x1, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x1, /* gcFEATURE_BIT_REG_DEC */
+ 0x1, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc600L_0x465x */
+ {
+ 0x600, /* ChipID */
+ 0x4652, /* ChipRevision */
+ 0x70005, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x7, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x1, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x1, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x1, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000nanoultra_4_6_5_rc3a */
+ {
+ 0x600, /* ChipID */
+ 0x4653, /* ChipRevision */
+ 0x70005, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x1, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x1, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x1, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x1, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x1, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000nanoultra_4_6_5_rc3b */
+ {
+ 0x600, /* ChipID */
+ 0x4653, /* ChipRevision */
+ 0x70005, /* ProductID */
+ 0x0, /* EcoID */
+ 0x101, /* CustomerID */
+ 0x2, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x1, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x1, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x1, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x1, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000nanoultra_4_6_5_rc3e */
+ {
+ 0x600, /* ChipID */
+ 0x4653, /* ChipRevision */
+ 0x70005, /* ProductID */
+ 0x0, /* EcoID */
+ 0x102, /* CustomerID */
+ 0x5, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x1, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x1, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x1, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x0, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc620_5_5_3_rc0 */
+ {
+ 0x620, /* ChipID */
+ 0x5530, /* ChipRevision */
+ 0x6200, /* ProductID */
+ 0x0, /* EcoID */
+ 0x200, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x0, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x1, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x0, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x0, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x0, /* gcFEATURE_BIT_REG_FlipY */
+ 0x0, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x0, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x0, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x0, /* gcFEATURE_BIT_REG_Render8K */
+ 0x0, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x0, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x0, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x0, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x0, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x0, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x0, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x0, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x1, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x1, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x1, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x1, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x1, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x1, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x1, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc620_5_5_5_rc0d */
+ {
+ 0x620, /* ChipID */
+ 0x5550, /* ChipRevision */
+ 0x6200, /* ProductID */
+ 0x0, /* EcoID */
+ 0x201, /* CustomerID */
+ 0x4, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x0, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x1, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x1, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x0, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x0, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x0, /* gcFEATURE_BIT_REG_FlipY */
+ 0x0, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x0, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x0, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x0, /* gcFEATURE_BIT_REG_Render8K */
+ 0x0, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x0, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x0, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x0, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x0, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x0, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x0, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x0, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x1, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x1, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x1, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x1, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x1, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x1, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x1, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x1, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc620tpc_5_5_6_rc0a */
+ {
+ 0x620, /* ChipID */
+ 0x5560, /* ChipRevision */
+ 0x6200, /* ProductID */
+ 0x0, /* EcoID */
+ 0x200, /* CustomerID */
+ 0x1, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x1, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x0, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x0, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x1, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x1, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x0, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x0, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x0, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x0, /* gcFEATURE_BIT_REG_FlipY */
+ 0x0, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x0, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x0, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x0, /* gcFEATURE_BIT_REG_Render8K */
+ 0x0, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x0, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x0, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x0, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x0, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x0, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x1, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x0, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x0, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x0, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x0, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x1, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x1, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x1, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x1, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x1, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x1, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x1, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x1, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc860L_0x464x */
+ {
+ 0x860, /* ChipID */
+ 0x4647, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x4, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x0, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x1, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc880_5106 */
+ {
+ 0x880, /* ChipID */
+ 0x5106, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x100, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0xb, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x0, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc880_5122 */
+ {
+ 0x880, /* ChipID */
+ 0x5122, /* ChipRevision */
+ 0x70007, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x240, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0xc, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x1, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc880TM_0x512x */
+ {
+ 0x880, /* ChipID */
+ 0x5124, /* ChipRevision */
+ 0x70007, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x2, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x240, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0xc, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x0, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x1, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x0, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc880TM_0x512x */
+ {
+ 0x880, /* ChipID */
+ 0x5124, /* ChipRevision */
+ 0x70007, /* ProductID */
+ 0x0, /* EcoID */
+ 0x103, /* CustomerID */
+ 0x2, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x240, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0xf, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x0, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x1, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x0, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc900_5250 */
+ {
+ 0x900, /* ChipID */
+ 0x5250, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x200, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x2, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc1000_5036 */
+ {
+ 0x1000, /* ChipID */
+ 0x5036, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x240, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x1, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc1000_5037 */
+ {
+ 0x1000, /* ChipID */
+ 0x5037, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x240, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x1, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc1000_5037_1 */
+ {
+ 0x1000, /* ChipID */
+ 0x5037, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x1, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x240, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x0, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x0, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x1, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc1000_5039 */
+ {
+ 0x1000, /* ChipID */
+ 0x5039, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x11, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x4, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x8, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x240, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x0, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x1, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x0, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x1, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc1500_5246 */
+ {
+ 0x1500, /* ChipID */
+ 0x5246, /* ChipRevision */
+ 0x70003, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x6, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x400, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0xf, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x2, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc2000_5108 */
+ {
+ 0x2000, /* ChipID */
+ 0x5108, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x200, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0xa8, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0xb, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x4, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x1, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x0, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x0, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x0, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x0, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x0, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x0, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x0, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x0, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x0, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x0, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc2000_5140 */
+ {
+ 0x2000, /* ChipID */
+ 0x5140, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x5, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x100, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x1, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc2000w_5_1_4_rc0e */
+ {
+ 0x2000, /* ChipID */
+ 0x5140, /* ChipRevision */
+ 0x20000, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x5, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionCount */
+ 0x100, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x8, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x0, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x1, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x0, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x0, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x0, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x0, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x0, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x0, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x0, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x0, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x0, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x0, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x0, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc2500_5422 */
+ {
+ 0x2500, /* ChipID */
+ 0x5422, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x12, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0xf, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x4, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x1, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc6400_5422 */
+ {
+ 0x6400, /* ChipID */
+ 0x5422, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x16, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0xf, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x1, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc3000_5435 */
+ {
+ 0x3000, /* ChipID */
+ 0x5435, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0xf, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x4, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x1, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x1, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc2000_ffff5450 */
+ {
+ 0x2000, /* ChipID */
+ 0xffff5450, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x8, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x4, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x1, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc3000_5450 */
+ {
+ 0x3000, /* ChipID */
+ 0x5450, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x8, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x4, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x1, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc3000_5451 */
+ {
+ 0x3000, /* ChipID */
+ 0x5451, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x4, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x4, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x1, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x1, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000L_551x */
+ {
+ 0x3000, /* ChipID */
+ 0x5512, /* ChipRevision */
+ 0x70002, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x3, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x4, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x1, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x1, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000L_5512 */
+ {
+ 0x3000, /* ChipID */
+ 0x5512, /* ChipRevision */
+ 0x70002, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x3, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x4, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x1, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x1, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000L_5514 */
+ {
+ 0x3000, /* ChipID */
+ 0x5514, /* ChipRevision */
+ 0x70002, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x4, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x1, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x1, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc4000_5222 */
+ {
+ 0x4000, /* ChipID */
+ 0x5222, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x800, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x800, /* gcFEATURE_VALUE_InstructionCount */
+ 0x200, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0xb, /* gcFEATURE_VALUE_VaryingCount */
+ 0x8, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x1, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x0, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x0, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x0, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x0, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc4000_5245 */
+ {
+ 0x4000, /* ChipID */
+ 0x5245, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x400, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0xf, /* gcFEATURE_VALUE_VaryingCount */
+ 0x8, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x0, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x0, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x0, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x1, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x0, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x0, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x0, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x0, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc5000_5434 */
+ {
+ 0x5000, /* ChipID */
+ 0x5434, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0xf, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x0, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x0, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x0, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x0, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x0, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x0, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x0, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x0, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x0, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x1, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x0, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000_551x */
+ {
+ 0x5000, /* ChipID */
+ 0x5513, /* ChipRevision */
+ 0x70000, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x1, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x1, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x1, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000_5513 */
+ {
+ 0x5000, /* ChipID */
+ 0x5513, /* ChipRevision */
+ 0x70000, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x1, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x1, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x1, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x0, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x1, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x1, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gcXAQ2_CMODEL */
+ {
+ 0x7000, /* ChipID */
+ 0x0, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x1f, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x40, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x100, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x1, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x1, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x1, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x1, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x1, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x0, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x0, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x0, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x0, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x1, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x0, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x0, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x0, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x1, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x0, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x0, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x1, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000XS_600x */
+ {
+ 0x7000, /* ChipID */
+ 0x6008, /* ChipRevision */
+ 0x70004, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0xb, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x1f, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x40, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x1, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000XS_6008 */
+ {
+ 0x7000, /* ChipID */
+ 0x6008, /* ChipRevision */
+ 0x70004, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0xb, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x1f, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x40, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x1, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000XSVX_600x */
+ {
+ 0x7000, /* ChipID */
+ 0x6008, /* ChipRevision */
+ 0x70008, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x1f, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x40, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x1, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000XSVX_6008 */
+ {
+ 0x7000, /* ChipID */
+ 0x6008, /* ChipRevision */
+ 0x70008, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x7, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x1f, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x40, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x1, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000XSVX_6009 */
+ {
+ 0x7000, /* ChipID */
+ 0x6009, /* ChipRevision */
+ 0x70008, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x9, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x1f, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x40, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x1, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000_6100 */
+ {
+ 0x7000, /* ChipID */
+ 0x6100, /* ChipRevision */
+ 0x70000, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x20, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x20, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x20, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000L_6100 */
+ {
+ 0x7000, /* ChipID */
+ 0x6100, /* ChipRevision */
+ 0x70002, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000XS_6100 */
+ {
+ 0x7000, /* ChipID */
+ 0x6100, /* ChipRevision */
+ 0x70004, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x1f, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x40, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x0, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x1, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vip7000UL_6100 */
+ {
+ 0x7000, /* ChipID */
+ 0x6100, /* ChipRevision */
+ 0x5070003, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x1, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x0, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000_6200 */
+ {
+ 0x7000, /* ChipID */
+ 0x6200, /* ChipRevision */
+ 0x70000, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x28, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x20, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x28, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000UL_6200 */
+ {
+ 0x7000, /* ChipID */
+ 0x6200, /* ChipRevision */
+ 0x70003, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x10, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x1, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000ULVX_6200 */
+ {
+ 0x7000, /* ChipID */
+ 0x6200, /* ChipRevision */
+ 0x7000f, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x10, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x1, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x1, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x1, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vip7000L_6200 */
+ {
+ 0x7000, /* ChipID */
+ 0x6200, /* ChipRevision */
+ 0x5070002, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x20, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x20, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x20, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vip7000UL_6200 */
+ {
+ 0x7000, /* ChipID */
+ 0x6201, /* ChipRevision */
+ 0x5070003, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vip8000UL_6211 */
+ {
+ 0x8000, /* ChipID */
+ 0x6212, /* ChipRevision */
+ 0x5080003, /* ProductID */
+ 0x0, /* EcoID */
+ 0x21, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x1, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x1, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0xe0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vip8000ULFN_6211 */
+ {
+ 0x8000, /* ChipID */
+ 0x6211, /* ChipRevision */
+ 0x5080003, /* ProductID */
+ 0x0, /* EcoID */
+ 0x22, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x1, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x1, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0xe0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vip8000UL_6211 */
+ {
+ 0x8000, /* ChipID */
+ 0x6211, /* ChipRevision */
+ 0x5080003, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x1, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x1, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x1, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0xe0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano */
+ {
+ 0x8000, /* ChipID */
+ 0x7000, /* ChipRevision */
+ 0x5080001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x29, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x1, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x1, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x1, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0xe0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x1, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gcnanovip */
+ {
+ 0x8000, /* ChipID */
+ 0x7000, /* ChipRevision */
+ 0x424f5343, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-q */
+ {
+ 0x8000, /* ChipID */
+ 0x7100, /* ChipRevision */
+ 0x45080001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x24, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x10, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x200, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x4, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x800, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x4, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x1, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x1, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-q */
+ {
+ 0x8000, /* ChipID */
+ 0x7100, /* ChipRevision */
+ 0x45080001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x82, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0xa, /* gcFEATURE_VALUE_NNCoreCount */
+ 0xa, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0xc, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x200, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x6, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x800, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x4, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x1, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x1, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x1, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vip8000UL-s */
+ {
+ 0x8000, /* ChipID */
+ 0x7000, /* ChipRevision */
+ 0x15080003, /* ProductID */
+ 0x0, /* EcoID */
+ 0x25, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x18, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x18, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0xe0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x80, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x1, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vip8000UL-s */
+ {
+ 0x8000, /* ChipID */
+ 0x7000, /* ChipRevision */
+ 0x15080003, /* ProductID */
+ 0x0, /* EcoID */
+ 0x83, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x2, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x18, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x18, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0xe0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x80, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x1, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x1, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vip8000UL-q */
+ {
+ 0x8000, /* ChipID */
+ 0x7000, /* ChipRevision */
+ 0x45080003, /* ProductID */
+ 0x0, /* EcoID */
+ 0x26, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x18, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x18, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x200, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x2, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vip8000UL */
+ {
+ 0x8000, /* ChipID */
+ 0x7000, /* ChipRevision */
+ 0x5080003, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x18, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x18, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x1, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x1, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x1, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0xe0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x80, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x1, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x1, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vip8000-q */
+ {
+ 0x8000, /* ChipID */
+ 0x7000, /* ChipRevision */
+ 0x45080000, /* ProductID */
+ 0x0, /* EcoID */
+ 0x72, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x20, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x200, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x2, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x1, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-d */
+ {
+ 0x8000, /* ChipID */
+ 0x7000, /* ChipRevision */
+ 0x25080001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x2a, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x100, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x4, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-d */
+ {
+ 0x8000, /* ChipID */
+ 0x7000, /* ChipRevision */
+ 0x25080001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x76, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x100, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x2, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x1, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x1, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x1, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vip8000L-O */
+ {
+ 0x8000, /* ChipID */
+ 0x7000, /* ChipRevision */
+ 0x85080002, /* ProductID */
+ 0x0, /* EcoID */
+ 0x2f, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x20, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x20, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x20, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x10, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x10, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x10, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x10, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0xc, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x200, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x4, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x4, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x1, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x1, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x1, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x1, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x1, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x1, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x1, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x1, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x1, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x1, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x1, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x1, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-s */
+ {
+ 0x8000, /* ChipID */
+ 0x7000, /* ChipRevision */
+ 0x15080001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x23, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0xe0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x80, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x1, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-qi */
+ {
+ 0x8000, /* ChipID */
+ 0x7000, /* ChipRevision */
+ 0x45080009, /* ProductID */
+ 0x0, /* EcoID */
+ 0x7d, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0xc, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x200, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x4, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x400, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x1, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-di */
+ {
+ 0x8000, /* ChipID */
+ 0x7000, /* ChipRevision */
+ 0x25080009, /* ProductID */
+ 0x0, /* EcoID */
+ 0x7e, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x100, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x4, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x800, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x1, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x1, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-si */
+ {
+ 0x8000, /* ChipID */
+ 0x7120, /* ChipRevision */
+ 0x15080009, /* ProductID */
+ 0x0, /* EcoID */
+ 0x80, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0xc, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0xe0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x100, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x2, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x400, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x1, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x1, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x1, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-di */
+ {
+ 0x8000, /* ChipID */
+ 0x7110, /* ChipRevision */
+ 0x25080009, /* ProductID */
+ 0x0, /* EcoID */
+ 0x7f, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x6, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x6, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x6, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0xc, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x100, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x6, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x200, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x4, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x1, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x1, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x1, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-di */
+ {
+ 0x8000, /* ChipID */
+ 0x7200, /* ChipRevision */
+ 0x25080009, /* ProductID */
+ 0x0, /* EcoID */
+ 0x84, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0xc, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x80, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x4, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x4, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x1, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x1, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x1, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x1, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-s */
+ {
+ 0x8000, /* ChipID */
+ 0x7010, /* ChipRevision */
+ 0x15080001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0xe0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x80, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x1, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x400, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x1, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-d */
+ {
+ 0x8000, /* ChipID */
+ 0x7010, /* ChipRevision */
+ 0x25080001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x100, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x2, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x400, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x1, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-q */
+ {
+ 0x8000, /* ChipID */
+ 0x7010, /* ChipRevision */
+ 0x45080001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x200, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x4, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x400, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x1, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-o */
+ {
+ 0x8000, /* ChipID */
+ 0x7010, /* ChipRevision */
+ 0x85080001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x10, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x10, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x10, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x10, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x400, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x8, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x400, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x1, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-s */
+ {
+ 0x8000, /* ChipID */
+ 0x7100, /* ChipRevision */
+ 0x15080001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x2, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0xe0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x80, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x1, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x400, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x1, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x1, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x1, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x1, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-d */
+ {
+ 0x8000, /* ChipID */
+ 0x7100, /* ChipRevision */
+ 0x25080001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x4, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x100, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x2, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x400, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x1, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x1, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x1, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x1, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-q */
+ {
+ 0x8000, /* ChipID */
+ 0x7100, /* ChipRevision */
+ 0x45080001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x8, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x200, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x4, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x400, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x1, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x1, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x1, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x1, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vipnano-o */
+ {
+ 0x8000, /* ChipID */
+ 0x7100, /* ChipRevision */
+ 0x85080001, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x100, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x1, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x40, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x10, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x10, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x10, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x10, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x6, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x40, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x400, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x10, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x400, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x8, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x400, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x3, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x1, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x1, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x1, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x1, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x1, /* gcFEATURE_BIT_TP_LRN */
+ 0x0, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x0, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x1, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x1, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x1, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x1, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x1, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x1, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x1, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x1, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x1, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x1, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x1, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x1, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7400_551x */
+ {
+ 0x7400, /* ChipID */
+ 0x5515, /* ChipRevision */
+ 0x74000, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x6, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x0, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x2, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x0, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x0, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x0, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x0, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x0, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x0, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x1, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x1, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x0, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x0, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x0, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x0, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x0, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x0, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x0, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x0, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x0, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x0, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x0, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x0, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x0, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x0, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x0, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x0, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x0, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x0, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x0, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x0, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x1, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x0, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x0, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x1, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x1, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc8000UL_6200 */
+ {
+ 0x8000, /* ChipID */
+ 0x6200, /* ChipRevision */
+ 0x80003, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x8, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x8, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x10, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x1, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* v630 */
+ {
+ 0x7000, /* ChipID */
+ 0x6300, /* ChipRevision */
+ 0x0, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x1f, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x20, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x1, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x1, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000XS_6200 */
+ {
+ 0x7000, /* ChipID */
+ 0x6200, /* ChipRevision */
+ 0x70004, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x1f, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x20, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x1, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000L_6200 */
+ {
+ 0x7000, /* ChipID */
+ 0x6200, /* ChipRevision */
+ 0x70002, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000LXS_6200 */
+ {
+ 0x7000, /* ChipID */
+ 0x6200, /* ChipRevision */
+ 0x7000a, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x1f, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x20, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x1, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* vip7000_6200 */
+ {
+ 0x7000, /* ChipID */
+ 0x6200, /* ChipRevision */
+ 0x5070000, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x1f, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x40, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x0, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000ULVX_V11_6200 */
+ {
+ 0x7000, /* ChipID */
+ 0x6200, /* ChipRevision */
+ 0x7000f, /* ProductID */
+ 0x0, /* EcoID */
+ 0x1, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x10, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x1, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x1, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x1, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000ULVX_V12_6200 */
+ {
+ 0x7000, /* ChipID */
+ 0x6200, /* ChipRevision */
+ 0x7000f, /* ProductID */
+ 0x0, /* EcoID */
+ 0x2, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x10, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x1, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc8000ULVX */
+ {
+ 0x8000, /* ChipID */
+ 0x6200, /* ChipRevision */
+ 0x8000f, /* ProductID */
+ 0x0, /* EcoID */
+ 0x3, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x10, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x1, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x0, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x1, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x1, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x1, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000ULVX_6200_pid0x60 */
+ {
+ 0x7000, /* ChipID */
+ 0x6203, /* ChipRevision */
+ 0x7000f, /* ProductID */
+ 0x0, /* EcoID */
+ 0x60, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x200, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x2, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x10, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x0, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x0, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x0, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x0, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x1, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x1, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000XS_6FFF */
+ {
+ 0x7000, /* ChipID */
+ 0x6fff, /* ChipRevision */
+ 0x70004, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x1f, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x20, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x1, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x0, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x0, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x0, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000_6210 */
+ {
+ 0x7000, /* ChipID */
+ 0x6210, /* ChipRevision */
+ 0x70000, /* ProductID */
+ 0x0, /* EcoID */
+ 0x6, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000_6210 */
+ {
+ 0x7000, /* ChipID */
+ 0x6210, /* ChipRevision */
+ 0x70000, /* ProductID */
+ 0x0, /* EcoID */
+ 0xa, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x1, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000XS_6210 */
+ {
+ 0x7000, /* ChipID */
+ 0x6210, /* ChipRevision */
+ 0x70004, /* ProductID */
+ 0x0, /* EcoID */
+ 0x8, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x30, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x30, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc8000XS_6210 */
+ {
+ 0x8000, /* ChipID */
+ 0x6210, /* ChipRevision */
+ 0x80004, /* ProductID */
+ 0x0, /* EcoID */
+ 0xd, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x30, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x30, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000XS_6210 */
+ {
+ 0x7000, /* ChipID */
+ 0x6210, /* ChipRevision */
+ 0x70004, /* ProductID */
+ 0x0, /* EcoID */
+ 0xc, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x30, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x30, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x1, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000L_6210 */
+ {
+ 0x7000, /* ChipID */
+ 0x6210, /* ChipRevision */
+ 0x70002, /* ProductID */
+ 0x0, /* EcoID */
+ 0x5, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x1, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000L_6210 */
+ {
+ 0x7000, /* ChipID */
+ 0x6210, /* ChipRevision */
+ 0x70002, /* ProductID */
+ 0x0, /* EcoID */
+ 0x9, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x1, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000LXS_6210 */
+ {
+ 0x7000, /* ChipID */
+ 0x6210, /* ChipRevision */
+ 0x7000a, /* ProductID */
+ 0x0, /* EcoID */
+ 0x0, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x30, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x30, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000XSVX_6210 */
+ {
+ 0x7000, /* ChipID */
+ 0x6210, /* ChipRevision */
+ 0x70008, /* ProductID */
+ 0x0, /* EcoID */
+ 0x7, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x20, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000XSVX_6210 */
+ {
+ 0x7000, /* ChipID */
+ 0x6210, /* ChipRevision */
+ 0x70008, /* ProductID */
+ 0x0, /* EcoID */
+ 0xb, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x20, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x1, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7000L_DEC400 */
+ {
+ 0x7000, /* ChipID */
+ 0x6214, /* ChipRevision */
+ 0x70002, /* ProductID */
+ 0x0, /* EcoID */
+ 0x30, /* CustomerID */
+ 0x8, /* PatchVersion */
+ 0x1, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x10, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x10, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x1, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x1, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x1, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7400_0002 */
+ {
+ 0x8400, /* ChipID */
+ 0x6310, /* ChipRevision */
+ 0x8400a, /* ProductID */
+ 0x0, /* EcoID */
+ 0x44, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x30, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x10, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x30, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x1, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x1, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x1, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x1, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x1, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc7400_0003 */
+ {
+ 0x8400, /* ChipID */
+ 0x6310, /* ChipRevision */
+ 0x8400a, /* ProductID */
+ 0x0, /* EcoID */
+ 0x45, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x8, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x400, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x4, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x30, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x8, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x30, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x1, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x0, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x1, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x1, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x1, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x1, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc8400_6300 */
+ {
+ 0x8400, /* ChipID */
+ 0x6300, /* ChipRevision */
+ 0x84004, /* ProductID */
+ 0x0, /* EcoID */
+ 0x41, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x10, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x40, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0xf, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x1, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x1, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x1, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc8100_6300_pid0x43 */
+ {
+ 0x8100, /* ChipID */
+ 0x6300, /* ChipRevision */
+ 0x81004, /* ProductID */
+ 0x0, /* EcoID */
+ 0x43, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x10, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x40, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x1, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x1, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x1, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x1, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* gc8200_6300_pid0x46 */
+ {
+ 0x8200, /* ChipID */
+ 0x6300, /* ChipRevision */
+ 0x82004, /* ProductID */
+ 0x0, /* EcoID */
+ 0x46, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x10, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x2, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x10, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x40, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x1, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x3, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x0, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x0, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x1, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x0, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x1, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x1, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x1, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x1, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x0, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x1, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x1, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x0, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x1, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x1, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x1, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x1, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x1, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x1, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x1, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x1, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x1, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x1, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x1, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x1, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* cc8000_6220 */
+ {
+ 0x8000, /* ChipID */
+ 0x6220, /* ChipRevision */
+ 0x6080000, /* ProductID */
+ 0x0, /* EcoID */
+ 0x50, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x1f, /* gcFEATURE_VALUE_VaryingCount */
+ 0x40, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x40, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x40, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x0, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x0, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x0, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x0, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x0, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x0, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+ /* cc8000_6330 */
+ {
+ 0x8000, /* ChipID */
+ 0x6330, /* ChipRevision */
+ 0x6080000, /* ProductID */
+ 0x0, /* EcoID */
+ 0x51, /* CustomerID */
+ 0x0, /* PatchVersion */
+ 0x0, /* FormalRelease */
+ 0x10, /* gcFEATURE_VALUE_Streams */
+ 0x40, /* gcFEATURE_VALUE_TempRegisters */
+ 0x800, /* gcFEATURE_VALUE_ThreadCount */
+ 0x10, /* gcFEATURE_VALUE_VertexCacheSize */
+ 0x8, /* gcFEATURE_VALUE_NumShaderCores */
+ 0x1, /* gcFEATURE_VALUE_NumPixelPipes */
+ 0x400, /* gcFEATURE_VALUE_VertexOutputBufferSize */
+ 0x0, /* gcFEATURE_VALUE_BufferSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionCount */
+ 0x140, /* gcFEATURE_VALUE_NumberOfConstants */
+ 0x1, /* gcFEATURE_VALUE_CoreCount */
+ 0x1f, /* gcFEATURE_VALUE_VaryingCount */
+ 0x20, /* gcFEATURE_VALUE_LocalStorageSize */
+ 0x20, /* gcFEATURE_VALUE_L1CacheSize */
+ 0x200, /* gcFEATURE_VALUE_InstructionMemorySize */
+ 0x14, /* gcFEATURE_VALUE_ShaderPCLength */
+ 0x0, /* gcFEATURE_VALUE_NumResolvePipes */
+ 0x20, /* gcFEATURE_VALUE_USC_MAX_PAGES */
+ 0x100, /* gcFEATURE_VALUE_RESULT_WINDOW_MAX_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NNMadPerCore */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT8 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_INT16 */
+ 0x0, /* gcFEATURE_VALUE_NNCoreCount_FLOAT16 */
+ 0x0, /* gcFEATURE_VALUE_NNInputBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_NNAccumBufferDepth */
+ 0x0, /* gcFEATURE_VALUE_ClusterAliveMask */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTCount */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_PwlLUTSize */
+ 0x0, /* gcFEATURE_VALUE_VIP_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_TPEngine_CoreCount */
+ 0x0, /* gcFEATURE_VALUE_AXI_SRAM_SIZE */
+ 0x0, /* gcFEATURE_VALUE_NN_INIMAGE_OFFSET_BITS */
+ 0x1, /* gcFEATURE_BIT_REG_FastClear */
+ 0x0, /* gcFEATURE_BIT_REG_SpecialAntiAliasing */
+ 0x1, /* gcFEATURE_BIT_REG_Pipe3D */
+ 0x1, /* gcFEATURE_BIT_REG_DXTTextureCompression */
+ 0x0, /* gcFEATURE_BIT_REG_DebugMode */
+ 0x1, /* gcFEATURE_BIT_REG_ZCompression */
+ 0x0, /* gcFEATURE_BIT_REG_YUV420Filter */
+ 0x1, /* gcFEATURE_BIT_REG_MSAA */
+ 0x0, /* gcFEATURE_BIT_REG_DC */
+ 0x0, /* gcFEATURE_BIT_REG_Pipe2D */
+ 0x1, /* gcFEATURE_BIT_REG_ETC1TextureCompression */
+ 0x1, /* gcFEATURE_BIT_REG_FastScaler */
+ 0x1, /* gcFEATURE_BIT_REG_HighDynamicRange */
+ 0x1, /* gcFEATURE_BIT_REG_YUV420Tiler */
+ 0x1, /* gcFEATURE_BIT_REG_ModuleCG */
+ 0x0, /* gcFEATURE_BIT_REG_MinArea */
+ 0x0, /* gcFEATURE_BIT_REG_NoEZ */
+ 0x0, /* gcFEATURE_BIT_REG_No422Texture */
+ 0x0, /* gcFEATURE_BIT_REG_BufferInterleaving */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite2D */
+ 0x0, /* gcFEATURE_BIT_REG_NoScaler */
+ 0x1, /* gcFEATURE_BIT_REG_YUY2Averaging */
+ 0x0, /* gcFEATURE_BIT_REG_HalfPECache */
+ 0x0, /* gcFEATURE_BIT_REG_HalfTXCache */
+ 0x0, /* gcFEATURE_BIT_REG_YUY2RenderTarget */
+ 0x0, /* gcFEATURE_BIT_REG_Mem32BitSupport */
+ 0x0, /* gcFEATURE_BIT_REG_PipeVG */
+ 0x0, /* gcFEATURE_BIT_REG_VGTS */
+ 0x0, /* gcFEATURE_BIT_REG_FE20 */
+ 0x1, /* gcFEATURE_BIT_REG_ByteWrite3D */
+ 0x1, /* gcFEATURE_BIT_REG_RsYuvTarget */
+ 0x1, /* gcFEATURE_BIT_REG_FE20BitIndex */
+ 0x1, /* gcFEATURE_BIT_REG_FlipY */
+ 0x1, /* gcFEATURE_BIT_REG_DualReturnBus */
+ 0x1, /* gcFEATURE_BIT_REG_EndiannessConfig */
+ 0x1, /* gcFEATURE_BIT_REG_Texture8K */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectTextureConverter */
+ 0x1, /* gcFEATURE_BIT_REG_SpecialMsaaLod */
+ 0x1, /* gcFEATURE_BIT_REG_FastClearFlush */
+ 0x1, /* gcFEATURE_BIT_REG_2DPE20 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectAutoDisable */
+ 0x1, /* gcFEATURE_BIT_REG_Render8K */
+ 0x1, /* gcFEATURE_BIT_REG_TileStatus2Bits */
+ 0x1, /* gcFEATURE_BIT_REG_SeparateTileStatusWhenInterleaved */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiled32x32 */
+ 0x0, /* gcFEATURE_BIT_REG_VG20 */
+ 0x0, /* gcFEATURE_BIT_REG_TSExtendedCommands */
+ 0x1, /* gcFEATURE_BIT_REG_CompressionFifoFixed */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions0 */
+ 0x0, /* gcFEATURE_BIT_REG_VGFilter */
+ 0x0, /* gcFEATURE_BIT_REG_VG21 */
+ 0x1, /* gcFEATURE_BIT_REG_ShaderGetsW */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions1 */
+ 0x1, /* gcFEATURE_BIT_REG_DefaultReg0 */
+ 0x1, /* gcFEATURE_BIT_REG_MC20 */
+ 0x0, /* gcFEATURE_BIT_REG_ShaderMSAASideband */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes0 */
+ 0x0, /* gcFEATURE_BIT_REG_VAA */
+ 0x0, /* gcFEATURE_BIT_REG_BypassInMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_HierarchicalZ */
+ 0x0, /* gcFEATURE_BIT_REG_NewTexture */
+ 0x0, /* gcFEATURE_BIT_REG_A8TargetSupport */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectStencil */
+ 0x1, /* gcFEATURE_BIT_REG_EnhanceVR */
+ 0x1, /* gcFEATURE_BIT_REG_RSUVSwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_V2Compression */
+ 0x0, /* gcFEATURE_BIT_REG_VGDoubleBuffer */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes1 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes2 */
+ 0x0, /* gcFEATURE_BIT_REG_TextureStride */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes3 */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisable1 */
+ 0x0, /* gcFEATURE_BIT_REG_AutoRestartTS */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes4 */
+ 0x0, /* gcFEATURE_BIT_REG_L2Windowing */
+ 0x1, /* gcFEATURE_BIT_REG_HalfFloatPipe */
+ 0x1, /* gcFEATURE_BIT_REG_PixelDither */
+ 0x1, /* gcFEATURE_BIT_REG_TwoStencilReference */
+ 0x1, /* gcFEATURE_BIT_REG_ExtendedPixelFormat */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectMinMaxDepth */
+ 0x1, /* gcFEATURE_BIT_REG_DitherAndFilterPlusAlpha2D */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes5 */
+ 0x0, /* gcFEATURE_BIT_REG_New2D */
+ 0x1, /* gcFEATURE_BIT_REG_NewFloatingPointArithmetic */
+ 0x1, /* gcFEATURE_BIT_REG_TextureHorizontalAlignmentSelect */
+ 0x1, /* gcFEATURE_BIT_REG_NonPowerOfTwo */
+ 0x1, /* gcFEATURE_BIT_REG_LinearTextureSupport */
+ 0x1, /* gcFEATURE_BIT_REG_Halti0 */
+ 0x0, /* gcFEATURE_BIT_REG_CorrectOverflowVG */
+ 0x1, /* gcFEATURE_BIT_REG_NegativeLogFix */
+ 0x1, /* gcFEATURE_BIT_REG_ResolveOffset */
+ 0x1, /* gcFEATURE_BIT_REG_OkToGateAxiClock */
+ 0x1, /* gcFEATURE_BIT_REG_MMU */
+ 0x1, /* gcFEATURE_BIT_REG_WideLine */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes6 */
+ 0x1, /* gcFEATURE_BIT_REG_FcFlushStall */
+ 0x1, /* gcFEATURE_BIT_REG_LineLoop */
+ 0x1, /* gcFEATURE_BIT_REG_LogicOp */
+ 0x1, /* gcFEATURE_BIT_REG_SeamlessCubeMap */
+ 0x1, /* gcFEATURE_BIT_REG_SuperTiledTexture */
+ 0x1, /* gcFEATURE_BIT_REG_LinearPE */
+ 0x1, /* gcFEATURE_BIT_REG_RectPrimitive */
+ 0x0, /* gcFEATURE_BIT_REG_Composition */
+ 0x1, /* gcFEATURE_BIT_REG_CorrectAutoDisableCountWidth */
+ 0x1, /* gcFEATURE_BIT_REG_PESwizzle */
+ 0x1, /* gcFEATURE_BIT_REG_EndEvent */
+ 0x1, /* gcFEATURE_BIT_REG_S1S8 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti1 */
+ 0x0, /* gcFEATURE_BIT_REG_RGB888 */
+ 0x1, /* gcFEATURE_BIT_REG_TX_YUVAssembler */
+ 0x1, /* gcFEATURE_BIT_REG_DynamicFrequencyScaling */
+ 0x0, /* gcFEATURE_BIT_REG_TXFilter */
+ 0x1, /* gcFEATURE_BIT_REG_FullDirectFB */
+ 0x0, /* gcFEATURE_BIT_REG_OnePass2DFilter */
+ 0x1, /* gcFEATURE_BIT_REG_ThreadWalkerInPS */
+ 0x1, /* gcFEATURE_BIT_REG_TileFiller */
+ 0x1, /* gcFEATURE_BIT_REG_YUVStandard */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSourceBlt */
+ 0x0, /* gcFEATURE_BIT_REG_YUVConversion */
+ 0x1, /* gcFEATURE_BIT_REG_FlushFixed2D */
+ 0x1, /* gcFEATURE_BIT_REG_Interleaver */
+ 0x1, /* gcFEATURE_BIT_REG_MixedStreams */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheFor2D420 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes7 */
+ 0x0, /* gcFEATURE_BIT_REG_NoIndexPattern */
+ 0x1, /* gcFEATURE_BIT_REG_TextureTileStatus */
+ 0x1, /* gcFEATURE_BIT_REG_DecompressZ16 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes8 */
+ 0x1, /* gcFEATURE_BIT_REG_DERotationStallFix */
+ 0x0, /* gcFEATURE_BIT_REG_OclOnly */
+ 0x1, /* gcFEATURE_BIT_REG_NewFeatures0 */
+ 0x1, /* gcFEATURE_BIT_REG_InstructionCache */
+ 0x0, /* gcFEATURE_BIT_REG_GeometryShader */
+ 0x1, /* gcFEATURE_BIT_REG_TexCompressionSupertiled */
+ 0x1, /* gcFEATURE_BIT_REG_Generics */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes9 */
+ 0x0, /* gcFEATURE_BIT_REG_FastMSAA */
+ 0x0, /* gcFEATURE_BIT_REG_WClip */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes10 */
+ 0x1, /* gcFEATURE_BIT_REG_UnifiedSamplers */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes11 */
+ 0x1, /* gcFEATURE_BIT_REG_PerformanceCounters */
+ 0x1, /* gcFEATURE_BIT_REG_ExtraShaderInstructions2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes12 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes13 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_ACE */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_DEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes14 */
+ 0x0, /* gcFEATURE_BIT_REG_PowerOptimizations0 */
+ 0x1, /* gcFEATURE_BIT_REG_NewHZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes15 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements1 */
+ 0x0, /* gcFEATURE_BIT_REG_DENoGamma */
+ 0x0, /* gcFEATURE_BIT_REG_PAEnhancements2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_PEEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_HIEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_FEEnhancements2 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes16 */
+ 0x0, /* gcFEATURE_BIT_REG_DEEnhancements5 */
+ 0x1, /* gcFEATURE_BIT_REG_TXEnhancements4 */
+ 0x0, /* gcFEATURE_BIT_REG_PEEnhancements4 */
+ 0x1, /* gcFEATURE_BIT_REG_MCEnhancements1 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti2 */
+ 0x0, /* gcFEATURE_BIT_REG_DEMirrorRotate */
+ 0x1, /* gcFEATURE_BIT_REG_SmallMSAA */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes17 */
+ 0x0, /* gcFEATURE_BIT_REG_Rasterizer2 */
+ 0x0, /* gcFEATURE_BIT_REG_DualPipeOPF */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2 */
+ 0x0, /* gcFEATURE_BIT_REG_CSCV2 */
+ 0x1, /* gcFEATURE_BIT_REG_PAEnhancements3 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes18 */
+ 0x0, /* gcFEATURE_BIT_REG_Compression2D */
+ 0x0, /* gcFEATURE_BIT_REG_Probe */
+ 0x1, /* gcFEATURE_BIT_REG_MediumPrecision */
+ 0x0, /* gcFEATURE_BIT_REG_DESupertile */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes19 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements6 */
+ 0x1, /* gcFEATURE_BIT_REG_SHEnhancements7 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes20 */
+ 0x0, /* gcFEATURE_BIT_REG_DEAddress40 */
+ 0x0, /* gcFEATURE_BIT_REG_MiniMMUFix */
+ 0x1, /* gcFEATURE_BIT_REG_EEZ */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes21 */
+ 0x0, /* gcFEATURE_BIT_REG_ExtraVgCaps */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV15 */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixes22 */
+ 0x1, /* gcFEATURE_BIT_REG_Halti3 */
+ 0x0, /* gcFEATURE_BIT_REG_TessellationShaders */
+ 0x0, /* gcFEATURE_BIT_REG_OPF9Tap */
+ 0x0, /* gcFEATURE_BIT_REG_MultiSrcV2StrQuad */
+ 0x0, /* gcFEATURE_BIT_REG_SeperateSRCAndDstCache */
+ 0x1, /* gcFEATURE_BIT_REG_Halti4 */
+ 0x1, /* gcFEATURE_BIT_REG_RAWriteDepth */
+ 0x0, /* gcFEATURE_BIT_REG_AndroidOnly */
+ 0x1, /* gcFEATURE_BIT_REG_HasChipProductReg */
+ 0x0, /* gcFEATURE_BIT_REG_TXSupportDEC */
+ 0x1, /* gcFEATURE_BIT_REG_S8MSAACompression */
+ 0x1, /* gcFEATURE_BIT_REG_BugFixesIn544 */
+ 0x0, /* gcFEATURE_BIT_REG_L2CacheRemove */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowRndVtxCnt */
+ 0x0, /* gcFEATURE_BIT_REG_CubeMapFL28 */
+ 0x1, /* gcFEATURE_BIT_REG_TX6bitFrac */
+ 0x1, /* gcFEATURE_BIT_REG_FEAllowStallPrefetchEng */
+ 0x0, /* gcFEATURE_BIT_REG_ThirdPartyCompression */
+ 0x1, /* gcFEATURE_BIT_REG_RSS8 */
+ 0x1, /* gcFEATURE_BIT_REG_MSAACoherencyCheck */
+ 0x1, /* gcFEATURE_BIT_REG_Halti5 */
+ 0x0, /* gcFEATURE_BIT_REG_Evis */
+ 0x1, /* gcFEATURE_BIT_REG_BltEngine */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes23 */
+ 0x0, /* gcFEATURE_BIT_REG_BugFixes24 */
+ 0x0, /* gcFEATURE_BIT_REG_DEC */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12 */
+ 0x0, /* gcFEATURE_BIT_REG_VSTileNV12_10BIT */
+ 0x0, /* gcFEATURE_BIT_RenderTarget8 */
+ 0x0, /* gcFEATURE_BIT_TxLodFlowCorrection */
+ 0x0, /* gcFEATURE_BIT_FaceLod */
+ 0x0, /* gcFEATURE_BIT_MultiCoreSemaphoreStallV2 */
+ 0x1, /* gcFEATURE_BIT_VMSAA */
+ 0x0, /* gcFEATURE_BIT_ChipEnableLink */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_1_5_ENHANCEMENT */
+ 0x0, /* gcFEATURE_BIT_MULTI_SRC_BLT_BILINEAR_FILTER */
+ 0x1, /* gcFEATURE_BIT_RA_HZEZ_CLOCK_CONTROL */
+ 0x1, /* gcFEATURE_BIT_CACHE128B256BPERLINE */
+ 0x1, /* gcFEATURE_BIT_V4Compression */
+ 0x0, /* gcFEATURE_BIT_PE2D_MAJOR_SUPER_TILE */
+ 0x1, /* gcFEATURE_BIT_PE_32BPC_COLORMASK_FIX */
+ 0x1, /* gcFEATURE_BIT_ALPHA_BLENDING_OPT */
+ 0x1, /* gcFEATURE_BIT_NEW_GPIPE */
+ 0x0, /* gcFEATURE_BIT_PIPELINE_32_ATTRIBUTES */
+ 0x0, /* gcFEATURE_BIT_MSAA_SHADING */
+ 0x0, /* gcFEATURE_BIT_NO_ANISTRO_FILTER */
+ 0x1, /* gcFEATURE_BIT_NO_ASTC */
+ 0x0, /* gcFEATURE_BIT_NO_DXT */
+ 0x0, /* gcFEATURE_BIT_HWTFB */
+ 0x1, /* gcFEATURE_BIT_RA_DEPTH_WRITE_MSAA1X_FIX */
+ 0x1, /* gcFEATURE_BIT_EZHZ_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_HALFDEPENDENCY_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MCFILL_FIX */
+ 0x1, /* gcFEATURE_BIT_TPG_TCPERF_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_MDFIFO_OVERFLOW_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_TEXLD_BARRIER_IN_CS_FIX */
+ 0x1, /* gcFEATURE_BIT_RS_NEW_BASEADDR */
+ 0x1, /* gcFEATURE_BIT_PE_8bpp_DUALPIPE_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_ADVANCED_INSTR */
+ 0x1, /* gcFEATURE_BIT_SH_FLAT_INTERPOLATION_DUAL16_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_CONTINUOUS_FLUS_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_V4 */
+ 0x0, /* gcFEATURE_BIT_SH_SUPPORT_ALPHA_KILL */
+ 0x1, /* gcFEATURE_BIT_PE_NO_ALPHA_TEST */
+ 0x0, /* gcFEATURE_BIT_TX_LOD_NEAREST_SELECT */
+ 0x1, /* gcFEATURE_BIT_SH_FIX_LDEXP */
+ 0x1, /* gcFEATURE_BIT_SUPPORT_MOVAI */
+ 0x1, /* gcFEATURE_BIT_SH_SNAP2PAGE_MAXPAGES_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_RGBA16I_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_8bpp_256TILE_FC_FIX */
+ 0x1, /* gcFEATURE_BIT_PE_64bit_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_FULL_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_YUV_ASSEMBLER_10BIT */
+ 0x1, /* gcFEATURE_BIT_FE_32bit_INDEX_FIX */
+ 0x1, /* gcFEATURE_BIT_BLT_64bpp_MASKED_CLEAR_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY */
+ 0x1, /* gcFEATURE_BIT_ROBUSTNESS */
+ 0x1, /* gcFEATURE_BIT_USC_ATOMIC_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_PSO_MSAA1x_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_VX_PERF_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_ABSDIFF */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BITREPLACE */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_BOXFILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_CORDIAC */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_DP32 */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_FILTER */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_IADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_NO_SELECTADD */
+ 0x0, /* gcFEATURE_BIT_EVIS_LERP_7OUTPUT */
+ 0x0, /* gcFEATURE_BIT_EVIS_ACCSQ_8OUTPUT */
+ 0x1, /* gcFEATURE_BIT_USC_GOS_ADDR_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_8bit_UVFrac */
+ 0x1, /* gcFEATURE_BIT_TX_DESC_CACHE_CLOCKGATE_FIX */
+ 0x1, /* gcFEATURE_BIT_RSBLT_MSAA_DECOMPRESSION */
+ 0x0, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE */
+ 0x1, /* gcFEATURE_BIT_DRAWID */
+ 0x1, /* gcFEATURE_BIT_PSIO_SAMPLEMASK_IN_R0ZW_FIX */
+ 0x1, /* gcFEATURE_BIT_TX_INTEGER_COORDINATE_V2 */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLVE_ENGINE */
+ 0x0, /* gcFEATURE_BIT_VG_PE_COLOR_KEY */
+ 0x0, /* gcFEATURE_BIT_VG_IM_INDEX_FORMAT */
+ 0x0, /* gcFEATURE_BIT_SNAPPAGE_CMD */
+ 0x1, /* gcFEATURE_BIT_SH_NO_INDEX_CONST_ON_A0 */
+ 0x1, /* gcFEATURE_BIT_SH_NO_ONECONST_LIMIT */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_ON_TEMP */
+ 0x1, /* gcFEATURE_BIT_COMPUTE_ONLY */
+ 0x1, /* gcFEATURE_BIT_SH_IMG_LDST_CLAMP */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_ALLOC_COUNT_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_ICACHE_PREFETCH */
+ 0x0, /* gcFEATURE_BIT_PE2D_SEPARATE_CACHE */
+ 0x0, /* gcFEATURE_BIT_VG_AYUV_INPUT_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_VG_DOUBLE_IMAGE */
+ 0x0, /* gcFEATURE_BIT_VG_RECTANGLE_STRIPE_MODE */
+ 0x0, /* gcFEATURE_BIT_VG_MMU */
+ 0x0, /* gcFEATURE_BIT_VG_IM_FILTER */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_IM_YUV_PLANAR */
+ 0x0, /* gcFEATURE_BIT_VG_PE_YUV_PACKET */
+ 0x0, /* gcFEATURE_BIT_VG_COLOR_PRECISION_8_BIT */
+ 0x1, /* gcFEATURE_BIT_PE_MSAA_OQ_FIX */
+ 0x1, /* gcFEATURE_BIT_PSIO_MSAA_CL_FIX */
+ 0x1, /* gcFEATURE_BIT_USC_DEFER_FILL_FIX */
+ 0x1, /* gcFEATURE_BIT_SH_CLOCK_GATE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_NEED_DUMMYDRAW */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_PE2D_LINEAR_YUV420_10BIT */
+ 0x0, /* gcFEATURE_BIT_MULTI_CLUSTER */
+ 0x0, /* gcFEATURE_BIT_VG_TS_CULLING */
+ 0x0, /* gcFEATURE_BIT_VG_FP25 */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK */
+ 0x0, /* gcFEATURE_BIT_SH_DUAL16_SAMPLEMASK_ZW */
+ 0x0, /* gcFEATURE_BIT_TPG_TRIVIAL_MODE_FIX */
+ 0x0, /* gcFEATURE_BIT_TX_ASTC_MULTISLICE_FIX */
+ 0x0, /* gcFEATURE_BIT_FE_ROBUST_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_GPIPE_ACCESS_FULLTEMPS */
+ 0x0, /* gcFEATURE_BIT_PSIO_INTERLOCK */
+ 0x1, /* gcFEATURE_BIT_PA_WIDELINE_FIX */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_HELPER_FIX */
+ 0x0, /* gcFEATURE_BIT_G2D_3rd_PARTY_COMPRESSION_1_1 */
+ 0x0, /* gcFEATURE_BIT_TX_FLUSH_L1CACHE */
+ 0x1, /* gcFEATURE_BIT_PE_DITHER_FIX2 */
+ 0x0, /* gcFEATURE_BIT_G2D_DEC400 */
+ 0x0, /* gcFEATURE_BIT_SH_TEXLD_U_FIX */
+ 0x0, /* gcFEATURE_BIT_MC_FCCACHE_BYTEMASK */
+ 0x0, /* gcFEATURE_BIT_SH_MULTI_WG_PACK_FIX */
+ 0x0, /* gcFEATURE_BIT_DC_OVERLAY_SCALING */
+ 0x0, /* gcFEATURE_BIT_DC_SOURCE_ROTATION */
+ 0x0, /* gcFEATURE_BIT_DC_TILED */
+ 0x0, /* gcFEATURE_BIT_DC_YUV_L1 */
+ 0x0, /* gcFEATURE_BIT_DC_D30_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_DC_MMU */
+ 0x0, /* gcFEATURE_BIT_DC_COMPRESSION */
+ 0x0, /* gcFEATURE_BIT_DC_QOS */
+ 0x0, /* gcFEATURE_BIT_PE_ADVANCE_BLEND_PART0 */
+ 0x0, /* gcFEATURE_BIT_FE_PATCHLIST_FETCH_FIX */
+ 0x1, /* gcFEATURE_BIT_RA_CG_FIX */
+ 0x0, /* gcFEATURE_BIT_EVIS_VX2 */
+ 0x0, /* gcFEATURE_BIT_NN_FLOAT */
+ 0x0, /* gcFEATURE_BIT_DEC400 */
+ 0x0, /* gcFEATURE_BIT_LS_SUPPORT_PERCOMP_DEPENDENCY */
+ 0x0, /* gcFEATURE_BIT_TP_ENGINE */
+ 0x0, /* gcFEATURE_BIT_MULTI_CORE_BLOCK_SET_CONFIG2 */
+ 0x0, /* gcFEATURE_BIT_PE_VMSAA_COVERAGE_CACHE_FIX */
+ 0x1, /* gcFEATURE_BIT_SECURITY_AHB */
+ 0x0, /* gcFEATURE_BIT_MULTICORE_SEMAPHORESTALL_V3 */
+ 0x0, /* gcFEATURE_BIT_SMALLBATCH */
+ 0x1, /* gcFEATURE_BIT_SH_CMPLX */
+ 0x1, /* gcFEATURE_BIT_SH_IDIV0_SWZL_EHS */
+ 0x0, /* gcFEATURE_BIT_TX_LERP_LESS_BIT */
+ 0x0, /* gcFEATURE_BIT_SH_GM_ENDIAN */
+ 0x0, /* gcFEATURE_BIT_SH_GM_USC_UNALLOC */
+ 0x1, /* gcFEATURE_BIT_SH_END_OF_BB */
+ 0x0, /* gcFEATURE_BIT_VIP_V7 */
+ 0x0, /* gcFEATURE_BIT_TX_BORDER_CLAMP_FIX */
+ 0x0, /* gcFEATURE_BIT_SH_IMG_LD_LASTPIXEL_FIX */
+ 0x1, /* gcFEATURE_BIT_ASYNC_BLT */
+ 0x1, /* gcFEATURE_BIT_ASYNC_FE_FENCE_FIX */
+ 0x1, /* gcFEATURE_BIT_PSCS_THROTTLE */
+ 0x1, /* gcFEATURE_BIT_SEPARATE_LS */
+ 0x0, /* gcFEATURE_BIT_MCFE */
+ 0x0, /* gcFEATURE_BIT_WIDELINE_TRIANGLE_EMU */
+ 0x0, /* gcFEATURE_BIT_VG_RESOLUTION_8K */
+ 0x0, /* gcFEATURE_BIT_FENCE_32BIT */
+ 0x1, /* gcFEATURE_BIT_FENCE_64BIT */
+ 0x0, /* gcFEATURE_BIT_NN_INTERLEVE8 */
+ 0x0, /* gcFEATURE_BIT_TP_REORDER */
+ 0x0, /* gcFEATURE_BIT_PE_DEPTH_ONLY_OQFIX */
+ 0x0, /* gcFEATURE_BIT_TP_LRN */
+ 0x1, /* gcFEATURE_BIT_TX_SEAMLESS_CUBE */
+ 0x1, /* gcFEATURE_BIT_TX_SNORM_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_TP_MAX_POOLING_STRIDE1 */
+ 0x0, /* gcFEATURE_BIT_SH_SCATTER_GATHER */
+ 0x0, /* gcFEATURE_BIT_HWMANAGED_LS */
+ 0x0, /* gcFEATURE_BIT_NN_FP16_ALU */
+ 0x0, /* gcFEATURE_BIT_NN_INT16_ALU */
+ 0x0, /* gcFEATURE_BIT_TP_ROI_POOLING */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP3 */
+ 0x0, /* gcFEATURE_BIT_NN_ZDP6 */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP9 */
+ 0x0, /* gcFEATURE_BIT_NN_INT8_SCALE */
+ 0x0, /* gcFEATURE_BIT_NN_POWER_ISOLATION */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE1 */
+ 0x0, /* gcFEATURE_BIT_SH_IMAGE_ENABLE_FIX */
+ 0x0, /* gcFEATURE_BIT_TF_QUANTIZATION */
+ 0x1, /* gcFEATURE_BIT_MSAA_FRAGMENT_OPERATION */
+ 0x0, /* gcFEATURE_BIT_TP_SIMPLE_INT16 */
+ 0x0, /* gcFEATURE_BIT_TP_REAL_INT16 */
+ 0x0, /* gcFEATURE_BIT_NN_FIRST_PIXEL_POOLING */
+ 0x0, /* gcFEATURE_BIT_SWTILING_PHASE2 */
+ 0x0, /* gcFEATURE_BIT_VG_FORMAT_ARGB2222 */
+ 0x0, /* gcFEATURE_BIT_PE_TILE_CACHE_FLUSH_FIX */
+ 0x0, /* gcFEATURE_BIT_BLT_YUV_OUTPUT */
+ 0x0, /* gcFEATURE_BIT_NN_STRIDE_SUPPORT */
+ 0x0, /* gcFEATURE_BIT_NN_XYDP6 */
+ },
+};
+
+static gcsFEATURE_DATABASE*
+gcQueryFeatureDB(
+ gctUINT32 ChipID,
+ gctUINT32 ChipVersion,
+ gctUINT32 ProductID,
+ gctUINT32 EcoID,
+ gctUINT32 CustomerID
+ )
+{
+ gctINT entryNum = sizeof(gChipInfo) / sizeof(gChipInfo[0]);
+ gctINT i;
+
+ /* check formal release entries first */
+ for (i = 0; i < entryNum; ++i)
+ {
+
+ if ((gChipInfo[i].chipID == ChipID)
+ && (gChipInfo[i].chipVersion == ChipVersion)
+ && (gChipInfo[i].productID == ProductID)
+ && (gChipInfo[i].ecoID == EcoID)
+ && (gChipInfo[i].customerID == CustomerID)
+ && (gChipInfo[i].formalRelease)
+ )
+ {
+ return &gChipInfo[i];
+ }
+ }
+
+ /* check informal release entries if we dont find in formal entries */
+ for (i = 0; i < entryNum; ++i)
+ {
+
+ if ((gChipInfo[i].chipID == ChipID)
+ && ((gChipInfo[i].chipVersion & 0xFFF0) == (ChipVersion & 0xFFF0))
+ && (gChipInfo[i].productID == ProductID)
+ && (gChipInfo[i].ecoID == EcoID)
+ && (gChipInfo[i].customerID == CustomerID)
+ && (!gChipInfo[i].formalRelease)
+ )
+ {
+ return &gChipInfo[i];
+ }
+ }
+
+ return gcvNULL;
+}
+#endif /* _gc_feature_database_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal.h
new file mode 100644
index 000000000000..6cde22deb38c
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal.h
@@ -0,0 +1,2827 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_h_
+#define __gc_hal_h_
+
+#include "gc_hal_rename.h"
+#include "gc_hal_types.h"
+#include "gc_hal_enum.h"
+#include "gc_hal_base.h"
+#include "gc_hal_profiler.h"
+#include "gc_hal_driver.h"
+#if gcdENABLE_3D
+#include "gc_hal_statistics.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+******************************* Alignment Macros *******************************
+\******************************************************************************/
+
+/* Alignment with a non-power of two value. */
+#define gcmALIGN_NP2(n, align) \
+( \
+ ((n) + (align) - 1) - (((n) + (align) - 1) % (align)) \
+)
+
+/* Alignment with a power of two value. */
+#define gcmALIGN(n, align) \
+( \
+ ((n) + ((align) - 1)) & ~((align) - 1) \
+)
+
+#define gcmALIGN_BASE(n, align) \
+( \
+ ((n) & ~((align) - 1)) \
+)
+
+/******************************************************************************\
+***************************** Element Count Macro *****************************
+\******************************************************************************/
+
+#define gcmSIZEOF(a) \
+( \
+ (gctSIZE_T) (sizeof(a)) \
+)
+
+#define gcmCOUNTOF(a) \
+( \
+ sizeof(a) / sizeof(a[0]) \
+)
+
+/******************************************************************************\
+********************************* Cast Macro **********************************
+\******************************************************************************/
+#define gcmNAME_TO_PTR(na) \
+ gckKERNEL_QueryPointerFromName(kernel, gcmALL_TO_UINT32(na))
+
+#define gcmPTR_TO_NAME(ptr) \
+ gckKERNEL_AllocateNameFromPointer(kernel, ptr)
+
+#define gcmRELEASE_NAME(na) \
+ gckKERNEL_DeleteName(kernel, gcmALL_TO_UINT32(na))
+
+#define gcmALL_TO_UINT32(t) \
+( \
+ (gctUINT32) (gctUINTPTR_T) (t)\
+)
+
+#define gcmPTR_TO_UINT64(p) \
+( \
+ (gctUINT64) (gctUINTPTR_T) (p)\
+)
+
+#define gcmUINT64_TO_PTR(u) \
+( \
+ (gctPOINTER) (gctUINTPTR_T) (u)\
+)
+
+#define gcmUINT64_TO_TYPE(u, t) \
+( \
+ (t) (gctUINTPTR_T) (u)\
+)
+
+/******************************************************************************\
+******************************** Useful Macro *********************************
+\******************************************************************************/
+
+#define gcvINVALID_ADDRESS ~0U
+#define gcvINVALID_VALUE 0xCCCCCCCC
+
+#define gcvINVALID_PHYSICAL_ADDRESS ~0U
+
+#define gcmGET_PRE_ROTATION(rotate) \
+ ((rotate) & (~(gcvSURF_POST_FLIP_X | gcvSURF_POST_FLIP_Y)))
+
+#define gcmGET_POST_ROTATION(rotate) \
+ ((rotate) & (gcvSURF_POST_FLIP_X | gcvSURF_POST_FLIP_Y))
+
+/******************************************************************************\
+******************************** gcsOBJECT Object *******************************
+\******************************************************************************/
+
+/* Type of objects. */
+typedef enum _gceOBJECT_TYPE
+{
+ gcvOBJ_UNKNOWN = 0,
+ gcvOBJ_2D = gcmCC('2','D',' ',' '),
+ gcvOBJ_3D = gcmCC('3','D',' ',' '),
+ gcvOBJ_ATTRIBUTE = gcmCC('A','T','T','R'),
+ gcvOBJ_BRUSHCACHE = gcmCC('B','R','U','$'),
+ gcvOBJ_BRUSHNODE = gcmCC('B','R','U','n'),
+ gcvOBJ_BRUSH = gcmCC('B','R','U','o'),
+ gcvOBJ_BUFFER = gcmCC('B','U','F','R'),
+ gcvOBJ_COMMAND = gcmCC('C','M','D',' '),
+ gcvOBJ_COMMANDBUFFER = gcmCC('C','M','D','B'),
+ gcvOBJ_CONTEXT = gcmCC('C','T','X','T'),
+ gcvOBJ_DEVICE = gcmCC('D','E','V',' '),
+ gcvOBJ_DUMP = gcmCC('D','U','M','P'),
+ gcvOBJ_EVENT = gcmCC('E','V','N','T'),
+ gcvOBJ_FUNCTION = gcmCC('F','U','N','C'),
+ gcvOBJ_HAL = gcmCC('H','A','L',' '),
+ gcvOBJ_HARDWARE = gcmCC('H','A','R','D'),
+ gcvOBJ_HEAP = gcmCC('H','E','A','P'),
+ gcvOBJ_INDEX = gcmCC('I','N','D','X'),
+ gcvOBJ_INTERRUPT = gcmCC('I','N','T','R'),
+ gcvOBJ_KERNEL = gcmCC('K','E','R','N'),
+ gcvOBJ_KERNEL_FUNCTION = gcmCC('K','F','C','N'),
+ gcvOBJ_MEMORYBUFFER = gcmCC('M','E','M','B'),
+ gcvOBJ_MMU = gcmCC('M','M','U',' '),
+ gcvOBJ_OS = gcmCC('O','S',' ',' '),
+ gcvOBJ_OUTPUT = gcmCC('O','U','T','P'),
+ gcvOBJ_PAINT = gcmCC('P','N','T',' '),
+ gcvOBJ_PATH = gcmCC('P','A','T','H'),
+ gcvOBJ_QUEUE = gcmCC('Q','U','E',' '),
+ gcvOBJ_SAMPLER = gcmCC('S','A','M','P'),
+ gcvOBJ_SHADER = gcmCC('S','H','D','R'),
+ gcvOBJ_VIR_SHADER = gcmCC('V','S','D','R'),
+ gcvOBJ_STREAM = gcmCC('S','T','R','M'),
+ gcvOBJ_SURF = gcmCC('S','U','R','F'),
+ gcvOBJ_TEXTURE = gcmCC('T','X','T','R'),
+ gcvOBJ_UNIFORM = gcmCC('U','N','I','F'),
+ gcvOBJ_VARIABLE = gcmCC('V','A','R','I'),
+ gcvOBJ_VERTEX = gcmCC('V','R','T','X'),
+ gcvOBJ_VIDMEM = gcmCC('V','M','E','M'),
+ gcvOBJ_VG = gcmCC('V','G',' ',' '),
+ gcvOBJ_BUFOBJ = gcmCC('B','U','F','O'),
+ gcvOBJ_UNIFORM_BLOCK = gcmCC('U','B','L','K'),
+ gcvOBJ_CL = gcmCC('C','L',' ',' '),
+ gcvOBJ_STORAGE_BLOCK = gcmCC('S','B','L','K'),
+ gcvOBJ_IO_BLOCK = gcmCC('I','O','B','K'),
+}
+gceOBJECT_TYPE;
+
+/* gcsOBJECT object defintinon. */
+typedef struct _gcsOBJECT
+{
+ /* Type of an object. */
+ gceOBJECT_TYPE type;
+}
+gcsOBJECT;
+
+typedef struct _gckHARDWARE * gckHARDWARE;
+
+
+#define gcdMAX_GPU_COUNT gcvCORE_COUNT
+
+#define gcdMAX_SURF_LAYERS 4
+
+#define gcdMAX_DRAW_BUFFERS 8
+
+/*******************************************************************************
+**
+** gcmVERIFY_OBJECT
+**
+** Assert if an object is invalid or is not of the specified type. If the
+** object is invalid or not of the specified type, gcvSTATUS_INVALID_OBJECT
+** will be returned from the current function. In retail mode this macro
+** does nothing.
+**
+** ARGUMENTS:
+**
+** obj Object to test.
+** t Expected type of the object.
+*/
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+#define _gcmVERIFY_OBJECT(prefix, obj, t) \
+ if ((obj) == gcvNULL) \
+ { \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ #prefix "VERIFY_OBJECT failed: NULL"); \
+ prefix##TRACE(gcvLEVEL_ERROR, " expected: %c%c%c%c", \
+ gcmCC_PRINT(t)); \
+ prefix##ASSERT((obj) != gcvNULL); \
+ prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_OBJECT); \
+ return gcvSTATUS_INVALID_OBJECT; \
+ } \
+ else if (((gcsOBJECT*) (obj))->type != t) \
+ { \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ #prefix "VERIFY_OBJECT failed: %c%c%c%c", \
+ gcmCC_PRINT(((gcsOBJECT*) (obj))->type)); \
+ prefix##TRACE(gcvLEVEL_ERROR, " expected: %c%c%c%c", \
+ gcmCC_PRINT(t)); \
+ prefix##ASSERT(((gcsOBJECT*)(obj))->type == t); \
+ prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_OBJECT); \
+ return gcvSTATUS_INVALID_OBJECT; \
+ }
+
+# define gcmVERIFY_OBJECT(obj, t) _gcmVERIFY_OBJECT(gcm, obj, t)
+# define gcmkVERIFY_OBJECT(obj, t) _gcmVERIFY_OBJECT(gcmk, obj, t)
+#else
+# define gcmVERIFY_OBJECT(obj, t) do {} while (gcvFALSE)
+# define gcmkVERIFY_OBJECT(obj, t) do {} while (gcvFALSE)
+#endif
+
+/******************************************************************************/
+/*VERIFY_OBJECT if special return expected*/
+/******************************************************************************/
+#ifndef EGL_API_ANDROID
+# define _gcmVERIFY_OBJECT_RETURN(prefix, obj, t, retVal) \
+ do \
+ { \
+ if ((obj) == gcvNULL) \
+ { \
+ prefix##PRINT_VERSION(); \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ #prefix "VERIFY_OBJECT_RETURN failed: NULL"); \
+ prefix##TRACE(gcvLEVEL_ERROR, " expected: %c%c%c%c", \
+ gcmCC_PRINT(t)); \
+ prefix##ASSERT((obj) != gcvNULL); \
+ prefix##FOOTER_ARG("retVal=%d", retVal); \
+ return retVal; \
+ } \
+ else if (((gcsOBJECT*) (obj))->type != t) \
+ { \
+ prefix##PRINT_VERSION(); \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ #prefix "VERIFY_OBJECT_RETURN failed: %c%c%c%c", \
+ gcmCC_PRINT(((gcsOBJECT*) (obj))->type)); \
+ prefix##TRACE(gcvLEVEL_ERROR, " expected: %c%c%c%c", \
+ gcmCC_PRINT(t)); \
+ prefix##ASSERT(((gcsOBJECT*)(obj))->type == t); \
+ prefix##FOOTER_ARG("retVal=%d", retVal); \
+ return retVal; \
+ } \
+ } \
+ while (gcvFALSE)
+# define gcmVERIFY_OBJECT_RETURN(obj, t, retVal) \
+ _gcmVERIFY_OBJECT_RETURN(gcm, obj, t, retVal)
+# define gcmkVERIFY_OBJECT_RETURN(obj, t, retVal) \
+ _gcmVERIFY_OBJECT_RETURN(gcmk, obj, t, retVal)
+#else
+# define gcmVERIFY_OBJECT_RETURN(obj, t) do {} while (gcvFALSE)
+# define gcmVERIFY_OBJECT_RETURN(obj, t) do {} while (gcvFALSE)
+#endif
+
+typedef struct _gcsContiguousBlock
+{
+ gctUINT32 ptr;
+ gctSIZE_T size;
+}
+gcsContiguousBlock;
+
+
+/******************************************************************************\
+********************************** gckOS Object *********************************
+\******************************************************************************/
+
+/* Construct a new gckOS object. */
+gceSTATUS
+gckOS_Construct(
+ IN gctPOINTER Context,
+ OUT gckOS * Os
+ );
+
+/* Destroy an gckOS object. */
+gceSTATUS
+gckOS_Destroy(
+ IN gckOS Os
+ );
+
+/* Query the video memory. */
+gceSTATUS
+gckOS_QueryVideoMemory(
+ IN gckOS Os,
+ OUT gctPHYS_ADDR * InternalAddress,
+ OUT gctSIZE_T * InternalSize,
+ OUT gctPHYS_ADDR * ExternalAddress,
+ OUT gctSIZE_T * ExternalSize,
+ OUT gctPHYS_ADDR * ContiguousAddress,
+ OUT gctSIZE_T * ContiguousSize
+ );
+
+/* Allocate memory from the heap. */
+gceSTATUS
+gckOS_Allocate(
+ IN gckOS Os,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Memory
+ );
+
+/* Free allocated memory. */
+gceSTATUS
+gckOS_Free(
+ IN gckOS Os,
+ IN gctPOINTER Memory
+ );
+
+/* Wrapper for allocation memory.. */
+gceSTATUS
+gckOS_AllocateMemory(
+ IN gckOS Os,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Memory
+ );
+
+/* Wrapper for freeing memory. */
+gceSTATUS
+gckOS_FreeMemory(
+ IN gckOS Os,
+ IN gctPOINTER Memory
+ );
+
+/* Allocate paged memory. */
+gceSTATUS
+gckOS_AllocatePagedMemory(
+ IN gckOS Os,
+ IN gctSIZE_T Bytes,
+ OUT gctPHYS_ADDR * Physical
+ );
+
+/* Allocate paged memory. */
+gceSTATUS
+gckOS_AllocatePagedMemoryEx(
+ IN gckOS Os,
+ IN gctUINT32 Flag,
+ IN gctSIZE_T Bytes,
+ OUT gctUINT32 * Gid,
+ OUT gctPHYS_ADDR * Physical
+ );
+
+/* Lock pages. */
+gceSTATUS
+gckOS_LockPages(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctBOOL Cacheable,
+ OUT gctPOINTER * Logical,
+ OUT gctSIZE_T * PageCount
+ );
+
+/* Map pages. */
+gceSTATUS
+gckOS_MapPages(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T PageCount,
+ IN gctPOINTER PageTable
+ );
+
+/* Map pages. */
+gceSTATUS
+gckOS_MapPagesEx(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T PageCount,
+ IN gctUINT32 Address,
+ IN gctPOINTER PageTable,
+ IN gctBOOL Writable,
+ IN gceSURF_TYPE Type
+ );
+
+gceSTATUS
+gckOS_UnmapPages(
+ IN gckOS Os,
+ IN gctSIZE_T PageCount,
+ IN gctUINT32 Address
+ );
+
+/* Unlock pages. */
+gceSTATUS
+gckOS_UnlockPages(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical
+ );
+
+/* Free paged memory. */
+gceSTATUS
+gckOS_FreePagedMemory(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes
+ );
+
+/* Allocate non-paged memory. */
+gceSTATUS
+gckOS_AllocateNonPagedMemory(
+ IN gckOS Os,
+ IN gctBOOL InUserSpace,
+ IN OUT gctSIZE_T * Bytes,
+ OUT gctPHYS_ADDR * Physical,
+ OUT gctPOINTER * Logical
+ );
+
+/* Free non-paged memory. */
+gceSTATUS
+gckOS_FreeNonPagedMemory(
+ IN gckOS Os,
+ IN gctSIZE_T Bytes,
+ IN gctPHYS_ADDR Physical,
+ IN gctPOINTER Logical
+ );
+
+/* Allocate contiguous memory. */
+gceSTATUS
+gckOS_AllocateContiguous(
+ IN gckOS Os,
+ IN gctBOOL InUserSpace,
+ IN OUT gctSIZE_T * Bytes,
+ OUT gctPHYS_ADDR * Physical,
+ OUT gctPOINTER * Logical
+ );
+
+/* Free contiguous memory. */
+gceSTATUS
+gckOS_FreeContiguous(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ );
+
+/* Get the number fo bytes per page. */
+gceSTATUS
+gckOS_GetPageSize(
+ IN gckOS Os,
+ OUT gctSIZE_T * PageSize
+ );
+
+/* Get the physical address of a corresponding logical address. */
+gceSTATUS
+gckOS_GetPhysicalAddress(
+ IN gckOS Os,
+ IN gctPOINTER Logical,
+ OUT gctPHYS_ADDR_T * Address
+ );
+
+/* Get the physical address of a corresponding user logical address. */
+gceSTATUS
+gckOS_UserLogicalToPhysical(
+ IN gckOS Os,
+ IN gctPOINTER Logical,
+ OUT gctPHYS_ADDR_T * Address
+ );
+
+/* Map physical memory. */
+gceSTATUS
+gckOS_MapPhysical(
+ IN gckOS Os,
+ IN gctUINT32 Physical,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Logical
+ );
+
+/* Unmap previously mapped physical memory. */
+gceSTATUS
+gckOS_UnmapPhysical(
+ IN gckOS Os,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ );
+
+/* Get real physical address from descriptor. */
+gceSTATUS
+gckOS_PhysicalToPhysicalAddress(
+ IN gckOS Os,
+ IN gctPOINTER Physical,
+ IN gctUINT32 Offset,
+ OUT gctPHYS_ADDR_T * PhysicalAddress
+ );
+
+/* Read data from a hardware register. */
+gceSTATUS
+gckOS_ReadRegister(
+ IN gckOS Os,
+ IN gctUINT32 Address,
+ OUT gctUINT32 * Data
+ );
+
+/* Read data from a hardware register. */
+gceSTATUS
+gckOS_ReadRegisterEx(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctUINT32 Address,
+ OUT gctUINT32 * Data
+ );
+
+/* Write data to a hardware register. */
+gceSTATUS
+gckOS_WriteRegister(
+ IN gckOS Os,
+ IN gctUINT32 Address,
+ IN gctUINT32 Data
+ );
+
+/* Write data to a hardware register. */
+gceSTATUS
+gckOS_WriteRegisterEx(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctUINT32 Address,
+ IN gctUINT32 Data
+ );
+
+/* Write data to a 32-bit memory location. */
+gceSTATUS
+gckOS_WriteMemory(
+ IN gckOS Os,
+ IN gctPOINTER Address,
+ IN gctUINT32 Data
+ );
+
+/* Map physical memory into the process space. */
+gceSTATUS
+gckOS_MapMemory(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Logical
+ );
+
+/* Unmap physical memory from the specified process space. */
+gceSTATUS
+gckOS_UnmapMemoryEx(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical,
+ IN gctUINT32 PID
+ );
+
+/* Unmap physical memory from the process space. */
+gceSTATUS
+gckOS_UnmapMemory(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical
+ );
+
+/* Unmap user logical memory out of physical memory.
+ * This function is only supported in Linux currently.
+ */
+gceSTATUS
+gckOS_UnmapUserLogical(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical
+ );
+
+/* Delete a mutex. */
+gceSTATUS
+gckOS_DeleteMutex(
+ IN gckOS Os,
+ IN gctPOINTER Mutex
+ );
+
+/* Acquire a mutex. */
+gceSTATUS
+gckOS_AcquireMutex(
+ IN gckOS Os,
+ IN gctPOINTER Mutex,
+ IN gctUINT32 Timeout
+ );
+
+/* Release a mutex. */
+gceSTATUS
+gckOS_ReleaseMutex(
+ IN gckOS Os,
+ IN gctPOINTER Mutex
+ );
+
+/* Atomically exchange a pair of 32-bit values. */
+gceSTATUS
+gckOS_AtomicExchange(
+ IN gckOS Os,
+ IN OUT gctUINT32_PTR Target,
+ IN gctUINT32 NewValue,
+ OUT gctUINT32_PTR OldValue
+ );
+
+/* Atomically exchange a pair of pointers. */
+gceSTATUS
+gckOS_AtomicExchangePtr(
+ IN gckOS Os,
+ IN OUT gctPOINTER * Target,
+ IN gctPOINTER NewValue,
+ OUT gctPOINTER * OldValue
+ );
+
+gceSTATUS
+gckOS_AtomSetMask(
+ IN gctPOINTER Atom,
+ IN gctUINT32 Mask
+ );
+
+gceSTATUS
+gckOS_AtomClearMask(
+ IN gctPOINTER Atom,
+ IN gctUINT32 Mask
+ );
+
+gceSTATUS
+gckOS_DumpCallStack(
+ IN gckOS Os
+ );
+
+gceSTATUS
+gckOS_GetProcessNameByPid(
+ IN gctINT Pid,
+ IN gctSIZE_T Length,
+ OUT gctUINT8_PTR String
+ );
+
+/*******************************************************************************
+**
+** gckOS_AtomConstruct
+**
+** Create an atom.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** OUTPUT:
+**
+** gctPOINTER * Atom
+** Pointer to a variable receiving the constructed atom.
+*/
+gceSTATUS
+gckOS_AtomConstruct(
+ IN gckOS Os,
+ OUT gctPOINTER * Atom
+ );
+
+/*******************************************************************************
+**
+** gckOS_AtomDestroy
+**
+** Destroy an atom.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gctPOINTER Atom
+** Pointer to the atom to destroy.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_AtomDestroy(
+ IN gckOS Os,
+ OUT gctPOINTER Atom
+ );
+
+/*******************************************************************************
+**
+** gckOS_AtomGet
+**
+** Get the 32-bit value protected by an atom.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gctPOINTER Atom
+** Pointer to the atom.
+**
+** OUTPUT:
+**
+** gctINT32_PTR Value
+** Pointer to a variable the receives the value of the atom.
+*/
+gceSTATUS
+gckOS_AtomGet(
+ IN gckOS Os,
+ IN gctPOINTER Atom,
+ OUT gctINT32_PTR Value
+ );
+
+/*******************************************************************************
+**
+** gckOS_AtomSet
+**
+** Set the 32-bit value protected by an atom.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gctPOINTER Atom
+** Pointer to the atom.
+**
+** gctINT32 Value
+** The value of the atom.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_AtomSet(
+ IN gckOS Os,
+ IN gctPOINTER Atom,
+ IN gctINT32 Value
+ );
+
+/*******************************************************************************
+**
+** gckOS_AtomIncrement
+**
+** Atomically increment the 32-bit integer value inside an atom.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gctPOINTER Atom
+** Pointer to the atom.
+**
+** OUTPUT:
+**
+** gctINT32_PTR Value
+** Pointer to a variable the receives the original value of the atom.
+*/
+gceSTATUS
+gckOS_AtomIncrement(
+ IN gckOS Os,
+ IN gctPOINTER Atom,
+ OUT gctINT32_PTR Value
+ );
+
+/*******************************************************************************
+**
+** gckOS_AtomDecrement
+**
+** Atomically decrement the 32-bit integer value inside an atom.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gctPOINTER Atom
+** Pointer to the atom.
+**
+** OUTPUT:
+**
+** gctINT32_PTR Value
+** Pointer to a variable the receives the original value of the atom.
+*/
+gceSTATUS
+gckOS_AtomDecrement(
+ IN gckOS Os,
+ IN gctPOINTER Atom,
+ OUT gctINT32_PTR Value
+ );
+
+/* Delay a number of milliseconds. */
+gceSTATUS
+gckOS_Delay(
+ IN gckOS Os,
+ IN gctUINT32 Delay
+ );
+
+/* Get time in milliseconds. */
+gceSTATUS
+gckOS_GetTicks(
+ OUT gctUINT32_PTR Time
+ );
+
+/* Compare time value. */
+gceSTATUS
+gckOS_TicksAfter(
+ IN gctUINT32 Time1,
+ IN gctUINT32 Time2,
+ OUT gctBOOL_PTR IsAfter
+ );
+
+/* Get time in microseconds. */
+gceSTATUS
+gckOS_GetTime(
+ OUT gctUINT64_PTR Time
+ );
+
+/* Memory barrier. */
+gceSTATUS
+gckOS_MemoryBarrier(
+ IN gckOS Os,
+ IN gctPOINTER Address
+ );
+
+/* Map user pointer. */
+gceSTATUS
+gckOS_MapUserPointer(
+ IN gckOS Os,
+ IN gctPOINTER Pointer,
+ IN gctSIZE_T Size,
+ OUT gctPOINTER * KernelPointer
+ );
+
+/* Unmap user pointer. */
+gceSTATUS
+gckOS_UnmapUserPointer(
+ IN gckOS Os,
+ IN gctPOINTER Pointer,
+ IN gctSIZE_T Size,
+ IN gctPOINTER KernelPointer
+ );
+
+/*******************************************************************************
+**
+** gckOS_QueryNeedCopy
+**
+** Query whether the memory can be accessed or mapped directly or it has to be
+** copied.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctUINT32 ProcessID
+** Process ID of the current process.
+**
+** OUTPUT:
+**
+** gctBOOL_PTR NeedCopy
+** Pointer to a boolean receiving gcvTRUE if the memory needs a copy or
+** gcvFALSE if the memory can be accessed or mapped dircetly.
+*/
+gceSTATUS
+gckOS_QueryNeedCopy(
+ IN gckOS Os,
+ IN gctUINT32 ProcessID,
+ OUT gctBOOL_PTR NeedCopy
+ );
+
+/*******************************************************************************
+**
+** gckOS_CopyFromUserData
+**
+** Copy data from user to kernel memory.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPOINTER KernelPointer
+** Pointer to kernel memory.
+**
+** gctPOINTER Pointer
+** Pointer to user memory.
+**
+** gctSIZE_T Size
+** Number of bytes to copy.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_CopyFromUserData(
+ IN gckOS Os,
+ IN gctPOINTER KernelPointer,
+ IN gctPOINTER Pointer,
+ IN gctSIZE_T Size
+ );
+
+/*******************************************************************************
+**
+** gckOS_CopyToUserData
+**
+** Copy data from kernel to user memory.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPOINTER KernelPointer
+** Pointer to kernel memory.
+**
+** gctPOINTER Pointer
+** Pointer to user memory.
+**
+** gctSIZE_T Size
+** Number of bytes to copy.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_CopyToUserData(
+ IN gckOS Os,
+ IN gctPOINTER KernelPointer,
+ IN gctPOINTER Pointer,
+ IN gctSIZE_T Size
+ );
+
+gceSTATUS
+gckOS_SuspendInterrupt(
+ IN gckOS Os
+ );
+
+gceSTATUS
+gckOS_SuspendInterruptEx(
+ IN gckOS Os,
+ IN gceCORE Core
+ );
+
+gceSTATUS
+gckOS_ResumeInterrupt(
+ IN gckOS Os
+ );
+
+gceSTATUS
+gckOS_ResumeInterruptEx(
+ IN gckOS Os,
+ IN gceCORE Core
+ );
+
+/* Get the base address for the physical memory. */
+gceSTATUS
+gckOS_GetBaseAddress(
+ IN gckOS Os,
+ OUT gctUINT32_PTR BaseAddress
+ );
+
+/* Perform a memory copy. */
+gceSTATUS
+gckOS_MemCopy(
+ IN gctPOINTER Destination,
+ IN gctCONST_POINTER Source,
+ IN gctSIZE_T Bytes
+ );
+
+/* Zero memory. */
+gceSTATUS
+gckOS_ZeroMemory(
+ IN gctPOINTER Memory,
+ IN gctSIZE_T Bytes
+ );
+
+/* Device I/O control to the kernel HAL layer. */
+gceSTATUS
+gckOS_DeviceControl(
+ IN gckOS Os,
+ IN gctBOOL FromUser,
+ IN gctUINT32 IoControlCode,
+ IN gctPOINTER InputBuffer,
+ IN gctSIZE_T InputBufferSize,
+ OUT gctPOINTER OutputBuffer,
+ IN gctSIZE_T OutputBufferSize
+ );
+
+/*******************************************************************************
+**
+** gckOS_GetProcessID
+**
+** Get current process ID.
+**
+** INPUT:
+**
+** Nothing.
+**
+** OUTPUT:
+**
+** gctUINT32_PTR ProcessID
+** Pointer to the variable that receives the process ID.
+*/
+gceSTATUS
+gckOS_GetProcessID(
+ OUT gctUINT32_PTR ProcessID
+ );
+
+gceSTATUS
+gckOS_GetCurrentProcessID(
+ OUT gctUINT32_PTR ProcessID
+ );
+
+/*******************************************************************************
+**
+** gckOS_GetThreadID
+**
+** Get current thread ID.
+**
+** INPUT:
+**
+** Nothing.
+**
+** OUTPUT:
+**
+** gctUINT32_PTR ThreadID
+** Pointer to the variable that receives the thread ID.
+*/
+gceSTATUS
+gckOS_GetThreadID(
+ OUT gctUINT32_PTR ThreadID
+ );
+
+/******************************************************************************\
+********************************** Signal Object *********************************
+\******************************************************************************/
+
+/* Create a signal. */
+gceSTATUS
+gckOS_CreateSignal(
+ IN gckOS Os,
+ IN gctBOOL ManualReset,
+ OUT gctSIGNAL * Signal
+ );
+
+/* Destroy a signal. */
+gceSTATUS
+gckOS_DestroySignal(
+ IN gckOS Os,
+ IN gctSIGNAL Signal
+ );
+
+/* Signal a signal. */
+gceSTATUS
+gckOS_Signal(
+ IN gckOS Os,
+ IN gctSIGNAL Signal,
+ IN gctBOOL State
+ );
+
+/* Wait for a signal. */
+gceSTATUS
+gckOS_WaitSignal(
+ IN gckOS Os,
+ IN gctSIGNAL Signal,
+ IN gctBOOL Interruptable,
+ IN gctUINT32 Wait
+ );
+
+#ifdef __QNXNTO__
+gceSTATUS
+gckOS_SignalPulse(
+ IN gckOS Os,
+ IN gctSIGNAL Signal
+ );
+
+gceSTATUS
+gckOS_SignalPending(
+ IN gckOS Os,
+ IN gctSIGNAL Signal
+ );
+#endif
+
+/* Map a user signal to the kernel space. */
+gceSTATUS
+gckOS_MapSignal(
+ IN gckOS Os,
+ IN gctSIGNAL Signal,
+ IN gctHANDLE Process,
+ OUT gctSIGNAL * MappedSignal
+ );
+
+/* Unmap a user signal */
+gceSTATUS
+gckOS_UnmapSignal(
+ IN gckOS Os,
+ IN gctSIGNAL Signal
+ );
+
+/* Map user memory. */
+gceSTATUS
+gckOS_MapUserMemory(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctPOINTER Memory,
+ IN gctUINT32 Physical,
+ IN gctSIZE_T Size,
+ OUT gctPOINTER * Info,
+ OUT gctUINT32_PTR Address
+ );
+
+/* Unmap user memory. */
+gceSTATUS
+gckOS_UnmapUserMemory(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctPOINTER Memory,
+ IN gctSIZE_T Size,
+ IN gctPOINTER Info,
+ IN gctUINT32 Address
+ );
+
+/* Get scatter-gather table from memory. */
+gceSTATUS
+gckOS_MemoryGetSGT(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Offset,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER *SGT
+ );
+
+/* Map a page range of memory to user space. */
+gceSTATUS
+gckOS_MemoryMmap(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T skipPages,
+ IN gctSIZE_T numPages,
+ INOUT gctPOINTER Vma
+ );
+
+/* Wrap a user memory to gctPHYS_ADDR. */
+gceSTATUS
+gckOS_WrapMemory(
+ IN gckOS Os,
+ IN gcsUSER_MEMORY_DESC_PTR Desc,
+ OUT gctSIZE_T *Bytes,
+ OUT gctPHYS_ADDR * Physical,
+ OUT gctBOOL *Contiguous
+ );
+
+gceSTATUS
+gckOS_GetPolicyID(
+ IN gckOS Os,
+ IN gceSURF_TYPE Type,
+ OUT gctUINT32_PTR PolicyID,
+ OUT gctUINT32_PTR AXIConfig
+ );
+
+/******************************************************************************\
+************************** Android Native Fence Sync ***************************
+\******************************************************************************/
+gceSTATUS
+gckOS_CreateSyncTimeline(
+ IN gckOS Os,
+ IN gceCORE Core,
+ OUT gctHANDLE * Timeline
+ );
+
+gceSTATUS
+gckOS_DestroySyncTimeline(
+ IN gckOS Os,
+ IN gctHANDLE Timeline
+ );
+
+gceSTATUS
+gckOS_CreateNativeFence(
+ IN gckOS Os,
+ IN gctHANDLE Timeline,
+ IN gctSIGNAL Signal,
+ OUT gctINT * FenceFD
+ );
+
+gceSTATUS
+gckOS_WaitNativeFence(
+ IN gckOS Os,
+ IN gctHANDLE Timeline,
+ IN gctINT FenceFD,
+ IN gctUINT32 Timeout
+ );
+
+#if !USE_NEW_LINUX_SIGNAL
+/* Create signal to be used in the user space. */
+gceSTATUS
+gckOS_CreateUserSignal(
+ IN gckOS Os,
+ IN gctBOOL ManualReset,
+ OUT gctINT * SignalID
+ );
+
+/* Destroy signal used in the user space. */
+gceSTATUS
+gckOS_DestroyUserSignal(
+ IN gckOS Os,
+ IN gctINT SignalID
+ );
+
+/* Wait for signal used in the user space. */
+gceSTATUS
+gckOS_WaitUserSignal(
+ IN gckOS Os,
+ IN gctINT SignalID,
+ IN gctUINT32 Wait
+ );
+
+/* Signal a signal used in the user space. */
+gceSTATUS
+gckOS_SignalUserSignal(
+ IN gckOS Os,
+ IN gctINT SignalID,
+ IN gctBOOL State
+ );
+#endif /* USE_NEW_LINUX_SIGNAL */
+
+/* Set a signal owned by a process. */
+#if defined(__QNXNTO__)
+gceSTATUS
+gckOS_UserSignal(
+ IN gckOS Os,
+ IN gctSIGNAL Signal,
+ IN gctINT Recvid,
+ IN gctINT Coid
+ );
+#else
+gceSTATUS
+gckOS_UserSignal(
+ IN gckOS Os,
+ IN gctSIGNAL Signal,
+ IN gctHANDLE Process
+ );
+#endif
+
+/******************************************************************************\
+** Cache Support
+*/
+
+gceSTATUS
+gckOS_CacheClean(
+ gckOS Os,
+ gctUINT32 ProcessID,
+ gctPHYS_ADDR Handle,
+ gctPHYS_ADDR_T Physical,
+ gctPOINTER Logical,
+ gctSIZE_T Bytes
+ );
+
+gceSTATUS
+gckOS_CacheFlush(
+ gckOS Os,
+ gctUINT32 ProcessID,
+ gctPHYS_ADDR Handle,
+ gctPHYS_ADDR_T Physical,
+ gctPOINTER Logical,
+ gctSIZE_T Bytes
+ );
+
+gceSTATUS
+gckOS_CacheInvalidate(
+ gckOS Os,
+ gctUINT32 ProcessID,
+ gctPHYS_ADDR Handle,
+ gctPHYS_ADDR_T Physical,
+ gctPOINTER Logical,
+ gctSIZE_T Bytes
+ );
+
+gceSTATUS
+gckOS_CPUPhysicalToGPUPhysical(
+ IN gckOS Os,
+ IN gctPHYS_ADDR_T CPUPhysical,
+ IN gctPHYS_ADDR_T * GPUPhysical
+ );
+
+gceSTATUS
+gckOS_GPUPhysicalToCPUPhysical(
+ IN gckOS Os,
+ IN gctUINT32 GPUPhysical,
+ IN gctPHYS_ADDR_T * CPUPhysical
+ );
+
+gceSTATUS
+gckOS_QueryOption(
+ IN gckOS Os,
+ IN gctCONST_STRING Option,
+ OUT gctUINT32 * Value
+ );
+
+/******************************************************************************\
+** Debug Support
+*/
+
+void
+gckOS_SetDebugLevel(
+ IN gctUINT32 Level
+ );
+
+void
+gckOS_SetDebugZone(
+ IN gctUINT32 Zone
+ );
+
+void
+gckOS_SetDebugLevelZone(
+ IN gctUINT32 Level,
+ IN gctUINT32 Zone
+ );
+
+void
+gckOS_SetDebugZones(
+ IN gctUINT32 Zones,
+ IN gctBOOL Enable
+ );
+
+void
+gckOS_SetDebugFile(
+ IN gctCONST_STRING FileName
+ );
+
+/*******************************************************************************
+** Broadcast interface.
+*/
+
+typedef enum _gceBROADCAST
+{
+ /* GPU might be idle. */
+ gcvBROADCAST_GPU_IDLE,
+
+ /* A commit is going to happen. */
+ gcvBROADCAST_GPU_COMMIT,
+
+ /* GPU seems to be stuck. */
+ gcvBROADCAST_GPU_STUCK,
+
+ /* First process gets attached. */
+ gcvBROADCAST_FIRST_PROCESS,
+
+ /* Last process gets detached. */
+ gcvBROADCAST_LAST_PROCESS,
+
+ /* AXI bus error. */
+ gcvBROADCAST_AXI_BUS_ERROR,
+
+ /* Out of memory. */
+ gcvBROADCAST_OUT_OF_MEMORY,
+}
+gceBROADCAST;
+
+gceSTATUS
+gckOS_Broadcast(
+ IN gckOS Os,
+ IN gckHARDWARE Hardware,
+ IN gceBROADCAST Reason
+ );
+
+gceSTATUS
+gckOS_BroadcastHurry(
+ IN gckOS Os,
+ IN gckHARDWARE Hardware,
+ IN gctUINT Urgency
+ );
+
+gceSTATUS
+gckOS_BroadcastCalibrateSpeed(
+ IN gckOS Os,
+ IN gckHARDWARE Hardware,
+ IN gctUINT Idle,
+ IN gctUINT Time
+ );
+
+/*******************************************************************************
+**
+** gckOS_SetGPUPower
+**
+** Set the power of the GPU on or off.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gceCORE Core
+** GPU whose power is set.
+**
+** gctBOOL Clock
+** gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock.
+**
+** gctBOOL Power
+** gcvTRUE to turn on the power, or gcvFALSE to turn off the power.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_SetGPUPower(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctBOOL Clock,
+ IN gctBOOL Power
+ );
+
+gceSTATUS
+gckOS_ResetGPU(
+ IN gckOS Os,
+ IN gceCORE Core
+ );
+
+gceSTATUS
+gckOS_PrepareGPUFrequency(
+ IN gckOS Os,
+ IN gceCORE Core
+ );
+
+gceSTATUS
+gckOS_FinishGPUFrequency(
+ IN gckOS Os,
+ IN gceCORE Core
+ );
+
+gceSTATUS
+gckOS_QueryGPUFrequency(
+ IN gckOS Os,
+ IN gceCORE Core,
+ OUT gctUINT32 * Frequency,
+ OUT gctUINT8 * Scale
+ );
+
+gceSTATUS
+gckOS_SetGPUFrequency(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctUINT8 Scale
+ );
+
+/*******************************************************************************
+** Semaphores.
+*/
+
+/* Create a new semaphore. */
+gceSTATUS
+gckOS_CreateSemaphore(
+ IN gckOS Os,
+ OUT gctPOINTER * Semaphore
+ );
+
+#if gcdENABLE_VG
+gceSTATUS
+gckOS_CreateSemaphoreVG(
+ IN gckOS Os,
+ OUT gctPOINTER * Semaphore
+ );
+#endif
+
+/* Delete a semahore. */
+gceSTATUS
+gckOS_DestroySemaphore(
+ IN gckOS Os,
+ IN gctPOINTER Semaphore
+ );
+
+/* Acquire a semahore. */
+gceSTATUS
+gckOS_AcquireSemaphore(
+ IN gckOS Os,
+ IN gctPOINTER Semaphore
+ );
+
+/* Try to acquire a semahore. */
+gceSTATUS
+gckOS_TryAcquireSemaphore(
+ IN gckOS Os,
+ IN gctPOINTER Semaphore
+ );
+
+/* Release a semahore. */
+gceSTATUS
+gckOS_ReleaseSemaphore(
+ IN gckOS Os,
+ IN gctPOINTER Semaphore
+ );
+
+/*******************************************************************************
+** Timer API.
+*/
+
+typedef void (*gctTIMERFUNCTION)(gctPOINTER);
+
+/* Create a timer. */
+gceSTATUS
+gckOS_CreateTimer(
+ IN gckOS Os,
+ IN gctTIMERFUNCTION Function,
+ IN gctPOINTER Data,
+ OUT gctPOINTER * Timer
+ );
+
+/* Destory a timer. */
+gceSTATUS
+gckOS_DestroyTimer(
+ IN gckOS Os,
+ IN gctPOINTER Timer
+ );
+
+/* Start a timer. */
+gceSTATUS
+gckOS_StartTimer(
+ IN gckOS Os,
+ IN gctPOINTER Timer,
+ IN gctUINT32 Delay
+ );
+
+/* Stop a timer. */
+gceSTATUS
+gckOS_StopTimer(
+ IN gckOS Os,
+ IN gctPOINTER Timer
+ );
+
+/******************************************************************************\
+********************************* gckHEAP Object ********************************
+\******************************************************************************/
+
+typedef struct _gckHEAP * gckHEAP;
+
+/* Construct a new gckHEAP object. */
+gceSTATUS
+gckHEAP_Construct(
+ IN gckOS Os,
+ IN gctSIZE_T AllocationSize,
+ OUT gckHEAP * Heap
+ );
+
+/* Destroy an gckHEAP object. */
+gceSTATUS
+gckHEAP_Destroy(
+ IN gckHEAP Heap
+ );
+
+/* Allocate memory. */
+gceSTATUS
+gckHEAP_Allocate(
+ IN gckHEAP Heap,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Node
+ );
+
+/* Free memory. */
+gceSTATUS
+gckHEAP_Free(
+ IN gckHEAP Heap,
+ IN gctPOINTER Node
+ );
+
+/* Profile the heap. */
+gceSTATUS
+gckHEAP_ProfileStart(
+ IN gckHEAP Heap
+ );
+
+gceSTATUS
+gckHEAP_ProfileEnd(
+ IN gckHEAP Heap,
+ IN gctCONST_STRING Title
+ );
+
+
+/******************************************************************************\
+******************************** gckVIDMEM Object ******************************
+\******************************************************************************/
+
+typedef struct _gckVIDMEM * gckVIDMEM;
+typedef struct _gckKERNEL * gckKERNEL;
+typedef struct _gckDB * gckDB;
+typedef struct _gckDVFS * gckDVFS;
+typedef struct _gcsASYNC_COMMAND * gckASYNC_COMMAND;
+typedef struct _gckMMU * gckMMU;
+typedef struct _gcsDEVICE * gckDEVICE;
+
+/* Construct a new gckVIDMEM object. */
+gceSTATUS
+gckVIDMEM_Construct(
+ IN gckOS Os,
+ IN gctUINT32 BaseAddress,
+ IN gctSIZE_T Bytes,
+ IN gctSIZE_T Threshold,
+ IN gctSIZE_T Banking,
+ OUT gckVIDMEM * Memory
+ );
+
+/* Destroy an gckVDIMEM object. */
+gceSTATUS
+gckVIDMEM_Destroy(
+ IN gckVIDMEM Memory
+ );
+
+/* Allocate linear memory. */
+gceSTATUS
+gckVIDMEM_AllocateLinear(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM Memory,
+ IN gctSIZE_T Bytes,
+ IN gctUINT32 Alignment,
+ IN gceSURF_TYPE Type,
+ IN gctBOOL Specified,
+ OUT gcuVIDMEM_NODE_PTR * Node
+ );
+
+/* Free memory. */
+gceSTATUS
+gckVIDMEM_Free(
+ IN gckKERNEL Kernel,
+ IN gcuVIDMEM_NODE_PTR Node
+ );
+
+/* Lock memory. */
+gceSTATUS
+gckVIDMEM_Lock(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM_NODE Node,
+ IN gctBOOL Cacheable,
+ OUT gctUINT32 * Address,
+ OUT gctUINT32 * Gid,
+ OUT gctUINT64 * PhysicalAddress
+ );
+
+/* Unlock memory. */
+gceSTATUS
+gckVIDMEM_Unlock(
+ IN gckKERNEL Kernel,
+ IN gckVIDMEM_NODE Node,
+ IN gceSURF_TYPE Type,
+ IN OUT gctBOOL * Asynchroneous
+ );
+
+/* Construct a gcuVIDMEM_NODE union for virtual memory. */
+gceSTATUS
+gckVIDMEM_ConstructVirtual(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 Flag,
+ IN gctSIZE_T Bytes,
+ OUT gcuVIDMEM_NODE_PTR * Node
+ );
+
+/* Destroy a gcuVIDMEM_NODE union for virtual memory. */
+gceSTATUS
+gckVIDMEM_DestroyVirtual(
+ IN gcuVIDMEM_NODE_PTR Node
+ );
+
+gceSTATUS
+gckVIDMEM_SetCommitStamp(
+ IN gckKERNEL Kernel,
+ IN gceENGINE Engine,
+ IN gctUINT32 Handle,
+ IN gctUINT64 CommitStamp
+ );
+
+gceSTATUS
+gckVIDMEM_GetCommitStamp(
+ IN gckKERNEL Kernel,
+ IN gceENGINE Engine,
+ IN gctUINT32 Handle,
+ OUT gctUINT64_PTR CommitStamp
+ );
+
+/******************************************************************************\
+******************************** gckKERNEL Object ******************************
+\******************************************************************************/
+
+struct _gcsHAL_INTERFACE;
+
+/* Notifications. */
+typedef enum _gceNOTIFY
+{
+ gcvNOTIFY_INTERRUPT,
+ gcvNOTIFY_COMMAND_QUEUE,
+}
+gceNOTIFY;
+
+/* Flush flags. */
+typedef enum _gceKERNEL_FLUSH
+{
+ gcvFLUSH_COLOR = 0x01,
+ gcvFLUSH_DEPTH = 0x02,
+ gcvFLUSH_TEXTURE = 0x04,
+ gcvFLUSH_2D = 0x08,
+ gcvFLUSH_L2 = 0x10,
+ gcvFLUSH_TILE_STATUS = 0x20,
+ gcvFLUSH_ICACHE = 0x40,
+ gcvFLUSH_TXDESC = 0x80,
+ gcvFLUSH_FENCE = 0x100,
+ gcvFLUSH_VERTEX = 0x200,
+ gcvFLUSH_TFBHEADER = 0x400,
+ gcvFLUSH_ALL = gcvFLUSH_COLOR
+ | gcvFLUSH_DEPTH
+ | gcvFLUSH_TEXTURE
+ | gcvFLUSH_2D
+ | gcvFLUSH_L2
+ | gcvFLUSH_TILE_STATUS
+ | gcvFLUSH_ICACHE
+ | gcvFLUSH_TXDESC
+ | gcvFLUSH_FENCE
+ | gcvFLUSH_VERTEX
+ | gcvFLUSH_TFBHEADER
+}
+gceKERNEL_FLUSH;
+
+/* Construct a new gckKERNEL object. */
+gceSTATUS
+gckKERNEL_Construct(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctUINT ChipID,
+ IN gctPOINTER Context,
+ IN gckDEVICE Device,
+ IN gckDB SharedDB,
+ OUT gckKERNEL * Kernel
+ );
+
+/* Destroy an gckKERNEL object. */
+gceSTATUS
+gckKERNEL_Destroy(
+ IN gckKERNEL Kernel
+ );
+
+/* Dispatch a user-level command. */
+gceSTATUS
+gckKERNEL_Dispatch(
+ IN gckKERNEL Kernel,
+ IN gckDEVICE Device,
+ IN gctBOOL FromUser,
+ IN OUT struct _gcsHAL_INTERFACE * Interface
+ );
+
+/* Query Database requirements. */
+gceSTATUS
+ gckKERNEL_QueryDatabase(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN OUT gcsHAL_INTERFACE * Interface
+ );
+
+/* Query the video memory. */
+gceSTATUS
+gckKERNEL_QueryVideoMemory(
+ IN gckKERNEL Kernel,
+ OUT struct _gcsHAL_INTERFACE * Interface
+ );
+
+/* Query used memory nodes of a specific pool. */
+gceSTATUS
+gckKERNEL_QueryVidMemPoolNodes(
+ gckKERNEL Kernel,
+ gcePOOL Pool,
+ gctUINT32 * TotalSize, /* sum of the sizes of the contiguous blocks (i.e. total memory used at current time) : to be filled by the called function */
+ gcsContiguousBlock * MemoryBlocks, /* previously allocated by the calling function : to be filled by the called function */
+ gctUINT32 NumMaxBlocks, /* provided by the calling function */
+ gctUINT32 * NumBlocks /* actual number of contiguous blocks : to be filled by the called function */
+ );
+
+/* Lookup the gckVIDMEM object for a pool. */
+gceSTATUS
+gckKERNEL_GetVideoMemoryPool(
+ IN gckKERNEL Kernel,
+ IN gcePOOL Pool,
+ OUT gckVIDMEM * VideoMemory
+ );
+
+gceSTATUS
+gckKERNEL_AllocateLinearMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN OUT gcePOOL * Pool,
+ IN gctSIZE_T Bytes,
+ IN gctUINT32 Alignment,
+ IN gceSURF_TYPE Type,
+ IN gctUINT32 Flag,
+ OUT gctUINT32 * Node
+ );
+
+gceSTATUS
+gckKERNEL_ReleaseVideoMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctUINT32 Handle
+ );
+
+gceSTATUS
+gckKERNEL_LockVideoMemory(
+ IN gckKERNEL Kernel,
+ IN gceCORE Core,
+ IN gctUINT32 ProcessID,
+ IN gctBOOL FromUser,
+ IN OUT gcsHAL_INTERFACE * Interface
+ );
+
+gceSTATUS
+gckKERNEL_UnlockVideoMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN OUT gcsHAL_INTERFACE * Interface
+ );
+
+/* Unlock video memory from gpu immediately w/o considering gpu cache flush. */
+gceSTATUS
+gckKERNEL_BottomHalfUnlockVideoMemory(
+ IN gckKERNEL Kernel,
+ IN gctUINT32 ProcessID,
+ IN gctUINT32 Node
+ );
+
+/* Map video memory. */
+gceSTATUS
+gckKERNEL_MapVideoMemory(
+ IN gckKERNEL Kernel,
+ IN gctBOOL InUserSpace,
+ IN gctUINT32 Address,
+#ifdef __QNXNTO__
+ IN gctUINT32 Pid,
+ IN gctUINT32 Bytes,
+#endif
+ OUT gctPOINTER * Logical
+ );
+
+/* Map video memory. */
+gceSTATUS
+gckKERNEL_MapVideoMemoryEx(
+ IN gckKERNEL Kernel,
+ IN gceCORE Core,
+ IN gctBOOL InUserSpace,
+ IN gctUINT32 Address,
+#ifdef __QNXNTO__
+ IN gctUINT32 Pid,
+ IN gctUINT32 Bytes,
+#endif
+ IN gcePOOL Pool,
+ OUT gctPOINTER * Logical
+ );
+
+#ifdef __QNXNTO__
+/* Unmap video memory. */
+gceSTATUS
+gckKERNEL_UnmapVideoMemory(
+ IN gckKERNEL Kernel,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Pid,
+ IN gctUINT32 Bytes
+ );
+#endif
+
+/* Map memory. */
+gceSTATUS
+gckKERNEL_MapMemory(
+ IN gckKERNEL Kernel,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Logical
+ );
+
+/* Unmap memory. */
+gceSTATUS
+gckKERNEL_UnmapMemory(
+ IN gckKERNEL Kernel,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical,
+ IN gctUINT32 ProcessID
+ );
+
+/* Notification of events. */
+gceSTATUS
+gckKERNEL_Notify(
+ IN gckKERNEL Kernel,
+ IN gceNOTIFY Notifcation,
+ IN gctBOOL Data
+ );
+
+gceSTATUS
+gckKERNEL_QuerySettings(
+ IN gckKERNEL Kernel,
+ OUT gcsKERNEL_SETTINGS * Settings
+ );
+
+/*******************************************************************************
+**
+** gckKERNEL_Recovery
+**
+** Try to recover the GPU from a fatal error.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckKERNEL_Recovery(
+ IN gckKERNEL Kernel
+ );
+
+/* Get access to the user data. */
+gceSTATUS
+gckKERNEL_OpenUserData(
+ IN gckKERNEL Kernel,
+ IN gctBOOL NeedCopy,
+ IN gctPOINTER StaticStorage,
+ IN gctPOINTER UserPointer,
+ IN gctSIZE_T Size,
+ OUT gctPOINTER * KernelPointer
+ );
+
+/* Release resources associated with the user data connection. */
+gceSTATUS
+gckKERNEL_CloseUserData(
+ IN gckKERNEL Kernel,
+ IN gctBOOL NeedCopy,
+ IN gctBOOL FlushData,
+ IN gctPOINTER UserPointer,
+ IN gctSIZE_T Size,
+ OUT gctPOINTER * KernelPointer
+ );
+
+gceSTATUS
+gckDVFS_Construct(
+ IN gckHARDWARE Hardware,
+ OUT gckDVFS * Frequency
+ );
+
+gceSTATUS
+gckDVFS_Destroy(
+ IN gckDVFS Dvfs
+ );
+
+gceSTATUS
+gckDVFS_Start(
+ IN gckDVFS Dvfs
+ );
+
+gceSTATUS
+gckDVFS_Stop(
+ IN gckDVFS Dvfs
+ );
+
+/******************************************************************************\
+******************************* gckHARDWARE Object *****************************
+\******************************************************************************/
+
+/* Construct a new gckHARDWARE object. */
+gceSTATUS
+gckHARDWARE_Construct(
+ IN gckOS Os,
+ IN gceCORE Core,
+ OUT gckHARDWARE * Hardware
+ );
+
+/* Destroy an gckHARDWARE object. */
+gceSTATUS
+gckHARDWARE_Destroy(
+ IN gckHARDWARE Hardware
+ );
+
+/* Get hardware type. */
+gceSTATUS
+gckHARDWARE_GetType(
+ IN gckHARDWARE Hardware,
+ OUT gceHARDWARE_TYPE * Type
+ );
+
+/* Query system memory requirements. */
+gceSTATUS
+gckHARDWARE_QuerySystemMemory(
+ IN gckHARDWARE Hardware,
+ OUT gctSIZE_T * SystemSize,
+ OUT gctUINT32 * SystemBaseAddress
+ );
+
+/* Build virtual address. */
+gceSTATUS
+gckHARDWARE_BuildVirtualAddress(
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 Index,
+ IN gctUINT32 Offset,
+ OUT gctUINT32 * Address
+ );
+
+/* Query command buffer requirements. */
+gceSTATUS
+gckHARDWARE_QueryCommandBuffer(
+ IN gckHARDWARE Hardware,
+ IN gceENGINE Engine,
+ OUT gctUINT32 * Alignment,
+ OUT gctUINT32 * ReservedHead,
+ OUT gctUINT32 * ReservedTail
+ );
+
+/* Add a WAIT/LINK pair in the command queue. */
+gceSTATUS
+gckHARDWARE_WaitLink(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Address,
+ IN gctUINT32 Offset,
+ IN OUT gctUINT32 * Bytes,
+ OUT gctUINT32 * WaitOffset,
+ OUT gctUINT32 * WaitBytes
+ );
+
+/* Kickstart the command processor. */
+gceSTATUS
+gckHARDWARE_Execute(
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 Address,
+ IN gctSIZE_T Bytes
+ );
+
+/* Add an END command in the command queue. */
+gceSTATUS
+gckHARDWARE_End(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Address,
+ IN OUT gctUINT32 * Bytes
+ );
+
+gceSTATUS
+gckHARDWARE_ChipEnable(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gceCORE_3D_MASK ChipEnable,
+ IN OUT gctSIZE_T * Bytes
+ );
+
+/* Add a NOP command in the command queue. */
+gceSTATUS
+gckHARDWARE_Nop(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN OUT gctSIZE_T * Bytes
+ );
+
+/* Add a PIPESELECT command in the command queue. */
+gceSTATUS
+gckHARDWARE_PipeSelect(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gcePIPE_SELECT Pipe,
+ IN OUT gctUINT32 * Bytes
+ );
+
+/* Add a LINK command in the command queue. */
+gceSTATUS
+gckHARDWARE_Link(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctUINT32 FetchAddress,
+ IN gctUINT32 FetchSize,
+ IN OUT gctUINT32 * Bytes,
+ OUT gctUINT32 * Low,
+ OUT gctUINT32 * High
+ );
+
+/* Add an EVENT command in the command queue. */
+gceSTATUS
+gckHARDWARE_Event(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctUINT8 Event,
+ IN gceKERNEL_WHERE FromWhere,
+ IN OUT gctUINT32 * Bytes
+ );
+
+/* Query the available memory. */
+gceSTATUS
+gckHARDWARE_QueryMemory(
+ IN gckHARDWARE Hardware,
+ OUT gctSIZE_T * InternalSize,
+ OUT gctUINT32 * InternalBaseAddress,
+ OUT gctUINT32 * InternalAlignment,
+ OUT gctSIZE_T * ExternalSize,
+ OUT gctUINT32 * ExternalBaseAddress,
+ OUT gctUINT32 * ExternalAlignment,
+ OUT gctUINT32 * HorizontalTileSize,
+ OUT gctUINT32 * VerticalTileSize
+ );
+
+/* Query the identity of the hardware. */
+gceSTATUS
+gckHARDWARE_QueryChipIdentity(
+ IN gckHARDWARE Hardware,
+ OUT gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity
+ );
+
+gceSTATUS
+gckHARDWARE_QueryChipOptions(
+ IN gckHARDWARE Hardware,
+ OUT gcsHAL_QUERY_CHIP_OPTIONS_PTR Options
+ );
+
+/* Query the shader uniforms support. */
+gceSTATUS
+gckHARDWARE_QueryShaderCaps(
+ IN gckHARDWARE Hardware,
+ OUT gctUINT * VertexUniforms,
+ OUT gctUINT * FragmentUniforms,
+ OUT gctBOOL * UnifiedUnforms
+ );
+
+/* Split a harwdare specific address into API stuff. */
+gceSTATUS
+gckHARDWARE_SplitMemory(
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 Address,
+ OUT gcePOOL * Pool,
+ OUT gctUINT32 * Offset
+ );
+
+/* Update command queue tail pointer. */
+gceSTATUS
+gckHARDWARE_UpdateQueueTail(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Offset
+ );
+
+/* Convert logical address to hardware specific address. */
+gceSTATUS
+gckHARDWARE_ConvertLogical(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctBOOL InUserSpace,
+ OUT gctUINT32 * Address
+ );
+
+/* Interrupt manager. */
+gceSTATUS
+gckHARDWARE_Interrupt(
+ IN gckHARDWARE Hardware,
+ IN gctBOOL InterruptValid
+ );
+
+/* Program MMU. */
+gceSTATUS
+gckHARDWARE_SetMMU(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical
+ );
+
+/* Flush the MMU. */
+gceSTATUS
+gckHARDWARE_FlushMMU(
+ IN gckHARDWARE Hardware
+ );
+
+gceSTATUS
+gckHARDWARE_FlushAsyncMMU(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN OUT gctUINT32 * Bytes
+ );
+
+/* Set the page table base address. */
+gceSTATUS
+gckHARDWARE_SetMMUv2(
+ IN gckHARDWARE Hardware,
+ IN gctBOOL Enable,
+ IN gctPOINTER MtlbAddress,
+ IN gceMMU_MODE Mode,
+ IN gctPOINTER SafeAddress,
+ IN gctBOOL FromPower
+ );
+
+#if gcdPROCESS_ADDRESS_SPACE
+/* Configure mmu configuration. */
+gceSTATUS
+gckHARDWARE_ConfigMMU(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctPOINTER MtlbLogical,
+ IN gctUINT32 Offset,
+ IN OUT gctSIZE_T * Bytes,
+ OUT gctSIZE_T * WaitLinkOffset,
+ OUT gctSIZE_T * WaitLinkBytes
+ );
+#endif
+
+/* Get idle register. */
+gceSTATUS
+gckHARDWARE_GetIdle(
+ IN gckHARDWARE Hardware,
+ IN gctBOOL Wait,
+ OUT gctUINT32 * Data
+ );
+
+/* Flush the caches. */
+gceSTATUS
+gckHARDWARE_Flush(
+ IN gckHARDWARE Hardware,
+ IN gceKERNEL_FLUSH Flush,
+ IN gctPOINTER Logical,
+ IN OUT gctUINT32 * Bytes
+ );
+
+/* Enable/disable fast clear. */
+gceSTATUS
+gckHARDWARE_SetFastClear(
+ IN gckHARDWARE Hardware,
+ IN gctINT Enable,
+ IN gctINT Compression
+ );
+
+gceSTATUS
+gckHARDWARE_ReadInterrupt(
+ IN gckHARDWARE Hardware,
+ OUT gctUINT32_PTR IDs
+ );
+
+/* Power management. */
+gceSTATUS
+gckHARDWARE_SetPowerManagementState(
+ IN gckHARDWARE Hardware,
+ IN gceCHIPPOWERSTATE State
+ );
+
+gceSTATUS
+gckHARDWARE_QueryPowerManagementState(
+ IN gckHARDWARE Hardware,
+ OUT gceCHIPPOWERSTATE* State
+ );
+
+gceSTATUS
+gckHARDWARE_SetPowerManagement(
+ IN gckHARDWARE Hardware,
+ IN gctBOOL PowerManagement
+ );
+
+gceSTATUS
+gckHARDWARE_SetGpuProfiler(
+ IN gckHARDWARE Hardware,
+ IN gctBOOL GpuProfiler
+ );
+
+#if gcdENABLE_FSCALE_VAL_ADJUST
+gceSTATUS
+gckHARDWARE_SetFscaleValue(
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 FscaleValue
+ );
+
+gceSTATUS
+gckHARDWARE_GetFscaleValue(
+ IN gckHARDWARE Hardware,
+ IN gctUINT * FscaleValue,
+ IN gctUINT * MinFscaleValue,
+ IN gctUINT * MaxFscaleValue
+ );
+
+gceSTATUS
+gckHARDWARE_SetMinFscaleValue(
+ IN gckHARDWARE Hardware,
+ IN gctUINT MinFscaleValue
+ );
+#endif
+
+#if gcdPOWEROFF_TIMEOUT
+gceSTATUS
+gckHARDWARE_SetPowerOffTimeout(
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 Timeout
+);
+
+gceSTATUS
+gckHARDWARE_QueryPowerOffTimeout(
+ IN gckHARDWARE Hardware,
+ OUT gctUINT32* Timeout
+);
+#endif
+
+/* Profile 2D Engine. */
+gceSTATUS
+gckHARDWARE_ProfileEngine2D(
+ IN gckHARDWARE Hardware,
+ OUT gcs2D_PROFILE_PTR Profile
+ );
+
+gceSTATUS
+gckHARDWARE_InitializeHardware(
+ IN gckHARDWARE Hardware
+ );
+
+gceSTATUS
+gckHARDWARE_Reset(
+ IN gckHARDWARE Hardware
+ );
+
+/* Check for Hardware features. */
+gceSTATUS
+gckHARDWARE_IsFeatureAvailable(
+ IN gckHARDWARE Hardware,
+ IN gceFEATURE Feature
+ );
+
+gceSTATUS
+gckHARDWARE_DumpMMUException(
+ IN gckHARDWARE Hardware
+ );
+
+gceSTATUS
+gckHARDWARE_DumpGPUState(
+ IN gckHARDWARE Hardware
+ );
+
+gceSTATUS
+gckHARDWARE_InitDVFS(
+ IN gckHARDWARE Hardware
+ );
+
+gceSTATUS
+gckHARDWARE_QueryLoad(
+ IN gckHARDWARE Hardware,
+ OUT gctUINT32 * Load
+ );
+
+gceSTATUS
+gckHARDWARE_SetDVFSPeroid(
+ IN gckHARDWARE Hardware,
+ IN gctUINT32 Frequency
+ );
+
+gceSTATUS
+gckHARDWARE_PrepareFunctions(
+ gckHARDWARE Hardware
+ );
+
+gceSTATUS
+gckHARDWARE_DestroyFunctions(
+ gckHARDWARE Hardware
+ );
+
+gceSTATUS
+gckHARDWARE_SetMMUStates(
+ IN gckHARDWARE Hardware,
+ IN gctPOINTER MtlbAddress,
+ IN gceMMU_MODE Mode,
+ IN gctPOINTER SafeAddress,
+ IN gctPOINTER Logical,
+ IN OUT gctUINT32 * Bytes
+ );
+
+gceSTATUS
+gckHARDWARE_QueryStateTimer(
+ IN gckHARDWARE Hardware,
+ OUT gctUINT64_PTR Start,
+ OUT gctUINT64_PTR End,
+ OUT gctUINT64_PTR On,
+ OUT gctUINT64_PTR Off,
+ OUT gctUINT64_PTR Idle,
+ OUT gctUINT64_PTR Suspend
+ );
+
+gceSTATUS
+gckHARDWARE_Fence(
+ IN gckHARDWARE Hardware,
+ IN gceENGINE Engine,
+ IN gctPOINTER Logical,
+ IN gctUINT32 FenceAddress,
+ IN gctUINT64 FenceData,
+ IN OUT gctUINT32 * Bytes
+ );
+
+#if !gcdENABLE_VG
+/******************************************************************************\
+***************************** gckINTERRUPT Object ******************************
+\******************************************************************************/
+
+typedef struct _gckINTERRUPT * gckINTERRUPT;
+
+typedef gceSTATUS (* gctINTERRUPT_HANDLER)(
+ IN gckKERNEL Kernel
+ );
+
+gceSTATUS
+gckINTERRUPT_Construct(
+ IN gckKERNEL Kernel,
+ OUT gckINTERRUPT * Interrupt
+ );
+
+gceSTATUS
+gckINTERRUPT_Destroy(
+ IN gckINTERRUPT Interrupt
+ );
+
+gceSTATUS
+gckINTERRUPT_SetHandler(
+ IN gckINTERRUPT Interrupt,
+ IN OUT gctINT32_PTR Id,
+ IN gctINTERRUPT_HANDLER Handler
+ );
+
+gceSTATUS
+gckINTERRUPT_Notify(
+ IN gckINTERRUPT Interrupt,
+ IN gctBOOL Valid
+ );
+#endif
+/******************************************************************************\
+******************************** gckEVENT Object *******************************
+\******************************************************************************/
+
+typedef struct _gckEVENT * gckEVENT;
+
+/* Construct a new gckEVENT object. */
+gceSTATUS
+gckEVENT_Construct(
+ IN gckKERNEL Kernel,
+ OUT gckEVENT * Event
+ );
+
+/* Destroy an gckEVENT object. */
+gceSTATUS
+gckEVENT_Destroy(
+ IN gckEVENT Event
+ );
+
+/* Reserve the next available hardware event. */
+gceSTATUS
+gckEVENT_GetEvent(
+ IN gckEVENT Event,
+ IN gctBOOL Wait,
+ OUT gctUINT8 * EventID,
+ IN gceKERNEL_WHERE Source
+ );
+
+/* Add a new event to the list of events. */
+gceSTATUS
+gckEVENT_AddList(
+ IN gckEVENT Event,
+ IN gcsHAL_INTERFACE_PTR Interface,
+ IN gceKERNEL_WHERE FromWhere,
+ IN gctBOOL AllocateAllowed,
+ IN gctBOOL FromKernel
+ );
+
+/* Schedule a FreeNonPagedMemory event. */
+gceSTATUS
+gckEVENT_FreeNonPagedMemory(
+ IN gckEVENT Event,
+ IN gctSIZE_T Bytes,
+ IN gctPHYS_ADDR Physical,
+ IN gctPOINTER Logical,
+ IN gceKERNEL_WHERE FromWhere
+ );
+
+/* Schedule a FreeContiguousMemory event. */
+gceSTATUS
+gckEVENT_FreeContiguousMemory(
+ IN gckEVENT Event,
+ IN gctSIZE_T Bytes,
+ IN gctPHYS_ADDR Physical,
+ IN gctPOINTER Logical,
+ IN gceKERNEL_WHERE FromWhere
+ );
+
+/* Schedule a FreeVideoMemory event. */
+gceSTATUS
+gckEVENT_FreeVideoMemory(
+ IN gckEVENT Event,
+ IN gcuVIDMEM_NODE_PTR VideoMemory,
+ IN gceKERNEL_WHERE FromWhere
+ );
+
+/* Schedule a signal event. */
+gceSTATUS
+gckEVENT_Signal(
+ IN gckEVENT Event,
+ IN gctSIGNAL Signal,
+ IN gceKERNEL_WHERE FromWhere
+ );
+
+/* Schedule an Unlock event. */
+gceSTATUS
+gckEVENT_Unlock(
+ IN gckEVENT Event,
+ IN gceKERNEL_WHERE FromWhere,
+ IN gctPOINTER Node,
+ IN gceSURF_TYPE Type
+ );
+
+/* Schedule a FreeVirtualCommandBuffer event. */
+gceSTATUS
+gckEVENT_DestroyVirtualCommandBuffer(
+ IN gckEVENT Event,
+ IN gctSIZE_T Bytes,
+ IN gctPHYS_ADDR Physical,
+ IN gctPOINTER Logical,
+ IN gceKERNEL_WHERE FromWhere
+ );
+
+gceSTATUS
+gckEVENT_Submit(
+ IN gckEVENT Event,
+ IN gctBOOL Wait,
+ IN gctBOOL FromPower
+ );
+
+gceSTATUS
+gckEVENT_Commit(
+ IN gckEVENT Event,
+ IN gcsQUEUE_PTR Queue,
+ IN gctBOOL Forced
+ );
+
+/* Event callback routine. */
+gceSTATUS
+gckEVENT_Notify(
+ IN gckEVENT Event,
+ IN gctUINT32 IDs
+ );
+
+/* Event callback routine. */
+gceSTATUS
+gckEVENT_Interrupt(
+ IN gckEVENT Event,
+ IN gctUINT32 IDs
+ );
+
+gceSTATUS
+gckEVENT_Dump(
+ IN gckEVENT Event
+ );
+/******************************************************************************\
+******************************* gckCOMMAND Object ******************************
+\******************************************************************************/
+
+typedef struct _gckCOMMAND * gckCOMMAND;
+
+/* Construct a new gckCOMMAND object. */
+gceSTATUS
+gckCOMMAND_Construct(
+ IN gckKERNEL Kernel,
+ OUT gckCOMMAND * Command
+ );
+
+/* Destroy an gckCOMMAND object. */
+gceSTATUS
+gckCOMMAND_Destroy(
+ IN gckCOMMAND Command
+ );
+
+/* Acquire command queue synchronization objects. */
+gceSTATUS
+gckCOMMAND_EnterCommit(
+ IN gckCOMMAND Command,
+ IN gctBOOL FromPower
+ );
+
+/* Release command queue synchronization objects. */
+gceSTATUS
+gckCOMMAND_ExitCommit(
+ IN gckCOMMAND Command,
+ IN gctBOOL FromPower
+ );
+
+/* Start the command queue. */
+gceSTATUS
+gckCOMMAND_Start(
+ IN gckCOMMAND Command
+ );
+
+/* Stop the command queue. */
+gceSTATUS
+gckCOMMAND_Stop(
+ IN gckCOMMAND Command
+ );
+
+gceSTATUS
+gckCOMMAND_Commit(
+ IN gckCOMMAND Command,
+ IN gckCONTEXT Context,
+ IN gcoCMDBUF CommandBuffer,
+ IN gcsSTATE_DELTA_PTR StateDelta,
+ IN gctUINT32 ProcessID,
+ IN gctBOOL Shared,
+ IN gctUINT32 Index,
+ OUT gctUINT64_PTR CommitStamp,
+ OUT gctBOOL_PTR ContextSwitched
+ );
+
+/* Reserve space in the command buffer. */
+gceSTATUS
+gckCOMMAND_Reserve(
+ IN gckCOMMAND Command,
+ IN gctUINT32 RequestedBytes,
+ OUT gctPOINTER * Buffer,
+ OUT gctUINT32 * BufferSize
+ );
+
+/* Execute reserved space in the command buffer. */
+gceSTATUS
+gckCOMMAND_Execute(
+ IN gckCOMMAND Command,
+ IN gctUINT32 RequstedBytes
+ );
+
+/* Stall the command queue. */
+gceSTATUS
+gckCOMMAND_Stall(
+ IN gckCOMMAND Command,
+ IN gctBOOL FromPower
+ );
+
+/* Attach user process. */
+gceSTATUS
+gckCOMMAND_Attach(
+ IN gckCOMMAND Command,
+ OUT gckCONTEXT * Context,
+ OUT gctSIZE_T * MaxState,
+ OUT gctUINT32 * NumStates,
+ IN gctUINT32 ProcessID
+ );
+
+/* Detach user process. */
+gceSTATUS
+gckCOMMAND_Detach(
+ IN gckCOMMAND Command,
+ IN gckCONTEXT Context
+ );
+
+/* Dump command buffer being executed by GPU. */
+gceSTATUS
+gckCOMMAND_DumpExecutingBuffer(
+ IN gckCOMMAND Command
+ );
+
+/* Whether a kernel command buffer address. */
+gceSTATUS
+gckCOMMAND_AddressInKernelCommandBuffer(
+ IN gckCOMMAND Command,
+ IN gctUINT32 Address,
+ OUT gctPOINTER * Pointer
+ );
+
+/******************************************************************************\
+********************************* gckMMU Object ********************************
+\******************************************************************************/
+
+/* Construct a new gckMMU object. */
+gceSTATUS
+gckMMU_Construct(
+ IN gckKERNEL Kernel,
+ IN gctSIZE_T MmuSize,
+ OUT gckMMU * Mmu
+ );
+
+/* Destroy an gckMMU object. */
+gceSTATUS
+gckMMU_Destroy(
+ IN gckMMU Mmu
+ );
+
+/* Allocate pages inside the MMU. */
+gceSTATUS
+gckMMU_AllocatePages(
+ IN gckMMU Mmu,
+ IN gctSIZE_T PageCount,
+ OUT gctPOINTER * PageTable,
+ OUT gctUINT32 * Address
+ );
+
+gceSTATUS
+gckMMU_AllocatePagesEx(
+ IN gckMMU Mmu,
+ IN gctSIZE_T PageCount,
+ IN gceSURF_TYPE Type,
+ IN gctBOOL Secure,
+ OUT gctPOINTER * PageTable,
+ OUT gctUINT32 * Address
+ );
+
+/* Remove a page table from the MMU. */
+gceSTATUS
+gckMMU_FreePages(
+ IN gckMMU Mmu,
+ IN gctBOOL Secure,
+ IN gctUINT32 Address,
+ IN gctPOINTER PageTable,
+ IN gctSIZE_T PageCount
+ );
+
+/* Set the MMU page with info. */
+gceSTATUS
+gckMMU_SetPage(
+ IN gckMMU Mmu,
+ IN gctPHYS_ADDR_T PageAddress,
+ IN gctBOOL Writable,
+ IN gctUINT32 *PageEntry
+ );
+
+gceSTATUS
+gckMMU_Flush(
+ IN gckMMU Mmu,
+ IN gceSURF_TYPE Type
+ );
+
+gceSTATUS
+gckMMU_DumpPageTableEntry(
+ IN gckMMU Mmu,
+ IN gctUINT32 Address
+ );
+
+gceSTATUS
+gckMMU_FillFlatMapping(
+ IN gckMMU Mmu,
+ IN gctUINT32 PhysBase,
+ IN gctSIZE_T Size
+ );
+
+gceSTATUS
+gckMMU_IsFlatMapped(
+ IN gckMMU Mmu,
+ OUT gctUINT32 Physical,
+ OUT gctBOOL *In
+ );
+
+
+gceSTATUS
+gckHARDWARE_QueryContextProfile(
+ IN gckHARDWARE Hardware,
+ IN gctBOOL Reset,
+ IN gckCONTEXT Context,
+ OUT gcsPROFILER_COUNTERS_PART1 * Counters_part1,
+ OUT gcsPROFILER_COUNTERS_PART2 * Counters_part2
+ );
+
+gceSTATUS
+gckHARDWARE_UpdateContextProfile(
+ IN gckHARDWARE Hardware,
+ IN gckCONTEXT Context
+ );
+
+gceSTATUS
+gckHARDWARE_InitProfiler(
+ IN gckHARDWARE Hardware
+ );
+
+gceSTATUS
+gckOS_DetectProcessByName(
+ IN gctCONST_POINTER Name
+ );
+
+void
+gckOS_DumpParam(
+ void
+ );
+
+#ifdef __cplusplus
+}
+#endif
+
+#if gcdENABLE_VG
+#include "gc_hal_vg.h"
+#endif
+
+#endif /* __gc_hal_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_base.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_base.h
new file mode 100644
index 000000000000..3c4897c0cd77
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_base.h
@@ -0,0 +1,6003 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_base_h_
+#define __gc_hal_base_h_
+
+#include "gc_hal_enum.h"
+#include "gc_hal_types.h"
+#include "gc_hal_dump.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+****************************** Object Declarations *****************************
+\******************************************************************************/
+
+typedef struct _gckOS * gckOS;
+typedef struct _gcoHAL * gcoHAL;
+typedef struct _gcoOS * gcoOS;
+typedef struct _gco2D * gco2D;
+typedef struct gcsATOM * gcsATOM_PTR;
+
+typedef struct _gco3D * gco3D;
+typedef struct _gcoCL * gcoCL;
+typedef struct _gcsFAST_FLUSH * gcsFAST_FLUSH_PTR;
+
+typedef struct _gcoSURF * gcoSURF;
+typedef struct _gcsSURF_NODE * gcsSURF_NODE_PTR;
+typedef struct _gcsSURF_FORMAT_INFO * gcsSURF_FORMAT_INFO_PTR;
+typedef struct _gcsPOINT * gcsPOINT_PTR;
+typedef struct _gcsSIZE * gcsSIZE_PTR;
+typedef struct _gcsRECT * gcsRECT_PTR;
+typedef struct _gcsBOUNDARY * gcsBOUNDARY_PTR;
+typedef struct _gcoDUMP * gcoDUMP;
+typedef struct _gcoHARDWARE * gcoHARDWARE;
+typedef union _gcuVIDMEM_NODE * gcuVIDMEM_NODE_PTR;
+typedef struct _gcsVIDMEM_NODE * gckVIDMEM_NODE;
+
+#if gcdENABLE_VG
+typedef struct _gcoVG * gcoVG;
+typedef struct _gcsCOMPLETION_SIGNAL * gcsCOMPLETION_SIGNAL_PTR;
+typedef struct _gcsCONTEXT_MAP * gcsCONTEXT_MAP_PTR;
+#else
+typedef void * gcoVG;
+#endif
+
+typedef struct _gcoFENCE * gcoFENCE;
+typedef struct _gcsSYNC_CONTEXT * gcsSYNC_CONTEXT_PTR;
+
+typedef enum {
+ gcvFENCE_TYPE_READ = 0x1,
+ gcvFENCE_TYPE_WRITE = 0x2,
+ gcvFENCE_TYPE_ALL = gcvFENCE_TYPE_READ | gcvFENCE_TYPE_WRITE,
+ gcvFNECE_TYPE_INVALID = 0x10000,
+}
+gceFENCE_TYPE;
+
+typedef struct _gcsUSER_MEMORY_DESC * gcsUSER_MEMORY_DESC_PTR;
+
+
+/******************************************************************************\
+********************* Share obj lock/unlock macros. ****************************
+\******************************************************************************/
+#define gcmLOCK_SHARE_OBJ(Obj) \
+{ \
+ if(Obj->sharedLock != gcvNULL)\
+ {\
+ (gcoOS_AcquireMutex( \
+ gcvNULL, Obj->sharedLock, gcvINFINITE));\
+ }\
+}
+
+
+#define gcmUNLOCK_SHARE_OBJ(Obj)\
+{\
+ if(Obj->sharedLock != gcvNULL)\
+ {\
+ (gcoOS_ReleaseMutex(gcvNULL, Obj->sharedLock));\
+ }\
+}
+
+typedef struct _gcsSystemInfo
+{
+ /* memory latency number for SH data fetch, in SH cycle*/
+ gctUINT32 memoryLatencySH;
+}
+gcsSystemInfo;
+
+
+#if gcdENABLE_3D
+#if gcdSYNC
+#define gcPLS_INITIALIZER \
+{ \
+ gcvNULL, /* gcoOS object. */ \
+ gcvNULL, /* gcoHAL object. */ \
+ 0, /* internalSize */ \
+ gcvNULL, /* internalPhysical */ \
+ gcvNULL, /* internalLogical */ \
+ 0, /* externalSize */ \
+ gcvNULL, /* externalPhysical */ \
+ gcvNULL, /* externalLogical */ \
+ 0, /* contiguousSize */ \
+ gcvNULL, /* contiguousPhysical */ \
+ gcvNULL, /* contiguousLogical */ \
+ gcvNULL, /* eglDisplayInfo */ \
+ gcvNULL, /* eglSurfaceInfo */ \
+ gcvSURF_A8R8G8B8,/* eglConfigFormat */ \
+ gcvNULL, /* reference */ \
+ 0, /* processID */ \
+ 0, /* threadID */ \
+ gcvFALSE, /* exiting */ \
+ gcvFALSE, /* Special flag for NP2 texture. */ \
+ gcvNULL, /* destructor */ \
+ gcvNULL, /* accessLock */ \
+ gcvNULL, /* GL FE compiler lock*/ \
+ gcvNULL, /* CL FE compiler lock*/ \
+ gcvPATCH_NOTINIT,/* global patchID */ \
+ gcvNULL, /* global fenceID*/ \
+}
+#else
+#define gcPLS_INITIALIZER \
+{ \
+ gcvNULL, /* gcoOS object. */ \
+ gcvNULL, /* gcoHAL object. */ \
+ 0, /* internalSize */ \
+ gcvNULL, /* internalPhysical */ \
+ gcvNULL, /* internalLogical */ \
+ 0, /* externalSize */ \
+ gcvNULL, /* externalPhysical */ \
+ gcvNULL, /* externalLogical */ \
+ 0, /* contiguousSize */ \
+ gcvNULL, /* contiguousPhysical */ \
+ gcvNULL, /* contiguousLogical */ \
+ gcvNULL, /* eglDisplayInfo */ \
+ gcvNULL, /* eglSurfaceInfo */ \
+ gcvSURF_A8R8G8B8,/* eglConfigFormat */ \
+ gcvNULL, /* reference */ \
+ 0, /* processID */ \
+ 0, /* threadID */ \
+ gcvFALSE, /* exiting */ \
+ gcvFALSE, /* Special flag for NP2 texture. */ \
+ gcvNULL, /* destructor */ \
+ gcvNULL, /* accessLock */ \
+ gcvNULL, /* GL FE compiler lock*/ \
+ gcvNULL, /* CL FE compiler lock*/ \
+ gcvPATCH_NOTINIT,/* global patchID */ \
+}
+#endif
+#else
+#define gcPLS_INITIALIZER \
+{ \
+ gcvNULL, /* gcoOS object. */ \
+ gcvNULL, /* gcoHAL object. */ \
+ 0, /* internalSize */ \
+ gcvNULL, /* internalPhysical */ \
+ gcvNULL, /* internalLogical */ \
+ 0, /* externalSize */ \
+ gcvNULL, /* externalPhysical */ \
+ gcvNULL, /* externalLogical */ \
+ 0, /* contiguousSize */ \
+ gcvNULL, /* contiguousPhysical */ \
+ gcvNULL, /* contiguousLogical */ \
+ gcvNULL, /* eglDisplayInfo */ \
+ gcvNULL, /* eglSurfaceInfo */ \
+ gcvSURF_A8R8G8B8,/* eglConfigFormat */ \
+ gcvNULL, /* reference */ \
+ 0, /* processID */ \
+ 0, /* threadID */ \
+ gcvFALSE, /* exiting */ \
+ gcvFALSE, /* Special flag for NP2 texture. */ \
+ gcvNULL, /* destructor */ \
+ gcvNULL, /* accessLock */ \
+}
+#endif
+
+/******************************************************************************\
+******************************* Thread local storage *************************
+\******************************************************************************/
+
+typedef struct _gcsDRIVER_TLS * gcsDRIVER_TLS_PTR;
+
+typedef struct _gcsDRIVER_TLS
+{
+ void (* destructor)(gcsDRIVER_TLS_PTR Tls);
+}
+gcsDRIVER_TLS;
+
+typedef enum _gceTLS_KEY
+{
+ gcvTLS_KEY_EGL,
+ gcvTLS_KEY_OPENGL_ES,
+ gcvTLS_KEY_OPENVG,
+ gcvTLS_KEY_OPENGL,
+ gcvTLS_KEY_OPENCL,
+ gcvTLS_KEY_OPENVX,
+
+ gcvTLS_KEY_COUNT
+}
+gceTLS_KEY;
+
+typedef struct _gcsTLS * gcsTLS_PTR;
+
+typedef struct _gcsTLS
+{
+ gceHARDWARE_TYPE currentType;
+
+ /* To which core device control is called,
+ * it is index in a hardware type.
+ */
+ gctUINT32 currentCoreIndex;
+
+ /* Current 3D hardwre of this thread */
+ gcoHARDWARE currentHardware;
+
+ /* Default 3D hardware of this thread */
+ gcoHARDWARE defaultHardware;
+
+ /* Only for separated 3D and 2D */
+ gcoHARDWARE hardware2D;
+#if gcdENABLE_VG
+ gcoVGHARDWARE vg;
+ gcoVG engineVG;
+#endif /* gcdENABLE_VG */
+#if gcdENABLE_3D
+ gco3D engine3D;
+#endif
+#if gcdENABLE_2D
+ gco2D engine2D;
+#if gcdDUMP_2D
+ gctUINT32 newDump2DFlag;
+#endif
+#endif
+
+ gctBOOL copied;
+
+ /* libGAL.so handle */
+ gctHANDLE handle;
+
+ /* If true, do not releas 2d engine and hardware in hal layer */
+ gctBOOL release2DUpper;
+
+ /* Driver tls. */
+ gcsDRIVER_TLS_PTR driverTLS[gcvTLS_KEY_COUNT];
+}
+gcsTLS;
+
+/******************************************************************************\
+********************************* Enumerations *********************************
+\******************************************************************************/
+
+typedef enum _gcePLS_VALUE
+{
+ gcePLS_VALUE_EGL_DISPLAY_INFO,
+ gcePLS_VALUE_EGL_CONFIG_FORMAT_INFO,
+ gcePLS_VALUE_EGL_DESTRUCTOR_INFO,
+}
+gcePLS_VALUE;
+
+/* Video memory pool type. */
+typedef enum _gcePOOL
+{
+ gcvPOOL_UNKNOWN = 0,
+ gcvPOOL_DEFAULT,
+ gcvPOOL_LOCAL,
+ gcvPOOL_LOCAL_INTERNAL,
+ gcvPOOL_LOCAL_EXTERNAL,
+ gcvPOOL_UNIFIED,
+ gcvPOOL_SYSTEM,
+ gcvPOOL_VIRTUAL,
+ gcvPOOL_USER,
+ gcvPOOL_CONTIGUOUS,
+
+ gcvPOOL_NUMBER_OF_POOLS
+}
+gcePOOL;
+
+#if gcdENABLE_3D
+/* Blending functions. */
+typedef enum _gceBLEND_FUNCTION
+{
+ gcvBLEND_ZERO,
+ gcvBLEND_ONE,
+ gcvBLEND_SOURCE_COLOR,
+ gcvBLEND_INV_SOURCE_COLOR,
+ gcvBLEND_SOURCE_ALPHA,
+ gcvBLEND_INV_SOURCE_ALPHA,
+ gcvBLEND_TARGET_COLOR,
+ gcvBLEND_INV_TARGET_COLOR,
+ gcvBLEND_TARGET_ALPHA,
+ gcvBLEND_INV_TARGET_ALPHA,
+ gcvBLEND_SOURCE_ALPHA_SATURATE,
+ gcvBLEND_CONST_COLOR,
+ gcvBLEND_INV_CONST_COLOR,
+ gcvBLEND_CONST_ALPHA,
+ gcvBLEND_INV_CONST_ALPHA,
+}
+gceBLEND_FUNCTION;
+
+/* Blending modes. */
+typedef enum _gceBLEND_MODE
+{
+ gcvBLEND_ADD = 0,
+ gcvBLEND_SUBTRACT,
+ gcvBLEND_REVERSE_SUBTRACT,
+ gcvBLEND_MIN,
+ gcvBLEND_MAX,
+ gcvBLEND_MULTIPLY,
+ gcvBLEND_SCREEN,
+ gcvBLEND_OVERLAY,
+ gcvBLEND_DARKEN,
+ gcvBLEND_LIGHTEN,
+ gcvBLEND_COLORDODGE,
+ gcvBLEND_COLORBURN,
+ gcvBLEND_HARDLIGHT,
+ gcvBLEND_SOFTLIGHT,
+ gcvBLEND_DIFFERENCE,
+ gcvBLEND_EXCLUSION,
+ gcvBLEND_HSL_HUE,
+ gcvBLEND_HSL_SATURATION,
+ gcvBLEND_HSL_COLOR,
+ gcvBLEND_HSL_LUMINOSITY,
+
+ gcvBLEND_TOTAL
+}
+gceBLEND_MODE;
+
+/* Depth modes. */
+typedef enum _gceDEPTH_MODE
+{
+ gcvDEPTH_NONE,
+ gcvDEPTH_Z,
+ gcvDEPTH_W,
+}
+gceDEPTH_MODE;
+#endif /* gcdENABLE_3D */
+
+
+/* API flags. */
+typedef enum _gceAPI
+{
+ gcvAPI_D3D = 1,
+ gcvAPI_OPENGL_ES11,
+ gcvAPI_OPENGL_ES20,
+ gcvAPI_OPENGL_ES30,
+ gcvAPI_OPENGL_ES31,
+ gcvAPI_OPENGL_ES32,
+ gcvAPI_OPENGL,
+ gcvAPI_OPENVG,
+ gcvAPI_OPENCL,
+ gcvAPI_OPENVK,
+}
+gceAPI;
+
+typedef enum _gceWHERE
+{
+ gcvWHERE_COMMAND_PREFETCH = 0,
+ gcvWHERE_COMMAND,
+ gcvWHERE_RASTER,
+ gcvWHERE_PIXEL,
+ gcvWHERE_BLT,
+}
+gceWHERE;
+
+typedef enum _gceHOW
+{
+ gcvHOW_SEMAPHORE = 0x1,
+ gcvHOW_STALL = 0x2,
+ gcvHOW_SEMAPHORE_STALL = 0x3,
+}
+gceHOW;
+
+typedef enum _gceSignalHandlerType
+{
+ gcvHANDLE_SIGFPE_WHEN_SIGNAL_CODE_IS_0 = 0x1,
+}
+gceSignalHandlerType;
+
+typedef struct _gcsSURF_VIEW
+{
+ gcoSURF surf;
+ gctUINT firstSlice;
+ gctUINT numSlices;
+}gcsSURF_VIEW;
+
+/* gcsHAL_Limits*/
+typedef struct _gcsHAL_LIMITS
+{
+ /* chip info */
+ gceCHIPMODEL chipModel;
+ gctUINT32 chipRevision;
+ gctUINT32 featureCount;
+ gctUINT32 *chipFeatures;
+
+ /* target caps */
+ gctUINT32 maxWidth;
+ gctUINT32 maxHeight;
+ gctUINT32 multiTargetCount;
+ gctUINT32 maxSamples;
+
+}gcsHAL_LIMITS;
+
+#define gcdEXTERNAL_MEMORY_NAME_MAX 32
+#define gcdEXTERNAL_MEMORY_DATA_MAX 8
+
+typedef struct _gcsEXTERNAL_MEMORY_INFO
+{
+ /* Name of allocator used to attach this memory. */
+ gctCHAR allocatorName[gcdEXTERNAL_MEMORY_NAME_MAX];
+
+ /* User defined data which will be passed to allocator. */
+ gctUINT32 userData[gcdEXTERNAL_MEMORY_DATA_MAX];
+}
+gcsEXTERNAL_MEMORY_INFO;
+
+/******************************************************************************\
+********************************* gcoHAL Object *********************************
+\******************************************************************************/
+
+/* Construct a new gcoHAL object. */
+gceSTATUS
+gcoHAL_ConstructEx(
+ IN gctPOINTER Context,
+ IN gcoOS Os,
+ OUT gcoHAL * Hal
+ );
+
+/* Destroy an gcoHAL object. */
+gceSTATUS
+gcoHAL_DestroyEx(
+ IN gcoHAL Hal
+ );
+
+/* Empty function for compatibility. */
+gceSTATUS
+gcoHAL_Construct(
+ IN gctPOINTER Context,
+ IN gcoOS Os,
+ OUT gcoHAL * Hal
+ );
+
+/* Empty function for compatibility. */
+gceSTATUS
+gcoHAL_Destroy(
+ IN gcoHAL Hal
+ );
+
+/* Get HAL options */
+gceSTATUS
+gcoHAL_GetOption(
+ IN gcoHAL Hal,
+ IN gceOPTION Option
+ );
+
+gceSTATUS
+gcoHAL_FrameInfoOps(
+ IN gcoHAL Hal,
+ IN gceFRAMEINFO FrameInfo,
+ IN gceFRAMEINFO_OP Op,
+ IN OUT gctUINT * Val
+ );
+
+/* Set HAL options */
+gceSTATUS
+gcoHAL_SetOption(
+ IN gcoHAL Hal,
+ IN gceOPTION Option,
+ IN gctBOOL Value
+ );
+
+gceSTATUS
+gcoHAL_GetHardware(
+ IN gcoHAL Hal,
+ OUT gcoHARDWARE* Hw
+ );
+
+#if gcdENABLE_2D
+/* Get pointer to gco2D object. */
+gceSTATUS
+gcoHAL_Get2DEngine(
+ IN gcoHAL Hal,
+ OUT gco2D * Engine
+ );
+#endif
+
+#if gcdENABLE_3D
+gceSTATUS
+gcoHAL_GetSpecialHintData(
+ IN gcoHAL Hal,
+ OUT gctINT * Hint
+ );
+/*
+** Deprecated(Don't use it), keep it here for external library(libgcu.so)
+*/
+gceSTATUS
+gcoHAL_Get3DEngine(
+ IN gcoHAL Hal,
+ OUT gco3D * Engine
+ );
+#endif /* gcdENABLE_3D */
+
+
+gceSTATUS
+gcoHAL_GetProductName(
+ IN gcoHAL Hal,
+ OUT gctSTRING *ProductName
+ );
+
+gceSTATUS
+gcoHAL_SetFscaleValue(
+ IN gctUINT FscaleValue
+ );
+
+gceSTATUS
+gcoHAL_GetFscaleValue(
+ OUT gctUINT * FscaleValue,
+ OUT gctUINT * MinFscaleValue,
+ OUT gctUINT * MaxFscaleValue
+ );
+
+gceSTATUS
+gcoHAL_SetBltNP2Texture(
+ gctBOOL enable
+ );
+
+gceSTATUS
+gcoHAL_ExportVideoMemory(
+ IN gctUINT32 Handle,
+ IN gctUINT32 Flags,
+ OUT gctINT32 * FD
+ );
+
+gceSTATUS
+gcoHAL_NameVideoMemory(
+ IN gctUINT32 Handle,
+ OUT gctUINT32 * Name
+ );
+
+gceSTATUS
+gcoHAL_ImportVideoMemory(
+ IN gctUINT32 Name,
+ OUT gctUINT32 * Handle
+ );
+
+gceSTATUS
+gcoHAL_GetVideoMemoryFd(
+ IN gctUINT32 Handle,
+ OUT gctINT * Fd
+ );
+
+/* Verify whether the specified feature is available in hardware. */
+gceSTATUS
+gcoHAL_IsFeatureAvailable(
+ IN gcoHAL Hal,
+ IN gceFEATURE Feature
+ );
+
+gceSTATUS
+gcoHAL_IsSwwaNeeded(
+ IN gcoHAL Hal,
+ IN gceSWWA Swwa
+ );
+
+gceSTATUS
+gcoHAL_IsFeatureAvailable1(
+ IN gcoHAL Hal,
+ IN gceFEATURE Feature
+ );
+
+/* Query the identity of the hardware. */
+gceSTATUS
+gcoHAL_QueryChipIdentity(
+ IN gcoHAL Hal,
+ OUT gceCHIPMODEL* ChipModel,
+ OUT gctUINT32* ChipRevision,
+ OUT gctUINT32* ChipFeatures,
+ OUT gctUINT32* ChipMinorFeatures
+ );
+
+
+gceSTATUS
+gcoHAL_QuerySuperTileMode(
+ OUT gctUINT32_PTR SuperTileMode
+ );
+
+gceSTATUS
+gcoHAL_QueryChipAxiBusWidth(
+ OUT gctBOOL * AXI128Bits
+ );
+
+gceSTATUS
+gcoHAL_QueryMultiGPUAffinityConfig(
+ IN gceHARDWARE_TYPE Type,
+ OUT gceMULTI_GPU_MODE *Mode,
+ OUT gctUINT32_PTR CoreIndex
+ );
+
+#ifdef LINUX
+gctINT32
+gcoOS_EndRecordAllocation(void);
+void
+gcoOS_RecordAllocation(void);
+void
+gcoOS_AddRecordAllocation(gctSIZE_T Size);
+#endif
+
+/* Query the amount of video memory. */
+gceSTATUS
+gcoHAL_QueryVideoMemory(
+ IN gcoHAL Hal,
+ OUT gctPHYS_ADDR * InternalAddress,
+ OUT gctSIZE_T * InternalSize,
+ OUT gctPHYS_ADDR * ExternalAddress,
+ OUT gctSIZE_T * ExternalSize,
+ OUT gctPHYS_ADDR * ContiguousAddress,
+ OUT gctSIZE_T * ContiguousSize
+ );
+
+/* Map video memory. */
+gceSTATUS
+gcoHAL_MapMemory(
+ IN gcoHAL Hal,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T NumberOfBytes,
+ OUT gctPOINTER * Logical
+ );
+
+/* Unmap video memory. */
+gceSTATUS
+gcoHAL_UnmapMemory(
+ IN gcoHAL Hal,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T NumberOfBytes,
+ IN gctPOINTER Logical
+ );
+
+/* Schedule an unmap of a buffer mapped through its physical address. */
+gceSTATUS
+gcoHAL_ScheduleUnmapMemory(
+ IN gcoHAL Hal,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T NumberOfBytes,
+ IN gctPOINTER Logical
+ );
+
+/* Allocate video memory. */
+gceSTATUS
+gcoOS_AllocateVideoMemory(
+ IN gcoOS Os,
+ IN gctBOOL InUserSpace,
+ IN gctBOOL InCacheable,
+ IN OUT gctSIZE_T * Bytes,
+ OUT gctUINT32 * Physical,
+ OUT gctPOINTER * Logical,
+ OUT gctPOINTER * Handle
+ );
+
+/* Free video memory. */
+gceSTATUS
+gcoOS_FreeVideoMemory(
+ IN gcoOS Os,
+ IN gctPOINTER Handle
+ );
+
+/* Lock video memory. */
+gceSTATUS
+gcoOS_LockVideoMemory(
+ IN gcoOS Os,
+ IN gctPOINTER Handle,
+ IN gctBOOL InUserSpace,
+ IN gctBOOL InCacheable,
+ OUT gctUINT32 * Physical,
+ OUT gctPOINTER * Logical
+ );
+
+/* Map user memory. */
+gceSTATUS
+gcoHAL_MapUserMemory(
+ IN gctPOINTER Logical,
+ IN gctUINT32 Physical,
+ IN gctSIZE_T Size,
+ OUT gctPOINTER * Info,
+ OUT gctUINT32_PTR GPUAddress
+ );
+
+/* Unmap user memory. */
+gceSTATUS
+gcoHAL_UnmapUserMemory(
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Size,
+ IN gctPOINTER Info,
+ IN gctUINT32 GPUAddress
+ );
+
+/* Schedule an unmap of a user buffer using event mechanism. */
+gceSTATUS
+gcoHAL_ScheduleUnmapUserMemory(
+ IN gcoHAL Hal,
+ IN gctPOINTER Info,
+ IN gctSIZE_T Size,
+ IN gctUINT32 Address,
+ IN gctPOINTER Memory
+ );
+
+/* Commit the current command buffer. */
+gceSTATUS
+gcoHAL_Commit(
+ IN gcoHAL Hal,
+ IN gctBOOL Stall
+ );
+
+#if gcdENABLE_3D
+/* Sencd fence command. */
+gceSTATUS
+gcoHAL_SendFence(
+ IN gcoHAL Hal
+ );
+#endif /* gcdENABLE_3D */
+
+/* Query the tile capabilities. */
+gceSTATUS
+gcoHAL_QueryTiled(
+ IN gcoHAL Hal,
+ OUT gctINT32 * TileWidth2D,
+ OUT gctINT32 * TileHeight2D,
+ OUT gctINT32 * TileWidth3D,
+ OUT gctINT32 * TileHeight3D
+ );
+
+gceSTATUS
+gcoHAL_Compact(
+ IN gcoHAL Hal
+ );
+
+#if VIVANTE_PROFILER
+gceSTATUS
+gcoHAL_ProfileStart(
+ IN gcoHAL Hal
+ );
+
+gceSTATUS
+gcoHAL_ProfileEnd(
+ IN gcoHAL Hal,
+ IN gctCONST_STRING Title
+ );
+#endif
+
+/* Power Management */
+gceSTATUS
+gcoHAL_SetPowerManagementState(
+ IN gcoHAL Hal,
+ IN gceCHIPPOWERSTATE State
+ );
+
+gceSTATUS
+gcoHAL_QueryPowerManagementState(
+ IN gcoHAL Hal,
+ OUT gceCHIPPOWERSTATE *State
+ );
+
+/* Set the filter type for filter blit. */
+gceSTATUS
+gcoHAL_SetFilterType(
+ IN gcoHAL Hal,
+ IN gceFILTER_TYPE FilterType
+ );
+
+gceSTATUS
+gcoHAL_GetDump(
+ IN gcoHAL Hal,
+ OUT gcoDUMP * Dump
+ );
+
+/* Call the kernel HAL layer. */
+gceSTATUS
+gcoHAL_Call(
+ IN gcoHAL Hal,
+ IN OUT gcsHAL_INTERFACE_PTR Interface
+ );
+
+/* Schedule an event. */
+gceSTATUS
+gcoHAL_ScheduleEvent(
+ IN gcoHAL Hal,
+ IN OUT gcsHAL_INTERFACE_PTR Interface
+ );
+
+/* Request a start/stop timestamp. */
+gceSTATUS
+gcoHAL_SetTimer(
+ IN gcoHAL Hal,
+ IN gctUINT32 Index,
+ IN gctBOOL Start
+ );
+
+/* Get Time delta from a Timer in microseconds. */
+gceSTATUS
+gcoHAL_GetTimerTime(
+ IN gcoHAL Hal,
+ IN gctUINT32 Timer,
+ OUT gctINT32_PTR TimeDelta
+ );
+
+/* set timeout value. */
+gceSTATUS
+gcoHAL_SetTimeOut(
+ IN gcoHAL Hal,
+ IN gctUINT32 timeOut
+ );
+
+gceSTATUS
+gcoHAL_SetHardwareType(
+ IN gcoHAL Hal,
+ IN gceHARDWARE_TYPE HardwardType
+ );
+
+gceSTATUS
+gcoHAL_GetHardwareType(
+ IN gcoHAL Hal,
+ OUT gceHARDWARE_TYPE * HardwardType
+ );
+
+gceSTATUS
+gcoHAL_QueryChipCount(
+ IN gcoHAL Hal,
+ OUT gctINT32 * Count
+ );
+
+gceSTATUS
+gcoHAL_Query3DCoreCount(
+ IN gcoHAL Hal,
+ OUT gctUINT32 *Count
+ );
+
+gceSTATUS
+gcoHAL_QueryCoreCount(
+ IN gcoHAL Hal,
+ IN gceHARDWARE_TYPE Type,
+ OUT gctUINT *Count,
+ OUT gctUINT_PTR ChipIDs
+ );
+
+gceSTATUS
+gcoHAL_QuerySeparated2D(
+ IN gcoHAL Hal
+ );
+
+gceSTATUS
+gcoHAL_QueryHybrid2D(
+ IN gcoHAL Hal
+ );
+
+gceSTATUS
+gcoHAL_Is3DAvailable(
+ IN gcoHAL Hal
+ );
+
+/* Get pointer to gcoVG object. */
+gceSTATUS
+gcoHAL_GetVGEngine(
+ IN gcoHAL Hal,
+ OUT gcoVG * Engine
+ );
+
+gceSTATUS
+gcoHAL_QueryChipLimits(
+ IN gcoHAL Hal,
+ IN gctINT32 Chip,
+ OUT gcsHAL_LIMITS *Limits);
+
+gceSTATUS
+gcoHAL_QueryChipFeature(
+ IN gcoHAL Hal,
+ IN gctINT32 Chip,
+ IN gceFEATURE Feature);
+
+gceSTATUS
+gcoHAL_SetCoreIndex(
+ IN gcoHAL Hal,
+ IN gctUINT32 Core
+ );
+
+gceSTATUS
+gcoHAL_GetCurrentCoreIndex(
+ IN gcoHAL Hal,
+ OUT gctUINT32 *Core
+ );
+
+/*----------------------------------------------------------------------------*/
+/*----- Shared Buffer --------------------------------------------------------*/
+
+/* Create shared buffer. */
+gceSTATUS
+gcoHAL_CreateShBuffer(
+ IN gctUINT32 Size,
+ OUT gctSHBUF * ShBuf
+ );
+
+/* Destroy shared buffer. */
+gceSTATUS
+gcoHAL_DestroyShBuffer(
+ IN gctSHBUF ShBuf
+ );
+
+/* Map shared buffer to current process. */
+gceSTATUS
+gcoHAL_MapShBuffer(
+ IN gctSHBUF ShBuf
+ );
+
+/* Write user data to shared buffer. */
+gceSTATUS
+gcoHAL_WriteShBuffer(
+ IN gctSHBUF ShBuf,
+ IN gctCONST_POINTER Data,
+ IN gctUINT32 ByteCount
+ );
+
+/* Read user data from shared buffer. */
+gceSTATUS
+gcoHAL_ReadShBuffer(
+ IN gctSHBUF ShBuf,
+ IN gctPOINTER Data,
+ IN gctUINT32 BytesCount,
+ OUT gctUINT32 * BytesRead
+ );
+
+/* Config power management to be enabled or disabled. */
+gceSTATUS
+gcoHAL_ConfigPowerManagement(
+ IN gctBOOL Enable
+ );
+
+gceSTATUS
+gcoHAL_AllocateVideoMemory(
+ IN gctUINT Alignment,
+ IN gceSURF_TYPE Type,
+ IN gctUINT32 Flag,
+ IN gcePOOL Pool,
+ IN OUT gctSIZE_T * Bytes,
+ OUT gctUINT32_PTR Node
+ );
+
+gceSTATUS
+gcoHAL_LockVideoMemory(
+ IN gctUINT32 Node,
+ IN gctBOOL Cacheable,
+ IN gceENGINE engine,
+ OUT gctUINT32 * Physical,
+ OUT gctPOINTER * Logical
+ );
+
+gceSTATUS
+gcoHAL_UnlockVideoMemory(
+ IN gctUINT32 Node,
+ IN gceSURF_TYPE Type,
+ IN gceENGINE engine
+ );
+
+gceSTATUS
+gcoHAL_ReleaseVideoMemory(
+ IN gctUINT32 Node
+ );
+
+gceSTATUS
+gcoHAL_AllocateContiguous(
+ IN gcoOS Os,
+ IN OUT gctSIZE_T * Bytes,
+ OUT gctPHYS_ADDR * Physical,
+ OUT gctPOINTER * Logical
+ );
+
+#if gcdENABLE_3D || gcdENABLE_VG
+/* Query the target capabilities. */
+gceSTATUS
+gcoHAL_QueryTargetCaps(
+ IN gcoHAL Hal,
+ OUT gctUINT * MaxWidth,
+ OUT gctUINT * MaxHeight,
+ OUT gctUINT * MultiTargetCount,
+ OUT gctUINT * MaxSamples
+ );
+#endif
+
+gceSTATUS
+gcoHAL_WrapUserMemory(
+ IN gcsUSER_MEMORY_DESC_PTR UserMemoryDesc,
+ OUT gctUINT32_PTR Node
+ );
+
+gceSTATUS
+gcoHAL_QueryResetTimeStamp(
+ OUT gctUINT64_PTR ResetTimeStamp,
+ OUT gctUINT64_PTR ContextID
+ );
+
+gceSTATUS
+gcoHAL_WaitFence(
+ IN gctUINT32 Handle,
+ IN gctUINT32 TimeOut
+ );
+
+#if gcdENABLE_2D
+gceSTATUS
+gcoHAL_AttachExternalMemory(
+ IN gcoHAL Hal,
+ IN gcsEXTERNAL_MEMORY_INFO * External,
+ OUT gctPOINTER * Handle,
+ OUT gctUINT32_PTR GPU2DAddress
+ );
+
+gceSTATUS
+gcoHAL_DetachExternalMemory(
+ IN gcoHAL Hal,
+ IN gctPOINTER * Handle
+ );
+#endif
+
+gceSTATUS
+gcoHAL_ScheduleSignal(
+ IN gctSIGNAL Signal,
+ IN gctSIGNAL AuxSignal,
+ IN gctINT ProcessID,
+ IN gceKERNEL_WHERE FromWhere
+ );
+
+gceSTATUS
+gcoHAL_GetGraphicBufferFd(
+ IN gctUINT32 Node[3],
+ IN gctSHBUF ShBuf,
+ IN gctSIGNAL Signal,
+ OUT gctINT32 * Fd
+ );
+
+/******************************************************************************\
+********************************** gcoOS Object *********************************
+\******************************************************************************/
+/* Lock PLS access */
+gceSTATUS
+gcoOS_LockPLS(
+ void
+ );
+
+/* Unlock PLS access */
+gceSTATUS
+gcoOS_UnLockPLS(
+ void
+ );
+
+/* Get PLS value for given key */
+gctPOINTER
+gcoOS_GetPLSValue(
+ IN gcePLS_VALUE key
+ );
+
+/* Set PLS value of a given key */
+void
+gcoOS_SetPLSValue(
+ IN gcePLS_VALUE key,
+ OUT gctPOINTER value
+ );
+
+/* Lock GL FE compiler access */
+gceSTATUS
+gcoOS_LockGLFECompiler(
+ void
+ );
+
+/* Unlock GL FE compiler access */
+gceSTATUS
+gcoOS_UnLockGLFECompiler(
+ void
+ );
+
+/* Lock CL FE compiler access */
+gceSTATUS
+gcoOS_LockCLFECompiler(
+ void
+ );
+
+/* Unlock CL FE compiler access */
+gceSTATUS
+gcoOS_UnLockCLFECompiler(
+ void
+ );
+
+gceSTATUS
+gcoOS_GetTLS(
+ OUT gcsTLS_PTR * TLS
+ );
+
+/* Copy the TLS from a source thread. */
+gceSTATUS
+gcoOS_CopyTLS(
+ IN gcsTLS_PTR Source
+ );
+
+/* Query the thread local storage. */
+gceSTATUS
+gcoOS_QueryTLS(
+ OUT gcsTLS_PTR * TLS
+ );
+
+/* Get access to driver tls. */
+gceSTATUS
+gcoOS_GetDriverTLS(
+ IN gceTLS_KEY Key,
+ OUT gcsDRIVER_TLS_PTR * TLS
+ );
+
+/*
+ * Set driver tls.
+ * May cause memory leak if 'destructor' not set.
+ */
+gceSTATUS
+gcoOS_SetDriverTLS(
+ IN gceTLS_KEY Key,
+ IN gcsDRIVER_TLS * TLS
+ );
+
+/* Destroy the objects associated with the current thread. */
+void
+gcoOS_FreeThreadData(
+ void
+ );
+
+/* Empty function for compatibility. */
+gceSTATUS
+gcoOS_Construct(
+ IN gctPOINTER Context,
+ OUT gcoOS * Os
+ );
+
+/* Empty function for compatibility. */
+gceSTATUS
+gcoOS_Destroy(
+ IN gcoOS Os
+ );
+
+/* Get the base address for the physical memory. */
+gceSTATUS
+gcoOS_GetBaseAddress(
+ IN gcoOS Os,
+ OUT gctUINT32_PTR BaseAddress
+ );
+
+/* Allocate memory from the heap. */
+gceSTATUS
+gcoOS_Allocate(
+ IN gcoOS Os,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Memory
+ );
+
+/* Get allocated memory size. */
+gceSTATUS
+gcoOS_GetMemorySize(
+ IN gcoOS Os,
+ IN gctPOINTER Memory,
+ OUT gctSIZE_T_PTR MemorySize
+ );
+
+/* Free allocated memory. */
+gceSTATUS
+gcoOS_Free(
+ IN gcoOS Os,
+ IN gctPOINTER Memory
+ );
+
+/* Allocate memory. */
+gceSTATUS
+gcoOS_AllocateSharedMemory(
+ IN gcoOS Os,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Memory
+ );
+
+/* Free memory. */
+gceSTATUS
+gcoOS_FreeSharedMemory(
+ IN gcoOS Os,
+ IN gctPOINTER Memory
+ );
+
+/* Allocate memory. */
+gceSTATUS
+gcoOS_AllocateMemory(
+ IN gcoOS Os,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Memory
+ );
+
+/* Free memory. */
+gceSTATUS
+gcoOS_FreeMemory(
+ IN gcoOS Os,
+ IN gctPOINTER Memory
+ );
+
+/* Free contiguous memory. */
+gceSTATUS
+gcoOS_FreeContiguous(
+ IN gcoOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ );
+
+/* Map user memory. */
+gceSTATUS
+gcoOS_MapUserMemory(
+ IN gcoOS Os,
+ IN gctPOINTER Memory,
+ IN gctSIZE_T Size,
+ OUT gctPOINTER * Info,
+ OUT gctUINT32_PTR Address
+ );
+
+/* Map user memory. */
+gceSTATUS
+gcoOS_MapUserMemoryEx(
+ IN gcoOS Os,
+ IN gctPOINTER Memory,
+ IN gctUINT32 Physical,
+ IN gctSIZE_T Size,
+ OUT gctPOINTER * Info,
+ OUT gctUINT32_PTR Address
+ );
+
+/* Unmap user memory. */
+gceSTATUS
+gcoOS_UnmapUserMemory(
+ IN gcoOS Os,
+ IN gctPOINTER Memory,
+ IN gctSIZE_T Size,
+ IN gctPOINTER Info,
+ IN gctUINT32 Address
+ );
+
+gceSTATUS
+gcoOS_CPUPhysicalToGPUPhysical(
+ IN gctUINT32 CPUPhysical,
+ OUT gctUINT32_PTR GPUPhysical
+ );
+
+/* Device I/O Control call to the kernel HAL layer. */
+gceSTATUS
+gcoOS_DeviceControl(
+ IN gcoOS Os,
+ IN gctUINT32 IoControlCode,
+ IN gctPOINTER InputBuffer,
+ IN gctSIZE_T InputBufferSize,
+ IN gctPOINTER OutputBuffer,
+ IN gctSIZE_T OutputBufferSize
+ );
+
+/* Allocate non paged memory. */
+gceSTATUS
+gcoOS_AllocateNonPagedMemory(
+ IN gcoOS Os,
+ IN gctBOOL InUserSpace,
+ IN OUT gctSIZE_T * Bytes,
+ OUT gctPHYS_ADDR * Physical,
+ OUT gctPOINTER * Logical
+ );
+
+/* Free non paged memory. */
+gceSTATUS
+gcoOS_FreeNonPagedMemory(
+ IN gcoOS Os,
+ IN gctSIZE_T Bytes,
+ IN gctPHYS_ADDR Physical,
+ IN gctPOINTER Logical
+ );
+
+#define gcmOS_SAFE_FREE(os, mem) \
+ gcoOS_Free(os, mem); \
+ mem = gcvNULL
+
+#define gcmOS_SAFE_FREE_SHARED_MEMORY(os, mem) \
+ gcoOS_FreeSharedMemory(os, mem); \
+ mem = gcvNULL
+
+#define gcmkOS_SAFE_FREE(os, mem) \
+ gckOS_Free(os, mem); \
+ mem = gcvNULL
+
+#define gcdMAX_PATH 512
+
+typedef enum _gceFILE_MODE
+{
+ gcvFILE_CREATE = 0,
+ gcvFILE_APPEND,
+ gcvFILE_READ,
+ gcvFILE_CREATETEXT,
+ gcvFILE_APPENDTEXT,
+ gcvFILE_READTEXT,
+}
+gceFILE_MODE;
+
+/* Open a file. */
+gceSTATUS
+gcoOS_Open(
+ IN gcoOS Os,
+ IN gctCONST_STRING FileName,
+ IN gceFILE_MODE Mode,
+ OUT gctFILE * File
+ );
+
+/* Close a file. */
+gceSTATUS
+gcoOS_Close(
+ IN gcoOS Os,
+ IN gctFILE File
+ );
+
+/* Read data from a file. */
+gceSTATUS
+gcoOS_Read(
+ IN gcoOS Os,
+ IN gctFILE File,
+ IN gctSIZE_T ByteCount,
+ IN gctPOINTER Data,
+ OUT gctSIZE_T * ByteRead
+ );
+
+/* Write data to a file. */
+gceSTATUS
+gcoOS_Write(
+ IN gcoOS Os,
+ IN gctFILE File,
+ IN gctSIZE_T ByteCount,
+ IN gctCONST_POINTER Data
+ );
+
+/* Flush data to a file. */
+gceSTATUS
+gcoOS_Flush(
+ IN gcoOS Os,
+ IN gctFILE File
+ );
+
+/* Close a file descriptor. */
+gceSTATUS
+gcoOS_CloseFD(
+ IN gcoOS Os,
+ IN gctINT FD
+ );
+
+/* Scan a file. */
+gceSTATUS
+gcoOS_FscanfI(
+ IN gcoOS Os,
+ IN gctFILE File,
+ IN gctCONST_STRING Format,
+ OUT gctUINT *result
+ );
+
+/* Dup file descriptor to another. */
+gceSTATUS
+gcoOS_DupFD(
+ IN gcoOS Os,
+ IN gctINT FD,
+ OUT gctINT * FD2
+ );
+
+/* Create an endpoint for communication. */
+gceSTATUS
+gcoOS_Socket(
+ IN gcoOS Os,
+ IN gctINT Domain,
+ IN gctINT Type,
+ IN gctINT Protocol,
+ OUT gctINT *SockFd
+ );
+
+/* Close a socket. */
+gceSTATUS
+gcoOS_CloseSocket(
+ IN gcoOS Os,
+ IN gctINT SockFd
+ );
+
+/* Initiate a connection on a socket. */
+gceSTATUS
+gcoOS_Connect(
+ IN gcoOS Os,
+ IN gctINT SockFd,
+ IN gctCONST_POINTER HostName,
+ IN gctUINT Port);
+
+/* Shut down part of connection on a socket. */
+gceSTATUS
+gcoOS_Shutdown(
+ IN gcoOS Os,
+ IN gctINT SockFd,
+ IN gctINT How
+ );
+
+/* Send a message on a socket. */
+gceSTATUS
+gcoOS_Send(
+ IN gcoOS Os,
+ IN gctINT SockFd,
+ IN gctSIZE_T ByteCount,
+ IN gctCONST_POINTER Data,
+ IN gctINT Flags
+ );
+
+/* Initiate a connection on a socket. */
+gceSTATUS
+gcoOS_WaitForSend(
+ IN gcoOS Os,
+ IN gctINT SockFd,
+ IN gctINT Seconds,
+ IN gctINT MicroSeconds);
+
+/* Get environment variable value. */
+gceSTATUS
+gcoOS_GetEnv(
+ IN gcoOS Os,
+ IN gctCONST_STRING VarName,
+ OUT gctSTRING * Value
+ );
+
+/* Set environment variable value. */
+gceSTATUS
+gcoOS_SetEnv(
+ IN gcoOS Os,
+ IN gctCONST_STRING VarName,
+ IN gctSTRING Value
+ );
+
+/* Get current working directory. */
+gceSTATUS
+gcoOS_GetCwd(
+ IN gcoOS Os,
+ IN gctINT SizeInBytes,
+ OUT gctSTRING Buffer
+ );
+
+/* Get file status info. */
+gceSTATUS
+gcoOS_Stat(
+ IN gcoOS Os,
+ IN gctCONST_STRING FileName,
+ OUT gctPOINTER Buffer
+ );
+
+typedef enum _gceFILE_WHENCE
+{
+ gcvFILE_SEEK_SET,
+ gcvFILE_SEEK_CUR,
+ gcvFILE_SEEK_END
+}
+gceFILE_WHENCE;
+
+/* Set the current position of a file. */
+gceSTATUS
+gcoOS_Seek(
+ IN gcoOS Os,
+ IN gctFILE File,
+ IN gctUINT32 Offset,
+ IN gceFILE_WHENCE Whence
+ );
+
+/* Set the current position of a file. */
+gceSTATUS
+gcoOS_SetPos(
+ IN gcoOS Os,
+ IN gctFILE File,
+ IN gctUINT32 Position
+ );
+
+/* Get the current position of a file. */
+gceSTATUS
+gcoOS_GetPos(
+ IN gcoOS Os,
+ IN gctFILE File,
+ OUT gctUINT32 * Position
+ );
+
+/* Same as strstr. */
+gceSTATUS
+gcoOS_StrStr(
+ IN gctCONST_STRING String,
+ IN gctCONST_STRING SubString,
+ OUT gctSTRING * Output
+ );
+
+/* Find the last occurance of a character inside a string. */
+gceSTATUS
+gcoOS_StrFindReverse(
+ IN gctCONST_STRING String,
+ IN gctINT8 Character,
+ OUT gctSTRING * Output
+ );
+
+gceSTATUS
+gcoOS_StrDup(
+ IN gcoOS Os,
+ IN gctCONST_STRING String,
+ OUT gctSTRING * Target
+ );
+
+/* Copy a string. */
+gceSTATUS
+gcoOS_StrCopySafe(
+ IN gctSTRING Destination,
+ IN gctSIZE_T DestinationSize,
+ IN gctCONST_STRING Source
+ );
+
+/* Append a string. */
+gceSTATUS
+gcoOS_StrCatSafe(
+ IN gctSTRING Destination,
+ IN gctSIZE_T DestinationSize,
+ IN gctCONST_STRING Source
+ );
+
+/* Compare two strings. */
+gceSTATUS
+gcoOS_StrCmp(
+ IN gctCONST_STRING String1,
+ IN gctCONST_STRING String2
+ );
+
+/* Compare characters of two strings. */
+gceSTATUS
+gcoOS_StrNCmp(
+ IN gctCONST_STRING String1,
+ IN gctCONST_STRING String2,
+ IN gctSIZE_T Count
+ );
+
+/* Convert string to float. */
+gceSTATUS
+gcoOS_StrToFloat(
+ IN gctCONST_STRING String,
+ OUT gctFLOAT * Float
+ );
+
+/* Convert hex string to integer. */
+gceSTATUS gcoOS_HexStrToInt(
+ IN gctCONST_STRING String,
+ OUT gctINT * Int
+ );
+
+/* Convert hex string to float. */
+gceSTATUS
+gcoOS_HexStrToFloat(
+ IN gctCONST_STRING String,
+ OUT gctFLOAT * Float
+ );
+
+/* Convert string to integer. */
+gceSTATUS
+gcoOS_StrToInt(
+ IN gctCONST_STRING String,
+ OUT gctINT * Int
+ );
+
+gceSTATUS
+gcoOS_MemCmp(
+ IN gctCONST_POINTER Memory1,
+ IN gctCONST_POINTER Memory2,
+ IN gctSIZE_T Bytes
+ );
+
+gceSTATUS
+gcoOS_PrintStrSafe(
+ OUT gctSTRING String,
+ IN gctSIZE_T StringSize,
+ IN OUT gctUINT * Offset,
+ IN gctCONST_STRING Format,
+ ...
+ );
+
+gceSTATUS
+gcoOS_LoadLibrary(
+ IN gcoOS Os,
+ IN gctCONST_STRING Library,
+ OUT gctHANDLE * Handle
+ );
+
+gceSTATUS
+gcoOS_FreeLibrary(
+ IN gcoOS Os,
+ IN gctHANDLE Handle
+ );
+
+gceSTATUS
+gcoOS_GetProcAddress(
+ IN gcoOS Os,
+ IN gctHANDLE Handle,
+ IN gctCONST_STRING Name,
+ OUT gctPOINTER * Function
+ );
+
+gceSTATUS
+gcoOS_Compact(
+ IN gcoOS Os
+ );
+
+gceSTATUS
+gcoOS_AddSignalHandler (
+ IN gceSignalHandlerType SignalHandlerType
+ );
+
+#if VIVANTE_PROFILER
+gceSTATUS
+gcoOS_ProfileStart(
+ IN gcoOS Os
+ );
+
+gceSTATUS
+gcoOS_ProfileEnd(
+ IN gcoOS Os,
+ IN gctCONST_STRING Title
+ );
+
+gceSTATUS
+gcoOS_SetProfileSetting(
+ IN gcoOS Os,
+ IN gctBOOL Enable,
+ IN gctCONST_STRING FileName
+ );
+#endif
+
+/* Get the amount of physical system memory */
+gceSTATUS
+gcoOS_GetPhysicalSystemMemorySize(
+ OUT gctSIZE_T * PhysicalSystemMemorySize
+ );
+
+/* Query the video memory. */
+gceSTATUS
+gcoOS_QueryVideoMemory(
+ IN gcoOS Os,
+ OUT gctPHYS_ADDR * InternalAddress,
+ OUT gctSIZE_T * InternalSize,
+ OUT gctPHYS_ADDR * ExternalAddress,
+ OUT gctSIZE_T * ExternalSize,
+ OUT gctPHYS_ADDR * ContiguousAddress,
+ OUT gctSIZE_T * ContiguousSize
+ );
+
+gceSTATUS
+gcoOS_QueryCurrentProcessName(
+ OUT gctSTRING Name,
+ IN gctSIZE_T Size
+ );
+
+
+/*----------------------------------------------------------------------------*/
+/*----- Atoms ----------------------------------------------------------------*/
+
+/* Construct an atom. */
+gceSTATUS
+gcoOS_AtomConstruct(
+ IN gcoOS Os,
+ OUT gcsATOM_PTR * Atom
+ );
+
+/* Destroy an atom. */
+gceSTATUS
+gcoOS_AtomDestroy(
+ IN gcoOS Os,
+ IN gcsATOM_PTR Atom
+ );
+
+/* Get the 32-bit value protected by an atom. */
+gceSTATUS
+gcoOS_AtomGet(
+ IN gcoOS Os,
+ IN gcsATOM_PTR Atom,
+ OUT gctINT32_PTR Value
+ );
+
+/* Set the 32-bit value protected by an atom. */
+gceSTATUS
+gcoOS_AtomSet(
+ IN gcoOS Os,
+ IN gcsATOM_PTR Atom,
+ IN gctINT32 Value
+ );
+
+/* Increment an atom. */
+gceSTATUS
+gcoOS_AtomIncrement(
+ IN gcoOS Os,
+ IN gcsATOM_PTR Atom,
+ OUT gctINT32_PTR OldValue
+ );
+
+/* Decrement an atom. */
+gceSTATUS
+gcoOS_AtomDecrement(
+ IN gcoOS Os,
+ IN gcsATOM_PTR Atom,
+ OUT gctINT32_PTR OldValue
+ );
+
+gctHANDLE
+gcoOS_GetCurrentProcessID(
+ void
+ );
+
+gctHANDLE
+gcoOS_GetCurrentThreadID(
+ void
+ );
+
+/*----------------------------------------------------------------------------*/
+/*----- Time -----------------------------------------------------------------*/
+
+/* Get the number of milliseconds since the system started. */
+gctUINT32
+gcoOS_GetTicks(
+ void
+ );
+
+/* Get time in microseconds. */
+gceSTATUS
+gcoOS_GetTime(
+ gctUINT64_PTR Time
+ );
+
+/* Get CPU usage in microseconds. */
+gceSTATUS
+gcoOS_GetCPUTime(
+ gctUINT64_PTR CPUTime
+ );
+
+/* Get memory usage. */
+gceSTATUS
+gcoOS_GetMemoryUsage(
+ gctUINT32_PTR MaxRSS,
+ gctUINT32_PTR IxRSS,
+ gctUINT32_PTR IdRSS,
+ gctUINT32_PTR IsRSS
+ );
+
+/* Delay a number of microseconds. */
+gceSTATUS
+gcoOS_Delay(
+ IN gcoOS Os,
+ IN gctUINT32 Delay
+ );
+
+/*----------------------------------------------------------------------------*/
+/*----- Threads --------------------------------------------------------------*/
+
+#ifdef _WIN32
+/* Cannot include windows.h here becuase "near" and "far"
+ * which are used in gcsDEPTH_INFO, are defined to nothing in WinDef.h.
+ * So, use the real value of DWORD and WINAPI, instead.
+ * DWORD is unsigned long, and WINAPI is __stdcall.
+ * If these two are change in WinDef.h, the following two typdefs
+ * need to be changed, too.
+ */
+typedef unsigned long gctTHREAD_RETURN;
+typedef unsigned long (__stdcall * gcTHREAD_ROUTINE)(void * Argument);
+#else
+typedef void * gctTHREAD_RETURN;
+typedef void * (* gcTHREAD_ROUTINE)(void *);
+#endif
+
+/* Create a new thread. */
+gceSTATUS
+gcoOS_CreateThread(
+ IN gcoOS Os,
+ IN gcTHREAD_ROUTINE Worker,
+ IN gctPOINTER Argument,
+ OUT gctPOINTER * Thread
+ );
+
+/* Close a thread. */
+gceSTATUS
+gcoOS_CloseThread(
+ IN gcoOS Os,
+ IN gctPOINTER Thread
+ );
+
+/*----------------------------------------------------------------------------*/
+/*----- Mutexes --------------------------------------------------------------*/
+
+/* Create a new mutex. */
+gceSTATUS
+gcoOS_CreateMutex(
+ IN gcoOS Os,
+ OUT gctPOINTER * Mutex
+ );
+
+/* Delete a mutex. */
+gceSTATUS
+gcoOS_DeleteMutex(
+ IN gcoOS Os,
+ IN gctPOINTER Mutex
+ );
+
+/* Acquire a mutex. */
+gceSTATUS
+gcoOS_AcquireMutex(
+ IN gcoOS Os,
+ IN gctPOINTER Mutex,
+ IN gctUINT32 Timeout
+ );
+
+/* Release a mutex. */
+gceSTATUS
+gcoOS_ReleaseMutex(
+ IN gcoOS Os,
+ IN gctPOINTER Mutex
+ );
+
+/*----------------------------------------------------------------------------*/
+/*----- Signals --------------------------------------------------------------*/
+
+/* Create a signal. */
+gceSTATUS
+gcoOS_CreateSignal(
+ IN gcoOS Os,
+ IN gctBOOL ManualReset,
+ OUT gctSIGNAL * Signal
+ );
+
+/* Destroy a signal. */
+gceSTATUS
+gcoOS_DestroySignal(
+ IN gcoOS Os,
+ IN gctSIGNAL Signal
+ );
+
+/* Signal a signal. */
+gceSTATUS
+gcoOS_Signal(
+ IN gcoOS Os,
+ IN gctSIGNAL Signal,
+ IN gctBOOL State
+ );
+
+/* Wait for a signal. */
+gceSTATUS
+gcoOS_WaitSignal(
+ IN gcoOS Os,
+ IN gctSIGNAL Signal,
+ IN gctUINT32 Wait
+ );
+
+/* Map a signal from another process */
+gceSTATUS
+gcoOS_MapSignal(
+ IN gctSIGNAL RemoteSignal,
+ OUT gctSIGNAL * LocalSignal
+ );
+
+/* Unmap a signal mapped from another process */
+gceSTATUS
+gcoOS_UnmapSignal(
+ IN gctSIGNAL Signal
+ );
+
+/*----------------------------------------------------------------------------*/
+/*----- Android Native Fence -------------------------------------------------*/
+
+/* Create native fence. */
+gceSTATUS
+gcoOS_CreateNativeFence(
+ IN gcoOS Os,
+ IN gctSIGNAL Signal,
+ OUT gctINT * FenceFD
+ );
+
+/* (CPU) Wait on native fence. */
+gceSTATUS
+gcoOS_ClientWaitNativeFence(
+ IN gcoOS Os,
+ IN gctINT FenceFD,
+ IN gctUINT32 Timeout
+ );
+
+/* (GPU) Wait on native fence. */
+gceSTATUS
+gcoOS_WaitNativeFence(
+ IN gcoOS Os,
+ IN gctINT FenceFD,
+ IN gctUINT32 Timeout
+ );
+
+/*----------------------------------------------------------------------------*/
+/*----- Memory Access and Cache ----------------------------------------------*/
+
+/* Write a register. */
+gceSTATUS
+gcoOS_WriteRegister(
+ IN gcoOS Os,
+ IN gctUINT32 Address,
+ IN gctUINT32 Data
+ );
+
+/* Read a register. */
+gceSTATUS
+gcoOS_ReadRegister(
+ IN gcoOS Os,
+ IN gctUINT32 Address,
+ OUT gctUINT32 * Data
+ );
+
+gceSTATUS
+gcoOS_CacheClean(
+ IN gcoOS Os,
+ IN gctUINT32 Node,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ );
+
+gceSTATUS
+gcoOS_CacheFlush(
+ IN gcoOS Os,
+ IN gctUINT32 Node,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ );
+
+gceSTATUS
+gcoOS_CacheInvalidate(
+ IN gcoOS Os,
+ IN gctUINT32 Node,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ );
+
+gceSTATUS
+gcoOS_MemoryBarrier(
+ IN gcoOS Os,
+ IN gctPOINTER Logical
+ );
+
+gceSTATUS
+gcoOS_CPUPhysicalToGPUPhysical(
+ IN gctUINT32 CPUPhysical,
+ OUT gctUINT32_PTR GPUPhysical
+ );
+
+gceSTATUS
+gcoOS_QuerySystemInfo(
+ IN gcoOS Os,
+ OUT gcsSystemInfo *Info
+ );
+
+/*----------------------------------------------------------------------------*/
+/*----- Profile --------------------------------------------------------------*/
+
+gceSTATUS
+gckOS_GetProfileTick(
+ OUT gctUINT64_PTR Tick
+ );
+
+gceSTATUS
+gckOS_QueryProfileTickRate(
+ OUT gctUINT64_PTR TickRate
+ );
+
+gctUINT32
+gckOS_ProfileToMS(
+ IN gctUINT64 Ticks
+ );
+
+gceSTATUS
+gcoOS_GetProfileTick(
+ OUT gctUINT64_PTR Tick
+ );
+
+gceSTATUS
+gcoOS_QueryProfileTickRate(
+ OUT gctUINT64_PTR TickRate
+ );
+
+#define _gcmPROFILE_INIT(prefix, freq, start) \
+ do { \
+ prefix ## OS_QueryProfileTickRate(&(freq)); \
+ prefix ## OS_GetProfileTick(&(start)); \
+ } while (gcvFALSE)
+
+#define _gcmPROFILE_QUERY(prefix, start, ticks) \
+ do { \
+ prefix ## OS_GetProfileTick(&(ticks)); \
+ (ticks) = ((ticks) > (start)) ? ((ticks) - (start)) \
+ : (~0ull - (start) + (ticks) + 1); \
+ } while (gcvFALSE)
+
+#if gcdENABLE_PROFILING
+# define gcmkPROFILE_INIT(freq, start) _gcmPROFILE_INIT(gck, freq, start)
+# define gcmkPROFILE_QUERY(start, ticks) _gcmPROFILE_QUERY(gck, start, ticks)
+# define gcmPROFILE_INIT(freq, start) _gcmPROFILE_INIT(gco, freq, start)
+# define gcmPROFILE_QUERY(start, ticks) _gcmPROFILE_QUERY(gco, start, ticks)
+# define gcmPROFILE_ONLY(x) x
+# define gcmPROFILE_ELSE(x) do { } while (gcvFALSE)
+# define gcmPROFILE_DECLARE_ONLY(x) x
+# define gcmPROFILE_DECLARE_ELSE(x) typedef x
+#else
+# define gcmkPROFILE_INIT(start, freq) do { } while (gcvFALSE)
+# define gcmkPROFILE_QUERY(start, ticks) do { } while (gcvFALSE)
+# define gcmPROFILE_INIT(start, freq) do { } while (gcvFALSE)
+# define gcmPROFILE_QUERY(start, ticks) do { } while (gcvFALSE)
+# define gcmPROFILE_ONLY(x) do { } while (gcvFALSE)
+# define gcmPROFILE_ELSE(x) x
+# define gcmPROFILE_DECLARE_ONLY(x) do { } while (gcvFALSE)
+# define gcmPROFILE_DECLARE_ELSE(x) x
+#endif
+
+/*******************************************************************************
+** gcoMATH object
+*/
+
+#define gcdPI 3.14159265358979323846f
+
+/* Kernel. */
+gctINT
+gckMATH_ModuloInt(
+ IN gctINT X,
+ IN gctINT Y
+ );
+
+/* User. */
+gctUINT32
+gcoMATH_Log2in5dot5(
+ IN gctINT X
+ );
+
+
+gctFLOAT
+gcoMATH_UIntAsFloat(
+ IN gctUINT32 X
+ );
+
+gctUINT32
+gcoMATH_FloatAsUInt(
+ IN gctFLOAT X
+ );
+
+gctBOOL
+gcoMATH_CompareEqualF(
+ IN gctFLOAT X,
+ IN gctFLOAT Y
+ );
+
+gctUINT16
+gcoMATH_UInt8AsFloat16(
+ IN gctUINT8 X
+ );
+
+gctUINT32
+gcoMATH_Float16ToFloat(
+ IN gctUINT16 In
+ );
+
+gctUINT16
+gcoMATH_FloatToFloat16(
+ IN gctUINT32 In
+ );
+
+gctUINT32
+gcoMATH_Float11ToFloat(
+ IN gctUINT32 In
+ );
+
+gctUINT16
+gcoMATH_FloatToFloat11(
+ IN gctUINT32 In
+ );
+
+gctUINT32
+gcoMATH_Float10ToFloat(
+ IN gctUINT32 In
+ );
+
+gctUINT16
+gcoMATH_FloatToFloat10(
+ IN gctUINT32 In
+ );
+
+gctUINT32
+gcoMATH_Float14ToFloat(
+ IN gctUINT16 In
+ );
+
+/******************************************************************************\
+**************************** Coordinate Structures *****************************
+\******************************************************************************/
+
+typedef struct _gcsPOINT
+{
+ gctINT32 x;
+ gctINT32 y;
+}
+gcsPOINT;
+
+typedef struct _gcsSIZE
+{
+ gctINT32 width;
+ gctINT32 height;
+}
+gcsSIZE;
+
+typedef struct _gcsRECT
+{
+ gctINT32 left;
+ gctINT32 top;
+ gctINT32 right;
+ gctINT32 bottom;
+}
+gcsRECT;
+
+typedef struct _gcsPIXEL
+{
+ union
+ {
+ struct
+ {
+ gctFLOAT r, g, b, a;
+ } f;
+ struct
+ {
+ gctINT32 r, g, b, a;
+ } i;
+ struct
+ {
+ gctUINT32 r, g, b, a;
+ } ui;
+ } color;
+
+ gctFLOAT d;
+ gctUINT32 s;
+
+} gcsPIXEL;
+
+/******************************************************************************\
+********************************* gcoSURF Object ********************************
+\******************************************************************************/
+
+/*----------------------------------------------------------------------------*/
+/*------------------------------- gcoSURF Common ------------------------------*/
+
+/* Color format classes. */
+typedef enum _gceFORMAT_CLASS
+{
+ gcvFORMAT_CLASS_RGBA = 4500,
+ gcvFORMAT_CLASS_YUV,
+ gcvFORMAT_CLASS_INDEX,
+ gcvFORMAT_CLASS_LUMINANCE,
+ gcvFORMAT_CLASS_BUMP,
+ gcvFORMAT_CLASS_DEPTH,
+ gcvFORMAT_CLASS_ASTC,
+ gcvFORMAT_CLASS_COMPRESSED,
+ gcvFORMAT_CLASS_OTHER
+}
+gceFORMAT_CLASS;
+
+/* Color format data type */
+typedef enum _gceFORMAT_DATATYPE
+{
+ gcvFORMAT_DATATYPE_UNSIGNED_NORMALIZED,
+ gcvFORMAT_DATATYPE_SIGNED_NORMALIZED,
+ gcvFORMAT_DATATYPE_UNSIGNED_INTEGER,
+ gcvFORMAT_DATATYPE_SIGNED_INTEGER,
+ gcvFORMAT_DATATYPE_FLOAT16,
+ gcvFORMAT_DATATYPE_FLOAT32,
+ gcvFORMAT_DATATYPE_FLOAT_E5B9G9R9,
+ gcvFORMAT_DATATYPE_FLOAT_B10G11R11F,
+ gcvFORMAT_DATATYPE_INDEX,
+ gcvFORMAT_DATATYPE_SRGB,
+ gcvFORMAT_DATATYPE_FLOAT32_UINT,
+}
+gceFORMAT_DATATYPE;
+
+/* Special enums for width field in gcsFORMAT_COMPONENT. */
+typedef enum _gceCOMPONENT_CONTROL
+{
+ gcvCOMPONENT_NOTPRESENT = 0x00,
+ gcvCOMPONENT_DONTCARE = 0x80,
+ gcvCOMPONENT_WIDTHMASK = 0x7F,
+ gcvCOMPONENT_ODD = 0x80
+}
+gceCOMPONENT_CONTROL;
+
+/* Color format component parameters. */
+typedef struct _gcsFORMAT_COMPONENT
+{
+ gctUINT8 start;
+ gctUINT8 width;
+}
+gcsFORMAT_COMPONENT;
+
+/* RGBA color format class. */
+typedef struct _gcsFORMAT_CLASS_TYPE_RGBA
+{
+ gcsFORMAT_COMPONENT alpha;
+ gcsFORMAT_COMPONENT red;
+ gcsFORMAT_COMPONENT green;
+ gcsFORMAT_COMPONENT blue;
+}
+gcsFORMAT_CLASS_TYPE_RGBA;
+
+/* YUV color format class. */
+typedef struct _gcsFORMAT_CLASS_TYPE_YUV
+{
+ gcsFORMAT_COMPONENT y;
+ gcsFORMAT_COMPONENT u;
+ gcsFORMAT_COMPONENT v;
+}
+gcsFORMAT_CLASS_TYPE_YUV;
+
+/* Index color format class. */
+typedef struct _gcsFORMAT_CLASS_TYPE_INDEX
+{
+ gcsFORMAT_COMPONENT value;
+}
+gcsFORMAT_CLASS_TYPE_INDEX;
+
+/* Luminance color format class. */
+typedef struct _gcsFORMAT_CLASS_TYPE_LUMINANCE
+{
+ gcsFORMAT_COMPONENT alpha;
+ gcsFORMAT_COMPONENT value;
+}
+gcsFORMAT_CLASS_TYPE_LUMINANCE;
+
+/* Bump map color format class. */
+typedef struct _gcsFORMAT_CLASS_TYPE_BUMP
+{
+ gcsFORMAT_COMPONENT alpha;
+ gcsFORMAT_COMPONENT l;
+ gcsFORMAT_COMPONENT v;
+ gcsFORMAT_COMPONENT u;
+ gcsFORMAT_COMPONENT q;
+ gcsFORMAT_COMPONENT w;
+}
+gcsFORMAT_CLASS_TYPE_BUMP;
+
+/* Depth and stencil format class. */
+typedef struct _gcsFORMAT_CLASS_TYPE_DEPTH
+{
+ gcsFORMAT_COMPONENT depth;
+ gcsFORMAT_COMPONENT stencil;
+}
+gcsFORMAT_CLASS_TYPE_DEPTH;
+
+typedef union _gcuPIXEL_FORMAT_CLASS
+{
+ gcsFORMAT_CLASS_TYPE_BUMP bump;
+ gcsFORMAT_CLASS_TYPE_RGBA rgba;
+ gcsFORMAT_CLASS_TYPE_YUV yuv;
+ gcsFORMAT_CLASS_TYPE_LUMINANCE lum;
+ gcsFORMAT_CLASS_TYPE_INDEX index;
+ gcsFORMAT_CLASS_TYPE_DEPTH depth;
+}
+gcuPIXEL_FORMAT_CLASS;
+
+/* Format parameters. */
+typedef struct _gcsSURF_FORMAT_INFO
+{
+ /* Name of the format */
+ gctCONST_STRING formatName;
+
+ /* Format code and class. */
+ gceSURF_FORMAT format;
+ gceFORMAT_CLASS fmtClass;
+
+ /* Format data type */
+ gceFORMAT_DATATYPE fmtDataType;
+
+ /* The size of one pixel in bits. */
+ gctUINT8 bitsPerPixel;
+
+ /* Pixel block dimensions. */
+ gctUINT blockWidth;
+ gctUINT blockHeight;
+
+ /* Pixel block size in bits. */
+ gctUINT blockSize;
+
+ /* Some formats are larger than what the GPU can support. */
+ /* These formats are read in the number of layers specified. */
+ gctUINT8 layers;
+
+ /* The format is faked and software will interpret it differently
+ ** with HW. Most of them can't be blendable(PE) or filterable(TX).
+ */
+ gctBOOL fakedFormat;
+
+ /* Some formats have two neighbour pixels interleaved together. */
+ /* To describe such format, set the flag to 1 and add another */
+ /* like this one describing the odd pixel format. */
+ gctBOOL interleaved;
+
+ /* sRGB format. */
+ gctBOOL sRGB;
+
+ /* Format components. */
+ gcuPIXEL_FORMAT_CLASS u;
+
+ /* Format components. */
+ gcuPIXEL_FORMAT_CLASS uOdd;
+
+ /* Render format. */
+ gceSURF_FORMAT closestRenderFormat;
+ /*gctCLOSEST_FORMAT dynamicClosestRenderFormat;*/
+ gctUINT renderFormat;
+ const gceTEXTURE_SWIZZLE * pixelSwizzle;
+
+ /* Texture format. */
+ gceSURF_FORMAT closestTXFormat;
+ gctUINT txFormat;
+ const gceTEXTURE_SWIZZLE * txSwizzle;
+ gctBOOL txIntFilter;
+}
+gcsSURF_FORMAT_INFO;
+
+/* Frame buffer information. */
+typedef struct _gcsSURF_FRAMEBUFFER
+{
+ gctPOINTER logical;
+ gctUINT width, height;
+ gctINT stride;
+ gceSURF_FORMAT format;
+}
+gcsSURF_FRAMEBUFFER;
+
+/* Generic pixel component descriptors. */
+extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_XXX8;
+extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_XX8X;
+extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_X8XX;
+extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_8XXX;
+
+typedef enum _gceORIENTATION
+{
+ gcvORIENTATION_TOP_BOTTOM,
+ gcvORIENTATION_BOTTOM_TOP,
+}
+gceORIENTATION;
+
+
+/* Construct a new gcoSURF object. */
+gceSTATUS
+gcoSURF_Construct(
+ IN gcoHAL Hal,
+ IN gctUINT Width,
+ IN gctUINT Height,
+ IN gctUINT Depth,
+ IN gceSURF_TYPE Type,
+ IN gceSURF_FORMAT Format,
+ IN gcePOOL Pool,
+ OUT gcoSURF * Surface
+ );
+
+/* Destroy an gcoSURF object. */
+gceSTATUS
+gcoSURF_Destroy(
+ IN gcoSURF Surface
+ );
+
+/* Map user-allocated surface. */
+gceSTATUS
+gcoSURF_MapUserSurface(
+ IN gcoSURF Surface,
+ IN gctUINT Alignment,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Physical
+ );
+
+/* Wrapp surface with known logical/GPU address */
+gceSTATUS
+gcoSURF_WrapSurface(
+ IN gcoSURF Surface,
+ IN gctUINT Alignment,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Physical
+ );
+
+
+/* Query vid mem node info. */
+gceSTATUS
+gcoSURF_QueryVidMemNode(
+ IN gcoSURF Surface,
+ OUT gctUINT32 * Node,
+ OUT gcePOOL * Pool,
+ OUT gctSIZE_T_PTR Bytes
+ );
+
+/* Set the color type of the surface. */
+gceSTATUS
+gcoSURF_SetColorType(
+ IN gcoSURF Surface,
+ IN gceSURF_COLOR_TYPE ColorType
+ );
+
+/* Get the color type of the surface. */
+gceSTATUS
+gcoSURF_GetColorType(
+ IN gcoSURF Surface,
+ OUT gceSURF_COLOR_TYPE *ColorType
+ );
+
+/* Set the color space of the surface. */
+gceSTATUS
+gcoSURF_SetColorSpace(
+ IN gcoSURF Surface,
+ IN gceSURF_COLOR_SPACE ColorSpace
+ );
+
+/* Get the color space of the surface. */
+gceSTATUS
+gcoSURF_GetColorSpace(
+ IN gcoSURF Surface,
+ OUT gceSURF_COLOR_SPACE *ColorSpace
+ );
+
+
+/* Set the surface ration angle. */
+gceSTATUS
+gcoSURF_SetRotation(
+ IN gcoSURF Surface,
+ IN gceSURF_ROTATION Rotation
+ );
+
+gceSTATUS
+gcoSURF_IsValid(
+ IN gcoSURF Surface
+ );
+
+#if gcdENABLE_3D
+/* Verify and return the state of the tile status mechanism. */
+gceSTATUS
+gcoSURF_IsTileStatusSupported(
+ IN gcoSURF Surface
+ );
+
+/* Verify if surface has tile status enabled. */
+gceSTATUS
+gcoSURF_IsTileStatusEnabled(
+ IN gcsSURF_VIEW *SurfView
+ );
+
+/* Verify if surface is compressed. */
+gceSTATUS
+gcoSURF_IsCompressed(
+ IN gcsSURF_VIEW *SurfView
+ );
+
+/* Enable tile status for the specified surface on zero slot. */
+gceSTATUS
+gcoSURF_EnableTileStatus(
+ IN gcsSURF_VIEW *Surface
+ );
+
+/* Enable tile status for the specified surface on specified slot. */
+gceSTATUS
+gcoSURF_EnableTileStatusEx(
+ IN gcsSURF_VIEW *surfView,
+ IN gctUINT RtIndex
+ );
+
+/* Disable tile status for the specified surface. */
+gceSTATUS
+gcoSURF_DisableTileStatus(
+ IN gcsSURF_VIEW *SurfView,
+ IN gctBOOL Decompress
+ );
+
+/* Flush tile status cache for the specified surface. */
+gceSTATUS
+gcoSURF_FlushTileStatus(
+ IN gcsSURF_VIEW *SurfView,
+ IN gctBOOL Decompress
+ );
+#endif /* gcdENABLE_3D */
+
+/* Get surface size. */
+gceSTATUS
+gcoSURF_GetSize(
+ IN gcoSURF Surface,
+ OUT gctUINT * Width,
+ OUT gctUINT * Height,
+ OUT gctUINT * Depth
+ );
+
+/* Get surface information */
+gceSTATUS
+gcoSURF_GetInfo(
+ IN gcoSURF Surface,
+ IN gceSURF_INFO_TYPE InfoType,
+ IN OUT gctINT32 *Value
+ );
+
+/* Get surface aligned sizes. */
+gceSTATUS
+gcoSURF_GetAlignedSize(
+ IN gcoSURF Surface,
+ OUT gctUINT * Width,
+ OUT gctUINT * Height,
+ OUT gctINT * Stride
+ );
+
+/* Get alignments. */
+gceSTATUS
+gcoSURF_GetAlignment(
+ IN gceSURF_TYPE Type,
+ IN gceSURF_FORMAT Format,
+ OUT gctUINT * AddressAlignment,
+ OUT gctUINT * XAlignment,
+ OUT gctUINT * YAlignment
+ );
+
+gceSTATUS
+gcoSURF_AlignResolveRect(
+ IN gcoSURF Surf,
+ IN gcsPOINT_PTR RectOrigin,
+ IN gcsPOINT_PTR RectSize,
+ OUT gcsPOINT_PTR AlignedOrigin,
+ OUT gcsPOINT_PTR AlignedSize
+ );
+
+/* Get surface type and format. */
+gceSTATUS
+gcoSURF_GetFormat(
+ IN gcoSURF Surface,
+ OUT OPTIONAL gceSURF_TYPE * Type,
+ OUT OPTIONAL gceSURF_FORMAT * Format
+ );
+
+/* Get surface information */
+gceSTATUS
+gcoSURF_GetFormatInfo(
+ IN gcoSURF Surface,
+ OUT gcsSURF_FORMAT_INFO_PTR * formatInfo
+ );
+
+/* Get Surface pack format */
+gceSTATUS
+gcoSURF_GetPackedFormat(
+ IN gcoSURF Surface,
+ OUT gceSURF_FORMAT * Format
+ );
+
+/* Get surface tiling. */
+gceSTATUS
+gcoSURF_GetTiling(
+ IN gcoSURF Surface,
+ OUT gceTILING * Tiling
+ );
+
+/* Get bottom buffer offset bytes. */
+gceSTATUS
+gcoSURF_GetBottomBufferOffset(
+ IN gcoSURF Surface,
+ OUT gctUINT_PTR BottomBufferOffset
+ );
+
+/* Lock the surface. */
+gceSTATUS
+gcoSURF_Lock(
+ IN gcoSURF Surface,
+ IN OUT gctUINT32 * Address,
+ IN OUT gctPOINTER * Memory
+ );
+
+/* Unlock the surface. */
+gceSTATUS
+gcoSURF_Unlock(
+ IN gcoSURF Surface,
+ IN gctPOINTER Memory
+ );
+
+/*. Query surface flags.*/
+gceSTATUS
+gcoSURF_QueryFlags(
+ IN gcoSURF Surface,
+ IN gceSURF_FLAG Flag
+ );
+
+gceSTATUS
+gcoSURF_QueryHints(
+ IN gcoSURF Surface,
+ IN gceSURF_TYPE Hints
+ );
+
+/* Return pixel format parameters; Info is required to be a pointer to an
+ * array of at least two items because some formats have up to two records
+ * of description. */
+gceSTATUS
+gcoSURF_QueryFormat(
+ IN gceSURF_FORMAT Format,
+ OUT gcsSURF_FORMAT_INFO_PTR * Info
+ );
+
+/* Compute the color pixel mask. */
+gceSTATUS
+gcoSURF_ComputeColorMask(
+ IN gcsSURF_FORMAT_INFO_PTR Format,
+ OUT gctUINT32_PTR ColorMask
+ );
+
+/* Flush the surface. */
+gceSTATUS
+gcoSURF_Flush(
+ IN gcoSURF Surface
+ );
+
+/* Fill surface from it's tile status buffer. */
+gceSTATUS
+gcoSURF_FillFromTile(
+ IN gcsSURF_VIEW *SurView
+ );
+
+/* Fill surface with a value. */
+gceSTATUS
+gcoSURF_Fill(
+ IN gcoSURF Surface,
+ IN gcsPOINT_PTR Origin,
+ IN gcsSIZE_PTR Size,
+ IN gctUINT32 Value,
+ IN gctUINT32 Mask
+ );
+
+/* Alpha blend two surfaces together. */
+gceSTATUS
+gcoSURF_Blend(
+ IN gcoSURF SrcSurf,
+ IN gcoSURF DstSurf,
+ IN gcsPOINT_PTR SrcOrigin,
+ IN gcsPOINT_PTR DstOrigin,
+ IN gcsSIZE_PTR Size,
+ IN gceSURF_BLEND_MODE Mode
+ );
+
+/* Create a new gcoSURF wrapper object. */
+gceSTATUS
+gcoSURF_ConstructWrapper(
+ IN gcoHAL Hal,
+ OUT gcoSURF * Surface
+ );
+
+/* Set surface flags.*/
+gceSTATUS
+gcoSURF_SetFlags(
+ IN gcoSURF Surface,
+ IN gceSURF_FLAG Flag,
+ IN gctBOOL Value
+ );
+
+/* Set the underlying buffer for the surface wrapper. */
+gceSTATUS
+gcoSURF_SetBuffer(
+ IN gcoSURF Surface,
+ IN gceSURF_TYPE Type,
+ IN gceSURF_FORMAT Format,
+ IN gctUINT Stride,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Physical
+ );
+
+/* Set the size of the surface in pixels and map the underlying buffer. */
+gceSTATUS
+gcoSURF_SetWindow(
+ IN gcoSURF Surface,
+ IN gctUINT X,
+ IN gctUINT Y,
+ IN gctUINT Width,
+ IN gctUINT Height
+ );
+
+/* Set the size of the surface in pixels and map the underlying buffer. */
+gceSTATUS
+gcoSURF_SetImage(
+ IN gcoSURF Surface,
+ IN gctUINT X,
+ IN gctUINT Y,
+ IN gctUINT Width,
+ IN gctUINT Height,
+ IN gctUINT Depth
+ );
+
+/* Set width/height alignment of the surface directly and calculate stride/size. This is only for dri backend now. Please be careful before use. */
+gceSTATUS
+gcoSURF_SetAlignment(
+ IN gcoSURF Surface,
+ IN gctUINT Width,
+ IN gctUINT Height
+ );
+
+/* Increase reference count of the surface. */
+gceSTATUS
+gcoSURF_ReferenceSurface(
+ IN gcoSURF Surface
+ );
+
+/* Get surface reference count. */
+gceSTATUS
+gcoSURF_QueryReferenceCount(
+ IN gcoSURF Surface,
+ OUT gctINT32 * ReferenceCount
+ );
+
+/* Set surface orientation. */
+gceSTATUS
+gcoSURF_SetOrientation(
+ IN gcoSURF Surface,
+ IN gceORIENTATION Orientation
+ );
+
+/* Query surface orientation. */
+gceSTATUS
+gcoSURF_QueryOrientation(
+ IN gcoSURF Surface,
+ OUT gceORIENTATION * Orientation
+ );
+
+gceSTATUS
+gcoSURF_NODE_Cache(
+ IN gcsSURF_NODE_PTR Node,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes,
+ IN gceCACHEOPERATION Operation
+ );
+
+gceSTATUS
+gcsSURF_NODE_SetHardwareAddress(
+ IN gcsSURF_NODE_PTR Node,
+ IN gctUINT32 Address
+ );
+
+gceSTATUS
+gcsSURF_NODE_GetHardwareAddress(
+ IN gcsSURF_NODE_PTR Node,
+ OUT gctUINT32_PTR Physical,
+ OUT gctUINT32_PTR Physical2,
+ OUT gctUINT32_PTR Physical3,
+ OUT gctUINT32_PTR PhysicalBottom
+ );
+
+gctUINT32
+gcsSURF_NODE_GetHWAddress(
+ IN gcsSURF_NODE_PTR Node
+ );
+
+/* Lock and unlock surface node */
+gceSTATUS
+gcoSURF_LockNode(
+ IN gcsSURF_NODE_PTR Node,
+ OUT gctUINT32 * Address,
+ OUT gctPOINTER * Memory
+ );
+
+gceSTATUS
+gcoSURF_UnLockNode(
+ IN gcsSURF_NODE_PTR Node,
+ IN gceSURF_TYPE Type
+ );
+
+/* Perform CPU cache operation on surface node */
+gceSTATUS
+gcoSURF_NODE_CPUCacheOperation(
+ IN gcsSURF_NODE_PTR Node,
+ IN gceSURF_TYPE Type,
+ IN gctSIZE_T Offset,
+ IN gctSIZE_T Length,
+ IN gceCACHEOPERATION Operation
+ );
+
+/* Perform CPU cache operation on surface */
+gceSTATUS
+gcoSURF_CPUCacheOperation(
+ IN gcoSURF Surface,
+ IN gceCACHEOPERATION Operation
+ );
+
+
+gceSTATUS
+gcoSURF_Swap(
+ IN gcoSURF Surface1,
+ IN gcoSURF Surface2
+ );
+
+gceSTATUS
+gcoSURF_ResetSurWH(
+ IN gcoSURF Surface,
+ IN gctUINT oriw,
+ IN gctUINT orih,
+ IN gctUINT alignw,
+ IN gctUINT alignh,
+ IN gceSURF_FORMAT fmt
+);
+
+/* Update surface timestamp. */
+gceSTATUS
+gcoSURF_UpdateTimeStamp(
+ IN gcoSURF Surface
+ );
+
+/* Query surface current timestamp. */
+gceSTATUS
+gcoSURF_QueryTimeStamp(
+ IN gcoSURF Surface,
+ OUT gctUINT64 * TimeStamp
+ );
+
+/*
+ * Allocate shared buffer for this surface, so that
+ * surface states can be shared across processes.
+ */
+gceSTATUS
+gcoSURF_AllocShBuffer(
+ IN gcoSURF Surface,
+ OUT gctSHBUF * ShBuf
+ );
+
+/* Bind shared buffer to this surface */
+gceSTATUS
+gcoSURF_BindShBuffer(
+ IN gcoSURF Surface,
+ IN gctSHBUF ShBuf
+ );
+
+/* Push surface shared states to shared buffer. */
+gceSTATUS
+gcoSURF_PushSharedInfo(
+ IN gcoSURF Surface
+ );
+
+/* Pop shared states from shared buffer. */
+gceSTATUS
+gcoSURF_PopSharedInfo(
+ IN gcoSURF Surface
+ );
+
+#if (gcdENABLE_3D || gcdENABLE_VG)
+/* Copy surface. */
+gceSTATUS
+gcoSURF_Copy(
+ IN gcoSURF Surface,
+ IN gcoSURF Source
+ );
+
+/* Set number of samples for a gcoSURF object. */
+gceSTATUS
+gcoSURF_SetSamples(
+ IN gcoSURF Surface,
+ IN gctUINT Samples
+ );
+
+/* Get the number of samples per pixel. */
+gceSTATUS
+gcoSURF_GetSamples(
+ IN gcoSURF Surface,
+ OUT gctUINT_PTR Samples
+ );
+
+/* Append tile status buffer to user pool surface. */
+gceSTATUS
+gcoSURF_AppendTileStatus(
+ IN gcoSURF Surface
+ );
+#endif
+
+gceSTATUS
+gcoSURF_WrapUserMemory(
+ IN gcoHAL Hal,
+ IN gctUINT Width,
+ IN gctUINT Height,
+ IN gctUINT Stride,
+ IN gctUINT Depth,
+ IN gceSURF_TYPE Type,
+ IN gceSURF_FORMAT Format,
+ IN gctUINT32 Handle,
+ IN gctUINT32 Flag,
+ OUT gcoSURF * Surface
+ );
+
+gceSTATUS
+gcoSURF_WrapUserMultiBuffer(
+ IN gcoHAL Hal,
+ IN gctUINT Width,
+ IN gctUINT Height,
+ IN gceSURF_TYPE Type,
+ IN gceSURF_FORMAT Format,
+ IN gctUINT Stride[3],
+ IN gctUINT32 Handle[3],
+ IN gctUINT BufferOffset[3],
+ IN gctUINT32 Flag,
+ OUT gcoSURF * Surface
+ );
+
+#define MAX_SURF_MIX_SRC_NUM 64
+gceSTATUS
+gcoSURF_MixSurfacesCPU(
+ IN gcoSURF TargetSurface,
+ IN gctUINT TargetSliceIndex,
+ IN gcoSURF *SourceSurface,
+ IN gctUINT *SourceSliceIndices,
+ IN gctFLOAT *Weights,
+ IN gctINT Count
+ );
+
+
+/******************************************************************************\
+********************************* gcoDUMP Object ********************************
+\******************************************************************************/
+
+/* Construct a new gcoDUMP object. */
+gceSTATUS
+gcoDUMP_Construct(
+ IN gcoOS Os,
+ IN gcoHAL Hal,
+ OUT gcoDUMP * Dump
+ );
+
+/* Destroy a gcoDUMP object. */
+gceSTATUS
+gcoDUMP_Destroy(
+ IN gcoDUMP Dump
+ );
+
+/* Enable/disable dumping. */
+gceSTATUS
+gcoDUMP_Control(
+ IN gcoDUMP Dump,
+ IN gctSTRING FileName
+ );
+
+gceSTATUS
+gcoDUMP_IsEnabled(
+ IN gcoDUMP Dump,
+ OUT gctBOOL * Enabled
+ );
+
+/* Add surface. */
+gceSTATUS
+gcoDUMP_AddSurface(
+ IN gcoDUMP Dump,
+ IN gctINT32 Width,
+ IN gctINT32 Height,
+ IN gceSURF_FORMAT PixelFormat,
+ IN gctUINT32 Address,
+ IN gctSIZE_T ByteCount
+ );
+
+/* Mark the beginning of a frame. */
+gceSTATUS
+gcoDUMP_FrameBegin(
+ IN gcoDUMP Dump
+ );
+
+/* Mark the end of a frame. */
+gceSTATUS
+gcoDUMP_FrameEnd(
+ IN gcoDUMP Dump
+ );
+
+/* Dump data. */
+gceSTATUS
+gcoDUMP_DumpData(
+ IN gcoDUMP Dump,
+ IN gceDUMP_TAG Type,
+ IN gctUINT32 Address,
+ IN gctSIZE_T ByteCount,
+ IN gctCONST_POINTER Data
+ );
+
+/* Delete an address. */
+gceSTATUS
+gcoDUMP_Delete(
+ IN gcoDUMP Dump,
+ IN gctUINT32 Address
+ );
+
+/* Enable dump or not. */
+gceSTATUS
+gcoDUMP_SetDumpFlag(
+ IN gctBOOL DumpState
+ );
+
+/******************************************************************************\
+******************************* gcsRECT Structure ******************************
+\******************************************************************************/
+
+/* Initialize rectangle structure. */
+gceSTATUS
+gcsRECT_Set(
+ OUT gcsRECT_PTR Rect,
+ IN gctINT32 Left,
+ IN gctINT32 Top,
+ IN gctINT32 Right,
+ IN gctINT32 Bottom
+ );
+
+/* Return the width of the rectangle. */
+gceSTATUS
+gcsRECT_Width(
+ IN gcsRECT_PTR Rect,
+ OUT gctINT32 * Width
+ );
+
+/* Return the height of the rectangle. */
+gceSTATUS
+gcsRECT_Height(
+ IN gcsRECT_PTR Rect,
+ OUT gctINT32 * Height
+ );
+
+/* Ensure that top left corner is to the left and above the right bottom. */
+gceSTATUS
+gcsRECT_Normalize(
+ IN OUT gcsRECT_PTR Rect
+ );
+
+/* Compare two rectangles. */
+gceSTATUS
+gcsRECT_IsEqual(
+ IN gcsRECT_PTR Rect1,
+ IN gcsRECT_PTR Rect2,
+ OUT gctBOOL * Equal
+ );
+
+/* Compare the sizes of two rectangles. */
+gceSTATUS
+gcsRECT_IsOfEqualSize(
+ IN gcsRECT_PTR Rect1,
+ IN gcsRECT_PTR Rect2,
+ OUT gctBOOL * EqualSize
+ );
+
+gceSTATUS
+gcsRECT_RelativeRotation(
+ IN gceSURF_ROTATION Orientation,
+ IN OUT gceSURF_ROTATION *Relation);
+
+gceSTATUS
+
+gcsRECT_Rotate(
+
+ IN OUT gcsRECT_PTR Rect,
+
+ IN gceSURF_ROTATION Rotation,
+
+ IN gceSURF_ROTATION toRotation,
+
+ IN gctINT32 SurfaceWidth,
+
+ IN gctINT32 SurfaceHeight
+
+ );
+
+/******************************************************************************\
+**************************** gcsBOUNDARY Structure *****************************
+\******************************************************************************/
+
+typedef struct _gcsBOUNDARY
+{
+ gctINT x;
+ gctINT y;
+ gctINT width;
+ gctINT height;
+}
+gcsBOUNDARY;
+
+/******************************************************************************\
+********************************* gcoHEAP Object ********************************
+\******************************************************************************/
+
+typedef struct _gcoHEAP * gcoHEAP;
+
+/* Construct a new gcoHEAP object. */
+gceSTATUS
+gcoHEAP_Construct(
+ IN gcoOS Os,
+ IN gctSIZE_T AllocationSize,
+ OUT gcoHEAP * Heap
+ );
+
+/* Destroy an gcoHEAP object. */
+gceSTATUS
+gcoHEAP_Destroy(
+ IN gcoHEAP Heap
+ );
+
+/* Allocate memory. */
+gceSTATUS
+gcoHEAP_Allocate(
+ IN gcoHEAP Heap,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Node
+ );
+
+gceSTATUS
+gcoHEAP_GetMemorySize(
+ IN gcoHEAP Heap,
+ IN gctPOINTER Memory,
+ OUT gctSIZE_T_PTR MemorySize
+ );
+
+/* Free memory. */
+gceSTATUS
+gcoHEAP_Free(
+ IN gcoHEAP Heap,
+ IN gctPOINTER Node
+ );
+
+#if (VIVANTE_PROFILER || gcdDEBUG)
+/* Profile the heap. */
+gceSTATUS
+gcoHEAP_ProfileStart(
+ IN gcoHEAP Heap
+ );
+
+gceSTATUS
+gcoHEAP_ProfileEnd(
+ IN gcoHEAP Heap,
+ IN gctCONST_STRING Title
+ );
+#endif
+
+
+/******************************************************************************\
+******************************* Debugging Macros *******************************
+\******************************************************************************/
+
+void
+gcoOS_SetDebugLevel(
+ IN gctUINT32 Level
+ );
+
+void
+gcoOS_GetDebugLevel(
+ OUT gctUINT32_PTR DebugLevel
+ );
+
+void
+gcoOS_SetDebugZone(
+ IN gctUINT32 Zone
+ );
+
+void
+gcoOS_GetDebugZone(
+ IN gctUINT32 Zone,
+ OUT gctUINT32_PTR DebugZone
+ );
+
+void
+gcoOS_SetDebugLevelZone(
+ IN gctUINT32 Level,
+ IN gctUINT32 Zone
+ );
+
+void
+gcoOS_SetDebugZones(
+ IN gctUINT32 Zones,
+ IN gctBOOL Enable
+ );
+
+void
+gcoOS_SetDebugFile(
+ IN gctCONST_STRING FileName
+ );
+
+gctFILE
+gcoOS_ReplaceDebugFile(
+ IN gctFILE fp
+ );
+
+/*******************************************************************************
+**
+** gcmFATAL
+**
+** Print a message to the debugger and execute a break point.
+**
+** ARGUMENTS:
+**
+** message Message.
+** ... Optional arguments.
+*/
+
+void
+gckOS_DebugFatal(
+ IN gctCONST_STRING Message,
+ ...
+ );
+
+void
+gcoOS_DebugFatal(
+ IN gctCONST_STRING Message,
+ ...
+ );
+
+#if gcmIS_DEBUG(gcdDEBUG_FATAL)
+# define gcmFATAL gcoOS_DebugFatal
+# define gcmkFATAL gckOS_DebugFatal
+#elif gcdHAS_ELLIPSIS
+# define gcmFATAL(...)
+# define gcmkFATAL(...)
+#else
+ gcmINLINE static void
+ __dummy_fatal(
+ IN gctCONST_STRING Message,
+ ...
+ )
+ {
+ }
+# define gcmFATAL __dummy_fatal
+# define gcmkFATAL __dummy_fatal
+#endif
+
+#define gcmENUM2TEXT(e) case e: return #e
+
+/*******************************************************************************
+**
+** gcmTRACE
+**
+** Print a message to the debugfer if the correct level has been set. In
+** retail mode this macro does nothing.
+**
+** ARGUMENTS:
+**
+** level Level of message.
+** message Message.
+** ... Optional arguments.
+*/
+#define gcvLEVEL_NONE -1
+#define gcvLEVEL_ERROR 0
+#define gcvLEVEL_WARNING 1
+#define gcvLEVEL_INFO 2
+#define gcvLEVEL_VERBOSE 3
+
+void
+gckOS_DebugTrace(
+ IN gctUINT32 Level,
+ IN gctCONST_STRING Message,
+ ...
+ );
+
+void
+gckOS_DebugTraceN(
+ IN gctUINT32 Level,
+ IN gctUINT ArgumentSize,
+ IN gctCONST_STRING Message,
+ ...
+ );
+
+void
+gcoOS_DebugTrace(
+ IN gctUINT32 Level,
+ IN gctCONST_STRING Message,
+ ...
+ );
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+# define gcmTRACE gcoOS_DebugTrace
+# define gcmkTRACE gckOS_DebugTrace
+# define gcmkTRACE_N gckOS_DebugTraceN
+#elif gcdHAS_ELLIPSIS
+# define gcmTRACE(...)
+# define gcmkTRACE(...)
+# define gcmkTRACE_N(...)
+#else
+ gcmINLINE static void
+ __dummy_trace(
+ IN gctUINT32 Level,
+ IN gctCONST_STRING Message,
+ ...
+ )
+ {
+ }
+
+ gcmINLINE static void
+ __dummy_trace_n(
+ IN gctUINT32 Level,
+ IN gctUINT ArgumentSize,
+ IN gctCONST_STRING Message,
+ ...
+ )
+ {
+ }
+
+# define gcmTRACE __dummy_trace
+# define gcmkTRACE __dummy_trace
+# define gcmkTRACE_N __dummy_trace_n
+#endif
+
+/* Zones common for kernel and user. */
+#define gcvZONE_OS (1 << 0)
+#define gcvZONE_HARDWARE (1 << 1)
+#define gcvZONE_HEAP (1 << 2)
+#define gcvZONE_SIGNAL (1 << 3)
+
+/* Kernel zones. */
+#define gcvZONE_KERNEL (1 << 4)
+#define gcvZONE_VIDMEM (1 << 5)
+#define gcvZONE_COMMAND (1 << 6)
+#define gcvZONE_DRIVER (1 << 7)
+#define gcvZONE_CMODEL (1 << 8)
+#define gcvZONE_MMU (1 << 9)
+#define gcvZONE_EVENT (1 << 10)
+#define gcvZONE_DEVICE (1 << 11)
+#define gcvZONE_DATABASE (1 << 12)
+#define gcvZONE_INTERRUPT (1 << 13)
+#define gcvZONE_POWER (1 << 14)
+#define gcvZONE_ASYNC_COMMAND (1 << 15)
+#define gcvZONE_ALLOCATOR (1 << 16)
+
+/* User zones. */
+#define gcvZONE_HAL (1 << 4)
+#define gcvZONE_BUFFER (1 << 5)
+#define gcvZONE_CONTEXT (1 << 6)
+#define gcvZONE_SURFACE (1 << 7)
+#define gcvZONE_INDEX (1 << 8)
+#define gcvZONE_STREAM (1 << 9)
+#define gcvZONE_TEXTURE (1 << 10)
+#define gcvZONE_2D (1 << 11)
+#define gcvZONE_3D (1 << 12)
+#define gcvZONE_COMPILER (1 << 13)
+#define gcvZONE_MEMORY (1 << 14)
+#define gcvZONE_STATE (1 << 15)
+#define gcvZONE_AUX (1 << 16)
+#define gcvZONE_VERTEX (1 << 17)
+#define gcvZONE_CL (1 << 18)
+#define gcvZONE_VG (1 << 19)
+#define gcvZONE_VX (1 << 20)
+#define gcvZONE_IMAGE (1 << 21)
+#define gcvZONE_UTILITY (1 << 22)
+#define gcvZONE_PARAMETERS (1 << 23)
+#define gcvZONE_BUFOBJ (1 << 24)
+#define gcvZONE_SHADER (1 << 25)
+#define gcvZONE_STREAM_OUT (1 << 26)
+
+/* API definitions. */
+#define gcvZONE_API_HAL ((gctUINT32) 1 << 28)
+#define gcvZONE_API_EGL ((gctUINT32) 2 << 28)
+#define gcvZONE_API_ES11 ((gctUINT32) 3 << 28)
+#define gcvZONE_API_ES20 ((gctUINT32) 4 << 28)
+#define gcvZONE_API_ES30 ((gctUINT32) 4 << 28)
+#define gcvZONE_API_VG11 ((gctUINT32) 5 << 28)
+#define gcvZONE_API_GL ((gctUINT32) 6 << 28)
+#define gcvZONE_API_DFB ((gctUINT32) 7 << 28)
+#define gcvZONE_API_GDI ((gctUINT32) 8 << 28)
+#define gcvZONE_API_D3D ((gctUINT32) 9 << 28)
+#define gcvZONE_API_CL ((gctUINT32) 10 << 28)
+#define gcvZONE_API_VX ((gctUINT32) 11 << 28)
+
+
+#define gcmZONE_GET_API(zone) ((zone) >> 28)
+/*Set gcdZONE_MASE like 0x0 | gcvZONE_API_EGL
+will enable print EGL module debug info*/
+#define gcdZONE_MASK 0x0FFFFFFF
+
+/* Handy zones. */
+#define gcvZONE_NONE 0
+#define gcvZONE_ALL 0x0FFFFFFF
+
+/*Dump API depth set 1 for API, 2 for API and API behavior*/
+#define gcvDUMP_API_DEPTH 1
+
+
+/*******************************************************************************
+**
+** gcmTRACE_ZONE
+**
+** Print a message to the debugger if the correct level and zone has been
+** set. In retail mode this macro does nothing.
+**
+** ARGUMENTS:
+**
+** Level Level of message.
+** Zone Zone of message.
+** Message Message.
+** ... Optional arguments.
+*/
+
+void
+gckOS_DebugTraceZone(
+ IN gctUINT32 Level,
+ IN gctUINT32 Zone,
+ IN gctCONST_STRING Message,
+ ...
+ );
+
+void
+gckOS_DebugTraceZoneN(
+ IN gctUINT32 Level,
+ IN gctUINT32 Zone,
+ IN gctUINT ArgumentSize,
+ IN gctCONST_STRING Message,
+ ...
+ );
+
+void
+gcoOS_DebugTraceZone(
+ IN gctUINT32 Level,
+ IN gctUINT32 Zone,
+ IN gctCONST_STRING Message,
+ ...
+ );
+
+#if gcmIS_DEBUG(gcdDEBUG_TRACE)
+# define gcmTRACE_ZONE gcoOS_DebugTraceZone
+# define gcmkTRACE_ZONE gckOS_DebugTraceZone
+# define gcmkTRACE_ZONE_N gckOS_DebugTraceZoneN
+#elif gcdHAS_ELLIPSIS
+# define gcmTRACE_ZONE(...)
+# define gcmkTRACE_ZONE(...)
+# define gcmkTRACE_ZONE_N(...)
+#else
+ gcmINLINE static void
+ __dummy_trace_zone(
+ IN gctUINT32 Level,
+ IN gctUINT32 Zone,
+ IN gctCONST_STRING Message,
+ ...
+ )
+ {
+ }
+
+ gcmINLINE static void
+ __dummy_trace_zone_n(
+ IN gctUINT32 Level,
+ IN gctUINT32 Zone,
+ IN gctUINT ArgumentSize,
+ IN gctCONST_STRING Message,
+ ...
+ )
+ {
+ }
+
+# define gcmTRACE_ZONE __dummy_trace_zone
+# define gcmkTRACE_ZONE __dummy_trace_zone
+# define gcmkTRACE_ZONE_N __dummy_trace_zone_n
+#endif
+
+
+/*******************************************************************************
+**
+** gcmDEBUG_ONLY
+**
+** Execute a statement or function only in DEBUG mode.
+**
+** ARGUMENTS:
+**
+** f Statement or function to execute.
+*/
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+# define gcmDEBUG_ONLY(f) f
+#else
+# define gcmDEBUG_ONLY(f)
+#endif
+
+
+/*******************************************************************************
+**
+** gcmSTACK_PUSH
+** gcmSTACK_POP
+** gcmSTACK_DUMP
+** gcmSTACK_REMOVE
+**
+** Push or pop a function with entry arguments on the trace stack.
+**
+** ARGUMENTS:
+**
+** Function Name of function.
+** Line Line number.
+** Text Optional text.
+** ... Optional arguments for text.
+**
+** Thread Thread id.
+*/
+void
+gcoOS_StackPush(
+ IN gctINT8_PTR Identity,
+ IN gctCONST_STRING Function,
+ IN gctINT Line,
+ IN gctCONST_STRING Text,
+ ...
+ );
+
+void
+gcoOS_StackPop(
+ IN gctINT8_PTR Identity,
+ IN gctCONST_STRING Function
+ );
+
+void
+gcoOS_StackDump(
+ void);
+
+void
+gcoOS_StackRemove(
+ IN gctHANDLE Thread
+ );
+
+#if gcmIS_DEBUG(gcdDEBUG_STACK)
+# define gcmSTACK_PUSH gcoOS_StackPush
+# define gcmSTACK_POP gcoOS_StackPop
+# define gcmSTACK_DUMP gcoOS_StackDump
+# define gcmSTACK_REMOVE gcoOS_StackRemove
+#elif gcdHAS_ELLIPSIS
+# define gcmSTACK_PUSH(...)
+# define gcmSTACK_POP(...)
+# define gcmSTACK_DUMP()
+# define gcmSTACK_REMOVE(...)
+#else
+ gcmINLINE static void
+ __dummy_stack_push(
+ IN gctCONST_STRING Function,
+ IN gctINT Line,
+ IN gctCONST_STRING Text,
+ ...
+ )
+ {
+ }
+
+ gcmINLINE static void
+ __dummy_stack_pop(
+ IN gctINT8_PTR Identity,
+ IN gctCONST_STRING Function
+ );
+
+ gcmINLINE static void
+ __dummy_stack_remove(
+ IN gctHANDLE Thread
+ );
+
+# define gcmSTACK_PUSH __dummy_stack_push
+# define gcmSTACK_POP(a,b) __dummy_stack_pop
+# define gcmSTACK_DUMP()
+# define gcmSTACK_REMOVE(a) __dummy_stack_remove
+#endif
+
+
+/*******************************************************************************
+**
+** gcmBINARY_TRACE
+**
+** Push or pop a function with entry arguments on the trace stack.
+**
+** ARGUMENTS:
+**
+** Function Name of function
+** Line Line number
+** Text Optional text
+** ... Optional arguments for text.
+*/
+typedef struct _gcsBINARY_TRACE_MESSAGE * gcsBINARY_TRACE_MESSAGE_PTR;
+typedef struct _gcsBINARY_TRACE_MESSAGE
+{
+ gctUINT32 signature;
+ gctUINT32 pid;
+ gctUINT32 tid;
+ gctUINT32 line;
+ gctUINT32 numArguments;
+ gctUINT8 payload;
+}
+gcsBINARY_TRACE_MESSAGE;
+
+void
+gcoOS_BinaryTrace(
+ IN gctCONST_STRING Function,
+ IN gctINT Line,
+ IN gctCONST_STRING Text OPTIONAL,
+ ...
+ );
+
+void
+gckOS_BinaryTrace(
+ IN gctCONST_STRING Function,
+ IN gctINT Line,
+ IN gctCONST_STRING Text OPTIONAL,
+ ...
+ );
+
+#define gcdBINARY_TRACE_MESSAGE_SIZE 240
+
+#if gcdBINARY_TRACE
+# define gcmBINARY_TRACE gcoOS_BinaryTrace
+# define gcmkBINARY_TRACE gckOS_BinaryTrace
+#elif gcdHAS_ELLIPSIS
+# define gcmBINARY_TRACE(Function, Line, Text, ...)
+# define gcmkBINARY_TRACE(Function, Line, Text, ...)
+#else
+ gcmINLINE static void
+ __dummy_binary_trace(
+ IN gctCONST_STRING Function,
+ IN gctINT Line,
+ IN gctCONST_STRING Text,
+ )
+ {
+ }
+
+# define gcmBINARY_TRACE __dummy_binary_trace
+# define gcmkBINARY_TRACE __dummy_binary_trace
+#endif
+
+
+/*******************************************************************************
+**
+** gcmSYSTRACE_BEGIN
+** gcmSYSTRACE_END
+**
+** Systrace is a performance tunning tool on linux.
+**
+** ARGUMENTS:
+**
+** FuncName Function name
+** Zone Systrace zone. Only specified zones are traced.
+*/
+
+void
+gcoOS_SysTraceBegin(
+ IN gctUINT32 Zone,
+ IN gctCONST_STRING FuncName
+ );
+
+void
+gcoOS_SysTraceEnd(
+ IN gctUINT32 Zone
+ );
+
+#if defined(LINUX) && gcdSYSTRACE
+# define gcmSYSTRACE_BEGIN gcoOS_SysTraceBegin
+# define gcmSYSTRACE_END gcoOS_SysTraceEnd
+#elif gcdHAS_ELLIPSIS
+# define gcmSYSTRACE_BEGIN(...)
+# define gcmSYSTRACE_END(...)
+#else
+ gcmINLINE static void
+ __dummy_systrace_begin(
+ IN gctUINT32 Zone,
+ IN gctCONST_STRING FuncName
+ )
+ {
+ }
+
+ gcmINLINE static void
+ __dummy_systrace_end(
+ IN gctUINT32 Zone
+ )
+ {
+ }
+
+# define gcmSYSTRACE_BEGIN __dummy_systrace_begin
+# define gcmSYSTRACE_END __dummy_systrace_end
+#endif
+
+
+/******************************************************************************\
+******************************** Logging Macros ********************************
+\******************************************************************************/
+
+#define gcdHEADER_LEVEL gcvLEVEL_VERBOSE
+
+/* Always enable header/footer when systrace build is on */
+#if defined(LINUX) && gcdSYSTRACE
+#undef gcdEMPTY_HEADER_FOOTER
+#endif
+
+#ifndef gcdEMPTY_HEADER_FOOTER
+#define gcdEMPTY_HEADER_FOOTER 0
+#endif
+
+#if gcdENABLE_PROFILING
+void
+gcoOS_ProfileDB(
+ IN gctCONST_STRING Function,
+ IN OUT gctBOOL_PTR Initialized
+ );
+
+#define gcmHEADER() \
+ gctINT8 __user__ = 1; \
+ static gctBOOL __profile__initialized__ = gcvFALSE; \
+ gcmSTACK_PUSH(&__user__, __FUNCTION__, __LINE__, gcvNULL, gcvNULL); \
+ gcoOS_ProfileDB(__FUNCTION__, &__profile__initialized__)
+
+#define gcmHEADER_ARG(...) \
+ gctINT8 __user__ = 1; \
+ static gctBOOL __profile__initialized__ = gcvFALSE; \
+ gcmSTACK_PUSH(&__user__, __FUNCTION__, __LINE__, Text, __VA_ARGS__); \
+ gcoOS_ProfileDB(__FUNCTION__, &__profile__initialized__)
+
+#define gcmFOOTER() \
+ gcmSTACK_POP(&__user__, __FUNCTION__); \
+ gcoOS_ProfileDB(__FUNCTION__, gcvNULL)
+
+#define gcmFOOTER_NO() \
+ gcmSTACK_POP(&__user__, __FUNCTION__); \
+ gcoOS_ProfileDB(__FUNCTION__, gcvNULL)
+
+#define gcmFOOTER_ARG(...) \
+ gcmSTACK_POP(&__user__, __FUNCTION__); \
+ gcoOS_ProfileDB(__FUNCTION__, gcvNULL)
+
+#define gcmFOOTER_KILL() \
+ gcmSTACK_POP(&__user__, __FUNCTION__); \
+ gcoOS_ProfileDB(gcvNULL, gcvNULL)
+
+#else /* !gcdENABLE_PROFILING */
+
+#if gcdEMPTY_HEADER_FOOTER
+# define gcmHEADER()
+#elif gcdHAS_ELLIPSIS
+#define gcmHEADER() \
+ gctINT8 __user__ = 1; \
+ gctINT8_PTR __user_ptr__ = &__user__; \
+ gcmSTACK_PUSH(__user_ptr__, __FUNCTION__, __LINE__, gcvNULL, gcvNULL); \
+ gcmSYSTRACE_BEGIN(_GC_OBJ_ZONE, __FUNCTION__); \
+ gcmBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \
+ gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+ "++%s(%d)", __FUNCTION__, __LINE__)
+#else
+ gcmINLINE static void
+ __dummy_header(void)
+ {
+ }
+# define gcmHEADER __dummy_header
+#endif
+
+#if gcdHAS_ELLIPSIS
+#if gcdEMPTY_HEADER_FOOTER
+# define gcmHEADER_ARG(Text, ...)
+#else
+# define gcmHEADER_ARG(Text, ...) \
+ gctINT8 __user__ = 1; \
+ gctINT8_PTR __user_ptr__ = &__user__; \
+ gcmSTACK_PUSH(__user_ptr__, __FUNCTION__, __LINE__, Text, __VA_ARGS__); \
+ gcmSYSTRACE_BEGIN(_GC_OBJ_ZONE, __FUNCTION__); \
+ gcmBINARY_TRACE(__FUNCTION__, __LINE__, Text, __VA_ARGS__); \
+ gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+ "++%s(%d): " Text, __FUNCTION__, __LINE__, __VA_ARGS__)
+#endif
+#else
+ gcmINLINE static void
+ __dummy_header_arg(
+ IN gctCONST_STRING Text,
+ ...
+ )
+ {
+ }
+# define gcmHEADER_ARG __dummy_header_arg
+#endif
+
+#if gcdEMPTY_HEADER_FOOTER
+# define gcmFOOTER()
+#elif gcdHAS_ELLIPSIS
+# define gcmFOOTER() \
+ gcmSTACK_POP(__user_ptr__, __FUNCTION__); \
+ gcmSYSTRACE_END(_GC_OBJ_ZONE); \
+ gcmBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \
+ gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+ "--%s(%d): status=%d(%s)", \
+ __FUNCTION__, __LINE__, \
+ status, gcmSTATUS2NAME(status)); \
+ *__user_ptr__ -= 1
+#else
+ gcmINLINE static void
+ __dummy_footer(void)
+ {
+ }
+# define gcmFOOTER __dummy_footer
+#endif
+
+#if gcdEMPTY_HEADER_FOOTER
+# define gcmFOOTER_NO()
+#elif gcdHAS_ELLIPSIS
+#define gcmFOOTER_NO() \
+ gcmSTACK_POP(__user_ptr__, __FUNCTION__); \
+ gcmSYSTRACE_END(_GC_OBJ_ZONE); \
+ gcmBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \
+ gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+ "--%s(%d)", __FUNCTION__, __LINE__); \
+ *__user_ptr__ -= 1
+#else
+ gcmINLINE static void
+ __dummy_footer_no(void)
+ {
+ }
+# define gcmFOOTER_NO __dummy_footer_no
+#endif
+
+#if gcdEMPTY_HEADER_FOOTER
+# define gcmFOOTER_KILL()
+#elif gcdHAS_ELLIPSIS
+#define gcmFOOTER_KILL() \
+ gcmSTACK_POP(__user_ptr__, __FUNCTION__); \
+ gcmSYSTRACE_END(_GC_OBJ_ZONE); \
+ gcmBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \
+ gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+ "--%s(%d)", __FUNCTION__, __LINE__); \
+ *__user_ptr__ -= 1
+#else
+ gcmINLINE static void
+ __dummy_footer_kill(void)
+ {
+ }
+# define gcmFOOTER_KILL __dummy_footer_kill
+#endif
+
+#if gcdHAS_ELLIPSIS
+#if gcdEMPTY_HEADER_FOOTER
+# define gcmFOOTER_ARG(Text, ...)
+#else
+# define gcmFOOTER_ARG(Text, ...) \
+ gcmSTACK_POP(__user_ptr__, __FUNCTION__); \
+ gcmSYSTRACE_END(_GC_OBJ_ZONE); \
+ gcmBINARY_TRACE(__FUNCTION__, __LINE__, Text, __VA_ARGS__); \
+ gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+ "--%s(%d): " Text, __FUNCTION__, __LINE__, __VA_ARGS__); \
+ *__user_ptr__ -= 1
+#endif
+#else
+ gcmINLINE static void
+ __dummy_footer_arg(
+ IN gctCONST_STRING Text,
+ ...
+ )
+ {
+ }
+# define gcmFOOTER_ARG __dummy_footer_arg
+#endif
+
+#endif /* gcdENABLE_PROFILING */
+
+#if gcdHAS_ELLIPSIS
+#define gcmkHEADER() \
+ gctINT8 __kernel__ = 1; \
+ gctINT8_PTR __kernel_ptr__ = &__kernel__; \
+ gcmkBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \
+ gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+ "++%s(%d)", __FUNCTION__, __LINE__)
+#else
+ gcmINLINE static void
+ __dummy_kheader(void)
+ {
+ }
+# define gcmkHEADER __dummy_kheader
+#endif
+
+#if gcdHAS_ELLIPSIS
+# define gcmkHEADER_ARG(Text, ...) \
+ gctINT8 __kernel__ = 1; \
+ gctINT8_PTR __kernel_ptr__ = &__kernel__; \
+ gcmkBINARY_TRACE(__FUNCTION__, __LINE__, Text, __VA_ARGS__); \
+ gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+ "++%s(%d): " Text, __FUNCTION__, __LINE__, __VA_ARGS__)
+#else
+ gcmINLINE static void
+ __dummy_kheader_arg(
+ IN gctCONST_STRING Text,
+ ...
+ )
+ {
+ }
+# define gcmkHEADER_ARG __dummy_kheader_arg
+#endif
+
+#if gcdHAS_ELLIPSIS
+#define gcmkFOOTER() \
+ gcmkBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, status); \
+ gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+ "--%s(%d): status=%d(%s)", \
+ __FUNCTION__, __LINE__, status, gcmkSTATUS2NAME(status)); \
+ *__kernel_ptr__ -= 1
+#else
+ gcmINLINE static void
+ __dummy_kfooter(void)
+ {
+ }
+# define gcmkFOOTER __dummy_kfooter
+#endif
+
+#if gcdHAS_ELLIPSIS
+#define gcmkFOOTER_NO() \
+ gcmkBINARY_TRACE(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \
+ gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+ "--%s(%d)", __FUNCTION__, __LINE__); \
+ *__kernel_ptr__ -= 1
+#else
+ gcmINLINE static void
+ __dummy_kfooter_no(void)
+ {
+ }
+# define gcmkFOOTER_NO __dummy_kfooter_no
+#endif
+
+#if gcdHAS_ELLIPSIS
+# define gcmkFOOTER_ARG(Text, ...) \
+ gcmkBINARY_TRACE(__FUNCTION__, __LINE__, Text, __VA_ARGS__); \
+ gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \
+ "--%s(%d): " Text, \
+ __FUNCTION__, __LINE__, __VA_ARGS__); \
+ *__kernel_ptr__ -= 1
+#else
+ gcmINLINE static void
+ __dummy_kfooter_arg(
+ IN gctCONST_STRING Text,
+ ...
+ )
+ {
+ }
+# define gcmkFOOTER_ARG __dummy_kfooter_arg
+#endif
+
+#define gcmOPT_VALUE(ptr) (((ptr) == gcvNULL) ? 0 : *(ptr))
+#define gcmOPT_VALUE_INDEX(ptr, index) (((ptr) == gcvNULL) ? 0 : ptr[index])
+#define gcmOPT_POINTER(ptr) (((ptr) == gcvNULL) ? gcvNULL : *(ptr))
+#define gcmOPT_STRING(ptr) (((ptr) == gcvNULL) ? "(nil)" : (ptr))
+
+void
+gckOS_Print(
+ IN gctCONST_STRING Message,
+ ...
+ );
+
+void
+gckOS_PrintN(
+ IN gctUINT ArgumentSize,
+ IN gctCONST_STRING Message,
+ ...
+ );
+
+void
+gckOS_CopyPrint(
+ IN gctCONST_STRING Message,
+ ...
+ );
+
+void
+gcoOS_Print(
+ IN gctCONST_STRING Message,
+ ...
+ );
+
+#define gcmPRINT gcoOS_Print
+#define gcmkPRINT gckOS_Print
+#define gcmkPRINT_N gckOS_PrintN
+
+#if gcdPRINT_VERSION
+# define gcmPRINT_VERSION() do { \
+ _gcmPRINT_VERSION(gcm); \
+ gcmSTACK_DUMP(); \
+ } while (0)
+# define gcmkPRINT_VERSION() _gcmPRINT_VERSION(gcmk)
+# define _gcmPRINT_VERSION(prefix) \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ "Vivante HAL version %d.%d.%d build %d", \
+ gcvVERSION_MAJOR, gcvVERSION_MINOR, \
+ gcvVERSION_PATCH, gcvVERSION_BUILD)
+#else
+# define gcmPRINT_VERSION() do { gcmSTACK_DUMP(); } while (gcvFALSE)
+# define gcmkPRINT_VERSION() do { } while (gcvFALSE)
+#endif
+
+typedef enum _gceDUMP_BUFFER
+{
+ gcvDUMP_BUFFER_CONTEXT,
+ gcvDUMP_BUFFER_USER,
+ gcvDUMP_BUFFER_KERNEL,
+ gcvDUMP_BUFFER_LINK,
+ gcvDUMP_BUFFER_WAITLINK,
+ gcvDUMP_BUFFER_FROM_USER,
+}
+gceDUMP_BUFFER;
+
+void
+gckOS_DumpBuffer(
+ IN gckOS Os,
+ IN gctPOINTER Buffer,
+ IN gctSIZE_T Size,
+ IN gceDUMP_BUFFER Type,
+ IN gctBOOL CopyMessage
+ );
+
+#define gcmkDUMPBUFFER gckOS_DumpBuffer
+
+#if gcdDUMP_COMMAND
+# define gcmkDUMPCOMMAND(Os, Buffer, Size, Type, CopyMessage) \
+ gcmkDUMPBUFFER(Os, Buffer, Size, Type, CopyMessage)
+#else
+# define gcmkDUMPCOMMAND(Os, Buffer, Size, Type, CopyMessage)
+#endif
+
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+
+void
+gckOS_DebugFlush(
+ gctCONST_STRING CallerName,
+ gctUINT LineNumber,
+ gctUINT32 DmaAddress
+ );
+
+# define gcmkDEBUGFLUSH(DmaAddress) \
+ gckOS_DebugFlush(__FUNCTION__, __LINE__, DmaAddress)
+#else
+# define gcmkDEBUGFLUSH(DmaAddress)
+#endif
+
+/*******************************************************************************
+**
+** gcmDUMP_FRAMERATE
+**
+** Print average frame rate
+**
+*/
+#if gcdDUMP_FRAMERATE
+ gceSTATUS
+ gcfDumpFrameRate(
+ void
+ );
+# define gcmDUMP_FRAMERATE gcfDumpFrameRate
+#elif gcdHAS_ELLIPSIS
+# define gcmDUMP_FRAMERATE(...)
+#else
+ gcmINLINE static void
+ __dummy_dump_frame_rate(
+ void
+ )
+ {
+ }
+# define gcmDUMP_FRAMERATE __dummy_dump_frame_rate
+#endif
+
+
+/*******************************************************************************
+**
+** gcmDUMP
+**
+** Print a dump message.
+**
+** ARGUMENTS:
+**
+** gctSTRING Message.
+**
+** ... Optional arguments.
+*/
+
+#if gcdDUMP || gcdDUMP_2DVG
+ gceSTATUS
+ gcfDump(
+ IN gcoOS Os,
+ IN gctCONST_STRING String,
+ ...
+ );
+# define gcmDUMP gcfDump
+#elif gcdHAS_ELLIPSIS
+# define gcmDUMP(...)
+#else
+ gcmINLINE static void
+ __dummy_dump(
+ IN gcoOS Os,
+ IN gctCONST_STRING Message,
+ ...
+ )
+ {
+ }
+# define gcmDUMP __dummy_dump
+#endif
+
+/*******************************************************************************
+**
+** gcmDUMP_DATA
+**
+** Add data to the dump.
+**
+** ARGUMENTS:
+**
+** gctSTRING Tag
+** Tag for dump.
+**
+** gctPOINTER Logical
+** Logical address of buffer.
+**
+** gctSIZE_T Bytes
+** Number of bytes.
+*/
+
+#if gcdDUMP || gcdDUMP_COMMAND
+ gceSTATUS
+ gcfDumpData(
+ IN gcoOS Os,
+ IN gctSTRING Tag,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ );
+# define gcmDUMP_DATA gcfDumpData
+#elif gcdHAS_ELLIPSIS
+# define gcmDUMP_DATA(...)
+#else
+ gcmINLINE static void
+ __dummy_dump_data(
+ IN gcoOS Os,
+ IN gctSTRING Tag,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ )
+ {
+ }
+# define gcmDUMP_DATA __dummy_dump_data
+#endif
+
+/*******************************************************************************
+**
+** gcmDUMP_BUFFER
+**
+** Print a buffer to the dump.
+**
+** ARGUMENTS:
+**
+** gctSTRING Tag
+** Tag for dump.
+**
+** gctUINT32 Physical
+** Physical address of buffer.
+**
+** gctPOINTER Logical
+** Logical address of buffer.
+**
+** gctUINT32 Offset
+** Offset into buffer.
+**
+** gctSIZE_T Bytes
+** Number of bytes.
+*/
+
+#if gcdDUMP || gcdDUMP_COMMAND || gcdDUMP_2DVG
+gceSTATUS
+gcfDumpBuffer(
+ IN gcoOS Os,
+ IN gctSTRING Tag,
+ IN gctUINT32 Physical,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Offset,
+ IN gctSIZE_T Bytes
+ );
+# define gcmDUMP_BUFFER gcfDumpBuffer
+#elif gcdHAS_ELLIPSIS
+# define gcmDUMP_BUFFER(...)
+#else
+ gcmINLINE static void
+ __dummy_dump_buffer(
+ IN gcoOS Os,
+ IN gctSTRING Tag,
+ IN gctUINT32 Physical,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Offset,
+ IN gctSIZE_T Bytes
+ )
+ {
+ }
+# define gcmDUMP_BUFFER __dummy_dump_buffer
+#endif
+
+#if gcdDUMP
+void
+gcfDumpLock(
+ void
+ );
+# define gcmDUMP_LOCK gcfDumpLock
+#elif gcdHAS_ELLIPSIS
+# define gcmDUMP_LOCK(...)
+#else
+ gcmINLINE static void
+ __dummy_dump_lock(
+ void
+ )
+ {
+ }
+# define gcmDUMP_LOCK __dummy_dump_lock
+#endif
+
+#if gcdDUMP
+void
+gcfDumpUnlock(
+ void
+ );
+# define gcmDUMP_UNLOCK gcfDumpUnlock
+#elif gcdHAS_ELLIPSIS
+# define gcmDUMP_UNLOCK(...)
+#else
+ gcmINLINE static void
+ __dummy_dump_unlock(
+ void
+ )
+ {
+ }
+# define gcmDUMP_UNLOCK __dummy_dump_unlock
+#endif
+
+/*******************************************************************************
+**
+** gcmDUMP_API
+**
+** Print a dump message for a high level API prefixed by the function name.
+**
+** ARGUMENTS:
+**
+** gctSTRING Message.
+**
+** ... Optional arguments.
+*/
+gceSTATUS gcfDumpApi(IN gctCONST_STRING String, ...);
+#if gcdDUMP_API
+# define gcmDUMP_API gcfDumpApi
+#elif gcdHAS_ELLIPSIS
+# define gcmDUMP_API(...)
+#else
+ gcmINLINE static void
+ __dummy_dump_api(
+ IN gctCONST_STRING Message,
+ ...
+ )
+ {
+ }
+# define gcmDUMP_API __dummy_dump_api
+#endif
+
+/*******************************************************************************
+**
+** gcmDUMP_API_ARRAY
+**
+** Print an array of data.
+**
+** ARGUMENTS:
+**
+** gctUINT32_PTR Pointer to array.
+** gctUINT32 Size.
+*/
+gceSTATUS gcfDumpArray(IN gctCONST_POINTER Data, IN gctUINT32 Size);
+#if gcdDUMP_API
+# define gcmDUMP_API_ARRAY gcfDumpArray
+#elif gcdHAS_ELLIPSIS
+# define gcmDUMP_API_ARRAY(...)
+#else
+ gcmINLINE static void
+ __dummy_dump_api_array(
+ IN gctCONST_POINTER Data,
+ IN gctUINT32 Size
+ )
+ {
+ }
+# define gcmDUMP_API_ARRAY __dummy_dump_api_array
+#endif
+
+/*******************************************************************************
+**
+** gcmDUMP_API_ARRAY_TOKEN
+**
+** Print an array of data terminated by a token.
+**
+** ARGUMENTS:
+**
+** gctUINT32_PTR Pointer to array.
+** gctUINT32 Termination.
+*/
+gceSTATUS gcfDumpArrayToken(IN gctCONST_POINTER Data, IN gctUINT32 Termination);
+#if gcdDUMP_API
+# define gcmDUMP_API_ARRAY_TOKEN gcfDumpArrayToken
+#elif gcdHAS_ELLIPSIS
+# define gcmDUMP_API_ARRAY_TOKEN(...)
+#else
+ gcmINLINE static void
+ __dummy_dump_api_array_token(
+ IN gctCONST_POINTER Data,
+ IN gctUINT32 Termination
+ )
+ {
+ }
+# define gcmDUMP_API_ARRAY_TOKEN __dummy_dump_api_array_token
+#endif
+
+/*******************************************************************************
+**
+** gcmDUMP_API_DATA
+**
+** Print an array of bytes.
+**
+** ARGUMENTS:
+**
+** gctCONST_POINTER Pointer to array.
+** gctSIZE_T Size.
+*/
+gceSTATUS gcfDumpApiData(IN gctCONST_POINTER Data, IN gctSIZE_T Size);
+#if gcdDUMP_API
+# define gcmDUMP_API_DATA gcfDumpApiData
+#elif gcdHAS_ELLIPSIS
+# define gcmDUMP_API_DATA(...)
+#else
+ gcmINLINE static void
+ __dummy_dump_api_data(
+ IN gctCONST_POINTER Data,
+ IN gctSIZE_T Size
+ )
+ {
+ }
+# define gcmDUMP_API_DATA __dummy_dump_api_data
+#endif
+
+/*******************************************************************************
+** gcmDUMP_2D_COMMAND
+**
+** Print the 2D command buffer.
+**
+** ARGUMENTS:
+**
+** gctUINT32_PTR Pointer to the command buffer.
+** gctUINT32 Command buffer size.
+*/
+gceSTATUS gcfDump2DCommand(IN gctUINT32_PTR Command, IN gctUINT32 Size);
+#if gcdDUMP_2D
+# define gcmDUMP_2D_COMMAND(cmd, size) \
+ if (Hardware->newDump2DLevel > 1) \
+ gcfDump2DCommand(cmd, size)
+#elif gcdHAS_ELLIPSIS
+# define gcmDUMP_2D_COMMAND(...)
+#else
+ gcmINLINE static void
+ __dummy_dump_2d_command(
+ IN gctUINT32_PTR Command,
+ IN gctUINT32 Size
+ )
+ {
+ }
+# define gcmDUMP_2D_COMMAND __dummy_dump_2d_command
+#endif
+
+/*******************************************************************************
+** gcmDUMP_2D_SURFACE
+**
+** Print the 2D surface memory.
+**
+** ARGUMENTS:
+**
+** gctBOOL Src.
+** gctUINT32 Address.
+*/
+gceSTATUS gcfDump2DSurface(IN gctBOOL Src, IN gctUINT32 Address);
+#if gcdDUMP_2D
+# define gcmDUMP_2D_SURFACE(src, addr) \
+ if (Hardware->newDump2DLevel > 2) \
+ gcfDump2DSurface(src, addr)
+#elif gcdHAS_ELLIPSIS
+# define gcmDUMP_2D_SURFACE(...)
+#else
+ gcmINLINE static void
+ __dummy_dump_2d_surface(
+ IN gctBOOL Src,
+ IN gctUINT32 Address
+ )
+ {
+ }
+# define gcmDUMP_2D_SURFACE __dummy_dump_2d_surface
+#endif
+
+/*******************************************************************************
+** gcmDUMP_ADD_MEMORY_INFO
+**
+** Record the memory info.
+**
+** ARGUMENTS:
+**
+** gctUINT32 Address.
+** gctSIZE_T Size.
+*/
+gceSTATUS gcfAddMemoryInfo(IN gctUINT32 GPUAddress, IN gctPOINTER Logical, IN gctUINT32 Physical, IN gctUINT32 Size);
+#if gcdDUMP_2D
+# define gcmDUMP_ADD_MEMORY_INFO gcfAddMemoryInfo
+#elif gcdHAS_ELLIPSIS
+# define gcmDUMP_ADD_MEMORY_INFO(...)
+#else
+ gcmINLINE static void
+ __dummy_dump_add_memory_info(
+ IN gctUINT32 GPUAddress,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Physical,
+ IN gctUINT32 Size
+ )
+ {
+ }
+# define gcmDUMP_ADD_MEMORY_INFO __dummy_dump_add_memory_info
+#endif
+
+/*******************************************************************************
+** gcmDUMP_DEL_MEMORY_INFO
+**
+** Record the memory info.
+**
+** ARGUMENTS:
+**
+** gctUINT32 Address.
+*/
+gceSTATUS gcfDelMemoryInfo(IN gctUINT32 Address);
+#if gcdDUMP_2D
+# define gcmDUMP_DEL_MEMORY_INFO gcfDelMemoryInfo
+#elif gcdHAS_ELLIPSIS
+# define gcmDUMP_DEL_MEMORY_INFO(...)
+#else
+ gcmINLINE static void
+ __dummy_dump_del_memory_info(
+ IN gctUINT32 Address
+ )
+ {
+ }
+# define gcmDUMP_DEL_MEMORY_INFO __dummy_dump_del_memory_info
+#endif
+
+/*******************************************************************************
+**
+** gcmTRACE_RELEASE
+**
+** Print a message to the shader debugger.
+**
+** ARGUMENTS:
+**
+** message Message.
+** ... Optional arguments.
+*/
+
+#define gcmTRACE_RELEASE gcoOS_DebugShaderTrace
+
+void
+gcoOS_DebugShaderTrace(
+ IN gctCONST_STRING Message,
+ ...
+ );
+
+void
+gcoOS_SetDebugShaderFiles(
+ IN gctCONST_STRING VSFileName,
+ IN gctCONST_STRING FSFileName
+ );
+
+void
+gcoOS_SetDebugShaderFileType(
+ IN gctUINT32 ShaderType
+ );
+
+void
+gcoOS_EnableDebugBuffer(
+ IN gctBOOL Enable
+ );
+
+/*******************************************************************************
+**
+** gcmBREAK
+**
+** Break into the debugger. In retail mode this macro does nothing.
+**
+** ARGUMENTS:
+**
+** None.
+*/
+
+void
+gcoOS_DebugBreak(
+ void
+ );
+
+void
+gckOS_DebugBreak(
+ void
+ );
+
+#if gcmIS_DEBUG(gcdDEBUG_BREAK)
+# define gcmBREAK gcoOS_DebugBreak
+# define gcmkBREAK gckOS_DebugBreak
+#else
+# define gcmBREAK()
+# define gcmkBREAK()
+#endif
+
+/*******************************************************************************
+**
+** gcmASSERT
+**
+** Evaluate an expression and break into the debugger if the expression
+** evaluates to false. In retail mode this macro does nothing.
+**
+** ARGUMENTS:
+**
+** exp Expression to evaluate.
+*/
+#if gcmIS_DEBUG(gcdDEBUG_ASSERT)
+# define _gcmASSERT(prefix, exp) \
+ do \
+ { \
+ if (!(exp)) \
+ { \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ #prefix "ASSERT at %s(%d)", \
+ __FUNCTION__, __LINE__); \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ "(%s)", #exp); \
+ prefix##BREAK(); \
+ } \
+ } \
+ while (gcvFALSE)
+# define gcmASSERT(exp) _gcmASSERT(gcm, exp)
+# define gcmkASSERT(exp) _gcmASSERT(gcmk, exp)
+#else
+# define gcmASSERT(exp)
+# define gcmkASSERT(exp)
+#endif
+
+/*******************************************************************************
+**
+** gcmVERIFY
+**
+** Verify if an expression returns true. If the expression does not
+** evaluates to true, an assertion will happen in debug mode.
+**
+** ARGUMENTS:
+**
+** exp Expression to evaluate.
+*/
+#if gcmIS_DEBUG(gcdDEBUG_ASSERT)
+# define gcmVERIFY(exp) gcmASSERT(exp)
+# define gcmkVERIFY(exp) gcmkASSERT(exp)
+#else
+# define gcmVERIFY(exp) exp
+# define gcmkVERIFY(exp) exp
+#endif
+
+/*******************************************************************************
+**
+** gcmVERIFY_OK
+**
+** Verify a fucntion returns gcvSTATUS_OK. If the function does not return
+** gcvSTATUS_OK, an assertion will happen in debug mode.
+**
+** ARGUMENTS:
+**
+** func Function to evaluate.
+*/
+
+void
+gcoOS_Verify(
+ IN gceSTATUS status
+ );
+
+void
+gckOS_Verify(
+ IN gceSTATUS status
+ );
+
+#if gcmIS_DEBUG(gcdDEBUG_ASSERT)
+# define gcmVERIFY_OK(func) \
+ do \
+ { \
+ gceSTATUS verifyStatus = func; \
+ gcoOS_Verify(verifyStatus); \
+ if (verifyStatus != gcvSTATUS_OK) \
+ { \
+ gcmTRACE( \
+ gcvLEVEL_ERROR, \
+ "gcmVERIFY_OK(%d): function returned %d", \
+ __LINE__, verifyStatus \
+ ); \
+ } \
+ gcmASSERT(verifyStatus == gcvSTATUS_OK); \
+ } \
+ while (gcvFALSE)
+# define gcmkVERIFY_OK(func) \
+ do \
+ { \
+ gceSTATUS verifyStatus = func; \
+ if (verifyStatus != gcvSTATUS_OK) \
+ { \
+ gcmkTRACE( \
+ gcvLEVEL_ERROR, \
+ "gcmkVERIFY_OK(%d): function returned %d", \
+ __LINE__, verifyStatus \
+ ); \
+ } \
+ gckOS_Verify(verifyStatus); \
+ gcmkASSERT(verifyStatus == gcvSTATUS_OK); \
+ } \
+ while (gcvFALSE)
+#else
+# define gcmVERIFY_OK(func) func
+# define gcmkVERIFY_OK(func) func
+#endif
+
+gctCONST_STRING
+gcoOS_DebugStatus2Name(
+ gceSTATUS status
+ );
+
+gctCONST_STRING
+gckOS_DebugStatus2Name(
+ gceSTATUS status
+ );
+
+#if gcmIS_DEBUG(gcdDEBUG)
+# define gcmSTATUS2NAME gcoOS_DebugStatus2Name
+# define gcmkSTATUS2NAME gckOS_DebugStatus2Name
+#else
+# define gcmSTATUS2NAME(status) status
+# define gcmkSTATUS2NAME(status) status
+#endif
+
+/*******************************************************************************
+**
+** gcmERR_BREAK
+**
+** Executes a break statement on error.
+**
+** ASSUMPTIONS:
+**
+** 'status' variable of gceSTATUS type must be defined.
+**
+** ARGUMENTS:
+**
+** func Function to evaluate.
+*/
+#define _gcmERR_BREAK(prefix, func) \
+ status = func; \
+ if (gcmIS_ERROR(status)) \
+ { \
+ prefix##PRINT_VERSION(); \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ #prefix "ERR_BREAK: status=%d(%s) @ %s(%d)", \
+ status, gcmSTATUS2NAME(status), __FUNCTION__, __LINE__); \
+ break; \
+ } \
+ do { } while (gcvFALSE)
+#define _gcmkERR_BREAK(prefix, func) \
+ status = func; \
+ if (gcmIS_ERROR(status)) \
+ { \
+ prefix##PRINT_VERSION(); \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ #prefix "ERR_BREAK: status=%d(%s) @ %s(%d)", \
+ status, gckOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \
+ break; \
+ } \
+ do { } while (gcvFALSE)
+#define gcmERR_BREAK(func) _gcmERR_BREAK(gcm, func)
+#define gcmkERR_BREAK(func) _gcmkERR_BREAK(gcmk, func)
+
+/*******************************************************************************
+**
+** gcmERR_RETURN
+**
+** Executes a return on error.
+**
+** ASSUMPTIONS:
+**
+** 'status' variable of gceSTATUS type must be defined.
+**
+** ARGUMENTS:
+**
+** func Function to evaluate.
+*/
+#define _gcmERR_RETURN(prefix, func) \
+ status = func; \
+ if (gcmIS_ERROR(status)) \
+ { \
+ prefix##PRINT_VERSION(); \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ #prefix "ERR_RETURN: status=%d(%s) @ %s(%d)", \
+ status, gcmSTATUS2NAME(status), __FUNCTION__, __LINE__); \
+ prefix##FOOTER(); \
+ return status; \
+ } \
+ do { } while (gcvFALSE)
+#define _gcmkERR_RETURN(prefix, func) \
+ status = func; \
+ if (gcmIS_ERROR(status)) \
+ { \
+ prefix##PRINT_VERSION(); \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ #prefix "ERR_RETURN: status=%d(%s) @ %s(%d)", \
+ status, gcmkSTATUS2NAME(status), __FUNCTION__, __LINE__); \
+ prefix##FOOTER(); \
+ return status; \
+ } \
+ do { } while (gcvFALSE)
+#define gcmERR_RETURN(func) _gcmERR_RETURN(gcm, func)
+#define gcmkERR_RETURN(func) _gcmkERR_RETURN(gcmk, func)
+
+
+/*******************************************************************************
+**
+** gcmONERROR
+**
+** Jump to the error handler in case there is an error.
+**
+** ASSUMPTIONS:
+**
+** 'status' variable of gceSTATUS type must be defined.
+**
+** ARGUMENTS:
+**
+** func Function to evaluate.
+*/
+#define _gcmONERROR(prefix, func) \
+ do \
+ { \
+ status = func; \
+ if (gcmIS_ERROR(status)) \
+ { \
+ prefix##PRINT_VERSION(); \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ #prefix "ONERROR: status=%d(%s) @ %s(%d)", \
+ status, gcmSTATUS2NAME(status), __FUNCTION__, __LINE__); \
+ goto OnError; \
+ } \
+ } \
+ while (gcvFALSE)
+#define _gcmkONERROR(prefix, func) \
+ do \
+ { \
+ status = func; \
+ if (gcmIS_ERROR(status)) \
+ { \
+ prefix##PRINT_VERSION(); \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ #prefix "ONERROR: status=%d(%s) @ %s(%d)", \
+ status, gcmkSTATUS2NAME(status), __FUNCTION__, __LINE__); \
+ goto OnError; \
+ } \
+ } \
+ while (gcvFALSE)
+#define gcmONERROR(func) _gcmONERROR(gcm, func)
+#define gcmkONERROR(func) _gcmkONERROR(gcmk, func)
+
+#define gcmGET_INDEX_SIZE(type, size) \
+ switch (type) \
+ { \
+ case gcvINDEX_8: \
+ size = 1; \
+ break; \
+ case gcvINDEX_16: \
+ size = 2; \
+ break; \
+ case gcvINDEX_32: \
+ size = 4; \
+ break; \
+ default: \
+ gcmONERROR(gcvSTATUS_INVALID_ARGUMENT); \
+ } \
+
+/*******************************************************************************
+**
+** gcmkSAFECASTSIZET
+**
+** Check wether value of a gctSIZE_T varible beyond the capability
+** of 32bits GPU hardware.
+**
+** ASSUMPTIONS:
+**
+**
+**
+** ARGUMENTS:
+**
+** x A gctUINT32 variable
+** y A gctSIZE_T variable
+*/
+#define gcmkSAFECASTSIZET(x, y) \
+ do \
+ { \
+ gctUINT32 tmp = (gctUINT32)(y); \
+ if (gcmSIZEOF(gctSIZE_T) > gcmSIZEOF(gctUINT32)) \
+ { \
+ gcmkASSERT(tmp <= gcvMAXUINT32); \
+ } \
+ (x) = tmp; \
+ } \
+ while (gcvFALSE)
+
+#define gcmSAFECASTSIZET(x, y) \
+ do \
+ { \
+ gctUINT32 tmp = (gctUINT32)(y); \
+ if (gcmSIZEOF(gctSIZE_T) > gcmSIZEOF(gctUINT32)) \
+ { \
+ gcmASSERT(tmp <= gcvMAXUINT32); \
+ } \
+ (x) = tmp; \
+ } \
+ while (gcvFALSE)
+
+/*******************************************************************************
+**
+** gcmkSAFECASTPHYSADDRT
+**
+** Check whether value of a gctPHYS_ADDR_T variable beyond the capability
+** of 32bits GPU hardware.
+**
+** ASSUMPTIONS:
+**
+**
+**
+** ARGUMENTS:
+**
+** x A gctUINT32 variable
+** y A gctPHYS_ADDR_T variable
+*/
+#define gcmkSAFECASTPHYSADDRT(x, y) \
+ do \
+ { \
+ gctUINT32 tmp = (gctUINT32)(y); \
+ if (gcmSIZEOF(gctPHYS_ADDR_T) > gcmSIZEOF(gctUINT32)) \
+ { \
+ gcmkASSERT(tmp <= gcvMAXUINT32); \
+ } \
+ (x) = tmp; \
+ } \
+ while (gcvFALSE)
+
+/*******************************************************************************
+**
+** gcmSAFECASTPHYSADDRT
+**
+** Check whether value of a gctPHYS_ADDR_T variable beyond the capability
+** of 32bits GPU hardware.
+**
+** ASSUMPTIONS:
+**
+**
+**
+** ARGUMENTS:
+**
+** x A gctUINT32 variable
+** y A gctPHYS_ADDR_T variable
+*/
+#define gcmSAFECASTPHYSADDRT(x, y) \
+ do \
+ { \
+ gctUINT32 tmp = (gctUINT32)(y); \
+ if (gcmSIZEOF(gctPHYS_ADDR_T) > gcmSIZEOF(gctUINT32)) \
+ { \
+ gcmASSERT(tmp <= gcvMAXUINT32); \
+ } \
+ (x) = tmp; \
+ } \
+ while (gcvFALSE)
+
+/*******************************************************************************
+**
+** gcmVERIFY_LOCK
+**
+** Verifies whether the surface is locked.
+**
+** ARGUMENTS:
+**
+** surfaceInfo Pointer to the surface iniformational structure.
+*/
+#define gcmVERIFY_LOCK(surfaceInfo) \
+ if (!surfaceInfo->node.valid) \
+ { \
+ gcmONERROR(gcvSTATUS_MEMORY_UNLOCKED); \
+ } \
+
+/*******************************************************************************
+**
+** gcmVERIFY_NODE_LOCK
+**
+** Verifies whether the surface node is locked.
+**
+** ARGUMENTS:
+**
+** surfaceInfo Pointer to the surface iniformational structure.
+*/
+#define gcmVERIFY_NODE_LOCK(surfaceNode) \
+ if (!(surfaceNode)->valid) \
+ { \
+ status = gcvSTATUS_MEMORY_UNLOCKED; \
+ break; \
+ } \
+ do { } while (gcvFALSE)
+
+/*******************************************************************************
+**
+** gcmBADOBJECT_BREAK
+**
+** Executes a break statement on bad object.
+**
+** ARGUMENTS:
+**
+** obj Object to test.
+** t Expected type of the object.
+*/
+#define gcmBADOBJECT_BREAK(obj, t) \
+ if ((obj == gcvNULL) \
+ || (((gcsOBJECT *)(obj))->type != t) \
+ ) \
+ { \
+ status = gcvSTATUS_INVALID_OBJECT; \
+ break; \
+ } \
+ do { } while (gcvFALSE)
+
+/*******************************************************************************
+**
+** gcmCHECK_STATUS
+**
+** Executes a break statement on error.
+**
+** ASSUMPTIONS:
+**
+** 'status' variable of gceSTATUS type must be defined.
+**
+** ARGUMENTS:
+**
+** func Function to evaluate.
+*/
+#define _gcmCHECK_STATUS(prefix, func) \
+ do \
+ { \
+ last = func; \
+ if (gcmIS_ERROR(last)) \
+ { \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ #prefix "CHECK_STATUS: status=%d(%s) @ %s(%d)", \
+ last, gcmSTATUS2NAME(last), __FUNCTION__, __LINE__); \
+ status = last; \
+ } \
+ } \
+ while (gcvFALSE)
+#define _gcmkCHECK_STATUS(prefix, func) \
+ do \
+ { \
+ last = func; \
+ if (gcmIS_ERROR(last)) \
+ { \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ #prefix "CHECK_STATUS: status=%d(%s) @ %s(%d)", \
+ last, gcmkSTATUS2NAME(last), __FUNCTION__, __LINE__); \
+ status = last; \
+ } \
+ } \
+ while (gcvFALSE)
+#define gcmCHECK_STATUS(func) _gcmCHECK_STATUS(gcm, func)
+#define gcmkCHECK_STATUS(func) _gcmkCHECK_STATUS(gcmk, func)
+
+/*******************************************************************************
+**
+** gcmVERIFY_ARGUMENT
+**
+** Assert if an argument does not apply to the specified expression. If
+** the argument evaluates to false, gcvSTATUS_INVALID_ARGUMENT will be
+** returned from the current function. In retail mode this macro does
+** nothing.
+**
+** ARGUMENTS:
+**
+** arg Argument to evaluate.
+*/
+# define _gcmVERIFY_ARGUMENT(prefix, arg) \
+ do \
+ { \
+ if (!(arg)) \
+ { \
+ prefix##TRACE(gcvLEVEL_ERROR, #prefix "VERIFY_ARGUMENT failed:"); \
+ prefix##ASSERT(arg); \
+ prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); \
+ return gcvSTATUS_INVALID_ARGUMENT; \
+ } \
+ } \
+ while (gcvFALSE)
+# define gcmVERIFY_ARGUMENT(arg) _gcmVERIFY_ARGUMENT(gcm, arg)
+# define gcmkVERIFY_ARGUMENT(arg) _gcmVERIFY_ARGUMENT(gcmk, arg)
+
+/*******************************************************************************
+**
+** gcmDEBUG_VERIFY_ARGUMENT
+**
+** Works just like gcmVERIFY_ARGUMENT, but is only valid in debug mode.
+** Use this to verify arguments inside non-public API functions.
+*/
+#if gcdDEBUG
+# define gcmDEBUG_VERIFY_ARGUMENT(arg) _gcmVERIFY_ARGUMENT(gcm, arg)
+# define gcmkDEBUG_VERIFY_ARGUMENT(arg) _gcmkVERIFY_ARGUMENT(gcm, arg)
+#else
+# define gcmDEBUG_VERIFY_ARGUMENT(arg)
+# define gcmkDEBUG_VERIFY_ARGUMENT(arg)
+#endif
+
+/*******************************************************************************
+**
+** gcmVERIFY_ARGUMENT_RETURN
+**
+** Assert if an argument does not apply to the specified expression. If
+** the argument evaluates to false, gcvSTATUS_INVALID_ARGUMENT will be
+** returned from the current function. In retail mode this macro does
+** nothing.
+**
+** ARGUMENTS:
+**
+** arg Argument to evaluate.
+*/
+# define _gcmVERIFY_ARGUMENT_RETURN(prefix, arg, value) \
+ do \
+ { \
+ if (!(arg)) \
+ { \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ #prefix "gcmVERIFY_ARGUMENT_RETURN failed:"); \
+ prefix##ASSERT(arg); \
+ prefix##FOOTER_ARG("value=%d", value); \
+ return value; \
+ } \
+ } \
+ while (gcvFALSE)
+# define gcmVERIFY_ARGUMENT_RETURN(arg, value) \
+ _gcmVERIFY_ARGUMENT_RETURN(gcm, arg, value)
+# define gcmkVERIFY_ARGUMENT_RETURN(arg, value) \
+ _gcmVERIFY_ARGUMENT_RETURN(gcmk, arg, value)
+
+#define MAX_LOOP_COUNT 0x7FFFFFFF
+
+/******************************************************************************\
+****************************** User Debug Option ******************************
+\******************************************************************************/
+
+/* User option. */
+typedef enum _gceDEBUG_MSG
+{
+ gcvDEBUG_MSG_NONE,
+ gcvDEBUG_MSG_ERROR,
+ gcvDEBUG_MSG_WARNING
+}
+gceDEBUG_MSG;
+
+typedef struct _gcsUSER_DEBUG_OPTION
+{
+ gceDEBUG_MSG debugMsg;
+}
+gcsUSER_DEBUG_OPTION;
+
+gcsUSER_DEBUG_OPTION *
+gcoHAL_GetUserDebugOption(
+ void
+ );
+
+#if gcdHAS_ELLIPSIS
+#define gcmUSER_DEBUG_MSG(level, ...) \
+ do \
+ { \
+ if (level <= gcoHAL_GetUserDebugOption()->debugMsg) \
+ { \
+ gcoOS_Print(__VA_ARGS__); \
+ } \
+ } while (gcvFALSE)
+
+#define gcmUSER_DEBUG_ERROR_MSG(...) gcmUSER_DEBUG_MSG(gcvDEBUG_MSG_ERROR, "Error: " __VA_ARGS__)
+#define gcmUSER_DEBUG_WARNING_MSG(...) gcmUSER_DEBUG_MSG(gcvDEBUG_MSG_WARNING, "Warring: " __VA_ARGS__)
+#else
+#define gcmUSER_DEBUG_MSG
+#define gcmUSER_DEBUG_ERROR_MSG
+#define gcmUSER_DEBUG_WARNING_MSG
+#endif
+
+/*******************************************************************************
+**
+** A set of macros to aid state loading.
+**
+** ARGUMENTS:
+**
+** CommandBuffer Pointer to a gcoCMDBUF object.
+** StateDelta Pointer to a gcsSTATE_DELTA state delta structure.
+** Memory Destination memory pointer of gctUINT32_PTR type.
+** PartOfContext Whether or not the state is a part of the context.
+** FixedPoint Whether or not the state is of the fixed point format.
+** Count Number of consecutive states to be loaded.
+** Address State address.
+** Data Data to be set to the state.
+*/
+
+/*----------------------------------------------------------------------------*/
+
+#if gcmIS_DEBUG(gcdDEBUG_CODE)
+
+# define gcmSTORELOADSTATE(CommandBuffer, Memory, Address, Count) \
+ CommandBuffer->lastLoadStatePtr = gcmPTR_TO_UINT64(Memory); \
+ CommandBuffer->lastLoadStateAddress = Address; \
+ CommandBuffer->lastLoadStateCount = Count
+
+# define gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address) \
+ gcmASSERT( \
+ (gctUINT) (Memory - gcmUINT64_TO_TYPE(CommandBuffer->lastLoadStatePtr, gctUINT32_PTR) - 1) \
+ == \
+ (gctUINT) (Address - CommandBuffer->lastLoadStateAddress) \
+ ); \
+ \
+ gcmASSERT(CommandBuffer->lastLoadStateCount > 0); \
+ \
+ CommandBuffer->lastLoadStateCount -= 1
+
+# define gcmVERIFYLOADSTATEDONE(CommandBuffer) \
+ gcmASSERT(CommandBuffer->lastLoadStateCount == 0);
+
+# define gcmDEFINELOADSTATEBASE() \
+ gctUINT32_PTR LoadStateBase;
+
+# define gcmSETLOADSTATEBASE(CommandBuffer, OutSide) \
+ if (OutSide) \
+ {\
+ LoadStateBase = (gctUINT32_PTR)*OutSide; \
+ }\
+ else\
+ {\
+ LoadStateBase = (gctUINT_PTR)CommandBuffer->buffer;\
+ }
+
+
+# define gcmVERIFYLOADSTATEALIGNED(CommandBuffer, Memory) \
+ gcmASSERT(((Memory - LoadStateBase) & 1) == 0);
+
+# define gcmUNSETLOADSTATEBASE() \
+ LoadStateBase = LoadStateBase;
+
+#else
+
+# define gcmSTORELOADSTATE(CommandBuffer, Memory, Address, Count)
+# define gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address)
+# define gcmVERIFYLOADSTATEDONE(CommandBuffer)
+
+# define gcmDEFINELOADSTATEBASE()
+# define gcmSETLOADSTATEBASE(CommandBuffer, OutSide)
+# define gcmVERIFYLOADSTATEALIGNED(CommandBuffer, Memory)
+# define gcmUNSETLOADSTATEBASE()
+
+#endif
+
+#if gcdSECURE_USER
+
+# define gcmDEFINESECUREUSER() \
+ gctUINT __secure_user_offset__; \
+ gctUINT32_PTR __secure_user_hintArray__;
+
+# define gcmBEGINSECUREUSER() \
+ __secure_user_offset__ = reserve->lastOffset; \
+ \
+ __secure_user_hintArray__ = gcmUINT64_TO_PTR(reserve->hintArrayTail)
+
+# define gcmENDSECUREUSER() \
+ reserve->hintArrayTail = gcmPTR_TO_UINT64(__secure_user_hintArray__)
+
+# define gcmSKIPSECUREUSER() \
+ __secure_user_offset__ += gcmSIZEOF(gctUINT32)
+
+# define gcmUPDATESECUREUSER() \
+ *__secure_user_hintArray__ = __secure_user_offset__; \
+ \
+ __secure_user_offset__ += gcmSIZEOF(gctUINT32); \
+ __secure_user_hintArray__ += 1
+
+#else
+
+# define gcmDEFINESECUREUSER()
+# define gcmBEGINSECUREUSER()
+# define gcmENDSECUREUSER()
+# define gcmSKIPSECUREUSER()
+# define gcmUPDATESECUREUSER()
+
+#endif
+
+/*----------------------------------------------------------------------------*/
+
+#if gcdDUMP
+# define gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, Data) \
+ if (FixedPoint) \
+ { \
+ gcmDUMP(gcvNULL, "#[state.x 0x%04X 0x%08X]", \
+ Address, Data \
+ ); \
+ } \
+ else \
+ { \
+ gcmDUMP(gcvNULL, "#[state 0x%04X 0x%08X]", \
+ Address, Data \
+ ); \
+ }
+#else
+# define gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, Data)
+#endif
+
+#define gcmDEFINESTATEBUFFER(CommandBuffer, StateDelta, Memory, ReserveSize) \
+ gcmDEFINESECUREUSER() \
+ gctSIZE_T ReserveSize; \
+ gcoCMDBUF CommandBuffer; \
+ gctUINT32_PTR Memory; \
+ gcsSTATE_DELTA_PTR StateDelta; \
+ gceENGINE CurrentEngine = gcvENGINE_RENDER
+
+#define gcmBEGINSTATEBUFFER(Hardware, CommandBuffer, StateDelta, Memory, ReserveSize) \
+{ \
+ gcmONERROR(gcoBUFFER_Reserve( \
+ Hardware->engine[CurrentEngine].buffer, ReserveSize, gcvTRUE, gcvCOMMAND_3D, &CommandBuffer \
+ )); \
+ \
+ Memory = (gctUINT32_PTR) gcmUINT64_TO_PTR(CommandBuffer->lastReserve); \
+ \
+ StateDelta = Hardware->delta; \
+ \
+ gcmBEGINSECUREUSER(); \
+}
+
+#define gcmENDSTATEBUFFER(Hardware, CommandBuffer, Memory, ReserveSize) \
+{ \
+ gcmENDSECUREUSER(); \
+ \
+ gcmASSERT( \
+ gcmUINT64_TO_TYPE(CommandBuffer->lastReserve, gctUINT8_PTR) + ReserveSize \
+ == \
+ (gctUINT8_PTR) Memory \
+ ); \
+}
+
+/*----------------------------------------------------------------------------*/
+
+#define gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, Count) \
+{ \
+ gcmASSERT(((Memory - gcmUINT64_TO_TYPE(CommandBuffer->lastReserve, gctUINT32_PTR)) & 1) == 0); \
+ gcmASSERT((gctUINT32)Count <= 1024); \
+ \
+ gcmVERIFYLOADSTATEDONE(CommandBuffer); \
+ \
+ gcmSTORELOADSTATE(CommandBuffer, Memory, Address, Count); \
+ \
+ *Memory++ \
+ = gcmSETFIELDVALUE(0, AQ_COMMAND_LOAD_STATE_COMMAND, OPCODE, LOAD_STATE) \
+ | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, FLOAT, FixedPoint) \
+ | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, COUNT, Count) \
+ | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, ADDRESS, Address); \
+ \
+ gcmSKIPSECUREUSER(); \
+}
+
+#define gcmENDSTATEBATCH(CommandBuffer, Memory) \
+{ \
+ gcmVERIFYLOADSTATEDONE(CommandBuffer); \
+ \
+ gcmASSERT(((Memory - gcmUINT64_TO_TYPE(CommandBuffer->lastReserve, gctUINT32_PTR)) & 1) == 0); \
+}
+
+/*----------------------------------------------------------------------------*/
+
+#define gcmSETSTATEDATA(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Data) \
+{ \
+ gctUINT32 __temp_data32__; \
+ \
+ gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \
+ \
+ gcmSAFECASTSIZET(__temp_data32__, Data); \
+ \
+ *Memory++ = __temp_data32__; \
+ \
+ gcoHARDWARE_UpdateDelta( \
+ StateDelta, Address, 0, __temp_data32__ \
+ ); \
+ \
+ gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \
+ \
+ gcmUPDATESECUREUSER(); \
+}
+
+#define gcmSETSTATEDATAWITHMASK(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Mask, Data) \
+{ \
+ gctUINT32 __temp_data32__; \
+ \
+ gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \
+ \
+ __temp_data32__ = Data; \
+ \
+ *Memory++ = __temp_data32__; \
+ \
+ gcoHARDWARE_UpdateDelta( \
+ StateDelta, Address, Mask, __temp_data32__ \
+ ); \
+ \
+ gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \
+ \
+ gcmUPDATESECUREUSER(); \
+}
+
+
+#define gcmSETCTRLSTATE(StateDelta, CommandBuffer, Memory, Address, Data) \
+{ \
+ gctUINT32 __temp_data32__; \
+ \
+ gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \
+ \
+ __temp_data32__ = Data; \
+ \
+ *Memory++ = __temp_data32__; \
+ \
+ gcmDUMPSTATEDATA(StateDelta, gcvFALSE, Address, __temp_data32__); \
+ \
+ gcmSKIPSECUREUSER(); \
+}
+
+#define gcmSETFILLER(CommandBuffer, Memory) \
+{ \
+ gcmVERIFYLOADSTATEDONE(CommandBuffer); \
+ \
+ Memory += 1; \
+ \
+ gcmSKIPSECUREUSER(); \
+}
+
+/*----------------------------------------------------------------------------*/
+
+#define gcmSETSINGLESTATE(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Data) \
+{ \
+ gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \
+ gcmSETSTATEDATA(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Data); \
+ gcmENDSTATEBATCH(CommandBuffer, Memory); \
+}
+
+#define gcmSETSINGLESTATEWITHMASK(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Mask, Data) \
+{ \
+ gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \
+ gcmSETSTATEDATAWITHMASK(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Mask, Data); \
+ gcmENDSTATEBATCH(CommandBuffer, Memory); \
+}
+
+
+#define gcmSETSINGLECTRLSTATE(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Data) \
+{ \
+ gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \
+ gcmSETCTRLSTATE(StateDelta, CommandBuffer, Memory, Address, Data); \
+ gcmENDSTATEBATCH(CommandBuffer, Memory); \
+}
+
+
+
+#define gcmSETSEMASTALLPIPE(StateDelta, CommandBuffer, Memory, Data) \
+{ \
+ gcmSETSINGLECTRLSTATE(StateDelta, CommandBuffer, Memory, gcvFALSE, AQSemaphoreRegAddrs, Data); \
+ \
+ *Memory++ = gcmSETFIELDVALUE(0, STALL_COMMAND, OPCODE, STALL); \
+ \
+ *Memory++ = Data; \
+ \
+ gcmDUMP(gcvNULL, "#[stall 0x%08X 0x%08X]", \
+ gcmSETFIELDVALUE(0, AQ_SEMAPHORE, SOURCE, FRONT_END), \
+ gcmSETFIELDVALUE(0, AQ_SEMAPHORE, DESTINATION, PIXEL_ENGINE)); \
+ \
+ gcmSKIPSECUREUSER(); \
+}
+
+/*******************************************************************************
+**
+** gcmSETSTARTDECOMMAND
+**
+** Form a START_DE command.
+**
+** ARGUMENTS:
+**
+** Memory Destination memory pointer of gctUINT32_PTR type.
+** Count Number of the rectangles.
+*/
+
+#define gcmSETSTARTDECOMMAND(Memory, Count) \
+{ \
+ *Memory++ \
+ = gcmSETFIELDVALUE(0, AQ_COMMAND_START_DE_COMMAND, OPCODE, START_DE) \
+ | gcmSETFIELD (0, AQ_COMMAND_START_DE_COMMAND, COUNT, Count) \
+ | gcmSETFIELD (0, AQ_COMMAND_START_DE_COMMAND, DATA_COUNT, 0); \
+ \
+ *Memory++ = 0xDEADDEED; \
+}
+
+/*****************************************
+** Temp command buffer macro
+*/
+#define gcmDEFINESTATEBUFFER_NEW(CommandBuffer, StateDelta, Memory) \
+ gcmDEFINESECUREUSER() \
+ gcmDEFINELOADSTATEBASE() \
+ gcsTEMPCMDBUF CommandBuffer = gcvNULL; \
+ gctUINT32_PTR Memory; \
+ gcsSTATE_DELTA_PTR StateDelta; \
+ gceENGINE CurrentEngine = gcvENGINE_RENDER
+
+
+#define gcmBEGINSTATEBUFFER_NEW(Hardware, CommandBuffer, StateDelta, Memory, OutSide) \
+{ \
+ if (OutSide) \
+ {\
+ Memory = (gctUINT32_PTR)*OutSide; \
+ }\
+ else \
+ {\
+ gcmONERROR(gcoBUFFER_StartTEMPCMDBUF( \
+ Hardware->engine[CurrentEngine].buffer, &CommandBuffer \
+ ));\
+ \
+ Memory = (gctUINT32_PTR)(CommandBuffer->buffer); \
+ \
+ }\
+ StateDelta = Hardware->delta; \
+ \
+ gcmBEGINSECUREUSER(); \
+ gcmSETLOADSTATEBASE(CommandBuffer,OutSide);\
+}
+
+#define gcmENDSTATEBUFFER_NEW(Hardware, CommandBuffer, Memory, OutSide) \
+{ \
+ gcmENDSECUREUSER(); \
+ \
+ if (OutSide) \
+ {\
+ *OutSide = Memory; \
+ }\
+ else \
+ {\
+ CommandBuffer->currentByteSize = (gctUINT32)((gctUINT8_PTR)Memory - \
+ (gctUINT8_PTR)CommandBuffer->buffer); \
+ \
+ gcmONERROR(gcoBUFFER_EndTEMPCMDBUF(Hardware->engine[CurrentEngine].buffer, gcvFALSE));\
+ }\
+ gcmUNSETLOADSTATEBASE()\
+}
+
+#define gcmDEFINECTRLSTATEBUFFER(CommandBuffer, Memory) \
+ gcmDEFINESECUREUSER() \
+ gcmDEFINELOADSTATEBASE() \
+ gcsTEMPCMDBUF CommandBuffer = gcvNULL; \
+ gctUINT32_PTR Memory; \
+ gceENGINE CurrentEngine = gcvENGINE_RENDER
+
+#define gcmBEGINCTRLSTATEBUFFER(Hardware, CommandBuffer, Memory, OutSide) \
+{ \
+ if (OutSide) \
+ { \
+ Memory = (gctUINT32_PTR)*OutSide; \
+ } \
+ else \
+ { \
+ gcmONERROR(gcoBUFFER_StartTEMPCMDBUF( \
+ Hardware->engine[CurrentEngine].buffer, &CommandBuffer \
+ )); \
+ \
+ Memory = (gctUINT32_PTR)(CommandBuffer->buffer); \
+ } \
+ gcmBEGINSECUREUSER(); \
+ gcmSETLOADSTATEBASE(CommandBuffer,OutSide); \
+}
+
+/*----------------------------------------------------------------------------*/
+
+#define gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, Count) \
+{ \
+ gcmVERIFYLOADSTATEALIGNED(CommandBuffer,Memory);\
+ gcmASSERT((gctUINT32)Count <= 1024); \
+ \
+ *Memory++ \
+ = gcmSETFIELDVALUE(0, AQ_COMMAND_LOAD_STATE_COMMAND, OPCODE, LOAD_STATE) \
+ | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, FLOAT, FixedPoint) \
+ | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, COUNT, Count) \
+ | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, ADDRESS, Address); \
+ \
+ gcmSKIPSECUREUSER(); \
+}
+
+#define gcmENDSTATEBATCH_NEW(CommandBuffer, Memory) \
+ gcmVERIFYLOADSTATEALIGNED(CommandBuffer,Memory);
+
+/*----------------------------------------------------------------------------*/
+
+#define gcmSETSTATEDATA_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Data) \
+{ \
+ gctUINT32 __temp_data32__; \
+ \
+ gcmSAFECASTSIZET(__temp_data32__, Data); \
+ \
+ *Memory++ = __temp_data32__; \
+ \
+ gcoHARDWARE_UpdateDelta( \
+ StateDelta, Address, 0, __temp_data32__ \
+ ); \
+ \
+ gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \
+ \
+ gcmUPDATESECUREUSER(); \
+}
+
+#define gcmSETSTATEDATAWITHMASK_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Mask, Data) \
+{ \
+ gctUINT32 __temp_data32__; \
+ \
+ __temp_data32__ = Data; \
+ \
+ *Memory++ = __temp_data32__; \
+ \
+ gcoHARDWARE_UpdateDelta( \
+ StateDelta, Address, Mask, __temp_data32__ \
+ ); \
+ \
+ gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \
+ \
+ gcmUPDATESECUREUSER(); \
+}
+
+
+#define gcmSETCTRLSTATE_NEW(StateDelta, CommandBuffer, Memory, Address, Data) \
+{ \
+ gctUINT32 __temp_data32__; \
+ \
+ __temp_data32__ = Data; \
+ \
+ *Memory++ = __temp_data32__; \
+ \
+ gcmDUMPSTATEDATA(StateDelta, gcvFALSE, Address, __temp_data32__); \
+ \
+ gcmSKIPSECUREUSER(); \
+}
+
+#define gcmSETFILLER_NEW(CommandBuffer, Memory) \
+{ \
+ Memory += 1; \
+ \
+ gcmSKIPSECUREUSER(); \
+}
+
+/*----------------------------------------------------------------------------*/
+
+#define gcmSETSINGLESTATE_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Data) \
+{ \
+ gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, 1); \
+ gcmSETSTATEDATA_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Data); \
+ gcmENDSTATEBATCH_NEW(CommandBuffer, Memory); \
+}
+
+#define gcmSETSINGLESTATEWITHMASK_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Mask, Data) \
+{ \
+ gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, 1); \
+ gcmSETSTATEDATAWITHMASK_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Mask, Data); \
+ gcmENDSTATEBATCH_NEW(CommandBuffer, Memory); \
+}
+
+
+#define gcmSETSINGLECTRLSTATE_NEW(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Data) \
+{ \
+ gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, 1); \
+ gcmSETCTRLSTATE_NEW(StateDelta, CommandBuffer, Memory, Address, Data); \
+ gcmENDSTATEBATCH_NEW(CommandBuffer, Memory); \
+}
+
+
+
+#define gcmSETSEMASTALLPIPE_NEW(StateDelta, CommandBuffer, Memory, Data) \
+{ \
+ gcmSETSINGLECTRLSTATE_NEW(StateDelta, CommandBuffer, Memory, gcvFALSE, AQSemaphoreRegAddrs, Data); \
+ \
+ *Memory++ = gcmSETFIELDVALUE(0, STALL_COMMAND, OPCODE, STALL); \
+ \
+ *Memory++ = Data; \
+ \
+ gcmDUMP(gcvNULL, "#[stall 0x%08X 0x%08X]", \
+ gcmSETFIELDVALUE(0, AQ_SEMAPHORE, SOURCE, FRONT_END), \
+ gcmSETFIELDVALUE(0, AQ_SEMAPHORE, DESTINATION, PIXEL_ENGINE)); \
+ \
+ gcmSKIPSECUREUSER(); \
+}
+
+#define gcmSETSTARTDECOMMAND_NEW(CommandBuffer, Memory, Count) \
+{ \
+ *Memory++ \
+ = gcmSETFIELDVALUE(0, AQ_COMMAND_START_DE_COMMAND, OPCODE, START_DE) \
+ | gcmSETFIELD (0, AQ_COMMAND_START_DE_COMMAND, COUNT, Count) \
+ | gcmSETFIELD (0, AQ_COMMAND_START_DE_COMMAND, DATA_COUNT, 0); \
+ \
+ *Memory++ = 0xDEADDEED; \
+ \
+}
+
+#define gcmSETSTATEDATA_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Data) \
+{ \
+ gctUINT32 __temp_data32__; \
+ \
+ __temp_data32__ = Data; \
+ \
+ *Memory++ = __temp_data32__; \
+ \
+ gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \
+ \
+ gcmUPDATESECUREUSER(); \
+}
+
+#define gcmSETSTATEDATAWITHMASK_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Mask, Data) \
+{ \
+ gctUINT32 __temp_data32__; \
+ \
+ __temp_data32__ = Data; \
+ \
+ *Memory++ = __temp_data32__; \
+ \
+ gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \
+ \
+ gcmUPDATESECUREUSER(); \
+}
+
+#define gcmSETSINGLESTATE_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Data) \
+{ \
+ gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, 1); \
+ gcmSETSTATEDATA_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Data); \
+ gcmENDSTATEBATCH_NEW(CommandBuffer, Memory); \
+}
+
+#define gcmSETSINGLESTATEWITHMASK_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Mask, Data) \
+{ \
+ gcmBEGINSTATEBATCH_NEW(CommandBuffer, Memory, FixedPoint, Address, 1); \
+ gcmSETSTATEDATAWITHMASK_NEW_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Mask, Data); \
+ gcmENDSTATEBATCH_NEW(CommandBuffer, Memory); \
+}
+
+#define gcmSETSTATEDATA_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Data) \
+{ \
+ gctUINT32 __temp_data32__; \
+ \
+ gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \
+ \
+ gcmSAFECASTSIZET(__temp_data32__, Data); \
+ \
+ *Memory++ = __temp_data32__; \
+ \
+ gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \
+ \
+ gcmUPDATESECUREUSER(); \
+}
+
+#define gcmSETSTATEDATAWITHMASK_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Mask, Data) \
+{ \
+ gctUINT32 __temp_data32__; \
+ \
+ gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \
+ \
+ __temp_data32__ = Data; \
+ \
+ *Memory++ = __temp_data32__; \
+ \
+ gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \
+ \
+ gcmUPDATESECUREUSER(); \
+}
+
+#define gcmSETSINGLESTATE_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Data) \
+{ \
+ gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \
+ gcmSETSTATEDATA_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Data); \
+ gcmENDSTATEBATCH(CommandBuffer, Memory); \
+}
+
+#define gcmSETSINGLESTATEWITHMASK_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Mask, Data) \
+{ \
+ gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \
+ gcmSETSTATEDATAWITHMASK_FAST(StateDelta, CommandBuffer, Memory, FixedPoint, \
+ Address, Mask, Data); \
+ gcmENDSTATEBATCH(CommandBuffer, Memory); \
+}
+
+#define gcmDEFINESTATEBUFFER_NEW_FAST(CommandBuffer, Memory) \
+ gcmDEFINESECUREUSER() \
+ gcmDEFINELOADSTATEBASE() \
+ gcsTEMPCMDBUF CommandBuffer = gcvNULL; \
+ gctUINT32_PTR Memory;
+
+#define gcmDEFINESTATEBUFFER_FAST(CommandBuffer, Memory, ReserveSize) \
+ gcmDEFINESECUREUSER() \
+ gctSIZE_T ReserveSize; \
+ gcoCMDBUF CommandBuffer; \
+ gctUINT32_PTR Memory;
+
+#define gcmBEGINSTATEBUFFER_FAST(Hardware, CommandBuffer, Memory, ReserveSize) \
+{ \
+ gcmONERROR(gcoBUFFER_Reserve( \
+ Hardware->engine[gcvENGINE_RENDER].buffer, ReserveSize, gcvTRUE, &CommandBuffer \
+ )); \
+ \
+ Memory = (gctUINT32_PTR) gcmUINT64_TO_PTR(CommandBuffer->lastReserve); \
+ \
+ gcmBEGINSECUREUSER(); \
+}
+
+#define gcmBEGINSTATEBUFFER_NEW_FAST(Hardware, CommandBuffer, Memory, OutSide) \
+{ \
+ if (OutSide) \
+ {\
+ Memory = (gctUINT32_PTR)*OutSide; \
+ }\
+ else \
+ {\
+ gcmONERROR(gcoBUFFER_StartTEMPCMDBUF( \
+ Hardware->engine[gcvENGINE_RENDER].buffer, &CommandBuffer \
+ ));\
+ \
+ Memory = (gctUINT32_PTR)(CommandBuffer->buffer); \
+ \
+ }\
+ \
+ gcmBEGINSECUREUSER(); \
+ gcmSETLOADSTATEBASE(CommandBuffer,OutSide);\
+}
+
+#define gcmENDSTATEBUFFER_NEW_FAST(Hardware, CommandBuffer, Memory, OutSide) \
+{ \
+ gcmENDSECUREUSER(); \
+ \
+ if (OutSide) \
+ {\
+ *OutSide = Memory; \
+ }\
+ else \
+ {\
+ CommandBuffer->currentByteSize = (gctUINT32)((gctUINT8_PTR)Memory - \
+ (gctUINT8_PTR)CommandBuffer->buffer); \
+ \
+ gcmONERROR(gcoBUFFER_EndTEMPCMDBUF(Hardware->engine[gcvENGINE_RENDER].buffer, gcvFALSE));\
+ }\
+ gcmUNSETLOADSTATEBASE()\
+}
+
+/*******************************************************************************
+**
+** gcmCONFIGUREUNIFORMS
+**
+** Configure uniforms according to chip and numConstants.
+*/
+#if !gcdENABLE_UNIFIED_CONSTANT
+#define gcmCONFIGUREUNIFORMS(ChipModel, ChipRevision, NumConstants, \
+ UnifiedConst, VsConstBase, PsConstBase, VsConstMax, PsConstMax, ConstMax) \
+{ \
+ if (ChipModel == gcv2000 && (ChipRevision == 0x5118 || ChipRevision == 0x5140)) \
+ { \
+ UnifiedConst = gcvFALSE; \
+ VsConstBase = AQVertexShaderConstRegAddrs; \
+ PsConstBase = AQPixelShaderConstRegAddrs; \
+ VsConstMax = 256; \
+ PsConstMax = 64; \
+ ConstMax = 320; \
+ } \
+ else if (NumConstants == 320) \
+ { \
+ UnifiedConst = gcvFALSE; \
+ VsConstBase = AQVertexShaderConstRegAddrs; \
+ PsConstBase = AQPixelShaderConstRegAddrs; \
+ VsConstMax = 256; \
+ PsConstMax = 64; \
+ ConstMax = 320; \
+ } \
+ /* All GC1000 series chips can only support 64 uniforms for ps on non-unified const mode. */ \
+ else if (NumConstants > 256 && ChipModel == gcv1000) \
+ { \
+ UnifiedConst = gcvFALSE; \
+ VsConstBase = AQVertexShaderConstRegAddrs; \
+ PsConstBase = AQPixelShaderConstRegAddrs; \
+ VsConstMax = 256; \
+ PsConstMax = 64; \
+ ConstMax = 320; \
+ } \
+ else if (NumConstants > 256) \
+ { \
+ UnifiedConst = gcvFALSE; \
+ VsConstBase = AQVertexShaderConstRegAddrs; \
+ PsConstBase = AQPixelShaderConstRegAddrs; \
+ VsConstMax = 256; \
+ PsConstMax = 256; \
+ ConstMax = 512; \
+ } \
+ else if (NumConstants == 256) \
+ { \
+ UnifiedConst = gcvFALSE; \
+ VsConstBase = AQVertexShaderConstRegAddrs; \
+ PsConstBase = AQPixelShaderConstRegAddrs; \
+ VsConstMax = 256; \
+ PsConstMax = 256; \
+ ConstMax = 512; \
+ } \
+ else \
+ { \
+ UnifiedConst = gcvFALSE; \
+ VsConstBase = AQVertexShaderConstRegAddrs; \
+ PsConstBase = AQPixelShaderConstRegAddrs; \
+ VsConstMax = 168; \
+ PsConstMax = 64; \
+ ConstMax = 232; \
+ } \
+}
+#else
+#define gcmCONFIGUREUNIFORMS(ChipModel, ChipRevision, Halti5Avail, NumConstants, \
+ UnifiedConst, VsConstBase, PsConstBase, VsConstMax, PsConstMax, ConstMax) \
+{ \
+ if (NumConstants > 256) \
+ { \
+ UnifiedConst = gcvTRUE; \
+ if (Halti5Avail) \
+ { \
+ VsConstBase = gcregGpipeUniformsRegAddrs; \
+ PsConstBase = gcregPixelUniformsRegAddrs; \
+ } \
+ else \
+ {\
+ VsConstBase = gcregSHUniformsRegAddrs; \
+ PsConstBase = gcregSHUniformsRegAddrs; \
+ }\
+ if ((ChipModel == gcv880) && ((ChipRevision & 0xfff0) == 0x5120)) \
+ { \
+ VsConstMax = 512; \
+ PsConstMax = 64; \
+ ConstMax = 576; \
+ } \
+ else \
+ { \
+ VsConstMax = gcmMIN(512, NumConstants - 64); \
+ PsConstMax = gcmMIN(512, NumConstants - 64); \
+ ConstMax = NumConstants; \
+ } \
+ } \
+ else if (NumConstants == 256) \
+ { \
+ if (ChipModel == gcv2000 && (ChipRevision == 0x5118 || ChipRevision == 0x5140)) \
+ { \
+ UnifiedConst = gcvFALSE; \
+ VsConstBase = AQVertexShaderConstRegAddrs; \
+ PsConstBase = AQPixelShaderConstRegAddrs; \
+ VsConstMax = 256; \
+ PsConstMax = 64; \
+ ConstMax = 320; \
+ } \
+ else \
+ { \
+ UnifiedConst = gcvFALSE; \
+ VsConstBase = AQVertexShaderConstRegAddrs; \
+ PsConstBase = AQPixelShaderConstRegAddrs; \
+ VsConstMax = 256; \
+ PsConstMax = 256; \
+ ConstMax = 512; \
+ } \
+ } \
+ else \
+ { \
+ UnifiedConst = gcvFALSE; \
+ VsConstBase = AQVertexShaderConstRegAddrs; \
+ PsConstBase = AQPixelShaderConstRegAddrs; \
+ VsConstMax = 168; \
+ PsConstMax = 64; \
+ ConstMax = 232; \
+ } \
+}
+#endif
+
+#define gcmAnyTileStatusEnableForFullMultiSlice(SurfView, anyTsEnableForMultiSlice)\
+{\
+ gctUINT i = 0; \
+ for (; i < (SurfView->surf->requestD); i++)\
+ {\
+ if ((SurfView->surf->tileStatusNode.pool != gcvPOOL_UNKNOWN) && \
+ (SurfView->surf->tileStatusDisabled[i] == gcvFALSE))\
+ {\
+ *anyTsEnableForMultiSlice = gcvTRUE;\
+ break;\
+ }\
+ }\
+}\
+
+#define gcmAnyTileStatusEnableForMultiSlice(SurfView, anyTsEnableForMultiSlice)\
+{\
+ gctUINT i = SurfView->firstSlice; \
+ for (; i < (SurfView->firstSlice + SurfView->numSlices); i++)\
+ {\
+ if ((SurfView->surf->tileStatusNode.pool != gcvPOOL_UNKNOWN) && \
+ (SurfView->surf->tileStatusDisabled[i] == gcvFALSE))\
+ {\
+ *anyTsEnableForMultiSlice = gcvTRUE;\
+ break;\
+ }\
+ }\
+}\
+
+#define gcmCanTileStatusEnabledForMultiSlice(SurfView, canTsEnabled)\
+{\
+ if (SurfView->numSlices > 1)\
+ {\
+ if (SurfView->surf->tileStatusNode.pool != gcvPOOL_UNKNOWN) \
+ {\
+ gctUINT i = 0;\
+ for (; i < SurfView->numSlices; i++)\
+ {\
+ if (SurfView->surf->tileStatusDisabled[i] == gcvTRUE)\
+ {\
+ *canTsEnabled = gcvFALSE;\
+ break;\
+ }\
+ if (SurfView->surf->fcValue[i] != SurfView->surf->fcValue[0])\
+ {\
+ *canTsEnabled = gcvFALSE;\
+ break;\
+ }\
+ \
+ if (SurfView->surf->fcValueUpper[i] != SurfView->surf->fcValueUpper[0])\
+ {\
+ *canTsEnabled = gcvFALSE;\
+ break;\
+ }\
+ }\
+ }\
+ else\
+ {\
+ *canTsEnabled = gcvFALSE;\
+ }\
+ }\
+ else\
+ {\
+ if ((SurfView->surf->tileStatusNode.pool == gcvPOOL_UNKNOWN) || (SurfView->surf->tileStatusDisabled[SurfView->firstSlice] == gcvTRUE))\
+ {\
+ *canTsEnabled = gcvFALSE;\
+ }\
+ }\
+}\
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_base_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_driver.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_driver.h
new file mode 100644
index 000000000000..69ffbc40a2bd
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_driver.h
@@ -0,0 +1,1365 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_driver_h_
+#define __gc_hal_driver_h_
+
+#include "gc_hal_enum.h"
+#include "gc_hal_types.h"
+
+#if gcdENABLE_VG
+#include "gc_hal_driver_vg.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+******************************* I/O Control Codes ******************************
+\******************************************************************************/
+
+#define gcvHAL_CLASS "galcore"
+#define IOCTL_GCHAL_INTERFACE 30000
+#define IOCTL_GCHAL_KERNEL_INTERFACE 30001
+#define IOCTL_GCHAL_TERMINATE 30002
+
+#undef CONFIG_ANDROID_RESERVED_MEMORY_ACCOUNT
+/******************************************************************************\
+********************************* Command Codes ********************************
+\******************************************************************************/
+
+typedef enum _gceHAL_COMMAND_CODES
+{
+ /* Generic query. */
+ gcvHAL_QUERY_VIDEO_MEMORY,
+ gcvHAL_QUERY_CHIP_IDENTITY,
+
+ /* Contiguous memory. */
+ gcvHAL_ALLOCATE_NON_PAGED_MEMORY,
+ gcvHAL_FREE_NON_PAGED_MEMORY,
+ gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY,
+ gcvHAL_FREE_CONTIGUOUS_MEMORY,
+
+ /* Video memory allocation. */
+ gcvHAL_ALLOCATE_VIDEO_MEMORY, /* Enforced alignment. */
+ gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY, /* No alignment. */
+ gcvHAL_RELEASE_VIDEO_MEMORY,
+
+ /* Physical-to-logical mapping. */
+ gcvHAL_MAP_MEMORY,
+ gcvHAL_UNMAP_MEMORY,
+
+ /* Logical-to-physical mapping. */
+ gcvHAL_MAP_USER_MEMORY,
+ gcvHAL_UNMAP_USER_MEMORY,
+
+ /* Surface lock/unlock. */
+ gcvHAL_LOCK_VIDEO_MEMORY,
+ gcvHAL_UNLOCK_VIDEO_MEMORY,
+
+ /* Event queue. */
+ gcvHAL_EVENT_COMMIT,
+
+ gcvHAL_USER_SIGNAL,
+ gcvHAL_SIGNAL,
+ gcvHAL_WRITE_DATA,
+
+ gcvHAL_COMMIT,
+ gcvHAL_STALL,
+
+ gcvHAL_READ_REGISTER,
+ gcvHAL_WRITE_REGISTER,
+
+ gcvHAL_GET_PROFILE_SETTING,
+ gcvHAL_SET_PROFILE_SETTING,
+
+ gcvHAL_PROFILE_REGISTERS_2D,
+ gcvHAL_READ_ALL_PROFILE_REGISTERS_PART1,
+ gcvHAL_READ_ALL_PROFILE_REGISTERS_PART2,
+ gcvHAL_READ_PROFILER_REGISTER_SETTING,
+
+ /* Power management. */
+ gcvHAL_SET_POWER_MANAGEMENT_STATE,
+ gcvHAL_QUERY_POWER_MANAGEMENT_STATE,
+
+ gcvHAL_GET_BASE_ADDRESS,
+
+ gcvHAL_SET_IDLE, /* reserved */
+
+ /* Queries. */
+ gcvHAL_QUERY_KERNEL_SETTINGS,
+
+ /* Reset. */
+ gcvHAL_RESET,
+
+ /* Map physical address into handle. */
+ gcvHAL_MAP_PHYSICAL,
+
+ /* Debugger stuff. */
+ gcvHAL_DEBUG,
+
+ /* Cache stuff. */
+ gcvHAL_CACHE,
+
+ /* TimeStamp */
+ gcvHAL_TIMESTAMP,
+
+ /* Database. */
+ gcvHAL_DATABASE,
+
+ /* Version. */
+ gcvHAL_VERSION,
+
+ /* Chip info */
+ gcvHAL_CHIP_INFO,
+
+ /* Process attaching/detaching. */
+ gcvHAL_ATTACH,
+ gcvHAL_DETACH,
+
+ /* Set timeOut value */
+ gcvHAL_SET_TIMEOUT,
+
+ /* Frame database. */
+ gcvHAL_GET_FRAME_INFO,
+
+ /* GPU profile dump */
+ gcvHAL_DUMP_GPU_PROFILE,
+
+ gcvHAL_QUERY_COMMAND_BUFFER,
+
+ gcvHAL_COMMIT_DONE,
+
+ /* GPU and event dump */
+ gcvHAL_DUMP_GPU_STATE,
+ gcvHAL_DUMP_EVENT,
+
+ /* Virtual command buffer. */
+ gcvHAL_ALLOCATE_VIRTUAL_COMMAND_BUFFER,
+ gcvHAL_FREE_VIRTUAL_COMMAND_BUFFER,
+
+ /* FSCALE_VAL. */
+ gcvHAL_SET_FSCALE_VALUE,
+ gcvHAL_GET_FSCALE_VALUE,
+
+ /* Export video memory as dma_buf fd */
+ gcvHAL_EXPORT_VIDEO_MEMORY,
+ gcvHAL_NAME_VIDEO_MEMORY,
+ gcvHAL_IMPORT_VIDEO_MEMORY,
+
+ /* Reset time stamp. */
+ gcvHAL_QUERY_RESET_TIME_STAMP,
+
+ /* Multi-GPU read/write. */
+ gcvHAL_READ_REGISTER_EX,
+ gcvHAL_WRITE_REGISTER_EX,
+
+ /* Create native fence and return its fd. */
+ gcvHAL_CREATE_NATIVE_FENCE,
+
+ /* Let GPU wait on native fence. */
+ gcvHAL_WAIT_NATIVE_FENCE,
+
+ /* Destory MMU. */
+ gcvHAL_DESTROY_MMU,
+
+ /* Shared buffer. */
+ gcvHAL_SHBUF,
+
+ /*
+ * Fd representation of android graphic buffer contents.
+ * Currently, it is only to reference video nodes, signal, etc to avoid being
+ * destroyed when trasfering across processes.
+ */
+ gcvHAL_GET_GRAPHIC_BUFFER_FD,
+
+ gcvHAL_SET_VIDEO_MEMORY_METADATA,
+
+ /* Connect a video node to an OS native fd. */
+ gcvHAL_GET_VIDEO_MEMORY_FD,
+
+ /* Config power management. */
+ gcvHAL_CONFIG_POWER_MANAGEMENT,
+
+ /* Wrap a user memory into a video memory node. */
+ gcvHAL_WRAP_USER_MEMORY,
+
+ /* Wait until GPU finishes access to a resource. */
+ gcvHAL_WAIT_FENCE,
+
+#if gcdDEC_ENABLE_AHB
+ gcvHAL_DEC300_READ,
+ gcvHAL_DEC300_WRITE,
+ gcvHAL_DEC300_FLUSH,
+ gcvHAL_DEC300_FLUSH_WAIT,
+#endif
+
+ gcvHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY,
+ gcvHAL_QUERY_CHIP_OPTION
+
+}
+gceHAL_COMMAND_CODES;
+
+/******************************************************************************\
+****************************** Interface Structure *****************************
+\******************************************************************************/
+
+#define gcdMAX_PROFILE_FILE_NAME 128
+
+/* Kernel settings. */
+typedef struct _gcsKERNEL_SETTINGS
+{
+ /* Used RealTime signal between kernel and user. */
+ gctINT signal;
+}
+gcsKERNEL_SETTINGS;
+
+typedef struct _gcsUSER_MEMORY_DESC
+{
+ /* Import flag. */
+ gctUINT32 flag;
+
+ /* gcvALLOC_FLAG_DMABUF */
+ gctUINT32 handle;
+ gctUINT64 dmabuf;
+
+ /* gcvALLOC_FLAG_USERMEMORY */
+ gctUINT64 logical;
+ gctUINT32 physical;
+ gctUINT32 size;
+
+ /* gcvALLOC_FLAG_EXTERNAL_MEMORY */
+ gcsEXTERNAL_MEMORY_INFO externalMemoryInfo;
+}
+gcsUSER_MEMORY_DESC;
+
+
+#define gcdMAX_FLAT_MAPPING_COUNT 16
+
+typedef struct _gcsFLAT_MAPPING_RANGE
+{
+ gctUINT64 start;
+ gctUINT64 end;
+}
+gcsFLAT_MAPPING_RANGE;
+
+/* gcvHAL_QUERY_CHIP_IDENTITY */
+typedef struct _gcsHAL_QUERY_CHIP_IDENTITY * gcsHAL_QUERY_CHIP_IDENTITY_PTR;
+typedef struct _gcsHAL_QUERY_CHIP_IDENTITY
+{
+
+ /* Chip model. */
+ gceCHIPMODEL chipModel;
+
+ /* Revision value.*/
+ gctUINT32 chipRevision;
+
+ /* Chip date. */
+ gctUINT32 chipDate;
+
+#if gcdENABLE_VG
+ /* Supported feature fields. */
+ gctUINT32 chipFeatures;
+
+ /* Supported minor feature fields. */
+ gctUINT32 chipMinorFeatures;
+
+ /* Supported minor feature 1 fields. */
+ gctUINT32 chipMinorFeatures1;
+
+ /* Supported minor feature 2 fields. */
+ gctUINT32 chipMinorFeatures2;
+
+ /* Supported minor feature 3 fields. */
+ gctUINT32 chipMinorFeatures3;
+
+ /* Supported minor feature 4 fields. */
+ gctUINT32 chipMinorFeatures4;
+
+ /* Supported minor feature 5 fields. */
+ gctUINT32 chipMinorFeatures5;
+
+ /* Supported minor feature 6 fields. */
+ gctUINT32 chipMinorFeatures6;
+#endif
+
+ /* Number of streams supported. */
+ gctUINT32 streamCount;
+
+ /* Number of pixel pipes. */
+ gctUINT32 pixelPipes;
+
+ /* Number of resolve pipes. */
+ gctUINT32 resolvePipes;
+
+ /* Number of instructions. */
+ gctUINT32 instructionCount;
+
+ /* Number of constants. */
+ gctUINT32 numConstants;
+
+ /* Number of varyings */
+ gctUINT32 varyingsCount;
+
+ /* Number of 3D GPUs */
+ gctUINT32 gpuCoreCount;
+
+ /* Product ID */
+ gctUINT32 productID;
+
+ /* Special chip flag bits */
+ gceCHIP_FLAG chipFlags;
+
+ /* ECO ID. */
+ gctUINT32 ecoID;
+
+ /* Customer ID. */
+ gctUINT32 customerID;
+}
+gcsHAL_QUERY_CHIP_IDENTITY;
+
+typedef struct _gcsHAL_QUERY_CHIP_OPTIONS * gcsHAL_QUERY_CHIP_OPTIONS_PTR;
+typedef struct _gcsHAL_QUERY_CHIP_OPTIONS
+{
+ gctBOOL gpuProfiler;
+ gctBOOL allowFastClear;
+ gctBOOL powerManagement;
+ /* Whether use new MMU. It is meaningless
+ ** for old MMU since old MMU is always enabled.
+ */
+ gctBOOL enableMMU;
+ gceCOMPRESSION_OPTION allowCompression;
+ gctUINT uscL1CacheRatio;
+ gceSECURE_MODE secureMode;
+
+}
+gcsHAL_QUERY_CHIP_OPTIONS;
+
+typedef struct _gcsHAL_INTERFACE
+{
+ /* Command code. */
+ gceHAL_COMMAND_CODES command;
+
+ /* Hardware type. */
+ gceHARDWARE_TYPE hardwareType;
+
+ /* Core index for current hardware type. */
+ gctUINT32 coreIndex;
+
+ /* Status value. */
+ gceSTATUS status;
+
+ /* Handle to this interface channel. */
+ gctUINT64 handle;
+
+ /* Pid of the client. */
+ gctUINT32 pid;
+
+ /* Engine */
+ gceENGINE engine;
+
+ /* Ignore information from TSL when doing IO control */
+ gctBOOL ignoreTLS;
+
+ /* Union of command structures. */
+ union _u
+ {
+ /* gcvHAL_GET_BASE_ADDRESS */
+ struct _gcsHAL_GET_BASE_ADDRESS
+ {
+ /* Physical memory address of internal memory. */
+ OUT gctUINT32 baseAddress;
+
+ OUT gctUINT32 flatMappingRangeCount;
+
+ OUT gcsFLAT_MAPPING_RANGE flatMappingRanges[gcdMAX_FLAT_MAPPING_COUNT];
+ }
+ GetBaseAddress;
+
+ /* gcvHAL_QUERY_VIDEO_MEMORY */
+ struct _gcsHAL_QUERY_VIDEO_MEMORY
+ {
+ /* Physical memory address of internal memory. Just a name. */
+ OUT gctUINT32 internalPhysical;
+
+ /* Size in bytes of internal memory. */
+ OUT gctUINT64 internalSize;
+
+ /* Physical memory address of external memory. Just a name. */
+ OUT gctUINT32 externalPhysical;
+
+ /* Size in bytes of external memory.*/
+ OUT gctUINT64 externalSize;
+
+ /* Physical memory address of contiguous memory. Just a name. */
+ OUT gctUINT32 contiguousPhysical;
+
+ /* Size in bytes of contiguous memory.*/
+ OUT gctUINT64 contiguousSize;
+ }
+ QueryVideoMemory;
+
+ /* gcvHAL_QUERY_CHIP_IDENTITY */
+ gcsHAL_QUERY_CHIP_IDENTITY QueryChipIdentity;
+
+ /* gcvHAL_MAP_MEMORY */
+ struct _gcsHAL_MAP_MEMORY
+ {
+ /* Physical memory address to map. Just a name on Linux/Qnx. */
+ IN gctUINT32 physical;
+
+ /* Number of bytes in physical memory to map. */
+ IN gctUINT64 bytes;
+
+ /* Address of mapped memory. */
+ OUT gctUINT64 logical;
+ }
+ MapMemory;
+
+ /* gcvHAL_UNMAP_MEMORY */
+ struct _gcsHAL_UNMAP_MEMORY
+ {
+ /* Physical memory address to unmap. Just a name on Linux/Qnx. */
+ IN gctUINT32 physical;
+
+ /* Number of bytes in physical memory to unmap. */
+ IN gctUINT64 bytes;
+
+ /* Address of mapped memory to unmap. */
+ IN gctUINT64 logical;
+ }
+ UnmapMemory;
+
+ /* gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY */
+ struct _gcsHAL_ALLOCATE_LINEAR_VIDEO_MEMORY
+ {
+ /* Number of bytes to allocate. */
+ IN OUT gctUINT bytes;
+
+ /* Buffer alignment. */
+ IN gctUINT alignment;
+
+ /* Type of allocation. */
+ IN gceSURF_TYPE type;
+
+ /* Flag of allocation. */
+ IN gctUINT32 flag;
+
+ /* Memory pool to allocate from. */
+ IN OUT gcePOOL pool;
+
+ /* Allocated video memory. */
+ OUT gctUINT32 node;
+ }
+ AllocateLinearVideoMemory;
+
+ /* gcvHAL_ALLOCATE_VIDEO_MEMORY */
+ struct _gcsHAL_ALLOCATE_VIDEO_MEMORY
+ {
+ /* Width of rectangle to allocate. */
+ IN OUT gctUINT width;
+
+ /* Height of rectangle to allocate. */
+ IN OUT gctUINT height;
+
+ /* Depth of rectangle to allocate. */
+ IN gctUINT depth;
+
+ /* Format rectangle to allocate in gceSURF_FORMAT. */
+ IN gceSURF_FORMAT format;
+
+ /* Type of allocation. */
+ IN gceSURF_TYPE type;
+
+ /* Memory pool to allocate from. */
+ IN OUT gcePOOL pool;
+
+ /* Allocated video memory. */
+ OUT gctUINT32 node;
+ }
+ AllocateVideoMemory;
+
+ /* gcvHAL_RELEASE_VIDEO_MEMORY */
+ struct _gcsHAL_RELEASE_VIDEO_MEMORY
+ {
+ /* Allocated video memory. */
+ IN gctUINT32 node;
+
+#ifdef __QNXNTO__
+ /* Mapped logical address to unmap in user space. */
+ OUT gctUINT64 memory;
+
+ /* Number of bytes to allocated. */
+ OUT gctUINT64 bytes;
+#endif
+ }
+ ReleaseVideoMemory;
+
+ /* gcvHAL_LOCK_VIDEO_MEMORY */
+ struct _gcsHAL_LOCK_VIDEO_MEMORY
+ {
+ /* Allocated video memory. */
+ IN gctUINT32 node;
+
+ /* Cache configuration. */
+ /* Only gcvPOOL_CONTIGUOUS and gcvPOOL_VIRUTAL
+ ** can be configured */
+ IN gctBOOL cacheable;
+
+ /* Hardware specific address. */
+ OUT gctUINT32 address;
+
+ /* Mapped logical address. */
+ OUT gctUINT64 memory;
+
+ /* Customer priviate handle*/
+ OUT gctUINT32 gid;
+
+ /* Bus address of a contiguous video node. */
+ OUT gctUINT64 physicalAddress;
+ }
+ LockVideoMemory;
+
+ /* gcvHAL_UNLOCK_VIDEO_MEMORY */
+ struct _gcsHAL_UNLOCK_VIDEO_MEMORY
+ {
+ /* Allocated video memory. */
+ IN gctUINT64 node;
+
+ /* Type of surface. */
+ IN gceSURF_TYPE type;
+
+ /* Pool of the unlock node */
+ OUT gcePOOL pool;
+
+ /* Bytes of the unlock node */
+ OUT gctUINT bytes;
+
+ /* Flag to unlock surface asynchroneously. */
+ IN OUT gctBOOL asynchroneous;
+ }
+ UnlockVideoMemory;
+
+ /* gcvHAL_ALLOCATE_NON_PAGED_MEMORY */
+ struct _gcsHAL_ALLOCATE_NON_PAGED_MEMORY
+ {
+ /* Number of bytes to allocate. */
+ IN OUT gctUINT64 bytes;
+
+ /* Physical address of allocation. Just a name. */
+ OUT gctUINT32 physical;
+
+ /* Logical address of allocation. */
+ OUT gctUINT64 logical;
+ }
+ AllocateNonPagedMemory;
+
+ /* gcvHAL_FREE_NON_PAGED_MEMORY */
+ struct _gcsHAL_FREE_NON_PAGED_MEMORY
+ {
+ /* Number of bytes allocated. */
+ IN gctUINT64 bytes;
+
+ /* Physical address of allocation. Just a name. */
+ IN gctUINT32 physical;
+
+ /* Logical address of allocation. */
+ IN gctUINT64 logical;
+ }
+ FreeNonPagedMemory;
+
+ /* gcvHAL_ALLOCATE_NON_PAGED_MEMORY */
+ struct _gcsHAL_ALLOCATE_VIRTUAL_COMMAND_BUFFER
+ {
+ /* Number of bytes to allocate. */
+ IN OUT gctUINT64 bytes;
+
+ /* Physical address of allocation. Just a name. */
+ OUT gctUINT32 physical;
+
+ /* Logical address of allocation. */
+ OUT gctUINT64 logical;
+ }
+ AllocateVirtualCommandBuffer;
+
+ /* gcvHAL_FREE_NON_PAGED_MEMORY */
+ struct _gcsHAL_FREE_VIRTUAL_COMMAND_BUFFER
+ {
+ /* Number of bytes allocated. */
+ IN gctUINT64 bytes;
+
+ /* Physical address of allocation. Just a name. */
+ IN gctUINT32 physical;
+
+ /* Logical address of allocation. */
+ IN gctUINT64 logical;
+ }
+ FreeVirtualCommandBuffer;
+
+ /* gcvHAL_EVENT_COMMIT. */
+ struct _gcsHAL_EVENT_COMMIT
+ {
+ /* Event queue in gcsQUEUE. */
+ IN gctUINT64 queue;
+ }
+ Event;
+
+ /* gcvHAL_COMMIT */
+ struct _gcsHAL_COMMIT
+ {
+ /* Context buffer object gckCONTEXT. */
+ IN gctUINT64 context;
+
+ /* Command buffer gcoCMDBUF. */
+ IN gctUINT64 commandBuffer;
+
+ /* State delta buffer in gcsSTATE_DELTA. */
+ gctUINT64 delta;
+
+ gctUINT64 deltas[gcvCORE_COUNT];
+
+ gctUINT64 contexts[gcvCORE_COUNT];
+
+ gctUINT64 commandBuffers[gcvCORE_COUNT];
+
+
+ /* Event queue in gcsQUEUE. */
+ IN gctUINT64 queue;
+
+ /* Used to distinguish different FE. */
+ IN gceENGINE engine1;
+
+ /* The command buffer is linked to multiple command queue. */
+ IN gctBOOL shared;
+
+ /* Index of command queue. */
+ IN gctUINT32 index;
+
+ /* Count of gpu core. */
+ IN gctUINT32 count;
+
+ /* Commit stamp of this commit. */
+ OUT gctUINT64 commitStamp;
+
+ /* If context switch for this commit */
+ OUT gctBOOL contextSwitched;
+ }
+ Commit;
+
+ /* gcvHAL_MAP_USER_MEMORY */
+ struct _gcsHAL_MAP_USER_MEMORY
+ {
+ /* Base address of user memory to map. */
+ IN gctUINT64 memory;
+
+ /* Physical address of user memory to map. */
+ IN gctUINT32 physical;
+
+ /* Size of user memory in bytes to map. */
+ IN gctUINT64 size;
+
+ /* Info record required by gcvHAL_UNMAP_USER_MEMORY. Just a name. */
+ OUT gctUINT32 info;
+
+ /* Physical address of mapped memory. */
+ OUT gctUINT32 address;
+ }
+ MapUserMemory;
+
+ /* gcvHAL_UNMAP_USER_MEMORY */
+ struct _gcsHAL_UNMAP_USER_MEMORY
+ {
+ /* Base address of user memory to unmap. */
+ IN gctUINT64 memory;
+
+ /* Size of user memory in bytes to unmap. */
+ IN gctUINT64 size;
+
+ /* Info record returned by gcvHAL_MAP_USER_MEMORY. Just a name. */
+ IN gctUINT32 info;
+
+ /* Physical address of mapped memory as returned by
+ gcvHAL_MAP_USER_MEMORY. */
+ IN gctUINT32 address;
+ }
+ UnmapUserMemory;
+#if !USE_NEW_LINUX_SIGNAL
+ /* gcsHAL_USER_SIGNAL */
+ struct _gcsHAL_USER_SIGNAL
+ {
+ /* Command. */
+ gceUSER_SIGNAL_COMMAND_CODES command;
+
+ /* Signal ID. */
+ IN OUT gctINT id;
+
+ /* Reset mode. */
+ IN gctBOOL manualReset;
+
+ /* Wait timedout. */
+ IN gctUINT32 wait;
+
+ /* State. */
+ IN gctBOOL state;
+ }
+ UserSignal;
+#endif
+
+ /* gcvHAL_SIGNAL. */
+ struct _gcsHAL_SIGNAL
+ {
+ /* Signal handle to signal gctSIGNAL. */
+ IN gctUINT64 signal;
+
+ /* Reserved gctSIGNAL. */
+ IN gctUINT64 auxSignal;
+
+ /* Process owning the signal gctHANDLE. */
+ IN gctUINT64 process;
+
+#if defined(__QNXNTO__)
+ /* Client pulse side-channel connection ID. Set by client in gcoOS_CreateSignal. */
+ IN gctINT32 coid;
+
+ /* Set by server. */
+ IN gctINT32 rcvid;
+#endif
+ /* Event generated from where of pipeline */
+ IN gceKERNEL_WHERE fromWhere;
+ }
+ Signal;
+
+ /* gcvHAL_WRITE_DATA. */
+ struct _gcsHAL_WRITE_DATA
+ {
+ /* Address to write data to. */
+ IN gctUINT32 address;
+
+ /* Data to write. */
+ IN gctUINT32 data;
+ }
+ WriteData;
+
+ /* gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY */
+ struct _gcsHAL_ALLOCATE_CONTIGUOUS_MEMORY
+ {
+ /* Number of bytes to allocate. */
+ IN OUT gctUINT64 bytes;
+
+ /* Hardware address of allocation. */
+ OUT gctUINT32 address;
+
+ /* Physical address of allocation. Just a name. */
+ OUT gctUINT32 physical;
+
+ /* Logical address of allocation. */
+ OUT gctUINT64 logical;
+ }
+ AllocateContiguousMemory;
+
+ /* gcvHAL_FREE_CONTIGUOUS_MEMORY */
+ struct _gcsHAL_FREE_CONTIGUOUS_MEMORY
+ {
+ /* Number of bytes allocated. */
+ IN gctUINT64 bytes;
+
+ /* Physical address of allocation. Just a name. */
+ IN gctUINT32 physical;
+
+ /* Logical address of allocation. */
+ IN gctUINT64 logical;
+ }
+ FreeContiguousMemory;
+
+ /* gcvHAL_READ_REGISTER */
+ struct _gcsHAL_READ_REGISTER
+ {
+ /* Logical address of memory to write data to. */
+ IN gctUINT32 address;
+
+ /* Data read. */
+ OUT gctUINT32 data;
+ }
+ ReadRegisterData;
+
+ /* gcvHAL_WRITE_REGISTER */
+ struct _gcsHAL_WRITE_REGISTER
+ {
+ /* Logical address of memory to write data to. */
+ IN gctUINT32 address;
+
+ /* Data read. */
+ IN gctUINT32 data;
+ }
+ WriteRegisterData;
+
+ /* gcvHAL_READ_REGISTER_EX */
+ struct _gcsHAL_READ_REGISTER_EX
+ {
+ /* Logical address of memory to write data to. */
+ IN gctUINT32 address;
+
+ IN gctUINT32 coreSelect;
+
+ /* Data read. */
+ OUT gctUINT32 data[4];
+ }
+ ReadRegisterDataEx;
+
+ /* gcvHAL_WRITE_REGISTER_EX */
+ struct _gcsHAL_WRITE_REGISTER_EX
+ {
+ /* Logical address of memory to write data to. */
+ IN gctUINT32 address;
+
+ IN gctUINT32 coreSelect;
+
+ /* Data read. */
+ IN gctUINT32 data[4];
+ }
+ WriteRegisterDataEx;
+
+#if VIVANTE_PROFILER
+ /* gcvHAL_GET_PROFILE_SETTING */
+ struct _gcsHAL_GET_PROFILE_SETTING
+ {
+ /* Enable profiling */
+ OUT gctBOOL enable;
+ }
+ GetProfileSetting;
+
+ /* gcvHAL_SET_PROFILE_SETTING */
+ struct _gcsHAL_SET_PROFILE_SETTING
+ {
+ /* Enable profiling */
+ IN gctBOOL enable;
+ }
+ SetProfileSetting;
+
+ /* gcvHAL_READ_PROFILER_REGISTER_SETTING */
+ struct _gcsHAL_READ_PROFILER_REGISTER_SETTING
+ {
+ /*Should Clear Register*/
+ IN gctBOOL bclear;
+ }
+ SetProfilerRegisterClear;
+
+ struct _gcsHAL_READ_ALL_PROFILE_REGISTERS_PART1
+ {
+ /* Context buffer object gckCONTEXT. Just a name. */
+ IN gctUINT32 context;
+
+ /* Data read. */
+ OUT gcsPROFILER_COUNTERS_PART1 Counters;
+ }
+ RegisterProfileData_part1;
+
+ struct _gcsHAL_READ_ALL_PROFILE_REGISTERS_PART2
+ {
+ /* Context buffer object gckCONTEXT. Just a name. */
+ IN gctUINT32 context;
+
+ /* Data read. */
+ OUT gcsPROFILER_COUNTERS_PART2 Counters;
+ }
+ RegisterProfileData_part2;
+
+ /* gcvHAL_PROFILE_REGISTERS_2D */
+ struct _gcsHAL_PROFILE_REGISTERS_2D
+ {
+ /* Data read in gcs2D_PROFILE. */
+ OUT gctUINT64 hwProfile2D;
+ }
+ RegisterProfileData2D;
+#endif
+
+ /* Power management. */
+ /* gcvHAL_SET_POWER_MANAGEMENT_STATE */
+ struct _gcsHAL_SET_POWER_MANAGEMENT
+ {
+ /* Data read. */
+ IN gceCHIPPOWERSTATE state;
+ }
+ SetPowerManagement;
+
+ /* gcvHAL_QUERY_POWER_MANAGEMENT_STATE */
+ struct _gcsHAL_QUERY_POWER_MANAGEMENT
+ {
+ /* Data read. */
+ OUT gceCHIPPOWERSTATE state;
+
+ /* Idle query. */
+ OUT gctBOOL isIdle;
+ }
+ QueryPowerManagement;
+
+ /* gcvHAL_QUERY_KERNEL_SETTINGS */
+ struct _gcsHAL_QUERY_KERNEL_SETTINGS
+ {
+ /* Settings.*/
+ OUT gcsKERNEL_SETTINGS settings;
+ }
+ QueryKernelSettings;
+
+ /* gcvHAL_MAP_PHYSICAL */
+ struct _gcsHAL_MAP_PHYSICAL
+ {
+ /* gcvTRUE to map, gcvFALSE to unmap. */
+ IN gctBOOL map;
+
+ /* Physical address. */
+ IN OUT gctUINT64 physical;
+ }
+ MapPhysical;
+
+ /* gcvHAL_DEBUG */
+ struct _gcsHAL_DEBUG
+ {
+ /* If gcvTRUE, set the debug information. */
+ IN gctBOOL set;
+ IN gctUINT32 level;
+ IN gctUINT32 zones;
+ IN gctBOOL enable;
+
+ IN gceDEBUG_MESSAGE_TYPE type;
+ IN gctUINT32 messageSize;
+
+ /* Message to print if not empty. */
+ IN gctCHAR message[80];
+
+ }
+ Debug;
+
+ /* gcvHAL_CACHE */
+ struct _gcsHAL_CACHE
+ {
+ IN gceCACHEOPERATION operation;
+ IN gctUINT64 process;
+ IN gctUINT64 logical;
+ IN gctUINT64 bytes;
+ IN gctUINT32 node;
+ }
+ Cache;
+
+ /* gcvHAL_TIMESTAMP */
+ struct _gcsHAL_TIMESTAMP
+ {
+ /* Timer select. */
+ IN gctUINT32 timer;
+
+ /* Timer request type (0-stop, 1-start, 2-send delta). */
+ IN gctUINT32 request;
+
+ /* Result of delta time in microseconds. */
+ OUT gctINT32 timeDelta;
+ }
+ TimeStamp;
+
+ /* gcvHAL_DATABASE */
+ struct _gcsHAL_DATABASE
+ {
+ /* Set to gcvTRUE if you want to query a particular process ID.
+ ** Set to gcvFALSE to query the last detached process. */
+ IN gctBOOL validProcessID;
+
+ /* Process ID to query. */
+ IN gctUINT32 processID;
+
+ /* Information. */
+ OUT gcuDATABASE_INFO vidMem;
+ OUT gcuDATABASE_INFO nonPaged;
+ OUT gcuDATABASE_INFO contiguous;
+ OUT gcuDATABASE_INFO gpuIdle;
+
+ /* Detail information about video memory. */
+ OUT gcuDATABASE_INFO vidMemPool[3];
+ }
+ Database;
+
+ /* gcvHAL_VERSION */
+ struct _gcsHAL_VERSION
+ {
+ /* Major version: N.n.n. */
+ OUT gctINT32 major;
+
+ /* Minor version: n.N.n. */
+ OUT gctINT32 minor;
+
+ /* Patch version: n.n.N. */
+ OUT gctINT32 patch;
+
+ /* Build version. */
+ OUT gctUINT32 build;
+ }
+ Version;
+
+ /* gcvHAL_CHIP_INFO */
+ struct _gcsHAL_CHIP_INFO
+ {
+ /* Chip count. */
+ OUT gctINT32 count;
+
+ /* Chip types. */
+ OUT gceHARDWARE_TYPE types[gcdCHIP_COUNT];
+
+ /* Chip IDs. */
+ OUT gctUINT32 ids[gcvCORE_COUNT];
+ }
+ ChipInfo;
+
+ /* gcvHAL_ATTACH */
+ struct _gcsHAL_ATTACH
+ {
+ /* Handle of context buffer object. */
+ OUT gctUINT32 context;
+
+ /* Maximum state in the buffer. */
+ OUT gctUINT64 maxState;
+
+ /* Number of states in the buffer. */
+ OUT gctUINT32 numStates;
+
+ /* Map context buffer to user or not. */
+ IN gctBOOL map;
+
+ /* Physical of context buffer. */
+ OUT gctUINT32 physicals[2];
+
+ /* Physical of context buffer. */
+ OUT gctUINT64 logicals[2];
+
+ /* Bytes of context buffer. */
+ OUT gctUINT32 bytes;
+ }
+ Attach;
+
+ /* gcvHAL_DETACH */
+ struct _gcsHAL_DETACH
+ {
+ /* Context buffer object gckCONTEXT. Just a name. */
+ IN gctUINT32 context;
+ }
+ Detach;
+
+ /* gcvHAL_GET_FRAME_INFO. */
+ struct _gcsHAL_GET_FRAME_INFO
+ {
+ /* gcsHAL_FRAME_INFO* */
+ OUT gctUINT64 frameInfo;
+ }
+ GetFrameInfo;
+
+ /* gcvHAL_SET_TIME_OUT. */
+ struct _gcsHAL_SET_TIMEOUT
+ {
+ gctUINT32 timeOut;
+ }
+ SetTimeOut;
+
+#if gcdENABLE_VG
+ /* gcvHAL_COMMIT */
+ struct _gcsHAL_VGCOMMIT
+ {
+ /* Context buffer. gcsVGCONTEXT_PTR */
+ IN gctUINT64 context;
+
+ /* Command queue. gcsVGCMDQUEUE_PTR */
+ IN gctUINT64 queue;
+
+ /* Number of entries in the queue. */
+ IN gctUINT entryCount;
+
+ /* Task table. gcsTASK_MASTER_TABLE_PTR */
+ IN gctUINT64 taskTable;
+ }
+ VGCommit;
+
+ /* gcvHAL_QUERY_COMMAND_BUFFER */
+ struct _gcsHAL_QUERY_COMMAND_BUFFER
+ {
+ /* Command buffer attributes. */
+ OUT gcsCOMMAND_BUFFER_INFO information;
+ }
+ QueryCommandBuffer;
+
+#endif
+
+ struct _gcsHAL_SET_FSCALE_VALUE
+ {
+ IN gctUINT value;
+ }
+ SetFscaleValue;
+
+ struct _gcsHAL_GET_FSCALE_VALUE
+ {
+ OUT gctUINT value;
+ OUT gctUINT minValue;
+ OUT gctUINT maxValue;
+ }
+ GetFscaleValue;
+
+ /* gcvHAL_EXPORT_VIDEO_MEMORY */
+ struct _gcsHAL_EXPORT_VIDEO_MEMORY
+ {
+ /* Allocated video memory. */
+ IN gctUINT32 node;
+
+ /* Export flags */
+ IN gctUINT32 flags;
+
+ /* Exported dma_buf fd */
+ OUT gctINT32 fd;
+ }
+ ExportVideoMemory;
+
+ struct _gcsHAL_NAME_VIDEO_MEMORY
+ {
+ IN gctUINT32 handle;
+ OUT gctUINT32 name;
+ }
+ NameVideoMemory;
+
+ struct _gcsHAL_IMPORT_VIDEO_MEMORY
+ {
+ IN gctUINT32 name;
+ OUT gctUINT32 handle;
+ }
+ ImportVideoMemory;
+
+ struct _gcsHAL_QUERY_RESET_TIME_STAMP
+ {
+ OUT gctUINT64 timeStamp;
+ OUT gctUINT64 contextID;
+ }
+ QueryResetTimeStamp;
+
+ struct _gcsHAL_CREATE_NATIVE_FENCE
+ {
+ /* Signal id. */
+ IN gctUINT64 signal;
+
+ /* Native fence file descriptor. */
+ OUT gctINT fenceFD;
+
+ }
+ CreateNativeFence;
+
+ struct _gcsHAL_WAIT_NATIVE_FENCE
+ {
+ /* Native fence file descriptor. */
+ IN gctINT fenceFD;
+
+ /* Wait timeout. */
+ IN gctUINT32 timeout;
+ }
+ WaitNativeFence;
+
+ struct _gcsHAL_DESTROY_MMU
+ {
+ /* Mmu object. */
+ IN gctUINT64 mmu;
+ }
+ DestroyMmu;
+
+ struct _gcsHAL_SHBUF
+ {
+ gceSHBUF_COMMAND_CODES command;
+
+ /* Shared buffer. */
+ IN OUT gctUINT64 id;
+
+ /* User data to be shared. */
+ IN gctUINT64 data;
+
+ /* Data size. */
+ IN OUT gctUINT32 bytes;
+ }
+ ShBuf;
+
+ struct _gcsHAL_GET_GRAPHIC_BUFFER_FD
+ {
+ /* Max 3 video nodes, node handle here. */
+ IN gctUINT32 node[3];
+
+ /* A shBuf. */
+ IN gctUINT64 shBuf;
+
+ /* A signal. */
+ IN gctUINT32 signal;
+
+ OUT gctINT32 fd;
+ }
+ GetGraphicBufferFd;
+
+ struct _gcsHAL_VIDEO_MEMORY_METADATA
+ {
+ /* Allocated video memory. */
+ IN gctUINT32 node;
+
+ IN gctUINT32 readback;
+
+ INOUT gctINT32 ts_fd;
+ INOUT gctUINT32 fc_enabled;
+ INOUT gctUINT32 fc_value;
+ INOUT gctUINT32 fc_value_upper;
+
+ INOUT gctUINT32 compressed;
+ INOUT gctUINT32 compress_format;
+ }
+ SetVidMemMetadata;
+
+ struct _gcsHAL_GET_VIDEO_MEMORY_FD
+ {
+ IN gctUINT32 handle;
+ OUT gctINT fd;
+ }
+ GetVideoMemoryFd;
+
+ struct _gcsHAL_CONFIG_POWER_MANAGEMENT
+ {
+ IN gctBOOL enable;
+ }
+ ConfigPowerManagement;
+
+ struct _gcsHAL_WRAP_USER_MEMORY
+ {
+ /* Description of user memory. */
+ IN gcsUSER_MEMORY_DESC desc;
+
+ /* Output video mmory node. */
+ OUT gctUINT32 node;
+
+ /* size of the node in bytes */
+ OUT gctUINT64 bytes;
+ }
+ WrapUserMemory;
+
+ struct _gcsHAL_WAIT_FENCE
+ {
+ IN gctUINT32 handle;
+ IN gctUINT32 timeOut;
+ }
+ WaitFence;
+
+ struct _gcsHAL_COMMIT_DONE
+ {
+ IN gctUINT64 context;
+ }
+ CommitDone;
+
+#if gcdDEC_ENABLE_AHB
+ struct _gcsHAL_DEC300_READ
+ {
+ gctUINT32 enable;
+ gctUINT32 readId;
+ gctUINT32 format;
+ gctUINT32 strides[3];
+ gctUINT32 is3D;
+ gctUINT32 isMSAA;
+ gctUINT32 clearValue;
+ gctUINT32 isTPC;
+ gctUINT32 isTPCCompressed;
+ gctUINT32 surfAddrs[3];
+ gctUINT32 tileAddrs[3];
+ }
+ DEC300Read;
+
+ struct _gcsHAL_DEC300_WRITE
+ {
+ gctUINT32 enable;
+ gctUINT32 readId;
+ gctUINT32 writeId;
+ gctUINT32 format;
+ gctUINT32 surfAddr;
+ gctUINT32 tileAddr;
+ }
+ DEC300Write;
+
+ struct _gcsHAL_DEC300_FLUSH
+ {
+ IN gctUINT8 useless;
+ }
+ DEC300Flush;
+
+ struct _gcsHAL_DEC300_FLUSH_WAIT
+ {
+ IN gctUINT32 done;
+ }
+ DEC300FlushWait;
+#endif
+ /* gcvHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY: */
+ struct _gcsHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY
+ {
+ /* Allocated video memory. */
+ IN gctUINT32 node;
+
+ /* Type of surface. */
+ IN gceSURF_TYPE type;
+ }
+ BottomHalfUnlockVideoMemory;
+
+ gcsHAL_QUERY_CHIP_OPTIONS QueryChipOptions;
+ }
+ u;
+}
+gcsHAL_INTERFACE;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_driver_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_driver_vg.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_driver_vg.h
new file mode 100644
index 000000000000..9dc4afd00e79
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_driver_vg.h
@@ -0,0 +1,300 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_driver_vg_h_
+#define __gc_hal_driver_vg_h_
+
+
+
+#include "gc_hal_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+******************************* I/O Control Codes ******************************
+\******************************************************************************/
+
+#define gcvHAL_CLASS "galcore"
+#define IOCTL_GCHAL_INTERFACE 30000
+
+/******************************************************************************\
+********************* Command buffer information structure. ********************
+\******************************************************************************/
+
+typedef struct _gcsCOMMAND_BUFFER_INFO * gcsCOMMAND_BUFFER_INFO_PTR;
+typedef struct _gcsCOMMAND_BUFFER_INFO
+{
+ /* FE command buffer interrupt ID. */
+ gctINT32 feBufferInt;
+
+ /* TS overflow interrupt ID. */
+ gctINT32 tsOverflowInt;
+
+ /* Alignment and mask for the buffer address. */
+ gctUINT addressMask;
+ gctUINT32 addressAlignment;
+
+ /* Alignment for each command. */
+ gctUINT32 commandAlignment;
+
+ /* Number of bytes required by the STATE command. */
+ gctUINT32 stateCommandSize;
+
+ /* Number of bytes required by the RESTART command. */
+ gctUINT32 restartCommandSize;
+
+ /* Number of bytes required by the FETCH command. */
+ gctUINT32 fetchCommandSize;
+
+ /* Number of bytes required by the CALL command. */
+ gctUINT32 callCommandSize;
+
+ /* Number of bytes required by the RETURN command. */
+ gctUINT32 returnCommandSize;
+
+ /* Number of bytes required by the EVENT command. */
+ gctUINT32 eventCommandSize;
+
+ /* Number of bytes required by the END command. */
+ gctUINT32 endCommandSize;
+
+ /* Number of bytes reserved at the tail of a static command buffer. */
+ gctUINT32 staticTailSize;
+
+ /* Number of bytes reserved at the tail of a dynamic command buffer. */
+ gctUINT32 dynamicTailSize;
+}
+gcsCOMMAND_BUFFER_INFO;
+
+/******************************************************************************\
+******************************** Task Structures *******************************
+\******************************************************************************/
+
+typedef enum _gceTASK
+{
+ gcvTASK_LINK,
+ gcvTASK_CLUSTER,
+ gcvTASK_INCREMENT,
+ gcvTASK_DECREMENT,
+ gcvTASK_SIGNAL,
+ gcvTASK_LOCKDOWN,
+ gcvTASK_UNLOCK_VIDEO_MEMORY,
+ gcvTASK_FREE_VIDEO_MEMORY,
+ gcvTASK_FREE_CONTIGUOUS_MEMORY,
+ gcvTASK_UNMAP_USER_MEMORY
+}
+gceTASK;
+
+typedef struct _gcsTASK_HEADER * gcsTASK_HEADER_PTR;
+typedef struct _gcsTASK_HEADER
+{
+ /* Task ID. */
+ IN gceTASK id;
+}
+gcsTASK_HEADER;
+
+typedef struct _gcsTASK_LINK * gcsTASK_LINK_PTR;
+typedef struct _gcsTASK_LINK
+{
+ /* Task ID (gcvTASK_LINK). */
+ IN gceTASK id;
+
+ /* Pointer to the next task container. */
+ IN gctPOINTER cotainer;
+
+ /* Pointer to the next task from the next task container. */
+ IN gcsTASK_HEADER_PTR task;
+}
+gcsTASK_LINK;
+
+typedef struct _gcsTASK_CLUSTER * gcsTASK_CLUSTER_PTR;
+typedef struct _gcsTASK_CLUSTER
+{
+ /* Task ID (gcvTASK_CLUSTER). */
+ IN gceTASK id;
+
+ /* Number of tasks in the cluster. */
+ IN gctUINT taskCount;
+}
+gcsTASK_CLUSTER;
+
+typedef struct _gcsTASK_INCREMENT * gcsTASK_INCREMENT_PTR;
+typedef struct _gcsTASK_INCREMENT
+{
+ /* Task ID (gcvTASK_INCREMENT). */
+ IN gceTASK id;
+
+ /* Address of the variable to increment. */
+ IN gctUINT32 address;
+}
+gcsTASK_INCREMENT;
+
+typedef struct _gcsTASK_DECREMENT * gcsTASK_DECREMENT_PTR;
+typedef struct _gcsTASK_DECREMENT
+{
+ /* Task ID (gcvTASK_DECREMENT). */
+ IN gceTASK id;
+
+ /* Address of the variable to decrement. */
+ IN gctUINT32 address;
+}
+gcsTASK_DECREMENT;
+
+typedef struct _gcsTASK_SIGNAL * gcsTASK_SIGNAL_PTR;
+typedef struct _gcsTASK_SIGNAL
+{
+ /* Task ID (gcvTASK_SIGNAL). */
+ IN gceTASK id;
+
+ /* Process owning the signal. */
+ IN gctHANDLE process;
+
+ /* Signal handle to signal. */
+ IN gctSIGNAL signal;
+
+#if defined(__QNXNTO__)
+ IN gctINT32 coid;
+ IN gctINT32 rcvid;
+#endif
+}
+gcsTASK_SIGNAL;
+
+typedef struct _gcsTASK_LOCKDOWN * gcsTASK_LOCKDOWN_PTR;
+typedef struct _gcsTASK_LOCKDOWN
+{
+ /* Task ID (gcvTASK_LOCKDOWN). */
+ IN gceTASK id;
+
+ /* Address of the user space counter. */
+ IN gctUINT32 userCounter;
+
+ /* Address of the kernel space counter. */
+ IN gctUINT32 kernelCounter;
+
+ /* Process owning the signal. */
+ IN gctHANDLE process;
+
+ /* Signal handle to signal. */
+ IN gctSIGNAL signal;
+}
+gcsTASK_LOCKDOWN;
+
+typedef struct _gcsTASK_UNLOCK_VIDEO_MEMORY * gcsTASK_UNLOCK_VIDEO_MEMORY_PTR;
+typedef struct _gcsTASK_UNLOCK_VIDEO_MEMORY
+{
+ /* Task ID (gcvTASK_UNLOCK_VIDEO_MEMORY). */
+ IN gceTASK id;
+
+ /* Allocated video memory. */
+ IN gctUINT64 node;
+}
+gcsTASK_UNLOCK_VIDEO_MEMORY;
+
+typedef struct _gcsTASK_FREE_VIDEO_MEMORY * gcsTASK_FREE_VIDEO_MEMORY_PTR;
+typedef struct _gcsTASK_FREE_VIDEO_MEMORY
+{
+ /* Task ID (gcvTASK_FREE_VIDEO_MEMORY). */
+ IN gceTASK id;
+
+ /* Allocated video memory. */
+ IN gctUINT32 node;
+}
+gcsTASK_FREE_VIDEO_MEMORY;
+
+typedef struct _gcsTASK_FREE_CONTIGUOUS_MEMORY * gcsTASK_FREE_CONTIGUOUS_MEMORY_PTR;
+typedef struct _gcsTASK_FREE_CONTIGUOUS_MEMORY
+{
+ /* Task ID (gcvTASK_FREE_CONTIGUOUS_MEMORY). */
+ IN gceTASK id;
+
+ /* Number of bytes allocated. */
+ IN gctSIZE_T bytes;
+
+ /* Physical address of allocation. */
+ IN gctPHYS_ADDR physical;
+
+ /* Logical address of allocation. */
+ IN gctPOINTER logical;
+}
+gcsTASK_FREE_CONTIGUOUS_MEMORY;
+
+typedef struct _gcsTASK_UNMAP_USER_MEMORY * gcsTASK_UNMAP_USER_MEMORY_PTR;
+typedef struct _gcsTASK_UNMAP_USER_MEMORY
+{
+ /* Task ID (gcvTASK_UNMAP_USER_MEMORY). */
+ IN gceTASK id;
+
+ /* Base address of user memory to unmap. */
+ IN gctPOINTER memory;
+
+ /* Size of user memory in bytes to unmap. */
+ IN gctSIZE_T size;
+
+ /* Info record returned by gcvHAL_MAP_USER_MEMORY. */
+ IN gctPOINTER info;
+
+ /* Physical address of mapped memory as returned by
+ gcvHAL_MAP_USER_MEMORY. */
+ IN gctUINT32 address;
+}
+gcsTASK_UNMAP_USER_MEMORY;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_driver_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_drm.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_drm.h
new file mode 100644
index 000000000000..cb59f8194c7f
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_drm.h
@@ -0,0 +1,199 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __VIVNATE_DRM_H__
+#define __VIVNATE_DRM_H__
+
+#if !defined(__KERNEL__)
+#include <drm.h>
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* creation flag bits. */
+#define DRM_VIV_GEM_CONTIGUOUS (1u << 0)
+#define DRM_VIV_GEM_CACHED (1u << 1)
+#define DRM_VIV_GEM_SECURE (1u << 2)
+#define DRM_VIV_GEM_CMA_LIMIT (1u << 3)
+
+struct drm_viv_gem_create {
+ __u64 size;
+ __u32 flags;
+ __u32 handle;
+};
+
+struct drm_viv_gem_lock {
+ __u32 handle;
+ __u32 cacheable;
+ __u64 logical;
+};
+
+struct drm_viv_gem_unlock {
+ __u32 handle;
+};
+
+
+#define DRM_VIV_GEM_CLEAN_CACHE 0x01
+#define DRM_VIV_GEM_INVALIDATE_CACHE 0x02
+#define DRM_VIV_GEM_FLUSH_CACHE 0x03
+#define DRM_VIV_GEM_MEMORY_BARRIER 0x04
+
+struct drm_viv_gem_cache {
+ __u32 handle;
+ __u32 op;
+ __u64 logical;
+ __u64 bytes;
+};
+
+
+#define DRM_VIV_GEM_PARAM_POOL 0x00
+#define DRM_VIV_GEM_PARAM_SIZE 0x01
+
+struct drm_viv_gem_query {
+ __u32 handle;
+ __u32 param;
+ __u64 value;
+};
+
+
+struct drm_viv_gem_timestamp {
+ __u32 handle;
+ /* inc count, 0 for query current. */
+ __u32 inc;
+ /* output inc'ed timestamp. */
+ __u64 timestamp;
+};
+
+
+/* basic tiling mode. */
+#define DRM_VIV_GEM_TILING_LINEAR 0x01
+#define DRM_VIV_GEM_TILING_TILED 0x02
+#define DRM_VIV_GEM_TILING_SUPERTILED 0x04
+#define DRM_VIV_GEM_TILING_MINORTILED 0x08
+
+/* tiling mode modifiers. */
+#define DRM_VIV_GEM_TILING_SPLIT 0x10
+#define DRM_VIV_GEM_TILING_X_MAJOR 0x20
+#define DRM_VIV_GEM_TILING_Y_MAJOR 0x40
+#define DRM_VIV_GEM_TILING_SWAP 0x80
+
+/* ts mode. */
+#define DRM_VIV_GEM_TS_NONE 0x00
+#define DRM_VIV_GEM_TS_DISABLED 0x01
+#define DRM_VIV_GEM_TS_NORMAL 0x02
+#define DRM_VIV_GEM_TS_COMPRESSED 0x03
+
+struct drm_viv_gem_set_tiling {
+ __u32 handle;
+ __u32 tiling_mode;
+
+ __u32 ts_mode;
+ __u64 clear_value;
+};
+
+struct drm_viv_gem_get_tiling {
+ __u32 handle;
+ __u32 tiling_mode;
+
+ __u32 ts_mode;
+ __u64 clear_value;
+};
+
+
+struct drm_viv_gem_attach_aux {
+ __u32 handle;
+ __u32 ts_handle;
+};
+
+
+struct drm_viv_gem_ref_node {
+ __u32 handle;
+
+ /* output. */
+ __u32 node;
+ __u32 ts_node;
+};
+
+
+#define DRM_VIV_GEM_CREATE 0x00
+#define DRM_VIV_GEM_LOCK 0x01
+#define DRM_VIV_GEM_UNLOCK 0x02
+#define DRM_VIV_GEM_CACHE 0x03
+#define DRM_VIV_GEM_QUERY 0x04
+#define DRM_VIV_GEM_TIMESTAMP 0x05
+#define DRM_VIV_GEM_SET_TILING 0x06
+#define DRM_VIV_GEM_GET_TILING 0x07
+#define DRM_VIV_GEM_ATTACH_AUX 0x08
+#define DRM_VIV_GEM_REF_NODE 0x09
+#define DRM_VIV_NUM_IOCTLS 0x0A
+
+#define DRM_IOCTL_VIV_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_CREATE, struct drm_viv_gem_create)
+#define DRM_IOCTL_VIV_GEM_LOCK DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_LOCK, struct drm_viv_gem_lock)
+#define DRM_IOCTL_VIV_GEM_UNLOCK DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_UNLOCK, struct drm_viv_gem_unlock)
+#define DRM_IOCTL_VIV_GEM_CACHE DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_CACHE, struct drm_viv_gem_cache)
+#define DRM_IOCTL_VIV_GEM_QUERY DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_QUERY, struct drm_viv_gem_query)
+#define DRM_IOCTL_VIV_GEM_TIMESTAMP DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_TIMESTAMP, struct drm_viv_gem_timestamp)
+#define DRM_IOCTL_VIV_GEM_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_SET_TILING, struct drm_viv_gem_set_tiling)
+#define DRM_IOCTL_VIV_GEM_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_GET_TILING, struct drm_viv_gem_get_tiling)
+#define DRM_IOCTL_VIV_GEM_ATTACH_AUX DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_ATTACH_AUX, struct drm_viv_gem_attach_aux)
+#define DRM_IOCTL_VIV_GEM_REF_NODE DRM_IOWR(DRM_COMMAND_BASE + DRM_VIV_GEM_REF_NODE, struct drm_viv_gem_ref_node)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __VIVNATE_DRM_H__ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_dump.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_dump.h
new file mode 100644
index 000000000000..aad72e789137
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_dump.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_dump_h_
+#define __gc_hal_dump_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** FILE LAYOUT:
+**
+** gcsDUMP_FILE structure
+**
+** gcsDUMP_DATA frame
+** gcsDUMP_DATA or gcDUMP_DATA_SIZE records rendingring the frame
+** gctUINT8 data[length]
+*/
+
+#define gcvDUMP_FILE_SIGNATURE gcmCC('g','c','D','B')
+
+typedef struct _gcsDUMP_FILE
+{
+ gctUINT32 signature; /* File signature */
+ gctSIZE_T length; /* Length of file */
+ gctUINT32 frames; /* Number of frames in file */
+}
+gcsDUMP_FILE;
+
+typedef enum _gceDUMP_TAG
+{
+ gcvTAG_SURFACE = gcmCC('s','u','r','f'),
+ gcvTAG_FRAME = gcmCC('f','r','m',' '),
+ gcvTAG_COMMAND = gcmCC('c','m','d',' '),
+ gcvTAG_INDEX = gcmCC('i','n','d','x'),
+ gcvTAG_STREAM = gcmCC('s','t','r','m'),
+ gcvTAG_TEXTURE = gcmCC('t','e','x','t'),
+ gcvTAG_RENDER_TARGET = gcmCC('r','n','d','r'),
+ gcvTAG_DEPTH = gcmCC('z','b','u','f'),
+ gcvTAG_RESOLVE = gcmCC('r','s','l','v'),
+ gcvTAG_DELETE = gcmCC('d','e','l',' '),
+ gcvTAG_BUFOBJ = gcmCC('b','u','f','o'),
+}
+gceDUMP_TAG;
+
+typedef struct _gcsDUMP_SURFACE
+{
+ gceDUMP_TAG type; /* Type of record. */
+ gctUINT32 address; /* Address of the surface. */
+ gctINT16 width; /* Width of surface. */
+ gctINT16 height; /* Height of surface. */
+ gceSURF_FORMAT format; /* Surface pixel format. */
+ gctSIZE_T length; /* Number of bytes inside the surface. */
+}
+gcsDUMP_SURFACE;
+
+typedef struct _gcsDUMP_DATA
+{
+ gceDUMP_TAG type; /* Type of record. */
+ gctSIZE_T length; /* Number of bytes of data. */
+ gctUINT32 address; /* Address for the data. */
+}
+gcsDUMP_DATA;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_dump_h_ */
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_eglplatform.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_eglplatform.h
new file mode 100644
index 000000000000..1dbdd4c907bb
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_eglplatform.h
@@ -0,0 +1,587 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_eglplatform_h_
+#define __gc_hal_eglplatform_h_
+
+#include "gc_hal_types.h"
+#include "gc_hal_base.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
+#ifndef WIN32_LEAN_AND_MEAN
+/* #define WIN32_LEAN_AND_MEAN 1 */
+#endif
+#include <windows.h>
+
+typedef HDC HALNativeDisplayType;
+typedef HWND HALNativeWindowType;
+typedef HBITMAP HALNativePixmapType;
+
+typedef struct __BITFIELDINFO
+{
+ BITMAPINFO bmi;
+ RGBQUAD bmiColors[2];
+}
+BITFIELDINFO;
+
+#elif /* defined(__APPLE__) || */ defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
+
+#elif defined(WL_EGL_PLATFORM) || defined(EGL_API_WL) /* Wayland */
+
+#elif defined(__GBM__) /* GBM */
+
+#elif defined(__ANDROID__) || defined(ANDROID)
+
+#elif defined(MIR_EGL_PLATFORM) /* Mir */
+
+#elif defined(__QNXNTO__)
+
+#elif defined(__unix__) || defined(__APPLE__)
+
+#if defined(EGL_API_DFB)
+
+#elif defined(EGL_API_FB)
+
+#elif defined(EGL_API_NULLWS)
+
+
+#else
+
+/* X11 (tetative). */
+#endif
+
+#else
+#error "Platform not recognized"
+#endif
+
+#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
+
+#include "gc_hal_eglplatform_type.h"
+
+/*******************************************************************************
+** Display. ********************************************************************
+*/
+
+gceSTATUS
+gcoOS_GetDisplay(
+ OUT HALNativeDisplayType * Display,
+ IN gctPOINTER Context
+ );
+
+gceSTATUS
+gcoOS_GetDisplayByIndex(
+ IN gctINT DisplayIndex,
+ OUT HALNativeDisplayType * Display,
+ IN gctPOINTER Context
+ );
+
+gceSTATUS
+gcoOS_GetDisplayInfo(
+ IN HALNativeDisplayType Display,
+ OUT gctINT * Width,
+ OUT gctINT * Height,
+ OUT gctSIZE_T * Physical,
+ OUT gctINT * Stride,
+ OUT gctINT * BitsPerPixel
+ );
+
+
+
+gceSTATUS
+gcoOS_GetDisplayInfoEx(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window,
+ IN gctUINT DisplayInfoSize,
+ OUT halDISPLAY_INFO * DisplayInfo
+ );
+
+gceSTATUS
+gcoOS_GetDisplayVirtual(
+ IN HALNativeDisplayType Display,
+ OUT gctINT * Width,
+ OUT gctINT * Height
+ );
+
+gceSTATUS
+gcoOS_GetDisplayBackbuffer(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window,
+ OUT gctPOINTER * context,
+ OUT gcoSURF * surface,
+ OUT gctUINT * Offset,
+ OUT gctINT * X,
+ OUT gctINT * Y
+ );
+
+gceSTATUS
+gcoOS_SetDisplayVirtual(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window,
+ IN gctUINT Offset,
+ IN gctINT X,
+ IN gctINT Y
+ );
+
+gceSTATUS
+gcoOS_SetDisplayVirtualEx(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window,
+ IN gctPOINTER Context,
+ IN gcoSURF Surface,
+ IN gctUINT Offset,
+ IN gctINT X,
+ IN gctINT Y
+ );
+
+gceSTATUS
+gcoOS_CancelDisplayBackbuffer(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window,
+ IN gctPOINTER Context,
+ IN gcoSURF Surface,
+ IN gctUINT Offset,
+ IN gctINT X,
+ IN gctINT Y
+ );
+
+gceSTATUS
+gcoOS_SetSwapInterval(
+ IN HALNativeDisplayType Display,
+ IN gctINT Interval
+);
+
+gceSTATUS
+gcoOS_SetSwapIntervalEx(
+ IN HALNativeDisplayType Display,
+ IN gctINT Interval,
+ IN gctPOINTER localDisplay);
+
+gceSTATUS
+gcoOS_GetSwapInterval(
+ IN HALNativeDisplayType Display,
+ IN gctINT_PTR Min,
+ IN gctINT_PTR Max
+);
+
+gceSTATUS
+gcoOS_DisplayBufferRegions(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window,
+ IN gctINT NumRects,
+ IN gctINT_PTR Rects
+ );
+
+gceSTATUS
+gcoOS_DestroyDisplay(
+ IN HALNativeDisplayType Display
+ );
+
+gceSTATUS
+gcoOS_InitLocalDisplayInfo(
+ IN HALNativeDisplayType Display,
+ IN OUT gctPOINTER * localDisplay
+ );
+
+gceSTATUS
+gcoOS_DeinitLocalDisplayInfo(
+ IN HALNativeDisplayType Display,
+ IN OUT gctPOINTER * localDisplay
+ );
+
+gceSTATUS
+gcoOS_GetDisplayInfoEx2(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window,
+ IN gctPOINTER localDisplay,
+ IN gctUINT DisplayInfoSize,
+ OUT halDISPLAY_INFO * DisplayInfo
+ );
+
+gceSTATUS
+gcoOS_GetDisplayBackbufferEx(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window,
+ IN gctPOINTER localDisplay,
+ OUT gctPOINTER * context,
+ OUT gcoSURF * surface,
+ OUT gctUINT * Offset,
+ OUT gctINT * X,
+ OUT gctINT * Y
+ );
+
+gceSTATUS
+gcoOS_IsValidDisplay(
+ IN HALNativeDisplayType Display
+ );
+
+gceSTATUS
+gcoOS_GetNativeVisualId(
+ IN HALNativeDisplayType Display,
+ OUT gctINT* nativeVisualId
+ );
+
+gctBOOL
+gcoOS_SynchronousFlip(
+ IN HALNativeDisplayType Display
+ );
+
+/*******************************************************************************
+** Windows. ********************************************************************
+*/
+
+gceSTATUS
+gcoOS_CreateWindow(
+ IN HALNativeDisplayType Display,
+ IN gctINT X,
+ IN gctINT Y,
+ IN gctINT Width,
+ IN gctINT Height,
+ OUT HALNativeWindowType * Window
+ );
+
+gceSTATUS
+gcoOS_GetWindowInfo(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window,
+ OUT gctINT * X,
+ OUT gctINT * Y,
+ OUT gctINT * Width,
+ OUT gctINT * Height,
+ OUT gctINT * BitsPerPixel,
+ OUT gctUINT * Offset
+ );
+
+gceSTATUS
+gcoOS_DestroyWindow(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window
+ );
+
+gceSTATUS
+gcoOS_DrawImage(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window,
+ IN gctINT Left,
+ IN gctINT Top,
+ IN gctINT Right,
+ IN gctINT Bottom,
+ IN gctINT Width,
+ IN gctINT Height,
+ IN gctINT BitsPerPixel,
+ IN gctPOINTER Bits
+ );
+
+gceSTATUS
+gcoOS_GetImage(
+ IN HALNativeWindowType Window,
+ IN gctINT Left,
+ IN gctINT Top,
+ IN gctINT Right,
+ IN gctINT Bottom,
+ OUT gctINT * BitsPerPixel,
+ OUT gctPOINTER * Bits
+ );
+
+gceSTATUS
+gcoOS_GetWindowInfoEx(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window,
+ OUT gctINT * X,
+ OUT gctINT * Y,
+ OUT gctINT * Width,
+ OUT gctINT * Height,
+ OUT gctINT * BitsPerPixel,
+ OUT gctUINT * Offset,
+ OUT gceSURF_FORMAT * Format,
+ OUT gceSURF_TYPE * Type
+ );
+
+gceSTATUS
+gcoOS_DrawImageEx(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window,
+ IN gctINT Left,
+ IN gctINT Top,
+ IN gctINT Right,
+ IN gctINT Bottom,
+ IN gctINT Width,
+ IN gctINT Height,
+ IN gctINT BitsPerPixel,
+ IN gctPOINTER Bits,
+ IN gceSURF_FORMAT Format
+ );
+
+/*
+ * Possiable types:
+ * gcvSURF_BITMAP
+ * gcvSURF_RENDER_TARGET
+ * gcvSURF_RENDER_TARGET_NO_COMPRESSION
+ * gcvSURF_RENDER_TARGET_NO_TILE_STATUS
+ */
+gceSTATUS
+gcoOS_SetWindowFormat(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window,
+ IN gceSURF_TYPE Type,
+ IN gceSURF_FORMAT Format
+ );
+
+
+/*******************************************************************************
+** Pixmaps. ********************************************************************
+*/
+
+gceSTATUS
+gcoOS_CreatePixmap(
+ IN HALNativeDisplayType Display,
+ IN gctINT Width,
+ IN gctINT Height,
+ IN gctINT BitsPerPixel,
+ OUT HALNativePixmapType * Pixmap
+ );
+
+gceSTATUS
+gcoOS_GetPixmapInfo(
+ IN HALNativeDisplayType Display,
+ IN HALNativePixmapType Pixmap,
+ OUT gctINT * Width,
+ OUT gctINT * Height,
+ OUT gctINT * BitsPerPixel,
+ OUT gctINT * Stride,
+ OUT gctPOINTER * Bits
+ );
+
+gceSTATUS
+gcoOS_DrawPixmap(
+ IN HALNativeDisplayType Display,
+ IN HALNativePixmapType Pixmap,
+ IN gctINT Left,
+ IN gctINT Top,
+ IN gctINT Right,
+ IN gctINT Bottom,
+ IN gctINT Width,
+ IN gctINT Height,
+ IN gctINT BitsPerPixel,
+ IN gctPOINTER Bits
+ );
+
+gceSTATUS
+gcoOS_DestroyPixmap(
+ IN HALNativeDisplayType Display,
+ IN HALNativePixmapType Pixmap
+ );
+
+gceSTATUS
+gcoOS_GetPixmapInfoEx(
+ IN HALNativeDisplayType Display,
+ IN HALNativePixmapType Pixmap,
+ OUT gctINT * Width,
+ OUT gctINT * Height,
+ OUT gctINT * BitsPerPixel,
+ OUT gctINT * Stride,
+ OUT gctPOINTER * Bits,
+ OUT gceSURF_FORMAT * Format
+ );
+
+gceSTATUS
+gcoOS_CopyPixmapBits(
+ IN HALNativeDisplayType Display,
+ IN HALNativePixmapType Pixmap,
+ IN gctUINT DstWidth,
+ IN gctUINT DstHeight,
+ IN gctINT DstStride,
+ IN gceSURF_FORMAT DstFormat,
+ OUT gctPOINTER DstBits
+ );
+
+/*******************************************************************************
+** OS relative. ****************************************************************
+*/
+gceSTATUS
+gcoOS_LoadEGLLibrary(
+ OUT gctHANDLE * Handle
+ );
+
+gceSTATUS
+gcoOS_FreeEGLLibrary(
+ IN gctHANDLE Handle
+ );
+
+gceSTATUS
+gcoOS_ShowWindow(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window
+ );
+
+gceSTATUS
+gcoOS_HideWindow(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window
+ );
+
+gceSTATUS
+gcoOS_SetWindowTitle(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window,
+ IN gctCONST_STRING Title
+ );
+
+gceSTATUS
+gcoOS_CapturePointer(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window
+ );
+
+gceSTATUS
+gcoOS_GetEvent(
+ IN HALNativeDisplayType Display,
+ IN HALNativeWindowType Window,
+ OUT halEvent * Event
+ );
+
+gceSTATUS
+gcoOS_CreateClientBuffer(
+ IN gctINT Width,
+ IN gctINT Height,
+ IN gctINT Format,
+ IN gctINT Type,
+ OUT gctPOINTER * ClientBuffer
+ );
+
+gceSTATUS
+gcoOS_GetClientBufferInfo(
+ IN gctPOINTER ClientBuffer,
+ OUT gctINT * Width,
+ OUT gctINT * Height,
+ OUT gctINT * Stride,
+ OUT gctPOINTER * Bits
+ );
+
+gceSTATUS
+gcoOS_DestroyClientBuffer(
+ IN gctPOINTER ClientBuffer
+ );
+
+gceSTATUS
+gcoOS_DestroyContext(
+ IN gctPOINTER Display,
+ IN gctPOINTER Context
+ );
+
+gceSTATUS
+gcoOS_CreateContext(
+ IN gctPOINTER LocalDisplay,
+ IN gctPOINTER Context
+ );
+
+gceSTATUS
+gcoOS_MakeCurrent(
+ IN gctPOINTER LocalDisplay,
+ IN HALNativeWindowType DrawDrawable,
+ IN HALNativeWindowType ReadDrawable,
+ IN gctPOINTER Context,
+ IN gcoSURF ResolveTarget
+ );
+
+gceSTATUS
+gcoOS_CreateDrawable(
+ IN gctPOINTER LocalDisplay,
+ IN HALNativeWindowType Drawable
+ );
+
+gceSTATUS
+gcoOS_DestroyDrawable(
+ IN gctPOINTER LocalDisplay,
+ IN HALNativeWindowType Drawable
+ );
+gceSTATUS
+gcoOS_SwapBuffers(
+ IN gctPOINTER LocalDisplay,
+ IN HALNativeWindowType Drawable,
+ IN gcoSURF RenderTarget,
+ IN gcoSURF ResolveTarget,
+ IN gctPOINTER ResolveBits,
+ OUT gctUINT *Width,
+ OUT gctUINT *Height
+ );
+
+gceSTATUS
+gcoOS_ResizeWindow(
+ IN gctPOINTER localDisplay,
+ IN HALNativeWindowType Drawable,
+ IN gctUINT Width,
+ IN gctUINT Height
+ );
+
+gceSTATUS
+gcoOS_RSForSwap(
+ IN gctPOINTER localDisplay,
+ IN HALNativeWindowType Drawable,
+ IN gctPOINTER resolve
+ );
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_eglplatform_h_ */
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_eglplatform_type.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_eglplatform_type.h
new file mode 100644
index 000000000000..a86708e88b72
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_eglplatform_type.h
@@ -0,0 +1,324 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_eglplatform_type_h_
+#define __gc_hal_eglplatform_type_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+** Events. *********************************************************************
+*/
+
+typedef enum _halEventType
+{
+ /* Keyboard event. */
+ HAL_KEYBOARD,
+
+ /* Mouse move event. */
+ HAL_POINTER,
+
+ /* Mouse button event. */
+ HAL_BUTTON,
+
+ /* Application close event. */
+ HAL_CLOSE,
+
+ /* Application window has been updated. */
+ HAL_WINDOW_UPDATE
+}
+halEventType;
+
+/* Scancodes for keyboard. */
+typedef enum _halKeys
+{
+ HAL_UNKNOWN = -1,
+
+ HAL_BACKSPACE = 0x08,
+ HAL_TAB,
+ HAL_ENTER = 0x0D,
+ HAL_ESCAPE = 0x1B,
+
+ HAL_SPACE = 0x20,
+ HAL_SINGLEQUOTE = 0x27,
+ HAL_PAD_ASTERISK = 0x2A,
+ HAL_COMMA = 0x2C,
+ HAL_HYPHEN,
+ HAL_PERIOD,
+ HAL_SLASH,
+ HAL_0,
+ HAL_1,
+ HAL_2,
+ HAL_3,
+ HAL_4,
+ HAL_5,
+ HAL_6,
+ HAL_7,
+ HAL_8,
+ HAL_9,
+ HAL_SEMICOLON = 0x3B,
+ HAL_EQUAL = 0x3D,
+ HAL_A = 0x41,
+ HAL_B,
+ HAL_C,
+ HAL_D,
+ HAL_E,
+ HAL_F,
+ HAL_G,
+ HAL_H,
+ HAL_I,
+ HAL_J,
+ HAL_K,
+ HAL_L,
+ HAL_M,
+ HAL_N,
+ HAL_O,
+ HAL_P,
+ HAL_Q,
+ HAL_R,
+ HAL_S,
+ HAL_T,
+ HAL_U,
+ HAL_V,
+ HAL_W,
+ HAL_X,
+ HAL_Y,
+ HAL_Z,
+ HAL_LBRACKET,
+ HAL_BACKSLASH,
+ HAL_RBRACKET,
+ HAL_BACKQUOTE = 0x60,
+
+ HAL_F1 = 0x80,
+ HAL_F2,
+ HAL_F3,
+ HAL_F4,
+ HAL_F5,
+ HAL_F6,
+ HAL_F7,
+ HAL_F8,
+ HAL_F9,
+ HAL_F10,
+ HAL_F11,
+ HAL_F12,
+
+ HAL_LCTRL,
+ HAL_RCTRL,
+ HAL_LSHIFT,
+ HAL_RSHIFT,
+ HAL_LALT,
+ HAL_RALT,
+ HAL_CAPSLOCK,
+ HAL_NUMLOCK,
+ HAL_SCROLLLOCK,
+ HAL_PAD_0,
+ HAL_PAD_1,
+ HAL_PAD_2,
+ HAL_PAD_3,
+ HAL_PAD_4,
+ HAL_PAD_5,
+ HAL_PAD_6,
+ HAL_PAD_7,
+ HAL_PAD_8,
+ HAL_PAD_9,
+ HAL_PAD_HYPHEN,
+ HAL_PAD_PLUS,
+ HAL_PAD_SLASH,
+ HAL_PAD_PERIOD,
+ HAL_PAD_ENTER,
+ HAL_SYSRQ,
+ HAL_PRNTSCRN,
+ HAL_BREAK,
+ HAL_UP,
+ HAL_LEFT,
+ HAL_RIGHT,
+ HAL_DOWN,
+ HAL_HOME,
+ HAL_END,
+ HAL_PGUP,
+ HAL_PGDN,
+ HAL_INSERT,
+ HAL_DELETE,
+ HAL_LWINDOW,
+ HAL_RWINDOW,
+ HAL_MENU,
+ HAL_POWER,
+ HAL_SLEEP,
+ HAL_WAKE
+}
+halKeys;
+
+/* Structure that defined keyboard mapping. */
+typedef struct _halKeyMap
+{
+ /* Normal key. */
+ halKeys normal;
+
+ /* Extended key. */
+ halKeys extended;
+}
+halKeyMap;
+
+/* Event structure. */
+typedef struct _halEvent
+{
+ /* Event type. */
+ halEventType type;
+
+ /* Event data union. */
+ union _halEventData
+ {
+ /* Event data for keyboard. */
+ struct _halKeyboard
+ {
+ /* Scancode. */
+ halKeys scancode;
+
+ /* ASCII characte of the key pressed. */
+ char key;
+
+ /* Flag whether the key was pressed (1) or released (0). */
+ char pressed;
+ }
+ keyboard;
+
+ /* Event data for pointer. */
+ struct _halPointer
+ {
+ /* Current pointer coordinate. */
+ int x;
+ int y;
+ }
+ pointer;
+
+ /* Event data for mouse buttons. */
+ struct _halButton
+ {
+ /* Left button state. */
+ int left;
+
+ /* Middle button state. */
+ int middle;
+
+ /* Right button state. */
+ int right;
+
+ /* Current pointer coordinate. */
+ int x;
+ int y;
+ }
+ button;
+ }
+ data;
+}
+halEvent;
+
+/* VFK_DISPLAY_INFO structure defining information returned by
+ vdkGetDisplayInfoEx. */
+typedef struct _halDISPLAY_INFO
+{
+ /* The size of the display in pixels. */
+ int width;
+ int height;
+
+ /* The stride of the dispay. -1 is returned if the stride is not known
+ ** for the specified display.*/
+ int stride;
+
+ /* The color depth of the display in bits per pixel. */
+ int bitsPerPixel;
+
+ /* The logical pointer to the display memory buffer. NULL is returned
+ ** if the pointer is not known for the specified display. */
+ void * logical;
+
+ /* The physical address of the display memory buffer. ~0 is returned
+ ** if the address is not known for the specified display. */
+ unsigned long physical;
+
+ /* Can be wraped as surface. */
+ int wrapFB;
+
+ /* FB_MULTI_BUFFER support */
+ int multiBuffer;
+ int backBufferY;
+
+ /* Tiled buffer / tile status support. */
+ int tiledBuffer;
+ int tileStatus;
+ int compression;
+
+ /* The color info of the display. */
+ unsigned int alphaLength;
+ unsigned int alphaOffset;
+ unsigned int redLength;
+ unsigned int redOffset;
+ unsigned int greenLength;
+ unsigned int greenOffset;
+ unsigned int blueLength;
+ unsigned int blueOffset;
+
+ /* Display flip support. */
+ int flip;
+}
+halDISPLAY_INFO;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_eglplatform_type_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_engine.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_engine.h
new file mode 100644
index 000000000000..531cb4cfe364
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_engine.h
@@ -0,0 +1,2970 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_engine_h_
+#define __gc_hal_engine_h_
+
+#include "gc_hal_types.h"
+#include "gc_hal_enum.h"
+
+
+#if gcdENABLE_3D && gcdENABLE_VG
+#include "gc_hal_engine_vg.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _gcsSURF_RESOLVE_ARGS
+{
+ gceHAL_ARG_VERSION version;
+
+ union _gcsSURF_RESOLVE_ARGS_UNION
+ {
+
+ struct _gcsSURF_RESOLVE_ARG_v2
+ {
+ gctBOOL yInverted;
+ gctBOOL directCopy;
+ gctBOOL resample;
+ gctBOOL bUploadTex; /* used for upload tex.*/
+ gctBOOL visualizeDepth; /* convert depth to visible color */
+ gcsPOINT srcOrigin;
+ gcsPOINT dstOrigin;
+ gcsPOINT rectSize;
+ gctUINT numSlices;
+ gceENGINE engine; /* 3DBlit engine */
+ gctBOOL gpuOnly; /* need only try HW path.*/
+
+ gctBOOL dump; /* need dump for verify */
+ gctBOOL srcSwizzle; /* src surface format swizzle infomation */
+ gctBOOL dstSwizzle; /* dst surface format swizzle infomation */
+ gctBOOL srcCompressed; /* src compressed format*/
+ gctBOOL dstCompressed; /* dst compressed format*/
+ } v2;
+ } uArgs;
+}
+gcsSURF_RESOLVE_ARGS;
+
+typedef struct _gscBUFFER_VIEW
+{
+ gctUINT32 cmd;
+}gcsBUFFER_VIEW, *gcsBUFFER_VIEW_PTR;
+
+typedef struct _gcsIMAGE_VIEW
+{
+ gctUINT32 cmd;
+}gcsIMAGE_VIEW, *gcsIMAGE_VIEW_PTR;
+
+#if gcdENABLE_3D
+/******************************************************************************\
+****************************** Object Declarations *****************************
+\******************************************************************************/
+
+typedef struct _gcoSTREAM * gcoSTREAM;
+typedef struct _gcoVERTEX * gcoVERTEX;
+typedef struct _gcoTEXTURE * gcoTEXTURE;
+typedef struct _gcoINDEX * gcoINDEX;
+typedef struct _gcsVERTEX_ATTRIBUTES * gcsVERTEX_ATTRIBUTES_PTR;
+typedef struct _gcoVERTEXARRAY * gcoVERTEXARRAY;
+typedef struct _gcoBUFOBJ * gcoBUFOBJ;
+
+#define gcdATTRIBUTE_COUNT 32
+#define gcdVERTEXARRAY_POOL_CAPACITY 32
+
+typedef enum _gcePROGRAM_STAGE
+{
+ gcvPROGRAM_STAGE_VERTEX = 0x0,
+ gcvPROGRAM_STAGE_TCS = 0x1,
+ gcvPROGRAM_STAGE_TES = 0x2,
+ gcvPROGRAM_STAGE_GEOMETRY = 0x3,
+ gcvPROGRAM_STAGE_FRAGMENT = 0x4,
+ gcvPROGRAM_STAGE_COMPUTE = 0x5,
+ gcvPROGRAM_STAGE_OPENCL = 0x6,
+ gcvPROGRAM_STAGE_LAST
+}
+gcePROGRAM_STAGE;
+
+typedef enum _gcePROGRAM_STAGE_BIT
+{
+ gcvPROGRAM_STAGE_VERTEX_BIT = 1 << gcvPROGRAM_STAGE_VERTEX,
+ gcvPROGRAM_STAGE_TCS_BIT = 1 << gcvPROGRAM_STAGE_TCS,
+ gcvPROGRAM_STAGE_TES_BIT = 1 << gcvPROGRAM_STAGE_TES,
+ gcvPROGRAM_STAGE_GEOMETRY_BIT = 1 << gcvPROGRAM_STAGE_GEOMETRY,
+ gcvPROGRAM_STAGE_FRAGMENT_BIT = 1 << gcvPROGRAM_STAGE_FRAGMENT,
+ gcvPROGRAM_STAGE_COMPUTE_BIT = 1 << gcvPROGRAM_STAGE_COMPUTE,
+ gcvPROGRAM_STAGE_OPENCL_BIT = 1 << gcvPROGRAM_STAGE_OPENCL,
+}
+gcePROGRAM_STAGE_BIT;
+
+
+#define gcvPORGRAM_STAGE_GPIPE (gcvPROGRAM_STAGE_VERTEX_BIT | \
+ gcvPROGRAM_STAGE_TCS_BIT | \
+ gcvPROGRAM_STAGE_TES_BIT | \
+ gcvPROGRAM_STAGE_GEOMETRY_BIT)
+
+/******************************************************************************\
+********************************* gcoHAL Object *********************************
+\******************************************************************************/
+
+gceSTATUS
+gcoHAL_QueryShaderCaps(
+ IN gcoHAL Hal,
+ OUT gctUINT * UnifiedUniforms,
+ OUT gctUINT * VertUniforms,
+ OUT gctUINT * FragUniforms,
+ OUT gctUINT * Varyings,
+ OUT gctUINT * ShaderCoreCount,
+ OUT gctUINT * ThreadCount,
+ OUT gctUINT * VertInstructionCount,
+ OUT gctUINT * FragInstructionCount
+ );
+
+gceSTATUS
+gcoHAL_QuerySamplerBase(
+ IN gcoHAL Hal,
+ OUT gctUINT32 * VertexCount,
+ OUT gctINT_PTR VertexBase,
+ OUT gctUINT32 * FragmentCount,
+ OUT gctINT_PTR FragmentBase
+ );
+
+gceSTATUS
+gcoHAL_QueryUniformBase(
+ IN gcoHAL Hal,
+ OUT gctUINT32 * VertexBase,
+ OUT gctUINT32 * FragmentBase
+ );
+
+gceSTATUS
+gcoHAL_QueryTextureCaps(
+ IN gcoHAL Hal,
+ OUT gctUINT * MaxWidth,
+ OUT gctUINT * MaxHeight,
+ OUT gctUINT * MaxDepth,
+ OUT gctBOOL * Cubic,
+ OUT gctBOOL * NonPowerOfTwo,
+ OUT gctUINT * VertexSamplers,
+ OUT gctUINT * PixelSamplers
+ );
+
+gceSTATUS
+gcoHAL_QueryTextureMaxAniso(
+ IN gcoHAL Hal,
+ OUT gctUINT * MaxAnisoValue
+ );
+
+gceSTATUS
+gcoHAL_QueryStreamCaps(
+ IN gcoHAL Hal,
+ OUT gctUINT32 * MaxAttributes,
+ OUT gctUINT32 * MaxStreamStride,
+ OUT gctUINT32 * NumberOfStreams,
+ OUT gctUINT32 * Alignment,
+ OUT gctUINT32 * MaxAttribOffset
+ );
+
+/******************************************************************************\
+********************************* gcoSURF Object ********************************
+\******************************************************************************/
+
+/*----------------------------------------------------------------------------*/
+/*--------------------------------- gcoSURF 3D --------------------------------*/
+typedef enum _gceBLIT_FLAG
+{
+ gcvBLIT_FLAG_SKIP_DEPTH_WRITE = 1 << 0,
+ gcvBLIT_FLAG_SKIP_STENCIL_WRITE = 1 << 1,
+} gceBLIT_FLAG;
+
+typedef struct _gcsSURF_BLIT_ARGS
+{
+ gcoSURF srcSurface;
+ gctINT srcX, srcY, srcZ;
+ gctINT srcWidth, srcHeight, srcDepth;
+ gcoSURF dstSurface;
+ gctINT dstX, dstY, dstZ;
+ gctINT dstWidth, dstHeight, dstDepth;
+ gctBOOL xReverse;
+ gctBOOL yReverse;
+ gctBOOL scissorTest;
+ gcsRECT scissor;
+ gctUINT flags;
+ gctUINT srcNumSlice, dstNumSlice;
+}
+gcsSURF_BLIT_ARGS;
+
+
+
+
+/* Clear flags. */
+typedef enum _gceCLEAR
+{
+ gcvCLEAR_COLOR = 0x1,
+ gcvCLEAR_DEPTH = 0x2,
+ gcvCLEAR_STENCIL = 0x4,
+ gcvCLEAR_HZ = 0x8,
+ gcvCLEAR_WITH_GPU_ONLY = 0x100,
+ gcvCLEAR_WITH_CPU_ONLY = 0x200,
+ gcvCLEAR_MULTI_SLICES = 0x400,
+}
+gceCLEAR;
+
+typedef struct _gcsSURF_CLEAR_ARGS
+{
+ /*
+ ** Color to fill the color portion of the framebuffer when clear
+ ** is called.
+ */
+ struct {
+ gcuVALUE r;
+ gcuVALUE g;
+ gcuVALUE b;
+ gcuVALUE a;
+ /* Color has multiple value type so we must specify it. */
+ gceVALUE_TYPE valueType;
+ } color;
+
+ gcuVALUE depth;
+ gctUINT stencil;
+
+ gctUINT8 stencilMask; /* stencil bit-wise mask */
+ gctBOOL depthMask; /* Depth Write Mask */
+ gctUINT8 colorMask; /* 4-bit channel Mask: ABGR:MSB->LSB */
+ gcsRECT_PTR clearRect; /* NULL means full clear */
+ gceCLEAR flags; /* clear flags */
+
+ gctUINT32 offset; /* Offset in surface to cube/array/3D, obsolete in v2 version */
+
+} gcsSURF_CLEAR_ARGS, *gcsSURF_CLEAR_ARGS_PTR;
+
+
+typedef struct _gscSURF_BLITDRAW_BLIT
+{
+ gcoSURF srcSurface;
+ gcoSURF dstSurface;
+ gcsRECT srcRect;
+ gcsRECT dstRect;
+ gceTEXTURE_FILTER filterMode;
+ gctBOOL xReverse;
+ gctBOOL yReverse;
+ gctBOOL scissorEnabled;
+ gcsRECT scissor;
+}gscSURF_BLITDRAW_BLIT;
+
+
+typedef enum _gceBLITDRAW_TYPE
+{
+ gcvBLITDRAW_CLEAR = 0,
+ gcvBLITDRAW_BLIT = 1,
+
+ /* last number, not a real type */
+ gcvBLITDRAW_NUM_TYPE
+ }
+gceBLITDRAW_TYPE;
+
+typedef enum _gceSPLIT_DRAW_TYPE
+{
+ gcvSPLIT_DRAW_UNKNOWN = 0x0,
+ gcvSPLIT_DRAW_1,
+ gcvSPLIT_DRAW_2,
+ gcvSPLIT_DRAW_3,
+ gcvSPLIT_DRAW_XFB,
+ gcvSPLIT_DRAW_INDEX_FETCH,
+ gcvSPLIT_DRAW_TCS,
+ gcvSPLIT_DRAW_WIDE_LINE,
+ gcvSPLIT_DRAW_STIPPLE,
+ gcvSPLIT_DRAW_LAST
+}
+gceSPLIT_DRAW_TYPE;
+
+typedef gceSTATUS (* gctSPLIT_DRAW_FUNC_PTR)(
+ IN gctPOINTER gc,
+ IN gctPOINTER instantDraw,
+ IN gctPOINTER splitDrawInfo
+ );
+
+typedef struct _gcsSPLIT_DRAW_INFO
+{
+ gceSPLIT_DRAW_TYPE splitDrawType;
+ gctSPLIT_DRAW_FUNC_PTR splitDrawFunc;
+
+ union _gcsSPLIT_DRAW_UNION
+ {
+ /* This path will split many draw.*/
+ struct __gcsSPLIT_DRAW_INFO_TCS
+ {
+ gctPOINTER indexPtr;
+ gctUINT indexPerPatch;
+ }info_tcs;
+
+ /* This path split into two draw at most.
+ ** es11 path follow the old code, es30 path
+ ** add more info parameter to record
+ */
+ struct __gcsSPLIT_DRAW_INFO_INDEX_FETCH
+ {
+ gctSIZE_T instanceCount;
+ gctSIZE_T splitCount;
+ gcePRIMITIVE splitPrimMode;
+ gctSIZE_T splitPrimCount;
+ }info_index_fetch;
+ }u;
+} gcsSPLIT_DRAW_INFO,
+*gcsSPLIT_DRAW_INFO_PTR;
+
+typedef struct _gscSURF_BLITDRAW_ARGS
+{
+ /* always the fist member */
+ gceHAL_ARG_VERSION version;
+
+ union _gcsSURF_BLITDRAW_ARGS_UNION
+ {
+ struct _gscSURF_BLITDRAW_ARG_v1
+ {
+ /* Whether it's clear or blit operation, can be extended. */
+ gceBLITDRAW_TYPE type;
+
+ union _gscSURF_BLITDRAW_UNION
+ {
+ gscSURF_BLITDRAW_BLIT blit;
+
+ struct _gscSURF_BLITDRAW_CLEAR
+ {
+ gcsSURF_CLEAR_ARGS clearArgs;
+ gcoSURF rtSurface;
+ gcoSURF dsSurface;
+ } clear;
+ } u;
+ } v1;
+ } uArgs;
+}
+gcsSURF_BLITDRAW_ARGS;
+
+typedef struct _gcsSURF_BLITBLT_ARGS
+{
+ gctCONST_POINTER buf;
+ gceSURF_FORMAT format;
+ gctUINT32 stride;
+ gcoSURF dstSurf;
+ gcsPOINT dstOrigin;
+ gcsPOINT rectSize;
+ gctUINT32 dstOffset;
+}
+gcsSURF_BLITBLT_ARGS;
+
+
+/* CPU Blit with format (including linear <-> tile) conversion*/
+gceSTATUS
+gcoSURF_BlitCPU(
+ gcsSURF_BLIT_ARGS* args
+ );
+
+/* Copy a rectangular area with format conversion. */
+gceSTATUS
+gcoSURF_CopyPixels(
+ IN gcsSURF_VIEW *SrcView,
+ IN gcsSURF_VIEW *DstView,
+ IN gcsSURF_RESOLVE_ARGS *Args
+ );
+
+/* Clear surface function. */
+gceSTATUS
+gcoSURF_Clear(
+ IN gcsSURF_VIEW *SurfView,
+ IN gcsSURF_CLEAR_ARGS_PTR ClearArgs
+ );
+
+/* Preserve pixels from source. */
+gceSTATUS
+gcoSURF_Preserve(
+ IN gcoSURF SrcSurf,
+ IN gcoSURF DstSurf,
+ IN gcsRECT_PTR MaskRect
+ );
+
+/* TO BE REMOVED */
+gceSTATUS
+depr_gcoSURF_Resolve(
+ IN gcoSURF SrcSurface,
+ IN gcoSURF DestSurface,
+ IN gctUINT32 DestAddress,
+ IN gctPOINTER DestBits,
+ IN gctINT DestStride,
+ IN gceSURF_TYPE DestType,
+ IN gceSURF_FORMAT DestFormat,
+ IN gctUINT DestWidth,
+ IN gctUINT DestHeight
+ );
+
+gceSTATUS
+depr_gcoSURF_ResolveRect(
+ IN gcoSURF SrcSurface,
+ IN gcoSURF DstSurface,
+ IN gctUINT32 DstAddress,
+ IN gctPOINTER DstBits,
+ IN gctINT DstStride,
+ IN gceSURF_TYPE DstType,
+ IN gceSURF_FORMAT DstFormat,
+ IN gctUINT DstWidth,
+ IN gctUINT DstHeight,
+ IN gcsPOINT_PTR SrcOrigin,
+ IN gcsPOINT_PTR gcoSURF,
+ IN gcsPOINT_PTR RectSize
+ );
+
+/* Resample surface. */
+gceSTATUS
+gcoSURF_Resample(
+ IN gcoSURF SrcSurf,
+ IN gcoSURF DstSurf
+ );
+
+/* Resolve rectangular area of a surface. */
+gceSTATUS
+gcoSURF_ResolveRect(
+ IN gcsSURF_VIEW *SrcView,
+ IN gcsSURF_VIEW *DstView,
+ IN gcsSURF_RESOLVE_ARGS *Args
+ );
+
+gceSTATUS
+gcoSURF_GetResolveAlignment(
+ IN gcoSURF Surface,
+ OUT gctUINT *originX,
+ OUT gctUINT *originY,
+ OUT gctUINT *sizeX,
+ OUT gctUINT *sizeY
+ );
+
+gceSTATUS
+gcoSURF_IsHWResolveable(
+ IN gcoSURF SrcSurf,
+ IN gcoSURF DstSurf,
+ IN gcsPOINT_PTR SrcOrigin,
+ IN gcsPOINT_PTR DstOrigin,
+ IN gcsPOINT_PTR RectSize
+ );
+
+/* Set surface resolvability. */
+gceSTATUS
+gcoSURF_SetResolvability(
+ IN gcoSURF Surface,
+ IN gctBOOL Resolvable
+ );
+
+gceSTATUS
+gcoSURF_IsRenderable(
+ IN gcoSURF Surface
+ );
+
+gceSTATUS
+gcoSURF_IsFormatRenderableAsRT(
+ IN gcoSURF Surface
+ );
+
+gceSTATUS
+gcoBUFOBJ_GetFence(
+ IN gcoBUFOBJ BufObj,
+ IN gceFENCE_TYPE Type
+ );
+
+gceSTATUS
+gcoBUFOBJ_WaitFence(
+ IN gcoBUFOBJ BufObj,
+ IN gceFENCE_TYPE Type
+ );
+
+gceSTATUS
+gcoBUFOBJ_IsFenceEnabled(
+ IN gcoBUFOBJ BufObj
+ );
+
+gceSTATUS
+gcoSURF_GetFence(
+ IN gcoSURF Surface,
+ IN gceFENCE_TYPE Type
+ );
+
+gceSTATUS
+gcoSURF_WaitFence(
+ IN gcoSURF Surface
+ );
+
+gceSTATUS
+gcoSTREAM_GetFence(
+ IN gcoSTREAM stream
+ );
+
+gceSTATUS
+gcoSTREAM_WaitFence(
+ IN gcoSTREAM stream
+ );
+
+gceSTATUS
+gcoINDEX_GetFence(
+ IN gcoINDEX Index
+ );
+
+gceSTATUS
+gcoINDEX_WaitFence(
+ IN gcoINDEX Index,
+ IN gceFENCE_TYPE Type
+ );
+
+gceSTATUS
+gcoSURF_DrawBlit(
+ gcsSURF_VIEW *SrcView,
+ gcsSURF_VIEW *DstView,
+ gscSURF_BLITDRAW_BLIT *Args
+ );
+
+
+/******************************************************************************\
+******************************** gcoINDEX Object *******************************
+\******************************************************************************/
+
+/* Construct a new gcoINDEX object. */
+gceSTATUS
+gcoINDEX_Construct(
+ IN gcoHAL Hal,
+ OUT gcoINDEX * Index
+ );
+
+/* Destroy a gcoINDEX object. */
+gceSTATUS
+gcoINDEX_Destroy(
+ IN gcoINDEX Index
+ );
+
+/* Lock index in memory. */
+gceSTATUS
+gcoINDEX_Lock(
+ IN gcoINDEX Index,
+ OUT gctUINT32 * Address,
+ OUT gctPOINTER * Memory
+ );
+
+/* Unlock index that was previously locked with gcoINDEX_Lock. */
+gceSTATUS
+gcoINDEX_Unlock(
+ IN gcoINDEX Index
+ );
+
+/* Upload index data into the memory. */
+gceSTATUS
+gcoINDEX_Load(
+ IN gcoINDEX Index,
+ IN gceINDEX_TYPE IndexType,
+ IN gctUINT32 IndexCount,
+ IN gctPOINTER IndexBuffer
+ );
+
+/* Bind an index object to the hardware. */
+gceSTATUS
+gcoINDEX_Bind(
+ IN gcoINDEX Index,
+ IN gceINDEX_TYPE Type
+ );
+
+/* Bind an index object to the hardware. */
+gceSTATUS
+gcoINDEX_BindOffset(
+ IN gcoINDEX Index,
+ IN gceINDEX_TYPE Type,
+ IN gctUINT32 Offset
+ );
+
+/* Free existing index buffer. */
+gceSTATUS
+gcoINDEX_Free(
+ IN gcoINDEX Index
+ );
+
+/* Upload data into an index buffer. */
+gceSTATUS
+gcoINDEX_Upload(
+ IN gcoINDEX Index,
+ IN gctCONST_POINTER Buffer,
+ IN gctSIZE_T Bytes
+ );
+
+/* Upload data into an index buffer starting at an offset. */
+gceSTATUS
+gcoINDEX_UploadOffset(
+ IN gcoINDEX Index,
+ IN gctSIZE_T Offset,
+ IN gctCONST_POINTER Buffer,
+ IN gctSIZE_T Bytes
+ );
+
+/*Merge index2 to index1 from 0, index2 must subset of inex1*/
+gceSTATUS
+gcoINDEX_Merge(
+ IN gcoINDEX Index1,
+ IN gcoINDEX Index2
+ );
+
+/*check if index buffer is enough for this draw*/
+gctBOOL
+gcoINDEX_CheckRange(
+ IN gcoINDEX Index,
+ IN gceINDEX_TYPE Type,
+ IN gctINT Count,
+ IN gctUINT32 Indices
+ );
+
+/* Query the index capabilities. */
+gceSTATUS
+gcoINDEX_QueryCaps(
+ OUT gctBOOL * Index8,
+ OUT gctBOOL * Index16,
+ OUT gctBOOL * Index32,
+ OUT gctUINT * MaxIndex
+ );
+
+/* Determine the index range in the current index buffer. */
+gceSTATUS
+gcoINDEX_GetIndexRange(
+ IN gcoINDEX Index,
+ IN gceINDEX_TYPE Type,
+ IN gctUINT32 Offset,
+ IN gctUINT32 Count,
+ OUT gctUINT32 * MinimumIndex,
+ OUT gctUINT32 * MaximumIndex
+ );
+
+/* Dynamic buffer management. */
+gceSTATUS
+gcoINDEX_SetDynamic(
+ IN gcoINDEX Index,
+ IN gctSIZE_T Bytes,
+ IN gctUINT Buffers
+ );
+
+gceSTATUS
+gcoCLHardware_Construct(void);
+/******************************************************************************\
+********************************** gco3D Object *********************************
+\******************************************************************************/
+
+/* Blending targets. */
+typedef enum _gceBLEND_UNIT
+{
+ gcvBLEND_SOURCE,
+ gcvBLEND_TARGET,
+}
+gceBLEND_UNIT;
+
+/* Construct a new gco3D object. */
+gceSTATUS
+gco3D_Construct(
+ IN gcoHAL Hal,
+ IN gctBOOL Robust,
+ OUT gco3D * Engine
+ );
+
+/* Destroy an gco3D object. */
+gceSTATUS
+gco3D_Destroy(
+ IN gco3D Engine
+ );
+
+/* Set 3D API type. */
+gceSTATUS
+gco3D_SetAPI(
+ IN gco3D Engine,
+ IN gceAPI ApiType
+ );
+
+/* Get 3D API type. */
+gceSTATUS
+gco3D_GetAPI(
+ IN gco3D Engine,
+ OUT gceAPI * ApiType
+ );
+
+gceSTATUS
+gco3D_SetTarget(
+ IN gco3D Engine,
+ IN gctUINT32 TargetIndex,
+ IN gcsSURF_VIEW *SurfView,
+ IN gctUINT32 LayerIndex
+ );
+
+gceSTATUS
+gco3D_UnsetTarget(
+ IN gco3D Engine,
+ IN gctUINT32 TargetIndex,
+ IN gcoSURF Surface
+ );
+
+gceSTATUS
+gco3D_SetPSOutputMapping(
+ IN gco3D Engine,
+ IN gctINT32 * psOutputMapping
+ );
+
+gceSTATUS
+gco3D_SetRenderLayered(
+ IN gco3D Engine,
+ IN gctBOOL Enable,
+ IN gctUINT MaxLayers
+ );
+
+gceSTATUS
+gco3D_SetShaderLayered(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+gceSTATUS
+gco3D_IsProgramSwitched(
+ IN gco3D Engine
+ );
+
+/* Set depth buffer. */
+gceSTATUS
+gco3D_SetDepth(
+ IN gco3D Engine,
+ IN gcsSURF_VIEW *SurfView
+ );
+
+/* Unset depth buffer. */
+gceSTATUS
+gco3D_UnsetDepth(
+ IN gco3D Engine,
+ IN gcoSURF Surface
+ );
+
+/* Set viewport. */
+gceSTATUS
+gco3D_SetViewport(
+ IN gco3D Engine,
+ IN gctINT32 Left,
+ IN gctINT32 Top,
+ IN gctINT32 Right,
+ IN gctINT32 Bottom
+ );
+
+/* Set scissors. */
+gceSTATUS
+gco3D_SetScissors(
+ IN gco3D Engine,
+ IN gctINT32 Left,
+ IN gctINT32 Top,
+ IN gctINT32 Right,
+ IN gctINT32 Bottom
+ );
+
+/* Set clear color. */
+gceSTATUS
+gco3D_SetClearColor(
+ IN gco3D Engine,
+ IN gctUINT8 Red,
+ IN gctUINT8 Green,
+ IN gctUINT8 Blue,
+ IN gctUINT8 Alpha
+ );
+
+/* Set fixed point clear color. */
+gceSTATUS
+gco3D_SetClearColorX(
+ IN gco3D Engine,
+ IN gctFIXED_POINT Red,
+ IN gctFIXED_POINT Green,
+ IN gctFIXED_POINT Blue,
+ IN gctFIXED_POINT Alpha
+ );
+
+/* Set floating point clear color. */
+gceSTATUS
+gco3D_SetClearColorF(
+ IN gco3D Engine,
+ IN gctFLOAT Red,
+ IN gctFLOAT Green,
+ IN gctFLOAT Blue,
+ IN gctFLOAT Alpha
+ );
+
+/* Set fixed point clear depth. */
+gceSTATUS
+gco3D_SetClearDepthX(
+ IN gco3D Engine,
+ IN gctFIXED_POINT Depth
+ );
+
+/* Set floating point clear depth. */
+gceSTATUS
+gco3D_SetClearDepthF(
+ IN gco3D Engine,
+ IN gctFLOAT Depth
+ );
+
+/* Set clear stencil. */
+gceSTATUS
+gco3D_SetClearStencil(
+ IN gco3D Engine,
+ IN gctUINT32 Stencil
+ );
+
+/* Set shading mode. */
+gceSTATUS
+gco3D_SetShading(
+ IN gco3D Engine,
+ IN gceSHADING Shading
+ );
+
+/* Set blending mode. */
+gceSTATUS
+gco3D_EnableBlending(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+/* Set blending function. */
+gceSTATUS
+gco3D_SetBlendFunction(
+ IN gco3D Engine,
+ IN gceBLEND_UNIT Unit,
+ IN gceBLEND_FUNCTION FunctionRGB,
+ IN gceBLEND_FUNCTION FunctionAlpha
+ );
+
+/* Set blending mode. */
+gceSTATUS
+gco3D_SetBlendMode(
+ IN gco3D Engine,
+ IN gceBLEND_MODE ModeRGB,
+ IN gceBLEND_MODE ModeAlpha
+ );
+
+/* Set blending mode for separate rt control */
+gceSTATUS
+gco3D_EnableBlendingIndexed(
+ IN gco3D Engine,
+ IN gctUINT Index,
+ IN gctBOOL Enable
+ );
+
+/* Set blending function for separate rt control */
+gceSTATUS
+gco3D_SetBlendFunctionIndexed(
+ IN gco3D Engine,
+ IN gctUINT Index,
+ IN gceBLEND_UNIT Unit,
+ IN gceBLEND_FUNCTION FunctionRGB,
+ IN gceBLEND_FUNCTION FunctionAlpha
+ );
+
+/* Set blending mode for separate rt control*/
+gceSTATUS
+gco3D_SetBlendModeIndexed(
+ IN gco3D Engine,
+ IN gctUINT Index,
+ IN gceBLEND_MODE ModeRGB,
+ IN gceBLEND_MODE ModeAlpha
+ );
+
+/* Set blending color. */
+gceSTATUS
+gco3D_SetBlendColor(
+ IN gco3D Engine,
+ IN gctUINT Red,
+ IN gctUINT Green,
+ IN gctUINT Blue,
+ IN gctUINT Alpha
+ );
+
+/* Set fixed point blending color. */
+gceSTATUS
+gco3D_SetBlendColorX(
+ IN gco3D Engine,
+ IN gctFIXED_POINT Red,
+ IN gctFIXED_POINT Green,
+ IN gctFIXED_POINT Blue,
+ IN gctFIXED_POINT Alpha
+ );
+
+/* Set floating point blending color. */
+gceSTATUS
+gco3D_SetBlendColorF(
+ IN gco3D Engine,
+ IN gctFLOAT Red,
+ IN gctFLOAT Green,
+ IN gctFLOAT Blue,
+ IN gctFLOAT Alpha
+ );
+
+/* Set culling mode. */
+gceSTATUS
+gco3D_SetCulling(
+ IN gco3D Engine,
+ IN gceCULL Mode
+ );
+
+/* Enable point size */
+gceSTATUS
+gco3D_SetPointSizeEnable(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+/* Set point sprite */
+gceSTATUS
+gco3D_SetPointSprite(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+
+/* Enable/Disable primitive-id. */
+gceSTATUS
+gco3D_SetPrimitiveIdEnable(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+/* Set fill mode. */
+gceSTATUS
+gco3D_SetFill(
+ IN gco3D Engine,
+ IN gceFILL Mode
+ );
+
+/* Set depth compare mode. */
+gceSTATUS
+gco3D_SetDepthCompare(
+ IN gco3D Engine,
+ IN gceCOMPARE Compare
+ );
+
+/* Enable depth writing. */
+gceSTATUS
+gco3D_EnableDepthWrite(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+/* Set depth mode. */
+gceSTATUS
+gco3D_SetDepthMode(
+ IN gco3D Engine,
+ IN gceDEPTH_MODE Mode
+ );
+
+/* Set depth range. */
+gceSTATUS
+gco3D_SetDepthRangeX(
+ IN gco3D Engine,
+ IN gceDEPTH_MODE Mode,
+ IN gctFIXED_POINT Near,
+ IN gctFIXED_POINT Far
+ );
+
+/* Set depth range. */
+gceSTATUS
+gco3D_SetDepthRangeF(
+ IN gco3D Engine,
+ IN gceDEPTH_MODE Mode,
+ IN gctFLOAT Near,
+ IN gctFLOAT Far
+ );
+
+/* Set last pixel enable */
+gceSTATUS
+gco3D_SetLastPixelEnable(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+/* Set depth Bias and Scale */
+gceSTATUS
+gco3D_SetDepthScaleBiasX(
+ IN gco3D Engine,
+ IN gctFIXED_POINT DepthScale,
+ IN gctFIXED_POINT DepthBias
+ );
+
+gceSTATUS
+gco3D_SetDepthScaleBiasF(
+ IN gco3D Engine,
+ IN gctFLOAT DepthScale,
+ IN gctFLOAT DepthBias
+ );
+
+/* Set depth near and far clipping plane. */
+gceSTATUS
+gco3D_SetDepthPlaneF(
+ IN gco3D Engine,
+ IN gctFLOAT Near,
+ IN gctFLOAT Far
+ );
+
+/* Enable or disable dithering. */
+gceSTATUS
+gco3D_EnableDither(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+/* Set color write enable bits. */
+gceSTATUS
+gco3D_SetColorWrite(
+ IN gco3D Engine,
+ IN gctUINT8 Enable
+ );
+
+/* Set color write enable bits for separate rt control */
+gceSTATUS
+gco3D_SetColorWriteIndexed(
+ IN gco3D Engine,
+ IN gctUINT Index,
+ IN gctUINT8 Enable
+ );
+
+/* Enable or disable early depth. */
+gceSTATUS
+gco3D_SetEarlyDepth(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+/* Deprecated: Enable or disable all early depth operations. */
+gceSTATUS
+gco3D_SetAllEarlyDepthModes(
+ IN gco3D Engine,
+ IN gctBOOL Disable
+ );
+
+
+gceSTATUS
+gco3D_SetEarlyDepthFromAPP(
+ IN gco3D Engine,
+ IN gctBOOL EarlyDepthFromAPP
+ );
+
+gceSTATUS
+gco3D_SetRADepthWrite(
+ IN gco3D Engine,
+ IN gctBOOL Disable,
+ IN gctBOOL psReadZ,
+ IN gctBOOL psReadW
+ );
+
+gceSTATUS
+gco3D_SetPatchVertices(
+ IN gco3D Engine,
+ IN gctINT PatchVertices
+ );
+
+
+/* Switch dynamic early mode */
+gceSTATUS
+gco3D_SwitchDynamicEarlyDepthMode(
+ IN gco3D Engine
+ );
+
+/* Set dynamic early mode */
+gceSTATUS
+gco3D_DisableDynamicEarlyDepthMode(
+ IN gco3D Engine,
+ IN gctBOOL Disable
+ );
+
+/* Enable or disable depth-only mode. */
+gceSTATUS
+gco3D_SetDepthOnly(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+typedef struct _gcsSTENCIL_INFO * gcsSTENCIL_INFO_PTR;
+typedef struct _gcsSTENCIL_INFO
+{
+ gceSTENCIL_MODE mode;
+
+ gctUINT8 maskFront;
+ gctUINT8 maskBack;
+ gctUINT8 writeMaskFront;
+ gctUINT8 writeMaskBack;
+
+ gctUINT8 referenceFront;
+
+ gceCOMPARE compareFront;
+ gceSTENCIL_OPERATION passFront;
+ gceSTENCIL_OPERATION failFront;
+ gceSTENCIL_OPERATION depthFailFront;
+
+ gctUINT8 referenceBack;
+ gceCOMPARE compareBack;
+ gceSTENCIL_OPERATION passBack;
+ gceSTENCIL_OPERATION failBack;
+ gceSTENCIL_OPERATION depthFailBack;
+}
+gcsSTENCIL_INFO;
+
+/* Set stencil mode. */
+gceSTATUS
+gco3D_SetStencilMode(
+ IN gco3D Engine,
+ IN gceSTENCIL_MODE Mode
+ );
+
+/* Set stencil mask. */
+gceSTATUS
+gco3D_SetStencilMask(
+ IN gco3D Engine,
+ IN gctUINT8 Mask
+ );
+
+/* Set stencil back mask. */
+gceSTATUS
+gco3D_SetStencilMaskBack(
+ IN gco3D Engine,
+ IN gctUINT8 Mask
+ );
+
+/* Set stencil write mask. */
+gceSTATUS
+gco3D_SetStencilWriteMask(
+ IN gco3D Engine,
+ IN gctUINT8 Mask
+ );
+
+/* Set stencil back write mask. */
+gceSTATUS
+gco3D_SetStencilWriteMaskBack(
+ IN gco3D Engine,
+ IN gctUINT8 Mask
+ );
+
+/* Set stencil reference. */
+gceSTATUS
+gco3D_SetStencilReference(
+ IN gco3D Engine,
+ IN gctUINT8 Reference,
+ IN gctBOOL Front
+ );
+
+/* Set stencil compare. */
+gceSTATUS
+gco3D_SetStencilCompare(
+ IN gco3D Engine,
+ IN gceSTENCIL_WHERE Where,
+ IN gceCOMPARE Compare
+ );
+
+/* Set stencil operation on pass. */
+gceSTATUS
+gco3D_SetStencilPass(
+ IN gco3D Engine,
+ IN gceSTENCIL_WHERE Where,
+ IN gceSTENCIL_OPERATION Operation
+ );
+
+/* Set stencil operation on fail. */
+gceSTATUS
+gco3D_SetStencilFail(
+ IN gco3D Engine,
+ IN gceSTENCIL_WHERE Where,
+ IN gceSTENCIL_OPERATION Operation
+ );
+
+/* Set stencil operation on depth fail. */
+gceSTATUS
+gco3D_SetStencilDepthFail(
+ IN gco3D Engine,
+ IN gceSTENCIL_WHERE Where,
+ IN gceSTENCIL_OPERATION Operation
+ );
+
+/* Set all stencil states in one blow. */
+gceSTATUS
+gco3D_SetStencilAll(
+ IN gco3D Engine,
+ IN gcsSTENCIL_INFO_PTR Info
+ );
+
+typedef struct _gcsALPHA_INFO * gcsALPHA_INFO_PTR;
+typedef struct _gcsALPHA_INFO
+{
+ /* Alpha test states. */
+ gctBOOL test;
+ gceCOMPARE compare;
+ gctUINT8 reference;
+ gctFLOAT floatReference;
+
+ /* Alpha blending states. */
+ gctBOOL blend[gcdMAX_DRAW_BUFFERS];
+
+ gceBLEND_FUNCTION srcFuncColor[gcdMAX_DRAW_BUFFERS];
+ gceBLEND_FUNCTION srcFuncAlpha[gcdMAX_DRAW_BUFFERS];
+ gceBLEND_FUNCTION trgFuncColor[gcdMAX_DRAW_BUFFERS];
+ gceBLEND_FUNCTION trgFuncAlpha[gcdMAX_DRAW_BUFFERS];
+
+ gceBLEND_MODE modeColor[gcdMAX_DRAW_BUFFERS];
+ gceBLEND_MODE modeAlpha[gcdMAX_DRAW_BUFFERS];
+
+ gctUINT32 color;
+
+ gctBOOL anyBlendEnabled;
+}
+gcsALPHA_INFO;
+
+
+/* Enable or disable alpha test. */
+gceSTATUS
+gco3D_SetAlphaTest(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+/* Set alpha test compare. */
+gceSTATUS
+gco3D_SetAlphaCompare(
+ IN gco3D Engine,
+ IN gceCOMPARE Compare
+ );
+
+/* Set alpha test reference in unsigned integer. */
+gceSTATUS
+gco3D_SetAlphaReference(
+ IN gco3D Engine,
+ IN gctUINT8 Reference,
+ IN gctFLOAT FloatReference
+ );
+
+/* Set alpha test reference in fixed point. */
+gceSTATUS
+gco3D_SetAlphaReferenceX(
+ IN gco3D Engine,
+ IN gctFIXED_POINT Reference
+ );
+
+/* Set alpha test reference in floating point. */
+gceSTATUS
+gco3D_SetAlphaReferenceF(
+ IN gco3D Engine,
+ IN gctFLOAT Reference
+ );
+
+#if gcdALPHA_KILL_IN_SHADER
+gceSTATUS
+gco3D_SetAlphaKill(
+ IN gco3D Engine,
+ IN gctBOOL AlphaKill,
+ IN gctBOOL ColorKill
+ );
+#endif
+
+/* Enable/Disable anti-alias line. */
+gceSTATUS
+gco3D_SetAntiAliasLine(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+/* Set texture slot for anti-alias line. */
+gceSTATUS
+gco3D_SetAALineTexSlot(
+ IN gco3D Engine,
+ IN gctUINT TexSlot
+ );
+
+/* Set anti-alias line width scale. */
+gceSTATUS
+gco3D_SetAALineWidth(
+ IN gco3D Engine,
+ IN gctFLOAT Width
+ );
+
+/* Draw a number of primitives. */
+gceSTATUS
+gco3D_DrawPrimitives(
+ IN gco3D Engine,
+ IN gcePRIMITIVE Type,
+ IN gctSIZE_T StartVertex,
+ IN gctSIZE_T PrimitiveCount
+ );
+
+gceSTATUS
+gco3D_DrawIndirectPrimitives(
+ IN gco3D Engine,
+ IN gcePRIMITIVE Type,
+ IN gctBOOL DrawIndex,
+ IN gctINT BaseOffset,
+ IN gcoBUFOBJ BufObj
+ );
+
+gceSTATUS
+gco3D_MultiDrawIndirectPrimitives(
+ IN gco3D Engine,
+ IN gcePRIMITIVE Type,
+ IN gctBOOL DrawIndex,
+ IN gctINT BaseOffset,
+ IN gctINT DrawCount,
+ IN gctINT Stride,
+ IN gcoBUFOBJ BufObj
+ );
+
+gceSTATUS
+gco3D_DrawInstancedPrimitives(
+ IN gco3D Engine,
+ IN gcePRIMITIVE Type,
+ IN gctBOOL DrawIndex,
+ IN gctINT StartVertex,
+ IN gctSIZE_T StartIndex,
+ IN gctSIZE_T PrimitiveCount,
+ IN gctSIZE_T VertexCount,
+ IN gctSIZE_T InstanceCount
+ );
+
+gceSTATUS
+gco3D_DrawNullPrimitives(
+ IN gco3D Engine
+ );
+
+gceSTATUS
+gco3D_DrawPrimitivesCount(
+ IN gco3D Engine,
+ IN gcePRIMITIVE Type,
+ IN gctINT* StartVertex,
+ IN gctSIZE_T* VertexCount,
+ IN gctSIZE_T PrimitiveCount
+ );
+
+
+/* Draw a number of primitives using offsets. */
+gceSTATUS
+gco3D_DrawPrimitivesOffset(
+ IN gco3D Engine,
+ IN gcePRIMITIVE Type,
+ IN gctINT32 StartOffset,
+ IN gctSIZE_T PrimitiveCount
+ );
+
+/* Draw a number of indexed primitives. */
+gceSTATUS
+gco3D_DrawIndexedPrimitives(
+ IN gco3D Engine,
+ IN gcePRIMITIVE Type,
+ IN gctSIZE_T BaseVertex,
+ IN gctSIZE_T StartIndex,
+ IN gctSIZE_T PrimitiveCount
+ );
+
+/* Draw a number of indexed primitives using offsets. */
+gceSTATUS
+gco3D_DrawIndexedPrimitivesOffset(
+ IN gco3D Engine,
+ IN gcePRIMITIVE Type,
+ IN gctINT32 BaseOffset,
+ IN gctINT32 StartOffset,
+ IN gctSIZE_T PrimitiveCount
+ );
+
+/* Draw a element from pattern */
+gceSTATUS
+gco3D_DrawPattern(
+ IN gco3D Engine,
+ IN gcsFAST_FLUSH_PTR FastFlushInfo
+ );
+
+/* Enable or disable anti-aliasing. */
+gceSTATUS
+gco3D_SetAntiAlias(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+/* Set msaa samples */
+gceSTATUS
+gco3D_SetSamples(
+ IN gco3D Engine,
+ IN gctUINT32 Samples
+ );
+
+
+/* Write data into the command buffer. */
+gceSTATUS
+gco3D_WriteBuffer(
+ IN gco3D Engine,
+ IN gctCONST_POINTER Data,
+ IN gctSIZE_T Bytes,
+ IN gctBOOL Aligned
+ );
+
+/* Send sempahore and stall until sempahore is signalled. */
+gceSTATUS
+gco3D_Semaphore(
+ IN gco3D Engine,
+ IN gceWHERE From,
+ IN gceWHERE To,
+ IN gceHOW How);
+
+
+/* Explicitly flush shader L1 cache */
+gceSTATUS
+gco3D_FlushSHL1Cache(
+ IN gco3D Engine
+ );
+
+/* Set the subpixels center. */
+gceSTATUS
+gco3D_SetCentroids(
+ IN gco3D Engine,
+ IN gctUINT32 Index,
+ IN gctPOINTER Centroids
+ );
+
+/* query msaa sample coordinates */
+gceSTATUS
+gco3D_GetSampleCoords(
+ IN gco3D Engine,
+ IN gctUINT32 SampleIndex,
+ IN gctBOOL yInverted,
+ OUT gctFLOAT_PTR Coords
+ );
+
+gceSTATUS
+gco3D_SetLogicOp(
+ IN gco3D Engine,
+ IN gctUINT8 Rop
+ );
+
+typedef enum _gceXfbCmd
+{
+ gcvXFBCMD_BEGIN = 0,
+ gcvXFBCMD_PAUSE = 1,
+ gcvXFBCMD_RESUME = 2,
+ gcvXFBCMD_END = 3,
+ gcvXFBCMD_PAUSE_INCOMMIT = 4,
+ gcvXFBCMD_RESUME_INCOMMIT = 5,
+ gcvXFBCMD_INVALID = 6,
+}
+gceXfbCmd;
+
+typedef enum _gceXfbStatus
+{
+ gcvXFB_Disabled = 0,
+ gcvXFB_Paused,
+ gcvXFB_Enabled,
+}
+gceXfbStatus;
+
+typedef enum _gceQueryStatus
+{
+ gcvQUERY_Disabled = 0,
+ gcvQUERY_Paused = 1,
+ gcvQUERY_Enabled = 2,
+}
+gceQueryStatus;
+
+typedef enum _gceQueryCmd
+{
+ gcvQUERYCMD_BEGIN = 0,
+ gcvQUERYCMD_PAUSE = 1,
+ gcvQUERYCMD_RESUME = 2,
+ gcvQUERYCMD_END = 3,
+ gcvQUERYCMD_INVALID = 4,
+}
+gceQueryCmd;
+
+typedef enum _gceQueryType
+{
+ gcvQUERY_OCCLUSION = 0,
+ gcvQUERY_XFB_WRITTEN = 1,
+ gcvQUERY_PRIM_GENERATED = 2,
+ gcvQUERY_MAX_NUM = 3,
+}
+gceQueryType;
+
+gceSTATUS
+gco3D_SetQuery(
+ IN gco3D Engine,
+ IN gctUINT32 QueryHeader,
+ IN gceQueryType Type,
+ IN gctBOOL Enable
+ );
+
+gceSTATUS
+gco3D_GetQuery(
+ IN gco3D Engine,
+ IN gceQueryType Type,
+ IN gcsSURF_NODE_PTR Node,
+ IN gctUINT32 Size,
+ IN gctPOINTER Locked,
+ OUT gctINT32 * Index
+ );
+
+gceSTATUS
+gco3D_SetXfbHeader(
+ IN gco3D Engine,
+ IN gctUINT32 Physical
+ );
+
+gceSTATUS
+gco3D_SetXfbBuffer(
+ IN gco3D Engine,
+ IN gctUINT32 Index,
+ IN gctUINT32 BufferAddr,
+ IN gctUINT32 BufferStride,
+ IN gctUINT32 BufferSize
+ );
+
+gceSTATUS
+gco3D_SetXfbCmd(
+ IN gco3D Engine,
+ IN gceXfbCmd Cmd
+ );
+
+gceSTATUS
+gco3D_SetRasterDiscard(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+gceSTATUS
+gco3D_SetColorOutCount(
+ IN gco3D Engine,
+ IN gctUINT32 ColorOutCount
+ );
+
+gceSTATUS
+gco3D_SetColorCacheMode(
+ IN gco3D Engine
+ );
+
+gceSTATUS
+gco3D_Set3DEngine(
+ IN gco3D Engine
+ );
+
+gceSTATUS
+gco3D_UnSet3DEngine(
+ IN gco3D Engine
+ );
+
+gceSTATUS
+gco3D_Get3DEngine(
+ OUT gco3D * Engine
+ );
+
+gceSTATUS
+gco3D_QueryReset(
+ IN gco3D Engine,
+ OUT gctBOOL_PTR Innocent
+ );
+
+/* OCL thread walker information. */
+typedef struct _gcsTHREAD_WALKER_INFO * gcsTHREAD_WALKER_INFO_PTR;
+typedef struct _gcsTHREAD_WALKER_INFO
+{
+ gctUINT32 dimensions;
+ gctUINT32 traverseOrder;
+ gctUINT32 enableSwathX;
+ gctUINT32 enableSwathY;
+ gctUINT32 enableSwathZ;
+ gctUINT32 swathSizeX;
+ gctUINT32 swathSizeY;
+ gctUINT32 swathSizeZ;
+ gctUINT32 valueOrder;
+
+ gctUINT32 globalSizeX;
+ gctUINT32 globalOffsetX;
+ gctUINT32 globalSizeY;
+ gctUINT32 globalOffsetY;
+ gctUINT32 globalSizeZ;
+ gctUINT32 globalOffsetZ;
+
+ gctUINT32 globalScaleX;
+ gctUINT32 globalScaleY;
+ gctUINT32 globalScaleZ;
+
+ gctUINT32 workGroupSizeX;
+ gctUINT32 workGroupCountX;
+ gctUINT32 workGroupSizeY;
+ gctUINT32 workGroupCountY;
+ gctUINT32 workGroupSizeZ;
+ gctUINT32 workGroupCountZ;
+
+ gctUINT32 threadAllocation;
+ gctBOOL barrierUsed;
+
+ gctBOOL indirect;
+ gctUINT32 groupNumberUniformIdx;
+ gctUINT32 baseAddress;
+}
+gcsTHREAD_WALKER_INFO;
+
+#if gcdENABLE_3D && gcdUSE_VX
+/* VX thread walker parameters. */
+typedef struct _gcsVX_THREAD_WALKER_PARAMETERS * gcsVX_THREAD_WALKER_PARAMETERS_PTR;
+
+typedef struct _gcsVX_THREAD_WALKER_PARAMETERS
+{
+ gctUINT32 valueOrder;
+ gctUINT32 workDim;
+
+ gctUINT32 workGroupSizeX;
+ gctUINT32 workGroupCountX;
+
+ gctUINT32 workGroupSizeY;
+ gctUINT32 workGroupCountY;
+
+ gctUINT32 globalOffsetX;
+ gctUINT32 globalScaleX;
+
+ gctUINT32 globalOffsetY;
+ gctUINT32 globalScaleY;
+
+#if gcdVX_OPTIMIZER > 1
+ gctBOOL tileMode;
+#endif
+}
+gcsVX_THREAD_WALKER_PARAMETERS;
+
+typedef struct _gcsVX_IMAGE_INFO * gcsVX_IMAGE_INFO_PTR;
+
+typedef struct _gcsVX_IMAGE_INFO
+{
+ gctUINT32 format;
+ gctUINT32 rect[4];
+ gctUINT32 width;
+ gctUINT32 height;
+
+ /*arraySize, sliceSize is for imageArray / image3D */
+ gctUINT32 arraySize;
+ gctUINT32 sliceSize;
+
+ gctUINT32 bpp;
+ gctUINT32 planes;
+ gctUINT32 componentCount;
+ gctBOOL isFloat;
+
+ gctUINT32 uPixels;
+ gctUINT32 vPixels;
+ gceSURF_FORMAT internalFormat;
+ gctUINT32 border;
+
+ /*vx_imagepatch_addressing_t == (gctUINT32 * 8) */
+ gctUINT32 imagepatch[8 * 3];
+ void *base_addr[3];
+
+ gctUINT32 stride[3];
+
+ gctPOINTER logicals[3];
+ gctUINT32 physicals[3];
+ gctUINT32 bytes;
+
+ gcsSURF_NODE_PTR nodes[3];
+
+ gctBOOL isVXC;
+#if gcdVX_OPTIMIZER
+ gctUINT32 uniformData[3][4];
+#endif
+}
+gcsVX_IMAGE_INFO;
+typedef struct _gcsVX_DISTRIBUTION_INFO * gcsVX_DISTRIBUTION_INFO_PTR;
+
+typedef struct _gcsVX_DISTRIBUTION_INFO
+{
+
+ gctUINT32 logical;
+ gctUINT32 physical;
+ gctUINT32 bytes;
+
+ gcsSURF_NODE_PTR node;
+}
+gcsVX_DISTRIBUTION_INFO;
+#endif
+
+/* Start OCL thread walker. */
+gceSTATUS
+gco3D_InvokeThreadWalker(
+ IN gco3D Engine,
+ IN gcsTHREAD_WALKER_INFO_PTR Info
+ );
+
+gceSTATUS
+gco3D_GetClosestRenderFormat(
+ IN gco3D Engine,
+ IN gceSURF_FORMAT InFormat,
+ OUT gceSURF_FORMAT* OutFormat
+ );
+
+/* Set w clip and w plane limit value. */
+gceSTATUS
+gco3D_SetWClipEnable(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+gceSTATUS
+gco3D_GetWClipEnable(
+ IN gco3D Engine,
+ OUT gctBOOL * Enable
+ );
+
+gceSTATUS
+gco3D_SetWPlaneLimitF(
+ IN gco3D Engine,
+ IN gctFLOAT Value
+ );
+
+gceSTATUS
+gco3D_SetWPlaneLimitX(
+ IN gco3D Engine,
+ IN gctFIXED_POINT Value
+ );
+
+gceSTATUS
+gco3D_SetWPlaneLimit(
+ IN gco3D Engine,
+ IN gctFLOAT Value
+ );
+
+gceSTATUS
+gco3D_PrimitiveRestart(
+ IN gco3D Engine,
+ IN gctBOOL PrimitiveRestart
+ );
+
+gceSTATUS
+gco3D_LoadProgram(
+ IN gco3D Engine,
+ IN gcePROGRAM_STAGE_BIT StageBits,
+ IN gctPOINTER ProgramState
+ );
+
+gceSTATUS
+gco3D_EnableAlphaToCoverage(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+gceSTATUS
+gco3D_EnableSampleCoverage(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+gceSTATUS
+gco3D_SetSampleCoverageValue(
+ IN gco3D Engine,
+ IN gctFLOAT CoverageValue,
+ IN gctBOOL Invert
+ );
+
+gceSTATUS
+gco3D_EnableSampleMask(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+gceSTATUS
+gco3D_SetSampleMask(
+ IN gco3D Engine,
+ IN gctUINT32 SampleMask
+ );
+
+gceSTATUS
+gco3D_EnableSampleShading(
+ IN gco3D Engine,
+ IN gctBOOL Enable
+ );
+
+gceSTATUS
+gco3D_SetMinSampleShadingValue(
+ IN gco3D Engine,
+ IN gctFLOAT MinSampleShadingValue
+ );
+
+gceSTATUS
+gco3D_SetSampleShading(
+ IN gco3D Engine,
+ IN gctBOOL Enable,
+ IN gctBOOL IsSampleIn,
+ IN gctFLOAT SampleShadingValue
+ );
+
+gceSTATUS
+gco3D_EnableSampleMaskOut(
+ IN gco3D Engine,
+ IN gctBOOL Enable,
+ IN gctINT SampleMaskLoc
+ );
+
+/*----------------------------------------------------------------------------*/
+/*-------------------------- gco3D Fragment Processor ------------------------*/
+
+/* Set the fragment processor configuration. */
+gceSTATUS
+gco3D_SetFragmentConfiguration(
+ IN gco3D Engine,
+ IN gctBOOL ColorFromStream,
+ IN gctBOOL EnableFog,
+ IN gctBOOL EnableSmoothPoint,
+ IN gctUINT32 ClipPlanes
+ );
+
+/* Enable/disable texture stage operation. */
+gceSTATUS
+gco3D_EnableTextureStage(
+ IN gco3D Engine,
+ IN gctINT Stage,
+ IN gctBOOL Enable
+ );
+
+/* Program the channel enable masks for the color texture function. */
+gceSTATUS
+gco3D_SetTextureColorMask(
+ IN gco3D Engine,
+ IN gctINT Stage,
+ IN gctBOOL ColorEnabled,
+ IN gctBOOL AlphaEnabled
+ );
+
+/* Program the channel enable masks for the alpha texture function. */
+gceSTATUS
+gco3D_SetTextureAlphaMask(
+ IN gco3D Engine,
+ IN gctINT Stage,
+ IN gctBOOL ColorEnabled,
+ IN gctBOOL AlphaEnabled
+ );
+
+/* Program the constant fragment color. */
+gceSTATUS
+gco3D_SetFragmentColorX(
+ IN gco3D Engine,
+ IN gctFIXED_POINT Red,
+ IN gctFIXED_POINT Green,
+ IN gctFIXED_POINT Blue,
+ IN gctFIXED_POINT Alpha
+ );
+
+gceSTATUS
+gco3D_SetFragmentColorF(
+ IN gco3D Engine,
+ IN gctFLOAT Red,
+ IN gctFLOAT Green,
+ IN gctFLOAT Blue,
+ IN gctFLOAT Alpha
+ );
+
+/* Program the constant fog color. */
+gceSTATUS
+gco3D_SetFogColorX(
+ IN gco3D Engine,
+ IN gctFIXED_POINT Red,
+ IN gctFIXED_POINT Green,
+ IN gctFIXED_POINT Blue,
+ IN gctFIXED_POINT Alpha
+ );
+
+gceSTATUS
+gco3D_SetFogColorF(
+ IN gco3D Engine,
+ IN gctFLOAT Red,
+ IN gctFLOAT Green,
+ IN gctFLOAT Blue,
+ IN gctFLOAT Alpha
+ );
+
+/* Program the constant texture color. */
+gceSTATUS
+gco3D_SetTetxureColorX(
+ IN gco3D Engine,
+ IN gctINT Stage,
+ IN gctFIXED_POINT Red,
+ IN gctFIXED_POINT Green,
+ IN gctFIXED_POINT Blue,
+ IN gctFIXED_POINT Alpha
+ );
+
+gceSTATUS
+gco3D_SetTetxureColorF(
+ IN gco3D Engine,
+ IN gctINT Stage,
+ IN gctFLOAT Red,
+ IN gctFLOAT Green,
+ IN gctFLOAT Blue,
+ IN gctFLOAT Alpha
+ );
+
+/* Configure color texture function. */
+gceSTATUS
+gco3D_SetColorTextureFunction(
+ IN gco3D Engine,
+ IN gctINT Stage,
+ IN gceTEXTURE_FUNCTION Function,
+ IN gceTEXTURE_SOURCE Source0,
+ IN gceTEXTURE_CHANNEL Channel0,
+ IN gceTEXTURE_SOURCE Source1,
+ IN gceTEXTURE_CHANNEL Channel1,
+ IN gceTEXTURE_SOURCE Source2,
+ IN gceTEXTURE_CHANNEL Channel2,
+ IN gctINT Scale
+ );
+
+/* Configure alpha texture function. */
+gceSTATUS
+gco3D_SetAlphaTextureFunction(
+ IN gco3D Engine,
+ IN gctINT Stage,
+ IN gceTEXTURE_FUNCTION Function,
+ IN gceTEXTURE_SOURCE Source0,
+ IN gceTEXTURE_CHANNEL Channel0,
+ IN gceTEXTURE_SOURCE Source1,
+ IN gceTEXTURE_CHANNEL Channel1,
+ IN gceTEXTURE_SOURCE Source2,
+ IN gceTEXTURE_CHANNEL Channel2,
+ IN gctINT Scale
+ );
+
+/******************************************************************************\
+******************************* gcoTEXTURE Object *******************************
+\******************************************************************************/
+
+/* Cube faces. */
+typedef enum _gceTEXTURE_FACE
+{
+ gcvFACE_NONE = 0,
+ gcvFACE_POSITIVE_X,
+ gcvFACE_NEGATIVE_X,
+ gcvFACE_POSITIVE_Y,
+ gcvFACE_NEGATIVE_Y,
+ gcvFACE_POSITIVE_Z,
+ gcvFACE_NEGATIVE_Z,
+}
+gceTEXTURE_FACE;
+
+typedef struct _gcsTEXTURE
+{
+ /* Addressing modes. */
+ gceTEXTURE_ADDRESSING s;
+ gceTEXTURE_ADDRESSING t;
+ gceTEXTURE_ADDRESSING r;
+
+ gceTEXTURE_SWIZZLE swizzle[gcvTEXTURE_COMPONENT_NUM];
+
+ /* Border color. */
+ gctUINT8 border[gcvTEXTURE_COMPONENT_NUM];
+
+ /* Filters. */
+ gceTEXTURE_FILTER minFilter;
+ gceTEXTURE_FILTER magFilter;
+ gceTEXTURE_FILTER mipFilter;
+ gctUINT anisoFilter;
+
+ /* Level of detail. */
+ gctFLOAT lodBias;
+ gctFLOAT lodMin;
+ gctFLOAT lodMax;
+
+ /* base/max level */
+ gctINT32 baseLevel;
+ gctINT32 maxLevel;
+
+ /* depth texture comparison */
+ gceTEXTURE_COMPARE_MODE compareMode;
+ gceCOMPARE compareFunc;
+
+ gceTEXTURE_DS_MODE dsMode;
+
+ /* sRGB decode */
+ gceTEXTURE_SRGBDECODE sRGB;
+
+ gcuVALUE borderColor[4];
+}
+gcsTEXTURE, * gcsTEXTURE_PTR;
+
+typedef struct _gcsTEXTURE_BINDTEXTS_ARGS
+{
+ /* must be the first member */
+ gceHAL_ARG_VERSION version;
+
+}
+gcsTEXTURE_BINDTEXTS_ARGS;
+
+/* Construct a new gcoTEXTURE object. */
+gceSTATUS
+gcoTEXTURE_Construct(
+ IN gcoHAL Hal,
+ OUT gcoTEXTURE * Texture
+ );
+
+/* Construct a new gcoTEXTURE object with type information. */
+gceSTATUS
+gcoTEXTURE_ConstructEx(
+ IN gcoHAL Hal,
+ IN gceTEXTURE_TYPE Type,
+ OUT gcoTEXTURE * Texture
+ );
+
+
+/* Construct a new sized gcoTEXTURE object. */
+gceSTATUS
+gcoTEXTURE_ConstructSized(
+ IN gcoHAL Hal,
+ IN gceSURF_FORMAT Format,
+ IN gctUINT Width,
+ IN gctUINT Height,
+ IN gctUINT Depth,
+ IN gctUINT Faces,
+ IN gctUINT MipMapCount,
+ IN gcePOOL Pool,
+ OUT gcoTEXTURE * Texture
+ );
+
+/* Destroy an gcoTEXTURE object. */
+gceSTATUS
+gcoTEXTURE_Destroy(
+ IN gcoTEXTURE Texture
+ );
+
+/* Upload data to an gcoTEXTURE object. */
+gceSTATUS
+gcoTEXTURE_Upload(
+ IN gcoTEXTURE Texture,
+ IN gctINT MipMap,
+ IN gceTEXTURE_FACE Face,
+ IN gctSIZE_T Width,
+ IN gctSIZE_T Height,
+ IN gctUINT Slice,
+ IN gctCONST_POINTER Memory,
+ IN gctSIZE_T Stride,
+ IN gceSURF_FORMAT Format,
+ IN gceSURF_COLOR_SPACE SrcColorSpace
+ );
+
+/* Upload data to an gcoTEXTURE object. */
+gceSTATUS
+gcoTEXTURE_UploadSub(
+ IN gcoTEXTURE Texture,
+ IN gctINT MipMap,
+ IN gceTEXTURE_FACE Face,
+ IN gctSIZE_T X,
+ IN gctSIZE_T Y,
+ IN gctSIZE_T Width,
+ IN gctSIZE_T Height,
+ IN gctUINT Slice,
+ IN gctCONST_POINTER Memory,
+ IN gctSIZE_T Stride,
+ IN gceSURF_FORMAT Format,
+ IN gceSURF_COLOR_SPACE SrcColorSpace,
+ IN gctUINT32 PhysicalAddress
+ );
+
+
+/* Upload YUV data to an gcoTEXTURE object. */
+gceSTATUS
+gcoTEXTURE_UploadYUV(
+ IN gcoTEXTURE Texture,
+ IN gceTEXTURE_FACE Face,
+ IN gctUINT Width,
+ IN gctUINT Height,
+ IN gctUINT Slice,
+ IN gctPOINTER Memory[3],
+ IN gctINT Stride[3],
+ IN gceSURF_FORMAT Format
+ );
+
+/* Upload compressed data to an gcoTEXTURE object. */
+gceSTATUS
+gcoTEXTURE_UploadCompressed(
+ IN gcoTEXTURE Texture,
+ IN gctINT MipMap,
+ IN gceTEXTURE_FACE Face,
+ IN gctSIZE_T Width,
+ IN gctSIZE_T Height,
+ IN gctUINT Slice,
+ IN gctCONST_POINTER Memory,
+ IN gctSIZE_T Bytes
+ );
+
+/* Upload compressed sub data to an gcoTEXTURE object. */
+gceSTATUS
+gcoTEXTURE_UploadCompressedSub(
+ IN gcoTEXTURE Texture,
+ IN gctINT MipMap,
+ IN gceTEXTURE_FACE Face,
+ IN gctSIZE_T XOffset,
+ IN gctSIZE_T YOffset,
+ IN gctSIZE_T Width,
+ IN gctSIZE_T Height,
+ IN gctUINT Slice,
+ IN gctCONST_POINTER Memory,
+ IN gctSIZE_T Size
+ );
+
+/* Get gcoSURF object for a mipmap level. */
+gceSTATUS
+gcoTEXTURE_GetMipMap(
+ IN gcoTEXTURE Texture,
+ IN gctUINT MipMap,
+ OUT gcoSURF * Surface
+ );
+
+/* Get gcoSURF object for a mipmap level and face offset. */
+gceSTATUS
+gcoTEXTURE_GetMipMapFace(
+ IN gcoTEXTURE Texture,
+ IN gctUINT MipMap,
+ IN gceTEXTURE_FACE Face,
+ OUT gcoSURF * Surface,
+ OUT gctSIZE_T_PTR Offset
+ );
+
+gceSTATUS
+gcoTEXTURE_GetMipMapSlice(
+ IN gcoTEXTURE Texture,
+ IN gctUINT MipMap,
+ IN gctUINT Slice,
+ OUT gcoSURF * Surface,
+ OUT gctSIZE_T_PTR Offset
+ );
+
+gceSTATUS
+gcoTEXTURE_AddMipMap(
+ IN gcoTEXTURE Texture,
+ IN gctINT Level,
+ IN gctINT InternalFormat,
+ IN gceSURF_FORMAT Format,
+ IN gctSIZE_T Width,
+ IN gctSIZE_T Height,
+ IN gctSIZE_T Depth,
+ IN gctUINT Faces,
+ IN gcePOOL Pool,
+ OUT gcoSURF * Surface
+ );
+
+gceSTATUS
+gcoTEXTURE_AddMipMapEx(
+ IN gcoTEXTURE Texture,
+ IN gctINT Level,
+ IN gctINT InternalFormat,
+ IN gceSURF_FORMAT Format,
+ IN gctSIZE_T Width,
+ IN gctSIZE_T Height,
+ IN gctSIZE_T Depth,
+ IN gctUINT Faces,
+ IN gcePOOL Pool,
+ IN gctUINT32 Samples,
+ IN gctBOOL Protected,
+ OUT gcoSURF * Surface
+ );
+
+gceSTATUS
+gcoTEXTURE_AddMipMapFromClient(
+ IN gcoTEXTURE Texture,
+ IN gctINT Level,
+ IN gcoSURF Surface
+ );
+
+gceSTATUS
+gcoTEXTURE_AddMipMapFromSurface(
+ IN gcoTEXTURE Texture,
+ IN gctINT Level,
+ IN gcoSURF Surface
+ );
+
+gceSTATUS
+gcoTEXTURE_LockMipMap(
+ IN gcoTEXTURE Texture,
+ IN gctUINT MipMap,
+ OPTIONAL OUT gctUINT32 * Address,
+ OPTIONAL OUT gctPOINTER * Memory
+ );
+
+gceSTATUS
+gcoTEXTURE_SetEndianHint(
+ IN gcoTEXTURE Texture,
+ IN gceENDIAN_HINT EndianHint
+ );
+
+gceSTATUS
+gcoTEXTURE_Disable(
+ IN gcoHAL Hal,
+ IN gctINT Sampler,
+ IN gctBOOL DefaultInteger
+ );
+
+gceSTATUS
+gcoTEXTURE_Flush(
+ IN gcoTEXTURE Texture
+ );
+
+gceSTATUS
+gcoTEXTURE_FlushVS(
+ IN gcoTEXTURE Texture
+ );
+
+gceSTATUS
+gcoTEXTURE_QueryCaps(
+ IN gcoHAL Hal,
+ OUT gctUINT * MaxWidth,
+ OUT gctUINT * MaxHeight,
+ OUT gctUINT * MaxDepth,
+ OUT gctBOOL * Cubic,
+ OUT gctBOOL * NonPowerOfTwo,
+ OUT gctUINT * VertexSamplers,
+ OUT gctUINT * PixelSamplers
+ );
+
+gceSTATUS
+gcoTEXTURE_GetClosestFormat(
+ IN gcoHAL Hal,
+ IN gceSURF_FORMAT InFormat,
+ OUT gceSURF_FORMAT* OutFormat
+ );
+
+gceSTATUS
+gcoTEXTURE_GetClosestFormatEx(
+ IN gcoHAL Hal,
+ IN gceSURF_FORMAT InFormat,
+ IN gceTEXTURE_TYPE TextureType,
+ OUT gceSURF_FORMAT* OutFormat
+ );
+
+gceSTATUS
+gcoTEXTURE_GetFormatInfo(
+ IN gcoTEXTURE Texture,
+ IN gctINT preferLevel,
+ OUT gcsSURF_FORMAT_INFO_PTR * TxFormatInfo
+ );
+
+gceSTATUS
+gcoTEXTURE_GetTextureFormatName(
+ IN gcsSURF_FORMAT_INFO_PTR TxFormatInfo,
+ OUT gctCONST_STRING * TxName
+ );
+
+gceSTATUS
+gcoTEXTURE_RenderIntoMipMap(
+ IN gcoTEXTURE Texture,
+ IN gctINT Level
+ );
+
+gceSTATUS
+gcoTEXTURE_RenderIntoMipMap2(
+ IN gcoTEXTURE Texture,
+ IN gctINT Level,
+ IN gctBOOL Sync
+ );
+
+gceSTATUS
+gcoTEXTURE_IsRenderable(
+ IN gcoTEXTURE Texture,
+ IN gctUINT Level
+ );
+
+gceSTATUS
+gcoTEXTURE_IsComplete(
+ IN gcoTEXTURE Texture,
+ IN gcsTEXTURE_PTR Info,
+ IN gctINT BaseLevel,
+ IN gctINT MaxLevel
+ );
+
+gceSTATUS
+gcoTEXTURE_CheckTexLevel0Attrib(
+ IN gcoTEXTURE Texture,
+ IN gctINT MaxLevel,
+ IN gctINT usedLevel
+ );
+
+gceSTATUS
+gcoTEXTURE_BindTexture(
+ IN gcoTEXTURE Texture,
+ IN gctINT Target,
+ IN gctINT Sampler,
+ IN gcsTEXTURE_PTR Info
+ );
+
+gceSTATUS
+gcoTEXTURE_BindTextureEx(
+ IN gcoTEXTURE Texture,
+ IN gctINT Target,
+ IN gctINT Sampler,
+ IN gcsTEXTURE_PTR Info,
+ IN gctINT textureLayer
+ );
+
+gceSTATUS
+gcoTEXTURE_BindTextureDesc(
+ IN gcoTEXTURE Texture,
+ IN gctINT Sampler,
+ IN gcsTEXTURE_PTR Info,
+ IN gctINT TextureLayer
+ );
+
+gceSTATUS
+gcoTEXTURE_SetDescDirty(
+ IN gcoTEXTURE Texture
+ );
+
+gceSTATUS
+gcoTEXTURE_InitParams(
+ IN gcoHAL Hal,
+ IN gcsTEXTURE_PTR TexParams
+ );
+
+gceSTATUS
+gcoTEXTURE_SetDepthTextureFlag(
+ IN gcoTEXTURE Texture,
+ IN gctBOOL unsized
+ );
+
+gceSTATUS
+gcoTEXTURE_BindTextureTS(
+ IN gcsTEXTURE_BINDTEXTS_ARGS * args
+ );
+
+gceSTATUS
+gcoTEXTURE_GenerateMipMap(
+ IN gcoTEXTURE Texture,
+ IN gctINT BaseLevel,
+ IN gctINT MaxLevel
+ );
+
+/******************************************************************************\
+******************************* gcoSTREAM Object ******************************
+\******************************************************************************/
+
+typedef enum _gceVERTEX_FORMAT
+{
+ gcvVERTEX_BYTE,
+ gcvVERTEX_UNSIGNED_BYTE,
+ gcvVERTEX_SHORT,
+ gcvVERTEX_UNSIGNED_SHORT,
+ gcvVERTEX_INT,
+ gcvVERTEX_UNSIGNED_INT,
+ gcvVERTEX_FIXED,
+ gcvVERTEX_HALF,
+ gcvVERTEX_FLOAT,
+ gcvVERTEX_UNSIGNED_INT_10_10_10_2,
+ gcvVERTEX_INT_10_10_10_2,
+ gcvVERTEX_UNSIGNED_INT_2_10_10_10_REV,
+ gcvVERTEX_INT_2_10_10_10_REV,
+ /* integer format */
+ gcvVERTEX_INT8,
+ gcvVERTEX_INT16,
+ gcvVERTEX_INT32,
+}
+gceVERTEX_FORMAT;
+
+/* What the SW converting scheme to create temp attrib */
+typedef enum _gceATTRIB_SCHEME
+{
+ gcvATTRIB_SCHEME_KEEP = 0,
+ gcvATTRIB_SCHEME_2_10_10_10_REV_TO_FLOAT,
+ gcvATTRIB_SCHEME_BYTE_TO_IVEC4,
+ gcvATTRIB_SCHEME_SHORT_TO_IVEC4,
+ gcvATTRIB_SCHEME_INT_TO_IVEC4,
+ gcvATTRIB_SCHEME_UBYTE_TO_UVEC4,
+ gcvATTRIB_SCHEME_USHORT_TO_UVEC4,
+ gcvATTRIB_SCHEME_UINT_TO_UVEC4,
+} gceATTRIB_SCHEME;
+
+gceSTATUS
+gcoSTREAM_Construct(
+ IN gcoHAL Hal,
+ OUT gcoSTREAM * Stream
+ );
+
+gceSTATUS
+gcoSTREAM_Destroy(
+ IN gcoSTREAM Stream
+ );
+
+gceSTATUS
+gcoSTREAM_Upload(
+ IN gcoSTREAM Stream,
+ IN gctCONST_POINTER Buffer,
+ IN gctSIZE_T Offset,
+ IN gctSIZE_T Bytes,
+ IN gctBOOL Dynamic
+ );
+
+gceSTATUS
+gcoSTREAM_ReAllocBufNode(
+ IN gcoSTREAM Stream
+ );
+
+gceSTATUS
+gcoSTREAM_SetStride(
+ IN gcoSTREAM Stream,
+ IN gctUINT32 Stride
+ );
+
+gceSTATUS
+gcoSTREAM_Node(
+ IN gcoSTREAM Stream,
+ OUT gcsSURF_NODE_PTR * Node
+ );
+
+gceSTATUS
+gcoSTREAM_Lock(
+ IN gcoSTREAM Stream,
+ OUT gctPOINTER * Logical,
+ OUT gctUINT32 * Physical
+ );
+
+gceSTATUS
+gcoSTREAM_Unlock(
+ IN gcoSTREAM Stream
+ );
+
+gceSTATUS
+gcoSTREAM_Reserve(
+ IN gcoSTREAM Stream,
+ IN gctSIZE_T Bytes
+ );
+
+gceSTATUS
+gcoSTREAM_Flush(
+ IN gcoSTREAM Stream
+ );
+
+typedef struct _gcsSTREAM_INFO
+{
+ gctUINT index;
+ gceVERTEX_FORMAT format;
+ gctBOOL normalized;
+ gctUINT components;
+ gctSIZE_T size;
+ gctCONST_POINTER data;
+ gctUINT stride;
+}
+gcsSTREAM_INFO, * gcsSTREAM_INFO_PTR;
+
+gceSTATUS
+gcoSTREAM_CPUCacheOperation(
+ IN gcoSTREAM Stream,
+ IN gceCACHEOPERATION Operation
+ );
+
+gceSTATUS
+gcoSTREAM_CPUCacheOperation_Range(
+ IN gcoSTREAM Stream,
+ IN gctSIZE_T Offset,
+ IN gctSIZE_T Length,
+ IN gceCACHEOPERATION Operation
+ );
+
+/******************************************************************************\
+******************************** gcoVERTEX Object ******************************
+\******************************************************************************/
+
+typedef struct _gcsVERTEX_ATTRIBUTES
+{
+ gceVERTEX_FORMAT format;
+ gctBOOL normalized;
+ gctUINT32 components;
+ gctSIZE_T size;
+ gctUINT32 stream;
+ gctUINT32 offset;
+ gctUINT32 stride;
+}
+gcsVERTEX_ATTRIBUTES;
+
+gceSTATUS
+gcoVERTEX_Construct(
+ IN gcoHAL Hal,
+ OUT gcoVERTEX * Vertex
+ );
+
+gceSTATUS
+gcoVERTEX_Destroy(
+ IN gcoVERTEX Vertex
+ );
+
+gceSTATUS
+gcoVERTEX_Reset(
+ IN gcoVERTEX Vertex
+ );
+
+gceSTATUS
+gcoVERTEX_EnableAttribute(
+ IN gcoVERTEX Vertex,
+ IN gctUINT32 Index,
+ IN gceVERTEX_FORMAT Format,
+ IN gctBOOL Normalized,
+ IN gctUINT32 Components,
+ IN gcoSTREAM Stream,
+ IN gctUINT32 Offset,
+ IN gctUINT32 Stride
+ );
+
+gceSTATUS
+gcoVERTEX_DisableAttribute(
+ IN gcoVERTEX Vertex,
+ IN gctUINT32 Index
+ );
+
+gceSTATUS
+gcoVERTEX_Bind(
+ IN gcoVERTEX Vertex
+ );
+
+/*******************************************************************************
+***** gcoVERTEXARRAY Object ***************************************************/
+
+typedef struct _gcsATTRIBUTE
+{
+ /* Enabled. */
+ gctBOOL enable;
+
+ /* Number of components. */
+ gctINT size;
+
+ /* Attribute format. */
+ gceVERTEX_FORMAT format;
+
+ /* Flag whether the attribute is normalized or not. */
+ gctBOOL normalized;
+
+ /* Stride of the component. */
+ gctSIZE_T stride;
+
+ /* Divisor of the attribute */
+ gctUINT divisor;
+
+ /* Pointer to the attribute data. */
+ gctCONST_POINTER pointer;
+
+ /* Stream object owning the attribute data. */
+ gcoBUFOBJ stream;
+
+ /* Generic values for attribute. */
+ gctFLOAT genericValue[4];
+
+ /* Generic size for attribute. */
+ gctINT genericSize;
+
+ /* Vertex shader linkage. */
+ gctUINT linkage;
+
+#if gcdUSE_WCLIP_PATCH
+ /* Does it hold positions? */
+ gctBOOL isPosition;
+#endif
+
+ /* Index to vertex array */
+ gctINT arrayIdx;
+
+ gceATTRIB_SCHEME convertScheme;
+
+ /* Pointer to the temporary buffer to be freed */
+ gcoBUFOBJ tempStream;
+
+ /* Pointer to the temporary memory to be freed */
+ gctCONST_POINTER tempMemory;
+}
+gcsATTRIBUTE,
+* gcsATTRIBUTE_PTR;
+
+typedef struct _gcsVERTEXARRAY
+{
+ /* Enabled. */
+ gctBOOL enable;
+
+ /* Number of components. */
+ gctINT size;
+
+ /* Attribute format. */
+ gceVERTEX_FORMAT format;
+
+ /* Flag whether the attribute is normalized or not. */
+ gctBOOL normalized;
+
+ /* Stride of the component. */
+ gctUINT stride;
+
+ /* Divisor of the attribute */
+ gctUINT divisor;
+
+ /* Pointer to the attribute data. */
+ gctCONST_POINTER pointer;
+
+ /* Stream object owning the attribute data. */
+ gcoSTREAM stream;
+
+ /* Generic values for attribute. */
+ gctFLOAT genericValue[4];
+
+ /* Generic size for attribute. */
+ gctINT genericSize;
+
+ /* Vertex shader linkage. */
+ gctUINT linkage;
+
+ gctBOOL isPosition;
+}
+gcsVERTEXARRAY,
+* gcsVERTEXARRAY_PTR;
+
+gceSTATUS
+gcoVERTEXARRAY_Construct(
+ IN gcoHAL Hal,
+ OUT gcoVERTEXARRAY * Vertex
+ );
+
+gceSTATUS
+gcoVERTEXARRAY_Destroy(
+ IN gcoVERTEXARRAY Vertex
+ );
+
+/* If don't consider isolation, STREAM_INFO / INDEX_INFO could be
+** include in the struct of instantDraw in chip level.*/
+typedef struct _gcsVERTEXARRAY_STREAM_INFO
+{
+ gctUINT attribMask;
+ gctSIZE_T first;
+ gctSIZE_T count;
+ gcePRIMITIVE primMode;
+ gctSIZE_T primCount;
+ gctINT vertexInstIndex;
+ gctBOOL instanced;
+ gctSIZE_T instanceCount;
+
+ union _gcsVERTEXARRAY_STREAM_INFO_UNION
+ {
+ struct _gcsVERTEXARRAY_STREAM_ES11_INFO
+ {
+ gcsVERTEXARRAY_PTR attributes;
+ }es11;
+
+ struct _gcsVERTEXARRAY_STREAM_ES30_INFO
+ {
+ gcsATTRIBUTE_PTR attributes;
+ }es30;
+ }u;
+}gcsVERTEXARRAY_STREAM_INFO,
+*gcsVERTEXARRAY_STREAM_INFO_PTR;
+
+typedef const struct _gcsVERTEXARRAY_STREAM_INFO* gcsVERTEXARRAY_STREAM_INFO_CONST_PTR;
+
+typedef struct _gcsVERTEXARRAY_INDEX_INFO
+{
+ gctSIZE_T count;
+ gceINDEX_TYPE indexType;
+ gctPOINTER indexMemory;
+
+ union _gcsVERTEXARRAY_INDEX_INFO_UNION
+ {
+ struct _gcsVERTEXARRAY_INDEX_ES11_INFO
+ {
+ gcoINDEX indexBuffer;
+ }es11;
+
+ struct _gcsVERTEXARRAY_INDEX_ES30_INFO
+ {
+ gcoBUFOBJ indexBuffer;
+ }es30;
+ }u;
+}gcsVERTEXARRAY_INDEX_INFO,
+*gcsVERTEXARRAY_INDEX_INFO_PTR;
+
+typedef const struct _gcsVERTEXARRAY_INDEX_INFO* gcsVERTEXARRAY_INDEX_INFO_CONST_PTR;
+
+gceSTATUS
+gcoVERTEXARRAY_IndexBind(
+ IN gcoVERTEXARRAY Vertex,
+ IN gcsVERTEXARRAY_INDEX_INFO_PTR IndexInfo
+ );
+
+gceSTATUS
+gcoVERTEXARRAY_StreamBind(
+ IN gcoVERTEXARRAY Vertex,
+#if gcdUSE_WCLIP_PATCH
+ IN OUT gctFLOAT * WLimitRms,
+ IN OUT gctBOOL * WLimitRmsDirty,
+#endif
+ IN gcsVERTEXARRAY_STREAM_INFO_CONST_PTR StreamInfo,
+ IN gcsVERTEXARRAY_INDEX_INFO_CONST_PTR IndexInfo
+ );
+
+gceSTATUS
+gcoVERTEXARRAY_IndexBind_Ex(
+ IN gcoVERTEXARRAY Vertex,
+ IN OUT gcsVERTEXARRAY_STREAM_INFO_PTR StreamInfo,
+ IN gcsVERTEXARRAY_INDEX_INFO_PTR IndexInfo
+ );
+
+gceSTATUS
+gcoVERTEXARRAY_StreamBind_Ex(
+ IN gcoVERTEXARRAY Vertex,
+#if gcdUSE_WCLIP_PATCH
+ IN OUT gctFLOAT * WLimitRms,
+ IN OUT gctBOOL * WLimitRmsDirty,
+#endif
+ IN OUT gcsVERTEXARRAY_STREAM_INFO_PTR StreamInfo,
+ IN gcsVERTEXARRAY_INDEX_INFO_PTR IndexInfo
+ );
+
+gceSTATUS
+gcoVERTEXARRAY_Bind(
+ IN gcoVERTEXARRAY Vertex,
+ IN gctUINT32 EnableBits,
+ IN gcsVERTEXARRAY_PTR VertexArray,
+ IN gctUINT First,
+ IN gctSIZE_T * Count,
+ IN gceINDEX_TYPE IndexType,
+ IN gcoINDEX IndexObject,
+ IN gctPOINTER IndexMemory,
+ IN OUT gcePRIMITIVE * PrimitiveType,
+#if gcdUSE_WCLIP_PATCH
+ IN OUT gctUINT * PrimitiveCount,
+ IN OUT gctFLOAT * wLimitRms,
+ IN OUT gctBOOL * wLimitDirty
+#else
+ IN OUT gctUINT * PrimitiveCount
+#endif
+ );
+
+/* Frame Database */
+gceSTATUS
+gcoHAL_AddFrameDB(
+ void
+ );
+
+gceSTATUS
+gcoHAL_DumpFrameDB(
+ gctCONST_STRING Filename OPTIONAL
+ );
+
+gceSTATUS
+gcoHAL_InitGPUProfile(
+ void
+ );
+
+gceSTATUS
+gcoHAL_DumpGPUProfile(
+ void
+ );
+
+/******************************************************************************
+**********************gcoBUFOBJ object*****************************************
+*******************************************************************************/
+typedef enum _gceBUFOBJ_TYPE
+{
+ gcvBUFOBJ_TYPE_ARRAY_BUFFER = 1,
+ gcvBUFOBJ_TYPE_ELEMENT_ARRAY_BUFFER = 2,
+ gcvBUFOBJ_TYPE_GENERIC_BUFFER = 100
+
+} gceBUFOBJ_TYPE;
+
+typedef enum _gceBUFOBJ_USAGE
+{
+ gcvBUFOBJ_USAGE_STREAM_DRAW = 1,
+ gcvBUFOBJ_USAGE_STREAM_READ,
+ gcvBUFOBJ_USAGE_STREAM_COPY,
+ gcvBUFOBJ_USAGE_STATIC_DRAW,
+ gcvBUFOBJ_USAGE_STATIC_READ,
+ gcvBUFOBJ_USAGE_STATIC_COPY,
+ gcvBUFOBJ_USAGE_DYNAMIC_DRAW,
+ gcvBUFOBJ_USAGE_DYNAMIC_READ,
+ gcvBUFOBJ_USAGE_DYNAMIC_COPY,
+
+ /* special patch for optimaize performance,
+ ** no fence and duplicate stream to ensure data correct
+ */
+ gcvBUFOBJ_USAGE_DISABLE_FENCE_DYNAMIC_STREAM = 256
+} gceBUFOBJ_USAGE;
+
+/* Construct a new gcoBUFOBJ object. */
+gceSTATUS
+gcoBUFOBJ_Construct(
+ IN gcoHAL Hal,
+ IN gceBUFOBJ_TYPE Type,
+ OUT gcoBUFOBJ * BufObj
+ );
+
+/* Destroy a gcoBUFOBJ object. */
+gceSTATUS
+gcoBUFOBJ_Destroy(
+ IN gcoBUFOBJ BufObj
+ );
+
+/* Lock pbo in memory. */
+gceSTATUS
+gcoBUFOBJ_Lock(
+ IN gcoBUFOBJ BufObj,
+ OUT gctUINT32 * Address,
+ OUT gctPOINTER * Memory
+ );
+
+/* Lock pbo in memory. */
+gceSTATUS
+gcoBUFOBJ_FastLock(
+ IN gcoBUFOBJ BufObj,
+ OUT gctUINT32 * Address,
+ OUT gctPOINTER * Memory
+ );
+
+/* Unlock pbo that was previously locked with gcoBUFOBJ_Lock. */
+gceSTATUS
+gcoBUFOBJ_Unlock(
+ IN gcoBUFOBJ BufObj
+ );
+
+/* Free existing pbo buffer. */
+gceSTATUS
+gcoBUFOBJ_Free(
+ IN gcoBUFOBJ BufObj
+ );
+
+/* Upload data into an pbo buffer. */
+gceSTATUS
+gcoBUFOBJ_Upload(
+ IN gcoBUFOBJ BufObj,
+ IN gctCONST_POINTER Buffer,
+ IN gctSIZE_T Offset,
+ IN gctSIZE_T Bytes,
+ IN gceBUFOBJ_USAGE Usage
+ );
+
+/* Bind an index object to the hardware. */
+gceSTATUS
+gcoBUFOBJ_IndexBind (
+ IN gcoBUFOBJ Index,
+ IN gceINDEX_TYPE Type,
+ IN gctUINT32 Offset,
+ IN gctSIZE_T Count
+ );
+
+/* Find min and max index for the index buffer */
+gceSTATUS
+gcoBUFOBJ_IndexGetRange(
+ IN gcoBUFOBJ Index,
+ IN gceINDEX_TYPE Type,
+ IN gctUINT32 Offset,
+ IN gctUINT32 Count,
+ OUT gctUINT32 * MinimumIndex,
+ OUT gctUINT32 * MaximumIndex
+ );
+
+/* Sets a buffer object as dirty */
+gceSTATUS
+gcoBUFOBJ_SetDirty(
+ IN gcoBUFOBJ BufObj
+ );
+
+/* Creates a new buffer if needed */
+gceSTATUS
+gcoBUFOBJ_AlignIndexBufferWhenNeeded(
+ IN gcoBUFOBJ BufObj,
+ IN gctSIZE_T Offset,
+ OUT gcoBUFOBJ * AlignedBufObj
+ );
+
+/* Cache operations on whole range */
+gceSTATUS
+gcoBUFOBJ_CPUCacheOperation(
+ IN gcoBUFOBJ BufObj,
+ IN gceCACHEOPERATION Operation
+ );
+
+/* Cache operations on a specified range */
+gceSTATUS
+gcoBUFOBJ_CPUCacheOperation_Range(
+ IN gcoBUFOBJ BufObj,
+ IN gctSIZE_T Offset,
+ IN gctSIZE_T Length,
+ IN gceCACHEOPERATION Operation
+ );
+
+/* Return size of the bufobj */
+gceSTATUS
+gcoBUFOBJ_GetSize(
+ IN gcoBUFOBJ BufObj,
+ OUT gctSIZE_T_PTR Size
+ );
+
+/* Return memory node of the bufobj */
+gceSTATUS
+gcoBUFOBJ_GetNode(
+ IN gcoBUFOBJ BufObj,
+ OUT gcsSURF_NODE_PTR * Node
+ );
+
+gceSTATUS
+gcoBUFOBJ_ReAllocBufNode(
+ IN gcoBUFOBJ BufObj
+ );
+
+/* Handle GPU cache operations */
+gceSTATUS
+gcoBUFOBJ_GPUCacheOperation(
+ gcoBUFOBJ BufObj
+ );
+
+/* Dump buffer. */
+void
+gcoBUFOBJ_Dump(
+ IN gcoBUFOBJ BufObj
+ );
+
+#endif /* gcdENABLE_3D */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_engine_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_engine_vg.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_engine_vg.h
new file mode 100644
index 000000000000..13c79c557848
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_engine_vg.h
@@ -0,0 +1,1318 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_engine_vg_h_
+#define __gc_hal_engine_vg_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gc_hal_types.h"
+
+/******************************************************************************\
+******************************** VG Enumerations *******************************
+\******************************************************************************/
+
+/**
+** @ingroup gcoVG
+**
+** @brief Tiling mode for painting and imagig.
+**
+** This enumeration defines the tiling modes supported by the HAL. This is
+** in fact a one-to-one mapping of the OpenVG 1.1 tile modes.
+*/
+typedef enum _gceTILE_MODE
+{
+ gcvTILE_FILL,
+ gcvTILE_PAD,
+ gcvTILE_REPEAT,
+ gcvTILE_REFLECT
+}
+gceTILE_MODE;
+
+/******************************************************************************/
+/** @ingroup gcoVG
+**
+** @brief The different paint modes.
+**
+** This enumeration lists the available paint modes.
+*/
+typedef enum _gcePAINT_TYPE
+{
+ /** Solid color. */
+ gcvPAINT_MODE_SOLID,
+
+ /** Linear gradient. */
+ gcvPAINT_MODE_LINEAR,
+
+ /** Radial gradient. */
+ gcvPAINT_MODE_RADIAL,
+
+ /** Pattern. */
+ gcvPAINT_MODE_PATTERN,
+
+ /** Mode count. */
+ gcvPAINT_MODE_COUNT
+}
+gcePAINT_TYPE;
+
+/**
+** @ingroup gcoVG
+**
+** @brief Types of path data supported by HAL.
+**
+** This enumeration defines the types of path data supported by the HAL.
+** This is in fact a one-to-one mapping of the OpenVG 1.1 path types.
+*/
+typedef enum _gcePATHTYPE
+{
+ gcePATHTYPE_UNKNOWN = -1,
+ gcePATHTYPE_INT8,
+ gcePATHTYPE_INT16,
+ gcePATHTYPE_INT32,
+ gcePATHTYPE_FLOAT
+}
+gcePATHTYPE;
+
+/**
+** @ingroup gcoVG
+**
+** @brief Supported path segment commands.
+**
+** This enumeration defines the path segment commands supported by the HAL.
+*/
+typedef enum _gceVGCMD
+{
+ gcvVGCMD_END, /* 0: GCCMD_TS_OPCODE_END */
+ gcvVGCMD_CLOSE, /* 1: GCCMD_TS_OPCODE_CLOSE */
+ gcvVGCMD_MOVE, /* 2: GCCMD_TS_OPCODE_MOVE */
+ gcvVGCMD_MOVE_REL, /* 3: GCCMD_TS_OPCODE_MOVE_REL */
+ gcvVGCMD_LINE, /* 4: GCCMD_TS_OPCODE_LINE */
+ gcvVGCMD_LINE_REL, /* 5: GCCMD_TS_OPCODE_LINE_REL */
+ gcvVGCMD_QUAD, /* 6: GCCMD_TS_OPCODE_QUADRATIC */
+ gcvVGCMD_QUAD_REL, /* 7: GCCMD_TS_OPCODE_QUADRATIC_REL */
+ gcvVGCMD_CUBIC, /* 8: GCCMD_TS_OPCODE_CUBIC */
+ gcvVGCMD_CUBIC_REL, /* 9: GCCMD_TS_OPCODE_CUBIC_REL */
+ gcvVGCMD_BREAK, /* 10: GCCMD_TS_OPCODE_BREAK */
+ gcvVGCMD_HLINE, /* 11: ******* R E S E R V E D *******/
+ gcvVGCMD_HLINE_REL, /* 12: ******* R E S E R V E D *******/
+ gcvVGCMD_VLINE, /* 13: ******* R E S E R V E D *******/
+ gcvVGCMD_VLINE_REL, /* 14: ******* R E S E R V E D *******/
+ gcvVGCMD_SQUAD, /* 15: ******* R E S E R V E D *******/
+ gcvVGCMD_SQUAD_REL, /* 16: ******* R E S E R V E D *******/
+ gcvVGCMD_SCUBIC, /* 17: ******* R E S E R V E D *******/
+ gcvVGCMD_SCUBIC_REL, /* 18: ******* R E S E R V E D *******/
+ gcvVGCMD_SCCWARC, /* 19: ******* R E S E R V E D *******/
+ gcvVGCMD_SCCWARC_REL, /* 20: ******* R E S E R V E D *******/
+ gcvVGCMD_SCWARC, /* 21: ******* R E S E R V E D *******/
+ gcvVGCMD_SCWARC_REL, /* 22: ******* R E S E R V E D *******/
+ gcvVGCMD_LCCWARC, /* 23: ******* R E S E R V E D *******/
+ gcvVGCMD_LCCWARC_REL, /* 24: ******* R E S E R V E D *******/
+ gcvVGCMD_LCWARC, /* 25: ******* R E S E R V E D *******/
+ gcvVGCMD_LCWARC_REL, /* 26: ******* R E S E R V E D *******/
+
+ /* The width of the command recognized by the hardware on bits. */
+ gcvVGCMD_WIDTH = 5,
+
+ /* Hardware command mask. */
+ gcvVGCMD_MASK = (1 << gcvVGCMD_WIDTH) - 1,
+
+ /* Command modifiers. */
+ gcvVGCMD_H_MOD = 1 << gcvVGCMD_WIDTH, /* = 32 */
+ gcvVGCMD_V_MOD = 2 << gcvVGCMD_WIDTH, /* = 64 */
+ gcvVGCMD_S_MOD = 3 << gcvVGCMD_WIDTH, /* = 96 */
+ gcvVGCMD_ARC_MOD = 4 << gcvVGCMD_WIDTH, /* = 128 */
+
+ /* Emulated LINE commands. */
+ gcvVGCMD_HLINE_EMUL = gcvVGCMD_H_MOD | gcvVGCMD_LINE, /* = 36 */
+ gcvVGCMD_HLINE_EMUL_REL = gcvVGCMD_H_MOD | gcvVGCMD_LINE_REL, /* = 37 */
+ gcvVGCMD_VLINE_EMUL = gcvVGCMD_V_MOD | gcvVGCMD_LINE, /* = 68 */
+ gcvVGCMD_VLINE_EMUL_REL = gcvVGCMD_V_MOD | gcvVGCMD_LINE_REL, /* = 69 */
+
+ /* Emulated SMOOTH commands. */
+ gcvVGCMD_SQUAD_EMUL = gcvVGCMD_S_MOD | gcvVGCMD_QUAD, /* = 102 */
+ gcvVGCMD_SQUAD_EMUL_REL = gcvVGCMD_S_MOD | gcvVGCMD_QUAD_REL, /* = 103 */
+ gcvVGCMD_SCUBIC_EMUL = gcvVGCMD_S_MOD | gcvVGCMD_CUBIC, /* = 104 */
+ gcvVGCMD_SCUBIC_EMUL_REL = gcvVGCMD_S_MOD | gcvVGCMD_CUBIC_REL, /* = 105 */
+
+ /* Emulation ARC commands. */
+ gcvVGCMD_ARC_LINE = gcvVGCMD_ARC_MOD | gcvVGCMD_LINE, /* = 132 */
+ gcvVGCMD_ARC_LINE_REL = gcvVGCMD_ARC_MOD | gcvVGCMD_LINE_REL, /* = 133 */
+ gcvVGCMD_ARC_QUAD = gcvVGCMD_ARC_MOD | gcvVGCMD_QUAD, /* = 134 */
+ gcvVGCMD_ARC_QUAD_REL = gcvVGCMD_ARC_MOD | gcvVGCMD_QUAD_REL /* = 135 */
+}
+gceVGCMD;
+typedef enum _gceVGCMD * gceVGCMD_PTR;
+
+/**
+** @ingroup gcoVG
+**
+** @brief Blending modes supported by the HAL.
+**
+** This enumeration defines the blending modes supported by the HAL. This is
+** in fact a one-to-one mapping of the OpenVG 1.1 blending modes.
+*/
+typedef enum _gceVG_BLEND
+{
+ gcvVG_BLEND_SRC,
+ gcvVG_BLEND_SRC_OVER,
+ gcvVG_BLEND_DST_OVER,
+ gcvVG_BLEND_SRC_IN,
+ gcvVG_BLEND_DST_IN,
+ gcvVG_BLEND_MULTIPLY,
+ gcvVG_BLEND_SCREEN,
+ gcvVG_BLEND_DARKEN,
+ gcvVG_BLEND_LIGHTEN,
+ gcvVG_BLEND_ADDITIVE,
+ gcvVG_BLEND_SUBTRACT,
+ gcvVG_BLEND_FILTER
+}
+gceVG_BLEND;
+
+/**
+** @ingroup gcoVG
+**
+** @brief Image modes supported by the HAL.
+**
+** This enumeration defines the image modes supported by the HAL. This is
+** in fact a one-to-one mapping of the OpenVG 1.1 image modes with the addition
+** of NO IMAGE.
+*/
+typedef enum _gceVG_IMAGE
+{
+ gcvVG_IMAGE_NONE,
+ gcvVG_IMAGE_NORMAL,
+ gcvVG_IMAGE_MULTIPLY,
+ gcvVG_IMAGE_STENCIL,
+ gcvVG_IMAGE_FILTER
+}
+gceVG_IMAGE;
+
+/**
+** @ingroup gcoVG
+**
+** @brief Filter mode patterns and imaging.
+**
+** This enumeration defines the filter modes supported by the HAL.
+*/
+typedef enum _gceIMAGE_FILTER
+{
+ gcvFILTER_POINT,
+ gcvFILTER_LINEAR,
+ gcvFILTER_BI_LINEAR
+}
+gceIMAGE_FILTER;
+
+/**
+** @ingroup gcoVG
+**
+** @brief Primitive modes supported by the HAL.
+**
+** This enumeration defines the primitive modes supported by the HAL.
+*/
+typedef enum _gceVG_PRIMITIVE
+{
+ gcvVG_SCANLINE,
+ gcvVG_RECTANGLE,
+ gcvVG_TESSELLATED,
+ gcvVG_TESSELLATED_TILED
+}
+gceVG_PRIMITIVE;
+
+/**
+** @ingroup gcoVG
+**
+** @brief Rendering quality modes supported by the HAL.
+**
+** This enumeration defines the rendering quality modes supported by the HAL.
+*/
+typedef enum _gceRENDER_QUALITY
+{
+ gcvVG_NONANTIALIASED,
+ gcvVG_2X2_MSAA,
+ gcvVG_2X4_MSAA,
+ gcvVG_4X4_MSAA
+}
+gceRENDER_QUALITY;
+
+/**
+** @ingroup gcoVG
+**
+** @brief Fill rules supported by the HAL.
+**
+** This enumeration defines the fill rules supported by the HAL.
+*/
+typedef enum _gceFILL_RULE
+{
+ gcvVG_EVEN_ODD,
+ gcvVG_NON_ZERO
+}
+gceFILL_RULE;
+
+/**
+** @ingroup gcoVG
+**
+** @brief Cap styles supported by the HAL.
+**
+** This enumeration defines the cap styles supported by the HAL.
+*/
+typedef enum _gceCAP_STYLE
+{
+ gcvCAP_BUTT,
+ gcvCAP_ROUND,
+ gcvCAP_SQUARE
+}
+gceCAP_STYLE;
+
+/**
+** @ingroup gcoVG
+**
+** @brief Join styles supported by the HAL.
+**
+** This enumeration defines the join styles supported by the HAL.
+*/
+typedef enum _gceJOIN_STYLE
+{
+ gcvJOIN_MITER,
+ gcvJOIN_ROUND,
+ gcvJOIN_BEVEL
+}
+gceJOIN_STYLE;
+
+/**
+** @ingroup gcoVG
+**
+** @brief Channel mask values.
+**
+** This enumeration defines the values for channel mask used in image
+** filtering.
+*/
+
+/* Base values for channel mask definitions. */
+#define gcvCHANNEL_X (0)
+#define gcvCHANNEL_R (1 << 0)
+#define gcvCHANNEL_G (1 << 1)
+#define gcvCHANNEL_B (1 << 2)
+#define gcvCHANNEL_A (1 << 3)
+
+typedef enum _gceCHANNEL
+{
+ gcvCHANNEL_XXXX = (gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_X),
+ gcvCHANNEL_XXXA = (gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_A),
+ gcvCHANNEL_XXBX = (gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_B | gcvCHANNEL_X),
+ gcvCHANNEL_XXBA = (gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_B | gcvCHANNEL_A),
+
+ gcvCHANNEL_XGXX = (gcvCHANNEL_X | gcvCHANNEL_G | gcvCHANNEL_X | gcvCHANNEL_X),
+ gcvCHANNEL_XGXA = (gcvCHANNEL_X | gcvCHANNEL_G | gcvCHANNEL_X | gcvCHANNEL_A),
+ gcvCHANNEL_XGBX = (gcvCHANNEL_X | gcvCHANNEL_G | gcvCHANNEL_B | gcvCHANNEL_X),
+ gcvCHANNEL_XGBA = (gcvCHANNEL_X | gcvCHANNEL_G | gcvCHANNEL_B | gcvCHANNEL_A),
+
+ gcvCHANNEL_RXXX = (gcvCHANNEL_R | gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_X),
+ gcvCHANNEL_RXXA = (gcvCHANNEL_R | gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_A),
+ gcvCHANNEL_RXBX = (gcvCHANNEL_R | gcvCHANNEL_X | gcvCHANNEL_B | gcvCHANNEL_X),
+ gcvCHANNEL_RXBA = (gcvCHANNEL_R | gcvCHANNEL_X | gcvCHANNEL_B | gcvCHANNEL_A),
+
+ gcvCHANNEL_RGXX = (gcvCHANNEL_R | gcvCHANNEL_G | gcvCHANNEL_X | gcvCHANNEL_X),
+ gcvCHANNEL_RGXA = (gcvCHANNEL_R | gcvCHANNEL_G | gcvCHANNEL_X | gcvCHANNEL_A),
+ gcvCHANNEL_RGBX = (gcvCHANNEL_R | gcvCHANNEL_G | gcvCHANNEL_B | gcvCHANNEL_X),
+ gcvCHANNEL_RGBA = (gcvCHANNEL_R | gcvCHANNEL_G | gcvCHANNEL_B | gcvCHANNEL_A),
+}
+gceCHANNEL;
+
+/******************************************************************************\
+******************************** VG Structures *******************************
+\******************************************************************************/
+
+/**
+** @ingroup gcoVG
+**
+** @brief Definition of the color ramp used by the gradient paints.
+**
+** The gcsCOLOR_RAMP structure defines the layout of one single color inside
+** a color ramp which is used by gradient paints.
+*/
+typedef struct _gcsCOLOR_RAMP
+{
+ /** Value for the color stop. */
+ gctFLOAT stop;
+
+ /** Red color channel value for the color stop. */
+ gctFLOAT red;
+
+ /** Green color channel value for the color stop. */
+ gctFLOAT green;
+
+ /** Blue color channel value for the color stop. */
+ gctFLOAT blue;
+
+ /** Alpha color channel value for the color stop. */
+ gctFLOAT alpha;
+}
+gcsCOLOR_RAMP, * gcsCOLOR_RAMP_PTR;
+
+/**
+** @ingroup gcoVG
+**
+** @brief Definition of the color ramp used by the gradient paints in fixed form.
+**
+** The gcsCOLOR_RAMP structure defines the layout of one single color inside
+** a color ramp which is used by gradient paints.
+*/
+typedef struct _gcsFIXED_COLOR_RAMP
+{
+ /** Value for the color stop. */
+ gctFIXED_POINT stop;
+
+ /** Red color channel value for the color stop. */
+ gctFIXED_POINT red;
+
+ /** Green color channel value for the color stop. */
+ gctFIXED_POINT green;
+
+ /** Blue color channel value for the color stop. */
+ gctFIXED_POINT blue;
+
+ /** Alpha color channel value for the color stop. */
+ gctFIXED_POINT alpha;
+}
+gcsFIXED_COLOR_RAMP, * gcsFIXED_COLOR_RAMP_PTR;
+
+
+/**
+** @ingroup gcoVG
+**
+** @brief Rectangle structure used by the gcoVG object.
+**
+** This structure defines the layout of a rectangle. Make sure width and
+** height are larger than 0.
+*/
+typedef struct _gcsVG_RECT * gcsVG_RECT_PTR;
+typedef struct _gcsVG_RECT
+{
+ /** Left location of the rectangle. */
+ gctINT x;
+
+ /** Top location of the rectangle. */
+ gctINT y;
+
+ /** Width of the rectangle. */
+ gctINT width;
+
+ /** Height of the rectangle. */
+ gctINT height;
+}
+gcsVG_RECT;
+
+/**
+** @ingroup gcoVG
+**
+** @brief Path command buffer attribute structure.
+**
+** The gcsPATH_BUFFER_INFO structure contains the specifics about
+** the layout of the path data command buffer.
+*/
+typedef struct _gcsPATH_BUFFER_INFO * gcsPATH_BUFFER_INFO_PTR;
+typedef struct _gcsPATH_BUFFER_INFO
+{
+ gctUINT reservedForHead;
+ gctUINT reservedForTail;
+}
+gcsPATH_BUFFER_INFO;
+
+/**
+** @ingroup gcoVG
+**
+** @brief Definition of the path data container structure.
+**
+** The gcsPATH structure defines the layout of the path data container.
+*/
+typedef struct _gcsPATH_DATA * gcsPATH_DATA_PTR;
+typedef struct _gcsPATH_DATA
+{
+ /* Data container in command buffer format. */
+ gcsCMDBUFFER data;
+
+ /* Path data type. */
+ gcePATHTYPE dataType;
+}
+gcsPATH_DATA;
+
+
+/******************************************************************************\
+********************************* gcoHAL Object ********************************
+\******************************************************************************/
+
+/* Query path data storage attributes. */
+gceSTATUS
+gcoHAL_QueryPathStorage(
+ IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ OUT gcsPATH_BUFFER_INFO_PTR Information
+ );
+
+/* Associate a completion signal with the command buffer. */
+gceSTATUS
+gcoHAL_AssociateCompletion(
+ IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcsPATH_DATA_PTR PathData
+ );
+
+/* Release the current command buffer completion signal. */
+gceSTATUS
+gcoHAL_DeassociateCompletion(
+ IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcsPATH_DATA_PTR PathData
+ );
+
+/* Verify whether the command buffer is still in use. */
+gceSTATUS
+gcoHAL_CheckCompletion(
+ IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcsPATH_DATA_PTR PathData
+ );
+
+/* Wait until the command buffer is no longer in use. */
+gceSTATUS
+gcoHAL_WaitCompletion(
+ IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcsPATH_DATA_PTR PathData
+ );
+
+/* Flush the pixel cache. */
+gceSTATUS
+gcoHAL_Flush(
+#if gcdGC355_PROFILER
+ IN gcoHAL Hal,
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth
+#else
+ IN gcoHAL Hal
+#endif
+ );
+
+/* Split a harwdare address into pool and offset. */
+gceSTATUS
+gcoHAL_SplitAddress(
+ IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctUINT32 Address,
+ OUT gcePOOL * Pool,
+ OUT gctUINT32 * Offset
+ );
+
+/* Combine pool and offset into a harwdare address. */
+gceSTATUS
+gcoHAL_CombineAddress(
+ IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcePOOL Pool,
+ IN gctUINT32 Offset,
+ OUT gctUINT32 * Address
+ );
+
+/* Schedule to free linear video memory allocated. */
+gceSTATUS
+gcoHAL_ScheduleVideoMemory(
+ IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctUINT32 Node
+ );
+
+/* Free linear video memory allocated with gcoHAL_AllocateLinearVideoMemory. */
+gceSTATUS
+gcoHAL_FreeVideoMemory(
+ IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctUINT32 Node,
+ IN gctBOOL asynchroneous
+ );
+
+/* Query command buffer attributes. */
+gceSTATUS
+gcoHAL_QueryCommandBuffer(
+ IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ OUT gcsCOMMAND_BUFFER_INFO_PTR Information
+ );
+/* Allocate and lock linear video memory. */
+gceSTATUS
+gcoHAL_AllocateLinearVideoMemory(
+ IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctUINT Size,
+ IN gctUINT Alignment,
+ IN gcePOOL Pool,
+ OUT gctUINT32 * Node,
+ OUT gctUINT32 * Address,
+ OUT gctPOINTER * Memory
+ );
+
+/* Align the specified size accordingly to the hardware requirements. */
+gceSTATUS
+gcoHAL_GetAlignedSurfaceSize(
+ IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gceSURF_TYPE Type,
+ IN OUT gctUINT32_PTR Width,
+ IN OUT gctUINT32_PTR Height
+ );
+
+gceSTATUS
+gcoHAL_ReserveTask(
+ IN gcoHAL Hal,
+#if gcdGC355_PROFILER
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gceBLOCK Block,
+ IN gctUINT TaskCount,
+ IN gctUINT32 Bytes,
+ OUT gctPOINTER * Memory
+ );
+/******************************************************************************\
+********************************** gcoVG Object ********************************
+\******************************************************************************/
+
+/** @defgroup gcoVG gcoVG
+**
+** The gcoVG object abstracts the VG hardware pipe.
+*/
+#if gcdGC355_PROFILER
+void
+gcoVG_ProfilerEnableDisable(
+ IN gcoVG Vg,
+ IN gctUINT enableGetAPITimes,
+ IN gctFILE apiTimeFile
+ );
+
+void
+gcoVG_ProfilerTreeDepth(
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth
+ );
+
+void
+gcoVG_ProfilerSetStates(
+ IN gcoVG Vg,
+ IN gctUINT treeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth
+ );
+#endif
+
+gctBOOL
+gcoVG_IsMaskSupported(
+#if gcdGC355_PROFILER
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gceSURF_FORMAT Format
+ );
+
+gctBOOL
+gcoVG_IsTargetSupported(
+#if gcdGC355_PROFILER
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gceSURF_FORMAT Format
+ );
+
+gctBOOL
+gcoVG_IsImageSupported(
+#if gcdGC355_PROFILER
+ IN gcoVG Vg,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gceSURF_FORMAT Format
+ );
+
+gctUINT8 gcoVG_PackColorComponent(
+#if gcdGC355_PROFILER
+ gcoVG Vg,
+ gctUINT TreeDepth,
+ gctUINT saveLayerTreeDepth,
+ gctUINT varTreeDepth,
+#endif
+ gctFLOAT Value
+ );
+
+gceSTATUS
+gcoVG_Construct(
+ IN gcoHAL Hal,
+ OUT gcoVG * Vg
+ );
+
+gceSTATUS
+gcoVG_Destroy(
+ IN gcoVG Vg
+#if gcdGC355_PROFILER
+ ,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth
+#endif
+ );
+
+gceSTATUS
+gcoVG_SetTarget(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcoSURF Target,
+ IN gceORIENTATION orientation
+ );
+
+gceSTATUS
+gcoVG_UnsetTarget(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcoSURF Surface
+ );
+
+gceSTATUS
+gcoVG_SetUserToSurface(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctFLOAT UserToSurface[9]
+ );
+
+gceSTATUS
+gcoVG_SetSurfaceToImage(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctFLOAT SurfaceToImage[9]
+ );
+
+gceSTATUS
+gcoVG_EnableMask(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctBOOL Enable
+ );
+
+gceSTATUS
+gcoVG_SetMask(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcoSURF Mask
+ );
+
+gceSTATUS
+gcoVG_UnsetMask(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcoSURF Surface
+ );
+
+gceSTATUS
+gcoVG_FlushMask(
+ IN gcoVG Vg
+#if gcdGC355_PROFILER
+ ,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth
+#endif
+ );
+
+gceSTATUS
+gcoVG_EnableScissor(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctBOOL Enable
+ );
+
+gceSTATUS
+gcoVG_SetScissor(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctSIZE_T RectangleCount,
+ IN gcsVG_RECT_PTR Rectangles
+ );
+
+gceSTATUS
+gcoVG_EnableColorTransform(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctBOOL Enable
+ );
+
+gceSTATUS
+gcoVG_SetColorTransform(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctFLOAT ColorTransform[8]
+ );
+
+gceSTATUS
+gcoVG_SetTileFillColor(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctFLOAT Red,
+ IN gctFLOAT Green,
+ IN gctFLOAT Blue,
+ IN gctFLOAT Alpha
+ );
+
+gceSTATUS
+gcoVG_SetSolidPaint(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctUINT8 Red,
+ IN gctUINT8 Green,
+ IN gctUINT8 Blue,
+ IN gctUINT8 Alpha
+ );
+
+gceSTATUS
+gcoVG_SetLinearPaint(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctFLOAT Constant,
+ IN gctFLOAT StepX,
+ IN gctFLOAT StepY
+ );
+
+gceSTATUS
+gcoVG_SetRadialPaint(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctFLOAT LinConstant,
+ IN gctFLOAT LinStepX,
+ IN gctFLOAT LinStepY,
+ IN gctFLOAT RadConstant,
+ IN gctFLOAT RadStepX,
+ IN gctFLOAT RadStepY,
+ IN gctFLOAT RadStepXX,
+ IN gctFLOAT RadStepYY,
+ IN gctFLOAT RadStepXY
+ );
+
+gceSTATUS
+gcoVG_SetPatternPaint(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctFLOAT UConstant,
+ IN gctFLOAT UStepX,
+ IN gctFLOAT UStepY,
+ IN gctFLOAT VConstant,
+ IN gctFLOAT VStepX,
+ IN gctFLOAT VStepY,
+ IN gctBOOL Linear
+ );
+
+gceSTATUS
+gcoVG_SetColorRamp(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcoSURF ColorRamp,
+ IN gceTILE_MODE ColorRampSpreadMode
+ );
+
+gceSTATUS
+gcoVG_SetPattern(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctINT32 width,
+ IN gctINT32 height,
+ IN gcoSURF Pattern,
+ IN gceTILE_MODE TileMode,
+ IN gceIMAGE_FILTER Filter
+ );
+
+gceSTATUS
+gcoVG_SetImageMode(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gceVG_IMAGE Mode
+ );
+
+gceSTATUS
+gcoVG_SetBlendMode(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gceVG_BLEND Mode
+ );
+
+gceSTATUS
+gcoVG_SetRenderingQuality(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gceRENDER_QUALITY Quality
+ );
+
+gceSTATUS
+gcoVG_SetFillRule(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gceFILL_RULE FillRule
+ );
+
+gceSTATUS
+gcoVG_FinalizePath(
+ IN gcoVG Vg,
+ IN gcsPATH_DATA_PTR PathData
+ );
+
+gceSTATUS
+gcoVG_Clear(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctINT X,
+ IN gctINT Y,
+ IN gctINT Width,
+ IN gctINT Height
+ );
+
+gceSTATUS
+gcoVG_DrawPath(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcsPATH_DATA_PTR PathData,
+ IN gctFLOAT Scale,
+ IN gctFLOAT Bias,
+#if gcdMOVG
+ IN gctUINT32 Width,
+ IN gctUINT32 Height,
+ IN gctFLOAT *Bounds,
+#endif
+ IN gctBOOL SoftwareTesselation
+ );
+
+gceSTATUS
+gcoVG_DrawImage(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gceORIENTATION orientation,
+ IN gcoSURF Source,
+ IN gcsPOINT_PTR SourceOrigin,
+ IN gcsPOINT_PTR TargetOrigin,
+ IN gcsSIZE_PTR SourceSize,
+ IN gctINT SourceX,
+ IN gctINT SourceY,
+ IN gctINT TargetX,
+ IN gctINT TargetY,
+ IN gctINT Width,
+ IN gctINT Height,
+ IN gctBOOL Mask,
+ IN gctBOOL isDrawImage
+ );
+
+gceSTATUS
+gcoVG_TesselateImage(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcoSURF Image,
+ IN gcsVG_RECT_PTR Rectangle,
+ IN gceIMAGE_FILTER Filter,
+ IN gctBOOL Mask,
+#if gcdMOVG
+ IN gctBOOL SoftwareTesselation,
+ IN gceVG_BLEND BlendMode,
+ IN gctINT Width,
+ IN gctINT Height
+#else
+ IN gctBOOL SoftwareTesselation
+#endif
+ );
+
+gceSTATUS
+gcoVG_DrawSurfaceToImage(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcoSURF Image,
+ IN const gcsVG_RECT_PTR SrcRectangle,
+ IN const gcsVG_RECT_PTR DstRectangle,
+ IN const gctFLOAT Matrix[9],
+ IN gceIMAGE_FILTER Filter,
+ IN gctBOOL Mask,
+ IN gctBOOL FirstTime
+ );
+
+gceSTATUS
+gcoVG_Blit(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcoSURF Source,
+ IN gcoSURF Target,
+ IN gcsVG_RECT_PTR SrcRect,
+ IN gcsVG_RECT_PTR TrgRect,
+ IN gceIMAGE_FILTER Filter,
+ IN gceVG_BLEND Mode
+ );
+
+gceSTATUS
+gcoVG_ColorMatrix(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcoSURF Source,
+ IN gcoSURF Target,
+ IN const gctFLOAT * Matrix,
+ IN gceCHANNEL ColorChannels,
+ IN gctBOOL FilterLinear,
+ IN gctBOOL FilterPremultiplied,
+ IN gcsPOINT_PTR SourceOrigin,
+ IN gcsPOINT_PTR TargetOrigin,
+ IN gctINT Width,
+ IN gctINT Height
+ );
+
+gceSTATUS
+gcoVG_SeparableConvolve(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcoSURF Source,
+ IN gcoSURF Target,
+ IN gctINT KernelWidth,
+ IN gctINT KernelHeight,
+ IN gctINT ShiftX,
+ IN gctINT ShiftY,
+ IN const gctINT16 * KernelX,
+ IN const gctINT16 * KernelY,
+ IN gctFLOAT Scale,
+ IN gctFLOAT Bias,
+ IN gceTILE_MODE TilingMode,
+ IN gctFLOAT_PTR FillColor,
+ IN gceCHANNEL ColorChannels,
+ IN gctBOOL FilterLinear,
+ IN gctBOOL FilterPremultiplied,
+ IN gcsPOINT_PTR SourceOrigin,
+ IN gcsPOINT_PTR TargetOrigin,
+ IN gcsSIZE_PTR SourceSize,
+ IN gctINT Width,
+ IN gctINT Height
+ );
+
+gceSTATUS
+gcoVG_GaussianBlur(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gcoSURF Source,
+ IN gcoSURF Target,
+ IN gctFLOAT StdDeviationX,
+ IN gctFLOAT StdDeviationY,
+ IN gceTILE_MODE TilingMode,
+ IN gctFLOAT_PTR FillColor,
+ IN gceCHANNEL ColorChannels,
+ IN gctBOOL FilterLinear,
+ IN gctBOOL FilterPremultiplied,
+ IN gcsPOINT_PTR SourceOrigin,
+ IN gcsPOINT_PTR TargetOrigin,
+ IN gcsSIZE_PTR SourceSize,
+ IN gctINT Width,
+ IN gctINT Height
+ );
+
+gceSTATUS
+gcoVG_EnableDither(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctBOOL Enable
+ );
+
+/* Color Key States. */
+gceSTATUS
+gcoVG_SetColorKey(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gcsPROFILERFUNCNODE *DList,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctUINT32* Values,
+ IN gctBOOL * Enables
+);
+
+/* Index Color States. */
+gceSTATUS
+gcoVG_SetColorIndexTable(
+ IN gcoVG Vg,
+#if gcdGC355_PROFILER
+ IN gcsPROFILERFUNCNODE *DList,
+ IN gctUINT TreeDepth,
+ IN gctUINT saveLayerTreeDepth,
+ IN gctUINT varTreeDepth,
+#endif
+ IN gctUINT32* Values,
+ IN gctINT32 Count
+);
+
+/* VG RS feature support: YUV format conversion. */
+gceSTATUS
+gcoVG_Resolve(
+ IN gcoVG Vg,
+ IN gcoSURF Source,
+ IN gcoSURF Target,
+ IN gctINT SX,
+ IN gctINT SY,
+ IN gctINT DX,
+ IN gctINT DY,
+ IN gctINT Width,
+ IN gctINT Height,
+ IN gctINT Src_uv,
+ IN gctINT Src_standard,
+ IN gctINT Dst_uv,
+ IN gctINT Dst_standard,
+ IN gctINT Dst_alpha
+);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_vg_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_enum.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_enum.h
new file mode 100644
index 000000000000..5b5dfd5d9b71
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_enum.h
@@ -0,0 +1,2179 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_enum_h_
+#define __gc_hal_enum_h_
+
+#include "gc_hal_options.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Chip models. */
+typedef enum _gceCHIPMODEL
+{
+ gcv200 = 0x0200,
+ gcv300 = 0x0300,
+ gcv320 = 0x0320,
+ gcv328 = 0x0328,
+ gcv350 = 0x0350,
+ gcv355 = 0x0355,
+ gcv400 = 0x0400,
+ gcv410 = 0x0410,
+ gcv420 = 0x0420,
+ gcv428 = 0x0428,
+ gcv450 = 0x0450,
+ gcv500 = 0x0500,
+ gcv520 = 0x0520,
+ gcv530 = 0x0530,
+ gcv600 = 0x0600,
+ gcv620 = 0x0620,
+ gcv700 = 0x0700,
+ gcv800 = 0x0800,
+ gcv860 = 0x0860,
+ gcv880 = 0x0880,
+ gcv900 = 0x0900,
+ gcv1000 = 0x1000,
+ gcv1500 = 0x1500,
+ gcv2000 = 0x2000,
+ gcv2100 = 0x2100,
+ gcv2200 = 0x2200,
+ gcv2500 = 0x2500,
+ gcv3000 = 0x3000,
+ gcv4000 = 0x4000,
+ gcv5000 = 0x5000,
+ gcv5200 = 0x5200,
+ gcv6400 = 0x6400,
+ gcv7000 = 0x7000,
+ gcv7400 = 0x7400,
+}
+gceCHIPMODEL;
+
+/* Chip features. */
+typedef enum _gceFEATURE
+{
+ gcvFEATURE_PIPE_2D = 0,
+ gcvFEATURE_PIPE_3D,
+ gcvFEATURE_PIPE_VG,
+ gcvFEATURE_DC,
+ gcvFEATURE_HIGH_DYNAMIC_RANGE,
+ gcvFEATURE_MODULE_CG,
+ gcvFEATURE_MIN_AREA,
+ gcvFEATURE_BUFFER_INTERLEAVING,
+ gcvFEATURE_BYTE_WRITE_2D,
+ gcvFEATURE_ENDIANNESS_CONFIG,
+ gcvFEATURE_DUAL_RETURN_BUS,
+ gcvFEATURE_DEBUG_MODE,
+ gcvFEATURE_YUY2_RENDER_TARGET,
+ gcvFEATURE_FRAGMENT_PROCESSOR,
+ gcvFEATURE_2DPE20,
+ gcvFEATURE_FAST_CLEAR,
+ gcvFEATURE_YUV420_TILER,
+ gcvFEATURE_YUY2_AVERAGING,
+ gcvFEATURE_FLIP_Y,
+ gcvFEATURE_EARLY_Z,
+ gcvFEATURE_COMPRESSION,
+ gcvFEATURE_MSAA,
+ gcvFEATURE_SPECIAL_ANTI_ALIASING,
+ gcvFEATURE_SPECIAL_MSAA_LOD,
+ gcvFEATURE_422_TEXTURE_COMPRESSION,
+ gcvFEATURE_DXT_TEXTURE_COMPRESSION,
+ gcvFEATURE_ETC1_TEXTURE_COMPRESSION,
+ gcvFEATURE_CORRECT_TEXTURE_CONVERTER,
+ gcvFEATURE_TEXTURE_8K,
+ gcvFEATURE_SCALER,
+ gcvFEATURE_YUV420_SCALER,
+ gcvFEATURE_SHADER_HAS_W,
+ gcvFEATURE_SHADER_HAS_SIGN,
+ gcvFEATURE_SHADER_HAS_FLOOR,
+ gcvFEATURE_SHADER_HAS_CEIL,
+ gcvFEATURE_SHADER_HAS_SQRT,
+ gcvFEATURE_SHADER_HAS_TRIG,
+ gcvFEATURE_HZ,
+ gcvFEATURE_CORRECT_STENCIL,
+ gcvFEATURE_VG20,
+ gcvFEATURE_VG_FILTER,
+ gcvFEATURE_VG21,
+ gcvFEATURE_VG_DOUBLE_BUFFER,
+ gcvFEATURE_MC20,
+ gcvFEATURE_SUPER_TILED,
+ gcvFEATURE_FAST_CLEAR_FLUSH,
+ gcvFEATURE_2D_FILTERBLIT_PLUS_ALPHABLEND,
+ gcvFEATURE_2D_DITHER,
+ gcvFEATURE_2D_A8_TARGET,
+ gcvFEATURE_2D_A8_NO_ALPHA,
+ gcvFEATURE_2D_FILTERBLIT_FULLROTATION,
+ gcvFEATURE_2D_BITBLIT_FULLROTATION,
+ gcvFEATURE_WIDE_LINE,
+ gcvFEATURE_FC_FLUSH_STALL,
+ gcvFEATURE_FULL_DIRECTFB,
+ gcvFEATURE_HALF_FLOAT_PIPE,
+ gcvFEATURE_LINE_LOOP,
+ gcvFEATURE_2D_YUV_BLIT,
+ gcvFEATURE_2D_TILING,
+ gcvFEATURE_NON_POWER_OF_TWO,
+ gcvFEATURE_3D_TEXTURE,
+ gcvFEATURE_TEXTURE_ARRAY,
+ gcvFEATURE_TILE_FILLER,
+ gcvFEATURE_LOGIC_OP,
+ gcvFEATURE_MIXED_STREAMS,
+ gcvFEATURE_2D_MULTI_SOURCE_BLT,
+ gcvFEATURE_END_EVENT,
+ gcvFEATURE_VERTEX_10_10_10_2,
+ gcvFEATURE_TEXTURE_10_10_10_2,
+ gcvFEATURE_TEXTURE_ANISOTROPIC_FILTERING,
+ gcvFEATURE_TEXTURE_FLOAT_HALF_FLOAT,
+ gcvFEATURE_2D_ROTATION_STALL_FIX,
+ gcvFEATURE_2D_MULTI_SOURCE_BLT_EX,
+ gcvFEATURE_BUG_FIXES10,
+ gcvFEATURE_2D_MINOR_TILING,
+ gcvFEATURE_TEX_COMPRRESSION_SUPERTILED, /* Supertiled compressed textures are supported. */
+ gcvFEATURE_FAST_MSAA,
+ gcvFEATURE_BUG_FIXED_INDEXED_TRIANGLE_STRIP,
+ gcvFEATURE_TEXTURE_TILE_STATUS_READ,
+ gcvFEATURE_DEPTH_BIAS_FIX,
+ gcvFEATURE_RECT_PRIMITIVE,
+ gcvFEATURE_BUG_FIXES11,
+ gcvFEATURE_SUPERTILED_TEXTURE,
+ gcvFEATURE_2D_NO_COLORBRUSH_INDEX8,
+ gcvFEATURE_RS_YUV_TARGET,
+ gcvFEATURE_2D_FC_SOURCE,
+ gcvFEATURE_2D_CC_NOAA_SOURCE,
+ gcvFEATURE_PE_DITHER_FIX,
+ gcvFEATURE_2D_YUV_SEPARATE_STRIDE,
+ gcvFEATURE_FRUSTUM_CLIP_FIX,
+ gcvFEATURE_TEXTURE_SWIZZLE,
+ gcvFEATURE_PRIMITIVE_RESTART,
+ gcvFEATURE_TEXTURE_LINEAR,
+ gcvFEATURE_TEXTURE_YUV_ASSEMBLER,
+ gcvFEATURE_LINEAR_RENDER_TARGET,
+ gcvFEATURE_SHADER_HAS_ATOMIC,
+ gcvFEATURE_SHADER_HAS_INSTRUCTION_CACHE,
+ gcvFEATURE_SHADER_ENHANCEMENTS2,
+ gcvFEATURE_BUG_FIXES7,
+ gcvFEATURE_SHADER_HAS_RTNE,
+ gcvFEATURE_SHADER_HAS_EXTRA_INSTRUCTIONS2,
+ gcvFEATURE_SHADER_ENHANCEMENTS3,
+ gcvFEATURE_DYNAMIC_FREQUENCY_SCALING,
+ gcvFEATURE_SINGLE_BUFFER,
+ gcvFEATURE_OCCLUSION_QUERY,
+ gcvFEATURE_2D_GAMMA,
+ gcvFEATURE_2D_COLOR_SPACE_CONVERSION,
+ gcvFEATURE_2D_SUPER_TILE_VERSION,
+ gcvFEATURE_HALTI0,
+ gcvFEATURE_HALTI1,
+ gcvFEATURE_HALTI2,
+ gcvFEATURE_SUPPORT_GCREGTX,
+ gcvFEATURE_2D_MIRROR_EXTENSION,
+ gcvFEATURE_TEXTURE_ASTC,
+ gcvFEATURE_TEXTURE_ASTC_DECODE_FIX,
+ gcvFEATURE_TEXTURE_ASTC_BASE_LOD_FIX,
+ gcvFEATURE_2D_SUPER_TILE_V1,
+ gcvFEATURE_2D_SUPER_TILE_V2,
+ gcvFEATURE_2D_SUPER_TILE_V3,
+ gcvFEATURE_2D_MULTI_SOURCE_BLT_EX2,
+ gcvFEATURE_NEW_RA,
+ gcvFEATURE_BUG_FIXED_IMPLICIT_PRIMITIVE_RESTART,
+ gcvFEATURE_PE_MULTI_RT_BLEND_ENABLE_CONTROL,
+ gcvFEATURE_SMALL_MSAA, /* An upgraded version of Fast MSAA */
+ gcvFEATURE_VERTEX_INST_ID_AS_ATTRIBUTE,
+ gcvFEATURE_DUAL_16,
+ gcvFEATURE_BRANCH_ON_IMMEDIATE_REG,
+ gcvFEATURE_2D_COMPRESSION,
+ gcvFEATURE_TPC_COMPRESSION,
+ gcvFEATURE_TPCV11_COMPRESSION,
+ gcvFEATURE_DEC_COMPRESSION,
+ gcvFEATURE_DEC300_COMPRESSION,
+ gcvFEATURE_DEC400_COMPRESSION,
+ gcvFEATURE_DEC_TPC_COMPRESSION,
+ gcvFEATURE_DEC_COMPRESSION_TILE_NV12_8BIT,
+ gcvFEATURE_DEC_COMPRESSION_TILE_NV12_10BIT,
+ gcvFEATURE_2D_OPF_YUV_OUTPUT,
+ gcvFEATURE_2D_FILTERBLIT_A8_ALPHA,
+ gcvFEATURE_2D_MULTI_SRC_BLT_TO_UNIFIED_DST_RECT,
+ gcvFEATURE_2D_MULTI_SRC_BLT_BILINEAR_FILTER,
+ gcvFEATURE_2D_MULTI_SRC_BLT_1_5_ENHANCEMENT,
+ gcvFEATURE_V2_COMPRESSION_Z16_FIX,
+ gcvFEATURE_VERTEX_INST_ID_AS_INTEGER,
+ gcvFEATURE_2D_YUV_MODE,
+ gcvFEATURE_2D_CACHE_128B256BPERLINE,
+ gcvFEATURE_2D_SEPARATE_CACHE,
+ gcvFEATURE_2D_MAJOR_SUPER_TILE,
+ gcvFEATURE_2D_V4COMPRESSION,
+ gcvFEATURE_2D_VMSAA,
+ gcvFEATURE_2D_10BIT_OUTPUT_LINEAR,
+ gcvFEATURE_2D_YUV420_OUTPUT_LINEAR,
+ gcvFEATURE_ACE,
+ gcvFEATURE_COLOR_COMPRESSION,
+ gcvFEATURE_32BPP_COMPONENT_TEXTURE_CHANNEL_SWIZZLE,
+ gcvFEATURE_64BPP_HW_CLEAR_SUPPORT,
+ gcvFEATURE_TX_LERP_PRECISION_FIX,
+ gcvFEATURE_COMPRESSION_V2,
+ gcvFEATURE_MMU,
+ gcvFEATURE_COMPRESSION_V3,
+ gcvFEATURE_TX_DECOMPRESSOR,
+ gcvFEATURE_MRT_TILE_STATUS_BUFFER,
+ gcvFEATURE_COMPRESSION_V1,
+ gcvFEATURE_V1_COMPRESSION_Z16_DECOMPRESS_FIX,
+ gcvFEATURE_RTT,
+ gcvFEATURE_GENERIC_ATTRIB,
+ gcvFEATURE_2D_ONE_PASS_FILTER,
+ gcvFEATURE_2D_ONE_PASS_FILTER_TAP,
+ gcvFEATURE_2D_POST_FLIP,
+ gcvFEATURE_2D_PIXEL_ALIGNMENT,
+ gcvFEATURE_CORRECT_AUTO_DISABLE_COUNT,
+ gcvFEATURE_CORRECT_AUTO_DISABLE_COUNT_WIDTH,
+ gcvFEATURE_8K_RT,
+ gcvFEATURE_HALTI3,
+ gcvFEATURE_EEZ,
+ gcvFEATURE_INTEGER_SIGNEXT_FIX,
+ gcvFEATURE_PSOUTPUT_MAPPING,
+ gcvFEATURE_8K_RT_FIX,
+ gcvFEATURE_TX_TILE_STATUS_MAPPING,
+ gcvFEATURE_SRGB_RT_SUPPORT,
+ gcvFEATURE_TEXTURE_16K,
+ gcvFEATURE_PA_FARZCLIPPING_FIX,
+ gcvFEATURE_PE_DITHER_COLORMASK_FIX,
+ gcvFEATURE_ZSCALE_FIX,
+ gcvFEATURE_MULTI_PIXELPIPES,
+ gcvFEATURE_PIPE_CL,
+ gcvFEATURE_BUG_FIXES18,
+ gcvFEATURE_UNIFIED_SAMPLERS,
+ gcvFEATURE_CL_PS_WALKER,
+ gcvFEATURE_NEW_HZ,
+ gcvFEATURE_TX_FRAC_PRECISION_6BIT,
+ gcvFEATURE_SH_INSTRUCTION_PREFETCH,
+ gcvFEATURE_PROBE,
+ gcvFEATURE_SINGLE_PIPE_HALTI1,
+ gcvFEATURE_BUG_FIXES8, /* This HW feature is wrong, we can't use this to check integer branch!!!*/
+ gcvFEATURE_2D_ALL_QUAD,
+ gcvFEATURE_SEPARATE_SRC_DST,
+ gcvFEATURE_TX_HOR_ALIGN_SEL,
+ gcvFEATURE_HALTI4,
+ gcvFEATURE_MRT_FC_FIX,
+ gcvFEATURE_TESSELLATION,
+ gcvFEATURE_DRAW_INDIRECT,
+ gcvFEATURE_COMPUTE_INDIRECT,
+ gcvFEATURE_MSAA_TEXTURE,
+ gcvFEATURE_STENCIL_TEXTURE,
+ gcvFEATURE_S8_ONLY_RENDERING,
+ gcvFEATURE_D24S8_SAMPLE_STENCIL,
+ gcvFEATURE_ADVANCED_BLEND_MODE_PART0,
+ gcvFEATURE_RA_DEPTH_WRITE,
+ gcvFEATURE_RS_DS_DOWNSAMPLE_NATIVE_SUPPORT,
+ gcvFEATURE_S8_MSAA_COMPRESSION,
+ gcvFEATURE_MSAA_FRAGMENT_OPERATION,
+ gcvFEATURE_FE_START_VERTEX_SUPPORT,
+ gcvFEATURE_DIVISOR_STREAM_ADDR_FIX,
+ gcvFEATURE_ZERO_ATTRIB_SUPPORT,
+ gcvFEATURE_DANGLING_VERTEX_FIX,
+ gcvFEATURE_PE_DISABLE_COLOR_PIPE,
+ gcvFEATURE_FE_12bit_stride,
+ gcvFEATURE_TX_LOD_GUARDBAND,
+ gcvFEATURE_HAS_PRODUCTID,
+ gcvFEATURE_INTEGER32_FIX,
+ gcvFEATURE_TEXTURE_GATHER,
+ gcvFEATURE_IMG_INSTRUCTION,
+ gcvFEATURE_HELPER_INVOCATION,
+ gcvFEATURE_NO_USER_CSC,
+ gcvFEATURE_ANDROID_ONLY,
+ gcvFEATURE_V2_MSAA_COHERENCY_FIX,
+ gcvFEATURE_BLOCK_SIZE_16x16,
+ gcvFEATURE_TX_SUPPORT_DEC,
+ gcvFEATURE_RSBLT_MSAA_DECOMPRESSION,
+ gcvFEATURE_TILEFILLER_32TILE_ALIGNED,
+ gcvFEATURE_GEOMETRY_SHADER,
+ gcvFEATURE_HALTI5,
+ gcvFEATURE_PIPELINE_32_ATTRIBUTES,
+ gcvFEATURE_USC,
+ gcvFEATURE_CUBEMAP_ARRAY,
+ gcvFEATURE_TX_DESCRIPTOR,
+ gcvFEATURE_SEPARATE_RT_CTRL,
+ gcvFEATURE_RENDER_ARRAY,
+ gcvFEATURE_BLT_ENGINE,
+ gcvFEATURE_SMALLDRAW_BATCH,
+ gcvFEATURE_TEXTURE_BUFFER,
+ gcvFEATURE_GS_SUPPORT_EMIT,
+ gcvFEATURE_SAMPLER_BASE_OFFSET,
+ gcvFEATURE_IMAGE_OUT_BOUNDARY_FIX,
+ gcvFEATURE_TX_BORDER_CLAMP,
+ gcvFEATURE_MSAA_SHADING,
+ gcvFEATURE_ADVANCED_SH_INST,
+ gcvFEATURE_LOD_FIX_FOR_BASELEVEL,
+ gcvFEATURE_MULTIDRAW_INDIRECT,
+ gcvFEATURE_DRAW_ELEMENTS_BASE_VERTEX,
+ gcvFEATURE_NEW_STEERING_AND_ICACHE_FLUSH, /* Steering base on register base. Trigger-style Icache flush state. */
+ gcvFEATURE_PE_DITHER_FIX2,
+ gcvFEATURE_INDEX_FETCH_FIX,
+ gcvFEATURE_TEX_BASELOD,
+ gcvFEATURE_TEX_SEAMLESS_CUBE,
+ gcvFEATURE_TEX_ETC2,
+ gcvFEATURE_TEX_CUBE_BORDER_LOD,
+ gcvFEATURE_FE_ALLOW_STALL_PREFETCH_ENG,
+ gcvFEATURE_TX_8BPP_TS_FIX,
+ gcvFEATURE_HW_TFB,
+ gcvFEATURE_COMPRESSION_V4,
+ gcvFEATURE_FENCE_32BIT,
+ gcvFEATURE_FENCE_64BIT,
+ gcvFEATURE_R8_UNORM,
+ gcvFEATURE_TX_DEFAULT_VALUE_FIX,
+ gcvFEATURE_TX_8bit_UVFrac,
+ gcvFEATURE_TX_MIPFILTER_NONE_FIX,
+ gcvFEATURE_MC_STENCIL_CTRL,
+ gcvFEATURE_DEPTH_MATH_FIX,
+ gcvFEATURE_PE_B2B_PIXEL_FIX,
+ gcvFEATURE_TEXTURE_GATHER_OFFSETS,
+ gcvFEATURE_TEX_CACHE_FLUSH_FIX,
+ gcvFEATURE_WIDELINE_HELPER_FIX,
+ gcvFEATURE_LINE_DIAMOND_RULE_FIX,
+ gcvFEATURE_MULTIGPU_SYNC_V2,
+ gcvFEATURE_DRAW_ID,
+ gcvFEATURE_SNAPPAGE_CMD,
+ gcvFEATURE_COMMAND_PREFETCH,
+ gcvFEATURE_SAMPLEPOS_SWIZZLE_FIX,
+ gcvFEATURE_SELECTMAP_SRC0_SWIZZLE_FIX,
+ gcvFEATURE_LOADATTR_OOB_FIX,
+ gcvFEATURE_RA_DEPTH_WRITE_MSAA1X_FIX,
+ gcvFEATURE_MRT_8BIT_DUAL_PIPE_FIX,
+ gcvFEATURE_BUG_FIXES1,
+ gcvFEATURE_MULTI_SOURCE_BLT,
+ gcvFEATURE_ZCOMPRESSION,
+ gcvFEATURE_DITHER_AND_FILTER_PLUS_ALPHA_2D,
+ gcvFEATURE_ONE_PASS_2D_FILTER,
+ gcvFEATURE_TX_FILTER,
+ gcvFEATURE_CHIPENABLE_LINK,
+ gcvFEATURE_TEXTURE_BIAS_LOD_FIX,
+ gcvFEATURE_USE_GL_Z,
+ gcvFEATURE_SUPPORT_INTEGER,
+ /* PARTLY_SUPPORT_INTEGER_BRANCH:
+ ** chips can support all integer types for compare instructions, e.g, CMP, SELECT.
+ ** FULLLY_SUPPORT_INTEGER_BRANCH:
+ ** chips can support all integer types for JMP instruction.
+ ** If PARTLY_SUPPORT_INTEGER_BRANCH is TRUE but FULLLY_SUPPORT_INTEGER_BRANCH is FALSE,
+ ** then this chip can only support INT32/UINT32 JMP instruction.
+ */
+ gcvFEATURE_PARTLY_SUPPORT_INTEGER_BRANCH,
+ gcvFEATURE_FULLLY_SUPPORT_INTEGER_BRANCH,
+ gcvFEATURE_SUPPORT_INTEGER_ATTRIBUTE,
+ gcvFEATURE_SUPPORT_MOVAI,
+ gcvFEATURE_NEED_FIX_FOR_CL_X,
+ gcvFEATURE_NEED_FIX_FOR_CL_XE,
+ gcvFEATURE_HAS_OUTPUT_COUNT_FIX,
+ gcvFEATURE_VARYING_PACKING_LIMITATION,
+ gcvFEATURE_HIGHP_VARYING_SHIFT,
+ gcvFEATURE_BUG_FIXES2,
+ gcvFEATURE_64K_L2_CACHE,
+ gcvFEATURE_128BTILE,
+ gcvFEATURE_ADVANCED_BLEND_OPT,
+ gcvFEATURE_SNAPPAGE_CMD_FIX,
+ gcvFEATURE_L2_CACHE_FOR_2D_420,
+ gcvFEATURE_TILE_STATUS_2BITS,
+ gcvFEATURE_EXTRA_SHADER_INSTRUCTIONS0,
+ gcvFEATURE_EXTRA_SHADER_INSTRUCTIONS1,
+ gcvFEATURE_EXTRA_SHADER_INSTRUCTIONS2,
+ gcvFEATURE_MEDIUM_PRECISION,
+ gcvFEATURE_FE20_BIT_INDEX,
+ gcvFEATURE_BUG_FIXES4,
+ gcvFEATURE_BUG_FIXES12,
+ gcvFEATURE_VMSAA,
+ gcvFEATURE_ROBUST_ATOMIC,
+ gcvFEATURE_32F_COLORMASK_FIX,
+ gcvFEATURE_NEW_GPIPE,
+ gcvFEATURE_RS_NEW_BASEADDR,
+ gcvFEATURE_TX_DXT,
+ gcvFEATURE_SH_FLAT_INTERPOLATION_DUAL16_FIX,
+ gcvFEATURE_EVIS,
+ gcvFEATURE_SH_SUPPORT_V4,
+ gcvFEATURE_SH_SUPPORT_ALPHA_KILL,
+ gcvFEATURE_PE_NO_ALPHA_TEST,
+ gcvFEATURE_SH_SNAP2PAGE_MAXPAGES_FIX,
+ gcvFEATURE_USC_FULLCACHE_FIX,
+ gcvFEATURE_PE_64bit_FENCE_FIX,
+ gcvFEATURE_BLT_8bit_256TILE_FC_FIX,
+ gcvFEATURE_PE_RGBA16I_FIX,
+ gcvFEATURE_BLT_64bpp_MASKED_CLEAR_FIX,
+ gcvFEATURE_SH_PSO_MSAA1x_FIX,
+ gcvFEATURE_USC_ATOMIC_FIX,
+ gcvFEATURE_INDEX_CONST_ON_B0,
+ gcvFEATURE_SH_NO_ONECONST_LIMIT,
+ gcvFEATURE_EVIS_NO_ABSDIFF,
+ gcvFEATURE_EVIS_NO_BITREPLACE,
+ gcvFEATURE_EVIS_NO_BOXFILTER,
+ gcvFEATURE_EVIS_NO_CORDIAC,
+ gcvFEATURE_EVIS_NO_DP32,
+ gcvFEATURE_EVIS_NO_FILTER,
+ gcvFEATURE_EVIS_NO_IADD,
+ gcvFEATURE_EVIS_NO_SELECTADD,
+ gcvFEATURE_EVIS_LERP_7OUTPUT,
+ gcvFEATURE_EVIS_ACCSQ_8OUTPUT,
+ gcvFEATURE_ROBUSTNESS,
+ gcvFEATURE_SECURITY,
+ gcvFEATURE_TX_YUV_ASSEMBLER_10BIT,
+ gcvFEATURE_USC_GOS_ADDR_FIX,
+ gcvFEATURE_SUPPORT_MSAA2X,
+ gcvFEATURE_TX_DESC_CACHE_CLOCKGATE_FIX,
+ gcvFEATURE_TX_INTEGER_COORDINATE,
+ gcvFEATURE_PSIO_SAMPLEMASK_IN_R0ZW_FIX,
+ gcvFEATURE_MULTI_CORE_BLOCK_SET_CONFIG,
+ gcvFEATURE_SH_IMG_LDST_ON_TEMP,
+ gcvFEATURE_TX_INTEGER_COORDINATE_V2,
+ gcvFEATURE_COMPUTE_ONLY,
+ gcvFEATURE_SH_IMG_LDST_CLAMP,
+ gcvFEATURE_SH_ICACHE_ALLOC_COUNT_FIX,
+ gcvFEATURE_MSAA_OQ_FIX,
+ gcvFEATURE_PE_ENHANCEMENTS2,
+ gcvFEATURE_PSIO_MSAA_CL_FIX,
+ gcvFEATURE_FE_NEED_DUMMYDRAW,
+ gcvFEATURE_MULTI_CLUSTER,
+ gcvFEATURE_PSIO_INTERLOCK,
+ gcvFEATURE_BLIT_COMPRESS_DEST,
+ gcvFEATURE_SH_MULTI_WG_PACK,
+ gcvFEATURE_FE_ROBUST_FIX,
+ gcvFEATURE_TX_ASTC_MULTISLICE_FIX,
+ gcvFEATURE_PSIO_DUAL16_32bpc_FIX,
+ gcvFEATURE_LS_SUPPORT_PER_COMP_DEPENDENCY,
+ gcvFEATURE_COMPRESSION_DEC400,
+ gcvFEATURE_SH_TEXLD_U_FIX,
+ gcvFEATURE_TX_FLUSH_L1CACHE,
+ gcvFEATURE_USC_DEFER_FILL_FIX,
+ gcvFEATURE_MC_FCCACHE_BYTEMASK,
+ gcvFEATURE_SH_MULTI_WG_PACK_FIX,
+ gcvFEATURE_FE_PATCHLIST_FETCH_FIX,
+ gcvFEATURE_RA_CG_FIX,
+ gcvFEATURE_EVIS_VX2,
+ gcvFEATURE_SH_HALF_DEPENDENCY_FIX,
+ gcvFEATURE_SH_CLOCK_GATE_FIX,
+ gcvFEATURE_GPIPE_CLOCK_GATE_FIX,
+ gcvFEATURE_TP_ENGINE,
+ gcvFEATURE_TX_BORDER_CLAMP_FIX,
+ gcvFEATURE_SH_IMAGE_LD_LAST_PIXEL_FIX,
+ gcvFEATURE_MULTI_CORE_BLOCK_SET_CONFIG2,
+ gcvFEATURE_MULTIGPU_SYNC_V3,
+ gcvFEATURE_PE_VMSAA_COVERAGE_CACHE_FIX,
+ gcvFEATURE_SECURITY_AHB,
+ gcvFEATURE_TX_LERP_LESS_BIT,
+ gcvFEATURE_VIP_V7,
+ gcvFEATURE_ASYNC_BLIT,
+ gcvFEATURE_ASYNC_FE_FENCE_FIX,
+ gcvFEATURE_PSCS_THROTTLE,
+ gcvFEATURE_WIDELINE_TRIANGLE_EMU,
+ gcvFEATURE_FENCE,
+ gcvFEATURE_PE_DEPTH_ONLY_OQFIX,
+ gcvFEATURE_VG_RESOLUTION_8K,
+ gcvFEATURE_IMAGE_LS_NO_FULLMASK_FIX,
+ gcvFEATURE_PE_TILE_CACHE_FLUSH_FIX,
+ /* Insert features above this comment only. */
+ gcvFEATURE_COUNT /* Not a feature. */
+}
+gceFEATURE;
+
+/* dummy draw type.*/
+typedef enum _gceDUMMY_DRAW_TYPE
+{
+ gcvDUMMY_DRAW_INVALID = 0,
+ gcvDUMMY_DRAW_GC400,
+ gcvDUMMY_DRAW_V60,
+}
+gceDUMMY_DRAW_TYPE;
+
+/* Chip SWWA. */
+typedef enum _gceSWWA
+{
+ gcvSWWA_601 = 0,
+ gcvSWWA_706,
+ gcvSWWA_1163,
+ gcvSWWA_1165,
+ /* Insert SWWA above this comment only. */
+ gcvSWWA_COUNT /* Not a SWWA. */
+}
+gceSWWA;
+
+
+/* Option Set*/
+typedef enum _gceOPTION
+{
+ /* HW setting. */
+ gcvOPTION_PREFER_ZCONVERT_BYPASS = 0,
+ gcvOPTION_PREFER_TILED_DISPLAY_BUFFER = 1,
+ gcvOPTION_PREFER_GUARDBAND = 2,
+ gcvOPTION_PREFER_TPG_TRIVIALMODEL = 3,
+ gcvOPTION_PREFER_RA_DEPTH_WRITE = 4,
+ gcvOPTION_PREFER_USC_RECONFIG = 5,
+ gcvOPTION_PREFER_DISALBE_HZ = 6,
+
+ /* SW options */
+ gcvOPTION_HW_NULL = 50,
+ gcvOPTION_PRINT_OPTION = 51,
+ gcvOPTION_KERNEL_FENCE = 52,
+ gcvOPTION_ASYNC_PIPE = 53,
+ gcvOPTION_FBO_PREFER_MEM = 54,
+ gcvOPTION_GPU_TEX_UPLOAD = 55,
+ gcvOPTION_GPU_BUFOBJ_UPLOAD = 56,
+ gcvOPTION_OCL_ASYNC_BLT = 57,
+ gcvOPTION_OCL_IN_THREAD = 58,
+ gcvOPTION_COMPRESSION_DEC400 = 59,
+
+ /* Insert option above this comment only */
+ gcvOPTION_COUNT /* Not a OPTION*/
+}
+gceOPTION;
+
+typedef enum _gceFRAMEINFO
+{
+ /* Total frame count in one run */
+ gcvFRAMEINFO_FRAME_NUM = 0,
+ /* Total draw count in current frame, including draw/compute */
+ gcvFRAMEINFO_DRAW_NUM = 1,
+ /* Total compute count in current frame, subset of drawNum */
+ gcvFRAMEINFO_COMPUTE_NUM = 2,
+ /* Total dual16 draw/compute count in current frame, subset of drawNum */
+ gcvFRAMEINFO_DUAL16_NUM = 3,
+ /* Current programID is being set. only valid for ES20 driver right now */
+ gcvFRAMEINFO_PROGRAM_ID = 4,
+
+ gcvFRAMEINFO_COUNT,
+}
+gceFRAMEINFO;
+
+typedef enum _gceFRAMEINFO_OP
+{
+ gcvFRAMEINFO_OP_INC = 0,
+ gcvFRAMEINFO_OP_DEC = 1,
+ gcvFRAMEINFO_OP_ZERO = 2,
+ gcvFRAMEINFO_OP_GET = 3,
+ gcvFRAMEINFO_OP_SET = 4,
+ gcvFRAMEINFO_OP_COUNT,
+}
+gceFRAMEINFO_OP;
+
+
+/* Chip Power Status. */
+typedef enum _gceCHIPPOWERSTATE
+{
+ gcvPOWER_ON = 0,
+ gcvPOWER_OFF,
+ gcvPOWER_IDLE,
+ gcvPOWER_SUSPEND,
+ gcvPOWER_IDLE_BROADCAST,
+ gcvPOWER_SUSPEND_BROADCAST,
+ gcvPOWER_OFF_BROADCAST,
+ gcvPOWER_OFF_TIMEOUT,
+ gcvPOWER_ON_AUTO
+}
+gceCHIPPOWERSTATE;
+
+/* CPU cache operations */
+typedef enum _gceCACHEOPERATION
+{
+ gcvCACHE_CLEAN = 0x01, /* Flush CPU cache to mem */
+ gcvCACHE_INVALIDATE = 0x02, /* Invalidte CPU cache */
+ gcvCACHE_FLUSH = gcvCACHE_CLEAN | gcvCACHE_INVALIDATE, /* Both flush & invalidate */
+ gcvCACHE_MEMORY_BARRIER = 0x04
+}
+gceCACHEOPERATION;
+
+/* Surface types. */
+typedef enum _gceSURF_TYPE
+{
+ gcvSURF_TYPE_UNKNOWN = 0,
+ gcvSURF_INDEX,
+ gcvSURF_VERTEX,
+ gcvSURF_TEXTURE,
+ gcvSURF_RENDER_TARGET,
+ gcvSURF_DEPTH,
+ gcvSURF_BITMAP,
+ gcvSURF_TILE_STATUS,
+ gcvSURF_IMAGE,
+ gcvSURF_MASK,
+ gcvSURF_SCISSOR,
+ gcvSURF_HIERARCHICAL_DEPTH,
+ gcvSURF_ICACHE,
+ gcvSURF_TXDESC,
+ gcvSURF_FENCE,
+ gcvSURF_TFBHEADER,
+ gcvSURF_NUM_TYPES, /* Make sure this is the last one! */
+
+ /* Combinations. */
+ gcvSURF_NO_TILE_STATUS = 0x100,
+ gcvSURF_NO_VIDMEM = 0x200, /* Used to allocate surfaces with no underlying vidmem node.
+ In Android, vidmem node is allocated by another process. */
+ gcvSURF_CACHEABLE = 0x400, /* Used to allocate a cacheable surface */
+ gcvSURF_TILE_RLV_FENCE = 0x800, /* create texture fence as tile */
+ gcvSURF_TILE_STATUS_DIRTY = 0x1000, /* Init tile status to all dirty */
+ gcvSURF_LINEAR = 0x2000,
+ gcvSURF_CREATE_AS_TEXTURE = 0x4000, /* create it as a texture */
+ gcvSURF_PROTECTED_CONTENT = 0x8000, /* create it as content protected */
+ gcvSURF_CREATE_AS_DISPLAYBUFFER = 0x10000, /*create it as a display buffer surface */
+ gcvSURF_CONTIGUOUS = 0x20000, /*create it as contiguous */
+ gcvSURF_NO_COMPRESSION = 0x40000, /* Create it as no compression, valid on when it has tile status. */
+ gcvSURF_DEC = 0x80000, /* Surface is DEC compressed */
+ gcvSURF_NO_HZ = 0x100000,
+ gcvSURF_3D = 0x200000, /* It's 3d surface */
+ gcvSURF_DMABUF_EXPORTABLE = 0x400000, /* master node can be exported as dma-buf fd */
+ gcvSURF_CMA_LIMIT = 0x800000,
+
+ gcvSURF_TEXTURE_LINEAR = gcvSURF_TEXTURE
+ | gcvSURF_LINEAR,
+
+ gcvSURF_RENDER_TARGET_LINEAR = gcvSURF_RENDER_TARGET
+ | gcvSURF_LINEAR,
+
+ gcvSURF_RENDER_TARGET_NO_TILE_STATUS = gcvSURF_RENDER_TARGET
+ | gcvSURF_NO_TILE_STATUS,
+
+ gcvSURF_RENDER_TARGET_NO_COMPRESSION = gcvSURF_RENDER_TARGET
+ | gcvSURF_NO_COMPRESSION,
+
+ gcvSURF_RENDER_TARGET_TS_DIRTY = gcvSURF_RENDER_TARGET
+ | gcvSURF_TILE_STATUS_DIRTY,
+
+ gcvSURF_DEPTH_NO_TILE_STATUS = gcvSURF_DEPTH
+ | gcvSURF_NO_TILE_STATUS,
+
+ gcvSURF_DEPTH_TS_DIRTY = gcvSURF_DEPTH
+ | gcvSURF_TILE_STATUS_DIRTY,
+
+ /* Supported surface types with no vidmem node. */
+ gcvSURF_BITMAP_NO_VIDMEM = gcvSURF_BITMAP
+ | gcvSURF_NO_VIDMEM,
+
+ gcvSURF_TEXTURE_NO_VIDMEM = gcvSURF_TEXTURE
+ | gcvSURF_NO_VIDMEM,
+
+ /* Cacheable surface types with no vidmem node. */
+ gcvSURF_CACHEABLE_BITMAP_NO_VIDMEM = gcvSURF_BITMAP_NO_VIDMEM
+ | gcvSURF_CACHEABLE,
+
+ gcvSURF_CACHEABLE_BITMAP = gcvSURF_BITMAP
+ | gcvSURF_CACHEABLE,
+
+ gcvSURF_TEXTURE_3D = gcvSURF_TEXTURE
+ | gcvSURF_3D
+}
+gceSURF_TYPE;
+
+typedef enum _gceSURF_USAGE
+{
+ gcvSURF_USAGE_UNKNOWN,
+ gcvSURF_USAGE_RESOLVE_AFTER_CPU,
+ gcvSURF_USAGE_RESOLVE_AFTER_3D
+}
+gceSURF_USAGE;
+
+typedef enum _gceSURF_COLOR_SPACE
+{
+ gcvSURF_COLOR_SPACE_UNKNOWN,
+ gcvSURF_COLOR_SPACE_LINEAR,
+ gcvSURF_COLOR_SPACE_NONLINEAR,
+}
+gceSURF_COLOR_SPACE;
+
+typedef enum _gceSURF_COLOR_TYPE
+{
+ gcvSURF_COLOR_UNKNOWN = 0,
+ gcvSURF_COLOR_LINEAR = 0x01,
+ gcvSURF_COLOR_ALPHA_PRE = 0x02,
+}
+gceSURF_COLOR_TYPE;
+
+/* Rotation. */
+typedef enum _gceSURF_ROTATION
+{
+ gcvSURF_0_DEGREE = 0,
+ gcvSURF_90_DEGREE,
+ gcvSURF_180_DEGREE,
+ gcvSURF_270_DEGREE,
+ gcvSURF_FLIP_X,
+ gcvSURF_FLIP_Y,
+
+ gcvSURF_POST_FLIP_X = 0x40000000,
+ gcvSURF_POST_FLIP_Y = 0x80000000,
+}
+gceSURF_ROTATION;
+
+/* Surface flag */
+typedef enum _gceSURF_FLAG
+{
+ /* None flag */
+ gcvSURF_FLAG_NONE = 0x0,
+ /* content is preserved after swap */
+ gcvSURF_FLAG_CONTENT_PRESERVED = 0x1,
+ /* content is updated after swap*/
+ gcvSURF_FLAG_CONTENT_UPDATED = 0x2,
+ /* content is y inverted */
+ gcvSURF_FLAG_CONTENT_YINVERTED = 0x4,
+ /* surface has multiple nodes */
+ gcvSURF_FLAG_MULTI_NODE = 0x8,
+}
+gceSURF_FLAG;
+
+typedef enum _gceMIPMAP_IMAGE_FORMAT
+{
+ gcvUNKNOWN_MIPMAP_IMAGE_FORMAT = -2
+}
+gceMIPMAP_IMAGE_FORMAT;
+
+/* Surface formats.
+** Name rules is from MSB->LSB.
+*/
+typedef enum _gceSURF_FORMAT
+{
+ /* Unknown format. */
+ gcvSURF_UNKNOWN = 0,
+
+ /* Palettized formats. */
+ gcvSURF_INDEX1 = 100,
+ gcvSURF_INDEX4,
+ gcvSURF_INDEX8,
+#if gcdVG_ONLY
+ gcvSURF_INDEX2,
+#endif
+
+ /* RGB formats. */
+ gcvSURF_A2R2G2B2 = 200,
+ gcvSURF_R3G3B2,
+ gcvSURF_A8R3G3B2,
+ gcvSURF_X4R4G4B4,
+ gcvSURF_A4R4G4B4,
+ gcvSURF_R4G4B4A4,
+ gcvSURF_X1R5G5B5,
+ gcvSURF_A1R5G5B5,
+ gcvSURF_R5G5B5A1,
+ gcvSURF_R5G6B5,
+ gcvSURF_R8G8B8,
+ gcvSURF_X8R8G8B8,
+ gcvSURF_A8R8G8B8,
+ gcvSURF_R8G8B8A8,
+ gcvSURF_G8R8G8B8,
+ gcvSURF_R8G8B8G8,
+ gcvSURF_X2R10G10B10,
+ gcvSURF_A2R10G10B10,
+ gcvSURF_R10G10B10A2,
+ gcvSURF_X12R12G12B12,
+ gcvSURF_A12R12G12B12,
+ gcvSURF_X16R16G16B16,
+ gcvSURF_A16R16G16B16,
+ gcvSURF_A32R32G32B32,
+ gcvSURF_R8G8B8X8,
+ gcvSURF_R5G5B5X1,
+ gcvSURF_R4G4B4X4,
+ gcvSURF_X16R16G16B16_2_A8R8G8B8,
+ gcvSURF_A16R16G16B16_2_A8R8G8B8,
+ gcvSURF_A32R32G32B32_2_G32R32F,
+ gcvSURF_A32R32G32B32_4_A8R8G8B8,
+ /* BGR formats. */
+ gcvSURF_A4B4G4R4 = 300,
+ gcvSURF_A1B5G5R5,
+ gcvSURF_B5G6R5,
+ gcvSURF_B8G8R8,
+ gcvSURF_B16G16R16,
+ gcvSURF_X8B8G8R8,
+ gcvSURF_A8B8G8R8,
+ gcvSURF_A2B10G10R10,
+ gcvSURF_X16B16G16R16,
+ gcvSURF_A16B16G16R16,
+ gcvSURF_B32G32R32,
+ gcvSURF_X32B32G32R32,
+ gcvSURF_A32B32G32R32,
+ gcvSURF_B4G4R4A4,
+ gcvSURF_B5G5R5A1,
+ gcvSURF_B8G8R8X8,
+ gcvSURF_B8G8R8A8,
+ gcvSURF_B10G10R10A2,
+ gcvSURF_X4B4G4R4,
+ gcvSURF_X1B5G5R5,
+ gcvSURF_B4G4R4X4,
+ gcvSURF_B5G5R5X1,
+ gcvSURF_X2B10G10R10,
+ gcvSURF_B8G8R8_SNORM,
+ gcvSURF_X8B8G8R8_SNORM,
+ gcvSURF_A8B8G8R8_SNORM,
+ gcvSURF_A8B12G12R12_2_A8R8G8B8,
+
+ /* Compressed formats. */
+ gcvSURF_DXT1 = 400,
+ gcvSURF_DXT2,
+ gcvSURF_DXT3,
+ gcvSURF_DXT4,
+ gcvSURF_DXT5,
+ gcvSURF_CXV8U8,
+ gcvSURF_ETC1,
+ gcvSURF_R11_EAC,
+ gcvSURF_SIGNED_R11_EAC,
+ gcvSURF_RG11_EAC,
+ gcvSURF_SIGNED_RG11_EAC,
+ gcvSURF_RGB8_ETC2,
+ gcvSURF_SRGB8_ETC2,
+ gcvSURF_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
+ gcvSURF_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
+ gcvSURF_RGBA8_ETC2_EAC,
+ gcvSURF_SRGB8_ALPHA8_ETC2_EAC,
+
+ /* YUV formats. */
+ gcvSURF_YUY2 = 500,
+ gcvSURF_UYVY,
+ gcvSURF_YV12,
+ gcvSURF_I420,
+ gcvSURF_NV12,
+ gcvSURF_NV21,
+ gcvSURF_NV16,
+ gcvSURF_NV61,
+ gcvSURF_YVYU,
+ gcvSURF_VYUY,
+ gcvSURF_AYUV,
+ gcvSURF_YUV420_10_ST,
+ gcvSURF_YUV420_TILE_ST,
+ gcvSURF_YUV420_TILE_10_ST,
+ gcvSURF_NV12_10BIT,
+ gcvSURF_NV21_10BIT,
+ gcvSURF_NV16_10BIT,
+ gcvSURF_NV61_10BIT,
+ gcvSURF_P010,
+#if gcdVG_ONLY
+ gcvSURF_AYUY2,
+ gcvSURF_ANV12,
+ gcvSURF_ANV16,
+#endif
+
+ /* Depth formats. */
+ gcvSURF_D16 = 600,
+ gcvSURF_D24S8,
+ gcvSURF_D32,
+ gcvSURF_D24X8,
+ gcvSURF_D32F,
+ gcvSURF_S8D32F,
+ gcvSURF_S8D32F_1_G32R32F,
+ gcvSURF_S8D32F_2_A8R8G8B8,
+ gcvSURF_D24S8_1_A8R8G8B8,
+ gcvSURF_S8,
+ gcvSURF_X24S8,
+ gcvSURF_X24S8_1_A8R8G8B8,
+
+ /* Alpha formats. */
+ gcvSURF_A4 = 700,
+ gcvSURF_A8,
+ gcvSURF_A12,
+ gcvSURF_A16,
+ gcvSURF_A32,
+ gcvSURF_A1,
+
+ gcvSURF_A8_1_A8R8G8B8,
+
+ /* Luminance formats. */
+ gcvSURF_L4 = 800,
+ gcvSURF_L8,
+ gcvSURF_L12,
+ gcvSURF_L16,
+ gcvSURF_L32,
+ gcvSURF_L1,
+
+ /* Alpha/Luminance formats. */
+ gcvSURF_A4L4 = 900,
+ gcvSURF_A2L6,
+ gcvSURF_A8L8,
+ gcvSURF_A4L12,
+ gcvSURF_A12L12,
+ gcvSURF_A16L16,
+
+ /* Bump formats. */
+ gcvSURF_L6V5U5 = 1000,
+ gcvSURF_V8U8,
+ gcvSURF_X8L8V8U8,
+ gcvSURF_Q8W8V8U8,
+ gcvSURF_A2W10V10U10,
+ gcvSURF_V16U16,
+ gcvSURF_Q16W16V16U16,
+
+ /* R/RG/RA formats. */
+ gcvSURF_R8 = 1100,
+ gcvSURF_X8R8,
+ gcvSURF_G8R8,
+ gcvSURF_X8G8R8,
+ gcvSURF_A8R8,
+ gcvSURF_R16,
+ gcvSURF_X16R16,
+ gcvSURF_G16R16,
+ gcvSURF_X16G16R16,
+ gcvSURF_A16R16,
+ gcvSURF_R32,
+ gcvSURF_X32R32,
+ gcvSURF_G32R32,
+ gcvSURF_X32G32R32,
+ gcvSURF_A32R32,
+ gcvSURF_RG16,
+ gcvSURF_R8_SNORM,
+ gcvSURF_G8R8_SNORM,
+
+ gcvSURF_R8_1_X8R8G8B8,
+ gcvSURF_G8R8_1_X8R8G8B8,
+
+ /* Floating point formats. */
+ gcvSURF_R16F = 1200,
+ gcvSURF_X16R16F,
+ gcvSURF_G16R16F,
+ gcvSURF_X16G16R16F,
+ gcvSURF_B16G16R16F,
+ gcvSURF_X16B16G16R16F,
+ gcvSURF_A16B16G16R16F,
+ gcvSURF_R32F,
+ gcvSURF_X32R32F,
+ gcvSURF_G32R32F,
+ gcvSURF_X32G32R32F,
+ gcvSURF_B32G32R32F,
+ gcvSURF_X32B32G32R32F,
+ gcvSURF_A32B32G32R32F,
+ gcvSURF_A16F,
+ gcvSURF_L16F,
+ gcvSURF_A16L16F,
+ gcvSURF_A16R16F,
+ gcvSURF_A32F,
+ gcvSURF_L32F,
+ gcvSURF_A32L32F,
+ gcvSURF_A32R32F,
+ gcvSURF_E5B9G9R9,
+ gcvSURF_B10G11R11F,
+
+ gcvSURF_X16B16G16R16F_2_A8R8G8B8,
+ gcvSURF_A16B16G16R16F_2_A8R8G8B8,
+ gcvSURF_A16B16G16R16F_2_G16R16F,
+ gcvSURF_G32R32F_2_A8R8G8B8,
+ gcvSURF_X32B32G32R32F_2_G32R32F,
+ gcvSURF_A32B32G32R32F_2_G32R32F,
+ gcvSURF_X32B32G32R32F_4_A8R8G8B8,
+ gcvSURF_A32B32G32R32F_4_A8R8G8B8,
+
+ gcvSURF_R16F_1_A4R4G4B4,
+ gcvSURF_G16R16F_1_A8R8G8B8,
+ gcvSURF_B16G16R16F_2_A8R8G8B8,
+
+ gcvSURF_R32F_1_A8R8G8B8,
+ gcvSURF_B32G32R32F_3_A8R8G8B8,
+ gcvSURF_B10G11R11F_1_A8R8G8B8,
+
+ gcvSURF_A32F_1_R32F,
+ gcvSURF_L32F_1_R32F,
+ gcvSURF_A32L32F_1_G32R32F,
+
+
+
+ /* sRGB format. */
+ gcvSURF_SBGR8 = 1400,
+ gcvSURF_A8_SBGR8,
+ gcvSURF_X8_SBGR8,
+ gcvSURF_A8_SRGB8,
+ gcvSURF_X8_SRGB8,
+
+ /* Integer formats. */
+ gcvSURF_R8I = 1500,
+ gcvSURF_R8UI,
+ gcvSURF_R16I,
+ gcvSURF_R16UI,
+ gcvSURF_R32I,
+ gcvSURF_R32UI,
+ gcvSURF_X8R8I,
+ gcvSURF_G8R8I,
+ gcvSURF_X8R8UI,
+ gcvSURF_G8R8UI,
+ gcvSURF_X16R16I,
+ gcvSURF_G16R16I,
+ gcvSURF_X16R16UI,
+ gcvSURF_G16R16UI,
+ gcvSURF_X32R32I,
+ gcvSURF_G32R32I,
+ gcvSURF_X32R32UI,
+ gcvSURF_G32R32UI,
+ gcvSURF_X8G8R8I,
+ gcvSURF_B8G8R8I,
+ gcvSURF_X8G8R8UI,
+ gcvSURF_B8G8R8UI,
+ gcvSURF_X16G16R16I,
+ gcvSURF_B16G16R16I,
+ gcvSURF_X16G16R16UI,
+ gcvSURF_B16G16R16UI,
+ gcvSURF_X32G32R32I,
+ gcvSURF_B32G32R32I,
+ gcvSURF_X32G32R32UI,
+ gcvSURF_B32G32R32UI,
+ gcvSURF_X8B8G8R8I,
+ gcvSURF_A8B8G8R8I,
+ gcvSURF_X8B8G8R8UI,
+ gcvSURF_A8B8G8R8UI,
+ gcvSURF_X16B16G16R16I,
+ gcvSURF_A16B16G16R16I,
+ gcvSURF_X16B16G16R16UI,
+ gcvSURF_A16B16G16R16UI,
+ gcvSURF_X32B32G32R32I,
+ gcvSURF_A32B32G32R32I,
+ gcvSURF_X32B32G32R32UI,
+ gcvSURF_A32B32G32R32UI,
+ gcvSURF_A2B10G10R10UI,
+ gcvSURF_G32R32I_2_A8R8G8B8,
+ gcvSURF_G32R32I_1_G32R32F,
+ gcvSURF_G32R32UI_2_A8R8G8B8,
+ gcvSURF_G32R32UI_1_G32R32F,
+ gcvSURF_X16B16G16R16I_2_A8R8G8B8,
+ gcvSURF_X16B16G16R16I_1_G32R32F,
+ gcvSURF_A16B16G16R16I_2_A8R8G8B8,
+ gcvSURF_A16B16G16R16I_1_G32R32F,
+ gcvSURF_X16B16G16R16UI_2_A8R8G8B8,
+ gcvSURF_X16B16G16R16UI_1_G32R32F,
+ gcvSURF_A16B16G16R16UI_2_A8R8G8B8,
+ gcvSURF_A16B16G16R16UI_1_G32R32F,
+ gcvSURF_X32B32G32R32I_2_G32R32I,
+ gcvSURF_A32B32G32R32I_2_G32R32I,
+ gcvSURF_A32B32G32R32I_2_G32R32F,
+ gcvSURF_X32B32G32R32I_3_A8R8G8B8,
+ gcvSURF_A32B32G32R32I_4_A8R8G8B8,
+ gcvSURF_X32B32G32R32UI_2_G32R32UI,
+ gcvSURF_A32B32G32R32UI_2_G32R32UI,
+ gcvSURF_A32B32G32R32UI_2_G32R32F,
+ gcvSURF_X32B32G32R32UI_3_A8R8G8B8,
+ gcvSURF_A32B32G32R32UI_4_A8R8G8B8,
+ gcvSURF_A2B10G10R10UI_1_A8R8G8B8,
+ gcvSURF_A8B8G8R8I_1_A8R8G8B8,
+ gcvSURF_A8B8G8R8UI_1_A8R8G8B8,
+ gcvSURF_R8I_1_A4R4G4B4,
+ gcvSURF_R8UI_1_A4R4G4B4,
+ gcvSURF_R16I_1_A4R4G4B4,
+ gcvSURF_R16UI_1_A4R4G4B4,
+ gcvSURF_R32I_1_A8R8G8B8,
+ gcvSURF_R32UI_1_A8R8G8B8,
+ gcvSURF_X8R8I_1_A4R4G4B4,
+ gcvSURF_X8R8UI_1_A4R4G4B4,
+ gcvSURF_G8R8I_1_A4R4G4B4,
+ gcvSURF_G8R8UI_1_A4R4G4B4,
+ gcvSURF_X16R16I_1_A4R4G4B4,
+ gcvSURF_X16R16UI_1_A4R4G4B4,
+ gcvSURF_G16R16I_1_A8R8G8B8,
+ gcvSURF_G16R16UI_1_A8R8G8B8,
+ gcvSURF_X32R32I_1_A8R8G8B8,
+ gcvSURF_X32R32UI_1_A8R8G8B8,
+ gcvSURF_X8G8R8I_1_A4R4G4B4,
+ gcvSURF_X8G8R8UI_1_A4R4G4B4,
+ gcvSURF_B8G8R8I_1_A8R8G8B8,
+ gcvSURF_B8G8R8UI_1_A8R8G8B8,
+ gcvSURF_B16G16R16I_2_A8R8G8B8,
+ gcvSURF_B16G16R16I_1_G32R32F,
+ gcvSURF_B16G16R16UI_2_A8R8G8B8,
+ gcvSURF_B16G16R16UI_1_G32R32F,
+ gcvSURF_B32G32R32I_3_A8R8G8B8,
+ gcvSURF_B32G32R32UI_3_A8R8G8B8,
+ gcvSURF_A16B16G16R16_2_A8R8G8B8,
+ gcvSURF_R8G8B8_1_A8R8G8B8,
+ gcvSURF_G16R16_1_A8R8G8B8,
+ gcvSURF_A2B10G10R10_1_A8R8G8B8,
+ gcvSURF_A2R10G10B10_1_A8R8G8B8,
+ gcvSURF_A2W10V10U10_1_A8R8G8B8,
+
+ /* ASTC formats. */
+ gcvSURF_ASTC4x4 = 1600,
+ gcvSURF_ASTC5x4,
+ gcvSURF_ASTC5x5,
+ gcvSURF_ASTC6x5,
+ gcvSURF_ASTC6x6,
+ gcvSURF_ASTC8x5,
+ gcvSURF_ASTC8x6,
+ gcvSURF_ASTC8x8,
+ gcvSURF_ASTC10x5,
+ gcvSURF_ASTC10x6,
+ gcvSURF_ASTC10x8,
+ gcvSURF_ASTC10x10,
+ gcvSURF_ASTC12x10,
+ gcvSURF_ASTC12x12,
+ gcvSURF_ASTC4x4_SRGB,
+ gcvSURF_ASTC5x4_SRGB,
+ gcvSURF_ASTC5x5_SRGB,
+ gcvSURF_ASTC6x5_SRGB,
+ gcvSURF_ASTC6x6_SRGB,
+ gcvSURF_ASTC8x5_SRGB,
+ gcvSURF_ASTC8x6_SRGB,
+ gcvSURF_ASTC8x8_SRGB,
+ gcvSURF_ASTC10x5_SRGB,
+ gcvSURF_ASTC10x6_SRGB,
+ gcvSURF_ASTC10x8_SRGB,
+ gcvSURF_ASTC10x10_SRGB,
+ gcvSURF_ASTC12x10_SRGB,
+ gcvSURF_ASTC12x12_SRGB,
+
+ /* Recompile format*/
+ gcvSURF_L16_1_A4R4G4B4 = 1700,
+ gcvSURF_V16U16_1_A8R8G8B8,
+ gcvSURF_Q8W8V8U8_1_A8R8G8B8,
+ gcvSURF_X8L8V8U8_1_A8R8G8B8,
+ gcvSURF_R3G3B2_1_A8R8G8B8,
+ gcvSURF_A8R3G3B2_1_A8R8G8B8,
+ gcvSURF_W11V11U10_1_A8R8G8B8,
+ gcvSURF_Q16W16V16U16_2_A8R8G8B8,
+ gcvSURF_W11V11U10,
+ gcvSURF_V8U8_1_A4R4G4B4,
+ gcvSURF_A8B8G8R8_1_A8R8G8B8,
+ gcvSURF_A32R32G32B32_1_A8R8G8B8,
+ gcvSURF_X16B16G16R16F_1_A8R8G8B8,
+ gcvSURF_A16B16G16R16F_1_A8R8G8B8,
+ gcvSURF_G32R32F_1_A8R8G8B8,
+ gcvSURF_X32B32G32R32F_1_A8R8G8B8,
+ gcvSURF_A32B32G32R32F_1_A8R8G8B8,
+ gcvSURF_G32R32I_1_A8R8G8B8,
+ gcvSURF_G32R32UI_1_A8R8G8B8,
+ gcvSURF_A32B32G32R32I_1_A8R8G8B8,
+ gcvSURF_A32B32G32R32UI_1_A8R8G8B8,
+ gcvSURF_Q16W16V16U16_1_A8R8G8B8,
+ gcvSURF_A16B16G16R16_1_A8R8G8B8,
+ gcvSURF_FORMAT_COUNT
+}
+gceSURF_FORMAT;
+
+typedef enum _gceIMAGE_MEM_TYPE
+{
+ gcvIMAGE_MEM_DEFAULT,
+ gcvIMAGE_MEM_HOST_PTR,
+ gcvIMAGE_MEM_HOST_PTR_UNCACHED,
+}
+gceIMAGE_MEM_TYPE;
+
+typedef enum _gceSURF_YUV_COLOR_SPACE
+{
+ gcvSURF_ITU_REC601,
+ gcvSURF_ITU_REC709,
+ gcvSURF_ITU_REC2020,
+}
+gceSURF_YUV_COLOR_SPACE;
+
+typedef enum _gceSURF_YUV_SAMPLE_RANGE
+{
+ gcvSURF_YUV_FULL_RANGE,
+ gcvSURF_YUV_NARROW_RANGE,
+}
+gceSURF_YUV_SAMPLE_RANGE;
+
+typedef enum _gceSURF_YUV_CHROMA_SITING
+{
+ gcvSURF_YUV_CHROMA_SITING_0,
+ gcvSURF_YUV_CHROMA_SITING_0_5,
+}
+gceSURF_YUV_CHROMA_SITING;
+
+typedef enum _gceSURF_INFO_TYPE
+{
+ gcvSURF_INFO_UNKNOWN = 0,
+ gcvSURF_INFO_LAYERSIZE = 1,
+ gcvSURF_INFO_SLICESIZE = 2,
+}
+gceSURF_INFO_TYPE;
+
+/* Format modifiers. */
+typedef enum _gceSURF_FORMAT_MODE
+{
+ gcvSURF_FORMAT_OCL = 0x80000000,
+ gcvSURF_FORMAT_PATCH_BORDER = 0x40000000,
+}
+gceSURF_FORMAT_MODE;
+
+/* Pixel swizzle modes. */
+typedef enum _gceSURF_SWIZZLE
+{
+ gcvSURF_NOSWIZZLE = 0,
+ gcvSURF_ARGB,
+ gcvSURF_ABGR,
+ gcvSURF_RGBA,
+ gcvSURF_BGRA
+}
+gceSURF_SWIZZLE;
+
+/* Transparency modes. */
+typedef enum _gceSURF_TRANSPARENCY
+{
+ /* Valid only for PE 1.0 */
+ gcvSURF_OPAQUE = 0,
+ gcvSURF_SOURCE_MATCH,
+ gcvSURF_SOURCE_MASK,
+ gcvSURF_PATTERN_MASK,
+}
+gceSURF_TRANSPARENCY;
+
+/* Surface Alignment. */
+typedef enum _gceSURF_ALIGNMENT
+{
+ gcvSURF_FOUR = 0,
+ gcvSURF_SIXTEEN,
+ gcvSURF_SUPER_TILED,
+ gcvSURF_SPLIT_TILED,
+ gcvSURF_SPLIT_SUPER_TILED
+}
+gceSURF_ALIGNMENT;
+
+/* Surface Addressing. */
+typedef enum _gceSURF_ADDRESSING
+{
+ gcvSURF_NO_STRIDE_TILED = 0,
+ gcvSURF_NO_STRIDE_LINEAR,
+ gcvSURF_STRIDE_TILED,
+ gcvSURF_STRIDE_LINEAR
+}
+gceSURF_ADDRESSING;
+
+/* Transparency modes. */
+typedef enum _gce2D_TRANSPARENCY
+{
+ /* Valid only for PE 2.0 */
+ gcv2D_OPAQUE = 0,
+ gcv2D_KEYED,
+ gcv2D_MASKED
+}
+gce2D_TRANSPARENCY;
+
+/* Mono packing modes. */
+typedef enum _gceSURF_MONOPACK
+{
+ gcvSURF_PACKED8 = 0,
+ gcvSURF_PACKED16,
+ gcvSURF_PACKED32,
+ gcvSURF_UNPACKED,
+}
+gceSURF_MONOPACK;
+
+/* Blending modes. */
+typedef enum _gceSURF_BLEND_MODE
+{
+ /* Porter-Duff blending modes. */
+ /* Fsrc Fdst */
+ gcvBLEND_CLEAR = 0, /* 0 0 */
+ gcvBLEND_SRC, /* 1 0 */
+ gcvBLEND_DST, /* 0 1 */
+ gcvBLEND_SRC_OVER_DST, /* 1 1 - Asrc */
+ gcvBLEND_DST_OVER_SRC, /* 1 - Adst 1 */
+ gcvBLEND_SRC_IN_DST, /* Adst 0 */
+ gcvBLEND_DST_IN_SRC, /* 0 Asrc */
+ gcvBLEND_SRC_OUT_DST, /* 1 - Adst 0 */
+ gcvBLEND_DST_OUT_SRC, /* 0 1 - Asrc */
+ gcvBLEND_SRC_ATOP_DST, /* Adst 1 - Asrc */
+ gcvBLEND_DST_ATOP_SRC, /* 1 - Adst Asrc */
+ gcvBLEND_SRC_XOR_DST, /* 1 - Adst 1 - Asrc */
+
+ /* Special blending modes. */
+ gcvBLEND_SET, /* DST = 1 */
+ gcvBLEND_SUB /* DST = DST * (1 - SRC) */
+}
+gceSURF_BLEND_MODE;
+
+/* Per-pixel alpha modes. */
+typedef enum _gceSURF_PIXEL_ALPHA_MODE
+{
+ gcvSURF_PIXEL_ALPHA_STRAIGHT = 0,
+ gcvSURF_PIXEL_ALPHA_INVERSED
+}
+gceSURF_PIXEL_ALPHA_MODE;
+
+/* Global alpha modes. */
+typedef enum _gceSURF_GLOBAL_ALPHA_MODE
+{
+ gcvSURF_GLOBAL_ALPHA_OFF = 0,
+ gcvSURF_GLOBAL_ALPHA_ON,
+ gcvSURF_GLOBAL_ALPHA_SCALE
+}
+gceSURF_GLOBAL_ALPHA_MODE;
+
+/* Color component modes for alpha blending. */
+typedef enum _gceSURF_PIXEL_COLOR_MODE
+{
+ gcvSURF_COLOR_STRAIGHT = 0,
+ gcvSURF_COLOR_MULTIPLY
+}
+gceSURF_PIXEL_COLOR_MODE;
+
+/* Color component modes for alpha blending. */
+typedef enum _gce2D_PIXEL_COLOR_MULTIPLY_MODE
+{
+ gcv2D_COLOR_MULTIPLY_DISABLE = 0,
+ gcv2D_COLOR_MULTIPLY_ENABLE
+}
+gce2D_PIXEL_COLOR_MULTIPLY_MODE;
+
+/* Color component modes for alpha blending. */
+typedef enum _gce2D_GLOBAL_COLOR_MULTIPLY_MODE
+{
+ gcv2D_GLOBAL_COLOR_MULTIPLY_DISABLE = 0,
+ gcv2D_GLOBAL_COLOR_MULTIPLY_ALPHA,
+ gcv2D_GLOBAL_COLOR_MULTIPLY_COLOR
+}
+gce2D_GLOBAL_COLOR_MULTIPLY_MODE;
+
+/* Alpha blending factor modes. */
+typedef enum _gceSURF_BLEND_FACTOR_MODE
+{
+ gcvSURF_BLEND_ZERO = 0,
+ gcvSURF_BLEND_ONE,
+ gcvSURF_BLEND_STRAIGHT,
+ gcvSURF_BLEND_INVERSED,
+ gcvSURF_BLEND_COLOR,
+ gcvSURF_BLEND_COLOR_INVERSED,
+ gcvSURF_BLEND_SRC_ALPHA_SATURATED,
+ gcvSURF_BLEND_STRAIGHT_NO_CROSS,
+ gcvSURF_BLEND_INVERSED_NO_CROSS,
+ gcvSURF_BLEND_COLOR_NO_CROSS,
+ gcvSURF_BLEND_COLOR_INVERSED_NO_CROSS,
+ gcvSURF_BLEND_SRC_ALPHA_SATURATED_CROSS
+}
+gceSURF_BLEND_FACTOR_MODE;
+
+/* Alpha blending porter duff rules. */
+typedef enum _gce2D_PORTER_DUFF_RULE
+{
+ gcvPD_CLEAR = 0,
+ gcvPD_SRC,
+ gcvPD_SRC_OVER,
+ gcvPD_DST_OVER,
+ gcvPD_SRC_IN,
+ gcvPD_DST_IN,
+ gcvPD_SRC_OUT,
+ gcvPD_DST_OUT,
+ gcvPD_SRC_ATOP,
+ gcvPD_DST_ATOP,
+ gcvPD_ADD,
+ gcvPD_XOR,
+ gcvPD_DST
+}
+gce2D_PORTER_DUFF_RULE;
+
+/* Alpha blending factor modes. */
+typedef enum _gce2D_YUV_COLOR_MODE
+{
+ gcv2D_YUV_601= 0,
+ gcv2D_YUV_709,
+ gcv2D_YUV_USER_DEFINED,
+ gcv2D_YUV_USER_DEFINED_CLAMP,
+
+ /* Default setting is for src. gcv2D_YUV_DST
+ can be ORed to set dst.
+ */
+ gcv2D_YUV_DST = 0x80000000,
+}
+gce2D_YUV_COLOR_MODE;
+
+/* Nature rotation rules. */
+typedef enum _gce2D_NATURE_ROTATION
+{
+ gcvNR_0_DEGREE = 0,
+ gcvNR_LEFT_90_DEGREE,
+ gcvNR_RIGHT_90_DEGREE,
+ gcvNR_180_DEGREE,
+ gcvNR_FLIP_X,
+ gcvNR_FLIP_Y,
+ gcvNR_TOTAL_RULE,
+}
+gce2D_NATURE_ROTATION;
+
+typedef enum _gce2D_COMMAND
+{
+ gcv2D_CLEAR = 0,
+ gcv2D_LINE,
+ gcv2D_BLT,
+ gcv2D_STRETCH,
+ gcv2D_HOR_FILTER,
+ gcv2D_VER_FILTER,
+ gcv2D_MULTI_SOURCE_BLT,
+ gcv2D_FILTER_BLT,
+}
+gce2D_COMMAND;
+
+typedef enum _gce2D_TILE_STATUS_CONFIG
+{
+ gcv2D_TSC_DISABLE = 0,
+ gcv2D_TSC_ENABLE = 0x00000001,
+ gcv2D_TSC_COMPRESSED = 0x00000002,
+ gcv2D_TSC_DOWN_SAMPLER = 0x00000004,
+ gcv2D_TSC_2D_COMPRESSED = 0x00000008,
+
+ gcv2D_TSC_DEC_COMPRESSED = 0x00000020,
+ gcv2D_TSC_DEC_TPC = 0x00000040,
+ gcv2D_TSC_DEC_TPC_COMPRESSED = 0x00000080,
+
+ gcv2D_TSC_V4_COMPRESSED = 0x00000100,
+ gcv2D_TSC_V4_COMPRESSED_256B = 0x00000200 | gcv2D_TSC_V4_COMPRESSED,
+
+ gcv2D_TSC_DEC_TPC_TILED = gcv2D_TSC_DEC_COMPRESSED | gcv2D_TSC_DEC_TPC,
+ gcv2D_TSC_DEC_TPC_TILED_COMPRESSED = gcv2D_TSC_DEC_TPC_TILED | gcv2D_TSC_DEC_TPC_COMPRESSED,
+
+ gcv2D_TSC_TPC_COMPRESSED = 0x00001000,
+ gcv2D_TSC_TPC_COMPRESSED_V10 = gcv2D_TSC_TPC_COMPRESSED | 0x00000400,
+ gcv2D_TSC_TPC_COMPRESSED_V11 = gcv2D_TSC_TPC_COMPRESSED | 0x00000800,
+}
+gce2D_TILE_STATUS_CONFIG;
+
+typedef enum _gce2D_QUERY
+{
+ gcv2D_QUERY_RGB_ADDRESS_MIN_ALIGN = 0,
+ gcv2D_QUERY_RGB_STRIDE_MIN_ALIGN,
+ gcv2D_QUERY_YUV_ADDRESS_MIN_ALIGN,
+ gcv2D_QUERY_YUV_STRIDE_MIN_ALIGN,
+}
+gce2D_QUERY;
+
+typedef enum _gce2D_SUPER_TILE_VERSION
+{
+ gcv2D_SUPER_TILE_VERSION_V1 = 1,
+ gcv2D_SUPER_TILE_VERSION_V2 = 2,
+ gcv2D_SUPER_TILE_VERSION_V3 = 3,
+}
+gce2D_SUPER_TILE_VERSION;
+
+typedef enum _gce2D_STATE
+{
+ gcv2D_STATE_SPECIAL_FILTER_MIRROR_MODE = 1,
+ gcv2D_STATE_SUPER_TILE_VERSION,
+ gcv2D_STATE_EN_GAMMA,
+ gcv2D_STATE_DE_GAMMA,
+ gcv2D_STATE_MULTI_SRC_BLIT_UNIFIED_DST_RECT,
+ gcv2D_STATE_MULTI_SRC_BLIT_BILINEAR_FILTER,
+ gcv2D_STATE_PROFILE_ENABLE,
+ gcv2D_STATE_XRGB_ENABLE,
+
+ gcv2D_STATE_ARRAY_EN_GAMMA = 0x10001,
+ gcv2D_STATE_ARRAY_DE_GAMMA,
+ gcv2D_STATE_ARRAY_CSC_YUV_TO_RGB,
+ gcv2D_STATE_ARRAY_CSC_RGB_TO_YUV,
+
+ gcv2D_STATE_DEC_TPC_NV12_10BIT = 0x20001,
+ gcv2D_STATE_ARRAY_YUV_SRC_TILE_STATUS_ADDR,
+ gcv2D_STATE_ARRAY_YUV_DST_TILE_STATUS_ADDR,
+}
+gce2D_STATE;
+
+typedef enum _gce2D_STATE_PROFILE
+{
+ gcv2D_STATE_PROFILE_NONE = 0x0,
+ gcv2D_STATE_PROFILE_COMMAND = 0x1,
+ gcv2D_STATE_PROFILE_SURFACE = 0x2,
+ gcv2D_STATE_PROFILE_ALL = 0xFFFF,
+}
+gce2D_STATE_PROFILE;
+
+/* Texture object types */
+typedef enum _gceTEXTURE_TYPE
+{
+ gcvTEXTURE_UNKNOWN = 0,
+ gcvTEXTURE_1D,
+ gcvTEXTURE_2D,
+ gcvTEXTURE_3D,
+ gcvTEXTURE_CUBEMAP,
+ gcvTEXTURE_1D_ARRAY,
+ gcvTEXTURE_2D_ARRAY,
+ gcvTEXTURE_2D_MS,
+ gcvTEXTURE_2D_MS_ARRAY,
+ gcvTEXTURE_CUBEMAP_ARRAY,
+ gcvTEXTURE_EXTERNAL
+}
+gceTEXTURE_TYPE;
+
+#if gcdENABLE_3D
+/* Texture functions. */
+typedef enum _gceTEXTURE_FUNCTION
+{
+ gcvTEXTURE_DUMMY = 0,
+ gcvTEXTURE_REPLACE = 0,
+ gcvTEXTURE_MODULATE,
+ gcvTEXTURE_ADD,
+ gcvTEXTURE_ADD_SIGNED,
+ gcvTEXTURE_INTERPOLATE,
+ gcvTEXTURE_SUBTRACT,
+ gcvTEXTURE_DOT3
+}
+gceTEXTURE_FUNCTION;
+
+/* Texture sources. */
+typedef enum _gceTEXTURE_SOURCE
+{
+ gcvCOLOR_FROM_TEXTURE = 0,
+ gcvCOLOR_FROM_CONSTANT_COLOR,
+ gcvCOLOR_FROM_PRIMARY_COLOR,
+ gcvCOLOR_FROM_PREVIOUS_COLOR
+}
+gceTEXTURE_SOURCE;
+
+/* Texture source channels. */
+typedef enum _gceTEXTURE_CHANNEL
+{
+ gcvFROM_COLOR = 0,
+ gcvFROM_ONE_MINUS_COLOR,
+ gcvFROM_ALPHA,
+ gcvFROM_ONE_MINUS_ALPHA
+}
+gceTEXTURE_CHANNEL;
+#endif /* gcdENABLE_3D */
+
+/* Filter types. */
+typedef enum _gceFILTER_TYPE
+{
+ gcvFILTER_SYNC = 0,
+ gcvFILTER_BLUR,
+ gcvFILTER_USER
+}
+gceFILTER_TYPE;
+
+/* Filter pass types. */
+typedef enum _gceFILTER_PASS_TYPE
+{
+ gcvFILTER_HOR_PASS = 0,
+ gcvFILTER_VER_PASS
+}
+gceFILTER_PASS_TYPE;
+
+/* Endian hints. */
+typedef enum _gceENDIAN_HINT
+{
+ gcvENDIAN_NO_SWAP = 0,
+ gcvENDIAN_SWAP_WORD,
+ gcvENDIAN_SWAP_DWORD
+}
+gceENDIAN_HINT;
+
+/* Tiling modes. */
+typedef enum _gceTILING
+{
+ gcvINVALIDTILED = 0x0, /* Invalid tiling */
+ /* Tiling basic modes enum'ed in power of 2. */
+ gcvLINEAR = 0x1, /* No tiling. */
+ gcvTILED = 0x2, /* 4x4 tiling. */
+ gcvSUPERTILED = 0x4, /* 64x64 tiling. */
+ gcvMINORTILED = 0x8, /* 2x2 tiling. */
+
+ /* Tiling special layouts. */
+ gcvTILING_SPLIT_BUFFER = 0x10,
+ gcvTILING_X_MAJOR = 0x20,
+ gcvTILING_Y_MAJOR = 0x40,
+ gcvTILING_SWAP = 0x80,
+
+ /* Tiling combination layouts. */
+ gcvMULTI_TILED = gcvTILED
+ | gcvTILING_SPLIT_BUFFER,
+
+ gcvMULTI_SUPERTILED = gcvSUPERTILED
+ | gcvTILING_SPLIT_BUFFER,
+
+ gcvYMAJOR_SUPERTILED = gcvSUPERTILED
+ | gcvTILING_Y_MAJOR,
+
+ gcvTILED_8X4 = 0x0100,
+ gcvTILED_4X8 = 0x0100 | gcvTILING_SWAP,
+ gcvTILED_8X8 = 0x0200,
+ gcvTILED_16X4 = 0x0400,
+ gcvTILED_32X4 = 0x0800,
+ gcvTILED_64X4 = 0x1000,
+
+ gcvTILED_8X8_XMAJOR = gcvTILED_8X8 | gcvTILING_X_MAJOR,
+ gcvTILED_8X8_YMAJOR = gcvTILED_8X8 | gcvTILING_Y_MAJOR,
+
+ gcvSUPERTILED_128B = 0x10000 | gcvSUPERTILED,
+ gcvSUPERTILED_256B = 0x20000 | gcvSUPERTILED,
+}
+gceTILING;
+
+typedef enum _gceCACHE_MODE
+{
+ gcvCACHE_NONE,
+ gcvCACHE_128,
+ gcvCACHE_256,
+}
+gceCACHE_MODE;
+
+#define DEFAULT_CACHE_MODE gcvCACHE_256
+
+/* 2D pattern type. */
+typedef enum _gce2D_PATTERN
+{
+ gcv2D_PATTERN_SOLID = 0,
+ gcv2D_PATTERN_MONO,
+ gcv2D_PATTERN_COLOR,
+ gcv2D_PATTERN_INVALID
+}
+gce2D_PATTERN;
+
+/* 2D source type. */
+typedef enum _gce2D_SOURCE
+{
+ gcv2D_SOURCE_MASKED = 0,
+ gcv2D_SOURCE_MONO,
+ gcv2D_SOURCE_COLOR,
+ gcv2D_SOURCE_INVALID
+}
+gce2D_SOURCE;
+
+/* Pipes. */
+typedef enum _gcePIPE_SELECT
+{
+ gcvPIPE_INVALID = ~0,
+ gcvPIPE_3D = 0,
+ gcvPIPE_2D
+}
+gcePIPE_SELECT;
+
+/* Hardware type. */
+typedef enum _gceHARDWARE_TYPE
+{
+ gcvHARDWARE_INVALID,
+ gcvHARDWARE_3D,
+ gcvHARDWARE_2D,
+ gcvHARDWARE_VG,
+ gcvHARDWARE_3D2D,
+ gcvHARDWARE_NUM_TYPES,
+}
+gceHARDWARE_TYPE;
+
+#define gcdCHIP_COUNT gcvCORE_COUNT
+
+typedef enum _gceMMU_MODE
+{
+ gcvMMU_MODE_1K,
+ gcvMMU_MODE_4K,
+} gceMMU_MODE;
+
+/* User signal command codes. */
+typedef enum _gceUSER_SIGNAL_COMMAND_CODES
+{
+ gcvUSER_SIGNAL_CREATE,
+ gcvUSER_SIGNAL_DESTROY,
+ gcvUSER_SIGNAL_SIGNAL,
+ gcvUSER_SIGNAL_WAIT,
+ gcvUSER_SIGNAL_MAP,
+ gcvUSER_SIGNAL_UNMAP,
+}
+gceUSER_SIGNAL_COMMAND_CODES;
+
+/* Shared buffer command codes. */
+typedef enum _gceSHBUF_COMMAND_CODES
+{
+ gcvSHBUF_CREATE,
+ gcvSHBUF_DESTROY,
+ gcvSHBUF_MAP,
+ gcvSHBUF_WRITE,
+ gcvSHBUF_READ,
+}
+gceSHBUF_COMMAND_CODES;
+
+/* Event locations. */
+typedef enum _gceKERNEL_WHERE
+{
+ gcvKERNEL_COMMAND,
+ gcvKERNEL_VERTEX,
+ gcvKERNEL_TRIANGLE,
+ gcvKERNEL_TEXTURE,
+ gcvKERNEL_PIXEL,
+ gcvKERNEL_BLT,
+}
+gceKERNEL_WHERE;
+
+#if gcdENABLE_VG
+/* Hardware blocks. */
+typedef enum _gceBLOCK
+{
+ gcvBLOCK_COMMAND,
+ gcvBLOCK_TESSELLATOR,
+ gcvBLOCK_TESSELLATOR2,
+ gcvBLOCK_TESSELLATOR3,
+ gcvBLOCK_RASTER,
+ gcvBLOCK_VG,
+ gcvBLOCK_VG2,
+ gcvBLOCK_VG3,
+ gcvBLOCK_PIXEL,
+
+ /* Number of defined blocks. */
+ gcvBLOCK_COUNT
+}
+gceBLOCK;
+#endif
+
+/* gcdDUMP message type. */
+typedef enum _gceDEBUG_MESSAGE_TYPE
+{
+ gcvMESSAGE_TEXT,
+ gcvMESSAGE_DUMP
+}
+gceDEBUG_MESSAGE_TYPE;
+
+/* Shading format. */
+typedef enum _gceSHADING
+{
+ gcvSHADING_SMOOTH,
+ gcvSHADING_FLAT_D3D,
+ gcvSHADING_FLAT_OPENGL,
+}
+gceSHADING;
+
+/* Culling modes. */
+typedef enum _gceCULL
+{
+ gcvCULL_NONE,
+ gcvCULL_CCW,
+ gcvCULL_CW,
+}
+gceCULL;
+
+/* Fill modes. */
+typedef enum _gceFILL
+{
+ gcvFILL_POINT,
+ gcvFILL_WIRE_FRAME,
+ gcvFILL_SOLID,
+}
+gceFILL;
+
+/* Compare modes. */
+typedef enum _gceCOMPARE
+{
+ gcvCOMPARE_INVALID = 0,
+ gcvCOMPARE_NEVER,
+ gcvCOMPARE_NOT_EQUAL,
+ gcvCOMPARE_LESS,
+ gcvCOMPARE_LESS_OR_EQUAL,
+ gcvCOMPARE_EQUAL,
+ gcvCOMPARE_GREATER,
+ gcvCOMPARE_GREATER_OR_EQUAL,
+ gcvCOMPARE_ALWAYS,
+}
+gceCOMPARE;
+
+/* Stencil modes. */
+typedef enum _gceSTENCIL_MODE
+{
+ gcvSTENCIL_NONE,
+ gcvSTENCIL_SINGLE_SIDED,
+ gcvSTENCIL_DOUBLE_SIDED,
+}
+gceSTENCIL_MODE;
+
+/* Stencil operations. */
+typedef enum _gceSTENCIL_OPERATION
+{
+ gcvSTENCIL_KEEP,
+ gcvSTENCIL_REPLACE,
+ gcvSTENCIL_ZERO,
+ gcvSTENCIL_INVERT,
+ gcvSTENCIL_INCREMENT,
+ gcvSTENCIL_DECREMENT,
+ gcvSTENCIL_INCREMENT_SATURATE,
+ gcvSTENCIL_DECREMENT_SATURATE,
+ gcvSTENCIL_OPERATION_INVALID = -1
+}
+gceSTENCIL_OPERATION;
+
+/* Stencil selection. */
+typedef enum _gceSTENCIL_WHERE
+{
+ gcvSTENCIL_FRONT,
+ gcvSTENCIL_BACK,
+}
+gceSTENCIL_WHERE;
+
+/* Texture addressing selection. */
+typedef enum _gceTEXTURE_WHICH
+{
+ gcvTEXTURE_S,
+ gcvTEXTURE_T,
+ gcvTEXTURE_R,
+}
+gceTEXTURE_WHICH;
+
+/* Texture addressing modes. */
+typedef enum _gceTEXTURE_ADDRESSING
+{
+ gcvTEXTURE_INVALID = 0,
+ gcvTEXTURE_CLAMP,
+ gcvTEXTURE_WRAP,
+ gcvTEXTURE_MIRROR,
+ gcvTEXTURE_BORDER,
+ gcvTEXTURE_MIRROR_ONCE,
+}
+gceTEXTURE_ADDRESSING;
+
+/* Texture filters. */
+typedef enum _gceTEXTURE_FILTER
+{
+ gcvTEXTURE_NONE,
+ gcvTEXTURE_POINT,
+ gcvTEXTURE_LINEAR,
+ gcvTEXTURE_ANISOTROPIC,
+}
+gceTEXTURE_FILTER;
+
+typedef enum _gceTEXTURE_COMPONENT
+{
+ gcvTEXTURE_COMPONENT_R,
+ gcvTEXTURE_COMPONENT_G,
+ gcvTEXTURE_COMPONENT_B,
+ gcvTEXTURE_COMPONENT_A,
+
+ gcvTEXTURE_COMPONENT_NUM,
+} gceTEXTURE_COMPONENT;
+
+/* Texture swizzle modes. */
+typedef enum _gceTEXTURE_SWIZZLE
+{
+ gcvTEXTURE_SWIZZLE_R = 0,
+ gcvTEXTURE_SWIZZLE_G,
+ gcvTEXTURE_SWIZZLE_B,
+ gcvTEXTURE_SWIZZLE_A,
+ gcvTEXTURE_SWIZZLE_0,
+ gcvTEXTURE_SWIZZLE_1,
+
+ gcvTEXTURE_SWIZZLE_INVALID,
+} gceTEXTURE_SWIZZLE;
+
+typedef enum _gceTEXTURE_SRGBDECODE
+{
+ gcvTEXTURE_SRGB_INVALID = 0,
+ gcvTEXTURE_DECODE,
+ gcvTEXTURE_SKIP_DECODE,
+}gceTEXTURE_SRGBDECODE;
+
+typedef enum _gceTEXTURE_COMPARE_MODE
+{
+ gcvTEXTURE_COMPARE_MODE_INVALID = 0,
+ gcvTEXTURE_COMPARE_MODE_NONE,
+ gcvTEXTURE_COMPARE_MODE_REF,
+} gceTEXTURE_COMPARE_MODE;
+
+typedef enum _gceTEXTURE_DS_MODE
+{
+ gcvTEXTURE_DS_MODE_INVALID = 0,
+ gcvTEXTURE_DS_MODE_DEPTH = 1,
+ gcvTEXTURE_DS_MODE_STENCIL = 2,
+}gceTEXTURE_DS_MODE;
+
+
+/* Pixel output swizzle modes. */
+typedef enum _gcePIXEL_SWIZZLE
+{
+ gcvPIXEL_SWIZZLE_R = gcvTEXTURE_SWIZZLE_R,
+ gcvPIXEL_SWIZZLE_G = gcvTEXTURE_SWIZZLE_G,
+ gcvPIXEL_SWIZZLE_B = gcvTEXTURE_SWIZZLE_B,
+ gcvPIXEL_SWIZZLE_A = gcvTEXTURE_SWIZZLE_A,
+
+ gcvPIXEL_SWIZZLE_INVALID,
+} gcePIXEL_SWIZZLE;
+
+/* Primitive types. */
+typedef enum _gcePRIMITIVE
+{
+ gcvPRIMITIVE_POINT_LIST,
+ gcvPRIMITIVE_LINE_LIST,
+ gcvPRIMITIVE_LINE_STRIP,
+ gcvPRIMITIVE_LINE_LOOP,
+ gcvPRIMITIVE_TRIANGLE_LIST,
+ gcvPRIMITIVE_TRIANGLE_STRIP,
+ gcvPRIMITIVE_TRIANGLE_FAN,
+ gcvPRIMITIVE_RECTANGLE,
+ gcvPRIMITIVE_LINES_ADJACENCY,
+ gcvPRIMITIVE_LINE_STRIP_ADJACENCY,
+ gcvPRIMITIVE_TRIANGLES_ADJACENCY,
+ gcvPRIMITIVE_TRIANGLE_STRIP_ADJACENCY,
+ gcvPRIMITIVE_PATCH_LIST,
+}
+gcePRIMITIVE;
+
+/* Index types. */
+typedef enum _gceINDEX_TYPE
+{
+ gcvINDEX_8,
+ gcvINDEX_16,
+ gcvINDEX_32,
+}
+gceINDEX_TYPE;
+
+/* Multi GPU rendering modes. */
+typedef enum _gceMULTI_GPU_RENDERING_MODE
+{
+ gcvMULTI_GPU_RENDERING_MODE_OFF,
+ gcvMULTI_GPU_RENDERING_MODE_SPLIT_WIDTH,
+ gcvMULTI_GPU_RENDERING_MODE_SPLIT_HEIGHT,
+ gcvMULTI_GPU_RENDERING_MODE_INTERLEAVED_64x64,
+ gcvMULTI_GPU_RENDERING_MODE_INTERLEAVED_128x64,
+ gcvMULTI_GPU_RENDERING_MODE_INTERLEAVED_128x128,
+ gcvMULTI_GPU_RENDERING_MODE_INVALID
+}
+gceMULTI_GPU_RENDERING_MODE;
+
+typedef enum _gceCORE_3D_MASK
+{
+ gcvCORE_3D_0_MASK = (1 << 0),
+ gcvCORE_3D_1_MASK = (1 << 1),
+
+ gcvCORE_3D_ALL_MASK = (0xFFFF)
+}
+gceCORE_3D_MASK;
+
+typedef enum _gceCORE_3D_ID
+{
+ gcvCORE_3D_0_ID = 0,
+ gcvCORE_3D_1_ID = 1,
+
+ gcvCORE_3D_ID_INVALID = ~0UL
+}
+gceCORE_3D_ID;
+
+typedef enum _gceMULTI_GPU_MODE
+{
+ gcvMULTI_GPU_MODE_COMBINED = 0,
+ gcvMULTI_GPU_MODE_INDEPENDENT = 1
+}
+gceMULTI_GPU_MODE;
+
+typedef enum _gceMACHINECODE
+{
+ gcvMACHINECODE_ANTUTU0 = 0x0,
+
+ gcvMACHINECODE_GLB27_RELEASE_0,
+
+ gcvMACHINECODE_GLB25_RELEASE_0,
+ gcvMACHINECODE_GLB25_RELEASE_1,
+
+ /* keep it as the last enum */
+ gcvMACHINECODE_COUNT
+}
+gceMACHINECODE;
+
+typedef enum _gceUNIFORMCVT
+{
+ gcvUNIFORMCVT_NONE = 0,
+ gcvUNIFORMCVT_TO_BOOL,
+ gcvUNIFORMCVT_TO_FLOAT,
+} gceUNIFORMCVT;
+
+typedef enum _gceHAL_ARG_VERSION
+{
+ gcvHAL_ARG_VERSION_V1 = 0x0,
+ gcvHAL_ARG_VERSION_V2,
+}
+gceHAL_ARG_VERSION;
+
+
+typedef enum _gceCMDBUF_TYPE
+{
+ /* Contiguous command buffer. */
+ gcvCMDBUF_CONTIGUOUS,
+ /* Virtual command buffer. */
+ gcvCMDBUF_VIRTUAL,
+ /* Command buffer allocated from reserved memory. */
+ gcvCMDBUF_RESERVED,
+}
+gceCMDBUF_SOURCE;
+
+typedef enum _gceCHIP_FLAG
+{
+ gcvCHIP_FLAG_MSAA_COHERENCEY_ECO_FIX = 1 << 0,
+ gcvCHIP_FLAG_GC2000_R2 = 1 << 1,
+ gcvCHIP_AXI_BUS128_BITS = 1 << 2,
+}
+gceCHIP_FLAG;
+
+/* If different, choose render engine */
+#define PRIORITY_ENGINE(a, b) gcmMIN(a,b)
+
+typedef enum
+{
+ gcvENGINE_RENDER = 0,
+ gcvENGINE_BLT = 1,
+ gcvENGINE_GPU_ENGINE_COUNT = 2,
+ gcvENGINE_CPU = gcvENGINE_GPU_ENGINE_COUNT,
+ gcvENGINE_ALL_COUNT = gcvENGINE_CPU + 1,
+ gcvENGINE_INVALID = gcvENGINE_ALL_COUNT + 0x100
+}
+gceENGINE;
+
+/* CORE enum. */
+typedef enum _gceCORE
+{
+ gcvCORE_MAJOR,
+ gcvCORE_3D1,
+ gcvCORE_3D2,
+ gcvCORE_3D3,
+ gcvCORE_3D4,
+ gcvCORE_3D5,
+ gcvCORE_3D6,
+ gcvCORE_3D7,
+ gcvCORE_3D_MAX = gcvCORE_3D7,
+ gcvCORE_2D,
+ gcvCORE_VG,
+#if gcdDEC_ENABLE_AHB
+ gcvCORE_DEC,
+#endif
+ gcvCORE_COUNT
+}
+gceCORE;
+
+
+typedef enum _gceADDRESS_AREA
+{
+ gcvADDRESS_AREA_NORMAL,
+ gcvADDRESS_AREA_SECURE,
+
+ gcvADDRESS_AREA_COUNT
+}
+gceADDRESS_AREA;
+
+typedef enum _gceSECURE_MODE
+{
+ /* For cores without gcvFEATURE_SECURITY. */
+ gcvSECURE_NONE,
+
+ /* Use registers added in gcvFEATURE_SECURITY in normal driver,
+ ** In this mode, GPU always works under non secure mode and
+ ** should not touch secure buffer. It is used to test basic function.
+ */
+ gcvSECURE_IN_NORMAL,
+
+ /* Make use of gcvFEATURE_SECURITY in trust application. */
+ gcvSECURE_IN_TA
+}
+gceSECURE_MODE;
+
+/* kernel driver compression option, as it's a system global option,
+** it means kernel driver allows the options, NOT necessarily means it must be on.
+*/
+typedef enum _gceCOMPRESSION_OPTION
+{
+ gcvCOMPRESSION_OPTION_NONE = 0x0, /* No any compression */
+ gcvCOMPRESSION_OPTION_COLOR = 0x1, /* Compression for non-msaa color format */
+ gcvCOMPRESSION_OPTION_DEPTH = 0x2, /* Compression for non-msaa depth format */
+ gcvCOMPRESSION_OPTION_MSAA_COLOR = 0x4, /* Compression for msaa color */
+ gcvCOMPRESSION_OPTION_MSAA_DEPTH = 0x8, /* Compression for msaa depth */
+
+ /* default compressio option */
+ gcvCOMPRESSION_OPTION_DEFAULT = gcvCOMPRESSION_OPTION_DEPTH |
+ gcvCOMPRESSION_OPTION_COLOR |
+ gcvCOMPRESSION_OPTION_MSAA_COLOR |
+ gcvCOMPRESSION_OPTION_MSAA_DEPTH,
+}
+gceCOMPRESSION_OPTION;
+
+/* No special needs. */
+#define gcvALLOC_FLAG_NONE 0x00000000
+
+/* Physical contiguous. */
+#define gcvALLOC_FLAG_CONTIGUOUS 0x00000001
+/* Can be remapped as cacheable. */
+#define gcvALLOC_FLAG_CACHEABLE 0x00000002
+/* Secure buffer. */
+#define gcvALLOC_FLAG_SECURITY 0x00000004
+/* Physical non contiguous. */
+#define gcvALLOC_FLAG_NON_CONTIGUOUS 0x00000008
+/* Can be exported as dmabuf-fd */
+#define gcvALLOC_FLAG_DMABUF_EXPORTABLE 0x00000010
+
+/* Do not try slow pools (gcvPOOL_VIRTUAL/gcvPOOL_CONTIGUOUS) */
+#define gcvALLOC_FLAG_FAST_POOLS 0x00000100
+
+/* Import DMABUF. */
+#define gcvALLOC_FLAG_DMABUF 0x00001000
+/* Import USERMEMORY. */
+#define gcvALLOC_FLAG_USERMEMORY 0x00002000
+/* Import an External Buffer. */
+#define gcvALLOC_FLAG_EXTERNAL_MEMORY 0x00004000
+/* Import linux reserved memory. */
+#define gcvALLOC_FLAG_LINUX_RESERVED_MEM 0x00008000
+
+/* Real allocation happens when GPU page fault. */
+#define gcvALLOC_FLAG_ALLOC_ON_FAULT 0x01000000
+/* Alloc with memory limit. */
+#define gcvALLOC_FLAG_MEMLIMIT 0x02000000
+
+/* CMA allocator only */
+#define gcvALLOC_FLAG_CMA_LIMIT 0x04000000
+
+#define gcvALLOC_FLAG_CMA_PREEMPT 0x08000000
+
+/* GL_VIV internal usage */
+#ifndef GL_MAP_BUFFER_OBJ_VIV
+#define GL_MAP_BUFFER_OBJ_VIV 0x10000
+#endif
+
+/* Command buffer usage. */
+#define gcvCOMMAND_2D (1 << 0)
+#define gcvCOMMAND_3D (1 << 1)
+
+/* Default chip ID means chip ID same as core index. */
+#define gcvCHIP_ID_DEFAULT (~0U)
+
+/******************************************************************************\
+****************************** Object Declarations *****************************
+\******************************************************************************/
+
+typedef struct _gckCONTEXT * gckCONTEXT;
+typedef struct _gcoCMDBUF * gcoCMDBUF;
+
+typedef struct _gcsSTATE_DELTA * gcsSTATE_DELTA_PTR;
+typedef struct _gcsQUEUE * gcsQUEUE_PTR;
+typedef struct _gcoQUEUE * gcoQUEUE;
+typedef struct _gcsHAL_INTERFACE * gcsHAL_INTERFACE_PTR;
+typedef struct _gcs2D_PROFILE * gcs2D_PROFILE_PTR;
+
+
+#if gcdENABLE_VG
+typedef struct _gcoVGHARDWARE * gcoVGHARDWARE;
+typedef struct _gcoVGBUFFER * gcoVGBUFFER;
+typedef struct _gckVGHARDWARE * gckVGHARDWARE;
+typedef struct _gcsVGCONTEXT * gcsVGCONTEXT_PTR;
+typedef struct _gcsVGCONTEXT_MAP * gcsVGCONTEXT_MAP_PTR;
+typedef struct _gcsVGCMDQUEUE * gcsVGCMDQUEUE_PTR;
+typedef struct _gcsTASK_MASTER_TABLE * gcsTASK_MASTER_TABLE_PTR;
+typedef struct _gckVGKERNEL * gckVGKERNEL;
+typedef void * gctTHREAD;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_enum_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_kernel_buffer.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_kernel_buffer.h
new file mode 100644
index 000000000000..399eb8d2ac23
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_kernel_buffer.h
@@ -0,0 +1,314 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_buffer_h_
+#define __gc_hal_kernel_buffer_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+************************ Command Buffer and Event Objects **********************
+\******************************************************************************/
+
+/* The number of context buffers per user. */
+#define gcdCONTEXT_BUFFER_COUNT 2
+
+#define gcdRENDER_FENCE_LENGTH (6 * gcmSIZEOF(gctUINT32))
+#define gcdBLT_FENCE_LENGTH (10 * gcmSIZEOF(gctUINT32))
+#define gcdRESERVED_FLUSHCACHE_LENGTH (2 * gcmSIZEOF(gctUINT32))
+#define gcdRESERVED_PAUSE_OQ_LENGTH (2 * gcmSIZEOF(gctUINT32))
+#define gcdRESERVED_PAUSE_XFBWRITTEN_QUERY_LENGTH (4 * gcmSIZEOF(gctUINT32))
+#define gcdRESERVED_PAUSE_PRIMGEN_QUERY_LENGTH (4 * gcmSIZEOF(gctUINT32))
+#define gcdRESERVED_PAUSE_XFB_LENGTH (2 * gcmSIZEOF(gctUINT32))
+#define gcdRESERVED_HW_FENCE_32BIT (4 * gcmSIZEOF(gctUINT32))
+#define gcdRESERVED_HW_FENCE_64BIT (6 * gcmSIZEOF(gctUINT32))
+#define gcdRESERVED_PAUSE_PROBE_LENGTH (TOTAL_PROBE_NUMBER * 2 * gcmSIZEOF(gctUINT32))
+
+#define gcdRESUME_OQ_LENGTH (2 * gcmSIZEOF(gctUINT32))
+#define gcdRESUME_XFBWRITTEN_QUERY_LENGTH (4 * gcmSIZEOF(gctUINT32))
+#define gcdRESUME_PRIMGEN_QUERY_LENGTH (4 * gcmSIZEOF(gctUINT32))
+#define gcdRESUME_XFB_LENGH (2 * gcmSIZEOF(gctUINT32))
+#define gcdRESUME_PROBE_LENGH (TOTAL_PROBE_NUMBER * 2 * gcmSIZEOF(gctUINT32))
+
+
+/* State delta record. */
+typedef struct _gcsSTATE_DELTA_RECORD * gcsSTATE_DELTA_RECORD_PTR;
+typedef struct _gcsSTATE_DELTA_RECORD
+{
+ /* State address. */
+ gctUINT address;
+
+ /* State mask. */
+ gctUINT32 mask;
+
+ /* State data. */
+ gctUINT32 data;
+}
+gcsSTATE_DELTA_RECORD;
+
+/* State delta. */
+typedef struct _gcsSTATE_DELTA
+{
+ /* For debugging: the number of delta in the order of creation. */
+ gctUINT num;
+
+ /* Main state delta ID. Every time state delta structure gets reinitialized,
+ main ID is incremented. If main state ID overflows, all map entry IDs get
+ reinitialized to make sure there is no potential erroneous match after
+ the overflow.*/
+ gctUINT id;
+
+ /* Vertex element count for the delta buffer. */
+ gctUINT elementCount;
+
+ /* Number of states currently stored in the record array. */
+ gctUINT recordCount;
+
+ /* Record array; holds all modified states in gcsSTATE_DELTA_RECORD. */
+ gctUINT64 recordArray;
+ gctUINT recordSize;
+
+ /* Map entry ID is used for map entry validation. If map entry ID does not
+ match the main state delta ID, the entry and the corresponding state are
+ considered not in use. */
+ gctUINT64 mapEntryID;
+ gctUINT mapEntryIDSize;
+
+ /* If the map entry ID matches the main state delta ID, index points to
+ the state record in the record array. */
+ gctUINT64 mapEntryIndex;
+}
+gcsSTATE_DELTA;
+
+#define gcdPATCH_LIST_SIZE 1024
+
+/* Command buffer patch record. */
+typedef struct _gcsPATCH
+{
+ /* Handle of a video memory node. */
+ gctUINT32 handle;
+
+ /* Flag */
+ gctUINT32 flag;
+}
+gcsPATCH;
+
+/* List of patches for the command buffer. */
+typedef struct _gcsPATCH_LIST
+{
+ /* Array of patch records. */
+ struct _gcsPATCH patch[gcdPATCH_LIST_SIZE];
+
+ /* Number of patches in the array. */
+ gctUINT count;
+
+ /* Next item in the list. */
+ struct _gcsPATCH_LIST *next;
+}
+gcsPATCH_LIST;
+
+#define FENCE_NODE_LIST_INIT_COUNT 100
+
+typedef struct _gcsFENCE_APPEND_NODE
+{
+ gcsSURF_NODE_PTR node;
+ gceFENCE_TYPE type;
+
+}gcsFENCE_APPEND_NODE;
+
+typedef gcsFENCE_APPEND_NODE * gcsFENCE_APPEND_NODE_PTR;
+
+typedef struct _gcsFENCE_LIST * gcsFENCE_LIST_PTR;
+
+typedef struct _gcsFENCE_LIST
+{
+ /* Resource that need get fence, but command used this resource not generated */
+ gcsFENCE_APPEND_NODE_PTR pendingList;
+ gctUINT pendingCount;
+ gctUINT pendingAllocCount;
+
+ /* Resoure that already generated command in this command buffer but not get fence */
+ gcsFENCE_APPEND_NODE_PTR onIssueList;
+ gctUINT onIssueCount;
+ gctUINT onIssueAllocCount;
+}
+gcsFENCE_LIST;
+
+/* Command buffer object. */
+struct _gcoCMDBUF
+{
+ /* The object. */
+ gcsOBJECT object;
+
+ /* Commit count. */
+ gctUINT64 commitCount;
+
+ /* Command buffer entry and exit pipes. */
+ gcePIPE_SELECT entryPipe;
+ gcePIPE_SELECT exitPipe;
+
+ /* Feature usage flags. */
+ gctBOOL using2D;
+ gctBOOL using3D;
+
+ /* Size of reserved tail for each commit. */
+ gctUINT32 reservedTail;
+
+ /* Physical address of command buffer. Just a name. */
+ gctUINT32 physical;
+
+ /* Logical address of command buffer. */
+ gctUINT64 logical;
+
+ /* Number of bytes in command buffer. */
+ gctUINT32 bytes;
+
+ /* Start offset into the command buffer. */
+ gctUINT32 startOffset;
+
+ /* Current offset into the command buffer. */
+ gctUINT32 offset;
+
+ /* Number of free bytes in command buffer. */
+ gctUINT32 free;
+
+ /* Location of the last reserved area. */
+ gctUINT64 lastReserve;
+ gctUINT32 lastOffset;
+
+#if gcdSECURE_USER
+ /* Hint array for the current command buffer. */
+ gctUINT hintArraySize;
+ gctUINT64 hintArray;
+ gctUINT64 hintArrayTail;
+#endif
+
+ /* Last load state command location and hardware address. */
+ gctUINT64 lastLoadStatePtr;
+ gctUINT32 lastLoadStateAddress;
+ gctUINT32 lastLoadStateCount;
+
+ /* List of patches. */
+ gctUINT64 patchHead;
+
+ /* Link to next gcoCMDBUF object in one commit. */
+ gctUINT64 nextCMDBUF;
+
+ /*
+ * Put pointer type member after this line.
+ */
+
+ /* Completion signal. */
+ gctSIGNAL signal;
+
+ /* Link to the siblings. */
+ gcoCMDBUF prev;
+ gcoCMDBUF next;
+
+ /* Mirror command buffer(s). */
+ gcoCMDBUF *mirrors;
+ gctUINT32 mirrorCount;
+};
+
+typedef struct _gcsQUEUE
+{
+ /* Pointer to next gcsQUEUE structure in gcsQUEUE. */
+ gctUINT64 next;
+
+ /* Event information. */
+ gcsHAL_INTERFACE iface;
+}
+gcsQUEUE;
+
+/* Event queue. */
+struct _gcoQUEUE
+{
+ /* The object. */
+ gcsOBJECT object;
+
+ /* Pointer to current event queue. */
+ gcsQUEUE_PTR head;
+ gcsQUEUE_PTR tail;
+
+ /* chunks of the records. */
+ gctPOINTER chunks;
+
+ /* List of free records. */
+ gcsQUEUE_PTR freeList;
+
+ #define gcdIN_QUEUE_RECORD_LIMIT 16
+ /* Number of records currently in queue */
+ gctUINT32 recordCount;
+
+ /* Max size of pending unlock node in vidmem pool not committed */
+ gctUINT maxUnlockBytes;
+
+ gceENGINE engine;
+};
+
+struct _gcsTEMPCMDBUF
+{
+ gctUINT32 currentByteSize;
+ gctPOINTER buffer;
+ gctBOOL inUse;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_kernel_buffer_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_mem.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_mem.h
new file mode 100644
index 000000000000..51a1d8ddd64d
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_mem.h
@@ -0,0 +1,564 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+/*
+** Include file for the local memory management.
+*/
+
+#ifndef __gc_hal_mem_h_
+#define __gc_hal_mem_h_
+#if (gcdENABLE_3D || gcdENABLE_VG)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+** Usage:
+
+ The macros to declare MemPool type and functions are
+ gcmMEM_DeclareFSMemPool (Type, TypeName, Prefix)
+ gcmMEM_DeclareVSMemPool (Type, TypeName, Prefix)
+ gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix)
+
+ The data structures for MemPool are
+ typedef struct _gcsMEM_FS_MEM_POOL * gcsMEM_FS_MEM_POOL;
+ typedef struct _gcsMEM_VS_MEM_POOL * gcsMEM_VS_MEM_POOL;
+ typedef struct _gcsMEM_AFS_MEM_POOL * gcsMEM_AFS_MEM_POOL;
+
+ The MemPool constructor and destructor functions are
+ gcfMEM_InitFSMemPool(gcsMEM_FS_MEM_POOL *, gcoOS, gctUINT, gctUINT);
+ gcfMEM_FreeFSMemPool(gcsMEM_FS_MEM_POOL *);
+ gcfMEM_InitVSMemPool(gcsMEM_VS_MEM_POOL *, gcoOS, gctUINT, gctBOOL);
+ gcfMEM_FreeVSMemPool(gcsMEM_VS_MEM_POOL *);
+ gcfMEM_InitAFSMemPool(gcsMEM_AFS_MEM_POOL *, gcoOS, gctUINT);
+ gcfMEM_FreeAFSMemPool(gcsMEM_AFS_MEM_POOL *);
+
+ FS: for Fixed-Size data structures
+ VS: for Variable-size data structures
+ AFS: for Array of Fixed-Size data structures
+
+
+ // Example 1: For a fixed-size data structure, struct gcsNode.
+ // It is used locally in a file, so the functions are static without prefix.
+ // At top level, declear allocate and free functions.
+ // The first argument is the data type.
+ // The second armument is the short name used in the fuctions.
+ gcmMEM_DeclareFSMemPool(struct gcsNode, Node, );
+
+ // The previous macro creates two inline functions,
+ // _AllocateNode and _FreeNode.
+
+ // In function or struct
+ gcsMEM_FS_MEM_POOL nodeMemPool;
+
+ // In function,
+ struct gcsNode * node;
+ gceSTATUS status;
+
+ // Before using the memory pool, initialize it.
+ // The second argument is the gcoOS object.
+ // The third argument is the number of data structures to allocate for each chunk.
+ status = gcfMEM_InitFSMemPool(&nodeMemPool, os, 100, sizeof(struct gcsNode));
+ ...
+
+ // Allocate a node.
+ status = _AllocateNode(nodeMemPool, &node);
+ ...
+ // Free a node.
+ _FreeNode(nodeMemPool, node);
+
+ // After using the memory pool, free it.
+ gcfMEM_FreeFSMemPool(&nodeMemPool);
+
+
+ // Example 2: For array of fixed-size data structures, struct gcsNode.
+ // It is used in several files, so the functions are extern with prefix.
+ // At top level, declear allocate and free functions.
+ // The first argument is the data type, and the second one is the short name
+ // used in the fuctions.
+ gcmMEM_DeclareAFSMemPool(struct gcsNode, NodeArray, gcfOpt);
+
+ // The previous macro creates two inline functions,
+ // gcfOpt_AllocateNodeArray and gcfOpt_FreeNodeArray.
+
+ // In function or struct
+ gcsMEM_AFS_MEM_POOL nodeArrayMemPool;
+
+ // In function,
+ struct gcsNode * nodeArray;
+ gceSTATUS status;
+
+ // Before using the array memory pool, initialize it.
+ // The second argument is the gcoOS object, the third is the number of data
+ // structures to allocate for each chunk.
+ status = gcfMEM_InitAFSMemPool(&nodeArrayMemPool, os, sizeof(struct gcsNode));
+ ...
+
+ // Allocate a node array of size 100.
+ status = gcfOpt_AllocateNodeArray(nodeArrayMemPool, &nodeArray, 100);
+ ...
+ // Free a node array.
+ gcfOpt_FreeNodeArray(&nodeArrayMemPool, nodeArray);
+
+ // After using the array memory pool, free it.
+ gcfMEM_FreeAFSMemPool(&nodeArrayMemPool);
+
+*******************************************************************************/
+
+/*******************************************************************************
+** To switch back to use gcoOS_Allocate and gcoOS_Free, add
+** #define USE_LOCAL_MEMORY_POOL 0
+** before including this file.
+*******************************************************************************/
+#ifndef USE_LOCAL_MEMORY_POOL
+/*
+ USE_LOCAL_MEMORY_POOL
+
+ This define enables the local memory management to improve performance.
+*/
+#define USE_LOCAL_MEMORY_POOL 1
+#endif
+
+/*******************************************************************************
+** Memory Pool Data Structures
+*******************************************************************************/
+#if USE_LOCAL_MEMORY_POOL
+ typedef struct _gcsMEM_FS_MEM_POOL * gcsMEM_FS_MEM_POOL;
+ typedef struct _gcsMEM_VS_MEM_POOL * gcsMEM_VS_MEM_POOL;
+ typedef struct _gcsMEM_AFS_MEM_POOL * gcsMEM_AFS_MEM_POOL;
+#else
+ typedef gcoOS gcsMEM_FS_MEM_POOL;
+ typedef gcoOS gcsMEM_VS_MEM_POOL;
+ typedef gcoOS gcsMEM_AFS_MEM_POOL;
+#endif
+
+/*******************************************************************************
+** Memory Pool Macros
+*******************************************************************************/
+#if USE_LOCAL_MEMORY_POOL
+#define gcmMEM_DeclareFSMemPool(Type, TypeName, Prefix) \
+gceSTATUS \
+Prefix##_Allocate##TypeName( \
+ gcsMEM_FS_MEM_POOL MemPool, \
+ Type ** Pointer \
+ ) \
+{ \
+ return(gcfMEM_FSMemPoolGetANode(MemPool, (gctPOINTER *) Pointer)); \
+} \
+ \
+gceSTATUS \
+Prefix##_CAllocate##TypeName( \
+ gcsMEM_FS_MEM_POOL MemPool, \
+ Type ** Pointer \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \
+ gcmERR_RETURN(gcfMEM_FSMemPoolGetANode(MemPool, (gctPOINTER *) Pointer)); \
+ gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, gcmSIZEOF(Type)); \
+ gcmFOOTER(); \
+ return gcvSTATUS_OK; \
+} \
+ \
+gceSTATUS \
+Prefix##_Free##TypeName( \
+ gcsMEM_FS_MEM_POOL MemPool, \
+ Type * Pointer \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \
+ status = gcfMEM_FSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer); \
+ gcmFOOTER(); \
+ return status; \
+} \
+ \
+gceSTATUS \
+Prefix##_Free##TypeName##List( \
+ gcsMEM_FS_MEM_POOL MemPool, \
+ Type * FirstPointer, \
+ Type * LastPointer \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x FirstPointer=0x%x LastPointer=0x%x", MemPool, FirstPointer, LastPointer); \
+ status = gcfMEM_FSMemPoolFreeAList(MemPool, (gctPOINTER) FirstPointer, (gctPOINTER) LastPointer); \
+ gcmFOOTER(); \
+ return status; \
+}
+
+#define gcmMEM_DeclareVSMemPool(Type, TypeName, Prefix) \
+gceSTATUS \
+Prefix##_Allocate##TypeName( \
+ gcsMEM_FS_MEM_POOL MemPool, \
+ Type ** Pointer, \
+ gctUINT Size \
+ ) \
+{ \
+ gceSTATUS status;\
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Size=%u", MemPool, Pointer, Size); \
+ status = gcfMEM_VSMemPoolGetANode(MemPool, Size, (gctPOINTER *) Pointer); \
+ gcmFOOTER(); \
+ return status; \
+} \
+ \
+gceSTATUS \
+ Prefix##_CAllocate##TypeName( \
+ gcsMEM_FS_MEM_POOL MemPool, \
+ Type ** Pointer, \
+ gctUINT Size \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Size=%u", MemPool, Pointer, Size); \
+ gcmERR_RETURN(gcfMEM_VSMemPoolGetANode(MemPool, Size, (gctPOINTER *) Pointer)); \
+ gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, size); \
+ gcmFOOTER(); \
+ return gcvSTATUS_OK; \
+} \
+ \
+gceSTATUS \
+Prefix##_Free##TypeName( \
+ gcsMEM_FS_MEM_POOL MemPool, \
+ Type * Pointer \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pinter); \
+ status = gcfMEM_VSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer); \
+ gcmFOOTER(); \
+ return status; \
+}
+
+#define gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix) \
+gceSTATUS \
+Prefix##_Allocate##TypeName( \
+ gcsMEM_AFS_MEM_POOL MemPool, \
+ Type ** Pointer, \
+ gctUINT Count \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Count=%u", MemPool, Pointer, Count); \
+ status = gcfMEM_AFSMemPoolGetANode(MemPool, Count, (gctPOINTER *) Pointer); \
+ gcmFOOTER(); \
+ return status; \
+} \
+ \
+gceSTATUS \
+Prefix##_CAllocate##TypeName( \
+ gcsMEM_AFS_MEM_POOL MemPool, \
+ Type ** Pointer, \
+ gctUINT Count \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Count=%u", MemPool, Pointer, Count); \
+ gcmERR_RETURN(gcfMEM_AFSMemPoolGetANode(MemPool, Count, (gctPOINTER *) Pointer)); \
+ gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Count * gcmSIZEOF(Type)); \
+ gcmFOOTER(); \
+ return gcvSTATUS_OK; \
+} \
+ \
+gceSTATUS \
+Prefix##_Free##TypeName( \
+ gcsMEM_AFS_MEM_POOL MemPool, \
+ Type * Pointer \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \
+ status = gcfMEM_AFSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer); \
+ gcmFOOTER(); \
+ return status; \
+}
+
+#else
+
+#define gcmMEM_DeclareFSMemPool(Type, TypeName, Prefix) \
+gceSTATUS \
+Prefix##_Allocate##TypeName( \
+ gcsMEM_FS_MEM_POOL MemPool, \
+ Type ** Pointer \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \
+ status = gcoOS_Allocate(MemPool, \
+ gcmSIZEOF(Type), \
+ (gctPOINTER *) Pointer); \
+ gcmFOOTER(); \
+ return status; \
+} \
+ \
+gceSTATUS \
+Prefix##_CAllocate##TypeName( \
+ gcsMEM_FS_MEM_POOL MemPool, \
+ Type ** Pointer \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \
+ gcmERR_RETURN(gcoOS_Allocate(MemPool, \
+ gcmSIZEOF(Type), \
+ (gctPOINTER *) Pointer)); \
+ gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, gcmSIZEOF(Type)); \
+ gcmFOOTER(); \
+ return gcvSTATUS_OK; \
+} \
+ \
+gceSTATUS \
+Prefix##_Free##TypeName( \
+ gcsMEM_FS_MEM_POOL MemPool, \
+ Type * Pointer \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \
+ status = gcmOS_SAFE_FREE(MemPool, Pointer); \
+ gcmFOOTER(); \
+ return status; \
+}
+
+#define gcmMEM_DeclareVSMemPool(Type, TypeName, Prefix) \
+gceSTATUS \
+Prefix##_Allocate##TypeName( \
+ gcsMEM_VS_MEM_POOL MemPool, \
+ Type ** Pointer, \
+ gctUINT Size \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Size=%u", MemPool, Pointer, Size); \
+ status = gcoOS_Allocate(MemPool, \
+ Size, \
+ (gctPOINTER *) Pointer); \
+ gcmFOOTER(); \
+ return status; \
+} \
+ \
+gceSTATUS \
+Prefix##_CAllocate##TypeName( \
+ gcsMEM_VS_MEM_POOL MemPool, \
+ Type ** Pointer, \
+ gctUINT Size \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Size=%u", MemPool, Pointer, Size); \
+ gcmERR_RETURN(gcoOS_Allocate(MemPool, \
+ Size, \
+ (gctPOINTER *) Pointer)); \
+ gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Size); \
+ gcmFOOTER(); \
+ return gcvSTATUS_OK; \
+} \
+ \
+gceSTATUS \
+Prefix##_Free##TypeName( \
+ gcsMEM_VS_MEM_POOL MemPool, \
+ Type * Pointer \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \
+ status = gcmOS_SAFE_FREE(MemPool, Pointer); \
+ gcmFOOTER(); \
+ return status; \
+}
+
+#define gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix) \
+gceSTATUS \
+Prefix##_Allocate##TypeName( \
+ gcsMEM_AFS_MEM_POOL MemPool, \
+ Type ** Pointer, \
+ gctUINT Count \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Count=%u", MemPool, Pointer, Count); \
+ status = gcoOS_Allocate(MemPool, \
+ Count * gcmSIZEOF(Type), \
+ (gctPOINTER *) Pointer); \
+ gcmFOOTER(); \
+ return status; \
+} \
+ \
+gceSTATUS \
+Prefix##_CAllocate##TypeName( \
+ gcsMEM_AFS_MEM_POOL MemPool, \
+ Type ** Pointer, \
+ gctUINT Count \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Count=%u", MemPool, Pointer, Count); \
+ gcmERR_RETURN(gcoOS_Allocate(MemPool, \
+ Count * gcmSIZEOF(Type), \
+ (gctPOINTER *) Pointer)); \
+ gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Count * gcmSIZEOF(Type)); \
+ gcmFOOTER(); \
+ return gcvSTATUS_OK; \
+} \
+ \
+gceSTATUS \
+Prefix##_Free##TypeName( \
+ gcsMEM_AFS_MEM_POOL MemPool, \
+ Type * Pointer \
+ ) \
+{ \
+ gceSTATUS status; \
+ gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \
+ status = gcmOS_SAFE_FREE(MemPool, Pointer); \
+ gcmFOOTER(); \
+ return status; \
+}
+#endif
+
+/*******************************************************************************
+** Memory Pool Data Functions
+*******************************************************************************/
+gceSTATUS
+gcfMEM_InitFSMemPool(
+ IN gcsMEM_FS_MEM_POOL * MemPool,
+ IN gcoOS OS,
+ IN gctUINT NodeCount,
+ IN gctUINT NodeSize
+ );
+
+gceSTATUS
+gcfMEM_FreeFSMemPool(
+ IN gcsMEM_FS_MEM_POOL * MemPool
+ );
+
+gceSTATUS
+gcfMEM_FSMemPoolGetANode(
+ IN gcsMEM_FS_MEM_POOL MemPool,
+ OUT gctPOINTER * Node
+ );
+
+gceSTATUS
+gcfMEM_FSMemPoolFreeANode(
+ IN gcsMEM_FS_MEM_POOL MemPool,
+ IN gctPOINTER Node
+ );
+
+gceSTATUS
+gcfMEM_FSMemPoolFreeAList(
+ IN gcsMEM_FS_MEM_POOL MemPool,
+ IN gctPOINTER FirstNode,
+ IN gctPOINTER LastNode
+ );
+
+gceSTATUS
+gcfMEM_InitVSMemPool(
+ IN gcsMEM_VS_MEM_POOL * MemPool,
+ IN gcoOS OS,
+ IN gctUINT BlockSize,
+ IN gctBOOL RecycleFreeNode
+ );
+
+gceSTATUS
+gcfMEM_FreeVSMemPool(
+ IN gcsMEM_VS_MEM_POOL * MemPool
+ );
+
+gceSTATUS
+gcfMEM_VSMemPoolGetANode(
+ IN gcsMEM_VS_MEM_POOL MemPool,
+ IN gctUINT Size,
+ IN gctUINT Alignment,
+ OUT gctPOINTER * Node
+ );
+
+gceSTATUS
+gcfMEM_VSMemPoolFreeANode(
+ IN gcsMEM_VS_MEM_POOL MemPool,
+ IN gctPOINTER Node
+ );
+
+gceSTATUS
+gcfMEM_InitAFSMemPool(
+ IN gcsMEM_AFS_MEM_POOL *MemPool,
+ IN gcoOS OS,
+ IN gctUINT NodeCount,
+ IN gctUINT NodeSize
+ );
+
+gceSTATUS
+gcfMEM_FreeAFSMemPool(
+ IN gcsMEM_AFS_MEM_POOL *MemPool
+ );
+
+gceSTATUS
+gcfMEM_AFSMemPoolGetANode(
+ IN gcsMEM_AFS_MEM_POOL MemPool,
+ IN gctUINT Count,
+ OUT gctPOINTER * Node
+ );
+
+gceSTATUS
+gcfMEM_AFSMemPoolFreeANode(
+ IN gcsMEM_AFS_MEM_POOL MemPool,
+ IN gctPOINTER Node
+ );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* (gcdENABLE_3D || gcdENABLE_VG) */
+#endif /* __gc_hal_mem_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_options.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_options.h
new file mode 100644
index 000000000000..4a11200d7fb5
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_options.h
@@ -0,0 +1,1404 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_options_h_
+#define __gc_hal_options_h_
+
+/*
+ gcdSECURITY
+
+*/
+#ifndef gcdSECURITY
+# define gcdSECURITY 0
+#endif
+
+/*
+ gcdPRINT_VERSION
+
+ Print HAL version.
+*/
+#ifndef gcdPRINT_VERSION
+# define gcdPRINT_VERSION 0
+#endif
+
+/*
+USE_KERNEL_VIRTUAL_BUFFERS
+
+This define enables the use of VM for gckCommand and fence buffers.
+*/
+#ifndef USE_KERNEL_VIRTUAL_BUFFERS
+#if defined(UNDER_CE)
+# define USE_KERNEL_VIRTUAL_BUFFERS 1
+#else
+# define USE_KERNEL_VIRTUAL_BUFFERS 1
+#endif
+#endif
+
+/*
+ USE_NEW_LINUX_SIGNAL
+
+ This define enables the Linux kernel signaling between kernel and user.
+*/
+#ifndef USE_NEW_LINUX_SIGNAL
+# define USE_NEW_LINUX_SIGNAL 0
+#endif
+
+/*
+ USE_LINUX_PCIE
+
+ This define enables galcore as a Linux PCIE driver.
+*/
+#ifndef USE_LINUX_PCIE
+# define USE_LINUX_PCIE 0
+#endif
+
+/*
+ VIVANTE_PROFILER
+
+ This define enables the profiler.
+*/
+#ifndef VIVANTE_PROFILER
+# define VIVANTE_PROFILER 1
+#endif
+
+/*
+ gcdUSE_VG
+
+ Enable VG HAL layer (only for GC350).
+*/
+#ifndef gcdUSE_VG
+# define gcdUSE_VG 0
+#endif
+
+/*
+ gcdUSE_VX
+
+ Enable VX HAL layer.
+*/
+#ifndef gcdUSE_VX
+# define gcdUSE_VX 1
+#endif
+
+/*
+ PROFILE_HAL_COUNTERS
+
+ This define enables HAL counter profiling support. HW and SHADER
+ counter profiling depends on this.
+*/
+#ifndef PROFILE_HAL_COUNTERS
+# define PROFILE_HAL_COUNTERS 1
+#endif
+
+/*
+ PROFILE_HW_COUNTERS
+
+ This define enables HW counter profiling support.
+*/
+#ifndef PROFILE_HW_COUNTERS
+# define PROFILE_HW_COUNTERS 1
+#endif
+
+/*
+ PROFILE_SHADER_COUNTERS
+
+ This define enables SHADER counter profiling support.
+*/
+#ifndef PROFILE_SHADER_COUNTERS
+# define PROFILE_SHADER_COUNTERS 1
+#endif
+
+/*
+ COMMAND_PROCESSOR_VERSION
+
+ The version of the command buffer and task manager.
+*/
+#define COMMAND_PROCESSOR_VERSION 1
+
+/*
+ gcdDUMP_KEY
+
+ Set this to a string that appears in 'cat /proc/<pid>/cmdline'. E.g. 'camera'.
+ HAL will create dumps for the processes matching this key.
+*/
+#ifndef gcdDUMP_KEY
+# define gcdDUMP_KEY "process"
+#endif
+
+/*
+ gcdDUMP_PATH
+
+ The dump file location. Some processes cannot write to the sdcard.
+ Try apps' data dir, e.g. /data/data/com.android.launcher
+*/
+#ifndef gcdDUMP_PATH
+#if defined(ANDROID)
+# define gcdDUMP_PATH "/mnt/sdcard/"
+#else
+# define gcdDUMP_PATH "./"
+#endif
+#endif
+
+/*
+ gcdDUMP
+
+ When set to 1, a dump of all states and memory uploads, as well as other
+ hardware related execution will be printed to the debug console. This
+ data can be used for playing back applications.
+
+ When set to 2, for vxc, all output memory will be dump.
+
+*/
+#ifndef gcdDUMP
+# define gcdDUMP 0
+#endif
+
+/*
+ gcdDUMP_API
+
+ When set to 1, a high level dump of the EGL and GL/VG APs's are
+ captured.
+*/
+#ifndef gcdDUMP_API
+# define gcdDUMP_API 0
+#endif
+
+#ifndef gcdDUMP_2DVG
+# define gcdDUMP_2DVG 0
+#endif
+
+/*
+ gcdDUMP_AHB_ACCESS
+
+ When set to 1, a dump of all AHB register access will be printed to kernel
+ message.
+*/
+#ifndef gcdDUMP_AHB_ACCESS
+# define gcdDUMP_AHB_ACCESS 0
+#endif
+
+/*
+ gcdDEBUG_OPTION
+ When set to 1, the debug options are enabled. We must set other MACRO to enable
+ sub case.
+*/
+#ifndef gcdDEBUG_OPTION
+# define gcdDEBUG_OPTION 0
+
+#if gcdDEBUG_OPTION
+/*
+ gcdDEBUG_OPTION_KEY
+ The process name of debug application.
+*/
+#ifndef gcdDEBUG_OPTION_KEY
+# define gcdDEBUG_OPTION_KEY "process"
+# endif
+/*
+ gcdDEBUG_OPTION_NO_GL_DRAWS
+ When set to 1, all glDrawArrays and glDrawElements will be skip.
+*/
+#ifndef gcdDEBUG_OPTION_NO_GL_DRAWS
+# define gcdDEBUG_OPTION_NO_GL_DRAWS 0
+# endif
+/*
+ gcdDEBUG_OPTION_NO_DRAW_PRIMITIVES
+ When set to 1, all DrawPrimitives will be skip.
+*/
+#ifndef gcdDEBUG_OPTION_NO_DRAW_PRIMITIVES
+# define gcdDEBUG_OPTION_NO_DRAW_PRIMITIVES 0
+# endif
+/*
+ gcdDEBUG_OPTION_SKIP_SWAP
+ When set to 1, just one out of gcdDEBUG_OPTION_SKIP_FRAMES(such as 1/10) eglSwapBuffers will be resolve,
+ others skip.
+*/
+#ifndef gcdDEBUG_OPTION_SKIP_SWAP
+# define gcdDEBUG_OPTION_SKIP_SWAP 0
+# define gcdDEBUG_OPTION_SKIP_FRAMES 10
+# endif
+/*
+ gcdDEBUG_OPTION_FORCE_16BIT_RENDER_TARGET
+ When set to 1, the format of render target will force to RGB565.
+*/
+#ifndef gcdDEBUG_OPTION_FORCE_16BIT_RENDER_TARGET
+# define gcdDEBUG_OPTION_FORCE_16BIT_RENDER_TARGET 0
+# endif
+/*
+ gcdDEBUG_OPTION_NONE_TEXTURE
+ When set to 1, the type of texture will be set to AQ_TEXTURE_SAMPLE_MODE_TYPE_NONE.
+*/
+#ifndef gcdDEBUG_OPTION_NONE_TEXTURE
+# define gcdDEBUG_OPTION_NONE_TEXTURE 0
+# endif
+/*
+ gcdDEBUG_OPTION_NONE_DEPTH
+ When set to 1, the depth format of surface will be set to gcvSURF_UNKNOWN.
+*/
+#ifndef gcdDEBUG_OPTION_NONE_DEPTH
+# define gcdDEBUG_OPTION_NONE_DEPTH 0
+# endif
+
+/*
+ gcdDEBUG_FORCE_CONTEXT_UPDATE
+ When set to 1, context will be updated before every commit.
+*/
+#ifndef gcdDEBUG_FORCE_CONTEXT_UPDATE
+# define gcdDEBUG_FORCE_CONTEXT_UPDATE 0
+# endif
+
+
+/*
+ gcdDEBUG_FORCE_CONTEXT_UPDATE
+ When set to 1, pool of each type surface can be specified by
+ changing poolPerType[] in gcsSURF_NODE_Construct.
+*/
+#ifndef gcdDEBUG_OPTION_SPECIFY_POOL
+# define gcdDEBUG_OPTION_SPECIFY_POOL 0
+# endif
+
+# endif
+#endif
+
+/*
+ gcdDUMP_VERIFY_PER_DRAW
+
+ When set to 1, verify RT and images(if used) for every single draw to ease simulation debug.
+ Only valid for ES3 driver for now.
+*/
+#ifndef gcdDUMP_VERIFY_PER_DRAW
+# define gcdDUMP_VERIFY_PER_DRAW 0
+#endif
+
+
+
+/*
+ gcdDUMP_FRAMERATE
+ When set to a value other than zero, averaqe frame rate will be dumped.
+ The value set is the starting frame that the average will be calculated.
+ This is needed because sometimes first few frames are too slow to be included
+ in the average. Frame count starts from 1.
+*/
+#ifndef gcdDUMP_FRAMERATE
+# define gcdDUMP_FRAMERATE 0
+#endif
+
+/*
+ gcdENABLE_FSCALE_VAL_ADJUST
+ When non-zero, FSCALE_VAL when gcvPOWER_ON can be adjusted externally.
+ */
+#ifndef gcdENABLE_FSCALE_VAL_ADJUST
+# define gcdENABLE_FSCALE_VAL_ADJUST 1
+#endif
+
+/*
+ gcdDUMP_IN_KERNEL
+
+ When set to 1, all dumps will happen in the kernel. This is handy if
+ you want the kernel to dump its command buffers as well and the data
+ needs to be in sync.
+*/
+#ifndef gcdDUMP_IN_KERNEL
+# define gcdDUMP_IN_KERNEL 0
+#endif
+
+/*
+ gcdDUMP_COMMAND
+
+ When set to non-zero, the command queue will dump all incoming command
+ and context buffers as well as all other modifications to the command
+ queue.
+*/
+#ifndef gcdDUMP_COMMAND
+# define gcdDUMP_COMMAND 0
+#endif
+
+/*
+ gcdDUMP_2D
+
+ When set to non-zero, it will dump the 2D command and surface.
+*/
+#ifndef gcdDUMP_2D
+# define gcdDUMP_2D 0
+#endif
+
+/*
+ gcdDUMP_FRAME_TGA
+
+ When set to a value other than 0, a dump of the frame specified by the value,
+ will be done into frame.tga. Frame count starts from 1.
+ */
+#ifndef gcdDUMP_FRAME_TGA
+# define gcdDUMP_FRAME_TGA 0
+#endif
+/*
+ gcdNULL_DRIVER
+
+ Set to 1 for infinite speed hardware.
+ Set to 2 for bypassing the HAL.
+*/
+#ifndef gcdNULL_DRIVER
+# define gcdNULL_DRIVER 0
+#endif
+
+/*
+ gcdENABLE_TIMEOUT_DETECTION
+
+ Enable timeout detection.
+*/
+#ifndef gcdENABLE_TIMEOUT_DETECTION
+# define gcdENABLE_TIMEOUT_DETECTION 0
+#endif
+
+/*
+ gcdCMD_BUFFER_SIZE
+
+ Number of bytes in a command buffer.
+*/
+#ifndef gcdCMD_BUFFER_SIZE
+# define gcdCMD_BUFFER_SIZE (128 << 10)
+#endif
+
+/*
+ gcdCMD_BLT_BUFFER_SIZE
+
+ Number of bytes in a command buffer.
+*/
+#ifndef gcdCMD_BLT_BUFFER_SIZE
+# define gcdCMD_BLT_BUFFER_SIZE (1 << 10)
+#endif
+
+/*
+ gcdCMD_BUFFERS
+
+ Number of command buffers to use per client.
+*/
+#ifndef gcdCMD_BUFFERS
+# define gcdCMD_BUFFERS 2
+#endif
+
+/*
+ gcdMAX_CMD_BUFFERS
+
+ Maximum number of command buffers to use per client.
+*/
+#ifndef gcdMAX_CMD_BUFFERS
+# define gcdMAX_CMD_BUFFERS 8
+#endif
+
+/*
+ gcdCOMMAND_QUEUES
+
+ Number of command queues in the kernel.
+*/
+#ifndef gcdCOMMAND_QUEUES
+# define gcdCOMMAND_QUEUES 2
+#endif
+
+/*
+ gcdPOWER_CONTROL_DELAY
+
+ The delay in milliseconds required to wait until the GPU has woke up
+ from a suspend or power-down state. This is system dependent because
+ the bus clock also needs to stabalize.
+*/
+#ifndef gcdPOWER_CONTROL_DELAY
+# define gcdPOWER_CONTROL_DELAY 0
+#endif
+
+/*
+ gcdMMU_SIZE
+
+ Size of the MMU page table in bytes. Each 4 bytes can hold 4kB worth of
+ virtual data.
+*/
+#ifndef gcdMMU_SIZE
+# define gcdMMU_SIZE (2048 << 10)
+#endif
+
+#ifndef gcdGC355_VGMMU_MEMORY_SIZE_KB
+# define gcdGC355_VGMMU_MEMORY_SIZE_KB 32
+#endif
+/*
+ gcdSECURE_USER
+
+ Use logical addresses instead of physical addresses in user land. In
+ this case a hint table is created for both command buffers and context
+ buffers, and that hint table will be used to patch up those buffers in
+ the kernel when they are ready to submit.
+*/
+#ifndef gcdSECURE_USER
+# define gcdSECURE_USER 0
+#endif
+
+/*
+ gcdSECURE_CACHE_SLOTS
+
+ Number of slots in the logical to DMA address cache table. Each time a
+ logical address needs to be translated into a DMA address for the GPU,
+ this cache will be walked. The replacement scheme is LRU.
+*/
+#ifndef gcdSECURE_CACHE_SLOTS
+# define gcdSECURE_CACHE_SLOTS 1024
+#endif
+
+/*
+ gcdSECURE_CACHE_METHOD
+
+ Replacement scheme used for Secure Cache. The following options are
+ available:
+
+ gcdSECURE_CACHE_LRU
+ A standard LRU cache.
+
+ gcdSECURE_CACHE_LINEAR
+ A linear walker with the idea that an application will always
+ render the scene in a similar way, so the next entry in the
+ cache should be a hit most of the time.
+
+ gcdSECURE_CACHE_HASH
+ A 256-entry hash table.
+
+ gcdSECURE_CACHE_TABLE
+ A simple cache but with potential of a lot of cache replacement.
+*/
+#ifndef gcdSECURE_CACHE_METHOD
+# define gcdSECURE_CACHE_METHOD gcdSECURE_CACHE_HASH
+#endif
+
+/*
+ gcdREGISTER_ACCESS_FROM_USER
+
+ Set to 1 to allow IOCTL calls to get through from user land. This
+ should only be in debug or development drops.
+*/
+#ifndef gcdREGISTER_ACCESS_FROM_USER
+# define gcdREGISTER_ACCESS_FROM_USER 1
+#endif
+
+/*
+ gcdHEAP_SIZE
+
+ Set the allocation size for the internal heaps. Each time a heap is
+ full, a new heap will be allocated with this minmimum amount of bytes.
+ The bigger this size, the fewer heaps there are to allocate, the better
+ the performance. However, heaps won't be freed until they are
+ completely free, so there might be some more memory waste if the size is
+ too big.
+*/
+#ifndef gcdHEAP_SIZE
+# define gcdHEAP_SIZE (64 << 10)
+#endif
+
+/*
+ gcdPOWER_SUSPEND_WHEN_IDLE
+
+ Set to 1 to make GPU enter gcvPOWER_SUSPEND when idle detected,
+ otherwise GPU will enter gcvPOWER_IDLE.
+*/
+#ifndef gcdPOWER_SUSPEND_WHEN_IDLE
+# define gcdPOWER_SUSPEND_WHEN_IDLE 1
+#endif
+
+#ifndef gcdFPGA_BUILD
+# define gcdFPGA_BUILD 0
+#endif
+
+/*
+ gcdGPU_TIMEOUT
+
+ This define specified the number of milliseconds the system will wait
+ before it broadcasts the GPU is stuck. In other words, it will define
+ the timeout of any operation that needs to wait for the GPU.
+
+ If the value is 0, no timeout will be checked for.
+*/
+#ifndef gcdGPU_TIMEOUT
+# define gcdGPU_TIMEOUT 20000
+#endif
+
+/*
+ gcdGPU_2D_TIMEOUT
+
+ This define specified the number of milliseconds the system will wait
+ before it broadcasts the 2D GPU is stuck. In other words, it will define
+ the timeout of any operation that needs to wait for the GPU.
+
+ If the value is 0, no timeout will be checked for.
+*/
+#ifndef gcdGPU_2D_TIMEOUT
+# define gcdGPU_2D_TIMEOUT 4000
+#endif
+
+
+/*
+ gcdGPU_ADVANCETIMER
+
+ it is advance timer.
+*/
+#ifndef gcdGPU_ADVANCETIMER
+# define gcdGPU_ADVANCETIMER 250
+#endif
+
+/*
+ gcdSTATIC_LINK
+
+ This define disalbes static linking;
+*/
+#ifndef gcdSTATIC_LINK
+# define gcdSTATIC_LINK 0
+#endif
+
+/*
+ gcdUSE_NEW_HEAP
+
+ Setting this define to 1 enables new heap.
+*/
+#ifndef gcdUSE_NEW_HEAP
+# define gcdUSE_NEW_HEAP 0
+#endif
+
+/*
+ gcdCMD_NO_2D_CONTEXT
+
+ This define enables no-context 2D command buffer.
+*/
+#ifndef gcdCMD_NO_2D_CONTEXT
+# define gcdCMD_NO_2D_CONTEXT 1
+#endif
+
+/*
+ gcdENABLE_BUFFER_ALIGNMENT
+
+ When enabled, video memory is allocated with atleast 16KB aligment
+ between multiple sub-buffers.
+*/
+#ifndef gcdENABLE_BUFFER_ALIGNMENT
+# define gcdENABLE_BUFFER_ALIGNMENT 1
+#endif
+
+/*
+ gcdENABLE_BANK_ALIGNMENT
+
+ When enabled, video memory is allocated bank aligned. The vendor can modify
+ _GetSurfaceBankAlignment() and _GetBankOffsetBytes() to define how
+ different types of allocations are bank and channel aligned.
+ When disabled (default), no bank alignment is done.
+*/
+#ifndef gcdENABLE_BANK_ALIGNMENT
+# define gcdENABLE_BANK_ALIGNMENT 0
+#endif
+
+/*
+ gcdBANK_BIT_START
+
+ Specifies the start bit of the bank (inclusive).
+*/
+#ifndef gcdBANK_BIT_START
+# define gcdBANK_BIT_START 12
+#endif
+
+/*
+ gcdBANK_BIT_END
+
+ Specifies the end bit of the bank (inclusive).
+*/
+#ifndef gcdBANK_BIT_END
+# define gcdBANK_BIT_END 14
+#endif
+
+/*
+ gcdBANK_CHANNEL_BIT
+
+ When set, video memory when allocated bank aligned is allocated such that
+ render and depth buffer addresses alternate on the channel bit specified.
+ This option has an effect only when gcdENABLE_BANK_ALIGNMENT is enabled.
+ When disabled (default), no alteration is done.
+*/
+#ifndef gcdBANK_CHANNEL_BIT
+# define gcdBANK_CHANNEL_BIT 7
+#endif
+
+/*
+ gcdDYNAMIC_SPEED
+
+ When non-zero, it informs the kernel driver to use the speed throttling
+ broadcasting functions to inform the system the GPU should be spet up or
+ slowed down. It will send a broadcast for slowdown each "interval"
+ specified by this define in milliseconds
+ (gckOS_BroadcastCalibrateSpeed).
+*/
+#ifndef gcdDYNAMIC_SPEED
+# define gcdDYNAMIC_SPEED 2000
+#endif
+
+/*
+ gcdDYNAMIC_EVENT_THRESHOLD
+
+ When non-zero, it specifies the maximum number of available events at
+ which the kernel driver will issue a broadcast to speed up the GPU
+ (gckOS_BroadcastHurry).
+*/
+#ifndef gcdDYNAMIC_EVENT_THRESHOLD
+# define gcdDYNAMIC_EVENT_THRESHOLD 5
+#endif
+
+/*
+ gcdENABLE_PROFILING
+
+ Enable profiling macros.
+*/
+#ifndef gcdENABLE_PROFILING
+# define gcdENABLE_PROFILING 0
+#endif
+
+/*
+ gcdENABLE_128B_MERGE
+
+ Enable 128B merge for the BUS control.
+*/
+#ifndef gcdENABLE_128B_MERGE
+# define gcdENABLE_128B_MERGE 0
+#endif
+
+/*
+ gcdFRAME_DB
+
+ When non-zero, it specified the number of frames inside the frame
+ database. The frame DB will collect per-frame timestamps and hardware
+ counters.
+*/
+#ifndef gcdFRAME_DB
+# define gcdFRAME_DB 0
+# define gcdFRAME_DB_RESET 0
+# define gcdFRAME_DB_NAME "/var/log/frameDB.log"
+#endif
+
+/*
+ gcdPAGED_MEMORY_CACHEABLE
+
+ When non-zero, paged memory will be cacheable.
+
+ Normally, driver will detemines whether a video memory
+ is cacheable or not. When cacheable is not neccessary,
+ it will be writecombine.
+
+ This option is only for those SOC which can't enable
+ writecombine without enabling cacheable.
+*/
+#ifndef gcdPAGED_MEMORY_CACHEABLE
+# define gcdPAGED_MEMORY_CACHEABLE 0
+#endif
+
+/*
+ gcdNONPAGED_MEMORY_CACHEABLE
+
+ When non-zero, non paged memory will be cacheable.
+*/
+#ifndef gcdNONPAGED_MEMORY_CACHEABLE
+# define gcdNONPAGED_MEMORY_CACHEABLE 0
+#endif
+
+/*
+ gcdNONPAGED_MEMORY_BUFFERABLE
+
+ When non-zero, non paged memory will be bufferable.
+ gcdNONPAGED_MEMORY_BUFFERABLE and gcdNONPAGED_MEMORY_CACHEABLE
+ can't be set 1 at same time
+*/
+#ifndef gcdNONPAGED_MEMORY_BUFFERABLE
+# define gcdNONPAGED_MEMORY_BUFFERABLE 1
+#endif
+
+/*
+ gcdENABLE_INFINITE_SPEED_HW
+ enable the Infinte HW , this is for 2D openVG
+*/
+#ifndef gcdENABLE_INFINITE_SPEED_HW
+# define gcdENABLE_INFINITE_SPEED_HW 0
+#endif
+
+/*
+ gcdPOWEROFF_TIMEOUT
+
+ When non-zero, GPU will power off automatically from
+ idle state, and gcdPOWEROFF_TIMEOUT is also the default
+ timeout in milliseconds.
+ */
+#ifndef gcdPOWEROFF_TIMEOUT
+# define gcdPOWEROFF_TIMEOUT 300
+#endif
+
+/*
+ QNX_SINGLE_THREADED_DEBUGGING
+*/
+#ifndef QNX_SINGLE_THREADED_DEBUGGING
+# define QNX_SINGLE_THREADED_DEBUGGING 0
+#endif
+
+/*
+ gcdSHARED_RESOLVE_BUFFER_ENABLED
+
+ Use shared resolve buffer for all app buffers.
+*/
+#ifndef gcdSHARED_RESOLVE_BUFFER_ENABLED
+# define gcdSHARED_RESOLVE_BUFFER_ENABLED 0
+#endif
+
+/*
+ gcdUSE_TRIANGLE_STRIP_PATCH
+ */
+#ifndef gcdUSE_TRIANGLE_STRIP_PATCH
+# define gcdUSE_TRIANGLE_STRIP_PATCH 1
+#endif
+
+/*
+ gcdPROCESS_ADDRESS_SPACE
+
+ When non-zero, every process which attaches to galcore has its own GPU
+ address space, size of which is gcdPROCESS_ADDRESS_SPACE_SIZE.
+*/
+#ifndef gcdPROCESS_ADDRESS_SPACE
+# define gcdPROCESS_ADDRESS_SPACE 0
+# define gcdPROCESS_ADDRESS_SPACE_SIZE 0x80000000
+#endif
+
+/*
+ gcdSHARED_PAGETABLE
+
+ When non-zero, multiple GPUs in one chip with same MMU use
+ one shared pagetable. So that when accessing same surface,
+ they can use same GPU virtual address.
+*/
+#ifndef gcdSHARED_PAGETABLE
+# define gcdSHARED_PAGETABLE 0
+#endif
+
+#ifndef gcdUSE_PVR
+# define gcdUSE_PVR 1
+#endif
+
+/*
+ gcdSMALL_BLOCK_SIZE
+
+ When non-zero, a part of VIDMEM will be reserved for requests
+ whose requesting size is less than gcdSMALL_BLOCK_SIZE.
+
+ For Linux, it's the size of a page. If this requeset fallbacks
+ to gcvPOOL_CONTIGUOUS or gcvPOOL_VIRTUAL, memory will be wasted
+ because they allocate a page at least.
+*/
+#ifndef gcdSMALL_BLOCK_SIZE
+# define gcdSMALL_BLOCK_SIZE 4096
+# define gcdRATIO_FOR_SMALL_MEMORY 32
+#endif
+
+/*
+ gcdCONTIGUOUS_SIZE_LIMIT
+ When non-zero, size of video node from gcvPOOL_CONTIGUOUS is
+ limited by gcdCONTIGUOUS_SIZE_LIMIT.
+*/
+#ifndef gcdCONTIGUOUS_SIZE_LIMIT
+# define gcdCONTIGUOUS_SIZE_LIMIT 0
+#endif
+
+/*
+ gcdLINK_QUEUE_SIZE
+
+ When non-zero, driver maintains a queue to record information of
+ latest lined context buffer and command buffer. Data in this queue
+ is be used to debug.
+*/
+#ifndef gcdLINK_QUEUE_SIZE
+# define gcdLINK_QUEUE_SIZE 64
+#endif
+
+/* gcdALPHA_KILL_IN_SHADER
+
+ Enable alpha kill inside the shader. This will be set automatically by the
+ HAL if certain states match a criteria.
+*/
+#ifndef gcdALPHA_KILL_IN_SHADER
+# define gcdALPHA_KILL_IN_SHADER 1
+#endif
+
+
+#ifndef gcdPRINT_SWAP_TIME
+# define gcdPRINT_SWAP_TIME 0
+#endif
+
+/*
+ gcdDVFS
+
+ When non-zero, software will make use of dynamic voltage and
+ frequency feature.
+ */
+#ifndef gcdDVFS
+# define gcdDVFS 0
+# define gcdDVFS_ANAYLSE_WINDOW 4
+# define gcdDVFS_POLLING_TIME (gcdDVFS_ANAYLSE_WINDOW * 4)
+#endif
+
+#ifndef gcdSYNC
+# define gcdSYNC 1
+#endif
+
+#ifndef gcdSHADER_SRC_BY_MACHINECODE
+# define gcdSHADER_SRC_BY_MACHINECODE 1
+#endif
+
+#ifndef gcdGLB27_SHADER_REPLACE_OPTIMIZATION
+# define gcdGLB27_SHADER_REPLACE_OPTIMIZATION 1
+#endif
+
+
+/*
+ gcdSUPPORT_SWAP_RECTANGLE
+
+ Support swap with a specific rectangle.
+
+ Set the rectangle with eglSetSwapRectangleVIV api.
+ Android only.
+*/
+#ifndef gcdSUPPORT_SWAP_RECTANGLE
+# define gcdSUPPORT_SWAP_RECTANGLE 1
+#endif
+
+/*
+ gcdGPU_LINEAR_BUFFER_ENABLED
+
+ Use linear buffer for GPU apps so HWC can do 2D composition.
+ Android only.
+*/
+#ifndef gcdGPU_LINEAR_BUFFER_ENABLED
+# define gcdGPU_LINEAR_BUFFER_ENABLED 1
+#endif
+
+/*
+ gcdENABLE_RENDER_INTO_WINDOW
+
+ Enable Render-Into-Window (ie, No-Resolve) feature on android.
+ NOTE that even if enabled, it still depends on hardware feature and
+ android application behavior. When hardware feature or application
+ behavior can not support render into window mode, it will fail back
+ to normal mode.
+ When Render-Into-Window is finally used, window back buffer of android
+ applications will be allocated matching render target tiling format.
+ Otherwise buffer tiling is decided by the above option
+ 'gcdGPU_LINEAR_BUFFER_ENABLED'.
+ Android only for now.
+*/
+#ifndef gcdENABLE_RENDER_INTO_WINDOW
+# define gcdENABLE_RENDER_INTO_WINDOW 1
+#endif
+
+/*
+ gcdENABLE_RENDER_INTO_WINDOW_WITH_FC
+
+ Enable Direct-rendering (ie, No-Resolve) with tile status.
+ This is expremental and in development stage.
+ This will dynamically check if color compression is available.
+*/
+#ifndef gcdENABLE_RENDER_INTO_WINDOW_WITH_FC
+# define gcdENABLE_RENDER_INTO_WINDOW_WITH_FC 1
+#endif
+
+/*
+ gcdENABLE_BLIT_BUFFER_PRESERVE
+
+ Render-Into-Window (ie, No-Resolve) does not include preserved swap
+ behavior. This feature can enable buffer preserve in No-Resolve mode.
+ When enabled, previous buffer (may be part of ) will be resolve-blitted
+ to current buffer.
+*/
+#ifndef gcdENABLE_BLIT_BUFFER_PRESERVE
+# define gcdENABLE_BLIT_BUFFER_PRESERVE 1
+#endif
+
+/*
+ gcdANDROID_NATIVE_FENCE_SYNC
+
+ Enable android native fence sync. It is introduced since jellybean-4.2.
+ Depends on linux kernel option: CONFIG_SYNC.
+
+ 0: Disabled
+ 1: Build framework for native fence sync feature, and EGL extension
+ 2: Enable async swap buffers for client
+ * Native fence sync for client 'queueBuffer' in EGL, which is
+ 'acquireFenceFd' for layer in compositor side.
+ 3. Enable async hwcomposer composition.
+ * 'releaseFenceFd' for layer in compositor side, which is native
+ fence sync when client 'dequeueBuffer'
+ * Native fence sync for compositor 'queueBuffer' in EGL, which is
+ 'acquireFenceFd' for framebuffer target for DC
+ */
+#ifndef gcdANDROID_NATIVE_FENCE_SYNC
+# define gcdANDROID_NATIVE_FENCE_SYNC 0
+#endif
+
+/*
+ gcdANDROID_IMPLICIT_NATIVE_BUFFER_SYNC
+
+ Enable implicit android native buffer sync.
+
+ For non-HW_RENDER buffer, CPU (or other hardware) and GPU can access
+ the buffer at the same time. This is to add implicit synchronization
+ between CPU (or the hardware) and GPU.
+
+ Eventually, please do not use implicit native buffer sync, but use
+ "fence sync" or "android native fence sync" instead in libgui, which
+ can be enabled in frameworks/native/libs/gui/Android.mk. This kind
+ of synchronization should be done by app but not driver itself.
+
+ Please disable this option when either "fence sync" or
+ "android native fence sync" is enabled.
+ */
+#ifndef gcdANDROID_IMPLICIT_NATIVE_BUFFER_SYNC
+# define gcdANDROID_IMPLICIT_NATIVE_BUFFER_SYNC 1
+#endif
+
+/*
+ * Implicit native buffer sync is not needed when ANDROID_native_fence_sync
+ * is available.
+ */
+#if gcdANDROID_NATIVE_FENCE_SYNC
+# undef gcdANDROID_IMPLICIT_NATIVE_BUFFER_SYNC
+# define gcdANDROID_IMPLICIT_NATIVE_BUFFER_SYNC 0
+#endif
+
+/*
+ gcdUSE_WCLIP_PATCH
+
+ Enable wclipping patch.
+*/
+#ifndef gcdUSE_WCLIP_PATCH
+# define gcdUSE_WCLIP_PATCH 1
+#endif
+
+#ifndef gcdUSE_NPOT_PATCH
+# define gcdUSE_NPOT_PATCH 1
+#endif
+
+/*
+ gcdINTERNAL_COMMENT
+
+ Wrap internal comment, content wrapped by it and the macor itself
+ will be removed in release driver.
+*/
+#ifndef gcdINTERNAL_COMMENT
+# define gcdINTERNAL_COMMENT 1
+#endif
+
+/*
+ gcdRTT_DISABLE_FC
+
+ Disable RTT FC support. For test only.
+*/
+#ifndef gcdRTT_DISABLE_FC
+# define gcdRTT_DISABLE_FC 0
+#endif
+
+/*
+ gcdFORCE_MIPMAP
+
+ Force generate mipmap for texture.
+*/
+#ifndef gcdFORCE_MIPMAP
+# define gcdFORCE_MIPMAP 0
+#endif
+
+/*
+ gcdFORCE_BILINEAR
+
+ Force bilinear for mipfilter.
+*/
+#ifndef gcdFORCE_BILINEAR
+# define gcdFORCE_BILINEAR 1
+#endif
+
+/*
+ gcdBINARY_TRACE
+
+ When non-zero, binary trace will be generated.
+
+ When gcdBINARY_TRACE_FILE_SIZE is non-zero, binary trace buffer will
+ be written to a file which size is limited to
+ gcdBINARY_TRACE_FILE_SIZE.
+*/
+#ifndef gcdBINARY_TRACE
+# define gcdBINARY_TRACE 0
+# define gcdBINARY_TRACE_FILE_SIZE 0
+#endif
+
+#ifndef gcdMOVG
+# define gcdMOVG 0
+# define gcdENABLE_TS_DOUBLE_BUFFER 1
+#else
+#if gcdMOVG
+# define gcdENABLE_TS_DOUBLE_BUFFER 0
+#else
+# define gcdENABLE_TS_DOUBLE_BUFFER 1
+#endif
+#endif
+
+/* gcdINTERRUPT_STATISTIC
+ *
+ * Monitor the event send to GPU and interrupt issued by GPU.
+ */
+
+#ifndef gcdINTERRUPT_STATISTIC
+#if defined(LINUX) || defined(__QNXNTO__) || defined(UNDER_CE)
+# define gcdINTERRUPT_STATISTIC 1
+#else
+# define gcdINTERRUPT_STATISTIC 0
+#endif
+#endif
+
+/*
+ gcdFENCE_WAIT_LOOP_COUNT
+ Wait fence, loop count.
+*/
+#ifndef gcdFENCE_WAIT_LOOP_COUNT
+# define gcdFENCE_WAIT_LOOP_COUNT 100
+#endif
+
+/*
+ gcdPARTIAL_FAST_CLEAR
+ When it's not zero, partial fast clear is enabled.
+ Depends on gcdHAL_3D_DRAWBLIT, if gcdHAL_3D_DRAWBLIT is not enabled,
+ only available when scissor box is completely aligned.
+ Expremental, under test.
+*/
+#ifndef gcdPARTIAL_FAST_CLEAR
+# define gcdPARTIAL_FAST_CLEAR 1
+#endif
+
+/*
+ gcdREMOVE_SURF_ORIENTATION
+ When it's not zero, we will remove surface orientation function.
+ It wil become to a parameter of resolve function.
+*/
+#ifndef gcdREMOVE_SURF_ORIENTATION
+# define gcdREMOVE_SURF_ORIENTATION 1
+#endif
+
+
+
+/*
+ gcdTEST_DEC200
+ Test part for DEC200. Remove when release.
+*/
+#ifndef gcdTEST_DEC200
+# define gcdTEST_DEC200 0
+#endif
+
+/*
+ gcdPATTERN_FAST_PATH
+ For pattern match
+*/
+#ifndef gcdPATTERN_FAST_PATH
+# define gcdPATTERN_FAST_PATH 1
+#endif
+
+/*
+ gcdUSE_INPUT_DEVICE
+ disable input devices usage under fb mode to support fb+vdk multi-process
+*/
+#ifndef gcdUSE_INPUT_DEVICE
+# define gcdUSE_INPUT_DEVICE 0
+#endif
+
+/*
+ gcdPERFORMANCE_ANALYSIS
+
+ When set to 1, driver will pass information through loadstate
+ to HW. This loadstate does not impact HW execution.
+*/
+#ifndef gcdPERFORMANCE_ANALYSIS
+# define gcdPERFORMANCE_ANALYSIS 0
+#endif
+
+/*
+ gcdFRAMEINFO_STATISTIC
+ When enable, collect frame information.
+*/
+#ifndef gcdFRAMEINFO_STATISTIC
+
+#if (defined(DBG) && DBG) || defined(DEBUG) || \
+ defined(_DEBUG) || gcdDUMP || gcdPERFORMANCE_ANALYSIS || \
+ (defined(WIN32) && !defined(UNDER_CE)) || \
+ gcdFPGA_BUILD
+
+# define gcdFRAMEINFO_STATISTIC 1
+#else
+# define gcdFRAMEINFO_STATISTIC 0
+#endif
+
+#endif
+
+/*
+ gcdDEC_ENABLE_AHB
+ Enable DEC300 compression AHB mode or not.
+*/
+#ifndef gcdDEC_ENABLE_AHB
+# define gcdDEC_ENABLE_AHB 0
+#endif
+
+/*
+ gcdENABLE_UNIFIED_CONSTANT
+ Enable unified constant or not.
+*/
+#ifndef gcdENABLE_UNIFIED_CONSTANT
+# define gcdENABLE_UNIFIED_CONSTANT 1
+#endif
+
+/*
+ Core configurations. By default enable all cores.
+*/
+#ifndef gcdENABLE_3D
+# define gcdENABLE_3D 1
+#endif
+
+#ifndef gcdENABLE_2D
+# define gcdENABLE_2D 1
+#endif
+
+#ifndef gcdENABLE_VG
+# define gcdENABLE_VG 0
+#endif
+
+#ifndef gcdVG_ONLY
+# define gcdVG_ONLY (!gcdENABLE_3D && !gcdENABLE_2D && gcdENABLE_VG)
+#endif
+
+#if defined(WIN32) && !defined(UNDER_CE) && (gcdENABLE_VG == 1)
+
+#ifdef gcdUSE_VX
+#undef gcdUSE_VX
+#endif
+
+#ifdef COMMAND_PROCESSOR_VERSION
+#undef COMMAND_PROCESSOR_VERSION
+#endif
+
+#ifdef gcdENABLE_TRUST_APPLICATION
+#undef gcdENABLE_TRUST_APPLICATION
+#endif
+
+#ifdef gcdENABLE_3D
+#undef gcdENABLE_3D
+#endif
+
+#ifdef gcdENABLE_2D
+#undef gcdENABLE_2D
+#endif
+
+#define gcdENABLE_3D 0
+#define gcdENABLE_2D 0
+#define gcdUSE_VX 0
+#define COMMAND_PROCESSOR_VERSION 2
+#define gcdENABLE_TRUST_APPLICATION 0
+
+#endif /* Only for GC355 Cmodel build. */
+
+#ifndef gcdGC355_PROFILER
+# define gcdGC355_PROFILER 0
+#endif
+
+#ifndef gcdGC355_MEM_PRINT
+# define gcdGC355_MEM_PRINT 0
+#else
+#if (!((gcdENABLE_3D == 0) && (gcdENABLE_2D == 0) && (gcdENABLE_VG == 1)))
+# undef gcdGC355_MEM_PRINT
+# define gcdGC355_MEM_PRINT 0
+# endif
+#endif
+
+
+/*
+ gcdRECORD_COMMAND
+*/
+#ifndef gcdRECORD_COMMAND
+# define gcdRECORD_COMMAND 0
+#endif
+
+/*
+ gcdALLOC_CMD_FROM_RESERVE
+
+ Provide a way by which location of command buffer can be
+ specified. This is a DEBUG option to limit command buffer
+ to some memory range.
+*/
+#ifndef gcdALLOC_CMD_FROM_RESERVE
+# define gcdALLOC_CMD_FROM_RESERVE 0
+#endif
+
+/*
+ gcdBOUNDARY_CHECK
+
+ When enabled, add bounary before and after a range of
+ GPU address. So overflow can be trapped by MMU exception.
+ This is a debug option for new MMU and gcdUSE_MMU_EXCEPTION
+ is enabled.
+*/
+#ifndef gcdBOUNDARY_CHECK
+# define gcdBOUNDARY_CHECK 0
+#endif
+
+/*
+ gcdRENDER_QUALITY_CHECK
+
+ When enabled, we disable performance opt patch
+ to get know rendering quality comparing with other vendor.
+*/
+#ifndef gcdRENDER_QUALITY_CHECK
+# define gcdRENDER_QUALITY_CHECK 0
+#endif
+
+/*
+ gcdSYSTRACE
+
+ When enabled, we embed systrace in function header/footer
+ to gather time information on linux platforms include android.
+ '1' to trace API (EGL, ES11, ES2x, ES3x, etc)
+ '2' to trace HAL (except compiler)
+ '4' to trace HAL compiler
+ See gc_hal_user_debug.c for more detailed trace zones.
+*/
+#ifndef gcdSYSTRACE
+# define gcdSYSTRACE 0
+#endif
+
+#ifndef gcdENABLE_APPCTXT_BLITDRAW
+# define gcdENABLE_APPCTXT_BLITDRAW 0
+#endif
+
+/*
+ gcdENABLE_TRUST_APPLICATION
+
+ When enabled, trust application is used to handle 'security' registers.
+
+ 1) If HW doesn't have robust and security feature, this option is meaningless.
+ 2) If HW have robust and security and this option is not enable,
+ security registers are handled by non secure driver. It is for
+ platform doesn't want/need to use trust zone.
+*/
+#ifndef gcdENABLE_TRUST_APPLICATION
+#if (defined(_WIN32) && !defined(UNDER_CE)) || (defined (LINUX) && !defined(EMULATOR))
+# define gcdENABLE_TRUST_APPLICATION 1
+#else
+# define gcdENABLE_TRUST_APPLICATION 0
+#endif
+#endif
+
+/* Disable gcdENABLE_TRUST_APPLICATION when oboslete gcdSECURITY enabled. */
+#if gcdSECURITY
+#undef gcdENABLE_TRUST_APPLICATION
+#define gcdENABLE_TRUST_APPLICATION 0
+#endif
+
+#ifndef gcdMMU_SECURE_AREA_SIZE
+# define gcdMMU_SECURE_AREA_SIZE 128
+#endif
+
+/*
+VIV:gcdUSE_MMU_EXCEPTION
+
+ When enabled, enable and check exception interrupt raised by MMU.
+*/
+#ifndef gcdUSE_MMU_EXCEPTION
+# define gcdUSE_MMU_EXCEPTION 1
+#endif
+
+#ifndef gcdVX_OPTIMIZER
+# define gcdVX_OPTIMIZER 0
+#endif
+
+#ifndef gcdOCL_READ_IMAGE_OPTIMIZATION
+# define gcdOCL_READ_IMAGE_OPTIMIZATION 0
+#endif
+
+#ifndef gcdALLOC_ON_FAULT
+# define gcdALLOC_ON_FAULT 0
+#endif
+
+/*
+ gcdDISABLE_GPU_VIRTUAL_ADDRESS
+
+ When enabled, disable MMU and all virtual allocated from MMU.
+*/
+#ifndef gcdDISABLE_GPU_VIRTUAL_ADDRESS
+# define gcdDISABLE_GPU_VIRTUAL_ADDRESS 0
+#endif
+
+/*
+ gcd2D_COMPRESSION_DEC400_ALIGN_MODE
+
+ Only for DEC400 compression.
+ Set 0 as 16bytes aligned. 1 as 32bytes aligned. 2 as 64bytes aligned.
+ Default is 0 which means 32bytes aligned.
+*/
+#ifndef gcd2D_COMPRESSION_DEC400_ALIGN_MODE
+# define gcd2D_COMPRESSION_DEC400_ALIGN_MODE 1
+#endif
+
+/*
+ gcdENABLE_KERNEL_FENCE
+ When enabled, use kernel fence to do resource tracking.
+*/
+#ifndef gcdENABLE_KENREL_FENCE
+# define gcdENABLE_KERNEL_FENCE 0
+#endif
+
+
+#endif /* __gc_hal_options_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_profiler.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_profiler.h
new file mode 100644
index 000000000000..2ee13d972d6f
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_profiler.h
@@ -0,0 +1,1173 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_profiler_h_
+#define __gc_hal_profiler_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GLVERTEX_OBJECT 10
+#define GLVERTEX_OBJECT_BYTES 11
+
+#define GLINDEX_OBJECT 20
+#define GLINDEX_OBJECT_BYTES 21
+
+#define GLTEXTURE_OBJECT 30
+#define GLTEXTURE_OBJECT_BYTES 31
+
+#define GLBUFOBJ_OBJECT 40
+#define GLBUFOBJ_OBJECT_BYTES 41
+
+#define ES11_CALLS 151
+#define ES11_DRAWCALLS (ES11_CALLS + 1)
+#define ES11_STATECHANGECALLS (ES11_DRAWCALLS + 1)
+#define ES11_POINTCOUNT (ES11_STATECHANGECALLS + 1)
+#define ES11_LINECOUNT (ES11_POINTCOUNT + 1)
+#define ES11_TRIANGLECOUNT (ES11_LINECOUNT + 1)
+
+#define ES30_CALLS 159
+#define ES30_DRAWCALLS (ES30_CALLS + 1)
+#define ES30_STATECHANGECALLS (ES30_DRAWCALLS + 1)
+#define ES30_POINTCOUNT (ES30_STATECHANGECALLS + 1)
+#define ES30_LINECOUNT (ES30_POINTCOUNT + 1)
+#define ES30_TRIANGLECOUNT (ES30_LINECOUNT + 1)
+
+#define VG11_CALLS 88
+#define VG11_DRAWCALLS (VG11_CALLS + 1)
+#define VG11_STATECHANGECALLS (VG11_DRAWCALLS + 1)
+#define VG11_FILLCOUNT (VG11_STATECHANGECALLS + 1)
+#define VG11_STROKECOUNT (VG11_FILLCOUNT + 1)
+/* End of Driver API ID Definitions. */
+
+/* HAL & MISC IDs. */
+#define HAL_VERTBUFNEWBYTEALLOC 1
+#define HAL_VERTBUFTOTALBYTEALLOC (HAL_VERTBUFNEWBYTEALLOC + 1)
+#define HAL_VERTBUFNEWOBJALLOC (HAL_VERTBUFTOTALBYTEALLOC + 1)
+#define HAL_VERTBUFTOTALOBJALLOC (HAL_VERTBUFNEWOBJALLOC + 1)
+#define HAL_INDBUFNEWBYTEALLOC (HAL_VERTBUFTOTALOBJALLOC + 1)
+#define HAL_INDBUFTOTALBYTEALLOC (HAL_INDBUFNEWBYTEALLOC + 1)
+#define HAL_INDBUFNEWOBJALLOC (HAL_INDBUFTOTALBYTEALLOC + 1)
+#define HAL_INDBUFTOTALOBJALLOC (HAL_INDBUFNEWOBJALLOC + 1)
+#define HAL_TEXBUFNEWBYTEALLOC (HAL_INDBUFTOTALOBJALLOC + 1)
+#define HAL_TEXBUFTOTALBYTEALLOC (HAL_TEXBUFNEWBYTEALLOC + 1)
+#define HAL_TEXBUFNEWOBJALLOC (HAL_TEXBUFTOTALBYTEALLOC + 1)
+#define HAL_TEXBUFTOTALOBJALLOC (HAL_TEXBUFNEWOBJALLOC + 1)
+
+#define GPU_CYCLES 1
+#define GPU_READ64BYTE (GPU_CYCLES + 1)
+#define GPU_WRITE64BYTE (GPU_READ64BYTE + 1)
+#define GPU_TOTALCYCLES (GPU_WRITE64BYTE + 1)
+#define GPU_IDLECYCLES (GPU_TOTALCYCLES + 1)
+
+#define VS_INSTCOUNT 1
+#define VS_BRANCHINSTCOUNT (VS_INSTCOUNT + 1)
+#define VS_TEXLDINSTCOUNT (VS_BRANCHINSTCOUNT + 1)
+#define VS_RENDEREDVERTCOUNT (VS_TEXLDINSTCOUNT + 1)
+#define VS_SOURCE (VS_RENDEREDVERTCOUNT + 1)
+#define VS_NONIDLESTARVECOUNT (VS_SOURCE + 1)
+#define VS_STARVELCOUNT (VS_NONIDLESTARVECOUNT + 1)
+#define VS_STALLCOUNT (VS_STARVELCOUNT + 1)
+#define VS_PROCESSCOUNT (VS_STALLCOUNT + 1)
+
+#define PS_INSTCOUNT 1
+#define PS_BRANCHINSTCOUNT (PS_INSTCOUNT + 1)
+#define PS_TEXLDINSTCOUNT (PS_BRANCHINSTCOUNT + 1)
+#define PS_RENDEREDPIXCOUNT (PS_TEXLDINSTCOUNT + 1)
+#define PS_SOURCE (PS_RENDEREDPIXCOUNT + 1)
+#define PS_NONIDLESTARVECOUNT (PS_SOURCE + 1)
+#define PS_STARVELCOUNT (PS_NONIDLESTARVECOUNT + 1)
+#define PS_STALLCOUNT (PS_STARVELCOUNT + 1)
+#define PS_PROCESSCOUNT (PS_STALLCOUNT + 1)
+#define PS_SHADERCYCLECOUNT (PS_PROCESSCOUNT + 1)
+
+#define PA_INVERTCOUNT 1
+#define PA_INPRIMCOUNT (PA_INVERTCOUNT + 1)
+#define PA_OUTPRIMCOUNT (PA_INPRIMCOUNT + 1)
+#define PA_DEPTHCLIPCOUNT (PA_OUTPRIMCOUNT + 1)
+#define PA_TRIVIALREJCOUNT (PA_DEPTHCLIPCOUNT + 1)
+#define PA_CULLCOUNT (PA_TRIVIALREJCOUNT + 1)
+#define PA_NONIDLESTARVECOUNT (PA_CULLCOUNT + 1)
+#define PA_STARVELCOUNT (PA_NONIDLESTARVECOUNT + 1)
+#define PA_STALLCOUNT (PA_STARVELCOUNT + 1)
+#define PA_PROCESSCOUNT (PA_STALLCOUNT + 1)
+
+#define SE_TRIANGLECOUNT 1
+#define SE_LINECOUNT (SE_TRIANGLECOUNT + 1)
+#define SE_STARVECOUNT (SE_LINECOUNT + 1)
+#define SE_STALLCOUNT (SE_STARVECOUNT + 1)
+#define SE_RECEIVETRIANGLECOUNT (SE_STALLCOUNT + 1)
+#define SE_SENDTRIANGLECOUNT (SE_RECEIVETRIANGLECOUNT + 1)
+#define SE_RECEIVELINESCOUNT (SE_SENDTRIANGLECOUNT + 1)
+#define SE_SENDLINESCOUNT (SE_RECEIVELINESCOUNT + 1)
+#define SE_NONIDLESTARVECOUNT (SE_SENDLINESCOUNT + 1)
+#define SE_PROCESSCOUNT (SE_NONIDLESTARVECOUNT + 1)
+
+#define RA_VALIDPIXCOUNT 1
+#define RA_TOTALQUADCOUNT (RA_VALIDPIXCOUNT + 1)
+#define RA_VALIDQUADCOUNTEZ (RA_TOTALQUADCOUNT + 1)
+#define RA_TOTALPRIMCOUNT (RA_VALIDQUADCOUNTEZ + 1)
+#define RA_PIPECACHEMISSCOUNT (RA_TOTALPRIMCOUNT + 1)
+#define RA_PREFCACHEMISSCOUNT (RA_PIPECACHEMISSCOUNT + 1)
+#define RA_EEZCULLCOUNT (RA_PREFCACHEMISSCOUNT + 1)
+#define RA_NONIDLESTARVECOUNT (RA_EEZCULLCOUNT + 1)
+#define RA_STARVELCOUNT (RA_NONIDLESTARVECOUNT + 1)
+#define RA_STALLCOUNT (RA_STARVELCOUNT + 1)
+#define RA_PROCESSCOUNT (RA_STALLCOUNT + 1)
+
+#define TX_TOTBILINEARREQ 1
+#define TX_TOTTRILINEARREQ (TX_TOTBILINEARREQ + 1)
+#define TX_TOTDISCARDTEXREQ (TX_TOTTRILINEARREQ + 1)
+#define TX_TOTTEXREQ (TX_TOTDISCARDTEXREQ + 1)
+#define TX_MEMREADCOUNT (TX_TOTTEXREQ + 1)
+#define TX_MEMREADIN8BCOUNT (TX_MEMREADCOUNT + 1)
+#define TX_CACHEMISSCOUNT (TX_MEMREADIN8BCOUNT + 1)
+#define TX_CACHEHITTEXELCOUNT (TX_CACHEMISSCOUNT + 1)
+#define TX_CACHEMISSTEXELCOUNT (TX_CACHEHITTEXELCOUNT + 1)
+#define TX_NONIDLESTARVECOUNT (TX_CACHEMISSTEXELCOUNT+ 1)
+#define TX_STARVELCOUNT (TX_NONIDLESTARVECOUNT + 1)
+#define TX_STALLCOUNT (TX_STARVELCOUNT + 1)
+#define TX_PROCESSCOUNT (TX_STALLCOUNT + 1)
+
+#define PE_KILLEDBYCOLOR 1
+#define PE_KILLEDBYDEPTH (PE_KILLEDBYCOLOR + 1)
+#define PE_DRAWNBYCOLOR (PE_KILLEDBYDEPTH + 1)
+#define PE_DRAWNBYDEPTH (PE_DRAWNBYCOLOR + 1)
+
+#define MC_READREQ8BPIPE 1
+#define MC_READREQ8BIP (MC_READREQ8BPIPE + 1)
+#define MC_WRITEREQ8BPIPE (MC_READREQ8BIP + 1)
+#define MC_AXIMINLATENCY (MC_WRITEREQ8BPIPE + 1)
+#define MC_AXIMAXLATENCY (MC_AXIMINLATENCY + 1)
+#define MC_AXITOTALLATENCY (MC_AXIMAXLATENCY + 1)
+#define MC_AXISAMPLECOUNT (MC_AXITOTALLATENCY + 1)
+
+#define AXI_READREQSTALLED 1
+#define AXI_WRITEREQSTALLED (AXI_READREQSTALLED + 1)
+#define AXI_WRITEDATASTALLED (AXI_WRITEREQSTALLED + 1)
+
+#define FE_DRAWCOUNT 1
+#define FE_OUTVERTEXCOUNT (FE_DRAWCOUNT + 1)
+#define FE_STALLCOUNT (FE_OUTVERTEXCOUNT + 1)
+#define FE_STARVECOUNT (FE_STALLCOUNT + 1)
+
+#define PVS_INSTRCOUNT 1
+#define PVS_ALUINSTRCOUNT (PVS_INSTRCOUNT + 1)
+#define PVS_TEXINSTRCOUNT (PVS_ALUINSTRCOUNT + 1)
+#define PVS_ATTRIBCOUNT (PVS_TEXINSTRCOUNT + 1)
+#define PVS_UNIFORMCOUNT (PVS_ATTRIBCOUNT + 1)
+#define PVS_FUNCTIONCOUNT (PVS_UNIFORMCOUNT + 1)
+#define PVS_SOURCE (PVS_FUNCTIONCOUNT + 1)
+
+#define PPS_INSTRCOUNT 1
+#define PPS_ALUINSTRCOUNT (PPS_INSTRCOUNT + 1)
+#define PPS_TEXINSTRCOUNT (PPS_ALUINSTRCOUNT + 1)
+#define PPS_ATTRIBCOUNT (PPS_TEXINSTRCOUNT + 1)
+#define PPS_UNIFORMCOUNT (PPS_ATTRIBCOUNT + 1)
+#define PPS_FUNCTIONCOUNT (PPS_UNIFORMCOUNT + 1)
+#define PPS_SOURCE (PPS_FUNCTIONCOUNT + 1)
+/* End of MISC Counter IDs. */
+
+
+/* Category Constants. */
+#define VPHEADER 0x010000
+#define VPG_INFO 0x020000
+#define VPG_TIME 0x030000
+#define VPG_MEM 0x040000
+#define VPG_ES11 0x050000
+#define VPG_ES30 0x060000
+#define VPG_VG11 0x070000
+#define VPG_HAL 0x080000
+#define VPG_HW 0x090000
+#define VPG_GPU 0x0a0000
+#define VPG_VS 0x0b0000
+#define VPG_PS 0x0c0000
+#define VPG_PA 0x0d0000
+#define VPG_SETUP 0x0e0000
+#define VPG_RA 0x0f0000
+#define VPG_TX 0x100000
+#define VPG_PE 0x110000
+#define VPG_MC 0x120000
+#define VPG_AXI 0x130000
+#define VPG_PROG 0x140000
+#define VPG_PVS 0x150000
+#define VPG_PPS 0x160000
+#define VPG_ES11_TIME 0x170000
+#define VPG_ES30_TIME 0x180000
+#define VPG_FRAME 0x190000
+#define VPG_ES11_DRAW 0x200000
+#define VPG_ES30_DRAW 0x210000
+#define VPG_VG11_TIME 0x220000
+#define VPG_FE 0x230000
+#define VPG_MULTI_GPU 0x240000
+#define VPNG_FE 0x250000
+#define VPNG_VS 0x260000
+#define VPNG_PS 0x270000
+#define VPNG_PA 0x280000
+#define VPNG_SETUP 0x290000
+#define VPNG_RA 0x2a0000
+#define VPNG_TX 0x2b0000
+#define VPNG_PE 0x2c0000
+#define VPNG_MCC 0x2d0000
+#define VPNG_MCZ 0x2e0000
+#define VPNG_HI 0x2f0000
+#define VPNG_L2 0x300000
+#define VPG_FINISH 0x310000
+#define VPG_END 0xff0000
+
+/* Info. */
+#define VPC_INFOCOMPANY (VPG_INFO + 1)
+#define VPC_INFOVERSION (VPC_INFOCOMPANY + 1)
+#define VPC_INFORENDERER (VPC_INFOVERSION + 1)
+#define VPC_INFOREVISION (VPC_INFORENDERER + 1)
+#define VPC_INFODRIVER (VPC_INFOREVISION + 1)
+#define VPC_INFODRIVERMODE (VPC_INFODRIVER + 1)
+#define VPC_INFOSCREENSIZE (VPC_INFODRIVERMODE + 1)
+
+/* Counter Constants. */
+#define VPC_ELAPSETIME (VPG_TIME + 1)
+#define VPC_CPUTIME (VPC_ELAPSETIME + 1)
+
+#define VPC_MEMMAXRES (VPG_MEM + 1)
+#define VPC_MEMSHARED (VPC_MEMMAXRES + 1)
+#define VPC_MEMUNSHAREDDATA (VPC_MEMSHARED + 1)
+#define VPC_MEMUNSHAREDSTACK (VPC_MEMUNSHAREDDATA + 1)
+
+/* OpenGL ES11 Statics Counter IDs. */
+#define VPC_ES11CALLS (VPG_ES11 + ES11_CALLS)
+#define VPC_ES11DRAWCALLS (VPG_ES11 + ES11_DRAWCALLS)
+#define VPC_ES11STATECHANGECALLS (VPG_ES11 + ES11_STATECHANGECALLS)
+#define VPC_ES11POINTCOUNT (VPG_ES11 + ES11_POINTCOUNT)
+#define VPC_ES11LINECOUNT (VPG_ES11 + ES11_LINECOUNT)
+#define VPC_ES11TRIANGLECOUNT (VPG_ES11 + ES11_TRIANGLECOUNT)
+
+/* OpenGL ES30 Statistics Counter IDs. */
+#define VPC_ES30CALLS (VPG_ES30 + ES30_CALLS)
+#define VPC_ES30DRAWCALLS (VPG_ES30 + ES30_DRAWCALLS)
+#define VPC_ES30STATECHANGECALLS (VPG_ES30 + ES30_STATECHANGECALLS)
+#define VPC_ES30POINTCOUNT (VPG_ES30 + ES30_POINTCOUNT)
+#define VPC_ES30LINECOUNT (VPG_ES30 + ES30_LINECOUNT)
+#define VPC_ES30TRIANGLECOUNT (VPG_ES30 + ES30_TRIANGLECOUNT)
+
+/* OpenVG Statistics Counter IDs. */
+#define VPC_VG11CALLS (VPG_VG11 + VG11_CALLS)
+#define VPC_VG11DRAWCALLS (VPG_VG11 + VG11_DRAWCALLS)
+#define VPC_VG11STATECHANGECALLS (VPG_VG11 + VG11_STATECHANGECALLS)
+#define VPC_VG11FILLCOUNT (VPG_VG11 + VG11_FILLCOUNT)
+#define VPC_VG11STROKECOUNT (VPG_VG11 + VG11_STROKECOUNT)
+
+/* HAL Counters. */
+#define VPC_HALVERTBUFNEWBYTEALLOC (VPG_HAL + HAL_VERTBUFNEWBYTEALLOC)
+#define VPC_HALVERTBUFTOTALBYTEALLOC (VPG_HAL + HAL_VERTBUFTOTALBYTEALLOC)
+#define VPC_HALVERTBUFNEWOBJALLOC (VPG_HAL + HAL_VERTBUFNEWOBJALLOC)
+#define VPC_HALVERTBUFTOTALOBJALLOC (VPG_HAL + HAL_VERTBUFTOTALOBJALLOC)
+#define VPC_HALINDBUFNEWBYTEALLOC (VPG_HAL + HAL_INDBUFNEWBYTEALLOC)
+#define VPC_HALINDBUFTOTALBYTEALLOC (VPG_HAL + HAL_INDBUFTOTALBYTEALLOC)
+#define VPC_HALINDBUFNEWOBJALLOC (VPG_HAL + HAL_INDBUFNEWOBJALLOC)
+#define VPC_HALINDBUFTOTALOBJALLOC (VPG_HAL + HAL_INDBUFTOTALOBJALLOC)
+#define VPC_HALTEXBUFNEWBYTEALLOC (VPG_HAL + HAL_TEXBUFNEWBYTEALLOC)
+#define VPC_HALTEXBUFTOTALBYTEALLOC (VPG_HAL + HAL_TEXBUFTOTALBYTEALLOC)
+#define VPC_HALTEXBUFNEWOBJALLOC (VPG_HAL + HAL_TEXBUFNEWOBJALLOC)
+#define VPC_HALTEXBUFTOTALOBJALLOC (VPG_HAL + HAL_TEXBUFTOTALOBJALLOC)
+
+/* HW: GPU Counters. */
+#define VPC_GPUCYCLES (VPG_GPU + GPU_CYCLES)
+#define VPC_GPUREAD64BYTE (VPG_GPU + GPU_READ64BYTE)
+#define VPC_GPUWRITE64BYTE (VPG_GPU + GPU_WRITE64BYTE)
+#define VPC_GPUTOTALCYCLES (VPG_GPU + GPU_TOTALCYCLES)
+#define VPC_GPUIDLECYCLES (VPG_GPU + GPU_IDLECYCLES)
+
+/* HW: Shader Counters. */
+#define VPC_VSINSTCOUNT (VPG_VS + VS_INSTCOUNT)
+#define VPC_VSBRANCHINSTCOUNT (VPG_VS + VS_BRANCHINSTCOUNT)
+#define VPC_VSTEXLDINSTCOUNT (VPG_VS + VS_TEXLDINSTCOUNT)
+#define VPC_VSRENDEREDVERTCOUNT (VPG_VS + VS_RENDEREDVERTCOUNT)
+#define VPC_VSNONIDLESTARVECOUNT (VPG_VS + VS_NONIDLESTARVECOUNT)
+#define VPC_VSSTARVELCOUNT (VPG_VS + VS_STARVELCOUNT)
+#define VPC_VSSTALLCOUNT (VPG_VS + VS_STALLCOUNT)
+#define VPC_VSPROCESSCOUNT (VPG_VS + VS_PROCESSCOUNT)
+/* HW: PS Count. */
+#define VPC_PSINSTCOUNT (VPG_PS + PS_INSTCOUNT)
+#define VPC_PSBRANCHINSTCOUNT (VPG_PS + PS_BRANCHINSTCOUNT)
+#define VPC_PSTEXLDINSTCOUNT (VPG_PS + PS_TEXLDINSTCOUNT)
+#define VPC_PSRENDEREDPIXCOUNT (VPG_PS + PS_RENDEREDPIXCOUNT)
+#define VPC_PSNONIDLESTARVECOUNT (VPG_PS + PS_NONIDLESTARVECOUNT)
+#define VPC_PSSTARVELCOUNT (VPG_PS + PS_STARVELCOUNT)
+#define VPC_PSSTALLCOUNT (VPG_PS + PS_STALLCOUNT)
+#define VPC_PSPROCESSCOUNT (VPG_PS + PS_PROCESSCOUNT)
+#define VPC_PSSHADERCYCLECOUNT (VPG_PS + PS_SHADERCYCLECOUNT)
+
+/* HW: PA Counters. */
+#define VPC_PAINVERTCOUNT (VPG_PA + PA_INVERTCOUNT)
+#define VPC_PAINPRIMCOUNT (VPG_PA + PA_INPRIMCOUNT)
+#define VPC_PAOUTPRIMCOUNT (VPG_PA + PA_OUTPRIMCOUNT)
+#define VPC_PADEPTHCLIPCOUNT (VPG_PA + PA_DEPTHCLIPCOUNT)
+#define VPC_PATRIVIALREJCOUNT (VPG_PA + PA_TRIVIALREJCOUNT)
+#define VPC_PACULLCOUNT (VPG_PA + PA_CULLCOUNT)
+#define VPC_PANONIDLESTARVECOUNT (VPG_PA + PA_NONIDLESTARVECOUNT)
+#define VPC_PASTARVELCOUNT (VPG_PA + PA_STARVELCOUNT)
+#define VPC_PASTALLCOUNT (VPG_PA + PA_STALLCOUNT)
+#define VPC_PAPROCESSCOUNT (VPG_PA + PA_PROCESSCOUNT)
+
+/* HW: Setup Counters. */
+#define VPC_SETRIANGLECOUNT (VPG_SETUP + SE_TRIANGLECOUNT)
+#define VPC_SELINECOUNT (VPG_SETUP + SE_LINECOUNT)
+#define VPC_SESTARVECOUNT (VPG_SETUP + SE_STARVECOUNT)
+#define VPC_SESTALLCOUNT (VPG_SETUP + SE_STALLCOUNT)
+#define VPC_SERECEIVETRIANGLECOUNT (VPG_SETUP + SE_RECEIVETRIANGLECOUNT)
+#define VPC_SESENDTRIANGLECOUNT (VPG_SETUP + SE_SENDTRIANGLECOUNT)
+#define VPC_SERECEIVELINESCOUNT (VPG_SETUP + SE_RECEIVELINESCOUNT)
+#define VPC_SESENDLINESCOUNT (VPG_SETUP + SE_SENDLINESCOUNT)
+#define VPC_SENONIDLESTARVECOUNT (VPG_SETUP + SE_NONIDLESTARVECOUNT)
+#define VPC_SEPROCESSCOUNT (VPG_SETUP + SE_PROCESSCOUNT)
+
+/* HW: RA Counters. */
+#define VPC_RAVALIDPIXCOUNT (VPG_RA + RA_VALIDPIXCOUNT)
+#define VPC_RATOTALQUADCOUNT (VPG_RA + RA_TOTALQUADCOUNT)
+#define VPC_RAVALIDQUADCOUNTEZ (VPG_RA + RA_VALIDQUADCOUNTEZ)
+#define VPC_RATOTALPRIMCOUNT (VPG_RA + RA_TOTALPRIMCOUNT)
+#define VPC_RAPIPECACHEMISSCOUNT (VPG_RA + RA_PIPECACHEMISSCOUNT)
+#define VPC_RAPREFCACHEMISSCOUNT (VPG_RA + RA_PREFCACHEMISSCOUNT)
+#define VPC_RAEEZCULLCOUNT (VPG_RA + RA_EEZCULLCOUNT)
+#define VPC_RANONIDLESTARVECOUNT (VPG_RA + RA_NONIDLESTARVECOUNT)
+#define VPC_RASTARVELCOUNT (VPG_RA + RA_STARVELCOUNT)
+#define VPC_RASTALLCOUNT (VPG_RA + RA_STALLCOUNT)
+#define VPC_RAPROCESSCOUNT (VPG_RA + RA_PROCESSCOUNT)
+
+/* HW: TEX Counters. */
+#define VPC_TXTOTBILINEARREQ (VPG_TX + TX_TOTBILINEARREQ)
+#define VPC_TXTOTTRILINEARREQ (VPG_TX + TX_TOTTRILINEARREQ)
+#define VPC_TXTOTDISCARDTEXREQ (VPG_TX + TX_TOTDISCARDTEXREQ)
+#define VPC_TXTOTTEXREQ (VPG_TX + TX_TOTTEXREQ)
+#define VPC_TXMEMREADCOUNT (VPG_TX + TX_MEMREADCOUNT)
+#define VPC_TXMEMREADIN8BCOUNT (VPG_TX + TX_MEMREADIN8BCOUNT)
+#define VPC_TXCACHEMISSCOUNT (VPG_TX + TX_CACHEMISSCOUNT)
+#define VPC_TXCACHEHITTEXELCOUNT (VPG_TX + TX_CACHEHITTEXELCOUNT)
+#define VPC_TXCACHEMISSTEXELCOUNT (VPG_TX + TX_CACHEMISSTEXELCOUNT)
+#define VPC_TXNONIDLESTARVECOUNT (VPG_TX + TX_NONIDLESTARVECOUNT)
+#define VPC_TXSTARVELCOUNT (VPG_TX + TX_STARVELCOUNT)
+#define VPC_TXSTALLCOUNT (VPG_TX + TX_STALLCOUNT)
+#define VPC_TXPROCESSCOUNT (VPG_TX + TX_PROCESSCOUNT)
+
+/* HW: PE Counters. */
+#define VPC_PEKILLEDBYCOLOR (VPG_PE + PE_KILLEDBYCOLOR)
+#define VPC_PEKILLEDBYDEPTH (VPG_PE + PE_KILLEDBYDEPTH)
+#define VPC_PEDRAWNBYCOLOR (VPG_PE + PE_DRAWNBYCOLOR)
+#define VPC_PEDRAWNBYDEPTH (VPG_PE + PE_DRAWNBYDEPTH)
+
+/* HW: MC Counters. */
+#define VPC_MCREADREQ8BPIPE (VPG_MC + MC_READREQ8BPIPE)
+#define VPC_MCREADREQ8BIP (VPG_MC + MC_READREQ8BIP)
+#define VPC_MCWRITEREQ8BPIPE (VPG_MC + MC_WRITEREQ8BPIPE)
+#define VPC_MCAXIMINLATENCY (VPG_MC + MC_AXIMINLATENCY)
+#define VPC_MCAXIMAXLATENCY (VPG_MC + MC_AXIMAXLATENCY)
+#define VPC_MCAXITOTALLATENCY (VPG_MC + MC_AXITOTALLATENCY)
+#define VPC_MCAXISAMPLECOUNT (VPG_MC + MC_AXISAMPLECOUNT)
+
+/* HW: AXI Counters. */
+#define VPC_AXIREADREQSTALLED (VPG_AXI + AXI_READREQSTALLED)
+#define VPC_AXIWRITEREQSTALLED (VPG_AXI + AXI_WRITEREQSTALLED)
+#define VPC_AXIWRITEDATASTALLED (VPG_AXI + AXI_WRITEDATASTALLED)
+
+/* HW: FE Counters. */
+#define VPC_FEDRAWCOUNT (VPG_FE + FE_DRAWCOUNT)
+#define VPC_FEOUTVERTEXCOUNT (VPG_FE + FE_OUTVERTEXCOUNT)
+#define VPC_FESTALLCOUNT (VPG_FE + FE_STALLCOUNT)
+#define VPC_FESTARVECOUNT (VPG_FE + FE_STARVECOUNT)
+
+/* HW: Shader Counters. */
+#define VPNC_VSINSTCOUNT (VPNG_VS + 1)
+#define VPNC_VSBRANCHINSTCOUNT (VPNG_VS + 2)
+#define VPNC_VSTEXLDINSTCOUNT (VPNG_VS + 3)
+#define VPNC_VSRENDEREDVERTCOUNT (VPNG_VS + 4)
+#define VPNC_VSNONIDLESTARVECOUNT (VPNG_VS + 5)
+#define VPNC_VSSTARVELCOUNT (VPNG_VS + 6)
+#define VPNC_VSSTALLCOUNT (VPNG_VS + 7)
+#define VPNC_VSPROCESSCOUNT (VPNG_VS + 8)
+#define VPNC_VSSHADERCYCLECOUNT (VPNG_VS + 9)
+#define VPNC_VS_COUNT VPNC_VSSHADERCYCLECOUNT - VPNG_VS
+
+/* HW: PS Count. */
+#define VPNC_PSINSTCOUNT (VPNG_PS + 1)
+#define VPNC_PSBRANCHINSTCOUNT (VPNG_PS + 2)
+#define VPNC_PSTEXLDINSTCOUNT (VPNG_PS + 3)
+#define VPNC_PSRENDEREDPIXCOUNT (VPNG_PS + 4)
+#define VPNC_PSNONIDLESTARVECOUNT (VPNG_PS + 5)
+#define VPNC_PSSTARVELCOUNT (VPNG_PS + 6)
+#define VPNC_PSSTALLCOUNT (VPNG_PS + 7)
+#define VPNC_PSPROCESSCOUNT (VPNG_PS + 8)
+#define VPNC_PSSHADERCYCLECOUNT (VPNG_PS + 9)
+#define VPNC_PS_COUNT VPNC_PSSHADERCYCLECOUNT - VPNG_PS
+
+/* HW: PA Counters. */
+#define VPNC_PAINVERTCOUNT (VPNG_PA + 1)
+#define VPNC_PAINPRIMCOUNT (VPNG_PA + 2)
+#define VPNC_PAOUTPRIMCOUNT (VPNG_PA + 3)
+#define VPNC_PADEPTHCLIPCOUNT (VPNG_PA + 4)
+#define VPNC_PATRIVIALREJCOUNT (VPNG_PA + 5)
+#define VPNC_PACULLPRIMCOUNT (VPNG_PA + 6)
+#define VPNC_PADROPPRIMCOUNT (VPNG_PA + 7)
+#define VPNC_PAFRCLIPPRIMCOUNT (VPNG_PA + 8)
+#define VPNC_PAFRCLIPDROPPRIMCOUNT (VPNG_PA + 9)
+#define VPNC_PANONIDLESTARVECOUNT (VPNG_PA + 10)
+#define VPNC_PASTARVELCOUNT (VPNG_PA + 11)
+#define VPNC_PASTALLCOUNT (VPNG_PA + 12)
+#define VPNC_PAPROCESSCOUNT (VPNG_PA + 13)
+#define VPNC_PA_COUNT VPNC_PAPROCESSCOUNT - VPNG_PA
+
+/* HW: Setup Counters. */
+#define VPNC_SECULLTRIANGLECOUNT (VPNG_SETUP + 1)
+#define VPNC_SECULLLINECOUNT (VPNG_SETUP + 2)
+#define VPNC_SECLIPTRIANGLECOUNT (VPNG_SETUP + 3)
+#define VPNC_SECLIPLINECOUNT (VPNG_SETUP + 4)
+#define VPNC_SESTARVECOUNT (VPNG_SETUP + 5)
+#define VPNC_SESTALLCOUNT (VPNG_SETUP + 6)
+#define VPNC_SERECEIVETRIANGLECOUNT (VPNG_SETUP + 7)
+#define VPNC_SESENDTRIANGLECOUNT (VPNG_SETUP + 8)
+#define VPNC_SERECEIVELINESCOUNT (VPNG_SETUP + 9)
+#define VPNC_SESENDLINESCOUNT (VPNG_SETUP + 10)
+#define VPNC_SENONIDLESTARVECOUNT (VPNG_SETUP + 11)
+#define VPNC_SETRIVIALREJLINECOUNT (VPNG_SETUP + 12)
+#define VPNC_SEPROCESSCOUNT (VPNG_SETUP + 13)
+#define VPNC_SE_COUNT VPNC_SEPROCESSCOUNT - VPNG_SETUP
+
+/* HW: RA Counters. */
+#define VPNC_RAVALIDPIXCOUNT (VPNG_RA + 1)
+#define VPNC_RATOTALQUADCOUNT (VPNG_RA + 2)
+#define VPNC_RAVALIDQUADCOUNTEZ (VPNG_RA + 3)
+#define VPNC_RAINPUTPRIMCOUNT (VPNG_RA + 4)
+#define VPNC_RAPIPECACHEMISSCOUNT (VPNG_RA + 5)
+#define VPNC_RAPREFCACHEMISSCOUNT (VPNG_RA + 6)
+#define VPNC_RAPIPEHZCACHEMISSCOUNT (VPNG_RA + 7)
+#define VPNC_RAPREFHZCACHEMISSCOUNT (VPNG_RA + 8)
+#define VPNC_RAOUTPUTQUADCOUNT (VPNG_RA + 9)
+#define VPNC_RAOUTPUTPIXELCOUNT (VPNG_RA + 10)
+#define VPNC_RAEEZCULLCOUNT (VPNG_RA + 11)
+#define VPNC_RANONIDLESTARVECOUNT (VPNG_RA + 12)
+#define VPNC_RASTARVELCOUNT (VPNG_RA + 13)
+#define VPNC_RASTALLCOUNT (VPNG_RA + 14)
+#define VPNC_RAPROCESSCOUNT (VPNG_RA + 15)
+#define VPNC_RA_COUNT VPNC_RAPROCESSCOUNT - VPNG_RA
+
+/* HW: TEX Counters. */
+#define VPNC_TXTOTBILINEARREQ (VPNG_TX + 1)
+#define VPNC_TXTOTTRILINEARREQ (VPNG_TX + 2)
+#define VPNC_TXTOTDISCARDTEXREQ (VPNG_TX + 3)
+#define VPNC_TXTOTTEXREQ (VPNG_TX + 4)
+#define VPNC_TXMC0MISSCOUNT (VPNG_TX + 5)
+#define VPNC_TXMC0REQCOUNT (VPNG_TX + 6)
+#define VPNC_TXMC1MISSCOUNT (VPNG_TX + 7)
+#define VPNC_TXMC1REQCOUNT (VPNG_TX + 8)
+#define VPNC_TX_COUNT VPNC_TXMC1REQCOUNT - VPNG_TX
+
+/* HW: PE Counters. */
+#define VPNC_PE0KILLEDBYCOLOR (VPNG_PE + 1)
+#define VPNC_PE0KILLEDBYDEPTH (VPNG_PE + 2)
+#define VPNC_PE0DRAWNBYCOLOR (VPNG_PE + 3)
+#define VPNC_PE0DRAWNBYDEPTH (VPNG_PE + 4)
+#define VPNC_PE1KILLEDBYCOLOR (VPNG_PE + 5)
+#define VPNC_PE1KILLEDBYDEPTH (VPNG_PE + 6)
+#define VPNC_PE1DRAWNBYCOLOR (VPNG_PE + 7)
+#define VPNC_PE1DRAWNBYDEPTH (VPNG_PE + 8)
+#define VPNC_PE_COUNT VPNC_PE1DRAWNBYDEPTH - VPNG_PE
+
+/* HW: MCC Counters. */
+#define VPNC_MCCREADREQ8BCOLORPIPE (VPNG_MCC + 1)
+#define VPNC_MCCREADREQ8BSOCOLORPIPE (VPNG_MCC + 2)
+#define VPNC_MCCWRITEREQ8BCOLORPIPE (VPNG_MCC + 3)
+#define VPNC_MCCREADREQSOCOLORPIPE (VPNG_MCC + 4)
+#define VPNC_MCCWRITEREQCOLORPIPE (VPNG_MCC + 5)
+#define VPNC_MCCREADREQ8BDEPTHPIPE (VPNG_MCC + 6)
+#define VPNC_MCCREADREQ8BSFDEPTHPIPE (VPNG_MCC + 7)
+#define VPNC_MCCWRITEREQ8BDEPTHPIPE (VPNG_MCC + 8)
+#define VPNC_MCCREADREQSFDEPTHPIPE (VPNG_MCC + 9)
+#define VPNC_MCCWRITEREQDEPTHPIPE (VPNG_MCC + 10)
+#define VPNC_MCCREADREQ8BOTHERPIPE (VPNG_MCC + 11)
+#define VPNC_MCCWRITEREQ8BOTHERPIPE (VPNG_MCC + 12)
+#define VPNC_MCCREADREQOTHERPIPE (VPNG_MCC + 13)
+#define VPNC_MCCWRITEREQOTHERPIPE (VPNG_MCC + 14)
+#define VPNC_MCCAXIMINLATENCY (VPNG_MCC + 15)
+#define VPNC_MCCAXIMAXLATENCY (VPNG_MCC + 16)
+#define VPNC_MCCAXITOTALLATENCY (VPNG_MCC + 17)
+#define VPNC_MCCAXISAMPLECOUNT (VPNG_MCC + 18)
+#define VPNC_MCCFEREADBANDWIDTH (VPNG_MCC + 19)
+#define VPNC_MCCMMUREADBANDWIDTH (VPNG_MCC + 20)
+#define VPNC_MCCBLTREADBANDWIDTH (VPNG_MCC + 21)
+#define VPNC_MCCSH0READBANDWIDTH (VPNG_MCC + 22)
+#define VPNC_MCCSH1READBANDWIDTH (VPNG_MCC + 23)
+#define VPNC_MCCPEWRITEBANDWIDTH (VPNG_MCC + 24)
+#define VPNC_MCCBLTWRITEBANDWIDTH (VPNG_MCC + 25)
+#define VPNC_MCCSH0WRITEBANDWIDTH (VPNG_MCC + 26)
+#define VPNC_MCCSH1WRITEBANDWIDTH (VPNG_MCC + 27)
+#define VPNC_MCC_COUNT VPNC_MCCSH1WRITEBANDWIDTH - VPNG_MCC
+
+/* HW: MCZ Counters. */
+#define VPNC_MCZREADREQ8BCOLORPIPE (VPNG_MCZ + 1)
+#define VPNC_MCZREADREQ8BSOCOLORPIPE (VPNG_MCZ + 2)
+#define VPNC_MCZWRITEREQ8BCOLORPIPE (VPNG_MCZ + 3)
+#define VPNC_MCZREADREQSOCOLORPIPE (VPNG_MCZ + 4)
+#define VPNC_MCZWRITEREQCOLORPIPE (VPNG_MCZ + 5)
+#define VPNC_MCZREADREQ8BDEPTHPIPE (VPNG_MCZ + 6)
+#define VPNC_MCZREADREQ8BSFDEPTHPIPE (VPNG_MCZ + 7)
+#define VPNC_MCZWRITEREQ8BDEPTHPIPE (VPNG_MCZ + 8)
+#define VPNC_MCZREADREQSFDEPTHPIPE (VPNG_MCZ + 9)
+#define VPNC_MCZWRITEREQDEPTHPIPE (VPNG_MCZ + 10)
+#define VPNC_MCZREADREQ8BOTHERPIPE (VPNG_MCZ + 11)
+#define VPNC_MCZWRITEREQ8BOTHERPIPE (VPNG_MCZ + 12)
+#define VPNC_MCZREADREQOTHERPIPE (VPNG_MCZ + 13)
+#define VPNC_MCZWRITEREQOTHERPIPE (VPNG_MCZ + 14)
+#define VPNC_MCZAXIMINLATENCY (VPNG_MCZ + 15)
+#define VPNC_MCZAXIMAXLATENCY (VPNG_MCZ + 16)
+#define VPNC_MCZAXITOTALLATENCY (VPNG_MCZ + 17)
+#define VPNC_MCZAXISAMPLECOUNT (VPNG_MCZ + 18)
+#define VPNC_MCZ_COUNT VPNC_MCZAXISAMPLECOUNT - VPNG_MCZ
+
+/* HW: HI Counters. */
+#define VPNC_HI0READ8BYTE (VPNG_HI + 1)
+#define VPNC_HI0WRITE8BYTE (VPNG_HI + 2)
+#define VPNC_HI0READREQ (VPNG_HI + 3)
+#define VPNC_HI0WRITEREQ (VPNG_HI + 4)
+#define VPNC_HI0AXIREADREQSTALL (VPNG_HI + 5)
+#define VPNC_HI0AXIWRITEREQSTALL (VPNG_HI + 6)
+#define VPNC_HI0AXIWRITEDATASTALL (VPNG_HI + 7)
+#define VPNC_HI1READ8BYTE (VPNG_HI + 8)
+#define VPNC_HI1WRITE8BYTE (VPNG_HI + 9)
+#define VPNC_HI1READREQ (VPNG_HI + 10)
+#define VPNC_HI1WRITEREQ (VPNG_HI + 11)
+#define VPNC_HI1AXIREADREQSTALL (VPNG_HI + 12)
+#define VPNC_HI1AXIWRITEREQSTALL (VPNG_HI + 13)
+#define VPNC_HI1AXIWRITEDATASTALL (VPNG_HI + 14)
+#define VPNC_HITOTALCYCLES (VPNG_HI + 15)
+#define VPNC_HIIDLECYCLES (VPNG_HI + 16)
+#define VPNC_HIREAD8BYTE (VPNG_HI + 17)
+#define VPNC_HIWRITE8BYTE (VPNG_HI + 18)
+#define VPNC_HI_COUNT VPNC_HIWRITE8BYTE - VPNG_HI
+
+/* HW: L2 Counters. */
+#define VPNC_L2AXI0READREQCOUNT (VPNG_L2 + 1)
+#define VPNC_L2AXI1READREQCOUNT (VPNG_L2 + 2)
+#define VPNC_L2AXI0WRITEREQCOUNT (VPNG_L2 + 3)
+#define VPNC_L2AXI1WRITEREQCOUNT (VPNG_L2 + 4)
+#define VPNC_L2READTRANSREQBYAXI0 (VPNG_L2 + 5)
+#define VPNC_L2READTRANSREQBYAXI1 (VPNG_L2 + 6)
+#define VPNC_L2WRITETRANSREQBYAXI0 (VPNG_L2 + 7)
+#define VPNC_L2WRITETRANSREQBYAXI1 (VPNG_L2 + 8)
+#define VPNC_L2AXI0MINLATENCY (VPNG_L2 + 9)
+#define VPNC_L2AXI0MAXLATENCY (VPNG_L2 + 10)
+#define VPNC_L2AXI0TOTLATENCY (VPNG_L2 + 11)
+#define VPNC_L2AXI0TOTREQCOUNT (VPNG_L2 + 12)
+#define VPNC_L2AXI1MINLATENCY (VPNG_L2 + 13)
+#define VPNC_L2AXI1MAXLATENCY (VPNG_L2 + 14)
+#define VPNC_L2AXI1TOTLATENCY (VPNG_L2 + 15)
+#define VPNC_L2AXI1TOTREQCOUNT (VPNG_L2 + 16)
+#define VPNC_L2_COUNT VPNC_L2AXI1TOTREQCOUNT - VPNG_L2
+
+/* HW: FE Counters. */
+#define VPNC_FEDRAWCOUNT (VPNG_FE + 1)
+#define VPNC_FEOUTVERTEXCOUNT (VPNG_FE + 2)
+#define VPNC_FECACHEMISSCOUNT (VPNG_FE + 3)
+#define VPNC_FECACHELKCOUNT (VPNG_FE + 4)
+#define VPNC_FESTALLCOUNT (VPNG_FE + 5)
+#define VPNC_FESTARVECOUNT (VPNG_FE + 6)
+#define VPNC_FEPROCESSCOUNT (VPNG_FE + 7)
+#define VPNC_FE_COUNT VPNC_FEPROCESSCOUNT - VPNG_FE
+
+#define TOTAL_COUNTER_NUMBER (VPNC_FE_COUNT + VPNC_VS_COUNT + VPNC_PA_COUNT + VPNC_SE_COUNT + VPNC_RA_COUNT \
+ + VPNC_PS_COUNT + VPNC_TX_COUNT + VPNC_PE_COUNT + VPNC_MCC_COUNT + VPNC_MCZ_COUNT \
+ + VPNC_HI_COUNT + VPNC_L2_COUNT)
+
+#define TOTAL_MODULE_NUMBER 12
+
+/* PROGRAM: Shader program counters. */
+#define VPC_PVSINSTRCOUNT (VPG_PVS + PVS_INSTRCOUNT)
+#define VPC_PVSALUINSTRCOUNT (VPG_PVS + PVS_ALUINSTRCOUNT)
+#define VPC_PVSTEXINSTRCOUNT (VPG_PVS + PVS_TEXINSTRCOUNT)
+#define VPC_PVSATTRIBCOUNT (VPG_PVS + PVS_ATTRIBCOUNT)
+#define VPC_PVSUNIFORMCOUNT (VPG_PVS + PVS_UNIFORMCOUNT)
+#define VPC_PVSFUNCTIONCOUNT (VPG_PVS + PVS_FUNCTIONCOUNT)
+#define VPC_PVSSOURCE (VPG_PVS + PVS_SOURCE)
+
+#define VPC_PPSINSTRCOUNT (VPG_PPS + PPS_INSTRCOUNT)
+#define VPC_PPSALUINSTRCOUNT (VPG_PPS + PPS_ALUINSTRCOUNT)
+#define VPC_PPSTEXINSTRCOUNT (VPG_PPS + PPS_TEXINSTRCOUNT)
+#define VPC_PPSATTRIBCOUNT (VPG_PPS + PPS_ATTRIBCOUNT)
+#define VPC_PPSUNIFORMCOUNT (VPG_PPS + PPS_UNIFORMCOUNT)
+#define VPC_PPSFUNCTIONCOUNT (VPG_PPS + PPS_FUNCTIONCOUNT)
+#define VPC_PPSSOURCE (VPG_PPS + PPS_SOURCE)
+
+#define VPC_PROGRAMHANDLE (VPG_PROG + 1)
+
+#define VPC_ES30_DRAW_NO (VPG_ES30_DRAW + 1)
+#define VPC_ES11_DRAW_NO (VPG_ES11_DRAW + 1)
+#define VPC_ES30_GPU_NO (VPG_MULTI_GPU + 1)
+
+
+#define MODULE_FRONT_END_COUNTER_NUM 0x5
+#define MODULE_VERTEX_SHADER_COUNTER_NUM 0x9
+#define MODULE_PRIMITIVE_ASSEMBLY_COUNTER_NUM 0xC
+#define MODULE_SETUP_COUNTER_NUM 0xD
+#define MODULE_RASTERIZER_COUNTER_NUM 0xE
+#define MODULE_PIXEL_SHADER_COUNTER_NUM 0x9
+#define MODULE_TEXTURE_COUNTER_NUM 0x8
+#define MODULE_PIXEL_ENGINE_COUNTER_NUM 0x8
+#define MODULE_MEMORY_CONTROLLER_COLOR_COUNTER_NUM 0xC
+#define MODULE_MEMORY_CONTROLLER_DEPTH_COUNTER_NUM 0xC
+#define MODULE_HOST_INTERFACE0_COUNTER_NUM 0x9
+#define MODULE_HOST_INTERFACE1_COUNTER_NUM 0x7
+#define MODULE_GPUL2_CACHE_COUNTER_NUM 0xE
+#define TOTAL_PROBE_NUMBER (MODULE_FRONT_END_COUNTER_NUM + MODULE_VERTEX_SHADER_COUNTER_NUM + MODULE_PRIMITIVE_ASSEMBLY_COUNTER_NUM \
+ + MODULE_SETUP_COUNTER_NUM + MODULE_RASTERIZER_COUNTER_NUM + MODULE_PIXEL_SHADER_COUNTER_NUM \
+ + MODULE_TEXTURE_COUNTER_NUM + MODULE_PIXEL_ENGINE_COUNTER_NUM + MODULE_MEMORY_CONTROLLER_COLOR_COUNTER_NUM \
+ + MODULE_MEMORY_CONTROLLER_DEPTH_COUNTER_NUM + MODULE_HOST_INTERFACE0_COUNTER_NUM + MODULE_HOST_INTERFACE1_COUNTER_NUM \
+ + MODULE_GPUL2_CACHE_COUNTER_NUM)
+
+
+#ifdef ANDROID
+#define DEFAULT_PROFILE_FILE_NAME "/sdcard/vprofiler.vpd"
+#else
+#define DEFAULT_PROFILE_FILE_NAME "vprofiler.vpd"
+#endif
+
+#if gcdENDIAN_BIG
+#define BIG_ENDIAN_TRANS_INT(x) ((gctUINT32)( \
+ (((gctUINT32)(x) & (gctUINT32)0x000000FFUL) << 24) | \
+ (((gctUINT32)(x) & (gctUINT32)0x0000FF00UL) << 8) | \
+ (((gctUINT32)(x) & (gctUINT32)0x00FF0000UL) >> 8) | \
+ (((gctUINT32)(x) & (gctUINT32)0xFF000000UL) >> 24)))
+#else
+#define BIG_ENDIAN_TRANS_INT(x) x
+#endif
+
+/* Write a data value. */
+#define gcmWRITE_VALUE(IntData) \
+ do \
+ { \
+ gceSTATUS status; \
+ gctINT32 value = IntData; \
+ value = BIG_ENDIAN_TRANS_INT(value); \
+ gcmERR_BREAK(gcoPROFILER_Write(Profiler, gcmSIZEOF(value), &value)); \
+ } \
+ while (gcvFALSE)
+
+#define gcmWRITE_CONST(Const) \
+ do \
+ { \
+ gceSTATUS status; \
+ gctINT32 data = Const; \
+ data = BIG_ENDIAN_TRANS_INT(data); \
+ gcmERR_BREAK(gcoPROFILER_Write(Profiler, gcmSIZEOF(data), &data)); \
+ } \
+ while (gcvFALSE)
+
+#define gcmWRITE_COUNTER(Counter, Value) \
+ gcmWRITE_CONST(Counter); \
+ gcmWRITE_VALUE(Value)
+
+/* Write a data value. */
+#define gcmRECORD_VALUE(IntData) \
+ do \
+ { \
+ gctINT32 value = IntData; \
+ value = BIG_ENDIAN_TRANS_INT(value); \
+ counterData[counterIndex++] = value; \
+ } \
+ while (gcvFALSE)
+
+#define gcmRECORD_CONST(Const) \
+ do \
+ { \
+ gctINT32 data = Const; \
+ data = BIG_ENDIAN_TRANS_INT(data); \
+ counterData[counterIndex++] = data; \
+ } \
+ while (gcvFALSE)
+
+#define gcmRECORD_COUNTER(Counter, Value) \
+ gcmRECORD_CONST(Counter); \
+ gcmRECORD_VALUE(Value)
+
+/* Write a string value (char*). */
+#define gcmWRITE_STRING(String) \
+ do \
+ { \
+ gceSTATUS status; \
+ gctINT32 length; \
+ length = (gctINT32) gcoOS_StrLen((gctSTRING)String, gcvNULL); \
+ length = BIG_ENDIAN_TRANS_INT(length); \
+ gcmERR_BREAK(gcoPROFILER_Write(Profiler, gcmSIZEOF(length), &length)); \
+ gcmERR_BREAK(gcoPROFILER_Write(Profiler, length, String)); \
+ } \
+ while (gcvFALSE)
+
+#define gcmWRITE_BUFFER(Size, Buffer) \
+ do \
+ { \
+ gceSTATUS status; \
+ gcmERR_BREAK(gcoPROFILER_Write(Profiler, Size, Buffer)); \
+ } \
+ while (gcvFALSE)
+
+#define gcmGET_COUNTER(counter, counterId) \
+ do \
+ { \
+ if ((gctUINT32)*(memory + counterId + offset) == 0xdeaddead) \
+ { \
+ counter = 0xdeaddead; \
+ } \
+ else \
+ { \
+ gctUINT64_PTR Memory = memory; \
+ Memory += TOTAL_PROBE_NUMBER * CoreId; \
+ counter = (gctUINT32)*(Memory + counterId + offset); \
+ } \
+ } \
+ while (gcvFALSE)
+
+#define gcmGET_LATENCY_COUNTER(minLatency, maxLatency, counterId) \
+ do \
+ { \
+ if ((gctUINT32)*(memory + counterId + offset) == 0xdeaddead) \
+ { \
+ minLatency = maxLatency = 0xdeaddead; \
+ } \
+ else \
+ { \
+ gctUINT64_PTR Memory = memory; \
+ Memory += TOTAL_PROBE_NUMBER * CoreId; \
+ maxLatency = (((gctUINT32)*(Memory + counterId + offset) & 0xfff000) >> 12); \
+ minLatency = ((gctUINT32)*(Memory + counterId + offset) & 0x000fff); \
+ if (minLatency == 4095) \
+ minLatency = 0; \
+ } \
+ } \
+ while (gcvFALSE)
+
+typedef enum _gceCOUNTER
+{
+ gcvCOUNTER_FRONT_END,
+ gcvCOUNTER_VERTEX_SHADER,
+ gcvCOUNTER_PRIMITIVE_ASSEMBLY,
+ gcvCOUNTER_SETUP,
+ gcvCOUNTER_RASTERIZER,
+ gcvCOUNTER_PIXEL_SHADER,
+ gcvCOUNTER_TEXTURE,
+ gcvCOUNTER_PIXEL_ENGINE,
+ gcvCOUNTER_MEMORY_CONTROLLER_COLOR,
+ gcvCOUNTER_MEMORY_CONTROLLER_DEPTH,
+ gcvCOUNTER_HOST_INTERFACE0,
+ gcvCOUNTER_HOST_INTERFACE1,
+ gcvCOUNTER_GPUL2_CACHE,
+ gcvCOUNTER_COUNT
+}
+gceCOUNTER;
+
+typedef enum _gceProfilerClient
+{
+ gcvCLIENT_OPENGLES11 = 1,
+ gcvCLIENT_OPENGLES,
+ gcvCLIENT_OPENGL,
+ gcvCLIENT_OPENVG,
+ gcvCLIENT_OPENCL,
+ gcvCLIENT_OPENVX,
+ gcvCLIENT_OPENVK,
+}
+gceProfilerClient;
+
+/* HW profile information. */
+typedef struct _gcsPROFILER_COUNTERS_PART1
+{
+ gctUINT32 gpuTotalRead64BytesPerFrame;
+ gctUINT32 gpuTotalWrite64BytesPerFrame;
+
+ /* FE */
+ gctUINT32 fe_draw_count;
+ gctUINT32 fe_out_vertex_count;
+ gctUINT32 fe_cache_miss_count;
+ gctUINT32 fe_cache_lk_count;
+ gctUINT32 fe_stall_count;
+ gctUINT32 fe_starve_count;
+ gctUINT32 fe_process_count;
+
+ /* PE */
+ gctUINT32 pe0_pixel_count_killed_by_color_pipe;
+ gctUINT32 pe0_pixel_count_killed_by_depth_pipe;
+ gctUINT32 pe0_pixel_count_drawn_by_color_pipe;
+ gctUINT32 pe0_pixel_count_drawn_by_depth_pipe;
+ gctUINT32 pe1_pixel_count_killed_by_color_pipe;
+ gctUINT32 pe1_pixel_count_killed_by_depth_pipe;
+ gctUINT32 pe1_pixel_count_drawn_by_color_pipe;
+ gctUINT32 pe1_pixel_count_drawn_by_depth_pipe;
+
+ /* SH */
+ gctUINT32 shader_cycle_count;
+ gctUINT32 vs_shader_cycle_count;
+ gctUINT32 ps_shader_cycle_count;
+ gctUINT32 ps_inst_counter;
+ gctUINT32 ps_rendered_pixel_counter;
+ gctUINT32 vs_inst_counter;
+ gctUINT32 vs_rendered_vertice_counter;
+ gctUINT32 vs_branch_inst_counter;
+ gctUINT32 vs_texld_inst_counter;
+ gctUINT32 ps_branch_inst_counter;
+ gctUINT32 ps_texld_inst_counter;
+ gctUINT32 vs_non_idle_starve_count;
+ gctUINT32 vs_starve_count;
+ gctUINT32 vs_stall_count;
+ gctUINT32 vs_process_count;
+ gctUINT32 ps_non_idle_starve_count;
+ gctUINT32 ps_starve_count;
+ gctUINT32 ps_stall_count;
+ gctUINT32 ps_process_count;
+
+ /* PA */
+ gctUINT32 pa_input_vtx_counter;
+ gctUINT32 pa_input_prim_counter;
+ gctUINT32 pa_output_prim_counter;
+ gctUINT32 pa_depth_clipped_counter;
+ gctUINT32 pa_trivial_rejected_counter;
+ gctUINT32 pa_culled_prim_counter;
+ gctUINT32 pa_droped_prim_counter;
+ gctUINT32 pa_frustum_clipped_prim_counter;
+ gctUINT32 pa_frustum_clipdroped_prim_counter;
+ gctUINT32 pa_non_idle_starve_count;
+ gctUINT32 pa_starve_count;
+ gctUINT32 pa_stall_count;
+ gctUINT32 pa_process_count;
+
+ /* SE */
+ gctUINT32 se_culled_triangle_count;
+ gctUINT32 se_culled_lines_count;
+ gctUINT32 se_clipped_triangle_count;
+ gctUINT32 se_clipped_line_count;
+ gctUINT32 se_starve_count;
+ gctUINT32 se_stall_count;
+ gctUINT32 se_receive_triangle_count;
+ gctUINT32 se_send_triangle_count;
+ gctUINT32 se_receive_lines_count;
+ gctUINT32 se_send_lines_count;
+ gctUINT32 se_process_count;
+ gctUINT32 se_trivial_rejected_line_count;
+ gctUINT32 se_non_idle_starve_count;
+
+ /* RA */
+ gctUINT32 ra_input_prim_count;
+ gctUINT32 ra_total_quad_count;
+ gctUINT32 ra_valid_quad_count_after_early_z;
+ gctUINT32 ra_valid_pixel_count_to_render;
+ gctUINT32 ra_output_valid_quad_count;
+ gctUINT32 ra_output_valid_pixel_count;
+ gctUINT32 ra_pipe_cache_miss_counter;
+ gctUINT32 ra_pipe_hz_cache_miss_counter;
+ gctUINT32 ra_prefetch_cache_miss_counter;
+ gctUINT32 ra_prefetch_hz_cache_miss_counter;
+ gctUINT32 ra_eez_culled_counter;
+ gctUINT32 ra_non_idle_starve_count;
+ gctUINT32 ra_starve_count;
+ gctUINT32 ra_stall_count;
+ gctUINT32 ra_process_count;
+
+ /* TX */
+ gctUINT32 tx_total_bilinear_requests;
+ gctUINT32 tx_total_trilinear_requests;
+ gctUINT32 tx_total_discarded_texture_requests;
+ gctUINT32 tx_total_texture_requests;
+ gctUINT32 tx_mc0_miss_count;
+ gctUINT32 tx_mc0_request_byte_count;
+ gctUINT32 tx_mc1_miss_count;
+ gctUINT32 tx_mc1_request_byte_count;
+ gctUINT32 tx_non_idle_starve_count;
+ gctUINT32 tx_starve_count;
+ gctUINT32 tx_stall_count;
+ gctUINT32 tx_process_count;
+}
+gcsPROFILER_COUNTERS_PART1;
+
+typedef struct _gcsPROFILER_COUNTERS_PART2
+{
+ /* MCC */
+ gctUINT32 mcc_total_read_req_8B_from_colorpipe;
+ gctUINT32 mcc_total_read_req_8B_sentout_from_colorpipe;
+ gctUINT32 mcc_total_write_req_8B_from_colorpipe;
+ gctUINT32 mcc_total_read_req_sentout_from_colorpipe;
+ gctUINT32 mcc_total_write_req_from_colorpipe;
+ gctUINT32 mcc_total_read_req_8B_from_depthpipe;
+ gctUINT32 mcc_total_read_req_8B_sentout_from_depthpipe;
+ gctUINT32 mcc_total_write_req_8B_from_depthpipe;
+ gctUINT32 mcc_total_read_req_sentout_from_depthpipe;
+ gctUINT32 mcc_total_write_req_from_depthpipe;
+ gctUINT32 mcc_total_read_req_8B_from_others;
+ gctUINT32 mcc_total_write_req_8B_from_others;
+ gctUINT32 mcc_total_read_req_from_others;
+ gctUINT32 mcc_total_write_req_from_others;
+ gctUINT32 mcc_axi_total_latency;
+ gctUINT32 mcc_axi_sample_count;
+ gctUINT32 mcc_axi_max_latency;
+ gctUINT32 mcc_axi_min_latency;
+ gctUINT32 mc_fe_read_bandwidth;
+ gctUINT32 mc_mmu_read_bandwidth;
+ gctUINT32 mc_blt_read_bandwidth;
+ gctUINT32 mc_sh0_read_bandwidth;
+ gctUINT32 mc_sh1_read_bandwidth;
+ gctUINT32 mc_pe_write_bandwidth;
+ gctUINT32 mc_blt_write_bandwidth;
+ gctUINT32 mc_sh0_write_bandwidth;
+ gctUINT32 mc_sh1_write_bandwidth;
+
+ /* MCZ */
+ gctUINT32 mcz_total_read_req_8B_from_colorpipe;
+ gctUINT32 mcz_total_read_req_8B_sentout_from_colorpipe;
+ gctUINT32 mcz_total_write_req_8B_from_colorpipe;
+ gctUINT32 mcz_total_read_req_sentout_from_colorpipe;
+ gctUINT32 mcz_total_write_req_from_colorpipe;
+ gctUINT32 mcz_total_read_req_8B_from_depthpipe;
+ gctUINT32 mcz_total_read_req_8B_sentout_from_depthpipe;
+ gctUINT32 mcz_total_write_req_8B_from_depthpipe;
+ gctUINT32 mcz_total_read_req_sentout_from_depthpipe;
+ gctUINT32 mcz_total_write_req_from_depthpipe;
+ gctUINT32 mcz_total_read_req_8B_from_others;
+ gctUINT32 mcz_total_write_req_8B_from_others;
+ gctUINT32 mcz_total_read_req_from_others;
+ gctUINT32 mcz_total_write_req_from_others;
+ gctUINT32 mcz_axi_total_latency;
+ gctUINT32 mcz_axi_sample_count;
+ gctUINT32 mcz_axi_max_latency;
+ gctUINT32 mcz_axi_min_latency;
+
+ /* HI */
+ gctUINT32 hi0_total_read_8B_count;
+ gctUINT32 hi0_total_write_8B_count;
+ gctUINT32 hi0_total_read_request_count;
+ gctUINT32 hi0_total_write_request_count;
+ gctUINT32 hi0_axi_cycles_read_request_stalled;
+ gctUINT32 hi0_axi_cycles_write_request_stalled;
+ gctUINT32 hi0_axi_cycles_write_data_stalled;
+ gctUINT32 hi1_total_read_8B_count;
+ gctUINT32 hi1_total_write_8B_count;
+ gctUINT32 hi1_total_read_request_count;
+ gctUINT32 hi1_total_write_request_count;
+ gctUINT32 hi1_axi_cycles_read_request_stalled;
+ gctUINT32 hi1_axi_cycles_write_request_stalled;
+ gctUINT32 hi1_axi_cycles_write_data_stalled;
+ gctUINT32 hi_total_cycle_count;
+ gctUINT32 hi_total_idle_cycle_count;
+ gctUINT32 hi_total_read_8B_count;
+ gctUINT32 hi_total_write_8B_count;
+
+ /* L2 */
+ gctUINT32 l2_total_axi0_read_request_count;
+ gctUINT32 l2_total_axi1_read_request_count;
+ gctUINT32 l2_total_axi0_write_request_count;
+ gctUINT32 l2_total_axi1_write_request_count;
+ gctUINT32 l2_total_read_transactions_request_by_axi0;
+ gctUINT32 l2_total_read_transactions_request_by_axi1;
+ gctUINT32 l2_total_write_transactions_request_by_axi0;
+ gctUINT32 l2_total_write_transactions_request_by_axi1;
+ gctUINT32 l2_axi0_minmax_latency;
+ gctUINT32 l2_axi0_min_latency;
+ gctUINT32 l2_axi0_max_latency;
+ gctUINT32 l2_axi0_total_latency;
+ gctUINT32 l2_axi0_total_request_count;
+ gctUINT32 l2_axi1_minmax_latency;
+ gctUINT32 l2_axi1_min_latency;
+ gctUINT32 l2_axi1_max_latency;
+ gctUINT32 l2_axi1_total_latency;
+ gctUINT32 l2_axi1_total_request_count;
+}
+gcsPROFILER_COUNTERS_PART2;
+
+typedef struct _gcsPROFILER_COUNTERS
+{
+ gcsPROFILER_COUNTERS_PART1 counters_part1;
+ gcsPROFILER_COUNTERS_PART2 counters_part2;
+}
+gcsPROFILER_COUNTERS;
+
+#define NumOfPerFrameBuf 16
+#define NumOfPerDrawBuf 128
+
+typedef enum _gceCOUNTER_OPTYPE
+{
+ gcvCOUNTER_OP_DRAW = 0,
+ gcvCOUNTER_OP_BLT = 1,
+ gcvCOUNTER_OP_COMPUTE = 2,
+ gcvCOUNTER_OP_RS = 3,
+ gcvCOUNTER_OP_FINISH = 4,
+ gcvCOUNTER_OP_FRAME = 5,
+ gcvCOUNTER_OP_NONE = 6
+}
+gceCOUNTER_OPTYPE;
+
+typedef struct gcsCounterBuffer * gcsCounterBuffer_PTR;
+
+struct gcsCounterBuffer
+{
+ gcsPROFILER_COUNTERS *counters;
+ gctHANDLE couterBufobj;
+ gctUINT32 probeAddress;
+ gctPOINTER logicalAddress;
+ gceCOUNTER_OPTYPE opType;
+ gctUINT32 opID;
+ gctUINT32 startPos;
+ gctUINT32 endPos;
+ gctUINT32 dataSize;
+ gctBOOL available;
+ gctBOOL needDump;
+ gcsCounterBuffer_PTR next;
+ gcsCounterBuffer_PTR prev;
+};
+
+typedef struct _gcoPROFILER * gcoPROFILER;
+
+struct _gcoPROFILER
+{
+ gctBOOL enable;
+ gctBOOL enablePrint;
+ gctBOOL disableProbe;
+ gctBOOL probeMode;
+
+ gctFILE file;
+ gctCHAR* fileName;
+
+ gcsCounterBuffer_PTR counterBuf;
+ gctUINT32 bufferCount;
+
+ gctBOOL perDrawMode;
+ gctBOOL needDump;
+ gctBOOL counterEnable;
+
+ gceProfilerClient profilerClient;
+
+ /*query some features from hw*/
+ gctUINT32 coreCount;
+ gctUINT32 shaderCoreCount;
+ gctBOOL bHalti4;
+ gctBOOL psRenderPixelFix;
+ gctBOOL axiBus128bits;
+};
+
+typedef enum _gceProbeStatus
+{
+ gcvPROBE_Disabled = 0,
+ gcvPROBE_Paused = 1,
+ gcvPROBE_Enabled = 2,
+}
+gceProbeStatus;
+
+typedef enum _gceProbeCmd
+{
+ gcvPROBECMD_BEGIN = 0,
+ gcvPROBECMD_PAUSE = 1,
+ gcvPROBECMD_RESUME = 2,
+ gcvPROBECMD_END = 3,
+}
+gceProbeCmd;
+
+typedef struct _gcsPROBESTATES
+{
+ gceProbeStatus status;
+ gctUINT32 probeAddress;
+}gcsPROBESTATES;
+
+/* Construct a Profiler object per context. */
+gceSTATUS
+gcoPROFILER_Construct(
+ OUT gcoPROFILER * Profiler
+ );
+
+gceSTATUS
+gcoPROFILER_Destroy(
+ IN gcoPROFILER Profiler
+ );
+
+gceSTATUS
+gcoPROFILER_Enable(
+ IN gcoPROFILER Profiler
+ );
+
+gceSTATUS
+gcoPROFILER_Disable(
+ void
+ );
+
+gceSTATUS
+gcoPROFILER_Begin(
+ IN gcoPROFILER Profiler,
+ IN gceCOUNTER_OPTYPE operationType
+ );
+
+gceSTATUS
+gcoPROFILER_End(
+ IN gcoPROFILER Profiler,
+ IN gceCOUNTER_OPTYPE operationType,
+ IN gctUINT32 OpID
+ );
+
+gceSTATUS
+gcoPROFILER_Write(
+ IN gcoPROFILER Profiler,
+ IN gctSIZE_T ByteCount,
+ IN gctCONST_POINTER Data
+ );
+
+gceSTATUS
+gcoPROFILER_Flush(
+ IN gcoPROFILER Profiler
+ );
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_profiler_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_raster.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_raster.h
new file mode 100644
index 000000000000..988577ff9285
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_raster.h
@@ -0,0 +1,1109 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_raster_h_
+#define __gc_hal_raster_h_
+
+#include "gc_hal_enum.h"
+#include "gc_hal_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+****************************** Object Declarations *****************************
+\******************************************************************************/
+
+typedef struct _gcoBRUSH * gcoBRUSH;
+typedef struct _gcoBRUSH_CACHE * gcoBRUSH_CACHE;
+
+/******************************************************************************\
+******************************** gcoBRUSH Object *******************************
+\******************************************************************************/
+
+/* Create a new solid color gcoBRUSH object. */
+gceSTATUS
+gcoBRUSH_ConstructSingleColor(
+ IN gcoHAL Hal,
+ IN gctUINT32 ColorConvert,
+ IN gctUINT32 Color,
+ IN gctUINT64 Mask,
+ gcoBRUSH * Brush
+ );
+
+/* Create a new monochrome gcoBRUSH object. */
+gceSTATUS
+gcoBRUSH_ConstructMonochrome(
+ IN gcoHAL Hal,
+ IN gctUINT32 OriginX,
+ IN gctUINT32 OriginY,
+ IN gctUINT32 ColorConvert,
+ IN gctUINT32 FgColor,
+ IN gctUINT32 BgColor,
+ IN gctUINT64 Bits,
+ IN gctUINT64 Mask,
+ gcoBRUSH * Brush
+ );
+
+/* Create a color gcoBRUSH object. */
+gceSTATUS
+gcoBRUSH_ConstructColor(
+ IN gcoHAL Hal,
+ IN gctUINT32 OriginX,
+ IN gctUINT32 OriginY,
+ IN gctPOINTER Address,
+ IN gceSURF_FORMAT Format,
+ IN gctUINT64 Mask,
+ gcoBRUSH * Brush
+ );
+
+/* Destroy an gcoBRUSH object. */
+gceSTATUS
+gcoBRUSH_Destroy(
+ IN gcoBRUSH Brush
+ );
+
+/******************************************************************************\
+******************************** gcoSURF Object *******************************
+\******************************************************************************/
+
+/* Set cipping rectangle. */
+gceSTATUS
+gcoSURF_SetClipping(
+ IN gcoSURF Surface
+ );
+
+/* Clear one or more rectangular areas. */
+gceSTATUS
+gcoSURF_Clear2D(
+ IN gcoSURF DestSurface,
+ IN gctUINT32 RectCount,
+ IN gcsRECT_PTR DestRect,
+ IN gctUINT32 LoColor,
+ IN gctUINT32 HiColor
+ );
+
+/* Draw one or more Bresenham lines. */
+gceSTATUS
+gcoSURF_Line(
+ IN gcoSURF Surface,
+ IN gctUINT32 LineCount,
+ IN gcsRECT_PTR Position,
+ IN gcoBRUSH Brush,
+ IN gctUINT8 FgRop,
+ IN gctUINT8 BgRop
+ );
+
+/* Generic rectangular blit. */
+gceSTATUS
+gcoSURF_Blit(
+ IN OPTIONAL gcoSURF SrcSurface,
+ IN gcoSURF DestSurface,
+ IN gctUINT32 RectCount,
+ IN OPTIONAL gcsRECT_PTR SrcRect,
+ IN gcsRECT_PTR DestRect,
+ IN OPTIONAL gcoBRUSH Brush,
+ IN gctUINT8 FgRop,
+ IN gctUINT8 BgRop,
+ IN OPTIONAL gceSURF_TRANSPARENCY Transparency,
+ IN OPTIONAL gctUINT32 TransparencyColor,
+ IN OPTIONAL gctPOINTER Mask,
+ IN OPTIONAL gceSURF_MONOPACK MaskPack
+ );
+
+/* Monochrome blit. */
+gceSTATUS
+gcoSURF_MonoBlit(
+ IN gcoSURF DestSurface,
+ IN gctPOINTER Source,
+ IN gceSURF_MONOPACK SourcePack,
+ IN gcsPOINT_PTR SourceSize,
+ IN gcsPOINT_PTR SourceOrigin,
+ IN gcsRECT_PTR DestRect,
+ IN OPTIONAL gcoBRUSH Brush,
+ IN gctUINT8 FgRop,
+ IN gctUINT8 BgRop,
+ IN gctBOOL ColorConvert,
+ IN gctUINT8 MonoTransparency,
+ IN gceSURF_TRANSPARENCY Transparency,
+ IN gctUINT32 FgColor,
+ IN gctUINT32 BgColor
+ );
+
+/* Filter blit. */
+gceSTATUS
+gcoSURF_FilterBlit(
+ IN gcoSURF SrcSurface,
+ IN gcoSURF DestSurface,
+ IN gcsRECT_PTR SrcRect,
+ IN gcsRECT_PTR DestRect,
+ IN gcsRECT_PTR DestSubRect
+ );
+
+/* Enable alpha blending engine in the hardware and disengage the ROP engine. */
+gceSTATUS
+gcoSURF_EnableAlphaBlend(
+ IN gcoSURF Surface,
+ IN gctUINT8 SrcGlobalAlphaValue,
+ IN gctUINT8 DstGlobalAlphaValue,
+ IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode,
+ IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode,
+ IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode,
+ IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode,
+ IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode,
+ IN gceSURF_BLEND_FACTOR_MODE DstFactorMode,
+ IN gceSURF_PIXEL_COLOR_MODE SrcColorMode,
+ IN gceSURF_PIXEL_COLOR_MODE DstColorMode
+ );
+
+/* Disable alpha blending engine in the hardware and engage the ROP engine. */
+gceSTATUS
+gcoSURF_DisableAlphaBlend(
+ IN gcoSURF Surface
+ );
+
+gceSTATUS
+gcoSURF_SetDither(
+ IN gcoSURF Surface,
+ IN gctBOOL Dither
+ );
+
+gceSTATUS
+gcoSURF_Set2DSource(
+ gcoSURF Surface,
+ gceSURF_ROTATION Rotation
+ );
+
+gceSTATUS
+gcoSURF_Set2DTarget(
+ gcoSURF Surface,
+ gceSURF_ROTATION Rotation
+ );
+
+/******************************************************************************\
+********************************** gco2D Object *********************************
+\******************************************************************************/
+
+/* Construct a new gco2D object. */
+gceSTATUS
+gco2D_Construct(
+ IN gcoHAL Hal,
+ OUT gco2D * Hardware
+ );
+
+/* Destroy an gco2D object. */
+gceSTATUS
+gco2D_Destroy(
+ IN gco2D Hardware
+ );
+
+/* Sets the maximum number of brushes in the brush cache. */
+gceSTATUS
+gco2D_SetBrushLimit(
+ IN gco2D Hardware,
+ IN gctUINT MaxCount
+ );
+
+/* Flush the brush. */
+gceSTATUS
+gco2D_FlushBrush(
+ IN gco2D Engine,
+ IN gcoBRUSH Brush,
+ IN gceSURF_FORMAT Format
+ );
+
+/* Program the specified solid color brush. */
+gceSTATUS
+gco2D_LoadSolidBrush(
+ IN gco2D Engine,
+ IN gceSURF_FORMAT Format,
+ IN gctUINT32 ColorConvert,
+ IN gctUINT32 Color,
+ IN gctUINT64 Mask
+ );
+
+gceSTATUS
+gco2D_LoadMonochromeBrush(
+ IN gco2D Engine,
+ IN gctUINT32 OriginX,
+ IN gctUINT32 OriginY,
+ IN gctUINT32 ColorConvert,
+ IN gctUINT32 FgColor,
+ IN gctUINT32 BgColor,
+ IN gctUINT64 Bits,
+ IN gctUINT64 Mask
+ );
+
+gceSTATUS
+gco2D_LoadColorBrush(
+ IN gco2D Engine,
+ IN gctUINT32 OriginX,
+ IN gctUINT32 OriginY,
+ IN gctUINT32 Address,
+ IN gceSURF_FORMAT Format,
+ IN gctUINT64 Mask
+ );
+
+/* Configure monochrome source. */
+gceSTATUS
+gco2D_SetMonochromeSource(
+ IN gco2D Engine,
+ IN gctBOOL ColorConvert,
+ IN gctUINT8 MonoTransparency,
+ IN gceSURF_MONOPACK DataPack,
+ IN gctBOOL CoordRelative,
+ IN gceSURF_TRANSPARENCY Transparency,
+ IN gctUINT32 FgColor,
+ IN gctUINT32 BgColor
+ );
+
+/* Configure color source. */
+gceSTATUS
+gco2D_SetColorSource(
+ IN gco2D Engine,
+ IN gctUINT32 Address,
+ IN gctUINT32 Stride,
+ IN gceSURF_FORMAT Format,
+ IN gceSURF_ROTATION Rotation,
+ IN gctUINT32 SurfaceWidth,
+ IN gctBOOL CoordRelative,
+ IN gceSURF_TRANSPARENCY Transparency,
+ IN gctUINT32 TransparencyColor
+ );
+
+/* Configure color source extension for full rotation. */
+gceSTATUS
+gco2D_SetColorSourceEx(
+ IN gco2D Engine,
+ IN gctUINT32 Address,
+ IN gctUINT32 Stride,
+ IN gceSURF_FORMAT Format,
+ IN gceSURF_ROTATION Rotation,
+ IN gctUINT32 SurfaceWidth,
+ IN gctUINT32 SurfaceHeight,
+ IN gctBOOL CoordRelative,
+ IN gceSURF_TRANSPARENCY Transparency,
+ IN gctUINT32 TransparencyColor
+ );
+
+/* Same as gco2D_SetColorSourceEx, but with better 64bit SW-path support.
+** Please do NOT export the API now.
+*/
+gceSTATUS
+gco2D_SetColorSource64(
+ IN gco2D Engine,
+ IN gctUINT32 Address,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Stride,
+ IN gceSURF_FORMAT Format,
+ IN gceSURF_ROTATION Rotation,
+ IN gctUINT32 SurfaceWidth,
+ IN gctUINT32 SurfaceHeight,
+ IN gctBOOL CoordRelative,
+ IN gceSURF_TRANSPARENCY Transparency,
+ IN gctUINT32 TransparencyColor
+ );
+
+/* Configure color source. */
+gceSTATUS
+gco2D_SetColorSourceAdvanced(
+ IN gco2D Engine,
+ IN gctUINT32 Address,
+ IN gctUINT32 Stride,
+ IN gceSURF_FORMAT Format,
+ IN gceSURF_ROTATION Rotation,
+ IN gctUINT32 SurfaceWidth,
+ IN gctUINT32 SurfaceHeight,
+ IN gctBOOL CoordRelative
+ );
+
+gceSTATUS
+gco2D_SetColorSourceN(
+ IN gco2D Engine,
+ IN gctUINT32 Address,
+ IN gctUINT32 Stride,
+ IN gceSURF_FORMAT Format,
+ IN gceSURF_ROTATION Rotation,
+ IN gctUINT32 SurfaceWidth,
+ IN gctUINT32 SurfaceHeight,
+ IN gctUINT32 SurfaceNumber
+ );
+
+/* Configure masked color source. */
+gceSTATUS
+gco2D_SetMaskedSource(
+ IN gco2D Engine,
+ IN gctUINT32 Address,
+ IN gctUINT32 Stride,
+ IN gceSURF_FORMAT Format,
+ IN gctBOOL CoordRelative,
+ IN gceSURF_MONOPACK MaskPack
+ );
+
+/* Configure masked color source extension for full rotation. */
+gceSTATUS
+gco2D_SetMaskedSourceEx(
+ IN gco2D Engine,
+ IN gctUINT32 Address,
+ IN gctUINT32 Stride,
+ IN gceSURF_FORMAT Format,
+ IN gctBOOL CoordRelative,
+ IN gceSURF_MONOPACK MaskPack,
+ IN gceSURF_ROTATION Rotation,
+ IN gctUINT32 SurfaceWidth,
+ IN gctUINT32 SurfaceHeight
+ );
+
+/* Same as gco2D_SetMaskedSourceEx, but with better 64bit SW-path support.
+** Please do NOT export the API now.
+*/
+gceSTATUS
+gco2D_SetMaskedSource64(
+ IN gco2D Engine,
+ IN gctUINT32 Address,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Stride,
+ IN gceSURF_FORMAT Format,
+ IN gctBOOL CoordRelative,
+ IN gceSURF_MONOPACK MaskPack,
+ IN gceSURF_ROTATION Rotation,
+ IN gctUINT32 SurfaceWidth,
+ IN gctUINT32 SurfaceHeight
+ );
+
+/* Setup the source rectangle. */
+gceSTATUS
+gco2D_SetSource(
+ IN gco2D Engine,
+ IN gcsRECT_PTR SrcRect
+ );
+
+/* Set clipping rectangle. */
+gceSTATUS
+gco2D_SetClipping(
+ IN gco2D Engine,
+ IN gcsRECT_PTR Rect
+ );
+
+/* Configure destination. */
+gceSTATUS
+gco2D_SetTarget(
+ IN gco2D Engine,
+ IN gctUINT32 Address,
+ IN gctUINT32 Stride,
+ IN gceSURF_ROTATION Rotation,
+ IN gctUINT32 SurfaceWidth
+ );
+
+/* Configure destination extension for full rotation. */
+gceSTATUS
+gco2D_SetTargetEx(
+ IN gco2D Engine,
+ IN gctUINT32 Address,
+ IN gctUINT32 Stride,
+ IN gceSURF_ROTATION Rotation,
+ IN gctUINT32 SurfaceWidth,
+ IN gctUINT32 SurfaceHeight
+ );
+
+/* Same as gco2D_SetTargetEx, but with better 64bit SW-path support.
+** Please do NOT export the API now.
+*/
+gceSTATUS
+gco2D_SetTarget64(
+ IN gco2D Engine,
+ IN gctUINT32 Address,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Stride,
+ IN gceSURF_ROTATION Rotation,
+ IN gctUINT32 SurfaceWidth,
+ IN gctUINT32 SurfaceHeight
+ );
+
+
+/* Calculate and program the stretch factors. */
+gceSTATUS
+gco2D_CalcStretchFactor(
+ IN gco2D Engine,
+ IN gctINT32 SrcSize,
+ IN gctINT32 DestSize,
+ OUT gctUINT32_PTR Factor
+ );
+
+gceSTATUS
+gco2D_SetStretchFactors(
+ IN gco2D Engine,
+ IN gctUINT32 HorFactor,
+ IN gctUINT32 VerFactor
+ );
+
+/* Calculate and program the stretch factors based on the rectangles. */
+gceSTATUS
+gco2D_SetStretchRectFactors(
+ IN gco2D Engine,
+ IN gcsRECT_PTR SrcRect,
+ IN gcsRECT_PTR DestRect
+ );
+
+/* Create a new solid color gcoBRUSH object. */
+gceSTATUS
+gco2D_ConstructSingleColorBrush(
+ IN gco2D Engine,
+ IN gctUINT32 ColorConvert,
+ IN gctUINT32 Color,
+ IN gctUINT64 Mask,
+ gcoBRUSH * Brush
+ );
+
+/* Create a new monochrome gcoBRUSH object. */
+gceSTATUS
+gco2D_ConstructMonochromeBrush(
+ IN gco2D Engine,
+ IN gctUINT32 OriginX,
+ IN gctUINT32 OriginY,
+ IN gctUINT32 ColorConvert,
+ IN gctUINT32 FgColor,
+ IN gctUINT32 BgColor,
+ IN gctUINT64 Bits,
+ IN gctUINT64 Mask,
+ gcoBRUSH * Brush
+ );
+
+/* Create a color gcoBRUSH object. */
+gceSTATUS
+gco2D_ConstructColorBrush(
+ IN gco2D Engine,
+ IN gctUINT32 OriginX,
+ IN gctUINT32 OriginY,
+ IN gctPOINTER Address,
+ IN gceSURF_FORMAT Format,
+ IN gctUINT64 Mask,
+ gcoBRUSH * Brush
+ );
+
+/* Clear one or more rectangular areas. */
+gceSTATUS
+gco2D_Clear(
+ IN gco2D Engine,
+ IN gctUINT32 RectCount,
+ IN gcsRECT_PTR Rect,
+ IN gctUINT32 Color32,
+ IN gctUINT8 FgRop,
+ IN gctUINT8 BgRop,
+ IN gceSURF_FORMAT DestFormat
+ );
+
+/* Draw one or more Bresenham lines. */
+gceSTATUS
+gco2D_Line(
+ IN gco2D Engine,
+ IN gctUINT32 LineCount,
+ IN gcsRECT_PTR Position,
+ IN gcoBRUSH Brush,
+ IN gctUINT8 FgRop,
+ IN gctUINT8 BgRop,
+ IN gceSURF_FORMAT DestFormat
+ );
+
+/* Draw one or more Bresenham lines based on the 32-bit color. */
+gceSTATUS
+gco2D_ColorLine(
+ IN gco2D Engine,
+ IN gctUINT32 LineCount,
+ IN gcsRECT_PTR Position,
+ IN gctUINT32 Color32,
+ IN gctUINT8 FgRop,
+ IN gctUINT8 BgRop,
+ IN gceSURF_FORMAT DestFormat
+ );
+
+/* Generic blit. */
+gceSTATUS
+gco2D_Blit(
+ IN gco2D Engine,
+ IN gctUINT32 RectCount,
+ IN gcsRECT_PTR Rect,
+ IN gctUINT8 FgRop,
+ IN gctUINT8 BgRop,
+ IN gceSURF_FORMAT DestFormat
+ );
+
+gceSTATUS
+gco2D_Blend(
+ IN gco2D Engine,
+ IN gctUINT32 SrcCount,
+ IN gctUINT32 RectCount,
+ IN gcsRECT_PTR Rect,
+ IN gctUINT8 FgRop,
+ IN gctUINT8 BgRop,
+ IN gceSURF_FORMAT DestFormat
+ );
+
+/* Batch blit. */
+gceSTATUS
+gco2D_BatchBlit(
+ IN gco2D Engine,
+ IN gctUINT32 RectCount,
+ IN gcsRECT_PTR SrcRect,
+ IN gcsRECT_PTR DestRect,
+ IN gctUINT8 FgRop,
+ IN gctUINT8 BgRop,
+ IN gceSURF_FORMAT DestFormat
+ );
+
+/* Stretch blit. */
+gceSTATUS
+gco2D_StretchBlit(
+ IN gco2D Engine,
+ IN gctUINT32 RectCount,
+ IN gcsRECT_PTR Rect,
+ IN gctUINT8 FgRop,
+ IN gctUINT8 BgRop,
+ IN gceSURF_FORMAT DestFormat
+ );
+
+/* Monochrome blit. */
+gceSTATUS
+gco2D_MonoBlit(
+ IN gco2D Engine,
+ IN gctPOINTER StreamBits,
+ IN gcsPOINT_PTR StreamSize,
+ IN gcsRECT_PTR StreamRect,
+ IN gceSURF_MONOPACK SrcStreamPack,
+ IN gceSURF_MONOPACK DestStreamPack,
+ IN gcsRECT_PTR DestRect,
+ IN gctUINT32 FgRop,
+ IN gctUINT32 BgRop,
+ IN gceSURF_FORMAT DestFormat
+ );
+
+gceSTATUS
+gco2D_MonoBlitEx(
+ IN gco2D Engine,
+ IN gctPOINTER StreamBits,
+ IN gctINT32 StreamStride,
+ IN gctINT32 StreamWidth,
+ IN gctINT32 StreamHeight,
+ IN gctINT32 StreamX,
+ IN gctINT32 StreamY,
+ IN gctUINT32 FgColor,
+ IN gctUINT32 BgColor,
+ IN gcsRECT_PTR SrcRect,
+ IN gcsRECT_PTR DstRect,
+ IN gctUINT8 FgRop,
+ IN gctUINT8 BgRop
+ );
+
+/* Set kernel size. */
+gceSTATUS
+gco2D_SetKernelSize(
+ IN gco2D Engine,
+ IN gctUINT8 HorKernelSize,
+ IN gctUINT8 VerKernelSize
+ );
+
+/* Set filter type. */
+gceSTATUS
+gco2D_SetFilterType(
+ IN gco2D Engine,
+ IN gceFILTER_TYPE FilterType
+ );
+
+/* Set the filter kernel by user. */
+gceSTATUS
+gco2D_SetUserFilterKernel(
+ IN gco2D Engine,
+ IN gceFILTER_PASS_TYPE PassType,
+ IN gctUINT16_PTR KernelArray
+ );
+
+/* Select the pass(es) to be done for user defined filter. */
+gceSTATUS
+gco2D_EnableUserFilterPasses(
+ IN gco2D Engine,
+ IN gctBOOL HorPass,
+ IN gctBOOL VerPass
+ );
+
+/* Frees the temporary buffer allocated by filter blit operation. */
+gceSTATUS
+gco2D_FreeFilterBuffer(
+ IN gco2D Engine
+ );
+
+/* Filter blit. */
+gceSTATUS
+gco2D_FilterBlit(
+ IN gco2D Engine,
+ IN gctUINT32 SrcAddress,
+ IN gctUINT SrcStride,
+ IN gctUINT32 SrcUAddress,
+ IN gctUINT SrcUStride,
+ IN gctUINT32 SrcVAddress,
+ IN gctUINT SrcVStride,
+ IN gceSURF_FORMAT SrcFormat,
+ IN gceSURF_ROTATION SrcRotation,
+ IN gctUINT32 SrcSurfaceWidth,
+ IN gcsRECT_PTR SrcRect,
+ IN gctUINT32 DestAddress,
+ IN gctUINT DestStride,
+ IN gceSURF_FORMAT DestFormat,
+ IN gceSURF_ROTATION DestRotation,
+ IN gctUINT32 DestSurfaceWidth,
+ IN gcsRECT_PTR DestRect,
+ IN gcsRECT_PTR DestSubRect
+ );
+
+/* Filter blit extension for full rotation. */
+gceSTATUS
+gco2D_FilterBlitEx(
+ IN gco2D Engine,
+ IN gctUINT32 SrcAddress,
+ IN gctUINT SrcStride,
+ IN gctUINT32 SrcUAddress,
+ IN gctUINT SrcUStride,
+ IN gctUINT32 SrcVAddress,
+ IN gctUINT SrcVStride,
+ IN gceSURF_FORMAT SrcFormat,
+ IN gceSURF_ROTATION SrcRotation,
+ IN gctUINT32 SrcSurfaceWidth,
+ IN gctUINT32 SrcSurfaceHeight,
+ IN gcsRECT_PTR SrcRect,
+ IN gctUINT32 DestAddress,
+ IN gctUINT DestStride,
+ IN gceSURF_FORMAT DestFormat,
+ IN gceSURF_ROTATION DestRotation,
+ IN gctUINT32 DestSurfaceWidth,
+ IN gctUINT32 DestSurfaceHeight,
+ IN gcsRECT_PTR DestRect,
+ IN gcsRECT_PTR DestSubRect
+ );
+
+gceSTATUS
+gco2D_FilterBlitEx2(
+ IN gco2D Engine,
+ IN gctUINT32_PTR SrcAddresses,
+ IN gctUINT32 SrcAddressNum,
+ IN gctUINT32_PTR SrcStrides,
+ IN gctUINT32 SrcStrideNum,
+ IN gceTILING SrcTiling,
+ IN gceSURF_FORMAT SrcFormat,
+ IN gceSURF_ROTATION SrcRotation,
+ IN gctUINT32 SrcSurfaceWidth,
+ IN gctUINT32 SrcSurfaceHeight,
+ IN gcsRECT_PTR SrcRect,
+ IN gctUINT32_PTR DestAddresses,
+ IN gctUINT32 DestAddressNum,
+ IN gctUINT32_PTR DestStrides,
+ IN gctUINT32 DestStrideNum,
+ IN gceTILING DestTiling,
+ IN gceSURF_FORMAT DestFormat,
+ IN gceSURF_ROTATION DestRotation,
+ IN gctUINT32 DestSurfaceWidth,
+ IN gctUINT32 DestSurfaceHeight,
+ IN gcsRECT_PTR DestRect,
+ IN gcsRECT_PTR DestSubRect
+ );
+
+/* Enable alpha blending engine in the hardware and disengage the ROP engine. */
+gceSTATUS
+gco2D_EnableAlphaBlend(
+ IN gco2D Engine,
+ IN gctUINT8 SrcGlobalAlphaValue,
+ IN gctUINT8 DstGlobalAlphaValue,
+ IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode,
+ IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode,
+ IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode,
+ IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode,
+ IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode,
+ IN gceSURF_BLEND_FACTOR_MODE DstFactorMode,
+ IN gceSURF_PIXEL_COLOR_MODE SrcColorMode,
+ IN gceSURF_PIXEL_COLOR_MODE DstColorMode
+ );
+
+/* Enable alpha blending engine in the hardware. */
+gceSTATUS
+gco2D_EnableAlphaBlendAdvanced(
+ IN gco2D Engine,
+ IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode,
+ IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode,
+ IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode,
+ IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode,
+ IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode,
+ IN gceSURF_BLEND_FACTOR_MODE DstFactorMode
+ );
+
+/* Enable alpha blending engine with Porter Duff rule. */
+gceSTATUS
+gco2D_SetPorterDuffBlending(
+ IN gco2D Engine,
+ IN gce2D_PORTER_DUFF_RULE Rule
+ );
+
+/* Disable alpha blending engine in the hardware and engage the ROP engine. */
+gceSTATUS
+gco2D_DisableAlphaBlend(
+ IN gco2D Engine
+ );
+
+/* Retrieve the maximum number of 32-bit data chunks for a single DE command. */
+gctUINT32
+gco2D_GetMaximumDataCount(
+ void
+ );
+
+/* Retrieve the maximum number of rectangles, that can be passed in a single DE command. */
+gctUINT32
+gco2D_GetMaximumRectCount(
+ void
+ );
+
+/* Returns the pixel alignment of the surface. */
+gceSTATUS
+gco2D_GetPixelAlignment(
+ gceSURF_FORMAT Format,
+ gcsPOINT_PTR Alignment
+ );
+
+/* Retrieve monochrome stream pack size. */
+gceSTATUS
+gco2D_GetPackSize(
+ IN gceSURF_MONOPACK StreamPack,
+ OUT gctUINT32 * PackWidth,
+ OUT gctUINT32 * PackHeight
+ );
+
+/* Flush the 2D pipeline. */
+gceSTATUS
+gco2D_Flush(
+ IN gco2D Engine
+ );
+
+/* Load 256-entry color table for INDEX8 source surfaces. */
+gceSTATUS
+gco2D_LoadPalette(
+ IN gco2D Engine,
+ IN gctUINT FirstIndex,
+ IN gctUINT IndexCount,
+ IN gctPOINTER ColorTable,
+ IN gctBOOL ColorConvert
+ );
+
+/* Enable/disable 2D BitBlt mirrorring. */
+gceSTATUS
+gco2D_SetBitBlitMirror(
+ IN gco2D Engine,
+ IN gctBOOL HorizontalMirror,
+ IN gctBOOL VerticalMirror
+ );
+
+/*
+ * Set the transparency for source, destination and pattern.
+ * It also enable or disable the DFB color key mode.
+ */
+gceSTATUS
+gco2D_SetTransparencyAdvancedEx(
+ IN gco2D Engine,
+ IN gce2D_TRANSPARENCY SrcTransparency,
+ IN gce2D_TRANSPARENCY DstTransparency,
+ IN gce2D_TRANSPARENCY PatTransparency,
+ IN gctBOOL EnableDFBColorKeyMode
+ );
+
+/* Set the transparency for source, destination and pattern. */
+gceSTATUS
+gco2D_SetTransparencyAdvanced(
+ IN gco2D Engine,
+ IN gce2D_TRANSPARENCY SrcTransparency,
+ IN gce2D_TRANSPARENCY DstTransparency,
+ IN gce2D_TRANSPARENCY PatTransparency
+ );
+
+/* Set the source color key. */
+gceSTATUS
+gco2D_SetSourceColorKeyAdvanced(
+ IN gco2D Engine,
+ IN gctUINT32 ColorKey
+ );
+
+/* Set the source color key range. */
+gceSTATUS
+gco2D_SetSourceColorKeyRangeAdvanced(
+ IN gco2D Engine,
+ IN gctUINT32 ColorKeyLow,
+ IN gctUINT32 ColorKeyHigh
+ );
+
+/* Set the target color key. */
+gceSTATUS
+gco2D_SetTargetColorKeyAdvanced(
+ IN gco2D Engine,
+ IN gctUINT32 ColorKey
+ );
+
+/* Set the target color key range. */
+gceSTATUS
+gco2D_SetTargetColorKeyRangeAdvanced(
+ IN gco2D Engine,
+ IN gctUINT32 ColorKeyLow,
+ IN gctUINT32 ColorKeyHigh
+ );
+
+/* Set the YUV color space mode. */
+gceSTATUS
+gco2D_SetYUVColorMode(
+ IN gco2D Engine,
+ IN gce2D_YUV_COLOR_MODE Mode
+ );
+
+/* Setup the source global color value in ARGB8 format. */
+gceSTATUS gco2D_SetSourceGlobalColorAdvanced(
+ IN gco2D Engine,
+ IN gctUINT32 Color32
+ );
+
+/* Setup the target global color value in ARGB8 format. */
+gceSTATUS gco2D_SetTargetGlobalColorAdvanced(
+ IN gco2D Engine,
+ IN gctUINT32 Color32
+ );
+
+/* Setup the source and target pixel multiply modes. */
+gceSTATUS
+gco2D_SetPixelMultiplyModeAdvanced(
+ IN gco2D Engine,
+ IN gce2D_PIXEL_COLOR_MULTIPLY_MODE SrcPremultiplySrcAlpha,
+ IN gce2D_PIXEL_COLOR_MULTIPLY_MODE DstPremultiplyDstAlpha,
+ IN gce2D_GLOBAL_COLOR_MULTIPLY_MODE SrcPremultiplyGlobalMode,
+ IN gce2D_PIXEL_COLOR_MULTIPLY_MODE DstDemultiplyDstAlpha
+ );
+
+/* Set the GPU clock cycles after which the idle engine will keep auto-flushing. */
+gceSTATUS
+gco2D_SetAutoFlushCycles(
+ IN gco2D Engine,
+ IN gctUINT32 Cycles
+ );
+
+#if VIVANTE_PROFILER
+/* Read the profile registers available in the 2D engine and sets them in the profile.
+ The function will also reset the pixelsRendered counter every time.
+*/
+gceSTATUS
+gco2D_ProfileEngine(
+ IN gco2D Engine,
+ OPTIONAL gcs2D_PROFILE_PTR Profile
+ );
+#endif
+
+/* Enable or disable 2D dithering. */
+gceSTATUS
+gco2D_EnableDither(
+ IN gco2D Engine,
+ IN gctBOOL Enable
+ );
+
+gceSTATUS
+gco2D_SetGenericSource(
+ IN gco2D Engine,
+ IN gctUINT32_PTR Addresses,
+ IN gctUINT32 AddressNum,
+ IN gctUINT32_PTR Strides,
+ IN gctUINT32 StrideNum,
+ IN gceTILING Tiling,
+ IN gceSURF_FORMAT Format,
+ IN gceSURF_ROTATION Rotation,
+ IN gctUINT32 SurfaceWidth,
+ IN gctUINT32 SurfaceHeight
+);
+
+gceSTATUS
+gco2D_SetGenericTarget(
+ IN gco2D Engine,
+ IN gctUINT32_PTR Addresses,
+ IN gctUINT32 AddressNum,
+ IN gctUINT32_PTR Strides,
+ IN gctUINT32 StrideNum,
+ IN gceTILING Tiling,
+ IN gceSURF_FORMAT Format,
+ IN gceSURF_ROTATION Rotation,
+ IN gctUINT32 SurfaceWidth,
+ IN gctUINT32 SurfaceHeight
+);
+
+gceSTATUS
+gco2D_SetCurrentSourceIndex(
+ IN gco2D Engine,
+ IN gctUINT32 SrcIndex
+ );
+
+gceSTATUS
+gco2D_MultiSourceBlit(
+ IN gco2D Engine,
+ IN gctUINT32 SourceMask,
+ IN gcsRECT_PTR DestRect,
+ IN gctUINT32 RectCount
+ );
+
+gceSTATUS
+gco2D_SetROP(
+ IN gco2D Engine,
+ IN gctUINT8 FgRop,
+ IN gctUINT8 BgRop
+ );
+
+gceSTATUS
+gco2D_SetGdiStretchMode(
+ IN gco2D Engine,
+ IN gctBOOL Enable
+ );
+
+gceSTATUS
+gco2D_SetSourceTileStatus(
+ IN gco2D Engine,
+ IN gce2D_TILE_STATUS_CONFIG TSControl,
+ IN gceSURF_FORMAT CompressedFormat,
+ IN gctUINT32 ClearValue,
+ IN gctUINT32 GpuAddress
+ );
+
+gceSTATUS
+gco2D_SetTargetTileStatus(
+ IN gco2D Engine,
+ IN gce2D_TILE_STATUS_CONFIG TileStatusConfig,
+ IN gceSURF_FORMAT CompressedFormat,
+ IN gctUINT32 ClearValue,
+ IN gctUINT32 GpuAddress
+ );
+
+gceSTATUS
+gco2D_QueryU32(
+ IN gco2D Engine,
+ IN gce2D_QUERY Item,
+ OUT gctUINT32_PTR Value
+ );
+
+gceSTATUS
+gco2D_SetStateU32(
+ IN gco2D Engine,
+ IN gce2D_STATE State,
+ IN gctUINT32 Value
+ );
+
+gceSTATUS
+gco2D_SetStateArrayI32(
+ IN gco2D Engine,
+ IN gce2D_STATE State,
+ IN gctINT32_PTR Array,
+ IN gctINT32 ArraySize
+ );
+
+gceSTATUS
+gco2D_SetStateArrayU32(
+ IN gco2D Engine,
+ IN gce2D_STATE State,
+ IN gctUINT32_PTR Array,
+ IN gctINT32 ArraySize
+ );
+
+gceSTATUS
+gco2D_SetTargetRect(
+ IN gco2D Engine,
+ IN gcsRECT_PTR Rect
+ );
+
+gceSTATUS
+gco2D_Set2DEngine(
+ IN gco2D Engine
+ );
+
+gceSTATUS
+gco2D_UnSet2DEngine(
+ IN gco2D Engine
+ );
+
+gceSTATUS
+gco2D_Get2DEngine(
+ OUT gco2D * Engine
+ );
+
+gceSTATUS
+gco2D_Commit(
+ IN gco2D Engine,
+ IN gctBOOL Stall
+ );
+
+gceSTATUS
+gco2D_NatureRotateTranslation(
+ IN gctBOOL IsSrcRot,
+ IN gce2D_NATURE_ROTATION NatureRotation,
+ IN gctINT32 SrcSurfaceWidth,
+ IN gctINT32 SrcSurfaceHeight,
+ IN gctINT32 DstSurfaceWidth,
+ IN gctINT32 DstSurfaceHeight,
+ IN OUT gcsRECT_PTR SrcRect,
+ IN OUT gcsRECT_PTR DstRect,
+ OUT gceSURF_ROTATION * SrcRotation,
+ OUT gceSURF_ROTATION * DstRotation
+ );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_raster_h_ */
+
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_rename.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_rename.h
new file mode 100644
index 000000000000..24c260f24cca
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_rename.h
@@ -0,0 +1,277 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_rename_h_
+#define __gc_hal_rename_h_
+
+
+#if defined(_HAL2D_APPENDIX)
+
+#define _HAL2D_RENAME_2(api, appendix) api ## appendix
+#define _HAL2D_RENAME_1(api, appendix) _HAL2D_RENAME_2(api, appendix)
+#define gcmHAL2D(api) _HAL2D_RENAME_1(api, _HAL2D_APPENDIX)
+
+
+#define gckOS_Construct gcmHAL2D(gckOS_Construct)
+#define gckOS_Destroy gcmHAL2D(gckOS_Destroy)
+#define gckOS_QueryVideoMemory gcmHAL2D(gckOS_QueryVideoMemory)
+#define gckOS_Allocate gcmHAL2D(gckOS_Allocate)
+#define gckOS_Free gcmHAL2D(gckOS_Free)
+#define gckOS_AllocateMemory gcmHAL2D(gckOS_AllocateMemory)
+#define gckOS_FreeMemory gcmHAL2D(gckOS_FreeMemory)
+#define gckOS_AllocatePagedMemory gcmHAL2D(gckOS_AllocatePagedMemory)
+#define gckOS_AllocatePagedMemoryEx gcmHAL2D(gckOS_AllocatePagedMemoryEx)
+#define gckOS_LockPages gcmHAL2D(gckOS_LockPages)
+#define gckOS_MapPages gcmHAL2D(gckOS_MapPages)
+#define gckOS_UnlockPages gcmHAL2D(gckOS_UnlockPages)
+#define gckOS_FreePagedMemory gcmHAL2D(gckOS_FreePagedMemory)
+#define gckOS_AllocateNonPagedMemory gcmHAL2D(gckOS_AllocateNonPagedMemory)
+#define gckOS_FreeNonPagedMemory gcmHAL2D(gckOS_FreeNonPagedMemory)
+#define gckOS_AllocateContiguous gcmHAL2D(gckOS_AllocateContiguous)
+#define gckOS_FreeContiguous gcmHAL2D(gckOS_FreeContiguous)
+#define gckOS_GetPageSize gcmHAL2D(gckOS_GetPageSize)
+#define gckOS_GetPhysicalAddress gcmHAL2D(gckOS_GetPhysicalAddress)
+#define gckOS_UserLogicalToPhysical gcmHAL2D(gckOS_UserLogicalToPhysical)
+#define gckOS_GetPhysicalAddressProcess gcmHAL2D(gckOS_GetPhysicalAddressProcess)
+#define gckOS_MapPhysical gcmHAL2D(gckOS_MapPhysical)
+#define gckOS_UnmapPhysical gcmHAL2D(gckOS_UnmapPhysical)
+#define gckOS_ReadRegister gcmHAL2D(gckOS_ReadRegister)
+#define gckOS_WriteRegister gcmHAL2D(gckOS_WriteRegister)
+#define gckOS_WriteMemory gcmHAL2D(gckOS_WriteMemory)
+#define gckOS_MapMemory gcmHAL2D(gckOS_MapMemory)
+#define gckOS_UnmapMemory gcmHAL2D(gckOS_UnmapMemory)
+#define gckOS_UnmapMemoryEx gcmHAL2D(gckOS_UnmapMemoryEx)
+#define gckOS_CreateMutex gcmHAL2D(gckOS_CreateMutex)
+#define gckOS_DeleteMutex gcmHAL2D(gckOS_DeleteMutex)
+#define gckOS_AcquireMutex gcmHAL2D(gckOS_AcquireMutex)
+#define gckOS_ReleaseMutex gcmHAL2D(gckOS_ReleaseMutex)
+#define gckOS_AtomicExchange gcmHAL2D(gckOS_AtomicExchange)
+#define gckOS_AtomicExchangePtr gcmHAL2D(gckOS_AtomicExchangePtr)
+#define gckOS_AtomConstruct gcmHAL2D(gckOS_AtomConstruct)
+#define gckOS_AtomDestroy gcmHAL2D(gckOS_AtomDestroy)
+#define gckOS_AtomGet gcmHAL2D(gckOS_AtomGet)
+#define gckOS_AtomIncrement gcmHAL2D(gckOS_AtomIncrement)
+#define gckOS_AtomDecrement gcmHAL2D(gckOS_AtomDecrement)
+#define gckOS_Delay gcmHAL2D(gckOS_Delay)
+#define gckOS_GetTime gcmHAL2D(gckOS_GetTime)
+#define gckOS_MemoryBarrier gcmHAL2D(gckOS_MemoryBarrier)
+#define gckOS_MapUserPointer gcmHAL2D(gckOS_MapUserPointer)
+#define gckOS_UnmapUserPointer gcmHAL2D(gckOS_UnmapUserPointer)
+#define gckOS_QueryNeedCopy gcmHAL2D(gckOS_QueryNeedCopy)
+#define gckOS_CopyFromUserData gcmHAL2D(gckOS_CopyFromUserData)
+#define gckOS_CopyToUserData gcmHAL2D(gckOS_CopyToUserData)
+#define gckOS_SuspendInterrupt gcmHAL2D(gckOS_SuspendInterrupt)
+#define gckOS_ResumeInterrupt gcmHAL2D(gckOS_ResumeInterrupt)
+#define gckOS_GetBaseAddress gcmHAL2D(gckOS_GetBaseAddress)
+#define gckOS_MemCopy gcmHAL2D(gckOS_MemCopy)
+#define gckOS_ZeroMemory gcmHAL2D(gckOS_ZeroMemory)
+#define gckOS_DeviceControl gcmHAL2D(gckOS_DeviceControl)
+#define gckOS_GetProcessID gcmHAL2D(gckOS_GetProcessID)
+#define gckOS_GetThreadID gcmHAL2D(gckOS_GetThreadID)
+#define gckOS_CreateSignal gcmHAL2D(gckOS_CreateSignal)
+#define gckOS_DestroySignal gcmHAL2D(gckOS_DestroySignal)
+#define gckOS_Signal gcmHAL2D(gckOS_Signal)
+#define gckOS_WaitSignal gcmHAL2D(gckOS_WaitSignal)
+#define gckOS_MapSignal gcmHAL2D(gckOS_MapSignal)
+#define gckOS_MapUserMemory gcmHAL2D(gckOS_MapUserMemory)
+#define gckOS_UnmapUserMemory gcmHAL2D(gckOS_UnmapUserMemory)
+#define gckOS_CreateUserSignal gcmHAL2D(gckOS_CreateUserSignal)
+#define gckOS_DestroyUserSignal gcmHAL2D(gckOS_DestroyUserSignal)
+#define gckOS_WaitUserSignal gcmHAL2D(gckOS_WaitUserSignal)
+#define gckOS_SignalUserSignal gcmHAL2D(gckOS_SignalUserSignal)
+#define gckOS_UserSignal gcmHAL2D(gckOS_UserSignal)
+#define gckOS_UserSignal gcmHAL2D(gckOS_UserSignal)
+#define gckOS_CacheClean gcmHAL2D(gckOS_CacheClean)
+#define gckOS_CacheFlush gcmHAL2D(gckOS_CacheFlush)
+#define gckOS_SetDebugLevel gcmHAL2D(gckOS_SetDebugLevel)
+#define gckOS_SetDebugZone gcmHAL2D(gckOS_SetDebugZone)
+#define gckOS_SetDebugLevelZone gcmHAL2D(gckOS_SetDebugLevelZone)
+#define gckOS_SetDebugZones gcmHAL2D(gckOS_SetDebugZones)
+#define gckOS_SetDebugFile gcmHAL2D(gckOS_SetDebugFile)
+#define gckOS_Broadcast gcmHAL2D(gckOS_Broadcast)
+#define gckOS_SetGPUPower gcmHAL2D(gckOS_SetGPUPower)
+#define gckOS_CreateSemaphore gcmHAL2D(gckOS_CreateSemaphore)
+#define gckOS_DestroySemaphore gcmHAL2D(gckOS_DestroySemaphore)
+#define gckOS_AcquireSemaphore gcmHAL2D(gckOS_AcquireSemaphore)
+#define gckOS_ReleaseSemaphore gcmHAL2D(gckOS_ReleaseSemaphore)
+#define gckHEAP_Construct gcmHAL2D(gckHEAP_Construct)
+#define gckHEAP_Destroy gcmHAL2D(gckHEAP_Destroy)
+#define gckHEAP_Allocate gcmHAL2D(gckHEAP_Allocate)
+#define gckHEAP_Free gcmHAL2D(gckHEAP_Free)
+#define gckHEAP_ProfileStart gcmHAL2D(gckHEAP_ProfileStart)
+#define gckHEAP_ProfileEnd gcmHAL2D(gckHEAP_ProfileEnd)
+#define gckHEAP_Test gcmHAL2D(gckHEAP_Test)
+#define gckVIDMEM_Construct gcmHAL2D(gckVIDMEM_Construct)
+#define gckVIDMEM_Destroy gcmHAL2D(gckVIDMEM_Destroy)
+#define gckVIDMEM_Allocate gcmHAL2D(gckVIDMEM_Allocate)
+#define gckVIDMEM_AllocateLinear gcmHAL2D(gckVIDMEM_AllocateLinear)
+#define gckVIDMEM_Free gcmHAL2D(gckVIDMEM_Free)
+#define gckVIDMEM_Lock gcmHAL2D(gckVIDMEM_Lock)
+#define gckVIDMEM_Unlock gcmHAL2D(gckVIDMEM_Unlock)
+#define gckVIDMEM_ConstructVirtual gcmHAL2D(gckVIDMEM_ConstructVirtual)
+#define gckVIDMEM_DestroyVirtual gcmHAL2D(gckVIDMEM_DestroyVirtual)
+#define gckKERNEL_Construct gcmHAL2D(gckKERNEL_Construct)
+#define gckKERNEL_Destroy gcmHAL2D(gckKERNEL_Destroy)
+#define gckKERNEL_Dispatch gcmHAL2D(gckKERNEL_Dispatch)
+#define gckKERNEL_QueryVideoMemory gcmHAL2D(gckKERNEL_QueryVideoMemory)
+#define gckKERNEL_GetVideoMemoryPool gcmHAL2D(gckKERNEL_GetVideoMemoryPool)
+#define gckKERNEL_MapVideoMemory gcmHAL2D(gckKERNEL_MapVideoMemory)
+#define gckKERNEL_UnmapVideoMemory gcmHAL2D(gckKERNEL_UnmapVideoMemory)
+#define gckKERNEL_MapMemory gcmHAL2D(gckKERNEL_MapMemory)
+#define gckKERNEL_UnmapMemory gcmHAL2D(gckKERNEL_UnmapMemory)
+#define gckKERNEL_Notify gcmHAL2D(gckKERNEL_Notify)
+#define gckKERNEL_QuerySettings gcmHAL2D(gckKERNEL_QuerySettings)
+#define gckKERNEL_Recovery gcmHAL2D(gckKERNEL_Recovery)
+#define gckKERNEL_OpenUserData gcmHAL2D(gckKERNEL_OpenUserData)
+#define gckKERNEL_CloseUserData gcmHAL2D(gckKERNEL_CloseUserData)
+#define gckHARDWARE_Construct gcmHAL2D(gckHARDWARE_Construct)
+#define gckHARDWARE_Destroy gcmHAL2D(gckHARDWARE_Destroy)
+#define gckHARDWARE_QuerySystemMemory gcmHAL2D(gckHARDWARE_QuerySystemMemory)
+#define gckHARDWARE_BuildVirtualAddress gcmHAL2D(gckHARDWARE_BuildVirtualAddress)
+#define gckHARDWARE_QueryCommandBuffer gcmHAL2D(gckHARDWARE_QueryCommandBuffer)
+#define gckHARDWARE_WaitLink gcmHAL2D(gckHARDWARE_WaitLink)
+#define gckHARDWARE_Execute gcmHAL2D(gckHARDWARE_Execute)
+#define gckHARDWARE_End gcmHAL2D(gckHARDWARE_End)
+#define gckHARDWARE_Nop gcmHAL2D(gckHARDWARE_Nop)
+#define gckHARDWARE_PipeSelect gcmHAL2D(gckHARDWARE_PipeSelect)
+#define gckHARDWARE_Link gcmHAL2D(gckHARDWARE_Link)
+#define gckHARDWARE_Event gcmHAL2D(gckHARDWARE_Event)
+#define gckHARDWARE_QueryMemory gcmHAL2D(gckHARDWARE_QueryMemory)
+#define gckHARDWARE_QueryChipIdentity gcmHAL2D(gckHARDWARE_QueryChipIdentity)
+#define gckHARDWARE_QueryChipSpecs gcmHAL2D(gckHARDWARE_QueryChipSpecs)
+#define gckHARDWARE_QueryShaderCaps gcmHAL2D(gckHARDWARE_QueryShaderCaps)
+#define gckHARDWARE_ConvertFormat gcmHAL2D(gckHARDWARE_ConvertFormat)
+#define gckHARDWARE_SplitMemory gcmHAL2D(gckHARDWARE_SplitMemory)
+#define gckHARDWARE_AlignToTile gcmHAL2D(gckHARDWARE_AlignToTile)
+#define gckHARDWARE_UpdateQueueTail gcmHAL2D(gckHARDWARE_UpdateQueueTail)
+#define gckHARDWARE_ConvertLogical gcmHAL2D(gckHARDWARE_ConvertLogical)
+#define gckHARDWARE_Interrupt gcmHAL2D(gckHARDWARE_Interrupt)
+#define gckHARDWARE_SetMMU gcmHAL2D(gckHARDWARE_SetMMU)
+#define gckHARDWARE_FlushMMU gcmHAL2D(gckHARDWARE_FlushMMU)
+#define gckHARDWARE_GetIdle gcmHAL2D(gckHARDWARE_GetIdle)
+#define gckHARDWARE_Flush gcmHAL2D(gckHARDWARE_Flush)
+#define gckHARDWARE_SetFastClear gcmHAL2D(gckHARDWARE_SetFastClear)
+#define gckHARDWARE_ReadInterrupt gcmHAL2D(gckHARDWARE_ReadInterrupt)
+#define gckHARDWARE_SetPowerManagementState gcmHAL2D(gckHARDWARE_SetPowerManagementState)
+#define gckHARDWARE_QueryPowerManagementState gcmHAL2D(gckHARDWARE_QueryPowerManagementState)
+#define gckHARDWARE_ProfileEngine2D gcmHAL2D(gckHARDWARE_ProfileEngine2D)
+#define gckHARDWARE_InitializeHardware gcmHAL2D(gckHARDWARE_InitializeHardware)
+#define gckHARDWARE_Reset gcmHAL2D(gckHARDWARE_Reset)
+#define gckINTERRUPT_Construct gcmHAL2D(gckINTERRUPT_Construct)
+#define gckINTERRUPT_Destroy gcmHAL2D(gckINTERRUPT_Destroy)
+#define gckINTERRUPT_SetHandler gcmHAL2D(gckINTERRUPT_SetHandler)
+#define gckINTERRUPT_Notify gcmHAL2D(gckINTERRUPT_Notify)
+#define gckEVENT_Construct gcmHAL2D(gckEVENT_Construct)
+#define gckEVENT_Destroy gcmHAL2D(gckEVENT_Destroy)
+#define gckEVENT_AddList gcmHAL2D(gckEVENT_AddList)
+#define gckEVENT_FreeNonPagedMemory gcmHAL2D(gckEVENT_FreeNonPagedMemory)
+#define gckEVENT_FreeContiguousMemory gcmHAL2D(gckEVENT_FreeContiguousMemory)
+#define gckEVENT_FreeVideoMemory gcmHAL2D(gckEVENT_FreeVideoMemory)
+#define gckEVENT_Signal gcmHAL2D(gckEVENT_Signal)
+#define gckEVENT_Unlock gcmHAL2D(gckEVENT_Unlock)
+#define gckEVENT_Submit gcmHAL2D(gckEVENT_Submit)
+#define gckEVENT_Commit gcmHAL2D(gckEVENT_Commit)
+#define gckEVENT_Notify gcmHAL2D(gckEVENT_Notify)
+#define gckEVENT_Interrupt gcmHAL2D(gckEVENT_Interrupt)
+#define gckCOMMAND_Construct gcmHAL2D(gckCOMMAND_Construct)
+#define gckCOMMAND_Destroy gcmHAL2D(gckCOMMAND_Destroy)
+#define gckCOMMAND_EnterCommit gcmHAL2D(gckCOMMAND_EnterCommit)
+#define gckCOMMAND_ExitCommit gcmHAL2D(gckCOMMAND_ExitCommit)
+#define gckCOMMAND_Start gcmHAL2D(gckCOMMAND_Start)
+#define gckCOMMAND_Stop gcmHAL2D(gckCOMMAND_Stop)
+#define gckCOMMAND_Commit gcmHAL2D(gckCOMMAND_Commit)
+#define gckCOMMAND_Reserve gcmHAL2D(gckCOMMAND_Reserve)
+#define gckCOMMAND_Execute gcmHAL2D(gckCOMMAND_Execute)
+#define gckCOMMAND_Stall gcmHAL2D(gckCOMMAND_Stall)
+#define gckCOMMAND_Attach gcmHAL2D(gckCOMMAND_Attach)
+#define gckCOMMAND_Detach gcmHAL2D(gckCOMMAND_Detach)
+#define gckMMU_Construct gcmHAL2D(gckMMU_Construct)
+#define gckMMU_Destroy gcmHAL2D(gckMMU_Destroy)
+#define gckMMU_AllocatePages gcmHAL2D(gckMMU_AllocatePages)
+#define gckMMU_FreePages gcmHAL2D(gckMMU_FreePages)
+#define gckMMU_Test gcmHAL2D(gckMMU_Test)
+#define gckHARDWARE_QueryProfileRegisters gcmHAL2D(gckHARDWARE_QueryProfileRegisters)
+
+
+#define FindMdlMap gcmHAL2D(FindMdlMap)
+#define OnProcessExit gcmHAL2D(OnProcessExit)
+
+#define gckGALDEVICE_Destroy gcmHAL2D(gckGALDEVICE_Destroy)
+#define gckOS_Print gcmHAL2D(gckOS_Print)
+#define gckGALDEVICE_FreeMemory gcmHAL2D(gckGALDEVICE_FreeMemory)
+#define gckGALDEVICE_AllocateMemory gcmHAL2D(gckGALDEVICE_AllocateMemory)
+#define gckOS_DebugBreak gcmHAL2D(gckOS_DebugBreak)
+#define gckGALDEVICE_Release_ISR gcmHAL2D(gckGALDEVICE_Release_ISR)
+#define gckOS_Verify gcmHAL2D(gckOS_Verify)
+#define gckCOMMAND_Release gcmHAL2D(gckCOMMAND_Release)
+#define gckGALDEVICE_Stop gcmHAL2D(gckGALDEVICE_Stop)
+#define gckGALDEVICE_Construct gcmHAL2D(gckGALDEVICE_Construct)
+#define gckOS_DebugFatal gcmHAL2D(gckOS_DebugFatal)
+#define gckOS_DebugTrace gcmHAL2D(gckOS_DebugTrace)
+#define gckHARDWARE_GetBaseAddress gcmHAL2D(gckHARDWARE_GetBaseAddress)
+#define gckGALDEVICE_Setup_ISR gcmHAL2D(gckGALDEVICE_Setup_ISR)
+#define gckKERNEL_AttachProcess gcmHAL2D(gckKERNEL_AttachProcess)
+#define gckKERNEL_AttachProcessEx gcmHAL2D(gckKERNEL_AttachProcessEx)
+#define gckGALDEVICE_Start_Thread gcmHAL2D(gckGALDEVICE_Start_Thread)
+#define gckHARDWARE_QueryIdle gcmHAL2D(gckHARDWARE_QueryIdle)
+#define gckGALDEVICE_Start gcmHAL2D(gckGALDEVICE_Start)
+#define gckOS_GetKernelLogical gcmHAL2D(gckOS_GetKernelLogical)
+#define gckOS_DebugTraceZone gcmHAL2D(gckOS_DebugTraceZone)
+#define gckGALDEVICE_Stop_Thread gcmHAL2D(gckGALDEVICE_Stop_Thread)
+#define gckHARDWARE_NeedBaseAddress gcmHAL2D(gckHARDWARE_NeedBaseAddress)
+
+#endif
+
+#endif /* __gc_hal_rename_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_resource.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_resource.h
new file mode 100644
index 000000000000..e8ff2a7b4254
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_resource.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_resource_h_
+#define __gc_hal_resource_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_resource_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_security_interface.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_security_interface.h
new file mode 100644
index 000000000000..db76826ba637
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_security_interface.h
@@ -0,0 +1,184 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef _GC_HAL_SECURITY_INTERFACE_H_
+#define _GC_HAL_SECURITY_INTERFACE_H_
+/*!
+ @brief Command codes between kernel module and TrustZone
+ @discussion
+ Critical services must be done in TrustZone to avoid sensitive content leak. Most of kernel module is kept in non-Secure os to minimize
+ code in TrustZone.
+ */
+typedef enum kernel_packet_command {
+ KERNEL_START_COMMAND,
+ KERNEL_SUBMIT,
+ KERNEL_MAP_MEMORY, /* */
+ KERNEL_UNMAP_MEMORY,
+ KERNEL_ALLOCATE_SECRUE_MEMORY, /*! Security memory management. */
+ KERNEL_FREE_SECURE_MEMORY,
+ KERNEL_EXECUTE, /* Execute a command buffer. */
+ KERNEL_DUMP_MMU_EXCEPTION,
+ KERNEL_HANDLE_MMU_EXCEPTION,
+ KERNEL_READ_MMU_EXCEPTION,
+} kernel_packet_command_t;
+
+struct kernel_start_command {
+ kernel_packet_command_t command; /*! The command (always needs to be the first entry in a structure). */
+ gctUINT8 gpu; /*! Which GPU. */
+ gctUINT32 address;
+ gctUINT32 bytes;
+};
+
+/*!
+ @brief gckCOMMAND Object requests TrustZone to submit command buffer.
+ @discussion
+ Code in trustzone will check content of command buffer after copying command buffer to TrustZone.
+ */
+struct kernel_submit {
+ kernel_packet_command_t command; /*! The command (always needs to be the first entry in a structure). */
+ gctUINT8 gpu; /*! Which GPU. */
+ gctUINT8 kernel_command; /*! Whether it is a kernel command. */
+ gctUINT32 command_buffer_handle; /*! Handle to command buffer. */
+ gctUINT32 offset; /* Offset in command buffer. */
+ gctUINT32 * command_buffer; /*! Content of command buffer need to be submit. */
+ gctUINT32 command_buffer_length; /*! Length of command buffer. */
+};
+
+
+/*!
+ @brief gckVIDMEM Object requests TrustZone to allocate security memory.
+ @discussion
+ Allocate a buffer from security GPU memory.
+ */
+struct kernel_allocate_security_memory {
+ kernel_packet_command_t command; /*! The command (always needs to be the first entry in a structure). */
+ gctUINT32 bytes; /*! Requested bytes. */
+ gctUINT32 memory_handle; /*! Handle of allocated memory. */
+};
+
+/*!
+ @brief gckVIDMEM Object requests TrustZone to allocate security memory.
+ @discussion
+ Free a video memory buffer from security GPU memory.
+ */
+struct kernel_free_security_memory {
+ kernel_packet_command_t command; /*! The command (always needs to be the first entry in a structure). */
+ gctUINT32 memory_handle; /*! Handle of allocated memory. */
+};
+
+struct kernel_execute {
+ kernel_packet_command_t command; /*! The command (always needs to be the first entry in a structure). */
+ gctUINT8 gpu; /*! Which GPU. */
+ gctUINT8 kernel_command; /*! Whether it is a kernel command. */
+ gctUINT32 * command_buffer; /*! Content of command buffer need to be submit. */
+ gctUINT32 command_buffer_length; /*! Length of command buffer. */
+};
+
+typedef struct kernel_map_scatter_gather {
+ gctUINT32 bytes;
+ gctUINT32 physical;
+ struct kernel_map_scatter_gather *next;
+}
+kernel_map_scatter_gather_t;
+
+struct kernel_map_memory {
+ kernel_packet_command_t command;
+ kernel_map_scatter_gather_t *scatter;
+ gctUINT32 *physicals;
+ gctPHYS_ADDR_T physical; /*! Contiguous physical address range. */
+ gctUINT32 pageCount;
+ gctUINT32 gpuAddress;
+};
+
+struct kernel_unmap_memory {
+ gctUINT32 gpuAddress;
+ gctUINT32 pageCount;
+};
+
+struct kernel_read_mmu_exception {
+ gctUINT32 mmuStatus;
+ gctUINT32 mmuException;
+};
+
+struct kernel_handle_mmu_exception {
+ gctUINT32 mmuStatus;
+ gctPHYS_ADDR_T physical;
+ gctUINT32 gpuAddress;
+};
+
+typedef struct _gcsTA_INTERFACE {
+ kernel_packet_command_t command;
+ union {
+ struct kernel_submit Submit;
+ struct kernel_start_command StartCommand;
+ struct kernel_allocate_security_memory AllocateSecurityMemory;
+ struct kernel_execute Execute;
+ struct kernel_map_memory MapMemory;
+ struct kernel_unmap_memory UnmapMemory;
+ struct kernel_read_mmu_exception ReadMMUException;
+ struct kernel_handle_mmu_exception HandleMMUException;
+ } u;
+ gceSTATUS result;
+} gcsTA_INTERFACE;
+
+enum {
+ gcvTA_COMMAND_INIT,
+ gcvTA_COMMAND_DISPATCH,
+
+ gcvTA_CALLBACK_ALLOC_SECURE_MEM,
+ gcvTA_CALLBACK_FREE_SECURE_MEM,
+};
+
+#endif
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_statistics.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_statistics.h
new file mode 100644
index 000000000000..2c48772ad1b1
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_statistics.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_statistics_h_
+#define __gc_hal_statistics_h_
+
+
+#define VIV_STAT_ENABLE_STATISTICS 0
+
+/* Toal number of frames for which the frame time is accounted. We have storage
+ to keep frame times for last this many frames.
+*/
+#define VIV_STAT_FRAME_BUFFER_SIZE 30
+
+
+/*
+ Total number of frames sampled for a mode. This means
+
+ # of frames for HZ Current : VIV_STAT_EARLY_Z_SAMPLE_FRAMES
+ # of frames for HZ Switched : VIV_STAT_EARLY_Z_SAMPLE_FRAMES
+ +
+ --------------------------------------------------------
+ : (2 * VIV_STAT_EARLY_Z_SAMPLE_FRAMES) frames needed
+
+ IMPORTANT: This total must be smaller than VIV_STAT_FRAME_BUFFER_SIZE
+*/
+#define VIV_STAT_EARLY_Z_SAMPLE_FRAMES 7
+#define VIV_STAT_EARLY_Z_LATENCY_FRAMES 2
+
+/* Multiplication factor for previous Hz off mode. Make it more than 1.0 to advertise HZ on.*/
+#define VIV_STAT_EARLY_Z_FACTOR (1.05f)
+
+/* Defines the statistical data keys monitored by the statistics module */
+typedef enum _gceSTATISTICS
+{
+ gcvFRAME_FPS = 1,
+}
+gceSTATISTICS;
+
+/* HAL statistics information. */
+typedef struct _gcsSTATISTICS_EARLYZ
+{
+ gctUINT switchBackCount;
+ gctUINT nextCheckPoint;
+ gctBOOL disabled;
+}
+gcsSTATISTICS_EARLYZ;
+
+
+/* HAL statistics information. */
+typedef struct _gcsSTATISTICS
+{
+ gctUINT64 frameTime[VIV_STAT_FRAME_BUFFER_SIZE];
+ gctUINT64 previousFrameTime;
+ gctUINT frame;
+ gcsSTATISTICS_EARLYZ earlyZ;
+}
+gcsSTATISTICS;
+
+
+/* Add a frame based data into current statistics. */
+void
+gcfSTATISTICS_AddData(
+ IN gceSTATISTICS Key,
+ IN gctUINT Value
+ );
+
+/* Marks the frame end and triggers statistical calculations and decisions.*/
+void
+gcfSTATISTICS_MarkFrameEnd (
+ void
+ );
+
+/* Sets whether the dynmaic HZ is disabled or not .*/
+void
+gcfSTATISTICS_DisableDynamicEarlyZ (
+ IN gctBOOL Disabled
+ );
+
+#endif /*__gc_hal_statistics_h_ */
+
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_types.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_types.h
new file mode 100644
index 000000000000..f2d3d2ae7ba9
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_types.h
@@ -0,0 +1,1034 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_types_h_
+#define __gc_hal_types_h_
+
+#include "gc_hal_version.h"
+#include "gc_hal_options.h"
+
+#if !defined(VIV_KMD)
+#if defined(__KERNEL__)
+#include "linux/version.h"
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ typedef unsigned long uintptr_t;
+# endif
+# include "linux/types.h"
+#elif defined(UNDER_CE)
+#include <crtdefs.h>
+#elif defined(_MSC_VER) && (_MSC_VER <= 1500)
+#include <crtdefs.h>
+#include "vadefs.h"
+#elif defined(__QNXNTO__)
+#define _QNX_SOURCE
+#include <stdint.h>
+#include <stddef.h>
+#else
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#endif
+#endif
+
+#ifdef _WIN32
+#pragma warning(disable:4127) /* Conditional expression is constant (do { }
+ ** while(0)). */
+#pragma warning(disable:4100) /* Unreferenced formal parameter. */
+#pragma warning(disable:4204) /* Non-constant aggregate initializer (C99). */
+#pragma warning(disable:4131) /* Uses old-style declarator (for Bison and
+ ** Flex generated files). */
+#pragma warning(disable:4206) /* Translation unit is empty. */
+#pragma warning(disable:4214) /* Nonstandard extension used :
+ ** bit field types other than int. */
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+** Platform macros.
+*/
+
+#if defined(__GNUC__)
+# define gcdHAS_ELLIPSIS 1 /* GCC always has it. */
+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define gcdHAS_ELLIPSIS 1 /* C99 has it. */
+#elif defined(_MSC_VER) && (_MSC_VER >= 1500)
+# define gcdHAS_ELLIPSIS 1 /* MSVC 2007+ has it. */
+#elif defined(UNDER_CE)
+#if UNDER_CE >= 600
+# define gcdHAS_ELLIPSIS 1
+# else
+# define gcdHAS_ELLIPSIS 0
+# endif
+#else
+# error "gcdHAS_ELLIPSIS: Platform could not be determined"
+#endif
+
+/******************************************************************************\
+************************************ Keyword ***********************************
+\******************************************************************************/
+
+#if defined(ANDROID) && defined(__BIONIC_FORTIFY)
+#if defined(__clang__)
+# define gcmINLINE __inline__ __attribute__ ((always_inline)) __attribute__ ((gnu_inline))
+# else
+# define gcmINLINE __inline__ __attribute__ ((always_inline)) __attribute__ ((gnu_inline)) __attribute__ ((artificial))
+# endif
+#elif ((defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || defined(__APPLE__))
+# define gcmINLINE inline /* C99 keyword. */
+#elif defined(__GNUC__)
+# define gcmINLINE __inline__ /* GNU keyword. */
+#elif defined(_MSC_VER) || defined(UNDER_CE)
+# define gcmINLINE __inline /* Internal keyword. */
+#else
+# error "gcmINLINE: Platform could not be determined"
+#endif
+
+/* Possible debug flags. */
+#define gcdDEBUG_NONE 0
+#define gcdDEBUG_ALL (1 << 0)
+#define gcdDEBUG_FATAL (1 << 1)
+#define gcdDEBUG_TRACE (1 << 2)
+#define gcdDEBUG_BREAK (1 << 3)
+#define gcdDEBUG_ASSERT (1 << 4)
+#define gcdDEBUG_CODE (1 << 5)
+#define gcdDEBUG_STACK (1 << 6)
+
+#define gcmIS_DEBUG(flag) ( gcdDEBUG & (flag | gcdDEBUG_ALL) )
+
+#ifndef gcdDEBUG
+#if (defined(DBG) && DBG) || defined(DEBUG) || defined(_DEBUG)
+# define gcdDEBUG gcdDEBUG_ALL
+# else
+# define gcdDEBUG gcdDEBUG_NONE
+# endif
+#endif
+
+#ifdef _USRDLL
+#ifdef _MSC_VER
+#ifdef HAL_EXPORTS
+# define HALAPI __declspec(dllexport)
+# else
+# define HALAPI __declspec(dllimport)
+# endif
+# define HALDECL __cdecl
+# else
+#ifdef HAL_EXPORTS
+# define HALAPI
+# else
+# define HALAPI extern
+# endif
+# endif
+#else
+# define HALAPI
+# define HALDECL
+#endif
+
+/******************************************************************************\
+********************************** Common Types ********************************
+\******************************************************************************/
+
+#define gcvFALSE 0
+#define gcvTRUE 1
+
+#define gcvINFINITE ((gctUINT32) ~0U)
+
+#define gcvINVALID_HANDLE ((gctHANDLE) ~0U)
+
+typedef int gctBOOL;
+typedef gctBOOL * gctBOOL_PTR;
+
+typedef int gctINT;
+typedef signed char gctINT8;
+typedef signed short gctINT16;
+typedef signed int gctINT32;
+typedef signed long long gctINT64;
+
+typedef gctINT * gctINT_PTR;
+typedef gctINT8 * gctINT8_PTR;
+typedef gctINT16 * gctINT16_PTR;
+typedef gctINT32 * gctINT32_PTR;
+typedef gctINT64 * gctINT64_PTR;
+
+typedef unsigned int gctUINT;
+typedef unsigned char gctUINT8;
+typedef unsigned short gctUINT16;
+typedef unsigned int gctUINT32;
+typedef unsigned long long gctUINT64;
+typedef uintptr_t gctUINTPTR_T;
+typedef ptrdiff_t gctPTRDIFF_T;
+
+typedef gctUINT * gctUINT_PTR;
+typedef gctUINT8 * gctUINT8_PTR;
+typedef gctUINT16 * gctUINT16_PTR;
+typedef gctUINT32 * gctUINT32_PTR;
+typedef gctUINT64 * gctUINT64_PTR;
+
+typedef size_t gctSIZE_T;
+typedef gctSIZE_T * gctSIZE_T_PTR;
+typedef gctUINT32 gctTRACE;
+
+#ifdef __cplusplus
+# define gcvNULL 0
+#else
+# define gcvNULL ((void *) 0)
+#endif
+
+#define gcvMAXINT8 0x7f
+#define gcvMININT8 0x80
+#define gcvMAXINT16 0x7fff
+#define gcvMININT16 0x8000
+#define gcvMAXINT32 0x7fffffff
+#define gcvMININT32 0x80000000
+#define gcvMAXINT64 0x7fffffffffffffff
+#define gcvMININT64 0x8000000000000000
+#define gcvMAXUINT8 0xff
+#define gcvMINUINT8 0x0
+#define gcvMAXUINT16 0xffff
+#define gcvMINUINT16 0x0
+#define gcvMAXUINT32 0xffffffff
+#define gcvMINUINT32 0x0
+#define gcvMAXUINT64 0xffffffffffffffff
+#define gcvMINUINT64 0x0
+#define gcvMAXUINTPTR_T (~(gctUINTPTR_T)0)
+
+typedef float gctFLOAT;
+typedef signed int gctFIXED_POINT;
+typedef float * gctFLOAT_PTR;
+
+typedef void * gctPHYS_ADDR;
+typedef void * gctHANDLE;
+typedef void * gctFILE;
+typedef void * gctSIGNAL;
+typedef void * gctWINDOW;
+typedef void * gctIMAGE;
+typedef void * gctSHBUF;
+
+typedef void * gctSEMAPHORE;
+
+typedef void * gctPOINTER;
+typedef const void * gctCONST_POINTER;
+
+typedef char gctCHAR;
+typedef char * gctSTRING;
+typedef const char * gctCONST_STRING;
+
+typedef gctUINT64 gctPHYS_ADDR_T;
+
+typedef struct _gcsCOUNT_STRING
+{
+ gctSIZE_T Length;
+ gctCONST_STRING String;
+}
+gcsCOUNT_STRING;
+
+typedef union _gcuFLOAT_UINT32
+{
+ gctFLOAT f;
+ gctUINT32 u;
+}
+gcuFLOAT_UINT32;
+
+/* Fixed point constants. */
+#define gcvZERO_X ((gctFIXED_POINT) 0x00000000)
+#define gcvHALF_X ((gctFIXED_POINT) 0x00008000)
+#define gcvONE_X ((gctFIXED_POINT) 0x00010000)
+#define gcvNEGONE_X ((gctFIXED_POINT) 0xFFFF0000)
+#define gcvTWO_X ((gctFIXED_POINT) 0x00020000)
+
+
+
+#define gcmFIXEDCLAMP_NEG1_TO_1(_x) \
+ (((_x) < gcvNEGONE_X) \
+ ? gcvNEGONE_X \
+ : (((_x) > gcvONE_X) \
+ ? gcvONE_X \
+ : (_x)))
+
+#define gcmFLOATCLAMP_NEG1_TO_1(_f) \
+ (((_f) < -1.0f) \
+ ? -1.0f \
+ : (((_f) > 1.0f) \
+ ? 1.0f \
+ : (_f)))
+
+
+#define gcmFIXEDCLAMP_0_TO_1(_x) \
+ (((_x) < 0) \
+ ? 0 \
+ : (((_x) > gcvONE_X) \
+ ? gcvONE_X \
+ : (_x)))
+
+#define gcmFLOATCLAMP_0_TO_1(_f) \
+ (((_f) < 0.0f) \
+ ? 0.0f \
+ : (((_f) > 1.0f) \
+ ? 1.0f \
+ : (_f)))
+
+
+/******************************************************************************\
+******************************* Multicast Values *******************************
+\******************************************************************************/
+
+/* Value types. */
+typedef enum _gceVALUE_TYPE
+{
+ gcvVALUE_UINT = 0x0,
+ gcvVALUE_FIXED,
+ gcvVALUE_FLOAT,
+ gcvVALUE_INT,
+
+ /*
+ ** The value need be unsigned denormalized. clamp (0.0-1.0) should be done first.
+ */
+ gcvVALUE_FLAG_UNSIGNED_DENORM = 0x00010000,
+
+ /*
+ ** The value need be signed denormalized. clamp (-1.0-1.0) should be done first.
+ */
+ gcvVALUE_FLAG_SIGNED_DENORM = 0x00020000,
+
+ /*
+ ** The value need to gammar
+ */
+ gcvVALUE_FLAG_GAMMAR = 0x00040000,
+
+ /*
+ ** The value need to convert from float to float16
+ */
+ gcvVALUE_FLAG_FLOAT_TO_FLOAT16 = 0x0080000,
+
+ /*
+ ** Mask for flag field.
+ */
+ gcvVALUE_FLAG_MASK = 0xFFFF0000,
+}
+gceVALUE_TYPE;
+
+/* Value unions. */
+typedef union _gcuVALUE
+{
+ gctUINT uintValue;
+ gctFIXED_POINT fixedValue;
+ gctFLOAT floatValue;
+ gctINT intValue;
+}
+gcuVALUE;
+
+
+
+
+/* Stringizing macro. */
+#define gcmSTRING(Value) #Value
+
+/******************************************************************************\
+******************************* Fixed Point Math *******************************
+\******************************************************************************/
+
+#define gcmXMultiply(x1, x2) gcoMATH_MultiplyFixed(x1, x2)
+#define gcmXDivide(x1, x2) gcoMATH_DivideFixed(x1, x2)
+#define gcmXMultiplyDivide(x1, x2, x3) gcoMATH_MultiplyDivideFixed(x1, x2, x3)
+
+/* 2D Engine profile. */
+typedef struct _gcs2D_PROFILE
+{
+ /* Cycle count.
+ 32bit counter incremented every 2D clock cycle.
+ Wraps back to 0 when the counter overflows.
+ */
+ gctUINT32 cycleCount;
+
+ /* Pixels rendered by the 2D engine.
+ Resets to 0 every time it is read. */
+ gctUINT32 pixelsRendered;
+}
+gcs2D_PROFILE;
+
+/* Macro to combine four characters into a Charcater Code. */
+#define gcmCC(c1, c2, c3, c4) \
+( \
+ (char) (c1) \
+ | \
+ ((char) (c2) << 8) \
+ | \
+ ((char) (c3) << 16) \
+ | \
+ ((char) (c4) << 24) \
+)
+
+#define gcmPRINTABLE(c) ((((c) >= ' ') && ((c) <= '}')) ? ((c) != '%' ? (c) : ' ') : ' ')
+
+#define gcmCC_PRINT(cc) \
+ gcmPRINTABLE((char) ( (cc) & 0xFF)), \
+ gcmPRINTABLE((char) (((cc) >> 8) & 0xFF)), \
+ gcmPRINTABLE((char) (((cc) >> 16) & 0xFF)), \
+ gcmPRINTABLE((char) (((cc) >> 24) & 0xFF))
+
+/******************************************************************************\
+****************************** Function Parameters *****************************
+\******************************************************************************/
+
+#define IN
+#define OUT
+#define INOUT
+#define OPTIONAL
+
+/******************************************************************************\
+********************************* Status Codes *********************************
+\******************************************************************************/
+
+typedef enum _gceSTATUS
+{
+ gcvSTATUS_OK = 0,
+ gcvSTATUS_FALSE = 0,
+ gcvSTATUS_TRUE = 1,
+ gcvSTATUS_NO_MORE_DATA = 2,
+ gcvSTATUS_CACHED = 3,
+ gcvSTATUS_MIPMAP_TOO_LARGE = 4,
+ gcvSTATUS_NAME_NOT_FOUND = 5,
+ gcvSTATUS_NOT_OUR_INTERRUPT = 6,
+ gcvSTATUS_MISMATCH = 7,
+ gcvSTATUS_MIPMAP_TOO_SMALL = 8,
+ gcvSTATUS_LARGER = 9,
+ gcvSTATUS_SMALLER = 10,
+ gcvSTATUS_CHIP_NOT_READY = 11,
+ gcvSTATUS_NEED_CONVERSION = 12,
+ gcvSTATUS_SKIP = 13,
+ gcvSTATUS_DATA_TOO_LARGE = 14,
+ gcvSTATUS_INVALID_CONFIG = 15,
+ gcvSTATUS_CHANGED = 16,
+ gcvSTATUS_NOT_SUPPORT_DITHER = 17,
+ gcvSTATUS_EXECUTED = 18,
+ gcvSTATUS_TERMINATE = 19,
+
+ gcvSTATUS_INVALID_ARGUMENT = -1,
+ gcvSTATUS_INVALID_OBJECT = -2,
+ gcvSTATUS_OUT_OF_MEMORY = -3,
+ gcvSTATUS_MEMORY_LOCKED = -4,
+ gcvSTATUS_MEMORY_UNLOCKED = -5,
+ gcvSTATUS_HEAP_CORRUPTED = -6,
+ gcvSTATUS_GENERIC_IO = -7,
+ gcvSTATUS_INVALID_ADDRESS = -8,
+ gcvSTATUS_CONTEXT_LOSSED = -9,
+ gcvSTATUS_TOO_COMPLEX = -10,
+ gcvSTATUS_BUFFER_TOO_SMALL = -11,
+ gcvSTATUS_INTERFACE_ERROR = -12,
+ gcvSTATUS_NOT_SUPPORTED = -13,
+ gcvSTATUS_MORE_DATA = -14,
+ gcvSTATUS_TIMEOUT = -15,
+ gcvSTATUS_OUT_OF_RESOURCES = -16,
+ gcvSTATUS_INVALID_DATA = -17,
+ gcvSTATUS_INVALID_MIPMAP = -18,
+ gcvSTATUS_NOT_FOUND = -19,
+ gcvSTATUS_NOT_ALIGNED = -20,
+ gcvSTATUS_INVALID_REQUEST = -21,
+ gcvSTATUS_GPU_NOT_RESPONDING = -22,
+ gcvSTATUS_TIMER_OVERFLOW = -23,
+ gcvSTATUS_VERSION_MISMATCH = -24,
+ gcvSTATUS_LOCKED = -25,
+ gcvSTATUS_INTERRUPTED = -26,
+ gcvSTATUS_DEVICE = -27,
+ gcvSTATUS_NOT_MULTI_PIPE_ALIGNED = -28,
+ gcvSTATUS_OUT_OF_SAMPLER = -29,
+
+ /* Linker errors. */
+ gcvSTATUS_GLOBAL_TYPE_MISMATCH = -1000,
+ gcvSTATUS_TOO_MANY_ATTRIBUTES = -1001,
+ gcvSTATUS_TOO_MANY_UNIFORMS = -1002,
+ gcvSTATUS_TOO_MANY_VARYINGS = -1003,
+ gcvSTATUS_UNDECLARED_VARYING = -1004,
+ gcvSTATUS_VARYING_TYPE_MISMATCH = -1005,
+ gcvSTATUS_MISSING_MAIN = -1006,
+ gcvSTATUS_NAME_MISMATCH = -1007,
+ gcvSTATUS_INVALID_INDEX = -1008,
+ gcvSTATUS_UNIFORM_MISMATCH = -1009,
+ gcvSTATUS_UNSAT_LIB_SYMBOL = -1010,
+ gcvSTATUS_TOO_MANY_SHADERS = -1011,
+ gcvSTATUS_LINK_INVALID_SHADERS = -1012,
+ gcvSTATUS_CS_NO_WORKGROUP_SIZE = -1013,
+ gcvSTATUS_LINK_LIB_ERROR = -1014,
+
+ gcvSTATUS_SHADER_VERSION_MISMATCH = -1015,
+ gcvSTATUS_TOO_MANY_INSTRUCTION = -1016,
+ gcvSTATUS_SSBO_MISMATCH = -1017,
+ gcvSTATUS_TOO_MANY_OUTPUT = -1018,
+ gcvSTATUS_TOO_MANY_INPUT = -1019,
+ gcvSTATUS_NOT_SUPPORT_CL = -1020,
+ gcvSTATUS_NOT_SUPPORT_INTEGER = -1021,
+ gcvSTATUS_UNIFORM_TYPE_MISMATCH = -1022,
+
+ gcvSTATUS_MISSING_PRIMITIVE_TYPE = -1023,
+ gcvSTATUS_MISSING_OUTPUT_VERTEX_COUNT = -1024,
+ gcvSTATUS_NON_INVOCATION_ID_AS_INDEX = -1025,
+ gcvSTATUS_INPUT_ARRAY_SIZE_MISMATCH = -1026,
+ gcvSTATUS_OUTPUT_ARRAY_SIZE_MISMATCH = -1027,
+ gcvSTATUS_LOCATION_ALIASED = -1028,
+
+ /* Compiler errors. */
+ gcvSTATUS_COMPILER_FE_PREPROCESSOR_ERROR = -2000,
+ gcvSTATUS_COMPILER_FE_PARSER_ERROR = -2001,
+
+ /* Recompilation Errors */
+ gcvSTATUS_RECOMPILER_CONVERT_UNIMPLEMENTED = -3000,
+}
+gceSTATUS;
+
+/******************************************************************************\
+********************************* Status Macros ********************************
+\******************************************************************************/
+
+#define gcmIS_ERROR(status) (status < 0)
+#define gcmNO_ERROR(status) (status >= 0)
+#define gcmIS_SUCCESS(status) (status == gcvSTATUS_OK)
+
+/******************************************************************************\
+********************************* Field Macros *********************************
+\******************************************************************************/
+
+#define __gcmSTART(reg_field) \
+ (0 ? reg_field)
+
+#define __gcmEND(reg_field) \
+ (1 ? reg_field)
+
+#define __gcmGETSIZE(reg_field) \
+ (__gcmEND(reg_field) - __gcmSTART(reg_field) + 1)
+
+#define __gcmALIGN(data, reg_field) \
+ (((gctUINT32) (data)) << __gcmSTART(reg_field))
+
+#define __gcmMASK(reg_field) \
+ ((gctUINT32) ((__gcmGETSIZE(reg_field) == 32) \
+ ? ~0U \
+ : (~(~0U << __gcmGETSIZE(reg_field)))))
+
+/*******************************************************************************
+**
+** gcmFIELDMASK
+**
+** Get aligned field mask.
+**
+** ARGUMENTS:
+**
+** reg Name of register.
+** field Name of field within register.
+*/
+#define gcmFIELDMASK(reg, field) \
+( \
+ __gcmALIGN(__gcmMASK(reg##_##field), reg##_##field) \
+)
+
+/*******************************************************************************
+**
+** gcmGETFIELD
+**
+** Extract the value of a field from specified data.
+**
+** ARGUMENTS:
+**
+** data Data value.
+** reg Name of register.
+** field Name of field within register.
+*/
+#define gcmGETFIELD(data, reg, field) \
+( \
+ ((((gctUINT32) (data)) >> __gcmSTART(reg##_##field)) \
+ & __gcmMASK(reg##_##field)) \
+)
+
+/*******************************************************************************
+**
+** gcmSETFIELD
+**
+** Set the value of a field within specified data.
+**
+** ARGUMENTS:
+**
+** data Data value.
+** reg Name of register.
+** field Name of field within register.
+** value Value for field.
+*/
+#define gcmSETFIELD(data, reg, field, value) \
+( \
+ (((gctUINT32) (data)) \
+ & ~__gcmALIGN(__gcmMASK(reg##_##field), reg##_##field)) \
+ | __gcmALIGN((gctUINT32) (value) \
+ & __gcmMASK(reg##_##field), reg##_##field) \
+)
+
+/*******************************************************************************
+**
+** gcmSETFIELDVALUE
+**
+** Set the value of a field within specified data with a
+** predefined value.
+**
+** ARGUMENTS:
+**
+** data Data value.
+** reg Name of register.
+** field Name of field within register.
+** value Name of the value within the field.
+*/
+#define gcmSETFIELDVALUE(data, reg, field, value) \
+( \
+ (((gctUINT32) (data)) \
+ & ~__gcmALIGN(__gcmMASK(reg##_##field), reg##_##field)) \
+ | __gcmALIGN(reg##_##field##_##value \
+ & __gcmMASK(reg##_##field), reg##_##field) \
+)
+
+/*******************************************************************************
+**
+** gcmGETMASKEDFIELDMASK
+**
+** Determine field mask of a masked field.
+**
+** ARGUMENTS:
+**
+** reg Name of register.
+** field Name of field within register.
+*/
+#define gcmGETMASKEDFIELDMASK(reg, field) \
+( \
+ gcmSETFIELD(0, reg, field, ~0U) | \
+ gcmSETFIELD(0, reg, MASK_ ## field, ~0U) \
+)
+
+/*******************************************************************************
+**
+** gcmSETMASKEDFIELD
+**
+** Set the value of a masked field with specified data.
+**
+** ARGUMENTS:
+**
+** reg Name of register.
+** field Name of field within register.
+** value Value for field.
+*/
+#define gcmSETMASKEDFIELD(reg, field, value) \
+( \
+ gcmSETFIELD (~0U, reg, field, value) & \
+ gcmSETFIELDVALUE(~0U, reg, MASK_ ## field, ENABLED) \
+)
+
+/*******************************************************************************
+**
+** gcmSETMASKEDFIELDVALUE
+**
+** Set the value of a masked field with specified data.
+**
+** ARGUMENTS:
+**
+** reg Name of register.
+** field Name of field within register.
+** value Value for field.
+*/
+#define gcmSETMASKEDFIELDVALUE(reg, field, value) \
+( \
+ gcmSETFIELDVALUE(~0U, reg, field, value) & \
+ gcmSETFIELDVALUE(~0U, reg, MASK_ ## field, ENABLED) \
+)
+
+/*******************************************************************************
+**
+** gcmVERIFYFIELDVALUE
+**
+** Verify if the value of a field within specified data equals a
+** predefined value.
+**
+** ARGUMENTS:
+**
+** data Data value.
+** reg Name of register.
+** field Name of field within register.
+** value Name of the value within the field.
+*/
+#define gcmVERIFYFIELDVALUE(data, reg, field, value) \
+( \
+ (((gctUINT32) (data)) >> __gcmSTART(reg##_##field) & \
+ __gcmMASK(reg##_##field)) \
+ == \
+ (reg##_##field##_##value & __gcmMASK(reg##_##field)) \
+)
+
+/*******************************************************************************
+** Bit field macros.
+*/
+
+#define __gcmSTARTBIT(Field) \
+ ( 1 ? Field )
+
+#define __gcmBITSIZE(Field) \
+ ( 0 ? Field )
+
+#define __gcmBITMASK(Field) \
+( \
+ (1 << __gcmBITSIZE(Field)) - 1 \
+)
+
+#define gcmGETBITS(Value, Type, Field) \
+( \
+ ( ((Type) (Value)) >> __gcmSTARTBIT(Field) ) \
+ & \
+ __gcmBITMASK(Field) \
+)
+
+#define gcmSETBITS(Value, Type, Field, NewValue) \
+( \
+ ( ((Type) (Value)) \
+ & ~(__gcmBITMASK(Field) << __gcmSTARTBIT(Field)) \
+ ) \
+ | \
+ ( ( ((Type) (NewValue)) \
+ & __gcmBITMASK(Field) \
+ ) << __gcmSTARTBIT(Field) \
+ ) \
+)
+
+/*******************************************************************************
+**
+** gcmISINREGRANGE
+**
+** Verify whether the specified address is in the register range.
+**
+** ARGUMENTS:
+**
+** Address Address to be verified.
+** Name Name of a register.
+*/
+
+#define gcmISINREGRANGE(Address, Name) \
+( \
+ ((Address & (~0U << Name ## _LSB)) == (Name ## _Address >> 2)) \
+)
+
+/******************************************************************************\
+******************************** Ceiling Macro ********************************
+\******************************************************************************/
+#define gcmCEIL(x) (((x) - (gctUINT32)(x)) == 0 ? (gctUINT32)(x) : (gctUINT32)(x) + 1)
+
+/******************************************************************************\
+******************************** Min/Max Macros ********************************
+\******************************************************************************/
+
+#define gcmMIN(x, y) (((x) <= (y)) ? (x) : (y))
+#define gcmMAX(x, y) (((x) >= (y)) ? (x) : (y))
+#define gcmCLAMP(x, min, max) (((x) < (min)) ? (min) : \
+ ((x) > (max)) ? (max) : (x))
+#define gcmABS(x) (((x) < 0) ? -(x) : (x))
+#define gcmNEG(x) (((x) < 0) ? (x) : -(x))
+
+/******************************************************************************\
+******************************** Bit Macro ********************************
+\******************************************************************************/
+#define gcmBITSET(x, y) ((x) & (y))
+/*******************************************************************************
+**
+** gcmPTR2INT
+**
+** Convert a pointer to an integer value.
+**
+** ARGUMENTS:
+**
+** p Pointer value.
+*/
+#define gcmPTR2INT(p) \
+( \
+ (gctUINTPTR_T) (p) \
+)
+
+#define gcmPTR2INT32(p) \
+( \
+ (gctUINT32)(gctUINTPTR_T) (p) \
+)
+
+/*******************************************************************************
+**
+** gcmINT2PTR
+**
+** Convert an integer value into a pointer.
+**
+** ARGUMENTS:
+**
+** v Integer value.
+*/
+
+#define gcmINT2PTR(i) \
+( \
+ (gctPOINTER) (gctUINTPTR_T)(i) \
+)
+
+/*******************************************************************************
+**
+** gcmOFFSETOF
+**
+** Compute the byte offset of a field inside a structure.
+**
+** ARGUMENTS:
+**
+** s Structure name.
+** field Field name.
+*/
+#define gcmOFFSETOF(s, field) \
+( \
+ gcmPTR2INT32(& (((struct s *) 0)->field)) \
+)
+
+/*******************************************************************************
+**
+** gcmCONTAINEROF
+**
+** Get containing structure of a member.
+**
+** ARGUMENTS:
+**
+** Pointer Pointer of member.
+** Type Structure name.
+** Name Field name.
+*/
+#define gcmCONTAINEROF(Pointer, Type, Member) \
+(\
+ (struct Type *)((gctUINTPTR_T)Pointer - gcmOFFSETOF(Type, Member)) \
+)
+
+/*******************************************************************************
+**
+** gcmBSWAP32
+**
+** Return a value with all bytes in the 32 bit argument swapped.
+*/
+#if defined(__GNUC__) && !defined(__KERNEL__)
+# define gcmBSWAP32(x) __builtin_bswap32(x)
+#else
+# define gcmBSWAP32(x) ((gctUINT32)( \
+ (((gctUINT32)(x) & (gctUINT32)0x000000FFUL) << 24) | \
+ (((gctUINT32)(x) & (gctUINT32)0x0000FF00UL) << 8) | \
+ (((gctUINT32)(x) & (gctUINT32)0x00FF0000UL) >> 8) | \
+ (((gctUINT32)(x) & (gctUINT32)0xFF000000UL) >> 24)))
+#endif
+
+/*******************************************************************************
+***** Database ****************************************************************/
+
+typedef struct _gcsDATABASE_COUNTERS
+{
+ /* Number of currently allocated bytes. */
+ gctUINT64 bytes;
+
+ /* Maximum number of bytes allocated (memory footprint). */
+ gctUINT64 maxBytes;
+
+ /* Total number of bytes allocated. */
+ gctUINT64 totalBytes;
+
+ /* The numbers of times video memory was allocated. */
+ gctUINT32 allocCount;
+
+ /* The numbers of times video memory was freed. */
+ gctUINT32 freeCount;
+}
+gcsDATABASE_COUNTERS;
+
+typedef struct _gcuDATABASE_INFO
+{
+ /* Counters. */
+ gcsDATABASE_COUNTERS counters;
+
+ /* Time value. */
+ gctUINT64 time;
+}
+gcuDATABASE_INFO;
+
+/*******************************************************************************
+***** Frame database **********************************************************/
+
+/* gcsHAL_FRAME_INFO */
+typedef struct _gcsHAL_FRAME_INFO
+{
+ /* Current timer tick. */
+ OUT gctUINT64 ticks;
+
+ /* Bandwidth counters. */
+ OUT gctUINT readBytes8[8];
+ OUT gctUINT writeBytes8[8];
+
+ /* Counters. */
+ OUT gctUINT cycles[8];
+ OUT gctUINT idleCycles[8];
+ OUT gctUINT mcCycles[8];
+ OUT gctUINT readRequests[8];
+ OUT gctUINT writeRequests[8];
+
+ /* 3D counters. */
+ OUT gctUINT vertexCount;
+ OUT gctUINT primitiveCount;
+ OUT gctUINT rejectedPrimitives;
+ OUT gctUINT culledPrimitives;
+ OUT gctUINT clippedPrimitives;
+ OUT gctUINT outPrimitives;
+ OUT gctUINT inPrimitives;
+ OUT gctUINT culledQuadCount;
+ OUT gctUINT totalQuadCount;
+ OUT gctUINT quadCount;
+ OUT gctUINT totalPixelCount;
+
+ /* PE counters. */
+ OUT gctUINT colorKilled[8];
+ OUT gctUINT colorDrawn[8];
+ OUT gctUINT depthKilled[8];
+ OUT gctUINT depthDrawn[8];
+
+ /* Shader counters. */
+ OUT gctUINT shaderCycles;
+ OUT gctUINT vsInstructionCount;
+ OUT gctUINT vsTextureCount;
+ OUT gctUINT psInstructionCount;
+ OUT gctUINT psTextureCount;
+
+ /* Texture counters. */
+ OUT gctUINT bilinearRequests;
+ OUT gctUINT trilinearRequests;
+ OUT gctUINT txBytes8;
+ OUT gctUINT txHitCount;
+ OUT gctUINT txMissCount;
+}
+gcsHAL_FRAME_INFO;
+
+typedef struct _gckLINKDATA * gckLINKDATA;
+struct _gckLINKDATA
+{
+ gctUINT32 start;
+ gctUINT32 end;
+ gctUINT32 pid;
+ gctUINT32 linkLow;
+ gctUINT32 linkHigh;
+};
+
+typedef struct _gckADDRESSDATA * gckADDRESSDATA;
+struct _gckADDRESSDATA
+{
+ gctUINT32 start;
+ gctUINT32 end;
+};
+
+typedef union _gcuQUEUEDATA
+{
+ struct _gckLINKDATA linkData;
+
+ struct _gckADDRESSDATA addressData;
+}
+gcuQUEUEDATA;
+
+typedef struct _gckQUEUE * gckQUEUE;
+struct _gckQUEUE
+{
+ gcuQUEUEDATA * datas;
+ gctUINT32 rear;
+ gctUINT32 front;
+ gctUINT32 count;
+ gctUINT32 size;
+};
+
+typedef enum _gceTRACEMODE
+{
+ gcvTRACEMODE_NONE = 0,
+ gcvTRACEMODE_FULL = 1,
+ gcvTRACEMODE_LOGGER = 2,
+ gcvTRACEMODE_PRE = 3,
+ gcvTRACEMODE_POST = 4,
+} gceTRACEMODE;
+
+typedef struct _gcsLISTHEAD * gcsLISTHEAD_PTR;
+typedef struct _gcsLISTHEAD
+{
+ gcsLISTHEAD_PTR prev;
+ gcsLISTHEAD_PTR next;
+}
+gcsLISTHEAD;
+
+/*
+ gcvFEATURE_DATABASE_DATE_MASK
+
+ Mask used to control which bits of chip date will be used to
+ query feature database, ignore release date for fpga and emulator.
+*/
+#if (gcdFPGA_BUILD || defined(EMULATOR))
+# define gcvFEATURE_DATABASE_DATE_MASK (0U)
+#else
+# define gcvFEATURE_DATABASE_DATE_MASK (~0U)
+#endif
+
+#if defined(__GNUC__)
+#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define gcdENDIAN_BIG 1
+#else
+#define gcdENDIAN_BIG 0
+#endif
+#else
+#define gcdENDIAN_BIG 0
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_types_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_version.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_version.h
new file mode 100644
index 000000000000..35d66f6f8ae2
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_version.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_version_h_
+#define __gc_hal_version_h_
+
+#define gcvVERSION_MAJOR 6
+
+#define gcvVERSION_MINOR 2
+
+#define gcvVERSION_PATCH 4
+
+#define gcvVERSION_BUILD 150331
+
+#define gcvVERSION_STRING "6.2.4.p1.150331"
+
+#endif /* __gc_hal_version_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_vg.h b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_vg.h
new file mode 100644
index 000000000000..83328c37fce6
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/kernel/inc/gc_hal_vg.h
@@ -0,0 +1,916 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_vg_h_
+#define __gc_hal_vg_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include "gc_hal_rename.h"
+#include "gc_hal_types.h"
+#include "gc_hal_enum.h"
+#include "gc_hal_base.h"
+
+#if gcdENABLE_VG
+
+/* Thread routine type. */
+#if defined(LINUX)
+ typedef gctINT gctTHREADFUNCRESULT;
+ typedef gctPOINTER gctTHREADFUNCPARAMETER;
+# define gctTHREADFUNCTYPE
+#elif defined(WIN32)
+ typedef gctUINT gctTHREADFUNCRESULT;
+ typedef gctPOINTER gctTHREADFUNCPARAMETER;
+# define gctTHREADFUNCTYPE __stdcall
+#elif defined(__QNXNTO__)
+ typedef void * gctTHREADFUNCRESULT;
+ typedef gctPOINTER gctTHREADFUNCPARAMETER;
+# define gctTHREADFUNCTYPE
+#endif
+
+typedef gctTHREADFUNCRESULT (gctTHREADFUNCTYPE * gctTHREADFUNC) (
+ gctTHREADFUNCPARAMETER ThreadParameter
+ );
+
+
+#if defined(gcvDEBUG)
+# undef gcvDEBUG
+#endif
+
+#define gcdFORCE_DEBUG 0
+#define gcdFORCE_MESSAGES 0
+
+
+#if DBG || defined(DEBUG) || defined(_DEBUG) || gcdFORCE_DEBUG
+# define gcvDEBUG 1
+#else
+# define gcvDEBUG 0
+#endif
+
+#define _gcmERROR_RETURN(prefix, func) \
+ status = func; \
+ if (gcmIS_ERROR(status)) \
+ { \
+ prefix##PRINT_VERSION(); \
+ prefix##TRACE(gcvLEVEL_ERROR, \
+ #prefix "ERR_RETURN: status=%d(%s) @ %s(%d)", \
+ status, gcoOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \
+ return status; \
+ } \
+ do { } while (gcvFALSE)
+
+#define gcmERROR_RETURN(func) _gcmERROR_RETURN(gcm, func)
+
+#define gcmLOG_LOCATION()
+
+#define gcmkIS_ERROR(status) (status < 0)
+
+#define gcmALIGNDOWN(n, align) \
+( \
+ (n) & ~((align) - 1) \
+)
+
+#define gcmIS_VALID_INDEX(Index, Array) \
+ (((gctUINT) (Index)) < gcmCOUNTOF(Array))
+
+
+#define gcmIS_NAN(x) \
+( \
+ ((* (gctUINT32_PTR) &(x)) & 0x7FFFFFFF) == 0x7FFFFFFF \
+)
+
+#define gcmLERP(v1, v2, w) \
+ ((v1) * (w) + (v2) * (1.0f - (w)))
+
+#define gcmINTERSECT(Start1, Start2, Length) \
+ (gcmABS((Start1) - (Start2)) < (Length))
+
+/*******************************************************************************
+**
+** gcmERR_GOTO
+**
+** Prints a message and terminates the current loop on error.
+**
+** ASSUMPTIONS:
+**
+** 'status' variable of gceSTATUS type must be defined.
+**
+** ARGUMENTS:
+**
+** Function
+** Function to evaluate.
+*/
+
+#define gcmERR_GOTO(Function) \
+ status = Function; \
+ if (gcmIS_ERROR(status)) \
+ { \
+ gcmTRACE( \
+ gcvLEVEL_ERROR, \
+ "gcmERR_GOTO: status=%d @ line=%d in function %s.\n", \
+ status, __LINE__, __FUNCTION__ \
+ ); \
+ goto ErrorHandler; \
+ }
+
+#if gcvDEBUG || gcdFORCE_MESSAGES
+# define gcmVERIFY_BOOLEAN(Expression) \
+ gcmASSERT( \
+ ( (Expression) == gcvFALSE ) || \
+ ( (Expression) == gcvTRUE ) \
+ )
+#else
+# define gcmVERIFY_BOOLEAN(Expression)
+#endif
+
+/*******************************************************************************
+**
+** gcmVERIFYFIELDFIT
+**
+** Verify whether the value fits in the field.
+**
+** ARGUMENTS:
+**
+** data Data value.
+** reg Name of register.
+** field Name of field within register.
+** value Value for field.
+*/
+#define gcmVERIFYFIELDFIT(reg, field, value) \
+ gcmASSERT( \
+ (value) <= gcmFIELDMAX(reg, field) \
+ )
+/*******************************************************************************
+**
+** gcmFIELDMAX
+**
+** Get field maximum value.
+**
+** ARGUMENTS:
+**
+** reg Name of register.
+** field Name of field within register.
+*/
+#define gcmFIELDMAX(reg, field) \
+( \
+ (gctUINT32) \
+ ( \
+ (__gcmGETSIZE(reg##_##field) == 32) \
+ ? ~0U \
+ : (~(~0U << __gcmGETSIZE(reg##_##field))) \
+ ) \
+)
+
+
+/* ANSI C does not have the 'f' functions, define replacements here. */
+#define gcmSINF(x) ((gctFLOAT) sin(x))
+#define gcmCOSF(x) ((gctFLOAT) cos(x))
+#define gcmASINF(x) ((gctFLOAT) asin(x))
+#define gcmACOSF(x) ((gctFLOAT) acos(x))
+#define gcmSQRTF(x) ((gctFLOAT) sqrt(x))
+#define gcmFABSF(x) ((gctFLOAT) fabs(x))
+#define gcmFMODF(x, y) ((gctFLOAT) fmod((x), (y)))
+#define gcmCEILF(x) ((gctFLOAT) ceil(x))
+#define gcmFLOORF(x) ((gctFLOAT) floor(x))
+
+
+
+/* Fixed point constants. */
+#define gcvZERO_X ((gctFIXED_POINT) 0x00000000)
+#define gcvHALF_X ((gctFIXED_POINT) 0x00008000)
+#define gcvONE_X ((gctFIXED_POINT) 0x00010000)
+#define gcvNEGONE_X ((gctFIXED_POINT) 0xFFFF0000)
+#define gcvTWO_X ((gctFIXED_POINT) 0x00020000)
+
+/* Integer constants. */
+#define gcvMAX_POS_INT ((gctINT) 0x7FFFFFFF)
+#define gcvMAX_NEG_INT ((gctINT) 0x80000000)
+
+/* Float constants. */
+#define gcvMAX_POS_FLOAT ((gctFLOAT) 3.4028235e+038)
+#define gcvMAX_NEG_FLOAT ((gctFLOAT) -3.4028235e+038)
+
+/******************************************************************************\
+***************************** Miscellaneous Macro ******************************
+\******************************************************************************/
+
+#define gcmKB2BYTES(Kilobyte) \
+( \
+ (Kilobyte) << 10 \
+)
+
+#define gcmMB2BYTES(Megabyte) \
+( \
+ (Megabyte) << 20 \
+)
+
+#define gcmMAT(Matrix, Row, Column) \
+( \
+ (Matrix) [(Row) * 3 + (Column)] \
+)
+
+#define gcmMAKE2CHAR(Char1, Char2) \
+( \
+ ((gctUINT16) (gctUINT8) (Char1) << 0) | \
+ ((gctUINT16) (gctUINT8) (Char2) << 8) \
+)
+
+#define gcmMAKE4CHAR(Char1, Char2, Char3, Char4) \
+( \
+ ((gctUINT32)(gctUINT8) (Char1) << 0) | \
+ ((gctUINT32)(gctUINT8) (Char2) << 8) | \
+ ((gctUINT32)(gctUINT8) (Char3) << 16) | \
+ ((gctUINT32)(gctUINT8) (Char4) << 24) \
+)
+
+/* some platforms need to fix the physical address for HW to access*/
+#define gcmFIXADDRESS(address) \
+(\
+ (address)\
+)
+
+#define gcmkFIXADDRESS(address) \
+(\
+ (address)\
+)
+
+/******************************************************************************\
+****************************** Kernel Debug Macro ******************************
+\******************************************************************************/
+
+/* Return the kernel logical pointer for the given physical one. */
+gceSTATUS
+gckOS_GetKernelLogical(
+ IN gckOS Os,
+ IN gctUINT32 Address,
+ OUT gctPOINTER * KernelPointer
+ );
+
+/* Return the kernel logical pointer for the given physical one. */
+gceSTATUS
+gckOS_GetKernelLogicalEx(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctUINT32 Address,
+ OUT gctPOINTER * KernelPointer
+ );
+
+/*----------------------------------------------------------------------------*/
+/*----------------------------- Semaphore Object -----------------------------*/
+
+/* Increment the value of a semaphore. */
+gceSTATUS
+gckOS_IncrementSemaphore(
+ IN gckOS Os,
+ IN gctSEMAPHORE Semaphore
+ );
+
+/* Decrement the value of a semaphore (waiting might occur). */
+gceSTATUS
+gckOS_DecrementSemaphore(
+ IN gckOS Os,
+ IN gctSEMAPHORE Semaphore
+ );
+
+
+/*----------------------------------------------------------------------------*/
+/*------------------------------- Thread Object ------------------------------*/
+
+/* Start a thread. */
+gceSTATUS
+gckOS_StartThread(
+ IN gckOS Os,
+ IN gctTHREADFUNC ThreadFunction,
+ IN gctPOINTER ThreadParameter,
+ OUT gctTHREAD * Thread
+ );
+
+/* Stop a thread. */
+gceSTATUS
+gckOS_StopThread(
+ IN gckOS Os,
+ IN gctTHREAD Thread
+ );
+
+/* Verify whether the thread is still running. */
+gceSTATUS
+gckOS_VerifyThread(
+ IN gckOS Os,
+ IN gctTHREAD Thread
+ );
+
+
+/* Construct a new gckVGKERNEL object. */
+gceSTATUS
+gckVGKERNEL_Construct(
+ IN gckOS Os,
+ IN gctPOINTER Context,
+ IN gckKERNEL inKernel,
+ OUT gckVGKERNEL * Kernel
+ );
+
+/* Destroy an gckVGKERNEL object. */
+gceSTATUS
+gckVGKERNEL_Destroy(
+ IN gckVGKERNEL Kernel
+ );
+
+/* Unmap memory. */
+gceSTATUS
+gckKERNEL_UnmapMemory(
+ IN gckKERNEL Kernel,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical,
+ IN gctUINT32 ProcessID
+ );
+
+/* Dispatch a user-level command. */
+gceSTATUS
+gckVGKERNEL_Dispatch(
+ IN gckKERNEL Kernel,
+ IN gctBOOL FromUser,
+ IN OUT struct _gcsHAL_INTERFACE * Interface
+ );
+
+/* Query command buffer requirements. */
+gceSTATUS
+gckKERNEL_QueryCommandBuffer(
+ IN gckKERNEL Kernel,
+ OUT gcsCOMMAND_BUFFER_INFO_PTR Information
+ );
+
+/******************************************************************************\
+******************************* gckVGHARDWARE Object ******************************
+\******************************************************************************/
+
+/* Construct a new gckVGHARDWARE object. */
+gceSTATUS
+gckVGHARDWARE_Construct(
+ IN gckOS Os,
+ OUT gckVGHARDWARE * Hardware
+ );
+
+/* Destroy an gckVGHARDWARE object. */
+gceSTATUS
+gckVGHARDWARE_Destroy(
+ IN gckVGHARDWARE Hardware
+ );
+
+/* Query system memory requirements. */
+gceSTATUS
+gckVGHARDWARE_QuerySystemMemory(
+ IN gckVGHARDWARE Hardware,
+ OUT gctSIZE_T * SystemSize,
+ OUT gctUINT32 * SystemBaseAddress
+ );
+
+/* Build virtual address. */
+gceSTATUS
+gckVGHARDWARE_BuildVirtualAddress(
+ IN gckVGHARDWARE Hardware,
+ IN gctUINT32 Index,
+ IN gctUINT32 Offset,
+ OUT gctUINT32 * Address
+ );
+
+/* Kickstart the command processor. */
+gceSTATUS
+gckVGHARDWARE_Execute(
+ IN gckVGHARDWARE Hardware,
+ IN gctUINT32 Address,
+ IN gctUINT32 Count
+ );
+
+/* Query the available memory. */
+gceSTATUS
+gckVGHARDWARE_QueryMemory(
+ IN gckVGHARDWARE Hardware,
+ OUT gctSIZE_T * InternalSize,
+ OUT gctUINT32 * InternalBaseAddress,
+ OUT gctUINT32 * InternalAlignment,
+ OUT gctSIZE_T * ExternalSize,
+ OUT gctUINT32 * ExternalBaseAddress,
+ OUT gctUINT32 * ExternalAlignment,
+ OUT gctUINT32 * HorizontalTileSize,
+ OUT gctUINT32 * VerticalTileSize
+ );
+
+/* Query the identity of the hardware. */
+gceSTATUS
+gckVGHARDWARE_QueryChipIdentity(
+ IN gckVGHARDWARE Hardware,
+ OUT gceCHIPMODEL* ChipModel,
+ OUT gctUINT32* ChipRevision,
+ OUT gctUINT32* ProductID,
+ OUT gctUINT32* EcoID,
+ OUT gctUINT32* CustomerID,
+ OUT gctUINT32* ChipFeatures,
+ OUT gctUINT32* ChipMinorFeatures,
+ OUT gctUINT32* ChipMinorFeatures1
+ );
+
+/* Convert an API format. */
+gceSTATUS
+gckVGHARDWARE_ConvertFormat(
+ IN gckVGHARDWARE Hardware,
+ IN gceSURF_FORMAT Format,
+ OUT gctUINT32 * BitsPerPixel,
+ OUT gctUINT32 * BytesPerTile
+ );
+
+/* Split a harwdare specific address into API stuff. */
+gceSTATUS
+gckVGHARDWARE_SplitMemory(
+ IN gckVGHARDWARE Hardware,
+ IN gctUINT32 Address,
+ OUT gcePOOL * Pool,
+ OUT gctUINT32 * Offset
+ );
+
+/* Align size to tile boundary. */
+gceSTATUS
+gckVGHARDWARE_AlignToTile(
+ IN gckVGHARDWARE Hardware,
+ IN gceSURF_TYPE Type,
+ IN OUT gctUINT32_PTR Width,
+ IN OUT gctUINT32_PTR Height
+ );
+
+/* Convert logical address to hardware specific address. */
+gceSTATUS
+gckVGHARDWARE_ConvertLogical(
+ IN gckVGHARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN gctBOOL InUserSpace,
+ OUT gctUINT32 * Address
+ );
+
+/* Program MMU. */
+gceSTATUS
+gckVGHARDWARE_SetMMU(
+ IN gckVGHARDWARE Hardware,
+ IN gctPOINTER Logical
+ );
+
+/* Flush the MMU. */
+gceSTATUS
+gckVGHARDWARE_FlushMMU(
+ IN gckVGHARDWARE Hardware
+ );
+
+/* Get idle register. */
+gceSTATUS
+gckVGHARDWARE_GetIdle(
+ IN gckVGHARDWARE Hardware,
+ OUT gctUINT32 * Data
+ );
+
+/* Flush the caches. */
+gceSTATUS
+gckVGHARDWARE_Flush(
+ IN gckVGHARDWARE Hardware,
+ IN gceKERNEL_FLUSH Flush,
+ IN gctPOINTER Logical,
+ IN OUT gctSIZE_T * Bytes
+ );
+
+/* Enable/disable fast clear. */
+gceSTATUS
+gckVGHARDWARE_SetFastClear(
+ IN gckVGHARDWARE Hardware,
+ IN gctINT Enable
+ );
+
+gceSTATUS
+gckVGHARDWARE_ReadInterrupt(
+ IN gckVGHARDWARE Hardware,
+ OUT gctUINT32_PTR IDs
+ );
+
+/* Power management. */
+gceSTATUS
+gckVGHARDWARE_SetPowerManagementState(
+ IN gckVGHARDWARE Hardware,
+ IN gceCHIPPOWERSTATE State
+ );
+
+gceSTATUS
+gckVGHARDWARE_QueryPowerManagementState(
+ IN gckVGHARDWARE Hardware,
+ OUT gceCHIPPOWERSTATE* State
+ );
+
+gceSTATUS
+gckVGHARDWARE_SetPowerManagement(
+ IN gckVGHARDWARE Hardware,
+ IN gctBOOL PowerManagement
+ );
+
+gceSTATUS
+gckVGHARDWARE_SetPowerOffTimeout(
+ IN gckVGHARDWARE Hardware,
+ IN gctUINT32 Timeout
+ );
+
+gceSTATUS
+gckVGHARDWARE_QueryPowerOffTimeout(
+ IN gckVGHARDWARE Hardware,
+ OUT gctUINT32* Timeout
+ );
+
+gceSTATUS
+gckVGHARDWARE_QueryIdle(
+ IN gckVGHARDWARE Hardware,
+ OUT gctBOOL_PTR IsIdle
+ );
+/******************************************************************************\
+*************************** Command Buffer Structures **************************
+\******************************************************************************/
+
+/* Vacant command buffer marker. */
+#define gcvVACANT_BUFFER ((gcsCOMPLETION_SIGNAL_PTR) ((gctSIZE_T)1))
+
+/* Command buffer header. */
+typedef struct _gcsCMDBUFFER * gcsCMDBUFFER_PTR;
+typedef struct _gcsCMDBUFFER
+{
+ /* Pointer to the completion signal. */
+ gcsCOMPLETION_SIGNAL_PTR completion;
+
+ /* The user sets this to the node of the container buffer whitin which
+ this particular command buffer resides. The kernel sets this to the
+ node of the internally allocated buffer. */
+ gcuVIDMEM_NODE_PTR node;
+
+ /* Command buffer hardware address. */
+ gctUINT32 address;
+
+ /* The offset of the buffer from the beginning of the header. */
+ gctUINT32 bufferOffset;
+
+ /* Size of the area allocated for the data portion of this particular
+ command buffer (headers and tail reserves are excluded). */
+ gctUINT32 size;
+
+ /* Offset into the buffer [0..size]; reflects exactly how much data has
+ been put into the command buffer. */
+ gctUINT offset;
+
+ /* The number of command units in the buffer for the hardware to
+ execute. */
+ gctUINT32 dataCount;
+
+ /* MANAGED BY : user HAL (gcoBUFFER object).
+ USED BY : user HAL (gcoBUFFER object).
+ Points to the immediate next allocated command buffer. */
+ gcsCMDBUFFER_PTR nextAllocated;
+
+ /* MANAGED BY : user layers (HAL and drivers).
+ USED BY : kernel HAL (gcoBUFFER object).
+ Points to the next subbuffer if any. A family of subbuffers are chained
+ together and are meant to be executed inseparably as a unit. Meaning
+ that context switching cannot occur while a chain of subbuffers is being
+ executed. */
+ gcsCMDBUFFER_PTR nextSubBuffer;
+}
+gcsCMDBUFFER;
+
+/* Command queue element. */
+typedef struct _gcsVGCMDQUEUE
+{
+ /* Pointer to the command buffer header. */
+ gcsCMDBUFFER_PTR commandBuffer;
+
+ /* Dynamic vs. static command buffer state. */
+ gctBOOL dynamic;
+}
+gcsVGCMDQUEUE;
+
+/* Context map entry. */
+typedef struct _gcsVGCONTEXT_MAP
+{
+ /* State index. */
+ gctUINT32 index;
+
+ /* New state value. */
+ gctUINT32 data;
+
+ /* Points to the next entry in the mod list. */
+ gcsVGCONTEXT_MAP_PTR next;
+}
+gcsVGCONTEXT_MAP;
+
+/* gcsVGCONTEXT structure that holds the current context. */
+typedef struct _gcsVGCONTEXT
+{
+ /* Context ID. */
+ gctUINT64 id;
+
+ /* State caching ebable flag. */
+ gctBOOL stateCachingEnabled;
+
+ /* Current pipe. */
+ gctUINT32 currentPipe;
+
+ /* State map/mod buffer. */
+ gctUINT32 mapFirst;
+ gctUINT32 mapLast;
+ gcsVGCONTEXT_MAP_PTR mapContainer;
+ gcsVGCONTEXT_MAP_PTR mapPrev;
+ gcsVGCONTEXT_MAP_PTR mapCurr;
+ gcsVGCONTEXT_MAP_PTR firstPrevMap;
+ gcsVGCONTEXT_MAP_PTR firstCurrMap;
+
+ /* Main context buffer. */
+ gcsCMDBUFFER_PTR header;
+ gctUINT32_PTR buffer;
+
+ /* Completion signal. */
+ gctHANDLE process;
+ gctSIGNAL signal;
+
+#if defined(__QNXNTO__)
+ gctSIGNAL userSignal;
+ gctINT32 coid;
+ gctINT32 rcvid;
+#endif
+}
+gcsVGCONTEXT;
+
+/* User space task header. */
+typedef struct _gcsTASK * gcsTASK_PTR;
+typedef struct _gcsTASK
+{
+ /* Pointer to the next task for the same interrupt in user space. */
+ gcsTASK_PTR next;
+
+ /* Size of the task data that immediately follows the structure. */
+ gctUINT size;
+
+ /* Task data starts here. */
+ /* ... */
+}
+gcsTASK;
+
+/* User space task master table entry. */
+typedef struct _gcsTASK_MASTER_ENTRY * gcsTASK_MASTER_ENTRY_PTR;
+typedef struct _gcsTASK_MASTER_ENTRY
+{
+ /* Pointers to the head and to the tail of the task chain. */
+ gcsTASK_PTR head;
+ gcsTASK_PTR tail;
+}
+gcsTASK_MASTER_ENTRY;
+
+/* User space task master table entry. */
+typedef struct _gcsTASK_MASTER_TABLE
+{
+ /* Table with one entry per block. */
+ gcsTASK_MASTER_ENTRY table[gcvBLOCK_COUNT];
+
+ /* The total number of tasks sckeduled. */
+ gctUINT count;
+
+ /* The total size of event data in bytes. */
+ gctUINT size;
+
+#if defined(__QNXNTO__)
+ gctINT32 coid;
+ gctINT32 rcvid;
+#endif
+}
+gcsTASK_MASTER_TABLE;
+
+/******************************************************************************\
+***************************** gckVGINTERRUPT Object ******************************
+\******************************************************************************/
+
+typedef struct _gckVGINTERRUPT * gckVGINTERRUPT;
+
+typedef gceSTATUS (* gctINTERRUPT_HANDLER)(
+ IN gckVGKERNEL Kernel
+ );
+
+gceSTATUS
+gckVGINTERRUPT_Construct(
+ IN gckVGKERNEL Kernel,
+ OUT gckVGINTERRUPT * Interrupt
+ );
+
+gceSTATUS
+gckVGINTERRUPT_Destroy(
+ IN gckVGINTERRUPT Interrupt
+ );
+
+gceSTATUS
+gckVGINTERRUPT_Enable(
+ IN gckVGINTERRUPT Interrupt,
+ IN OUT gctINT32_PTR Id,
+ IN gctINTERRUPT_HANDLER Handler
+ );
+
+gceSTATUS
+gckVGINTERRUPT_Disable(
+ IN gckVGINTERRUPT Interrupt,
+ IN gctINT32 Id
+ );
+
+#ifndef __QNXNTO__
+
+gceSTATUS
+gckVGINTERRUPT_Enque(
+ IN gckVGINTERRUPT Interrupt
+ );
+
+#else
+
+gceSTATUS
+gckVGINTERRUPT_Enque(
+ IN gckVGINTERRUPT Interrupt,
+ OUT gckOS *Os,
+ OUT gctSEMAPHORE *Semaphore
+ );
+
+#endif
+
+gceSTATUS
+gckVGINTERRUPT_DumpState(
+ IN gckVGINTERRUPT Interrupt
+ );
+
+
+/******************************************************************************\
+******************************* gckVGCOMMAND Object *******************************
+\******************************************************************************/
+
+typedef struct _gckVGCOMMAND * gckVGCOMMAND;
+
+/* Construct a new gckVGCOMMAND object. */
+gceSTATUS
+gckVGCOMMAND_Construct(
+ IN gckVGKERNEL Kernel,
+ IN gctUINT TaskGranularity,
+ IN gctUINT QueueSize,
+ OUT gckVGCOMMAND * Command
+ );
+
+/* Destroy an gckVGCOMMAND object. */
+gceSTATUS
+gckVGCOMMAND_Destroy(
+ IN gckVGCOMMAND Command
+ );
+
+/* Query command buffer attributes. */
+gceSTATUS
+gckVGCOMMAND_QueryCommandBuffer(
+ IN gckVGCOMMAND Command,
+ OUT gcsCOMMAND_BUFFER_INFO_PTR Information
+ );
+
+/* Allocate a command queue. */
+gceSTATUS
+gckVGCOMMAND_Allocate(
+ IN gckVGCOMMAND Command,
+ IN gctSIZE_T Size,
+ OUT gcsCMDBUFFER_PTR * CommandBuffer,
+ OUT gctPOINTER * Data
+ );
+
+/* Release memory held by the command queue. */
+gceSTATUS
+gckVGCOMMAND_Free(
+ IN gckVGCOMMAND Command,
+ IN gcsCMDBUFFER_PTR CommandBuffer
+ );
+
+/* Schedule the command queue for execution. */
+gceSTATUS
+gckVGCOMMAND_Execute(
+ IN gckVGCOMMAND Command,
+ IN gcsCMDBUFFER_PTR CommandBuffer
+ );
+
+/* Commit a buffer to the command queue. */
+gceSTATUS
+gckVGCOMMAND_Commit(
+ IN gckVGCOMMAND Command,
+ IN gcsVGCONTEXT_PTR Context,
+ IN gcsVGCMDQUEUE_PTR Queue,
+ IN gctUINT EntryCount,
+ IN gcsTASK_MASTER_TABLE_PTR TaskTable
+ );
+
+/******************************************************************************\
+********************************* gckVGMMU Object ********************************
+\******************************************************************************/
+
+typedef struct _gckVGMMU * gckVGMMU;
+
+/* Construct a new gckVGMMU object. */
+gceSTATUS
+gckVGMMU_Construct(
+ IN gckVGKERNEL Kernel,
+ IN gctUINT32 MmuSize,
+ OUT gckVGMMU * Mmu
+ );
+
+/* Destroy an gckVGMMU object. */
+gceSTATUS
+gckVGMMU_Destroy(
+ IN gckVGMMU Mmu
+ );
+
+/* Allocate pages inside the MMU. */
+gceSTATUS
+gckVGMMU_AllocatePages(
+ IN gckVGMMU Mmu,
+ IN gctSIZE_T PageCount,
+ OUT gctPOINTER * PageTable,
+ OUT gctUINT32 * Address
+ );
+
+/* Remove a page table from the MMU. */
+gceSTATUS
+gckVGMMU_FreePages(
+ IN gckVGMMU Mmu,
+ IN gctPOINTER PageTable,
+ IN gctSIZE_T PageCount
+ );
+
+/* Set the MMU page with info. */
+gceSTATUS
+gckVGMMU_SetPage(
+ IN gckVGMMU Mmu,
+ IN gctUINT32 PageAddress,
+ IN gctUINT32 *PageEntry
+ );
+
+/* Flush MMU */
+gceSTATUS
+gckVGMMU_Flush(
+ IN gckVGMMU Mmu
+ );
+
+#endif /* gcdENABLE_VG */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __gc_hal_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_array.h b/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_array.h
new file mode 100644
index 000000000000..8abb7e52f5ce
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_array.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_allocator_array_h_
+#define __gc_hal_kernel_allocator_array_h_
+
+extern gceSTATUS
+_GFPAlloctorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ );
+
+extern gceSTATUS
+_UserMemoryAlloctorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ );
+
+extern gceSTATUS
+_ReservedMemoryAllocatorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ );
+
+#ifdef CONFIG_DMA_SHARED_BUFFER
+extern gceSTATUS
+_DmabufAlloctorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ );
+#endif
+
+#ifndef NO_DMA_COHERENT
+extern gceSTATUS
+_DmaAlloctorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ );
+#endif
+
+/* Default allocator entry. */
+gcsALLOCATOR_DESC allocatorArray[] =
+{
+ /* GFP allocator. */
+ gcmkDEFINE_ALLOCATOR_DESC("gfp", _GFPAlloctorInit),
+
+ /* User memory importer. */
+ gcmkDEFINE_ALLOCATOR_DESC("user", _UserMemoryAlloctorInit),
+
+#ifdef CONFIG_DMA_SHARED_BUFFER
+ /* Dmabuf allocator. */
+ gcmkDEFINE_ALLOCATOR_DESC("dmabuf", _DmabufAlloctorInit),
+#endif
+
+#ifndef NO_DMA_COHERENT
+ gcmkDEFINE_ALLOCATOR_DESC("dma", _DmaAlloctorInit),
+#endif
+
+ gcmkDEFINE_ALLOCATOR_DESC("reserved-mem", _ReservedMemoryAllocatorInit),
+};
+
+#endif
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_dma.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_dma.c
new file mode 100644
index 000000000000..5aeeaaf3cfcc
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_dma.c
@@ -0,0 +1,594 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_allocator.h"
+
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <asm/atomic.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#define _GC_OBJ_ZONE gcvZONE_OS
+
+typedef struct _gcsDMA_PRIV * gcsDMA_PRIV_PTR;
+typedef struct _gcsDMA_PRIV {
+ atomic_t usage;
+}
+gcsDMA_PRIV;
+
+struct mdl_dma_priv {
+ gctPOINTER kvaddr;
+ dma_addr_t dmaHandle;
+};
+
+/*
+* Debugfs support.
+*/
+static int gc_dma_usage_show(struct seq_file* m, void* data)
+{
+ gcsINFO_NODE *node = m->private;
+ gckALLOCATOR Allocator = node->device;
+ gcsDMA_PRIV_PTR priv = Allocator->privateData;
+ long long usage = (long long)atomic_read(&priv->usage);
+
+ seq_printf(m, "type n pages bytes\n");
+ seq_printf(m, "normal %10llu %12llu\n", usage, usage * PAGE_SIZE);
+
+ return 0;
+}
+
+static gcsINFO InfoList[] =
+{
+ {"dmausage", gc_dma_usage_show},
+};
+
+static void
+_DebugfsInit(
+ IN gckALLOCATOR Allocator,
+ IN gckDEBUGFS_DIR Root
+ )
+{
+ gcmkVERIFY_OK(
+ gckDEBUGFS_DIR_Init(&Allocator->debugfsDir, Root->root, "dma"));
+
+ gcmkVERIFY_OK(gckDEBUGFS_DIR_CreateFiles(
+ &Allocator->debugfsDir,
+ InfoList,
+ gcmCOUNTOF(InfoList),
+ Allocator
+ ));
+}
+
+static void
+_DebugfsCleanup(
+ IN gckALLOCATOR Allocator
+ )
+{
+ gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(
+ &Allocator->debugfsDir,
+ InfoList,
+ gcmCOUNTOF(InfoList)
+ ));
+
+ gckDEBUGFS_DIR_Deinit(&Allocator->debugfsDir);
+}
+
+#ifdef CONFIG_ARM64
+static struct device *
+_GetDevice(
+ IN gckOS Os
+ )
+{
+ gcsPLATFORM *platform;
+
+ platform = Os->device->platform;
+
+ if (!platform)
+ {
+ return gcvNULL;
+ }
+
+ return &platform->device->dev;
+}
+#endif
+
+static gceSTATUS
+_DmaAlloc(
+ IN gckALLOCATOR Allocator,
+ INOUT PLINUX_MDL Mdl,
+ IN gctSIZE_T NumPages,
+ IN gctUINT32 Flags
+ )
+{
+ gceSTATUS status;
+ gcsDMA_PRIV_PTR allocatorPriv = (gcsDMA_PRIV_PTR)Allocator->privateData;
+
+ struct mdl_dma_priv *mdlPriv=gcvNULL;
+ gckOS os = Allocator->os;
+
+ gcmkHEADER_ARG("Mdl=%p NumPages=0x%zx Flags=0x%x", Mdl, NumPages, Flags);
+
+ gcmkONERROR(gckOS_Allocate(os, sizeof(struct mdl_dma_priv), (gctPOINTER *)&mdlPriv));
+
+ mdlPriv->kvaddr
+#if defined CONFIG_ARM64
+ = dma_alloc_coherent(_GetDevice(os), NumPages * PAGE_SIZE, &mdlPriv->dmaHandle, GFP_KERNEL | gcdNOWARN);
+#elif defined CONFIG_MIPS || defined CONFIG_CPU_CSKYV2 || defined CONFIG_PPC
+ = dma_alloc_coherent(gcvNULL, NumPages * PAGE_SIZE, &mdlPriv->dmaHandle, GFP_KERNEL | gcdNOWARN);
+#else
+ = dma_alloc_writecombine(gcvNULL, NumPages * PAGE_SIZE, &mdlPriv->dmaHandle, GFP_KERNEL | gcdNOWARN);
+#endif
+
+#ifdef CONFLICT_BETWEEN_BASE_AND_PHYS
+ if ((os->device->baseAddress & 0x80000000) != (mdlPriv->dmaHandle & 0x80000000))
+ {
+ mdlPriv->dmaHandle = (mdlPriv->dmaHandle & ~0x80000000)
+ | (os->device->baseAddress & 0x80000000);
+ }
+#endif
+
+ if (mdlPriv->kvaddr == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ Mdl->priv = mdlPriv;
+
+ Mdl->dmaHandle = mdlPriv->dmaHandle;
+
+ /* Statistic. */
+ atomic_add(NumPages, &allocatorPriv->usage);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (mdlPriv)
+ {
+ gckOS_Free(os, mdlPriv);
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+_DmaGetSGT(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctSIZE_T Offset,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER *SGT
+ )
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
+ struct page ** pages = gcvNULL;
+ struct page * page = gcvNULL;
+ struct sg_table *sgt = NULL;
+ struct mdl_dma_priv *mdlPriv = (struct mdl_dma_priv*)Mdl->priv;
+
+ gceSTATUS status = gcvSTATUS_OK;
+ gctSIZE_T offset = Offset & ~PAGE_MASK; /* Offset to the first page */
+ gctINT skipPages = Offset >> PAGE_SHIFT; /* skipped pages */
+ gctINT numPages = (PAGE_ALIGN(Offset + Bytes) >> PAGE_SHIFT) - skipPages;
+ gctINT i;
+
+ gcmkASSERT(Offset + Bytes <= Mdl->numPages << PAGE_SHIFT);
+
+ sgt = kmalloc(sizeof(struct sg_table), GFP_KERNEL | gcdNOWARN);
+ if (!sgt)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ pages = kmalloc(sizeof(struct page*) * numPages, GFP_KERNEL | gcdNOWARN);
+ if (!pages)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
+ page = phys_to_page (mdlPriv->dmaHandle);
+#else
+ page = phys_to_page(dma_to_phys(&Allocator->os->device->platform->device->dev, mdlPriv->dmaHandle));
+#endif
+
+ for (i = 0; i < numPages; ++i)
+ {
+ pages[i] = nth_page(page, i + skipPages);
+ }
+
+ if (sg_alloc_table_from_pages(sgt, pages, numPages, offset, Bytes, GFP_KERNEL) < 0)
+ {
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+ *SGT = (gctPOINTER)sgt;
+
+OnError:
+ if (pages)
+ {
+ kfree(pages);
+ }
+
+ if (gcmIS_ERROR(status) && sgt)
+ {
+ kfree(sgt);
+ }
+
+ return status;
+#else
+ return gcvSTATUS_NOT_SUPPORTED;
+#endif
+}
+
+static void
+_DmaFree(
+ IN gckALLOCATOR Allocator,
+ IN OUT PLINUX_MDL Mdl
+ )
+{
+ gckOS os = Allocator->os;
+ struct mdl_dma_priv *mdlPriv=(struct mdl_dma_priv *)Mdl->priv;
+ gcsDMA_PRIV_PTR allocatorPriv = (gcsDMA_PRIV_PTR)Allocator->privateData;
+
+#if defined CONFIG_ARM64
+ dma_free_coherent(_GetDevice(os), Mdl->numPages * PAGE_SIZE, mdlPriv->kvaddr, mdlPriv->dmaHandle);
+#elif defined CONFIG_MIPS || defined CONFIG_CPU_CSKYV2 || defined CONFIG_PPC
+ dma_free_coherent(gcvNULL, Mdl->numPages * PAGE_SIZE, mdlPriv->kvaddr, mdlPriv->dmaHandle);
+#else
+ dma_free_writecombine(gcvNULL, Mdl->numPages * PAGE_SIZE, mdlPriv->kvaddr, mdlPriv->dmaHandle);
+#endif
+
+ gckOS_Free(os, mdlPriv);
+
+ /* Statistic. */
+ atomic_sub(Mdl->numPages, &allocatorPriv->usage);
+}
+
+static gceSTATUS
+_DmaMmap(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctSIZE_T skipPages,
+ IN gctSIZE_T numPages,
+ INOUT struct vm_area_struct *vma
+ )
+{
+ struct mdl_dma_priv *mdlPriv = (struct mdl_dma_priv*)Mdl->priv;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ gcmkHEADER_ARG("Allocator=%p Mdl=%p vma=%p", Allocator, Mdl, vma);
+
+ gcmkASSERT(skipPages + numPages <= Mdl->numPages);
+
+ /* map kernel memory to user space.. */
+#if defined CONFIG_MIPS || defined CONFIG_CPU_CSKYV2 || defined CONFIG_PPC
+ if (remap_pfn_range(
+ vma,
+ vma->vm_start,
+ (mdlPriv->dmaHandle >> PAGE_SHIFT) + skipPages,
+ numPages << PAGE_SHIFT,
+ gcmkNONPAGED_MEMROY_PROT(vma->vm_page_prot)) < 0)
+#else
+ /* map kernel memory to user space.. */
+ if (dma_mmap_writecombine(gcvNULL,
+ vma,
+ (gctINT8_PTR)mdlPriv->kvaddr + (skipPages << PAGE_SHIFT),
+ mdlPriv->dmaHandle + (skipPages << PAGE_SHIFT),
+ numPages << PAGE_SHIFT) < 0)
+#endif
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_WARNING, gcvZONE_OS,
+ "%s(%d): dma_mmap_attrs error",
+ __FUNCTION__, __LINE__
+ );
+
+ status = gcvSTATUS_OUT_OF_MEMORY;
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+static void
+_DmaUnmapUser(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Size
+ )
+{
+ if (unlikely(current->mm == gcvNULL))
+ {
+ /* Do nothing if process is exiting. */
+ return;
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)
+ if (vm_munmap((unsigned long)Logical, Size) < 0)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_WARNING, gcvZONE_OS,
+ "%s(%d): vm_munmap failed",
+ __FUNCTION__, __LINE__
+ );
+ }
+#else
+ down_write(&current->mm->mmap_sem);
+ if (do_munmap(current->mm, (unsigned long)Logical, Size) < 0)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_WARNING, gcvZONE_OS,
+ "%s(%d): do_munmap failed",
+ __FUNCTION__, __LINE__
+ );
+ }
+ up_write(&current->mm->mmap_sem);
+#endif
+}
+
+static gceSTATUS
+_DmaMapUser(
+ gckALLOCATOR Allocator,
+ PLINUX_MDL Mdl,
+ gctBOOL Cacheable,
+ OUT gctPOINTER * UserLogical
+ )
+{
+ gctPOINTER userLogical = gcvNULL;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ gcmkHEADER_ARG("Allocator=%p Mdl=%p Cacheable=%d", Allocator, Mdl, Cacheable);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ userLogical = (gctPOINTER)vm_mmap(gcvNULL,
+ 0L,
+ Mdl->numPages * PAGE_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_NORESERVE,
+ 0);
+#else
+ down_write(&current->mm->mmap_sem);
+ userLogical = (gctPOINTER)do_mmap_pgoff(gcvNULL,
+ 0L,
+ Mdl->numPages * PAGE_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ 0);
+ up_write(&current->mm->mmap_sem);
+#endif
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): vmaAddr->%p for phys_addr->%p",
+ __FUNCTION__, __LINE__, userLogical, Mdl
+ );
+
+ if (IS_ERR(userLogical))
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): do_mmap_pgoff error",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ down_write(&current->mm->mmap_sem);
+ do
+ {
+ struct vm_area_struct *vma = find_vma(current->mm, (unsigned long)userLogical);
+ if (vma == gcvNULL)
+ {
+ up_write(&current->mm->mmap_sem);
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): find_vma error",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkERR_BREAK(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ gcmkERR_BREAK(_DmaMmap(Allocator, Mdl, 0, Mdl->numPages, vma));
+
+ *UserLogical = userLogical;
+ }
+ while (gcvFALSE);
+ up_write(&current->mm->mmap_sem);
+
+OnError:
+ if (gcmIS_ERROR(status) && userLogical)
+ {
+ _DmaUnmapUser(Allocator, Mdl, userLogical, Mdl->numPages * PAGE_SIZE);
+ }
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+_DmaMapKernel(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ OUT gctPOINTER *Logical
+ )
+{
+ struct mdl_dma_priv *mdlPriv=(struct mdl_dma_priv *)Mdl->priv;
+ *Logical =mdlPriv->kvaddr;
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_DmaUnmapKernel(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_DmaCache(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Physical,
+ IN gctUINT32 Bytes,
+ IN gceCACHEOPERATION Operation
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_DmaPhysical(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctUINT32 Offset,
+ OUT gctPHYS_ADDR_T * Physical
+ )
+{
+ struct mdl_dma_priv *mdlPriv=(struct mdl_dma_priv *)Mdl->priv;
+
+ *Physical = mdlPriv->dmaHandle + Offset;
+
+ return gcvSTATUS_OK;
+}
+
+static void
+_DmaAllocatorDestructor(
+ gcsALLOCATOR *Allocator
+ )
+{
+ _DebugfsCleanup(Allocator);
+
+ if (Allocator->privateData)
+ {
+ kfree(Allocator->privateData);
+ }
+
+ kfree(Allocator);
+}
+
+/* Default allocator operations. */
+gcsALLOCATOR_OPERATIONS DmaAllocatorOperations = {
+ .Alloc = _DmaAlloc,
+ .Free = _DmaFree,
+ .Mmap = _DmaMmap,
+ .MapUser = _DmaMapUser,
+ .UnmapUser = _DmaUnmapUser,
+ .MapKernel = _DmaMapKernel,
+ .UnmapKernel = _DmaUnmapKernel,
+ .Cache = _DmaCache,
+ .Physical = _DmaPhysical,
+ .GetSGT = _DmaGetSGT,
+};
+
+/* Default allocator entry. */
+gceSTATUS
+_DmaAlloctorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ )
+{
+ gceSTATUS status;
+ gckALLOCATOR allocator = gcvNULL;
+ gcsDMA_PRIV_PTR priv = gcvNULL;
+
+ gcmkONERROR(gckALLOCATOR_Construct(Os, &DmaAllocatorOperations, &allocator));
+
+ priv = kzalloc(gcmSIZEOF(gcsDMA_PRIV), GFP_KERNEL | gcdNOWARN);
+
+ if (!priv)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ atomic_set(&priv->usage, 0);
+
+ /* Register private data. */
+ allocator->privateData = priv;
+ allocator->destructor = _DmaAllocatorDestructor;
+
+ _DebugfsInit(allocator, Parent);
+
+ /*
+ * DMA allocator is only used for NonPaged memory
+ * when NO_DMA_COHERENT is not defined.
+ */
+ allocator->capability = gcvALLOC_FLAG_DMABUF_EXPORTABLE;
+
+ *Allocator = allocator;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ if (allocator)
+ {
+ kfree(allocator);
+ }
+ return status;
+}
+
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_dmabuf.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_dmabuf.c
new file mode 100644
index 000000000000..d07743be68ba
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_dmabuf.c
@@ -0,0 +1,522 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_allocator.h"
+
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <asm/atomic.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/dma-buf.h>
+#include <linux/platform_device.h>
+
+#define _GC_OBJ_ZONE gcvZONE_OS
+
+/* Descriptor of a dma_buf imported. */
+typedef struct _gcsDMABUF
+{
+ struct dma_buf * dmabuf;
+ struct dma_buf_attachment * attachment;
+ struct sg_table * sgtable;
+ unsigned long * pagearray;
+
+ int npages;
+ int pid;
+ struct list_head list;
+}
+gcsDMABUF;
+
+struct allocator_priv
+{
+ struct mutex lock;
+ struct list_head buf_list;
+};
+
+/*
+* Debugfs support.
+*/
+static int dma_buf_info_show(struct seq_file* m, void* data)
+{
+ int ret;
+ gcsDMABUF *buf_desc;
+ struct dma_buf_attachment *attach_obj;
+ int count = 0;
+ size_t size = 0;
+ int npages = 0;
+ const char *exp_name;
+
+ gcsINFO_NODE *node = m->private;
+ gckALLOCATOR allocator = node->device;
+ struct allocator_priv *priv = allocator->privateData;
+
+ ret = mutex_lock_interruptible(&priv->lock);
+
+ if (ret)
+ return ret;
+
+ seq_puts(m, "Attached dma-buf objects:\n");
+ seq_puts(m, " pid fd pages size exporter attached-devices\n");
+
+ list_for_each_entry(buf_desc, &priv->buf_list, list) {
+ struct dma_buf *buf_obj = buf_desc->dmabuf;
+
+ ret = mutex_lock_interruptible(&buf_obj->lock);
+
+ if (ret) {
+ seq_puts(m,
+ "ERROR locking buffer object: skipping\n");
+ continue;
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+ exp_name = buf_obj->exp_name;
+#else
+ exp_name = "unknown";
+#endif
+
+ seq_printf(m, "%6d %p %8d %8zu %10s",
+ buf_desc->pid,
+ buf_desc->dmabuf,
+ buf_desc->npages,
+ buf_obj->size,
+ exp_name);
+
+ list_for_each_entry(attach_obj, &buf_obj->attachments, node) {
+ seq_printf(m, " %s", dev_name(attach_obj->dev));
+ }
+ seq_puts(m, "\n");
+
+ count++;
+ size += buf_obj->size;
+ npages += buf_desc->npages;
+
+ mutex_unlock(&buf_obj->lock);
+ }
+
+ seq_printf(m, "\nTotal %d objects, %d pages, %zu bytes\n", count, npages, size);
+
+ mutex_unlock(&priv->lock);
+ return 0;
+}
+
+static gcsINFO _InfoList[] =
+{
+ {"bufinfo", dma_buf_info_show},
+};
+
+static void
+_DebugfsInit(
+ IN gckALLOCATOR Allocator,
+ IN gckDEBUGFS_DIR Root
+ )
+{
+ gcmkVERIFY_OK(
+ gckDEBUGFS_DIR_Init(&Allocator->debugfsDir, Root->root, "dma_buf"));
+
+ gcmkVERIFY_OK(gckDEBUGFS_DIR_CreateFiles(
+ &Allocator->debugfsDir,
+ _InfoList,
+ gcmCOUNTOF(_InfoList),
+ Allocator
+ ));
+}
+
+static void
+_DebugfsCleanup(
+ IN gckALLOCATOR Allocator
+ )
+{
+ gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(
+ &Allocator->debugfsDir,
+ _InfoList,
+ gcmCOUNTOF(_InfoList)
+ ));
+
+ gckDEBUGFS_DIR_Deinit(&Allocator->debugfsDir);
+}
+
+static gceSTATUS
+_DmabufAttach(
+ IN gckALLOCATOR Allocator,
+ IN gcsATTACH_DESC_PTR Desc,
+ IN PLINUX_MDL Mdl
+ )
+{
+ gceSTATUS status;
+
+ gckOS os = Allocator->os;
+
+ struct dma_buf *dmabuf = Desc->dmaBuf.dmabuf;
+ struct sg_table *sgt = NULL;
+ struct dma_buf_attachment *attachment = NULL;
+ int npages = 0;
+ unsigned long *pagearray = NULL;
+ int i, j, k = 0;
+ struct scatterlist *s;
+ struct allocator_priv *priv = Allocator->privateData;
+ gcsDMABUF *buf_desc = NULL;
+
+ gcmkHEADER();
+
+ gcmkVERIFY_OBJECT(os, gcvOBJ_OS);
+
+ if (!dmabuf)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ get_dma_buf(dmabuf);
+ attachment = dma_buf_attach(dmabuf, &os->device->platform->device->dev);
+
+ if (!attachment)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ sgt = dma_buf_map_attachment(attachment, DMA_BIDIRECTIONAL);
+
+ if (!sgt)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ /* Prepare page array. */
+ /* Get number of pages. */
+ for_each_sg(sgt->sgl, s, sgt->orig_nents, i)
+ {
+ npages += (sg_dma_len(s) + PAGE_SIZE - 1) / PAGE_SIZE;
+ }
+
+ /* Allocate page arrary. */
+ gcmkONERROR(gckOS_Allocate(os, npages * gcmSIZEOF(*pagearray), (gctPOINTER *)&pagearray));
+
+ /* Fill page arrary. */
+ for_each_sg(sgt->sgl, s, sgt->orig_nents, i)
+ {
+ for (j = 0; j < (sg_dma_len(s) + PAGE_SIZE - 1) / PAGE_SIZE; j++)
+ {
+ pagearray[k++] = sg_dma_address(s) + j * PAGE_SIZE;
+ }
+ }
+
+ /* Prepare descriptor. */
+ gcmkONERROR(gckOS_Allocate(os, sizeof(gcsDMABUF), (gctPOINTER *)&buf_desc));
+
+ buf_desc->dmabuf = dmabuf;
+ buf_desc->pagearray = pagearray;
+ buf_desc->attachment = attachment;
+ buf_desc->sgtable = sgt;
+
+ /* Record in buffer list to support debugfs. */
+ buf_desc->npages = npages;
+ buf_desc->pid = _GetProcessID();
+
+ mutex_lock(&priv->lock);
+ list_add(&buf_desc->list, &priv->buf_list);
+ mutex_unlock(&priv->lock);
+
+ /* Record page number. */
+ Mdl->numPages = npages;
+
+ Mdl->priv = buf_desc;
+
+ /* Need set it as true to avoid MMU mapping. */
+ Mdl->contiguous = gcvTRUE;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (pagearray)
+ {
+ gcmkOS_SAFE_FREE(os, pagearray);
+ }
+
+ if (sgt)
+ {
+ dma_buf_unmap_attachment(attachment, sgt, DMA_BIDIRECTIONAL);
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+
+static void
+_DmabufFree(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl
+ )
+{
+ gcsDMABUF *buf_desc = Mdl->priv;
+ gckOS os = Allocator->os;
+ struct allocator_priv *priv = Allocator->privateData;
+
+ mutex_lock(&priv->lock);
+ list_del(&buf_desc->list);
+ mutex_unlock(&priv->lock);
+
+ dma_buf_unmap_attachment(buf_desc->attachment, buf_desc->sgtable, DMA_BIDIRECTIONAL);
+
+ dma_buf_detach(buf_desc->dmabuf, buf_desc->attachment);
+
+ dma_buf_put(buf_desc->dmabuf);
+
+ gckOS_Free(os, buf_desc->pagearray);
+
+ gckOS_Free(os, buf_desc);
+}
+
+static void
+_DmabufUnmapUser(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Size
+ )
+{
+ gcsDMABUF *buf_desc = Mdl->priv;
+ gctINT8_PTR userLogical = Logical;
+
+ if (unlikely(current->mm == gcvNULL))
+ {
+ /* Do nothing if process is exiting. */
+ return;
+ }
+
+ userLogical -= buf_desc->sgtable->sgl->offset;
+ vm_munmap((unsigned long)userLogical, Mdl->numPages << PAGE_SHIFT);
+}
+
+static gceSTATUS
+_DmabufMapUser(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctBOOL Cacheable,
+ OUT gctPOINTER * UserLogical
+ )
+{
+ gcsDMABUF *buf_desc = Mdl->priv;
+ gctINT8_PTR userLogical = gcvNULL;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ userLogical = (gctINT8_PTR)vm_mmap(buf_desc->dmabuf->file,
+ 0L,
+ Mdl->numPages << PAGE_SHIFT,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_NORESERVE,
+ 0);
+
+ if (IS_ERR(userLogical))
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+ userLogical += buf_desc->sgtable->sgl->offset;
+
+ /* To make sure the mapping is created. */
+ if (access_ok(VERIFY_READ, userLogical, 4))
+ {
+ uint32_t mem;
+ get_user(mem, (uint32_t *)userLogical);
+
+ (void)mem;
+ }
+
+ *UserLogical = (gctPOINTER)userLogical;
+
+OnError:
+ if (gcmIS_ERROR(status) && userLogical)
+ {
+ _DmabufUnmapUser(Allocator, Mdl, userLogical, Mdl->numPages << PAGE_SHIFT);
+ }
+ return status;
+}
+
+static gceSTATUS
+_DmabufMapKernel(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ OUT gctPOINTER *Logical
+ )
+{
+ /* Kernel doesn't acess video memory. */
+ return gcvSTATUS_NOT_SUPPORTED;
+
+}
+
+static gceSTATUS
+_DmabufUnmapKernel(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical
+ )
+{
+ /* Kernel doesn't acess video memory. */
+ return gcvSTATUS_NOT_SUPPORTED;
+}
+
+static gceSTATUS
+_DmabufCache(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Physical,
+ IN gctUINT32 Bytes,
+ IN gceCACHEOPERATION Operation
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+
+static gceSTATUS
+_DmabufPhysical(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctUINT32 Offset,
+ OUT gctPHYS_ADDR_T * Physical
+ )
+{
+ gcsDMABUF *buf_desc = Mdl->priv;
+ gctUINT32 offsetInPage = Offset & ~PAGE_MASK;
+ gctUINT32 index = Offset / PAGE_SIZE;
+
+ *Physical = buf_desc->pagearray[index] + offsetInPage;
+
+
+ return gcvSTATUS_OK;
+}
+
+/* Default allocator operations. */
+static gcsALLOCATOR_OPERATIONS DmabufAllocatorOperations =
+{
+ .Attach = _DmabufAttach,
+ .Free = _DmabufFree,
+ .MapUser = _DmabufMapUser,
+ .UnmapUser = _DmabufUnmapUser,
+ .MapKernel = _DmabufMapKernel,
+ .UnmapKernel = _DmabufUnmapKernel,
+ .Cache = _DmabufCache,
+ .Physical = _DmabufPhysical,
+};
+
+static void
+_DmabufAllocatorDestructor(
+ gcsALLOCATOR *Allocator
+ )
+{
+ _DebugfsCleanup(Allocator);
+
+ if (Allocator->privateData)
+ {
+ kfree(Allocator->privateData);
+ }
+
+ kfree(Allocator);
+}
+
+/* Default allocator entry. */
+gceSTATUS
+_DmabufAlloctorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ )
+{
+ gceSTATUS status;
+ gckALLOCATOR allocator;
+ struct allocator_priv *priv = NULL;
+
+ priv = kmalloc(sizeof (struct allocator_priv), GFP_KERNEL | gcdNOWARN);
+
+ if (!priv)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ mutex_init(&priv->lock);
+ INIT_LIST_HEAD(&priv->buf_list);
+
+ gcmkONERROR(
+ gckALLOCATOR_Construct(Os, &DmabufAllocatorOperations, &allocator));
+
+ allocator->capability = gcvALLOC_FLAG_DMABUF
+ | gcvALLOC_FLAG_DMABUF_EXPORTABLE
+ ;
+
+ /* Register private data. */
+ allocator->privateData = priv;
+ allocator->destructor = _DmabufAllocatorDestructor;
+
+ _DebugfsInit(allocator, Parent);
+
+ *Allocator = allocator;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ if (priv)
+ {
+ kfree(priv);
+ }
+
+ return status;
+}
+
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_gfp.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_gfp.c
new file mode 100644
index 000000000000..20a163393e34
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_gfp.c
@@ -0,0 +1,1006 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_allocator.h"
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <asm/atomic.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+
+#include "gc_hal_kernel_platform.h"
+
+#define _GC_OBJ_ZONE gcvZONE_OS
+
+#define gcdDISCRETE_PAGES 0
+
+struct gfp_priv
+{
+ atomic_t low;
+ atomic_t high;
+};
+
+struct gfp_mdl_priv
+{
+ union
+ {
+ /* Pointer to a array of pages. */
+ struct page * contiguousPages;
+ /* Pointer to a array of pointers to page. */
+ struct page ** nonContiguousPages;
+ };
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ gctBOOL exact;
+#endif
+
+ gctBOOL cacheable;
+
+ gcsPLATFORM * platform;
+
+ gctBOOL contiguous;
+};
+
+/******************************************************************************\
+************************** GFP Allocator Debugfs ***************************
+\******************************************************************************/
+
+static int gc_usage_show(struct seq_file* m, void* data)
+{
+ gcsINFO_NODE *node = m->private;
+ gckALLOCATOR Allocator = node->device;
+ struct gfp_priv *priv = Allocator->privateData;
+ long long low = (long long)atomic_read(&priv->low);
+ long long high = (long long)atomic_read(&priv->high);
+
+ seq_printf(m, "type n pages bytes\n");
+ seq_printf(m, "normal %10llu %12llu\n", low, low * PAGE_SIZE);
+ seq_printf(m, "HighMem %10llu %12llu\n", high, high * PAGE_SIZE);
+
+ return 0;
+}
+
+static gcsINFO InfoList[] =
+{
+ {"usage", gc_usage_show},
+};
+
+static void
+_GFPAllocatorDebugfsInit(
+ IN gckALLOCATOR Allocator,
+ IN gckDEBUGFS_DIR Root
+ )
+{
+ gcmkVERIFY_OK(
+ gckDEBUGFS_DIR_Init(&Allocator->debugfsDir, Root->root, "gfp"));
+
+ gcmkVERIFY_OK(gckDEBUGFS_DIR_CreateFiles(
+ &Allocator->debugfsDir,
+ InfoList,
+ gcmCOUNTOF(InfoList),
+ Allocator
+ ));
+}
+
+static void
+_GFPAllocatorDebugfsCleanup(
+ IN gckALLOCATOR Allocator
+ )
+{
+ gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(
+ &Allocator->debugfsDir,
+ InfoList,
+ gcmCOUNTOF(InfoList)
+ ));
+
+ gckDEBUGFS_DIR_Deinit(&Allocator->debugfsDir);
+}
+
+static void
+_NonContiguousFree(
+ IN struct page ** Pages,
+ IN gctUINT32 NumPages
+ )
+{
+ gctINT i;
+
+ gcmkHEADER_ARG("Pages=%p, NumPages=%u", Pages, NumPages);
+
+ gcmkASSERT(Pages != gcvNULL);
+
+ for (i = 0; i < NumPages; i++)
+ {
+ __free_page(Pages[i]);
+ }
+
+ if (is_vmalloc_addr(Pages))
+ {
+ vfree(Pages);
+ }
+ else
+ {
+ kfree(Pages);
+ }
+
+ gcmkFOOTER_NO();
+}
+
+static struct page **
+_NonContiguousAlloc(
+ IN gctUINT32 NumPages
+ )
+{
+ struct page ** pages;
+ struct page *p;
+#if gcdDISCRETE_PAGES
+ struct page *l;
+#endif
+ gctINT i, size;
+
+ gcmkHEADER_ARG("NumPages=%u", NumPages);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
+ if (NumPages > totalram_pages)
+#else
+ if (NumPages > num_physpages)
+#endif
+ {
+ gcmkFOOTER_NO();
+ return gcvNULL;
+ }
+
+ size = NumPages * sizeof(struct page *);
+
+ pages = kmalloc(size, GFP_KERNEL | gcdNOWARN);
+
+ if (!pages)
+ {
+ pages = vmalloc(size);
+
+ if (!pages)
+ {
+ gcmkFOOTER_NO();
+ return gcvNULL;
+ }
+ }
+
+ for (i = 0; i < NumPages; i++)
+ {
+ p = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | gcdNOWARN);
+
+ if (!p)
+ {
+ _NonContiguousFree(pages, i);
+ gcmkFOOTER_NO();
+ return gcvNULL;
+ }
+
+#if gcdDISCRETE_PAGES
+ if (i != 0)
+ {
+ if (page_to_pfn(pages[i-1]) == page_to_pfn(p)-1)
+ {
+ /* Replaced page. */
+ l = p;
+
+ /* Allocate a page which is not contiguous to previous one. */
+ p = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN);
+
+ /* Give replaced page back. */
+ __free_page(l);
+
+ if (!p)
+ {
+ _NonContiguousFree(pages, i);
+ gcmkFOOTER_NO();
+ return gcvNULL;
+ }
+ }
+ }
+#endif
+
+ pages[i] = p;
+ }
+
+ gcmkFOOTER_ARG("pages=0x%X", pages);
+ return pages;
+}
+
+/***************************************************************************\
+************************ GFP Allocator **********************************
+\***************************************************************************/
+static gceSTATUS
+_GFPAlloc(
+ IN gckALLOCATOR Allocator,
+ INOUT PLINUX_MDL Mdl,
+ IN gctSIZE_T NumPages,
+ IN gctUINT32 Flags
+ )
+{
+ gceSTATUS status;
+ gctUINT i;
+ gctBOOL contiguous = Flags & gcvALLOC_FLAG_CONTIGUOUS;
+#ifdef gcdSYS_FREE_MEMORY_LIMIT
+ struct sysinfo temsysinfo;
+#endif
+
+ struct gfp_priv *priv = (struct gfp_priv *)Allocator->privateData;
+ struct gfp_mdl_priv *mdlPriv = gcvNULL;
+ int low = 0;
+ int high = 0;
+
+ gcmkHEADER_ARG("Allocator=%p Mdl=%p NumPages=%zu Flags=0x%x", Allocator, Mdl, NumPages, Flags);
+
+#ifdef gcdSYS_FREE_MEMORY_LIMIT
+ si_meminfo(&temsysinfo);
+
+ if (Flags & gcvALLOC_FLAG_MEMLIMIT)
+ {
+ if ( (temsysinfo.freeram < NumPages) || ((temsysinfo.freeram-NumPages) < gcdSYS_FREE_MEMORY_LIMIT) )
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+ }
+#endif
+
+ gcmkONERROR(gckOS_Allocate(Allocator->os, sizeof(struct gfp_mdl_priv), (gctPOINTER *)&mdlPriv));
+
+ memset(mdlPriv, 0, sizeof(struct gfp_mdl_priv));
+
+ if (contiguous)
+ {
+ size_t bytes = NumPages << PAGE_SHIFT;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ void *addr = NULL;
+
+ addr = alloc_pages_exact(bytes, GFP_KERNEL | gcdNOWARN | __GFP_NORETRY);
+
+ mdlPriv->contiguousPages = addr ? virt_to_page(addr) : gcvNULL;
+
+ mdlPriv->exact = gcvTRUE;
+#endif
+
+ if (mdlPriv->contiguousPages == gcvNULL)
+ {
+ int order = get_order(bytes);
+
+ if (order >= MAX_ORDER)
+ {
+ status = gcvSTATUS_OUT_OF_MEMORY;
+ goto OnError;
+ }
+
+ mdlPriv->contiguousPages =
+ alloc_pages(GFP_KERNEL | __GFP_HIGHMEM | gcdNOWARN, order);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ mdlPriv->exact = gcvFALSE;
+#endif
+ }
+
+ if (mdlPriv->contiguousPages == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+#if defined(CONFIG_X86)
+ if (!PageHighMem(mdlPriv->contiguousPages))
+ {
+ if (set_memory_wc((unsigned long)page_address(mdlPriv->contiguousPages), NumPages) != 0)
+ {
+ printk("%s(%d): failed to set_memory_wc\n", __func__, __LINE__);
+ }
+ }
+#endif
+ }
+ else
+ {
+ mdlPriv->nonContiguousPages = _NonContiguousAlloc(NumPages);
+
+ if (mdlPriv->nonContiguousPages == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+#if defined(CONFIG_X86)
+ if (set_pages_array_wc(mdlPriv->nonContiguousPages, NumPages))
+ {
+ printk("%s(%d): failed to set_pages_array_wc\n", __func__, __LINE__);
+ }
+#endif
+ }
+
+ for (i = 0; i < NumPages; i++)
+ {
+ struct page *page;
+ gctPHYS_ADDR_T phys = 0U;
+
+ if (contiguous)
+ {
+ page = nth_page(mdlPriv->contiguousPages, i);
+ }
+ else
+ {
+ page = mdlPriv->nonContiguousPages[i];
+ }
+
+ SetPageReserved(page);
+
+ phys = page_to_phys(page);
+
+ BUG_ON(!phys);
+
+ if (PageHighMem(page))
+ {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+ void *vaddr = kmap_atomic(page);
+#else
+ void *vaddr = kmap_atomic(page, KM_USER0);
+#endif
+
+ gcmkVERIFY_OK(gckOS_CacheFlush(
+ Allocator->os, _GetProcessID(), gcvNULL, phys, vaddr, PAGE_SIZE
+ ));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
+ kunmap_atomic(vaddr);
+#else
+ kunmap_atomic(vaddr, KM_USER0);
+#endif
+ high++;
+ }
+ else
+ {
+ gcmkVERIFY_OK(gckOS_CacheFlush(
+ Allocator->os, _GetProcessID(), gcvNULL, phys, page_address(page), PAGE_SIZE
+ ));
+ low++;
+ }
+ }
+
+ mdlPriv->platform = Allocator->os->device->platform;
+ mdlPriv->contiguous = contiguous;
+ atomic_add(low, &priv->low);
+ atomic_add(high, &priv->high);
+
+ Mdl->priv = mdlPriv;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (mdlPriv)
+ {
+ gcmkOS_SAFE_FREE(Allocator->os, mdlPriv);
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+_GFPGetSGT(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctSIZE_T Offset,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER *SGT
+ )
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
+ struct page ** pages = gcvNULL;
+ struct page ** tmpPages = gcvNULL;
+ struct sg_table *sgt = NULL;
+ struct gfp_mdl_priv *mdlPriv = (struct gfp_mdl_priv*)Mdl->priv;
+
+ gceSTATUS status = gcvSTATUS_OK;
+ gctSIZE_T offset = Offset & ~PAGE_MASK; /* Offset to the first page */
+ gctINT skipPages = Offset >> PAGE_SHIFT; /* skipped pages */
+ gctINT numPages = (PAGE_ALIGN(Offset + Bytes) >> PAGE_SHIFT) - skipPages;
+ gctINT i;
+
+ gcmkASSERT(Offset + Bytes <= Mdl->numPages << PAGE_SHIFT);
+
+ if (Mdl->contiguous)
+ {
+ pages = tmpPages = kmalloc(sizeof(struct page*) * numPages, GFP_KERNEL | gcdNOWARN);
+ if (!pages)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ for (i = 0; i < numPages; ++i)
+ {
+ pages[i] = nth_page(mdlPriv->contiguousPages, i + skipPages);
+ }
+ }
+ else
+ {
+ pages = &mdlPriv->nonContiguousPages[skipPages];
+ }
+
+ sgt = kmalloc(sizeof(struct sg_table), GFP_KERNEL | gcdNOWARN);
+ if (!sgt)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ if (sg_alloc_table_from_pages(sgt, pages, numPages, offset, Bytes, GFP_KERNEL) < 0)
+ {
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+ *SGT = (gctPOINTER)sgt;
+
+OnError:
+ if (tmpPages)
+ {
+ kfree(tmpPages);
+ }
+
+ if (gcmIS_ERROR(status) && sgt)
+ {
+ kfree(sgt);
+ }
+
+ return status;
+#else
+ return gcvSTATUS_NOT_SUPPORTED;
+#endif
+}
+
+static void
+_GFPFree(
+ IN gckALLOCATOR Allocator,
+ IN OUT PLINUX_MDL Mdl
+ )
+{
+ gctINT i;
+ struct page * page;
+ struct gfp_priv *priv = (struct gfp_priv *)Allocator->privateData;
+ struct gfp_mdl_priv *mdlPriv = Mdl->priv;
+ int low = 0;
+ int high = 0;
+
+ for (i = 0; i < Mdl->numPages; i++)
+ {
+ if (Mdl->contiguous)
+ {
+ page = nth_page(mdlPriv->contiguousPages, i);
+ }
+ else
+ {
+ page = mdlPriv->nonContiguousPages[i];
+ }
+
+ ClearPageReserved(page);
+
+ if (PageHighMem(page))
+ {
+ high++;
+ }
+ else
+ {
+ low++;
+ }
+ }
+
+ atomic_sub(low, &priv->low);
+ atomic_sub(high, &priv->high);
+
+ if (Mdl->contiguous)
+ {
+#if defined(CONFIG_X86)
+ if (!PageHighMem(mdlPriv->contiguousPages))
+ {
+ set_memory_wb((unsigned long)page_address(mdlPriv->contiguousPages), Mdl->numPages);
+ }
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ if (mdlPriv->exact == gcvTRUE)
+ {
+ free_pages_exact(page_address(mdlPriv->contiguousPages), Mdl->numPages * PAGE_SIZE);
+ }
+ else
+#endif
+ {
+ __free_pages(mdlPriv->contiguousPages, get_order(Mdl->numPages * PAGE_SIZE));
+ }
+ }
+ else
+ {
+#if defined(CONFIG_X86)
+ set_pages_array_wb(mdlPriv->nonContiguousPages, Mdl->numPages);
+#endif
+
+ _NonContiguousFree(mdlPriv->nonContiguousPages, Mdl->numPages);
+ }
+
+ gcmkOS_SAFE_FREE(Allocator->os, Mdl->priv);
+}
+
+static gceSTATUS
+_GFPMmap(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctSIZE_T skipPages,
+ IN gctSIZE_T numPages,
+ INOUT struct vm_area_struct *vma
+ )
+{
+ struct gfp_mdl_priv *mdlPriv = (struct gfp_mdl_priv*)Mdl->priv;
+ gcsPLATFORM *platform = mdlPriv->platform;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ gcmkHEADER_ARG("Allocator=%p Mdl=%p vma=%p", Allocator, Mdl, vma);
+
+ vma->vm_flags |= gcdVM_FLAGS;
+ if (mdlPriv->cacheable == gcvFALSE)
+ {
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ }
+
+ if (platform && platform->ops->adjustProt)
+ {
+ platform->ops->adjustProt(vma);
+ }
+
+ gcmkASSERT(skipPages + numPages <= Mdl->numPages);
+
+ /* Now map all the vmalloc pages to this user address. */
+ if (mdlPriv->contiguous)
+ {
+ /* map kernel memory to user space.. */
+ if (remap_pfn_range(vma,
+ vma->vm_start,
+ page_to_pfn(mdlPriv->contiguousPages) + skipPages,
+ numPages << PAGE_SHIFT,
+ vma->vm_page_prot) < 0)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): remap_pfn_range error.",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+ }
+ else
+ {
+ gctUINT i;
+ unsigned long start = vma->vm_start;
+
+ for (i = 0; i < numPages; ++i)
+ {
+ unsigned long pfn = page_to_pfn(mdlPriv->nonContiguousPages[i + skipPages]);
+
+ if (remap_pfn_range(vma,
+ start,
+ pfn,
+ PAGE_SIZE,
+ vma->vm_page_prot) < 0)
+ {
+ gcmkTRACE(
+ gcvLEVEL_ERROR,
+ "%s(%d): remap_pfn_range error.",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ start += PAGE_SIZE;
+ }
+ }
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+static void
+_GFPUnmapUser(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Size
+ )
+{
+ struct gfp_mdl_priv *mdlPriv = (struct gfp_mdl_priv*)Mdl->priv;
+
+ mdlPriv->cacheable = gcvFALSE;
+
+ if (unlikely(current->mm == gcvNULL))
+ {
+ /* Do nothing if process is exiting. */
+ return;
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+ if (vm_munmap((unsigned long)Logical, Size) < 0)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_WARNING, gcvZONE_OS,
+ "%s(%d): vm_munmap failed",
+ __FUNCTION__, __LINE__
+ );
+ }
+#else
+ down_write(&current->mm->mmap_sem);
+ if (do_munmap(current->mm, (unsigned long)Logical, Size) < 0)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_WARNING, gcvZONE_OS,
+ "%s(%d): do_munmap failed",
+ __FUNCTION__, __LINE__
+ );
+ }
+ up_write(&current->mm->mmap_sem);
+#endif
+}
+
+static gceSTATUS
+_GFPMapUser(
+ gckALLOCATOR Allocator,
+ PLINUX_MDL Mdl,
+ gctBOOL Cacheable,
+ OUT gctPOINTER * UserLogical
+ )
+{
+ gctPOINTER userLogical = gcvNULL;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ gcmkHEADER_ARG("Allocator=%p Mdl=%p Cacheable=%d", Allocator, Mdl, Cacheable);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ userLogical = (gctPOINTER)vm_mmap(NULL,
+ 0L,
+ Mdl->numPages * PAGE_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_NORESERVE,
+ 0);
+#else
+ down_write(&current->mm->mmap_sem);
+ userLogical = (gctPOINTER)do_mmap_pgoff(NULL,
+ 0L,
+ Mdl->numPages * PAGE_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ 0);
+ up_write(&current->mm->mmap_sem);
+#endif
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): vmaAddr->%p for phys_addr->%p",
+ __FUNCTION__, __LINE__,
+ userLogical,
+ Mdl
+ );
+
+ if (IS_ERR(userLogical))
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): do_mmap_pgoff error",
+ __FUNCTION__, __LINE__
+ );
+
+ userLogical = gcvNULL;
+
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ down_write(&current->mm->mmap_sem);
+ do
+ {
+ struct gfp_mdl_priv *mdlPriv = (struct gfp_mdl_priv*)Mdl->priv;
+ struct vm_area_struct *vma = find_vma(current->mm, (unsigned long)userLogical);
+
+ if (vma == gcvNULL)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): find_vma error",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkERR_BREAK(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ /* mdlPriv->cacheable must be used under protection of mdl->mapMutex. */
+ mdlPriv->cacheable = Cacheable;
+ gcmkERR_BREAK(_GFPMmap(Allocator, Mdl, 0, Mdl->numPages, vma));
+ }
+ while (gcvFALSE);
+ up_write(&current->mm->mmap_sem);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ gcmkONERROR(gckOS_CacheFlush(
+ Allocator->os,
+ _GetProcessID(),
+ Mdl,
+ gcvINVALID_ADDRESS,
+ userLogical,
+ Mdl->numPages * PAGE_SIZE
+ ));
+
+ *UserLogical = userLogical;
+ }
+
+OnError:
+ if (gcmIS_ERROR(status) && userLogical)
+ {
+ _GFPUnmapUser(Allocator, Mdl, userLogical, Mdl->numPages * PAGE_SIZE);
+ }
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+_GFPMapKernel(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ OUT gctPOINTER *Logical
+ )
+{
+ void *addr = 0;
+ gctINT numPages = Mdl->numPages;
+ struct gfp_mdl_priv *mdlPriv = Mdl->priv;
+
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ if (Mdl->contiguous)
+ {
+ addr = page_address(mdlPriv->contiguousPages);
+ }
+ else
+ {
+ addr = vmap(mdlPriv->nonContiguousPages,
+ numPages,
+ 0,
+ PAGE_KERNEL);
+
+ /* Trigger a page fault. */
+ memset(addr, 0, numPages * PAGE_SIZE);
+ }
+#else
+ struct page ** pages;
+ gctBOOL free = gcvFALSE;
+ gctINT i;
+
+ if (Mdl->contiguous)
+ {
+ pages = kmalloc(sizeof(struct page *) * numPages, GFP_KERNEL | gcdNOWARN);
+
+ if (!pages)
+ {
+ return gcvSTATUS_OUT_OF_MEMORY;
+ }
+
+ for (i = 0; i < numPages; i++)
+ {
+ pages[i] = nth_page(mdlPriv->contiguousPages, i);
+ }
+
+ free = gcvTRUE;
+ }
+ else
+ {
+ pages = mdlPriv->nonContiguousPages;
+ }
+
+ addr = vmap(pages, numPages, 0, pgprot_writecombine(PAGE_KERNEL));
+
+ if (free)
+ {
+ kfree(pages);
+ }
+#endif
+
+ if (addr)
+ {
+ *Logical = addr;
+ return gcvSTATUS_OK;
+ }
+ else
+ {
+ return gcvSTATUS_OUT_OF_MEMORY;
+ }
+}
+
+static gceSTATUS
+_GFPUnmapKernel(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical
+ )
+{
+
+#if !gcdNONPAGED_MEMORY_CACHEABLE
+ vunmap(Logical);
+#endif
+
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_GFPCache(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Physical,
+ IN gctUINT32 Bytes,
+ IN gceCACHEOPERATION Operation
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_GFPPhysical(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctUINT32 Offset,
+ OUT gctPHYS_ADDR_T * Physical
+ )
+{
+ struct gfp_mdl_priv *mdlPriv = Mdl->priv;
+ gctUINT32 offsetInPage = Offset & ~PAGE_MASK;
+ gctUINT32 index = Offset / PAGE_SIZE;
+
+ if (Mdl->contiguous)
+ {
+ *Physical = page_to_phys(nth_page(mdlPriv->contiguousPages, index));
+ }
+ else
+ {
+ *Physical = page_to_phys(mdlPriv->nonContiguousPages[index]);
+ }
+
+ *Physical += offsetInPage;
+
+ return gcvSTATUS_OK;
+}
+
+static void
+_GFPAllocatorDestructor(
+ gcsALLOCATOR *Allocator
+ )
+{
+ _GFPAllocatorDebugfsCleanup(Allocator);
+
+ if (Allocator->privateData)
+ {
+ kfree(Allocator->privateData);
+ }
+
+ kfree(Allocator);
+}
+
+/* GFP allocator operations. */
+static gcsALLOCATOR_OPERATIONS GFPAllocatorOperations = {
+ .Alloc = _GFPAlloc,
+ .Free = _GFPFree,
+ .Mmap = _GFPMmap,
+ .MapUser = _GFPMapUser,
+ .UnmapUser = _GFPUnmapUser,
+ .MapKernel = _GFPMapKernel,
+ .UnmapKernel = _GFPUnmapKernel,
+ .Cache = _GFPCache,
+ .Physical = _GFPPhysical,
+ .GetSGT = _GFPGetSGT,
+};
+
+/* GFP allocator entry. */
+gceSTATUS
+_GFPAlloctorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ )
+{
+ gceSTATUS status;
+ gckALLOCATOR allocator = gcvNULL;
+ struct gfp_priv *priv = gcvNULL;
+
+ gcmkONERROR(
+ gckALLOCATOR_Construct(Os, &GFPAllocatorOperations, &allocator));
+
+ priv = kzalloc(sizeof(struct gfp_priv), GFP_KERNEL | gcdNOWARN);
+
+ if (!priv)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ atomic_set(&priv->low, 0);
+ atomic_set(&priv->high, 0);
+
+ /* Register private data. */
+ allocator->privateData = priv;
+ allocator->destructor = _GFPAllocatorDestructor;
+
+ _GFPAllocatorDebugfsInit(allocator, Parent);
+
+ allocator->capability = gcvALLOC_FLAG_CONTIGUOUS
+ | gcvALLOC_FLAG_NON_CONTIGUOUS
+ | gcvALLOC_FLAG_CACHEABLE
+ | gcvALLOC_FLAG_MEMLIMIT
+ | gcvALLOC_FLAG_ALLOC_ON_FAULT
+ | gcvALLOC_FLAG_DMABUF_EXPORTABLE
+ ;
+
+#if defined(gcdEMULATE_SECURE_ALLOCATOR)
+ allocator->capability |= gcvALLOC_FLAG_SECURITY;
+#endif
+
+ *Allocator = allocator;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ if (allocator)
+ {
+ kfree(allocator);
+ }
+ return status;
+}
+
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_reserved_mem.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_reserved_mem.c
new file mode 100644
index 000000000000..52518c12a2a8
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_reserved_mem.c
@@ -0,0 +1,494 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_allocator.h"
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <asm/atomic.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+
+#define _GC_OBJ_ZONE gcvZONE_OS
+
+/*
+ * reserved_mem is for contiguous pool, internal pool and external pool, etc.
+ */
+
+/* mdl private. */
+struct reserved_mem
+{
+ unsigned long start;
+ unsigned long size;
+ char name[32];
+ int release;
+
+ /* Link together. */
+ struct list_head link;
+};
+
+/* allocator info. */
+struct reserved_mem_alloc
+{
+ /* Record allocated reserved memory regions. */
+ struct list_head region;
+ struct mutex lock;
+};
+
+static int reserved_mem_show(struct seq_file* m, void* data)
+{
+ struct list_head *pos;
+ gcsINFO_NODE *node = m->private;
+ gckALLOCATOR Allocator = node->device;
+ struct reserved_mem_alloc *alloc = Allocator->privateData;
+
+ list_for_each(pos, &alloc->region)
+ {
+ struct reserved_mem * res= list_entry(pos, struct reserved_mem, link);
+
+ seq_printf(m, "0x%08lx-0x%08lx : %s\n",
+ res->start, res->start + res->size -1, res->name);
+ }
+
+ return 0;
+}
+
+static gcsINFO info_list[] =
+{
+ {"reserved-mem", reserved_mem_show},
+};
+
+static void
+reserved_mem_debugfs_init(
+ IN gckALLOCATOR Allocator,
+ IN gckDEBUGFS_DIR Root
+ )
+{
+ gcmkVERIFY_OK(
+ gckDEBUGFS_DIR_Init(&Allocator->debugfsDir, Root->root, "reserved-mem"));
+
+ gcmkVERIFY_OK(gckDEBUGFS_DIR_CreateFiles(
+ &Allocator->debugfsDir,
+ info_list,
+ gcmCOUNTOF(info_list),
+ Allocator
+ ));
+}
+
+static void
+reserved_mem_debugfs_cleanup(
+ IN gckALLOCATOR Allocator
+ )
+{
+ gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(
+ &Allocator->debugfsDir,
+ info_list,
+ gcmCOUNTOF(info_list)
+ ));
+
+ gckDEBUGFS_DIR_Deinit(&Allocator->debugfsDir);
+}
+
+static gceSTATUS
+reserved_mem_attach(
+ IN gckALLOCATOR Allocator,
+ IN gcsATTACH_DESC_PTR Desc,
+ IN PLINUX_MDL Mdl
+ )
+{
+ struct reserved_mem_alloc *alloc = Allocator->privateData;
+ struct reserved_mem *res;
+ struct resource *region = NULL;
+
+ res = kzalloc(sizeof(struct reserved_mem), GFP_KERNEL | gcdNOWARN);
+
+ if (!res)
+ return gcvSTATUS_OUT_OF_MEMORY;
+
+ res->start = Desc->reservedMem.start;
+ res->size = Desc->reservedMem.size;
+ strncpy(res->name, Desc->reservedMem.name, sizeof(res->name)-1);
+ res->release = 1;
+
+ if (!Desc->reservedMem.requested)
+ {
+ region = request_mem_region(res->start, res->size, res->name);
+
+ if (!region)
+ {
+ printk("request mem %s(0x%lx - 0x%lx) failed\n",
+ res->name, res->start, res->start + res->size - 1);
+
+ kfree(res);
+ return gcvSTATUS_OUT_OF_RESOURCES;
+ }
+
+ res->release = 1;
+ }
+
+ mutex_lock(&alloc->lock);
+ list_add(&res->link, &alloc->region);
+ mutex_unlock(&alloc->lock);
+
+ Mdl->priv = res;
+
+ return gcvSTATUS_OK;
+}
+
+static void
+reserved_mem_detach(
+ IN gckALLOCATOR Allocator,
+ IN OUT PLINUX_MDL Mdl
+ )
+{
+ struct reserved_mem_alloc *alloc = Allocator->privateData;
+ struct reserved_mem *res = Mdl->priv;
+
+ /* unlink from region list. */
+ mutex_lock(&alloc->lock);
+ list_del_init(&res->link);
+ mutex_unlock(&alloc->lock);
+
+ if (res->release)
+ {
+ release_mem_region(res->start, res->size);
+ }
+
+ kfree(res);
+}
+
+static gceSTATUS
+reserved_mem_mmap(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctSIZE_T skipPages,
+ IN gctSIZE_T numPages,
+ INOUT struct vm_area_struct *vma
+ )
+{
+ struct reserved_mem *res = (struct reserved_mem*)Mdl->priv;
+ unsigned long pfn;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ gcmkHEADER_ARG("Allocator=%p Mdl=%p vma=%p", Allocator, Mdl, vma);
+
+ gcmkASSERT(skipPages + numPages <= Mdl->numPages);
+
+ pfn = (res->start >> PAGE_SHIFT) + skipPages;
+
+ /* Make this mapping non-cached. */
+ vma->vm_flags |= gcdVM_FLAGS;
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ if (remap_pfn_range(vma, vma->vm_start,
+ pfn, numPages << PAGE_SHIFT, vma->vm_page_prot) < 0)
+ {
+ gcmkTRACE(
+ gcvLEVEL_ERROR,
+ "%s(%d): remap_pfn_range error.",
+ __FUNCTION__, __LINE__
+ );
+
+ status = gcvSTATUS_OUT_OF_MEMORY;
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+static void
+reserved_mem_unmap_user(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Size
+ )
+{
+ if (unlikely(!current->mm))
+ return;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+ if (vm_munmap((unsigned long)Logical, (unsigned long)Size) < 0)
+ {
+ printk("%s: vm_munmap failed\n", __func__);
+ }
+#else
+ down_write(&current->mm->mmap_sem);
+ if (do_munmap(current->mm, (unsigned long)Logical, (unsigned long)Size) < 0)
+ {
+ printk("%s: do_munmap failed\n", __func__);
+ }
+ up_write(&current->mm->mmap_sem);
+#endif
+}
+
+static gceSTATUS
+reserved_mem_map_user(
+ gckALLOCATOR Allocator,
+ PLINUX_MDL Mdl,
+ gctBOOL Cacheable,
+ OUT gctPOINTER *UserLogical
+ )
+{
+ struct reserved_mem *res = (struct reserved_mem*)Mdl->priv;
+ gctPOINTER userLogical = gcvNULL;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ gcmkHEADER_ARG("Allocator=%p Mdl=%p Cacheable=%d", Allocator, Mdl, Cacheable);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ userLogical = (gctPOINTER)vm_mmap(NULL, 0L, res->size,
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, 0);
+#else
+ down_write(&current->mm->mmap_sem);
+ userLogical = (gctPOINTER)do_mmap_pgoff(NULL, 0L, res->size,
+ PROT_READ | PROT_WRITE, MAP_SHARED, 0);
+ up_write(&current->mm->mmap_sem);
+#endif
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): vmaAddr->%p for phys_addr->%p",
+ __FUNCTION__, __LINE__, userLogical, Mdl
+ );
+
+ if (IS_ERR(userLogical))
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): do_mmap_pgoff error",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ down_write(&current->mm->mmap_sem);
+ do
+ {
+ struct vm_area_struct *vma = find_vma(current->mm, (unsigned long)userLogical);
+ if (vma == gcvNULL)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): find_vma error",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkERR_BREAK(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ gcmkERR_BREAK(reserved_mem_mmap(Allocator, Mdl, 0, Mdl->numPages, vma));
+
+ *UserLogical = userLogical;
+ }
+ while (gcvFALSE);
+ up_write(&current->mm->mmap_sem);
+
+OnError:
+ if (gcmIS_ERROR(status) && userLogical)
+ {
+ reserved_mem_unmap_user(Allocator, Mdl, userLogical, res->size);
+ }
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+reserved_mem_map_kernel(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ OUT gctPOINTER *Logical
+ )
+{
+ struct reserved_mem *res = Mdl->priv;
+ void *vaddr;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0)
+ vaddr = memremap(res->start, res->size, MEMREMAP_WC);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0)
+ vaddr = memremap(res->start, res->size, MEMREMAP_WT);
+#else
+ vaddr = ioremap_nocache(res->start, res->size);
+#endif
+
+ if (!vaddr)
+ {
+ return gcvSTATUS_OUT_OF_MEMORY;
+ }
+
+ *Logical = vaddr;
+ return gcvSTATUS_OK;;
+}
+
+static gceSTATUS
+reserved_mem_unmap_kernel(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical
+ )
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0)
+ memunmap((void *)Logical);
+#else
+ iounmap((void *)Logical);
+#endif
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+reserved_mem_cache_op(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Physical,
+ IN gctUINT32 Bytes,
+ IN gceCACHEOPERATION Operation
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+reserved_mem_get_physical(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctUINT32 Offset,
+ OUT gctPHYS_ADDR_T * Physical
+ )
+{
+ struct reserved_mem *res = Mdl->priv;
+ *Physical = res->start + Offset;
+
+ return gcvSTATUS_OK;
+}
+
+static void
+reserved_mem_dtor(
+ gcsALLOCATOR *Allocator
+ )
+{
+ reserved_mem_debugfs_cleanup(Allocator);
+
+ if (Allocator->privateData)
+ {
+ kfree(Allocator->privateData);
+ }
+
+ kfree(Allocator);
+}
+
+/* GFP allocator operations. */
+static gcsALLOCATOR_OPERATIONS reserved_mem_ops = {
+ .Alloc = NULL,
+ .Attach = reserved_mem_attach,
+ .Free = reserved_mem_detach,
+ .Mmap = reserved_mem_mmap,
+ .MapUser = reserved_mem_map_user,
+ .UnmapUser = reserved_mem_unmap_user,
+ .MapKernel = reserved_mem_map_kernel,
+ .UnmapKernel = reserved_mem_unmap_kernel,
+ .Cache = reserved_mem_cache_op,
+ .Physical = reserved_mem_get_physical,
+};
+
+/* GFP allocator entry. */
+gceSTATUS
+_ReservedMemoryAllocatorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ )
+{
+ gceSTATUS status;
+ gckALLOCATOR allocator = gcvNULL;
+ struct reserved_mem_alloc *alloc = NULL;
+
+ gcmkONERROR(
+ gckALLOCATOR_Construct(Os, &reserved_mem_ops, &allocator));
+
+ alloc = kzalloc(sizeof(*alloc), GFP_KERNEL | gcdNOWARN);
+
+ if (!alloc)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ INIT_LIST_HEAD(&alloc->region);
+ mutex_init(&alloc->lock);
+
+ /* Register private data. */
+ allocator->privateData = alloc;
+ allocator->destructor = reserved_mem_dtor;
+
+ reserved_mem_debugfs_init(allocator, Parent);
+
+ allocator->capability = gcvALLOC_FLAG_LINUX_RESERVED_MEM;
+
+ *Allocator = allocator;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ if (allocator)
+ {
+ kfree(allocator);
+ }
+ return status;
+}
+
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_user_memory.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_user_memory.c
new file mode 100644
index 000000000000..bf75718cd8a4
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/default/gc_hal_kernel_allocator_user_memory.c
@@ -0,0 +1,715 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_allocator.h"
+
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+
+#define _GC_OBJ_ZONE gcvZONE_ALLOCATOR
+
+enum um_desc_type
+{
+ UM_PHYSICAL_MAP,
+ UM_PAGE_MAP,
+ UM_PFN_MAP,
+};
+
+/* Descriptor of a user memory imported. */
+struct um_desc
+{
+ int type;
+
+ union
+ {
+ /* UM_PHYSICAL_MAP. */
+ unsigned long physical;
+
+ /* UM_PAGE_MAP. */
+ struct page **pages;
+
+ /* UM_PFN_MAP. */
+ struct
+ {
+ unsigned long *pfns;
+ int *refs;
+ };
+ };
+
+ /* contiguous chunks, does not include padding pages. */
+ int chunk_count;
+
+ unsigned long user_vaddr;
+ size_t size;
+ unsigned long offset;
+
+ size_t pageCount;
+ size_t extraPage;
+};
+
+static int import_physical_map(struct um_desc *um, unsigned long phys)
+{
+ um->type = UM_PHYSICAL_MAP;
+ um->physical = phys & PAGE_MASK;
+ um->chunk_count = 1;
+ return 0;
+}
+
+static int import_page_map(struct um_desc *um,
+ unsigned long addr, size_t page_count)
+{
+ int i;
+ int result;
+ struct page **pages;
+
+ pages = kzalloc(page_count * sizeof(void *), GFP_KERNEL | gcdNOWARN);
+ if (!pages)
+ return -ENOMEM;
+
+ down_read(&current->mm->mmap_sem);
+
+ result = get_user_pages(
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
+ current,
+ current->mm,
+#endif
+ addr & PAGE_MASK,
+ page_count,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
+ FOLL_WRITE,
+#else
+ 1,
+ 0,
+#endif
+ pages,
+ NULL);
+
+ up_read(&current->mm->mmap_sem);
+
+ if (result < page_count)
+ {
+ for (i = 0; i < result; i++)
+ {
+ if (pages[i])
+ {
+ put_page(pages[i]);
+ }
+ }
+
+ kfree(pages);
+ return -ENODEV;
+ }
+
+ um->chunk_count = 1;
+ for (i = 1; i < page_count; i++)
+ {
+ if (page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1)
+ {
+ ++um->chunk_count;
+ }
+ }
+
+ um->type = UM_PAGE_MAP;
+ um->pages = pages;
+
+ return 0;
+}
+
+
+static int import_pfn_map(struct um_desc *um,
+ unsigned long addr, size_t pfn_count)
+{
+ int i;
+ struct vm_area_struct *vma;
+ unsigned long *pfns;
+ int *refs;
+
+ if (!current->mm)
+ return -ENOTTY;
+
+ down_read(&current->mm->mmap_sem);
+ vma = find_vma(current->mm, addr);
+ up_read(&current->mm->mmap_sem);
+
+ if (!vma)
+ return -ENOTTY;
+
+ pfns = kzalloc(pfn_count * sizeof(unsigned long), GFP_KERNEL | gcdNOWARN);
+
+ if (!pfns)
+ return -ENOMEM;
+
+ refs = kzalloc(pfn_count * sizeof(int), GFP_KERNEL | gcdNOWARN);
+
+ if (!refs)
+ {
+ kfree(pfns);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < pfn_count; i++)
+ {
+ spinlock_t *ptl;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ pgd = pgd_offset(current->mm, addr);
+ if (pgd_none(*pgd) || pgd_bad(*pgd))
+ goto err;
+
+ pud = pud_offset(pgd, addr);
+ if (pud_none(*pud) || pud_bad(*pud))
+ goto err;
+
+ pmd = pmd_offset(pud, addr);
+ if (pmd_none(*pmd) || pmd_bad(*pmd))
+ goto err;
+
+ pte = pte_offset_map_lock(current->mm, pmd, addr, &ptl);
+ if (!pte)
+ {
+ spin_unlock(ptl);
+ goto err;
+ }
+
+ if (!pte_present(*pte))
+ {
+ pte_unmap_unlock(pte, ptl);
+ goto err;
+ }
+
+ pfns[i] = pte_pfn(*pte);
+ pte_unmap_unlock(pte, ptl);
+
+ /* Advance to next. */
+ addr += PAGE_SIZE;
+ }
+
+ for (i = 0; i < pfn_count; i++)
+ {
+ if (pfn_valid(pfns[i]))
+ {
+ struct page *page = pfn_to_page(pfns[i]);
+ refs[i] = get_page_unless_zero(page);
+ }
+ }
+
+ um->chunk_count = 1;
+ for (i = 1; i < pfn_count; i++)
+ {
+ if (pfns[i] != pfns[i - 1] + 1)
+ {
+ ++um->chunk_count;
+ }
+ }
+
+ um->type = UM_PFN_MAP;
+ um->pfns = pfns;
+ um->refs = refs;
+ return 0;
+
+err:
+ if (pfns)
+ kfree(pfns);
+
+ if (refs)
+ kfree(refs);
+
+ return -ENOTTY;
+}
+
+static gceSTATUS
+_Import(
+ IN gckOS Os,
+ IN gctPOINTER Memory,
+ IN gctUINT32 Physical,
+ IN gctSIZE_T Size,
+ IN struct um_desc * UserMemory
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+ int pfn_map = 0;
+ unsigned long start, end, memory;
+ int result = 0;
+
+ gctSIZE_T extraPage;
+ gctSIZE_T pageCount, i;
+
+ gcmkHEADER_ARG("Os=0x%p Memory=%p Physical=0x%x Size=%lu", Os, Memory, Physical, Size);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Memory != gcvNULL || Physical != ~0U);
+ gcmkVERIFY_ARGUMENT(Size > 0);
+
+ memory = (unsigned long)Memory;
+
+ /* Get the number of required pages. */
+ end = (memory + Size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ start = memory >> PAGE_SHIFT;
+ pageCount = end - start;
+
+ /* Allocate extra page to avoid cache overflow */
+#if gcdENABLE_2D
+ extraPage = 2;
+#else
+ extraPage = (((memory + gcmALIGN(Size + 64, 64) + PAGE_SIZE - 1) >> PAGE_SHIFT) > end) ? 1 : 0;
+#endif
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, _GC_OBJ_ZONE,
+ "%s(%d): pageCount: %d. extraPage: %d",
+ __FUNCTION__, __LINE__,
+ pageCount, extraPage
+ );
+
+ /* Overflow. */
+ if ((memory + Size) < memory)
+ {
+ gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT);
+ return gcvSTATUS_INVALID_ARGUMENT;
+ }
+
+ if (memory)
+ {
+ struct vm_area_struct *vma = NULL;
+ unsigned long vaddr = memory;
+
+ for (i = 0; i < pageCount; i++)
+ {
+ u32 data;
+ get_user(data, (u32 *)((memory & PAGE_MASK) + PAGE_SIZE * i));
+ put_user(data, (u32 *)((memory & PAGE_MASK) + PAGE_SIZE * i));
+ }
+
+ vma = find_vma(current->mm, vaddr);
+
+ if (!vma)
+ {
+ /* No such memory, or across vmas. */
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ pfn_map = !!(vma->vm_flags & VM_PFNMAP);
+ vaddr = vma->vm_end;
+
+ while (vaddr < memory + Size)
+ {
+ vma = find_vma(current->mm, vaddr);
+
+ if (!vma)
+ {
+ /* No such memory. */
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ if (!!(vma->vm_flags & VM_PFNMAP) != pfn_map)
+ {
+ /* Can not support different map type: both PFN and PAGE detected. */
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ vaddr = vma->vm_end;
+ }
+ }
+
+ if (Physical != gcvINVALID_PHYSICAL_ADDRESS)
+ {
+ result = import_physical_map(UserMemory, Physical);
+ }
+ else
+ {
+ if (pfn_map)
+ {
+ result = import_pfn_map(UserMemory, memory, pageCount);
+ }
+ else
+ {
+ result = import_page_map(UserMemory, memory, pageCount);
+ }
+ }
+
+ if (result == -EINVAL)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+ else if (result == -ENOMEM)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+ else if (result < 0)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ if (UserMemory->type == UM_PAGE_MAP)
+ {
+ for (i = 0; i < pageCount; i++)
+ {
+ gctUINT32 phys = page_to_phys(UserMemory->pages[i]);
+
+ /* Flush(clean) the data cache. */
+ gckOS_CacheFlush(Os, _GetProcessID(), gcvNULL,
+ phys,
+ (gctPOINTER)(memory & PAGE_MASK) + i*PAGE_SIZE,
+ PAGE_SIZE);
+ }
+ }
+
+ UserMemory->user_vaddr = (unsigned long)Memory;
+ UserMemory->size = Size;
+ UserMemory->offset = (Physical != gcvINVALID_PHYSICAL_ADDRESS)
+ ? (Physical & ~PAGE_MASK)
+ : (memory & ~PAGE_MASK);
+
+ UserMemory->pageCount = pageCount;
+ UserMemory->extraPage = extraPage;
+
+ if (extraPage && UserMemory->type == UM_PAGE_MAP)
+ {
+ /*Add the padding pages */
+ UserMemory->chunk_count++;
+ }
+
+ /* Success. */
+ gcmkFOOTER();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+_UserMemoryAttach(
+ IN gckALLOCATOR Allocator,
+ IN gcsATTACH_DESC_PTR Desc,
+ IN PLINUX_MDL Mdl
+ )
+{
+ gceSTATUS status;
+ struct um_desc * userMemory = gcvNULL;
+
+ gckOS os = Allocator->os;
+
+ gcmkHEADER();
+
+ /* Handle is meangless for this importer. */
+ gcmkVERIFY_ARGUMENT(Desc != gcvNULL);
+
+ gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct um_desc), (gctPOINTER *)&userMemory));
+
+ gckOS_ZeroMemory(userMemory, gcmSIZEOF(struct um_desc));
+
+ gcmkONERROR(_Import(os, Desc->userMem.memory, Desc->userMem.physical, Desc->userMem.size, userMemory));
+
+ Mdl->priv = userMemory;
+ Mdl->numPages = userMemory->pageCount + userMemory->extraPage;
+ Mdl->contiguous = (userMemory->chunk_count == 1);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (userMemory != gcvNULL)
+ {
+ gckOS_Free(os,(gctPOINTER)userMemory);
+ }
+ gcmkFOOTER();
+ return status;
+}
+
+static void release_physical_map(struct um_desc *um)
+{
+}
+
+static void release_page_map(struct um_desc *um)
+{
+ int i;
+
+ for (i = 0; i < um->pageCount; i++)
+ {
+ if (!PageReserved(um->pages[i]))
+ {
+ SetPageDirty(um->pages[i]);
+ }
+
+ put_page(um->pages[i]);
+ }
+
+ kfree(um->pages);
+}
+
+static void release_pfn_map(struct um_desc *um)
+{
+
+ int i;
+
+ for (i = 0; i < um->pageCount; i++)
+ {
+ if (pfn_valid(um->pfns[i]))
+ {
+ struct page *page = pfn_to_page(um->pfns[i]);
+ if (!PageReserved(page))
+ {
+ SetPageDirty(page);
+ }
+
+ if (um->refs[i])
+ {
+ put_page(page);
+ }
+ }
+ }
+
+ kfree(um->pfns);
+ kfree(um->refs);
+}
+
+static void
+_UserMemoryFree(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl
+ )
+{
+ gckOS os = Allocator->os;
+ struct um_desc *userMemory = Mdl->priv;
+
+ gcmkHEADER();
+
+ if (userMemory)
+ {
+ switch (userMemory->type)
+ {
+ case UM_PHYSICAL_MAP:
+ release_physical_map(userMemory);
+ break;
+ case UM_PAGE_MAP:
+ release_page_map(userMemory);
+ break;
+ case UM_PFN_MAP:
+ release_pfn_map(userMemory);
+ break;
+ }
+
+ gcmkOS_SAFE_FREE(os, userMemory);
+ }
+
+ gcmkFOOTER_NO();
+}
+
+static gceSTATUS
+_UserMemoryMapUser(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctBOOL Cacheable,
+ OUT gctPOINTER * UserLogical
+ )
+{
+ struct um_desc *userMemory = Mdl->priv;
+
+ *UserLogical = (gctPOINTER)userMemory->user_vaddr;
+
+ return gcvSTATUS_OK;
+}
+
+static void
+_UserMemoryUnmapUser(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Size
+ )
+{
+ return;
+}
+
+static gceSTATUS
+_UserMemoryMapKernel(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ OUT gctPOINTER *Logical
+ )
+{
+ /* Kernel doesn't acess video memory. */
+ return gcvSTATUS_NOT_SUPPORTED;
+
+}
+
+static gceSTATUS
+_UserMemoryUnmapKernel(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical
+ )
+{
+ /* Kernel doesn't acess video memory. */
+ return gcvSTATUS_NOT_SUPPORTED;
+}
+
+static gceSTATUS
+_UserMemoryCache(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Physical,
+ IN gctUINT32 Bytes,
+ IN gceCACHEOPERATION Operation
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_UserMemoryPhysical(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctUINT32 Offset,
+ OUT gctPHYS_ADDR_T * Physical
+ )
+{
+ gckOS os = Allocator->os;
+ struct um_desc *userMemory = Mdl->priv;
+ unsigned long offset = Offset + userMemory->offset;
+ gctUINT32 offsetInPage = offset & ~PAGE_MASK;
+ gctUINT32 index = offset / PAGE_SIZE;
+
+ if (index >= userMemory->pageCount)
+ {
+ if (index < userMemory->pageCount + userMemory->extraPage)
+ {
+ *Physical = page_to_phys(os->paddingPage);
+ }
+ else
+ {
+ return gcvSTATUS_INVALID_ARGUMENT;
+ }
+ }
+ else
+ {
+ switch (userMemory->type)
+ {
+ case UM_PHYSICAL_MAP:
+ *Physical = userMemory->physical + index * PAGE_SIZE;
+ break;
+ case UM_PAGE_MAP:
+ *Physical = page_to_phys(userMemory->pages[index]);
+ break;
+ case UM_PFN_MAP:
+ *Physical = userMemory->pfns[index] << PAGE_SHIFT;
+ break;
+ }
+ }
+
+ *Physical += offsetInPage;
+
+ return gcvSTATUS_OK;
+}
+
+static void
+_UserMemoryAllocatorDestructor(
+ gcsALLOCATOR *Allocator
+ )
+{
+ if (Allocator->privateData)
+ {
+ kfree(Allocator->privateData);
+ }
+
+ kfree(Allocator);
+}
+
+/* User memory allocator (importer) operations. */
+static gcsALLOCATOR_OPERATIONS UserMemoryAllocatorOperations =
+{
+ .Attach = _UserMemoryAttach,
+ .Free = _UserMemoryFree,
+ .MapUser = _UserMemoryMapUser,
+ .UnmapUser = _UserMemoryUnmapUser,
+ .MapKernel = _UserMemoryMapKernel,
+ .UnmapKernel = _UserMemoryUnmapKernel,
+ .Cache = _UserMemoryCache,
+ .Physical = _UserMemoryPhysical,
+};
+
+/* Default allocator entry. */
+gceSTATUS
+_UserMemoryAlloctorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ )
+{
+ gceSTATUS status;
+ gckALLOCATOR allocator;
+
+ gcmkONERROR(
+ gckALLOCATOR_Construct(Os, &UserMemoryAllocatorOperations, &allocator));
+
+ allocator->destructor = _UserMemoryAllocatorDestructor;
+
+ allocator->capability = gcvALLOC_FLAG_USERMEMORY;
+
+ *Allocator = allocator;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/freescale/gc_hal_kernel_allocator_array.h b/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/freescale/gc_hal_kernel_allocator_array.h
new file mode 100644
index 000000000000..f5c27ce2bb78
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/freescale/gc_hal_kernel_allocator_array.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_allocator_array_h_
+#define __gc_hal_kernel_allocator_array_h_
+
+extern gceSTATUS
+_GFPAlloctorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ );
+
+extern gceSTATUS
+_UserMemoryAlloctorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ );
+
+extern gceSTATUS
+_ReservedMemoryAllocatorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ );
+
+#if LINUX_CMA_FSL
+extern gceSTATUS
+_CMAFSLAlloctorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ );
+#endif
+
+#ifdef CONFIG_DMA_SHARED_BUFFER
+extern gceSTATUS
+_DmabufAlloctorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ );
+#endif
+
+#ifndef NO_DMA_COHERENT
+extern gceSTATUS
+_DmaAlloctorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ );
+#endif
+
+gcsALLOCATOR_DESC allocatorArray[] =
+{
+#if LINUX_CMA_FSL
+ gcmkDEFINE_ALLOCATOR_DESC("cmafsl", _CMAFSLAlloctorInit),
+#endif
+ /* GFP allocator. */
+ gcmkDEFINE_ALLOCATOR_DESC("gfp", _GFPAlloctorInit),
+
+ /* User memory importer. */
+ gcmkDEFINE_ALLOCATOR_DESC("user", _UserMemoryAlloctorInit),
+
+#ifdef CONFIG_DMA_SHARED_BUFFER
+ /* Dmabuf allocator. */
+ gcmkDEFINE_ALLOCATOR_DESC("dmabuf", _DmabufAlloctorInit),
+#endif
+
+#ifndef NO_DMA_COHERENT
+ gcmkDEFINE_ALLOCATOR_DESC("dma", _DmaAlloctorInit),
+#endif
+
+ gcmkDEFINE_ALLOCATOR_DESC("reserved-mem", _ReservedMemoryAllocatorInit),
+};
+
+#endif
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/freescale/gc_hal_kernel_allocator_cma.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/freescale/gc_hal_kernel_allocator_cma.c
new file mode 100644
index 000000000000..6e787c9d3e87
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/allocator/freescale/gc_hal_kernel_allocator_cma.c
@@ -0,0 +1,588 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_allocator.h"
+
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <asm/atomic.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#define _GC_OBJ_ZONE gcvZONE_OS
+
+typedef struct _gcsCMA_PRIV * gcsCMA_PRIV_PTR;
+typedef struct _gcsCMA_PRIV {
+ atomic_t cmasize;
+ gctBOOL cmaLimitRequest;
+}
+gcsCMA_PRIV;
+
+struct mdl_cma_priv {
+ gctPOINTER kvaddr;
+ dma_addr_t physical;
+};
+
+static int gc_cma_usage_show(struct seq_file* m, void* data)
+{
+ gcsINFO_NODE *node = m->private;
+ gckALLOCATOR Allocator = node->device;
+ gcsCMA_PRIV_PTR priv = Allocator->privateData;
+ long long size = (long long)atomic_read(&priv->cmasize);
+
+ seq_printf(m, "type n pages bytes\n");
+ seq_printf(m, "cma %10llu %12llu\n", size, size * PAGE_SIZE);
+
+ return 0;
+}
+
+static gcsINFO InfoList[] =
+{
+ {"cmausage", gc_cma_usage_show},
+};
+
+static void
+_CMAAllocatorDebugfsInit(
+ IN gckALLOCATOR Allocator,
+ IN gckDEBUGFS_DIR Root
+ )
+{
+ gcmkVERIFY_OK(
+ gckDEBUGFS_DIR_Init(&Allocator->debugfsDir, Root->root, "cma"));
+
+ gcmkVERIFY_OK(gckDEBUGFS_DIR_CreateFiles(
+ &Allocator->debugfsDir,
+ InfoList,
+ gcmCOUNTOF(InfoList),
+ Allocator
+ ));
+}
+
+static void
+_CMAAllocatorDebugfsCleanup(
+ IN gckALLOCATOR Allocator
+ )
+{
+ gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(
+ &Allocator->debugfsDir,
+ InfoList,
+ gcmCOUNTOF(InfoList)
+ ));
+
+ gckDEBUGFS_DIR_Deinit(&Allocator->debugfsDir);
+}
+
+static gceSTATUS
+_CMAFSLAlloc(
+ IN gckALLOCATOR Allocator,
+ INOUT PLINUX_MDL Mdl,
+ IN gctSIZE_T NumPages,
+ IN gctUINT32 Flags
+ )
+{
+ gceSTATUS status;
+ gcsCMA_PRIV_PTR priv = (gcsCMA_PRIV_PTR)Allocator->privateData;
+
+ struct mdl_cma_priv *mdl_priv=gcvNULL;
+ gckOS os = Allocator->os;
+
+ gcmkHEADER_ARG("Mdl=%p NumPages=0x%zx", Mdl, NumPages);
+
+ if (os->allocatorLimitMarker)
+ {
+ if ((Flags & gcvALLOC_FLAG_CMA_LIMIT) && !(Flags & gcvALLOC_FLAG_CMA_PREEMPT))
+ {
+ priv->cmaLimitRequest = gcvTRUE;
+ }
+ else if (priv->cmaLimitRequest == gcvTRUE)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+ }
+
+ gcmkONERROR(gckOS_Allocate(os, sizeof(struct mdl_cma_priv), (gctPOINTER *)&mdl_priv));
+ mdl_priv->kvaddr = gcvNULL;
+
+ mdl_priv->kvaddr = dma_alloc_writecombine(&os->device->platform->device->dev,
+ NumPages * PAGE_SIZE,
+ &mdl_priv->physical,
+ GFP_KERNEL | gcdNOWARN);
+
+ if (mdl_priv->kvaddr == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ Mdl->priv = mdl_priv;
+ Mdl->dmaHandle = mdl_priv->physical;
+ atomic_add(NumPages, &priv->cmasize);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (mdl_priv)
+ {
+ gckOS_Free(os, mdl_priv);
+ }
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+_CMAFSLGetSGT(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctSIZE_T Offset,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER *SGT
+ )
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
+ struct page ** pages = gcvNULL;
+ struct page * page = gcvNULL;
+ struct sg_table *sgt = NULL;
+ struct mdl_cma_priv *mdl_priv = (struct mdl_cma_priv*)Mdl->priv;
+
+ gceSTATUS status = gcvSTATUS_OK;
+ gctSIZE_T offset = Offset & ~PAGE_MASK; /* Offset to the first page */
+ gctINT skipPages = Offset >> PAGE_SHIFT; /* skipped pages */
+ gctINT numPages = (PAGE_ALIGN(Offset + Bytes) >> PAGE_SHIFT) - skipPages;
+ gctINT i;
+
+ gcmkASSERT(Offset + Bytes <= Mdl->numPages << PAGE_SHIFT);
+
+ sgt = kmalloc(sizeof(struct sg_table), GFP_KERNEL | gcdNOWARN);
+ if (!sgt)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ pages = kmalloc(sizeof(struct page*) * numPages, GFP_KERNEL | gcdNOWARN);
+ if (!pages)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
+ page = phys_to_page (mdlPriv->physical);
+#else
+ page = phys_to_page(dma_to_phys(&Allocator->os->device->platform->device->dev, mdl_priv->physical));
+#endif
+
+ for (i = 0; i < numPages; ++i)
+ {
+ pages[i] = nth_page(page, i + skipPages);
+ }
+
+ if (sg_alloc_table_from_pages(sgt, pages, numPages, offset, Bytes, GFP_KERNEL) < 0)
+ {
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+ *SGT = (gctPOINTER)sgt;
+
+OnError:
+ if (pages)
+ {
+ kfree(pages);
+ }
+
+ if (gcmIS_ERROR(status) && sgt)
+ {
+ kfree(sgt);
+ }
+
+ return status;
+#else
+ return gcvSTATUS_NOT_SUPPORTED;
+#endif
+}
+
+static void
+_CMAFSLFree(
+ IN gckALLOCATOR Allocator,
+ IN OUT PLINUX_MDL Mdl
+ )
+{
+ gckOS os = Allocator->os;
+ struct mdl_cma_priv *mdlPriv=(struct mdl_cma_priv *)Mdl->priv;
+ gcsCMA_PRIV_PTR priv = (gcsCMA_PRIV_PTR)Allocator->privateData;
+ dma_free_writecombine(&os->device->platform->device->dev,
+ Mdl->numPages * PAGE_SIZE,
+ mdlPriv->kvaddr,
+ mdlPriv->physical);
+ gckOS_Free(os, mdlPriv);
+ atomic_sub(Mdl->numPages, &priv->cmasize);
+}
+
+static gceSTATUS
+_CMAFSLMmap(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctSIZE_T skipPages,
+ IN gctSIZE_T numPages,
+ INOUT struct vm_area_struct *vma
+ )
+{
+ gckOS os = Allocator->os;
+ struct mdl_cma_priv *mdlPriv = (struct mdl_cma_priv*)Mdl->priv;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ gcmkHEADER_ARG("Allocator=%p Mdl=%p vma=%p", Allocator, Mdl, vma);
+
+ gcmkASSERT(skipPages + numPages <= Mdl->numPages);
+
+ /* Now map all the vmalloc pages to this user address. */
+ if (Mdl->contiguous)
+ {
+ /* map kernel memory to user space.. */
+ if (dma_mmap_writecombine(&os->device->platform->device->dev,
+ vma,
+ (gctINT8_PTR)mdlPriv->kvaddr + (skipPages << PAGE_SHIFT),
+ mdlPriv->physical + (skipPages << PAGE_SHIFT),
+ numPages << PAGE_SHIFT) < 0)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_WARNING, gcvZONE_OS,
+ "%s(%d): dma_mmap_attrs error",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+ }
+ else
+ {
+ gcmkFATAL("%s(%d): unexpected noncontiguous mdl\n");
+ gcmkONERROR(gcvSTATUS_HEAP_CORRUPTED);
+ }
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+static void
+_CMAFSLUnmapUser(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Size
+ )
+{
+ if (unlikely(current->mm == gcvNULL))
+ {
+ /* Do nothing if process is exiting. */
+ return;
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,0)
+ if (vm_munmap((unsigned long)Logical, Size) < 0)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_WARNING, gcvZONE_OS,
+ "%s(%d): vm_munmap failed",
+ __FUNCTION__, __LINE__
+ );
+ }
+#else
+ down_write(&current->mm->mmap_sem);
+ if (do_munmap(current->mm, (unsigned long)Logical, Size) < 0)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_WARNING, gcvZONE_OS,
+ "%s(%d): do_munmap failed",
+ __FUNCTION__, __LINE__
+ );
+ }
+ up_write(&current->mm->mmap_sem);
+#endif
+}
+
+static gceSTATUS
+_CMAFSLMapUser(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctBOOL Cacheable,
+ OUT gctPOINTER * UserLogical
+ )
+{
+ gctPOINTER userLogical = gcvNULL;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ gcmkHEADER_ARG("Allocator=%p Mdl=%p Cacheable=%d", Allocator, Mdl, Cacheable);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
+ userLogical = (gctPOINTER)vm_mmap(gcvNULL,
+ 0L,
+ Mdl->numPages * PAGE_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_NORESERVE,
+ 0);
+#else
+ down_write(&current->mm->mmap_sem);
+ userLogical = (gctPOINTER)do_mmap_pgoff(gcvNULL,
+ 0L,
+ Mdl->numPages * PAGE_SIZE,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ 0);
+ up_write(&current->mm->mmap_sem);
+#endif
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): vmaAddr->%p for phys_addr->%p",
+ __FUNCTION__, __LINE__, userLogical, Mdl
+ );
+
+ if (IS_ERR(userLogical))
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): do_mmap_pgoff error",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ down_write(&current->mm->mmap_sem);
+ do
+ {
+ struct vm_area_struct *vma = find_vma(current->mm, (unsigned long)userLogical);
+ if (vma == gcvNULL)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): find_vma error",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkERR_BREAK(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ gcmkERR_BREAK(_CMAFSLMmap(Allocator, Mdl, 0, Mdl->numPages, vma));
+ }
+ while (gcvFALSE);
+ up_write(&current->mm->mmap_sem);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ gcmkONERROR(gckOS_CacheFlush(
+ Allocator->os,
+ _GetProcessID(),
+ Mdl,
+ gcvINVALID_ADDRESS,
+ userLogical,
+ Mdl->numPages * PAGE_SIZE
+ ));
+
+ *UserLogical = userLogical;
+ }
+
+OnError:
+ if (gcmIS_ERROR(status) && userLogical)
+ {
+ _CMAFSLUnmapUser(Allocator, Mdl, userLogical, Mdl->numPages * PAGE_SIZE);
+ }
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+_CMAMapKernel(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ OUT gctPOINTER *Logical
+ )
+{
+ struct mdl_cma_priv *mdl_priv=(struct mdl_cma_priv *)Mdl->priv;
+ *Logical =mdl_priv->kvaddr;
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_CMAUnmapKernel(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_CMACache(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Physical,
+ IN gctUINT32 Bytes,
+ IN gceCACHEOPERATION Operation
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_CMAPhysical(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctUINT32 Offset,
+ OUT gctPHYS_ADDR_T * Physical
+ )
+{
+ struct mdl_cma_priv *mdl_priv=(struct mdl_cma_priv *)Mdl->priv;
+
+ *Physical = mdl_priv->physical + Offset;
+
+ return gcvSTATUS_OK;
+}
+
+static void
+_CMAAllocatorDestructor(
+ gcsALLOCATOR *Allocator
+ )
+{
+ _CMAAllocatorDebugfsCleanup(Allocator);
+
+ if (Allocator->privateData)
+ {
+ kfree(Allocator->privateData);
+ }
+
+ kfree(Allocator);
+}
+
+/* Default allocator operations. */
+static gcsALLOCATOR_OPERATIONS CMAFSLAllocatorOperations =
+{
+ .Alloc = _CMAFSLAlloc,
+ .Free = _CMAFSLFree,
+ .Mmap = _CMAFSLMmap,
+ .MapUser = _CMAFSLMapUser,
+ .UnmapUser = _CMAFSLUnmapUser,
+ .MapKernel = _CMAMapKernel,
+ .UnmapKernel = _CMAUnmapKernel,
+ .Cache = _CMACache,
+ .Physical = _CMAPhysical,
+ .GetSGT = _CMAFSLGetSGT,
+};
+
+/* Default allocator entry. */
+gceSTATUS
+_CMAFSLAlloctorInit(
+ IN gckOS Os,
+ IN gcsDEBUGFS_DIR *Parent,
+ OUT gckALLOCATOR * Allocator
+ )
+{
+ gceSTATUS status;
+ gckALLOCATOR allocator = gcvNULL;
+ gcsCMA_PRIV_PTR priv = gcvNULL;
+
+ gcmkONERROR(
+ gckALLOCATOR_Construct(Os, &CMAFSLAllocatorOperations, &allocator));
+
+ priv = kzalloc(gcmSIZEOF(gcsCMA_PRIV), GFP_KERNEL | gcdNOWARN);
+
+ if (!priv)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ atomic_set(&priv->cmasize, 0);
+
+ /* Register private data. */
+ allocator->privateData = priv;
+ allocator->destructor = _CMAAllocatorDestructor;
+
+ _CMAAllocatorDebugfsInit(allocator, Parent);
+
+ allocator->capability = gcvALLOC_FLAG_CONTIGUOUS
+ | gcvALLOC_FLAG_DMABUF_EXPORTABLE
+ ;
+
+#if defined(CONFIG_ARM64)
+ Os->allocatorLimitMarker = (Os->device->baseAddress + totalram_pages * PAGE_SIZE) > 0x100000000;
+#else
+ Os->allocatorLimitMarker = gcvFALSE;
+#endif
+ priv->cmaLimitRequest = gcvFALSE;
+
+ if (Os->allocatorLimitMarker)
+ {
+ allocator->capability |= gcvALLOC_FLAG_CMA_LIMIT;
+ allocator->capability |= gcvALLOC_FLAG_CMA_PREEMPT;
+ }
+
+ *Allocator = allocator;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ if (allocator)
+ {
+ kfree(allocator);
+ }
+ return status;
+}
+
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_allocator.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_allocator.c
new file mode 100644
index 000000000000..85b52d587302
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_allocator.c
@@ -0,0 +1,180 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_allocator.h"
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <asm/atomic.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
+#include <linux/anon_inodes.h>
+#endif
+#include <linux/file.h>
+
+#include "gc_hal_kernel_allocator_array.h"
+#include "gc_hal_kernel_platform.h"
+
+#define _GC_OBJ_ZONE gcvZONE_OS
+
+
+/******************************************************************************\
+******************************** Debugfs Support *******************************
+\******************************************************************************/
+
+static gceSTATUS
+_AllocatorDebugfsInit(
+ IN gckOS Os
+ )
+{
+ gceSTATUS status;
+ gckGALDEVICE device = Os->device;
+
+ gckDEBUGFS_DIR dir = &Os->allocatorDebugfsDir;
+
+ gcmkONERROR(gckDEBUGFS_DIR_Init(dir, device->debugfsDir.root, "allocators"));
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+static void
+_AllocatorDebugfsCleanup(
+ IN gckOS Os
+ )
+{
+ gckDEBUGFS_DIR dir = &Os->allocatorDebugfsDir;
+
+ gckDEBUGFS_DIR_Deinit(dir);
+}
+
+/***************************************************************************\
+************************ Allocator management *******************************
+\***************************************************************************/
+
+gceSTATUS
+gckOS_ImportAllocators(
+ gckOS Os
+ )
+{
+ gceSTATUS status;
+ gctUINT i;
+ gckALLOCATOR allocator;
+
+ _AllocatorDebugfsInit(Os);
+
+ INIT_LIST_HEAD(&Os->allocatorList);
+
+ for (i = 0; i < gcmCOUNTOF(allocatorArray); i++)
+ {
+ if (allocatorArray[i].construct)
+ {
+ /* Construct allocator. */
+ status = allocatorArray[i].construct(Os, &Os->allocatorDebugfsDir, &allocator);
+
+ if (gcmIS_ERROR(status))
+ {
+ gcmkPRINT("["DEVICE_NAME"]: Can't construct allocator(%s)",
+ allocatorArray[i].name);
+
+ continue;
+ }
+
+ allocator->name = allocatorArray[i].name;
+
+ list_add_tail(&allocator->link, &Os->allocatorList);
+ }
+ }
+
+#if gcdDEBUG
+ list_for_each_entry(allocator, &Os->allocatorList, link)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_WARNING, gcvZONE_OS,
+ "%s(%d) Allocator: %s",
+ __FUNCTION__, __LINE__,
+ allocator->name
+ );
+ }
+#endif
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_FreeAllocators(
+ gckOS Os
+ )
+{
+ gckALLOCATOR allocator;
+ gckALLOCATOR temp;
+
+ list_for_each_entry_safe(allocator, temp, &Os->allocatorList, link)
+ {
+ list_del(&allocator->link);
+
+ /* Destroy allocator. */
+ allocator->destructor(allocator);
+ }
+
+ _AllocatorDebugfsCleanup(Os);
+
+ return gcvSTATUS_OK;
+}
+
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_allocator.h b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_allocator.h
new file mode 100644
index 000000000000..30690f9d4cd6
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_allocator.h
@@ -0,0 +1,558 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_allocator_h_
+#define __gc_hal_kernel_allocator_h_
+
+#include "gc_hal_kernel_linux.h"
+#include <linux/slab.h>
+#include <linux/mm_types.h>
+
+typedef struct _gcsALLOCATOR * gckALLOCATOR;
+typedef union _gcsATTACH_DESC * gcsATTACH_DESC_PTR;
+
+typedef struct _gcsALLOCATOR_OPERATIONS
+{
+ /**************************************************************************
+ **
+ ** Alloc
+ **
+ ** Allocte memory, request size is page aligned.
+ **
+ ** INPUT:
+ **
+ ** gckALLOCATOR Allocator
+ ** Pointer to an gckALLOCATOER object.
+ **
+ ** PLINUX_Mdl
+ ** Pointer to Mdl whichs stores information
+ ** about allocated memory.
+ **
+ ** gctSIZE_T NumPages
+ ** Number of pages need to allocate.
+ **
+ ** gctUINT32 Flag
+ ** Allocation option.
+ **
+ ** OUTPUT:
+ **
+ ** Nothing.
+ **
+ */
+ gceSTATUS
+ (*Alloc)(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctSIZE_T NumPages,
+ IN gctUINT32 Flag
+ );
+
+ /**************************************************************************
+ **
+ ** Free
+ **
+ ** Free memory.
+ **
+ ** INPUT:
+ **
+ ** gckALLOCATOR Allocator
+ ** Pointer to an gckALLOCATOER object.
+ **
+ ** PLINUX_MDL Mdl
+ ** Mdl which stores information.
+ **
+ ** OUTPUT:
+ **
+ ** Nothing.
+ **
+ */
+ void
+ (*Free)(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl
+ );
+
+ /**************************************************************************
+ **
+ ** Mmap
+ **
+ ** Map a page range of the memory to user space.
+ **
+ ** INPUT:
+ ** gckALLOCATOR Allocator
+ ** Pointer to an gckALLOCATOER object.
+ **
+ ** PLINUX_MDL Mdl
+ ** Pointer to a Mdl.
+ **
+ ** gctSIZE_T skipPages
+ ** Number of page to be skipped from beginning of this memory.
+ **
+ ** gctSIZE_T numPages
+ ** Number of pages to be mapped from skipPages.
+ **
+ ** INOUT:
+ **
+ ** struct vm_area_struct *vma
+ ** Pointer to VMM memory area.
+ **
+ */
+ gceSTATUS
+ (*Mmap)(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctSIZE_T skipPages,
+ IN gctSIZE_T numPages,
+ INOUT struct vm_area_struct *vma
+ );
+
+ /**************************************************************************
+ **
+ ** MapUser
+ **
+ ** Map memory to user space.
+ **
+ ** INPUT:
+ ** gckALLOCATOR Allocator
+ ** Pointer to an gckALLOCATOER object.
+ **
+ ** PLINUX_MDL Mdl
+ ** Pointer to a Mdl.
+ **
+ ** gctBOOL Cacheable
+ ** Whether this mapping is cacheable.
+ **
+ ** OUTPUT:
+ **
+ ** gctPOINTER * UserLogical
+ ** Pointer to user logical address.
+ **
+ ** Nothing.
+ **
+ */
+ gceSTATUS
+ (*MapUser)(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctBOOL Cacheable,
+ OUT gctPOINTER * UserLogical
+ );
+
+ /**************************************************************************
+ **
+ ** UnmapUser
+ **
+ ** Unmap address from user address space.
+ **
+ ** INPUT:
+ ** gckALLOCATOR Allocator
+ ** Pointer to an gckALLOCATOER object.
+ **
+ ** gctPOINTER Logical
+ ** Address to be unmap
+ **
+ ** gctUINT32 Size
+ ** Size of address space
+ **
+ ** OUTPUT:
+ **
+ ** Nothing.
+ **
+ */
+ void
+ (*UnmapUser)(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Size
+ );
+
+ /**************************************************************************
+ **
+ ** MapKernel
+ **
+ ** Map memory to kernel space.
+ **
+ ** INPUT:
+ ** gckALLOCATOR Allocator
+ ** Pointer to an gckALLOCATOER object.
+ **
+ ** PLINUX_MDL Mdl
+ ** Pointer to a Mdl object.
+ **
+ ** OUTPUT:
+ ** gctPOINTER * Logical
+ ** Mapped kernel address.
+ */
+ gceSTATUS
+ (*MapKernel)(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ OUT gctPOINTER *Logical
+ );
+
+ /**************************************************************************
+ **
+ ** UnmapKernel
+ **
+ ** Unmap memory from kernel space.
+ **
+ ** INPUT:
+ ** gckALLOCATOR Allocator
+ ** Pointer to an gckALLOCATOER object.
+ **
+ ** PLINUX_MDL Mdl
+ ** Pointer to a Mdl object.
+ **
+ ** gctPOINTER Logical
+ ** Mapped kernel address.
+ **
+ ** OUTPUT:
+ **
+ ** Nothing.
+ **
+ */
+ gceSTATUS
+ (*UnmapKernel)(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical
+ );
+
+ /**************************************************************************
+ **
+ ** Cache
+ **
+ ** Maintain cache coherency.
+ **
+ ** INPUT:
+ ** gckALLOCATOR Allocator
+ ** Pointer to an gckALLOCATOER object.
+ **
+ ** PLINUX_MDL Mdl
+ ** Pointer to a Mdl object.
+ **
+ ** gctPOINTER Logical
+ ** Logical address, could be user address or kernel address
+ **
+ ** gctUINT32_PTR Physical
+ ** Physical address.
+ **
+ ** gctUINT32 Bytes
+ ** Size of memory region.
+ **
+ ** gceCACHEOPERATION Opertaion
+ ** Cache operation.
+ **
+ ** OUTPUT:
+ **
+ ** Nothing.
+ **
+ */
+ gceSTATUS (*Cache)(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctPOINTER Logical,
+ IN gctUINT32 Physical,
+ IN gctUINT32 Bytes,
+ IN gceCACHEOPERATION Operation
+ );
+
+ /**************************************************************************
+ **
+ ** Physical
+ **
+ ** Get physical address from a offset in memory region.
+ **
+ ** INPUT:
+ ** gckALLOCATOR Allocator
+ ** Pointer to an gckALLOCATOER object.
+ **
+ ** PLINUX_MDL Mdl
+ ** Pointer to a Mdl object.
+ **
+ ** gctUINT32 Offset
+ ** Offset in this memory region.
+ **
+ ** OUTPUT:
+ ** gctUINT32_PTR Physical
+ ** Physical address.
+ **
+ */
+ gceSTATUS (*Physical)(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctUINT32 Offset,
+ OUT gctPHYS_ADDR_T * Physical
+ );
+
+ /**************************************************************************
+ **
+ ** Attach
+ **
+ ** Import memory allocated by an external allocator.
+ **
+ ** INPUT:
+ ** gckALLOCATOR Allocator
+ ** Pointer to an gckALLOCATOER object.
+ **
+ ** gctUINT32 Handle
+ ** Handle of the memory.
+ **
+ ** OUTPUT:
+ ** None.
+ **
+ */
+ gceSTATUS (*Attach)(
+ IN gckALLOCATOR Allocator,
+ IN gcsATTACH_DESC_PTR Desc,
+ OUT PLINUX_MDL Mdl
+ );
+
+ /**************************************************************************
+ **
+ ** GetSGT
+ **
+ ** Get scatter-gather table from a range of the memory.
+ **
+ ** INPUT:
+ ** gckALLOCATOR Allocator
+ ** Pointer to an gckALLOCATOER object.
+ **
+ ** gctUINT32 Handle
+ ** Handle of the memory.
+ **
+ ** gctSIZE_T Offset
+ ** Offset to the beginning of this mdl.
+ **
+ ** gctSIZE_T Bytes
+ ** Total bytes form Offset.
+ **
+ ** OUTPUT:
+ ** gctPOINTER *SGT
+ ** scatter-gather table
+ **
+ */
+ gceSTATUS (*GetSGT)(
+ IN gckALLOCATOR Allocator,
+ IN PLINUX_MDL Mdl,
+ IN gctSIZE_T Offset,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER *SGT
+ );
+}
+gcsALLOCATOR_OPERATIONS;
+
+typedef struct _gcsALLOCATOR
+{
+ /* Pointer to gckOS Object. */
+ gckOS os;
+
+ /* Name. */
+ gctSTRING name;
+
+ /* Operations. */
+ gcsALLOCATOR_OPERATIONS * ops;
+
+ /* Capability of this allocator. */
+ gctUINT32 capability;
+
+ /* Debugfs entry of this allocator. */
+ gcsDEBUGFS_DIR debugfsDir;
+
+ /* Private data used by customer allocator. */
+ void * privateData;
+
+ /* Allocator destructor. */
+ void (*destructor)(struct _gcsALLOCATOR *);
+
+ struct list_head link;
+}
+gcsALLOCATOR;
+
+typedef struct _gcsALLOCATOR_DESC
+{
+ /* Name of a allocator. */
+ char * name;
+
+ /* Entry function to construct a allocator. */
+ gceSTATUS (*construct)(gckOS, gcsDEBUGFS_DIR *, gckALLOCATOR *);
+}
+gcsALLOCATOR_DESC;
+
+typedef union _gcsATTACH_DESC
+{
+ /* gcvALLOC_FLAG_DMABUF */
+ struct
+ {
+ gctPOINTER dmabuf;
+ }
+ dmaBuf;
+
+ /* gcvALLOC_FLAG_USERMEMORY */
+ struct
+ {
+ gctPOINTER memory;
+ gctPHYS_ADDR_T physical;
+ gctSIZE_T size;
+ }
+ userMem;
+
+ /* gcvALLOC_FLAG_EXTERNAL_MEMORY */
+ struct
+ {
+ gcsEXTERNAL_MEMORY_INFO info;
+ }
+ externalMem;
+
+ /* Reserved memory. */
+ struct
+ {
+ unsigned long start;
+ unsigned long size;
+ const char * name;
+ int requested;
+ }
+ reservedMem;
+}
+gcsATTACH_DESC;
+
+/*
+* Helpers
+*/
+
+/* Fill a gcsALLOCATOR_DESC structure. */
+#define gcmkDEFINE_ALLOCATOR_DESC(Name, Construct) \
+ { \
+ .name = Name, \
+ .construct = Construct, \
+ }
+
+/* Construct a allocator. */
+static inline gceSTATUS
+gckALLOCATOR_Construct(
+ IN gckOS Os,
+ IN gcsALLOCATOR_OPERATIONS * Operations,
+ OUT gckALLOCATOR * Allocator
+ )
+{
+ gceSTATUS status;
+ gckALLOCATOR allocator;
+
+ gcmkASSERT(Allocator != gcvNULL);
+ gcmkASSERT
+ ( Operations
+ && (Operations->Alloc || Operations->Attach)
+ && (Operations->Free)
+ && Operations->MapUser
+ && Operations->UnmapUser
+ && Operations->MapKernel
+ && Operations->UnmapKernel
+ && Operations->Cache
+ && Operations->Physical
+ );
+
+ allocator = kzalloc(sizeof(gcsALLOCATOR), GFP_KERNEL | gcdNOWARN);
+ if (unlikely(!allocator))
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ /* Record os. */
+ allocator->os = Os;
+
+ /* Set operations. */
+ allocator->ops = Operations;
+
+ *Allocator = allocator;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+/*
+ How to implement customer allocator
+
+ Build in customer alloctor
+
+ It is recommanded that customer allocator is implmented in independent
+ source file(s) which is specified by CUSOMTER_ALLOCATOR_OBJS in Kbuld.
+
+ Register gcsALLOCATOR
+
+ For each customer specified allocator, a desciption entry must be added
+ to allocatorArray defined in gc_hal_kernel_allocator_array.h.
+
+ An entry in allocatorArray is a gcsALLOCATOR_DESC structure which describes
+ name and constructor of a gckALLOCATOR object.
+
+
+ Implement gcsALLOCATOR_DESC.init()
+
+ In gcsALLOCATOR_DESC.init(), gckALLOCATOR_Construct should be called
+ to create a gckALLOCATOR object, customer specified private data can
+ be put in gcsALLOCATOR.privateData.
+
+
+ Implement gcsALLOCATOR_OPERATIONS
+
+ When call gckALLOCATOR_Construct to create a gckALLOCATOR object, a
+ gcsALLOCATOR_OPERATIONS structure must be provided whose all members
+ implemented.
+
+*/
+#endif
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debug.h b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debug.h
new file mode 100644
index 000000000000..a3428a1667b8
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debug.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_debug_h_
+#define __gc_hal_kernel_debug_h_
+
+#include <gc_hal_kernel_linux.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************\
+****************************** OS-dependent Macros *****************************
+\******************************************************************************/
+
+typedef va_list gctARGUMENTS;
+
+#define gcmkARGUMENTS_START(Arguments, Pointer) \
+ va_start(Arguments, Pointer)
+
+#define gcmkARGUMENTS_END(Arguments) \
+ va_end(Arguments)
+
+#define gcmkARGUMENTS_ARG(Arguments, Type) \
+ va_arg(Arguments, Type)
+
+#define gcmkDECLARE_MUTEX(__mutex__) \
+ DEFINE_MUTEX(__mutex__); \
+
+#define gcmkMUTEX_LOCK(__mutex__) \
+ mutex_lock(&__mutex__);
+
+#define gcmkMUTEX_UNLOCK(__mutex__) \
+ mutex_unlock(&__mutex__);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+# define gcmkGETPROCESSID() \
+ task_tgid_vnr(current)
+#else
+# define gcmkGETPROCESSID() \
+ current->tgid
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+# define gcmkGETTHREADID() \
+ task_pid_vnr(current)
+#else
+# define gcmkGETTHREADID() \
+ current->pid
+#endif
+
+#define gcmkOUTPUT_STRING(String) \
+ if (gckDEBUGFS_IsEnabled()) \
+ { \
+ while (-ERESTARTSYS == gckDEBUGFS_Print(String)); \
+ } \
+ else \
+ { \
+ printk(String); \
+ }
+
+#define gcmkSPRINTF(Destination, Size, Message, Value) \
+ snprintf(Destination, Size, Message, Value)
+
+#define gcmkSPRINTF2(Destination, Size, Message, Value1, Value2) \
+ snprintf(Destination, Size, Message, Value1, Value2)
+
+#define gcmkSPRINTF3(Destination, Size, Message, Value1, Value2, Value3) \
+ snprintf(Destination, Size, Message, Value1, Value2, Value3)
+
+#define gcmkVSPRINTF(Destination, Size, Message, Arguments) \
+ vsnprintf(Destination, Size, Message, *((va_list*)Arguments))
+
+#define gcmkSTRCATSAFE(Destination, Size, String) \
+ strncat(Destination, String, (Size) - 1)
+
+#define gcmkMEMCPY(Destination, Source, Size) \
+ memcpy(Destination, Source, Size)
+
+#define gcmkSTRLEN(String) \
+ strlen(String)
+
+/* If not zero, forces data alignment in the variable argument list
+ by its individual size. */
+#define gcdALIGNBYSIZE 1
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gc_hal_kernel_debug_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debugfs.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debugfs.c
new file mode 100644
index 000000000000..1bb68fcd6c88
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debugfs.c
@@ -0,0 +1,964 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/vmalloc.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+#include <linux/completion.h>
+#include <linux/seq_file.h>
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_debug.h"
+
+/*
+ Prequsite:
+
+ 1) Debugfs feature must be enabled in the kernel.
+ 1.a) You can enable this, in the compilation of the uImage, all you have to do is, In the "make menuconfig" part,
+ you have to enable the debugfs in the kernel hacking part of the menu.
+
+ HOW TO USE:
+ 1) insert the driver with the following option logFileSize, Ex: insmod galcore.ko ...... logFileSize=10240
+ This gives a circular buffer of 10 MB
+
+ 2)Usually after inserting the driver, the debug file system is mounted under /sys/kernel/debug/
+
+ 2.a)If the debugfs is not mounted, you must do "mount -t debugfs none /sys/kernel/debug"
+
+ 3) To read what is being printed in the debugfs file system:
+ Ex : cat /sys/kernel/debug/gc/galcore_trace
+
+ 4)To write into the debug file system from user side :
+ Ex: echo "hello" > cat /sys/kernel/debug/gc/galcore_trace
+
+ 5)To write into debugfs from kernel side, Use the function called gckDEBUGFS_Print
+
+ How to Get Video Memory Usage:
+ 1) Select a process whose video memory usage can be dump, no need to reset it until <pid> is needed to be change.
+ echo <pid> > /sys/kernel/debug/gc/vidmem
+
+ 2) Get video memory usage.
+ cat /sys/kernel/debug/gc/vidmem
+
+ USECASE Kernel Dump:
+
+ 1) Go to /hal/inc/gc_hal_options.h, and enable the following flags:
+ - # define gcdDUMP 1
+ - # define gcdDUMP_IN_KERNEL 1
+ - # define gcdDUMP_COMMAND 1
+
+ 2) Go to /hal/kernel/gc_hal_kernel_command.c and disable the following flag
+ -#define gcdSIMPLE_COMMAND_DUMP 0
+
+ 3) Compile the driver
+ 4) insmod it with the logFileSize option
+ 5) Run an application
+ 6) You can get the dump by cat /sys/kernel/debug/gpu/galcore_trace
+
+ */
+
+/**/
+typedef va_list gctDBGARGS ;
+#define gcmkARGS_START(argument, pointer) va_start(argument, pointer)
+#define gcmkARGS_END(argument) va_end(argument)
+
+#define gcmkDEBUGFS_PRINT(ArgumentSize, Message) \
+ { \
+ gctDBGARGS __arguments__; \
+ gcmkARGS_START(__arguments__, Message); \
+ _debugfs_res = _DebugFSPrint(ArgumentSize, Message, &__arguments__);\
+ gcmkARGS_END(__arguments__); \
+ }
+
+
+static DEFINE_SPINLOCK(traceLock);
+
+/* Debug File System Node Struct. */
+struct _gcsDEBUGFS_Node
+{
+ /*wait queues for read and write operations*/
+#if defined(DECLARE_WAIT_QUEUE_HEAD)
+ wait_queue_head_t read_q , write_q ;
+#else
+ struct wait_queue *read_q , *write_q ;
+#endif
+ struct dentry *parent ; /*parent directory*/
+ struct dentry *filen ; /*filename*/
+ struct semaphore sem ; /* mutual exclusion semaphore */
+ char *data ; /* The circular buffer data */
+ int size ; /* Size of the buffer pointed to by 'data' */
+ int refcount ; /* Files that have this buffer open */
+ int read_point ; /* Offset in circ. buffer of oldest data */
+ int write_point ; /* Offset in circ. buffer of newest data */
+ int offset ; /* Byte number of read_point in the stream */
+ struct _gcsDEBUGFS_Node *next ;
+
+ caddr_t temp;
+ int tempSize;
+};
+
+/* amount of data in the queue */
+#define gcmkNODE_QLEN(node) ( (node)->write_point >= (node)->read_point ? \
+ (node)->write_point - (node)->read_point : \
+ (node)->size - (node)->read_point + (node)->write_point)
+
+/* byte number of the last byte in the queue */
+#define gcmkNODE_FIRST_EMPTY_BYTE(node) ((node)->offset + gcmkNODE_QLEN(node))
+
+/*Synchronization primitives*/
+#define gcmkNODE_READQ(node) (&((node)->read_q))
+#define gcmkNODE_WRITEQ(node) (&((node)->write_q))
+#define gcmkNODE_SEM(node) (&((node)->sem))
+
+/*Utilities*/
+#define gcmkMIN(x, y) ((x) < (y) ? (x) : y)
+
+/*Debug File System Struct*/
+typedef struct _gcsDEBUGFS_
+{
+ gcsDEBUGFS_Node* linkedlist ;
+ gcsDEBUGFS_Node* currentNode ;
+ int isInited ;
+} gcsDEBUGFS_ ;
+
+/*debug file system*/
+static gcsDEBUGFS_ gc_dbgfs ;
+
+static int gc_debugfs_open(struct inode *inode, struct file *file)
+{
+ gcsINFO_NODE *node = inode->i_private;
+
+ return single_open(file, node->info->show, node);
+}
+
+static ssize_t
+gc_debugfs_write(
+ struct file *file,
+ const char __user *buf,
+ size_t count,
+ loff_t *pos
+ )
+{
+ struct seq_file *s = file->private_data;
+ gcsINFO_NODE *node = s->private;
+ gcsINFO *info = node->info;
+
+ if (info->write)
+ {
+ info->write(buf, count, node);
+ }
+
+ return count;
+}
+
+static const struct file_operations gc_debugfs_operations = {
+ .owner = THIS_MODULE,
+ .open = gc_debugfs_open,
+ .write = gc_debugfs_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+gceSTATUS
+gckDEBUGFS_DIR_Init(
+ IN gckDEBUGFS_DIR Dir,
+ IN struct dentry *root,
+ IN gctCONST_STRING Name
+ )
+{
+ Dir->root = debugfs_create_dir(Name, root);
+
+ if (!Dir->root)
+ {
+ return gcvSTATUS_NOT_SUPPORTED;
+ }
+
+ INIT_LIST_HEAD(&Dir->nodeList);
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckDEBUGFS_DIR_CreateFiles(
+ IN gckDEBUGFS_DIR Dir,
+ IN gcsINFO * List,
+ IN int count,
+ IN gctPOINTER Data
+ )
+{
+ int i;
+ gcsINFO_NODE * node;
+ gceSTATUS status;
+
+ for (i = 0; i < count; i++)
+ {
+ umode_t mode = 0;
+
+ /* Create a node. */
+ node = (gcsINFO_NODE *)kzalloc(sizeof(gcsINFO_NODE), GFP_KERNEL);
+
+ node->info = &List[i];
+ node->device = Data;
+
+ mode |= List[i].show ? S_IRUGO : 0;
+ mode |= List[i].write ? S_IWUSR : 0;
+
+ node->entry = debugfs_create_file(
+ List[i].name, mode, Dir->root, node, &gc_debugfs_operations);
+
+ if (!node->entry)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ list_add(&(node->head), &(Dir->nodeList));
+ }
+
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(Dir, List, count));
+ return status;
+}
+
+gceSTATUS
+gckDEBUGFS_DIR_RemoveFiles(
+ IN gckDEBUGFS_DIR Dir,
+ IN gcsINFO * List,
+ IN int count
+ )
+{
+ int i;
+ gcsINFO_NODE * node;
+ gcsINFO_NODE * temp;
+
+ for (i = 0; i < count; i++)
+ {
+ list_for_each_entry_safe(node, temp, &Dir->nodeList, head)
+ {
+ if (node->info == &List[i])
+ {
+ debugfs_remove(node->entry);
+ list_del(&node->head);
+ kfree(node);
+ }
+ }
+ }
+
+ return gcvSTATUS_OK;
+}
+
+void
+gckDEBUGFS_DIR_Deinit(
+ IN gckDEBUGFS_DIR Dir
+ )
+{
+ if (Dir->root != NULL)
+ {
+ debugfs_remove(Dir->root);
+ Dir->root = NULL;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** READ & WRITE FUNCTIONS (START)
+ **
+ *******************************************************************************/
+
+/*******************************************************************************
+ **
+ ** _ReadFromNode
+ **
+ ** 1) reading bytes out of a circular buffer with wraparound.
+ ** 2)returns caddr_t, pointer to data read, which the caller must free.
+ ** 3) length is (a pointer to) the number of bytes to be read, which will be set by this function to
+ ** be the number of bytes actually returned
+ **
+ *******************************************************************************/
+static caddr_t
+_ReadFromNode (
+ gcsDEBUGFS_Node* Node ,
+ size_t *Length ,
+ loff_t *Offset
+ )
+{
+ caddr_t retval ;
+ int bytes_copied = 0 , n , start_point , remaining ;
+
+ /* find the smaller of the total bytes we have available and what
+ * the user is asking for */
+ *Length = gcmkMIN ( *Length , gcmkNODE_QLEN(Node) ) ;
+
+ remaining = * Length ;
+
+ /* Get start point. */
+ start_point = Node->read_point;
+
+ /* allocate memory to return */
+ if (remaining > Node->tempSize)
+ {
+ kfree(Node->temp);
+
+ if ( ( retval = kmalloc ( sizeof (char ) * remaining , GFP_KERNEL ) ) == NULL )
+ return NULL;
+
+ Node->temp = retval;
+ Node->tempSize = remaining;
+ }
+ else
+ {
+ retval = Node->temp;
+ }
+
+ /* copy the (possibly noncontiguous) data to our buffer */
+ while ( remaining )
+ {
+ n = gcmkMIN ( remaining , Node->size - start_point ) ;
+ memcpy ( retval + bytes_copied , Node->data + start_point , n ) ;
+ bytes_copied += n ;
+ remaining -= n ;
+ start_point = ( start_point + n ) % Node->size ;
+ }
+
+ /* advance user's file pointer */
+ Node->read_point = (Node->read_point + * Length) % Node->size ;
+
+ return retval ;
+}
+
+/*******************************************************************************
+ **
+ ** _WriteToNode
+ **
+ ** 1) writes to a circular buffer with wraparound.
+ ** 2)in case of an overflow, it overwrites the oldest unread data.
+ **
+ *********************************************************************************/
+static void
+_WriteToNode (
+ gcsDEBUGFS_Node* Node ,
+ caddr_t Buf ,
+ int Length
+ )
+{
+ int bytes_copied = 0 ;
+ int overflow = 0 ;
+ int n ;
+
+ if ( Length + gcmkNODE_QLEN ( Node ) >= ( Node->size - 1 ) )
+ {
+ overflow = 1 ;
+ }
+
+ while ( Length )
+ {
+ /* how many contiguous bytes are available from the write point to
+ * the end of the circular buffer? */
+ n = gcmkMIN ( Length , Node->size - Node->write_point ) ;
+ memcpy ( Node->data + Node->write_point , Buf + bytes_copied , n ) ;
+ bytes_copied += n ;
+ Length -= n ;
+ Node->write_point = ( Node->write_point + n ) % Node->size ;
+ }
+
+ /* if there is an overflow, reset the read point to read whatever is
+ * the oldest data that we have, that has not yet been
+ * overwritten. */
+ if ( overflow )
+ {
+ Node->read_point = ( Node->write_point + 1 ) % Node->size ;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** PRINTING UTILITY (START)
+ **
+ *******************************************************************************/
+
+/*******************************************************************************
+ **
+ ** _GetArgumentSize
+ **
+ **
+ *******************************************************************************/
+static gctINT
+_GetArgumentSize (
+ IN gctCONST_STRING Message
+ )
+{
+ gctINT i , count ;
+
+ for ( i = 0 , count = 0 ; Message[i] ; i += 1 )
+ {
+ if ( Message[i] == '%' )
+ {
+ count += 1 ;
+ }
+ }
+ return count * sizeof (unsigned int ) ;
+}
+
+/*******************************************************************************
+ **
+ ** _AppendString
+ **
+ **
+ *******************************************************************************/
+static ssize_t
+_AppendString (
+ IN gcsDEBUGFS_Node* Node,
+ IN gctCONST_STRING String,
+ IN int Length
+ )
+{
+ int n;
+ unsigned long flags;
+
+ /* if the message is longer than the buffer, just take the beginning
+ * of it, in hopes that the reader (if any) will have time to read
+ * before we wrap around and obliterate it */
+ n = gcmkMIN ( Length , Node->size - 1 );
+
+ spin_lock_irqsave(&traceLock, flags);
+
+ /* now copy it into the circular buffer and free our temp copy */
+ _WriteToNode ( Node , (caddr_t)String , n ) ;
+
+ spin_unlock_irqrestore(&traceLock, flags);
+
+ return n ;
+}
+
+/*******************************************************************************
+ **
+ ** _DebugFSPrint
+ **
+ **
+ *******************************************************************************/
+static ssize_t
+_DebugFSPrint (
+ IN unsigned int ArgumentSize ,
+ IN const char* Message ,
+ IN gctDBGARGS * Arguments
+
+ )
+{
+ char buffer[MAX_LINE_SIZE] ;
+ int len ;
+ ssize_t res=0;
+
+ len = vsnprintf ( buffer , sizeof (buffer ) , Message , *( va_list * ) Arguments ) ;
+
+ buffer[len] = '\0' ;
+
+ /* Add end-of-line if missing. */
+ if ( buffer[len - 1] != '\n' )
+ {
+ buffer[len ++] = '\n' ;
+ buffer[len] = '\0' ;
+ }
+
+ res = _AppendString ( gc_dbgfs.currentNode , buffer , len ) ;
+
+ wake_up_interruptible ( gcmkNODE_READQ ( gc_dbgfs.currentNode ) ) ; /* blocked in read*/
+
+ return res;
+}
+
+/*******************************************************************************
+ **
+ ** LINUX SYSTEM FUNCTIONS (START)
+ **
+ *******************************************************************************/
+static int
+_DebugFSOpen (
+ struct inode* inode,
+ struct file* filp
+ )
+{
+ filp->private_data = inode->i_private;
+
+ return 0;
+}
+
+/*******************************************************************************
+ **
+ ** _DebugFSRead
+ **
+ *******************************************************************************/
+static ssize_t
+_DebugFSRead (
+ struct file *file,
+ char __user * buffer,
+ size_t length,
+ loff_t * offset
+ )
+{
+ int retval;
+ caddr_t data_to_return;
+ unsigned long flags;
+ gcsDEBUGFS_Node* node = file->private_data;
+
+ if (node == NULL)
+ {
+ printk ( "debugfs_read: record not found\n" );
+ return - EIO ;
+ }
+
+ spin_lock_irqsave(&traceLock, flags);
+
+ /* wait until there's data available (unless we do nonblocking reads) */
+ while (!gcmkNODE_QLEN(node))
+ {
+ spin_unlock_irqrestore(&traceLock, flags);
+
+ if (file->f_flags & O_NONBLOCK)
+ {
+ return - EAGAIN ;
+ }
+
+ if (wait_event_interruptible((*(gcmkNODE_READQ(node))) , (*offset < gcmkNODE_FIRST_EMPTY_BYTE(node))))
+ {
+ return - ERESTARTSYS ; /* signal: tell the fs layer to handle it */
+ }
+
+ spin_lock_irqsave(&traceLock, flags);
+ }
+
+ data_to_return = _ReadFromNode(node , &length , offset);
+
+ spin_unlock_irqrestore(&traceLock, flags);
+
+ if (data_to_return == NULL)
+ {
+ retval = 0;
+ goto unlock;
+ }
+
+ if (copy_to_user(buffer, data_to_return, length) > 0)
+ {
+ retval = - EFAULT;
+ }
+ else
+ {
+ retval = length;
+ }
+unlock:
+
+ wake_up_interruptible(gcmkNODE_WRITEQ(node));
+ return retval ;
+}
+
+/*******************************************************************************
+ **
+ **_DebugFSWrite
+ **
+ *******************************************************************************/
+static ssize_t
+_DebugFSWrite (
+ struct file *file ,
+ const char __user * buffer ,
+ size_t length ,
+ loff_t * offset
+ )
+{
+ caddr_t message = NULL ;
+ int n ;
+ gcsDEBUGFS_Node* node = file->private_data;
+
+ /* get the metadata about this log */
+ if (node == NULL)
+ {
+ return - EIO ;
+ }
+
+ if ( down_interruptible ( gcmkNODE_SEM ( node ) ) )
+ {
+ return - ERESTARTSYS ;
+ }
+
+ /* if the message is longer than the buffer, just take the beginning
+ * of it, in hopes that the reader (if any) will have time to read
+ * before we wrap around and obliterate it */
+ n = gcmkMIN ( length , node->size - 1 ) ;
+
+ /* make sure we have the memory for it */
+ if ( ( message = kmalloc ( n , GFP_KERNEL ) ) == NULL )
+ {
+ up ( gcmkNODE_SEM ( node ) ) ;
+ return - ENOMEM ;
+ }
+
+
+ /* copy into our temp buffer */
+ if ( copy_from_user ( message , buffer , n ) > 0 )
+ {
+ up ( gcmkNODE_SEM ( node ) ) ;
+ kfree ( message ) ;
+ return - EFAULT ;
+ }
+
+ /* now copy it into the circular buffer and free our temp copy */
+ _WriteToNode ( node , message , n ) ;
+
+ kfree ( message ) ;
+ up ( gcmkNODE_SEM ( node ) ) ;
+
+ /* wake up any readers that might be waiting for the data. we call
+ * schedule in the vague hope that a reader will run before the
+ * writer's next write, to avoid losing data. */
+ wake_up_interruptible ( gcmkNODE_READQ ( node ) ) ;
+
+ return n ;
+}
+
+/*******************************************************************************
+ **
+ ** File Operations Table
+ **
+ *******************************************************************************/
+static const struct file_operations debugfs_operations = {
+ .owner = THIS_MODULE ,
+ .open = _DebugFSOpen ,
+ .read = _DebugFSRead ,
+ .write = _DebugFSWrite ,
+} ;
+
+/*******************************************************************************
+ **
+ ** INTERFACE FUNCTIONS (START)
+ **
+ *******************************************************************************/
+
+/*******************************************************************************
+ **
+ ** gckDEBUGFS_IsEnabled
+ **
+ **
+ ** INPUT:
+ **
+ ** OUTPUT:
+ **
+ *******************************************************************************/
+
+
+gctINT
+gckDEBUGFS_IsEnabled ( void )
+{
+ return gc_dbgfs.isInited ;
+}
+/*******************************************************************************
+ **
+ ** gckDEBUGFS_Initialize
+ **
+ **
+ ** INPUT:
+ **
+ ** OUTPUT:
+ **
+ *******************************************************************************/
+
+gctINT
+gckDEBUGFS_Initialize ( void )
+{
+ if ( ! gc_dbgfs.isInited )
+ {
+ gc_dbgfs.linkedlist = gcvNULL ;
+ gc_dbgfs.currentNode = gcvNULL ;
+ gc_dbgfs.isInited = 1 ;
+ }
+ return gc_dbgfs.isInited ;
+}
+/*******************************************************************************
+ **
+ ** gckDEBUGFS_Terminate
+ **
+ **
+ ** INPUT:
+ **
+ ** OUTPUT:
+ **
+ *******************************************************************************/
+
+gctINT
+gckDEBUGFS_Terminate ( void )
+{
+ gcsDEBUGFS_Node * next = gcvNULL ;
+ gcsDEBUGFS_Node * temp = gcvNULL ;
+ if ( gc_dbgfs.isInited )
+ {
+ temp = gc_dbgfs.linkedlist ;
+ while ( temp != gcvNULL )
+ {
+ next = temp->next ;
+ gckDEBUGFS_FreeNode ( temp ) ;
+ kfree ( temp ) ;
+ temp = next ;
+ }
+ gc_dbgfs.isInited = 0 ;
+ }
+ return 0 ;
+}
+
+
+/*******************************************************************************
+ **
+ ** gckDEBUGFS_CreateNode
+ **
+ **
+ ** INPUT:
+ **
+ ** OUTPUT:
+ **
+ ** gckDEBUGFS_FreeNode * Device
+ ** Pointer to a variable receiving the gcsDEBUGFS_Node object pointer on
+ ** success.
+ *********************************************************************************/
+
+gctINT
+gckDEBUGFS_CreateNode (
+ IN gctPOINTER Device,
+ IN gctINT SizeInKB ,
+ IN struct dentry * Root ,
+ IN gctCONST_STRING NodeName ,
+ OUT gcsDEBUGFS_Node **Node
+ )
+{
+ gcsDEBUGFS_Node*node ;
+ /* allocate space for our metadata and initialize it */
+ if ( ( node = kmalloc ( sizeof (gcsDEBUGFS_Node ) , GFP_KERNEL ) ) == NULL )
+ goto struct_malloc_failed ;
+
+ /*Zero it out*/
+ memset ( node , 0 , sizeof (gcsDEBUGFS_Node ) ) ;
+
+ /*Init the sync primitives*/
+#if defined(DECLARE_WAIT_QUEUE_HEAD)
+ init_waitqueue_head ( gcmkNODE_READQ ( node ) ) ;
+#else
+ init_waitqueue ( gcmkNODE_READQ ( node ) ) ;
+#endif
+
+#if defined(DECLARE_WAIT_QUEUE_HEAD)
+ init_waitqueue_head ( gcmkNODE_WRITEQ ( node ) ) ;
+#else
+ init_waitqueue ( gcmkNODE_WRITEQ ( node ) ) ;
+#endif
+ sema_init ( gcmkNODE_SEM ( node ) , 1 ) ;
+ /*End the sync primitives*/
+
+ /*creating the debug file system*/
+ node->parent = Root;
+
+ if (SizeInKB)
+ {
+ /* figure out how much of a buffer this should be and allocate the buffer */
+ node->size = 1024 * SizeInKB ;
+ if ( ( node->data = ( char * ) vmalloc ( sizeof (char ) * node->size ) ) == NULL )
+ goto data_malloc_failed ;
+
+ node->tempSize = 0;
+ node->temp = NULL;
+
+ /*creating the file*/
+ node->filen = debugfs_create_file(NodeName, S_IRUGO|S_IWUSR, node->parent, node,
+ &debugfs_operations);
+ }
+
+ /* add it to our linked list */
+ node->next = gc_dbgfs.linkedlist ;
+ gc_dbgfs.linkedlist = node ;
+
+
+ /* pass the struct back */
+ *Node = node ;
+ return 0 ;
+
+
+data_malloc_failed:
+ kfree ( node ) ;
+struct_malloc_failed:
+ return - ENOMEM ;
+}
+
+/*******************************************************************************
+ **
+ ** gckDEBUGFS_FreeNode
+ **
+ **
+ ** INPUT:
+ **
+ ** OUTPUT:
+ **
+ *******************************************************************************/
+void
+gckDEBUGFS_FreeNode (
+ IN gcsDEBUGFS_Node * Node
+ )
+{
+
+ gcsDEBUGFS_Node **ptr ;
+
+ if ( Node == NULL )
+ {
+ printk ( "null passed to free_vinfo\n" ) ;
+ return ;
+ }
+
+ down ( gcmkNODE_SEM ( Node ) ) ;
+ /*free data*/
+ vfree ( Node->data ) ;
+
+ kfree(Node->temp);
+
+ /*Close Debug fs*/
+ if ( Node->filen )
+ {
+ debugfs_remove ( Node->filen ) ;
+ }
+
+ /* now delete the node from the linked list */
+ ptr = & ( gc_dbgfs.linkedlist ) ;
+ while ( *ptr != Node )
+ {
+ if ( ! *ptr )
+ {
+ printk ( "corrupt info list!\n" ) ;
+ break ;
+ }
+ else
+ ptr = & ( ( **ptr ).next ) ;
+ }
+ *ptr = Node->next ;
+ up ( gcmkNODE_SEM ( Node ) ) ;
+}
+
+/*******************************************************************************
+ **
+ ** gckDEBUGFS_SetCurrentNode
+ **
+ **
+ ** INPUT:
+ **
+ ** OUTPUT:
+ **
+ *******************************************************************************/
+void
+gckDEBUGFS_SetCurrentNode (
+ IN gcsDEBUGFS_Node * Node
+ )
+{
+ gc_dbgfs.currentNode = Node ;
+}
+
+/*******************************************************************************
+ **
+ ** gckDEBUGFS_GetCurrentNode
+ **
+ **
+ ** INPUT:
+ **
+ ** OUTPUT:
+ **
+ *******************************************************************************/
+void
+gckDEBUGFS_GetCurrentNode (
+ OUT gcsDEBUGFS_Node ** Node
+ )
+{
+ *Node = gc_dbgfs.currentNode ;
+}
+
+/*******************************************************************************
+ **
+ ** gckDEBUGFS_Print
+ **
+ **
+ ** INPUT:
+ **
+ ** OUTPUT:
+ **
+ *******************************************************************************/
+ssize_t
+gckDEBUGFS_Print (
+ IN gctCONST_STRING Message ,
+ ...
+ )
+{
+ ssize_t _debugfs_res;
+ gcmkDEBUGFS_PRINT ( _GetArgumentSize ( Message ) , Message ) ;
+ return _debugfs_res;
+}
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debugfs.h b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debugfs.h
new file mode 100644
index 000000000000..14a3324442a9
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_debugfs.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include <stdarg.h>
+
+#ifndef __gc_hal_kernel_debugfs_h_
+#define __gc_hal_kernel_debugfs_h_
+
+ #define MAX_LINE_SIZE 768 /* Max bytes for a line of debug info */
+
+
+ typedef struct _gcsDEBUGFS_Node gcsDEBUGFS_Node;
+
+typedef struct _gcsDEBUGFS_DIR *gckDEBUGFS_DIR;
+typedef struct _gcsDEBUGFS_DIR
+{
+ struct dentry * root;
+ struct list_head nodeList;
+}
+gcsDEBUGFS_DIR;
+
+typedef struct _gcsINFO
+{
+ const char * name;
+ int (*show)(struct seq_file*, void*);
+ int (*write)(const char __user *buf, size_t count, void*);
+}
+gcsINFO;
+
+typedef struct _gcsINFO_NODE
+{
+ gcsINFO * info;
+ gctPOINTER device;
+ struct dentry * entry;
+ struct list_head head;
+}
+gcsINFO_NODE;
+
+gceSTATUS
+gckDEBUGFS_DIR_Init(
+ IN gckDEBUGFS_DIR Dir,
+ IN struct dentry *root,
+ IN gctCONST_STRING Name
+ );
+
+gceSTATUS
+gckDEBUGFS_DIR_CreateFiles(
+ IN gckDEBUGFS_DIR Dir,
+ IN gcsINFO * List,
+ IN int count,
+ IN gctPOINTER Data
+ );
+
+gceSTATUS
+gckDEBUGFS_DIR_RemoveFiles(
+ IN gckDEBUGFS_DIR Dir,
+ IN gcsINFO * List,
+ IN int count
+ );
+
+void
+gckDEBUGFS_DIR_Deinit(
+ IN gckDEBUGFS_DIR Dir
+ );
+
+/*******************************************************************************
+ **
+ ** System Related
+ **
+ *******************************************************************************/
+
+gctINT gckDEBUGFS_IsEnabled(void);
+
+gctINT gckDEBUGFS_Initialize(void);
+
+gctINT gckDEBUGFS_Terminate(void);
+
+
+/*******************************************************************************
+ **
+ ** Node Related
+ **
+ *******************************************************************************/
+
+gctINT
+gckDEBUGFS_CreateNode(
+ IN gctPOINTER Device,
+ IN gctINT SizeInKB,
+ IN struct dentry * Root,
+ IN gctCONST_STRING NodeName,
+ OUT gcsDEBUGFS_Node **Node
+ );
+
+void gckDEBUGFS_FreeNode(
+ IN gcsDEBUGFS_Node * Node
+ );
+
+
+
+void gckDEBUGFS_SetCurrentNode(
+ IN gcsDEBUGFS_Node * Node
+ );
+
+
+
+void gckDEBUGFS_GetCurrentNode(
+ OUT gcsDEBUGFS_Node ** Node
+ );
+
+
+ssize_t gckDEBUGFS_Print(
+ IN gctCONST_STRING Message,
+ ...
+ );
+
+#endif
+
+
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c
new file mode 100644
index 000000000000..c69dd5c9f18b
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c
@@ -0,0 +1,2288 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <linux/slab.h>
+
+#define _GC_OBJ_ZONE gcvZONE_DEVICE
+
+#define DEBUG_FILE "galcore_trace"
+#define PARENT_FILE "gpu"
+
+#define gcdDEBUG_FS_WARN "Experimental debug entry, may be removed in future release, do NOT rely on it!\n"
+
+static gckGALDEVICE galDevice;
+
+extern gcTA globalTA[16];
+
+/******************************************************************************\
+******************************** Debugfs Support *******************************
+\******************************************************************************/
+
+/******************************************************************************\
+***************************** DEBUG SHOW FUNCTIONS *****************************
+\******************************************************************************/
+
+int gc_info_show(struct seq_file* m, void* data)
+{
+ gcsINFO_NODE *node = m->private;
+ gckGALDEVICE device = node->device;
+ int i = 0;
+ gceCHIPMODEL chipModel;
+ gctUINT32 chipRevision;
+ gctUINT32 productID = 0;
+ gctUINT32 ecoID = 0;
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (device->irqLines[i] != -1)
+ {
+#if gcdENABLE_VG
+ if (i == gcvCORE_VG)
+ {
+ chipModel = device->kernels[i]->vg->hardware->chipModel;
+ chipRevision = device->kernels[i]->vg->hardware->chipRevision;
+ }
+ else
+#endif
+ {
+ chipModel = device->kernels[i]->hardware->identity.chipModel;
+ chipRevision = device->kernels[i]->hardware->identity.chipRevision;
+ productID = device->kernels[i]->hardware->identity.productID;
+ ecoID = device->kernels[i]->hardware->identity.ecoID;
+ }
+
+ seq_printf(m, "gpu : %d\n", i);
+ seq_printf(m, "model : %4x\n", chipModel);
+ seq_printf(m, "revision : %4x\n", chipRevision);
+ seq_printf(m, "product : %4x\n", productID);
+ seq_printf(m, "eco : %4x\n", ecoID);
+ seq_printf(m, "\n");
+ }
+ }
+
+ return 0;
+}
+
+int gc_clients_show(struct seq_file* m, void* data)
+{
+ gcsINFO_NODE *node = m->private;
+ gckGALDEVICE device = node->device;
+
+ gckKERNEL kernel = _GetValidKernel(device);
+
+ gcsDATABASE_PTR database;
+ gctINT i, pid;
+ char name[24];
+
+ seq_printf(m, "%-8s%s\n", "PID", "NAME");
+ seq_printf(m, "------------------------\n");
+
+ /* Acquire the database mutex. */
+ gcmkVERIFY_OK(
+ gckOS_AcquireMutex(kernel->os, kernel->db->dbMutex, gcvINFINITE));
+
+ /* Walk the databases. */
+ for (i = 0; i < gcmCOUNTOF(kernel->db->db); ++i)
+ {
+ for (database = kernel->db->db[i];
+ database != gcvNULL;
+ database = database->next)
+ {
+ pid = database->processID;
+
+ gcmkVERIFY_OK(gckOS_GetProcessNameByPid(pid, gcmSIZEOF(name), name));
+
+ seq_printf(m, "%-8d%s\n", pid, name);
+ }
+ }
+
+ /* Release the database mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(kernel->os, kernel->db->dbMutex));
+
+ /* Success. */
+ return 0;
+}
+
+static void
+_CounterAdd(
+ gcsDATABASE_COUNTERS * Dest,
+ gcsDATABASE_COUNTERS * Src
+ )
+{
+ Dest->bytes += Src->bytes;
+ Dest->maxBytes += Src->maxBytes;
+ Dest->totalBytes += Src->totalBytes;
+}
+
+static void
+_CounterPrint(
+ gcsDATABASE_COUNTERS * Counter,
+ gctCONST_STRING Name,
+ struct seq_file* m
+ )
+{
+ seq_printf(m, " %s:\n", Name);
+ seq_printf(m, " Used : %10llu B\n", Counter->bytes);
+}
+
+int gc_meminfo_show(struct seq_file* m, void* data)
+{
+ gcsINFO_NODE *node = m->private;
+ gckGALDEVICE device = node->device;
+ gckKERNEL kernel = _GetValidKernel(device);
+ gckVIDMEM memory;
+ gceSTATUS status;
+ gcsDATABASE_PTR database;
+ gctUINT32 i;
+
+ gctUINT32 free = 0, used = 0, total = 0, minFree = 0, maxUsed = 0;
+
+ gcsDATABASE_COUNTERS contiguousCounter = {0, 0, 0};
+ gcsDATABASE_COUNTERS virtualCounter = {0, 0, 0};
+ gcsDATABASE_COUNTERS nonPagedCounter = {0, 0, 0};
+
+ status = gckKERNEL_GetVideoMemoryPool(kernel, gcvPOOL_SYSTEM, &memory);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ gcmkVERIFY_OK(
+ gckOS_AcquireMutex(memory->os, memory->mutex, gcvINFINITE));
+
+ free = memory->freeBytes;
+ minFree = memory->minFreeBytes;
+ used = memory->bytes - memory->freeBytes;
+ maxUsed = memory->bytes - memory->minFreeBytes;
+ total = memory->bytes;
+
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(memory->os, memory->mutex));
+ }
+
+ seq_printf(m, "VIDEO MEMORY:\n");
+ seq_printf(m, " gcvPOOL_SYSTEM:\n");
+ seq_printf(m, " Free : %10u B\n", free);
+ seq_printf(m, " Used : %10u B\n", used);
+ seq_printf(m, " MinFree : %10u B\n", minFree);
+ seq_printf(m, " MaxUsed : %10u B\n", maxUsed);
+ seq_printf(m, " Total : %10u B\n", total);
+
+ /* Acquire the database mutex. */
+ gcmkVERIFY_OK(
+ gckOS_AcquireMutex(kernel->os, kernel->db->dbMutex, gcvINFINITE));
+
+ /* Walk the databases. */
+ for (i = 0; i < gcmCOUNTOF(kernel->db->db); ++i)
+ {
+ for (database = kernel->db->db[i];
+ database != gcvNULL;
+ database = database->next)
+ {
+ gcsDATABASE_COUNTERS * counter = &database->vidMemPool[gcvPOOL_CONTIGUOUS];
+ _CounterAdd(&contiguousCounter, counter);
+
+ counter = &database->vidMemPool[gcvPOOL_VIRTUAL];
+ _CounterAdd(&virtualCounter, counter);
+
+
+ counter = &database->nonPaged;
+ _CounterAdd(&nonPagedCounter, counter);
+ }
+ }
+
+ /* Release the database mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(kernel->os, kernel->db->dbMutex));
+
+ _CounterPrint(&contiguousCounter, "gcvPOOL_CONTIGUOUS", m);
+ _CounterPrint(&virtualCounter, "gcvPOOL_VIRTUAL", m);
+
+ seq_printf(m, "\n");
+
+ seq_printf(m, "NON PAGED MEMORY:\n");
+ seq_printf(m, " Used : %10llu B\n", nonPagedCounter.bytes);
+
+ return 0;
+}
+
+static int
+_ShowRecord(
+ IN struct seq_file *File,
+ IN gcsDATABASE_RECORD_PTR Record
+ )
+{
+ static const char * recordTypes[gcvDB_NUM_TYPES] = {
+ "Unknown",
+ "VideoMemory",
+ "CommandBuffer",
+ "NonPaged",
+ "Contiguous",
+ "Signal",
+ "VidMemLock",
+ "Context",
+ "Idel",
+ "MapMemory",
+ "MapUserMemory",
+ "ShBuf",
+ };
+
+ seq_printf(File, "%-14s %3d %16p %16zu %16zu\n",
+ recordTypes[Record->type],
+ Record->kernel->core,
+ Record->data,
+ (size_t) Record->physical,
+ Record->bytes
+ );
+
+ return 0;
+}
+
+static int
+_ShowRecords(
+ IN struct seq_file *File,
+ IN gcsDATABASE_PTR Database
+ )
+{
+ gctUINT i;
+
+ seq_printf(File, "Records:\n");
+
+ seq_printf(File, "%14s %3s %16s %16s %16s\n",
+ "Type", "GPU", "Data/Node", "Physical/Node", "Bytes");
+
+ for (i = 0; i < gcmCOUNTOF(Database->list); i++)
+ {
+ gcsDATABASE_RECORD_PTR record = Database->list[i];
+
+ while (record != NULL)
+ {
+ _ShowRecord(File, record);
+ record = record->next;
+ }
+ }
+
+ return 0;
+}
+
+static void
+_ShowCounters(
+ struct seq_file *File,
+ gcsDATABASE_PTR Database
+ )
+{
+ gctUINT i = 0;
+
+ static const char * surfaceTypes[gcvSURF_NUM_TYPES] = {
+ "Unknown",
+ "Index",
+ "Vertex",
+ "Texture",
+ "RenderTarget",
+ "Depth",
+ "Bitmap",
+ "TileStatus",
+ "Image",
+ "Mask",
+ "Scissor",
+ "HZ",
+ "ICache",
+ "TxDesc",
+ "Fence",
+ "TFBHeader",
+ };
+
+ static const char * poolTypes[gcvPOOL_NUMBER_OF_POOLS] = {
+ "Unknown",
+ "Default",
+ "Local",
+ "Internal",
+ "External",
+ "Unified",
+ "System",
+ "Virtual",
+ "User",
+ "Contiguous",
+ };
+
+ static const char * otherCounterNames[] = {
+ "AllocNonPaged",
+ "AllocContiguous",
+ "MapUserMemory",
+ "MapMemory",
+ };
+
+ gcsDATABASE_COUNTERS * otherCounters[] = {
+ &Database->nonPaged,
+ &Database->contiguous,
+ &Database->mapUserMemory,
+ &Database->mapMemory,
+ };
+
+ seq_printf(File, "%-16s %16s %16s %16s\n", "", "Current", "Maximum", "Total");
+
+ /* Print surface type counters. */
+ seq_printf(File, "%-16s %16lld %16lld %16lld\n",
+ "All-Types",
+ Database->vidMem.bytes,
+ Database->vidMem.maxBytes,
+ Database->vidMem.totalBytes);
+
+ for (i = 1; i < gcvSURF_NUM_TYPES; i++)
+ {
+ seq_printf(File, "%-16s %16lld %16lld %16lld\n",
+ surfaceTypes[i],
+ Database->vidMemType[i].bytes,
+ Database->vidMemType[i].maxBytes,
+ Database->vidMemType[i].totalBytes);
+ }
+ seq_puts(File, "\n");
+
+ /* Print surface pool counters. */
+ seq_printf(File, "%-16s %16lld %16lld %16lld\n",
+ "All-Pools",
+ Database->vidMem.bytes,
+ Database->vidMem.maxBytes,
+ Database->vidMem.totalBytes);
+
+ for (i = 1; i < gcvPOOL_NUMBER_OF_POOLS; i++)
+ {
+ seq_printf(File, "%-16s %16lld %16lld %16lld\n",
+ poolTypes[i],
+ Database->vidMemPool[i].bytes,
+ Database->vidMemPool[i].maxBytes,
+ Database->vidMemPool[i].totalBytes);
+ }
+ seq_puts(File, "\n");
+
+ /* Print other counters. */
+ for (i = 0; i < gcmCOUNTOF(otherCounterNames); i++)
+ {
+ seq_printf(File, "%-16s %16lld %16lld %16lld\n",
+ otherCounterNames[i],
+ otherCounters[i]->bytes,
+ otherCounters[i]->maxBytes,
+ otherCounters[i]->totalBytes);
+ }
+ seq_puts(File, "\n");
+}
+
+static void
+_ShowProcess(
+ IN struct seq_file *File,
+ IN gcsDATABASE_PTR Database
+ )
+{
+ gctINT pid;
+ char name[24];
+
+ /* Process ID and name */
+ pid = Database->processID;
+ gcmkVERIFY_OK(gckOS_GetProcessNameByPid(pid, gcmSIZEOF(name), name));
+
+ seq_printf(File, "--------------------------------------------------------------------------------\n");
+ seq_printf(File, "Process: %-8d %s\n", pid, name);
+
+ /* Detailed records */
+ _ShowRecords(File, Database);
+
+ seq_printf(File, "Counters:\n");
+
+ _ShowCounters(File, Database);
+}
+
+static void
+_ShowProcesses(
+ IN struct seq_file * File,
+ IN gckKERNEL Kernel
+ )
+{
+ gcsDATABASE_PTR database;
+ gctINT i;
+ static gctUINT64 idleTime = 0;
+
+ /* Acquire the database mutex. */
+ gcmkVERIFY_OK(
+ gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE));
+
+ if (Kernel->db->idleTime)
+ {
+ /* Record idle time if DB upated. */
+ idleTime = Kernel->db->idleTime;
+ Kernel->db->idleTime = 0;
+ }
+
+ /* Idle time since last call */
+ seq_printf(File, "GPU Idle: %llu ns\n", idleTime);
+
+ /* Walk the databases. */
+ for (i = 0; i < gcmCOUNTOF(Kernel->db->db); ++i)
+ {
+ for (database = Kernel->db->db[i];
+ database != gcvNULL;
+ database = database->next)
+ {
+ _ShowProcess(File, database);
+ }
+ }
+
+ /* Release the database mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex));
+}
+
+static int
+gc_db_show(struct seq_file *m, void *data)
+{
+ gcsINFO_NODE *node = m->private;
+ gckGALDEVICE device = node->device;
+ gckKERNEL kernel = _GetValidKernel(device);
+ _ShowProcesses(m, kernel);
+ return 0 ;
+}
+
+static int
+gc_version_show(struct seq_file *m, void *data)
+{
+ gcsINFO_NODE *node = m->private;
+ gckGALDEVICE device = node->device;
+ gcsPLATFORM * platform = device->platform;
+
+ seq_printf(m, "%s built at %s\n", gcvVERSION_STRING, HOST);
+
+ if (platform->name)
+ {
+ seq_printf(m, "Platform path: %s\n", platform->name);
+ }
+ else
+ {
+ seq_printf(m, "Code path: %s\n", __FILE__);
+ }
+
+ return 0 ;
+}
+
+/*******************************************************************************
+**
+** Show PM state timer.
+**
+** Entry is called as 'idle' for compatible reason, it shows more information
+** than idle actually.
+**
+** Start: Start time of this counting period.
+** End: End time of this counting peroid.
+** On: Time GPU stays in gcvPOWER_0N.
+** Off: Time GPU stays in gcvPOWER_0FF.
+** Idle: Time GPU stays in gcvPOWER_IDLE.
+** Suspend: Time GPU stays in gcvPOWER_SUSPEND.
+*/
+static int
+gc_idle_show(struct seq_file *m, void *data)
+{
+ gcsINFO_NODE *node = m->private;
+ gckGALDEVICE device = node->device;
+ gckKERNEL kernel = _GetValidKernel(device);
+
+ gctUINT64 start;
+ gctUINT64 end;
+ gctUINT64 on;
+ gctUINT64 off;
+ gctUINT64 idle;
+ gctUINT64 suspend;
+
+ gckHARDWARE_QueryStateTimer(kernel->hardware, &start, &end, &on, &off, &idle, &suspend);
+
+ /* Idle time since last call */
+ seq_printf(m, "Start: %llu ns\n", start);
+ seq_printf(m, "End: %llu ns\n", end);
+ seq_printf(m, "On: %llu ns\n", on);
+ seq_printf(m, "Off: %llu ns\n", off);
+ seq_printf(m, "Idle: %llu ns\n", idle);
+ seq_printf(m, "Suspend: %llu ns\n", suspend);
+
+ return 0 ;
+}
+
+extern void
+_DumpState(
+ IN gckKERNEL Kernel
+ );
+
+/*******************************************************************************
+**
+** Show PM state timer.
+**
+** Entry is called as 'idle' for compatible reason, it shows more information
+** than idle actually.
+**
+** Start: Start time of this counting period.
+** End: End time of this counting peroid.
+** On: Time GPU stays in gcvPOWER_0N.
+** Off: Time GPU stays in gcvPOWER_0FF.
+** Idle: Time GPU stays in gcvPOWER_IDLE.
+** Suspend: Time GPU stays in gcvPOWER_SUSPEND.
+*/
+
+static int dumpCore = 0;
+
+static int
+gc_dump_trigger_show(struct seq_file *m, void *data)
+{
+#if gcdENABLE_3D || gcdENABLE_2D
+ gcsINFO_NODE *node = m->private;
+ gckGALDEVICE device = node->device;
+ gckKERNEL kernel = gcvNULL;
+
+ if (dumpCore >= gcvCORE_MAJOR && dumpCore < gcvCORE_COUNT)
+ {
+ kernel = device->kernels[dumpCore];
+ }
+#endif
+
+ seq_printf(m, gcdDEBUG_FS_WARN);
+
+#if gcdENABLE_3D || gcdENABLE_2D
+ seq_printf(m, "Get dump from /proc/kmsg or /sys/kernel/debug/gc/galcore_trace\n");
+
+ if (kernel && kernel->hardware->options.powerManagement == gcvFALSE)
+ {
+ _DumpState(kernel);
+ }
+#endif
+
+ return 0;
+}
+
+static int dumpProcess = 0;
+
+
+static int gc_vidmem_show(struct seq_file *m, void *unused)
+{
+ gceSTATUS status;
+ gcsDATABASE_PTR database;
+ gcsINFO_NODE *node = m->private;
+ gckGALDEVICE device = node->device;
+ char name[64];
+ int i;
+
+ gckKERNEL kernel = _GetValidKernel(device);
+
+ if (dumpProcess == 0)
+ {
+ /* Acquire the database mutex. */
+ gcmkVERIFY_OK(
+ gckOS_AcquireMutex(kernel->os, kernel->db->dbMutex, gcvINFINITE));
+
+ for (i = 0; i < gcmCOUNTOF(kernel->db->db); i++)
+ {
+ for (database = kernel->db->db[i];
+ database != gcvNULL;
+ database = database->next)
+ {
+ gckOS_GetProcessNameByPid(database->processID, gcmSIZEOF(name), name);
+ seq_printf(m, "VidMem Usage (Process %d: %s):\n", database->processID, name);
+ _ShowCounters(m, database);
+ seq_puts(m, "\n");
+ }
+ }
+
+ /* Release the database mutex. */
+ gcmkVERIFY_OK(gckOS_ReleaseMutex(kernel->os, kernel->db->dbMutex));
+ }
+ else
+ {
+ /* Find the database. */
+ status = gckKERNEL_FindDatabase(kernel, dumpProcess, gcvFALSE, &database);
+
+ if (gcmIS_ERROR(status))
+ {
+ seq_printf(m, "ERROR: process %d not found\n", dumpProcess);
+ return 0;
+ }
+
+ gckOS_GetProcessNameByPid(dumpProcess, gcmSIZEOF(name), name);
+ seq_printf(m, "VidMem Usage (Process %d: %s):\n", dumpProcess, name);
+ _ShowCounters(m, database);
+ }
+
+ return 0;
+}
+
+static inline int strtoint_from_user(const char __user *s,
+ size_t count, int *res)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)
+ int ret = kstrtoint_from_user(s, count, 10, res);
+
+ return ret < 0 ? ret : count;
+#else
+ /* sign, base 2 representation, newline, terminator */
+ char buf[1 + sizeof(long) * 8 + 1 + 1];
+
+ size_t len = min(count, sizeof(buf) - 1);
+
+ if (copy_from_user(buf, s, len))
+ return -EFAULT;
+ buf[len] = '\0';
+
+ *res = (int) simple_strtol(buf, NULL, 0);
+
+ return count;
+#endif
+}
+
+static int gc_vidmem_write(const char __user *buf, size_t count, void* data)
+{
+ return strtoint_from_user(buf, count, &dumpProcess);
+}
+
+static int gc_dump_trigger_write(const char __user *buf, size_t count, void* data)
+{
+ return strtoint_from_user(buf, count, &dumpCore);
+}
+
+static gcsINFO InfoList[] =
+{
+ {"info", gc_info_show},
+ {"clients", gc_clients_show},
+ {"meminfo", gc_meminfo_show},
+ {"idle", gc_idle_show},
+ {"database", gc_db_show},
+ {"version", gc_version_show},
+ {"vidmem", gc_vidmem_show, gc_vidmem_write},
+ {"dump_trigger", gc_dump_trigger_show, gc_dump_trigger_write},
+};
+
+static gceSTATUS
+_DebugfsInit(
+ IN gckGALDEVICE Device
+ )
+{
+ gceSTATUS status;
+
+ gckDEBUGFS_DIR dir = &Device->debugfsDir;
+
+ gcmkONERROR(gckDEBUGFS_DIR_Init(dir, gcvNULL, "gc"));
+
+ gcmkONERROR(gckDEBUGFS_DIR_CreateFiles(dir, InfoList, gcmCOUNTOF(InfoList), Device));
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+static void
+_DebugfsCleanup(
+ IN gckGALDEVICE Device
+ )
+{
+ gckDEBUGFS_DIR dir = &Device->debugfsDir;
+
+ if (Device->debugfsDir.root)
+ {
+ gcmkVERIFY_OK(gckDEBUGFS_DIR_RemoveFiles(dir, InfoList, gcmCOUNTOF(InfoList)));
+
+ gckDEBUGFS_DIR_Deinit(dir);
+ }
+}
+
+
+/******************************************************************************\
+*************************** Memory Allocation Wrappers *************************
+\******************************************************************************/
+
+static gceSTATUS
+_AllocateMemory(
+ IN gckGALDEVICE Device,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER *Logical,
+ OUT gctPHYS_ADDR *Physical,
+ OUT gctUINT32 *PhysAddr
+ )
+{
+ gceSTATUS status;
+ gctPHYS_ADDR_T physAddr;
+
+ gcmkHEADER_ARG("Device=0x%x Bytes=%lu", Device, Bytes);
+
+ gcmkVERIFY_ARGUMENT(Device != NULL);
+ gcmkVERIFY_ARGUMENT(Logical != NULL);
+ gcmkVERIFY_ARGUMENT(Physical != NULL);
+ gcmkVERIFY_ARGUMENT(PhysAddr != NULL);
+
+ gcmkONERROR(gckOS_AllocateContiguous(
+ Device->os, gcvFALSE, &Bytes, Physical, Logical
+ ));
+
+ gcmkONERROR(gckOS_GetPhysicalAddress(
+ Device->os, *Logical, &physAddr
+ ));
+
+ gcmkSAFECASTPHYSADDRT(*PhysAddr, physAddr);
+
+ /* Success. */
+ gcmkFOOTER_ARG(
+ "*Logical=0x%x *Physical=0x%x *PhysAddr=0x%08x",
+ *Logical, *Physical, *PhysAddr
+ );
+
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+_FreeMemory(
+ IN gckGALDEVICE Device,
+ IN gctPOINTER Logical,
+ IN gctPHYS_ADDR Physical)
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Device=0x%x Logical=0x%x Physical=0x%x",
+ Device, Logical, Physical);
+
+ gcmkVERIFY_ARGUMENT(Device != NULL);
+
+ status = gckOS_FreeContiguous(
+ Device->os, Physical, Logical,
+ ((PLINUX_MDL) Physical)->numPages * PAGE_SIZE
+ );
+
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+_SetupVidMem(
+ IN gckGALDEVICE Device,
+ IN gctUINT32 ContiguousBase,
+ IN gctSIZE_T ContiguousSize,
+ IN gctSIZE_T BankSize,
+ IN gcsDEVICE_CONSTRUCT_ARGS * Args
+ )
+{
+ gceSTATUS status;
+ gctUINT32 physAddr = ~0U;
+ gckGALDEVICE device = Device;
+
+ /* set up the contiguous memory */
+ device->contiguousBase = ContiguousBase;
+ device->contiguousSize = ContiguousSize;
+
+ if (ContiguousSize > 0)
+ {
+ if (ContiguousBase == 0)
+ {
+ while (device->contiguousSize > 0)
+ {
+ /* Allocate contiguous memory. */
+ status = _AllocateMemory(
+ device,
+ device->contiguousSize,
+ &device->contiguousLogical,
+ &device->contiguousPhysical,
+ &physAddr
+ );
+
+ if (gcmIS_SUCCESS(status))
+ {
+ status = gckVIDMEM_Construct(
+ device->os,
+ physAddr | device->systemMemoryBaseAddress,
+ device->contiguousSize,
+ 64,
+ BankSize,
+ &device->contiguousVidMem
+ );
+
+ if (gcmIS_SUCCESS(status))
+ {
+ device->contiguousVidMem->physical = device->contiguousPhysical;
+ device->contiguousBase = physAddr;
+ break;
+ }
+
+ gcmkONERROR(_FreeMemory(
+ device,
+ device->contiguousLogical,
+ device->contiguousPhysical
+ ));
+
+ device->contiguousLogical = gcvNULL;
+ device->contiguousPhysical = gcvNULL;
+ }
+
+ if (device->contiguousSize <= (4 << 20))
+ {
+ device->contiguousSize = 0;
+ }
+ else
+ {
+ device->contiguousSize -= (4 << 20);
+ }
+ }
+ }
+ else
+ {
+ /* Create the contiguous memory heap. */
+ status = gckVIDMEM_Construct(
+ device->os,
+ ContiguousBase | device->systemMemoryBaseAddress,
+ ContiguousSize,
+ 64, BankSize,
+ &device->contiguousVidMem
+ );
+
+ if (gcmIS_ERROR(status))
+ {
+ /* Error, disable contiguous memory pool. */
+ device->contiguousVidMem = gcvNULL;
+ device->contiguousSize = 0;
+ }
+ else
+ {
+ gcmkONERROR(gckOS_RequestReservedMemory(
+ device->os, ContiguousBase, ContiguousSize,
+ "galcore contiguous memory",
+ Args->contiguousRequested,
+ &device->contiguousPhysical
+ ));
+
+ device->contiguousVidMem->physical = device->contiguousPhysical;
+ device->requestedContiguousBase = ContiguousBase;
+ device->requestedContiguousSize = ContiguousSize;
+
+ device->contiguousPhysicalName = 0;
+ device->contiguousSize = ContiguousSize;
+ }
+ }
+ }
+
+ return gcvSTATUS_OK;
+OnError:
+ return status;
+}
+
+void
+_SetupRegisterPhysical(
+ IN gckGALDEVICE Device,
+ IN gcsDEVICE_CONSTRUCT_ARGS * Args
+ )
+{
+ gctINT *irqs = Args->irqs;
+ gctUINT *registerBases = Args->registerBases;
+ gctUINT *registerSizes = Args->registerSizes;
+
+ gctINT i = 0;
+
+ for (i = 0; i < gcvCORE_COUNT; i++)
+ {
+ if (irqs[i] != -1)
+ {
+ Device->requestedRegisterMemBases[i] = registerBases[i];
+ Device->requestedRegisterMemSizes[i] = registerSizes[i];
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, _GC_OBJ_ZONE,
+ "Get register base %llx of core %d",
+ registerBases[i], i);
+ }
+ }
+}
+
+/******************************************************************************\
+******************************* Interrupt Handler ******************************
+\******************************************************************************/
+static irqreturn_t isrRoutine(int irq, void *ctxt)
+{
+ gceSTATUS status;
+ gckGALDEVICE device;
+ gceCORE core = (gceCORE)gcmPTR2INT32(ctxt) - 1;
+
+ device = galDevice;
+
+ /* Call kernel interrupt notification. */
+ status = gckKERNEL_Notify(device->kernels[core], gcvNOTIFY_INTERRUPT, gcvTRUE);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ up(&device->semas[core]);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int threadRoutine(void *ctxt)
+{
+ gckGALDEVICE device = galDevice;
+ gceCORE core = (gceCORE) gcmPTR2INT32(ctxt);
+ gctUINT i;
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER,
+ "Starting isr Thread with extension=%p",
+ device);
+
+ if (core != gcvCORE_VG)
+ {
+ /* Make kernel update page table of this thread to include entry related to command buffer.*/
+ for (i = 0; i < gcdCOMMAND_QUEUES; i++)
+ {
+ gctUINT32 data = *(gctUINT32_PTR)device->kernels[core]->command->queues[i].logical;
+
+ data = 0;
+ }
+ }
+
+ for (;;)
+ {
+ static int down;
+
+ down = down_interruptible(&device->semas[core]);
+ if (down); /*To make gcc 4.6 happye*/
+
+ if (device->killThread == gcvTRUE)
+ {
+ /* The daemon exits. */
+ while (!kthread_should_stop())
+ {
+ gckOS_Delay(device->os, 1);
+ }
+
+ return 0;
+ }
+
+ gckKERNEL_Notify(device->kernels[core],
+ gcvNOTIFY_INTERRUPT,
+ gcvFALSE);
+ }
+}
+
+static irqreturn_t isrRoutineVG(int irq, void *ctxt)
+{
+#if gcdENABLE_VG
+ gceSTATUS status;
+ gckGALDEVICE device;
+
+ device = (gckGALDEVICE) ctxt;
+
+ /* Serve the interrupt. */
+ status = gckVGINTERRUPT_Enque(device->kernels[gcvCORE_VG]->vg->interrupt);
+
+ /* Determine the return value. */
+ return (status == gcvSTATUS_NOT_OUR_INTERRUPT)
+ ? IRQ_RETVAL(0)
+ : IRQ_RETVAL(1);
+#else
+ return IRQ_NONE;
+#endif
+}
+
+/******************************************************************************\
+******************************* gckGALDEVICE Code ******************************
+\******************************************************************************/
+
+static gceSTATUS
+_StartThread(
+ IN int (*ThreadRoutine)(void *data),
+ IN gceCORE Core
+ )
+{
+ gceSTATUS status;
+ gckGALDEVICE device = galDevice;
+ struct task_struct * task;
+
+ if (device->kernels[Core] != gcvNULL)
+ {
+ /* Start the kernel thread. */
+ task = kthread_run(ThreadRoutine, (void *)Core, "galcore deamon thread for core[%d]", Core);
+
+ if (IS_ERR(task))
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): Could not start the kernel thread.\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+ device->threadCtxts[Core] = task;
+ device->threadInitializeds[Core] = gcvTRUE;
+ }
+ else
+ {
+ device->threadInitializeds[Core] = gcvFALSE;
+ }
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckGALDEVICE_Construct
+**
+** Constructor.
+**
+** INPUT:
+**
+** OUTPUT:
+**
+** gckGALDEVICE * Device
+** Pointer to a variable receiving the gckGALDEVICE object pointer on
+** success.
+*/
+gceSTATUS
+gckGALDEVICE_Construct(
+ IN gctINT IrqLine,
+ IN gctUINT32 RegisterMemBase,
+ IN gctSIZE_T RegisterMemSize,
+ IN gctINT IrqLine2D,
+ IN gctUINT32 RegisterMemBase2D,
+ IN gctSIZE_T RegisterMemSize2D,
+ IN gctINT IrqLineVG,
+ IN gctUINT32 RegisterMemBaseVG,
+ IN gctSIZE_T RegisterMemSizeVG,
+ IN gctUINT32 ContiguousBase,
+ IN gctSIZE_T ContiguousSize,
+ IN gctUINT32 ExternalBase,
+ IN gctSIZE_T ExternalSize,
+ IN gctSIZE_T BankSize,
+ IN gctINT FastClear,
+ IN gctINT Compression,
+ IN gctUINT32 PhysBaseAddr,
+ IN gctUINT32 PhysSize,
+ IN gctINT Signal,
+ IN gctUINT LogFileSize,
+ IN gctINT PowerManagement,
+ IN gctINT GpuProfiler,
+ IN gcsDEVICE_CONSTRUCT_ARGS * Args,
+ OUT gckGALDEVICE *Device
+ )
+{
+ gctUINT32 internalBaseAddress = 0, internalAlignment = 0;
+ gctUINT32 externalAlignment = 0;
+ gctUINT32 physical;
+ gckGALDEVICE device;
+ gceSTATUS status;
+ gctINT32 i;
+ gceHARDWARE_TYPE type;
+ gckKERNEL kernel = gcvNULL;
+
+ gcmkHEADER_ARG("IrqLine=%d RegisterMemBase=0x%08x RegisterMemSize=%u "
+ "IrqLine2D=%d RegisterMemBase2D=0x%08x RegisterMemSize2D=%u "
+ "IrqLineVG=%d RegisterMemBaseVG=0x%08x RegisterMemSizeVG=%u "
+ "ContiguousBase=0x%08x ContiguousSize=%lu BankSize=%lu "
+ "FastClear=%d Compression=%d PhysBaseAddr=0x%x PhysSize=%d Signal=%d",
+ IrqLine, RegisterMemBase, RegisterMemSize,
+ IrqLine2D, RegisterMemBase2D, RegisterMemSize2D,
+ IrqLineVG, RegisterMemBaseVG, RegisterMemSizeVG,
+ ContiguousBase, ContiguousSize, BankSize, FastClear, Compression,
+ PhysBaseAddr, PhysSize, Signal);
+
+#if !gcdENABLE_3D
+ IrqLine = -1;
+#endif
+
+#if !gcdENABLE_2D
+ IrqLine2D = -1;
+#endif
+ /* Allocate device structure. */
+ device = kmalloc(sizeof(struct _gckGALDEVICE), GFP_KERNEL | __GFP_NOWARN);
+ if (!device)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ memset(device, 0, sizeof(struct _gckGALDEVICE));
+
+ device->dbgNode = gcvNULL;
+
+ device->platform = Args->platform;
+
+ device->args = *Args;
+
+ /* set up the contiguous memory */
+ device->contiguousSize = ContiguousSize;
+
+ /* Clear irq lines. */
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ device->irqLines[i] = -1;
+ }
+
+ gcmkONERROR(_DebugfsInit(device));
+
+ if (gckDEBUGFS_CreateNode(
+ device, LogFileSize, device->debugfsDir.root ,DEBUG_FILE, &(device->dbgNode)))
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): Failed to create the debug file system %s/%s \n",
+ __FUNCTION__, __LINE__,
+ PARENT_FILE, DEBUG_FILE
+ );
+ }
+ else if (LogFileSize)
+ {
+ gckDEBUGFS_SetCurrentNode(device->dbgNode);
+ }
+
+ _SetupRegisterPhysical(device, Args);
+
+ if (IrqLine != -1)
+ {
+ device->requestedRegisterMemBases[gcvCORE_MAJOR] = RegisterMemBase;
+ device->requestedRegisterMemSizes[gcvCORE_MAJOR] = RegisterMemSize;
+ }
+
+ if (IrqLine2D != -1)
+ {
+ device->requestedRegisterMemBases[gcvCORE_2D] = RegisterMemBase2D;
+ device->requestedRegisterMemSizes[gcvCORE_2D] = RegisterMemSize2D;
+ }
+
+ if (IrqLineVG != -1)
+ {
+ device->requestedRegisterMemBases[gcvCORE_VG] = RegisterMemBaseVG;
+ device->requestedRegisterMemSizes[gcvCORE_VG] = RegisterMemSizeVG;
+ }
+#if gcdDEC_ENABLE_AHB
+ {
+ device->requestedRegisterMemBases[gcvCORE_DEC] = Args->registerMemBaseDEC300;
+ device->requestedRegisterMemSizes[gcvCORE_DEC] = Args->registerMemSizeDEC300;
+ }
+#endif
+
+
+ for (i = gcvCORE_MAJOR; i < gcvCORE_COUNT; i++)
+ {
+ if (Args->irqs[i] != -1)
+ {
+ device->requestedRegisterMemBases[i] = Args->registerBases[i];
+ device->requestedRegisterMemSizes[i] = Args->registerSizes[i];
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DEVICE,
+ "%s(%d): Core = %d, RegiseterBase = %x",
+ __FUNCTION__, __LINE__,
+ i, Args->registerBases[i]
+ );
+ }
+ }
+
+ /* Initialize the ISR. */
+ device->irqLines[gcvCORE_MAJOR] = IrqLine;
+ device->irqLines[gcvCORE_2D] = IrqLine2D;
+ device->irqLines[gcvCORE_VG] = IrqLineVG;
+
+ for (i = gcvCORE_MAJOR; i < gcvCORE_COUNT; i++)
+ {
+ if (Args->irqs[i] != -1)
+ {
+ device->irqLines[i] = Args->irqs[i];
+ }
+ }
+
+ device->requestedContiguousBase = 0;
+ device->requestedContiguousSize = 0;
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ physical = device->requestedRegisterMemBases[i];
+
+ /* Set up register memory region. */
+ if (physical != 0)
+ {
+ if (Args->registerMemMapped)
+ {
+ device->registerBases[i] = Args->registerMemAddress;
+ device->requestedRegisterMemBases[i] = 0;
+
+ }
+ else
+ {
+#if USE_LINUX_PCIE
+ device->registerBases[i] = (gctPOINTER) pci_iomap(device->platform->device, 1,
+ device->requestedRegisterMemSizes[i]);
+#else
+ if (!request_mem_region(physical, device->requestedRegisterMemSizes[i], "galcore register region"))
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): Failed to claim %lu bytes @ 0x%zx\n",
+ __FUNCTION__, __LINE__,
+ physical, device->requestedRegisterMemSizes[i]
+ );
+
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+ device->registerBases[i] = (gctPOINTER)ioremap_nocache(
+ physical, device->requestedRegisterMemSizes[i]);
+#endif
+
+ if (device->registerBases[i] == gcvNULL)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): Unable to map %ld bytes @ 0x%08X\n",
+ __FUNCTION__, __LINE__,
+ physical, device->requestedRegisterMemSizes[i]
+ );
+
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+ }
+
+ physical += device->requestedRegisterMemSizes[i];
+ }
+ }
+
+ /* Set the base address */
+ device->baseAddress = device->physBase = PhysBaseAddr;
+ device->physSize = PhysSize;
+
+ /* Construct the gckOS object. */
+ gcmkONERROR(gckOS_Construct(device, &device->os));
+
+ /* Construct the gckDEVICE object for os independent core management. */
+ gcmkONERROR(gckDEVICE_Construct(device->os, &device->device));
+
+ if (device->irqLines[gcvCORE_MAJOR] != -1)
+ {
+ gcmkONERROR(gctaOS_ConstructOS(device->os, &device->taos));
+ }
+
+ gcmkONERROR(_SetupVidMem(device, ContiguousBase, ContiguousSize, BankSize, Args));
+
+ /* Set external base and size */
+ device->externalBase = ExternalBase;
+ device->externalSize = ExternalSize;
+
+ if (device->irqLines[gcvCORE_MAJOR] != -1)
+ {
+ gcmkONERROR(gcTA_Construct(device->taos, gcvCORE_MAJOR, &globalTA[gcvCORE_MAJOR]));
+
+ gcmkONERROR(gckDEVICE_AddCore(device->device, gcvCORE_MAJOR, Args->chipIDs[gcvCORE_MAJOR], device, &device->kernels[gcvCORE_MAJOR]));
+
+ gcmkONERROR(gckHARDWARE_SetFastClear(
+ device->kernels[gcvCORE_MAJOR]->hardware, FastClear, Compression
+ ));
+
+ gcmkONERROR(gckHARDWARE_SetPowerManagement(
+ device->kernels[gcvCORE_MAJOR]->hardware, PowerManagement
+ ));
+
+#if gcdENABLE_FSCALE_VAL_ADJUST
+ gcmkONERROR(gckHARDWARE_SetMinFscaleValue(
+ device->kernels[gcvCORE_MAJOR]->hardware, Args->gpu3DMinClock
+ ));
+#endif
+
+ gcmkONERROR(gckHARDWARE_SetGpuProfiler(
+ device->kernels[gcvCORE_MAJOR]->hardware, GpuProfiler
+ ));
+ }
+ else
+ {
+ device->kernels[gcvCORE_MAJOR] = gcvNULL;
+ }
+
+ if (device->irqLines[gcvCORE_2D] != -1)
+ {
+ gcmkONERROR(gckDEVICE_AddCore(device->device, gcvCORE_2D, gcvCHIP_ID_DEFAULT, device, &device->kernels[gcvCORE_2D]));
+
+ /* Verify the hardware type */
+ gcmkONERROR(gckHARDWARE_GetType(device->kernels[gcvCORE_2D]->hardware, &type));
+
+ if (type != gcvHARDWARE_2D)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): Unexpected hardware type: %d\n",
+ __FUNCTION__, __LINE__,
+ type
+ );
+
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gcmkONERROR(gckHARDWARE_SetPowerManagement(
+ device->kernels[gcvCORE_2D]->hardware, PowerManagement
+ ));
+
+#if gcdENABLE_FSCALE_VAL_ADJUST
+ gcmkONERROR(gckHARDWARE_SetMinFscaleValue(
+ device->kernels[gcvCORE_2D]->hardware, 1
+ ));
+#endif
+ }
+ else
+ {
+ device->kernels[gcvCORE_2D] = gcvNULL;
+ }
+
+ if (device->irqLines[gcvCORE_VG] != -1)
+ {
+#if gcdENABLE_VG
+ gcmkONERROR(gckDEVICE_AddCore(device->device, gcvCORE_VG, gcvCHIP_ID_DEFAULT, device, &device->kernels[gcvCORE_VG]));
+
+ gcmkONERROR(gckVGHARDWARE_SetPowerManagement(
+ device->kernels[gcvCORE_VG]->vg->hardware,
+ PowerManagement
+ ));
+#endif
+ }
+ else
+ {
+ device->kernels[gcvCORE_VG] = gcvNULL;
+ }
+
+ /* Add core for multiple core. */
+ for (i = gcvCORE_3D1; i <= gcvCORE_3D_MAX; i++)
+ {
+ if (Args->irqs[i] != -1)
+ {
+ gcmkONERROR(gcTA_Construct(device->taos, (gceCORE)i, &globalTA[i]));
+ gckDEVICE_AddCore(device->device, i, Args->chipIDs[i], device, &device->kernels[i]);
+
+ gcmkONERROR(
+ gckHARDWARE_SetFastClear(device->kernels[i]->hardware,
+ FastClear,
+ Compression));
+
+ gcmkONERROR(gckHARDWARE_SetPowerManagement(
+ device->kernels[i]->hardware, PowerManagement
+ ));
+
+ gcmkONERROR(gckHARDWARE_SetGpuProfiler(
+ device->kernels[i]->hardware, GpuProfiler
+ ));
+ }
+ }
+
+ /* Initialize the kernel thread semaphores. */
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (device->irqLines[i] != -1) sema_init(&device->semas[i], 0);
+ }
+
+ device->signal = Signal;
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (device->kernels[i] != gcvNULL) break;
+ }
+
+ if (i == gcdMAX_GPU_COUNT)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+#if gcdENABLE_VG
+ if (i == gcvCORE_VG)
+ {
+ /* Query the ceiling of the system memory. */
+ gcmkONERROR(gckVGHARDWARE_QuerySystemMemory(
+ device->kernels[i]->vg->hardware,
+ &device->systemMemorySize,
+ &device->systemMemoryBaseAddress
+ ));
+ }
+ else
+#endif
+ {
+ /* Query the ceiling of the system memory. */
+ gcmkONERROR(gckHARDWARE_QuerySystemMemory(
+ device->kernels[i]->hardware,
+ &device->systemMemorySize,
+ &device->systemMemoryBaseAddress
+ ));
+ }
+
+ /* Grab the first availiable kernel */
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (device->irqLines[i] != -1)
+ {
+ kernel = device->kernels[i];
+ break;
+ }
+ }
+
+ /* Set up the internal memory region. */
+ if (device->internalSize > 0)
+ {
+ status = gckVIDMEM_Construct(
+ device->os,
+ internalBaseAddress, device->internalSize, internalAlignment,
+ 0, &device->internalVidMem
+ );
+
+ if (gcmIS_ERROR(status))
+ {
+ /* Error, disable internal heap. */
+ device->internalSize = 0;
+ }
+ else
+ {
+ /* Map internal memory. */
+ device->internalLogical
+ = (gctPOINTER) ioremap_nocache(physical, device->internalSize);
+
+ if (device->internalLogical == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ device->internalPhysical = (gctPHYS_ADDR)(gctUINTPTR_T) physical;
+ physical += device->internalSize;
+ }
+ }
+
+ if (device->externalSize > 0)
+ {
+ /* create the external memory heap */
+ status = gckVIDMEM_Construct(
+ device->os,
+ device->externalBase, device->externalSize, externalAlignment,
+ 0, &device->externalVidMem
+ );
+
+ if (gcmIS_ERROR(status))
+ {
+ /* Error, disable external heap. */
+ device->externalSize = 0;
+ }
+ else
+ {
+ /* Map external memory. */
+ gcmkONERROR(gckOS_RequestReservedMemory(
+ device->os,
+ device->externalBase, device->externalSize,
+ "galcore external memory",
+ gcvTRUE,
+ &device->externalPhysical
+ ));
+ device->externalVidMem->physical = device->externalPhysical;
+ }
+ }
+
+ if (device->internalPhysical)
+ {
+ device->internalPhysicalName = gcmPTR_TO_NAME(device->internalPhysical);
+ }
+
+ if (device->externalPhysical)
+ {
+ device->externalPhysicalName = gcmPTR_TO_NAME(device->externalPhysical);
+ }
+
+ if (device->contiguousPhysical)
+ {
+ device->contiguousPhysicalName = gcmPTR_TO_NAME(device->contiguousPhysical);
+ }
+
+ /* Return pointer to the device. */
+ *Device = galDevice = device;
+
+ gcmkFOOTER_ARG("*Device=0x%x", * Device);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Roll back. */
+ gcmkVERIFY_OK(gckGALDEVICE_Destroy(device));
+
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckGALDEVICE_Destroy
+**
+** Class destructor.
+**
+** INPUT:
+**
+** Nothing.
+**
+** OUTPUT:
+**
+** Nothing.
+**
+** RETURNS:
+**
+** Nothing.
+*/
+gceSTATUS
+gckGALDEVICE_Destroy(
+ gckGALDEVICE Device)
+{
+ gctINT i;
+ gckKERNEL kernel = gcvNULL;
+
+ gcmkHEADER_ARG("Device=0x%x", Device);
+
+ if (Device != gcvNULL)
+ {
+ /* Grab the first availiable kernel */
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (Device->irqLines[i] != -1)
+ {
+ kernel = Device->kernels[i];
+ break;
+ }
+ }
+
+ if (Device->internalPhysicalName != 0)
+ {
+ gcmRELEASE_NAME(Device->internalPhysicalName);
+ Device->internalPhysicalName = 0;
+ }
+ if (Device->externalPhysicalName != 0)
+ {
+ gcmRELEASE_NAME(Device->externalPhysicalName);
+ Device->externalPhysicalName = 0;
+ }
+ if (Device->contiguousPhysicalName != 0)
+ {
+ gcmRELEASE_NAME(Device->contiguousPhysicalName);
+ Device->contiguousPhysicalName = 0;
+ }
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (Device->kernels[i] != gcvNULL)
+ {
+ Device->kernels[i] = gcvNULL;
+ }
+ }
+
+ if (Device->internalLogical != gcvNULL)
+ {
+ /* Unmap the internal memory. */
+ iounmap(Device->internalLogical);
+ Device->internalLogical = gcvNULL;
+ }
+
+ if (Device->internalVidMem != gcvNULL)
+ {
+ /* Destroy the internal heap. */
+ gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->internalVidMem));
+ Device->internalVidMem = gcvNULL;
+ }
+
+ if (Device->externalPhysical != gcvNULL)
+ {
+ gckOS_ReleaseReservedMemory(
+ Device->os,
+ Device->externalPhysical
+ );
+ }
+
+ if (Device->externalLogical != gcvNULL)
+ {
+ Device->externalLogical = gcvNULL;
+ }
+
+ if (Device->externalVidMem != gcvNULL)
+ {
+ /* destroy the external heap */
+ gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->externalVidMem));
+ Device->externalVidMem = gcvNULL;
+ }
+
+ if (Device->contiguousPhysical != gcvNULL)
+ {
+ if (Device->requestedContiguousBase == 0)
+ {
+ gcmkVERIFY_OK(_FreeMemory(
+ Device,
+ Device->contiguousLogical,
+ Device->contiguousPhysical
+ ));
+ }
+ else
+ {
+ gckOS_ReleaseReservedMemory(
+ Device->os,
+ Device->contiguousPhysical
+ );
+
+ Device->requestedContiguousBase = 0;
+ Device->requestedContiguousSize = 0;
+ }
+
+ Device->contiguousLogical = gcvNULL;
+ Device->contiguousPhysical = gcvNULL;
+ }
+
+ if (Device->contiguousVidMem != gcvNULL)
+ {
+ /* Destroy the contiguous heap. */
+ gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->contiguousVidMem));
+ Device->contiguousVidMem = gcvNULL;
+ }
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (Device->registerBases[i])
+ {
+ /* Unmap register memory. */
+ if (Device->requestedRegisterMemBases[i] != 0)
+ {
+#if USE_LINUX_PCIE
+ pci_iounmap(Device->platform->device, Device->registerBases[i]);
+#else
+
+ iounmap(Device->registerBases[i]);
+ release_mem_region(Device->requestedRegisterMemBases[i],
+ Device->requestedRegisterMemSizes[i]);
+#endif
+ }
+
+ Device->registerBases[i] = gcvNULL;
+ Device->requestedRegisterMemBases[i] = 0;
+ Device->requestedRegisterMemSizes[i] = 0;
+ }
+ }
+
+ if (Device->device)
+ {
+ gcmkVERIFY_OK(gckDEVICE_Destroy(Device->os, Device->device));
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (globalTA[i])
+ {
+ gcTA_Destroy(globalTA[i]);
+ globalTA[i] = gcvNULL;
+ }
+ }
+
+ Device->device = gcvNULL;
+ }
+
+ if (Device->taos)
+ {
+ gcmkVERIFY_OK(gctaOS_DestroyOS(Device->taos));
+ Device->taos = gcvNULL;
+ }
+
+ /* Destroy the gckOS object. */
+ if (Device->os != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_Destroy(Device->os));
+ Device->os = gcvNULL;
+ }
+
+ if (Device->dbgNode)
+ {
+ gckDEBUGFS_FreeNode(Device->dbgNode);
+
+ if(Device->dbgNode != gcvNULL)
+ {
+ kfree(Device->dbgNode);
+ Device->dbgNode = gcvNULL;
+ }
+ }
+
+ _DebugfsCleanup(Device);
+
+ /* Free the device. */
+ kfree(Device);
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+static const char *isrNames[] =
+{
+ "galcore:0",
+ "galcore:3d-1",
+ "galcore:3d-2",
+ "galcore:3d-3",
+ "galcore:3d-4",
+ "galcore:3d-5",
+ "galcore:3d-6",
+ "galcore:3d-7",
+ "galcore:2d",
+ "galcore:vg",
+#if gcdDEC_ENABLE_AHB
+ "galcore:dec"
+#endif
+};
+
+/*******************************************************************************
+**
+** gckGALDEVICE_Setup_ISR
+**
+** Start the ISR routine.
+**
+** INPUT:
+**
+** gckGALDEVICE Device
+** Pointer to an gckGALDEVICE object.
+**
+** OUTPUT:
+**
+** Nothing.
+**
+** RETURNS:
+**
+** gcvSTATUS_OK
+** Setup successfully.
+** gcvSTATUS_GENERIC_IO
+** Setup failed.
+*/
+gceSTATUS
+gckGALDEVICE_Setup_ISR(
+ IN gceCORE Core
+ )
+{
+ gceSTATUS status;
+ gctINT ret = 0;
+ gckGALDEVICE Device = galDevice;
+
+ gcmkHEADER_ARG("Device=0x%x Core=%d", Device, Core);
+
+ gcmkVERIFY_ARGUMENT(Device != NULL);
+
+ if (Device->irqLines[Core] < 0)
+ {
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+#if defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4))
+ {
+ _Static_assert(gcvCORE_COUNT == gcmCOUNTOF(isrNames),
+ "Core count is lager than isrNames size");
+ }
+#endif
+
+ /* Hook up the isr based on the irq line. */
+ ret = request_irq(
+ Device->irqLines[Core], isrRoutine, gcdIRQF_FLAG,
+ isrNames[Core], (void *)(uintptr_t)(Core + 1)
+ );
+
+ if (ret != 0)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): Could not register irq line %d (error=%d)\n",
+ __FUNCTION__, __LINE__,
+ Device->irqLines[Core], ret
+ );
+
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+ /* Mark ISR as initialized. */
+ Device->isrInitializeds[Core] = gcvTRUE;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckGALDEVICE_Setup_ISR_VG(
+ IN gckGALDEVICE Device
+ )
+{
+ gceSTATUS status;
+ gctINT ret;
+
+ gcmkHEADER_ARG("Device=0x%x", Device);
+
+ gcmkVERIFY_ARGUMENT(Device != NULL);
+
+ if (Device->irqLines[gcvCORE_VG] < 0)
+ {
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+ /* Hook up the isr based on the irq line. */
+ ret = request_irq(
+ Device->irqLines[gcvCORE_VG], isrRoutineVG, gcdIRQF_FLAG,
+ isrNames[gcvCORE_VG], Device
+ );
+
+ if (ret != 0)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): Could not register irq line %d (error=%d)\n",
+ __FUNCTION__, __LINE__,
+ Device->irqLines[gcvCORE_VG], ret
+ );
+
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+ /* Mark ISR as initialized. */
+ Device->isrInitializeds[gcvCORE_VG] = gcvTRUE;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckGALDEVICE_Release_ISR
+**
+** Release the irq line.
+**
+** INPUT:
+**
+** gckGALDEVICE Device
+** Pointer to an gckGALDEVICE object.
+**
+** OUTPUT:
+**
+** Nothing.
+**
+** RETURNS:
+**
+** Nothing.
+*/
+gceSTATUS
+gckGALDEVICE_Release_ISR(
+ IN gceCORE Core
+ )
+{
+ gckGALDEVICE Device = galDevice;
+ gcmkHEADER_ARG("Device=0x%x", Device);
+
+ gcmkVERIFY_ARGUMENT(Device != NULL);
+
+ /* release the irq */
+ if (Device->isrInitializeds[Core])
+ {
+ free_irq(Device->irqLines[Core], (void *)(uintptr_t)(Core + 1));
+ Device->isrInitializeds[Core] = gcvFALSE;
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckGALDEVICE_Release_ISR_VG(
+ IN gckGALDEVICE Device
+ )
+{
+ gcmkHEADER_ARG("Device=0x%x", Device);
+
+ gcmkVERIFY_ARGUMENT(Device != NULL);
+
+ /* release the irq */
+ if (Device->isrInitializeds[gcvCORE_VG])
+ {
+ free_irq(Device->irqLines[gcvCORE_VG], Device);
+ Device->isrInitializeds[gcvCORE_VG] = gcvFALSE;
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckGALDEVICE_Start_Threads
+**
+** Start the daemon threads.
+**
+** INPUT:
+**
+** gckGALDEVICE Device
+** Pointer to an gckGALDEVICE object.
+**
+** OUTPUT:
+**
+** Nothing.
+**
+** RETURNS:
+**
+** gcvSTATUS_OK
+** Start successfully.
+** gcvSTATUS_GENERIC_IO
+** Start failed.
+*/
+gceSTATUS
+gckGALDEVICE_Start_Threads(
+ IN gckGALDEVICE Device
+ )
+{
+ gceSTATUS status;
+ gctUINT i;
+
+ gcmkHEADER_ARG("Device=0x%x", Device);
+
+ gcmkVERIFY_ARGUMENT(Device != NULL);
+
+ gcmkONERROR(_StartThread(threadRoutine, gcvCORE_MAJOR));
+ gcmkONERROR(_StartThread(threadRoutine, gcvCORE_2D));
+
+ gcmkONERROR(_StartThread(threadRoutine, gcvCORE_VG));
+
+ for (i = gcvCORE_3D1; i <= gcvCORE_3D_MAX; i++)
+ {
+ gcmkONERROR(_StartThread(threadRoutine, i));
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckGALDEVICE_Stop_Threads
+**
+** Stop the gal device, including the following actions: stop the daemon
+** thread, release the irq.
+**
+** INPUT:
+**
+** gckGALDEVICE Device
+** Pointer to an gckGALDEVICE object.
+**
+** OUTPUT:
+**
+** Nothing.
+**
+** RETURNS:
+**
+** Nothing.
+*/
+gceSTATUS
+gckGALDEVICE_Stop_Threads(
+ gckGALDEVICE Device
+ )
+{
+ gctINT i;
+
+ gcmkHEADER_ARG("Device=0x%x", Device);
+
+ gcmkVERIFY_ARGUMENT(Device != NULL);
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ /* Stop the kernel threads. */
+ if (Device->threadInitializeds[i])
+ {
+ Device->killThread = gcvTRUE;
+ up(&Device->semas[i]);
+
+ kthread_stop(Device->threadCtxts[i]);
+ Device->threadCtxts[i] = gcvNULL;
+ Device->threadInitializeds[i] = gcvFALSE;
+ }
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckGALDEVICE_Start
+**
+** Start the gal device, including the following actions: setup the isr routine
+** and start the daemoni thread.
+**
+** INPUT:
+**
+** gckGALDEVICE Device
+** Pointer to an gckGALDEVICE object.
+**
+** OUTPUT:
+**
+** Nothing.
+**
+** RETURNS:
+**
+** gcvSTATUS_OK
+** Start successfully.
+*/
+gceSTATUS
+gckGALDEVICE_Start(
+ IN gckGALDEVICE Device
+ )
+{
+ gceSTATUS status;
+ gctUINT i;
+
+ gcmkHEADER_ARG("Device=0x%x", Device);
+
+ /* Start the kernel thread. */
+ gcmkONERROR(gckGALDEVICE_Start_Threads(Device));
+
+ for (i = 0; i < gcvCORE_COUNT; i++)
+ {
+ if (i == gcvCORE_VG)
+ {
+ continue;
+ }
+
+ if (Device->kernels[i] != gcvNULL)
+ {
+ /* Setup the ISR routine. */
+ gcmkONERROR(gckGALDEVICE_Setup_ISR(i));
+
+ /* Switch to SUSPEND power state. */
+ gcmkONERROR(gckHARDWARE_SetPowerManagementState(
+ Device->kernels[i]->hardware, gcvPOWER_OFF_BROADCAST
+ ));
+ }
+ }
+
+ if (Device->kernels[gcvCORE_VG] != gcvNULL)
+ {
+ /* Setup the ISR routine. */
+ gcmkONERROR(gckGALDEVICE_Setup_ISR_VG(Device));
+
+#if gcdENABLE_VG
+ /* Switch to SUSPEND power state. */
+ gcmkONERROR(gckVGHARDWARE_SetPowerManagementState(
+ Device->kernels[gcvCORE_VG]->vg->hardware, gcvPOWER_OFF_BROADCAST
+ ));
+#endif
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckGALDEVICE_Stop
+**
+** Stop the gal device, including the following actions: stop the daemon
+** thread, release the irq.
+**
+** INPUT:
+**
+** gckGALDEVICE Device
+** Pointer to an gckGALDEVICE object.
+**
+** OUTPUT:
+**
+** Nothing.
+**
+** RETURNS:
+**
+** Nothing.
+*/
+gceSTATUS
+gckGALDEVICE_Stop(
+ gckGALDEVICE Device
+ )
+{
+ gceSTATUS status;
+ gctUINT i;
+
+ gcmkHEADER_ARG("Device=0x%x", Device);
+
+ gcmkVERIFY_ARGUMENT(Device != NULL);
+
+ for (i = 0; i < gcvCORE_COUNT; i++)
+ {
+ if (i == gcvCORE_VG)
+ {
+ continue;
+ }
+
+ if (Device->kernels[i] != gcvNULL)
+ {
+ gcmkONERROR(gckHARDWARE_SetPowerManagement(
+ Device->kernels[i]->hardware, gcvTRUE
+ ));
+
+ /* Switch to OFF power state. */
+ gcmkONERROR(gckHARDWARE_SetPowerManagementState(
+ Device->kernels[i]->hardware, gcvPOWER_OFF
+ ));
+
+ /* Remove the ISR routine. */
+ gcmkONERROR(gckGALDEVICE_Release_ISR(i));
+ }
+ }
+
+ if (Device->kernels[gcvCORE_VG] != gcvNULL)
+ {
+ /* Setup the ISR routine. */
+ gcmkONERROR(gckGALDEVICE_Release_ISR_VG(Device));
+
+#if gcdENABLE_VG
+ /* Switch to OFF power state. */
+ gcmkONERROR(gckVGHARDWARE_SetPowerManagementState(
+ Device->kernels[gcvCORE_VG]->vg->hardware, gcvPOWER_OFF
+ ));
+#endif
+ }
+
+ /* Stop the kernel thread. */
+ gcmkONERROR(gckGALDEVICE_Stop_Threads(Device));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckGALDEVICE_AddCore
+**
+** Add a core after gckGALDevice is constructed.
+**
+** INPUT:
+**
+** OUTPUT:
+**
+*/
+gceSTATUS
+gckGALDEVICE_AddCore(
+ IN gckGALDEVICE Device,
+ IN gcsDEVICE_CONSTRUCT_ARGS * Args
+ )
+{
+ gceSTATUS status;
+ gceCORE core = gcvCORE_COUNT;
+ gctUINT i = 0;
+
+ gcmkHEADER();
+ gcmkVERIFY_ARGUMENT(Device != gcvNULL);
+
+ /* Find which core is added. */
+ for (i = 0; i < gcvCORE_COUNT; i++)
+ {
+ if (Args->irqs[i] != -1)
+ {
+ core = i;
+ break;
+ }
+ }
+
+ if (i == gcvCORE_COUNT)
+ {
+ gcmkPRINT("[galcore]: No valid core information found");
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+
+ gcmkPRINT("[galcore]: add core[%d]", core);
+
+ /* Record irq, registerBase, registerSize. */
+ Device->irqLines[core] = Args->irqs[core];
+ _SetupRegisterPhysical(Device, Args);
+
+ /* Map register memory.*/
+
+ /* Add a platform indepedent framework. */
+ gcmkONERROR(gckDEVICE_AddCore(
+ Device->device,
+ core,
+ Args->chipIDs[core],
+ Device,
+ &Device->kernels[core]
+ ));
+
+ /* Start thread routine. */
+ _StartThread(threadRoutine, core);
+
+ /* Register ISR. */
+ gckGALDEVICE_Setup_ISR(core);
+
+ /* Set default power management state. */
+ gcmkONERROR(gckHARDWARE_SetPowerManagementState(
+ Device->kernels[core]->hardware, gcvPOWER_OFF_BROADCAST
+ ));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return gcvSTATUS_OK;
+}
+
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.h b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.h
new file mode 100644
index 000000000000..185485cf310b
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.h
@@ -0,0 +1,272 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_device_h_
+#define __gc_hal_kernel_device_h_
+
+#include "gc_hal_kernel_debugfs.h"
+#include "gc_hal_ta.h"
+
+typedef struct _gcsDEVICE_CONSTRUCT_ARGS
+{
+ gctBOOL recovery;
+ gctUINT stuckDump;
+ gctUINT gpu3DMinClock;
+
+ gctBOOL contiguousRequested;
+ gcsPLATFORM* platform;
+ gctBOOL mmu;
+ gctBOOL registerMemMapped;
+ gctPOINTER registerMemAddress;
+#if gcdDEC_ENABLE_AHB
+ gctUINT32 registerMemBaseDEC300;
+ gctSIZE_T registerMemSizeDEC300;
+#endif
+ gctINT irqs[gcvCORE_COUNT];
+ gctUINT registerBases[gcvCORE_COUNT];
+ gctUINT registerSizes[gcvCORE_COUNT];
+ gctBOOL powerManagement;
+ gctBOOL gpuProfiler;
+ gctUINT chipIDs[gcvCORE_COUNT];
+}
+gcsDEVICE_CONSTRUCT_ARGS;
+
+/******************************************************************************\
+************************** gckGALDEVICE Structure ******************************
+\******************************************************************************/
+
+typedef struct _gckGALDEVICE
+{
+ /* Objects. */
+ gckOS os;
+ gckKERNEL kernels[gcdMAX_GPU_COUNT];
+
+ gcsPLATFORM* platform;
+
+ /* Attributes. */
+ gctSIZE_T internalSize;
+ gctPHYS_ADDR internalPhysical;
+ gctUINT32 internalPhysicalName;
+ gctPOINTER internalLogical;
+ gckVIDMEM internalVidMem;
+
+ gctUINT32 externalBase;
+ gctSIZE_T externalSize;
+ gctPHYS_ADDR externalPhysical;
+ gctUINT32 externalPhysicalName;
+ gctPOINTER externalLogical;
+ gckVIDMEM externalVidMem;
+
+ gctPHYS_ADDR_T contiguousBase;
+ gctSIZE_T contiguousSize;
+
+ gckVIDMEM contiguousVidMem;
+ gctPOINTER contiguousLogical;
+ gctPHYS_ADDR contiguousPhysical;
+ gctUINT32 contiguousPhysicalName;
+
+ gctSIZE_T systemMemorySize;
+ gctUINT32 systemMemoryBaseAddress;
+ gctPOINTER registerBases[gcdMAX_GPU_COUNT];
+ gctSIZE_T registerSizes[gcdMAX_GPU_COUNT];
+
+ gctUINT32 baseAddress;
+ gctUINT32 physBase;
+ gctUINT32 physSize;
+
+ /* By request_mem_region. */
+ gctUINT32 requestedRegisterMemBases[gcdMAX_GPU_COUNT];
+ gctSIZE_T requestedRegisterMemSizes[gcdMAX_GPU_COUNT];
+
+ /* By request_mem_region. */
+ gctUINT32 requestedContiguousBase;
+ gctSIZE_T requestedContiguousSize;
+
+ /* IRQ management. */
+ gctINT irqLines[gcdMAX_GPU_COUNT];
+ gctBOOL isrInitializeds[gcdMAX_GPU_COUNT];
+
+ /* Thread management. */
+ struct task_struct *threadCtxts[gcdMAX_GPU_COUNT];
+ struct semaphore semas[gcdMAX_GPU_COUNT];
+ gctBOOL threadInitializeds[gcdMAX_GPU_COUNT];
+ gctBOOL killThread;
+
+ /* Signal management. */
+ gctINT signal;
+
+ /* States before suspend. */
+ gceCHIPPOWERSTATE statesStored[gcdMAX_GPU_COUNT];
+
+ /* Device Debug File System Entry in kernel. */
+ struct _gcsDEBUGFS_Node * dbgNode;
+
+ gcsDEBUGFS_DIR debugfsDir;
+
+ gckDEVICE device;
+
+ gcsDEVICE_CONSTRUCT_ARGS args;
+
+ /* gctsOs object for trust application. */
+ gctaOS taos;
+
+#if gcdENABLE_DRM
+ void* drm;
+#endif
+}
+* gckGALDEVICE;
+
+typedef struct _gcsHAL_PRIVATE_DATA
+{
+ gckGALDEVICE device;
+ /*
+ * 'fput' schedules actual work in '__fput' in a different thread.
+ * So the process opens the device may not be the same as the one that
+ * closes it.
+ */
+ gctUINT32 pidOpen;
+}
+gcsHAL_PRIVATE_DATA, * gcsHAL_PRIVATE_DATA_PTR;
+
+gceSTATUS gckGALDEVICE_Setup_ISR(
+ IN gceCORE Core
+ );
+
+gceSTATUS gckGALDEVICE_Setup_ISR_VG(
+ IN gckGALDEVICE Device
+ );
+
+gceSTATUS gckGALDEVICE_Release_ISR(
+ IN gceCORE Core
+ );
+
+gceSTATUS gckGALDEVICE_Release_ISR_VG(
+ IN gckGALDEVICE Device
+ );
+
+gceSTATUS gckGALDEVICE_Start_Threads(
+ IN gckGALDEVICE Device
+ );
+
+gceSTATUS gckGALDEVICE_Stop_Threads(
+ gckGALDEVICE Device
+ );
+
+gceSTATUS gckGALDEVICE_Start(
+ IN gckGALDEVICE Device
+ );
+
+gceSTATUS gckGALDEVICE_Stop(
+ gckGALDEVICE Device
+ );
+
+gceSTATUS gckGALDEVICE_Construct(
+ IN gctINT IrqLine,
+ IN gctUINT32 RegisterMemBase,
+ IN gctSIZE_T RegisterMemSize,
+ IN gctINT IrqLine2D,
+ IN gctUINT32 RegisterMemBase2D,
+ IN gctSIZE_T RegisterMemSize2D,
+ IN gctINT IrqLineVG,
+ IN gctUINT32 RegisterMemBaseVG,
+ IN gctSIZE_T RegisterMemSizeVG,
+ IN gctUINT32 ContiguousBase,
+ IN gctSIZE_T ContiguousSize,
+ IN gctUINT32 ExternalBase,
+ IN gctSIZE_T ExternalSize,
+ IN gctSIZE_T BankSize,
+ IN gctINT FastClear,
+ IN gctINT Compression,
+ IN gctUINT32 PhysBaseAddr,
+ IN gctUINT32 PhysSize,
+ IN gctINT Signal,
+ IN gctUINT LogFileSize,
+ IN gctINT PowerManagement,
+ IN gctINT GpuProfiler,
+ IN gcsDEVICE_CONSTRUCT_ARGS * Args,
+ OUT gckGALDEVICE *Device
+ );
+
+gceSTATUS gckGALDEVICE_Destroy(
+ IN gckGALDEVICE Device
+ );
+
+static gcmINLINE gckKERNEL
+_GetValidKernel(
+ gckGALDEVICE Device
+ )
+{
+ if (Device->kernels[gcvCORE_MAJOR])
+ {
+ return Device->kernels[gcvCORE_MAJOR];
+ }
+ else
+ if (Device->kernels[gcvCORE_2D])
+ {
+ return Device->kernels[gcvCORE_2D];
+ }
+ else
+ if (Device->kernels[gcvCORE_VG])
+ {
+ return Device->kernels[gcvCORE_VG];
+ }
+ else
+ {
+ gcmkASSERT(gcvFALSE);
+ return gcvNULL;
+ }
+}
+
+#endif /* __gc_hal_kernel_device_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_driver.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_driver.c
new file mode 100644
index 000000000000..724e77100205
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_driver.c
@@ -0,0 +1,1297 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_driver.h"
+
+#include <linux/platform_device.h>
+
+/* Zone used for header/footer. */
+#define _GC_OBJ_ZONE gcvZONE_DRIVER
+
+MODULE_DESCRIPTION("Vivante Graphics Driver");
+MODULE_LICENSE("Dual MIT/GPL");
+
+/* Disable MSI for internal FPGA build except PPC */
+#if gcdFPGA_BUILD && !defined(CONFIG_PPC)
+#define USE_MSI 0
+#else
+#define USE_MSI 1
+#endif
+
+static struct class* gpuClass;
+
+static gcsPLATFORM *platform;
+
+static gckGALDEVICE galDevice;
+
+static uint major = 199;
+module_param(major, uint, 0644);
+MODULE_PARM_DESC(major, "major device number for GC device");
+
+static int irqLine = -1;
+module_param(irqLine, int, 0644);
+MODULE_PARM_DESC(irqLine, "IRQ number of GC core");
+
+static ulong registerMemBase = 0x80000000;
+module_param(registerMemBase, ulong, 0644);
+MODULE_PARM_DESC(registerMemBase, "Base of bus address of GC core AHB register");
+
+static ulong registerMemSize = 2 << 10;
+module_param(registerMemSize, ulong, 0644);
+MODULE_PARM_DESC(registerMemSize, "Size of bus address range of GC core AHB register");
+
+static int irqLine2D = -1;
+module_param(irqLine2D, int, 0644);
+MODULE_PARM_DESC(irqLine2D, "IRQ number of G2D core if irqLine is used for a G3D core");
+
+static ulong registerMemBase2D = 0x00000000;
+module_param(registerMemBase2D, ulong, 0644);
+MODULE_PARM_DESC(registerMemBase2D, "Base of bus address of G2D core if registerMemBase2D is used for a G3D core");
+
+static ulong registerMemSize2D = 2 << 10;
+module_param(registerMemSize2D, ulong, 0644);
+MODULE_PARM_DESC(registerMemSize2D, "Size of bus address range of G2D core if registerMemSize is used for a G3D core");
+
+static int irqLineVG = -1;
+module_param(irqLineVG, int, 0644);
+MODULE_PARM_DESC(irqLineVG, "IRQ number of VG core");
+
+static ulong registerMemBaseVG = 0x00000000;
+module_param(registerMemBaseVG, ulong, 0644);
+MODULE_PARM_DESC(registerMemBaseVG, "Base of bus address of VG core");
+
+static ulong registerMemSizeVG = 2 << 10;
+module_param(registerMemSizeVG, ulong, 0644);
+MODULE_PARM_DESC(registerMemSizeVG, "Size of bus address range of VG core");
+
+#if gcdDEC_ENABLE_AHB
+static ulong registerMemBaseDEC300 = 0x00000000;
+module_param(registerMemBaseDEC300, ulong, 0644);
+
+static ulong registerMemSizeDEC300 = 2 << 10;
+module_param(registerMemSizeDEC300, ulong, 0644);
+#endif
+
+#ifndef gcdDEFAULT_CONTIGUOUS_SIZE
+#define gcdDEFAULT_CONTIGUOUS_SIZE (4 << 20)
+#endif
+static ulong contiguousSize = gcdDEFAULT_CONTIGUOUS_SIZE;
+module_param(contiguousSize, ulong, 0644);
+MODULE_PARM_DESC(contiguousSize, "Size of memory reserved for GC");
+
+static ulong contiguousBase = 0;
+module_param(contiguousBase, ulong, 0644);
+MODULE_PARM_DESC(contiguousBase, "Base address of memory reserved for GC, if it is 0, GC driver will try to allocate a buffer whose size defined by contiguousSize");
+
+static ulong externalSize = 0;
+module_param(externalSize, ulong, 0644);
+MODULE_PARM_DESC(externalSize, "Size of external memory, if it is 0, means there is no external pool");
+
+static ulong externalBase = 0;
+module_param(externalBase, ulong, 0644);
+MODULE_PARM_DESC(externalBase, "Base address of external memory");
+
+static int fastClear = -1;
+module_param(fastClear, int, 0644);
+MODULE_PARM_DESC(fastClear, "Disable fast clear if set it to 0, enabled by default");
+
+static int compression = -1;
+module_param(compression, int, 0644);
+MODULE_PARM_DESC(compression, "Disable compression if set it to 0, enabled by default");
+
+static int powerManagement = 1;
+module_param(powerManagement, int, 0644);
+MODULE_PARM_DESC(powerManagement, "Disable auto power saving if set it to 1, enabled by default");
+
+static int gpuProfiler = 0;
+module_param(gpuProfiler, int, 0644);
+MODULE_PARM_DESC(gpuProfiler, "Enable profiling support, disabled by default");
+
+static ulong baseAddress = 0;
+module_param(baseAddress, ulong, 0644);
+MODULE_PARM_DESC(baseAddress, "Only used for old MMU, set it to 0 if memory which can be accessed by GPU falls into 0 - 2G, otherwise set it to 0x80000000");
+
+static ulong physSize = 0;
+module_param(physSize, ulong, 0644);
+MODULE_PARM_DESC(physSize, "Obsolete");
+
+static uint logFileSize = 0;
+module_param(logFileSize,uint, 0644);
+MODULE_PARM_DESC(logFileSize, "Size of buffer to store GC driver output messsage, if it is not 0, message is read from /sys/kernel/debug/gc/galcore_trace, default value is 0");
+
+static uint recovery = 0;
+module_param(recovery, uint, 0644);
+MODULE_PARM_DESC(recovery, "Recover GPU from stuck (1: Enable, 0: Disable)");
+
+/* Middle needs about 40KB buffer, Maximal may need more than 200KB buffer. */
+static uint stuckDump = 0;
+module_param(stuckDump, uint, 0644);
+MODULE_PARM_DESC(stuckDump, "Level of stuck dump content (1: Minimal, 2: Middle, 3: Maximal)");
+
+static int showArgs = 0;
+module_param(showArgs, int, 0644);
+MODULE_PARM_DESC(showArgs, "Display parameters value when driver loaded");
+
+static int mmu = 1;
+module_param(mmu, int, 0644);
+MODULE_PARM_DESC(mmu, "Disable MMU if set it to 0, enabled by default");
+
+static int irqs[gcvCORE_COUNT] = {[0 ... gcvCORE_COUNT - 1] = -1};
+module_param_array(irqs, int, NULL, 0644);
+MODULE_PARM_DESC(irqs, "Array of IRQ numbers of multi-GPU");
+
+static uint registerBases[gcvCORE_COUNT];
+module_param_array(registerBases, uint, NULL, 0644);
+MODULE_PARM_DESC(registerBases, "Array of bases of bus address of register of multi-GPU");
+
+static uint registerSizes[gcvCORE_COUNT] = {[0 ... gcvCORE_COUNT - 1] = 2 << 10};
+module_param_array(registerSizes, uint, NULL, 0644);
+MODULE_PARM_DESC(registerSizes, "Array of sizes of bus address range of register of multi-GPU");
+
+static uint chipIDs[gcvCORE_COUNT] = {[0 ... gcvCORE_COUNT - 1] = gcvCHIP_ID_DEFAULT};
+module_param_array(chipIDs, uint, NULL, 0644);
+MODULE_PARM_DESC(chipIDs, "Array of chipIDs of multi-GPU");
+
+static uint type = 0;
+module_param(type, uint, 0664);
+MODULE_PARM_DESC(type, "0 - Char Driver (Default), 1 - Misc Driver");
+
+static int gpu3DMinClock = 1;
+
+static int contiguousRequested = 0;
+
+static gctBOOL registerMemMapped = gcvFALSE;
+static gctPOINTER registerMemAddress = gcvNULL;
+static ulong bankSize = 0;
+static int signal = 48;
+
+void
+_UpdateModuleParam(
+ gcsMODULE_PARAMETERS *Param
+ )
+{
+ irqLine = Param->irqLine ;
+ registerMemBase = Param->registerMemBase;
+ registerMemSize = Param->registerMemSize;
+ irqLine2D = Param->irqLine2D ;
+ registerMemBase2D = Param->registerMemBase2D;
+ registerMemSize2D = Param->registerMemSize2D;
+#if gcdENABLE_VG
+ irqLineVG = Param->irqLineVG;
+ registerMemBaseVG = Param->registerMemBaseVG;
+ registerMemSizeVG = Param->registerMemSizeVG;
+#endif
+ contiguousSize = Param->contiguousSize;
+ contiguousBase = Param->contiguousBase;
+ externalSize = Param->externalSize;
+ externalBase = Param->externalBase;
+ bankSize = Param->bankSize;
+ fastClear = Param->fastClear;
+ compression = (gctINT)Param->compression;
+ powerManagement = Param->powerManagement;
+ gpuProfiler = Param->gpuProfiler;
+ signal = Param->signal;
+ baseAddress = Param->baseAddress;
+ physSize = Param->physSize;
+ logFileSize = Param->logFileSize;
+ recovery = Param->recovery;
+ stuckDump = Param->stuckDump;
+ showArgs = Param->showArgs;
+ contiguousRequested = Param->contiguousRequested;
+ gpu3DMinClock = Param->gpu3DMinClock;
+ registerMemMapped = Param->registerMemMapped;
+ registerMemAddress = Param->registerMemAddress;
+
+ memcpy(irqs, Param->irqs, gcmSIZEOF(gctINT) * gcvCORE_COUNT);
+ memcpy(registerBases, Param->registerBases, gcmSIZEOF(gctUINT) * gcvCORE_COUNT);
+ memcpy(registerSizes, Param->registerSizes, gcmSIZEOF(gctUINT) * gcvCORE_COUNT);
+ memcpy(chipIDs, Param->chipIDs, gcmSIZEOF(gctUINT) * gcvCORE_COUNT);
+}
+
+void
+gckOS_DumpParam(
+ void
+ )
+{
+ gctINT i;
+
+ printk("Galcore options:\n");
+ if (irqLine != -1)
+ {
+ printk(" irqLine = %d\n", irqLine);
+ printk(" registerMemBase = 0x%08lX\n", registerMemBase);
+ printk(" registerMemSize = 0x%08lX\n", registerMemSize);
+ }
+
+ if (irqLine2D != -1)
+ {
+ printk(" irqLine2D = %d\n", irqLine2D);
+ printk(" registerMemBase2D = 0x%08lX\n", registerMemBase2D);
+ printk(" registerMemSize2D = 0x%08lX\n", registerMemSize2D);
+ }
+
+ if (irqLineVG != -1)
+ {
+ printk(" irqLineVG = %d\n", irqLineVG);
+ printk(" registerMemBaseVG = 0x%08lX\n", registerMemBaseVG);
+ printk(" registerMemSizeVG = 0x%08lX\n", registerMemSizeVG);
+ }
+
+#if gcdDEC_ENABLE_AHB
+ printk(" registerMemBaseDEC300 = 0x%08lX\n", registerMemBaseDEC300);
+ printk(" registerMemSizeDEC300 = 0x%08lX\n", registerMemSizeDEC300);
+#endif
+
+ printk(" contiguousSize = 0x%08lX\n", contiguousSize);
+ printk(" contiguousBase = 0x%08lX\n", contiguousBase);
+ printk(" externalSize = 0x%08lX\n", externalSize);
+ printk(" externalBase = 0x%08lX\n", externalBase);
+ printk(" bankSize = 0x%08lX\n", bankSize);
+ printk(" fastClear = %d\n", fastClear);
+ printk(" compression = %d\n", compression);
+ printk(" signal = %d\n", signal);
+ printk(" powerManagement = %d\n", powerManagement);
+ printk(" baseAddress = 0x%08lX\n", baseAddress);
+ printk(" physSize = 0x%08lX\n", physSize);
+ printk(" logFileSize = %d KB \n", logFileSize);
+ printk(" recovery = %d\n", recovery);
+ printk(" stuckDump = %d\n", stuckDump);
+ printk(" gpuProfiler = %d\n", gpuProfiler);
+
+ printk(" irqs = ");
+ for (i = 0; i < gcvCORE_COUNT; i++)
+ {
+ printk("%d, ", irqs[i]);
+ }
+ printk("\n");
+
+ printk(" registerBases = ");
+ for (i = 0; i < gcvCORE_COUNT; i++)
+ {
+ printk("0x%08X, ", registerBases[i]);
+ }
+ printk("\n");
+
+ printk(" registerSizes = ");
+ for (i = 0; i < gcvCORE_COUNT; i++)
+ {
+ printk("0x%08X, ", registerSizes[i]);
+ }
+ printk("\n");
+
+ printk(" chipIDs = ");
+ for (i = 0; i < gcvCORE_COUNT; i++)
+ {
+ printk("0x%08X, ", chipIDs[i]);
+ }
+ printk("\n");
+
+ printk("Build options:\n");
+ printk(" gcdGPU_TIMEOUT = %d\n", gcdGPU_TIMEOUT);
+ printk(" gcdGPU_2D_TIMEOUT = %d\n", gcdGPU_2D_TIMEOUT);
+ printk(" gcdINTERRUPT_STATISTIC = %d\n", gcdINTERRUPT_STATISTIC);
+}
+
+static int drv_open(
+ struct inode* inode,
+ struct file* filp
+ )
+{
+ gceSTATUS status;
+ gctBOOL attached = gcvFALSE;
+ gcsHAL_PRIVATE_DATA_PTR data = gcvNULL;
+ gctINT i;
+
+ gcmkHEADER_ARG("inode=0x%08X filp=0x%08X", inode, filp);
+
+ if (filp == gcvNULL)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): filp is NULL\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ data = kmalloc(sizeof(gcsHAL_PRIVATE_DATA), GFP_KERNEL | __GFP_NOWARN);
+
+ if (data == gcvNULL)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): private_data is NULL\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ data->device = galDevice;
+ data->pidOpen = _GetProcessID();
+
+ /* Attached the process. */
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (galDevice->kernels[i] != gcvNULL)
+ {
+ gcmkONERROR(gckKERNEL_AttachProcess(galDevice->kernels[i], gcvTRUE));
+ }
+ }
+ attached = gcvTRUE;
+
+ filp->private_data = data;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return 0;
+
+OnError:
+ if (data != gcvNULL)
+ {
+ kfree(data);
+ }
+
+ if (attached)
+ {
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (galDevice->kernels[i] != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckKERNEL_AttachProcess(galDevice->kernels[i], gcvFALSE));
+ }
+ }
+ }
+
+ gcmkFOOTER();
+ return -ENOTTY;
+}
+
+static int drv_release(
+ struct inode* inode,
+ struct file* filp
+ )
+{
+ gceSTATUS status;
+ gcsHAL_PRIVATE_DATA_PTR data;
+ gckGALDEVICE device;
+ gctINT i;
+
+ gcmkHEADER_ARG("inode=0x%08X filp=0x%08X", inode, filp);
+
+ if (filp == gcvNULL)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): filp is NULL\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ data = filp->private_data;
+
+ if (data == gcvNULL)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): private_data is NULL\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ device = data->device;
+
+ if (device == gcvNULL)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): device is NULL\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ /* A process gets detached. */
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (galDevice->kernels[i] != gcvNULL)
+ {
+ gcmkONERROR(gckKERNEL_AttachProcessEx(galDevice->kernels[i], gcvFALSE, data->pidOpen));
+ }
+ }
+
+ kfree(data);
+ filp->private_data = NULL;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return 0;
+
+OnError:
+ gcmkFOOTER();
+ return -ENOTTY;
+}
+
+static long drv_ioctl(
+ struct file* filp,
+ unsigned int ioctlCode,
+ unsigned long arg
+ )
+{
+ gceSTATUS status;
+ gcsHAL_INTERFACE iface;
+ gctUINT32 copyLen;
+ DRIVER_ARGS drvArgs;
+ gckGALDEVICE device;
+ gcsHAL_PRIVATE_DATA_PTR data;
+
+ gcmkHEADER_ARG(
+ "filp=0x%08X ioctlCode=0x%08X arg=0x%08X",
+ filp, ioctlCode, arg
+ );
+
+ if (filp == gcvNULL)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): filp is NULL\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ data = filp->private_data;
+
+ if (data == gcvNULL)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): private_data is NULL\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ device = data->device;
+
+ if (device == gcvNULL)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): device is NULL\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ if ((ioctlCode != IOCTL_GCHAL_INTERFACE)
+ && (ioctlCode != IOCTL_GCHAL_KERNEL_INTERFACE)
+ )
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): unknown command %d\n",
+ __FUNCTION__, __LINE__,
+ ioctlCode
+ );
+
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ /* Get the drvArgs. */
+ copyLen = copy_from_user(
+ &drvArgs, (void *) arg, sizeof(DRIVER_ARGS)
+ );
+
+ if (copyLen != 0)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): error copying of the input arguments.\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ /* Now bring in the gcsHAL_INTERFACE structure. */
+ if ((drvArgs.InputBufferSize != sizeof(gcsHAL_INTERFACE))
+ || (drvArgs.OutputBufferSize != sizeof(gcsHAL_INTERFACE))
+ )
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): input or/and output structures are invalid.\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ copyLen = copy_from_user(
+ &iface, gcmUINT64_TO_PTR(drvArgs.InputBuffer), sizeof(gcsHAL_INTERFACE)
+ );
+
+ if (copyLen != 0)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): error copying of input HAL interface.\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ status = gckDEVICE_Dispatch(device->device, &iface);
+
+ /* Redo system call after pending signal is handled. */
+ if (status == gcvSTATUS_INTERRUPTED)
+ {
+ gcmkFOOTER();
+ return -ERESTARTSYS;
+ }
+
+ /* Copy data back to the user. */
+ copyLen = copy_to_user(
+ gcmUINT64_TO_PTR(drvArgs.OutputBuffer), &iface, sizeof(gcsHAL_INTERFACE)
+ );
+
+ if (copyLen != 0)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): error copying of output HAL interface.\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return 0;
+
+OnError:
+ gcmkFOOTER();
+ return -ENOTTY;
+}
+
+static struct file_operations driver_fops =
+{
+ .owner = THIS_MODULE,
+ .open = drv_open,
+ .release = drv_release,
+ .unlocked_ioctl = drv_ioctl,
+#ifdef HAVE_COMPAT_IOCTL
+ .compat_ioctl = drv_ioctl,
+#endif
+};
+
+static struct miscdevice gal_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = DEVICE_NAME,
+ .fops = &driver_fops,
+};
+
+static int drv_init(void)
+{
+ int ret;
+ int result = -EINVAL;
+ gceSTATUS status;
+ gckGALDEVICE device = gcvNULL;
+ struct class* device_class = gcvNULL;
+
+ gcsDEVICE_CONSTRUCT_ARGS args = {
+ .recovery = recovery,
+ .stuckDump = stuckDump,
+ .gpu3DMinClock = gpu3DMinClock,
+ .contiguousRequested = contiguousRequested,
+ .platform = platform,
+ .mmu = mmu,
+ .registerMemMapped = registerMemMapped,
+ .registerMemAddress = registerMemAddress,
+#if gcdDEC_ENABLE_AHB
+ .registerMemBaseDEC300 = registerMemBaseDEC300,
+ .registerMemSizeDEC300 = registerMemSizeDEC300,
+#endif
+ };
+
+ gcmkHEADER();
+
+ memcpy(args.irqs, irqs, gcmSIZEOF(gctINT) * gcvCORE_COUNT);
+ memcpy(args.registerBases, registerBases, gcmSIZEOF(gctUINT) * gcvCORE_COUNT);
+ memcpy(args.registerSizes, registerSizes, gcmSIZEOF(gctUINT) * gcvCORE_COUNT);
+ memcpy(args.chipIDs, chipIDs, gcmSIZEOF(gctUINT) * gcvCORE_COUNT);
+
+ printk(KERN_INFO "Galcore version %d.%d.%d.%d\n",
+ gcvVERSION_MAJOR, gcvVERSION_MINOR, gcvVERSION_PATCH, gcvVERSION_BUILD);
+
+ args.powerManagement = powerManagement;
+ args.gpuProfiler = gpuProfiler;
+
+ if (showArgs)
+ {
+ gckOS_DumpParam();
+ }
+
+ if (logFileSize != 0)
+ {
+ gckDEBUGFS_Initialize();
+ }
+
+ /* Create the GAL device. */
+ status = gckGALDEVICE_Construct(
+ irqLine,
+ registerMemBase, registerMemSize,
+ irqLine2D,
+ registerMemBase2D, registerMemSize2D,
+ irqLineVG,
+ registerMemBaseVG, registerMemSizeVG,
+ contiguousBase, contiguousSize,
+ externalBase, externalSize,
+ bankSize, fastClear, compression, baseAddress, physSize, signal,
+ logFileSize,
+ powerManagement,
+ gpuProfiler,
+ &args,
+ &device
+ );
+
+ if (gcmIS_ERROR(status))
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): Failed to create the GAL device: status=%d\n",
+ __FUNCTION__, __LINE__, status);
+
+ goto OnError;
+ }
+
+ /* Start the GAL device. */
+ gcmkONERROR(gckGALDEVICE_Start(device));
+
+ if ((physSize != 0)
+ && (device->kernels[gcvCORE_MAJOR] != gcvNULL)
+ && (device->kernels[gcvCORE_MAJOR]->hardware->mmuVersion != 0))
+ {
+ /* Reset the base address */
+ device->baseAddress = 0;
+ }
+
+ /* Set global galDevice pointer. */
+ galDevice = device;
+
+ if (type == 1)
+ {
+ /* Register as misc driver. */
+ ret = misc_register(&gal_device);
+
+ if (ret < 0)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): misc_register fails.\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+ }
+ else
+ {
+ /* Register the character device. */
+ ret = register_chrdev(major, DEVICE_NAME, &driver_fops);
+
+ if (ret < 0)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): Could not allocate major number for mmap.\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ if (major == 0)
+ {
+ major = ret;
+ }
+
+ /* Create the device class. */
+ device_class = class_create(THIS_MODULE, CLASS_NAME);
+
+ if (IS_ERR(device_class))
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_DRIVER,
+ "%s(%d): Failed to create the class.\n",
+ __FUNCTION__, __LINE__
+ );
+
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+ device_create(device_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);
+#else
+ device_create(device_class, NULL, MKDEV(major, 0), DEVICE_NAME);
+#endif
+
+ gpuClass = device_class;
+ }
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_DRIVER,
+ "%s(%d): irqLine=%d, contiguousSize=%lu, memBase=0x%lX\n",
+ __FUNCTION__, __LINE__,
+ irqLine, contiguousSize, registerMemBase
+ );
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return 0;
+
+OnError:
+ /* Roll back. */
+ if (device_class != gcvNULL)
+ {
+ device_destroy(device_class, MKDEV(major, 0));
+ class_destroy(device_class);
+ }
+
+ if (device != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckGALDEVICE_Stop(device));
+ gcmkVERIFY_OK(gckGALDEVICE_Destroy(device));
+ }
+
+ gcmkFOOTER();
+ return result;
+}
+
+static void drv_exit(void)
+{
+ gcmkHEADER();
+
+ if (type == 1)
+ {
+ misc_deregister(&gal_device);
+ }
+ else
+ {
+ gcmkASSERT(gpuClass != gcvNULL);
+ device_destroy(gpuClass, MKDEV(major, 0));
+ class_destroy(gpuClass);
+
+ unregister_chrdev(major, DEVICE_NAME);
+ }
+
+ gcmkVERIFY_OK(gckGALDEVICE_Stop(galDevice));
+ gcmkVERIFY_OK(gckGALDEVICE_Destroy(galDevice));
+
+ if(gckDEBUGFS_IsEnabled())
+ {
+ gckDEBUGFS_Terminate();
+ }
+
+ gcmkFOOTER_NO();
+}
+
+#if gcdENABLE_DRM
+int viv_drm_probe(struct device *dev);
+int viv_drm_remove(struct device *dev);
+#endif
+
+#if USE_LINUX_PCIE
+static int gpu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+#else /* USE_LINUX_PCIE */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ static int gpu_probe(struct platform_device *pdev)
+#else
+ static int __devinit gpu_probe(struct platform_device *pdev)
+#endif
+#endif /* USE_LINUX_PCIE */
+{
+ int ret = -ENODEV;
+ gcsMODULE_PARAMETERS moduleParam = {
+ .irqLine = irqLine,
+ .registerMemBase = registerMemBase,
+ .registerMemSize = registerMemSize,
+ .irqLine2D = irqLine2D,
+ .registerMemBase2D = registerMemBase2D,
+ .registerMemSize2D = registerMemSize2D,
+ .irqLineVG = irqLineVG,
+ .registerMemBaseVG = registerMemBaseVG,
+ .registerMemSizeVG = registerMemSizeVG,
+ .contiguousSize = contiguousSize,
+ .contiguousBase = contiguousBase,
+ .externalSize = externalSize,
+ .externalBase = externalBase,
+ .bankSize = bankSize,
+ .fastClear = fastClear,
+ .powerManagement = powerManagement,
+ .gpuProfiler = gpuProfiler,
+ .signal = signal,
+ .baseAddress = baseAddress,
+ .physSize = physSize,
+ .logFileSize = logFileSize,
+ .recovery = recovery,
+ .stuckDump = stuckDump,
+ .showArgs = showArgs,
+ .gpu3DMinClock = gpu3DMinClock,
+ .registerMemMapped = registerMemMapped,
+ };
+
+ gcmkHEADER();
+
+ memcpy(moduleParam.irqs, irqs, gcmSIZEOF(gctINT) * gcvCORE_COUNT);
+ memcpy(moduleParam.registerBases, registerBases, gcmSIZEOF(gctUINT) * gcvCORE_COUNT);
+ memcpy(moduleParam.registerSizes, registerSizes, gcmSIZEOF(gctUINT) * gcvCORE_COUNT);
+ memcpy(moduleParam.chipIDs, chipIDs, gcmSIZEOF(gctUINT) * gcvCORE_COUNT);
+ moduleParam.compression = compression;
+ platform->device = pdev;
+#if USE_LINUX_PCIE
+ if (pci_enable_device(pdev)) {
+ printk(KERN_ERR "galcore: pci_enable_device() failed.\n");
+ }
+
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ printk(KERN_ERR "galcore: Failed to set DMA mask.\n");
+ }
+
+ pci_set_master(pdev);
+
+ if (pci_request_regions(pdev, "galcore")) {
+ printk(KERN_ERR "galcore: Failed to get ownership of BAR region.\n");
+ }
+
+#if USE_MSI
+ if (pci_enable_msi(pdev)) {
+ printk(KERN_ERR "galcore: Failed to enable MSI.\n");
+ }
+#endif
+#endif
+
+ if (platform->ops->getPower)
+ {
+ if (gcmIS_ERROR(platform->ops->getPower(platform)))
+ {
+ gcmkFOOTER_NO();
+ return ret;
+ }
+ }
+
+ if (platform->ops->adjustParam)
+ {
+ /* Override default module param. */
+ platform->ops->adjustParam(platform, &moduleParam);
+
+ /* Update module param because drv_init() uses them directly. */
+ _UpdateModuleParam(&moduleParam);
+ }
+
+ ret = drv_init();
+
+ if (!ret)
+ {
+#if USE_LINUX_PCIE
+ pci_set_drvdata(pdev, galDevice);
+#else
+ platform_set_drvdata(pdev, galDevice);
+#endif
+
+#if gcdENABLE_DRM
+ ret = viv_drm_probe(&pdev->dev);
+#endif
+ }
+
+ if (ret < 0)
+ {
+ gcmkFOOTER_ARG(KERN_INFO "Failed to register gpu driver: %d\n", ret);
+ }
+ else
+ {
+ gcmkFOOTER_NO();
+ }
+ return ret;
+}
+
+#if USE_LINUX_PCIE
+static void gpu_remove(struct pci_dev *pdev)
+#else /* USE_LINUX_PCIE */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ static int gpu_remove(struct platform_device *pdev)
+#else
+ static int __devexit gpu_remove(struct platform_device *pdev)
+#endif
+#endif /* USE_LINUX_PCIE */
+{
+ gcmkHEADER();
+
+#if gcdENABLE_DRM
+ viv_drm_remove(&pdev->dev);
+#endif
+
+ drv_exit();
+
+ if (platform->ops->putPower)
+ {
+ platform->ops->putPower(platform);
+ }
+
+#if USE_LINUX_PCIE
+ pci_set_drvdata(pdev, NULL);
+#if USE_MSI
+ pci_disable_msi(pdev);
+#endif
+ pci_clear_master(pdev);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ gcmkFOOTER_NO();
+ return;
+#else
+ gcmkFOOTER_NO();
+ return 0;
+#endif
+}
+
+static int gpu_suspend(struct platform_device *dev, pm_message_t state)
+{
+ gceSTATUS status;
+ gckGALDEVICE device;
+ gctINT i;
+
+ device = platform_get_drvdata(dev);
+
+ if (!device)
+ {
+ return -1;
+ }
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (device->kernels[i] != gcvNULL)
+ {
+ /* Store states. */
+#if gcdENABLE_VG
+ if (i == gcvCORE_VG)
+ {
+ status = gckVGHARDWARE_QueryPowerManagementState(device->kernels[i]->vg->hardware, &device->statesStored[i]);
+ }
+ else
+#endif
+ {
+ status = gckHARDWARE_QueryPowerManagementState(device->kernels[i]->hardware, &device->statesStored[i]);
+ }
+
+ if (gcmIS_ERROR(status))
+ {
+ return -1;
+ }
+
+ /* need pull up power to flush gpu command buffer before suspend */
+#if gcdENABLE_VG
+ if (i == gcvCORE_VG)
+ {
+ status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, gcvPOWER_ON);
+ }
+ else
+#endif
+ {
+ status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, gcvPOWER_ON);
+ }
+
+ if (gcmIS_ERROR(status))
+ {
+ return -1;
+ }
+
+#if gcdENABLE_VG
+ if (i == gcvCORE_VG)
+ {
+ status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, gcvPOWER_OFF);
+ }
+ else
+#endif
+ {
+ status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, gcvPOWER_OFF);
+ }
+
+ if (gcmIS_ERROR(status))
+ {
+ return -1;
+ }
+
+ }
+ }
+
+ return 0;
+}
+
+static int gpu_resume(struct platform_device *dev)
+{
+ gceSTATUS status;
+ gckGALDEVICE device;
+ gctINT i;
+ gceCHIPPOWERSTATE statesStored;
+
+ device = platform_get_drvdata(dev);
+
+ if (!device)
+ {
+ return -1;
+ }
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; i++)
+ {
+ if (device->kernels[i] != gcvNULL)
+ {
+#if gcdENABLE_VG
+ if (i == gcvCORE_VG)
+ {
+ status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, gcvPOWER_ON);
+ }
+ else
+#endif
+ {
+ status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, gcvPOWER_ON);
+ }
+
+ if (gcmIS_ERROR(status))
+ {
+ return -1;
+ }
+
+ /* Convert global state to crossponding internal state. */
+ switch(device->statesStored[i])
+ {
+ case gcvPOWER_OFF:
+ statesStored = gcvPOWER_OFF_BROADCAST;
+ break;
+ case gcvPOWER_IDLE:
+ statesStored = gcvPOWER_IDLE_BROADCAST;
+ break;
+ case gcvPOWER_SUSPEND:
+ statesStored = gcvPOWER_SUSPEND_BROADCAST;
+ break;
+ case gcvPOWER_ON:
+ statesStored = gcvPOWER_ON_AUTO;
+ break;
+ default:
+ statesStored = device->statesStored[i];
+ break;
+ }
+
+ /* Restore states. */
+#if gcdENABLE_VG
+ if (i == gcvCORE_VG)
+ {
+ status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, statesStored);
+ }
+ else
+#endif
+ {
+ gctINT j = 0;
+
+ for (; j < 100; j++)
+ {
+ status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, statesStored);
+
+ if (( statesStored != gcvPOWER_OFF_BROADCAST
+ && statesStored != gcvPOWER_SUSPEND_BROADCAST)
+ || status != gcvSTATUS_CHIP_NOT_READY)
+ {
+ break;
+ }
+
+ gcmkVERIFY_OK(gckOS_Delay(device->kernels[i]->os, 10));
+ };
+ }
+
+ if (gcmIS_ERROR(status))
+ {
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_PM) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+#ifdef CONFIG_PM_SLEEP
+static int gpu_system_suspend(struct device *dev)
+{
+ pm_message_t state={0};
+ return gpu_suspend(to_platform_device(dev), state);
+}
+
+static int gpu_system_resume(struct device *dev)
+{
+ return gpu_resume(to_platform_device(dev));
+}
+#endif
+
+static const struct dev_pm_ops gpu_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(gpu_system_suspend, gpu_system_resume)
+};
+#endif
+
+#if USE_LINUX_PCIE
+static const struct pci_device_id vivpci_ids[] = {
+ {
+ .class = 0x000000,
+ .class_mask = 0x000000,
+ .vendor = 0x10ee,
+ .device = 0x7012,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = 0
+ }, { /* End: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE(pci, vivpci_ids);
+
+static struct pci_driver gpu_driver = {
+ .name = DEVICE_NAME,
+ .id_table = vivpci_ids,
+ .probe = gpu_probe,
+ .remove = gpu_remove
+};
+
+#else /* USE_LINUX_PCIE */
+
+static struct platform_driver gpu_driver = {
+ .probe = gpu_probe,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
+ .remove = gpu_remove,
+#else
+ .remove = __devexit_p(gpu_remove),
+#endif
+
+ .suspend = gpu_suspend,
+ .resume = gpu_resume,
+
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DEVICE_NAME,
+#if defined(CONFIG_PM) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
+ .pm = &gpu_pm_ops,
+#endif
+ }
+};
+#endif /* USE_LINUX_PCIE */
+
+static int __init gpu_init(void)
+{
+ int ret = 0;
+
+ ret = soc_platform_init(&gpu_driver, &platform);
+
+ if (ret || !platform)
+ {
+ printk(KERN_ERR "galcore: Soc platform init failed.\n");
+ return -ENODEV;
+ }
+
+#if USE_LINUX_PCIE
+ ret = pci_register_driver(&gpu_driver);
+#else /* USE_LINUX_PCIE */
+ ret = platform_driver_register(&gpu_driver);
+#endif /* USE_LINUX_PCIE */
+
+ if (ret)
+ {
+ printk(KERN_ERR "galcore: gpu_init() failed to register driver!\n");
+ soc_platform_terminate(platform);
+ platform = NULL;
+ return ret;
+ }
+
+ platform->driver = &gpu_driver;
+
+ return 0;
+}
+
+static void __exit gpu_exit(void)
+{
+#if USE_LINUX_PCIE
+ pci_unregister_driver(&gpu_driver);
+#else
+ platform_driver_unregister(&gpu_driver);
+#endif /* USE_LINUX_PCIE */
+
+ soc_platform_terminate(platform);
+ platform = NULL;
+}
+
+module_init(gpu_init);
+module_exit(gpu_exit);
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_drm.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_drm.c
new file mode 100644
index 000000000000..b4846cb65bb8
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_drm.c
@@ -0,0 +1,813 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#if gcdENABLE_DRM
+
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+#include <linux/dma-buf.h>
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_drm.h"
+
+#define _GC_OBJ_ZONE gcvZONE_KERNEL
+
+/******************************************************************************\
+******************************* gckKERNEL DRM Code ******************************
+\******************************************************************************/
+
+struct viv_gem_object {
+ struct drm_gem_object base;
+
+ uint32_t node_handle;
+ gckVIDMEM_NODE node_object;
+};
+
+struct dma_buf *viv_gem_prime_export(struct drm_device *drm,
+ struct drm_gem_object *gem_obj,
+ int flags)
+{
+ struct viv_gem_object *viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+ struct dma_buf *dmabuf = gcvNULL;
+ gckGALDEVICE gal_dev = (gckGALDEVICE)drm->dev_private;
+
+ if (gal_dev)
+ {
+ gckKERNEL kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0];
+ gcmkVERIFY_OK(gckVIDMEM_NODE_Export(kernel, viv_obj->node_handle, flags,
+ (gctPOINTER*)&dmabuf, gcvNULL));
+ }
+
+ return dmabuf;
+}
+
+struct drm_gem_object *viv_gem_prime_import(struct drm_device *drm,
+ struct dma_buf *dmabuf)
+{
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj;
+
+ gcsHAL_INTERFACE iface;
+ gckGALDEVICE gal_dev;
+ gckKERNEL kernel;
+ gctUINT32 processID;
+ gckVIDMEM_NODE nodeObject;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gckOS_ZeroMemory(&iface, sizeof(iface));
+ iface.command = gcvHAL_WRAP_USER_MEMORY;
+ iface.hardwareType = gal_dev->device->defaultHwType;
+ iface.u.WrapUserMemory.desc.flag = gcvALLOC_FLAG_DMABUF;
+ iface.u.WrapUserMemory.desc.handle = -1;
+ iface.u.WrapUserMemory.desc.dmabuf = gcmPTR_TO_UINT64(dmabuf);
+ gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+ kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0];
+ gcmkONERROR(gckOS_GetProcessID(&processID));
+ gcmkONERROR(gckVIDMEM_HANDLE_Lookup(kernel, processID, iface.u.WrapUserMemory.node, &nodeObject));
+
+ /* ioctl output */
+ gem_obj = kzalloc(sizeof(struct viv_gem_object), GFP_KERNEL);
+ drm_gem_private_object_init(drm, gem_obj, dmabuf->size);
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+ viv_obj->node_handle = iface.u.WrapUserMemory.node;
+ viv_obj->node_object = nodeObject;
+
+OnError:
+ return gem_obj;
+}
+
+void viv_gem_free_object(struct drm_gem_object *gem_obj)
+{
+ struct viv_gem_object *viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+ struct drm_device *drm = gem_obj->dev;
+
+ gcsHAL_INTERFACE iface;
+ gckGALDEVICE gal_dev = (gckGALDEVICE)drm->dev_private;
+
+ gckOS_ZeroMemory(&iface, sizeof(iface));
+ iface.command = gcvHAL_RELEASE_VIDEO_MEMORY;
+ iface.hardwareType = gal_dev->device->defaultHwType;
+ iface.u.ReleaseVideoMemory.node = viv_obj->node_handle;
+ gcmkVERIFY_OK(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+ drm_gem_object_release(gem_obj);
+ kfree(gem_obj);
+}
+
+static int viv_ioctl_gem_create(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ int ret = 0;
+ struct drm_viv_gem_create *args = (struct drm_viv_gem_create*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gcsHAL_INTERFACE iface;
+ gckGALDEVICE gal_dev;
+ gckKERNEL kernel;
+ gctUINT32 processID;
+ gckVIDMEM_NODE nodeObject;
+ gctUINT32 flags = gcvALLOC_FLAG_DMABUF_EXPORTABLE;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ if (args->flags & DRM_VIV_GEM_CONTIGUOUS)
+ {
+ flags |= gcvALLOC_FLAG_CONTIGUOUS;
+ }
+ if (args->flags & DRM_VIV_GEM_CACHED)
+ {
+ flags |= gcvALLOC_FLAG_CACHEABLE;
+ }
+ if (args->flags & DRM_VIV_GEM_SECURE)
+ {
+ flags |= gcvALLOC_FLAG_SECURITY;
+ }
+ if (args->flags & DRM_VIV_GEM_CMA_LIMIT)
+ {
+ flags |= gcvALLOC_FLAG_CMA_LIMIT;
+ }
+
+ gckOS_ZeroMemory(&iface, sizeof(iface));
+ iface.command = gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY;
+ iface.hardwareType = gal_dev->device->defaultHwType;
+ iface.u.AllocateLinearVideoMemory.bytes = PAGE_ALIGN(args->size);
+ iface.u.AllocateLinearVideoMemory.alignment = 256;
+ iface.u.AllocateLinearVideoMemory.type = gcvSURF_RENDER_TARGET; /* should be general */
+ iface.u.AllocateLinearVideoMemory.flag = flags;
+ iface.u.AllocateLinearVideoMemory.pool = gcvPOOL_DEFAULT;
+ gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+ kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0];
+ gcmkONERROR(gckOS_GetProcessID(&processID));
+ gcmkONERROR(gckVIDMEM_HANDLE_Lookup(kernel, processID, iface.u.AllocateLinearVideoMemory.node, &nodeObject));
+
+ /* ioctl output */
+ gem_obj = kzalloc(sizeof(struct viv_gem_object), GFP_KERNEL);
+ drm_gem_private_object_init(drm, gem_obj, iface.u.AllocateLinearVideoMemory.bytes);
+ ret = drm_gem_handle_create(file, gem_obj, &args->handle);
+
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+ viv_obj->node_handle = iface.u.AllocateLinearVideoMemory.node;
+ viv_obj->node_object = nodeObject;
+
+ /* drop reference from allocate - handle holds it now */
+ drm_gem_object_unreference_unlocked(gem_obj);
+
+OnError:
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_lock(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_lock *args = (struct drm_viv_gem_lock*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gcsHAL_INTERFACE iface;
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+ gckOS_ZeroMemory(&iface, sizeof(iface));
+ iface.command = gcvHAL_LOCK_VIDEO_MEMORY;
+ iface.hardwareType = gal_dev->device->defaultHwType;
+ iface.u.LockVideoMemory.node = viv_obj->node_handle;
+ iface.u.LockVideoMemory.cacheable = args->cacheable;
+ gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+ args->logical = iface.u.LockVideoMemory.memory;
+
+OnError:
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+ }
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_unlock(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_unlock *args = (struct drm_viv_gem_unlock*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gcsHAL_INTERFACE iface;
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+ memset(&iface, 0, sizeof(iface));
+ iface.command = gcvHAL_UNLOCK_VIDEO_MEMORY;
+ iface.hardwareType = gal_dev->device->defaultHwType;
+ iface.u.UnlockVideoMemory.node = (gctUINT64)viv_obj->node_handle;
+ iface.u.UnlockVideoMemory.type = gcvSURF_TYPE_UNKNOWN;
+ gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+ memset(&iface, 0, sizeof(iface));
+ iface.command = gcvHAL_BOTTOM_HALF_UNLOCK_VIDEO_MEMORY;
+ iface.hardwareType = gal_dev->device->defaultHwType;
+ iface.u.BottomHalfUnlockVideoMemory.node = (gctUINT64)viv_obj->node_handle;
+ iface.u.BottomHalfUnlockVideoMemory.type = gcvSURF_TYPE_UNKNOWN;
+ gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+OnError:
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+ }
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_cache(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_cache *args = (struct drm_viv_gem_cache*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gcsHAL_INTERFACE iface;
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+ gceCACHEOPERATION cache_op = 0;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+ switch (args->op)
+ {
+ case DRM_VIV_GEM_CLEAN_CACHE:
+ cache_op = gcvCACHE_CLEAN;
+ break;
+ case DRM_VIV_GEM_INVALIDATE_CACHE:
+ cache_op = gcvCACHE_INVALIDATE;
+ break;
+ case DRM_VIV_GEM_FLUSH_CACHE:
+ cache_op = gcvCACHE_FLUSH;
+ break;
+ case DRM_VIV_GEM_MEMORY_BARRIER:
+ cache_op = gcvCACHE_MEMORY_BARRIER;
+ break;
+ default:
+ break;
+ }
+
+ gckOS_ZeroMemory(&iface, sizeof(iface));
+ iface.command = gcvHAL_CACHE;
+ iface.hardwareType = gal_dev->device->defaultHwType;
+ iface.u.Cache.node = viv_obj->node_handle;
+ iface.u.Cache.operation = cache_op;
+ iface.u.Cache.logical = args->logical;
+ iface.u.Cache.bytes = args->bytes;
+ gcmkONERROR(gckDEVICE_Dispatch(gal_dev->device, &iface));
+
+OnError:
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+ }
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_query(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_query *args = (struct drm_viv_gem_query*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+ switch (args->param)
+ {
+ case DRM_VIV_GEM_PARAM_POOL:
+ args->value = (__u64)viv_obj->node_object->pool;
+ break;
+ case DRM_VIV_GEM_PARAM_SIZE:
+ args->value = (__u64)gem_obj->size;
+ break;
+ default:
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+OnError:
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+ }
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_timestamp(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_timestamp *args = (struct drm_viv_gem_timestamp *)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+ viv_obj->node_object->timeStamp += args->inc;
+ args->timestamp = viv_obj->node_object->timeStamp;
+
+OnError:
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+ }
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_set_tiling(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_set_tiling *args = (struct drm_viv_gem_set_tiling*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+ viv_obj->node_object->tilingMode = args->tiling_mode;
+ viv_obj->node_object->tsMode = args->ts_mode;
+ viv_obj->node_object->clearValue = args->clear_value;
+
+OnError:
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+ }
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_get_tiling(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_get_tiling *args = (struct drm_viv_gem_get_tiling*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+
+ args->tiling_mode = viv_obj->node_object->tilingMode;
+ args->ts_mode = viv_obj->node_object->tsMode;
+ args->clear_value = viv_obj->node_object->clearValue;
+
+OnError:
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+ }
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_attach_aux(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_attach_aux *args = (struct drm_viv_gem_attach_aux*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+ struct drm_gem_object *gem_ts_obj = gcvNULL;
+
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+ gckVIDMEM_NODE nodeObj = gcvNULL;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+ nodeObj = viv_obj->node_object;
+
+ /* do not support re-attach */
+ if (nodeObj->tsNode)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ if (args->ts_handle)
+ {
+ struct viv_gem_object *viv_ts_obj;
+ gckKERNEL kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0];
+
+ gem_ts_obj = drm_gem_object_lookup(file, args->ts_handle);
+ if (!gem_ts_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_ts_obj = container_of(gem_ts_obj, struct viv_gem_object, base);
+
+ gcmkONERROR(gckVIDMEM_NODE_Reference(kernel, viv_ts_obj->node_object));
+ nodeObj->tsNode = viv_ts_obj->node_object;
+ }
+
+OnError:
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+
+ if (gem_ts_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_ts_obj);
+ }
+ }
+ return gcmIS_ERROR(status) ? -ENOTTY : 0;
+}
+
+static int viv_ioctl_gem_ref_node(struct drm_device *drm, void *data,
+ struct drm_file *file)
+{
+ struct drm_viv_gem_ref_node *args = (struct drm_viv_gem_ref_node*)data;
+ struct drm_gem_object *gem_obj = gcvNULL;
+ struct viv_gem_object *viv_obj = gcvNULL;
+
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+ gckKERNEL kernel = gcvNULL;
+ gctUINT32 processID;
+ gckVIDMEM_NODE nodeObj;
+ gctUINT32 nodeHandle = 0, tsNodeHandle = 0;
+ gctBOOL refered = gcvFALSE;
+ int ret = 0;
+
+ gal_dev = (gckGALDEVICE)drm->dev_private;
+ if (!gal_dev)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+ kernel = gal_dev->device->map[gal_dev->device->defaultHwType].kernels[0];
+
+ gem_obj = drm_gem_object_lookup(file, args->handle);
+ if (!gem_obj)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+ viv_obj = container_of(gem_obj, struct viv_gem_object, base);
+ nodeObj = viv_obj->node_object;
+
+ gcmkONERROR(gckOS_GetProcessID(&processID));
+ gcmkONERROR(gckVIDMEM_HANDLE_Allocate(kernel, nodeObj, &nodeHandle));
+ gcmkONERROR(
+ gckKERNEL_AddProcessDB(kernel,
+ processID, gcvDB_VIDEO_MEMORY,
+ gcmINT2PTR(nodeHandle),
+ gcvNULL,
+ 0));
+ gcmkONERROR(gckVIDMEM_NODE_Reference(kernel, nodeObj));
+ refered = gcvTRUE;
+
+ if (nodeObj->tsNode)
+ {
+ gcmkONERROR(gckVIDMEM_HANDLE_Allocate(kernel, nodeObj->tsNode, &tsNodeHandle));
+ gcmkONERROR(
+ gckKERNEL_AddProcessDB(kernel,
+ processID, gcvDB_VIDEO_MEMORY,
+ gcmINT2PTR(tsNodeHandle),
+ gcvNULL,
+ 0));
+ gcmkONERROR(gckVIDMEM_NODE_Reference(kernel, nodeObj->tsNode));
+ }
+ args->node = nodeHandle;
+ args->ts_node = tsNodeHandle;
+
+OnError:
+ if (gcmIS_ERROR(status) && kernel)
+ {
+ gctUINT32 processID;
+
+ gcmkVERIFY_OK(gckOS_GetProcessID(&processID));
+
+ if (tsNodeHandle)
+ {
+ gckVIDMEM_HANDLE_Dereference(kernel, processID, tsNodeHandle);
+ }
+
+ if (nodeHandle)
+ {
+ gckVIDMEM_HANDLE_Dereference(kernel, processID, nodeHandle);
+ }
+
+ if (refered)
+ {
+ gcmkONERROR(gckVIDMEM_NODE_Dereference(kernel, nodeObj));
+ }
+
+ args->node = 0;
+ args->ts_node = 0;
+
+ ret = -ENOTTY;
+ }
+
+ if (gem_obj)
+ {
+ drm_gem_object_unreference_unlocked(gem_obj);
+ }
+
+ return ret;
+}
+
+static const struct drm_ioctl_desc viv_ioctls[] =
+{
+ DRM_IOCTL_DEF_DRV(VIV_GEM_CREATE, viv_ioctl_gem_create, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_LOCK, viv_ioctl_gem_lock, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_UNLOCK, viv_ioctl_gem_unlock, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_CACHE, viv_ioctl_gem_cache, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_QUERY, viv_ioctl_gem_query, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_TIMESTAMP, viv_ioctl_gem_timestamp, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_SET_TILING, viv_ioctl_gem_set_tiling, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_GET_TILING, viv_ioctl_gem_get_tiling, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_ATTACH_AUX, viv_ioctl_gem_attach_aux, DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(VIV_GEM_REF_NODE, viv_ioctl_gem_ref_node, DRM_AUTH | DRM_RENDER_ALLOW),
+};
+
+int viv_drm_open(struct drm_device *drm, struct drm_file *file)
+{
+ gctINT i;
+ gctUINT32 pid = _GetProcessID();
+ gckGALDEVICE gal_dev = (gckGALDEVICE)drm->dev_private;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; ++i)
+ {
+ if (gal_dev->kernels[i])
+ {
+ gcmkONERROR(gckKERNEL_AttachProcessEx(gal_dev->kernels[i], gcvTRUE, pid));
+ }
+ }
+ file->driver_priv = gcmINT2PTR(pid);
+
+OnError:
+ return gcmIS_ERROR(status) ? -ENODEV : 0;
+}
+
+void viv_drm_postclose(struct drm_device *drm, struct drm_file *file)
+{
+ gctINT i;
+ gctUINT32 pid = gcmPTR2INT(file->driver_priv);
+ gckGALDEVICE gal_dev = (gckGALDEVICE)drm->dev_private;
+
+ for (i = 0; i < gcdMAX_GPU_COUNT; ++i)
+ {
+ if (gal_dev->kernels[i])
+ {
+ gcmkVERIFY_OK(gckKERNEL_AttachProcessEx(gal_dev->kernels[i], gcvFALSE, pid));
+ }
+ }
+}
+
+static const struct file_operations viv_drm_fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
+ .poll = drm_poll,
+ .read = drm_read,
+ .llseek = no_llseek,
+};
+
+static struct drm_driver viv_drm_driver = {
+ .driver_features = DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER,
+ .open = viv_drm_open,
+ .postclose = viv_drm_postclose,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0)
+ .gem_free_object_unlocked = viv_gem_free_object,
+#else
+ .gem_free_object = viv_gem_free_object,
+#endif
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = viv_gem_prime_export,
+ .gem_prime_import = viv_gem_prime_import,
+ .ioctls = viv_ioctls,
+ .num_ioctls = DRM_VIV_NUM_IOCTLS,
+ .fops = &viv_drm_fops,
+ .name = "vivante",
+ .desc = "vivante DRM",
+ .date = "20170808",
+ .major = 1,
+ .minor = 0,
+};
+
+int viv_drm_probe(struct device *dev)
+{
+ int ret = 0;
+ gceSTATUS status = gcvSTATUS_OK;
+ gckGALDEVICE gal_dev = gcvNULL;
+ struct drm_device *drm = gcvNULL;
+
+ gal_dev = (gckGALDEVICE)dev_get_drvdata(dev);
+ if (!gal_dev)
+ {
+ ret = -ENODEV;
+ gcmkONERROR(gcvSTATUS_INVALID_OBJECT);
+ }
+
+ drm = drm_dev_alloc(&viv_drm_driver, dev);
+ if (IS_ERR(drm))
+ {
+ ret = PTR_ERR(drm);
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+ drm->dev_private = (void*)gal_dev;
+
+ ret = drm_dev_register(drm, 0);
+ if (ret)
+ {
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+ gal_dev->drm = (void*)drm;
+
+OnError:
+ if (gcmIS_ERROR(status))
+ {
+ if (drm)
+ {
+ drm_dev_unref(drm);
+ }
+ printk(KERN_ERR "galcore: Failed to setup drm device.\n");
+ }
+ return ret;
+}
+
+int viv_drm_remove(struct device *dev)
+{
+ gckGALDEVICE gal_dev = (gckGALDEVICE)dev_get_drvdata(dev);
+
+ if (gal_dev)
+ {
+ struct drm_device *drm = (struct drm_device*)gal_dev->drm;
+
+ drm_dev_unregister(drm);
+ drm_dev_unref(drm);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_iommu.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_iommu.c
new file mode 100644
index 000000000000..f36e11682f91
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_iommu.c
@@ -0,0 +1,250 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_device.h"
+
+#include <linux/iommu.h>
+#include <linux/platform_device.h>
+
+#define _GC_OBJ_ZONE gcvZONE_OS
+
+typedef struct _gcsIOMMU
+{
+ struct iommu_domain * domain;
+ struct device * device;
+}
+gcsIOMMU;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+static int
+_IOMMU_Fault_Handler(
+ struct iommu_domain * Domain,
+ struct device * Dev,
+ unsigned long DomainAddress,
+ int flags,
+ void * args
+ )
+#else
+static int
+_IOMMU_Fault_Handler(
+ struct iommu_domain * Domain,
+ struct device * Dev,
+ unsigned long DomainAddress,
+ int flags
+ )
+#endif
+{
+ return 0;
+}
+
+static int
+_FlatMapping(
+ IN gckIOMMU Iommu
+ )
+{
+ gceSTATUS status;
+ gctUINT32 physical;
+
+ for (physical = 0; physical < 0x80000000; physical += PAGE_SIZE)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "Map %x => %x bytes = %d",
+ physical, physical, PAGE_SIZE
+ );
+
+ gcmkONERROR(gckIOMMU_Map(Iommu, physical, physical, PAGE_SIZE));
+ }
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+void
+gckIOMMU_Destory(
+ IN gckOS Os,
+ IN gckIOMMU Iommu
+ )
+{
+ gcmkHEADER();
+
+ if (Iommu->domain && Iommu->device)
+ {
+ iommu_attach_device(Iommu->domain, Iommu->device);
+ }
+
+ if (Iommu->domain)
+ {
+ iommu_domain_free(Iommu->domain);
+ }
+
+ if (Iommu)
+ {
+ gcmkOS_SAFE_FREE(Os, Iommu);
+ }
+
+ gcmkFOOTER_NO();
+}
+
+gceSTATUS
+gckIOMMU_Construct(
+ IN gckOS Os,
+ OUT gckIOMMU * Iommu
+ )
+{
+ gceSTATUS status;
+ gckIOMMU iommu = gcvNULL;
+ struct device *dev;
+ int ret;
+
+ gcmkHEADER();
+
+ dev = &Os->device->platform->device->dev;
+
+ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcsIOMMU), (gctPOINTER *)&iommu));
+
+ gckOS_ZeroMemory(iommu, gcmSIZEOF(gcsIOMMU));
+
+ iommu->domain = iommu_domain_alloc(&platform_bus_type);
+
+ if (!iommu->domain)
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "iommu_domain_alloc() fail");
+
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+ iommu_set_fault_handler(iommu->domain, _IOMMU_Fault_Handler, dev);
+#else
+ iommu_set_fault_handler(iommu->domain, _IOMMU_Fault_Handler);
+#endif
+
+ ret = iommu_attach_device(iommu->domain, dev);
+
+ if (ret)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS, "iommu_attach_device() fail %d", ret);
+
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ iommu->device = dev;
+
+ _FlatMapping(iommu);
+
+ *Iommu = iommu;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+
+ gckIOMMU_Destory(Os, iommu);
+
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckIOMMU_Map(
+ IN gckIOMMU Iommu,
+ IN gctUINT32 DomainAddress,
+ IN gctUINT32 Physical,
+ IN gctUINT32 Bytes
+ )
+{
+ gceSTATUS status;
+ int ret;
+
+ gcmkHEADER_ARG("DomainAddress=%#X, Physical=%#X, Bytes=%d",
+ DomainAddress, Physical, Bytes);
+
+ ret = iommu_map(Iommu->domain, DomainAddress, Physical, Bytes, 0);
+
+ if (ret)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+
+ gcmkFOOTER();
+ return status;
+
+}
+
+gceSTATUS
+gckIOMMU_Unmap(
+ IN gckIOMMU Iommu,
+ IN gctUINT32 DomainAddress,
+ IN gctUINT32 Bytes
+ )
+{
+ gcmkHEADER();
+
+ iommu_unmap(Iommu->domain, DomainAddress, Bytes);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.c
new file mode 100644
index 000000000000..bcda2c161874
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.c
@@ -0,0 +1,518 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+
+#define _GC_OBJ_ZONE gcvZONE_KERNEL
+
+/******************************************************************************\
+******************************* gckKERNEL API Code ******************************
+\******************************************************************************/
+
+/*******************************************************************************
+**
+** gckKERNEL_QueryVideoMemory
+**
+** Query the amount of video memory.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** OUTPUT:
+**
+** gcsHAL_INTERFACE * Interface
+** Pointer to an gcsHAL_INTERFACE structure that will be filled in with
+** the memory information.
+*/
+gceSTATUS
+gckKERNEL_QueryVideoMemory(
+ IN gckKERNEL Kernel,
+ OUT gcsHAL_INTERFACE * Interface
+ )
+{
+ gckGALDEVICE device;
+
+ gcmkHEADER_ARG("Kernel=%p", Kernel);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Interface != NULL);
+
+ /* Extract the pointer to the gckGALDEVICE class. */
+ device = (gckGALDEVICE) Kernel->context;
+
+ /* Get internal memory size and physical address. */
+ Interface->u.QueryVideoMemory.internalSize = device->internalSize;
+ Interface->u.QueryVideoMemory.internalPhysical = device->internalPhysicalName;
+
+ /* Get external memory size and physical address. */
+ Interface->u.QueryVideoMemory.externalSize = device->externalSize;
+ Interface->u.QueryVideoMemory.externalPhysical = device->externalPhysicalName;
+
+ /* Get contiguous memory size and physical address. */
+ Interface->u.QueryVideoMemory.contiguousSize = device->contiguousSize;
+ Interface->u.QueryVideoMemory.contiguousPhysical = device->contiguousPhysicalName;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_GetVideoMemoryPool
+**
+** Get the gckVIDMEM object belonging to the specified pool.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gcePOOL Pool
+** Pool to query gckVIDMEM object for.
+**
+** OUTPUT:
+**
+** gckVIDMEM * VideoMemory
+** Pointer to a variable that will hold the pointer to the gckVIDMEM
+** object belonging to the requested pool.
+*/
+gceSTATUS
+gckKERNEL_GetVideoMemoryPool(
+ IN gckKERNEL Kernel,
+ IN gcePOOL Pool,
+ OUT gckVIDMEM * VideoMemory
+ )
+{
+ gckGALDEVICE device;
+ gckVIDMEM videoMemory;
+
+ gcmkHEADER_ARG("Kernel=%p Pool=%d", Kernel, Pool);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(VideoMemory != NULL);
+
+ /* Extract the pointer to the gckGALDEVICE class. */
+ device = (gckGALDEVICE) Kernel->context;
+
+ /* Dispatch on pool. */
+ switch (Pool)
+ {
+ case gcvPOOL_LOCAL_INTERNAL:
+ /* Internal memory. */
+ videoMemory = device->internalVidMem;
+ break;
+
+ case gcvPOOL_LOCAL_EXTERNAL:
+ /* External memory. */
+ videoMemory = device->externalVidMem;
+ break;
+
+ case gcvPOOL_SYSTEM:
+ /* System memory. */
+ videoMemory = device->contiguousVidMem;
+ break;
+
+ default:
+ /* Unknown pool. */
+ videoMemory = NULL;
+ }
+
+ /* Return pointer to the gckVIDMEM object. */
+ *VideoMemory = videoMemory;
+
+ /* Return status. */
+ gcmkFOOTER_ARG("*VideoMemory=%p", *VideoMemory);
+ return (videoMemory == NULL) ? gcvSTATUS_OUT_OF_MEMORY : gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_MapMemory
+**
+** Map video memory into the current process space.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctPHYS_ADDR Physical
+** Physical address of video memory to map.
+**
+** gctSIZE_T Bytes
+** Number of bytes to map.
+**
+** OUTPUT:
+**
+** gctPOINTER * Logical
+** Pointer to a variable that will hold the base address of the mapped
+** memory region.
+*/
+gceSTATUS
+gckKERNEL_MapMemory(
+ IN gckKERNEL Kernel,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Logical
+ )
+{
+ gckKERNEL kernel = Kernel;
+ gctPHYS_ADDR physical = gcmNAME_TO_PTR(Physical);
+
+ return gckOS_MapMemory(Kernel->os, physical, Bytes, Logical);
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_UnmapMemory
+**
+** Unmap video memory from the current process space.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctPHYS_ADDR Physical
+** Physical address of video memory to map.
+**
+** gctSIZE_T Bytes
+** Number of bytes to map.
+**
+** gctPOINTER Logical
+** Base address of the mapped memory region.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckKERNEL_UnmapMemory(
+ IN gckKERNEL Kernel,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical,
+ IN gctUINT32 ProcessID
+ )
+{
+ gckKERNEL kernel = Kernel;
+ gctPHYS_ADDR physical = gcmNAME_TO_PTR(Physical);
+
+ return gckOS_UnmapMemoryEx(Kernel->os, physical, Bytes, Logical, ProcessID);
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_MapVideoMemory
+**
+** Get the logical address for a hardware specific memory address for the
+** current process.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctBOOL InUserSpace
+** gcvTRUE to map the memory into the user space.
+**
+** gctUINT32 Address
+** Hardware specific memory address.
+**
+** OUTPUT:
+**
+** gctPOINTER * Logical
+** Pointer to a variable that will hold the logical address of the
+** specified memory address.
+*/
+gceSTATUS
+gckKERNEL_MapVideoMemoryEx(
+ IN gckKERNEL Kernel,
+ IN gceCORE Core,
+ IN gctBOOL InUserSpace,
+ IN gctUINT32 Address,
+ IN gcePOOL Pool,
+ OUT gctPOINTER * Logical
+ )
+{
+ gckGALDEVICE device = gcvNULL;
+ gctUINT32 offset = 0;
+ gctUINT32 base = 0;
+ gctSIZE_T bytes = 0;
+ gctPHYS_ADDR physical = gcvNULL;
+ gceSTATUS status;
+ gctPOINTER logical = gcvNULL;
+#if gcdENABLE_VG
+ gcePOOL pool = gcvPOOL_UNKNOWN;
+#endif
+
+ gcmkHEADER_ARG("Kernel=%p InUserSpace=%d Address=%08x",
+ Kernel, InUserSpace, Address);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Logical != NULL);
+
+ /* Extract the pointer to the gckGALDEVICE class. */
+ device = (gckGALDEVICE) Kernel->context;
+
+#if gcdENABLE_VG
+ if (Core == gcvCORE_VG)
+ {
+ /* Split the memory address into a pool type and offset. */
+ gcmkONERROR(
+ gckVGHARDWARE_SplitMemory(Kernel->vg->hardware, Address, &pool, &offset));
+ }
+ else
+#endif
+ {
+ offset = Address;
+ }
+
+ /* Dispatch on pool. */
+ switch (Pool)
+ {
+ case gcvPOOL_LOCAL_INTERNAL:
+ /* Internal memory. */
+ logical = device->internalLogical;
+ /* Impossible to use per device logical for all user processes. */
+ BUG_ON("Incorrect path");
+ break;
+
+ case gcvPOOL_LOCAL_EXTERNAL:
+ physical = device->externalPhysical;
+ bytes = device->externalSize;
+
+#if gcdENABLE_VG
+ if (Core == gcvCORE_VG)
+ {
+ gcmkVERIFY_OK(
+ gckVGHARDWARE_SplitMemory(Kernel->vg->hardware,
+ device->externalVidMem->baseAddress,
+ &pool,
+ &base));
+ }
+ else
+#endif
+ {
+ base = Kernel->externalBaseAddress;
+ }
+
+ break;
+
+ case gcvPOOL_SYSTEM:
+ /* System memory. */
+ physical = device->contiguousPhysical;
+ bytes = device->contiguousSize;
+
+#if gcdENABLE_VG
+ if (Core == gcvCORE_VG)
+ {
+ gcmkVERIFY_OK(
+ gckVGHARDWARE_SplitMemory(Kernel->vg->hardware,
+ device->contiguousVidMem->baseAddress,
+ &pool,
+ &base));
+ }
+ else
+#endif
+ {
+ base = Kernel->contiguousBaseAddress;
+ }
+
+ break;
+
+ default:
+ /* Invalid memory pool. */
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ gcmkONERROR(gckOS_MapMemory(Kernel->os, physical, bytes, &logical));
+
+ /* GPU address offset */
+ offset -= base;
+
+ /* Build logical address of specified address. */
+ *Logical = (gctPOINTER) ((gctUINT8_PTR) logical + offset);
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Logical=%p", *Logical);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Retunn the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckKERNEL_MapVideoMemory
+**
+** Get the logical address for a hardware specific memory address for the
+** current process.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gctBOOL InUserSpace
+** gcvTRUE to map the memory into the user space.
+**
+** gctUINT32 Address
+** Hardware specific memory address.
+**
+** OUTPUT:
+**
+** gctPOINTER * Logical
+** Pointer to a variable that will hold the logical address of the
+** specified memory address.
+*/
+gceSTATUS
+gckKERNEL_MapVideoMemory(
+ IN gckKERNEL Kernel,
+ IN gctBOOL InUserSpace,
+ IN gctUINT32 Address,
+ OUT gctPOINTER * Logical
+ )
+{
+ return gckKERNEL_MapVideoMemoryEx(Kernel, gcvCORE_MAJOR, InUserSpace, Address, gcvPOOL_SYSTEM, Logical);
+}
+/*******************************************************************************
+**
+** gckKERNEL_Notify
+**
+** This function iscalled by clients to notify the gckKERNRL object of an event.
+**
+** INPUT:
+**
+** gckKERNEL Kernel
+** Pointer to an gckKERNEL object.
+**
+** gceNOTIFY Notification
+** Notification event.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckKERNEL_Notify(
+ IN gckKERNEL Kernel,
+ IN gceNOTIFY Notification,
+ IN gctBOOL Data
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Kernel=%p Notification=%d Data=%d",
+ Kernel, Notification, Data);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+
+ /* Dispatch on notifcation. */
+ switch (Notification)
+ {
+ case gcvNOTIFY_INTERRUPT:
+ /* Process the interrupt. */
+#if COMMAND_PROCESSOR_VERSION > 1
+ status = gckINTERRUPT_Notify(Kernel->interrupt, Data);
+#else
+ status = gckHARDWARE_Interrupt(Kernel->hardware,
+ Data);
+#endif
+ break;
+
+ default:
+ status = gcvSTATUS_OK;
+ break;
+ }
+
+ /* Success. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckKERNEL_QuerySettings(
+ IN gckKERNEL Kernel,
+ OUT gcsKERNEL_SETTINGS * Settings
+ )
+{
+ gckGALDEVICE device;
+
+ gcmkHEADER_ARG("Kernel=%p", Kernel);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL);
+ gcmkVERIFY_ARGUMENT(Settings != gcvNULL);
+
+ /* Extract the pointer to the gckGALDEVICE class. */
+ device = (gckGALDEVICE) Kernel->context;
+
+ /* Fill in signal. */
+ Settings->signal = device->signal;
+
+ /* Success. */
+ gcmkFOOTER_ARG("Settings->signal=%d", Settings->signal);
+ return gcvSTATUS_OK;
+}
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.h b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.h
new file mode 100644
index 000000000000..f1ae2b196354
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_linux.h
@@ -0,0 +1,376 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_linux_h_
+#define __gc_hal_kernel_linux_h_
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+#include <linux/dma-mapping.h>
+#include <linux/kthread.h>
+
+#include <linux/idr.h>
+
+#ifdef MODVERSIONS
+# include <linux/modversions.h>
+#endif
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#if ENABLE_GPU_CLOCK_BY_DRIVER && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
+#include <linux/clk.h>
+#endif
+
+#define NTSTRSAFE_NO_CCH_FUNCTIONS
+#include "gc_hal.h"
+#include "gc_hal_driver.h"
+#include "gc_hal_kernel.h"
+#include "gc_hal_kernel_platform.h"
+#include "gc_hal_kernel_device.h"
+#include "gc_hal_kernel_os.h"
+#include "gc_hal_kernel_debugfs.h"
+#include "gc_hal_ta.h"
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+#define FIND_TASK_BY_PID(x) pid_task(find_vpid(x), PIDTYPE_PID)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+#define FIND_TASK_BY_PID(x) find_task_by_vpid(x)
+#else
+#define FIND_TASK_BY_PID(x) find_task_by_pid(x)
+#endif
+
+#ifndef DEVICE_NAME
+# define DEVICE_NAME "galcore"
+#endif
+
+#ifndef CLASS_NAME
+# define CLASS_NAME "graphics_class"
+#endif
+
+#define GetPageCount(size, offset) ((((size) + ((offset) & ~PAGE_MASK)) + PAGE_SIZE - 1) >> PAGE_SHIFT)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (3,7,0)
+#define gcdVM_FLAGS (VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP)
+#else
+#define gcdVM_FLAGS (VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED)
+#endif
+
+/* Protection bit when mapping memroy to user sapce */
+#define gcmkPAGED_MEMROY_PROT(x) pgprot_writecombine(x)
+
+#if gcdNONPAGED_MEMORY_BUFFERABLE
+#define gcmkIOREMAP ioremap_wc
+#define gcmkNONPAGED_MEMROY_PROT(x) pgprot_writecombine(x)
+#elif !gcdNONPAGED_MEMORY_CACHEABLE
+#define gcmkIOREMAP ioremap_nocache
+#define gcmkNONPAGED_MEMROY_PROT(x) pgprot_noncached(x)
+#endif
+
+#define gcdSUPPRESS_OOM_MESSAGE 1
+
+#if gcdSUPPRESS_OOM_MESSAGE
+#define gcdNOWARN __GFP_NOWARN
+#else
+#define gcdNOWARN 0
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (4, 1, 0)
+#ifdef gcdIRQ_SHARED
+# define gcdIRQF_FLAG (IRQF_SHARED)
+# else
+# define gcdIRQF_FLAG (0)
+# endif
+#else
+#ifdef gcdIRQ_SHARED
+# define gcdIRQF_FLAG (IRQF_DISABLED | IRQF_SHARED)
+# else
+# define gcdIRQF_FLAG (IRQF_DISABLED)
+# endif
+#endif
+
+/******************************************************************************\
+********************************** Structures **********************************
+\******************************************************************************/
+typedef struct _gcsIOMMU * gckIOMMU;
+
+typedef struct _gcsUSER_MAPPING * gcsUSER_MAPPING_PTR;
+typedef struct _gcsUSER_MAPPING
+{
+ /* Pointer to next mapping structure. */
+ gcsUSER_MAPPING_PTR next;
+
+ /* Physical address of this mapping. */
+ gctUINT32 physical;
+
+ /* Logical address of this mapping. */
+ gctPOINTER logical;
+
+ /* Number of bytes of this mapping. */
+ gctSIZE_T bytes;
+
+ /* Starting address of this mapping. */
+ gctINT8_PTR start;
+
+ /* Ending address of this mapping. */
+ gctINT8_PTR end;
+}
+gcsUSER_MAPPING;
+
+typedef struct _gcsINTEGER_DB * gcsINTEGER_DB_PTR;
+typedef struct _gcsINTEGER_DB
+{
+ struct idr idr;
+ spinlock_t lock;
+ gctINT curr;
+}
+gcsINTEGER_DB;
+
+struct _gckOS
+{
+ /* Object. */
+ gcsOBJECT object;
+
+ /* Pointer to device */
+ gckGALDEVICE device;
+
+ /* Memory management */
+ struct mutex mdlMutex;
+ struct list_head mdlHead;
+
+ /* Kernel process ID. */
+ gctUINT32 kernelProcessID;
+
+ /* Signal management. */
+
+ /* Lock. */
+ struct mutex signalMutex;
+
+ /* signal id database. */
+ gcsINTEGER_DB signalDB;
+
+ gcsUSER_MAPPING_PTR userMap;
+
+ /* workqueue for os timer. */
+ struct workqueue_struct * workqueue;
+
+ /* Allocate extra page to avoid cache overflow */
+ struct page* paddingPage;
+
+ /* Detect unfreed allocation. */
+ atomic_t allocateCount;
+
+ struct list_head allocatorList;
+
+ gcsDEBUGFS_DIR allocatorDebugfsDir;
+
+ gctBOOL allocatorLimitMarker;
+
+ /* Lock for register access check. */
+ spinlock_t registerAccessLock;
+
+ /* External power states. */
+ gctBOOL powerStates[gcdMAX_GPU_COUNT];
+
+ /* External clock states. */
+ gctBOOL clockStates[gcdMAX_GPU_COUNT];
+
+ /* IOMMU. */
+ gckIOMMU iommu;
+};
+
+typedef struct _gcsSIGNAL * gcsSIGNAL_PTR;
+typedef struct _gcsSIGNAL
+{
+ /* Kernel sync primitive. */
+ volatile unsigned int done;
+ spinlock_t lock;
+
+ wait_queue_head_t wait;
+
+ /* Manual reset flag. */
+ gctBOOL manualReset;
+
+ /* The reference counter. */
+ atomic_t ref;
+
+ /* The owner of the signal. */
+ gctHANDLE process;
+
+ /* ID. */
+ gctUINT32 id;
+
+#if gcdANDROID_NATIVE_FENCE_SYNC
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
+ /* Parent timeline. */
+ struct sync_timeline * timeline;
+# else
+ struct fence *fence;
+# endif
+#endif
+}
+gcsSIGNAL;
+
+typedef struct _gcsOSTIMER * gcsOSTIMER_PTR;
+typedef struct _gcsOSTIMER
+{
+ struct delayed_work work;
+ gctTIMERFUNCTION function;
+ gctPOINTER data;
+} gcsOSTIMER;
+
+gceSTATUS
+gckOS_ImportAllocators(
+ gckOS Os
+ );
+
+gceSTATUS
+gckOS_FreeAllocators(
+ gckOS Os
+ );
+
+/* Reserved memory. */
+gceSTATUS
+gckOS_RequestReservedMemory(
+ gckOS Os,
+ unsigned long Start,
+ unsigned long Size,
+ const char * Name,
+ gctBOOL Requested,
+ void ** MemoryHandle
+ );
+
+void
+gckOS_ReleaseReservedMemory(
+ gckOS Os,
+ void * MemoryHandle
+ );
+
+gceSTATUS
+_ConvertLogical2Physical(
+ IN gckOS Os,
+ IN gctPOINTER Logical,
+ IN gctUINT32 ProcessID,
+ IN PLINUX_MDL Mdl,
+ OUT gctPHYS_ADDR_T * Physical
+ );
+
+gctBOOL
+_QuerySignal(
+ IN gckOS Os,
+ IN gctSIGNAL Signal
+ );
+
+static inline gctINT
+_GetProcessID(
+ void
+ )
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ return task_tgid_vnr(current);
+#else
+ return current->tgid;
+#endif
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+static inline int
+is_vmalloc_addr(
+ void *Addr
+ )
+{
+ unsigned long addr = (unsigned long)Addr;
+
+ return addr >= VMALLOC_START && addr < VMALLOC_END;
+}
+#endif
+
+#ifdef CONFIG_IOMMU_SUPPORT
+void
+gckIOMMU_Destory(
+ IN gckOS Os,
+ IN gckIOMMU Iommu
+ );
+
+gceSTATUS
+gckIOMMU_Construct(
+ IN gckOS Os,
+ OUT gckIOMMU * Iommu
+ );
+
+gceSTATUS
+gckIOMMU_Map(
+ IN gckIOMMU Iommu,
+ IN gctUINT32 DomainAddress,
+ IN gctUINT32 Physical,
+ IN gctUINT32 Bytes
+ );
+
+gceSTATUS
+gckIOMMU_Unmap(
+ IN gckIOMMU Iommu,
+ IN gctUINT32 DomainAddress,
+ IN gctUINT32 Bytes
+ );
+#endif
+
+#endif /* __gc_hal_kernel_linux_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_math.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_math.c
new file mode 100644
index 000000000000..f373f47a41e0
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_math.c
@@ -0,0 +1,66 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+
+gctINT
+gckMATH_ModuloInt(
+ IN gctINT X,
+ IN gctINT Y
+ )
+{
+ if(Y ==0) {return 0;}
+ else {return X % Y;}
+}
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_mutex.h b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_mutex.h
new file mode 100644
index 000000000000..d2c94e2254ad
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_mutex.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef _gc_hal_kernel_mutex_h_
+#define _gc_hal_kernel_mutex_h_
+
+#include "gc_hal.h"
+#include <linux/mutex.h>
+
+/* Create a new mutex. */
+#define gckOS_CreateMutex(Os, Mutex) \
+({ \
+ gceSTATUS _status; \
+ gcmkHEADER_ARG("Os=0x%X", Os); \
+ \
+ /* Validate the arguments. */ \
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); \
+ gcmkVERIFY_ARGUMENT(Mutex != gcvNULL); \
+ \
+ /* Allocate the mutex structure. */ \
+ _status = gckOS_Allocate(Os, gcmSIZEOF(struct mutex), Mutex); \
+ \
+ if (gcmIS_SUCCESS(_status)) \
+ { \
+ /* Initialize the mutex. */ \
+ mutex_init(*(struct mutex **)Mutex); \
+ } \
+ \
+ /* Return status. */ \
+ gcmkFOOTER_ARG("*Mutex=0x%X", *(struct mutex **)Mutex); \
+ _status; \
+})
+
+#endif
+
+
+
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c
new file mode 100644
index 000000000000..88cf582bffe6
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c
@@ -0,0 +1,7838 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/mman.h>
+#include <asm/atomic.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/irqflags.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
+#include <linux/math64.h>
+#endif
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+#include <linux/anon_inodes.h>
+#endif
+
+#if gcdANDROID_NATIVE_FENCE_SYNC
+# include <linux/file.h>
+# include "gc_hal_kernel_sync.h"
+#endif
+
+#if defined(CONFIG_DMA_SHARED_BUFFER)
+#include <linux/dma-buf.h>
+#endif
+
+#if defined(CONFIG_ARM) && LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)
+#include <dma.h>
+#endif
+
+#define _GC_OBJ_ZONE gcvZONE_OS
+
+#include "gc_hal_kernel_allocator.h"
+
+#define gcmkBUG_ON(x) \
+ do { \
+ if (unlikely(!!(x))) \
+ { \
+ gcmkPRINT("[galcore]: BUG ON @ %s(%d)", __func__, __LINE__); \
+ dump_stack(); \
+ } \
+ } while (0)
+
+/******************************************************************************\
+******************************* Private Functions ******************************
+\******************************************************************************/
+static gctINT
+_GetThreadID(
+ void
+ )
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ return task_pid_vnr(current);
+#else
+ return current->pid;
+#endif
+}
+
+/* Must hold Mdl->mpasMutex before call this function. */
+static inline PLINUX_MDL_MAP
+_CreateMdlMap(
+ IN PLINUX_MDL Mdl,
+ IN gctINT ProcessID
+ )
+{
+ PLINUX_MDL_MAP mdlMap;
+
+ gcmkHEADER_ARG("Mdl=0x%X ProcessID=%d", Mdl, ProcessID);
+
+ mdlMap = (PLINUX_MDL_MAP)kmalloc(sizeof(struct _LINUX_MDL_MAP), GFP_KERNEL | gcdNOWARN);
+
+ if (mdlMap == gcvNULL)
+ {
+ gcmkFOOTER_NO();
+ return gcvNULL;
+ }
+
+ mdlMap->pid = ProcessID;
+ mdlMap->vmaAddr = gcvNULL;
+ mdlMap->count = 0;
+
+ list_add(&mdlMap->link, &Mdl->mapsHead);
+
+ gcmkFOOTER_ARG("0x%X", mdlMap);
+ return mdlMap;
+}
+
+/* Must hold Mdl->mpasMutex before call this function. */
+static inline gceSTATUS
+_DestroyMdlMap(
+ IN PLINUX_MDL Mdl,
+ IN PLINUX_MDL_MAP MdlMap
+ )
+{
+ gcmkHEADER_ARG("Mdl=0x%X MdlMap=0x%X", Mdl, MdlMap);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_ARGUMENT(MdlMap != gcvNULL);
+
+ list_del(&MdlMap->link);
+ kfree(MdlMap);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/* Must hold Mdl->mpasMutex before call this function. */
+extern PLINUX_MDL_MAP
+FindMdlMap(
+ IN PLINUX_MDL Mdl,
+ IN gctINT ProcessID
+ )
+{
+ PLINUX_MDL_MAP mdlMap;
+
+ gcmkHEADER_ARG("Mdl=0x%X ProcessID=%d", Mdl, ProcessID);
+
+ if (Mdl == gcvNULL)
+ {
+ gcmkFOOTER_NO();
+ return gcvNULL;
+ }
+
+ list_for_each_entry(mdlMap, &Mdl->mapsHead, link)
+ {
+ if (mdlMap->pid == ProcessID)
+ {
+ gcmkFOOTER_ARG("0x%X", mdlMap);
+ return mdlMap;
+ }
+ }
+
+ gcmkFOOTER_NO();
+ return gcvNULL;
+}
+
+
+static PLINUX_MDL
+_CreateMdl(
+ IN gckOS Os
+ )
+{
+ PLINUX_MDL mdl;
+
+ gcmkHEADER();
+
+ mdl = (PLINUX_MDL)kzalloc(sizeof(struct _LINUX_MDL), GFP_KERNEL | gcdNOWARN);
+
+ if (mdl)
+ {
+ mdl->os = Os;
+ atomic_set(&mdl->refs, 1);
+ mutex_init(&mdl->mapsMutex);
+ INIT_LIST_HEAD(&mdl->mapsHead);
+ }
+
+ gcmkFOOTER_ARG("0x%X", mdl);
+ return mdl;
+}
+
+static gceSTATUS
+_DestroyMdl(
+ IN PLINUX_MDL Mdl
+ )
+{
+ gcmkHEADER_ARG("Mdl=0x%X", Mdl);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_ARGUMENT(Mdl != gcvNULL);
+
+ if (atomic_dec_and_test(&Mdl->refs))
+ {
+ gckOS os = Mdl->os;
+ gckALLOCATOR allocator = Mdl->allocator;
+ PLINUX_MDL_MAP mdlMap, next;
+
+ /* Valid private means alloc/attach successfully */
+ if (Mdl->priv)
+ {
+ if (Mdl->addr)
+ {
+ allocator->ops->UnmapKernel(allocator, Mdl, Mdl->addr);
+ }
+ allocator->ops->Free(allocator, Mdl);
+ }
+
+ mutex_lock(&Mdl->mapsMutex);
+ list_for_each_entry_safe(mdlMap, next, &Mdl->mapsHead, link)
+ {
+ gcmkVERIFY_OK(_DestroyMdlMap(Mdl, mdlMap));
+ }
+ mutex_unlock(&Mdl->mapsMutex);
+
+ if (Mdl->link.next)
+ {
+ /* Remove the node from global list.. */
+ mutex_lock(&os->mdlMutex);
+ list_del(&Mdl->link);
+ mutex_unlock(&os->mdlMutex);
+ }
+
+ kfree(Mdl);
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+** Integer Id Management.
+*/
+gceSTATUS
+_AllocateIntegerId(
+ IN gcsINTEGER_DB_PTR Database,
+ IN gctPOINTER KernelPointer,
+ OUT gctUINT32 *Id
+ )
+{
+ int result;
+ gctINT next;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
+ idr_preload(GFP_KERNEL | gcdNOWARN);
+
+ spin_lock(&Database->lock);
+
+ next = (Database->curr + 1 <= 0) ? 1 : Database->curr + 1;
+
+ result = idr_alloc(&Database->idr, KernelPointer, next, 0, GFP_ATOMIC);
+
+ /* ID allocated should not be 0. */
+ gcmkASSERT(result != 0);
+
+ if (result > 0)
+ {
+ Database->curr = *Id = result;
+ }
+
+ spin_unlock(&Database->lock);
+
+ idr_preload_end();
+
+ if (result < 0)
+ {
+ return gcvSTATUS_OUT_OF_RESOURCES;
+ }
+#else
+again:
+ if (idr_pre_get(&Database->idr, GFP_KERNEL | gcdNOWARN) == 0)
+ {
+ return gcvSTATUS_OUT_OF_MEMORY;
+ }
+
+ spin_lock(&Database->lock);
+
+ next = (Database->curr + 1 <= 0) ? 1 : Database->curr + 1;
+
+ /* Try to get a id greater than 0. */
+ result = idr_get_new_above(&Database->idr, KernelPointer, next, Id);
+
+ if (!result)
+ {
+ Database->curr = *Id;
+ }
+
+ spin_unlock(&Database->lock);
+
+ if (result == -EAGAIN)
+ {
+ goto again;
+ }
+
+ if (result != 0)
+ {
+ return gcvSTATUS_OUT_OF_RESOURCES;
+ }
+#endif
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+_QueryIntegerId(
+ IN gcsINTEGER_DB_PTR Database,
+ IN gctUINT32 Id,
+ OUT gctPOINTER * KernelPointer
+ )
+{
+ gctPOINTER pointer;
+
+ spin_lock(&Database->lock);
+
+ pointer = idr_find(&Database->idr, Id);
+
+ spin_unlock(&Database->lock);
+
+ if (pointer)
+ {
+ *KernelPointer = pointer;
+ return gcvSTATUS_OK;
+ }
+ else
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_ERROR, gcvZONE_OS,
+ "%s(%d) Id = %d is not found",
+ __FUNCTION__, __LINE__, Id);
+
+ return gcvSTATUS_NOT_FOUND;
+ }
+}
+
+gceSTATUS
+_DestroyIntegerId(
+ IN gcsINTEGER_DB_PTR Database,
+ IN gctUINT32 Id
+ )
+{
+ spin_lock(&Database->lock);
+
+ idr_remove(&Database->idr, Id);
+
+ spin_unlock(&Database->lock);
+
+ return gcvSTATUS_OK;
+}
+
+static inline gceSTATUS
+_QueryProcessPageTable(
+ IN gctPOINTER Logical,
+ OUT gctPHYS_ADDR_T * Address
+ )
+{
+ unsigned long logical = (unsigned long)Logical;
+ unsigned long offset = logical & ~PAGE_MASK;
+
+ if (is_vmalloc_addr(Logical))
+ {
+ /* vmalloc area. */
+ *Address = page_to_phys(vmalloc_to_page(Logical)) | offset;
+ return gcvSTATUS_OK;
+ }
+ else if (virt_addr_valid(logical))
+ {
+ /* Kernel logical address. */
+ *Address = virt_to_phys(Logical);
+ return gcvSTATUS_OK;
+ }
+ else
+ {
+ /* Try user VM area. */
+ struct vm_area_struct *vma;
+ spinlock_t *ptl;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ if (!current->mm)
+ return gcvSTATUS_NOT_FOUND;
+
+ down_read(&current->mm->mmap_sem);
+ vma = find_vma(current->mm, logical);
+ up_read(&current->mm->mmap_sem);
+
+ /* To check if mapped to user. */
+ if (!vma)
+ return gcvSTATUS_NOT_FOUND;
+
+ pgd = pgd_offset(current->mm, logical);
+ if (pgd_none(*pgd) || pgd_bad(*pgd))
+ return gcvSTATUS_NOT_FOUND;
+
+ pud = pud_offset(pgd, logical);
+ if (pud_none(*pud) || pud_bad(*pud))
+ return gcvSTATUS_NOT_FOUND;
+
+ pmd = pmd_offset(pud, logical);
+ if (pmd_none(*pmd) || pmd_bad(*pmd))
+ return gcvSTATUS_NOT_FOUND;
+
+ pte = pte_offset_map_lock(current->mm, pmd, logical, &ptl);
+ if (!pte)
+ {
+ spin_unlock(ptl);
+ return gcvSTATUS_NOT_FOUND;
+ }
+
+ if (!pte_present(*pte))
+ {
+ pte_unmap_unlock(pte, ptl);
+ return gcvSTATUS_NOT_FOUND;
+ }
+
+ *Address = (pte_pfn(*pte) << PAGE_SHIFT) | offset;
+ pte_unmap_unlock(pte, ptl);
+
+ return gcvSTATUS_OK;
+ }
+}
+
+#if !gcdCACHE_FUNCTION_UNIMPLEMENTED && defined(CONFIG_OUTER_CACHE)
+static inline gceSTATUS
+outer_func(
+ gceCACHEOPERATION Type,
+ unsigned long Start,
+ unsigned long End
+ )
+{
+ switch (Type)
+ {
+ case gcvCACHE_CLEAN:
+ outer_clean_range(Start, End);
+ break;
+ case gcvCACHE_INVALIDATE:
+ outer_inv_range(Start, End);
+ break;
+ case gcvCACHE_FLUSH:
+ outer_flush_range(Start, End);
+ break;
+ default:
+ return gcvSTATUS_INVALID_ARGUMENT;
+ break;
+ }
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+** _HandleOuterCache
+**
+** Handle the outer cache for the specified addresses.
+**
+** ARGUMENTS:
+**
+** gckOS Os
+** Pointer to gckOS object.
+**
+** gctPOINTER Physical
+** Physical address to flush.
+**
+** gctPOINTER Logical
+** Logical address to flush.
+**
+** gctSIZE_T Bytes
+** Size of the address range in bytes to flush.
+**
+** gceOUTERCACHE_OPERATION Type
+** Operation need to be execute.
+*/
+gceSTATUS
+_HandleOuterCache(
+ IN gckOS Os,
+ IN gctUINT32 Physical,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes,
+ IN gceCACHEOPERATION Type
+ )
+{
+ gceSTATUS status;
+ gctPHYS_ADDR_T paddr;
+ gctPOINTER vaddr;
+ gctUINT32 offset, bytes, left;
+
+ gcmkHEADER_ARG("Os=0x%X Logical=0x%X Bytes=%lu",
+ Os, Logical, Bytes);
+
+ if (Physical != gcvINVALID_ADDRESS)
+ {
+ /* Non paged memory or gcvPOOL_USER surface */
+ paddr = (unsigned long) Physical;
+ gcmkONERROR(outer_func(Type, paddr, paddr + Bytes));
+ }
+ else
+ {
+ /* Non contiguous virtual memory */
+ vaddr = Logical;
+ left = Bytes;
+
+ while (left)
+ {
+ /* Handle (part of) current page. */
+ offset = (gctUINTPTR_T)vaddr & ~PAGE_MASK;
+
+ bytes = gcmMIN(left, PAGE_SIZE - offset);
+
+ gcmkONERROR(_QueryProcessPageTable(vaddr, &paddr));
+ gcmkONERROR(outer_func(Type, paddr, paddr + bytes));
+
+ vaddr = (gctUINT8_PTR)vaddr + bytes;
+ left -= bytes;
+ }
+ }
+
+ mb();
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+#endif
+
+
+static gceSTATUS
+_ShrinkMemory(
+ IN gckOS Os
+ )
+{
+ gcsPLATFORM * platform;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ gcmkHEADER_ARG("Os=0x%X", Os);
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+
+ platform = Os->device->platform;
+
+ if (platform && platform->ops->shrinkMemory)
+ {
+ status = platform->ops->shrinkMemory(platform);
+ }
+ else
+ {
+ gcmkFOOTER_NO();
+ return gcvSTATUS_NOT_SUPPORTED;
+ }
+
+ gcmkFOOTER_NO();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_Construct
+**
+** Construct a new gckOS object.
+**
+** INPUT:
+**
+** gctPOINTER Context
+** Pointer to the gckGALDEVICE class.
+**
+** OUTPUT:
+**
+** gckOS * Os
+** Pointer to a variable that will hold the pointer to the gckOS object.
+*/
+gceSTATUS
+gckOS_Construct(
+ IN gctPOINTER Context,
+ OUT gckOS * Os
+ )
+{
+ gckOS os;
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Context=0x%X", Context);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_ARGUMENT(Os != gcvNULL);
+
+ /* Allocate the gckOS object. */
+ os = (gckOS) kmalloc(gcmSIZEOF(struct _gckOS), GFP_KERNEL | gcdNOWARN);
+
+ if (os == gcvNULL)
+ {
+ /* Out of memory. */
+ gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY);
+ return gcvSTATUS_OUT_OF_MEMORY;
+ }
+
+ /* Zero the memory. */
+ gckOS_ZeroMemory(os, gcmSIZEOF(struct _gckOS));
+
+ /* Initialize the gckOS object. */
+ os->object.type = gcvOBJ_OS;
+
+ /* Set device device. */
+ os->device = Context;
+
+ /* Set allocateCount to 0, gckOS_Allocate has not been used yet. */
+ atomic_set(&os->allocateCount, 0);
+
+ /* Initialize the memory lock. */
+ mutex_init(&os->mdlMutex);
+
+ INIT_LIST_HEAD(&os->mdlHead);
+
+ /* Get the kernel process ID. */
+ os->kernelProcessID = _GetProcessID();
+
+ /*
+ * Initialize the signal manager.
+ */
+
+ /* Initialize mutex. */
+ mutex_init(&os->signalMutex);
+
+ /* Initialize signal id database lock. */
+ spin_lock_init(&os->signalDB.lock);
+
+ /* Initialize signal id database. */
+ idr_init(&os->signalDB.idr);
+
+ /* Create a workqueue for os timer. */
+ os->workqueue = create_singlethread_workqueue("galcore workqueue");
+
+ if (os->workqueue == gcvNULL)
+ {
+ /* Out of memory. */
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ os->paddingPage = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | gcdNOWARN);
+ if (os->paddingPage == gcvNULL)
+ {
+ /* Out of memory. */
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+ else
+ {
+ SetPageReserved(os->paddingPage);
+ }
+
+ spin_lock_init(&os->registerAccessLock);
+
+ gckOS_ImportAllocators(os);
+
+#ifdef CONFIG_IOMMU_SUPPORT
+ if (((gckGALDEVICE)(os->device))->args.mmu == gcvFALSE)
+ {
+ /* Only use IOMMU when internal MMU is not enabled. */
+ status = gckIOMMU_Construct(os, &os->iommu);
+
+ if (gcmIS_ERROR(status))
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): Fail to setup IOMMU",
+ __FUNCTION__, __LINE__
+ );
+ }
+ }
+#endif
+
+ /* Return pointer to the gckOS object. */
+ *Os = os;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Os=0x%X", *Os);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (os->workqueue != gcvNULL)
+ {
+ destroy_workqueue(os->workqueue);
+ }
+
+ kfree(os);
+
+ /* Return the error. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_Destroy
+**
+** Destroy an gckOS object.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object that needs to be destroyed.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_Destroy(
+ IN gckOS Os
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X", Os);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+
+ if (Os->paddingPage != gcvNULL)
+ {
+ ClearPageReserved(Os->paddingPage);
+ __free_page(Os->paddingPage);
+ Os->paddingPage = gcvNULL;
+ }
+
+ /*
+ * Destroy the signal manager.
+ */
+
+ /* Wait for all works done. */
+ flush_workqueue(Os->workqueue);
+
+ /* Destory work queue. */
+ destroy_workqueue(Os->workqueue);
+
+ gckOS_FreeAllocators(Os);
+
+#ifdef CONFIG_IOMMU_SUPPORT
+ if (Os->iommu)
+ {
+ gckIOMMU_Destory(Os, Os->iommu);
+ }
+#endif
+
+ /* Flush the debug cache. */
+ gcmkDEBUGFLUSH(~0U);
+
+ /* Mark the gckOS object as unknown. */
+ Os->object.type = gcvOBJ_UNKNOWN;
+
+
+ /* Free the gckOS object. */
+ kfree(Os);
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_CreateKernelVirtualMapping(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Logical,
+ OUT gctSIZE_T * PageCount
+ )
+{
+ gceSTATUS status;
+ PLINUX_MDL mdl = (PLINUX_MDL)Physical;
+ gckALLOCATOR allocator = mdl->allocator;
+
+ gcmkHEADER();
+
+ *PageCount = mdl->numPages;
+
+ gcmkONERROR(allocator->ops->MapKernel(allocator, mdl, Logical));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckOS_DestroyKernelVirtualMapping(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical
+ )
+{
+ PLINUX_MDL mdl = (PLINUX_MDL)Physical;
+ gckALLOCATOR allocator = mdl->allocator;
+
+ gcmkHEADER();
+
+ allocator->ops->UnmapKernel(allocator, mdl, Logical);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_CreateUserVirtualMapping(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Logical,
+ OUT gctSIZE_T * PageCount
+ )
+{
+ return gckOS_LockPages(Os, Physical, Bytes, gcvFALSE, Logical, PageCount);
+}
+
+gceSTATUS
+gckOS_DestroyUserVirtualMapping(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical
+ )
+{
+ return gckOS_UnlockPages(Os, Physical, Bytes, Logical);
+}
+
+/*******************************************************************************
+**
+** gckOS_Allocate
+**
+** Allocate memory.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctSIZE_T Bytes
+** Number of bytes to allocate.
+**
+** OUTPUT:
+**
+** gctPOINTER * Memory
+** Pointer to a variable that will hold the allocated memory location.
+*/
+gceSTATUS
+gckOS_Allocate(
+ IN gckOS Os,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Memory
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Os=0x%X Bytes=%lu", Os, Bytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
+
+ gcmkONERROR(gckOS_AllocateMemory(Os, Bytes, Memory));
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Memory=0x%X", *Memory);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_Free
+**
+** Free allocated memory.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPOINTER Memory
+** Pointer to memory allocation to free.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_Free(
+ IN gckOS Os,
+ IN gctPOINTER Memory
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Os=0x%X Memory=0x%X", Os, Memory);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
+
+ gcmkONERROR(gckOS_FreeMemory(Os, Memory));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_AllocateMemory
+**
+** Allocate memory wrapper.
+**
+** INPUT:
+**
+** gctSIZE_T Bytes
+** Number of bytes to allocate.
+**
+** OUTPUT:
+**
+** gctPOINTER * Memory
+** Pointer to a variable that will hold the allocated memory location.
+*/
+gceSTATUS
+gckOS_AllocateMemory(
+ IN gckOS Os,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Memory
+ )
+{
+ gctPOINTER memory;
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Os=0x%X Bytes=%lu", Os, Bytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
+
+ if (Bytes > PAGE_SIZE)
+ {
+ memory = (gctPOINTER) vmalloc(Bytes);
+ }
+ else
+ {
+ memory = (gctPOINTER) kmalloc(Bytes, GFP_KERNEL | gcdNOWARN);
+ }
+
+ if (memory == gcvNULL)
+ {
+ /* Out of memory. */
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ /* Increase count. */
+ atomic_inc(&Os->allocateCount);
+
+ /* Return pointer to the memory allocation. */
+ *Memory = memory;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Memory=0x%X", *Memory);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_FreeMemory
+**
+** Free allocated memory wrapper.
+**
+** INPUT:
+**
+** gctPOINTER Memory
+** Pointer to memory allocation to free.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_FreeMemory(
+ IN gckOS Os,
+ IN gctPOINTER Memory
+ )
+{
+ gcmkHEADER_ARG("Memory=0x%X", Memory);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
+
+ /* Free the memory from the OS pool. */
+ if (is_vmalloc_addr(Memory))
+ {
+ vfree(Memory);
+ }
+ else
+ {
+ kfree(Memory);
+ }
+
+ /* Decrease count. */
+ atomic_dec(&Os->allocateCount);
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_MapMemory
+**
+** Map physical memory into the current process.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPHYS_ADDR Physical
+** Start of physical address memory.
+**
+** gctSIZE_T Bytes
+** Number of bytes to map.
+**
+** OUTPUT:
+**
+** gctPOINTER * Memory
+** Pointer to a variable that will hold the logical address of the
+** mapped memory.
+*/
+gceSTATUS
+gckOS_MapMemory(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Logical
+ )
+{
+ gceSTATUS status;
+ PLINUX_MDL_MAP mdlMap;
+ PLINUX_MDL mdl = (PLINUX_MDL) Physical;
+ gckALLOCATOR allocator;
+ gctINT pid = _GetProcessID();
+
+ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Bytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Physical != 0);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+ mutex_lock(&mdl->mapsMutex);
+
+ mdlMap = FindMdlMap(mdl, pid);
+
+ if (mdlMap == gcvNULL)
+ {
+ mdlMap = _CreateMdlMap(mdl, pid);
+
+ if (mdlMap == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+ }
+
+ if (mdlMap->vmaAddr == gcvNULL)
+ {
+ allocator = mdl->allocator;
+
+ gcmkONERROR(
+ allocator->ops->MapUser(allocator,
+ mdl, gcvFALSE,
+ &mdlMap->vmaAddr));
+ }
+
+ mutex_unlock(&mdl->mapsMutex);
+
+ *Logical = mdlMap->vmaAddr;
+
+ gcmkFOOTER_ARG("*Logical=0x%X", *Logical);
+ return gcvSTATUS_OK;
+
+OnError:
+ mutex_unlock(&mdl->mapsMutex);
+
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_UnmapMemory
+**
+** Unmap physical memory out of the current process.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPHYS_ADDR Physical
+** Start of physical address memory.
+**
+** gctSIZE_T Bytes
+** Number of bytes to unmap.
+**
+** gctPOINTER Memory
+** Pointer to a previously mapped memory region.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_UnmapMemory(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu Logical=0x%X",
+ Os, Physical, Bytes, Logical);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Physical != 0);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+ gckOS_UnmapMemoryEx(Os, Physical, Bytes, Logical, _GetProcessID());
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+
+/*******************************************************************************
+**
+** gckOS_UnmapMemoryEx
+**
+** Unmap physical memory in the specified process.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPHYS_ADDR Physical
+** Start of physical address memory.
+**
+** gctSIZE_T Bytes
+** Number of bytes to unmap.
+**
+** gctPOINTER Memory
+** Pointer to a previously mapped memory region.
+**
+** gctUINT32 PID
+** Pid of the process that opened the device and mapped this memory.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_UnmapMemoryEx(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical,
+ IN gctUINT32 PID
+ )
+{
+ PLINUX_MDL_MAP mdlMap;
+ PLINUX_MDL mdl = (PLINUX_MDL)Physical;
+
+ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu Logical=0x%X PID=%d",
+ Os, Physical, Bytes, Logical, PID);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Physical != 0);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(PID != 0);
+
+ if (Logical)
+ {
+ gckALLOCATOR allocator = mdl->allocator;
+
+ mutex_lock(&mdl->mapsMutex);
+
+ mdlMap = FindMdlMap(mdl, PID);
+
+ if (mdlMap == gcvNULL || mdlMap->vmaAddr == gcvNULL)
+ {
+ mutex_unlock(&mdl->mapsMutex);
+
+ gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT);
+ return gcvSTATUS_INVALID_ARGUMENT;
+ }
+
+ BUG_ON(!allocator || !allocator->ops->UnmapUser);
+
+ allocator->ops->UnmapUser(allocator, mdl,
+ mdlMap->vmaAddr, mdl->numPages * PAGE_SIZE);
+
+ gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap));
+
+ mutex_unlock(&mdl->mapsMutex);
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_UnmapUserLogical
+**
+** Unmap user logical memory out of physical memory.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPHYS_ADDR Physical
+** Start of physical address memory.
+**
+** gctSIZE_T Bytes
+** Number of bytes to unmap.
+**
+** gctPOINTER Memory
+** Pointer to a previously mapped memory region.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_UnmapUserLogical(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu Logical=0x%X",
+ Os, Physical, Bytes, Logical);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Physical != 0);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+ gckOS_UnmapMemory(Os, Physical, Bytes, Logical);
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+}
+
+/*******************************************************************************
+**
+** gckOS_AllocateNonPagedMemory
+**
+** Allocate a number of pages from non-paged memory.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctBOOL InUserSpace
+** gcvTRUE if the pages need to be mapped into user space.
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that holds the number of bytes to allocate.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that hold the number of bytes allocated.
+**
+** gctPHYS_ADDR * Physical
+** Pointer to a variable that will hold the physical address of the
+** allocation.
+**
+** gctPOINTER * Logical
+** Pointer to a variable that will hold the logical address of the
+** allocation.
+*/
+gceSTATUS
+gckOS_AllocateNonPagedMemory(
+ IN gckOS Os,
+ IN gctBOOL InUserSpace,
+ IN OUT gctSIZE_T * Bytes,
+ OUT gctPHYS_ADDR * Physical,
+ OUT gctPOINTER * Logical
+ )
+{
+ gctSIZE_T bytes;
+ gctINT numPages;
+ PLINUX_MDL mdl = gcvNULL;
+ PLINUX_MDL_MAP mdlMap = gcvNULL;
+ gctPOINTER addr;
+ gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+ gckALLOCATOR allocator;
+ gctUINT32 flag = gcvALLOC_FLAG_CONTIGUOUS;
+
+ gcmkHEADER_ARG("Os=0x%X InUserSpace=%d *Bytes=%lu",
+ Os, InUserSpace, gcmOPT_VALUE(Bytes));
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Bytes != gcvNULL);
+ gcmkVERIFY_ARGUMENT(*Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+ /* Align number of bytes to page size. */
+ bytes = gcmALIGN(*Bytes, PAGE_SIZE);
+
+ /* Get total number of pages.. */
+ numPages = GetPageCount(bytes, 0);
+
+ /* Allocate mdl structure */
+ mdl = _CreateMdl(Os);
+ if (mdl == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ if (Os->allocatorLimitMarker)
+ {
+ flag |= gcvALLOC_FLAG_CMA_LIMIT;
+ }
+
+ /* Walk all allocators. */
+ list_for_each_entry(allocator, &Os->allocatorList, link)
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d) flag = %x allocator->capability = %x",
+ __FUNCTION__, __LINE__, flag, allocator->capability);
+
+#ifndef NO_DMA_COHERENT
+ /* Point to dma coherent allocator. */
+ if (strcmp(allocator->name, "dma"))
+ {
+ if (((flag & allocator->capability) != flag) ||
+ (numPages > 1))
+ {
+ continue;
+ }
+ }
+#else
+ if ((flag & allocator->capability) != flag)
+ {
+ continue;
+ }
+#endif
+ status = allocator->ops->Alloc(allocator, mdl, numPages, flag);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ mdl->allocator = allocator;
+ break;
+ }
+ }
+
+ /* Check status. */
+ gcmkONERROR(status);
+
+ mdl->numPages = numPages;
+
+ mdl->contiguous = gcvTRUE;
+
+ gcmkONERROR(allocator->ops->MapKernel(allocator, mdl, &addr));
+
+ /* Trigger a page fault. */
+ memset(addr, 0, numPages * PAGE_SIZE);
+
+ mdl->addr = addr;
+
+ if (InUserSpace)
+ {
+ mdlMap = _CreateMdlMap(mdl, _GetProcessID());
+
+ if (mdlMap == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ gcmkONERROR(allocator->ops->MapUser(allocator, mdl, gcvFALSE, &mdlMap->vmaAddr));
+
+ *Logical = mdlMap->vmaAddr;
+ }
+ else
+ {
+ *Logical = addr;
+ }
+
+ /*
+ * Add this to a global list.
+ * Will be used by get physical address
+ * and mapuser pointer functions.
+ */
+ mutex_lock(&Os->mdlMutex);
+ list_add_tail(&mdl->link, &Os->mdlHead);
+ mutex_unlock(&Os->mdlMutex);
+
+ /* Return allocated memory. */
+ *Bytes = bytes;
+ *Physical = (gctPHYS_ADDR) mdl;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Bytes=%lu *Physical=0x%X *Logical=0x%X",
+ *Bytes, *Physical, *Logical);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (mdl != gcvNULL)
+ {
+ /* Free LINUX_MDL. */
+ gcmkVERIFY_OK(_DestroyMdl(mdl));
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+
+/*******************************************************************************
+**
+** gckOS_FreeNonPagedMemory
+**
+** Free previously allocated and mapped pages from non-paged memory.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctSIZE_T Bytes
+** Number of bytes allocated.
+**
+** gctPHYS_ADDR Physical
+** Physical address of the allocated memory.
+**
+** gctPOINTER Logical
+** Logical address of the allocated memory.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS gckOS_FreeNonPagedMemory(
+ IN gckOS Os,
+ IN gctSIZE_T Bytes,
+ IN gctPHYS_ADDR Physical,
+ IN gctPOINTER Logical
+ )
+{
+ PLINUX_MDL mdl = (PLINUX_MDL)Physical;
+
+ gcmkHEADER_ARG("Os=0x%X Bytes=%lu Physical=0x%X Logical=0x%X",
+ Os, Bytes, Physical, Logical);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Physical != 0);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+ gcmkVERIFY_OK(_DestroyMdl(mdl));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+static inline gckALLOCATOR
+_FindAllocator(
+ gckOS Os,
+ gctUINT Flag
+ )
+{
+ gckALLOCATOR allocator;
+
+ list_for_each_entry(allocator, &Os->allocatorList, link)
+ {
+ if ((allocator->capability & Flag) == Flag)
+ {
+ return allocator;
+ }
+ }
+
+ return gcvNULL;
+}
+
+gceSTATUS
+gckOS_RequestReservedMemory(
+ gckOS Os,
+ unsigned long Start,
+ unsigned long Size,
+ const char * Name,
+ gctBOOL Requested,
+ void ** MemoryHandle
+ )
+{
+ PLINUX_MDL mdl = gcvNULL;
+ gceSTATUS status;
+ gckALLOCATOR allocator;
+ gcsATTACH_DESC desc;
+
+ gcmkHEADER_ARG("start=0x%lx size=0x%lx name=%s", Start, Size, Name);
+
+ /* Round up to page size. */
+ Size = (Size + ~PAGE_MASK) & PAGE_MASK;
+
+ mdl = _CreateMdl(Os);
+ if (!mdl)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ desc.reservedMem.start = Start;
+ desc.reservedMem.size = Size;
+ desc.reservedMem.name = Name;
+ desc.reservedMem.requested = Requested;
+
+ allocator = _FindAllocator(Os, gcvALLOC_FLAG_LINUX_RESERVED_MEM);
+ if (!allocator)
+ {
+ gcmkPRINT("reserved-mem allocator not integrated!");
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+ /* Call attach. */
+ gcmkONERROR(allocator->ops->Attach(allocator, &desc, mdl));
+
+ /* Assign alloator. */
+ mdl->allocator = allocator;
+ mdl->numPages = Size >> PAGE_SHIFT;
+ mdl->contiguous = gcvTRUE;
+ mdl->addr = gcvNULL;
+ mdl->dmaHandle = Start;
+ mdl->gid = 0;
+
+ /*
+ * Add this to a global list.
+ * Will be used by get physical address
+ * and mapuser pointer functions.
+ */
+ mutex_lock(&Os->mdlMutex);
+ list_add_tail(&mdl->link, &Os->mdlHead);
+ mutex_unlock(&Os->mdlMutex);
+
+ *MemoryHandle = (void *)mdl;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (mdl)
+ {
+ gcmkVERIFY_OK(_DestroyMdl(mdl));
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+void
+gckOS_ReleaseReservedMemory(
+ gckOS Os,
+ void * MemoryHandle
+ )
+{
+ gckALLOCATOR allocator;
+ PLINUX_MDL mdl = (PLINUX_MDL)MemoryHandle;
+
+ allocator = _FindAllocator(Os, gcvALLOC_FLAG_LINUX_RESERVED_MEM);
+
+ /* If no allocator, how comes the memory? */
+ BUG_ON(!allocator);
+
+ allocator->ops->Free(allocator, mdl);
+}
+
+/*******************************************************************************
+**
+** gckOS_ReadRegister
+**
+** Read data from a register.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctUINT32 Address
+** Address of register.
+**
+** OUTPUT:
+**
+** gctUINT32 * Data
+** Pointer to a variable that receives the data read from the register.
+*/
+gceSTATUS
+gckOS_ReadRegister(
+ IN gckOS Os,
+ IN gctUINT32 Address,
+ OUT gctUINT32 * Data
+ )
+{
+ return gckOS_ReadRegisterEx(Os, gcvCORE_MAJOR, Address, Data);
+}
+
+gceSTATUS
+gckOS_ReadRegisterEx(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctUINT32 Address,
+ OUT gctUINT32 * Data
+ )
+{
+ if (in_irq())
+ {
+ spin_lock(&Os->registerAccessLock);
+
+ if (unlikely(Os->clockStates[Core] == gcvFALSE))
+ {
+ spin_unlock(&Os->registerAccessLock);
+
+ /*
+ * Read register when power off:
+ * 1. In shared IRQ, read register may be called and that's not our irq.
+ */
+ return gcvSTATUS_GENERIC_IO;
+ }
+
+ *Data = readl((gctUINT8 *)Os->device->registerBases[Core] + Address);
+ spin_unlock(&Os->registerAccessLock);
+ }
+ else
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&Os->registerAccessLock, flags);
+
+ if (unlikely(Os->clockStates[Core] == gcvFALSE))
+ {
+ spin_unlock_irqrestore(&Os->registerAccessLock, flags);
+
+ /*
+ * Read register when power off:
+ * 2. In non-irq context, register access should not be called,
+ * otherwise it's driver bug.
+ */
+ printk(KERN_ERR "[galcore]: %s(%d) GPU[%d] external clock off",
+ __func__, __LINE__, Core);
+ gcmkBUG_ON(1);
+ return gcvSTATUS_GENERIC_IO;
+ }
+
+ *Data = readl((gctUINT8 *)Os->device->registerBases[Core] + Address);
+ spin_unlock_irqrestore(&Os->registerAccessLock, flags);
+
+#if gcdDUMP_AHB_ACCESS
+ /* Dangerous to print in interrupt context, skip. */
+ gcmkPRINT("@[RD %d] %08x %08x", Core, Address, *Data);
+#endif
+ }
+
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_WriteRegister
+**
+** Write data to a register.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctUINT32 Address
+** Address of register.
+**
+** gctUINT32 Data
+** Data for register.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_WriteRegister(
+ IN gckOS Os,
+ IN gctUINT32 Address,
+ IN gctUINT32 Data
+ )
+{
+ return gckOS_WriteRegisterEx(Os, gcvCORE_MAJOR, Address, Data);
+}
+
+gceSTATUS
+gckOS_WriteRegisterEx(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctUINT32 Address,
+ IN gctUINT32 Data
+ )
+{
+ if (in_irq())
+ {
+ spin_lock(&Os->registerAccessLock);
+
+ if (unlikely(Os->clockStates[Core] == gcvFALSE))
+ {
+ spin_unlock(&Os->registerAccessLock);
+
+ printk(KERN_ERR "[galcore]: %s(%d) GPU[%d] external clock off",
+ __func__, __LINE__, Core);
+
+ /* Driver bug: register write when clock off. */
+ gcmkBUG_ON(1);
+ return gcvSTATUS_GENERIC_IO;
+ }
+
+ writel(Data, (gctUINT8 *)Os->device->registerBases[Core] + Address);
+ spin_unlock(&Os->registerAccessLock);
+ }
+ else
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&Os->registerAccessLock, flags);
+
+ if (unlikely(Os->clockStates[Core] == gcvFALSE))
+ {
+ spin_unlock_irqrestore(&Os->registerAccessLock, flags);
+
+ printk(KERN_ERR "[galcore]: %s(%d) GPU[%d] external clock off",
+ __func__, __LINE__, Core);
+
+ /* Driver bug: register write when clock off. */
+ gcmkBUG_ON(1);
+ return gcvSTATUS_GENERIC_IO;
+ }
+
+ writel(Data, (gctUINT8 *)Os->device->registerBases[Core] + Address);
+ spin_unlock_irqrestore(&Os->registerAccessLock, flags);
+
+#if gcdDUMP_AHB_ACCESS
+ /* Dangerous to print in interrupt context, skip. */
+ gcmkPRINT("@[WR %d] %08x %08x", Core, Address, Data);
+#endif
+ }
+
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_GetPageSize
+**
+** Get the system's page size.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** OUTPUT:
+**
+** gctSIZE_T * PageSize
+** Pointer to a variable that will receive the system's page size.
+*/
+gceSTATUS gckOS_GetPageSize(
+ IN gckOS Os,
+ OUT gctSIZE_T * PageSize
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X", Os);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(PageSize != gcvNULL);
+
+ /* Return the page size. */
+ *PageSize = (gctSIZE_T) PAGE_SIZE;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*PageSize=%d", *PageSize);
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_GetPhysicalAddressProcess
+**
+** Get the physical system address of a corresponding virtual address for a
+** given process.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to gckOS object.
+**
+** gctPOINTER Logical
+** Logical address.
+**
+** gctUINT32 ProcessID
+** Process ID.
+**
+** OUTPUT:
+**
+** gctUINT32 * Address
+** Poinetr to a variable that receives the 32-bit physical adress.
+*/
+static gceSTATUS
+_GetPhysicalAddressProcess(
+ IN gckOS Os,
+ IN gctPOINTER Logical,
+ IN gctUINT32 ProcessID,
+ OUT gctPHYS_ADDR_T * Address
+ )
+{
+ PLINUX_MDL mdl;
+ gceSTATUS status = gcvSTATUS_INVALID_ADDRESS;
+
+ gcmkHEADER_ARG("Os=0x%X Logical=0x%X ProcessID=%d", Os, Logical, ProcessID);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+ mutex_lock(&Os->mdlMutex);
+
+ if (Os->device->contiguousPhysical)
+ {
+ /* Try the contiguous memory pool. */
+ mdl = (PLINUX_MDL) Os->device->contiguousPhysical;
+
+ mutex_lock(&mdl->mapsMutex);
+
+ status = _ConvertLogical2Physical(Os, Logical, ProcessID, mdl, Address);
+
+ mutex_unlock(&mdl->mapsMutex);
+ }
+
+ if (gcmIS_ERROR(status))
+ {
+ /* Walk all MDLs. */
+ list_for_each_entry(mdl, &Os->mdlHead, link)
+ {
+ mutex_lock(&mdl->mapsMutex);
+
+ status = _ConvertLogical2Physical(Os, Logical, ProcessID, mdl, Address);
+
+ mutex_unlock(&mdl->mapsMutex);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ break;
+ }
+ }
+ }
+
+ mutex_unlock(&Os->mdlMutex);
+
+ gcmkONERROR(status);
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Address=%p", *Address);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+
+
+/*******************************************************************************
+**
+** gckOS_GetPhysicalAddress
+**
+** Get the physical system address of a corresponding virtual address.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPOINTER Logical
+** Logical address.
+**
+** OUTPUT:
+**
+** gctUINT32 * Address
+** Poinetr to a variable that receives the 32-bit physical adress.
+*/
+gceSTATUS
+gckOS_GetPhysicalAddress(
+ IN gckOS Os,
+ IN gctPOINTER Logical,
+ OUT gctPHYS_ADDR_T * Address
+ )
+{
+ gceSTATUS status;
+ gctUINT32 processID;
+
+ gcmkHEADER_ARG("Os=0x%X Logical=0x%X", Os, Logical);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+ /* Query page table of current process first. */
+ status = _QueryProcessPageTable(Logical, Address);
+
+ if (gcmIS_ERROR(status))
+ {
+ /* Get current process ID. */
+ processID = _GetProcessID();
+
+ /* Route through other function. */
+ gcmkONERROR(
+ _GetPhysicalAddressProcess(Os, Logical, processID, Address));
+ }
+
+ gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(Os, *Address, Address));
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Address=%p", *Address);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_UserLogicalToPhysical
+**
+** Get the physical system address of a corresponding user virtual address.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPOINTER Logical
+** Logical address.
+**
+** OUTPUT:
+**
+** gctUINT32 * Address
+** Pointer to a variable that receives the 32-bit physical address.
+*/
+gceSTATUS gckOS_UserLogicalToPhysical(
+ IN gckOS Os,
+ IN gctPOINTER Logical,
+ OUT gctPHYS_ADDR_T * Address
+ )
+{
+ return gckOS_GetPhysicalAddress(Os, Logical, Address);
+}
+
+#if gcdSECURE_USER
+static gceSTATUS
+gckOS_AddMapping(
+ IN gckOS Os,
+ IN gctUINT32 Physical,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ )
+{
+ gceSTATUS status;
+ gcsUSER_MAPPING_PTR map;
+
+ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Logical=0x%X Bytes=%lu",
+ Os, Physical, Logical, Bytes);
+
+ gcmkONERROR(gckOS_Allocate(Os,
+ gcmSIZEOF(gcsUSER_MAPPING),
+ (gctPOINTER *) &map));
+
+ map->next = Os->userMap;
+ map->physical = Physical - Os->device->baseAddress;
+ map->logical = Logical;
+ map->bytes = Bytes;
+ map->start = (gctINT8_PTR) Logical;
+ map->end = map->start + Bytes;
+
+ Os->userMap = map;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+static gceSTATUS
+gckOS_RemoveMapping(
+ IN gckOS Os,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ )
+{
+ gceSTATUS status;
+ gcsUSER_MAPPING_PTR map, prev;
+
+ gcmkHEADER_ARG("Os=0x%X Logical=0x%X Bytes=%lu", Os, Logical, Bytes);
+
+ for (map = Os->userMap, prev = gcvNULL; map != gcvNULL; map = map->next)
+ {
+ if ((map->logical == Logical) && (map->bytes == Bytes))
+ {
+ break;
+ }
+
+ prev = map;
+ }
+
+ if (map == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ADDRESS);
+ }
+
+ if (prev == gcvNULL)
+ {
+ Os->userMap = map->next;
+ }
+ else
+ {
+ prev->next = map->next;
+ }
+
+ gcmkONERROR(gcmkOS_SAFE_FREE(Os, map));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+#endif
+
+gceSTATUS
+_ConvertLogical2Physical(
+ IN gckOS Os,
+ IN gctPOINTER Logical,
+ IN gctUINT32 ProcessID,
+ IN PLINUX_MDL Mdl,
+ OUT gctPHYS_ADDR_T * Physical
+ )
+{
+ gckALLOCATOR allocator = Mdl->allocator;
+ gctUINT32 offset;
+ gceSTATUS status = gcvSTATUS_NOT_FOUND;
+ gctINT8_PTR vBase;
+
+ /* TASK_SIZE is userspace - kernelspace virtual memory split. */
+ if ((gctUINTPTR_T)Logical >= TASK_SIZE)
+ {
+ /* Kernel virtual address. */
+ vBase = Mdl->addr;
+ }
+ else
+ {
+ /* User virtual address. */
+ PLINUX_MDL_MAP map;
+
+ map = FindMdlMap(Mdl, (gctINT) ProcessID);
+ vBase = (map == gcvNULL) ? gcvNULL : (gctINT8_PTR) map->vmaAddr;
+ }
+
+ /* Is the given address within that range. */
+ if ((vBase != gcvNULL)
+ && ((gctINT8_PTR) Logical >= vBase)
+ && ((gctINT8_PTR) Logical < vBase + Mdl->numPages * PAGE_SIZE)
+ )
+ {
+ offset = (gctINT8_PTR) Logical - vBase;
+
+ allocator->ops->Physical(allocator, Mdl, offset, Physical);
+
+ status = gcvSTATUS_OK;
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_MapPhysical
+**
+** Map a physical address into kernel space.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctUINT32 Physical
+** Physical address of the memory to map.
+**
+** gctSIZE_T Bytes
+** Number of bytes to map.
+**
+** OUTPUT:
+**
+** gctPOINTER * Logical
+** Pointer to a variable that receives the base address of the mapped
+** memory.
+*/
+gceSTATUS
+gckOS_MapPhysical(
+ IN gckOS Os,
+ IN gctUINT32 Physical,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER * Logical
+ )
+{
+ gctPOINTER logical;
+ PLINUX_MDL mdl;
+ gctBOOL found = gcvFALSE;
+ gctUINT32 physical = Physical;
+
+ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Bytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+ mutex_lock(&Os->mdlMutex);
+
+ /* Go through our mapping to see if we know this physical address already. */
+ list_for_each_entry(mdl, &Os->mdlHead, link)
+ {
+ if (mdl->dmaHandle != 0)
+ {
+ if ((physical >= mdl->dmaHandle)
+ && (physical < mdl->dmaHandle + mdl->numPages * PAGE_SIZE)
+ )
+ {
+ *Logical = mdl->addr + (physical - mdl->dmaHandle);
+ found = gcvTRUE;
+ break;
+ }
+ }
+ }
+
+ mutex_unlock(&Os->mdlMutex);
+
+ if (!found)
+ {
+ unsigned long pfn = physical >> PAGE_SHIFT;
+
+ if (pfn_valid(pfn))
+ {
+ gctUINT32 offset = physical & ~PAGE_MASK;
+ struct page ** pages;
+ struct page * page;
+ gctUINT numPages;
+ gctINT i;
+
+ numPages = GetPageCount(PAGE_ALIGN(offset + Bytes), 0);
+
+ pages = kmalloc(sizeof(struct page *) * numPages, GFP_KERNEL | gcdNOWARN);
+
+ if (!pages)
+ {
+ gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY);
+ return gcvSTATUS_OUT_OF_MEMORY;
+ }
+
+ page = pfn_to_page(pfn);
+
+ for (i = 0; i < numPages; i++)
+ {
+ pages[i] = nth_page(page, i);
+ }
+
+ logical = vmap(pages, numPages, 0, gcmkNONPAGED_MEMROY_PROT(PAGE_KERNEL));
+
+ kfree(pages);
+
+ if (logical == gcvNULL)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): Failed to vmap",
+ __FUNCTION__, __LINE__
+ );
+
+ /* Out of resources. */
+ gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES);
+ return gcvSTATUS_OUT_OF_RESOURCES;
+ }
+
+ logical += offset;
+ }
+ else
+ {
+ /* Map memory as cached memory. */
+ request_mem_region(physical, Bytes, "MapRegion");
+ logical = (gctPOINTER) ioremap_nocache(physical, Bytes);
+
+ if (logical == gcvNULL)
+ {
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): Failed to ioremap",
+ __FUNCTION__, __LINE__
+ );
+
+ /* Out of resources. */
+ gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES);
+ return gcvSTATUS_OUT_OF_RESOURCES;
+ }
+ }
+
+ /* Return pointer to mapped memory. */
+ *Logical = logical;
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Logical=0x%X", *Logical);
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_UnmapPhysical
+**
+** Unmap a previously mapped memory region from kernel memory.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPOINTER Logical
+** Pointer to the base address of the memory to unmap.
+**
+** gctSIZE_T Bytes
+** Number of bytes to unmap.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_UnmapPhysical(
+ IN gckOS Os,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ )
+{
+ PLINUX_MDL mdl;
+ gctBOOL found = gcvFALSE;
+
+ gcmkHEADER_ARG("Os=0x%X Logical=0x%X Bytes=%lu", Os, Logical, Bytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+
+ mutex_lock(&Os->mdlMutex);
+
+ list_for_each_entry(mdl, &Os->mdlHead, link)
+ {
+ if (mdl->addr != gcvNULL)
+ {
+ if ((Logical >= (gctPOINTER)mdl->addr) &&
+ (Logical < (gctPOINTER)((gctSTRING)mdl->addr + mdl->numPages * PAGE_SIZE)))
+ {
+ found = gcvTRUE;
+ break;
+ }
+ }
+ }
+
+ mutex_unlock(&Os->mdlMutex);
+
+ if (!found)
+ {
+ /* Unmap the memory. */
+ vunmap((void *)((unsigned long)Logical & PAGE_MASK));
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_DeleteMutex
+**
+** Delete a mutex.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPOINTER Mutex
+** Pointer to the mute to be deleted.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_DeleteMutex(
+ IN gckOS Os,
+ IN gctPOINTER Mutex
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Os=0x%X Mutex=0x%X", Os, Mutex);
+
+ /* Validate the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Mutex != gcvNULL);
+
+ /* Destroy the mutex. */
+ mutex_destroy((struct mutex *)Mutex);
+
+ /* Free the mutex structure. */
+ gcmkONERROR(gckOS_Free(Os, Mutex));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_AcquireMutex
+**
+** Acquire a mutex.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPOINTER Mutex
+** Pointer to the mutex to be acquired.
+**
+** gctUINT32 Timeout
+** Timeout value specified in milliseconds.
+** Specify the value of gcvINFINITE to keep the thread suspended
+** until the mutex has been acquired.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_AcquireMutex(
+ IN gckOS Os,
+ IN gctPOINTER Mutex,
+ IN gctUINT32 Timeout
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Mutex=0x%0x Timeout=%u", Os, Mutex, Timeout);
+
+ /* Validate the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Mutex != gcvNULL);
+
+ if (Timeout == gcvINFINITE)
+ {
+ /* Lock the mutex. */
+ mutex_lock(Mutex);
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+ for (;;)
+ {
+ /* Try to acquire the mutex. */
+ if (mutex_trylock(Mutex))
+ {
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+ if (Timeout-- == 0)
+ {
+ break;
+ }
+
+ /* Wait for 1 millisecond. */
+ gcmkVERIFY_OK(gckOS_Delay(Os, 1));
+ }
+
+ /* Timeout. */
+ gcmkFOOTER_ARG("status=%d", gcvSTATUS_TIMEOUT);
+ return gcvSTATUS_TIMEOUT;
+}
+
+/*******************************************************************************
+**
+** gckOS_ReleaseMutex
+**
+** Release an acquired mutex.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPOINTER Mutex
+** Pointer to the mutex to be released.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_ReleaseMutex(
+ IN gckOS Os,
+ IN gctPOINTER Mutex
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Mutex=0x%0x", Os, Mutex);
+
+ /* Validate the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Mutex != gcvNULL);
+
+ /* Release the mutex. */
+ mutex_unlock(Mutex);
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_AtomicExchange
+**
+** Atomically exchange a pair of 32-bit values.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** IN OUT gctINT32_PTR Target
+** Pointer to the 32-bit value to exchange.
+**
+** IN gctINT32 NewValue
+** Specifies a new value for the 32-bit value pointed to by Target.
+**
+** OUT gctINT32_PTR OldValue
+** The old value of the 32-bit value pointed to by Target.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_AtomicExchange(
+ IN gckOS Os,
+ IN OUT gctUINT32_PTR Target,
+ IN gctUINT32 NewValue,
+ OUT gctUINT32_PTR OldValue
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Target=0x%X NewValue=%u", Os, Target, NewValue);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(OldValue != gcvNULL);
+
+ /* Exchange the pair of 32-bit values. */
+ *OldValue = (gctUINT32) atomic_xchg((atomic_t *) Target, (int) NewValue);
+
+ /* Success. */
+ gcmkFOOTER_ARG("*OldValue=%u", *OldValue);
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_AtomicExchangePtr
+**
+** Atomically exchange a pair of pointers.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** IN OUT gctPOINTER * Target
+** Pointer to the 32-bit value to exchange.
+**
+** IN gctPOINTER NewValue
+** Specifies a new value for the pointer pointed to by Target.
+**
+** OUT gctPOINTER * OldValue
+** The old value of the pointer pointed to by Target.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_AtomicExchangePtr(
+ IN gckOS Os,
+ IN OUT gctPOINTER * Target,
+ IN gctPOINTER NewValue,
+ OUT gctPOINTER * OldValue
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Target=0x%X NewValue=0x%X", Os, Target, NewValue);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(OldValue != gcvNULL);
+
+ /* Exchange the pair of pointers. */
+ *OldValue = (gctPOINTER)(gctUINTPTR_T) atomic_xchg((atomic_t *) Target, (int)(gctUINTPTR_T) NewValue);
+
+ /* Success. */
+ gcmkFOOTER_ARG("*OldValue=0x%X", *OldValue);
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_AtomicSetMask
+**
+** Atomically set mask to Atom
+**
+** INPUT:
+** IN OUT gctPOINTER Atom
+** Pointer to the atom to set.
+**
+** IN gctUINT32 Mask
+** Mask to set.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_AtomSetMask(
+ IN gctPOINTER Atom,
+ IN gctUINT32 Mask
+ )
+{
+ gctUINT32 oval, nval;
+
+ gcmkHEADER_ARG("Atom=0x%0x", Atom);
+ gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
+
+ do
+ {
+ oval = atomic_read((atomic_t *) Atom);
+ nval = oval | Mask;
+ }
+ while (atomic_cmpxchg((atomic_t *) Atom, oval, nval) != oval);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_AtomClearMask
+**
+** Atomically clear mask from Atom
+**
+** INPUT:
+** IN OUT gctPOINTER Atom
+** Pointer to the atom to clear.
+**
+** IN gctUINT32 Mask
+** Mask to clear.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_AtomClearMask(
+ IN gctPOINTER Atom,
+ IN gctUINT32 Mask
+ )
+{
+ gctUINT32 oval, nval;
+
+ gcmkHEADER_ARG("Atom=0x%0x", Atom);
+ gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
+
+ do
+ {
+ oval = atomic_read((atomic_t *) Atom);
+ nval = oval & ~Mask;
+ }
+ while (atomic_cmpxchg((atomic_t *) Atom, oval, nval) != oval);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_AtomConstruct
+**
+** Create an atom.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** OUTPUT:
+**
+** gctPOINTER * Atom
+** Pointer to a variable receiving the constructed atom.
+*/
+gceSTATUS
+gckOS_AtomConstruct(
+ IN gckOS Os,
+ OUT gctPOINTER * Atom
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Os=0x%X", Os);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
+
+ /* Allocate the atom. */
+ gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(atomic_t), Atom));
+
+ /* Initialize the atom. */
+ atomic_set((atomic_t *) *Atom, 0);
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Atom=0x%X", *Atom);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_AtomDestroy
+**
+** Destroy an atom.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gctPOINTER Atom
+** Pointer to the atom to destroy.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_AtomDestroy(
+ IN gckOS Os,
+ OUT gctPOINTER Atom
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
+
+ /* Free the atom. */
+ gcmkONERROR(gcmkOS_SAFE_FREE(Os, Atom));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_AtomGet
+**
+** Get the 32-bit value protected by an atom.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gctPOINTER Atom
+** Pointer to the atom.
+**
+** OUTPUT:
+**
+** gctINT32_PTR Value
+** Pointer to a variable the receives the value of the atom.
+*/
+gceSTATUS
+gckOS_AtomGet(
+ IN gckOS Os,
+ IN gctPOINTER Atom,
+ OUT gctINT32_PTR Value
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
+
+ /* Return the current value of atom. */
+ *Value = atomic_read((atomic_t *) Atom);
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Value=%d", *Value);
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_AtomSet
+**
+** Set the 32-bit value protected by an atom.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gctPOINTER Atom
+** Pointer to the atom.
+**
+** gctINT32 Value
+** The value of the atom.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_AtomSet(
+ IN gckOS Os,
+ IN gctPOINTER Atom,
+ IN gctINT32 Value
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Atom=0x%0x Value=%d", Os, Atom);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
+
+ /* Set the current value of atom. */
+ atomic_set((atomic_t *) Atom, Value);
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_AtomIncrement
+**
+** Atomically increment the 32-bit integer value inside an atom.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gctPOINTER Atom
+** Pointer to the atom.
+**
+** OUTPUT:
+**
+** gctINT32_PTR Value
+** Pointer to a variable that receives the original value of the atom.
+*/
+gceSTATUS
+gckOS_AtomIncrement(
+ IN gckOS Os,
+ IN gctPOINTER Atom,
+ OUT gctINT32_PTR Value
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
+
+ /* Increment the atom. */
+ *Value = atomic_inc_return((atomic_t *) Atom) - 1;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Value=%d", *Value);
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_AtomDecrement
+**
+** Atomically decrement the 32-bit integer value inside an atom.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gctPOINTER Atom
+** Pointer to the atom.
+**
+** OUTPUT:
+**
+** gctINT32_PTR Value
+** Pointer to a variable that receives the original value of the atom.
+*/
+gceSTATUS
+gckOS_AtomDecrement(
+ IN gckOS Os,
+ IN gctPOINTER Atom,
+ OUT gctINT32_PTR Value
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Atom != gcvNULL);
+
+ /* Decrement the atom. */
+ *Value = atomic_dec_return((atomic_t *) Atom) + 1;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Value=%d", *Value);
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_Delay
+**
+** Delay execution of the current thread for a number of milliseconds.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctUINT32 Delay
+** Delay to sleep, specified in milliseconds.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_Delay(
+ IN gckOS Os,
+ IN gctUINT32 Delay
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Delay=%u", Os, Delay);
+
+ if (Delay > 0)
+ {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
+ ktime_t delay = ktime_set((Delay / MSEC_PER_SEC), (Delay % MSEC_PER_SEC) * NSEC_PER_MSEC);
+ __set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_hrtimeout(&delay, HRTIMER_MODE_REL);
+#else
+ msleep(Delay);
+#endif
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_GetTicks
+**
+** Get the number of milliseconds since the system started.
+**
+** INPUT:
+**
+** OUTPUT:
+**
+** gctUINT32_PTR Time
+** Pointer to a variable to get time.
+**
+*/
+gceSTATUS
+gckOS_GetTicks(
+ OUT gctUINT32_PTR Time
+ )
+{
+ gcmkHEADER();
+
+ *Time = jiffies_to_msecs(jiffies);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_TicksAfter
+**
+** Compare time values got from gckOS_GetTicks.
+**
+** INPUT:
+** gctUINT32 Time1
+** First time value to be compared.
+**
+** gctUINT32 Time2
+** Second time value to be compared.
+**
+** OUTPUT:
+**
+** gctBOOL_PTR IsAfter
+** Pointer to a variable to result.
+**
+*/
+gceSTATUS
+gckOS_TicksAfter(
+ IN gctUINT32 Time1,
+ IN gctUINT32 Time2,
+ OUT gctBOOL_PTR IsAfter
+ )
+{
+ gcmkHEADER();
+
+ *IsAfter = time_after((unsigned long)Time1, (unsigned long)Time2);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_GetTime
+**
+** Get the number of microseconds since the system started.
+**
+** INPUT:
+**
+** OUTPUT:
+**
+** gctUINT64_PTR Time
+** Pointer to a variable to get time.
+**
+*/
+gceSTATUS
+gckOS_GetTime(
+ OUT gctUINT64_PTR Time
+ )
+{
+ struct timeval tv;
+ gcmkHEADER();
+
+ /* Return the time of day in microseconds. */
+ do_gettimeofday(&tv);
+ *Time = (tv.tv_sec * 1000000ULL) + tv.tv_usec;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_MemoryBarrier
+**
+** Make sure the CPU has executed everything up to this point and the data got
+** written to the specified pointer.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPOINTER Address
+** Address of memory that needs to be barriered.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_MemoryBarrier(
+ IN gckOS Os,
+ IN gctPOINTER Address
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Address=0x%X", Os, Address);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+
+#if gcdNONPAGED_MEMORY_BUFFERABLE \
+ && defined (CONFIG_ARM) \
+ && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34))
+ /* drain write buffer */
+ dsb();
+
+ /* drain outer cache's write buffer? */
+#else
+ mb();
+#endif
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_AllocatePagedMemory
+**
+** Allocate memory from the paged pool.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctSIZE_T Bytes
+** Number of bytes to allocate.
+**
+** OUTPUT:
+**
+** gctPHYS_ADDR * Physical
+** Pointer to a variable that receives the physical address of the
+** memory allocation.
+*/
+gceSTATUS
+gckOS_AllocatePagedMemory(
+ IN gckOS Os,
+ IN gctSIZE_T Bytes,
+ OUT gctPHYS_ADDR * Physical
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Os=0x%X Bytes=%lu", Os, Bytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+
+ /* Allocate the memory. */
+ gcmkONERROR(gckOS_AllocatePagedMemoryEx(Os, gcvALLOC_FLAG_NONE, Bytes, gcvNULL, Physical));
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Physical=0x%X", *Physical);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_AllocatePagedMemoryEx
+**
+** Allocate memory from the paged pool.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctUINT32 Flag
+** Allocation attribute.
+**
+** gctSIZE_T Bytes
+** Number of bytes to allocate.
+**
+** OUTPUT:
+**
+** gctUINT32 * Gid
+** Save the global ID for the piece of allocated memory.
+**
+** gctPHYS_ADDR * Physical
+** Pointer to a variable that receives the physical address of the
+** memory allocation.
+*/
+gceSTATUS
+gckOS_AllocatePagedMemoryEx(
+ IN gckOS Os,
+ IN gctUINT32 Flag,
+ IN gctSIZE_T Bytes,
+ OUT gctUINT32 * Gid,
+ OUT gctPHYS_ADDR * Physical
+ )
+{
+ gctINT numPages;
+ PLINUX_MDL mdl = gcvNULL;
+ gctSIZE_T bytes;
+ gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+ gckALLOCATOR allocator;
+
+ gcmkHEADER_ARG("Os=0x%X Flag=%x Bytes=%lu", Os, Flag, Bytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+
+ bytes = gcmALIGN(Bytes, PAGE_SIZE);
+
+ numPages = GetPageCount(bytes, 0);
+
+ mdl = _CreateMdl(Os);
+ if (mdl == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ if (Os->allocatorLimitMarker && (Flag & gcvALLOC_FLAG_CMA_LIMIT))
+ {
+ Flag &= ~gcvALLOC_FLAG_CACHEABLE;
+ }
+ else
+ {
+ Flag &= ~gcvALLOC_FLAG_CMA_LIMIT;
+ }
+
+ /* Walk all allocators. */
+ list_for_each_entry(allocator, &Os->allocatorList, link)
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d) flag = %x allocator->capability = %x",
+ __FUNCTION__, __LINE__, Flag, allocator->capability);
+
+ if ((Flag & allocator->capability) != Flag)
+ {
+ continue;
+ }
+
+ status = allocator->ops->Alloc(allocator, mdl, numPages, Flag);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ mdl->allocator = allocator;
+ break;
+ }
+ }
+
+ /* Check status. */
+ gcmkONERROR(status);
+
+ mdl->dmaHandle = 0;
+ mdl->addr = 0;
+ mdl->numPages = numPages;
+ mdl->contiguous = Flag & gcvALLOC_FLAG_CONTIGUOUS;
+
+ if (Gid != gcvNULL)
+ {
+ *Gid = mdl->gid;
+ }
+
+ /*
+ * Add this to a global list.
+ * Will be used by get physical address
+ * and mapuser pointer functions.
+ */
+ mutex_lock(&Os->mdlMutex);
+ list_add_tail(&mdl->link, &Os->mdlHead);
+ mutex_unlock(&Os->mdlMutex);
+
+ /* Return physical address. */
+ *Physical = (gctPHYS_ADDR) mdl;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Physical=0x%X", *Physical);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (mdl != gcvNULL)
+ {
+ /* Free the memory. */
+ _DestroyMdl(mdl);
+ }
+
+ /* Return the status. */
+ gcmkFOOTER_ARG("Os=0x%X Flag=%x Bytes=%lu", Os, Flag, Bytes);
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_FreePagedMemory
+**
+** Free memory allocated from the paged pool.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPHYS_ADDR Physical
+** Physical address of the allocation.
+**
+** gctSIZE_T Bytes
+** Number of bytes of the allocation.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_FreePagedMemory(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes
+ )
+{
+ PLINUX_MDL mdl = (PLINUX_MDL)Physical;
+
+ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Bytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+
+ /* Free the structure... */
+ gcmkVERIFY_OK(_DestroyMdl(mdl));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_LockPages
+**
+** Lock memory allocated from the paged pool.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPHYS_ADDR Physical
+** Physical address of the allocation.
+**
+** gctSIZE_T Bytes
+** Number of bytes of the allocation.
+**
+** gctBOOL Cacheable
+** Cache mode of mapping.
+**
+** OUTPUT:
+**
+** gctPOINTER * Logical
+** Pointer to a variable that receives the address of the mapped
+** memory.
+**
+** gctSIZE_T * PageCount
+** Pointer to a variable that receives the number of pages required for
+** the page table according to the GPU page size.
+*/
+gceSTATUS
+gckOS_LockPages(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctBOOL Cacheable,
+ OUT gctPOINTER * Logical,
+ OUT gctSIZE_T * PageCount
+ )
+{
+ gceSTATUS status;
+ PLINUX_MDL mdl;
+ PLINUX_MDL_MAP mdlMap;
+ gckALLOCATOR allocator;
+
+ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Logical);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(PageCount != gcvNULL);
+
+ mdl = (PLINUX_MDL) Physical;
+ allocator = mdl->allocator;
+
+ mutex_lock(&mdl->mapsMutex);
+
+ mdlMap = FindMdlMap(mdl, _GetProcessID());
+
+ if (mdlMap == gcvNULL)
+ {
+ mdlMap = _CreateMdlMap(mdl, _GetProcessID());
+
+ if (mdlMap == gcvNULL)
+ {
+ mutex_unlock(&mdl->mapsMutex);
+
+ gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY);
+ return gcvSTATUS_OUT_OF_MEMORY;
+ }
+ }
+
+ if (mdlMap->vmaAddr == gcvNULL)
+ {
+ status = allocator->ops->MapUser(allocator, mdl, Cacheable, &mdlMap->vmaAddr);
+
+ if (gcmIS_ERROR(status))
+ {
+ mutex_unlock(&mdl->mapsMutex);
+
+ gcmkFOOTER_ARG("*status=%d", status);
+ return status;
+ }
+ }
+
+ mdlMap->count++;
+
+ /* Convert pointer to MDL. */
+ *Logical = mdlMap->vmaAddr;
+
+ /* Return the page number according to the GPU page size. */
+ gcmkASSERT((PAGE_SIZE % 4096) == 0);
+ gcmkASSERT((PAGE_SIZE / 4096) >= 1);
+
+ *PageCount = mdl->numPages * (PAGE_SIZE / 4096);
+
+ mutex_unlock(&mdl->mapsMutex);
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Logical=0x%X *PageCount=%lu", *Logical, *PageCount);
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_MapPages
+**
+** Map paged memory into a page table.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPHYS_ADDR Physical
+** Physical address of the allocation.
+**
+** gctSIZE_T PageCount
+** Number of pages required for the physical address.
+**
+** gctPOINTER PageTable
+** Pointer to the page table to fill in.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_MapPages(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T PageCount,
+ IN gctPOINTER PageTable
+ )
+{
+ return gcvSTATUS_NOT_SUPPORTED;
+}
+
+gceSTATUS
+gckOS_MapPagesEx(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T PageCount,
+ IN gctUINT32 Address,
+ IN gctPOINTER PageTable,
+ IN gctBOOL Writable,
+ IN gceSURF_TYPE Type
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+ PLINUX_MDL mdl;
+ gctUINT32* table;
+ gctUINT32 offset = 0;
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ gckMMU mmu;
+ PLINUX_MDL mmuMdl;
+ gctUINT32 bytes;
+ gctPHYS_ADDR pageTablePhysical;
+#endif
+
+#if gcdPROCESS_ADDRESS_SPACE
+ gckKERNEL kernel = Os->device->kernels[Core];
+ gckMMU mmu;
+#endif
+ gckALLOCATOR allocator;
+
+ gctUINT32 policyID = 0;
+ gctUINT32 axiConfig = 0;
+
+ gcsPLATFORM * platform = Os->device->platform;
+
+ gcmkHEADER_ARG("Os=0x%X Core=%d Physical=0x%X PageCount=%u PageTable=0x%X",
+ Os, Core, Physical, PageCount, PageTable);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(PageCount > 0);
+ gcmkVERIFY_ARGUMENT(PageTable != gcvNULL);
+
+ /* Convert pointer to MDL. */
+ mdl = (PLINUX_MDL)Physical;
+
+ allocator = mdl->allocator;
+
+ gcmkASSERT(allocator != gcvNULL);
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): Physical->0x%X PageCount->0x%X",
+ __FUNCTION__, __LINE__,
+ (gctUINT32)(gctUINTPTR_T)Physical,
+ (gctUINT32)(gctUINTPTR_T)PageCount
+ );
+
+#if gcdPROCESS_ADDRESS_SPACE
+ gcmkONERROR(gckKERNEL_GetProcessMMU(kernel, &mmu));
+#endif
+
+ table = (gctUINT32 *)PageTable;
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ mmu = Os->device->kernels[Core]->mmu;
+ bytes = PageCount * sizeof(*table);
+ mmuMdl = (PLINUX_MDL)mmu->pageTablePhysical;
+#endif
+
+ if (platform && platform->ops->getPolicyID)
+ {
+ platform->ops->getPolicyID(platform, Type, &policyID, &axiConfig);
+
+ gcmkBUG_ON(policyID > 0x1F);
+
+ /* ID[3:0] is used in STLB. */
+ policyID &= 0xF;
+ }
+
+ /* Get all the physical addresses and store them in the page table. */
+
+ PageCount = PageCount / (PAGE_SIZE / 4096);
+
+ /* Try to get the user pages so DMA can happen. */
+ while (PageCount-- > 0)
+ {
+ gctUINT i;
+ gctPHYS_ADDR_T phys = ~0U;
+
+ allocator->ops->Physical(allocator, mdl, offset, &phys);
+
+ gcmkVERIFY_OK(gckOS_CPUPhysicalToGPUPhysical(Os, phys, &phys));
+
+ if (policyID)
+ {
+ /* AxUSER must not used for address currently. */
+ gcmkBUG_ON((phys >> 32) & 0xF);
+
+ /* Merge policyID to AxUSER[7:4].*/
+ phys |= ((gctPHYS_ADDR_T)policyID << 36);
+ }
+
+#ifdef CONFIG_IOMMU_SUPPORT
+ if (Os->iommu)
+ {
+ /* remove LSB. */
+ phys &= PAGE_MASK;
+
+ gcmkTRACE_ZONE(
+ gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d): Setup mapping in IOMMU %x => %x",
+ __FUNCTION__, __LINE__,
+ Address + offset, phys
+ );
+
+ /* When use IOMMU, GPU use system PAGE_SIZE. */
+ gcmkONERROR(gckIOMMU_Map(
+ Os->iommu, Address + offset, phys, PAGE_SIZE));
+ }
+ else
+#endif
+ {
+ /* remove LSB. */
+ phys &= ~(4096ull - 1);
+
+#if gcdENABLE_VG
+ if (Core == gcvCORE_VG)
+ {
+ for (i = 0; i < (PAGE_SIZE / 4096); i++)
+ {
+ gcmkONERROR(
+ gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu,
+ phys + (i * 4096),
+ table++));
+ }
+ }
+ else
+#endif
+ {
+ for (i = 0; i < (PAGE_SIZE / 4096); i++)
+ {
+#if gcdPROCESS_ADDRESS_SPACE
+ gctUINT32_PTR pageTableEntry;
+ gckMMU_GetPageEntry(mmu, Address + offset + (i * 4096), &pageTableEntry);
+ gcmkONERROR(
+ gckMMU_SetPage(mmu,
+ phys + (i * 4096),
+ Writable,
+ pageTableEntry));
+#else
+ gcmkONERROR(
+ gckMMU_SetPage(Os->device->kernels[Core]->mmu,
+ phys + (i * 4096),
+ Writable,
+ table++));
+#endif
+ }
+ }
+ }
+
+ offset += PAGE_SIZE;
+ }
+
+#if gcdNONPAGED_MEMORY_CACHEABLE
+ /* Get physical address of pageTable */
+ pageTablePhysical = (gctPHYS_ADDR)(mmuMdl->dmaHandle +
+ ((gctUINT32 *)PageTable - mmu->pageTableLogical));
+
+ /* Flush the mmu page table cache. */
+ gcmkONERROR(gckOS_CacheClean(
+ Os,
+ _GetProcessID(),
+ gcvNULL,
+ pageTablePhysical,
+ PageTable,
+ bytes
+ ));
+#endif
+
+OnError:
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckOS_UnmapPages(
+ IN gckOS Os,
+ IN gctSIZE_T PageCount,
+ IN gctUINT32 Address
+ )
+{
+#ifdef CONFIG_IOMMU_SUPPORT
+ if (Os->iommu)
+ {
+ gcmkVERIFY_OK(gckIOMMU_Unmap(
+ Os->iommu, Address, PageCount * PAGE_SIZE));
+ }
+#endif
+
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_UnlockPages
+**
+** Unlock memory allocated from the paged pool.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPHYS_ADDR Physical
+** Physical address of the allocation.
+**
+** gctSIZE_T Bytes
+** Number of bytes of the allocation.
+**
+** gctPOINTER Logical
+** Address of the mapped memory.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_UnlockPages(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical
+ )
+{
+ PLINUX_MDL_MAP mdlMap;
+ PLINUX_MDL mdl = (PLINUX_MDL)Physical;
+ gckALLOCATOR allocator = mdl->allocator;
+ gctINT pid = _GetProcessID();
+
+ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%u Logical=0x%X",
+ Os, Physical, Bytes, Logical);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+ mutex_lock(&mdl->mapsMutex);
+
+ list_for_each_entry(mdlMap, &mdl->mapsHead, link)
+ {
+ if ((mdlMap->vmaAddr != gcvNULL) && (mdlMap->pid == pid))
+ {
+ if (--mdlMap->count == 0)
+ {
+ allocator->ops->UnmapUser(
+ allocator,
+ mdl,
+ mdlMap->vmaAddr,
+ mdl->numPages * PAGE_SIZE);
+
+ mdlMap->vmaAddr = gcvNULL;
+ }
+ }
+ }
+
+ mutex_unlock(&mdl->mapsMutex);
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+
+/*******************************************************************************
+**
+** gckOS_AllocateContiguous
+**
+** Allocate memory from the contiguous pool.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctBOOL InUserSpace
+** gcvTRUE if the pages need to be mapped into user space.
+**
+** gctSIZE_T * Bytes
+** Pointer to the number of bytes to allocate.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that receives the number of bytes allocated.
+**
+** gctPHYS_ADDR * Physical
+** Pointer to a variable that receives the physical address of the
+** memory allocation.
+**
+** gctPOINTER * Logical
+** Pointer to a variable that receives the logical address of the
+** memory allocation.
+*/
+gceSTATUS
+gckOS_AllocateContiguous(
+ IN gckOS Os,
+ IN gctBOOL InUserSpace,
+ IN OUT gctSIZE_T * Bytes,
+ OUT gctPHYS_ADDR * Physical,
+ OUT gctPOINTER * Logical
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Os=0x%X InUserSpace=%d *Bytes=%lu",
+ Os, InUserSpace, gcmOPT_VALUE(Bytes));
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Bytes != gcvNULL);
+ gcmkVERIFY_ARGUMENT(*Bytes > 0);
+ gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+
+ /* Same as non-paged memory for now. */
+ gcmkONERROR(gckOS_AllocateNonPagedMemory(Os,
+ InUserSpace,
+ Bytes,
+ Physical,
+ Logical));
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Bytes=%lu *Physical=0x%X *Logical=0x%X",
+ *Bytes, *Physical, *Logical);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_FreeContiguous
+**
+** Free memory allocated from the contiguous pool.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPHYS_ADDR Physical
+** Physical address of the allocation.
+**
+** gctPOINTER Logical
+** Logicval address of the allocation.
+**
+** gctSIZE_T Bytes
+** Number of bytes of the allocation.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_FreeContiguous(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Os=0x%X Physical=0x%X Logical=0x%X Bytes=%lu",
+ Os, Physical, Logical, Bytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+
+ /* Same of non-paged memory for now. */
+ gcmkONERROR(gckOS_FreeNonPagedMemory(Os, Bytes, Physical, Logical));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+#if gcdENABLE_VG
+/******************************************************************************
+**
+** gckOS_GetKernelLogical
+**
+** Return the kernel logical pointer that corresponods to the specified
+** hardware address.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctUINT32 Address
+** Hardware physical address.
+**
+** OUTPUT:
+**
+** gctPOINTER * KernelPointer
+** Pointer to a variable receiving the pointer in kernel address space.
+*/
+gceSTATUS
+gckOS_GetKernelLogical(
+ IN gckOS Os,
+ IN gctUINT32 Address,
+ OUT gctPOINTER * KernelPointer
+ )
+{
+ return gckOS_GetKernelLogicalEx(Os, gcvCORE_MAJOR, Address, KernelPointer);
+}
+
+gceSTATUS
+gckOS_GetKernelLogicalEx(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctUINT32 Address,
+ OUT gctPOINTER * KernelPointer
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Os=0x%X Core=%d Address=0x%08x", Os, Core, Address);
+
+ do
+ {
+ gckGALDEVICE device;
+ gckKERNEL kernel;
+ gcePOOL pool;
+ gctUINT32 offset;
+ gctPOINTER logical;
+
+ /* Extract the pointer to the gckGALDEVICE class. */
+ device = (gckGALDEVICE) Os->device;
+
+ /* Kernel shortcut. */
+ kernel = device->kernels[Core];
+#if gcdENABLE_VG
+ if (Core == gcvCORE_VG)
+ {
+ gcmkERR_BREAK(gckVGHARDWARE_SplitMemory(
+ kernel->vg->hardware, Address, &pool, &offset
+ ));
+ }
+ else
+#endif
+ {
+ /* Split the memory address into a pool type and offset. */
+ gcmkERR_BREAK(gckHARDWARE_SplitMemory(
+ kernel->hardware, Address, &pool, &offset
+ ));
+ }
+
+ /* Dispatch on pool. */
+ switch (pool)
+ {
+ case gcvPOOL_LOCAL_INTERNAL:
+ /* Internal memory. */
+ logical = device->internalLogical;
+ break;
+
+ case gcvPOOL_LOCAL_EXTERNAL:
+ /* External memory. */
+ logical = device->externalLogical;
+ break;
+
+ case gcvPOOL_SYSTEM:
+ /* System memory. */
+ logical = device->contiguousLogical;
+ break;
+
+ default:
+ /* Invalid memory pool. */
+ gcmkFOOTER();
+ return gcvSTATUS_INVALID_ARGUMENT;
+ }
+
+ /* Build logical address of specified address. */
+ * KernelPointer = ((gctUINT8_PTR) logical) + offset;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*KernelPointer=0x%X", *KernelPointer);
+ return gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ /* Return status. */
+ gcmkFOOTER();
+ return status;
+}
+#endif
+
+/*******************************************************************************
+**
+** gckOS_MapUserPointer
+**
+** Map a pointer from the user process into the kernel address space.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPOINTER Pointer
+** Pointer in user process space that needs to be mapped.
+**
+** gctSIZE_T Size
+** Number of bytes that need to be mapped.
+**
+** OUTPUT:
+**
+** gctPOINTER * KernelPointer
+** Pointer to a variable receiving the mapped pointer in kernel address
+** space.
+*/
+gceSTATUS
+gckOS_MapUserPointer(
+ IN gckOS Os,
+ IN gctPOINTER Pointer,
+ IN gctSIZE_T Size,
+ OUT gctPOINTER * KernelPointer
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Pointer=0x%X Size=%lu", Os, Pointer, Size);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Size > 0);
+ gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
+
+ *KernelPointer = Pointer;
+
+ gcmkFOOTER_ARG("*KernelPointer=0x%X", *KernelPointer);
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_UnmapUserPointer
+**
+** Unmap a user process pointer from the kernel address space.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPOINTER Pointer
+** Pointer in user process space that needs to be unmapped.
+**
+** gctSIZE_T Size
+** Number of bytes that need to be unmapped.
+**
+** gctPOINTER KernelPointer
+** Pointer in kernel address space that needs to be unmapped.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_UnmapUserPointer(
+ IN gckOS Os,
+ IN gctPOINTER Pointer,
+ IN gctSIZE_T Size,
+ IN gctPOINTER KernelPointer
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Pointer=0x%X Size=%lu KernelPointer=0x%X",
+ Os, Pointer, Size, KernelPointer);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_QueryNeedCopy
+**
+** Query whether the memory can be accessed or mapped directly or it has to be
+** copied.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctUINT32 ProcessID
+** Process ID of the current process.
+**
+** OUTPUT:
+**
+** gctBOOL_PTR NeedCopy
+** Pointer to a boolean receiving gcvTRUE if the memory needs a copy or
+** gcvFALSE if the memory can be accessed or mapped dircetly.
+*/
+gceSTATUS
+gckOS_QueryNeedCopy(
+ IN gckOS Os,
+ IN gctUINT32 ProcessID,
+ OUT gctBOOL_PTR NeedCopy
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X ProcessID=%d", Os, ProcessID);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(NeedCopy != gcvNULL);
+
+ /* We need to copy data. */
+ *NeedCopy = gcvTRUE;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*NeedCopy=%d", *NeedCopy);
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_CopyFromUserData
+**
+** Copy data from user to kernel memory.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPOINTER KernelPointer
+** Pointer to kernel memory.
+**
+** gctPOINTER Pointer
+** Pointer to user memory.
+**
+** gctSIZE_T Size
+** Number of bytes to copy.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_CopyFromUserData(
+ IN gckOS Os,
+ IN gctPOINTER KernelPointer,
+ IN gctPOINTER Pointer,
+ IN gctSIZE_T Size
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Os=0x%X KernelPointer=0x%X Pointer=0x%X Size=%lu",
+ Os, KernelPointer, Pointer, Size);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Size > 0);
+
+ /* Copy data from user. */
+ if (copy_from_user(KernelPointer, Pointer, Size) != 0)
+ {
+ /* Could not copy all the bytes. */
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_CopyToUserData
+**
+** Copy data from kernel to user memory.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPOINTER KernelPointer
+** Pointer to kernel memory.
+**
+** gctPOINTER Pointer
+** Pointer to user memory.
+**
+** gctSIZE_T Size
+** Number of bytes to copy.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_CopyToUserData(
+ IN gckOS Os,
+ IN gctPOINTER KernelPointer,
+ IN gctPOINTER Pointer,
+ IN gctSIZE_T Size
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Os=0x%X KernelPointer=0x%X Pointer=0x%X Size=%lu",
+ Os, KernelPointer, Pointer, Size);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Pointer != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Size > 0);
+
+ /* Copy data to user. */
+ if (copy_to_user(Pointer, KernelPointer, Size) != 0)
+ {
+ /* Could not copy all the bytes. */
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_WriteMemory
+**
+** Write data to a memory.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctPOINTER Address
+** Address of the memory to write to.
+**
+** gctUINT32 Data
+** Data for register.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_WriteMemory(
+ IN gckOS Os,
+ IN gctPOINTER Address,
+ IN gctUINT32 Data
+ )
+{
+ gceSTATUS status;
+ gcmkHEADER_ARG("Os=0x%X Address=0x%X Data=%u", Os, Address, Data);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+ /* Write memory. */
+ if (access_ok(VERIFY_WRITE, Address, 4))
+ {
+ /* User address. */
+ if (put_user(Data, (gctUINT32*)Address))
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ADDRESS);
+ }
+ }
+ else
+ {
+ /* Kernel address. */
+ *(gctUINT32 *)Address = Data;
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckOS_ReadMappedPointer(
+ IN gckOS Os,
+ IN gctPOINTER Address,
+ IN gctUINT32_PTR Data
+ )
+{
+ gceSTATUS status;
+ gcmkHEADER_ARG("Os=0x%X Address=0x%X Data=%u", Os, Address, Data);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_ARGUMENT(Address != gcvNULL);
+
+ /* Write memory. */
+ if (access_ok(VERIFY_READ, Address, 4))
+ {
+ /* User address. */
+ if (get_user(*Data, (gctUINT32*)Address))
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ADDRESS);
+ }
+ }
+ else
+ {
+ /* Kernel address. */
+ *Data = *(gctUINT32_PTR)Address;
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_MapUserMemory
+**
+** Lock down a user buffer and return an DMA'able address to be used by the
+** hardware to access it.
+**
+** INPUT:
+**
+** gctPOINTER Memory
+** Pointer to memory to lock down.
+**
+** gctSIZE_T Size
+** Size in bytes of the memory to lock down.
+**
+** OUTPUT:
+**
+** gctPOINTER * Info
+** Pointer to variable receiving the information record required by
+** gckOS_UnmapUserMemory.
+**
+** gctUINT32_PTR Address
+** Pointer to a variable that will receive the address DMA'able by the
+** hardware.
+*/
+gceSTATUS
+gckOS_MapUserMemory(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctPOINTER Memory,
+ IN gctUINT32 Physical,
+ IN gctSIZE_T Size,
+ OUT gctPOINTER * Info,
+ OUT gctUINT32_PTR Address
+ )
+{
+ return gcvSTATUS_NOT_SUPPORTED;
+}
+
+/*******************************************************************************
+**
+** gckOS_UnmapUserMemory
+**
+** Unlock a user buffer and that was previously locked down by
+** gckOS_MapUserMemory.
+**
+** INPUT:
+**
+** gctPOINTER Memory
+** Pointer to memory to unlock.
+**
+** gctSIZE_T Size
+** Size in bytes of the memory to unlock.
+**
+** gctPOINTER Info
+** Information record returned by gckOS_MapUserMemory.
+**
+** gctUINT32_PTR Address
+** The address returned by gckOS_MapUserMemory.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_UnmapUserMemory(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctPOINTER Memory,
+ IN gctSIZE_T Size,
+ IN gctPOINTER Info,
+ IN gctUINT32 Address
+ )
+{
+ return gcvSTATUS_NOT_SUPPORTED;
+}
+
+/*******************************************************************************
+**
+** gckOS_GetBaseAddress
+**
+** Get the base address for the physical memory.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to the gckOS object.
+**
+** OUTPUT:
+**
+** gctUINT32_PTR BaseAddress
+** Pointer to a variable that will receive the base address.
+*/
+gceSTATUS
+gckOS_GetBaseAddress(
+ IN gckOS Os,
+ OUT gctUINT32_PTR BaseAddress
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X", Os);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(BaseAddress != gcvNULL);
+
+ /* Return base address. */
+ *BaseAddress = Os->device->baseAddress;
+
+ /* Success. */
+ gcmkFOOTER_ARG("*BaseAddress=0x%08x", *BaseAddress);
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_SuspendInterrupt(
+ IN gckOS Os
+ )
+{
+ return gckOS_SuspendInterruptEx(Os, gcvCORE_MAJOR);
+}
+
+gceSTATUS
+gckOS_SuspendInterruptEx(
+ IN gckOS Os,
+ IN gceCORE Core
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+
+ disable_irq(Os->device->irqLines[Core]);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_ResumeInterrupt(
+ IN gckOS Os
+ )
+{
+ return gckOS_ResumeInterruptEx(Os, gcvCORE_MAJOR);
+}
+
+gceSTATUS
+gckOS_ResumeInterruptEx(
+ IN gckOS Os,
+ IN gceCORE Core
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+
+ enable_irq(Os->device->irqLines[Core]);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_MemCopy(
+ IN gctPOINTER Destination,
+ IN gctCONST_POINTER Source,
+ IN gctSIZE_T Bytes
+ )
+{
+ gcmkHEADER_ARG("Destination=0x%X Source=0x%X Bytes=%lu",
+ Destination, Source, Bytes);
+
+ gcmkVERIFY_ARGUMENT(Destination != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Source != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+
+ memcpy(Destination, Source, Bytes);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_ZeroMemory(
+ IN gctPOINTER Memory,
+ IN gctSIZE_T Bytes
+ )
+{
+ gcmkHEADER_ARG("Memory=0x%X Bytes=%lu", Memory, Bytes);
+
+ gcmkVERIFY_ARGUMENT(Memory != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+
+ memset(Memory, 0, Bytes);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+********************************* Cache Control ********************************
+*******************************************************************************/
+
+/*******************************************************************************
+** gckOS_CacheClean
+**
+** Clean the cache for the specified addresses. The GPU is going to need the
+** data. If the system is allocating memory as non-cachable, this function can
+** be ignored.
+**
+** ARGUMENTS:
+**
+** gckOS Os
+** Pointer to gckOS object.
+**
+** gctUINT32 ProcessID
+** Process ID Logical belongs.
+**
+** gctPHYS_ADDR Handle
+** Physical address handle. If gcvNULL it is video memory.
+**
+** gctPOINTER Physical
+** Physical address to flush.
+**
+** gctPOINTER Logical
+** Logical address to flush.
+**
+** gctSIZE_T Bytes
+** Size of the address range in bytes to flush.
+*/
+
+/*
+
+Following patch can be applied to kernel in case cache API is not exported.
+
+diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c
+index 054b491..e9e74ec 100644
+--- a/arch/arm/mm/proc-syms.c
++++ b/arch/arm/mm/proc-syms.c
+@@ -30,6 +30,9 @@ EXPORT_SYMBOL(__cpuc_flush_user_all);
+ EXPORT_SYMBOL(__cpuc_flush_user_range);
+ EXPORT_SYMBOL(__cpuc_coherent_kern_range);
+ EXPORT_SYMBOL(__cpuc_flush_dcache_area);
++EXPORT_SYMBOL(__glue(_CACHE,_dma_map_area));
++EXPORT_SYMBOL(__glue(_CACHE,_dma_unmap_area));
++EXPORT_SYMBOL(__glue(_CACHE,_dma_flush_range));
+ #else
+ EXPORT_SYMBOL(cpu_cache);
+ #endif
+
+*/
+gceSTATUS
+gckOS_CacheClean(
+ IN gckOS Os,
+ IN gctUINT32 ProcessID,
+ IN gctPHYS_ADDR Handle,
+ IN gctPHYS_ADDR_T Physical,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ )
+{
+ gcsPLATFORM * platform;
+
+ gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=%p Bytes=%lu",
+ Os, ProcessID, Handle, Logical, Bytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+
+ platform = Os->device->platform;
+
+ if (platform && platform->ops->cache)
+ {
+ platform->ops->cache(
+ platform,
+ ProcessID,
+ Handle,
+ Physical,
+ Logical,
+ Bytes,
+ gcvCACHE_CLEAN
+ );
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+#if !gcdCACHE_FUNCTION_UNIMPLEMENTED
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+
+#if defined (CONFIG_ARM)
+ /* Inner cache. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
+ dmac_map_area(Logical, Bytes, DMA_TO_DEVICE);
+# else
+ dmac_clean_range(Logical, Logical + Bytes);
+# endif
+
+#elif defined(CONFIG_ARM64)
+ __dma_map_area(Logical, Bytes, DMA_TO_DEVICE);
+#endif
+
+#if defined(CONFIG_OUTER_CACHE)
+ /* Outer cache. */
+ _HandleOuterCache(Os, Physical, Logical, Bytes, gcvCACHE_CLEAN);
+#endif
+
+#elif defined(CONFIG_MIPS)
+ dma_cache_wback((unsigned long) Logical, Bytes);
+#elif defined(CONFIG_PPC)
+ flush_dcache_range((unsigned long)Logical, (unsigned long)Logical + Bytes);
+#else
+ dma_sync_single_for_device(
+ gcvNULL,
+ (dma_addr_t)Physical,
+ Bytes,
+ DMA_TO_DEVICE);
+#endif
+#endif
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+** gckOS_CacheInvalidate
+**
+** Invalidate the cache for the specified addresses. The GPU is going to need
+** data. If the system is allocating memory as non-cachable, this function can
+** be ignored.
+**
+** ARGUMENTS:
+**
+** gckOS Os
+** Pointer to gckOS object.
+**
+** gctUINT32 ProcessID
+** Process ID Logical belongs.
+**
+** gctPHYS_ADDR Handle
+** Physical address handle. If gcvNULL it is video memory.
+**
+** gctPOINTER Logical
+** Logical address to flush.
+**
+** gctSIZE_T Bytes
+** Size of the address range in bytes to flush.
+*/
+gceSTATUS
+gckOS_CacheInvalidate(
+ IN gckOS Os,
+ IN gctUINT32 ProcessID,
+ IN gctPHYS_ADDR Handle,
+ IN gctPHYS_ADDR_T Physical,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ )
+{
+ gcsPLATFORM * platform;
+
+ gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=%p Bytes=%lu",
+ Os, ProcessID, Handle, Logical, Bytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+
+ platform = Os->device->platform;
+
+ if (platform && platform->ops->cache)
+ {
+ platform->ops->cache(
+ platform,
+ ProcessID,
+ Handle,
+ Physical,
+ Logical,
+ Bytes,
+ gcvCACHE_INVALIDATE
+ );
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+#if !gcdCACHE_FUNCTION_UNIMPLEMENTED
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+
+#if defined (CONFIG_ARM)
+ /* Inner cache. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
+ dmac_unmap_area(Logical, Bytes, DMA_FROM_DEVICE);
+# else
+ dmac_inv_range(Logical, Logical + Bytes);
+# endif
+#elif defined(CONFIG_ARM64)
+ __dma_unmap_area(Logical, Bytes, DMA_FROM_DEVICE);
+#endif
+
+#if defined(CONFIG_OUTER_CACHE)
+ /* Outer cache. */
+ _HandleOuterCache(Os, Physical, Logical, Bytes, gcvCACHE_INVALIDATE);
+#endif
+
+#elif defined(CONFIG_MIPS)
+ dma_cache_inv((unsigned long) Logical, Bytes);
+#elif defined(CONFIG_PPC)
+ flush_dcache_range((unsigned long)Logical, (unsigned long)Logical + Bytes);
+#else
+ dma_sync_single_for_device(
+ gcvNULL,
+ (dma_addr_t)Physical,
+ Bytes,
+ DMA_FROM_DEVICE);
+#endif
+#endif
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+** gckOS_CacheFlush
+**
+** Clean the cache for the specified addresses and invalidate the lines as
+** well. The GPU is going to need and modify the data. If the system is
+** allocating memory as non-cachable, this function can be ignored.
+**
+** ARGUMENTS:
+**
+** gckOS Os
+** Pointer to gckOS object.
+**
+** gctUINT32 ProcessID
+** Process ID Logical belongs.
+**
+** gctPHYS_ADDR Handle
+** Physical address handle. If gcvNULL it is video memory.
+**
+** gctPOINTER Logical
+** Logical address to flush.
+**
+** gctSIZE_T Bytes
+** Size of the address range in bytes to flush.
+*/
+gceSTATUS
+gckOS_CacheFlush(
+ IN gckOS Os,
+ IN gctUINT32 ProcessID,
+ IN gctPHYS_ADDR Handle,
+ IN gctPHYS_ADDR_T Physical,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes
+ )
+{
+ gcsPLATFORM * platform;
+
+ gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=%p Bytes=%lu",
+ Os, ProcessID, Handle, Logical, Bytes);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Logical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Bytes > 0);
+
+ platform = Os->device->platform;
+
+ if (platform && platform->ops->cache)
+ {
+ platform->ops->cache(
+ platform,
+ ProcessID,
+ Handle,
+ Physical,
+ Logical,
+ Bytes,
+ gcvCACHE_FLUSH
+ );
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+#if !gcdCACHE_FUNCTION_UNIMPLEMENTED
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+#if defined (CONFIG_ARM)
+ /* Inner cache. */
+ dmac_flush_range(Logical, Logical + Bytes);
+#elif defined (CONFIG_ARM64)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
+ __dma_flush_area(Logical, Bytes);
+#else
+ __dma_flush_range(Logical, Logical + Bytes);
+#endif
+#endif
+
+#if defined(CONFIG_OUTER_CACHE)
+ /* Outer cache. */
+ _HandleOuterCache(Os, Physical, Logical, Bytes, gcvCACHE_FLUSH);
+#endif
+
+#elif defined(CONFIG_MIPS)
+ dma_cache_wback_inv((unsigned long) Logical, Bytes);
+#elif defined(CONFIG_PPC)
+ flush_dcache_range((unsigned long)Logical, (unsigned long)Logical + Bytes);
+#elif defined(CONFIG_X86)
+ wbinvd_on_all_cpus();
+#else
+ dma_sync_single_for_device(
+ gcvNULL,
+ (dma_addr_t)Physical,
+ Bytes,
+ DMA_BIDIRECTIONAL);
+#endif
+#endif
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+********************************* Broadcasting *********************************
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** gckOS_Broadcast
+**
+** System hook for broadcast events from the kernel driver.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to the gckOS object.
+**
+** gckHARDWARE Hardware
+** Pointer to the gckHARDWARE object.
+**
+** gceBROADCAST Reason
+** Reason for the broadcast. Can be one of the following values:
+**
+** gcvBROADCAST_GPU_IDLE
+** Broadcasted when the kernel driver thinks the GPU might be
+** idle. This can be used to handle power management.
+**
+** gcvBROADCAST_GPU_COMMIT
+** Broadcasted when any client process commits a command
+** buffer. This can be used to handle power management.
+**
+** gcvBROADCAST_GPU_STUCK
+** Broadcasted when the kernel driver hits the timeout waiting
+** for the GPU.
+**
+** gcvBROADCAST_FIRST_PROCESS
+** First process is trying to connect to the kernel.
+**
+** gcvBROADCAST_LAST_PROCESS
+** Last process has detached from the kernel.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_Broadcast(
+ IN gckOS Os,
+ IN gckHARDWARE Hardware,
+ IN gceBROADCAST Reason
+ )
+{
+ gceSTATUS status;
+#if gcdPOWER_SUSPEND_WHEN_IDLE
+ gceCHIPPOWERSTATE state = gcvPOWER_SUSPEND_BROADCAST;
+#else
+ gceCHIPPOWERSTATE state = gcvPOWER_IDLE_BROADCAST;
+#endif
+
+ gcmkHEADER_ARG("Os=0x%X Hardware=0x%X Reason=%d", Os, Hardware, Reason);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ switch (Reason)
+ {
+ case gcvBROADCAST_FIRST_PROCESS:
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "First process has attached");
+ break;
+
+ case gcvBROADCAST_LAST_PROCESS:
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "Last process has detached");
+
+ /* Put GPU OFF. */
+ gcmkONERROR(
+ gckHARDWARE_SetPowerManagementState(Hardware,
+ gcvPOWER_OFF_BROADCAST));
+ break;
+
+ case gcvBROADCAST_GPU_IDLE:
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "GPU idle.");
+
+ /* Put GPU IDLE. */
+ gcmkONERROR(
+ gckHARDWARE_SetPowerManagementState(Hardware, state));
+
+ /* Add idle process DB. */
+ gcmkONERROR(gckKERNEL_AddProcessDB(Hardware->kernel,
+ 1,
+ gcvDB_IDLE,
+ gcvNULL, gcvNULL, 0));
+ break;
+
+ case gcvBROADCAST_GPU_COMMIT:
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "COMMIT has arrived.");
+
+ /* Add busy process DB. */
+ gcmkONERROR(gckKERNEL_AddProcessDB(Hardware->kernel,
+ 0,
+ gcvDB_IDLE,
+ gcvNULL, gcvNULL, 0));
+
+ /* Put GPU ON. */
+ gcmkONERROR(
+ gckHARDWARE_SetPowerManagementState(Hardware, gcvPOWER_ON_AUTO));
+ break;
+
+ case gcvBROADCAST_GPU_STUCK:
+ gcmkTRACE_N(gcvLEVEL_ERROR, 0, "gcvBROADCAST_GPU_STUCK\n");
+ gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel));
+ break;
+
+ case gcvBROADCAST_AXI_BUS_ERROR:
+ gcmkTRACE_N(gcvLEVEL_ERROR, 0, "gcvBROADCAST_AXI_BUS_ERROR\n");
+ gcmkONERROR(gckHARDWARE_DumpGPUState(Hardware));
+ gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel));
+ break;
+
+ case gcvBROADCAST_OUT_OF_MEMORY:
+ gcmkTRACE_N(gcvLEVEL_INFO, 0, "gcvBROADCAST_OUT_OF_MEMORY\n");
+
+ status = _ShrinkMemory(Os);
+
+ if (status == gcvSTATUS_NOT_SUPPORTED)
+ {
+ goto OnError;
+ }
+
+ gcmkONERROR(status);
+
+ break;
+
+ default:
+ /* Skip unimplemented broadcast. */
+ break;
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_BroadcastHurry
+**
+** The GPU is running too slow.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to the gckOS object.
+**
+** gckHARDWARE Hardware
+** Pointer to the gckHARDWARE object.
+**
+** gctUINT Urgency
+** The higher the number, the higher the urgency to speed up the GPU.
+** The maximum value is defined by the gcdDYNAMIC_EVENT_THRESHOLD.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_BroadcastHurry(
+ IN gckOS Os,
+ IN gckHARDWARE Hardware,
+ IN gctUINT Urgency
+ )
+{
+ gcmkHEADER_ARG("Os=0x%x Hardware=0x%x Urgency=%u", Os, Hardware, Urgency);
+
+ /* Do whatever you need to do to speed up the GPU now. */
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_BroadcastCalibrateSpeed
+**
+** Calibrate the speed of the GPU.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to the gckOS object.
+**
+** gckHARDWARE Hardware
+** Pointer to the gckHARDWARE object.
+**
+** gctUINT Idle, Time
+** Idle/Time will give the percentage the GPU is idle, so you can use
+** this to calibrate the working point of the GPU.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_BroadcastCalibrateSpeed(
+ IN gckOS Os,
+ IN gckHARDWARE Hardware,
+ IN gctUINT Idle,
+ IN gctUINT Time
+ )
+{
+ gcmkHEADER_ARG("Os=0x%x Hardware=0x%x Idle=%u Time=%u",
+ Os, Hardware, Idle, Time);
+
+ /* Do whatever you need to do to callibrate the GPU speed. */
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+********************************** Semaphores **********************************
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** gckOS_CreateSemaphore
+**
+** Create a semaphore.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to the gckOS object.
+**
+** OUTPUT:
+**
+** gctPOINTER * Semaphore
+** Pointer to the variable that will receive the created semaphore.
+*/
+gceSTATUS
+gckOS_CreateSemaphore(
+ IN gckOS Os,
+ OUT gctPOINTER * Semaphore
+ )
+{
+ gceSTATUS status;
+ struct semaphore *sem = gcvNULL;
+
+ gcmkHEADER_ARG("Os=0x%X", Os);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
+
+ /* Allocate the semaphore structure. */
+ sem = (struct semaphore *)kmalloc(gcmSIZEOF(struct semaphore), GFP_KERNEL | gcdNOWARN);
+ if (sem == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ /* Initialize the semaphore. */
+ sema_init(sem, 1);
+
+ /* Return to caller. */
+ *Semaphore = (gctPOINTER) sem;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_AcquireSemaphore
+**
+** Acquire a semaphore.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to the gckOS object.
+**
+** gctPOINTER Semaphore
+** Pointer to the semaphore thet needs to be acquired.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_AcquireSemaphore(
+ IN gckOS Os,
+ IN gctPOINTER Semaphore
+ )
+{
+ gcmkHEADER_ARG("Os=0x%08X Semaphore=0x%08X", Os, Semaphore);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
+
+ /* Acquire the semaphore. */
+ down((struct semaphore *) Semaphore);
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_TryAcquireSemaphore
+**
+** Try to acquire a semaphore.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to the gckOS object.
+**
+** gctPOINTER Semaphore
+** Pointer to the semaphore thet needs to be acquired.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_TryAcquireSemaphore(
+ IN gckOS Os,
+ IN gctPOINTER Semaphore
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Os=0x%x", Os);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
+
+ /* Acquire the semaphore. */
+ if (down_trylock((struct semaphore *) Semaphore))
+ {
+ /* Timeout. */
+ status = gcvSTATUS_TIMEOUT;
+ gcmkFOOTER();
+ return status;
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_ReleaseSemaphore
+**
+** Release a previously acquired semaphore.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to the gckOS object.
+**
+** gctPOINTER Semaphore
+** Pointer to the semaphore thet needs to be released.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_ReleaseSemaphore(
+ IN gckOS Os,
+ IN gctPOINTER Semaphore
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Semaphore=0x%X", Os, Semaphore);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
+
+ /* Release the semaphore. */
+ up((struct semaphore *) Semaphore);
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_DestroySemaphore
+**
+** Destroy a semaphore.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to the gckOS object.
+**
+** gctPOINTER Semaphore
+** Pointer to the semaphore thet needs to be destroyed.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_DestroySemaphore(
+ IN gckOS Os,
+ IN gctPOINTER Semaphore
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Semaphore=0x%X", Os, Semaphore);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
+
+ /* Free the sempahore structure. */
+ kfree(Semaphore);
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_GetProcessID
+**
+** Get current process ID.
+**
+** INPUT:
+**
+** Nothing.
+**
+** OUTPUT:
+**
+** gctUINT32_PTR ProcessID
+** Pointer to the variable that receives the process ID.
+*/
+gceSTATUS
+gckOS_GetProcessID(
+ OUT gctUINT32_PTR ProcessID
+ )
+{
+ /* Get process ID. */
+ *ProcessID = _GetProcessID();
+
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_GetThreadID
+**
+** Get current thread ID.
+**
+** INPUT:
+**
+** Nothing.
+**
+** OUTPUT:
+**
+** gctUINT32_PTR ThreadID
+** Pointer to the variable that receives the thread ID.
+*/
+gceSTATUS
+gckOS_GetThreadID(
+ OUT gctUINT32_PTR ThreadID
+ )
+{
+ /* Get thread ID. */
+ if (ThreadID != gcvNULL)
+ {
+ *ThreadID = _GetThreadID();
+ }
+
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_SetGPUPower
+**
+** Set the power of the GPU on or off.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gceCORE Core
+** GPU whose power is set.
+**
+** gctBOOL Clock
+** gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock.
+**
+** gctBOOL Power
+** gcvTRUE to turn on the power, or gcvFALSE to turn off the power.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_SetGPUPower(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctBOOL Clock,
+ IN gctBOOL Power
+ )
+{
+ gcsPLATFORM * platform;
+
+ gctBOOL powerChange = gcvFALSE;
+ gctBOOL clockChange = gcvFALSE;
+
+ gcmkHEADER_ARG("Os=0x%X Core=%d Clock=%d Power=%d", Os, Core, Clock, Power);
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+
+ platform = Os->device->platform;
+
+ powerChange = (Power != Os->powerStates[Core]);
+
+ clockChange = (Clock != Os->clockStates[Core]);
+
+ if (powerChange && (Power == gcvTRUE))
+ {
+ if (platform && platform->ops->setPower)
+ {
+ gcmkVERIFY_OK(platform->ops->setPower(platform, Core, Power));
+ }
+
+ Os->powerStates[Core] = Power;
+ }
+
+ if (clockChange)
+ {
+ unsigned long flags;
+
+ if (!Clock)
+ {
+ spin_lock_irqsave(&Os->registerAccessLock, flags);
+
+ /* Record clock off, ahead. */
+ Os->clockStates[Core] = gcvFALSE;
+
+ spin_unlock_irqrestore(&Os->registerAccessLock, flags);
+ }
+
+ if (platform && platform->ops->setClock)
+ {
+ gcmkVERIFY_OK(platform->ops->setClock(platform, Core, Clock));
+ }
+
+ if (Clock)
+ {
+ spin_lock_irqsave(&Os->registerAccessLock, flags);
+
+ /* Record clock on, behind. */
+ Os->clockStates[Core] = gcvTRUE;
+
+ spin_unlock_irqrestore(&Os->registerAccessLock, flags);
+ }
+ }
+
+ if (powerChange && (Power == gcvFALSE))
+ {
+ if (platform && platform->ops->setPower)
+ {
+ gcmkVERIFY_OK(platform->ops->setPower(platform, Core, Power));
+ }
+
+ Os->powerStates[Core] = Power;
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_ResetGPU
+**
+** Reset the GPU.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gckCORE Core
+** GPU whose power is set.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_ResetGPU(
+ IN gckOS Os,
+ IN gceCORE Core
+ )
+{
+ gceSTATUS status = gcvSTATUS_NOT_SUPPORTED;
+ gcsPLATFORM * platform;
+
+ gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core);
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+
+ platform = Os->device->platform;
+
+ if (platform && platform->ops->reset)
+ {
+ status = platform->ops->reset(platform, Core);
+ }
+
+ gcmkFOOTER_NO();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_PrepareGPUFrequency
+**
+** Prepare to set GPU frequency and voltage.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gckCORE Core
+** GPU whose frequency and voltage will be set.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_PrepareGPUFrequency(
+ IN gckOS Os,
+ IN gceCORE Core
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_FinishGPUFrequency
+**
+** Finish GPU frequency setting.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gckCORE Core
+** GPU whose frequency and voltage is set.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_FinishGPUFrequency(
+ IN gckOS Os,
+ IN gceCORE Core
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_QueryGPUFrequency
+**
+** Query the current frequency of the GPU.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gckCORE Core
+** GPU whose power is set.
+**
+** gctUINT32 * Frequency
+** Pointer to a gctUINT32 to obtain current frequency, in MHz.
+**
+** gctUINT8 * Scale
+** Pointer to a gctUINT8 to obtain current scale(1 - 64).
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_QueryGPUFrequency(
+ IN gckOS Os,
+ IN gceCORE Core,
+ OUT gctUINT32 * Frequency,
+ OUT gctUINT8 * Scale
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_SetGPUFrequency
+**
+** Set frequency and voltage of the GPU.
+**
+** 1. DVFS manager gives the target scale of full frequency, BSP must find
+** a real frequency according to this scale and board's configure.
+**
+** 2. BSP should find a suitable voltage for this frequency.
+**
+** 3. BSP must make sure setting take effect before this function returns.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to a gckOS object.
+**
+** gckCORE Core
+** GPU whose power is set.
+**
+** gctUINT8 Scale
+** Target scale of full frequency, range is [1, 64]. 1 means 1/64 of
+** full frequency and 64 means 64/64 of full frequency.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_SetGPUFrequency(
+ IN gckOS Os,
+ IN gceCORE Core,
+ IN gctUINT8 Scale
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+/*----------------------------------------------------------------------------*/
+/*----- Profile --------------------------------------------------------------*/
+
+gceSTATUS
+gckOS_GetProfileTick(
+ OUT gctUINT64_PTR Tick
+ )
+{
+ struct timespec time;
+
+ ktime_get_ts(&time);
+
+ *Tick = time.tv_nsec + time.tv_sec * 1000000000ULL;
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_QueryProfileTickRate(
+ OUT gctUINT64_PTR TickRate
+ )
+{
+ struct timespec res;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ res.tv_sec = 0;
+ res.tv_nsec = hrtimer_resolution;
+#else
+ hrtimer_get_res(CLOCK_MONOTONIC, &res);
+#endif
+
+ *TickRate = res.tv_nsec + res.tv_sec * 1000000000ULL;
+
+ return gcvSTATUS_OK;
+}
+
+gctUINT32
+gckOS_ProfileToMS(
+ IN gctUINT64 Ticks
+ )
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23)
+ return div_u64(Ticks, 1000000);
+#else
+ gctUINT64 rem = Ticks;
+ gctUINT64 b = 1000000;
+ gctUINT64 res, d = 1;
+ gctUINT32 high = rem >> 32;
+
+ /* Reduce the thing a bit first */
+ res = 0;
+ if (high >= 1000000)
+ {
+ high /= 1000000;
+ res = (gctUINT64) high << 32;
+ rem -= (gctUINT64) (high * 1000000) << 32;
+ }
+
+ while (((gctINT64) b > 0) && (b < rem))
+ {
+ b <<= 1;
+ d <<= 1;
+ }
+
+ do
+ {
+ if (rem >= b)
+ {
+ rem -= b;
+ res += d;
+ }
+
+ b >>= 1;
+ d >>= 1;
+ }
+ while (d);
+
+ return (gctUINT32) res;
+#endif
+}
+
+/******************************************************************************\
+******************************* Signal Management ******************************
+\******************************************************************************/
+
+#undef _GC_OBJ_ZONE
+#define _GC_OBJ_ZONE gcvZONE_SIGNAL
+
+/*******************************************************************************
+**
+** gckOS_CreateSignal
+**
+** Create a new signal.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctBOOL ManualReset
+** If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in
+** order to set the signal to nonsignaled state.
+** If set to gcvFALSE, the signal will automatically be set to
+** nonsignaled state by gckOS_WaitSignal function.
+**
+** OUTPUT:
+**
+** gctSIGNAL * Signal
+** Pointer to a variable receiving the created gctSIGNAL.
+*/
+gceSTATUS
+gckOS_CreateSignal(
+ IN gckOS Os,
+ IN gctBOOL ManualReset,
+ OUT gctSIGNAL * Signal
+ )
+{
+ gceSTATUS status;
+ gcsSIGNAL_PTR signal;
+
+ gcmkHEADER_ARG("Os=0x%X ManualReset=%d", Os, ManualReset);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
+
+ /* Create an event structure. */
+ signal = (gcsSIGNAL_PTR) kmalloc(sizeof(gcsSIGNAL), GFP_KERNEL | gcdNOWARN);
+
+ if (signal == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ /* Save the process ID. */
+ signal->process = (gctHANDLE)(gctUINTPTR_T) _GetProcessID();
+
+ signal->done = 0;
+ init_waitqueue_head(&signal->wait);
+ spin_lock_init(&signal->lock);
+ signal->manualReset = ManualReset;
+
+ atomic_set(&signal->ref, 1);
+
+#if gcdANDROID_NATIVE_FENCE_SYNC
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
+ signal->timeline = gcvNULL;
+# else
+ signal->fence = gcvNULL;
+# endif
+#endif
+
+ gcmkONERROR(_AllocateIntegerId(&Os->signalDB, signal, &signal->id));
+
+ *Signal = (gctSIGNAL)(gctUINTPTR_T)signal->id;
+
+ gcmkFOOTER_ARG("*Signal=0x%X", *Signal);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (signal != gcvNULL)
+ {
+ kfree(signal);
+ }
+
+ gcmkFOOTER_NO();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_DestroySignal
+**
+** Destroy a signal.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctSIGNAL Signal
+** Pointer to the gctSIGNAL.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_DestroySignal(
+ IN gckOS Os,
+ IN gctSIGNAL Signal
+ )
+{
+ gceSTATUS status;
+ gcsSIGNAL_PTR signal;
+ gctBOOL acquired = gcvFALSE;
+
+ gcmkHEADER_ARG("Os=0x%X Signal=0x%X", Os, Signal);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
+
+ mutex_lock(&Os->signalMutex);
+ acquired = gcvTRUE;
+
+ gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
+
+ gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
+
+ if (atomic_dec_and_test(&signal->ref))
+ {
+ gcmkVERIFY_OK(_DestroyIntegerId(&Os->signalDB, signal->id));
+
+ /* Free the sgianl. */
+ kfree(signal);
+ }
+
+ mutex_unlock(&Os->signalMutex);
+ acquired = gcvFALSE;
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ if (acquired)
+ {
+ /* Release the mutex. */
+ mutex_unlock(&Os->signalMutex);
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_Signal
+**
+** Set a state of the specified signal.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctSIGNAL Signal
+** Pointer to the gctSIGNAL.
+**
+** gctBOOL State
+** If gcvTRUE, the signal will be set to signaled state.
+** If gcvFALSE, the signal will be set to nonsignaled state.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_Signal(
+ IN gckOS Os,
+ IN gctSIGNAL Signal,
+ IN gctBOOL State
+ )
+{
+ gceSTATUS status;
+ gcsSIGNAL_PTR signal;
+#if gcdANDROID_NATIVE_FENCE_SYNC
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
+ struct sync_timeline * timeline = gcvNULL;
+# else
+ struct fence * fence = gcvNULL;
+# endif
+#endif
+
+ gcmkHEADER_ARG("Os=0x%X Signal=0x%X State=%d", Os, Signal, State);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
+
+ mutex_lock(&Os->signalMutex);
+
+ status = _QueryIntegerId(&Os->signalDB,
+ (gctUINT32)(gctUINTPTR_T)Signal,
+ (gctPOINTER)&signal);
+
+ if (gcmIS_ERROR(status))
+ {
+ mutex_unlock(&Os->signalMutex);
+ gcmkONERROR(status);
+ }
+
+ /*
+ * Signal saved in event is not referenced. Inc reference here to avoid
+ * concurrent issue: signaling the signal while another thread is destroying
+ * it.
+ */
+ atomic_inc(&signal->ref);
+
+ mutex_unlock(&Os->signalMutex);
+
+ gcmkONERROR(status);
+
+ gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
+
+ spin_lock(&signal->lock);
+
+ if (State)
+ {
+ signal->done = 1;
+
+ wake_up(&signal->wait);
+
+#if gcdANDROID_NATIVE_FENCE_SYNC
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
+ timeline = signal->timeline;
+# else
+ fence = signal->fence;
+ signal->fence = NULL;
+# endif
+#endif
+ }
+ else
+ {
+ signal->done = 0;
+ }
+
+ spin_unlock(&signal->lock);
+
+#if gcdANDROID_NATIVE_FENCE_SYNC
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
+ /* Signal timeline. */
+ if (timeline)
+ {
+ sync_timeline_signal(timeline);
+ }
+# else
+ if (fence)
+ {
+ fence_signal(fence);
+ fence_put(fence);
+ }
+# endif
+#endif
+
+ mutex_lock(&Os->signalMutex);
+
+ if (atomic_dec_and_test(&signal->ref))
+ {
+ gcmkVERIFY_OK(_DestroyIntegerId(&Os->signalDB, signal->id));
+
+ /* Free the sgianl. */
+ kfree(signal);
+ }
+
+ mutex_unlock(&Os->signalMutex);
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_UserSignal
+**
+** Set the specified signal which is owned by a process to signaled state.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctSIGNAL Signal
+** Pointer to the gctSIGNAL.
+**
+** gctHANDLE Process
+** Handle of process owning the signal.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_UserSignal(
+ IN gckOS Os,
+ IN gctSIGNAL Signal,
+ IN gctHANDLE Process
+ )
+{
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Os=0x%X Signal=0x%X Process=%d",
+ Os, Signal, (gctINT32)(gctUINTPTR_T)Process);
+
+ /* Signal. */
+ status = gckOS_Signal(Os, Signal, gcvTRUE);
+
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_WaitSignal
+**
+** Wait for a signal to become signaled.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctSIGNAL Signal
+** Pointer to the gctSIGNAL.
+**
+** gctUINT32 Wait
+** Number of milliseconds to wait.
+** Pass the value of gcvINFINITE for an infinite wait.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_WaitSignal(
+ IN gckOS Os,
+ IN gctSIGNAL Signal,
+ IN gctBOOL Interruptable,
+ IN gctUINT32 Wait
+ )
+{
+ gceSTATUS status;
+ gcsSIGNAL_PTR signal;
+ int done;
+
+ gcmkHEADER_ARG("Os=0x%X Signal=0x%X Wait=0x%08X", Os, Signal, Wait);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
+
+ gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
+
+ gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal);
+
+ spin_lock(&signal->lock);
+ done = signal->done;
+ spin_unlock(&signal->lock);
+
+ /*
+ * Do not need to lock below:
+ * 1. If signal already done, return immediately.
+ * 2. If signal not done, wait_event_xxx will handle correctly even read of
+ * signal->done is not atomic.
+ *
+ * Rest signal->done do not require lock either:
+ * No other thread can query/wait auto-reseted signal, because that is
+ * logic error.
+ */
+ if (done)
+ {
+ status = gcvSTATUS_OK;
+
+ if (!signal->manualReset)
+ {
+ signal->done = 0;
+ }
+ }
+ else if (Wait == 0)
+ {
+ status = gcvSTATUS_TIMEOUT;
+ }
+ else
+ {
+ /* Convert wait to milliseconds. */
+ long timeout = (Wait == gcvINFINITE)
+ ? MAX_SCHEDULE_TIMEOUT
+ : msecs_to_jiffies(Wait);
+
+ long ret;
+
+ if (Interruptable)
+ {
+ ret = wait_event_interruptible_timeout(signal->wait, signal->done, timeout);
+ }
+ else
+ {
+ ret = wait_event_timeout(signal->wait, signal->done, timeout);
+ }
+
+ if (likely(ret > 0))
+ {
+ status = gcvSTATUS_OK;
+
+ if (!signal->manualReset)
+ {
+ /* Auto reset. */
+ signal->done = 0;
+ }
+ }
+ else
+ {
+ status = (ret == -ERESTARTSYS) ? gcvSTATUS_INTERRUPTED
+ : gcvSTATUS_TIMEOUT;
+ }
+ }
+
+OnError:
+ /* Return status. */
+ gcmkFOOTER_ARG("Signal=0x%lX status=%d", Signal, status);
+ return status;
+}
+
+gceSTATUS
+_QuerySignal(
+ IN gckOS Os,
+ IN gctSIGNAL Signal
+ )
+{
+ /*
+ * This function is called by 'has_signaled' callback of sync_timeline.
+ * By design, 'has_signaled' could be called in interrupt context, but
+ * in current driver, it can be called only when 'gckOS_Signal' and
+ * 'gckOS_CreateNativeFence'. Thus its safe to use normal version of
+ * spinlock for 'Os->signalDB.lock' and 'signal->obj.wait.lock'.
+ */
+ gceSTATUS status;
+ gcsSIGNAL_PTR signal = gcvNULL;
+
+ status = _QueryIntegerId(&Os->signalDB,
+ (gctUINT32)(gctUINTPTR_T)Signal,
+ (gctPOINTER)&signal);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ spin_lock(&signal->lock);
+ status = signal->done ? gcvSTATUS_TRUE : gcvSTATUS_FALSE;
+ spin_unlock(&signal->lock);
+ }
+
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_MapSignal
+**
+** Map a signal in to the current process space.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctSIGNAL Signal
+** Pointer to tha gctSIGNAL to map.
+**
+** gctHANDLE Process
+** Handle of process owning the signal.
+**
+** OUTPUT:
+**
+** gctSIGNAL * MappedSignal
+** Pointer to a variable receiving the mapped gctSIGNAL.
+*/
+gceSTATUS
+gckOS_MapSignal(
+ IN gckOS Os,
+ IN gctSIGNAL Signal,
+ IN gctHANDLE Process,
+ OUT gctSIGNAL * MappedSignal
+ )
+{
+ gceSTATUS status;
+ gcsSIGNAL_PTR signal = gcvNULL;
+ gcmkHEADER_ARG("Os=0x%X Signal=0x%X Process=0x%X", Os, Signal, Process);
+
+ gcmkVERIFY_ARGUMENT(Signal != gcvNULL);
+ gcmkVERIFY_ARGUMENT(MappedSignal != gcvNULL);
+
+ mutex_lock(&Os->signalMutex);
+
+ gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal));
+
+ if (atomic_inc_return(&signal->ref) <= 1)
+ {
+ /* The previous value is 0, it has been deleted. */
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ *MappedSignal = (gctSIGNAL) Signal;
+
+ mutex_unlock(&Os->signalMutex);
+
+ /* Success. */
+ gcmkFOOTER_ARG("*MappedSignal=0x%X", *MappedSignal);
+ return gcvSTATUS_OK;
+
+OnError:
+ mutex_unlock(&Os->signalMutex);
+
+ gcmkFOOTER_NO();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_UnmapSignal
+**
+** Unmap a signal .
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctSIGNAL Signal
+** Pointer to that gctSIGNAL mapped.
+*/
+gceSTATUS
+gckOS_UnmapSignal(
+ IN gckOS Os,
+ IN gctSIGNAL Signal
+ )
+{
+ return gckOS_DestroySignal(Os, Signal);
+}
+
+/*******************************************************************************
+**
+** gckOS_CreateUserSignal
+**
+** Create a new signal to be used in the user space.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctBOOL ManualReset
+** If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in
+** order to set the signal to nonsignaled state.
+** If set to gcvFALSE, the signal will automatically be set to
+** nonsignaled state by gckOS_WaitSignal function.
+**
+** OUTPUT:
+**
+** gctINT * SignalID
+** Pointer to a variable receiving the created signal's ID.
+*/
+gceSTATUS
+gckOS_CreateUserSignal(
+ IN gckOS Os,
+ IN gctBOOL ManualReset,
+ OUT gctINT * SignalID
+ )
+{
+ gceSTATUS status;
+ gctSIZE_T signal;
+
+ /* Create a new signal. */
+ gcmkONERROR(gckOS_CreateSignal(Os, ManualReset, (gctSIGNAL *) &signal));
+ *SignalID = (gctINT) signal;
+
+OnError:
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_DestroyUserSignal
+**
+** Destroy a signal to be used in the user space.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctINT SignalID
+** The signal's ID.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_DestroyUserSignal(
+ IN gckOS Os,
+ IN gctINT SignalID
+ )
+{
+ return gckOS_DestroySignal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID);
+}
+
+/*******************************************************************************
+**
+** gckOS_WaitUserSignal
+**
+** Wait for a signal used in the user mode to become signaled.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctINT SignalID
+** Signal ID.
+**
+** gctUINT32 Wait
+** Number of milliseconds to wait.
+** Pass the value of gcvINFINITE for an infinite wait.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_WaitUserSignal(
+ IN gckOS Os,
+ IN gctINT SignalID,
+ IN gctUINT32 Wait
+ )
+{
+ return gckOS_WaitSignal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID, gcvTRUE, Wait);
+}
+
+/*******************************************************************************
+**
+** gckOS_SignalUserSignal
+**
+** Set a state of the specified signal to be used in the user space.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctINT SignalID
+** SignalID.
+**
+** gctBOOL State
+** If gcvTRUE, the signal will be set to signaled state.
+** If gcvFALSE, the signal will be set to nonsignaled state.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_SignalUserSignal(
+ IN gckOS Os,
+ IN gctINT SignalID,
+ IN gctBOOL State
+ )
+{
+ return gckOS_Signal(Os, (gctSIGNAL)(gctUINTPTR_T)SignalID, State);
+}
+
+#if gcdENABLE_VG
+gceSTATUS
+gckOS_CreateSemaphoreVG(
+ IN gckOS Os,
+ OUT gctSEMAPHORE * Semaphore
+ )
+{
+ gceSTATUS status;
+ struct semaphore * newSemaphore;
+
+ gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
+
+ do
+ {
+ /* Allocate the semaphore structure. */
+ newSemaphore = (struct semaphore *)kmalloc(gcmSIZEOF(struct semaphore), GFP_KERNEL | gcdNOWARN);
+ if (newSemaphore == gcvNULL)
+ {
+ gcmkERR_BREAK(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ /* Initialize the semaphore. */
+ sema_init(newSemaphore, 0);
+
+ /* Set the handle. */
+ * Semaphore = (gctSEMAPHORE) newSemaphore;
+
+ /* Success. */
+ status = gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ gcmkFOOTER();
+ /* Return the status. */
+ return status;
+}
+
+
+gceSTATUS
+gckOS_IncrementSemaphore(
+ IN gckOS Os,
+ IN gctSEMAPHORE Semaphore
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
+
+ /* Increment the semaphore's count. */
+ up((struct semaphore *) Semaphore);
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_DecrementSemaphore(
+ IN gckOS Os,
+ IN gctSEMAPHORE Semaphore
+ )
+{
+ gceSTATUS status;
+ gctINT result;
+
+ gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL);
+
+ do
+ {
+ /* Decrement the semaphore's count. If the count is zero, wait
+ until it gets incremented. */
+ result = down_interruptible((struct semaphore *) Semaphore);
+
+ /* Signal received? */
+ if (result != 0)
+ {
+ status = gcvSTATUS_TERMINATE;
+ break;
+ }
+
+ /* Success. */
+ status = gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ gcmkFOOTER();
+ /* Return the status. */
+ return status;
+}
+
+/******************************************************************************\
+******************************** Thread Object *********************************
+\******************************************************************************/
+
+gceSTATUS
+gckOS_StartThread(
+ IN gckOS Os,
+ IN gctTHREADFUNC ThreadFunction,
+ IN gctPOINTER ThreadParameter,
+ OUT gctTHREAD * Thread
+ )
+{
+ gceSTATUS status;
+ struct task_struct * thread;
+
+ gcmkHEADER_ARG("Os=0x%X ", Os);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(ThreadFunction != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
+
+ do
+ {
+ /* Create the thread. */
+ thread = kthread_create(
+ ThreadFunction,
+ ThreadParameter,
+ "Vivante Kernel Thread"
+ );
+
+ /* Failed? */
+ if (IS_ERR(thread))
+ {
+ status = gcvSTATUS_GENERIC_IO;
+ break;
+ }
+
+ /* Start the thread. */
+ wake_up_process(thread);
+
+ /* Set the thread handle. */
+ * Thread = (gctTHREAD) thread;
+
+ /* Success. */
+ status = gcvSTATUS_OK;
+ }
+ while (gcvFALSE);
+
+ gcmkFOOTER();
+ /* Return the status. */
+ return status;
+}
+
+gceSTATUS
+gckOS_StopThread(
+ IN gckOS Os,
+ IN gctTHREAD Thread
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Thread=0x%x", Os, Thread);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
+
+ /* Thread should have already been enabled to terminate. */
+ kthread_stop((struct task_struct *) Thread);
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_VerifyThread(
+ IN gckOS Os,
+ IN gctTHREAD Thread
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X Thread=0x%x", Os, Thread);
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Thread != gcvNULL);
+
+ gcmkFOOTER_NO();
+ /* Success. */
+ return gcvSTATUS_OK;
+}
+#endif
+
+/******************************************************************************\
+******************************** Software Timer ********************************
+\******************************************************************************/
+
+void
+_TimerFunction(
+ struct work_struct * work
+ )
+{
+ gcsOSTIMER_PTR timer = (gcsOSTIMER_PTR)work;
+
+ gctTIMERFUNCTION function = timer->function;
+
+ function(timer->data);
+}
+
+/*******************************************************************************
+**
+** gckOS_CreateTimer
+**
+** Create a software timer.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to the gckOS object.
+**
+** gctTIMERFUNCTION Function.
+** Pointer to a call back function which will be called when timer is
+** expired.
+**
+** gctPOINTER Data.
+** Private data which will be passed to call back function.
+**
+** OUTPUT:
+**
+** gctPOINTER * Timer
+** Pointer to a variable receiving the created timer.
+*/
+gceSTATUS
+gckOS_CreateTimer(
+ IN gckOS Os,
+ IN gctTIMERFUNCTION Function,
+ IN gctPOINTER Data,
+ OUT gctPOINTER * Timer
+ )
+{
+ gceSTATUS status;
+ gcsOSTIMER_PTR pointer;
+ gcmkHEADER_ARG("Os=0x%X Function=0x%X Data=0x%X", Os, Function, Data);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
+
+ gcmkONERROR(gckOS_Allocate(Os, sizeof(gcsOSTIMER), (gctPOINTER)&pointer));
+
+ pointer->function = Function;
+ pointer->data = Data;
+
+ INIT_DELAYED_WORK(&pointer->work, _TimerFunction);
+
+ *Timer = pointer;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_DestroyTimer
+**
+** Destory a software timer.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to the gckOS object.
+**
+** gctPOINTER Timer
+** Pointer to the timer to be destoryed.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_DestroyTimer(
+ IN gckOS Os,
+ IN gctPOINTER Timer
+ )
+{
+ gcsOSTIMER_PTR timer;
+ gcmkHEADER_ARG("Os=0x%X Timer=0x%X", Os, Timer);
+
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
+
+ timer = (gcsOSTIMER_PTR)Timer;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
+ cancel_delayed_work_sync(&timer->work);
+#else
+ cancel_delayed_work(&timer->work);
+ flush_workqueue(Os->workqueue);
+#endif
+
+ gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, Timer));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_StartTimer
+**
+** Schedule a software timer.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to the gckOS object.
+**
+** gctPOINTER Timer
+** Pointer to the timer to be scheduled.
+**
+** gctUINT32 Delay
+** Delay in milliseconds.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_StartTimer(
+ IN gckOS Os,
+ IN gctPOINTER Timer,
+ IN gctUINT32 Delay
+ )
+{
+ gcsOSTIMER_PTR timer;
+
+ gcmkHEADER_ARG("Os=0x%X Timer=0x%X Delay=%u", Os, Timer, Delay);
+
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
+ gcmkVERIFY_ARGUMENT(Delay != 0);
+
+ timer = (gcsOSTIMER_PTR)Timer;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
+ mod_delayed_work(Os->workqueue, &timer->work, msecs_to_jiffies(Delay));
+#else
+ if (unlikely(delayed_work_pending(&timer->work)))
+ {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
+ cancel_delayed_work_sync(&timer->work);
+#else
+ cancel_delayed_work(&timer->work);
+ flush_workqueue(Os->workqueue);
+#endif
+ }
+
+ queue_delayed_work(Os->workqueue, &timer->work, msecs_to_jiffies(Delay));
+#endif
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_StopTimer
+**
+** Cancel a unscheduled timer.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to the gckOS object.
+**
+** gctPOINTER Timer
+** Pointer to the timer to be cancel.
+**
+** OUTPUT:
+**
+** Nothing.
+*/
+gceSTATUS
+gckOS_StopTimer(
+ IN gckOS Os,
+ IN gctPOINTER Timer
+ )
+{
+ gcsOSTIMER_PTR timer;
+ gcmkHEADER_ARG("Os=0x%X Timer=0x%X", Os, Timer);
+
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Timer != gcvNULL);
+
+ timer = (gcsOSTIMER_PTR)Timer;
+
+ cancel_delayed_work(&timer->work);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_GetProcessNameByPid(
+ IN gctINT Pid,
+ IN gctSIZE_T Length,
+ OUT gctUINT8_PTR String
+ )
+{
+ struct task_struct *task;
+
+ /* Get the task_struct of the task with pid. */
+ rcu_read_lock();
+
+ task = FIND_TASK_BY_PID(Pid);
+
+ if (task == gcvNULL)
+ {
+ rcu_read_unlock();
+ return gcvSTATUS_NOT_FOUND;
+ }
+
+ /* Get name of process. */
+ strncpy(String, task->comm, Length);
+
+ rcu_read_unlock();
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_DumpCallStack(
+ IN gckOS Os
+ )
+{
+ gcmkHEADER_ARG("Os=0x%X", Os);
+
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+
+ dump_stack();
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+/*******************************************************************************
+**
+** gckOS_DetectProcessByName
+**
+** task->comm maybe part of process name, so this function
+** can only be used for debugging.
+**
+** INPUT:
+**
+** gctCONST_POINTER Name
+** Pointer to a string to hold name to be check. If the length
+** of name is longer than TASK_COMM_LEN (16), use part of name
+** to detect.
+**
+** OUTPUT:
+**
+** gcvSTATUS_TRUE if name of current process matches Name.
+**
+*/
+gceSTATUS
+gckOS_DetectProcessByName(
+ IN gctCONST_POINTER Name
+ )
+{
+ char comm[sizeof(current->comm)];
+
+ memset(comm, 0, sizeof(comm));
+
+ gcmkVERIFY_OK(
+ gckOS_GetProcessNameByPid(_GetProcessID(), sizeof(current->comm), comm));
+
+ return strstr(comm, Name) ? gcvSTATUS_TRUE
+ : gcvSTATUS_FALSE;
+}
+
+#if gcdANDROID_NATIVE_FENCE_SYNC
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
+gceSTATUS
+gckOS_CreateSyncTimeline(
+ IN gckOS Os,
+ IN gceCORE Core,
+ OUT gctHANDLE * Timeline
+ )
+{
+ struct viv_sync_timeline * timeline;
+ char name[32];
+
+ snprintf(name, 32, "gccore-%u", (unsigned int) Core);
+
+ /* Create viv sync timeline. */
+ timeline = viv_sync_timeline_create(name, Os);
+
+ if (timeline == gcvNULL)
+ {
+ /* Out of memory. */
+ return gcvSTATUS_OUT_OF_MEMORY;
+ }
+
+ *Timeline = (gctHANDLE) timeline;
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_DestroySyncTimeline(
+ IN gckOS Os,
+ IN gctHANDLE Timeline
+ )
+{
+ struct viv_sync_timeline * timeline;
+ gcmkASSERT(Timeline != gcvNULL);
+
+ /* Destroy timeline. */
+ timeline = (struct viv_sync_timeline *) Timeline;
+ sync_timeline_destroy(&timeline->obj);
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_CreateNativeFence(
+ IN gckOS Os,
+ IN gctHANDLE Timeline,
+ IN gctSIGNAL Signal,
+ OUT gctINT * FenceFD
+ )
+{
+ int fd = -1;
+ struct viv_sync_timeline *timeline;
+ struct sync_pt * pt = gcvNULL;
+ struct sync_fence * fence;
+ char name[32];
+ gcsSIGNAL_PTR signal;
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Os=0x%X Timeline=0x%X Signal=%d",
+ Os, Timeline, (gctUINT)(gctUINTPTR_T)Signal);
+
+ gcmkONERROR(
+ _QueryIntegerId(&Os->signalDB,
+ (gctUINT32)(gctUINTPTR_T)Signal,
+ (gctPOINTER)&signal));
+
+ /* Cast timeline. */
+ timeline = (struct viv_sync_timeline *) Timeline;
+
+ fd = get_unused_fd_flags(O_CLOEXEC);
+
+ if (fd < 0)
+ {
+ /* Out of resources. */
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ /* Create viv_sync_pt. */
+ pt = viv_sync_pt_create(timeline, Signal);
+
+ if (pt == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ /* Reference sync_timeline. */
+ signal->timeline = &timeline->obj;
+
+ /* Build fence name. */
+ snprintf(name, 32, "%.16s-signal_%lu",
+ current->comm,
+ (unsigned long)Signal);
+
+ /* Create sync_fence. */
+ fence = sync_fence_create(name, pt);
+
+ if (fence == NULL)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ /* Install fence to fd. */
+ sync_fence_install(fence, fd);
+
+ *FenceFD = fd;
+ gcmkFOOTER_ARG("*FenceFD=%d", fd);
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Error roll back. */
+ if (pt)
+ {
+ sync_pt_free(pt);
+ }
+
+ if (fd > 0)
+ {
+ put_unused_fd(fd);
+ }
+
+ gcmkFOOTER();
+ return status;
+}
+
+static void
+_NativeFenceSignaled(
+ struct sync_fence *fence,
+ struct sync_fence_waiter *waiter
+ )
+{
+ kfree(waiter);
+ sync_fence_put(fence);
+}
+
+gceSTATUS
+gckOS_WaitNativeFence(
+ IN gckOS Os,
+ IN gctHANDLE Timeline,
+ IN gctINT FenceFD,
+ IN gctUINT32 Timeout
+ )
+{
+ struct sync_timeline * timeline;
+ struct sync_fence * fence;
+ gctBOOL wait;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ gcmkHEADER_ARG("Os=0x%X Timeline=0x%X FenceFD=%d Timeout=%u",
+ Os, Timeline, FenceFD, Timeout);
+
+ /* Get shortcut. */
+ timeline = (struct sync_timeline *) Timeline;
+
+ /* Get sync fence. */
+ fence = sync_fence_fdget(FenceFD);
+
+ if (!fence)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ if (sync_fence_wait(fence, 0) == 0)
+ {
+ /* Already signaled. */
+ sync_fence_put(fence);
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+ }
+
+ wait = gcvFALSE;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
+ {
+ int i;
+
+ for (i = 0; i < fence->num_fences; i++)
+ {
+ struct fence *f = fence->cbs[i].sync_pt;
+ struct sync_pt *pt = container_of(f, struct sync_pt, base);
+
+ /* Do not need to wait on same timeline. */
+ if ((sync_pt_parent(pt) != timeline) && !fence_is_signaled(f))
+ {
+ wait = gcvTRUE;
+ break;
+ }
+ }
+ }
+#else
+ {
+ struct list_head *pos;
+ list_for_each(pos, &fence->pt_list_head)
+ {
+ struct sync_pt * pt =
+ container_of(pos, struct sync_pt, pt_list);
+
+ /* Do not need to wait on same timeline. */
+ if (pt->parent != timeline)
+ {
+ wait = gcvTRUE;
+ break;
+ }
+ }
+ }
+#endif
+
+ if (wait)
+ {
+ int err;
+ long timeout = (Timeout == gcvINFINITE) ? - 1 : (long) Timeout;
+ err = sync_fence_wait(fence, timeout);
+
+ /* Put the fence. */
+ sync_fence_put(fence);
+
+ switch (err)
+ {
+ case 0:
+ break;
+ case -ETIME:
+ status = gcvSTATUS_TIMEOUT;
+ break;
+ default:
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ break;
+ }
+ }
+ else
+ {
+ int err;
+ struct sync_fence_waiter *waiter;
+ waiter = (struct sync_fence_waiter *)kmalloc(
+ sizeof (struct sync_fence_waiter), gcdNOWARN | GFP_KERNEL);
+
+ /*
+ * schedule a callback to put the sync_fence. Otherwise after this function
+ * is returned, the caller may free it since it's signaled. Then there's
+ * be a real signal on a free'ed sync fence.
+ */
+ if (!waiter)
+ {
+ sync_fence_put(fence);
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ /* Schedule a waiter callback. */
+ sync_fence_waiter_init(waiter, _NativeFenceSignaled);
+ err = sync_fence_wait_async(fence, waiter);
+
+ switch (err)
+ {
+ case 0:
+ /* Put fence in callback function. */
+ break;
+ case 1:
+ /* already signaled. */
+ sync_fence_put(fence);
+ break;
+ default:
+ sync_fence_put(fence);
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ break;
+ }
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+# else /* v4.9.0 */
+
+gceSTATUS
+gckOS_CreateSyncTimeline(
+ IN gckOS Os,
+ IN gceCORE Core,
+ OUT gctHANDLE * Timeline
+ )
+{
+ struct viv_sync_timeline *timeline;
+
+ char name[32];
+
+ snprintf(name, 32, "gccore-%u", (unsigned int) Core);
+ timeline = viv_sync_timeline_create(name, Os);
+
+ if (timeline == gcvNULL)
+ {
+ /* Out of memory. */
+ return gcvSTATUS_OUT_OF_MEMORY;
+ }
+
+ *Timeline = (gctHANDLE) timeline;
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_DestroySyncTimeline(
+ IN gckOS Os,
+ IN gctHANDLE Timeline
+ )
+{
+ struct viv_sync_timeline * timeline;
+
+ /* Destroy timeline. */
+ timeline = (struct viv_sync_timeline *) Timeline;
+ viv_sync_timeline_destroy(timeline);
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_CreateNativeFence(
+ IN gckOS Os,
+ IN gctHANDLE Timeline,
+ IN gctSIGNAL Signal,
+ OUT gctINT * FenceFD
+ )
+{
+ struct fence *fence = NULL;
+ struct sync_file *sync = NULL;
+ int fd;
+ struct viv_sync_timeline *timeline;
+ gcsSIGNAL_PTR signal = gcvNULL;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ /* Create fence. */
+ timeline = (struct viv_sync_timeline *) Timeline;
+
+ gcmkONERROR(
+ _QueryIntegerId(&Os->signalDB,
+ (gctUINT32)(gctUINTPTR_T)Signal,
+ (gctPOINTER)&signal));
+
+ fence = viv_fence_create(timeline, signal);
+
+ if (!fence)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ /* Create sync_file. */
+ sync = sync_file_create(fence);
+
+ if (!sync)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ /* Get a unused fd. */
+ fd = get_unused_fd_flags(O_CLOEXEC);
+
+ if (fd < 0)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ fd_install(fd, sync->file);
+
+ *FenceFD = fd;
+ return gcvSTATUS_OK;
+
+OnError:
+ if (sync)
+ {
+ fput(sync->file);
+ }
+
+ if (fence)
+ {
+ fence_put(fence);
+ }
+
+ if (fd > 0)
+ {
+ put_unused_fd(fd);
+ }
+
+ *FenceFD = -1;
+ return status;
+}
+
+gceSTATUS
+gckOS_WaitNativeFence(
+ IN gckOS Os,
+ IN gctHANDLE Timeline,
+ IN gctINT FenceFD,
+ IN gctUINT32 Timeout
+ )
+{
+ struct fence *fence;
+ struct viv_sync_timeline *timeline;
+ gceSTATUS status = gcvSTATUS_OK;
+ unsigned int i;
+ unsigned int numFences;
+ struct fence **fences;
+ unsigned long timeout;
+
+ timeline = (struct viv_sync_timeline *) Timeline;
+
+ fence = sync_file_get_fence(FenceFD);
+
+ if (!fence)
+ {
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+ if (fence_is_array(fence))
+ {
+ struct fence_array *array = to_fence_array(fence);
+ fences = array->fences;
+ numFences = array->num_fences;
+ }
+ else
+ {
+ fences = &fence;
+ numFences = 1;
+ }
+
+ timeout = msecs_to_jiffies(Timeout);
+
+ for (i = 0; i < numFences; i++)
+ {
+ struct fence *f = fences[i];
+
+ if (f->context != timeline->context &&
+ !fence_is_signaled(f))
+ {
+ signed long ret;
+ ret = fence_wait_timeout(fence, 1, timeout);
+
+ if (ret == -ERESTARTSYS)
+ {
+ status = gcvSTATUS_INTERRUPTED;
+ break;
+ }
+ else if (ret <= 0)
+ {
+ status = gcvSTATUS_TIMEOUT;
+ break;
+ }
+ else
+ {
+ /* wait success. */
+ timeout -= ret;
+ }
+ }
+ }
+
+ fence_put(fence);
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+# endif /* v4.9.0 */
+#endif
+
+#if gcdSECURITY
+gceSTATUS
+gckOS_AllocatePageArray(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T PageCount,
+ OUT gctPOINTER * PageArrayLogical,
+ OUT gctPHYS_ADDR * PageArrayPhysical
+ )
+{
+ gceSTATUS status = gcvSTATUS_OK;
+ PLINUX_MDL mdl;
+ gctUINT32* table;
+ gctUINT32 offset;
+ gctSIZE_T bytes;
+ gckALLOCATOR allocator;
+
+ gcmkHEADER_ARG("Os=0x%X Physical=0x%X PageCount=%u",
+ Os, Physical, PageCount);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+ gcmkVERIFY_ARGUMENT(PageCount > 0);
+
+ bytes = PageCount * gcmSIZEOF(gctUINT32);
+ gcmkONERROR(gckOS_AllocateNonPagedMemory(
+ Os,
+ gcvFALSE,
+ &bytes,
+ PageArrayPhysical,
+ PageArrayLogical
+ ));
+
+ table = *PageArrayLogical;
+
+ /* Convert pointer to MDL. */
+ mdl = (PLINUX_MDL)Physical;
+
+ allocator = mdl->allocator;
+
+ /* Get all the physical addresses and store them in the page table. */
+
+ offset = 0;
+ PageCount = PageCount / (PAGE_SIZE / 4096);
+
+ /* Try to get the user pages so DMA can happen. */
+ while (PageCount-- > 0)
+ {
+ unsigned long phys = ~0;
+
+ gctPHYS_ADDR_T phys_addr;
+
+ allocator->ops->Physical(allocator, mdl, offset * PAGE_SIZE, &phys_addr);
+
+ phys = (unsigned long)phys_addr;
+
+ table[offset] = phys & PAGE_MASK;
+
+ offset += 1;
+ }
+
+OnError:
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+#endif
+
+gceSTATUS
+gckOS_CPUPhysicalToGPUPhysical(
+ IN gckOS Os,
+ IN gctPHYS_ADDR_T CPUPhysical,
+ IN gctPHYS_ADDR_T * GPUPhysical
+ )
+{
+ gcsPLATFORM * platform;
+ gcmkHEADER_ARG("CPUPhysical=%p", CPUPhysical);
+
+ platform = Os->device->platform;
+
+ if (platform && platform->ops->getGPUPhysical)
+ {
+ gcmkVERIFY_OK(
+ platform->ops->getGPUPhysical(platform, CPUPhysical, GPUPhysical));
+ }
+ else
+ {
+ *GPUPhysical = CPUPhysical;
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_GPUPhysicalToCPUPhysical(
+ IN gckOS Os,
+ IN gctUINT32 GPUPhysical,
+ IN gctPHYS_ADDR_T * CPUPhysical
+ )
+{
+ gcsPLATFORM * platform;
+ gcmkHEADER_ARG("GPUPhysical=0x%X", GPUPhysical);
+
+ platform = Os->device->platform;
+
+ if (platform && platform->ops->getCPUPhysical)
+ {
+ gcmkVERIFY_OK(
+ platform->ops->getCPUPhysical(platform, GPUPhysical, CPUPhysical));
+ }
+ else
+ {
+ *CPUPhysical = GPUPhysical;
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_PhysicalToPhysicalAddress(
+ IN gckOS Os,
+ IN gctPOINTER Physical,
+ IN gctUINT32 Offset,
+ OUT gctPHYS_ADDR_T * PhysicalAddress
+ )
+{
+ PLINUX_MDL mdl = (PLINUX_MDL)Physical;
+ gckALLOCATOR allocator = mdl->allocator;
+
+ if (allocator)
+ {
+ return allocator->ops->Physical(allocator, mdl, Offset, PhysicalAddress);
+ }
+
+ return gcvSTATUS_NOT_SUPPORTED;
+}
+
+static int fd_release(struct inode *inode, struct file *file)
+{
+ gcsFDPRIVATE_PTR private = (gcsFDPRIVATE_PTR)file->private_data;
+
+ if (private && private->release)
+ {
+ return private->release(private);
+ }
+
+ return 0;
+}
+
+static const struct file_operations fd_fops =
+{
+ .release = fd_release,
+};
+
+gceSTATUS
+gckOS_GetFd(
+ IN gctSTRING Name,
+ IN gcsFDPRIVATE_PTR Private,
+ OUT gctINT * Fd
+ )
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+ *Fd = anon_inode_getfd(Name, &fd_fops, Private, O_RDWR);
+
+ if (*Fd < 0)
+ {
+ return gcvSTATUS_OUT_OF_RESOURCES;
+ }
+
+ return gcvSTATUS_OK;
+#else
+ return gcvSTATUS_NOT_SUPPORTED;
+#endif
+}
+
+gceSTATUS
+gckOS_QueryOption(
+ IN gckOS Os,
+ IN gctCONST_STRING Option,
+ OUT gctUINT32 * Value
+ )
+{
+ gckGALDEVICE device = Os->device;
+
+ if (!strcmp(Option, "physBase"))
+ {
+ *Value = device->physBase;
+ return gcvSTATUS_OK;
+ }
+ else if (!strcmp(Option, "physSize"))
+ {
+ *Value = device->physSize;
+ return gcvSTATUS_OK;
+ }
+ else if (!strcmp(Option, "mmu"))
+ {
+#if gcdSECURITY
+ *Value = 0;
+#else
+ *Value = device->args.mmu;
+#endif
+ return gcvSTATUS_OK;
+ }
+ else if (!strcmp(Option, "contiguousSize"))
+ {
+ *Value = device->contiguousSize;
+ return gcvSTATUS_OK;
+ }
+ else if (!strcmp(Option, "contiguousBase"))
+ {
+ *Value = (gctUINT32)device->contiguousBase;
+ return gcvSTATUS_OK;
+ }
+ else if (!strcmp(Option, "externalSize"))
+ {
+ *Value = device->externalSize;
+ return gcvSTATUS_OK;
+ }
+ else if (!strcmp(Option, "externalBase"))
+ {
+ *Value = device->externalBase;
+ return gcvSTATUS_OK;
+ }
+ else if (!strcmp(Option, "recovery"))
+ {
+ *Value = device->args.recovery;
+ return gcvSTATUS_OK;
+ }
+ else if (!strcmp(Option, "stuckDump"))
+ {
+ *Value = device->args.stuckDump;
+ return gcvSTATUS_OK;
+ }
+ else if (!strcmp(Option, "powerManagement"))
+ {
+ *Value = device->args.powerManagement;
+ return gcvSTATUS_OK;
+ }
+ else if (!strcmp(Option, "TA"))
+ {
+ *Value = 0;
+ return gcvSTATUS_OK;
+ }
+ else if (!strcmp(Option, "gpuProfiler"))
+ {
+ *Value = device->args.gpuProfiler;
+ return gcvSTATUS_OK;
+ }
+
+ return gcvSTATUS_NOT_SUPPORTED;
+}
+
+gceSTATUS
+gckOS_MemoryGetSGT(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T Offset,
+ IN gctSIZE_T Bytes,
+ OUT gctPOINTER *SGT
+ )
+{
+ PLINUX_MDL mdl;
+ gckALLOCATOR allocator;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ if (!Physical)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ mdl = (PLINUX_MDL)Physical;
+ allocator = mdl->allocator;
+
+ if (!allocator->ops->GetSGT)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ if (Bytes > 0)
+ {
+ gcmkONERROR(allocator->ops->GetSGT(allocator, mdl, Offset, Bytes, SGT));
+ }
+
+OnError:
+ return status;
+}
+
+gceSTATUS
+gckOS_MemoryMmap(
+ IN gckOS Os,
+ IN gctPHYS_ADDR Physical,
+ IN gctSIZE_T skipPages,
+ IN gctSIZE_T numPages,
+ INOUT gctPOINTER Vma
+ )
+{
+ PLINUX_MDL mdl;
+ gckALLOCATOR allocator;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ if (!Physical)
+ {
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ mdl = (PLINUX_MDL)Physical;
+ allocator = mdl->allocator;
+
+ if (!allocator->ops->Mmap)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ gcmkONERROR(allocator->ops->Mmap(allocator, mdl, skipPages, numPages, Vma));
+
+OnError:
+ return status;
+}
+
+/*******************************************************************************
+**
+** gckOS_WrapMemory
+**
+** Import a number of pages allocated by other allocator.
+**
+** INPUT:
+**
+** gckOS Os
+** Pointer to an gckOS object.
+**
+** gctUINT32 Flag
+** Memory type.
+**
+** OUTPUT:
+**
+** gctSIZE_T * Bytes
+** Pointer to a variable that hold the number of bytes allocated.
+**
+** gctPHYS_ADDR * Physical
+** Pointer to a variable that will hold the physical address of the
+** allocation.
+*/
+gceSTATUS
+gckOS_WrapMemory(
+ IN gckOS Os,
+ IN gcsUSER_MEMORY_DESC_PTR Desc,
+ OUT gctSIZE_T *Bytes,
+ OUT gctPHYS_ADDR * Physical,
+ OUT gctBOOL *Contiguous
+ )
+{
+ PLINUX_MDL mdl = gcvNULL;
+ gceSTATUS status = gcvSTATUS_OUT_OF_MEMORY;
+ gckALLOCATOR allocator;
+ gcsATTACH_DESC desc;
+ gctSIZE_T bytes = 0;
+
+ gcmkHEADER_ARG("Os=0x%X ", Os);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Os, gcvOBJ_OS);
+ gcmkVERIFY_ARGUMENT(Physical != gcvNULL);
+
+ mdl = _CreateMdl(Os);
+ if (mdl == gcvNULL)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ if (Desc->flag & gcvALLOC_FLAG_DMABUF)
+ {
+ desc.dmaBuf.dmabuf = gcmUINT64_TO_PTR(Desc->dmabuf);
+
+#if defined(CONFIG_DMA_SHARED_BUFFER)
+ {
+ struct dma_buf *dmabuf = (struct dma_buf*)desc.dmaBuf.dmabuf;
+ bytes = dmabuf->size;
+ }
+#endif
+ }
+ else if (Desc->flag & gcvALLOC_FLAG_USERMEMORY)
+ {
+ desc.userMem.memory = gcmUINT64_TO_PTR(Desc->logical);
+ desc.userMem.physical = Desc->physical;
+ desc.userMem.size = Desc->size;
+ bytes = Desc->size;
+ }
+ else if (Desc->flag & gcvALLOC_FLAG_EXTERNAL_MEMORY)
+ {
+ desc.externalMem.info = Desc->externalMemoryInfo;
+ }
+ else
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ /* Walk all allocators. */
+ list_for_each_entry(allocator, &Os->allocatorList, link)
+ {
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS,
+ "%s(%d) Flag = %x allocator->capability = %x",
+ __FUNCTION__, __LINE__, Desc->flag, allocator->capability);
+
+ if ((Desc->flag & allocator->capability) != Desc->flag)
+ {
+ status = gcvSTATUS_NOT_SUPPORTED;
+ continue;
+ }
+
+ if (Desc->flag == gcvALLOC_FLAG_EXTERNAL_MEMORY)
+ {
+ /* Use name to match suitable allocator for external memory. */
+ if (!strncmp(Desc->externalMemoryInfo.allocatorName,
+ allocator->name, gcdEXTERNAL_MEMORY_NAME_MAX))
+ {
+ status = gcvSTATUS_NOT_SUPPORTED;
+ continue;
+ }
+ }
+
+ status = allocator->ops->Attach(allocator, &desc, mdl);
+
+ if (gcmIS_SUCCESS(status))
+ {
+ mdl->allocator = allocator;
+ break;
+ }
+ }
+
+ /* Check status. */
+ gcmkONERROR(status);
+
+ mdl->dmaHandle = 0;
+ mdl->addr = 0;
+
+ *Bytes = bytes ? bytes : mdl->numPages * PAGE_SIZE;
+
+ /* Return physical address. */
+ *Physical = (gctPHYS_ADDR) mdl;
+
+ *Contiguous = mdl->contiguous;
+
+ /*
+ * Add this to a global list.
+ * Will be used by get physical address
+ * and mapuser pointer functions.
+ */
+ mutex_lock(&Os->mdlMutex);
+ list_add_tail(&mdl->link, &Os->mdlHead);
+ mutex_unlock(&Os->mdlMutex);
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Physical=0x%X", *Physical);
+ return gcvSTATUS_OK;
+
+OnError:
+ if (mdl != gcvNULL)
+ {
+ /* Free the memory. */
+ _DestroyMdl(mdl);
+ }
+
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckOS_GetPolicyID(
+ IN gckOS Os,
+ IN gceSURF_TYPE Type,
+ OUT gctUINT32_PTR PolicyID,
+ OUT gctUINT32_PTR AXIConfig
+ )
+{
+ gcsPLATFORM * platform = Os->device->platform;
+
+ if (platform && platform->ops->getPolicyID)
+ {
+ return platform->ops->getPolicyID(platform, Type, PolicyID, AXIConfig);
+ }
+
+ return gcvSTATUS_NOT_SUPPORTED;
+}
+
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.h b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.h
new file mode 100644
index 000000000000..57cd01a1354b
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_os_h_
+#define __gc_hal_kernel_os_h_
+
+typedef struct _LINUX_MDL LINUX_MDL, *PLINUX_MDL;
+typedef struct _LINUX_MDL_MAP LINUX_MDL_MAP, *PLINUX_MDL_MAP;
+
+struct _LINUX_MDL_MAP
+{
+ gctINT pid;
+ gctPOINTER vmaAddr;
+ gctUINT32 count;
+
+ struct list_head link;
+};
+
+struct _LINUX_MDL
+{
+ gckOS os;
+
+ atomic_t refs;
+
+ char * addr;
+
+ gctINT numPages;
+ gctBOOL contiguous;
+ dma_addr_t dmaHandle;
+
+ struct mutex mapsMutex;
+ struct list_head mapsHead;
+
+ /* Pointer to allocator which allocates memory for this mdl. */
+ void * allocator;
+
+ /* Private data used by allocator. */
+ void * priv;
+
+ uint gid;
+
+ struct list_head link;
+};
+
+extern PLINUX_MDL_MAP
+FindMdlMap(
+ IN PLINUX_MDL Mdl,
+ IN gctINT PID
+ );
+
+typedef struct _DRIVER_ARGS
+{
+ gctUINT64 InputBuffer;
+ gctUINT64 InputBufferSize;
+ gctUINT64 OutputBuffer;
+ gctUINT64 OutputBufferSize;
+}
+DRIVER_ARGS;
+
+#endif /* __gc_hal_kernel_os_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_platform.h b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_platform.h
new file mode 100644
index 000000000000..b790b90df082
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_platform.h
@@ -0,0 +1,305 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef _gc_hal_kernel_platform_h_
+#define _gc_hal_kernel_platform_h_
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#if USE_LINUX_PCIE
+#include <linux/pci.h>
+#endif
+
+typedef struct _gcsMODULE_PARAMETERS
+{
+ gctINT irqLine;
+ gctUINT registerMemBase;
+ gctUINT registerMemSize;
+ gctINT irqLine2D;
+ gctUINT registerMemBase2D;
+ gctUINT registerMemSize2D;
+ gctINT irqLineVG;
+ gctUINT registerMemBaseVG;
+ gctUINT registerMemSizeVG;
+ gctUINT contiguousSize;
+ gctUINT contiguousBase;
+ gctUINT contiguousRequested;
+ gctUINT externalSize;
+ gctUINT externalBase;
+ gctUINT bankSize;
+ gctINT fastClear;
+ gceCOMPRESSION_OPTION compression;
+ gctINT powerManagement;
+ gctINT gpuProfiler;
+ gctINT signal;
+ gctUINT baseAddress;
+ gctUINT physSize;
+ gctUINT logFileSize;
+ gctUINT recovery;
+ gctUINT stuckDump;
+ gctUINT showArgs;
+ gctUINT gpu3DMinClock;
+ gctBOOL registerMemMapped;
+ gctPOINTER registerMemAddress;
+ gctINT irqs[gcvCORE_COUNT];
+ gctUINT registerBases[gcvCORE_COUNT];
+ gctUINT registerSizes[gcvCORE_COUNT];
+ gctUINT chipIDs[gcvCORE_COUNT];
+}
+gcsMODULE_PARAMETERS;
+
+typedef struct soc_platform gcsPLATFORM;
+
+typedef struct soc_platform_ops
+{
+
+ /*******************************************************************************
+ **
+ ** adjustParam
+ **
+ ** Override content of arguments, if a argument is not changed here, it will
+ ** keep as default value or value set by insmod command line.
+ */
+ gceSTATUS
+ (*adjustParam)(
+ IN gcsPLATFORM * Platform,
+ OUT gcsMODULE_PARAMETERS *Args
+ );
+
+ /*******************************************************************************
+ **
+ ** getPower
+ **
+ ** Prepare power and clock operation.
+ */
+ gceSTATUS
+ (*getPower)(
+ IN gcsPLATFORM * Platform
+ );
+
+ /*******************************************************************************
+ **
+ ** putPower
+ **
+ ** Finish power and clock operation.
+ */
+ gceSTATUS
+ (*putPower)(
+ IN gcsPLATFORM * Platform
+ );
+
+ /*******************************************************************************
+ **
+ ** setPower
+ **
+ ** Set power state of specified GPU.
+ **
+ ** INPUT:
+ **
+ ** gceCORE GPU
+ ** GPU neeed to config.
+ **
+ ** gceBOOL Enable
+ ** Enable or disable power.
+ */
+ gceSTATUS
+ (*setPower)(
+ IN gcsPLATFORM * Platform,
+ IN gceCORE GPU,
+ IN gctBOOL Enable
+ );
+
+ /*******************************************************************************
+ **
+ ** setClock
+ **
+ ** Set clock state of specified GPU.
+ **
+ ** INPUT:
+ **
+ ** gceCORE GPU
+ ** GPU neeed to config.
+ **
+ ** gceBOOL Enable
+ ** Enable or disable clock.
+ */
+ gceSTATUS
+ (*setClock)(
+ IN gcsPLATFORM * Platform,
+ IN gceCORE GPU,
+ IN gctBOOL Enable
+ );
+
+ /*******************************************************************************
+ **
+ ** reset
+ **
+ ** Reset GPU outside.
+ **
+ ** INPUT:
+ **
+ ** gceCORE GPU
+ ** GPU neeed to reset.
+ */
+ gceSTATUS
+ (*reset)(
+ IN gcsPLATFORM * Platform,
+ IN gceCORE GPU
+ );
+
+ /*******************************************************************************
+ **
+ ** getGPUPhysical
+ **
+ ** Convert CPU physical address to GPU physical address if they are
+ ** different.
+ */
+ gceSTATUS
+ (*getGPUPhysical)(
+ IN gcsPLATFORM * Platform,
+ IN gctPHYS_ADDR_T CPUPhysical,
+ OUT gctPHYS_ADDR_T * GPUPhysical
+ );
+
+ /*******************************************************************************
+ **
+ ** getCPUPhysical
+ **
+ ** Convert GPU physical address to CPU physical address if they are
+ ** different.
+ */
+ gceSTATUS
+ (*getCPUPhysical)(
+ IN gcsPLATFORM * Platform,
+ IN gctUINT32 GPUPhysical,
+ OUT gctPHYS_ADDR_T * CPUPhysical
+ );
+
+ /*******************************************************************************
+ **
+ ** adjustProt
+ **
+ ** Override Prot flag when mapping paged memory to userspace.
+ */
+ gceSTATUS
+ (*adjustProt)(
+ IN struct vm_area_struct * vma
+ );
+
+ /*******************************************************************************
+ **
+ ** shrinkMemory
+ **
+ ** Do something to collect memory, eg, act as oom killer.
+ */
+ gceSTATUS
+ (*shrinkMemory)(
+ IN gcsPLATFORM * Platform
+ );
+
+ /*******************************************************************************
+ **
+ ** cache
+ **
+ ** Cache operation.
+ */
+ gceSTATUS
+ (*cache)(
+ IN gcsPLATFORM * Platform,
+ IN gctUINT32 ProcessID,
+ IN gctPHYS_ADDR Handle,
+ IN gctUINT32 Physical,
+ IN gctPOINTER Logical,
+ IN gctSIZE_T Bytes,
+ IN gceCACHEOPERATION Operation
+ );
+
+ /*******************************************************************************
+ **
+ ** getPolicyID
+ **
+ ** Get policyID for a specified surface type.
+ */
+ gceSTATUS
+ (*getPolicyID)(
+ IN gcsPLATFORM * Platform,
+ IN gceSURF_TYPE Type,
+ OUT gctUINT32_PTR PolicyID,
+ OUT gctUINT32_PTR AXIConfig
+ );
+}
+gcsPLATFORM_OPERATIONS;
+
+struct soc_platform
+{
+#if USE_LINUX_PCIE
+ struct pci_dev* device;
+ struct pci_driver* driver;
+#else
+ struct platform_device* device;
+ struct platform_driver* driver;
+#endif
+
+ const char *name;
+ gcsPLATFORM_OPERATIONS* ops;
+};
+
+#if USE_LINUX_PCIE
+int soc_platform_init(struct pci_driver *pdrv, gcsPLATFORM **platform);
+#else
+int soc_platform_init(struct platform_driver *pdrv, gcsPLATFORM **platform);
+#endif
+int soc_platform_terminate(gcsPLATFORM *platform);
+
+#endif
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_security_channel.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_security_channel.c
new file mode 100644
index 000000000000..d0969ff24661
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_security_channel.c
@@ -0,0 +1,426 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include <linux/slab.h>
+
+#include "tee_client_api.h"
+
+#define _GC_OBJ_ZONE gcvZONE_OS
+
+#define GPU3D_UUID { 0xcc9f80ea, 0xa836, 0x11e3, { 0x9b, 0x07, 0x78, 0x2b, 0xcb, 0x5c, 0xf3, 0xe3 } }
+
+static const TEEC_UUID gpu3d_uuid = GPU3D_UUID;
+TEEC_Context teecContext;
+
+typedef struct _gcsSecurityChannel
+{
+ gckOS os;
+ TEEC_Session session;
+ int * virtual;
+ TEEC_SharedMemory inputBuffer;
+ gctUINT32 bytes;
+ gctPOINTER mutex;
+}
+gcsSecurityChannel;
+
+TEEC_SharedMemory *
+gpu3d_allocate_secure_mem(
+ gckOS Os,
+ unsigned int size
+ )
+{
+ TEEC_Result result;
+ TEEC_Context *context = &teecContext;
+ TEEC_SharedMemory *shm = NULL;
+ void *handle = NULL;
+ gctPHYS_ADDR_T phyAddr;
+ gceSTATUS status;
+ gctSIZE_T bytes = size;
+
+ shm = kmalloc(sizeof(TEEC_SharedMemory), GFP_KERNEL);
+
+ if (NULL == shm)
+ {
+ return NULL;
+ }
+
+ memset(shm, 0, sizeof(TEEC_SharedMemory));
+
+ status = gckOS_AllocatePagedMemoryEx(
+ Os,
+ gcvALLOC_FLAG_SECURITY,
+ bytes,
+ gcvNULL,
+ (gctPHYS_ADDR *)&handle);
+
+ if (gcmIS_ERROR(status))
+ {
+ kfree(shm);
+ return NULL;
+ }
+
+ status = gckOS_PhysicalToPhysicalAddress(
+ Os,
+ handle,
+ 0,
+ &phyAddr);
+
+ if (gcmIS_ERROR(status))
+ {
+ kfree(shm);
+ return NULL;
+ }
+
+ /* record the handle into shm->user_data */
+ shm->userdata = handle;
+
+ /* [b] Bulk input buffer. */
+ shm->size = size;
+ shm->flags = TEEC_MEM_INPUT;
+
+ /* Use TEE Client API to register the underlying memory buffer. */
+ shm->phyAddr = (void *)(gctUINT32)phyAddr;
+
+ result = TEEC_RegisterSharedMemory(
+ context,
+ shm);
+
+ if (result != TEEC_SUCCESS)
+ {
+ gckOS_FreePagedMemory(Os, (gctPHYS_ADDR)handle, shm->size);
+ kfree(shm);
+ return NULL;
+ }
+
+ return shm;
+}
+
+void gpu3d_release_secure_mem(
+ gckOS Os,
+ void *shm_handle
+ )
+{
+ TEEC_SharedMemory *shm = shm_handle;
+ void * handle;
+
+ if (!shm)
+ {
+ return;
+ }
+
+ handle = shm->userdata;
+
+ TEEC_ReleaseSharedMemory(shm);
+ gckOS_FreePagedMemory(Os, (gctPHYS_ADDR)handle, shm->size);
+
+ kfree(shm);
+
+ return;
+}
+
+static TEEC_Result gpu3d_session_callback(
+ TEEC_Session* session,
+ uint32_t commandID,
+ TEEC_Operation* operation,
+ void* userdata
+ )
+{
+ gcsSecurityChannel *channel = userdata;
+
+ if (channel == gcvNULL)
+ {
+ return TEEC_ERROR_BAD_PARAMETERS;
+ }
+
+ switch (commandID)
+ {
+ case gcvTA_CALLBACK_ALLOC_SECURE_MEM:
+ {
+ uint32_t size = operation->params[0].value.a;
+ TEEC_SharedMemory *shm = NULL;
+
+ shm = gpu3d_allocate_secure_mem(channel->os, size);
+ if (shm == NULL)
+ {
+ return TEEC_ERROR_OUT_OF_MEMORY;
+ }
+
+ /* use the value to save the pointer in client side */
+ operation->params[0].value.a = (uint32_t)shm;
+ operation->params[0].value.b = (uint32_t)shm->phyAddr;
+
+ break;
+ }
+ case gcvTA_CALLBACK_FREE_SECURE_MEM:
+ {
+ TEEC_SharedMemory *shm = (TEEC_SharedMemory *)operation->params[0].value.a;
+
+ gpu3d_release_secure_mem(channel->os, shm);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return TEEC_SUCCESS;
+}
+
+gceSTATUS
+gckOS_OpenSecurityChannel(
+ IN gckOS Os,
+ IN gceCORE GPU,
+ OUT gctUINT32 *Channel
+ )
+{
+ gceSTATUS status;
+ TEEC_Result result;
+ static bool initialized = gcvFALSE;
+ gcsSecurityChannel *channel = gcvNULL;
+
+ TEEC_Operation operation = {0};
+
+ /* Connect to TEE. */
+ if (initialized == gcvFALSE)
+ {
+ result = TEEC_InitializeContext(NULL, &teecContext);
+
+ if (result != TEEC_SUCCESS)
+ {
+ gcmkONERROR(gcvSTATUS_CHIP_NOT_READY);
+ }
+
+ initialized = gcvTRUE;
+ }
+
+ /* Construct channel. */
+ gcmkONERROR(
+ gckOS_Allocate(Os, gcmSIZEOF(*channel), (gctPOINTER *)&channel));
+
+ gckOS_ZeroMemory(channel, gcmSIZEOF(gcsSecurityChannel));
+
+ channel->os = Os;
+
+ gcmkONERROR(gckOS_CreateMutex(Os, &channel->mutex));
+
+ /* Allocate shared memory for passing gcTA_INTERFACE. */
+ channel->bytes = gcmSIZEOF(gcsTA_INTERFACE);
+ channel->virtual = kmalloc(channel->bytes, GFP_KERNEL | __GFP_NOWARN);
+
+ if (!channel->virtual)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY);
+ }
+
+ channel->inputBuffer.size = channel->bytes;
+ channel->inputBuffer.flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
+ channel->inputBuffer.phyAddr = (void *)virt_to_phys(channel->virtual);
+
+ result = TEEC_RegisterSharedMemory(&teecContext, &channel->inputBuffer);
+
+ if (result != TEEC_SUCCESS)
+ {
+ gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES);
+ }
+
+ operation.paramTypes = TEEC_PARAM_TYPES(
+ TEEC_VALUE_INPUT,
+ TEEC_NONE,
+ TEEC_NONE,
+ TEEC_NONE);
+
+ operation.params[0].value.a = GPU;
+
+ /* Open session with TEE application. */
+ result = TEEC_OpenSession(
+ &teecContext,
+ &channel->session,
+ &gpu3d_uuid,
+ TEEC_LOGIN_USER,
+ NULL,
+ &operation,
+ NULL);
+
+ /* Prepare callback. */
+ TEEC_RegisterCallback(&channel->session, gpu3d_session_callback, channel);
+
+ *Channel = (gctUINT32)channel;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ if (channel)
+ {
+ if (channel->virtual)
+ {
+ }
+
+ if (channel->mutex)
+ {
+ gcmkVERIFY_OK(gckOS_DeleteMutex(Os, channel->mutex));
+ }
+
+ gcmkVERIFY_OK(gckOS_Free(Os, channel));
+ }
+
+ return status;
+}
+
+gceSTATUS
+gckOS_CloseSecurityChannel(
+ IN gctUINT32 Channel
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_CallSecurityService(
+ IN gctUINT32 Channel,
+ IN gcsTA_INTERFACE *Interface
+ )
+{
+ gceSTATUS status;
+ TEEC_Result result;
+ gcsSecurityChannel *channel = (gcsSecurityChannel *)Channel;
+ TEEC_Operation operation = {0};
+
+ gcmkHEADER();
+ gcmkVERIFY_ARGUMENT(Channel != 0);
+
+ gckOS_AcquireMutex(channel->os, channel->mutex, gcvINFINITE);
+
+ gckOS_MemCopy(channel->virtual, Interface, channel->bytes);
+
+ operation.paramTypes = TEEC_PARAM_TYPES(
+ TEEC_MEMREF_PARTIAL_INPUT,
+ TEEC_NONE,
+ TEEC_NONE,
+ TEEC_NONE);
+
+ /* Note: we use the updated size in the MemRef output by the encryption. */
+ operation.params[0].memref.parent = &channel->inputBuffer;
+ operation.params[0].memref.offset = 0;
+ operation.params[0].memref.size = sizeof(gcsTA_INTERFACE);
+ operation.started = true;
+
+ /* Start the commit command within the TEE application. */
+ result = TEEC_InvokeCommand(
+ &channel->session,
+ gcvTA_COMMAND_DISPATCH,
+ &operation,
+ NULL);
+
+ gckOS_MemCopy(Interface, channel->virtual, channel->bytes);
+
+ gckOS_ReleaseMutex(channel->os, channel->mutex);
+
+ if (result != TEEC_SUCCESS)
+ {
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gckOS_InitSecurityChannel(
+ IN gctUINT32 Channel
+ )
+{
+ gceSTATUS status;
+ TEEC_Result result;
+ gcsSecurityChannel *channel = (gcsSecurityChannel *)Channel;
+ TEEC_Operation operation = {0};
+
+ gcmkHEADER();
+ gcmkVERIFY_ARGUMENT(Channel != 0);
+
+ operation.paramTypes = TEEC_PARAM_TYPES(
+ TEEC_MEMREF_PARTIAL_INPUT,
+ TEEC_NONE,
+ TEEC_NONE,
+ TEEC_NONE);
+
+ /* Note: we use the updated size in the MemRef output by the encryption. */
+ operation.params[0].memref.parent = &channel->inputBuffer;
+ operation.params[0].memref.offset = 0;
+ operation.params[0].memref.size = gcmSIZEOF(gcsTA_INTERFACE);
+ operation.started = true;
+
+ /* Start the commit command within the TEE application. */
+ result = TEEC_InvokeCommand(
+ &channel->session,
+ gcvTA_COMMAND_INIT,
+ &operation,
+ NULL);
+
+ if (result != TEEC_SUCCESS)
+ {
+ gcmkONERROR(gcvSTATUS_GENERIC_IO);
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_security_channel_emulator.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_security_channel_emulator.c
new file mode 100644
index 000000000000..c0b17ceead52
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_security_channel_emulator.c
@@ -0,0 +1,116 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+
+#define _GC_OBJ_ZONE gcvZONE_OS
+
+#if gcdENABLE_TRUST_APPLICATION
+
+gceSTATUS
+gckOS_OpenSecurityChannel(
+ IN gckOS Os,
+ IN gceCORE Core,
+ OUT gctUINT32 *Channel
+ )
+{
+ *Channel = Core + 1;
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_InitSecurityChannel(
+ OUT gctUINT32 Channel
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gckOS_CloseSecurityChannel(
+ IN gctUINT32 Channel
+ )
+{
+ return gcvSTATUS_OK;
+}
+
+extern gceSTATUS
+TAEmulator (
+ gceCORE,
+ void *
+ );
+
+gceSTATUS
+gckOS_CallSecurityService(
+ IN gctUINT32 Channel,
+ IN gcsTA_INTERFACE *Interface
+ )
+{
+ gceCORE core;
+ gceSTATUS status;
+ gcmkHEADER();
+ gcmkVERIFY_ARGUMENT(Channel != 0);
+
+ core = (gceCORE)(Channel - 1);
+
+ TAEmulator(core, Interface);
+
+ status = Interface->result;
+
+ gcmkFOOTER();
+ return status;
+}
+
+#endif
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_sync.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_sync.c
new file mode 100644
index 000000000000..95f3e460e648
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_sync.c
@@ -0,0 +1,373 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include <gc_hal.h>
+#include <gc_hal_base.h>
+
+#if gcdANDROID_NATIVE_FENCE_SYNC
+
+#include <linux/kernel.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+
+#include "gc_hal_kernel_sync.h"
+#include "gc_hal_kernel_linux.h"
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
+
+static struct sync_pt * viv_sync_pt_dup(struct sync_pt *sync_pt)
+{
+ gceSTATUS status;
+ struct viv_sync_pt *pt;
+ struct viv_sync_pt *src;
+ struct viv_sync_timeline *obj;
+
+ src = (struct viv_sync_pt *)sync_pt;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
+ obj = (struct viv_sync_timeline *)sync_pt_parent(sync_pt);
+#else
+ obj = (struct viv_sync_timeline *)sync_pt->parent;
+#endif
+
+ /* Create the new sync_pt. */
+ pt = (struct viv_sync_pt *)
+ sync_pt_create(&obj->obj, sizeof(struct viv_sync_pt));
+
+ pt->stamp = src->stamp;
+
+ /* Reference signal. */
+ status = gckOS_MapSignal(obj->os,
+ src->signal,
+ gcvNULL /* (gctHANDLE) _GetProcessID() */,
+ &pt->signal);
+
+ if (gcmIS_ERROR(status)) {
+ sync_pt_free((struct sync_pt *)pt);
+ return NULL;
+ }
+
+ return (struct sync_pt *)pt;
+}
+
+static int viv_sync_pt_has_signaled(struct sync_pt *sync_pt)
+{
+ gceSTATUS status;
+ struct viv_sync_pt *pt;
+ struct viv_sync_timeline *obj;
+
+ pt = (struct viv_sync_pt *)sync_pt;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
+ obj = (struct viv_sync_timeline *)sync_pt_parent(sync_pt);
+#else
+ obj = (struct viv_sync_timeline *)sync_pt->parent;
+#endif
+
+ status = _QuerySignal(obj->os, pt->signal);
+
+ if (gcmIS_ERROR(status)) {
+ /* Error. */
+ return -1;
+ }
+
+ return (int) status;
+}
+
+static int viv_sync_pt_compare(struct sync_pt *a, struct sync_pt *b)
+{
+ int ret;
+ struct viv_sync_pt *pt1 = (struct viv_sync_pt *)a;
+ struct viv_sync_pt *pt2 = (struct viv_sync_pt *)b;
+
+ ret = (pt1->stamp < pt2->stamp) ? -1
+ : (pt1->stamp == pt2->stamp) ? 0
+ : 1;
+
+ return ret;
+}
+
+static void viv_sync_pt_free(struct sync_pt *sync_pt)
+{
+ struct viv_sync_pt *pt;
+ struct viv_sync_timeline *obj;
+
+ pt = (struct viv_sync_pt *)sync_pt;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
+ obj = (struct viv_sync_timeline *)sync_pt_parent(sync_pt);
+#else
+ obj = (struct viv_sync_timeline *)sync_pt->parent;
+#endif
+
+ gckOS_DestroySignal(obj->os, pt->signal);
+}
+
+static void viv_timeline_value_str(struct sync_timeline *timeline,
+ char *str, int size)
+{
+ struct viv_sync_timeline *obj;
+
+ obj = (struct viv_sync_timeline *)timeline;
+ snprintf(str, size, "stamp_%llu", obj->stamp);
+}
+
+static void viv_pt_value_str(struct sync_pt *sync_pt, char *str, int size)
+{
+ struct viv_sync_pt *pt;
+
+ pt = (struct viv_sync_pt *)sync_pt;
+ snprintf(str, size, "signal_%lu@stamp_%llu",
+ (unsigned long)pt->signal, pt->stamp);
+}
+
+static struct sync_timeline_ops viv_timeline_ops =
+{
+ .driver_name = "viv_gpu_sync",
+ .dup = viv_sync_pt_dup,
+ .has_signaled = viv_sync_pt_has_signaled,
+ .compare = viv_sync_pt_compare,
+ .free_pt = viv_sync_pt_free,
+ .timeline_value_str = viv_timeline_value_str,
+ .pt_value_str = viv_pt_value_str,
+};
+
+struct viv_sync_timeline * viv_sync_timeline_create(const char *name, gckOS os)
+{
+ struct viv_sync_timeline * obj;
+
+ obj = (struct viv_sync_timeline *)
+ sync_timeline_create(&viv_timeline_ops, sizeof(struct viv_sync_timeline), name);
+
+ obj->os = os;
+ obj->stamp = 0;
+
+ return obj;
+}
+
+struct sync_pt * viv_sync_pt_create(struct viv_sync_timeline *obj,
+ gctSIGNAL Signal)
+{
+ gceSTATUS status;
+ struct viv_sync_pt *pt;
+
+ pt = (struct viv_sync_pt *)
+ sync_pt_create(&obj->obj, sizeof(struct viv_sync_pt));
+
+ pt->stamp = obj->stamp++;
+
+ /* Dup signal. */
+ status = gckOS_MapSignal(obj->os,
+ Signal,
+ gcvNULL /* (gctHANDLE) _GetProcessID() */,
+ &pt->signal);
+
+ if (gcmIS_ERROR(status)) {
+ sync_pt_free((struct sync_pt *)pt);
+ return NULL;
+ }
+
+ return (struct sync_pt *)pt;
+}
+
+#else /* v4.9.0 */
+
+struct viv_sync_timeline * viv_sync_timeline_create(const char *name, gckOS Os)
+{
+ struct viv_sync_timeline *timeline;
+
+ timeline = kmalloc(sizeof(struct viv_sync_timeline),
+ gcdNOWARN | GFP_KERNEL);
+
+ if (!timeline)
+ return NULL;
+
+ strncpy(timeline->name, name, sizeof(timeline->name));
+ timeline->context = fence_context_alloc(1);
+ atomic64_set(&timeline->seqno, 0);
+ timeline->os = Os;
+
+ return timeline;
+}
+
+void viv_sync_timeline_destroy(struct viv_sync_timeline *timeline)
+{
+ kfree(timeline);
+}
+
+static const char * viv_fence_get_driver_name(struct fence *fence)
+{
+ return "viv_gpu_sync";
+}
+
+static const char * viv_fence_get_timeline_name(struct fence *fence)
+{
+ struct viv_fence *f = (struct viv_fence *)fence;
+ return f->parent->name;
+}
+
+/* Same as fence_signaled. */
+static inline bool __viv_fence_signaled(struct fence *fence)
+{
+ struct viv_fence *f = (struct viv_fence *)fence;
+ struct viv_sync_timeline *timeline = f->parent;
+ gceSTATUS status;
+
+ status = _QuerySignal(timeline->os, f->signal);
+
+ return (status == gcvSTATUS_TRUE) ? true : false;
+}
+
+static bool viv_fence_enable_signaling(struct fence *fence)
+{
+ /* fence is locked already. */
+ return !__viv_fence_signaled(fence);
+}
+
+static bool viv_fence_signaled(struct fence *fence)
+{
+ /* fence could be locked, could be not. */
+ return __viv_fence_signaled(fence);
+}
+
+static void viv_fence_release(struct fence *fence)
+{
+ struct viv_fence *f = (struct viv_fence *)fence;
+ struct viv_sync_timeline *timeline = f->parent;
+
+ if (f->signal)
+ gckOS_DestroySignal(timeline->os, f->signal);
+
+ kfree(fence);
+}
+
+static struct fence_ops viv_fence_ops =
+{
+ .get_driver_name = viv_fence_get_driver_name,
+ .get_timeline_name = viv_fence_get_timeline_name,
+ .enable_signaling = viv_fence_enable_signaling,
+ .signaled = viv_fence_signaled,
+ .wait = fence_default_wait,
+ .release = viv_fence_release,
+};
+
+struct fence * viv_fence_create(struct viv_sync_timeline *timeline,
+ gcsSIGNAL *signal)
+{
+ gceSTATUS status;
+ struct viv_fence *fence;
+ struct fence *old_fence = NULL;
+ unsigned seqno;
+
+ fence = kzalloc(sizeof(struct viv_fence), gcdNOWARN | GFP_KERNEL);
+
+ if (!fence)
+ return NULL;
+
+ /* Reference signal in fence. */
+ status = gckOS_MapSignal(timeline->os, (gctSIGNAL)(uintptr_t)signal->id,
+ NULL, &fence->signal);
+
+ if (gcmIS_ERROR(status)) {
+ kfree(fence);
+ return NULL;
+ }
+
+ spin_lock_init(&fence->lock);
+
+ fence->parent = timeline;
+
+ seqno = (unsigned)atomic64_inc_return(&timeline->seqno);
+
+ fence_init((struct fence *)fence, &viv_fence_ops,
+ &fence->lock, timeline->context, seqno);
+
+ /*
+ * Reference fence in signal.
+ * Be aware of recursive reference!!
+ */
+ spin_lock(&signal->lock);
+
+ if (signal->fence) {
+ old_fence = signal->fence;
+ signal->fence = NULL;
+ }
+
+ if (!signal->done) {
+ signal->fence = (struct fence*)fence;
+ fence_get((struct fence*)fence);
+ }
+
+ spin_unlock(&signal->lock);
+
+ if (old_fence)
+ fence_put(old_fence);
+
+ if (!signal->fence) {
+ /* Fence already signaled. */
+ gckOS_DestroySignal(timeline->os, fence->signal);
+ fence->signal = NULL;
+
+ fence_signal_locked((struct fence*)fence);
+ }
+
+ return (struct fence*)fence;
+}
+
+#endif /* v4.9.0 */
+
+#endif
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_sync.h b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_sync.h
new file mode 100644
index 000000000000..9fe50429b164
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_sync.h
@@ -0,0 +1,146 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef __gc_hal_kernel_sync_h_
+#define __gc_hal_kernel_sync_h_
+
+#include <linux/types.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
+
+/* sync.h is in drivers/staging/android/ for now. */
+#include <sync.h>
+
+#include <gc_hal.h>
+#include <gc_hal_base.h>
+
+struct viv_sync_timeline
+{
+ /* Parent object. */
+ struct sync_timeline obj;
+
+ /* Timestamp when sync_pt is created. */
+ gctUINT64 stamp;
+
+ /* Pointer to os struct. */
+ gckOS os;
+};
+
+
+struct viv_sync_pt
+{
+ /* Parent object. */
+ struct sync_pt pt;
+
+ /* Reference signal. */
+ gctSIGNAL signal;
+
+ /* Timestamp when sync_pt is created. */
+ gctUINT64 stamp;
+};
+
+/* Create viv_sync_timeline object. */
+struct viv_sync_timeline * viv_sync_timeline_create(const char *name, gckOS Os);
+
+/* Create viv_sync_pt object. */
+struct sync_pt * viv_sync_pt_create(struct viv_sync_timeline *obj,
+ gctSIGNAL signal);
+
+#else /* v4.9.0 */
+
+#include <linux/sync_file.h>
+#include <linux/fence.h>
+#include <linux/fence-array.h>
+
+#include <gc_hal.h>
+#include <gc_hal_base.h>
+#include "gc_hal_kernel_linux.h"
+
+struct viv_sync_timeline
+{
+ char name[64];
+
+ /* Parent object. */
+ u64 context;
+
+ /* Timestamp when sync_pt is created. */
+ atomic64_t seqno;
+
+ /* Pointer to os struct. */
+ gckOS os;
+};
+
+struct viv_fence
+{
+ /* must be the first. */
+ struct fence base;
+ spinlock_t lock;
+
+ struct viv_sync_timeline *parent;
+
+ /* link with signal. */
+ gctSIGNAL signal;
+};
+
+struct viv_sync_timeline * viv_sync_timeline_create(const char *name, gckOS Os);
+
+void viv_sync_timeline_destroy(struct viv_sync_timeline *timeline);
+
+struct fence * viv_fence_create(struct viv_sync_timeline *timeline,
+ gcsSIGNAL *signal);
+
+#endif /* v4.9.0 */
+
+#endif /* __gc_hal_kernel_sync_h_ */
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/default/gc_hal_kernel_platform_default.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/default/gc_hal_kernel_platform_default.c
new file mode 100644
index 000000000000..1f522b6ced68
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/default/gc_hal_kernel_platform_default.c
@@ -0,0 +1,146 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_platform.h"
+
+
+gceSTATUS
+_AdjustParam(
+ IN gcsPLATFORM *Platform,
+ OUT gcsMODULE_PARAMETERS *Args
+ )
+{
+#if USE_LINUX_PCIE
+ struct pci_dev *pdev = Platform->device;
+ unsigned char irqline = pdev->irq;
+
+ if ((Args->irqLine2D != -1) && (Args->irqLine2D != irqline))
+ {
+ Args->irqLine2D = irqline;
+ }
+ if ((Args->irqLine != -1) && (Args->irqLine != irqline))
+ {
+ Args->irqLine = irqline;
+ }
+#endif
+ return gcvSTATUS_OK;
+}
+
+static struct soc_platform_ops default_ops =
+{
+ .adjustParam = _AdjustParam,
+};
+
+static struct soc_platform default_platform =
+{
+ .name = __FILE__,
+ .ops = &default_ops,
+};
+
+#if USE_LINUX_PCIE
+
+int soc_platform_init(struct pci_driver *pdrv,
+ struct soc_platform **platform)
+{
+ *platform = &default_platform;
+ return 0;
+}
+
+int soc_platform_terminate(struct soc_platform *platform)
+{
+ return 0;
+}
+
+#else
+static struct platform_device *default_dev;
+
+int soc_platform_init(struct platform_driver *pdrv,
+ struct soc_platform **platform)
+{
+ int ret;
+ default_dev = platform_device_alloc(pdrv->driver.name, -1);
+
+ if (!default_dev) {
+ printk(KERN_ERR "galcore: platform_device_alloc failed.\n");
+ return -ENOMEM;
+ }
+
+ /* Add device */
+ ret = platform_device_add(default_dev);
+ if (ret) {
+ printk(KERN_ERR "galcore: platform_device_add failed.\n");
+ goto put_dev;
+ }
+
+ *platform = &default_platform;
+ return 0;
+
+put_dev:
+ platform_device_put(default_dev);
+
+ return ret;
+}
+
+int soc_platform_terminate(struct soc_platform *platform)
+{
+ if (default_dev) {
+ platform_device_unregister(default_dev);
+ default_dev = NULL;
+ }
+
+ return 0;
+}
+#endif
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/freescale/gc_hal_kernel_platform_imx.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/freescale/gc_hal_kernel_platform_imx.c
new file mode 100644
index 000000000000..1d59805f135f
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/freescale/gc_hal_kernel_platform_imx.c
@@ -0,0 +1,1569 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_kernel_linux.h"
+#include "gc_hal_kernel_platform.h"
+#include "gc_hal_kernel_device.h"
+#include "gc_hal_driver.h"
+#include <linux/slab.h>
+
+#if defined(CONFIG_PM_OPP)
+#include <linux/pm_opp.h>
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+# include <linux/of_platform.h>
+# include <linux/of_gpio.h>
+# include <linux/of_address.h>
+#endif
+
+#if USE_PLATFORM_DRIVER
+# include <linux/platform_device.h>
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0)) || defined(IMX8_SCU_CONTROL)
+# define IMX_GPU_SUBSYSTEM 1
+# include <linux/component.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
+# include <mach/viv_gpu.h>
+#elif defined (CONFIG_PM)
+# include <linux/pm_runtime.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
+# include <mach/busfreq.h>
+# elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 29)
+# include <linux/busfreq-imx6.h>
+# include <linux/reset.h>
+# else
+# include <linux/busfreq-imx.h>
+# include <linux/reset.h>
+# endif
+#endif
+
+#include <linux/clk.h>
+
+#if defined(IMX8_SCU_CONTROL)
+# include <soc/imx8/sc/sci.h>
+static sc_ipc_t gpu_ipcHandle;
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
+# include <mach/hardware.h>
+#endif
+
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+#ifdef CONFIG_DEVICE_THERMAL
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+# include <linux/device_cooling.h>
+# define REG_THERMAL_NOTIFIER(a) register_devfreq_cooling_notifier(a);
+# define UNREG_THERMAL_NOTIFIER(a) unregister_devfreq_cooling_notifier(a);
+# else
+extern int register_thermal_notifier(struct notifier_block *nb);
+extern int unregister_thermal_notifier(struct notifier_block *nb);
+# define REG_THERMAL_NOTIFIER(a) register_thermal_notifier(a);
+# define UNREG_THERMAL_NOTIFIER(a) unregister_thermal_notifier(a);
+# endif
+#endif
+
+#ifndef gcdFSL_CONTIGUOUS_SIZE
+# define gcdFSL_CONTIGUOUS_SIZE (4 << 20)
+#endif
+
+#if defined(CONFIG_PM_OPP)
+typedef enum _gceGOVERN_MODE
+{
+ OVERDRIVE,
+ NOMINAL,
+ UNDERDRIVE,
+ GOVERN_COUNT
+}
+gceGOVERN_MODE;
+#endif
+
+static int initgpu3DMinClock = 1;
+module_param(initgpu3DMinClock, int, 0644);
+
+struct platform_device *pdevice;
+
+#ifdef CONFIG_GPU_LOW_MEMORY_KILLER
+# include <linux/kernel.h>
+# include <linux/mm.h>
+# include <linux/oom.h>
+# include <linux/sched.h>
+# include <linux/profile.h>
+
+static unsigned long timeout;
+struct task_struct *almostfail;
+
+static int
+notif_func(struct notifier_block *self, unsigned long val, void *data)
+{
+ struct task_struct *task = data;
+
+ if (task == almostfail)
+ almostfail = NULL;
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block task_nb = {
+ .notifier_call = notif_func,
+};
+
+static int force_shrink_mem(IN gckKERNEL Kernel)
+{
+ struct task_struct *p = NULL;
+ struct task_struct *selected = NULL;
+ int cur_size = 0;
+ int set_size = 0;
+ int oom_val = 0;
+ int mem_adj = 0;
+ int retVal = -1;
+
+ if (almostfail && time_before_eq(jiffies, timeout))
+ return 0;
+
+ rcu_read_lock();
+
+ for_each_process(p) {
+ gcuDATABASE_INFO info;
+ struct mm_struct *mm;
+ struct signal_struct *sig;
+
+ cur_size = 0;
+
+ task_lock(p);
+ sig = p->signal;
+ mm = p->mm;
+ if (!sig || !mm) {
+ task_unlock(p);
+ continue;
+ }
+ oom_val = sig->oom_score_adj;
+ if (oom_val < 0) {
+ task_unlock(p);
+ continue;
+ }
+ task_unlock(p);
+
+ rcu_read_unlock();
+ if (gckKERNEL_QueryProcessDB(Kernel, p->pid, gcvFALSE, gcvDB_VIDEO_MEMORY, &info) == gcvSTATUS_OK){
+ cur_size += info.counters.bytes / PAGE_SIZE;
+ }
+ if (gckKERNEL_QueryProcessDB(Kernel, p->pid, gcvFALSE, gcvDB_CONTIGUOUS, &info) == gcvSTATUS_OK){
+ cur_size += info.counters.bytes / PAGE_SIZE;
+ }
+ rcu_read_lock();
+
+ if (cur_size <= 0) continue;
+
+ printk("<gpu> pid %d (%s), adj %d, size %d\n", p->pid, p->comm, oom_val, cur_size);
+
+ if (selected) {
+ if ((oom_val < mem_adj) || (oom_val == mem_adj && cur_size <= set_size)) continue;
+ }
+ set_size = cur_size;
+ mem_adj = oom_val;
+ selected = p;
+ }
+
+ if (selected && mem_adj > 0) {
+ printk("<gpu> send sigkill to %d (%s), adj %d, size %d\n",
+ selected->pid, selected->comm, mem_adj, set_size);
+ almostfail = selected;
+ timeout = jiffies + HZ;
+ force_sig(SIGKILL, selected);
+ retVal = 0;
+ }
+
+ rcu_read_unlock();
+
+ return retVal;
+}
+
+extern gckKERNEL
+_GetValidKernel(
+ gckGALDEVICE Device
+ );
+
+static gceSTATUS
+_ShrinkMemory(
+ IN gcsPLATFORM * Platform
+ )
+{
+ struct platform_device *pdev;
+ gckGALDEVICE galDevice;
+ gckKERNEL kernel;
+ gceSTATUS status = gcvSTATUS_OK;
+
+ pdev = Platform->device;
+
+ galDevice = platform_get_drvdata(pdev);
+
+ kernel = _GetValidKernel(galDevice);
+
+ if (kernel != gcvNULL)
+ {
+ if (force_shrink_mem(kernel) != 0)
+ status = gcvSTATUS_OUT_OF_MEMORY;
+ }
+ else
+ {
+ printk("%s: can't find kernel!\n", __FUNCTION__);
+ }
+
+ return status;
+}
+#endif
+
+#if gcdENABLE_FSCALE_VAL_ADJUST && (defined(CONFIG_DEVICE_THERMAL) || defined(CONFIG_DEVICE_THERMAL_MODULE))
+static int thermal_hot_pm_notify(struct notifier_block *nb, unsigned long event,
+ void *dummy)
+{
+ static gctUINT orgFscale, minFscale, maxFscale;
+ static gctBOOL bAlreadyTooHot = gcvFALSE;
+ gckHARDWARE hardware;
+ gckGALDEVICE galDevice;
+
+ galDevice = platform_get_drvdata(pdevice);
+ if (!galDevice)
+ {
+ /* GPU is not ready, so it is meaningless to change GPU freq. */
+ return NOTIFY_OK;
+ }
+
+ if (!galDevice->kernels[gcvCORE_MAJOR])
+ {
+ return NOTIFY_OK;
+ }
+
+ hardware = galDevice->kernels[gcvCORE_MAJOR]->hardware;
+
+ if (!hardware)
+ {
+ return NOTIFY_OK;
+ }
+
+ if (event && !bAlreadyTooHot) {
+ gckHARDWARE_GetFscaleValue(hardware,&orgFscale,&minFscale, &maxFscale);
+ gckHARDWARE_SetFscaleValue(hardware, minFscale);
+ bAlreadyTooHot = gcvTRUE;
+ printk("System is too hot. GPU3D will work at %d/64 clock.\n", minFscale);
+ } else if (!event && bAlreadyTooHot) {
+ gckHARDWARE_SetFscaleValue(hardware, orgFscale);
+ printk("Hot alarm is canceled. GPU3D clock will return to %d/64\n", orgFscale);
+ bAlreadyTooHot = gcvFALSE;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block thermal_hot_pm_notifier =
+{
+ .notifier_call = thermal_hot_pm_notify,
+};
+
+static ssize_t gpu3DMinClock_show(struct device_driver *dev, char *buf)
+{
+ gctUINT currentf,minf,maxf;
+ gckGALDEVICE galDevice;
+
+ galDevice = platform_get_drvdata(pdevice);
+
+ minf = 0;
+ if (galDevice->kernels[gcvCORE_MAJOR])
+ {
+ gckHARDWARE_GetFscaleValue(galDevice->kernels[gcvCORE_MAJOR]->hardware,
+ &currentf, &minf, &maxf);
+ }
+
+ snprintf(buf, PAGE_SIZE, "%d\n", minf);
+ return strlen(buf);
+}
+
+static ssize_t gpu3DMinClock_store(struct device_driver *dev, const char *buf, size_t count)
+{
+
+ gctINT fields;
+ gctUINT MinFscaleValue;
+ gckGALDEVICE galDevice;
+
+ galDevice = platform_get_drvdata(pdevice);
+
+ if (galDevice->kernels[gcvCORE_MAJOR])
+ {
+ fields = sscanf(buf, "%d", &MinFscaleValue);
+
+ if (fields < 1)
+ return -EINVAL;
+
+ gckHARDWARE_SetMinFscaleValue(galDevice->kernels[gcvCORE_MAJOR]->hardware,MinFscaleValue);
+ }
+
+ return count;
+}
+
+static DRIVER_ATTR_RW(gpu3DMinClock);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+static const struct of_device_id mxs_gpu_dt_ids[] = {
+#ifdef IMX_GPU_SUBSYSTEM
+ { .compatible = "fsl,imx8-gpu-ss", },
+#endif
+ { .compatible = "fsl,imx6q-gpu", }, /*Backward Compatiblity */
+ {/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, mxs_gpu_dt_ids);
+#endif
+
+struct gpu_clk
+{
+ struct clk *clk_core;
+ struct clk *clk_shader;
+ struct clk *clk_axi;
+ struct clk *clk_ahb;
+};
+
+#if defined(CONFIG_PM_OPP)
+struct gpu_govern
+{
+ unsigned long core_clk_freq[GOVERN_COUNT];
+ unsigned long shader_clk_freq[GOVERN_COUNT];
+ struct device* dev;
+ int num_modes;
+ int current_mode;
+};
+#endif
+
+struct imx_priv
+{
+ struct gpu_clk imx_gpu_clks[gcdMAX_GPU_COUNT];
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+ /*Power management.*/
+ struct regulator *gpu_regulator;
+# endif
+#endif
+ /*Run time pm*/
+ struct device *pmdev[gcdMAX_GPU_COUNT];
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+ struct reset_control *rstc[gcdMAX_GPU_COUNT];
+#endif
+
+#if defined(IMX8_SCU_CONTROL)
+ sc_rsrc_t sc_gpu_pid[gcdMAX_GPU_COUNT];
+#endif
+
+ int gpu3dCount;
+
+#if defined(CONFIG_PM_OPP)
+ struct gpu_govern imx_gpu_govern;
+#endif
+};
+
+static struct imx_priv imxPriv;
+
+#if defined(CONFIG_PM_OPP)
+static ssize_t gpu_mode_show(struct device_driver *dev, char *buf)
+{
+ struct imx_priv *priv = &imxPriv;
+ char buffer[512];
+ char mode[16] = "undefined\n";
+ int i;
+
+ unsigned long core_freq = 0;
+ unsigned long shader_freq = 0;
+
+ snprintf(buf, 512, "GPU support %d modes\n", priv->imx_gpu_govern.num_modes);
+
+ for(i = 0;i<priv->imx_gpu_govern.num_modes;i++)
+ {
+ switch(i){
+ case OVERDRIVE:
+ core_freq = priv->imx_gpu_govern.core_clk_freq[i];
+ shader_freq = priv->imx_gpu_govern.shader_clk_freq[i];
+ snprintf(buffer, 512, "overdrive:\tcore_clk frequency: %ld\tshader_clk frequency: %ld\n", core_freq,shader_freq);
+ strcat(buf,buffer);
+ if(OVERDRIVE == priv->imx_gpu_govern.current_mode)
+ strcpy(mode,"overdrive\n");
+ break;
+ case NOMINAL:
+ core_freq = priv->imx_gpu_govern.core_clk_freq[i];
+ shader_freq = priv->imx_gpu_govern.shader_clk_freq[i];
+ snprintf(buffer, 512, "nominal:\tcore_clk frequency: %ld\tshader_clk frequency: %ld\n", core_freq,shader_freq);
+ strcat(buf,buffer);
+ if(NOMINAL == priv->imx_gpu_govern.current_mode)
+ strcpy(mode,"nominal\n");
+ break;
+ case UNDERDRIVE:
+ core_freq = priv->imx_gpu_govern.core_clk_freq[i];
+ shader_freq = priv->imx_gpu_govern.shader_clk_freq[i];
+ snprintf(buffer, 512, "underdrive:\tcore_clk frequency: %ld\tshader_clk frequency: %ld\n", core_freq,shader_freq);
+ strcat(buf,buffer);
+ if(UNDERDRIVE == priv->imx_gpu_govern.current_mode)
+ strcpy(mode,"underdrive\n");
+ break;
+ default:
+ strcpy(mode,"undefined\n");
+ break;
+ }
+ }
+ strcat(buf,"Currently GPU runs on mode ");
+ strcat(buf,mode);
+ return strlen(buf);
+}
+
+static ssize_t gpu_mode_store(struct device_driver *dev, const char *buf, size_t count)
+{
+ unsigned long core_freq = 0;
+ unsigned long shader_freq = 0;
+ struct imx_priv *priv = &imxPriv;
+ int core = gcvCORE_MAJOR;
+
+ do{
+ if(strstr(buf,"overdrive"))
+ {
+ core_freq = priv->imx_gpu_govern.core_clk_freq[OVERDRIVE];
+ shader_freq = priv->imx_gpu_govern.shader_clk_freq[OVERDRIVE];
+ priv->imx_gpu_govern.current_mode = OVERDRIVE;
+ break;
+ }
+ if(strstr(buf,"nominal"))
+ {
+ core_freq = priv->imx_gpu_govern.core_clk_freq[NOMINAL];
+ shader_freq = priv->imx_gpu_govern.shader_clk_freq[NOMINAL];
+ priv->imx_gpu_govern.current_mode = NOMINAL;
+ break;
+ }
+ if(strstr(buf,"underdrive"))
+ {
+ core_freq = priv->imx_gpu_govern.core_clk_freq[UNDERDRIVE];
+ shader_freq = priv->imx_gpu_govern.shader_clk_freq[UNDERDRIVE];
+ priv->imx_gpu_govern.current_mode = UNDERDRIVE;
+ break;
+ }
+ }while(0);
+
+ while(core != gcvCORE_3D_MAX)
+ {
+ struct clk* clk_core = priv->imx_gpu_clks[core].clk_core;
+ struct clk* clk_shader = priv->imx_gpu_clks[core].clk_shader;
+ if(clk_core != NULL && clk_shader != NULL && core_freq != 0 && shader_freq != 0)
+ {
+ clk_set_rate(clk_core,core_freq);
+ clk_set_rate(clk_shader,shader_freq);
+ }
+ core++;
+ }
+ return count;
+}
+
+static DRIVER_ATTR_RW(gpu_mode);
+
+int init_gpu_opp_table(struct device *dev)
+{
+ const struct property *prop;
+ const __be32 *val;
+ int nr;
+ int ret = 0;
+ int govern = 0;
+ int tuple_count = 0;
+ struct imx_priv *priv = &imxPriv;
+ priv->imx_gpu_govern.num_modes = 0;
+ priv->imx_gpu_govern.current_mode = OVERDRIVE;
+
+ prop = of_find_property(dev->of_node, "operating-points", NULL);
+ if (!prop)
+ return -ENODEV;
+ if (!prop->value)
+ return -ENODATA;
+
+ /*
+ * Each OPP is a set of tuples consisting of frequency and
+ * voltage like <freq-kHz vol-uV>.
+ */
+ nr = prop->length / sizeof(u32);
+ if (nr % 2) {
+ dev_err(dev, "%s: Invalid OPP list\n", __func__);
+ return -EINVAL;
+ }
+ tuple_count = nr;
+ val = prop->value;
+ while (nr > 0) {
+ unsigned long core_freq,core_volt,shader_freq,shader_volt;
+ core_freq = be32_to_cpup(val++) * 1000;
+ core_volt = be32_to_cpup(val++);
+ if(nr == 2)
+ {
+ shader_freq = core_freq;
+ shader_volt = core_volt;
+ }
+ else{
+ shader_freq = be32_to_cpup(val++) * 1000;
+ shader_volt = be32_to_cpup(val++);
+ }
+
+ /*We only register core_clk frequency*/
+ if (dev_pm_opp_add(dev, core_freq, core_volt))
+ {
+ dev_warn(dev, "%s: Failed to add OPP %ld\n",
+ __func__, core_freq);
+ nr -= 4;
+ continue;
+ }
+
+ priv->imx_gpu_govern.core_clk_freq[govern] = core_freq;
+ priv->imx_gpu_govern.shader_clk_freq[govern] = shader_freq;
+ govern++;
+ priv->imx_gpu_govern.num_modes++;
+ if(govern == GOVERN_COUNT)
+ break;
+
+ nr -= 4;
+ }
+ priv->imx_gpu_govern.dev = dev;
+
+ if(priv->imx_gpu_govern.num_modes > 0)
+ {
+ ret = driver_create_file(dev->driver, &driver_attr_gpu_mode);
+ if (ret)
+ dev_err(dev, "create gpu_mode attr failed (%d)\n", ret);
+ }
+ return ret;
+}
+
+int remove_gpu_opp_table(void)
+{
+ struct imx_priv *priv = &imxPriv;
+ struct device* dev = priv->imx_gpu_govern.dev;
+ int govern = 0;
+ while(govern != priv->imx_gpu_govern.num_modes)
+ {
+ unsigned long core_freq;
+ core_freq = priv->imx_gpu_govern.core_clk_freq[govern];
+ dev_pm_opp_remove(dev,core_freq);
+ govern++;
+ }
+ if(priv->imx_gpu_govern.num_modes > 0)
+ driver_remove_file(dev->driver, &driver_attr_gpu_mode);
+ return 0;
+}
+#endif
+
+#ifdef IMX_GPU_SUBSYSTEM
+
+static int use_imx_gpu_subsystem;
+
+/* sub device component ops. */
+static int mxc_gpu_sub_bind(struct device *dev,
+ struct device *master, void *data)
+{
+ return 0;
+}
+
+static void mxc_gpu_sub_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+}
+
+static const struct component_ops mxc_gpu_sub_ops =
+{
+ .bind = mxc_gpu_sub_bind,
+ .unbind = mxc_gpu_sub_unbind,
+};
+
+/* sub device driver. */
+static const struct of_device_id mxc_gpu_sub_match[] =
+{
+ { .compatible = "fsl,imx8-gpu"},
+ { /* sentinel */ }
+};
+
+static int mxc_gpu_sub_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &mxc_gpu_sub_ops);
+}
+
+static int mxc_gpu_sub_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &mxc_gpu_sub_ops);
+ return 0;
+}
+
+struct platform_driver mxc_gpu_sub_driver =
+{
+ .driver = {
+ .name = "mxc-gpu",
+ .owner = THIS_MODULE,
+ .of_match_table = mxc_gpu_sub_match,
+ },
+
+ .probe = mxc_gpu_sub_probe,
+ .remove = mxc_gpu_sub_remove,
+};
+
+static int register_mxc_gpu_sub_driver(void)
+{
+ return use_imx_gpu_subsystem ? platform_driver_register(&mxc_gpu_sub_driver) : 0;
+}
+
+static void unregister_mxc_gpu_sub_driver(void)
+{
+ if (use_imx_gpu_subsystem) {
+ platform_driver_unregister(&mxc_gpu_sub_driver);
+ }
+}
+
+static int patch_param_imx8_subsystem(struct platform_device *pdev,
+ gcsMODULE_PARAMETERS *args)
+{
+ int i = 0;
+ struct resource* res;
+ struct device_node *node = pdev->dev.of_node;
+ struct device_node *core_node;
+ int core = gcvCORE_MAJOR;
+
+ while ((core_node = of_parse_phandle(node, "cores", i++)) != NULL) {
+ struct platform_device *pdev_gpu;
+ int irqLine = -1;
+
+ if (!of_device_is_available(core_node)) {
+ of_node_put(core_node);
+ continue;
+ }
+
+ pdev_gpu = of_find_device_by_node(core_node);
+
+ if (!pdev_gpu)
+ break;
+
+ irqLine = platform_get_irq(pdev_gpu, 0);
+
+ if (irqLine < 0)
+ break;
+
+ res = platform_get_resource(pdev_gpu, IORESOURCE_MEM, 0);
+
+ if (!res)
+ break;
+
+ args->irqs[core] = irqLine;
+ args->registerBases[core] = res->start;
+ args->registerSizes[core] = res->end - res->start + 1;
+
+ of_node_put(core_node);
+ ++core;
+ }
+
+ if (core_node)
+ of_node_put(core_node);
+
+ return 0;
+}
+
+static inline int get_power_imx8_subsystem(struct device *pdev)
+{
+ struct imx_priv *priv = &imxPriv;
+ struct clk *clk_core = NULL;
+ struct clk *clk_shader = NULL;
+ struct clk *clk_axi = NULL;
+
+ /* Initialize the clock structure */
+ int i = 0;
+ struct device_node *node = pdev->of_node;
+ struct device_node *core_node;
+ int core = gcvCORE_MAJOR;
+
+#if defined(IMX8_SCU_CONTROL)
+ sc_err_t sciErr;
+ uint32_t mu_id;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+
+ if (sciErr != SC_ERR_NONE) {
+ printk("galcore; cannot obtain mu id\n");
+ return -EINVAL;
+ }
+
+ sciErr = sc_ipc_open(&gpu_ipcHandle, mu_id);
+
+ if (sciErr != SC_ERR_NONE) {
+ printk("galcore: cannot open MU channel to SCU\n");
+ return -EINVAL;
+ }
+#endif
+
+ while ((core_node = of_parse_phandle(node, "cores", i++)) != NULL) {
+ struct platform_device *pdev_gpu = NULL;
+ clk_shader = NULL;
+ clk_core = NULL;
+ clk_axi = NULL;
+
+ if (!of_device_is_available(core_node)) {
+ of_node_put(core_node);
+ continue;
+ }
+
+ pdev_gpu = of_find_device_by_node(core_node);
+
+ if (!pdev_gpu)
+ break;
+
+ clk_core = clk_get(&pdev_gpu->dev, "core");
+
+ if (IS_ERR(clk_core)) {
+ printk("galcore: clk_get clk_core failed\n");
+ break;
+ }
+
+ clk_axi = clk_get(&pdev_gpu->dev, "bus");
+
+ if (IS_ERR(clk_axi))
+ clk_axi = NULL;
+
+ clk_shader = clk_get(&pdev_gpu->dev, "shader");
+
+ if (IS_ERR(clk_shader)) {
+ printk("galcore: clk_get clk_3d_shader failed\n");
+ continue;
+ }
+
+#if defined(CONFIG_ANDROID) && LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0)
+ /* TODO: freescale BSP issue in some platform like imx8dv. */
+ clk_prepare(clk_core);
+ clk_set_rate(clk_core, 800000000);
+ clk_unprepare(clk_core);
+
+ clk_prepare(clk_shader);
+ clk_set_rate(clk_shader, 800000000);
+ clk_unprepare(clk_shader);
+#endif
+
+ priv->imx_gpu_clks[core].clk_shader = clk_shader;
+ priv->imx_gpu_clks[core].clk_core = clk_core;
+ priv->imx_gpu_clks[core].clk_axi = clk_axi;
+
+#if defined(IMX8_SCU_CONTROL)
+ if (of_property_read_u32(core_node, "fsl,sc_gpu_pid", &priv->sc_gpu_pid[core])) {
+ priv->sc_gpu_pid[core] = 0;
+ }
+#endif
+
+#ifdef CONFIG_PM
+ pm_runtime_get_noresume(&pdev_gpu->dev);
+ pm_runtime_set_active(&pdev_gpu->dev);
+ pm_runtime_enable(&pdev_gpu->dev);
+ pm_runtime_put_sync(&pdev_gpu->dev);
+ priv->pmdev[core] = &pdev_gpu->dev;
+#endif
+ of_node_put(core_node);
+ ++core;
+ }
+
+ priv->gpu3dCount = core;
+
+ if (core_node)
+ of_node_put(core_node);
+
+ return 0;
+}
+
+#endif
+
+static int patch_param_imx6(struct platform_device *pdev,
+ gcsMODULE_PARAMETERS *args)
+{
+ struct resource* res;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_3d");
+
+ if (res)
+ args->irqLine = res->start;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_3d");
+
+ if (res) {
+ args->registerMemBase = res->start;
+ args->registerMemSize = res->end - res->start + 1;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_2d");
+
+ if (res)
+ args->irqLine2D = res->start;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_2d");
+
+ if (res) {
+ args->registerMemBase2D = res->start;
+ args->registerMemSize2D = res->end - res->start + 1;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq_vg");
+
+ if (res)
+ args->irqLineVG = res->start;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iobase_vg");
+
+ if (res) {
+ args->registerMemBaseVG = res->start;
+ args->registerMemSizeVG = res->end - res->start + 1;
+ }
+
+ return 0;
+}
+
+static int patch_param(struct platform_device *pdev,
+ gcsMODULE_PARAMETERS *args)
+{
+ struct resource* res;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+ struct device_node *dn =pdev->dev.of_node;
+ const u32 *prop;
+#else
+ struct viv_gpu_platform_data *pdata;
+#endif
+
+ pdevice = pdev;
+
+#ifdef IMX_GPU_SUBSYSTEM
+ if (pdev->dev.of_node && use_imx_gpu_subsystem)
+ patch_param_imx8_subsystem(pdev, args);
+ else
+#endif
+ patch_param_imx6(pdev, args);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+ if(args->compression == -1)
+ {
+ const u32 *property;
+ args->compression = gcvCOMPRESSION_OPTION_DEFAULT;
+ property = of_get_property(pdev->dev.of_node, "depth-compression", NULL);
+ if (property && *property == 0)
+ {
+ args->compression &= ~gcvCOMPRESSION_OPTION_DEPTH;
+ }
+ }
+#endif
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phys_baseaddr");
+
+ if (res && !args->baseAddress && !args->physSize) {
+ args->baseAddress = res->start;
+ args->physSize = res->end - res->start + 1;
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "contiguous_mem");
+
+ if (res) {
+ if (args->contiguousBase == 0)
+ args->contiguousBase = res->start;
+
+ if (args->contiguousSize == ~0U)
+ args->contiguousSize = res->end - res->start + 1;
+ }
+
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+ args->contiguousBase = 0;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+ prop = of_get_property(dn, "contiguousbase", NULL);
+
+ if (prop)
+ args->contiguousBase = *prop;
+
+ of_property_read_u32(dn,"contiguoussize", (u32 *)&contiguousSize);
+#else
+
+ pdata = pdev->dev.platform_data;
+
+ if (pdata) {
+ args->contiguousBase = pdata->reserved_mem_base;
+ args->contiguousSize = pdata->reserved_mem_size;
+ }
+
+#endif
+
+ if (args->contiguousSize == ~0U) {
+ printk("Warning: No contiguous memory is reserverd for gpu.!\n");
+ printk("Warning: Will use default value(%d) for the reserved memory!\n", gcdFSL_CONTIGUOUS_SIZE);
+
+ args->contiguousSize = gcdFSL_CONTIGUOUS_SIZE;
+ }
+
+ args->gpu3DMinClock = initgpu3DMinClock;
+
+ if (args->physSize == 0) {
+#if defined(IMX8_PHYS_BASE)
+ args->baseAddress = IMX8_PHYS_BASE;
+#endif
+
+#if defined(IMX8_PHYS_SIZE)
+ args->physSize = IMX8_PHYS_SIZE;
+#else
+ args->physSize = 0x80000000;
+#endif
+ }
+
+ return 0;
+}
+
+int init_priv(void)
+{
+ memset(&imxPriv, 0, sizeof(imxPriv));
+
+#ifdef CONFIG_GPU_LOW_MEMORY_KILLER
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
+ task_free_register(&task_nb);
+# else
+ task_handoff_register(&task_nb);
+# endif
+#endif
+
+ return 0;
+}
+
+void
+free_priv(void)
+{
+#ifdef CONFIG_GPU_LOW_MEMORY_KILLER
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0)
+ task_free_unregister(&task_nb);
+# else
+ task_handoff_unregister(&task_nb);
+# endif
+#endif
+}
+
+static int set_clock(int gpu, int enable);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+static void imx6sx_optimize_qosc_for_GPU(void)
+{
+ struct device_node *np;
+ void __iomem *src_base;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-qosc");
+ if (!np)
+ return;
+
+ src_base = of_iomap(np, 0);
+ WARN_ON(!src_base);
+
+ set_clock(gcvCORE_MAJOR, 1);
+
+ writel_relaxed(0, src_base); /* Disable clkgate & soft_rst */
+ writel_relaxed(0, src_base+0x60); /* Enable all masters */
+ writel_relaxed(0, src_base+0x1400); /* Disable clkgate & soft_rst for gpu */
+ writel_relaxed(0x0f000222, src_base+0x1400+0xd0); /* Set Write QoS 2 for gpu */
+ writel_relaxed(0x0f000822, src_base+0x1400+0xe0); /* Set Read QoS 8 for gpu */
+
+ set_clock(gcvCORE_MAJOR, 0);
+ return;
+}
+#endif
+
+static inline int get_power_imx6(struct device *pdev)
+{
+ struct imx_priv *priv = &imxPriv;
+ struct clk *clk_core = NULL;
+ struct clk *clk_shader = NULL;
+ struct clk *clk_axi = NULL;
+ struct clk *clk_ahb = NULL;
+
+#ifdef CONFIG_RESET_CONTROLLER
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+ struct reset_control *rstc;
+
+ rstc = devm_reset_control_get(pdev, "gpu3d");
+ priv->rstc[gcvCORE_MAJOR] = IS_ERR(rstc) ? NULL : rstc;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0)
+ rstc = devm_reset_control_get_shared(pdev, "gpu2d");
+ priv->rstc[gcvCORE_2D] = IS_ERR(rstc) ? NULL : rstc;
+ rstc = devm_reset_control_get_shared(pdev, "gpuvg");
+# else
+ rstc = devm_reset_control_get(pdev, "gpu2d");
+ priv->rstc[gcvCORE_2D] = IS_ERR(rstc) ? NULL : rstc;
+ rstc = devm_reset_control_get(pdev, "gpuvg");
+# endif
+ priv->rstc[gcvCORE_VG] = IS_ERR(rstc) ? NULL : rstc;
+# endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
+ /* Get gpu regulator */
+ priv->gpu_regulator = regulator_get(pdev, "cpu_vddgpu");
+# elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+ priv->gpu_regulator = devm_regulator_get(pdev, "pu");
+# endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+ if (IS_ERR(priv->gpu_regulator)) {
+ printk("%s: Failed to get gpu regulator\n", __FUNCTION__);
+ return -ENXIO;
+ }
+# endif
+#endif
+
+ clk_core = clk_get(pdev, "gpu3d_clk");
+
+ if (!IS_ERR(clk_core)) {
+ clk_axi = clk_get(pdev, "gpu3d_axi_clk");
+ clk_shader = clk_get(pdev, "gpu3d_shader_clk");
+
+ if (IS_ERR(clk_shader)) {
+ clk_put(clk_core);
+ clk_core = NULL;
+ clk_shader = NULL;
+ printk("galcore: clk_get gpu3d_shader_clk failed, disable 3d!\n");
+ }
+
+ clk_ahb = clk_get(pdev, "gpu3d_ahb_clk");
+ if (IS_ERR(clk_ahb)) {
+ clk_ahb = NULL;
+ }
+ } else {
+ clk_core = NULL;
+ printk("galcore: clk_get gpu3d_clk failed, disable 3d!\n");
+ }
+
+ priv->imx_gpu_clks[gcvCORE_MAJOR].clk_core = clk_core;
+ priv->imx_gpu_clks[gcvCORE_MAJOR].clk_shader = clk_shader;
+ priv->imx_gpu_clks[gcvCORE_MAJOR].clk_axi = clk_axi;
+ priv->imx_gpu_clks[gcvCORE_MAJOR].clk_ahb = clk_ahb;
+
+ clk_core = clk_get(pdev, "gpu2d_clk");
+
+ if (IS_ERR(clk_core)) {
+ clk_core = NULL;
+ printk("galcore: clk_get 2d core clock failed, disable 2d/vg!\n");
+ } else {
+ clk_axi = clk_get(pdev, "gpu2d_axi_clk");
+ if (IS_ERR(clk_axi)) {
+ clk_axi = NULL;
+ printk("galcore: clk_get 2d axi clock failed, disable 2d\n");
+ }
+ clk_ahb = clk_get(pdev, "gpu2d_ahb_clk");
+ if (IS_ERR(clk_ahb)) {
+ clk_ahb = NULL;
+ }
+
+ priv->imx_gpu_clks[gcvCORE_2D].clk_ahb = clk_ahb;
+ priv->imx_gpu_clks[gcvCORE_2D].clk_core = clk_core;
+ priv->imx_gpu_clks[gcvCORE_2D].clk_axi = clk_axi;
+
+ clk_axi = clk_get(pdev, "openvg_axi_clk");
+
+ if (IS_ERR(clk_axi)) {
+ clk_axi = NULL;
+ printk("galcore: clk_get vg clock failed, disable vg!\n");
+ }
+
+ priv->imx_gpu_clks[gcvCORE_VG].clk_core = clk_core;
+ priv->imx_gpu_clks[gcvCORE_VG].clk_axi = clk_axi;
+ }
+
+#ifdef CONFIG_PM
+ pm_runtime_enable(pdev);
+
+ priv->pmdev[gcvCORE_MAJOR] = pdev;
+ priv->pmdev[gcvCORE_2D] = pdev;
+ priv->pmdev[gcvCORE_VG] = pdev;
+#endif
+
+ return 0;
+}
+
+static inline int get_power(struct device *pdev)
+{
+ int ret;
+
+ /*Initialize the clock structure*/
+#ifdef IMX_GPU_SUBSYSTEM
+ if (pdev->of_node && use_imx_gpu_subsystem)
+ ret = get_power_imx8_subsystem(pdev);
+ else
+#endif
+ ret = get_power_imx6(pdev);
+
+ if (ret)
+ return ret;
+
+#if gcdENABLE_FSCALE_VAL_ADJUST && (defined(CONFIG_DEVICE_THERMAL) || defined(CONFIG_DEVICE_THERMAL_MODULE))
+ REG_THERMAL_NOTIFIER(&thermal_hot_pm_notifier);
+
+ ret = driver_create_file(pdev->driver, &driver_attr_gpu3DMinClock);
+
+ if (ret)
+ dev_err(pdev, "create gpu3DMinClock attr failed (%d)\n", ret);
+#endif
+
+#if defined(CONFIG_PM_OPP)
+ init_gpu_opp_table(pdev);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+ imx6sx_optimize_qosc_for_GPU();
+#endif
+
+ return 0;
+}
+
+static inline void put_power(void)
+{
+ int core = 0;
+ struct gpu_clk *imx_clk = NULL;
+ struct imx_priv *priv = &imxPriv;
+ struct device *pmdev_last = NULL;/*legacy gpu device entry for imx6*/
+ struct clk *clk_core_last = NULL;/*vg has same core clk as 2d */
+
+ for (core = 0; core < gcdMAX_GPU_COUNT; core++) {
+ imx_clk = &priv->imx_gpu_clks[core];
+
+ if (imx_clk->clk_core && imx_clk->clk_core != clk_core_last) {
+ clk_put(imx_clk->clk_core);
+ clk_core_last = imx_clk->clk_core;
+ imx_clk->clk_core = NULL;
+ }
+
+ if (imx_clk->clk_shader) {
+ clk_put(imx_clk->clk_shader);
+ imx_clk->clk_shader = NULL;
+ }
+
+ if (imx_clk->clk_axi) {
+ clk_put(imx_clk->clk_axi);
+ imx_clk->clk_axi = NULL;
+ }
+
+ if (imx_clk->clk_ahb) {
+ clk_put(imx_clk->clk_ahb);
+ imx_clk->clk_ahb = NULL;
+ }
+
+#ifdef CONFIG_PM
+ if (priv->pmdev[core] && priv->pmdev[core] != pmdev_last){
+ pm_runtime_disable(priv->pmdev[core]);
+ pmdev_last = priv->pmdev[core];
+ }
+#endif
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
+ if (priv->gpu_regulator) {
+ regulator_put(priv->gpu_regulator);
+ priv->gpu_regulator = NULL;
+ }
+#endif
+
+#if gcdENABLE_FSCALE_VAL_ADJUST && (defined(CONFIG_DEVICE_THERMAL) || defined(CONFIG_DEVICE_THERMAL_MODULE))
+ UNREG_THERMAL_NOTIFIER(&thermal_hot_pm_notifier);
+
+ driver_remove_file(pdevice->dev.driver, &driver_attr_gpu3DMinClock);
+#endif
+
+#if defined(CONFIG_PM_OPP)
+ remove_gpu_opp_table();
+#endif
+
+#if defined(IMX8_SCU_CONTROL)
+ if (gpu_ipcHandle)
+ sc_ipc_close(gpu_ipcHandle);
+#endif
+}
+
+static inline int set_power(int gpu, int enable)
+{
+#ifdef CONFIG_PM
+ struct imx_priv* priv = &imxPriv;
+#endif
+
+ if (enable) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+ if (!IS_ERR(priv->gpu_regulator)) {
+ int ret = regulator_enable(priv->gpu_regulator);
+
+ if (ret)
+ printk("%s: fail to enable pu regulator %d!\n", __FUNCTION__, ret);
+ }
+# else
+ imx_gpc_power_up_pu(true);
+# endif
+#endif
+
+#ifdef CONFIG_PM
+ pm_runtime_get_sync(priv->pmdev[gpu]);
+#endif
+
+#if defined(IMX8_SCU_CONTROL)
+ if (priv->sc_gpu_pid[gpu]) {
+ sc_err_t sciErr = sc_misc_set_control(gpu_ipcHandle, priv->sc_gpu_pid[gpu], SC_C_ID, gpu);
+ if (sciErr != SC_ERR_NONE)
+ printk("galcore: failed to set gpu id for 3d_%d\n", gpu);
+
+ if (priv->gpu3dCount > 1) {
+ sciErr = sc_misc_set_control(gpu_ipcHandle, priv->sc_gpu_pid[gpu], SC_C_SINGLE_MODE, 0);
+ if (sciErr != SC_ERR_NONE)
+ printk("galcore: failed to set gpu dual mode for 3d_%d\n", gpu);
+ } else {
+ sciErr = sc_misc_set_control(gpu_ipcHandle, priv->sc_gpu_pid[gpu], SC_C_SINGLE_MODE, 1);
+ if (sciErr != SC_ERR_NONE)
+ printk("galcore: failed to set gpu single mode for 3d_%d\n", gpu);
+ }
+ }
+#endif
+ } else {
+#ifdef CONFIG_PM
+ pm_runtime_put_sync(priv->pmdev[gpu]);
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+ if (!IS_ERR(priv->gpu_regulator))
+ regulator_disable(priv->gpu_regulator);
+# else
+ imx_gpc_power_up_pu(false);
+# endif
+#endif
+ }
+
+ return 0;
+}
+
+int set_clock(int gpu, int enable)
+{
+ struct imx_priv* priv = &imxPriv;
+ struct clk *clk_core = priv->imx_gpu_clks[gpu].clk_core;
+ struct clk *clk_shader = priv->imx_gpu_clks[gpu].clk_shader;
+ struct clk *clk_axi = priv->imx_gpu_clks[gpu].clk_axi;
+ struct clk *clk_ahb = priv->imx_gpu_clks[gpu].clk_ahb;
+
+ if (enable) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+ if (clk_core)
+ clk_prepare(clk_core);
+
+ if (clk_shader)
+ clk_prepare(clk_shader);
+
+ if (clk_axi)
+ clk_prepare(clk_axi);
+
+ if (clk_ahb)
+ clk_prepare(clk_ahb);
+#endif
+ if (clk_core)
+ clk_enable(clk_core);
+
+ if (clk_shader)
+ clk_enable(clk_shader);
+
+ if (clk_axi)
+ clk_enable(clk_axi);
+
+ if (clk_ahb)
+ clk_enable(clk_ahb);
+ } else {
+ if (clk_core)
+ clk_disable(clk_core);
+
+ if (clk_shader)
+ clk_disable(clk_shader);
+
+ if (clk_axi)
+ clk_disable(clk_axi);
+
+ if (clk_ahb)
+ clk_disable(clk_ahb);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+ if (clk_core)
+ clk_unprepare(clk_core);
+
+ if (clk_shader)
+ clk_unprepare(clk_shader);
+
+ if (clk_axi)
+ clk_unprepare(clk_axi);
+
+ if (clk_ahb)
+ clk_unprepare(clk_ahb);
+#endif
+ }
+
+ return gcvSTATUS_OK;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+#ifdef CONFIG_PM
+static int gpu_runtime_suspend(struct device *dev)
+{
+ release_bus_freq(BUS_FREQ_HIGH);
+ return 0;
+}
+
+static int gpu_runtime_resume(struct device *dev)
+{
+ request_bus_freq(BUS_FREQ_HIGH);
+ return 0;
+}
+
+static struct dev_pm_ops gpu_pm_ops;
+#endif
+#endif
+
+
+static int adjust_platform_driver(struct platform_driver *driver)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+ driver->driver.of_match_table = mxs_gpu_dt_ids;
+#endif
+
+#ifdef CONFIG_PM
+ /* Override PM callbacks to add runtime PM callbacks. */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
+ /* Fill local structure with original value. */
+ memcpy(&gpu_pm_ops, driver->driver.pm, sizeof(struct dev_pm_ops));
+
+ /* Add runtime PM callback. */
+#ifdef CONFIG_PM
+ gpu_pm_ops.runtime_suspend = gpu_runtime_suspend;
+ gpu_pm_ops.runtime_resume = gpu_runtime_resume;
+ gpu_pm_ops.runtime_idle = NULL;
+#endif
+
+ /* Replace callbacks. */
+ driver->driver.pm = &gpu_pm_ops;
+#endif
+#endif
+
+ return 0;
+}
+
+#define SRC_SCR_OFFSET 0
+#define BP_SRC_SCR_GPU3D_RST 1
+#define BP_SRC_SCR_GPU2D_RST 4
+
+static inline int reset_gpu(int gpu)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0)
+ void __iomem *src_base = IO_ADDRESS(SRC_BASE_ADDR);
+ uint32_t bit_offset, val;
+
+ if (gpu == gcvCORE_MAJOR)
+ bit_offset = BP_SRC_SCR_GPU3D_RST;
+ else if ((gpu == gcvCORE_VG) ||(gpu == gcvCORE_2D))
+ bit_offset = BP_SRC_SCR_GPU2D_RST;
+ else
+ return -ENXIO;
+
+ val = __raw_readl(src_base + SRC_SCR_OFFSET);
+ val &= ~(1 << (bit_offset));
+ val |= (1 << (bit_offset));
+ __raw_writel(val, src_base + SRC_SCR_OFFSET);
+
+ while ((__raw_readl(src_base + SRC_SCR_OFFSET) & (1 << (bit_offset))) != 0);
+
+ return -ENODEV;
+
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
+ struct imx_priv* priv = &imxPriv;
+ struct reset_control *rstc = priv->rstc[gpu];
+
+ if (rstc)
+ reset_control_reset(rstc);
+#else
+ imx_src_reset_gpu((int)gpu);
+#endif
+
+ return 0;
+}
+
+static gceSTATUS
+_AdjustParam(
+ gcsPLATFORM * Platform,
+ gcsMODULE_PARAMETERS *Args
+ )
+{
+ patch_param(Platform->device, Args);
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_GetPower(
+ gcsPLATFORM * Platform
+ )
+{
+ int ret = get_power(&Platform->device->dev);
+
+ if (ret)
+ return gcvSTATUS_GENERIC_IO;
+
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_PutPower(
+ gcsPLATFORM * Platform
+ )
+{
+ put_power();
+ return gcvSTATUS_OK;
+}
+
+
+static gceSTATUS
+_SetPower(
+ gcsPLATFORM * Platform,
+ gceCORE GPU,
+ gctBOOL Enable
+ )
+{
+ return set_power((int)GPU, Enable) ? gcvSTATUS_GENERIC_IO
+ : gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_SetClock(
+ gcsPLATFORM * Platform,
+ gceCORE GPU,
+ gctBOOL Enable
+ )
+{
+ set_clock((int)GPU, Enable);
+ return gcvSTATUS_OK;
+}
+
+static gceSTATUS
+_Reset(
+ gcsPLATFORM * Platform,
+ gceCORE GPU
+ )
+{
+ int ret;
+
+ ret = reset_gpu((int)GPU);
+
+ if (!ret)
+ return gcvSTATUS_OK;
+ else if (ret == -ENODEV)
+ return gcvSTATUS_NOT_SUPPORTED;
+ else
+ return gcvSTATUS_INVALID_CONFIG;
+}
+
+struct soc_platform_ops imx_platform_ops =
+{
+ .adjustParam = _AdjustParam,
+ .getPower = _GetPower,
+ .putPower = _PutPower,
+ .setPower = _SetPower,
+ .setClock = _SetClock,
+ .reset = _Reset,
+#ifdef CONFIG_GPU_LOW_MEMORY_KILLER
+ .shrinkMemory = _ShrinkMemory,
+#endif
+};
+
+static struct soc_platform imx_platform =
+{
+ .name = __FILE__,
+ .ops = &imx_platform_ops,
+};
+
+int soc_platform_init(struct platform_driver *pdrv,
+ struct soc_platform **platform)
+{
+#ifdef IMX_GPU_SUBSYSTEM
+ if (of_find_compatible_node(NULL, NULL, "fsl,imx8-gpu-ss")) {
+ use_imx_gpu_subsystem = 1;
+ }
+
+ if (of_find_compatible_node(NULL, NULL, "fsl,imx8x-gpu")) {
+ printk(KERN_ERR "Incorrect device-tree, please update dtb.");
+ return -EINVAL;
+ }
+#endif
+
+ adjust_platform_driver(pdrv);
+ init_priv();
+
+#ifdef IMX_GPU_SUBSYSTEM
+ register_mxc_gpu_sub_driver();
+#endif
+
+ *platform = &imx_platform;
+ return 0;
+}
+
+int soc_platform_terminate(struct soc_platform *platform)
+{
+#ifdef IMX_GPU_SUBSYSTEM
+ unregister_mxc_gpu_sub_driver();
+#endif
+
+ free_priv();
+ return 0;
+}
+
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/freescale/gc_hal_kernel_platform_imx.config b/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/freescale/gc_hal_kernel_platform_imx.config
new file mode 100644
index 000000000000..396ae1de8741
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/platform/freescale/gc_hal_kernel_platform_imx.config
@@ -0,0 +1,27 @@
+EXTRA_CFLAGS += -DgcdDEFAULT_CONTIGUOUS_SIZE=~0U
+EXTRA_CFLAGS += -DgcdFSL_CONTIGUOUS_SIZE=134217728
+
+ifneq ($(CONFIG_ANDROID),)
+# build for android
+EXTRA_CFLAGS += -DgcdANDROID_NATIVE_FENCE_SYNC=2
+EXTRA_CFLAGS += -DgcdANDROID
+ifeq ($(CONFIG_SYNC)$(CONFIG_SYNC_FILE),)
+$(warn CONFIG_SYNC or CONFIG_SYNC_FILE is not set in kernel config)
+$(warn Android native fence sync requires CONFIG_SYNC or CONFIG_SYNC_FILE)
+endif
+endif
+
+ifneq ($(CONFIG_ARCH_FSL_IMX8QM),)
+EXTRA_CFLAGS += -DIMX8_SCU_CONTROL=1 -DIMX8_PHYS_BASE=0x80000000 -DIMX8_PHYS_SIZE=0x80000000
+endif
+
+EXTRA_CFLAGS += -DLINUX_CMA_FSL=1
+ALLOCATOR_ARRAY_H_LOCATION := $(OS_KERNEL_DIR)/allocator/freescale
+CUSTOMER_ALLOCATOR_OBJS := $(ALLOCATOR_ARRAY_H_LOCATION)/gc_hal_kernel_allocator_cma.o
+
+EXTRA_CFLAGS += -DCLASS_NAME=\"gpu_class\"
+
+EXTRA_CFLAGS += -DgcdGPU_2D_TIMEOUT=20000
+EXTRA_CFLAGS += -DNO_DMA_COHERENT=1
+EXTRA_CFLAGS += -DgcdSYS_FREE_MEMORY_LIMIT=51200
+
diff --git a/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta.c b/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta.c
new file mode 100644
index 000000000000..7b677e43a543
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta.c
@@ -0,0 +1,348 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_types.h"
+#include "gc_hal_base.h"
+#include "gc_hal_security_interface.h"
+#include "gc_hal_ta.h"
+#include "gc_hal.h"
+
+#define _GC_OBJ_ZONE gcvZONE_KERNEL
+
+/*
+* Responsibility of TA (trust application).
+* 1) Start FE.
+* When non secure driver asks for start FE. TA enable MMU and start FE.
+* TA always execute MMU enable processes because it has no idea whether
+* GPU has been power off.
+*
+* 2) Setup page table
+* When non secure driver asks for set up GPU address to physical address
+* mapping, TA check the attribute of physical address and attribute of
+* GPU address to make sure they are match. Then it change page table.
+*
+*/
+
+gcTA_MMU SharedMmu = gcvNULL;
+
+/*******************************************************************************
+**
+** gcTA_Construct
+**
+** Construct a new gcTA object.
+*/
+int
+gcTA_Construct(
+ IN gctaOS Os,
+ IN gceCORE Core,
+ OUT gcTA *TA
+ )
+{
+ gceSTATUS status;
+ gctPOINTER pointer;
+ gcTA ta = gcvNULL;
+
+ gcmkHEADER();
+ gcmkVERIFY_ARGUMENT(TA != gcvNULL);
+
+ /* Construct a gcTA object. */
+ gcmkONERROR(gctaOS_Allocate(sizeof(struct _gcTA), &pointer));
+
+ gctaOS_ZeroMemory(pointer, sizeof(struct _gcTA));
+
+ ta = (gcTA)pointer;
+
+ ta->os = Os;
+ ta->core = Core;
+
+ gcmkONERROR(gctaHARDWARE_Construct(ta, &ta->hardware));
+
+ if (gctaHARDWARE_IsFeatureAvailable(ta->hardware, gcvFEATURE_SECURITY))
+ {
+ if (SharedMmu == gcvNULL)
+ {
+ gcmkONERROR(gctaMMU_Construct(ta, &ta->mmu));
+
+ /* Record shared MMU. */
+ SharedMmu = ta->mmu;
+ ta->destoryMmu = gcvTRUE;
+ }
+ else
+ {
+ ta->mmu = SharedMmu;
+ ta->destoryMmu = gcvFALSE;
+ }
+
+ gcmkONERROR(gctaHARDWARE_PrepareFunctions(ta->hardware));
+ }
+
+ *TA = ta;
+
+ gcmkFOOTER_NO();
+ return 0;
+
+OnError:
+ if (ta)
+ {
+ if (ta->mmu && ta->destoryMmu)
+ {
+ gcmkVERIFY_OK(gctaMMU_Destory(ta->mmu));
+ }
+
+ if (ta->hardware)
+ {
+ gcmkVERIFY_OK(gctaHARDWARE_Destroy(ta->hardware));
+ }
+
+ gcmkVERIFY_OK(gctaOS_Free(ta));
+ }
+ gcmkFOOTER();
+ return status;
+}
+
+/*******************************************************************************
+**
+** gcTA_Construct
+**
+** Destroy a gcTA object.
+*/
+int
+gcTA_Destroy(
+ IN gcTA TA
+ )
+{
+ if (TA->mmu && TA->destoryMmu)
+ {
+ gcmkVERIFY_OK(gctaMMU_Destory(TA->mmu));
+ }
+
+ if (TA->hardware)
+ {
+ gcmkVERIFY_OK(gctaHARDWARE_Destroy(TA->hardware));
+ }
+
+ gcmkVERIFY_OK(gctaOS_Free(TA));
+
+ /* Destroy. */
+ return 0;
+}
+
+
+/*
+* Map a scatter gather list into gpu address space.
+*
+*/
+gceSTATUS
+gcTA_MapMemory(
+ IN gcTA TA,
+ IN gctUINT32 *PhysicalArray,
+ IN gctPHYS_ADDR_T Physical,
+ IN gctUINT32 PageCount,
+ OUT gctUINT32 *GPUAddress
+ )
+{
+ gceSTATUS status;
+ gcTA_MMU mmu;
+ gctUINT32 pageCount = PageCount;
+ gctUINT32 i;
+ gctUINT32 gpuAddress = *GPUAddress;
+ gctBOOL mtlbSecure = gcvFALSE;
+ gctBOOL physicalSecure = gcvFALSE;
+
+ mmu = TA->mmu;
+
+ /* Fill in page table. */
+ for (i = 0; i < pageCount; i++)
+ {
+ gctUINT32 physical;
+ gctUINT32_PTR entry;
+
+ if (PhysicalArray)
+ {
+ physical = PhysicalArray[i];
+ }
+ else
+ {
+ physical = (gctUINT32)Physical + 4096 * i;
+ }
+
+ gcmkONERROR(gctaMMU_GetPageEntry(mmu, gpuAddress, gcvNULL, &entry, &mtlbSecure));
+
+ status = gctaOS_IsPhysicalSecure(TA->os, physical, &physicalSecure);
+
+ if (gcmIS_SUCCESS(status) && physicalSecure != mtlbSecure)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ gctaMMU_SetPage(mmu, physical, entry);
+
+ gpuAddress += 4096;
+ }
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+gceSTATUS
+gcTA_UnmapMemory(
+ IN gcTA TA,
+ IN gctUINT32 GPUAddress,
+ IN gctUINT32 PageCount
+ )
+{
+ gceSTATUS status;
+
+ gcmkONERROR(gctaMMU_FreePages(TA->mmu, GPUAddress, PageCount));
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+gceSTATUS
+gcTA_StartCommand(
+ IN gcTA TA,
+ IN gctUINT32 Address,
+ IN gctUINT32 Bytes
+ )
+{
+ gctaHARDWARE_Execute(TA, Address, Bytes);
+ return gcvSTATUS_OK;
+}
+
+int
+gcTA_Dispatch(
+ IN gcTA TA,
+ IN gcsTA_INTERFACE * Interface
+ )
+{
+ int command = Interface->command;
+
+ gceSTATUS status = gcvSTATUS_OK;
+
+ switch (command)
+ {
+ case KERNEL_START_COMMAND:
+ /* Enable MMU every time FE starts.
+ ** Because if normal world stop GPU and power off GPU, MMU states is reset.
+ */
+ gcmkONERROR(gctaHARDWARE_SetMMU(TA->hardware, TA->mmu->mtlbLogical));
+
+ gcmkONERROR(gcTA_StartCommand(
+ TA,
+ Interface->u.StartCommand.address,
+ Interface->u.StartCommand.bytes
+ ));
+ break;
+
+ case KERNEL_MAP_MEMORY:
+ gcmkONERROR(gcTA_MapMemory(
+ TA,
+ Interface->u.MapMemory.physicals,
+ Interface->u.MapMemory.physical,
+ Interface->u.MapMemory.pageCount,
+ &Interface->u.MapMemory.gpuAddress
+ ));
+
+ break;
+
+ case KERNEL_UNMAP_MEMORY:
+ status = gcTA_UnmapMemory(
+ TA,
+ Interface->u.UnmapMemory.gpuAddress,
+ Interface->u.UnmapMemory.pageCount
+ );
+ break;
+
+ case KERNEL_DUMP_MMU_EXCEPTION:
+ status = gctaHARDWARE_DumpMMUException(TA->hardware);
+ break;
+
+ case KERNEL_HANDLE_MMU_EXCEPTION:
+ status = gctaHARDWARE_HandleMMUException(
+ TA->hardware,
+ Interface->u.HandleMMUException.mmuStatus,
+ Interface->u.HandleMMUException.physical,
+ Interface->u.HandleMMUException.gpuAddress
+ );
+ break;
+
+ case KERNEL_READ_MMU_EXCEPTION:
+ status = gctaHARDWARE_ReadMMUException(
+ TA->hardware,
+ &Interface->u.ReadMMUException.mmuStatus,
+ &Interface->u.ReadMMUException.mmuException
+ );
+ break;
+
+ default:
+ gcmkASSERT(0);
+
+ status = gcvSTATUS_INVALID_ARGUMENT;
+ break;
+ }
+
+OnError:
+ Interface->result = status;
+
+ return 0;
+}
+
+
+
diff --git a/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta.h b/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta.h
new file mode 100644
index 000000000000..a29513bd2877
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta.h
@@ -0,0 +1,373 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef _GC_HAL_TA_H_
+#define _GC_HAL_TA_H_
+#include "gc_hal_types.h"
+#include "gc_hal_security_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct _gctaOS * gctaOS;
+typedef struct _gcTA * gcTA;
+
+typedef struct _gcTA_HARDWARE * gcTA_HARDWARE;
+typedef struct _gcTA_MMU * gcTA_MMU;
+
+/*
+ Trust Application is a object needed to be created as a context in trust zone.
+ One client for a core.
+*/
+typedef struct _gcTA {
+ /* gctaOS object */
+ gctaOS os;
+
+ gceCORE core;
+
+ gcTA_MMU mmu;
+
+ gcTA_HARDWARE hardware;
+
+ gctBOOL destoryMmu;
+} gcsTA;
+
+typedef struct _gcTA_MMU
+{
+ gctaOS os;
+
+ gctSIZE_T mtlbBytes;
+ gctPOINTER mtlbLogical;
+ gctPHYS_ADDR mtlbPhysical;
+
+ gctPOINTER stlbs;
+
+ gctPOINTER safePageLogical;
+ gctPHYS_ADDR safePagePhysical;
+
+ gctPOINTER nonSecureSafePageLogical;
+ gctPHYS_ADDR nonSecureSafePagePhysical;
+
+ gctPOINTER mutex;
+}
+gcsTA_MMU;
+
+gceSTATUS HALDECL
+TAEmulator(
+ gceCORE Core,
+ void * Interface
+ );
+
+int
+gcTA_Construct(
+ IN gctaOS Os,
+ IN gceCORE Core,
+ OUT gcTA *TA
+);
+
+int
+gcTA_Destroy(
+ IN gcTA TA
+);
+
+int
+gcTA_Dispatch(
+ IN gcTA TA,
+ IN OUT gcsTA_INTERFACE * Interface
+);
+
+/*************************************
+* Porting layer
+*/
+
+gceSTATUS
+gctaOS_ConstructOS(
+ IN gckOS Os,
+ OUT gctaOS *TAos
+ );
+
+gceSTATUS
+gctaOS_DestroyOS(
+ IN gctaOS Os
+ );
+
+gceSTATUS
+gctaOS_Allocate(
+ IN gctUINT32 Bytes,
+ OUT gctPOINTER *Pointer
+ );
+
+gceSTATUS
+gctaOS_Free(
+ IN gctPOINTER Pointer
+ );
+
+gceSTATUS
+gctaOS_AllocateSecurityMemory(
+ IN gctaOS Os,
+ IN gctSIZE_T *Bytes,
+ OUT gctPOINTER *Logical,
+ OUT gctPOINTER *Physical
+ );
+
+gceSTATUS
+gctaOS_FreeSecurityMemory(
+ IN gctaOS Os,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical,
+ OUT gctPOINTER Physical
+ );
+
+gceSTATUS
+gctaOS_AllocateNonSecurityMemory(
+ IN gctaOS Os,
+ IN gctSIZE_T *Bytes,
+ OUT gctPOINTER *Logical,
+ OUT gctPOINTER *Physical
+ );
+
+gceSTATUS
+gctaOS_FreeNonSecurityMemory(
+ IN gctaOS Os,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical,
+ OUT gctPOINTER Physical
+ );
+
+
+
+gceSTATUS
+gctaOS_GetPhysicalAddress(
+ IN gctaOS Os,
+ IN gctPOINTER Logical,
+ OUT gctPHYS_ADDR_T * Physical
+ );
+
+gceSTATUS gctaOS_WriteRegister(
+ IN gctaOS Os, IN gceCORE Core,
+ IN gctUINT32 Address,
+ IN gctUINT32 Data
+ );
+
+gceSTATUS gctaOS_ReadRegister(
+ IN gctaOS Os, IN gceCORE Core,
+ IN gctUINT32 Address,
+ IN gctUINT32 *Data
+ );
+
+gceSTATUS
+gctaOS_MemCopy(
+ IN gctUINT8_PTR Dest,
+ IN gctUINT8_PTR Src,
+ IN gctUINT32 Bytes
+ );
+
+gceSTATUS
+gctaOS_ZeroMemory(
+ IN gctUINT8_PTR Dest,
+ IN gctUINT32 Bytes
+ );
+
+void
+gctaOS_CacheFlush(
+ IN gctUINT8_PTR Dest,
+ IN gctUINT32 Bytes
+ );
+
+void
+gctaOS_CacheClean(
+ IN gctUINT8_PTR Dest,
+ IN gctUINT32 Bytes
+ );
+
+void
+gctaOS_CacheInvalidate(
+ IN gctUINT8_PTR Dest,
+ IN gctUINT32 Bytes
+ );
+
+gceSTATUS
+gctaOS_IsPhysicalSecure(
+ IN gctaOS Os,
+ IN gctUINT32 Physical,
+ OUT gctBOOL *Secure
+ );
+
+gceSTATUS
+gctaOS_Delay(
+ IN gctaOS Os,
+ IN gctUINT32 Delay
+ );
+
+gceSTATUS
+gctaOS_SetGPUPower(
+ IN gctaOS Os,
+ IN gctUINT32 Core,
+ IN gctBOOL Clock,
+ IN gctBOOL Power
+ );
+
+/*
+** gctaHARDWARE
+*/
+gceSTATUS
+gctaHARDWARE_Construct(
+ IN gcTA TA,
+ OUT gcTA_HARDWARE * Hardware
+ );
+
+gceSTATUS
+gctaHARDWARE_Destroy(
+ IN gcTA_HARDWARE Hardware
+ );
+
+gceSTATUS
+gctaHARDWARE_Execute(
+ IN gcTA TA,
+ IN gctUINT32 Address,
+ IN gctUINT32 Bytes
+ );
+
+gceSTATUS
+gctaHARDWARE_End(
+ IN gcTA_HARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN OUT gctUINT32 * Bytes
+ );
+
+gceSTATUS
+gctaHARDWARE_SetMMU(
+ IN gcTA_HARDWARE Hardware,
+ IN gctPOINTER Logical
+ );
+
+gceSTATUS
+gctaHARDWARE_IsFeatureAvailable(
+ IN gcTA_HARDWARE Hardware,
+ IN gceFEATURE Feature
+ );
+
+gceSTATUS
+gctaHARDWARE_PrepareFunctions(
+ IN gcTA_HARDWARE Hardware
+ );
+
+gceSTATUS
+gctaHARDWARE_DumpMMUException(
+ IN gcTA_HARDWARE Hardware
+ );
+
+gceSTATUS
+gctaHARDWARE_HandleMMUException(
+ IN gcTA_HARDWARE Hardware,
+ IN gctUINT32 MMUStatus,
+ IN gctPHYS_ADDR_T Physical,
+ IN gctUINT32 GPUAddress
+ );
+
+gceSTATUS
+gctaHARDWARE_ReadMMUException(
+ IN gcTA_HARDWARE Hardware,
+ OUT gctUINT32_PTR MMUStatus,
+ OUT gctUINT32_PTR MMUException
+ );
+
+gceSTATUS
+gctaMMU_Construct(
+ IN gcTA TA,
+ OUT gcTA_MMU *Mmu
+ );
+
+gceSTATUS
+gctaMMU_Destory(
+ IN gcTA_MMU Mmu
+ );
+
+gceSTATUS
+gctaMMU_SetPage(
+ IN gcTA_MMU Mmu,
+ IN gctUINT32 PageAddress,
+ IN gctUINT32 *PageEntry
+ );
+
+gceSTATUS
+gctaMMU_GetPageEntry(
+ IN gcTA_MMU Mmu,
+ IN gctUINT32 Address,
+ OUT gctUINT32_PTR MtlbEntry,
+ OUT gctUINT32_PTR *PageTable,
+ OUT gctBOOL * Secure
+ );
+
+void
+gctaMMU_DumpPagetableEntry(
+ IN gcTA_MMU Mmu,
+ IN gctUINT32 Address
+ );
+
+gceSTATUS
+gctaMMU_FreePages(
+ IN gcTA_MMU Mmu,
+ IN gctUINT32 Address,
+ IN gctUINT32 PageCount
+ );
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_hardware.c b/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_hardware.c
new file mode 100644
index 000000000000..def77c313b35
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_hardware.c
@@ -0,0 +1,965 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_types.h"
+#include "gc_hal_base.h"
+#include "gc_hal_security_interface.h"
+#include "gc_hal_ta.h"
+#include "gc_hal_ta_hardware.h"
+#include "gc_hal.h"
+#include "gc_feature_database.h"
+
+
+#define _GC_OBJ_ZONE 1
+#define SRC_MAX 8
+#define RECT_ADDR_OFFSET 3
+
+#define INVALID_ADDRESS ~0U
+
+/******************************************************************************\
+********************************* Support Code *********************************
+\******************************************************************************/
+static gceSTATUS
+_IdentifyHardwareByDatabase(
+ IN gcTA_HARDWARE Hardware
+ )
+{
+ gceSTATUS status;
+ gctUINT32 chipIdentity;
+ gcsFEATURE_DATABASE *database;
+ gctaOS os = Hardware->os;
+
+ gcmkHEADER();
+
+ /***************************************************************************
+ ** Get chip ID and revision.
+ */
+
+ /* Read chip identity register. */
+ gcmkONERROR(gctaOS_ReadRegister(os, Hardware->ta->core, 0x00018, &chipIdentity));
+
+ /* Special case for older graphic cores. */
+ if (((((gctUINT32) (chipIdentity)) >> (0 ? 31:24) & ((gctUINT32) ((((1 ?
+ 31:24) - (0 ? 31:24) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:24) - (0 ?
+ 31:24) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:24) - (0 ? 31:24) + 1))))))))
+ {
+ Hardware->chipModel = gcv500;
+ Hardware->chipRevision = (((((gctUINT32) (chipIdentity)) >> (0 ? 15:12)) & ((gctUINT32) ((((1 ? 15:12) - (0 ? 15:12) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:12) - (0 ? 15:12) + 1)))))) );
+ }
+
+ else
+ {
+ /* Read chip identity register. */
+ gcmkONERROR(
+ gctaOS_ReadRegister(os, Hardware->ta->core,
+ 0x00020,
+ (gctUINT32_PTR) &Hardware->chipModel));
+
+ if (((Hardware->chipModel & 0xFF00) == 0x0400)
+ && (Hardware->chipModel != 0x0420)
+ && (Hardware->chipModel != 0x0428))
+ {
+ Hardware->chipModel = (gceCHIPMODEL) (Hardware->chipModel & 0x0400);
+ }
+
+ /* Read CHIP_REV register. */
+ gcmkONERROR(
+ gctaOS_ReadRegister(os, Hardware->ta->core,
+ 0x00024,
+ &Hardware->chipRevision));
+
+ if ((Hardware->chipModel == gcv300)
+ && (Hardware->chipRevision == 0x2201)
+ )
+ {
+ gctUINT32 chipDate;
+ gctUINT32 chipTime;
+
+ /* Read date and time registers. */
+ gcmkONERROR(
+ gctaOS_ReadRegister(os, Hardware->ta->core,
+ 0x00028,
+ &chipDate));
+
+ gcmkONERROR(
+ gctaOS_ReadRegister(os, Hardware->ta->core,
+ 0x0002C,
+ &chipTime));
+
+ if ((chipDate == 0x20080814) && (chipTime == 0x12051100))
+ {
+ /* This IP has an ECO; put the correct revision in it. */
+ Hardware->chipRevision = 0x1051;
+ }
+ }
+
+ gcmkONERROR(
+ gctaOS_ReadRegister(os, Hardware->ta->core,
+ 0x000A8,
+ &Hardware->productID));
+ }
+
+ gcmkVERIFY_OK(gctaOS_ReadRegister(
+ os, Hardware->ta->core,
+ 0x000E8
+,
+ &Hardware->ecoID
+ ));
+
+ gcmkVERIFY_OK(gctaOS_ReadRegister(
+ os, Hardware->ta->core,
+ 0x00030
+,
+ &Hardware->customerID
+ ));
+
+ /***************************************************************************
+ ** Get chip features.
+ */
+
+ database =
+ Hardware->featureDatabase =
+ gcQueryFeatureDB(
+ Hardware->chipModel,
+ Hardware->chipRevision,
+ Hardware->productID,
+ Hardware->ecoID,
+ Hardware->customerID
+ );
+
+ if (database == gcvNULL)
+ {
+ gcmkPRINT("[galcore]: Feature database is not found,"
+ "chipModel=0x%0x, chipRevision=0x%x, productID=0x%x, ecoID=0x%x, customerID=0x%x",
+ Hardware->chipModel,
+ Hardware->chipRevision,
+ Hardware->productID,
+ Hardware->ecoID,
+ Hardware->customerID);
+ gcmkONERROR(gcvSTATUS_NOT_FOUND);
+ }
+
+ /* Success. */
+ gcmkFOOTER();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+
+gceSTATUS
+gctaHARDWARE_SetMMUStates(
+ IN gcTA_HARDWARE Hardware,
+ IN gctPOINTER MtlbAddress,
+ IN gceMMU_MODE Mode,
+ IN gctPOINTER SafeAddress,
+ IN gctPOINTER Logical,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gceSTATUS status;
+ gctUINT32 config;
+ gctUINT32 extMtlb;
+ gctPHYS_ADDR_T physical;
+ gctUINT32_PTR buffer;
+ gctUINT32 reserveBytes = 2 * 4;
+ gcsMMU_TABLE_ARRAY_ENTRY * entry;
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ entry = (gcsMMU_TABLE_ARRAY_ENTRY *) Hardware->pagetableArray.logical;
+
+ /* Convert logical address into physical address. */
+ gcmkONERROR(
+ gctaOS_GetPhysicalAddress(Hardware->os, MtlbAddress, &physical));
+
+ config = (gctUINT32)(physical & 0xFFFFFFFF);
+ extMtlb = (gctUINT32)(physical >> 32);
+ /* more than 40bit physical address */
+ if (extMtlb & 0xFFFFFF00)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ switch (Mode)
+ {
+ case gcvMMU_MODE_1K:
+ if (config & 0x3FF)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
+ }
+
+ config |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ break;
+
+ case gcvMMU_MODE_4K:
+ if (config & 0xFFF)
+ {
+ gcmkONERROR(gcvSTATUS_NOT_ALIGNED);
+ }
+
+ config |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)));
+
+ break;
+
+ default:
+ gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT);
+ }
+
+ if (Logical != gcvNULL)
+ {
+ buffer = Logical;
+
+ /* Setup page table array entry. */
+ entry->low = config;
+ entry->high = extMtlb;
+
+ /* Setup command buffer to load index 0 of page table array. */
+ *buffer++
+ = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ?
+ 31:27) - (0 ? 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ?
+ 31:27) + 1))))))) << (0 ? 31:27)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0x006B) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ?
+ 25:16) - (0 ? 25:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 25:16) - (0 ?
+ 25:16) + 1))))))) << (0 ? 25:16)));
+
+ *buffer++
+ = (((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) &((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 16:16) - (0 ?
+ 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ?
+ 16:16))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))));
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ *Bytes = reserveBytes;
+ }
+
+ /* Return the status. */
+ gcmkFOOTER_NO();
+ return status;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gctaHARDWARE_End(
+ IN gcTA_HARDWARE Hardware,
+ IN gctPOINTER Logical,
+ IN OUT gctUINT32 * Bytes
+ )
+{
+ gctUINT32_PTR logical = (gctUINT32_PTR) Logical;
+ gceSTATUS status;
+
+ gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu",
+ Hardware, Logical, gcmOPT_VALUE(Bytes));
+
+ /* Verify the arguments. */
+ gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL));
+
+ if (Logical != gcvNULL)
+ {
+ if (*Bytes < 8)
+ {
+ /* Command queue too small. */
+ gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL);
+ }
+
+ /* Append END. */
+ logical[0] =
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ?
+ 31:27) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ?
+ 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)));
+
+ /* Record the count of execution which is finised by this END. */
+ logical[1] =
+ 0;
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: END", Logical);
+ }
+
+ if (Bytes != gcvNULL)
+ {
+ /* Return number of bytes required by the END command. */
+ *Bytes = 8;
+ }
+
+ /* Success. */
+ gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes));
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+
+gceSTATUS
+gctaHARDWARE_Construct(
+ IN gcTA TA,
+ OUT gcTA_HARDWARE * Hardware
+ )
+{
+ gceSTATUS status;
+ gcTA_HARDWARE hardware = gcvNULL;
+
+ gctaOS os = TA->os;
+
+ gcmkONERROR(gctaOS_Allocate(
+ gcmSIZEOF(gcsTA_HARDWARE),
+ (gctPOINTER *)&hardware
+ ));
+
+ gctaOS_ZeroMemory((gctUINT8_PTR)hardware, gcmSIZEOF(gcsTA_HARDWARE));
+
+ hardware->ta = TA;
+ hardware->os = os;
+
+ hardware->pagetableArray.size = 4096;
+
+ hardware->functionBytes = 4096;
+
+ /* Power on GPU. */
+ gctaOS_SetGPUPower(os, TA->core, gcvTRUE, gcvTRUE);
+
+ /*************************************/
+ /******** Get chip information ******/
+ /*************************************/
+ gctaOS_WriteRegister(
+ hardware->ta->os, hardware->ta->core,
+ 0x00000,
+ 0x00000900
+ );
+
+ gcmkONERROR(_IdentifyHardwareByDatabase(hardware));
+
+ *Hardware = hardware;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ if (hardware)
+ {
+ gctaOS_Free(hardware);
+ }
+
+ return status;
+}
+
+gceSTATUS
+gctaHARDWARE_Destroy(
+ IN gcTA_HARDWARE Hardware
+ )
+{
+ if (Hardware->pagetableArray.logical)
+ {
+ gctaOS_FreeSecurityMemory(
+ Hardware->ta->os,
+ Hardware->pagetableArray.size,
+ Hardware->pagetableArray.logical,
+ (gctUINT32_PTR)Hardware->pagetableArray.physical
+ );
+ }
+
+ if (Hardware->functionLogical)
+ {
+ gctaOS_FreeSecurityMemory(
+ Hardware->ta->os,
+ Hardware->functionBytes,
+ Hardware->functionLogical,
+ (gctUINT32_PTR)Hardware->functionPhysical
+ );
+ }
+
+ gctaOS_Free(Hardware);
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaHARDWARE_Execute(
+ IN gcTA TA,
+ IN gctUINT32 Address,
+ IN gctUINT32 Bytes
+ )
+{
+ gceSTATUS status;
+ gctUINT32 address = Address, control;
+
+ gcmkHEADER_ARG("Address=0x%x Bytes=%lu",
+ Address, Bytes);
+
+ /* Enable all events. */
+ gcmkONERROR(
+ gctaOS_WriteRegister(TA->os, TA->core, 0x00014, ~0U));
+
+ /* Write address register. */
+ gcmkONERROR(
+ gctaOS_WriteRegister(TA->os, TA->core, 0x00654, address));
+
+ /* Build control register. */
+ control = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ?
+ 16:16) - (0 ? 16:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 16:16) - (0 ?
+ 16:16) + 1))))))) << (0 ? 16:16)))
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ?
+ 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0))) | (((gctUINT32) ((gctUINT32) ((Bytes + 7) >> 3) & ((gctUINT32) ((((1 ?
+ 15:0) - (0 ? 15:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ?
+ 15:0)));
+
+ /* Write control register. */
+ gcmkONERROR(
+ gctaOS_WriteRegister(TA->os, TA->core, 0x003A4, control));
+
+ gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE,
+ "Started command buffer @ 0x%08x",
+ address);
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ /* Return the status. */
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gctaHARDWARE_MmuEnable(
+ IN gcTA_HARDWARE Hardware
+ )
+{
+ gctaOS_WriteRegister(
+ Hardware->ta->os, Hardware->ta->core,
+ 0x0018C,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) ((gctUINT32) (1 ) & ((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))));
+
+ return gcvSTATUS_OK;
+}
+
+/*
+* In trust zone, we prepare page table array table and configure base address of
+* it to hardware.
+*/
+gceSTATUS
+gctaHARDWARE_SetMMU(
+ IN gcTA_HARDWARE Hardware,
+ IN gctPOINTER Logical
+ )
+{
+ gcsMMU_TABLE_ARRAY_ENTRY *entry;
+ gcsHARDWARE_FUNCTION *function = &Hardware->functions[0];
+ gctUINT32 delay = 1;
+ gctUINT32 timer = 0;
+ gctUINT32 idle;
+ gctPHYS_ADDR_T mtlbPhysical;
+ gctPHYS_ADDR_T secureSafeAddress;
+ gctPHYS_ADDR_T nonSecureSafeAddress;
+
+ gctaOS_GetPhysicalAddress(Hardware->ta->os, Logical, &mtlbPhysical);
+
+ gctaOS_GetPhysicalAddress(Hardware->ta->os, Hardware->ta->mmu->safePageLogical, &secureSafeAddress);
+
+ gctaOS_GetPhysicalAddress(Hardware->ta->os, Hardware->ta->mmu->nonSecureSafePageLogical, &nonSecureSafeAddress);
+
+ /* not support more than 40bit physical address */
+ if ((secureSafeAddress & 0xFFFFFF0000000000ULL) ||
+ (nonSecureSafeAddress & 0xFFFFFF0000000000ULL))
+ {
+ return (gcvSTATUS_NOT_SUPPORTED);
+ }
+
+ /* Fill entry 0 of page table array. */
+ entry = (gcsMMU_TABLE_ARRAY_ENTRY *)Hardware->pagetableArray.logical;
+
+ entry->low = (gctUINT32)(mtlbPhysical & 0xFFFFFFFF);
+
+ entry->high = (gctUINT32)(mtlbPhysical >> 32)
+ | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 8:8) - (0 ? 8:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ?
+ 8:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:8) - (0 ?
+ 8:8) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ?
+ 8:8)))
+ ;
+
+ /* Set page table base. */
+ gctaOS_WriteRegister(
+ Hardware->ta->os, Hardware->ta->core,
+ 0x0038C,
+ (gctUINT32)(Hardware->pagetableArray.address & 0xFFFFFFFF)
+ );
+
+ gctaOS_WriteRegister(
+ Hardware->ta->os, Hardware->ta->core,
+ 0x00390,
+ (gctUINT32)((Hardware->pagetableArray.address >> 32) & 0xFFFFFFFF)
+ );
+
+ gctaOS_WriteRegister(
+ Hardware->ta->os, Hardware->ta->core,
+ 0x00394
+,
+ 1
+ );
+
+ gctaOS_WriteRegister(
+ Hardware->ta->os, Hardware->ta->core,
+ 0x0039C,
+ (gctUINT32)(secureSafeAddress & 0xFFFFFFFF)
+ );
+
+ gctaOS_WriteRegister(
+ Hardware->ta->os, Hardware->ta->core,
+ 0x00398,
+ (gctUINT32)(nonSecureSafeAddress & 0xFFFFFFFF)
+ );
+
+ gctaOS_WriteRegister(
+ Hardware->ta->os, Hardware->ta->core,
+ 0x003A0,
+ (((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:16) - (0 ?
+ 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ? 23:16) + 1))))))) << (0 ?
+ 23:16))) | (((gctUINT32) ((gctUINT32) ((gctUINT32)((secureSafeAddress >> 32) & 0xFFFFFFFF)) & ((gctUINT32) ((((1 ?
+ 23:16) - (0 ? 23:16) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 23:16) - (0 ?
+ 23:16) + 1))))))) << (0 ? 23:16))) &((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ?
+ 31:31) - (0 ? 31:31) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ?
+ 31:31) - (0 ? 31:31) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 31:31) - (0 ?
+ 31:31) + 1))))))) << (0 ? 31:31))))
+ | (((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:0) - (0 ?
+ 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) | (((gctUINT32) ((gctUINT32) ((gctUINT32)((nonSecureSafeAddress >> 32) & 0xFFFFFFFF)) & ((gctUINT32) ((((1 ?
+ 7:0) - (0 ? 7:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 7:0) - (0 ? 7:0) + 1))))))) << (0 ?
+ 7:0))) &((((gctUINT32) (~0U)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:15) - (0 ?
+ 15:15) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 15:15) - (0 ? 15:15) + 1))))))) << (0 ?
+ 15:15))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 15:15) - (0 ? 15:15) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 15:15) - (0 ? 15:15) + 1))))))) << (0 ? 15:15))))
+ );
+
+ /* Execute prepared command sequence. */
+ gctaHARDWARE_Execute(
+ Hardware->ta,
+ function->address,
+ function->bytes
+ );
+
+ /* Wait until MMU configure finishes. */
+ do
+ {
+ gctaOS_Delay(Hardware->os, delay);
+
+ gctaOS_ReadRegister(
+ Hardware->ta->os, Hardware->ta->core,
+ 0x00004,
+ &idle);
+
+ timer += delay;
+ delay *= 2;
+ }
+ while (!(((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ));
+
+ /* Enable MMU. */
+ gctaOS_WriteRegister(
+ Hardware->os, Hardware->ta->core,
+ 0x00388,
+ ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ?
+ 0:0) + 1) == 32) ? ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ?
+ 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ?
+ ~0U : (~(~0U << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))
+ );
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaHARDWARE_PrepareFunctions(
+ IN gcTA_HARDWARE Hardware
+ )
+{
+ gceSTATUS status;
+ gcsHARDWARE_FUNCTION * function;
+ gctUINT32 mmuBytes;
+ gctUINT32 endBytes = 8;
+ gctUINT8_PTR logical;
+
+ gcmkHEADER();
+
+ /* Allocate page table array. */
+ gcmkONERROR(gctaOS_AllocateSecurityMemory(
+ Hardware->ta->os,
+ &Hardware->pagetableArray.size,
+ &Hardware->pagetableArray.logical,
+ &Hardware->pagetableArray.physical
+ ));
+
+ gcmkONERROR(gctaOS_GetPhysicalAddress(
+ Hardware->ta->os,
+ Hardware->pagetableArray.logical,
+ &Hardware->pagetableArray.address
+ ));
+
+ /* Allocate GPU functions. */
+ gcmkONERROR(gctaOS_AllocateSecurityMemory(
+ Hardware->ta->os,
+ &Hardware->functionBytes,
+ &Hardware->functionLogical,
+ &Hardware->functionPhysical
+ ));
+
+ gcmkONERROR(gctaOS_GetPhysicalAddress(
+ Hardware->ta->os,
+ Hardware->functionLogical,
+ (gctPHYS_ADDR_T *)&Hardware->functionAddress
+ ));
+
+ function = &Hardware->functions[0];
+
+ function->logical = Hardware->functionLogical;
+
+ function->address = Hardware->functionAddress;
+
+ logical = function->logical;
+
+ gcmkONERROR(gctaHARDWARE_SetMMUStates(
+ Hardware,
+ Hardware->ta->mmu->mtlbLogical,
+ gcvMMU_MODE_4K,
+ Hardware->ta->mmu->safePageLogical,
+ logical,
+ &mmuBytes
+ ));
+
+ logical += 8;
+
+ gcmkONERROR(gctaHARDWARE_End(
+ Hardware,
+ logical,
+ &endBytes
+ ));
+
+ function->bytes = mmuBytes + endBytes;
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gctaHARDWARE_IsFeatureAvailable(
+ IN gcTA_HARDWARE Hardware,
+ IN gceFEATURE Feature
+ )
+{
+ gctBOOL available;
+ gcsFEATURE_DATABASE *database = Hardware->featureDatabase;
+
+ switch (Feature)
+ {
+ case gcvFEATURE_SECURITY:
+ available = database->SECURITY;
+ break;
+ default:
+ gcmkFATAL("Invalid feature has been requested.");
+ available = gcvFALSE;
+ }
+
+ return available;
+}
+
+gceSTATUS
+gctaHARDWARE_DumpMMUException(
+ IN gcTA_HARDWARE Hardware
+ )
+{
+ gctUINT32 mmu = 0;
+ gctUINT32 mmuStatus = 0;
+ gctUINT32 address = 0;
+ gctUINT32 i = 0;
+
+ gctUINT32 mmuStatusRegAddress;
+ gctUINT32 mmuExceptionAddress;
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ mmuStatusRegAddress = 0x00384;
+ mmuExceptionAddress = 0x00380;
+
+ /* Verify the arguments. */
+ gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE);
+
+ gcmkPRINT("ChipModel=0x%x ChipRevision=0x%x:\n",
+ Hardware->chipModel,
+ Hardware->chipRevision);
+
+ gcmkPRINT("**************************\n");
+ gcmkPRINT("*** MMU ERROR DUMP ***\n");
+ gcmkPRINT("**************************\n");
+
+ gcmkVERIFY_OK(gctaOS_ReadRegister(
+ Hardware->os, Hardware->ta->core,
+ mmuStatusRegAddress
+,
+ &mmuStatus
+ ));
+
+ gcmkPRINT(" MMU status = 0x%08X\n", mmuStatus);
+
+ for (i = 0; i < 4; i += 1)
+ {
+ mmu = mmuStatus & 0xF;
+ mmuStatus >>= 4;
+
+ if (mmu == 0)
+ {
+ continue;
+ }
+
+ switch (mmu)
+ {
+ case 1:
+ gcmkPRINT(" MMU%d: slave not present\n", i);
+ break;
+
+ case 2:
+ gcmkPRINT(" MMU%d: page not present\n", i);
+ break;
+
+ case 3:
+ gcmkPRINT(" MMU%d: write violation\n", i);
+ break;
+
+ case 4:
+ gcmkPRINT(" MMU%d: out of bound", i);
+ break;
+
+ case 5:
+ gcmkPRINT(" MMU%d: read security violation", i);
+ break;
+
+ case 6:
+ gcmkPRINT(" MMU%d: write security violation", i);
+ break;
+
+ default:
+ gcmkPRINT(" MMU%d: unknown state\n", i);
+ }
+
+ gcmkVERIFY_OK(gctaOS_ReadRegister(
+ Hardware->os, Hardware->ta->core,
+ mmuExceptionAddress + i * 4
+,
+ &address
+ ));
+
+ gcmkPRINT(" MMU%d: exception address = 0x%08X\n", i, address);
+
+ gctaMMU_DumpPagetableEntry(Hardware->ta->mmu, address);
+ }
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaHARDWARE_ReadMMUException(
+ IN gcTA_HARDWARE Hardware,
+ OUT gctUINT32_PTR MMUStatus,
+ OUT gctUINT32_PTR MMUException
+ )
+{
+ gctUINT32 mmuStatusRegAddress;
+ gctUINT32 mmuExceptionAddress;
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ mmuStatusRegAddress = 0x00384;
+ mmuExceptionAddress = 0x00380;
+
+ gcmkVERIFY_OK(gctaOS_ReadRegister(
+ Hardware->os, Hardware->ta->core,
+ mmuStatusRegAddress
+,
+ MMUStatus
+ ));
+
+ gcmkVERIFY_OK(gctaOS_ReadRegister(
+ Hardware->os, Hardware->ta->core,
+ mmuExceptionAddress
+,
+ MMUException
+ ));
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaHARDWARE_HandleMMUException(
+ IN gcTA_HARDWARE Hardware,
+ IN gctUINT32 MMUStatus,
+ IN gctPHYS_ADDR_T Physical,
+ IN gctUINT32 GPUAddress
+ )
+{
+ gctUINT32 mmu = 0;
+ gctUINT32 mmuStatus = 0;
+ gctUINT32 mtlbEntry = 0;
+ gctUINT32_PTR stlbEntry;
+ gctBOOL secure;
+
+ gctUINT32 mmuStatusRegAddress;
+ gctUINT32 mmuExceptionAddress;
+
+ gcmkHEADER_ARG("Hardware=0x%x", Hardware);
+
+ mmuStatusRegAddress = 0x00384;
+ mmuExceptionAddress = 0x00380;
+
+ gcmkVERIFY_OK(gctaOS_ReadRegister(
+ Hardware->os, Hardware->ta->core,
+ mmuStatusRegAddress
+,
+ &mmuStatus
+ ));
+
+ mmu = mmuStatus & 0xF;
+
+ /* Setup page table. */
+
+ gctaMMU_GetPageEntry(
+ Hardware->ta->mmu,
+ GPUAddress,
+ &mtlbEntry,
+ &stlbEntry,
+ &secure
+ );
+
+ gctaMMU_SetPage(
+ Hardware->ta->mmu,
+ (gctUINT32)Physical,
+ stlbEntry
+ );
+
+ switch (mmu)
+ {
+ case 1:
+ gcmkASSERT(mtlbEntry != 0);
+ gctaOS_WriteRegister(
+ Hardware->os, Hardware->ta->core,
+ mmuExceptionAddress
+,
+ mtlbEntry
+ );
+
+ break;
+
+ case 2:
+ gctaOS_WriteRegister(
+ Hardware->os, Hardware->ta->core,
+ mmuExceptionAddress
+,
+ *stlbEntry
+ );
+ break;
+
+ default:
+ gcmkASSERT(0);
+ }
+
+
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
diff --git a/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_hardware.h b/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_hardware.h
new file mode 100644
index 000000000000..2ae926aa0f80
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_hardware.h
@@ -0,0 +1,139 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#ifndef _GC_HAL_TA_HARDWARE_H_
+#define _GC_HAL_TA_HARDWARE_H_
+#include "gc_hal_types.h"
+#include "gc_hal_security_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _gcsMMU_TABLE_ARRAY_ENTRY
+{
+ gctUINT32 low;
+ gctUINT32 high;
+}
+gcsMMU_TABLE_ARRAY_ENTRY;
+
+typedef struct _gcsHARDWARE_PAGETABLE_ARRAY
+{
+ /* Number of entries in page table array. */
+ gctUINT num;
+
+ /* Size in bytes of array. */
+ gctSIZE_T size;
+
+ /* Physical address of array. */
+ gctPHYS_ADDR_T address;
+
+ /* Memory descriptor. */
+ gctPOINTER physical;
+
+ /* Logical address of array. */
+ gctPOINTER logical;
+}
+gcsHARDWARE_PAGETABLE_ARRAY;
+
+typedef struct _gcsHARWARE_FUNCTION
+{
+ /* Entry of the function. */
+ gctUINT32 address;
+
+ /* CPU address of the function. */
+ gctUINT8_PTR logical;
+
+ /* Bytes of the function. */
+ gctUINT32 bytes;
+
+ /* Hardware address of END in this function. */
+ gctUINT32 endAddress;
+
+ /* Logical of END in this function. */
+ gctUINT8_PTR endLogical;
+}
+gcsHARDWARE_FUNCTION;
+
+typedef struct _gcTA_HARDWARE
+{
+ gctaOS os;
+ gcTA ta;
+
+ gctUINT32 chipModel;
+ gctUINT32 chipRevision;
+ gctUINT32 productID;
+ gctUINT32 ecoID;
+ gctUINT32 customerID;
+
+ gctPOINTER featureDatabase;
+
+ gcsHARDWARE_PAGETABLE_ARRAY pagetableArray;
+
+ /* Function used by gctaHARDWARE. */
+ gctPHYS_ADDR functionPhysical;
+ gctPOINTER functionLogical;
+ gctUINT32 functionAddress;
+ gctSIZE_T functionBytes;
+
+ gcsHARDWARE_FUNCTION functions[1];
+}
+gcsTA_HARDWARE;
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_mmu.c b/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_mmu.c
new file mode 100644
index 000000000000..fda0493e14c5
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/security_v1/gc_hal_ta_mmu.c
@@ -0,0 +1,586 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_types.h"
+#include "gc_hal_base.h"
+#include "gc_hal_security_interface.h"
+#include "gc_hal_ta.h"
+#include "gc_hal.h"
+
+#define _GC_OBJ_ZONE 2
+/*******************************************************************************
+************************************ Define ************************************
+********************************************************************************/
+
+#define gcdMMU_MTLB_SHIFT 22
+#define gcdMMU_STLB_4K_SHIFT 12
+#define gcdMMU_STLB_64K_SHIFT 16
+
+#define gcdMMU_MTLB_BITS (32 - gcdMMU_MTLB_SHIFT)
+#define gcdMMU_PAGE_4K_BITS gcdMMU_STLB_4K_SHIFT
+#define gcdMMU_STLB_4K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_4K_BITS)
+#define gcdMMU_PAGE_64K_BITS gcdMMU_STLB_64K_SHIFT
+#define gcdMMU_STLB_64K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_64K_BITS)
+
+#define gcdMMU_MTLB_ENTRY_NUM (1 << gcdMMU_MTLB_BITS)
+#define gcdMMU_MTLB_SIZE (gcdMMU_MTLB_ENTRY_NUM << 2)
+#define gcdMMU_STLB_4K_ENTRY_NUM (1 << gcdMMU_STLB_4K_BITS)
+#define gcdMMU_STLB_4K_SIZE (gcdMMU_STLB_4K_ENTRY_NUM << 2)
+#define gcdMMU_PAGE_4K_SIZE (1 << gcdMMU_STLB_4K_SHIFT)
+#define gcdMMU_STLB_64K_ENTRY_NUM (1 << gcdMMU_STLB_64K_BITS)
+#define gcdMMU_STLB_64K_SIZE (gcdMMU_STLB_64K_ENTRY_NUM << 2)
+#define gcdMMU_PAGE_64K_SIZE (1 << gcdMMU_STLB_64K_SHIFT)
+
+#define gcdMMU_MTLB_MASK (~((1U << gcdMMU_MTLB_SHIFT)-1))
+#define gcdMMU_STLB_4K_MASK ((~0U << gcdMMU_STLB_4K_SHIFT) ^ gcdMMU_MTLB_MASK)
+#define gcdMMU_PAGE_4K_MASK (gcdMMU_PAGE_4K_SIZE - 1)
+#define gcdMMU_STLB_64K_MASK ((~((1U << gcdMMU_STLB_64K_SHIFT)-1)) ^ gcdMMU_MTLB_MASK)
+#define gcdMMU_PAGE_64K_MASK (gcdMMU_PAGE_64K_SIZE - 1)
+
+/* Page offset definitions. */
+#define gcdMMU_OFFSET_4K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_STLB_4K_BITS)
+#define gcdMMU_OFFSET_4K_MASK ((1U << gcdMMU_OFFSET_4K_BITS) - 1)
+#define gcdMMU_OFFSET_16K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_STLB_16K_BITS)
+#define gcdMMU_OFFSET_16K_MASK ((1U << gcdMMU_OFFSET_16K_BITS) - 1)
+
+#define gcdMMU_MTLB_PRESENT 0x00000001
+#define gcdMMU_MTLB_EXCEPTION 0x00000002
+#define gcdMMU_MTLB_4K_PAGE 0x00000000
+
+#define gcdMMU_STLB_PRESENT 0x00000001
+#define gcdMMU_STLB_EXCEPTION 0x00000002
+#define gcdMMU_STLB_SECURITY (1 << 4)
+#define gcdMMU_STLB_4K_PAGE 0x00000000
+
+#define gcdUSE_MMU_EXCEPTION 1
+
+#define gcdMMU_SECURE_AREA_START ((gcdMMU_MTLB_ENTRY_NUM - gcdMMU_SECURE_AREA_SIZE) << gcdMMU_MTLB_SHIFT)
+
+typedef enum _gceMMU_TYPE
+{
+ gcvMMU_USED = (0 << 4),
+ gcvMMU_SINGLE = (1 << 4),
+ gcvMMU_FREE = (2 << 4),
+}
+gceMMU_TYPE;
+
+typedef struct _gcsMMU_STLB *gcsMMU_STLB_PTR;
+typedef struct _gcsMMU_STLB
+{
+ gctPHYS_ADDR physical;
+ gctUINT32_PTR logical;
+ gctSIZE_T size;
+ gctPHYS_ADDR_T physBase;
+ gctSIZE_T pageCount;
+ gctUINT32 mtlbIndex;
+ gctUINT32 mtlbEntryNum;
+ gcsMMU_STLB_PTR next;
+} gcsMMU_STLB;
+
+
+#define gcmENTRY_TYPE(x) (x & 0xF0)
+/*
+* We need flat mapping ta command buffer.
+
+*/
+
+/*
+* Helper
+*/
+gctUINT32
+_MtlbOffset(
+ gctUINT32 Address
+ )
+{
+ return (Address & gcdMMU_MTLB_MASK) >> gcdMMU_MTLB_SHIFT;
+}
+
+gctUINT32
+_StlbOffset(
+ gctUINT32 Address
+ )
+{
+ return (Address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT;
+}
+
+static gctUINT32
+_SetPage(gctUINT32 PageAddress)
+{
+ return PageAddress
+ /* writable */
+ | (1 << 2)
+ /* Ignore exception */
+ | (0 << 1)
+ /* Present */
+ | (1 << 0);
+}
+
+static void
+_WritePageEntry(
+ IN gctUINT32_PTR PageEntry,
+ IN gctUINT32 EntryValue
+ )
+{
+ *PageEntry = EntryValue;
+
+ gctaOS_CacheClean((gctUINT8_PTR)PageEntry, gcmSIZEOF(gctUINT32));
+}
+
+static gceSTATUS
+_FillPageTable(
+ IN gctUINT32_PTR PageTable,
+ IN gctUINT32 PageCount,
+ IN gctUINT32 EntryValue
+)
+{
+ gctUINT i;
+
+ for (i = 0; i < PageCount; i++)
+ {
+ _WritePageEntry(PageTable + i, EntryValue);
+ }
+
+ return gcvSTATUS_OK;
+}
+
+
+static gceSTATUS
+_AllocateStlb(
+ IN gctaOS Os,
+ OUT gcsMMU_STLB_PTR *Stlb
+ )
+{
+ gceSTATUS status;
+ gcsMMU_STLB_PTR stlb;
+ gctPOINTER pointer = gcvNULL;
+
+ /* Allocate slave TLB record. */
+ gcmkONERROR(gctaOS_Allocate(gcmSIZEOF(gcsMMU_STLB), &pointer));
+ stlb = pointer;
+
+ stlb->size = gcdMMU_STLB_4K_SIZE;
+
+ /* Allocate slave TLB entries. */
+ gcmkONERROR(gctaOS_AllocateSecurityMemory(
+ Os,
+ &stlb->size,
+ (gctPOINTER *)&stlb->logical,
+ &stlb->physical
+ ));
+
+ gcmkONERROR(gctaOS_GetPhysicalAddress(Os, stlb->logical, &stlb->physBase));
+
+#if gcdUSE_MMU_EXCEPTION
+ _FillPageTable(stlb->logical, stlb->size / 4, gcdMMU_STLB_EXCEPTION);
+#else
+ gctaOS_ZeroMemory(stlb->logical, stlb->size);
+#endif
+
+ *Stlb = stlb;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ if(pointer != gcvNULL)
+ gcmkVERIFY_OK(gctaOS_Free(pointer));
+ return status;
+}
+
+gceSTATUS
+gctaMMU_Construct(
+ IN gcTA TA,
+ OUT gcTA_MMU *Mmu
+ )
+{
+ gceSTATUS status;
+ gctSIZE_T bytes = 4096;
+
+ gcTA_MMU mmu = gcvNULL;
+
+ gcmkONERROR(gctaOS_Allocate(
+ gcmSIZEOF(gcsTA_MMU),
+ (gctPOINTER *)&mmu
+ ));
+
+ mmu->mtlbLogical = gcvNULL;
+ mmu->stlbs = gcvNULL;
+ mmu->safePageLogical = gcvNULL;
+ mmu->nonSecureSafePageLogical = gcvNULL;
+
+ mmu->os = TA->os;
+
+ /* MTLB bytes. */
+ mmu->mtlbBytes = gcdMMU_MTLB_SIZE;
+
+ /* Allocate MTLB. */
+ gcmkONERROR(gctaOS_AllocateSecurityMemory(
+ TA->os,
+ &mmu->mtlbBytes,
+ &mmu->mtlbLogical,
+ &mmu->mtlbPhysical
+ ));
+
+#if gcdUSE_MMU_EXCEPTION
+ _FillPageTable(mmu->mtlbLogical, mmu->mtlbBytes / 4, gcdMMU_STLB_EXCEPTION);
+#else
+ gctaOS_ZeroMemory(mmu->mtlbLogical, mmu->mtlbBytes);
+#endif
+
+ /* Allocate a array to store stlbs. */
+ gcmkONERROR(gctaOS_Allocate(mmu->mtlbBytes, &mmu->stlbs));
+
+ gctaOS_ZeroMemory((gctUINT8_PTR)mmu->stlbs, mmu->mtlbBytes);
+
+ /* Allocate security safe page. */
+ gcmkONERROR(gctaOS_AllocateSecurityMemory(
+ TA->os,
+ &bytes,
+ &mmu->safePageLogical,
+ &mmu->safePagePhysical
+ ));
+
+ gctaOS_ZeroMemory((gctUINT8_PTR)mmu->safePageLogical, bytes);
+
+ /* Allocate non security safe page. */
+ gcmkONERROR(gctaOS_AllocateSecurityMemory(
+ TA->os,
+ &bytes,
+ &mmu->nonSecureSafePageLogical,
+ &mmu->nonSecureSafePagePhysical
+ ));
+
+ gctaOS_ZeroMemory((gctUINT8_PTR)mmu->nonSecureSafePageLogical, bytes);
+
+ /* gcmkONERROR(gctaOS_CreateMutex(TA->os, &mmu->mutex)); */
+
+ *Mmu = mmu;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ if (mmu)
+ {
+ if (mmu->safePageLogical)
+ {
+ gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+ TA->os,
+ 4096,
+ mmu->safePageLogical,
+ mmu->safePagePhysical
+ ));
+ }
+
+ if (mmu->nonSecureSafePageLogical)
+ {
+ gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+ TA->os,
+ 4096,
+ mmu->nonSecureSafePageLogical,
+ mmu->nonSecureSafePagePhysical
+ ));
+ }
+
+ if (mmu->mtlbLogical)
+ {
+ gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+ TA->os,
+ 4096,
+ mmu->mtlbLogical,
+ mmu->mtlbPhysical
+ ));
+ }
+
+ if (mmu->stlbs)
+ {
+ gcmkVERIFY_OK(gctaOS_Free((gctPOINTER)mmu->stlbs));
+ }
+
+ gcmkVERIFY_OK(gctaOS_Free((gctPOINTER)mmu));
+ }
+ return status;
+}
+
+gceSTATUS
+gctaMMU_Destory(
+ IN gcTA_MMU Mmu
+ )
+{
+ gctaOS os = Mmu->os;
+
+ if (Mmu->safePageLogical)
+ {
+ gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+ os,
+ 4096,
+ Mmu->safePageLogical,
+ Mmu->safePagePhysical
+ ));
+ }
+
+ if (Mmu->nonSecureSafePageLogical)
+ {
+ gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+ os,
+ 4096,
+ Mmu->nonSecureSafePageLogical,
+ Mmu->nonSecureSafePagePhysical
+ ));
+ }
+
+ if (Mmu->mtlbLogical)
+ {
+ gcmkVERIFY_OK(gctaOS_FreeSecurityMemory(
+ os,
+ 4096,
+ Mmu->mtlbLogical,
+ Mmu->mtlbPhysical
+ ));
+ }
+
+ if (Mmu->stlbs)
+ {
+ gcmkVERIFY_OK(gctaOS_Free((gctPOINTER)Mmu->stlbs));
+ }
+
+ gcmkVERIFY_OK(gctaOS_Free(Mmu));
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaMMU_GetPageEntry(
+ IN gcTA_MMU Mmu,
+ IN gctUINT32 Address,
+ OUT gctUINT32_PTR MtlbEntry,
+ OUT gctUINT32_PTR *PageTable,
+ OUT gctBOOL * Secure
+ )
+{
+ gceSTATUS status;
+ struct _gcsMMU_STLB *stlb;
+ struct _gcsMMU_STLB **stlbs = (struct _gcsMMU_STLB **)Mmu->stlbs;
+ gctUINT32 offset = _MtlbOffset(Address);
+ gctUINT32 mtlbEntry;
+ gctBOOL secure = Address > gcdMMU_SECURE_AREA_START;
+
+ gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_ARGUMENT((Address & 0xFFF) == 0);
+
+ stlb = stlbs[offset];
+
+ if (stlb == gcvNULL)
+ {
+ gcmkONERROR(_AllocateStlb(Mmu->os, &stlb));
+
+ mtlbEntry = (gctUINT32)(stlb->physBase & 0xFFFFFFFF)
+ | gcdMMU_MTLB_4K_PAGE
+ | gcdMMU_MTLB_PRESENT
+ ;
+
+ if (secure)
+ {
+ /* Secure MTLB. */
+ mtlbEntry |= (1 << 4);
+ }
+
+ /* Insert Slave TLB address to Master TLB entry.*/
+ _WritePageEntry((gctUINT32_PTR)Mmu->mtlbLogical + offset, mtlbEntry);
+
+ /* Record stlb. */
+ stlbs[offset] = stlb;
+
+ if (MtlbEntry)
+ {
+ /* Return entry value of new mtlb entry. */
+ *MtlbEntry = mtlbEntry;
+ }
+ }
+
+ *PageTable = &stlb->logical[_StlbOffset(Address)];
+
+ if (Secure)
+ {
+ *Secure = secure;
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gctaMMU_SetPage(
+ IN gcTA_MMU Mmu,
+ IN gctUINT32 PageAddress,
+ IN gctUINT32 *PageEntry
+ )
+{
+ /* gctBOOL secure; */
+
+ gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+ /* Verify the arguments. */
+ gcmkVERIFY_ARGUMENT(PageEntry != gcvNULL);
+ gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFF));
+
+ _WritePageEntry(PageEntry, _SetPage(PageAddress));
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaMMU_FreePages(
+ IN gcTA_MMU Mmu,
+ IN gctUINT32 Address,
+ IN gctUINT32 PageCount
+ )
+{
+ gceSTATUS status;
+ gctUINT32 i;
+ gctUINT32_PTR entry;
+ gcmkHEADER_ARG("Mmu=0x%x", Mmu);
+
+ /* Fill in page table. */
+ for (i = 0; i < PageCount; i++)
+ {
+ gcmkONERROR(gctaMMU_GetPageEntry(Mmu, Address, gcvNULL, &entry, gcvNULL));
+
+#if gcdUSE_MMU_EXCEPTION
+ *entry = gcdMMU_STLB_EXCEPTION;
+#else
+ *entry = 0;
+#endif
+
+ Address += 4096;
+ }
+
+ /* Success. */
+ gcmkFOOTER_NO();
+ return gcvSTATUS_OK;
+
+OnError:
+ gcmkFOOTER();
+ return status;
+}
+
+gceSTATUS
+gctaMMU_Enable(
+ IN gcTA_MMU Mmu,
+ IN gcTA TA
+ )
+{
+ gceSTATUS status;
+ gctPHYS_ADDR_T address;
+ gctPHYS_ADDR_T safeAddress;
+
+ gcmkONERROR(gctaOS_GetPhysicalAddress(Mmu->os, Mmu->mtlbLogical, &address));
+
+ gctaOS_GetPhysicalAddress(Mmu->os, Mmu->safePageLogical, &safeAddress);
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+void
+gctaMMU_DumpPagetableEntry(
+ IN gcTA_MMU Mmu,
+ IN gctUINT32 Address
+ )
+{
+ gctUINT32 entry;
+ gctUINT32 mtlb = _MtlbOffset(Address);
+ gctUINT32_PTR mtlbLogical = Mmu->mtlbLogical;
+ gctUINT32_PTR stlbLogical;
+ gcsMMU_STLB_PTR stlb;
+ struct _gcsMMU_STLB **stlbs = (struct _gcsMMU_STLB **)Mmu->stlbs;
+
+ gctUINT32 stlbOffset = (Address & gcdMMU_STLB_4K_MASK) >> gcdMMU_STLB_4K_SHIFT;
+ gctUINT32 offsetInPage = Address & gcdMMU_OFFSET_4K_MASK;
+
+ stlb = stlbs[mtlb];
+
+ gcmkPRINT(" MTLB entry = %d\n", mtlb);
+
+ gcmkPRINT(" STLB entry = %d\n", stlbOffset);
+
+ gcmkPRINT(" Offset = 0x%08X (%d)\n", offsetInPage, offsetInPage);
+
+
+ if (stlb == gcvNULL)
+ {
+ /* Dmp mtlb entry. */
+ entry = mtlbLogical[mtlb];
+
+ gcmkPRINT(" mtlb entry [%d] = %x", mtlb, entry);
+ }
+ else
+ {
+ stlbLogical = stlb->logical;
+
+ gcmkPRINT(" stlb entry = 0x%08X", stlbLogical[stlbOffset]);
+ }
+}
+
+
diff --git a/drivers/mxc/gpu-viv/hal/security_v1/os/emulator/gc_hal_ta_emulator.c b/drivers/mxc/gpu-viv/hal/security_v1/os/emulator/gc_hal_ta_emulator.c
new file mode 100644
index 000000000000..b5dac8da1501
--- /dev/null
+++ b/drivers/mxc/gpu-viv/hal/security_v1/os/emulator/gc_hal_ta_emulator.c
@@ -0,0 +1,322 @@
+/****************************************************************************
+*
+* The MIT License (MIT)
+*
+* Copyright (c) 2014 - 2018 Vivante Corporation
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+*
+*****************************************************************************
+*
+* The GPL License (GPL)
+*
+* Copyright (C) 2014 - 2018 Vivante Corporation
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*****************************************************************************
+*
+* Note: This software is released under dual MIT and GPL licenses. A
+* recipient may use this file under the terms of either the MIT license or
+* GPL License. If you wish to use only one license not the other, you can
+* indicate your decision by deleting one of the above license notices in your
+* version of this file.
+*
+*****************************************************************************/
+
+
+#include "gc_hal_base.h"
+#include "gc_hal.h"
+#include "gc_hal_ta.h"
+#include "gc_hal_kernel_mutex.h"
+
+#define _GC_OBJ_ZONE gcvZONE_OS
+
+gcTA globalTA[16] = { gcvNULL, gcvNULL, gcvNULL, gcvNULL,gcvNULL, gcvNULL, gcvNULL, gcvNULL };
+gctaOS globalTAos;
+
+struct _gctaOS {
+ void *os;
+
+ gctPOINTER dispatchMutex;
+};
+
+gceSTATUS HALDECL
+TAEmulator(
+ gceCORE Core,
+ void * Interface
+ )
+{
+ gckOS_AcquireMutex(globalTAos->os, globalTAos->dispatchMutex, gcvINFINITE);
+
+ gcTA_Dispatch(globalTA[Core], Interface);
+
+ gckOS_ReleaseMutex(globalTAos->os, globalTAos->dispatchMutex);
+ return gcvSTATUS_OK;
+}
+
+
+gceSTATUS
+gctaOS_ConstructOS(
+ IN gckOS Os,
+ OUT gctaOS *TAos
+ )
+{
+ gctaOS os;
+ gctPOINTER pointer = gcvNULL;
+ gceSTATUS status;
+
+ gcmkONERROR(gckOS_AllocateMemory(Os, gcmSIZEOF(struct _gctaOS), &pointer));
+
+ os = (gctaOS)pointer;
+ os->os = Os;
+
+ gcmkONERROR(gckOS_CreateMutex(Os, &os->dispatchMutex));
+
+ *TAos = globalTAos = os;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ if (pointer != gcvNULL)
+ {
+ gcmkVERIFY_OK(gckOS_FreeMemory(Os, pointer));
+ }
+ return status;
+}
+
+gceSTATUS
+gctaOS_DestroyOS(
+ IN gctaOS Os
+ )
+{
+ gckOS os = Os->os;
+
+ gcmkVERIFY_OK(gckOS_DeleteMutex(os, Os->dispatchMutex));
+ gcmkVERIFY_OK(gckOS_FreeMemory(os, Os));
+
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaOS_AllocateSecurityMemory(
+ IN gctaOS Os,
+ IN gctSIZE_T *Bytes,
+ OUT gctPOINTER *Logical,
+ OUT gctPOINTER *Physical
+ )
+{
+ gceSTATUS status;
+
+ gcmkONERROR(gckOS_AllocateNonPagedMemory(Os->os, gcvFALSE, Bytes, (gctPHYS_ADDR *)Physical, Logical));
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+gceSTATUS
+gctaOS_FreeSecurityMemory(
+ IN gctaOS Os,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical,
+ OUT gctPOINTER Physical
+ )
+{
+ gckOS_FreeNonPagedMemory(Os->os, Bytes, (gctPHYS_ADDR)Physical, Logical);
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaOS_AllocateNonSecurityMemory(
+ IN gctaOS Os,
+ IN gctSIZE_T *Bytes,
+ OUT gctPOINTER *Logical,
+ OUT gctPOINTER *Physical
+ )
+{
+ gceSTATUS status;
+
+ gcmkONERROR(gckOS_AllocateNonPagedMemory(Os->os, gcvFALSE, Bytes, (gctPHYS_ADDR *)Physical, Logical));
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+gceSTATUS
+gctaOS_FreeNonSecurityMemory(
+ IN gctaOS Os,
+ IN gctSIZE_T Bytes,
+ IN gctPOINTER Logical,
+ OUT gctPOINTER Physical
+ )
+{
+ gckOS_FreeNonPagedMemory(Os->os, Bytes, (gctPHYS_ADDR)Physical, Logical);
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaOS_Allocate(
+ IN gctUINT32 Bytes,
+ OUT gctPOINTER *Pointer
+ )
+{
+ return gckOS_AllocateMemory(globalTAos->os, Bytes, Pointer);
+}
+
+gceSTATUS
+gctaOS_Free(
+ IN gctPOINTER Pointer
+ )
+{
+ return gckOS_FreeMemory(globalTAos->os, Pointer);
+}
+
+gceSTATUS
+gctaOS_GetPhysicalAddress(
+ IN gctaOS Os,
+ IN gctPOINTER Logical,
+ OUT gctPHYS_ADDR_T * Physical
+ )
+{
+ gctPHYS_ADDR_T physical;
+ gceSTATUS status;
+
+ gcmkONERROR(gckOS_GetPhysicalAddress(Os->os, Logical, &physical));
+
+ *Physical = (gctUINT32)physical;
+
+ return gcvSTATUS_OK;
+
+OnError:
+ return status;
+}
+
+gceSTATUS gctaOS_WriteRegister(
+ IN gctaOS Os, IN gceCORE Core,
+ IN gctUINT32 Address,
+ IN gctUINT32 Data
+ )
+{
+ return gckOS_WriteRegisterEx(Os->os, Core, Address, Data);
+}
+
+gceSTATUS gctaOS_ReadRegister(
+ IN gctaOS Os, IN gceCORE Core,
+ IN gctUINT32 Address,
+ IN gctUINT32 *Data
+ )
+{
+ return gckOS_ReadRegisterEx(Os->os, Core, Address, Data);
+}
+
+gceSTATUS
+gctaOS_MemCopy(
+ IN gctUINT8_PTR Dest,
+ IN gctUINT8_PTR Src,
+ IN gctUINT32 Bytes
+ )
+{
+ gckOS_MemCopy(Dest, Src, Bytes);
+ return gcvSTATUS_OK;
+}
+
+gceSTATUS
+gctaOS_ZeroMemory(
+ IN gctUINT8_PTR Dest,
+ IN gctUINT32 Bytes
+ )
+{
+ gckOS_ZeroMemory(Dest, Bytes);
+ return gcvSTATUS_OK;
+}
+
+void
+gctaOS_CacheFlush(
+ IN gctUINT8_PTR Dest,
+ IN gctUINT32 Bytes
+ )
+{
+
+}
+
+void
+gctaOS_CacheClean(
+ IN gctUINT8_PTR Dest,
+ IN gctUINT32 Bytes
+ )
+{
+
+}
+
+void
+gctaOS_CacheInvalidate(
+ IN gctUINT8_PTR Dest,
+ IN gctUINT32 Bytes
+ )
+{
+
+}
+
+gceSTATUS
+gctaOS_IsPhysicalSecure(
+ IN gctaOS Os,
+ IN gctUINT32 Physical,
+ OUT gctBOOL *Secure
+ )
+{
+ return gcvSTATUS_NOT_SUPPORTED;
+}
+
+gceSTATUS
+gctaOS_Delay(
+ IN gctaOS Os,
+ IN gctUINT32 Delay
+ )
+{
+ return gckOS_Delay(Os->os, Delay);
+}
+
+gceSTATUS
+gctaOS_SetGPUPower(
+ IN gctaOS Os,
+ IN gctUINT32 Core,
+ IN gctBOOL Clock,
+ IN gctBOOL Power
+ )
+{
+ return gckOS_SetGPUPower(Os->os, Core, Power, Clock);
+}
+
+
diff --git a/drivers/mxc/hantro/Kconfig b/drivers/mxc/hantro/Kconfig
new file mode 100755
index 000000000000..815a01e27b69
--- /dev/null
+++ b/drivers/mxc/hantro/Kconfig
@@ -0,0 +1,14 @@
+#
+# Codec configuration
+#
+
+menu "MXC HANTRO(Video Processing Unit) support"
+ depends on ARCH_FSL_IMX8MQ
+
+config MXC_HANTRO
+ tristate "Support for MXC HANTRO(Video Processing Unit)"
+ default y
+ ---help---
+ VPU codec device.
+
+endmenu
diff --git a/drivers/mxc/hantro/Makefile b/drivers/mxc/hantro/Makefile
new file mode 100755
index 000000000000..3673ac214fa3
--- /dev/null
+++ b/drivers/mxc/hantro/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the VPU drivers.
+#
+
+ccflags-y += -I$(PWD)/./dwl
+
+obj-$(CONFIG_MXC_HANTRO) += hantrodec.o
+
diff --git a/drivers/mxc/hantro/dwl_defs.h b/drivers/mxc/hantro/dwl_defs.h
new file mode 100755
index 000000000000..8976dcf156b6
--- /dev/null
+++ b/drivers/mxc/hantro/dwl_defs.h
@@ -0,0 +1,94 @@
+/*****************************************************************************
+ * The GPL License (GPL)
+ *
+ * Copyright (c) 2015-2017, VeriSilicon Inc.
+ * Copyright (c) 2011-2014, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *****************************************************************************/
+
+#ifndef SOFTWARE_LINUX_DWL_DWL_DEFS_H_
+#define SOFTWARE_LINUX_DWL_DWL_DEFS_H_
+
+#define DWL_MPEG2_E 31 /* 1 bit */
+#define DWL_VC1_E 29 /* 2 bits */
+#define DWL_JPEG_E 28 /* 1 bit */
+#define DWL_MPEG4_E 26 /* 2 bits */
+#define DWL_H264_E 24 /* 2 bits */
+#define DWL_VP6_E 23 /* 1 bit */
+#define DWL_RV_E 26 /* 2 bits */
+#define DWL_VP8_E 23 /* 1 bit */
+#define DWL_VP7_E 24 /* 1 bit */
+#define DWL_WEBP_E 19 /* 1 bit */
+#define DWL_AVS_E 22 /* 1 bit */
+#if 0
+#define DWL_PP_E 16 /* 1 bit */
+#endif
+#define DWL_PP_E 31 /* 1 bit */
+#define DWL_HEVC_E 5 /* 2 bits */
+#define DWL_VP9_E 3 /* 2 bits */
+
+#define DWL_HEVC_ENA 0 /* 1 bits */
+#define DWL_VP9_ENA 1 /* 1 bits */
+#define DWL_RFC_E 2 /* 1 bits */
+#define DWL_DS_E 3 /* 1 bits */
+#define DWL_HEVC_VER 8 /* 4 bits */
+#define DWL_VP9_PROFILE 12 /* 3 bits */
+#define DWL_RING_E 16 /* 1 bits */
+
+#define HANTRODEC_IRQ_STAT_DEC 1
+#define HANTRODEC_IRQ_STAT_DEC_OFF (HANTRODEC_IRQ_STAT_DEC * 4)
+
+#define HANTRODECPP_SYNTH_CFG 60
+#define HANTRODECPP_SYNTH_CFG_OFF (HANTRODECPP_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG 50
+#define HANTRODEC_SYNTH_CFG_OFF (HANTRODEC_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG_2 54
+#define HANTRODEC_SYNTH_CFG_2_OFF (HANTRODEC_SYNTH_CFG_2 * 4)
+#define HANTRODEC_SYNTH_CFG_3 56
+#define HANTRODEC_SYNTH_CFG_3_OFF (HANTRODEC_SYNTH_CFG_3 * 4)
+#define HANTRODEC_CFG_STAT 23
+#define HANTRODEC_CFG_STAT_OFF (HANTRODEC_CFG_STAT * 4)
+
+
+#define HANTRODEC_DEC_E 0x01
+#define HANTRODEC_PP_E 0x01
+#define HANTRODEC_DEC_ABORT 0x20
+#define HANTRODEC_DEC_IRQ_DISABLE 0x10
+#define HANTRODEC_DEC_IRQ 0x100
+
+/* Legacy from G1 */
+#define HANTRO_IRQ_STAT_DEC 1
+#define HANTRO_IRQ_STAT_DEC_OFF (HANTRO_IRQ_STAT_DEC * 4)
+#define HANTRO_IRQ_STAT_PP 60
+#define HANTRO_IRQ_STAT_PP_OFF (HANTRO_IRQ_STAT_PP * 4)
+
+#define HANTROPP_SYNTH_CFG 100
+#define HANTROPP_SYNTH_CFG_OFF (HANTROPP_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG 50
+#define HANTRODEC_SYNTH_CFG_OFF (HANTRODEC_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG_2 54
+#define HANTRODEC_SYNTH_CFG_2_OFF (HANTRODEC_SYNTH_CFG_2 * 4)
+
+#define HANTRO_DEC_E 0x01
+#define HANTRO_PP_E 0x01
+#define HANTRO_DEC_ABORT 0x20
+#define HANTRO_DEC_IRQ_DISABLE 0x10
+#define HANTRO_PP_IRQ_DISABLE 0x10
+#define HANTRO_DEC_IRQ 0x100
+#define HANTRO_PP_IRQ 0x100
+
+#endif /* SOFTWARE_LINUX_DWL_DWL_DEFS_H_ */
diff --git a/drivers/mxc/hantro/hantrodec.c b/drivers/mxc/hantro/hantrodec.c
new file mode 100755
index 000000000000..0346a06fbb15
--- /dev/null
+++ b/drivers/mxc/hantro/hantrodec.c
@@ -0,0 +1,1918 @@
+/*****************************************************************************
+ * The GPL License (GPL)
+ *
+ * Copyright (c) 2015-2017, VeriSilicon Inc.
+ * Copyright (c) 2011-2014, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *****************************************************************************/
+#include <linux/hantrodec.h>
+#include "dwl_defs.h"
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/busfreq-imx.h>
+
+#ifdef CONFIG_DEVICE_THERMAL
+#include <linux/device_cooling.h>
+#define HANTRO_REG_THERMAL_NOTIFIER(a) register_devfreq_cooling_notifier(a)
+#define HANTRO_UNREG_THERMAL_NOTIFIER(a) unregister_devfreq_cooling_notifier(a)
+DEFINE_SPINLOCK(thermal_lock);
+/*1:hot, 0: not hot*/
+static int thermal_event;
+static int thermal_cur;
+static int hantro_clock_ratio = 2;
+static int hantro_dynamic_clock;
+module_param(hantro_clock_ratio, int, 0644);
+module_param(hantro_dynamic_clock, int, 0644);
+MODULE_PARM_DESC(hantro_clock_ratio, "clock ratio 1/N");
+MODULE_PARM_DESC(hantro_dynamic_clock, "enable or disable dynamic clock rate");
+#endif
+
+/*hantro G1 regs config including dec and pp*/
+#define HANTRO_DEC_ORG_REGS 60
+#define HANTRO_PP_ORG_REGS 41
+
+#define HANTRO_DEC_EXT_REGS 27
+#define HANTRO_PP_EXT_REGS 9
+
+#define HANTRO_G1_DEC_TOTAL_REGS (HANTRO_DEC_ORG_REGS + HANTRO_DEC_EXT_REGS)
+#define HANTRO_PP_TOTAL_REGS (HANTRO_PP_ORG_REGS + HANTRO_PP_EXT_REGS)
+#define HANTRO_G1_TOTAL_REGS 155 /*G1 total regs*/
+
+#define HANTRO_DEC_ORG_FIRST_REG 0
+#define HANTRO_DEC_ORG_LAST_REG 59
+#define HANTRO_DEC_EXT_FIRST_REG 119
+#define HANTRO_DEC_EXT_LAST_REG 145
+
+#define HANTRO_PP_ORG_FIRST_REG 60
+#define HANTRO_PP_ORG_LAST_REG 100
+#define HANTRO_PP_EXT_FIRST_REG 146
+#define HANTRO_PP_EXT_LAST_REG 154
+
+/*hantro G2 reg config*/
+#define HANTRO_G2_DEC_REGS 265 /*G2 total regs*/
+
+#define HANTRO_G2_DEC_FIRST_REG 0
+#define HANTRO_G2_DEC_LAST_REG (HANTRO_G2_DEC_REGS - 1)
+
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#define DEC_IO_SIZE_MAX (MAX(HANTRO_G2_DEC_REGS, HANTRO_G1_TOTAL_REGS) * 4)
+
+/********************************************************************
+ * PORTING SEGMENT
+ * NOTES: customer should modify these configuration if do porting to own platform.
+ * Please guarantee the base_addr, io_size,dec_irq belong to same core.
+ ********************************************************************/
+
+#define HXDEC_MAX_CORES 2
+
+/* Logic module base address */
+#define SOCLE_LOGIC_0_BASE 0x38300000
+#define SOCLE_LOGIC_1_BASE 0x38310000
+#define BLK_CTL_BASE 0x38320000
+
+#define VEXPRESS_LOGIC_0_BASE 0xFC010000
+#define VEXPRESS_LOGIC_1_BASE 0xFC020000
+
+#define DEC_IO_SIZE_0 ((HANTRO_G2_DEC_REGS) * 4) /* bytes */
+#define DEC_IO_SIZE_1 ((HANTRO_G2_DEC_REGS) * 4) /* bytes */
+
+#define HANTRO_G1_DEF_CLK (600000000)
+#define HANTRO_G2_DEF_CLK (600000000)
+#define HANTRO_BUS_DEF_CLK (800000000)
+#define HANTRO_CLK_VOL_THR (600000000)
+/***********************************************************************/
+
+#define IS_G1(hw_id) ((hw_id == 0x6731) ? 1:0)
+
+static const int DecHwId[] = {
+ 0x8190, /* Legacy HW */
+ 0x8170,
+ 0x9170,
+ 0x9190,
+ 0x6731, /* G1 */
+ 0x6732 /* G2 */
+};
+
+ulong multicorebase[HXDEC_MAX_CORES] = {
+ SOCLE_LOGIC_0_BASE,
+ SOCLE_LOGIC_1_BASE
+};
+
+
+static struct class *hantro_class;
+#define DEVICE_NAME "mxc_hantro"
+
+static struct device *hantro_dev;
+static struct clk *hantro_clk_g1;
+static struct clk *hantro_clk_g2;
+static struct clk *hantro_clk_bus;
+static struct regulator *hantro_regulator;
+
+static int hantro_dbg = -1;
+module_param(hantro_dbg, int, 0644);
+MODULE_PARM_DESC(hantro_dbg, "Debug level (0-1)");
+#undef PDEBUG
+#define PDEBUG(fmt, arg...) \
+ do { \
+ if (hantro_dbg > 0) { \
+ dev_info(hantro_dev, fmt, ## arg); \
+ } \
+ } while (0)
+
+
+static int hantrodec_major; /* dynamic allocation */
+
+/* here's all the must remember stuff */
+typedef struct {
+ char *buffer;
+ unsigned int iosize[HXDEC_MAX_CORES];
+ volatile u8 *hwregs[HXDEC_MAX_CORES];
+ int irq[HXDEC_MAX_CORES];
+ int hw_id[HXDEC_MAX_CORES];
+ int cores;
+ struct fasync_struct *async_queue_dec;
+ struct fasync_struct *async_queue_pp;
+} hantrodec_t;
+
+static hantrodec_t hantrodec_data; /* dynamic allocation? */
+
+static int ReserveIO(void);
+static void ReleaseIO(void);
+
+static void ResetAsic(hantrodec_t *dev);
+
+#ifdef HANTRODEC_DEBUG
+static void dump_regs(hantrodec_t *dev);
+#endif
+
+/* IRQ handler */
+static irqreturn_t hantrodec_isr(int irq, void *dev_id);
+
+static u32 dec_regs[HXDEC_MAX_CORES][DEC_IO_SIZE_MAX/4];
+struct semaphore dec_core_sem;
+struct semaphore pp_core_sem;
+
+static int dec_irq;
+static int pp_irq;
+
+atomic_t irq_rx = ATOMIC_INIT(0);
+atomic_t irq_tx = ATOMIC_INIT(0);
+
+static struct file *dec_owner[HXDEC_MAX_CORES];
+static struct file *pp_owner[HXDEC_MAX_CORES];
+
+/* spinlock_t owner_lock = SPIN_LOCK_UNLOCKED; */
+DEFINE_SPINLOCK(owner_lock);
+
+DECLARE_WAIT_QUEUE_HEAD(dec_wait_queue);
+DECLARE_WAIT_QUEUE_HEAD(pp_wait_queue);
+
+DECLARE_WAIT_QUEUE_HEAD(hw_queue);
+
+#define DWL_CLIENT_TYPE_H264_DEC 1U
+#define DWL_CLIENT_TYPE_MPEG4_DEC 2U
+#define DWL_CLIENT_TYPE_JPEG_DEC 3U
+#define DWL_CLIENT_TYPE_PP 4U
+#define DWL_CLIENT_TYPE_VC1_DEC 5U
+#define DWL_CLIENT_TYPE_MPEG2_DEC 6U
+#define DWL_CLIENT_TYPE_VP6_DEC 7U
+#define DWL_CLIENT_TYPE_AVS_DEC 8U
+#define DWL_CLIENT_TYPE_RV_DEC 9U
+#define DWL_CLIENT_TYPE_VP8_DEC 10U
+#define DWL_CLIENT_TYPE_VP9_DEC 11U
+#define DWL_CLIENT_TYPE_HEVC_DEC 12U
+
+static u32 cfg[HXDEC_MAX_CORES];
+static u32 timeout;
+
+static int hantro_update_voltage(struct device *dev)
+{
+ unsigned long new_vol, old_vol;
+ int ret;
+ unsigned long clk1, clk2;
+
+ clk1 = clk_get_rate(hantro_clk_g1);
+ clk2 = clk_get_rate(hantro_clk_g2);
+
+ if (!clk1 || !clk2)
+ return -1;
+
+ old_vol = regulator_get_voltage(hantro_regulator);
+ if ((clk1 >= HANTRO_CLK_VOL_THR) || (clk2 >= HANTRO_CLK_VOL_THR))
+ new_vol = 1000000; // 1.0v
+ else
+ new_vol = 900000; // 0.9v
+
+ if (old_vol != new_vol) {
+ ret = regulator_set_voltage_tol(hantro_regulator, new_vol, 0);
+ if (ret)
+ pr_err("failed to set hantro voltage: %ld mV\n", new_vol/1000);
+ else
+ pr_info("update hantro voltage from %ld mV to %ld mV\n", old_vol/1000, new_vol/1000);
+ }
+ return 0;
+}
+
+static int hantro_clk_enable(struct device *dev)
+{
+ clk_prepare(hantro_clk_g1);
+ clk_enable(hantro_clk_g1);
+ clk_prepare(hantro_clk_g2);
+ clk_enable(hantro_clk_g2);
+ clk_prepare(hantro_clk_bus);
+ clk_enable(hantro_clk_bus);
+ return 0;
+}
+
+static int hantro_clk_disable(struct device *dev)
+{
+ if (hantro_clk_g1) {
+ clk_disable(hantro_clk_g1);
+ clk_unprepare(hantro_clk_g1);
+ }
+ if (hantro_clk_g2) {
+ clk_disable(hantro_clk_g2);
+ clk_unprepare(hantro_clk_g2);
+ }
+ if (hantro_clk_bus) {
+ clk_disable(hantro_clk_bus);
+ clk_unprepare(hantro_clk_bus);
+ }
+ return 0;
+}
+
+static int hantro_ctrlblk_reset(struct device *dev)
+{
+ volatile u8 *iobase;
+
+ //config G1/G2
+ hantro_clk_enable(dev);
+ iobase = (volatile u8 *)ioremap_nocache(BLK_CTL_BASE, 0x10000);
+ iowrite32(0x3, iobase); //VPUMIX G1/G2 block soft reset control
+ iowrite32(0x3, iobase+4); //VPUMIX G1/G2 block clock enable control
+ iowrite32(0xFFFFFFFF, iobase + 0x8); // all G1 fuse dec enable
+ iowrite32(0xFFFFFFFF, iobase + 0xC); // all G1 fuse pp enable
+ iowrite32(0xFFFFFFFF, iobase + 0x10); // all G2 fuse dec enable
+ iounmap(iobase);
+ hantro_clk_disable(dev);
+ return 0;
+}
+
+#ifdef CONFIG_DEVICE_THERMAL
+static int hantro_thermal_check(struct device *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&thermal_lock, flags);
+ if (thermal_event == thermal_cur) {
+ /*nothing to do and return directly*/
+ spin_unlock_irqrestore(&thermal_lock, flags);
+ return 0;
+ }
+ thermal_cur = thermal_event;
+ spin_unlock_irqrestore(&thermal_lock, flags);
+
+ if (thermal_cur) {
+ int ratio = hantro_clock_ratio;
+
+ pr_debug("hantro: too hot, need to decrease clock, ratio: 1/%d\n", ratio);
+ /*clock disable/enable are not required for vpu clock rate operation*/
+ clk_set_rate(hantro_clk_g1, HANTRO_G1_DEF_CLK/ratio);
+ clk_set_rate(hantro_clk_g2, HANTRO_G2_DEF_CLK/ratio);
+ clk_set_rate(hantro_clk_bus, HANTRO_BUS_DEF_CLK/ratio);
+ } else {
+ pr_debug("hantro: not hot again, will restore default clock\n");
+ clk_set_rate(hantro_clk_g1, HANTRO_G1_DEF_CLK);
+ clk_set_rate(hantro_clk_g2, HANTRO_G2_DEF_CLK);
+ clk_set_rate(hantro_clk_bus, HANTRO_BUS_DEF_CLK);
+ }
+ pr_info("hantro: event(%d), g1, g2, bus clock: %ld, %ld, %ld\n", thermal_cur,
+ clk_get_rate(hantro_clk_g1), clk_get_rate(hantro_clk_g2), clk_get_rate(hantro_clk_bus));
+ hantro_update_voltage(dev);
+ return 0;
+}
+
+static int hantro_thermal_hot_notify(struct notifier_block *nb, unsigned long event, void *dummy)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&thermal_lock, flags);
+ thermal_event = event; /*event: 1: hot, 0: cool*/
+ spin_unlock_irqrestore(&thermal_lock, flags);
+ pr_info("hantro receive hot notification event: %ld\n", event);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block hantro_thermal_hot_notifier = {
+ .notifier_call = hantro_thermal_hot_notify,
+};
+#endif //CONFIG_DEVICE_THERMAL
+
+static void ReadCoreConfig(hantrodec_t *dev)
+{
+ int c;
+ u32 reg, tmp, mask;
+
+ memset(cfg, 0, sizeof(cfg));
+
+ for (c = 0; c < dev->cores; c++) {
+ /* Decoder configuration */
+ if (IS_G1(dev->hw_id[c])) {
+ reg = ioread32(dev->hwregs[c] + HANTRODEC_SYNTH_CFG * 4);
+
+ tmp = (reg >> DWL_H264_E) & 0x3U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has H264\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_H264_DEC : 0;
+
+ tmp = (reg >> DWL_JPEG_E) & 0x01U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has JPEG\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+
+ tmp = (reg >> DWL_MPEG4_E) & 0x3U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has MPEG4\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG4_DEC : 0;
+
+ tmp = (reg >> DWL_VC1_E) & 0x3U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has VC1\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VC1_DEC : 0;
+
+ tmp = (reg >> DWL_MPEG2_E) & 0x01U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has MPEG2\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG2_DEC : 0;
+
+ tmp = (reg >> DWL_VP6_E) & 0x01U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has VP6\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP6_DEC : 0;
+
+ reg = ioread32(dev->hwregs[c] + HANTRODEC_SYNTH_CFG_2 * 4);
+
+ /* VP7 and WEBP is part of VP8 */
+ mask = (1 << DWL_VP8_E) | (1 << DWL_VP7_E) | (1 << DWL_WEBP_E);
+ tmp = (reg & mask);
+ if (tmp & (1 << DWL_VP8_E))
+ pr_debug("hantrodec: Core[%d] has VP8\n", c);
+ if (tmp & (1 << DWL_VP7_E))
+ pr_debug("hantrodec: Core[%d] has VP7\n", c);
+ if (tmp & (1 << DWL_WEBP_E))
+ pr_debug("hantrodec: Core[%d] has WebP\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP8_DEC : 0;
+
+ tmp = (reg >> DWL_AVS_E) & 0x01U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has AVS\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_AVS_DEC : 0;
+
+ tmp = (reg >> DWL_RV_E) & 0x03U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has RV\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_RV_DEC : 0;
+
+ /* Post-processor configuration */
+ reg = ioread32(dev->hwregs[c] + HANTROPP_SYNTH_CFG * 4);
+ } else {
+ reg = ioread32(dev->hwregs[c] + HANTRODEC_SYNTH_CFG_2 * 4);
+
+ tmp = (reg >> DWL_HEVC_E) & 0x3U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has HEVC\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_HEVC_DEC : 0;
+
+ tmp = (reg >> DWL_VP9_E) & 0x03U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has VP9\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_VP9_DEC : 0;
+ }
+
+ /* Post-processor configuration */
+ reg = ioread32(dev->hwregs[c] + HANTRODECPP_SYNTH_CFG * 4);
+
+ tmp = (reg >> DWL_PP_E) & 0x01U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has PP\n", c);
+ cfg[c] |= tmp ? 1 << DWL_CLIENT_TYPE_PP : 0;
+ }
+}
+
+static int CoreHasFormat(const u32 *cfg, int Core, u32 format)
+{
+ return (cfg[Core] & (1 << format)) ? 1 : 0;
+}
+
+int GetDecCore(long Core, hantrodec_t *dev, struct file *filp)
+{
+ int success = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&owner_lock, flags);
+ if (dec_owner[Core] == NULL) {
+ dec_owner[Core] = filp;
+ success = 1;
+ }
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ return success;
+}
+
+int GetDecCoreAny(long *Core, hantrodec_t *dev, struct file *filp,
+ unsigned long format) {
+ int success = 0;
+ long c;
+
+ *Core = -1;
+
+ for (c = 0; c < dev->cores; c++) {
+ /* a free Core that has format */
+ if (CoreHasFormat(cfg, c, format) && GetDecCore(c, dev, filp)) {
+ success = 1;
+ *Core = c;
+ break;
+ }
+ }
+
+ return success;
+}
+int GetDecCoreID(hantrodec_t *dev, struct file *filp,
+ unsigned long format) {
+ long c;
+
+ int core_id = -1;
+
+ for (c = 0; c < dev->cores; c++) {
+ /* a Core that has format */
+ if (CoreHasFormat(cfg, c, format)) {
+ core_id = c;
+ break;
+ }
+ }
+ PDEBUG("GetDecCoreID=%d\n", core_id);
+ return core_id;
+}
+
+static int hantrodec_choose_core(int is_g1)
+{
+ volatile unsigned char *reg = NULL;
+ unsigned int blk_base = BLK_CTL_BASE;
+
+ PDEBUG("hantrodec_choose_core\n");
+ if (!request_mem_region(blk_base, 0x1000, "blk_ctl")) {
+ pr_err("blk_ctl: failed to reserve HW regs\n");
+ return -EBUSY;
+ }
+
+ reg = (volatile u8 *) ioremap_nocache(blk_base, 0x1000);
+
+ if (reg == NULL) {
+ pr_err("blk_ctl: failed to ioremap HW regs\n");
+ if (reg)
+ iounmap((void *)reg);
+ release_mem_region(blk_base, 0x1000);
+ return -EBUSY;
+ }
+
+ // G1 use, set to 1; G2 use, set to 0, choose the one you are using
+ if (is_g1)
+ iowrite32(0x1, reg + 0x14); // VPUMIX only use G1
+ else
+ iowrite32(0x0, reg + 0x14); // VPUMIX only use G2
+
+ if (reg)
+ iounmap((void *)reg);
+ release_mem_region(blk_base, 0x1000);
+ PDEBUG("hantrodec_choose_core OK!\n");
+ return 0;
+}
+
+
+long ReserveDecoder(hantrodec_t *dev, struct file *filp, unsigned long format)
+{
+ long Core = -1;
+
+ /* reserve a Core */
+ if (down_interruptible(&dec_core_sem))
+ return -ERESTARTSYS;
+
+ /* lock a Core that has specific format*/
+ if (wait_event_interruptible(hw_queue, GetDecCoreAny(&Core, dev, filp, format) != 0))
+ return -ERESTARTSYS;
+
+ if (IS_G1(dev->hw_id[Core])) {
+ if (0 == hantrodec_choose_core(1))
+ PDEBUG("G1 is reserved\n");
+ else
+ return -1;
+ } else {
+ if (0 == hantrodec_choose_core(0))
+ PDEBUG("G2 is reserved\n");
+ else
+ return -1;
+ }
+
+#ifdef CONFIG_DEVICE_THERMAL
+ if (hantro_dynamic_clock)
+ hantro_thermal_check(hantro_dev);
+#endif
+
+ return Core;
+}
+
+void ReleaseDecoder(hantrodec_t *dev, long Core)
+{
+ u32 status;
+ unsigned long flags;
+
+ status = ioread32(dev->hwregs[Core] + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+ /* make sure HW is disabled */
+ if (status & HANTRODEC_DEC_E) {
+ pr_info("hantrodec: DEC[%li] still enabled -> reset\n", Core);
+
+ /* abort decoder */
+ status |= HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+ iowrite32(status, dev->hwregs[Core] + HANTRODEC_IRQ_STAT_DEC_OFF);
+ }
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ dec_owner[Core] = NULL;
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ up(&dec_core_sem);
+
+ wake_up_interruptible_all(&hw_queue);
+
+}
+
+long ReservePostProcessor(hantrodec_t *dev, struct file *filp)
+{
+ unsigned long flags;
+
+ long Core = 0;
+
+ /* single Core PP only */
+ if (down_interruptible(&pp_core_sem))
+ return -ERESTARTSYS;
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ pp_owner[Core] = filp;
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ return Core;
+}
+
+void ReleasePostProcessor(hantrodec_t *dev, long Core)
+{
+ unsigned long flags;
+
+ u32 status = ioread32(dev->hwregs[Core] + HANTRO_IRQ_STAT_PP_OFF);
+
+ /* make sure HW is disabled */
+ if (status & HANTRO_PP_E) {
+ pr_info("hantrodec: PP[%li] still enabled -> reset\n", Core);
+
+ /* disable IRQ */
+ status |= HANTRO_PP_IRQ_DISABLE;
+
+ /* disable postprocessor */
+ status &= (~HANTRO_PP_E);
+ iowrite32(0x10, dev->hwregs[Core] + HANTRO_IRQ_STAT_PP_OFF);
+ }
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ pp_owner[Core] = NULL;
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ up(&pp_core_sem);
+}
+
+long ReserveDecPp(hantrodec_t *dev, struct file *filp, unsigned long format)
+{
+ /* reserve Core 0, DEC+PP for pipeline */
+ unsigned long flags;
+
+ long Core = 0;
+
+ /* check that Core has the requested dec format */
+ if (!CoreHasFormat(cfg, Core, format))
+ return -EFAULT;
+
+ /* check that Core has PP */
+ if (!CoreHasFormat(cfg, Core, DWL_CLIENT_TYPE_PP))
+ return -EFAULT;
+
+ /* reserve a Core */
+ if (down_interruptible(&dec_core_sem))
+ return -ERESTARTSYS;
+
+ /* wait until the Core is available */
+ if (wait_event_interruptible(hw_queue, GetDecCore(Core, dev, filp) != 0)) {
+ up(&dec_core_sem);
+ return -ERESTARTSYS;
+ }
+
+ if (down_interruptible(&pp_core_sem)) {
+ ReleaseDecoder(dev, Core);
+ return -ERESTARTSYS;
+ }
+
+ spin_lock_irqsave(&owner_lock, flags);
+ pp_owner[Core] = filp;
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ return Core;
+}
+
+long DecFlushRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+ long ret = 0, i;
+
+ u32 id = Core->id;
+
+ if (IS_G1(dev->hw_id[id])) {
+ /* copy original dec regs to kernal space*/
+ ret = copy_from_user(dec_regs[id], Core->regs, HANTRO_DEC_ORG_REGS*4);
+ if (ret) {
+ pr_err("copy_from_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+#ifdef USE_64BIT_ENV
+ /* copy extended dec regs to kernal space*/
+ ret = copy_from_user(dec_regs[id] + HANTRO_DEC_EXT_FIRST_REG,
+ Core->regs + HANTRO_DEC_EXT_FIRST_REG, HANTRO_DEC_EXT_REGS * 4);
+#endif
+ if (ret) {
+ pr_err("copy_from_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+
+ /* write dec regs but the status reg[1] to hardware */
+ /* both original and extended regs need to be written */
+ for (i = 2; i <= HANTRO_DEC_ORG_LAST_REG; i++)
+ iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+#ifdef USE_64BIT_ENV
+ for (i = HANTRO_DEC_EXT_FIRST_REG; i <= HANTRO_DEC_EXT_LAST_REG; i++)
+ iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+#endif
+ } else {
+ ret = copy_from_user(dec_regs[id], Core->regs, HANTRO_G2_DEC_REGS*4);
+ if (ret) {
+ pr_err("copy_from_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+
+ /* write all regs but the status reg[1] to hardware */
+ for (i = 2; i <= HANTRO_G2_DEC_LAST_REG; i++)
+ iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+ }
+
+ /* write the status register, which may start the decoder */
+ iowrite32(dec_regs[id][1], dev->hwregs[id] + 4);
+
+ PDEBUG("flushed registers on Core %d\n", id);
+
+ return 0;
+}
+
+long DecRefreshRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+ long ret, i;
+ u32 id = Core->id;
+
+ if (IS_G1(dev->hw_id[id])) {
+ /* user has to know exactly what they are asking for */
+ //if(Core->size != (HANTRO_DEC_ORG_REGS * 4))
+ // return -EFAULT;
+
+ /* read all registers from hardware */
+ /* both original and extended regs need to be read */
+ for (i = 0; i <= HANTRO_DEC_ORG_LAST_REG; i++)
+ dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+#ifdef USE_64BIT_ENV
+ for (i = HANTRO_DEC_EXT_FIRST_REG; i <= HANTRO_DEC_EXT_LAST_REG; i++)
+ dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+#endif
+
+ if (timeout) {
+ /* Enable TIMEOUT bits in Reg[1] */
+ dec_regs[id][1] = 0x40100;
+ /* Reset HW */
+ ResetAsic(dev);
+ timeout = 0;
+ }
+
+ /* put registers to user space*/
+ /* put original registers to user space*/
+ ret = copy_to_user(Core->regs, dec_regs[id], HANTRO_DEC_ORG_REGS*4);
+#ifdef USE_64BIT_ENV
+ /*put extended registers to user space*/
+ ret = copy_to_user(Core->regs + HANTRO_DEC_EXT_FIRST_REG,
+ dec_regs[id] + HANTRO_DEC_EXT_FIRST_REG, HANTRO_DEC_EXT_REGS * 4);
+#endif
+ if (ret) {
+ pr_err("copy_to_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+ } else {
+ /* user has to know exactly what they are asking for */
+ if (Core->size != (HANTRO_G2_DEC_REGS * 4))
+ return -EFAULT;
+
+ /* read all registers from hardware */
+ for (i = 0; i <= HANTRO_G2_DEC_LAST_REG; i++)
+ dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+
+ if (timeout) {
+ /* Enable TIMEOUT bits in Reg[1] */
+ dec_regs[id][1] = 0x40100;
+ /* Reset HW */
+ ResetAsic(dev);
+ timeout = 0;
+ }
+
+ /* put registers to user space*/
+ ret = copy_to_user(Core->regs, dec_regs[id], HANTRO_G2_DEC_REGS*4);
+ if (ret) {
+ pr_err("copy_to_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+ }
+ return 0;
+}
+
+static int CheckDecIrq(hantrodec_t *dev, int id)
+{
+ unsigned long flags;
+ int rdy = 0;
+
+ const u32 irq_mask = (1 << id);
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ if (dec_irq & irq_mask) {
+ /* reset the wait condition(s) */
+ dec_irq &= ~irq_mask;
+ rdy = 1;
+ }
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ return rdy;
+}
+
+long WaitDecReadyAndRefreshRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+ u32 id = Core->id;
+ long ret;
+
+ PDEBUG("wait_event_interruptible DEC[%d]\n", id);
+
+ ret = wait_event_interruptible_timeout(dec_wait_queue, CheckDecIrq(dev, id), msecs_to_jiffies(200));
+ if (ret == -ERESTARTSYS) {
+ pr_err("DEC[%d] failed to wait_event_interruptible interrupted\n", id);
+ return -ERESTARTSYS;
+ } else if (ret == 0) {
+ pr_err("DEC[%d] wait_event_interruptible timeout\n", id);
+ timeout = 1;
+ }
+
+ atomic_inc(&irq_tx);
+
+ /* refresh registers */
+ return DecRefreshRegs(dev, Core);
+}
+
+long PPFlushRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+ long ret = 0;
+ u32 id = Core->id;
+ u32 i;
+
+ /* copy original dec regs to kernal space*/
+ ret = copy_from_user(dec_regs[id] + HANTRO_PP_ORG_FIRST_REG,
+ Core->regs + HANTRO_PP_ORG_FIRST_REG, HANTRO_PP_ORG_REGS*4);
+#ifdef USE_64BIT_ENV
+ /* copy extended dec regs to kernal space*/
+ ret = copy_from_user(dec_regs[id] + HANTRO_PP_EXT_FIRST_REG,
+ Core->regs + HANTRO_PP_EXT_FIRST_REG, HANTRO_PP_EXT_REGS*4);
+#endif
+ if (ret) {
+ pr_err("copy_from_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+
+ /* write all regs but the status reg[1] to hardware */
+ /* both original and extended regs need to be written */
+ for (i = HANTRO_PP_ORG_FIRST_REG + 1; i <= HANTRO_PP_ORG_LAST_REG; i++)
+ iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+#ifdef USE_64BIT_ENV
+ for (i = HANTRO_PP_EXT_FIRST_REG; i <= HANTRO_PP_EXT_LAST_REG; i++)
+ iowrite32(dec_regs[id][i], dev->hwregs[id] + i*4);
+#endif
+ /* write the stat reg, which may start the PP */
+ iowrite32(dec_regs[id][HANTRO_PP_ORG_FIRST_REG],
+ dev->hwregs[id] + HANTRO_PP_ORG_FIRST_REG * 4);
+
+ return 0;
+}
+
+long PPRefreshRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+ long i, ret;
+ u32 id = Core->id;
+#ifdef USE_64BIT_ENV
+ /* user has to know exactly what they are asking for */
+ if (Core->size != (HANTRO_PP_TOTAL_REGS * 4))
+ return -EFAULT;
+#else
+ /* user has to know exactly what they are asking for */
+ if (Core->size != (HANTRO_PP_ORG_REGS * 4))
+ return -EFAULT;
+#endif
+
+ /* read all registers from hardware */
+ /* both original and extended regs need to be read */
+ for (i = HANTRO_PP_ORG_FIRST_REG; i <= HANTRO_PP_ORG_LAST_REG; i++)
+ dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+#ifdef USE_64BIT_ENV
+ for (i = HANTRO_PP_EXT_FIRST_REG; i <= HANTRO_PP_EXT_LAST_REG; i++)
+ dec_regs[id][i] = ioread32(dev->hwregs[id] + i*4);
+#endif
+ /* put registers to user space*/
+ /* put original registers to user space*/
+ ret = copy_to_user(Core->regs + HANTRO_PP_ORG_FIRST_REG,
+ dec_regs[id] + HANTRO_PP_ORG_FIRST_REG, HANTRO_PP_ORG_REGS*4);
+#ifdef USE_64BIT_ENV
+ /* put extended registers to user space*/
+ ret = copy_to_user(Core->regs + HANTRO_PP_EXT_FIRST_REG,
+ dec_regs[id] + HANTRO_PP_EXT_FIRST_REG, HANTRO_PP_EXT_REGS * 4);
+#endif
+ if (ret) {
+ pr_err("copy_to_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int CheckPPIrq(hantrodec_t *dev, int id)
+{
+ unsigned long flags;
+ int rdy = 0;
+
+ const u32 irq_mask = (1 << id);
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ if (pp_irq & irq_mask) {
+ /* reset the wait condition(s) */
+ pp_irq &= ~irq_mask;
+ rdy = 1;
+ }
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ return rdy;
+}
+
+long WaitPPReadyAndRefreshRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+ u32 id = Core->id;
+
+ PDEBUG("wait_event_interruptible PP[%d]\n", id);
+
+ if (wait_event_interruptible(pp_wait_queue, CheckPPIrq(dev, id))) {
+ pr_err("PP[%d] failed to wait_event_interruptible interrupted\n", id);
+ return -ERESTARTSYS;
+ }
+
+ atomic_inc(&irq_tx);
+
+ /* refresh registers */
+ return PPRefreshRegs(dev, Core);
+}
+
+static int CheckCoreIrq(hantrodec_t *dev, const struct file *filp, int *id)
+{
+ unsigned long flags;
+ int rdy = 0, n = 0;
+
+ do {
+ u32 irq_mask = (1 << n);
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ if (dec_irq & irq_mask) {
+ if (dec_owner[n] == filp) {
+ /* we have an IRQ for our client */
+
+ /* reset the wait condition(s) */
+ dec_irq &= ~irq_mask;
+
+ /* signal ready Core no. for our client */
+ *id = n;
+
+ rdy = 1;
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+ break;
+ } else if (dec_owner[n] == NULL) {
+ /* zombie IRQ */
+ pr_info("IRQ on Core[%d], but no owner!!!\n", n);
+
+ /* reset the wait condition(s) */
+ dec_irq &= ~irq_mask;
+ }
+ }
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ n++; /* next Core */
+ } while (n < dev->cores);
+
+ return rdy;
+}
+
+long WaitCoreReady(hantrodec_t *dev, const struct file *filp, int *id)
+{
+ PDEBUG("wait_event_interruptible CORE\n");
+
+ if (wait_event_interruptible(dec_wait_queue, CheckCoreIrq(dev, filp, id))) {
+ pr_err("CORE failed to wait_event_interruptible interrupted\n");
+ return -ERESTARTSYS;
+ }
+
+ atomic_inc(&irq_tx);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------
+ *Function name : hantrodec_ioctl
+ *Description : communication method to/from the user space
+ *
+ *Return type : long
+ *-------------------------------------------------------------------------
+ */
+
+static long hantrodec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+ long tmp;
+
+ PDEBUG("ioctl cmd 0x%08x\n", cmd);
+ /*
+ * extract the type and number bitfields, and don't decode
+ * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+ */
+ if (_IOC_TYPE(cmd) != HANTRODEC_IOC_MAGIC)
+ return -ENOTTY;
+ if (_IOC_NR(cmd) > HANTRODEC_IOC_MAXNR)
+ return -ENOTTY;
+
+ /*
+ * the direction is a bitmask, and VERIFY_WRITE catches R/W
+ * transfers. `Type' is user-oriented, while
+ * access_ok is kernel-oriented, so the concept of "read" and
+ * "write" is reversed
+ */
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = !access_ok(VERIFY_WRITE, (void *) arg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ err = !access_ok(VERIFY_READ, (void *) arg, _IOC_SIZE(cmd));
+
+ if (err)
+ return -EFAULT;
+
+ switch (_IOC_NR(cmd)) {
+ case _IOC_NR(HANTRODEC_IOC_CLI): {
+ __u32 id;
+
+ __get_user(id, (__u32 *)arg);
+ if (id >= hantrodec_data.cores)
+ return -EFAULT;
+ disable_irq(hantrodec_data.irq[id]);
+ break;
+ }
+ case _IOC_NR(HANTRODEC_IOC_STI): {
+ __u32 id;
+
+ __get_user(id, (__u32 *)arg);
+ if (id >= hantrodec_data.cores)
+ return -EFAULT;
+ enable_irq(hantrodec_data.irq[id]);
+ break;
+ }
+ case _IOC_NR(HANTRODEC_IOCGHWOFFSET): {
+ __u32 id;
+
+ __get_user(id, (__u32 *)arg);
+ if (id >= hantrodec_data.cores)
+ return -EFAULT;
+
+ __put_user(multicorebase[id], (unsigned long *) arg);
+ break;
+ }
+ case _IOC_NR(HANTRODEC_IOCGHWIOSIZE): {
+ __u32 id;
+ __u32 io_size;
+
+ __get_user(id, (__u32 *)arg);
+ if (id >= hantrodec_data.cores)
+ return -EFAULT;
+ io_size = hantrodec_data.iosize[id];
+ __put_user(io_size, (u32 *) arg);
+
+ return 0;
+ }
+ case _IOC_NR(HANTRODEC_IOC_MC_OFFSETS): {
+ tmp = copy_to_user((u64 *) arg, multicorebase, sizeof(multicorebase));
+ if (err) {
+ pr_err("copy_to_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+ break;
+ }
+ case _IOC_NR(HANTRODEC_IOC_MC_CORES):
+ __put_user(hantrodec_data.cores, (unsigned int *) arg);
+ PDEBUG("hantrodec_data.cores=%d\n", hantrodec_data.cores);
+ break;
+ case _IOC_NR(HANTRODEC_IOCS_DEC_PUSH_REG): {
+ struct core_desc Core;
+
+ /* get registers from user space*/
+ tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+ if (tmp) {
+ pr_err("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ DecFlushRegs(&hantrodec_data, &Core);
+ break;
+ }
+ case _IOC_NR(HANTRODEC_IOCS_PP_PUSH_REG): {
+ struct core_desc Core;
+
+ /* get registers from user space*/
+ tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+ if (tmp) {
+ pr_err("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ PPFlushRegs(&hantrodec_data, &Core);
+ break;
+ }
+ case _IOC_NR(HANTRODEC_IOCS_DEC_PULL_REG): {
+ struct core_desc Core;
+
+ /* get registers from user space*/
+ tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+ if (tmp) {
+ pr_err("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ return DecRefreshRegs(&hantrodec_data, &Core);
+ }
+ case _IOC_NR(HANTRODEC_IOCS_PP_PULL_REG): {
+ struct core_desc Core;
+
+ /* get registers from user space*/
+ tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+ if (tmp) {
+ pr_err("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ return PPRefreshRegs(&hantrodec_data, &Core);
+ }
+ case _IOC_NR(HANTRODEC_IOCH_DEC_RESERVE): {
+ PDEBUG("Reserve DEC Core, format = %li\n", arg);
+ return ReserveDecoder(&hantrodec_data, filp, arg);
+ }
+ case _IOC_NR(HANTRODEC_IOCT_DEC_RELEASE): {
+ if (arg >= hantrodec_data.cores || dec_owner[arg] != filp) {
+ pr_err("bogus DEC release, Core = %li\n", arg);
+ return -EFAULT;
+ }
+
+ PDEBUG("Release DEC, Core = %li\n", arg);
+
+ ReleaseDecoder(&hantrodec_data, arg);
+
+ break;
+ }
+ case _IOC_NR(HANTRODEC_IOCQ_PP_RESERVE):
+ return ReservePostProcessor(&hantrodec_data, filp);
+ case _IOC_NR(HANTRODEC_IOCT_PP_RELEASE): {
+ if (arg != 0 || pp_owner[arg] != filp) {
+ pr_err("bogus PP release %li\n", arg);
+ return -EFAULT;
+ }
+
+ ReleasePostProcessor(&hantrodec_data, arg);
+
+ break;
+ }
+ case _IOC_NR(HANTRODEC_IOCX_DEC_WAIT): {
+ struct core_desc Core;
+
+ /* get registers from user space */
+ tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+ if (tmp) {
+ pr_err("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ return WaitDecReadyAndRefreshRegs(&hantrodec_data, &Core);
+ }
+ case _IOC_NR(HANTRODEC_IOCX_PP_WAIT): {
+ struct core_desc Core;
+
+ /* get registers from user space */
+ tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+ if (tmp) {
+ pr_err("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ return WaitPPReadyAndRefreshRegs(&hantrodec_data, &Core);
+ }
+ case _IOC_NR(HANTRODEC_IOCG_CORE_WAIT): {
+ int id;
+
+ tmp = WaitCoreReady(&hantrodec_data, filp, &id);
+ __put_user(id, (int *) arg);
+ return tmp;
+ }
+ case _IOC_NR(HANTRODEC_IOX_ASIC_ID): {
+ u32 id;
+
+ __get_user(id, (u32 *)arg);
+ if (id >= hantrodec_data.cores)
+ return -EFAULT;
+ id = ioread32(hantrodec_data.hwregs[id]);
+ __put_user(id, (u32 *) arg);
+ return 0;
+ }
+ case _IOC_NR(HANTRODEC_IOCG_CORE_ID): {
+ PDEBUG("Get DEC Core_id, format = %li\n", arg);
+ return GetDecCoreID(&hantrodec_data, filp, arg);
+ }
+ case _IOC_NR(HANTRODEC_DEBUG_STATUS): {
+ PDEBUG("hantrodec: dec_irq = 0x%08x\n", dec_irq);
+ PDEBUG("hantrodec: pp_irq = 0x%08x\n", pp_irq);
+
+ PDEBUG("hantrodec: IRQs received/sent2user = %d / %d\n",
+ atomic_read(&irq_rx), atomic_read(&irq_tx));
+
+ for (tmp = 0; tmp < hantrodec_data.cores; tmp++) {
+ PDEBUG("hantrodec: dec_core[%li] %s\n",
+ tmp, dec_owner[tmp] == NULL ? "FREE" : "RESERVED");
+ PDEBUG("hantrodec: pp_core[%li] %s\n",
+ tmp, pp_owner[tmp] == NULL ? "FREE" : "RESERVED");
+ }
+ }
+ default:
+ return -ENOTTY;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_COMPAT
+struct core_desc_32 {
+ __u32 id; /* id of the Core */
+ compat_caddr_t regs; /* pointer to user registers */
+ __u32 size; /* size of register space */
+};
+
+static int get_hantro_core_desc32(struct core_desc *kp, struct core_desc_32 __user *up)
+{
+ u32 tmp;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(struct core_desc_32)) ||
+ get_user(kp->id, &up->id) ||
+ get_user(kp->size, &up->size) ||
+ get_user(tmp, &up->regs)) {
+ return -EFAULT;
+ }
+ kp->regs = (__force u32 *)compat_ptr(tmp);
+ return 0;
+}
+
+static int put_hantro_core_desc32(struct core_desc *kp, struct core_desc_32 __user *up)
+{
+ u32 tmp = (u32)((unsigned long)kp->regs);
+
+ if (!access_ok(VERIFY_WRITE, up, sizeof(struct core_desc_32)) ||
+ put_user(kp->id, &up->id) ||
+ put_user(kp->size, &up->size) ||
+ put_user(tmp, &up->regs)) {
+ return -EFAULT;
+ }
+ return 0;
+}
+static long hantrodec_ioctl32(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+#define HANTRO_IOCTL32(err, filp, cmd, arg) { \
+ mm_segment_t old_fs = get_fs(); \
+ set_fs(KERNEL_DS); \
+ err = hantrodec_ioctl(filp, cmd, arg); \
+ if (err) \
+ return err; \
+ set_fs(old_fs); \
+ }
+
+ union {
+ struct core_desc kcore;
+ unsigned long kux;
+ unsigned int kui;
+ } karg;
+ void __user *up = compat_ptr(arg);
+ long err = 0;
+
+ switch (_IOC_NR(cmd)) {
+ case _IOC_NR(HANTRODEC_IOCGHWOFFSET):
+ case _IOC_NR(HANTRODEC_IOC_MC_OFFSETS):
+ err = get_user(karg.kux, (s32 __user *)up);
+ if (err)
+ return err;
+ HANTRO_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+ err = put_user(((s32)karg.kux), (s32 __user *)up);
+ break;
+ case _IOC_NR(HANTRODEC_IOCGHWIOSIZE):
+ case _IOC_NR(HANTRODEC_IOC_MC_CORES):
+ case _IOC_NR(HANTRODEC_IOCG_CORE_WAIT):
+ case _IOC_NR(HANTRODEC_IOX_ASIC_ID):
+ err = get_user(karg.kui, (s32 __user *)up);
+ if (err)
+ return err;
+ HANTRO_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+ err = put_user(((s32)karg.kui), (s32 __user *)up);
+ break;
+ case _IOC_NR(HANTRODEC_IOCS_DEC_PUSH_REG):
+ case _IOC_NR(HANTRODEC_IOCS_PP_PUSH_REG):
+ case _IOC_NR(HANTRODEC_IOCX_DEC_WAIT):
+ case _IOC_NR(HANTRODEC_IOCX_PP_WAIT):
+ case _IOC_NR(HANTRODEC_IOCS_DEC_PULL_REG):
+ case _IOC_NR(HANTRODEC_IOCS_PP_PULL_REG):
+ err = get_hantro_core_desc32(&karg.kcore, up);
+ if (err)
+ return err;
+ HANTRO_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+ err = put_hantro_core_desc32(&karg.kcore, up);
+ break;
+ default:
+ err = hantrodec_ioctl(filp, cmd, (unsigned long)up);
+ break;
+ }
+
+ return err;
+}
+
+#endif //ifdef CONFIG_COMPAT
+
+/*--------------------------------------------------------------------------
+ *Function name : hantrodec_open
+ *Description : open method
+ *
+ *Return type : int
+ *---------------------------------------------------------------------------
+ */
+static int hantrodec_open(struct inode *inode, struct file *filp)
+{
+ PDEBUG("dev opened\n");
+ hantro_clk_enable(hantro_dev);
+ pm_runtime_get_sync(hantro_dev);
+ return 0;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : hantrodec_release
+ *Description : Release driver
+ *
+ *Return type : int
+ *----------------------------------------------------------------------------
+ */
+static int hantrodec_release(struct inode *inode, struct file *filp)
+{
+ int n;
+ hantrodec_t *dev = &hantrodec_data;
+
+ PDEBUG("closing ...\n");
+
+ for (n = 0; n < dev->cores; n++) {
+ if (dec_owner[n] == filp) {
+ PDEBUG("releasing dec Core %i lock\n", n);
+ ReleaseDecoder(dev, n);
+ }
+ }
+
+ for (n = 0; n < 1; n++) {
+ if (pp_owner[n] == filp) {
+ PDEBUG("releasing pp Core %i lock\n", n);
+ ReleasePostProcessor(dev, n);
+ }
+ }
+
+ pm_runtime_put_sync(hantro_dev);
+ hantro_clk_disable(hantro_dev);
+ PDEBUG("closed\n");
+ return 0;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : hantro_mmap
+ *Description : memory map interface for hantro file operation
+ *
+ *Return type : int
+ *---------------------------------------------------------------------------
+ */
+static int hantro_mmap(struct file *fp, struct vm_area_struct *vm)
+{
+ if (vm->vm_pgoff == (multicorebase[0] >> PAGE_SHIFT) || vm->vm_pgoff == (multicorebase[1] >> PAGE_SHIFT)) {
+ vm->vm_flags |= VM_IO;
+ vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);
+ PDEBUG("hantro mmap: size=0x%lX, page off=0x%lX\n", (vm->vm_end - vm->vm_start), vm->vm_pgoff);
+ return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end - vm->vm_start,
+ vm->vm_page_prot) ? -EAGAIN : 0;
+ } else {
+ pr_err("invalid map offset :0x%lX\n", vm->vm_pgoff);
+ return -EINVAL;
+ }
+}
+
+/* VFS methods */
+static const struct file_operations hantrodec_fops = {
+ .owner = THIS_MODULE,
+ .open = hantrodec_open,
+ .release = hantrodec_release,
+ .unlocked_ioctl = hantrodec_ioctl,
+ .fasync = NULL,
+ .mmap = hantro_mmap,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = hantrodec_ioctl32,
+#endif
+};
+
+/*---------------------------------------------------------------------------
+ *Function name : hantrodec_init
+ *Description : Initialize the driver
+ *
+ *Return type : int
+ *---------------------------------------------------------------------------
+ */
+int hantrodec_init(struct platform_device *pdev)
+{
+ int result;
+ int irq_0, irq_1;
+
+ dec_irq = 0;
+ pp_irq = 0;
+ pr_debug("hantrodec: Init multi Core[0] at 0x%16lx\n"
+ " Core[1] at 0x%16lx\n", multicorebase[0], multicorebase[1]);
+
+ hantrodec_data.cores = 0;
+ hantrodec_data.iosize[0] = DEC_IO_SIZE_0;
+ hantrodec_data.iosize[1] = DEC_IO_SIZE_1;
+
+ hantrodec_data.async_queue_dec = NULL;
+ hantrodec_data.async_queue_pp = NULL;
+
+ result = register_chrdev(hantrodec_major, "hantrodec", &hantrodec_fops);
+ if (result < 0) {
+ pr_err("hantrodec: unable to get major %d\n", hantrodec_major);
+ goto err;
+ } else if (result != 0) { /* this is for dynamic major */
+ hantrodec_major = result;
+ }
+
+ result = ReserveIO();
+ if (result < 0)
+ goto err;
+
+ memset(dec_owner, 0, sizeof(dec_owner));
+ memset(pp_owner, 0, sizeof(pp_owner));
+
+ sema_init(&dec_core_sem, hantrodec_data.cores-1);
+ sema_init(&pp_core_sem, 1);
+
+ /* read configuration fo all cores */
+ ReadCoreConfig(&hantrodec_data);
+
+ /* reset hardware */
+ ResetAsic(&hantrodec_data);
+
+ /* register irq for each core*/
+ irq_0 = platform_get_irq_byname(pdev, "irq_hantro_g1");
+ if (irq_0 > 0) {
+ hantrodec_data.irq[0] = irq_0;
+ result = request_irq(irq_0, hantrodec_isr, IRQF_SHARED,
+ "hantrodec", (void *) &hantrodec_data);
+
+ if (result != 0) {
+ if (result == -EINVAL)
+ pr_err("hantrodec: Bad irq number or handler\n");
+ else if (result == -EBUSY) {
+ pr_err("hantrodec: IRQ <%d> busy, change your config\n",
+ hantrodec_data.irq[0]);
+ }
+ ReleaseIO();
+ goto err;
+ }
+ } else {
+ pr_err("hantrodec: IRQ0 not in use!\n");
+ goto err;
+ }
+
+ irq_1 = platform_get_irq_byname(pdev, "irq_hantro_g2");
+ if (irq_1 > 0) {
+ hantrodec_data.irq[1] = irq_1;
+ result = request_irq(irq_1, hantrodec_isr, IRQF_SHARED,
+ "hantrodec", (void *) &hantrodec_data);
+
+ if (result != 0) {
+ if (result == -EINVAL)
+ pr_err("hantrodec: Bad irq number or handler\n");
+ else if (result == -EBUSY) {
+ pr_err("hantrodec: IRQ <%d> busy, change your config\n",
+ hantrodec_data.irq[1]);
+ }
+
+ ReleaseIO();
+ goto err;
+ }
+ } else {
+ pr_err("hantrodec: IRQ1 not in use!\n");
+ goto err;
+ }
+ pr_info("hantrodec: module inserted. Major = %d\n", hantrodec_major);
+
+ return 0;
+
+err:
+ pr_err("hantrodec: module not inserted\n");
+ unregister_chrdev(hantrodec_major, "hantrodec");
+ return result;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : hantrodec_cleanup
+ *Description : clean up
+ *
+ *Return type : int
+ *---------------------------------------------------------------------------
+ */
+void hantrodec_cleanup(void)
+{
+ hantrodec_t *dev = &hantrodec_data;
+ int n = 0;
+ /* reset hardware */
+ ResetAsic(dev);
+
+ /* free the IRQ */
+ for (n = 0; n < dev->cores; n++) {
+ if (dev->irq[n] != -1)
+ free_irq(dev->irq[n], (void *) dev);
+ }
+
+ ReleaseIO();
+
+ unregister_chrdev(hantrodec_major, "hantrodec");
+
+ PDEBUG("hantrodec: module removed\n");
+
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : CheckHwId
+ *Return type : int
+ *---------------------------------------------------------------------------
+ */
+static int CheckHwId(hantrodec_t *dev)
+{
+ long int hwid;
+ int i;
+ size_t num_hw = sizeof(DecHwId) / sizeof(*DecHwId);
+
+ int found = 0;
+
+ for (i = 0; i < dev->cores; i++) {
+ if (dev->hwregs[i] != NULL) {
+ hwid = readl(dev->hwregs[i]);
+ pr_debug("hantrodec: Core %d HW ID=0x%16lx\n", i, hwid);
+ hwid = (hwid >> 16) & 0xFFFF; /* product version only */
+
+ while (num_hw--) {
+ if (hwid == DecHwId[num_hw]) {
+ pr_debug("hantrodec: Supported HW found at 0x%16lx\n",
+ multicorebase[i]);
+ found++;
+ dev->hw_id[i] = hwid;
+ break;
+ }
+ }
+ if (!found) {
+ pr_err("hantrodec: Unknown HW found at 0x%16lx\n", multicorebase[i]);
+ return 0;
+ }
+ found = 0;
+ num_hw = sizeof(DecHwId) / sizeof(*DecHwId);
+ }
+ }
+
+ return 1;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : ReserveIO
+ *Description : IO reserve
+ *
+ *Return type : int
+ *---------------------------------------------------------------------------
+ */
+static int ReserveIO(void)
+{
+ int i;
+
+ for (i = 0; i < HXDEC_MAX_CORES; i++) {
+ if (multicorebase[i] != -1) {
+ if (!request_mem_region(multicorebase[i], hantrodec_data.iosize[i], "hantrodec0")) {
+ pr_err("hantrodec: failed to reserve HW regs\n");
+ return -EBUSY;
+ }
+
+ hantrodec_data.hwregs[i] = (volatile u8 *) ioremap_nocache(multicorebase[i],
+ hantrodec_data.iosize[i]);
+
+ if (hantrodec_data.hwregs[i] == NULL) {
+ pr_err("hantrodec: failed to ioremap HW regs\n");
+ ReleaseIO();
+ return -EBUSY;
+ }
+ hantrodec_data.cores++;
+ }
+ }
+
+ /* check for correct HW */
+ if (!CheckHwId(&hantrodec_data)) {
+ ReleaseIO();
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : releaseIO
+ *Description : release
+ *
+ *Return type : void
+ *---------------------------------------------------------------------------
+ */
+static void ReleaseIO(void)
+{
+ int i;
+
+ for (i = 0; i < hantrodec_data.cores; i++) {
+ if (hantrodec_data.hwregs[i])
+ iounmap((void *) hantrodec_data.hwregs[i]);
+ release_mem_region(multicorebase[i], hantrodec_data.iosize[i]);
+ }
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : hantrodec_isr
+ *Description : interrupt handler
+ *
+ *Return type : irqreturn_t
+ *---------------------------------------------------------------------------
+ */
+irqreturn_t hantrodec_isr(int irq, void *dev_id)
+{
+ unsigned long flags;
+ unsigned int handled = 0;
+ int i;
+ volatile u8 *hwregs;
+
+ hantrodec_t *dev = (hantrodec_t *) dev_id;
+ u32 irq_status_dec;
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ for (i = 0; i < dev->cores; i++) {
+ volatile u8 *hwregs = dev->hwregs[i];
+
+ /* interrupt status register read */
+ irq_status_dec = ioread32(hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+ if (irq_status_dec & HANTRODEC_DEC_IRQ) {
+ /* clear dec IRQ */
+ irq_status_dec &= (~HANTRODEC_DEC_IRQ);
+ iowrite32(irq_status_dec, hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+ PDEBUG("decoder IRQ received! Core %d\n", i);
+
+ atomic_inc(&irq_rx);
+
+ dec_irq |= (1 << i);
+
+ wake_up_interruptible_all(&dec_wait_queue);
+ handled++;
+ }
+ }
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ if (!handled)
+ pr_info("IRQ received, but not hantrodec's!\n");
+
+ (void)hwregs;
+ return IRQ_RETVAL(handled);
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : ResetAsic
+ *Description : reset asic
+ *
+ *Return type :
+ *---------------------------------------------------------------------------
+ */
+void ResetAsic(hantrodec_t *dev)
+{
+ int i, j;
+ u32 status;
+
+ for (j = 0; j < dev->cores; j++) {
+ status = ioread32(dev->hwregs[j] + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+ if (status & HANTRODEC_DEC_E) {
+ /* abort with IRQ disabled */
+ status = HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+ iowrite32(status, dev->hwregs[j] + HANTRODEC_IRQ_STAT_DEC_OFF);
+ }
+
+ if (IS_G1(dev->hw_id[j]))
+ /* reset PP */
+ iowrite32(0, dev->hwregs[j] + HANTRO_IRQ_STAT_PP_OFF);
+
+ for (i = 4; i < dev->iosize[j]; i += 4)
+ iowrite32(0, dev->hwregs[j] + i);
+ }
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : dump_regs
+ *Description : Dump registers
+ *
+ *Return type :
+ *---------------------------------------------------------------------------
+ */
+#ifdef HANTRODEC_DEBUG
+void dump_regs(hantrodec_t *dev)
+{
+ int i, c;
+
+ PDEBUG("Reg Dump Start\n");
+ for (c = 0; c < dev->cores; c++) {
+ for (i = 0; i < dev->iosize[c]; i += 4*4) {
+ PDEBUG("\toffset %04X: %08X %08X %08X %08X\n", i,
+ ioread32(dev->hwregs[c] + i),
+ ioread32(dev->hwregs[c] + i + 4),
+ ioread32(dev->hwregs[c] + i + 8),
+ ioread32(dev->hwregs[c] + i + 12));
+ }
+ }
+ PDEBUG("Reg Dump End\n");
+}
+#endif
+
+static int hantro_dev_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ struct device *temp_class;
+ struct resource *res;
+ unsigned long reg_base;
+
+ hantro_dev = &pdev->dev;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs_hantro");
+ if (!res) {
+ pr_err("hantro: unable to get vpu base addr\n");
+ return -ENODEV;
+ }
+ reg_base = res->start;
+ if ((ulong)reg_base != multicorebase[0]) {
+ pr_err("hantrodec: regbase(0x%lX) not equal to expected value(0x%lX)\n", reg_base, multicorebase[0]);
+ return -ENODEV;
+ }
+
+ hantro_clk_g1 = clk_get(&pdev->dev, "clk_hantro_g1");
+ hantro_clk_g2 = clk_get(&pdev->dev, "clk_hantro_g2");
+ hantro_clk_bus = clk_get(&pdev->dev, "clk_hantro_bus");
+ if (IS_ERR(hantro_clk_g1) || IS_ERR(hantro_clk_g2) || IS_ERR(hantro_clk_bus)) {
+ pr_err("hantro: get clock failed\n");
+ return -ENODEV;
+ }
+ pr_debug("hantro: g1, g2, bus clock: 0x%lX, 0x%lX, 0x%lX\n", clk_get_rate(hantro_clk_g1),
+ clk_get_rate(hantro_clk_g2), clk_get_rate(hantro_clk_bus));
+
+ hantro_regulator = regulator_get(&pdev->dev, "regulator");
+ if (IS_ERR(hantro_regulator)) {
+ pr_err("hantro: get regulator failed\n");
+ return -ENODEV;
+ }
+ hantro_update_voltage(&pdev->dev);
+
+ hantro_clk_enable(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+ hantro_ctrlblk_reset(&pdev->dev);
+
+ err = hantrodec_init(pdev);
+ if (0 != err) {
+ pr_err("hantro: hantrodec_init failed\n");
+ goto error;
+ }
+
+ hantro_class = class_create(THIS_MODULE, "mxc_hantro");
+ if (IS_ERR(hantro_class)) {
+ err = PTR_ERR(hantro_class);
+ goto error;
+ }
+ temp_class = device_create(hantro_class, NULL, MKDEV(hantrodec_major, 0), NULL, DEVICE_NAME);
+ if (IS_ERR(temp_class)) {
+ err = PTR_ERR(temp_class);
+ goto err_out_class;
+ }
+
+#ifdef CONFIG_DEVICE_THERMAL
+ HANTRO_REG_THERMAL_NOTIFIER(&hantro_thermal_hot_notifier);
+ thermal_event = 0;
+ thermal_cur = 0;
+ hantro_dynamic_clock = 0;
+#endif
+ timeout = 0;
+ goto out;
+
+err_out_class:
+ device_destroy(hantro_class, MKDEV(hantrodec_major, 0));
+ class_destroy(hantro_class);
+error:
+ pr_err("hantro probe failed\n");
+out:
+ pm_runtime_put_sync(&pdev->dev);
+ hantro_clk_disable(&pdev->dev);
+ return err;
+}
+
+static int hantro_dev_remove(struct platform_device *pdev)
+{
+ hantro_clk_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+ if (hantrodec_major > 0) {
+ device_destroy(hantro_class, MKDEV(hantrodec_major, 0));
+ class_destroy(hantro_class);
+ hantrodec_cleanup();
+ hantrodec_major = 0;
+ }
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ hantro_clk_disable(&pdev->dev);
+
+#ifdef CONFIG_DEVICE_THERMAL
+ HANTRO_UNREG_THERMAL_NOTIFIER(&hantro_thermal_hot_notifier);
+#endif
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int hantro_suspend(struct device *dev)
+{
+ pm_runtime_put_sync_suspend(dev); //power off
+ return 0;
+}
+static int hantro_resume(struct device *dev)
+{
+ pm_runtime_get_sync(dev); //power on
+ hantro_ctrlblk_reset(dev);
+ return 0;
+}
+static int hantro_runtime_suspend(struct device *dev)
+{
+ release_bus_freq(BUS_FREQ_HIGH);
+ return 0;
+}
+
+static int hantro_runtime_resume(struct device *dev)
+{
+ request_bus_freq(BUS_FREQ_HIGH);
+ hantro_ctrlblk_reset(dev);
+ return 0;
+}
+
+static const struct dev_pm_ops hantro_pm_ops = {
+ SET_RUNTIME_PM_OPS(hantro_runtime_suspend, hantro_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(hantro_suspend, hantro_resume)
+};
+#endif //CONFIG_PM
+
+static const struct of_device_id hantro_of_match[] = {
+ { .compatible = "nxp,imx8mq-hantro", },
+ {/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, vpu_of_match);
+
+
+static struct platform_driver mxchantro_driver = {
+ .driver = {
+ .name = "mxc_hantro",
+ .of_match_table = hantro_of_match,
+#ifdef CONFIG_PM
+ .pm = &hantro_pm_ops,
+#endif
+ },
+ .probe = hantro_dev_probe,
+ .remove = hantro_dev_remove,
+};
+
+static int __init hantro_init(void)
+{
+ int ret = platform_driver_register(&mxchantro_driver);
+
+ return ret;
+}
+
+static void __exit hantro_exit(void)
+{
+ if (!IS_ERR(hantro_clk_g1))
+ clk_put(hantro_clk_g1);
+ if (!IS_ERR(hantro_clk_g2))
+ clk_put(hantro_clk_g2);
+ if (!IS_ERR(hantro_clk_bus))
+ clk_put(hantro_clk_bus);
+ if (!IS_ERR(hantro_regulator))
+ regulator_put(hantro_regulator);
+ platform_driver_unregister(&mxchantro_driver);
+}
+
+module_init(hantro_init);
+module_exit(hantro_exit);
+
+/* module description */
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Google Finland Oy");
+MODULE_DESCRIPTION("Driver module for Hantro Decoder/Post-Processor");
+
diff --git a/drivers/mxc/hantro_845/Kconfig b/drivers/mxc/hantro_845/Kconfig
new file mode 100755
index 000000000000..6b59c33f91c6
--- /dev/null
+++ b/drivers/mxc/hantro_845/Kconfig
@@ -0,0 +1,14 @@
+#
+# Codec configuration
+#
+
+menu "MXC HANTRO(Video Processing Unit) 845 support"
+ depends on ARCH_FSL_IMX8MQ
+
+config MXC_HANTRO_845
+ tristate "Support for MXC HANTRO(Video Processing Unit) 845"
+ default y
+ ---help---
+ VPU codec device.
+
+endmenu
diff --git a/drivers/mxc/hantro_845/Makefile b/drivers/mxc/hantro_845/Makefile
new file mode 100755
index 000000000000..575756282a8b
--- /dev/null
+++ b/drivers/mxc/hantro_845/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the VPU drivers.
+#
+
+#ccflags-y += -I$(PWD)
+
+obj-$(CONFIG_MXC_HANTRO_845) += hantrodec_845s.o
+
diff --git a/drivers/mxc/hantro_845/dwl_defs.h b/drivers/mxc/hantro_845/dwl_defs.h
new file mode 100644
index 000000000000..8976dcf156b6
--- /dev/null
+++ b/drivers/mxc/hantro_845/dwl_defs.h
@@ -0,0 +1,94 @@
+/*****************************************************************************
+ * The GPL License (GPL)
+ *
+ * Copyright (c) 2015-2017, VeriSilicon Inc.
+ * Copyright (c) 2011-2014, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *****************************************************************************/
+
+#ifndef SOFTWARE_LINUX_DWL_DWL_DEFS_H_
+#define SOFTWARE_LINUX_DWL_DWL_DEFS_H_
+
+#define DWL_MPEG2_E 31 /* 1 bit */
+#define DWL_VC1_E 29 /* 2 bits */
+#define DWL_JPEG_E 28 /* 1 bit */
+#define DWL_MPEG4_E 26 /* 2 bits */
+#define DWL_H264_E 24 /* 2 bits */
+#define DWL_VP6_E 23 /* 1 bit */
+#define DWL_RV_E 26 /* 2 bits */
+#define DWL_VP8_E 23 /* 1 bit */
+#define DWL_VP7_E 24 /* 1 bit */
+#define DWL_WEBP_E 19 /* 1 bit */
+#define DWL_AVS_E 22 /* 1 bit */
+#if 0
+#define DWL_PP_E 16 /* 1 bit */
+#endif
+#define DWL_PP_E 31 /* 1 bit */
+#define DWL_HEVC_E 5 /* 2 bits */
+#define DWL_VP9_E 3 /* 2 bits */
+
+#define DWL_HEVC_ENA 0 /* 1 bits */
+#define DWL_VP9_ENA 1 /* 1 bits */
+#define DWL_RFC_E 2 /* 1 bits */
+#define DWL_DS_E 3 /* 1 bits */
+#define DWL_HEVC_VER 8 /* 4 bits */
+#define DWL_VP9_PROFILE 12 /* 3 bits */
+#define DWL_RING_E 16 /* 1 bits */
+
+#define HANTRODEC_IRQ_STAT_DEC 1
+#define HANTRODEC_IRQ_STAT_DEC_OFF (HANTRODEC_IRQ_STAT_DEC * 4)
+
+#define HANTRODECPP_SYNTH_CFG 60
+#define HANTRODECPP_SYNTH_CFG_OFF (HANTRODECPP_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG 50
+#define HANTRODEC_SYNTH_CFG_OFF (HANTRODEC_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG_2 54
+#define HANTRODEC_SYNTH_CFG_2_OFF (HANTRODEC_SYNTH_CFG_2 * 4)
+#define HANTRODEC_SYNTH_CFG_3 56
+#define HANTRODEC_SYNTH_CFG_3_OFF (HANTRODEC_SYNTH_CFG_3 * 4)
+#define HANTRODEC_CFG_STAT 23
+#define HANTRODEC_CFG_STAT_OFF (HANTRODEC_CFG_STAT * 4)
+
+
+#define HANTRODEC_DEC_E 0x01
+#define HANTRODEC_PP_E 0x01
+#define HANTRODEC_DEC_ABORT 0x20
+#define HANTRODEC_DEC_IRQ_DISABLE 0x10
+#define HANTRODEC_DEC_IRQ 0x100
+
+/* Legacy from G1 */
+#define HANTRO_IRQ_STAT_DEC 1
+#define HANTRO_IRQ_STAT_DEC_OFF (HANTRO_IRQ_STAT_DEC * 4)
+#define HANTRO_IRQ_STAT_PP 60
+#define HANTRO_IRQ_STAT_PP_OFF (HANTRO_IRQ_STAT_PP * 4)
+
+#define HANTROPP_SYNTH_CFG 100
+#define HANTROPP_SYNTH_CFG_OFF (HANTROPP_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG 50
+#define HANTRODEC_SYNTH_CFG_OFF (HANTRODEC_SYNTH_CFG * 4)
+#define HANTRODEC_SYNTH_CFG_2 54
+#define HANTRODEC_SYNTH_CFG_2_OFF (HANTRODEC_SYNTH_CFG_2 * 4)
+
+#define HANTRO_DEC_E 0x01
+#define HANTRO_PP_E 0x01
+#define HANTRO_DEC_ABORT 0x20
+#define HANTRO_DEC_IRQ_DISABLE 0x10
+#define HANTRO_PP_IRQ_DISABLE 0x10
+#define HANTRO_DEC_IRQ 0x100
+#define HANTRO_PP_IRQ 0x100
+
+#endif /* SOFTWARE_LINUX_DWL_DWL_DEFS_H_ */
diff --git a/drivers/mxc/hantro_845/hantrodec_845s.c b/drivers/mxc/hantro_845/hantrodec_845s.c
new file mode 100755
index 000000000000..f6be60199106
--- /dev/null
+++ b/drivers/mxc/hantro_845/hantrodec_845s.c
@@ -0,0 +1,2018 @@
+/*****************************************************************************
+ * The GPL License (GPL)
+ *
+ * Copyright (c) 2015-2018, VeriSilicon Inc.
+ * Copyright (c) 2011-2014, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *****************************************************************************/
+#include <linux/hantrodec.h>
+#include "dwl_defs.h"
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/busfreq-imx.h>
+
+#include <linux/delay.h>
+
+//#define CONFIG_DEVICE_THERMAL_HANTRO
+#ifdef CONFIG_DEVICE_THERMAL_HANTRO
+#include <linux/device_cooling.h>
+#define HANTRO_REG_THERMAL_NOTIFIER(a) register_devfreq_cooling_notifier(a)
+#define HANTRO_UNREG_THERMAL_NOTIFIER(a) unregister_devfreq_cooling_notifier(a)
+static DEFINE_SPINLOCK(thermal_lock);
+/*1:hot, 0: not hot*/
+static int thermal_event;
+static int hantro_clock_ratio = 2;
+static int hantro_dynamic_clock;
+module_param(hantro_clock_ratio, int, 0644);
+module_param(hantro_dynamic_clock, int, 0644);
+MODULE_PARM_DESC(hantro_clock_ratio, "clock ratio 1/N");
+MODULE_PARM_DESC(hantro_dynamic_clock, "enable or disable dynamic clock rate");
+#endif
+
+/*hantro G1 regs config including dec and pp*/
+#define HANTRO_DEC_ORG_REGS 60
+#define HANTRO_PP_ORG_REGS 41
+
+#define HANTRO_DEC_EXT_REGS 27
+#define HANTRO_PP_EXT_REGS 9
+
+#define HANTRO_G1_DEC_TOTAL_REGS (HANTRO_DEC_ORG_REGS + HANTRO_DEC_EXT_REGS)
+#define HANTRO_PP_TOTAL_REGS (HANTRO_PP_ORG_REGS + HANTRO_PP_EXT_REGS)
+#define HANTRO_G1_TOTAL_REGS 155 /*G1 total regs*/
+
+#define HANTRO_DEC_ORG_FIRST_REG 0
+#define HANTRO_DEC_ORG_LAST_REG 59
+#define HANTRO_DEC_EXT_FIRST_REG 119
+#define HANTRO_DEC_EXT_LAST_REG 145
+
+#define HANTRO_PP_ORG_FIRST_REG 60
+#define HANTRO_PP_ORG_LAST_REG 100
+#define HANTRO_PP_EXT_FIRST_REG 146
+#define HANTRO_PP_EXT_LAST_REG 154
+
+/*hantro G2 reg config*/
+#define HANTRO_G2_DEC_REGS 265 /*G2 total regs*/
+
+#define HANTRO_G2_DEC_FIRST_REG 0
+#define HANTRO_G2_DEC_LAST_REG (HANTRO_G2_DEC_REGS - 1)
+
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#define DEC_IO_SIZE_MAX (MAX(HANTRO_G2_DEC_REGS, HANTRO_G1_TOTAL_REGS) * 4)
+
+/********************************************************************
+ * PORTING SEGMENT
+ * NOTES: customer should modify these configuration if do porting to own platform.
+ * Please guarantee the base_addr, io_size,dec_irq belong to same core.
+ ********************************************************************/
+
+#define HXDEC_MAX_CORES 2
+
+/* Logic module base address */
+#define SOCLE_LOGIC_0_BASE 0x38300000
+#define SOCLE_LOGIC_1_BASE 0x38310000
+#define BLK_CTL_BASE 0x38330000 //0x38320000
+
+#define VEXPRESS_LOGIC_0_BASE 0xFC010000
+#define VEXPRESS_LOGIC_1_BASE 0xFC020000
+
+#define DEC_IO_SIZE_0 ((HANTRO_G2_DEC_REGS) * 4) /* bytes */
+#define DEC_IO_SIZE_1 ((HANTRO_G2_DEC_REGS) * 4) /* bytes */
+
+#define HANTRO_DEC_DEF_CLK (600000000)
+#define HANTRO_BUS_DEF_CLK (800000000)
+/***********************************************************************/
+
+#define IS_G1(hw_id) ((hw_id == 0x6731) ? 1:0)
+
+static const int DecHwId[] = {
+ 0x8190, /* Legacy HW */
+ 0x8170,
+ 0x9170,
+ 0x9190,
+ 0x6731, /* G1 */
+ 0x6732 /* G2 */
+};
+
+static ulong multicorebase[HXDEC_MAX_CORES] = {
+ SOCLE_LOGIC_0_BASE,
+ SOCLE_LOGIC_1_BASE
+};
+
+
+static struct class *hantro_class;
+#define DEVICE_NAME "mxc_hantro"
+
+//static struct device *hantro_dev[HXDEC_MAX_CORES];
+
+typedef struct {
+ struct clk *dec;
+ struct clk *bus;
+} hantrodec_clk;
+
+static int hantro_dbg = -1;
+module_param(hantro_dbg, int, 0644);
+MODULE_PARM_DESC(hantro_dbg, "Debug level (0-1)");
+#undef PDEBUG
+#define PDEBUG(fmt, arg...) \
+ do { \
+ if (hantro_dbg > 0) { \
+ dev_info(hantrodec_data[0].dev, fmt, ## arg); \
+ } \
+ } while (0)
+
+
+static int hantrodec_major;
+static int cores = 2;
+/* here's all the must remember stuff */
+typedef struct {
+ //char *buffer;
+ unsigned int iosize;
+ volatile u8 *hwregs;
+ int irq;
+ int hw_id;
+ int core_id;
+ //int cores;
+ //struct fasync_struct *async_queue_dec;
+ //struct fasync_struct *async_queue_pp;
+ hantrodec_clk clk;
+ u32 dec_regs[DEC_IO_SIZE_MAX/4];
+ struct semaphore dec_core_sem;
+ struct semaphore pp_core_sem;
+ struct file *dec_owner;
+ struct file *pp_owner;
+ u32 cfg;
+ u32 timeout;
+ atomic_t irq_rx;
+ atomic_t irq_tx;
+ struct device *dev;
+ struct mutex dev_mutex;
+ int thermal_cur;
+} hantrodec_t;
+
+static hantrodec_t hantrodec_data[HXDEC_MAX_CORES]; /* dynamic allocation? */
+
+typedef struct {
+ char inst_id;
+ char core_id; //1:g1; 2:g2; 3:unknow
+} hantrodec_instance;
+static unsigned long instance_mask;
+#define MAX_HANTRODEC_INSTANCE 32
+static hantrodec_instance hantrodec_ctx[MAX_HANTRODEC_INSTANCE];
+
+static int ReserveIO(int);
+static void ReleaseIO(int);
+
+static void ResetAsic(hantrodec_t *dev);
+
+#ifdef HANTRODEC_DEBUG
+static void dump_regs(hantrodec_t *dev);
+#endif
+
+/* IRQ handler */
+static irqreturn_t hantrodec_isr(int irq, void *dev_id);
+
+static int dec_irq;
+static int pp_irq;
+
+
+/* spinlock_t owner_lock = SPIN_LOCK_UNLOCKED; */
+static DEFINE_SPINLOCK(owner_lock);
+
+static DECLARE_WAIT_QUEUE_HEAD(dec_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD(pp_wait_queue);
+
+static DECLARE_WAIT_QUEUE_HEAD(hw_queue);
+
+#define DWL_CLIENT_TYPE_H264_DEC 1U
+#define DWL_CLIENT_TYPE_MPEG4_DEC 2U
+#define DWL_CLIENT_TYPE_JPEG_DEC 3U
+#define DWL_CLIENT_TYPE_PP 4U
+#define DWL_CLIENT_TYPE_VC1_DEC 5U
+#define DWL_CLIENT_TYPE_MPEG2_DEC 6U
+#define DWL_CLIENT_TYPE_VP6_DEC 7U
+#define DWL_CLIENT_TYPE_AVS_DEC 8U
+#define DWL_CLIENT_TYPE_RV_DEC 9U
+#define DWL_CLIENT_TYPE_VP8_DEC 10U
+#define DWL_CLIENT_TYPE_VP9_DEC 11U
+#define DWL_CLIENT_TYPE_HEVC_DEC 12U
+
+static int hantro_device_id(struct device *dev)
+{
+ int id;
+
+ if (strcmp("vpu_g1", dev->of_node->name) == 0) {
+ id = 0;
+ } else if (strcmp("vpu_g2", dev->of_node->name) == 0) {
+ id = 1;
+ } else {
+ return id = -1;
+ }
+ return id;
+}
+static int hantro_clk_enable(hantrodec_clk *clk)
+{
+ clk_prepare(clk->dec);
+ clk_enable(clk->dec);
+ clk_prepare(clk->bus);
+ clk_enable(clk->bus);
+ return 0;
+}
+
+static int hantro_clk_disable(hantrodec_clk *clk)
+{
+ clk_disable(clk->dec);
+ clk_unprepare(clk->dec);
+ clk_disable(clk->bus);
+ clk_unprepare(clk->bus);
+ return 0;
+}
+
+static int hantro_ctrlblk_reset(hantrodec_t *dev)
+{
+ volatile u8 *iobase;
+ u32 val;
+
+ //config G1/G2
+ hantro_clk_enable(&dev->clk);
+ iobase = (volatile u8 *)ioremap_nocache(BLK_CTL_BASE, 0x10000);
+ if (dev->core_id == 0) {
+ val = ioread32(iobase);
+ val &= (~0x2);
+ iowrite32(val, iobase); //assert G1 block soft reset control
+ udelay(2);
+ val = ioread32(iobase);
+ val |= 0x2;
+ iowrite32(val, iobase); //desert G1 block soft reset control
+
+ val = ioread32(iobase+4);
+ val |= 0x2;
+ iowrite32(val, iobase+4); //VPUMIX G1 block clock enable control
+ iowrite32(0xFFFFFFFF, iobase + 0x8); // all G1 fuse dec enable
+ iowrite32(0xFFFFFFFF, iobase + 0xC); // all G1 fuse pp enable
+ } else {
+ val = ioread32(iobase);
+ val &= (~0x1);
+ iowrite32(val, iobase); //assert G2 block soft reset control
+ udelay(2);
+ val = ioread32(iobase);
+ val |= 0x1;
+ iowrite32(val, iobase); //desert G2 block soft reset control
+
+ val = ioread32(iobase+4);
+ val |= 0x1;
+ iowrite32(val, iobase+4); //VPUMIX G2 block clock enable control
+ iowrite32(0xFFFFFFFF, iobase + 0x10); // all G2 fuse dec enable
+ }
+ iounmap(iobase);
+ hantro_clk_disable(&dev->clk);
+ return 0;
+}
+
+static int hantro_power_on_disirq(hantrodec_t *hantrodev)
+{
+ //spin_lock_irq(&owner_lock);
+ mutex_lock(&hantrodev->dev_mutex);
+ disable_irq(hantrodev->irq);
+ pm_runtime_get_sync(hantrodev->dev);
+ enable_irq(hantrodev->irq);
+ mutex_unlock(&hantrodev->dev_mutex);
+ //spin_unlock_irq(&owner_lock);
+ return 0;
+}
+
+static int hantro_new_instance(void)
+{
+ int idx;
+
+ spin_lock(&owner_lock);
+ if (instance_mask == ((1UL << MAX_HANTRODEC_INSTANCE) - 1)) {
+ spin_unlock(&owner_lock);
+ return -1;
+ }
+ idx = ffz(instance_mask);
+ set_bit(idx, &instance_mask);
+ spin_unlock(&owner_lock);
+ return idx;
+}
+
+static int hantro_free_instance(int idx)
+{
+ spin_lock(&owner_lock);
+ clear_bit(idx, &instance_mask);
+ spin_unlock(&owner_lock);
+
+ return 0;
+}
+
+#ifdef CONFIG_DEVICE_THERMAL_HANTRO
+static int hantro_thermal_check(struct device *dev)
+{
+ hantrodec_t *hantrodev = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&thermal_lock, flags);
+ if (thermal_event == hantrodev->thermal_cur) {
+ /*nothing to do and return directly*/
+ spin_unlock_irqrestore(&thermal_lock, flags);
+ return 0;
+ }
+ hantrodev->thermal_cur = thermal_event;
+ spin_unlock_irqrestore(&thermal_lock, flags);
+
+ if (hantrodev->thermal_cur) {
+ int ratio = hantro_clock_ratio;
+
+ pr_debug("hantro[%d]: too hot, need to decrease clock, ratio: 1/%d\n", hantrodev->core_id, ratio);
+ /*clock disable/enable are not required for vpu clock rate operation*/
+ clk_set_rate(hantrodev->clk.dec, HANTRO_DEC_DEF_CLK/ratio);
+ clk_set_rate(hantrodev->clk.bus, HANTRO_BUS_DEF_CLK/ratio);
+ } else {
+ pr_debug("hantro[%d]: not hot again, will restore default clock\n", hantrodev->core_id);
+ clk_set_rate(hantrodev->clk.dec, HANTRO_DEC_DEF_CLK);
+ clk_set_rate(hantrodev->clk.bus, HANTRO_BUS_DEF_CLK);
+ }
+ pr_info("hantro[%d]: event(%d), dec, bus clock: %ld, %ld\n", hantrodev->core_id, hantrodev->thermal_cur,
+ clk_get_rate(hantrodev->clk.dec), clk_get_rate(hantrodev->clk.bus));
+ return 0;
+}
+
+static int hantro_thermal_hot_notify(struct notifier_block *nb, unsigned long event, void *dummy)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&thermal_lock, flags);
+ thermal_event = event; /*event: 1: hot, 0: cool*/
+ spin_unlock_irqrestore(&thermal_lock, flags);
+ pr_info("hantro receive hot notification event: %ld\n", event);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block hantro_thermal_hot_notifier = {
+ .notifier_call = hantro_thermal_hot_notify,
+};
+#endif //CONFIG_DEVICE_THERMAL_HANTRO
+
+static void ReadCoreConfig(hantrodec_t *dev)
+{
+ int c = dev->core_id;
+ u32 reg, tmp, mask;
+
+ memset(&dev->cfg, 0, sizeof(dev->cfg));
+
+ //for (c = 0; c < dev->cores; c++) {
+ /* Decoder configuration */
+ if (IS_G1(dev->hw_id)) {
+ reg = ioread32(dev->hwregs + HANTRODEC_SYNTH_CFG * 4);
+
+ tmp = (reg >> DWL_H264_E) & 0x3U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has H264\n", c);
+ dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_H264_DEC : 0;
+
+ tmp = (reg >> DWL_JPEG_E) & 0x01U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has JPEG\n", c);
+ dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_JPEG_DEC : 0;
+
+ tmp = (reg >> DWL_MPEG4_E) & 0x3U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has MPEG4\n", c);
+ dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG4_DEC : 0;
+
+ tmp = (reg >> DWL_VC1_E) & 0x3U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has VC1\n", c);
+ dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_VC1_DEC : 0;
+
+ tmp = (reg >> DWL_MPEG2_E) & 0x01U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has MPEG2\n", c);
+ dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_MPEG2_DEC : 0;
+
+ tmp = (reg >> DWL_VP6_E) & 0x01U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has VP6\n", c);
+ dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_VP6_DEC : 0;
+
+ reg = ioread32(dev->hwregs + HANTRODEC_SYNTH_CFG_2 * 4);
+
+ /* VP7 and WEBP is part of VP8 */
+ mask = (1 << DWL_VP8_E) | (1 << DWL_VP7_E) | (1 << DWL_WEBP_E);
+ tmp = (reg & mask);
+ if (tmp & (1 << DWL_VP8_E))
+ pr_debug("hantrodec: Core[%d] has VP8\n", c);
+ if (tmp & (1 << DWL_VP7_E))
+ pr_debug("hantrodec: Core[%d] has VP7\n", c);
+ if (tmp & (1 << DWL_WEBP_E))
+ pr_debug("hantrodec: Core[%d] has WebP\n", c);
+ dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_VP8_DEC : 0;
+
+ tmp = (reg >> DWL_AVS_E) & 0x01U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has AVS\n", c);
+ dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_AVS_DEC : 0;
+
+ tmp = (reg >> DWL_RV_E) & 0x03U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has RV\n", c);
+ dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_RV_DEC : 0;
+
+ /* Post-processor configuration */
+ reg = ioread32(dev->hwregs + HANTROPP_SYNTH_CFG * 4);
+ } else {
+ reg = ioread32(dev->hwregs + HANTRODEC_SYNTH_CFG_2 * 4);
+
+ tmp = (reg >> DWL_HEVC_E) & 0x3U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has HEVC\n", c);
+ dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_HEVC_DEC : 0;
+
+ tmp = (reg >> DWL_VP9_E) & 0x03U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has VP9\n", c);
+ dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_VP9_DEC : 0;
+ }
+
+ /* Post-processor configuration */
+ reg = ioread32(dev->hwregs + HANTRODECPP_SYNTH_CFG * 4);
+
+ tmp = (reg >> DWL_PP_E) & 0x01U;
+ if (tmp)
+ pr_debug("hantrodec: Core[%d] has PP\n", c);
+ dev->cfg |= tmp ? 1 << DWL_CLIENT_TYPE_PP : 0;
+ //}
+}
+
+static int CoreHasFormat(const u32 cfg, u32 format)
+{
+ return (cfg & (1 << format)) ? 1 : 0;
+}
+
+static int GetDecCore(hantrodec_t *dev, struct file *filp)
+{
+ int success = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&owner_lock, flags);
+ if (dev->dec_owner == NULL) {
+ dev->dec_owner = filp;
+ success = 1;
+ }
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ return success;
+}
+
+static int GetDecCoreAny(long *Core, hantrodec_t *dev, struct file *filp,
+ unsigned long format) {
+ int success = 0;
+ //long c;
+
+ *Core = -1;
+
+ //for (c = 0; c < dev->cores; c++) {
+ /* a free Core that has format */
+ if (CoreHasFormat(dev->cfg, format) && GetDecCore(dev, filp)) {
+ success = 1;
+ *Core = dev->core_id;
+ //break;
+ }
+ //}
+
+ return success;
+}
+
+static int GetDecCoreID(unsigned long format)
+{
+ long c;
+
+ int core_id = -1;
+
+ for (c = 0; c < cores; c++) {
+ /* a Core that has format */
+ if (CoreHasFormat(hantrodec_data[c].cfg, format)) {
+ core_id = c;
+ break;
+ }
+ }
+ PDEBUG("GetDecCoreID=%d\n", core_id);
+ return core_id;
+}
+#if 0
+static int hantrodec_choose_core(int is_g1)
+{
+ volatile unsigned char *reg = NULL;
+ unsigned int blk_base = BLK_CTL_BASE;
+
+ PDEBUG("hantrodec_choose_core\n");
+ if (!request_mem_region(blk_base, 0x1000, "blk_ctl")) {
+ pr_err("blk_ctl: failed to reserve HW regs\n");
+ return -EBUSY;
+ }
+
+ reg = (volatile u8 *) ioremap_nocache(blk_base, 0x1000);
+
+ if (reg == NULL) {
+ pr_err("blk_ctl: failed to ioremap HW regs\n");
+ if (reg)
+ iounmap((void *)reg);
+ release_mem_region(blk_base, 0x1000);
+ return -EBUSY;
+ }
+
+ // G1 use, set to 1; G2 use, set to 0, choose the one you are using
+ if (is_g1)
+ iowrite32(0x1, reg + 0x14); // VPUMIX only use G1
+ else
+ iowrite32(0x0, reg + 0x14); // VPUMIX only use G2
+
+ if (reg)
+ iounmap((void *)reg);
+ release_mem_region(blk_base, 0x1000);
+ PDEBUG("hantrodec_choose_core OK!\n");
+ return 0;
+}
+#endif
+
+static long ReserveDecoder(hantrodec_t *dev, struct file *filp, unsigned long format)
+{
+ long Core = -1;
+
+ /* reserve a Core */
+ if (down_interruptible(&dev->dec_core_sem))
+ return -ERESTARTSYS;
+
+#if 1
+ if (GetDecCoreAny(&Core, dev, filp, format) == 0) {
+ pr_err("Core %d is already been reserved !\n", dev->core_id);
+ return -1;
+ }
+#else
+ /* lock a Core that has specific format*/
+ if (wait_event_interruptible(hw_queue, GetDecCoreAny(&Core, dev, filp, format) != 0))
+ return -ERESTARTSYS;
+#endif
+#if 0
+ if (IS_G1(dev->hw_id)) {
+ if (0 == hantrodec_choose_core(1))
+ PDEBUG("G1 is reserved\n");
+ else
+ return -1;
+ } else {
+ if (0 == hantrodec_choose_core(0))
+ PDEBUG("G2 is reserved\n");
+ else
+ return -1;
+ }
+#endif
+#ifdef CONFIG_DEVICE_THERMAL_HANTRO
+ if (hantro_dynamic_clock)
+ hantro_thermal_check(dev->dev);
+#endif
+
+ return Core;
+}
+
+static void ReleaseDecoder(hantrodec_t *dev)
+{
+ u32 status;
+ unsigned long flags;
+
+ status = ioread32(dev->hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+ /* make sure HW is disabled */
+ if (status & HANTRODEC_DEC_E) {
+ pr_info("hantrodec: DEC[%d] still enabled -> reset\n", dev->core_id);
+
+ /* abort decoder */
+ status |= HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+ iowrite32(status, dev->hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+ }
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ dev->dec_owner = NULL;
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ up(&dev->dec_core_sem);
+
+ //wake_up_interruptible_all(&hw_queue);
+
+}
+
+static long ReservePostProcessor(hantrodec_t *dev, struct file *filp)
+{
+ unsigned long flags;
+
+ long Core = 0;
+
+ /* single Core PP only */
+ if (down_interruptible(&dev->pp_core_sem))
+ return -ERESTARTSYS;
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ dev->pp_owner = filp;
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ return Core;
+}
+
+static void ReleasePostProcessor(hantrodec_t *dev)
+{
+ unsigned long flags;
+
+ u32 status = ioread32(dev->hwregs + HANTRO_IRQ_STAT_PP_OFF);
+
+ /* make sure HW is disabled */
+ if (status & HANTRO_PP_E) {
+ pr_info("hantrodec: PP[%d] still enabled -> reset\n", dev->core_id);
+
+ /* disable IRQ */
+ status |= HANTRO_PP_IRQ_DISABLE;
+
+ /* disable postprocessor */
+ status &= (~HANTRO_PP_E);
+ iowrite32(0x10, dev->hwregs + HANTRO_IRQ_STAT_PP_OFF);
+ }
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ dev->pp_owner = NULL;
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ up(&dev->pp_core_sem);
+}
+
+#if 0
+static long ReserveDecPp(hantrodec_t *dev, struct file *filp, unsigned long format)
+{
+ /* reserve Core 0, DEC+PP for pipeline */
+ unsigned long flags;
+
+ long Core = 0;
+
+ /* check that Core has the requested dec format */
+ if (!CoreHasFormat(dev->cfg, format))
+ return -EFAULT;
+
+ /* check that Core has PP */
+ if (!CoreHasFormat(dev->cfg, DWL_CLIENT_TYPE_PP))
+ return -EFAULT;
+
+ /* reserve a Core */
+ if (down_interruptible(&dev->dec_core_sem))
+ return -ERESTARTSYS;
+
+ /* wait until the Core is available */
+ if (wait_event_interruptible(hw_queue, GetDecCore(dev, filp) != 0)) {
+ up(&dev->dec_core_sem);
+ return -ERESTARTSYS;
+ }
+
+ if (down_interruptible(&dev->pp_core_sem)) {
+ ReleaseDecoder(dev);
+ return -ERESTARTSYS;
+ }
+
+ spin_lock_irqsave(&owner_lock, flags);
+ dev->pp_owner = filp;
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ return Core;
+}
+#endif
+static long DecFlushRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+ long ret = 0, i;
+
+ //u32 id = Core->id;
+
+ if (IS_G1(dev->hw_id)) {
+ /* copy original dec regs to kernal space*/
+ ret = copy_from_user(dev->dec_regs, Core->regs, HANTRO_DEC_ORG_REGS*4);
+ if (ret) {
+ pr_err("copy_from_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+#ifdef USE_64BIT_ENV
+ /* copy extended dec regs to kernal space*/
+ ret = copy_from_user(dev->dec_regs + HANTRO_DEC_EXT_FIRST_REG,
+ Core->regs + HANTRO_DEC_EXT_FIRST_REG, HANTRO_DEC_EXT_REGS * 4);
+#endif
+ if (ret) {
+ pr_err("copy_from_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+
+ /* write dec regs but the status reg[1] to hardware */
+ /* both original and extended regs need to be written */
+ for (i = 2; i <= HANTRO_DEC_ORG_LAST_REG; i++)
+ iowrite32(dev->dec_regs[i], dev->hwregs + i*4);
+#ifdef USE_64BIT_ENV
+ for (i = HANTRO_DEC_EXT_FIRST_REG; i <= HANTRO_DEC_EXT_LAST_REG; i++)
+ iowrite32(dev->dec_regs[i], dev->hwregs + i*4);
+#endif
+ } else {
+ ret = copy_from_user(dev->dec_regs, Core->regs, HANTRO_G2_DEC_REGS*4);
+ if (ret) {
+ pr_err("copy_from_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+
+ /* write all regs but the status reg[1] to hardware */
+ for (i = 2; i <= HANTRO_G2_DEC_LAST_REG; i++)
+ iowrite32(dev->dec_regs[i], dev->hwregs + i*4);
+ }
+
+ /* write the status register, which may start the decoder */
+ iowrite32(dev->dec_regs[1], dev->hwregs + 4);
+
+ PDEBUG("flushed registers on Core %d\n", dev->core_id);
+
+ return 0;
+}
+
+static long DecRefreshRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+ long ret, i;
+ //u32 id = Core->id;
+
+ if (IS_G1(dev->hw_id)) {
+ /* user has to know exactly what they are asking for */
+ //if(Core->size != (HANTRO_DEC_ORG_REGS * 4))
+ // return -EFAULT;
+
+ /* read all registers from hardware */
+ /* both original and extended regs need to be read */
+ for (i = 0; i <= HANTRO_DEC_ORG_LAST_REG; i++)
+ dev->dec_regs[i] = ioread32(dev->hwregs + i*4);
+#ifdef USE_64BIT_ENV
+ for (i = HANTRO_DEC_EXT_FIRST_REG; i <= HANTRO_DEC_EXT_LAST_REG; i++)
+ dev->dec_regs[i] = ioread32(dev->hwregs + i*4);
+#endif
+
+ if (dev->timeout) {
+ /* Enable TIMEOUT bits in Reg[1] */
+ dev->dec_regs[1] = 0x40100;
+ /* Reset HW */
+ ResetAsic(dev);
+ dev->timeout = 0;
+ }
+
+ /* put registers to user space*/
+ /* put original registers to user space*/
+ ret = copy_to_user(Core->regs, dev->dec_regs, HANTRO_DEC_ORG_REGS*4);
+#ifdef USE_64BIT_ENV
+ /*put extended registers to user space*/
+ ret = copy_to_user(Core->regs + HANTRO_DEC_EXT_FIRST_REG,
+ dev->dec_regs + HANTRO_DEC_EXT_FIRST_REG, HANTRO_DEC_EXT_REGS * 4);
+#endif
+ if (ret) {
+ pr_err("copy_to_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+ } else {
+ /* user has to know exactly what they are asking for */
+ if (Core->size != (HANTRO_G2_DEC_REGS * 4))
+ return -EFAULT;
+
+ /* read all registers from hardware */
+ for (i = 0; i <= HANTRO_G2_DEC_LAST_REG; i++)
+ dev->dec_regs[i] = ioread32(dev->hwregs + i*4);
+
+ if (dev->timeout) {
+ /* Enable TIMEOUT bits in Reg[1] */
+ dev->dec_regs[1] = 0x40100;
+ /* Reset HW */
+ ResetAsic(dev);
+ dev->timeout = 0;
+ }
+
+ /* put registers to user space*/
+ ret = copy_to_user(Core->regs, dev->dec_regs, HANTRO_G2_DEC_REGS*4);
+ if (ret) {
+ pr_err("copy_to_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+ }
+ return 0;
+}
+
+static int CheckDecIrq(hantrodec_t *dev)
+{
+ unsigned long flags;
+ int rdy = 0;
+
+ const u32 irq_mask = (1 << dev->core_id);
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ if (dec_irq & irq_mask) {
+ /* reset the wait condition(s) */
+ dec_irq &= ~irq_mask;
+ rdy = 1;
+ }
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ return rdy;
+}
+
+static long WaitDecReadyAndRefreshRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+ //u32 id = Core->id;
+ long ret;
+
+ PDEBUG("wait_event_interruptible DEC[%d]\n", dev->core_id);
+
+ ret = wait_event_interruptible_timeout(dec_wait_queue, CheckDecIrq(dev), msecs_to_jiffies(200));
+ if (ret == -ERESTARTSYS) {
+ pr_err("DEC[%d] failed to wait_event_interruptible interrupted\n", dev->core_id);
+ return -ERESTARTSYS;
+ } else if (ret == 0) {
+ pr_err("DEC[%d] wait_event_interruptible timeout\n", dev->core_id);
+ dev->timeout = 1;
+ }
+
+ atomic_inc(&dev->irq_tx);
+
+ /* refresh registers */
+ return DecRefreshRegs(dev, Core);
+}
+
+static long PPFlushRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+ long ret = 0;
+ //u32 id = Core->id;
+ u32 i;
+
+ /* copy original dec regs to kernal space*/
+ ret = copy_from_user(dev->dec_regs + HANTRO_PP_ORG_FIRST_REG,
+ Core->regs + HANTRO_PP_ORG_FIRST_REG, HANTRO_PP_ORG_REGS*4);
+#ifdef USE_64BIT_ENV
+ /* copy extended dec regs to kernal space*/
+ ret = copy_from_user(dev->dec_regs + HANTRO_PP_EXT_FIRST_REG,
+ Core->regs + HANTRO_PP_EXT_FIRST_REG, HANTRO_PP_EXT_REGS*4);
+#endif
+ if (ret) {
+ pr_err("copy_from_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+
+ /* write all regs but the status reg[1] to hardware */
+ /* both original and extended regs need to be written */
+ for (i = HANTRO_PP_ORG_FIRST_REG + 1; i <= HANTRO_PP_ORG_LAST_REG; i++)
+ iowrite32(dev->dec_regs[i], dev->hwregs + i*4);
+#ifdef USE_64BIT_ENV
+ for (i = HANTRO_PP_EXT_FIRST_REG; i <= HANTRO_PP_EXT_LAST_REG; i++)
+ iowrite32(dev->dec_regs[i], dev->hwregs + i*4);
+#endif
+ /* write the stat reg, which may start the PP */
+ iowrite32(dev->dec_regs[HANTRO_PP_ORG_FIRST_REG],
+ dev->hwregs + HANTRO_PP_ORG_FIRST_REG * 4);
+
+ return 0;
+}
+
+static long PPRefreshRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+ long i, ret;
+ //u32 id = Core->id;
+#ifdef USE_64BIT_ENV
+ /* user has to know exactly what they are asking for */
+ if (Core->size != (HANTRO_PP_TOTAL_REGS * 4))
+ return -EFAULT;
+#else
+ /* user has to know exactly what they are asking for */
+ if (Core->size != (HANTRO_PP_ORG_REGS * 4))
+ return -EFAULT;
+#endif
+
+ /* read all registers from hardware */
+ /* both original and extended regs need to be read */
+ for (i = HANTRO_PP_ORG_FIRST_REG; i <= HANTRO_PP_ORG_LAST_REG; i++)
+ dev->dec_regs[i] = ioread32(dev->hwregs + i*4);
+#ifdef USE_64BIT_ENV
+ for (i = HANTRO_PP_EXT_FIRST_REG; i <= HANTRO_PP_EXT_LAST_REG; i++)
+ dev->dec_regs[i] = ioread32(dev->hwregs + i*4);
+#endif
+ /* put registers to user space*/
+ /* put original registers to user space*/
+ ret = copy_to_user(Core->regs + HANTRO_PP_ORG_FIRST_REG,
+ dev->dec_regs + HANTRO_PP_ORG_FIRST_REG, HANTRO_PP_ORG_REGS*4);
+#ifdef USE_64BIT_ENV
+ /* put extended registers to user space*/
+ ret = copy_to_user(Core->regs + HANTRO_PP_EXT_FIRST_REG,
+ dev->dec_regs + HANTRO_PP_EXT_FIRST_REG, HANTRO_PP_EXT_REGS * 4);
+#endif
+ if (ret) {
+ pr_err("copy_to_user failed, returned %li\n", ret);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int CheckPPIrq(hantrodec_t *dev)
+{
+ unsigned long flags;
+ int rdy = 0;
+
+ const u32 irq_mask = (1 << dev->core_id);
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ if (pp_irq & irq_mask) {
+ /* reset the wait condition(s) */
+ pp_irq &= ~irq_mask;
+ rdy = 1;
+ }
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ return rdy;
+}
+
+static long WaitPPReadyAndRefreshRegs(hantrodec_t *dev, struct core_desc *Core)
+{
+ //u32 id = Core->id;
+
+ PDEBUG("wait_event_interruptible PP[%d]\n", dev->core_id);
+
+ if (wait_event_interruptible(pp_wait_queue, CheckPPIrq(dev))) {
+ pr_err("PP[%d] failed to wait_event_interruptible interrupted\n", dev->core_id);
+ return -ERESTARTSYS;
+ }
+
+ atomic_inc(&dev->irq_tx);
+
+ /* refresh registers */
+ return PPRefreshRegs(dev, Core);
+}
+
+static int CheckCoreIrq(const struct file *filp, int *id)
+{
+ unsigned long flags;
+ int rdy = 0, n = 0;
+ hantrodec_t *dev;
+
+ do {
+ u32 irq_mask;
+
+ dev = &hantrodec_data[n];
+ irq_mask = (1 << dev->core_id);
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ if (dec_irq & irq_mask) {
+ if (dev->dec_owner == filp) {
+ /* we have an IRQ for our client */
+
+ /* reset the wait condition(s) */
+ dec_irq &= ~irq_mask;
+
+ /* signal ready Core no. for our client */
+ *id = dev->core_id;
+
+ rdy = 1;
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+ break;
+ } else if (dev->dec_owner == NULL) {
+ /* zombie IRQ */
+ pr_info("IRQ on Core[%d], but no owner!!!\n", n);
+
+ /* reset the wait condition(s) */
+ dec_irq &= ~irq_mask;
+ }
+ }
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ n++; /* next Core */
+ } while (n < cores);
+
+ return rdy;
+}
+
+static long WaitCoreReady(const struct file *filp, int *id)
+{
+ PDEBUG("wait_event_interruptible CORE\n");
+
+ if (wait_event_interruptible(dec_wait_queue, CheckCoreIrq(filp, id))) {
+ pr_err("CORE failed to wait_event_interruptible interrupted\n");
+ return -ERESTARTSYS;
+ }
+
+ atomic_inc(&hantrodec_data[*id].irq_tx);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------
+ *Function name : hantrodec_ioctl
+ *Description : communication method to/from the user space
+ *
+ *Return type : long
+ *-------------------------------------------------------------------------
+ */
+
+static long hantrodec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+ long tmp;
+
+ PDEBUG("ioctl cmd 0x%08x\n", cmd);
+ /*
+ * extract the type and number bitfields, and don't decode
+ * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+ */
+ if (_IOC_TYPE(cmd) != HANTRODEC_IOC_MAGIC)
+ return -ENOTTY;
+ if (_IOC_NR(cmd) > HANTRODEC_IOC_MAXNR)
+ return -ENOTTY;
+
+ /*
+ * the direction is a bitmask, and VERIFY_WRITE catches R/W
+ * transfers. `Type' is user-oriented, while
+ * access_ok is kernel-oriented, so the concept of "read" and
+ * "write" is reversed
+ */
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = !access_ok(VERIFY_WRITE, (void *) arg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ err = !access_ok(VERIFY_READ, (void *) arg, _IOC_SIZE(cmd));
+
+ if (err)
+ return -EFAULT;
+
+ switch (_IOC_NR(cmd)) {
+ case _IOC_NR(HANTRODEC_IOC_CLI): {
+ __u32 id;
+
+ __get_user(id, (__u32 *)arg);
+ if (id >= cores)
+ return -EFAULT;
+ disable_irq(hantrodec_data[id].irq);
+ break;
+ }
+ case _IOC_NR(HANTRODEC_IOC_STI): {
+ __u32 id;
+
+ __get_user(id, (__u32 *)arg);
+ if (id >= cores)
+ return -EFAULT;
+ enable_irq(hantrodec_data[id].irq);
+ break;
+ }
+ case _IOC_NR(HANTRODEC_IOCGHWOFFSET): {
+ __u32 id;
+
+ __get_user(id, (__u32 *)arg);
+ if (id >= cores)
+ return -EFAULT;
+
+ __put_user(multicorebase[id], (unsigned long *) arg);
+ break;
+ }
+ case _IOC_NR(HANTRODEC_IOCGHWIOSIZE): {
+ __u32 id;
+ __u32 io_size;
+
+ __get_user(id, (__u32 *)arg);
+ if (id >= cores)
+ return -EFAULT;
+ io_size = hantrodec_data[id].iosize;
+ __put_user(io_size, (u32 *) arg);
+
+ return 0;
+ }
+ case _IOC_NR(HANTRODEC_IOC_MC_OFFSETS): {
+ tmp = copy_to_user((u64 *) arg, multicorebase, sizeof(multicorebase));
+ if (err) {
+ pr_err("copy_to_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+ break;
+ }
+ case _IOC_NR(HANTRODEC_IOC_MC_CORES):
+ __put_user(cores, (unsigned int *) arg);
+ PDEBUG("hantrodec_data.cores=%d\n", cores);
+ break;
+ case _IOC_NR(HANTRODEC_IOCS_DEC_PUSH_REG): {
+ struct core_desc Core;
+
+ /* get registers from user space*/
+ tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+ if (tmp) {
+ pr_err("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ DecFlushRegs(&hantrodec_data[Core.id], &Core);
+ break;
+ }
+ case _IOC_NR(HANTRODEC_IOCS_PP_PUSH_REG): {
+ struct core_desc Core;
+
+ /* get registers from user space*/
+ tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+ if (tmp) {
+ pr_err("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ PPFlushRegs(&hantrodec_data[Core.id], &Core);
+ break;
+ }
+ case _IOC_NR(HANTRODEC_IOCS_DEC_PULL_REG): {
+ struct core_desc Core;
+
+ /* get registers from user space*/
+ tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+ if (tmp) {
+ pr_err("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ return DecRefreshRegs(&hantrodec_data[Core.id], &Core);
+ }
+ case _IOC_NR(HANTRODEC_IOCS_PP_PULL_REG): {
+ struct core_desc Core;
+
+ /* get registers from user space*/
+ tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+ if (tmp) {
+ pr_err("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ return PPRefreshRegs(&hantrodec_data[Core.id], &Core);
+ }
+ case _IOC_NR(HANTRODEC_IOCH_DEC_RESERVE): {
+ int id;
+
+ PDEBUG("Reserve DEC Core, format = %li\n", arg);
+ id = GetDecCoreID(arg);
+ if (id < 0) {
+ pr_err("invalid format: %ld\n", arg);
+ return -EFAULT;
+ }
+ return ReserveDecoder(&hantrodec_data[id], filp, arg);
+ }
+ case _IOC_NR(HANTRODEC_IOCT_DEC_RELEASE): {
+ if (arg >= cores || hantrodec_data[arg].dec_owner != filp) {
+ pr_err("bogus DEC release, Core = %li\n", arg);
+ return -EFAULT;
+ }
+
+ PDEBUG("Release DEC, Core = %li\n", arg);
+
+ ReleaseDecoder(&hantrodec_data[arg]);
+
+ break;
+ }
+ case _IOC_NR(HANTRODEC_IOCQ_PP_RESERVE):
+ return ReservePostProcessor(&hantrodec_data[0], filp);
+ case _IOC_NR(HANTRODEC_IOCT_PP_RELEASE): {
+ if (arg != 0 || hantrodec_data[arg].pp_owner != filp) {
+ pr_err("bogus PP release %li\n", arg);
+ return -EFAULT;
+ }
+
+ ReleasePostProcessor(&hantrodec_data[arg]);
+
+ break;
+ }
+ case _IOC_NR(HANTRODEC_IOCX_DEC_WAIT): {
+ struct core_desc Core;
+
+ /* get registers from user space */
+ tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+ if (tmp) {
+ pr_err("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ return WaitDecReadyAndRefreshRegs(&hantrodec_data[Core.id], &Core);
+ }
+ case _IOC_NR(HANTRODEC_IOCX_PP_WAIT): {
+ struct core_desc Core;
+
+ /* get registers from user space */
+ tmp = copy_from_user(&Core, (void *)arg, sizeof(struct core_desc));
+ if (tmp) {
+ pr_err("copy_from_user failed, returned %li\n", tmp);
+ return -EFAULT;
+ }
+
+ return WaitPPReadyAndRefreshRegs(&hantrodec_data[Core.id], &Core);
+ }
+ case _IOC_NR(HANTRODEC_IOCG_CORE_WAIT): {
+ int id;
+
+ tmp = WaitCoreReady(filp, &id);
+ __put_user(id, (int *) arg);
+ return tmp;
+ }
+ case _IOC_NR(HANTRODEC_IOX_ASIC_ID): {
+ u32 id;
+
+ __get_user(id, (u32 *)arg);
+ if (id >= cores)
+ return -EFAULT;
+ id = ioread32(hantrodec_data[id].hwregs);
+ __put_user(id, (u32 *) arg);
+ return 0;
+ }
+ case _IOC_NR(HANTRODEC_IOCG_CORE_ID): {
+ int id;
+ hantrodec_instance *ctx = (hantrodec_instance *)filp->private_data;
+
+ PDEBUG("Get DEC Core_id, format = %li\n", arg);
+ id = GetDecCoreID(arg);
+ if ((ctx->core_id == 3) && (id >= 0)) {
+ if (id == 0) {
+ ctx->core_id = 1; //g1
+ /*power off g2*/
+ pm_runtime_put_sync(hantrodec_data[1].dev);
+ hantro_clk_disable(&hantrodec_data[1].clk);
+ } else if (id == 1) {
+ ctx->core_id = 2; //g2
+ /*power off g1*/
+ pm_runtime_put_sync(hantrodec_data[0].dev);
+ hantro_clk_disable(&hantrodec_data[0].clk);
+ }
+ }
+ return id;
+ }
+ case _IOC_NR(HANTRODEC_DEBUG_STATUS): {
+ PDEBUG("hantrodec: dec_irq = 0x%08x\n", dec_irq);
+ PDEBUG("hantrodec: pp_irq = 0x%08x\n", pp_irq);
+
+ //PDEBUG("hantrodec: IRQs received/sent2user = %d / %d\n",
+ //atomic_read(&irq_rx), atomic_read(&irq_tx));
+
+ for (tmp = 0; tmp < cores; tmp++) {
+ PDEBUG("hantrodec: Core %ld IRQs received/sent2user = %d / %d\n", tmp,
+ atomic_read(&hantrodec_data[tmp].irq_rx), atomic_read(&hantrodec_data[tmp].irq_tx));
+
+ PDEBUG("hantrodec: dec_core[%li] %s\n",
+ tmp, hantrodec_data[tmp].dec_owner == NULL ? "FREE" : "RESERVED");
+ PDEBUG("hantrodec: pp_core[%li] %s\n",
+ tmp, hantrodec_data[tmp].pp_owner == NULL ? "FREE" : "RESERVED");
+ }
+ }
+ default:
+ return -ENOTTY;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_COMPAT
+struct core_desc_32 {
+ __u32 id; /* id of the Core */
+ compat_caddr_t regs; /* pointer to user registers */
+ __u32 size; /* size of register space */
+};
+
+static int get_hantro_core_desc32(struct core_desc *kp, struct core_desc_32 __user *up)
+{
+ u32 tmp;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(struct core_desc_32)) ||
+ get_user(kp->id, &up->id) ||
+ get_user(kp->size, &up->size) ||
+ get_user(tmp, &up->regs)) {
+ return -EFAULT;
+ }
+ kp->regs = (__force u32 *)compat_ptr(tmp);
+ return 0;
+}
+
+static int put_hantro_core_desc32(struct core_desc *kp, struct core_desc_32 __user *up)
+{
+ u32 tmp = (u32)((unsigned long)kp->regs);
+
+ if (!access_ok(VERIFY_WRITE, up, sizeof(struct core_desc_32)) ||
+ put_user(kp->id, &up->id) ||
+ put_user(kp->size, &up->size) ||
+ put_user(tmp, &up->regs)) {
+ return -EFAULT;
+ }
+ return 0;
+}
+static long hantrodec_ioctl32(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+#define HANTRO_IOCTL32(err, filp, cmd, arg) { \
+ mm_segment_t old_fs = get_fs(); \
+ set_fs(KERNEL_DS); \
+ err = hantrodec_ioctl(filp, cmd, arg); \
+ if (err) \
+ return err; \
+ set_fs(old_fs); \
+ }
+
+ union {
+ struct core_desc kcore;
+ unsigned long kux;
+ unsigned int kui;
+ } karg;
+ void __user *up = compat_ptr(arg);
+ long err = 0;
+
+ switch (_IOC_NR(cmd)) {
+ case _IOC_NR(HANTRODEC_IOCGHWOFFSET):
+ case _IOC_NR(HANTRODEC_IOC_MC_OFFSETS):
+ err = get_user(karg.kux, (s32 __user *)up);
+ if (err)
+ return err;
+ HANTRO_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+ err = put_user(((s32)karg.kux), (s32 __user *)up);
+ break;
+ case _IOC_NR(HANTRODEC_IOCGHWIOSIZE):
+ case _IOC_NR(HANTRODEC_IOC_MC_CORES):
+ case _IOC_NR(HANTRODEC_IOCG_CORE_WAIT):
+ case _IOC_NR(HANTRODEC_IOX_ASIC_ID):
+ err = get_user(karg.kui, (s32 __user *)up);
+ if (err)
+ return err;
+ HANTRO_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+ err = put_user(((s32)karg.kui), (s32 __user *)up);
+ break;
+ case _IOC_NR(HANTRODEC_IOCS_DEC_PUSH_REG):
+ case _IOC_NR(HANTRODEC_IOCS_PP_PUSH_REG):
+ case _IOC_NR(HANTRODEC_IOCX_DEC_WAIT):
+ case _IOC_NR(HANTRODEC_IOCX_PP_WAIT):
+ case _IOC_NR(HANTRODEC_IOCS_DEC_PULL_REG):
+ case _IOC_NR(HANTRODEC_IOCS_PP_PULL_REG):
+ err = get_hantro_core_desc32(&karg.kcore, up);
+ if (err)
+ return err;
+ HANTRO_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+ err = put_hantro_core_desc32(&karg.kcore, up);
+ break;
+ default:
+ err = hantrodec_ioctl(filp, cmd, (unsigned long)up);
+ break;
+ }
+
+ return err;
+}
+
+#endif //ifdef CONFIG_COMPAT
+
+/*--------------------------------------------------------------------------
+ *Function name : hantrodec_open
+ *Description : open method
+ *
+ *Return type : int
+ *---------------------------------------------------------------------------
+ */
+static int hantrodec_open(struct inode *inode, struct file *filp)
+{
+ int i;
+ int idx;
+
+ idx = hantro_new_instance();
+ if (idx < 0)
+ return -ENOMEM;
+
+ PDEBUG("dev opened: id: %d\n", idx);
+ hantrodec_ctx[idx].core_id = 3; //unknow
+ hantrodec_ctx[idx].inst_id = idx;
+ filp->private_data = (void *)(&hantrodec_ctx[idx]);
+
+ /*not yet know which core id, so power on both g1 and g2 firstly*/
+ for (i = 0; i < 2; i++) {
+ hantro_clk_enable(&hantrodec_data[i].clk);
+ hantro_power_on_disirq(&hantrodec_data[i]);
+ }
+ return 0;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : hantrodec_release
+ *Description : Release driver
+ *
+ *Return type : int
+ *----------------------------------------------------------------------------
+ */
+static int hantrodec_release(struct inode *inode, struct file *filp)
+{
+ int n;
+ //hantrodec_t *dev = &hantrodec_data;
+ hantrodec_instance *ctx = (hantrodec_instance *)filp->private_data;
+
+ PDEBUG("closing ...\n");
+ for (n = 0; n < cores; n++) {
+ if (hantrodec_data[n].dec_owner == filp) {
+ PDEBUG("releasing dec Core %i lock\n", n);
+ ReleaseDecoder(&hantrodec_data[n]);
+ }
+ }
+
+ for (n = 0; n < 1; n++) {
+ if (hantrodec_data[n].pp_owner == filp) {
+ PDEBUG("releasing pp Core %i lock\n", n);
+ ReleasePostProcessor(&hantrodec_data[n]);
+ }
+ }
+
+ if (ctx->core_id & 0x1) {
+ pm_runtime_put_sync(hantrodec_data[0].dev);
+ hantro_clk_disable(&hantrodec_data[0].clk);
+ }
+ if (ctx->core_id & 0x2) {
+ pm_runtime_put_sync(hantrodec_data[1].dev);
+ hantro_clk_disable(&hantrodec_data[1].clk);
+ }
+ hantro_free_instance(ctx->inst_id);
+
+ PDEBUG("closed: id: %d\n", n);
+ return 0;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : hantro_mmap
+ *Description : memory map interface for hantro file operation
+ *
+ *Return type : int
+ *---------------------------------------------------------------------------
+ */
+static int hantro_mmap(struct file *fp, struct vm_area_struct *vm)
+{
+ if (vm->vm_pgoff == (multicorebase[0] >> PAGE_SHIFT) || vm->vm_pgoff == (multicorebase[1] >> PAGE_SHIFT)) {
+ vm->vm_flags |= VM_IO;
+ vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);
+ PDEBUG("hantro mmap: size=0x%lX, page off=0x%lX\n", (vm->vm_end - vm->vm_start), vm->vm_pgoff);
+ return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end - vm->vm_start,
+ vm->vm_page_prot) ? -EAGAIN : 0;
+ } else {
+ pr_err("invalid map offset :0x%lX\n", vm->vm_pgoff);
+ return -EINVAL;
+ }
+}
+
+/* VFS methods */
+static const struct file_operations hantrodec_fops = {
+ .owner = THIS_MODULE,
+ .open = hantrodec_open,
+ .release = hantrodec_release,
+ .unlocked_ioctl = hantrodec_ioctl,
+ .fasync = NULL,
+ .mmap = hantro_mmap,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = hantrodec_ioctl32,
+#endif
+};
+
+/*---------------------------------------------------------------------------
+ *Function name : hantrodec_init
+ *Description : Initialize the driver
+ *
+ *Return type : int
+ *---------------------------------------------------------------------------
+ */
+static int hantrodec_init(struct platform_device *pdev, int id)
+{
+ int result;
+ int irq;
+ struct device *temp_class;
+
+ //dec_irq = 0;
+ //pp_irq = 0;
+ pr_debug("hantrodec: Init multi Core[0] at 0x%16lx\n"
+ " Core[1] at 0x%16lx\n", multicorebase[0], multicorebase[1]);
+
+ //hantrodec_data.cores = 0;
+ //hantrodec_data.iosize[0] = DEC_IO_SIZE_0;
+ //hantrodec_data.iosize[1] = DEC_IO_SIZE_1;
+
+ //hantrodec_data.async_queue_dec = NULL;
+ //hantrodec_data.async_queue_pp = NULL;
+
+ hantrodec_data[id].iosize = (id == 0) ? DEC_IO_SIZE_0 : DEC_IO_SIZE_1;
+
+ if (!hantrodec_major) {
+ dec_irq = 0;
+ pp_irq = 0;
+
+ result = register_chrdev(hantrodec_major, "hantrodec", &hantrodec_fops);
+ if (result < 0) {
+ pr_err("hantrodec: unable to get major %d\n", hantrodec_major);
+ goto err;
+ } else if (result != 0) { /* this is for dynamic major */
+ hantrodec_major = result;
+ }
+
+ hantro_class = class_create(THIS_MODULE, "mxc_hantro_845");
+ if (IS_ERR(hantro_class)) {
+ result = -1;
+ goto err;
+ }
+ temp_class = device_create(hantro_class, NULL, MKDEV(hantrodec_major, 0), NULL, DEVICE_NAME);
+ if (IS_ERR(temp_class)) {
+ result = -1;
+ goto err_out_class;
+ }
+ }
+
+ result = ReserveIO(id);
+ if (result < 0)
+ goto err;
+
+ hantrodec_data[id].dec_owner = 0;
+ hantrodec_data[id].pp_owner = 0;
+
+ sema_init(&hantrodec_data[id].dec_core_sem, 1);
+ sema_init(&hantrodec_data[id].pp_core_sem, 1);
+
+ /* read configuration fo all cores */
+ ReadCoreConfig(&hantrodec_data[id]);
+
+ /* reset hardware */
+ ResetAsic(&hantrodec_data[id]);
+
+ /* register irq for each core*/
+ irq = platform_get_irq_byname(pdev, "irq_hantro");
+ if (irq > 0) {
+ hantrodec_data[id].irq = irq;
+ result = request_irq(irq, hantrodec_isr, IRQF_SHARED,
+ "hantrodec", (void *) &hantrodec_data[id]);
+
+ if (result != 0) {
+ if (result == -EINVAL)
+ pr_err("hantrodec: Bad irq number or handler\n");
+ else if (result == -EBUSY) {
+ pr_err("hantrodec: IRQ <%d> busy, change your config\n",
+ hantrodec_data[id].irq);
+ }
+ ReleaseIO(id);
+ goto err;
+ }
+ } else {
+ pr_err("hantrodec: IRQ0 not in use!\n");
+ goto err;
+ }
+
+ hantrodec_data[id].irq_rx.counter = 0;
+ hantrodec_data[id].irq_tx.counter = 0;
+ irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
+ pr_info("hantrodec %d : module inserted. Major = %d\n", id, hantrodec_major);
+
+ return 0;
+
+err_out_class:
+ device_destroy(hantro_class, MKDEV(hantrodec_major, 0));
+ class_destroy(hantro_class);
+err:
+ pr_err("hantrodec: module not inserted\n");
+ unregister_chrdev(hantrodec_major, "hantrodec");
+ return result;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : hantrodec_cleanup
+ *Description : clean up
+ *
+ *Return type : int
+ *---------------------------------------------------------------------------
+ */
+static void hantrodec_cleanup(int id)
+{
+ hantrodec_t *dev = &hantrodec_data[id];
+ //int n = 0;
+ /* reset hardware */
+ ResetAsic(dev);
+
+ /* free the IRQ */
+ //for (n = 0; n < dev->cores; n++) {
+ if (dev->irq != -1)
+ free_irq(dev->irq, (void *) dev);
+ //}
+
+ ReleaseIO(id);
+
+ //unregister_chrdev(hantrodec_major, "hantrodec");
+
+ PDEBUG("hantrodec: module removed\n");
+
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : CheckHwId
+ *Return type : int
+ *---------------------------------------------------------------------------
+ */
+static int CheckHwId(hantrodec_t *dev)
+{
+ long int hwid;
+ //int i;
+ size_t num_hw = sizeof(DecHwId) / sizeof(*DecHwId);
+
+ int found = 0;
+
+ //for (i = 0; i < cores; i++) {
+ if (dev->hwregs != NULL) {
+ hwid = readl(dev->hwregs);
+ pr_debug("hantrodec: Core %d HW ID=0x%16lx\n", dev->core_id, hwid);
+ hwid = (hwid >> 16) & 0xFFFF; /* product version only */
+
+ while (num_hw--) {
+ if (hwid == DecHwId[num_hw]) {
+ pr_debug("hantrodec: Supported HW found at 0x%16lx\n",
+ multicorebase[dev->core_id]);
+ found++;
+ dev->hw_id = hwid;
+ break;
+ }
+ }
+ if (!found) {
+ pr_err("hantrodec: Unknown HW found at 0x%16lx\n", multicorebase[dev->core_id]);
+ return 0;
+ }
+ found = 0;
+ num_hw = sizeof(DecHwId) / sizeof(*DecHwId);
+ }
+ //}
+
+ return 1;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : ReserveIO
+ *Description : IO reserve
+ *
+ *Return type : int
+ *---------------------------------------------------------------------------
+ */
+static int ReserveIO(int i)
+{
+ //int i;
+
+ //for (i = 0; i < HXDEC_MAX_CORES; i++) {
+ if (multicorebase[i] != -1) {
+ if (!request_mem_region(multicorebase[i], hantrodec_data[i].iosize, "hantrodec0")) {
+ pr_err("hantrodec: failed to reserve HW regs, %d, base: 0x%lX, %d\n", i, multicorebase[i], hantrodec_data[i].iosize);
+ return -EBUSY;
+ }
+
+ hantrodec_data[i].hwregs = (volatile u8 *) ioremap_nocache(multicorebase[i],
+ hantrodec_data[i].iosize);
+
+ if (hantrodec_data[i].hwregs == NULL) {
+ pr_err("hantrodec: failed to ioremap HW regs\n");
+ ReleaseIO(i);
+ return -EBUSY;
+ }
+ //hantrodec_data.cores++;
+ }
+ //}
+
+ /* check for correct HW */
+ if (!CheckHwId(&hantrodec_data[i])) {
+ ReleaseIO(i);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : releaseIO
+ *Description : release
+ *
+ *Return type : void
+ *---------------------------------------------------------------------------
+ */
+static void ReleaseIO(int i)
+{
+ //int i;
+
+ //for (i = 0; i < hantrodec_data.cores; i++) {
+ if (hantrodec_data[i].hwregs)
+ iounmap((void *) hantrodec_data[i].hwregs);
+ release_mem_region(multicorebase[i], hantrodec_data[i].iosize);
+ //}
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : hantrodec_isr
+ *Description : interrupt handler
+ *
+ *Return type : irqreturn_t
+ *---------------------------------------------------------------------------
+ */
+static irqreturn_t hantrodec_isr(int irq, void *dev_id)
+{
+ unsigned long flags;
+ unsigned int handled = 0;
+ //int i;
+ volatile u8 *hwregs;
+
+ hantrodec_t *dev = (hantrodec_t *) dev_id;
+ u32 irq_status_dec;
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ //for (i = 0; i < cores; i++) {
+ hwregs = dev->hwregs;
+
+ /* interrupt status register read */
+ irq_status_dec = ioread32(hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+ if (irq_status_dec & HANTRODEC_DEC_IRQ) {
+ /* clear dec IRQ */
+ irq_status_dec &= (~HANTRODEC_DEC_IRQ);
+ iowrite32(irq_status_dec, hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+ PDEBUG("decoder IRQ received! Core %d\n", dev->core_id);
+
+ atomic_inc(&hantrodec_data[dev->core_id].irq_rx);
+
+ dec_irq |= (1 << dev->core_id);
+
+ wake_up_interruptible_all(&dec_wait_queue);
+ handled++;
+ }
+ //}
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ if (!handled)
+ pr_info("IRQ received, but not hantrodec's!\n");
+
+ (void)hwregs;
+ return IRQ_RETVAL(handled);
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : ResetAsic
+ *Description : reset asic
+ *
+ *Return type :
+ *---------------------------------------------------------------------------
+ */
+static void ResetAsic(hantrodec_t *dev)
+{
+ int i;
+ u32 status;
+
+ //for (j = 0; j < dev->cores; j++) {
+ status = ioread32(dev->hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+
+ if (status & HANTRODEC_DEC_E) {
+ /* abort with IRQ disabled */
+ status = HANTRODEC_DEC_ABORT | HANTRODEC_DEC_IRQ_DISABLE;
+ iowrite32(status, dev->hwregs + HANTRODEC_IRQ_STAT_DEC_OFF);
+ }
+
+ if (IS_G1(dev->hw_id))
+ /* reset PP */
+ iowrite32(0, dev->hwregs + HANTRO_IRQ_STAT_PP_OFF);
+
+ for (i = 4; i < dev->iosize; i += 4)
+ iowrite32(0, dev->hwregs + i);
+ //}
+}
+
+/*---------------------------------------------------------------------------
+ *Function name : dump_regs
+ *Description : Dump registers
+ *
+ *Return type :
+ *---------------------------------------------------------------------------
+ */
+#ifdef HANTRODEC_DEBUG
+static void dump_regs(hantrodec_t *dev)
+{
+ int i, c;
+
+ PDEBUG("Reg Dump Start\n");
+ for (c = 0; c < dev->cores; c++) {
+ for (i = 0; i < dev->iosize[c]; i += 4*4) {
+ PDEBUG("\toffset %04X: %08X %08X %08X %08X\n", i,
+ ioread32(dev->hwregs[c] + i),
+ ioread32(dev->hwregs[c] + i + 4),
+ ioread32(dev->hwregs[c] + i + 8),
+ ioread32(dev->hwregs[c] + i + 12));
+ }
+ }
+ PDEBUG("Reg Dump End\n");
+}
+#endif
+
+static int hantro_dev_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ struct resource *res;
+ unsigned long reg_base;
+ int id;
+
+ id = hantro_device_id(&pdev->dev);
+ if (id < 0)
+ return -ENODEV;
+
+ hantrodec_data[id].dev = &pdev->dev;
+ hantrodec_data[id].core_id = id;
+ platform_set_drvdata(pdev, &hantrodec_data[id]);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs_hantro");
+ if (!res) {
+ pr_err("hantro: unable to get vpu base addr\n");
+ return -ENODEV;
+ }
+ reg_base = res->start;
+ if ((ulong)reg_base != multicorebase[id]) {
+ pr_err("hantrodec %d: regbase(0x%lX) not equal to expected value(0x%lX)\n", id, reg_base, multicorebase[id]);
+ return -ENODEV;
+ }
+
+ hantrodec_data[id].clk.dec = clk_get(&pdev->dev, "clk_hantro");
+ hantrodec_data[id].clk.bus = clk_get(&pdev->dev, "clk_hantro_bus");
+ if (IS_ERR(hantrodec_data[id].clk.dec) || IS_ERR(hantrodec_data[id].clk.bus)) {
+ pr_err("hantro: get clock failed\n");
+ return -ENODEV;
+ }
+ pr_debug("hantro: dec, bus clock: 0x%lX, 0x%lX\n", clk_get_rate(hantrodec_data[id].clk.dec),
+ clk_get_rate(hantrodec_data[id].clk.bus));
+
+ hantro_clk_enable(&hantrodec_data[id].clk);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+ hantro_ctrlblk_reset(&hantrodec_data[id]);
+
+ err = hantrodec_init(pdev, id);
+ if (err != 0) {
+ pr_err("hantro: hantrodec_init failed\n");
+ goto error;
+ }
+
+#ifdef CONFIG_DEVICE_THERMAL_HANTRO
+ HANTRO_REG_THERMAL_NOTIFIER(&hantro_thermal_hot_notifier);
+ thermal_event = 0;
+ hantro_dynamic_clock = 0;
+ hantrodec_data[id].thermal_cur = 0;
+#endif
+ hantrodec_data[id].timeout = 0;
+ mutex_init(&hantrodec_data[id].dev_mutex);
+ instance_mask = 0;
+
+ goto out;
+
+error:
+ pr_err("hantro probe failed\n");
+out:
+ pm_runtime_put_sync(&pdev->dev);
+ hantro_clk_disable(&hantrodec_data[id].clk);
+ return err;
+}
+
+static int hantro_dev_remove(struct platform_device *pdev)
+{
+ hantrodec_t *dev = platform_get_drvdata(pdev);
+
+ hantro_clk_enable(&dev->clk);
+ pm_runtime_get_sync(&pdev->dev);
+
+ hantrodec_cleanup(dev->core_id);
+#if 1 // FIXME: need to identify core id
+ if (hantrodec_major > 0) {
+ device_destroy(hantro_class, MKDEV(hantrodec_major, 0));
+ class_destroy(hantro_class);
+ unregister_chrdev(hantrodec_major, "hantrodec");
+ hantrodec_major = 0;
+ }
+#endif
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ hantro_clk_disable(&dev->clk);
+
+#ifdef CONFIG_DEVICE_THERMAL_HANTRO
+ HANTRO_UNREG_THERMAL_NOTIFIER(&hantro_thermal_hot_notifier);
+#endif
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int hantro_suspend(struct device *dev)
+{
+ pm_runtime_put_sync_suspend(dev); //power off
+ return 0;
+}
+static int hantro_resume(struct device *dev)
+{
+ hantrodec_t *hantrodev = dev_get_drvdata(dev);
+
+ hantro_power_on_disirq(hantrodev);
+ hantro_ctrlblk_reset(hantrodev);
+ return 0;
+}
+static int hantro_runtime_suspend(struct device *dev)
+{
+ release_bus_freq(BUS_FREQ_HIGH);
+ return 0;
+}
+
+static int hantro_runtime_resume(struct device *dev)
+{
+ hantrodec_t *hantrodev = dev_get_drvdata(dev);
+
+ request_bus_freq(BUS_FREQ_HIGH);
+ hantro_ctrlblk_reset(hantrodev);
+ return 0;
+}
+
+static const struct dev_pm_ops hantro_pm_ops = {
+ SET_RUNTIME_PM_OPS(hantro_runtime_suspend, hantro_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(hantro_suspend, hantro_resume)
+};
+#endif //CONFIG_PM
+
+static const struct of_device_id hantro_of_match[] = {
+ { .compatible = "nxp,imx8mm-hantro", },
+ {/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, vpu_of_match);
+
+
+static struct platform_driver mxchantro_driver = {
+ .driver = {
+ .name = "mxc_hantro_845",
+ .of_match_table = hantro_of_match,
+#ifdef CONFIG_PM
+ .pm = &hantro_pm_ops,
+#endif
+ },
+ .probe = hantro_dev_probe,
+ .remove = hantro_dev_remove,
+};
+
+static int __init hantro_init(void)
+{
+ int ret = platform_driver_register(&mxchantro_driver);
+
+ return ret;
+}
+
+static void __exit hantro_exit(void)
+{
+ //clk_put(hantro_clk);
+ platform_driver_unregister(&mxchantro_driver);
+}
+
+module_init(hantro_init);
+module_exit(hantro_exit);
+
+/* module description */
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Google Finland Oy");
+MODULE_DESCRIPTION("Driver module for Hantro Decoder/Post-Processor");
+
diff --git a/drivers/mxc/hantro_845_h1/Kconfig b/drivers/mxc/hantro_845_h1/Kconfig
new file mode 100755
index 000000000000..65b21d92770c
--- /dev/null
+++ b/drivers/mxc/hantro_845_h1/Kconfig
@@ -0,0 +1,14 @@
+#
+# Codec configuration
+#
+
+menu "MXC HANTRO(Video Processing Unit) encoder support"
+ depends on ARCH_FSL_IMX8MQ
+
+config MXC_HANTRO_845_H1
+ tristate "Support for MXC HANTRO(Video Processing Unit) encoder"
+ default y
+ ---help---
+ VPU codec device.
+
+endmenu
diff --git a/drivers/mxc/hantro_845_h1/Makefile b/drivers/mxc/hantro_845_h1/Makefile
new file mode 100755
index 000000000000..acb87202c5b0
--- /dev/null
+++ b/drivers/mxc/hantro_845_h1/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the VPU drivers.
+#
+
+#ccflags-y += -I$(PWD)
+
+obj-$(CONFIG_MXC_HANTRO_845_H1) += hx280enc.o
+
diff --git a/drivers/mxc/hantro_845_h1/hx280enc.c b/drivers/mxc/hantro_845_h1/hx280enc.c
new file mode 100755
index 000000000000..0ba6440212a8
--- /dev/null
+++ b/drivers/mxc/hantro_845_h1/hx280enc.c
@@ -0,0 +1,883 @@
+/*
+ * Encoder device driver (kernel module)
+ *
+ * Copyright (c) 2013-2018, VeriSilicon Inc.
+ * Copyright (C) 2012 Google Finland Oy.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+--------------------------------------------------------------------------------
+--
+-- Abstract : 6280/7280/8270/8290/H1 Encoder device driver (kernel module)
+--
+------------------------------------------------------------------------------*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+/* needed for __init,__exit directives */
+#include <linux/init.h>
+/* needed for remap_page_range
+ SetPageReserved
+ ClearPageReserved
+*/
+#include <linux/mm.h>
+/* obviously, for kmalloc */
+#include <linux/slab.h>
+/* for struct file_operations, register_chrdev() */
+#include <linux/fs.h>
+/* standard error codes */
+#include <linux/errno.h>
+
+#include <linux/moduleparam.h>
+/* request_irq(), free_irq() */
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+
+/* needed for virt_to_phys() */
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/uaccess.h>
+#include <linux/ioport.h>
+
+#include <asm/irq.h>
+#include <linux/of_irq.h>
+#include <linux/version.h>
+
+/* our own stuff */
+#include <linux/hx280enc.h>
+
+#ifndef VSI
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+//static int hantro_h1_major = -1; /* dynamic allocation */
+static struct class *hantro_h1_class;
+#define DEVICE_NAME "mxc_hantro_h1"
+static struct device *hantro_h1_dev;
+static struct clk *hantro_clk_h1;
+static struct clk *hantro_clk_h1_bus;
+#define IRQF_DISABLED 0x0
+#endif
+
+#include <linux/delay.h>
+
+/* module description */
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Google Finland Oy");
+MODULE_DESCRIPTION("Hantro 6280/7280/8270/8290/H1 Encoder driver");
+
+/* this is ARM Integrator specific stuff */
+#ifndef VSI
+#define INTEGRATOR_LOGIC_MODULE0_BASE 0x38320000
+#else
+#define INTEGRATOR_LOGIC_MODULE0_BASE 0xC0000000
+#endif
+#define BLK_CTL_BASE 0x38330000 //0x38320000
+/*
+#define INTEGRATOR_LOGIC_MODULE1_BASE 0xD0000000
+#define INTEGRATOR_LOGIC_MODULE2_BASE 0xE0000000
+#define INTEGRATOR_LOGIC_MODULE3_BASE 0xF0000000
+*/
+
+#define VP_PB_INT_LT 30
+/*
+#define INT_EXPINT1 10
+#define INT_EXPINT2 11
+#define INT_EXPINT3 12
+*/
+/* these could be module params in the future */
+
+#define ENC_IO_BASE INTEGRATOR_LOGIC_MODULE0_BASE
+#define ENC_IO_SIZE (500 * 4) /* bytes */
+
+#define ENC_HW_ID1 0x62800000
+#define ENC_HW_ID2 0x72800000
+#define ENC_HW_ID3 0x82700000
+#define ENC_HW_ID4 0x82900000
+#define ENC_HW_ID5 0x48310000
+
+#define HX280ENC_BUF_SIZE 0
+
+static unsigned long base_port = INTEGRATOR_LOGIC_MODULE0_BASE;
+static int irq = VP_PB_INT_LT;
+
+/* for critical data access */
+static DEFINE_SPINLOCK(owner_lock);
+/* for irq wait */
+static DECLARE_WAIT_QUEUE_HEAD(enc_wait_queue);
+/* for reserve hw */
+static DECLARE_WAIT_QUEUE_HEAD(enc_hw_queue);
+
+/* module_param(name, type, perm) */
+module_param(base_port, ulong, 0644);
+module_param(irq, int, 0644);
+
+/* and this is our MAJOR; use 0 for dynamic allocation (recommended)*/
+static int hx280enc_major;
+
+/* here's all the must remember stuff */
+typedef struct {
+ u32 hw_id; //hw id to indicate project
+ u32 is_valid; //indicate this core is hantro's core or not
+ u32 is_reserved; //indicate this core is occupied by user or not
+ int pid; //indicate which process is occupying the core
+ u32 irq_received; //indicate this core receives irq
+ u32 irq_status;
+ int irq;
+ unsigned long iobaseaddr;
+ unsigned int iosize;
+
+ volatile u8 *hwregs;
+ struct fasync_struct *async_queue;
+ struct device *dev;
+ struct mutex dev_mutex;
+} hx280enc_t;
+
+/* dynamic allocation? */
+static hx280enc_t hx280enc_data;
+
+static int ReserveIO(void);
+static void ReleaseIO(void);
+static void ResetAsic(hx280enc_t *dev);
+
+#ifdef HX280ENC_DEBUG
+static void dump_regs(unsigned long data);
+#endif
+
+/* IRQ handler */
+static irqreturn_t hx280enc_isr(int irq, void *dev_id);
+
+#ifndef VSI
+static int hantro_h1_clk_enable(struct device *dev)
+{
+ clk_prepare(hantro_clk_h1);
+ clk_enable(hantro_clk_h1);
+ clk_prepare(hantro_clk_h1_bus);
+ clk_enable(hantro_clk_h1_bus);
+ return 0;
+}
+
+static int hantro_h1_clk_disable(struct device *dev)
+{
+ if (hantro_clk_h1) {
+ clk_disable(hantro_clk_h1);
+ clk_unprepare(hantro_clk_h1);
+ }
+ if (hantro_clk_h1_bus) {
+ clk_disable(hantro_clk_h1_bus);
+ clk_unprepare(hantro_clk_h1_bus);
+ }
+ return 0;
+}
+
+static int hantro_h1_ctrlblk_reset(struct device *dev)
+{
+ volatile u8 *iobase;
+ u32 val;
+
+ //config H1
+ hantro_h1_clk_enable(dev);
+ iobase = (volatile u8 *)ioremap_nocache(BLK_CTL_BASE, 0x10000);
+
+ val = ioread32(iobase);
+ val &= (~0x4);
+ iowrite32(val, iobase); // assert soft reset
+ udelay(2);
+
+ val = ioread32(iobase);
+ val |= 0x4;
+ iowrite32(val, iobase); // release soft reset
+
+ val = ioread32(iobase+0x4);
+ val |= 0x4;
+ iowrite32(val, iobase + 0x4); // enable clock
+
+ iowrite32(0xFFFFFFFF, iobase + 0x14); // H1 fuse encoder enable
+ iounmap(iobase);
+ hantro_h1_clk_disable(dev);
+ return 0;
+}
+
+static int hantro_h1_power_on_disirq(hx280enc_t *hx280enc)
+{
+ //spin_lock_irq(&owner_lock);
+ mutex_lock(&hx280enc->dev_mutex);
+ disable_irq(hx280enc->irq);
+ pm_runtime_get_sync(hx280enc->dev);
+ enable_irq(hx280enc->irq);
+ mutex_unlock(&hx280enc->dev_mutex);
+ //spin_unlock_irq(&owner_lock);
+ return 0;
+}
+
+#endif
+
+/* the device's mmap method. The VFS has kindly prepared the process's
+ * vm_area_struct for us, so we examine this to see what was requested.
+ */
+
+static int hx280enc_mmap(struct file *filp, struct vm_area_struct *vm)
+{
+#ifdef VSI
+ int result = -EINVAL;
+
+ result = -EINVAL;
+ vma->vm_ops = &hx280enc_vm_ops;
+ return result;
+#else
+ if (vm->vm_pgoff == (hx280enc_data.iobaseaddr >> PAGE_SHIFT)) {
+ vm->vm_flags |= VM_IO;
+ vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);
+ PDEBUG("hx280enc mmap: size=0x%lX, page off=0x%lX\n", (vm->vm_end - vm->vm_start), vm->vm_pgoff);
+ return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff, vm->vm_end - vm->vm_start,
+ vm->vm_page_prot) ? -EAGAIN : 0;
+ } else {
+ pr_err("invalid map offset :0x%lX\n", vm->vm_pgoff);
+ return -EINVAL;
+ }
+#endif
+}
+
+static int CheckEncIrq(hx280enc_t *dev)
+{
+ unsigned long flags;
+ int rdy = 0;
+
+ spin_lock_irqsave(&owner_lock, flags);
+
+ if (dev->irq_received) {
+ /* reset the wait condition(s) */
+ PDEBUG("check irq ready\n");
+ dev->irq_received = 0;
+ rdy = 1;
+ }
+
+ spin_unlock_irqrestore(&owner_lock, flags);
+ //printk("rdy=%d\n",rdy);
+
+ return rdy;
+}
+
+unsigned int WaitEncReady(hx280enc_t *dev)
+{
+ PDEBUG("WaitEncReady\n");
+
+ if (wait_event_interruptible(enc_wait_queue, CheckEncIrq(dev))) {
+ PDEBUG("ENC wait_event_interruptible interrupted\n");
+ return -ERESTARTSYS;
+ }
+
+ return 0;
+}
+
+int CheckCoreOccupation(hx280enc_t *dev)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&owner_lock, flags);
+ if (!dev->is_reserved) {
+ dev->is_reserved = 1;
+ dev->pid = current->pid;
+ ret = 1;
+ PDEBUG("CheckCoreOccupation pid=%d\n", dev->pid);
+ }
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ return ret;
+}
+
+int GetWorkableCore(hx280enc_t *dev)
+{
+ int ret = 0;
+
+ PDEBUG("GetWorkableCore\n");
+
+ if (dev->is_valid && CheckCoreOccupation(dev))
+ ret = 1;
+
+ return ret;
+}
+
+long ReserveEncoder(hx280enc_t *dev)
+{
+ /* lock a core that has specified core id*/
+ if (wait_event_interruptible(enc_hw_queue, GetWorkableCore(dev) != 0))
+ return -ERESTARTSYS;
+
+ return 0;
+}
+
+void ReleaseEncoder(hx280enc_t *dev)
+{
+ unsigned long flags;
+
+ PDEBUG("ReleaseEncoder\n");
+
+ spin_lock_irqsave(&owner_lock, flags);
+ PDEBUG("relase reseve by pid=%d with current->pid=%d\n", dev->pid, current->pid);
+ if (dev->is_reserved && dev->pid == current->pid) {
+ dev->pid = -1;
+ dev->is_reserved = 0;
+ }
+
+ dev->irq_received = 0;
+ dev->irq_status = 0;
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ wake_up_interruptible_all(&enc_hw_queue);
+
+}
+
+
+static long hx280enc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+
+ PDEBUG("ioctl cmd 0x%X\n", cmd);
+ /*
+ * extract the type and number bitfields, and don't encode
+ * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
+ */
+ if (_IOC_TYPE(cmd) != HX280ENC_IOC_MAGIC)
+ return -ENOTTY;
+ if (_IOC_NR(cmd) > HX280ENC_IOC_MAXNR)
+ return -ENOTTY;
+
+ /*
+ * the direction is a bitmask, and VERIFY_WRITE catches R/W
+ * transfers. `Type' is user-oriented, while
+ * access_ok is kernel-oriented, so the concept of "read" and
+ * "write" is reversed
+ */
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = !access_ok(VERIFY_WRITE, (void *) arg, _IOC_SIZE(cmd));
+ else if (_IOC_DIR(cmd) & _IOC_WRITE)
+ err = !access_ok(VERIFY_READ, (void *) arg, _IOC_SIZE(cmd));
+ if (err)
+ return -EFAULT;
+
+ switch (_IOC_NR(cmd)) {
+ case _IOC_NR(HX280ENC_IOCGHWOFFSET):
+ __put_user(hx280enc_data.iobaseaddr, (unsigned long *) arg);
+ break;
+ case _IOC_NR(HX280ENC_IOCGHWIOSIZE):
+ __put_user(hx280enc_data.iosize, (unsigned int *) arg);
+ break;
+ case _IOC_NR(HX280ENC_IOCH_ENC_RESERVE): {
+ int ret;
+
+ PDEBUG("Reserve ENC Cores\n");
+ ret = ReserveEncoder(&hx280enc_data);
+ return ret;
+ }
+ case _IOC_NR(HX280ENC_IOCH_ENC_RELEASE):
+ PDEBUG("Release ENC Core\n");
+ ReleaseEncoder(&hx280enc_data);
+ break;
+ case _IOC_NR(HX280ENC_IOCG_CORE_WAIT): {
+ int ret;
+
+ ret = WaitEncReady(&hx280enc_data);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int hx280enc_open(struct inode *inode, struct file *filp)
+{
+ int result = 0;
+ hx280enc_t *dev = &hx280enc_data;
+
+ filp->private_data = (void *) dev;
+
+#ifndef VSI
+ hantro_h1_clk_enable(dev->dev);
+ hantro_h1_power_on_disirq(dev);
+#endif
+
+ PDEBUG("dev opened\n");
+ return result;
+}
+
+static int hx280enc_release(struct inode *inode, struct file *filp)
+{
+ hx280enc_t *dev = (hx280enc_t *) filp->private_data;
+ unsigned long flags;
+#ifdef HX280ENC_DEBUG
+ dump_regs((unsigned long) dev); /* dump the regs */
+#endif
+
+ PDEBUG("dev closed\n");
+ spin_lock_irqsave(&owner_lock, flags);
+ if (dev->is_reserved == 1 && dev->pid == current->pid) {
+ dev->pid = -1;
+ dev->is_reserved = 0;
+ dev->irq_received = 0;
+ dev->irq_status = 0;
+ PDEBUG("release reserved core\n");
+ }
+ spin_unlock_irqrestore(&owner_lock, flags);
+ wake_up_interruptible_all(&enc_hw_queue);
+
+#ifndef VSI
+ pm_runtime_put_sync(hantro_h1_dev);
+ hantro_h1_clk_disable(hantro_h1_dev);
+#endif
+
+ return 0;
+}
+
+static long hx280enc_ioctl32(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ long err = 0;
+#define HX280ENC_IOCTL32(err, filp, cmd, arg) { \
+ mm_segment_t old_fs = get_fs(); \
+ set_fs(KERNEL_DS); \
+ err = hx280enc_ioctl(filp, cmd, arg); \
+ if (err) \
+ return err; \
+ set_fs(old_fs); \
+}
+
+union {
+ unsigned long kux;
+ unsigned int kui;
+} karg;
+ void __user *up = compat_ptr(arg);
+
+ switch (_IOC_NR(cmd)) {
+ case _IOC_NR(HX280ENC_IOCGHWOFFSET):
+ err = get_user(karg.kux, (s32 __user *)up);
+ if (err)
+ return err;
+ HX280ENC_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+ err = put_user(((s32)karg.kux), (s32 __user *)up);
+ break;
+ case _IOC_NR(HX280ENC_IOCGHWIOSIZE):
+ err = get_user(karg.kui, (s32 __user *)up);
+ if (err)
+ return err;
+ HX280ENC_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+ err = put_user(((s32)karg.kui), (s32 __user *)up);
+ break;
+ case _IOC_NR(HX280ENC_IOCH_ENC_RESERVE): {
+ int ret;
+ PDEBUG("Reserve ENC Cores\n");
+ ret = ReserveEncoder(&hx280enc_data);
+ return ret;
+ }
+ case _IOC_NR(HX280ENC_IOCH_ENC_RELEASE): {
+ PDEBUG("Release ENC Core\n");
+ ReleaseEncoder(&hx280enc_data);
+ break;
+ }
+ case _IOC_NR(HX280ENC_IOCG_CORE_WAIT): {
+ int ret;
+ ret = WaitEncReady(&hx280enc_data);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+/* VFS methods */
+static struct file_operations hx280enc_fops = {
+ .owner = THIS_MODULE,
+ .open = hx280enc_open,
+ .release = hx280enc_release,
+ .unlocked_ioctl = hx280enc_ioctl,
+ .fasync = NULL,
+ .mmap = hx280enc_mmap,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = hx280enc_ioctl32,
+#endif
+};
+
+#ifndef VSI
+static int hx280enc_init(void)
+#else
+static int __init hx280enc_init(void)
+#endif
+{
+ int result;
+
+ PDEBUG(KERN_INFO "hx280enc: module init - base_port=0x%08lx irq=%i\n",
+ base_port, irq);
+
+ hx280enc_data.iobaseaddr = base_port;
+ hx280enc_data.iosize = ENC_IO_SIZE;
+ hx280enc_data.irq = irq;
+ hx280enc_data.async_queue = NULL;
+ hx280enc_data.hwregs = NULL;
+
+ result = register_chrdev(hx280enc_major, "hx280enc", &hx280enc_fops);
+ if (result < 0) {
+ PDEBUG(KERN_INFO "hx280enc: unable to get major <%d>\n", hx280enc_major);
+ return result;
+ } else if (result != 0) /* this is for dynamic major */
+ hx280enc_major = result;
+
+ result = ReserveIO();
+ if (result < 0)
+ goto err;
+
+ ResetAsic(&hx280enc_data); /* reset hardware */
+
+ /* get the IRQ line */
+ if (irq != -1) {
+ result = request_irq(irq, hx280enc_isr,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
+ SA_INTERRUPT | SA_SHIRQ,
+#else
+ //IRQF_DISABLED | IRQF_SHARED,
+ IRQF_SHARED,
+#endif
+ "hx280enc", (void *) &hx280enc_data);
+ if (result == -EINVAL) {
+ PDEBUG(KERN_ERR "hx280enc: Bad irq number or handler\n");
+ ReleaseIO();
+ goto err;
+ } else if (result == -EBUSY) {
+ PDEBUG(KERN_ERR "hx280enc: IRQ <%d> busy, change your config\n",
+ hx280enc_data.irq);
+ ReleaseIO();
+ goto err;
+ }
+ } else
+ PDEBUG(KERN_INFO "hx280enc: IRQ not in use!\n");
+ irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
+
+ pr_info("hx280enc: module inserted. Major <%d>\n", hx280enc_major);
+ return 0;
+
+err:
+ unregister_chrdev(hx280enc_major, "hx280enc");
+ PDEBUG(KERN_ERR "hx280enc: module not inserted\n");
+ return result;
+}
+
+#ifndef VSI
+static void hx280enc_cleanup(void)
+#else
+static void __exit hx280enc_cleanup(void)
+#endif
+{
+ writel(0, hx280enc_data.hwregs + 0x38); /* disable HW */
+ writel(0, hx280enc_data.hwregs + 0x04); /* clear enc IRQ */
+
+ /* free the encoder IRQ */
+ if (hx280enc_data.irq != -1)
+ free_irq(hx280enc_data.irq, (void *) &hx280enc_data);
+
+ ReleaseIO();
+ unregister_chrdev(hx280enc_major, "hx280enc");
+
+ PDEBUG(KERN_INFO "hx280enc: module removed\n");
+}
+
+#ifdef VSI
+module_init(hx280enc_init);
+module_exit(hx280enc_cleanup);
+#endif
+static int ReserveIO(void)
+{
+ long int hwid;
+
+ if (!request_mem_region(hx280enc_data.iobaseaddr, hx280enc_data.iosize, "hx280enc")) {
+ PDEBUG(KERN_INFO "hx280enc: failed to reserve HW regs\n");
+ return -EBUSY;
+ }
+ hx280enc_data.hwregs = (volatile u8 *) ioremap_nocache(hx280enc_data.iobaseaddr, hx280enc_data.iosize);
+ if (hx280enc_data.hwregs == NULL) {
+ PDEBUG(KERN_INFO "hx280enc: failed to ioremap HW regs\n");
+ ReleaseIO();
+ return -EBUSY;
+ }
+
+ hwid = readl(hx280enc_data.hwregs);
+
+ /* check for encoder HW ID */
+ if ((((hwid >> 16) & 0xFFFF) != ((ENC_HW_ID1 >> 16) & 0xFFFF)) &&
+ (((hwid >> 16) & 0xFFFF) != ((ENC_HW_ID2 >> 16) & 0xFFFF)) &&
+ (((hwid >> 16) & 0xFFFF) != ((ENC_HW_ID3 >> 16) & 0xFFFF)) &&
+ (((hwid >> 16) & 0xFFFF) != ((ENC_HW_ID4 >> 16) & 0xFFFF)) &&
+ (((hwid >> 16) & 0xFFFF) != ((ENC_HW_ID5 >> 16) & 0xFFFF))) {
+ PDEBUG(KERN_ERR "hx280enc: HW not found at 0x%08lx\n", hx280enc_data.iobaseaddr);
+#ifdef HX280ENC_DEBUG
+ dump_regs((unsigned long) &hx280enc_data);
+#endif
+ ReleaseIO();
+ return -EBUSY;
+ }
+
+ hx280enc_data.hw_id = hwid;
+ hx280enc_data.is_valid = 1;
+
+ PDEBUG(KERN_INFO "hx280enc: HW at base <0x%08lx> with ID <0x%08lx>\n", hx280enc_data.iobaseaddr, hwid);
+ return 0;
+}
+
+static void ReleaseIO(void)
+{
+ if (hx280enc_data.is_valid == 0)
+ return;
+ if (hx280enc_data.hwregs)
+ iounmap((void *) hx280enc_data.hwregs);
+ release_mem_region(hx280enc_data.iobaseaddr, hx280enc_data.iosize);
+}
+
+irqreturn_t hx280enc_isr(int irq, void *dev_id)
+{
+ hx280enc_t *dev = (hx280enc_t *) dev_id;
+ u32 irq_status;
+ unsigned long flags;
+ u32 is_write1_clr;
+
+ spin_lock_irqsave(&owner_lock, flags);
+ if (!dev->is_reserved) {
+ spin_unlock_irqrestore(&owner_lock, flags);
+ return IRQ_HANDLED;
+ }
+ spin_unlock_irqrestore(&owner_lock, flags);
+ irq_status = readl(dev->hwregs + 0x04);
+
+ /* BASE_HWFuse2 = 0x4a0; HWCFGIrqClearSupport = 0x00800000 */
+ is_write1_clr = (readl(dev->hwregs + 0x4a0) & 0x00800000);
+ if (irq_status & 0x01) {
+ /* clear enc IRQ and slice ready interrupt bit */
+ if (is_write1_clr)
+ writel(irq_status & (0x101), dev->hwregs + 0x04);
+ else
+ writel(irq_status & (~0x101), dev->hwregs + 0x04);
+
+ /* Handle slice ready interrupts. The reference implementation
+ * doesn't signal slice ready interrupts to EWL.
+ * The EWL will poll the slices ready register value. */
+ if ((irq_status & 0x1FE) == 0x100) {
+ PDEBUG("Slice ready IRQ handled!\n");
+ return IRQ_HANDLED;
+ }
+
+ spin_lock_irqsave(&owner_lock, flags);
+ dev->irq_received = 1;
+ dev->irq_status = irq_status & (~0x01);
+ spin_unlock_irqrestore(&owner_lock, flags);
+
+ wake_up_interruptible_all(&enc_wait_queue);
+
+ PDEBUG("IRQ handled!\n");
+ return IRQ_HANDLED;
+ } else {
+ PDEBUG("IRQ received, but NOT handled!\n");
+ return IRQ_NONE;
+ }
+}
+
+static void ResetAsic(hx280enc_t *dev)
+{
+ int i;
+
+ if (dev->is_valid == 0)
+ return;
+
+ writel(0, dev->hwregs + 0x38);
+
+ for (i = 4; i < dev->iosize; i += 4)
+ writel(0, dev->hwregs + i);
+}
+
+#ifdef HX280ENC_DEBUG
+static void dump_regs(unsigned long data)
+{
+ hx280enc_t *dev = (hx280enc_t *) data;
+ int i;
+
+ PDEBUG("Reg Dump Start\n");
+ for (i = 0; i < dev->iosize; i += 4)
+ PDEBUG("\toffset %02X = %08X\n", i, readl(dev->hwregs + i));
+ PDEBUG("Reg Dump End\n");
+}
+#endif
+
+
+
+#ifndef VSI
+static int hantro_h1_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ struct device *temp_class;
+ struct resource *res;
+ unsigned long reg_base;
+
+ hantro_h1_dev = &pdev->dev;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs_hantro_h1");
+ if (!res) {
+ pr_err("hantro h1: unable to get vpu base addr\n");
+ return -ENODEV;
+ }
+ reg_base = res->start;
+ if ((ulong)reg_base != base_port) {
+ pr_err("hantro h1: regbase(0x%lX) not equal to expected value(0x%lX)\n", reg_base, base_port);
+ return -ENODEV;
+ }
+
+ irq = platform_get_irq_byname(pdev, "irq_hantro_h1");
+ if (irq < 0) {
+ pr_err("hantro h1: not find valid irq\n");
+ return -ENODEV;
+ }
+
+ hantro_clk_h1 = clk_get(&pdev->dev, "clk_hantro_h1");
+ if (IS_ERR(hantro_clk_h1)) {
+ pr_err("hantro h1: get clock failed, %p\n", hantro_clk_h1);
+ err = -ENXIO;
+ goto error;
+ }
+ hantro_clk_h1_bus = clk_get(&pdev->dev, "clk_hantro_h1_bus");
+ if (IS_ERR(hantro_clk_h1_bus)) {
+ pr_err("hantro h1: get bus clock failed, %p\n", hantro_clk_h1_bus);
+ err = -ENXIO;
+ goto error;
+ }
+
+ PDEBUG("hantro: h1 clock: 0x%lX, 0x%lX\n", clk_get_rate(hantro_clk_h1), clk_get_rate(hantro_clk_h1_bus));
+
+ hantro_h1_clk_enable(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+ hantro_h1_ctrlblk_reset(&pdev->dev);
+
+ err = hx280enc_init();
+ if (0 != err) {
+ pr_err("hantro h1: init failed\n");
+ goto error;
+ }
+
+ hantro_h1_class = class_create(THIS_MODULE, "mxc_hantro_h1");
+ if (IS_ERR(hantro_h1_class)) {
+ err = PTR_ERR(hantro_h1_class);
+ goto error;
+ }
+ temp_class = device_create(hantro_h1_class, NULL, MKDEV(hx280enc_major, 0), NULL, DEVICE_NAME);
+ if (IS_ERR(temp_class)) {
+ err = PTR_ERR(temp_class);
+ goto err_out_class;
+ }
+ hx280enc_data.dev = &pdev->dev;
+ platform_set_drvdata(pdev, &hx280enc_data);
+ mutex_init(&hx280enc_data.dev_mutex);
+
+ goto out;
+
+err_out_class:
+ device_destroy(hantro_h1_class, MKDEV(hx280enc_major, 0));
+ class_destroy(hantro_h1_class);
+error:
+ pr_err("hantro probe failed\n");
+out:
+ pm_runtime_put_sync(&pdev->dev);
+ hantro_h1_clk_disable(&pdev->dev);
+ return err;
+}
+
+static int hantro_h1_dev_remove(struct platform_device *pdev)
+{
+ hantro_h1_clk_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+ if (hx280enc_major > 0) {
+ device_destroy(hantro_h1_class, MKDEV(hx280enc_major, 0));
+ class_destroy(hantro_h1_class);
+ hx280enc_cleanup();
+ hx280enc_major = 0;
+ }
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ hantro_h1_clk_disable(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int hantro_h1_suspend(struct device *dev)
+{
+ pm_runtime_put_sync_suspend(dev); //power off
+ return 0;
+}
+static int hantro_h1_resume(struct device *dev)
+{
+ hx280enc_t *hx280enc = dev_get_drvdata(dev);
+
+ hantro_h1_power_on_disirq(hx280enc);
+ hantro_h1_ctrlblk_reset(dev);
+ return 0;
+}
+static int hantro_h1_runtime_suspend(struct device *dev)
+{
+ //release_bus_freq(BUS_FREQ_HIGH);
+ return 0;
+}
+
+static int hantro_h1_runtime_resume(struct device *dev)
+{
+ //request_bus_freq(BUS_FREQ_HIGH);
+ hantro_h1_ctrlblk_reset(dev);
+ return 0;
+}
+
+static const struct dev_pm_ops hantro_h1_pm_ops = {
+ SET_RUNTIME_PM_OPS(hantro_h1_runtime_suspend, hantro_h1_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(hantro_h1_suspend, hantro_h1_resume)
+};
+#endif //CONFIG_PM
+
+static const struct of_device_id hantro_h1_of_match[] = {
+ { .compatible = "nxp,imx8mm-hantro-h1", },
+ {/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, vpu_of_match);
+
+
+static struct platform_driver mxchantro_h1_driver = {
+ .driver = {
+ .name = "mxc_hantro_h1",
+ .of_match_table = hantro_h1_of_match,
+#ifdef CONFIG_PM
+ .pm = &hantro_h1_pm_ops,
+#endif
+ },
+ .probe = hantro_h1_probe,
+ .remove = hantro_h1_dev_remove,
+};
+
+static int __init hantro_h1_init(void)
+{
+ int ret = platform_driver_register(&mxchantro_h1_driver);
+
+ return ret;
+}
+
+static void __exit hantro_h1_exit(void)
+{
+ //clk_put(hantro_clk);
+ platform_driver_unregister(&mxchantro_h1_driver);
+}
+
+module_init(hantro_h1_init);
+module_exit(hantro_h1_exit);
+
+#endif
+
diff --git a/drivers/mxc/hantro_845_h1/hx280enc.h b/drivers/mxc/hantro_845_h1/hx280enc.h
new file mode 100755
index 000000000000..d465c25f9f66
--- /dev/null
+++ b/drivers/mxc/hantro_845_h1/hx280enc.h
@@ -0,0 +1,79 @@
+ /*****************************************************************************
+ * Encoder device driver (kernel module header)
+ *
+ * Copyright (C) 2012 Google Finland Oy.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+--------------------------------------------------------------------------------
+--
+-- Abstract : 6280/7280/8270/8290/H1 Encoder device driver (kernel module)
+--
+*****************************************************************************/
+#ifndef _UAPI_HX280ENC_H_
+#define _UAPI_HX280ENC_H_
+#include <linux/ioctl.h> /* needed for the _IOW etc stuff used later */
+
+/*
+ * Macros to help debugging
+ */
+
+#undef PDEBUG /* undef it, just in case */
+#ifdef HX280ENC_DEBUG
+# ifdef __KERNEL__
+ /* This one if debugging is on, and kernel space */
+# define PDEBUG(fmt, args...) printk(KERN_INFO "hmp4e: " fmt, ## args)
+# else
+ /* This one for user space */
+# define PDEBUG(fmt, args...) printf(__FILE__ ":%d: " fmt, __LINE__, ## args)
+# endif
+#else
+# define PDEBUG(fmt, args...) /* not debugging: nothing */
+#endif
+
+/*
+ * Ioctl definitions
+ */
+
+/* Use 'k' as magic number */
+#define HX280ENC_IOC_MAGIC 'k'
+/*
+ * S means "Set" through a ptr,
+ * T means "Tell" directly with the argument value
+ * G means "Get": reply by setting through a pointer
+ * Q means "Query": response is on the return value
+ * X means "eXchange": G and S atomically
+ * H means "sHift": T and Q atomically
+ */
+ /*
+ * #define HX280ENC_IOCGBUFBUSADDRESS _IOR(HX280ENC_IOC_MAGIC, 1, unsigned long *)
+ * #define HX280ENC_IOCGBUFSIZE _IOR(HX280ENC_IOC_MAGIC, 2, unsigned int *)
+ */
+#define HX280ENC_IOCGHWOFFSET _IOR(HX280ENC_IOC_MAGIC, 3, unsigned long *)
+#define HX280ENC_IOCGHWIOSIZE _IOR(HX280ENC_IOC_MAGIC, 4, unsigned int *)
+#define HX280ENC_IOC_CLI _IO(HX280ENC_IOC_MAGIC, 5)
+#define HX280ENC_IOC_STI _IO(HX280ENC_IOC_MAGIC, 6)
+#define HX280ENC_IOCXVIRT2BUS _IOWR(HX280ENC_IOC_MAGIC, 7, unsigned long *)
+
+#define HX280ENC_IOCHARDRESET _IO(HX280ENC_IOC_MAGIC, 8) /* debugging tool */
+#define HX280ENC_IOCGSRAMOFFSET _IOR(HX280ENC_IOC_MAGIC, 9, unsigned long *)
+#define HX280ENC_IOCGSRAMEIOSIZE _IOR(HX280ENC_IOC_MAGIC, 10, unsigned int *)
+
+#define HX280ENC_IOCH_ENC_RESERVE _IOR(HX280ENC_IOC_MAGIC, 11, unsigned int *)
+#define HX280ENC_IOCH_ENC_RELEASE _IOR(HX280ENC_IOC_MAGIC, 12, unsigned int *)
+#define HX280ENC_IOCG_CORE_WAIT _IOR(HX280ENC_IOC_MAGIC, 13, unsigned int *)
+#define HX280ENC_IOC_MAXNR 30
+
+#endif /* !_UAPI_HX280ENC_H_ */
diff --git a/drivers/mxc/hdmi-cec/Kconfig b/drivers/mxc/hdmi-cec/Kconfig
new file mode 100644
index 000000000000..c0be06854e27
--- /dev/null
+++ b/drivers/mxc/hdmi-cec/Kconfig
@@ -0,0 +1,11 @@
+
+menu "MXC HDMI CEC (Consumer Electronics Control) support"
+
+config MXC_HDMI_CEC
+ tristate "Support for MXC HDMI CEC (Consumer Electronics Control)"
+ depends on MFD_MXC_HDMI
+ depends on FB_MXC_HDMI
+ help
+ The HDMI CEC device implement low level protocol on i.MX6x platforms.
+
+endmenu
diff --git a/drivers/mxc/hdmi-cec/Makefile b/drivers/mxc/hdmi-cec/Makefile
new file mode 100644
index 000000000000..07248b25b033
--- /dev/null
+++ b/drivers/mxc/hdmi-cec/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MXC_HDMI_CEC) += mxc_hdmi-cec.o
diff --git a/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c b/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c
new file mode 100644
index 000000000000..75c01972e584
--- /dev/null
+++ b/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c
@@ -0,0 +1,665 @@
+/*
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file mxc_hdmi-cec.c
+ *
+ * @brief HDMI CEC system initialization and file operation implementation
+ *
+ * @ingroup HDMI
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/fsl_devices.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+#include <linux/sizes.h>
+
+#include <linux/console.h>
+#include <linux/types.h>
+#include <linux/mfd/mxc-hdmi-core.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <video/mxc_hdmi.h>
+
+#include "mxc_hdmi-cec.h"
+
+
+#define MAX_MESSAGE_LEN 17
+
+#define MESSAGE_TYPE_RECEIVE_SUCCESS 1
+#define MESSAGE_TYPE_NOACK 2
+#define MESSAGE_TYPE_DISCONNECTED 3
+#define MESSAGE_TYPE_CONNECTED 4
+#define MESSAGE_TYPE_SEND_SUCCESS 5
+
+
+struct hdmi_cec_priv {
+ int receive_error;
+ int send_error;
+ u8 Logical_address;
+ bool cec_state;
+ u8 last_msg[MAX_MESSAGE_LEN];
+ u8 msg_len;
+ u8 latest_cec_stat;
+ spinlock_t irq_lock;
+ struct delayed_work hdmi_cec_work;
+ struct mutex lock;
+};
+
+struct hdmi_cec_event {
+ int event_type;
+ int msg_len;
+ u8 msg[MAX_MESSAGE_LEN];
+ struct list_head list;
+};
+
+static LIST_HEAD(head);
+
+static int hdmi_cec_major;
+static struct class *hdmi_cec_class;
+static struct hdmi_cec_priv hdmi_cec_data;
+static u8 open_count;
+
+static wait_queue_head_t hdmi_cec_queue;
+static irqreturn_t mxc_hdmi_cec_isr(int irq, void *data)
+{
+ struct hdmi_cec_priv *hdmi_cec = data;
+ u8 cec_stat = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hdmi_cec->irq_lock, flags);
+
+ hdmi_writeb(0x7f, HDMI_IH_MUTE_CEC_STAT0);
+
+ cec_stat = hdmi_readb(HDMI_IH_CEC_STAT0);
+ hdmi_writeb(cec_stat, HDMI_IH_CEC_STAT0);
+
+ if ((cec_stat & (HDMI_IH_CEC_STAT0_ERROR_INIT | \
+ HDMI_IH_CEC_STAT0_NACK | HDMI_IH_CEC_STAT0_EOM | \
+ HDMI_IH_CEC_STAT0_DONE)) == 0) {
+ spin_unlock_irqrestore(&hdmi_cec->irq_lock, flags);
+ return IRQ_HANDLED;
+ }
+
+ pr_debug("HDMI CEC interrupt received\n");
+ hdmi_cec->latest_cec_stat = cec_stat;
+
+ schedule_delayed_work(&(hdmi_cec->hdmi_cec_work), msecs_to_jiffies(20));
+
+ spin_unlock_irqrestore(&hdmi_cec->irq_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+void mxc_hdmi_cec_handle(u16 cec_stat)
+{
+ u8 val = 0, i = 0;
+ struct hdmi_cec_event *event = NULL;
+
+ /* The current transmission is successful (for initiator only). */
+ if (!open_count)
+ return;
+
+ if (cec_stat & HDMI_IH_CEC_STAT0_DONE) {
+
+ event = vmalloc(sizeof(struct hdmi_cec_event));
+ if (NULL == event) {
+ pr_err("%s: Not enough memory!\n", __func__);
+ return;
+ }
+
+ memset(event, 0, sizeof(struct hdmi_cec_event));
+ event->event_type = MESSAGE_TYPE_SEND_SUCCESS;
+
+ mutex_lock(&hdmi_cec_data.lock);
+ list_add_tail(&event->list, &head);
+ mutex_unlock(&hdmi_cec_data.lock);
+
+ wake_up(&hdmi_cec_queue);
+ }
+
+ /* EOM is detected so that the received data is ready
+ * in the receiver data buffer
+ */
+ if (cec_stat & HDMI_IH_CEC_STAT0_EOM) {
+
+ hdmi_writeb(0x02, HDMI_IH_CEC_STAT0);
+
+ event = vmalloc(sizeof(struct hdmi_cec_event));
+ if (NULL == event) {
+ pr_err("%s: Not enough memory!\n", __func__);
+ return;
+ }
+ memset(event, 0, sizeof(struct hdmi_cec_event));
+
+ event->msg_len = hdmi_readb(HDMI_CEC_RX_CNT);
+ if (!event->msg_len) {
+ pr_err("%s: Invalid CEC message length!\n", __func__);
+ vfree(event);
+ return;
+ }
+ event->event_type = MESSAGE_TYPE_RECEIVE_SUCCESS;
+
+ for (i = 0; i < event->msg_len; i++)
+ event->msg[i] = hdmi_readb(HDMI_CEC_RX_DATA0+i);
+ hdmi_writeb(0x0, HDMI_CEC_LOCK);
+
+ mutex_lock(&hdmi_cec_data.lock);
+ list_add_tail(&event->list, &head);
+ mutex_unlock(&hdmi_cec_data.lock);
+
+ wake_up(&hdmi_cec_queue);
+ }
+
+ /* An error is detected on cec line (for initiator only). */
+ if (cec_stat & HDMI_IH_CEC_STAT0_ERROR_INIT) {
+
+ mutex_lock(&hdmi_cec_data.lock);
+ hdmi_cec_data.send_error++;
+ if (hdmi_cec_data.send_error > 5) {
+ pr_err("%s:Re-transmission is attempted more than 5 times!\n",
+ __func__);
+ hdmi_cec_data.send_error = 0;
+ mutex_unlock(&hdmi_cec_data.lock);
+ return;
+ }
+
+ for (i = 0; i < hdmi_cec_data.msg_len; i++) {
+ hdmi_writeb(hdmi_cec_data.last_msg[i],
+ HDMI_CEC_TX_DATA0 + i);
+ }
+ hdmi_writeb(hdmi_cec_data.msg_len, HDMI_CEC_TX_CNT);
+
+ val = hdmi_readb(HDMI_CEC_CTRL);
+ val |= 0x01;
+ hdmi_writeb(val, HDMI_CEC_CTRL);
+ mutex_unlock(&hdmi_cec_data.lock);
+ }
+
+ /* A frame is not acknowledged in a directly addressed message.
+ * Or a frame is negatively acknowledged in
+ * a broadcast message (for initiator only).
+ */
+ if (cec_stat & HDMI_IH_CEC_STAT0_NACK) {
+ event = vmalloc(sizeof(struct hdmi_cec_event));
+ if (NULL == event) {
+ pr_err("%s: Not enough memory\n", __func__);
+ return;
+ }
+ memset(event, 0, sizeof(struct hdmi_cec_event));
+ event->event_type = MESSAGE_TYPE_NOACK;
+
+ mutex_lock(&hdmi_cec_data.lock);
+ list_add_tail(&event->list, &head);
+ mutex_unlock(&hdmi_cec_data.lock);
+
+ wake_up(&hdmi_cec_queue);
+ }
+
+ /* An error is notified by a follower.
+ * Abnormal logic data bit error (for follower).
+ */
+ if (cec_stat & HDMI_IH_CEC_STAT0_ERROR_FOLL) {
+ hdmi_cec_data.receive_error++;
+ }
+
+ /* HDMI cable connected */
+ if (cec_stat & 0x80) {
+ event = vmalloc(sizeof(struct hdmi_cec_event));
+ if (NULL == event) {
+ pr_err("%s: Not enough memory\n", __func__);
+ return;
+ }
+ memset(event, 0, sizeof(struct hdmi_cec_event));
+ event->event_type = MESSAGE_TYPE_CONNECTED;
+
+ mutex_lock(&hdmi_cec_data.lock);
+ list_add_tail(&event->list, &head);
+ mutex_unlock(&hdmi_cec_data.lock);
+
+ wake_up(&hdmi_cec_queue);
+ }
+
+ /* HDMI cable disconnected */
+ if (cec_stat & 0x100) {
+ event = vmalloc(sizeof(struct hdmi_cec_event));
+ if (NULL == event) {
+ pr_err("%s: Not enough memory!\n", __func__);
+ return;
+ }
+ memset(event, 0, sizeof(struct hdmi_cec_event));
+ event->event_type = MESSAGE_TYPE_DISCONNECTED;
+
+ mutex_lock(&hdmi_cec_data.lock);
+ list_add_tail(&event->list, &head);
+ mutex_unlock(&hdmi_cec_data.lock);
+
+ wake_up(&hdmi_cec_queue);
+ }
+
+ return;
+}
+EXPORT_SYMBOL(mxc_hdmi_cec_handle);
+
+static void mxc_hdmi_cec_worker(struct work_struct *work)
+{
+ u8 val;
+
+ mxc_hdmi_cec_handle(hdmi_cec_data.latest_cec_stat);
+ val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL |
+ HDMI_IH_CEC_STAT0_ARB_LOST;
+ hdmi_writeb(val, HDMI_IH_MUTE_CEC_STAT0);
+}
+
+/*!
+ * @brief open function for vpu file operation
+ *
+ * @return 0 on success or negative error code on error
+ */
+static int hdmi_cec_open(struct inode *inode, struct file *filp)
+{
+ mutex_lock(&hdmi_cec_data.lock);
+ if (open_count) {
+ mutex_unlock(&hdmi_cec_data.lock);
+ return -EBUSY;
+ }
+
+ open_count = 1;
+ filp->private_data = (void *)(&hdmi_cec_data);
+ hdmi_cec_data.Logical_address = 15;
+ hdmi_cec_data.cec_state = false;
+ mutex_unlock(&hdmi_cec_data.lock);
+
+ return 0;
+}
+
+static ssize_t hdmi_cec_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct hdmi_cec_event *event = NULL;
+
+ pr_debug("function : %s\n", __func__);
+ if (!open_count)
+ return -ENODEV;
+
+ mutex_lock(&hdmi_cec_data.lock);
+ if (false == hdmi_cec_data.cec_state) {
+ mutex_unlock(&hdmi_cec_data.lock);
+ return -EACCES;
+ }
+ mutex_unlock(&hdmi_cec_data.lock);
+
+ /* delete from list */
+ mutex_lock(&hdmi_cec_data.lock);
+ if (list_empty(&head)) {
+ mutex_unlock(&hdmi_cec_data.lock);
+ return -EACCES;
+ }
+ event = list_first_entry(&head, struct hdmi_cec_event, list);
+ list_del(&event->list);
+ mutex_unlock(&hdmi_cec_data.lock);
+
+ if (copy_to_user(buf, event,
+ sizeof(struct hdmi_cec_event) - sizeof(struct list_head))) {
+ vfree(event);
+ return -EFAULT;
+ }
+ vfree(event);
+
+ return sizeof(struct hdmi_cec_event);
+}
+
+static ssize_t hdmi_cec_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int ret = 0 , i = 0;
+ u8 msg[MAX_MESSAGE_LEN];
+ u8 msg_len = 0, val = 0;
+
+ pr_debug("function : %s\n", __func__);
+ if (!open_count)
+ return -ENODEV;
+
+ mutex_lock(&hdmi_cec_data.lock);
+ if (false == hdmi_cec_data.cec_state) {
+ mutex_unlock(&hdmi_cec_data.lock);
+ return -EACCES;
+ }
+ mutex_unlock(&hdmi_cec_data.lock);
+
+ if (count > MAX_MESSAGE_LEN)
+ return -EINVAL;
+
+ mutex_lock(&hdmi_cec_data.lock);
+ hdmi_cec_data.send_error = 0;
+ memset(&msg, 0, MAX_MESSAGE_LEN);
+ ret = copy_from_user(&msg, buf, count);
+ if (ret) {
+ ret = -EACCES;
+ goto end;
+ }
+
+ msg_len = count;
+ hdmi_writeb(msg_len, HDMI_CEC_TX_CNT);
+ for (i = 0; i < msg_len; i++) {
+ hdmi_writeb(msg[i], HDMI_CEC_TX_DATA0+i);
+ }
+
+ val = hdmi_readb(HDMI_CEC_CTRL);
+ val |= 0x01;
+ hdmi_writeb(val, HDMI_CEC_CTRL);
+ memcpy(hdmi_cec_data.last_msg, msg, msg_len);
+ hdmi_cec_data.msg_len = msg_len;
+
+ i = 0;
+ val = hdmi_readb(HDMI_CEC_CTRL);
+ while ((val & 0x01) == 0x1) {
+ msleep(50);
+ i++;
+ if (i > 3) {
+ ret = -EIO;
+ goto end;
+ }
+ val = hdmi_readb(HDMI_CEC_CTRL);
+ }
+
+end:
+ mutex_unlock(&hdmi_cec_data.lock);
+
+ return ret;
+}
+
+/*!
+ * @brief IO ctrl function for vpu file operation
+ * @param cmd IO ctrl command
+ * @return 0 on success or negative error code on error
+ */
+static long hdmi_cec_ioctl(struct file *filp, u_int cmd,
+ u_long arg)
+{
+ int ret = 0, status = 0;
+ u8 val = 0, msg = 0;
+ struct mxc_edid_cfg hdmi_edid_cfg;
+
+ pr_debug("function : %s\n", __func__);
+ if (!open_count)
+ return -ENODEV;
+
+ switch (cmd) {
+ case HDMICEC_IOC_SETLOGICALADDRESS:
+ mutex_lock(&hdmi_cec_data.lock);
+ if (false == hdmi_cec_data.cec_state) {
+ mutex_unlock(&hdmi_cec_data.lock);
+ return -EACCES;
+ }
+
+ hdmi_cec_data.Logical_address = (u8)arg;
+
+ if (hdmi_cec_data.Logical_address <= 7) {
+ val = 1 << hdmi_cec_data.Logical_address;
+ hdmi_writeb(val, HDMI_CEC_ADDR_L);
+ hdmi_writeb(0, HDMI_CEC_ADDR_H);
+ } else if (hdmi_cec_data.Logical_address > 7 &&
+ hdmi_cec_data.Logical_address <= 15) {
+ val = 1 << (hdmi_cec_data.Logical_address - 8);
+ hdmi_writeb(val, HDMI_CEC_ADDR_H);
+ hdmi_writeb(0, HDMI_CEC_ADDR_L);
+ } else {
+ ret = -EINVAL;
+ }
+
+ /* Send Polling message with same source
+ * and destination address
+ */
+ if (0 == ret && 15 != hdmi_cec_data.Logical_address) {
+ msg = (hdmi_cec_data.Logical_address << 4) |
+ hdmi_cec_data.Logical_address;
+ hdmi_writeb(1, HDMI_CEC_TX_CNT);
+ hdmi_writeb(msg, HDMI_CEC_TX_DATA0);
+
+ val = hdmi_readb(HDMI_CEC_CTRL);
+ val |= 0x01;
+ hdmi_writeb(val, HDMI_CEC_CTRL);
+ }
+
+ mutex_unlock(&hdmi_cec_data.lock);
+ break;
+
+ case HDMICEC_IOC_STARTDEVICE:
+ val = hdmi_readb(HDMI_MC_CLKDIS);
+ val &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE;
+ hdmi_writeb(val, HDMI_MC_CLKDIS);
+
+ hdmi_writeb(0x02, HDMI_CEC_CTRL);
+
+ val = HDMI_IH_CEC_STAT0_ERROR_INIT | HDMI_IH_CEC_STAT0_NACK |
+ HDMI_IH_CEC_STAT0_EOM | HDMI_IH_CEC_STAT0_DONE;
+ hdmi_writeb(val, HDMI_CEC_POLARITY);
+
+ val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL |
+ HDMI_IH_CEC_STAT0_ARB_LOST;
+ hdmi_writeb(val, HDMI_CEC_MASK);
+ hdmi_writeb(val, HDMI_IH_MUTE_CEC_STAT0);
+
+ mutex_lock(&hdmi_cec_data.lock);
+ hdmi_cec_data.cec_state = true;
+ mutex_unlock(&hdmi_cec_data.lock);
+ break;
+
+ case HDMICEC_IOC_STOPDEVICE:
+ hdmi_writeb(0x10, HDMI_CEC_CTRL);
+
+ val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL |
+ HDMI_IH_CEC_STAT0_ERROR_INIT | HDMI_IH_CEC_STAT0_ARB_LOST |
+ HDMI_IH_CEC_STAT0_NACK | HDMI_IH_CEC_STAT0_EOM |
+ HDMI_IH_CEC_STAT0_DONE;
+ hdmi_writeb(val, HDMI_CEC_MASK);
+ hdmi_writeb(val, HDMI_IH_MUTE_CEC_STAT0);
+
+ hdmi_writeb(0x0, HDMI_CEC_POLARITY);
+
+ val = hdmi_readb(HDMI_MC_CLKDIS);
+ val |= HDMI_MC_CLKDIS_CECCLK_DISABLE;
+ hdmi_writeb(val, HDMI_MC_CLKDIS);
+
+ mutex_lock(&hdmi_cec_data.lock);
+ hdmi_cec_data.cec_state = false;
+ mutex_unlock(&hdmi_cec_data.lock);
+ break;
+
+ case HDMICEC_IOC_GETPHYADDRESS:
+ hdmi_get_edid_cfg(&hdmi_edid_cfg);
+ status = copy_to_user((void __user *)arg,
+ &hdmi_edid_cfg.physical_address,
+ 4*sizeof(u8));
+ if (status)
+ ret = -EFAULT;
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+* @brief Release function for vpu file operation
+* @return 0 on success or negative error code on error
+*/
+static int hdmi_cec_release(struct inode *inode, struct file *filp)
+{
+ mutex_lock(&hdmi_cec_data.lock);
+
+ if (open_count) {
+ open_count = 0;
+ hdmi_cec_data.cec_state = false;
+ hdmi_cec_data.Logical_address = 15;
+ }
+
+ mutex_unlock(&hdmi_cec_data.lock);
+
+ return 0;
+}
+
+static unsigned int hdmi_cec_poll(struct file *file, poll_table *wait)
+{
+ unsigned int mask = 0;
+
+ pr_debug("function : %s\n", __func__);
+
+ if (!open_count)
+ return -ENODEV;
+
+ if (false == hdmi_cec_data.cec_state)
+ return -EACCES;
+
+ poll_wait(file, &hdmi_cec_queue, wait);
+
+ if (!list_empty(&head))
+ mask |= (POLLIN | POLLRDNORM);
+
+ return mask;
+}
+
+const struct file_operations hdmi_cec_fops = {
+ .owner = THIS_MODULE,
+ .read = hdmi_cec_read,
+ .write = hdmi_cec_write,
+ .open = hdmi_cec_open,
+ .unlocked_ioctl = hdmi_cec_ioctl,
+ .release = hdmi_cec_release,
+ .poll = hdmi_cec_poll,
+};
+
+static int hdmi_cec_dev_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ struct device *temp_class;
+ struct resource *res;
+ struct pinctrl *pinctrl;
+ int irq = platform_get_irq(pdev, 0);
+
+ hdmi_cec_major = register_chrdev(hdmi_cec_major,
+ "mxc_hdmi_cec", &hdmi_cec_fops);
+ if (hdmi_cec_major < 0) {
+ dev_err(&pdev->dev, "hdmi_cec: unable to get a major for HDMI CEC\n");
+ err = -EBUSY;
+ goto out;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (unlikely(res == NULL)) {
+ dev_err(&pdev->dev, "hdmi_cec:No HDMI irq line provided\n");
+ goto err_out_chrdev;
+ }
+
+ spin_lock_init(&hdmi_cec_data.irq_lock);
+
+ err = devm_request_irq(&pdev->dev, irq, mxc_hdmi_cec_isr, IRQF_SHARED,
+ dev_name(&pdev->dev), &hdmi_cec_data);
+ if (err < 0) {
+ dev_err(&pdev->dev, "hdmi_cec:Unable to request irq: %d\n", err);
+ goto err_out_chrdev;
+ }
+
+ hdmi_cec_class = class_create(THIS_MODULE, "mxc_hdmi_cec");
+ if (IS_ERR(hdmi_cec_class)) {
+ err = PTR_ERR(hdmi_cec_class);
+ goto err_out_chrdev;
+ }
+
+ temp_class = device_create(hdmi_cec_class, NULL,
+ MKDEV(hdmi_cec_major, 0), NULL, "mxc_hdmi_cec");
+ if (IS_ERR(temp_class)) {
+ err = PTR_ERR(temp_class);
+ goto err_out_class;
+ }
+
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ dev_err(&pdev->dev, "can't get/select CEC pinctrl\n");
+ goto err_out_class;
+ }
+
+ init_waitqueue_head(&hdmi_cec_queue);
+
+ INIT_LIST_HEAD(&head);
+
+ mutex_init(&hdmi_cec_data.lock);
+
+ hdmi_cec_data.Logical_address = 15;
+
+ platform_set_drvdata(pdev, &hdmi_cec_data);
+
+ INIT_DELAYED_WORK(&hdmi_cec_data.hdmi_cec_work, mxc_hdmi_cec_worker);
+
+ dev_info(&pdev->dev, "HDMI CEC initialized\n");
+ goto out;
+
+err_out_class:
+ device_destroy(hdmi_cec_class, MKDEV(hdmi_cec_major, 0));
+ class_destroy(hdmi_cec_class);
+err_out_chrdev:
+ unregister_chrdev(hdmi_cec_major, "mxc_hdmi_cec");
+out:
+ return err;
+}
+
+static int hdmi_cec_dev_remove(struct platform_device *pdev)
+{
+ if (hdmi_cec_major > 0) {
+ device_destroy(hdmi_cec_class, MKDEV(hdmi_cec_major, 0));
+ class_destroy(hdmi_cec_class);
+ unregister_chrdev(hdmi_cec_major, "mxc_hdmi_cec");
+ hdmi_cec_major = 0;
+ }
+ return 0;
+}
+
+static const struct of_device_id imx_hdmi_cec_match[] = {
+ { .compatible = "fsl,imx6q-hdmi-cec", },
+ { .compatible = "fsl,imx6dl-hdmi-cec", },
+ { /* sentinel */ }
+};
+
+static struct platform_driver mxc_hdmi_cec_driver = {
+ .probe = hdmi_cec_dev_probe,
+ .remove = hdmi_cec_dev_remove,
+ .driver = {
+ .name = "mxc_hdmi_cec",
+ .of_match_table = imx_hdmi_cec_match,
+ },
+};
+
+module_platform_driver(mxc_hdmi_cec_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Linux HDMI CEC driver for Freescale i.MX/MXC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mxc_hdmi_cec");
+
diff --git a/drivers/mxc/hdmi-cec/mxc_hdmi-cec.h b/drivers/mxc/hdmi-cec/mxc_hdmi-cec.h
new file mode 100644
index 000000000000..5c402af4d0c3
--- /dev/null
+++ b/drivers/mxc/hdmi-cec/mxc_hdmi-cec.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef _HDMICEC_H_
+#define _HDMICEC_H_
+#include <linux/ioctl.h>
+
+/*
+ * Ioctl definitions
+ */
+
+/* Use 'k' as magic number */
+#define HDMICEC_IOC_MAGIC 'H'
+/*
+ * S means "Set" through a ptr,
+ * T means "Tell" directly with the argument value
+ * G means "Get": reply by setting through a pointer
+ * Q means "Query": response is on the return value
+ * X means "eXchange": G and S atomically
+ * H means "sHift": T and Q atomically
+ */
+#define HDMICEC_IOC_SETLOGICALADDRESS \
+ _IOW(HDMICEC_IOC_MAGIC, 1, unsigned char)
+#define HDMICEC_IOC_STARTDEVICE _IO(HDMICEC_IOC_MAGIC, 2)
+#define HDMICEC_IOC_STOPDEVICE _IO(HDMICEC_IOC_MAGIC, 3)
+#define HDMICEC_IOC_GETPHYADDRESS \
+ _IOR(HDMICEC_IOC_MAGIC, 4, unsigned char[4])
+
+#endif /* !_HDMICEC_H_ */
diff --git a/drivers/mxc/hdp-cec/Kconfig b/drivers/mxc/hdp-cec/Kconfig
new file mode 100644
index 000000000000..7acbc07525cf
--- /dev/null
+++ b/drivers/mxc/hdp-cec/Kconfig
@@ -0,0 +1,5 @@
+config IMX_HDP_CEC
+ bool "Enable IMX HDP CEC support"
+ depends on MEDIA_CEC
+ ---help---
+ When selected the imx hdmi will support the optional HDMI CEC feature.
diff --git a/drivers/mxc/hdp-cec/Makefile b/drivers/mxc/hdp-cec/Makefile
new file mode 100644
index 000000000000..a432aa700990
--- /dev/null
+++ b/drivers/mxc/hdp-cec/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_IMX_HDP_CEC) += imx-hdp-cec.o
diff --git a/drivers/mxc/hdp-cec/imx-hdp-cec.c b/drivers/mxc/hdp-cec/imx-hdp-cec.c
new file mode 100644
index 000000000000..25c2d0c34730
--- /dev/null
+++ b/drivers/mxc/hdp-cec/imx-hdp-cec.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/timer.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+#include <linux/kthread.h>
+#include <media/cec.h>
+#include <soc/imx8/soc.h>
+
+#include "imx-hdp-cec.h"
+
+#define CEC_NAME "hdp-cec"
+
+#define REG_ADDR_OFF 1
+
+#define MAX_LA_IDX 4
+#define MAX_LA_VAL 15
+
+/**
+ * Maximum number of Messages in the RX Buffers.
+ */
+# define CEC_MAX_RX_MSGS 2
+
+#define set_la F_MY_LOG_ADDR0
+#define get_la F_MY_LOG_ADDR0_RD
+#define set_la_valid F_LOG_ADDR_VALID0
+#define get_la_valid F_LOG_ADDR_VALID0_RD
+
+u32 cec_read(struct imx_cec_dev *cec, u32 offset)
+{
+ u32 addr = (offset << 2) + ADDR_HDP_CEC_BASE;
+ u32 value;
+
+ cec->rw->read_reg(cec->mem, addr, &value);
+ return value;
+}
+
+void cec_write(struct imx_cec_dev *cec, u32 offset, u32 value)
+{
+ u32 addr = (offset << 2) + ADDR_HDP_CEC_BASE;
+
+ cec->rw->write_reg(cec->mem, addr, value);
+}
+
+void cec_clear_rx_buffer(struct imx_cec_dev *cec)
+{
+ cec_write(cec, RX_CLEAR_BUF, 1);
+ cec_write(cec, RX_CLEAR_BUF, 0);
+}
+
+void cec_set_divider(struct imx_cec_dev *cec)
+{
+ /* Set clock divider */
+ if (cec->clk_div == 0) {
+ dev_warn(cec->dev,
+ "Warning. Clock divider is 0. Changing to 1.\n");
+ cec_write(cec, CLK_DIV_MSB, 0);
+ cec_write(cec, CLK_DIV_LSB, 1);
+ } else {
+ cec_write(cec, CLK_DIV_MSB,
+ (cec->clk_div >> 8) & 0xFF);
+ cec_write(cec, CLK_DIV_LSB, cec->clk_div & 0xFF);
+ }
+}
+
+u32 cec_read_message(struct imx_cec_dev *cec)
+{
+ struct cec_msg *msg = &cec->msg;
+ int len;
+ int i;
+
+ cec_write(cec, RX_MSG_CMD, CEC_RX_READ);
+
+ len = cec_read(cec, RX_MSG_LENGTH);
+ msg->len = len + 1;
+ dev_dbg(cec->dev, "RX MSG len =%d\n", len);
+
+ /* Read RX MSG bytes */
+ for (i = 0; i < msg->len; ++i) {
+ msg->msg[i] = (u8) cec_read(cec, RX_MSG_DATA1 + (i * REG_ADDR_OFF));
+ dev_dbg(cec->dev, "RX MSG[%d]=0x%x\n", i, msg->msg[i]);
+ }
+
+ cec_write(cec, RX_MSG_CMD, CEC_RX_STOP);
+
+ return true;
+}
+
+u32 cec_write_message(struct imx_cec_dev *cec, struct cec_msg *msg)
+{
+ u8 i;
+
+ cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
+
+ if (msg->len > CEC_MAX_MSG_SIZE) {
+ dev_err(cec->dev, "Invalid MSG size!\n");
+ return -EINVAL;
+ }
+
+ /* Write Message to register */
+ for (i = 0; i < msg->len; ++i) {
+ cec_write(cec, TX_MSG_HEADER + (i * REG_ADDR_OFF),
+ msg->msg[i]);
+ }
+ /* Write Message Length (payload + opcode) */
+ cec_write(cec, TX_MSG_LENGTH, msg->len - 1);
+
+ cec_write(cec, TX_MSG_CMD, CEC_TX_TRANSMIT);
+
+ return true;
+}
+
+void cec_abort_tx_transfer(struct imx_cec_dev *cec)
+{
+ cec_write(cec, TX_MSG_CMD, CEC_TX_ABORT);
+ cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
+}
+
+u32 imx_cec_set_logical_addr(struct imx_cec_dev *cec, u32 la)
+{
+ u8 i;
+ u8 la_reg;
+
+ if (la >= MAX_LA_VAL) {
+ dev_err(cec->dev, "Error logical Addr\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < MAX_LA_IDX; ++i) {
+ la_reg =
+ cec_read(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF));
+
+ if (get_la_valid(la_reg))
+ continue;
+
+ if (get_la(la_reg) == la) {
+ dev_warn(cec->dev, "Warning. LA already in use.\n");
+ return true;
+ }
+
+ la = set_la(la) | set_la_valid(1);
+
+ cec_write(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF), la);
+ return true;
+ }
+
+ dev_warn(cec->dev, "All LA in use\n");
+
+ return false;
+}
+
+static int cec_poll_worker(void *_cec)
+{
+ struct imx_cec_dev *cec = (struct imx_cec_dev *)_cec;
+ int num_rx_msgs, i;
+ int sts;
+
+ for (;;) {
+ if (kthread_should_stop())
+ break;
+
+ /* Check TX State */
+ sts = cec_read(cec, TX_MSG_STATUS);
+ switch (sts) {
+ case CEC_STS_SUCCESS:
+ cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0,
+ 0);
+ cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
+ break;
+ case CEC_STS_ERROR:
+ cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
+ cec_transmit_done(cec->adap,
+ CEC_TX_STATUS_MAX_RETRIES |
+ CEC_TX_STATUS_ERROR, 0, 0, 0, 1);
+ break;
+ case CEC_STS_BUSY:
+ default:
+ break;
+ }
+
+ /* Check RX State */
+ sts = cec_read(cec, RX_MSG_STATUS);
+ num_rx_msgs = cec_read(cec, NUM_OF_MSG_RX_BUF);
+ switch (sts) {
+ case CEC_STS_SUCCESS:
+ if (num_rx_msgs == 0xf)
+ num_rx_msgs = CEC_MAX_RX_MSGS;
+
+ if (num_rx_msgs > CEC_MAX_RX_MSGS) {
+ dev_err(cec->dev, "Error rx msg num %d\n",
+ num_rx_msgs);
+ cec_clear_rx_buffer(cec);
+ break;
+ }
+
+ /* Rx FIFO Depth 2 RX MSG */
+ for (i = 0; i < num_rx_msgs; i++) {
+ cec_read_message(cec);
+ cec->msg.rx_status = CEC_RX_STATUS_OK;
+ cec_received_msg(cec->adap, &cec->msg);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!kthread_should_stop())
+ schedule_timeout_idle(20);
+ }
+
+ return 0;
+}
+
+static int imx_cec_adap_enable(struct cec_adapter *adap, bool enable)
+{
+ struct imx_cec_dev *cec = adap->priv;
+
+ if (enable) {
+ cec_write(cec, DB_L_TIMER, 0x10);
+ cec_set_divider(cec);
+ } else {
+ cec_set_divider(cec);
+ }
+
+ return 0;
+}
+
+static int imx_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
+{
+ struct imx_cec_dev *cec = adap->priv;
+
+ imx_cec_set_logical_addr(cec, addr);
+ return 0;
+}
+
+static int imx_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
+ u32 signal_free_time, struct cec_msg *msg)
+{
+ struct imx_cec_dev *cec = adap->priv;
+
+ cec_write_message(cec, msg);
+
+ return 0;
+}
+
+static const struct cec_adap_ops imx_cec_adap_ops = {
+ .adap_enable = imx_cec_adap_enable,
+ .adap_log_addr = imx_cec_adap_log_addr,
+ .adap_transmit = imx_cec_adap_transmit,
+};
+
+int imx_cec_register(struct imx_cec_dev *cec)
+{
+ struct device *dev = cec->dev;
+ int ret;
+
+ cec->adap = cec_allocate_adapter(&imx_cec_adap_ops, cec,
+ CEC_NAME,
+ CEC_CAP_PHYS_ADDR | CEC_CAP_LOG_ADDRS |
+ CEC_CAP_TRANSMIT | CEC_CAP_PASSTHROUGH
+ | CEC_CAP_RC, 1, dev);
+ ret = PTR_ERR_OR_ZERO(cec->adap);
+ if (ret)
+ return ret;
+ ret = cec_register_adapter(cec->adap);
+ if (ret) {
+ cec_delete_adapter(cec->adap);
+ return ret;
+ }
+
+ cec->dev = dev;
+
+ cec->cec_worker = kthread_create(cec_poll_worker, cec, "hdp-cec");
+ if (IS_ERR(cec->cec_worker))
+ dev_err(cec->dev, "failed create hdp cec thread\n");
+
+ wake_up_process(cec->cec_worker);
+
+ dev_dbg(dev, "CEC successfuly probed\n");
+ return 0;
+}
+
+int imx_cec_unregister(struct imx_cec_dev *cec)
+{
+ if (cec->cec_worker) {
+ kthread_stop(cec->cec_worker);
+ cec->cec_worker = NULL;
+ }
+ cec_unregister_adapter(cec->adap);
+ return 0;
+}
+
+MODULE_AUTHOR("Sandor.Yu@NXP.com");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("NXP IMX HDP CEC driver");
diff --git a/drivers/mxc/hdp-cec/imx-hdp-cec.h b/drivers/mxc/hdp-cec/imx-hdp-cec.h
new file mode 100644
index 000000000000..42a06b9d728d
--- /dev/null
+++ b/drivers/mxc/hdp-cec/imx-hdp-cec.h
@@ -0,0 +1,346 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _IMX_HDP_CEC_H_
+#define _IMX_HDP_CEC_H_
+
+#include <linux/cec.h>
+#include "../hdp/util.h"
+#include "../hdp/address.h"
+
+/* regsiter define */
+/* register TX_MSG_HEADER */
+#define TX_MSG_HEADER 0
+#define F_TX_FOLLOWER_ADDRESS(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_TX_FOLLOWER_ADDRESS_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_TX_INITIATOR_ADDRESS(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_TX_INITIATOR_ADDRESS_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+
+/* register TX_MSG_OPCODE */
+#define TX_MSG_OPCODE 1
+#define F_TX_MSG_OPCODE(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TX_MSG_OPCODE_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register TX_MSG_OP1 */
+#define TX_MSG_OP1 2
+#define F_TX_MSG_OP1(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TX_MSG_OP1_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register TX_MSG_OP2 */
+#define TX_MSG_OP2 3
+#define F_TX_MSG_OP2(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TX_MSG_OP2_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register TX_MSG_OP3 */
+#define TX_MSG_OP3 4
+#define F_TX_MSG_OP3(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TX_MSG_OP3_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register TX_MSG_OP4 */
+#define TX_MSG_OP4 5
+#define F_TX_MSG_OP4(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TX_MSG_OP4_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register TX_MSG_OP5 */
+#define TX_MSG_OP5 6
+#define F_TX_MSG_OP5(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TX_MSG_OP5_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register TX_MSG_OP6 */
+#define TX_MSG_OP6 7
+#define F_TX_MSG_OP6(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TX_MSG_OP6_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register TX_MSG_OP7 */
+#define TX_MSG_OP7 8
+#define F_TX_MSG_OP7(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TX_MSG_OP7_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register TX_MSG_OP8 */
+#define TX_MSG_OP8 9
+#define F_TX_MSG_OP8(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TX_MSG_OP8_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register TX_MSG_OP9 */
+#define TX_MSG_OP9 10
+#define F_TX_MSG_OP9(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TX_MSG_OP9_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register TX_MSG_OP10 */
+#define TX_MSG_OP10 11
+#define F_TX_MSG_OP10(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TX_MSG_OP10_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register TX_MSG_OP11 */
+#define TX_MSG_OP11 12
+#define F_TX_MSG_OP11(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TX_MSG_OP11_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register TX_MSG_OP12 */
+#define TX_MSG_OP12 13
+#define F_TX_MSG_OP12(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TX_MSG_OP12_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register TX_MSG_OP13 */
+#define TX_MSG_OP13 14
+#define F_TX_MSG_OP13(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TX_MSG_OP13_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register TX_MSG_OP14 */
+#define TX_MSG_OP14 15
+#define F_TX_MSG_OP14(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TX_MSG_OP14_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register TX_MSG_LENGTH */
+#define TX_MSG_LENGTH 16
+#define F_TX_MSG_LENGTH(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_TX_MSG_LENGTH_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+
+/* register TX_MSG_CMD */
+#define TX_MSG_CMD 17
+#define F_TX_MSG_CMD(x) (((x) & ((1 << 2) - 1)) << 0)
+#define F_TX_MSG_CMD_RD(x) (((x) & (((1 << 2) - 1) << 0)) >> 0)
+
+/* register TX_WRITE_BUF */
+#define TX_WRITE_BUF 18
+#define F_TX_WRITE_BUF(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_TX_WRITE_BUF_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register TX_CLEAR_BUF */
+#define TX_CLEAR_BUF 19
+#define F_TX_CLEAR_BUF(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_TX_CLEAR_BUF_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register RX_MSG_CMD */
+#define RX_MSG_CMD 20
+#define F_RX_MSG_CMD(x) (((x) & ((1 << 2) - 1)) << 0)
+#define F_RX_MSG_CMD_RD(x) (((x) & (((1 << 2) - 1) << 0)) >> 0)
+
+/* register RX_CLEAR_BUF */
+#define RX_CLEAR_BUF 21
+#define F_RX_CLEAR_BUF(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_RX_CLEAR_BUF_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register LOGICAL_ADDRESS_LA0 */
+#define LOGICAL_ADDRESS_LA0 22
+#define F_MY_LOG_ADDR0(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_MY_LOG_ADDR0_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_LOG_ADDR_VALID0(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_LOG_ADDR_VALID0_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+
+/* register LOGICAL_ADDRESS_LA1 */
+#define LOGICAL_ADDRESS_LA1 23
+#define F_MY_LOG_ADDR1(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_MY_LOG_ADDR1_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_LOG_ADDR_VALID1(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_LOG_ADDR_VALID1_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+
+/* register LOGICAL_ADDRESS_LA2 */
+#define LOGICAL_ADDRESS_LA2 24
+#define F_MY_LOG_ADDR2(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_MY_LOG_ADDR2_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_LOG_ADDR_VALID2(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_LOG_ADDR_VALID2_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+
+/* register LOGICAL_ADDRESS_LA3 */
+#define LOGICAL_ADDRESS_LA3 25
+#define F_MY_LOG_ADDR3(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_MY_LOG_ADDR3_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_LOG_ADDR_VALID3(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_LOG_ADDR_VALID3_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+
+/* register LOGICAL_ADDRESS_LA4 */
+#define LOGICAL_ADDRESS_LA4 26
+#define F_MY_LOG_ADDR4(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_MY_LOG_ADDR4_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_LOG_ADDR_VALID4(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_LOG_ADDR_VALID4_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+
+/* register CLK_DIV_MSB */
+#define CLK_DIV_MSB 27
+#define F_CLK_DIV_MSB(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_CLK_DIV_MSB_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register CLK_DIV_LSB */
+#define CLK_DIV_LSB 28
+#define F_CLK_DIV_LSB(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_CLK_DIV_LSB_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register CDC_MSG */
+#define CDC_MSG 31
+#define F_CDC_MSG(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_CDC_MSG_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register RX_MSG_DATA1 */
+#define RX_MSG_DATA1 64
+#define F_RX_FOLLOWER_ADDRESS(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_RX_FOLLOWER_ADDRESS_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_RX_INITIATOR_ADDRESS(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_RX_INITIATOR_ADDRESS_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+
+/* register RX_MSG_DATA2 */
+#define RX_MSG_DATA2 65
+#define F_RX_MSG_OPCODE(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_RX_MSG_OPCODE_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register RX_MSG_DATA3 */
+#define RX_MSG_DATA3 66
+#define F_RX_MSG_OP1(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_RX_MSG_OP1_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register RX_MSG_DATA4 */
+#define RX_MSG_DATA4 67
+#define F_RX_MSG_OP2(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_RX_MSG_OP2_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register RX_MSG_DATA5 */
+#define RX_MSG_DATA5 68
+#define F_RX_MSG_OP3(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_RX_MSG_OP3_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register RX_MSG_DATA6 */
+#define RX_MSG_DATA6 69
+#define F_RX_MSG_OP4(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_RX_MSG_OP4_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register RX_MSG_DATA7 */
+#define RX_MSG_DATA7 70
+#define F_RX_MSG_OP5(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_RX_MSG_OP5_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register RX_MSG_DATA8 */
+#define RX_MSG_DATA8 71
+#define F_RX_MSG_OP6(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_RX_MSG_OP6_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register RX_MSG_DATA9 */
+#define RX_MSG_DATA9 72
+#define F_RX_MSG_OP7(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_RX_MSG_OP7_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register RX_MSG_DATA10 */
+#define RX_MSG_DATA10 73
+#define F_RX_MSG_OP8(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_RX_MSG_OP8_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register RX_MSG_DATA11 */
+#define RX_MSG_DATA11 74
+#define F_RX_MSG_OP9(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_RX_MSG_OP9_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register RX_MSG_DATA12 */
+#define RX_MSG_DATA12 75
+#define F_RX_MSG_OP10(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_RX_MSG_OP10_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register RX_MSG_DATA13 */
+#define RX_MSG_DATA13 76
+#define F_RX_MSG_OP11(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_RX_MSG_OP11_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register RX_MSG_DATA14 */
+#define RX_MSG_DATA14 77
+#define F_RX_MSG_OP12(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_RX_MSG_OP12_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register RX_MSG_DATA15 */
+#define RX_MSG_DATA15 78
+#define F_RX_MSG_OP13(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_RX_MSG_OP13_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register RX_MSG_DATA16 */
+#define RX_MSG_DATA16 79
+#define F_RX_MSG_OP14(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_RX_MSG_OP14_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register RX_MSG_LENGTH */
+#define RX_MSG_LENGTH 80
+#define F_RX_MSG_LENGTH(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_RX_MSG_LENGTH_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+
+/* register RX_MSG_STATUS */
+#define RX_MSG_STATUS 81
+#define F_RX_MSG_STATUS(x) (((x) & ((1 << 2) - 1)) << 0)
+#define F_RX_MSG_STATUS_RD(x) (((x) & (((1 << 2) - 1) << 0)) >> 0)
+
+/* register NUM_OF_MSG_RX_BUF */
+#define NUM_OF_MSG_RX_BUF 82
+#define F_RX_NUM_MSG(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_RX_NUM_MSG_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+
+/* register TX_MSG_STATUS */
+#define TX_MSG_STATUS 83
+#define F_TX_MSG_STATUS(x) (((x) & ((1 << 2) - 1)) << 0)
+#define F_TX_MSG_STATUS_RD(x) (((x) & (((1 << 2) - 1) << 0)) >> 0)
+
+/* register DB_L_TIMER */
+#define DB_L_TIMER 96
+
+/* register DB_M_TIMER */
+#define DB_M_TIMER 97
+
+/* register DB_H_TIMER */
+#define DB_H_TIMER 98
+
+#define RX_OP_TIMEOUT 10000
+#define TX_OP_TIMEOUT 10000
+
+/**
+ * CEC Transceiver operation.
+ */
+enum {
+ CEC_TX_STOP,
+ CEC_TX_TRANSMIT,
+ CEC_TX_ABORT,
+ CEC_TX_ABORT_AND_TRANSMIT
+};
+
+/**
+ * CEC Transceiver status.
+ */
+enum {
+ CEC_STS_IDLE,
+ CEC_STS_BUSY,
+ CEC_STS_SUCCESS,
+ CEC_STS_ERROR
+};
+
+/**
+ * CEC Receiver operation.
+ */
+enum {
+ CEC_RX_STOP,
+ CEC_RX_READ,
+ CEC_RX_DISABLE,
+ CEC_RX_ABORT_AND_CLR_FIFO
+};
+
+struct imx_cec_dev {
+ struct cec_adapter *adap;
+ struct device *dev;
+ struct mutex lock;
+
+ struct cec_msg msg;
+ u32 clk_div;
+ struct task_struct *cec_worker;
+
+ /* inited by HDP controller driver */
+ struct hdp_mem *mem;
+ struct hdp_rw_func *rw;
+};
+
+int imx_cec_register(struct imx_cec_dev *cec);
+int imx_cec_unregister(struct imx_cec_dev *cec);
+
+#endif
diff --git a/drivers/mxc/hdp/API_AFE.c b/drivers/mxc/hdp/API_AFE.c
new file mode 100644
index 000000000000..060a6a495710
--- /dev/null
+++ b/drivers/mxc/hdp/API_AFE.c
@@ -0,0 +1,188 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_AFE.c
+ *
+ ******************************************************************************
+ */
+
+#include "address.h"
+#include "API_AFE.h"
+#include "API_General.h"
+
+void Afe_write(state_struct *state, u32 offset, u16 val)
+{
+ CDN_API_STATUS sts;
+
+ sts =
+ CDN_API_General_Write_Register_blocking(state,
+ ADDR_AFE + (offset << 2),
+ val);
+
+ if (sts != CDN_OK) {
+ pr_err
+ ("CDN_API_General_Write_Register_blocking(0x%.8X, 0x%.8X) returned %d\n",
+ offset, val, (int)sts);
+ }
+}
+
+u16 Afe_read(state_struct *state, u32 offset)
+{
+ GENERAL_Read_Register_response resp;
+ CDN_API_STATUS sts;
+
+ sts =
+ CDN_API_General_Read_Register_blocking(state,
+ ADDR_AFE + (offset << 2),
+ &resp);
+
+ if (sts != CDN_OK) {
+ pr_err
+ ("CDN_API_General_Read_Register_blocking(0x%.8X) returned %d\n",
+ offset, (int)sts);
+ }
+ return resp.val;
+}
+
+void set_field_value(reg_field_t *reg_field, u32 value)
+{
+ u8 length;
+ u32 max_value;
+ u32 trunc_val;
+ length = (reg_field->msb - reg_field->lsb + 1);
+
+ max_value = (1 << length) - 1;
+ if (value > max_value) {
+ trunc_val = value;
+ trunc_val &= (1 << length) - 1;
+ pr_err("set_field_value() Error! Specified value (0x%0X)\
+ exceeds field capacity - it will by truncated to\
+ 0x%0X (%0d-bit field - max value: %0d dec)\n",
+ value, trunc_val, length, max_value);
+ } else
+ reg_field->value = value;
+}
+
+int set_reg_value(reg_field_t reg_field)
+{
+ return reg_field.value << reg_field.lsb;
+}
+
+int inside(u32 value, u32 left_sharp_corner, u32 right_sharp_corner)
+{
+ if (value < left_sharp_corner)
+ return 0;
+ if (value > right_sharp_corner)
+ return 0;
+ return 1;
+}
+
+int get_table_row_match_column(
+ const u32 *array,
+ u32 table_rows,
+ u32 table_cols,
+ u32 start_row,
+ u32 column_to_search,
+ u32 value_to_search_in_column)
+{
+ u32 idx_cols, idx_rows;
+ u32 value;
+
+ for (idx_rows = start_row; idx_rows < table_rows; idx_rows++) {
+ for (idx_cols = 0; idx_cols < table_cols; idx_cols++) {
+ if (idx_cols == column_to_search) {
+ value = *((array + idx_rows * table_cols) +
+ idx_cols);
+ if (value == value_to_search_in_column) {
+ return idx_rows;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+int get_table_row(
+ const u32 *array,
+ u32 table_rows,
+ u32 table_cols,
+ u32 variable_in_range,
+ u32 range_min_column,
+ u32 range_max_column,
+ u32 column_to_search,
+ u32 column_value)
+{
+ u32 i = 0;
+ while (1) {
+ i = get_table_row_match_column(array, table_rows, table_cols, i,
+ column_to_search, column_value);
+ if (i + 1) {
+ if (inside(variable_in_range,
+ *((array + i * table_cols) +
+ range_min_column),
+ *((array + i * table_cols) +
+ range_max_column))) {
+ break;
+ }
+ i++;
+ } else {
+ break;
+ }
+ }
+ return i;
+}
+
+u8 AFE_check_rate_supported(ENUM_AFE_LINK_RATE rate)
+{
+ switch (rate) {
+ case AFE_LINK_RATE_1_6:
+ case AFE_LINK_RATE_2_1:
+ case AFE_LINK_RATE_2_4:
+ case AFE_LINK_RATE_2_7:
+ case AFE_LINK_RATE_3_2:
+ case AFE_LINK_RATE_4_3:
+ case AFE_LINK_RATE_5_4:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
diff --git a/drivers/mxc/hdp/API_AFE.h b/drivers/mxc/hdp/API_AFE.h
new file mode 100644
index 000000000000..37ddaa4ff568
--- /dev/null
+++ b/drivers/mxc/hdp/API_AFE.h
@@ -0,0 +1,111 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_AFE.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef API_AFE_H_
+#define API_AFE_H_
+
+#include "util.h"
+
+typedef enum {
+ AFE_LINK_RATE_1_6 = 0x6, /* 1.62 Gb/s */
+ AFE_LINK_RATE_2_1 = 0x8, /* 2.16 Gb/s */
+ AFE_LINK_RATE_2_4 = 0x9, /* 2.43 Gb/s */
+ AFE_LINK_RATE_2_7 = 0xA, /* 2.70 Gb/s */
+ AFE_LINK_RATE_3_2 = 0xC, /* 3.24 Gb/s */
+ AFE_LINK_RATE_4_3 = 0x10, /* 4.32 Gb/s */
+ AFE_LINK_RATE_5_4 = 0x14, /* 5.40 Gb/s */
+ AFE_LINK_RATE_8_1 = 0x1E, /* 8.10 Gb/s */
+} ENUM_AFE_LINK_RATE;
+
+/* Some of the PHY programming sequences
+ * depend on the reference clock frequency.
+ * Variable of this type is used to control
+ * the programming flow. */
+typedef enum {
+ REFCLK_24MHZ,
+ REFCLK_27MHZ
+} REFCLK_FREQ;
+
+typedef enum {
+ CLK_RATIO_1_1,
+ CLK_RATIO_5_4,
+ CLK_RATIO_3_2,
+ CLK_RATIO_2_1,
+ CLK_RATIO_1_2,
+ CLK_RATIO_5_8,
+ CLK_RATIO_3_4
+} clk_ratio_t;
+
+typedef struct {
+ u32 value;
+ u8 lsb;
+ u8 msb;
+ u8 *label;
+} reg_field_t;
+
+u8 AFE_check_rate_supported(ENUM_AFE_LINK_RATE rate);
+void Afe_write(state_struct *state, u32 offset, u16 val);
+u16 Afe_read(state_struct *state, u32 offset);
+void AFE_init(state_struct *state, int num_lanes,
+ ENUM_AFE_LINK_RATE link_rate);
+void afe_init_t28hpc(state_struct *state, int num_lanes,
+ ENUM_AFE_LINK_RATE link_rate);
+void AFE_power(state_struct *state, int num_lanes,
+ ENUM_AFE_LINK_RATE link_rate);
+void afe_power_t28hpc(state_struct *state, int num_lanes,
+ ENUM_AFE_LINK_RATE link_rate);
+void set_field_value(reg_field_t *reg_field, u32 value);
+int set_reg_value(reg_field_t reg_field);
+int inside(u32 value, u32 left_sharp_corner, u32 right_sharp_corner);
+int get_table_row_match_column(const u32 *array, u32 table_rows,
+ u32 table_cols, u32 start_row,
+ u32 column_to_search,
+ u32 value_to_search_in_column);
+int get_table_row(const u32 *array, u32 table_rows,
+ u32 table_cols, u32 variable_in_range,
+ u32 range_min_column, u32 range_max_column,
+ u32 column_to_search, u32 column_value);
+#endif
diff --git a/drivers/mxc/hdp/API_Audio.c b/drivers/mxc/hdp/API_Audio.c
new file mode 100644
index 000000000000..b49b0765ae07
--- /dev/null
+++ b/drivers/mxc/hdp/API_Audio.c
@@ -0,0 +1,432 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * API_Audio.c
+ *
+ ******************************************************************************
+ */
+#include "address.h"
+#include "aif_pckt2smp.h"
+#include "API_Audio.h"
+#include "API_DPTX.h"
+#include "API_General.h"
+#include "clock_meters.h"
+#include "dptx_stream.h"
+#include "dptx_framer.h"
+#include "source_aif_decoder.h"
+#include "source_aif_smpl2pckt.h"
+#include "source_car.h"
+#include "util.h"
+
+CDN_API_STATUS CDN_API_AudioMute(state_struct *state, AUDIO_MUTE_MODE mode)
+{
+ return (CDN_API_General_Write_Field
+ (state, ADDR_DPTX_STREAM + (DP_VB_ID << 2), 4, 1,
+ (1 - mode) << 4));
+}
+
+CDN_API_STATUS CDN_API_AudioMute_blocking(state_struct *state,
+ AUDIO_MUTE_MODE mode)
+{
+ internal_block_function(&state->mutex, CDN_API_AudioMute(state, mode));
+}
+
+CDN_API_STATUS CDN_API_AudioMode(state_struct *state, AUDIO_MODE mode)
+{
+ return (CDN_API_General_Write_Register
+ (state, ADDR_DPTX_FRAMER + (AUDIO_PACK_CONTROL << 2),
+ F_AUDIO_PACK_EN(mode)));
+}
+
+CDN_API_STATUS CDN_API_AudioMode_blocking(state_struct *state, AUDIO_MODE mode)
+{
+ internal_block_function(&state->mutex, CDN_API_AudioMode(state, mode));
+}
+
+CDN_API_STATUS CDN_API_AudioConfigCore(state_struct *state,
+ AUDIO_TYPE audioType, int numOfChannels,
+ AUDIO_FREQ freq, int lanes,
+ AUDIO_WIDTH width)
+{
+ int i;
+ int lanesParam;
+ u32 I2S_DEC_PORT_EN_Val;
+
+ if (numOfChannels == 2) {
+ if (lanes == 1)
+ lanesParam = 1;
+ else
+ lanesParam = 3;
+ } else
+ lanesParam = 0;
+
+ if (audioType == AUDIO_TYPE_I2S) {
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_DECODER + (AUDIO_SRC_CNFG << 2),
+ 0x20000);
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_SMPL2PCKT + (FIFO_CNTL << 2), 2);
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_SMPL2PCKT + (SMPL2PKT_CNFG << 2),
+ F_MAX_NUM_CH(numOfChannels - 1) |
+ F_NUM_OF_I2S_PORTS_S((numOfChannels / 2) - 1) |
+ (1 << 8) | (lanesParam << 11));
+
+ if (numOfChannels == 2)
+ I2S_DEC_PORT_EN_Val = 1;
+ else if (numOfChannels == 4)
+ I2S_DEC_PORT_EN_Val = 3;
+ else
+ I2S_DEC_PORT_EN_Val = 0xF;
+
+ /* 24 bit configuration + number of channels according to config */
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_DECODER + (AUDIO_SRC_CNFG << 2),
+ 0x01000 | F_AUDIO_SAMPLE_WIDTH(width) |
+ F_AUDIO_CH_NUM(numOfChannels - 1) |
+ F_I2S_DEC_PORT_EN(I2S_DEC_PORT_EN_Val));
+
+ for (i = 0; i < (numOfChannels + 1) / 2; i++) {
+ cdn_apb_write(state, ADDR_SOURCE_AIF_DECODER +
+ ((STTS_BIT_CH01 + i) << 2),
+ F_WORD_LENGTH_CH0(0x2) |
+ F_WORD_LENGTH_CH1(0x2) |
+ F_CHANNEL_NUM_CH0(i * 2) |
+ F_CHANNEL_NUM_CH1((i * 2) + 1));
+ }
+
+ /*set ch status bits */
+ switch (freq) {
+
+ case AUDIO_FREQ_32:
+ cdn_apb_write(state, ADDR_SOURCE_AIF_DECODER +
+ (COM_CH_STTS_BITS << 2),
+ 4 | F_SAMPLING_FREQ(0x3) |
+ F_ORIGINAL_SAMP_FREQ(0xC));
+ break;
+ case AUDIO_FREQ_192:
+ cdn_apb_write(state, ADDR_SOURCE_AIF_DECODER +
+ (COM_CH_STTS_BITS << 2),
+ 4 | F_SAMPLING_FREQ(0xE) |
+ F_ORIGINAL_SAMP_FREQ(0x1));
+ break;
+
+ case AUDIO_FREQ_48:
+ cdn_apb_write(state, ADDR_SOURCE_AIF_DECODER +
+ (COM_CH_STTS_BITS << 2),
+ 4 | F_SAMPLING_FREQ(0x2) |
+ F_ORIGINAL_SAMP_FREQ(0xD));
+ break;
+ case AUDIO_FREQ_96:
+ cdn_apb_write(state, ADDR_SOURCE_AIF_DECODER +
+ (COM_CH_STTS_BITS << 2),
+ 4 | F_SAMPLING_FREQ(0xA) |
+ F_ORIGINAL_SAMP_FREQ(0x5));
+ break;
+ case AUDIO_FREQ_44_1:
+ cdn_apb_write(state, ADDR_SOURCE_AIF_DECODER +
+ (COM_CH_STTS_BITS << 2),
+ 4 | F_SAMPLING_FREQ(0x0) |
+ F_ORIGINAL_SAMP_FREQ(0xF));
+ break;
+ case AUDIO_FREQ_88_2:
+ cdn_apb_write(state, ADDR_SOURCE_AIF_DECODER +
+ (COM_CH_STTS_BITS << 2),
+ 4 | F_SAMPLING_FREQ(0x8) |
+ F_ORIGINAL_SAMP_FREQ(0x7));
+ break;
+ case AUDIO_FREQ_176_4:
+ cdn_apb_write(state, ADDR_SOURCE_AIF_DECODER +
+ (COM_CH_STTS_BITS << 2),
+ 4 | F_SAMPLING_FREQ(0xC) |
+ F_ORIGINAL_SAMP_FREQ(0x3));
+ break;
+ }
+
+ /* Enable I2S encoder */
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_DECODER + (AUDIO_SRC_CNTL << 2), 2);
+ /* Enable smpl2pkt */
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_SMPL2PCKT + (SMPL2PKT_CNTL << 2), 2);
+ } else {
+
+ /* set spidif 2c en */
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_DECODER + (SPDIF_CTRL_ADDR << 2),
+ 0x1F0707);
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_SMPL2PCKT + (FIFO_CNTL << 2), 2);
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_SMPL2PCKT + (SMPL2PKT_CNFG << 2),
+ 0x101 | (lanesParam << 11));
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_SMPL2PCKT + (SMPL2PKT_CNTL << 2), 2);
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_DECODER + (SPDIF_CTRL_ADDR << 2),
+ 0x3F0707);
+ }
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_AudioConfigCore_blocking(state_struct *state,
+ AUDIO_TYPE audioType,
+ int numOfChannels,
+ AUDIO_FREQ freq, int lanes,
+ AUDIO_WIDTH width)
+{
+ internal_block_function(&state->mutex, CDN_API_AudioConfigCore
+ (state, audioType, numOfChannels, freq, lanes,
+ width));
+}
+
+CDN_API_STATUS CDN_API_AudioAutoConfig(state_struct *state,
+ AUDIO_TYPE audioType, int numOfChannels,
+ AUDIO_FREQ freq, int lanes,
+ AUDIO_WIDTH width,
+ CDN_PROTOCOL_TYPE protocol, int ncts,
+ AUDIO_MUTE_MODE mode)
+{
+
+ CDN_API_STATUS ret = CDN_BSY;
+ u32 REF_CYC_Val;
+
+ switch (state->tmp) {
+ case 0:
+ if (protocol == CDN_DPTX) {
+ ret =
+ CDN_API_General_Write_Register(state,
+ ADDR_DPTX_FRAMER +
+ (AUDIO_PACK_STATUS <<
+ 2), 0x11 << 16);
+ } else {
+ ret = CDN_OK;
+ }
+ break;
+
+ case 1:
+ if (protocol == CDN_DPTX) {
+ REF_CYC_Val = 0x8000;
+ ret =
+ CDN_API_General_Write_Register(state,
+ ADDR_CLOCK_METERS +
+ (CM_LANE_CTRL << 2),
+ REF_CYC_Val);
+ } else {
+ /* hdmi mode */
+ ret =
+ CDN_API_General_Write_Register(state,
+ ADDR_CLOCK_METERS +
+ (CM_CTRL << 2), 8);
+
+ }
+ break;
+ case 2:
+ if ((protocol == CDN_HDMITX_TYPHOON)
+ || (protocol == CDN_HDMITX_KIRAN)) {
+ ret =
+ CDN_API_General_Write_Register(state,
+ ADDR_CLOCK_METERS +
+ (CM_I2S_CTRL << 2),
+ ncts | 0x4000000);
+ } else {
+ ret = CDN_OK;
+ }
+
+ break;
+
+ case 3:
+ if ((protocol == CDN_HDMITX_TYPHOON)
+ || (protocol == CDN_HDMITX_KIRAN)) {
+ ret = CDN_OK;
+ } else {
+ /* in dptx set audio on in dp framer */
+ ret = CDN_API_AudioMode(state, 1);
+ }
+ break;
+
+ case 4:
+ /* set car audio on _not reset */
+ if (protocol == CDN_DPTX) {
+ /* TODO DK: try to merge case 3 and 4 */
+ ret = CDN_OK;
+ } else {
+ ret = CDN_OK;
+ }
+ break;
+
+ case 5:
+ if ((protocol == CDN_DPTX) && (audioType != AUDIO_TYPE_I2S)) {
+ ret =
+ CDN_API_General_Write_Register(state,
+ ADDR_SOURCE_CAR +
+ (SOURCE_AIF_CAR <<
+ 2), 0xff);
+ } else {
+ ret = CDN_OK;
+ }
+ break;
+ case 6:
+ if (protocol == CDN_DPTX) {
+ ret =
+ CDN_API_General_Write_Register(state,
+ ADDR_CLOCK_METERS +
+ (CM_CTRL << 2), 0);
+ } else {
+ ret = CDN_OK;
+ }
+ break;
+
+ case 7:
+ ret =
+ CDN_API_AudioConfigCore(state, audioType, numOfChannels,
+ freq, lanes, width);
+ break;
+ }
+ if (!state->tmp && ret == CDN_STARTED)
+ return CDN_STARTED;
+ switch (ret) {
+ case CDN_OK:
+ state->tmp++;
+ break;
+ case CDN_STARTED:
+ return CDN_BSY;
+ break;
+ default:
+ return ret;
+ }
+ if (state->tmp == 9) {
+ state->tmp = 0;
+ return CDN_OK;
+ }
+ return CDN_BSY;
+
+}
+
+CDN_API_STATUS CDN_API_AudioAutoConfig_blocking(state_struct *state,
+ AUDIO_TYPE audioType,
+ int numOfChannels,
+ AUDIO_FREQ freq, int lanes,
+ AUDIO_WIDTH width,
+ CDN_PROTOCOL_TYPE protocol,
+ int ncts, AUDIO_MUTE_MODE mode)
+{
+ internal_block_function(&state->mutex, CDN_API_AudioAutoConfig
+ (state, audioType, numOfChannels, freq, lanes,
+ width, protocol, ncts, mode));
+}
+
+CDN_API_STATUS CDN_API_AudioOff(state_struct *state, AUDIO_TYPE audioType)
+{
+ CDN_API_STATUS ret = CDN_BSY;
+
+ switch (state->tmp) {
+ case 0:
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_DECODER + (SPDIF_CTRL_ADDR << 2),
+ 0x1F0707);
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_DECODER + (AUDIO_SRC_CNTL << 2),
+ 0);
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_DECODER + (AUDIO_SRC_CNFG << 2),
+ 0);
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_DECODER + (AUDIO_SRC_CNTL << 2),
+ 1);
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_DECODER + (AUDIO_SRC_CNTL << 2),
+ 0);
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_SMPL2PCKT + (SMPL2PKT_CNTL << 2),
+ 0);
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_SMPL2PCKT + (SMPL2PKT_CNTL << 2),
+ 1);
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_SMPL2PCKT + (SMPL2PKT_CNTL << 2),
+ 0);
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_SMPL2PCKT + (FIFO_CNTL << 2), 1);
+ cdn_apb_write(state,
+ ADDR_SOURCE_AIF_SMPL2PCKT + (FIFO_CNTL << 2), 0);
+ ret = CDN_OK;
+
+ break;
+ case 1:
+ ret =
+ CDN_API_General_Write_Register(state, ADDR_SOURCE_CAR +
+ (SOURCE_AIF_CAR << 2), 0x5f);
+ break;
+ case 2:
+ ret =
+ CDN_API_General_Write_Register(state, ADDR_SOURCE_CAR +
+ (SOURCE_AIF_CAR << 2), 0x0f);
+ break;
+ case 3:
+ ret = CDN_OK;
+ break;
+ }
+
+ if (!state->tmp && ret == CDN_STARTED)
+ return CDN_STARTED;
+ switch (ret) {
+ case CDN_OK:
+ state->tmp++;
+ break;
+ case CDN_STARTED:
+ return CDN_BSY;
+ break;
+ default:
+ return ret;
+ }
+ if (state->tmp == 4) {
+ state->tmp = 0;
+ return CDN_OK;
+ }
+ return CDN_BSY;
+}
+
+CDN_API_STATUS CDN_API_AudioOff_blocking(state_struct *state,
+ AUDIO_TYPE audioType)
+{
+ internal_block_function(&state->mutex, CDN_API_AudioOff(state, audioType));
+}
diff --git a/drivers/mxc/hdp/API_Audio.h b/drivers/mxc/hdp/API_Audio.h
new file mode 100644
index 000000000000..4147594d4cba
--- /dev/null
+++ b/drivers/mxc/hdp/API_Audio.h
@@ -0,0 +1,159 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * API_Audio.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef API_AUDIO_H_
+#define API_AUDIO_H_
+
+#include "API_General.h"
+/**
+ * \addtogroup AUDIO_API
+ * \{
+ */
+typedef enum {
+ AUDIO_TYPE_I2S,
+ AUDIO_TYPE_SPIDIF_INTERNAL,
+ AUDIO_TYPE_SPIDIF_EXTERNAL,
+} AUDIO_TYPE;
+
+typedef enum {
+ AUDIO_FREQ_32,
+ AUDIO_FREQ_48,
+ AUDIO_FREQ_96,
+ AUDIO_FREQ_192,
+ AUDIO_FREQ_44_1,
+ AUDIO_FREQ_88_2,
+ AUDIO_FREQ_176_4,
+} AUDIO_FREQ;
+
+typedef enum {
+ AUDIO_WIDTH_16,
+ AUDIO_WIDTH_24,
+ AUDIO_WIDTH_32,
+} AUDIO_WIDTH;
+
+typedef enum {
+ AUDIO_MODE_OFF,
+ AUDIO_MODE_ON
+} AUDIO_MODE;
+
+typedef enum {
+ AUDIO_MUTE_MODE_MUTE,
+ AUDIO_MUTE_MODE_UNMUTE
+} AUDIO_MUTE_MODE;
+
+/**
+ * \brief mute or unmute audio
+ */
+CDN_API_STATUS CDN_API_AudioMute(state_struct *state, AUDIO_MUTE_MODE mode);
+
+/**
+ * \brief blocking version of #CDN_API_AudioMute
+ */
+CDN_API_STATUS CDN_API_AudioMute_blocking(state_struct *state,
+ AUDIO_MUTE_MODE mode);
+
+/**
+ * \brief start playing audio with the input parameters
+ ncts and mode are relevant only in HDMI TX mode , not relevant for DPTX mode
+ */
+CDN_API_STATUS CDN_API_AudioAutoConfig(state_struct *state,
+ AUDIO_TYPE audioType, int numOfChannels,
+ AUDIO_FREQ freq, int lanes,
+ AUDIO_WIDTH width,
+ CDN_PROTOCOL_TYPE protocol, int ncts,
+ AUDIO_MUTE_MODE mode);
+
+/**
+ * \brief blocking version of #CDN_API_AudioAutoConfig
+ */
+CDN_API_STATUS CDN_API_AudioAutoConfig_blocking(state_struct *state,
+ AUDIO_TYPE audioType,
+ int numOfChannels,
+ AUDIO_FREQ freq, int lanes,
+ AUDIO_WIDTH width,
+ CDN_PROTOCOL_TYPE protocol,
+ int ncts, AUDIO_MUTE_MODE mode);
+
+/**
+ * \brief audio off (use it to stop current audio and start new one using CDN_API_AudioAutoConfig)
+ */
+CDN_API_STATUS CDN_API_AudioOff(state_struct *state, AUDIO_TYPE audioType);
+
+/**
+ * \brief blocking version of #CDN_API_AudioOff
+ */
+CDN_API_STATUS CDN_API_AudioOff_blocking(state_struct *state,
+ AUDIO_TYPE audioType);
+
+/**
+ * \brief internal function to set audio on or off inside internal registers
+ */
+CDN_API_STATUS CDN_API_AudioMode(state_struct *state, AUDIO_MODE mode);
+
+/**
+ * \brief blocking version of #CDN_API_AudioMode
+ */
+CDN_API_STATUS CDN_API_AudioMode_blocking(state_struct *state,
+ AUDIO_MODE mode);
+
+/**
+ * \brief internal function to set audio core registers
+ */
+CDN_API_STATUS CDN_API_AudioConfigCore(state_struct *state,
+ AUDIO_TYPE audioType, int numOfChannels,
+ AUDIO_FREQ freq, int lanes,
+ AUDIO_WIDTH width);
+
+/**
+ * \brief blocking version of #CDN_API_AudioConfigCore
+ */
+CDN_API_STATUS CDN_API_AudioConfigCore_blocking(state_struct *state,
+ AUDIO_TYPE audioType,
+ int numOfChannels,
+ AUDIO_FREQ freq, int lanes,
+ AUDIO_WIDTH width);
+
+#endif
diff --git a/drivers/mxc/hdp/API_DPTX.c b/drivers/mxc/hdp/API_DPTX.c
new file mode 100644
index 000000000000..4bd74bd4156d
--- /dev/null
+++ b/drivers/mxc/hdp/API_DPTX.c
@@ -0,0 +1,936 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_DPTX.c
+ *
+ ******************************************************************************
+ */
+#include "API_DPTX.h"
+#include "util.h"
+#include "opcodes.h"
+#include "address.h"
+#include "dptx_stream.h"
+#include "dptx_framer.h"
+#include "source_vif.h"
+
+CDN_API_STATUS CDN_API_DPTX_Read_DPCD(state_struct *state, int numOfBytes,
+ int addr, DPTX_Read_DPCD_response *resp,
+ CDN_BUS_TYPE bus_type)
+{
+ CDN_API_STATUS ret;
+ if (!state->running) {
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_DP_TX, DPTX_READ_DPCD,
+ 2, 2, numOfBytes, 3, addr);
+ state->bus_type = bus_type;
+ state->rxEnable = 1;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ ret = internal_test_rx_head(state, MB_MODULE_ID_DP_TX,
+ DPTX_DPCD_READ_RESP);
+ if (ret != CDN_OK) {
+ state->running = 0;
+ return ret;
+ }
+ /* Clean most significant bytes in members of structure used for response. */
+ resp->size = 0;
+ resp->addr = 0;
+ internal_readmsg(state, 3,
+ 2, &resp->size, 3, &resp->addr, 0, &resp->buff);
+ state->running = 0;
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_Read_DPCD_blocking(state_struct *state,
+ int numOfBytes, int addr,
+ DPTX_Read_DPCD_response *resp,
+ CDN_BUS_TYPE bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_Read_DPCD
+ (state, numOfBytes, addr, resp, bus_type));
+}
+
+CDN_API_STATUS CDN_API_DPTX_Read_EDID(state_struct *state, u8 segment,
+ u8 extension,
+ DPTX_Read_EDID_response *resp)
+{
+ CDN_API_STATUS ret;
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_DP_TX, DPTX_GET_EDID,
+ 2, 1, segment, 1, extension);
+ state->rxEnable = 1;
+ state->bus_type = CDN_BUS_TYPE_APB;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ ret = internal_test_rx_head(state, MB_MODULE_ID_DP_TX,
+ DPTX_GET_EDID);
+ if (ret != CDN_OK)
+ return ret;
+ internal_readmsg(state, 3,
+ 1, &resp->size, 1, &resp->blockNo, 0, &resp->buff);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_Read_EDID_blocking(state_struct *state, u8 segment,
+ u8 extension,
+ DPTX_Read_EDID_response *resp)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_Read_EDID
+ (state, segment, extension, resp));
+}
+
+CDN_API_STATUS CDN_API_DPTX_SetHostCap(state_struct *state, u8 maxLinkRate,
+ u8 lanesCount_SSC,
+ u8 maxVoltageSwing,
+ u8 maxPreemphasis,
+ u8 testPatternsSupported,
+ u8 fastLinkTraining,
+ u8 laneMapping, u8 enchanced)
+{
+ /* fifth bit of lanesCount_SSC is used to declare eDP. */
+ state->edp = ((lanesCount_SSC >> 5) & 1);
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_DP_TX,
+ DPTX_SET_HOST_CAPABILITIES, 8, 1,
+ maxLinkRate, 1, lanesCount_SSC, 1,
+ maxVoltageSwing, 1, maxPreemphasis, 1,
+ testPatternsSupported, 1,
+ fastLinkTraining, 1, laneMapping, 1,
+ enchanced);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_SetHostCap_blocking(state_struct *state,
+ u8 maxLinkRate,
+ u8 lanesCount_SSC,
+ u8 maxVoltageSwing,
+ u8 maxPreemphasis,
+ u8 testPatternsSupported,
+ u8 fastLinkTraining,
+ u8 laneMapping, u8 enchanced)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_SetHostCap
+ (state, maxLinkRate, lanesCount_SSC,
+ maxVoltageSwing, maxPreemphasis,
+ testPatternsSupported, fastLinkTraining,
+ laneMapping, enchanced));
+}
+
+CDN_API_STATUS CDN_API_DPTX_SetPowerMode(state_struct *state,
+ CDN_API_PWR_MODE mode)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_DP_TX,
+ DPTX_SET_POWER_MNG, 1, 1, mode);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_SetPowerMode_blocking(state_struct *state,
+ CDN_API_PWR_MODE mode)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_SetPowerMode(state, mode));
+}
+
+CDN_API_STATUS CDN_API_DPTX_Control(state_struct *state, u32 mode)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_DP_TX,
+ DPTX_TRAINING_CONTROL, 1, 1, mode);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_Control_blocking(state_struct *state, u32 mode)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_Control(state, mode));
+}
+
+CDN_API_STATUS CDN_API_DPTX_EDP_Training(state_struct *state,
+ u8 mode, ENUM_AFE_LINK_RATE linkRate,
+ u8 rateId)
+{
+ if (AFE_check_rate_supported(linkRate) == 0)
+ return CDN_ERROR_NOT_SUPPORTED;
+
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_DP_TX, DPTX_EDP_RATE_TRAINING, 3,
+ 1, mode,
+ 1, (u8)linkRate,
+ 1, rateId);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_EDP_Training_blocking(state_struct *state,
+ u8 mode,
+ ENUM_AFE_LINK_RATE linkRate,
+ u8 rateId)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_EDP_Training(state, mode, linkRate, rateId));
+}
+
+CDN_API_STATUS CDN_API_DPTX_Write_DPCD(state_struct *state, u32 numOfBytes,
+ u32 addr, u8 *buff,
+ DPTX_Write_DPCD_response *resp,
+ CDN_BUS_TYPE bus_type)
+{
+ CDN_API_STATUS ret;
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_DP_TX,
+ DPTX_WRITE_DPCD, 3, 2, numOfBytes, 3,
+ addr, -numOfBytes, buff);
+ state->rxEnable = 1;
+ state->bus_type = bus_type;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ ret = internal_test_rx_head(state, MB_MODULE_ID_DP_TX,
+ DPTX_DPCD_WRITE_RESP);
+ if (ret != CDN_OK)
+ return ret;
+ internal_readmsg(state, 2, 2, &resp->size, 3, &resp->addr);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_Write_DPCD_blocking(state_struct *state,
+ u32 numOfBytes, u32 addr,
+ u8 *buff,
+ DPTX_Write_DPCD_response *resp,
+ CDN_BUS_TYPE bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_Write_DPCD
+ (state, numOfBytes, addr, buff, resp,
+ bus_type));
+}
+
+CDN_API_STATUS CDN_API_DPTX_Read_Register(state_struct *state, u8 base,
+ u8 regNo,
+ DPTX_Read_Register_response *resp)
+{
+ u16 addr = (base << 8) + (regNo << 2);
+ CDN_API_STATUS ret;
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_DP_TX,
+ DPTX_READ_REGISTER, 1, 2, addr);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ state->rxEnable = 1;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ ret = internal_test_rx_head(state, MB_MODULE_ID_DP_TX,
+ DPTX_READ_REGISTER_RESP);
+ if (ret != CDN_OK)
+ return ret;
+ internal_readmsg(state, 3,
+ 1, &resp->base, 1, &resp->regNo, 4, &resp->val);
+ resp->regNo >>= 2;
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_Read_Register_blocking(state_struct *state,
+ u8 base, u8 regNo,
+ DPTX_Read_Register_response *resp)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_Read_Register
+ (state, base, regNo, resp));
+}
+
+CDN_API_STATUS CDN_API_DPTX_Write_Register(state_struct *state, u8 base,
+ u8 regNo, u32 val)
+{
+ u16 addr = (base << 8) + (regNo << 2);
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_DP_TX,
+ DPTX_WRITE_REGISTER, 2, 2, addr, 4, val);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_Write_Register_blocking(state_struct *state,
+ u8 base, u8 regNo, u32 val)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_Write_Register
+ (state, base, regNo, val));
+}
+
+CDN_API_STATUS CDN_API_DPTX_Write_Field(state_struct *state, u8 base, u8 regNo,
+ u8 startBit, u8 bitsNo, u32 val)
+{
+ u16 addr = (base << 8) + (regNo << 2);
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_DP_TX,
+ DPTX_WRITE_FIELD, 4, 2, addr, 1, startBit,
+ 1, bitsNo, 4, val);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_Write_Field_blocking(state_struct *state, u8 base,
+ u8 regNo,
+ u8 startBit,
+ u8 bitsNo, u32 val)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_Write_Field
+ (state, base, regNo, startBit, bitsNo, val));
+}
+
+CDN_API_STATUS CDN_API_DPTX_EnableEvent(state_struct *state, bool hpd,
+ bool training)
+{
+ uint8_t events = 0;
+
+ if (!state->running) {
+ if (!internal_apb_available(state)) {
+ return CDN_BSY;
+ }
+
+ events |= (hpd ? 1 << DP_TX_EVENT_ENABLE_HPD_BIT : 0);
+ events |= (training ? 1 << DP_TX_EVENT_ENABLE_TRAINING_BIT : 0);
+
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_DP_TX, DPTX_ENABLE_EVENT, 2, 1, events, 4, 0);
+
+ state->bus_type = CDN_BUS_TYPE_APB;
+
+ return CDN_STARTED;
+ }
+
+ internal_process_messages(state);
+
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_EnableEvent_blocking(state_struct *state, bool hpd,
+ bool training)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_EnableEvent(state, hpd, training));
+}
+
+CDN_API_STATUS CDN_API_DPTX_ReadEvent(state_struct *state, u8 *LinkeventId,
+ u8 *HPDevents)
+{
+ CDN_API_STATUS ret;
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_DP_TX,
+ DPTX_READ_EVENT, 0);
+ state->rxEnable = 1;
+ state->bus_type = CDN_BUS_TYPE_APB;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ ret = internal_test_rx_head(state, MB_MODULE_ID_DP_TX,
+ DPTX_READ_EVENT);
+ if (ret != CDN_OK)
+ return ret;
+ internal_readmsg(state, 2, 1, HPDevents, 1, LinkeventId);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_ReadEvent_blocking(state_struct *state,
+ u8 *LinkeventId, u8 *HPDevents)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_ReadEvent
+ (state, LinkeventId, HPDevents));
+}
+
+CDN_API_STATUS CDN_API_DPTX_Set_VIC(state_struct *state,
+ struct drm_display_mode *mode,
+ int bitsPerPixel,
+ VIC_NUM_OF_LANES NumOfLanes,
+ VIC_SYMBOL_RATE rate,
+ VIC_PXL_ENCODING_FORMAT pxlencformat,
+ STEREO_VIDEO_ATTR steroVidAttr,
+ BT_TYPE bt_type, int TU)
+{
+ int min_link_rate;
+ int bitsPerPixelCalc;
+ int TU_SIZE_reg = 34;
+ int val, val_f, val2, val2_f;
+ u32 lineThresh;
+ u32 pixelClockFreq;
+ u32 MSA_MISC_Param, tempForMisc, tempForMisc2;
+ u32 oddEvenV_Total;
+ u32 DP_FRAMER_SP_Param;
+ u32 DP_FRONT_BACK_PORCH_Param;
+ u32 DP_BYTE_COUNT_Param;
+ u32 MSA_HORIZONTAL_0_Param;
+ u32 MSA_HORIZONTAL_1_Param;
+ u32 MSA_VERTICAL_0_Param;
+ u32 MSA_VERTICAL_1_Param;
+ u32 DP_HORIZONTAL_ADDR_Param;
+ u32 DP_VERTICAL_0_ADDR_Param;
+ u32 DP_VERTICAL_1_ADDR_Param;
+ u32 DP_FRAMER_PXL_REPR_Param;
+ u32 HSYNC2VSYNC_POL_CTRL_Param = 0;
+ u32 BND_HSYNC2VSYNC_Param = 0;
+ u32 DP_FRAMER_TU_Param;
+ u32 tu_vs_diff = 0;
+ VIC_COLOR_DEPTH colorDepth;
+ CDN_API_STATUS ret = CDN_OK;
+
+ if (pxlencformat == YCBCR_4_2_2)
+ bitsPerPixelCalc = bitsPerPixel * 2;
+ else if (pxlencformat == YCBCR_4_2_0)
+ bitsPerPixelCalc = bitsPerPixel * 3 / 2;
+ else
+ bitsPerPixelCalc = bitsPerPixel * 3;
+
+ /* KHz */
+ pixelClockFreq = mode->clock;
+
+ /* KHz */
+ min_link_rate = rate * 995;
+ rate *= 1000;
+
+ val = TU_SIZE_reg * pixelClockFreq * bitsPerPixelCalc;
+ val_f = val / (NumOfLanes * rate * 8);
+ val /= NumOfLanes * rate * 8;
+
+ val2 = TU_SIZE_reg * pixelClockFreq * bitsPerPixelCalc;
+ val2_f = val2 / (NumOfLanes * min_link_rate * 8);
+ val2 /= NumOfLanes * min_link_rate * 8;
+
+ /* find optimum value for the TU_SIZE */
+
+ while (((val == 1) || (TU_SIZE_reg - val < 2) || (val != val2)
+ || (val_f % 1000 > 850) || (val2_f % 1000 > 850)
+ || (val_f % 1000 < 100) || (val2_f % 1000 < 100))
+ && (TU_SIZE_reg < 64)) {
+ TU_SIZE_reg += 2;
+
+ val = TU_SIZE_reg * pixelClockFreq * bitsPerPixelCalc;
+ val_f = val / (NumOfLanes * rate * 8);
+ val /= NumOfLanes * rate * 8;
+
+ val2 = TU_SIZE_reg * pixelClockFreq * bitsPerPixelCalc;
+ val2_f = val2 / (NumOfLanes * min_link_rate * 8);
+ val2 /= NumOfLanes * min_link_rate * 8;
+ }
+
+ /* calculate the fixed valid symbols */
+ val = TU_SIZE_reg * pixelClockFreq * bitsPerPixelCalc;
+ val /= NumOfLanes * rate * 8;
+
+ if (val > 64) {
+ return CDN_ERROR_NOT_SUPPORTED;
+ }
+ DP_FRAMER_TU_Param = (TU_SIZE_reg << 8) + val + (1 << 15);
+
+ tu_vs_diff = 0;
+ if ((TU_SIZE_reg - val) <= 3) {
+ tu_vs_diff = TU_SIZE_reg - val;
+ }
+
+ /* LINE_THRESH set according to zeev presantation */
+ lineThresh =
+ ((val + 1) * NumOfLanes - ((pixelClockFreq / rate) * (val + 1) *
+ (bitsPerPixelCalc / 8) -
+ (bitsPerPixelCalc / 8))) /
+ ((bitsPerPixelCalc * NumOfLanes) / 8);
+ lineThresh += 2;
+
+ DP_FRAMER_SP_Param =
+ ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? 4 : 0) +
+ ((mode->flags & DRM_MODE_FLAG_NHSYNC) ? 2 : 0) +
+ ((mode->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
+
+ DP_FRONT_BACK_PORCH_Param =
+ mode->htotal - mode->hsync_end + ((mode->hsync_start - mode->hdisplay) << 16);
+
+ DP_BYTE_COUNT_Param = mode->hdisplay * (bitsPerPixelCalc) / 8;
+
+ MSA_HORIZONTAL_0_Param =
+ mode->htotal + ((mode->htotal - mode->hsync_start) << 16);
+
+ MSA_HORIZONTAL_1_Param =
+ mode->hsync_end - mode->hsync_start +
+ ((mode->flags & DRM_MODE_FLAG_NHSYNC ? 0 : 1) << 15) + (mode->hdisplay << 16);
+
+ MSA_VERTICAL_0_Param =
+ (mode->flags & DRM_MODE_FLAG_INTERLACE ? (mode->vtotal / 2) : mode->vtotal) +
+ ((mode->vtotal - mode->vsync_start) << 16);
+
+ MSA_VERTICAL_1_Param =
+ (mode->vsync_end - mode->vsync_start +
+ ((mode->flags & DRM_MODE_FLAG_NVSYNC ? 0 : 1) << 15)) +
+ ((mode->flags & DRM_MODE_FLAG_INTERLACE ? mode->vdisplay / 2 : mode->vdisplay) << 16);
+
+ DP_HORIZONTAL_ADDR_Param = (mode->hdisplay << 16) + mode->hsync;
+
+ DP_VERTICAL_0_ADDR_Param =
+ (mode->flags & DRM_MODE_FLAG_INTERLACE ? (mode->vtotal / 2) : mode->vtotal) -
+ (mode->vtotal - mode->vdisplay) + ((mode->vtotal - mode->vsync_start) << 16);
+
+ DP_VERTICAL_1_ADDR_Param =
+ mode->flags & DRM_MODE_FLAG_INTERLACE ? (mode->vtotal / 2) : mode->vtotal;
+
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ BND_HSYNC2VSYNC_Param = 0x3020;
+ else
+ BND_HSYNC2VSYNC_Param = 0x2000;
+
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ HSYNC2VSYNC_POL_CTRL_Param |= F_HPOL(1);
+
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ HSYNC2VSYNC_POL_CTRL_Param |= F_VPOL(1);
+
+ switch (bitsPerPixel) {
+ case 6:
+ colorDepth = BCS_6;
+ break;
+ case 8:
+ colorDepth = BCS_8;
+ break;
+ case 10:
+ colorDepth = BCS_10;
+ break;
+ case 12:
+ colorDepth = BCS_12;
+ break;
+ case 16:
+ colorDepth = BCS_16;
+ break;
+ default:
+ colorDepth = BCS_8;
+ };
+
+ DP_FRAMER_PXL_REPR_Param = (pxlencformat << 8) + colorDepth;
+
+ switch (pxlencformat) {
+ case PXL_RGB: /*0x1 */
+ tempForMisc = 0;
+ break;
+ case YCBCR_4_4_4: /*0x2 */
+ tempForMisc = 6 + 8 * (bt_type);
+ break;
+ case YCBCR_4_2_2: /*0x4 */
+ tempForMisc = 5 + 8 * (bt_type);
+ break;
+ case YCBCR_4_2_0: /*0x8 */
+ tempForMisc = 5;
+ break;
+
+ case Y_ONLY: /*0x10 */
+ tempForMisc = 0;
+ break;
+ default:
+ tempForMisc = 0;
+ };
+
+ switch (bitsPerPixel) {
+ case 6:
+ tempForMisc2 = 0;
+ break;
+
+ case 8:
+ tempForMisc2 = 1;
+ break;
+
+ case 10:
+ tempForMisc2 = 2;
+ break;
+
+ case 12:
+ tempForMisc2 = 3;
+ break;
+
+ case 16:
+ tempForMisc2 = 4;
+ break;
+ default:
+ tempForMisc2 = 1;
+
+ };
+
+ oddEvenV_Total = mode->vtotal % 2;
+ oddEvenV_Total = 1 - oddEvenV_Total;
+ oddEvenV_Total = oddEvenV_Total << 8;
+ MSA_MISC_Param =
+ ((tempForMisc * 2) + (32 * tempForMisc2) +
+ ((pxlencformat == Y_ONLY ? 1 : 0) << 14) +
+ ((oddEvenV_Total) * (mode->flags & DRM_MODE_FLAG_INTERLACE ? 1 : 0)));
+
+ /* 420 has diffrent parameters, enable VSS SDP */
+ if (pxlencformat == YCBCR_4_2_0)
+ MSA_MISC_Param = 1 << 14;
+
+ switch (state->tmp) {
+ case 0:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_SOURCE_VIF,
+ BND_HSYNC2VSYNC,
+ BND_HSYNC2VSYNC_Param);
+ break;
+ case 1:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_SOURCE_VIF,
+ HSYNC2VSYNC_POL_CTRL,
+ HSYNC2VSYNC_POL_CTRL_Param);
+ break;
+ case 2:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_DPTX_STREAM,
+ DP_FRAMER_TU,
+ DP_FRAMER_TU_Param);
+ break;
+ case 3:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_DPTX_STREAM,
+ DP_FRAMER_PXL_REPR,
+ DP_FRAMER_PXL_REPR_Param);
+ break;
+ case 4:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_DPTX_STREAM,
+ DP_FRAMER_SP,
+ DP_FRAMER_SP_Param);
+ break;
+ case 5:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_DPTX_STREAM,
+ DP_FRONT_BACK_PORCH,
+ DP_FRONT_BACK_PORCH_Param);
+ break;
+ case 6:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_DPTX_STREAM,
+ DP_BYTE_COUNT,
+ DP_BYTE_COUNT_Param);
+ break;
+ case 7:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_DPTX_STREAM,
+ MSA_HORIZONTAL_0,
+ MSA_HORIZONTAL_0_Param);
+ break;
+ case 8:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_DPTX_STREAM,
+ MSA_HORIZONTAL_1,
+ MSA_HORIZONTAL_1_Param);
+ break;
+ case 9:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_DPTX_STREAM,
+ MSA_VERTICAL_0,
+ MSA_VERTICAL_0_Param);
+ break;
+ case 10:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_DPTX_STREAM,
+ MSA_VERTICAL_1,
+ MSA_VERTICAL_1_Param);
+ break;
+ case 11:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_DPTX_STREAM,
+ MSA_MISC, MSA_MISC_Param);
+ break;
+ case 12:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_DPTX_STREAM,
+ STREAM_CONFIG, 1);
+ break;
+ case 13:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_DPTX_STREAM,
+ DP_HORIZONTAL,
+ DP_HORIZONTAL_ADDR_Param);
+ break;
+ case 14:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_DPTX_STREAM,
+ DP_VERTICAL_0,
+ DP_VERTICAL_0_ADDR_Param);
+ break;
+ case 15:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_DPTX_STREAM,
+ DP_VERTICAL_1,
+ DP_VERTICAL_1_ADDR_Param);
+ break;
+ case 16:
+ ret =
+ CDN_API_DPTX_Write_Field(state, BASE_DPTX_STREAM, DP_VB_ID,
+ 2, 1,
+ ((mode->flags & DRM_MODE_FLAG_INTERLACE ? 1 : 0) << 2));
+ break;
+ case 17:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_DPTX_STREAM,
+ LINE_THRESH, lineThresh);
+ break;
+ case 18:
+ ret =
+ CDN_API_DPTX_Write_Register(state, BASE_DPTX_STREAM,
+ RATE_GOVERNOR_STATUS,
+ tu_vs_diff << 8);
+ break;
+ }
+ if (!state->tmp && ret == CDN_STARTED)
+ return CDN_STARTED;
+ switch (ret) {
+ case CDN_OK:
+ state->tmp++;
+ break;
+ case CDN_STARTED:
+ return CDN_BSY;
+ break;
+ default:
+ return ret;
+ }
+ if (state->tmp == 19) {
+ state->tmp = 0;
+ return CDN_OK;
+ }
+ return CDN_BSY;
+}
+
+CDN_API_STATUS CDN_API_DPTX_Set_VIC_blocking(state_struct *state,
+ struct drm_display_mode *mode,
+ int bitsPerPixel,
+ VIC_NUM_OF_LANES NumOfLanes,
+ VIC_SYMBOL_RATE rate,
+ VIC_PXL_ENCODING_FORMAT
+ pxlencformat,
+ STEREO_VIDEO_ATTR steroVidAttr,
+ BT_TYPE bt_type, int TU)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_Set_VIC
+ (state, mode, bitsPerPixel, NumOfLanes, rate,
+ pxlencformat, steroVidAttr, bt_type, TU));
+}
+
+CDN_API_STATUS CDN_API_DPTX_SetVideo(state_struct *state, u8 mode)
+{
+ internal_macro_command_tx(state, MB_MODULE_ID_DP_TX, DPTX_SET_VIDEO,
+ CDN_BUS_TYPE_APB, 1, 1, mode);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_SetVideo_blocking(state_struct *state, u8 mode)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_SetVideo(state, mode));
+}
+
+CDN_API_STATUS CDN_API_DPTX_ReadLinkStat(state_struct *state,
+ S_LINK_STAT *stat)
+{
+ internal_macro_command_txrx(state, MB_MODULE_ID_DP_TX,
+ DPTX_READ_LINK_STAT, CDN_BUS_TYPE_APB, 0);
+ internal_readmsg(state, 10, 1, &stat->rate, 1, &stat->lanes, 1,
+ &stat->swing[0], 1, &stat->preemphasis[0], 1,
+ &stat->swing[1], 1, &stat->preemphasis[1], 1,
+ &stat->swing[2], 1, &stat->preemphasis[2], 1,
+ &stat->swing[3], 1, &stat->preemphasis[3]);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_ReadLinkStat_blocking(state_struct *state,
+ S_LINK_STAT *stat)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_ReadLinkStat(state, stat));
+}
+
+CDN_API_STATUS CDN_API_DPTX_TrainingControl(state_struct *state, u8 val)
+{
+ internal_macro_command_tx(state, MB_MODULE_ID_DP_TX,
+ DPTX_TRAINING_CONTROL, CDN_BUS_TYPE_APB, 1, 1,
+ val);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_TrainingControl_blocking(state_struct *state,
+ u8 val)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_TrainingControl(state, val));
+}
+
+CDN_API_STATUS CDN_API_DPTX_GetLastAuxStatus(state_struct *state, u8 *resp)
+{
+ internal_macro_command_txrx(state, MB_MODULE_ID_DP_TX,
+ DPTX_GET_LAST_AUX_STAUS, CDN_BUS_TYPE_APB,
+ 0);
+ internal_readmsg(state, 1, 1, resp);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_GetLastAuxStatus_blocking(state_struct *state,
+ u8 *resp)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_GetLastAuxStatus(state, resp));
+}
+
+CDN_API_STATUS CDN_API_DPTX_GetHpdStatus(state_struct *state, u8 *resp)
+{
+ internal_macro_command_txrx(state, MB_MODULE_ID_DP_TX, DPTX_HPD_STATE,
+ CDN_BUS_TYPE_APB, 0);
+ internal_readmsg(state, 1, 1, resp);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_GetHpdStatus_blocking(state_struct *state,
+ u8 *resp)
+{
+
+ internal_block_function(&state->mutex, CDN_API_DPTX_GetHpdStatus(state, resp));
+}
+
+CDN_API_STATUS CDN_API_DPTX_ForceLanes(state_struct *state, u8 linkRate,
+ u8 numOfLanes,
+ u8 voltageSwing_l0,
+ u8 preemphasis_l0,
+ u8 voltageSwing_l1,
+ u8 preemphasis_l1,
+ u8 voltageSwing_l2,
+ u8 preemphasis_l2,
+ u8 voltageSwing_l3,
+ u8 preemphasis_l3, u8 pattern, u8 ssc)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_DP_TX,
+ DPTX_FORCE_LANES, 12, 1, linkRate, 1,
+ numOfLanes, 1, voltageSwing_l0, 1,
+ preemphasis_l0, 1, voltageSwing_l1, 1,
+ preemphasis_l1, 1, voltageSwing_l2, 1,
+ preemphasis_l2, 1, voltageSwing_l3, 1,
+ preemphasis_l3, 1, pattern, 1, ssc);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_ForceLanes_blocking(state_struct *state,
+ u8 linkRate, u8 numOfLanes,
+ u8 voltageSwing_l0,
+ u8 preemphasis_l0,
+ u8 voltageSwing_l1,
+ u8 preemphasis_l1,
+ u8 voltageSwing_l2,
+ u8 preemphasis_l2,
+ u8 voltageSwing_l3,
+ u8 preemphasis_l3, u8 pattern,
+ u8 ssc)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_ForceLanes_blocking
+ (state, linkRate, numOfLanes, voltageSwing_l0,
+ preemphasis_l0, voltageSwing_l1,
+ preemphasis_l1, voltageSwing_l2,
+ preemphasis_l2, voltageSwing_l3,
+ preemphasis_l3, pattern, ssc));
+}
+
+CDN_API_STATUS CDN_API_DPTX_SetDbg(state_struct *state, uint32_t dbg_cfg)
+{
+ uint8_t buf[sizeof(uint32_t)];
+
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+
+ buf[0] = (uint8_t) (dbg_cfg);
+ buf[1] = (uint8_t) (dbg_cfg >> 8);
+ buf[2] = (uint8_t) (dbg_cfg >> 16);
+ buf[3] = (uint8_t) (dbg_cfg >> 24);
+
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_DP_TX, DPTX_DBG_SET,
+ 1, -sizeof(buf), buf);
+
+ state->bus_type = CDN_BUS_TYPE_APB;
+
+ return CDN_STARTED;
+ }
+
+ internal_process_messages(state);
+
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_DPTX_SetDbg_blocking(state_struct *state,
+ uint32_t dbg_cfg)
+{
+ internal_block_function(&state->mutex, CDN_API_DPTX_SetDbg(state, dbg_cfg));
+}
diff --git a/drivers/mxc/hdp/API_DPTX.h b/drivers/mxc/hdp/API_DPTX.h
new file mode 100644
index 000000000000..89105009ee1f
--- /dev/null
+++ b/drivers/mxc/hdp/API_DPTX.h
@@ -0,0 +1,448 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_DPTX.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef _API_DPTX_H_
+#define _API_DPTX_H_
+
+#include "API_General.h"
+#include "API_AFE.h"
+
+#define MAX_NUM_OF_EVENTS 4
+
+/* Flags for CDN_API_DPTX_SetDbg */
+#define DPTX_DBG_SET_PWR_SKIP_SLEEP (1 << 0)
+#define DPTX_DBG_SET_ALT_CIPHER_ADDR (1 << 1)
+
+/**
+ * \addtogroup DP_TX_API
+ * \{
+ */
+typedef u8 CDN_API_PWR_MODE;
+typedef u32 CDN_EVENT;
+
+/**
+ * reply data struct for CDN_API_DPTX_READ_EDID
+ * please note, buff will point to internal api buffer, user must copy it for later use
+ */
+typedef struct {
+ u8 *buff;
+ u8 size;
+ u8 blockNo;
+} DPTX_Read_EDID_response;
+/**
+ * \brief Cadence API for DP TX to get RX EDID
+ * \param [in] segment - EDID segment to read
+ * \param [in] extension - EDID extension to read
+ * \param [out] resp - pointer to store response
+ * buffer , please note, buff will point to internal api buffer, user must copy it for later use
+ * \return status
+ *
+ */
+CDN_API_STATUS CDN_API_DPTX_Read_EDID(state_struct *state, u8 segment,
+ u8 extension,
+ DPTX_Read_EDID_response *resp);
+/**
+ * \brief blocking version of #CDN_API_DPTX_Read_EDID
+ */
+CDN_API_STATUS CDN_API_DPTX_Read_EDID_blocking(state_struct *state, u8 segment,
+ u8 extension,
+ DPTX_Read_EDID_response *resp);
+
+/**
+ * \brief Cadence API for DP TX to set power mode of sink
+ *
+ * \param [in] mode - power mode
+ * \return status
+ *
+ */
+CDN_API_STATUS CDN_API_DPTX_SetPowerMode(state_struct *state,
+ CDN_API_PWR_MODE mode);
+/**
+ * \brief blocking version of #CDN_API_DPTX_SetPowerMode
+ */
+CDN_API_STATUS CDN_API_DPTX_SetPowerMode_blocking(state_struct *state,
+ CDN_API_PWR_MODE mode);
+
+/**
+ * \brief Cadence API for DP TX to set Host capabilities
+ *
+ * \param [in] maxLinkRate Max link rate-> 0x06=1.62Gbps 0x0A=2.7Gbps 0x14=5.4Gbps 0x1E=8.1Gbps
+ * \param [in] lanesCount_SSC bit 0-3 lanes count, bit 4 SSC
+ * \param [in] maxVoltageSwing - - max supported VoltageSwing
+ * \param [in] maxPreemphasis - max supported Preemphasis
+ * \param [in] testPatternsSupported -which test patern supportrd by phy
+ * \param [in] fastLinkTraining - is it fast link training
+ * \param [in] laneMapping - line mapping for USB type C
+ * \param [in] enchanced - enchanced mode
+ * \return status
+ *
+ */
+CDN_API_STATUS CDN_API_DPTX_SetHostCap(state_struct *state, u8 maxLinkRate,
+ u8 lanesCount_SSC,
+ u8 maxVoltageSwing,
+ u8 maxPreemphasis,
+ u8 testPatternsSupported,
+ u8 fastLinkTraining,
+ u8 laneMapping, u8 enchanced);
+/**
+ * \brief blocking version of #CDN_API_DPTX_SetHostCap
+ */
+CDN_API_STATUS CDN_API_DPTX_SetHostCap_blocking(state_struct *state,
+ u8 maxLinkRate,
+ u8 lanesCount_SSC,
+ u8 maxVoltageSwing,
+ u8 maxPreemphasis,
+ u8 testPatternsSupported,
+ u8 fastLinkTraining,
+ u8 laneMapping, u8 enchanced);
+
+/**
+ * reply data struct for #CDN_API_DPTX_READ_DPCD
+ */
+typedef struct {
+ /** buffer where data will be stored, will become invalid after next call to API */
+ u8 *buff;
+ int addr;
+ int size;
+} DPTX_Read_DPCD_response;
+/**
+ * \brief Cadence API for DP TX to read DPCD
+ *
+ * \param [in] numOfBytes - num of bytes to read
+ * \param [in] addr - address to read from
+ * \param [out] resp - pointer to store response
+ * \return status
+ *
+ */
+CDN_API_STATUS CDN_API_DPTX_Read_DPCD(state_struct *state, int numOfBytes,
+ int addr, DPTX_Read_DPCD_response *resp,
+ CDN_BUS_TYPE bus_type);
+/**
+ * blocking version of #CDN_API_DPTX_READ_DPCD
+ */
+CDN_API_STATUS CDN_API_DPTX_Read_DPCD_blocking(state_struct *state,
+ int numOfBytes, int addr,
+ DPTX_Read_DPCD_response *resp,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * reply data struct for CDN_API_DPTX_WRITE_DPCD
+ */
+typedef struct {
+ int addr;
+ int size;
+} DPTX_Write_DPCD_response;
+/**
+ * \brief Cadence API for DP TX to write DPCD
+ *
+ * \param [in] numOfBytes - num of bytes to write
+ * \param [in] addr - address to write
+ * \param [in] buff - with the data to write
+ * \param [out] resp - pointer to store response
+ * \return status
+ *
+ */
+CDN_API_STATUS CDN_API_DPTX_Write_DPCD(state_struct *state, u32 numOfBytes,
+ u32 addr, u8 *buff,
+ DPTX_Write_DPCD_response *resp,
+ CDN_BUS_TYPE bus_type);
+/**
+ * blocking version of #CDN_API_DPTX_WRITE_DPCD
+ */
+CDN_API_STATUS CDN_API_DPTX_Write_DPCD_blocking(state_struct *state,
+ u32 numOfBytes, u32 addr,
+ u8 *buff,
+ DPTX_Write_DPCD_response *resp,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * DPTX_Read_Register response struct
+ */
+typedef struct {
+ u8 base;
+ u8 regNo;
+ u32 val;
+} DPTX_Read_Register_response;
+/**
+ * \brief Cadence API for DP TX to read register
+ *
+ * \param [in] base - bank numeber (MSB of bank base address)
+ * \param [in] regNo - register number
+ * \param [out] resp - pointer to store response
+ * \return status
+ *
+ * this function will return #CDN_ERR if value of base is incorrect
+ */
+CDN_API_STATUS CDN_API_DPTX_Read_Register(state_struct *state, u8 base,
+ u8 regNo,
+ DPTX_Read_Register_response *resp);
+/**
+ * blocking version of #CDN_API_DPTX_READ_REGISTER
+ */
+CDN_API_STATUS CDN_API_DPTX_Read_Register_blocking(state_struct *state,
+ u8 base, u8 regNo,
+ DPTX_Read_Register_response *
+ resp);
+
+/**
+ * \brief Cadence API for DP TX write register
+ *
+ * \param [in] base - bank numeber (MSB of bank base address)
+ * \param [in] regNo - register number
+ * \param [in] val - value to write
+ * \return status
+ *
+ * this function will return #CDN_ERR if value of base is incorrect
+ */
+CDN_API_STATUS CDN_API_DPTX_Write_Register(state_struct *state, u8 base,
+ u8 regNo, u32 val);
+/**
+ * blocking version of #CDN_API_DPTX_Write_Register
+ */
+CDN_API_STATUS CDN_API_DPTX_Write_Register_blocking(state_struct *state,
+ u8 base, u8 regNo, u32 val);
+
+/**
+ * \brief Cadence API for DP TX write register
+ *
+ * \param [in] base - bank numeber (MSB of bank base address)
+ * \param [in] regNo - register number
+ * \param [in] startBit - first bit to write
+ * \param [in] bitsNo - number of bits to write
+ * \param [in] val - value to write
+ * \return status
+ *
+ * this function will return #CDN_ERR if value of base is incorrect
+ */
+CDN_API_STATUS CDN_API_DPTX_Write_Field(state_struct *state, u8 base, u8 regNo,
+ u8 startBit, u8 bitsNo, u32 val);
+/**
+ * blocking version of #CDN_API_DPTX_Write_Field
+ */
+CDN_API_STATUS CDN_API_DPTX_Write_Field_blocking(state_struct *state, u8 base,
+ u8 regNo,
+ u8 startBit,
+ u8 bitsNo, u32 val);
+
+/* TODO doxygen of DPTX_CONTROL API */
+CDN_API_STATUS CDN_API_DPTX_Control(state_struct *state, u32 mode);
+/**
+ * blocking version of #CDN_API_DPTX_Control
+ */
+CDN_API_STATUS CDN_API_DPTX_Control_blocking(state_struct *state, u32 mode);
+
+/**
+ * \brief Performs Fast Link Training, using LINK_RATE_SET DPCD register.
+ * \param [in] mode - 0 to stop training, 1 to start it, 2 to restart it.
+ * \param [in] linkRate - Link Rate to be used for training.
+ * \param [in] rateId - index of selected Link Rate in DPCd registers.
+ *
+ * Performs Fast Link Training, selecting Link Rate using LINK_RATE_SET DPCD
+ * register, characteristic to Embedded DisplayPort (eDP) v1.4 standard.
+ * If requested link rate is not supported by DPTX, function will return error
+ * code CDN_ERROR_NOT_SUPPORTED, and will take no further action.
+ * rateId is used to select, which Link Rate supported by sink (enumerated in
+ * SUPPORTED_LINK_RATES DPCD registers) is equal to rate requested. This value
+ * will be written to first 3 bits of LINK_RATE_SET DPCD registers. Allowed
+ * range is 0-7. If it is not known beforehand, SUPPORTED_LINK_RATES DPCD
+ * registers may be read by an upper layer, and then used to determine the
+ * correct value to use.
+ */
+CDN_API_STATUS CDN_API_DPTX_EDP_Training(state_struct *state, u8 mode, ENUM_AFE_LINK_RATE linkRate, u8 rateId);
+CDN_API_STATUS CDN_API_DPTX_EDP_Training_blocking(state_struct *state, u8 mode, ENUM_AFE_LINK_RATE linkRate, u8 rateId);
+/**
+ * \brief send DPX_ENABLE_EVENT command
+ */
+CDN_API_STATUS CDN_API_DPTX_EnableEvent(state_struct *state, bool hpd,
+ bool training);
+
+/**
+ * blocking version of #CDN_API_DPTX_EnableEvent
+ */
+CDN_API_STATUS CDN_API_DPTX_EnableEvent_blocking(state_struct *state, bool hpd,
+ bool training);
+
+/**
+ * \brief send DPTX_READ_EVENT_REQUEST command
+ */
+CDN_API_STATUS CDN_API_DPTX_ReadEvent(state_struct *state, u8 *LinkeventId,
+ u8 *HPDevents);
+
+/**
+ * blocking version of #CDN_API_DPTX_ReadEvent
+ */
+CDN_API_STATUS CDN_API_DPTX_ReadEvent_blocking(state_struct *state,
+ u8 *LinkeventId,
+ u8 *HPDevents);
+
+/**
+ * \brief set vic mode according to vic table, the input are video parameters
+ */
+CDN_API_STATUS CDN_API_DPTX_Set_VIC(state_struct *state, struct drm_display_mode *mode,
+ int bitsPerPixel,
+ VIC_NUM_OF_LANES NumOfLanes,
+ VIC_SYMBOL_RATE rate,
+ VIC_PXL_ENCODING_FORMAT pxlencformat,
+ STEREO_VIDEO_ATTR steroVidAttr,
+ BT_TYPE bt_type, int TU);
+
+/**
+ * blocking version of #CDN_API_DPTX_Set_VIC
+ */
+CDN_API_STATUS CDN_API_DPTX_Set_VIC_blocking(state_struct *state,
+ struct drm_display_mode *mode,
+ int bitsPerPixel,
+ VIC_NUM_OF_LANES NumOfLanes,
+ VIC_SYMBOL_RATE rate,
+ VIC_PXL_ENCODING_FORMAT
+ pxlencformat,
+ STEREO_VIDEO_ATTR steroVidAttr,
+ BT_TYPE bt_type, int TU);
+
+/**
+ * \brief turn on or off the video
+ */
+CDN_API_STATUS CDN_API_DPTX_SetVideo(state_struct *state, u8 mode);
+
+/**
+ * \brief blocking version of CDN_API_DPTX_SetVideo
+ */
+CDN_API_STATUS CDN_API_DPTX_SetVideo_blocking(state_struct *state, u8 mode);
+/**
+ * \brief blocking version of #CDN_API_DPTX_SetAudio
+ */
+CDN_API_STATUS CDN_API_DPTX_SetAudio_blocking(state_struct *state, u8 mode);
+
+typedef struct {
+ u8 rate;
+ u8 lanes;
+ u8 swing[3];
+ u8 preemphasis[3];
+} S_LINK_STAT;
+
+/**
+ * \brief get current link status (rate, num of lanes etc), user may read it after get link finish event
+ */
+CDN_API_STATUS CDN_API_DPTX_ReadLinkStat(state_struct *state,
+ S_LINK_STAT *stat);
+
+/**
+ * \brief blocking version of #CDN_API_DPTX_ReadLinkStat
+ */
+CDN_API_STATUS CDN_API_DPTX_ReadLinkStat_blocking(state_struct *state,
+ S_LINK_STAT *stat);
+
+/**
+ * \brief start link training
+ */
+CDN_API_STATUS CDN_API_DPTX_TrainingControl(state_struct *state, u8 val);
+/**
+ * \brief blocking version of #CDN_API_DPTX_TrainingControl
+ */
+CDN_API_STATUS CDN_API_DPTX_TrainingControl_blocking(state_struct *state,
+ u8 val);
+
+/**
+ * \brief check if last auxilary transaction succedd
+ */
+CDN_API_STATUS CDN_API_DPTX_GetLastAuxStatus(state_struct *state, u8 *resp);
+/**
+ * \brief blocking version of #CDN_API_DPTX_GetLastAuxStatus
+ */
+CDN_API_STATUS CDN_API_DPTX_GetLastAuxStatus_blocking(state_struct *state,
+ u8 *resp);
+
+/**
+ * \brief get current hpd status
+ */
+
+CDN_API_STATUS CDN_API_DPTX_GetHpdStatus(state_struct *state, u8 *resp);
+/**
+ * \brief blocking version of #CDN_API_DPTX_GetHpdStatus
+ */
+CDN_API_STATUS CDN_API_DPTX_GetHpdStatus_blocking(state_struct *state,
+ u8 *resp);
+
+/**
+ * \brief force the lanes to specific swing or preemphasis, with SSc or without to pattern (0=PRBS7 or 1=D10.2) for CTS or debug phy purpose
+ */
+CDN_API_STATUS CDN_API_DPTX_ForceLanes(state_struct *state, u8 linkRate,
+ u8 numOfLanes,
+ u8 voltageSwing_l0,
+ u8 preemphasis_l0,
+ u8 voltageSwing_l1,
+ u8 preemphasis_l1,
+ u8 voltageSwing_l2,
+ u8 preemphasis_l2,
+ u8 voltageSwing_l3,
+ u8 preemphasis_l3, u8 pattern, u8 ssc);
+
+/**
+ * \brief blocking version of #CDN_API_DPTX_ForceLanes
+ */
+CDN_API_STATUS CDN_API_DPTX_ForceLanes_blocking(state_struct *state,
+ u8 linkRate, u8 numOfLanes,
+ u8 voltageSwing_l0,
+ u8 preemphasis_l0,
+ u8 voltageSwing_l1,
+ u8 preemphasis_l1,
+ u8 voltageSwing_l2,
+ u8 preemphasis_l2,
+ u8 voltageSwing_l3,
+ u8 preemphasis_l3, u8 pattern,
+ u8 ssc);
+
+/**
+ * \brief Sets DP TX debug related features.
+ */
+CDN_API_STATUS CDN_API_DPTX_SetDbg(state_struct *state, u32 dbg_cfg);
+
+/**
+ * \brief blocking version of #CDN_API_DPTX_SetDbg
+ */
+CDN_API_STATUS CDN_API_DPTX_SetDbg_blocking(state_struct *state, u32 dbg_cfg);
+
+#endif
diff --git a/drivers/mxc/hdp/API_General.c b/drivers/mxc/hdp/API_General.c
new file mode 100644
index 000000000000..85c0b61963f2
--- /dev/null
+++ b/drivers/mxc/hdp/API_General.c
@@ -0,0 +1,510 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_General.c
+ *
+ ******************************************************************************
+ */
+
+#include "API_General.h"
+#include "address.h"
+#include "apb_cfg.h"
+#include "opcodes.h"
+#include "general_handler.h"
+#include "util.h"
+
+static u32 alive;
+
+CDN_API_STATUS CDN_API_LoadFirmware(state_struct *state, u8 *iMem,
+ int imemSize, u8 *dMem, int dmemSize)
+{
+ int i;
+ for (i = 0; i < imemSize; i += 4)
+ if (cdn_apb_write(state, ADDR_IMEM + i,
+ (u32) iMem[i] << 0 |
+ (u32) iMem[i + 1] << 8 |
+ (u32) iMem[i + 2] << 16 |
+ (u32) iMem[i + 3] << 24))
+ return CDN_ERR;
+ for (i = 0; i < dmemSize; i += 4)
+ if (cdn_apb_write(state, ADDR_DMEM + i,
+ (u32) dMem[i] << 0 |
+ (u32) dMem[i + 1] << 8 |
+ (u32) dMem[i + 2] << 16 |
+ (u32) dMem[i + 3] << 24))
+ return CDN_ERR;
+
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_General_Test_Echo(state_struct *state, u32 val,
+ CDN_BUS_TYPE bus_type)
+{
+ CDN_API_STATUS ret;
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ state->bus_type = bus_type;
+ state->rxEnable = 1;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_GENERAL,
+ GENERAL_TEST_ECHO, 1, 4, val);
+ return CDN_STARTED;
+ }
+ if (state->txEnable && !internal_mbox_tx_process(state).txend)
+ return CDN_BSY;
+ if (state->rxEnable && !internal_mbox_rx_process(state).rxend)
+ return CDN_BSY;
+ ret = internal_test_rx_head(state, MB_MODULE_ID_GENERAL,
+ GENERAL_TEST_ECHO);
+ if (ret != CDN_OK) {
+ state->running = 0;
+ return ret;
+ }
+ state->running = 0;
+ if (val != internal_betoi(state->rxBuffer + INTERNAL_CMD_HEAD_SIZE, 4))
+ return CDN_ERR;
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_General_Test_Echo_blocking(state_struct *state, u32 val,
+ CDN_BUS_TYPE bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_General_Test_Echo
+ (state, val, bus_type));
+}
+
+CDN_API_STATUS CDN_API_General_Test_Echo_Ext(state_struct *state,
+ u8 const *msg, u8 *resp,
+ u16 num_bytes,
+ CDN_BUS_TYPE bus_type)
+{
+ CDN_API_STATUS ret;
+
+ if (!msg || !resp) {
+ return CDN_ERR;
+ }
+
+ if ((num_bytes > GENERAL_TEST_ECHO_MAX_PAYLOAD)
+ || (num_bytes < GENERAL_TEST_ECHO_MIN_PAYLOAD)) {
+ return CDN_ERR;
+ }
+
+ if (!state->running) {
+ if (!internal_apb_available(state)) {
+ return CDN_BSY;
+ }
+
+ state->bus_type = bus_type;
+ state->rxEnable = 1;
+
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_GENERAL,
+ GENERAL_TEST_ECHO, 1, -num_bytes, msg);
+
+ return CDN_STARTED;
+ }
+
+ if (state->txEnable && !internal_mbox_tx_process(state).txend) {
+ return CDN_BSY;
+ }
+
+ if (state->rxEnable && !internal_mbox_rx_process(state).rxend) {
+ return CDN_BSY;
+ }
+
+ ret =
+ internal_test_rx_head(state, MB_MODULE_ID_GENERAL,
+ GENERAL_TEST_ECHO);
+
+ if (ret != CDN_OK) {
+ state->running = 0;
+ return ret;
+ }
+
+ state->running = 0;
+
+ memcpy(resp, state->rxBuffer + INTERNAL_CMD_HEAD_SIZE, num_bytes);
+
+ if (memcmp(msg, resp, num_bytes) != 0) {
+ return CDN_ERR;
+ }
+
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_General_Test_Echo_Ext_blocking(state_struct *state,
+ u8 const *msg, u8 *resp,
+ u16 num_bytes,
+ CDN_BUS_TYPE bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_General_Test_Echo_Ext
+ (state, msg, resp, num_bytes, bus_type));
+}
+
+CDN_API_STATUS CDN_API_General_getCurVersion(state_struct *state, u16 *ver,
+ u16 *verlib)
+{
+ u32 vh, vl, vlh, vll;
+ if (cdn_apb_read(state, VER_L << 2, &vl))
+ return CDN_ERR;
+ if (cdn_apb_read(state, VER_H << 2, &vh))
+ return CDN_ERR;
+ if (cdn_apb_read(state, VER_LIB_L_ADDR << 2, &vll))
+ return CDN_ERR;
+ if (cdn_apb_read(state, VER_LIB_H_ADDR << 2, &vlh))
+ return CDN_ERR;
+ *ver = F_VER_MSB_RD(vh) << 8 | F_VER_LSB_RD(vl);
+ *verlib = F_SW_LIB_VER_H_RD(vlh) << 8 | F_SW_LIB_VER_L_RD(vll);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_Get_Event(state_struct *state, u32 *events)
+{
+ u32 evt[4] = { 0 };
+
+ if (!events) {
+ return CDN_ERR;
+ }
+
+ if (cdn_apb_read(state, SW_EVENTS0 << 2, &evt[0])
+ || cdn_apb_read(state, SW_EVENTS1 << 2, &evt[1])
+ || cdn_apb_read(state, SW_EVENTS2 << 2, &evt[2])
+ || cdn_apb_read(state, SW_EVENTS3 << 2, &evt[3])) {
+ printk("Failed to read events registers.\n");
+
+ return CDN_ERR;
+ }
+
+ *events = (evt[0] & 0xFF)
+ | ((evt[1] & 0xFF) << 8)
+ | ((evt[2] & 0xFF) << 16)
+ | ((evt[3] & 0xFF) << 24);
+
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_Get_Debug_Reg_Val(state_struct *state, u16 *val)
+{
+ u32 dbg[2] = { 0 };
+
+ if (!val) {
+ printk("val pointer is NULL!\n");
+ return CDN_ERR;
+ }
+
+ if (cdn_apb_read(state, SW_DEBUG_L << 2, &dbg[0])
+ || cdn_apb_read(state, SW_DEBUG_H << 2, &dbg[1])) {
+ printk("Failed to read debug registers.\n");
+
+ return CDN_ERR;
+ }
+
+ *val = (u16) ((dbg[0] & 0xFF) | ((dbg[1] & 0xFF) << 8));
+
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_CheckAlive(state_struct *state)
+{
+ u32 newalive;
+ if (cdn_apb_read(state, KEEP_ALIVE << 2, &newalive))
+ return CDN_ERR;
+ if (alive == newalive)
+ return CDN_BSY;
+ alive = newalive;
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_CheckAlive_blocking(state_struct *state)
+{
+ internal_block_function(&state->mutex, CDN_API_CheckAlive(state));
+}
+
+CDN_API_STATUS CDN_API_MainControl(state_struct *state, u8 mode, u8 *resp)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ state->bus_type = CDN_BUS_TYPE_APB;
+ state->rxEnable = 1;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_GENERAL,
+ GENERAL_MAIN_CONTROL, 1, 1, mode);
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ internal_opcode_ok_or_return(state, MB_MODULE_ID_GENERAL,
+ GENERAL_MAIN_CONTROL_RESP);
+ internal_readmsg(state, 1, 1, resp);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_MainControl_blocking(state_struct *state, u8 mode,
+ u8 *resp)
+{
+ internal_block_function(&state->mutex, CDN_API_MainControl(state, mode, resp));
+}
+
+CDN_API_STATUS CDN_API_ApbConf(state_struct *state, u8 dpcd_bus_sel,
+ u8 dpcd_bus_lock, u8 hdcp_bus_sel,
+ u8 hdcp_bus_lock, u8 capb_bus_sel,
+ u8 capb_bus_lock, u8 *dpcd_resp, u8 *hdcp_resp,
+ u8 *capb_resp)
+{
+ u8 resp;
+ u8 set = 0;
+
+ if (!state->running) {
+ if (!internal_apb_available(state)) {
+ return CDN_BSY;
+ }
+
+ state->bus_type = CDN_BUS_TYPE_APB;
+ state->rxEnable = 1;
+
+ set |= (dpcd_bus_sel)
+ ? (1 << GENERAL_BUS_SETTINGS_DPCD_BUS_BIT)
+ : 0;
+ set |= (dpcd_bus_lock)
+ ? (1 << GENERAL_BUS_SETTINGS_DPCD_BUS_LOCK_BIT)
+ : 0;
+ set |= (hdcp_bus_sel)
+ ? (1 << GENERAL_BUS_SETTINGS_HDCP_BUS_BIT)
+ : 0;
+ set |= (hdcp_bus_lock)
+ ? (1 << GENERAL_BUS_SETTINGS_HDCP_BUS_LOCK_BIT)
+ : 0;
+ set |= (capb_bus_sel)
+ ? (1 << GENERAL_BUS_SETTINGS_CAPB_OWNER_BIT)
+ : 0;
+ set |= (capb_bus_lock)
+ ? (1 << GENERAL_BUS_SETTINGS_CAPB_OWNER_LOCK_BIT)
+ : 0;
+
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_GENERAL,
+ GENERAL_BUS_SETTINGS, 1, 1, set);
+
+ return CDN_STARTED;
+ }
+
+ internal_process_messages(state);
+ internal_opcode_ok_or_return(state, MB_MODULE_ID_GENERAL,
+ GENERAL_BUS_SETTINGS_RESP);
+
+ /* Read one one-byte response */
+ internal_readmsg(state, 1, 1, &resp);
+
+ *dpcd_resp =
+ (resp & (1 << GENERAL_BUS_SETTINGS_RESP_DPCD_BUS_BIT)) ? 1 : 0;
+ *hdcp_resp =
+ (resp & (1 << GENERAL_BUS_SETTINGS_RESP_HDCP_BUS_BIT)) ? 1 : 0;
+ *capb_resp =
+ (resp & (1 << GENERAL_BUS_SETTINGS_RESP_CAPB_OWNER_BIT)) ? 1 : 0;
+
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_ApbConf_blocking(state_struct *state, u8 dpcd_bus_sel,
+ u8 dpcd_bus_lock,
+ u8 hdcp_bus_sel,
+ u8 hdcp_bus_lock,
+ u8 capb_bus_sel,
+ u8 capb_bus_lock,
+ u8 *dpcd_resp,
+ u8 *hdcp_resp, u8 *capb_resp)
+{
+ internal_block_function(&state->mutex, CDN_API_ApbConf
+ (state, dpcd_bus_sel, dpcd_bus_lock,
+ hdcp_bus_sel, hdcp_bus_lock, capb_bus_sel,
+ capb_bus_lock, dpcd_resp, hdcp_resp,
+ capb_resp));
+}
+
+CDN_API_STATUS CDN_API_SetClock(state_struct *state, u8 MHz)
+{
+ return cdn_apb_write(state, SW_CLK_H << 2, MHz);
+}
+
+CDN_API_STATUS CDN_API_GetClock(state_struct *state, u32 *MHz)
+{
+ return cdn_apb_read(state, SW_CLK_H << 2, MHz);
+}
+
+CDN_API_STATUS CDN_API_General_Read_Register(state_struct *state, u32 addr,
+ GENERAL_Read_Register_response *resp)
+{
+ CDN_API_STATUS ret;
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_GENERAL,
+ GENERAL_READ_REGISTER, 1, 4, addr);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ state->rxEnable = 1;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ ret = internal_test_rx_head(state, MB_MODULE_ID_GENERAL,
+ GENERAL_READ_REGISTER_RESP);
+ if (ret != CDN_OK)
+ return ret;
+ internal_readmsg(state, 2, 4, &resp->addr, 4, &resp->val);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_General_Read_Register_blocking(state_struct *state,
+ u32 addr, GENERAL_Read_Register_response *resp)
+{
+ internal_block_function(&state->mutex, CDN_API_General_Read_Register
+ (state, addr, resp));
+}
+
+CDN_API_STATUS CDN_API_General_Write_Register(state_struct *state, u32 addr,
+ u32 val)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_GENERAL,
+ GENERAL_WRITE_REGISTER, 2, 4, addr, 4,
+ val);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_General_Write_Register_blocking(state_struct *state,
+ u32 addr, u32 val)
+{
+ internal_block_function(&state->mutex, CDN_API_General_Write_Register
+ (state, addr, val));
+}
+
+CDN_API_STATUS CDN_API_General_Write_Field(state_struct *state, u32 addr,
+ u8 startBit, u8 bitsNo, u32 val)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_GENERAL,
+ GENERAL_WRITE_FIELD, 4, 4, addr, 1,
+ startBit, 1, bitsNo, 4, val);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_General_Write_Field_blocking(state_struct *state,
+ u32 addr, u8 startBit,
+ u8 bitsNo, u32 val)
+{
+ internal_block_function(&state->mutex, CDN_API_General_Write_Field
+ (state, addr, startBit, bitsNo, val));
+}
+
+CDN_API_STATUS CDN_API_General_Phy_Test_Access(state_struct *state, u8 *resp)
+{
+ CDN_API_STATUS ret;
+
+ *resp = 0;
+
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_GENERAL,
+ GENERAL_TEST_ACCESS, 0);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ state->rxEnable = 1;
+
+ return CDN_STARTED;
+ }
+
+ internal_process_messages(state);
+
+ ret =
+ internal_test_rx_head(state, MB_MODULE_ID_GENERAL,
+ GENERAL_TEST_ACCESS);
+
+ if (ret != CDN_OK)
+ return ret;
+
+ internal_readmsg(state, 1, 1, resp);
+
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_General_Phy_Test_Access_blocking(state_struct *state,
+ u8 *resp)
+{
+ internal_block_function(&state->mutex, CDN_API_General_Phy_Test_Access(state, resp));
+}
+
+CDN_API_STATUS CDN_API_General_GetHpdState(state_struct *state, u8 *hpd_state)
+{
+ CDN_API_STATUS ret;
+ *hpd_state = 0;
+
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_GENERAL, GENERAL_GET_HPD_STATE, 0);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ state->rxEnable = 1;
+ return CDN_STARTED;
+ }
+
+ internal_process_messages(state);
+ ret = internal_test_rx_head(state, MB_MODULE_ID_GENERAL, GENERAL_GET_HPD_STATE);
+ if (ret != CDN_OK)
+ return ret;
+
+ internal_readmsg(state, 1, 1, hpd_state);
+
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_General_GetHpdState_blocking(state_struct *state, u8 *hpd_state)
+{
+ internal_block_function(&state->mutex, CDN_API_General_GetHpdState(state, hpd_state));
+}
diff --git a/drivers/mxc/hdp/API_General.h b/drivers/mxc/hdp/API_General.h
new file mode 100644
index 000000000000..1a17a208288a
--- /dev/null
+++ b/drivers/mxc/hdp/API_General.h
@@ -0,0 +1,248 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_General.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef API_GENERAL_H_
+#define API_GENERAL_H_
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/io.h>
+#include "util.h"
+
+#define GENERAL_TEST_ECHO_MAX_PAYLOAD 100
+#define GENERAL_TEST_ECHO_MIN_PAYLOAD 1
+
+/**
+ * GENERAL_Read_Register response struct
+ */
+typedef struct {
+ u32 addr;
+ u32 val;
+} GENERAL_Read_Register_response;
+
+/**
+ * \brief set up API, must be called before any other API call
+ */
+void CDN_API_Init(state_struct *state);
+
+/**
+ * \brief Loads firmware
+ *
+ * \param iMem - pointer to instruction memory
+ * \param imemSize - size of instruction memory buffer
+ * \param dMem - pointer to data memory
+ * \param dmemSize - size of data memory buffer
+ * \return 0 if success, 1 if apb error encountered, 2 if CPU isn't alive after loading firmware
+ *
+ * This function does not require initialisation by #CDN_API_Init
+ */
+
+CDN_API_STATUS CDN_API_LoadFirmware(state_struct *state, u8 *iMem,
+ int imemSize, u8 *dMem, int dmemSize);
+
+/**
+ * \brief debug echo command for APB
+ * \param val - value to echo
+ * \return status
+ *
+ * will return #CDN_ERROR if reply message doesn't match request
+ */
+CDN_API_STATUS CDN_API_General_Test_Echo(state_struct *state, u32 val,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief blocking version of #CDN_API_General_Test_Echo
+ */
+CDN_API_STATUS CDN_API_General_Test_Echo_blocking(state_struct *state, u32 val,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief Extended Echo test for mailbox.
+ *
+ * This test will send msg buffer to firmware's mailbox and receive it back to
+ * the resp buffer. Received data will be check against data sent and status will
+ * be returned as well as received data.
+ *
+ * \param msg - Pointer to a buffer to send.
+ * \param resp - Pointer to buffer for receiving msg payload back.
+ * \param num_bytes - Number of bytes to send and receive.
+ * \param bus_type Bus type.
+ * \return status
+ *
+ * will return #CDN_ERROR if reply message doesn't match request or if
+ * arguments are invalid.
+ */
+CDN_API_STATUS CDN_API_General_Test_Echo_Ext(state_struct *state,
+ u8 const *msg, u8 *resp,
+ u16 num_bytes,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief blocking version of #CDN_API_General_Test_Echo_Ext
+ */
+CDN_API_STATUS CDN_API_General_Test_Echo_Ext_blocking(state_struct *state,
+ u8 const *msg, u8 *resp,
+ u16 num_bytes,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief get current version
+ * \param [out] ver - fw version
+ * \param [out] libver - lib version
+ * \return status
+ *
+ * this fucntion does not require #CDN_API_Init
+ */
+CDN_API_STATUS CDN_API_General_getCurVersion(state_struct *state, u16 *ver,
+ u16 *verlib);
+
+/**
+ * \brief read event value
+ * \param [out] event - pointer to store 32-bit events value
+ * \return status
+ *
+ * this function does not require #CDN_API_Init
+ */
+CDN_API_STATUS CDN_API_Get_Event(state_struct *state, u32 *events);
+
+/**
+ * \brief read debug register value
+ * \param [out] val - pointer to store 16-bit debug reg value
+ * \return status
+ *
+ * this function does not require #CDN_API_Init
+ */
+CDN_API_STATUS CDN_API_Get_Debug_Reg_Val(state_struct *state, u16 *val);
+
+/**
+ * \brief check if KEEP_ALIVE register changed
+ * \return #CDN_BSY if KEEP_ALIVE not changed, #CDN_OK if changed and #CDN_ERR if error occured while reading
+ */
+CDN_API_STATUS CDN_API_CheckAlive(state_struct *state);
+
+/**
+ * \breif blocking version of #CDN_API_CheckAlive
+ * blocks untill KEEP_ALIVE register changes or error occurs while reading
+ */
+CDN_API_STATUS CDN_API_CheckAlive_blocking(state_struct *state);
+
+/**
+ * \brief set cpu to standby or active
+ * \param [in] state - 1 for active, 0 for standby
+ * \return status
+ */
+CDN_API_STATUS CDN_API_MainControl(state_struct *state, u8 mode, u8 *resp);
+
+/**
+ * \breif blocking version of #CDN_API_MainControl
+ */
+CDN_API_STATUS CDN_API_MainControl_blocking(state_struct *state, u8 mode,
+ u8 *resp);
+
+/**
+ * \brief settings for APB
+ *
+ * Sends GENERAL_APB_CONF Command via regular Mailbox.
+ * @param dpcd_bus_sel Set DPCD to use selected bus (0 for APB or 1 for SAPB)
+ * @param dpcd_bus_lock Lock bus type. Aftern that bus type cannot be changed
+ * by using this function.
+ * @param hdcp_bus_sel Same meaning as for DPCD but for HDCP.
+ * @param hdcp_bus_lock Same meaning as for DPCD but for HDCP.
+ * @param capb_bus_sel Same meaning as for DPCD but for Cipher APB.
+ * @param capb_bus_lock Same meaning as for DPCD but for Cipher APB.
+ * @param dpcd_resp [out] Status of the operation.
+ * If set to zero then DPCD bus type was successfuly changed.
+ * If not then error occurred, most likely due to locked DPCD bus.
+ * @param hdcp_resp [out] Same as for DPCD but for HDCP.
+ * @param capb_resp [out] Same as for DPCD but for Cipher APB.
+ *
+ * \return status
+ */
+CDN_API_STATUS CDN_API_ApbConf(state_struct *state, u8 dpcd_bus_sel,
+ u8 dpcd_bus_lock, u8 hdcp_bus_sel,
+ u8 hdcp_bus_lock, u8 capb_bus_sel,
+ u8 capb_bus_lock, u8 *dpcd_resp, u8 *hdcp_resp,
+ u8 *capb_resp);
+
+/**
+ * blocking version of #CDN_API_MainControl
+ */
+CDN_API_STATUS CDN_API_ApbConf_blocking(state_struct *state, u8 dpcd_bus_sel,
+ u8 dpcd_bus_lock,
+ u8 hdcp_bus_sel,
+ u8 hdcp_bus_lock,
+ u8 capb_bus_sel,
+ u8 capb_bus_lock,
+ u8 *dpcd_resp,
+ u8 *hdcp_resp, u8 *capb_resp);
+
+/**
+ * \brief set the xtensa clk, write this api before turn on the cpu
+ */
+CDN_API_STATUS CDN_API_SetClock(state_struct *state, u8 MHz);
+
+CDN_API_STATUS CDN_API_GetClock(state_struct *state, u32 *MHz);
+
+CDN_API_STATUS CDN_API_General_Read_Register(state_struct *state, u32 addr,
+ GENERAL_Read_Register_response *resp);
+CDN_API_STATUS CDN_API_General_Read_Register_blocking(state_struct *state,
+ u32 addr, GENERAL_Read_Register_response *resp);
+CDN_API_STATUS CDN_API_General_Write_Register(state_struct *state, u32 addr,
+ u32 val);
+CDN_API_STATUS CDN_API_General_Write_Register_blocking(state_struct *state,
+ u32 addr, u32 val);
+CDN_API_STATUS CDN_API_General_Write_Field(state_struct *state, u32 addr,
+ u8 startBit, u8 bitsNo, u32 val);
+CDN_API_STATUS CDN_API_General_Write_Field_blocking(state_struct *state,
+ u32 addr, u8 startBit,
+ u8 bitsNo, u32 val);
+CDN_API_STATUS CDN_API_General_Phy_Test_Access(state_struct *state, u8 *resp);
+CDN_API_STATUS CDN_API_General_Phy_Test_Access_blocking(state_struct *state,
+ u8 *resp);
+CDN_API_STATUS CDN_API_General_GetHpdState(state_struct *state, u8 *hpd_state);
+
+CDN_API_STATUS CDN_API_General_GetHpdState_blocking(state_struct *state, u8 *hpd_state);
+#endif
diff --git a/drivers/mxc/hdp/API_HDCP.c b/drivers/mxc/hdp/API_HDCP.c
new file mode 100644
index 000000000000..27b281ca2905
--- /dev/null
+++ b/drivers/mxc/hdp/API_HDCP.c
@@ -0,0 +1,454 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * API_HDCP.c
+ *
+ ******************************************************************************
+ */
+
+#include "API_HDCP.h"
+#include "util.h"
+#include "address.h"
+#include "opcodes.h"
+#include "hdcp2.h"
+
+CDN_API_STATUS CDN_API_HDCP_TX_CONFIGURATION(state_struct *state, u8 val,
+ CDN_BUS_TYPE bus_type)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ state->bus_type = bus_type;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDCP_TX,
+ HDCP_TX_CONFIGURATION, 1, 1, val);
+ return CDN_STARTED;
+ }
+ if (state->txEnable && !internal_mbox_tx_process(state).txend)
+ return CDN_BSY;
+ state->running = 0;
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDCP_TX_CONFIGURATION_blocking(state_struct *state,
+ u8 val,
+ CDN_BUS_TYPE bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_HDCP_TX_CONFIGURATION
+ (state, val, bus_type));
+}
+
+CDN_API_STATUS
+CDN_API_HDCP2_TX_SET_PUBLIC_KEY_PARAMS(state_struct *state,
+ S_HDCP_TRANS_PUBLIC_KEY_PARAMS *val,
+ CDN_BUS_TYPE bus_type)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ state->bus_type = bus_type;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDCP_TX,
+ HDCP2_TX_SET_PUBLIC_KEY_PARAMS, 2,
+ -sizeof(val->N), &val->N, -sizeof(val->E),
+ &val->E);
+ return CDN_STARTED;
+ }
+ if (state->txEnable && !internal_mbox_tx_process(state).txend)
+ return CDN_BSY;
+ state->running = 0;
+ return CDN_OK;
+}
+
+CDN_API_STATUS
+CDN_API_HDCP2_TX_SET_PUBLIC_KEY_PARAMS_blocking(state_struct *state,
+ S_HDCP_TRANS_PUBLIC_KEY_PARAMS *val,
+ CDN_BUS_TYPE bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_HDCP2_TX_SET_PUBLIC_KEY_PARAMS
+ (state, val, bus_type));
+}
+
+CDN_API_STATUS CDN_API_HDCP2_TX_SET_KM_KEY_PARAMS(state_struct *state,
+ S_HDCP_TRANS_KM_KEY_PARAMS *val,
+ CDN_BUS_TYPE bus_type)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+
+ state->bus_type = bus_type;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDCP_TX,
+ HDCP2_TX_SET_KM_KEY_PARAMS, 1,
+ -sizeof(val->KM_KEY), &val->KM_KEY);
+
+ return CDN_STARTED;
+ }
+
+ if (state->txEnable && !internal_mbox_tx_process(state).txend)
+ return CDN_BSY;
+
+ state->running = 0;
+
+ return CDN_OK;
+}
+
+CDN_API_STATUS
+CDN_API_HDCP2_TX_SET_KM_KEY_PARAMS_blocking(state_struct *state,
+ S_HDCP_TRANS_KM_KEY_PARAMS *val,
+ CDN_BUS_TYPE bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_HDCP2_TX_SET_KM_KEY_PARAMS
+ (state, val, bus_type));
+}
+
+CDN_API_STATUS
+CDN_API_HDCP2_TX_SET_DEBUG_RANDOM_NUMBERS(state_struct *state,
+ S_HDCP_TRANS_DEBUG_RANDOM_NUMBERS *val,
+ CDN_BUS_TYPE bus_type)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ state->bus_type = bus_type;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDCP_TX,
+ HDCP2_TX_SET_DEBUG_RANDOM_NUMBERS, 5,
+ -sizeof(val->KM), &val->KM,
+ -sizeof(val->RN), &val->RN,
+ -sizeof(val->KS), &val->KS,
+ -sizeof(val->RIV), &val->RIV,
+ -sizeof(val->RTX), &val->RTX);
+ return CDN_STARTED;
+ }
+ if (state->txEnable && !internal_mbox_tx_process(state).txend)
+ return CDN_BSY;
+ state->running = 0;
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDCP2_TX_SET_DEBUG_RANDOM_NUMBERS_blocking(
+ state_struct *state,
+ S_HDCP_TRANS_DEBUG_RANDOM_NUMBERS *val,
+ CDN_BUS_TYPE bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_HDCP2_TX_SET_DEBUG_RANDOM_NUMBERS
+ (state, val, bus_type));
+}
+
+CDN_API_STATUS CDN_API_HDCP2_TX_RESPOND_KM(state_struct *state,
+ S_HDCP_TRANS_PAIRING_DATA *val,
+ CDN_BUS_TYPE bus_type)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ state->bus_type = bus_type;
+ /* pairing info found in storage */
+ if (val != NULL)
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDCP_TX,
+ HDCP2_TX_RESPOND_KM, 4,
+ -sizeof(val->Receiver_ID),
+ &val->Receiver_ID,
+ -sizeof(val->m), &val->m,
+ -sizeof(val->KM), &val->KM,
+ -sizeof(val->EKH), &val->EKH);
+ else
+ /* no pairing info found in storage */
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDCP_TX,
+ HDCP2_TX_RESPOND_KM, 0);
+ return CDN_STARTED;
+ }
+ if (state->txEnable && !internal_mbox_tx_process(state).txend)
+ return CDN_BSY;
+ state->running = 0;
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDCP2_TX_RESPOND_KM_blocking(state_struct *state,
+ S_HDCP_TRANS_PAIRING_DATA *val,
+ CDN_BUS_TYPE bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_HDCP2_TX_RESPOND_KM
+ (state, val, bus_type));
+}
+
+CDN_API_STATUS
+CDN_API_HDCP1_TX_SEND_KEYS(state_struct *state,
+ S_HDCP_TX_MAIL_BOX_CMD_HDCP1_TX_SEND_KEYS *val,
+ CDN_BUS_TYPE bus_type)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ state->bus_type = bus_type;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDCP_TX,
+ HDCP1_TX_SEND_KEYS, 2, -sizeof(val->AKSV),
+ &val->AKSV, -sizeof(val->KSV), &val->KSV);
+ return CDN_STARTED;
+ }
+ if (state->txEnable && !internal_mbox_tx_process(state).txend)
+ return CDN_BSY;
+ state->running = 0;
+ return CDN_OK;
+}
+
+CDN_API_STATUS
+CDN_API_HDCP1_TX_SEND_KEYS_blocking(state_struct *state,
+ S_HDCP_TX_MAIL_BOX_CMD_HDCP1_TX_SEND_KEYS *val,
+ CDN_BUS_TYPE bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_HDCP1_TX_SEND_KEYS
+ (state, val, bus_type));
+}
+
+CDN_API_STATUS CDN_API_HDCP1_TX_SEND_RANDOM_AN(state_struct *state, u8 An[8],
+ CDN_BUS_TYPE bus_type)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ state->bus_type = bus_type;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDCP_TX,
+ HDCP1_TX_SEND_RANDOM_AN, 1, -8, An);
+ return CDN_STARTED;
+ }
+ if (state->txEnable && !internal_mbox_tx_process(state).txend)
+ return CDN_BSY;
+ state->running = 0;
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDCP1_TX_SEND_RANDOM_AN_blocking(state_struct *state,
+ u8 An[8], CDN_BUS_TYPE bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_HDCP1_TX_SEND_RANDOM_AN
+ (state, An, bus_type));
+}
+
+CDN_API_STATUS CDN_API_HDCP_TX_STATUS_REQ(state_struct *state,
+ u8 *resp, CDN_BUS_TYPE bus_type)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ state->bus_type = bus_type;
+ state->rxEnable = 1;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDCP_TX,
+ HDCP_TX_STATUS_CHANGE, 0);
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ internal_opcode_match_or_return(state);
+ internal_readmsg(state, 1, -5, resp);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDCP_TX_STATUS_REQ_blocking(state_struct *state,
+ u8 resp[5],
+ CDN_BUS_TYPE bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_HDCP_TX_STATUS_REQ
+ (state, resp, bus_type));
+}
+
+CDN_API_STATUS CDN_API_HDCP2_TX_IS_KM_STORED_REQ(state_struct *state,
+ u8 resp[5],
+ CDN_BUS_TYPE bus_type)
+{
+ printk("_debug: 0\n");
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ printk("_debug: 1\n");
+ state->bus_type = bus_type;
+ state->rxEnable = 1;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDCP_TX,
+ HDCP2_TX_IS_KM_STORED, 0);
+ printk("_debug: 2\n");
+ return CDN_STARTED;
+ }
+ printk("_debug: 3\n");
+ internal_process_messages(state);
+ printk("_debug: 4\n");
+ internal_opcode_match_or_return(state);
+ printk("_debug: 5\n");
+ internal_readmsg(state, 1, -5, resp);
+ printk("_debug: 6\n");
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDCP2_TX_IS_KM_STORED_REQ_blocking(state_struct *state,
+ u8 resp[5],
+ CDN_BUS_TYPE bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_HDCP2_TX_IS_KM_STORED_REQ
+ (state, resp, bus_type));
+}
+
+CDN_API_STATUS CDN_API_HDCP2_TX_STORE_KM_REQ(state_struct *state,
+ S_HDCP_TRANS_PAIRING_DATA *resp,
+ CDN_BUS_TYPE bus_type)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ state->bus_type = bus_type;
+ state->rxEnable = 1;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDCP_TX,
+ HDCP2_TX_STORE_KM, 0);
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ internal_opcode_match_or_return(state);
+ internal_readmsg(state, 4,
+ -sizeof(resp->Receiver_ID), &resp->Receiver_ID,
+ -sizeof(resp->m), &resp->m,
+ -sizeof(resp->KM), &resp->KM,
+ -sizeof(resp->EKH), &resp->EKH);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDCP2_TX_STORE_KM_REQ_blocking(state_struct *state,
+ S_HDCP_TRANS_PAIRING_DATA
+ *resp,
+ CDN_BUS_TYPE bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_HDCP2_TX_STORE_KM_REQ
+ (state, resp, bus_type));
+}
+
+CDN_API_STATUS CDN_API_HDCP_TX_IS_RECEIVER_ID_VALID_REQ(state_struct *state,
+ u8 *num, u8 *id,
+ CDN_BUS_TYPE bus_type)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ state->bus_type = bus_type;
+ state->rxEnable = 1;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDCP_TX,
+ HDCP_TX_IS_RECEIVER_ID_VALID, 0);
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ internal_opcode_match_or_return(state);
+ internal_readmsg(state, 1, 1, num);
+ internal_readmsg(state, 2, 1, NULL, -5 * *num, id);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDCP_TX_IS_RECEIVER_ID_VALID_REQ_blocking(
+ state_struct *state,
+ u8 *num,
+ u8 *id,
+ CDN_BUS_TYPE
+ bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_HDCP_TX_IS_RECEIVER_ID_VALID_REQ
+ (state, num, id, bus_type));
+}
+
+CDN_API_STATUS CDN_API_HDCP_TX_RESPOND_RECEIVER_ID_VALID(
+ state_struct *state,
+ u8 valid,
+ CDN_BUS_TYPE bus_type)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ state->bus_type = bus_type;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDCP_TX,
+ HDCP_TX_RESPOND_RECEIVER_ID_VALID, 1, 1,
+ valid);
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDCP_TX_RESPOND_RECEIVER_ID_VALID_blocking(
+ state_struct *state,
+ u8 valid,
+ CDN_BUS_TYPE
+ bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_HDCP_TX_RESPOND_RECEIVER_ID_VALID
+ (state, valid, bus_type));
+}
+
+CDN_API_STATUS CDN_API_HDCP_GENERAL_2_SET_LC(state_struct *state, u8 *lc,
+ CDN_BUS_TYPE bus_type)
+{
+ internal_macro_command_tx(state, MB_MODULE_ID_HDCP_GENERAL,
+ HDCP_GENERAL_SET_LC_128, bus_type, 1, -16, lc);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDCP_GENERAL_2_SET_LC_blocking(state_struct *state,
+ u8 *lc,
+ CDN_BUS_TYPE bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_HDCP_GENERAL_2_SET_LC
+ (state, lc, bus_type));
+}
+
+CDN_API_STATUS CDN_API_TEST_KEYS(state_struct *state, u8 test_type, u8 resp[1],
+ CDN_BUS_TYPE bus_type)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ state->bus_type = bus_type;
+ state->rxEnable = 1;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDCP_TX,
+ HDCP_TX_TEST_KEYS, 1, 1, test_type);
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ internal_opcode_match_or_return(state);
+ internal_readmsg(state, 1, -1, resp);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_TEST_KEYS_blocking(state_struct *state, u8 test_type,
+ u8 resp[1], CDN_BUS_TYPE bus_type)
+{
+ internal_block_function(&state->mutex, CDN_API_TEST_KEYS
+ (state, test_type, resp, bus_type));
+}
diff --git a/drivers/mxc/hdp/API_HDCP.h b/drivers/mxc/hdp/API_HDCP.h
new file mode 100644
index 000000000000..ca523225abab
--- /dev/null
+++ b/drivers/mxc/hdp/API_HDCP.h
@@ -0,0 +1,263 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * API_HDCP.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef _API_HDCP_H_
+#define _API_HDCP_H_
+
+/**
+ * \addtogroup HDCP_API
+ * \{
+ */
+
+#include "API_General.h"
+#include "hdcp_tran.h"
+
+/**
+ * \brief send HDCP_TX_CONFIGURATION command
+ * \return status
+ */
+CDN_API_STATUS CDN_API_HDCP_TX_CONFIGURATION(state_struct *state, u8 val,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief blocking version of #CDN_API_HDCP_TX_CONFIGURATION
+ */
+CDN_API_STATUS CDN_API_HDCP_TX_CONFIGURATION_blocking(state_struct *state,
+ u8 val,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief send HDCP2_TX_SET_PUBLIC_KEY_PARAMS command
+ * \return status
+ */
+CDN_API_STATUS
+CDN_API_HDCP2_TX_SET_PUBLIC_KEY_PARAMS(state_struct *state,
+ S_HDCP_TRANS_PUBLIC_KEY_PARAMS *val,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief blocking version of #CDN_API_HDCP2_TX_SET_PUBLIC_KEY_PARAMS
+ */
+CDN_API_STATUS
+CDN_API_HDCP2_TX_SET_PUBLIC_KEY_PARAMS_blocking(state_struct *state,
+ S_HDCP_TRANS_PUBLIC_KEY_PARAMS *val,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief send HDCP2_TX_SET_KM_KEY_PARAMS command
+ * \return status
+ */
+CDN_API_STATUS CDN_API_HDCP2_TX_SET_KM_KEY_PARAMS(state_struct *state,
+ S_HDCP_TRANS_KM_KEY_PARAMS *val,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief blocking version of #CDN_API_HDCP2_TX_SET_KM_KEY_PARAMS
+ */
+CDN_API_STATUS
+CDN_API_HDCP2_TX_SET_KM_KEY_PARAMS_blocking(state_struct *state,
+ S_HDCP_TRANS_KM_KEY_PARAMS *val,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief send HDCP2_TX_SET_DEBUG_RANDOM_NUMBERS command
+ * \return status
+ */
+CDN_API_STATUS
+CDN_API_HDCP2_TX_SET_DEBUG_RANDOM_NUMBERS(state_struct *state,
+ S_HDCP_TRANS_DEBUG_RANDOM_NUMBERS *val,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief blocking version of #CDN_API_HDCP2_TX_SET_DEBUG_RANDOM_NUMBERS
+ */
+CDN_API_STATUS
+ CDN_API_HDCP2_TX_SET_DEBUG_RANDOM_NUMBERS_blocking
+ (state_struct *state, S_HDCP_TRANS_DEBUG_RANDOM_NUMBERS *val,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief send HDCP2_TX_RESPOND_KM command
+ * \param val - if NULL no arguments will be send
+ * \return status
+ */
+CDN_API_STATUS CDN_API_HDCP2_TX_RESPOND_KM(state_struct *state,
+ S_HDCP_TRANS_PAIRING_DATA *val,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief blocking version of #CDN_API_HDCP2_TX_RESPOND_KM
+ */
+CDN_API_STATUS CDN_API_HDCP2_TX_RESPOND_KM_blocking(state_struct *state,
+ S_HDCP_TRANS_PAIRING_DATA *val,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief send HDCP1_TX_SEND_KEYS command
+ * \return status
+ */
+CDN_API_STATUS
+CDN_API_HDCP1_TX_SEND_KEYS(state_struct *state,
+ S_HDCP_TX_MAIL_BOX_CMD_HDCP1_TX_SEND_KEYS *val,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief blocking version of #CDN_API_HDCP1_TX_SEND_KEYS
+ */
+CDN_API_STATUS
+CDN_API_HDCP1_TX_SEND_KEYS_blocking(state_struct *state,
+ S_HDCP_TX_MAIL_BOX_CMD_HDCP1_TX_SEND_KEYS *val,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief send HDCP1_TX_SEND_RANDOM_AN command
+ * \return status
+ */
+CDN_API_STATUS CDN_API_HDCP1_TX_SEND_RANDOM_AN(state_struct *state, u8 An[8],
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief blocking version of #CDN_API_HDCP1_TX_SEND_RANDOM_AN
+ */
+CDN_API_STATUS CDN_API_HDCP1_TX_SEND_RANDOM_AN_blocking(state_struct *state,
+ u8 An[8],
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief send HDCP_TX_STATUS_REQ command
+ * \return status
+ */
+CDN_API_STATUS CDN_API_HDCP_TX_STATUS_REQ(state_struct *state, u8 resp[5],
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief blocking version of #CDN_API_HDCP_TX_STATUS_REQ
+ */
+CDN_API_STATUS CDN_API_HDCP_TX_STATUS_REQ_blocking(state_struct *state,
+ u8 resp[5],
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief send HDCP2_TX_IS_KM_STORED_REQ command
+ * \return status
+ */
+CDN_API_STATUS CDN_API_HDCP2_TX_IS_KM_STORED_REQ(state_struct *state,
+ u8 resp[5],
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief blocking version of #CDN_API_HDCP2_TX_IS_KM_STORED_REQ
+ */
+CDN_API_STATUS CDN_API_HDCP2_TX_IS_KM_STORED_REQ_blocking(state_struct *state,
+ u8 resp[5],
+ CDN_BUS_TYPE
+ bus_type);
+
+/**
+ * \brief send HDCP2_TX_STORE_KM_REQ command
+ * \return status
+ */
+CDN_API_STATUS CDN_API_HDCP2_TX_STORE_KM_REQ(state_struct *state,
+ S_HDCP_TRANS_PAIRING_DATA *resp,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief blocking version of #CDN_API_HDCP2_TX_STORE_KM_REQ
+ */
+CDN_API_STATUS CDN_API_HDCP2_TX_STORE_KM_REQ_blocking(state_struct *state,
+ S_HDCP_TRANS_PAIRING_DATA
+ *resp,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief send HDCP_TX_IS_RECEIVER_ID_VALID_REQ command
+ * \return status
+ */
+CDN_API_STATUS CDN_API_HDCP_TX_IS_RECEIVER_ID_VALID_REQ(state_struct *state,
+ u8 *num, u8 *id,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief blocking version of #CDN_API_HDCP_TX_IS_RECEIVER_ID_VALID_REQ
+ */
+CDN_API_STATUS CDN_API_HDCP_TX_IS_RECEIVER_ID_VALID_REQ_blocking(state_struct *state,
+ u8 *num,
+ u8 *id,
+ CDN_BUS_TYPE
+ bus_type);
+
+/**
+ * \brief send HDCP_TX_RESPOND_RECEIVER_ID_VALID command
+ * \return status
+ */
+CDN_API_STATUS CDN_API_HDCP_TX_RESPOND_RECEIVER_ID_VALID(state_struct *state,
+ u8 valid,
+ CDN_BUS_TYPE bus_type);
+
+/**
+ * \brief blocking version of #CDN_API_HDCP_TX_RESPOND_RECEIVER_ID_VALID
+ */
+CDN_API_STATUS CDN_API_HDCP_TX_RESPOND_RECEIVER_ID_VALID_blocking(state_struct *state,
+ u8 valid,
+ CDN_BUS_TYPE
+ bus_type);
+
+CDN_API_STATUS CDN_API_HDCP_GENERAL_2_SET_LC(state_struct *state, u8 *lc,
+ CDN_BUS_TYPE bus_type);
+CDN_API_STATUS CDN_API_HDCP_GENERAL_2_SET_LC_blocking(state_struct *state,
+ u8 *lc,
+ CDN_BUS_TYPE bus_type);
+/* TODO DK: Implement */
+CDN_API_STATUS CDN_API_HDCP_SET_SEED(state_struct *state, u8 *seed,
+ CDN_BUS_TYPE bus_type);
+CDN_API_STATUS CDN_API_HDCP_SET_SEED_blocking(state_struct *state, u8 *seed,
+ CDN_BUS_TYPE bus_type);
+CDN_API_STATUS CDN_API_TEST_KEYS(state_struct *state, u8 test_type, u8 resp[1],
+ CDN_BUS_TYPE bus_type);
+CDN_API_STATUS CDN_API_TEST_KEYS_blocking(state_struct *state, u8 test_type,
+ u8 resp[1], CDN_BUS_TYPE bus_type);
+
+#endif
diff --git a/drivers/mxc/hdp/API_HDMIRX.c b/drivers/mxc/hdp/API_HDMIRX.c
new file mode 100644
index 000000000000..7dcb9254fd06
--- /dev/null
+++ b/drivers/mxc/hdp/API_HDMIRX.c
@@ -0,0 +1,236 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_HDMIRX.c
+ *
+ ******************************************************************************
+ */
+
+#include "API_HDMIRX.h"
+#include "util.h"
+#include "opcodes.h"
+#include "address.h"
+#include "sink_vif.h"
+
+CDN_API_STATUS CDN_API_HDMIRX_ReadEvent(state_struct *state, u8 *Events_5v)
+{
+ CDN_API_STATUS ret;
+ u8 reserved1;
+ u8 reserved2;
+ u8 reserved3;
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDMI_RX, HDMI_RX_READ_EVENTS, 0);
+ state->rxEnable = 1;
+ state->bus_type = CDN_BUS_TYPE_APB;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ ret = internal_test_rx_head(state, MB_MODULE_ID_HDMI_RX, HDMI_RX_READ_EVENTS);
+ if (ret != CDN_OK)
+ return ret;
+ internal_readmsg(state,
+ 4,
+ 1,
+ Events_5v,
+ 1,
+ &reserved1,
+ 1,
+ &reserved2,
+ 1,
+ &reserved3);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDMIRX_ReadEvent_blocking(
+ state_struct *state,
+ u8 *Events_5v)
+{
+ internal_block_function(&state->mutex, CDN_API_HDMIRX_ReadEvent(state, Events_5v));
+}
+
+CDN_API_STATUS CDN_API_HDMIRX_Init_blocking(state_struct *state)
+{
+ CDN_API_STATUS ret;
+
+ ret =
+ CDN_API_General_Write_Register_blocking(state,
+ ADDR_SINK_VIDEO_HD + (VIDEO_UNPACK_CTRL << 2),
+ F_CD_ENABLE(1));
+ ret =
+ CDN_API_General_Write_Register_blocking(state,
+ ADDR_SINK_VIDEO_HD + (VANLYZ_CTRL << 2),
+ F_VANLYZ_START(1) |
+ F_VANLYZ_FRAMES_CHECK_EN(1) |
+ F_VANLYZ_FORMAT_FINDER_EN(1));
+
+ return ret;
+}
+
+CDN_API_STATUS CDN_API_HDMIRX_Stop_blocking(state_struct *state)
+{
+ CDN_API_STATUS ret;
+
+ ret =
+ CDN_API_General_Write_Register_blocking(state,
+ ADDR_SINK_VIDEO_HD + (VIDEO_UNPACK_CTRL << 2),
+ F_CD_ENABLE(0));
+ ret =
+ CDN_API_General_Write_Register_blocking(state,
+ ADDR_SINK_VIDEO_HD + (VANLYZ_CTRL << 2), F_VANLYZ_RESET(1));
+
+ return ret;
+}
+
+CDN_API_STATUS CDN_API_HDMIRX_SET_EDID(
+ state_struct *state,
+ u8 segment,
+ u8 extension,
+ u8 *edid_buff)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state,
+ MB_MODULE_ID_HDMI_RX,
+ HDMI_RX_SET_EDID,
+ 3,
+ 1,
+ segment,
+ 1,
+ extension,
+ -128,
+ edid_buff);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDMIRX_SET_EDID_blocking(
+ state_struct *state,
+ u8 segment,
+ u8 extension,
+ u8 *edid_buff)
+{
+ internal_block_function(&state->mutex,
+ CDN_API_HDMIRX_SET_EDID(state, segment, extension, edid_buff));
+}
+
+CDN_API_STATUS CDN_API_HDMIRX_SET_SCDC_SLAVE(state_struct *state,
+ S_HDMI_SCDC_SET_MSG *scdcData)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state,
+ MB_MODULE_ID_HDMI_RX,
+ HDMI_RX_SCDC_SET,
+ 1,
+ -sizeof(S_HDMI_SCDC_SET_MSG),
+ scdcData);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDMIRX_SET_SCDC_SLAVE_blocking(
+ state_struct *state,
+ S_HDMI_SCDC_SET_MSG *scdcData)
+{
+ internal_block_function(&state->mutex,
+ CDN_API_HDMIRX_SET_SCDC_SLAVE(state, scdcData));
+}
+
+CDN_API_STATUS CDN_API_HDMIRX_GET_SCDC_SLAVE(state_struct *state,
+ S_HDMI_SCDC_GET_MSG *scdcData)
+{
+ CDN_API_STATUS ret;
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDMI_RX, HDMI_RX_SCDC_GET, 0);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ state->rxEnable = 1;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ ret = internal_test_rx_head(state, MB_MODULE_ID_HDMI_RX, HDMI_RX_SCDC_GET);
+ if (ret != CDN_OK)
+ return ret;
+ internal_readmsg(state,
+ 4,
+ 1, &scdcData->source_ver,
+ 1, &scdcData->TMDS_Config,
+ 1, &scdcData->config_0,
+ -sizeof(scdcData->manufacturerSpecific),
+ &scdcData->manufacturerSpecific);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDMIRX_GET_SCDC_SLAVE_blocking(state_struct *state,
+ S_HDMI_SCDC_GET_MSG *scdcData)
+{
+ internal_block_function(&state->mutex,
+ CDN_API_HDMIRX_GET_SCDC_SLAVE(state, scdcData));
+}
+
+CDN_API_STATUS CDN_API_HDMIRX_SetHpd(state_struct *state, u8 hpd)
+{
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDMI_RX, HDMI_RX_SET_HPD, 1, 1, hpd);
+ state->bus_type = CDN_BUS_TYPE_APB;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDMIRX_SetHpd_blocking(state_struct *state, u8 hpd)
+{
+ internal_block_function(&state->mutex, CDN_API_HDMIRX_SetHpd(state, hpd));
+}
diff --git a/drivers/mxc/hdp/API_HDMIRX.h b/drivers/mxc/hdp/API_HDMIRX.h
new file mode 100644
index 000000000000..4adbe422b7a9
--- /dev/null
+++ b/drivers/mxc/hdp/API_HDMIRX.h
@@ -0,0 +1,135 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_HDMIRX.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef _API_HDMIRX_H_
+#define _API_HDMIRX_H_
+
+#include "API_General.h"
+#include "hdmi.h"
+
+/**
+ * \addtogroup HDMI_RX_API
+ * \{
+ */
+
+/**
+ * \brief init hdmi rx registers
+ * \returns status
+ */
+CDN_API_STATUS CDN_API_HDMIRX_Init_blocking(state_struct *state);
+CDN_API_STATUS CDN_API_HDMIRX_Stop_blocking(state_struct *state);
+
+/**
+ * \brief get hdmi rx events (currently 5v events)
+ * \returns status
+ */
+CDN_API_STATUS CDN_API_HDMIRX_ReadEvent(state_struct *state, u8 *Events_5v);
+
+/**
+ * \brief blocking version of CDN_API_HDMIRX_ReadEvent
+ * \returns status
+ */
+CDN_API_STATUS CDN_API_HDMIRX_ReadEvent_blocking(state_struct *state, u8 *Events_5v);
+
+
+/**
+ * \brief Cadence API for HDMI TX to set EDID
+ * \param [in] segment - EDID segment to read
+ * \param [in] extension - EDID extension to read
+ * \param [in] edid_buff - pointer to buffer with 128 bytes of edid block
+ * please note, edid_buff should be allocated\clear by caller
+ * \return status
+ *
+ */
+CDN_API_STATUS CDN_API_HDMIRX_SET_EDID(state_struct *state, u8 segment, u8 extension, u8 *edid_buff);
+/**
+ * \brief blocking version of #CDN_API_HDMIRX_SET_EDID
+ */
+CDN_API_STATUS CDN_API_HDMIRX_SET_EDID_blocking(state_struct *state, u8 segment, u8 extension, u8 *edid_buff);
+
+/**
+ * \brief Cadence API for HDMI Rx to set general scdc information
+ * \param [in] scdcData - general slave scdc information
+ * \return status
+ *
+ */
+CDN_API_STATUS CDN_API_HDMIRX_SET_SCDC_SLAVE(state_struct *state, S_HDMI_SCDC_SET_MSG *scdcData);
+
+/**
+ * \brief blocking version of #CDN_API_HDMIRX_SET_SCDC_SLAVE
+ */
+CDN_API_STATUS CDN_API_HDMIRX_SET_SCDC_SLAVE_blocking(state_struct *state, S_HDMI_SCDC_SET_MSG *scdcData);
+
+/**
+ * \brief Cadence API for HDMI Rx to get general scdc information
+ * \param [in] source_ver - SCDC register - Source Version
+ * \param [in] TMDS_Config - SCDC register - TMDS_Config
+ * \param [in] config_0 - SCDC register - Config_0
+ * \param [in] manufacturerSpecific - manufacturer specific data
+ * \return status
+ *
+ */
+CDN_API_STATUS CDN_API_HDMIRX_GET_SCDC_SLAVE(state_struct *state, S_HDMI_SCDC_GET_MSG *scdcData);
+
+/**
+ * \brief blocking version of #CDN_API_HDMIRX_GET_SCDC_SLAVE
+ */
+CDN_API_STATUS CDN_API_HDMIRX_GET_SCDC_SLAVE_blocking(state_struct *state, S_HDMI_SCDC_GET_MSG *scdcData);
+
+/**
+ * \brief Cadence API for HDMI Rx to set hpd
+ * \param [in] hpd - 0 or 1
+ * \return status
+ *
+ */
+CDN_API_STATUS CDN_API_HDMIRX_SetHpd(state_struct *state, u8 hpd);
+
+/**
+ * \brief blocking version of #CDN_API_HDMIRX_SetHpd
+ */
+CDN_API_STATUS CDN_API_HDMIRX_SetHpd_blocking(state_struct *state, u8 hpd);
+
+#endif
diff --git a/drivers/mxc/hdp/API_HDMITX.c b/drivers/mxc/hdp/API_HDMITX.c
new file mode 100644
index 000000000000..e3c1318591cb
--- /dev/null
+++ b/drivers/mxc/hdp/API_HDMITX.c
@@ -0,0 +1,520 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_HDMITX.c
+ *
+ ******************************************************************************
+ */
+
+#include "API_HDMITX.h"
+#include "util.h"
+#include "opcodes.h"
+#include "mhl_hdtx_top.h"
+#include "source_phy.h"
+#include "address.h"
+#include "source_car.h"
+#include "source_vif.h"
+#include "general_handler.h"
+#include <soc/imx8/soc.h>
+
+CDN_API_STATUS CDN_API_HDMITX_DDC_READ(state_struct *state,
+ HDMITX_TRANS_DATA *data_in,
+ HDMITX_TRANS_DATA *data_out)
+{
+ internal_macro_command_txrx(state, MB_MODULE_ID_HDMI_TX, HDMI_TX_READ,
+ CDN_BUS_TYPE_APB, 3, 1, data_in->slave, 1,
+ data_in->offset, 2, data_in->len);
+ internal_readmsg(state, 5, 1, &data_out->status, 1, &data_out->slave, 1,
+ &data_out->offset, 2, &data_out->len, 0,
+ &data_out->buff);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDMITX_DDC_READ_blocking(state_struct *state,
+ HDMITX_TRANS_DATA *data_in,
+ HDMITX_TRANS_DATA *data_out)
+{
+ internal_block_function(&state->mutex, CDN_API_HDMITX_DDC_READ
+ (state, data_in, data_out));
+}
+
+CDN_API_STATUS CDN_API_HDMITX_DDC_WRITE(state_struct *state,
+ HDMITX_TRANS_DATA *data_in,
+ HDMITX_TRANS_DATA *data_out)
+{
+ internal_macro_command_txrx(state, MB_MODULE_ID_HDMI_TX, HDMI_TX_WRITE,
+ CDN_BUS_TYPE_APB, 4, 1, data_in->slave, 1,
+ data_in->offset, 2, data_in->len,
+ -data_in->len, data_in->buff);
+ internal_readmsg(state, 4, 1, &data_out->status, 1, &data_out->slave, 1,
+ &data_out->offset, 2, &data_out->len);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDMITX_DDC_WRITE_blocking(state_struct *state,
+ HDMITX_TRANS_DATA *data_in,
+ HDMITX_TRANS_DATA *data_out)
+{
+ internal_block_function(&state->mutex, CDN_API_HDMITX_DDC_WRITE
+ (state, data_in, data_out));
+}
+
+CDN_API_STATUS CDN_API_HDMITX_DDC_UPDATE_READ(state_struct *state,
+ HDMITX_TRANS_DATA *data_out)
+{
+ internal_macro_command_txrx(state, MB_MODULE_ID_HDMI_TX,
+ HDMI_TX_UPDATE_READ, CDN_BUS_TYPE_APB, 0);
+ internal_readmsg(state, 2, 1, &data_out->status, 0, &data_out->buff);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDMITX_DDC_UPDATE_READ_blocking(state_struct *state,
+ HDMITX_TRANS_DATA *
+ data_out)
+{
+ internal_block_function(&state->mutex, CDN_API_HDMITX_DDC_UPDATE_READ
+ (state, data_out));
+}
+
+CDN_API_STATUS CDN_API_HDMITX_READ_EDID(state_struct *state, u8 block,
+ u8 segment,
+ HDMITX_TRANS_DATA *data_out)
+{
+ internal_macro_command_txrx(state, MB_MODULE_ID_HDMI_TX, HDMI_TX_EDID,
+ CDN_BUS_TYPE_APB, 2, 1, block, 1, segment);
+ internal_readmsg(state, 5, 1, &data_out->status, 1, &data_out->slave, 1,
+ &data_out->offset, 2, &data_out->len, 0,
+ &data_out->buff);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDMITX_READ_EDID_blocking(state_struct *state, u8 block,
+ u8 segment,
+ HDMITX_TRANS_DATA *data_out)
+{
+ internal_block_function(&state->mutex, CDN_API_HDMITX_READ_EDID
+ (state, block, segment, data_out));
+}
+
+CDN_API_STATUS
+CDN_API_HDMITX_Set_Mode_blocking(state_struct *state,
+ HDMI_TX_MAIL_HANDLER_PROTOCOL_TYPE protocol,
+ u32 character_rate)
+{
+ CDN_API_STATUS ret;
+ GENERAL_Read_Register_response resp;
+ HDMITX_TRANS_DATA data_in;
+ HDMITX_TRANS_DATA data_out;
+ u32 clk_reg_0, clk_reg_1;
+ u8 buff = 1;
+
+ /* enable/disable scrambler; */
+ if (protocol == HDMI_TX_MODE_HDMI_2_0) {
+ if (character_rate >= 340000) {
+ buff = 3; /* enable scrambling + TMDS_Bit_Clock_Ratio */
+ } else {
+ buff = 1; /* enable scrambling */
+ }
+ } else {
+ buff = 0; /* disable scrambling */
+ }
+
+ data_in.buff = &buff;
+ data_in.len = 1;
+ data_in.slave = 0x54;
+ data_in.offset = 0x20; /* TMDS config */
+ /* Workaround for imx8qm DDC R/W failed issue */
+ if (!cpu_is_imx8qm()) {
+ ret = CDN_API_HDMITX_DDC_WRITE_blocking(state, &data_in, &data_out);
+ pr_info("CDN_API_HDMITX_DDC_WRITE_blocking ret = %d\n", ret);
+ if (ret != CDN_OK)
+ return ret;
+ }
+
+ ret = CDN_API_General_Read_Register_blocking(
+ state, ADDR_SOURCE_MHL_HD + (HDTX_CONTROLLER << 2), &resp);
+ if (ret != CDN_OK)
+ return ret;
+
+ /* remove data enable */
+ resp.val = resp.val & (~(F_DATA_EN(1)));
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_MHL_HD +
+ (HDTX_CONTROLLER << 2),
+ resp.val);
+ if (ret != CDN_OK)
+ return ret;
+ clk_reg_0 = 0x7c1f;
+ clk_reg_1 = 0x7c1f;
+ if (protocol == HDMI_TX_MODE_HDMI_2_0) {
+ if (character_rate >= 340000) {
+ clk_reg_0 = 0;
+ clk_reg_1 = 0xFFFFF;
+ }
+ }
+ ret = CDN_API_General_Write_Register_blocking(
+ state, ADDR_SOURCE_MHL_HD + (HDTX_CLOCK_REG_0 << 2),
+ F_DATA_REGISTER_VAL_0(clk_reg_0));
+ if (ret != CDN_OK)
+ return ret;
+ ret = CDN_API_General_Write_Register_blocking(
+ state, ADDR_SOURCE_MHL_HD + (HDTX_CLOCK_REG_1 << 2),
+ F_DATA_REGISTER_VAL_1(clk_reg_1));
+ if (ret != CDN_OK)
+ return ret;
+
+ /* set hdmi mode and preemble mode */
+ resp.val = resp.val & (~(F_HDMI_MODE(3)));
+ resp.val = resp.val & (~(F_HDMI2_PREAMBLE_EN(1)));
+
+ resp.val =
+ (resp.val) | (F_HDMI_MODE(protocol)) | (F_HDMI2_PREAMBLE_EN(1));
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_MHL_HD +
+ (HDTX_CONTROLLER << 2),
+ resp.val);
+ if (ret != CDN_OK)
+ return ret;
+
+ /* data enable */
+ resp.val |= F_DATA_EN(1);
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_MHL_HD +
+ (HDTX_CONTROLLER << 2),
+ resp.val);
+ return ret;
+}
+
+CDN_API_STATUS CDN_API_HDMITX_Init_blocking(state_struct *state)
+{
+ CDN_API_STATUS ret;
+
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCD_PHY +
+ (PHY_DATA_SEL << 2),
+ F_SOURCE_PHY_MHDP_SEL(1));
+ if (ret != CDN_OK)
+ return ret;
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_MHL_HD +
+ (HDTX_HPD << 2),
+ F_HPD_VALID_WIDTH(4) |
+ F_HPD_GLITCH_WIDTH(0));
+ if (ret != CDN_OK)
+ return ret;
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_MHL_HD +
+ (HDTX_CONTROLLER << 2),
+ F_HDMI_MODE(1) |
+ F_AUTO_MODE(0) | F_GCP_EN(1)
+ | F_DATA_EN(1) |
+ F_CLEAR_AVMUTE(1) |
+ F_HDMI2_PREAMBLE_EN(1) |
+ F_HDMI2_CTRL_IL_MODE(1) |
+ F_PIC_3D(0XF) |
+ F_BCH_EN(1));
+ if (ret != CDN_OK)
+ return ret;
+ /* open CARS */
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_CAR +
+ (SOURCE_PHY_CAR << 2), 0xF);
+ if (ret != CDN_OK)
+ return ret;
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_CAR +
+ (SOURCE_HDTX_CAR << 2),
+ 0xFF);
+ if (ret != CDN_OK)
+ return ret;
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_CAR +
+ (SOURCE_PKT_CAR << 2), 0xF);
+ if (ret != CDN_OK)
+ return ret;
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_CAR +
+ (SOURCE_AIF_CAR << 2), 0xF);
+ if (ret != CDN_OK)
+ return ret;
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_CAR +
+ (SOURCE_CIPHER_CAR << 2),
+ 0xF);
+ if (ret != CDN_OK)
+ return ret;
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_CAR +
+ (SOURCE_CRYPTO_CAR << 2),
+ 0xF);
+ if (ret != CDN_OK)
+ return ret;
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_CAR +
+ (SOURCE_CEC_CAR << 2), 3);
+ if (ret != CDN_OK)
+ return ret;
+
+ /* init vif */
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_VIF +
+ (HSYNC2VSYNC_POL_CTRL << 2),
+ F_HPOL(0) | F_VPOL(0));
+ return ret;
+}
+
+CDN_API_STATUS CDN_API_HDMITX_SetVic_blocking(state_struct *state,
+ struct drm_display_mode *mode, int bpp,
+ VIC_PXL_ENCODING_FORMAT format)
+{
+ CDN_API_STATUS ret;
+ GENERAL_Read_Register_response resp;
+ u32 vsync_lines = mode->vsync_end - mode->vsync_start;
+ u32 eof_lines = mode->vsync_start - mode->vdisplay;
+ u32 sof_lines = mode->vtotal - mode->vsync_end;
+ u32 hblank = mode->htotal - mode->hdisplay;
+ u32 hactive = mode->hdisplay;
+ u32 vblank = mode->vtotal - mode->vdisplay;
+ u32 vactive = mode->vdisplay;
+ u32 hfront = mode->hsync_start - mode->hdisplay;
+ u32 hback = mode->htotal - mode->hsync_end;
+ u32 vfront = eof_lines;
+ u32 hsync = hblank - hfront - hback;
+ u32 vsync = vsync_lines;
+ u32 vback = sof_lines;
+ u32 v_h_polarity = ((mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1) +
+ ((mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : 2);
+
+ ret = CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_MHL_HD +
+ (SCHEDULER_H_SIZE << 2),
+ (hactive << 16) + hblank);
+ if (ret != CDN_OK)
+ return ret;
+
+ ret = CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_MHL_HD +
+ (SCHEDULER_V_SIZE << 2),
+ (vactive << 16) + vblank);
+ if (ret != CDN_OK)
+ return ret;
+
+ ret = CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_MHL_HD +
+ (HDTX_SIGNAL_FRONT_WIDTH <<
+ 2),
+ (vfront << 16) + hfront);
+ if (ret != CDN_OK)
+ return ret;
+
+ ret = CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_MHL_HD +
+ (HDTX_SIGNAL_SYNC_WIDTH <<
+ 2), (vsync << 16) + hsync);
+ if (ret != CDN_OK)
+ return ret;
+
+ ret = CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_MHL_HD +
+ (HDTX_SIGNAL_BACK_WIDTH <<
+ 2), (vback << 16) + hback);
+ if (ret != CDN_OK)
+ return ret;
+
+ ret = CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_VIF +
+ (HSYNC2VSYNC_POL_CTRL << 2),
+ v_h_polarity);
+ if (ret != CDN_OK)
+ return ret;
+
+ /* Reset Data Enable */
+ CDN_API_General_Read_Register_blocking(state, ADDR_SOURCE_MHL_HD +
+ (HDTX_CONTROLLER << 2), &resp);
+ if (ret != CDN_OK)
+ return ret;
+
+ /* reset data enable */
+ resp.val = resp.val & (~(F_DATA_EN(1)));
+ ret = CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_MHL_HD +
+ (HDTX_CONTROLLER << 2),
+ resp.val);
+ if (ret != CDN_OK)
+ return ret;
+
+ /* set bpp */
+ resp.val = resp.val & (~(F_VIF_DATA_WIDTH(3)));
+ switch (bpp) {
+ case 8:
+ resp.val = resp.val | (F_VIF_DATA_WIDTH(0));
+ break;
+
+ case 10:
+ resp.val = resp.val | (F_VIF_DATA_WIDTH(1));
+ break;
+
+ case 12:
+ resp.val = resp.val | (F_VIF_DATA_WIDTH(2));
+ break;
+
+ case 16:
+ resp.val = resp.val | (F_VIF_DATA_WIDTH(3));
+ break;
+ }
+
+ /* select color encoding */
+ resp.val = resp.val & (~(F_HDMI_ENCODING(3)));
+ switch (format) {
+ case PXL_RGB:
+
+ resp.val = resp.val | (F_HDMI_ENCODING(0));
+ break;
+
+ case YCBCR_4_4_4:
+ resp.val = resp.val | (F_HDMI_ENCODING(2));
+ break;
+
+ case YCBCR_4_2_2:
+ resp.val = resp.val | (F_HDMI_ENCODING(1));
+ break;
+
+ case YCBCR_4_2_0:
+ resp.val = resp.val | (F_HDMI_ENCODING(3));
+ break;
+ case Y_ONLY:
+ /* not exist in hdmi */
+ break;
+ }
+
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_MHL_HD +
+ (HDTX_CONTROLLER << 2),
+ resp.val);
+ if (ret != CDN_OK)
+ return ret;
+
+ /* set data enable */
+ resp.val = resp.val | (F_DATA_EN(1));
+ ret =
+ CDN_API_General_Write_Register_blocking(state, ADDR_SOURCE_MHL_HD +
+ (HDTX_CONTROLLER << 2),
+ resp.val);
+ if (ret != CDN_OK)
+ return ret;
+ return ret;
+}
+
+CDN_API_STATUS CDN_API_HDMITX_Disable_GCP(state_struct *state)
+{
+ GENERAL_Read_Register_response resp;
+
+ CDN_API_General_Read_Register_blocking(state, ADDR_SOURCE_MHL_HD +(HDTX_CONTROLLER<<2), &resp);
+ resp.val = resp.val & (~F_GCP_EN(1));
+ return CDN_API_General_Write_Register_blocking(state,
+ ADDR_SOURCE_MHL_HD +(HDTX_CONTROLLER<<2), resp.val);
+}
+
+CDN_API_STATUS CDN_API_HDMITX_ForceColorDepth_blocking(state_struct *state,
+ u8 force, u8 val)
+{
+ u32 valToWrite = F_COLOR_DEPTH_VAL(val) | F_COLOR_DEPTH_FORCE(force);
+ return CDN_API_General_Write_Register_blocking(state,
+ ADDR_SOURCE_MHL_HD +
+ (GCP_FORCE_COLOR_DEPTH_CODING
+ << 2), valToWrite);
+
+}
+
+CDN_API_STATUS CDN_API_HDMITX_ReadEvents(state_struct *state,
+ uint32_t *events)
+{
+ CDN_API_STATUS ret;
+
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_HDMI_TX,
+ HDMI_TX_EVENTS, 0);
+ state->rxEnable = 1;
+ state->bus_type = CDN_BUS_TYPE_APB;
+
+ return CDN_STARTED;
+ }
+
+ internal_process_messages(state);
+
+ ret =
+ internal_test_rx_head(state, MB_MODULE_ID_HDMI_TX, HDMI_TX_EVENTS);
+
+ if (ret != CDN_OK)
+ return ret;
+
+ internal_readmsg(state, 1, 4, events);
+
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDMITX_ReadEvents_blocking(state_struct *state,
+ uint32_t *events)
+{
+ internal_block_function(&state->mutex, CDN_API_HDMITX_ReadEvents(state, events));
+}
+
+CDN_API_STATUS CDN_API_HDMITX_GetHpdStatus(state_struct *state, u8 *hpd_sts)
+{
+ CDN_API_STATUS ret;
+ if (!state->running) {
+ if (!internal_apb_available(state))
+ return CDN_BSY;
+ internal_tx_mkfullmsg(state, MB_MODULE_ID_GENERAL, GENERAL_GET_HPD_STATE, 0);
+ state->rxEnable = 1;
+ state->bus_type = CDN_BUS_TYPE_APB;
+ return CDN_STARTED;
+ }
+ internal_process_messages(state);
+ ret =
+ internal_test_rx_head(state, MB_MODULE_ID_GENERAL, GENERAL_GET_HPD_STATE);
+ if (ret != CDN_OK)
+ return ret;
+ internal_readmsg(state, 1, 1, hpd_sts);
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_HDMITX_GetHpdStatus_blocking(state_struct *state,
+ u8 *hpd_sts)
+{
+ internal_block_function(&state->mutex, CDN_API_HDMITX_GetHpdStatus(state, hpd_sts));
+}
diff --git a/drivers/mxc/hdp/API_HDMITX.h b/drivers/mxc/hdp/API_HDMITX.h
new file mode 100644
index 000000000000..0f64cc272037
--- /dev/null
+++ b/drivers/mxc/hdp/API_HDMITX.h
@@ -0,0 +1,165 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * API_HDMITX.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef _API_HDMITX_H_
+#define _API_HDMITX_H_
+
+#include "API_General.h"
+#include "hdmi.h"
+
+/**
+ * \addtogroup HDMI_TX_API
+ * \{
+ */
+
+# define HDMI_TX_EVENT_CODE_HPD_HIGH 0x01
+# define HDMI_TX_EVENT_CODE_HPD_LOW 0x02
+# define HDMI_TX_EVENT_CODE_HPD_STATE_LOW 0x00
+# define HDMI_TX_EVENT_CODE_HPD_STATE_HIGH 0x08
+typedef struct {
+ /** if used to return data, this pointer is set (instead of being a destination to copy data to */
+ u8 *buff;
+ HDMI_I2C_STATUS status;
+ u16 len;
+ u8 slave;
+ u8 offset;
+} HDMITX_TRANS_DATA;
+
+typedef enum {
+ HDMI_TX_MODE_DVI,
+ HDMI_TX_MODE_HDMI_1_4,
+ HDMI_TX_MODE_HDMI_2_0,
+} HDMI_TX_MAIL_HANDLER_PROTOCOL_TYPE;
+
+/**
+ * \brief I2C read transaction
+ * \param [in] data_in - fields used: len, slave, offset
+ * \param [out] data_out - fields used: all
+ * \returns status
+ */
+CDN_API_STATUS CDN_API_HDMITX_DDC_READ(state_struct *state,
+ HDMITX_TRANS_DATA *data_in,
+ HDMITX_TRANS_DATA *data_out);
+CDN_API_STATUS CDN_API_HDMITX_DDC_READ_blocking(state_struct *state,
+ HDMITX_TRANS_DATA *data_in,
+ HDMITX_TRANS_DATA *data_out);
+
+/**
+ * \brief I2C write transaction
+ * \param [in] data_in - fields used: len, slave, offset, buff
+ * \param [out] data_out - fields used: status, len, slave, offset
+ * \returns status
+ */
+CDN_API_STATUS CDN_API_HDMITX_DDC_WRITE(state_struct *state,
+ HDMITX_TRANS_DATA *data_in,
+ HDMITX_TRANS_DATA *data_out);
+CDN_API_STATUS CDN_API_HDMITX_DDC_WRITE_blocking(state_struct *state,
+ HDMITX_TRANS_DATA *data_in,
+ HDMITX_TRANS_DATA *data_out);
+
+/**
+ * \brief I2C update read
+ * \param [out] data_out - fields used: status, buff
+ * \returns status
+ */
+CDN_API_STATUS CDN_API_HDMITX_DDC_UPDATE_READ(state_struct *state,
+ HDMITX_TRANS_DATA *data_out);
+CDN_API_STATUS CDN_API_HDMITX_DDC_UPDATE_READ_blocking(state_struct *state,
+ HDMITX_TRANS_DATA *
+ data_out);
+
+/**
+ * \brief I2C read edid
+ * \param [in] block - EDID block
+ * \pram [in] segment - EDID segment
+ * \param [out] data_out - fields used: status, buff, slave (as block), offset (as segment), len
+ * \returns status
+ */
+CDN_API_STATUS CDN_API_HDMITX_READ_EDID(state_struct *state, u8 block,
+ u8 segment,
+ HDMITX_TRANS_DATA *data_out);
+CDN_API_STATUS CDN_API_HDMITX_READ_EDID_blocking(state_struct *state, u8 block,
+ u8 segment,
+ HDMITX_TRANS_DATA *data_out);
+
+/**
+ * \brief set hdmi protocol type (DVI,1.x,2.x) (send scrambler command over scdc and set bits in controller)
+ * \param [in] protocol - type
+ * \returns status
+ */
+CDN_API_STATUS
+CDN_API_HDMITX_Set_Mode_blocking(state_struct *state,
+ HDMI_TX_MAIL_HANDLER_PROTOCOL_TYPE protocol,
+ u32 character_rate);
+
+/**
+ * \brief init hdmi registers
+ * \returns status
+ */
+CDN_API_STATUS CDN_API_HDMITX_Init_blocking(state_struct *state);
+
+/**
+ * \brief change to vid id vicMode
+ * \returns status
+ */
+CDN_API_STATUS CDN_API_HDMITX_SetVic_blocking(state_struct *state,
+ struct drm_display_mode *mode, int bpp,
+ VIC_PXL_ENCODING_FORMAT format);
+
+/**
+ * \brief option to force color depth in the gcp or not force (HW mode)
+ * \returns status
+ */
+CDN_API_STATUS CDN_API_HDMITX_ForceColorDepth_blocking(state_struct *state,
+ u8 force, u8 val);
+CDN_API_STATUS CDN_API_HDMITX_ReadEvents(state_struct *state, u32 *events);
+CDN_API_STATUS CDN_API_HDMITX_ReadEvents_blocking(state_struct *state,
+ u32 *events);
+CDN_API_STATUS CDN_API_HDMITX_GetHpdStatus(state_struct *state, u8 *hpd_sts);
+CDN_API_STATUS CDN_API_HDMITX_GetHpdStatus_blocking(state_struct *state,
+ u8 *hpd_sts);
+CDN_API_STATUS CDN_API_HDMITX_Disable_GCP(state_struct *state);
+#endif
diff --git a/drivers/mxc/hdp/API_HDMI_RX_Audio.c b/drivers/mxc/hdp/API_HDMI_RX_Audio.c
new file mode 100644
index 000000000000..1d1442c731ff
--- /dev/null
+++ b/drivers/mxc/hdp/API_HDMI_RX_Audio.c
@@ -0,0 +1,191 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_HDMI_RX_Audio.c
+ *
+ ******************************************************************************
+ */
+
+#include "API_HDMI_RX_Audio.h"
+#include "sink_aif_encoder.h"
+#include "aif_pckt2smp.h"
+#include "address.h"
+#include "util.h"
+#include "API_General.h"
+
+CDN_API_STATUS CDN_API_RX_AudioAutoConfig(
+ state_struct *state,
+ u8 max_ch_num,
+ u8 i2s_ports_num,
+ u8 dis_port3,
+ u8 enc_sample_width,
+ u8 i2s_sample_width)
+{
+ u32 regread;
+ u8 num_of_pairs_of_channels_per_port = max_ch_num / (i2s_ports_num * 2);
+ u8 enc_size_code;
+ u8 i2s_size_code;
+ u8 i2s_port3_dis = (dis_port3 != 0 && i2s_ports_num == 4) ? 1 : 0;
+ u8 times = 0;
+
+ /* Valid values: 1/2/4. */
+ /* 3 ports can be emulated with 'i2s_ports_num = 4' and 'dis_port3 = 1'. */
+ if (i2s_ports_num == 0 || i2s_ports_num == 3 || i2s_ports_num > 4)
+ return CDN_ERR;
+
+ /* 'dis_port3' makes sense only with 4 ports enabled */
+ if (dis_port3 != 0 && i2s_ports_num < 4)
+ return CDN_ERR;
+
+ switch (enc_sample_width) {
+ case 16:
+ enc_size_code = 0x0;
+ break;
+ case 24:
+ enc_size_code = 0x1;
+ break;
+ case 32:
+ enc_size_code = 0x2;
+ break;
+ default:
+ return CDN_ERR;
+ }
+
+ switch (i2s_sample_width) {
+ case 16:
+ i2s_size_code = 0x0;
+ break;
+ case 24:
+ i2s_size_code = 0x1;
+ break;
+ case 32:
+ i2s_size_code = 0x2;
+ break;
+ default:
+ return CDN_ERR;
+ }
+
+ /* Maximum number of channels has to be in range from 2 to 32 */
+ if (max_ch_num < 2 || max_ch_num > 32)
+ return CDN_ERR;
+ /* Maximum number of channels has to be power of 2 */
+ else if (!(max_ch_num * (max_ch_num - 1)))
+ return CDN_ERR;
+ /* Each active port shall carry the same number of sub-channels */
+ else if (max_ch_num % i2s_ports_num)
+ return CDN_ERR;
+
+ /* Disable ACR during configuration */
+ if (cdn_apb_write(state, ADDR_AIF_ENCODER + (ACR_CFG << 2), F_ACR_SW_RESET(1)))
+ return CDN_ERR;
+
+ /* Configuring audio FIFO */
+ if (cdn_apb_write(state,
+ ADDR_AIF_ENCODER + ((0x40 + FIFO_CNTL_ADDR) << 2),
+ F_CFG_FIFO_SW_RST(0) | F_CFG_INDEX_SYNC_EN(1) |
+ F_CFG_FIFO_DIR(1) | F_CFG_DIS_PORT3(i2s_port3_dis)))
+ return CDN_ERR;
+
+ /* Configuring audio parameters */
+ if (cdn_apb_write(state,
+ ADDR_AIF_ENCODER + ((0x40 + AUDIO_SINK_CNFG) << 2),
+ F_ENC_LOW_INDEX_MSB(0) | F_SINK_AUDIO_CH_NUM(max_ch_num - 1) |
+ F_ENC_SAMPLE_JUST(0x0) | F_ENC_SMPL_WIDTH(enc_size_code) |
+ F_I2S_ENC_WL_SIZE(i2s_size_code) | F_CNTL_SMPL_ONLY_EN(1) |
+ F_CNTL_TYPE_OVRD(0x0) | F_CNTL_TYPE_OVRD_EN(0) |
+ F_I2S_ENC_PORT_EN((1 << i2s_ports_num) - 1) | F_WS_POLARITY(0)))
+ return CDN_ERR;
+
+ /* Waiting for N value... */
+ do {
+ if (cdn_apb_read(state,
+ ADDR_AIF_ENCODER + (AIF_ACR_N_ST << 2), &regread))
+ return CDN_ERR;
+ times++;
+ udelay(10);
+ } while (!(regread) && times < 100);
+
+ if (times == 100)
+ return CDN_ERR;
+
+ /* Enable ACR */
+ if (cdn_apb_write(state,
+ ADDR_AIF_ENCODER + (ACR_CFG << 2), F_ACR_SW_RESET(0)))
+ return CDN_ERR;
+
+ /* Important: */
+ /* Write to AIF_ACR_N_OFST_CFG register is interpreted as new N_CTS value. */
+ /* The ACR has to be enabled (reset released) to register that event. */
+
+ if (cdn_apb_write(state,
+ ADDR_AIF_ENCODER + (AIF_ACR_N_OFST_CFG << 2),
+ F_ACR_N_OFFSET(regread * (num_of_pairs_of_channels_per_port - 1))))
+ return CDN_ERR;
+
+ /* Enable sample decoder */
+ if (cdn_apb_write(state,
+ ADDR_AIF_ENCODER + (PKT2SMPL_CNTL << 2), F_PKT2SMPL_EN(1)))
+ return CDN_ERR;
+
+ /* Enable I2S encoder */
+ if (cdn_apb_write(state,
+ ADDR_AIF_ENCODER + ((0x40 + AUDIO_SINK_CNTL) << 2), F_I2S_ENC_START(1)))
+ return CDN_ERR;
+
+ return CDN_OK;
+
+}
+
+CDN_API_STATUS CDN_API_RX_AudioAutoConfig_blocking(state_struct *state,
+ u8 max_ch_num,
+ u8 i2s_ports_num,
+ u8 dis_port3,
+ u8 enc_sample_width,
+ u8 i2s_sample_width)
+{
+ internal_block_function(&state->mutex,
+ CDN_API_RX_AudioAutoConfig(state,
+ max_ch_num,
+ i2s_ports_num,
+ dis_port3,
+ enc_sample_width,
+ i2s_sample_width));
+}
diff --git a/drivers/mxc/hdp/API_HDMI_RX_Audio.h b/drivers/mxc/hdp/API_HDMI_RX_Audio.h
new file mode 100644
index 000000000000..3dc0c2819527
--- /dev/null
+++ b/drivers/mxc/hdp/API_HDMI_RX_Audio.h
@@ -0,0 +1,80 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * API_HDMI_RX_Audio.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef API_HDMI_RX_AUDIO_H_
+#define API_HDMI_RX_AUDIO_H_
+
+#include "API_General.h"
+
+/**
+ * \addtogroup AUDIO_API
+ * \{
+ */
+
+/**
+ * \brief start audio reception with the input parameters
+ */
+CDN_API_STATUS CDN_API_RX_AudioAutoConfig(
+ state_struct *state,
+ u8 max_ch_num,
+ u8 i2s_ports_num,
+ u8 dis_port3,
+ u8 enc_sample_width,
+ u8 i2s_sample_width);
+
+/**
+ * \brief blocking version of #CDN_API_RX_AudioAutoConfig
+ */
+CDN_API_STATUS CDN_API_RX_AudioAutoConfig_blocking(
+ state_struct *state,
+ u8 max_ch_num,
+ u8 i2s_ports_num,
+ u8 dis_port3,
+ u8 enc_sample_width,
+ u8 i2s_sample_width);
+
+#endif
+
diff --git a/drivers/mxc/hdp/API_Infoframe.c b/drivers/mxc/hdp/API_Infoframe.c
new file mode 100644
index 000000000000..2a4e9739e14f
--- /dev/null
+++ b/drivers/mxc/hdp/API_Infoframe.c
@@ -0,0 +1,163 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * API_Infoframe.c
+ *
+ ******************************************************************************
+ */
+
+#include "API_Infoframe.h"
+#include "address.h"
+#include "source_pif.h"
+#include "util.h"
+
+#define BANK_OFFSET 0x0
+
+static CDN_API_STATUS infoframeSet(state_struct *state, u8 entry_id,
+ u8 packet_len,
+ u32 *packet, u8 packet_type, u8 active_idle)
+{
+ u32 idx;
+ u32 activeIdleBit = (0 == active_idle) ? 0 : 0x20000;
+
+ /* invalidate entry */
+ if (cdn_apb_write
+ (state,
+ BANK_OFFSET | ADDR_SOURCE_PIF | (SOURCE_PIF_PKT_ALLOC_REG << 2),
+ activeIdleBit | F_PKT_ALLOC_ADDRESS(entry_id)))
+ return CDN_ERR;
+ if (cdn_apb_write
+ (state,
+ BANK_OFFSET | ADDR_SOURCE_PIF | (SOURCE_PIF_PKT_ALLOC_WR_EN << 2),
+ F_PKT_ALLOC_WR_EN(1)))
+ return CDN_ERR;
+
+ /* flush fifo 1 */
+ if (cdn_apb_write
+ (state,
+ BANK_OFFSET | ADDR_SOURCE_PIF | (SOURCE_PIF_FIFO1_FLUSH << 2),
+ F_FIFO1_FLUSH(1)))
+ return CDN_ERR;
+
+ /* write packet into memory */
+ for (idx = 0; idx < packet_len; idx++)
+ if (cdn_apb_write
+ (state,
+ BANK_OFFSET | ADDR_SOURCE_PIF | (SOURCE_PIF_DATA_WR << 2),
+ F_DATA_WR(packet[idx])))
+ return CDN_ERR;
+
+ /* write entry id */
+ if (cdn_apb_write
+ (state, BANK_OFFSET | ADDR_SOURCE_PIF | (SOURCE_PIF_WR_ADDR << 2),
+ F_WR_ADDR(entry_id)))
+ return CDN_ERR;
+
+ /* write request */
+ if (cdn_apb_write
+ (state, BANK_OFFSET | ADDR_SOURCE_PIF | (SOURCE_PIF_WR_REQ << 2),
+ F_HOST_WR(1)))
+ return CDN_ERR;
+
+ /* update entry */
+ if (cdn_apb_write
+ (state,
+ BANK_OFFSET | ADDR_SOURCE_PIF | (SOURCE_PIF_PKT_ALLOC_REG << 2),
+ activeIdleBit | F_TYPE_VALID(1) | F_PACKET_TYPE(packet_type) |
+ F_PKT_ALLOC_ADDRESS(entry_id)))
+ return CDN_ERR;
+ if (cdn_apb_write
+ (state,
+ BANK_OFFSET | ADDR_SOURCE_PIF | (SOURCE_PIF_PKT_ALLOC_WR_EN << 2),
+ F_PKT_ALLOC_WR_EN(1)))
+ return CDN_ERR;
+
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_InfoframeSet(state_struct *state, u8 entry_id,
+ u8 packet_len, u32 *packet, u8 packet_type)
+{
+ return infoframeSet(state, entry_id, packet_len, packet, packet_type,
+ 1);
+}
+
+CDN_API_STATUS CDN_API_InfoframeSetNoActiveIdle(state_struct *state,
+ u8 entry_id, u8 packet_len,
+ u32 *packet, u8 packet_type)
+{
+ return infoframeSet(state, entry_id, packet_len, packet, packet_type,
+ 0);
+}
+
+CDN_API_STATUS CDN_API_InfoframeRemove(state_struct *state, u8 entry_id)
+{
+ /* invalidate entry */
+ if (cdn_apb_write
+ (state,
+ BANK_OFFSET | ADDR_SOURCE_PIF | (SOURCE_PIF_PKT_ALLOC_REG << 2),
+ 0x20000 | F_PKT_ALLOC_ADDRESS(entry_id)))
+ return CDN_ERR;
+ if (cdn_apb_write
+ (state,
+ BANK_OFFSET | ADDR_SOURCE_PIF | (SOURCE_PIF_PKT_ALLOC_WR_EN << 2),
+ F_PKT_ALLOC_WR_EN(1)))
+ return CDN_ERR;
+
+ return CDN_OK;
+}
+
+CDN_API_STATUS CDN_API_InfoframeRemovePacket(state_struct *state, u8 entry_id, u8 packet_type)
+{
+ /* invalidate entry */
+ if (cdn_apb_write
+ (state,
+ BANK_OFFSET | ADDR_SOURCE_PIF | (SOURCE_PIF_PKT_ALLOC_REG << 2),
+ 0x20000 | F_PKT_ALLOC_ADDRESS(entry_id) | F_PACKET_TYPE(packet_type)))
+ return CDN_ERR;
+ if (cdn_apb_write
+ (state,
+ BANK_OFFSET | ADDR_SOURCE_PIF | (SOURCE_PIF_PKT_ALLOC_WR_EN << 2),
+ F_PKT_ALLOC_WR_EN(1)))
+ return CDN_ERR;
+
+ return CDN_OK;
+}
diff --git a/drivers/mxc/hdp/API_Infoframe.h b/drivers/mxc/hdp/API_Infoframe.h
new file mode 100644
index 000000000000..492eb6646629
--- /dev/null
+++ b/drivers/mxc/hdp/API_Infoframe.h
@@ -0,0 +1,64 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * API_Infoframe.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef API_INFOFRAME_H
+#define API_INFOFRAME_H
+
+#include "API_General.h"
+/**
+ * \addtogroup INFO_FRAME_API
+ * \{
+ */
+CDN_API_STATUS CDN_API_InfoframeSet(state_struct *state, u8 entry_id,
+ u8 packet_len, u32 *packet,
+ u8 packet_type);
+CDN_API_STATUS CDN_API_InfoframeSetNoActiveIdle(state_struct *state,
+ u8 entry_id, u8 packet_len,
+ u32 *packet, u8 packet_type);
+CDN_API_STATUS CDN_API_InfoframeRemove(state_struct *state, u8 entry_id);
+CDN_API_STATUS CDN_API_InfoframeRemovePacket(state_struct *state, u8 entry_id, u8 packet_type);
+
+#endif
diff --git a/drivers/mxc/hdp/Kconfig b/drivers/mxc/hdp/Kconfig
new file mode 100644
index 000000000000..fe98359c5c07
--- /dev/null
+++ b/drivers/mxc/hdp/Kconfig
@@ -0,0 +1,5 @@
+config MX8_HDP
+ tristate "IMX8 HDP API "
+
+config MX8_HDP_RX
+ tristate "IMX8 HDP RX API "
diff --git a/drivers/mxc/hdp/Makefile b/drivers/mxc/hdp/Makefile
new file mode 100644
index 000000000000..363cdba3fe41
--- /dev/null
+++ b/drivers/mxc/hdp/Makefile
@@ -0,0 +1,13 @@
+obj-$(CONFIG_MX8_HDP) += \
+ API_Audio.o \
+ API_AFE.o \
+ API_General.o \
+ API_HDCP.o \
+ API_HDMITX.o \
+ API_Infoframe.o \
+ API_DPTX.o \
+ util.o
+
+obj-$(CONFIG_MX8_HDP_RX) += \
+ API_HDMIRX.o \
+ API_HDMI_RX_Audio.o
diff --git a/drivers/mxc/hdp/address.h b/drivers/mxc/hdp/address.h
new file mode 100644
index 000000000000..59a68a631645
--- /dev/null
+++ b/drivers/mxc/hdp/address.h
@@ -0,0 +1,109 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * address.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef ADDRESS_H_
+#define ADDRESS_H_
+
+#define ADDR_IMEM 0x10000
+#define ADDR_DMEM 0x20000
+#define ADDR_CIPHER 0x60000
+#define BASE_CIPHER 0x600
+#define ADDR_APB_CFG 0x00000
+#define BASE_APB_CFG 0x000
+#define ADDR_SOURCE_AIF_DECODER 0x30000
+#define BASE_SOURCE_AIF_DECODER 0x300
+#define ADDR_SOURCE_AIF_SMPL2PCKT 0x30080
+#define BASE_SOURCE_AIF_SMPL2PCKT 0x300
+#define ADDR_AIF_ENCODER 0x30000
+#define BASE_AIF_ENCODER 0x300
+#define ADDR_SOURCE_PIF 0x30800
+#define BASE_SOURCE_PIF 0x308
+#define ADDR_SINK_PIF 0x30800
+#define BASE_SINK_PIF 0x308
+#define ADDR_APB_CFG 0x00000
+#define BASE_APB_CFG 0x000
+#define ADDR_SOURCE_CSC 0x40000
+#define BASE_SOURCE_CSC 0x400
+#define ADDR_UCPU_CFG 0x00000
+#define BASE_UCPU_CFG 0x000
+#define ADDR_SOURCE_CAR 0x00900
+#define BASE_SOURCE_CAR 0x009
+#define ADDR_SINK_CAR 0x00900
+#define BASE_SINK_CAR 0x009
+#define ADDR_CLOCK_METERS 0x00A00
+#define BASE_CLOCK_METERS 0x00A
+#define ADDR_SOURCE_VIF 0x00b00
+#define BASE_SOURCE_VIF 0x00b
+#define ADDR_SINK_MHL_HD 0x01000
+#define ADDR_SINK_VIDEO_HD 0x01800
+#define BASE_SINK_MHL_HD 0x010
+#define ADDR_SINK_CORE 0x07800
+#define BASE_SINK_CORE 0x078
+#define ADDR_DPTX_PHY 0x02000
+#define BASE_DPTX_PHY 0x020
+#define ADDR_DPTX_HPD 0x02100
+#define BASE_DPTX_HPD 0x021
+#define ADDR_DPTX_FRAMER 0x02200
+#define BASE_DPTX_FRAMER 0x022
+#define ADDR_DPTX_STREAM 0x02200
+#define BASE_DPTX_STREAM 0x022
+#define ADDR_DPTX_GLBL 0x02300
+#define BASE_DPTX_GLBL 0x023
+#define ADDR_DPTX_HDCP 0x02400
+#define BASE_DPTX_HDCP 0x024
+#define ADDR_DP_AUX 0x02800
+#define BASE_DP_AUX 0x028
+#define ADDR_CRYPTO 0x05800
+#define BASE_CRYPTO 0x058
+#define ADDR_CIPHER 0x60000
+#define BASE_CIPHER 0x600
+#define ADDR_SOURCE_MHL_HD 0x01000
+#define ADDR_HDP_CEC_BASE 0x33800
+
+#define ADDR_AFE (0x20000 * 4)
+#define ADDR_SOURCD_PHY (0x800)
+
+#endif
diff --git a/drivers/mxc/hdp/aif_pckt2smp.h b/drivers/mxc/hdp/aif_pckt2smp.h
new file mode 100644
index 000000000000..b1b28bc3b38f
--- /dev/null
+++ b/drivers/mxc/hdp/aif_pckt2smp.h
@@ -0,0 +1,168 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * aif_pckt2smp.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef AIF_PCKT2SMP_H_
+#define AIF_PCKT2SMP_H_
+
+/* register PKT2SMPL_CNTL */
+#define PKT2SMPL_CNTL 0
+#define F_SW_RST(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_PKT2SMPL_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_PKT2SMPL_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_NUM_OF_I2S_PORTS(x) (((x) & ((1 << 2) - 1)) << 2)
+#define F_NUM_OF_I2S_PORTS_RD(x) (((x) & (((1 << 2) - 1) << 2)) >> 2)
+#define F_AIF_ERR_MASK(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_AIF_ERR_MASK_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_AIF_OVERFLOW_MASK(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_AIF_OVERFLOW_MASK_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_AIF_UNDERFLOW_MASK(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_AIF_UNDERFLOW_MASK_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+#define F_CFG_FORCE_SP(x) (((x) & ((1 << 1) - 1)) << 7)
+#define F_CFG_FORCE_SP_RD(x) (((x) & (((1 << 1) - 1) << 7)) >> 7)
+
+/* register ACR_CFG */
+#define ACR_CFG 1
+#define F_ACR_STOP_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_ACR_STOP_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_ACR_FIFO_STATUS_DIS(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_ACR_FIFO_STATUS_DIS_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_ACR_DIS_USE_NEDGE(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_ACR_DIS_USE_NEDGE_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_ACR_MASTER_CLK_FX_MODE(x) (((x) & ((1 << 2) - 1)) << 3)
+#define F_ACR_MASTER_CLK_FX_MODE_RD(x) (((x) & (((1 << 2) - 1) << 3)) >> 3)
+#define F_ACR_SW_RESET(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_ACR_SW_RESET_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+
+/* register SPDIF_CFG */
+#define SPDIF_CFG 2
+#define F_SPDIF_SELECTED(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SPDIF_SELECTED_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register AUDIO_FIFO_PTR_CFG0 */
+#define AUDIO_FIFO_PTR_CFG0 3
+#define F_AUDIO_FIFO_PTR_EMPTY_LOW(x) (((x) & ((1 << 9) - 1)) << 0)
+#define F_AUDIO_FIFO_PTR_EMPTY_LOW_RD(x) (((x) & (((1 << 9) - 1) << 0)) >> 0)
+#define F_AUDIO_FIFO_PTR_EMPTY_HIGH(x) (((x) & ((1 << 9) - 1)) << 9)
+#define F_AUDIO_FIFO_PTR_EMPTY_HIGH_RD(x) (((x) & (((1 << 9) - 1) << 9)) >> 9)
+#define F_AUDIO_FIFO_PTR_LOW_LOW(x) (((x) & ((1 << 9) - 1)) << 18)
+#define F_AUDIO_FIFO_PTR_LOW_LOW_RD(x) (((x) & (((1 << 9) - 1) << 18)) >> 18)
+
+/* register AUDIO_FIFO_PTR_CFG1 */
+#define AUDIO_FIFO_PTR_CFG1 4
+#define F_AUDIO_FIFO_PTR_LOW_HIGH(x) (((x) & ((1 << 9) - 1)) << 0)
+#define F_AUDIO_FIFO_PTR_LOW_HIGH_RD(x) (((x) & (((1 << 9) - 1) << 0)) >> 0)
+#define F_AUDIO_FIFO_PTR_BELOW_LOW(x) (((x) & ((1 << 9) - 1)) << 9)
+#define F_AUDIO_FIFO_PTR_BELOW_LOW_RD(x) (((x) & (((1 << 9) - 1) << 9)) >> 9)
+#define F_AUDIO_FIFO_PTR_BELOW_HIGH(x) (((x) & ((1 << 9) - 1)) << 18)
+#define F_AUDIO_FIFO_PTR_BELOW_HIGH_RD(x) (((x) & (((1 << 9) - 1) << 18)) >> 18)
+
+/* register AUDIO_FIFO_PTR_CFG2 */
+#define AUDIO_FIFO_PTR_CFG2 5
+#define F_AUDIO_FIFO_PTR_NOMINAL_LOW(x) (((x) & ((1 << 9) - 1)) << 0)
+#define F_AUDIO_FIFO_PTR_NOMINAL_LOW_RD(x) (((x) & (((1 << 9) - 1) << 0)) >> 0)
+#define F_AUDIO_FIFO_PTR_NOMINAL_HIGH(x) (((x) & ((1 << 9) - 1)) << 9)
+#define F_AUDIO_FIFO_PTR_NOMINAL_HIGH_RD(x) (((x) & (((1 << 9) - 1) << 9)) >> 9)
+#define F_AUDIO_FIFO_PTR_ABOVE_LOW(x) (((x) & ((1 << 9) - 1)) << 18)
+#define F_AUDIO_FIFO_PTR_ABOVE_LOW_RD(x) (((x) & (((1 << 9) - 1) << 18)) >> 18)
+
+/* register AUDIO_FIFO_PTR_CFG3 */
+#define AUDIO_FIFO_PTR_CFG3 6
+#define F_AUDIO_FIFO_PTR_ABOVE_HIGH(x) (((x) & ((1 << 9) - 1)) << 0)
+#define F_AUDIO_FIFO_PTR_ABOVE_HIGH_RD(x) (((x) & (((1 << 9) - 1) << 0)) >> 0)
+#define F_AUDIO_FIFO_PTR_HIGH_LOW(x) (((x) & ((1 << 9) - 1)) << 9)
+#define F_AUDIO_FIFO_PTR_HIGH_LOW_RD(x) (((x) & (((1 << 9) - 1) << 9)) >> 9)
+#define F_AUDIO_FIFO_PTR_HIGH_HIGH(x) (((x) & ((1 << 9) - 1)) << 18)
+#define F_AUDIO_FIFO_PTR_HIGH_HIGH_RD(x) (((x) & (((1 << 9) - 1) << 18)) >> 18)
+
+/* register AUDIO_FIFO_PTR_CFG4 */
+#define AUDIO_FIFO_PTR_CFG4 7
+#define F_AUDIO_FIFO_PTR_FULL_LOW(x) (((x) & ((1 << 9) - 1)) << 0)
+#define F_AUDIO_FIFO_PTR_FULL_LOW_RD(x) (((x) & (((1 << 9) - 1) << 0)) >> 0)
+#define F_AUDIO_FIFO_PTR_FULL_HIGH(x) (((x) & ((1 << 9) - 1)) << 9)
+#define F_AUDIO_FIFO_PTR_FULL_HIGH_RD(x) (((x) & (((1 << 9) - 1) << 9)) >> 9)
+
+/* register AUDIO_FIFO_PTR_CFG5 */
+#define AUDIO_FIFO_PTR_CFG5 8
+#define F_AUDIO_FIFO_PTR_IDLE_LOW(x) (((x) & ((1 << 9) - 1)) << 0)
+#define F_AUDIO_FIFO_PTR_IDLE_LOW_RD(x) (((x) & (((1 << 9) - 1) << 0)) >> 0)
+#define F_AUDIO_FIFO_PTR_IDLE_HIGH(x) (((x) & ((1 << 9) - 1)) << 9)
+#define F_AUDIO_FIFO_PTR_IDLE_HIGH_RD(x) (((x) & (((1 << 9) - 1) << 9)) >> 9)
+
+/* register AIF_INT_STTS */
+#define AIF_INT_STTS 9
+#define F_AIF_ERR_STATUS(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_AIF_ERR_STATUS_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_AIF_OVERFLOW_STATUS(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_AIF_OVERFLOW_STATUS_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_AIF_UNDERFLOW_STATUS(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_AIF_UNDERFLOW_STATUS_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+
+/* register AIF_ACR_N_ST */
+#define AIF_ACR_N_ST 10
+#define F_ACR_N(x) (((x) & ((1 << 20) - 1)) << 0)
+#define F_ACR_N_RD(x) (((x) & (((1 << 20) - 1) << 0)) >> 0)
+
+/* register AIF_ACR_CTS_ST */
+#define AIF_ACR_CTS_ST 11
+#define F_ACR_CTS(x) (((x) & ((1 << 20) - 1)) << 0)
+#define F_ACR_CTS_RD(x) (((x) & (((1 << 20) - 1) << 0)) >> 0)
+
+/* register AIF_ACR_N_OFST_CFG */
+#define AIF_ACR_N_OFST_CFG 12
+#define F_ACR_N_OFFSET(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_ACR_N_OFFSET_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+
+/* register AIF_ACR_CTS_OFST_CFG */
+#define AIF_ACR_CTS_OFST_CFG 13
+#define F_ACR_CTS_OFFSET(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_ACR_CTS_OFFSET_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+
+#endif
diff --git a/drivers/mxc/hdp/all.h b/drivers/mxc/hdp/all.h
new file mode 100644
index 000000000000..bfe3da3a1b5e
--- /dev/null
+++ b/drivers/mxc/hdp/all.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * all.h
+ *
+ ******************************************************************************
+ */
+#include "address.h"
+#include "apb_cfg.h"
+#include "API_AFE.h"
+#include "API_DPTX.h"
+#include "API_General.h"
+#include "API_Infoframe.h"
+#include "API_Audio.h"
+#include "API_HDCP.h"
+#include "API_HDMITX.h"
+#include "dptx_framer.h"
+#include "source_car.h"
+#include "source_phy.h"
+#include "source_vif.h"
+#include "util.h"
+#include "sink_pif.h"
+#include "sink_mhl_hd.h"
+#include "sink_car.h"
+#include "API_HDMIRX.h"
diff --git a/drivers/mxc/hdp/apb_cfg.h b/drivers/mxc/hdp/apb_cfg.h
new file mode 100644
index 000000000000..80baa5b55315
--- /dev/null
+++ b/drivers/mxc/hdp/apb_cfg.h
@@ -0,0 +1,185 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * apb_cfg.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef APB_CFG_H_
+#define APB_CFG_H_
+
+/* register APB_CTRL */
+#define APB_CTRL 0
+#define F_APB_XT_RESET(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_APB_XT_RESET_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_APB_DRAM_PATH(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_APB_DRAM_PATH_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_APB_IRAM_PATH(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_APB_IRAM_PATH_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+
+/* register XT_INT_CTRL */
+#define XT_INT_CTRL 1
+#define F_XT_INT_POLARITY(x) (((x) & ((1 << 2) - 1)) << 0)
+#define F_XT_INT_POLARITY_RD(x) (((x) & (((1 << 2) - 1) << 0)) >> 0)
+
+/* register MAILBOX_FULL_ADDR */
+#define MAILBOX_FULL_ADDR 2
+#define F_MAILBOX_FULL(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_MAILBOX_FULL_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register MAILBOX_EMPTY_ADDR */
+#define MAILBOX_EMPTY_ADDR 3
+#define F_MAILBOX_EMPTY(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_MAILBOX_EMPTY_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register MAILBOX0_WR_DATA */
+#define MAILBOX0_WR_DATA 4
+#define F_MAILBOX0_WR_DATA(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_MAILBOX0_WR_DATA_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register MAILBOX0_RD_DATA */
+#define MAILBOX0_RD_DATA 5
+#define F_MAILBOX0_RD_DATA(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_MAILBOX0_RD_DATA_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register KEEP_ALIVE */
+#define KEEP_ALIVE 6
+#define F_KEEP_ALIVE_CNT(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_KEEP_ALIVE_CNT_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register VER_L */
+#define VER_L 7
+#define F_VER_LSB(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_VER_LSB_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register VER_H */
+#define VER_H 8
+#define F_VER_MSB(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_VER_MSB_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register VER_LIB_L_ADDR */
+#define VER_LIB_L_ADDR 9
+#define F_SW_LIB_VER_L(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SW_LIB_VER_L_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register VER_LIB_H_ADDR */
+#define VER_LIB_H_ADDR 10
+#define F_SW_LIB_VER_H(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SW_LIB_VER_H_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register SW_DEBUG_L */
+#define SW_DEBUG_L 11
+#define F_SW_DEBUG_7_0(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SW_DEBUG_7_0_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register SW_DEBUG_H */
+#define SW_DEBUG_H 12
+#define F_SW_DEBUG_15_8(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SW_DEBUG_15_8_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register MAILBOX_INT_MASK */
+#define MAILBOX_INT_MASK 13
+#define F_MAILBOX_INT_MASK(x) (((x) & ((1 << 2) - 1)) << 0)
+#define F_MAILBOX_INT_MASK_RD(x) (((x) & (((1 << 2) - 1) << 0)) >> 0)
+
+/* register MAILBOX_INT_STATUS */
+#define MAILBOX_INT_STATUS 14
+#define F_MAILBOX_INT_STATUS(x) (((x) & ((1 << 2) - 1)) << 0)
+#define F_MAILBOX_INT_STATUS_RD(x) (((x) & (((1 << 2) - 1) << 0)) >> 0)
+
+/* register SW_CLK_L */
+#define SW_CLK_L 15
+#define F_SW_CLOCK_VAL_L(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SW_CLOCK_VAL_L_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register SW_CLK_H */
+#define SW_CLK_H 16
+#define F_SW_CLOCK_VAL_H(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SW_CLOCK_VAL_H_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register SW_EVENTS0 */
+#define SW_EVENTS0 17
+#define F_SW_EVENTS7_0(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SW_EVENTS7_0_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register SW_EVENTS1 */
+#define SW_EVENTS1 18
+#define F_SW_EVENTS15_8(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SW_EVENTS15_8_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register SW_EVENTS2 */
+#define SW_EVENTS2 19
+#define F_SW_EVENTS23_16(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SW_EVENTS23_16_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register SW_EVENTS3 */
+#define SW_EVENTS3 20
+#define F_SW_EVENTS31_24(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SW_EVENTS31_24_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register XT_OCD_CTRL */
+#define XT_OCD_CTRL 24
+#define F_XT_DRESET(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_XT_DRESET_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_XT_OCDHALTONRESET(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_XT_OCDHALTONRESET_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+
+/* register XT_OCD_CTRL_RO */
+#define XT_OCD_CTRL_RO 25
+#define F_XT_XOCDMODE(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_XT_XOCDMODE_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register APB_INT_MASK */
+#define APB_INT_MASK 27
+#define F_APB_INTR_MASK(x) (((x) & ((1 << 3) - 1)) << 0)
+#define F_APB_INTR_MASK_RD(x) (((x) & (((1 << 3) - 1) << 0)) >> 0)
+
+/* register APB_STATUS_MASK */
+#define APB_STATUS_MASK 28
+#define F_APB_INTR_STATUS(x) (((x) & ((1 << 3) - 1)) << 0)
+#define F_APB_INTR_STATUS_RD(x) (((x) & (((1 << 3) - 1) << 0)) >> 0)
+
+#endif
diff --git a/drivers/mxc/hdp/clock_meters.h b/drivers/mxc/hdp/clock_meters.h
new file mode 100644
index 000000000000..f9433b40a109
--- /dev/null
+++ b/drivers/mxc/hdp/clock_meters.h
@@ -0,0 +1,157 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * clock_meters.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef CLOCK_METERS_H_
+#define CLOCK_METERS_H_
+
+/* register CM_CTRL */
+#define CM_CTRL 0
+#define F_NMVID_SEL_EXTERNAL(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_NMVID_SEL_EXTERNAL_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SPDIF_SEL_EXTERNAL(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SPDIF_SEL_EXTERNAL_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_I2S_SEL_EXTERNAL(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_I2S_SEL_EXTERNAL_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_SEL_AUD_LANE_REF(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_SEL_AUD_LANE_REF_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_I2S_MULT(x) (((x) & ((1 << 3) - 1)) << 4)
+#define F_I2S_MULT_RD(x) (((x) & (((1 << 3) - 1) << 4)) >> 4)
+
+/* register CM_I2S_CTRL */
+#define CM_I2S_CTRL 1
+#define F_I2S_REF_CYC(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_I2S_REF_CYC_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_I2S_MEAS_TOLERANCE(x) (((x) & ((1 << 4) - 1)) << 24)
+#define F_I2S_MEAS_TOLERANCE_RD(x) (((x) & (((1 << 4) - 1) << 24)) >> 24)
+
+/* register CM_SPDIF_CTRL */
+#define CM_SPDIF_CTRL 2
+#define F_SPDIF_REF_CYC(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_SPDIF_REF_CYC_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_SPDIF_MEAS_TOLERANCE(x) (((x) & ((1 << 4) - 1)) << 24)
+#define F_SPDIF_MEAS_TOLERANCE_RD(x) (((x) & (((1 << 4) - 1) << 24)) >> 24)
+
+/* register CM_VID_CTRL */
+#define CM_VID_CTRL 3
+#define F_NMVID_REF_CYC(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_NMVID_REF_CYC_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_NMVID_MEAS_TOLERANCE(x) (((x) & ((1 << 4) - 1)) << 24)
+#define F_NMVID_MEAS_TOLERANCE_RD(x) (((x) & (((1 << 4) - 1) << 24)) >> 24)
+
+/* register CM_LANE_CTRL */
+#define CM_LANE_CTRL 4
+#define F_LANE_REF_CYC(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_LANE_REF_CYC_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+
+/* register I2S_NM_STABLE */
+#define I2S_NM_STABLE 5
+#define F_I2S_MNAUD_STABLE(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_I2S_MNAUD_STABLE_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register I2S_NCTS_STABLE */
+#define I2S_NCTS_STABLE 6
+#define F_I2S_NCTS_STABLE(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_I2S_NCTS_STABLE_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register SPDIF_NM_STABLE */
+#define SPDIF_NM_STABLE 7
+#define F_SPDIF_MNAUD_STABLE(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SPDIF_MNAUD_STABLE_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register SPDIF_NCTS_STABLE */
+#define SPDIF_NCTS_STABLE 8
+#define F_SPDIF_NCTS_STABLE(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SPDIF_NCTS_STABLE_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register NMVID_MEAS_STABLE */
+#define NMVID_MEAS_STABLE 9
+#define F_ST_NMVID_MEAS_STABLE(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_ST_NMVID_MEAS_STABLE_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register CM_VID_MEAS */
+#define CM_VID_MEAS 10
+#define F_NMVID_MEAS_CYC(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_NMVID_MEAS_CYC_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_NMVID_MEAS_VALID_INDC(x) (((x) & ((1 << 1) - 1)) << 24)
+#define F_NMVID_MEAS_VALID_INDC_RD(x) (((x) & (((1 << 1) - 1) << 24)) >> 24)
+
+/* register CM_AUD_MEAS */
+#define CM_AUD_MEAS 11
+#define F_NMAUD_MEAS_CYC(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_NMAUD_MEAS_CYC_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_NMAUD_MEAS_VALID_INDC(x) (((x) & ((1 << 1) - 1)) << 24)
+#define F_NMAUD_MEAS_VALID_INDC_RD(x) (((x) & (((1 << 1) - 1) << 24)) >> 24)
+
+/* register I2S_MEAS */
+#define I2S_MEAS 16
+#define F_I2_MEAS(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_I2_MEAS_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+
+/* register I2S_DP_MEAS */
+#define I2S_DP_MEAS 17
+#define F_I2_DP_MEAS(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_I2_DP_MEAS_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+
+/* register SPDIF_DP_MEAS */
+#define SPDIF_DP_MEAS 32
+#define F_SPDIF_DP_MEAS(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_SPDIF_DP_MEAS_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+
+/* register SPDIF_MEAS */
+#define SPDIF_MEAS 33
+#define F_SPDIF_MEAS(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_SPDIF_MEAS_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+
+/* register NMVID_MEAS */
+#define NMVID_MEAS 48
+#define F_NMVID_MEAS(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_NMVID_MEAS_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+
+#endif //CLOCK_METERS
diff --git a/drivers/mxc/hdp/dptx_framer.h b/drivers/mxc/hdp/dptx_framer.h
new file mode 100644
index 000000000000..1a7ddf8766b1
--- /dev/null
+++ b/drivers/mxc/hdp/dptx_framer.h
@@ -0,0 +1,372 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * dptx_framer.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef DPTX_FRAMER_H_
+#define DPTX_FRAMER_H_
+
+/* register DP_FRAMER_GLOBAL_CONFIG */
+#define DP_FRAMER_GLOBAL_CONFIG 0
+#define F_NUM_LANES(x) (((x) & ((1 << 2) - 1)) << 0)
+#define F_NUM_LANES_RD(x) (((x) & (((1 << 2) - 1) << 0)) >> 0)
+#define F_MST_SST(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_MST_SST_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_GLOBAL_EN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_GLOBAL_EN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_RG_EN(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_RG_EN_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_NO_VIDEO(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_NO_VIDEO_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_ENC_RST_DIS(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_ENC_RST_DIS_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+#define F_WR_VHSYNC_FALL(x) (((x) & ((1 << 1) - 1)) << 7)
+#define F_WR_VHSYNC_FALL_RD(x) (((x) & (((1 << 1) - 1) << 7)) >> 7)
+
+/* register DP_SW_RESET */
+#define DP_SW_RESET 1
+#define F_SW_RST(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register DP_FRAMER_TU */
+#define DP_FRAMER_TU 2
+#define F_TU_VALID_SYMBOLS(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_TU_VALID_SYMBOLS_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_TU_SIZE(x) (((x) & ((1 << 7) - 1)) << 8)
+#define F_TU_SIZE_RD(x) (((x) & (((1 << 7) - 1) << 8)) >> 8)
+#define F_TU_CNT_RST_EN(x) (((x) & ((1 << 1) - 1)) << 15)
+#define F_TU_CNT_RST_EN_RD(x) (((x) & (((1 << 1) - 1) << 15)) >> 15)
+#define F_BS_SR_REPLACE_POSITION(x) (((x) & ((1 << 9) - 1)) << 16)
+#define F_BS_SR_REPLACE_POSITION_RD(x) (((x) & (((1 << 9) - 1) << 16)) >> 16)
+
+/* register DP_FRAMER_PXL_REPR */
+#define DP_FRAMER_PXL_REPR 3
+#define F_COLOR_DEPTH(x) (((x) & ((1 << 5) - 1)) << 0)
+#define F_COLOR_DEPTH_RD(x) (((x) & (((1 << 5) - 1) << 0)) >> 0)
+#define F_PXL_ENC_FORMAT(x) (((x) & ((1 << 5) - 1)) << 8)
+#define F_PXL_ENC_FORMAT_RD(x) (((x) & (((1 << 5) - 1) << 8)) >> 8)
+
+/* register DP_FRAMER_SP */
+#define DP_FRAMER_SP 4
+#define F_VSP(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_VSP_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_HSP(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_HSP_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_INTERLACE_EN(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_INTERLACE_EN_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_FRAMER_3D_EN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_FRAMER_3D_EN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_STACKED_3D_EN(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_STACKED_3D_EN_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+
+/* register AUDIO_PACK_CONTROL */
+#define AUDIO_PACK_CONTROL 5
+#define F_MST_SDP_ID(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_MST_SDP_ID_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_AUDIO_PACK_EN(x) (((x) & ((1 << 1) - 1)) << 8)
+#define F_AUDIO_PACK_EN_RD(x) (((x) & (((1 << 1) - 1) << 8)) >> 8)
+#define F_MONO(x) (((x) & ((1 << 1) - 1)) << 9)
+#define F_MONO_RD(x) (((x) & (((1 << 1) - 1) << 9)) >> 9)
+
+/* register DP_VC_TABLE_0 */
+#define DP_VC_TABLE_0 6
+#define F_VC_TABLE_0(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_VC_TABLE_0_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VC_TABLE_1(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VC_TABLE_1_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+#define F_VC_TABLE_2(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_VC_TABLE_2_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_VC_TABLE_3(x) (((x) & ((1 << 6) - 1)) << 24)
+#define F_VC_TABLE_3_RD(x) (((x) & (((1 << 6) - 1) << 24)) >> 24)
+
+/* register DP_VC_TABLE_1 */
+#define DP_VC_TABLE_1 7
+#define F_VC_TABLE_4(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_VC_TABLE_4_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VC_TABLE_5(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VC_TABLE_5_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+#define F_VC_TABLE_6(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_VC_TABLE_6_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_VC_TABLE_7(x) (((x) & ((1 << 6) - 1)) << 24)
+#define F_VC_TABLE_7_RD(x) (((x) & (((1 << 6) - 1) << 24)) >> 24)
+
+/* register DP_VC_TABLE_2 */
+#define DP_VC_TABLE_2 8
+#define F_VC_TABLE_8(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_VC_TABLE_8_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VC_TABLE_9(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VC_TABLE_9_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+#define F_VC_TABLE_10(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_VC_TABLE_10_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_VC_TABLE_11(x) (((x) & ((1 << 6) - 1)) << 24)
+#define F_VC_TABLE_11_RD(x) (((x) & (((1 << 6) - 1) << 24)) >> 24)
+
+/* register DP_VC_TABLE_3 */
+#define DP_VC_TABLE_3 9
+#define F_VC_TABLE_12(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_VC_TABLE_12_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VC_TABLE_13(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VC_TABLE_13_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+#define F_VC_TABLE_14(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_VC_TABLE_14_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_VC_TABLE_15(x) (((x) & ((1 << 6) - 1)) << 24)
+#define F_VC_TABLE_15_RD(x) (((x) & (((1 << 6) - 1) << 24)) >> 24)
+
+/* register DP_VC_TABLE_4 */
+#define DP_VC_TABLE_4 10
+#define F_VC_TABLE_16(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_VC_TABLE_16_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VC_TABLE_17(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VC_TABLE_17_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+#define F_VC_TABLE_18(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_VC_TABLE_18_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_VC_TABLE_19(x) (((x) & ((1 << 6) - 1)) << 24)
+#define F_VC_TABLE_19_RD(x) (((x) & (((1 << 6) - 1) << 24)) >> 24)
+
+/* register DP_VC_TABLE_5 */
+#define DP_VC_TABLE_5 11
+#define F_VC_TABLE_20(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_VC_TABLE_20_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VC_TABLE_21(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VC_TABLE_21_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+#define F_VC_TABLE_22(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_VC_TABLE_22_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_VC_TABLE_23(x) (((x) & ((1 << 6) - 1)) << 24)
+#define F_VC_TABLE_23_RD(x) (((x) & (((1 << 6) - 1) << 24)) >> 24)
+
+/* register DP_VC_TABLE_6 */
+#define DP_VC_TABLE_6 12
+#define F_VC_TABLE_24(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_VC_TABLE_24_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VC_TABLE_25(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VC_TABLE_25_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+#define F_VC_TABLE_26(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_VC_TABLE_26_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_VC_TABLE_27(x) (((x) & ((1 << 6) - 1)) << 24)
+#define F_VC_TABLE_27_RD(x) (((x) & (((1 << 6) - 1) << 24)) >> 24)
+
+/* register DP_VC_TABLE_7 */
+#define DP_VC_TABLE_7 13
+#define F_VC_TABLE_28(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_VC_TABLE_28_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VC_TABLE_29(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VC_TABLE_29_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+#define F_VC_TABLE_30(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_VC_TABLE_30_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_VC_TABLE_31(x) (((x) & ((1 << 6) - 1)) << 24)
+#define F_VC_TABLE_31_RD(x) (((x) & (((1 << 6) - 1) << 24)) >> 24)
+
+/* register DP_VC_TABLE_8 */
+#define DP_VC_TABLE_8 14
+#define F_VC_TABLE_32(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_VC_TABLE_32_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VC_TABLE_33(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VC_TABLE_33_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+#define F_VC_TABLE_34(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_VC_TABLE_34_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_VC_TABLE_35(x) (((x) & ((1 << 6) - 1)) << 24)
+#define F_VC_TABLE_35_RD(x) (((x) & (((1 << 6) - 1) << 24)) >> 24)
+
+/* register DP_VC_TABLE_9 */
+#define DP_VC_TABLE_9 15
+#define F_VC_TABLE_36(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_VC_TABLE_36_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_VC_TABLE_37(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VC_TABLE_37_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+#define F_VC_TABLE_38(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_VC_TABLE_38_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_VC_TABLE_39(x) (((x) & ((1 << 6) - 1)) << 24)
+#define F_VC_TABLE_39_RD(x) (((x) & (((1 << 6) - 1) << 24)) >> 24)
+
+/* register DP_VC_TABLE_10 */
+#define DP_VC_TABLE_10 16
+#define F_VC_TABLE_40(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_VC_TABLE_40_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VC_TABLE_41(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VC_TABLE_41_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+#define F_VC_TABLE_42(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_VC_TABLE_42_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_VC_TABLE_43(x) (((x) & ((1 << 6) - 1)) << 24)
+#define F_VC_TABLE_43_RD(x) (((x) & (((1 << 6) - 1) << 24)) >> 24)
+
+/* register DP_VC_TABLE_11 */
+#define DP_VC_TABLE_11 17
+#define F_VC_TABLE_44(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_VC_TABLE_44_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VC_TABLE_45(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VC_TABLE_45_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+#define F_VC_TABLE_46(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_VC_TABLE_46_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_VC_TABLE_47(x) (((x) & ((1 << 6) - 1)) << 24)
+#define F_VC_TABLE_47_RD(x) (((x) & (((1 << 6) - 1) << 24)) >> 24)
+
+/* register DP_VC_TABLE_12 */
+#define DP_VC_TABLE_12 18
+#define F_VC_TABLE_48(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_VC_TABLE_48_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VC_TABLE_49(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VC_TABLE_49_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+#define F_VC_TABLE_50(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_VC_TABLE_50_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_VC_TABLE_51(x) (((x) & ((1 << 6) - 1)) << 24)
+#define F_VC_TABLE_51_RD(x) (((x) & (((1 << 6) - 1) << 24)) >> 24)
+
+/* register DP_VC_TABLE_13 */
+#define DP_VC_TABLE_13 19
+#define F_VC_TABLE_52(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_VC_TABLE_52_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VC_TABLE_53(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VC_TABLE_53_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+#define F_VC_TABLE_54(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_VC_TABLE_54_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_VC_TABLE_55(x) (((x) & ((1 << 6) - 1)) << 24)
+#define F_VC_TABLE_55_RD(x) (((x) & (((1 << 6) - 1) << 24)) >> 24)
+
+/* register DP_VC_TABLE_14 */
+#define DP_VC_TABLE_14 20
+#define F_VC_TABLE_56(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_VC_TABLE_56_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VC_TABLE_57(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VC_TABLE_57_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+#define F_VC_TABLE_58(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_VC_TABLE_58_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_VC_TABLE_59(x) (((x) & ((1 << 6) - 1)) << 24)
+#define F_VC_TABLE_59_RD(x) (((x) & (((1 << 6) - 1) << 24)) >> 24)
+
+/* register LINE_THRESH */
+#define LINE_THRESH 21
+#define F_CFG_ACTIVE_LINE_TRESH(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_CFG_ACTIVE_LINE_TRESH_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VC_TABLE_61(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VC_TABLE_61_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+#define F_VC_TABLE_62(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_VC_TABLE_62_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_VC_TABLE_63(x) (((x) & ((1 << 6) - 1)) << 24)
+#define F_VC_TABLE_63_RD(x) (((x) & (((1 << 6) - 1) << 24)) >> 24)
+
+/* register DP_VB_ID */
+#define DP_VB_ID 22
+#define F_VB_ID(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_VB_ID_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register DP_MTPH_LVP_CONTROL */
+#define DP_MTPH_LVP_CONTROL 23
+#define F_MTPH_LVP_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_MTPH_LVP_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register DP_MTPH_SYMBOL_VALUES */
+#define DP_MTPH_SYMBOL_VALUES 24
+#define F_MPTH_LVP_SYM(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_MPTH_LVP_SYM_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_MTPH_ECF_SYM(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_MTPH_ECF_SYM_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_MTPH_MTPH_SYM(x) (((x) & ((1 << 8) - 1)) << 16)
+#define F_MTPH_MTPH_SYM_RD(x) (((x) & (((1 << 8) - 1) << 16)) >> 16)
+
+/* register DP_MTPH_ECF_CONTROL */
+#define DP_MTPH_ECF_CONTROL 25
+#define F_MPTH_ECF_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_MPTH_ECF_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_MTPH_ACT_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_MTPH_ACT_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+
+/* register DP_FIELDSEQ_3D */
+#define DP_FIELDSEQ_3D 26
+#define F_FIELD_SEQ_START(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_FIELD_SEQ_START_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_FIELD_SEQ_END(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_FIELD_SEQ_END_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register DP_MTPH_STATUS */
+#define DP_MTPH_STATUS 27
+#define F_MTP_ACT_CNT_CTRL_CURR_STATE(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_MTP_ACT_CNT_CTRL_CURR_STATE_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_MTP_ECF_CNT_CTRL_CURR_STATE(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_MTP_ECF_CNT_CTRL_CURR_STATE_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_MTPH_ACT_STATUS(x) (((x) & ((1 << 1) - 1)) << 16)
+#define F_MTPH_ACT_STATUS_RD(x) (((x) & (((1 << 1) - 1) << 16)) >> 16)
+#define F_MTPH_ECF_STATUS(x) (((x) & ((1 << 1) - 1)) << 17)
+#define F_MTPH_ECF_STATUS_RD(x) (((x) & (((1 << 1) - 1) << 17)) >> 17)
+#define F_MTPH_LVP_STATUS(x) (((x) & ((1 << 1) - 1)) << 18)
+#define F_MTPH_LVP_STATUS_RD(x) (((x) & (((1 << 1) - 1) << 18)) >> 18)
+
+/* register DP_INTERRUPT_SOURCE */
+#define DP_INTERRUPT_SOURCE 28
+#define F_PSLVERR(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_PSLVERR_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_MTPH_ACT_EN_CLEAR(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_MTPH_ACT_EN_CLEAR_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_MTPH_LVP_EN_CLEAR(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_MTPH_LVP_EN_CLEAR_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_MTPH_ECF_EN_CLEAR(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_MTPH_ECF_EN_CLEAR_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+
+/* register DP_INTERRUPT_MASK */
+#define DP_INTERRUPT_MASK 29
+#define F_PSLVERR_MASK(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_PSLVERR_MASK_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_MTPH_ACT_EN_CLEAR_MASK(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_MTPH_ACT_EN_CLEAR_MASK_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_MTPH_LVP_EN_CLEAR_MASK(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_MTPH_LVP_EN_CLEAR_MASK_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_MTPH_ECF_EN_CLEAR_MASK(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_MTPH_ECF_EN_CLEAR_MASK_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+
+/* register DP_FRONT_BACK_PORCH */
+#define DP_FRONT_BACK_PORCH 30
+#define F_BACK_PORCH(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_BACK_PORCH_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_FRONT_PORCH(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_FRONT_PORCH_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register DP_BYTE_COUNT */
+#define DP_BYTE_COUNT 31
+#define F_BYTE_COUNT(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_BYTE_COUNT_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+
+#endif //DPTX_FRAMER
diff --git a/drivers/mxc/hdp/dptx_stream.h b/drivers/mxc/hdp/dptx_stream.h
new file mode 100644
index 000000000000..c8235a171e7c
--- /dev/null
+++ b/drivers/mxc/hdp/dptx_stream.h
@@ -0,0 +1,208 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * dptx_stream.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef DPTX_STREAM_H_
+#define DPTX_STREAM_H_
+
+/* register MSA_HORIZONTAL_0 */
+#define MSA_HORIZONTAL_0 32
+#define F_PCK_STUFF_HTOTAL(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_PCK_STUFF_HTOTAL_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_PCK_STUFF_HSTART(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_PCK_STUFF_HSTART_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register MSA_HORIZONTAL_1 */
+#define MSA_HORIZONTAL_1 33
+#define F_PCK_STUFF_HSYNCWIDTH(x) (((x) & ((1 << 15) - 1)) << 0)
+#define F_PCK_STUFF_HSYNCWIDTH_RD(x) (((x) & (((1 << 15) - 1) << 0)) >> 0)
+#define F_PCK_STUFF_HSYNCPOLARITY(x) (((x) & ((1 << 1) - 1)) << 15)
+#define F_PCK_STUFF_HSYNCPOLARITY_RD(x) (((x) & (((1 << 1) - 1) << 15)) >> 15)
+#define F_PCK_STUFF_HWIDTH(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_PCK_STUFF_HWIDTH_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register MSA_VERTICAL_0 */
+#define MSA_VERTICAL_0 34
+#define F_PCK_STUFF_VTOTAL(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_PCK_STUFF_VTOTAL_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_PCK_STUFF_VSTART(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_PCK_STUFF_VSTART_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register MSA_VERTICAL_1 */
+#define MSA_VERTICAL_1 35
+#define F_PCK_STUFF_VSYNCWIDTH(x) (((x) & ((1 << 15) - 1)) << 0)
+#define F_PCK_STUFF_VSYNCWIDTH_RD(x) (((x) & (((1 << 15) - 1) << 0)) >> 0)
+#define F_PCK_STUFF_VSYNCPOLARITY(x) (((x) & ((1 << 1) - 1)) << 15)
+#define F_PCK_STUFF_VSYNCPOLARITY_RD(x) (((x) & (((1 << 1) - 1) << 15)) >> 15)
+#define F_PCK_STUFF_VHEIGHT(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_PCK_STUFF_VHEIGHT_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register MSA_MISC */
+#define MSA_MISC 36
+#define F_MSA_MISC0(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_MSA_MISC0_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_MSA_MISC1(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_MSA_MISC1_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_MSA_MISC1_INV(x) (((x) & ((1 << 1) - 1)) << 16)
+#define F_MSA_MISC1_INV_RD(x) (((x) & (((1 << 1) - 1) << 16)) >> 16)
+#define F_MSA_IN_MID_INTERLACE_EN(x) (((x) & ((1 << 1) - 1)) << 17)
+#define F_MSA_IN_MID_INTERLACE_EN_RD(x) (((x) & (((1 << 1) - 1) << 17)) >> 17)
+
+/* register STREAM_CONFIG */
+#define STREAM_CONFIG 37
+#define F_STREAM_NUM(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_STREAM_NUM_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+
+/* register AUDIO_PACK_STATUS */
+#define AUDIO_PACK_STATUS 38
+#define F_AP_FIFO_EMPTY(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_AP_FIFO_EMPTY_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_AP_FIFO_FULL(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_AP_FIFO_FULL_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_AP_AIF_FSM_CURR_ST(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_AP_AIF_FSM_CURR_ST_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_AP_SDP_TRANSFER_FSM_CURR_ST(x) (((x) & ((1 << 3) - 1)) << 3)
+#define F_AP_SDP_TRANSFER_FSM_CURR_ST_RD(x) (((x) & (((1 << 3) - 1) << 3)) >> 3)
+#define F_AP_FIFO_RD_FSM_CURR_ST(x) (((x) & ((1 << 2) - 1)) << 6)
+#define F_AP_FIFO_RD_FSM_CURR_ST_RD(x) (((x) & (((1 << 2) - 1) << 6)) >> 6)
+#define F_AP_FIFO_WR_FSM_CURR_ST(x) (((x) & ((1 << 2) - 1)) << 8)
+#define F_AP_FIFO_WR_FSM_CURR_ST_RD(x) (((x) & (((1 << 2) - 1) << 8)) >> 8)
+#define F_AP_PARITY_FSM_CURRENT_STATE(x) (((x) & ((1 << 3) - 1)) << 10)
+#define F_AP_PARITY_FSM_CURRENT_STATE_RD(x) (((x) & (((1 << 3) - 1) << 10)) >> 10)
+#define F_AUDIO_TS_VERSION(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_AUDIO_TS_VERSION_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+
+/* register VIF_STATUS */
+#define VIF_STATUS 39
+#define F_VIF_FIFO_EMPTY(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_VIF_FIFO_EMPTY_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_VIF_FIFO_FULL(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_VIF_FIFO_FULL_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_VIF_WR_CTRL_STATE(x) (((x) & ((1 << 6) - 1)) << 2)
+#define F_VIF_WR_CTRL_STATE_RD(x) (((x) & (((1 << 6) - 1) << 2)) >> 2)
+#define F_VIF_RD_CTRL_STATE(x) (((x) & ((1 << 20) - 1)) << 8)
+#define F_VIF_RD_CTRL_STATE_RD(x) (((x) & (((1 << 20) - 1) << 8)) >> 8)
+
+/* register PCK_STUFF_STATUS_0 */
+#define PCK_STUFF_STATUS_0 40
+#define F_NO_VIDEO_GEN_STATE(x) (((x) & ((1 << 5) - 1)) << 0)
+#define F_NO_VIDEO_GEN_STATE_RD(x) (((x) & (((1 << 5) - 1) << 0)) >> 0)
+#define F_SST_VIDEO_GEN_STATE(x) (((x) & ((1 << 7) - 1)) << 8)
+#define F_SST_VIDEO_GEN_STATE_RD(x) (((x) & (((1 << 7) - 1) << 8)) >> 8)
+#define F_MST_VIDEO_GEN_STATE(x) (((x) & ((1 << 6) - 1)) << 16)
+#define F_MST_VIDEO_GEN_STATE_RD(x) (((x) & (((1 << 6) - 1) << 16)) >> 16)
+#define F_MSA_GEN_STATE(x) (((x) & ((1 << 7) - 1)) << 24)
+#define F_MSA_GEN_STATE_RD(x) (((x) & (((1 << 7) - 1) << 24)) >> 24)
+
+/* register PCK_STUFF_STATUS_1 */
+#define PCK_STUFF_STATUS_1 41
+#define F_SST_SS_GEN_STATE(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_SST_SS_GEN_STATE_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_MST_SS_GEN_STATE(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_MST_SS_GEN_STATE_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+
+/* register INFO_PACK_STATUS */
+#define INFO_PACK_STATUS 42
+#define F_INFO_PACK_FIFO_FULL(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_INFO_PACK_FIFO_FULL_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_INFO_PACK_FIFO_EMPTY(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_INFO_PACK_FIFO_EMPTY_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_IP_PARITY_FSM_CURRENT_STATE(x) (((x) & ((1 << 3) - 1)) << 2)
+#define F_IP_PARITY_FSM_CURRENT_STATE_RD(x) (((x) & (((1 << 3) - 1) << 2)) >> 2)
+#define F_IP_FIFO_WR_FSM_CURRENT_STATE(x) (((x) & ((1 << 3) - 1)) << 5)
+#define F_IP_FIFO_WR_FSM_CURRENT_STATE_RD(x) (((x) & (((1 << 3) - 1) << 5)) >> 5)
+#define F_IP_FIFO_RD_FSM_CURRENT_STATE(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_IP_FIFO_RD_FSM_CURRENT_STATE_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_IP_SEND_DATA_FSM_CURRENT_STATE(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_IP_SEND_DATA_FSM_CURRENT_STATE_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_IN_VBID(x) (((x) & ((1 << 8) - 1)) << 24)
+#define F_IN_VBID_RD(x) (((x) & (((1 << 8) - 1) << 24)) >> 24)
+
+/* register RATE_GOVERNOR_STATUS */
+#define RATE_GOVERNOR_STATUS 43
+#define F_RATE_GOVERNOR_FSM_STATE(x) (((x) & ((1 << 3) - 1)) << 0)
+#define F_RATE_GOVERNOR_FSM_STATE_RD(x) (((x) & (((1 << 3) - 1) << 0)) >> 0)
+#define F_CFG_TU_VS_DIFF(x) (((x) & ((1 << 2) - 1)) << 8)
+#define F_CFG_TU_VS_DIFF_RD(x) (((x) & (((1 << 2) - 1) << 8)) >> 8)
+#define F_CFG_HSYNC_DELAY(x) (((x) & ((1 << 8) - 1)) << 16)
+#define F_CFG_HSYNC_DELAY_RD(x) (((x) & (((1 << 8) - 1) << 16)) >> 16)
+#define F_CFG_EN_HSYNC_DELAY(x) (((x) & ((1 << 1) - 1)) << 24)
+#define F_CFG_EN_HSYNC_DELAY_RD(x) (((x) & (((1 << 1) - 1) << 24)) >> 24)
+
+/* register DP_HORIZONTAL */
+#define DP_HORIZONTAL 44
+#define F_HSYNCWIDTH(x) (((x) & ((1 << 15) - 1)) << 0)
+#define F_HSYNCWIDTH_RD(x) (((x) & (((1 << 15) - 1) << 0)) >> 0)
+#define F_HWIDTH(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_HWIDTH_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register DP_VERTICAL_0 */
+#define DP_VERTICAL_0 45
+#define F_VHEIGHT(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_VHEIGHT_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_VSTART(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_VSTART_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register DP_VERTICAL_1 */
+#define DP_VERTICAL_1 46
+#define F_VTOTAL(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_VTOTAL_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_VTOTAL_EVEN(x) (((x) & ((1 << 1) - 1)) << 16)
+#define F_VTOTAL_EVEN_RD(x) (((x) & (((1 << 1) - 1) << 16)) >> 16)
+
+/* register DP_BLOCK_SDP */
+#define DP_BLOCK_SDP 47
+#define F_BLOCK_SDP_BS(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_BLOCK_SDP_BS_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_BLOCK_SDP_BE(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_BLOCK_SDP_BE_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_NO_VIDEO_BLOCK_SDP(x) (((x) & ((1 << 12) - 1)) << 16)
+#define F_NO_VIDEO_BLOCK_SDP_RD(x) (((x) & (((1 << 12) - 1) << 16)) >> 16)
+
+#endif //DPTX_STREAM
diff --git a/drivers/mxc/hdp/general_handler.h b/drivers/mxc/hdp/general_handler.h
new file mode 100644
index 000000000000..8ff69a2c3a13
--- /dev/null
+++ b/drivers/mxc/hdp/general_handler.h
@@ -0,0 +1,166 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * general_handler.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef GENERAL_HANDLER_H
+#define GENERAL_HANDLER_H
+
+/**
+ * \file
+ * \brief general handler, checks available messages, receives it from mailbox, handles requests and sends response to the host
+ */
+#define DP_TX_MAIL_HANDLER_REQUEST_BUFFER_LEN 256
+
+/**
+ * \brief opcode defines host->controller
+ */
+#define GENERAL_MAIN_CONTROL 0x01
+#define GENERAL_TEST_ECHO 0x02
+#define GENERAL_BUS_SETTINGS 0x03
+#define GENERAL_TEST_ACCESS 0x04
+
+#define GENERAL_WRITE_REGISTER 0x05
+#define GENERAL_WRITE_FIELD 0x06
+#define GENERAL_READ_REGISTER 0x07
+#define GENERAL_GET_HPD_STATE 0x11
+
+#define GENERAL_TEST_TRNG_SIMPLE 0xF0
+
+#define GENERAL_MAIN_CONTROL_SET_ACTIVE_BIT 0
+#define GENERAL_MAIN_CONTROL_SET_ALT_CIPHER_ADDR 1
+#define GENERAL_MAIN_CONTROL_SET_FAST_HDCP_DELAYS 2
+
+#define GENERAL_BUS_SETTINGS_DPCD_BUS_BIT 0
+#define GENERAL_BUS_SETTINGS_DPCD_BUS_LOCK_BIT 1
+#define GENERAL_BUS_SETTINGS_HDCP_BUS_BIT 2
+#define GENERAL_BUS_SETTINGS_HDCP_BUS_LOCK_BIT 3
+#define GENERAL_BUS_SETTINGS_CAPB_OWNER_BIT 4
+#define GENERAL_BUS_SETTINGS_CAPB_OWNER_LOCK_BIT 5
+
+/**
+ * \brief opcode defines controller->host
+ */
+
+#define GENERAL_MAIN_CONTROL_RESP 0x01
+#define GENERAL_TEST_ECHO_RESP 0x02
+#define GENERAL_BUS_SETTINGS_RESP 0x03
+
+#define GENERAL_READ_REGISTER_RESP 0x07
+
+#define GENERAL_BUS_SETTINGS_RESP_DPCD_BUS_BIT 0
+#define GENERAL_BUS_SETTINGS_RESP_HDCP_BUS_BIT 1
+#define GENERAL_BUS_SETTINGS_RESP_CAPB_OWNER_BIT 2
+
+#define GENERAL_BUS_SETTINGS_RESP_SUCCESS 0
+#define GENERAL_BUS_SETTINGS_RESP_LOCK_ERROR 1
+
+typedef struct {
+ unsigned char dpcd_locked;
+ unsigned char hdcp_locked;
+ unsigned char capb_locked;
+ unsigned char active_mode;
+} S_GENERAL_HANDLER_DATA;
+
+/**
+ * \brief event id sent to the host
+ */
+typedef enum {
+ EVENT_ID_DPTX_HPD = 0,
+ EVENT_ID_HDMI_TX_HPD = 0,
+ EVENT_ID_HDMI_RX_5V = 0,
+
+ EVENT_ID_DPTX_TRAINING = 1,
+ EVENT_ID_HDMI_RX_SCDC_CHANGE = 1,
+
+ EVENT_ID_RESERVE0 = 2,
+ EVENT_ID_RESERVE1 = 3,
+
+ EVENT_ID_HDCPTX_STATUS = 4,
+ EVENT_ID_HDCPRX_STATUS = 4,
+
+ EVENT_ID_HDCPTX_IS_KM_STORED = 5,
+ EVENT_ID_HDCPTX_STORE_KM = 6,
+ EVENT_ID_HDCPTX_IS_RECEIVER_ID_VALID = 7,
+ EVENT_ID_HDMITX_READ_REQUEST = 8,
+} EVENT_ID;
+
+/**
+ * \brief convert bank id and register number to address and write to ptr
+ */
+
+#define select_reg_old(bank, reg_no, ptr) \
+{ \
+ ptr = 0; \
+ if ((bank == 0x22) || (bank == 0x20) || (bank == 0x0b) || (bank == 0x09) || (bank == 0x0A)) \
+ ptr = (u32 *)(bank << 8 | reg_no); \
+}
+
+#define select_reg(bank, reg_no, ptr) \
+do { \
+ ptr = (u32 *)(bank << 8 | reg_no); \
+} while (0)
+
+#define select_reg4(pmsb, p2, p3, plsb, ptr) \
+do { \
+ ptr = (u32 *)((pmsb << 24) | (p2 << 16) | (p3 << 8) | (plsb << 0)); \
+} while (0)
+
+#define EVENTS_DPTX_CNT 2
+#define EVENTS_HDCPTX_CNT 4
+
+void general_handler_set_active_mode(void);
+void general_handler_set_standby_mode(void);
+
+/**
+ * \brief request sending en event to the host
+ * \param [in] eventId
+ * \param [in] eventCode
+ */
+
+#endif /* GENERAL_HANDLER_H */
diff --git a/drivers/mxc/hdp/hdcp.h b/drivers/mxc/hdp/hdcp.h
new file mode 100644
index 000000000000..d756541dc9d1
--- /dev/null
+++ b/drivers/mxc/hdp/hdcp.h
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * hdcp.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef HDCP_H
+#define HDCP_H
+# include "mailBox.h"
+
+#define RX_TX_HDCP_TRANS_MAX_BUFFER 640
+#endif //HDCP_H
diff --git a/drivers/mxc/hdp/hdcp2.h b/drivers/mxc/hdp/hdcp2.h
new file mode 100644
index 000000000000..df11446b3ba1
--- /dev/null
+++ b/drivers/mxc/hdp/hdcp2.h
@@ -0,0 +1,289 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * hdcp2.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef HDCP2_H
+#define HDCP2_H
+#include "mailBox.h"
+/* HDCP 2 registers
+ * and general use function for HDCP2 (transmitter and receiver)
+ * Author - yehonatan levin - cadence */
+/**
+ * \file
+ * \brief HDCP 2 registers
+ * and general use function for HDCP2 (trasmiter and reciever)
+ */
+
+/* HDCP2 register list */
+
+#ifdef DP_TX
+#define HDCP2_RTX 0x69000
+#define HDCP2_TX_CAPS 0x69008
+#define HDCP2_CERT_RX 0x6900B
+#define HDCP2_RRX 0x69215
+#define HDCP2_RX_CAPS 0x6921D
+#define HDCP2_EKPUB_KM 0x69220
+#define HDCP2_EKH_KM_WR 0x692A0
+#define HDCP2_M 0x692B0
+#define HDCP2_H_TAG 0x692C0
+#define HDCP2_EKH_KM_RD 0x692E0
+#define HDCP2_RN 0x692F0
+#define HDCP2_L_TAG 0x692F8
+#define HDCP2_EDKEY_KS 0x69318
+#define HDCP2_RIV 0x69328
+#define HDCP2_RX_INFO 0x69330
+#define HDCP2_SEQ_NUM_V 0x69332
+#define HDCP2_V_TAG 0x69335
+#define HDCP2_RECEIVER_ID_LIST 0x69345
+#define HDCP2_V 0x693E0
+#define HDCP2_SEQ_NUM_M 0x693F0
+#define HDCP2_K 0x693F3
+#define HDCP2_STREAM_ID_TYPE 0x693F5
+#define HDCP2_M_TAG 0x69473
+#define HDCP2_RXSTATUS 0x69493
+#define HDCP2_RSVD 0x69494
+#define HDCP2_DBG 0x69518
+
+#else /* HDMI */
+#define HDCP2_HDCP14 0x0
+#define HDCP2_RSVD1 0x44
+#define HDCP2_HDCP2_VERSION 0x50
+#define HDCP2_RSVD2 0x51
+#define HDCP2_WRITE_MESSAGE 0x60
+#define HDCP2_RSVD3 0x61
+#define HDCP2_RXSTATUS 0x70
+#define HDCP2_RSVD4 0x72
+#define HDCP2_READ_MESSAGE 0x80
+#define HDCP2_RSVD5 0x81
+#define HDCP2_DBG 0xC0
+#endif
+
+/* HDCP2 commands */
+#define HDCP2_CMD_AKE_INIT 2
+#define HDCP2_CMD_AKE_SEND_CERT 3
+#define HDCP2_CMD_AKE_NO_STORED_KM 4
+#define HDCP2_CMD_AKE_STORED_KM 5
+#define HDCP2_CMD_AKE_SEND_H_PRIME 7
+#define HDCP2_CMD_AKE_SEND_PAIRING_INFO 8
+#define HDCP2_CMD_LC_INIT 9
+#define HDCP2_CMD_LC_SEND_L_PRIME 10
+#define HDCP2_SKE_SEND_EKS 11
+#define HDCP2_REPEATER_AUTH_SEND_RECEIVER_ID_LIST 12
+#define HDCP2_REPEATER_AUTH_SEND_ACK 15
+#define HDCP2_REPEATER_AUTH_STREAM_MANAGE 16
+#define HDCP2_REPEATER_AUTH_STREAM_READY 17
+
+/* values */
+#define HDCP2_VAL_HDCP2_VERSION_SUPPORTED 2
+
+#define LC_128_LEN 16
+extern u8 pHdcpLc128[LC_128_LEN];
+
+typedef enum {
+ HDCP2_NOT_FINISHED = 0x11,
+ HDCP2_FINISHED
+} HDCP_2_REC_RES;
+
+/* command structs */
+/* AKE INIT */
+typedef struct {
+ u8 version;
+ u8 transmitter_capability_mask[2];
+} S_HDCP2_TXCAPS;
+
+typedef struct {
+ u8 rtx[8];
+ S_HDCP2_TXCAPS txcaps;
+} S_HDCP2_CMD_AKE_INIT;
+
+/* AKE_SEND_CERT */
+
+typedef struct {
+ u8 cert_rx[522];
+ u8 r_rx[8];
+ u8 rxcaps[3];
+} S_HDCP2_CMD_AKE_SEND_CERT;
+
+/* AKE_NO_STORED_KM */
+
+typedef struct {
+ u8 ekpub_km[128];
+} S_HDCP2_CMD_AKE_NO_STORED_KM;
+
+/* AKE_STORED_KM */
+
+typedef struct {
+ u8 ekh_km[16];
+ u8 m[16];
+} S_HDCP2_CMD_AKE_STORED_KM;
+
+/* AKE_SEND_H_PRIME */
+
+typedef struct {
+ u8 h[32];
+} S_HDCP2_CMD_AKE_SEND_H_PRIME;
+
+/* AKE_SEND_PAIRING_INFO */
+
+typedef struct {
+ u8 Ekh_Km[16];
+} S_HDCP2_CMD_AKE_SEND_PAIRING_INFO;
+
+/* LC_Init */
+
+typedef struct {
+ u8 rn[8];
+} S_HDCP2_CMD_LC_Init;
+
+/* LC_Send_L_Prime */
+
+typedef struct {
+ u8 l[32];
+} S_HDCP2_CMD_LC_Send_L_Prime;
+
+/* LC_Send_Eks */
+
+typedef struct {
+ u8 Edkey_Ks[16];
+ u8 Riv[8];
+} S_HDCP2_CMD_SKE_Send_Eks;
+
+/* REPEATER_AUTH_SEND_RECEIVER_ID_LIST */
+
+typedef struct {
+ u8 RxInfo[2];
+ u8 seq_num_V[3];
+ u8 V[16]; /* max device count * 5 */
+} S_HDCP2_CMD_REPEATER_AUTH_SEND_RECEIVER_ID_LIST;
+
+/* HDCP2_RxInfo bits */
+typedef struct {
+ u16 HDCP1_DEVICE_DOWNSTREAM:1;
+ u16 HDCP2_0_REPEATER_DOWNSTREAM:1;
+ u16 MAX_CASCADE_EXCEEDED:1;
+ u16 MAX_DEVS_EXCEEDED:1;
+ u16 DEVICE_COUNT:5;
+ u16 DEPTH:3;
+} S_HDCP2_RX_INFO_BITS;
+
+typedef union {
+ S_HDCP2_RX_INFO_BITS bits;
+ u16 value16Bit;
+} U_HDCP2_RX_INFO;
+
+/* REPEATER_AUTH_SEND_ACK */
+
+typedef struct {
+ u8 v[16];
+} S_HDCP2_CMD_REPEATER_AUTH_SEND_ACK;
+
+/* REPEATER_AUTH_STREAM_MANAGE */
+
+typedef struct {
+ u8 seq_num_m[3];
+ u8 k[2];
+ u8 streamId_Type[2]; /* should be k*2 by spec??? */
+} S_HDCP2_CMD_REPEATER_AUTH_STREAM_MANAGE;
+
+/* REPEATER_AUTH_STREAM_READY */
+
+typedef struct {
+ u8 m[32];
+} S_HDCP2_CMD_REPEATER_AUTH_STREAM_READY;
+
+/* HDCP2_RXSTATUS bits */
+#ifdef DP_TX
+typedef struct {
+
+ u8 READY:1;
+ u8 H_AVAILABLE:1;
+ u8 PAIRING_AVAILABLE:1;
+ u8 REAUTH_REQ:1;
+ u8 LINK_INTEGRITY_FAILURE:1;
+ u8 RSVD:3;
+} S_HDCP2_RX_STATUS_BITS;
+#else
+typedef struct {
+ u16 Message_Size:10;
+ u16 READY:1;
+ u16 REAUTH_REQ:1;
+ u16 RSVD:4;
+} S_HDCP2_RX_STATUS_BITS;
+
+#endif
+
+typedef union {
+ S_HDCP2_RX_STATUS_BITS bits;
+ u16 value16Bit;
+} U_HDCP2_RX_STATUS;
+
+/* HDCP ports mail box messages */
+typedef enum {
+ HDCP_GENERAL_SET_LC_128 = 0,
+ HDCP_SET_SEED,
+} HDCP_GENERAL_MSG;
+
+/**
+ * \brief get command length for specific command
+ *
+ * \param [in] offset offset of the command
+ * \return Return_Description
+ *
+ */
+u32 hdcp2_commandLen(u32 offset);
+/**
+ * \brief message length for specific message
+ *
+ * \param [in] msg the message
+ * \return the size of this message
+ *
+ */
+u32 hdcp2_MsgcommandLen(u8 msg);
+
+#endif
diff --git a/drivers/mxc/hdp/hdcp_tran.h b/drivers/mxc/hdp/hdcp_tran.h
new file mode 100644
index 000000000000..38f365ffa2a4
--- /dev/null
+++ b/drivers/mxc/hdp/hdcp_tran.h
@@ -0,0 +1,258 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * hdcp_tran.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef HDCP_TRAN_H
+#define HDCP_TRAN_H
+
+#include "hdcp.h"
+
+/**
+ * \file
+ * \brief general HDCP2 transmitter function and data structures
+ */
+
+/* supported HDCP TX ports */
+typedef enum {
+ HDCP_TX_PORT_0,
+ HDCP_TX_PORT_1,
+ HDCP_TX_PORT_2,
+ HDCP_TX_PORT_3,
+ HDCP_TX_NUM_OF_PORTS,
+} HDCP_TX_PORT;
+
+/* HDCP TX ports working mode (HDCP 2.2 or 1.4) */
+typedef enum {
+ HDCP_TX_2, /* lock only with HDCP2 */
+ HDCP_TX_1, /* lock only with HDCP1 */
+ HDCP_TX_BOTH, /* lock on HDCP2 or 1 depend on other side */
+} HDCP_TX_MODE;
+
+/* HDCP TX ports stream type (relevant if receiver is repeater) */
+typedef enum {
+ HDCP_CONTENT_TYPE_0, /* May be transmitted by The HDCP Repeater to all HDCP Devices. */
+ HDCP_CONTENT_TYPE_1, /* Must not be transmitted by the HDCP Repeater to HDCP 1.x-compliant Devices and HDCP 2.0-compliant Repeaters */
+} HDCP_TX_CONTENT_STREAM_TYPE;
+
+/* HDCP TX ports stream packet status */
+typedef enum {
+ HDCP_CONTENT_NEED_TO_SEND,
+ HDCP_CONTENT_SENT_AND_WAIT_FOR_RESPOND,
+ HDCP_CONTENT_SENT_AND_FAILED,
+ HDCP_CONTENT_SUCCESS,
+} HDCP_TX_CONTENT_STREAM_STATUS;
+
+/* HDCP TX ports working mode (HDCP 2.2 or 1.4) */
+typedef enum {
+ HDCP_TX_NOT_ACTIVE,
+ HDCP_TX_NOT_CONFIGURED,
+ HDCP_TX_START,
+ HDCP_TX_WAIT_FOR_RX_TYPE,
+ HDCP_TX_ACTION
+} HDCP_TX_STATE;
+
+typedef union {
+ struct {
+ HDCP_TX_MODE port_supported_modes:2;
+ HDCP_TX_MODE port_cur_mode:2;
+ HDCP_TX_STATE port_state:4;
+ HDCP_TX_CONTENT_STREAM_TYPE contentType:1;
+ HDCP_TX_CONTENT_STREAM_STATUS content_status:2;
+ u8 statusWasUpdated:1;
+ u8 errorWasUpdated:1;
+ u8 ENABLE_1_1_FEATURES:1;
+ u8 ENABLE_1_1_FEATURES_onCurrentConnection:1;
+ u8 hdmi_mode:1;
+ u8 irq:1;
+ } fields;
+ u32 bits;
+} U_HDCP_TRANS_PORT_DATA_STATUS;
+
+/* struct holding data needed to the HDCP transmitter */
+#define TX_PORT_STATUS_EXTRA_DATA 3
+typedef struct {
+
+ U_HDCP_TRANS_PORT_DATA_STATUS status;
+ u16 port_status;
+ u8 port_status_extraData[TX_PORT_STATUS_EXTRA_DATA];
+ u32 seq_num_M; /* for sending content stream manage */
+ u32 seq_num_V;
+ u8 rxTxBuffer[RX_TX_HDCP_TRANS_MAX_BUFFER];
+
+ u8 recieverIdListCommand[(128 * 5) + 4];
+ u32 recieverIdListSize;
+ MB_TYPE mailBoxType;
+
+} S_HDCP_TRANS_PORT_DATA;
+
+typedef struct {
+ S_HDCP_TRANS_PORT_DATA port[HDCP_TX_NUM_OF_PORTS];
+} S_HDCP_TRANS_DATA;
+
+/* HDCP TX ports working mode (HDCP 2.2 or 1.4) */
+
+/**
+ *
+ * \brief transmitter supported API (via mail box)
+ */
+typedef enum {
+ HDCP_TX_CONFIGURATION, /*!< use this command to set HDCP transmitter type and wake it up (or stop ), 1 byte with following bits : Bit (0-1)= 0 - support only HDCP 2, 1 - support only HDCP 1, 2 - support both HDCP, Bit 2 - active (to activate port set to 1), to stop port set to 0 */
+ HDCP2_TX_SET_PUBLIC_KEY_PARAMS, /*!< use it to set public key for the HDCP2.x transmitter(HDCP2.x), Modulus n - 384 bytes, E - 3 bytes */
+ HDCP2_TX_SET_DEBUG_RANDOM_NUMBERS, /*!< use this command to enforce the random parameters (for debug only!), instead of the random data generated by the embedded RNG.Use this command after HDCP_TX_SET_PUBLIC_KEY_PARAMS command. Relevant to (HDCP2.x), data is : KM 16 bytes,RN 8 bytes,KS 16 bytes,RIV 8 bytes,RTX 8 bytes */
+ HDCP2_TX_RESPOND_KM, /*!< If km is stored, return all parameters, else there is no extra data(HDCP2.x), data is : Receiver ID (5 bytes),m (16 bytes),Km (16 bytes),Ekh(Km)(16 bytes) */
+ HDCP1_TX_SEND_KEYS, /*!< send keys needed for HDCP 1, data is : AKSV (5 bytes), ksv (7*40 = 280 bytes) */
+ HDCP1_TX_SEND_RANDOM_AN, /*!< set AN, use it for debug purpose, if not use, it will be random number, data is (8 bytes) */
+ HDCP_TX_STATUS_CHANGE, /*!< Will be called in port status change event by cadence HDCP IP, Status for the port:Bit 0 - AUTHENTICATED (1 - link is authenticated), Bit 1 - receiver is REPEATER (1 for repeater, 0 not),Bit 2 - 0 for HDCP1, 1 for HDCP2, */
+ HDCP2_TX_IS_KM_STORED, /*!< controller check if KM is stored by host(HDCP2.x), data is : Receiver ID (5 bytes) */
+ HDCP2_TX_STORE_KM, /*!< controller ask host to store KM, host may store it on non-volatile memory for faster authentication(HDCP2.x), data is : Receiver ID (5 bytes),m (16 bytes),Km(16 bytes),Ekh(Km),(16 bytes) */
+ HDCP_TX_IS_RECEIVER_ID_VALID, /*!< controller check if receivers ID are not in revocation list, input is->first byte for number of receivers, then list of receivers (5 bytes each) */
+ HDCP_TX_RESPOND_RECEIVER_ID_VALID, /*!< If receivers ID are valid return 1, otherwise return 0, same for HDCP1,HDCP2 */
+ HDCP_TX_TEST_KEYS, /*!< compare HDCP keys with facsimile key */
+ HDCP2_TX_SET_KM_KEY_PARAMS, /*!< This Command is used to load customer defined Key for km-key encryption into the HDCP2.x transmitter controller. */
+} HDCP_TRNAS_MAIL_BOX_MSG;
+ /** @} *///
+
+/* HDCP_TX_CONFIGURATION */
+
+/* bits 0-1 HDCP_TX_MODE */
+#define HDCP_TX_CONFIGURATION_MODE_OFFSET 0
+#define HDCP_TX_CONFIGURATION_MODE_LEN 2
+#define HDCP_TX_CONFIGURATION_RUN 2
+#define HDCP_TX_CONFIGURATION_RPTR_CONTENT_STREAM_MNGR_OFFSET 3
+#define HDCP_TX_CONFIGURATION_RPTR 4
+#define HDCP_TX_ENABLE_1_1_FEATURES 5
+#define HDCP_TX_SECOND_LINK 6
+#define HDCP_TX_HDMI_MODE 7
+
+#define HDCP_TX_CONFIGURATION_ENABLE_KM_KEY_MASK (1 << 4)
+
+/* HDCP_TX_STATUS_CHANGE bits */
+#define HDCP_STATUS_AUTHENTICATED 0
+#define HDCP_STATUS_REPEATER 1
+#define HDCP_STATUS_HDCP2 2
+#define HDCP_STATUS_STRAM_MANAGE_SUCCESS 4
+#define HDCP_STATUS_ERROR_TYPE 5
+#define HDCP_STATUS_1_1_FEATURES 9
+
+/**
+ *
+ * \brief different error types for HDCP_TX_STATUS_CHANGE
+ */
+typedef enum {
+ HDCP_TRAN_ERR_No_error,
+ HDCP_TRAN_ERR_HPD_is_down,
+ HDCP_TRAN_ERR_SRM_failure,
+ HDCP_TRAN_ERR_signature_verification,
+ HDCP_TRAN_ERR_h_tag_diff_h,
+ HDCP_TRAN_ERR_v_tag_diff_v,
+ HDCP_TRAN_ERR_locality_check,
+ HDCP_TRAN_ERR_Ddc,
+ HDCP_TRAN_ERR_REAUTH_REQ,
+ HDCP_TRAN_ERR_topology,
+ HDCP_TRAN_ERR_HDCP_RSVD1,
+ HDCP_TRAN_ERR_HDMI_capability,
+ HDCP_TRAN_ERR_RI,
+ HDCP_TRAN_ERR_watchDog_expired,
+} HDCP_TRNAS_ERR_TYPE;
+
+/* HDCP2_TX_SET_PUBLIC_KEY_PARAMS */
+#define DLP_MODULUS_N 384
+#define DLP_E 3
+typedef struct {
+ u8 N[DLP_MODULUS_N];
+ u8 E[DLP_E];
+} S_HDCP_TRANS_PUBLIC_KEY_PARAMS;
+
+/* HDCP2_TX_SET_KM_KEY_PARAMS */
+#define DLP_KM_KEY 16
+typedef struct {
+ u8 KM_KEY[DLP_KM_KEY];
+} S_HDCP_TRANS_KM_KEY_PARAMS;
+
+/* HDCP2_TX_SET_DEBUG_RANDOM_NUMBERS */
+#define DEBUG_RANDOM_NUMBERS_KM_LEN 16
+#define DEBUG_RANDOM_NUMBERS_RN_LEN 8
+#define DEBUG_RANDOM_NUMBERS_KS_LEN 16
+#define DEBUG_RANDOM_NUMBERS_RIV_LEN 8
+#define DEBUG_RANDOM_NUMBERS_RTX_LEN 8
+
+typedef struct {
+ u8 KM[DEBUG_RANDOM_NUMBERS_KM_LEN];
+ u8 RN[DEBUG_RANDOM_NUMBERS_RN_LEN];
+ u8 KS[DEBUG_RANDOM_NUMBERS_KS_LEN];
+ u8 RIV[DEBUG_RANDOM_NUMBERS_RIV_LEN];
+ u8 RTX[DEBUG_RANDOM_NUMBERS_RTX_LEN];
+} S_HDCP_TRANS_DEBUG_RANDOM_NUMBERS;
+
+#define HDCP_PAIRING_M_LEN 16
+#define HDCP_PAIRING_M_EKH 16
+#define HDCP_PAIRING_R_ID 5
+
+typedef struct {
+ u8 Receiver_ID[HDCP_PAIRING_R_ID];
+ u8 m[HDCP_PAIRING_M_LEN];
+ u8 KM[DEBUG_RANDOM_NUMBERS_KM_LEN];
+ u8 EKH[HDCP_PAIRING_M_EKH];
+} S_HDCP_TRANS_PAIRING_DATA;
+
+typedef struct {
+ u8 Receiver_ID[HDCP_PAIRING_R_ID];
+} S_HDCP_TRANS_REVOCATION_LIST;
+
+/* HDCP1_TX_SEND_KEYS */
+#define AKSV_SIZE (5)
+#define HDCPT1_KSV_SIZE (7 * 40)
+
+typedef struct {
+ u8 AKSV[AKSV_SIZE];
+ u8 KSV[HDCPT1_KSV_SIZE];
+} S_HDCP_TX_MAIL_BOX_CMD_HDCP1_TX_SEND_KEYS;
+
+#define AN_SIZE (8)
+
+/* HDCP2_TX_SESSION_KEY */
+#define HDCP_SESSION_KEY_LEN 16
+
+#endif //HDCP_TRAN_H
diff --git a/drivers/mxc/hdp/hdmi.h b/drivers/mxc/hdp/hdmi.h
new file mode 100644
index 000000000000..de69699c5d14
--- /dev/null
+++ b/drivers/mxc/hdp/hdmi.h
@@ -0,0 +1,122 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * hdmi.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef _HDMI__
+#define _HDMI__
+/* ONLY ENUMS AND #DEFINES IN THIS FILE *
+ * THIS FILE WILL BE USED IN HOST'S API */
+
+#define EDID_SLAVE_ADDRESS 0x50
+#define EDID_SEGMENT_SLAVE_ADDRESS 0x30
+#define SCDC_SLAVE_ADDRESS 0x54
+
+typedef enum {
+ HDMI_TX_READ,
+ HDMI_TX_WRITE,
+ HDMI_TX_UPDATE_READ,
+ HDMI_TX_EDID,
+ HDMI_TX_EVENTS,
+ HDMI_TX_HPD_STATUS,
+ HDMI_TX_DEBUG_ECHO = 0xAA,
+ HDMI_TX_TEST = 0xBB,
+ HDMI_TX_EDID_INTERNAL = 0xF0,
+} HDMI_TX_OPCODE;
+
+typedef enum {
+ HDMI_I2C_ACK,
+ HDMI_I2C_NACK,
+ HDMI_I2C_TO,
+ HDMI_I2C_ARB_LOST,
+ HDMI_I2C_RRTO,
+ HDMI_I2C_RRT,
+ /** when i2c hardware didn't respond after some time */
+ HDMI_I2C_HW_TO,
+ HDMI_I2C_ERR //unspecified error
+} HDMI_I2C_STATUS;
+
+typedef enum {
+ HDMI_RX_SET_EDID,
+ HDMI_RX_SCDC_SET,
+ HDMI_RX_SCDC_GET,
+ HDMI_RX_READ_EVENTS,
+ HDMI_RX_SET_HPD,
+
+ HDMI_RX_DEBUG_ECHO = 0xAA,
+ HDMI_RX_TEST = 0xBB,
+} HDMI_RX_OPCODE;
+
+typedef enum {
+ HDMI_SCDC_SINK_VER,
+ HDMI_SCDC_SOURCE_VER,
+} HDMI_SCDC_FIELD;
+
+typedef struct {
+ u8 sink_ver;
+ u8 manufacturer_oui_1;
+ u8 manufacturer_oui_2;
+ u8 manufacturer_oui_3;
+ u8 devId[8];
+ u8 hardware_major_rev;
+ u8 hardware_minor_rev;
+ u8 software_major_rev;
+ u8 software_minor_rev;
+ u8 manufacturerSpecific[34];
+} S_HDMI_SCDC_SET_MSG;
+
+typedef struct {
+ u8 source_ver;
+ u8 TMDS_Config;
+ u8 config_0;
+ u8 manufacturerSpecific[34];
+} S_HDMI_SCDC_GET_MSG;
+
+/* hpd events location */
+#define HDMI_RX_EVENT_5V_HIGH 0
+#define HDMI_RX_EVENT_5V_LOW 1
+#define HDMI_TX_EVENT_reserved 2
+#define HDMI_RX_EVENT_5V_VAL 3
+
+#endif
diff --git a/drivers/mxc/hdp/mailBox.h b/drivers/mxc/hdp/mailBox.h
new file mode 100644
index 000000000000..b8e069378de0
--- /dev/null
+++ b/drivers/mxc/hdp/mailBox.h
@@ -0,0 +1,116 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * mailBox.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef MAIL_BOX_H
+#define MAIL_BOX_H
+
+#define MAIL_BOX_MAX_SIZE 600
+#define MAIL_BOX_MAX_TX_SIZE 160
+
+ /**
+ * \file mailBox.h
+ * \brief Implementation mail box communication channel between IP and external host
+ */
+
+#define MB_MODULE_ID_DP_TX 0x01
+#define MB_MODULE_ID_DP_RX 0x02
+#define MB_MODULE_ID_HDMI_TX 0x03
+#define MB_MODULE_ID_HDMI_RX 0x04
+#define MB_MODULE_ID_MHL_TX 0x05
+#define MB_MODULE_ID_MHL_RX 0x06
+#define MB_MODULE_ID_HDCP_TX 0x07
+#define MB_MODULE_ID_HDCP_RX 0x08
+#define MB_MODULE_ID_HDCP_GENERAL 0x09
+#define MB_MODULE_ID_GENERAL 0x0A
+
+typedef enum {
+ MB_TYPE_REGULAR,
+ MB_TYPE_SECURE,
+ MB_TYPE_COUNT,
+} MB_TYPE;
+
+typedef enum {
+ MB_SUCCESS,
+ MB_BUSY,
+ MB_NO_MEMORY
+} MB_RET;
+
+typedef enum {
+ MB_TO_HOST,
+ MB_TO_CONTROLLER,
+} MB_IDX;
+
+typedef enum {
+ MB_STATE_EMPTY,
+ MB_STATE_WAIT_MODULE_ID,
+ MB_STATE_WAIT_SIZE_MSB,
+ MB_STATE_WAIT_SIZE_LSB,
+ MB_STATE_READ_DATA,
+ MB_STATE_MSG_READY,
+} MB_RX_STATE;
+
+#define MB_OPCODE_ID 0
+#define MB_MODULE_ID 1
+#define MB_SIZE_MSB_ID 2
+#define MB_SIZE_LSB_ID 3
+#define MB_DATA_ID 4
+
+typedef struct {
+ MB_RX_STATE rxState;
+ u32 rx_data_idx;
+ u32 rx_final_msgSize;
+ u8 rxBuff[MAIL_BOX_MAX_SIZE];
+ u8 txBuff[MAIL_BOX_MAX_TX_SIZE];
+ u32 txTotal;
+ u32 txCur;
+} S_MAIL_BOX_PORT_DATA;
+
+typedef struct {
+ S_MAIL_BOX_PORT_DATA portData;
+ u8 portsTxBusy; //bit for each port (0-7)
+} S_MAIL_BOX_DATA;
+
+#endif //MAIL_BOX_H
diff --git a/drivers/mxc/hdp/mhl_hdtx_top.h b/drivers/mxc/hdp/mhl_hdtx_top.h
new file mode 100644
index 000000000000..209b939a88e1
--- /dev/null
+++ b/drivers/mxc/hdp/mhl_hdtx_top.h
@@ -0,0 +1,220 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * mhl_hdtx_top.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef MHL_HDTX_TOP_H_
+#define MHL_HDTX_TOP_H_
+
+/* register SCHEDULER_H_SIZE */
+#define SCHEDULER_H_SIZE 0
+#define F_H_BLANK_SIZE(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_H_BLANK_SIZE_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_H_ACTIVE_SIZE(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_H_ACTIVE_SIZE_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register SCHEDULER_V_SIZE */
+#define SCHEDULER_V_SIZE 1
+#define F_V_BLANK_SIZE(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_V_BLANK_SIZE_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_V_ACTIVE_SIZE(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_V_ACTIVE_SIZE_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register SCHEDULER_KEEP_OUT */
+#define SCHEDULER_KEEP_OUT 2
+#define F_HKEEP_OUT(x) (((x) & ((1 << 9) - 1)) << 0)
+#define F_HKEEP_OUT_RD(x) (((x) & (((1 << 9) - 1) << 0)) >> 0)
+#define F_VKEEP_OUT_START(x) (((x) & ((1 << 11) - 1)) << 9)
+#define F_VKEEP_OUT_START_RD(x) (((x) & (((1 << 11) - 1) << 9)) >> 9)
+#define F_VKEEP_OUT_ZONE(x) (((x) & ((1 << 8) - 1)) << 20)
+#define F_VKEEP_OUT_ZONE_RD(x) (((x) & (((1 << 8) - 1) << 20)) >> 20)
+
+/* register HDTX_SIGNAL_FRONT_WIDTH */
+#define HDTX_SIGNAL_FRONT_WIDTH 3
+#define F_HFRONT(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_HFRONT_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_VFRONT(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_VFRONT_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register HDTX_SIGNAL_SYNC_WIDTH */
+#define HDTX_SIGNAL_SYNC_WIDTH 4
+#define F_HSYNC(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_HSYNC_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_VSYNC(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_VSYNC_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register HDTX_SIGNAL_BACK_WIDTH */
+#define HDTX_SIGNAL_BACK_WIDTH 5
+#define F_HBACK(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_HBACK_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_VBACK(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_VBACK_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register HDTX_CONTROLLER */
+#define HDTX_CONTROLLER 6
+#define F_HDMI_MODE(x) (((x) & ((1 << 2) - 1)) << 0)
+#define F_HDMI_MODE_RD(x) (((x) & (((1 << 2) - 1) << 0)) >> 0)
+#define F_VIF_DATA_WIDTH(x) (((x) & ((1 << 2) - 1)) << 2)
+#define F_VIF_DATA_WIDTH_RD(x) (((x) & (((1 << 2) - 1) << 2)) >> 2)
+#define F_AUTO_MODE(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_AUTO_MODE_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_IL_PROG(x) (((x) & ((1 << 2) - 1)) << 5)
+#define F_IL_PROG_RD(x) (((x) & (((1 << 2) - 1) << 5)) >> 5)
+#define F_PIC_3D(x) (((x) & ((1 << 4) - 1)) << 7)
+#define F_PIC_3D_RD(x) (((x) & (((1 << 4) - 1) << 7)) >> 7)
+#define F_BCH_EN(x) (((x) & ((1 << 1) - 1)) << 11)
+#define F_BCH_EN_RD(x) (((x) & (((1 << 1) - 1) << 11)) >> 11)
+#define F_GCP_EN(x) (((x) & ((1 << 1) - 1)) << 12)
+#define F_GCP_EN_RD(x) (((x) & (((1 << 1) - 1) << 12)) >> 12)
+#define F_SET_AVMUTE(x) (((x) & ((1 << 1) - 1)) << 13)
+#define F_SET_AVMUTE_RD(x) (((x) & (((1 << 1) - 1) << 13)) >> 13)
+#define F_CLEAR_AVMUTE(x) (((x) & ((1 << 1) - 1)) << 14)
+#define F_CLEAR_AVMUTE_RD(x) (((x) & (((1 << 1) - 1) << 14)) >> 14)
+#define F_DATA_EN(x) (((x) & ((1 << 1) - 1)) << 15)
+#define F_DATA_EN_RD(x) (((x) & (((1 << 1) - 1) << 15)) >> 15)
+#define F_HDMI_ENCODING(x) (((x) & ((1 << 2) - 1)) << 16)
+#define F_HDMI_ENCODING_RD(x) (((x) & (((1 << 2) - 1) << 16)) >> 16)
+#define F_HDMI2_PREAMBLE_EN(x) (((x) & ((1 << 1) - 1)) << 18)
+#define F_HDMI2_PREAMBLE_EN_RD(x) (((x) & (((1 << 1) - 1) << 18)) >> 18)
+#define F_HDMI2_CTRL_IL_MODE(x) (((x) & ((1 << 1) - 1)) << 19)
+#define F_HDMI2_CTRL_IL_MODE_RD(x) (((x) & (((1 << 1) - 1) << 19)) >> 19)
+
+/* register HDTX_HDCP */
+#define HDTX_HDCP 7
+#define F_HDTX_HDCP_SELECT(x) (((x) & ((1 << 2) - 1)) << 0)
+#define F_HDTX_HDCP_SELECT_RD(x) (((x) & (((1 << 2) - 1) << 0)) >> 0)
+#define F_ENC_BIT(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_ENC_BIT_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_HDCP_ENABLE_1P1_FEATURES(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_HDCP_ENABLE_1P1_FEATURES_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_HDCP_DELAY_FIFO_SW_RST(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_HDCP_DELAY_FIFO_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_HDCP_DELAY_FIFO_SW_START(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_HDCP_DELAY_FIFO_SW_START_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_HDCP_DOUBLE_FIFO_SW_RST(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_HDCP_DOUBLE_FIFO_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+#define F_HDCP_SINGLE_FIFO_SW_RST(x) (((x) & ((1 << 1) - 1)) << 7)
+#define F_HDCP_SINGLE_FIFO_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 7)) >> 7)
+#define F_HDCP_DELAY_FIFO_AFULL_THR(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_HDCP_DELAY_FIFO_AFULL_THR_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_HDCP_CTRL_SW_RST(x) (((x) & ((1 << 1) - 1)) << 12)
+#define F_HDCP_CTRL_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 12)) >> 12)
+#define F_HDCP_CTRL_IL_MODE(x) (((x) & ((1 << 1) - 1)) << 13)
+#define F_HDCP_CTRL_IL_MODE_RD(x) (((x) & (((1 << 1) - 1) << 13)) >> 13)
+
+/* register HDTX_HPD */
+#define HDTX_HPD 8
+#define F_HPD_VALID_WIDTH(x) (((x) & ((1 << 12) - 1)) << 0)
+#define F_HPD_VALID_WIDTH_RD(x) (((x) & (((1 << 12) - 1) << 0)) >> 0)
+#define F_HPD_GLITCH_WIDTH(x) (((x) & ((1 << 8) - 1)) << 12)
+#define F_HPD_GLITCH_WIDTH_RD(x) (((x) & (((1 << 8) - 1) << 12)) >> 12)
+
+/* register HDTX_CLOCK_REG_0 */
+#define HDTX_CLOCK_REG_0 9
+#define F_DATA_REGISTER_VAL_0(x) (((x) & ((1 << 20) - 1)) << 0)
+#define F_DATA_REGISTER_VAL_0_RD(x) (((x) & (((1 << 20) - 1) << 0)) >> 0)
+
+/* register HDTX_CLOCK_REG_1 */
+#define HDTX_CLOCK_REG_1 10
+#define F_DATA_REGISTER_VAL_1(x) (((x) & ((1 << 20) - 1)) << 0)
+#define F_DATA_REGISTER_VAL_1_RD(x) (((x) & (((1 << 20) - 1) << 0)) >> 0)
+
+/* register HPD_PLUG_IN */
+#define HPD_PLUG_IN 11
+#define F_FILTER_HPD(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_FILTER_HPD_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register HDCP_IN */
+#define HDCP_IN 12
+#define F_HDCP_ESS_STATE(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_HDCP_ESS_STATE_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_HDCP_DOUBLE_FIFO_WFULL(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_HDCP_DOUBLE_FIFO_WFULL_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_HDCP_DOUBLE_FIFO_REMPTY(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_HDCP_DOUBLE_FIFO_REMPTY_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_HDCP_DOUBLE_FIFO_OVERRUN(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_HDCP_DOUBLE_FIFO_OVERRUN_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+#define F_HDCP_DOUBLE_FIFO_UNDERRUN(x) (((x) & ((1 << 1) - 1)) << 7)
+#define F_HDCP_DOUBLE_FIFO_UNDERRUN_RD(x) (((x) & (((1 << 1) - 1) << 7)) >> 7)
+#define F_HDCP_DELAY_FIFO_EMPTY(x) (((x) & ((1 << 1) - 1)) << 8)
+#define F_HDCP_DELAY_FIFO_EMPTY_RD(x) (((x) & (((1 << 1) - 1) << 8)) >> 8)
+#define F_HDCP_DELAY_FIFO_FULL(x) (((x) & ((1 << 1) - 1)) << 9)
+#define F_HDCP_DELAY_FIFO_FULL_RD(x) (((x) & (((1 << 1) - 1) << 9)) >> 9)
+#define F_HDCP_SINGLE_FIFO_WFULL(x) (((x) & ((1 << 2) - 1)) << 10)
+#define F_HDCP_SINGLE_FIFO_WFULL_RD(x) (((x) & (((1 << 2) - 1) << 10)) >> 10)
+#define F_HDCP_SINGLE_FIFO_REMPTY(x) (((x) & ((1 << 2) - 1)) << 12)
+#define F_HDCP_SINGLE_FIFO_REMPTY_RD(x) (((x) & (((1 << 2) - 1) << 12)) >> 12)
+#define F_HDCP_SINGLE_FIFO_OVERRUN(x) (((x) & ((1 << 2) - 1)) << 14)
+#define F_HDCP_SINGLE_FIFO_OVERRUN_RD(x) (((x) & (((1 << 2) - 1) << 14)) >> 14)
+#define F_HDCP_SINGLE_FIFO_UNDERRUN(x) (((x) & ((1 << 2) - 1)) << 16)
+#define F_HDCP_SINGLE_FIFO_UNDERRUN_RD(x) (((x) & (((1 << 2) - 1) << 16)) >> 16)
+
+/* register GCP_FORCE_COLOR_DEPTH_CODING */
+#define GCP_FORCE_COLOR_DEPTH_CODING 13
+#define F_COLOR_DEPTH_VAL(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_COLOR_DEPTH_VAL_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_COLOR_DEPTH_FORCE(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_COLOR_DEPTH_FORCE_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_DEFAULT_PHASE_VAL(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_DEFAULT_PHASE_VAL_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+
+/* register SSCP_POSITIONING */
+#define SSCP_POSITIONING 14
+#define F_SSCP_ROW_VAL(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_SSCP_ROW_VAL_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_SSCP_COL_VAL(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_SSCP_COL_VAL_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register HDCP_WIN_OF_OPP_POSITION */
+#define HDCP_WIN_OF_OPP_POSITION 15
+#define F_HDCP_WIN_OF_OPP_START(x) (((x) & ((1 << 10) - 1)) << 0)
+#define F_HDCP_WIN_OF_OPP_START_RD(x) (((x) & (((1 << 10) - 1) << 0)) >> 0)
+#define F_HDCP_WIN_OF_OPP_SIZE(x) (((x) & ((1 << 6) - 1)) << 10)
+#define F_HDCP_WIN_OF_OPP_SIZE_RD(x) (((x) & (((1 << 6) - 1) << 10)) >> 10)
+
+#endif //MHL_HDTX_TOP
diff --git a/drivers/mxc/hdp/opcodes.h b/drivers/mxc/hdp/opcodes.h
new file mode 100644
index 000000000000..0313d63a5176
--- /dev/null
+++ b/drivers/mxc/hdp/opcodes.h
@@ -0,0 +1,116 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * opcodes.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef OPCODES_H_
+#define OPCODES_H_
+
+#define DP_TX_MAIL_HANDLER_H
+#define DP_TX_MAIL_HANDLER_REQUEST_BUFFER_LEN 256
+#define DPTX_SET_POWER_MNG 0x00
+#define DPTX_SET_HOST_CAPABILITIES 0x01
+#define DPTX_GET_EDID 0x02
+#define DPTX_READ_DPCD 0x03
+#define DPTX_WRITE_DPCD 0x04
+#define DPTX_ENABLE_EVENT 0x05
+#define DPTX_WRITE_REGISTER 0x06
+#define DPTX_READ_REGISTER 0x07
+#define DPTX_WRITE_FIELD 0x08
+#define DPTX_TRAINING_CONTROL 0x09
+#define DPTX_READ_EVENT 0x0A
+#define DPTX_READ_LINK_STAT 0x0B
+#define DPTX_SET_VIDEO 0x0C
+#define DPTX_SET_AUDIO 0x0D
+#define DPTX_GET_LAST_AUX_STAUS 0x0E
+#define DPTX_SET_LINK_BREAK_POINT 0x0F
+#define DPTX_FORCE_LANES 0x10
+#define DPTX_HPD_STATE 0x11
+#define DPTX_EDP_RATE_TRAINING 0x12
+#define DPTX_DBG_SET 0xF0
+#define DP_TX_OPCODE_READ_I2C_REQUEST 0xA5
+#define DP_TX_OPCODE_WRITE_I2C_REQUEST 0xA6
+#define DP_TX_OPCODE_MESSAGE_FILTER 0xA7
+#define DPTX_EDID_RESP 0x02
+#define DPTX_DPCD_READ_RESP 0x03
+#define DPTX_DPCD_WRITE_RESP 0x04
+#define DPTX_READ_EVENT_RESP 0x0A
+#define DPTX_READ_REGISTER_RESP 0x07
+#define DP_TX_OPCODE_MESSAGE 0x10
+#define DP_TX_OPCODE_READ_I2C_RESPONSE 0x50
+#define DP_TX_OPCODE_WRITE_I2C_RESPONSE 0x60
+#define DP_TX_OPCODE_LOOPBACK_TEST 0xFE
+#define DP_TX_OPCODE_BIT_TEST 0xFF
+#define DP_TX_EVENT_ENABLE_HPD_BIT 0x00
+#define DP_TX_EVENT_ENABLE_TRAINING_BIT 0x01
+#define DP_TX_EVENT_CODE_HPD_HIGH 0x01
+#define DP_TX_EVENT_CODE_HPD_LOW 0x02
+#define DP_TX_EVENT_CODE_HPD_PULSE 0x04
+#define DP_TX_EVENT_CODE_HPD_STATE_HIGH 0x08
+#define DP_TX_EVENT_CODE_HPD_STATE_LOW 0x00
+#define DP_TX_EVENT_CODE_TRAINING_FULL_STARTED 0x01
+#define DP_TX_EVENT_CODE_TRAINING_FAST_STARTED 0x02
+#define DP_TX_EVENT_CODE_TRAINING_FINISHED_CR 0x04
+#define DP_TX_EVENT_CODE_TRAINING_FINISHED_EQ 0x08
+#define DP_TX_EVENT_CODE_TRAINING_FINISHED_FAST 0x10
+#define DP_TX_EVENT_CODE_TRAINING_FAILED_CR 0x20
+#define DP_TX_EVENT_CODE_TRAINING_FAILED_EQ 0x40
+#define DP_TX_EVENT_CODE_TRAINING_FAILED_FAST 0x80
+#define MB_MODULE_ID_DP_TX 0x01
+#define MB_MODULE_ID_DP_RX 0x02
+#define MB_MODULE_ID_HDMI_TX 0x03
+#define MB_MODULE_ID_HDMI_RX 0x04
+#define MB_MODULE_ID_MHL_TX 0x05
+#define MB_MODULE_ID_MHL_RX 0x06
+#define MB_MODULE_ID_HDCP_TX 0x07
+#define MB_MODULE_ID_HDCP_RX 0x08
+#define MB_MODULE_ID_HDCP_GENERAL 0x09
+#define MB_MODULE_ID_GENERAL 0x0A
+#define MB_MODULE_ID 1
+
+#endif
diff --git a/drivers/mxc/hdp/sink_aif_encoder.h b/drivers/mxc/hdp/sink_aif_encoder.h
new file mode 100644
index 000000000000..c75a1033ebd3
--- /dev/null
+++ b/drivers/mxc/hdp/sink_aif_encoder.h
@@ -0,0 +1,367 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * sink_aif_encoder.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef SINK_AIF_ENCODER_H_
+#define SINK_AIF_ENCODER_H_
+
+/* register AUDIO_SINK_CNTL */
+#define AUDIO_SINK_CNTL 0
+#define F_SINK_SW_RST(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_I2S_ENC_START(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_I2S_ENC_START_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+
+/* register AUDIO_SINK_STTS */
+#define AUDIO_SINK_STTS 1
+#define F_CH_INDX_ERR(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_CH_INDX_ERR_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register AUDIO_SINK_CNFG */
+#define AUDIO_SINK_CNFG 2
+#define F_ENC_LOW_INDEX_MSB(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_ENC_LOW_INDEX_MSB_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_AUDIO_CH_NUM(x) (((x) & ((1 << 5) - 1)) << 1)
+#define F_SINK_AUDIO_CH_NUM_RD(x) (((x) & (((1 << 5) - 1) << 1)) >> 1)
+#define F_ENC_SAMPLE_JUST(x) (((x) & ((1 << 2) - 1)) << 6)
+#define F_ENC_SAMPLE_JUST_RD(x) (((x) & (((1 << 2) - 1) << 6)) >> 6)
+#define F_ENC_SMPL_WIDTH(x) (((x) & ((1 << 2) - 1)) << 8)
+#define F_ENC_SMPL_WIDTH_RD(x) (((x) & (((1 << 2) - 1) << 8)) >> 8)
+#define F_I2S_ENC_WL_SIZE(x) (((x) & ((1 << 2) - 1)) << 10)
+#define F_I2S_ENC_WL_SIZE_RD(x) (((x) & (((1 << 2) - 1) << 10)) >> 10)
+#define F_CNTL_SMPL_ONLY_EN(x) (((x) & ((1 << 1) - 1)) << 12)
+#define F_CNTL_SMPL_ONLY_EN_RD(x) (((x) & (((1 << 1) - 1) << 12)) >> 12)
+#define F_SINK_AIF_TYPE_SMPL(x) (((x) & ((1 << 4) - 1)) << 13)
+#define F_SINK_AIF_TYPE_SMPL_RD(x) (((x) & (((1 << 4) - 1) << 13)) >> 13)
+#define F_CNTL_TYPE_OVRD(x) (((x) & ((1 << 4) - 1)) << 17)
+#define F_CNTL_TYPE_OVRD_RD(x) (((x) & (((1 << 4) - 1) << 17)) >> 17)
+#define F_CNTL_TYPE_OVRD_EN(x) (((x) & ((1 << 1) - 1)) << 21)
+#define F_CNTL_TYPE_OVRD_EN_RD(x) (((x) & (((1 << 1) - 1) << 21)) >> 21)
+#define F_I2S_ENC_PORT_EN(x) (((x) & ((1 << 4) - 1)) << 22)
+#define F_I2S_ENC_PORT_EN_RD(x) (((x) & (((1 << 4) - 1) << 22)) >> 22)
+#define F_WS_POLARITY(x) (((x) & ((1 << 1) - 1)) << 26)
+#define F_WS_POLARITY_RD(x) (((x) & (((1 << 1) - 1) << 26)) >> 26)
+
+/* register FIFO_CNTL_ADDR */
+#define FIFO_CNTL_ADDR 3
+#define F_CFG_FIFO_SW_RST(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_CFG_FIFO_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_CFG_INDEX_SYNC_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_CFG_INDEX_SYNC_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_CFG_FIFO_DIR(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_CFG_FIFO_DIR_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_CFG_DIS_PORT3(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_CFG_DIS_PORT3_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+
+/* register FIFO_STTS_ADDR */
+#define FIFO_STTS_ADDR 4
+#define F_ST_WFULL_REG(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_ST_WFULL_REG_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_ST_REMPTY_REG(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_ST_REMPTY_REG_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_ST_OVERRUN_REG(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_ST_OVERRUN_REG_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_ST_UNDERRUN_REG(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_ST_UNDERRUN_REG_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+
+/* register SINK_COM_CH_STTS_BITS */
+#define SINK_COM_CH_STTS_BITS 5
+#define F_BYTE0(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_BYTE0_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_CATEGORY_CODE(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_CATEGORY_CODE_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_SAMPLING_FREQ(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_SAMPLING_FREQ_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_CLOCK_ACCURACY(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_CLOCK_ACCURACY_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_ORIGINAL_SAMP_FREQ(x) (((x) & ((1 << 4) - 1)) << 24)
+#define F_ORIGINAL_SAMP_FREQ_RD(x) (((x) & (((1 << 4) - 1) << 24)) >> 24)
+
+/* register SINK_STTS_BIT_CH01 */
+#define SINK_STTS_BIT_CH01 6
+#define F_SOURCE_NUM_CH0(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH0_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH0(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH0_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH0(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH0_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH1(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH1_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH1(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH1_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH1(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH1_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+
+/* register SINK_STTS_BIT_CH23 */
+#define SINK_STTS_BIT_CH23 7
+#define F_SOURCE_NUM_CH2(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH2_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH2(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH2_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH2(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH2_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH3(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH3_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH3(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH3_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH3(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH3_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+
+/* register SINK_STTS_BIT_CH45 */
+#define SINK_STTS_BIT_CH45 8
+#define F_SOURCE_NUM_CH4(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH4_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH4(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH4_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH4(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH4_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH5(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH5_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH5(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH5_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH5(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH5_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+
+/* register SINK_STTS_BIT_CH67 */
+#define SINK_STTS_BIT_CH67 9
+#define F_SOURCE_NUM_CH6(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH6_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH6(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH6_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH6(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH6_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH7(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH7_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH7(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH7_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH7(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH7_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+
+/* register SINK_STTS_BIT_CH89 */
+#define SINK_STTS_BIT_CH89 10
+#define F_SOURCE_NUM_CH8(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH8_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH8(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH8_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH8(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH8_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH9(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH9_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH9(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH9_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH9(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH9_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+
+/* register SINK_STTS_BIT_CH1011 */
+#define SINK_STTS_BIT_CH1011 11
+#define F_SOURCE_NUM_CH10(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH10_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH10(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH10_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH10(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH10_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH11(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH11_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH11(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH11_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH11(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH11_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+
+/* register SINK_STTS_BIT_CH1213 */
+#define SINK_STTS_BIT_CH1213 12
+#define F_SOURCE_NUM_CH12(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH12_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH12(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH12_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH12(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH12_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH13(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH13_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH13(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH13_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH13(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH13_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+
+/* register SINK_STTS_BIT_CH1415 */
+#define SINK_STTS_BIT_CH1415 13
+#define F_SOURCE_NUM_CH14(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH14_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH14(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH14_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH14(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH14_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH15(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH15_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH15(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH15_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH15(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH15_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+
+/* register SINK_STTS_BIT_CH1617 */
+#define SINK_STTS_BIT_CH1617 14
+#define F_SOURCE_NUM_CH16(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH16_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH16(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH16_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH16(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH16_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH17(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH17_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH17(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH17_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH17(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH17_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+
+/* register SINK_STTS_BIT_CH1819 */
+#define SINK_STTS_BIT_CH1819 15
+#define F_SOURCE_NUM_CH18(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH18_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH18(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH18_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH18(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH18_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH19(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH19_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH19(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH19_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH19(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH19_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+
+/* register SINK_STTS_BIT_CH2021 */
+#define SINK_STTS_BIT_CH2021 16
+#define F_SOURCE_NUM_CH20(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH20_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH20(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH20_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH20(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH20_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH21(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH21_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH21(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH21_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH21(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH21_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+
+/* register SINK_STTS_BIT_CH2223 */
+#define SINK_STTS_BIT_CH2223 17
+#define F_SOURCE_NUM_CH22(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH22_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH22(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH22_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH22(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH22_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH23(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH23_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH23(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH23_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH23(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH23_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+
+/* register SINK_STTS_BIT_CH2425 */
+#define SINK_STTS_BIT_CH2425 18
+#define F_SOURCE_NUM_CH24(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH24_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH24(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH24_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH24(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH24_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH25(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH25_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH25(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH25_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH25(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH25_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+
+/* register SINK_STTS_BIT_CH2627 */
+#define SINK_STTS_BIT_CH2627 19
+#define F_SOURCE_NUM_CH26(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH26_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH26(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH26_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH26(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH26_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH27(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH27_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH27(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH27_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH27(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH27_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+
+/* register SINK_STTS_BIT_CH2829 */
+#define SINK_STTS_BIT_CH2829 20
+#define F_SOURCE_NUM_CH28(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH28_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH28(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH28_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH28(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH28_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH29(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH29_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH29(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH29_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH29(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH29_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+
+/* register SINK_STTS_BIT_CH3031 */
+#define SINK_STTS_BIT_CH3031 21
+#define F_SOURCE_NUM_CH30(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH30_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH30(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH30_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH30(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH30_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH31(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH31_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH31(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH31_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH31(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH31_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+
+#endif /* SINK_AIF_ENCODER */
+
diff --git a/drivers/mxc/hdp/sink_car.h b/drivers/mxc/hdp/sink_car.h
new file mode 100644
index 000000000000..a38001c15b02
--- /dev/null
+++ b/drivers/mxc/hdp/sink_car.h
@@ -0,0 +1,168 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * sink_car.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef SINK_CAR_H_
+#define SINK_CAR_H_
+
+/* register SINK_MHL_HD_CAR */
+#define SINK_MHL_HD_CAR 0
+#define F_SINK_MHL_HD_VIF_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_MHL_HD_VIF_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_MHL_HD_VIF_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SINK_MHL_HD_VIF_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_SINK_MHL_HD_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_SINK_MHL_HD_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_SINK_MHL_HD_SYS_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_SINK_MHL_HD_SYS_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_SINK_MHL_HD_PHY_DATA_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_SINK_MHL_HD_PHY_DATA_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_SINK_MHL_HD_PHY_DATA_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_SINK_MHL_HD_PHY_DATA_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+
+/* register SINK_CEC_CAR */
+#define SINK_CEC_CAR 1
+#define F_SINK_CEC_SYS_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_CEC_SYS_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_CEC_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SINK_CEC_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+
+/* register SINK_SCDC_CAR */
+#define SINK_SCDC_CAR 2
+#define F_SINK_SCDC_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_SCDC_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_SCDC_SYS_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SINK_SCDC_SYS_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_SINK_SCDC_RSTN_EN(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_SINK_SCDC_RSTN_EN_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_SINK_SCDC_CLK_EN(x) (((x) & ((1 << 8) - 1)) << 16)
+#define F_SINK_SCDC_CLK_EN_RD(x) (((x) & (((1 << 8) - 1) << 16)) >> 16)
+
+/* register SINK_PKT_CAR */
+#define SINK_PKT_CAR 3
+#define F_SINK_PKT_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_PKT_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_PKT_SYS_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SINK_PKT_SYS_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_SINK_PKT_DATA_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_SINK_PKT_DATA_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_SINK_PKT_DATA_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_SINK_PKT_DATA_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+
+/* register SINK_AIF_CAR */
+#define SINK_AIF_CAR 4
+#define F_SINK_AIF_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_AIF_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_AIF_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SINK_AIF_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_SINK_AIF_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_SINK_AIF_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_SINK_AIF_SYS_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_SINK_AIF_SYS_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_SINK_ACR_CHAR_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_SINK_ACR_CHAR_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_SINK_ACR_CHAR_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_SINK_ACR_CHAR_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+
+/* register SINK_CIPHER_CAR */
+#define SINK_CIPHER_CAR 5
+#define F_SINK_CIPHER_CHAR_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_CIPHER_CHAR_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_CIPHER_CHAR_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SINK_CIPHER_CHAR_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_SINK_CIPHER_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_SINK_CIPHER_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_SINK_CIPHER_SYS_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_SINK_CIPHER_SYS_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+
+/* register SINK_CRYPTO_CAR */
+#define SINK_CRYPTO_CAR 6
+#define F_SINK_CRYPTO_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_CRYPTO_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_CRYPTO_SYS_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SINK_CRYPTO_SYS_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+
+/* register SINK_VIF_CAR */
+#define SINK_VIF_CAR 7
+#define F_SINK_VIF_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_VIF_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_VIF_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SINK_VIF_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+
+/* register SINK_AUDIO_CAR */
+#define SINK_AUDIO_CAR 8
+#define F_SINK_ACR_REF_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_ACR_REF_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_ACR_REF_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SINK_ACR_REF_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_SINK_SPDIF_MCLK_EN(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_SINK_SPDIF_MCLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_SINK_SPDIF_MCLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_SINK_SPDIF_MCLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_SINK_I2S_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_SINK_I2S_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_SINK_I2S_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_SINK_I2S_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+
+/* register SINK_PHY_CAR */
+#define SINK_PHY_CAR 9
+#define F_SINK_XT_PCLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_XT_PCLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_XT_PRESETN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SINK_XT_PRESETN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+
+/* register SINK_DEBUG_CAR */
+#define SINK_DEBUG_CAR 10
+#define F_SINK_CLOCK_METER_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_CLOCK_METER_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_CLOCK_METER_SYS_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SINK_CLOCK_METER_SYS_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+
+#endif /* SINK_CAR */
+
diff --git a/drivers/mxc/hdp/sink_clk_meters.h b/drivers/mxc/hdp/sink_clk_meters.h
new file mode 100644
index 000000000000..c238b9785583
--- /dev/null
+++ b/drivers/mxc/hdp/sink_clk_meters.h
@@ -0,0 +1,241 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * sink_clk_meters.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef SINK_CLK_METERS_H_
+#define SINK_CLK_METERS_H_
+
+/* register CLK_METER_REF_CFG */
+#define CLK_METER_REF_CFG 0
+#define F_REF_CYCLES_SINK_REF_CLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_REF_CYCLES_SINK_REF_CLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_TOLERANCE_SINK_REF_CLK(x) (((x) & ((1 << 4) - 1)) << 24)
+#define F_MEAS_TOLERANCE_SINK_REF_CLK_RD(x) (((x) & (((1 << 4) - 1) << 24)) >> 24)
+
+/* register CLK_METER_PHY_CHAR_CFG */
+#define CLK_METER_PHY_CHAR_CFG 1
+#define F_REF_CYCLES_SINK_PHY_CHAR_CLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_REF_CYCLES_SINK_PHY_CHAR_CLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_TOLERANCE_SINK_PHY_CHAR_CLK(x) (((x) & ((1 << 4) - 1)) << 24)
+#define F_MEAS_TOLERANCE_SINK_PHY_CHAR_CLK_RD(x) (((x) & (((1 << 4) - 1) << 24)) >> 24)
+
+/* register CLK_METER_PHY_DATA_CFG */
+#define CLK_METER_PHY_DATA_CFG 2
+#define F_REF_CYCLES_SINK_PHY_DATA_CLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_REF_CYCLES_SINK_PHY_DATA_CLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_TOLERANCE_SINK_PHY_DATA_CLK(x) (((x) & ((1 << 4) - 1)) << 24)
+#define F_MEAS_TOLERANCE_SINK_PHY_DATA_CLK_RD(x) (((x) & (((1 << 4) - 1) << 24)) >> 24)
+
+/* register CLK_METER_PHY_PIXEL_CFG */
+#define CLK_METER_PHY_PIXEL_CFG 3
+#define F_REF_CYCLES_SINK_PHY_PIXEL_CLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_REF_CYCLES_SINK_PHY_PIXEL_CLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_TOLERANCE_SINK_PHY_PIXEL_CLK(x) (((x) & ((1 << 4) - 1)) << 24)
+#define F_MEAS_TOLERANCE_SINK_PHY_PIXEL_CLK_RD(x) (((x) & (((1 << 4) - 1) << 24)) >> 24)
+
+/* register CLK_METER_SPDIF_CFG */
+#define CLK_METER_SPDIF_CFG 4
+#define F_REF_CYCLES_SINK_SPDIF_MCLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_REF_CYCLES_SINK_SPDIF_MCLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_TOLERANCE_SINK_SPDIF_MCLK(x) (((x) & ((1 << 4) - 1)) << 24)
+#define F_MEAS_TOLERANCE_SINK_SPDIF_MCLK_RD(x) (((x) & (((1 << 4) - 1) << 24)) >> 24)
+
+/* register CLK_METER_I2S_CFG */
+#define CLK_METER_I2S_CFG 5
+#define F_REF_CYCLES_SINK_I2S_CLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_REF_CYCLES_SINK_I2S_CLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_TOLERANCE_SINK_I2S_CLK(x) (((x) & ((1 << 4) - 1)) << 24)
+#define F_MEAS_TOLERANCE_SINK_I2S_CLK_RD(x) (((x) & (((1 << 4) - 1) << 24)) >> 24)
+
+/* register CLK_METER_PCLK_CFG */
+#define CLK_METER_PCLK_CFG 6
+#define F_REF_CYCLES_SINK_PCLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_REF_CYCLES_SINK_PCLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_TOLERANCE_SINK_PCLK(x) (((x) & ((1 << 4) - 1)) << 24)
+#define F_MEAS_TOLERANCE_SINK_PCLK_RD(x) (((x) & (((1 << 4) - 1) << 24)) >> 24)
+
+/* register CLK_METER_SCLK_CFG */
+#define CLK_METER_SCLK_CFG 7
+#define F_REF_CYCLES_SINK_SCLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_REF_CYCLES_SINK_SCLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_TOLERANCE_SINK_SCLK(x) (((x) & ((1 << 4) - 1)) << 24)
+#define F_MEAS_TOLERANCE_SINK_SCLK_RD(x) (((x) & (((1 << 4) - 1) << 24)) >> 24)
+
+/* register CLK_METER_CCLK_CFG */
+#define CLK_METER_CCLK_CFG 8
+#define F_REF_CYCLES_SINK_CCLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_REF_CYCLES_SINK_CCLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_TOLERANCE_SINK_CCLK(x) (((x) & ((1 << 4) - 1)) << 24)
+#define F_MEAS_TOLERANCE_SINK_CCLK_RD(x) (((x) & (((1 << 4) - 1) << 24)) >> 24)
+
+/* register CLK_METER_TRNG_CFG */
+#define CLK_METER_TRNG_CFG 9
+#define F_REF_CYCLES_SINK_TRNG_CLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_REF_CYCLES_SINK_TRNG_CLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_TOLERANCE_SINK_TRNG_CLK(x) (((x) & ((1 << 4) - 1)) << 24)
+#define F_MEAS_TOLERANCE_SINK_TRNG_CLK_RD(x) (((x) & (((1 << 4) - 1) << 24)) >> 24)
+
+/* register CLK_METER_REF_ST */
+#define CLK_METER_REF_ST 10
+#define F_MEAS_CYCLES_SINK_REF_CLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_MEAS_CYCLES_SINK_REF_CLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_STABLE_SINK_REF_CLK(x) (((x) & ((1 << 1) - 1)) << 24)
+#define F_MEAS_STABLE_SINK_REF_CLK_RD(x) (((x) & (((1 << 1) - 1) << 24)) >> 24)
+
+/* register CLK_METER_PHY_CHAR_ST */
+#define CLK_METER_PHY_CHAR_ST 11
+#define F_MEAS_CYCLES_SINK_PHY_CHAR_CLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_MEAS_CYCLES_SINK_PHY_CHAR_CLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_STABLE_SINK_PHY_CHAR_CLK(x) (((x) & ((1 << 1) - 1)) << 24)
+#define F_MEAS_STABLE_SINK_PHY_CHAR_CLK_RD(x) (((x) & (((1 << 1) - 1) << 24)) >> 24)
+
+/* register CLK_METER_PHY_DATA_ST */
+#define CLK_METER_PHY_DATA_ST 12
+#define F_MEAS_CYCLES_SINK_PHY_DATA_CLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_MEAS_CYCLES_SINK_PHY_DATA_CLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_STABLE_SINK_PHY_DATA_CLK(x) (((x) & ((1 << 1) - 1)) << 24)
+#define F_MEAS_STABLE_SINK_PHY_DATA_CLK_RD(x) (((x) & (((1 << 1) - 1) << 24)) >> 24)
+
+/* register CLK_METER_PHY_PIXEL_ST */
+#define CLK_METER_PHY_PIXEL_ST 13
+#define F_MEAS_CYCLES_SINK_PHY_PIXEL_CLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_MEAS_CYCLES_SINK_PHY_PIXEL_CLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_STABLE_SINK_PHY_PIXEL_CLK(x) (((x) & ((1 << 1) - 1)) << 24)
+#define F_MEAS_STABLE_SINK_PHY_PIXEL_CLK_RD(x) (((x) & (((1 << 1) - 1) << 24)) >> 24)
+
+/* register CLK_METER_SPDIF_ST */
+#define CLK_METER_SPDIF_ST 14
+#define F_MEAS_CYCLES_SINK_SPDIF_MCLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_MEAS_CYCLES_SINK_SPDIF_MCLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_STABLE_SINK_SPDIF_MCLK(x) (((x) & ((1 << 1) - 1)) << 24)
+#define F_MEAS_STABLE_SINK_SPDIF_MCLK_RD(x) (((x) & (((1 << 1) - 1) << 24)) >> 24)
+
+/* register CLK_METER_I2S_ST */
+#define CLK_METER_I2S_ST 15
+#define F_MEAS_CYCLES_SINK_I2S_CLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_MEAS_CYCLES_SINK_I2S_CLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_STABLE_SINK_I2S_CLK(x) (((x) & ((1 << 1) - 1)) << 24)
+#define F_MEAS_STABLE_SINK_I2S_CLK_RD(x) (((x) & (((1 << 1) - 1) << 24)) >> 24)
+
+/* register CLK_METER_PCLK_ST */
+#define CLK_METER_PCLK_ST 16
+#define F_MEAS_CYCLES_SINK_PCLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_MEAS_CYCLES_SINK_PCLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_STABLE_SINK_PCLK(x) (((x) & ((1 << 1) - 1)) << 24)
+#define F_MEAS_STABLE_SINK_PCLK_RD(x) (((x) & (((1 << 1) - 1) << 24)) >> 24)
+
+/* register CLK_METER_SCLK_ST */
+#define CLK_METER_SCLK_ST 17
+#define F_MEAS_CYCLES_SINK_SCLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_MEAS_CYCLES_SINK_SCLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_STABLE_SINK_SCLK(x) (((x) & ((1 << 1) - 1)) << 24)
+#define F_MEAS_STABLE_SINK_SCLK_RD(x) (((x) & (((1 << 1) - 1) << 24)) >> 24)
+
+/* register CLK_METER_CCLK_ST */
+#define CLK_METER_CCLK_ST 18
+#define F_MEAS_CYCLES_SINK_CCLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_MEAS_CYCLES_SINK_CCLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_STABLE_SINK_CCLK(x) (((x) & ((1 << 1) - 1)) << 24)
+#define F_MEAS_STABLE_SINK_CCLK_RD(x) (((x) & (((1 << 1) - 1) << 24)) >> 24)
+
+/* register CLK_METER_TRNG_ST */
+#define CLK_METER_TRNG_ST 19
+#define F_MEAS_CYCLES_SINK_TRNG_CLK(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_MEAS_CYCLES_SINK_TRNG_CLK_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_MEAS_STABLE_SINK_TRNG_CLK(x) (((x) & ((1 << 1) - 1)) << 24)
+#define F_MEAS_STABLE_SINK_TRNG_CLK_RD(x) (((x) & (((1 << 1) - 1) << 24)) >> 24)
+
+/* register CLK_METER_INT_MASK */
+#define CLK_METER_INT_MASK 20
+#define F_MEAS_MASK_SINK_REF_CLK(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_MEAS_MASK_SINK_REF_CLK_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_MEAS_MASK_SINK_PHY_CHAR_CLK(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_MEAS_MASK_SINK_PHY_CHAR_CLK_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_MEAS_MASK_SINK_PHY_DATA_CLK(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_MEAS_MASK_SINK_PHY_DATA_CLK_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_MEAS_MASK_SINK_PHY_PIXEL_CLK(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_MEAS_MASK_SINK_PHY_PIXEL_CLK_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_MEAS_MASK_SINK_SPDIF_MCLK(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_MEAS_MASK_SINK_SPDIF_MCLK_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_MEAS_MASK_SINK_I2S_CLK(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_MEAS_MASK_SINK_I2S_CLK_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_MEAS_MASK_SINK_PCLK(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_MEAS_MASK_SINK_PCLK_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+#define F_MEAS_MASK_SINK_SCLK(x) (((x) & ((1 << 1) - 1)) << 7)
+#define F_MEAS_MASK_SINK_SCLK_RD(x) (((x) & (((1 << 1) - 1) << 7)) >> 7)
+#define F_MEAS_MASK_SINK_CCLK(x) (((x) & ((1 << 1) - 1)) << 8)
+#define F_MEAS_MASK_SINK_CCLK_RD(x) (((x) & (((1 << 1) - 1) << 8)) >> 8)
+#define F_MEAS_MASK_SINK_TRNG_CLK(x) (((x) & ((1 << 1) - 1)) << 9)
+#define F_MEAS_MASK_SINK_TRNG_CLK_RD(x) (((x) & (((1 << 1) - 1) << 9)) >> 9)
+
+/* register CLK_METER_INT_ST */
+#define CLK_METER_INT_ST 21
+#define F_MEAS_STATUS_SINK_REF_CLK(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_MEAS_STATUS_SINK_REF_CLK_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_MEAS_STATUS_SINK_PHY_CHAR_CLK(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_MEAS_STATUS_SINK_PHY_CHAR_CLK_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_MEAS_STATUS_SINK_PHY_DATA_CLK(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_MEAS_STATUS_SINK_PHY_DATA_CLK_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_MEAS_STATUS_SINK_PHY_PIXEL_CLK(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_MEAS_STATUS_SINK_PHY_PIXEL_CLK_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_MEAS_STATUS_SINK_SPDIF_MCLK(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_MEAS_STATUS_SINK_SPDIF_MCLK_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_MEAS_STATUS_SINK_I2S_CLK(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_MEAS_STATUS_SINK_I2S_CLK_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_MEAS_STATUS_SINK_PCLK(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_MEAS_STATUS_SINK_PCLK_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+#define F_MEAS_STATUS_SINK_SCLK(x) (((x) & ((1 << 1) - 1)) << 7)
+#define F_MEAS_STATUS_SINK_SCLK_RD(x) (((x) & (((1 << 1) - 1) << 7)) >> 7)
+#define F_MEAS_STATUS_SINK_CCLK(x) (((x) & ((1 << 1) - 1)) << 8)
+#define F_MEAS_STATUS_SINK_CCLK_RD(x) (((x) & (((1 << 1) - 1) << 8)) >> 8)
+#define F_MEAS_STATUS_SINK_TRNG_CLK(x) (((x) & ((1 << 1) - 1)) << 9)
+#define F_MEAS_STATUS_SINK_TRNG_CLK_RD(x) (((x) & (((1 << 1) - 1) << 9)) >> 9)
+
+#endif /* SINK_CLK_METERS */
+
diff --git a/drivers/mxc/hdp/sink_core.h b/drivers/mxc/hdp/sink_core.h
new file mode 100644
index 000000000000..ba63ca2af41a
--- /dev/null
+++ b/drivers/mxc/hdp/sink_core.h
@@ -0,0 +1,117 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * sink_core.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef SINK_CORE_H_
+#define SINK_CORE_H_
+
+/* register SCDC_INT_MSK */
+#define SCDC_INT_MSK 0
+#define F_SCDC_INT_MASK(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SCDC_INT_MASK_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register SCDC_INT_STS */
+#define SCDC_INT_STS 1
+#define F_SCDC_INT_STATUS(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SCDC_INT_STATUS_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register PHY_IF_LANE0_CFG */
+#define PHY_IF_LANE0_CFG 2
+#define F_SINK_PHY_DATA0_DATA_REVERSE(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_PHY_DATA0_DATA_REVERSE_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_PHY_DATA0_CHAR_REVERSE(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SINK_PHY_DATA0_CHAR_REVERSE_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_SINK_PHY_CHAR0_SWAP(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_SINK_PHY_CHAR0_SWAP_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_SINK_PHY_LANE0(x) (((x) & ((1 << 2) - 1)) << 3)
+#define F_SINK_PHY_LANE0_RD(x) (((x) & (((1 << 2) - 1) << 3)) >> 3)
+
+/* register PHY_IF_LANE1_CFG */
+#define PHY_IF_LANE1_CFG 3
+#define F_SINK_PHY_DATA1_DATA_REVERSE(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_PHY_DATA1_DATA_REVERSE_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_PHY_DATA1_CHAR_REVERSE(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SINK_PHY_DATA1_CHAR_REVERSE_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_SINK_PHY_CHAR1_SWAP(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_SINK_PHY_CHAR1_SWAP_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_SINK_PHY_LANE1(x) (((x) & ((1 << 2) - 1)) << 3)
+#define F_SINK_PHY_LANE1_RD(x) (((x) & (((1 << 2) - 1) << 3)) >> 3)
+
+/* register PHY_IF_LANE2_CFG */
+#define PHY_IF_LANE2_CFG 4
+#define F_SINK_PHY_DATA2_DATA_REVERSE(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_PHY_DATA2_DATA_REVERSE_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_PHY_DATA2_CHAR_REVERSE(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SINK_PHY_DATA2_CHAR_REVERSE_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_SINK_PHY_CHAR2_SWAP(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_SINK_PHY_CHAR2_SWAP_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_SINK_PHY_LANE2(x) (((x) & ((1 << 2) - 1)) << 3)
+#define F_SINK_PHY_LANE2_RD(x) (((x) & (((1 << 2) - 1) << 3)) >> 3)
+
+/* register TOP_ST */
+#define TOP_ST 5
+#define F_SINK_5V(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_5V_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register TOP_CFG */
+#define TOP_CFG 6
+#define F_SINK_HPD(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_HPD_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register SCDC_FILTER_CFG */
+#define SCDC_FILTER_CFG 7
+#define F_SCDC_FILTER_BYPASS(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SCDC_FILTER_BYPASS_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SCDC_FILTER_VALID_WIDTH(x) (((x) & ((1 << 12) - 1)) << 1)
+#define F_SCDC_FILTER_VALID_WIDTH_RD(x) (((x) & (((1 << 12) - 1) << 1)) >> 1)
+#define F_SCDC_FILTER_GLITCH_WIDTH(x) (((x) & ((1 << 8) - 1)) << 13)
+#define F_SCDC_FILTER_GLITCH_WIDTH_RD(x) (((x) & (((1 << 8) - 1) << 13)) >> 13)
+
+#endif /* SINK_CORE */
+
diff --git a/drivers/mxc/hdp/sink_mhl_hd.h b/drivers/mxc/hdp/sink_mhl_hd.h
new file mode 100644
index 000000000000..be03200e9d96
--- /dev/null
+++ b/drivers/mxc/hdp/sink_mhl_hd.h
@@ -0,0 +1,418 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * sink_mhl_hd.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef SINK_MHL_HD_H_
+#define SINK_MHL_HD_H_
+
+/* register TMDS_ALIGN_CTRL */
+#define TMDS_ALIGN_CTRL 0
+#define F_CHAR_MATCH_CNT_THR(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_CHAR_MATCH_CNT_THR_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHAR_HAM_DIS_TOL(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHAR_HAM_DIS_TOL_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_LOCK_ALIGN(x) (((x) & ((1 << 1) - 1)) << 8)
+#define F_LOCK_ALIGN_RD(x) (((x) & (((1 << 1) - 1) << 8)) >> 8)
+#define F_ALIGN_WD_THR(x) (((x) & ((1 << 3) - 1)) << 9)
+#define F_ALIGN_WD_THR_RD(x) (((x) & (((1 << 3) - 1) << 9)) >> 9)
+#define F_ALIGN_ANY_CHAR(x) (((x) & ((1 << 1) - 1)) << 12)
+#define F_ALIGN_ANY_CHAR_RD(x) (((x) & (((1 << 1) - 1) << 12)) >> 12)
+
+/* register TMDS_DEC_CTRL */
+#define TMDS_DEC_CTRL 1
+#define F_DECODER_ERR_CORR_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_DECODER_ERR_CORR_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_TMDS_DECODER_SW_RST(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_TMDS_DECODER_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_TMDS_FORCE_HDMI_MODE(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_TMDS_FORCE_HDMI_MODE_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_TMDS_SW_HDMI_MODE(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_TMDS_SW_HDMI_MODE_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+
+/* register TMDS_DEC_ST */
+#define TMDS_DEC_ST 2
+#define F_DEFRAMER_HDMI_MODE(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_DEFRAMER_HDMI_MODE_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_CHAR_HAM_ERR(x) (((x) & ((1 << 3) - 1)) << 2)
+#define F_CHAR_HAM_ERR_RD(x) (((x) & (((1 << 3) - 1) << 2)) >> 2)
+#define F_CHAR_ALIGNED(x) (((x) & ((1 << 3) - 1)) << 5)
+#define F_CHAR_ALIGNED_RD(x) (((x) & (((1 << 3) - 1) << 5)) >> 5)
+#define F_CTRL_ALIGN_ERR(x) (((x) & ((1 << 1) - 1)) << 8)
+#define F_CTRL_ALIGN_ERR_RD(x) (((x) & (((1 << 1) - 1) << 8)) >> 8)
+#define F_CTRL_ALIGNED(x) (((x) & ((1 << 1) - 1)) << 9)
+#define F_CTRL_ALIGNED_RD(x) (((x) & (((1 << 1) - 1) << 9)) >> 9)
+#define F_TMDS_CHAR_CH0_WIN(x) (((x) & ((1 << 4) - 1)) << 10)
+#define F_TMDS_CHAR_CH0_WIN_RD(x) (((x) & (((1 << 4) - 1) << 10)) >> 10)
+#define F_TMDS_CHAR_CH1_WIN(x) (((x) & ((1 << 4) - 1)) << 14)
+#define F_TMDS_CHAR_CH1_WIN_RD(x) (((x) & (((1 << 4) - 1) << 14)) >> 14)
+#define F_TMDS_CHAR_CH2_WIN(x) (((x) & ((1 << 4) - 1)) << 18)
+#define F_TMDS_CHAR_CH2_WIN_RD(x) (((x) & (((1 << 4) - 1) << 18)) >> 18)
+
+/* register TMDS_CH0_ERR_CNT */
+#define TMDS_CH0_ERR_CNT 3
+#define F_DEFRAMER_CH0_ERROR_CNT(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_DEFRAMER_CH0_ERROR_CNT_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+
+/* register TMDS_CH1_ERR_CNT */
+#define TMDS_CH1_ERR_CNT 4
+#define F_DEFRAMER_CH1_ERROR_CNT(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_DEFRAMER_CH1_ERROR_CNT_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+
+/* register TMDS_CH2_ERR_CNT */
+#define TMDS_CH2_ERR_CNT 5
+#define F_DEFRAMER_CH2_ERROR_CNT(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_DEFRAMER_CH2_ERROR_CNT_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+
+/* register HDCP_FIFO_STAT */
+#define HDCP_FIFO_STAT 6
+#define F_HDCP_DOUBLE_FIFO_REMPTY(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_HDCP_DOUBLE_FIFO_REMPTY_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_HDCP_DOUBLE_FIFO_WFULL(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_HDCP_DOUBLE_FIFO_WFULL_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_HDCP_DOUBLE_FIFO_UNDERRUN(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_HDCP_DOUBLE_FIFO_UNDERRUN_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_HDCP_DOUBLE_FIFO_OVERRUN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_HDCP_DOUBLE_FIFO_OVERRUN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_HDCP22_DATA_FIFO_UNDERRUN(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_HDCP22_DATA_FIFO_UNDERRUN_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_HDCP22_DATA_FIFO_OVERRUN(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_HDCP22_DATA_FIFO_OVERRUN_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_HDCP22_DATA_FIFO_REMPTY(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_HDCP22_DATA_FIFO_REMPTY_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+#define F_HDCP22_DATA_FIFO_WFULL(x) (((x) & ((1 << 1) - 1)) << 7)
+#define F_HDCP22_DATA_FIFO_WFULL_RD(x) (((x) & (((1 << 1) - 1) << 7)) >> 7)
+#define F_HDCP_DELAY_FIFO_EMPTY(x) (((x) & ((1 << 1) - 1)) << 8)
+#define F_HDCP_DELAY_FIFO_EMPTY_RD(x) (((x) & (((1 << 1) - 1) << 8)) >> 8)
+#define F_HDCP_DELAY_FIFO_FULL(x) (((x) & ((1 << 1) - 1)) << 9)
+#define F_HDCP_DELAY_FIFO_FULL_RD(x) (((x) & (((1 << 1) - 1) << 9)) >> 9)
+#define F_HDCP14_DATA_FIFO_UNDERRUN(x) (((x) & ((1 << 2) - 1)) << 10)
+#define F_HDCP14_DATA_FIFO_UNDERRUN_RD(x) (((x) & (((1 << 2) - 1) << 10)) >> 10)
+#define F_HDCP14_DATA_FIFO_OVERRUN(x) (((x) & ((1 << 2) - 1)) << 12)
+#define F_HDCP14_DATA_FIFO_OVERRUN_RD(x) (((x) & (((1 << 2) - 1) << 12)) >> 12)
+#define F_HDCP14_DATA_FIFO_REMPTY(x) (((x) & ((1 << 2) - 1)) << 14)
+#define F_HDCP14_DATA_FIFO_REMPTY_RD(x) (((x) & (((1 << 2) - 1) << 14)) >> 14)
+#define F_HDCP14_DATA_FIFO_WFULL(x) (((x) & ((1 << 2) - 1)) << 16)
+#define F_HDCP14_DATA_FIFO_WFULL_RD(x) (((x) & (((1 << 2) - 1) << 16)) >> 16)
+
+/* register HDCP_DELAY_FIFO_CTRL */
+#define HDCP_DELAY_FIFO_CTRL 7
+#define F_HDCP_DELAY_FIFO_AFULL_THR(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_HDCP_DELAY_FIFO_AFULL_THR_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_HDCP_DELAY_FIFO_SW_RST(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_HDCP_DELAY_FIFO_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_HDCP_DOUBLE_FIFO_SW_RST(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_HDCP_DOUBLE_FIFO_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_HDCP14_DATA_FIFO_SW_RST(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_HDCP14_DATA_FIFO_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+#define F_HDCP_CTRL_SW_RST(x) (((x) & ((1 << 1) - 1)) << 7)
+#define F_HDCP_CTRL_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 7)) >> 7)
+
+/* register HDCP_CTRL */
+#define HDCP_CTRL 8
+#define F_HDCP_ENABLE_1P1_FEATURES(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_HDCP_ENABLE_1P1_FEATURES_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_HDCP_SELECT(x) (((x) & ((1 << 2) - 1)) << 1)
+#define F_HDCP_SELECT_RD(x) (((x) & (((1 << 2) - 1) << 1)) >> 1)
+#define F_FORCE_VSYNC_POLARITY(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_FORCE_VSYNC_POLARITY_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_FORCE_HSYNC_POLARITY(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_FORCE_HSYNC_POLARITY_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_SW_VSYNC_POLARITY(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_SW_VSYNC_POLARITY_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_SW_HSYNC_POLARITY(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_SW_HSYNC_POLARITY_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+
+/* register HDCP_STAT */
+#define HDCP_STAT 9
+#define F_HDCP_ESS_STATE(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_HDCP_ESS_STATE_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_SINK_HD_CIPHER_HSYNC_POLARITY(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_SINK_HD_CIPHER_HSYNC_POLARITY_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_SINK_HD_CIPHER_VSYNC_POLARITY(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_SINK_HD_CIPHER_VSYNC_POLARITY_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+
+/* register PKT_CTRL */
+#define PKT_CTRL 10
+#define F_SINK_AVMUTE_SET(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_AVMUTE_SET_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_AVMUTE_CLR(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SINK_AVMUTE_CLR_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_ERR_CORR_EN(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_ERR_CORR_EN_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+
+/* register PKT_STAT_0 */
+#define PKT_STAT_0 11
+#define F_SINK_AVMUTE(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SINK_AVMUTE_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SINK_ACR_CTS(x) (((x) & ((1 << 20) - 1)) << 1)
+#define F_SINK_ACR_CTS_RD(x) (((x) & (((1 << 20) - 1) << 1)) >> 1)
+#define F_PKT_DEC_GCP_CD(x) (((x) & ((1 << 4) - 1)) << 21)
+#define F_PKT_DEC_GCP_CD_RD(x) (((x) & (((1 << 4) - 1) << 21)) >> 21)
+#define F_PKT_DEC_GCP_PP(x) (((x) & ((1 << 4) - 1)) << 25)
+#define F_PKT_DEC_GCP_PP_RD(x) (((x) & (((1 << 4) - 1) << 25)) >> 25)
+
+/* register PKT_STAT_1 */
+#define PKT_STAT_1 12
+#define F_SINK_ACR_N(x) (((x) & ((1 << 20) - 1)) << 0)
+#define F_SINK_ACR_N_RD(x) (((x) & (((1 << 20) - 1) << 0)) >> 0)
+
+/* register PKT_ERR_CNT_HEADER */
+#define PKT_ERR_CNT_HEADER 13
+#define F_PKT_HEADER_ERR_CNT(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_PKT_HEADER_ERR_CNT_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_PKT_HEADER_CORR_ERR_CNT(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_PKT_HEADER_CORR_ERR_CNT_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+
+/* register PKT_ERR_CNT_01 */
+#define PKT_ERR_CNT_01 14
+#define F_PKT_SUBPKT0_ERR_CNT(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_PKT_SUBPKT0_ERR_CNT_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_PKT_SUBPKT0_CORR_ERR_CNT(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_PKT_SUBPKT0_CORR_ERR_CNT_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_PKT_SUBPKT1_ERR_CNT(x) (((x) & ((1 << 8) - 1)) << 16)
+#define F_PKT_SUBPKT1_ERR_CNT_RD(x) (((x) & (((1 << 8) - 1) << 16)) >> 16)
+#define F_PKT_SUBPKT1_CORR_ERR_CNT(x) (((x) & ((1 << 8) - 1)) << 24)
+#define F_PKT_SUBPKT1_CORR_ERR_CNT_RD(x) (((x) & (((1 << 8) - 1) << 24)) >> 24)
+
+/* register PKT_ERR_CNT_23 */
+#define PKT_ERR_CNT_23 15
+#define F_PKT_SUBPKT2_ERR_CNT(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_PKT_SUBPKT2_ERR_CNT_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_PKT_SUBPKT2_CORR_ERR_CNT(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_PKT_SUBPKT2_CORR_ERR_CNT_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_PKT_SUBPKT3_ERR_CNT(x) (((x) & ((1 << 8) - 1)) << 16)
+#define F_PKT_SUBPKT3_ERR_CNT_RD(x) (((x) & (((1 << 8) - 1) << 16)) >> 16)
+#define F_PKT_SUBPKT3_CORR_ERR_CNT(x) (((x) & ((1 << 8) - 1)) << 24)
+#define F_PKT_SUBPKT3_CORR_ERR_CNT_RD(x) (((x) & (((1 << 8) - 1) << 24)) >> 24)
+
+/* register TMDS_SCR_CTRL */
+#define TMDS_SCR_CTRL 16
+#define F_SCRAMBLER_MODE(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SCRAMBLER_MODE_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SCRAMBLER_SW_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SCRAMBLER_SW_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_SCRAMBLER_CTRL_SW_RST(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_SCRAMBLER_CTRL_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+
+/* register TMDS_SCR_CNT_INT_CTRL */
+#define TMDS_SCR_CNT_INT_CTRL 17
+#define F_SCRAMBLER_SSCP_LINE_DET_THR(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SCRAMBLER_SSCP_LINE_DET_THR_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_SCRAMBLER_CTRL_LINE_DET_THR(x) (((x) & ((1 << 24) - 1)) << 8)
+#define F_SCRAMBLER_CTRL_LINE_DET_THR_RD(x) (((x) & (((1 << 24) - 1) << 8)) >> 8)
+
+/* register TMDS_SCR_VALID_CTRL */
+#define TMDS_SCR_VALID_CTRL 18
+#define F_SCRAMBLER_SSCP_LINE_VALID_THR(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SCRAMBLER_SSCP_LINE_VALID_THR_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_SCRAMBLER_CTRL_LINE_VALID_THR(x) (((x) & ((1 << 24) - 1)) << 8)
+#define F_SCRAMBLER_CTRL_LINE_VALID_THR_RD(x) (((x) & (((1 << 24) - 1) << 8)) >> 8)
+
+/* register TMDS_SCR_CNT_INT_ST */
+#define TMDS_SCR_CNT_INT_ST 19
+#define F_SCRAMBLER_SSCP_LINE_CNT(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SCRAMBLER_SSCP_LINE_CNT_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_SCRAMBLER_CTRL_LINE_CNT(x) (((x) & ((1 << 24) - 1)) << 8)
+#define F_SCRAMBLER_CTRL_LINE_CNT_RD(x) (((x) & (((1 << 24) - 1) << 8)) >> 8)
+
+/* register TMDS_MHL_HD_INT_MASK */
+#define TMDS_MHL_HD_INT_MASK 20
+#define F_TMDS_MHL_HD_MASK(x) (((x) & ((1 << 9) - 1)) << 0)
+#define F_TMDS_MHL_HD_MASK_RD(x) (((x) & (((1 << 9) - 1) << 0)) >> 0)
+
+/* register TMDS_MHL_HD_INT_STAT */
+#define TMDS_MHL_HD_INT_STAT 21
+#define F_TMDS_MHL_HD_STATUS(x) (((x) & ((1 << 9) - 1)) << 0)
+#define F_TMDS_MHL_HD_STATUS_RD(x) (((x) & (((1 << 9) - 1) << 0)) >> 0)
+
+/* register TMDS_STAT_CNT0_CTRL */
+#define TMDS_STAT_CNT0_CTRL 22
+#define F_STATUS_CNT0_INC_SEL(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_STATUS_CNT0_INC_SEL_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_STATUS_CNT0_DEC_SEL(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_STATUS_CNT0_DEC_SEL_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_STATUS_CNT0_CLR_SEL(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_STATUS_CNT0_CLR_SEL_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_STATUS_CNT0_START_SEL(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_STATUS_CNT0_START_SEL_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_STATUS_CNT0_STOP_SEL(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_STATUS_CNT0_STOP_SEL_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+
+/* register TMDS_STAT_CNT0_THR */
+#define TMDS_STAT_CNT0_THR 23
+#define F_STATUS_CNT0_THR(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_STATUS_CNT0_THR_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register TMDS_STAT_CNT0_VAL */
+#define TMDS_STAT_CNT0_VAL 24
+#define F_STATUS_CNT0_VAL(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_STATUS_CNT0_VAL_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register TMDS_STAT_CNT1_CTRL */
+#define TMDS_STAT_CNT1_CTRL 25
+#define F_STATUS_CNT1_INC_SEL(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_STATUS_CNT1_INC_SEL_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_STATUS_CNT1_DEC_SEL(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_STATUS_CNT1_DEC_SEL_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_STATUS_CNT1_CLR_SEL(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_STATUS_CNT1_CLR_SEL_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_STATUS_CNT1_START_SEL(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_STATUS_CNT1_START_SEL_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_STATUS_CNT1_STOP_SEL(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_STATUS_CNT1_STOP_SEL_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+
+/* register TMDS_STAT_CNT1_THR */
+#define TMDS_STAT_CNT1_THR 26
+#define F_STATUS_CNT1_THR(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_STATUS_CNT1_THR_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register TMDS_STAT_CNT1_VAL */
+#define TMDS_STAT_CNT1_VAL 27
+#define F_STATUS_CNT1_VAL(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_STATUS_CNT1_VAL_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register TMDS_STAT_CNT2_CTRL */
+#define TMDS_STAT_CNT2_CTRL 28
+#define F_STATUS_CNT2_INC_SEL(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_STATUS_CNT2_INC_SEL_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_STATUS_CNT2_DEC_SEL(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_STATUS_CNT2_DEC_SEL_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_STATUS_CNT2_CLR_SEL(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_STATUS_CNT2_CLR_SEL_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_STATUS_CNT2_START_SEL(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_STATUS_CNT2_START_SEL_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_STATUS_CNT2_STOP_SEL(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_STATUS_CNT2_STOP_SEL_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+
+/* register TMDS_STAT_CNT2_THR */
+#define TMDS_STAT_CNT2_THR 29
+#define F_STATUS_CNT2_THR(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_STATUS_CNT2_THR_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register TMDS_STAT_CNT2_VAL */
+#define TMDS_STAT_CNT2_VAL 30
+#define F_STATUS_CNT2_VAL(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_STATUS_CNT2_VAL_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register TMDS_STAT_CNT3_CTRL */
+#define TMDS_STAT_CNT3_CTRL 31
+#define F_STATUS_CNT3_INC_SEL(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_STATUS_CNT3_INC_SEL_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_STATUS_CNT3_DEC_SEL(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_STATUS_CNT3_DEC_SEL_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_STATUS_CNT3_CLR_SEL(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_STATUS_CNT3_CLR_SEL_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_STATUS_CNT3_START_SEL(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_STATUS_CNT3_START_SEL_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_STATUS_CNT3_STOP_SEL(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_STATUS_CNT3_STOP_SEL_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+
+/* register TMDS_STAT_CNT3_THR */
+#define TMDS_STAT_CNT3_THR 32
+#define F_STATUS_CNT3_THR(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_STATUS_CNT3_THR_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register TMDS_STAT_CNT3_VAL */
+#define TMDS_STAT_CNT3_VAL 33
+#define F_STATUS_CNT3_VAL(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_STATUS_CNT3_VAL_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register TMDS_POLARITY_STAT */
+#define TMDS_POLARITY_STAT 34
+#define F_TMDS_HSYNC_POLARITY(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_TMDS_HSYNC_POLARITY_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_TMDS_VSYNC_POLARITY(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_TMDS_VSYNC_POLARITY_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+
+/* register TMDS_MHL_HD_ERR_INT_MASK */
+#define TMDS_MHL_HD_ERR_INT_MASK 35
+#define F_TMDS_MHL_HD_ERR_MASK(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TMDS_MHL_HD_ERR_MASK_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register TMDS_MHL_HD_ERR_INT_STAT */
+#define TMDS_MHL_HD_ERR_INT_STAT 36
+#define F_TMDS_MHL_HD_ERR_STATUS(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_TMDS_MHL_HD_ERR_STATUS_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+/* register MHL_HD_INT_MASK */
+#define MHL_HD_INT_MASK 37
+#define F_MHL_HD_INT_MASK(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_MHL_HD_INT_MASK_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+
+/* register MHL_HD_INT_STAT */
+#define MHL_HD_INT_STAT 38
+#define F_MHL_HD_INT_STATUS(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_MHL_HD_INT_STATUS_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+
+/* register PKT_ACR_CTS_CTRL */
+#define PKT_ACR_CTS_CTRL 39
+#define F_SW_FORCE_ACR_CTS(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SW_FORCE_ACR_CTS_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_PKT_DEC_ACR_CTS(x) (((x) & ((1 << 20) - 1)) << 1)
+#define F_PKT_DEC_ACR_CTS_RD(x) (((x) & (((1 << 20) - 1) << 1)) >> 1)
+
+/* register PKT_ACR_N_CTRL */
+#define PKT_ACR_N_CTRL 40
+#define F_SW_FORCE_ACR_N(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SW_FORCE_ACR_N_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_PKT_DEC_ACR_N(x) (((x) & ((1 << 20) - 1)) << 1)
+#define F_PKT_DEC_ACR_N_RD(x) (((x) & (((1 << 20) - 1) << 1)) >> 1)
+
+/* register PKT_AVI_DATA_LOW */
+#define PKT_AVI_DATA_LOW 41
+#define F_PKT_DEC_AVI_DATA_LOW(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_PKT_DEC_AVI_DATA_LOW_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register PKT_AVI_DATA_HIGH */
+#define PKT_AVI_DATA_HIGH 42
+#define F_PKT_DEC_AVI_DATA_HIGH(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_PKT_DEC_AVI_DATA_HIGH_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+
+#endif /* SINK_MHL_HD */
+
diff --git a/drivers/mxc/hdp/sink_pif.h b/drivers/mxc/hdp/sink_pif.h
new file mode 100644
index 000000000000..bd0944fbb27f
--- /dev/null
+++ b/drivers/mxc/hdp/sink_pif.h
@@ -0,0 +1,160 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * sink_pif.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef SINK_PIF_H_
+#define SINK_PIF_H_
+
+/* register PKT_INFO_TYPE_CFG1 */
+#define PKT_INFO_TYPE_CFG1 0
+#define F_INFO_TYPE1(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_INFO_TYPE1_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_INFO_TYPE2(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_INFO_TYPE2_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_INFO_TYPE3(x) (((x) & ((1 << 8) - 1)) << 16)
+#define F_INFO_TYPE3_RD(x) (((x) & (((1 << 8) - 1) << 16)) >> 16)
+#define F_INFO_TYPE4(x) (((x) & ((1 << 8) - 1)) << 24)
+#define F_INFO_TYPE4_RD(x) (((x) & (((1 << 8) - 1) << 24)) >> 24)
+
+/* register PKT_INFO_TYPE_CFG2 */
+#define PKT_INFO_TYPE_CFG2 1
+#define F_INFO_TYPE5(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_INFO_TYPE5_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_INFO_TYPE6(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_INFO_TYPE6_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_INFO_TYPE7(x) (((x) & ((1 << 8) - 1)) << 16)
+#define F_INFO_TYPE7_RD(x) (((x) & (((1 << 8) - 1) << 16)) >> 16)
+#define F_INFO_TYPE8(x) (((x) & ((1 << 8) - 1)) << 24)
+#define F_INFO_TYPE8_RD(x) (((x) & (((1 << 8) - 1) << 24)) >> 24)
+
+/* register PKT_INFO_TYPE_CFG3 */
+#define PKT_INFO_TYPE_CFG3 2
+#define F_INFO_TYPE9(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_INFO_TYPE9_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_INFO_TYPE10(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_INFO_TYPE10_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_INFO_TYPE11(x) (((x) & ((1 << 8) - 1)) << 16)
+#define F_INFO_TYPE11_RD(x) (((x) & (((1 << 8) - 1) << 16)) >> 16)
+#define F_INFO_TYPE12(x) (((x) & ((1 << 8) - 1)) << 24)
+#define F_INFO_TYPE12_RD(x) (((x) & (((1 << 8) - 1) << 24)) >> 24)
+
+/* register PKT_INFO_TYPE_CFG4 */
+#define PKT_INFO_TYPE_CFG4 3
+#define F_INFO_TYPE13(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_INFO_TYPE13_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_INFO_TYPE14(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_INFO_TYPE14_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_INFO_TYPE15(x) (((x) & ((1 << 8) - 1)) << 16)
+#define F_INFO_TYPE15_RD(x) (((x) & (((1 << 8) - 1) << 16)) >> 16)
+#define F_INFO_TYPE16(x) (((x) & ((1 << 8) - 1)) << 24)
+#define F_INFO_TYPE16_RD(x) (((x) & (((1 << 8) - 1) << 24)) >> 24)
+
+/* register PKT_INFO_CTRL */
+#define PKT_INFO_CTRL 4
+#define F_PACKET_RDN_WR(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_PACKET_RDN_WR_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_PACKET_NUM(x) (((x) & ((1 << 4) - 1)) << 1)
+#define F_PACKET_NUM_RD(x) (((x) & (((1 << 4) - 1) << 1)) >> 1)
+
+/* register PKT_INFO_HEADER */
+#define PKT_INFO_HEADER 7
+#define F_PKT_MEMORY_HEADER(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_PKT_MEMORY_HEADER_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register PKT_INFO_DATA1 */
+#define PKT_INFO_DATA1 8
+#define F_PKT_MEMORY_DATA1(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_PKT_MEMORY_DATA1_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register PKT_INFO_DATA2 */
+#define PKT_INFO_DATA2 9
+#define F_PKT_MEMORY_DATA2(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_PKT_MEMORY_DATA2_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register PKT_INFO_DATA3 */
+#define PKT_INFO_DATA3 10
+#define F_PKT_MEMORY_DATA3(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_PKT_MEMORY_DATA3_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register PKT_INFO_DATA4 */
+#define PKT_INFO_DATA4 11
+#define F_PKT_MEMORY_DATA4(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_PKT_MEMORY_DATA4_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register PKT_INFO_DATA5 */
+#define PKT_INFO_DATA5 12
+#define F_PKT_MEMORY_DATA5(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_PKT_MEMORY_DATA5_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register PKT_INFO_DATA6 */
+#define PKT_INFO_DATA6 13
+#define F_PKT_MEMORY_DATA6(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_PKT_MEMORY_DATA6_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register PKT_INFO_DATA7 */
+#define PKT_INFO_DATA7 14
+#define F_PKT_MEMORY_DATA7(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_PKT_MEMORY_DATA7_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register PKT_INT_STATUS */
+#define PKT_INT_STATUS 15
+#define F_PKT_RDY_STATUS(x) (((x) & ((1 << 17) - 1)) << 0)
+#define F_PKT_RDY_STATUS_RD(x) (((x) & (((1 << 17) - 1) << 0)) >> 0)
+
+/* register PKT_INT_MASK */
+#define PKT_INT_MASK 16
+#define F_PKT_RDY_MASK(x) (((x) & ((1 << 17) - 1)) << 0)
+#define F_PKT_RDY_MASK_RD(x) (((x) & (((1 << 17) - 1) << 0)) >> 0)
+
+/* register PKT_TRANS_CTRL */
+#define PKT_TRANS_CTRL 17
+#define F_PKT_TRANS_MASK_ERR(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_PKT_TRANS_MASK_ERR_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+#endif /* SINK_PIF */
diff --git a/drivers/mxc/hdp/sink_vif.h b/drivers/mxc/hdp/sink_vif.h
new file mode 100644
index 000000000000..cce0080a81e3
--- /dev/null
+++ b/drivers/mxc/hdp/sink_vif.h
@@ -0,0 +1,285 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2018 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * sink_vif.h
+ *
+ ******************************************************************************
+ */
+#ifndef SINK_VIF_H_
+#define SINK_VIF_H_
+
+/* register VIDEO_UNPACK_CFG */
+#define VIDEO_UNPACK_CFG 0
+#define F_SW_CD_PHASE(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SW_CD_PHASE_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_FORCE_SW_CD(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_FORCE_SW_CD_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_SW_CD_COLOR_DEPTH(x) (((x) & ((1 << 4) - 1)) << 5)
+#define F_SW_CD_COLOR_DEPTH_RD(x) (((x) & (((1 << 4) - 1) << 5)) >> 5)
+#define F_FORCE_SW_PHASE(x) (((x) & ((1 << 1) - 1)) << 9)
+#define F_FORCE_SW_PHASE_RD(x) (((x) & (((1 << 1) - 1) << 9)) >> 9)
+#define F_VIDEO_PIXEL_ENCODING(x) (((x) & ((1 << 2) - 1)) << 10)
+#define F_VIDEO_PIXEL_ENCODING_RD(x) (((x) & (((1 << 2) - 1) << 10)) >> 10)
+
+/* register VIDEO_UNPACK_CTRL */
+#define VIDEO_UNPACK_CTRL 1
+#define F_SW_CD_FSM_CLR(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SW_CD_FSM_CLR_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_CD_ENABLE(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_CD_ENABLE_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_CD_FIFO_AEMPTY_TH(x) (((x) & ((1 << 5) - 1)) << 2)
+#define F_CD_FIFO_AEMPTY_TH_RD(x) (((x) & (((1 << 5) - 1) << 2)) >> 2)
+#define F_FSM_ERROR_ENABLE(x) (((x) & ((1 << 1) - 1)) << 7)
+#define F_FSM_ERROR_ENABLE_RD(x) (((x) & (((1 << 1) - 1) << 7)) >> 7)
+
+/* register VIDEO_UNPACK_STAT */
+#define VIDEO_UNPACK_STAT 2
+#define F_CD_FIFO_OVERRUN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_CD_FIFO_OVERRUN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_CD_FIFO_UNDERRUN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_CD_FIFO_UNDERRUN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_CD_PHASE(x) (((x) & ((1 << 4) - 1)) << 2)
+#define F_CD_PHASE_RD(x) (((x) & (((1 << 4) - 1) << 2)) >> 2)
+#define F_CD_COLOR_DEPTH(x) (((x) & ((1 << 4) - 1)) << 6)
+#define F_CD_COLOR_DEPTH_RD(x) (((x) & (((1 << 4) - 1) << 6)) >> 6)
+#define F_CD_LAST_PHASE(x) (((x) & ((1 << 4) - 1)) << 10)
+#define F_CD_LAST_PHASE_RD(x) (((x) & (((1 << 4) - 1) << 10)) >> 10)
+#define F_CD_FIFO_EMPTY(x) (((x) & ((1 << 1) - 1)) << 14)
+#define F_CD_FIFO_EMPTY_RD(x) (((x) & (((1 << 1) - 1) << 14)) >> 14)
+#define F_CD_FIFO_FULL(x) (((x) & ((1 << 1) - 1)) << 15)
+#define F_CD_FIFO_FULL_RD(x) (((x) & (((1 << 1) - 1) << 15)) >> 15)
+#define F_CD_STATE(x) (((x) & ((1 << 5) - 1)) << 16)
+#define F_CD_STATE_RD(x) (((x) & (((1 << 5) - 1) << 16)) >> 16)
+
+/* register VANLYZ_CTRL */
+#define VANLYZ_CTRL 4
+#define F_VANLYZ_START(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_VANLYZ_START_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_VANLYZ_RESET(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_VANLYZ_RESET_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_VANLYZ_FRAMES_CHECK_EN(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_VANLYZ_FRAMES_CHECK_EN_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_VANLYZ_FORMAT_FINDER_EN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_VANLYZ_FORMAT_FINDER_EN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+
+/* register VANLYZ_FRAMES_TO_CHECK */
+#define VANLYZ_FRAMES_TO_CHECK 5
+#define F_VANLYZ_FRAMES_TO_CHECK(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_VANLYZ_FRAMES_TO_CHECK_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register VANLYZ_CFG_0 */
+#define VANLYZ_CFG_0 6
+#define F_VANLYZ_HSYNC_POLARITY(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_VANLYZ_HSYNC_POLARITY_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_VANLYZ_VSYNC_POLARITY(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_VANLYZ_VSYNC_POLARITY_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_VANLYZ_BITWIDTH(x) (((x) & ((1 << 2) - 1)) << 2)
+#define F_VANLYZ_BITWIDTH_RD(x) (((x) & (((1 << 2) - 1) << 2)) >> 2)
+
+/* register VANLYZ_CFG_1 */
+#define VANLYZ_CFG_1 7
+#define F_VANLYZ_FRONT_PORCH(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_VANLYZ_FRONT_PORCH_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_VANLYZ_BACK_PORCH(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_VANLYZ_BACK_PORCH_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register VANLYZ_CFG_2 */
+#define VANLYZ_CFG_2 8
+#define F_VANLYZ_ACTIVE_SLOT(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_VANLYZ_ACTIVE_SLOT_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_VANLYZ_FRAME_LINES(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_VANLYZ_FRAME_LINES_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register VANLYZ_CFG_3 */
+#define VANLYZ_CFG_3 9
+#define F_VANLYZ_LINE_WIDTH(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_VANLYZ_LINE_WIDTH_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+
+/* register VANLYZ_CFG_4 */
+#define VANLYZ_CFG_4 10
+#define F_VANLYZ_NUM_CLK_CYC(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_VANLYZ_NUM_CLK_CYC_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+#define F_VANLYZ_VSYNC_LINES(x) (((x) & ((1 << 8) - 1)) << 24)
+#define F_VANLYZ_VSYNC_LINES_RD(x) (((x) & (((1 << 8) - 1) << 24)) >> 24)
+
+/* register VANLYZ_CFG_5 */
+#define VANLYZ_CFG_5 11
+#define F_VANLYZ_3D_MODE(x) (((x) & ((1 << 3) - 1)) << 0)
+#define F_VANLYZ_3D_MODE_RD(x) (((x) & (((1 << 3) - 1) << 0)) >> 0)
+#define F_VANLYZ_EOF_LINES(x) (((x) & ((1 << 8) - 1)) << 3)
+#define F_VANLYZ_EOF_LINES_RD(x) (((x) & (((1 << 8) - 1) << 3)) >> 3)
+#define F_VANLYZ_SOF_LINES(x) (((x) & ((1 << 8) - 1)) << 11)
+#define F_VANLYZ_SOF_LINES_RD(x) (((x) & (((1 << 8) - 1) << 11)) >> 11)
+
+/* register VANLYZ_CLK_METER_REF_CYC */
+#define VANLYZ_CLK_METER_REF_CYC 12
+#define F_VANLYZ_CLK_METER_REF_CYC(x) (((x) & ((1 << 24) - 1)) << 0)
+#define F_VANLYZ_CLK_METER_REF_CYC_RD(x) (((x) & (((1 << 24) - 1) << 0)) >> 0)
+
+/* register VANLYZ_CLK_METER_MEAS_TOLRNCE */
+#define VANLYZ_CLK_METER_MEAS_TOLRNCE 13
+#define F_VANLYZ_CLK_METER_MEAS_TOLRNCE(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_VANLYZ_CLK_METER_MEAS_TOLRNCE_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+
+/* register VANLYZ_FORMAT_NUM */
+#define VANLYZ_FORMAT_NUM 14
+#define F_VANLYZ_FORMAT1_NUM(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_VANLYZ_FORMAT1_NUM_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VANLYZ_FORMAT2_NUM(x) (((x) & ((1 << 6) - 1)) << 8)
+#define F_VANLYZ_FORMAT2_NUM_RD(x) (((x) & (((1 << 6) - 1) << 8)) >> 8)
+
+/* register VANLYZ_FAILURES */
+#define VANLYZ_FAILURES 15
+#define F_VANLYZ_FAILURES(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_VANLYZ_FAILURES_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+
+/* register VANLYZ_ST_0 */
+#define VANLYZ_ST_0 16
+#define F_VANLYZ_STATUS_HP(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_VANLYZ_STATUS_HP_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_VANLYZ_STATUS_VP(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_VANLYZ_STATUS_VP_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+
+/* register VANLYZ_ST_1 */
+#define VANLYZ_ST_1 17
+#define F_VANLYZ_STATUS_FRAME_LINES(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_VANLYZ_STATUS_FRAME_LINES_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_VANLYZ_STATUS_FP(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_VANLYZ_STATUS_FP_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register VANLYZ_ST_2 */
+#define VANLYZ_ST_2 18
+#define F_VANLYZ_STATUS_BP(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_VANLYZ_STATUS_BP_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_VANLYZ_STATUS_AS(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_VANLYZ_STATUS_AS_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register VANLYZ_STATUS_3 */
+#define VANLYZ_STATUS_3 19
+#define F_VANLYZ_STATUS_LINE_WIDTH(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_VANLYZ_STATUS_LINE_WIDTH_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+
+/* register VANLYZ_STATUS_4 */
+#define VANLYZ_STATUS_4 20
+#define F_VANLYZ_STATUS_VSYNC_LINES(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_VANLYZ_STATUS_VSYNC_LINES_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_VANLYZ_STATUS_EOF_LINES(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_VANLYZ_STATUS_EOF_LINES_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_VANLYZ_STATUS_SOF_LINES(x) (((x) & ((1 << 8) - 1)) << 16)
+#define F_VANLYZ_STATUS_SOF_LINES_RD(x) (((x) & (((1 << 8) - 1) << 16)) >> 16)
+
+/* register VANLYZ_STATUS_5 */
+#define VANLYZ_STATUS_5 21
+#define F_VANLYZ_FORMAT_FINDER_ADD(x) (((x) & ((1 << 6) - 1)) << 0)
+#define F_VANLYZ_FORMAT_FINDER_ADD_RD(x) (((x) & (((1 << 6) - 1) << 0)) >> 0)
+#define F_VANLYZ_FORMAT_FINDER_ACTIVE(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_VANLYZ_FORMAT_FINDER_ACTIVE_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+#define F_VANLYZ_CNT_LINES(x) (((x) & ((1 << 18) - 1)) << 7)
+#define F_VANLYZ_CNT_LINES_RD(x) (((x) & (((1 << 18) - 1) << 7)) >> 7)
+
+/* register VANLYZ_STATUS_6 */
+#define VANLYZ_STATUS_6 22
+#define F_VANLYZ_CNT_VIDEO(x) (((x) & ((1 << 18) - 1)) << 0)
+#define F_VANLYZ_CNT_VIDEO_RD(x) (((x) & (((1 << 18) - 1) << 0)) >> 0)
+
+/* register VANLYZ_STATUS_7 */
+#define VANLYZ_STATUS_7 23
+#define F_VANLYZ_VIDEO_SIZE(x) (((x) & ((1 << 18) - 1)) << 0)
+#define F_VANLYZ_VIDEO_SIZE_RD(x) (((x) & (((1 << 18) - 1) << 0)) >> 0)
+
+/* register VANLYZ_PIC_CFG_0 */
+#define VANLYZ_PIC_CFG_0 24
+#define F_VANLYZ_PIC_R(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_VANLYZ_PIC_R_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_VANLYZ_PIC_G(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_VANLYZ_PIC_G_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register VANLYZ_PIC_CFG_1 */
+#define VANLYZ_PIC_CFG_1 25
+#define F_VANLYZ_PIC_B(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_VANLYZ_PIC_B_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+
+/* register VIF_MHL_HD_ERR_INT_MASK */
+#define VIF_MHL_HD_ERR_INT_MASK 26
+#define F_VIF_MHL_HD_ERR_MASK(x) (((x) & ((1 << 20) - 1)) << 0)
+#define F_VIF_MHL_HD_ERR_MASK_RD(x) (((x) & (((1 << 20) - 1) << 0)) >> 0)
+
+/* register VIF_MHL_HD_ERR_INT_STAT */
+#define VIF_MHL_HD_ERR_INT_STAT 27
+#define F_VIF_MHL_HD_ERR_STATUS(x) (((x) & ((1 << 20) - 1)) << 0)
+#define F_VIF_MHL_HD_ERR_STATUS_RD(x) (((x) & (((1 << 20) - 1) << 0)) >> 0)
+
+/* register VIF_IP_DETECT_CTRL */
+#define VIF_IP_DETECT_CTRL 28
+#define F_READ_DTCT_ERR(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_READ_DTCT_ERR_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_IP_DTCT_WIN(x) (((x) & ((1 << 12) - 1)) << 1)
+#define F_IP_DTCT_WIN_RD(x) (((x) & (((1 << 12) - 1) << 1)) >> 1)
+#define F_IP_DTCT_EN(x) (((x) & ((1 << 1) - 1)) << 13)
+#define F_IP_DTCT_EN_RD(x) (((x) & (((1 << 1) - 1) << 13)) >> 13)
+
+/* register VIF_IP_DETECT_ST1 */
+#define VIF_IP_DETECT_ST1 29
+#define F_IP_DTCT_HSYNC2VSYNC_F1(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_IP_DTCT_HSYNC2VSYNC_F1_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+#define F_IP_DTCT_HSYNC2VSYNC_F2(x) (((x) & ((1 << 16) - 1)) << 16)
+#define F_IP_DTCT_HSYNC2VSYNC_F2_RD(x) (((x) & (((1 << 16) - 1) << 16)) >> 16)
+
+/* register VIF_IP_DETECT_ST2 */
+#define VIF_IP_DETECT_ST2 30
+#define F_IP_STATE(x) (((x) & ((1 << 2) - 1)) << 0)
+#define F_IP_STATE_RD(x) (((x) & (((1 << 2) - 1) << 0)) >> 0)
+#define F_IP_DTCT_ERR(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_IP_DTCT_ERR_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_IP_DTCT_HJITTER(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_IP_DTCT_HJITTER_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_IP_DTCT_VJITTER(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_IP_DTCT_VJITTER_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_IP_DTCT_IP(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_IP_DTCT_IP_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_IP_DTCT_FIELD(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_IP_DTCT_FIELD_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+
+#endif /* SINK_VIF */
diff --git a/drivers/mxc/hdp/source_aif_decoder.h b/drivers/mxc/hdp/source_aif_decoder.h
new file mode 100644
index 000000000000..6b69e44865f1
--- /dev/null
+++ b/drivers/mxc/hdp/source_aif_decoder.h
@@ -0,0 +1,452 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * source_aif_decoder.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef SOURCE_AIF_DECODER_H_
+#define SOURCE_AIF_DECODER_H_
+
+/* register AUDIO_SRC_CNTL */
+#define AUDIO_SRC_CNTL 0
+#define F_SW_RST(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_I2S_DEC_START(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_I2S_DEC_START_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_I2S_BLOCK_START_FORCE(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_I2S_BLOCK_START_FORCE_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_SPDIF_TS_EN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_SPDIF_TS_EN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_I2S_TS_EN(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_I2S_TS_EN_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_VALID_BITS_FORCE(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_VALID_BITS_FORCE_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_VALID_ALL(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_VALID_ALL_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+
+/* register AUDIO_SRC_CNFG */
+#define AUDIO_SRC_CNFG 1
+#define F_LOW_INDEX_MSB(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_LOW_INDEX_MSB_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_WS_POLARITY(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_WS_POLARITY_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_AUDIO_CH_NUM(x) (((x) & ((1 << 5) - 1)) << 2)
+#define F_AUDIO_CH_NUM_RD(x) (((x) & (((1 << 5) - 1) << 2)) >> 2)
+#define F_AUDIO_SAMPLE_JUST(x) (((x) & ((1 << 2) - 1)) << 7)
+#define F_AUDIO_SAMPLE_JUST_RD(x) (((x) & (((1 << 2) - 1) << 7)) >> 7)
+#define F_AUDIO_SAMPLE_WIDTH(x) (((x) & ((1 << 2) - 1)) << 9)
+#define F_AUDIO_SAMPLE_WIDTH_RD(x) (((x) & (((1 << 2) - 1) << 9)) >> 9)
+#define F_TRANS_SMPL_WIDTH(x) (((x) & ((1 << 2) - 1)) << 11)
+#define F_TRANS_SMPL_WIDTH_RD(x) (((x) & (((1 << 2) - 1) << 11)) >> 11)
+#define F_AUDIO_CHANNEL_TYPE(x) (((x) & ((1 << 4) - 1)) << 13)
+#define F_AUDIO_CHANNEL_TYPE_RD(x) (((x) & (((1 << 4) - 1) << 13)) >> 13)
+#define F_I2S_DEC_PORT_EN(x) (((x) & ((1 << 4) - 1)) << 17)
+#define F_I2S_DEC_PORT_EN_RD(x) (((x) & (((1 << 4) - 1) << 17)) >> 17)
+
+/* register COM_CH_STTS_BITS */
+#define COM_CH_STTS_BITS 2
+#define F_BYTE0(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_BYTE0_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_CATEGORY_CODE(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_CATEGORY_CODE_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_SAMPLING_FREQ(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_SAMPLING_FREQ_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_CLOCK_ACCURACY(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_CLOCK_ACCURACY_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_ORIGINAL_SAMP_FREQ(x) (((x) & ((1 << 4) - 1)) << 24)
+#define F_ORIGINAL_SAMP_FREQ_RD(x) (((x) & (((1 << 4) - 1) << 24)) >> 24)
+
+/* register STTS_BIT_CH01 */
+#define STTS_BIT_CH01 3
+#define F_SOURCE_NUM_CH0(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH0_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH0(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH0_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH0(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH0_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH1(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH1_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH1(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH1_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH1(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH1_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_VALID_BITS1_0(x) (((x) & ((1 << 2) - 1)) << 24)
+#define F_VALID_BITS1_0_RD(x) (((x) & (((1 << 2) - 1) << 24)) >> 24)
+
+/* register STTS_BIT_CH23 */
+#define STTS_BIT_CH23 4
+#define F_SOURCE_NUM_CH2(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH2_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH2(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH2_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH2(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH2_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH3(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH3_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH3(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH3_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH3(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH3_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_VALID_BITS3_2(x) (((x) & ((1 << 2) - 1)) << 24)
+#define F_VALID_BITS3_2_RD(x) (((x) & (((1 << 2) - 1) << 24)) >> 24)
+
+/* register STTS_BIT_CH45 */
+#define STTS_BIT_CH45 5
+#define F_SOURCE_NUM_CH4(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH4_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH4(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH4_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH4(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH4_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH5(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH5_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH5(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH5_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH5(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH5_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_VALID_BITS5_4(x) (((x) & ((1 << 2) - 1)) << 24)
+#define F_VALID_BITS5_4_RD(x) (((x) & (((1 << 2) - 1) << 24)) >> 24)
+
+/* register STTS_BIT_CH67 */
+#define STTS_BIT_CH67 6
+#define F_SOURCE_NUM_CH6(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH6_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH6(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH6_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH6(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH6_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH7(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH7_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH7(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH7_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH7(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH7_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_VALID_BITS7_6(x) (((x) & ((1 << 2) - 1)) << 24)
+#define F_VALID_BITS7_6_RD(x) (((x) & (((1 << 2) - 1) << 24)) >> 24)
+
+/* register STTS_BIT_CH89 */
+#define STTS_BIT_CH89 7
+#define F_SOURCE_NUM_CH8(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH8_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH8(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH8_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH8(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH8_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH9(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH9_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH9(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH9_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH9(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH9_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_VALID_BITS9_8(x) (((x) & ((1 << 2) - 1)) << 24)
+#define F_VALID_BITS9_8_RD(x) (((x) & (((1 << 2) - 1) << 24)) >> 24)
+
+/* register STTS_BIT_CH1011 */
+#define STTS_BIT_CH1011 8
+#define F_SOURCE_NUM_CH10(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH10_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH10(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH10_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH10(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH10_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH11(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH11_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH11(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH11_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH11(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH11_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_VALID_BITS11_10(x) (((x) & ((1 << 2) - 1)) << 24)
+#define F_VALID_BITS11_10_RD(x) (((x) & (((1 << 2) - 1) << 24)) >> 24)
+
+/* register STTS_BIT_CH1213 */
+#define STTS_BIT_CH1213 9
+#define F_SOURCE_NUM_CH12(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH12_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH12(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH12_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH12(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH12_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH13(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH13_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH13(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH13_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH13(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH13_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_VALID_BITS13_12(x) (((x) & ((1 << 2) - 1)) << 24)
+#define F_VALID_BITS13_12_RD(x) (((x) & (((1 << 2) - 1) << 24)) >> 24)
+
+/* register STTS_BIT_CH1415 */
+#define STTS_BIT_CH1415 10
+#define F_SOURCE_NUM_CH14(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH14_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH14(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH14_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH14(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH14_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH15(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH15_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH15(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH15_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH15(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH15_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_VALID_BITS15_14(x) (((x) & ((1 << 2) - 1)) << 24)
+#define F_VALID_BITS15_14_RD(x) (((x) & (((1 << 2) - 1) << 24)) >> 24)
+
+/* register STTS_BIT_CH1617 */
+#define STTS_BIT_CH1617 11
+#define F_SOURCE_NUM_CH16(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH16_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH16(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH16_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH16(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH16_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH17(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH17_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH17(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH17_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH17(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH17_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_VALID_BITS17_16(x) (((x) & ((1 << 2) - 1)) << 24)
+#define F_VALID_BITS17_16_RD(x) (((x) & (((1 << 2) - 1) << 24)) >> 24)
+
+/* register STTS_BIT_CH1819 */
+#define STTS_BIT_CH1819 12
+#define F_SOURCE_NUM_CH18(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH18_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH18(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH18_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH18(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH18_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH19(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH19_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH19(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH19_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH19(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH19_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_VALID_BITS19_18(x) (((x) & ((1 << 2) - 1)) << 24)
+#define F_VALID_BITS19_18_RD(x) (((x) & (((1 << 2) - 1) << 24)) >> 24)
+
+/* register STTS_BIT_CH2021 */
+#define STTS_BIT_CH2021 13
+#define F_SOURCE_NUM_CH20(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH20_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH20(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH20_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH20(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH20_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH21(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH21_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH21(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH21_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH21(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH21_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_VALID_BITS21_20(x) (((x) & ((1 << 2) - 1)) << 24)
+#define F_VALID_BITS21_20_RD(x) (((x) & (((1 << 2) - 1) << 24)) >> 24)
+
+/* register STTS_BIT_CH2223 */
+#define STTS_BIT_CH2223 14
+#define F_SOURCE_NUM_CH22(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH22_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH22(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH22_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH22(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH22_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH23(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH23_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH23(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH23_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH23(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH23_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_VALID_BITS23_22(x) (((x) & ((1 << 2) - 1)) << 24)
+#define F_VALID_BITS23_22_RD(x) (((x) & (((1 << 2) - 1) << 24)) >> 24)
+
+/* register STTS_BIT_CH2425 */
+#define STTS_BIT_CH2425 15
+#define F_SOURCE_NUM_CH24(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH24_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH24(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH24_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH24(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH24_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH25(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH25_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH25(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH25_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH25(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH25_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_VALID_BITS25_24(x) (((x) & ((1 << 2) - 1)) << 24)
+#define F_VALID_BITS25_24_RD(x) (((x) & (((1 << 2) - 1) << 24)) >> 24)
+
+/* register STTS_BIT_CH2627 */
+#define STTS_BIT_CH2627 16
+#define F_SOURCE_NUM_CH26(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH26_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH26(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH26_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH26(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH26_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH27(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH27_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH27(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH27_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH27(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH27_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_VALID_BITS27_26(x) (((x) & ((1 << 2) - 1)) << 24)
+#define F_VALID_BITS27_26_RD(x) (((x) & (((1 << 2) - 1) << 24)) >> 24)
+
+/* register STTS_BIT_CH2829 */
+#define STTS_BIT_CH2829 17
+#define F_SOURCE_NUM_CH28(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH28_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH28(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH28_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH28(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH28_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH29(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH29_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH29(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH29_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH29(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH29_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_VALID_BITS29_28(x) (((x) & ((1 << 2) - 1)) << 24)
+#define F_VALID_BITS29_28_RD(x) (((x) & (((1 << 2) - 1) << 24)) >> 24)
+
+/* register STTS_BIT_CH3031 */
+#define STTS_BIT_CH3031 18
+#define F_SOURCE_NUM_CH30(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_NUM_CH30_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_CHANNEL_NUM_CH30(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_CHANNEL_NUM_CH30_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_WORD_LENGTH_CH30(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_WORD_LENGTH_CH30_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_NUM_CH31(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_NUM_CH31_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_CHANNEL_NUM_CH31(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CHANNEL_NUM_CH31_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_WORD_LENGTH_CH31(x) (((x) & ((1 << 4) - 1)) << 20)
+#define F_WORD_LENGTH_CH31_RD(x) (((x) & (((1 << 4) - 1) << 20)) >> 20)
+#define F_VALID_BITS31_30(x) (((x) & ((1 << 2) - 1)) << 24)
+#define F_VALID_BITS31_30_RD(x) (((x) & (((1 << 2) - 1) << 24)) >> 24)
+
+/* register SPDIF_CTRL_ADDR */
+#define SPDIF_CTRL_ADDR 19
+#define F_SPDIF_JITTER_AVG_WIN(x) (((x) & ((1 << 3) - 1)) << 0)
+#define F_SPDIF_JITTER_AVG_WIN_RD(x) (((x) & (((1 << 3) - 1) << 0)) >> 0)
+#define F_SPDIF_JITTER_THRSH(x) (((x) & ((1 << 8) - 1)) << 3)
+#define F_SPDIF_JITTER_THRSH_RD(x) (((x) & (((1 << 8) - 1) << 3)) >> 3)
+#define F_SPDIF_FIFO_MID_RANGE(x) (((x) & ((1 << 8) - 1)) << 11)
+#define F_SPDIF_FIFO_MID_RANGE_RD(x) (((x) & (((1 << 8) - 1) << 11)) >> 11)
+#define F_SPDIF_JITTER_BYPASS(x) (((x) & ((1 << 1) - 1)) << 19)
+#define F_SPDIF_JITTER_BYPASS_RD(x) (((x) & (((1 << 1) - 1) << 19)) >> 19)
+#define F_SPDIF_AVG_SEL(x) (((x) & ((1 << 1) - 1)) << 20)
+#define F_SPDIF_AVG_SEL_RD(x) (((x) & (((1 << 1) - 1) << 20)) >> 20)
+#define F_SPDIF_ENABLE(x) (((x) & ((1 << 1) - 1)) << 21)
+#define F_SPDIF_ENABLE_RD(x) (((x) & (((1 << 1) - 1) << 21)) >> 21)
+#define F_SPDIF_JITTER_STATUS(x) (((x) & ((1 << 4) - 1)) << 22)
+#define F_SPDIF_JITTER_STATUS_RD(x) (((x) & (((1 << 4) - 1) << 22)) >> 22)
+
+/* register SPDIF_CH1_CS_3100_ADDR */
+#define SPDIF_CH1_CS_3100_ADDR 20
+#define F_SPDIF_CH1_ST_STTS_BITS3100(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_SPDIF_CH1_ST_STTS_BITS3100_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register SPDIF_CH1_CS_6332_ADDR */
+#define SPDIF_CH1_CS_6332_ADDR 21
+#define F_SPDIF_CH1_ST_STTS_BITS6332(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_SPDIF_CH1_ST_STTS_BITS6332_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register SPDIF_CH1_CS_9564_ADDR */
+#define SPDIF_CH1_CS_9564_ADDR 22
+#define F_SPDIF_CH1_ST_STTS_BITS9564(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_SPDIF_CH1_ST_STTS_BITS9564_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register SPDIF_CH1_CS_12796_ADDR */
+#define SPDIF_CH1_CS_12796_ADDR 23
+#define F_SPDIF_CH1_ST_STTS_BITS12796(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_SPDIF_CH1_ST_STTS_BITS12796_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register SPDIF_CH1_CS_159128_ADDR */
+#define SPDIF_CH1_CS_159128_ADDR 24
+#define F_SPDIF_CH1_ST_STTS_BITS159128(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_SPDIF_CH1_ST_STTS_BITS159128_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register SPDIF_CH1_CS_191160_ADDR */
+#define SPDIF_CH1_CS_191160_ADDR 25
+#define F_SPDIF_CH1_ST_STTS_BITS191160(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_SPDIF_CH1_ST_STTS_BITS191160_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register SPDIF_CH2_CS_3100_ADDR */
+#define SPDIF_CH2_CS_3100_ADDR 26
+#define F_SPDIF_CH2_ST_STTS_BITS3100(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_SPDIF_CH2_ST_STTS_BITS3100_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register SPDIF_CH2_CS_6332_ADDR */
+#define SPDIF_CH2_CS_6332_ADDR 27
+#define F_SPDIF_CH2_ST_STTS_BITS6332(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_SPDIF_CH2_ST_STTS_BITS6332_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register SPDIF_CH2_CS_9564_ADDR */
+#define SPDIF_CH2_CS_9564_ADDR 28
+#define F_SPDIF_CH2_ST_STTS_BITS9564(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_SPDIF_CH2_ST_STTS_BITS9564_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register SPDIF_CH2_CS_12796_ADDR */
+#define SPDIF_CH2_CS_12796_ADDR 29
+#define F_SPDIF_CH2_ST_STTS_BITS12796(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_SPDIF_CH2_ST_STTS_BITS12796_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register SPDIF_CH2_CS_159128_ADDR */
+#define SPDIF_CH2_CS_159128_ADDR 30
+#define F_SPDIF_CH2_ST_STTS_BITS159128(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_SPDIF_CH2_ST_STTS_BITS159128_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+/* register SPDIF_CH2_CS_191160_ADDR */
+#define SPDIF_CH2_CS_191160_ADDR 31
+#define F_SPDIF_CH2_ST_STTS_BITS191160(x) (((x) & ((1 << 32) - 1)) << 0)
+#define F_SPDIF_CH2_ST_STTS_BITS191160_RD(x) (((x) & (((1 << 32) - 1) << 0)) >> 0)
+
+#endif //SOURCE_AIF_DECODER
diff --git a/drivers/mxc/hdp/source_aif_smpl2pckt.h b/drivers/mxc/hdp/source_aif_smpl2pckt.h
new file mode 100644
index 000000000000..8721cf432528
--- /dev/null
+++ b/drivers/mxc/hdp/source_aif_smpl2pckt.h
@@ -0,0 +1,113 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * source_aif_smpl2pckt.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef SOURCE_AIF_SMPL2PCKT_H_
+#define SOURCE_AIF_SMPL2PCKT_H_
+
+/* register SMPL2PKT_CNTL */
+#define SMPL2PKT_CNTL 0
+#define F_SW_RST(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SMPL2PKT_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SMPL2PKT_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+
+/* register SMPL2PKT_CNFG */
+#define SMPL2PKT_CNFG 1
+#define F_MAX_NUM_CH(x) (((x) & ((1 << 5) - 1)) << 0)
+#define F_MAX_NUM_CH_RD(x) (((x) & (((1 << 5) - 1) << 0)) >> 0)
+#define F_NUM_OF_I2S_PORTS_S(x) (((x) & ((1 << 2) - 1)) << 5)
+#define F_NUM_OF_I2S_PORTS_RD_S(x) (((x) & (((1 << 2) - 1) << 5)) >> 5)
+#define F_AUDIO_TYPE(x) (((x) & ((1 << 4) - 1)) << 7)
+#define F_AUDIO_TYPE_RD(x) (((x) & (((1 << 4) - 1) << 7)) >> 7)
+#define F_CFG_SUB_PCKT_NUM(x) (((x) & ((1 << 3) - 1)) << 11)
+#define F_CFG_SUB_PCKT_NUM_RD(x) (((x) & (((1 << 3) - 1) << 11)) >> 11)
+#define F_CFG_BLOCK_LPCM_FIRST_PKT(x) (((x) & ((1 << 1) - 1)) << 14)
+#define F_CFG_BLOCK_LPCM_FIRST_PKT_RD(x) (((x) & (((1 << 1) - 1) << 14)) >> 14)
+#define F_CFG_EN_AUTO_SUB_PCKT_NUM(x) (((x) & ((1 << 1) - 1)) << 15)
+#define F_CFG_EN_AUTO_SUB_PCKT_NUM_RD(x) (((x) & (((1 << 1) - 1) << 15)) >> 15)
+#define F_CFG_SAMPLE_PRESENT(x) (((x) & ((1 << 4) - 1)) << 16)
+#define F_CFG_SAMPLE_PRESENT_RD(x) (((x) & (((1 << 4) - 1) << 16)) >> 16)
+#define F_CFG_SAMPLE_PRESENT_FORCE(x) (((x) & ((1 << 1) - 1)) << 20)
+#define F_CFG_SAMPLE_PRESENT_FORCE_RD(x) (((x) & (((1 << 1) - 1) << 20)) >> 20)
+
+/* register FIFO_CNTL */
+#define FIFO_CNTL 2
+#define F_FIFO_SW_RST(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_FIFO_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SYNC_WR_TO_CH_ZERO(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SYNC_WR_TO_CH_ZERO_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_FIFO_DIR(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_FIFO_DIR_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_FIFO_EMPTY_CALC(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_FIFO_EMPTY_CALC_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_CFG_DIS_PORT3(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_CFG_DIS_PORT3_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+
+/* register FIFO_STTS */
+#define FIFO_STTS 3
+#define F_WFULL(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_WFULL_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_REMPTY(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_REMPTY_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_OVERRUN(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_OVERRUN_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_UNDERRUN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_UNDERRUN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+
+/* register SUB_PCKT_THRSH */
+#define SUB_PCKT_THRSH 4
+#define F_CFG_MEM_FIFO_THRSH1(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_CFG_MEM_FIFO_THRSH1_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_CFG_MEM_FIFO_THRSH2(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_CFG_MEM_FIFO_THRSH2_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_CFG_MEM_FIFO_THRSH3(x) (((x) & ((1 << 8) - 1)) << 16)
+#define F_CFG_MEM_FIFO_THRSH3_RD(x) (((x) & (((1 << 8) - 1) << 16)) >> 16)
+
+#endif //SOURCE_AIF_SMPL2PCKT
diff --git a/drivers/mxc/hdp/source_car.h b/drivers/mxc/hdp/source_car.h
new file mode 100644
index 000000000000..a53f99a08c5f
--- /dev/null
+++ b/drivers/mxc/hdp/source_car.h
@@ -0,0 +1,173 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * source_car.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef SOURCE_CAR_H_
+#define SOURCE_CAR_H_
+
+/* register SOURCE_HDTX_CAR */
+#define SOURCE_HDTX_CAR 0
+#define F_SOURCE_HDTX_PIXEL_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SOURCE_HDTX_PIXEL_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SOURCE_HDTX_PIXEL_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SOURCE_HDTX_PIXEL_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_SOURCE_HDTX_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_SOURCE_HDTX_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_SOURCE_HDTX_SYS_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_SOURCE_HDTX_SYS_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_SOURCE_HDTX_PHY_DATA_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_SOURCE_HDTX_PHY_DATA_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_SOURCE_HDTX_PHY_DATA_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_SOURCE_HDTX_PHY_DATA_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_SOURCE_HDTX_PHY_CHAR_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_SOURCE_HDTX_PHY_CHAR_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+#define F_SOURCE_HDTX_PHY_CHAR_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 7)
+#define F_SOURCE_HDTX_PHY_CHAR_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 7)) >> 7)
+
+/* register SOURCE_DPTX_CAR */
+#define SOURCE_DPTX_CAR 1
+#define F_SOURCE_CFG_DPTX_VIF_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SOURCE_CFG_DPTX_VIF_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SOURCE_CFG_DPTX_VIF_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SOURCE_CFG_DPTX_VIF_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_SOURCE_DPTX_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_SOURCE_DPTX_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_SOURCE_DPTX_SYS_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_SOURCE_DPTX_SYS_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_SOURCE_AUX_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_SOURCE_AUX_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_SOURCE_AUX_SYS_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_SOURCE_AUX_SYS_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_SOUrcE_DPTX_PHY_CHAR_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_SOUrcE_DPTX_PHY_CHAR_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+#define F_SOUrcE_DPTX_PHY_CHAR_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 7)
+#define F_SOUrcE_DPTX_PHY_CHAR_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 7)) >> 7)
+#define F_SOUrcE_DPTX_PHY_DATA_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 8)
+#define F_SOUrcE_DPTX_PHY_DATA_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 8)) >> 8)
+#define F_SOUrcE_DPTX_PHY_DATA_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 9)
+#define F_SOUrcE_DPTX_PHY_DATA_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 9)) >> 9)
+#define F_SOUrcE_DPTX_FRMR_DATA_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 10)
+#define F_SOUrcE_DPTX_FRMR_DATA_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 10)) >> 10)
+#define F_SOUrcE_DPTX_FRMR_DATA_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 11)
+#define F_SOUrcE_DPTX_FRMR_DATA_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 11)) >> 11)
+
+/* register SOURCE_PHY_CAR */
+#define SOURCE_PHY_CAR 2
+#define F_SOURCE_PHY_DATA_OUT_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SOURCE_PHY_DATA_OUT_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SOURCE_PHY_DATA_OUT_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SOURCE_PHY_DATA_OUT_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_SOURCE_PHY_CHAR_OUT_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_SOURCE_PHY_CHAR_OUT_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_SOURCE_PHY_CHAR_OUT_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_SOURCE_PHY_CHAR_OUT_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+
+/* register SOURCE_CEC_CAR */
+#define SOURCE_CEC_CAR 3
+#define F_SOURCE_CEC_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SOURCE_CEC_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SOURCE_CEC_SYS_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SOURCE_CEC_SYS_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+
+/* register SOURCE_CBUS_CAR */
+#define SOURCE_CBUS_CAR 4
+#define F_SOURCE_CBUS_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SOURCE_CBUS_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SOURCE_CBUS_SYS_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SOURCE_CBUS_SYS_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+
+/* register SOURCE_PKT_CAR */
+#define SOURCE_PKT_CAR 6
+#define F_SOURCE_PKT_DATA_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SOURCE_PKT_DATA_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SOURCE_PKT_DATA_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SOURCE_PKT_DATA_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_SOURCE_PKT_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_SOURCE_PKT_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_SOURCE_PKT_SYS_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_SOURCE_PKT_SYS_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+
+/* register SOURCE_AIF_CAR */
+#define SOURCE_AIF_CAR 7
+#define F_SOURCE_AIF_PKT_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SOURCE_AIF_PKT_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SOURCE_AIF_PKT_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SOURCE_AIF_PKT_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_SOURCE_AIF_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_SOURCE_AIF_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_SOURCE_AIF_SYS_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_SOURCE_AIF_SYS_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_SOURCE_SPDIF_CDR_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_SOURCE_SPDIF_CDR_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_SOURCE_SPDIF_CDR_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_SOURCE_SPDIF_CDR_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_SOURCE_SPDIF_MCLK_EN(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_SOURCE_SPDIF_MCLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+#define F_SOURCE_SPDIF_MCLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 7)
+#define F_SOURCE_SPDIF_MCLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 7)) >> 7)
+
+/* register SOURCE_CIPHER_CAR */
+#define SOURCE_CIPHER_CAR 8
+#define F_SOURCE_CIPHER_CHAR_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SOURCE_CIPHER_CHAR_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SOURCE_CIPHER_CHAR_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SOURCE_CIPHER_CHAR_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_SOURCE_CIPHER_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_SOURCE_CIPHER_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+
+/* register SOURCE_CRYPTO_CAR */
+#define SOURCE_CRYPTO_CAR 9
+#define F_SOURCE_CRYPTO_SYS_CLK_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SOURCE_CRYPTO_SYS_CLK_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_SOURCE_CRYPTO_SYS_CLK_RSTN_EN(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_SOURCE_CRYPTO_SYS_CLK_RSTN_EN_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+
+#endif /* SOURCE_CAR */
diff --git a/drivers/mxc/hdp/source_phy.h b/drivers/mxc/hdp/source_phy.h
new file mode 100644
index 000000000000..40fd427db71f
--- /dev/null
+++ b/drivers/mxc/hdp/source_phy.h
@@ -0,0 +1,180 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * source_phy.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef SOURCE_PHY_H_
+#define SOURCE_PHY_H_
+
+/* register SHIFT_PATTERN_IN_3_0 */
+#define SHIFT_PATTERN_IN_3_0 0
+#define F_SOURCE_PHY_SHIFT_PATTERN0(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SOURCE_PHY_SHIFT_PATTERN0_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_SOURCE_PHY_SHIFT_PATTERN1(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_SOURCE_PHY_SHIFT_PATTERN1_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_SOURCE_PHY_SHIFT_PATTERN2(x) (((x) & ((1 << 8) - 1)) << 16)
+#define F_SOURCE_PHY_SHIFT_PATTERN2_RD(x) (((x) & (((1 << 8) - 1) << 16)) >> 16)
+#define F_SOURCE_PHY_SHIFT_PATTERN3(x) (((x) & ((1 << 8) - 1)) << 24)
+#define F_SOURCE_PHY_SHIFT_PATTERN3_RD(x) (((x) & (((1 << 8) - 1) << 24)) >> 24)
+
+/* register SHIFT_PATTERN_IN_4_7 */
+#define SHIFT_PATTERN_IN_4_7 1
+#define F_SOURCE_PHY_SHIFT_PATTERN4(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SOURCE_PHY_SHIFT_PATTERN4_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_SOURCE_PHY_SHIFT_PATTERN5(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_SOURCE_PHY_SHIFT_PATTERN5_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_SOURCE_PHY_SHIFT_PATTERN6(x) (((x) & ((1 << 8) - 1)) << 16)
+#define F_SOURCE_PHY_SHIFT_PATTERN6_RD(x) (((x) & (((1 << 8) - 1) << 16)) >> 16)
+#define F_SOURCE_PHY_SHIFT_PATTERN7(x) (((x) & ((1 << 8) - 1)) << 24)
+#define F_SOURCE_PHY_SHIFT_PATTERN7_RD(x) (((x) & (((1 << 8) - 1) << 24)) >> 24)
+
+/* register SHIFT_PATTERN_IN9_8 */
+#define SHIFT_PATTERN_IN9_8 2
+#define F_SOURCE_PHY_SHIFT_PATTERN8(x) (((x) & ((1 << 8) - 1)) << 0)
+#define F_SOURCE_PHY_SHIFT_PATTERN8_RD(x) (((x) & (((1 << 8) - 1) << 0)) >> 0)
+#define F_SOURCE_PHY_SHIFT_PATTERN9(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_SOURCE_PHY_SHIFT_PATTERN9_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_SOURCE_PHY_SHIFT_LOAD(x) (((x) & ((1 << 1) - 1)) << 16)
+#define F_SOURCE_PHY_SHIFT_LOAD_RD(x) (((x) & (((1 << 1) - 1) << 16)) >> 16)
+#define F_SOURCE_PHY_SHIFT_EN(x) (((x) & ((1 << 1) - 1)) << 17)
+#define F_SOURCE_PHY_SHIFT_EN_RD(x) (((x) & (((1 << 1) - 1) << 17)) >> 17)
+#define F_SOURCE_PHY_SHIFT_REPETITION(x) (((x) & ((1 << 3) - 1)) << 18)
+#define F_SOURCE_PHY_SHIFT_REPETITION_RD(x) (((x) & (((1 << 3) - 1) << 18)) >> 18)
+
+/* register PRBS_CNTRL */
+#define PRBS_CNTRL 3
+#define F_SOURCE_PHY_PRBS0_MODE(x) (((x) & ((1 << 2) - 1)) << 0)
+#define F_SOURCE_PHY_PRBS0_MODE_RD(x) (((x) & (((1 << 2) - 1) << 0)) >> 0)
+#define F_SOURCE_PHY_PRBS0_OUT_MODE(x) (((x) & ((1 << 2) - 1)) << 2)
+#define F_SOURCE_PHY_PRBS0_OUT_MODE_RD(x) (((x) & (((1 << 2) - 1) << 2)) >> 2)
+#define F_SOURCE_PHY_PRBS1_MODE(x) (((x) & ((1 << 2) - 1)) << 4)
+#define F_SOURCE_PHY_PRBS1_MODE_RD(x) (((x) & (((1 << 2) - 1) << 4)) >> 4)
+#define F_SOURCE_PHY_PRBS1_OUT_MODE(x) (((x) & ((1 << 2) - 1)) << 6)
+#define F_SOURCE_PHY_PRBS1_OUT_MODE_RD(x) (((x) & (((1 << 2) - 1) << 6)) >> 6)
+#define F_SOURCE_PHY_PRBS2_MODE(x) (((x) & ((1 << 2) - 1)) << 8)
+#define F_SOURCE_PHY_PRBS2_MODE_RD(x) (((x) & (((1 << 2) - 1) << 8)) >> 8)
+#define F_SOURCE_PHY_PRBS2_OUT_MODE(x) (((x) & ((1 << 2) - 1)) << 10)
+#define F_SOURCE_PHY_PRBS2_OUT_MODE_RD(x) (((x) & (((1 << 2) - 1) << 10)) >> 10)
+#define F_SOURCE_PHY_PRBS3_MODE(x) (((x) & ((1 << 2) - 1)) << 12)
+#define F_SOURCE_PHY_PRBS3_MODE_RD(x) (((x) & (((1 << 2) - 1) << 12)) >> 12)
+#define F_SOURCE_PHY_PRBS3_OUT_MODE(x) (((x) & ((1 << 2) - 1)) << 14)
+#define F_SOURCE_PHY_PRBS3_OUT_MODE_RD(x) (((x) & (((1 << 2) - 1) << 14)) >> 14)
+
+/* register PRBS_ERR_INSERTION */
+#define PRBS_ERR_INSERTION 4
+#define F_ADD_ERROR0(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_ADD_ERROR0_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_NUMBER_OF_ERRORS0(x) (((x) & ((1 << 5) - 1)) << 1)
+#define F_NUMBER_OF_ERRORS0_RD(x) (((x) & (((1 << 5) - 1) << 1)) >> 1)
+#define F_ADD_ERROR1(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_ADD_ERROR1_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+#define F_NUMBER_OF_ERRORS1(x) (((x) & ((1 << 5) - 1)) << 7)
+#define F_NUMBER_OF_ERRORS1_RD(x) (((x) & (((1 << 5) - 1) << 7)) >> 7)
+#define F_ADD_ERROR2(x) (((x) & ((1 << 1) - 1)) << 12)
+#define F_ADD_ERROR2_RD(x) (((x) & (((1 << 1) - 1) << 12)) >> 12)
+#define F_NUMBER_OF_ERRORS2(x) (((x) & ((1 << 5) - 1)) << 13)
+#define F_NUMBER_OF_ERRORS2_RD(x) (((x) & (((1 << 5) - 1) << 13)) >> 13)
+#define F_ADD_ERROR3(x) (((x) & ((1 << 1) - 1)) << 18)
+#define F_ADD_ERROR3_RD(x) (((x) & (((1 << 1) - 1) << 18)) >> 18)
+#define F_NUMBER_OF_ERRORS3(x) (((x) & ((1 << 5) - 1)) << 19)
+#define F_NUMBER_OF_ERRORS3_RD(x) (((x) & (((1 << 5) - 1) << 19)) >> 19)
+
+/* register LANES_CONFIG */
+#define LANES_CONFIG 5
+#define F_SOURCE_PHY_LANE0_SWAP(x) (((x) & ((1 << 2) - 1)) << 0)
+#define F_SOURCE_PHY_LANE0_SWAP_RD(x) (((x) & (((1 << 2) - 1) << 0)) >> 0)
+#define F_SOURCE_PHY_LANE1_SWAP(x) (((x) & ((1 << 2) - 1)) << 2)
+#define F_SOURCE_PHY_LANE1_SWAP_RD(x) (((x) & (((1 << 2) - 1) << 2)) >> 2)
+#define F_SOURCE_PHY_LANE2_SWAP(x) (((x) & ((1 << 2) - 1)) << 4)
+#define F_SOURCE_PHY_LANE2_SWAP_RD(x) (((x) & (((1 << 2) - 1) << 4)) >> 4)
+#define F_SOURCE_PHY_LANE3_SWAP(x) (((x) & ((1 << 2) - 1)) << 6)
+#define F_SOURCE_PHY_LANE3_SWAP_RD(x) (((x) & (((1 << 2) - 1) << 6)) >> 6)
+#define F_SOURCE_PHY_LANE0_LSB_MSB(x) (((x) & ((1 << 1) - 1)) << 8)
+#define F_SOURCE_PHY_LANE0_LSB_MSB_RD(x) (((x) & (((1 << 1) - 1) << 8)) >> 8)
+#define F_SOURCE_PHY_LANE1_LSB_MSB(x) (((x) & ((1 << 1) - 1)) << 9)
+#define F_SOURCE_PHY_LANE1_LSB_MSB_RD(x) (((x) & (((1 << 1) - 1) << 9)) >> 9)
+#define F_SOURCE_PHY_LANE2_LSB_MSB(x) (((x) & ((1 << 1) - 1)) << 10)
+#define F_SOURCE_PHY_LANE2_LSB_MSB_RD(x) (((x) & (((1 << 1) - 1) << 10)) >> 10)
+#define F_SOURCE_PHY_LANE3_LSB_MSB(x) (((x) & ((1 << 1) - 1)) << 11)
+#define F_SOURCE_PHY_LANE3_LSB_MSB_RD(x) (((x) & (((1 << 1) - 1) << 11)) >> 11)
+#define F_SOURCE_PHY_AUX_SPARE(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_PHY_AUX_SPARE_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+#define F_SOURCE_PHY_LANE0_POLARITY(x) (((x) & ((1 << 1) - 1)) << 16)
+#define F_SOURCE_PHY_LANE0_POLARITY_RD(x) (((x) & (((1 << 1) - 1) << 16)) >> 16)
+#define F_SOURCE_PHY_LANE1_POLARITY(x) (((x) & ((1 << 1) - 1)) << 17)
+#define F_SOURCE_PHY_LANE1_POLARITY_RD(x) (((x) & (((1 << 1) - 1) << 17)) >> 17)
+#define F_SOURCE_PHY_LANE2_POLARITY(x) (((x) & ((1 << 1) - 1)) << 18)
+#define F_SOURCE_PHY_LANE2_POLARITY_RD(x) (((x) & (((1 << 1) - 1) << 18)) >> 18)
+#define F_SOURCE_PHY_LANE3_POLARITY(x) (((x) & ((1 << 1) - 1)) << 19)
+#define F_SOURCE_PHY_LANE3_POLARITY_RD(x) (((x) & (((1 << 1) - 1) << 19)) >> 19)
+#define F_SOURCE_PHY_DATA_DEL_EN(x) (((x) & ((1 << 1) - 1)) << 20)
+#define F_SOURCE_PHY_DATA_DEL_EN_RD(x) (((x) & (((1 << 1) - 1) << 20)) >> 20)
+#define F_SOURCE_PHY_COMB_BYPASS(x) (((x) & ((1 << 1) - 1)) << 21)
+#define F_SOURCE_PHY_COMB_BYPASS_RD(x) (((x) & (((1 << 1) - 1) << 21)) >> 21)
+#define F_SOURCE_PHY_20_10(x) (((x) & ((1 << 1) - 1)) << 22)
+#define F_SOURCE_PHY_20_10_RD(x) (((x) & (((1 << 1) - 1) << 22)) >> 22)
+
+/* register PHY_DATA_SEL */
+#define PHY_DATA_SEL 6
+#define F_SOURCE_PHY_DATA_SEL(x) (((x) & ((1 << 3) - 1)) << 0)
+#define F_SOURCE_PHY_DATA_SEL_RD(x) (((x) & (((1 << 3) - 1) << 0)) >> 0)
+#define F_SOURCE_PHY_MHDP_SEL(x) (((x) & ((1 << 2) - 1)) << 3)
+#define F_SOURCE_PHY_MHDP_SEL_RD(x) (((x) & (((1 << 2) - 1) << 3)) >> 3)
+
+/* register LANES_DEL_VAL */
+#define LANES_DEL_VAL 7
+#define F_SOURCE_PHY_LANE0_DEL_VAL(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_SOURCE_PHY_LANE0_DEL_VAL_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_SOURCE_PHY_LANE1_DEL_VAL(x) (((x) & ((1 << 4) - 1)) << 4)
+#define F_SOURCE_PHY_LANE1_DEL_VAL_RD(x) (((x) & (((1 << 4) - 1) << 4)) >> 4)
+#define F_SOURCE_PHY_LANE2_DEL_VAL(x) (((x) & ((1 << 4) - 1)) << 8)
+#define F_SOURCE_PHY_LANE2_DEL_VAL_RD(x) (((x) & (((1 << 4) - 1) << 8)) >> 8)
+#define F_SOURCE_PHY_LANE3_DEL_VAL(x) (((x) & ((1 << 4) - 1)) << 12)
+#define F_SOURCE_PHY_LANE3_DEL_VAL_RD(x) (((x) & (((1 << 4) - 1) << 12)) >> 12)
+
+#endif //SOURCE_PHY
diff --git a/drivers/mxc/hdp/source_pif.h b/drivers/mxc/hdp/source_pif.h
new file mode 100644
index 000000000000..ed6c66aa611e
--- /dev/null
+++ b/drivers/mxc/hdp/source_pif.h
@@ -0,0 +1,170 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * source_pif.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef SOURCE_PIF_H_
+#define SOURCE_PIF_H_
+
+/* register SOURCE_PIF_WR_ADDR */
+#define SOURCE_PIF_WR_ADDR 0
+#define F_WR_ADDR(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_WR_ADDR_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+
+/* register SOURCE_PIF_WR_REQ */
+#define SOURCE_PIF_WR_REQ 1
+#define F_HOST_WR(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_HOST_WR_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register SOURCE_PIF_RD_ADDR */
+#define SOURCE_PIF_RD_ADDR 2
+#define F_RD_ADDR(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_RD_ADDR_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+
+/* register SOURCE_PIF_RD_REQ */
+#define SOURCE_PIF_RD_REQ 3
+#define F_HOST_RD(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_HOST_RD_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register SOURCE_PIF_DATA_WR */
+#define SOURCE_PIF_DATA_WR 4
+#define F_DATA_WR(x) (x)
+#define F_DATA_WR_RD(x) (x)
+
+/* register SOURCE_PIF_DATA_RD */
+#define SOURCE_PIF_DATA_RD 5
+#define F_FIFO2_DATA_OUT(x) (x)
+#define F_FIFO2_DATA_OUT_RD(x) (x)
+
+/* register SOURCE_PIF_FIFO1_FLUSH */
+#define SOURCE_PIF_FIFO1_FLUSH 6
+#define F_FIFO1_FLUSH(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_FIFO1_FLUSH_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register SOURCE_PIF_FIFO2_FLUSH */
+#define SOURCE_PIF_FIFO2_FLUSH 7
+#define F_FIFO2_FLUSH(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_FIFO2_FLUSH_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register SOURCE_PIF_STATUS */
+#define SOURCE_PIF_STATUS 8
+#define F_SOURCE_PKT_MEM_CTRL_FSM_STATE(x) (((x) & ((1 << 2) - 1)) << 0)
+#define F_SOURCE_PKT_MEM_CTRL_FSM_STATE_RD(x) (((x) & (((1 << 2) - 1) << 0)) >> 0)
+#define F_FIFO1_FULL(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_FIFO1_FULL_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_FIFO2_EMPTY(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_FIFO2_EMPTY_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+
+/* register SOURCE_PIF_INTERRUPT_SOURCE */
+#define SOURCE_PIF_INTERRUPT_SOURCE 9
+#define F_HOST_WR_DONE_INT(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_HOST_WR_DONE_INT_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_HOST_RD_DONE_INT(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_HOST_RD_DONE_INT_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_NONVALID_TYPE_REQUESTED_INT(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_NONVALID_TYPE_REQUESTED_INT_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_PSLVERR(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_PSLVERR_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_ALLOC_WR_DONE(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_ALLOC_WR_DONE_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_ALLOC_WR_ERROR(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_ALLOC_WR_ERROR_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_FIFO1_OVERFLOW(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_FIFO1_OVERFLOW_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+#define F_FIFO1_UNDERFLOW(x) (((x) & ((1 << 1) - 1)) << 7)
+#define F_FIFO1_UNDERFLOW_RD(x) (((x) & (((1 << 1) - 1) << 7)) >> 7)
+#define F_FIFO2_OVERFLOW(x) (((x) & ((1 << 1) - 1)) << 8)
+#define F_FIFO2_OVERFLOW_RD(x) (((x) & (((1 << 1) - 1) << 8)) >> 8)
+#define F_FIFO2_UNDERFLOW(x) (((x) & ((1 << 1) - 1)) << 9)
+#define F_FIFO2_UNDERFLOW_RD(x) (((x) & (((1 << 1) - 1) << 9)) >> 9)
+
+/* register SOURCE_PIF_INTERRUPT_MASK */
+#define SOURCE_PIF_INTERRUPT_MASK 10
+#define F_HOST_WR_DONE_INT_MASK(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_HOST_WR_DONE_INT_MASK_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_HOST_RD_DONE_INT_MASK(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_HOST_RD_DONE_INT_MASK_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_NONVALID_TYPE_REQUESTED_INT_MASK(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_NONVALID_TYPE_REQUESTED_INT_MASK_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_PSLVERR_MASK(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_PSLVERR_MASK_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+#define F_ALLOC_WR_DONE_MASK(x) (((x) & ((1 << 1) - 1)) << 4)
+#define F_ALLOC_WR_DONE_MASK_RD(x) (((x) & (((1 << 1) - 1) << 4)) >> 4)
+#define F_ALLOC_WR_ERROR_MASK(x) (((x) & ((1 << 1) - 1)) << 5)
+#define F_ALLOC_WR_ERROR_MASK_RD(x) (((x) & (((1 << 1) - 1) << 5)) >> 5)
+#define F_FIFO1_OVERFLOW_MASK(x) (((x) & ((1 << 1) - 1)) << 6)
+#define F_FIFO1_OVERFLOW_MASK_RD(x) (((x) & (((1 << 1) - 1) << 6)) >> 6)
+#define F_FIFO1_UNDERFLOW_MASK(x) (((x) & ((1 << 1) - 1)) << 7)
+#define F_FIFO1_UNDERFLOW_MASK_RD(x) (((x) & (((1 << 1) - 1) << 7)) >> 7)
+#define F_FIFO2_OVERFLOW_MASK(x) (((x) & ((1 << 1) - 1)) << 8)
+#define F_FIFO2_OVERFLOW_MASK_RD(x) (((x) & (((1 << 1) - 1) << 8)) >> 8)
+#define F_FIFO2_UNDERFLOW_MASK(x) (((x) & ((1 << 1) - 1)) << 9)
+#define F_FIFO2_UNDERFLOW_MASK_RD(x) (((x) & (((1 << 1) - 1) << 9)) >> 9)
+
+/* register SOURCE_PIF_PKT_ALLOC_REG */
+#define SOURCE_PIF_PKT_ALLOC_REG 11
+#define F_PKT_ALLOC_ADDRESS(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_PKT_ALLOC_ADDRESS_RD(x) (((x) & (((1 << 4) - 1) << 0)) >> 0)
+#define F_PACKET_TYPE(x) (((x) & ((1 << 8) - 1)) << 8)
+#define F_PACKET_TYPE_RD(x) (((x) & (((1 << 8) - 1) << 8)) >> 8)
+#define F_TYPE_VALID(x) (((x) & ((1 << 1) - 1)) << 16)
+#define F_TYPE_VALID_RD(x) (((x) & (((1 << 1) - 1) << 16)) >> 16)
+#define F_ACTIVE_IDLE_TYPE(x) (((x) & ((1 << 1) - 1)) << 17)
+#define F_ACTIVE_IDLE_TYPE_RD(x) (((x) & (((1 << 1) - 1) << 17)) >> 17)
+
+/* register SOURCE_PIF_PKT_ALLOC_WR_EN */
+#define SOURCE_PIF_PKT_ALLOC_WR_EN 12
+#define F_PKT_ALLOC_WR_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_PKT_ALLOC_WR_EN_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+/* register SOURCE_PIF_SW_RESET */
+#define SOURCE_PIF_SW_RESET 13
+#define F_SW_RST(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_SW_RST_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+#endif //SOURCE_PIF
diff --git a/drivers/mxc/hdp/source_vif.h b/drivers/mxc/hdp/source_vif.h
new file mode 100644
index 000000000000..8281f9bcb282
--- /dev/null
+++ b/drivers/mxc/hdp/source_vif.h
@@ -0,0 +1,93 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated. Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * source_vif.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef SOURCE_VIF_H_
+#define SOURCE_VIF_H_
+
+/* register BND_HSYNC2VSYNC */
+#define BND_HSYNC2VSYNC 0
+#define F_IP_DTCT_WIN(x) (((x) & ((1 << 12) - 1)) << 0)
+#define F_IP_DTCT_WIN_RD(x) (((x) & (((1 << 12) - 1) << 0)) >> 0)
+#define F_IP_DET_EN(x) (((x) & ((1 << 1) - 1)) << 12)
+#define F_IP_DET_EN_RD(x) (((x) & (((1 << 1) - 1) << 12)) >> 12)
+#define F_IP_VIF_BYPASS(x) (((x) & ((1 << 1) - 1)) << 13)
+#define F_IP_VIF_BYPASS_RD(x) (((x) & (((1 << 1) - 1) << 13)) >> 13)
+
+/* register HSYNC2VSYNC_F1_L1 */
+#define HSYNC2VSYNC_F1_L1 1
+#define F_IP_DTCT_HSYNC2VSYNC_F1(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_IP_DTCT_HSYNC2VSYNC_F1_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+
+/* register HSYNC2VSYNC_F2_L1 */
+#define HSYNC2VSYNC_F2_L1 2
+#define F_IP_DTCT_HSYNC2VSYNC_F2(x) (((x) & ((1 << 16) - 1)) << 0)
+#define F_IP_DTCT_HSYNC2VSYNC_F2_RD(x) (((x) & (((1 << 16) - 1) << 0)) >> 0)
+
+/* register HSYNC2VSYNC_STATUS */
+#define HSYNC2VSYNC_STATUS 3
+#define F_IP_DTCT_ERR(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_IP_DTCT_ERR_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+#define F_IP_DCT_IP(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_IP_DCT_IP_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_IP_DTCT_VJITTER(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_IP_DTCT_VJITTER_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_IP_DTCT_HJITTER(x) (((x) & ((1 << 1) - 1)) << 3)
+#define F_IP_DTCT_HJITTER_RD(x) (((x) & (((1 << 1) - 1) << 3)) >> 3)
+
+/* register HSYNC2VSYNC_POL_CTRL */
+#define HSYNC2VSYNC_POL_CTRL 4
+#define F_VPOL(x) (((x) & ((1 << 1) - 1)) << 2)
+#define F_VPOL_RD(x) (((x) & (((1 << 1) - 1) << 2)) >> 2)
+#define F_HPOL(x) (((x) & ((1 << 1) - 1)) << 1)
+#define F_HPOL_RD(x) (((x) & (((1 << 1) - 1) << 1)) >> 1)
+#define F_VIF_AUTO_MODE(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_VIF_AUTO_MODE_RD(x) (((x) & (((1 << 1) - 1) << 0)) >> 0)
+
+#endif //SOURCE_VIF
diff --git a/drivers/mxc/hdp/util.c b/drivers/mxc/hdp/util.c
new file mode 100644
index 000000000000..61d2c8797ffc
--- /dev/null
+++ b/drivers/mxc/hdp/util.c
@@ -0,0 +1,360 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * util.c
+ *
+ ******************************************************************************
+ */
+#include "util.h"
+#include "API_General.h"
+#include "apb_cfg.h"
+#include "opcodes.h"
+
+int cdn_apb_read(state_struct *state, u32 addr, u32 *value)
+{
+ struct hdp_mem *mem = state->mem;
+ state->rw->read_reg(mem, addr, value);
+ return 0;
+}
+
+int cdn_apb_write(state_struct *state, u32 addr, u32 value)
+{
+ struct hdp_mem *mem = state->mem;
+ state->rw->write_reg(mem, addr, value);
+ return 0;
+}
+
+int cdn_sapb_read(state_struct *state, u32 addr, u32 *value)
+{
+ struct hdp_mem *mem = state->mem;
+ state->rw->sread_reg(mem, addr, value);
+ return 0;
+}
+
+int cdn_sapb_write(state_struct *state, u32 addr, u32 value)
+{
+ struct hdp_mem *mem = state->mem;
+ state->rw->swrite_reg(mem, addr, value);
+ return 0;
+}
+
+void cdn_sleep(u32 ms)
+{
+ mdelay(ms);
+}
+
+void cdn_usleep(u32 us)
+{
+ udelay(us);
+}
+
+int cdn_bus_read(state_struct *state, u32 addr, u32 *value)
+{
+ return state->bus_type ?
+ cdn_sapb_read(state, addr, value) : cdn_apb_read(state, addr,
+ value);
+}
+
+int cdn_bus_write(state_struct *state, u32 addr, u32 value)
+{
+ return state->bus_type ?
+ cdn_sapb_write(state, addr, value) : cdn_apb_write(state, addr,
+ value);
+}
+
+void internal_itobe(int val, volatile u8 *dest, int bytes)
+{
+ int i;
+ for (i = bytes - 1; i >= 0; --i) {
+ dest[i] = (u8) val;
+ val >>= 8;
+ }
+}
+
+u32 internal_betoi(volatile u8 const *src, u8 bytes)
+{
+ u32 ret = 0;
+ int i;
+
+ if (bytes > sizeof(ret)) {
+ printk
+ ("Warning. Read request for payload larger then supported.\n");
+ bytes = sizeof(ret);
+
+ }
+
+ for (i = 0; i < bytes; ++i) {
+ ret <<= 8;
+ ret |= (u32) src[i];
+ }
+
+ return ret;
+}
+
+u32 internal_mkmsg(volatile u8 *dest, int valNo, ...)
+{
+ va_list vl;
+ u32 len = 0;
+ va_start(vl, valNo);
+ len = internal_vmkmsg(dest, valNo, vl);
+ va_end(vl);
+ return len;
+}
+
+u32 internal_vmkmsg(volatile u8 *dest, int valNo, va_list vl)
+{
+ u32 len = 0;
+ int i;
+ for (i = 0; i < valNo; ++i) {
+ int size = va_arg(vl, int);
+ if (size > 0) {
+ internal_itobe(va_arg(vl, int), dest, size);
+ dest += size;
+ len += size;;
+ } else {
+ memcpy((void *)dest, va_arg(vl, void *), -size);
+ dest -= size;
+ len -= size;
+ }
+ }
+ return len;
+}
+
+void internal_tx_mkfullmsg(state_struct *state, u8 module, u8 opcode,
+ int valNo, ...)
+{
+ va_list vl;
+ va_start(vl, valNo);
+ internal_vtx_mkfullmsg(state, module, opcode, valNo, vl);
+ va_end(vl);
+}
+
+void internal_vtx_mkfullmsg(state_struct *state, u8 module, u8 opcode,
+ int valNo, va_list vl)
+{
+ u32 len =
+ internal_vmkmsg(state->txBuffer + INTERNAL_CMD_HEAD_SIZE, valNo,
+ vl);
+ internal_mbox_tx_enable(state, module, opcode, len);
+ state->txEnable = 1;
+ state->running = 1;
+}
+
+void internal_readmsg(state_struct *state, int valNo, ...)
+{
+ va_list vl;
+ va_start(vl, valNo);
+ internal_vreadmsg(state, valNo, vl);
+ va_end(vl);
+}
+
+void internal_vreadmsg(state_struct *state, int valNo, va_list vl)
+{
+ u8 *src = state->rxBuffer + INTERNAL_CMD_HEAD_SIZE;
+ size_t i;
+
+ for (i = 0; i < (size_t) valNo; ++i) {
+ int size = va_arg(vl, int);
+ void *ptr = va_arg(vl, void *);
+
+ if (!ptr) {
+ src += size;
+ } else if (!size) {
+ *((u8 **) ptr) = src;
+ } else if (size > 0) {
+ switch ((size_t) size) {
+ case sizeof(u8):
+ *((u8 *) ptr) = internal_betoi(src, size);
+ break;
+ case sizeof(u16):
+ *((u16 *) ptr) = internal_betoi(src, size);
+ break;
+ case 3: // 3-byte value (e.g. DPCD address) can be safely converted from BE
+ case sizeof(u32):
+ *((u32 *) ptr) = internal_betoi(src, size);
+ break;
+ default:
+ pr_warn("Warning. Unsupported variable size.\n");
+ memcpy(ptr, src, size);
+ };
+
+ src += size;
+ } else {
+ memcpy(ptr, src, -size);
+ src -= size;
+ }
+ }
+}
+
+INTERNAL_MBOX_STATUS mailbox_write(state_struct *state, u8 val)
+{
+ INTERNAL_MBOX_STATUS ret;
+ u32 full;
+ if (cdn_bus_read(state, MAILBOX_FULL_ADDR << 2, &full)) {
+ ret.tx_status = CDN_TX_APB_ERROR;
+ return ret;
+ }
+ if (full) {
+ ret.tx_status = CDN_TX_FULL;
+ return ret;
+ }
+ if (cdn_bus_write(state, MAILBOX0_WR_DATA << 2, val)) {
+ ret.tx_status = CDN_TX_APB_ERROR;
+ return ret;
+ }
+ ret.tx_status = CDN_TX_WRITE;
+ return ret;
+}
+
+INTERNAL_MBOX_STATUS mailbox_read(state_struct *state, volatile u8 *val)
+{
+ INTERNAL_MBOX_STATUS ret;
+ u32 empty;
+ u32 rd;
+ if (cdn_bus_read(state, MAILBOX_EMPTY_ADDR << 2, &empty)) {
+ ret.rx_status = CDN_RX_APB_ERROR;
+ return ret;
+ }
+ if (empty) {
+ ret.rx_status = CDN_RX_EMPTY;
+ return ret;
+ }
+ if (cdn_bus_read(state, MAILBOX0_RD_DATA << 2, &rd)) {
+ ret.rx_status = CDN_RX_APB_ERROR;
+ return ret;
+ }
+ *val = (u8) rd;
+ ret.rx_status = CDN_RX_READ;
+ return ret;
+}
+
+INTERNAL_MBOX_STATUS internal_mbox_tx_process(state_struct *state)
+{
+ u32 txCount = 0;
+ u32 length = (u32) state->txBuffer[2] << 8 | (u32) state->txBuffer[3];
+ INTERNAL_MBOX_STATUS ret = {.txend = 0 };
+ INTERNAL_MBOX_STATUS tx_ret;
+
+ ret.tx_status = CDN_TX_NOTHING;
+ if (!state->txEnable)
+ return ret;
+ while ((tx_ret.tx_status =
+ mailbox_write(state, state->txBuffer[state->txi]).tx_status) ==
+ CDN_TX_WRITE) {
+ txCount++;
+ if (++state->txi >= length + 4) {
+ state->txEnable = 0;
+ state->txi = 0;
+ ret.txend = 1;
+ break;
+ }
+ }
+ if (txCount && tx_ret.tx_status == CDN_TX_FULL)
+ ret.tx_status = CDN_TX_WRITE;
+ else
+ ret.tx_status = tx_ret.tx_status;
+ return ret;
+}
+
+INTERNAL_MBOX_STATUS internal_mbox_rx_process(state_struct *state)
+{
+ u32 rxCount = 0;
+ INTERNAL_MBOX_STATUS ret = { 0, 0, 0, 0 };
+ INTERNAL_MBOX_STATUS rx_ret;
+ while ((rx_ret.rx_status =
+ mailbox_read(state, state->rxBuffer + state->rxi).rx_status) ==
+ CDN_RX_READ) {
+ rxCount++;
+ if (++state->rxi >=
+ 4 +
+ ((u32) state->rxBuffer[2] << 8 | (u32) state->
+ rxBuffer[3])) {
+ state->rxi = 0;
+ ret.rxend = 1;
+ state->rxEnable = 0;
+ break;
+ }
+ }
+ ret.rx_status = rxCount ? CDN_RX_READ : CDN_RX_EMPTY;
+ return ret;
+}
+
+u32 internal_apb_available(state_struct *state)
+{
+ return !(state->rxEnable || state->txEnable);
+}
+
+void internal_mbox_tx_enable(state_struct *state, u8 module, u8 opcode,
+ u16 length)
+{
+ state->txBuffer[0] = opcode;
+ state->txBuffer[1] = module;
+ state->txBuffer[2] = (u8) (length >> 8);
+ state->txBuffer[3] = (u8) length;
+ state->txEnable = 1;
+}
+
+CDN_API_STATUS internal_test_rx_head(state_struct *state, u8 module, u8 opcode)
+{
+ if (opcode != state->rxBuffer[0])
+ return CDN_BAD_OPCODE;
+ if (module != state->rxBuffer[1])
+ return CDN_BAD_MODULE;
+ return CDN_OK;
+}
+
+CDN_API_STATUS internal_test_rx_head_match(state_struct *state)
+{
+ return internal_test_rx_head(state, state->txBuffer[1],
+ state->txBuffer[0]);
+}
+
+void print_fw_ver(state_struct *state)
+{
+ u16 ver, verlib;
+ CDN_API_General_getCurVersion(state, &ver, &verlib);
+ printk("FIRMWARE VERSION: %d, LIB VERSION: %d\n", ver, verlib);
+}
+
+u16 internal_get_msg_len(state_struct *state)
+{
+ return ((u16) state->rxBuffer[2] << 8) | (u16) state->rxBuffer[3];
+}
diff --git a/drivers/mxc/hdp/util.h b/drivers/mxc/hdp/util.h
new file mode 100644
index 000000000000..5cf3c815a059
--- /dev/null
+++ b/drivers/mxc/hdp/util.h
@@ -0,0 +1,394 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * 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.
+ *
+ * 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. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Copyright 2017-2018 NXP
+ *
+ ******************************************************************************
+ *
+ * util.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef UTIL_H_
+#define UTIL_H_
+
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_edid.h>
+
+/**
+ * \addtogroup GENERAL_API
+ * \{
+ */
+/** status code returned by API calls */
+typedef enum {
+ /** operation succedded */
+ CDN_OK = 0,
+ /** CEC operation succedded */
+ CDN_CEC_ERR_NONE = 0,
+ /** mailbox is currently sending or receiving data */
+ CDN_BSY,
+ /** message set up and ready to be sent, no data sent yet */
+ CDN_STARTED,
+ /** error encountered while reading/writing APB */
+ CDN_ERR,
+ /** reply returned with bad opcode */
+ CDN_BAD_OPCODE,
+ /** reply returned with bad module */
+ CDN_BAD_MODULE,
+ /** reply not supported mode */
+ CDN_ERROR_NOT_SUPPORTED,
+ /** Invalid argument passed to CEC API function */
+ CDN_CEC_ERR_INVALID_ARG,
+ /**
+ * TX Buffer for CEC Messages is full. This is applicable only
+ * when TX Buffers for CEC Messages are implemented in the HW.
+ */
+ CDN_CEC_ERR_TX_BUFF_FULL,
+ /** No Messages in the RX Buffers are present. */
+ CDN_CEC_ERR_RX_BUFF_EMPTY,
+ /** Timeout during TX operation */
+ CDN_CEC_ERR_TX_TIMEOUT,
+ /** Timeout during RX operation */
+ CDN_CEC_ERR_RX_TIMEOUT,
+ /** Data transmision fail. */
+ CDN_CEC_ERR_TX_FAILED,
+ /** Data reception fail. */
+ CDN_CEC_ERR_RX_FAILED,
+ /** Operation aborted. */
+ CDN_CEC_ERR_ABORT,
+ /** All Logical Addresses are in use. */
+ CDN_CEC_ERR_ALL_LA_IN_USE,
+} CDN_API_STATUS;
+
+typedef enum {
+ CDN_DPTX,
+ CDN_HDMITX_TYPHOON,
+ CDN_HDMITX_KIRAN,
+} CDN_PROTOCOL_TYPE;
+
+typedef enum {
+ CDN_BUS_TYPE_APB = 0,
+ CDN_BUS_TYPE_SAPB = 1
+} CDN_BUS_TYPE;
+
+typedef enum {
+ NUM_OF_LANES_1 = 1,
+ NUM_OF_LANES_2 = 2,
+ NUM_OF_LANES_4 = 4,
+} VIC_NUM_OF_LANES;
+
+typedef enum {
+ RATE_1_6 = 162,
+ RATE_2_1 = 216,
+ RATE_2_4 = 243,
+ RATE_2_7 = 270,
+ RATE_3_2 = 324,
+ RATE_4_3 = 432,
+ RATE_5_4 = 540,
+ RATE_8_1 = 810,
+} VIC_SYMBOL_RATE;
+
+typedef enum {
+ PXL_RGB = 0x1,
+ YCBCR_4_4_4 = 0x2,
+ YCBCR_4_2_2 = 0x4,
+ YCBCR_4_2_0 = 0x8,
+ Y_ONLY = 0x10,
+} VIC_PXL_ENCODING_FORMAT;
+
+typedef enum {
+ BCS_6 = 0x1,
+ BCS_8 = 0x2,
+ BCS_10 = 0x4,
+ BCS_12 = 0x8,
+ BCS_16 = 0x10,
+} VIC_COLOR_DEPTH;
+
+typedef enum {
+ STEREO_VIDEO_LEFT = 0x0,
+ STEREO_VIDEO_RIGHT = 0x1,
+} STEREO_VIDEO_ATTR;
+
+typedef enum {
+ BT_601 = 0x0,
+ BT_709 = 0x1,
+} BT_TYPE;
+
+typedef struct {
+ /** apb write status */
+ enum tx_status_enum {
+ /** one or more bytes written */
+ CDN_TX_WRITE = 0,
+ /** nothing to write */
+ CDN_TX_NOTHING = 1,
+ /** mailbox full, 0 bytes written */
+ CDN_TX_FULL = 2,
+ /** APB error while writing */
+ CDN_TX_APB_ERROR = 3
+ } tx_status:3;
+ /** apb read status */
+ enum rx_status_enum {
+ /** 1 or more bytes read */
+ CDN_RX_READ = 0,
+ /** mailbox empty, 0 bytes read */
+ CDN_RX_EMPTY = 1,
+ /** apb error while reading */
+ CDN_RX_APB_ERROR = 2
+ } rx_status:2;
+ /** indicates end of currenly recived message */
+ u8 rxend:1;
+ /** end of tx message reached */
+ u8 txend:1;
+} INTERNAL_MBOX_STATUS;
+
+struct hdp_mem {
+ void __iomem *regs_base; /* Controller regs base */
+ void __iomem *ss_base; /* HDP Subsystem regs base */
+ void __iomem *rst_base; /* HDP Subsystem reset base */
+};
+
+struct hdp_rw_func {
+ int (*read_reg) (struct hdp_mem *mem, u32 addr, u32 *value);
+ int (*write_reg) (struct hdp_mem *mem, u32 addr, u32 value);
+ int (*sread_reg) (struct hdp_mem *mem, u32 addr, u32 *value);
+ int (*swrite_reg) (struct hdp_mem *mem, u32 addr, u32 value);
+};
+
+typedef struct {
+ u8 txBuffer[1024];
+ u8 rxBuffer[1024];
+ u32 txi; //iterators
+ u32 rxi;
+ u8 txEnable; //data readt to send
+ u8 rxEnable;
+ u8 running;
+ CDN_BUS_TYPE bus_type;
+ u32 tmp;
+ u32 edp; /* use eDP */
+
+ struct mutex mutex; //mutex may replace running
+ struct hdp_mem *mem;
+ struct hdp_rw_func *rw;
+} state_struct;
+/**
+ * \addtogroup UTILS
+ * \{
+ */
+#define INTERNAL_CMD_HEAD_SIZE 4
+
+/**
+ * \brief expands to blocking function body
+ * \param x - function call
+ */
+#define MAILBOX_FILL_TIMEOUT 1500
+#define internal_block_function(y, x) \
+do { \
+ unsigned long end_jiffies = jiffies + \
+ msecs_to_jiffies(MAILBOX_FILL_TIMEOUT); \
+ CDN_API_STATUS ret; \
+ mutex_lock(y); \
+ do { \
+ ret = x; \
+ cpu_relax(); \
+ } while (time_after(end_jiffies, jiffies) && \
+ (ret == CDN_BSY || ret == CDN_STARTED)); \
+ mutex_unlock(y); \
+ return ret; \
+} while (0)
+
+/**
+ * \brief write message and write response (if any), non-blocking way. Also sets state.running = 0
+ */
+#define internal_process_messages(state) \
+do { \
+ if (state->txEnable && !internal_mbox_tx_process(state).txend) \
+ return CDN_BSY; \
+ if (state->rxEnable && !internal_mbox_rx_process(state).rxend) \
+ return CDN_BSY; \
+ state->running = 0; \
+} while (0)
+
+#define internal_opcode_ok_or_return(state, module, opcode) do { \
+ CDN_API_STATUS ret; \
+ ret = internal_test_rx_head(state, module, opcode); \
+ if (ret != CDN_OK) \
+ return ret; \
+} while (0)
+
+#define internal_opcode_match_or_return(state) do { \
+ CDN_API_STATUS ret; \
+ ret = internal_test_rx_head_match(state); \
+ if (ret != CDN_OK) \
+ return ret; \
+} while (0)
+
+/* macro for simple tx only command, command format as in mkfullmsg (with count) */
+#define internal_macro_command_tx(state, module, opcode, bustype, command...) \
+do { \
+ if (!state->running) { \
+ internal_tx_mkfullmsg(state, module, opcode, command); \
+ state->bus_type = bustype; \
+ return CDN_STARTED; \
+ } \
+ internal_process_messages(state); \
+} while (0)
+
+/* macro for command with response with matching opcode, command format as in mkfullmsg (with count) */
+#define internal_macro_command_txrx(state, module, opcode, bustype, command...) \
+do { \
+ if (!state->running) { \
+ internal_tx_mkfullmsg(state, module, opcode, command); \
+ state->bus_type = bustype; \
+ state->rxEnable = 1; \
+ return CDN_STARTED; \
+ } \
+ internal_process_messages(state); \
+ internal_opcode_match_or_return(state); \
+} while (0)
+
+/**
+ * \brief put val into dest in big endian format
+ * \param val - value to put
+ * \param dest - place to put value
+ * \param bytes - true size of val in bytes. for example if bytes = 2 val is treated as short int
+ */
+void internal_itobe(int val, volatile u8 *dest, int bytes);
+
+/**
+ * \brief read big endian value from src and return it
+ * \param src - source to read from
+ * \param bytes - size of read value
+ * \return result
+ */
+u32 internal_betoi(volatile u8 const *src, u8 bytes);
+
+/**
+ * \brief create message from size and value pairs; also sets state.runnging and state.txEnable
+ * \param dest - pointer to write message to
+ * \param valNo - number of values to write
+ * \param ... - pairs of size and value, each value is written after another. if size is positive value, value is written with #internal_itobe, if size is negative, value is treated as src pointer for memcpy
+ *
+ * example:
+ *
+ * u16 x = 0xAABB;
+ *
+ * internal_mkmsg(dest, 3, 1, 1, 2, 3, -2, &x);
+ *
+ * will write 01 00 03 AA BB to dest
+ */
+u32 internal_mkmsg(volatile u8 *dest, int valNo, ...);
+u32 internal_vmkmsg(volatile u8 *dest, int valNo, va_list vl);
+
+/**
+ * \brief setup message header in txBuffer, set txEnable = 1
+ */
+void internal_mbox_tx_enable(state_struct *state, u8 module, u8 opcode,
+ u16 length);
+
+/**
+ * \brief write from txBuffer to mailbox untill full or end of message.
+ *
+ * when txEnable == 0 writes nothing
+ * when write reaches end of message set txEnable = 0
+ */
+
+/**
+ * \brief combination of #internal_mkmsg and #internal_mbox_tx_enable
+ *
+ * #internal_mkmsg dest and #internal_mbox_tx_enable length are determined automaticly
+ * this function also sets state.txEnable = 1 and state.running
+ */
+void internal_tx_mkfullmsg(state_struct *state, u8 module, u8 opcode,
+ int valNo, ...);
+void internal_vtx_mkfullmsg(state_struct *state, u8 module, u8 opcode,
+ int valNo, va_list vl);
+
+/**
+ * \brief read from state.txBuffer and store results in specified pointers
+ * \param valNo - numbero of values to read
+ * \param ... - pairs of size and ptr
+ *
+ * this function is similar to #internal_mkmsg -
+ *
+ * when size is positive read value using #internal_betoi
+ * when size is negative mempcy from txBuffer to ptr -size bytes
+ * when size is 0 write to ptr addres of current position in rxbuffer
+ * when ptr is NULL ignore size bytes (if size is negative this will rewind buffer)
+ */
+void internal_readmsg(state_struct *state, int valNo, ...);
+void internal_vreadmsg(state_struct *state, int valNo, va_list vl);
+
+INTERNAL_MBOX_STATUS internal_mbox_tx_process(state_struct *state);
+/**
+ * \brief read to rxBuffer from mailbox untill empty or end of message
+ *
+ * when rxEnable == 0 reads nothing
+ * when end of message reached sets rxEnable = 0
+ */
+INTERNAL_MBOX_STATUS internal_mbox_rx_process(state_struct *state);
+
+/**
+ * \brief check if apb is available
+ * \return !(rxEnable && txEable)
+ */
+u32 internal_apb_available(state_struct *state);
+
+/**
+ * \brief test if parameters match module and opcode in rxBuffer
+ * \return CDN_OK or CDN_BAD_OPCODE or CDN_BAD_MODULE
+ */
+CDN_API_STATUS internal_test_rx_head(state_struct *state, u8 module,
+ u8 opcode);
+
+CDN_API_STATUS internal_test_rx_head_match(state_struct *state);
+
+/**
+ * \brief print current fw and lib version
+ */
+void print_fw_ver(state_struct *state);
+
+int cdn_apb_read(state_struct *state, u32 addr, u32 *value);
+int cdn_sapb_read(state_struct *state, u32 addr, u32 *value);
+int cdn_apb_write(state_struct *state, u32 addr, u32 value);
+int cdn_sapb_write(state_struct *state, u32 addr, u32 value);
+void cdn_sleep(u32 ms);
+void cdn_usleep(u32 us);
+u16 internal_get_msg_len(state_struct *state);
+#endif
diff --git a/drivers/mxc/ipu3/Kconfig b/drivers/mxc/ipu3/Kconfig
new file mode 100644
index 000000000000..c702efed2b55
--- /dev/null
+++ b/drivers/mxc/ipu3/Kconfig
@@ -0,0 +1,21 @@
+config MXC_IPU_V3
+ bool
+
+config MXC_IPU_V3_PRG
+ tristate "i.MX IPUv3 prefetch gasket engine"
+ depends on MXC_IPU_V3 && MXC_IPU_V3_PRE
+ help
+ This enables support for the IPUv3 prefetch gasket engine to
+ support double buffer handshake control bewteen IPUv3 and
+ prefetch engine(PRE), snoop the AXI interface for display
+ refresh requests to memory and modify the request address to
+ fetch the double buffered row of blocks in OCRAM.
+
+config MXC_IPU_V3_PRE
+ tristate "i.MX IPUv3 prefetch engine"
+ depends on MXC_IPU_V3
+ select MXC_IPU_V3_PRG
+ help
+ This enables support for the IPUv3 prefetch engine to improve
+ the system memory performance. The engine has the capability
+ to resolve framebuffers in tile pixel format to linear.
diff --git a/drivers/mxc/ipu3/Makefile b/drivers/mxc/ipu3/Makefile
new file mode 100644
index 000000000000..d48f11244073
--- /dev/null
+++ b/drivers/mxc/ipu3/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_MXC_IPU_V3) = mxc_ipu.o
+
+obj-$(CONFIG_MXC_IPU_V3_PRG) += prg.o
+obj-$(CONFIG_MXC_IPU_V3_PRE) += pre.o
+
+mxc_ipu-objs := ipu_common.o ipu_ic.o ipu_disp.o ipu_capture.o ipu_device.o \
+ ipu_calc_stripes_sizes.o vdoa.o ipu_pixel_clk.o
diff --git a/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c b/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c
new file mode 100644
index 000000000000..512404d4101c
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c
@@ -0,0 +1,495 @@
+/*
+ * Copyright 2009-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ * @file ipu_calc_stripes_sizes.c
+ *
+ * @brief IPU IC functions
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/ipu-v3.h>
+#include <linux/module.h>
+#include <linux/math64.h>
+
+#define BPP_32 0
+#define BPP_16 3
+#define BPP_8 5
+#define BPP_24 1
+#define BPP_12 4
+#define BPP_18 2
+
+static u32 truncate(u32 up, /* 0: down; else: up */
+ u64 a, /* must be non-negative */
+ u32 b)
+{
+ u32 d;
+ u64 div;
+ div = div_u64(a, b);
+ d = b * (div >> 32);
+ if (up && (a > (((u64)d) << 32)))
+ return d+b;
+ else
+ return d;
+}
+
+static unsigned int f_calc(unsigned int pfs, unsigned int bpp, unsigned int *write)
+{/* return input_f */
+ unsigned int f_calculated = 0;
+ switch (pfs) {
+ case IPU_PIX_FMT_YVU422P:
+ case IPU_PIX_FMT_YUV422P:
+ case IPU_PIX_FMT_YUV420P2:
+ case IPU_PIX_FMT_YUV420P:
+ case IPU_PIX_FMT_YVU420P:
+ case IPU_PIX_FMT_YUV444P:
+ f_calculated = 16;
+ break;
+
+ case IPU_PIX_FMT_RGB565:
+ case IPU_PIX_FMT_YUYV:
+ case IPU_PIX_FMT_UYVY:
+ f_calculated = 8;
+ break;
+
+ case IPU_PIX_FMT_NV12:
+ f_calculated = 8;
+ break;
+
+ default:
+ f_calculated = 0;
+ break;
+
+ }
+ if (!f_calculated) {
+ switch (bpp) {
+ case BPP_32:
+ f_calculated = 2;
+ break;
+
+ case BPP_16:
+ f_calculated = 4;
+ break;
+
+ case BPP_8:
+ case BPP_24:
+ f_calculated = 8;
+ break;
+
+ case BPP_12:
+ f_calculated = 16;
+ break;
+
+ case BPP_18:
+ f_calculated = 32;
+ break;
+
+ default:
+ f_calculated = 0;
+ break;
+ }
+ }
+ return f_calculated;
+}
+
+
+static unsigned int m_calc(unsigned int pfs)
+{
+ unsigned int m_calculated = 0;
+ switch (pfs) {
+ case IPU_PIX_FMT_YUV420P2:
+ case IPU_PIX_FMT_YUV420P:
+ case IPU_PIX_FMT_YVU422P:
+ case IPU_PIX_FMT_YUV422P:
+ case IPU_PIX_FMT_YVU420P:
+ case IPU_PIX_FMT_YUV444P:
+ m_calculated = 16;
+ break;
+
+ case IPU_PIX_FMT_NV12:
+ case IPU_PIX_FMT_YUYV:
+ case IPU_PIX_FMT_UYVY:
+ m_calculated = 8;
+ break;
+
+ default:
+ m_calculated = 8;
+ break;
+
+ }
+ return m_calculated;
+}
+
+static int calc_split_resize_coeffs(unsigned int inSize, unsigned int outSize,
+ unsigned int *resizeCoeff,
+ unsigned int *downsizeCoeff)
+{
+ uint32_t tempSize;
+ uint32_t tempDownsize;
+
+ if (inSize > 4096) {
+ pr_debug("IC input size(%d) cannot exceed 4096\n",
+ inSize);
+ return -EINVAL;
+ }
+
+ if (outSize > 1024) {
+ pr_debug("IC output size(%d) cannot exceed 1024\n",
+ outSize);
+ return -EINVAL;
+ }
+
+ if ((outSize << 3) < inSize) {
+ pr_debug("IC cannot downsize more than 8:1\n");
+ return -EINVAL;
+ }
+
+ /* Compute downsizing coefficient */
+ /* Output of downsizing unit cannot be more than 1024 */
+ tempDownsize = 0;
+ tempSize = inSize;
+ while (((tempSize > 1024) || (tempSize >= outSize * 2)) &&
+ (tempDownsize < 2)) {
+ tempSize >>= 1;
+ tempDownsize++;
+ }
+ *downsizeCoeff = tempDownsize;
+
+ /* compute resizing coefficient using the following equation:
+ resizeCoeff = M*(SI -1)/(SO - 1)
+ where M = 2^13, SI - input size, SO - output size */
+ *resizeCoeff = (8192L * (tempSize - 1)) / (outSize - 1);
+ if (*resizeCoeff >= 16384L) {
+ pr_debug("Overflow on IC resize coefficient.\n");
+ return -EINVAL;
+ }
+
+ pr_debug("resizing from %u -> %u pixels, "
+ "downsize=%u, resize=%u.%lu (reg=%u)\n", inSize, outSize,
+ *downsizeCoeff, (*resizeCoeff >= 8192L) ? 1 : 0,
+ ((*resizeCoeff & 0x1FFF) * 10000L) / 8192L, *resizeCoeff);
+
+ return 0;
+}
+
+/* Stripe parameters calculator */
+/**************************************************************************
+Notes:
+MSW = the maximal width allowed for a stripe
+ i.MX31: 720, i.MX35: 800, i.MX37/51/53: 1024
+cirr = the maximal inverse resizing ratio for which overlap in the input
+ is requested; typically cirr~2
+flags
+ bit 0 - equal_stripes
+ 0 each stripe is allowed to have independent parameters
+ for maximal image quality
+ 1 the stripes are requested to have identical parameters
+ (except the base address), for maximal performance
+ bit 1 - vertical/horizontal
+ 0 horizontal
+ 1 vertical
+
+If performance is the top priority (above image quality)
+ Avoid overlap, by setting CIRR = 0
+ This will also force effectively identical_stripes = 1
+ Choose IF & OF that corresponds to the same IOX/SX for both stripes
+ Choose IFW & OFW such that
+ IFW/IM, IFW/IF, OFW/OM, OFW/OF are even integers
+ The function returns an error status:
+ 0: no error
+ 1: invalid input parameters -> aborted without result
+ Valid parameters should satisfy the following conditions
+ IFW <= OFW, otherwise downsizing is required
+ - which is not supported yet
+ 4 <= IFW,OFW, so some interpolation may be needed even without overlap
+ IM, OM, IF, OF should not vanish
+ 2*IF <= IFW
+ so the frame can be split to two equal stripes, even without overlap
+ 2*(OF+IF/irr_opt) <= OFW
+ so a valid positive INW exists even for equal stripes
+ OF <= MSW, otherwise, the left stripe cannot be sufficiently large
+ MSW < OFW, so splitting to stripes is required
+ OFW <= 2*MSW, so two stripes are sufficient
+ (this also implies that 2<=MSW)
+ 2: OF is not a multiple of OM - not fully-supported yet
+ Output is produced but OW is not guaranited to be a multiple of OM
+ 4: OFW reduced to be a multiple of OM
+ 8: CIRR > 1: truncated to 1
+ Overlap is not supported (and not needed) y for upsizing)
+**************************************************************************/
+int ipu_calc_stripes_sizes(const unsigned int input_frame_width,
+ /* input frame width;>1 */
+ unsigned int output_frame_width, /* output frame width; >1 */
+ const unsigned int maximal_stripe_width,
+ /* the maximal width allowed for a stripe */
+ const unsigned long long cirr, /* see above */
+ const unsigned int flags, /* see above */
+ u32 input_pixelformat,/* pixel format after of read channel*/
+ u32 output_pixelformat,/* pixel format after of write channel*/
+ struct stripe_param *left,
+ struct stripe_param *right)
+{
+ const unsigned int irr_frac_bits = 13;
+ const unsigned long irr_steps = 1 << irr_frac_bits;
+ const u64 dirr = ((u64)1) << (32 - 2);
+ /* The maximum relative difference allowed between the irrs */
+ const u64 cr = ((u64)4) << 32;
+ /* The importance ratio between the two terms in the cost function below */
+
+ unsigned int status;
+ unsigned int temp;
+ unsigned int onw_min;
+ unsigned int inw = 0, onw = 0, inw_best = 0;
+ /* number of pixels in the left stripe NOT hidden by the right stripe */
+ u64 irr_opt; /* the optimal inverse resizing ratio */
+ u64 rr_opt; /* the optimal resizing ratio = 1/irr_opt*/
+ u64 dinw; /* the misalignment between the stripes */
+ /* (measured in units of input columns) */
+ u64 difwl, difwr = 0;
+ /* The number of input columns not reflected in the output */
+ /* the resizing ratio used for the right stripe is */
+ /* left->irr and right->irr respectively */
+ u64 cost, cost_min;
+ u64 div; /* result of division */
+ bool equal_stripes = (flags & 0x1) != 0;
+ bool vertical = (flags & 0x2) != 0;
+
+ unsigned int input_m, input_f, output_m, output_f; /* parameters for upsizing by stripes */
+ unsigned int resize_coeff;
+ unsigned int downsize_coeff;
+
+ status = 0;
+
+ if (vertical) {
+ input_f = 2;
+ input_m = 8;
+ output_f = 8;
+ output_m = 2;
+ } else {
+ input_f = f_calc(input_pixelformat, 0, NULL);
+ input_m = m_calc(input_pixelformat);
+ output_f = input_m;
+ output_m = m_calc(output_pixelformat);
+ }
+ if ((input_frame_width < 4) || (output_frame_width < 4))
+ return 1;
+
+ irr_opt = div_u64((((u64)(input_frame_width - 1)) << 32),
+ (output_frame_width - 1));
+ rr_opt = div_u64((((u64)(output_frame_width - 1)) << 32),
+ (input_frame_width - 1));
+
+ if ((input_m == 0) || (output_m == 0) || (input_f == 0) || (output_f == 0)
+ || (input_frame_width < (2 * input_f))
+ || ((((u64)output_frame_width) << 32) <
+ (2 * ((((u64)output_f) << 32) + (input_f * rr_opt))))
+ || (maximal_stripe_width < output_f)
+ || ((output_frame_width <= maximal_stripe_width)
+ && (equal_stripes == 0))
+ || ((2 * maximal_stripe_width) < output_frame_width))
+ return 1;
+
+ if (output_f % output_m)
+ status += 2;
+
+ temp = truncate(0, (((u64)output_frame_width) << 32), output_m);
+ if (temp < output_frame_width) {
+ output_frame_width = temp;
+ status += 4;
+ }
+
+ pr_debug("---------------->\n"
+ "if = %d\n"
+ "im = %d\n"
+ "of = %d\n"
+ "om = %d\n"
+ "irr_opt = %llu\n"
+ "rr_opt = %llu\n"
+ "cirr = %llu\n"
+ "pixel in = %08x\n"
+ "pixel out = %08x\n"
+ "ifw = %d\n"
+ "ofwidth = %d\n",
+ input_f,
+ input_m,
+ output_f,
+ output_m,
+ irr_opt,
+ rr_opt,
+ cirr,
+ input_pixelformat,
+ output_pixelformat,
+ input_frame_width,
+ output_frame_width
+ );
+
+ if (equal_stripes) {
+ if ((irr_opt > cirr) /* overlap in the input is not requested */
+ && ((input_frame_width % (input_m << 1)) == 0)
+ && ((input_frame_width % (input_f << 1)) == 0)
+ && ((output_frame_width % (output_m << 1)) == 0)
+ && ((output_frame_width % (output_f << 1)) == 0)) {
+ /* without overlap */
+ left->input_width = right->input_width = right->input_column =
+ input_frame_width >> 1;
+ left->output_width = right->output_width = right->output_column =
+ output_frame_width >> 1;
+ left->input_column = 0;
+ left->output_column = 0;
+ div = div_u64(((((u64)irr_steps) << 32) *
+ (right->input_width - 1)), (right->output_width - 1));
+ left->irr = right->irr = truncate(0, div, 1);
+ } else { /* with overlap */
+ onw = truncate(0, (((u64)output_frame_width - 1) << 32) >> 1,
+ output_f);
+ inw = truncate(0, onw * irr_opt, input_f);
+ /* this is the maximal inw which allows the same resizing ratio */
+ /* in both stripes */
+ onw = truncate(1, (inw * rr_opt), output_f);
+ div = div_u64((((u64)(irr_steps * inw)) <<
+ 32), onw);
+ left->irr = right->irr = truncate(0, div, 1);
+ left->output_width = right->output_width =
+ output_frame_width - onw;
+ /* These are valid assignments for output_width, */
+ /* assuming output_f is a multiple of output_m */
+ div = (((u64)(left->output_width-1) * (left->irr)) << 32);
+ div = (((u64)1) << 32) + div_u64(div, irr_steps);
+
+ left->input_width = right->input_width = truncate(1, div, input_m);
+
+ div = div_u64((((u64)((right->output_width - 1) * right->irr)) <<
+ 32), irr_steps);
+ difwr = (((u64)(input_frame_width - 1 - inw)) << 32) - div;
+ div = div_u64((difwr + (((u64)input_f) << 32)), 2);
+ left->input_column = truncate(0, div, input_f);
+
+
+ /* This splits the truncated input columns evenly */
+ /* between the left and right margins */
+ right->input_column = left->input_column + inw;
+ left->output_column = 0;
+ right->output_column = onw;
+ }
+ if (left->input_width > left->output_width) {
+ if (calc_split_resize_coeffs(left->input_width,
+ left->output_width,
+ &resize_coeff,
+ &downsize_coeff) < 0)
+ return -EINVAL;
+
+ if (downsize_coeff > 0) {
+ left->irr = right->irr =
+ (downsize_coeff << 14) | resize_coeff;
+ }
+ }
+ pr_debug("inw %d, onw %d, ilw %d, ilc %d, olw %d,"
+ " irw %d, irc %d, orw %d, orc %d, "
+ "difwr %llu, lirr %u\n",
+ inw, onw, left->input_width,
+ left->input_column, left->output_width,
+ right->input_width, right->input_column,
+ right->output_width,
+ right->output_column, difwr, left->irr);
+ } else { /* independent stripes */
+ onw_min = output_frame_width - maximal_stripe_width;
+ /* onw is a multiple of output_f, in the range */
+ /* [max(output_f,output_frame_width-maximal_stripe_width),*/
+ /*min(output_frame_width-2,maximal_stripe_width)] */
+ /* definitely beyond the cost of any valid setting */
+ cost_min = (((u64)input_frame_width) << 32) + cr;
+ onw = truncate(0, ((u64)maximal_stripe_width), output_f);
+ if (output_frame_width - onw == 1)
+ onw -= output_f; /* => onw and output_frame_width-1-onw are positive */
+ inw = truncate(0, onw * irr_opt, input_f);
+ /* this is the maximal inw which allows the same resizing ratio */
+ /* in both stripes */
+ onw = truncate(1, inw * rr_opt, output_f);
+ do {
+ div = div_u64((((u64)(irr_steps * inw)) << 32), onw);
+ left->irr = truncate(0, div, 1);
+ div = div_u64((((u64)(onw * left->irr)) << 32),
+ irr_steps);
+ dinw = (((u64)inw) << 32) - div;
+
+ div = div_u64((((u64)((output_frame_width - 1 - onw) * left->irr)) <<
+ 32), irr_steps);
+
+ difwl = (((u64)(input_frame_width - 1 - inw)) << 32) - div;
+
+ cost = difwl + (((u64)(cr * dinw)) >> 32);
+
+ if (cost < cost_min) {
+ inw_best = inw;
+ cost_min = cost;
+ }
+
+ inw -= input_f;
+ onw = truncate(1, inw * rr_opt, output_f);
+ /* This is the minimal onw which allows the same resizing ratio */
+ /* in both stripes */
+ } while (onw >= onw_min);
+
+ inw = inw_best;
+ onw = truncate(1, inw * rr_opt, output_f);
+ div = div_u64((((u64)(irr_steps * inw)) << 32), onw);
+ left->irr = truncate(0, div, 1);
+
+ left->output_width = onw;
+ right->output_width = output_frame_width - onw;
+ /* These are valid assignments for output_width, */
+ /* assuming output_f is a multiple of output_m */
+ left->input_width = truncate(1, ((u64)(inw + 1)) << 32, input_m);
+ right->input_width = truncate(1, ((u64)(input_frame_width - inw)) <<
+ 32, input_m);
+
+ div = div_u64((((u64)(irr_steps * (input_frame_width - 1 - inw))) <<
+ 32), (right->output_width - 1));
+ right->irr = truncate(0, div, 1);
+ temp = truncate(0, ((u64)left->irr) * ((((u64)1) << 32) + dirr), 1);
+ if (temp < right->irr)
+ right->irr = temp;
+ div = div_u64(((u64)((right->output_width - 1) * right->irr) <<
+ 32), irr_steps);
+ difwr = (u64)(input_frame_width - 1 - inw) - div;
+
+
+ div = div_u64((difwr + (((u64)input_f) << 32)), 2);
+ left->input_column = truncate(0, div, input_f);
+
+ /* This splits the truncated input columns evenly */
+ /* between the left and right margins */
+ right->input_column = left->input_column + inw;
+ left->output_column = 0;
+ right->output_column = onw;
+ if (left->input_width > left->output_width) {
+ if (calc_split_resize_coeffs(left->input_width,
+ left->output_width,
+ &resize_coeff,
+ &downsize_coeff) < 0)
+ return -EINVAL;
+ left->irr = (downsize_coeff << 14) | resize_coeff;
+ }
+ if (right->input_width > right->output_width) {
+ if (calc_split_resize_coeffs(right->input_width,
+ right->output_width,
+ &resize_coeff,
+ &downsize_coeff) < 0)
+ return -EINVAL;
+ right->irr = (downsize_coeff << 14) | resize_coeff;
+ }
+ }
+ return status;
+}
+EXPORT_SYMBOL(ipu_calc_stripes_sizes);
diff --git a/drivers/mxc/ipu3/ipu_capture.c b/drivers/mxc/ipu3/ipu_capture.c
new file mode 100644
index 000000000000..f304c8140be4
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_capture.c
@@ -0,0 +1,816 @@
+/*
+ * Copyright 2008-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_capture.c
+ *
+ * @brief IPU capture dase functions
+ *
+ * @ingroup IPU
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "ipu_prv.h"
+#include "ipu_regs.h"
+
+/*!
+ * _ipu_csi_mclk_set
+ *
+ * @param ipu ipu handler
+ * @param pixel_clk desired pixel clock frequency in Hz
+ * @param csi csi 0 or csi 1
+ *
+ * @return Returns 0 on success or negative error code on fail
+ */
+int _ipu_csi_mclk_set(struct ipu_soc *ipu, uint32_t pixel_clk, uint32_t csi)
+{
+ uint32_t temp;
+ int32_t div_ratio;
+
+ div_ratio = (clk_get_rate(ipu->ipu_clk) / pixel_clk) - 1;
+
+ if (div_ratio > 0xFF || div_ratio < 0) {
+ dev_dbg(ipu->dev, "value of pixel_clk extends normal range\n");
+ return -EINVAL;
+ }
+
+ temp = ipu_csi_read(ipu, csi, CSI_SENS_CONF);
+ temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
+ ipu_csi_write(ipu, csi, temp |
+ (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
+ CSI_SENS_CONF);
+
+ return 0;
+}
+
+/*!
+ * ipu_csi_init_interface
+ * Sets initial values for the CSI registers.
+ * The width and height of the sensor and the actual frame size will be
+ * set to the same values.
+ * @param ipu ipu handler
+ * @param width Sensor width
+ * @param height Sensor height
+ * @param pixel_fmt pixel format
+ * @param cfg_param ipu_csi_signal_cfg_t structure
+ * @param csi csi 0 or csi 1
+ *
+ * @return 0 for success, -EINVAL for error
+ */
+int32_t
+ipu_csi_init_interface(struct ipu_soc *ipu, uint16_t width, uint16_t height,
+ uint32_t pixel_fmt, ipu_csi_signal_cfg_t cfg_param)
+{
+ uint32_t data = 0;
+ uint32_t csi = cfg_param.csi;
+
+ /* Set SENS_DATA_FORMAT bits (8, 9 and 10)
+ RGB or YUV444 is 0 which is current value in data so not set
+ explicitly
+ This is also the default value if attempts are made to set it to
+ something invalid. */
+ switch (pixel_fmt) {
+ case IPU_PIX_FMT_YUYV:
+ cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
+ break;
+ case IPU_PIX_FMT_UYVY:
+ cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
+ break;
+ case IPU_PIX_FMT_RGB24:
+ case IPU_PIX_FMT_BGR24:
+ cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
+ break;
+ case IPU_PIX_FMT_GENERIC:
+ case IPU_PIX_FMT_GENERIC_16:
+ cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+ break;
+ case IPU_PIX_FMT_RGB565:
+ cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
+ break;
+ case IPU_PIX_FMT_RGB555:
+ cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Set the CSI_SENS_CONF register remaining fields */
+ data |= cfg_param.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
+ cfg_param.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
+ cfg_param.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
+ cfg_param.Vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
+ cfg_param.Hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
+ cfg_param.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
+ cfg_param.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
+ cfg_param.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
+ cfg_param.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
+ cfg_param.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
+ cfg_param.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
+
+ _ipu_get(ipu);
+
+ mutex_lock(&ipu->mutex_lock);
+
+ ipu_csi_write(ipu, csi, data, CSI_SENS_CONF);
+
+ /* Setup sensor frame size */
+ ipu_csi_write(ipu, csi, (width - 1) | (height - 1) << 16, CSI_SENS_FRM_SIZE);
+
+ /* Set CCIR registers */
+ if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) {
+ ipu_csi_write(ipu, csi, 0x40030, CSI_CCIR_CODE_1);
+ ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
+ } else if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED) {
+ if (width == 720 && height == 625) {
+ /* PAL case */
+ /*
+ * Field0BlankEnd = 0x6, Field0BlankStart = 0x2,
+ * Field0ActiveEnd = 0x4, Field0ActiveStart = 0
+ */
+ ipu_csi_write(ipu, csi, 0x40596, CSI_CCIR_CODE_1);
+ /*
+ * Field1BlankEnd = 0x7, Field1BlankStart = 0x3,
+ * Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1
+ */
+ ipu_csi_write(ipu, csi, 0xD07DF, CSI_CCIR_CODE_2);
+
+ ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
+
+ } else if (width == 720 && height == 525) {
+ /* NTSC case */
+ /*
+ * Field0BlankEnd = 0x7, Field0BlankStart = 0x3,
+ * Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1
+ */
+ ipu_csi_write(ipu, csi, 0xD07DF, CSI_CCIR_CODE_1);
+ /*
+ * Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
+ * Field1ActiveEnd = 0x4, Field1ActiveStart = 0
+ */
+ ipu_csi_write(ipu, csi, 0x40596, CSI_CCIR_CODE_2);
+ ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
+ } else {
+ dev_err(ipu->dev, "Unsupported CCIR656 interlaced "
+ "video mode\n");
+ mutex_unlock(&ipu->mutex_lock);
+ _ipu_put(ipu);
+ return -EINVAL;
+ }
+ _ipu_csi_ccir_err_detection_enable(ipu, csi);
+ } else if ((cfg_param.clk_mode ==
+ IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR) ||
+ (cfg_param.clk_mode ==
+ IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR) ||
+ (cfg_param.clk_mode ==
+ IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR) ||
+ (cfg_param.clk_mode ==
+ IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR)) {
+ ipu_csi_write(ipu, csi, 0x40030, CSI_CCIR_CODE_1);
+ ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
+ _ipu_csi_ccir_err_detection_enable(ipu, csi);
+ } else if ((cfg_param.clk_mode == IPU_CSI_CLK_MODE_GATED_CLK) ||
+ (cfg_param.clk_mode == IPU_CSI_CLK_MODE_NONGATED_CLK)) {
+ _ipu_csi_ccir_err_detection_disable(ipu, csi);
+ }
+
+ dev_dbg(ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
+ ipu_csi_read(ipu, csi, CSI_SENS_CONF));
+ dev_dbg(ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
+ ipu_csi_read(ipu, csi, CSI_ACT_FRM_SIZE));
+
+ mutex_unlock(&ipu->mutex_lock);
+
+ _ipu_put(ipu);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_csi_init_interface);
+
+/*!
+ * ipu_csi_get_sensor_protocol
+ *
+ * @param ipu ipu handler
+ * @param csi csi 0 or csi 1
+ *
+ * @return Returns sensor protocol
+ */
+int32_t ipu_csi_get_sensor_protocol(struct ipu_soc *ipu, uint32_t csi)
+{
+ int ret;
+ _ipu_get(ipu);
+ ret = (ipu_csi_read(ipu, csi, CSI_SENS_CONF) &
+ CSI_SENS_CONF_SENS_PRTCL_MASK) >>
+ CSI_SENS_CONF_SENS_PRTCL_SHIFT;
+ _ipu_put(ipu);
+ return ret;
+}
+EXPORT_SYMBOL(ipu_csi_get_sensor_protocol);
+
+/*!
+ * ipu_csi_enable_mclk
+ *
+ * @param ipu ipu handler
+ * @param csi csi 0 or csi 1
+ * @param flag true to enable mclk, false to disable mclk
+ * @param wait true to wait 100ms make clock stable, false not wait
+ *
+ * @return Returns 0 on success
+ */
+int ipu_csi_enable_mclk(struct ipu_soc *ipu, int csi, bool flag, bool wait)
+{
+ /* Return immediately if there is no csi_clk to manage */
+ if (ipu->csi_clk[csi] == NULL)
+ return 0;
+
+ if (flag) {
+ clk_enable(ipu->csi_clk[csi]);
+ if (wait == true)
+ msleep(10);
+ } else {
+ clk_disable(ipu->csi_clk[csi]);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_csi_enable_mclk);
+
+/*!
+ * ipu_csi_get_window_size
+ *
+ * @param ipu ipu handler
+ * @param width pointer to window width
+ * @param height pointer to window height
+ * @param csi csi 0 or csi 1
+ */
+void ipu_csi_get_window_size(struct ipu_soc *ipu, uint32_t *width, uint32_t *height, uint32_t csi)
+{
+ uint32_t reg;
+
+ _ipu_get(ipu);
+
+ mutex_lock(&ipu->mutex_lock);
+
+ reg = ipu_csi_read(ipu, csi, CSI_ACT_FRM_SIZE);
+ *width = (reg & 0xFFFF) + 1;
+ *height = (reg >> 16 & 0xFFFF) + 1;
+
+ mutex_unlock(&ipu->mutex_lock);
+
+ _ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_csi_get_window_size);
+
+/*!
+ * ipu_csi_set_window_size
+ *
+ * @param ipu ipu handler
+ * @param width window width
+ * @param height window height
+ * @param csi csi 0 or csi 1
+ */
+void ipu_csi_set_window_size(struct ipu_soc *ipu, uint32_t width, uint32_t height, uint32_t csi)
+{
+ _ipu_get(ipu);
+
+ mutex_lock(&ipu->mutex_lock);
+
+ ipu_csi_write(ipu, csi, (width - 1) | (height - 1) << 16, CSI_ACT_FRM_SIZE);
+
+ mutex_unlock(&ipu->mutex_lock);
+
+ _ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_csi_set_window_size);
+
+/*!
+ * ipu_csi_set_window_pos
+ *
+ * @param ipu ipu handler
+ * @param left uint32 window x start
+ * @param top uint32 window y start
+ * @param csi csi 0 or csi 1
+ */
+void ipu_csi_set_window_pos(struct ipu_soc *ipu, uint32_t left, uint32_t top, uint32_t csi)
+{
+ uint32_t temp;
+
+ _ipu_get(ipu);
+
+ mutex_lock(&ipu->mutex_lock);
+
+ temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
+ temp &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
+ temp |= ((top << CSI_VSC_SHIFT) | (left << CSI_HSC_SHIFT));
+ ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
+
+ mutex_unlock(&ipu->mutex_lock);
+
+ _ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_csi_set_window_pos);
+
+/*!
+ * _ipu_csi_horizontal_downsize_enable
+ * Enable horizontal downsizing(decimation) by 2.
+ *
+ * @param ipu ipu handler
+ * @param csi csi 0 or csi 1
+ */
+void _ipu_csi_horizontal_downsize_enable(struct ipu_soc *ipu, uint32_t csi)
+{
+ uint32_t temp;
+
+ temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
+ temp |= CSI_HORI_DOWNSIZE_EN;
+ ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
+}
+
+/*!
+ * _ipu_csi_horizontal_downsize_disable
+ * Disable horizontal downsizing(decimation) by 2.
+ *
+ * @param ipu ipu handler
+ * @param csi csi 0 or csi 1
+ */
+void _ipu_csi_horizontal_downsize_disable(struct ipu_soc *ipu, uint32_t csi)
+{
+ uint32_t temp;
+
+ temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
+ temp &= ~CSI_HORI_DOWNSIZE_EN;
+ ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
+}
+
+/*!
+ * _ipu_csi_vertical_downsize_enable
+ * Enable vertical downsizing(decimation) by 2.
+ *
+ * @param ipu ipu handler
+ * @param csi csi 0 or csi 1
+ */
+void _ipu_csi_vertical_downsize_enable(struct ipu_soc *ipu, uint32_t csi)
+{
+ uint32_t temp;
+
+ temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
+ temp |= CSI_VERT_DOWNSIZE_EN;
+ ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
+}
+
+/*!
+ * _ipu_csi_vertical_downsize_disable
+ * Disable vertical downsizing(decimation) by 2.
+ *
+ * @param ipu ipu handler
+ * @param csi csi 0 or csi 1
+ */
+void _ipu_csi_vertical_downsize_disable(struct ipu_soc *ipu, uint32_t csi)
+{
+ uint32_t temp;
+
+ temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
+ temp &= ~CSI_VERT_DOWNSIZE_EN;
+ ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
+}
+
+/*!
+ * _ipu_csi_set_test_generator
+ *
+ * @param ipu ipu handler
+ * @param active 1 for active and 0 for inactive
+ * @param r_value red value for the generated pattern of even pixel
+ * @param g_value green value for the generated pattern of even
+ * pixel
+ * @param b_value blue value for the generated pattern of even pixel
+ * @param pixel_clk desired pixel clock frequency in Hz
+ * @param csi csi 0 or csi 1
+ */
+void _ipu_csi_set_test_generator(struct ipu_soc *ipu, bool active, uint32_t r_value,
+ uint32_t g_value, uint32_t b_value, uint32_t pix_clk, uint32_t csi)
+{
+ uint32_t temp;
+
+ temp = ipu_csi_read(ipu, csi, CSI_TST_CTRL);
+
+ if (active == false) {
+ temp &= ~CSI_TEST_GEN_MODE_EN;
+ ipu_csi_write(ipu, csi, temp, CSI_TST_CTRL);
+ } else {
+ /* Set sensb_mclk div_ratio*/
+ _ipu_csi_mclk_set(ipu, pix_clk, csi);
+
+ temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
+ CSI_TEST_GEN_B_MASK);
+ temp |= CSI_TEST_GEN_MODE_EN;
+ temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
+ (g_value << CSI_TEST_GEN_G_SHIFT) |
+ (b_value << CSI_TEST_GEN_B_SHIFT);
+ ipu_csi_write(ipu, csi, temp, CSI_TST_CTRL);
+ }
+}
+
+/*!
+ * _ipu_csi_ccir_err_detection_en
+ * Enable error detection and correction for
+ * CCIR interlaced mode with protection bit.
+ *
+ * @param ipu ipu handler
+ * @param csi csi 0 or csi 1
+ */
+void _ipu_csi_ccir_err_detection_enable(struct ipu_soc *ipu, uint32_t csi)
+{
+ uint32_t temp;
+
+ temp = ipu_csi_read(ipu, csi, CSI_CCIR_CODE_1);
+ temp |= CSI_CCIR_ERR_DET_EN;
+ ipu_csi_write(ipu, csi, temp, CSI_CCIR_CODE_1);
+
+}
+
+/*!
+ * _ipu_csi_ccir_err_detection_disable
+ * Disable error detection and correction for
+ * CCIR interlaced mode with protection bit.
+ *
+ * @param ipu ipu handler
+ * @param csi csi 0 or csi 1
+ */
+void _ipu_csi_ccir_err_detection_disable(struct ipu_soc *ipu, uint32_t csi)
+{
+ uint32_t temp;
+
+ temp = ipu_csi_read(ipu, csi, CSI_CCIR_CODE_1);
+ temp &= ~CSI_CCIR_ERR_DET_EN;
+ ipu_csi_write(ipu, csi, temp, CSI_CCIR_CODE_1);
+
+}
+
+/*!
+ * _ipu_csi_set_mipi_di
+ *
+ * @param ipu ipu handler
+ * @param num MIPI data identifier 0-3 handled by CSI
+ * @param di_val data identifier value
+ * @param csi csi 0 or csi 1
+ *
+ * @return Returns 0 on success or negative error code on fail
+ */
+int _ipu_csi_set_mipi_di(struct ipu_soc *ipu, uint32_t num, uint32_t di_val, uint32_t csi)
+{
+ uint32_t temp;
+ int retval = 0;
+
+ if (di_val > 0xFFL) {
+ retval = -EINVAL;
+ goto err;
+ }
+
+ temp = ipu_csi_read(ipu, csi, CSI_MIPI_DI);
+
+ switch (num) {
+ case IPU_CSI_MIPI_DI0:
+ temp &= ~CSI_MIPI_DI0_MASK;
+ temp |= (di_val << CSI_MIPI_DI0_SHIFT);
+ ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
+ break;
+ case IPU_CSI_MIPI_DI1:
+ temp &= ~CSI_MIPI_DI1_MASK;
+ temp |= (di_val << CSI_MIPI_DI1_SHIFT);
+ ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
+ break;
+ case IPU_CSI_MIPI_DI2:
+ temp &= ~CSI_MIPI_DI2_MASK;
+ temp |= (di_val << CSI_MIPI_DI2_SHIFT);
+ ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
+ break;
+ case IPU_CSI_MIPI_DI3:
+ temp &= ~CSI_MIPI_DI3_MASK;
+ temp |= (di_val << CSI_MIPI_DI3_SHIFT);
+ ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
+ break;
+ default:
+ retval = -EINVAL;
+ }
+
+err:
+ return retval;
+}
+
+/*!
+ * _ipu_csi_set_skip_isp
+ *
+ * @param ipu ipu handler
+ * @param skip select frames to be skipped and set the
+ * correspond bits to 1
+ * @param max_ratio number of frames in a skipping set and the
+ * maximum value of max_ratio is 5
+ * @param csi csi 0 or csi 1
+ *
+ * @return Returns 0 on success or negative error code on fail
+ */
+int _ipu_csi_set_skip_isp(struct ipu_soc *ipu, uint32_t skip, uint32_t max_ratio, uint32_t csi)
+{
+ uint32_t temp;
+ int retval = 0;
+
+ if (max_ratio > 5) {
+ retval = -EINVAL;
+ goto err;
+ }
+
+ temp = ipu_csi_read(ipu, csi, CSI_SKIP);
+ temp &= ~(CSI_MAX_RATIO_SKIP_ISP_MASK | CSI_SKIP_ISP_MASK);
+ temp |= (max_ratio << CSI_MAX_RATIO_SKIP_ISP_SHIFT) |
+ (skip << CSI_SKIP_ISP_SHIFT);
+ ipu_csi_write(ipu, csi, temp, CSI_SKIP);
+
+err:
+ return retval;
+}
+
+/*!
+ * _ipu_csi_set_skip_smfc
+ *
+ * @param ipu ipu handler
+ * @param skip select frames to be skipped and set the
+ * correspond bits to 1
+ * @param max_ratio number of frames in a skipping set and the
+ * maximum value of max_ratio is 5
+ * @param id csi to smfc skipping id
+ * @param csi csi 0 or csi 1
+ *
+ * @return Returns 0 on success or negative error code on fail
+ */
+int _ipu_csi_set_skip_smfc(struct ipu_soc *ipu, uint32_t skip,
+ uint32_t max_ratio, uint32_t id, uint32_t csi)
+{
+ uint32_t temp;
+ int retval = 0;
+
+ if (max_ratio > 5 || id > 3) {
+ retval = -EINVAL;
+ goto err;
+ }
+
+ temp = ipu_csi_read(ipu, csi, CSI_SKIP);
+ temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
+ CSI_SKIP_SMFC_MASK);
+ temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
+ (id << CSI_ID_2_SKIP_SHIFT) |
+ (skip << CSI_SKIP_SMFC_SHIFT);
+ ipu_csi_write(ipu, csi, temp, CSI_SKIP);
+
+err:
+ return retval;
+}
+
+/*!
+ * _ipu_smfc_init
+ * Map CSI frames to IDMAC channels.
+ *
+ * @param ipu ipu handler
+ * @param channel IDMAC channel 0-3
+ * @param mipi_id mipi id number 0-3
+ * @param csi csi0 or csi1
+ */
+void _ipu_smfc_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t mipi_id, uint32_t csi)
+{
+ uint32_t temp;
+
+ temp = ipu_smfc_read(ipu, SMFC_MAP);
+
+ switch (channel) {
+ case CSI_MEM0:
+ temp &= ~SMFC_MAP_CH0_MASK;
+ temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH0_SHIFT;
+ break;
+ case CSI_MEM1:
+ temp &= ~SMFC_MAP_CH1_MASK;
+ temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH1_SHIFT;
+ break;
+ case CSI_MEM2:
+ temp &= ~SMFC_MAP_CH2_MASK;
+ temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH2_SHIFT;
+ break;
+ case CSI_MEM3:
+ temp &= ~SMFC_MAP_CH3_MASK;
+ temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH3_SHIFT;
+ break;
+ default:
+ return;
+ }
+
+ ipu_smfc_write(ipu, temp, SMFC_MAP);
+}
+
+/*!
+ * _ipu_smfc_set_wmc
+ * Caution: The number of required channels, the enabled channels
+ * and the FIFO size per channel are configured restrictedly.
+ *
+ * @param ipu ipu handler
+ * @param channel IDMAC channel 0-3
+ * @param set set 1 or clear 0
+ * @param level water mark level when FIFO is on the
+ * relative size
+ */
+void _ipu_smfc_set_wmc(struct ipu_soc *ipu, ipu_channel_t channel, bool set, uint32_t level)
+{
+ uint32_t temp;
+
+ temp = ipu_smfc_read(ipu, SMFC_WMC);
+
+ switch (channel) {
+ case CSI_MEM0:
+ if (set == true) {
+ temp &= ~SMFC_WM0_SET_MASK;
+ temp |= level << SMFC_WM0_SET_SHIFT;
+ } else {
+ temp &= ~SMFC_WM0_CLR_MASK;
+ temp |= level << SMFC_WM0_CLR_SHIFT;
+ }
+ break;
+ case CSI_MEM1:
+ if (set == true) {
+ temp &= ~SMFC_WM1_SET_MASK;
+ temp |= level << SMFC_WM1_SET_SHIFT;
+ } else {
+ temp &= ~SMFC_WM1_CLR_MASK;
+ temp |= level << SMFC_WM1_CLR_SHIFT;
+ }
+ break;
+ case CSI_MEM2:
+ if (set == true) {
+ temp &= ~SMFC_WM2_SET_MASK;
+ temp |= level << SMFC_WM2_SET_SHIFT;
+ } else {
+ temp &= ~SMFC_WM2_CLR_MASK;
+ temp |= level << SMFC_WM2_CLR_SHIFT;
+ }
+ break;
+ case CSI_MEM3:
+ if (set == true) {
+ temp &= ~SMFC_WM3_SET_MASK;
+ temp |= level << SMFC_WM3_SET_SHIFT;
+ } else {
+ temp &= ~SMFC_WM3_CLR_MASK;
+ temp |= level << SMFC_WM3_CLR_SHIFT;
+ }
+ break;
+ default:
+ return;
+ }
+
+ ipu_smfc_write(ipu, temp, SMFC_WMC);
+}
+
+/*!
+ * _ipu_smfc_set_burst_size
+ *
+ * @param ipu ipu handler
+ * @param channel IDMAC channel 0-3
+ * @param bs burst size of IDMAC channel,
+ * the value programmed here shoud be BURST_SIZE-1
+ */
+void _ipu_smfc_set_burst_size(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t bs)
+{
+ uint32_t temp;
+
+ temp = ipu_smfc_read(ipu, SMFC_BS);
+
+ switch (channel) {
+ case CSI_MEM0:
+ temp &= ~SMFC_BS0_MASK;
+ temp |= bs << SMFC_BS0_SHIFT;
+ break;
+ case CSI_MEM1:
+ temp &= ~SMFC_BS1_MASK;
+ temp |= bs << SMFC_BS1_SHIFT;
+ break;
+ case CSI_MEM2:
+ temp &= ~SMFC_BS2_MASK;
+ temp |= bs << SMFC_BS2_SHIFT;
+ break;
+ case CSI_MEM3:
+ temp &= ~SMFC_BS3_MASK;
+ temp |= bs << SMFC_BS3_SHIFT;
+ break;
+ default:
+ return;
+ }
+
+ ipu_smfc_write(ipu, temp, SMFC_BS);
+}
+
+/*!
+ * _ipu_csi_init
+ *
+ * @param ipu ipu handler
+ * @param channel IDMAC channel
+ * @param csi csi 0 or csi 1
+ *
+ * @return Returns 0 on success or negative error code on fail
+ */
+int _ipu_csi_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t csi)
+{
+ uint32_t csi_sens_conf, csi_dest;
+ int retval = 0;
+
+ switch (channel) {
+ case CSI_MEM0:
+ case CSI_MEM1:
+ case CSI_MEM2:
+ case CSI_MEM3:
+ csi_dest = CSI_DATA_DEST_IDMAC;
+ break;
+ case CSI_PRP_ENC_MEM:
+ case CSI_PRP_VF_MEM:
+ csi_dest = CSI_DATA_DEST_IC;
+ break;
+ default:
+ retval = -EINVAL;
+ goto err;
+ }
+
+ csi_sens_conf = ipu_csi_read(ipu, csi, CSI_SENS_CONF);
+ csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
+ ipu_csi_write(ipu, csi, csi_sens_conf | (csi_dest <<
+ CSI_SENS_CONF_DATA_DEST_SHIFT), CSI_SENS_CONF);
+err:
+ return retval;
+}
+
+/*!
+ * csi_irq_handler
+ *
+ * @param irq interrupt id
+ * @param dev_id pointer to ipu handler
+ *
+ * @return Returns if irq is handled
+ */
+static irqreturn_t csi_irq_handler(int irq, void *dev_id)
+{
+ struct ipu_soc *ipu = dev_id;
+ struct completion *comp = &ipu->csi_comp;
+
+ complete(comp);
+ return IRQ_HANDLED;
+}
+
+/*!
+ * _ipu_csi_wait4eof
+ *
+ * @param ipu ipu handler
+ * @param channel IDMAC channel
+ *
+ */
+void _ipu_csi_wait4eof(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+ int ret;
+ int irq = 0;
+
+ if (channel == CSI_MEM0)
+ irq = IPU_IRQ_CSI0_OUT_EOF;
+ else if (channel == CSI_MEM1)
+ irq = IPU_IRQ_CSI1_OUT_EOF;
+ else if (channel == CSI_MEM2)
+ irq = IPU_IRQ_CSI2_OUT_EOF;
+ else if (channel == CSI_MEM3)
+ irq = IPU_IRQ_CSI3_OUT_EOF;
+ else if (channel == CSI_PRP_ENC_MEM)
+ irq = IPU_IRQ_PRP_ENC_OUT_EOF;
+ else if (channel == CSI_PRP_VF_MEM)
+ irq = IPU_IRQ_PRP_VF_OUT_EOF;
+ else{
+ dev_err(ipu->dev, "Not a CSI channel\n");
+ return;
+ }
+
+ init_completion(&ipu->csi_comp);
+ ret = ipu_request_irq(ipu, irq, csi_irq_handler, 0, NULL, ipu);
+ if (ret < 0) {
+ dev_err(ipu->dev, "CSI irq %d in use\n", irq);
+ return;
+ }
+ ret = wait_for_completion_timeout(&ipu->csi_comp, msecs_to_jiffies(500));
+ ipu_free_irq(ipu, irq, ipu);
+ dev_dbg(ipu->dev, "CSI stop timeout - %d * 10ms\n", 5 - ret);
+}
diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c
new file mode 100644
index 000000000000..c5b82f78421f
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_common.c
@@ -0,0 +1,3494 @@
+/*
+ * Copyright 2005-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_common.c
+ *
+ * @brief This file contains the IPU driver common API functions.
+ *
+ * @ingroup IPU
+ */
+#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/cacheflush.h>
+
+#include "ipu_param_mem.h"
+#include "ipu_regs.h"
+
+static struct ipu_soc ipu_array[MXC_IPU_MAX_NUM];
+
+/* Static functions */
+static irqreturn_t ipu_sync_irq_handler(int irq, void *desc);
+static irqreturn_t ipu_err_irq_handler(int irq, void *desc);
+
+static inline uint32_t channel_2_dma(ipu_channel_t ch, ipu_buffer_t type)
+{
+ return ((uint32_t) ch >> (6 * type)) & 0x3F;
+};
+
+static inline int _ipu_is_ic_chan(uint32_t dma_chan)
+{
+ return (((dma_chan >= 11) && (dma_chan <= 22) && (dma_chan != 17) &&
+ (dma_chan != 18)));
+}
+
+static inline int _ipu_is_vdi_out_chan(uint32_t dma_chan)
+{
+ return (dma_chan == 5);
+}
+
+static inline int _ipu_is_ic_graphic_chan(uint32_t dma_chan)
+{
+ return (dma_chan == 14 || dma_chan == 15);
+}
+
+/* Either DP BG or DP FG can be graphic window */
+static inline int _ipu_is_dp_graphic_chan(uint32_t dma_chan)
+{
+ return (dma_chan == 23 || dma_chan == 27);
+}
+
+static inline int _ipu_is_irt_chan(uint32_t dma_chan)
+{
+ return ((dma_chan >= 45) && (dma_chan <= 50));
+}
+
+static inline int _ipu_is_dmfc_chan(uint32_t dma_chan)
+{
+ return ((dma_chan >= 23) && (dma_chan <= 29));
+}
+
+static inline int _ipu_is_trb_chan(struct ipu_soc *ipu, uint32_t dma_chan)
+{
+ return (((dma_chan == 8) || (dma_chan == 9) ||
+ (dma_chan == 10) || (dma_chan == 13) ||
+ (dma_chan == 21) || (dma_chan == 23) ||
+ (dma_chan == 27) || (dma_chan == 28)) &&
+ (ipu->devtype >= IPUv3EX));
+}
+
+/*
+ * We usually use IDMAC 23 as full plane and IDMAC 27 as partial
+ * plane.
+ * IDMAC 23/24/28/41 can drive a display respectively - primary
+ * IDMAC 27 depends on IDMAC 23 - nonprimary
+ */
+static inline int _ipu_is_primary_disp_chan(uint32_t dma_chan)
+{
+ return ((dma_chan == 23) || (dma_chan == 24) ||
+ (dma_chan == 28) || (dma_chan == 41));
+}
+
+static inline int _ipu_is_sync_irq(uint32_t irq)
+{
+ /* sync interrupt register number */
+ int reg_num = irq / 32 + 1;
+
+ return ((reg_num == 1) || (reg_num == 2) || (reg_num == 3) ||
+ (reg_num == 4) || (reg_num == 7) || (reg_num == 8) ||
+ (reg_num == 11) || (reg_num == 12) || (reg_num == 13) ||
+ (reg_num == 14) || (reg_num == 15));
+}
+
+static inline uint32_t tri_cur_buf_mask(uint32_t dma_chan)
+{
+ uint32_t mask = 1UL << ((dma_chan * 2) & 0x1F);
+
+ return mask * 3;
+}
+
+static inline uint32_t tri_cur_buf_shift(uint32_t dma_chan)
+{
+ uint32_t mask = 1UL << ((dma_chan * 2) & 0x1F);
+
+ return ffs(mask) - 1;
+}
+
+#define idma_is_valid(ch) ((ch) != NO_DMA)
+#define idma_mask(ch) (idma_is_valid(ch) ? (1UL << ((ch) & 0x1F)) : 0)
+
+static inline bool idma_is_set(struct ipu_soc *ipu, uint32_t reg, uint32_t dma)
+{
+ return !!(ipu_idmac_read(ipu, reg) & idma_mask(dma));
+}
+
+static int ipu_clk_setup_enable(struct ipu_soc *ipu)
+{
+ char pixel_clk[11];
+ char pixel_clk_sel[15];
+ char pixel_clk_div[15];
+ char pixel_clk_parent0[5];
+ char pixel_clk_parent1[9];
+ char *pixel_clk_parents[2];
+ char di_clk[4];
+ char di_clk_sel[8];
+ struct clk *clk;
+ unsigned int di;
+ unsigned int ipu_id; /* for clk naming */
+ int ret;
+
+ dev_dbg(ipu->dev, "ipu_clk = %lu\n", clk_get_rate(ipu->ipu_clk));
+
+ ipu_id = ipu->id + 1;
+
+ pixel_clk_parents[0] = pixel_clk_parent0;
+ pixel_clk_parents[1] = pixel_clk_parent1;
+
+ for (di = 0; di < 2; di++) {
+ snprintf(pixel_clk_sel, sizeof(pixel_clk_sel),
+ "ipu%u_pclk%u_sel", ipu_id, di);
+ snprintf(pixel_clk_parent0, sizeof(pixel_clk_parent0),
+ "ipu%u", ipu_id);
+ snprintf(pixel_clk_parent1, sizeof(pixel_clk_parent1),
+ "ipu%u_di%u", ipu_id, di);
+ clk = clk_register_mux_pix_clk(ipu->dev, pixel_clk_sel,
+ (const char **)pixel_clk_parents,
+ ARRAY_SIZE(pixel_clk_parents),
+ 0, ipu->id, di, 0);
+ if (IS_ERR(clk)) {
+ dev_err(ipu->dev, "di%u mux clk register failed\n", di);
+ return PTR_ERR(clk);
+ }
+ ipu->pixel_clk_sel[di] = clk;
+
+ snprintf(pixel_clk_div, sizeof(pixel_clk_div),
+ "ipu%u_pclk%u_div", ipu_id, di);
+ clk = clk_register_div_pix_clk(ipu->dev, pixel_clk_div,
+ pixel_clk_sel, 0, ipu->id, di, 0);
+ if (IS_ERR(clk)) {
+ dev_err(ipu->dev, "di%u div clk register failed\n", di);
+ return PTR_ERR(clk);
+ }
+
+ snprintf(pixel_clk, sizeof(pixel_clk),
+ "ipu%u_pclk%u", ipu_id, di);
+ ipu->pixel_clk[di] = clk_register_gate_pix_clk(ipu->dev,
+ pixel_clk, pixel_clk_div,
+ CLK_SET_RATE_PARENT, ipu->id, di, 0);
+ if (IS_ERR(ipu->pixel_clk[di])) {
+ dev_err(ipu->dev,
+ "di%u gate clk register failed\n", di);
+ return PTR_ERR(ipu->pixel_clk[di]);
+ }
+
+ ret = clk_set_parent(ipu->pixel_clk_sel[di], ipu->ipu_clk);
+ if (ret) {
+ dev_err(ipu->dev, "pixel clk set parent failed\n");
+ return ret;
+ }
+
+ snprintf(di_clk, sizeof(di_clk), "di%u", di);
+ ipu->di_clk[di] = devm_clk_get(ipu->dev, di_clk);
+ if (IS_ERR(ipu->di_clk[di])) {
+ dev_err(ipu->dev, "di%u clk get failed\n", di);
+ return PTR_ERR(ipu->di_clk[di]);
+ }
+
+ snprintf(di_clk_sel, sizeof(di_clk_sel), "di%u_sel", di);
+ ipu->di_clk_sel[di] = devm_clk_get(ipu->dev, di_clk_sel);
+ if (IS_ERR(ipu->di_clk_sel[di])) {
+ dev_err(ipu->dev, "di%u sel clk get failed\n", di);
+ return PTR_ERR(ipu->di_clk_sel[di]);
+ }
+ }
+
+ return 0;
+}
+
+static int ipu_mem_reset(struct ipu_soc *ipu)
+{
+ int timeout = 1000;
+
+ ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST);
+
+ while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) {
+ if (!timeout--)
+ return -ETIME;
+ msleep(1);
+ }
+
+ return 0;
+}
+
+struct ipu_soc *ipu_get_soc(int id)
+{
+ if (id >= MXC_IPU_MAX_NUM)
+ return ERR_PTR(-ENODEV);
+ else if (!ipu_array[id].online)
+ return ERR_PTR(-ENODEV);
+ else
+ return &(ipu_array[id]);
+}
+EXPORT_SYMBOL_GPL(ipu_get_soc);
+
+void _ipu_get(struct ipu_soc *ipu)
+{
+ int ret;
+
+ ret = clk_enable(ipu->ipu_clk);
+ if (ret < 0)
+ BUG();
+}
+
+void _ipu_put(struct ipu_soc *ipu)
+{
+ clk_disable(ipu->ipu_clk);
+}
+
+void ipu_disable_hsp_clk(struct ipu_soc *ipu)
+{
+ _ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_disable_hsp_clk);
+
+struct ipu_devtype {
+ const char *name;
+ unsigned long cm_ofs;
+ unsigned long idmac_ofs;
+ unsigned long ic_ofs;
+ unsigned long csi0_ofs;
+ unsigned long csi1_ofs;
+ unsigned long di0_ofs;
+ unsigned long di1_ofs;
+ unsigned long smfc_ofs;
+ unsigned long dc_ofs;
+ unsigned long dmfc_ofs;
+ unsigned long vdi_ofs;
+ unsigned long cpmem_ofs;
+ unsigned long srm_ofs;
+ unsigned long tpm_ofs;
+ unsigned long dc_tmpl_ofs;
+ enum ipuv3_type type;
+ bool idmac_used_bufs_present;
+};
+
+struct ipu_platform_type {
+ struct ipu_devtype devtype;
+ unsigned int ch0123_axi;
+ unsigned int ch23_axi;
+ unsigned int ch27_axi;
+ unsigned int ch28_axi;
+ unsigned int normal_axi;
+ bool smfc_idmac_12bit_3planar_bs_fixup; /* workaround little stripes */
+ bool idmac_used_bufs_en_r;
+ bool idmac_used_bufs_en_w;
+ unsigned int idmac_used_bufs_max_r;
+ unsigned int idmac_used_bufs_max_w;
+};
+
+static struct ipu_platform_type ipu_type_imx51 = {
+ .devtype = {
+ .name = "IPUv3EX",
+ .cm_ofs = 0x1E000000,
+ .idmac_ofs = 0x1E008000,
+ .ic_ofs = 0x1E020000,
+ .csi0_ofs = 0x1E030000,
+ .csi1_ofs = 0x1E038000,
+ .di0_ofs = 0x1E040000,
+ .di1_ofs = 0x1E048000,
+ .smfc_ofs = 0x1E050000,
+ .dc_ofs = 0x1E058000,
+ .dmfc_ofs = 0x1E060000,
+ .vdi_ofs = 0x1E068000,
+ .cpmem_ofs = 0x1F000000,
+ .srm_ofs = 0x1F040000,
+ .tpm_ofs = 0x1F060000,
+ .dc_tmpl_ofs = 0x1F080000,
+ .type = IPUv3EX,
+ .idmac_used_bufs_present = false,
+ },
+ .ch0123_axi = 1,
+ .ch23_axi = 1,
+ .ch23_axi = 1,
+ .ch27_axi = 1,
+ .ch28_axi = 1,
+ .normal_axi = 0,
+ .smfc_idmac_12bit_3planar_bs_fixup = false,
+};
+
+static struct ipu_platform_type ipu_type_imx53 = {
+ .devtype = {
+ .name = "IPUv3M",
+ .cm_ofs = 0x06000000,
+ .idmac_ofs = 0x06008000,
+ .ic_ofs = 0x06020000,
+ .csi0_ofs = 0x06030000,
+ .csi1_ofs = 0x06038000,
+ .di0_ofs = 0x06040000,
+ .di1_ofs = 0x06048000,
+ .smfc_ofs = 0x06050000,
+ .dc_ofs = 0x06058000,
+ .dmfc_ofs = 0x06060000,
+ .vdi_ofs = 0x06068000,
+ .cpmem_ofs = 0x07000000,
+ .srm_ofs = 0x07040000,
+ .tpm_ofs = 0x07060000,
+ .dc_tmpl_ofs = 0x07080000,
+ .type = IPUv3M,
+ .idmac_used_bufs_present = true,
+ },
+ .ch0123_axi = 1,
+ .ch23_axi = 1,
+ .ch27_axi = 1,
+ .ch28_axi = 1,
+ .normal_axi = 0,
+ .idmac_used_bufs_en_r = false,
+ .idmac_used_bufs_en_w = false,
+ .smfc_idmac_12bit_3planar_bs_fixup = false,
+};
+
+static struct ipu_platform_type ipu_type_imx6q = {
+ .devtype = {
+ .name = "IPUv3H",
+ .cm_ofs = 0x00200000,
+ .idmac_ofs = 0x00208000,
+ .ic_ofs = 0x00220000,
+ .csi0_ofs = 0x00230000,
+ .csi1_ofs = 0x00238000,
+ .di0_ofs = 0x00240000,
+ .di1_ofs = 0x00248000,
+ .smfc_ofs = 0x00250000,
+ .dc_ofs = 0x00258000,
+ .dmfc_ofs = 0x00260000,
+ .vdi_ofs = 0x00268000,
+ .cpmem_ofs = 0x00300000,
+ .srm_ofs = 0x00340000,
+ .tpm_ofs = 0x00360000,
+ .dc_tmpl_ofs = 0x00380000,
+ .type = IPUv3H,
+ .idmac_used_bufs_present = true,
+ },
+ .ch0123_axi = 0,
+ .ch23_axi = 0,
+ .ch27_axi = 0,
+ .ch28_axi = 0,
+ .normal_axi = 1,
+ .idmac_used_bufs_en_r = false,
+ .idmac_used_bufs_en_w = false,
+ .smfc_idmac_12bit_3planar_bs_fixup = false,
+};
+
+static struct ipu_platform_type ipu_type_imx6qp = {
+ .devtype = {
+ .name = "IPUv3H",
+ .cm_ofs = 0x00200000,
+ .idmac_ofs = 0x00208000,
+ .ic_ofs = 0x00220000,
+ .csi0_ofs = 0x00230000,
+ .csi1_ofs = 0x00238000,
+ .di0_ofs = 0x00240000,
+ .di1_ofs = 0x00248000,
+ .smfc_ofs = 0x00250000,
+ .dc_ofs = 0x00258000,
+ .dmfc_ofs = 0x00260000,
+ .vdi_ofs = 0x00268000,
+ .cpmem_ofs = 0x00300000,
+ .srm_ofs = 0x00340000,
+ .tpm_ofs = 0x00360000,
+ .dc_tmpl_ofs = 0x00380000,
+ .type = IPUv3H,
+ .idmac_used_bufs_present = true,
+ },
+ .ch0123_axi = 0,
+ .ch23_axi = 0,
+ .ch27_axi = 2,
+ .ch28_axi = 3,
+ .normal_axi = 1,
+ .idmac_used_bufs_en_r = true,
+ .idmac_used_bufs_en_w = true,
+ .idmac_used_bufs_max_r = 0x3,
+ .idmac_used_bufs_max_w = 0x3,
+ .smfc_idmac_12bit_3planar_bs_fixup = true,
+ };
+
+static const struct of_device_id imx_ipuv3_dt_ids[] = {
+ { .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, },
+ { .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, },
+ { .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
+ { .compatible = "fsl,imx6qp-ipu", .data = &ipu_type_imx6qp, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_ipuv3_dt_ids);
+
+/*!
+ * This function is called by the driver framework to initialize the IPU
+ * hardware.
+ *
+ * @param dev The device structure for the IPU passed in by the
+ * driver framework.
+ *
+ * @return Returns 0 on success or negative error code on error
+ */
+static int ipu_probe(struct platform_device *pdev)
+{
+ struct ipu_soc *ipu;
+ struct resource *res;
+ unsigned long ipu_base;
+ const struct of_device_id *of_id =
+ of_match_device(imx_ipuv3_dt_ids, &pdev->dev);
+ const struct ipu_platform_type *iputype = of_id->data;
+ const struct ipu_devtype *devtype = &iputype->devtype;
+ int ret = 0, id;
+ u32 bypass_reset, reg;
+
+ dev_dbg(&pdev->dev, "<%s>\n", __func__);
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "bypass_reset", &bypass_reset);
+ if (ret < 0) {
+ dev_dbg(&pdev->dev, "can not get bypass_reset\n");
+ return ret;
+ }
+
+ id = of_alias_get_id(pdev->dev.of_node, "ipu");
+ if (id < 0) {
+ dev_dbg(&pdev->dev, "can not get alias id\n");
+ return id;
+ }
+
+ ipu = &ipu_array[id];
+ memset(ipu, 0, sizeof(struct ipu_soc));
+ ipu->bypass_reset = (bool)bypass_reset;
+ ipu->dev = &pdev->dev;
+ ipu->id = id;
+ ipu->devtype = devtype->type;
+ ipu->ch0123_axi = iputype->ch0123_axi;
+ ipu->ch23_axi = iputype->ch23_axi;
+ ipu->ch27_axi = iputype->ch27_axi;
+ ipu->ch28_axi = iputype->ch28_axi;
+ ipu->normal_axi = iputype->normal_axi;
+ ipu->smfc_idmac_12bit_3planar_bs_fixup =
+ iputype->smfc_idmac_12bit_3planar_bs_fixup;
+ spin_lock_init(&ipu->int_reg_spin_lock);
+ spin_lock_init(&ipu->rdy_reg_spin_lock);
+ mutex_init(&ipu->mutex_lock);
+
+ dev_dbg(&pdev->dev, "revision is %s\n", devtype->name);
+
+ ipu->irq_sync = platform_get_irq(pdev, 0);
+ ipu->irq_err = platform_get_irq(pdev, 1);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res || ipu->irq_sync < 0 || ipu->irq_err < 0) {
+ dev_err(&pdev->dev, "can't get device resources\n");
+ return -ENODEV;
+ }
+
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), pdev->name))
+ return -EBUSY;
+
+ ret = devm_request_irq(&pdev->dev, ipu->irq_sync,
+ ipu_sync_irq_handler, 0, pdev->name, ipu);
+ if (ret) {
+ dev_err(ipu->dev, "request SYNC interrupt failed\n");
+ return ret;
+ }
+ ret = devm_request_irq(&pdev->dev, ipu->irq_err,
+ ipu_err_irq_handler, 0, pdev->name, ipu);
+ if (ret) {
+ dev_err(ipu->dev, "request ERR interrupt failed\n");
+ return ret;
+ }
+
+ ipu_base = res->start;
+
+ ipu->cm_reg = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->cm_ofs, PAGE_SIZE);
+ ipu->ic_reg = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->ic_ofs, PAGE_SIZE);
+ ipu->idmac_reg = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->idmac_ofs, PAGE_SIZE);
+ /* DP Registers are accessed thru the SRM */
+ ipu->dp_reg = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->srm_ofs, PAGE_SIZE);
+ ipu->dc_reg = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->dc_ofs, PAGE_SIZE);
+ ipu->dmfc_reg = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->dmfc_ofs, PAGE_SIZE);
+ ipu->di_reg[0] = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->di0_ofs, PAGE_SIZE);
+ ipu->di_reg[1] = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->di1_ofs, PAGE_SIZE);
+ ipu->smfc_reg = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->smfc_ofs, PAGE_SIZE);
+ ipu->csi_reg[0] = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->csi0_ofs, PAGE_SIZE);
+ ipu->csi_reg[1] = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->csi1_ofs, PAGE_SIZE);
+ ipu->cpmem_base = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->cpmem_ofs, SZ_128K);
+ ipu->tpmem_base = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->tpm_ofs, SZ_64K);
+ ipu->dc_tmpl_reg = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->dc_tmpl_ofs, SZ_128K);
+ ipu->vdi_reg = devm_ioremap(&pdev->dev,
+ ipu_base + devtype->vdi_ofs, PAGE_SIZE);
+ if (!ipu->cm_reg || !ipu->ic_reg || !ipu->idmac_reg ||
+ !ipu->dp_reg || !ipu->dc_reg || !ipu->dmfc_reg ||
+ !ipu->di_reg[0] || !ipu->di_reg[1] || !ipu->smfc_reg ||
+ !ipu->csi_reg[0] || !ipu->csi_reg[1] || !ipu->cpmem_base ||
+ !ipu->tpmem_base || !ipu->dc_tmpl_reg || !ipu->vdi_reg)
+ return -ENOMEM;
+
+ dev_dbg(ipu->dev, "IPU CM Regs = %p\n", ipu->cm_reg);
+ dev_dbg(ipu->dev, "IPU IC Regs = %p\n", ipu->ic_reg);
+ dev_dbg(ipu->dev, "IPU IDMAC Regs = %p\n", ipu->idmac_reg);
+ dev_dbg(ipu->dev, "IPU DP Regs = %p\n", ipu->dp_reg);
+ dev_dbg(ipu->dev, "IPU DC Regs = %p\n", ipu->dc_reg);
+ dev_dbg(ipu->dev, "IPU DMFC Regs = %p\n", ipu->dmfc_reg);
+ dev_dbg(ipu->dev, "IPU DI0 Regs = %p\n", ipu->di_reg[0]);
+ dev_dbg(ipu->dev, "IPU DI1 Regs = %p\n", ipu->di_reg[1]);
+ dev_dbg(ipu->dev, "IPU SMFC Regs = %p\n", ipu->smfc_reg);
+ dev_dbg(ipu->dev, "IPU CSI0 Regs = %p\n", ipu->csi_reg[0]);
+ dev_dbg(ipu->dev, "IPU CSI1 Regs = %p\n", ipu->csi_reg[1]);
+ dev_dbg(ipu->dev, "IPU CPMem = %p\n", ipu->cpmem_base);
+ dev_dbg(ipu->dev, "IPU TPMem = %p\n", ipu->tpmem_base);
+ dev_dbg(ipu->dev, "IPU DC Template Mem = %p\n", ipu->dc_tmpl_reg);
+ dev_dbg(ipu->dev, "IPU VDI Regs = %p\n", ipu->vdi_reg);
+
+ ipu->ipu_clk = devm_clk_get(ipu->dev, "bus");
+ if (IS_ERR(ipu->ipu_clk)) {
+ dev_err(ipu->dev, "clk_get ipu failed");
+ return PTR_ERR(ipu->ipu_clk);
+ }
+
+ /* ipu_clk is always prepared */
+ ret = clk_prepare_enable(ipu->ipu_clk);
+ if (ret < 0) {
+ dev_err(ipu->dev, "ipu clk enable failed\n");
+ return ret;
+ }
+
+ ipu->prg_clk = devm_clk_get(ipu->dev, "prg");
+ if (IS_ERR(ipu->prg_clk))
+ ipu->prg_clk = NULL;
+
+ ipu->online = true;
+
+ platform_set_drvdata(pdev, ipu);
+
+ if (!bypass_reset) {
+ ret = device_reset(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to reset: %d\n", ret);
+ return ret;
+ }
+
+ ipu_mem_reset(ipu);
+
+ ipu_disp_init(ipu);
+
+ /* Set MCU_T to divide MCU access window into 2 */
+ ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18),
+ IPU_DISP_GEN);
+ }
+
+ /* setup ipu clk tree after ipu reset */
+ ret = ipu_clk_setup_enable(ipu);
+ if (ret < 0) {
+ dev_err(ipu->dev, "ipu clk setup failed\n");
+ ipu->online = false;
+ return ret;
+ }
+
+ if (devtype->idmac_used_bufs_present) {
+ reg = ipu_idmac_read(ipu, IDMAC_CONF);
+ if (iputype->idmac_used_bufs_en_r)
+ reg |= IDMAC_CONF_USED_BUFS_EN_R;
+ else
+ reg &= ~IDMAC_CONF_USED_BUFS_EN_R;
+ if (iputype->idmac_used_bufs_en_w)
+ reg |= IDMAC_CONF_USED_BUFS_EN_W;
+ else
+ reg &= ~IDMAC_CONF_USED_BUFS_EN_W;
+
+ reg &= ~IDMAC_CONF_USED_BUFS_MAX_R_MASK;
+ reg |= (iputype->idmac_used_bufs_max_r <<
+ IDMAC_CONF_USED_BUFS_MAX_R_OFFSET);
+ reg &= ~IDMAC_CONF_USED_BUFS_MAX_W_MASK;
+ reg |= (iputype->idmac_used_bufs_max_w <<
+ IDMAC_CONF_USED_BUFS_MAX_W_OFFSET);
+ ipu_idmac_write(ipu, reg, IDMAC_CONF);
+ }
+
+ /* Set sync refresh channels and CSI->mem channel as high priority */
+ ipu_idmac_write(ipu, 0x18800003L, IDMAC_CHA_PRI(0));
+
+ /* Enable error interrupts by default */
+ ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(5));
+ ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(6));
+ ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(9));
+ ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(10));
+
+ if (!bypass_reset)
+ clk_disable(ipu->ipu_clk);
+
+ register_ipu_device(ipu, id);
+
+ pm_runtime_enable(&pdev->dev);
+
+ return ret;
+}
+
+int ipu_remove(struct platform_device *pdev)
+{
+ struct ipu_soc *ipu = platform_get_drvdata(pdev);
+
+ unregister_ipu_device(ipu, ipu->id);
+
+ clk_put(ipu->ipu_clk);
+
+ return 0;
+}
+
+void ipu_dump_registers(struct ipu_soc *ipu)
+{
+ dev_dbg(ipu->dev, "IPU_CONF = \t0x%08X\n", ipu_cm_read(ipu, IPU_CONF));
+ dev_dbg(ipu->dev, "IDMAC_CONF = \t0x%08X\n", ipu_idmac_read(ipu, IDMAC_CONF));
+ dev_dbg(ipu->dev, "IDMAC_CHA_EN1 = \t0x%08X\n",
+ ipu_idmac_read(ipu, IDMAC_CHA_EN(0)));
+ dev_dbg(ipu->dev, "IDMAC_CHA_EN2 = \t0x%08X\n",
+ ipu_idmac_read(ipu, IDMAC_CHA_EN(32)));
+ dev_dbg(ipu->dev, "IDMAC_CHA_PRI1 = \t0x%08X\n",
+ ipu_idmac_read(ipu, IDMAC_CHA_PRI(0)));
+ dev_dbg(ipu->dev, "IDMAC_CHA_PRI2 = \t0x%08X\n",
+ ipu_idmac_read(ipu, IDMAC_CHA_PRI(32)));
+ dev_dbg(ipu->dev, "IDMAC_BAND_EN1 = \t0x%08X\n",
+ ipu_idmac_read(ipu, IDMAC_BAND_EN(ipu->devtype, 0)));
+ dev_dbg(ipu->dev, "IDMAC_BAND_EN2 = \t0x%08X\n",
+ ipu_idmac_read(ipu, IDMAC_BAND_EN(ipu->devtype, 32)));
+ dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
+ ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0)));
+ dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
+ ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32)));
+ if (ipu->devtype >= IPUv3EX) {
+ dev_dbg(ipu->dev, "IPU_CHA_TRB_MODE_SEL0 = \t0x%08X\n",
+ ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(ipu->devtype, 0)));
+ dev_dbg(ipu->dev, "IPU_CHA_TRB_MODE_SEL1 = \t0x%08X\n",
+ ipu_cm_read(ipu,
+ IPU_CHA_TRB_MODE_SEL(ipu->devtype, 32)));
+ }
+ dev_dbg(ipu->dev, "DMFC_WR_CHAN = \t0x%08X\n",
+ ipu_dmfc_read(ipu, DMFC_WR_CHAN));
+ dev_dbg(ipu->dev, "DMFC_WR_CHAN_DEF = \t0x%08X\n",
+ ipu_dmfc_read(ipu, DMFC_WR_CHAN_DEF));
+ dev_dbg(ipu->dev, "DMFC_DP_CHAN = \t0x%08X\n",
+ ipu_dmfc_read(ipu, DMFC_DP_CHAN));
+ dev_dbg(ipu->dev, "DMFC_DP_CHAN_DEF = \t0x%08X\n",
+ ipu_dmfc_read(ipu, DMFC_DP_CHAN_DEF));
+ dev_dbg(ipu->dev, "DMFC_IC_CTRL = \t0x%08X\n",
+ ipu_dmfc_read(ipu, DMFC_IC_CTRL));
+ dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW1 = \t0x%08X\n",
+ ipu_cm_read(ipu, IPU_FS_PROC_FLOW1));
+ dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW2 = \t0x%08X\n",
+ ipu_cm_read(ipu, IPU_FS_PROC_FLOW2));
+ dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW3 = \t0x%08X\n",
+ ipu_cm_read(ipu, IPU_FS_PROC_FLOW3));
+ dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
+ ipu_cm_read(ipu, IPU_FS_DISP_FLOW1));
+ dev_dbg(ipu->dev, "IPU_VDIC_VDI_FSIZE = \t0x%08X\n",
+ ipu_vdi_read(ipu, VDI_FSIZE));
+ dev_dbg(ipu->dev, "IPU_VDIC_VDI_C = \t0x%08X\n",
+ ipu_vdi_read(ipu, VDI_C));
+ dev_dbg(ipu->dev, "IPU_IC_CONF = \t0x%08X\n",
+ ipu_ic_read(ipu, IC_CONF));
+}
+
+/*!
+ * This function is called to initialize a logical IPU channel.
+ *
+ * @param ipu ipu handler
+ * @param channel Input parameter for the logical channel ID to init.
+ *
+ * @param params Input parameter containing union of channel
+ * initialization parameters.
+ *
+ * @return Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_init_channel(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params)
+{
+ int ret = 0;
+ bool bad_pixfmt;
+ uint32_t ipu_conf, reg, in_g_pixel_fmt, sec_dma;
+
+ dev_dbg(ipu->dev, "init channel = %d\n", IPU_CHAN_ID(channel));
+
+ ret = pm_runtime_get_sync(ipu->dev);
+ if (ret < 0) {
+ dev_err(ipu->dev, "ch = %d, pm_runtime_get failed:%d!\n",
+ IPU_CHAN_ID(channel), ret);
+ dump_stack();
+ return ret;
+ }
+ /*
+ * Here, ret could be 1 if the device's runtime PM status was
+ * already 'active', so clear it to be 0.
+ */
+ ret = 0;
+
+ _ipu_get(ipu);
+
+ mutex_lock(&ipu->mutex_lock);
+
+ /* Re-enable error interrupts every time a channel is initialized */
+ ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(5));
+ ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(6));
+ ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(9));
+ ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(10));
+
+ if (ipu->channel_init_mask & (1L << IPU_CHAN_ID(channel))) {
+ dev_warn(ipu->dev, "Warning: channel already initialized %d\n",
+ IPU_CHAN_ID(channel));
+ }
+
+ ipu_conf = ipu_cm_read(ipu, IPU_CONF);
+
+ switch (channel) {
+ case CSI_MEM0:
+ case CSI_MEM1:
+ case CSI_MEM2:
+ case CSI_MEM3:
+ if (params->csi_mem.csi > 1) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (params->csi_mem.interlaced)
+ ipu->chan_is_interlaced[channel_2_dma(channel,
+ IPU_OUTPUT_BUFFER)] = true;
+ else
+ ipu->chan_is_interlaced[channel_2_dma(channel,
+ IPU_OUTPUT_BUFFER)] = false;
+
+ ipu->smfc_use_count++;
+ ipu->csi_channel[params->csi_mem.csi] = channel;
+
+ /*SMFC setting*/
+ if (params->csi_mem.mipi_en) {
+ ipu_conf |= (1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+ params->csi_mem.csi));
+ _ipu_smfc_init(ipu, channel, params->csi_mem.mipi_vc,
+ params->csi_mem.csi);
+ _ipu_csi_set_mipi_di(ipu, params->csi_mem.mipi_vc,
+ params->csi_mem.mipi_id, params->csi_mem.csi);
+ } else {
+ ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+ params->csi_mem.csi));
+ _ipu_smfc_init(ipu, channel, 0, params->csi_mem.csi);
+ }
+
+ /*CSI data (include compander) dest*/
+ _ipu_csi_init(ipu, channel, params->csi_mem.csi);
+ break;
+ case CSI_PRP_ENC_MEM:
+ if (params->csi_prp_enc_mem.csi > 1) {
+ ret = -EINVAL;
+ goto err;
+ }
+ if ((ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM) ||
+ (ipu->using_ic_dirct_ch == MEM_VDI_MEM)) {
+ ret = -EINVAL;
+ goto err;
+ }
+ ipu->using_ic_dirct_ch = CSI_PRP_ENC_MEM;
+
+ ipu->ic_use_count++;
+ ipu->csi_channel[params->csi_prp_enc_mem.csi] = channel;
+
+ if (params->csi_prp_enc_mem.mipi_en) {
+ ipu_conf |= (1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+ params->csi_prp_enc_mem.csi));
+ _ipu_csi_set_mipi_di(ipu,
+ params->csi_prp_enc_mem.mipi_vc,
+ params->csi_prp_enc_mem.mipi_id,
+ params->csi_prp_enc_mem.csi);
+ } else
+ ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+ params->csi_prp_enc_mem.csi));
+
+ /*CSI0/1 feed into IC*/
+ ipu_conf &= ~IPU_CONF_IC_INPUT;
+ if (params->csi_prp_enc_mem.csi)
+ ipu_conf |= IPU_CONF_CSI_SEL;
+ else
+ ipu_conf &= ~IPU_CONF_CSI_SEL;
+
+ /*PRP skip buffer in memory, only valid when RWS_EN is true*/
+ reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+ ipu_cm_write(ipu, reg & ~FS_ENC_IN_VALID, IPU_FS_PROC_FLOW1);
+
+ /*CSI data (include compander) dest*/
+ _ipu_csi_init(ipu, channel, params->csi_prp_enc_mem.csi);
+ _ipu_ic_init_prpenc(ipu, params, true);
+ break;
+ case CSI_PRP_VF_MEM:
+ if (params->csi_prp_vf_mem.csi > 1) {
+ ret = -EINVAL;
+ goto err;
+ }
+ if ((ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM) ||
+ (ipu->using_ic_dirct_ch == MEM_VDI_MEM)) {
+ ret = -EINVAL;
+ goto err;
+ }
+ ipu->using_ic_dirct_ch = CSI_PRP_VF_MEM;
+
+ ipu->ic_use_count++;
+ ipu->csi_channel[params->csi_prp_vf_mem.csi] = channel;
+
+ if (params->csi_prp_vf_mem.mipi_en) {
+ ipu_conf |= (1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+ params->csi_prp_vf_mem.csi));
+ _ipu_csi_set_mipi_di(ipu,
+ params->csi_prp_vf_mem.mipi_vc,
+ params->csi_prp_vf_mem.mipi_id,
+ params->csi_prp_vf_mem.csi);
+ } else
+ ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+ params->csi_prp_vf_mem.csi));
+
+ /*CSI0/1 feed into IC*/
+ ipu_conf &= ~IPU_CONF_IC_INPUT;
+ if (params->csi_prp_vf_mem.csi)
+ ipu_conf |= IPU_CONF_CSI_SEL;
+ else
+ ipu_conf &= ~IPU_CONF_CSI_SEL;
+
+ /*PRP skip buffer in memory, only valid when RWS_EN is true*/
+ reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+ ipu_cm_write(ipu, reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
+
+ /*CSI data (include compander) dest*/
+ _ipu_csi_init(ipu, channel, params->csi_prp_vf_mem.csi);
+ _ipu_ic_init_prpvf(ipu, params, true);
+ break;
+ case MEM_PRP_VF_MEM:
+ if (params->mem_prp_vf_mem.graphics_combine_en) {
+ sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+ in_g_pixel_fmt = params->mem_prp_vf_mem.in_g_pixel_fmt;
+ bad_pixfmt =
+ _ipu_ch_param_bad_alpha_pos(in_g_pixel_fmt);
+
+ if (params->mem_prp_vf_mem.alpha_chan_en) {
+ if (bad_pixfmt) {
+ dev_err(ipu->dev, "bad pixel format "
+ "for graphics plane from "
+ "ch%d\n", sec_dma);
+ ret = -EINVAL;
+ goto err;
+ }
+ ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = true;
+ }
+ ipu->sec_chan_en[IPU_CHAN_ID(channel)] = true;
+ }
+
+ reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+ ipu_cm_write(ipu, reg | FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
+
+ _ipu_ic_init_prpvf(ipu, params, false);
+ ipu->ic_use_count++;
+ break;
+ case MEM_VDI_PRP_VF_MEM:
+ if ((ipu->using_ic_dirct_ch == CSI_PRP_VF_MEM) ||
+ (ipu->using_ic_dirct_ch == MEM_VDI_MEM) ||
+ (ipu->using_ic_dirct_ch == CSI_PRP_ENC_MEM)) {
+ ret = -EINVAL;
+ goto err;
+ }
+ ipu->using_ic_dirct_ch = MEM_VDI_PRP_VF_MEM;
+ ipu->ic_use_count++;
+ ipu->vdi_use_count++;
+ reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+ reg &= ~FS_VDI_SRC_SEL_MASK;
+ ipu_cm_write(ipu, reg , IPU_FS_PROC_FLOW1);
+
+ if (params->mem_prp_vf_mem.graphics_combine_en)
+ ipu->sec_chan_en[IPU_CHAN_ID(channel)] = true;
+ _ipu_ic_init_prpvf(ipu, params, false);
+ _ipu_vdi_init(ipu, channel, params);
+ break;
+ case MEM_VDI_PRP_VF_MEM_P:
+ case MEM_VDI_PRP_VF_MEM_N:
+ case MEM_VDI_MEM_P:
+ case MEM_VDI_MEM_N:
+ _ipu_vdi_init(ipu, channel, params);
+ break;
+ case MEM_VDI_MEM:
+ if ((ipu->using_ic_dirct_ch == CSI_PRP_VF_MEM) ||
+ (ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM) ||
+ (ipu->using_ic_dirct_ch == CSI_PRP_ENC_MEM)) {
+ ret = -EINVAL;
+ goto err;
+ }
+ ipu->using_ic_dirct_ch = MEM_VDI_MEM;
+ ipu->ic_use_count++;
+ ipu->vdi_use_count++;
+ _ipu_vdi_init(ipu, channel, params);
+ break;
+ case MEM_ROT_VF_MEM:
+ ipu->ic_use_count++;
+ ipu->rot_use_count++;
+ _ipu_ic_init_rotate_vf(ipu, params);
+ break;
+ case MEM_PRP_ENC_MEM:
+ ipu->ic_use_count++;
+ reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+ ipu_cm_write(ipu, reg | FS_ENC_IN_VALID, IPU_FS_PROC_FLOW1);
+ _ipu_ic_init_prpenc(ipu, params, false);
+ break;
+ case MEM_ROT_ENC_MEM:
+ ipu->ic_use_count++;
+ ipu->rot_use_count++;
+ _ipu_ic_init_rotate_enc(ipu, params);
+ break;
+ case MEM_PP_MEM:
+ if (params->mem_pp_mem.graphics_combine_en) {
+ sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+ in_g_pixel_fmt = params->mem_pp_mem.in_g_pixel_fmt;
+ bad_pixfmt =
+ _ipu_ch_param_bad_alpha_pos(in_g_pixel_fmt);
+
+ if (params->mem_pp_mem.alpha_chan_en) {
+ if (bad_pixfmt) {
+ dev_err(ipu->dev, "bad pixel format "
+ "for graphics plane from "
+ "ch%d\n", sec_dma);
+ ret = -EINVAL;
+ goto err;
+ }
+ ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = true;
+ }
+
+ ipu->sec_chan_en[IPU_CHAN_ID(channel)] = true;
+ }
+
+ _ipu_ic_init_pp(ipu, params);
+ ipu->ic_use_count++;
+ break;
+ case MEM_ROT_PP_MEM:
+ _ipu_ic_init_rotate_pp(ipu, params);
+ ipu->ic_use_count++;
+ ipu->rot_use_count++;
+ break;
+ case MEM_DC_SYNC:
+ if (params->mem_dc_sync.di > 1) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ipu->dc_di_assignment[1] = params->mem_dc_sync.di;
+ _ipu_dc_init(ipu, 1, params->mem_dc_sync.di,
+ params->mem_dc_sync.interlaced,
+ params->mem_dc_sync.out_pixel_fmt);
+ ipu->di_use_count[params->mem_dc_sync.di]++;
+ ipu->dc_use_count++;
+ ipu->dmfc_use_count++;
+ break;
+ case MEM_BG_SYNC:
+ if (params->mem_dp_bg_sync.di > 1) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (params->mem_dp_bg_sync.alpha_chan_en)
+ ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = true;
+
+ ipu->dc_di_assignment[5] = params->mem_dp_bg_sync.di;
+ _ipu_dp_init(ipu, channel, params->mem_dp_bg_sync.in_pixel_fmt,
+ params->mem_dp_bg_sync.out_pixel_fmt);
+ _ipu_dc_init(ipu, 5, params->mem_dp_bg_sync.di,
+ params->mem_dp_bg_sync.interlaced,
+ params->mem_dp_bg_sync.out_pixel_fmt);
+ ipu->di_use_count[params->mem_dp_bg_sync.di]++;
+ ipu->dc_use_count++;
+ ipu->dp_use_count++;
+ ipu->dmfc_use_count++;
+ break;
+ case MEM_FG_SYNC:
+ _ipu_dp_init(ipu, channel, params->mem_dp_fg_sync.in_pixel_fmt,
+ params->mem_dp_fg_sync.out_pixel_fmt);
+
+ if (params->mem_dp_fg_sync.alpha_chan_en)
+ ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = true;
+
+ ipu->dc_use_count++;
+ ipu->dp_use_count++;
+ ipu->dmfc_use_count++;
+ break;
+ case DIRECT_ASYNC0:
+ if (params->direct_async.di > 1) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ipu->dc_di_assignment[8] = params->direct_async.di;
+ _ipu_dc_init(ipu, 8, params->direct_async.di, false, IPU_PIX_FMT_GENERIC);
+ ipu->di_use_count[params->direct_async.di]++;
+ ipu->dc_use_count++;
+ break;
+ case DIRECT_ASYNC1:
+ if (params->direct_async.di > 1) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ipu->dc_di_assignment[9] = params->direct_async.di;
+ _ipu_dc_init(ipu, 9, params->direct_async.di, false, IPU_PIX_FMT_GENERIC);
+ ipu->di_use_count[params->direct_async.di]++;
+ ipu->dc_use_count++;
+ break;
+ default:
+ dev_err(ipu->dev, "Missing channel initialization\n");
+ break;
+ }
+
+ ipu->channel_init_mask |= 1L << IPU_CHAN_ID(channel);
+
+ ipu_cm_write(ipu, ipu_conf, IPU_CONF);
+
+err:
+ mutex_unlock(&ipu->mutex_lock);
+ return ret;
+}
+EXPORT_SYMBOL(ipu_init_channel);
+
+/*!
+ * This function is called to uninitialize a logical IPU channel.
+ *
+ * @param ipu ipu handler
+ * @param channel Input parameter for the logical channel ID to uninit.
+ */
+void ipu_uninit_channel(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+ uint32_t reg;
+ uint32_t in_dma, out_dma = 0;
+ uint32_t ipu_conf;
+ uint32_t dc_chan = 0;
+ int ret;
+
+ mutex_lock(&ipu->mutex_lock);
+
+ if ((ipu->channel_init_mask & (1L << IPU_CHAN_ID(channel))) == 0) {
+ dev_dbg(ipu->dev, "Channel already uninitialized %d\n",
+ IPU_CHAN_ID(channel));
+ mutex_unlock(&ipu->mutex_lock);
+ return;
+ }
+
+ /* Make sure channel is disabled */
+ /* Get input and output dma channels */
+ in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+ out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
+
+ if (idma_is_set(ipu, IDMAC_CHA_EN(in_dma), in_dma) ||
+ idma_is_set(ipu, IDMAC_CHA_EN(out_dma), out_dma)) {
+ dev_err(ipu->dev,
+ "Channel %d is not disabled, disable first\n",
+ IPU_CHAN_ID(channel));
+ mutex_unlock(&ipu->mutex_lock);
+ return;
+ }
+
+ ipu_conf = ipu_cm_read(ipu, IPU_CONF);
+
+ /* Reset the double buffer */
+ reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(in_dma));
+ ipu_cm_write(ipu, reg & ~idma_mask(in_dma), IPU_CHA_DB_MODE_SEL(in_dma));
+ reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(out_dma));
+ ipu_cm_write(ipu, reg & ~idma_mask(out_dma), IPU_CHA_DB_MODE_SEL(out_dma));
+
+ /* Reset the triple buffer */
+ reg = ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(ipu->devtype, in_dma));
+ ipu_cm_write(ipu, reg & ~idma_mask(in_dma),
+ IPU_CHA_TRB_MODE_SEL(ipu->devtype, in_dma));
+ reg = ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(ipu->devtype, out_dma));
+ ipu_cm_write(ipu, reg & ~idma_mask(out_dma),
+ IPU_CHA_TRB_MODE_SEL(ipu->devtype, out_dma));
+
+ if (_ipu_is_ic_chan(in_dma) || _ipu_is_dp_graphic_chan(in_dma)) {
+ ipu->sec_chan_en[IPU_CHAN_ID(channel)] = false;
+ ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = false;
+ }
+
+ switch (channel) {
+ case CSI_MEM0:
+ case CSI_MEM1:
+ case CSI_MEM2:
+ case CSI_MEM3:
+ ipu->smfc_use_count--;
+ if (ipu->csi_channel[0] == channel) {
+ ipu->csi_channel[0] = CHAN_NONE;
+ } else if (ipu->csi_channel[1] == channel) {
+ ipu->csi_channel[1] = CHAN_NONE;
+ }
+ break;
+ case CSI_PRP_ENC_MEM:
+ ipu->ic_use_count--;
+ if (ipu->using_ic_dirct_ch == CSI_PRP_ENC_MEM)
+ ipu->using_ic_dirct_ch = 0;
+ _ipu_ic_uninit_prpenc(ipu);
+ if (ipu->csi_channel[0] == channel) {
+ ipu->csi_channel[0] = CHAN_NONE;
+ } else if (ipu->csi_channel[1] == channel) {
+ ipu->csi_channel[1] = CHAN_NONE;
+ }
+ break;
+ case CSI_PRP_VF_MEM:
+ ipu->ic_use_count--;
+ if (ipu->using_ic_dirct_ch == CSI_PRP_VF_MEM)
+ ipu->using_ic_dirct_ch = 0;
+ _ipu_ic_uninit_prpvf(ipu);
+ if (ipu->csi_channel[0] == channel) {
+ ipu->csi_channel[0] = CHAN_NONE;
+ } else if (ipu->csi_channel[1] == channel) {
+ ipu->csi_channel[1] = CHAN_NONE;
+ }
+ break;
+ case MEM_PRP_VF_MEM:
+ ipu->ic_use_count--;
+ _ipu_ic_uninit_prpvf(ipu);
+ reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+ ipu_cm_write(ipu, reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
+ break;
+ case MEM_VDI_PRP_VF_MEM:
+ ipu->ic_use_count--;
+ ipu->vdi_use_count--;
+ if (ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM)
+ ipu->using_ic_dirct_ch = 0;
+ _ipu_ic_uninit_prpvf(ipu);
+ _ipu_vdi_uninit(ipu);
+ reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+ ipu_cm_write(ipu, reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
+ break;
+ case MEM_VDI_MEM:
+ ipu->ic_use_count--;
+ ipu->vdi_use_count--;
+ if (ipu->using_ic_dirct_ch == MEM_VDI_MEM)
+ ipu->using_ic_dirct_ch = 0;
+ _ipu_vdi_uninit(ipu);
+ break;
+ case MEM_VDI_PRP_VF_MEM_P:
+ case MEM_VDI_PRP_VF_MEM_N:
+ case MEM_VDI_MEM_P:
+ case MEM_VDI_MEM_N:
+ break;
+ case MEM_ROT_VF_MEM:
+ ipu->rot_use_count--;
+ ipu->ic_use_count--;
+ _ipu_ic_uninit_rotate_vf(ipu);
+ break;
+ case MEM_PRP_ENC_MEM:
+ ipu->ic_use_count--;
+ _ipu_ic_uninit_prpenc(ipu);
+ reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+ ipu_cm_write(ipu, reg & ~FS_ENC_IN_VALID, IPU_FS_PROC_FLOW1);
+ break;
+ case MEM_ROT_ENC_MEM:
+ ipu->rot_use_count--;
+ ipu->ic_use_count--;
+ _ipu_ic_uninit_rotate_enc(ipu);
+ break;
+ case MEM_PP_MEM:
+ ipu->ic_use_count--;
+ _ipu_ic_uninit_pp(ipu);
+ break;
+ case MEM_ROT_PP_MEM:
+ ipu->rot_use_count--;
+ ipu->ic_use_count--;
+ _ipu_ic_uninit_rotate_pp(ipu);
+ break;
+ case MEM_DC_SYNC:
+ dc_chan = 1;
+ _ipu_dc_uninit(ipu, 1);
+ ipu->di_use_count[ipu->dc_di_assignment[1]]--;
+ ipu->dc_use_count--;
+ ipu->dmfc_use_count--;
+ break;
+ case MEM_BG_SYNC:
+ dc_chan = 5;
+ _ipu_dp_uninit(ipu, channel);
+ _ipu_dc_uninit(ipu, 5);
+ ipu->di_use_count[ipu->dc_di_assignment[5]]--;
+ ipu->dc_use_count--;
+ ipu->dp_use_count--;
+ ipu->dmfc_use_count--;
+ break;
+ case MEM_FG_SYNC:
+ _ipu_dp_uninit(ipu, channel);
+ ipu->dc_use_count--;
+ ipu->dp_use_count--;
+ ipu->dmfc_use_count--;
+ break;
+ case DIRECT_ASYNC0:
+ dc_chan = 8;
+ _ipu_dc_uninit(ipu, 8);
+ ipu->di_use_count[ipu->dc_di_assignment[8]]--;
+ ipu->dc_use_count--;
+ break;
+ case DIRECT_ASYNC1:
+ dc_chan = 9;
+ _ipu_dc_uninit(ipu, 9);
+ ipu->di_use_count[ipu->dc_di_assignment[9]]--;
+ ipu->dc_use_count--;
+ break;
+ default:
+ break;
+ }
+
+ if (ipu->ic_use_count == 0)
+ ipu_conf &= ~IPU_CONF_IC_EN;
+ if (ipu->vdi_use_count == 0) {
+ ipu_conf &= ~IPU_CONF_ISP_EN;
+ ipu_conf &= ~IPU_CONF_VDI_EN;
+ ipu_conf &= ~IPU_CONF_IC_INPUT;
+ }
+ if (ipu->rot_use_count == 0)
+ ipu_conf &= ~IPU_CONF_ROT_EN;
+ if (ipu->dc_use_count == 0)
+ ipu_conf &= ~IPU_CONF_DC_EN;
+ if (ipu->dp_use_count == 0)
+ ipu_conf &= ~IPU_CONF_DP_EN;
+ if (ipu->dmfc_use_count == 0)
+ ipu_conf &= ~IPU_CONF_DMFC_EN;
+ if (ipu->di_use_count[0] == 0) {
+ ipu_conf &= ~IPU_CONF_DI0_EN;
+ }
+ if (ipu->di_use_count[1] == 0) {
+ ipu_conf &= ~IPU_CONF_DI1_EN;
+ }
+ if (ipu->smfc_use_count == 0)
+ ipu_conf &= ~IPU_CONF_SMFC_EN;
+
+ ipu_cm_write(ipu, ipu_conf, IPU_CONF);
+
+ ipu->channel_init_mask &= ~(1L << IPU_CHAN_ID(channel));
+
+ /*
+ * Disable pixel clk and its parent clock(if the parent clock
+ * usecount is 1) after clearing DC/DP/DI bits in IPU_CONF
+ * register to prevent LVDS display channel starvation.
+ */
+ if (_ipu_is_primary_disp_chan(in_dma) &&
+ ipu->pixel_clk_en[ipu->dc_di_assignment[dc_chan]]) {
+ clk_disable_unprepare(ipu->pixel_clk[ipu->dc_di_assignment[dc_chan]]);
+ ipu->pixel_clk_en[ipu->dc_di_assignment[dc_chan]] = false;
+ }
+
+ mutex_unlock(&ipu->mutex_lock);
+
+ _ipu_put(ipu);
+
+ ret = pm_runtime_put_sync_suspend(ipu->dev);
+ if (ret < 0) {
+ dev_err(ipu->dev, "ch = %d, pm_runtime_put failed:%d!\n",
+ IPU_CHAN_ID(channel), ret);
+ dump_stack();
+ }
+
+ WARN_ON(ipu->ic_use_count < 0);
+ WARN_ON(ipu->vdi_use_count < 0);
+ WARN_ON(ipu->rot_use_count < 0);
+ WARN_ON(ipu->dc_use_count < 0);
+ WARN_ON(ipu->dp_use_count < 0);
+ WARN_ON(ipu->dmfc_use_count < 0);
+ WARN_ON(ipu->smfc_use_count < 0);
+}
+EXPORT_SYMBOL(ipu_uninit_channel);
+
+/*!
+ * This function is called to initialize buffer(s) for logical IPU channel.
+ *
+ * @param ipu ipu handler
+ *
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param type Input parameter which buffer to initialize.
+ *
+ * @param pixel_fmt Input parameter for pixel format of buffer.
+ * Pixel format is a FOURCC ASCII code.
+ *
+ * @param width Input parameter for width of buffer in pixels.
+ *
+ * @param height Input parameter for height of buffer in pixels.
+ *
+ * @param stride Input parameter for stride length of buffer
+ * in pixels.
+ *
+ * @param rot_mode Input parameter for rotation setting of buffer.
+ * A rotation setting other than
+ * IPU_ROTATE_VERT_FLIP
+ * should only be used for input buffers of
+ * rotation channels.
+ *
+ * @param phyaddr_0 Input parameter buffer 0 physical address.
+ *
+ * @param phyaddr_1 Input parameter buffer 1 physical address.
+ * Setting this to a value other than NULL enables
+ * double buffering mode.
+ *
+ * @param phyaddr_2 Input parameter buffer 2 physical address.
+ * Setting this to a value other than NULL enables
+ * triple buffering mode, phyaddr_1 should not be
+ * NULL then.
+ *
+ * @param u private u offset for additional cropping,
+ * zero if not used.
+ *
+ * @param v private v offset for additional cropping,
+ * zero if not used.
+ *
+ * @return Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_init_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
+ ipu_buffer_t type,
+ uint32_t pixel_fmt,
+ uint16_t width, uint16_t height,
+ uint32_t stride,
+ ipu_rotate_mode_t rot_mode,
+ dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
+ dma_addr_t phyaddr_2,
+ uint32_t u, uint32_t v)
+{
+ uint32_t reg;
+ uint32_t dma_chan;
+ uint32_t burst_size;
+
+ dma_chan = channel_2_dma(channel, type);
+ if (!idma_is_valid(dma_chan))
+ return -EINVAL;
+
+ if (stride < width * bytes_per_pixel(pixel_fmt))
+ stride = width * bytes_per_pixel(pixel_fmt);
+
+ if (stride % 4) {
+ dev_err(ipu->dev,
+ "Stride not 32-bit aligned, stride = %d\n", stride);
+ return -EINVAL;
+ }
+ /* IC & IRT channels' width must be multiple of 8 pixels */
+ if ((_ipu_is_ic_chan(dma_chan) || _ipu_is_irt_chan(dma_chan))
+ && (width % 8)) {
+ dev_err(ipu->dev, "Width must be 8 pixel multiple\n");
+ return -EINVAL;
+ }
+
+ if (_ipu_is_vdi_out_chan(dma_chan) &&
+ ((width < 16) || (height < 16) || (width % 2) || (height % 4))) {
+ dev_err(ipu->dev, "vdi width/height limited err\n");
+ return -EINVAL;
+ }
+
+ /* IPUv3EX and IPUv3M support triple buffer */
+ if ((!_ipu_is_trb_chan(ipu, dma_chan)) && phyaddr_2) {
+ dev_err(ipu->dev, "Chan%d doesn't support triple buffer "
+ "mode\n", dma_chan);
+ return -EINVAL;
+ }
+ if (!phyaddr_1 && phyaddr_2) {
+ dev_err(ipu->dev, "Chan%d's buf1 physical addr is NULL for "
+ "triple buffer mode\n", dma_chan);
+ return -EINVAL;
+ }
+
+ mutex_lock(&ipu->mutex_lock);
+
+ /* Build parameter memory data for DMA channel */
+ _ipu_ch_param_init(ipu, dma_chan, pixel_fmt, width, height, stride, u, v, 0,
+ phyaddr_0, phyaddr_1, phyaddr_2);
+
+ /* Set correlative channel parameter of local alpha channel */
+ if ((_ipu_is_ic_graphic_chan(dma_chan) ||
+ _ipu_is_dp_graphic_chan(dma_chan)) &&
+ (ipu->thrd_chan_en[IPU_CHAN_ID(channel)] == true)) {
+ _ipu_ch_param_set_alpha_use_separate_channel(ipu, dma_chan, true);
+ _ipu_ch_param_set_alpha_buffer_memory(ipu, dma_chan);
+ _ipu_ch_param_set_alpha_condition_read(ipu, dma_chan);
+ /* fix alpha width as 8 and burst size as 16*/
+ _ipu_ch_params_set_alpha_width(ipu, dma_chan, 8);
+ _ipu_ch_param_set_burst_size(ipu, dma_chan, 16);
+ } else if (_ipu_is_ic_graphic_chan(dma_chan) &&
+ ipu_pixel_format_has_alpha(pixel_fmt))
+ _ipu_ch_param_set_alpha_use_separate_channel(ipu, dma_chan, false);
+
+ if (rot_mode)
+ _ipu_ch_param_set_rotation(ipu, dma_chan, rot_mode);
+
+ /* IC and ROT channels have restriction of 8 or 16 pix burst length */
+ if (_ipu_is_ic_chan(dma_chan) || _ipu_is_vdi_out_chan(dma_chan)) {
+ if ((width % 16) == 0)
+ _ipu_ch_param_set_burst_size(ipu, dma_chan, 16);
+ else
+ _ipu_ch_param_set_burst_size(ipu, dma_chan, 8);
+ } else if (_ipu_is_irt_chan(dma_chan)) {
+ _ipu_ch_param_set_burst_size(ipu, dma_chan, 8);
+ _ipu_ch_param_set_block_mode(ipu, dma_chan);
+ } else if (_ipu_is_dmfc_chan(dma_chan)) {
+ burst_size = _ipu_ch_param_get_burst_size(ipu, dma_chan);
+ _ipu_dmfc_set_wait4eot(ipu, dma_chan, width);
+ _ipu_dmfc_set_burst_size(ipu, dma_chan, burst_size);
+ }
+
+ if (_ipu_disp_chan_is_interlaced(ipu, channel) ||
+ ipu->chan_is_interlaced[dma_chan])
+ _ipu_ch_param_set_interlaced_scan(ipu, dma_chan);
+
+ if (_ipu_is_ic_chan(dma_chan) || _ipu_is_irt_chan(dma_chan) ||
+ _ipu_is_vdi_out_chan(dma_chan)) {
+ burst_size = _ipu_ch_param_get_burst_size(ipu, dma_chan);
+ _ipu_ic_idma_init(ipu, dma_chan, width, height, burst_size,
+ rot_mode);
+ } else if (_ipu_is_smfc_chan(dma_chan)) {
+ burst_size = _ipu_ch_param_get_burst_size(ipu, dma_chan);
+ /*
+ * This is different from IPUv3 spec, but it is confirmed
+ * in IPUforum that SMFC burst size should be NPB[6:3]
+ * when IDMAC works in 16-bit generic data mode.
+ */
+ if (pixel_fmt == IPU_PIX_FMT_GENERIC)
+ /* 8 bits per pixel */
+ burst_size = burst_size >> 4;
+ else if (pixel_fmt == IPU_PIX_FMT_GENERIC_16)
+ /* 16 bits per pixel */
+ burst_size = burst_size >> 3;
+ else
+ burst_size = burst_size >> 2;
+ _ipu_smfc_set_burst_size(ipu, channel, burst_size-1);
+ }
+
+ switch (dma_chan) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ _ipu_ch_param_set_axi_id(ipu, dma_chan, ipu->ch0123_axi);
+ break;
+ case 23:
+ _ipu_ch_param_set_axi_id(ipu, dma_chan, ipu->ch23_axi);
+ break;
+ case 27:
+ _ipu_ch_param_set_axi_id(ipu, dma_chan, ipu->ch27_axi);
+ break;
+ case 28:
+ _ipu_ch_param_set_axi_id(ipu, dma_chan, ipu->ch28_axi);
+ break;
+ default:
+ _ipu_ch_param_set_axi_id(ipu, dma_chan, ipu->normal_axi);
+ break;
+ }
+
+ if (idma_is_set(ipu, IDMAC_CHA_PRI(dma_chan), dma_chan) &&
+ ipu->devtype == IPUv3H) {
+ uint32_t reg = IDMAC_CH_LOCK_EN_1(ipu->devtype);
+ uint32_t value = 0;
+
+ switch (dma_chan) {
+ case 5:
+ value = 0x3;
+ break;
+ case 11:
+ value = 0x3 << 2;
+ break;
+ case 12:
+ value = 0x3 << 4;
+ break;
+ case 14:
+ value = 0x3 << 6;
+ break;
+ case 15:
+ value = 0x3 << 8;
+ break;
+ case 20:
+ value = 0x3 << 10;
+ break;
+ case 21:
+ value = 0x3 << 12;
+ break;
+ case 22:
+ value = 0x3 << 14;
+ break;
+ case 23:
+ value = 0x3 << 16;
+ break;
+ case 27:
+ value = 0x3 << 18;
+ break;
+ case 28:
+ value = 0x3 << 20;
+ break;
+ case 45:
+ reg = IDMAC_CH_LOCK_EN_2(ipu->devtype);
+ value = 0x3 << 0;
+ break;
+ case 46:
+ reg = IDMAC_CH_LOCK_EN_2(ipu->devtype);
+ value = 0x3 << 2;
+ break;
+ case 47:
+ reg = IDMAC_CH_LOCK_EN_2(ipu->devtype);
+ value = 0x3 << 4;
+ break;
+ case 48:
+ reg = IDMAC_CH_LOCK_EN_2(ipu->devtype);
+ value = 0x3 << 6;
+ break;
+ case 49:
+ reg = IDMAC_CH_LOCK_EN_2(ipu->devtype);
+ value = 0x3 << 8;
+ break;
+ case 50:
+ reg = IDMAC_CH_LOCK_EN_2(ipu->devtype);
+ value = 0x3 << 10;
+ break;
+ default:
+ break;
+ }
+ value |= ipu_idmac_read(ipu, reg);
+ ipu_idmac_write(ipu, value, reg);
+ }
+
+ _ipu_ch_param_dump(ipu, dma_chan);
+
+ if (phyaddr_2 && ipu->devtype >= IPUv3EX) {
+ reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(dma_chan));
+ reg &= ~idma_mask(dma_chan);
+ ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(dma_chan));
+
+ reg = ipu_cm_read(ipu,
+ IPU_CHA_TRB_MODE_SEL(ipu->devtype, dma_chan));
+ reg |= idma_mask(dma_chan);
+ ipu_cm_write(ipu, reg,
+ IPU_CHA_TRB_MODE_SEL(ipu->devtype, dma_chan));
+
+ /* Set IDMAC third buffer's cpmem number */
+ /* See __ipu_ch_get_third_buf_cpmem_num() for mapping */
+ ipu_idmac_write(ipu, 0x00444047L,
+ IDMAC_SUB_ADDR_4(ipu->devtype));
+ ipu_idmac_write(ipu, 0x46004241L,
+ IDMAC_SUB_ADDR_3(ipu->devtype));
+ ipu_idmac_write(ipu, 0x00000045L,
+ IDMAC_SUB_ADDR_1(ipu->devtype));
+
+ /* Reset to buffer 0 */
+ ipu_cm_write(ipu, tri_cur_buf_mask(dma_chan),
+ IPU_CHA_TRIPLE_CUR_BUF(ipu->devtype, dma_chan));
+ } else {
+ reg = ipu_cm_read(ipu,
+ IPU_CHA_TRB_MODE_SEL(ipu->devtype, dma_chan));
+ reg &= ~idma_mask(dma_chan);
+ ipu_cm_write(ipu, reg,
+ IPU_CHA_TRB_MODE_SEL(ipu->devtype, dma_chan));
+
+ reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(dma_chan));
+ if (phyaddr_1)
+ reg |= idma_mask(dma_chan);
+ else
+ reg &= ~idma_mask(dma_chan);
+ ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(dma_chan));
+
+ /* Reset to buffer 0 */
+ ipu_cm_write(ipu, idma_mask(dma_chan),
+ IPU_CHA_CUR_BUF(ipu->devtype, dma_chan));
+
+ }
+
+ mutex_unlock(&ipu->mutex_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_init_channel_buffer);
+
+/*!
+ * This function is called to update the physical address of a buffer for
+ * a logical IPU channel.
+ *
+ * @param ipu ipu handler
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param type Input parameter which buffer to initialize.
+ *
+ * @param bufNum Input parameter for buffer number to update.
+ * 0 or 1 are the only valid values.
+ *
+ * @param phyaddr Input parameter buffer physical address.
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail. This function will fail if the buffer is set to ready.
+ */
+int32_t ipu_update_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
+ ipu_buffer_t type, uint32_t bufNum, dma_addr_t phyaddr)
+{
+ uint32_t reg;
+ int ret = 0;
+ uint32_t dma_chan = channel_2_dma(channel, type);
+ unsigned long lock_flags;
+
+ if (dma_chan == IDMA_CHAN_INVALID)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+ if (bufNum == 0)
+ reg = ipu_cm_read(ipu,
+ IPU_CHA_BUF0_RDY(ipu->devtype, dma_chan));
+ else if (bufNum == 1)
+ reg = ipu_cm_read(ipu,
+ IPU_CHA_BUF1_RDY(ipu->devtype, dma_chan));
+ else
+ reg = ipu_cm_read(ipu,
+ IPU_CHA_BUF2_RDY(ipu->devtype, dma_chan));
+
+ if ((reg & idma_mask(dma_chan)) == 0)
+ _ipu_ch_param_set_buffer(ipu, dma_chan, bufNum, phyaddr);
+ else
+ ret = -EACCES;
+ spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(ipu_update_channel_buffer);
+
+/*!
+ * This function is called to update the band mode setting for
+ * a logical IPU channel.
+ *
+ * @param ipu ipu handler
+ *
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param type Input parameter which buffer to initialize.
+ *
+ * @param band_height Input parameter for band lines:
+ * shoule be log2(4/8/16/32/64/128/256).
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int32_t ipu_set_channel_bandmode(struct ipu_soc *ipu, ipu_channel_t channel,
+ ipu_buffer_t type, uint32_t band_height)
+{
+ uint32_t reg;
+ int ret = 0;
+ uint32_t dma_chan = channel_2_dma(channel, type);
+
+ if ((2 > band_height) || (8 < band_height))
+ return -EINVAL;
+
+ mutex_lock(&ipu->mutex_lock);
+
+ reg = ipu_idmac_read(ipu, IDMAC_BAND_EN(ipu->devtype, dma_chan));
+ reg |= 1 << (dma_chan % 32);
+ ipu_idmac_write(ipu, reg, IDMAC_BAND_EN(ipu->devtype, dma_chan));
+
+ _ipu_ch_param_set_bandmode(ipu, dma_chan, band_height);
+ dev_dbg(ipu->dev, "dma_chan:%d, band_height:%d.\n\n",
+ dma_chan, 1 << band_height);
+ mutex_unlock(&ipu->mutex_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(ipu_set_channel_bandmode);
+
+/*!
+ * This function is called to initialize a buffer for logical IPU channel.
+ *
+ * @param ipu ipu handler
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param type Input parameter which buffer to initialize.
+ *
+ * @param pixel_fmt Input parameter for pixel format of buffer.
+ * Pixel format is a FOURCC ASCII code.
+ *
+ * @param width Input parameter for width of buffer in pixels.
+ *
+ * @param height Input parameter for height of buffer in pixels.
+ *
+ * @param stride Input parameter for stride length of buffer
+ * in pixels.
+ *
+ * @param u predefined private u offset for additional cropping,
+ * zero if not used.
+ *
+ * @param v predefined private v offset for additional cropping,
+ * zero if not used.
+ *
+ * @param vertical_offset vertical offset for Y coordinate
+ * in the existed frame
+ *
+ *
+ * @param horizontal_offset horizontal offset for X coordinate
+ * in the existed frame
+ *
+ *
+ * @return Returns 0 on success or negative error code on fail
+ * This function will fail if any buffer is set to ready.
+ */
+
+int32_t ipu_update_channel_offset(struct ipu_soc *ipu,
+ ipu_channel_t channel, ipu_buffer_t type,
+ uint32_t pixel_fmt,
+ uint16_t width, uint16_t height,
+ uint32_t stride,
+ uint32_t u, uint32_t v,
+ uint32_t vertical_offset, uint32_t horizontal_offset)
+{
+ int ret = 0;
+ uint32_t dma_chan = channel_2_dma(channel, type);
+ unsigned long lock_flags;
+
+ if (dma_chan == IDMA_CHAN_INVALID)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+ if ((ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(ipu->devtype, dma_chan)) &
+ idma_mask(dma_chan)) ||
+ (ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(ipu->devtype, dma_chan)) &
+ idma_mask(dma_chan)) ||
+ ((ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(ipu->devtype, dma_chan)) &
+ idma_mask(dma_chan)) &&
+ (ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(ipu->devtype, dma_chan)) &
+ idma_mask(dma_chan)) && _ipu_is_trb_chan(ipu, dma_chan)))
+ ret = -EACCES;
+ else
+ _ipu_ch_offset_update(ipu, dma_chan, pixel_fmt, width, height, stride,
+ u, v, 0, vertical_offset, horizontal_offset);
+ spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(ipu_update_channel_offset);
+
+int32_t ipu_get_channel_offset(uint32_t pixel_fmt,
+ uint16_t width, uint16_t height,
+ uint32_t stride,
+ uint32_t u, uint32_t v,
+ uint32_t vertical_offset, uint32_t horizontal_offset,
+ uint32_t *u_offset, uint32_t *v_offset)
+{
+ return __ipu_ch_offset_calc(pixel_fmt, width, height, stride,
+ u, v, 0,
+ vertical_offset, horizontal_offset,
+ u_offset, v_offset);
+}
+EXPORT_SYMBOL(ipu_get_channel_offset);
+
+/*!
+ * This function is called to set a channel's buffer as ready.
+ *
+ * @param ipu ipu handler
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param type Input parameter which buffer to initialize.
+ *
+ * @param bufNum Input parameter for which buffer number set to
+ * ready state.
+ *
+ * @return Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_select_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
+ ipu_buffer_t type, uint32_t bufNum)
+{
+ uint32_t dma_chan = channel_2_dma(channel, type);
+ unsigned long lock_flags;
+
+ if (dma_chan == IDMA_CHAN_INVALID)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+ /* Mark buffer to be ready. */
+ if (bufNum == 0)
+ ipu_cm_write(ipu, idma_mask(dma_chan),
+ IPU_CHA_BUF0_RDY(ipu->devtype, dma_chan));
+ else if (bufNum == 1)
+ ipu_cm_write(ipu, idma_mask(dma_chan),
+ IPU_CHA_BUF1_RDY(ipu->devtype, dma_chan));
+ else
+ ipu_cm_write(ipu, idma_mask(dma_chan),
+ IPU_CHA_BUF2_RDY(ipu->devtype, dma_chan));
+ spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_select_buffer);
+
+/*!
+ * This function is called to set a channel's buffer as ready.
+ *
+ * @param ipu ipu handler
+ * @param bufNum Input parameter for which buffer number set to
+ * ready state.
+ *
+ * @return Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_select_multi_vdi_buffer(struct ipu_soc *ipu, uint32_t bufNum)
+{
+
+ uint32_t dma_chan = channel_2_dma(MEM_VDI_PRP_VF_MEM, IPU_INPUT_BUFFER);
+ uint32_t mask_bit =
+ idma_mask(channel_2_dma(MEM_VDI_PRP_VF_MEM_P, IPU_INPUT_BUFFER))|
+ idma_mask(dma_chan)|
+ idma_mask(channel_2_dma(MEM_VDI_PRP_VF_MEM_N, IPU_INPUT_BUFFER));
+ unsigned long lock_flags;
+
+ spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+ /* Mark buffers to be ready. */
+ if (bufNum == 0)
+ ipu_cm_write(ipu, mask_bit,
+ IPU_CHA_BUF0_RDY(ipu->devtype, dma_chan));
+ else
+ ipu_cm_write(ipu, mask_bit,
+ IPU_CHA_BUF1_RDY(ipu->devtype, dma_chan));
+ spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_select_multi_vdi_buffer);
+
+#define NA -1
+static int proc_dest_sel[] = {
+ 0, 1, 1, 3, 5, 5, 4, 7, 8, 9, 10, 11, 12, 14, 15, 16,
+ 0, 1, 1, 5, 5, 5, 5, 5, 7, 8, 9, 10, 11, 12, 14, 31 };
+static int proc_src_sel[] = { 0, 6, 7, 6, 7, 8, 5, NA, NA, NA,
+ NA, NA, NA, NA, NA, 1, 2, 3, 4, 7, 8, NA, 8, NA };
+static int disp_src_sel[] = { 0, 6, 7, 8, 3, 4, 5, NA, NA, NA,
+ NA, NA, NA, NA, NA, 1, NA, 2, NA, 3, 4, 4, 4, 4 };
+
+
+/*!
+ * This function links 2 channels together for automatic frame
+ * synchronization. The output of the source channel is linked to the input of
+ * the destination channel.
+ *
+ * @param ipu ipu handler
+ * @param src_ch Input parameter for the logical channel ID of
+ * the source channel.
+ *
+ * @param dest_ch Input parameter for the logical channel ID of
+ * the destination channel.
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int32_t ipu_link_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_channel_t dest_ch)
+{
+ int retval = 0;
+ uint32_t fs_proc_flow1;
+ uint32_t fs_proc_flow2;
+ uint32_t fs_proc_flow3;
+ uint32_t fs_disp_flow1;
+
+ mutex_lock(&ipu->mutex_lock);
+
+ fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+ fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+ fs_proc_flow3 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW3);
+ fs_disp_flow1 = ipu_cm_read(ipu, IPU_FS_DISP_FLOW1);
+
+ switch (src_ch) {
+ case CSI_MEM0:
+ fs_proc_flow3 &= ~FS_SMFC0_DEST_SEL_MASK;
+ fs_proc_flow3 |=
+ proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+ FS_SMFC0_DEST_SEL_OFFSET;
+ break;
+ case CSI_MEM1:
+ fs_proc_flow3 &= ~FS_SMFC1_DEST_SEL_MASK;
+ fs_proc_flow3 |=
+ proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+ FS_SMFC1_DEST_SEL_OFFSET;
+ break;
+ case CSI_MEM2:
+ fs_proc_flow3 &= ~FS_SMFC2_DEST_SEL_MASK;
+ fs_proc_flow3 |=
+ proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+ FS_SMFC2_DEST_SEL_OFFSET;
+ break;
+ case CSI_MEM3:
+ fs_proc_flow3 &= ~FS_SMFC3_DEST_SEL_MASK;
+ fs_proc_flow3 |=
+ proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+ FS_SMFC3_DEST_SEL_OFFSET;
+ break;
+ case CSI_PRP_ENC_MEM:
+ fs_proc_flow2 &= ~FS_PRPENC_DEST_SEL_MASK;
+ fs_proc_flow2 |=
+ proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+ FS_PRPENC_DEST_SEL_OFFSET;
+ break;
+ case CSI_PRP_VF_MEM:
+ fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+ fs_proc_flow2 |=
+ proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+ FS_PRPVF_DEST_SEL_OFFSET;
+ break;
+ case MEM_PP_MEM:
+ fs_proc_flow2 &= ~FS_PP_DEST_SEL_MASK;
+ fs_proc_flow2 |=
+ proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+ FS_PP_DEST_SEL_OFFSET;
+ break;
+ case MEM_ROT_PP_MEM:
+ fs_proc_flow2 &= ~FS_PP_ROT_DEST_SEL_MASK;
+ fs_proc_flow2 |=
+ proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+ FS_PP_ROT_DEST_SEL_OFFSET;
+ break;
+ case MEM_PRP_ENC_MEM:
+ fs_proc_flow2 &= ~FS_PRPENC_DEST_SEL_MASK;
+ fs_proc_flow2 |=
+ proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+ FS_PRPENC_DEST_SEL_OFFSET;
+ break;
+ case MEM_ROT_ENC_MEM:
+ fs_proc_flow2 &= ~FS_PRPENC_ROT_DEST_SEL_MASK;
+ fs_proc_flow2 |=
+ proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+ FS_PRPENC_ROT_DEST_SEL_OFFSET;
+ break;
+ case MEM_PRP_VF_MEM:
+ fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+ fs_proc_flow2 |=
+ proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+ FS_PRPVF_DEST_SEL_OFFSET;
+ break;
+ case MEM_VDI_PRP_VF_MEM:
+ fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+ fs_proc_flow2 |=
+ proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+ FS_PRPVF_DEST_SEL_OFFSET;
+ break;
+ case MEM_ROT_VF_MEM:
+ fs_proc_flow2 &= ~FS_PRPVF_ROT_DEST_SEL_MASK;
+ fs_proc_flow2 |=
+ proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+ FS_PRPVF_ROT_DEST_SEL_OFFSET;
+ break;
+ case MEM_VDOA_MEM:
+ fs_proc_flow3 &= ~FS_VDOA_DEST_SEL_MASK;
+ if (MEM_VDI_MEM == dest_ch)
+ fs_proc_flow3 |= FS_VDOA_DEST_SEL_VDI;
+ else if (MEM_PP_MEM == dest_ch)
+ fs_proc_flow3 |= FS_VDOA_DEST_SEL_IC;
+ else {
+ retval = -EINVAL;
+ goto err;
+ }
+ break;
+ default:
+ retval = -EINVAL;
+ goto err;
+ }
+
+ switch (dest_ch) {
+ case MEM_PP_MEM:
+ fs_proc_flow1 &= ~FS_PP_SRC_SEL_MASK;
+ if (MEM_VDOA_MEM == src_ch)
+ fs_proc_flow1 |= FS_PP_SRC_SEL_VDOA;
+ else
+ fs_proc_flow1 |= proc_src_sel[IPU_CHAN_ID(src_ch)] <<
+ FS_PP_SRC_SEL_OFFSET;
+ break;
+ case MEM_ROT_PP_MEM:
+ fs_proc_flow1 &= ~FS_PP_ROT_SRC_SEL_MASK;
+ fs_proc_flow1 |=
+ proc_src_sel[IPU_CHAN_ID(src_ch)] <<
+ FS_PP_ROT_SRC_SEL_OFFSET;
+ break;
+ case MEM_PRP_ENC_MEM:
+ fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+ fs_proc_flow1 |=
+ proc_src_sel[IPU_CHAN_ID(src_ch)] << FS_PRP_SRC_SEL_OFFSET;
+ break;
+ case MEM_ROT_ENC_MEM:
+ fs_proc_flow1 &= ~FS_PRPENC_ROT_SRC_SEL_MASK;
+ fs_proc_flow1 |=
+ proc_src_sel[IPU_CHAN_ID(src_ch)] <<
+ FS_PRPENC_ROT_SRC_SEL_OFFSET;
+ break;
+ case MEM_PRP_VF_MEM:
+ fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+ fs_proc_flow1 |=
+ proc_src_sel[IPU_CHAN_ID(src_ch)] << FS_PRP_SRC_SEL_OFFSET;
+ break;
+ case MEM_VDI_PRP_VF_MEM:
+ fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+ fs_proc_flow1 |=
+ proc_src_sel[IPU_CHAN_ID(src_ch)] << FS_PRP_SRC_SEL_OFFSET;
+ break;
+ case MEM_ROT_VF_MEM:
+ fs_proc_flow1 &= ~FS_PRPVF_ROT_SRC_SEL_MASK;
+ fs_proc_flow1 |=
+ proc_src_sel[IPU_CHAN_ID(src_ch)] <<
+ FS_PRPVF_ROT_SRC_SEL_OFFSET;
+ break;
+ case MEM_DC_SYNC:
+ fs_disp_flow1 &= ~FS_DC1_SRC_SEL_MASK;
+ fs_disp_flow1 |=
+ disp_src_sel[IPU_CHAN_ID(src_ch)] << FS_DC1_SRC_SEL_OFFSET;
+ break;
+ case MEM_BG_SYNC:
+ fs_disp_flow1 &= ~FS_DP_SYNC0_SRC_SEL_MASK;
+ fs_disp_flow1 |=
+ disp_src_sel[IPU_CHAN_ID(src_ch)] <<
+ FS_DP_SYNC0_SRC_SEL_OFFSET;
+ break;
+ case MEM_FG_SYNC:
+ fs_disp_flow1 &= ~FS_DP_SYNC1_SRC_SEL_MASK;
+ fs_disp_flow1 |=
+ disp_src_sel[IPU_CHAN_ID(src_ch)] <<
+ FS_DP_SYNC1_SRC_SEL_OFFSET;
+ break;
+ case MEM_DC_ASYNC:
+ fs_disp_flow1 &= ~FS_DC2_SRC_SEL_MASK;
+ fs_disp_flow1 |=
+ disp_src_sel[IPU_CHAN_ID(src_ch)] << FS_DC2_SRC_SEL_OFFSET;
+ break;
+ case MEM_BG_ASYNC0:
+ fs_disp_flow1 &= ~FS_DP_ASYNC0_SRC_SEL_MASK;
+ fs_disp_flow1 |=
+ disp_src_sel[IPU_CHAN_ID(src_ch)] <<
+ FS_DP_ASYNC0_SRC_SEL_OFFSET;
+ break;
+ case MEM_FG_ASYNC0:
+ fs_disp_flow1 &= ~FS_DP_ASYNC1_SRC_SEL_MASK;
+ fs_disp_flow1 |=
+ disp_src_sel[IPU_CHAN_ID(src_ch)] <<
+ FS_DP_ASYNC1_SRC_SEL_OFFSET;
+ break;
+ case MEM_VDI_MEM:
+ fs_proc_flow1 &= ~FS_VDI_SRC_SEL_MASK;
+ if (MEM_VDOA_MEM == src_ch)
+ fs_proc_flow1 |= FS_VDI_SRC_SEL_VDOA;
+ else {
+ retval = -EINVAL;
+ goto err;
+ }
+ break;
+ default:
+ retval = -EINVAL;
+ goto err;
+ }
+
+ ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+ ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+ ipu_cm_write(ipu, fs_proc_flow3, IPU_FS_PROC_FLOW3);
+ ipu_cm_write(ipu, fs_disp_flow1, IPU_FS_DISP_FLOW1);
+
+err:
+ mutex_unlock(&ipu->mutex_lock);
+ return retval;
+}
+EXPORT_SYMBOL(ipu_link_channels);
+
+/*!
+ * This function unlinks 2 channels and disables automatic frame
+ * synchronization.
+ *
+ * @param ipu ipu handler
+ * @param src_ch Input parameter for the logical channel ID of
+ * the source channel.
+ *
+ * @param dest_ch Input parameter for the logical channel ID of
+ * the destination channel.
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int32_t ipu_unlink_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_channel_t dest_ch)
+{
+ int retval = 0;
+ uint32_t fs_proc_flow1;
+ uint32_t fs_proc_flow2;
+ uint32_t fs_proc_flow3;
+ uint32_t fs_disp_flow1;
+
+ mutex_lock(&ipu->mutex_lock);
+
+ fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+ fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+ fs_proc_flow3 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW3);
+ fs_disp_flow1 = ipu_cm_read(ipu, IPU_FS_DISP_FLOW1);
+
+ switch (src_ch) {
+ case CSI_MEM0:
+ fs_proc_flow3 &= ~FS_SMFC0_DEST_SEL_MASK;
+ break;
+ case CSI_MEM1:
+ fs_proc_flow3 &= ~FS_SMFC1_DEST_SEL_MASK;
+ break;
+ case CSI_MEM2:
+ fs_proc_flow3 &= ~FS_SMFC2_DEST_SEL_MASK;
+ break;
+ case CSI_MEM3:
+ fs_proc_flow3 &= ~FS_SMFC3_DEST_SEL_MASK;
+ break;
+ case CSI_PRP_ENC_MEM:
+ fs_proc_flow2 &= ~FS_PRPENC_DEST_SEL_MASK;
+ break;
+ case CSI_PRP_VF_MEM:
+ fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+ break;
+ case MEM_PP_MEM:
+ fs_proc_flow2 &= ~FS_PP_DEST_SEL_MASK;
+ break;
+ case MEM_ROT_PP_MEM:
+ fs_proc_flow2 &= ~FS_PP_ROT_DEST_SEL_MASK;
+ break;
+ case MEM_PRP_ENC_MEM:
+ fs_proc_flow2 &= ~FS_PRPENC_DEST_SEL_MASK;
+ break;
+ case MEM_ROT_ENC_MEM:
+ fs_proc_flow2 &= ~FS_PRPENC_ROT_DEST_SEL_MASK;
+ break;
+ case MEM_PRP_VF_MEM:
+ fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+ break;
+ case MEM_VDI_PRP_VF_MEM:
+ fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+ break;
+ case MEM_ROT_VF_MEM:
+ fs_proc_flow2 &= ~FS_PRPVF_ROT_DEST_SEL_MASK;
+ break;
+ case MEM_VDOA_MEM:
+ fs_proc_flow3 &= ~FS_VDOA_DEST_SEL_MASK;
+ break;
+ default:
+ retval = -EINVAL;
+ goto err;
+ }
+
+ switch (dest_ch) {
+ case MEM_PP_MEM:
+ fs_proc_flow1 &= ~FS_PP_SRC_SEL_MASK;
+ break;
+ case MEM_ROT_PP_MEM:
+ fs_proc_flow1 &= ~FS_PP_ROT_SRC_SEL_MASK;
+ break;
+ case MEM_PRP_ENC_MEM:
+ fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+ break;
+ case MEM_ROT_ENC_MEM:
+ fs_proc_flow1 &= ~FS_PRPENC_ROT_SRC_SEL_MASK;
+ break;
+ case MEM_PRP_VF_MEM:
+ fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+ break;
+ case MEM_VDI_PRP_VF_MEM:
+ fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+ break;
+ case MEM_ROT_VF_MEM:
+ fs_proc_flow1 &= ~FS_PRPVF_ROT_SRC_SEL_MASK;
+ break;
+ case MEM_DC_SYNC:
+ fs_disp_flow1 &= ~FS_DC1_SRC_SEL_MASK;
+ break;
+ case MEM_BG_SYNC:
+ fs_disp_flow1 &= ~FS_DP_SYNC0_SRC_SEL_MASK;
+ break;
+ case MEM_FG_SYNC:
+ fs_disp_flow1 &= ~FS_DP_SYNC1_SRC_SEL_MASK;
+ break;
+ case MEM_DC_ASYNC:
+ fs_disp_flow1 &= ~FS_DC2_SRC_SEL_MASK;
+ break;
+ case MEM_BG_ASYNC0:
+ fs_disp_flow1 &= ~FS_DP_ASYNC0_SRC_SEL_MASK;
+ break;
+ case MEM_FG_ASYNC0:
+ fs_disp_flow1 &= ~FS_DP_ASYNC1_SRC_SEL_MASK;
+ break;
+ case MEM_VDI_MEM:
+ fs_proc_flow1 &= ~FS_VDI_SRC_SEL_MASK;
+ break;
+ default:
+ retval = -EINVAL;
+ goto err;
+ }
+
+ ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+ ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+ ipu_cm_write(ipu, fs_proc_flow3, IPU_FS_PROC_FLOW3);
+ ipu_cm_write(ipu, fs_disp_flow1, IPU_FS_DISP_FLOW1);
+
+err:
+ mutex_unlock(&ipu->mutex_lock);
+ return retval;
+}
+EXPORT_SYMBOL(ipu_unlink_channels);
+
+/*!
+ * This function check whether a logical channel was enabled.
+ *
+ * @param ipu ipu handler
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @return This function returns 1 while request channel is enabled or
+ * 0 for not enabled.
+ */
+int32_t ipu_is_channel_busy(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+ uint32_t reg;
+ uint32_t in_dma;
+ uint32_t out_dma;
+
+ out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
+ in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+
+ reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(in_dma));
+ if (reg & idma_mask(in_dma))
+ return 1;
+ reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(out_dma));
+ if (reg & idma_mask(out_dma))
+ return 1;
+ return 0;
+}
+EXPORT_SYMBOL(ipu_is_channel_busy);
+
+/*!
+ * This function enables a logical channel.
+ *
+ * @param ipu ipu handler
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int32_t ipu_enable_channel(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+ uint32_t reg;
+ uint32_t ipu_conf;
+ uint32_t in_dma;
+ uint32_t out_dma;
+ uint32_t sec_dma;
+ uint32_t thrd_dma;
+ uint32_t di = 0;
+
+ mutex_lock(&ipu->mutex_lock);
+
+ if (ipu->channel_enable_mask & (1L << IPU_CHAN_ID(channel))) {
+ dev_err(ipu->dev, "Warning: channel already enabled %d\n",
+ IPU_CHAN_ID(channel));
+ mutex_unlock(&ipu->mutex_lock);
+ return -EACCES;
+ }
+
+ /* Get input and output dma channels */
+ out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
+ in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+
+ ipu_conf = ipu_cm_read(ipu, IPU_CONF);
+ switch (channel) {
+ case MEM_BG_SYNC:
+ di = ipu->dc_di_assignment[5];
+ if (ipu->di_use_count[di] > 0)
+ ipu_conf |= di ? IPU_CONF_DI1_EN : IPU_CONF_DI0_EN;
+ if (ipu->dp_use_count > 0)
+ ipu_conf |= IPU_CONF_DP_EN;
+ if (ipu->dc_use_count > 0)
+ ipu_conf |= IPU_CONF_DC_EN;
+ if (ipu->dmfc_use_count > 0)
+ ipu_conf |= IPU_CONF_DMFC_EN;
+ break;
+ case MEM_DC_SYNC:
+ di = ipu->dc_di_assignment[1];
+ if (ipu->di_use_count[di] > 0)
+ ipu_conf |= di ? IPU_CONF_DI1_EN : IPU_CONF_DI0_EN;
+ if (ipu->dc_use_count > 0)
+ ipu_conf |= IPU_CONF_DC_EN;
+ if (ipu->dmfc_use_count > 0)
+ ipu_conf |= IPU_CONF_DMFC_EN;
+ break;
+ case MEM_FG_SYNC:
+ if (ipu->dp_use_count > 0)
+ ipu_conf |= IPU_CONF_DP_EN;
+ if (ipu->dc_use_count > 0)
+ ipu_conf |= IPU_CONF_DC_EN;
+ if (ipu->dmfc_use_count > 0)
+ ipu_conf |= IPU_CONF_DMFC_EN;
+ break;
+ case DIRECT_ASYNC0:
+ di = ipu->dc_di_assignment[8];
+ /* fall through */
+ case DIRECT_ASYNC1:
+ di = ipu->dc_di_assignment[9];
+ if (ipu->di_use_count[di] > 0)
+ ipu_conf |= di ? IPU_CONF_DI1_EN : IPU_CONF_DI0_EN;
+ if (ipu->dc_use_count > 0)
+ ipu_conf |= IPU_CONF_DC_EN;
+ break;
+ case MEM_ROT_PP_MEM:
+ case MEM_ROT_ENC_MEM:
+ case MEM_ROT_VF_MEM:
+ if (ipu->rot_use_count > 0)
+ ipu_conf |= IPU_CONF_ROT_EN;
+ /* fall through */
+ case MEM_PP_MEM:
+ case MEM_PRP_ENC_MEM:
+ case MEM_PRP_VF_MEM:
+ case CSI_PRP_ENC_MEM:
+ case CSI_PRP_VF_MEM:
+ if (ipu->ic_use_count > 0)
+ ipu_conf |= IPU_CONF_IC_EN;
+ break;
+ case CSI_MEM0:
+ case CSI_MEM1:
+ case CSI_MEM2:
+ case CSI_MEM3:
+ if (ipu->smfc_use_count > 0)
+ ipu_conf |= IPU_CONF_SMFC_EN;
+ break;
+ case MEM_VDI_PRP_VF_MEM:
+ case MEM_VDI_MEM:
+ if (ipu->vdi_use_count > 0) {
+ ipu_conf |= IPU_CONF_ISP_EN;
+ ipu_conf |= IPU_CONF_VDI_EN;
+ ipu_conf |= IPU_CONF_IC_INPUT;
+ }
+ if (ipu->ic_use_count > 0)
+ ipu_conf |= IPU_CONF_IC_EN;
+ break;
+ default:
+ break;
+ }
+ ipu_cm_write(ipu, ipu_conf, IPU_CONF);
+
+ if (idma_is_valid(in_dma)) {
+ reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(in_dma));
+ ipu_idmac_write(ipu, reg | idma_mask(in_dma), IDMAC_CHA_EN(in_dma));
+ }
+ if (idma_is_valid(out_dma)) {
+ reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(out_dma));
+ ipu_idmac_write(ipu, reg | idma_mask(out_dma), IDMAC_CHA_EN(out_dma));
+ }
+
+ if ((ipu->sec_chan_en[IPU_CHAN_ID(channel)]) &&
+ ((channel == MEM_PP_MEM) || (channel == MEM_PRP_VF_MEM) ||
+ (channel == MEM_VDI_PRP_VF_MEM))) {
+ sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+ reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(sec_dma));
+ ipu_idmac_write(ipu, reg | idma_mask(sec_dma), IDMAC_CHA_EN(sec_dma));
+ }
+ if ((ipu->thrd_chan_en[IPU_CHAN_ID(channel)]) &&
+ ((channel == MEM_PP_MEM) || (channel == MEM_PRP_VF_MEM))) {
+ thrd_dma = channel_2_dma(channel, IPU_ALPHA_IN_BUFFER);
+ reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(thrd_dma));
+ ipu_idmac_write(ipu, reg | idma_mask(thrd_dma), IDMAC_CHA_EN(thrd_dma));
+
+ sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+ reg = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
+ ipu_idmac_write(ipu, reg | idma_mask(sec_dma), IDMAC_SEP_ALPHA);
+ } else if ((ipu->thrd_chan_en[IPU_CHAN_ID(channel)]) &&
+ ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC))) {
+ thrd_dma = channel_2_dma(channel, IPU_ALPHA_IN_BUFFER);
+ reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(thrd_dma));
+ ipu_idmac_write(ipu, reg | idma_mask(thrd_dma), IDMAC_CHA_EN(thrd_dma));
+ reg = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
+ ipu_idmac_write(ipu, reg | idma_mask(in_dma), IDMAC_SEP_ALPHA);
+ }
+
+ if ((channel == MEM_DC_SYNC) || (channel == MEM_BG_SYNC) ||
+ (channel == MEM_FG_SYNC)) {
+ reg = ipu_idmac_read(ipu, IDMAC_WM_EN(in_dma));
+ ipu_idmac_write(ipu, reg | idma_mask(in_dma), IDMAC_WM_EN(in_dma));
+
+ _ipu_dp_dc_enable(ipu, channel);
+ }
+
+ if (_ipu_is_ic_chan(in_dma) || _ipu_is_ic_chan(out_dma) ||
+ _ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma) ||
+ _ipu_is_vdi_out_chan(out_dma))
+ _ipu_ic_enable_task(ipu, channel);
+
+ ipu->channel_enable_mask |= 1L << IPU_CHAN_ID(channel);
+
+ if (ipu->prg_clk)
+ clk_prepare_enable(ipu->prg_clk);
+
+ mutex_unlock(&ipu->mutex_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_enable_channel);
+
+/*!
+ * This function check buffer ready for a logical channel.
+ *
+ * @param ipu ipu handler
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param type Input parameter which buffer to clear.
+ *
+ * @param bufNum Input parameter for which buffer number clear
+ * ready state.
+ *
+ */
+int32_t ipu_check_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
+ uint32_t bufNum)
+{
+ uint32_t dma_chan = channel_2_dma(channel, type);
+ uint32_t reg;
+ unsigned long lock_flags;
+
+ if (dma_chan == IDMA_CHAN_INVALID)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+ if (bufNum == 0)
+ reg = ipu_cm_read(ipu,
+ IPU_CHA_BUF0_RDY(ipu->devtype, dma_chan));
+ else if (bufNum == 1)
+ reg = ipu_cm_read(ipu,
+ IPU_CHA_BUF1_RDY(ipu->devtype, dma_chan));
+ else
+ reg = ipu_cm_read(ipu,
+ IPU_CHA_BUF2_RDY(ipu->devtype, dma_chan));
+ spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+ if (reg & idma_mask(dma_chan))
+ return 1;
+ else
+ return 0;
+}
+EXPORT_SYMBOL(ipu_check_buffer_ready);
+
+/*!
+ * This function clear buffer ready for a logical channel.
+ *
+ * @param ipu ipu handler
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param type Input parameter which buffer to clear.
+ *
+ * @param bufNum Input parameter for which buffer number clear
+ * ready state.
+ *
+ */
+void _ipu_clear_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
+ uint32_t bufNum)
+{
+ uint32_t dma_ch = channel_2_dma(channel, type);
+
+ if (!idma_is_valid(dma_ch))
+ return;
+
+ ipu_cm_write(ipu, 0xF0300000, IPU_GPR); /* write one to clear */
+ if (bufNum == 0)
+ ipu_cm_write(ipu, idma_mask(dma_ch),
+ IPU_CHA_BUF0_RDY(ipu->devtype, dma_ch));
+ else if (bufNum == 1)
+ ipu_cm_write(ipu, idma_mask(dma_ch),
+ IPU_CHA_BUF1_RDY(ipu->devtype, dma_ch));
+ else
+ ipu_cm_write(ipu, idma_mask(dma_ch),
+ IPU_CHA_BUF2_RDY(ipu->devtype, dma_ch));
+ ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
+}
+
+void ipu_clear_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
+ uint32_t bufNum)
+{
+ unsigned long lock_flags;
+
+ spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+ _ipu_clear_buffer_ready(ipu, channel, type, bufNum);
+ spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+}
+EXPORT_SYMBOL(ipu_clear_buffer_ready);
+
+/*!
+ * This function disables a logical channel.
+ *
+ * @param ipu ipu handler
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param wait_for_stop Flag to set whether to wait for channel end
+ * of frame or return immediately.
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int32_t ipu_disable_channel(struct ipu_soc *ipu, ipu_channel_t channel, bool wait_for_stop)
+{
+ uint32_t reg;
+ uint32_t in_dma;
+ uint32_t out_dma;
+ uint32_t sec_dma = NO_DMA;
+ uint32_t thrd_dma = NO_DMA;
+ uint16_t fg_pos_x, fg_pos_y;
+ unsigned long lock_flags;
+
+ mutex_lock(&ipu->mutex_lock);
+
+ if ((ipu->channel_enable_mask & (1L << IPU_CHAN_ID(channel))) == 0) {
+ dev_dbg(ipu->dev, "Channel already disabled %d\n",
+ IPU_CHAN_ID(channel));
+ mutex_unlock(&ipu->mutex_lock);
+ return -EACCES;
+ }
+
+ /* Get input and output dma channels */
+ out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
+ in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+
+ if ((idma_is_valid(in_dma) &&
+ !idma_is_set(ipu, IDMAC_CHA_EN(in_dma), in_dma))
+ && (idma_is_valid(out_dma) &&
+ !idma_is_set(ipu, IDMAC_CHA_EN(out_dma), out_dma))) {
+ mutex_unlock(&ipu->mutex_lock);
+ return -EINVAL;
+ }
+
+ if (ipu->sec_chan_en[IPU_CHAN_ID(channel)])
+ sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+ if (ipu->thrd_chan_en[IPU_CHAN_ID(channel)]) {
+ sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+ thrd_dma = channel_2_dma(channel, IPU_ALPHA_IN_BUFFER);
+ }
+
+ if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) ||
+ (channel == MEM_DC_SYNC)) {
+ if (channel == MEM_FG_SYNC) {
+ _ipu_disp_get_window_pos(ipu, channel, &fg_pos_x, &fg_pos_y);
+ _ipu_disp_set_window_pos(ipu, channel, 0, 0);
+ }
+
+ _ipu_dp_dc_disable(ipu, channel, false);
+
+ /*
+ * wait for BG channel EOF then disable FG-IDMAC,
+ * it avoid FG NFB4EOF error.
+ */
+ if ((channel == MEM_FG_SYNC) && (ipu_is_channel_busy(ipu, MEM_BG_SYNC))) {
+ int timeout = 50;
+
+ ipu_cm_write(ipu, IPUIRQ_2_MASK(IPU_IRQ_BG_SYNC_EOF),
+ IPUIRQ_2_STATREG(ipu->devtype,
+ IPU_IRQ_BG_SYNC_EOF));
+ while ((ipu_cm_read(ipu,
+ IPUIRQ_2_STATREG(ipu->devtype,
+ IPU_IRQ_BG_SYNC_EOF)) &
+ IPUIRQ_2_MASK(IPU_IRQ_BG_SYNC_EOF)) == 0) {
+ msleep(10);
+ timeout -= 10;
+ if (timeout <= 0) {
+ dev_err(ipu->dev, "warning: wait for bg sync eof timeout\n");
+ break;
+ }
+ }
+ }
+ } else if (wait_for_stop && !_ipu_is_smfc_chan(out_dma) &&
+ channel != CSI_PRP_VF_MEM && channel != CSI_PRP_ENC_MEM) {
+ while (idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype, in_dma),
+ in_dma) ||
+ idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype, out_dma),
+ out_dma) ||
+ (ipu->sec_chan_en[IPU_CHAN_ID(channel)] &&
+ idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype, sec_dma),
+ sec_dma)) ||
+ (ipu->thrd_chan_en[IPU_CHAN_ID(channel)] &&
+ idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype, thrd_dma),
+ thrd_dma))) {
+ uint32_t irq = 0xffffffff;
+ int timeout = 50000;
+
+ if (idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype,
+ out_dma), out_dma))
+ irq = out_dma;
+ if (ipu->sec_chan_en[IPU_CHAN_ID(channel)] &&
+ idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype,
+ sec_dma), sec_dma))
+ irq = sec_dma;
+ if (ipu->thrd_chan_en[IPU_CHAN_ID(channel)] &&
+ idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype,
+ thrd_dma), thrd_dma))
+ irq = thrd_dma;
+ if (idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype,
+ in_dma), in_dma))
+ irq = in_dma;
+
+ if (irq == 0xffffffff) {
+ dev_dbg(ipu->dev, "warning: no channel busy, break\n");
+ break;
+ }
+
+ ipu_cm_write(ipu, IPUIRQ_2_MASK(irq),
+ IPUIRQ_2_STATREG(ipu->devtype, irq));
+
+ dev_dbg(ipu->dev, "warning: channel %d busy, need wait\n", irq);
+
+ while (((ipu_cm_read(ipu,
+ IPUIRQ_2_STATREG(ipu->devtype, irq))
+ & IPUIRQ_2_MASK(irq)) == 0) &&
+ (idma_is_set(ipu, IDMAC_CHA_BUSY(ipu->devtype,
+ irq), irq))) {
+ udelay(10);
+ timeout -= 10;
+ if (timeout <= 0) {
+ ipu_dump_registers(ipu);
+ dev_err(ipu->dev, "warning: disable ipu dma channel %d during its busy state\n", irq);
+ break;
+ }
+ }
+ dev_dbg(ipu->dev, "wait_time:%d\n", 50000 - timeout);
+
+ }
+ }
+
+ if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) ||
+ (channel == MEM_DC_SYNC)) {
+ reg = ipu_idmac_read(ipu, IDMAC_WM_EN(in_dma));
+ ipu_idmac_write(ipu, reg & ~idma_mask(in_dma), IDMAC_WM_EN(in_dma));
+ }
+
+ /* Disable IC task */
+ if (_ipu_is_ic_chan(in_dma) || _ipu_is_ic_chan(out_dma) ||
+ _ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma) ||
+ _ipu_is_vdi_out_chan(out_dma))
+ _ipu_ic_disable_task(ipu, channel);
+
+ /* Disable DMA channel(s) */
+ if (idma_is_valid(in_dma)) {
+ reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(in_dma));
+ ipu_idmac_write(ipu, reg & ~idma_mask(in_dma), IDMAC_CHA_EN(in_dma));
+ ipu_cm_write(ipu, idma_mask(in_dma),
+ IPU_CHA_CUR_BUF(ipu->devtype, in_dma));
+ ipu_cm_write(ipu, tri_cur_buf_mask(in_dma),
+ IPU_CHA_TRIPLE_CUR_BUF(ipu->devtype, in_dma));
+ }
+ if (idma_is_valid(out_dma)) {
+ reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(out_dma));
+ ipu_idmac_write(ipu, reg & ~idma_mask(out_dma), IDMAC_CHA_EN(out_dma));
+ ipu_cm_write(ipu, idma_mask(out_dma),
+ IPU_CHA_CUR_BUF(ipu->devtype, out_dma));
+ ipu_cm_write(ipu, tri_cur_buf_mask(out_dma),
+ IPU_CHA_TRIPLE_CUR_BUF(ipu->devtype, out_dma));
+ }
+ if (ipu->sec_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(sec_dma)) {
+ reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(sec_dma));
+ ipu_idmac_write(ipu, reg & ~idma_mask(sec_dma), IDMAC_CHA_EN(sec_dma));
+ ipu_cm_write(ipu, idma_mask(sec_dma),
+ IPU_CHA_CUR_BUF(ipu->devtype, sec_dma));
+ }
+ if (ipu->thrd_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(thrd_dma)) {
+ reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(thrd_dma));
+ ipu_idmac_write(ipu, reg & ~idma_mask(thrd_dma), IDMAC_CHA_EN(thrd_dma));
+ if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) {
+ reg = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
+ ipu_idmac_write(ipu, reg & ~idma_mask(in_dma), IDMAC_SEP_ALPHA);
+ } else {
+ reg = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
+ ipu_idmac_write(ipu, reg & ~idma_mask(sec_dma), IDMAC_SEP_ALPHA);
+ }
+ ipu_cm_write(ipu, idma_mask(thrd_dma),
+ IPU_CHA_CUR_BUF(ipu->devtype, thrd_dma));
+ }
+
+ if (channel == MEM_FG_SYNC)
+ _ipu_disp_set_window_pos(ipu, channel, fg_pos_x, fg_pos_y);
+
+ spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+ /* Set channel buffers NOT to be ready */
+ if (idma_is_valid(in_dma)) {
+ _ipu_clear_buffer_ready(ipu, channel, IPU_VIDEO_IN_BUFFER, 0);
+ _ipu_clear_buffer_ready(ipu, channel, IPU_VIDEO_IN_BUFFER, 1);
+ _ipu_clear_buffer_ready(ipu, channel, IPU_VIDEO_IN_BUFFER, 2);
+ }
+ if (idma_is_valid(out_dma)) {
+ _ipu_clear_buffer_ready(ipu, channel, IPU_OUTPUT_BUFFER, 0);
+ _ipu_clear_buffer_ready(ipu, channel, IPU_OUTPUT_BUFFER, 1);
+ }
+ if (ipu->sec_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(sec_dma)) {
+ _ipu_clear_buffer_ready(ipu, channel, IPU_GRAPH_IN_BUFFER, 0);
+ _ipu_clear_buffer_ready(ipu, channel, IPU_GRAPH_IN_BUFFER, 1);
+ }
+ if (ipu->thrd_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(thrd_dma)) {
+ _ipu_clear_buffer_ready(ipu, channel, IPU_ALPHA_IN_BUFFER, 0);
+ _ipu_clear_buffer_ready(ipu, channel, IPU_ALPHA_IN_BUFFER, 1);
+ }
+ spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+ ipu->channel_enable_mask &= ~(1L << IPU_CHAN_ID(channel));
+
+ if (ipu->prg_clk)
+ clk_disable_unprepare(ipu->prg_clk);
+
+ mutex_unlock(&ipu->mutex_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_disable_channel);
+
+/*!
+ * This function enables CSI.
+ *
+ * @param ipu ipu handler
+ * @param csi csi num 0 or 1
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int32_t ipu_enable_csi(struct ipu_soc *ipu, uint32_t csi)
+{
+ uint32_t reg;
+
+ if (csi > 1) {
+ dev_err(ipu->dev, "Wrong csi num_%d\n", csi);
+ return -EINVAL;
+ }
+
+ _ipu_get(ipu);
+ mutex_lock(&ipu->mutex_lock);
+ ipu->csi_use_count[csi]++;
+
+ if (ipu->csi_use_count[csi] == 1) {
+ reg = ipu_cm_read(ipu, IPU_CONF);
+ if (csi == 0)
+ ipu_cm_write(ipu, reg | IPU_CONF_CSI0_EN, IPU_CONF);
+ else
+ ipu_cm_write(ipu, reg | IPU_CONF_CSI1_EN, IPU_CONF);
+ }
+ mutex_unlock(&ipu->mutex_lock);
+ _ipu_put(ipu);
+ return 0;
+}
+EXPORT_SYMBOL(ipu_enable_csi);
+
+/*!
+ * This function disables CSI.
+ *
+ * @param ipu ipu handler
+ * @param csi csi num 0 or 1
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int32_t ipu_disable_csi(struct ipu_soc *ipu, uint32_t csi)
+{
+ uint32_t reg;
+
+ if (csi > 1) {
+ dev_err(ipu->dev, "Wrong csi num_%d\n", csi);
+ return -EINVAL;
+ }
+ _ipu_get(ipu);
+ mutex_lock(&ipu->mutex_lock);
+ ipu->csi_use_count[csi]--;
+ if (ipu->csi_use_count[csi] == 0) {
+ _ipu_csi_wait4eof(ipu, ipu->csi_channel[csi]);
+ reg = ipu_cm_read(ipu, IPU_CONF);
+ if (csi == 0)
+ ipu_cm_write(ipu, reg & ~IPU_CONF_CSI0_EN, IPU_CONF);
+ else
+ ipu_cm_write(ipu, reg & ~IPU_CONF_CSI1_EN, IPU_CONF);
+ }
+ mutex_unlock(&ipu->mutex_lock);
+ _ipu_put(ipu);
+ return 0;
+}
+EXPORT_SYMBOL(ipu_disable_csi);
+
+static irqreturn_t ipu_sync_irq_handler(int irq, void *desc)
+{
+ struct ipu_soc *ipu = desc;
+ int i;
+ uint32_t line, bit, int_stat, int_ctrl;
+ irqreturn_t result = IRQ_NONE;
+ const int int_reg[] = { 1, 2, 3, 4, 11, 12, 13, 14, 15, 0 };
+
+ spin_lock(&ipu->int_reg_spin_lock);
+
+ for (i = 0; int_reg[i] != 0; i++) {
+ int_stat = ipu_cm_read(ipu,
+ IPU_INT_STAT(ipu->devtype, int_reg[i]));
+ int_ctrl = ipu_cm_read(ipu, IPU_INT_CTRL(int_reg[i]));
+ int_stat &= int_ctrl;
+ ipu_cm_write(ipu, int_stat,
+ IPU_INT_STAT(ipu->devtype, int_reg[i]));
+ while ((line = ffs(int_stat)) != 0) {
+ bit = --line;
+ int_stat &= ~(1UL << line);
+ line += (int_reg[i] - 1) * 32;
+ result |=
+ ipu->irq_list[line].handler(line,
+ ipu->irq_list[line].
+ dev_id);
+ if (ipu->irq_list[line].flags & IPU_IRQF_ONESHOT) {
+ int_ctrl &= ~(1UL << bit);
+ ipu_cm_write(ipu, int_ctrl,
+ IPU_INT_CTRL(int_reg[i]));
+ }
+ }
+ }
+
+ spin_unlock(&ipu->int_reg_spin_lock);
+
+ return result;
+}
+
+static irqreturn_t ipu_err_irq_handler(int irq, void *desc)
+{
+ struct ipu_soc *ipu = desc;
+ int i;
+ uint32_t int_stat;
+ const int err_reg[] = { 5, 6, 9, 10, 0 };
+
+ spin_lock(&ipu->int_reg_spin_lock);
+
+ for (i = 0; err_reg[i] != 0; i++) {
+ int_stat = ipu_cm_read(ipu,
+ IPU_INT_STAT(ipu->devtype, err_reg[i]));
+ int_stat &= ipu_cm_read(ipu, IPU_INT_CTRL(err_reg[i]));
+ if (int_stat) {
+ ipu_cm_write(ipu, int_stat,
+ IPU_INT_STAT(ipu->devtype, err_reg[i]));
+ dev_warn(ipu->dev,
+ "IPU Warning - IPU_INT_STAT_%d = 0x%08X\n",
+ err_reg[i], int_stat);
+ /* Disable interrupts so we only get error once */
+ int_stat = ipu_cm_read(ipu, IPU_INT_CTRL(err_reg[i])) &
+ ~int_stat;
+ ipu_cm_write(ipu, int_stat, IPU_INT_CTRL(err_reg[i]));
+ }
+ }
+
+ spin_unlock(&ipu->int_reg_spin_lock);
+
+ return IRQ_HANDLED;
+}
+
+/*!
+ * This function enables the interrupt for the specified interrupt line.
+ * The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param ipu ipu handler
+ * @param irq Interrupt line to enable interrupt for.
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int ipu_enable_irq(struct ipu_soc *ipu, uint32_t irq)
+{
+ uint32_t reg;
+ unsigned long lock_flags;
+ int ret = 0;
+
+ _ipu_get(ipu);
+
+ spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+
+ /*
+ * Check sync interrupt handler only, since we do nothing for
+ * error interrupts but than print out register values in the
+ * error interrupt source handler.
+ */
+ if (_ipu_is_sync_irq(irq) && (ipu->irq_list[irq].handler == NULL)) {
+ dev_err(ipu->dev, "handler hasn't been registered on sync "
+ "irq %d\n", irq);
+ ret = -EACCES;
+ goto out;
+ }
+
+ reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq));
+ reg |= IPUIRQ_2_MASK(irq);
+ ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq));
+out:
+ spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+ _ipu_put(ipu);
+
+ return ret;
+}
+EXPORT_SYMBOL(ipu_enable_irq);
+
+/*!
+ * This function disables the interrupt for the specified interrupt line.
+ * The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param ipu ipu handler
+ * @param irq Interrupt line to disable interrupt for.
+ *
+ */
+void ipu_disable_irq(struct ipu_soc *ipu, uint32_t irq)
+{
+ uint32_t reg;
+ unsigned long lock_flags;
+
+ _ipu_get(ipu);
+
+ spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+
+ reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq));
+ reg &= ~IPUIRQ_2_MASK(irq);
+ ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq));
+
+ spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+ _ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_disable_irq);
+
+/*!
+ * This function clears the interrupt for the specified interrupt line.
+ * The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param ipu ipu handler
+ * @param irq Interrupt line to clear interrupt for.
+ *
+ */
+void ipu_clear_irq(struct ipu_soc *ipu, uint32_t irq)
+{
+ unsigned long lock_flags;
+
+ _ipu_get(ipu);
+
+ spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+
+ ipu_cm_write(ipu, IPUIRQ_2_MASK(irq),
+ IPUIRQ_2_STATREG(ipu->devtype, irq));
+
+ spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+ _ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_clear_irq);
+
+/*!
+ * This function returns the current interrupt status for the specified
+ * interrupt line. The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param ipu ipu handler
+ * @param irq Interrupt line to get status for.
+ *
+ * @return Returns true if the interrupt is pending/asserted or false if
+ * the interrupt is not pending.
+ */
+bool ipu_get_irq_status(struct ipu_soc *ipu, uint32_t irq)
+{
+ uint32_t reg;
+ unsigned long lock_flags;
+
+ _ipu_get(ipu);
+
+ spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+ reg = ipu_cm_read(ipu, IPUIRQ_2_STATREG(ipu->devtype, irq));
+ spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+ _ipu_put(ipu);
+
+ if (reg & IPUIRQ_2_MASK(irq))
+ return true;
+ else
+ return false;
+}
+EXPORT_SYMBOL(ipu_get_irq_status);
+
+/*!
+ * This function registers an interrupt handler function for the specified
+ * interrupt line. The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param ipu ipu handler
+ * @param irq Interrupt line to get status for.
+ *
+ * @param handler Input parameter for address of the handler
+ * function.
+ *
+ * @param irq_flags Flags for interrupt mode. Currently not used.
+ *
+ * @param devname Input parameter for string name of driver
+ * registering the handler.
+ *
+ * @param dev_id Input parameter for pointer of data to be
+ * passed to the handler.
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int ipu_request_irq(struct ipu_soc *ipu, uint32_t irq,
+ irqreturn_t(*handler) (int, void *),
+ uint32_t irq_flags, const char *devname, void *dev_id)
+{
+ uint32_t reg;
+ unsigned long lock_flags;
+ int ret = 0;
+
+ BUG_ON(irq >= IPU_IRQ_COUNT);
+
+ _ipu_get(ipu);
+
+ spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+
+ if (ipu->irq_list[irq].handler != NULL) {
+ dev_err(ipu->dev,
+ "handler already installed on irq %d\n", irq);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * Check sync interrupt handler only, since we do nothing for
+ * error interrupts but than print out register values in the
+ * error interrupt source handler.
+ */
+ if (_ipu_is_sync_irq(irq) && (handler == NULL)) {
+ dev_err(ipu->dev, "handler is NULL for sync irq %d\n", irq);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ipu->irq_list[irq].handler = handler;
+ ipu->irq_list[irq].flags = irq_flags;
+ ipu->irq_list[irq].dev_id = dev_id;
+ ipu->irq_list[irq].name = devname;
+
+ /* clear irq stat for previous use */
+ ipu_cm_write(ipu, IPUIRQ_2_MASK(irq),
+ IPUIRQ_2_STATREG(ipu->devtype, irq));
+ /* enable the interrupt */
+ reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq));
+ reg |= IPUIRQ_2_MASK(irq);
+ ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq));
+out:
+ spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+ _ipu_put(ipu);
+
+ return ret;
+}
+EXPORT_SYMBOL(ipu_request_irq);
+
+/*!
+ * This function unregisters an interrupt handler for the specified interrupt
+ * line. The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param ipu ipu handler
+ * @param irq Interrupt line to get status for.
+ *
+ * @param dev_id Input parameter for pointer of data to be passed
+ * to the handler. This must match value passed to
+ * ipu_request_irq().
+ *
+ */
+void ipu_free_irq(struct ipu_soc *ipu, uint32_t irq, void *dev_id)
+{
+ uint32_t reg;
+ unsigned long lock_flags;
+
+ _ipu_get(ipu);
+
+ spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+
+ /* disable the interrupt */
+ reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq));
+ reg &= ~IPUIRQ_2_MASK(irq);
+ ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq));
+ if (ipu->irq_list[irq].dev_id == dev_id)
+ memset(&ipu->irq_list[irq], 0, sizeof(ipu->irq_list[irq]));
+
+ spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+ _ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_free_irq);
+
+uint32_t ipu_get_cur_buffer_idx(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type)
+{
+ uint32_t reg, dma_chan;
+
+ dma_chan = channel_2_dma(channel, type);
+ if (!idma_is_valid(dma_chan))
+ return -EINVAL;
+
+ reg = ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(ipu->devtype, dma_chan));
+ if ((reg & idma_mask(dma_chan)) && _ipu_is_trb_chan(ipu, dma_chan)) {
+ reg = ipu_cm_read(ipu,
+ IPU_CHA_TRIPLE_CUR_BUF(ipu->devtype, dma_chan));
+ return (reg & tri_cur_buf_mask(dma_chan)) >>
+ tri_cur_buf_shift(dma_chan);
+ } else {
+ reg = ipu_cm_read(ipu, IPU_CHA_CUR_BUF(ipu->devtype, dma_chan));
+ if (reg & idma_mask(dma_chan))
+ return 1;
+ else
+ return 0;
+ }
+}
+EXPORT_SYMBOL(ipu_get_cur_buffer_idx);
+
+uint32_t _ipu_channel_status(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+ uint32_t stat = 0;
+ uint32_t task_stat_reg = ipu_cm_read(ipu,
+ IPU_PROC_TASK_STAT(ipu->devtype));
+
+ switch (channel) {
+ case MEM_PRP_VF_MEM:
+ stat = (task_stat_reg & TSTAT_VF_MASK) >> TSTAT_VF_OFFSET;
+ break;
+ case MEM_VDI_PRP_VF_MEM:
+ stat = (task_stat_reg & TSTAT_VF_MASK) >> TSTAT_VF_OFFSET;
+ break;
+ case MEM_ROT_VF_MEM:
+ stat =
+ (task_stat_reg & TSTAT_VF_ROT_MASK) >> TSTAT_VF_ROT_OFFSET;
+ break;
+ case MEM_PRP_ENC_MEM:
+ stat = (task_stat_reg & TSTAT_ENC_MASK) >> TSTAT_ENC_OFFSET;
+ break;
+ case MEM_ROT_ENC_MEM:
+ stat =
+ (task_stat_reg & TSTAT_ENC_ROT_MASK) >>
+ TSTAT_ENC_ROT_OFFSET;
+ break;
+ case MEM_PP_MEM:
+ stat = (task_stat_reg & TSTAT_PP_MASK) >> TSTAT_PP_OFFSET;
+ break;
+ case MEM_ROT_PP_MEM:
+ stat =
+ (task_stat_reg & TSTAT_PP_ROT_MASK) >> TSTAT_PP_ROT_OFFSET;
+ break;
+
+ default:
+ stat = TASK_STAT_IDLE;
+ break;
+ }
+ return stat;
+}
+
+/*!
+ * This function check for a logical channel status
+ *
+ * @param ipu ipu handler
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @return This function returns 0 on idle and 1 on busy.
+ *
+ */
+uint32_t ipu_channel_status(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+ uint32_t dma_status;
+
+ _ipu_get(ipu);
+ mutex_lock(&ipu->mutex_lock);
+ dma_status = ipu_is_channel_busy(ipu, channel);
+ mutex_unlock(&ipu->mutex_lock);
+ _ipu_put(ipu);
+
+ dev_dbg(ipu->dev, "%s, dma_status:%d.\n", __func__, dma_status);
+
+ return dma_status;
+}
+EXPORT_SYMBOL(ipu_channel_status);
+
+int32_t ipu_swap_channel(struct ipu_soc *ipu, ipu_channel_t from_ch, ipu_channel_t to_ch)
+{
+ uint32_t reg;
+ unsigned long lock_flags;
+ int from_dma = channel_2_dma(from_ch, IPU_INPUT_BUFFER);
+ int to_dma = channel_2_dma(to_ch, IPU_INPUT_BUFFER);
+
+ mutex_lock(&ipu->mutex_lock);
+
+ /* enable target channel */
+ reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(to_dma));
+ ipu_idmac_write(ipu, reg | idma_mask(to_dma), IDMAC_CHA_EN(to_dma));
+
+ ipu->channel_enable_mask |= 1L << IPU_CHAN_ID(to_ch);
+
+ /* switch dp dc */
+ _ipu_dp_dc_disable(ipu, from_ch, true);
+
+ /* disable source channel */
+ reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(from_dma));
+ ipu_idmac_write(ipu, reg & ~idma_mask(from_dma), IDMAC_CHA_EN(from_dma));
+ ipu_cm_write(ipu, idma_mask(from_dma),
+ IPU_CHA_CUR_BUF(ipu->devtype, from_dma));
+ ipu_cm_write(ipu, tri_cur_buf_mask(from_dma),
+ IPU_CHA_TRIPLE_CUR_BUF(ipu->devtype, from_dma));
+
+ ipu->channel_enable_mask &= ~(1L << IPU_CHAN_ID(from_ch));
+
+ spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+ _ipu_clear_buffer_ready(ipu, from_ch, IPU_VIDEO_IN_BUFFER, 0);
+ _ipu_clear_buffer_ready(ipu, from_ch, IPU_VIDEO_IN_BUFFER, 1);
+ _ipu_clear_buffer_ready(ipu, from_ch, IPU_VIDEO_IN_BUFFER, 2);
+ spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+ mutex_unlock(&ipu->mutex_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_swap_channel);
+
+uint32_t bytes_per_pixel(uint32_t fmt)
+{
+ switch (fmt) {
+ case IPU_PIX_FMT_GENERIC: /*generic data */
+ case IPU_PIX_FMT_RGB332:
+ case IPU_PIX_FMT_YUV420P:
+ case IPU_PIX_FMT_YVU420P:
+ case IPU_PIX_FMT_YUV422P:
+ case IPU_PIX_FMT_YUV444P:
+ case IPU_PIX_FMT_NV12:
+ case PRE_PIX_FMT_NV21:
+ case IPU_PIX_FMT_NV16:
+ case PRE_PIX_FMT_NV61:
+ return 1;
+ break;
+ case IPU_PIX_FMT_GENERIC_16: /* generic data */
+ case IPU_PIX_FMT_RGB565:
+ case IPU_PIX_FMT_BGRA4444:
+ case IPU_PIX_FMT_BGRA5551:
+ case IPU_PIX_FMT_YUYV:
+ case IPU_PIX_FMT_UYVY:
+ case IPU_PIX_FMT_GPU16_SB_ST:
+ case IPU_PIX_FMT_GPU16_SB_SRT:
+ case IPU_PIX_FMT_GPU16_ST:
+ case IPU_PIX_FMT_GPU16_SRT:
+ return 2;
+ break;
+ case IPU_PIX_FMT_BGR24:
+ case IPU_PIX_FMT_RGB24:
+ case IPU_PIX_FMT_YUV444:
+ return 3;
+ break;
+ case IPU_PIX_FMT_GENERIC_32: /*generic data */
+ case IPU_PIX_FMT_BGR32:
+ case IPU_PIX_FMT_BGRA32:
+ case IPU_PIX_FMT_RGB32:
+ case IPU_PIX_FMT_RGBA32:
+ case IPU_PIX_FMT_ABGR32:
+ case IPU_PIX_FMT_GPU32_SB_ST:
+ case IPU_PIX_FMT_GPU32_SB_SRT:
+ case IPU_PIX_FMT_GPU32_ST:
+ case IPU_PIX_FMT_GPU32_SRT:
+ case IPU_PIX_FMT_AYUV:
+ return 4;
+ break;
+ default:
+ return 1;
+ break;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(bytes_per_pixel);
+
+ipu_color_space_t format_to_colorspace(uint32_t fmt)
+{
+ switch (fmt) {
+ case IPU_PIX_FMT_RGB666:
+ case IPU_PIX_FMT_RGB565:
+ case IPU_PIX_FMT_BGRA4444:
+ case IPU_PIX_FMT_BGRA5551:
+ case IPU_PIX_FMT_BGR24:
+ case IPU_PIX_FMT_RGB24:
+ case IPU_PIX_FMT_GBR24:
+ case IPU_PIX_FMT_BGR32:
+ case IPU_PIX_FMT_BGRA32:
+ case IPU_PIX_FMT_RGB32:
+ case IPU_PIX_FMT_RGBA32:
+ case IPU_PIX_FMT_ABGR32:
+ case IPU_PIX_FMT_LVDS666:
+ case IPU_PIX_FMT_LVDS888:
+ case IPU_PIX_FMT_GPU32_SB_ST:
+ case IPU_PIX_FMT_GPU32_SB_SRT:
+ case IPU_PIX_FMT_GPU32_ST:
+ case IPU_PIX_FMT_GPU32_SRT:
+ case IPU_PIX_FMT_GPU16_SB_ST:
+ case IPU_PIX_FMT_GPU16_SB_SRT:
+ case IPU_PIX_FMT_GPU16_ST:
+ case IPU_PIX_FMT_GPU16_SRT:
+ return RGB;
+ break;
+
+ default:
+ return YCbCr;
+ break;
+ }
+ return RGB;
+}
+EXPORT_SYMBOL(format_to_colorspace);
+
+bool ipu_pixel_format_has_alpha(uint32_t fmt)
+{
+ switch (fmt) {
+ case IPU_PIX_FMT_RGBA32:
+ case IPU_PIX_FMT_BGRA32:
+ case IPU_PIX_FMT_ABGR32:
+ return true;
+ break;
+ default:
+ return false;
+ break;
+ }
+ return false;
+}
+
+bool ipu_ch_param_bad_alpha_pos(uint32_t pixel_fmt)
+{
+ return _ipu_ch_param_bad_alpha_pos(pixel_fmt);
+}
+EXPORT_SYMBOL(ipu_ch_param_bad_alpha_pos);
+
+bool ipu_pixel_format_is_gpu_tile(uint32_t fmt)
+{
+ switch (fmt) {
+ case IPU_PIX_FMT_GPU32_SB_ST:
+ case IPU_PIX_FMT_GPU32_SB_SRT:
+ case IPU_PIX_FMT_GPU32_ST:
+ case IPU_PIX_FMT_GPU32_SRT:
+ case IPU_PIX_FMT_GPU16_SB_ST:
+ case IPU_PIX_FMT_GPU16_SB_SRT:
+ case IPU_PIX_FMT_GPU16_ST:
+ case IPU_PIX_FMT_GPU16_SRT:
+ return true;
+ default:
+ return false;
+ }
+}
+EXPORT_SYMBOL(ipu_pixel_format_is_gpu_tile);
+
+bool ipu_pixel_format_is_split_gpu_tile(uint32_t fmt)
+{
+ switch (fmt) {
+ case IPU_PIX_FMT_GPU32_SB_ST:
+ case IPU_PIX_FMT_GPU32_SB_SRT:
+ case IPU_PIX_FMT_GPU16_SB_ST:
+ case IPU_PIX_FMT_GPU16_SB_SRT:
+ return true;
+ default:
+ return false;
+ }
+}
+EXPORT_SYMBOL(ipu_pixel_format_is_split_gpu_tile);
+
+bool ipu_pixel_format_is_pre_yuv(uint32_t fmt)
+{
+ switch (fmt) {
+ case PRE_PIX_FMT_NV21:
+ case PRE_PIX_FMT_NV61:
+ return true;
+ default:
+ return false;
+ }
+}
+EXPORT_SYMBOL(ipu_pixel_format_is_pre_yuv);
+
+bool ipu_pixel_format_is_multiplanar_yuv(uint32_t fmt)
+{
+ switch (fmt) {
+ case IPU_PIX_FMT_YVU410P:
+ case IPU_PIX_FMT_YUV420P:
+ case IPU_PIX_FMT_YUV420P2:
+ case IPU_PIX_FMT_YVU420P:
+ case IPU_PIX_FMT_YUV422P:
+ case IPU_PIX_FMT_YVU422P:
+ case IPU_PIX_FMT_YUV444P:
+ case IPU_PIX_FMT_NV12:
+ case PRE_PIX_FMT_NV21:
+ case IPU_PIX_FMT_NV16:
+ case PRE_PIX_FMT_NV61:
+ return true;
+ default:
+ return false;
+ }
+}
+EXPORT_SYMBOL(ipu_pixel_format_is_multiplanar_yuv);
+
+int ipu_ch_param_get_axi_id(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type)
+{
+ uint32_t dma_chan = channel_2_dma(channel, type);
+ int axi_id;
+
+ if (!idma_is_valid(dma_chan))
+ return -EINVAL;
+
+ _ipu_get(ipu);
+ mutex_lock(&ipu->mutex_lock);
+ axi_id = _ipu_ch_param_get_axi_id(ipu, dma_chan);
+ mutex_unlock(&ipu->mutex_lock);
+ _ipu_put(ipu);
+
+ return axi_id;
+}
+EXPORT_SYMBOL(ipu_ch_param_get_axi_id);
+
+#ifdef CONFIG_PM
+int ipu_runtime_suspend(struct device *dev)
+{
+ release_bus_freq(BUS_FREQ_HIGH);
+ dev_dbg(dev, "ipu busfreq high release.\n");
+
+ return 0;
+}
+
+int ipu_runtime_resume(struct device *dev)
+{
+ request_bus_freq(BUS_FREQ_HIGH);
+ dev_dbg(dev, "ipu busfreq high requst.\n");
+
+ return 0;
+}
+
+static const struct dev_pm_ops ipu_pm_ops = {
+ SET_RUNTIME_PM_OPS(ipu_runtime_suspend, ipu_runtime_resume, NULL)
+};
+#endif
+
+/*!
+ * This structure contains pointers to the power management callback functions.
+ */
+static struct platform_driver mxcipu_driver = {
+ .driver = {
+ .name = "imx-ipuv3",
+ .of_match_table = imx_ipuv3_dt_ids,
+ #ifdef CONFIG_PM
+ .pm = &ipu_pm_ops,
+ #endif
+ },
+ .probe = ipu_probe,
+ .remove = ipu_remove,
+};
+
+int32_t __init ipu_gen_init(void)
+{
+ int32_t ret;
+
+ ret = platform_driver_register(&mxcipu_driver);
+ return 0;
+}
+
+subsys_initcall(ipu_gen_init);
+
+static void __exit ipu_gen_uninit(void)
+{
+ platform_driver_unregister(&mxcipu_driver);
+}
+
+module_exit(ipu_gen_uninit);
diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c
new file mode 100644
index 000000000000..c6cfc97a0923
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_device.c
@@ -0,0 +1,3750 @@
+/*
+ * Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_device.c
+ *
+ * @brief This file contains the IPUv3 driver device interface and fops functions.
+ *
+ * @ingroup IPU
+ */
+#include <linux/clk.h>
+#include <linux/cpumask.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/sched/rt.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+
+#include <asm/cacheflush.h>
+#include <asm/outercache.h>
+
+#include "ipu_param_mem.h"
+#include "ipu_regs.h"
+#include "vdoa.h"
+
+#define CHECK_RETCODE(cont, str, err, label, ret) \
+do { \
+ if (cont) { \
+ dev_err(t->dev, "ERR:[0x%p]-no:0x%x "#str" ret:%d," \
+ "line:%d\n", t, t->task_no, ret, __LINE__);\
+ if (ret != -EACCES) { \
+ t->state = err; \
+ goto label; \
+ } \
+ } \
+} while (0)
+
+#define CHECK_RETCODE_CONT(cont, str, err, ret) \
+do { \
+ if (cont) { \
+ dev_err(t->dev, "ERR:[0x%p]-no:0x%x"#str" ret:%d," \
+ "line:%d\n", t, t->task_no, ret, __LINE__);\
+ if (ret != -EACCES) { \
+ if (t->state == STATE_OK) \
+ t->state = err; \
+ } \
+ } \
+} while (0)
+
+#undef DBG_IPU_PERF
+#ifdef DBG_IPU_PERF
+#define CHECK_PERF(ts) \
+do { \
+ getnstimeofday(ts); \
+} while (0)
+
+#define DECLARE_PERF_VAR \
+ struct timespec ts_queue; \
+ struct timespec ts_dotask; \
+ struct timespec ts_waitirq; \
+ struct timespec ts_sche; \
+ struct timespec ts_rel; \
+ struct timespec ts_frame
+
+#define PRINT_TASK_STATISTICS \
+do { \
+ ts_queue = timespec_sub(tsk->ts_dotask, tsk->ts_queue); \
+ ts_dotask = timespec_sub(tsk->ts_waitirq, tsk->ts_dotask); \
+ ts_waitirq = timespec_sub(tsk->ts_inirq, tsk->ts_waitirq); \
+ ts_sche = timespec_sub(tsk->ts_wakeup, tsk->ts_inirq); \
+ ts_rel = timespec_sub(tsk->ts_rel, tsk->ts_wakeup); \
+ ts_frame = timespec_sub(tsk->ts_rel, tsk->ts_queue); \
+ dev_dbg(tsk->dev, "[0x%p] no-0x%x, ts_q:%ldus, ts_do:%ldus," \
+ "ts_waitirq:%ldus,ts_sche:%ldus, ts_rel:%ldus," \
+ "ts_frame: %ldus\n", tsk, tsk->task_no, \
+ ts_queue.tv_nsec / NSEC_PER_USEC + ts_queue.tv_sec * USEC_PER_SEC,\
+ ts_dotask.tv_nsec / NSEC_PER_USEC + ts_dotask.tv_sec * USEC_PER_SEC,\
+ ts_waitirq.tv_nsec / NSEC_PER_USEC + ts_waitirq.tv_sec * USEC_PER_SEC,\
+ ts_sche.tv_nsec / NSEC_PER_USEC + ts_sche.tv_sec * USEC_PER_SEC,\
+ ts_rel.tv_nsec / NSEC_PER_USEC + ts_rel.tv_sec * USEC_PER_SEC,\
+ ts_frame.tv_nsec / NSEC_PER_USEC + ts_frame.tv_sec * USEC_PER_SEC); \
+ if ((ts_frame.tv_nsec/NSEC_PER_USEC + ts_frame.tv_sec*USEC_PER_SEC) > \
+ 80000) \
+ dev_dbg(tsk->dev, "ts_frame larger than 80ms [0x%p] no-0x%x.\n"\
+ , tsk, tsk->task_no); \
+} while (0)
+#else
+#define CHECK_PERF(ts)
+#define DECLARE_PERF_VAR
+#define PRINT_TASK_STATISTICS
+#endif
+
+#define IPU_PP_CH_VF (IPU_TASK_ID_VF - 1)
+#define IPU_PP_CH_PP (IPU_TASK_ID_PP - 1)
+#define MAX_PP_CH (IPU_TASK_ID_MAX - 1)
+#define VDOA_DEF_TIMEOUT_MS (HZ/2)
+
+/* Strucutures and variables for exporting MXC IPU as device*/
+typedef enum {
+ STATE_OK = 0,
+ STATE_QUEUE,
+ STATE_IN_PROGRESS,
+ STATE_ERR,
+ STATE_TIMEOUT,
+ STATE_RES_TIMEOUT,
+ STATE_NO_IPU,
+ STATE_NO_IRQ,
+ STATE_IPU_BUSY,
+ STATE_IRQ_FAIL,
+ STATE_IRQ_TIMEOUT,
+ STATE_ENABLE_CHAN_FAIL,
+ STATE_DISABLE_CHAN_FAIL,
+ STATE_SEL_BUF_FAIL,
+ STATE_INIT_CHAN_FAIL,
+ STATE_LINK_CHAN_FAIL,
+ STATE_UNLINK_CHAN_FAIL,
+ STATE_INIT_CHAN_BUF_FAIL,
+ STATE_INIT_CHAN_BAND_FAIL,
+ STATE_SYS_NO_MEM,
+ STATE_VDOA_IRQ_TIMEOUT,
+ STATE_VDOA_IRQ_FAIL,
+ STATE_VDOA_TASK_FAIL,
+} ipu_state_t;
+
+enum {
+ INPUT_CHAN_VDI_P = 1,
+ INPUT_CHAN,
+ INPUT_CHAN_VDI_N,
+};
+
+struct ipu_state_msg {
+ int state;
+ char *msg;
+} state_msg[] = {
+ {STATE_OK, "ok"},
+ {STATE_QUEUE, "split queue"},
+ {STATE_IN_PROGRESS, "split in progress"},
+ {STATE_ERR, "error"},
+ {STATE_TIMEOUT, "split task timeout"},
+ {STATE_RES_TIMEOUT, "wait resource timeout"},
+ {STATE_NO_IPU, "no ipu found"},
+ {STATE_NO_IRQ, "no irq found for task"},
+ {STATE_IPU_BUSY, "ipu busy"},
+ {STATE_IRQ_FAIL, "request irq failed"},
+ {STATE_IRQ_TIMEOUT, "wait for irq timeout"},
+ {STATE_ENABLE_CHAN_FAIL, "ipu enable channel fail"},
+ {STATE_DISABLE_CHAN_FAIL, "ipu disable channel fail"},
+ {STATE_SEL_BUF_FAIL, "ipu select buf fail"},
+ {STATE_INIT_CHAN_FAIL, "ipu init channel fail"},
+ {STATE_LINK_CHAN_FAIL, "ipu link channel fail"},
+ {STATE_UNLINK_CHAN_FAIL, "ipu unlink channel fail"},
+ {STATE_INIT_CHAN_BUF_FAIL, "ipu init channel buffer fail"},
+ {STATE_INIT_CHAN_BAND_FAIL, "ipu init channel band mode fail"},
+ {STATE_SYS_NO_MEM, "sys no mem: -ENOMEM"},
+ {STATE_VDOA_IRQ_TIMEOUT, "wait for vdoa irq timeout"},
+ {STATE_VDOA_IRQ_FAIL, "vdoa irq fail"},
+ {STATE_VDOA_TASK_FAIL, "vdoa task fail"},
+};
+
+struct stripe_setting {
+ u32 iw;
+ u32 ih;
+ u32 ow;
+ u32 oh;
+ u32 outh_resize_ratio;
+ u32 outv_resize_ratio;
+ u32 i_left_pos;
+ u32 i_right_pos;
+ u32 i_top_pos;
+ u32 i_bottom_pos;
+ u32 o_left_pos;
+ u32 o_right_pos;
+ u32 o_top_pos;
+ u32 o_bottom_pos;
+ u32 rl_split_line;
+ u32 ud_split_line;
+};
+
+struct task_set {
+#define NULL_MODE 0x0
+#define IC_MODE 0x1
+#define ROT_MODE 0x2
+#define VDI_MODE 0x4
+#define IPU_PREPROCESS_MODE_MASK (IC_MODE | ROT_MODE | VDI_MODE)
+/* VDOA_MODE means this task use vdoa, and VDOA has two modes:
+ * BAND MODE and non-BAND MODE. Non-band mode will do transfer data
+ * to memory. BAND mode needs hareware sync with IPU, it is used default
+ * if connected to VDIC.
+ */
+#define VDOA_MODE 0x8
+#define VDOA_BAND_MODE 0x10
+ u8 mode;
+#define IC_VF 0x1
+#define IC_PP 0x2
+#define ROT_VF 0x4
+#define ROT_PP 0x8
+#define VDI_VF 0x10
+#define VDOA_ONLY 0x20
+ u8 task;
+#define NO_SPLIT 0x0
+#define RL_SPLIT 0x1
+#define UD_SPLIT 0x2
+#define LEFT_STRIPE 0x1
+#define RIGHT_STRIPE 0x2
+#define UP_STRIPE 0x4
+#define DOWN_STRIPE 0x8
+#define SPLIT_MASK 0xF
+ u8 split_mode;
+ u8 band_lines;
+ ipu_channel_t ic_chan;
+ ipu_channel_t rot_chan;
+ ipu_channel_t vdi_ic_p_chan;
+ ipu_channel_t vdi_ic_n_chan;
+
+ u32 i_off;
+ u32 i_uoff;
+ u32 i_voff;
+ u32 istride;
+
+ u32 ov_off;
+ u32 ov_uoff;
+ u32 ov_voff;
+ u32 ovstride;
+
+ u32 ov_alpha_off;
+ u32 ov_alpha_stride;
+
+ u32 o_off;
+ u32 o_uoff;
+ u32 o_voff;
+ u32 ostride;
+
+ u32 r_fmt;
+ u32 r_width;
+ u32 r_height;
+ u32 r_stride;
+ dma_addr_t r_paddr;
+
+ struct stripe_setting sp_setting;
+};
+
+struct ipu_split_task {
+ struct ipu_task task;
+ struct ipu_task_entry *parent_task;
+ struct ipu_task_entry *child_task;
+ u32 task_no;
+};
+
+struct ipu_task_entry {
+ struct ipu_input input;
+ struct ipu_output output;
+
+ bool overlay_en;
+ struct ipu_overlay overlay;
+#define DEF_TIMEOUT_MS 1000
+#define DEF_DELAY_MS 20
+ int timeout;
+ int irq;
+
+ u8 task_id;
+ u8 ipu_id;
+ u8 task_in_list;
+ u8 split_done;
+ struct mutex split_lock;
+ struct mutex vdic_lock;
+ wait_queue_head_t split_waitq;
+
+ struct list_head node;
+ struct list_head split_list;
+ struct ipu_soc *ipu;
+ struct device *dev;
+ struct task_set set;
+ wait_queue_head_t task_waitq;
+ struct completion irq_comp;
+ struct kref refcount;
+ ipu_state_t state;
+ u32 task_no;
+ atomic_t done;
+ atomic_t res_free;
+ atomic_t res_get;
+
+ struct ipu_task_entry *parent;
+ char *vditmpbuf[2];
+ u32 old_save_lines;
+ u32 old_size;
+ bool buf1filled;
+ bool buf0filled;
+
+ vdoa_handle_t vdoa_handle;
+ struct vdoa_output_mem {
+ void *vaddr;
+ dma_addr_t paddr;
+ int size;
+ } vdoa_dma;
+
+#ifdef DBG_IPU_PERF
+ struct timespec ts_queue;
+ struct timespec ts_dotask;
+ struct timespec ts_waitirq;
+ struct timespec ts_inirq;
+ struct timespec ts_wakeup;
+ struct timespec ts_rel;
+#endif
+};
+
+struct ipu_channel_tabel {
+ struct mutex lock;
+ u8 used[MXC_IPU_MAX_NUM][MAX_PP_CH];
+ u8 vdoa_used;
+};
+
+struct ipu_thread_data {
+ struct ipu_soc *ipu;
+ u32 id;
+ u32 is_vdoa;
+};
+
+struct ipu_alloc_list {
+ struct list_head list;
+ dma_addr_t phy_addr;
+ void *cpu_addr;
+ u32 size;
+ void *file_index;
+};
+
+static LIST_HEAD(ipu_alloc_list);
+static DEFINE_MUTEX(ipu_alloc_lock);
+static struct ipu_channel_tabel ipu_ch_tbl;
+static LIST_HEAD(ipu_task_list);
+static DEFINE_SPINLOCK(ipu_task_list_lock);
+static DECLARE_WAIT_QUEUE_HEAD(thread_waitq);
+static DECLARE_WAIT_QUEUE_HEAD(res_waitq);
+static atomic_t req_cnt;
+static atomic_t file_index = ATOMIC_INIT(1);
+static int major;
+static int max_ipu_no;
+static int thread_id;
+static atomic_t frame_no;
+static struct class *ipu_class;
+static struct device *ipu_dev;
+static int debug;
+module_param(debug, int, 0600);
+#ifdef DBG_IPU_PERF
+static struct timespec ts_frame_max;
+static u32 ts_frame_avg;
+static atomic_t frame_cnt;
+#endif
+
+static bool deinterlace_3_field(struct ipu_task_entry *t)
+{
+ return ((t->set.mode & VDI_MODE) &&
+ (t->input.deinterlace.motion != HIGH_MOTION));
+}
+
+static u32 tiled_filed_size(struct ipu_task_entry *t)
+{
+ u32 field_size;
+
+ /* note: page_align is required by VPU hw ouput buffer */
+ field_size = TILED_NV12_FRAME_SIZE(t->input.width, t->input.height/2);
+ return field_size;
+}
+
+static bool only_ic(u8 mode)
+{
+ mode = mode & IPU_PREPROCESS_MODE_MASK;
+ return ((mode == IC_MODE) || (mode == VDI_MODE));
+}
+
+static bool only_rot(u8 mode)
+{
+ mode = mode & IPU_PREPROCESS_MODE_MASK;
+ return (mode == ROT_MODE);
+}
+
+static bool ic_and_rot(u8 mode)
+{
+ mode = mode & IPU_PREPROCESS_MODE_MASK;
+ return ((mode == (IC_MODE | ROT_MODE)) ||
+ (mode == (VDI_MODE | ROT_MODE)));
+}
+
+static bool need_split(struct ipu_task_entry *t)
+{
+ return ((t->set.split_mode != NO_SPLIT) || (t->task_no & SPLIT_MASK));
+}
+
+unsigned int fmt_to_bpp(unsigned int pixelformat)
+{
+ u32 bpp;
+
+ switch (pixelformat) {
+ case IPU_PIX_FMT_RGB565:
+ /*interleaved 422*/
+ case IPU_PIX_FMT_YUYV:
+ case IPU_PIX_FMT_UYVY:
+ /*non-interleaved 422*/
+ case IPU_PIX_FMT_YUV422P:
+ case IPU_PIX_FMT_YVU422P:
+ bpp = 16;
+ break;
+ case IPU_PIX_FMT_BGR24:
+ case IPU_PIX_FMT_RGB24:
+ case IPU_PIX_FMT_YUV444:
+ case IPU_PIX_FMT_YUV444P:
+ bpp = 24;
+ break;
+ case IPU_PIX_FMT_BGR32:
+ case IPU_PIX_FMT_BGRA32:
+ case IPU_PIX_FMT_RGB32:
+ case IPU_PIX_FMT_RGBA32:
+ case IPU_PIX_FMT_ABGR32:
+ bpp = 32;
+ break;
+ /*non-interleaved 420*/
+ case IPU_PIX_FMT_YUV420P:
+ case IPU_PIX_FMT_YVU420P:
+ case IPU_PIX_FMT_YUV420P2:
+ case IPU_PIX_FMT_NV12:
+ bpp = 12;
+ break;
+ default:
+ bpp = 8;
+ break;
+ }
+ return bpp;
+}
+EXPORT_SYMBOL_GPL(fmt_to_bpp);
+
+cs_t colorspaceofpixel(int fmt)
+{
+ switch (fmt) {
+ case IPU_PIX_FMT_RGB565:
+ case IPU_PIX_FMT_RGB666:
+ case IPU_PIX_FMT_BGR24:
+ case IPU_PIX_FMT_RGB24:
+ case IPU_PIX_FMT_BGRA32:
+ case IPU_PIX_FMT_BGR32:
+ case IPU_PIX_FMT_RGBA32:
+ case IPU_PIX_FMT_RGB32:
+ case IPU_PIX_FMT_ABGR32:
+ return RGB_CS;
+ break;
+ case IPU_PIX_FMT_UYVY:
+ case IPU_PIX_FMT_YUYV:
+ case IPU_PIX_FMT_YUV420P2:
+ case IPU_PIX_FMT_YUV420P:
+ case IPU_PIX_FMT_YVU420P:
+ case IPU_PIX_FMT_YVU422P:
+ case IPU_PIX_FMT_YUV422P:
+ case IPU_PIX_FMT_YUV444:
+ case IPU_PIX_FMT_YUV444P:
+ case IPU_PIX_FMT_NV12:
+ case IPU_PIX_FMT_TILED_NV12:
+ case IPU_PIX_FMT_TILED_NV12F:
+ return YUV_CS;
+ break;
+ default:
+ return NULL_CS;
+ }
+}
+EXPORT_SYMBOL_GPL(colorspaceofpixel);
+
+int need_csc(int ifmt, int ofmt)
+{
+ cs_t ics, ocs;
+
+ ics = colorspaceofpixel(ifmt);
+ ocs = colorspaceofpixel(ofmt);
+
+ if ((ics == NULL_CS) || (ocs == NULL_CS))
+ return -1;
+ else if (ics != ocs)
+ return 1;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(need_csc);
+
+static int soc_max_in_width(u32 is_vdoa)
+{
+ return is_vdoa ? 8192 : 4096;
+}
+
+static int soc_max_vdi_in_width(struct ipu_soc *ipu)
+{
+ int i;
+
+ if (!ipu) {
+ for (i = 0; i < max_ipu_no; i++) {
+ ipu = ipu_get_soc(i);
+ if (!IS_ERR_OR_NULL(ipu))
+ break;
+ }
+
+ if (i == max_ipu_no)
+ return 720;
+ }
+ return IPU_MAX_VDI_IN_WIDTH(ipu->devtype);
+}
+static int soc_max_in_height(void)
+{
+ return 4096;
+}
+
+static int soc_max_out_width(void)
+{
+ /* mx51/mx53/mx6q is 1024*/
+ return 1024;
+}
+
+static int soc_max_out_height(void)
+{
+ /* mx51/mx53/mx6q is 1024*/
+ return 1024;
+}
+
+static void dump_task_info(struct ipu_task_entry *t)
+{
+ if (!debug)
+ return;
+ dev_dbg(t->dev, "[0x%p]input:\n", (void *)t);
+ dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->input.format);
+ dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->input.width);
+ dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->input.height);
+ dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", (void *)t, t->input.crop.w);
+ dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", (void *)t, t->input.crop.h);
+ dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
+ (void *)t, t->input.crop.pos.x);
+ dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
+ (void *)t, t->input.crop.pos.y);
+ dev_dbg(t->dev, "[0x%p]input buffer:\n", (void *)t);
+ dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->input.paddr);
+ dev_dbg(t->dev, "[0x%p]\ti_off = 0x%x\n", (void *)t, t->set.i_off);
+ dev_dbg(t->dev, "[0x%p]\ti_uoff = 0x%x\n", (void *)t, t->set.i_uoff);
+ dev_dbg(t->dev, "[0x%p]\ti_voff = 0x%x\n", (void *)t, t->set.i_voff);
+ dev_dbg(t->dev, "[0x%p]\tistride = %d\n", (void *)t, t->set.istride);
+ if (t->input.deinterlace.enable) {
+ dev_dbg(t->dev, "[0x%p]deinterlace enabled with:\n", (void *)t);
+ if (t->input.deinterlace.motion != HIGH_MOTION) {
+ dev_dbg(t->dev, "[0x%p]\tlow/medium motion\n", (void *)t);
+ dev_dbg(t->dev, "[0x%p]\tpaddr_n = 0x%x\n",
+ (void *)t, t->input.paddr_n);
+ } else
+ dev_dbg(t->dev, "[0x%p]\thigh motion\n", (void *)t);
+ }
+
+ dev_dbg(t->dev, "[0x%p]output:\n", (void *)t);
+ dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->output.format);
+ dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->output.width);
+ dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->output.height);
+ dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", (void *)t, t->output.crop.w);
+ dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", (void *)t, t->output.crop.h);
+ dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
+ (void *)t, t->output.crop.pos.x);
+ dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
+ (void *)t, t->output.crop.pos.y);
+ dev_dbg(t->dev, "[0x%p]\trotate = %d\n", (void *)t, t->output.rotate);
+ dev_dbg(t->dev, "[0x%p]output buffer:\n", (void *)t);
+ dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->output.paddr);
+ dev_dbg(t->dev, "[0x%p]\to_off = 0x%x\n", (void *)t, t->set.o_off);
+ dev_dbg(t->dev, "[0x%p]\to_uoff = 0x%x\n", (void *)t, t->set.o_uoff);
+ dev_dbg(t->dev, "[0x%p]\to_voff = 0x%x\n", (void *)t, t->set.o_voff);
+ dev_dbg(t->dev, "[0x%p]\tostride = %d\n", (void *)t, t->set.ostride);
+
+ if (t->overlay_en) {
+ dev_dbg(t->dev, "[0x%p]overlay:\n", (void *)t);
+ dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n",
+ (void *)t, t->overlay.format);
+ dev_dbg(t->dev, "[0x%p]\twidth = %d\n",
+ (void *)t, t->overlay.width);
+ dev_dbg(t->dev, "[0x%p]\theight = %d\n",
+ (void *)t, t->overlay.height);
+ dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n",
+ (void *)t, t->overlay.crop.w);
+ dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n",
+ (void *)t, t->overlay.crop.h);
+ dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
+ (void *)t, t->overlay.crop.pos.x);
+ dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
+ (void *)t, t->overlay.crop.pos.y);
+ dev_dbg(t->dev, "[0x%p]overlay buffer:\n", (void *)t);
+ dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n",
+ (void *)t, t->overlay.paddr);
+ dev_dbg(t->dev, "[0x%p]\tov_off = 0x%x\n",
+ (void *)t, t->set.ov_off);
+ dev_dbg(t->dev, "[0x%p]\tov_uoff = 0x%x\n",
+ (void *)t, t->set.ov_uoff);
+ dev_dbg(t->dev, "[0x%p]\tov_voff = 0x%x\n",
+ (void *)t, t->set.ov_voff);
+ dev_dbg(t->dev, "[0x%p]\tovstride = %d\n",
+ (void *)t, t->set.ovstride);
+ if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+ dev_dbg(t->dev, "[0x%p]local alpha enabled with:\n",
+ (void *)t);
+ dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n",
+ (void *)t, t->overlay.alpha.loc_alp_paddr);
+ dev_dbg(t->dev, "[0x%p]\tov_alpha_off = 0x%x\n",
+ (void *)t, t->set.ov_alpha_off);
+ dev_dbg(t->dev, "[0x%p]\tov_alpha_stride = %d\n",
+ (void *)t, t->set.ov_alpha_stride);
+ } else
+ dev_dbg(t->dev, "[0x%p]globle alpha enabled with value 0x%x\n",
+ (void *)t, t->overlay.alpha.gvalue);
+ if (t->overlay.colorkey.enable)
+ dev_dbg(t->dev, "[0x%p]colorkey enabled with value 0x%x\n",
+ (void *)t, t->overlay.colorkey.value);
+ }
+
+ dev_dbg(t->dev, "[0x%p]want task_id = %d\n", (void *)t, t->task_id);
+ dev_dbg(t->dev, "[0x%p]want task mode is 0x%x\n",
+ (void *)t, t->set.mode);
+ dev_dbg(t->dev, "[0x%p]\tIC_MODE = 0x%x\n", (void *)t, IC_MODE);
+ dev_dbg(t->dev, "[0x%p]\tROT_MODE = 0x%x\n", (void *)t, ROT_MODE);
+ dev_dbg(t->dev, "[0x%p]\tVDI_MODE = 0x%x\n", (void *)t, VDI_MODE);
+ dev_dbg(t->dev, "[0x%p]\tTask_no = 0x%x\n\n\n", (void *)t, t->task_no);
+}
+
+static void dump_check_err(struct device *dev, int err)
+{
+ switch (err) {
+ case IPU_CHECK_ERR_INPUT_CROP:
+ dev_err(dev, "input crop setting error\n");
+ break;
+ case IPU_CHECK_ERR_OUTPUT_CROP:
+ dev_err(dev, "output crop setting error\n");
+ break;
+ case IPU_CHECK_ERR_OVERLAY_CROP:
+ dev_err(dev, "overlay crop setting error\n");
+ break;
+ case IPU_CHECK_ERR_INPUT_OVER_LIMIT:
+ dev_err(dev, "input over limitation\n");
+ break;
+ case IPU_CHECK_ERR_OVERLAY_WITH_VDI:
+ dev_err(dev, "do not support overlay with deinterlace\n");
+ break;
+ case IPU_CHECK_ERR_OV_OUT_NO_FIT:
+ dev_err(dev,
+ "width/height of overlay and ic output should be same\n");
+ break;
+ case IPU_CHECK_ERR_PROC_NO_NEED:
+ dev_err(dev, "no ipu processing need\n");
+ break;
+ case IPU_CHECK_ERR_SPLIT_INPUTW_OVER:
+ dev_err(dev, "split mode input width overflow\n");
+ break;
+ case IPU_CHECK_ERR_SPLIT_INPUTH_OVER:
+ dev_err(dev, "split mode input height overflow\n");
+ break;
+ case IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER:
+ dev_err(dev, "split mode output width overflow\n");
+ break;
+ case IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER:
+ dev_err(dev, "split mode output height overflow\n");
+ break;
+ case IPU_CHECK_ERR_SPLIT_WITH_ROT:
+ dev_err(dev, "not support split mode with rotation\n");
+ break;
+ case IPU_CHECK_ERR_W_DOWNSIZE_OVER:
+ dev_err(dev, "horizontal downsizing ratio overflow\n");
+ break;
+ case IPU_CHECK_ERR_H_DOWNSIZE_OVER:
+ dev_err(dev, "vertical downsizing ratio overflow\n");
+ break;
+ default:
+ break;
+ }
+}
+
+static void dump_check_warn(struct device *dev, int warn)
+{
+ if (warn & IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN)
+ dev_warn(dev, "input u/v offset not 8 align\n");
+ if (warn & IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN)
+ dev_warn(dev, "output u/v offset not 8 align\n");
+ if (warn & IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN)
+ dev_warn(dev, "overlay u/v offset not 8 align\n");
+}
+
+static int set_crop(struct ipu_crop *crop, int width, int height, int fmt)
+{
+ if ((width == 0) || (height == 0)) {
+ pr_err("Invalid param: width=%d, height=%d\n", width, height);
+ return -EINVAL;
+ }
+
+ if ((IPU_PIX_FMT_TILED_NV12 == fmt) ||
+ (IPU_PIX_FMT_TILED_NV12F == fmt)) {
+ if (crop->w || crop->h) {
+ if (((crop->w + crop->pos.x) > width)
+ || ((crop->h + crop->pos.y) > height)
+ || (0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+ || (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+ || (0 != (crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+ || (0 != (crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+ ) {
+ pr_err("set_crop error MB align.\n");
+ return -EINVAL;
+ }
+ } else {
+ crop->pos.x = 0;
+ crop->pos.y = 0;
+ crop->w = width;
+ crop->h = height;
+ if ((0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+ || (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))) {
+ pr_err("set_crop error w/h MB align.\n");
+ return -EINVAL;
+ }
+ }
+ } else {
+ if (crop->w || crop->h) {
+ if (((crop->w + crop->pos.x) > (width + 16))
+ || ((crop->h + crop->pos.y) > height + 16)) {
+ pr_err("set_crop error exceeds width/height.\n");
+ return -EINVAL;
+ }
+ } else {
+ crop->pos.x = 0;
+ crop->pos.y = 0;
+ crop->w = width;
+ crop->h = height;
+ }
+ crop->w -= crop->w%8;
+ crop->h -= crop->h%8;
+ }
+
+ if ((crop->w == 0) || (crop->h == 0)) {
+ pr_err("Invalid crop param: crop.w=%d, crop.h=%d\n",
+ crop->w, crop->h);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void update_offset(unsigned int fmt,
+ unsigned int width, unsigned int height,
+ unsigned int pos_x, unsigned int pos_y,
+ int *off, int *uoff, int *voff, int *stride)
+{
+ /* NOTE: u v offset should based on start point of off*/
+ switch (fmt) {
+ case IPU_PIX_FMT_YUV420P2:
+ case IPU_PIX_FMT_YUV420P:
+ *off = pos_y * width + pos_x;
+ *uoff = (width * (height - pos_y) - pos_x)
+ + (width/2) * (pos_y/2) + pos_x/2;
+ /* In case height is odd, round up to even */
+ *voff = *uoff + (width/2) * ((height+1)/2);
+ break;
+ case IPU_PIX_FMT_YVU420P:
+ *off = pos_y * width + pos_x;
+ *voff = (width * (height - pos_y) - pos_x)
+ + (width/2) * (pos_y/2) + pos_x/2;
+ /* In case height is odd, round up to even */
+ *uoff = *voff + (width/2) * ((height+1)/2);
+ break;
+ case IPU_PIX_FMT_YVU422P:
+ *off = pos_y * width + pos_x;
+ *voff = (width * (height - pos_y) - pos_x)
+ + (width/2) * pos_y + pos_x/2;
+ *uoff = *voff + (width/2) * height;
+ break;
+ case IPU_PIX_FMT_YUV422P:
+ *off = pos_y * width + pos_x;
+ *uoff = (width * (height - pos_y) - pos_x)
+ + (width/2) * pos_y + pos_x/2;
+ *voff = *uoff + (width/2) * height;
+ break;
+ case IPU_PIX_FMT_YUV444P:
+ *off = pos_y * width + pos_x;
+ *uoff = width * height;
+ *voff = width * height * 2;
+ break;
+ case IPU_PIX_FMT_NV12:
+ *off = pos_y * width + pos_x;
+ *uoff = (width * (height - pos_y) - pos_x)
+ + width * (pos_y/2) + pos_x;
+ break;
+ case IPU_PIX_FMT_TILED_NV12:
+ /*
+ * tiled format, progressive:
+ * assuming that line is aligned with MB height (aligned to 16)
+ * offset = line * stride + (pixel / MB_width) * pixels_in_MB
+ * = line * stride + (pixel / 16) * 256
+ * = line * stride + pixel * 16
+ */
+ *off = pos_y * width + (pos_x << 4);
+ *uoff = ALIGN(width * height, SZ_4K) + (*off >> 1) - *off;
+ break;
+ case IPU_PIX_FMT_TILED_NV12F:
+ /*
+ * tiled format, interlaced:
+ * same as above, only number of pixels in MB is 128,
+ * instead of 256
+ */
+ *off = (pos_y >> 1) * width + (pos_x << 3);
+ *uoff = ALIGN(width * height/2, SZ_4K) + (*off >> 1) - *off;
+ break;
+ default:
+ *off = (pos_y * width + pos_x) * fmt_to_bpp(fmt)/8;
+ break;
+ }
+ *stride = width * bytes_per_pixel(fmt);
+}
+
+static int update_split_setting(struct ipu_task_entry *t, bool vdi_split)
+{
+ struct stripe_param left_stripe;
+ struct stripe_param right_stripe;
+ struct stripe_param up_stripe;
+ struct stripe_param down_stripe;
+ u32 iw, ih, ow, oh;
+ u32 max_width;
+ int ret;
+
+ if (t->output.rotate >= IPU_ROTATE_90_RIGHT)
+ return IPU_CHECK_ERR_SPLIT_WITH_ROT;
+
+ iw = t->input.crop.w;
+ ih = t->input.crop.h;
+
+ ow = t->output.crop.w;
+ oh = t->output.crop.h;
+
+ memset(&left_stripe, 0, sizeof(left_stripe));
+ memset(&right_stripe, 0, sizeof(right_stripe));
+ memset(&up_stripe, 0, sizeof(up_stripe));
+ memset(&down_stripe, 0, sizeof(down_stripe));
+
+ if (t->set.split_mode & RL_SPLIT) {
+ /*
+ * We do want equal strips: initialize stripes in case
+ * calc_stripes returns before actually doing the calculation
+ */
+ left_stripe.input_width = iw / 2;
+ left_stripe.output_width = ow / 2;
+ right_stripe.input_column = iw / 2;
+ right_stripe.output_column = ow / 2;
+
+ if (vdi_split)
+ max_width = soc_max_vdi_in_width(t->ipu);
+ else
+ max_width = soc_max_out_width();
+ ret = ipu_calc_stripes_sizes(iw,
+ ow,
+ max_width,
+ (((unsigned long long)1) << 32), /* 32bit for fractional*/
+ 1, /* equal stripes */
+ t->input.format,
+ t->output.format,
+ &left_stripe,
+ &right_stripe);
+ if (ret < 0)
+ return IPU_CHECK_ERR_W_DOWNSIZE_OVER;
+ else if (ret)
+ dev_dbg(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
+ t->task_no, ret);
+ t->set.sp_setting.iw = left_stripe.input_width;
+ t->set.sp_setting.ow = left_stripe.output_width;
+ t->set.sp_setting.outh_resize_ratio = left_stripe.irr;
+ t->set.sp_setting.i_left_pos = left_stripe.input_column;
+ t->set.sp_setting.o_left_pos = left_stripe.output_column;
+ t->set.sp_setting.i_right_pos = right_stripe.input_column;
+ t->set.sp_setting.o_right_pos = right_stripe.output_column;
+ } else {
+ t->set.sp_setting.iw = iw;
+ t->set.sp_setting.ow = ow;
+ t->set.sp_setting.outh_resize_ratio = 0;
+ t->set.sp_setting.i_left_pos = 0;
+ t->set.sp_setting.o_left_pos = 0;
+ t->set.sp_setting.i_right_pos = 0;
+ t->set.sp_setting.o_right_pos = 0;
+ }
+ if ((t->set.sp_setting.iw + t->set.sp_setting.i_right_pos) > (iw+16))
+ return IPU_CHECK_ERR_SPLIT_INPUTW_OVER;
+ if (((t->set.sp_setting.ow + t->set.sp_setting.o_right_pos) > ow)
+ || (t->set.sp_setting.ow > soc_max_out_width()))
+ return IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER;
+ if (rounddown(t->set.sp_setting.ow, 8) * 8 <=
+ rounddown(t->set.sp_setting.iw, 8))
+ return IPU_CHECK_ERR_W_DOWNSIZE_OVER;
+
+ if (t->set.split_mode & UD_SPLIT) {
+ /*
+ * We do want equal strips: initialize stripes in case
+ * calc_stripes returns before actually doing the calculation
+ */
+ up_stripe.input_width = ih / 2;
+ up_stripe.output_width = oh / 2;
+ down_stripe.input_column = ih / 2;
+ down_stripe.output_column = oh / 2;
+ ret = ipu_calc_stripes_sizes(ih,
+ oh,
+ soc_max_out_height(),
+ (((unsigned long long)1) << 32), /* 32bit for fractional*/
+ 0x1 | 0x2, /* equal stripes and vertical */
+ t->input.format,
+ t->output.format,
+ &up_stripe,
+ &down_stripe);
+ if (ret < 0)
+ return IPU_CHECK_ERR_H_DOWNSIZE_OVER;
+ else if (ret)
+ dev_err(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
+ t->task_no, ret);
+ t->set.sp_setting.ih = up_stripe.input_width;
+ t->set.sp_setting.oh = up_stripe.output_width;
+ t->set.sp_setting.outv_resize_ratio = up_stripe.irr;
+ t->set.sp_setting.i_top_pos = up_stripe.input_column;
+ t->set.sp_setting.o_top_pos = up_stripe.output_column;
+ t->set.sp_setting.i_bottom_pos = down_stripe.input_column;
+ t->set.sp_setting.o_bottom_pos = down_stripe.output_column;
+ } else {
+ t->set.sp_setting.ih = ih;
+ t->set.sp_setting.oh = oh;
+ t->set.sp_setting.outv_resize_ratio = 0;
+ t->set.sp_setting.i_top_pos = 0;
+ t->set.sp_setting.o_top_pos = 0;
+ t->set.sp_setting.i_bottom_pos = 0;
+ t->set.sp_setting.o_bottom_pos = 0;
+ }
+
+ /* downscale case: enforce limits */
+ if (((t->set.sp_setting.ih + t->set.sp_setting.i_bottom_pos) > (ih))
+ && (t->set.sp_setting.ih >= t->set.sp_setting.oh))
+ return IPU_CHECK_ERR_SPLIT_INPUTH_OVER;
+ /* upscale case: relax limits because ipu_calc_stripes_sizes() may
+ create input stripe that falls just outside of the input window */
+ else if ((t->set.sp_setting.ih + t->set.sp_setting.i_bottom_pos)
+ > (ih+16))
+ return IPU_CHECK_ERR_SPLIT_INPUTH_OVER;
+ if (((t->set.sp_setting.oh + t->set.sp_setting.o_bottom_pos) > oh)
+ || (t->set.sp_setting.oh > soc_max_out_height()))
+ return IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER;
+ if (rounddown(t->set.sp_setting.oh, 8) * 8 <=
+ rounddown(t->set.sp_setting.ih, 8))
+ return IPU_CHECK_ERR_H_DOWNSIZE_OVER;
+
+ return IPU_CHECK_OK;
+}
+
+static int check_task(struct ipu_task_entry *t)
+{
+ int tmp;
+ int ret = IPU_CHECK_OK;
+ int timeout;
+ bool vdi_split = false;
+ int ocw, och;
+
+ if ((IPU_PIX_FMT_TILED_NV12 == t->overlay.format) ||
+ (IPU_PIX_FMT_TILED_NV12F == t->overlay.format) ||
+ (IPU_PIX_FMT_TILED_NV12 == t->output.format) ||
+ (IPU_PIX_FMT_TILED_NV12F == t->output.format) ||
+ ((IPU_PIX_FMT_TILED_NV12F == t->input.format) &&
+ !t->input.deinterlace.enable)) {
+ ret = IPU_CHECK_ERR_NOT_SUPPORT;
+ goto done;
+ }
+
+ /* check input */
+ ret = set_crop(&t->input.crop, t->input.width, t->input.height,
+ t->input.format);
+ if (ret < 0) {
+ ret = IPU_CHECK_ERR_INPUT_CROP;
+ goto done;
+ } else
+ update_offset(t->input.format, t->input.width, t->input.height,
+ t->input.crop.pos.x, t->input.crop.pos.y,
+ &t->set.i_off, &t->set.i_uoff,
+ &t->set.i_voff, &t->set.istride);
+
+ /* check output */
+ ret = set_crop(&t->output.crop, t->output.width, t->output.height,
+ t->output.format);
+ if (ret < 0) {
+ ret = IPU_CHECK_ERR_OUTPUT_CROP;
+ goto done;
+ } else
+ update_offset(t->output.format,
+ t->output.width, t->output.height,
+ t->output.crop.pos.x, t->output.crop.pos.y,
+ &t->set.o_off, &t->set.o_uoff,
+ &t->set.o_voff, &t->set.ostride);
+
+ if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+ /*
+ * Cache output width and height and
+ * swap them so that we may check
+ * downsize overflow correctly.
+ */
+ ocw = t->output.crop.h;
+ och = t->output.crop.w;
+ } else {
+ ocw = t->output.crop.w;
+ och = t->output.crop.h;
+ }
+
+ if (ocw * 8 <= t->input.crop.w) {
+ ret = IPU_CHECK_ERR_W_DOWNSIZE_OVER;
+ goto done;
+ }
+
+ if (och * 8 <= t->input.crop.h) {
+ ret = IPU_CHECK_ERR_H_DOWNSIZE_OVER;
+ goto done;
+ }
+
+ if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
+ (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
+ if ((t->input.crop.w > soc_max_in_width(1)) ||
+ (t->input.crop.h > soc_max_in_height())) {
+ ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
+ goto done;
+ }
+ /* output fmt: NV12 and YUYV, now don't support resize */
+ if (((IPU_PIX_FMT_NV12 != t->output.format) &&
+ (IPU_PIX_FMT_YUYV != t->output.format)) ||
+ (t->input.crop.w != t->output.crop.w) ||
+ (t->input.crop.h != t->output.crop.h)) {
+ ret = IPU_CHECK_ERR_NOT_SUPPORT;
+ goto done;
+ }
+ }
+
+ /* check overlay if there is */
+ if (t->overlay_en) {
+ if (t->input.deinterlace.enable) {
+ ret = IPU_CHECK_ERR_OVERLAY_WITH_VDI;
+ goto done;
+ }
+
+ ret = set_crop(&t->overlay.crop, t->overlay.width,
+ t->overlay.height, t->overlay.format);
+ if (ret < 0) {
+ ret = IPU_CHECK_ERR_OVERLAY_CROP;
+ goto done;
+ } else {
+ ocw = t->output.crop.w;
+ och = t->output.crop.h;
+
+ if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+ ocw = t->output.crop.h;
+ och = t->output.crop.w;
+ }
+ if ((t->overlay.crop.w != ocw) ||
+ (t->overlay.crop.h != och)) {
+ ret = IPU_CHECK_ERR_OV_OUT_NO_FIT;
+ goto done;
+ }
+
+ update_offset(t->overlay.format,
+ t->overlay.width, t->overlay.height,
+ t->overlay.crop.pos.x, t->overlay.crop.pos.y,
+ &t->set.ov_off, &t->set.ov_uoff,
+ &t->set.ov_voff, &t->set.ovstride);
+ if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+ t->set.ov_alpha_stride = t->overlay.width;
+ t->set.ov_alpha_off = t->overlay.crop.pos.y *
+ t->overlay.width + t->overlay.crop.pos.x;
+ }
+ }
+ }
+
+ /* input overflow? */
+ if (!((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
+ (IPU_PIX_FMT_TILED_NV12F == t->input.format))) {
+ if ((t->input.crop.w > soc_max_in_width(0)) ||
+ (t->input.crop.h > soc_max_in_height())) {
+ ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
+ goto done;
+ }
+ }
+
+ /* check task mode */
+ t->set.mode = NULL_MODE;
+ t->set.split_mode = NO_SPLIT;
+
+ if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+ /*output swap*/
+ tmp = t->output.crop.w;
+ t->output.crop.w = t->output.crop.h;
+ t->output.crop.h = tmp;
+ }
+
+ if (t->output.rotate >= IPU_ROTATE_90_RIGHT)
+ t->set.mode |= ROT_MODE;
+
+ /*need resize or CSC?*/
+ if ((t->input.crop.w != t->output.crop.w) ||
+ (t->input.crop.h != t->output.crop.h) ||
+ need_csc(t->input.format, t->output.format))
+ t->set.mode |= IC_MODE;
+
+ /*need cropping?*/
+ if ((t->input.crop.w != t->input.width) ||
+ (t->input.crop.h != t->input.height) ||
+ (t->output.crop.w != t->output.width) ||
+ (t->output.crop.h != t->output.height))
+ t->set.mode |= IC_MODE;
+
+ /*need flip?*/
+ if ((t->set.mode == NULL_MODE) && (t->output.rotate > IPU_ROTATE_NONE))
+ t->set.mode |= IC_MODE;
+
+ /*need IDMAC do format(same color space)?*/
+ if ((t->set.mode == NULL_MODE) && (t->input.format != t->output.format))
+ t->set.mode |= IC_MODE;
+
+ /*overlay support*/
+ if (t->overlay_en)
+ t->set.mode |= IC_MODE;
+
+ /*deinterlace*/
+ if (t->input.deinterlace.enable) {
+ t->set.mode &= ~IC_MODE;
+ t->set.mode |= VDI_MODE;
+ }
+ if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
+ (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
+ if (t->set.mode & ROT_MODE) {
+ ret = IPU_CHECK_ERR_NOT_SUPPORT;
+ goto done;
+ }
+ t->set.mode |= VDOA_MODE;
+ if (IPU_PIX_FMT_TILED_NV12F == t->input.format)
+ t->set.mode |= VDOA_BAND_MODE;
+ t->set.mode &= ~IC_MODE;
+ }
+
+ if ((t->set.mode & (IC_MODE | VDI_MODE)) &&
+ (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
+ if (t->output.crop.w > soc_max_out_width())
+ t->set.split_mode |= RL_SPLIT;
+ if (t->output.crop.h > soc_max_out_height())
+ t->set.split_mode |= UD_SPLIT;
+ if (!t->set.split_mode && (t->set.mode & VDI_MODE) &&
+ (t->input.crop.w >
+ soc_max_vdi_in_width(t->ipu))) {
+ t->set.split_mode |= RL_SPLIT;
+ vdi_split = true;
+ }
+ if (t->set.split_mode) {
+ if ((t->set.split_mode == RL_SPLIT) ||
+ (t->set.split_mode == UD_SPLIT))
+ timeout = DEF_TIMEOUT_MS * 2 + DEF_DELAY_MS;
+ else
+ timeout = DEF_TIMEOUT_MS * 4 + DEF_DELAY_MS;
+ if (t->timeout < timeout)
+ t->timeout = timeout;
+
+ ret = update_split_setting(t, vdi_split);
+ if (ret > IPU_CHECK_ERR_MIN)
+ goto done;
+ }
+ }
+
+ if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+ /*output swap*/
+ tmp = t->output.crop.w;
+ t->output.crop.w = t->output.crop.h;
+ t->output.crop.h = tmp;
+ }
+
+ if (t->set.mode == NULL_MODE) {
+ ret = IPU_CHECK_ERR_PROC_NO_NEED;
+ goto done;
+ }
+
+ if ((t->set.i_uoff % 8) || (t->set.i_voff % 8))
+ ret |= IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN;
+ if ((t->set.o_uoff % 8) || (t->set.o_voff % 8))
+ ret |= IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN;
+ if (t->overlay_en && ((t->set.ov_uoff % 8) || (t->set.ov_voff % 8)))
+ ret |= IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN;
+
+done:
+ /* dump msg */
+ if (debug) {
+ if (ret > IPU_CHECK_ERR_MIN)
+ dump_check_err(t->dev, ret);
+ else if (ret != IPU_CHECK_OK)
+ dump_check_warn(t->dev, ret);
+ }
+
+ return ret;
+}
+
+static int prepare_task(struct ipu_task_entry *t)
+{
+ int ret = 0;
+
+ ret = check_task(t);
+ if (ret > IPU_CHECK_ERR_MIN)
+ return -EINVAL;
+
+ if (t->set.mode & VDI_MODE) {
+ t->task_id = IPU_TASK_ID_VF;
+ t->set.task = VDI_VF;
+ if (t->set.mode & ROT_MODE)
+ t->set.task |= ROT_VF;
+ }
+
+ if (VDOA_MODE == t->set.mode) {
+ if (t->set.task != 0) {
+ dev_err(t->dev, "ERR: vdoa only task:0x%x, [0x%p].\n",
+ t->set.task, t);
+ return -EINVAL;
+ }
+ t->set.task |= VDOA_ONLY;
+ }
+
+ if (VDOA_BAND_MODE & t->set.mode) {
+ /* to save band size: 1<<3 = 8 lines */
+ t->set.band_lines = 3;
+ }
+
+ dump_task_info(t);
+
+ return ret;
+}
+
+static uint32_t ic_vf_pp_is_busy(struct ipu_soc *ipu, bool is_vf)
+{
+ uint32_t status;
+ uint32_t status_vf;
+ uint32_t status_rot;
+
+ if (is_vf) {
+ status = ipu_channel_status(ipu, MEM_VDI_PRP_VF_MEM);
+ status_vf = ipu_channel_status(ipu, MEM_PRP_VF_MEM);
+ status_rot = ipu_channel_status(ipu, MEM_ROT_VF_MEM);
+ return status || status_vf || status_rot;
+ } else {
+ status = ipu_channel_status(ipu, MEM_PP_MEM);
+ status_rot = ipu_channel_status(ipu, MEM_ROT_PP_MEM);
+ return status || status_rot;
+ }
+}
+
+static int _get_vdoa_ipu_res(struct ipu_task_entry *t)
+{
+ int i;
+ struct ipu_soc *ipu;
+ u8 *used;
+ uint32_t found_ipu = 0;
+ uint32_t found_vdoa = 0;
+ struct ipu_channel_tabel *tbl = &ipu_ch_tbl;
+
+ mutex_lock(&tbl->lock);
+ if (t->set.mode & VDOA_MODE) {
+ if (NULL != t->vdoa_handle)
+ found_vdoa = 1;
+ else {
+ found_vdoa = tbl->vdoa_used ? 0 : 1;
+ if (found_vdoa) {
+ tbl->vdoa_used = 1;
+ vdoa_get_handle(&t->vdoa_handle);
+ } else
+ /* first get vdoa->ipu resource sequence */
+ goto out;
+ if (t->set.task & VDOA_ONLY)
+ goto out;
+ }
+ }
+
+ for (i = 0; i < max_ipu_no; i++) {
+ ipu = ipu_get_soc(i);
+ if (IS_ERR(ipu))
+ dev_err(t->dev, "no:0x%x,found_vdoa:%d, ipu:%d\n",
+ t->task_no, found_vdoa, i);
+
+ used = &tbl->used[i][IPU_PP_CH_VF];
+ if (t->set.mode & VDI_MODE) {
+ if (0 == *used) {
+ *used = 1;
+ found_ipu = 1;
+ break;
+ }
+ } else if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) {
+ if (0 == *used) {
+ t->task_id = IPU_TASK_ID_VF;
+ if (t->set.mode & IC_MODE)
+ t->set.task |= IC_VF;
+ if (t->set.mode & ROT_MODE)
+ t->set.task |= ROT_VF;
+ *used = 1;
+ found_ipu = 1;
+ break;
+ }
+ } else
+ dev_err(t->dev, "no:0x%x,found_vdoa:%d, mode:0x%x\n",
+ t->task_no, found_vdoa, t->set.mode);
+ }
+ if (found_ipu)
+ goto next;
+
+ for (i = 0; i < max_ipu_no; i++) {
+ ipu = ipu_get_soc(i);
+ if (IS_ERR(ipu))
+ dev_err(t->dev, "no:0x%x,found_vdoa:%d, ipu:%d\n",
+ t->task_no, found_vdoa, i);
+
+ if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) {
+ used = &tbl->used[i][IPU_PP_CH_PP];
+ if (0 == *used) {
+ t->task_id = IPU_TASK_ID_PP;
+ if (t->set.mode & IC_MODE)
+ t->set.task |= IC_PP;
+ if (t->set.mode & ROT_MODE)
+ t->set.task |= ROT_PP;
+ *used = 1;
+ found_ipu = 1;
+ break;
+ }
+ }
+ }
+
+next:
+ if (found_ipu) {
+ t->ipu = ipu;
+ t->ipu_id = i;
+ t->dev = ipu->dev;
+ if (atomic_inc_return(&t->res_get) == 2)
+ dev_err(t->dev,
+ "ERR no:0x%x,found_vdoa:%d,get ipu twice\n",
+ t->task_no, found_vdoa);
+ }
+out:
+ dev_dbg(t->dev,
+ "%s:no:0x%x,found_vdoa:%d, found_ipu:%d\n",
+ __func__, t->task_no, found_vdoa, found_ipu);
+ mutex_unlock(&tbl->lock);
+ if (t->set.task & VDOA_ONLY)
+ return found_vdoa;
+ else if (t->set.mode & VDOA_MODE)
+ return found_vdoa && found_ipu;
+ else
+ return found_ipu;
+}
+
+static void put_vdoa_ipu_res(struct ipu_task_entry *tsk, int vdoa_only)
+{
+ int ret;
+ int rel_vdoa = 0, rel_ipu = 0;
+ struct ipu_channel_tabel *tbl = &ipu_ch_tbl;
+
+ mutex_lock(&tbl->lock);
+ if (tsk->set.mode & VDOA_MODE) {
+ if (!tbl->vdoa_used && tsk->vdoa_handle)
+ dev_err(tsk->dev,
+ "ERR no:0x%x,vdoa not used,mode:0x%x\n",
+ tsk->task_no, tsk->set.mode);
+ if (tbl->vdoa_used && tsk->vdoa_handle) {
+ tbl->vdoa_used = 0;
+ vdoa_put_handle(&tsk->vdoa_handle);
+ if (tsk->ipu)
+ tsk->ipu->vdoa_en = 0;
+ rel_vdoa = 1;
+ if (vdoa_only || (tsk->set.task & VDOA_ONLY))
+ goto out;
+ }
+ }
+
+ tbl->used[tsk->ipu_id][tsk->task_id - 1] = 0;
+ rel_ipu = 1;
+ ret = atomic_inc_return(&tsk->res_free);
+ if (ret == 2)
+ dev_err(tsk->dev,
+ "ERR no:0x%x,rel_vdoa:%d,put ipu twice\n",
+ tsk->task_no, rel_vdoa);
+out:
+ dev_dbg(tsk->dev,
+ "%s:no:0x%x,rel_vdoa:%d, rel_ipu:%d\n",
+ __func__, tsk->task_no, rel_vdoa, rel_ipu);
+ mutex_unlock(&tbl->lock);
+}
+
+static int get_vdoa_ipu_res(struct ipu_task_entry *t)
+{
+ int ret;
+ uint32_t found = 0;
+
+ found = _get_vdoa_ipu_res(t);
+ if (!found) {
+ t->ipu_id = -1;
+ t->ipu = NULL;
+ /* blocking to get resource */
+ ret = atomic_inc_return(&req_cnt);
+ dev_dbg(t->dev,
+ "wait_res:no:0x%x,req_cnt:%d\n", t->task_no, ret);
+ ret = wait_event_timeout(res_waitq, _get_vdoa_ipu_res(t),
+ msecs_to_jiffies(t->timeout - DEF_DELAY_MS));
+ if (ret == 0) {
+ dev_err(t->dev, "ERR[0x%p,no-0x%x] wait_res timeout:%dms!\n",
+ t, t->task_no, t->timeout - DEF_DELAY_MS);
+ ret = -ETIMEDOUT;
+ t->state = STATE_RES_TIMEOUT;
+ goto out;
+ } else {
+ if (!(t->set.task & VDOA_ONLY) && (!t->ipu))
+ dev_err(t->dev,
+ "ERR[no-0x%x] can not get ipu!\n",
+ t->task_no);
+ ret = atomic_read(&req_cnt);
+ if (ret > 0)
+ ret = atomic_dec_return(&req_cnt);
+ else
+ dev_err(t->dev,
+ "ERR[no-0x%x] req_cnt:%d mismatch!\n",
+ t->task_no, ret);
+ dev_dbg(t->dev, "no-0x%x,[0x%p],req_cnt:%d, got_res!\n",
+ t->task_no, t, ret);
+ found = 1;
+ }
+ }
+
+out:
+ return found;
+}
+
+static struct ipu_task_entry *create_task_entry(struct ipu_task *task)
+{
+ struct ipu_task_entry *tsk;
+
+ tsk = kzalloc(sizeof(struct ipu_task_entry), GFP_KERNEL);
+ if (!tsk)
+ return ERR_PTR(-ENOMEM);
+ kref_init(&tsk->refcount);
+ tsk->state = -EINVAL;
+ tsk->ipu_id = -1;
+ tsk->dev = ipu_dev;
+ tsk->input = task->input;
+ tsk->output = task->output;
+ tsk->overlay_en = task->overlay_en;
+ if (tsk->overlay_en)
+ tsk->overlay = task->overlay;
+ if (task->timeout > DEF_TIMEOUT_MS)
+ tsk->timeout = task->timeout;
+ else
+ tsk->timeout = DEF_TIMEOUT_MS;
+
+ return tsk;
+}
+
+static void task_mem_free(struct kref *ref)
+{
+ struct ipu_task_entry *tsk =
+ container_of(ref, struct ipu_task_entry, refcount);
+ kfree(tsk);
+}
+
+int create_split_child_task(struct ipu_split_task *sp_task)
+{
+ int ret = 0;
+ struct ipu_task_entry *tsk;
+
+ tsk = create_task_entry(&sp_task->task);
+ if (IS_ERR(tsk))
+ return PTR_ERR(tsk);
+
+ sp_task->child_task = tsk;
+ tsk->task_no = sp_task->task_no;
+
+ ret = prepare_task(tsk);
+ if (ret < 0)
+ goto err;
+
+ tsk->parent = sp_task->parent_task;
+ tsk->set.sp_setting = sp_task->parent_task->set.sp_setting;
+
+ list_add(&tsk->node, &tsk->parent->split_list);
+ dev_dbg(tsk->dev, "[0x%p] sp_tsk Q list,no-0x%x\n", tsk, tsk->task_no);
+ tsk->state = STATE_QUEUE;
+ CHECK_PERF(&tsk->ts_queue);
+err:
+ return ret;
+}
+
+static inline int sp_task_check_done(struct ipu_split_task *sp_task,
+ struct ipu_task_entry *parent, int num, int *idx)
+{
+ int i;
+ int ret = 0;
+ struct ipu_task_entry *tsk;
+ struct mutex *lock = &parent->split_lock;
+
+ *idx = -EINVAL;
+ mutex_lock(lock);
+ for (i = 0; i < num; i++) {
+ tsk = sp_task[i].child_task;
+ if (tsk && tsk->split_done) {
+ *idx = i;
+ ret = 1;
+ goto out;
+ }
+ }
+
+out:
+ mutex_unlock(lock);
+ return ret;
+}
+
+static int create_split_task(
+ int stripe,
+ struct ipu_split_task *sp_task)
+{
+ struct ipu_task *task = &(sp_task->task);
+ struct ipu_task_entry *t = sp_task->parent_task;
+ int ret;
+
+ sp_task->task_no |= stripe;
+
+ task->input = t->input;
+ task->output = t->output;
+ task->overlay_en = t->overlay_en;
+ if (task->overlay_en)
+ task->overlay = t->overlay;
+ task->task_id = t->task_id;
+ if ((t->set.split_mode == RL_SPLIT) ||
+ (t->set.split_mode == UD_SPLIT))
+ task->timeout = t->timeout / 2;
+ else
+ task->timeout = t->timeout / 4;
+
+ task->input.crop.w = t->set.sp_setting.iw;
+ task->input.crop.h = t->set.sp_setting.ih;
+ if (task->overlay_en) {
+ task->overlay.crop.w = t->set.sp_setting.ow;
+ task->overlay.crop.h = t->set.sp_setting.oh;
+ }
+ if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+ task->output.crop.w = t->set.sp_setting.oh;
+ task->output.crop.h = t->set.sp_setting.ow;
+ t->set.sp_setting.rl_split_line = t->set.sp_setting.o_bottom_pos;
+ t->set.sp_setting.ud_split_line = t->set.sp_setting.o_right_pos;
+
+ } else {
+ task->output.crop.w = t->set.sp_setting.ow;
+ task->output.crop.h = t->set.sp_setting.oh;
+ t->set.sp_setting.rl_split_line = t->set.sp_setting.o_right_pos;
+ t->set.sp_setting.ud_split_line = t->set.sp_setting.o_bottom_pos;
+ }
+
+ if (stripe & LEFT_STRIPE)
+ task->input.crop.pos.x += t->set.sp_setting.i_left_pos;
+ else if (stripe & RIGHT_STRIPE)
+ task->input.crop.pos.x += t->set.sp_setting.i_right_pos;
+ if (stripe & UP_STRIPE)
+ task->input.crop.pos.y += t->set.sp_setting.i_top_pos;
+ else if (stripe & DOWN_STRIPE)
+ task->input.crop.pos.y += t->set.sp_setting.i_bottom_pos;
+
+ if (task->overlay_en) {
+ if (stripe & LEFT_STRIPE)
+ task->overlay.crop.pos.x += t->set.sp_setting.o_left_pos;
+ else if (stripe & RIGHT_STRIPE)
+ task->overlay.crop.pos.x += t->set.sp_setting.o_right_pos;
+ if (stripe & UP_STRIPE)
+ task->overlay.crop.pos.y += t->set.sp_setting.o_top_pos;
+ else if (stripe & DOWN_STRIPE)
+ task->overlay.crop.pos.y += t->set.sp_setting.o_bottom_pos;
+ }
+
+ switch (t->output.rotate) {
+ case IPU_ROTATE_NONE:
+ if (stripe & LEFT_STRIPE)
+ task->output.crop.pos.x += t->set.sp_setting.o_left_pos;
+ else if (stripe & RIGHT_STRIPE)
+ task->output.crop.pos.x += t->set.sp_setting.o_right_pos;
+ if (stripe & UP_STRIPE)
+ task->output.crop.pos.y += t->set.sp_setting.o_top_pos;
+ else if (stripe & DOWN_STRIPE)
+ task->output.crop.pos.y += t->set.sp_setting.o_bottom_pos;
+ break;
+ case IPU_ROTATE_VERT_FLIP:
+ if (stripe & LEFT_STRIPE)
+ task->output.crop.pos.x += t->set.sp_setting.o_left_pos;
+ else if (stripe & RIGHT_STRIPE)
+ task->output.crop.pos.x += t->set.sp_setting.o_right_pos;
+ if (stripe & UP_STRIPE)
+ task->output.crop.pos.y =
+ t->output.crop.pos.y + t->output.crop.h
+ - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
+ else if (stripe & DOWN_STRIPE)
+ task->output.crop.pos.y =
+ t->output.crop.pos.y + t->output.crop.h
+ - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
+ break;
+ case IPU_ROTATE_HORIZ_FLIP:
+ if (stripe & LEFT_STRIPE)
+ task->output.crop.pos.x =
+ t->output.crop.pos.x + t->output.crop.w
+ - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
+ else if (stripe & RIGHT_STRIPE)
+ task->output.crop.pos.x =
+ t->output.crop.pos.x + t->output.crop.w
+ - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
+ if (stripe & UP_STRIPE)
+ task->output.crop.pos.y += t->set.sp_setting.o_top_pos;
+ else if (stripe & DOWN_STRIPE)
+ task->output.crop.pos.y += t->set.sp_setting.o_bottom_pos;
+ break;
+ case IPU_ROTATE_180:
+ if (stripe & LEFT_STRIPE)
+ task->output.crop.pos.x =
+ t->output.crop.pos.x + t->output.crop.w
+ - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
+ else if (stripe & RIGHT_STRIPE)
+ task->output.crop.pos.x =
+ t->output.crop.pos.x + t->output.crop.w
+ - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
+ if (stripe & UP_STRIPE)
+ task->output.crop.pos.y =
+ t->output.crop.pos.y + t->output.crop.h
+ - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
+ else if (stripe & DOWN_STRIPE)
+ task->output.crop.pos.y =
+ t->output.crop.pos.y + t->output.crop.h
+ - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
+ break;
+ case IPU_ROTATE_90_RIGHT:
+ if (stripe & UP_STRIPE)
+ task->output.crop.pos.x =
+ t->output.crop.pos.x + t->output.crop.w
+ - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
+ else if (stripe & DOWN_STRIPE)
+ task->output.crop.pos.x =
+ t->output.crop.pos.x + t->output.crop.w
+ - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
+ if (stripe & LEFT_STRIPE)
+ task->output.crop.pos.y += t->set.sp_setting.o_left_pos;
+ else if (stripe & RIGHT_STRIPE)
+ task->output.crop.pos.y += t->set.sp_setting.o_right_pos;
+ break;
+ case IPU_ROTATE_90_RIGHT_HFLIP:
+ if (stripe & UP_STRIPE)
+ task->output.crop.pos.x += t->set.sp_setting.o_top_pos;
+ else if (stripe & DOWN_STRIPE)
+ task->output.crop.pos.x += t->set.sp_setting.o_bottom_pos;
+ if (stripe & LEFT_STRIPE)
+ task->output.crop.pos.y += t->set.sp_setting.o_left_pos;
+ else if (stripe & RIGHT_STRIPE)
+ task->output.crop.pos.y += t->set.sp_setting.o_right_pos;
+ break;
+ case IPU_ROTATE_90_RIGHT_VFLIP:
+ if (stripe & UP_STRIPE)
+ task->output.crop.pos.x =
+ t->output.crop.pos.x + t->output.crop.w
+ - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
+ else if (stripe & DOWN_STRIPE)
+ task->output.crop.pos.x =
+ t->output.crop.pos.x + t->output.crop.w
+ - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
+ if (stripe & LEFT_STRIPE)
+ task->output.crop.pos.y =
+ t->output.crop.pos.y + t->output.crop.h
+ - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
+ else if (stripe & RIGHT_STRIPE)
+ task->output.crop.pos.y =
+ t->output.crop.pos.y + t->output.crop.h
+ - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
+ break;
+ case IPU_ROTATE_90_LEFT:
+ if (stripe & UP_STRIPE)
+ task->output.crop.pos.x += t->set.sp_setting.o_top_pos;
+ else if (stripe & DOWN_STRIPE)
+ task->output.crop.pos.x += t->set.sp_setting.o_bottom_pos;
+ if (stripe & LEFT_STRIPE)
+ task->output.crop.pos.y =
+ t->output.crop.pos.y + t->output.crop.h
+ - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
+ else if (stripe & RIGHT_STRIPE)
+ task->output.crop.pos.y =
+ t->output.crop.pos.y + t->output.crop.h
+ - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
+ break;
+ default:
+ dev_err(t->dev, "ERR:should not be here\n");
+ break;
+ }
+
+ ret = create_split_child_task(sp_task);
+ if (ret < 0)
+ dev_err(t->dev, "ERR:create_split_child_task() ret:%d\n", ret);
+ return ret;
+}
+
+static int queue_split_task(struct ipu_task_entry *t,
+ struct ipu_split_task *sp_task, uint32_t size)
+{
+ int err[4];
+ int ret = 0;
+ int i, j;
+ struct ipu_task_entry *tsk = NULL;
+ struct mutex *lock = &t->split_lock;
+ struct mutex *vdic_lock = &t->vdic_lock;
+
+ dev_dbg(t->dev, "Split task 0x%p, no-0x%x, size:%d\n",
+ t, t->task_no, size);
+ mutex_init(lock);
+ mutex_init(vdic_lock);
+ init_waitqueue_head(&t->split_waitq);
+ INIT_LIST_HEAD(&t->split_list);
+ for (j = 0; j < size; j++) {
+ memset(&sp_task[j], 0, sizeof(*sp_task));
+ sp_task[j].parent_task = t;
+ sp_task[j].task_no = t->task_no;
+ }
+
+ if (t->set.split_mode == RL_SPLIT) {
+ i = 0;
+ err[i] = create_split_task(RIGHT_STRIPE, &sp_task[i]);
+ if (err[i] < 0)
+ goto err_start;
+ i = 1;
+ err[i] = create_split_task(LEFT_STRIPE, &sp_task[i]);
+ } else if (t->set.split_mode == UD_SPLIT) {
+ i = 0;
+ err[i] = create_split_task(DOWN_STRIPE, &sp_task[i]);
+ if (err[i] < 0)
+ goto err_start;
+ i = 1;
+ err[i] = create_split_task(UP_STRIPE, &sp_task[i]);
+ } else {
+ i = 0;
+ err[i] = create_split_task(RIGHT_STRIPE | DOWN_STRIPE, &sp_task[i]);
+ if (err[i] < 0)
+ goto err_start;
+ i = 1;
+ err[i] = create_split_task(LEFT_STRIPE | DOWN_STRIPE, &sp_task[i]);
+ if (err[i] < 0)
+ goto err_start;
+ i = 2;
+ err[i] = create_split_task(RIGHT_STRIPE | UP_STRIPE, &sp_task[i]);
+ if (err[i] < 0)
+ goto err_start;
+ i = 3;
+ err[i] = create_split_task(LEFT_STRIPE | UP_STRIPE, &sp_task[i]);
+ }
+
+err_start:
+ for (j = 0; j < (i + 1); j++) {
+ if (err[j] < 0) {
+ if (sp_task[j].child_task)
+ dev_err(t->dev,
+ "sp_task[%d],no-0x%x fail state:%d, queue err:%d.\n",
+ j, sp_task[j].child_task->task_no,
+ sp_task[j].child_task->state, err[j]);
+ goto err_exit;
+ }
+ dev_dbg(t->dev, "[0x%p] sp_task[%d], no-0x%x state:%s, queue ret:%d.\n",
+ sp_task[j].child_task, j, sp_task[j].child_task->task_no,
+ state_msg[sp_task[j].child_task->state].msg, err[j]);
+ }
+
+ return ret;
+
+err_exit:
+ for (j = 0; j < (i + 1); j++) {
+ if (err[j] < 0 && !ret)
+ ret = err[j];
+ tsk = sp_task[j].child_task;
+ if (!tsk)
+ continue;
+ kfree(tsk);
+ }
+ t->state = STATE_ERR;
+ return ret;
+
+}
+
+static int init_tiled_buf(struct ipu_soc *ipu, struct ipu_task_entry *t,
+ ipu_channel_t channel, uint32_t ch_type)
+{
+ int ret = 0;
+ int i;
+ uint32_t ipu_fmt;
+ dma_addr_t inbuf_base = 0;
+ u32 field_size;
+ struct vdoa_params param;
+ struct vdoa_ipu_buf buf;
+ struct ipu_soc *ipu_idx;
+ u32 ipu_stride, obuf_size;
+ u32 height, width;
+ ipu_buffer_t type;
+
+ if ((IPU_PIX_FMT_YUYV != t->output.format) &&
+ (IPU_PIX_FMT_NV12 != t->output.format)) {
+ dev_err(t->dev, "ERR:[0x%d] output format\n", t->task_no);
+ return -EINVAL;
+ }
+
+ memset(&param, 0, sizeof(param));
+ /* init channel tiled bufs */
+ if (deinterlace_3_field(t) &&
+ (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
+ field_size = tiled_filed_size(t);
+ if (INPUT_CHAN_VDI_P == ch_type) {
+ inbuf_base = t->input.paddr + field_size;
+ param.vfield_buf.prev_veba = inbuf_base + t->set.i_off;
+ } else if (INPUT_CHAN == ch_type) {
+ inbuf_base = t->input.paddr_n;
+ param.vfield_buf.cur_veba = inbuf_base + t->set.i_off;
+ } else if (INPUT_CHAN_VDI_N == ch_type) {
+ inbuf_base = t->input.paddr_n + field_size;
+ param.vfield_buf.next_veba = inbuf_base + t->set.i_off;
+ } else
+ return -EINVAL;
+ height = t->input.crop.h >> 1; /* field format for vdoa */
+ width = t->input.crop.w;
+ param.vfield_buf.vubo = t->set.i_uoff;
+ param.interlaced = 1;
+ param.scan_order = 1;
+ type = IPU_INPUT_BUFFER;
+ } else if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) &&
+ (INPUT_CHAN == ch_type)) {
+ height = t->input.crop.h;
+ width = t->input.crop.w;
+ param.vframe_buf.veba = t->input.paddr + t->set.i_off;
+ param.vframe_buf.vubo = t->set.i_uoff;
+ type = IPU_INPUT_BUFFER;
+ } else
+ return -EINVAL;
+
+ param.band_mode = (t->set.mode & VDOA_BAND_MODE) ? 1 : 0;
+ if (param.band_mode && (t->set.band_lines != 3) &&
+ (t->set.band_lines != 4) && (t->set.band_lines != 5))
+ return -EINVAL;
+ else if (param.band_mode)
+ param.band_lines = (1 << t->set.band_lines);
+ for (i = 0; i < max_ipu_no; i++) {
+ ipu_idx = ipu_get_soc(i);
+ if (!IS_ERR(ipu_idx) && ipu_idx == ipu)
+ break;
+ }
+ if (t->set.task & VDOA_ONLY)
+ /* dummy, didn't need ipu res */
+ i = 0;
+ if (max_ipu_no == i) {
+ dev_err(t->dev, "ERR:[0x%p] get ipu num\n", t);
+ return -EINVAL;
+ }
+
+ param.ipu_num = i;
+ param.vpu_stride = t->input.width;
+ param.height = height;
+ param.width = width;
+ if (IPU_PIX_FMT_NV12 == t->output.format)
+ param.pfs = VDOA_PFS_NV12;
+ else
+ param.pfs = VDOA_PFS_YUYV;
+ ipu_fmt = (param.pfs == VDOA_PFS_YUYV) ? IPU_PIX_FMT_YUYV :
+ IPU_PIX_FMT_NV12;
+ ipu_stride = param.width * bytes_per_pixel(ipu_fmt);
+ obuf_size = PAGE_ALIGN(param.width * param.height *
+ fmt_to_bpp(ipu_fmt)/8);
+ dev_dbg(t->dev, "band_mode:%d, band_lines:%d\n",
+ param.band_mode, param.band_lines);
+ if (!param.band_mode) {
+ /* note: if only for tiled -> raster convert and
+ no other post-processing, we don't need alloc buf
+ and use output buffer directly.
+ */
+ if (t->set.task & VDOA_ONLY)
+ param.ieba0 = t->output.paddr;
+ else {
+ dev_err(t->dev, "ERR:[0x%d] vdoa task\n", t->task_no);
+ return -EINVAL;
+ }
+ } else {
+ if (IPU_PIX_FMT_TILED_NV12F != t->input.format) {
+ dev_err(t->dev, "ERR [0x%d] vdoa task\n", t->task_no);
+ return -EINVAL;
+ }
+ }
+ ret = vdoa_setup(t->vdoa_handle, &param);
+ if (ret)
+ goto done;
+ vdoa_get_output_buf(t->vdoa_handle, &buf);
+ if (t->set.task & VDOA_ONLY)
+ goto done;
+
+ ret = ipu_init_channel_buffer(ipu,
+ channel,
+ type,
+ ipu_fmt,
+ width,
+ height,
+ ipu_stride,
+ IPU_ROTATE_NONE,
+ buf.ieba0,
+ buf.ieba1,
+ 0,
+ buf.iubo,
+ 0);
+ if (ret < 0) {
+ t->state = STATE_INIT_CHAN_BUF_FAIL;
+ goto done;
+ }
+
+ if (param.band_mode) {
+ ret = ipu_set_channel_bandmode(ipu, channel,
+ type, t->set.band_lines);
+ if (ret < 0) {
+ t->state = STATE_INIT_CHAN_BAND_FAIL;
+ goto done;
+ }
+ }
+done:
+ return ret;
+}
+
+static int init_tiled_ch_bufs(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+ int ret = 0;
+
+ if (IPU_PIX_FMT_TILED_NV12 == t->input.format) {
+ ret = init_tiled_buf(ipu, t, t->set.ic_chan, INPUT_CHAN);
+ CHECK_RETCODE(ret < 0, "init tiled_ch", t->state, done, ret);
+ } else if (IPU_PIX_FMT_TILED_NV12F == t->input.format) {
+ ret = init_tiled_buf(ipu, t, t->set.ic_chan, INPUT_CHAN);
+ CHECK_RETCODE(ret < 0, "init tiled_ch-c", t->state, done, ret);
+ ret = init_tiled_buf(ipu, t, t->set.vdi_ic_p_chan,
+ INPUT_CHAN_VDI_P);
+ CHECK_RETCODE(ret < 0, "init tiled_ch-p", t->state, done, ret);
+ ret = init_tiled_buf(ipu, t, t->set.vdi_ic_n_chan,
+ INPUT_CHAN_VDI_N);
+ CHECK_RETCODE(ret < 0, "init tiled_ch-n", t->state, done, ret);
+ } else {
+ ret = -EINVAL;
+ dev_err(t->dev, "ERR[no-0x%x] invalid fmt:0x%x!\n",
+ t->task_no, t->input.format);
+ }
+
+done:
+ return ret;
+}
+
+static int init_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+ int ret = 0;
+ ipu_channel_params_t params;
+ dma_addr_t inbuf = 0, ovbuf = 0, ov_alp_buf = 0;
+ dma_addr_t inbuf_p = 0, inbuf_n = 0;
+ dma_addr_t outbuf = 0;
+ int out_uoff = 0, out_voff = 0, out_rot;
+ int out_w = 0, out_h = 0, out_stride;
+ int out_fmt;
+ u32 vdi_frame_idx = 0;
+
+ memset(&params, 0, sizeof(params));
+
+ /* is it need link a rot channel */
+ if (ic_and_rot(t->set.mode)) {
+ outbuf = t->set.r_paddr;
+ out_w = t->set.r_width;
+ out_h = t->set.r_height;
+ out_stride = t->set.r_stride;
+ out_fmt = t->set.r_fmt;
+ out_uoff = 0;
+ out_voff = 0;
+ out_rot = IPU_ROTATE_NONE;
+ } else {
+ outbuf = t->output.paddr + t->set.o_off;
+ out_w = t->output.crop.w;
+ out_h = t->output.crop.h;
+ out_stride = t->set.ostride;
+ out_fmt = t->output.format;
+ out_uoff = t->set.o_uoff;
+ out_voff = t->set.o_voff;
+ out_rot = t->output.rotate;
+ }
+
+ /* settings */
+ params.mem_prp_vf_mem.in_width = t->input.crop.w;
+ params.mem_prp_vf_mem.out_width = out_w;
+ params.mem_prp_vf_mem.in_height = t->input.crop.h;
+ params.mem_prp_vf_mem.out_height = out_h;
+ params.mem_prp_vf_mem.in_pixel_fmt = t->input.format;
+ params.mem_prp_vf_mem.out_pixel_fmt = out_fmt;
+ params.mem_prp_vf_mem.motion_sel = t->input.deinterlace.motion;
+
+ params.mem_prp_vf_mem.outh_resize_ratio =
+ t->set.sp_setting.outh_resize_ratio;
+ params.mem_prp_vf_mem.outv_resize_ratio =
+ t->set.sp_setting.outv_resize_ratio;
+
+ if (t->overlay_en) {
+ params.mem_prp_vf_mem.in_g_pixel_fmt = t->overlay.format;
+ params.mem_prp_vf_mem.graphics_combine_en = 1;
+ if (t->overlay.alpha.mode == IPU_ALPHA_MODE_GLOBAL)
+ params.mem_prp_vf_mem.global_alpha_en = 1;
+ else if (t->overlay.alpha.loc_alp_paddr)
+ params.mem_prp_vf_mem.alpha_chan_en = 1;
+ /* otherwise, alpha bending per pixel is used. */
+ params.mem_prp_vf_mem.alpha = t->overlay.alpha.gvalue;
+ if (t->overlay.colorkey.enable) {
+ params.mem_prp_vf_mem.key_color_en = 1;
+ params.mem_prp_vf_mem.key_color = t->overlay.colorkey.value;
+ }
+ }
+
+ if (t->input.deinterlace.enable) {
+ if (t->input.deinterlace.field_fmt & IPU_DEINTERLACE_FIELD_MASK)
+ params.mem_prp_vf_mem.field_fmt =
+ IPU_DEINTERLACE_FIELD_BOTTOM;
+ else
+ params.mem_prp_vf_mem.field_fmt =
+ IPU_DEINTERLACE_FIELD_TOP;
+
+ if (t->input.deinterlace.field_fmt & IPU_DEINTERLACE_RATE_EN)
+ vdi_frame_idx = t->input.deinterlace.field_fmt &
+ IPU_DEINTERLACE_RATE_FRAME1;
+ }
+
+ if (t->set.mode & VDOA_MODE)
+ ipu->vdoa_en = 1;
+
+ /* init channels */
+ if (!(t->set.task & VDOA_ONLY)) {
+ ret = ipu_init_channel(ipu, t->set.ic_chan, &params);
+ if (ret < 0) {
+ t->state = STATE_INIT_CHAN_FAIL;
+ goto done;
+ }
+ }
+
+ if (deinterlace_3_field(t)) {
+ ret = ipu_init_channel(ipu, t->set.vdi_ic_p_chan, &params);
+ if (ret < 0) {
+ t->state = STATE_INIT_CHAN_FAIL;
+ goto done;
+ }
+ ret = ipu_init_channel(ipu, t->set.vdi_ic_n_chan, &params);
+ if (ret < 0) {
+ t->state = STATE_INIT_CHAN_FAIL;
+ goto done;
+ }
+ }
+
+ /* init channel bufs */
+ if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
+ (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
+ ret = init_tiled_ch_bufs(ipu, t);
+ if (ret < 0)
+ goto done;
+ } else {
+ if ((deinterlace_3_field(t)) &&
+ (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
+ if (params.mem_prp_vf_mem.field_fmt ==
+ IPU_DEINTERLACE_FIELD_TOP) {
+ if (vdi_frame_idx) {
+ inbuf_p = t->input.paddr + t->set.istride +
+ t->set.i_off;
+ inbuf = t->input.paddr_n + t->set.i_off;
+ inbuf_n = t->input.paddr_n + t->set.istride +
+ t->set.i_off;
+ params.mem_prp_vf_mem.field_fmt =
+ IPU_DEINTERLACE_FIELD_BOTTOM;
+ } else {
+ inbuf_p = t->input.paddr + t->set.i_off;
+ inbuf = t->input.paddr + t->set.istride + t->set.i_off;
+ inbuf_n = t->input.paddr_n + t->set.i_off;
+ }
+ } else {
+ if (vdi_frame_idx) {
+ inbuf_p = t->input.paddr + t->set.i_off;
+ inbuf = t->input.paddr_n + t->set.istride + t->set.i_off;
+ inbuf_n = t->input.paddr_n + t->set.i_off;
+ params.mem_prp_vf_mem.field_fmt =
+ IPU_DEINTERLACE_FIELD_TOP;
+ } else {
+ inbuf_p = t->input.paddr + t->set.istride +
+ t->set.i_off;
+ inbuf = t->input.paddr + t->set.i_off;
+ inbuf_n = t->input.paddr_n + t->set.istride +
+ t->set.i_off;
+ }
+ }
+ } else {
+ if (t->input.deinterlace.enable) {
+ if (params.mem_prp_vf_mem.field_fmt ==
+ IPU_DEINTERLACE_FIELD_TOP) {
+ if (vdi_frame_idx) {
+ inbuf = t->input.paddr + t->set.istride + t->set.i_off;
+ params.mem_prp_vf_mem.field_fmt =
+ IPU_DEINTERLACE_FIELD_BOTTOM;
+ } else
+ inbuf = t->input.paddr + t->set.i_off;
+ } else {
+ if (vdi_frame_idx) {
+ inbuf = t->input.paddr + t->set.i_off;
+ params.mem_prp_vf_mem.field_fmt =
+ IPU_DEINTERLACE_FIELD_TOP;
+ } else
+ inbuf = t->input.paddr + t->set.istride + t->set.i_off;
+ }
+ } else
+ inbuf = t->input.paddr + t->set.i_off;
+ }
+
+ if (t->overlay_en)
+ ovbuf = t->overlay.paddr + t->set.ov_off;
+ }
+ if (t->overlay_en && (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL))
+ ov_alp_buf = t->overlay.alpha.loc_alp_paddr
+ + t->set.ov_alpha_off;
+
+ if ((IPU_PIX_FMT_TILED_NV12 != t->input.format) &&
+ (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
+ ret = ipu_init_channel_buffer(ipu,
+ t->set.ic_chan,
+ IPU_INPUT_BUFFER,
+ t->input.format,
+ t->input.crop.w,
+ t->input.crop.h,
+ t->set.istride,
+ IPU_ROTATE_NONE,
+ inbuf,
+ 0,
+ 0,
+ t->set.i_uoff,
+ t->set.i_voff);
+ if (ret < 0) {
+ t->state = STATE_INIT_CHAN_BUF_FAIL;
+ goto done;
+ }
+ }
+ if (deinterlace_3_field(t) &&
+ (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
+ ret = ipu_init_channel_buffer(ipu,
+ t->set.vdi_ic_p_chan,
+ IPU_INPUT_BUFFER,
+ t->input.format,
+ t->input.crop.w,
+ t->input.crop.h,
+ t->set.istride,
+ IPU_ROTATE_NONE,
+ inbuf_p,
+ 0,
+ 0,
+ t->set.i_uoff,
+ t->set.i_voff);
+ if (ret < 0) {
+ t->state = STATE_INIT_CHAN_BUF_FAIL;
+ goto done;
+ }
+
+ ret = ipu_init_channel_buffer(ipu,
+ t->set.vdi_ic_n_chan,
+ IPU_INPUT_BUFFER,
+ t->input.format,
+ t->input.crop.w,
+ t->input.crop.h,
+ t->set.istride,
+ IPU_ROTATE_NONE,
+ inbuf_n,
+ 0,
+ 0,
+ t->set.i_uoff,
+ t->set.i_voff);
+ if (ret < 0) {
+ t->state = STATE_INIT_CHAN_BUF_FAIL;
+ goto done;
+ }
+ }
+
+ if (t->overlay_en) {
+ ret = ipu_init_channel_buffer(ipu,
+ t->set.ic_chan,
+ IPU_GRAPH_IN_BUFFER,
+ t->overlay.format,
+ t->overlay.crop.w,
+ t->overlay.crop.h,
+ t->set.ovstride,
+ IPU_ROTATE_NONE,
+ ovbuf,
+ 0,
+ 0,
+ t->set.ov_uoff,
+ t->set.ov_voff);
+ if (ret < 0) {
+ t->state = STATE_INIT_CHAN_BUF_FAIL;
+ goto done;
+ }
+ }
+
+ if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+ ret = ipu_init_channel_buffer(ipu,
+ t->set.ic_chan,
+ IPU_ALPHA_IN_BUFFER,
+ IPU_PIX_FMT_GENERIC,
+ t->overlay.crop.w,
+ t->overlay.crop.h,
+ t->set.ov_alpha_stride,
+ IPU_ROTATE_NONE,
+ ov_alp_buf,
+ 0,
+ 0,
+ 0, 0);
+ if (ret < 0) {
+ t->state = STATE_INIT_CHAN_BUF_FAIL;
+ goto done;
+ }
+ }
+
+ if (!(t->set.task & VDOA_ONLY)) {
+ ret = ipu_init_channel_buffer(ipu,
+ t->set.ic_chan,
+ IPU_OUTPUT_BUFFER,
+ out_fmt,
+ out_w,
+ out_h,
+ out_stride,
+ out_rot,
+ outbuf,
+ 0,
+ 0,
+ out_uoff,
+ out_voff);
+ if (ret < 0) {
+ t->state = STATE_INIT_CHAN_BUF_FAIL;
+ goto done;
+ }
+ }
+
+ if ((t->set.mode & VDOA_BAND_MODE) && (t->set.task & VDI_VF)) {
+ ret = ipu_link_channels(ipu, MEM_VDOA_MEM, t->set.ic_chan);
+ CHECK_RETCODE(ret < 0, "ipu_link_ch vdoa_ic",
+ STATE_LINK_CHAN_FAIL, done, ret);
+ }
+
+done:
+ return ret;
+}
+
+static void uninit_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+ int ret;
+
+ if ((t->set.mode & VDOA_BAND_MODE) && (t->set.task & VDI_VF)) {
+ ret = ipu_unlink_channels(ipu, MEM_VDOA_MEM, t->set.ic_chan);
+ CHECK_RETCODE_CONT(ret < 0, "ipu_unlink_ch vdoa_ic",
+ STATE_UNLINK_CHAN_FAIL, ret);
+ }
+ ipu_uninit_channel(ipu, t->set.ic_chan);
+ if (deinterlace_3_field(t)) {
+ ipu_uninit_channel(ipu, t->set.vdi_ic_p_chan);
+ ipu_uninit_channel(ipu, t->set.vdi_ic_n_chan);
+ }
+}
+
+static int init_rot(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+ int ret = 0;
+ dma_addr_t inbuf = 0, outbuf = 0;
+ int in_uoff = 0, in_voff = 0;
+ int in_fmt, in_width, in_height, in_stride;
+
+ /* init channel */
+ ret = ipu_init_channel(ipu, t->set.rot_chan, NULL);
+ if (ret < 0) {
+ t->state = STATE_INIT_CHAN_FAIL;
+ goto done;
+ }
+
+ /* init channel buf */
+ /* is it need link to a ic channel */
+ if (ic_and_rot(t->set.mode)) {
+ in_fmt = t->set.r_fmt;
+ in_width = t->set.r_width;
+ in_height = t->set.r_height;
+ in_stride = t->set.r_stride;
+ inbuf = t->set.r_paddr;
+ in_uoff = 0;
+ in_voff = 0;
+ } else {
+ in_fmt = t->input.format;
+ in_width = t->input.crop.w;
+ in_height = t->input.crop.h;
+ in_stride = t->set.istride;
+ inbuf = t->input.paddr + t->set.i_off;
+ in_uoff = t->set.i_uoff;
+ in_voff = t->set.i_voff;
+ }
+ outbuf = t->output.paddr + t->set.o_off;
+
+ ret = ipu_init_channel_buffer(ipu,
+ t->set.rot_chan,
+ IPU_INPUT_BUFFER,
+ in_fmt,
+ in_width,
+ in_height,
+ in_stride,
+ t->output.rotate,
+ inbuf,
+ 0,
+ 0,
+ in_uoff,
+ in_voff);
+ if (ret < 0) {
+ t->state = STATE_INIT_CHAN_BUF_FAIL;
+ goto done;
+ }
+
+ ret = ipu_init_channel_buffer(ipu,
+ t->set.rot_chan,
+ IPU_OUTPUT_BUFFER,
+ t->output.format,
+ t->output.crop.w,
+ t->output.crop.h,
+ t->set.ostride,
+ IPU_ROTATE_NONE,
+ outbuf,
+ 0,
+ 0,
+ t->set.o_uoff,
+ t->set.o_voff);
+ if (ret < 0) {
+ t->state = STATE_INIT_CHAN_BUF_FAIL;
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+static void uninit_rot(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+ ipu_uninit_channel(ipu, t->set.rot_chan);
+}
+
+static int get_irq(struct ipu_task_entry *t)
+{
+ int irq;
+ ipu_channel_t chan;
+
+ if (only_ic(t->set.mode))
+ chan = t->set.ic_chan;
+ else
+ chan = t->set.rot_chan;
+
+ switch (chan) {
+ case MEM_ROT_VF_MEM:
+ irq = IPU_IRQ_PRP_VF_ROT_OUT_EOF;
+ break;
+ case MEM_ROT_PP_MEM:
+ irq = IPU_IRQ_PP_ROT_OUT_EOF;
+ break;
+ case MEM_VDI_PRP_VF_MEM:
+ case MEM_PRP_VF_MEM:
+ irq = IPU_IRQ_PRP_VF_OUT_EOF;
+ break;
+ case MEM_PP_MEM:
+ irq = IPU_IRQ_PP_OUT_EOF;
+ break;
+ case MEM_VDI_MEM:
+ irq = IPU_IRQ_VDIC_OUT_EOF;
+ break;
+ default:
+ irq = -EINVAL;
+ }
+
+ return irq;
+}
+
+static irqreturn_t task_irq_handler(int irq, void *dev_id)
+{
+ struct ipu_task_entry *prev_tsk = dev_id;
+
+ CHECK_PERF(&prev_tsk->ts_inirq);
+ complete(&prev_tsk->irq_comp);
+ dev_dbg(prev_tsk->dev, "[0x%p] no-0x%x in-irq!",
+ prev_tsk, prev_tsk->task_no);
+
+ return IRQ_HANDLED;
+}
+
+/* Fix deinterlace up&down split mode medium line */
+static void vdi_split_process(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+ u32 vdi_size;
+ u32 vdi_save_lines;
+ u32 stripe_mode;
+ u32 task_no;
+ u32 i, offset_addr;
+ u32 line_size;
+ unsigned char *base_off;
+ struct ipu_task_entry *parent = t->parent;
+ struct mutex *lock = &parent->vdic_lock;
+
+ if (!parent) {
+ dev_err(t->dev, "ERR[0x%x]invalid parent\n", t->task_no);
+ return;
+ }
+ mutex_lock(lock);
+ stripe_mode = t->task_no & 0xf;
+ task_no = t->task_no >> 4;
+
+ /* Save both luma and chroma part for interleaved YUV(e.g. YUYV).
+ * Save luma part for non-interleaved and partial-interleaved
+ * YUV format (e.g NV12 and YV12). */
+ if (t->output.format == IPU_PIX_FMT_YUYV ||
+ t->output.format == IPU_PIX_FMT_UYVY)
+ line_size = t->output.crop.w * fmt_to_bpp(t->output.format)/8;
+ else
+ line_size = t->output.crop.w;
+
+ vdi_save_lines = (t->output.crop.h - t->set.sp_setting.ud_split_line)/2;
+ vdi_size = vdi_save_lines * line_size;
+ if (vdi_save_lines <= 0) {
+ dev_err(t->dev, "[0x%p] vdi_save_line error\n", (void *)t);
+ mutex_unlock(lock);
+ return;
+ }
+
+ /*check vditmpbuf buffer have alloced or buffer size is changed */
+ if ((vdi_save_lines != parent->old_save_lines) ||
+ (vdi_size != parent->old_size)) {
+ if (parent->vditmpbuf[0] != NULL)
+ kfree(parent->vditmpbuf[0]);
+ if (parent->vditmpbuf[1] != NULL)
+ kfree(parent->vditmpbuf[1]);
+
+ parent->vditmpbuf[0] = kmalloc(vdi_size, GFP_KERNEL);
+ if (parent->vditmpbuf[0] == NULL) {
+ dev_err(t->dev,
+ "[0x%p]Falied Alloc vditmpbuf[0]\n", (void *)t);
+ mutex_unlock(lock);
+ return;
+ }
+ memset(parent->vditmpbuf[0], 0, vdi_size);
+
+ parent->vditmpbuf[1] = kmalloc(vdi_size, GFP_KERNEL);
+ if (parent->vditmpbuf[1] == NULL) {
+ dev_err(t->dev,
+ "[0x%p]Falied Alloc vditmpbuf[1]\n", (void *)t);
+ mutex_unlock(lock);
+ return;
+ }
+ memset(parent->vditmpbuf[1], 0, vdi_size);
+
+ parent->old_save_lines = vdi_save_lines;
+ parent->old_size = vdi_size;
+ }
+
+ if (pfn_valid(t->output.paddr >> PAGE_SHIFT)) {
+ base_off = page_address(pfn_to_page(t->output.paddr >> PAGE_SHIFT));
+ base_off += t->output.paddr & ((1 << PAGE_SHIFT) - 1);
+ } else {
+ base_off = (char *)ioremap_nocache(t->output.paddr,
+ t->output.width * t->output.height *
+ fmt_to_bpp(t->output.format)/8);
+ }
+ if (base_off == NULL) {
+ dev_err(t->dev, "ERR[0x%p]Failed get virtual address\n", t);
+ mutex_unlock(lock);
+ return;
+ }
+
+ /* UP stripe or UP&LEFT stripe */
+ if ((stripe_mode == UP_STRIPE) ||
+ (stripe_mode == (UP_STRIPE | LEFT_STRIPE))) {
+ if (!parent->buf0filled) {
+ offset_addr = t->set.o_off +
+ t->set.sp_setting.ud_split_line*t->set.ostride;
+ dmac_flush_range(base_off + offset_addr,
+ base_off + offset_addr + vdi_size);
+ outer_flush_range(t->output.paddr + offset_addr,
+ t->output.paddr + offset_addr + vdi_size);
+
+ for (i = 0; i < vdi_save_lines; i++)
+ memcpy(parent->vditmpbuf[0] + i*line_size,
+ base_off + offset_addr +
+ i*t->set.ostride, line_size);
+ parent->buf0filled = true;
+ } else {
+ offset_addr = t->set.o_off + (t->output.crop.h -
+ vdi_save_lines) * t->set.ostride;
+ for (i = 0; i < vdi_save_lines; i++)
+ memcpy(base_off + offset_addr + i*t->set.ostride,
+ parent->vditmpbuf[0] + i*line_size, line_size);
+
+ dmac_flush_range(base_off + offset_addr,
+ base_off + offset_addr + i*t->set.ostride);
+ outer_flush_range(t->output.paddr + offset_addr,
+ t->output.paddr + offset_addr + i*t->set.ostride);
+ parent->buf0filled = false;
+ }
+ }
+ /*Down stripe or Down&Left stripe*/
+ else if ((stripe_mode == DOWN_STRIPE) ||
+ (stripe_mode == (DOWN_STRIPE | LEFT_STRIPE))) {
+ if (!parent->buf0filled) {
+ offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride;
+ dmac_flush_range(base_off + offset_addr,
+ base_off + offset_addr + vdi_size);
+ outer_flush_range(t->output.paddr + offset_addr,
+ t->output.paddr + offset_addr + vdi_size);
+
+ for (i = 0; i < vdi_save_lines; i++)
+ memcpy(parent->vditmpbuf[0] + i*line_size,
+ base_off + offset_addr + i*t->set.ostride,
+ line_size);
+ parent->buf0filled = true;
+ } else {
+ offset_addr = t->set.o_off;
+ for (i = 0; i < vdi_save_lines; i++)
+ memcpy(base_off + offset_addr + i*t->set.ostride,
+ parent->vditmpbuf[0] + i*line_size,
+ line_size);
+
+ dmac_flush_range(base_off + offset_addr,
+ base_off + offset_addr + i*t->set.ostride);
+ outer_flush_range(t->output.paddr + offset_addr,
+ t->output.paddr + offset_addr + i*t->set.ostride);
+ parent->buf0filled = false;
+ }
+ }
+ /*Up&Right stripe*/
+ else if (stripe_mode == (UP_STRIPE | RIGHT_STRIPE)) {
+ if (!parent->buf1filled) {
+ offset_addr = t->set.o_off +
+ t->set.sp_setting.ud_split_line*t->set.ostride;
+ dmac_flush_range(base_off + offset_addr,
+ base_off + offset_addr + vdi_size);
+ outer_flush_range(t->output.paddr + offset_addr,
+ t->output.paddr + offset_addr + vdi_size);
+
+ for (i = 0; i < vdi_save_lines; i++)
+ memcpy(parent->vditmpbuf[1] + i*line_size,
+ base_off + offset_addr + i*t->set.ostride,
+ line_size);
+ parent->buf1filled = true;
+ } else {
+ offset_addr = t->set.o_off +
+ (t->output.crop.h - vdi_save_lines)*t->set.ostride;
+ for (i = 0; i < vdi_save_lines; i++)
+ memcpy(base_off + offset_addr + i*t->set.ostride,
+ parent->vditmpbuf[1] + i*line_size,
+ line_size);
+
+ dmac_flush_range(base_off + offset_addr,
+ base_off + offset_addr + i*t->set.ostride);
+ outer_flush_range(t->output.paddr + offset_addr,
+ t->output.paddr + offset_addr + i*t->set.ostride);
+ parent->buf1filled = false;
+ }
+ }
+ /*Down stripe or Down&Right stript*/
+ else if (stripe_mode == (DOWN_STRIPE | RIGHT_STRIPE)) {
+ if (!parent->buf1filled) {
+ offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride;
+ dmac_flush_range(base_off + offset_addr,
+ base_off + offset_addr + vdi_save_lines*t->set.ostride);
+ outer_flush_range(t->output.paddr + offset_addr,
+ t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride);
+
+ for (i = 0; i < vdi_save_lines; i++)
+ memcpy(parent->vditmpbuf[1] + i*line_size,
+ base_off + offset_addr + i*t->set.ostride,
+ line_size);
+ parent->buf1filled = true;
+ } else {
+ offset_addr = t->set.o_off;
+ for (i = 0; i < vdi_save_lines; i++)
+ memcpy(base_off + offset_addr + i*t->set.ostride,
+ parent->vditmpbuf[1] + i*line_size,
+ line_size);
+
+ dmac_flush_range(base_off + offset_addr,
+ base_off + offset_addr + vdi_save_lines*t->set.ostride);
+ outer_flush_range(t->output.paddr + offset_addr,
+ t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride);
+ parent->buf1filled = false;
+ }
+ }
+ if (!pfn_valid(t->output.paddr >> PAGE_SHIFT))
+ iounmap(base_off);
+ mutex_unlock(lock);
+}
+
+static void do_task_release(struct ipu_task_entry *t, int fail)
+{
+ int ret;
+ struct ipu_soc *ipu = t->ipu;
+
+ if (t->input.deinterlace.enable && !fail &&
+ (t->task_no & (UP_STRIPE | DOWN_STRIPE)))
+ vdi_split_process(ipu, t);
+
+ ipu_free_irq(ipu, t->irq, t);
+
+ if (t->vdoa_dma.vaddr)
+ dma_free_coherent(t->dev,
+ t->vdoa_dma.size,
+ t->vdoa_dma.vaddr,
+ t->vdoa_dma.paddr);
+
+ if (only_ic(t->set.mode)) {
+ ret = ipu_disable_channel(ipu, t->set.ic_chan, true);
+ CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic",
+ STATE_DISABLE_CHAN_FAIL, ret);
+ if (deinterlace_3_field(t)) {
+ ret = ipu_disable_channel(ipu, t->set.vdi_ic_p_chan,
+ true);
+ CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic_p",
+ STATE_DISABLE_CHAN_FAIL, ret);
+ ret = ipu_disable_channel(ipu, t->set.vdi_ic_n_chan,
+ true);
+ CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic_n",
+ STATE_DISABLE_CHAN_FAIL, ret);
+ }
+ } else if (only_rot(t->set.mode)) {
+ ret = ipu_disable_channel(ipu, t->set.rot_chan, true);
+ CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_rot",
+ STATE_DISABLE_CHAN_FAIL, ret);
+ } else if (ic_and_rot(t->set.mode)) {
+ ret = ipu_unlink_channels(ipu, t->set.ic_chan, t->set.rot_chan);
+ CHECK_RETCODE_CONT(ret < 0, "ipu_unlink_ch",
+ STATE_UNLINK_CHAN_FAIL, ret);
+ ret = ipu_disable_channel(ipu, t->set.rot_chan, true);
+ CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch ic_and_rot-rot",
+ STATE_DISABLE_CHAN_FAIL, ret);
+ ret = ipu_disable_channel(ipu, t->set.ic_chan, true);
+ CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch ic_and_rot-ic",
+ STATE_DISABLE_CHAN_FAIL, ret);
+ if (deinterlace_3_field(t)) {
+ ret = ipu_disable_channel(ipu, t->set.vdi_ic_p_chan,
+ true);
+ CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch icrot-ic-p",
+ STATE_DISABLE_CHAN_FAIL, ret);
+ ret = ipu_disable_channel(ipu, t->set.vdi_ic_n_chan,
+ true);
+ CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch icrot-ic-n",
+ STATE_DISABLE_CHAN_FAIL, ret);
+ }
+ }
+
+ if (only_ic(t->set.mode))
+ uninit_ic(ipu, t);
+ else if (only_rot(t->set.mode))
+ uninit_rot(ipu, t);
+ else if (ic_and_rot(t->set.mode)) {
+ uninit_ic(ipu, t);
+ uninit_rot(ipu, t);
+ }
+
+ t->state = STATE_OK;
+ CHECK_PERF(&t->ts_rel);
+ return;
+}
+
+static void do_task_vdoa_only(struct ipu_task_entry *t)
+{
+ int ret;
+
+ ret = init_tiled_ch_bufs(NULL, t);
+ CHECK_RETCODE(ret < 0, "do_vdoa_only", STATE_ERR, out, ret);
+ ret = vdoa_start(t->vdoa_handle, VDOA_DEF_TIMEOUT_MS);
+ vdoa_stop(t->vdoa_handle);
+ CHECK_RETCODE(ret < 0, "vdoa_wait4complete, do_vdoa_only",
+ STATE_VDOA_IRQ_TIMEOUT, out, ret);
+
+ t->state = STATE_OK;
+out:
+ return;
+}
+
+static void do_task(struct ipu_task_entry *t)
+{
+ int r_size;
+ int irq;
+ int ret;
+ uint32_t busy;
+ struct ipu_soc *ipu = t->ipu;
+
+ CHECK_PERF(&t->ts_dotask);
+
+ if (!ipu) {
+ t->state = STATE_NO_IPU;
+ return;
+ }
+
+ init_completion(&t->irq_comp);
+ dev_dbg(ipu->dev, "[0x%p]Do task no:0x%x: id %d\n", (void *)t,
+ t->task_no, t->task_id);
+ dump_task_info(t);
+
+ if (t->set.task & IC_PP) {
+ t->set.ic_chan = MEM_PP_MEM;
+ dev_dbg(ipu->dev, "[0x%p]ic channel MEM_PP_MEM\n", (void *)t);
+ } else if (t->set.task & IC_VF) {
+ t->set.ic_chan = MEM_PRP_VF_MEM;
+ dev_dbg(ipu->dev, "[0x%p]ic channel MEM_PRP_VF_MEM\n", (void *)t);
+ } else if (t->set.task & VDI_VF) {
+ if (t->set.mode & VDOA_BAND_MODE) {
+ t->set.ic_chan = MEM_VDI_MEM;
+ if (deinterlace_3_field(t)) {
+ t->set.vdi_ic_p_chan = MEM_VDI_MEM_P;
+ t->set.vdi_ic_n_chan = MEM_VDI_MEM_N;
+ }
+ dev_dbg(ipu->dev, "[0x%p]ic ch MEM_VDI_MEM\n",
+ (void *)t);
+ } else {
+ t->set.ic_chan = MEM_VDI_PRP_VF_MEM;
+ if (deinterlace_3_field(t)) {
+ t->set.vdi_ic_p_chan = MEM_VDI_PRP_VF_MEM_P;
+ t->set.vdi_ic_n_chan = MEM_VDI_PRP_VF_MEM_N;
+ }
+ dev_dbg(ipu->dev,
+ "[0x%p]ic ch MEM_VDI_PRP_VF_MEM\n", t);
+ }
+ }
+
+ if (t->set.task & ROT_PP) {
+ t->set.rot_chan = MEM_ROT_PP_MEM;
+ dev_dbg(ipu->dev, "[0x%p]rot channel MEM_ROT_PP_MEM\n", (void *)t);
+ } else if (t->set.task & ROT_VF) {
+ t->set.rot_chan = MEM_ROT_VF_MEM;
+ dev_dbg(ipu->dev, "[0x%p]rot channel MEM_ROT_VF_MEM\n", (void *)t);
+ }
+
+ if (t->task_id == IPU_TASK_ID_VF)
+ busy = ic_vf_pp_is_busy(ipu, true);
+ else if (t->task_id == IPU_TASK_ID_PP)
+ busy = ic_vf_pp_is_busy(ipu, false);
+ else {
+ dev_err(ipu->dev, "ERR[no:0x%x]ipu task_id:%d invalid!\n",
+ t->task_no, t->task_id);
+ return;
+ }
+ if (busy) {
+ dev_err(ipu->dev, "ERR[0x%p-no:0x%x]ipu task_id:%d busy!\n",
+ (void *)t, t->task_no, t->task_id);
+ t->state = STATE_IPU_BUSY;
+ return;
+ }
+
+ irq = get_irq(t);
+ if (irq < 0) {
+ t->state = STATE_NO_IRQ;
+ return;
+ }
+ t->irq = irq;
+
+ /* channel setup */
+ if (only_ic(t->set.mode)) {
+ dev_dbg(t->dev, "[0x%p]only ic mode\n", (void *)t);
+ ret = init_ic(ipu, t);
+ CHECK_RETCODE(ret < 0, "init_ic only_ic",
+ t->state, chan_setup, ret);
+ } else if (only_rot(t->set.mode)) {
+ dev_dbg(t->dev, "[0x%p]only rot mode\n", (void *)t);
+ ret = init_rot(ipu, t);
+ CHECK_RETCODE(ret < 0, "init_rot only_rot",
+ t->state, chan_setup, ret);
+ } else if (ic_and_rot(t->set.mode)) {
+ int rot_idx = (t->task_id == IPU_TASK_ID_VF) ? 0 : 1;
+
+ dev_dbg(t->dev, "[0x%p]ic + rot mode\n", (void *)t);
+ t->set.r_fmt = t->output.format;
+ if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+ t->set.r_width = t->output.crop.h;
+ t->set.r_height = t->output.crop.w;
+ } else {
+ t->set.r_width = t->output.crop.w;
+ t->set.r_height = t->output.crop.h;
+ }
+ t->set.r_stride = t->set.r_width *
+ bytes_per_pixel(t->set.r_fmt);
+ r_size = PAGE_ALIGN(t->set.r_width * t->set.r_height
+ * fmt_to_bpp(t->set.r_fmt)/8);
+
+ if (r_size > ipu->rot_dma[rot_idx].size) {
+ dev_dbg(t->dev, "[0x%p]realloc rot buffer\n", (void *)t);
+
+ if (ipu->rot_dma[rot_idx].vaddr)
+ dma_free_coherent(t->dev,
+ ipu->rot_dma[rot_idx].size,
+ ipu->rot_dma[rot_idx].vaddr,
+ ipu->rot_dma[rot_idx].paddr);
+
+ ipu->rot_dma[rot_idx].size = r_size;
+ ipu->rot_dma[rot_idx].vaddr = dma_alloc_coherent(t->dev,
+ r_size,
+ &ipu->rot_dma[rot_idx].paddr,
+ GFP_DMA | GFP_KERNEL);
+ CHECK_RETCODE(ipu->rot_dma[rot_idx].vaddr == NULL,
+ "ic_and_rot", STATE_SYS_NO_MEM,
+ chan_setup, -ENOMEM);
+ }
+ t->set.r_paddr = ipu->rot_dma[rot_idx].paddr;
+
+ dev_dbg(t->dev, "[0x%p]rotation:\n", (void *)t);
+ dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->set.r_fmt);
+ dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->set.r_width);
+ dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->set.r_height);
+ dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->set.r_paddr);
+ dev_dbg(t->dev, "[0x%p]\trstride = %d\n", (void *)t, t->set.r_stride);
+
+ ret = init_ic(ipu, t);
+ CHECK_RETCODE(ret < 0, "init_ic ic_and_rot",
+ t->state, chan_setup, ret);
+ ret = init_rot(ipu, t);
+ CHECK_RETCODE(ret < 0, "init_rot ic_and_rot",
+ t->state, chan_setup, ret);
+ ret = ipu_link_channels(ipu, t->set.ic_chan,
+ t->set.rot_chan);
+ CHECK_RETCODE(ret < 0, "ipu_link_ch ic_and_rot",
+ STATE_LINK_CHAN_FAIL, chan_setup, ret);
+ } else {
+ dev_err(t->dev, "ERR [0x%p]do task: should not be here\n", t);
+ t->state = STATE_ERR;
+ return;
+ }
+
+ ret = ipu_request_irq(ipu, irq, task_irq_handler, 0, NULL, t);
+ CHECK_RETCODE(ret < 0, "ipu_req_irq",
+ STATE_IRQ_FAIL, chan_setup, ret);
+
+ /* enable/start channel */
+ if (only_ic(t->set.mode)) {
+ ret = ipu_enable_channel(ipu, t->set.ic_chan);
+ CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic",
+ STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+ if (deinterlace_3_field(t)) {
+ ret = ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
+ CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic_p",
+ STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+ ret = ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
+ CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic_n",
+ STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+ }
+
+ ret = ipu_select_buffer(ipu, t->set.ic_chan, IPU_OUTPUT_BUFFER,
+ 0);
+ CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic",
+ STATE_SEL_BUF_FAIL, chan_buf, ret);
+ if (t->overlay_en) {
+ ret = ipu_select_buffer(ipu, t->set.ic_chan,
+ IPU_GRAPH_IN_BUFFER, 0);
+ CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_g",
+ STATE_SEL_BUF_FAIL, chan_buf, ret);
+ if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+ ret = ipu_select_buffer(ipu, t->set.ic_chan,
+ IPU_ALPHA_IN_BUFFER, 0);
+ CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_a",
+ STATE_SEL_BUF_FAIL, chan_buf,
+ ret);
+ }
+ }
+ if (!(t->set.mode & VDOA_BAND_MODE)) {
+ if (deinterlace_3_field(t))
+ ipu_select_multi_vdi_buffer(ipu, 0);
+ else {
+ ret = ipu_select_buffer(ipu, t->set.ic_chan,
+ IPU_INPUT_BUFFER, 0);
+ CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_i",
+ STATE_SEL_BUF_FAIL, chan_buf, ret);
+ }
+ }
+ } else if (only_rot(t->set.mode)) {
+ ret = ipu_enable_channel(ipu, t->set.rot_chan);
+ CHECK_RETCODE(ret < 0, "ipu_enable_ch only_rot",
+ STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+ ret = ipu_select_buffer(ipu, t->set.rot_chan,
+ IPU_OUTPUT_BUFFER, 0);
+ CHECK_RETCODE(ret < 0, "ipu_sel_buf only_rot_o",
+ STATE_SEL_BUF_FAIL, chan_buf, ret);
+ ret = ipu_select_buffer(ipu, t->set.rot_chan,
+ IPU_INPUT_BUFFER, 0);
+ CHECK_RETCODE(ret < 0, "ipu_sel_buf only_rot_i",
+ STATE_SEL_BUF_FAIL, chan_buf, ret);
+ } else if (ic_and_rot(t->set.mode)) {
+ ret = ipu_enable_channel(ipu, t->set.rot_chan);
+ CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-rot",
+ STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+ ret = ipu_enable_channel(ipu, t->set.ic_chan);
+ CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-ic",
+ STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+ if (deinterlace_3_field(t)) {
+ ret = ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
+ CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-p",
+ STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+ ret = ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
+ CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-n",
+ STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+ }
+
+ ret = ipu_select_buffer(ipu, t->set.rot_chan,
+ IPU_OUTPUT_BUFFER, 0);
+ CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-rot-o",
+ STATE_SEL_BUF_FAIL, chan_buf, ret);
+ if (t->overlay_en) {
+ ret = ipu_select_buffer(ipu, t->set.ic_chan,
+ IPU_GRAPH_IN_BUFFER, 0);
+ CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-g",
+ STATE_SEL_BUF_FAIL, chan_buf, ret);
+ if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+ ret = ipu_select_buffer(ipu, t->set.ic_chan,
+ IPU_ALPHA_IN_BUFFER, 0);
+ CHECK_RETCODE(ret < 0, "ipu_sel_buf icrot-ic-a",
+ STATE_SEL_BUF_FAIL,
+ chan_buf, ret);
+ }
+ }
+ ret = ipu_select_buffer(ipu, t->set.ic_chan,
+ IPU_OUTPUT_BUFFER, 0);
+ CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-o",
+ STATE_SEL_BUF_FAIL, chan_buf, ret);
+ if (deinterlace_3_field(t))
+ ipu_select_multi_vdi_buffer(ipu, 0);
+ else {
+ ret = ipu_select_buffer(ipu, t->set.ic_chan,
+ IPU_INPUT_BUFFER, 0);
+ CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-i",
+ STATE_SEL_BUF_FAIL, chan_buf, ret);
+ }
+ }
+
+ if (need_split(t))
+ t->state = STATE_IN_PROGRESS;
+
+ if (t->set.mode & VDOA_BAND_MODE) {
+ ret = vdoa_start(t->vdoa_handle, VDOA_DEF_TIMEOUT_MS);
+ CHECK_RETCODE(ret < 0, "vdoa_wait4complete, do_vdoa_band",
+ STATE_VDOA_IRQ_TIMEOUT, chan_rel, ret);
+ }
+
+ CHECK_PERF(&t->ts_waitirq);
+ ret = wait_for_completion_timeout(&t->irq_comp,
+ msecs_to_jiffies(t->timeout - DEF_DELAY_MS));
+ CHECK_PERF(&t->ts_wakeup);
+ CHECK_RETCODE(ret == 0, "wait_for_comp_timeout",
+ STATE_IRQ_TIMEOUT, chan_rel, ret);
+ dev_dbg(t->dev, "[0x%p] no-0x%x ipu irq done!", t, t->task_no);
+
+chan_rel:
+chan_buf:
+chan_en:
+chan_setup:
+ if (t->set.mode & VDOA_BAND_MODE)
+ vdoa_stop(t->vdoa_handle);
+ do_task_release(t, t->state >= STATE_ERR);
+ return;
+}
+
+static void do_task_vdoa_vdi(struct ipu_task_entry *t)
+{
+ int i;
+ int ret;
+ u32 stripe_width;
+
+ /* FIXME: crop mode not support now */
+ stripe_width = t->input.width >> 1;
+ t->input.crop.pos.x = 0;
+ t->input.crop.pos.y = 0;
+ t->input.crop.w = stripe_width;
+ t->input.crop.h = t->input.height;
+ t->output.crop.w = stripe_width;
+ t->output.crop.h = t->input.height;
+
+ for (i = 0; i < 2; i++) {
+ t->input.crop.pos.x = t->input.crop.pos.x + i * stripe_width;
+ t->output.crop.pos.x = t->output.crop.pos.x + i * stripe_width;
+ /* check input */
+ ret = set_crop(&t->input.crop, t->input.width, t->input.height,
+ t->input.format);
+ if (ret < 0) {
+ ret = STATE_ERR;
+ goto done;
+ } else
+ update_offset(t->input.format,
+ t->input.width, t->input.height,
+ t->input.crop.pos.x,
+ t->input.crop.pos.y,
+ &t->set.i_off, &t->set.i_uoff,
+ &t->set.i_voff, &t->set.istride);
+ dev_dbg(t->dev, "i_off:0x%x, i_uoff:0x%x, istride:%d.\n",
+ t->set.i_off, t->set.i_uoff, t->set.istride);
+ /* check output */
+ ret = set_crop(&t->output.crop, t->input.width,
+ t->output.height, t->output.format);
+ if (ret < 0) {
+ ret = STATE_ERR;
+ goto done;
+ } else
+ update_offset(t->output.format,
+ t->output.width, t->output.height,
+ t->output.crop.pos.x,
+ t->output.crop.pos.y,
+ &t->set.o_off, &t->set.o_uoff,
+ &t->set.o_voff, &t->set.ostride);
+
+ dev_dbg(t->dev, "o_off:0x%x, o_uoff:0x%x, ostride:%d.\n",
+ t->set.o_off, t->set.o_uoff, t->set.ostride);
+
+ do_task(t);
+ }
+
+ return;
+done:
+ dev_err(t->dev, "ERR %s set_crop.\n", __func__);
+ t->state = ret;
+ return;
+}
+
+static void get_res_do_task(struct ipu_task_entry *t)
+{
+ uint32_t found;
+ uint32_t split_child;
+ struct mutex *lock;
+
+ found = get_vdoa_ipu_res(t);
+ if (!found) {
+ dev_err(t->dev, "ERR:[0x%p] no-0x%x can not get res\n",
+ t, t->task_no);
+ return;
+ } else {
+ if (t->set.task & VDOA_ONLY)
+ do_task_vdoa_only(t);
+ else if ((IPU_PIX_FMT_TILED_NV12F == t->input.format) &&
+ (t->set.mode & VDOA_BAND_MODE) &&
+ (t->input.crop.w >
+ soc_max_vdi_in_width(t->ipu)))
+ do_task_vdoa_vdi(t);
+ else
+ do_task(t);
+ put_vdoa_ipu_res(t, 0);
+ }
+ if (t->state != STATE_OK) {
+ dev_err(t->dev, "ERR:[0x%p] no-0x%x state: %s\n",
+ t, t->task_no, state_msg[t->state].msg);
+ }
+
+ split_child = need_split(t) && t->parent;
+ if (split_child) {
+ lock = &t->parent->split_lock;
+ mutex_lock(lock);
+ t->split_done = 1;
+ mutex_unlock(lock);
+ wake_up(&t->parent->split_waitq);
+ }
+
+ return;
+}
+
+static void wait_split_task_complete(struct ipu_task_entry *parent,
+ struct ipu_split_task *sp_task, uint32_t size)
+{
+ struct ipu_task_entry *tsk = NULL;
+ int ret = 0, rc;
+ int j, idx = -1;
+ unsigned long flags;
+ struct mutex *lock = &parent->split_lock;
+ int k, busy_vf, busy_pp;
+ struct ipu_soc *ipu;
+ DECLARE_PERF_VAR;
+
+ for (j = 0; j < size; j++) {
+ rc = wait_event_timeout(
+ parent->split_waitq,
+ sp_task_check_done(sp_task, parent, size, &idx),
+ msecs_to_jiffies(parent->timeout - DEF_DELAY_MS));
+ if (!rc) {
+ dev_err(parent->dev,
+ "ERR:[0x%p] no-0x%x, split_task timeout,j:%d,"
+ "size:%d.\n",
+ parent, parent->task_no, j, size);
+ ret = -ETIMEDOUT;
+ goto out;
+ } else {
+ if (idx < 0) {
+ dev_err(parent->dev,
+ "ERR:[0x%p] no-0x%x, invalid task idx:%d\n",
+ parent, parent->task_no, idx);
+ continue;
+ }
+ tsk = sp_task[idx].child_task;
+ mutex_lock(lock);
+ if (!tsk->split_done || !tsk->ipu)
+ dev_err(tsk->dev,
+ "ERR:no-0x%x,split not done:%d/null ipu:0x%p\n",
+ tsk->task_no, tsk->split_done, tsk->ipu);
+ tsk->split_done = 0;
+ mutex_unlock(lock);
+
+ dev_dbg(tsk->dev,
+ "[0x%p] no-0x%x sp_tsk[%d] done,state:%d.\n",
+ tsk, tsk->task_no, idx, tsk->state);
+ #ifdef DBG_IPU_PERF
+ CHECK_PERF(&tsk->ts_rel);
+ PRINT_TASK_STATISTICS;
+ #endif
+ }
+ }
+
+out:
+ if (ret == -ETIMEDOUT) {
+ /* debug */
+ for (k = 0; k < max_ipu_no; k++) {
+ ipu = ipu_get_soc(k);
+ if (IS_ERR(ipu)) {
+ dev_err(parent->dev, "no:0x%x, null ipu:%d\n",
+ parent->task_no, k);
+ } else {
+ busy_vf = ic_vf_pp_is_busy(ipu, true);
+ busy_pp = ic_vf_pp_is_busy(ipu, false);
+ dev_err(parent->dev,
+ "ERR:ipu[%d] busy_vf:%d, busy_pp:%d.\n",
+ k, busy_vf, busy_pp);
+ }
+ }
+ for (k = 0; k < size; k++) {
+ tsk = sp_task[k].child_task;
+ if (!tsk)
+ continue;
+ dev_err(parent->dev,
+ "ERR: sp_task[%d][0x%p] no-0x%x done:%d,"
+ "state:%s,on_list:%d, ipu:0x%p,timeout!\n",
+ k, tsk, tsk->task_no, tsk->split_done,
+ state_msg[tsk->state].msg, tsk->task_in_list,
+ tsk->ipu);
+ }
+ }
+
+ for (j = 0; j < size; j++) {
+ tsk = sp_task[j].child_task;
+ if (!tsk)
+ continue;
+ spin_lock_irqsave(&ipu_task_list_lock, flags);
+ if (tsk->task_in_list) {
+ list_del(&tsk->node);
+ tsk->task_in_list = 0;
+ dev_dbg(tsk->dev,
+ "[0x%p] no-0x%x,id:%d sp_tsk timeout list_del.\n",
+ tsk, tsk->task_no, tsk->task_id);
+ }
+ spin_unlock_irqrestore(&ipu_task_list_lock, flags);
+ if (!tsk->ipu)
+ continue;
+ if (tsk->state != STATE_OK) {
+ dev_err(tsk->dev,
+ "ERR:[0x%p] no-0x%x,id:%d, sp_tsk state: %s\n",
+ tsk, tsk->task_no, tsk->task_id,
+ state_msg[tsk->state].msg);
+ }
+ kref_put(&tsk->refcount, task_mem_free);
+ }
+
+ kfree(parent->vditmpbuf[0]);
+ kfree(parent->vditmpbuf[1]);
+
+ if (ret < 0)
+ parent->state = STATE_TIMEOUT;
+ else
+ parent->state = STATE_OK;
+ return;
+}
+
+static inline int find_task(struct ipu_task_entry **t, int thread_id)
+{
+ int found;
+ unsigned long flags;
+ struct ipu_task_entry *tsk;
+ struct list_head *task_list = &ipu_task_list;
+
+ *t = NULL;
+ spin_lock_irqsave(&ipu_task_list_lock, flags);
+ found = !list_empty(task_list);
+ if (found) {
+ tsk = list_first_entry(task_list, struct ipu_task_entry, node);
+ if (tsk->task_in_list) {
+ list_del(&tsk->node);
+ tsk->task_in_list = 0;
+ *t = tsk;
+ kref_get(&tsk->refcount);
+ dev_dbg(tsk->dev,
+ "thread_id:%d,[0x%p] task_no:0x%x,mode:0x%x list_del\n",
+ thread_id, tsk, tsk->task_no, tsk->set.mode);
+ } else
+ dev_err(tsk->dev,
+ "thread_id:%d,task_no:0x%x,mode:0x%x not on list_del\n",
+ thread_id, tsk->task_no, tsk->set.mode);
+ }
+ spin_unlock_irqrestore(&ipu_task_list_lock, flags);
+
+ return found;
+}
+
+static int ipu_task_thread(void *argv)
+{
+ struct ipu_task_entry *tsk;
+ struct ipu_task_entry *sp_tsk0;
+ struct ipu_split_task sp_task[4];
+ /* priority lower than irq_thread */
+ const struct sched_param param = {
+ .sched_priority = MAX_USER_RT_PRIO/2 - 1,
+ };
+ int ret;
+ int curr_thread_id;
+ uint32_t size;
+ unsigned long flags;
+ unsigned int cpu;
+ struct cpumask cpu_mask;
+ struct ipu_thread_data *data = (struct ipu_thread_data *)argv;
+
+ thread_id++;
+ curr_thread_id = thread_id;
+ sched_setscheduler(current, SCHED_FIFO, &param);
+
+ if (!data->is_vdoa) {
+ cpu = cpumask_first(cpu_online_mask);
+ cpumask_set_cpu(cpu, &cpu_mask);
+ ret = sched_setaffinity(data->ipu->thread[data->id]->pid,
+ &cpu_mask);
+ if (ret < 0) {
+ pr_err("%s: sched_setaffinity fail:%d.\n", __func__, ret);
+ }
+ pr_debug("%s: sched_setaffinity cpu:%d.\n", __func__, cpu);
+ }
+
+ while (!kthread_should_stop()) {
+ int split_fail = 0;
+ int split_parent;
+ int split_child;
+
+ wait_event_interruptible(thread_waitq, find_task(&tsk, curr_thread_id));
+
+ if (!tsk) {
+ pr_err("thread:%d can not find task.\n",
+ curr_thread_id);
+ continue;
+ }
+
+ /* note: other threads run split child task */
+ split_parent = need_split(tsk) && !tsk->parent;
+ split_child = need_split(tsk) && tsk->parent;
+ if (split_parent) {
+ if ((tsk->set.split_mode == RL_SPLIT) ||
+ (tsk->set.split_mode == UD_SPLIT))
+ size = 2;
+ else
+ size = 4;
+ ret = queue_split_task(tsk, sp_task, size);
+ if (ret < 0) {
+ split_fail = 1;
+ } else {
+ struct list_head *pos;
+
+ spin_lock_irqsave(&ipu_task_list_lock, flags);
+
+ sp_tsk0 = list_first_entry(&tsk->split_list,
+ struct ipu_task_entry, node);
+ list_del(&sp_tsk0->node);
+
+ list_for_each(pos, &tsk->split_list) {
+ struct ipu_task_entry *tmp;
+
+ tmp = list_entry(pos,
+ struct ipu_task_entry, node);
+ tmp->task_in_list = 1;
+ dev_dbg(tmp->dev,
+ "[0x%p] no-0x%x,id:%d sp_tsk "
+ "add_to_list.\n", tmp,
+ tmp->task_no, tmp->task_id);
+ }
+ /* add to global list */
+ list_splice(&tsk->split_list, &ipu_task_list);
+
+ spin_unlock_irqrestore(&ipu_task_list_lock,
+ flags);
+ /* let the parent thread do the first sp_task */
+ /* FIXME: ensure the correct sequence for split
+ 4size: 5/6->9/a*/
+ if (!sp_tsk0)
+ dev_err(tsk->dev,
+ "ERR: no-0x%x,can not get split_tsk0\n",
+ tsk->task_no);
+ wake_up_interruptible(&thread_waitq);
+ get_res_do_task(sp_tsk0);
+ dev_dbg(sp_tsk0->dev,
+ "thread:%d complete tsk no:0x%x.\n",
+ curr_thread_id, sp_tsk0->task_no);
+ ret = atomic_read(&req_cnt);
+ if (ret > 0) {
+ wake_up(&res_waitq);
+ dev_dbg(sp_tsk0->dev,
+ "sp_tsk0 sche thread:%d no:0x%x,"
+ "req_cnt:%d\n", curr_thread_id,
+ sp_tsk0->task_no, ret);
+ /* For other threads to get_res */
+ schedule();
+ }
+ }
+ } else
+ get_res_do_task(tsk);
+
+ /* wait for all 4 sp_task finished here or timeout
+ and then release all resources */
+ if (split_parent && !split_fail)
+ wait_split_task_complete(tsk, sp_task, size);
+
+ if (!split_child) {
+ atomic_inc(&tsk->done);
+ wake_up(&tsk->task_waitq);
+ }
+
+ dev_dbg(tsk->dev, "thread:%d complete tsk no:0x%x-[0x%p].\n",
+ curr_thread_id, tsk->task_no, tsk);
+ ret = atomic_read(&req_cnt);
+ if (ret > 0) {
+ wake_up(&res_waitq);
+ dev_dbg(tsk->dev, "sche thread:%d no:0x%x,req_cnt:%d\n",
+ curr_thread_id, tsk->task_no, ret);
+ /* note: give cpu to other threads to get_res */
+ schedule();
+ }
+
+ kref_put(&tsk->refcount, task_mem_free);
+ }
+
+ pr_info("ERR %s exit.\n", __func__);
+ return 0;
+}
+
+int ipu_check_task(struct ipu_task *task)
+{
+ struct ipu_task_entry *tsk;
+ int ret = 0;
+
+ tsk = create_task_entry(task);
+ if (IS_ERR(tsk))
+ return PTR_ERR(tsk);
+
+ ret = check_task(tsk);
+
+ task->input = tsk->input;
+ task->output = tsk->output;
+ task->overlay = tsk->overlay;
+ dump_task_info(tsk);
+
+ kref_put(&tsk->refcount, task_mem_free);
+ if (ret != 0)
+ pr_debug("%s ret:%d.\n", __func__, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_check_task);
+
+int ipu_queue_task(struct ipu_task *task)
+{
+ struct ipu_task_entry *tsk;
+ unsigned long flags;
+ int ret;
+ u32 tmp_task_no;
+ DECLARE_PERF_VAR;
+
+ tsk = create_task_entry(task);
+ if (IS_ERR(tsk))
+ return PTR_ERR(tsk);
+
+ CHECK_PERF(&tsk->ts_queue);
+ ret = prepare_task(tsk);
+ if (ret < 0)
+ goto done;
+
+ if (need_split(tsk)) {
+ CHECK_PERF(&tsk->ts_dotask);
+ CHECK_PERF(&tsk->ts_waitirq);
+ CHECK_PERF(&tsk->ts_inirq);
+ CHECK_PERF(&tsk->ts_wakeup);
+ }
+
+ /* task_no last four bits for split task type*/
+ tmp_task_no = atomic_inc_return(&frame_no);
+ tsk->task_no = tmp_task_no << 4;
+ init_waitqueue_head(&tsk->task_waitq);
+
+ spin_lock_irqsave(&ipu_task_list_lock, flags);
+ list_add_tail(&tsk->node, &ipu_task_list);
+ tsk->task_in_list = 1;
+ dev_dbg(tsk->dev, "[0x%p,no-0x%x] list_add_tail\n", tsk, tsk->task_no);
+ spin_unlock_irqrestore(&ipu_task_list_lock, flags);
+ wake_up_interruptible(&thread_waitq);
+
+ ret = wait_event_timeout(tsk->task_waitq, atomic_read(&tsk->done),
+ msecs_to_jiffies(tsk->timeout));
+ if (0 == ret) {
+ /* note: the timeout should larger than the internal timeout!*/
+ ret = -ETIMEDOUT;
+ dev_err(tsk->dev, "ERR: [0x%p] no-0x%x, timeout:%dms!\n",
+ tsk, tsk->task_no, tsk->timeout);
+ } else {
+ if (STATE_OK != tsk->state) {
+ dev_err(tsk->dev, "ERR: [0x%p] no-0x%x,state %d: %s\n",
+ tsk, tsk->task_no, tsk->state,
+ state_msg[tsk->state].msg);
+ ret = -ECANCELED;
+ } else
+ ret = 0;
+ }
+
+ spin_lock_irqsave(&ipu_task_list_lock, flags);
+ if (tsk->task_in_list) {
+ list_del(&tsk->node);
+ tsk->task_in_list = 0;
+ dev_dbg(tsk->dev, "[0x%p] no:0x%x list_del\n",
+ tsk, tsk->task_no);
+ }
+ spin_unlock_irqrestore(&ipu_task_list_lock, flags);
+
+#ifdef DBG_IPU_PERF
+ CHECK_PERF(&tsk->ts_rel);
+ PRINT_TASK_STATISTICS;
+ if (ts_frame_avg == 0)
+ ts_frame_avg = ts_frame.tv_nsec / NSEC_PER_USEC +
+ ts_frame.tv_sec * USEC_PER_SEC;
+ else
+ ts_frame_avg = (ts_frame_avg + ts_frame.tv_nsec / NSEC_PER_USEC
+ + ts_frame.tv_sec * USEC_PER_SEC)/2;
+ if (timespec_compare(&ts_frame, &ts_frame_max) > 0)
+ ts_frame_max = ts_frame;
+
+ atomic_inc(&frame_cnt);
+
+ if ((atomic_read(&frame_cnt) % 1000) == 0)
+ pr_debug("ipu_dev: max frame time:%ldus, avg frame time:%dus,"
+ "frame_cnt:%d\n", ts_frame_max.tv_nsec / NSEC_PER_USEC
+ + ts_frame_max.tv_sec * USEC_PER_SEC,
+ ts_frame_avg, atomic_read(&frame_cnt));
+#endif
+done:
+ if (ret < 0)
+ dev_err(tsk->dev, "ERR: no-0x%x,ipu_queue_task err:%d\n",
+ tsk->task_no, ret);
+
+ kref_put(&tsk->refcount, task_mem_free);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_queue_task);
+
+static int mxc_ipu_open(struct inode *inode, struct file *file)
+{
+ file->private_data = (void *)atomic_inc_return(&file_index);
+ return 0;
+}
+
+static long mxc_ipu_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int __user *argp = (void __user *)arg;
+ int ret = 0;
+
+ switch (cmd) {
+ case IPU_CHECK_TASK:
+ {
+ struct ipu_task task;
+
+ if (copy_from_user
+ (&task, (struct ipu_task *) arg,
+ sizeof(struct ipu_task)))
+ return -EFAULT;
+ ret = ipu_check_task(&task);
+ if (copy_to_user((struct ipu_task *) arg,
+ &task, sizeof(struct ipu_task)))
+ return -EFAULT;
+ break;
+ }
+ case IPU_QUEUE_TASK:
+ {
+ struct ipu_task task;
+
+ if (copy_from_user
+ (&task, (struct ipu_task *) arg,
+ sizeof(struct ipu_task)))
+ return -EFAULT;
+ ret = ipu_queue_task(&task);
+ break;
+ }
+ case IPU_ALLOC:
+ {
+ int size;
+ struct ipu_alloc_list *mem;
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (mem == NULL)
+ return -ENOMEM;
+
+ if (get_user(size, argp)) {
+ kfree(mem);
+ return -EFAULT;
+ }
+
+ mem->size = PAGE_ALIGN(size);
+
+ mem->cpu_addr = dma_alloc_coherent(ipu_dev, size,
+ &mem->phy_addr,
+ GFP_DMA | GFP_KERNEL);
+ if (mem->cpu_addr == NULL) {
+ kfree(mem);
+ return -ENOMEM;
+ }
+ mem->file_index = file->private_data;
+ mutex_lock(&ipu_alloc_lock);
+ list_add(&mem->list, &ipu_alloc_list);
+ mutex_unlock(&ipu_alloc_lock);
+
+ if (put_user(mem->phy_addr, argp)) {
+ mutex_lock(&ipu_alloc_lock);
+ list_del(&mem->list);
+ mutex_unlock(&ipu_alloc_lock);
+ dma_free_coherent(ipu_dev,
+ mem->size,
+ mem->cpu_addr,
+ mem->phy_addr);
+ kfree(mem);
+ return -EFAULT;
+ }
+
+ dev_dbg(ipu_dev, "allocated %d bytes @ 0x%08X\n",
+ mem->size, mem->phy_addr);
+
+ break;
+ }
+ case IPU_FREE:
+ {
+ unsigned long offset;
+ struct ipu_alloc_list *mem;
+
+ if (get_user(offset, argp))
+ return -EFAULT;
+
+ ret = -EINVAL;
+ mutex_lock(&ipu_alloc_lock);
+ list_for_each_entry(mem, &ipu_alloc_list, list) {
+ if (mem->phy_addr == offset) {
+ list_del(&mem->list);
+ dma_free_coherent(ipu_dev,
+ mem->size,
+ mem->cpu_addr,
+ mem->phy_addr);
+ kfree(mem);
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&ipu_alloc_lock);
+ if (0 == ret)
+ dev_dbg(ipu_dev, "free %d bytes @ 0x%08X\n",
+ mem->size, mem->phy_addr);
+
+ break;
+ }
+ default:
+ break;
+ }
+ return ret;
+}
+
+static int mxc_ipu_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ bool found = false;
+ u32 len;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ struct ipu_alloc_list *mem;
+
+ mutex_lock(&ipu_alloc_lock);
+ list_for_each_entry(mem, &ipu_alloc_list, list) {
+ if (offset == mem->phy_addr) {
+ found = true;
+ len = mem->size;
+ break;
+ }
+ }
+ mutex_unlock(&ipu_alloc_lock);
+ if (!found)
+ return -EINVAL;
+
+ if (vma->vm_end - vma->vm_start > len)
+ return -EINVAL;
+
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
+ printk(KERN_ERR
+ "mmap failed!\n");
+ return -ENOBUFS;
+ }
+ return 0;
+}
+
+static int mxc_ipu_release(struct inode *inode, struct file *file)
+{
+ struct ipu_alloc_list *mem;
+ struct ipu_alloc_list *n;
+
+ mutex_lock(&ipu_alloc_lock);
+ list_for_each_entry_safe(mem, n, &ipu_alloc_list, list) {
+ if ((mem->cpu_addr != 0) &&
+ (file->private_data == mem->file_index)) {
+ list_del(&mem->list);
+ dma_free_coherent(ipu_dev,
+ mem->size,
+ mem->cpu_addr,
+ mem->phy_addr);
+ dev_dbg(ipu_dev, "rel-free %d bytes @ 0x%08X\n",
+ mem->size, mem->phy_addr);
+ kfree(mem);
+ }
+ }
+ mutex_unlock(&ipu_alloc_lock);
+ atomic_dec(&file_index);
+
+ return 0;
+}
+
+static struct file_operations mxc_ipu_fops = {
+ .owner = THIS_MODULE,
+ .open = mxc_ipu_open,
+ .mmap = mxc_ipu_mmap,
+ .release = mxc_ipu_release,
+ .unlocked_ioctl = mxc_ipu_ioctl,
+};
+
+int register_ipu_device(struct ipu_soc *ipu, int id)
+{
+ int ret = 0;
+ static int idx;
+ static struct ipu_thread_data thread_data[5];
+
+ if (!major) {
+ major = register_chrdev(0, "mxc_ipu", &mxc_ipu_fops);
+ if (major < 0) {
+ printk(KERN_ERR "Unable to register mxc_ipu as a char device\n");
+ ret = major;
+ goto register_cdev_fail;
+ }
+
+ ipu_class = class_create(THIS_MODULE, "mxc_ipu");
+ if (IS_ERR(ipu_class)) {
+ ret = PTR_ERR(ipu_class);
+ goto ipu_class_fail;
+ }
+
+ ipu_dev = device_create(ipu_class, NULL, MKDEV(major, 0),
+ NULL, "mxc_ipu");
+ if (IS_ERR(ipu_dev)) {
+ ret = PTR_ERR(ipu_dev);
+ goto dev_create_fail;
+ }
+ ipu_dev->dma_mask = kmalloc(sizeof(*ipu_dev->dma_mask), GFP_KERNEL);
+ *ipu_dev->dma_mask = DMA_BIT_MASK(32);
+ ipu_dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ mutex_init(&ipu_ch_tbl.lock);
+ }
+ max_ipu_no = ++id;
+ ipu->rot_dma[0].size = 0;
+ ipu->rot_dma[1].size = 0;
+
+ thread_data[idx].ipu = ipu;
+ thread_data[idx].id = 0;
+ thread_data[idx].is_vdoa = 0;
+ ipu->thread[0] = kthread_run(ipu_task_thread, &thread_data[idx++],
+ "ipu%d_task", id);
+ if (IS_ERR(ipu->thread[0])) {
+ ret = PTR_ERR(ipu->thread[0]);
+ goto kthread0_fail;
+ }
+
+ thread_data[idx].ipu = ipu;
+ thread_data[idx].id = 1;
+ thread_data[idx].is_vdoa = 0;
+ ipu->thread[1] = kthread_run(ipu_task_thread, &thread_data[idx++],
+ "ipu%d_task", id);
+ if (IS_ERR(ipu->thread[1])) {
+ ret = PTR_ERR(ipu->thread[1]);
+ goto kthread1_fail;
+ }
+
+
+ return ret;
+
+kthread1_fail:
+ kthread_stop(ipu->thread[0]);
+kthread0_fail:
+ if (id == 0)
+ device_destroy(ipu_class, MKDEV(major, 0));
+dev_create_fail:
+ if (id == 0) {
+ class_destroy(ipu_class);
+ }
+ipu_class_fail:
+ if (id == 0)
+ unregister_chrdev(major, "mxc_ipu");
+register_cdev_fail:
+ return ret;
+}
+
+void unregister_ipu_device(struct ipu_soc *ipu, int id)
+{
+ int i;
+
+ kthread_stop(ipu->thread[0]);
+ kthread_stop(ipu->thread[1]);
+ for (i = 0; i < 2; i++) {
+ if (ipu->rot_dma[i].vaddr)
+ dma_free_coherent(ipu_dev,
+ ipu->rot_dma[i].size,
+ ipu->rot_dma[i].vaddr,
+ ipu->rot_dma[i].paddr);
+ }
+
+ if (major) {
+ device_destroy(ipu_class, MKDEV(major, 0));
+ class_destroy(ipu_class);
+ unregister_chrdev(major, "mxc_ipu");
+ major = 0;
+ }
+}
diff --git a/drivers/mxc/ipu3/ipu_disp.c b/drivers/mxc/ipu3/ipu_disp.c
new file mode 100644
index 000000000000..f2ccb1e3a137
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_disp.c
@@ -0,0 +1,1981 @@
+/*
+ * Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_disp.c
+ *
+ * @brief IPU display submodule API functions
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/atomic.h>
+
+#include "ipu_param_mem.h"
+#include "ipu_regs.h"
+
+struct dp_csc_param_t {
+ int mode;
+ void *coeff;
+};
+
+#define SYNC_WAVE 0
+#define NULL_WAVE (-1)
+#define ASYNC_SER_WAVE 6
+
+/* DC display ID assignments */
+#define DC_DISP_ID_SYNC(di) (di)
+#define DC_DISP_ID_SERIAL 2
+#define DC_DISP_ID_ASYNC 3
+
+int dmfc_type_setup;
+
+void _ipu_dmfc_init(struct ipu_soc *ipu, int dmfc_type, int first)
+{
+ u32 dmfc_wr_chan, dmfc_dp_chan;
+
+ if (first) {
+ if (dmfc_type_setup > dmfc_type)
+ dmfc_type = dmfc_type_setup;
+ else
+ dmfc_type_setup = dmfc_type;
+
+ /* disable DMFC-IC channel*/
+ ipu_dmfc_write(ipu, 0x2, DMFC_IC_CTRL);
+ } else if (dmfc_type_setup >= DMFC_HIGH_RESOLUTION_DC) {
+ dev_dbg(ipu->dev, "DMFC high resolution has set, will not change\n");
+ return;
+ } else
+ dmfc_type_setup = dmfc_type;
+
+ if (dmfc_type == DMFC_HIGH_RESOLUTION_DC) {
+ /* 1 - segment 0~3;
+ * 5B - segement 4, 5;
+ * 5F - segement 6, 7;
+ * 1C, 2C and 6B, 6F unused;
+ */
+ dev_info(ipu->dev, "IPU DMFC DC HIGH RESOLUTION: 1(0~3), 5B(4,5), 5F(6,7)\n");
+ dmfc_wr_chan = 0x00000088;
+ dmfc_dp_chan = 0x00009694;
+ ipu->dmfc_size_28 = 256*4;
+ ipu->dmfc_size_29 = 0;
+ ipu->dmfc_size_24 = 0;
+ ipu->dmfc_size_27 = 128*4;
+ ipu->dmfc_size_23 = 128*4;
+ } else if (dmfc_type == DMFC_HIGH_RESOLUTION_DP) {
+ /* 1 - segment 0, 1;
+ * 5B - segement 2~5;
+ * 5F - segement 6,7;
+ * 1C, 2C and 6B, 6F unused;
+ */
+ dev_info(ipu->dev, "IPU DMFC DP HIGH RESOLUTION: 1(0,1), 5B(2~5), 5F(6,7)\n");
+ dmfc_wr_chan = 0x00000090;
+ dmfc_dp_chan = 0x0000968a;
+ ipu->dmfc_size_28 = 128*4;
+ ipu->dmfc_size_29 = 0;
+ ipu->dmfc_size_24 = 0;
+ ipu->dmfc_size_27 = 128*4;
+ ipu->dmfc_size_23 = 256*4;
+ } else if (dmfc_type == DMFC_HIGH_RESOLUTION_ONLY_DP) {
+ /* 5B - segement 0~3;
+ * 5F - segement 4~7;
+ * 1, 1C, 2C and 6B, 6F unused;
+ */
+ dev_info(ipu->dev, "IPU DMFC ONLY-DP HIGH RESOLUTION: 5B(0~3), 5F(4~7)\n");
+ dmfc_wr_chan = 0x00000000;
+ dmfc_dp_chan = 0x00008c88;
+ ipu->dmfc_size_28 = 0;
+ ipu->dmfc_size_29 = 0;
+ ipu->dmfc_size_24 = 0;
+ ipu->dmfc_size_27 = 256*4;
+ ipu->dmfc_size_23 = 256*4;
+ } else {
+ /* 1 - segment 0, 1;
+ * 5B - segement 4, 5;
+ * 5F - segement 6, 7;
+ * 1C, 2C and 6B, 6F unused;
+ */
+ dev_info(ipu->dev, "IPU DMFC NORMAL mode: 1(0~1), 5B(4,5), 5F(6,7)\n");
+ dmfc_wr_chan = 0x00000090;
+ dmfc_dp_chan = 0x00009694;
+ ipu->dmfc_size_28 = 128*4;
+ ipu->dmfc_size_29 = 0;
+ ipu->dmfc_size_24 = 0;
+ ipu->dmfc_size_27 = 128*4;
+ ipu->dmfc_size_23 = 128*4;
+ }
+ ipu_dmfc_write(ipu, dmfc_wr_chan, DMFC_WR_CHAN);
+ ipu_dmfc_write(ipu, 0x202020F6, DMFC_WR_CHAN_DEF);
+ ipu_dmfc_write(ipu, dmfc_dp_chan, DMFC_DP_CHAN);
+ /* Enable chan 5 watermark set at 5 bursts and clear at 7 bursts */
+ ipu_dmfc_write(ipu, 0x2020F6F6, DMFC_DP_CHAN_DEF);
+}
+
+static int __init dmfc_setup(char *options)
+{
+ get_option(&options, &dmfc_type_setup);
+ if (dmfc_type_setup > DMFC_HIGH_RESOLUTION_ONLY_DP)
+ dmfc_type_setup = DMFC_HIGH_RESOLUTION_ONLY_DP;
+ return 1;
+}
+__setup("dmfc=", dmfc_setup);
+
+void _ipu_dmfc_set_wait4eot(struct ipu_soc *ipu, int dma_chan, int width)
+{
+ u32 dmfc_gen1 = ipu_dmfc_read(ipu, DMFC_GENERAL1);
+
+ if (width >= HIGH_RESOLUTION_WIDTH) {
+ if (dma_chan == 23)
+ _ipu_dmfc_init(ipu, DMFC_HIGH_RESOLUTION_DP, 0);
+ else if (dma_chan == 28)
+ _ipu_dmfc_init(ipu, DMFC_HIGH_RESOLUTION_DC, 0);
+ }
+
+ if (dma_chan == 23) { /*5B*/
+ if (ipu->dmfc_size_23/width > 3)
+ dmfc_gen1 |= 1UL << 20;
+ else
+ dmfc_gen1 &= ~(1UL << 20);
+ } else if (dma_chan == 24) { /*6B*/
+ if (ipu->dmfc_size_24/width > 1)
+ dmfc_gen1 |= 1UL << 22;
+ else
+ dmfc_gen1 &= ~(1UL << 22);
+ } else if (dma_chan == 27) { /*5F*/
+ if (ipu->dmfc_size_27/width > 2)
+ dmfc_gen1 |= 1UL << 21;
+ else
+ dmfc_gen1 &= ~(1UL << 21);
+ } else if (dma_chan == 28) { /*1*/
+ if (ipu->dmfc_size_28/width > 2)
+ dmfc_gen1 |= 1UL << 16;
+ else
+ dmfc_gen1 &= ~(1UL << 16);
+ } else if (dma_chan == 29) { /*6F*/
+ if (ipu->dmfc_size_29/width > 1)
+ dmfc_gen1 |= 1UL << 23;
+ else
+ dmfc_gen1 &= ~(1UL << 23);
+ }
+
+ ipu_dmfc_write(ipu, dmfc_gen1, DMFC_GENERAL1);
+}
+
+void _ipu_dmfc_set_burst_size(struct ipu_soc *ipu, int dma_chan, int burst_size)
+{
+ u32 dmfc_wr_chan = ipu_dmfc_read(ipu, DMFC_WR_CHAN);
+ u32 dmfc_dp_chan = ipu_dmfc_read(ipu, DMFC_DP_CHAN);
+ int dmfc_bs = 0;
+
+ switch (burst_size) {
+ case 64:
+ dmfc_bs = 0x40;
+ break;
+ case 32:
+ case 20:
+ dmfc_bs = 0x80;
+ break;
+ case 16:
+ dmfc_bs = 0xc0;
+ break;
+ default:
+ dev_err(ipu->dev, "Unsupported burst size %d\n",
+ burst_size);
+ return;
+ }
+
+ if (dma_chan == 23) { /*5B*/
+ dmfc_dp_chan &= ~(0xc0);
+ dmfc_dp_chan |= dmfc_bs;
+ } else if (dma_chan == 27) { /*5F*/
+ dmfc_dp_chan &= ~(0xc000);
+ dmfc_dp_chan |= (dmfc_bs << 8);
+ } else if (dma_chan == 28) { /*1*/
+ dmfc_wr_chan &= ~(0xc0);
+ dmfc_wr_chan |= dmfc_bs;
+ }
+
+ ipu_dmfc_write(ipu, dmfc_wr_chan, DMFC_WR_CHAN);
+ ipu_dmfc_write(ipu, dmfc_dp_chan, DMFC_DP_CHAN);
+}
+
+static void _ipu_di_data_wave_config(struct ipu_soc *ipu,
+ int di, int wave_gen,
+ int access_size, int component_size)
+{
+ u32 reg;
+ reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
+ (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
+ ipu_di_write(ipu, di, reg, DI_DW_GEN(wave_gen));
+}
+
+static void _ipu_di_data_pin_config(struct ipu_soc *ipu,
+ int di, int wave_gen, int di_pin, int set,
+ int up, int down)
+{
+ u32 reg;
+
+ reg = ipu_di_read(ipu, di, DI_DW_GEN(wave_gen));
+ reg &= ~(0x3 << (di_pin * 2));
+ reg |= set << (di_pin * 2);
+ ipu_di_write(ipu, di, reg, DI_DW_GEN(wave_gen));
+
+ ipu_di_write(ipu, di, (down << 16) | up, DI_DW_SET(wave_gen, set));
+}
+
+static void _ipu_di_sync_config(struct ipu_soc *ipu,
+ int di, int wave_gen,
+ int run_count, int run_src,
+ int offset_count, int offset_src,
+ int repeat_count, int cnt_clr_src,
+ int cnt_polarity_gen_en,
+ int cnt_polarity_clr_src,
+ int cnt_polarity_trigger_src,
+ int cnt_up, int cnt_down)
+{
+ u32 reg;
+
+ if ((run_count >= 0x1000) || (offset_count >= 0x1000) || (repeat_count >= 0x1000) ||
+ (cnt_up >= 0x400) || (cnt_down >= 0x400)) {
+ dev_err(ipu->dev, "DI%d counters out of range.\n", di);
+ return;
+ }
+
+ reg = (run_count << 19) | (++run_src << 16) |
+ (offset_count << 3) | ++offset_src;
+ ipu_di_write(ipu, di, reg, DI_SW_GEN0(wave_gen));
+ reg = (cnt_polarity_gen_en << 29) | (++cnt_clr_src << 25) |
+ (++cnt_polarity_trigger_src << 12) | (++cnt_polarity_clr_src << 9);
+ reg |= (cnt_down << 16) | cnt_up;
+ if (repeat_count == 0) {
+ /* Enable auto reload */
+ reg |= 0x10000000;
+ }
+ ipu_di_write(ipu, di, reg, DI_SW_GEN1(wave_gen));
+ reg = ipu_di_read(ipu, di, DI_STP_REP(wave_gen));
+ reg &= ~(0xFFFF << (16 * ((wave_gen - 1) & 0x1)));
+ reg |= repeat_count << (16 * ((wave_gen - 1) & 0x1));
+ ipu_di_write(ipu, di, reg, DI_STP_REP(wave_gen));
+}
+
+static void _ipu_dc_map_link(struct ipu_soc *ipu,
+ int current_map,
+ int base_map_0, int buf_num_0,
+ int base_map_1, int buf_num_1,
+ int base_map_2, int buf_num_2)
+{
+ int ptr_0 = base_map_0 * 3 + buf_num_0;
+ int ptr_1 = base_map_1 * 3 + buf_num_1;
+ int ptr_2 = base_map_2 * 3 + buf_num_2;
+ int ptr;
+ u32 reg;
+ ptr = (ptr_2 << 10) + (ptr_1 << 5) + ptr_0;
+
+ reg = ipu_dc_read(ipu, DC_MAP_CONF_PTR(current_map));
+ reg &= ~(0x1F << ((16 * (current_map & 0x1))));
+ reg |= ptr << ((16 * (current_map & 0x1)));
+ ipu_dc_write(ipu, reg, DC_MAP_CONF_PTR(current_map));
+}
+
+static void _ipu_dc_map_config(struct ipu_soc *ipu,
+ int map, int byte_num, int offset, int mask)
+{
+ int ptr = map * 3 + byte_num;
+ u32 reg;
+
+ reg = ipu_dc_read(ipu, DC_MAP_CONF_VAL(ptr));
+ reg &= ~(0xFFFF << (16 * (ptr & 0x1)));
+ reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
+ ipu_dc_write(ipu, reg, DC_MAP_CONF_VAL(ptr));
+
+ reg = ipu_dc_read(ipu, DC_MAP_CONF_PTR(map));
+ reg &= ~(0x1F << ((16 * (map & 0x1)) + (5 * byte_num)));
+ reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
+ ipu_dc_write(ipu, reg, DC_MAP_CONF_PTR(map));
+}
+
+static void _ipu_dc_map_clear(struct ipu_soc *ipu, int map)
+{
+ u32 reg = ipu_dc_read(ipu, DC_MAP_CONF_PTR(map));
+ ipu_dc_write(ipu, reg & ~(0xFFFF << (16 * (map & 0x1))),
+ DC_MAP_CONF_PTR(map));
+}
+
+static void _ipu_dc_write_tmpl(struct ipu_soc *ipu,
+ int word, u32 opcode, u32 operand, int map,
+ int wave, int glue, int sync, int stop)
+{
+ u32 reg;
+
+ if (opcode == WRG) {
+ reg = sync;
+ reg |= (glue << 4);
+ reg |= (++wave << 11);
+ reg |= ((operand & 0x1FFFF) << 15);
+ ipu_dc_tmpl_write(ipu, reg, word * 8);
+
+ reg = (operand >> 17);
+ reg |= opcode << 7;
+ reg |= (stop << 9);
+ ipu_dc_tmpl_write(ipu, reg, word * 8 + 4);
+ } else {
+ reg = sync;
+ reg |= (glue << 4);
+ reg |= (++wave << 11);
+ reg |= (++map << 15);
+ reg |= (operand << 20) & 0xFFF00000;
+ ipu_dc_tmpl_write(ipu, reg, word * 8);
+
+ reg = (operand >> 12);
+ reg |= opcode << 4;
+ reg |= (stop << 9);
+ ipu_dc_tmpl_write(ipu, reg, word * 8 + 4);
+ }
+}
+
+static void _ipu_dc_link_event(struct ipu_soc *ipu,
+ int chan, int event, int addr, int priority)
+{
+ u32 reg;
+ u32 address_shift;
+ if (event < DC_EVEN_UGDE0) {
+ reg = ipu_dc_read(ipu, DC_RL_CH(chan, event));
+ reg &= ~(0xFFFF << (16 * (event & 0x1)));
+ reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
+ ipu_dc_write(ipu, reg, DC_RL_CH(chan, event));
+ } else {
+ reg = ipu_dc_read(ipu, DC_UGDE_0((event - DC_EVEN_UGDE0) / 2));
+ if ((event - DC_EVEN_UGDE0) & 0x1) {
+ reg &= ~(0x2FF << 16);
+ reg |= (addr << 16);
+ reg |= priority ? (2 << 24) : 0x0;
+ } else {
+ reg &= ~0xFC00FFFF;
+ if (priority)
+ chan = (chan >> 1) +
+ ((((chan & 0x1) + ((chan & 0x2) >> 1))) | (chan >> 3));
+ else
+ chan = 0x7;
+ address_shift = ((event - DC_EVEN_UGDE0) >> 1) ? 7 : 8;
+ reg |= (addr << address_shift) | (priority << 3) | chan;
+ }
+ ipu_dc_write(ipu, reg, DC_UGDE_0((event - DC_EVEN_UGDE0) / 2));
+ }
+}
+
+/* Y = R * 1.200 + G * 2.343 + B * .453 + 0.250;
+ U = R * -.672 + G * -1.328 + B * 2.000 + 512.250.;
+ V = R * 2.000 + G * -1.672 + B * -.328 + 512.250.;*/
+static const int rgb2ycbcr_coeff[5][3] = {
+ {0x4D, 0x96, 0x1D},
+ {-0x2B, -0x55, 0x80},
+ {0x80, -0x6B, -0x15},
+ {0x0000, 0x0200, 0x0200}, /* B0, B1, B2 */
+ {0x2, 0x2, 0x2}, /* S0, S1, S2 */
+};
+
+/* R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
+ G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
+ B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); */
+static const int ycbcr2rgb_coeff[5][3] = {
+ {0x095, 0x000, 0x0CC},
+ {0x095, 0x3CE, 0x398},
+ {0x095, 0x0FF, 0x000},
+ {0x3E42, 0x010A, 0x3DD6}, /*B0,B1,B2 */
+ {0x1, 0x1, 0x1}, /*S0,S1,S2 */
+};
+
+#define mask_a(a) ((u32)(a) & 0x3FF)
+#define mask_b(b) ((u32)(b) & 0x3FFF)
+
+/* Pls keep S0, S1 and S2 as 0x2 by using this convertion */
+static int _rgb_to_yuv(int n, int red, int green, int blue)
+{
+ int c;
+ c = red * rgb2ycbcr_coeff[n][0];
+ c += green * rgb2ycbcr_coeff[n][1];
+ c += blue * rgb2ycbcr_coeff[n][2];
+ c /= 16;
+ c += rgb2ycbcr_coeff[3][n] * 4;
+ c += 8;
+ c /= 16;
+ if (c < 0)
+ c = 0;
+ if (c > 255)
+ c = 255;
+ return c;
+}
+
+/*
+ * Row is for BG: RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
+ * Column is for FG: RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
+ */
+static struct dp_csc_param_t dp_csc_array[CSC_NUM][CSC_NUM] = {
+{
+ {DP_COM_CONF_CSC_DEF_BOTH, (void *)&rgb2ycbcr_coeff},
+ {0, 0}, {0, 0},
+ {DP_COM_CONF_CSC_DEF_BG, (void *)&rgb2ycbcr_coeff},
+ {DP_COM_CONF_CSC_DEF_BG, (void *)&rgb2ycbcr_coeff}
+},
+{
+ {0, 0},
+ {DP_COM_CONF_CSC_DEF_BOTH, (void *)&ycbcr2rgb_coeff},
+ {DP_COM_CONF_CSC_DEF_BG, (void *)&ycbcr2rgb_coeff},
+ {0, 0},
+ {DP_COM_CONF_CSC_DEF_BG, (void *)&ycbcr2rgb_coeff}
+},
+{
+ {0, 0},
+ {DP_COM_CONF_CSC_DEF_FG, (void *)&ycbcr2rgb_coeff},
+ {0, 0}, {0, 0}, {0, 0}
+},
+{
+ {DP_COM_CONF_CSC_DEF_FG, (void *)&rgb2ycbcr_coeff},
+ {0, 0}, {0, 0}, {0, 0}, {0, 0}
+},
+{
+ {DP_COM_CONF_CSC_DEF_FG, (void *)&rgb2ycbcr_coeff},
+ {DP_COM_CONF_CSC_DEF_FG, (void *)&ycbcr2rgb_coeff},
+ {0, 0}, {0, 0}, {0, 0}
+}
+};
+
+void __ipu_dp_csc_setup(struct ipu_soc *ipu,
+ int dp, struct dp_csc_param_t dp_csc_param,
+ bool srm_mode_update)
+{
+ u32 reg;
+ const int (*coeff)[5][3];
+
+ if (dp_csc_param.mode >= 0) {
+ reg = ipu_dp_read(ipu, DP_COM_CONF(dp));
+ reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+ reg |= dp_csc_param.mode;
+ ipu_dp_write(ipu, reg, DP_COM_CONF(dp));
+ }
+
+ coeff = dp_csc_param.coeff;
+
+ if (coeff) {
+ ipu_dp_write(ipu, mask_a((*coeff)[0][0]) |
+ (mask_a((*coeff)[0][1]) << 16), DP_CSC_A_0(dp));
+ ipu_dp_write(ipu, mask_a((*coeff)[0][2]) |
+ (mask_a((*coeff)[1][0]) << 16), DP_CSC_A_1(dp));
+ ipu_dp_write(ipu, mask_a((*coeff)[1][1]) |
+ (mask_a((*coeff)[1][2]) << 16), DP_CSC_A_2(dp));
+ ipu_dp_write(ipu, mask_a((*coeff)[2][0]) |
+ (mask_a((*coeff)[2][1]) << 16), DP_CSC_A_3(dp));
+ ipu_dp_write(ipu, mask_a((*coeff)[2][2]) |
+ (mask_b((*coeff)[3][0]) << 16) |
+ ((*coeff)[4][0] << 30), DP_CSC_0(dp));
+ ipu_dp_write(ipu, mask_b((*coeff)[3][1]) | ((*coeff)[4][1] << 14) |
+ (mask_b((*coeff)[3][2]) << 16) |
+ ((*coeff)[4][2] << 30), DP_CSC_1(dp));
+ }
+
+ if (srm_mode_update) {
+ reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+ ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+ }
+}
+
+int _ipu_dp_init(struct ipu_soc *ipu,
+ ipu_channel_t channel, uint32_t in_pixel_fmt,
+ uint32_t out_pixel_fmt)
+{
+ int in_fmt, out_fmt;
+ int dp;
+ int partial = false;
+ uint32_t reg;
+
+ if (channel == MEM_FG_SYNC) {
+ dp = DP_SYNC;
+ partial = true;
+ } else if (channel == MEM_BG_SYNC) {
+ dp = DP_SYNC;
+ partial = false;
+ } else if (channel == MEM_BG_ASYNC0) {
+ dp = DP_ASYNC0;
+ partial = false;
+ } else {
+ return -EINVAL;
+ }
+
+ in_fmt = format_to_colorspace(in_pixel_fmt);
+ out_fmt = format_to_colorspace(out_pixel_fmt);
+
+ if (partial) {
+ if (in_fmt == RGB) {
+ if (out_fmt == RGB)
+ ipu->fg_csc_type = RGB2RGB;
+ else
+ ipu->fg_csc_type = RGB2YUV;
+ } else {
+ if (out_fmt == RGB)
+ ipu->fg_csc_type = YUV2RGB;
+ else
+ ipu->fg_csc_type = YUV2YUV;
+ }
+ } else {
+ if (in_fmt == RGB) {
+ if (out_fmt == RGB)
+ ipu->bg_csc_type = RGB2RGB;
+ else
+ ipu->bg_csc_type = RGB2YUV;
+ } else {
+ if (out_fmt == RGB)
+ ipu->bg_csc_type = YUV2RGB;
+ else
+ ipu->bg_csc_type = YUV2YUV;
+ }
+ }
+
+ /* Transform color key from rgb to yuv if CSC is enabled */
+ reg = ipu_dp_read(ipu, DP_COM_CONF(dp));
+ if (ipu->color_key_4rgb && (reg & DP_COM_CONF_GWCKE) &&
+ (((ipu->fg_csc_type == RGB2YUV) && (ipu->bg_csc_type == YUV2YUV)) ||
+ ((ipu->fg_csc_type == YUV2YUV) && (ipu->bg_csc_type == RGB2YUV)) ||
+ ((ipu->fg_csc_type == YUV2YUV) && (ipu->bg_csc_type == YUV2YUV)) ||
+ ((ipu->fg_csc_type == YUV2RGB) && (ipu->bg_csc_type == YUV2RGB)))) {
+ int red, green, blue;
+ int y, u, v;
+ uint32_t color_key = ipu_dp_read(ipu, DP_GRAPH_WIND_CTRL(dp)) & 0xFFFFFFL;
+
+ dev_dbg(ipu->dev, "_ipu_dp_init color key 0x%x need change to yuv fmt!\n", color_key);
+
+ red = (color_key >> 16) & 0xFF;
+ green = (color_key >> 8) & 0xFF;
+ blue = color_key & 0xFF;
+
+ y = _rgb_to_yuv(0, red, green, blue);
+ u = _rgb_to_yuv(1, red, green, blue);
+ v = _rgb_to_yuv(2, red, green, blue);
+ color_key = (y << 16) | (u << 8) | v;
+
+ reg = ipu_dp_read(ipu, DP_GRAPH_WIND_CTRL(dp)) & 0xFF000000L;
+ ipu_dp_write(ipu, reg | color_key, DP_GRAPH_WIND_CTRL(dp));
+ ipu->color_key_4rgb = false;
+
+ dev_dbg(ipu->dev, "_ipu_dp_init color key change to yuv fmt 0x%x!\n", color_key);
+ }
+
+ __ipu_dp_csc_setup(ipu, dp,
+ dp_csc_array[ipu->bg_csc_type][ipu->fg_csc_type],
+ false);
+
+ return 0;
+}
+
+void _ipu_dp_uninit(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+ int dp;
+ int partial = false;
+
+ if (channel == MEM_FG_SYNC) {
+ dp = DP_SYNC;
+ partial = true;
+ } else if (channel == MEM_BG_SYNC) {
+ dp = DP_SYNC;
+ partial = false;
+ } else if (channel == MEM_BG_ASYNC0) {
+ dp = DP_ASYNC0;
+ partial = false;
+ } else {
+ return;
+ }
+
+ if (partial)
+ ipu->fg_csc_type = CSC_NONE;
+ else
+ ipu->bg_csc_type = CSC_NONE;
+
+ __ipu_dp_csc_setup(ipu, dp, dp_csc_array[ipu->bg_csc_type][ipu->fg_csc_type], false);
+}
+
+void _ipu_dc_init(struct ipu_soc *ipu, int dc_chan, int di, bool interlaced, uint32_t pixel_fmt)
+{
+ u32 reg = 0;
+
+ if ((dc_chan == 1) || (dc_chan == 5)) {
+ if (interlaced) {
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NL, 0, 3);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOL, 0, 2);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA, 0, 1);
+ } else {
+ if (di) {
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NL, 2, 3);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOL, 3, 2);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA, 1, 1);
+ if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+ (pixel_fmt == IPU_PIX_FMT_UYVY) ||
+ (pixel_fmt == IPU_PIX_FMT_YVYU) ||
+ (pixel_fmt == IPU_PIX_FMT_VYUY)) {
+ _ipu_dc_link_event(ipu, dc_chan, DC_ODD_UGDE1, 9, 5);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVEN_UGDE1, 8, 5);
+ }
+ } else {
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NL, 5, 3);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOL, 6, 2);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA, 12, 1);
+ if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+ (pixel_fmt == IPU_PIX_FMT_UYVY) ||
+ (pixel_fmt == IPU_PIX_FMT_YVYU) ||
+ (pixel_fmt == IPU_PIX_FMT_VYUY)) {
+ _ipu_dc_link_event(ipu, dc_chan, DC_ODD_UGDE0, 10, 5);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVEN_UGDE0, 11, 5);
+ }
+ }
+ }
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NF, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NFIELD, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOF, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOFIELD, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR, 0, 0);
+
+ reg = 0x2;
+ reg |= DC_DISP_ID_SYNC(di) << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
+ reg |= di << 2;
+ if (interlaced)
+ reg |= DC_WR_CH_CONF_FIELD_MODE;
+ } else if ((dc_chan == 8) || (dc_chan == 9)) {
+ /* async channels */
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_W_0, 0x64, 1);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_W_1, 0x64, 1);
+
+ reg = 0x3;
+ reg |= DC_DISP_ID_SERIAL << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
+ }
+ ipu_dc_write(ipu, reg, DC_WR_CH_CONF(dc_chan));
+
+ ipu_dc_write(ipu, 0x00000000, DC_WR_CH_ADDR(dc_chan));
+
+ ipu_dc_write(ipu, 0x00000084, DC_GEN);
+}
+
+void _ipu_dc_uninit(struct ipu_soc *ipu, int dc_chan)
+{
+ if ((dc_chan == 1) || (dc_chan == 5)) {
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NL, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOL, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NF, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NFIELD, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOF, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOFIELD, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_ODD_UGDE0, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVEN_UGDE0, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_ODD_UGDE1, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVEN_UGDE1, 0, 0);
+ } else if ((dc_chan == 8) || (dc_chan == 9)) {
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR_W_0, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR_W_1, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN_W_0, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN_W_1, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_W_0, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_W_1, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR_R_0, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR_R_1, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN_R_0, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN_R_1, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_R_0, 0, 0);
+ _ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_R_1, 0, 0);
+ }
+}
+
+int _ipu_disp_chan_is_interlaced(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+ if (channel == MEM_DC_SYNC)
+ return !!(ipu_dc_read(ipu, DC_WR_CH_CONF_1) &
+ DC_WR_CH_CONF_FIELD_MODE);
+ else if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC))
+ return !!(ipu_dc_read(ipu, DC_WR_CH_CONF_5) &
+ DC_WR_CH_CONF_FIELD_MODE);
+ return 0;
+}
+
+void _ipu_dp_dc_enable(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+ int di;
+ uint32_t reg;
+ uint32_t dc_chan;
+ int irq = 0;
+
+ if (channel == MEM_FG_SYNC)
+ irq = IPU_IRQ_DP_SF_END;
+ else if (channel == MEM_DC_SYNC)
+ dc_chan = 1;
+ else if (channel == MEM_BG_SYNC)
+ dc_chan = 5;
+ else
+ return;
+
+ if (channel == MEM_FG_SYNC) {
+ /* Enable FG channel */
+ reg = ipu_dp_read(ipu, DP_COM_CONF(DP_SYNC));
+ ipu_dp_write(ipu, reg | DP_COM_CONF_FG_EN, DP_COM_CONF(DP_SYNC));
+
+ reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+ ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+ return;
+ } else if (channel == MEM_BG_SYNC) {
+ reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+ ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+ }
+
+ di = ipu->dc_di_assignment[dc_chan];
+
+ /* Make sure other DC sync channel is not assigned same DI */
+ reg = ipu_dc_read(ipu, DC_WR_CH_CONF(6 - dc_chan));
+ if ((di << 2) == (reg & DC_WR_CH_CONF_PROG_DI_ID)) {
+ reg &= ~DC_WR_CH_CONF_PROG_DI_ID;
+ reg |= di ? 0 : DC_WR_CH_CONF_PROG_DI_ID;
+ ipu_dc_write(ipu, reg, DC_WR_CH_CONF(6 - dc_chan));
+ }
+
+ reg = ipu_dc_read(ipu, DC_WR_CH_CONF(dc_chan));
+ reg |= 4 << DC_WR_CH_CONF_PROG_TYPE_OFFSET;
+ ipu_dc_write(ipu, reg, DC_WR_CH_CONF(dc_chan));
+
+ clk_prepare_enable(ipu->pixel_clk[di]);
+ ipu->pixel_clk_en[ipu->dc_di_assignment[dc_chan]] = true;
+}
+
+static irqreturn_t dc_irq_handler(int irq, void *dev_id)
+{
+ struct ipu_soc *ipu = dev_id;
+ struct completion *comp = &ipu->dc_comp;
+ uint32_t reg;
+ uint32_t dc_chan;
+
+ if (irq == IPU_IRQ_DC_FC_1)
+ dc_chan = 1;
+ else
+ dc_chan = 5;
+
+ if (!ipu->dc_swap) {
+ reg = ipu_dc_read(ipu, DC_WR_CH_CONF(dc_chan));
+ reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+ ipu_dc_write(ipu, reg, DC_WR_CH_CONF(dc_chan));
+
+ reg = ipu_cm_read(ipu, IPU_DISP_GEN);
+ if (ipu->dc_di_assignment[dc_chan])
+ reg &= ~DI1_COUNTER_RELEASE;
+ else
+ reg &= ~DI0_COUNTER_RELEASE;
+ ipu_cm_write(ipu, reg, IPU_DISP_GEN);
+ }
+
+ complete(comp);
+ return IRQ_HANDLED;
+}
+
+void _ipu_dp_dc_disable(struct ipu_soc *ipu, ipu_channel_t channel, bool swap)
+{
+ int ret;
+ uint32_t reg;
+ uint32_t csc;
+ uint32_t dc_chan;
+ int irq = 0;
+ int timeout = 50;
+
+ ipu->dc_swap = swap;
+
+ if (channel == MEM_DC_SYNC) {
+ dc_chan = 1;
+ irq = IPU_IRQ_DC_FC_1;
+ } else if (channel == MEM_BG_SYNC) {
+ dc_chan = 5;
+ irq = IPU_IRQ_DP_SF_END;
+ } else if (channel == MEM_FG_SYNC) {
+ /* Disable FG channel */
+ dc_chan = 5;
+
+ reg = ipu_dp_read(ipu, DP_COM_CONF(DP_SYNC));
+ csc = reg & DP_COM_CONF_CSC_DEF_MASK;
+ if (csc == DP_COM_CONF_CSC_DEF_FG)
+ reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+
+ reg &= ~DP_COM_CONF_FG_EN;
+ ipu_dp_write(ipu, reg, DP_COM_CONF(DP_SYNC));
+
+ reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+ ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+ if (ipu_is_channel_busy(ipu, MEM_BG_SYNC)) {
+ ipu_cm_write(ipu, IPUIRQ_2_MASK(IPU_IRQ_DP_SF_END),
+ IPUIRQ_2_STATREG(ipu->devtype,
+ IPU_IRQ_DP_SF_END));
+ while ((ipu_cm_read(ipu,
+ IPUIRQ_2_STATREG(ipu->devtype,
+ IPU_IRQ_DP_SF_END)) &
+ IPUIRQ_2_MASK(IPU_IRQ_DP_SF_END)) == 0) {
+ msleep(2);
+ timeout -= 2;
+ if (timeout <= 0)
+ break;
+ }
+ }
+ return;
+ } else {
+ return;
+ }
+
+ init_completion(&ipu->dc_comp);
+ ret = ipu_request_irq(ipu, irq, dc_irq_handler, 0, NULL, ipu);
+ if (ret < 0) {
+ dev_err(ipu->dev, "DC irq %d in use\n", irq);
+ return;
+ }
+ ret = wait_for_completion_timeout(&ipu->dc_comp, msecs_to_jiffies(50));
+ ipu_free_irq(ipu, irq, ipu);
+ dev_dbg(ipu->dev, "DC stop timeout - %d * 10ms\n", 5 - ret);
+
+ if (ipu->dc_swap) {
+ /* Swap DC channel 1 and 5 settings, and disable old dc chan */
+ reg = ipu_dc_read(ipu, DC_WR_CH_CONF(dc_chan));
+ ipu_dc_write(ipu, reg, DC_WR_CH_CONF(6 - dc_chan));
+ reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+ reg ^= DC_WR_CH_CONF_PROG_DI_ID;
+ ipu_dc_write(ipu, reg, DC_WR_CH_CONF(dc_chan));
+ }
+}
+
+void _ipu_init_dc_mappings(struct ipu_soc *ipu)
+{
+ /* IPU_PIX_FMT_RGB24 */
+ _ipu_dc_map_clear(ipu, 0);
+ _ipu_dc_map_config(ipu, 0, 0, 7, 0xFF);
+ _ipu_dc_map_config(ipu, 0, 1, 15, 0xFF);
+ _ipu_dc_map_config(ipu, 0, 2, 23, 0xFF);
+
+ /* IPU_PIX_FMT_RGB666 */
+ _ipu_dc_map_clear(ipu, 1);
+ _ipu_dc_map_config(ipu, 1, 0, 5, 0xFC);
+ _ipu_dc_map_config(ipu, 1, 1, 11, 0xFC);
+ _ipu_dc_map_config(ipu, 1, 2, 17, 0xFC);
+
+ /* IPU_PIX_FMT_YUV444 */
+ _ipu_dc_map_clear(ipu, 2);
+ _ipu_dc_map_config(ipu, 2, 0, 15, 0xFF);
+ _ipu_dc_map_config(ipu, 2, 1, 23, 0xFF);
+ _ipu_dc_map_config(ipu, 2, 2, 7, 0xFF);
+
+ /* IPU_PIX_FMT_RGB565 */
+ _ipu_dc_map_clear(ipu, 3);
+ _ipu_dc_map_config(ipu, 3, 0, 4, 0xF8);
+ _ipu_dc_map_config(ipu, 3, 1, 10, 0xFC);
+ _ipu_dc_map_config(ipu, 3, 2, 15, 0xF8);
+
+ /* IPU_PIX_FMT_LVDS666 */
+ _ipu_dc_map_clear(ipu, 4);
+ _ipu_dc_map_config(ipu, 4, 0, 5, 0xFC);
+ _ipu_dc_map_config(ipu, 4, 1, 13, 0xFC);
+ _ipu_dc_map_config(ipu, 4, 2, 21, 0xFC);
+
+ /* IPU_PIX_FMT_VYUY 16bit width */
+ _ipu_dc_map_clear(ipu, 5);
+ _ipu_dc_map_config(ipu, 5, 0, 7, 0xFF);
+ _ipu_dc_map_config(ipu, 5, 1, 0, 0x0);
+ _ipu_dc_map_config(ipu, 5, 2, 15, 0xFF);
+ _ipu_dc_map_clear(ipu, 6);
+ _ipu_dc_map_config(ipu, 6, 0, 0, 0x0);
+ _ipu_dc_map_config(ipu, 6, 1, 7, 0xFF);
+ _ipu_dc_map_config(ipu, 6, 2, 15, 0xFF);
+
+ /* IPU_PIX_FMT_UYUV 16bit width */
+ _ipu_dc_map_clear(ipu, 7);
+ _ipu_dc_map_link(ipu, 7, 6, 0, 6, 1, 6, 2);
+ _ipu_dc_map_clear(ipu, 8);
+ _ipu_dc_map_link(ipu, 8, 5, 0, 5, 1, 5, 2);
+
+ /* IPU_PIX_FMT_YUYV 16bit width */
+ _ipu_dc_map_clear(ipu, 9);
+ _ipu_dc_map_link(ipu, 9, 5, 2, 5, 1, 5, 0);
+ _ipu_dc_map_clear(ipu, 10);
+ _ipu_dc_map_link(ipu, 10, 5, 1, 5, 2, 5, 0);
+
+ /* IPU_PIX_FMT_YVYU 16bit width */
+ _ipu_dc_map_clear(ipu, 11);
+ _ipu_dc_map_link(ipu, 11, 5, 1, 5, 2, 5, 0);
+ _ipu_dc_map_clear(ipu, 12);
+ _ipu_dc_map_link(ipu, 12, 5, 2, 5, 1, 5, 0);
+
+ /* IPU_PIX_FMT_GBR24 */
+ /* IPU_PIX_FMT_VYU444 */
+ _ipu_dc_map_clear(ipu, 13);
+ _ipu_dc_map_link(ipu, 13, 0, 2, 0, 0, 0, 1);
+
+ /* IPU_PIX_FMT_BGR24 */
+ _ipu_dc_map_clear(ipu, 14);
+ _ipu_dc_map_link(ipu, 14, 0, 2, 0, 1, 0, 0);
+}
+
+int _ipu_pixfmt_to_map(uint32_t fmt)
+{
+ switch (fmt) {
+ case IPU_PIX_FMT_GENERIC:
+ case IPU_PIX_FMT_RGB24:
+ return 0;
+ case IPU_PIX_FMT_RGB666:
+ return 1;
+ case IPU_PIX_FMT_YUV444:
+ return 2;
+ case IPU_PIX_FMT_RGB565:
+ return 3;
+ case IPU_PIX_FMT_LVDS666:
+ return 4;
+ case IPU_PIX_FMT_VYUY:
+ return 6;
+ case IPU_PIX_FMT_UYVY:
+ return 8;
+ case IPU_PIX_FMT_YUYV:
+ return 10;
+ case IPU_PIX_FMT_YVYU:
+ return 12;
+ case IPU_PIX_FMT_GBR24:
+ case IPU_PIX_FMT_VYU444:
+ return 13;
+ case IPU_PIX_FMT_BGR24:
+ return 14;
+ }
+
+ return -1;
+}
+
+/*!
+ * This function sets the colorspace for of dp.
+ * modes.
+ *
+ * @param ipu ipu handler
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param param If it's not NULL, update the csc table
+ * with this parameter.
+ *
+ * @return N/A
+ */
+void _ipu_dp_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_t param[][3])
+{
+ int dp;
+ struct dp_csc_param_t dp_csc_param;
+
+ if (channel == MEM_FG_SYNC)
+ dp = DP_SYNC;
+ else if (channel == MEM_BG_SYNC)
+ dp = DP_SYNC;
+ else if (channel == MEM_BG_ASYNC0)
+ dp = DP_ASYNC0;
+ else
+ return;
+
+ dp_csc_param.mode = -1;
+ dp_csc_param.coeff = param;
+ __ipu_dp_csc_setup(ipu, dp, dp_csc_param, true);
+}
+
+void ipu_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_t param[][3])
+{
+ _ipu_dp_set_csc_coefficients(ipu, channel, param);
+}
+EXPORT_SYMBOL(ipu_set_csc_coefficients);
+
+/*!
+ * This function is called to adapt synchronous LCD panel to IPU restriction.
+ *
+ */
+void adapt_panel_to_ipu_restricitions(struct ipu_soc *ipu, uint16_t *v_start_width,
+ uint16_t *v_sync_width,
+ uint16_t *v_end_width)
+{
+ if (*v_end_width < 2) {
+ uint16_t diff = 2 - *v_end_width;
+ if (*v_start_width >= diff) {
+ *v_end_width = 2;
+ *v_start_width = *v_start_width - diff;
+ } else if (*v_sync_width > diff) {
+ *v_end_width = 2;
+ *v_sync_width = *v_sync_width - diff;
+ } else
+ dev_err(ipu->dev, "WARNING: try to adapt timming, but failed\n");
+ dev_err(ipu->dev, "WARNING: adapt panel end blank lines\n");
+ }
+}
+
+/*!
+ * This function is called to initialize a synchronous LCD panel.
+ *
+ * @param ipu ipu handler
+ * @param disp The DI the panel is attached to.
+ *
+ * @param pixel_clk Desired pixel clock frequency in Hz.
+ *
+ * @param pixel_fmt Input parameter for pixel format of buffer.
+ * Pixel format is a FOURCC ASCII code.
+ *
+ * @param width The width of panel in pixels.
+ *
+ * @param height The height of panel in pixels.
+ *
+ * @param hStartWidth The number of pixel clocks between the HSYNC
+ * signal pulse and the start of valid data.
+ *
+ * @param hSyncWidth The width of the HSYNC signal in units of pixel
+ * clocks.
+ *
+ * @param hEndWidth The number of pixel clocks between the end of
+ * valid data and the HSYNC signal for next line.
+ *
+ * @param vStartWidth The number of lines between the VSYNC
+ * signal pulse and the start of valid data.
+ *
+ * @param vSyncWidth The width of the VSYNC signal in units of lines
+ *
+ * @param vEndWidth The number of lines between the end of valid
+ * data and the VSYNC signal for next frame.
+ *
+ * @param sig Bitfield of signal polarities for LCD interface.
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int32_t ipu_init_sync_panel(struct ipu_soc *ipu, int disp, uint32_t pixel_clk,
+ uint16_t width, uint16_t height,
+ uint32_t pixel_fmt,
+ uint16_t h_start_width, uint16_t h_sync_width,
+ uint16_t h_end_width, uint16_t v_start_width,
+ uint16_t v_sync_width, uint16_t v_end_width,
+ uint32_t v_to_h_sync, ipu_di_signal_cfg_t sig)
+{
+ uint32_t field0_offset = 0;
+ uint32_t field1_offset;
+ uint32_t reg;
+ uint32_t di_gen, vsync_cnt;
+ uint32_t div, rounded_pixel_clk;
+ uint32_t h_total, v_total;
+ int map;
+ int ret;
+ struct clk *ldb_di0_clk, *ldb_di1_clk;
+ struct clk *di_parent;
+
+ dev_dbg(ipu->dev, "panel size = %d x %d\n", width, height);
+
+ if ((v_sync_width == 0) || (h_sync_width == 0))
+ return -EINVAL;
+
+ adapt_panel_to_ipu_restricitions(ipu, &v_start_width, &v_sync_width, &v_end_width);
+ h_total = width + h_sync_width + h_start_width + h_end_width;
+ v_total = height + v_sync_width + v_start_width + v_end_width;
+
+ /* Init clocking */
+ dev_dbg(ipu->dev, "pixel clk = %d\n", pixel_clk);
+
+ di_parent = clk_get_parent(ipu->di_clk_sel[disp]);
+ if (!di_parent) {
+ dev_err(ipu->dev, "get di clk parent fail\n");
+ return -EINVAL;
+ }
+ ldb_di0_clk = clk_get(ipu->dev, "ldb_di0");
+ if (IS_ERR(ldb_di0_clk)) {
+ dev_err(ipu->dev, "clk_get di0 failed");
+ return PTR_ERR(ldb_di0_clk);
+ }
+ ldb_di1_clk = clk_get(ipu->dev, "ldb_di1");
+ if (IS_ERR(ldb_di1_clk)) {
+ dev_err(ipu->dev, "clk_get di1 failed");
+ return PTR_ERR(ldb_di1_clk);
+ }
+ if (!strcmp(__clk_get_name(di_parent), __clk_get_name(ldb_di0_clk)) ||
+ !strcmp(__clk_get_name(di_parent), __clk_get_name(ldb_di1_clk))) {
+ /* if di clk parent is tve/ldb, then keep it;*/
+ dev_dbg(ipu->dev, "use special clk parent\n");
+ ret = clk_set_parent(ipu->pixel_clk_sel[disp], ipu->di_clk[disp]);
+ if (ret) {
+ dev_err(ipu->dev, "set pixel clk error:%d\n", ret);
+ return ret;
+ }
+ clk_put(ldb_di0_clk);
+ clk_put(ldb_di1_clk);
+ } else {
+ /* try ipu clk first*/
+ dev_dbg(ipu->dev, "try ipu internal clk\n");
+ ret = clk_set_parent(ipu->pixel_clk_sel[disp], ipu->ipu_clk);
+ if (ret) {
+ dev_err(ipu->dev, "set pixel clk error:%d\n", ret);
+ return ret;
+ }
+ rounded_pixel_clk = clk_round_rate(ipu->pixel_clk[disp], pixel_clk);
+ dev_dbg(ipu->dev, "rounded pix clk:%d\n", rounded_pixel_clk);
+ /*
+ * we will only use 1/2 fraction for ipu clk,
+ * so if the clk rate is not fit, try ext clk.
+ */
+ if (!sig.int_clk &&
+ ((rounded_pixel_clk >= pixel_clk + pixel_clk/200) ||
+ (rounded_pixel_clk <= pixel_clk - pixel_clk/200))) {
+ dev_dbg(ipu->dev, "try ipu ext di clk\n");
+
+ rounded_pixel_clk =
+ clk_round_rate(ipu->di_clk[disp], pixel_clk);
+ ret = clk_set_rate(ipu->di_clk[disp],
+ rounded_pixel_clk);
+ if (ret) {
+ dev_err(ipu->dev,
+ "set di clk rate error:%d\n", ret);
+ return ret;
+ }
+ dev_dbg(ipu->dev, "di clk:%d\n", rounded_pixel_clk);
+ ret = clk_set_parent(ipu->pixel_clk_sel[disp],
+ ipu->di_clk[disp]);
+ if (ret) {
+ dev_err(ipu->dev,
+ "set pixel clk parent error:%d\n", ret);
+ return ret;
+ }
+ }
+ }
+ rounded_pixel_clk = clk_round_rate(ipu->pixel_clk[disp], pixel_clk);
+ dev_dbg(ipu->dev, "round pixel clk:%d\n", rounded_pixel_clk);
+ ret = clk_set_rate(ipu->pixel_clk[disp], rounded_pixel_clk);
+ if (ret) {
+ dev_err(ipu->dev, "set pixel clk rate error:%d\n", ret);
+ return ret;
+ }
+ msleep(5);
+ /* Get integer portion of divider */
+ div = clk_get_rate(clk_get_parent(ipu->pixel_clk_sel[disp])) / rounded_pixel_clk;
+ dev_dbg(ipu->dev, "div:%d\n", div);
+ if (!div) {
+ dev_err(ipu->dev, "invalid pixel clk div = 0\n");
+ return -EINVAL;
+ }
+
+
+ mutex_lock(&ipu->mutex_lock);
+
+ _ipu_di_data_wave_config(ipu, disp, SYNC_WAVE, div - 1, div - 1);
+ _ipu_di_data_pin_config(ipu, disp, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
+
+ map = _ipu_pixfmt_to_map(pixel_fmt);
+ if (map < 0) {
+ dev_dbg(ipu->dev, "IPU_DISP: No MAP\n");
+ mutex_unlock(&ipu->mutex_lock);
+ return -EINVAL;
+ }
+
+ /*clear DI*/
+ di_gen = ipu_di_read(ipu, disp, DI_GENERAL);
+ di_gen &= (0x3 << 20);
+ ipu_di_write(ipu, disp, di_gen, DI_GENERAL);
+
+ if (sig.interlaced) {
+ if (ipu->devtype >= IPUv3EX) {
+ /* Setup internal HSYNC waveform */
+ _ipu_di_sync_config(ipu,
+ disp, /* display */
+ 1, /* counter */
+ h_total/2 - 1, /* run count */
+ DI_SYNC_CLK, /* run_resolution */
+ 0, /* offset */
+ DI_SYNC_NONE, /* offset resolution */
+ 0, /* repeat count */
+ DI_SYNC_NONE, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 0 /* COUNT DOWN */
+ );
+
+ /* Field 1 VSYNC waveform */
+ _ipu_di_sync_config(ipu,
+ disp, /* display */
+ 2, /* counter */
+ h_total - 1, /* run count */
+ DI_SYNC_CLK, /* run_resolution */
+ 0, /* offset */
+ DI_SYNC_NONE, /* offset resolution */
+ 0, /* repeat count */
+ DI_SYNC_NONE, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 2*div /* COUNT DOWN */
+ );
+
+ /* Setup internal HSYNC waveform */
+ _ipu_di_sync_config(ipu,
+ disp, /* display */
+ 3, /* counter */
+ v_total*2 - 1, /* run count */
+ DI_SYNC_INT_HSYNC, /* run_resolution */
+ 1, /* offset */
+ DI_SYNC_INT_HSYNC, /* offset resolution */
+ 0, /* repeat count */
+ DI_SYNC_NONE, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 2*div /* COUNT DOWN */
+ );
+
+ /* Active Field ? */
+ _ipu_di_sync_config(ipu,
+ disp, /* display */
+ 4, /* counter */
+ v_total/2 - 1, /* run count */
+ DI_SYNC_HSYNC, /* run_resolution */
+ v_start_width, /* offset */
+ DI_SYNC_HSYNC, /* offset resolution */
+ 2, /* repeat count */
+ DI_SYNC_VSYNC, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 0 /* COUNT DOWN */
+ );
+
+ /* Active Line */
+ _ipu_di_sync_config(ipu,
+ disp, /* display */
+ 5, /* counter */
+ 0, /* run count */
+ DI_SYNC_HSYNC, /* run_resolution */
+ 0, /* offset */
+ DI_SYNC_NONE, /* offset resolution */
+ height/2, /* repeat count */
+ 4, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 0 /* COUNT DOWN */
+ );
+
+ /* Field 0 VSYNC waveform */
+ _ipu_di_sync_config(ipu,
+ disp, /* display */
+ 6, /* counter */
+ v_total - 1, /* run count */
+ DI_SYNC_HSYNC, /* run_resolution */
+ 0, /* offset */
+ DI_SYNC_NONE, /* offset resolution */
+ 0, /* repeat count */
+ DI_SYNC_NONE, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 0 /* COUNT DOWN */
+ );
+
+ /* DC VSYNC waveform */
+ vsync_cnt = 7;
+ _ipu_di_sync_config(ipu,
+ disp, /* display */
+ 7, /* counter */
+ v_total/2 - 1, /* run count */
+ DI_SYNC_HSYNC, /* run_resolution */
+ 9, /* offset */
+ DI_SYNC_HSYNC, /* offset resolution */
+ 2, /* repeat count */
+ DI_SYNC_VSYNC, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 0 /* COUNT DOWN */
+ );
+
+ /* active pixel waveform */
+ _ipu_di_sync_config(ipu,
+ disp, /* display */
+ 8, /* counter */
+ 0, /* run count */
+ DI_SYNC_CLK, /* run_resolution */
+ h_start_width, /* offset */
+ DI_SYNC_CLK, /* offset resolution */
+ width, /* repeat count */
+ 5, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 0 /* COUNT DOWN */
+ );
+
+ /* Second VSYNC */
+ _ipu_di_sync_config(ipu,
+ disp, /* display */
+ 9, /* counter */
+ v_total - 1, /* run count */
+ DI_SYNC_INT_HSYNC, /* run_resolution */
+ v_total/2, /* offset */
+ DI_SYNC_INT_HSYNC, /* offset resolution */
+ 0, /* repeat count */
+ DI_SYNC_HSYNC, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 2*div /* COUNT DOWN */
+ );
+
+ /* set gentime select and tag sel */
+ reg = ipu_di_read(ipu, disp, DI_SW_GEN1(9));
+ reg &= 0x1FFFFFFF;
+ reg |= (3-1)<<29 | 0x00008000;
+ ipu_di_write(ipu, disp, reg, DI_SW_GEN1(9));
+
+ ipu_di_write(ipu, disp, v_total / 2 - 1, DI_SCR_CONF);
+
+ /* set y_sel = 1 */
+ di_gen |= 0x10000000;
+ di_gen |= DI_GEN_POLARITY_5;
+ di_gen |= DI_GEN_POLARITY_8;
+ } else {
+ /* Setup internal HSYNC waveform */
+ _ipu_di_sync_config(ipu, disp, 1, h_total - 1, DI_SYNC_CLK,
+ 0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
+ DI_SYNC_NONE, 0, 0);
+
+ field1_offset = v_sync_width + v_start_width + height / 2 +
+ v_end_width;
+ if (sig.odd_field_first) {
+ field0_offset = field1_offset - 1;
+ field1_offset = 0;
+ }
+ v_total += v_start_width + v_end_width;
+
+ /* Field 1 VSYNC waveform */
+ _ipu_di_sync_config(ipu, disp, 2, v_total - 1, 1,
+ field0_offset,
+ field0_offset ? 1 : DI_SYNC_NONE,
+ 0, DI_SYNC_NONE, 0,
+ DI_SYNC_NONE, DI_SYNC_NONE, 0, 4);
+
+ /* Setup internal HSYNC waveform */
+ _ipu_di_sync_config(ipu, disp, 3, h_total - 1, DI_SYNC_CLK,
+ 0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0,
+ DI_SYNC_NONE, DI_SYNC_NONE, 0, 4);
+
+ /* Active Field ? */
+ _ipu_di_sync_config(ipu, disp, 4,
+ field0_offset ?
+ field0_offset : field1_offset - 2,
+ 1, v_start_width + v_sync_width, 1, 2, 2,
+ 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0);
+
+ /* Active Line */
+ _ipu_di_sync_config(ipu, disp, 5, 0, 1,
+ 0, DI_SYNC_NONE,
+ height / 2, 4, 0, DI_SYNC_NONE,
+ DI_SYNC_NONE, 0, 0);
+
+ /* Field 0 VSYNC waveform */
+ _ipu_di_sync_config(ipu, disp, 6, v_total - 1, 1,
+ 0, DI_SYNC_NONE,
+ 0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
+ DI_SYNC_NONE, 0, 0);
+
+ /* DC VSYNC waveform */
+ vsync_cnt = 7;
+ _ipu_di_sync_config(ipu, disp, 7, 0, 1,
+ field1_offset,
+ field1_offset ? 1 : DI_SYNC_NONE,
+ 1, 2, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0);
+
+ /* active pixel waveform */
+ _ipu_di_sync_config(ipu, disp, 8, 0, DI_SYNC_CLK,
+ h_sync_width + h_start_width, DI_SYNC_CLK,
+ width, 5, 0, DI_SYNC_NONE, DI_SYNC_NONE,
+ 0, 0);
+
+ /* ??? */
+ _ipu_di_sync_config(ipu, disp, 9, v_total - 1, 2,
+ 0, DI_SYNC_NONE,
+ 0, DI_SYNC_NONE, 6, DI_SYNC_NONE,
+ DI_SYNC_NONE, 0, 0);
+
+ reg = ipu_di_read(ipu, disp, DI_SW_GEN1(9));
+ reg |= 0x8000;
+ ipu_di_write(ipu, disp, reg, DI_SW_GEN1(9));
+
+ ipu_di_write(ipu, disp, v_sync_width + v_start_width +
+ v_end_width + height / 2 - 1, DI_SCR_CONF);
+ }
+
+ /* Init template microcode */
+ _ipu_dc_write_tmpl(ipu, 0, WROD(0), 0, map, SYNC_WAVE, 0, 8, 1);
+
+ if (sig.Hsync_pol)
+ di_gen |= DI_GEN_POLARITY_3;
+ if (sig.Vsync_pol)
+ di_gen |= DI_GEN_POLARITY_2;
+ } else {
+ /* Setup internal HSYNC waveform */
+ _ipu_di_sync_config(ipu, disp, 1, h_total - 1, DI_SYNC_CLK,
+ 0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
+ DI_SYNC_NONE, 0, 0);
+
+ /* Setup external (delayed) HSYNC waveform */
+ _ipu_di_sync_config(ipu, disp, DI_SYNC_HSYNC, h_total - 1,
+ DI_SYNC_CLK, div * v_to_h_sync, DI_SYNC_CLK,
+ 0, DI_SYNC_NONE, 1, DI_SYNC_NONE,
+ DI_SYNC_CLK, 0, h_sync_width * 2);
+ /* Setup VSYNC waveform */
+ vsync_cnt = DI_SYNC_VSYNC;
+ _ipu_di_sync_config(ipu, disp, DI_SYNC_VSYNC, v_total - 1,
+ DI_SYNC_INT_HSYNC, 0, DI_SYNC_NONE, 0,
+ DI_SYNC_NONE, 1, DI_SYNC_NONE,
+ DI_SYNC_INT_HSYNC, 0, v_sync_width * 2);
+ ipu_di_write(ipu, disp, v_total - 1, DI_SCR_CONF);
+
+ /* Setup active data waveform to sync with DC */
+ _ipu_di_sync_config(ipu, disp, 4, 0, DI_SYNC_HSYNC,
+ v_sync_width + v_start_width, DI_SYNC_HSYNC, height,
+ DI_SYNC_VSYNC, 0, DI_SYNC_NONE,
+ DI_SYNC_NONE, 0, 0);
+ _ipu_di_sync_config(ipu, disp, 5, 0, DI_SYNC_CLK,
+ h_sync_width + h_start_width, DI_SYNC_CLK,
+ width, 4, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0,
+ 0);
+
+ /* set VGA delayed hsync/vsync no matter VGA enabled */
+ if (disp) {
+ /* couter 7 for VGA delay HSYNC */
+ _ipu_di_sync_config(ipu, disp, 7,
+ h_total - 1, DI_SYNC_CLK,
+ 18, DI_SYNC_CLK,
+ 0, DI_SYNC_NONE,
+ 1, DI_SYNC_NONE, DI_SYNC_CLK,
+ 0, h_sync_width * 2);
+
+ /* couter 8 for VGA delay VSYNC */
+ _ipu_di_sync_config(ipu, disp, 8,
+ v_total - 1, DI_SYNC_INT_HSYNC,
+ 1, DI_SYNC_INT_HSYNC,
+ 0, DI_SYNC_NONE,
+ 1, DI_SYNC_NONE, DI_SYNC_INT_HSYNC,
+ 0, v_sync_width * 2);
+ }
+
+ /* reset all unused counters */
+ ipu_di_write(ipu, disp, 0, DI_SW_GEN0(6));
+ ipu_di_write(ipu, disp, 0, DI_SW_GEN1(6));
+ if (!disp) {
+ ipu_di_write(ipu, disp, 0, DI_SW_GEN0(7));
+ ipu_di_write(ipu, disp, 0, DI_SW_GEN1(7));
+ ipu_di_write(ipu, disp, 0, DI_STP_REP(7));
+ ipu_di_write(ipu, disp, 0, DI_SW_GEN0(8));
+ ipu_di_write(ipu, disp, 0, DI_SW_GEN1(8));
+ ipu_di_write(ipu, disp, 0, DI_STP_REP(8));
+ }
+ ipu_di_write(ipu, disp, 0, DI_SW_GEN0(9));
+ ipu_di_write(ipu, disp, 0, DI_SW_GEN1(9));
+ ipu_di_write(ipu, disp, 0, DI_STP_REP(9));
+
+ reg = ipu_di_read(ipu, disp, DI_STP_REP(6));
+ reg &= 0x0000FFFF;
+ ipu_di_write(ipu, disp, reg, DI_STP_REP(6));
+
+ /* Init template microcode */
+ if (disp) {
+ if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+ (pixel_fmt == IPU_PIX_FMT_UYVY) ||
+ (pixel_fmt == IPU_PIX_FMT_YVYU) ||
+ (pixel_fmt == IPU_PIX_FMT_VYUY)) {
+ _ipu_dc_write_tmpl(ipu, 8, WROD(0), 0, (map - 1), SYNC_WAVE, 0, 5, 1);
+ _ipu_dc_write_tmpl(ipu, 9, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
+ /* configure user events according to DISP NUM */
+ ipu_dc_write(ipu, (width - 1), DC_UGDE_3(disp));
+ }
+ _ipu_dc_write_tmpl(ipu, 2, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1);
+ _ipu_dc_write_tmpl(ipu, 3, WROD(0), 0, map, SYNC_WAVE, 4, 5, 0);
+ _ipu_dc_write_tmpl(ipu, 4, WRG, 0, map, NULL_WAVE, 0, 0, 1);
+ _ipu_dc_write_tmpl(ipu, 1, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
+
+ } else {
+ if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+ (pixel_fmt == IPU_PIX_FMT_UYVY) ||
+ (pixel_fmt == IPU_PIX_FMT_YVYU) ||
+ (pixel_fmt == IPU_PIX_FMT_VYUY)) {
+ _ipu_dc_write_tmpl(ipu, 10, WROD(0), 0, (map - 1), SYNC_WAVE, 0, 5, 1);
+ _ipu_dc_write_tmpl(ipu, 11, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
+ /* configure user events according to DISP NUM */
+ ipu_dc_write(ipu, width - 1, DC_UGDE_3(disp));
+ }
+ _ipu_dc_write_tmpl(ipu, 5, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1);
+ _ipu_dc_write_tmpl(ipu, 6, WROD(0), 0, map, SYNC_WAVE, 4, 5, 0);
+ _ipu_dc_write_tmpl(ipu, 7, WRG, 0, map, NULL_WAVE, 0, 0, 1);
+ _ipu_dc_write_tmpl(ipu, 12, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
+ }
+
+ if (sig.Hsync_pol) {
+ di_gen |= DI_GEN_POLARITY_2;
+ if (disp)
+ di_gen |= DI_GEN_POLARITY_7;
+ }
+ if (sig.Vsync_pol) {
+ di_gen |= DI_GEN_POLARITY_3;
+ if (disp)
+ di_gen |= DI_GEN_POLARITY_8;
+ }
+ }
+ /* changinc DISP_CLK polarity: it can be wrong for some applications */
+ if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+ (pixel_fmt == IPU_PIX_FMT_UYVY) ||
+ (pixel_fmt == IPU_PIX_FMT_YVYU) ||
+ (pixel_fmt == IPU_PIX_FMT_VYUY))
+ di_gen |= 0x00020000;
+
+ if (!sig.clk_pol)
+ di_gen |= DI_GEN_POLARITY_DISP_CLK;
+
+ ipu_di_write(ipu, disp, di_gen, DI_GENERAL);
+
+ ipu_di_write(ipu, disp, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) |
+ 0x00000002, DI_SYNC_AS_GEN);
+ reg = ipu_di_read(ipu, disp, DI_POL);
+ reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
+ if (sig.enable_pol)
+ reg |= DI_POL_DRDY_POLARITY_15;
+ if (sig.data_pol)
+ reg |= DI_POL_DRDY_DATA_POLARITY;
+ ipu_di_write(ipu, disp, reg, DI_POL);
+
+ ipu_dc_write(ipu, width, DC_DISP_CONF2(DC_DISP_ID_SYNC(disp)));
+
+ mutex_unlock(&ipu->mutex_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_init_sync_panel);
+
+void ipu_uninit_sync_panel(struct ipu_soc *ipu, int disp)
+{
+ uint32_t reg;
+ uint32_t di_gen;
+
+ if (disp != 0 && disp != 1)
+ return;
+
+ mutex_lock(&ipu->mutex_lock);
+
+ di_gen = ipu_di_read(ipu, disp, DI_GENERAL);
+ di_gen |= 0x3ff | DI_GEN_POLARITY_DISP_CLK;
+ ipu_di_write(ipu, disp, di_gen, DI_GENERAL);
+
+ reg = ipu_di_read(ipu, disp, DI_POL);
+ reg |= 0x3ffffff;
+ ipu_di_write(ipu, disp, reg, DI_POL);
+
+ mutex_unlock(&ipu->mutex_lock);
+}
+EXPORT_SYMBOL(ipu_uninit_sync_panel);
+
+int ipu_init_async_panel(struct ipu_soc *ipu, int disp, int type, uint32_t cycle_time,
+ uint32_t pixel_fmt, ipu_adc_sig_cfg_t sig)
+{
+ int map;
+ u32 ser_conf = 0;
+ u32 div;
+ u32 di_clk = clk_get_rate(ipu->ipu_clk);
+
+ /* round up cycle_time, then calcalate the divider using scaled math */
+ cycle_time += (1000000000UL / di_clk) - 1;
+ div = (cycle_time * (di_clk / 256UL)) / (1000000000UL / 256UL);
+
+ map = _ipu_pixfmt_to_map(pixel_fmt);
+ if (map < 0)
+ return -EINVAL;
+
+ mutex_lock(&ipu->mutex_lock);
+
+ if (type == IPU_PANEL_SERIAL) {
+ ipu_di_write(ipu, disp, (div << 24) | ((sig.ifc_width - 1) << 4),
+ DI_DW_GEN(ASYNC_SER_WAVE));
+
+ _ipu_di_data_pin_config(ipu, disp, ASYNC_SER_WAVE, DI_PIN_CS,
+ 0, 0, (div * 2) + 1);
+ _ipu_di_data_pin_config(ipu, disp, ASYNC_SER_WAVE, DI_PIN_SER_CLK,
+ 1, div, div * 2);
+ _ipu_di_data_pin_config(ipu, disp, ASYNC_SER_WAVE, DI_PIN_SER_RS,
+ 2, 0, 0);
+
+ _ipu_dc_write_tmpl(ipu, 0x64, WROD(0), 0, map, ASYNC_SER_WAVE, 0, 0, 1);
+
+ /* Configure DC for serial panel */
+ ipu_dc_write(ipu, 0x14, DC_DISP_CONF1(DC_DISP_ID_SERIAL));
+
+ if (sig.clk_pol)
+ ser_conf |= DI_SER_CONF_SERIAL_CLK_POL;
+ if (sig.data_pol)
+ ser_conf |= DI_SER_CONF_SERIAL_DATA_POL;
+ if (sig.rs_pol)
+ ser_conf |= DI_SER_CONF_SERIAL_RS_POL;
+ if (sig.cs_pol)
+ ser_conf |= DI_SER_CONF_SERIAL_CS_POL;
+ ipu_di_write(ipu, disp, ser_conf, DI_SER_CONF);
+ }
+
+ mutex_unlock(&ipu->mutex_lock);
+ return 0;
+}
+EXPORT_SYMBOL(ipu_init_async_panel);
+
+/*!
+ * This function sets the foreground and background plane global alpha blending
+ * modes. This function also sets the DP graphic plane according to the
+ * parameter of IPUv3 DP channel.
+ *
+ * @param ipu ipu handler
+ * @param channel IPUv3 DP channel
+ *
+ * @param enable Boolean to enable or disable global alpha
+ * blending. If disabled, local blending is used.
+ *
+ * @param alpha Global alpha value.
+ *
+ * @return Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_disp_set_global_alpha(struct ipu_soc *ipu, ipu_channel_t channel,
+ bool enable, uint8_t alpha)
+{
+ uint32_t reg;
+ uint32_t flow;
+ bool bg_chan;
+
+ if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC)
+ flow = DP_SYNC;
+ else if (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0)
+ flow = DP_ASYNC0;
+ else if (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1)
+ flow = DP_ASYNC1;
+ else
+ return -EINVAL;
+
+ if (channel == MEM_BG_SYNC || channel == MEM_BG_ASYNC0 ||
+ channel == MEM_BG_ASYNC1)
+ bg_chan = true;
+ else
+ bg_chan = false;
+
+ _ipu_get(ipu);
+
+ mutex_lock(&ipu->mutex_lock);
+
+ if (bg_chan) {
+ reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+ ipu_dp_write(ipu, reg & ~DP_COM_CONF_GWSEL, DP_COM_CONF(flow));
+ } else {
+ reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+ ipu_dp_write(ipu, reg | DP_COM_CONF_GWSEL, DP_COM_CONF(flow));
+ }
+
+ if (enable) {
+ reg = ipu_dp_read(ipu, DP_GRAPH_WIND_CTRL(flow)) & 0x00FFFFFFL;
+ ipu_dp_write(ipu, reg | ((uint32_t) alpha << 24),
+ DP_GRAPH_WIND_CTRL(flow));
+
+ reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+ ipu_dp_write(ipu, reg | DP_COM_CONF_GWAM, DP_COM_CONF(flow));
+ } else {
+ reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+ ipu_dp_write(ipu, reg & ~DP_COM_CONF_GWAM, DP_COM_CONF(flow));
+ }
+
+ reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+ ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+ mutex_unlock(&ipu->mutex_lock);
+
+ _ipu_put(ipu);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_disp_set_global_alpha);
+
+/*!
+ * This function sets the transparent color key for SDC graphic plane.
+ *
+ * @param ipu ipu handler
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param enable Boolean to enable or disable color key
+ *
+ * @param colorKey 24-bit RGB color for transparent color key.
+ *
+ * @return Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_disp_set_color_key(struct ipu_soc *ipu, ipu_channel_t channel,
+ bool enable, uint32_t color_key)
+{
+ uint32_t reg, flow;
+ int y, u, v;
+ int red, green, blue;
+
+ if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC)
+ flow = DP_SYNC;
+ else if (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0)
+ flow = DP_ASYNC0;
+ else if (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1)
+ flow = DP_ASYNC1;
+ else
+ return -EINVAL;
+
+ _ipu_get(ipu);
+
+ mutex_lock(&ipu->mutex_lock);
+
+ ipu->color_key_4rgb = true;
+ /* Transform color key from rgb to yuv if CSC is enabled */
+ if (((ipu->fg_csc_type == RGB2YUV) && (ipu->bg_csc_type == YUV2YUV)) ||
+ ((ipu->fg_csc_type == YUV2YUV) && (ipu->bg_csc_type == RGB2YUV)) ||
+ ((ipu->fg_csc_type == YUV2YUV) && (ipu->bg_csc_type == YUV2YUV)) ||
+ ((ipu->fg_csc_type == YUV2RGB) && (ipu->bg_csc_type == YUV2RGB))) {
+
+ dev_dbg(ipu->dev, "color key 0x%x need change to yuv fmt\n", color_key);
+
+ red = (color_key >> 16) & 0xFF;
+ green = (color_key >> 8) & 0xFF;
+ blue = color_key & 0xFF;
+
+ y = _rgb_to_yuv(0, red, green, blue);
+ u = _rgb_to_yuv(1, red, green, blue);
+ v = _rgb_to_yuv(2, red, green, blue);
+ color_key = (y << 16) | (u << 8) | v;
+
+ ipu->color_key_4rgb = false;
+
+ dev_dbg(ipu->dev, "color key change to yuv fmt 0x%x\n", color_key);
+ }
+
+ if (enable) {
+ reg = ipu_dp_read(ipu, DP_GRAPH_WIND_CTRL(flow)) & 0xFF000000L;
+ ipu_dp_write(ipu, reg | color_key, DP_GRAPH_WIND_CTRL(flow));
+
+ reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+ ipu_dp_write(ipu, reg | DP_COM_CONF_GWCKE, DP_COM_CONF(flow));
+ } else {
+ reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+ ipu_dp_write(ipu, reg & ~DP_COM_CONF_GWCKE, DP_COM_CONF(flow));
+ }
+
+ reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+ ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+ mutex_unlock(&ipu->mutex_lock);
+
+ _ipu_put(ipu);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_disp_set_color_key);
+
+/*!
+ * This function sets the gamma correction for DP output.
+ *
+ * @param ipu ipu handler
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param enable Boolean to enable or disable gamma correction.
+ *
+ * @param constk Gamma piecewise linear approximation constk coeff.
+ *
+ * @param slopek Gamma piecewise linear approximation slopek coeff.
+ *
+ * @return Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_disp_set_gamma_correction(struct ipu_soc *ipu, ipu_channel_t channel, bool enable, int constk[], int slopek[])
+{
+ uint32_t reg, flow, i;
+
+ if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC)
+ flow = DP_SYNC;
+ else if (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0)
+ flow = DP_ASYNC0;
+ else if (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1)
+ flow = DP_ASYNC1;
+ else
+ return -EINVAL;
+
+ _ipu_get(ipu);
+
+ mutex_lock(&ipu->mutex_lock);
+
+ for (i = 0; i < 8; i++)
+ ipu_dp_write(ipu, (constk[2*i] & 0x1ff) | ((constk[2*i+1] & 0x1ff) << 16), DP_GAMMA_C(flow, i));
+ for (i = 0; i < 4; i++)
+ ipu_dp_write(ipu, (slopek[4*i] & 0xff) | ((slopek[4*i+1] & 0xff) << 8) |
+ ((slopek[4*i+2] & 0xff) << 16) | ((slopek[4*i+3] & 0xff) << 24), DP_GAMMA_S(flow, i));
+
+ reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+ if (enable) {
+ if ((ipu->bg_csc_type == RGB2YUV) || (ipu->bg_csc_type == YUV2YUV))
+ reg |= DP_COM_CONF_GAMMA_YUV_EN;
+ else
+ reg &= ~DP_COM_CONF_GAMMA_YUV_EN;
+ ipu_dp_write(ipu, reg | DP_COM_CONF_GAMMA_EN, DP_COM_CONF(flow));
+ } else
+ ipu_dp_write(ipu, reg & ~DP_COM_CONF_GAMMA_EN, DP_COM_CONF(flow));
+
+ reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+ ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+ mutex_unlock(&ipu->mutex_lock);
+
+ _ipu_put(ipu);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_disp_set_gamma_correction);
+
+/*!
+ * This function sets the window position of the foreground or background plane.
+ * modes.
+ *
+ * @param ipu ipu handler
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param x_pos The X coordinate position to place window at.
+ * The position is relative to the top left corner.
+ *
+ * @param y_pos The Y coordinate position to place window at.
+ * The position is relative to the top left corner.
+ *
+ * @return Returns 0 on success or negative error code on fail
+ */
+int32_t _ipu_disp_set_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+ int16_t x_pos, int16_t y_pos)
+{
+ u32 reg;
+ uint32_t flow = 0;
+ uint32_t dp_srm_shift;
+
+ if ((channel == MEM_FG_SYNC) || (channel == MEM_BG_SYNC)) {
+ flow = DP_SYNC;
+ dp_srm_shift = 3;
+ } else if (channel == MEM_FG_ASYNC0) {
+ flow = DP_ASYNC0;
+ dp_srm_shift = 5;
+ } else if (channel == MEM_FG_ASYNC1) {
+ flow = DP_ASYNC1;
+ dp_srm_shift = 7;
+ } else
+ return -EINVAL;
+
+ ipu_dp_write(ipu, (x_pos << 16) | y_pos, DP_FG_POS(flow));
+
+ if (ipu_is_channel_busy(ipu, channel)) {
+ /* controled by FSU if channel enabled */
+ reg = ipu_cm_read(ipu, IPU_SRM_PRI2) & (~(0x3 << dp_srm_shift));
+ reg |= (0x1 << dp_srm_shift);
+ ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+ } else {
+ /* disable auto swap, controled by MCU if channel disabled */
+ reg = ipu_cm_read(ipu, IPU_SRM_PRI2) & (~(0x3 << dp_srm_shift));
+ ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+ }
+
+ return 0;
+}
+
+int32_t ipu_disp_set_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+ int16_t x_pos, int16_t y_pos)
+{
+ int ret;
+
+ _ipu_get(ipu);
+ mutex_lock(&ipu->mutex_lock);
+ ret = _ipu_disp_set_window_pos(ipu, channel, x_pos, y_pos);
+ mutex_unlock(&ipu->mutex_lock);
+ _ipu_put(ipu);
+ return ret;
+}
+EXPORT_SYMBOL(ipu_disp_set_window_pos);
+
+int32_t _ipu_disp_get_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+ int16_t *x_pos, int16_t *y_pos)
+{
+ u32 reg;
+ uint32_t flow = 0;
+
+ if (channel == MEM_FG_SYNC)
+ flow = DP_SYNC;
+ else if (channel == MEM_FG_ASYNC0)
+ flow = DP_ASYNC0;
+ else if (channel == MEM_FG_ASYNC1)
+ flow = DP_ASYNC1;
+ else
+ return -EINVAL;
+
+ reg = ipu_dp_read(ipu, DP_FG_POS(flow));
+
+ *x_pos = (reg >> 16) & 0x7FF;
+ *y_pos = reg & 0x7FF;
+
+ return 0;
+}
+int32_t ipu_disp_get_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+ int16_t *x_pos, int16_t *y_pos)
+{
+ int ret;
+
+ _ipu_get(ipu);
+ mutex_lock(&ipu->mutex_lock);
+ ret = _ipu_disp_get_window_pos(ipu, channel, x_pos, y_pos);
+ mutex_unlock(&ipu->mutex_lock);
+ _ipu_put(ipu);
+ return ret;
+}
+EXPORT_SYMBOL(ipu_disp_get_window_pos);
+
+void ipu_reset_disp_panel(struct ipu_soc *ipu)
+{
+ uint32_t tmp;
+
+ tmp = ipu_di_read(ipu, 1, DI_GENERAL);
+ ipu_di_write(ipu, 1, tmp | 0x08, DI_GENERAL);
+ msleep(10); /* tRES >= 100us */
+ tmp = ipu_di_read(ipu, 1, DI_GENERAL);
+ ipu_di_write(ipu, 1, tmp & ~0x08, DI_GENERAL);
+ msleep(60);
+
+ return;
+}
+EXPORT_SYMBOL(ipu_reset_disp_panel);
+
+void ipu_disp_init(struct ipu_soc *ipu)
+{
+ ipu->fg_csc_type = ipu->bg_csc_type = CSC_NONE;
+ ipu->color_key_4rgb = true;
+ _ipu_init_dc_mappings(ipu);
+ _ipu_dmfc_init(ipu, DMFC_NORMAL, 1);
+}
diff --git a/drivers/mxc/ipu3/ipu_ic.c b/drivers/mxc/ipu3/ipu_ic.c
new file mode 100644
index 000000000000..29519bd00d12
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_ic.c
@@ -0,0 +1,924 @@
+/*
+ * Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ * @file ipu_ic.c
+ *
+ * @brief IPU IC functions
+ *
+ * @ingroup IPU
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include "ipu_param_mem.h"
+#include "ipu_regs.h"
+
+enum {
+ IC_TASK_VIEWFINDER,
+ IC_TASK_ENCODER,
+ IC_TASK_POST_PROCESSOR
+};
+
+static void _init_csc(struct ipu_soc *ipu, uint8_t ic_task, ipu_color_space_t in_format,
+ ipu_color_space_t out_format, int csc_index);
+
+static int _calc_resize_coeffs(struct ipu_soc *ipu,
+ uint32_t inSize, uint32_t outSize,
+ uint32_t *resizeCoeff,
+ uint32_t *downsizeCoeff);
+
+void _ipu_vdi_set_top_field_man(struct ipu_soc *ipu, bool top_field_0)
+{
+ uint32_t reg;
+
+ reg = ipu_vdi_read(ipu, VDI_C);
+ if (top_field_0)
+ reg &= ~VDI_C_TOP_FIELD_MAN_1;
+ else
+ reg |= VDI_C_TOP_FIELD_MAN_1;
+ ipu_vdi_write(ipu, reg, VDI_C);
+}
+
+void _ipu_vdi_set_motion(struct ipu_soc *ipu, ipu_motion_sel motion_sel)
+{
+ uint32_t reg;
+
+ reg = ipu_vdi_read(ipu, VDI_C);
+ reg &= ~(VDI_C_MOT_SEL_FULL | VDI_C_MOT_SEL_MED | VDI_C_MOT_SEL_LOW);
+ if (motion_sel == HIGH_MOTION)
+ reg |= VDI_C_MOT_SEL_FULL;
+ else if (motion_sel == MED_MOTION)
+ reg |= VDI_C_MOT_SEL_MED;
+ else
+ reg |= VDI_C_MOT_SEL_LOW;
+
+ ipu_vdi_write(ipu, reg, VDI_C);
+ dev_dbg(ipu->dev, "VDI_C = \t0x%08X\n", reg);
+}
+
+void ic_dump_register(struct ipu_soc *ipu)
+{
+ printk(KERN_DEBUG "IC_CONF = \t0x%08X\n", ipu_ic_read(ipu, IC_CONF));
+ printk(KERN_DEBUG "IC_PRP_ENC_RSC = \t0x%08X\n",
+ ipu_ic_read(ipu, IC_PRP_ENC_RSC));
+ printk(KERN_DEBUG "IC_PRP_VF_RSC = \t0x%08X\n",
+ ipu_ic_read(ipu, IC_PRP_VF_RSC));
+ printk(KERN_DEBUG "IC_PP_RSC = \t0x%08X\n", ipu_ic_read(ipu, IC_PP_RSC));
+ printk(KERN_DEBUG "IC_IDMAC_1 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_1));
+ printk(KERN_DEBUG "IC_IDMAC_2 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_2));
+ printk(KERN_DEBUG "IC_IDMAC_3 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_3));
+}
+
+void _ipu_ic_enable_task(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+ uint32_t ic_conf;
+
+ ic_conf = ipu_ic_read(ipu, IC_CONF);
+ switch (channel) {
+ case CSI_PRP_VF_MEM:
+ case MEM_PRP_VF_MEM:
+ ic_conf |= IC_CONF_PRPVF_EN;
+ break;
+ case MEM_VDI_PRP_VF_MEM:
+ ic_conf |= IC_CONF_PRPVF_EN;
+ break;
+ case MEM_VDI_MEM:
+ ic_conf |= IC_CONF_PRPVF_EN | IC_CONF_RWS_EN ;
+ break;
+ case MEM_ROT_VF_MEM:
+ ic_conf |= IC_CONF_PRPVF_ROT_EN;
+ break;
+ case CSI_PRP_ENC_MEM:
+ case MEM_PRP_ENC_MEM:
+ ic_conf |= IC_CONF_PRPENC_EN;
+ break;
+ case MEM_ROT_ENC_MEM:
+ ic_conf |= IC_CONF_PRPENC_ROT_EN;
+ break;
+ case MEM_PP_MEM:
+ ic_conf |= IC_CONF_PP_EN;
+ break;
+ case MEM_ROT_PP_MEM:
+ ic_conf |= IC_CONF_PP_ROT_EN;
+ break;
+ default:
+ break;
+ }
+ ipu_ic_write(ipu, ic_conf, IC_CONF);
+}
+
+void _ipu_ic_disable_task(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+ uint32_t ic_conf;
+
+ ic_conf = ipu_ic_read(ipu, IC_CONF);
+ switch (channel) {
+ case CSI_PRP_VF_MEM:
+ case MEM_PRP_VF_MEM:
+ ic_conf &= ~IC_CONF_PRPVF_EN;
+ break;
+ case MEM_VDI_PRP_VF_MEM:
+ ic_conf &= ~IC_CONF_PRPVF_EN;
+ break;
+ case MEM_VDI_MEM:
+ ic_conf &= ~(IC_CONF_PRPVF_EN | IC_CONF_RWS_EN);
+ break;
+ case MEM_ROT_VF_MEM:
+ ic_conf &= ~IC_CONF_PRPVF_ROT_EN;
+ break;
+ case CSI_PRP_ENC_MEM:
+ case MEM_PRP_ENC_MEM:
+ ic_conf &= ~IC_CONF_PRPENC_EN;
+ break;
+ case MEM_ROT_ENC_MEM:
+ ic_conf &= ~IC_CONF_PRPENC_ROT_EN;
+ break;
+ case MEM_PP_MEM:
+ ic_conf &= ~IC_CONF_PP_EN;
+ break;
+ case MEM_ROT_PP_MEM:
+ ic_conf &= ~IC_CONF_PP_ROT_EN;
+ break;
+ default:
+ break;
+ }
+ ipu_ic_write(ipu, ic_conf, IC_CONF);
+}
+
+void _ipu_vdi_init(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params)
+{
+ uint32_t reg;
+ uint32_t pixel_fmt;
+ uint32_t pix_per_burst;
+
+ reg = ((params->mem_prp_vf_mem.in_height-1) << 16) |
+ (params->mem_prp_vf_mem.in_width-1);
+ ipu_vdi_write(ipu, reg, VDI_FSIZE);
+
+ /* Full motion, only vertical filter is used
+ Burst size is 4 accesses */
+ if (params->mem_prp_vf_mem.in_pixel_fmt ==
+ IPU_PIX_FMT_UYVY ||
+ params->mem_prp_vf_mem.in_pixel_fmt ==
+ IPU_PIX_FMT_YUYV) {
+ pixel_fmt = VDI_C_CH_422;
+ pix_per_burst = 32;
+ } else {
+ pixel_fmt = VDI_C_CH_420;
+ pix_per_burst = 64;
+ }
+
+ reg = ipu_vdi_read(ipu, VDI_C);
+ reg |= pixel_fmt;
+ switch (channel) {
+ case MEM_VDI_PRP_VF_MEM:
+ reg |= VDI_C_BURST_SIZE2_4;
+ break;
+ case MEM_VDI_PRP_VF_MEM_P:
+ reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_SET_1 | VDI_C_VWM1_CLR_2;
+ break;
+ case MEM_VDI_PRP_VF_MEM_N:
+ reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_SET_1 | VDI_C_VWM3_CLR_2;
+ break;
+
+ case MEM_VDI_MEM:
+ reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
+ << VDI_C_BURST_SIZE2_OFFSET;
+ break;
+ case MEM_VDI_MEM_P:
+ reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
+ << VDI_C_BURST_SIZE1_OFFSET;
+ reg |= VDI_C_VWM1_SET_2 | VDI_C_VWM1_CLR_2;
+ break;
+ case MEM_VDI_MEM_N:
+ reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
+ << VDI_C_BURST_SIZE3_OFFSET;
+ reg |= VDI_C_VWM3_SET_2 | VDI_C_VWM3_CLR_2;
+ break;
+ default:
+ break;
+ }
+ ipu_vdi_write(ipu, reg, VDI_C);
+
+ if (params->mem_prp_vf_mem.field_fmt == IPU_DEINTERLACE_FIELD_TOP)
+ _ipu_vdi_set_top_field_man(ipu, true);
+ else if (params->mem_prp_vf_mem.field_fmt == IPU_DEINTERLACE_FIELD_BOTTOM)
+ _ipu_vdi_set_top_field_man(ipu, false);
+
+ _ipu_vdi_set_motion(ipu, params->mem_prp_vf_mem.motion_sel);
+
+ reg = ipu_ic_read(ipu, IC_CONF);
+ reg &= ~IC_CONF_RWS_EN;
+ ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+void _ipu_vdi_uninit(struct ipu_soc *ipu)
+{
+ ipu_vdi_write(ipu, 0, VDI_FSIZE);
+ ipu_vdi_write(ipu, 0, VDI_C);
+}
+
+int _ipu_ic_init_prpvf(struct ipu_soc *ipu, ipu_channel_params_t *params,
+ bool src_is_csi)
+{
+ uint32_t reg, ic_conf;
+ uint32_t downsizeCoeff, resizeCoeff;
+ ipu_color_space_t in_fmt, out_fmt;
+ int ret = 0;
+
+ /* Setup vertical resizing */
+ if (!params->mem_prp_vf_mem.outv_resize_ratio) {
+ ret = _calc_resize_coeffs(ipu, params->mem_prp_vf_mem.in_height,
+ params->mem_prp_vf_mem.out_height,
+ &resizeCoeff, &downsizeCoeff);
+ if (ret < 0) {
+ dev_err(ipu->dev, "failed to calculate prpvf height "
+ "scaling coefficients\n");
+ return ret;
+ }
+
+ reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
+ } else
+ reg = (params->mem_prp_vf_mem.outv_resize_ratio) << 16;
+
+ /* Setup horizontal resizing */
+ if (!params->mem_prp_vf_mem.outh_resize_ratio) {
+ ret = _calc_resize_coeffs(ipu, params->mem_prp_vf_mem.in_width,
+ params->mem_prp_vf_mem.out_width,
+ &resizeCoeff, &downsizeCoeff);
+ if (ret < 0) {
+ dev_err(ipu->dev, "failed to calculate prpvf width "
+ "scaling coefficients\n");
+ return ret;
+ }
+
+ reg |= (downsizeCoeff << 14) | resizeCoeff;
+ } else
+ reg |= params->mem_prp_vf_mem.outh_resize_ratio;
+
+ ipu_ic_write(ipu, reg, IC_PRP_VF_RSC);
+
+ ic_conf = ipu_ic_read(ipu, IC_CONF);
+
+ /* Setup color space conversion */
+ in_fmt = format_to_colorspace(params->mem_prp_vf_mem.in_pixel_fmt);
+ out_fmt = format_to_colorspace(params->mem_prp_vf_mem.out_pixel_fmt);
+ if (in_fmt == RGB) {
+ if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
+ /* Enable RGB->YCBCR CSC1 */
+ _init_csc(ipu, IC_TASK_VIEWFINDER, RGB, out_fmt, 1);
+ ic_conf |= IC_CONF_PRPVF_CSC1;
+ }
+ }
+ if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
+ if (out_fmt == RGB) {
+ /* Enable YCBCR->RGB CSC1 */
+ _init_csc(ipu, IC_TASK_VIEWFINDER, YCbCr, RGB, 1);
+ ic_conf |= IC_CONF_PRPVF_CSC1;
+ } else {
+ /* TODO: Support YUV<->YCbCr conversion? */
+ }
+ }
+
+ if (params->mem_prp_vf_mem.graphics_combine_en) {
+ ic_conf |= IC_CONF_PRPVF_CMB;
+
+ if (!(ic_conf & IC_CONF_PRPVF_CSC1)) {
+ /* need transparent CSC1 conversion */
+ _init_csc(ipu, IC_TASK_VIEWFINDER, RGB, RGB, 1);
+ ic_conf |= IC_CONF_PRPVF_CSC1; /* Enable RGB->RGB CSC */
+ }
+ in_fmt = format_to_colorspace(params->mem_prp_vf_mem.in_g_pixel_fmt);
+ out_fmt = format_to_colorspace(params->mem_prp_vf_mem.out_pixel_fmt);
+ if (in_fmt == RGB) {
+ if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
+ /* Enable RGB->YCBCR CSC2 */
+ _init_csc(ipu, IC_TASK_VIEWFINDER, RGB, out_fmt, 2);
+ ic_conf |= IC_CONF_PRPVF_CSC2;
+ }
+ }
+ if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
+ if (out_fmt == RGB) {
+ /* Enable YCBCR->RGB CSC2 */
+ _init_csc(ipu, IC_TASK_VIEWFINDER, YCbCr, RGB, 2);
+ ic_conf |= IC_CONF_PRPVF_CSC2;
+ } else {
+ /* TODO: Support YUV<->YCbCr conversion? */
+ }
+ }
+
+ if (params->mem_prp_vf_mem.global_alpha_en) {
+ ic_conf |= IC_CONF_IC_GLB_LOC_A;
+ reg = ipu_ic_read(ipu, IC_CMBP_1);
+ reg &= ~(0xff);
+ reg |= params->mem_prp_vf_mem.alpha;
+ ipu_ic_write(ipu, reg, IC_CMBP_1);
+ } else
+ ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
+
+ if (params->mem_prp_vf_mem.key_color_en) {
+ ic_conf |= IC_CONF_KEY_COLOR_EN;
+ ipu_ic_write(ipu, params->mem_prp_vf_mem.key_color,
+ IC_CMBP_2);
+ } else
+ ic_conf &= ~IC_CONF_KEY_COLOR_EN;
+ } else {
+ ic_conf &= ~IC_CONF_PRPVF_CMB;
+ }
+
+ if (src_is_csi)
+ ic_conf &= ~IC_CONF_RWS_EN;
+ else
+ ic_conf |= IC_CONF_RWS_EN;
+
+ ipu_ic_write(ipu, ic_conf, IC_CONF);
+
+ return ret;
+}
+
+void _ipu_ic_uninit_prpvf(struct ipu_soc *ipu)
+{
+ uint32_t reg;
+
+ reg = ipu_ic_read(ipu, IC_CONF);
+ reg &= ~(IC_CONF_PRPVF_EN | IC_CONF_PRPVF_CMB |
+ IC_CONF_PRPVF_CSC2 | IC_CONF_PRPVF_CSC1);
+ ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+void _ipu_ic_init_rotate_vf(struct ipu_soc *ipu, ipu_channel_params_t *params)
+{
+}
+
+void _ipu_ic_uninit_rotate_vf(struct ipu_soc *ipu)
+{
+ uint32_t reg;
+ reg = ipu_ic_read(ipu, IC_CONF);
+ reg &= ~IC_CONF_PRPVF_ROT_EN;
+ ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+int _ipu_ic_init_prpenc(struct ipu_soc *ipu, ipu_channel_params_t *params,
+ bool src_is_csi)
+{
+ uint32_t reg, ic_conf;
+ uint32_t downsizeCoeff, resizeCoeff;
+ ipu_color_space_t in_fmt, out_fmt;
+ int ret = 0;
+
+ /* Setup vertical resizing */
+ if (!params->mem_prp_enc_mem.outv_resize_ratio) {
+ ret = _calc_resize_coeffs(ipu,
+ params->mem_prp_enc_mem.in_height,
+ params->mem_prp_enc_mem.out_height,
+ &resizeCoeff, &downsizeCoeff);
+ if (ret < 0) {
+ dev_err(ipu->dev, "failed to calculate prpenc height "
+ "scaling coefficients\n");
+ return ret;
+ }
+
+ reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
+ } else
+ reg = (params->mem_prp_enc_mem.outv_resize_ratio) << 16;
+
+ /* Setup horizontal resizing */
+ if (!params->mem_prp_enc_mem.outh_resize_ratio) {
+ ret = _calc_resize_coeffs(ipu, params->mem_prp_enc_mem.in_width,
+ params->mem_prp_enc_mem.out_width,
+ &resizeCoeff, &downsizeCoeff);
+ if (ret < 0) {
+ dev_err(ipu->dev, "failed to calculate prpenc width "
+ "scaling coefficients\n");
+ return ret;
+ }
+
+ reg |= (downsizeCoeff << 14) | resizeCoeff;
+ } else
+ reg |= params->mem_prp_enc_mem.outh_resize_ratio;
+
+ ipu_ic_write(ipu, reg, IC_PRP_ENC_RSC);
+
+ ic_conf = ipu_ic_read(ipu, IC_CONF);
+
+ /* Setup color space conversion */
+ in_fmt = format_to_colorspace(params->mem_prp_enc_mem.in_pixel_fmt);
+ out_fmt = format_to_colorspace(params->mem_prp_enc_mem.out_pixel_fmt);
+ if (in_fmt == RGB) {
+ if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
+ /* Enable RGB->YCBCR CSC1 */
+ _init_csc(ipu, IC_TASK_ENCODER, RGB, out_fmt, 1);
+ ic_conf |= IC_CONF_PRPENC_CSC1;
+ }
+ }
+ if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
+ if (out_fmt == RGB) {
+ /* Enable YCBCR->RGB CSC1 */
+ _init_csc(ipu, IC_TASK_ENCODER, YCbCr, RGB, 1);
+ ic_conf |= IC_CONF_PRPENC_CSC1;
+ } else {
+ /* TODO: Support YUV<->YCbCr conversion? */
+ }
+ }
+
+ if (src_is_csi)
+ ic_conf &= ~IC_CONF_RWS_EN;
+ else
+ ic_conf |= IC_CONF_RWS_EN;
+
+ ipu_ic_write(ipu, ic_conf, IC_CONF);
+
+ return ret;
+}
+
+void _ipu_ic_uninit_prpenc(struct ipu_soc *ipu)
+{
+ uint32_t reg;
+
+ reg = ipu_ic_read(ipu, IC_CONF);
+ reg &= ~(IC_CONF_PRPENC_EN | IC_CONF_PRPENC_CSC1);
+ ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+void _ipu_ic_init_rotate_enc(struct ipu_soc *ipu, ipu_channel_params_t *params)
+{
+}
+
+void _ipu_ic_uninit_rotate_enc(struct ipu_soc *ipu)
+{
+ uint32_t reg;
+
+ reg = ipu_ic_read(ipu, IC_CONF);
+ reg &= ~(IC_CONF_PRPENC_ROT_EN);
+ ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+int _ipu_ic_init_pp(struct ipu_soc *ipu, ipu_channel_params_t *params)
+{
+ uint32_t reg, ic_conf;
+ uint32_t downsizeCoeff, resizeCoeff;
+ ipu_color_space_t in_fmt, out_fmt;
+ int ret = 0;
+
+ /* Setup vertical resizing */
+ if (!params->mem_pp_mem.outv_resize_ratio) {
+ ret = _calc_resize_coeffs(ipu, params->mem_pp_mem.in_height,
+ params->mem_pp_mem.out_height,
+ &resizeCoeff, &downsizeCoeff);
+ if (ret < 0) {
+ dev_err(ipu->dev, "failed to calculate pp height "
+ "scaling coefficients\n");
+ return ret;
+ }
+
+ reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
+ } else {
+ reg = (params->mem_pp_mem.outv_resize_ratio) << 16;
+ }
+
+ /* Setup horizontal resizing */
+ if (!params->mem_pp_mem.outh_resize_ratio) {
+ ret = _calc_resize_coeffs(ipu, params->mem_pp_mem.in_width,
+ params->mem_pp_mem.out_width,
+ &resizeCoeff, &downsizeCoeff);
+ if (ret < 0) {
+ dev_err(ipu->dev, "failed to calculate pp width "
+ "scaling coefficients\n");
+ return ret;
+ }
+
+ reg |= (downsizeCoeff << 14) | resizeCoeff;
+ } else {
+ reg |= params->mem_pp_mem.outh_resize_ratio;
+ }
+
+ ipu_ic_write(ipu, reg, IC_PP_RSC);
+
+ ic_conf = ipu_ic_read(ipu, IC_CONF);
+
+ /* Setup color space conversion */
+ in_fmt = format_to_colorspace(params->mem_pp_mem.in_pixel_fmt);
+ out_fmt = format_to_colorspace(params->mem_pp_mem.out_pixel_fmt);
+ if (in_fmt == RGB) {
+ if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
+ /* Enable RGB->YCBCR CSC1 */
+ _init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, out_fmt, 1);
+ ic_conf |= IC_CONF_PP_CSC1;
+ }
+ }
+ if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
+ if (out_fmt == RGB) {
+ /* Enable YCBCR->RGB CSC1 */
+ _init_csc(ipu, IC_TASK_POST_PROCESSOR, YCbCr, RGB, 1);
+ ic_conf |= IC_CONF_PP_CSC1;
+ } else {
+ /* TODO: Support YUV<->YCbCr conversion? */
+ }
+ }
+
+ if (params->mem_pp_mem.graphics_combine_en) {
+ ic_conf |= IC_CONF_PP_CMB;
+
+ if (!(ic_conf & IC_CONF_PP_CSC1)) {
+ /* need transparent CSC1 conversion */
+ _init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, RGB, 1);
+ ic_conf |= IC_CONF_PP_CSC1; /* Enable RGB->RGB CSC */
+ }
+
+ in_fmt = format_to_colorspace(params->mem_pp_mem.in_g_pixel_fmt);
+ out_fmt = format_to_colorspace(params->mem_pp_mem.out_pixel_fmt);
+ if (in_fmt == RGB) {
+ if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
+ /* Enable RGB->YCBCR CSC2 */
+ _init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, out_fmt, 2);
+ ic_conf |= IC_CONF_PP_CSC2;
+ }
+ }
+ if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
+ if (out_fmt == RGB) {
+ /* Enable YCBCR->RGB CSC2 */
+ _init_csc(ipu, IC_TASK_POST_PROCESSOR, YCbCr, RGB, 2);
+ ic_conf |= IC_CONF_PP_CSC2;
+ } else {
+ /* TODO: Support YUV<->YCbCr conversion? */
+ }
+ }
+
+ if (params->mem_pp_mem.global_alpha_en) {
+ ic_conf |= IC_CONF_IC_GLB_LOC_A;
+ reg = ipu_ic_read(ipu, IC_CMBP_1);
+ reg &= ~(0xff00);
+ reg |= (params->mem_pp_mem.alpha << 8);
+ ipu_ic_write(ipu, reg, IC_CMBP_1);
+ } else
+ ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
+
+ if (params->mem_pp_mem.key_color_en) {
+ ic_conf |= IC_CONF_KEY_COLOR_EN;
+ ipu_ic_write(ipu, params->mem_pp_mem.key_color,
+ IC_CMBP_2);
+ } else
+ ic_conf &= ~IC_CONF_KEY_COLOR_EN;
+ } else {
+ ic_conf &= ~IC_CONF_PP_CMB;
+ }
+
+ ipu_ic_write(ipu, ic_conf, IC_CONF);
+
+ return ret;
+}
+
+void _ipu_ic_uninit_pp(struct ipu_soc *ipu)
+{
+ uint32_t reg;
+
+ reg = ipu_ic_read(ipu, IC_CONF);
+ reg &= ~(IC_CONF_PP_EN | IC_CONF_PP_CSC1 | IC_CONF_PP_CSC2 |
+ IC_CONF_PP_CMB);
+ ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+void _ipu_ic_init_rotate_pp(struct ipu_soc *ipu, ipu_channel_params_t *params)
+{
+}
+
+void _ipu_ic_uninit_rotate_pp(struct ipu_soc *ipu)
+{
+ uint32_t reg;
+ reg = ipu_ic_read(ipu, IC_CONF);
+ reg &= ~IC_CONF_PP_ROT_EN;
+ ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+int _ipu_ic_idma_init(struct ipu_soc *ipu, int dma_chan,
+ uint16_t width, uint16_t height,
+ int burst_size, ipu_rotate_mode_t rot)
+{
+ u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
+ u32 temp_rot = bitrev8(rot) >> 5;
+ bool need_hor_flip = false;
+
+ if ((burst_size != 8) && (burst_size != 16)) {
+ dev_dbg(ipu->dev, "Illegal burst length for IC\n");
+ return -EINVAL;
+ }
+
+ width--;
+ height--;
+
+ if (temp_rot & 0x2) /* Need horizontal flip */
+ need_hor_flip = true;
+
+ ic_idmac_1 = ipu_ic_read(ipu, IC_IDMAC_1);
+ ic_idmac_2 = ipu_ic_read(ipu, IC_IDMAC_2);
+ ic_idmac_3 = ipu_ic_read(ipu, IC_IDMAC_3);
+ if (dma_chan == 22) { /* PP output - CB2 */
+ if (burst_size == 16)
+ ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
+
+ if (need_hor_flip)
+ ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
+
+ ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
+ ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
+
+ ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
+ ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
+ } else if (dma_chan == 11) { /* PP Input - CB5 */
+ if (burst_size == 16)
+ ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
+ } else if (dma_chan == 47) { /* PP Rot input */
+ ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
+ ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
+ }
+
+ if (dma_chan == 12) { /* PRP Input - CB6 */
+ if (burst_size == 16)
+ ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
+ }
+
+ if (dma_chan == 20) { /* PRP ENC output - CB0 */
+ if (burst_size == 16)
+ ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
+
+ if (need_hor_flip)
+ ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
+
+ ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
+ ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
+
+ ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
+ ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
+
+ } else if (dma_chan == 45) { /* PRP ENC Rot input */
+ ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
+ ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
+ }
+
+ if (dma_chan == 21) { /* PRP VF output - CB1 */
+ if (burst_size == 16)
+ ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
+
+ if (need_hor_flip)
+ ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
+
+ ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
+ ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
+
+ ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
+ ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
+
+ } else if (dma_chan == 46) { /* PRP VF Rot input */
+ ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
+ ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
+ }
+
+ if (dma_chan == 14) { /* PRP VF graphics combining input - CB3 */
+ if (burst_size == 16)
+ ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
+ } else if (dma_chan == 15) { /* PP graphics combining input - CB4 */
+ if (burst_size == 16)
+ ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
+ } else if (dma_chan == 5) { /* VDIC OUTPUT - CB7 */
+ if (burst_size == 16)
+ ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
+ else
+ ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
+ }
+
+ ipu_ic_write(ipu, ic_idmac_1, IC_IDMAC_1);
+ ipu_ic_write(ipu, ic_idmac_2, IC_IDMAC_2);
+ ipu_ic_write(ipu, ic_idmac_3, IC_IDMAC_3);
+ return 0;
+}
+
+static void _init_csc(struct ipu_soc *ipu, uint8_t ic_task, ipu_color_space_t in_format,
+ ipu_color_space_t out_format, int csc_index)
+{
+ /*
+ * Y = 0.257 * R + 0.504 * G + 0.098 * B + 16;
+ * U = -0.148 * R - 0.291 * G + 0.439 * B + 128;
+ * V = 0.439 * R - 0.368 * G - 0.071 * B + 128;
+ */
+ static const uint32_t rgb2ycbcr_coeff[4][3] = {
+ {0x0042, 0x0081, 0x0019},
+ {0x01DA, 0x01B6, 0x0070},
+ {0x0070, 0x01A2, 0x01EE},
+ {0x0040, 0x0200, 0x0200}, /* A0, A1, A2 */
+ };
+
+ /* transparent RGB->RGB matrix for combining
+ */
+ static const uint32_t rgb2rgb_coeff[4][3] = {
+ {0x0080, 0x0000, 0x0000},
+ {0x0000, 0x0080, 0x0000},
+ {0x0000, 0x0000, 0x0080},
+ {0x0000, 0x0000, 0x0000}, /* A0, A1, A2 */
+ };
+
+/* R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
+ G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
+ B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); */
+ static const uint32_t ycbcr2rgb_coeff[4][3] = {
+ {149, 0, 204},
+ {149, 462, 408},
+ {149, 255, 0},
+ {8192 - 446, 266, 8192 - 554}, /* A0, A1, A2 */
+ };
+
+ uint32_t param;
+ uint32_t *base = NULL;
+
+ if (ic_task == IC_TASK_ENCODER) {
+ base = (uint32_t *)ipu->tpmem_base + 0x2008 / 4;
+ } else if (ic_task == IC_TASK_VIEWFINDER) {
+ if (csc_index == 1)
+ base = (uint32_t *)ipu->tpmem_base + 0x4028 / 4;
+ else
+ base = (uint32_t *)ipu->tpmem_base + 0x4040 / 4;
+ } else if (ic_task == IC_TASK_POST_PROCESSOR) {
+ if (csc_index == 1)
+ base = (uint32_t *)ipu->tpmem_base + 0x6060 / 4;
+ else
+ base = (uint32_t *)ipu->tpmem_base + 0x6078 / 4;
+ } else {
+ BUG();
+ }
+
+ if ((in_format == YCbCr) && (out_format == RGB)) {
+ /* Init CSC (YCbCr->RGB) */
+ param = (ycbcr2rgb_coeff[3][0] << 27) |
+ (ycbcr2rgb_coeff[0][0] << 18) |
+ (ycbcr2rgb_coeff[1][1] << 9) | ycbcr2rgb_coeff[2][2];
+ writel(param, base++);
+ /* scale = 2, sat = 0 */
+ param = (ycbcr2rgb_coeff[3][0] >> 5) | (2L << (40 - 32));
+ writel(param, base++);
+
+ param = (ycbcr2rgb_coeff[3][1] << 27) |
+ (ycbcr2rgb_coeff[0][1] << 18) |
+ (ycbcr2rgb_coeff[1][0] << 9) | ycbcr2rgb_coeff[2][0];
+ writel(param, base++);
+ param = (ycbcr2rgb_coeff[3][1] >> 5);
+ writel(param, base++);
+
+ param = (ycbcr2rgb_coeff[3][2] << 27) |
+ (ycbcr2rgb_coeff[0][2] << 18) |
+ (ycbcr2rgb_coeff[1][2] << 9) | ycbcr2rgb_coeff[2][1];
+ writel(param, base++);
+ param = (ycbcr2rgb_coeff[3][2] >> 5);
+ writel(param, base++);
+ } else if ((in_format == RGB) && (out_format == YCbCr)) {
+ /* Init CSC (RGB->YCbCr) */
+ param = (rgb2ycbcr_coeff[3][0] << 27) |
+ (rgb2ycbcr_coeff[0][0] << 18) |
+ (rgb2ycbcr_coeff[1][1] << 9) | rgb2ycbcr_coeff[2][2];
+ writel(param, base++);
+ /* scale = 1, sat = 0 */
+ param = (rgb2ycbcr_coeff[3][0] >> 5) | (1UL << 8);
+ writel(param, base++);
+
+ param = (rgb2ycbcr_coeff[3][1] << 27) |
+ (rgb2ycbcr_coeff[0][1] << 18) |
+ (rgb2ycbcr_coeff[1][0] << 9) | rgb2ycbcr_coeff[2][0];
+ writel(param, base++);
+ param = (rgb2ycbcr_coeff[3][1] >> 5);
+ writel(param, base++);
+
+ param = (rgb2ycbcr_coeff[3][2] << 27) |
+ (rgb2ycbcr_coeff[0][2] << 18) |
+ (rgb2ycbcr_coeff[1][2] << 9) | rgb2ycbcr_coeff[2][1];
+ writel(param, base++);
+ param = (rgb2ycbcr_coeff[3][2] >> 5);
+ writel(param, base++);
+ } else if ((in_format == RGB) && (out_format == RGB)) {
+ /* Init CSC */
+ param =
+ (rgb2rgb_coeff[3][0] << 27) | (rgb2rgb_coeff[0][0] << 18) |
+ (rgb2rgb_coeff[1][1] << 9) | rgb2rgb_coeff[2][2];
+ writel(param, base++);
+ /* scale = 2, sat = 0 */
+ param = (rgb2rgb_coeff[3][0] >> 5) | (2UL << 8);
+ writel(param, base++);
+
+ param =
+ (rgb2rgb_coeff[3][1] << 27) | (rgb2rgb_coeff[0][1] << 18) |
+ (rgb2rgb_coeff[1][0] << 9) | rgb2rgb_coeff[2][0];
+ writel(param, base++);
+ param = (rgb2rgb_coeff[3][1] >> 5);
+ writel(param, base++);
+
+ param =
+ (rgb2rgb_coeff[3][2] << 27) | (rgb2rgb_coeff[0][2] << 18) |
+ (rgb2rgb_coeff[1][2] << 9) | rgb2rgb_coeff[2][1];
+ writel(param, base++);
+ param = (rgb2rgb_coeff[3][2] >> 5);
+ writel(param, base++);
+ } else {
+ dev_err(ipu->dev, "Unsupported color space conversion\n");
+ }
+}
+
+static int _calc_resize_coeffs(struct ipu_soc *ipu,
+ uint32_t inSize, uint32_t outSize,
+ uint32_t *resizeCoeff,
+ uint32_t *downsizeCoeff)
+{
+ uint32_t tempSize;
+ uint32_t tempDownsize;
+
+ if (inSize > 4096) {
+ dev_err(ipu->dev, "IC input size(%d) cannot exceed 4096\n",
+ inSize);
+ return -EINVAL;
+ }
+
+ if (outSize > 1024) {
+ dev_err(ipu->dev, "IC output size(%d) cannot exceed 1024\n",
+ outSize);
+ return -EINVAL;
+ }
+
+ if ((outSize << 3) < inSize) {
+ dev_err(ipu->dev, "IC cannot downsize more than 8:1\n");
+ return -EINVAL;
+ }
+
+ /* Compute downsizing coefficient */
+ /* Output of downsizing unit cannot be more than 1024 */
+ tempDownsize = 0;
+ tempSize = inSize;
+ while (((tempSize > 1024) || (tempSize >= outSize * 2)) &&
+ (tempDownsize < 2)) {
+ tempSize >>= 1;
+ tempDownsize++;
+ }
+ *downsizeCoeff = tempDownsize;
+
+ /* compute resizing coefficient using the following equation:
+ resizeCoeff = M*(SI -1)/(SO - 1)
+ where M = 2^13, SI - input size, SO - output size */
+ *resizeCoeff = (8192L * (tempSize - 1)) / (outSize - 1);
+ if (*resizeCoeff >= 16384L) {
+ dev_err(ipu->dev, "Overflow on IC resize coefficient.\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(ipu->dev, "resizing from %u -> %u pixels, "
+ "downsize=%u, resize=%u.%lu (reg=%u)\n", inSize, outSize,
+ *downsizeCoeff, (*resizeCoeff >= 8192L) ? 1 : 0,
+ ((*resizeCoeff & 0x1FFF) * 10000L) / 8192L, *resizeCoeff);
+
+ return 0;
+}
+
+void _ipu_vdi_toggle_top_field_man(struct ipu_soc *ipu)
+{
+ uint32_t reg;
+ uint32_t mask_reg;
+
+ reg = ipu_vdi_read(ipu, VDI_C);
+ mask_reg = reg & VDI_C_TOP_FIELD_MAN_1;
+ if (mask_reg == VDI_C_TOP_FIELD_MAN_1)
+ reg &= ~VDI_C_TOP_FIELD_MAN_1;
+ else
+ reg |= VDI_C_TOP_FIELD_MAN_1;
+
+ ipu_vdi_write(ipu, reg, VDI_C);
+}
diff --git a/drivers/mxc/ipu3/ipu_param_mem.h b/drivers/mxc/ipu3/ipu_param_mem.h
new file mode 100644
index 000000000000..a22839a98ac8
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_param_mem.h
@@ -0,0 +1,998 @@
+/*
+ * Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __INCLUDE_IPU_PARAM_MEM_H__
+#define __INCLUDE_IPU_PARAM_MEM_H__
+
+#include <linux/bitrev.h>
+#include <linux/types.h>
+
+#include "ipu_prv.h"
+
+extern u32 *ipu_cpmem_base;
+
+struct ipu_ch_param_word {
+ uint32_t data[5];
+ uint32_t res[3];
+};
+
+struct ipu_ch_param {
+ struct ipu_ch_param_word word[2];
+};
+
+#define ipu_ch_param_addr(ipu, ch) \
+ (((struct ipu_ch_param *)(ipu)->cpmem_base) + (ch))
+
+#define _param_word(base, w) \
+ (((struct ipu_ch_param *)(base))->word[(w)].data)
+
+#define ipu_ch_param_set_field(base, w, bit, size, v) { \
+ int i = (bit) / 32; \
+ int off = (bit) % 32; \
+ _param_word((base), (w))[i] |= (v) << off; \
+ if (((bit)+(size)-1)/32 > i) { \
+ _param_word((base), (w))[i + 1] |= \
+ (v) >> (off ? (32 - off) : 0); \
+ } \
+}
+
+#define ipu_ch_param_set_field_io(base, w, bit, size, v) { \
+ int i = (bit) / 32; \
+ int off = (bit) % 32; \
+ unsigned reg_offset; \
+ u32 temp; \
+ reg_offset = sizeof(struct ipu_ch_param_word) * (w) / 4; \
+ reg_offset += i; \
+ temp = readl((u32 *)(base) + reg_offset); \
+ temp |= (v) << off; \
+ writel(temp, (u32 *)(base) + reg_offset); \
+ if (((bit)+(size)-1)/32 > i) { \
+ reg_offset++; \
+ temp = readl((u32 *)(base) + reg_offset); \
+ temp |= (v) >> (off ? (32 - off) : 0); \
+ writel(temp, (u32 *)(base) + reg_offset); \
+ } \
+}
+
+#define ipu_ch_param_mod_field(base, w, bit, size, v) { \
+ int i = (bit) / 32; \
+ int off = (bit) % 32; \
+ u32 mask = (1UL << (size)) - 1; \
+ u32 temp = _param_word((base), (w))[i]; \
+ temp &= ~(mask << off); \
+ _param_word((base), (w))[i] = temp | (v) << off; \
+ if (((bit)+(size)-1)/32 > i) { \
+ temp = _param_word((base), (w))[i + 1]; \
+ temp &= ~(mask >> (32 - off)); \
+ _param_word((base), (w))[i + 1] = \
+ temp | ((v) >> (off ? (32 - off) : 0)); \
+ } \
+}
+
+#define ipu_ch_param_mod_field_io(base, w, bit, size, v) { \
+ int i = (bit) / 32; \
+ int off = (bit) % 32; \
+ u32 mask = (1UL << (size)) - 1; \
+ unsigned reg_offset; \
+ u32 temp; \
+ reg_offset = sizeof(struct ipu_ch_param_word) * (w) / 4; \
+ reg_offset += i; \
+ temp = readl((u32 *)(base) + reg_offset); \
+ temp &= ~(mask << off); \
+ temp |= (v) << off; \
+ writel(temp, (u32 *)(base) + reg_offset); \
+ if (((bit)+(size)-1)/32 > i) { \
+ reg_offset++; \
+ temp = readl((u32 *)(base) + reg_offset); \
+ temp &= ~(mask >> (32 - off)); \
+ temp |= ((v) >> (off ? (32 - off) : 0)); \
+ writel(temp, (u32 *)(base) + reg_offset); \
+ } \
+}
+
+#define ipu_ch_param_read_field(base, w, bit, size) ({ \
+ u32 temp2; \
+ int i = (bit) / 32; \
+ int off = (bit) % 32; \
+ u32 mask = (1UL << (size)) - 1; \
+ u32 temp1 = _param_word((base), (w))[i]; \
+ temp1 = mask & (temp1 >> off); \
+ if (((bit)+(size)-1)/32 > i) { \
+ temp2 = _param_word((base), (w))[i + 1]; \
+ temp2 &= mask >> (off ? (32 - off) : 0); \
+ temp1 |= temp2 << (off ? (32 - off) : 0); \
+ } \
+ temp1; \
+})
+
+#define ipu_ch_param_read_field_io(base, w, bit, size) ({ \
+ u32 temp1, temp2; \
+ int i = (bit) / 32; \
+ int off = (bit) % 32; \
+ u32 mask = (1UL << (size)) - 1; \
+ unsigned reg_offset; \
+ reg_offset = sizeof(struct ipu_ch_param_word) * (w) / 4; \
+ reg_offset += i; \
+ temp1 = readl((u32 *)(base) + reg_offset); \
+ temp1 = mask & (temp1 >> off); \
+ if (((bit)+(size)-1)/32 > i) { \
+ reg_offset++; \
+ temp2 = readl((u32 *)(base) + reg_offset); \
+ temp2 &= mask >> (off ? (32 - off) : 0); \
+ temp1 |= temp2 << (off ? (32 - off) : 0); \
+ } \
+ temp1; \
+})
+
+static inline int __ipu_ch_get_third_buf_cpmem_num(int ch)
+{
+ switch (ch) {
+ case 8:
+ return 64;
+ case 9:
+ return 65;
+ case 10:
+ return 66;
+ case 13:
+ return 67;
+ case 21:
+ return 68;
+ case 23:
+ return 69;
+ case 27:
+ return 70;
+ case 28:
+ return 71;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static inline void _ipu_ch_params_set_packing(struct ipu_ch_param *p,
+ int red_width, int red_offset,
+ int green_width, int green_offset,
+ int blue_width, int blue_offset,
+ int alpha_width, int alpha_offset)
+{
+ /* Setup red width and offset */
+ ipu_ch_param_set_field(p, 1, 116, 3, red_width - 1);
+ ipu_ch_param_set_field(p, 1, 128, 5, red_offset);
+ /* Setup green width and offset */
+ ipu_ch_param_set_field(p, 1, 119, 3, green_width - 1);
+ ipu_ch_param_set_field(p, 1, 133, 5, green_offset);
+ /* Setup blue width and offset */
+ ipu_ch_param_set_field(p, 1, 122, 3, blue_width - 1);
+ ipu_ch_param_set_field(p, 1, 138, 5, blue_offset);
+ /* Setup alpha width and offset */
+ ipu_ch_param_set_field(p, 1, 125, 3, alpha_width - 1);
+ ipu_ch_param_set_field(p, 1, 143, 5, alpha_offset);
+}
+
+static inline void _ipu_ch_param_dump(struct ipu_soc *ipu, int ch)
+{
+ struct ipu_ch_param *p = ipu_ch_param_addr(ipu, ch);
+ dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", ch,
+ p->word[0].data[0], p->word[0].data[1], p->word[0].data[2],
+ p->word[0].data[3], p->word[0].data[4]);
+ dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", ch,
+ p->word[1].data[0], p->word[1].data[1], p->word[1].data[2],
+ p->word[1].data[3], p->word[1].data[4]);
+ dev_dbg(ipu->dev, "PFS 0x%x, ",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 85, 4));
+ dev_dbg(ipu->dev, "BPP 0x%x, ",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 107, 3));
+ dev_dbg(ipu->dev, "NPB 0x%x\n",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7));
+
+ dev_dbg(ipu->dev, "FW %d, ",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 125, 13));
+ dev_dbg(ipu->dev, "FH %d, ",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 138, 12));
+ dev_dbg(ipu->dev, "EBA0 0x%x\n",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 0, 29) << 3);
+ dev_dbg(ipu->dev, "EBA1 0x%x\n",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 29, 29) << 3);
+ dev_dbg(ipu->dev, "Stride %d\n",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14));
+ dev_dbg(ipu->dev, "scan_order %d\n",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 113, 1));
+ dev_dbg(ipu->dev, "uv_stride %d\n",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 128, 14));
+ dev_dbg(ipu->dev, "u_offset 0x%x\n",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22) << 3);
+ dev_dbg(ipu->dev, "v_offset 0x%x\n",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22) << 3);
+
+ dev_dbg(ipu->dev, "Width0 %d+1, ",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 116, 3));
+ dev_dbg(ipu->dev, "Width1 %d+1, ",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 119, 3));
+ dev_dbg(ipu->dev, "Width2 %d+1, ",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 122, 3));
+ dev_dbg(ipu->dev, "Width3 %d+1, ",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 125, 3));
+ dev_dbg(ipu->dev, "Offset0 %d, ",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 128, 5));
+ dev_dbg(ipu->dev, "Offset1 %d, ",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 133, 5));
+ dev_dbg(ipu->dev, "Offset2 %d, ",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 138, 5));
+ dev_dbg(ipu->dev, "Offset3 %d\n",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 143, 5));
+}
+
+static inline void fill_cpmem(struct ipu_soc *ipu, int ch, struct ipu_ch_param *params)
+{
+ int i, w;
+ void *addr = ipu_ch_param_addr(ipu, ch);
+
+ /* 2 words, 5 valid data */
+ for (w = 0; w < 2; w++) {
+ for (i = 0; i < 5; i++) {
+ writel(params->word[w].data[i], addr);
+ addr += 4;
+ }
+ addr += 12;
+ }
+}
+
+static inline void _ipu_ch_param_init(struct ipu_soc *ipu, int ch,
+ uint32_t pixel_fmt, uint32_t width,
+ uint32_t height, uint32_t stride,
+ uint32_t u, uint32_t v,
+ uint32_t uv_stride, dma_addr_t addr0,
+ dma_addr_t addr1, dma_addr_t addr2)
+{
+ uint32_t u_offset = 0;
+ uint32_t v_offset = 0;
+ uint32_t bs = 0;
+ int32_t sub_ch = 0;
+ struct ipu_ch_param params;
+
+ memset(&params, 0, sizeof(params));
+
+ ipu_ch_param_set_field(&params, 0, 125, 13, width - 1);
+
+ if (((ch == 8) || (ch == 9) || (ch == 10)) && !ipu->vdoa_en) {
+ ipu_ch_param_set_field(&params, 0, 138, 12, (height / 2) - 1);
+ ipu_ch_param_set_field(&params, 1, 102, 14, (stride * 2) - 1);
+ } else {
+ /* note: for vdoa+vdi- ch8/9/10, always use band mode */
+ ipu_ch_param_set_field(&params, 0, 138, 12, height - 1);
+ ipu_ch_param_set_field(&params, 1, 102, 14, stride - 1);
+ }
+
+ /* EBA is 8-byte aligned */
+ ipu_ch_param_set_field(&params, 1, 0, 29, addr0 >> 3);
+ ipu_ch_param_set_field(&params, 1, 29, 29, addr1 >> 3);
+ if (addr0%8)
+ dev_warn(ipu->dev,
+ "IDMAC%d's EBA0 is not 8-byte aligned\n", ch);
+ if (addr1%8)
+ dev_warn(ipu->dev,
+ "IDMAC%d's EBA1 is not 8-byte aligned\n", ch);
+
+ switch (pixel_fmt) {
+ case IPU_PIX_FMT_GENERIC:
+ /*Represents 8-bit Generic data */
+ ipu_ch_param_set_field(&params, 0, 107, 3, 5); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 6); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 63); /* burst size */
+
+ break;
+ case IPU_PIX_FMT_GENERIC_16:
+ /* Represents 16-bit generic data */
+ ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 6); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
+
+ break;
+ case IPU_PIX_FMT_GENERIC_32:
+ /*Represents 32-bit Generic data */
+ break;
+ case IPU_PIX_FMT_RGB565:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
+
+ _ipu_ch_params_set_packing(&params, 5, 0, 6, 5, 5, 11, 8, 16);
+ break;
+ case IPU_PIX_FMT_BGRA4444:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
+
+ _ipu_ch_params_set_packing(&params, 4, 4, 4, 8, 4, 12, 4, 0);
+ break;
+ case IPU_PIX_FMT_BGRA5551:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
+
+ _ipu_ch_params_set_packing(&params, 5, 1, 5, 6, 5, 11, 1, 0);
+ break;
+ case IPU_PIX_FMT_BGR24:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 1); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 19); /* burst size */
+
+ _ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
+ break;
+ case IPU_PIX_FMT_RGB24:
+ case IPU_PIX_FMT_YUV444:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 1); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 19); /* burst size */
+
+ _ipu_ch_params_set_packing(&params, 8, 16, 8, 8, 8, 0, 8, 24);
+ break;
+ case IPU_PIX_FMT_VYU444:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 1); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 19); /* burst size */
+
+ _ipu_ch_params_set_packing(&params, 8, 8, 8, 0, 8, 16, 8, 24);
+ break;
+ case IPU_PIX_FMT_AYUV:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 0); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
+
+ _ipu_ch_params_set_packing(&params, 8, 8, 8, 16, 8, 24, 8, 0);
+ break;
+ case IPU_PIX_FMT_BGRA32:
+ case IPU_PIX_FMT_BGR32:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 0); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
+
+ _ipu_ch_params_set_packing(&params, 8, 8, 8, 16, 8, 24, 8, 0);
+ break;
+ case IPU_PIX_FMT_RGBA32:
+ case IPU_PIX_FMT_RGB32:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 0); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
+
+ _ipu_ch_params_set_packing(&params, 8, 24, 8, 16, 8, 8, 8, 0);
+ break;
+ case IPU_PIX_FMT_ABGR32:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 0); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
+
+ _ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
+ break;
+ case IPU_PIX_FMT_UYVY:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 0xA); /* pix format */
+ if ((ch == 8) || (ch == 9) || (ch == 10)) {
+ ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
+ } else {
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
+ }
+ break;
+ case IPU_PIX_FMT_YUYV:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 0x8); /* pix format */
+ if ((ch == 8) || (ch == 9) || (ch == 10)) {
+ if (ipu->vdoa_en) {
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31);
+ } else {
+ ipu_ch_param_set_field(&params, 1, 78, 7, 15);
+ }
+ } else {
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
+ }
+ break;
+ case IPU_PIX_FMT_YUV420P2:
+ case IPU_PIX_FMT_YUV420P:
+ ipu_ch_param_set_field(&params, 1, 85, 4, 2); /* pix format */
+
+ if (uv_stride < stride / 2)
+ uv_stride = stride / 2;
+
+ u_offset = stride * height;
+ v_offset = u_offset + (uv_stride * height / 2);
+ if ((ch == 8) || (ch == 9) || (ch == 10)) {
+ ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
+ uv_stride = uv_stride*2;
+ } else {
+ if (_ipu_is_smfc_chan(ch) &&
+ ipu->smfc_idmac_12bit_3planar_bs_fixup)
+ bs = 15;
+ else
+ bs = 31;
+ ipu_ch_param_set_field(&params, 1, 78, 7, bs); /* burst size */
+ }
+ break;
+ case IPU_PIX_FMT_YVU420P:
+ ipu_ch_param_set_field(&params, 1, 85, 4, 2); /* pix format */
+
+ if (uv_stride < stride / 2)
+ uv_stride = stride / 2;
+
+ v_offset = stride * height;
+ u_offset = v_offset + (uv_stride * height / 2);
+ if ((ch == 8) || (ch == 9) || (ch == 10)) {
+ ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
+ uv_stride = uv_stride*2;
+ } else {
+ if (_ipu_is_smfc_chan(ch) &&
+ ipu->smfc_idmac_12bit_3planar_bs_fixup)
+ bs = 15;
+ else
+ bs = 31;
+ ipu_ch_param_set_field(&params, 1, 78, 7, bs); /* burst size */
+ }
+ break;
+ case IPU_PIX_FMT_YVU422P:
+ /* BPP & pixel format */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 1); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
+
+ if (uv_stride < stride / 2)
+ uv_stride = stride / 2;
+
+ v_offset = (v == 0) ? stride * height : v;
+ u_offset = (u == 0) ? v_offset + v_offset / 2 : u;
+ break;
+ case IPU_PIX_FMT_YUV422P:
+ /* BPP & pixel format */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 1); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
+
+ if (uv_stride < stride / 2)
+ uv_stride = stride / 2;
+
+ u_offset = (u == 0) ? stride * height : u;
+ v_offset = (v == 0) ? u_offset + u_offset / 2 : v;
+ break;
+ case IPU_PIX_FMT_YUV444P:
+ /* BPP & pixel format */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 0); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
+ uv_stride = stride;
+ u_offset = (u == 0) ? stride * height : u;
+ v_offset = (v == 0) ? u_offset * 2 : v;
+ break;
+ case IPU_PIX_FMT_NV16:
+ ipu_ch_param_set_field(&params, 1, 85, 4, 1); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
+ uv_stride = stride;
+ u_offset = (u == 0) ? stride * height : u;
+ break;
+ case IPU_PIX_FMT_NV12:
+ /* BPP & pixel format */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 4); /* pix format */
+ uv_stride = stride;
+ u_offset = (u == 0) ? stride * height : u;
+ if ((ch == 8) || (ch == 9) || (ch == 10)) {
+ if (ipu->vdoa_en) {
+ /* one field buffer, memory width 64bits */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 63);
+ } else {
+ ipu_ch_param_set_field(&params, 1, 78, 7, 15);
+ /* top/bottom field in one buffer*/
+ uv_stride = uv_stride*2;
+ }
+ } else {
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
+ }
+ break;
+ default:
+ dev_err(ipu->dev, "mxc ipu: unimplemented pixel format\n");
+ break;
+ }
+ /*set burst size to 16*/
+
+
+ if (uv_stride)
+ ipu_ch_param_set_field(&params, 1, 128, 14, uv_stride - 1);
+
+ /* Get the uv offset from user when need cropping */
+ if (u || v) {
+ u_offset = u;
+ v_offset = v;
+ }
+
+ /* UBO and VBO are 22-bit and 8-byte aligned */
+ if (u_offset/8 > 0x3fffff)
+ dev_warn(ipu->dev,
+ "IDMAC%d's U offset exceeds IPU limitation\n", ch);
+ if (v_offset/8 > 0x3fffff)
+ dev_warn(ipu->dev,
+ "IDMAC%d's V offset exceeds IPU limitation\n", ch);
+ if (u_offset%8)
+ dev_warn(ipu->dev,
+ "IDMAC%d's U offset is not 8-byte aligned\n", ch);
+ if (v_offset%8)
+ dev_warn(ipu->dev,
+ "IDMAC%d's V offset is not 8-byte aligned\n", ch);
+
+ ipu_ch_param_set_field(&params, 0, 46, 22, u_offset / 8);
+ ipu_ch_param_set_field(&params, 0, 68, 22, v_offset / 8);
+
+ dev_dbg(ipu->dev, "initializing idma ch %d @ %p\n", ch, ipu_ch_param_addr(ipu, ch));
+ fill_cpmem(ipu, ch, &params);
+ if (addr2) {
+ sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+ if (sub_ch <= 0)
+ return;
+
+ ipu_ch_param_set_field(&params, 1, 0, 29, addr2 >> 3);
+ ipu_ch_param_set_field(&params, 1, 29, 29, 0);
+ if (addr2%8)
+ dev_warn(ipu->dev,
+ "IDMAC%d's sub-CPMEM entry%d EBA0 is not "
+ "8-byte aligned\n", ch, sub_ch);
+
+ dev_dbg(ipu->dev, "initializing idma ch %d @ %p sub cpmem\n", ch,
+ ipu_ch_param_addr(ipu, sub_ch));
+ fill_cpmem(ipu, sub_ch, &params);
+ }
+};
+
+static inline void _ipu_ch_param_set_burst_size(struct ipu_soc *ipu,
+ uint32_t ch,
+ uint16_t burst_pixels)
+{
+ int32_t sub_ch = 0;
+
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7,
+ burst_pixels - 1);
+
+ sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+ if (sub_ch <= 0)
+ return;
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 78, 7,
+ burst_pixels - 1);
+};
+
+static inline int _ipu_ch_param_get_burst_size(struct ipu_soc *ipu, uint32_t ch)
+{
+ return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7) + 1;
+};
+
+static inline int _ipu_ch_param_get_bpp(struct ipu_soc *ipu, uint32_t ch)
+{
+ return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 107, 3);
+};
+
+static inline void _ipu_ch_param_set_buffer(struct ipu_soc *ipu, uint32_t ch,
+ int bufNum, dma_addr_t phyaddr)
+{
+ if (bufNum == 2) {
+ ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+ if (ch <= 0)
+ return;
+ bufNum = 0;
+ }
+
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 29 * bufNum, 29,
+ phyaddr / 8);
+};
+
+static inline void _ipu_ch_param_set_rotation(struct ipu_soc *ipu, uint32_t ch,
+ ipu_rotate_mode_t rot)
+{
+ u32 temp_rot = bitrev8(rot) >> 5;
+ int32_t sub_ch = 0;
+
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 119, 3, temp_rot);
+
+ sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+ if (sub_ch <= 0)
+ return;
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 119, 3, temp_rot);
+};
+
+static inline void _ipu_ch_param_set_block_mode(struct ipu_soc *ipu, uint32_t ch)
+{
+ int32_t sub_ch = 0;
+
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 117, 2, 1);
+
+ sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+ if (sub_ch <= 0)
+ return;
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 117, 2, 1);
+};
+
+static inline void _ipu_ch_param_set_alpha_use_separate_channel(struct ipu_soc *ipu,
+ uint32_t ch,
+ bool option)
+{
+ int32_t sub_ch = 0;
+
+ if (option) {
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 89, 1, 1);
+ } else {
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 89, 1, 0);
+ }
+
+ sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+ if (sub_ch <= 0)
+ return;
+
+ if (option) {
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 89, 1, 1);
+ } else {
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 89, 1, 0);
+ }
+};
+
+static inline void _ipu_ch_param_set_alpha_condition_read(struct ipu_soc *ipu, uint32_t ch)
+{
+ int32_t sub_ch = 0;
+
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 149, 1, 1);
+
+ sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+ if (sub_ch <= 0)
+ return;
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 149, 1, 1);
+};
+
+static inline void _ipu_ch_param_set_alpha_buffer_memory(struct ipu_soc *ipu, uint32_t ch)
+{
+ int alp_mem_idx;
+ int32_t sub_ch = 0;
+
+ switch (ch) {
+ case 14: /* PRP graphic */
+ alp_mem_idx = 0;
+ break;
+ case 15: /* PP graphic */
+ alp_mem_idx = 1;
+ break;
+ case 23: /* DP BG SYNC graphic */
+ alp_mem_idx = 4;
+ break;
+ case 27: /* DP FG SYNC graphic */
+ alp_mem_idx = 2;
+ break;
+ default:
+ dev_err(ipu->dev, "unsupported correlative channel of local "
+ "alpha channel\n");
+ return;
+ }
+
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 90, 3, alp_mem_idx);
+
+ sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+ if (sub_ch <= 0)
+ return;
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 90, 3, alp_mem_idx);
+};
+
+static inline void _ipu_ch_param_set_interlaced_scan(struct ipu_soc *ipu, uint32_t ch)
+{
+ u32 stride;
+ int32_t sub_ch = 0;
+
+ sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+
+ ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), 0, 113, 1, 1);
+ if (sub_ch > 0)
+ ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 113, 1, 1);
+ stride = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14) + 1;
+ /* ILO is 20-bit and 8-byte aligned */
+ if (stride/8 > 0xfffff)
+ dev_warn(ipu->dev,
+ "IDMAC%d's ILO exceeds IPU limitation\n", ch);
+ if (stride%8)
+ dev_warn(ipu->dev,
+ "IDMAC%d's ILO is not 8-byte aligned\n", ch);
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 58, 20, stride / 8);
+ if (sub_ch > 0)
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 58, 20,
+ stride / 8);
+ stride *= 2;
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14, stride - 1);
+ if (sub_ch > 0)
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 102, 14,
+ stride - 1);
+};
+
+static inline void _ipu_ch_param_set_axi_id(struct ipu_soc *ipu, uint32_t ch, uint32_t id)
+{
+ int32_t sub_ch = 0;
+
+ id %= 4;
+
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 93, 2, id);
+
+ sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+ if (sub_ch <= 0)
+ return;
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 93, 2, id);
+};
+
+static inline int _ipu_ch_param_get_axi_id(struct ipu_soc *ipu, uint32_t ch)
+{
+ return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 93, 2);
+}
+
+static inline int __ipu_ch_offset_calc(uint32_t pixel_fmt,
+ uint32_t width,
+ uint32_t height,
+ uint32_t stride,
+ uint32_t u,
+ uint32_t v,
+ uint32_t uv_stride,
+ uint32_t vertical_offset,
+ uint32_t horizontal_offset,
+ uint32_t *u_offset,
+ uint32_t *v_offset)
+{
+ uint32_t u_fix = 0;
+ uint32_t v_fix = 0;
+
+ switch (pixel_fmt) {
+ case IPU_PIX_FMT_GENERIC:
+ case IPU_PIX_FMT_GENERIC_16:
+ case IPU_PIX_FMT_GENERIC_32:
+ case IPU_PIX_FMT_RGB565:
+ case IPU_PIX_FMT_BGR24:
+ case IPU_PIX_FMT_RGB24:
+ case IPU_PIX_FMT_YUV444:
+ case IPU_PIX_FMT_BGRA32:
+ case IPU_PIX_FMT_BGR32:
+ case IPU_PIX_FMT_RGBA32:
+ case IPU_PIX_FMT_RGB32:
+ case IPU_PIX_FMT_ABGR32:
+ case IPU_PIX_FMT_UYVY:
+ case IPU_PIX_FMT_YUYV:
+ case IPU_PIX_FMT_GPU32_SB_ST:
+ case IPU_PIX_FMT_GPU32_SB_SRT:
+ case IPU_PIX_FMT_GPU32_ST:
+ case IPU_PIX_FMT_GPU32_SRT:
+ case IPU_PIX_FMT_GPU16_SB_ST:
+ case IPU_PIX_FMT_GPU16_SB_SRT:
+ case IPU_PIX_FMT_GPU16_ST:
+ case IPU_PIX_FMT_GPU16_SRT:
+ *u_offset = 0;
+ *v_offset = 0;
+ break;
+ case IPU_PIX_FMT_YUV420P2:
+ case IPU_PIX_FMT_YUV420P:
+ if (uv_stride < stride / 2)
+ uv_stride = stride / 2;
+
+ *u_offset = stride * (height - vertical_offset - 1) +
+ (stride - horizontal_offset) +
+ (uv_stride * vertical_offset / 2) +
+ horizontal_offset / 2;
+ *v_offset = *u_offset + (uv_stride * height / 2);
+ u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
+ (horizontal_offset / 2) -
+ (stride * vertical_offset) - (horizontal_offset)) :
+ *u_offset;
+ v_fix = v ? (v + (uv_stride * vertical_offset / 2) +
+ (horizontal_offset / 2) -
+ (stride * vertical_offset) - (horizontal_offset)) :
+ *v_offset;
+ break;
+ case IPU_PIX_FMT_YVU420P:
+ if (uv_stride < stride / 2)
+ uv_stride = stride / 2;
+
+ *v_offset = stride * (height - vertical_offset - 1) +
+ (stride - horizontal_offset) +
+ (uv_stride * vertical_offset / 2) +
+ horizontal_offset / 2;
+ *u_offset = *v_offset + (uv_stride * height / 2);
+ u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
+ (horizontal_offset / 2) -
+ (stride * vertical_offset) - (horizontal_offset)) :
+ *u_offset;
+ v_fix = v ? (v + (uv_stride * vertical_offset / 2) +
+ (horizontal_offset / 2) -
+ (stride * vertical_offset) - (horizontal_offset)) :
+ *v_offset;
+ break;
+ case IPU_PIX_FMT_YVU422P:
+ if (uv_stride < stride / 2)
+ uv_stride = stride / 2;
+
+ *v_offset = stride * (height - vertical_offset - 1) +
+ (stride - horizontal_offset) +
+ (uv_stride * vertical_offset) +
+ horizontal_offset / 2;
+ *u_offset = *v_offset + uv_stride * height;
+ u_fix = u ? (u + (uv_stride * vertical_offset) +
+ horizontal_offset / 2 -
+ (stride * vertical_offset) - (horizontal_offset)) :
+ *u_offset;
+ v_fix = v ? (v + (uv_stride * vertical_offset) +
+ horizontal_offset / 2 -
+ (stride * vertical_offset) - (horizontal_offset)) :
+ *v_offset;
+ break;
+ case IPU_PIX_FMT_YUV422P:
+ if (uv_stride < stride / 2)
+ uv_stride = stride / 2;
+
+ *u_offset = stride * (height - vertical_offset - 1) +
+ (stride - horizontal_offset) +
+ (uv_stride * vertical_offset) +
+ horizontal_offset / 2;
+ *v_offset = *u_offset + uv_stride * height;
+ u_fix = u ? (u + (uv_stride * vertical_offset) +
+ horizontal_offset / 2 -
+ (stride * vertical_offset) - (horizontal_offset)) :
+ *u_offset;
+ v_fix = v ? (v + (uv_stride * vertical_offset) +
+ horizontal_offset / 2 -
+ (stride * vertical_offset) - (horizontal_offset)) :
+ *v_offset;
+ break;
+ case IPU_PIX_FMT_YUV444P:
+ uv_stride = stride;
+ *u_offset = stride * (height - vertical_offset - 1) +
+ (stride - horizontal_offset) +
+ (uv_stride * vertical_offset) +
+ horizontal_offset;
+ *v_offset = *u_offset + uv_stride * height;
+ u_fix = u ? (u + (uv_stride * vertical_offset) +
+ horizontal_offset -
+ (stride * vertical_offset) -
+ (horizontal_offset)) :
+ *u_offset;
+ v_fix = v ? (v + (uv_stride * vertical_offset) +
+ horizontal_offset -
+ (stride * vertical_offset) -
+ (horizontal_offset)) :
+ *v_offset;
+ break;
+ case IPU_PIX_FMT_NV12:
+ case IPU_PIX_FMT_NV16:
+ case PRE_PIX_FMT_NV21:
+ case PRE_PIX_FMT_NV61:
+ uv_stride = stride;
+ *u_offset = stride * (height - vertical_offset - 1) +
+ (stride - horizontal_offset) +
+ (uv_stride * vertical_offset / 2) +
+ horizontal_offset;
+ *v_offset = 0;
+ u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
+ horizontal_offset -
+ (stride * vertical_offset) - (horizontal_offset)) :
+ *u_offset;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (u_fix > *u_offset)
+ *u_offset = u_fix;
+
+ if (v_fix > *v_offset)
+ *v_offset = v_fix;
+
+ return 0;
+}
+
+/* IDMAC U/V offset changing support */
+/* U and V input is not affected, */
+/* the update is done by new calculation according to */
+/* vertical_offset and horizontal_offset */
+static inline void _ipu_ch_offset_update(struct ipu_soc *ipu,
+ int ch,
+ uint32_t pixel_fmt,
+ uint32_t width,
+ uint32_t height,
+ uint32_t stride,
+ uint32_t u,
+ uint32_t v,
+ uint32_t uv_stride,
+ uint32_t vertical_offset,
+ uint32_t horizontal_offset)
+{
+ uint32_t u_offset = 0;
+ uint32_t v_offset = 0;
+ uint32_t old_offset = 0;
+ int32_t sub_ch = 0;
+ int ret;
+
+ ret = __ipu_ch_offset_calc(pixel_fmt, width, height, stride,
+ u, v, uv_stride,
+ vertical_offset, horizontal_offset,
+ &u_offset, &v_offset);
+ if (ret) {
+ dev_err(ipu->dev, "mxc ipu: unimplemented pixel format\n");
+ return;
+ }
+
+ /* UBO and VBO are 22-bit and 8-byte aligned */
+ if (u_offset/8 > 0x3fffff)
+ dev_warn(ipu->dev,
+ "IDMAC%d's U offset exceeds IPU limitation\n", ch);
+ if (v_offset/8 > 0x3fffff)
+ dev_warn(ipu->dev,
+ "IDMAC%d's V offset exceeds IPU limitation\n", ch);
+ if (u_offset%8)
+ dev_warn(ipu->dev,
+ "IDMAC%d's U offset is not 8-byte aligned\n", ch);
+ if (v_offset%8)
+ dev_warn(ipu->dev,
+ "IDMAC%d's V offset is not 8-byte aligned\n", ch);
+
+ old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22);
+ if (old_offset != u_offset / 8)
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22, u_offset / 8);
+ old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22);
+ if (old_offset != v_offset / 8)
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22, v_offset / 8);
+
+ sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+ if (sub_ch <= 0)
+ return;
+ old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22);
+ if (old_offset != u_offset / 8)
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22, u_offset / 8);
+ old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22);
+ if (old_offset != v_offset / 8)
+ ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22, v_offset / 8);
+};
+
+static inline void _ipu_ch_params_set_alpha_width(struct ipu_soc *ipu, uint32_t ch, int alpha_width)
+{
+ int32_t sub_ch = 0;
+
+ ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), 1, 125, 3, alpha_width - 1);
+
+ sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+ if (sub_ch <= 0)
+ return;
+ ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 125, 3, alpha_width - 1);
+};
+
+static inline void _ipu_ch_param_set_bandmode(struct ipu_soc *ipu,
+ uint32_t ch, uint32_t band_height)
+{
+ int32_t sub_ch = 0;
+
+ ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch),
+ 0, 114, 3, band_height - 1);
+ sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+ if (sub_ch <= 0)
+ return;
+ ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch),
+ 0, 114, 3, band_height - 1);
+
+ dev_dbg(ipu->dev, "BNDM 0x%x, ",
+ ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 114, 3));
+}
+
+/*
+ * The IPUv3 IDMAC has a bug to read 32bpp pixels from a graphics plane
+ * whose alpha component is at the most significant 8 bits. The bug only
+ * impacts on cases in which the relevant separate alpha channel is enabled.
+ *
+ * Return true on bad alpha component position, otherwise, return false.
+ */
+static inline bool _ipu_ch_param_bad_alpha_pos(uint32_t pixel_fmt)
+{
+ switch (pixel_fmt) {
+ case IPU_PIX_FMT_BGRA32:
+ case IPU_PIX_FMT_BGR32:
+ case IPU_PIX_FMT_RGBA32:
+ case IPU_PIX_FMT_RGB32:
+ return true;
+ }
+
+ return false;
+}
+#endif
diff --git a/drivers/mxc/ipu3/ipu_pixel_clk.c b/drivers/mxc/ipu3/ipu_pixel_clk.c
new file mode 100644
index 000000000000..66e73dd6284f
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_pixel_clk.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file ipu_pixel_clk.c
+ *
+ * @brief IPU pixel clock implementation
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "ipu_prv.h"
+#include "ipu_regs.h"
+
+ /*
+ * muxd clock implementation
+ */
+struct clk_di_mux {
+ struct clk_hw hw;
+ u8 ipu_id;
+ u8 di_id;
+ u8 flags;
+ u8 index;
+};
+#define to_clk_di_mux(_hw) container_of(_hw, struct clk_di_mux, hw)
+
+static int _ipu_pixel_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_di_mux *mux = to_clk_di_mux(hw);
+ struct ipu_soc *ipu = ipu_get_soc(mux->ipu_id);
+ u32 di_gen;
+
+ di_gen = ipu_di_read(ipu, mux->di_id, DI_GENERAL);
+ if (index == 0)
+ /* ipu1_clk or ipu2_clk internal clk */
+ di_gen &= ~DI_GEN_DI_CLK_EXT;
+ else
+ di_gen |= DI_GEN_DI_CLK_EXT;
+
+ ipu_di_write(ipu, mux->di_id, di_gen, DI_GENERAL);
+ mux->index = index;
+ pr_debug("ipu_pixel_clk: di_clk_ext:0x%x, di_gen reg:0x%x.\n",
+ !(di_gen & DI_GEN_DI_CLK_EXT), di_gen);
+ return 0;
+}
+
+static u8 _ipu_pixel_clk_get_parent(struct clk_hw *hw)
+{
+ struct clk_di_mux *mux = to_clk_di_mux(hw);
+
+ return mux->index;
+}
+
+const struct clk_ops clk_mux_di_ops = {
+ .get_parent = _ipu_pixel_clk_get_parent,
+ .set_parent = _ipu_pixel_clk_set_parent,
+};
+
+struct clk *clk_register_mux_pix_clk(struct device *dev, const char *name,
+ const char **parent_names, u8 num_parents, unsigned long flags,
+ u8 ipu_id, u8 di_id, u8 clk_mux_flags)
+{
+ struct clk_di_mux *mux;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ mux = kzalloc(sizeof(struct clk_di_mux), GFP_KERNEL);
+ if (!mux)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &clk_mux_di_ops;
+ init.flags = flags;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+
+ mux->ipu_id = ipu_id;
+ mux->di_id = di_id;
+ mux->flags = clk_mux_flags | CLK_SET_RATE_PARENT;
+ mux->hw.init = &init;
+
+ clk = clk_register(dev, &mux->hw);
+ if (IS_ERR(clk))
+ kfree(mux);
+
+ return clk;
+}
+
+/*
+ * Gated clock implementation
+ */
+struct clk_di_div {
+ struct clk_hw hw;
+ u8 ipu_id;
+ u8 di_id;
+ u8 flags;
+};
+#define to_clk_di_div(_hw) container_of(_hw, struct clk_di_div, hw)
+
+static unsigned long _ipu_pixel_clk_div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_di_div *di_div = to_clk_di_div(hw);
+ struct ipu_soc *ipu = ipu_get_soc(di_div->ipu_id);
+ u32 div;
+ u64 final_rate = (unsigned long long)parent_rate * 16;
+
+ _ipu_get(ipu);
+ div = ipu_di_read(ipu, di_div->di_id, DI_BS_CLKGEN0);
+ _ipu_put(ipu);
+ pr_debug("ipu_di%d read BS_CLKGEN0 div:%d, final_rate:%lld, prate:%ld\n",
+ di_div->di_id, div, final_rate, parent_rate);
+
+ if (div == 0)
+ return 0;
+ do_div(final_rate, div);
+
+ return (unsigned long)final_rate;
+}
+
+static long _ipu_pixel_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_clk_rate)
+{
+ u64 div, final_rate;
+ u32 remainder;
+ u64 parent_rate = (unsigned long long)(*parent_clk_rate) * 16;
+
+ /*
+ * Calculate divider
+ * Fractional part is 4 bits,
+ * so simply multiply by 2^4 to get fractional part.
+ */
+ div = parent_rate;
+ remainder = do_div(div, rate);
+ /* Round the divider value */
+ if (remainder > (rate/2))
+ div++;
+ if (div < 0x10) /* Min DI disp clock divider is 1 */
+ div = 0x10;
+ if (div & ~0xFEF)
+ div &= 0xFF8;
+ else {
+ /* Round up divider if it gets us closer to desired pix clk */
+ if ((div & 0xC) == 0xC) {
+ div += 0x10;
+ div &= ~0xF;
+ }
+ }
+ final_rate = parent_rate;
+ do_div(final_rate, div);
+
+ return final_rate;
+}
+
+static int _ipu_pixel_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_clk_rate)
+{
+ struct clk_di_div *di_div = to_clk_di_div(hw);
+ struct ipu_soc *ipu = ipu_get_soc(di_div->ipu_id);
+ u64 div, parent_rate;
+ u32 remainder;
+
+ parent_rate = (unsigned long long)parent_clk_rate * 16;
+ div = parent_rate;
+ remainder = do_div(div, rate);
+ /* Round the divider value */
+ if (remainder > (rate/2))
+ div++;
+
+ /* Round up divider if it gets us closer to desired pix clk */
+ if ((div & 0xC) == 0xC) {
+ div += 0x10;
+ div &= ~0xF;
+ }
+ if (div > 0x1000)
+ pr_err("Overflow, di:%d, DI_BS_CLKGEN0 div:0x%x\n",
+ di_div->di_id, (u32)div);
+ _ipu_get(ipu);
+ ipu_di_write(ipu, di_div->di_id, (u32)div, DI_BS_CLKGEN0);
+
+ /* Setup pixel clock timing */
+ /* FIXME: needs to be more flexible */
+ /* Down time is half of period */
+ ipu_di_write(ipu, di_div->di_id, ((u32)div / 16) << 16, DI_BS_CLKGEN1);
+ _ipu_put(ipu);
+
+ return 0;
+}
+
+static struct clk_ops clk_div_ops = {
+ .recalc_rate = _ipu_pixel_clk_div_recalc_rate,
+ .round_rate = _ipu_pixel_clk_div_round_rate,
+ .set_rate = _ipu_pixel_clk_div_set_rate,
+};
+
+struct clk *clk_register_div_pix_clk(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ u8 ipu_id, u8 di_id, u8 clk_div_flags)
+{
+ struct clk_di_div *di_div;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ di_div = kzalloc(sizeof(struct clk_di_div), GFP_KERNEL);
+ if (!di_div)
+ return ERR_PTR(-ENOMEM);
+
+ /* struct clk_di_div assignments */
+ di_div->ipu_id = ipu_id;
+ di_div->di_id = di_id;
+ di_div->flags = clk_div_flags;
+
+ init.name = name;
+ init.ops = &clk_div_ops;
+ init.flags = flags | CLK_SET_RATE_PARENT;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ init.num_parents = parent_name ? 1 : 0;
+
+ di_div->hw.init = &init;
+
+ clk = clk_register(dev, &di_div->hw);
+ if (IS_ERR(clk))
+ kfree(di_div);
+
+ return clk;
+}
+
+/*
+ * Gated clock implementation
+ */
+struct clk_di_gate {
+ struct clk_hw hw;
+ u8 ipu_id;
+ u8 di_id;
+ u8 flags;
+};
+#define to_clk_di_gate(_hw) container_of(_hw, struct clk_di_gate, hw)
+
+static int _ipu_pixel_clk_enable(struct clk_hw *hw)
+{
+ struct clk_di_gate *gate = to_clk_di_gate(hw);
+ struct ipu_soc *ipu = ipu_get_soc(gate->ipu_id);
+ u32 disp_gen;
+
+ disp_gen = ipu_cm_read(ipu, IPU_DISP_GEN);
+ disp_gen |= gate->di_id ? DI1_COUNTER_RELEASE : DI0_COUNTER_RELEASE;
+ ipu_cm_write(ipu, disp_gen, IPU_DISP_GEN);
+
+ return 0;
+}
+
+static void _ipu_pixel_clk_disable(struct clk_hw *hw)
+{
+ struct clk_di_gate *gate = to_clk_di_gate(hw);
+ struct ipu_soc *ipu = ipu_get_soc(gate->ipu_id);
+ u32 disp_gen;
+
+ disp_gen = ipu_cm_read(ipu, IPU_DISP_GEN);
+ disp_gen &= gate->di_id ? ~DI1_COUNTER_RELEASE : ~DI0_COUNTER_RELEASE;
+ ipu_cm_write(ipu, disp_gen, IPU_DISP_GEN);
+
+}
+
+
+static struct clk_ops clk_gate_di_ops = {
+ .enable = _ipu_pixel_clk_enable,
+ .disable = _ipu_pixel_clk_disable,
+};
+
+struct clk *clk_register_gate_pix_clk(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ u8 ipu_id, u8 di_id, u8 clk_gate_flags)
+{
+ struct clk_di_gate *gate;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ gate = kzalloc(sizeof(struct clk_di_gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ gate->ipu_id = ipu_id;
+ gate->di_id = di_id;
+ gate->flags = clk_gate_flags;
+
+ init.name = name;
+ init.ops = &clk_gate_di_ops;
+ init.flags = flags | CLK_SET_RATE_PARENT;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ init.num_parents = parent_name ? 1 : 0;
+
+ gate->hw.init = &init;
+
+ clk = clk_register(dev, &gate->hw);
+ if (IS_ERR(clk))
+ kfree(gate);
+
+ return clk;
+}
diff --git a/drivers/mxc/ipu3/ipu_prv.h b/drivers/mxc/ipu3/ipu_prv.h
new file mode 100644
index 000000000000..0a21d922c127
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_prv.h
@@ -0,0 +1,369 @@
+/*
+ * Copyright 2005-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __INCLUDE_IPU_PRV_H__
+#define __INCLUDE_IPU_PRV_H__
+
+#include <linux/clkdev.h>
+#include <linux/device.h>
+#include <linux/fsl_devices.h>
+#include <linux/interrupt.h>
+#include <linux/ipu-v3.h>
+#include <linux/types.h>
+
+#define MXC_IPU_MAX_NUM 2
+#define MXC_DI_NUM_PER_IPU 2
+
+/* Globals */
+extern int dmfc_type_setup;
+
+#define IDMA_CHAN_INVALID 0xFF
+#define HIGH_RESOLUTION_WIDTH 1024
+
+enum ipuv3_type {
+ IPUv3D, /* i.MX37 */
+ IPUv3EX, /* i.MX51 */
+ IPUv3M, /* i.MX53 */
+ IPUv3H, /* i.MX6Q/SDL */
+};
+
+#define IPU_MAX_VDI_IN_WIDTH(type) ({ (type) >= IPUv3M ? 968 : 720; })
+
+struct ipu_irq_node {
+ irqreturn_t(*handler) (int, void *); /*!< the ISR */
+ const char *name; /*!< device associated with the interrupt */
+ void *dev_id; /*!< some unique information for the ISR */
+ __u32 flags; /*!< not used */
+};
+
+enum csc_type_t {
+ RGB2YUV = 0,
+ YUV2RGB,
+ RGB2RGB,
+ YUV2YUV,
+ CSC_NONE,
+ CSC_NUM
+};
+
+struct ipu_soc {
+ unsigned int id;
+ unsigned int devtype;
+ bool online;
+
+ /*clk*/
+ struct clk *ipu_clk;
+ struct clk *di_clk[2];
+ struct clk *di_clk_sel[2];
+ struct clk *pixel_clk[2];
+ bool pixel_clk_en[2];
+ struct clk *pixel_clk_sel[2];
+ struct clk *csi_clk[2];
+ struct clk *prg_clk;
+
+ /*irq*/
+ int irq_sync;
+ int irq_err;
+ struct ipu_irq_node irq_list[IPU_IRQ_COUNT];
+
+ /*reg*/
+ void __iomem *cm_reg;
+ void __iomem *idmac_reg;
+ void __iomem *dp_reg;
+ void __iomem *ic_reg;
+ void __iomem *dc_reg;
+ void __iomem *dc_tmpl_reg;
+ void __iomem *dmfc_reg;
+ void __iomem *di_reg[2];
+ void __iomem *smfc_reg;
+ void __iomem *csi_reg[2];
+ void __iomem *cpmem_base;
+ void __iomem *tpmem_base;
+ void __iomem *vdi_reg;
+
+ struct device *dev;
+
+ ipu_channel_t csi_channel[2];
+ ipu_channel_t using_ic_dirct_ch;
+ unsigned char dc_di_assignment[10];
+ bool sec_chan_en[IPU_MAX_CH];
+ bool thrd_chan_en[IPU_MAX_CH];
+ bool chan_is_interlaced[52];
+ uint32_t channel_init_mask;
+ uint32_t channel_enable_mask;
+
+ /*use count*/
+ int dc_use_count;
+ int dp_use_count;
+ int dmfc_use_count;
+ int smfc_use_count;
+ int ic_use_count;
+ int rot_use_count;
+ int vdi_use_count;
+ int di_use_count[2];
+ int csi_use_count[2];
+
+ struct mutex mutex_lock;
+ spinlock_t int_reg_spin_lock;
+ spinlock_t rdy_reg_spin_lock;
+
+ int dmfc_size_28;
+ int dmfc_size_29;
+ int dmfc_size_24;
+ int dmfc_size_27;
+ int dmfc_size_23;
+
+ enum csc_type_t fg_csc_type;
+ enum csc_type_t bg_csc_type;
+ bool color_key_4rgb;
+ bool dc_swap;
+ struct completion dc_comp;
+ struct completion csi_comp;
+
+ struct rot_mem {
+ void *vaddr;
+ dma_addr_t paddr;
+ int size;
+ } rot_dma[2];
+
+ int vdoa_en;
+ struct task_struct *thread[2];
+
+ /*
+ * Bypass reset to avoid display channel being
+ * stopped by probe since it may starts to work
+ * in bootloader.
+ */
+ bool bypass_reset;
+
+ unsigned int ch0123_axi;
+ unsigned int ch23_axi;
+ unsigned int ch27_axi;
+ unsigned int ch28_axi;
+ unsigned int normal_axi;
+
+ bool smfc_idmac_12bit_3planar_bs_fixup; /* workaround little stripes */
+};
+
+struct ipu_channel {
+ u8 video_in_dma;
+ u8 alpha_in_dma;
+ u8 graph_in_dma;
+ u8 out_dma;
+};
+
+enum ipu_dmfc_type {
+ DMFC_NORMAL = 0,
+ DMFC_HIGH_RESOLUTION_DC,
+ DMFC_HIGH_RESOLUTION_DP,
+ DMFC_HIGH_RESOLUTION_ONLY_DP,
+};
+
+static inline int _ipu_is_smfc_chan(uint32_t dma_chan)
+{
+ return dma_chan <= 3;
+}
+
+static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
+{
+ return readl(ipu->cm_reg + offset);
+}
+
+static inline void ipu_cm_write(struct ipu_soc *ipu,
+ u32 value, unsigned offset)
+{
+ writel(value, ipu->cm_reg + offset);
+}
+
+static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
+{
+ return readl(ipu->idmac_reg + offset);
+}
+
+static inline void ipu_idmac_write(struct ipu_soc *ipu,
+ u32 value, unsigned offset)
+{
+ writel(value, ipu->idmac_reg + offset);
+}
+
+static inline u32 ipu_dc_read(struct ipu_soc *ipu, unsigned offset)
+{
+ return readl(ipu->dc_reg + offset);
+}
+
+static inline void ipu_dc_write(struct ipu_soc *ipu,
+ u32 value, unsigned offset)
+{
+ writel(value, ipu->dc_reg + offset);
+}
+
+static inline u32 ipu_dc_tmpl_read(struct ipu_soc *ipu, unsigned offset)
+{
+ return readl(ipu->dc_tmpl_reg + offset);
+}
+
+static inline void ipu_dc_tmpl_write(struct ipu_soc *ipu,
+ u32 value, unsigned offset)
+{
+ writel(value, ipu->dc_tmpl_reg + offset);
+}
+
+static inline u32 ipu_dmfc_read(struct ipu_soc *ipu, unsigned offset)
+{
+ return readl(ipu->dmfc_reg + offset);
+}
+
+static inline void ipu_dmfc_write(struct ipu_soc *ipu,
+ u32 value, unsigned offset)
+{
+ writel(value, ipu->dmfc_reg + offset);
+}
+
+static inline u32 ipu_dp_read(struct ipu_soc *ipu, unsigned offset)
+{
+ return readl(ipu->dp_reg + offset);
+}
+
+static inline void ipu_dp_write(struct ipu_soc *ipu,
+ u32 value, unsigned offset)
+{
+ writel(value, ipu->dp_reg + offset);
+}
+
+static inline u32 ipu_di_read(struct ipu_soc *ipu, int di, unsigned offset)
+{
+ return readl(ipu->di_reg[di] + offset);
+}
+
+static inline void ipu_di_write(struct ipu_soc *ipu, int di,
+ u32 value, unsigned offset)
+{
+ writel(value, ipu->di_reg[di] + offset);
+}
+
+static inline u32 ipu_csi_read(struct ipu_soc *ipu, int csi, unsigned offset)
+{
+ return readl(ipu->csi_reg[csi] + offset);
+}
+
+static inline void ipu_csi_write(struct ipu_soc *ipu, int csi,
+ u32 value, unsigned offset)
+{
+ writel(value, ipu->csi_reg[csi] + offset);
+}
+
+static inline u32 ipu_smfc_read(struct ipu_soc *ipu, unsigned offset)
+{
+ return readl(ipu->smfc_reg + offset);
+}
+
+static inline void ipu_smfc_write(struct ipu_soc *ipu,
+ u32 value, unsigned offset)
+{
+ writel(value, ipu->smfc_reg + offset);
+}
+
+static inline u32 ipu_vdi_read(struct ipu_soc *ipu, unsigned offset)
+{
+ return readl(ipu->vdi_reg + offset);
+}
+
+static inline void ipu_vdi_write(struct ipu_soc *ipu,
+ u32 value, unsigned offset)
+{
+ writel(value, ipu->vdi_reg + offset);
+}
+
+static inline u32 ipu_ic_read(struct ipu_soc *ipu, unsigned offset)
+{
+ return readl(ipu->ic_reg + offset);
+}
+
+static inline void ipu_ic_write(struct ipu_soc *ipu,
+ u32 value, unsigned offset)
+{
+ writel(value, ipu->ic_reg + offset);
+}
+
+int register_ipu_device(struct ipu_soc *ipu, int id);
+void unregister_ipu_device(struct ipu_soc *ipu, int id);
+ipu_color_space_t format_to_colorspace(uint32_t fmt);
+bool ipu_pixel_format_has_alpha(uint32_t fmt);
+
+void ipu_dump_registers(struct ipu_soc *ipu);
+
+uint32_t _ipu_channel_status(struct ipu_soc *ipu, ipu_channel_t channel);
+
+void ipu_disp_init(struct ipu_soc *ipu);
+void _ipu_init_dc_mappings(struct ipu_soc *ipu);
+int _ipu_dp_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t in_pixel_fmt,
+ uint32_t out_pixel_fmt);
+void _ipu_dp_uninit(struct ipu_soc *ipu, ipu_channel_t channel);
+void _ipu_dc_init(struct ipu_soc *ipu, int dc_chan, int di, bool interlaced, uint32_t pixel_fmt);
+void _ipu_dc_uninit(struct ipu_soc *ipu, int dc_chan);
+void _ipu_dp_dc_enable(struct ipu_soc *ipu, ipu_channel_t channel);
+void _ipu_dp_dc_disable(struct ipu_soc *ipu, ipu_channel_t channel, bool swap);
+void _ipu_dmfc_init(struct ipu_soc *ipu, int dmfc_type, int first);
+void _ipu_dmfc_set_wait4eot(struct ipu_soc *ipu, int dma_chan, int width);
+void _ipu_dmfc_set_burst_size(struct ipu_soc *ipu, int dma_chan, int burst_size);
+int _ipu_disp_chan_is_interlaced(struct ipu_soc *ipu, ipu_channel_t channel);
+
+void _ipu_ic_enable_task(struct ipu_soc *ipu, ipu_channel_t channel);
+void _ipu_ic_disable_task(struct ipu_soc *ipu, ipu_channel_t channel);
+int _ipu_ic_init_prpvf(struct ipu_soc *ipu, ipu_channel_params_t *params,
+ bool src_is_csi);
+void _ipu_vdi_init(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params);
+void _ipu_vdi_uninit(struct ipu_soc *ipu);
+void _ipu_ic_uninit_prpvf(struct ipu_soc *ipu);
+void _ipu_ic_init_rotate_vf(struct ipu_soc *ipu, ipu_channel_params_t *params);
+void _ipu_ic_uninit_rotate_vf(struct ipu_soc *ipu);
+void _ipu_ic_init_csi(struct ipu_soc *ipu, ipu_channel_params_t *params);
+void _ipu_ic_uninit_csi(struct ipu_soc *ipu);
+int _ipu_ic_init_prpenc(struct ipu_soc *ipu, ipu_channel_params_t *params,
+ bool src_is_csi);
+void _ipu_ic_uninit_prpenc(struct ipu_soc *ipu);
+void _ipu_ic_init_rotate_enc(struct ipu_soc *ipu, ipu_channel_params_t *params);
+void _ipu_ic_uninit_rotate_enc(struct ipu_soc *ipu);
+int _ipu_ic_init_pp(struct ipu_soc *ipu, ipu_channel_params_t *params);
+void _ipu_ic_uninit_pp(struct ipu_soc *ipu);
+void _ipu_ic_init_rotate_pp(struct ipu_soc *ipu, ipu_channel_params_t *params);
+void _ipu_ic_uninit_rotate_pp(struct ipu_soc *ipu);
+int _ipu_ic_idma_init(struct ipu_soc *ipu, int dma_chan, uint16_t width, uint16_t height,
+ int burst_size, ipu_rotate_mode_t rot);
+void _ipu_vdi_toggle_top_field_man(struct ipu_soc *ipu);
+int _ipu_csi_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t csi);
+int _ipu_csi_set_mipi_di(struct ipu_soc *ipu, uint32_t num, uint32_t di_val, uint32_t csi);
+void ipu_csi_set_test_generator(struct ipu_soc *ipu, bool active, uint32_t r_value,
+ uint32_t g_value, uint32_t b_value,
+ uint32_t pix_clk, uint32_t csi);
+void _ipu_csi_ccir_err_detection_enable(struct ipu_soc *ipu, uint32_t csi);
+void _ipu_csi_ccir_err_detection_disable(struct ipu_soc *ipu, uint32_t csi);
+void _ipu_csi_wait4eof(struct ipu_soc *ipu, ipu_channel_t channel);
+void _ipu_smfc_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t mipi_id, uint32_t csi);
+void _ipu_smfc_set_burst_size(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t bs);
+void _ipu_dp_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_t param[][3]);
+int32_t _ipu_disp_set_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+ int16_t x_pos, int16_t y_pos);
+int32_t _ipu_disp_get_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+ int16_t *x_pos, int16_t *y_pos);
+void _ipu_get(struct ipu_soc *ipu);
+void _ipu_put(struct ipu_soc *ipu);
+
+struct clk *clk_register_mux_pix_clk(struct device *dev, const char *name,
+ const char **parent_names, u8 num_parents, unsigned long flags,
+ u8 ipu_id, u8 di_id, u8 clk_mux_flags);
+struct clk *clk_register_div_pix_clk(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ u8 ipu_id, u8 di_id, u8 clk_div_flags);
+struct clk *clk_register_gate_pix_clk(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ u8 ipu_id, u8 di_id, u8 clk_gate_flags);
+#endif /* __INCLUDE_IPU_PRV_H__ */
diff --git a/drivers/mxc/ipu3/ipu_regs.h b/drivers/mxc/ipu3/ipu_regs.h
new file mode 100644
index 000000000000..099346da3e1b
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_regs.h
@@ -0,0 +1,702 @@
+/*
+ * Copyright (C) 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ * @file ipu_regs.h
+ *
+ * @brief IPU Register definitions
+ *
+ * @ingroup IPU
+ */
+#ifndef __IPU_REGS_INCLUDED__
+#define __IPU_REGS_INCLUDED__
+
+#include "ipu_prv.h"
+
+#define IPU_MCU_T_DEFAULT 8
+
+/* Register addresses */
+/* IPU Common registers */
+#define IPU_CM_REG(offset) (offset)
+
+#define IPU_CONF IPU_CM_REG(0)
+#define IPU_SRM_PRI1 IPU_CM_REG(0x00A0)
+#define IPU_SRM_PRI2 IPU_CM_REG(0x00A4)
+#define IPU_FS_PROC_FLOW1 IPU_CM_REG(0x00A8)
+#define IPU_FS_PROC_FLOW2 IPU_CM_REG(0x00AC)
+#define IPU_FS_PROC_FLOW3 IPU_CM_REG(0x00B0)
+#define IPU_FS_DISP_FLOW1 IPU_CM_REG(0x00B4)
+#define IPU_FS_DISP_FLOW2 IPU_CM_REG(0x00B8)
+#define IPU_SKIP IPU_CM_REG(0x00BC)
+#define IPU_DISP_ALT_CONF IPU_CM_REG(0x00C0)
+#define IPU_DISP_GEN IPU_CM_REG(0x00C4)
+#define IPU_DISP_ALT1 IPU_CM_REG(0x00C8)
+#define IPU_DISP_ALT2 IPU_CM_REG(0x00CC)
+#define IPU_DISP_ALT3 IPU_CM_REG(0x00D0)
+#define IPU_DISP_ALT4 IPU_CM_REG(0x00D4)
+#define IPU_SNOOP IPU_CM_REG(0x00D8)
+#define IPU_MEM_RST IPU_CM_REG(0x00DC)
+#define IPU_PM IPU_CM_REG(0x00E0)
+#define IPU_GPR IPU_CM_REG(0x00E4)
+#define IPU_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
+/*
+ * IPUv3D doesn't support triple buffer, so point
+ * IPU_CHA_TRB_MODE_SEL, IPU_CHA_TRIPLE_CUR_BUF and
+ * IPU_CHA_BUF2_RDY to readonly
+ * IPU_ALT_CUR_BUF0 for IPUv3D.
+ */
+#define IPU_CHA_TRB_MODE_SEL(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
+ (0x0178 + 4 * ((ch) / 32)) : \
+ (0x012C); })
+#define IPU_CHA_TRIPLE_CUR_BUF(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
+ (0x0258 + \
+ 4 * (((ch) * 2) / 32)) : \
+ (0x012C); })
+#define IPU_CHA_BUF2_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
+ (0x0288 + 4 * ((ch) / 32)) : \
+ (0x012C); })
+#define IPU_CHA_CUR_BUF(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
+ (0x023C + 4 * ((ch) / 32)) : \
+ (0x0124 + 4 * ((ch) / 32)); })
+#define IPU_ALT_CUR_BUF0(type) IPU_CM_REG({(type) >= IPUv3EX ? \
+ (0x0244) : \
+ (0x012C); })
+#define IPU_ALT_CUR_BUF1(type) IPU_CM_REG({(type) >= IPUv3EX ? \
+ (0x0248) : \
+ (0x0130); })
+#define IPU_SRM_STAT(type) IPU_CM_REG({(type) >= IPUv3EX ? \
+ (0x024C) : \
+ (0x0134); })
+#define IPU_PROC_TASK_STAT(type) IPU_CM_REG({(type) >= IPUv3EX ? \
+ (0x0250) : \
+ (0x0138); })
+#define IPU_DISP_TASK_STAT(type) IPU_CM_REG({(type) >= IPUv3EX ? \
+ (0x0254) : \
+ (0x013C); })
+#define IPU_CHA_BUF0_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
+ (0x0268 + 4 * ((ch) / 32)) : \
+ (0x0140 + 4 * ((ch) / 32)); })
+#define IPU_CHA_BUF1_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
+ (0x0270 + 4 * ((ch) / 32)) : \
+ (0x0148 + 4 * ((ch) / 32)); })
+#define IPU_ALT_CHA_BUF0_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
+ (0x0278 + 4 * ((ch) / 32)) : \
+ (0x0158 + 4 * ((ch) / 32)); })
+#define IPU_ALT_CHA_BUF1_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
+ (0x0280 + 4 * ((ch) / 32)) : \
+ (0x0160 + 4 * ((ch) / 32)); })
+
+#define IPU_INT_CTRL(n) IPU_CM_REG(0x003C + 4 * ((n) - 1))
+#define IPU_INT_STAT(type, n) IPU_CM_REG({(type) >= IPUv3EX ? \
+ (0x0200 + 4 * ((n) - 1)) : \
+ (0x00E8 + 4 * ((n) - 1)); })
+
+#define IPUIRQ_2_STATREG(type, irq) IPU_CM_REG(IPU_INT_STAT((type), 1) + 4 \
+ * ((irq) / 32))
+#define IPUIRQ_2_CTRLREG(irq) IPU_CM_REG(IPU_INT_CTRL(1) + 4 * ((irq) / 32))
+#define IPUIRQ_2_MASK(irq) (1UL << ((irq) & 0x1F))
+
+/* IPU VDI registers */
+#define IPU_VDI_REG(offset) (offset)
+
+#define VDI_FSIZE IPU_VDI_REG(0)
+#define VDI_C IPU_VDI_REG(0x0004)
+
+/* IPU CSI Registers */
+#define IPU_CSI_REG(offset) (offset)
+
+#define CSI_SENS_CONF IPU_CSI_REG(0)
+#define CSI_SENS_FRM_SIZE IPU_CSI_REG(0x0004)
+#define CSI_ACT_FRM_SIZE IPU_CSI_REG(0x0008)
+#define CSI_OUT_FRM_CTRL IPU_CSI_REG(0x000C)
+#define CSI_TST_CTRL IPU_CSI_REG(0x0010)
+#define CSI_CCIR_CODE_1 IPU_CSI_REG(0x0014)
+#define CSI_CCIR_CODE_2 IPU_CSI_REG(0x0018)
+#define CSI_CCIR_CODE_3 IPU_CSI_REG(0x001C)
+#define CSI_MIPI_DI IPU_CSI_REG(0x0020)
+#define CSI_SKIP IPU_CSI_REG(0x0024)
+#define CSI_CPD_CTRL IPU_CSI_REG(0x0028)
+#define CSI_CPD_RC(n) IPU_CSI_REG(0x002C + 4 * (n))
+#define CSI_CPD_RS(n) IPU_CSI_REG(0x004C + 4 * (n))
+#define CSI_CPD_GRC(n) IPU_CSI_REG(0x005C + 4 * (n))
+#define CSI_CPD_GRS(n) IPU_CSI_REG(0x007C + 4 * (n))
+#define CSI_CPD_GBC(n) IPU_CSI_REG(0x008C + 4 * (n))
+#define CSI_CPD_GBS(n) IPU_CSI_REG(0x00AC + 4 * (n))
+#define CSI_CPD_BC(n) IPU_CSI_REG(0x00BC + 4 * (n))
+#define CSI_CPD_BS(n) IPU_CSI_REG(0x00DC + 4 * (n))
+#define CSI_CPD_OFFSET1 IPU_CSI_REG(0x00EC)
+#define CSI_CPD_OFFSET2 IPU_CSI_REG(0x00F0)
+
+/* IPU SMFC Registers */
+#define IPU_SMFC_REG(offset) (offset)
+
+#define SMFC_MAP IPU_SMFC_REG(0)
+#define SMFC_WMC IPU_SMFC_REG(0x0004)
+#define SMFC_BS IPU_SMFC_REG(0x0008)
+
+/* IPU IC Registers */
+#define IPU_IC_REG(offset) (offset)
+
+#define IC_CONF IPU_IC_REG(0)
+#define IC_PRP_ENC_RSC IPU_IC_REG(0x0004)
+#define IC_PRP_VF_RSC IPU_IC_REG(0x0008)
+#define IC_PP_RSC IPU_IC_REG(0x000C)
+#define IC_CMBP_1 IPU_IC_REG(0x0010)
+#define IC_CMBP_2 IPU_IC_REG(0x0014)
+#define IC_IDMAC_1 IPU_IC_REG(0x0018)
+#define IC_IDMAC_2 IPU_IC_REG(0x001C)
+#define IC_IDMAC_3 IPU_IC_REG(0x0020)
+#define IC_IDMAC_4 IPU_IC_REG(0x0024)
+
+/* IPU IDMAC Registers */
+#define IPU_IDMAC_REG(offset) (offset)
+
+#define IDMAC_CONF IPU_IDMAC_REG(0x0000)
+#define IDMAC_CHA_EN(ch) IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
+#define IDMAC_SEP_ALPHA IPU_IDMAC_REG(0x000C)
+#define IDMAC_ALT_SEP_ALPHA IPU_IDMAC_REG(0x0010)
+#define IDMAC_CHA_PRI(ch) IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
+#define IDMAC_WM_EN(ch) IPU_IDMAC_REG(0x001C + 4 * ((ch) / 32))
+#define IDMAC_CH_LOCK_EN_1(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+ (0x0024) : 0; })
+#define IDMAC_CH_LOCK_EN_2(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+ (0x0028) : \
+ (0x0024); })
+#define IDMAC_SUB_ADDR_0(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+ (0x002C) : \
+ (0x0028); })
+#define IDMAC_SUB_ADDR_1(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+ (0x0030) : \
+ (0x002C); })
+#define IDMAC_SUB_ADDR_2(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+ (0x0034) : \
+ (0x0030); })
+/*
+ * IPUv3D doesn't support IDMAC_SUB_ADDR_3 and IDMAC_SUB_ADDR_4,
+ * so point them to readonly IDMAC_CHA_BUSY1 for IPUv3D.
+ */
+#define IDMAC_SUB_ADDR_3(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+ (0x0038) : \
+ (0x0040); })
+#define IDMAC_SUB_ADDR_4(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+ (0x003C) : \
+ (0x0040); })
+#define IDMAC_BAND_EN(type, ch) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+ (0x0040 + 4 * ((ch) / 32)) : \
+ (0x0034 + 4 * ((ch) / 32)); })
+#define IDMAC_CHA_BUSY(type, ch) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
+ (0x0100 + 4 * ((ch) / 32)) : \
+ (0x0040 + 4 * ((ch) / 32)); })
+
+/* IPU DI Registers */
+#define IPU_DI_REG(offset) (offset)
+
+#define DI_GENERAL IPU_DI_REG(0)
+#define DI_BS_CLKGEN0 IPU_DI_REG(0x0004)
+#define DI_BS_CLKGEN1 IPU_DI_REG(0x0008)
+#define DI_SW_GEN0(gen) IPU_DI_REG(0x000C + 4 * ((gen) - 1))
+#define DI_SW_GEN1(gen) IPU_DI_REG(0x0030 + 4 * ((gen) - 1))
+#define DI_STP_REP(gen) IPU_DI_REG(0x0148 + 4 * (((gen) - 1) / 2))
+#define DI_SYNC_AS_GEN IPU_DI_REG(0x0054)
+#define DI_DW_GEN(gen) IPU_DI_REG(0x0058 + 4 * (gen))
+#define DI_DW_SET(gen, set) IPU_DI_REG(0x0088 + 4 * ((gen) + 0xC * (set)))
+#define DI_SER_CONF IPU_DI_REG(0x015C)
+#define DI_SSC IPU_DI_REG(0x0160)
+#define DI_POL IPU_DI_REG(0x0164)
+#define DI_AW0 IPU_DI_REG(0x0168)
+#define DI_AW1 IPU_DI_REG(0x016C)
+#define DI_SCR_CONF IPU_DI_REG(0x0170)
+#define DI_STAT IPU_DI_REG(0x0174)
+
+/* IPU DMFC Registers */
+#define IPU_DMFC_REG(offset) (offset)
+
+#define DMFC_RD_CHAN IPU_DMFC_REG(0)
+#define DMFC_WR_CHAN IPU_DMFC_REG(0x0004)
+#define DMFC_WR_CHAN_DEF IPU_DMFC_REG(0x0008)
+#define DMFC_DP_CHAN IPU_DMFC_REG(0x000C)
+#define DMFC_DP_CHAN_DEF IPU_DMFC_REG(0x0010)
+#define DMFC_GENERAL1 IPU_DMFC_REG(0x0014)
+#define DMFC_GENERAL2 IPU_DMFC_REG(0x0018)
+#define DMFC_IC_CTRL IPU_DMFC_REG(0x001C)
+#define DMFC_STAT IPU_DMFC_REG(0x0020)
+
+/* IPU DC Registers */
+#define IPU_DC_REG(offset) (offset)
+
+#define DC_MAP_CONF_PTR(n) IPU_DC_REG(0x0108 + ((n) & ~0x1) * 2)
+#define DC_MAP_CONF_VAL(n) IPU_DC_REG(0x0144 + ((n) & ~0x1) * 2)
+
+#define _RL_CH_2_OFFSET(ch) (((ch) == 0) ? 8 : ( \
+ ((ch) == 1) ? 0x24 : ( \
+ ((ch) == 2) ? 0x40 : ( \
+ ((ch) == 5) ? 0x64 : ( \
+ ((ch) == 6) ? 0x80 : ( \
+ ((ch) == 8) ? 0x9C : ( \
+ ((ch) == 9) ? 0xBC : (-1))))))))
+#define DC_RL_CH(ch, evt) IPU_DC_REG(_RL_CH_2_OFFSET(ch) + \
+ ((evt) & ~0x1) * 2)
+
+#define DC_EVT_NF 0
+#define DC_EVT_NL 1
+#define DC_EVT_EOF 2
+#define DC_EVT_NFIELD 3
+#define DC_EVT_EOL 4
+#define DC_EVT_EOFIELD 5
+#define DC_EVT_NEW_ADDR 6
+#define DC_EVT_NEW_CHAN 7
+#define DC_EVT_NEW_DATA 8
+
+#define DC_EVT_NEW_ADDR_W_0 0
+#define DC_EVT_NEW_ADDR_W_1 1
+#define DC_EVT_NEW_CHAN_W_0 2
+#define DC_EVT_NEW_CHAN_W_1 3
+#define DC_EVT_NEW_DATA_W_0 4
+#define DC_EVT_NEW_DATA_W_1 5
+#define DC_EVT_NEW_ADDR_R_0 6
+#define DC_EVT_NEW_ADDR_R_1 7
+#define DC_EVT_NEW_CHAN_R_0 8
+#define DC_EVT_NEW_CHAN_R_1 9
+#define DC_EVT_NEW_DATA_R_0 10
+#define DC_EVT_NEW_DATA_R_1 11
+#define DC_EVEN_UGDE0 12
+#define DC_ODD_UGDE0 13
+#define DC_EVEN_UGDE1 14
+#define DC_ODD_UGDE1 15
+#define DC_EVEN_UGDE2 16
+#define DC_ODD_UGDE2 17
+#define DC_EVEN_UGDE3 18
+#define DC_ODD_UGDE3 19
+
+#define dc_ch_offset(ch) \
+({ \
+ const u8 _offset[] = { \
+ 0, 0x1C, 0x38, 0x54, 0x58, 0x5C, 0x78, 0, 0x94, 0xB4}; \
+ _offset[ch]; \
+})
+#define DC_WR_CH_CONF(ch) IPU_DC_REG(dc_ch_offset(ch))
+#define DC_WR_CH_ADDR(ch) IPU_DC_REG(dc_ch_offset(ch) + 4)
+
+#define DC_WR_CH_CONF_1 IPU_DC_REG(0x001C)
+#define DC_WR_CH_ADDR_1 IPU_DC_REG(0x0020)
+#define DC_WR_CH_CONF_5 IPU_DC_REG(0x005C)
+#define DC_WR_CH_ADDR_5 IPU_DC_REG(0x0060)
+#define DC_GEN IPU_DC_REG(0x00D4)
+#define DC_DISP_CONF1(disp) IPU_DC_REG(0x00D8 + 4 * (disp))
+#define DC_DISP_CONF2(disp) IPU_DC_REG(0x00E8 + 4 * (disp))
+#define DC_STAT IPU_DC_REG(0x01C8)
+#define DC_UGDE_0(evt) IPU_DC_REG(0x0174 + 16 * (evt))
+#define DC_UGDE_1(evt) IPU_DC_REG(0x0178 + 16 * (evt))
+#define DC_UGDE_2(evt) IPU_DC_REG(0x017C + 16 * (evt))
+#define DC_UGDE_3(evt) IPU_DC_REG(0x0180 + 16 * (evt))
+
+/* IPU DP Registers */
+#define IPU_DP_REG(offset) (offset)
+
+#define DP_SYNC 0
+#define DP_ASYNC0 0x60
+#define DP_ASYNC1 0xBC
+#define DP_COM_CONF(flow) IPU_DP_REG(flow)
+#define DP_GRAPH_WIND_CTRL(flow) IPU_DP_REG(0x0004 + (flow))
+#define DP_FG_POS(flow) IPU_DP_REG(0x0008 + (flow))
+#define DP_GAMMA_C(flow, i) IPU_DP_REG(0x0014 + (flow) + 4 * (i))
+#define DP_GAMMA_S(flow, i) IPU_DP_REG(0x0034 + (flow) + 4 * (i))
+#define DP_CSC_A_0(flow) IPU_DP_REG(0x0044 + (flow))
+#define DP_CSC_A_1(flow) IPU_DP_REG(0x0048 + (flow))
+#define DP_CSC_A_2(flow) IPU_DP_REG(0x004C + (flow))
+#define DP_CSC_A_3(flow) IPU_DP_REG(0x0050 + (flow))
+#define DP_CSC_0(flow) IPU_DP_REG(0x0054 + (flow))
+#define DP_CSC_1(flow) IPU_DP_REG(0x0058 + (flow))
+
+enum {
+ IPU_CONF_CSI0_EN = 0x00000001,
+ IPU_CONF_CSI1_EN = 0x00000002,
+ IPU_CONF_IC_EN = 0x00000004,
+ IPU_CONF_ROT_EN = 0x00000008,
+ IPU_CONF_ISP_EN = 0x00000010,
+ IPU_CONF_DP_EN = 0x00000020,
+ IPU_CONF_DI0_EN = 0x00000040,
+ IPU_CONF_DI1_EN = 0x00000080,
+ IPU_CONF_DMFC_EN = 0x00000400,
+ IPU_CONF_SMFC_EN = 0x00000100,
+ IPU_CONF_DC_EN = 0x00000200,
+ IPU_CONF_VDI_EN = 0x00001000,
+ IPU_CONF_IDMAC_DIS = 0x00400000,
+ IPU_CONF_IC_DMFC_SEL = 0x02000000,
+ IPU_CONF_IC_DMFC_SYNC = 0x04000000,
+ IPU_CONF_VDI_DMFC_SYNC = 0x08000000,
+ IPU_CONF_CSI0_DATA_SOURCE = 0x10000000,
+ IPU_CONF_CSI0_DATA_SOURCE_OFFSET = 28,
+ IPU_CONF_CSI1_DATA_SOURCE = 0x20000000,
+ IPU_CONF_IC_INPUT = 0x40000000,
+ IPU_CONF_CSI_SEL = 0x80000000,
+
+ DI0_COUNTER_RELEASE = 0x01000000,
+ DI1_COUNTER_RELEASE = 0x02000000,
+
+ FS_PRPVF_ROT_SRC_SEL_MASK = 0x00000F00,
+ FS_PRPVF_ROT_SRC_SEL_OFFSET = 8,
+ FS_PRPENC_ROT_SRC_SEL_MASK = 0x0000000F,
+ FS_PRPENC_ROT_SRC_SEL_OFFSET = 0,
+ FS_PP_ROT_SRC_SEL_MASK = 0x000F0000,
+ FS_PP_ROT_SRC_SEL_OFFSET = 16,
+ FS_PP_SRC_SEL_MASK = 0x0000F000,
+ FS_PP_SRC_SEL_VDOA = 0x00008000,
+ FS_PP_SRC_SEL_OFFSET = 12,
+ FS_PRP_SRC_SEL_MASK = 0x0F000000,
+ FS_PRP_SRC_SEL_OFFSET = 24,
+ FS_VF_IN_VALID = 0x80000000,
+ FS_ENC_IN_VALID = 0x40000000,
+ FS_VDI_SRC_SEL_MASK = 0x30000000,
+ FS_VDI_SRC_SEL_VDOA = 0x20000000,
+ FS_VDOA_DEST_SEL_MASK = 0x00030000,
+ FS_VDOA_DEST_SEL_VDI = 0x00020000,
+ FS_VDOA_DEST_SEL_IC = 0x00010000,
+ FS_VDI_SRC_SEL_OFFSET = 28,
+
+
+ FS_PRPENC_DEST_SEL_MASK = 0x0000000F,
+ FS_PRPENC_DEST_SEL_OFFSET = 0,
+ FS_PRPVF_DEST_SEL_MASK = 0x000000F0,
+ FS_PRPVF_DEST_SEL_OFFSET = 4,
+ FS_PRPVF_ROT_DEST_SEL_MASK = 0x00000F00,
+ FS_PRPVF_ROT_DEST_SEL_OFFSET = 8,
+ FS_PP_DEST_SEL_MASK = 0x0000F000,
+ FS_PP_DEST_SEL_OFFSET = 12,
+ FS_PP_ROT_DEST_SEL_MASK = 0x000F0000,
+ FS_PP_ROT_DEST_SEL_OFFSET = 16,
+ FS_PRPENC_ROT_DEST_SEL_MASK = 0x00F00000,
+ FS_PRPENC_ROT_DEST_SEL_OFFSET = 20,
+
+ FS_SMFC0_DEST_SEL_MASK = 0x0000000F,
+ FS_SMFC0_DEST_SEL_OFFSET = 0,
+ FS_SMFC1_DEST_SEL_MASK = 0x00000070,
+ FS_SMFC1_DEST_SEL_OFFSET = 4,
+ FS_SMFC2_DEST_SEL_MASK = 0x00000780,
+ FS_SMFC2_DEST_SEL_OFFSET = 7,
+ FS_SMFC3_DEST_SEL_MASK = 0x00003800,
+ FS_SMFC3_DEST_SEL_OFFSET = 11,
+
+ FS_DC1_SRC_SEL_MASK = 0x00F00000,
+ FS_DC1_SRC_SEL_OFFSET = 20,
+ FS_DC2_SRC_SEL_MASK = 0x000F0000,
+ FS_DC2_SRC_SEL_OFFSET = 16,
+ FS_DP_SYNC0_SRC_SEL_MASK = 0x0000000F,
+ FS_DP_SYNC0_SRC_SEL_OFFSET = 0,
+ FS_DP_SYNC1_SRC_SEL_MASK = 0x000000F0,
+ FS_DP_SYNC1_SRC_SEL_OFFSET = 4,
+ FS_DP_ASYNC0_SRC_SEL_MASK = 0x00000F00,
+ FS_DP_ASYNC0_SRC_SEL_OFFSET = 8,
+ FS_DP_ASYNC1_SRC_SEL_MASK = 0x0000F000,
+ FS_DP_ASYNC1_SRC_SEL_OFFSET = 12,
+
+ FS_AUTO_REF_PER_MASK = 0,
+ FS_AUTO_REF_PER_OFFSET = 16,
+
+ TSTAT_VF_MASK = 0x0000000C,
+ TSTAT_VF_OFFSET = 2,
+ TSTAT_VF_ROT_MASK = 0x00000300,
+ TSTAT_VF_ROT_OFFSET = 8,
+ TSTAT_ENC_MASK = 0x00000003,
+ TSTAT_ENC_OFFSET = 0,
+ TSTAT_ENC_ROT_MASK = 0x000000C0,
+ TSTAT_ENC_ROT_OFFSET = 6,
+ TSTAT_PP_MASK = 0x00000030,
+ TSTAT_PP_OFFSET = 4,
+ TSTAT_PP_ROT_MASK = 0x00000C00,
+ TSTAT_PP_ROT_OFFSET = 10,
+
+ TASK_STAT_IDLE = 0,
+ TASK_STAT_ACTIVE = 1,
+ TASK_STAT_WAIT4READY = 2,
+
+ /* IDMAC register bits */
+ IDMAC_CONF_USED_BUFS_EN_R = 0x02000000,
+ IDMAC_CONF_USED_BUFS_MAX_R_MASK = 0x01E00000,
+ IDMAC_CONF_USED_BUFS_MAX_R_OFFSET = 21,
+ IDMAC_CONF_USED_BUFS_EN_W = 0x00100000,
+ IDMAC_CONF_USED_BUFS_MAX_W_MASK = 0x000E0000,
+ IDMAC_CONF_USED_BUFS_MAX_W_OFFSET = 17,
+
+ /* Image Converter Register bits */
+ IC_CONF_PRPENC_EN = 0x00000001,
+ IC_CONF_PRPENC_CSC1 = 0x00000002,
+ IC_CONF_PRPENC_ROT_EN = 0x00000004,
+ IC_CONF_PRPVF_EN = 0x00000100,
+ IC_CONF_PRPVF_CSC1 = 0x00000200,
+ IC_CONF_PRPVF_CSC2 = 0x00000400,
+ IC_CONF_PRPVF_CMB = 0x00000800,
+ IC_CONF_PRPVF_ROT_EN = 0x00001000,
+ IC_CONF_PP_EN = 0x00010000,
+ IC_CONF_PP_CSC1 = 0x00020000,
+ IC_CONF_PP_CSC2 = 0x00040000,
+ IC_CONF_PP_CMB = 0x00080000,
+ IC_CONF_PP_ROT_EN = 0x00100000,
+ IC_CONF_IC_GLB_LOC_A = 0x10000000,
+ IC_CONF_KEY_COLOR_EN = 0x20000000,
+ IC_CONF_RWS_EN = 0x40000000,
+ IC_CONF_CSI_MEM_WR_EN = 0x80000000,
+
+ IC_RSZ_MAX_RESIZE_RATIO = 0x00004000,
+
+ IC_IDMAC_1_CB0_BURST_16 = 0x00000001,
+ IC_IDMAC_1_CB1_BURST_16 = 0x00000002,
+ IC_IDMAC_1_CB2_BURST_16 = 0x00000004,
+ IC_IDMAC_1_CB3_BURST_16 = 0x00000008,
+ IC_IDMAC_1_CB4_BURST_16 = 0x00000010,
+ IC_IDMAC_1_CB5_BURST_16 = 0x00000020,
+ IC_IDMAC_1_CB6_BURST_16 = 0x00000040,
+ IC_IDMAC_1_CB7_BURST_16 = 0x00000080,
+ IC_IDMAC_1_PRPENC_ROT_MASK = 0x00003800,
+ IC_IDMAC_1_PRPENC_ROT_OFFSET = 11,
+ IC_IDMAC_1_PRPVF_ROT_MASK = 0x0001C000,
+ IC_IDMAC_1_PRPVF_ROT_OFFSET = 14,
+ IC_IDMAC_1_PP_ROT_MASK = 0x000E0000,
+ IC_IDMAC_1_PP_ROT_OFFSET = 17,
+ IC_IDMAC_1_PP_FLIP_RS = 0x00400000,
+ IC_IDMAC_1_PRPVF_FLIP_RS = 0x00200000,
+ IC_IDMAC_1_PRPENC_FLIP_RS = 0x00100000,
+
+ IC_IDMAC_2_PRPENC_HEIGHT_MASK = 0x000003FF,
+ IC_IDMAC_2_PRPENC_HEIGHT_OFFSET = 0,
+ IC_IDMAC_2_PRPVF_HEIGHT_MASK = 0x000FFC00,
+ IC_IDMAC_2_PRPVF_HEIGHT_OFFSET = 10,
+ IC_IDMAC_2_PP_HEIGHT_MASK = 0x3FF00000,
+ IC_IDMAC_2_PP_HEIGHT_OFFSET = 20,
+
+ IC_IDMAC_3_PRPENC_WIDTH_MASK = 0x000003FF,
+ IC_IDMAC_3_PRPENC_WIDTH_OFFSET = 0,
+ IC_IDMAC_3_PRPVF_WIDTH_MASK = 0x000FFC00,
+ IC_IDMAC_3_PRPVF_WIDTH_OFFSET = 10,
+ IC_IDMAC_3_PP_WIDTH_MASK = 0x3FF00000,
+ IC_IDMAC_3_PP_WIDTH_OFFSET = 20,
+
+ CSI_SENS_CONF_DATA_FMT_SHIFT = 8,
+ CSI_SENS_CONF_DATA_FMT_MASK = 0x00000700,
+ CSI_SENS_CONF_DATA_FMT_RGB_YUV444 = 0L,
+ CSI_SENS_CONF_DATA_FMT_YUV422_YUYV = 1L,
+ CSI_SENS_CONF_DATA_FMT_YUV422_UYVY = 2L,
+ CSI_SENS_CONF_DATA_FMT_BAYER = 3L,
+ CSI_SENS_CONF_DATA_FMT_RGB565 = 4L,
+ CSI_SENS_CONF_DATA_FMT_RGB555 = 5L,
+ CSI_SENS_CONF_DATA_FMT_RGB444 = 6L,
+ CSI_SENS_CONF_DATA_FMT_JPEG = 7L,
+
+ CSI_SENS_CONF_VSYNC_POL_SHIFT = 0,
+ CSI_SENS_CONF_HSYNC_POL_SHIFT = 1,
+ CSI_SENS_CONF_DATA_POL_SHIFT = 2,
+ CSI_SENS_CONF_PIX_CLK_POL_SHIFT = 3,
+ CSI_SENS_CONF_SENS_PRTCL_MASK = 0x00000070L,
+ CSI_SENS_CONF_SENS_PRTCL_SHIFT = 4,
+ CSI_SENS_CONF_PACK_TIGHT_SHIFT = 7,
+ CSI_SENS_CONF_DATA_WIDTH_SHIFT = 11,
+ CSI_SENS_CONF_EXT_VSYNC_SHIFT = 15,
+ CSI_SENS_CONF_DIVRATIO_SHIFT = 16,
+
+ CSI_SENS_CONF_DIVRATIO_MASK = 0x00FF0000L,
+ CSI_SENS_CONF_DATA_DEST_SHIFT = 24,
+ CSI_SENS_CONF_DATA_DEST_MASK = 0x07000000L,
+ CSI_SENS_CONF_JPEG8_EN_SHIFT = 27,
+ CSI_SENS_CONF_JPEG_EN_SHIFT = 28,
+ CSI_SENS_CONF_FORCE_EOF_SHIFT = 29,
+ CSI_SENS_CONF_DATA_EN_POL_SHIFT = 31,
+
+ CSI_DATA_DEST_ISP = 1L,
+ CSI_DATA_DEST_IC = 2L,
+ CSI_DATA_DEST_IDMAC = 4L,
+
+ CSI_CCIR_ERR_DET_EN = 0x01000000L,
+ CSI_HORI_DOWNSIZE_EN = 0x80000000L,
+ CSI_VERT_DOWNSIZE_EN = 0x40000000L,
+ CSI_TEST_GEN_MODE_EN = 0x01000000L,
+
+ CSI_HSC_MASK = 0x1FFF0000,
+ CSI_HSC_SHIFT = 16,
+ CSI_VSC_MASK = 0x00000FFF,
+ CSI_VSC_SHIFT = 0,
+
+ CSI_TEST_GEN_R_MASK = 0x000000FFL,
+ CSI_TEST_GEN_R_SHIFT = 0,
+ CSI_TEST_GEN_G_MASK = 0x0000FF00L,
+ CSI_TEST_GEN_G_SHIFT = 8,
+ CSI_TEST_GEN_B_MASK = 0x00FF0000L,
+ CSI_TEST_GEN_B_SHIFT = 16,
+
+ CSI_MIPI_DI0_MASK = 0x000000FFL,
+ CSI_MIPI_DI0_SHIFT = 0,
+ CSI_MIPI_DI1_MASK = 0x0000FF00L,
+ CSI_MIPI_DI1_SHIFT = 8,
+ CSI_MIPI_DI2_MASK = 0x00FF0000L,
+ CSI_MIPI_DI2_SHIFT = 16,
+ CSI_MIPI_DI3_MASK = 0xFF000000L,
+ CSI_MIPI_DI3_SHIFT = 24,
+
+ CSI_MAX_RATIO_SKIP_ISP_MASK = 0x00070000L,
+ CSI_MAX_RATIO_SKIP_ISP_SHIFT = 16,
+ CSI_SKIP_ISP_MASK = 0x00F80000L,
+ CSI_SKIP_ISP_SHIFT = 19,
+ CSI_MAX_RATIO_SKIP_SMFC_MASK = 0x00000007L,
+ CSI_MAX_RATIO_SKIP_SMFC_SHIFT = 0,
+ CSI_SKIP_SMFC_MASK = 0x000000F8L,
+ CSI_SKIP_SMFC_SHIFT = 3,
+ CSI_ID_2_SKIP_MASK = 0x00000300L,
+ CSI_ID_2_SKIP_SHIFT = 8,
+
+ CSI_COLOR_FIRST_ROW_MASK = 0x00000002L,
+ CSI_COLOR_FIRST_COMP_MASK = 0x00000001L,
+
+ SMFC_MAP_CH0_MASK = 0x00000007L,
+ SMFC_MAP_CH0_SHIFT = 0,
+ SMFC_MAP_CH1_MASK = 0x00000038L,
+ SMFC_MAP_CH1_SHIFT = 3,
+ SMFC_MAP_CH2_MASK = 0x000001C0L,
+ SMFC_MAP_CH2_SHIFT = 6,
+ SMFC_MAP_CH3_MASK = 0x00000E00L,
+ SMFC_MAP_CH3_SHIFT = 9,
+
+ SMFC_WM0_SET_MASK = 0x00000007L,
+ SMFC_WM0_SET_SHIFT = 0,
+ SMFC_WM1_SET_MASK = 0x000001C0L,
+ SMFC_WM1_SET_SHIFT = 6,
+ SMFC_WM2_SET_MASK = 0x00070000L,
+ SMFC_WM2_SET_SHIFT = 16,
+ SMFC_WM3_SET_MASK = 0x01C00000L,
+ SMFC_WM3_SET_SHIFT = 22,
+
+ SMFC_WM0_CLR_MASK = 0x00000038L,
+ SMFC_WM0_CLR_SHIFT = 3,
+ SMFC_WM1_CLR_MASK = 0x00000E00L,
+ SMFC_WM1_CLR_SHIFT = 9,
+ SMFC_WM2_CLR_MASK = 0x00380000L,
+ SMFC_WM2_CLR_SHIFT = 19,
+ SMFC_WM3_CLR_MASK = 0x0E000000L,
+ SMFC_WM3_CLR_SHIFT = 25,
+
+ SMFC_BS0_MASK = 0x0000000FL,
+ SMFC_BS0_SHIFT = 0,
+ SMFC_BS1_MASK = 0x000000F0L,
+ SMFC_BS1_SHIFT = 4,
+ SMFC_BS2_MASK = 0x00000F00L,
+ SMFC_BS2_SHIFT = 8,
+ SMFC_BS3_MASK = 0x0000F000L,
+ SMFC_BS3_SHIFT = 12,
+
+ PF_CONF_TYPE_MASK = 0x00000007,
+ PF_CONF_TYPE_SHIFT = 0,
+ PF_CONF_PAUSE_EN = 0x00000010,
+ PF_CONF_RESET = 0x00008000,
+ PF_CONF_PAUSE_ROW_MASK = 0x00FF0000,
+ PF_CONF_PAUSE_ROW_SHIFT = 16,
+
+ DI_DW_GEN_ACCESS_SIZE_OFFSET = 24,
+ DI_DW_GEN_COMPONENT_SIZE_OFFSET = 16,
+
+ DI_GEN_DI_CLK_EXT = 0x100000,
+ DI_GEN_POLARITY_DISP_CLK = 0x00020000,
+ DI_GEN_POLARITY_1 = 0x00000001,
+ DI_GEN_POLARITY_2 = 0x00000002,
+ DI_GEN_POLARITY_3 = 0x00000004,
+ DI_GEN_POLARITY_4 = 0x00000008,
+ DI_GEN_POLARITY_5 = 0x00000010,
+ DI_GEN_POLARITY_6 = 0x00000020,
+ DI_GEN_POLARITY_7 = 0x00000040,
+ DI_GEN_POLARITY_8 = 0x00000080,
+
+ DI_POL_DRDY_DATA_POLARITY = 0x00000080,
+ DI_POL_DRDY_POLARITY_15 = 0x00000010,
+
+ DI_VSYNC_SEL_OFFSET = 13,
+
+ DC_WR_CH_CONF_FIELD_MODE = 0x00000200,
+ DC_WR_CH_CONF_PROG_TYPE_OFFSET = 5,
+ DC_WR_CH_CONF_PROG_TYPE_MASK = 0x000000E0,
+ DC_WR_CH_CONF_PROG_DI_ID = 0x00000004,
+ DC_WR_CH_CONF_PROG_DISP_ID_OFFSET = 3,
+ DC_WR_CH_CONF_PROG_DISP_ID_MASK = 0x00000018,
+
+ DC_UGDE_0_ODD_EN = 0x02000000,
+ DC_UGDE_0_ID_CODED_MASK = 0x00000007,
+ DC_UGDE_0_ID_CODED_OFFSET = 0,
+ DC_UGDE_0_EV_PRIORITY_MASK = 0x00000078,
+ DC_UGDE_0_EV_PRIORITY_OFFSET = 3,
+
+ DP_COM_CONF_FG_EN = 0x00000001,
+ DP_COM_CONF_GWSEL = 0x00000002,
+ DP_COM_CONF_GWAM = 0x00000004,
+ DP_COM_CONF_GWCKE = 0x00000008,
+ DP_COM_CONF_CSC_DEF_MASK = 0x00000300,
+ DP_COM_CONF_CSC_DEF_OFFSET = 8,
+ DP_COM_CONF_CSC_DEF_FG = 0x00000300,
+ DP_COM_CONF_CSC_DEF_BG = 0x00000200,
+ DP_COM_CONF_CSC_DEF_BOTH = 0x00000100,
+ DP_COM_CONF_GAMMA_EN = 0x00001000,
+ DP_COM_CONF_GAMMA_YUV_EN = 0x00002000,
+
+ DI_SER_CONF_LLA_SER_ACCESS = 0x00000020,
+ DI_SER_CONF_SERIAL_CLK_POL = 0x00000010,
+ DI_SER_CONF_SERIAL_DATA_POL = 0x00000008,
+ DI_SER_CONF_SERIAL_RS_POL = 0x00000004,
+ DI_SER_CONF_SERIAL_CS_POL = 0x00000002,
+ DI_SER_CONF_WAIT4SERIAL = 0x00000001,
+
+ VDI_C_CH_420 = 0x00000000,
+ VDI_C_CH_422 = 0x00000002,
+ VDI_C_MOT_SEL_FULL = 0x00000008,
+ VDI_C_MOT_SEL_LOW = 0x00000004,
+ VDI_C_MOT_SEL_MED = 0x00000000,
+ VDI_C_BURST_SIZE1_4 = 0x00000030,
+ VDI_C_BURST_SIZE2_4 = 0x00000300,
+ VDI_C_BURST_SIZE3_4 = 0x00003000,
+ VDI_C_BURST_SIZE_MASK = 0xF,
+ VDI_C_BURST_SIZE1_OFFSET = 4,
+ VDI_C_BURST_SIZE2_OFFSET = 8,
+ VDI_C_BURST_SIZE3_OFFSET = 12,
+ VDI_C_VWM1_SET_1 = 0x00000000,
+ VDI_C_VWM1_SET_2 = 0x00010000,
+ VDI_C_VWM1_CLR_2 = 0x00080000,
+ VDI_C_VWM3_SET_1 = 0x00000000,
+ VDI_C_VWM3_SET_2 = 0x00400000,
+ VDI_C_VWM3_CLR_2 = 0x02000000,
+ VDI_C_TOP_FIELD_MAN_1 = 0x40000000,
+ VDI_C_TOP_FIELD_AUTO_1 = 0x80000000,
+};
+
+enum di_pins {
+ DI_PIN11 = 0,
+ DI_PIN12 = 1,
+ DI_PIN13 = 2,
+ DI_PIN14 = 3,
+ DI_PIN15 = 4,
+ DI_PIN16 = 5,
+ DI_PIN17 = 6,
+ DI_PIN_CS = 7,
+
+ DI_PIN_SER_CLK = 0,
+ DI_PIN_SER_RS = 1,
+};
+
+enum di_sync_wave {
+ DI_SYNC_NONE = -1,
+ DI_SYNC_CLK = 0,
+ DI_SYNC_INT_HSYNC = 1,
+ DI_SYNC_HSYNC = 2,
+ DI_SYNC_VSYNC = 3,
+ DI_SYNC_DE = 5,
+};
+
+/* DC template opcodes */
+#define WROD(lf) (0x18 | ((lf) << 1))
+#define WRG (0x01)
+
+#endif
diff --git a/drivers/mxc/ipu3/pre-regs.h b/drivers/mxc/ipu3/pre-regs.h
new file mode 100644
index 000000000000..06a9b029ce3e
--- /dev/null
+++ b/drivers/mxc/ipu3/pre-regs.h
@@ -0,0 +1,480 @@
+/*
+ * Freescale PRE Register Definitions
+ *
+ * Copyright 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __ARCH_ARM___PRE_H
+#define __ARCH_ARM___PRE_H
+
+
+#define HW_PRE_CTRL (0x00000000)
+#define HW_PRE_CTRL_SET (0x00000004)
+#define HW_PRE_CTRL_CLR (0x00000008)
+#define HW_PRE_CTRL_TOG (0x0000000c)
+
+#define BM_PRE_CTRL_SFTRST 0x80000000
+#define BF_PRE_CTRL_SFTRST(v) \
+ (((v) << 31) & BM_PRE_CTRL_SFTRST)
+#define BM_PRE_CTRL_CLKGATE 0x40000000
+#define BF_PRE_CTRL_CLKGATE(v) \
+ (((v) << 30) & BM_PRE_CTRL_CLKGATE)
+#define BM_PRE_CTRL_TPR_RESET_SEL 0x20000000
+#define BF_PRE_CTRL_TPR_RESET_SEL(v) \
+ (((v) << 29) & BM_PRE_CTRL_TPR_RESET_SEL)
+#define BM_PRE_CTRL_EN_REPEAT 0x10000000
+#define BF_PRE_CTRL_EN_REPEAT(v) \
+ (((v) << 28) & BM_PRE_CTRL_EN_REPEAT)
+#define BP_PRE_CTRL_RSVD2 16
+#define BM_PRE_CTRL_RSVD2 0x0FFF0000
+#define BF_PRE_CTRL_RSVD2(v) \
+ (((v) << 16) & BM_PRE_CTRL_RSVD2)
+#define BP_PRE_CTRL_RSVD1 12
+#define BM_PRE_CTRL_RSVD1 0x0000F000
+#define BF_PRE_CTRL_RSVD1(v) \
+ (((v) << 12) & BM_PRE_CTRL_RSVD1)
+#define BM_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN 0x00000800
+#define BF_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN(v) \
+ (((v) << 11) & BM_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN)
+#define BV_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN__0 0x0
+#define BV_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN__1 0x1
+#define BP_PRE_CTRL_HANDSHAKE_LINE_NUM 9
+#define BM_PRE_CTRL_HANDSHAKE_LINE_NUM 0x00000600
+#define BF_PRE_CTRL_HANDSHAKE_LINE_NUM(v) \
+ (((v) << 9) & BM_PRE_CTRL_HANDSHAKE_LINE_NUM)
+#define BV_PRE_CTRL_HANDSHAKE_LINE_NUM__0 0x0
+#define BV_PRE_CTRL_HANDSHAKE_LINE_NUM__1 0x1
+#define BV_PRE_CTRL_HANDSHAKE_LINE_NUM__2 0x2
+#define BM_PRE_CTRL_HANDSHAKE_EN 0x00000100
+#define BF_PRE_CTRL_HANDSHAKE_EN(v) \
+ (((v) << 8) & BM_PRE_CTRL_HANDSHAKE_EN)
+#define BV_PRE_CTRL_HANDSHAKE_EN__0 0x0
+#define BV_PRE_CTRL_HANDSHAKE_EN__1 0x1
+#define BM_PRE_CTRL_INTERLACED_FIELD 0x00000080
+#define BF_PRE_CTRL_INTERLACED_FIELD(v) \
+ (((v) << 7) & BM_PRE_CTRL_INTERLACED_FIELD)
+#define BM_PRE_CTRL_SO 0x00000040
+#define BF_PRE_CTRL_SO(v) \
+ (((v) << 6) & BM_PRE_CTRL_SO)
+#define BM_PRE_CTRL_VFLIP 0x00000020
+#define BF_PRE_CTRL_VFLIP(v) \
+ (((v) << 5) & BM_PRE_CTRL_VFLIP)
+#define BM_PRE_CTRL_SDW_UPDATE 0x00000010
+#define BF_PRE_CTRL_SDW_UPDATE(v) \
+ (((v) << 4) & BM_PRE_CTRL_SDW_UPDATE)
+#define BM_PRE_CTRL_RSVD0 0x00000008
+#define BF_PRE_CTRL_RSVD0(v) \
+ (((v) << 3) & BM_PRE_CTRL_RSVD0)
+#define BM_PRE_CTRL_BLOCK_16 0x00000004
+#define BF_PRE_CTRL_BLOCK_16(v) \
+ (((v) << 2) & BM_PRE_CTRL_BLOCK_16)
+#define BV_PRE_CTRL_BLOCK_16__32x4 0x0
+#define BV_PRE_CTRL_BLOCK_16__16x4 0x1
+#define BM_PRE_CTRL_BLOCK_EN 0x00000002
+#define BF_PRE_CTRL_BLOCK_EN(v) \
+ (((v) << 1) & BM_PRE_CTRL_BLOCK_EN)
+#define BV_PRE_CTRL_BLOCK_EN__0 0x0
+#define BV_PRE_CTRL_BLOCK_EN__1 0x1
+#define BM_PRE_CTRL_ENABLE 0x00000001
+#define BF_PRE_CTRL_ENABLE(v) \
+ (((v) << 0) & BM_PRE_CTRL_ENABLE)
+
+#define HW_PRE_IRQ_MASK (0x00000010)
+#define HW_PRE_IRQ_MASK_SET (0x00000014)
+#define HW_PRE_IRQ_MASK_CLR (0x00000018)
+#define HW_PRE_IRQ_MASK_TOG (0x0000001c)
+
+#define BP_PRE_IRQ_MASK_RSVD1 4
+#define BM_PRE_IRQ_MASK_RSVD1 0xFFFFFFF0
+#define BF_PRE_IRQ_MASK_RSVD1(v) \
+ (((v) << 4) & BM_PRE_IRQ_MASK_RSVD1)
+#define BM_PRE_IRQ_MASK_TPR_RD_NUM_BYTES_OVFL_IRQ_EN 0x00000008
+#define BF_PRE_IRQ_MASK_TPR_RD_NUM_BYTES_OVFL_IRQ_EN(v) \
+ (((v) << 3) & BM_PRE_IRQ_MASK_TPR_RD_NUM_BYTES_OVFL_IRQ_EN)
+#define BM_PRE_IRQ_MASK_HANDSHAKE_ABORT_IRQ_EN 0x00000004
+#define BF_PRE_IRQ_MASK_HANDSHAKE_ABORT_IRQ_EN(v) \
+ (((v) << 2) & BM_PRE_IRQ_MASK_HANDSHAKE_ABORT_IRQ_EN)
+#define BM_PRE_IRQ_MASK_STORE_IRQ_EN 0x00000002
+#define BF_PRE_IRQ_MASK_STORE_IRQ_EN(v) \
+ (((v) << 1) & BM_PRE_IRQ_MASK_STORE_IRQ_EN)
+#define BM_PRE_IRQ_MASK_PREFETCH_IRQ_EN 0x00000001
+#define BF_PRE_IRQ_MASK_PREFETCH_IRQ_EN(v) \
+ (((v) << 0) & BM_PRE_IRQ_MASK_PREFETCH_IRQ_EN)
+
+#define HW_PRE_IRQ (0x00000020)
+#define HW_PRE_IRQ_SET (0x00000024)
+#define HW_PRE_IRQ_CLR (0x00000028)
+#define HW_PRE_IRQ_TOG (0x0000002c)
+
+#define BP_PRE_IRQ_RSVD1 14
+#define BM_PRE_IRQ_RSVD1 0xFFFFC000
+#define BF_PRE_IRQ_RSVD1(v) \
+ (((v) << 14) & BM_PRE_IRQ_RSVD1)
+#define BP_PRE_IRQ_AXI_ERROR_ID 10
+#define BM_PRE_IRQ_AXI_ERROR_ID 0x00003C00
+#define BF_PRE_IRQ_AXI_ERROR_ID(v) \
+ (((v) << 10) & BM_PRE_IRQ_AXI_ERROR_ID)
+#define BM_PRE_IRQ_AXI_READ_ERROR 0x00000200
+#define BF_PRE_IRQ_AXI_READ_ERROR(v) \
+ (((v) << 9) & BM_PRE_IRQ_AXI_READ_ERROR)
+#define BM_PRE_IRQ_AXI_WRITE_ERROR 0x00000100
+#define BF_PRE_IRQ_AXI_WRITE_ERROR(v) \
+ (((v) << 8) & BM_PRE_IRQ_AXI_WRITE_ERROR)
+#define BP_PRE_IRQ_RSVD0 5
+#define BM_PRE_IRQ_RSVD0 0x000000E0
+#define BF_PRE_IRQ_RSVD0(v) \
+ (((v) << 5) & BM_PRE_IRQ_RSVD0)
+#define BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ 0x00000010
+#define BF_PRE_IRQ_HANDSHAKE_ERROR_IRQ(v) \
+ (((v) << 4) & BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ)
+#define BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ 0x00000008
+#define BF_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ(v) \
+ (((v) << 3) & BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ)
+#define BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ 0x00000004
+#define BF_PRE_IRQ_HANDSHAKE_ABORT_IRQ(v) \
+ (((v) << 2) & BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ)
+#define BM_PRE_IRQ_STORE_IRQ 0x00000002
+#define BF_PRE_IRQ_STORE_IRQ(v) \
+ (((v) << 1) & BM_PRE_IRQ_STORE_IRQ)
+#define BM_PRE_IRQ_PREFETCH_IRQ 0x00000001
+#define BF_PRE_IRQ_PREFETCH_IRQ(v) \
+ (((v) << 0) & BM_PRE_IRQ_PREFETCH_IRQ)
+
+#define HW_PRE_CUR_BUF (0x00000030)
+
+#define BP_PRE_CUR_BUF_ADDR 0
+#define BM_PRE_CUR_BUF_ADDR 0xFFFFFFFF
+#define BF_PRE_CUR_BUF_ADDR(v) (v)
+
+#define HW_PRE_NEXT_BUF (0x00000040)
+
+#define BP_PRE_NEXT_BUF_ADDR 0
+#define BM_PRE_NEXT_BUF_ADDR 0xFFFFFFFF
+#define BF_PRE_NEXT_BUF_ADDR(v) (v)
+
+#define HW_PRE_U_BUF_OFFSET (0x00000050)
+
+#define BP_PRE_U_BUF_OFFSET_RSVD0 25
+#define BM_PRE_U_BUF_OFFSET_RSVD0 0xFE000000
+#define BF_PRE_U_BUF_OFFSET_RSVD0(v) \
+ (((v) << 25) & BM_PRE_U_BUF_OFFSET_RSVD0)
+#define BP_PRE_U_BUF_OFFSET_UBO 0
+#define BM_PRE_U_BUF_OFFSET_UBO 0x01FFFFFF
+#define BF_PRE_U_BUF_OFFSET_UBO(v) \
+ (((v) << 0) & BM_PRE_U_BUF_OFFSET_UBO)
+
+#define HW_PRE_V_BUF_OFFSET (0x00000060)
+
+#define BP_PRE_V_BUF_OFFSET_RSVD0 25
+#define BM_PRE_V_BUF_OFFSET_RSVD0 0xFE000000
+#define BF_PRE_V_BUF_OFFSET_RSVD0(v) \
+ (((v) << 25) & BM_PRE_V_BUF_OFFSET_RSVD0)
+#define BP_PRE_V_BUF_OFFSET_VBO 0
+#define BM_PRE_V_BUF_OFFSET_VBO 0x01FFFFFF
+#define BF_PRE_V_BUF_OFFSET_VBO(v) \
+ (((v) << 0) & BM_PRE_V_BUF_OFFSET_VBO)
+
+#define HW_PRE_TPR_CTRL (0x00000070)
+#define HW_PRE_TPR_CTRL_SET (0x00000074)
+#define HW_PRE_TPR_CTRL_CLR (0x00000078)
+#define HW_PRE_TPR_CTRL_TOG (0x0000007c)
+
+#define BP_PRE_TPR_CTRL_RSVD 8
+#define BM_PRE_TPR_CTRL_RSVD 0xFFFFFF00
+#define BF_PRE_TPR_CTRL_RSVD(v) \
+ (((v) << 8) & BM_PRE_TPR_CTRL_RSVD)
+#define BP_PRE_TPR_CTRL_TILE_FORMAT 0
+#define BM_PRE_TPR_CTRL_TILE_FORMAT 0x000000FF
+#define BF_PRE_TPR_CTRL_TILE_FORMAT(v) \
+ (((v) << 0) & BM_PRE_TPR_CTRL_TILE_FORMAT)
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__BYPASS 0x00
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_SB_ST 0x10
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_SB_SRT 0x50
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_ST 0x20
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_SRT 0x60
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_MST 0xA0
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_MSRT 0xE0
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_SB_ST 0x11
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_SB_SRT 0x51
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_ST 0x21
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_SRT 0x61
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_MST 0xA1
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_MSRT 0xE1
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__VPU8_PRO 0x22
+#define BV_PRE_TPR_CTRL_TILE_FORMAT__VPU8_SB_INT 0x13
+
+#define HW_PRE_PREFETCH_ENGINE_CTRL (0x00000080)
+#define HW_PRE_PREFETCH_ENGINE_CTRL_SET (0x00000084)
+#define HW_PRE_PREFETCH_ENGINE_CTRL_CLR (0x00000088)
+#define HW_PRE_PREFETCH_ENGINE_CTRL_TOG (0x0000008c)
+
+#define BP_PRE_PREFETCH_ENGINE_CTRL_RSVD1 16
+#define BM_PRE_PREFETCH_ENGINE_CTRL_RSVD1 0xFFFF0000
+#define BF_PRE_PREFETCH_ENGINE_CTRL_RSVD1(v) \
+ (((v) << 16) & BM_PRE_PREFETCH_ENGINE_CTRL_RSVD1)
+#define BM_PRE_PREFETCH_ENGINE_CTRL_TPR_COOR_OFFSET_EN 0x00008000
+#define BF_PRE_PREFETCH_ENGINE_CTRL_TPR_COOR_OFFSET_EN(v) \
+ (((v) << 15) & BM_PRE_PREFETCH_ENGINE_CTRL_TPR_COOR_OFFSET_EN)
+#define BM_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP 0x00004000
+#define BF_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP(v) \
+ (((v) << 14) & BM_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP)
+#define BM_PRE_PREFETCH_ENGINE_CTRL_CROP_EN 0x00002000
+#define BF_PRE_PREFETCH_ENGINE_CTRL_CROP_EN(v) \
+ (((v) << 13) & BM_PRE_PREFETCH_ENGINE_CTRL_CROP_EN)
+#define BV_PRE_PREFETCH_ENGINE_CTRL_CROP_EN__0 0x0
+#define BV_PRE_PREFETCH_ENGINE_CTRL_CROP_EN__1 0x1
+#define BM_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE 0x00001000
+#define BF_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE(v) \
+ (((v) << 12) & BM_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE)
+#define BV_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE__0 0x0
+#define BV_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE__1 0x1
+#define BM_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS 0x00000800
+#define BF_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS(v) \
+ (((v) << 11) & BM_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS)
+#define BV_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS__0 0x0
+#define BV_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS__1 0x1
+#define BP_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT 8
+#define BM_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT 0x00000700
+#define BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(v) \
+ (((v) << 8) & BM_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT)
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__0 0x0
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__1 0x1
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__2 0x2
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__3 0x3
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__4 0x4
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__5 0x5
+#define BP_PRE_PREFETCH_ENGINE_CTRL_RSVD0 6
+#define BM_PRE_PREFETCH_ENGINE_CTRL_RSVD0 0x000000C0
+#define BF_PRE_PREFETCH_ENGINE_CTRL_RSVD0(v) \
+ (((v) << 6) & BM_PRE_PREFETCH_ENGINE_CTRL_RSVD0)
+#define BP_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP 4
+#define BM_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP 0x00000030
+#define BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(v) \
+ (((v) << 4) & BM_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP)
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP__0 0x0
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP__1 0x1
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP__2 0x2
+#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP__3 0x3
+#define BP_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES 1
+#define BM_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES 0x0000000E
+#define BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(v) \
+ (((v) << 1) & BM_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES)
+#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__8_bytes 0x0
+#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__16_bytes 0x1
+#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__32_bytes 0x2
+#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__64_bytes 0x3
+#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__128_bytes 0x4
+#define BM_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN 0x00000001
+#define BF_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN(v) \
+ (((v) << 0) & BM_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN)
+#define BV_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN__0 0x0
+#define BV_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN__1 0x1
+
+#define HW_PRE_PREFETCH_ENGINE_STATUS (0x00000090)
+
+#define BP_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_Y 16
+#define BM_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_Y 0x3FFF0000
+#define BF_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_Y(v) \
+ (((v) << 16) & BM_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_Y)
+#define BP_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_X 0
+#define BM_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_X 0x0000FFFF
+#define BF_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_X(v) \
+ (((v) << 0) & BM_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_X)
+
+#define HW_PRE_PREFETCH_ENGINE_INPUT_SIZE (0x000000a0)
+
+#define BP_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT 16
+#define BM_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT 0xFFFF0000
+#define BF_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT(v) \
+ (((v) << 16) & BM_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT)
+#define BP_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH 0
+#define BM_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH 0x0000FFFF
+#define BF_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH(v) \
+ (((v) << 0) & BM_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH)
+
+#define HW_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC (0x000000b0)
+
+#define BP_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y 16
+#define BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y 0xFFFF0000
+#define BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y(v) \
+ (((v) << 16) & BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y)
+#define BP_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X 0
+#define BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X 0x0000FFFF
+#define BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X(v) \
+ (((v) << 0) & BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X)
+
+#define HW_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC (0x000000c0)
+
+#define BP_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_Y 16
+#define BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_Y 0xFFFF0000
+#define BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_Y(v) \
+ (((v) << 16) & BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_Y)
+#define BP_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_X 0
+#define BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_X 0x0000FFFF
+#define BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_X(v) \
+ (((v) << 0) & BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_X)
+
+#define HW_PRE_PREFETCH_ENGINE_PITCH (0x000000d0)
+
+#define BP_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH 16
+#define BM_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH 0xFFFF0000
+#define BF_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH(v) \
+ (((v) << 16) & BM_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH)
+#define BP_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH 0
+#define BM_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH 0x0000FFFF
+#define BF_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH(v) \
+ (((v) << 0) & BM_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH)
+
+#define HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET (0x000000e0)
+#define HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_SET (0x000000e4)
+#define HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_CLR (0x000000e8)
+#define HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_TOG (0x000000ec)
+
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD0 29
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD0 0xE0000000
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD0(v) \
+ (((v) << 29) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD0)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET3 24
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET3 0x1F000000
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET3(v) \
+ (((v) << 24) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET3)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD1 21
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD1 0x00E00000
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD1(v) \
+ (((v) << 21) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD1)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET2 16
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET2 0x001F0000
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET2(v) \
+ (((v) << 16) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET2)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD2 13
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD2 0x0000E000
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD2(v) \
+ (((v) << 13) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD2)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET1 8
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET1 0x00001F00
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET1(v) \
+ (((v) << 8) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET1)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD3 5
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD3 0x000000E0
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD3(v) \
+ (((v) << 5) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD3)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET0 0
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET0 0x0000001F
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET0(v) \
+ (((v) << 0) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET0)
+
+#define HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH (0x000000f0)
+#define HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_SET (0x000000f4)
+#define HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_CLR (0x000000f8)
+#define HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_TOG (0x000000fc)
+
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_RSVD0 16
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_RSVD0 0xFFFF0000
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_RSVD0(v) \
+ (((v) << 16) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_RSVD0)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH3 12
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH3 0x0000F000
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH3(v) \
+ (((v) << 12) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH3)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH2 8
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH2 0x00000F00
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH2(v) \
+ (((v) << 8) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH2)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH1 4
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH1 0x000000F0
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH1(v) \
+ (((v) << 4) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH1)
+#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH0 0
+#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH0 0x0000000F
+#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH0(v) \
+ (((v) << 0) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH0)
+
+#define HW_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET (0x00000100)
+
+#define BP_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_RSVD0 23
+#define BM_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_RSVD0 0xFF800000
+#define BF_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_RSVD0(v) \
+ (((v) << 23) & BM_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_RSVD0)
+#define BP_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET 0
+#define BM_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET 0xFFFFFFFF
+#define BF_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET(v) \
+ (((v) << 0) & BM_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET)
+
+#define HW_PRE_STORE_ENGINE_CTRL (0x00000110)
+#define HW_PRE_STORE_ENGINE_CTRL_SET (0x00000114)
+#define HW_PRE_STORE_ENGINE_CTRL_CLR (0x00000118)
+#define HW_PRE_STORE_ENGINE_CTRL_TOG (0x0000011c)
+
+#define BP_PRE_STORE_ENGINE_CTRL_RSVD0 6
+#define BM_PRE_STORE_ENGINE_CTRL_RSVD0 0xFFFFFFC0
+#define BF_PRE_STORE_ENGINE_CTRL_RSVD0(v) \
+ (((v) << 6) & BM_PRE_STORE_ENGINE_CTRL_RSVD0)
+#define BP_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP 4
+#define BM_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP 0x00000030
+#define BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(v) \
+ (((v) << 4) & BM_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP)
+#define BV_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP__8_bits 0x0
+#define BV_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP__16_bits 0x1
+#define BV_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP__32_bits 0x2
+#define BV_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP__64_bits 0x3
+#define BP_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES 1
+#define BM_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES 0x0000000E
+#define BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(v) \
+ (((v) << 1) & BM_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES)
+#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__8_bytes 0x0
+#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__16_bytes 0x1
+#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__32_bytes 0x2
+#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__64_bytes 0x3
+#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__128_bytes 0x4
+#define BM_PRE_STORE_ENGINE_CTRL_STORE_EN 0x00000001
+#define BF_PRE_STORE_ENGINE_CTRL_STORE_EN(v) \
+ (((v) << 0) & BM_PRE_STORE_ENGINE_CTRL_STORE_EN)
+#define BV_PRE_STORE_ENGINE_CTRL_STORE_EN__0 0x0
+#define BV_PRE_STORE_ENGINE_CTRL_STORE_EN__1 0x1
+
+#define HW_PRE_STORE_ENGINE_STATUS (0x00000120)
+
+#define BP_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y 16
+#define BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y 0x3FFF0000
+#define BF_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y(v) \
+ (((v) << 16) & BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y)
+#define BP_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_X 0
+#define BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_X 0x0000FFFF
+#define BF_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_X(v) \
+ (((v) << 0) & BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_X)
+
+#define HW_PRE_STORE_ENGINE_SIZE (0x00000130)
+
+#define BP_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT 16
+#define BM_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT 0xFFFF0000
+#define BF_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT(v) \
+ (((v) << 16) & BM_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT)
+#define BP_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH 0
+#define BM_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH 0x0000FFFF
+#define BF_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH(v) \
+ (((v) << 0) & BM_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH)
+
+#define HW_PRE_STORE_ENGINE_PITCH (0x00000140)
+
+#define BP_PRE_STORE_ENGINE_PITCH_RSVD0 16
+#define BM_PRE_STORE_ENGINE_PITCH_RSVD0 0xFFFF0000
+#define BF_PRE_STORE_ENGINE_PITCH_RSVD0(v) \
+ (((v) << 16) & BM_PRE_STORE_ENGINE_PITCH_RSVD0)
+#define BP_PRE_STORE_ENGINE_PITCH_OUT_PITCH 0
+#define BM_PRE_STORE_ENGINE_PITCH_OUT_PITCH 0x0000FFFF
+#define BF_PRE_STORE_ENGINE_PITCH_OUT_PITCH(v) \
+ (((v) << 0) & BM_PRE_STORE_ENGINE_PITCH_OUT_PITCH)
+
+#define HW_PRE_STORE_ENGINE_ADDR (0x00000150)
+
+#define BP_PRE_STORE_ENGINE_ADDR_OUT_BASE_ADDR 0
+#define BM_PRE_STORE_ENGINE_ADDR_OUT_BASE_ADDR 0xFFFFFFFF
+#define BF_PRE_STORE_ENGINE_ADDR_OUT_BASE_ADDR(v) (v)
+#endif /* __ARCH_ARM___PRE_H */
diff --git a/drivers/mxc/ipu3/pre.c b/drivers/mxc/ipu3/pre.c
new file mode 100644
index 000000000000..f1ce02b3fe90
--- /dev/null
+++ b/drivers/mxc/ipu3/pre.c
@@ -0,0 +1,999 @@
+/*
+ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/clk.h>
+#include <linux/genalloc.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/ipu-v3-pre.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "pre-regs.h"
+
+struct ipu_pre_data {
+ unsigned int id;
+ struct device *dev;
+ void __iomem *base;
+ struct clk *clk;
+
+ struct mutex mutex; /* for in_use */
+ spinlock_t lock; /* for register access */
+
+ struct list_head list;
+
+ struct gen_pool *iram_pool;
+ unsigned long double_buffer_size;
+ unsigned long double_buffer_base;
+ unsigned long double_buffer_paddr;
+
+ bool in_use;
+ bool enabled;
+};
+
+static LIST_HEAD(pre_list);
+static DEFINE_SPINLOCK(pre_list_lock);
+
+static inline void pre_write(struct ipu_pre_data *pre,
+ u32 value, unsigned int offset)
+{
+ writel(value, pre->base + offset);
+}
+
+static inline u32 pre_read(struct ipu_pre_data *pre, unsigned offset)
+{
+ return readl(pre->base + offset);
+}
+
+static struct ipu_pre_data *get_pre(unsigned int id)
+{
+ struct ipu_pre_data *pre;
+ unsigned long lock_flags;
+
+ spin_lock_irqsave(&pre_list_lock, lock_flags);
+ list_for_each_entry(pre, &pre_list, list) {
+ if (pre->id == id) {
+ spin_unlock_irqrestore(&pre_list_lock, lock_flags);
+ return pre;
+ }
+ }
+ spin_unlock_irqrestore(&pre_list_lock, lock_flags);
+
+ return NULL;
+}
+
+int ipu_pre_alloc(int ipu_id, ipu_channel_t channel)
+{
+ struct ipu_pre_data *pre;
+ int i, fixed;
+
+ if (channel == MEM_BG_SYNC) {
+ fixed = ipu_id ? 3 : 0;
+ pre = get_pre(fixed);
+ if (pre) {
+ mutex_lock(&pre->mutex);
+ if (!pre->in_use) {
+ pre->in_use = true;
+ mutex_unlock(&pre->mutex);
+ return pre->id;
+ }
+ mutex_unlock(&pre->mutex);
+ }
+ return pre ? -EBUSY : -ENOENT;
+ }
+
+ for (i = 1; i < 3; i++) {
+ pre = get_pre(i);
+ if (!pre)
+ continue;
+ mutex_lock(&pre->mutex);
+ if (!pre->in_use) {
+ pre->in_use = true;
+ mutex_unlock(&pre->mutex);
+ return pre->id;
+ }
+ mutex_unlock(&pre->mutex);
+ }
+
+ return pre ? -EBUSY : -ENOENT;
+}
+EXPORT_SYMBOL(ipu_pre_alloc);
+
+void ipu_pre_free(unsigned int *id)
+{
+ struct ipu_pre_data *pre;
+
+ pre = get_pre(*id);
+ if (!pre)
+ return;
+
+ mutex_lock(&pre->mutex);
+ pre->in_use = false;
+ mutex_unlock(&pre->mutex);
+
+ *id = -1;
+}
+EXPORT_SYMBOL(ipu_pre_free);
+
+unsigned long ipu_pre_alloc_double_buffer(unsigned int id, unsigned int size)
+{
+ struct ipu_pre_data *pre = get_pre(id);
+
+ if (!pre)
+ return -ENOENT;
+
+ if (!size)
+ return -EINVAL;
+
+ pre->double_buffer_base = gen_pool_alloc(pre->iram_pool, size);
+ if (!pre->double_buffer_base) {
+ dev_err(pre->dev, "double buffer allocate failed\n");
+ return -ENOMEM;
+ }
+ pre->double_buffer_size = size;
+
+ pre->double_buffer_paddr = gen_pool_virt_to_phys(pre->iram_pool,
+ pre->double_buffer_base);
+
+ return pre->double_buffer_paddr;
+}
+EXPORT_SYMBOL(ipu_pre_alloc_double_buffer);
+
+void ipu_pre_free_double_buffer(unsigned int id)
+{
+ struct ipu_pre_data *pre = get_pre(id);
+
+ if (!pre)
+ return;
+
+ if (pre->double_buffer_base) {
+ gen_pool_free(pre->iram_pool,
+ pre->double_buffer_base,
+ pre->double_buffer_size);
+ pre->double_buffer_base = 0;
+ pre->double_buffer_size = 0;
+ pre->double_buffer_paddr = 0;
+ }
+}
+EXPORT_SYMBOL(ipu_pre_free_double_buffer);
+
+/* PRE register configurations */
+int ipu_pre_set_ctrl(unsigned int id, struct ipu_pre_context *config)
+{
+ struct ipu_pre_data *pre = get_pre(id);
+ unsigned long lock_flags;
+ int ret = 0;
+
+ if (!pre)
+ return -EINVAL;
+
+ if (!pre->enabled)
+ clk_prepare_enable(pre->clk);
+
+ spin_lock_irqsave(&pre->lock, lock_flags);
+ pre_write(pre, BF_PRE_CTRL_TPR_RESET_SEL(1), HW_PRE_CTRL_SET);
+
+ if (config->repeat)
+ pre_write(pre, BF_PRE_CTRL_EN_REPEAT(1), HW_PRE_CTRL_SET);
+ else
+ pre_write(pre, BM_PRE_CTRL_EN_REPEAT, HW_PRE_CTRL_CLR);
+
+ if (config->vflip)
+ pre_write(pre, BF_PRE_CTRL_VFLIP(1), HW_PRE_CTRL_SET);
+ else
+ pre_write(pre, BM_PRE_CTRL_VFLIP, HW_PRE_CTRL_CLR);
+
+ if (config->handshake_en) {
+ pre_write(pre, BF_PRE_CTRL_HANDSHAKE_EN(1), HW_PRE_CTRL_SET);
+ if (config->hsk_abort_en)
+ pre_write(pre, BF_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN(1),
+ HW_PRE_CTRL_SET);
+ else
+ pre_write(pre, BM_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN,
+ HW_PRE_CTRL_CLR);
+
+ switch (config->hsk_line_num) {
+ case 0 /* 4 lines */:
+ pre_write(pre, BM_PRE_CTRL_HANDSHAKE_LINE_NUM,
+ HW_PRE_CTRL_CLR);
+ break;
+ case 1 /* 8 lines */:
+ pre_write(pre, BM_PRE_CTRL_HANDSHAKE_LINE_NUM,
+ HW_PRE_CTRL_CLR);
+ pre_write(pre, BF_PRE_CTRL_HANDSHAKE_LINE_NUM(1),
+ HW_PRE_CTRL_SET);
+ break;
+ case 2 /* 16 lines */:
+ pre_write(pre, BM_PRE_CTRL_HANDSHAKE_LINE_NUM,
+ HW_PRE_CTRL_CLR);
+ pre_write(pre, BF_PRE_CTRL_HANDSHAKE_LINE_NUM(2),
+ HW_PRE_CTRL_SET);
+ break;
+ default:
+ dev_err(pre->dev, "invalid hanshake line number\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ } else
+ pre_write(pre, BM_PRE_CTRL_HANDSHAKE_EN, HW_PRE_CTRL_CLR);
+
+
+ switch (config->prefetch_mode) {
+ case 0:
+ pre_write(pre, BM_PRE_CTRL_BLOCK_EN, HW_PRE_CTRL_CLR);
+ break;
+ case 1:
+ pre_write(pre, BF_PRE_CTRL_BLOCK_EN(1), HW_PRE_CTRL_SET);
+ switch (config->block_size) {
+ case 0:
+ pre_write(pre, BM_PRE_CTRL_BLOCK_16, HW_PRE_CTRL_CLR);
+ break;
+ case 1:
+ pre_write(pre, BF_PRE_CTRL_BLOCK_16(1), HW_PRE_CTRL_SET);
+ break;
+ default:
+ dev_err(pre->dev, "invalid block size for pre\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ break;
+ default:
+ dev_err(pre->dev, "invalid prefech mode for pre\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ switch (config->interlaced) {
+ case 0: /* progressive mode */
+ pre_write(pre, BM_PRE_CTRL_SO, HW_PRE_CTRL_CLR);
+ break;
+ case 2: /* interlaced mode: Pal */
+ pre_write(pre, BF_PRE_CTRL_SO(1), HW_PRE_CTRL_SET);
+ pre_write(pre, BM_PRE_CTRL_INTERLACED_FIELD, HW_PRE_CTRL_CLR);
+ break;
+ case 3: /* interlaced mode: NTSC */
+ pre_write(pre, BF_PRE_CTRL_SO(1), HW_PRE_CTRL_SET);
+ pre_write(pre, BF_PRE_CTRL_INTERLACED_FIELD(1), HW_PRE_CTRL_SET);
+ break;
+ default:
+ dev_err(pre->dev, "invalid interlaced or progressive mode\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (config->sdw_update)
+ pre_write(pre, BF_PRE_CTRL_SDW_UPDATE(1), HW_PRE_CTRL_SET);
+ else
+ pre_write(pre, BM_PRE_CTRL_SDW_UPDATE, HW_PRE_CTRL_CLR);
+
+err:
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+ if (!pre->enabled)
+ clk_disable_unprepare(pre->clk);
+
+ return ret;
+}
+EXPORT_SYMBOL(ipu_pre_set_ctrl);
+
+static void ipu_pre_irq_mask(struct ipu_pre_data *pre,
+ unsigned long mask, bool clear)
+{
+ if (clear) {
+ pre_write(pre, mask & 0x1f, HW_PRE_IRQ_MASK_CLR);
+ return;
+ }
+ pre_write(pre, mask & 0x1f, HW_PRE_IRQ_MASK_SET);
+}
+
+static int ipu_pre_buf_set(unsigned int id, unsigned long cur_buf,
+ unsigned long next_buf)
+{
+ struct ipu_pre_data *pre = get_pre(id);
+ unsigned long lock_flags;
+
+ if (!pre)
+ return -EINVAL;
+
+ spin_lock_irqsave(&pre->lock, lock_flags);
+ pre_write(pre, cur_buf, HW_PRE_CUR_BUF);
+ pre_write(pre, next_buf, HW_PRE_NEXT_BUF);
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+ return 0;
+}
+
+static int ipu_pre_plane_buf_off_set(unsigned int id,
+ unsigned long sec_buf_off,
+ unsigned long trd_buf_off)
+{
+ struct ipu_pre_data *pre = get_pre(id);
+ unsigned long lock_flags;
+
+ if (!pre || sec_buf_off & BM_PRE_U_BUF_OFFSET_RSVD0 ||
+ trd_buf_off & BM_PRE_V_BUF_OFFSET_RSVD0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&pre->lock, lock_flags);
+ pre_write(pre, sec_buf_off, HW_PRE_U_BUF_OFFSET);
+ pre_write(pre, trd_buf_off, HW_PRE_V_BUF_OFFSET);
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+ return 0;
+}
+
+static int ipu_pre_tpr_set(unsigned int id, unsigned int tile_fmt)
+{
+ struct ipu_pre_data *pre = get_pre(id);
+ unsigned long lock_flags;
+ unsigned int tpr_ctrl, fmt;
+
+ if (!pre)
+ return -EINVAL;
+
+ switch (tile_fmt) {
+ case 0x0: /* Bypass */
+ fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x0);
+ break;
+ case IPU_PIX_FMT_GPU32_SB_ST:
+ fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x10);
+ break;
+ case IPU_PIX_FMT_GPU16_SB_ST:
+ fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x11);
+ break;
+ case IPU_PIX_FMT_GPU32_ST:
+ fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x20);
+ break;
+ case IPU_PIX_FMT_GPU16_ST:
+ fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x21);
+ break;
+ case IPU_PIX_FMT_GPU32_SB_SRT:
+ fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x50);
+ break;
+ case IPU_PIX_FMT_GPU16_SB_SRT:
+ fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x51);
+ break;
+ case IPU_PIX_FMT_GPU32_SRT:
+ fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x60);
+ break;
+ case IPU_PIX_FMT_GPU16_SRT:
+ fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x61);
+ break;
+ default:
+ dev_err(pre->dev, "invalid tile fmt for pre\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&pre->lock, lock_flags);
+ tpr_ctrl = pre_read(pre, HW_PRE_TPR_CTRL);
+ tpr_ctrl &= ~BM_PRE_TPR_CTRL_TILE_FORMAT;
+ tpr_ctrl |= fmt;
+ pre_write(pre, tpr_ctrl, HW_PRE_TPR_CTRL);
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+ return 0;
+}
+
+static int ipu_pre_set_shift(int id, unsigned int offset, unsigned int width)
+{
+ struct ipu_pre_data *pre = get_pre(id);
+ unsigned long lock_flags;
+
+ if (!pre)
+ return -EINVAL;
+
+ spin_lock_irqsave(&pre->lock, lock_flags);
+ pre_write(pre, offset, HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET);
+ pre_write(pre, width, HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH);
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+ return 0;
+}
+
+static int ipu_pre_prefetch(unsigned int id,
+ unsigned int read_burst,
+ unsigned int input_bpp,
+ unsigned int input_pixel_fmt,
+ bool shift_bypass,
+ bool field_inverse,
+ bool tpr_coor_offset_en,
+ struct ipu_rect output_size,
+ unsigned int input_width,
+ unsigned int input_height,
+ unsigned int input_active_width,
+ unsigned int interlaced,
+ int interlace_offset)
+{
+ unsigned int prefetch_ctrl = 0;
+ unsigned int input_y_pitch = 0, input_uv_pitch = 0;
+ struct ipu_pre_data *pre = get_pre(id);
+ unsigned long lock_flags;
+
+ if (!pre)
+ return -EINVAL;
+
+ spin_lock_irqsave(&pre->lock, lock_flags);
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN(1);
+ switch (read_burst) {
+ case 0x0:
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(0x0);
+ break;
+ case 0x1:
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(0x1);
+ break;
+ case 0x2:
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(0x2);
+ break;
+ case 0x3:
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(0x3);
+ break;
+ case 0x4:
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(0x4);
+ break;
+ default:
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+ dev_err(pre->dev, "invalid read burst for prefetch engine\n");
+ return -EINVAL;
+ }
+
+ switch (input_bpp) {
+ case 8:
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(0x0);
+ break;
+ case 16:
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(0x1);
+ break;
+ case 32:
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(0x2);
+ break;
+ case 64:
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(0x3);
+ break;
+ default:
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+ dev_err(pre->dev, "invalid input bpp for prefetch engine\n");
+ return -EINVAL;
+ }
+
+ switch (input_pixel_fmt) {
+ case 0x1: /* tile */
+ case 0x0: /* generic data */
+ case IPU_PIX_FMT_RGB666:
+ case IPU_PIX_FMT_RGB565:
+ case IPU_PIX_FMT_BGRA4444:
+ case IPU_PIX_FMT_BGRA5551:
+ case IPU_PIX_FMT_BGR24:
+ case IPU_PIX_FMT_RGB24:
+ case IPU_PIX_FMT_GBR24:
+ case IPU_PIX_FMT_BGR32:
+ case IPU_PIX_FMT_BGRA32:
+ case IPU_PIX_FMT_RGB32:
+ case IPU_PIX_FMT_RGBA32:
+ case IPU_PIX_FMT_ABGR32:
+ case IPU_PIX_FMT_YUYV:
+ case IPU_PIX_FMT_UYVY:
+ case IPU_PIX_FMT_YUV444:
+ case IPU_PIX_FMT_AYUV:
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x0);
+ input_y_pitch = input_width * (input_bpp >> 3);
+ if (interlaced && input_pixel_fmt != 0x1)
+ input_y_pitch *= 2;
+ break;
+ case IPU_PIX_FMT_YUV444P:
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x1);
+ input_y_pitch = input_width;
+ input_uv_pitch = input_width;
+ break;
+ case IPU_PIX_FMT_YUV422P:
+ case IPU_PIX_FMT_YVU422P:
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x2);
+ input_y_pitch = input_width;
+ input_uv_pitch = input_width >> 1;
+ break;
+ case IPU_PIX_FMT_YUV420P2:
+ case IPU_PIX_FMT_YUV420P:
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x3);
+ input_y_pitch = input_width;
+ input_uv_pitch = input_width >> 1;
+ break;
+ case PRE_PIX_FMT_NV61:
+ prefetch_ctrl |= BM_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP;
+ case IPU_PIX_FMT_NV16:
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x4);
+ input_y_pitch = input_width;
+ input_uv_pitch = input_width;
+ break;
+ case PRE_PIX_FMT_NV21:
+ prefetch_ctrl |= BM_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP;
+ case IPU_PIX_FMT_NV12:
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x5);
+ input_y_pitch = input_width;
+ input_uv_pitch = input_width;
+ break;
+ default:
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+ dev_err(pre->dev, "invalid input pixel format for prefetch engine\n");
+ return -EINVAL;
+ }
+
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS(shift_bypass ? 1 : 0);
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE(field_inverse ? 1 : 0);
+ prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_TPR_COOR_OFFSET_EN(tpr_coor_offset_en ? 1 : 0);
+
+ pre_write(pre, BF_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH(input_active_width) |
+ BF_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT(input_height),
+ HW_PRE_PREFETCH_ENGINE_INPUT_SIZE);
+
+ if (tpr_coor_offset_en)
+ pre_write(pre, BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X(output_size.left) |
+ BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y(output_size.top),
+ HW_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC);
+
+ pre_write(pre, BF_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH(input_y_pitch) |
+ BF_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH(input_uv_pitch),
+ HW_PRE_PREFETCH_ENGINE_PITCH);
+
+ pre_write(pre, BF_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET(interlace_offset), HW_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET);
+
+ pre_write(pre, prefetch_ctrl, HW_PRE_PREFETCH_ENGINE_CTRL);
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+ return 0;
+}
+
+static int ipu_pre_store(unsigned int id,
+ bool store_en,
+ unsigned int write_burst,
+ unsigned int output_bpp,
+ /* this means the output
+ * width by prefetch
+ */
+ unsigned int input_width,
+ unsigned int input_height,
+ unsigned int out_pitch,
+ unsigned int output_addr)
+{
+ struct ipu_pre_data *pre = get_pre(id);
+ unsigned int store_ctrl = 0;
+ unsigned long lock_flags;
+
+ if (!pre)
+ return -EINVAL;
+
+ spin_lock_irqsave(&pre->lock, lock_flags);
+ store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_STORE_EN(store_en ? 1 : 0);
+
+ if (store_en) {
+ switch (write_burst) {
+ case 0x0:
+ store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(0x0);
+ break;
+ case 0x1:
+ store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(0x1);
+ break;
+ case 0x2:
+ store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(0x2);
+ break;
+ case 0x3:
+ store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(0x3);
+ break;
+ case 0x4:
+ store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(0x4);
+ break;
+ default:
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+ dev_err(pre->dev, "invalid write burst value for store engine\n");
+ return -EINVAL;
+ }
+
+ switch (output_bpp) {
+ case 8:
+ store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(0x0);
+ break;
+ case 16:
+ store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(0x1);
+ break;
+ case 32:
+ store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(0x2);
+ break;
+ case 64:
+ store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(0x3);
+ break;
+ default:
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+ dev_err(pre->dev, "invalid ouput bpp for store engine\n");
+ return -EINVAL;
+ }
+
+ pre_write(pre, BF_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH(input_width) |
+ BF_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT(input_height),
+ HW_PRE_STORE_ENGINE_SIZE);
+
+ pre_write(pre, BF_PRE_STORE_ENGINE_PITCH_OUT_PITCH(out_pitch),
+ HW_PRE_STORE_ENGINE_PITCH);
+
+ pre_write(pre, BF_PRE_STORE_ENGINE_ADDR_OUT_BASE_ADDR(output_addr),
+ HW_PRE_STORE_ENGINE_ADDR);
+ }
+
+ pre_write(pre, store_ctrl, HW_PRE_STORE_ENGINE_CTRL);
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+ return 0;
+}
+/* End */
+
+static irqreturn_t ipu_pre_irq_handle(int irq, void *dev_id)
+{
+ struct ipu_pre_data *pre = dev_id;
+ unsigned int irq_stat, axi_id = 0;
+
+ spin_lock(&pre->lock);
+ irq_stat = pre_read(pre, HW_PRE_IRQ);
+
+ if (irq_stat & BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ) {
+ dev_warn(pre->dev, "handshake abort\n");
+ pre_write(pre, BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ, HW_PRE_IRQ_CLR);
+ }
+
+ if (irq_stat & BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ) {
+ dev_warn(pre->dev, "tpr read num bytes overflow\n");
+ pre_write(pre, BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ,
+ HW_PRE_IRQ_CLR);
+ }
+
+ if (irq_stat & BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ) {
+ dev_warn(pre->dev, "handshake error\n");
+ pre_write(pre, BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ, HW_PRE_IRQ_CLR);
+ }
+
+ axi_id = (irq_stat & BM_PRE_IRQ_AXI_ERROR_ID) >>
+ BP_PRE_IRQ_AXI_ERROR_ID;
+ if (irq_stat & BM_PRE_IRQ_AXI_WRITE_ERROR) {
+ dev_warn(pre->dev, "AXI%d write error\n", axi_id);
+ pre_write(pre, BM_PRE_IRQ_AXI_WRITE_ERROR, HW_PRE_IRQ_CLR);
+ }
+
+ if (irq_stat & BM_PRE_IRQ_AXI_READ_ERROR) {
+ dev_warn(pre->dev, "AXI%d read error\n", axi_id);
+ pre_write(pre, BM_PRE_IRQ_AXI_READ_ERROR, HW_PRE_IRQ_CLR);
+ }
+ spin_unlock(&pre->lock);
+
+ return IRQ_HANDLED;
+}
+
+static void ipu_pre_out_of_reset(unsigned int id)
+{
+ struct ipu_pre_data *pre = get_pre(id);
+ unsigned long lock_flags;
+
+ if (!pre)
+ return;
+
+ spin_lock_irqsave(&pre->lock, lock_flags);
+ pre_write(pre, BF_PRE_CTRL_SFTRST(1) | BF_PRE_CTRL_CLKGATE(1),
+ HW_PRE_CTRL_CLR);
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+}
+
+int ipu_pre_config(int id, struct ipu_pre_context *config)
+{
+ int ret = 0;
+ struct ipu_pre_data *pre = get_pre(id);
+
+ if (!config || !pre)
+ return -EINVAL;
+
+ config->store_addr = pre->double_buffer_paddr;
+
+ if (!pre->enabled)
+ clk_prepare_enable(pre->clk);
+
+ ipu_pre_out_of_reset(id);
+
+ ret = ipu_pre_plane_buf_off_set(id, config->sec_buf_off,
+ config->trd_buf_off);
+ if (ret < 0)
+ goto out;
+
+ ret = ipu_pre_tpr_set(id, config->tile_fmt);
+ if (ret < 0)
+ goto out;
+
+ ret = ipu_pre_buf_set(id, config->cur_buf, config->next_buf);
+ if (ret < 0)
+ goto out;
+
+ ret = ipu_pre_set_shift(id, config->prefetch_shift_offset,
+ config->prefetch_shift_width);
+ if (ret < 0)
+ goto out;
+
+ ret = ipu_pre_prefetch(id, config->read_burst, config->prefetch_input_bpp,
+ config->prefetch_input_pixel_fmt, config->shift_bypass,
+ config->field_inverse, config->tpr_coor_offset_en,
+ config->prefetch_output_size, config->prefetch_input_width,
+ config->prefetch_input_height,
+ config->prefetch_input_active_width,
+ config->interlaced,
+ config->interlace_offset);
+ if (ret < 0)
+ goto out;
+
+ ret = ipu_pre_store(id, config->store_en,
+ config->write_burst, config->store_output_bpp,
+ config->prefetch_output_size.width, config->prefetch_output_size.height,
+ config->store_pitch,
+ config->store_addr);
+ if (ret < 0)
+ goto out;
+
+ ipu_pre_irq_mask(pre, BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ |
+ BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ |
+ BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ, false);
+out:
+ if (!pre->enabled)
+ clk_disable_unprepare(pre->clk);
+
+ return ret;
+}
+EXPORT_SYMBOL(ipu_pre_config);
+
+int ipu_pre_enable(int id)
+{
+ int ret = 0;
+ struct ipu_pre_data *pre = get_pre(id);
+ unsigned long lock_flags;
+
+ if (!pre)
+ return -EINVAL;
+
+ if (pre->enabled)
+ return 0;
+
+ clk_prepare_enable(pre->clk);
+
+ /* start the pre engine */
+ spin_lock_irqsave(&pre->lock, lock_flags);
+ pre_write(pre, BF_PRE_CTRL_ENABLE(1), HW_PRE_CTRL_SET);
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+ pre->enabled = true;
+
+ return ret;
+}
+EXPORT_SYMBOL(ipu_pre_enable);
+
+int ipu_pre_sdw_update(int id)
+{
+ int ret = 0;
+ struct ipu_pre_data *pre = get_pre(id);
+ unsigned long lock_flags;
+
+ if (!pre)
+ return -EINVAL;
+
+ if (!pre->enabled)
+ clk_prepare_enable(pre->clk);
+
+ /* start the pre engine */
+ spin_lock_irqsave(&pre->lock, lock_flags);
+ pre_write(pre, BF_PRE_CTRL_SDW_UPDATE(1), HW_PRE_CTRL_SET);
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+ if (!pre->enabled)
+ clk_disable_unprepare(pre->clk);
+
+ return ret;
+}
+EXPORT_SYMBOL(ipu_pre_sdw_update);
+
+void ipu_pre_disable(int id)
+{
+ struct ipu_pre_data *pre = get_pre(id);
+ unsigned long lock_flags;
+
+ if (!pre)
+ return;
+
+ if (!pre->enabled)
+ return;
+
+ /* stop the pre engine */
+ spin_lock_irqsave(&pre->lock, lock_flags);
+ pre_write(pre, BF_PRE_CTRL_ENABLE(1), HW_PRE_CTRL_CLR);
+ pre_write(pre, BF_PRE_CTRL_SDW_UPDATE(1), HW_PRE_CTRL_SET);
+ pre_write(pre, BF_PRE_CTRL_SFTRST(1), HW_PRE_CTRL_SET);
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+ clk_disable_unprepare(pre->clk);
+
+ pre->enabled = false;
+}
+EXPORT_SYMBOL(ipu_pre_disable);
+
+int ipu_pre_set_fb_buffer(int id, bool resolve,
+ unsigned long fb_paddr,
+ unsigned int y_res,
+ unsigned int x_crop,
+ unsigned int y_crop,
+ unsigned int sec_buf_off,
+ unsigned int trd_buf_off)
+{
+ struct ipu_pre_data *pre = get_pre(id);
+ unsigned int store_stat, store_block_y;
+ unsigned long lock_flags;
+ bool update = true;
+
+ if (!pre)
+ return -EINVAL;
+
+ spin_lock_irqsave(&pre->lock, lock_flags);
+ pre_write(pre, fb_paddr, HW_PRE_NEXT_BUF);
+ pre_write(pre, sec_buf_off, HW_PRE_U_BUF_OFFSET);
+ pre_write(pre, trd_buf_off, HW_PRE_V_BUF_OFFSET);
+ pre_write(pre, BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X(x_crop) |
+ BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y(y_crop),
+ HW_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC);
+
+ /*
+ * Update shadow only when store engine runs out of the problematic
+ * window to workaround the SoC design bug recorded by errata ERR009624.
+ */
+ if (y_res > IPU_PRE_SMALL_LINE) {
+ unsigned long timeout = jiffies + msecs_to_jiffies(20);
+
+ do {
+ if (time_after(jiffies, timeout)) {
+ update = false;
+ dev_warn(pre->dev, "timeout waiting for PRE "
+ "to run out of problematic window for "
+ "shadow update\n");
+ break;
+ }
+
+ store_stat = pre_read(pre, HW_PRE_STORE_ENGINE_STATUS);
+ store_block_y = (store_stat &
+ BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y) >>
+ BP_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y;
+ } while (store_block_y >=
+ (resolve ? DIV_ROUND_UP(y_res, 4) - 1 : y_res - 2) ||
+ store_block_y == 0);
+ }
+
+ if (update)
+ pre_write(pre, BF_PRE_CTRL_SDW_UPDATE(1), HW_PRE_CTRL_SET);
+ spin_unlock_irqrestore(&pre->lock, lock_flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_pre_set_fb_buffer);
+
+static int ipu_pre_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct ipu_pre_data *pre;
+ struct resource *res;
+ unsigned long lock_flags;
+ int id, irq, err;
+
+ pre = devm_kzalloc(&pdev->dev, sizeof(*pre), GFP_KERNEL);
+ if (!pre)
+ return -ENOMEM;
+ pre->dev = &pdev->dev;
+
+ id = of_alias_get_id(np, "pre");
+ if (id < 0) {
+ dev_err(&pdev->dev, "failed to get PRE id\n");
+ return id;
+ }
+ pre->id = id;
+
+ mutex_init(&pre->mutex);
+ spin_lock_init(&pre->lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pre->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pre->base))
+ return PTR_ERR(pre->base);
+
+ pre->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pre->clk)) {
+ dev_err(&pdev->dev, "failed to get the pre clk\n");
+ return PTR_ERR(pre->clk);
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ err = devm_request_irq(&pdev->dev, irq, ipu_pre_irq_handle,
+ IRQF_TRIGGER_RISING, pdev->name, pre);
+ if (err) {
+ dev_err(&pdev->dev, "failed to request pre irq\n");
+ return err;
+ }
+
+ pre->iram_pool = of_gen_pool_get(pdev->dev.of_node, "ocram", 0);
+ if (!pre->iram_pool) {
+ dev_err(&pdev->dev, "no iram exist for pre\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(&pre_list_lock, lock_flags);
+ list_add_tail(&pre->list, &pre_list);
+ spin_unlock_irqrestore(&pre_list_lock, lock_flags);
+
+ ipu_pre_alloc_double_buffer(pre->id, IPU_PRE_MAX_WIDTH * 8 * IPU_PRE_MAX_BPP);
+
+ /* PRE GATE ON */
+ clk_prepare_enable(pre->clk);
+ pre_write(pre, BF_PRE_CTRL_SFTRST(1) | BF_PRE_CTRL_CLKGATE(1),
+ HW_PRE_CTRL_CLR);
+ pre_write(pre, 0xf, HW_PRE_IRQ_MASK);
+ clk_disable_unprepare(pre->clk);
+
+ platform_set_drvdata(pdev, pre);
+
+ dev_info(&pdev->dev, "driver probed\n");
+
+ return 0;
+}
+
+static int ipu_pre_remove(struct platform_device *pdev)
+{
+ struct ipu_pre_data *pre = platform_get_drvdata(pdev);
+ unsigned long lock_flags;
+
+ if (pre->iram_pool && pre->double_buffer_base) {
+ gen_pool_free(pre->iram_pool,
+ pre->double_buffer_base,
+ pre->double_buffer_size);
+ }
+
+ spin_lock_irqsave(&pre_list_lock, lock_flags);
+ list_del(&pre->list);
+ spin_unlock_irqrestore(&pre_list_lock, lock_flags);
+
+ return 0;
+}
+
+static const struct of_device_id imx_ipu_pre_dt_ids[] = {
+ { .compatible = "fsl,imx6q-pre", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_ipu_pre_dt_ids);
+
+static struct platform_driver ipu_pre_driver = {
+ .driver = {
+ .name = "imx-pre",
+ .of_match_table = of_match_ptr(imx_ipu_pre_dt_ids),
+ },
+ .probe = ipu_pre_probe,
+ .remove = ipu_pre_remove,
+};
+
+static int __init ipu_pre_init(void)
+{
+ return platform_driver_register(&ipu_pre_driver);
+}
+subsys_initcall(ipu_pre_init);
+
+static void __exit ipu_pre_exit(void)
+{
+ platform_driver_unregister(&ipu_pre_driver);
+}
+module_exit(ipu_pre_exit);
+
+MODULE_DESCRIPTION("i.MX PRE driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mxc/ipu3/prg-regs.h b/drivers/mxc/ipu3/prg-regs.h
new file mode 100644
index 000000000000..bca0e560a6f9
--- /dev/null
+++ b/drivers/mxc/ipu3/prg-regs.h
@@ -0,0 +1,70 @@
+/*
+ * Freescale IPU PRG Register Definitions
+ *
+ * Copyright 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/bitops.h>
+
+#ifndef __IPU_PRG_H__
+#define __IPU_PRG_H__
+
+#define IPU_PR_CTRL 0x00
+#define IPU_PR_STATUS 0x04
+#define IPU_PR_QOS 0x08
+#define IPU_PR_REG_UPDATE 0x0c
+#define IPU_PR_STRIDE(ch) (0x10 + (ch) * 4)
+#define IPU_PR_CROP_LINE 0x1c
+#define IPU_PR_ADDR_THD 0x20
+#define IPU_PR_CH_BADDR(ch) (0x24 + (ch) * 4)
+#define IPU_PR_CH_OFFSET(ch) (0x30 + (ch) * 4)
+#define IPU_PR_CH_ILO(ch) (0x3c + (ch) * 4)
+#define IPU_PR_CH_HEIGHT(ch) (0x48 + (ch) * 4)
+
+#define IPU_PR_CTRL_CH_BYPASS(ch) (0x1 << (ch))
+#define IPU_PR_CTRL_SOFT_CH_ARID(ch, n) ((n) << ((ch) * 2 + 8))
+#define IPU_PR_CTRL_SOFT_CH_ARID_MASK(ch) (0x3 << ((ch) * 2 + 8))
+#define IPU_PR_CTRL_CH_SO(ch, interlace) ((interlace) << ((ch) + 16))
+#define IPU_PR_CTRL_CH_SO_MASK(ch) (0x1 << ((ch) + 16))
+#define IPU_PR_CTRL_CH_VFLIP(ch, vflip) ((vflip) << ((ch) + 19))
+#define IPU_PR_CTRL_CH_VFLIP_MASK(ch) (0x1 << ((ch) + 19))
+#define IPU_PR_CTRL_CH_BLOCK_MODE(ch, mode) ((mode) << ((ch) + 22))
+#define IPU_PR_CTRL_CH_BLOCK_MODE_MASK(ch) (0x1 << ((ch) + 22))
+#define IPU_PR_CTRL_CH_CNT_LOAD_EN(ch) (0x1 << ((ch) + 25))
+#define IPU_PR_CTRL_CH_CNT_LOAD_EN_MASK (0x7 << 25)
+#define IPU_PR_CTRL_SOFTRST BIT(30)
+#define IPU_PR_CTRL_SHADOW_EN BIT(31)
+
+#define IPU_PR_STATUS_BUF_RDY(ch, buf) (1 << ((ch) * 2 + (buf)))
+
+#define IPU_PR_QOS_PRI(id, qos) ((qos) << ((id) * 4))
+#define IPU_PR_QOS_MASK(id) (0xf << ((id) * 4))
+
+#define IPU_PR_REG_UPDATE_EN BIT(0)
+
+#define IPU_PR_STRIDE_MASK 0x3fff
+
+#define IPU_PR_CROP_LINE_NUM(ch, n) ((n) << ((ch) * 4))
+#define IPU_PR_CROP_LINE_MASK(ch) (0xf << ((ch) * 4))
+
+#define IPU_PR_ADDR_THD_MASK 0xffffffff
+
+#define IPU_PR_CH_BADDR_MASK 0xffffffff
+
+#define IPU_PR_CH_OFFSET_MASK 0xffffffff
+
+#define IPU_PR_CH_ILO_MASK 0x007fffff
+#define IPU_PR_CH_ILO_NUM(ilo) ((ilo) & IPU_PR_CH_ILO_MASK)
+
+#define IPU_PR_CH_HEIGHT_MASK 0x00000fff
+#define IPU_PR_CH_HEIGHT_NUM(fh) (((fh) - 1) & IPU_PR_CH_HEIGHT_MASK)
+#define IPU_PR_CH_IPU_HEIGHT_MASK 0x0fff0000
+#define IPU_PR_CH_IPU_HEIGHT_NUM(fh) ((((fh) - 1) << 16) & IPU_PR_CH_IPU_HEIGHT_MASK)
+
+#endif /* __IPU_PRG_H__ */
diff --git a/drivers/mxc/ipu3/prg.c b/drivers/mxc/ipu3/prg.c
new file mode 100644
index 000000000000..45363a843392
--- /dev/null
+++ b/drivers/mxc/ipu3/prg.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ipu-v3-prg.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "prg-regs.h"
+
+#define PRG_CHAN_NUM 3
+
+struct prg_chan {
+ unsigned int pre_num;
+ struct mutex mutex; /* for in_use */
+ bool in_use;
+};
+
+struct ipu_prg_data {
+ unsigned int id;
+ void __iomem *base;
+ unsigned long memory;
+ struct clk *axi_clk;
+ struct clk *apb_clk;
+ struct list_head list;
+ struct device *dev;
+ struct prg_chan chan[PRG_CHAN_NUM];
+ struct regmap *regmap;
+ struct regmap_field *pre_prg_sel[2];
+ spinlock_t lock;
+};
+
+static LIST_HEAD(prg_list);
+static DEFINE_MUTEX(prg_lock);
+
+static inline void prg_write(struct ipu_prg_data *prg,
+ u32 value, unsigned int offset)
+{
+ writel(value, prg->base + offset);
+}
+
+static inline u32 prg_read(struct ipu_prg_data *prg, unsigned offset)
+{
+ return readl(prg->base + offset);
+}
+
+static struct ipu_prg_data *get_prg(unsigned int ipu_id)
+{
+ struct ipu_prg_data *prg;
+
+ mutex_lock(&prg_lock);
+ list_for_each_entry(prg, &prg_list, list) {
+ if (prg->id == ipu_id) {
+ mutex_unlock(&prg_lock);
+ return prg;
+ }
+ }
+ mutex_unlock(&prg_lock);
+
+ return NULL;
+}
+
+static int assign_prg_chan(struct ipu_prg_data *prg, unsigned int pre_num,
+ ipu_channel_t ipu_ch)
+{
+ int prg_ch;
+
+ if (!prg)
+ return -EINVAL;
+
+ switch (ipu_ch) {
+ case MEM_BG_SYNC:
+ prg_ch = 0;
+ break;
+ case MEM_FG_SYNC:
+ prg_ch = 1;
+ break;
+ case MEM_DC_SYNC:
+ prg_ch = 2;
+ break;
+ default:
+ dev_err(prg->dev, "wrong ipu channel type\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&prg->chan[prg_ch].mutex);
+ if (!prg->chan[prg_ch].in_use) {
+ prg->chan[prg_ch].in_use = true;
+ prg->chan[prg_ch].pre_num = pre_num;
+
+ if (prg_ch != 0) {
+ unsigned int pmux, psel; /* primary */
+ unsigned int smux, ssel; /* secondary */
+ struct regmap_field *pfield, *sfield;
+
+ psel = pre_num - 1;
+ ssel = psel ? 0 : 1;
+
+ pfield = prg->pre_prg_sel[psel];
+ sfield = prg->pre_prg_sel[ssel];
+ pmux = (prg_ch - 1) + (prg->id << 1);
+
+ mutex_lock(&prg_lock);
+ regmap_field_write(pfield, pmux);
+
+ /*
+ * PRE1 and PRE2 cannot bind with a same channel of
+ * one PRG even if one of the two PREs is disabled.
+ */
+ regmap_field_read(sfield, &smux);
+ if (smux == pmux) {
+ smux = pmux ^ 0x1;
+ regmap_field_write(sfield, smux);
+ }
+ mutex_unlock(&prg_lock);
+ }
+ mutex_unlock(&prg->chan[prg_ch].mutex);
+ dev_dbg(prg->dev, "bind prg%u ch%d with pre%u\n",
+ prg->id, prg_ch, pre_num);
+ return prg_ch;
+ }
+ mutex_unlock(&prg->chan[prg_ch].mutex);
+ return -EBUSY;
+}
+
+static inline int get_prg_chan(struct ipu_prg_data *prg, unsigned int pre_num)
+{
+ int i;
+
+ if (!prg)
+ return -EINVAL;
+
+ for (i = 0; i < PRG_CHAN_NUM; i++) {
+ mutex_lock(&prg->chan[i].mutex);
+ if (prg->chan[i].in_use &&
+ prg->chan[i].pre_num == pre_num) {
+ mutex_unlock(&prg->chan[i].mutex);
+ return i;
+ }
+ mutex_unlock(&prg->chan[i].mutex);
+ }
+ return -ENOENT;
+}
+
+int ipu_prg_config(struct ipu_prg_config *config)
+{
+ struct ipu_prg_data *prg = get_prg(config->id);
+ struct ipu_soc *ipu = ipu_get_soc(config->id);
+ int prg_ch, axi_id;
+ u32 reg;
+
+ if (!prg || config->crop_line > 3 || !ipu)
+ return -EINVAL;
+
+ if (config->height & ~IPU_PR_CH_HEIGHT_MASK)
+ return -EINVAL;
+
+ prg_ch = assign_prg_chan(prg, config->pre_num, config->ipu_ch);
+ if (prg_ch < 0)
+ return prg_ch;
+
+ axi_id = ipu_ch_param_get_axi_id(ipu, config->ipu_ch, IPU_INPUT_BUFFER);
+
+ clk_prepare_enable(prg->axi_clk);
+ clk_prepare_enable(prg->apb_clk);
+
+ spin_lock(&prg->lock);
+ /* clear all load enable to impact other channels */
+ reg = prg_read(prg, IPU_PR_CTRL);
+ reg &= ~IPU_PR_CTRL_CH_CNT_LOAD_EN_MASK;
+ prg_write(prg, reg, IPU_PR_CTRL);
+
+ /* counter load enable */
+ reg = prg_read(prg, IPU_PR_CTRL);
+ reg |= IPU_PR_CTRL_CH_CNT_LOAD_EN(prg_ch);
+ prg_write(prg, reg, IPU_PR_CTRL);
+
+ /* AXI ID */
+ reg = prg_read(prg, IPU_PR_CTRL);
+ reg &= ~IPU_PR_CTRL_SOFT_CH_ARID_MASK(prg_ch);
+ reg |= IPU_PR_CTRL_SOFT_CH_ARID(prg_ch, axi_id);
+ prg_write(prg, reg, IPU_PR_CTRL);
+
+ /* so */
+ reg = prg_read(prg, IPU_PR_CTRL);
+ reg &= ~IPU_PR_CTRL_CH_SO_MASK(prg_ch);
+ reg |= IPU_PR_CTRL_CH_SO(prg_ch, config->so);
+ prg_write(prg, reg, IPU_PR_CTRL);
+
+ /* vflip */
+ reg = prg_read(prg, IPU_PR_CTRL);
+ reg &= ~IPU_PR_CTRL_CH_VFLIP_MASK(prg_ch);
+ reg |= IPU_PR_CTRL_CH_VFLIP(prg_ch, config->vflip);
+ prg_write(prg, reg, IPU_PR_CTRL);
+
+ /* block mode */
+ reg = prg_read(prg, IPU_PR_CTRL);
+ reg &= ~IPU_PR_CTRL_CH_BLOCK_MODE_MASK(prg_ch);
+ reg |= IPU_PR_CTRL_CH_BLOCK_MODE(prg_ch, config->block_mode);
+ prg_write(prg, reg, IPU_PR_CTRL);
+
+ /* disable bypass */
+ reg = prg_read(prg, IPU_PR_CTRL);
+ reg &= ~IPU_PR_CTRL_CH_BYPASS(prg_ch);
+ prg_write(prg, reg, IPU_PR_CTRL);
+
+ /* stride */
+ reg = prg_read(prg, IPU_PR_STRIDE(prg_ch));
+ reg &= ~IPU_PR_STRIDE_MASK;
+ reg |= config->stride - 1;
+ prg_write(prg, reg, IPU_PR_STRIDE(prg_ch));
+
+ /* ilo */
+ reg = prg_read(prg, IPU_PR_CH_ILO(prg_ch));
+ reg &= ~IPU_PR_CH_ILO_MASK;
+ reg |= IPU_PR_CH_ILO_NUM(config->ilo);
+ prg_write(prg, reg, IPU_PR_CH_ILO(prg_ch));
+
+ /* height */
+ reg = prg_read(prg, IPU_PR_CH_HEIGHT(prg_ch));
+ reg &= ~IPU_PR_CH_HEIGHT_MASK;
+ reg |= IPU_PR_CH_HEIGHT_NUM(config->height);
+ prg_write(prg, reg, IPU_PR_CH_HEIGHT(prg_ch));
+
+ /* ipu height */
+ reg = prg_read(prg, IPU_PR_CH_HEIGHT(prg_ch));
+ reg &= ~IPU_PR_CH_IPU_HEIGHT_MASK;
+ reg |= IPU_PR_CH_IPU_HEIGHT_NUM(config->ipu_height);
+ prg_write(prg, reg, IPU_PR_CH_HEIGHT(prg_ch));
+
+ /* crop */
+ reg = prg_read(prg, IPU_PR_CROP_LINE);
+ reg &= ~IPU_PR_CROP_LINE_MASK(prg_ch);
+ reg |= IPU_PR_CROP_LINE_NUM(prg_ch, config->crop_line);
+ prg_write(prg, reg, IPU_PR_CROP_LINE);
+
+ /* buffer address */
+ reg = prg_read(prg, IPU_PR_CH_BADDR(prg_ch));
+ reg &= ~IPU_PR_CH_BADDR_MASK;
+ reg |= config->baddr;
+ prg_write(prg, reg, IPU_PR_CH_BADDR(prg_ch));
+
+ /* offset */
+ reg = prg_read(prg, IPU_PR_CH_OFFSET(prg_ch));
+ reg &= ~IPU_PR_CH_OFFSET_MASK;
+ reg |= config->offset;
+ prg_write(prg, reg, IPU_PR_CH_OFFSET(prg_ch));
+
+ /* threshold */
+ reg = prg_read(prg, IPU_PR_ADDR_THD);
+ reg &= ~IPU_PR_ADDR_THD_MASK;
+ reg |= prg->memory;
+ prg_write(prg, reg, IPU_PR_ADDR_THD);
+
+ /* shadow enable */
+ reg = prg_read(prg, IPU_PR_CTRL);
+ reg |= IPU_PR_CTRL_SHADOW_EN;
+ prg_write(prg, reg, IPU_PR_CTRL);
+
+ /* register update */
+ reg = prg_read(prg, IPU_PR_REG_UPDATE);
+ reg |= IPU_PR_REG_UPDATE_EN;
+ prg_write(prg, reg, IPU_PR_REG_UPDATE);
+ spin_unlock(&prg->lock);
+
+ clk_disable_unprepare(prg->apb_clk);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_prg_config);
+
+int ipu_prg_disable(unsigned int ipu_id, unsigned int pre_num)
+{
+ struct ipu_prg_data *prg = get_prg(ipu_id);
+ int prg_ch;
+ u32 reg;
+
+ if (!prg)
+ return -EINVAL;
+
+ prg_ch = get_prg_chan(prg, pre_num);
+ if (prg_ch < 0)
+ return prg_ch;
+
+ clk_prepare_enable(prg->apb_clk);
+
+ spin_lock(&prg->lock);
+ /* clear all load enable to impact other channels */
+ reg = prg_read(prg, IPU_PR_CTRL);
+ reg &= ~IPU_PR_CTRL_CH_CNT_LOAD_EN_MASK;
+ prg_write(prg, reg, IPU_PR_CTRL);
+
+ /* counter load enable */
+ reg = prg_read(prg, IPU_PR_CTRL);
+ reg |= IPU_PR_CTRL_CH_CNT_LOAD_EN(prg_ch);
+ prg_write(prg, reg, IPU_PR_CTRL);
+
+ /* enable bypass */
+ reg = prg_read(prg, IPU_PR_CTRL);
+ reg |= IPU_PR_CTRL_CH_BYPASS(prg_ch);
+ prg_write(prg, reg, IPU_PR_CTRL);
+
+ /* shadow enable */
+ reg = prg_read(prg, IPU_PR_CTRL);
+ reg |= IPU_PR_CTRL_SHADOW_EN;
+ prg_write(prg, reg, IPU_PR_CTRL);
+
+ /* register update */
+ reg = prg_read(prg, IPU_PR_REG_UPDATE);
+ reg |= IPU_PR_REG_UPDATE_EN;
+ prg_write(prg, reg, IPU_PR_REG_UPDATE);
+ spin_unlock(&prg->lock);
+
+ clk_disable_unprepare(prg->apb_clk);
+ clk_disable_unprepare(prg->axi_clk);
+
+ mutex_lock(&prg->chan[prg_ch].mutex);
+ prg->chan[prg_ch].in_use = false;
+ mutex_unlock(&prg->chan[prg_ch].mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_prg_disable);
+
+int ipu_prg_wait_buf_ready(unsigned int ipu_id, unsigned int pre_num,
+ unsigned int hsk_line_num,
+ int pre_store_out_height)
+{
+ struct ipu_prg_data *prg = get_prg(ipu_id);
+ int prg_ch, timeout = 1000;
+ u32 reg;
+
+ if (!prg)
+ return -EINVAL;
+
+ prg_ch = get_prg_chan(prg, pre_num);
+ if (prg_ch < 0)
+ return prg_ch;
+
+ clk_prepare_enable(prg->apb_clk);
+
+ spin_lock(&prg->lock);
+ if (pre_store_out_height <= (4 << hsk_line_num)) {
+ do {
+ reg = prg_read(prg, IPU_PR_STATUS);
+ udelay(1000);
+ timeout--;
+ } while (!(reg & IPU_PR_STATUS_BUF_RDY(prg_ch, 0)) && timeout);
+ } else {
+ do {
+ reg = prg_read(prg, IPU_PR_STATUS);
+ udelay(1000);
+ timeout--;
+ } while ((!(reg & IPU_PR_STATUS_BUF_RDY(prg_ch, 0)) ||
+ !(reg & IPU_PR_STATUS_BUF_RDY(prg_ch, 1))) && timeout);
+ }
+ spin_unlock(&prg->lock);
+
+ clk_disable_unprepare(prg->apb_clk);
+
+ if (!timeout)
+ dev_err(prg->dev, "wait for buffer ready timeout\n");
+
+ return 0;
+}
+EXPORT_SYMBOL(ipu_prg_wait_buf_ready);
+
+static int ipu_prg_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node, *memory;
+ struct ipu_prg_data *prg;
+ struct resource *res;
+ struct reg_field reg_field0 = REG_FIELD(IOMUXC_GPR5,
+ IMX6Q_GPR5_PRE_PRG_SEL0_LSB,
+ IMX6Q_GPR5_PRE_PRG_SEL0_MSB);
+ struct reg_field reg_field1 = REG_FIELD(IOMUXC_GPR5,
+ IMX6Q_GPR5_PRE_PRG_SEL1_LSB,
+ IMX6Q_GPR5_PRE_PRG_SEL1_MSB);
+ int id, i;
+
+ prg = devm_kzalloc(&pdev->dev, sizeof(*prg), GFP_KERNEL);
+ if (!prg)
+ return -ENOMEM;
+ prg->dev = &pdev->dev;
+
+ for (i = 0; i < PRG_CHAN_NUM; i++)
+ mutex_init(&prg->chan[i].mutex);
+
+ spin_lock_init(&prg->lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ prg->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(prg->base))
+ return PTR_ERR(prg->base);
+
+ prg->axi_clk = devm_clk_get(&pdev->dev, "axi");
+ if (IS_ERR(prg->axi_clk)) {
+ dev_err(&pdev->dev, "failed to get the axi clk\n");
+ return PTR_ERR(prg->axi_clk);
+ }
+
+ prg->apb_clk = devm_clk_get(&pdev->dev, "apb");
+ if (IS_ERR(prg->apb_clk)) {
+ dev_err(&pdev->dev, "failed to get the apb clk\n");
+ return PTR_ERR(prg->apb_clk);
+ }
+
+ prg->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
+ if (IS_ERR(prg->regmap)) {
+ dev_err(&pdev->dev, "failed to get regmap\n");
+ return PTR_ERR(prg->regmap);
+ }
+
+ prg->pre_prg_sel[0] = devm_regmap_field_alloc(&pdev->dev, prg->regmap,
+ reg_field0);
+ if (IS_ERR(prg->pre_prg_sel[0]))
+ return PTR_ERR(prg->pre_prg_sel[0]);
+
+ prg->pre_prg_sel[1] = devm_regmap_field_alloc(&pdev->dev, prg->regmap,
+ reg_field1);
+ if (IS_ERR(prg->pre_prg_sel[1]))
+ return PTR_ERR(prg->pre_prg_sel[1]);
+
+ memory = of_parse_phandle(np, "memory-region", 0);
+ if (!memory)
+ return -ENODEV;
+
+ prg->memory = of_translate_address(memory,
+ of_get_address(memory, 0, NULL, NULL));
+
+ id = of_alias_get_id(np, "prg");
+ if (id < 0) {
+ dev_err(&pdev->dev, "failed to get PRG id\n");
+ return id;
+ }
+ prg->id = id;
+
+ mutex_lock(&prg_lock);
+ list_add_tail(&prg->list, &prg_list);
+ mutex_unlock(&prg_lock);
+
+ platform_set_drvdata(pdev, prg);
+
+ dev_info(&pdev->dev, "driver probed\n");
+
+ return 0;
+}
+
+static int ipu_prg_remove(struct platform_device *pdev)
+{
+ struct ipu_prg_data *prg = platform_get_drvdata(pdev);
+
+ mutex_lock(&prg_lock);
+ list_del(&prg->list);
+ mutex_unlock(&prg_lock);
+
+ return 0;
+}
+
+static const struct of_device_id imx_ipu_prg_dt_ids[] = {
+ { .compatible = "fsl,imx6q-prg", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_ipu_prg_dt_ids);
+
+static struct platform_driver ipu_prg_driver = {
+ .driver = {
+ .name = "imx-prg",
+ .of_match_table = of_match_ptr(imx_ipu_prg_dt_ids),
+ },
+ .probe = ipu_prg_probe,
+ .remove = ipu_prg_remove,
+};
+
+static int __init ipu_prg_init(void)
+{
+ return platform_driver_register(&ipu_prg_driver);
+}
+subsys_initcall(ipu_prg_init);
+
+static void __exit ipu_prg_exit(void)
+{
+ platform_driver_unregister(&ipu_prg_driver);
+}
+module_exit(ipu_prg_exit);
+
+MODULE_DESCRIPTION("i.MX PRG driver");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mxc/ipu3/vdoa.c b/drivers/mxc/ipu3/vdoa.c
new file mode 100644
index 000000000000..68194c9158f1
--- /dev/null
+++ b/drivers/mxc/ipu3/vdoa.c
@@ -0,0 +1,536 @@
+/*
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/ipu.h>
+#include <linux/genalloc.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "vdoa.h"
+/* 6band(3field* double buffer) * (width*2) * bandline(8)
+ = 6x1024x2x8 = 96k or 72k(1.5byte) */
+#define MAX_VDOA_IRAM_SIZE (1024*96)
+#define VDOA_IRAM_SIZE (1024*72)
+
+#define VDOAC_BAND_HEIGHT_32LINES (32)
+#define VDOAC_BAND_HEIGHT_16LINES (16)
+#define VDOAC_BAND_HEIGHT_8LINES (8)
+#define VDOAC_THREE_FRAMES (0x1 << 2)
+#define VDOAC_SYNC_BAND_MODE (0x1 << 3)
+#define VDOAC_SCAN_ORDER_INTERLACED (0x1 << 4)
+#define VDOAC_PFS_YUYV (0x1 << 5)
+#define VDOAC_IPU_SEL_1 (0x1 << 6)
+#define VDOAFP_FH_MASK (0x1FFF)
+#define VDOAFP_FH_SHIFT (16)
+#define VDOAFP_FW_MASK (0x3FFF)
+#define VDOAFP_FW_SHIFT (0)
+#define VDOASL_VSLY_MASK (0x3FFF)
+#define VDOASL_VSLY_SHIFT (16)
+#define VDOASL_ISLY_MASK (0x7FFF)
+#define VDOASL_ISLY_SHIFT (0)
+#define VDOASRR_START_XFER (0x2)
+#define VDOASRR_SWRST (0x1)
+#define VDOAIEIST_TRANSFER_ERR (0x2)
+#define VDOAIEIST_TRANSFER_END (0x1)
+
+#define VDOAC (0x0) /* Control Register */
+#define VDOASRR (0x4) /* Start and Reset Register */
+#define VDOAIE (0x8) /* Interrupt Enable Register */
+#define VDOAIST (0xc) /* Interrupt Status Register */
+#define VDOAFP (0x10) /* Frame Parameters Register */
+#define VDOAIEBA00 (0x14) /* External Buffer n Frame m Address Register */
+#define VDOAIEBA01 (0x18) /* External Buffer n Frame m Address Register */
+#define VDOAIEBA02 (0x1c) /* External Buffer n Frame m Address Register */
+#define VDOAIEBA10 (0x20) /* External Buffer n Frame m Address Register */
+#define VDOAIEBA11 (0x24) /* External Buffer n Frame m Address Register */
+#define VDOAIEBA12 (0x28) /* External Buffer n Frame m Address Register */
+#define VDOASL (0x2c) /* IPU Stride Line Register */
+#define VDOAIUBO (0x30) /* IPU Chroma Buffer Offset Register */
+#define VDOAVEBA0 (0x34) /* External Buffer m Address Register */
+#define VDOAVEBA1 (0x38) /* External Buffer m Address Register */
+#define VDOAVEBA2 (0x3c) /* External Buffer m Address Register */
+#define VDOAVUBO (0x40) /* VPU Chroma Buffer Offset */
+#define VDOASR (0x44) /* Status Register */
+#define VDOATD (0x48) /* Test Debug Register */
+
+
+enum {
+ VDOA_INIT = 0x1,
+ VDOA_GET = 0x2,
+ VDOA_SETUP = 0x4,
+ VDOA_GET_OBUF = 0x8,
+ VDOA_START = 0x10,
+ VDOA_INIRQ = 0x20,
+ VDOA_STOP = 0x40,
+ VDOA_PUT = VDOA_INIT,
+};
+
+enum {
+ VDOA_NULL = 0,
+ VDOA_FRAME = 1,
+ VDOA_PREV_FIELD = 2,
+ VDOA_CURR_FIELD = 3,
+ VDOA_NEXT_FIELD = 4,
+};
+
+#define CHECK_STATE(expect, retcode) \
+do { \
+ if (!((expect) & vdoa->state)) { \
+ dev_err(vdoa->dev, "ERR: %s state:0x%x, expect:0x%x.\n",\
+ __func__, vdoa->state, (expect)); \
+ retcode; \
+ } \
+} while (0)
+
+#define CHECK_NULL_PTR(ptr) \
+do { \
+ pr_debug("vdoa_ptr:0x%p in %s state:0x%x.\n", \
+ vdoa, __func__, vdoa->state); \
+ if (NULL == (ptr)) { \
+ pr_err("ERR vdoa: %s state:0x%x null ptr.\n", \
+ __func__, vdoa->state); \
+ } \
+} while (0)
+
+struct vdoa_info {
+ int state;
+ struct device *dev;
+ struct clk *vdoa_clk;
+ void __iomem *reg_base;
+ struct gen_pool *iram_pool;
+ unsigned long iram_base;
+ unsigned long iram_paddr;
+ int irq;
+ int field;
+ struct completion comp;
+};
+
+static struct vdoa_info *g_vdoa;
+static unsigned long iram_size;
+static DEFINE_MUTEX(vdoa_lock);
+
+static inline void vdoa_read_register(struct vdoa_info *vdoa,
+ u32 reg, u32 *val)
+{
+ *val = ioread32(vdoa->reg_base + reg);
+ dev_dbg(vdoa->dev, "read_reg:0x%02x, val:0x%08x.\n", reg, *val);
+}
+
+static inline void vdoa_write_register(struct vdoa_info *vdoa,
+ u32 reg, u32 val)
+{
+ iowrite32(val, vdoa->reg_base + reg);
+ dev_dbg(vdoa->dev, "\t\twrite_reg:0x%02x, val:0x%08x.\n", reg, val);
+}
+
+static void dump_registers(struct vdoa_info *vdoa)
+{
+ int i;
+ u32 data;
+
+ for (i = VDOAC; i < VDOATD; i += 4)
+ vdoa_read_register(vdoa, i, &data);
+}
+
+int vdoa_setup(vdoa_handle_t handle, struct vdoa_params *params)
+{
+ int band_size;
+ int total_band_size = 0;
+ int ipu_stride;
+ u32 data;
+ struct vdoa_info *vdoa = (struct vdoa_info *)handle;
+
+ CHECK_NULL_PTR(vdoa);
+ CHECK_STATE(VDOA_GET | VDOA_GET_OBUF | VDOA_STOP, return -EINVAL);
+ if (VDOA_GET == vdoa->state) {
+ dev_dbg(vdoa->dev, "w:%d, h:%d.\n",
+ params->width, params->height);
+ data = (params->band_lines == VDOAC_BAND_HEIGHT_32LINES) ? 2 :
+ ((params->band_lines == VDOAC_BAND_HEIGHT_16LINES) ?
+ 1 : 0);
+ data |= params->scan_order ? VDOAC_SCAN_ORDER_INTERLACED : 0;
+ data |= params->band_mode ? VDOAC_SYNC_BAND_MODE : 0;
+ data |= params->pfs ? VDOAC_PFS_YUYV : 0;
+ data |= params->ipu_num ? VDOAC_IPU_SEL_1 : 0;
+ vdoa_write_register(vdoa, VDOAC, data);
+
+ data = ((params->width & VDOAFP_FW_MASK) << VDOAFP_FW_SHIFT) |
+ ((params->height & VDOAFP_FH_MASK) << VDOAFP_FH_SHIFT);
+ vdoa_write_register(vdoa, VDOAFP, data);
+
+ ipu_stride = params->pfs ? params->width << 1 : params->width;
+ data = ((params->vpu_stride & VDOASL_VSLY_MASK) <<
+ VDOASL_VSLY_SHIFT) |
+ ((ipu_stride & VDOASL_ISLY_MASK) << VDOASL_ISLY_SHIFT);
+ vdoa_write_register(vdoa, VDOASL, data);
+
+ dev_dbg(vdoa->dev, "band_mode:%d, band_line:%d, base:0x%lx.\n",
+ params->band_mode, params->band_lines, vdoa->iram_paddr);
+ }
+ /*
+ * band size = (luma_per_line + chroma_per_line) * bandLines
+ * = width * (3/2 or 2) * bandLines
+ * double buffer mode used.
+ */
+ if (params->pfs)
+ band_size = (params->width << 1) * params->band_lines;
+ else
+ band_size = ((params->width * 3) >> 1) *
+ params->band_lines;
+ if (params->interlaced) {
+ total_band_size = 6 * band_size; /* 3 frames*double buffer */
+ if (iram_size < total_band_size) {
+ dev_err(vdoa->dev, "iram_size:0x%lx is smaller than "
+ "request:0x%x!\n", iram_size, total_band_size);
+ return -EINVAL;
+ }
+ if (params->vfield_buf.prev_veba) {
+ if (params->band_mode) {
+ vdoa_write_register(vdoa, VDOAIEBA00,
+ vdoa->iram_paddr);
+ vdoa_write_register(vdoa, VDOAIEBA10,
+ vdoa->iram_paddr + band_size);
+ } else
+ vdoa_write_register(vdoa, VDOAIEBA00,
+ params->ieba0);
+ vdoa_write_register(vdoa, VDOAVEBA0,
+ params->vfield_buf.prev_veba);
+ vdoa->field = VDOA_PREV_FIELD;
+ }
+ if (params->vfield_buf.cur_veba) {
+ if (params->band_mode) {
+ vdoa_write_register(vdoa, VDOAIEBA01,
+ vdoa->iram_paddr + band_size * 2);
+ vdoa_write_register(vdoa, VDOAIEBA11,
+ vdoa->iram_paddr + band_size * 3);
+ } else
+ vdoa_write_register(vdoa, VDOAIEBA01,
+ params->ieba1);
+ vdoa_write_register(vdoa, VDOAVEBA1,
+ params->vfield_buf.cur_veba);
+ vdoa->field = VDOA_CURR_FIELD;
+ }
+ if (params->vfield_buf.next_veba) {
+ if (params->band_mode) {
+ vdoa_write_register(vdoa, VDOAIEBA02,
+ vdoa->iram_paddr + band_size * 4);
+ vdoa_write_register(vdoa, VDOAIEBA12,
+ vdoa->iram_paddr + band_size * 5);
+ } else
+ vdoa_write_register(vdoa, VDOAIEBA02,
+ params->ieba2);
+ vdoa_write_register(vdoa, VDOAVEBA2,
+ params->vfield_buf.next_veba);
+ vdoa->field = VDOA_NEXT_FIELD;
+ vdoa_read_register(vdoa, VDOAC, &data);
+ data |= VDOAC_THREE_FRAMES;
+ vdoa_write_register(vdoa, VDOAC, data);
+ }
+
+ if (!params->pfs)
+ vdoa_write_register(vdoa, VDOAIUBO,
+ params->width * params->band_lines);
+ vdoa_write_register(vdoa, VDOAVUBO,
+ params->vfield_buf.vubo);
+ dev_dbg(vdoa->dev, "total band_size:0x%x.\n", band_size*6);
+ } else if (params->band_mode) {
+ /* used for progressive frame resize on PrP channel */
+ BUG(); /* currently not support */
+ /* progressvie frame: band mode */
+ vdoa_write_register(vdoa, VDOAIEBA00, vdoa->iram_paddr);
+ vdoa_write_register(vdoa, VDOAIEBA10,
+ vdoa->iram_paddr + band_size);
+ if (!params->pfs)
+ vdoa_write_register(vdoa, VDOAIUBO,
+ params->width * params->band_lines);
+ dev_dbg(vdoa->dev, "total band_size:0x%x\n", band_size*2);
+ } else {
+ /* progressive frame: mem->mem, non-band mode */
+ vdoa->field = VDOA_FRAME;
+ vdoa_write_register(vdoa, VDOAVEBA0, params->vframe_buf.veba);
+ vdoa_write_register(vdoa, VDOAVUBO, params->vframe_buf.vubo);
+ vdoa_write_register(vdoa, VDOAIEBA00, params->ieba0);
+ if (!params->pfs)
+ /* note: iubo is relative value, based on ieba0 */
+ vdoa_write_register(vdoa, VDOAIUBO,
+ params->width * params->height);
+ }
+ vdoa->state = VDOA_SETUP;
+ return 0;
+}
+
+void vdoa_get_output_buf(vdoa_handle_t handle, struct vdoa_ipu_buf *buf)
+{
+ u32 data;
+ struct vdoa_info *vdoa = (struct vdoa_info *)handle;
+
+ CHECK_NULL_PTR(vdoa);
+ CHECK_STATE(VDOA_SETUP, return);
+ vdoa->state = VDOA_GET_OBUF;
+ memset(buf, 0, sizeof(*buf));
+
+ vdoa_read_register(vdoa, VDOAC, &data);
+ switch (vdoa->field) {
+ case VDOA_FRAME:
+ case VDOA_PREV_FIELD:
+ vdoa_read_register(vdoa, VDOAIEBA00, &buf->ieba0);
+ if (data & VDOAC_SYNC_BAND_MODE)
+ vdoa_read_register(vdoa, VDOAIEBA10, &buf->ieba1);
+ break;
+ case VDOA_CURR_FIELD:
+ vdoa_read_register(vdoa, VDOAIEBA01, &buf->ieba0);
+ vdoa_read_register(vdoa, VDOAIEBA11, &buf->ieba1);
+ break;
+ case VDOA_NEXT_FIELD:
+ vdoa_read_register(vdoa, VDOAIEBA02, &buf->ieba0);
+ vdoa_read_register(vdoa, VDOAIEBA12, &buf->ieba1);
+ break;
+ default:
+ BUG();
+ break;
+ }
+ if (!(data & VDOAC_PFS_YUYV))
+ vdoa_read_register(vdoa, VDOAIUBO, &buf->iubo);
+}
+
+int vdoa_start(vdoa_handle_t handle, int timeout_ms)
+{
+ int ret;
+ struct vdoa_info *vdoa = (struct vdoa_info *)handle;
+
+ CHECK_NULL_PTR(vdoa);
+ CHECK_STATE(VDOA_GET_OBUF, return -EINVAL);
+ vdoa->state = VDOA_START;
+ init_completion(&vdoa->comp);
+ vdoa_write_register(vdoa, VDOAIST,
+ VDOAIEIST_TRANSFER_ERR | VDOAIEIST_TRANSFER_END);
+ vdoa_write_register(vdoa, VDOAIE,
+ VDOAIEIST_TRANSFER_ERR | VDOAIEIST_TRANSFER_END);
+
+ enable_irq(vdoa->irq);
+ vdoa_write_register(vdoa, VDOASRR, VDOASRR_START_XFER);
+ dump_registers(vdoa);
+
+ ret = wait_for_completion_timeout(&vdoa->comp,
+ msecs_to_jiffies(timeout_ms));
+
+ return ret > 0 ? 0 : -ETIMEDOUT;
+}
+
+void vdoa_stop(vdoa_handle_t handle)
+{
+ struct vdoa_info *vdoa = (struct vdoa_info *)handle;
+
+ CHECK_NULL_PTR(vdoa);
+ CHECK_STATE(VDOA_GET | VDOA_START | VDOA_INIRQ, return);
+ vdoa->state = VDOA_STOP;
+
+ disable_irq(vdoa->irq);
+
+ vdoa_write_register(vdoa, VDOASRR, VDOASRR_SWRST);
+}
+
+void vdoa_get_handle(vdoa_handle_t *handle)
+{
+ struct vdoa_info *vdoa = g_vdoa;
+
+ CHECK_NULL_PTR(handle);
+ *handle = (vdoa_handle_t *)NULL;
+ CHECK_STATE(VDOA_INIT, return);
+ mutex_lock(&vdoa_lock);
+ clk_prepare_enable(vdoa->vdoa_clk);
+ vdoa->state = VDOA_GET;
+ vdoa->field = VDOA_NULL;
+ vdoa_write_register(vdoa, VDOASRR, VDOASRR_SWRST);
+
+ *handle = (vdoa_handle_t *)vdoa;
+}
+
+void vdoa_put_handle(vdoa_handle_t *handle)
+{
+ struct vdoa_info *vdoa = (struct vdoa_info *)(*handle);
+
+ CHECK_NULL_PTR(vdoa);
+ CHECK_STATE(VDOA_STOP, return);
+ if (vdoa != g_vdoa)
+ BUG();
+
+ clk_disable_unprepare(vdoa->vdoa_clk);
+ vdoa->state = VDOA_PUT;
+ *handle = (vdoa_handle_t *)NULL;
+ mutex_unlock(&vdoa_lock);
+}
+
+static irqreturn_t vdoa_irq_handler(int irq, void *data)
+{
+ u32 status, mask, val;
+ struct vdoa_info *vdoa = data;
+
+ CHECK_NULL_PTR(vdoa);
+ CHECK_STATE(VDOA_START, return IRQ_HANDLED);
+ vdoa->state = VDOA_INIRQ;
+ vdoa_read_register(vdoa, VDOAIST, &status);
+ vdoa_read_register(vdoa, VDOAIE, &mask);
+ val = status & mask;
+ vdoa_write_register(vdoa, VDOAIST, val);
+ if (VDOAIEIST_TRANSFER_ERR & val)
+ dev_err(vdoa->dev, "vdoa Transfer err irq!\n");
+ if (VDOAIEIST_TRANSFER_END & val)
+ dev_dbg(vdoa->dev, "vdoa Transfer end irq!\n");
+ if (0 == val) {
+ dev_err(vdoa->dev, "vdoa unknown irq!\n");
+ BUG();
+ }
+
+ complete(&vdoa->comp);
+ return IRQ_HANDLED;
+}
+
+/* IRAM Size in Kbytes, example:vdoa_iram_size=64, 64KBytes */
+static int __init vdoa_iram_size_setup(char *options)
+{
+ int ret;
+
+ ret = kstrtoul(options, 0, &iram_size);
+ if (ret)
+ iram_size = 0;
+ else
+ iram_size *= SZ_1K;
+
+ return 1;
+}
+__setup("vdoa_iram_size=", vdoa_iram_size_setup);
+
+static const struct of_device_id imx_vdoa_dt_ids[] = {
+ { .compatible = "fsl,imx6q-vdoa", },
+ { /* sentinel */ }
+};
+
+static int vdoa_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct vdoa_info *vdoa;
+ struct resource *res;
+ struct resource *res_irq;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = pdev->dev.of_node;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "can't get device resources\n");
+ return -ENOENT;
+ }
+
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res_irq) {
+ dev_err(dev, "failed to get irq resource\n");
+ return -ENOENT;
+ }
+
+ vdoa = devm_kzalloc(dev, sizeof(struct vdoa_info), GFP_KERNEL);
+ if (!vdoa)
+ return -ENOMEM;
+ vdoa->dev = dev;
+
+ vdoa->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (!vdoa->reg_base)
+ return -EBUSY;
+
+ vdoa->irq = res_irq->start;
+ ret = devm_request_irq(dev, vdoa->irq, vdoa_irq_handler, 0,
+ "vdoa", vdoa);
+ if (ret) {
+ dev_err(dev, "can't claim irq %d\n", vdoa->irq);
+ return ret;
+ }
+ disable_irq(vdoa->irq);
+
+ vdoa->vdoa_clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(vdoa->vdoa_clk)) {
+ dev_err(dev, "failed to get vdoa_clk\n");
+ return PTR_ERR(vdoa->vdoa_clk);
+ }
+
+ vdoa->iram_pool = of_gen_pool_get(np, "iram", 0);
+ if (!vdoa->iram_pool) {
+ dev_err(&pdev->dev, "iram pool not available\n");
+ return -ENOMEM;
+ }
+
+ if ((iram_size == 0) || (iram_size > MAX_VDOA_IRAM_SIZE))
+ iram_size = VDOA_IRAM_SIZE;
+
+ vdoa->iram_base = gen_pool_alloc(vdoa->iram_pool, iram_size);
+ if (!vdoa->iram_base) {
+ dev_err(&pdev->dev, "unable to alloc iram\n");
+ return -ENOMEM;
+ }
+
+ vdoa->iram_paddr = gen_pool_virt_to_phys(vdoa->iram_pool,
+ vdoa->iram_base);
+
+ dev_dbg(dev, "iram_base:0x%lx,iram_paddr:0x%lx,size:0x%lx\n",
+ vdoa->iram_base, vdoa->iram_paddr, iram_size);
+
+ vdoa->state = VDOA_INIT;
+ dev_set_drvdata(dev, vdoa);
+ g_vdoa = vdoa;
+ dev_info(dev, "i.MX Video Data Order Adapter(VDOA) driver probed\n");
+ return 0;
+}
+
+static int vdoa_remove(struct platform_device *pdev)
+{
+ struct vdoa_info *vdoa = dev_get_drvdata(&pdev->dev);
+
+ gen_pool_free(vdoa->iram_pool, vdoa->iram_base, iram_size);
+ kfree(vdoa);
+ dev_set_drvdata(&pdev->dev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver vdoa_driver = {
+ .driver = {
+ .name = "mxc_vdoa",
+ .of_match_table = imx_vdoa_dt_ids,
+ },
+ .probe = vdoa_probe,
+ .remove = vdoa_remove,
+};
+
+static int __init vdoa_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&vdoa_driver);
+ if (err) {
+ pr_err("vdoa_driver register failed\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void __exit vdoa_cleanup(void)
+{
+ platform_driver_unregister(&vdoa_driver);
+}
+
+module_init(vdoa_init);
+module_exit(vdoa_cleanup);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX Video Data Order Adapter(VDOA) driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mxc/ipu3/vdoa.h b/drivers/mxc/ipu3/vdoa.h
new file mode 100644
index 000000000000..3e4c7356cb26
--- /dev/null
+++ b/drivers/mxc/ipu3/vdoa.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __VDOA_H__
+#define __VDOA_H__
+
+#define VDOA_PFS_YUYV (1)
+#define VDOA_PFS_NV12 (0)
+
+
+struct vfield_buf {
+ u32 prev_veba;
+ u32 cur_veba;
+ u32 next_veba;
+ u32 vubo;
+};
+
+struct vframe_buf {
+ u32 veba;
+ u32 vubo;
+};
+
+struct vdoa_params {
+ u32 width;
+ u32 height;
+ int vpu_stride;
+ int interlaced;
+ int scan_order;
+ int ipu_num;
+ int band_lines;
+ int band_mode;
+ int pfs;
+ u32 ieba0;
+ u32 ieba1;
+ u32 ieba2;
+ struct vframe_buf vframe_buf;
+ struct vfield_buf vfield_buf;
+};
+struct vdoa_ipu_buf {
+ u32 ieba0;
+ u32 ieba1;
+ u32 iubo;
+};
+
+struct vdoa_info;
+typedef void *vdoa_handle_t;
+
+int vdoa_setup(vdoa_handle_t handle, struct vdoa_params *params);
+void vdoa_get_output_buf(vdoa_handle_t handle, struct vdoa_ipu_buf *buf);
+int vdoa_start(vdoa_handle_t handle, int timeout_ms);
+void vdoa_stop(vdoa_handle_t handle);
+void vdoa_get_handle(vdoa_handle_t *handle);
+void vdoa_put_handle(vdoa_handle_t *handle);
+#endif
diff --git a/drivers/mxc/mipi/Kconfig b/drivers/mxc/mipi/Kconfig
new file mode 100644
index 000000000000..4c85da374ed2
--- /dev/null
+++ b/drivers/mxc/mipi/Kconfig
@@ -0,0 +1,14 @@
+#
+# MIPI configuration
+#
+
+menu "MXC MIPI Support"
+
+config MXC_MIPI_CSI2
+ tristate "MIPI CSI2 support"
+ depends on (SOC_IMX6 || SOC_IMX7)
+ default n
+ ---help---
+ Say Y to get the MIPI CSI2 support.
+
+endmenu
diff --git a/drivers/mxc/mipi/Makefile b/drivers/mxc/mipi/Makefile
new file mode 100644
index 000000000000..98cda773bd28
--- /dev/null
+++ b/drivers/mxc/mipi/Makefile
@@ -0,0 +1,4 @@
+#
+# Makefile for the mipi interface driver
+#
+obj-$(CONFIG_MXC_MIPI_CSI2) += mxc_mipi_csi2.o
diff --git a/drivers/mxc/mipi/mxc_mipi_csi2.c b/drivers/mxc/mipi/mxc_mipi_csi2.c
new file mode 100644
index 000000000000..df45c364f144
--- /dev/null
+++ b/drivers/mxc/mipi/mxc_mipi_csi2.c
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/fsl_devices.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include <linux/mipi_csi2.h>
+
+#include "mxc_mipi_csi2.h"
+
+static struct mipi_csi2_info *gmipi_csi2;
+
+void _mipi_csi2_lock(struct mipi_csi2_info *info)
+{
+ if (!in_irq() && !in_softirq())
+ mutex_lock(&info->mutex_lock);
+}
+
+void _mipi_csi2_unlock(struct mipi_csi2_info *info)
+{
+ if (!in_irq() && !in_softirq())
+ mutex_unlock(&info->mutex_lock);
+}
+
+static inline void mipi_csi2_write(struct mipi_csi2_info *info,
+ unsigned value, unsigned offset)
+{
+ writel(value, info->mipi_csi2_base + offset);
+}
+
+static inline unsigned int mipi_csi2_read(struct mipi_csi2_info *info,
+ unsigned offset)
+{
+ return readl(info->mipi_csi2_base + offset);
+}
+
+/*!
+ * This function is called to enable the mipi csi2 interface.
+ *
+ * @param info mipi csi2 hander
+ * @return Returns setted value
+ */
+bool mipi_csi2_enable(struct mipi_csi2_info *info)
+{
+ bool status;
+
+ _mipi_csi2_lock(info);
+
+ if (!info->mipi_en) {
+ info->mipi_en = true;
+ clk_prepare_enable(info->cfg_clk);
+ clk_prepare_enable(info->dphy_clk);
+ } else
+ mipi_dbg("mipi csi2 already enabled!\n");
+
+ status = info->mipi_en;
+
+ _mipi_csi2_unlock(info);
+
+ return status;
+}
+EXPORT_SYMBOL(mipi_csi2_enable);
+
+/*!
+ * This function is called to disable the mipi csi2 interface.
+ *
+ * @param info mipi csi2 hander
+ * @return Returns setted value
+ */
+bool mipi_csi2_disable(struct mipi_csi2_info *info)
+{
+ bool status;
+
+ _mipi_csi2_lock(info);
+
+ if (info->mipi_en) {
+ info->mipi_en = false;
+ clk_disable_unprepare(info->dphy_clk);
+ clk_disable_unprepare(info->cfg_clk);
+ } else
+ mipi_dbg("mipi csi2 already disabled!\n");
+
+ status = info->mipi_en;
+
+ _mipi_csi2_unlock(info);
+
+ return status;
+}
+EXPORT_SYMBOL(mipi_csi2_disable);
+
+/*!
+ * This function is called to get mipi csi2 disable/enable status.
+ *
+ * @param info mipi csi2 hander
+ * @return Returns mipi csi2 status
+ */
+bool mipi_csi2_get_status(struct mipi_csi2_info *info)
+{
+ bool status;
+
+ _mipi_csi2_lock(info);
+ status = info->mipi_en;
+ _mipi_csi2_unlock(info);
+
+ return status;
+}
+EXPORT_SYMBOL(mipi_csi2_get_status);
+
+/*!
+ * This function is called to set mipi lanes.
+ *
+ * @param info mipi csi2 hander
+ * @return Returns setted value
+ */
+unsigned int mipi_csi2_set_lanes(struct mipi_csi2_info *info)
+{
+ unsigned int lanes;
+
+ _mipi_csi2_lock(info);
+ mipi_csi2_write(info, info->lanes - 1, MIPI_CSI2_N_LANES);
+ lanes = mipi_csi2_read(info, MIPI_CSI2_N_LANES);
+ _mipi_csi2_unlock(info);
+
+ return lanes;
+}
+EXPORT_SYMBOL(mipi_csi2_set_lanes);
+
+/*!
+ * This function is called to set mipi data type.
+ *
+ * @param info mipi csi2 hander
+ * @return Returns setted value
+ */
+unsigned int mipi_csi2_set_datatype(struct mipi_csi2_info *info,
+ unsigned int datatype)
+{
+ unsigned int dtype;
+
+ _mipi_csi2_lock(info);
+ info->datatype = datatype;
+ dtype = info->datatype;
+ _mipi_csi2_unlock(info);
+
+ return dtype;
+}
+EXPORT_SYMBOL(mipi_csi2_set_datatype);
+
+/*!
+ * This function is called to get mipi data type.
+ *
+ * @param info mipi csi2 hander
+ * @return Returns mipi data type
+ */
+unsigned int mipi_csi2_get_datatype(struct mipi_csi2_info *info)
+{
+ unsigned int dtype;
+
+ _mipi_csi2_lock(info);
+ dtype = info->datatype;
+ _mipi_csi2_unlock(info);
+
+ return dtype;
+}
+EXPORT_SYMBOL(mipi_csi2_get_datatype);
+
+/*!
+ * This function is called to get mipi csi2 dphy status.
+ *
+ * @param info mipi csi2 hander
+ * @return Returns dphy status
+ */
+unsigned int mipi_csi2_dphy_status(struct mipi_csi2_info *info)
+{
+ unsigned int status;
+
+ _mipi_csi2_lock(info);
+ status = mipi_csi2_read(info, MIPI_CSI2_PHY_STATE);
+ _mipi_csi2_unlock(info);
+
+ return status;
+}
+EXPORT_SYMBOL(mipi_csi2_dphy_status);
+
+/*!
+ * This function is called to get mipi csi2 error1 status.
+ *
+ * @param info mipi csi2 hander
+ * @return Returns error1 value
+ */
+unsigned int mipi_csi2_get_error1(struct mipi_csi2_info *info)
+{
+ unsigned int err1;
+
+ _mipi_csi2_lock(info);
+ err1 = mipi_csi2_read(info, MIPI_CSI2_ERR1);
+ _mipi_csi2_unlock(info);
+
+ return err1;
+}
+EXPORT_SYMBOL(mipi_csi2_get_error1);
+
+/*!
+ * This function is called to get mipi csi2 error1 status.
+ *
+ * @param info mipi csi2 hander
+ * @return Returns error1 value
+ */
+unsigned int mipi_csi2_get_error2(struct mipi_csi2_info *info)
+{
+ unsigned int err2;
+
+ _mipi_csi2_lock(info);
+ err2 = mipi_csi2_read(info, MIPI_CSI2_ERR2);
+ _mipi_csi2_unlock(info);
+
+ return err2;
+}
+EXPORT_SYMBOL(mipi_csi2_get_error2);
+
+/*!
+ * This function is called to enable mipi to ipu pixel clock.
+ *
+ * @param info mipi csi2 hander
+ * @return Returns 0 on success or negative error code on fail
+ */
+int mipi_csi2_pixelclk_enable(struct mipi_csi2_info *info)
+{
+ return clk_prepare_enable(info->pixel_clk);
+}
+EXPORT_SYMBOL(mipi_csi2_pixelclk_enable);
+
+/*!
+ * This function is called to disable mipi to ipu pixel clock.
+ *
+ * @param info mipi csi2 hander
+ * @return Returns 0 on success or negative error code on fail
+ */
+void mipi_csi2_pixelclk_disable(struct mipi_csi2_info *info)
+{
+ clk_disable_unprepare(info->pixel_clk);
+}
+EXPORT_SYMBOL(mipi_csi2_pixelclk_disable);
+
+/*!
+ * This function is called to power on mipi csi2.
+ *
+ * @param info mipi csi2 hander
+ * @return Returns 0 on success or negative error code on fail
+ */
+int mipi_csi2_reset(struct mipi_csi2_info *info)
+{
+ _mipi_csi2_lock(info);
+
+ mipi_csi2_write(info, 0x0, MIPI_CSI2_PHY_SHUTDOWNZ);
+ mipi_csi2_write(info, 0x0, MIPI_CSI2_DPHY_RSTZ);
+ mipi_csi2_write(info, 0x0, MIPI_CSI2_CSI2_RESETN);
+
+ mipi_csi2_write(info, 0x00000001, MIPI_CSI2_PHY_TST_CTRL0);
+ mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL1);
+ mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL0);
+ mipi_csi2_write(info, 0x00000002, MIPI_CSI2_PHY_TST_CTRL0);
+ mipi_csi2_write(info, 0x00010044, MIPI_CSI2_PHY_TST_CTRL1);
+ mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL0);
+ mipi_csi2_write(info, 0x00000014, MIPI_CSI2_PHY_TST_CTRL1);
+ mipi_csi2_write(info, 0x00000002, MIPI_CSI2_PHY_TST_CTRL0);
+ mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL0);
+
+ mipi_csi2_write(info, 0xffffffff, MIPI_CSI2_PHY_SHUTDOWNZ);
+ mipi_csi2_write(info, 0xffffffff, MIPI_CSI2_DPHY_RSTZ);
+ mipi_csi2_write(info, 0xffffffff, MIPI_CSI2_CSI2_RESETN);
+
+ _mipi_csi2_unlock(info);
+
+ return 0;
+}
+EXPORT_SYMBOL(mipi_csi2_reset);
+
+/*!
+ * This function is called to get mipi csi2 info.
+ *
+ * @return Returns mipi csi2 info struct pointor
+ */
+struct mipi_csi2_info *mipi_csi2_get_info(void)
+{
+ return gmipi_csi2;
+}
+EXPORT_SYMBOL(mipi_csi2_get_info);
+
+/*!
+ * This function is called to get mipi csi2 bind ipu num.
+ *
+ * @return Returns mipi csi2 bind ipu num
+ */
+int mipi_csi2_get_bind_ipu(struct mipi_csi2_info *info)
+{
+ int ipu_id;
+
+ _mipi_csi2_lock(info);
+ ipu_id = info->ipu_id;
+ _mipi_csi2_unlock(info);
+
+ return ipu_id;
+}
+EXPORT_SYMBOL(mipi_csi2_get_bind_ipu);
+
+/*!
+ * This function is called to get mipi csi2 bind csi num.
+ *
+ * @return Returns mipi csi2 bind csi num
+ */
+unsigned int mipi_csi2_get_bind_csi(struct mipi_csi2_info *info)
+{
+ unsigned int csi_id;
+
+ _mipi_csi2_lock(info);
+ csi_id = info->csi_id;
+ _mipi_csi2_unlock(info);
+
+ return csi_id;
+}
+EXPORT_SYMBOL(mipi_csi2_get_bind_csi);
+
+/*!
+ * This function is called to get mipi csi2 virtual channel.
+ *
+ * @return Returns mipi csi2 virtual channel num
+ */
+unsigned int mipi_csi2_get_virtual_channel(struct mipi_csi2_info *info)
+{
+ unsigned int v_channel;
+
+ _mipi_csi2_lock(info);
+ v_channel = info->v_channel;
+ _mipi_csi2_unlock(info);
+
+ return v_channel;
+}
+EXPORT_SYMBOL(mipi_csi2_get_virtual_channel);
+
+/**
+ * This function is called by the driver framework to initialize the MIPI CSI2
+ * device.
+ *
+ * @param pdev The device structure for the MIPI CSI2 passed in by the
+ * driver framework.
+ *
+ * @return Returns 0 on success or negative error code on error
+ */
+static int mipi_csi2_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res;
+ u32 mipi_csi2_dphy_ver;
+ int ret;
+
+ gmipi_csi2 = kmalloc(sizeof(struct mipi_csi2_info), GFP_KERNEL);
+ if (!gmipi_csi2) {
+ ret = -ENOMEM;
+ goto alloc_failed;
+ }
+
+ ret = of_property_read_u32(np, "ipu_id", &(gmipi_csi2->ipu_id));
+ if (ret) {
+ dev_err(&pdev->dev, "ipu_id missing or invalid\n");
+ goto err;
+ }
+
+ ret = of_property_read_u32(np, "csi_id", &(gmipi_csi2->csi_id));
+ if (ret) {
+ dev_err(&pdev->dev, "csi_id missing or invalid\n");
+ goto err;
+ }
+
+ ret = of_property_read_u32(np, "v_channel", &(gmipi_csi2->v_channel));
+ if (ret) {
+ dev_err(&pdev->dev, "v_channel missing or invalid\n");
+ goto err;
+ }
+
+ ret = of_property_read_u32(np, "lanes", &(gmipi_csi2->lanes));
+ if (ret) {
+ dev_err(&pdev->dev, "lanes missing or invalid\n");
+ goto err;
+ }
+
+ if ((gmipi_csi2->ipu_id < 0) || (gmipi_csi2->ipu_id > 1) ||
+ (gmipi_csi2->csi_id > 1) || (gmipi_csi2->v_channel > 3) ||
+ (gmipi_csi2->lanes > 4)) {
+ dev_err(&pdev->dev, "invalid param for mipi csi2!\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* initialize mutex */
+ mutex_init(&gmipi_csi2->mutex_lock);
+
+ /* get mipi csi2 informaiton */
+ gmipi_csi2->pdev = pdev;
+ gmipi_csi2->mipi_en = false;
+
+ gmipi_csi2->cfg_clk = devm_clk_get(dev, "cfg_clk");
+ if (IS_ERR(gmipi_csi2->cfg_clk)) {
+ dev_err(&pdev->dev, "failed to get cfg_clk\n");
+ ret = PTR_ERR(gmipi_csi2->cfg_clk);
+ goto err;
+ }
+
+ /* get mipi dphy clk */
+ gmipi_csi2->dphy_clk = devm_clk_get(dev, "dphy_clk");
+ if (IS_ERR(gmipi_csi2->dphy_clk)) {
+ dev_err(&pdev->dev, "failed to get dphy pll_ref_clk\n");
+ ret = PTR_ERR(gmipi_csi2->dphy_clk);
+ goto err;
+ }
+
+ /* get mipi to ipu pixel clk */
+ gmipi_csi2->pixel_clk = devm_clk_get(dev, "pixel_clk");
+ if (IS_ERR(gmipi_csi2->pixel_clk)) {
+ dev_err(&pdev->dev, "failed to get mipi pixel clk\n");
+ ret = PTR_ERR(gmipi_csi2->pixel_clk);
+ goto err;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ /* mipi register mapping */
+ gmipi_csi2->mipi_csi2_base = ioremap(res->start, PAGE_SIZE);
+ if (!gmipi_csi2->mipi_csi2_base) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* mipi dphy clk enable for register access */
+ clk_prepare_enable(gmipi_csi2->dphy_clk);
+ /* get mipi csi2 dphy version */
+ mipi_csi2_dphy_ver = mipi_csi2_read(gmipi_csi2, MIPI_CSI2_VERSION);
+
+ clk_disable_unprepare(gmipi_csi2->dphy_clk);
+
+ platform_set_drvdata(pdev, gmipi_csi2);
+
+ dev_info(&pdev->dev, "i.MX MIPI CSI2 driver probed\n");
+ dev_info(&pdev->dev, "i.MX MIPI CSI2 dphy version is 0x%x\n",
+ mipi_csi2_dphy_ver);
+
+ return 0;
+
+err:
+ kfree(gmipi_csi2);
+alloc_failed:
+ dev_err(&pdev->dev, "i.MX MIPI CSI2 driver probed - error\n");
+ return ret;
+}
+
+static int mipi_csi2_remove(struct platform_device *pdev)
+{
+ /* unmapping mipi register */
+ iounmap(gmipi_csi2->mipi_csi2_base);
+
+ kfree(gmipi_csi2);
+
+ dev_set_drvdata(&pdev->dev, NULL);
+
+ return 0;
+}
+
+static const struct of_device_id imx_mipi_csi2_dt_ids[] = {
+ { .compatible = "fsl,imx6q-mipi-csi2", },
+ { /* sentinel */ }
+};
+
+static struct platform_driver mipi_csi2_driver = {
+ .driver = {
+ .name = "mxc_mipi_csi2",
+ .of_match_table = imx_mipi_csi2_dt_ids,
+ },
+ .probe = mipi_csi2_probe,
+ .remove = mipi_csi2_remove,
+};
+
+static int __init mipi_csi2_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&mipi_csi2_driver);
+ if (err) {
+ pr_err("mipi_csi2_driver register failed\n");
+ return -ENODEV;
+ }
+
+ pr_info("MIPI CSI2 driver module loaded\n");
+
+ return 0;
+}
+
+static void __exit mipi_csi2_cleanup(void)
+{
+ platform_driver_unregister(&mipi_csi2_driver);
+}
+
+subsys_initcall(mipi_csi2_init);
+module_exit(mipi_csi2_cleanup);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX MIPI CSI2 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mxc/mipi/mxc_mipi_csi2.h b/drivers/mxc/mipi/mxc_mipi_csi2.h
new file mode 100644
index 000000000000..291d7e891e09
--- /dev/null
+++ b/drivers/mxc/mipi/mxc_mipi_csi2.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __MXC_MIPI_CSI2_H__
+#define __MXC_MIPI_CSI2_H__
+
+#ifdef DEBUG
+#define mipi_dbg(fmt, ...) \
+ printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
+#else
+#define mipi_dbg(fmt, ...)
+#endif
+
+/* driver private data */
+struct mipi_csi2_info {
+ bool mipi_en;
+ int ipu_id;
+ unsigned int csi_id;
+ unsigned int v_channel;
+ unsigned int lanes;
+ unsigned int datatype;
+ struct clk *cfg_clk;
+ struct clk *dphy_clk;
+ struct clk *pixel_clk;
+ void __iomem *mipi_csi2_base;
+ struct platform_device *pdev;
+
+ struct mutex mutex_lock;
+};
+
+#endif
diff --git a/drivers/mxc/mlb/Kconfig b/drivers/mxc/mlb/Kconfig
new file mode 100644
index 000000000000..343f884b9221
--- /dev/null
+++ b/drivers/mxc/mlb/Kconfig
@@ -0,0 +1,17 @@
+#
+# MLB150 configuration
+#
+
+menu "MXC Media Local Bus Driver"
+
+config MXC_MLB
+ boolean
+
+config MXC_MLB150
+ tristate "MLB150 support"
+ depends on (SOC_IMX6Q || SOC_IMX6SX || ARCH_FSL_IMX8QM || ARCH_FSL_IMX8QXP)
+ select MXC_MLB
+ ---help---
+ Say Y to get the MLB150 support.
+
+endmenu
diff --git a/drivers/mxc/mlb/Makefile b/drivers/mxc/mlb/Makefile
new file mode 100644
index 000000000000..e71005a3788f
--- /dev/null
+++ b/drivers/mxc/mlb/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the i.MX6Q/DL MLB150 driver
+#
+
+obj-$(CONFIG_MXC_MLB150) += mxc_mlb.o
diff --git a/drivers/mxc/mlb/mxc_mlb.c b/drivers/mxc/mlb/mxc_mlb.c
new file mode 100755
index 000000000000..a664118f6aad
--- /dev/null
+++ b/drivers/mxc/mlb/mxc_mlb.c
@@ -0,0 +1,2812 @@
+/*
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/cdev.h>
+#include <linux/circ_buf.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/genalloc.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mxc_mlb.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+
+#define DRIVER_NAME "mxc_mlb150"
+
+/*
+ * MLB module memory map registers define
+ */
+#define REG_MLBC0 0x0
+#define MLBC0_MLBEN (0x1)
+#define MLBC0_MLBCLK_MASK (0x7 << 2)
+#define MLBC0_MLBCLK_SHIFT (2)
+#define MLBC0_MLBPEN (0x1 << 5)
+#define MLBC0_MLBLK (0x1 << 7)
+#define MLBC0_ASYRETRY (0x1 << 12)
+#define MLBC0_CTLRETRY (0x1 << 12)
+#define MLBC0_FCNT_MASK (0x7 << 15)
+#define MLBC0_FCNT_SHIFT (15)
+
+#define REG_MLBPC0 0x8
+#define MLBPC0_MCLKHYS (0x1 << 11)
+
+#define REG_MS0 0xC
+#define REG_MS1 0x14
+
+#define REG_MSS 0x20
+#define MSS_RSTSYSCMD (0x1)
+#define MSS_LKSYSCMD (0x1 << 1)
+#define MSS_ULKSYSCMD (0x1 << 2)
+#define MSS_CSSYSCMD (0x1 << 3)
+#define MSS_SWSYSCMD (0x1 << 4)
+#define MSS_SERVREQ (0x1 << 5)
+
+#define REG_MSD 0x24
+
+#define REG_MIEN 0x2C
+#define MIEN_ISOC_PE (0x1)
+#define MIEN_ISOC_BUFO (0x1 << 1)
+#define MIEN_SYNC_PE (0x1 << 16)
+#define MIEN_ARX_DONE (0x1 << 17)
+#define MIEN_ARX_PE (0x1 << 18)
+#define MIEN_ARX_BREAK (0x1 << 19)
+#define MIEN_ATX_DONE (0x1 << 20)
+#define MIEN_ATX_PE (0x1 << 21)
+#define MIEN_ATX_BREAK (0x1 << 22)
+#define MIEN_CRX_DONE (0x1 << 24)
+#define MIEN_CRX_PE (0x1 << 25)
+#define MIEN_CRX_BREAK (0x1 << 26)
+#define MIEN_CTX_DONE (0x1 << 27)
+#define MIEN_CTX_PE (0x1 << 28)
+#define MIEN_CTX_BREAK (0x1 << 29)
+
+#define REG_MLBPC2 0x34
+#define REG_MLBPC1 0x38
+#define MLBPC1_VAL (0x00000888)
+
+#define REG_MLBC1 0x3C
+#define MLBC1_LOCK (0x1 << 6)
+#define MLBC1_CLKM (0x1 << 7)
+#define MLBC1_NDA_MASK (0xFF << 8)
+#define MLBC1_NDA_SHIFT (8)
+
+#define REG_HCTL 0x80
+#define HCTL_RST0 (0x1)
+#define HCTL_RST1 (0x1 << 1)
+#define HCTL_EN (0x1 << 15)
+
+#define REG_HCMR0 0x88
+#define REG_HCMR1 0x8C
+#define REG_HCER0 0x90
+#define REG_HCER1 0x94
+#define REG_HCBR0 0x98
+#define REG_HCBR1 0x9C
+
+#define REG_MDAT0 0xC0
+#define REG_MDAT1 0xC4
+#define REG_MDAT2 0xC8
+#define REG_MDAT3 0xCC
+
+#define REG_MDWE0 0xD0
+#define REG_MDWE1 0xD4
+#define REG_MDWE2 0xD8
+#define REG_MDWE3 0xDC
+
+#define REG_MCTL 0xE0
+#define MCTL_XCMP (0x1)
+
+#define REG_MADR 0xE4
+#define MADR_WNR (0x1 << 31)
+#define MADR_TB (0x1 << 30)
+#define MADR_ADDR_MASK (0x7f << 8)
+#define MADR_ADDR_SHIFT (0)
+
+#define REG_ACTL 0x3C0
+#define ACTL_MPB (0x1 << 4)
+#define ACTL_DMAMODE (0x1 << 2)
+#define ACTL_SMX (0x1 << 1)
+#define ACTL_SCE (0x1)
+
+#define REG_ACSR0 0x3D0
+#define REG_ACSR1 0x3D4
+#define REG_ACMR0 0x3D8
+#define REG_ACMR1 0x3DC
+
+#define REG_CAT_MDATn(ch) (REG_MDAT0 + ((ch % 8) >> 1) * 4)
+#define REG_CAT_MDWEn(ch) (REG_MDWE0 + ((ch % 8) >> 1) * 4)
+
+#define INT_AHB0_CH_START (0)
+#define INT_AHB1_CH_START (32)
+
+#define LOGIC_CH_NUM (64)
+#define BUF_CDT_OFFSET (0x0)
+#define BUF_ADT_OFFSET (0x40)
+#define BUF_CAT_MLB_OFFSET (0x80)
+#define BUF_CAT_HBI_OFFSET (0x88)
+#define BUF_CTR_END_OFFSET (0x8F)
+
+#define CAT_MODE_RX (0x1 << 0)
+#define CAT_MODE_TX (0x1 << 1)
+#define CAT_MODE_INBOUND_DMA (0x1 << 8)
+#define CAT_MODE_OUTBOUND_DMA (0x1 << 9)
+
+#define CH_SYNC_DEFAULT_QUAD (1)
+#define CH_SYNC_MAX_QUAD (15)
+#define CH_SYNC_CDT_BUF_DEP (CH_SYNC_DEFAULT_QUAD * 4 * 4)
+#define CH_SYNC_ADT_BUF_MULTI (4)
+#define CH_SYNC_ADT_BUF_DEP (CH_SYNC_CDT_BUF_DEP * CH_SYNC_ADT_BUF_MULTI)
+#define CH_SYNC_BUF_SZ (CH_SYNC_MAX_QUAD * 4 * 4 * \
+ CH_SYNC_ADT_BUF_MULTI)
+#define CH_CTRL_CDT_BUF_DEP (64)
+#define CH_CTRL_ADT_BUF_DEP (CH_CTRL_CDT_BUF_DEP)
+#define CH_CTRL_BUF_SZ (CH_CTRL_ADT_BUF_DEP)
+#define CH_ASYNC_MDP_PACKET_LEN (1024)
+#define CH_ASYNC_MEP_PACKET_LEN (1536)
+#define CH_ASYNC_CDT_BUF_DEP (CH_ASYNC_MEP_PACKET_LEN)
+#define CH_ASYNC_ADT_BUF_DEP (CH_ASYNC_CDT_BUF_DEP)
+#define CH_ASYNC_BUF_SZ (CH_ASYNC_ADT_BUF_DEP)
+#define CH_ISOC_BLK_SIZE_188 (188)
+#define CH_ISOC_BLK_SIZE_196 (196)
+#define CH_ISOC_BLK_SIZE (CH_ISOC_BLK_SIZE_188)
+#define CH_ISOC_BLK_NUM (1)
+#define CH_ISOC_CDT_BUF_DEP (CH_ISOC_BLK_SIZE * CH_ISOC_BLK_NUM)
+#define CH_ISOC_ADT_BUF_DEP (CH_ISOC_CDT_BUF_DEP)
+#define CH_ISOC_BUF_SZ (1024)
+
+#define CH_SYNC_DBR_BUF_OFFSET (0x0)
+#define CH_CTRL_DBR_BUF_OFFSET (CH_SYNC_DBR_BUF_OFFSET + \
+ 2 * (CH_SYNC_MAX_QUAD * 4 * 4))
+#define CH_ASYNC_DBR_BUF_OFFSET (CH_CTRL_DBR_BUF_OFFSET + \
+ 2 * CH_CTRL_CDT_BUF_DEP)
+#define CH_ISOC_DBR_BUF_OFFSET (CH_ASYNC_DBR_BUF_OFFSET + \
+ 2 * CH_ASYNC_CDT_BUF_DEP)
+
+#define DBR_BUF_START 0x00000
+
+#define CDT_LEN (16)
+#define ADT_LEN (16)
+#define CAT_LEN (2)
+
+#define CDT_SZ (CDT_LEN * LOGIC_CH_NUM)
+#define ADT_SZ (ADT_LEN * LOGIC_CH_NUM)
+#define CAT_SZ (CAT_LEN * LOGIC_CH_NUM * 2)
+
+#define CDT_BASE(base) (base + BUF_CDT_OFFSET)
+#define ADT_BASE(base) (base + BUF_ADT_OFFSET)
+#define CAT_MLB_BASE(base) (base + BUF_CAT_MLB_OFFSET)
+#define CAT_HBI_BASE(base) (base + BUF_CAT_HBI_OFFSET)
+
+#define CDTn_ADDR(base, n) (base + BUF_CDT_OFFSET + n * CDT_LEN)
+#define ADTn_ADDR(base, n) (base + BUF_ADT_OFFSET + n * ADT_LEN)
+#define CATn_MLB_ADDR(base, n) (base + BUF_CAT_MLB_OFFSET + n * CAT_LEN)
+#define CATn_HBI_ADDR(base, n) (base + BUF_CAT_HBI_OFFSET + n * CAT_LEN)
+
+#define CAT_CL_SHIFT (0x0)
+#define CAT_CT_SHIFT (8)
+#define CAT_CE (0x1 << 11)
+#define CAT_RNW (0x1 << 12)
+#define CAT_MT (0x1 << 13)
+#define CAT_FCE (0x1 << 14)
+#define CAT_MFE (0x1 << 14)
+
+#define CDT_WSBC_SHIFT (14)
+#define CDT_WPC_SHIFT (11)
+#define CDT_RSBC_SHIFT (30)
+#define CDT_RPC_SHIFT (27)
+#define CDT_WPC_1_SHIFT (12)
+#define CDT_RPC_1_SHIFT (28)
+#define CDT_WPTR_SHIFT (0)
+#define CDT_SYNC_WSTS_MASK (0x0000f000)
+#define CDT_SYNC_WSTS_SHIFT (12)
+#define CDT_CTRL_ASYNC_WSTS_MASK (0x0000f000)
+#define CDT_CTRL_ASYNC_WSTS_SHIFT (12)
+#define CDT_ISOC_WSTS_MASK (0x0000e000)
+#define CDT_ISOC_WSTS_SHIFT (13)
+#define CDT_RPTR_SHIFT (16)
+#define CDT_SYNC_RSTS_MASK (0xf0000000)
+#define CDT_SYNC_RSTS_SHIFT (28)
+#define CDT_CTRL_ASYNC_RSTS_MASK (0xf0000000)
+#define CDT_CTRL_ASYNC_RSTS_SHIFT (28)
+#define CDT_ISOC_RSTS_MASK (0xe0000000)
+#define CDT_ISOC_RSTS_SHIFT (29)
+#define CDT_CTRL_ASYNC_WSTS_1 (0x1 << 14)
+#define CDT_CTRL_ASYNC_RSTS_1 (0x1 << 15)
+#define CDT_BD_SHIFT (0)
+#define CDT_BA_SHIFT (16)
+#define CDT_BS_SHIFT (0)
+#define CDT_BF_SHIFT (31)
+
+#define ADT_PG (0x1 << 13)
+#define ADT_LE (0x1 << 14)
+#define ADT_CE (0x1 << 15)
+#define ADT_BD1_SHIFT (0)
+#define ADT_ERR1 (0x1 << 13)
+#define ADT_DNE1 (0x1 << 14)
+#define ADT_RDY1 (0x1 << 15)
+#define ADT_BD2_SHIFT (16)
+#define ADT_ERR2 (0x1 << 29)
+#define ADT_DNE2 (0x1 << 30)
+#define ADT_RDY2 (0x1 << 31)
+#define ADT_BA1_SHIFT (0x0)
+#define ADT_BA2_SHIFT (0x0)
+#define ADT_PS1 (0x1 << 12)
+#define ADT_PS2 (0x1 << 28)
+#define ADT_MEP1 (0x1 << 11)
+#define ADT_MEP2 (0x1 << 27)
+
+#define MLB_MINOR_DEVICES 4
+#define MLB_CONTROL_DEV_NAME "ctrl"
+#define MLB_ASYNC_DEV_NAME "async"
+#define MLB_SYNC_DEV_NAME "sync"
+#define MLB_ISOC_DEV_NAME "isoc"
+
+#define TX_CHANNEL 0
+#define RX_CHANNEL 1
+
+#define TRANS_RING_NODES (1 << 3)
+#define MLB_QUIRK_MLB150 (1 << 0)
+
+enum MLB_CTYPE {
+ MLB_CTYPE_SYNC,
+ MLB_CTYPE_CTRL,
+ MLB_CTYPE_ASYNC,
+ MLB_CTYPE_ISOC,
+};
+
+enum CLK_SPEED {
+ CLK_256FS,
+ CLK_512FS,
+ CLK_1024FS,
+ CLK_2048FS,
+ CLK_3072FS,
+ CLK_4096FS,
+ CLK_6144FS,
+ CLK_8192FS,
+};
+
+enum MLB_INDEX {
+ IMX6Q_MLB = 0,
+ IMX6SX_MLB,
+};
+
+struct mlb_ringbuf {
+ s8 *virt_bufs[TRANS_RING_NODES];
+ u32 phy_addrs[TRANS_RING_NODES];
+ s32 head;
+ s32 tail;
+ s32 unit_size;
+ s32 total_size;
+ rwlock_t rb_lock ____cacheline_aligned; /* ring index lock */
+};
+
+struct mlb_channel_info {
+ /* Input MLB channel address */
+ u32 address;
+ /* Internal AHB channel label */
+ u32 cl;
+ /* DBR buf head */
+ u32 dbr_buf_head;
+};
+
+struct mlb_dev_info {
+ /* device node name */
+ const char dev_name[20];
+ /* channel type */
+ const unsigned int channel_type;
+ /* ch fps */
+ enum CLK_SPEED fps;
+ /* channel info for tx/rx */
+ struct mlb_channel_info channels[2];
+ /* ring buffer */
+ u8 *rbuf_base_virt;
+ u32 rbuf_base_phy;
+ struct mlb_ringbuf rx_rbuf;
+ struct mlb_ringbuf tx_rbuf;
+ /* exception event */
+ unsigned long ex_event;
+ /* tx busy indicator */
+ unsigned long tx_busy;
+ /* channel started up or not */
+ atomic_t on;
+ /* device open count */
+ atomic_t opencnt;
+ /* wait queue head for channel */
+ wait_queue_head_t rx_wq;
+ wait_queue_head_t tx_wq;
+ /* TX OK */
+ s32 tx_ok;
+ /* spinlock for event access */
+ spinlock_t event_lock;
+ /*
+ * Block size for isoc mode
+ * This variable can be configured in ioctl
+ */
+ u32 isoc_blksz;
+ /*
+ * Quads number for sync mode
+ * This variable can be confifured in ioctl
+ */
+ u32 sync_quad;
+ /* Buffer depth in cdt */
+ u32 cdt_buf_dep;
+ /* Buffer depth in adt */
+ u32 adt_buf_dep;
+ /* Buffer size to hold data */
+ u32 buf_size;
+};
+
+struct mlb_data {
+ struct device *dev;
+ struct mlb_dev_info *devinfo;
+#ifdef CONFIG_ARCH_MXC_ARM64
+ struct clk *ipg;
+ struct clk *hclk;
+#endif
+ struct clk *mlb;
+ struct cdev cdev;
+ struct class *class; /* device class */
+ dev_t firstdev;
+#ifdef CONFIG_REGULATOR
+ struct regulator *nvcc;
+#endif
+ void __iomem *membase; /* mlb module base address */
+ struct gen_pool *iram_pool;
+ u32 iram_size;
+ int irq_ahb0;
+ int irq_ahb1;
+ int irq_mlb;
+ u32 quirk_flag;
+ bool use_iram;
+};
+
+/*
+ * For optimization, we use fixed channel label for
+ * input channels of each mode
+ * SYNC: CL = 0 for RX, CL = 64 for TX
+ * CTRL: CL = 1 for RX, CL = 65 for TX
+ * ASYNC: CL = 2 for RX, CL = 66 for TX
+ * ISOC: CL = 3 for RX, CL = 67 for TX
+ */
+#define SYNC_RX_CL_AHB0 0
+#define CTRL_RX_CL_AHB0 1
+#define ASYNC_RX_CL_AHB0 2
+#define ISOC_RX_CL_AHB0 3
+#define SYNC_TX_CL_AHB0 4
+#define CTRL_TX_CL_AHB0 5
+#define ASYNC_TX_CL_AHB0 6
+#define ISOC_TX_CL_AHB0 7
+
+#define SYNC_RX_CL_AHB1 32
+#define CTRL_RX_CL_AHB1 33
+#define ASYNC_RX_CL_AHB1 34
+#define ISOC_RX_CL_AHB1 35
+#define SYNC_TX_CL_AHB1 36
+#define CTRL_TX_CL_AHB1 37
+#define ASYNC_TX_CL_AHB1 38
+#define ISOC_TX_CL_AHB1 39
+
+#define SYNC_RX_CL SYNC_RX_CL_AHB0
+#define CTRL_RX_CL CTRL_RX_CL_AHB0
+#define ASYNC_RX_CL ASYNC_RX_CL_AHB0
+#define ISOC_RX_CL ISOC_RX_CL_AHB0
+
+#define SYNC_TX_CL SYNC_TX_CL_AHB0
+#define CTRL_TX_CL CTRL_TX_CL_AHB0
+#define ASYNC_TX_CL ASYNC_TX_CL_AHB0
+#define ISOC_TX_CL ISOC_TX_CL_AHB0
+
+static struct mlb_dev_info mlb_devinfo[MLB_MINOR_DEVICES] = {
+ {
+ .dev_name = MLB_SYNC_DEV_NAME,
+ .channel_type = MLB_CTYPE_SYNC,
+ .channels = {
+ [0] = {
+ .cl = SYNC_TX_CL,
+ .dbr_buf_head = CH_SYNC_DBR_BUF_OFFSET,
+ },
+ [1] = {
+ .cl = SYNC_RX_CL,
+ .dbr_buf_head = CH_SYNC_DBR_BUF_OFFSET
+ + CH_SYNC_BUF_SZ,
+ },
+ },
+ .rx_rbuf = {
+ .unit_size = CH_SYNC_BUF_SZ,
+ .rb_lock =
+ __RW_LOCK_UNLOCKED(mlb_devinfo[0].rx_rbuf.rb_lock),
+ },
+ .tx_rbuf = {
+ .unit_size = CH_SYNC_BUF_SZ,
+ .rb_lock =
+ __RW_LOCK_UNLOCKED(mlb_devinfo[0].tx_rbuf.rb_lock),
+ },
+ .cdt_buf_dep = CH_SYNC_CDT_BUF_DEP,
+ .adt_buf_dep = CH_SYNC_ADT_BUF_DEP,
+ .buf_size = CH_SYNC_BUF_SZ,
+ .on = ATOMIC_INIT(0),
+ .opencnt = ATOMIC_INIT(0),
+ .event_lock = __SPIN_LOCK_UNLOCKED(mlb_devinfo[0].event_lock),
+ },
+ {
+ .dev_name = MLB_CONTROL_DEV_NAME,
+ .channel_type = MLB_CTYPE_CTRL,
+ .channels = {
+ [0] = {
+ .cl = CTRL_TX_CL,
+ .dbr_buf_head = CH_CTRL_DBR_BUF_OFFSET,
+ },
+ [1] = {
+ .cl = CTRL_RX_CL,
+ .dbr_buf_head = CH_CTRL_DBR_BUF_OFFSET
+ + CH_CTRL_BUF_SZ,
+ },
+ },
+ .rx_rbuf = {
+ .unit_size = CH_CTRL_BUF_SZ,
+ .rb_lock =
+ __RW_LOCK_UNLOCKED(mlb_devinfo[1].rx_rbuf.rb_lock),
+ },
+ .tx_rbuf = {
+ .unit_size = CH_CTRL_BUF_SZ,
+ .rb_lock =
+ __RW_LOCK_UNLOCKED(mlb_devinfo[1].tx_rbuf.rb_lock),
+ },
+ .cdt_buf_dep = CH_CTRL_CDT_BUF_DEP,
+ .adt_buf_dep = CH_CTRL_ADT_BUF_DEP,
+ .buf_size = CH_CTRL_BUF_SZ,
+ .on = ATOMIC_INIT(0),
+ .opencnt = ATOMIC_INIT(0),
+ .event_lock = __SPIN_LOCK_UNLOCKED(mlb_devinfo[1].event_lock),
+ },
+ {
+ .dev_name = MLB_ASYNC_DEV_NAME,
+ .channel_type = MLB_CTYPE_ASYNC,
+ .channels = {
+ [0] = {
+ .cl = ASYNC_TX_CL,
+ .dbr_buf_head = CH_ASYNC_DBR_BUF_OFFSET,
+ },
+ [1] = {
+ .cl = ASYNC_RX_CL,
+ .dbr_buf_head = CH_ASYNC_DBR_BUF_OFFSET
+ + CH_ASYNC_BUF_SZ,
+ },
+ },
+ .rx_rbuf = {
+ .unit_size = CH_ASYNC_BUF_SZ,
+ .rb_lock =
+ __RW_LOCK_UNLOCKED(mlb_devinfo[2].rx_rbuf.rb_lock),
+ },
+ .tx_rbuf = {
+ .unit_size = CH_ASYNC_BUF_SZ,
+ .rb_lock =
+ __RW_LOCK_UNLOCKED(mlb_devinfo[2].tx_rbuf.rb_lock),
+ },
+ .cdt_buf_dep = CH_ASYNC_CDT_BUF_DEP,
+ .adt_buf_dep = CH_ASYNC_ADT_BUF_DEP,
+ .buf_size = CH_ASYNC_BUF_SZ,
+ .on = ATOMIC_INIT(0),
+ .opencnt = ATOMIC_INIT(0),
+ .event_lock = __SPIN_LOCK_UNLOCKED(mlb_devinfo[2].event_lock),
+ },
+ {
+ .dev_name = MLB_ISOC_DEV_NAME,
+ .channel_type = MLB_CTYPE_ISOC,
+ .channels = {
+ [0] = {
+ .cl = ISOC_TX_CL,
+ .dbr_buf_head = CH_ISOC_DBR_BUF_OFFSET,
+ },
+ [1] = {
+ .cl = ISOC_RX_CL,
+ .dbr_buf_head = CH_ISOC_DBR_BUF_OFFSET
+ + CH_ISOC_BUF_SZ,
+ },
+ },
+ .rx_rbuf = {
+ .unit_size = CH_ISOC_BUF_SZ,
+ .rb_lock =
+ __RW_LOCK_UNLOCKED(mlb_devinfo[3].rx_rbuf.rb_lock),
+ },
+ .tx_rbuf = {
+ .unit_size = CH_ISOC_BUF_SZ,
+ .rb_lock =
+ __RW_LOCK_UNLOCKED(mlb_devinfo[3].tx_rbuf.rb_lock),
+ },
+ .cdt_buf_dep = CH_ISOC_CDT_BUF_DEP,
+ .adt_buf_dep = CH_ISOC_ADT_BUF_DEP,
+ .buf_size = CH_ISOC_BUF_SZ,
+ .on = ATOMIC_INIT(0),
+ .opencnt = ATOMIC_INIT(0),
+ .event_lock = __SPIN_LOCK_UNLOCKED(mlb_devinfo[3].event_lock),
+ .isoc_blksz = CH_ISOC_BLK_SIZE_188,
+ },
+};
+
+static void __iomem *mlb_base;
+
+DEFINE_SPINLOCK(ctr_lock);
+
+#ifdef DEBUG
+#define DUMP_REG(reg) pr_debug(#reg": 0x%08x\n", __raw_readl(mlb_base + reg))
+
+static void mlb150_dev_dump_reg(void)
+{
+ pr_debug("mxc_mlb150: Dump registers:\n");
+ DUMP_REG(REG_MLBC0);
+ DUMP_REG(REG_MLBPC0);
+ DUMP_REG(REG_MS0);
+ DUMP_REG(REG_MS1);
+ DUMP_REG(REG_MSS);
+ DUMP_REG(REG_MSD);
+ DUMP_REG(REG_MIEN);
+ DUMP_REG(REG_MLBPC2);
+ DUMP_REG(REG_MLBPC1);
+ DUMP_REG(REG_MLBC1);
+ DUMP_REG(REG_HCTL);
+ DUMP_REG(REG_HCMR0);
+ DUMP_REG(REG_HCMR1);
+ DUMP_REG(REG_HCER0);
+ DUMP_REG(REG_HCER1);
+ DUMP_REG(REG_HCBR0);
+ DUMP_REG(REG_HCBR1);
+ DUMP_REG(REG_MDAT0);
+ DUMP_REG(REG_MDAT1);
+ DUMP_REG(REG_MDAT2);
+ DUMP_REG(REG_MDAT3);
+ DUMP_REG(REG_MDWE0);
+ DUMP_REG(REG_MDWE1);
+ DUMP_REG(REG_MDWE2);
+ DUMP_REG(REG_MDWE3);
+ DUMP_REG(REG_MCTL);
+ DUMP_REG(REG_MADR);
+ DUMP_REG(REG_ACTL);
+ DUMP_REG(REG_ACSR0);
+ DUMP_REG(REG_ACSR1);
+ DUMP_REG(REG_ACMR0);
+ DUMP_REG(REG_ACMR1);
+}
+
+static void mlb150_dev_dump_hex(const u8 *buf, u32 len)
+{
+ print_hex_dump(KERN_DEBUG, "CTR DUMP:",
+ DUMP_PREFIX_OFFSET, 8, 1, buf, len, 0);
+}
+#endif
+
+static inline void mlb150_dev_enable_ctr_write(u32 mdat0_bits_en,
+ u32 mdat1_bits_en, u32 mdat2_bits_en, u32 mdat3_bits_en)
+{
+ __raw_writel(mdat0_bits_en, mlb_base + REG_MDWE0);
+ __raw_writel(mdat1_bits_en, mlb_base + REG_MDWE1);
+ __raw_writel(mdat2_bits_en, mlb_base + REG_MDWE2);
+ __raw_writel(mdat3_bits_en, mlb_base + REG_MDWE3);
+}
+
+#ifdef DEBUG
+static inline u8 mlb150_dev_dbr_read(u32 dbr_addr)
+{
+ s32 timeout = 1000;
+ u8 dbr_val = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctr_lock, flags);
+ __raw_writel(MADR_TB | dbr_addr,
+ mlb_base + REG_MADR);
+
+ while ((!(__raw_readl(mlb_base + REG_MCTL)
+ & MCTL_XCMP)) &&
+ timeout--)
+ ;
+
+ if (0 == timeout) {
+ spin_unlock_irqrestore(&ctr_lock, flags);
+ return -ETIME;
+ }
+
+ dbr_val = __raw_readl(mlb_base + REG_MDAT0) & 0x000000ff;
+
+ __raw_writel(0, mlb_base + REG_MCTL);
+ spin_unlock_irqrestore(&ctr_lock, flags);
+
+ return dbr_val;
+}
+
+static inline s32 mlb150_dev_dbr_write(u32 dbr_addr, u8 dbr_val)
+{
+ s32 timeout = 1000;
+ u32 mdat0 = dbr_val & 0x000000ff;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctr_lock, flags);
+ __raw_writel(mdat0, mlb_base + REG_MDAT0);
+
+ __raw_writel(MADR_WNR | MADR_TB | dbr_addr,
+ mlb_base + REG_MADR);
+
+ while ((!(__raw_readl(mlb_base + REG_MCTL)
+ & MCTL_XCMP)) &&
+ timeout--)
+ ;
+
+ if (timeout <= 0) {
+ spin_unlock_irqrestore(&ctr_lock, flags);
+ return -ETIME;
+ }
+
+ __raw_writel(0, mlb_base + REG_MCTL);
+ spin_unlock_irqrestore(&ctr_lock, flags);
+
+ return 0;
+}
+
+static inline s32 mlb150_dev_dbr_dump(u32 addr, u32 size)
+{
+ u8 *dump_buf = NULL;
+ u8 *buf_ptr = NULL;
+ s32 i;
+
+ dump_buf = kzalloc(size, GFP_KERNEL);
+ if (!dump_buf) {
+ pr_err("can't allocate enough memory\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0, buf_ptr = dump_buf;
+ i < size; ++i, ++buf_ptr)
+ *buf_ptr = mlb150_dev_dbr_read(addr + i);
+
+ mlb150_dev_dump_hex(dump_buf, size);
+
+ kfree(dump_buf);
+
+ return 0;
+}
+#endif
+
+static s32 mlb150_dev_ctr_read(u32 ctr_offset, u32 *ctr_val)
+{
+ s32 timeout = 1000;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctr_lock, flags);
+ __raw_writel(ctr_offset, mlb_base + REG_MADR);
+
+ while ((!(__raw_readl(mlb_base + REG_MCTL)
+ & MCTL_XCMP)) &&
+ timeout--)
+ ;
+
+ if (timeout <= 0) {
+ spin_unlock_irqrestore(&ctr_lock, flags);
+ pr_debug("mxc_mlb150: Read CTR timeout\n");
+ return -ETIME;
+ }
+
+ ctr_val[0] = __raw_readl(mlb_base + REG_MDAT0);
+ ctr_val[1] = __raw_readl(mlb_base + REG_MDAT1);
+ ctr_val[2] = __raw_readl(mlb_base + REG_MDAT2);
+ ctr_val[3] = __raw_readl(mlb_base + REG_MDAT3);
+
+ __raw_writel(0, mlb_base + REG_MCTL);
+
+ spin_unlock_irqrestore(&ctr_lock, flags);
+
+ return 0;
+}
+
+static s32 mlb150_dev_ctr_write(u32 ctr_offset, const u32 *ctr_val)
+{
+ s32 timeout = 1000;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctr_lock, flags);
+
+ __raw_writel(ctr_val[0], mlb_base + REG_MDAT0);
+ __raw_writel(ctr_val[1], mlb_base + REG_MDAT1);
+ __raw_writel(ctr_val[2], mlb_base + REG_MDAT2);
+ __raw_writel(ctr_val[3], mlb_base + REG_MDAT3);
+
+ __raw_writel(MADR_WNR | ctr_offset,
+ mlb_base + REG_MADR);
+
+ while ((!(__raw_readl(mlb_base + REG_MCTL)
+ & MCTL_XCMP)) &&
+ timeout--)
+ ;
+
+ if (timeout <= 0) {
+ spin_unlock_irqrestore(&ctr_lock, flags);
+ pr_debug("mxc_mlb150: Write CTR timeout\n");
+ return -ETIME;
+ }
+
+ __raw_writel(0, mlb_base + REG_MCTL);
+
+ spin_unlock_irqrestore(&ctr_lock, flags);
+
+#ifdef DEBUG_CTR
+ {
+ u32 ctr_rd[4] = { 0 };
+
+ if (!mlb150_dev_ctr_read(ctr_offset, ctr_rd)) {
+ if (ctr_val[0] == ctr_rd[0] &&
+ ctr_val[1] == ctr_rd[1] &&
+ ctr_val[2] == ctr_rd[2] &&
+ ctr_val[3] == ctr_rd[3])
+ return 0;
+ else {
+ pr_debug("mxc_mlb150: ctr write failed\n");
+ pr_debug("offset: 0x%x\n", ctr_offset);
+ pr_debug("Write: 0x%x 0x%x 0x%x 0x%x\n",
+ ctr_val[3], ctr_val[2],
+ ctr_val[1], ctr_val[0]);
+ pr_debug("Read: 0x%x 0x%x 0x%x 0x%x\n",
+ ctr_rd[3], ctr_rd[2],
+ ctr_rd[1], ctr_rd[0]);
+ return -EBADE;
+ }
+ } else {
+ pr_debug("mxc_mlb150: ctr read failed\n");
+ return -EBADE;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+#ifdef DEBUG
+static s32 mlb150_dev_cat_read(u32 ctr_offset, u32 ch, u16 *cat_val)
+{
+ u16 ctr_val[8] = { 0 };
+
+ if (mlb150_dev_ctr_read(ctr_offset, (u32 *)ctr_val))
+ return -ETIME;
+
+ /*
+ * Use u16 array to get u32 array value,
+ * need to convert
+ */
+ cat_val = ctr_val[ch % 8];
+
+ return 0;
+}
+#endif
+
+static s32 mlb150_dev_cat_write(u32 ctr_offset, u32 ch, const u16 cat_val)
+{
+ u16 ctr_val[8] = { 0 };
+
+ if (mlb150_dev_ctr_read(ctr_offset, (u32 *)ctr_val))
+ return -ETIME;
+
+ ctr_val[ch % 8] = cat_val;
+ if (mlb150_dev_ctr_write(ctr_offset, (u32 *)ctr_val))
+ return -ETIME;
+
+ return 0;
+}
+
+#define mlb150_dev_cat_mlb_read(ch, cat_val) \
+ mlb150_dev_cat_read(BUF_CAT_MLB_OFFSET + (ch >> 3), ch, cat_val)
+#define mlb150_dev_cat_mlb_write(ch, cat_val) \
+ mlb150_dev_cat_write(BUF_CAT_MLB_OFFSET + (ch >> 3), ch, cat_val)
+#define mlb150_dev_cat_hbi_read(ch, cat_val) \
+ mlb150_dev_cat_read(BUF_CAT_HBI_OFFSET + (ch >> 3), ch, cat_val)
+#define mlb150_dev_cat_hbi_write(ch, cat_val) \
+ mlb150_dev_cat_write(BUF_CAT_HBI_OFFSET + (ch >> 3), ch, cat_val)
+
+#define mlb150_dev_cdt_read(ch, cdt_val) \
+ mlb150_dev_ctr_read(BUF_CDT_OFFSET + ch, cdt_val)
+#define mlb150_dev_cdt_write(ch, cdt_val) \
+ mlb150_dev_ctr_write(BUF_CDT_OFFSET + ch, cdt_val)
+#define mlb150_dev_adt_read(ch, adt_val) \
+ mlb150_dev_ctr_read(BUF_ADT_OFFSET + ch, adt_val)
+#define mlb150_dev_adt_write(ch, adt_val) \
+ mlb150_dev_ctr_write(BUF_ADT_OFFSET + ch, adt_val)
+
+static s32 mlb150_dev_get_adt_sts(u32 ch)
+{
+ s32 timeout = 1000;
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&ctr_lock, flags);
+ __raw_writel(BUF_ADT_OFFSET + ch,
+ mlb_base + REG_MADR);
+
+ while ((!(__raw_readl(mlb_base + REG_MCTL)
+ & MCTL_XCMP)) &&
+ timeout--)
+ ;
+
+ if (timeout <= 0) {
+ spin_unlock_irqrestore(&ctr_lock, flags);
+ pr_debug("mxc_mlb150: Read CTR timeout\n");
+ return -ETIME;
+ }
+
+ reg = __raw_readl(mlb_base + REG_MDAT1);
+
+ __raw_writel(0, mlb_base + REG_MCTL);
+ spin_unlock_irqrestore(&ctr_lock, flags);
+
+#ifdef DEBUG_ADT
+ pr_debug("mxc_mlb150: Get ch %d adt sts: 0x%08x\n", ch, reg);
+#endif
+
+ return reg;
+}
+
+#ifdef DEBUG
+static void mlb150_dev_dump_ctr_tbl(u32 ch_start, u32 ch_end)
+{
+ u32 i = 0;
+ u32 ctr_val[4] = { 0 };
+
+ pr_debug("mxc_mlb150: CDT Table");
+ for (i = BUF_CDT_OFFSET + ch_start;
+ i < BUF_CDT_OFFSET + ch_end;
+ ++i) {
+ mlb150_dev_ctr_read(i, ctr_val);
+ pr_debug("CTR 0x%02x: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ i, ctr_val[3], ctr_val[2], ctr_val[1], ctr_val[0]);
+ }
+
+ pr_debug("mxc_mlb150: ADT Table");
+ for (i = BUF_ADT_OFFSET + ch_start;
+ i < BUF_ADT_OFFSET + ch_end;
+ ++i) {
+ mlb150_dev_ctr_read(i, ctr_val);
+ pr_debug("CTR 0x%02x: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ i, ctr_val[3], ctr_val[2], ctr_val[1], ctr_val[0]);
+ }
+
+ pr_debug("mxc_mlb150: CAT MLB Table");
+ for (i = BUF_CAT_MLB_OFFSET + (ch_start >> 3);
+ i <= BUF_CAT_MLB_OFFSET + ((ch_end + 8) >> 3);
+ ++i) {
+ mlb150_dev_ctr_read(i, ctr_val);
+ pr_debug("CTR 0x%02x: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ i, ctr_val[3], ctr_val[2], ctr_val[1], ctr_val[0]);
+ }
+
+ pr_debug("mxc_mlb150: CAT HBI Table");
+ for (i = BUF_CAT_HBI_OFFSET + (ch_start >> 3);
+ i <= BUF_CAT_HBI_OFFSET + ((ch_end + 8) >> 3);
+ ++i) {
+ mlb150_dev_ctr_read(i, ctr_val);
+ pr_debug("CTR 0x%02x: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ i, ctr_val[3], ctr_val[2], ctr_val[1], ctr_val[0]);
+ }
+}
+#endif
+
+/*
+ * Initial the MLB module device
+ */
+static inline void mlb150_dev_enable_dma_irq(u32 enable)
+{
+ u32 ch_rx_mask = (1 << SYNC_RX_CL_AHB0) | (1 << CTRL_RX_CL_AHB0)
+ | (1 << ASYNC_RX_CL_AHB0) | (1 << ISOC_RX_CL_AHB0)
+ | (1 << SYNC_TX_CL_AHB0) | (1 << CTRL_TX_CL_AHB0)
+ | (1 << ASYNC_TX_CL_AHB0) | (1 << ISOC_TX_CL_AHB0);
+ u32 ch_tx_mask = (1 << (SYNC_RX_CL_AHB1 - INT_AHB1_CH_START)) |
+ (1 << (CTRL_RX_CL_AHB1 - INT_AHB1_CH_START)) |
+ (1 << (ASYNC_RX_CL_AHB1 - INT_AHB1_CH_START)) |
+ (1 << (ISOC_RX_CL_AHB1 - INT_AHB1_CH_START)) |
+ (1 << (SYNC_TX_CL_AHB1 - INT_AHB1_CH_START)) |
+ (1 << (CTRL_TX_CL_AHB1 - INT_AHB1_CH_START)) |
+ (1 << (ASYNC_TX_CL_AHB1 - INT_AHB1_CH_START)) |
+ (1 << (ISOC_TX_CL_AHB1 - INT_AHB1_CH_START));
+
+ if (enable) {
+ __raw_writel(ch_rx_mask, mlb_base + REG_ACMR0);
+ __raw_writel(ch_tx_mask, mlb_base + REG_ACMR1);
+ } else {
+ __raw_writel(0x0, mlb_base + REG_ACMR0);
+ __raw_writel(0x0, mlb_base + REG_ACMR1);
+ }
+}
+
+
+static void mlb150_dev_init_ir_amba_ahb(void)
+{
+ u32 reg = 0;
+
+ /*
+ * Step 1. Program the ACMRn registers to enable interrupts from all
+ * active DMA channels
+ */
+ mlb150_dev_enable_dma_irq(1);
+
+ /*
+ * Step 2. Select the status clear method:
+ * ACTL.SCE = 0, hardware clears on read
+ * ACTL.SCE = 1, software writes a '1' to clear
+ * We only support DMA MODE 1
+ */
+ reg = __raw_readl(mlb_base + REG_ACTL);
+ reg |= ACTL_DMAMODE;
+#ifdef MULTIPLE_PACKAGE_MODE
+ reg |= REG_ACTL_MPB;
+#endif
+
+ /*
+ * Step 3. Select 1 or 2 interrupt signals:
+ * ACTL.SMX = 0: one interrupt for channels 0 - 31 on ahb_init[0]
+ * and another interrupt for channels 32 - 63 on ahb_init[1]
+ * ACTL.SMX = 1: singel interrupt all channels on ahb_init[0]
+ */
+ reg &= ~ACTL_SMX;
+
+ __raw_writel(reg, mlb_base + REG_ACTL);
+}
+
+static inline void mlb150_dev_enable_ir_mlb(u32 enable)
+{
+ /*
+ * Step 1, Select the MSn to be cleared by software,
+ * writing a '0' to the appropriate bits
+ */
+ __raw_writel(0, mlb_base + REG_MS0);
+ __raw_writel(0, mlb_base + REG_MS1);
+
+ /*
+ * Step 1, Program MIEN to enable protocol error
+ * interrupts for all active MLB channels
+ */
+ if (enable)
+ __raw_writel(MIEN_CTX_PE |
+ MIEN_CRX_PE | MIEN_ATX_PE |
+ MIEN_ARX_PE | MIEN_SYNC_PE |
+ MIEN_ISOC_PE,
+ mlb_base + REG_MIEN);
+ else
+ __raw_writel(0, mlb_base + REG_MIEN);
+}
+
+static inline void mlb150_enable_pll(struct mlb_data *drvdata)
+{
+ u32 c0_val;
+
+ __raw_writel(MLBPC1_VAL,
+ drvdata->membase + REG_MLBPC1);
+
+ c0_val = __raw_readl(drvdata->membase + REG_MLBC0);
+ if (c0_val & MLBC0_MLBPEN) {
+ c0_val &= ~MLBC0_MLBPEN;
+ __raw_writel(c0_val,
+ drvdata->membase + REG_MLBC0);
+ }
+
+ c0_val |= (MLBC0_MLBPEN);
+ __raw_writel(c0_val, drvdata->membase + REG_MLBC0);
+}
+
+static inline void mlb150_disable_pll(struct mlb_data *drvdata)
+{
+ u32 c0_val;
+
+ c0_val = __raw_readl(drvdata->membase + REG_MLBC0);
+
+ __raw_writel(0x0, drvdata->membase + REG_MLBPC1);
+
+ c0_val &= ~MLBC0_MLBPEN;
+ __raw_writel(c0_val, drvdata->membase + REG_MLBC0);
+}
+
+static void mlb150_dev_reset_cdt(void)
+{
+ int i = 0;
+ u32 ctr_val[4] = { 0 };
+
+ mlb150_dev_enable_ctr_write(0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff);
+
+ for (i = 0; i < (LOGIC_CH_NUM); ++i)
+ mlb150_dev_ctr_write(BUF_CDT_OFFSET + i, ctr_val);
+}
+
+static s32 mlb150_dev_init_ch_cdt(struct mlb_dev_info *pdevinfo, u32 ch,
+ enum MLB_CTYPE ctype, u32 ch_func)
+{
+ u32 cdt_val[4] = { 0 };
+
+ /* a. Set the 14-bit base address (BA) */
+ pr_debug("mxc_mlb150: ctype: %d, ch: %d, dbr_buf_head: 0x%08x",
+ ctype, ch, pdevinfo->channels[ch_func].dbr_buf_head);
+ cdt_val[3] = (pdevinfo->channels[ch_func].dbr_buf_head)
+ << CDT_BA_SHIFT;
+ /*
+ * b. Set the 12-bit or 13-bit buffer depth (BD)
+ * BD = buffer depth in bytes - 1
+ * For synchronous channels: (BD + 1) = 4 * m * bpf
+ * For control channels: (BD + 1) >= max packet length (64)
+ * For asynchronous channels: (BD + 1) >= max packet length
+ * 1024 for a MOST Data packet (MDP);
+ * 1536 for a MOST Ethernet Packet (MEP)
+ * For isochronous channels: (BD + 1) mod (BS + 1) = 0
+ * BS
+ */
+ if (MLB_CTYPE_ISOC == ctype)
+ cdt_val[1] |= (pdevinfo->isoc_blksz - 1);
+ /* BD */
+ cdt_val[3] |= (pdevinfo->cdt_buf_dep - 1) << CDT_BD_SHIFT;
+
+ pr_debug("mxc_mlb150: Set CDT val of channel %d, type: %d: "
+ "0x%08x 0x%08x 0x%08x 0x%08x\n",
+ ch, ctype, cdt_val[3], cdt_val[2], cdt_val[1], cdt_val[0]);
+
+ if (mlb150_dev_cdt_write(ch, cdt_val))
+ return -ETIME;
+
+#ifdef DEBUG_CTR
+ {
+ u32 cdt_rd[4] = { 0 };
+ if (!mlb150_dev_cdt_read(ch, cdt_rd)) {
+ pr_debug("mxc_mlb150: CDT val of channel %d: "
+ "0x%08x 0x%08x 0x%08x 0x%08x\n",
+ ch, cdt_rd[3], cdt_rd[2], cdt_rd[1], cdt_rd[0]);
+ if (cdt_rd[3] == cdt_val[3] &&
+ cdt_rd[2] == cdt_val[2] &&
+ cdt_rd[1] == cdt_val[1] &&
+ cdt_rd[0] == cdt_val[0]) {
+ pr_debug("mxc_mlb150: set cdt succeed!\n");
+ return 0;
+ } else {
+ pr_debug("mxc_mlb150: set cdt failed!\n");
+ return -EBADE;
+ }
+ } else {
+ pr_debug("mxc_mlb150: Read CDT val of channel %d failed\n",
+ ch);
+ return -EBADE;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static s32 mlb150_dev_init_ch_cat(u32 ch, u32 cl,
+ u32 cat_mode, enum MLB_CTYPE ctype)
+{
+ u16 cat_val = 0;
+#ifdef DEBUG_CTR
+ u16 cat_rd = 0;
+#endif
+
+ cat_val = CAT_CE | (ctype << CAT_CT_SHIFT) | cl;
+
+ if (cat_mode & CAT_MODE_OUTBOUND_DMA)
+ cat_val |= CAT_RNW;
+
+ if (MLB_CTYPE_SYNC == ctype)
+ cat_val |= CAT_MT;
+
+ switch (cat_mode) {
+ case CAT_MODE_RX | CAT_MODE_INBOUND_DMA:
+ case CAT_MODE_TX | CAT_MODE_OUTBOUND_DMA:
+ pr_debug("mxc_mlb150: set CAT val of channel %d, type: %d: 0x%04x\n",
+ ch, ctype, cat_val);
+
+ if (mlb150_dev_cat_mlb_write(ch, cat_val))
+ return -ETIME;
+#ifdef DEBUG_CTR
+ if (!mlb150_dev_cat_mlb_read(ch, &cat_rd))
+ pr_debug("mxc_mlb150: CAT val of mlb channel %d: 0x%04x",
+ ch, cat_rd);
+ else {
+ pr_debug("mxc_mlb150: Read CAT of mlb channel %d failed\n",
+ ch);
+ return -EBADE;
+ }
+#endif
+ break;
+ case CAT_MODE_TX | CAT_MODE_INBOUND_DMA:
+ case CAT_MODE_RX | CAT_MODE_OUTBOUND_DMA:
+ pr_debug("mxc_mlb150: set CAT val of channel %d, type: %d: 0x%04x\n",
+ cl, ctype, cat_val);
+
+ if (mlb150_dev_cat_hbi_write(cl, cat_val))
+ return -ETIME;
+#ifdef DEBUG_CTR
+ if (!mlb150_dev_cat_hbi_read(cl, &cat_rd))
+ pr_debug("mxc_mlb150: CAT val of hbi channel %d: 0x%04x",
+ cl, cat_rd);
+ else {
+ pr_debug("mxc_mlb150: Read CAT of hbi channel %d failed\n",
+ cl);
+ return -EBADE;
+ }
+#endif
+ break;
+ default:
+ return EBADRQC;
+ }
+
+#ifdef DEBUG_CTR
+ {
+ if (cat_val == cat_rd) {
+ pr_debug("mxc_mlb150: set cat succeed!\n");
+ return 0;
+ } else {
+ pr_debug("mxc_mlb150: set cat failed!\n");
+ return -EBADE;
+ }
+ }
+#endif
+ return 0;
+}
+
+static void mlb150_dev_reset_cat(void)
+{
+ int i = 0;
+ u32 ctr_val[4] = { 0 };
+
+ mlb150_dev_enable_ctr_write(0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff);
+
+ for (i = 0; i < (LOGIC_CH_NUM >> 3); ++i) {
+ mlb150_dev_ctr_write(BUF_CAT_MLB_OFFSET + i, ctr_val);
+ mlb150_dev_ctr_write(BUF_CAT_HBI_OFFSET + i, ctr_val);
+ }
+}
+
+static void mlb150_dev_init_rfb(struct mlb_dev_info *pdevinfo, u32 rx_ch,
+ u32 tx_ch, enum MLB_CTYPE ctype)
+{
+ u32 rx_cl = pdevinfo->channels[RX_CHANNEL].cl;
+ u32 tx_cl = pdevinfo->channels[TX_CHANNEL].cl;
+ /* Step 1, Initialize all bits of CAT to '0' */
+ mlb150_dev_reset_cat();
+ mlb150_dev_reset_cdt();
+ /*
+ * Step 2, Initialize logical channel
+ * Step 3, Program the CDT for channel N
+ */
+ mlb150_dev_init_ch_cdt(pdevinfo, rx_cl, ctype, RX_CHANNEL);
+ mlb150_dev_init_ch_cdt(pdevinfo, tx_cl, ctype, TX_CHANNEL);
+
+ /* Step 4&5, Program the CAT for the inbound and outbound DMA */
+ mlb150_dev_init_ch_cat(rx_ch, rx_cl,
+ CAT_MODE_RX | CAT_MODE_INBOUND_DMA,
+ ctype);
+ mlb150_dev_init_ch_cat(rx_ch, rx_cl,
+ CAT_MODE_RX | CAT_MODE_OUTBOUND_DMA,
+ ctype);
+ mlb150_dev_init_ch_cat(tx_ch, tx_cl,
+ CAT_MODE_TX | CAT_MODE_INBOUND_DMA,
+ ctype);
+ mlb150_dev_init_ch_cat(tx_ch, tx_cl,
+ CAT_MODE_TX | CAT_MODE_OUTBOUND_DMA,
+ ctype);
+}
+
+static void mlb150_dev_reset_adt(void)
+{
+ int i = 0;
+ u32 ctr_val[4] = { 0 };
+
+ mlb150_dev_enable_ctr_write(0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff);
+
+ for (i = 0; i < (LOGIC_CH_NUM); ++i)
+ mlb150_dev_ctr_write(BUF_ADT_OFFSET + i, ctr_val);
+}
+
+static void mlb150_dev_reset_whole_ctr(void)
+{
+ mlb150_dev_enable_ctr_write(0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff);
+ mlb150_dev_reset_cdt();
+ mlb150_dev_reset_adt();
+ mlb150_dev_reset_cat();
+}
+
+#define CLR_REG(reg) __raw_writel(0x0, mlb_base + reg)
+
+static void mlb150_dev_reset_all_regs(void)
+{
+ CLR_REG(REG_MLBC0);
+ CLR_REG(REG_MLBPC0);
+ CLR_REG(REG_MS0);
+ CLR_REG(REG_MS1);
+ CLR_REG(REG_MSS);
+ CLR_REG(REG_MSD);
+ CLR_REG(REG_MIEN);
+ CLR_REG(REG_MLBPC2);
+ CLR_REG(REG_MLBPC1);
+ CLR_REG(REG_MLBC1);
+ CLR_REG(REG_HCTL);
+ CLR_REG(REG_HCMR0);
+ CLR_REG(REG_HCMR1);
+ CLR_REG(REG_HCER0);
+ CLR_REG(REG_HCER1);
+ CLR_REG(REG_HCBR0);
+ CLR_REG(REG_HCBR1);
+ CLR_REG(REG_MDAT0);
+ CLR_REG(REG_MDAT1);
+ CLR_REG(REG_MDAT2);
+ CLR_REG(REG_MDAT3);
+ CLR_REG(REG_MDWE0);
+ CLR_REG(REG_MDWE1);
+ CLR_REG(REG_MDWE2);
+ CLR_REG(REG_MDWE3);
+ CLR_REG(REG_MCTL);
+ CLR_REG(REG_MADR);
+ CLR_REG(REG_ACTL);
+ CLR_REG(REG_ACSR0);
+ CLR_REG(REG_ACSR1);
+ CLR_REG(REG_ACMR0);
+ CLR_REG(REG_ACMR1);
+}
+
+static inline s32 mlb150_dev_pipo_start(struct mlb_ringbuf *rbuf,
+ u32 ahb_ch, u32 buf_addr)
+{
+ u32 ctr_val[4] = { 0 };
+
+ ctr_val[1] |= ADT_RDY1;
+ ctr_val[2] = buf_addr;
+
+ if (mlb150_dev_adt_write(ahb_ch, ctr_val))
+ return -ETIME;
+
+ return 0;
+}
+
+static inline s32 mlb150_dev_pipo_next(u32 ahb_ch, enum MLB_CTYPE ctype,
+ u32 dne_sts, u32 buf_addr)
+{
+ u32 ctr_val[4] = { 0 };
+
+ if (MLB_CTYPE_ASYNC == ctype ||
+ MLB_CTYPE_CTRL == ctype) {
+ ctr_val[1] |= ADT_PS1;
+ ctr_val[1] |= ADT_PS2;
+ }
+
+ /*
+ * Clear DNE1 and ERR1
+ * Set the page ready bit (RDY1)
+ */
+ if (dne_sts & ADT_DNE1) {
+ ctr_val[1] |= ADT_RDY2;
+ ctr_val[3] = buf_addr;
+ } else {
+ ctr_val[1] |= ADT_RDY1;
+ ctr_val[2] = buf_addr;
+ }
+
+ if (mlb150_dev_adt_write(ahb_ch, ctr_val))
+ return -ETIME;
+
+ return 0;
+}
+
+static inline s32 mlb150_dev_pipo_stop(struct mlb_ringbuf *rbuf, u32 ahb_ch)
+{
+ u32 ctr_val[4] = { 0 };
+ unsigned long flags;
+
+ write_lock_irqsave(&rbuf->rb_lock, flags);
+ rbuf->head = rbuf->tail = 0;
+ write_unlock_irqrestore(&rbuf->rb_lock, flags);
+
+ if (mlb150_dev_adt_write(ahb_ch, ctr_val))
+ return -ETIME;
+
+ return 0;
+}
+
+static s32 mlb150_dev_init_ch_amba_ahb(struct mlb_dev_info *pdevinfo,
+ struct mlb_channel_info *chinfo,
+ enum MLB_CTYPE ctype)
+{
+ u32 ctr_val[4] = { 0 };
+
+ /* a. Set the 32-bit base address (BA1) */
+ ctr_val[3] = 0;
+ ctr_val[2] = 0;
+ ctr_val[1] = (pdevinfo->adt_buf_dep - 1) << ADT_BD1_SHIFT;
+ ctr_val[1] |= (pdevinfo->adt_buf_dep - 1) << ADT_BD2_SHIFT;
+ if (MLB_CTYPE_ASYNC == ctype ||
+ MLB_CTYPE_CTRL == ctype) {
+ ctr_val[1] |= ADT_PS1;
+ ctr_val[1] |= ADT_PS2;
+ }
+
+ ctr_val[0] |= (ADT_LE | ADT_CE);
+
+ pr_debug("mxc_mlb150: Set ADT val of channel %d, ctype: %d: "
+ "0x%08x 0x%08x 0x%08x 0x%08x\n",
+ chinfo->cl, ctype, ctr_val[3], ctr_val[2],
+ ctr_val[1], ctr_val[0]);
+
+ if (mlb150_dev_adt_write(chinfo->cl, ctr_val))
+ return -ETIME;
+
+#ifdef DEBUG_CTR
+ {
+ u32 ctr_rd[4] = { 0 };
+ if (!mlb150_dev_adt_read(chinfo->cl, ctr_rd)) {
+ pr_debug("mxc_mlb150: ADT val of channel %d: "
+ "0x%08x 0x%08x 0x%08x 0x%08x\n",
+ chinfo->cl, ctr_rd[3], ctr_rd[2],
+ ctr_rd[1], ctr_rd[0]);
+ if (ctr_rd[3] == ctr_val[3] &&
+ ctr_rd[2] == ctr_val[2] &&
+ ctr_rd[1] == ctr_val[1] &&
+ ctr_rd[0] == ctr_val[0]) {
+ pr_debug("mxc_mlb150: set adt succeed!\n");
+ return 0;
+ } else {
+ pr_debug("mxc_mlb150: set adt failed!\n");
+ return -EBADE;
+ }
+ } else {
+ pr_debug("mxc_mlb150: Read ADT val of channel %d failed\n",
+ chinfo->cl);
+ return -EBADE;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static void mlb150_dev_init_amba_ahb(struct mlb_dev_info *pdevinfo,
+ enum MLB_CTYPE ctype)
+{
+ struct mlb_channel_info *tx_chinfo = &pdevinfo->channels[TX_CHANNEL];
+ struct mlb_channel_info *rx_chinfo = &pdevinfo->channels[RX_CHANNEL];
+
+ /* Step 1, Initialize all bits of the ADT to '0' */
+ mlb150_dev_reset_adt();
+
+ /*
+ * Step 2, Select a logic channel
+ * Step 3, Program the AMBA AHB block ping page for channel N
+ * Step 4, Program the AMBA AHB block pong page for channel N
+ */
+ mlb150_dev_init_ch_amba_ahb(pdevinfo, rx_chinfo, ctype);
+ mlb150_dev_init_ch_amba_ahb(pdevinfo, tx_chinfo, ctype);
+}
+
+static void mlb150_dev_exit(void)
+{
+ u32 c0_val, hctl_val;
+
+ /* Disable EN bits */
+ c0_val = __raw_readl(mlb_base + REG_MLBC0);
+ c0_val &= ~(MLBC0_MLBEN | MLBC0_MLBPEN);
+ __raw_writel(c0_val, mlb_base + REG_MLBC0);
+
+ hctl_val = __raw_readl(mlb_base + REG_HCTL);
+ hctl_val &= ~HCTL_EN;
+ __raw_writel(hctl_val, mlb_base + REG_HCTL);
+
+ __raw_writel(0x0, mlb_base + REG_HCMR0);
+ __raw_writel(0x0, mlb_base + REG_HCMR1);
+
+ mlb150_dev_enable_dma_irq(0);
+ mlb150_dev_enable_ir_mlb(0);
+}
+
+static void mlb150_dev_init(void)
+{
+ u32 c0_val;
+ u32 ch_rx_mask = (1 << SYNC_RX_CL_AHB0) | (1 << CTRL_RX_CL_AHB0)
+ | (1 << ASYNC_RX_CL_AHB0) | (1 << ISOC_RX_CL_AHB0)
+ | (1 << SYNC_TX_CL_AHB0) | (1 << CTRL_TX_CL_AHB0)
+ | (1 << ASYNC_TX_CL_AHB0) | (1 << ISOC_TX_CL_AHB0);
+ u32 ch_tx_mask = (1 << (SYNC_RX_CL_AHB1 - INT_AHB1_CH_START)) |
+ (1 << (CTRL_RX_CL_AHB1 - INT_AHB1_CH_START)) |
+ (1 << (ASYNC_RX_CL_AHB1 - INT_AHB1_CH_START)) |
+ (1 << (ISOC_RX_CL_AHB1 - INT_AHB1_CH_START)) |
+ (1 << (SYNC_TX_CL_AHB1 - INT_AHB1_CH_START)) |
+ (1 << (CTRL_TX_CL_AHB1 - INT_AHB1_CH_START)) |
+ (1 << (ASYNC_TX_CL_AHB1 - INT_AHB1_CH_START)) |
+ (1 << (ISOC_TX_CL_AHB1 - INT_AHB1_CH_START));
+
+ /* Disable EN bits */
+ mlb150_dev_exit();
+
+ /*
+ * Step 1. Initialize CTR and registers
+ * a. Set all bit of the CTR (CAT, CDT, and ADT) to 0.
+ */
+ mlb150_dev_reset_whole_ctr();
+
+ /* a. Set all bit of the CTR (CAT, CDT, and ADT) to 0. */
+ mlb150_dev_reset_all_regs();
+
+ /*
+ * Step 2, Configure the MediaLB interface
+ * Select pin mode and clock, 3-pin and 256fs
+ */
+ c0_val = __raw_readl(mlb_base + REG_MLBC0);
+ c0_val &= ~(MLBC0_MLBPEN | MLBC0_MLBCLK_MASK);
+ __raw_writel(c0_val, mlb_base + REG_MLBC0);
+
+ c0_val |= MLBC0_MLBEN;
+ __raw_writel(c0_val, mlb_base + REG_MLBC0);
+
+ /* Step 3, Configure the HBI interface */
+ __raw_writel(ch_rx_mask, mlb_base + REG_HCMR0);
+ __raw_writel(ch_tx_mask, mlb_base + REG_HCMR1);
+ __raw_writel(HCTL_EN, mlb_base + REG_HCTL);
+
+ mlb150_dev_init_ir_amba_ahb();
+
+ mlb150_dev_enable_ir_mlb(1);
+}
+
+static s32 mlb150_dev_unmute_syn_ch(u32 rx_ch, u32 rx_cl, u32 tx_ch, u32 tx_cl)
+{
+ u32 timeout = 10000;
+
+ /*
+ * Check that MediaLB clock is running (MLBC1.CLKM = 0)
+ * If MLBC1.CLKM = 1, clear the register bit, wait one
+ * APB or I/O clock cycle and repeat the check
+ */
+ while ((__raw_readl(mlb_base + REG_MLBC1) & MLBC1_CLKM)
+ && --timeout)
+ __raw_writel(~MLBC1_CLKM, mlb_base + REG_MLBC1);
+
+ if (0 == timeout)
+ return -ETIME;
+
+ timeout = 10000;
+ /* Poll for MLB lock (MLBC0.MLBLK = 1) */
+ while (!(__raw_readl(mlb_base + REG_MLBC0) & MLBC0_MLBLK)
+ && --timeout)
+ ;
+
+ if (0 == timeout)
+ return -ETIME;
+
+ /* Unmute synchronous channel(s) */
+ mlb150_dev_cat_mlb_write(rx_ch, CAT_CE | rx_cl);
+ mlb150_dev_cat_mlb_write(tx_ch,
+ CAT_CE | tx_cl | CAT_RNW);
+ mlb150_dev_cat_hbi_write(rx_cl,
+ CAT_CE | rx_cl | CAT_RNW);
+ mlb150_dev_cat_hbi_write(tx_cl, CAT_CE | tx_cl);
+
+ return 0;
+}
+
+/* In case the user calls channel shutdown, but rx or tx is not completed yet */
+static s32 mlb150_trans_complete_check(struct mlb_dev_info *pdevinfo)
+{
+ struct mlb_ringbuf *rx_rbuf = &pdevinfo->rx_rbuf;
+ struct mlb_ringbuf *tx_rbuf = &pdevinfo->tx_rbuf;
+ s32 timeout = 1024;
+
+ while (timeout--) {
+ read_lock(&tx_rbuf->rb_lock);
+ if (!CIRC_CNT(tx_rbuf->head, tx_rbuf->tail, TRANS_RING_NODES)) {
+ read_unlock(&tx_rbuf->rb_lock);
+ break;
+ } else
+ read_unlock(&tx_rbuf->rb_lock);
+ }
+
+ if (timeout <= 0) {
+ pr_debug("TX complete check timeout!\n");
+ return -ETIME;
+ }
+
+ timeout = 1024;
+ while (timeout--) {
+ read_lock(&rx_rbuf->rb_lock);
+ if (!CIRC_CNT(rx_rbuf->head, rx_rbuf->tail, TRANS_RING_NODES)) {
+ read_unlock(&rx_rbuf->rb_lock);
+ break;
+ } else
+ read_unlock(&rx_rbuf->rb_lock);
+ }
+
+ if (timeout <= 0) {
+ pr_debug("RX complete check timeout!\n");
+ return -ETIME;
+ }
+
+ /*
+ * Interrupt from TX can only inform that the data is sent
+ * to AHB bus, not mean that it is sent to MITB. Thus we add
+ * a delay here for data to be completed sent.
+ */
+ udelay(1000);
+
+ return 0;
+}
+
+/*
+ * Enable/Disable the MLB IRQ
+ */
+static void mxc_mlb150_irq_enable(struct mlb_data *drvdata, u8 enable)
+{
+ if (enable) {
+ enable_irq(drvdata->irq_ahb0);
+ enable_irq(drvdata->irq_mlb);
+ if (drvdata->irq_ahb1 > 0)
+ enable_irq(drvdata->irq_ahb1);
+ } else {
+ disable_irq(drvdata->irq_ahb0);
+ disable_irq(drvdata->irq_mlb);
+ if (drvdata->irq_ahb1 > 0)
+ disable_irq(drvdata->irq_ahb1);
+ }
+}
+
+/*
+ * Enable the MLB channel
+ */
+static s32 mlb_channel_enable(struct mlb_data *drvdata,
+ int chan_dev_id, int on)
+{
+ struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+ struct mlb_channel_info *tx_chinfo = &pdevinfo->channels[TX_CHANNEL];
+ struct mlb_channel_info *rx_chinfo = &pdevinfo->channels[RX_CHANNEL];
+ u32 tx_ch = tx_chinfo->address;
+ u32 rx_ch = rx_chinfo->address;
+ u32 tx_cl = tx_chinfo->cl;
+ u32 rx_cl = rx_chinfo->cl;
+ s32 ret = 0;
+
+ /*
+ * setup the direction, enable, channel type,
+ * mode select, channel address and mask buf start
+ */
+ if (on) {
+ u32 ctype = pdevinfo->channel_type;
+
+ mlb150_dev_enable_ctr_write(0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff);
+ mlb150_dev_init_rfb(pdevinfo, rx_ch, tx_ch, ctype);
+
+ mlb150_dev_init_amba_ahb(pdevinfo, ctype);
+
+#ifdef DEBUG
+ mlb150_dev_dump_ctr_tbl(0, tx_chinfo->cl + 1);
+#endif
+ /* Synchronize and unmute synchrouous channel */
+ if (MLB_CTYPE_SYNC == ctype) {
+ ret = mlb150_dev_unmute_syn_ch(rx_ch, rx_cl,
+ tx_ch, tx_cl);
+ if (ret)
+ return ret;
+ }
+
+ mlb150_dev_enable_ctr_write(0x0, ADT_RDY1 | ADT_DNE1 |
+ ADT_ERR1 | ADT_PS1 |
+ ADT_RDY2 | ADT_DNE2 | ADT_ERR2 | ADT_PS2,
+ 0xffffffff, 0xffffffff);
+
+ if (pdevinfo->fps >= CLK_2048FS)
+ mlb150_enable_pll(drvdata);
+
+ atomic_set(&pdevinfo->on, 1);
+
+#ifdef DEBUG
+ mlb150_dev_dump_reg();
+ mlb150_dev_dump_ctr_tbl(0, tx_chinfo->cl + 1);
+#endif
+ /* Init RX ADT */
+ mlb150_dev_pipo_start(&pdevinfo->rx_rbuf, rx_cl,
+ pdevinfo->rx_rbuf.phy_addrs[0]);
+ } else {
+ mlb150_dev_pipo_stop(&pdevinfo->rx_rbuf, rx_cl);
+
+ mlb150_dev_enable_dma_irq(0);
+ mlb150_dev_enable_ir_mlb(0);
+
+ mlb150_dev_reset_cat();
+
+ atomic_set(&pdevinfo->on, 0);
+
+ if (pdevinfo->fps >= CLK_2048FS)
+ mlb150_disable_pll(drvdata);
+ }
+
+ return 0;
+}
+
+/*
+ * MLB interrupt handler
+ */
+static void mlb_rx_isr(s32 ctype, u32 ahb_ch, struct mlb_dev_info *pdevinfo)
+{
+ struct mlb_ringbuf *rx_rbuf = &pdevinfo->rx_rbuf;
+ s32 head, tail, adt_sts;
+ u32 rx_buf_ptr;
+
+#ifdef DEBUG_RX
+ pr_debug("mxc_mlb150: mlb_rx_isr\n");
+#endif
+
+ read_lock(&rx_rbuf->rb_lock);
+
+ head = (rx_rbuf->head + 1) & (TRANS_RING_NODES - 1);
+ tail = ACCESS_ONCE(rx_rbuf->tail);
+ read_unlock(&rx_rbuf->rb_lock);
+
+ if (CIRC_SPACE(head, tail, TRANS_RING_NODES) >= 1) {
+ rx_buf_ptr = rx_rbuf->phy_addrs[head];
+
+ /* commit the item before incrementing the head */
+ smp_wmb();
+
+ write_lock(&rx_rbuf->rb_lock);
+ rx_rbuf->head = head;
+ write_unlock(&rx_rbuf->rb_lock);
+
+ /* wake up the reader */
+ wake_up_interruptible(&pdevinfo->rx_wq);
+ } else {
+ rx_buf_ptr = rx_rbuf->phy_addrs[head];
+ pr_debug("drop RX package, due to no space, (%d,%d)\n",
+ head, tail);
+ }
+
+ adt_sts = mlb150_dev_get_adt_sts(ahb_ch);
+ /* Set ADT for RX */
+ mlb150_dev_pipo_next(ahb_ch, ctype, adt_sts, rx_buf_ptr);
+}
+
+static void mlb_tx_isr(s32 ctype, u32 ahb_ch, struct mlb_dev_info *pdevinfo)
+{
+ struct mlb_ringbuf *tx_rbuf = &pdevinfo->tx_rbuf;
+ s32 head, tail, adt_sts;
+ u32 tx_buf_ptr;
+
+ read_lock(&tx_rbuf->rb_lock);
+
+ head = ACCESS_ONCE(tx_rbuf->head);
+ tail = (tx_rbuf->tail + 1) & (TRANS_RING_NODES - 1);
+ read_unlock(&tx_rbuf->rb_lock);
+
+ smp_mb();
+ write_lock(&tx_rbuf->rb_lock);
+ tx_rbuf->tail = tail;
+ write_unlock(&tx_rbuf->rb_lock);
+
+ /* check the current tx buffer is available or not */
+ if (CIRC_CNT(head, tail, TRANS_RING_NODES) >= 1) {
+ /* read index before reading contents at that index */
+ smp_read_barrier_depends();
+
+ tx_buf_ptr = tx_rbuf->phy_addrs[tail];
+
+ wake_up_interruptible(&pdevinfo->tx_wq);
+
+ adt_sts = mlb150_dev_get_adt_sts(ahb_ch);
+ /* Set ADT for TX */
+ mlb150_dev_pipo_next(ahb_ch, ctype, adt_sts, tx_buf_ptr);
+ }
+}
+
+static irqreturn_t mlb_ahb_isr(int irq, void *dev_id)
+{
+ u32 acsr0, hcer0;
+ u32 ch_mask = (1 << SYNC_RX_CL) | (1 << CTRL_RX_CL)
+ | (1 << ASYNC_RX_CL) | (1 << ISOC_RX_CL)
+ | (1 << SYNC_TX_CL) | (1 << CTRL_TX_CL)
+ | (1 << ASYNC_TX_CL) | (1 << ISOC_TX_CL);
+
+ /*
+ * Step 5, Read the ACSRn registers to determine which channel or
+ * channels are causing the interrupt
+ */
+ acsr0 = __raw_readl(mlb_base + REG_ACSR0);
+
+ hcer0 = __raw_readl(mlb_base + REG_HCER0);
+
+ /*
+ * Step 6, If ACTL.SCE = 1, write the result of step 5 back to ACSR0
+ * and ACSR1 to clear the interrupt
+ * We'll not set ACTL_SCE
+ */
+
+ if (ch_mask & hcer0)
+ pr_err("CH encounters an AHB error: 0x%x\n", hcer0);
+
+ if ((1 << SYNC_RX_CL) & acsr0)
+ mlb_rx_isr(MLB_CTYPE_SYNC, SYNC_RX_CL,
+ &mlb_devinfo[MLB_CTYPE_SYNC]);
+
+ if ((1 << CTRL_RX_CL) & acsr0)
+ mlb_rx_isr(MLB_CTYPE_CTRL, CTRL_RX_CL,
+ &mlb_devinfo[MLB_CTYPE_CTRL]);
+
+ if ((1 << ASYNC_RX_CL) & acsr0)
+ mlb_rx_isr(MLB_CTYPE_ASYNC, ASYNC_RX_CL,
+ &mlb_devinfo[MLB_CTYPE_ASYNC]);
+
+ if ((1 << ISOC_RX_CL) & acsr0)
+ mlb_rx_isr(MLB_CTYPE_ISOC, ISOC_RX_CL,
+ &mlb_devinfo[MLB_CTYPE_ISOC]);
+
+ if ((1 << SYNC_TX_CL) & acsr0)
+ mlb_tx_isr(MLB_CTYPE_SYNC, SYNC_TX_CL,
+ &mlb_devinfo[MLB_CTYPE_SYNC]);
+
+ if ((1 << CTRL_TX_CL) & acsr0)
+ mlb_tx_isr(MLB_CTYPE_CTRL, CTRL_TX_CL,
+ &mlb_devinfo[MLB_CTYPE_CTRL]);
+
+ if ((1 << ASYNC_TX_CL) & acsr0)
+ mlb_tx_isr(MLB_CTYPE_ASYNC, ASYNC_TX_CL,
+ &mlb_devinfo[MLB_CTYPE_ASYNC]);
+
+ if ((1 << ISOC_TX_CL) & acsr0)
+ mlb_tx_isr(MLB_CTYPE_ASYNC, ISOC_TX_CL,
+ &mlb_devinfo[MLB_CTYPE_ISOC]);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mlb_isr(int irq, void *dev_id)
+{
+ u32 rx_int_sts, tx_int_sts, ms0,
+ ms1, tx_cis, rx_cis, ctype;
+ int minor;
+ u32 cdt_val[4] = { 0 };
+
+ /*
+ * Step 4, Read the MSn register to determine which channel(s)
+ * are causing the interrupt
+ */
+ ms0 = __raw_readl(mlb_base + REG_MS0);
+ ms1 = __raw_readl(mlb_base + REG_MS1);
+
+ /*
+ * The MLB150_MS0, MLB150_MS1 registers need to be cleared. In
+ * the spec description, the registers should be cleared when
+ * enabling interrupt. In fact, we also should clear it in ISR.
+ */
+ __raw_writel(0, mlb_base + REG_MS0);
+ __raw_writel(0, mlb_base + REG_MS1);
+
+ pr_debug("mxc_mlb150: mlb interrupt:0x%08x 0x%08x\n",
+ (u32)ms0, (u32)ms1);
+
+ for (minor = 0; minor < MLB_MINOR_DEVICES; minor++) {
+ struct mlb_dev_info *pdevinfo = &mlb_devinfo[minor];
+ u32 rx_mlb_ch = pdevinfo->channels[RX_CHANNEL].address;
+ u32 tx_mlb_ch = pdevinfo->channels[TX_CHANNEL].address;
+ u32 rx_mlb_cl = pdevinfo->channels[RX_CHANNEL].cl;
+ u32 tx_mlb_cl = pdevinfo->channels[TX_CHANNEL].cl;
+
+ tx_cis = rx_cis = 0;
+
+ ctype = pdevinfo->channel_type;
+ rx_int_sts = (rx_mlb_ch < 31) ? ms0 : ms1;
+ tx_int_sts = (tx_mlb_ch < 31) ? ms0 : ms1;
+
+ pr_debug("mxc_mlb150: channel interrupt: "
+ "tx %d: 0x%08x, rx %d: 0x%08x\n",
+ tx_mlb_ch, (u32)tx_int_sts, rx_mlb_ch, (u32)rx_int_sts);
+
+ /* Get tx channel interrupt status */
+ if (tx_int_sts & (1 << (tx_mlb_ch % 32))) {
+ mlb150_dev_cdt_read(tx_mlb_cl, cdt_val);
+ pr_debug("mxc_mlb150: TX_CH: %d, cdt_val[3]: 0x%08x, "
+ "cdt_val[2]: 0x%08x, "
+ "cdt_val[1]: 0x%08x, "
+ "cdt_val[0]: 0x%08x\n",
+ tx_mlb_ch, cdt_val[3], cdt_val[2],
+ cdt_val[1], cdt_val[0]);
+ switch (ctype) {
+ case MLB_CTYPE_SYNC:
+ tx_cis = (cdt_val[2] & CDT_SYNC_WSTS_MASK)
+ >> CDT_SYNC_WSTS_SHIFT;
+ /*
+ * Clear RSTS/WSTS errors to resume
+ * channel operation
+ * a. For synchronous channels: WSTS[3] = 0
+ */
+ cdt_val[2] &= ~(0x8 << CDT_SYNC_WSTS_SHIFT);
+ break;
+ case MLB_CTYPE_CTRL:
+ case MLB_CTYPE_ASYNC:
+ tx_cis = (cdt_val[2] &
+ CDT_CTRL_ASYNC_WSTS_MASK)
+ >> CDT_CTRL_ASYNC_WSTS_SHIFT;
+ tx_cis = (cdt_val[3] & CDT_CTRL_ASYNC_WSTS_1) ?
+ (tx_cis | (0x1 << 4)) : tx_cis;
+ /*
+ * b. For async and ctrl channels:
+ * RSTS[4]/WSTS[4] = 0
+ * and RSTS[2]/WSTS[2] = 0
+ */
+ cdt_val[3] &= ~CDT_CTRL_ASYNC_WSTS_1;
+ cdt_val[2] &=
+ ~(0x4 << CDT_CTRL_ASYNC_WSTS_SHIFT);
+ break;
+ case MLB_CTYPE_ISOC:
+ tx_cis = (cdt_val[2] & CDT_ISOC_WSTS_MASK)
+ >> CDT_ISOC_WSTS_SHIFT;
+ /* c. For isoc channels: WSTS[2:1] = 0x00 */
+ cdt_val[2] &= ~(0x6 << CDT_ISOC_WSTS_SHIFT);
+ break;
+ default:
+ break;
+ }
+ mlb150_dev_cdt_write(tx_mlb_ch, cdt_val);
+ }
+
+ /* Get rx channel interrupt status */
+ if (rx_int_sts & (1 << (rx_mlb_ch % 32))) {
+ mlb150_dev_cdt_read(rx_mlb_cl, cdt_val);
+ pr_debug("mxc_mlb150: RX_CH: %d, cdt_val[3]: 0x%08x, "
+ "cdt_val[2]: 0x%08x, "
+ "cdt_val[1]: 0x%08x, "
+ "cdt_val[0]: 0x%08x\n",
+ rx_mlb_ch, cdt_val[3], cdt_val[2],
+ cdt_val[1], cdt_val[0]);
+ switch (ctype) {
+ case MLB_CTYPE_SYNC:
+ rx_cis = (cdt_val[2] & CDT_SYNC_RSTS_MASK)
+ >> CDT_SYNC_RSTS_SHIFT;
+ cdt_val[2] &= ~(0x8 << CDT_SYNC_WSTS_SHIFT);
+ break;
+ case MLB_CTYPE_CTRL:
+ case MLB_CTYPE_ASYNC:
+ rx_cis =
+ (cdt_val[2] & CDT_CTRL_ASYNC_RSTS_MASK)
+ >> CDT_CTRL_ASYNC_RSTS_SHIFT;
+ rx_cis = (cdt_val[3] & CDT_CTRL_ASYNC_RSTS_1) ?
+ (rx_cis | (0x1 << 4)) : rx_cis;
+ cdt_val[3] &= ~CDT_CTRL_ASYNC_RSTS_1;
+ cdt_val[2] &=
+ ~(0x4 << CDT_CTRL_ASYNC_RSTS_SHIFT);
+ break;
+ case MLB_CTYPE_ISOC:
+ rx_cis = (cdt_val[2] & CDT_ISOC_RSTS_MASK)
+ >> CDT_ISOC_RSTS_SHIFT;
+ cdt_val[2] &= ~(0x6 << CDT_ISOC_WSTS_SHIFT);
+ break;
+ default:
+ break;
+ }
+ mlb150_dev_cdt_write(rx_mlb_ch, cdt_val);
+ }
+
+ if (!tx_cis && !rx_cis)
+ continue;
+
+ /* fill exception event */
+ spin_lock(&pdevinfo->event_lock);
+ pdevinfo->ex_event |= (rx_cis << 16) | tx_cis;
+ spin_unlock(&pdevinfo->event_lock);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int mxc_mlb150_open(struct inode *inode, struct file *filp)
+{
+ int minor, ring_buf_size, buf_size, j, ret;
+ void *buf_addr;
+ dma_addr_t phy_addr;
+ struct mlb_dev_info *pdevinfo = NULL;
+ struct mlb_channel_info *pchinfo = NULL;
+ struct mlb_data *drvdata;
+
+ minor = MINOR(inode->i_rdev);
+ drvdata = container_of(inode->i_cdev, struct mlb_data, cdev);
+ drvdata->use_iram = true;
+
+ if (minor < 0 || minor >= MLB_MINOR_DEVICES) {
+ pr_err("no device\n");
+ return -ENODEV;
+ }
+
+ /* open for each channel device */
+ if (atomic_cmpxchg(&mlb_devinfo[minor].opencnt, 0, 1) != 0) {
+ pr_err("busy\n");
+ return -EBUSY;
+ }
+
+#ifdef CONFIG_ARCH_MXC_ARM64
+ clk_prepare_enable(drvdata->ipg);
+ clk_prepare_enable(drvdata->hclk);
+#endif
+ clk_prepare_enable(drvdata->mlb);
+
+ /* initial MLB module */
+ mlb150_dev_init();
+
+ pdevinfo = &mlb_devinfo[minor];
+ pchinfo = &pdevinfo->channels[TX_CHANNEL];
+
+ ring_buf_size = pdevinfo->buf_size;
+ buf_size = ring_buf_size * (TRANS_RING_NODES * 2);
+
+ buf_addr = gen_pool_dma_alloc(drvdata->iram_pool, buf_size, &phy_addr);
+ if (!buf_addr) {
+ drvdata->use_iram = false;
+ buf_addr = dma_alloc_coherent(drvdata->dev, buf_size, &phy_addr, GFP_KERNEL);
+ if (!buf_addr) {
+ ret = -ENOMEM;
+ pr_err("can not alloc rx/tx buffers: %d\n", buf_size);
+ return ret;
+ }
+ }
+
+ pr_debug("IRAM Range: Virt 0x%p - 0x%p, Phys 0x%x - 0x%x, size: 0x%x\n",
+ buf_addr, (buf_addr + buf_size - 1), (u32)phy_addr,
+ (u32)(phy_addr + buf_size - 1), buf_size);
+ pdevinfo->rbuf_base_virt = buf_addr;
+ pdevinfo->rbuf_base_phy = phy_addr;
+ drvdata->iram_size = drvdata->use_iram ? buf_size : 0;
+
+ memset(buf_addr, 0, buf_size);
+
+ for (j = 0; j < (TRANS_RING_NODES);
+ ++j, buf_addr += ring_buf_size, phy_addr += ring_buf_size) {
+ pdevinfo->rx_rbuf.virt_bufs[j] = buf_addr;
+ pdevinfo->rx_rbuf.phy_addrs[j] = phy_addr;
+ pr_debug("RX Ringbuf[%d]: 0x%p 0x%x\n",
+ j, buf_addr, (u32)phy_addr);
+ }
+ pdevinfo->rx_rbuf.unit_size = ring_buf_size;
+ pdevinfo->rx_rbuf.total_size = buf_size;
+ for (j = 0; j < (TRANS_RING_NODES);
+ ++j, buf_addr += ring_buf_size, phy_addr += ring_buf_size) {
+ pdevinfo->tx_rbuf.virt_bufs[j] = buf_addr;
+ pdevinfo->tx_rbuf.phy_addrs[j] = phy_addr;
+ pr_debug("TX Ringbuf[%d]: 0x%p 0x%x\n",
+ j, buf_addr, (u32)phy_addr);
+ }
+
+ pdevinfo->tx_rbuf.unit_size = ring_buf_size;
+ pdevinfo->tx_rbuf.total_size = buf_size;
+
+ /* reset the buffer read/write ptr */
+ pdevinfo->rx_rbuf.head = pdevinfo->rx_rbuf.tail = 0;
+ pdevinfo->tx_rbuf.head = pdevinfo->tx_rbuf.tail = 0;
+ pdevinfo->ex_event = 0;
+ pdevinfo->tx_ok = 0;
+
+ init_waitqueue_head(&pdevinfo->rx_wq);
+ init_waitqueue_head(&pdevinfo->tx_wq);
+
+ drvdata = container_of(inode->i_cdev, struct mlb_data, cdev);
+ drvdata->devinfo = pdevinfo;
+ mxc_mlb150_irq_enable(drvdata, 1);
+ filp->private_data = drvdata;
+
+ return 0;
+}
+
+static int mxc_mlb150_release(struct inode *inode, struct file *filp)
+{
+ int minor;
+ struct mlb_data *drvdata = filp->private_data;
+ struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+
+ minor = MINOR(inode->i_rdev);
+ mxc_mlb150_irq_enable(drvdata, 0);
+
+#ifdef DEBUG
+ mlb150_dev_dump_reg();
+ mlb150_dev_dump_ctr_tbl(0, pdevinfo->channels[TX_CHANNEL].cl + 1);
+#endif
+
+ if (drvdata->use_iram)
+ gen_pool_free(drvdata->iram_pool,
+ (ulong)pdevinfo->rbuf_base_virt, drvdata->iram_size);
+
+ mlb150_dev_exit();
+
+ atomic_set(&pdevinfo->on, 0);
+
+ clk_disable_unprepare(drvdata->mlb);
+#ifdef CONFIG_ARCH_MXC_ARM64
+ clk_disable_unprepare(drvdata->hclk);
+ clk_disable_unprepare(drvdata->ipg);
+#endif
+ /* decrease the open count */
+ atomic_set(&pdevinfo->opencnt, 0);
+
+ drvdata->devinfo = NULL;
+
+ return 0;
+}
+
+static long mxc_mlb150_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ //struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = file_inode(filp);
+ struct mlb_data *drvdata = filp->private_data;
+ struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+ void __user *argp = (void __user *)arg;
+ unsigned long flags, event;
+ int minor;
+
+ minor = MINOR(inode->i_rdev);
+
+ switch (cmd) {
+ case MLB_CHAN_SETADDR:
+ {
+ unsigned int caddr;
+ /* get channel address from user space */
+ if (copy_from_user(&caddr, argp, sizeof(caddr))) {
+ pr_err("mxc_mlb150: copy from user failed\n");
+ return -EFAULT;
+ }
+ pdevinfo->channels[TX_CHANNEL].address =
+ (caddr >> 16) & 0xFFFF;
+ pdevinfo->channels[RX_CHANNEL].address = caddr & 0xFFFF;
+ pr_debug("mxc_mlb150: set ch addr, tx: %d, rx: %d\n",
+ pdevinfo->channels[TX_CHANNEL].address,
+ pdevinfo->channels[RX_CHANNEL].address);
+ break;
+ }
+
+ case MLB_CHAN_STARTUP:
+ if (atomic_read(&pdevinfo->on)) {
+ pr_debug("mxc_mlb150: channel alreadly startup\n");
+ break;
+ }
+ if (mlb_channel_enable(drvdata, minor, 1))
+ return -EFAULT;
+ break;
+ case MLB_CHAN_SHUTDOWN:
+ if (atomic_read(&pdevinfo->on) == 0) {
+ pr_debug("mxc_mlb150: channel areadly shutdown\n");
+ break;
+ }
+ mlb150_trans_complete_check(pdevinfo);
+ mlb_channel_enable(drvdata, minor, 0);
+ break;
+ case MLB_CHAN_GETEVENT:
+ /* get and clear the ex_event */
+ spin_lock_irqsave(&pdevinfo->event_lock, flags);
+ event = pdevinfo->ex_event;
+ pdevinfo->ex_event = 0;
+ spin_unlock_irqrestore(&pdevinfo->event_lock, flags);
+
+ if (event) {
+ if (copy_to_user(argp, &event, sizeof(event))) {
+ pr_err("mxc_mlb150: copy to user failed\n");
+ return -EFAULT;
+ }
+ } else
+ return -EAGAIN;
+ break;
+ case MLB_SET_ISOC_BLKSIZE_188:
+ pdevinfo->isoc_blksz = 188;
+ pdevinfo->cdt_buf_dep = pdevinfo->adt_buf_dep =
+ pdevinfo->isoc_blksz * CH_ISOC_BLK_NUM;
+ break;
+ case MLB_SET_ISOC_BLKSIZE_196:
+ pdevinfo->isoc_blksz = 196;
+ pdevinfo->cdt_buf_dep = pdevinfo->adt_buf_dep =
+ pdevinfo->isoc_blksz * CH_ISOC_BLK_NUM;
+ break;
+ case MLB_SET_SYNC_QUAD:
+ {
+ u32 quad;
+
+ if (copy_from_user(&quad, argp, sizeof(quad))) {
+ pr_err("mxc_mlb150: get quad number "
+ "from user failed\n");
+ return -EFAULT;
+ }
+ if (quad <= 0 || quad > 3) {
+ pr_err("mxc_mlb150: Invalid Quadlets!"
+ "Quadlets in Sync mode can "
+ "only be 1, 2, 3\n");
+ return -EINVAL;
+ }
+ pdevinfo->sync_quad = quad;
+ /* Each quadlets is 4 bytes */
+ pdevinfo->cdt_buf_dep = quad * 4 * 4;
+ pdevinfo->adt_buf_dep =
+ pdevinfo->cdt_buf_dep * CH_SYNC_ADT_BUF_MULTI;
+ }
+ break;
+ case MLB_SET_FPS:
+ {
+ u32 fps, c0_val;
+
+ /* get fps from user space */
+ if (copy_from_user(&fps, argp, sizeof(fps))) {
+ pr_err("mxc_mlb150: copy from user failed\n");
+ return -EFAULT;
+ }
+
+ if ((fps > 1024) &&
+ !(drvdata->quirk_flag & MLB_QUIRK_MLB150)) {
+ pr_err("mxc_mlb150: not support fps %d\n", fps);
+ return -EINVAL;
+ }
+
+ c0_val = __raw_readl(mlb_base + REG_MLBC0);
+ c0_val &= ~MLBC0_MLBCLK_MASK;
+
+ /* check fps value */
+ switch (fps) {
+ case 256:
+ case 512:
+ case 1024:
+ pdevinfo->fps = fps >> 9;
+ c0_val &= ~MLBC0_MLBPEN;
+ c0_val |= (fps >> 9)
+ << MLBC0_MLBCLK_SHIFT;
+
+ if (1024 == fps) {
+ /*
+ * Invert output clock phase
+ * in 1024 fps
+ */
+ __raw_writel(0x1,
+ mlb_base + REG_MLBPC2);
+ }
+ break;
+ case 2048:
+ case 3072:
+ case 4096:
+ pdevinfo->fps = (fps >> 10) + 1;
+ c0_val |= ((fps >> 10) + 1)
+ << MLBC0_MLBCLK_SHIFT;
+ break;
+ case 6144:
+ pdevinfo->fps = fps >> 10;
+ c0_val |= ((fps >> 10) + 1)
+ << MLBC0_MLBCLK_SHIFT;
+ break;
+ case 8192:
+ pdevinfo->fps = (fps >> 10) - 1;
+ c0_val |= ((fps >> 10) - 1)
+ << MLBC0_MLBCLK_SHIFT;
+ break;
+ default:
+ pr_debug("mxc_mlb150: invalid fps argument: %d\n",
+ fps);
+ return -EINVAL;
+ }
+
+ __raw_writel(c0_val, mlb_base + REG_MLBC0);
+
+ pr_debug("mxc_mlb150: set fps to %d, MLBC0: 0x%08x\n",
+ fps,
+ (u32)__raw_readl(mlb_base + REG_MLBC0));
+
+ break;
+ }
+
+ case MLB_GET_VER:
+ {
+ u32 version;
+
+ /* get MLB device module version */
+ version = 0x03030003;
+
+ pr_debug("mxc_mlb150: get version: 0x%08x\n",
+ version);
+
+ if (copy_to_user(argp, &version, sizeof(version))) {
+ pr_err("mxc_mlb150: copy to user failed\n");
+ return -EFAULT;
+ }
+ break;
+ }
+
+ case MLB_SET_DEVADDR:
+ {
+ u32 c1_val;
+ u8 devaddr;
+
+ /* get MLB device address from user space */
+ if (copy_from_user
+ (&devaddr, argp, sizeof(unsigned char))) {
+ pr_err("mxc_mlb150: copy from user failed\n");
+ return -EFAULT;
+ }
+
+ c1_val = __raw_readl(mlb_base + REG_MLBC1);
+ c1_val &= ~MLBC1_NDA_MASK;
+ c1_val |= devaddr << MLBC1_NDA_SHIFT;
+ __raw_writel(c1_val, mlb_base + REG_MLBC1);
+ pr_debug("mxc_mlb150: set dev addr, dev addr: %d, "
+ "MLBC1: 0x%08x\n", devaddr,
+ (u32)__raw_readl(mlb_base + REG_MLBC1));
+
+ break;
+ }
+
+ case MLB_IRQ_DISABLE:
+ {
+ disable_irq(drvdata->irq_mlb);
+ break;
+ }
+
+ case MLB_IRQ_ENABLE:
+ {
+ enable_irq(drvdata->irq_mlb);
+ break;
+ }
+ default:
+ pr_info("mxc_mlb150: Invalid ioctl command\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * MLB read routine
+ * Read the current received data from queued buffer,
+ * and free this buffer for hw to fill ingress data.
+ */
+static ssize_t mxc_mlb150_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ int size;
+ struct mlb_data *drvdata = filp->private_data;
+ struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+ struct mlb_ringbuf *rx_rbuf = &pdevinfo->rx_rbuf;
+ int head, tail;
+ unsigned long flags;
+
+ read_lock_irqsave(&rx_rbuf->rb_lock, flags);
+
+ head = ACCESS_ONCE(rx_rbuf->head);
+ tail = rx_rbuf->tail;
+
+ read_unlock_irqrestore(&rx_rbuf->rb_lock, flags);
+
+ /* check the current rx buffer is available or not */
+ if (0 == CIRC_CNT(head, tail, TRANS_RING_NODES)) {
+
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ do {
+ DEFINE_WAIT(__wait);
+
+ for (;;) {
+ prepare_to_wait(&pdevinfo->rx_wq,
+ &__wait, TASK_INTERRUPTIBLE);
+
+ read_lock_irqsave(&rx_rbuf->rb_lock, flags);
+ if (CIRC_CNT(rx_rbuf->head, rx_rbuf->tail,
+ TRANS_RING_NODES) > 0) {
+ read_unlock_irqrestore(&rx_rbuf->rb_lock,
+ flags);
+ break;
+ }
+ read_unlock_irqrestore(&rx_rbuf->rb_lock,
+ flags);
+
+ if (!signal_pending(current)) {
+ schedule();
+ continue;
+ }
+ return -ERESTARTSYS;
+ }
+ finish_wait(&pdevinfo->rx_wq, &__wait);
+ } while (0);
+ }
+
+ /* read index before reading contents at that index */
+ smp_read_barrier_depends();
+
+ size = pdevinfo->adt_buf_dep;
+ if (size > count) {
+ /* the user buffer is too small */
+ pr_warn("mxc_mlb150: received data size is biggerthan size:"
+ "%d, count: %d\n", size, (int)count);
+ return -EINVAL;
+ }
+
+ /* extract one item from the buffer */
+ if (copy_to_user(buf, rx_rbuf->virt_bufs[tail], size)) {
+ pr_err("mxc_mlb150: copy from user failed\n");
+ return -EFAULT;
+ }
+
+ /* finish reading descriptor before incrementing tail */
+ smp_mb();
+
+ write_lock_irqsave(&rx_rbuf->rb_lock, flags);
+ rx_rbuf->tail = (tail + 1) & (TRANS_RING_NODES - 1);
+ write_unlock_irqrestore(&rx_rbuf->rb_lock, flags);
+
+ *f_pos = 0;
+
+ return size;
+}
+
+/*
+ * MLB write routine
+ * Copy the user data to tx channel buffer,
+ * and prepare the channel current/next buffer ptr.
+ */
+static ssize_t mxc_mlb150_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ s32 ret = 0;
+ struct mlb_channel_info *pchinfo = NULL;
+ struct mlb_data *drvdata = filp->private_data;
+ struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+ struct mlb_ringbuf *tx_rbuf = &pdevinfo->tx_rbuf;
+ int head, tail;
+ unsigned long flags;
+
+ /*
+ * minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+ */
+ pchinfo = &pdevinfo->channels[TX_CHANNEL];
+
+ if (count > pdevinfo->buf_size) {
+ /* too many data to write */
+ pr_warning("mxc_mlb150: overflow write data\n");
+ return -EFBIG;
+ }
+
+ *f_pos = 0;
+
+ read_lock_irqsave(&tx_rbuf->rb_lock, flags);
+
+ head = tx_rbuf->head;
+ tail = ACCESS_ONCE(tx_rbuf->tail);
+ read_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
+
+ if (0 == CIRC_SPACE(head, tail, TRANS_RING_NODES)) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ do {
+ DEFINE_WAIT(__wait);
+
+ for (;;) {
+ prepare_to_wait(&pdevinfo->tx_wq,
+ &__wait, TASK_INTERRUPTIBLE);
+
+ read_lock_irqsave(&tx_rbuf->rb_lock, flags);
+ if (CIRC_SPACE(tx_rbuf->head, tx_rbuf->tail,
+ TRANS_RING_NODES) > 0) {
+ read_unlock_irqrestore(&tx_rbuf->rb_lock,
+ flags);
+ break;
+ }
+ read_unlock_irqrestore(&tx_rbuf->rb_lock,
+ flags);
+
+ if (!signal_pending(current)) {
+ schedule();
+ continue;
+ }
+ return -ERESTARTSYS;
+ }
+ finish_wait(&pdevinfo->tx_wq, &__wait);
+ } while (0);
+ }
+
+ if (copy_from_user((void *)tx_rbuf->virt_bufs[head], buf, count)) {
+ read_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
+ pr_err("mxc_mlb: copy from user failed\n");
+ ret = -EFAULT;
+ goto out;
+ }
+
+ write_lock_irqsave(&tx_rbuf->rb_lock, flags);
+ smp_wmb();
+ tx_rbuf->head = (head + 1) & (TRANS_RING_NODES - 1);
+ write_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
+
+ if (0 == CIRC_CNT(head, tail, TRANS_RING_NODES)) {
+ u32 tx_buf_ptr, ahb_ch;
+ s32 adt_sts;
+ u32 ctype = pdevinfo->channel_type;
+
+ /* read index before reading contents at that index */
+ smp_read_barrier_depends();
+
+ tx_buf_ptr = tx_rbuf->phy_addrs[tail];
+
+ ahb_ch = pdevinfo->channels[TX_CHANNEL].cl;
+ adt_sts = mlb150_dev_get_adt_sts(ahb_ch);
+
+ /* Set ADT for TX */
+ mlb150_dev_pipo_next(ahb_ch, ctype, adt_sts, tx_buf_ptr);
+ }
+
+ ret = count;
+out:
+ return ret;
+}
+
+static unsigned int mxc_mlb150_poll(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ int minor;
+ unsigned int ret = 0;
+ struct mlb_data *drvdata = filp->private_data;
+ struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+ struct mlb_ringbuf *tx_rbuf = &pdevinfo->tx_rbuf;
+ struct mlb_ringbuf *rx_rbuf = &pdevinfo->rx_rbuf;
+ int head, tail;
+ unsigned long flags;
+
+
+ minor = MINOR(file_inode(filp)->i_rdev);
+
+ poll_wait(filp, &pdevinfo->rx_wq, wait);
+ poll_wait(filp, &pdevinfo->tx_wq, wait);
+
+ read_lock_irqsave(&tx_rbuf->rb_lock, flags);
+ head = tx_rbuf->head;
+ tail = tx_rbuf->tail;
+ read_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
+
+ /* check the tx buffer is avaiable or not */
+ if (CIRC_SPACE(head, tail, TRANS_RING_NODES) >= 1)
+ ret |= POLLOUT | POLLWRNORM;
+
+ read_lock_irqsave(&rx_rbuf->rb_lock, flags);
+ head = rx_rbuf->head;
+ tail = rx_rbuf->tail;
+ read_unlock_irqrestore(&rx_rbuf->rb_lock, flags);
+
+ /* check the rx buffer filled or not */
+ if (CIRC_CNT(head, tail, TRANS_RING_NODES) >= 1)
+ ret |= POLLIN | POLLRDNORM;
+
+
+ /* check the exception event */
+ if (pdevinfo->ex_event)
+ ret |= POLLIN | POLLRDNORM;
+
+ return ret;
+}
+
+/*
+ * char dev file operations structure
+ */
+static const struct file_operations mxc_mlb150_fops = {
+
+ .owner = THIS_MODULE,
+ .open = mxc_mlb150_open,
+ .release = mxc_mlb150_release,
+ .unlocked_ioctl = mxc_mlb150_ioctl,
+ .poll = mxc_mlb150_poll,
+ .read = mxc_mlb150_read,
+ .write = mxc_mlb150_write,
+};
+
+static struct platform_device_id imx_mlb150_devtype[] = {
+ {
+ .name = "imx6q-mlb150",
+ .driver_data = MLB_QUIRK_MLB150,
+ }, {
+ .name = "imx6sx-mlb50",
+ .driver_data = 0,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(platform, imx_mlb150_devtype);
+
+static const struct of_device_id mlb150_imx_dt_ids[] = {
+ { .compatible = "fsl,imx6q-mlb150",
+ .data = &imx_mlb150_devtype[IMX6Q_MLB], },
+ { .compatible = "fsl,imx6sx-mlb50",
+ .data = &imx_mlb150_devtype[IMX6SX_MLB], },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mlb150_imx_dt_ids);
+
+/*
+ * This function is called whenever the MLB device is detected.
+ */
+static int mxc_mlb150_probe(struct platform_device *pdev)
+{
+ int ret, mlb_major, i;
+ struct mlb_data *drvdata;
+ struct resource *res;
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *of_id;
+
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(struct mlb_data),
+ GFP_KERNEL);
+ if (!drvdata) {
+ dev_err(&pdev->dev, "can't allocate enough memory\n");
+ return -ENOMEM;
+ }
+
+ drvdata->dev = &pdev->dev;
+ of_id = of_match_device(mlb150_imx_dt_ids, &pdev->dev);
+ if (of_id)
+ pdev->id_entry = of_id->data;
+ else
+ return -EINVAL;
+ /*
+ * Register MLB lld as four character devices
+ */
+ ret = alloc_chrdev_region(&drvdata->firstdev, 0,
+ MLB_MINOR_DEVICES, "mxc_mlb150");
+ if (ret < 0) {
+ dev_err(&pdev->dev, "alloc region error\n");
+ goto err_reg;
+ }
+ mlb_major = MAJOR(drvdata->firstdev);
+ dev_dbg(&pdev->dev, "MLB device major: %d\n", mlb_major);
+
+ cdev_init(&drvdata->cdev, &mxc_mlb150_fops);
+ drvdata->cdev.owner = THIS_MODULE;
+
+ ret = cdev_add(&drvdata->cdev, drvdata->firstdev, MLB_MINOR_DEVICES);
+ if (ret) {
+ dev_err(&pdev->dev, "can't add cdev\n");
+ goto err_reg;
+ }
+
+ /* create class and device for udev information */
+ drvdata->class = class_create(THIS_MODULE, "mlb150");
+ if (IS_ERR(drvdata->class)) {
+ dev_err(&pdev->dev, "failed to create device class\n");
+ ret = -ENOMEM;
+ goto err_class;
+ }
+
+ for (i = 0; i < MLB_MINOR_DEVICES; i++) {
+ struct device *class_dev;
+
+ class_dev = device_create(drvdata->class, NULL,
+ MKDEV(mlb_major, i),
+ NULL, mlb_devinfo[i].dev_name);
+ if (IS_ERR(class_dev)) {
+ dev_err(&pdev->dev, "failed to create mlb150 %s"
+ " class device\n", mlb_devinfo[i].dev_name);
+ ret = -ENOMEM;
+ goto err_dev;
+ }
+ }
+
+ drvdata->quirk_flag = pdev->id_entry->driver_data;
+
+ /* ahb0 irq */
+ drvdata->irq_ahb0 = platform_get_irq(pdev, 1);
+ if (drvdata->irq_ahb0 < 0) {
+ dev_err(&pdev->dev, "No ahb0 irq line provided\n");
+ goto err_dev;
+ }
+ dev_dbg(&pdev->dev, "ahb0_irq: %d\n", drvdata->irq_ahb0);
+ if (devm_request_irq(&pdev->dev, drvdata->irq_ahb0, mlb_ahb_isr,
+ 0, "mlb_ahb0", NULL)) {
+ dev_err(&pdev->dev, "can't claim irq %d\n", drvdata->irq_ahb0);
+ goto err_dev;
+ }
+
+ /* ahb1 irq */
+ drvdata->irq_ahb1 = platform_get_irq(pdev, 2);
+ dev_dbg(&pdev->dev, "ahb1_irq: %d\n", drvdata->irq_ahb1);
+ if (drvdata->irq_ahb1 > 0) {
+ if (devm_request_irq(&pdev->dev, drvdata->irq_ahb1, mlb_ahb_isr,
+ 0, "mlb_ahb1", NULL)) {
+ dev_err(&pdev->dev, "can't claim irq %d\n", drvdata->irq_ahb1);
+ goto err_dev;
+ }
+ }
+
+ /* mlb irq */
+ drvdata->irq_mlb = platform_get_irq(pdev, 0);
+ if (drvdata->irq_mlb < 0) {
+ dev_err(&pdev->dev, "No mlb irq line provided\n");
+ goto err_dev;
+ }
+ dev_dbg(&pdev->dev, "mlb_irq: %d\n", drvdata->irq_mlb);
+ if (devm_request_irq(&pdev->dev, drvdata->irq_mlb, mlb_isr,
+ 0, "mlb", NULL)) {
+ dev_err(&pdev->dev, "can't claim irq %d\n", drvdata->irq_mlb);
+ goto err_dev;
+ }
+
+ /* ioremap from phy mlb to kernel space */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't get device resources\n");
+ ret = -ENOENT;
+ goto err_dev;
+ }
+ mlb_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mlb_base)) {
+ dev_err(&pdev->dev,
+ "failed to get ioremap base\n");
+ ret = PTR_ERR(mlb_base);
+ goto err_dev;
+ }
+ drvdata->membase = mlb_base;
+
+#ifdef CONFIG_REGULATOR
+ drvdata->nvcc = devm_regulator_get(&pdev->dev, "reg_nvcc");
+ if (!IS_ERR(drvdata->nvcc)) {
+ regulator_set_voltage(drvdata->nvcc, 2500000, 2500000);
+ dev_err(&pdev->dev, "enalbe regulator\n");
+ ret = regulator_enable(drvdata->nvcc);
+ if (ret) {
+ dev_err(&pdev->dev, "vdd set voltage error\n");
+ goto err_dev;
+ }
+ }
+#endif
+
+#ifdef CONFIG_ARCH_MXC_ARM64
+ drvdata->ipg = devm_clk_get(&pdev->dev, "ipg");
+ if (IS_ERR(drvdata->ipg)) {
+ dev_err(&pdev->dev, "unable to get mlb ipg clock\n");
+ ret = PTR_ERR(drvdata->ipg);
+ goto err_dev;
+ };
+
+ drvdata->hclk = devm_clk_get(&pdev->dev, "hclk");
+ if (IS_ERR(drvdata->hclk)) {
+ dev_err(&pdev->dev, "unable to get mlb hclk clock\n");
+ ret = PTR_ERR(drvdata->hclk);
+ goto err_dev;
+ };
+#endif
+
+ drvdata->mlb = devm_clk_get(&pdev->dev, "mlb");
+ if (IS_ERR(drvdata->mlb)) {
+ dev_err(&pdev->dev, "unable to get mlb clock\n");
+ ret = PTR_ERR(drvdata->mlb);
+ goto err_dev;
+ }
+
+ drvdata->iram_pool = of_gen_pool_get(np, "iram", 0);
+ if (!drvdata->iram_pool)
+ dev_warn(&pdev->dev, "no iram assigned, using external mem\n");
+
+ drvdata->devinfo = NULL;
+ mxc_mlb150_irq_enable(drvdata, 0);
+ platform_set_drvdata(pdev, drvdata);
+ return 0;
+
+err_dev:
+ for (--i; i >= 0; i--)
+ device_destroy(drvdata->class, MKDEV(mlb_major, i));
+
+ class_destroy(drvdata->class);
+err_class:
+ cdev_del(&drvdata->cdev);
+err_reg:
+ unregister_chrdev_region(drvdata->firstdev, MLB_MINOR_DEVICES);
+
+ return ret;
+}
+
+static int mxc_mlb150_remove(struct platform_device *pdev)
+{
+ int i;
+ struct mlb_data *drvdata = platform_get_drvdata(pdev);
+ struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+
+ if (pdevinfo && atomic_read(&pdevinfo->opencnt))
+ clk_disable_unprepare(drvdata->mlb);
+
+ /* disable mlb power */
+#ifdef CONFIG_REGULATOR
+ if (!IS_ERR(drvdata->nvcc))
+ regulator_disable(drvdata->nvcc);
+#endif
+
+ /* destroy mlb device class */
+ for (i = MLB_MINOR_DEVICES - 1; i >= 0; i--)
+ device_destroy(drvdata->class,
+ MKDEV(MAJOR(drvdata->firstdev), i));
+ class_destroy(drvdata->class);
+
+ cdev_del(&drvdata->cdev);
+
+ /* Unregister the two MLB devices */
+ unregister_chrdev_region(drvdata->firstdev, MLB_MINOR_DEVICES);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mxc_mlb150_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct mlb_data *drvdata = platform_get_drvdata(pdev);
+ struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+
+ if (pdevinfo && atomic_read(&pdevinfo->opencnt)) {
+ mlb150_dev_exit();
+ clk_disable_unprepare(drvdata->mlb);
+ }
+
+ return 0;
+}
+
+static int mxc_mlb150_resume(struct platform_device *pdev)
+{
+ struct mlb_data *drvdata = platform_get_drvdata(pdev);
+ struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+
+ if (pdevinfo && atomic_read(&pdevinfo->opencnt)) {
+ clk_prepare_enable(drvdata->mlb);
+ mlb150_dev_init();
+ }
+
+ return 0;
+}
+#else
+#define mxc_mlb150_suspend NULL
+#define mxc_mlb150_resume NULL
+#endif
+
+/*
+ * platform driver structure for MLB
+ */
+static struct platform_driver mxc_mlb150_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = mlb150_imx_dt_ids,
+ },
+ .probe = mxc_mlb150_probe,
+ .remove = mxc_mlb150_remove,
+ .suspend = mxc_mlb150_suspend,
+ .resume = mxc_mlb150_resume,
+ .id_table = imx_mlb150_devtype,
+};
+
+static int __init mxc_mlb150_init(void)
+{
+ return platform_driver_register(&mxc_mlb150_driver);
+}
+
+static void __exit mxc_mlb150_exit(void)
+{
+ platform_driver_unregister(&mxc_mlb150_driver);
+}
+
+module_init(mxc_mlb150_init);
+module_exit(mxc_mlb150_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MLB150 low level driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mxc/sim/Kconfig b/drivers/mxc/sim/Kconfig
new file mode 100644
index 000000000000..d5b9e3e1e929
--- /dev/null
+++ b/drivers/mxc/sim/Kconfig
@@ -0,0 +1,27 @@
+#
+# SIM configuration
+#
+
+menu "MXC SIM Support"
+
+config MXC_SIMv2
+ tristate "MXC SIMv2 support"
+ depends on ARCH_MXC && MXC_SIM
+ default n
+ ---help---
+ Say Y if you want to use the SIMv2 on NXP i.MX6/7 processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called imx_sim.
+
+config MXC_EMVSIM
+ tristate "IMX EMVSIM support"
+ depends on ARCH_MXC_ARM64 && MXC_SIM
+ default n
+ ---help---
+ Say Y here if you want to use the EMVSIM on NXP i.MX8 processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called imx_emvsim.
+
+endmenu
diff --git a/drivers/mxc/sim/Makefile b/drivers/mxc/sim/Makefile
new file mode 100644
index 000000000000..7b1ca96b6b28
--- /dev/null
+++ b/drivers/mxc/sim/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the i.MX SIM driver
+#
+
+obj-$(CONFIG_MXC_SIMv2) += imx_sim.o
+obj-$(CONFIG_MXC_EMVSIM) += imx_emvsim.o
diff --git a/drivers/mxc/sim/imx_emvsim.c b/drivers/mxc/sim/imx_emvsim.c
new file mode 100644
index 000000000000..59f54dcd533e
--- /dev/null
+++ b/drivers/mxc/sim/imx_emvsim.c
@@ -0,0 +1,1638 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mxc_sim_interface.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#define DRIVER_NAME "mxc_emvsim"
+
+/* Definitions of the offset of the SIM hardware registers */
+#define EMV_SIM_VER_ID 0X00
+#define EMV_SIM_PARAM 0X04
+#define EMV_SIM_CLKCFG 0X08
+#define EMV_SIM_DIVISOR 0X0C
+#define EMV_SIM_CTRL 0X10
+#define EMV_SIM_INT_MASK 0X14
+#define EMV_SIM_RX_THD 0X18
+#define EMV_SIM_TX_THD 0X1C
+#define EMV_SIM_RX_STATUS 0X20
+#define EMV_SIM_TX_STATUS 0X24
+#define EMV_SIM_PCSR 0X28
+#define EMV_SIM_RX_BUF 0X2C
+#define EMV_SIM_TX_BUF 0X30
+#define EMV_SIM_TX_GETU 0X34
+#define EMV_SIM_CWT_VAL 0X38
+#define EMV_SIM_BWT_VAL 0X3C
+#define EMV_SIM_BGT_VAL 0X40
+#define EMV_SIM_GPCNT0_VAL 0X44
+#define EMV_SIM_GPCNT1_VAL 0X48
+
+#define SIM_XMT_BUFFER_SIZE 300
+#define SIM_RCV_BUFFER_SIZE 400
+
+#define SIM_TX_FIFO_DEPTH 16
+#define SIM_RX_FIFO_DEPTH 16
+#define TX_FIFO_THRESHOLD 4
+
+#define SIM_STATE_REMOVED 0
+#define SIM_STATE_DETECTED 1
+#define SIM_STATE_ATR_RECEIVING 2
+#define SIM_STATE_ATR_RECEIVED 3
+#define SIM_STATE_XMTING 4
+#define SIM_STATE_XMT_DONE 5
+#define SIM_STATE_XMT_ERROR 6
+#define SIM_STATE_RECEIVING 7
+#define SIM_STATE_RECEIVE_DONE 8
+#define SIM_STATE_RECEIVE_ERROR 9
+#define SIM_STATE_RESET_SEQUENCY 10
+
+#define SIM_CNTL_GPCNT_RESET 0
+#define SIM_CNTL_GPCNT_CARD_CLK 1
+#define SIM_CNTL_GPCNT_RCV_CLK 2
+#define SIM_CNTL_GPCNT_ETU_CLK 3
+#define SIM_EMV_NACK_THRESHOLD 5
+#define EMV_T0_BGT 16
+#define EMV_T1_BGT 22
+#define ATR_THRESHOLD_MAX 100
+#define ATR_MAX_CWT 10080
+#define ATR_MAX_DURATION 20160
+#define FCLK_FREQ 4000000
+
+#define ATR_TIMEOUT 5
+#define TX_TIMEOUT 10
+#define RX_TIMEOUT 100
+#define RESET_RETRY_TIMES 5
+#define EMV_RESET_LOW_CYCLES 40000
+#define ATR_MAX_DELAY_CLK 46400
+#define DIVISOR_VALUE 372
+
+#define SIM_CNTL_GPCNT0_CLK_SEL_MASK (3 << 10)
+#define SIM_CNTL_GPCNT0_CLK_SEL(x) ((x & 3) << 10)
+#define SIM_CNTL_GPCNT1_CLK_SEL_MASK (3 << 8)
+#define SIM_CNTL_GPCNT1_CLK_SEL(x) ((x & 3) << 8)
+
+/* EMV_SIM_CTRL */
+#define IC (1 << 0)
+#define ICM (1 << 1)
+#define ANACK (1 << 2)
+#define ONACK (1 << 3)
+#define FLSH_RX (1 << 8)
+#define FLSH_TX (1 << 9)
+#define SW_RST (1 << 10)
+#define KILL_CLOCKS (1 << 11)
+#define RCV_EN (1 << 16)
+#define XMT_EN (1 << 17)
+#define RCVR_11 (1 << 18)
+#define CWT_EN (1 << 27)
+#define BWT_EN (1 << 31)
+
+/* EMV_SIM_INT_MASK */
+#define RDT_IM (1 << 0)
+#define TC_IM (1 << 1)
+#define ETC_IM (1 << 3)
+#define TNACK_IM (1 << 5)
+#define TDT_IM (1 << 7)
+#define GPCNT0_IM (1 << 8)
+#define CWT_ERR_IM (1 << 9)
+#define RNACK_IM (1 << 10)
+#define BWT_ERR_IM (1 << 11)
+#define GPCNT1_IM (1 << 13)
+#define RX_DATA_IM (1 << 14)
+
+/* EMV_SIM_RX_THD */
+#define SIM_RCV_THRESHOLD_RDT_MASK (0x0f << 0)
+#define SIM_RCV_THRESHOLD_RDT(x) ((x & 0x0f) << 0)
+#define SIM_RCV_THRESHOLD_RTH_MASK (0x0f << 8)
+#define SIM_RCV_THRESHOLD_RTH(x) ((x & 0x0f) << 8)
+
+/* EMV_SIM_TX_THD */
+#define SIM_XMT_THRESHOLD_TDT_MASK (0x0f << 0)
+#define SIM_XMT_THRESHOLD_TDT(x) ((x & 0x0f) << 0)
+#define SIM_XMT_THRESHOLD_XTH_MASK (0x0f << 8)
+#define SIM_XMT_THRESHOLD_XTH(x) ((x & 0x0f) << 8)
+
+/* EMV_SIM_RX_STATUS */
+#define RX_DATA (1 << 4)
+#define RDTF (1 << 5)
+#define CWT_ERR (1 << 8)
+#define RTE (1 << 9)
+#define BWT_ERR (1 << 10)
+#define BGT_ERR (1 << 11)
+#define PEF (1 << 12)
+#define FEF (1 << 13)
+
+/* EMV_SIM_TX_STATUS */
+#define TNTE (1 << 0)
+#define ETCF (1 << 4)
+#define TCF (1 << 5)
+#define TDTF (1 << 7)
+#define GPCNT0_TO (1 << 8)
+#define GPCNT1_TO (1 << 9)
+
+/* EMV_SIM_PCSR */
+#define SAPD (1 << 0)
+#define SVCC_EN (1 << 1)
+#define VCCENP (1 << 2)
+#define SRST (1 << 3)
+#define SCEN (1 << 4)
+#define SPD (1 << 7)
+#define SPDIM (1 << 24)
+#define SPDIF (1 << 25)
+#define SPDP (1 << 26)
+#define SPDES (1 << 27)
+
+struct emvsim_t {
+ s32 present;
+ u8 open_cnt;
+ int state;
+ struct clk *clk;
+ struct clk *ipg;
+ struct resource *res;
+ void __iomem *ioaddr;
+ int irq;
+
+ int errval;
+ int protocol_type;
+ sim_timing_t timing_data;
+ sim_baud_t baud_rate;
+ int timeout;
+ u8 nack_threshold;
+ u8 nack_enable;
+ u32 expected_rcv_cnt;
+ u8 is_fixed_len_rec;
+ u32 xmt_remaining;
+ u32 xmt_pos;
+ u32 rcv_count;
+ u8 rcv_buffer[SIM_RCV_BUFFER_SIZE];
+ u8 xmt_buffer[SIM_XMT_BUFFER_SIZE];
+ struct completion xfer_done;
+ u16 rcv_head;
+ spinlock_t lock;
+ u32 clk_rate;
+ u8 checking_ts_timing;
+};
+
+static struct miscdevice emvsim_dev;
+
+static void emvsim_data_reset(struct emvsim_t *emvsim)
+{
+ emvsim->errval = SIM_OK;
+ emvsim->protocol_type = 0;
+ emvsim->timeout = 0;
+ emvsim->nack_threshold = SIM_EMV_NACK_THRESHOLD;
+ emvsim->nack_enable = 0;
+ memset(&emvsim->timing_data, 0, sizeof(emvsim->timing_data));
+ memset(&emvsim->baud_rate, 0, sizeof(emvsim->baud_rate));
+
+ emvsim->xmt_remaining = 0;
+ emvsim->xmt_pos = 0;
+ emvsim->rcv_count = 0;
+ emvsim->rcv_head = 0;
+ memset(emvsim->rcv_buffer, 0, SIM_RCV_BUFFER_SIZE);
+ memset(emvsim->xmt_buffer, 0, SIM_XMT_BUFFER_SIZE);
+
+ reinit_completion(&emvsim->xfer_done);
+};
+
+static void emvsim_set_nack(struct emvsim_t *emvsim, u8 enable)
+{
+ u32 reg_val;
+
+ reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+ /*Disable overrun NACK setting for now*/
+ reg_val &= ~ONACK;
+
+ if (enable) {
+ reg_val |= ANACK;
+ __raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_CTRL);
+
+ reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_TX_THD);
+ reg_val &= ~(SIM_XMT_THRESHOLD_XTH_MASK);
+ reg_val |= SIM_XMT_THRESHOLD_XTH(emvsim->nack_threshold);
+ __raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_TX_THD);
+ } else {
+ reg_val &= ~ANACK;
+ __raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_CTRL);
+ }
+
+ emvsim->nack_enable = enable;
+}
+
+static void emvsim_set_tx(struct emvsim_t *emvsim, u8 enable)
+{
+ u32 reg_data;
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+ if (enable) {
+ reg_data |= XMT_EN;
+ reg_data &= ~RCV_EN;
+ } else {
+ reg_data &= ~XMT_EN;
+ }
+
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_CTRL);
+}
+
+static void emvsim_set_rx(struct emvsim_t *emvsim, u8 enable)
+{
+ u32 reg_data;
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+ if (enable) {
+ reg_data |= RCV_EN;
+ reg_data &= ~XMT_EN;
+ } else {
+ reg_data &= ~RCV_EN;
+ }
+
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_CTRL);
+}
+
+static void emvsim_mask_timer0_int(struct emvsim_t *emvsim)
+{
+ u32 reg_data;
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+ reg_data |= GPCNT0_IM;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_TX_STATUS);
+ reg_data |= GPCNT0_TO;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_TX_STATUS);
+}
+
+static void emvsim_mask_timer1_int(struct emvsim_t *emvsim)
+{
+ u32 reg_data;
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+ reg_data |= GPCNT1_IM;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_TX_STATUS);
+ reg_data |= GPCNT1_TO;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_TX_STATUS);
+}
+
+static void emvsim_set_gpctimer0_clk(struct emvsim_t *emvsim, u8 clk_source)
+{
+ u32 reg_data;
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_CLKCFG);
+ reg_data &= ~SIM_CNTL_GPCNT0_CLK_SEL_MASK;
+ reg_data |= SIM_CNTL_GPCNT0_CLK_SEL(clk_source);
+ writel(reg_data, emvsim->ioaddr + EMV_SIM_CLKCFG);
+}
+
+static void emvsim_set_gpctimer1_clk(struct emvsim_t *emvsim, u8 clk_source)
+{
+ u32 reg_data;
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_CLKCFG);
+ reg_data &= ~SIM_CNTL_GPCNT1_CLK_SEL_MASK;
+ reg_data |= SIM_CNTL_GPCNT1_CLK_SEL(clk_source);
+ writel(reg_data, emvsim->ioaddr + EMV_SIM_CLKCFG);
+}
+
+static void emvsim_reset_gpctimer(struct emvsim_t *emvsim)
+{
+ emvsim_set_gpctimer0_clk(emvsim, SIM_CNTL_GPCNT_RESET);
+ emvsim_set_gpctimer1_clk(emvsim, SIM_CNTL_GPCNT_RESET);
+
+ /* need a tx_en posedge to update gpctimer0 clk */
+ emvsim_set_tx(emvsim, 0);
+ emvsim_set_tx(emvsim, 1);
+ emvsim_set_tx(emvsim, 0);
+}
+
+static int emvsim_reset_low_timing(struct emvsim_t *emvsim, u32 clock_cycle)
+{
+ int errval = 0;
+ int timeout = 0;
+ u32 fclk_in_khz, delay_in_us, reg_data;
+
+ fclk_in_khz = emvsim->clk_rate / MSEC_PER_SEC;
+ delay_in_us = EMV_RESET_LOW_CYCLES * USEC_PER_MSEC / fclk_in_khz;
+
+ emvsim_mask_timer0_int(emvsim);
+ __raw_writel(clock_cycle, emvsim->ioaddr + EMV_SIM_GPCNT0_VAL);
+ emvsim_set_gpctimer0_clk(emvsim, SIM_CNTL_GPCNT_CARD_CLK);
+ emvsim_set_tx(emvsim, 1);
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+ reg_data &= ~GPCNT0_IM;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+
+ timeout = wait_for_completion_timeout(
+ &emvsim->xfer_done,
+ msecs_to_jiffies(delay_in_us / 1000 * 2));
+ if (timeout == 0) {
+ dev_err(emvsim_dev.parent, "Reset low GPC timout\n");
+ errval = -SIM_E_TIMEOUT;
+ }
+
+ return errval;
+}
+
+static void emvsim_set_cwt(struct emvsim_t *emvsim, u8 enable)
+{
+ u32 reg_val;
+
+ reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+ if (enable && emvsim->timing_data.cwt)
+ reg_val |= CWT_EN;
+ else
+ reg_val &= ~CWT_EN;
+ __raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_CTRL);
+}
+
+static void emvsim_set_bwt(struct emvsim_t *emvsim, u8 enable)
+{
+ u32 reg_val;
+
+ reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+ if (enable && (emvsim->timing_data.bwt || emvsim->timing_data.bgt))
+ reg_val |= BWT_EN;
+ else
+ reg_val &= ~BWT_EN;
+ __raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_CTRL);
+}
+
+static int emvsim_reset_module(struct emvsim_t *emvsim)
+{
+ u32 reg_val;
+
+ reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+ reg_val |= SW_RST;
+ __raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_CTRL);
+
+ /* Software should allow a minimum of 4 Protocol clock cycles(4MHz)*/
+ usleep_range(1, 3);
+
+ return 0;
+}
+
+static void emvsim_receive_atr_set(struct emvsim_t *emvsim)
+{
+ u32 reg_data;
+
+ __raw_writel(0x0, emvsim->ioaddr + EMV_SIM_GPCNT1_VAL);
+ emvsim_set_gpctimer1_clk(emvsim, SIM_CNTL_GPCNT_ETU_CLK);
+ emvsim_set_rx(emvsim, 1);
+
+ /*Set the cwt timer.Refer the setting of ATR on EMV4.3 book*/
+ __raw_writel(ATR_MAX_CWT, emvsim->ioaddr + EMV_SIM_CWT_VAL);
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+ reg_data |= CWT_EN;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_CTRL);
+
+ emvsim_set_nack(emvsim, 0);
+ emvsim->errval = 0;
+ emvsim->rcv_count = 0;
+ emvsim->checking_ts_timing = 1;
+ emvsim->state = SIM_STATE_ATR_RECEIVING;
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+ reg_data |= CWT_ERR_IM;
+ reg_data &= ~(RX_DATA_IM | GPCNT0_IM);
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+}
+
+static int32_t emvsim_check_rec_data(u32 *reg_data)
+{
+ s32 err = 0;
+
+ if (*reg_data & CWT_ERR)
+ err |= SIM_ERROR_CWT;
+
+ if (*reg_data & FEF)
+ err |= SIM_ERROR_FRAME;
+
+ if (*reg_data & PEF)
+ err |= SIM_ERROR_PARITY;
+
+ return err;
+}
+
+static void emvsim_xmt_fill_fifo(struct emvsim_t *emvsim)
+{
+ u32 reg_data;
+ u32 bytesleft, i;
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_TX_STATUS);
+ bytesleft = SIM_TX_FIFO_DEPTH - ((reg_data >> 24) & 0x1F);
+
+ if (bytesleft > emvsim->xmt_remaining)
+ bytesleft = emvsim->xmt_remaining;
+
+ for (i = 0; i < bytesleft; i++) {
+ __raw_writel(emvsim->xmt_buffer[emvsim->xmt_pos],
+ emvsim->ioaddr + EMV_SIM_TX_BUF);
+ emvsim->xmt_pos++;
+ };
+ emvsim->xmt_remaining -= bytesleft;
+};
+
+static void emvsim_rcv_read_fifo(struct emvsim_t *emvsim)
+{
+ u16 i, count;
+ u32 reg_data;
+ u8 data;
+
+ count = __raw_readl(emvsim->ioaddr + EMV_SIM_RX_STATUS) >> 24;
+
+ spin_lock(&emvsim->lock);
+ for (i = 0; i < count; i++) {
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_RX_STATUS);
+ emvsim->errval |= emvsim_check_rec_data(&reg_data);
+
+ /* T1 mode and t0 mode no parity error, T1 mode SIM module
+ * will not produce NACK be NACK is disabled. T0 mode to
+ * ensure there is no parity error for the current byte
+ */
+ if (!(emvsim->nack_enable && (reg_data & PEF))) {
+ data = __raw_readb(emvsim->ioaddr + EMV_SIM_RX_BUF);
+ emvsim->rcv_buffer[emvsim->rcv_head + emvsim->rcv_count] = data;
+ emvsim->rcv_count++;
+ }
+
+ if (emvsim->rcv_head + emvsim->rcv_count >=
+ SIM_RCV_BUFFER_SIZE) {
+ dev_err(emvsim_dev.parent,
+ "The software fifo is full,head %d, cnt%d\n",
+ emvsim->rcv_head, emvsim->rcv_count);
+ break;
+ }
+ }
+ spin_unlock(&emvsim->lock);
+}
+
+static void emvsim_tx_irq_enable(struct emvsim_t *emvsim)
+{
+ u32 reg_val;
+
+ /*Clear the TX&RX status, W1C */
+ reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_TX_STATUS);
+ __raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_TX_STATUS);
+ reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_RX_STATUS);
+ __raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_RX_STATUS);
+
+ reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+ reg_val |= CWT_ERR_IM | BWT_ERR_IM | RX_DATA_IM | RX_DATA_IM;
+
+ if (emvsim->xmt_remaining != 0) {
+ reg_val &= ~TDT_IM;
+ } else {
+ reg_val &= ~TC_IM;
+ reg_val &= ~ETC_IM;
+ }
+
+ /* NACK interrupt is enabled only when T0 mode*/
+ if (emvsim->protocol_type == SIM_PROTOCOL_T0 ||
+ emvsim->nack_enable != 0)
+ reg_val &= ~TNACK_IM;
+ else
+ reg_val |= TNACK_IM;
+
+ __raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_INT_MASK);
+}
+
+static void emvsim_tx_irq_disable(struct emvsim_t *emvsim)
+{
+ u32 reg_val;
+
+ reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+ reg_val |= (TDT_IM | TC_IM | TNACK_IM | ETC_IM);
+ __raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_INT_MASK);
+}
+
+static void emvsim_rx_irq_enable(struct emvsim_t *emvsim)
+{
+ u32 reg_data;
+
+ /* Ensure the CWT timer is enabled */
+ emvsim_set_cwt(emvsim, 1);
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+ reg_data |= (TC_IM | TDT_IM | TNACK_IM);
+ reg_data &= ~(RX_DATA_IM | CWT_ERR_IM | BWT_ERR_IM);
+
+ if (emvsim->protocol_type == SIM_PROTOCOL_T0 ||
+ emvsim->nack_enable != 0)
+ reg_data &= ~RNACK_IM;
+ else
+ reg_data |= RNACK_IM;
+
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+}
+
+static void emvsim_rx_irq_disable(struct emvsim_t *emvsim)
+{
+ u32 reg_val;
+
+ reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+ reg_val |= (RX_DATA_IM | CWT_ERR_IM | BWT_ERR_IM | RNACK_IM);
+ __raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_INT_MASK);
+}
+
+static irqreturn_t emvsim_irq_handler(int irq, void *dev_id)
+{
+ u32 reg_data, tx_status, rx_status;
+ struct emvsim_t *emvsim = (struct emvsim_t *)dev_id;
+
+ /* clear TX/RX interrupt status, W1C*/
+ tx_status = __raw_readl(emvsim->ioaddr + EMV_SIM_TX_STATUS);
+ rx_status = __raw_readl(emvsim->ioaddr + EMV_SIM_RX_STATUS);
+ __raw_writel(tx_status, emvsim->ioaddr + EMV_SIM_TX_STATUS);
+ __raw_writel(rx_status, emvsim->ioaddr + EMV_SIM_RX_STATUS);
+
+ if (emvsim->state == SIM_STATE_ATR_RECEIVING &&
+ emvsim->checking_ts_timing == 1) {
+ if ((tx_status & GPCNT0_TO) && !(rx_status & RX_DATA)) {
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+ reg_data &= ~CWT_EN;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_CTRL);
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+ reg_data |= (GPCNT0_IM | CWT_ERR_IM | RX_DATA_IM);
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+
+ emvsim->errval = SIM_ERROR_ATR_DELAY;
+ complete(&emvsim->xfer_done);
+ emvsim->checking_ts_timing = 0;
+ } else if (rx_status & RX_DATA) {
+ u8 rdt = 1;
+
+ emvsim_mask_timer0_int(emvsim);
+
+ /* ATR each received byte will cost 12 ETU */
+ reg_data = ATR_MAX_DURATION - emvsim->rcv_count * 12;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_GPCNT1_VAL);
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+ reg_data &= ~(GPCNT1_IM | CWT_ERR_IM | RX_DATA_IM);
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+ emvsim_rcv_read_fifo(emvsim);
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_TX_STATUS);
+ reg_data |= GPCNT1_TO;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_TX_STATUS);
+
+ reg_data = SIM_RCV_THRESHOLD_RTH(0) | SIM_RCV_THRESHOLD_RDT(rdt);
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_RX_THD);
+
+ /* ATR has arrived as EMV demands */
+ emvsim->checking_ts_timing = 0;
+ } else {
+ dev_err(emvsim_dev.parent,
+ "Unexpected irq when delay checking\n");
+ }
+ }
+
+ else if (emvsim->state == SIM_STATE_ATR_RECEIVING) {
+ /*CWT ERROR OR ATR_MAX_DURATION TIMEOUT */
+ if ((rx_status & CWT_ERR) ||
+ ((tx_status & GPCNT1_TO) && (emvsim->rcv_count != 0))) {
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+ reg_data &= ~CWT_EN;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_CTRL);
+
+ reg_data = __raw_readl(emvsim->ioaddr +
+ EMV_SIM_INT_MASK);
+ reg_data |= (GPCNT1_IM | CWT_ERR_IM | RX_DATA_IM | GPCNT0_IM);
+ __raw_writel(reg_data, emvsim->ioaddr +
+ EMV_SIM_INT_MASK);
+
+ if (tx_status & GPCNT1_TO)
+ emvsim->errval |= SIM_ERROR_ATR_TIMEROUT;
+
+ if (rx_status & CWT_ERR)
+ emvsim->errval |= SIM_ERROR_CWT;
+
+ emvsim_rcv_read_fifo(emvsim);
+ emvsim->state = SIM_STATE_ATR_RECEIVED;
+
+ complete(&emvsim->xfer_done);
+ } else if (rx_status & RX_DATA) {
+ emvsim_rcv_read_fifo(emvsim);
+ }
+ }
+
+ else if (emvsim->state == SIM_STATE_XMTING) {
+ /* need to enable CWT timer */
+ if (tx_status & ETCF)
+ emvsim_set_cwt(emvsim, 1);
+
+ if (tx_status & TNTE) {
+ emvsim_set_tx(emvsim, 0);
+
+ /*Disalbe the timers*/
+ emvsim_set_cwt(emvsim, 0);
+ emvsim_set_bwt(emvsim, 0);
+
+ /*Disable the NACK interruptand TX related interrupt*/
+ emvsim_tx_irq_disable(emvsim);
+
+ /*Update the state and status*/
+ emvsim->errval |= SIM_ERROR_NACK_THRESHOLD;
+ emvsim->state = SIM_STATE_XMT_ERROR;
+
+ complete(&emvsim->xfer_done);
+ } else if (tx_status & TDTF && emvsim->xmt_remaining != 0) {
+ emvsim_xmt_fill_fifo(emvsim);
+ if (emvsim->xmt_remaining == 0) {
+ reg_data = __raw_readl(emvsim->ioaddr +
+ EMV_SIM_INT_MASK);
+ reg_data |= TDT_IM;
+ reg_data &= ~(TC_IM | ETC_IM);
+ __raw_writel(reg_data, emvsim->ioaddr +
+ EMV_SIM_INT_MASK);
+ }
+ } else if ((tx_status & TCF) && !emvsim->xmt_remaining) {
+ emvsim_tx_irq_disable(emvsim);
+ emvsim_set_rx(emvsim, 1);
+ emvsim->state = SIM_STATE_XMT_DONE;
+ complete(&emvsim->xfer_done);
+ }
+ }
+
+ /*
+ * It takes some time to change from SIM_STATE_XMT_DONE to
+ * SIM_STATE_RECEIVING RX would only be enabled after state
+ * becomes SIM_STATE_RECEIVING
+ */
+ else if (emvsim->state == SIM_STATE_RECEIVING) {
+ if (rx_status & RTE) {
+ emvsim_set_rx(emvsim, 0);
+
+ /* Disable the BWT timer and CWT timer right now */
+ emvsim_set_cwt(emvsim, 0);
+ emvsim_set_bwt(emvsim, 0);
+
+ /* Disable the interrupt right now */
+ emvsim_rx_irq_disable(emvsim);
+
+ /* Should we read the fifo or just flush the fifo? */
+ emvsim_rcv_read_fifo(emvsim);
+ emvsim->errval = SIM_ERROR_NACK_THRESHOLD;
+ emvsim->state = SIM_STATE_RECEIVE_ERROR;
+ complete(&emvsim->xfer_done);
+ }
+
+ if (rx_status & RX_DATA) {
+ emvsim_rcv_read_fifo(emvsim);
+ if (emvsim->is_fixed_len_rec &&
+ emvsim->rcv_count >= emvsim->expected_rcv_cnt) {
+ emvsim_rx_irq_disable(emvsim);
+
+ if (emvsim->state == SIM_STATE_RECEIVING) {
+ emvsim->state = SIM_STATE_RECEIVE_DONE;
+ complete(&emvsim->xfer_done);
+ }
+ }
+ }
+
+ if (rx_status & (CWT_ERR | BWT_ERR | BGT_ERR)) {
+ emvsim_set_cwt(emvsim, 0);
+ emvsim_set_bwt(emvsim, 0);
+ emvsim_rx_irq_disable(emvsim);
+
+ if (rx_status & BWT_ERR)
+ emvsim->errval |= SIM_ERROR_BWT;
+ if (rx_status & CWT_ERR)
+ emvsim->errval |= SIM_ERROR_CWT;
+ if (rx_status & BGT_ERR)
+ emvsim->errval |= SIM_ERROR_BGT;
+
+ emvsim_rcv_read_fifo(emvsim);
+
+ if (emvsim->state == SIM_STATE_RECEIVING) {
+ emvsim->state = SIM_STATE_RECEIVE_DONE;
+ complete(&emvsim->xfer_done);
+ }
+ }
+ }
+
+ else if ((emvsim->state == SIM_STATE_RESET_SEQUENCY) &&
+ (tx_status & GPCNT0_TO)) {
+ complete(&emvsim->xfer_done);
+ emvsim_mask_timer0_int(emvsim);
+ } else if (rx_status & RX_DATA) {
+ dev_err(emvsim_dev.parent,
+ "unexpected status %d\n", emvsim->state);
+ emvsim_rcv_read_fifo(emvsim);
+ }
+
+ return IRQ_HANDLED;
+};
+
+static void emvsim_start(struct emvsim_t *emvsim)
+{
+ u32 reg_data, clk_rate, clk_div = 0;
+
+ clk_rate = clk_get_rate(emvsim->clk);
+ clk_div = (clk_rate + emvsim->clk_rate - 1) / emvsim->clk_rate;
+ __raw_writel(clk_div, emvsim->ioaddr + EMV_SIM_CLKCFG);
+
+ usleep_range(90, 100);
+ /* SPDP=0: SIM Presence Detect pin is low, default PRESENT status */
+ if (__raw_readl(emvsim->ioaddr + EMV_SIM_PCSR) & SPDP) {
+ emvsim->present = SIM_PRESENT_REMOVED;
+ emvsim->state = SIM_STATE_REMOVED;
+ } else {
+ emvsim->present = SIM_PRESENT_DETECTED;
+ emvsim->state = SIM_STATE_DETECTED;
+ };
+
+ /* disabled card interrupt. clear interrupt status*/
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+ reg_data |= SPDIM | SPDIF;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_PCSR);
+};
+
+static void emvsim_cold_reset_sequency(struct emvsim_t *emvsim)
+{
+ u32 reg_data;
+
+ emvsim->state = SIM_STATE_RESET_SEQUENCY;
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+ reg_data &= ~VCCENP;
+ reg_data |= SVCC_EN;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_PCSR);
+
+ msleep(20);
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+ reg_data |= SCEN;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_PCSR);
+
+ emvsim_reset_low_timing(emvsim, EMV_RESET_LOW_CYCLES);
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+ reg_data |= SRST;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_PCSR);
+
+ emvsim_mask_timer0_int(emvsim);
+ __raw_writel(ATR_MAX_DELAY_CLK, emvsim->ioaddr +
+ EMV_SIM_GPCNT0_VAL);
+};
+
+static void emvsim_deactivate(struct emvsim_t *emvsim)
+{
+ u32 reg_data;
+
+ /* Auto powdown to implement the deactivate sequence */
+ if (emvsim->present != SIM_PRESENT_REMOVED) {
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+ reg_data |= SAPD | SPD;
+ writel(reg_data, emvsim->ioaddr + EMV_SIM_PCSR);
+ } else {
+ dev_err(emvsim_dev.parent, ">>>No card%s\n", __func__);
+ }
+};
+
+static void emvsim_cold_reset(struct emvsim_t *emvsim)
+{
+ if (emvsim->present != SIM_PRESENT_REMOVED) {
+ emvsim->state = SIM_STATE_DETECTED;
+ emvsim->present = SIM_PRESENT_DETECTED;
+ emvsim_cold_reset_sequency(emvsim);
+ emvsim_receive_atr_set(emvsim);
+ } else {
+ dev_err(emvsim_dev.parent, "No card%s\n", __func__);
+ }
+};
+
+static void emvsim_warm_reset_sequency(struct emvsim_t *emvsim)
+{
+ u32 reg_data;
+
+ /*enable power/clk, deassert rst*/
+ emvsim->state = SIM_STATE_RESET_SEQUENCY;
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+ reg_data |= (SRST | SCEN);
+ reg_data &= ~VCCENP;
+ reg_data |= SVCC_EN;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_PCSR);
+
+ usleep_range(20, 25);
+
+ /* assert rst */
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+ reg_data &= ~SRST;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_PCSR);
+
+ /* rst keep low */
+ emvsim_reset_low_timing(emvsim, EMV_RESET_LOW_CYCLES);
+
+ /* deassert rst */
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+ reg_data |= SRST;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_PCSR);
+
+ emvsim_mask_timer0_int(emvsim);
+ __raw_writel(ATR_MAX_DELAY_CLK, emvsim->ioaddr + EMV_SIM_GPCNT0_VAL);
+}
+
+static void emvsim_warm_reset(struct emvsim_t *emvsim)
+{
+ if (emvsim->present != SIM_PRESENT_REMOVED) {
+ emvsim_data_reset(emvsim);
+ emvsim_reset_gpctimer(emvsim);
+ emvsim_warm_reset_sequency(emvsim);
+ emvsim_receive_atr_set(emvsim);
+ } else {
+ dev_err(emvsim_dev.parent, "No card%s\n", __func__);
+ }
+};
+
+static int emvsim_card_lock(struct emvsim_t *emvsim)
+{
+ int errval;
+
+ /* place holder for true physcial locking */
+ if (emvsim->present != SIM_PRESENT_REMOVED)
+ errval = SIM_OK;
+ else
+ errval = -SIM_E_NOCARD;
+
+ return errval;
+};
+
+static int emvsim_card_eject(struct emvsim_t *emvsim)
+{
+ int errval;
+
+ /* place holder for true physcial locking */
+ if (emvsim->present != SIM_PRESENT_REMOVED)
+ errval = SIM_OK;
+ else
+ errval = -SIM_E_NOCARD;
+
+ return errval;
+};
+
+static int emvsim_check_baud_rate(sim_baud_t *baud_rate)
+{
+ /* The valid value is decribed in the 8.3.3.1 in EMV 4.3 */
+ if (baud_rate->fi == 1 && (baud_rate->di == 1 ||
+ baud_rate->di == 2 || baud_rate->di == 3))
+ return 0;
+
+ return -EINVAL;
+}
+
+static int emvsim_set_baud_rate(struct emvsim_t *emvsim)
+{
+ u32 reg_data;
+
+ switch (emvsim->baud_rate.di) {
+ case 1:
+ reg_data = 372;
+ break;
+ case 2:
+ reg_data = 372 >> 1;
+ break;
+ case 3:
+ reg_data = 372 >> 2;
+ break;
+ default:
+ dev_err(emvsim_dev.parent,
+ "Invalid baud Di, Using default 372 / 1\n");
+ reg_data = 372;
+ break;
+ }
+
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_DIVISOR);
+
+ return 0;
+}
+
+static int emvsim_check_timing_data(sim_timing_t *timing_data)
+{
+ if (timing_data->wwt > 0xFFFF || timing_data->cwt > 0xFFFF ||
+ timing_data->bgt > 0xFFFF || timing_data->cgt > 0xFF) {
+ dev_err(emvsim_dev.parent,
+ "The timing value is out of scope of IP\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void emvsim_set_timer_counter(struct emvsim_t *emvsim)
+{
+ u32 reg;
+
+ if (emvsim->timing_data.wwt != 0 &&
+ emvsim->protocol_type == SIM_PROTOCOL_T0) {
+ emvsim->timing_data.cwt = emvsim->timing_data.wwt;
+ emvsim->timing_data.bwt = emvsim->timing_data.wwt;
+ }
+
+ if (emvsim->timing_data.bgt != 0)
+ __raw_writel(emvsim->timing_data.bgt,
+ emvsim->ioaddr + EMV_SIM_BGT_VAL);
+
+ if (emvsim->timing_data.cwt != 0)
+ __raw_writel(emvsim->timing_data.cwt,
+ emvsim->ioaddr + EMV_SIM_CWT_VAL);
+
+ if (emvsim->timing_data.bwt != 0)
+ __raw_writel(emvsim->timing_data.bwt,
+ emvsim->ioaddr + EMV_SIM_BWT_VAL);
+
+ /* 11 etu and 12 etu, T0: 12ETU; T1: 11ETU */
+ if (emvsim->protocol_type == SIM_PROTOCOL_T0) {
+ /*
+ * From EMV4.3 , T0 mode means 12 ETU. TotalETU=12+CGT.
+ * If cgt equals 0xFF, TotalETU = 12
+ */
+ reg = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+ reg &= ~RCVR_11;
+ __raw_writel(reg, emvsim->ioaddr + EMV_SIM_CTRL);
+
+ /* set Transmitter Guard Time Value in ETU */
+ if (emvsim->timing_data.cgt == 0xFF)
+ __raw_writel(0, emvsim->ioaddr + EMV_SIM_TX_GETU);
+ else
+ __raw_writel(emvsim->timing_data.cgt,
+ emvsim->ioaddr + EMV_SIM_TX_GETU);
+ } else if (emvsim->protocol_type == SIM_PROTOCOL_T1) {
+ /* From EMV4.3 , T1 mode means 11 ETU. TotalETU=11+CGT */
+ reg = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+ reg |= RCVR_11;
+ __raw_writel(reg, emvsim->ioaddr + EMV_SIM_CTRL);
+ __raw_writel(emvsim->timing_data.cgt,
+ emvsim->ioaddr + EMV_SIM_TX_GETU);
+ }
+}
+
+static int emvsim_xmt_start(struct emvsim_t *emvsim)
+{
+ u32 reg_val;
+
+ emvsim_set_baud_rate(emvsim);
+ if (emvsim->protocol_type == SIM_PROTOCOL_T0) {
+ emvsim_set_nack(emvsim, 1);
+ } else if (emvsim->protocol_type == SIM_PROTOCOL_T1) {
+ emvsim_set_nack(emvsim, 0);
+ } else {
+ dev_err(emvsim_dev.parent, "Invalid protocol not T0 or T1\n");
+ return -EINVAL;
+ }
+
+ emvsim_set_timer_counter(emvsim);
+
+ if (emvsim->xmt_remaining != 0) {
+ reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_TX_THD);
+ reg_val &= ~SIM_XMT_THRESHOLD_TDT_MASK;
+ reg_val |= SIM_XMT_THRESHOLD_TDT(TX_FIFO_THRESHOLD);
+ __raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_TX_THD);
+ }
+
+ emvsim_set_bwt(emvsim, 1);
+ emvsim_set_cwt(emvsim, 0);
+
+ emvsim_set_tx(emvsim, 1);
+ emvsim_xmt_fill_fifo(emvsim);
+ emvsim_tx_irq_enable(emvsim);
+ emvsim->state = SIM_STATE_XMTING;
+
+ return 0;
+}
+
+static void emvsim_flush_fifo(struct emvsim_t *emvsim, u8 flush_tx, u8 flush_rx)
+{
+ u32 reg_val;
+
+ reg_val = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+
+ if (flush_tx)
+ reg_val |= FLSH_TX;
+ if (flush_rx)
+ reg_val |= FLSH_RX;
+ __raw_writel(reg_val, emvsim->ioaddr + EMV_SIM_CTRL);
+}
+
+static void emvsim_start_rcv(struct emvsim_t *emvsim)
+{
+ int rdt = 1;
+
+ emvsim->state = SIM_STATE_RECEIVING;
+
+ emvsim_set_rx(emvsim, 1);
+ emvsim_set_baud_rate(emvsim);
+ emvsim_set_timer_counter(emvsim);
+ emvsim_set_cwt(emvsim, 1);
+ emvsim_set_bwt(emvsim, 1);
+
+ if (emvsim->protocol_type == SIM_PROTOCOL_T0)
+ emvsim_set_nack(emvsim, 1);
+ else if (emvsim->protocol_type == SIM_PROTOCOL_T1)
+ emvsim_set_nack(emvsim, 0);
+
+ /*Set RX threshold*/
+ if (emvsim->protocol_type == SIM_PROTOCOL_T0)
+ __raw_writel(SIM_RCV_THRESHOLD_RTH(emvsim->nack_threshold) |
+ SIM_RCV_THRESHOLD_RDT(rdt),
+ emvsim->ioaddr + EMV_SIM_RX_THD);
+ else
+ __raw_writel(SIM_RCV_THRESHOLD_RDT(rdt),
+ emvsim->ioaddr + EMV_SIM_RX_THD);
+
+ /*Clear status and enable interrupt*/
+ emvsim_rx_irq_enable(emvsim);
+}
+
+static void emvsim_polling_delay(struct emvsim_t *emvsim, u32 delay)
+{
+ u32 reg_data;
+ unsigned long orig_jiffies = jiffies;
+
+ emvsim_mask_timer1_int(emvsim);
+
+ __raw_writel(delay, emvsim->ioaddr + EMV_SIM_GPCNT0_VAL);
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+ reg_data &= ~GPCNT1_IM;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+
+ /* Loop for timeout, add timeout mechanism to avoid dead loop */
+ while (!(__raw_readl(emvsim->ioaddr + EMV_SIM_TX_STATUS) & GPCNT0_TO)) {
+ if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
+ dev_err(emvsim_dev.parent, "polling delay timeout\n");
+ break;
+ }
+
+ usleep_range(10, 20);
+ }
+
+ emvsim_mask_timer1_int(emvsim);
+}
+
+void emvsim_clear_rx_buf(struct emvsim_t *emvsim)
+{
+ unsigned int i;
+
+ for (i = 0; i < SIM_RCV_BUFFER_SIZE; i++)
+ emvsim->rcv_buffer[i] = 0;
+ emvsim->rcv_count = 0;
+ emvsim->rcv_head = 0;
+}
+
+static long emvsim_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret, errval = SIM_OK;
+ unsigned long timeout;
+ u32 reg_data;
+ u32 delay;
+ u32 copy_cnt, val;
+ unsigned long flags;
+ unsigned char __user *atr_buffer;
+ unsigned char __user *xmt_buffer;
+ unsigned char __user *rcv_buffer;
+
+ struct emvsim_t *emvsim = (struct emvsim_t *)file->private_data;
+
+ switch (cmd) {
+ case SIM_IOCTL_GET_ATR:
+ if (emvsim->present != SIM_PRESENT_DETECTED) {
+ dev_err(emvsim_dev.parent, "NO card ...\n");
+ errval = -SIM_E_NOCARD;
+ break;
+ }
+
+ emvsim->timeout = ATR_TIMEOUT * HZ;
+ val = 0;
+ ret = copy_to_user(&(((sim_atr_t *)arg)->size), &val,
+ sizeof((((sim_atr_t *)arg)->size)));
+
+ timeout = wait_for_completion_interruptible_timeout(
+ &emvsim->xfer_done, emvsim->timeout);
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_CTRL);
+ reg_data &= ~CWT_EN;
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_CTRL);
+
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_INT_MASK);
+ reg_data |= (GPCNT0_IM | CWT_ERR_IM);
+ __raw_writel(reg_data, emvsim->ioaddr + EMV_SIM_INT_MASK);
+
+ if (timeout == 0) {
+ dev_err(emvsim_dev.parent, "ATR timeout\n");
+ errval = -SIM_E_TIMEOUT;
+ break;
+ }
+
+ ret = copy_to_user(&(((sim_atr_t *)arg)->size),
+ &emvsim->rcv_count,
+ sizeof(emvsim->rcv_count));
+ if (ret) {
+ dev_err(emvsim_dev.parent,
+ "ATR ACCESS rcv_count Error, %d\n", ret);
+ errval = -SIM_E_ACCESS;
+ break;
+ }
+
+ __get_user(atr_buffer, &((sim_atr_t __user *)arg)->atr_buffer);
+ ret = copy_to_user(atr_buffer,
+ emvsim->rcv_buffer, emvsim->rcv_count);
+ if (ret) {
+ dev_err(emvsim_dev.parent,
+ "ATR ACCESS buffer Error %d %d\n",
+ emvsim->rcv_count, ret);
+ errval = -SIM_E_ACCESS;
+ break;
+ }
+
+ ret = copy_to_user(&(((sim_atr_t *)arg)->errval),
+ &emvsim->errval, sizeof(emvsim->errval));
+ if (ret) {
+ dev_err(emvsim_dev.parent, "ATR ACCESS Error\n");
+ errval = -SIM_E_ACCESS;
+ break;
+ }
+ emvsim->rcv_count = 0;
+ emvsim->rcv_head = 0;
+ emvsim->errval = 0;
+
+ break;
+
+ case SIM_IOCTL_DEACTIVATE:
+ emvsim_deactivate(emvsim);
+ break;
+
+ case SIM_IOCTL_COLD_RESET:
+ emvsim->present = SIM_PRESENT_REMOVED;
+ emvsim->state = SIM_STATE_REMOVED;
+ emvsim_reset_module(emvsim);
+ emvsim_data_reset(emvsim);
+ emvsim_start(emvsim);
+ emvsim_cold_reset(emvsim);
+ break;
+
+ case SIM_IOCTL_WARM_RESET:
+ emvsim_warm_reset(emvsim);
+ break;
+
+ case SIM_IOCTL_XMT:
+ ret = copy_from_user(&emvsim->xmt_remaining,
+ &(((sim_xmt_t *)arg)->xmt_length),
+ sizeof(uint32_t));
+ if (ret || emvsim->xmt_remaining > SIM_XMT_BUFFER_SIZE) {
+ dev_err(emvsim_dev.parent,
+ "copy error or to big buffer\n");
+ errval = -EINVAL;
+ break;
+ }
+
+ __get_user(xmt_buffer, &((sim_xmt_t *)arg)->xmt_buffer);
+ ret = copy_from_user(emvsim->xmt_buffer, xmt_buffer,
+ emvsim->xmt_remaining);
+ if (ret) {
+ dev_err(emvsim_dev.parent, "Copy Error\n");
+ errval = ret;
+ break;
+ }
+
+ emvsim_clear_rx_buf(emvsim);
+ emvsim_set_cwt(emvsim, 0);
+ emvsim_set_bwt(emvsim, 0);
+ /*Flush the tx rx fifo*/
+ emvsim_flush_fifo(emvsim, 1, 1);
+ emvsim->xmt_pos = 0;
+ emvsim->errval = 0;
+
+ errval = emvsim_xmt_start(emvsim);
+ if (errval)
+ break;
+
+ emvsim->timeout = TX_TIMEOUT * HZ;
+ timeout = wait_for_completion_interruptible_timeout(
+ &emvsim->xfer_done, emvsim->timeout);
+ if (timeout == 0) {
+ /*Disable the NACK interruptand TX related interrupt*/
+ emvsim_tx_irq_disable(emvsim);
+ dev_err(emvsim_dev.parent, "tx timeout\n");
+ }
+
+ if (timeout == 0 || emvsim->state == SIM_STATE_XMT_ERROR) {
+ dev_err(emvsim_dev.parent, "TX error\n");
+ /*Disable timers*/
+ emvsim_set_cwt(emvsim, 0);
+ emvsim_set_bwt(emvsim, 0);
+ /*Disable TX*/
+ emvsim_set_tx(emvsim, 0);
+ /*Flush the tx fifos*/
+ emvsim_flush_fifo(emvsim, 1, 0);
+ if (timeout == 0)
+ errval = -SIM_E_TIMEOUT;
+ else
+ errval = -SIM_E_NACK;
+
+ ret = copy_to_user(&(((sim_atr_t *)arg)->errval),
+ &emvsim->errval,
+ sizeof(emvsim->errval));
+ emvsim->errval = 0;
+ break;
+ }
+
+ /*Copy the error status to user space*/
+ ret = copy_to_user(&(((sim_atr_t *)arg)->errval),
+ &emvsim->errval, sizeof(emvsim->errval));
+ emvsim->errval = 0;
+
+ emvsim_start_rcv(emvsim);
+
+ break;
+
+ case SIM_IOCTL_RCV:
+ if (emvsim->present != SIM_PRESENT_DETECTED) {
+ errval = -SIM_E_NOCARD;
+ break;
+ }
+
+ val = 0;
+ emvsim->is_fixed_len_rec = 0;
+ ret = copy_from_user(&emvsim->expected_rcv_cnt,
+ &(((sim_rcv_t *)arg)->rcv_length),
+ sizeof(emvsim->expected_rcv_cnt));
+
+ /*Set the length to be 0 at first*/
+ ret = copy_to_user(&(((sim_rcv_t *)arg)->rcv_length), &val,
+ sizeof(val));
+
+ /*Set error value to be 0 at first*/
+ ret = copy_to_user(&(((sim_rcv_t *)arg)->errval), &val,
+ sizeof(val));
+
+ if (emvsim->expected_rcv_cnt != 0)
+ emvsim->is_fixed_len_rec = 1;
+
+ if (emvsim->is_fixed_len_rec &&
+ emvsim->rcv_count >= emvsim->expected_rcv_cnt)
+ goto copy_data;
+
+ if (emvsim->state != SIM_STATE_RECEIVING)
+ emvsim_start_rcv(emvsim);
+
+ spin_lock_irqsave(&emvsim->lock, flags);
+ spin_unlock_irqrestore(&emvsim->lock, flags);
+ emvsim->timeout = RX_TIMEOUT * HZ;
+ timeout = wait_for_completion_interruptible_timeout(
+ &emvsim->xfer_done, emvsim->timeout);
+ if (timeout == 0) {
+ dev_err(emvsim_dev.parent, "Receiving timeout\n");
+ emvsim_set_cwt(emvsim, 0);
+ emvsim_set_bwt(emvsim, 0);
+ emvsim_rx_irq_disable(emvsim);
+ errval = -SIM_E_TIMEOUT;
+ break;
+ }
+copy_data:
+ if (emvsim->is_fixed_len_rec)
+ copy_cnt = emvsim->rcv_count > emvsim->expected_rcv_cnt
+ ? emvsim->expected_rcv_cnt
+ : emvsim->rcv_count;
+ else
+ copy_cnt = emvsim->rcv_count;
+
+ ret = copy_to_user(&(((sim_rcv_t *)arg)->rcv_length),
+ &copy_cnt, sizeof(copy_cnt));
+ if (ret) {
+ dev_err(emvsim_dev.parent, "ATR ACCESS Error\n");
+ errval = -SIM_E_ACCESS;
+ break;
+ }
+
+ __get_user(rcv_buffer, &((sim_rcv_t *)arg)->rcv_buffer);
+ ret = copy_to_user(rcv_buffer,
+ &emvsim->rcv_buffer[emvsim->rcv_head],
+ copy_cnt);
+ if (ret) {
+ dev_err(emvsim_dev.parent, "ATR ACCESS Error\n");
+ errval = -SIM_E_ACCESS;
+ break;
+ }
+
+ ret = copy_to_user(&(((sim_rcv_t *)arg)->errval),
+ &emvsim->errval, sizeof(emvsim->errval));
+ if (ret) {
+ dev_err(emvsim_dev.parent, "ATR ACCESS Error\n");
+ errval = -SIM_E_ACCESS;
+ break;
+ }
+ /*Reset the receiving count and errval*/
+ spin_lock_irqsave(&emvsim->lock, flags);
+ emvsim->rcv_head += copy_cnt;
+ emvsim->rcv_count -= copy_cnt;
+ emvsim->errval = 0;
+ spin_unlock_irqrestore(&emvsim->lock, flags);
+
+ break;
+
+ case SIM_IOCTL_SET_PROTOCOL:
+ ret = copy_from_user(&emvsim->protocol_type, (int *)arg,
+ sizeof(int));
+ if (ret)
+ errval = -SIM_E_ACCESS;
+ break;
+
+ case SIM_IOCTL_SET_TIMING:
+ ret = copy_from_user(&emvsim->timing_data, (sim_timing_t *)arg,
+ sizeof(sim_timing_t));
+ if (ret) {
+ dev_err(emvsim_dev.parent, "Copy Error\n");
+ errval = ret;
+ break;
+ }
+
+ ret = emvsim_check_timing_data(&emvsim->timing_data);
+ if (ret)
+ errval = ret;
+
+ break;
+
+ case SIM_IOCTL_SET_BAUD:
+ ret = copy_from_user(&emvsim->baud_rate, (sim_baud_t *)arg,
+ sizeof(sim_baud_t));
+ if (ret) {
+ dev_err(emvsim_dev.parent, "Copy Error\n");
+ errval = ret;
+ break;
+ }
+
+ emvsim_check_baud_rate(&emvsim->baud_rate);
+
+ break;
+ case SIM_IOCTL_WAIT:
+ ret = copy_from_user(&delay, (unsigned int *)arg,
+ sizeof(unsigned int));
+ if (ret) {
+ dev_err(emvsim_dev.parent, "\nWait Copy Error\n");
+ errval = ret;
+ break;
+ }
+
+ emvsim_polling_delay(emvsim, delay);
+ break;
+
+ case SIM_IOCTL_GET_PRESENSE:
+ if (put_user(emvsim->present, (int *)arg))
+ errval = -SIM_E_ACCESS;
+ break;
+
+ case SIM_IOCTL_CARD_LOCK:
+ errval = emvsim_card_lock(emvsim);
+ break;
+
+ case SIM_IOCTL_CARD_EJECT:
+ errval = emvsim_card_eject(emvsim);
+ break;
+ };
+
+ return errval;
+};
+
+static int emvsim_open(struct inode *inode, struct file *file)
+{
+ int errval = SIM_OK;
+ struct emvsim_t *emvsim = dev_get_drvdata(emvsim_dev.parent);
+
+ file->private_data = emvsim;
+ spin_lock_init(&emvsim->lock);
+
+ if (!emvsim->ioaddr) {
+ errval = -ENOMEM;
+ return errval;
+ }
+
+ if (!emvsim->open_cnt) {
+ clk_prepare_enable(emvsim->ipg);
+ clk_prepare_enable(emvsim->clk);
+ }
+
+ emvsim->open_cnt = 1;
+ init_completion(&emvsim->xfer_done);
+ errval = emvsim_reset_module(emvsim);
+ emvsim_data_reset(emvsim);
+
+ return errval;
+};
+
+static int emvsim_release(struct inode *inode, struct file *file)
+{
+ u32 reg_data;
+ struct emvsim_t *emvsim = (struct emvsim_t *)file->private_data;
+
+ /* disable presense detection interrupt */
+ reg_data = __raw_readl(emvsim->ioaddr + EMV_SIM_PCSR);
+ __raw_writel(reg_data | SPDIM, emvsim->ioaddr + EMV_SIM_PCSR);
+
+ if (emvsim->present != SIM_PRESENT_REMOVED)
+ emvsim_deactivate(emvsim);
+
+ if (emvsim->open_cnt) {
+ clk_disable_unprepare(emvsim->clk);
+ clk_disable_unprepare(emvsim->ipg);
+ }
+
+ emvsim->open_cnt = 0;
+
+ return 0;
+};
+
+static const struct file_operations emvsim_fops = {
+ .owner = THIS_MODULE,
+ .open = emvsim_open,
+ .release = emvsim_release,
+ .unlocked_ioctl = emvsim_ioctl,
+};
+
+static struct miscdevice emvsim_dev = {
+ MISC_DYNAMIC_MINOR,
+ "mxc_sim",
+ &emvsim_fops
+};
+
+static const struct of_device_id emvsim_imx_dt_ids[] = {
+ { .compatible = "fsl,imx8-emvsim" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, emvsim_imx_dt_ids);
+
+static int emvsim_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ const struct of_device_id *of_id;
+ struct emvsim_t *emvsim = NULL;
+
+ emvsim = devm_kzalloc(&pdev->dev, sizeof(struct emvsim_t),
+ GFP_KERNEL);
+ if (!emvsim)
+ return -ENOMEM;
+
+ of_id = of_match_device(emvsim_imx_dt_ids, &pdev->dev);
+ if (of_id)
+ pdev->id_entry = of_id->data;
+ else
+ return -EINVAL;
+
+ emvsim->clk_rate = FCLK_FREQ;
+ emvsim->open_cnt = 0;
+
+ emvsim->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!emvsim->res) {
+ dev_err(emvsim_dev.parent, "Can't get the MEMORY\n");
+ return -ENOMEM;
+ }
+ emvsim->ioaddr = devm_ioremap_resource(&pdev->dev, emvsim->res);
+ if (IS_ERR(emvsim->ioaddr)) {
+ dev_err(&pdev->dev,
+ "failed to get ioremap base\n");
+ ret = PTR_ERR(emvsim->ioaddr);
+ return ret;
+ }
+
+ /* request the emvsim per clk and ipg clk */
+ emvsim->clk = devm_clk_get(&pdev->dev, "sim");
+ if (IS_ERR(emvsim->clk)) {
+ ret = PTR_ERR(emvsim->clk);
+ dev_err(emvsim_dev.parent, "Get PER CLK ERROR !\n");
+ return ret;
+ }
+
+ emvsim->ipg = devm_clk_get(&pdev->dev, "ipg");
+ if (IS_ERR(emvsim->ipg)) {
+ ret = PTR_ERR(emvsim->ipg);
+ dev_err(emvsim_dev.parent, "Get IPG CLK ERROR !\n");
+ return ret;
+ }
+
+ emvsim->irq = platform_get_irq(pdev, 0);
+ if (emvsim->irq < 0) {
+ dev_err(&pdev->dev, "No irq line provided\n");
+ return -ENOENT;
+ }
+
+ if (devm_request_irq(&pdev->dev, emvsim->irq, emvsim_irq_handler,
+ 0, "mxc_emvsim_irq", emvsim)) {
+ dev_err(&pdev->dev, "can't claim irq %d\n", emvsim->irq);
+ return -ENOENT;
+ }
+
+ platform_set_drvdata(pdev, emvsim);
+ emvsim_dev.parent = &pdev->dev;
+
+ ret = misc_register(&emvsim_dev);
+ dev_info(&pdev->dev, "emvsim register %s\n", ret ? "fail" : "success");
+
+ return ret;
+}
+
+static int emvsim_remove(struct platform_device *pdev)
+{
+ struct emvsim_t *emvsim = platform_get_drvdata(pdev);
+
+ if (emvsim->open_cnt) {
+ clk_disable_unprepare(emvsim->clk);
+ clk_disable_unprepare(emvsim->ipg);
+ }
+
+ misc_deregister(&emvsim_dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int emvsim_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct emvsim_t *emvsim = platform_get_drvdata(pdev);
+
+ if (emvsim->open_cnt) {
+ clk_disable_unprepare(emvsim->clk);
+ clk_disable_unprepare(emvsim->ipg);
+ }
+
+ pinctrl_pm_select_sleep_state(&pdev->dev);
+
+ return 0;
+}
+
+static int emvsim_resume(struct platform_device *pdev)
+{
+ struct emvsim_t *emvsim = platform_get_drvdata(pdev);
+
+ if (!emvsim->open_cnt) {
+ clk_prepare_enable(emvsim->ipg);
+ clk_prepare_enable(emvsim->clk);
+ }
+
+ pinctrl_pm_select_default_state(&pdev->dev);
+
+ return 0;
+}
+
+#else
+#define emvsim_suspend NULL
+#define emvsim_resume NULL
+#endif
+
+static struct platform_driver emvsim_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = emvsim_imx_dt_ids,
+ },
+ .probe = emvsim_probe,
+ .remove = emvsim_remove,
+ .suspend = emvsim_suspend,
+ .resume = emvsim_resume,
+};
+
+static int __init emvsim_drv_init(void)
+{
+ return platform_driver_register(&emvsim_driver);
+}
+
+static void __exit emvsim_drv_exit(void)
+{
+ platform_driver_unregister(&emvsim_driver);
+}
+
+module_init(emvsim_drv_init);
+module_exit(emvsim_drv_exit);
+
+MODULE_AUTHOR("Gao Pan <pandy.gao@nxp.com>");
+MODULE_DESCRIPTION("NXP EMVSIM Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mxc/sim/imx_sim.c b/drivers/mxc/sim/imx_sim.c
new file mode 100755
index 000000000000..e907bd3a8ec8
--- /dev/null
+++ b/drivers/mxc/sim/imx_sim.c
@@ -0,0 +1,1865 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/clk.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mxc_sim_interface.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+
+#include <linux/io.h>
+
+#define DRIVER_NAME "mxc_sim"
+#define SIM_INTERNAL_CLK (0)
+#define SIM_RFU (-1)
+
+/* Transmit and receive buffer sizes */
+#define SIM_XMT_BUFFER_SIZE (300)
+#define SIM_RCV_BUFFER_SIZE (400)
+
+#define SIM_TX_FIFO_DEPTH (16)
+#define SIM_RX_FIFO_DEPTH (285)
+
+#define TX_FIFO_THRESHOLD (0x04)
+#define RX_FIFO_THRESHOLD (250)
+
+/* Interface character references */
+#define SIM_IFC_TXI(letter, number) (letter + number * 4)
+#define SIM_IFC_TA1 SIM_IFC_TXI(0, 0)
+#define SIM_IFC_TB1 SIM_IFC_TXI(0, 1)
+#define SIM_IFC_TC1 SIM_IFC_TXI(0, 2)
+#define SIM_IFC_TD1 SIM_IFC_TXI(0, 3)
+#define SIM_IFC_TA2 SIM_IFC_TXI(1, 0)
+#define SIM_IFC_TB2 SIM_IFC_TXI(1, 1)
+#define SIM_IFC_TC2 SIM_IFC_TXI(1, 2)
+#define SIM_IFC_TD2 SIM_IFC_TXI(1, 3)
+#define SIM_IFC_TA3 SIM_IFC_TXI(2, 0)
+#define SIM_IFC_TB3 SIM_IFC_TXI(2, 1)
+#define SIM_IFC_TC3 SIM_IFC_TXI(2, 2)
+#define SIM_IFC_TD3 SIM_IFC_TXI(2, 3)
+#define SIM_IFC_TA4 SIM_IFC_TXI(3, 0)
+#define SIM_IFC_TB4 SIM_IFC_TXI(3, 1)
+#define SIM_IFC_TC4 SIM_IFC_TXI(3, 2)
+#define SIM_IFC_TD4 SIM_IFC_TXI(3, 3)
+
+/* ATR and OPS states */
+#define SIM_STATE_REMOVED (0)
+#define SIM_STATE_DETECTED (1)
+#define SIM_STATE_ATR_RECEIVING (2)
+#define SIM_STATE_ATR_RECEIVED (3)
+#define SIM_STATE_XMTING (4)
+#define SIM_STATE_XMT_DONE (5)
+#define SIM_STATE_XMT_ERROR (6)
+#define SIM_STATE_RECEIVING (7)
+#define SIM_STATE_RECEIVE_DONE (8)
+#define SIM_STATE_RECEIVE_ERROR (9)
+#define SIM_STATE_RESET_SEQUENCY (10)
+
+/* Definitions of the offset of the SIM hardware registers */
+#define PORT1_CNTL (0x00)
+#define SETUP (0x04)
+#define PORT1_DETECT (0x08)
+#define PORT1_XMT_BUF (0x0C)
+#define PORT1_RCV_BUF (0x10)
+#define PORT0_CNTL (0x14)
+#define CNTL (0x18)
+#define CLK_PRESCALER (0x1C)
+#define RCV_THRESHOLD (0x20)
+#define ENABLE (0x24)
+#define XMT_STATUS (0x28)
+#define RCV_STATUS (0x2C)
+#define INT_MASK (0x30)
+#define PORTO_XMT_BUF (0x34)
+#define PORT0_RCV_BUF (0x38)
+#define PORT0_DETECT (0x3C)
+#define DATA_FORMAT (0x40)
+#define XMT_THRESHOLD (0x44)
+#define GUARD_CNTL (0x48)
+#define OD_CONFIG (0x4C)
+#define RESET_CNTL (0x50)
+#define CHAR_WAIT (0x54)
+#define GPCNT (0x58)
+#define DIVISOR (0x5C)
+#define BWT (0x60)
+#define BGT (0x64)
+#define BWT_H (0x68)
+#define XMT_FIFO_STAT (0x6C)
+#define RCV_FIFO_CNT (0x70)
+#define RCV_FIFO_WPTR (0x74)
+#define RCV_FIFO_RPTR (0x78)
+
+/* SIM SETUP register bits */
+#define SIM_SETUP_SPS_PORT0 (0 << 1)
+#define SIM_SETUP_SPS_PORT1 (1 << 1)
+
+/* SIM port[0|1]_cntl register bits */
+#define SIM_PORT_CNTL_SFPD (1 << 7)
+#define SIM_PORT_CNTL_3VOLT (1 << 6)
+#define SIM_PORT_CNTL_SCSP (1 << 5)
+#define SIM_PORT_CNTL_SCEN (1 << 4)
+#define SIM_PORT_CNTL_SRST (1 << 3)
+#define SIM_PORT_CNTL_STEN (1 << 2)
+#define SIM_PORT_CNTL_SVEN (1 << 1)
+#define SIM_PORT_CNTL_SAPD (1 << 0)
+
+/* SIM od_config register bits */
+#define SIM_OD_CONFIG_OD_P1 (1 << 1)
+#define SIM_OD_CONFIG_OD_P0 (1 << 0)
+
+/* SIM enable register bits */
+#define SIM_ENABLE_XMTEN (1 << 1)
+#define SIM_ENABLE_RCVEN (1 << 0)
+#define SIM_ESTOP_EN (1 << 5)
+#define SIM_ESTOP_EXE (1 << 6)
+
+/* SIM int_mask register bits */
+#define SIM_INT_MASK_RFEM (1 << 13)
+#define SIM_INT_MASK_BGTM (1 << 12)
+#define SIM_INT_MASK_BWTM (1 << 11)
+#define SIM_INT_MASK_RTM (1 << 10)
+#define SIM_INT_MASK_CWTM (1 << 9)
+#define SIM_INT_MASK_GPCM (1 << 8)
+#define SIM_INT_MASK_TDTFM (1 << 7)
+#define SIM_INT_MASK_TFOM (1 << 6)
+#define SIM_INT_MASK_XTM (1 << 5)
+#define SIM_INT_MASK_TFEIM (1 << 4)
+#define SIM_INT_MASK_ETCIM (1 << 3)
+#define SIM_INT_MASK_OIM (1 << 2)
+#define SIM_INT_MASK_TCIM (1 << 1)
+#define SIM_INT_MASK_RIM (1 << 0)
+
+/* SIM xmt_status register bits */
+#define SIM_XMT_STATUS_GPCNT (1 << 8)
+#define SIM_XMT_STATUS_TDTF (1 << 7)
+#define SIM_XMT_STATUS_TFO (1 << 6)
+#define SIM_XMT_STATUS_TC (1 << 5)
+#define SIM_XMT_STATUS_ETC (1 << 4)
+#define SIM_XMT_STATUS_TFE (1 << 3)
+#define SIM_XMT_STATUS_XTE (1 << 0)
+
+/* SIM rcv_status register bits */
+#define SIM_RCV_STATUS_BGT (1 << 11)
+#define SIM_RCV_STATUS_BWT (1 << 10)
+#define SIM_RCV_STATUS_RTE (1 << 9)
+#define SIM_RCV_STATUS_CWT (1 << 8)
+#define SIM_RCV_STATUS_CRCOK (1 << 7)
+#define SIM_RCV_STATUS_LRCOK (1 << 6)
+#define SIM_RCV_STATUS_RDRF (1 << 5)
+#define SIM_RCV_STATUS_RFD (1 << 4)
+#define SIM_RCV_STATUS_RFE (1 << 1)
+#define SIM_RCV_STATUS_OEF (1 << 0)
+
+/* SIM cntl register bits */
+#define SIM_CNTL_BWTEN (1 << 15)
+#define SIM_CNTL_XMT_CRC_LRC (1 << 14)
+#define SIM_CNTL_CRCEN (1 << 13)
+#define SIM_CNTL_LRCEN (1 << 12)
+#define SIM_CNTL_CWTEN (1 << 11)
+#define SIM_CNTL_SAMPLE12 (1 << 4)
+#define SIM_CNTL_ONACK (1 << 3)
+#define SIM_CNTL_ANACK (1 << 2)
+#define SIM_CNTL_ICM (1 << 1)
+#define SIM_CNTL_GPCNT_CLK_SEL(x) ((x&0x03) << 9)
+#define SIM_CNTL_GPCNT_CLK_SEL_MASK (0x03 << 9)
+#define SIM_CNTL_BAUD_SEL(x) ((x&0x07) << 6)
+#define SIM_CNTL_BAUD_SEL_MASK (0x07 << 6)
+#define SIM_CNTL_GPCNT_CARD_CLK 1
+#define SIM_CNTL_GPCNT_RCV_CLK 2
+#define SIM_CNTL_GPCNT_ETU_CLK 3
+
+/* SIM rcv_threshold register bits */
+#define SIM_RCV_THRESHOLD_RTH(x) ((x&0x0f) << 9)
+#define SIM_RCV_THRESHOLD_RTH_MASK (0x0f << 9)
+#define SIM_RCV_THRESHOLD_RDT(x) ((x&0x1ff) << 0)
+#define SIM_RCV_THRESHOLD_RDT_MASK (0x1ff << 0)
+
+/* SIM xmt_threshold register bits */
+#define SIM_XMT_THRESHOLD_XTH(x) ((x&0x0f) << 4)
+#define SIM_XMT_THRESHOLD_XTH_MASK (0x0f << 4)
+#define SIM_XMT_THRESHOLD_TDT(x) ((x&0x0f) << 0)
+#define SIM_XMT_THRESHOLD_TDT_MASK (0x0f << 0)
+
+/* SIM guard_cntl register bits */
+#define SIM_GUARD_CNTL_RCVR11 (1 << 8)
+#define SIM_GIARD_CNTL_GETU(x) (x&0xff)
+#define SIM_GIARD_CNTL_GETU_MASK (0xff)
+
+/* SIM port[0|]_detect register bits */
+#define SIM_PORT_DETECT_SPDS (1 << 3)
+#define SIM_PORT_DETECT_SPDP (1 << 2)
+#define SIM_PORT_DETECT_SDI (1 << 1)
+#define SIM_PORT_DETECT_SDIM (1 << 0)
+
+/* SIM RESET_CNTL register bits*/
+#define SIM_RESET_CNTL_FLUSH_RCV (1 << 0)
+#define SIM_RESET_CNTL_FLUSH_XMT (1 << 1)
+#define SIM_RESET_CNTL_SOFT_RESET (1 << 2)
+#define SIM_RESET_CNTL_KILL_CLOCK (1 << 3)
+#define SIM_RESET_CNTL_DOZE (1 << 4)
+#define SIM_RESET_CNTL_STOP (1 << 5)
+#define SIM_RESET_CNTL_DEBUG (1 << 6)
+
+
+/*SIM receive buffer register error status*/
+#define SIM_REC_CWT_ERROR (1 << 10)
+#define SIM_REC_FRAME_ERROR (1 << 9)
+#define SIM_REC_PARITY_ERROR (1 << 8)
+
+#define SIM_EMV_NACK_THRESHOLD (5)
+#define EMV_T0_BGT (16)
+#define EMV_T1_BGT (22)
+#define ATR_THRESHOLD_MAX (100)
+#define ATR_MAX_CWT (10080)
+#define ATR_MAX_DURATION (20160)
+#define FCLK_FREQ (4000000)
+
+#define ATR_TIMEOUT (5)
+#define TX_TIMEOUT (10)
+#define RX_TIMEOUT (100)
+#define RESET_RETRY_TIMES (5)
+#define SIM_QUIRK_TKT259347 (1 << 0)
+#define EMV_RESET_LOW_CYCLES 40000
+#define ATR_MAX_DELAY_CLK 46400
+
+/* Main SIM driver structure */
+struct sim_t{
+ s32 present;
+ u8 open_cnt;
+ int state;
+ struct clk *clk;
+ struct resource *res;
+ void __iomem *ioaddr;
+ int ipb_irq;
+ int dat_irq;
+
+ /* error code occured during transfer */
+ int errval;
+ int protocol_type;
+ sim_timing_t timing_data;
+ sim_baud_t baud_rate;
+ int timeout;
+ u8 nack_threshold;
+ u8 nack_enable;
+ u32 expected_rcv_cnt;
+ u8 is_fixed_len_rec;
+
+ /* remaining bytes to transmit for the current transfer */
+ u32 xmt_remaining;
+ /* transmit position */
+ u32 xmt_pos;
+ /* receive position / number of bytes received */
+ u32 rcv_count;
+ u8 rcv_buffer[SIM_RCV_BUFFER_SIZE];
+ u8 xmt_buffer[SIM_XMT_BUFFER_SIZE];
+ /* transfer completion notifier */
+ struct completion xfer_done;
+ /* async notifier for card and ATR detection */
+ struct fasync_struct *fasync;
+ /* Platform specific data */
+ struct mxc_sim_platform_data *plat_data;
+ bool last_is_tx;
+ u16 rcv_head;
+ spinlock_t lock;
+ bool sven_low_active;
+ u32 port_index;
+ u32 port_detect_reg;
+ u32 port_ctrl_reg;
+ u32 clk_rate;
+ u32 quirks;
+ u8 checking_ts_timing;
+};
+
+static struct miscdevice sim_dev;
+
+static void sim_data_reset(struct sim_t *sim)
+{
+ sim->errval = SIM_OK;
+ sim->protocol_type = 0;
+ sim->timeout = 0;
+ sim->nack_threshold = SIM_EMV_NACK_THRESHOLD;
+ sim->nack_enable = 0;
+ memset(&sim->timing_data, 0, sizeof(sim->timing_data));
+ memset(&sim->baud_rate, 0, sizeof(sim->baud_rate));
+
+ sim->xmt_remaining = 0;
+ sim->xmt_pos = 0;
+ sim->rcv_count = 0;
+ sim->rcv_head = 0;
+ sim->last_is_tx = false;
+ memset(sim->rcv_buffer, 0, SIM_RCV_BUFFER_SIZE);
+ memset(sim->xmt_buffer, 0, SIM_XMT_BUFFER_SIZE);
+
+ init_completion(&sim->xfer_done);
+};
+
+static void sim_set_nack(struct sim_t *sim, u8 enable)
+{
+ u32 reg_val;
+
+ reg_val = __raw_readl(sim->ioaddr + CNTL);
+ /*Disable overrun NACK setting for now*/
+ reg_val &= ~(SIM_CNTL_ONACK);
+
+ if (enable) {
+ reg_val |= SIM_CNTL_ANACK;
+ __raw_writel(reg_val, sim->ioaddr + CNTL);
+ reg_val = __raw_readl(sim->ioaddr + XMT_THRESHOLD);
+ reg_val &= ~(SIM_XMT_THRESHOLD_XTH_MASK);
+ reg_val |= SIM_XMT_THRESHOLD_XTH(sim->nack_threshold);
+ __raw_writel(reg_val, sim->ioaddr + XMT_THRESHOLD);
+ } else {
+ reg_val &= ~SIM_CNTL_ANACK;
+ __raw_writel(reg_val, sim->ioaddr + CNTL);
+ }
+
+ sim->nack_enable = enable;
+}
+
+static void sim_set_tx(struct sim_t *sim, u8 enable)
+{
+ u32 reg_data;
+
+ reg_data = __raw_readl(sim->ioaddr + ENABLE);
+ if (enable) {
+ reg_data |= SIM_ENABLE_XMTEN | SIM_ENABLE_RCVEN;
+ if (sim->quirks & SIM_QUIRK_TKT259347)
+ reg_data &= ~(SIM_ESTOP_EN | SIM_ESTOP_EXE);
+ } else
+ reg_data &= ~SIM_ENABLE_XMTEN;
+
+ __raw_writel(reg_data, sim->ioaddr + ENABLE);
+}
+
+static void sim_set_rx(struct sim_t *sim, u8 enable)
+{
+ u32 reg_data;
+ reg_data = __raw_readl(sim->ioaddr + ENABLE);
+ if (enable) {
+ reg_data |= SIM_ENABLE_RCVEN;
+ reg_data &= ~SIM_ENABLE_XMTEN;
+ if (sim->quirks & SIM_QUIRK_TKT259347)
+ reg_data |= (SIM_ESTOP_EN | SIM_ESTOP_EXE);
+ } else {
+ reg_data &= ~SIM_ENABLE_RCVEN;
+ if (sim->quirks & SIM_QUIRK_TKT259347)
+ reg_data &= ~(SIM_ESTOP_EN | SIM_ESTOP_EXE);
+ }
+
+ __raw_writel(reg_data, sim->ioaddr + ENABLE);
+}
+
+static void sim_reset_timer(struct sim_t *sim)
+{
+ u32 reg_data;
+
+ reg_data = __raw_readl(sim->ioaddr + CNTL);
+ reg_data &= ~SIM_CNTL_GPCNT_CLK_SEL_MASK;
+ __raw_writel(reg_data, sim->ioaddr + CNTL);
+}
+
+static void sim_start_timer(struct sim_t *sim, u8 clk_source)
+{
+ u32 reg_data;
+
+ reg_data = __raw_readl(sim->ioaddr + CNTL);
+ reg_data &= ~SIM_CNTL_GPCNT_CLK_SEL_MASK;
+ reg_data |= SIM_CNTL_GPCNT_CLK_SEL(clk_source);
+ writel(reg_data, sim->ioaddr + CNTL);
+}
+
+static void sim_set_gpc_timer(struct sim_t *sim, u32 val)
+{
+ uint32_t reg_data;
+
+ /*Clear the interrupt status*/
+ reg_data = __raw_readl(sim->ioaddr + XMT_STATUS);
+ reg_data |= SIM_XMT_STATUS_GPCNT;
+ __raw_writel(reg_data, sim->ioaddr + XMT_STATUS);
+
+ /*Set the timer counter*/
+ __raw_writel(val, sim->ioaddr + GPCNT);
+
+ /*First reset the counter*/
+ sim_reset_timer(sim);
+
+ /*Enable GPC timer interrupt*/
+ reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+ reg_data &= ~SIM_INT_MASK_GPCM;
+ __raw_writel(reg_data, sim->ioaddr + INT_MASK);
+
+ /*Set the GPCNT clock source to be Fclk*/
+ sim_start_timer(sim, SIM_CNTL_GPCNT_CARD_CLK);
+}
+
+static int sim_reset_low_timing(struct sim_t *sim, u32 clock_cycle)
+{
+ int errval = 0;
+ int timeout = 0;
+ u32 fclk_in_khz, delay_in_us, reg_data;
+
+ fclk_in_khz = sim->clk_rate / MSEC_PER_SEC;
+ delay_in_us = EMV_RESET_LOW_CYCLES * USEC_PER_MSEC / fclk_in_khz;
+
+ sim_set_gpc_timer(sim, clock_cycle);
+
+ timeout = wait_for_completion_timeout(&sim->xfer_done,
+ msecs_to_jiffies(delay_in_us / 1000 * 2));
+ if (timeout == 0) {
+ pr_err("Reset low GPC timout\n");
+ errval = -SIM_E_TIMEOUT;
+ }
+
+ sim_reset_timer(sim);
+ /*Disable GPC timer interrupt*/
+ reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+ reg_data |= SIM_INT_MASK_GPCM;
+ __raw_writel(reg_data, sim->ioaddr + INT_MASK);
+
+ return errval;
+}
+
+static void sim_set_cwt(struct sim_t *sim, u8 enable)
+{
+ u32 reg_val;
+ reg_val = __raw_readl(sim->ioaddr + CNTL);
+ if (enable && sim->timing_data.cwt)
+ reg_val |= SIM_CNTL_CWTEN;
+ else
+ reg_val &= ~SIM_CNTL_CWTEN;
+ __raw_writel(reg_val, sim->ioaddr + CNTL);
+}
+
+static void sim_set_bwt(struct sim_t *sim, u8 enable)
+{
+ u32 reg_val;
+ reg_val = __raw_readl(sim->ioaddr + CNTL);
+ if (enable && (sim->timing_data.bwt || sim->timing_data.bgt))
+ reg_val |= SIM_CNTL_BWTEN;
+ else
+ reg_val &= ~SIM_CNTL_BWTEN;
+ __raw_writel(reg_val, sim->ioaddr + CNTL);
+}
+
+static int sim_reset_module(struct sim_t *sim)
+{
+ u32 reg_val;
+ s8 timeout = RESET_RETRY_TIMES;
+
+ reg_val = __raw_readl(sim->ioaddr + RESET_CNTL);
+ reg_val |= (SIM_RESET_CNTL_SOFT_RESET);
+ __raw_writel(reg_val, sim->ioaddr + RESET_CNTL);
+
+ while (__raw_readl(sim->ioaddr + RESET_CNTL) & SIM_RESET_CNTL_SOFT_RESET) {
+ usleep_range(1, 3);
+ if (timeout-- <= 0) {
+ pr_err("SIM module reset timeout\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static void sim_receive_atr_set(struct sim_t *sim)
+{
+ u32 reg_data;
+
+ /*Enable RX*/
+ sim_set_rx(sim, 1);
+
+ /*Receive fifo threshold = 1*/
+ reg_data = SIM_RCV_THRESHOLD_RTH(0) | SIM_RCV_THRESHOLD_RDT(1);
+ __raw_writel(reg_data, sim->ioaddr + RCV_THRESHOLD);
+
+ /* Clear the interrupt status*/
+ reg_data = __raw_readl(sim->ioaddr + RCV_STATUS);
+ reg_data |= (SIM_RCV_STATUS_CWT | SIM_RCV_STATUS_RDRF);
+ __raw_writel(reg_data, sim->ioaddr + RCV_STATUS);
+
+ /*Set the cwt timer.Refer the setting of ATR on EMV4.3 book*/
+ __raw_writel(ATR_MAX_CWT, sim->ioaddr + CHAR_WAIT);
+
+ /*Set the baud rate to be 1/372. Refer the setting of ATR on EMV4.3 book
+ *Enable the CWT timer during receiving ATR process.
+ */
+ reg_data = __raw_readl(sim->ioaddr + CNTL);
+ reg_data &= ~SIM_CNTL_BAUD_SEL_MASK;
+ reg_data |= SIM_CNTL_BAUD_SEL(0) | SIM_CNTL_CWTEN;
+
+ /*Enable ICM mode*/
+ reg_data |= SIM_CNTL_ICM;
+
+ /*Enable Sample12*/
+ reg_data |= SIM_CNTL_SAMPLE12;
+ __raw_writel(reg_data, sim->ioaddr + CNTL);
+
+ /*Disable NACK*/
+ sim_set_nack(sim, 0);
+
+ /*Set 12 ETUS*/
+ __raw_writel(0, sim->ioaddr + GUARD_CNTL);
+
+ sim->errval = 0;
+ sim->rcv_count = 0;
+ sim->checking_ts_timing = 1;
+ sim->state = SIM_STATE_ATR_RECEIVING;
+
+ /*Enable the RIM and GPC interrupt, disalbe the CWT interrupt*/
+ reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+ reg_data |= SIM_INT_MASK_CWTM;
+ reg_data &= ~(SIM_INT_MASK_RIM | SIM_INT_MASK_GPCM);
+ __raw_writel(reg_data, sim->ioaddr + INT_MASK);
+}
+
+static int32_t sim_check_rec_data(u32 *reg_data)
+{
+ s32 err = 0;
+
+ if (*reg_data & SIM_REC_CWT_ERROR)
+ err |= SIM_ERROR_CWT;
+
+ if (*reg_data & SIM_REC_FRAME_ERROR)
+ err |= SIM_ERROR_FRAME;
+
+ if (*reg_data & SIM_REC_PARITY_ERROR)
+ err |= SIM_ERROR_PARITY;
+
+ return err;
+}
+
+static void sim_xmt_fill_fifo(struct sim_t *sim)
+{
+ u32 reg_data;
+ u32 bytesleft, i;
+
+ reg_data = __raw_readl(sim->ioaddr + XMT_FIFO_STAT);
+ bytesleft = SIM_TX_FIFO_DEPTH - ((reg_data >> 8) & 0x0F);
+
+ if (bytesleft > sim->xmt_remaining)
+ bytesleft = sim->xmt_remaining;
+
+ for (i = 0; i < bytesleft; i++) {
+ __raw_writel(sim->xmt_buffer[sim->xmt_pos],
+ sim->ioaddr + PORT1_XMT_BUF);
+ sim->xmt_pos++;
+ };
+ sim->xmt_remaining -= bytesleft;
+};
+
+static void sim_rcv_read_fifo(struct sim_t *sim)
+{
+ u16 i, count;
+ u32 reg_data;
+
+ count = __raw_readl(sim->ioaddr + RCV_FIFO_CNT);
+
+ spin_lock(&sim->lock);
+ for (i = 0; i < count; i++) {
+ reg_data = __raw_readl(sim->ioaddr + PORT1_RCV_BUF);
+ sim->errval |= sim_check_rec_data(&reg_data);
+
+ /* T1 mode and t0 mode no parity error, T1 mode SIM module will not produce NACK be
+ * NACK is disabled. T0 mode to ensure there is no parity error for the current byte
+ */
+ if (!(sim->nack_enable && (reg_data & SIM_REC_PARITY_ERROR))) {
+ sim->rcv_buffer[sim->rcv_head + sim->rcv_count] = (u8)reg_data;
+ sim->rcv_count++;
+ }
+ if (sim->rcv_head + sim->rcv_count >= SIM_RCV_BUFFER_SIZE) {
+ pr_err("The software fifo is full,head %d, cnt%d\n", sim->rcv_head, sim->rcv_count);
+ break;
+ }
+ }
+ spin_unlock(&sim->lock);
+}
+
+static void sim_tx_irq_enable(struct sim_t *sim)
+{
+ u32 reg_val;
+ /*Clear the status and enable the related interrupt*/
+ reg_val = __raw_readl(sim->ioaddr + XMT_STATUS);
+ __raw_writel(reg_val, sim->ioaddr + XMT_STATUS);
+ reg_val = __raw_readl(sim->ioaddr + RCV_STATUS);
+ __raw_writel(reg_val, sim->ioaddr + RCV_STATUS);
+
+ reg_val = __raw_readl(sim->ioaddr + INT_MASK);
+ /*
+ *Disable CWT , BWT interrupt when transmitting, it would
+ *be enabled when rx is enabled just after tx completes
+ *The timer will be enabled.
+ */
+ reg_val |= SIM_INT_MASK_CWTM | SIM_INT_MASK_BWTM;
+ reg_val |= SIM_INT_MASK_RIM | SIM_INT_MASK_RTM;
+
+ if (sim->xmt_remaining != 0)
+ reg_val &= ~SIM_INT_MASK_TDTFM;
+ else{
+ reg_val &= ~SIM_INT_MASK_TCIM;
+ /*Enable transmit early complete interrupt.*/
+ reg_val &= ~SIM_INT_MASK_ETCIM;
+ }
+
+ /*NACK interrupt is enabled only when T0 mode*/
+ if (sim->protocol_type == SIM_PROTOCOL_T0 || sim->nack_enable != 0)
+ reg_val &= ~SIM_INT_MASK_XTM;
+ else
+ reg_val |= SIM_INT_MASK_XTM;
+ __raw_writel(reg_val, sim->ioaddr + INT_MASK);
+}
+
+static void sim_tx_irq_disable(struct sim_t *sim)
+{
+ u32 reg_val;
+ /*Disable the NACK interruptand TX related interrupt*/
+ reg_val = __raw_readl(sim->ioaddr + INT_MASK);
+ reg_val |= (SIM_INT_MASK_TDTFM | SIM_INT_MASK_TCIM | SIM_INT_MASK_XTM | SIM_INT_MASK_ETCIM);
+ __raw_writel(reg_val, sim->ioaddr + INT_MASK);
+}
+
+static void sim_rx_irq_enable(struct sim_t *sim)
+{
+ u32 reg_data;
+ /*
+ * Ensure the CWT timer is enabled.
+ */
+ sim_set_cwt(sim, 1);
+ reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+ reg_data |= (SIM_INT_MASK_TCIM | SIM_INT_MASK_TDTFM | SIM_INT_MASK_XTM);
+ reg_data &= ~(SIM_INT_MASK_RIM | SIM_INT_MASK_CWTM | SIM_INT_MASK_BWTM);
+
+ if (sim->protocol_type == SIM_PROTOCOL_T0 || sim->nack_enable != 0)
+ reg_data &= ~SIM_INT_MASK_RTM;
+ else
+ reg_data |= SIM_INT_MASK_RTM;
+
+ __raw_writel(reg_data, sim->ioaddr + INT_MASK);
+}
+
+static void sim_rx_irq_disable(struct sim_t *sim)
+{
+ u32 reg_val;
+ reg_val = __raw_readl(sim->ioaddr + INT_MASK);
+ reg_val |= (SIM_INT_MASK_RIM | SIM_INT_MASK_CWTM | SIM_INT_MASK_BWTM | SIM_INT_MASK_RTM);
+ __raw_writel(reg_val, sim->ioaddr + INT_MASK);
+}
+
+static irqreturn_t sim_irq_handler(int irq, void *dev_id)
+{
+ u32 reg_data, tx_status, rx_status;
+
+ struct sim_t *sim = (struct sim_t *) dev_id;
+
+ tx_status = __raw_readl(sim->ioaddr + XMT_STATUS);
+ rx_status = __raw_readl(sim->ioaddr + RCV_STATUS);
+ __raw_writel(tx_status, sim->ioaddr + XMT_STATUS);
+ __raw_writel(rx_status, sim->ioaddr + RCV_STATUS);
+
+ if (sim->state == SIM_STATE_ATR_RECEIVING &&
+ sim->checking_ts_timing == 1) {
+
+ if ((tx_status & SIM_XMT_STATUS_GPCNT) &&
+ !(rx_status & SIM_RCV_STATUS_RDRF)) {
+ /*Disable the GPCNT timer and CWT timer right now*/
+ reg_data = __raw_readl(sim->ioaddr + CNTL);
+ reg_data &= ~(SIM_CNTL_GPCNT_CLK_SEL_MASK |
+ SIM_CNTL_CWTEN);
+ __raw_writel(reg_data, sim->ioaddr + CNTL);
+
+ reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+ reg_data |= (SIM_INT_MASK_GPCM |
+ SIM_INT_MASK_CWTM | SIM_INT_MASK_RIM);
+ __raw_writel(reg_data, sim->ioaddr + INT_MASK);
+ sim->errval = SIM_ERROR_ATR_DELAY;
+ complete(&sim->xfer_done);
+ sim->checking_ts_timing = 0;
+ } else if (rx_status & SIM_RCV_STATUS_RDRF) {
+ /*
+ * Reset/stop the GPCNT timer first.
+ */
+ sim_reset_timer(sim);
+
+ /*Enable GPC, CWT interrupt and
+ *disable the rx full interrupt
+ */
+ reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+ reg_data &= ~(SIM_INT_MASK_GPCM | SIM_INT_MASK_CWTM);
+ reg_data |= SIM_INT_MASK_RIM;
+ __raw_writel(reg_data, sim->ioaddr + INT_MASK);
+ sim_rcv_read_fifo(sim);
+
+ /*Clear the GPCNT expiring status*/
+ __raw_writel(SIM_XMT_STATUS_GPCNT,
+ sim->ioaddr + XMT_STATUS);
+
+ /*ATR each recieved byte will cost 12 ETU, so get the remaining etus*/
+ reg_data = ATR_MAX_DURATION - sim->rcv_count * 12;
+ __raw_writel(reg_data, sim->ioaddr + GPCNT);
+
+ sim_start_timer(sim, SIM_CNTL_GPCNT_ETU_CLK);
+
+ /*Receive fifo threshold set to max value*/
+ reg_data = SIM_RCV_THRESHOLD_RTH(0) | SIM_RCV_THRESHOLD_RDT(ATR_THRESHOLD_MAX);
+ __raw_writel(reg_data, sim->ioaddr + RCV_THRESHOLD);
+ sim->checking_ts_timing = 0;
+ } else {
+ pr_err("Unexpected irq when delay checking\n");
+ }
+ }
+
+ else if (sim->state == SIM_STATE_ATR_RECEIVING) {
+ if ((rx_status & SIM_RCV_STATUS_CWT) ||
+ ((tx_status & SIM_XMT_STATUS_GPCNT) &&
+ (sim->rcv_count != 0))) {
+
+ /*Disable the GPCNT timer and CWT timer right now*/
+ reg_data = __raw_readl(sim->ioaddr + CNTL);
+ reg_data &= ~(SIM_CNTL_GPCNT_CLK_SEL_MASK | SIM_CNTL_CWTEN);
+ __raw_writel(reg_data, sim->ioaddr + CNTL);
+
+ reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+ reg_data |= (SIM_INT_MASK_GPCM | SIM_INT_MASK_CWTM);
+ __raw_writel(reg_data, sim->ioaddr + INT_MASK);
+
+ if (tx_status & SIM_XMT_STATUS_GPCNT)
+ sim->errval |= SIM_ERROR_ATR_TIMEROUT;
+
+ if (rx_status & SIM_RCV_STATUS_CWT)
+ sim->errval |= SIM_ERROR_CWT;
+
+ sim_rcv_read_fifo(sim);
+ sim->state = SIM_STATE_ATR_RECEIVED;
+
+ complete(&sim->xfer_done);
+ }
+ }
+
+ else if (sim->state == SIM_STATE_XMTING) {
+ /*The CWT BWT expire should not happen when in the transmitting state*/
+ if (tx_status & SIM_XMT_STATUS_ETC) {
+ /*Once the transmit frame is completed, need to enable CWT timer*/
+ sim_set_cwt(sim, 1);
+ }
+ if (tx_status & SIM_XMT_STATUS_XTE) {
+ /*Disable TX*/
+ sim_set_tx(sim, 0);
+ /*Disalbe the timers*/
+ sim_set_cwt(sim, 0);
+ sim_set_bwt(sim, 0);
+ /*Disable the NACK interruptand TX related interrupt*/
+ sim_tx_irq_disable(sim);
+
+ /*Update the state and status*/
+ sim->errval |= SIM_ERROR_NACK_THRESHOLD;
+ sim->state = SIM_STATE_XMT_ERROR;
+
+ complete(&sim->xfer_done);
+ } else if (tx_status & SIM_XMT_STATUS_TDTF && sim->xmt_remaining != 0) {
+ sim_xmt_fill_fifo(sim);
+ if (sim->xmt_remaining == 0) {
+ /*Disable TX threshold interrupt and enable tx complete interrupt*/
+ reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+ reg_data |= SIM_INT_MASK_TDTFM;
+ /*Enable transmit complete and early transmit complete interrupt*/
+ reg_data &= ~(SIM_INT_MASK_TCIM | SIM_INT_MASK_ETCIM);
+ __raw_writel(reg_data, sim->ioaddr + INT_MASK);
+ }
+ } else if (tx_status & SIM_XMT_STATUS_TC && sim->xmt_remaining == 0) {
+ /*Disable the NACK interruptand TX related interrupt*/
+ sim_tx_irq_disable(sim);
+ sim_set_rx(sim, 1);
+ /*Update the state and status*/
+ sim->state = SIM_STATE_XMT_DONE;
+ complete(&sim->xfer_done);
+ }
+ }
+
+ /*
+ * It takes some time to change from SIM_STATE_XMT_DONE to SIM_STATE_RECEIVING
+ * RX would only be enabled after state becomes SIM_STATE_RECEIVING
+ */
+ else if (sim->state == SIM_STATE_RECEIVING) {
+ if (rx_status & SIM_RCV_STATUS_RTE) {
+ /*Disable RX*/
+ sim_set_rx(sim, 0);
+ /*Disable the BWT timer and CWT timer right now*/
+ sim_set_cwt(sim, 0);
+ sim_set_bwt(sim, 0);
+ /*Disable the interrupt right now*/
+ sim_rx_irq_disable(sim);
+ /*Should we read the fifo or just flush the fifo?*/
+ sim_rcv_read_fifo(sim);
+ sim->errval = SIM_ERROR_NACK_THRESHOLD;
+ sim->state = SIM_STATE_RECEIVE_ERROR;
+ complete(&sim->xfer_done);
+ }
+
+ if (rx_status & SIM_RCV_STATUS_RDRF) {
+ sim_rcv_read_fifo(sim);
+ if (sim->is_fixed_len_rec &&
+ sim->rcv_count >= sim->expected_rcv_cnt) {
+
+ /*Disable the BWT timer and CWT timer right now*/
+ sim_rx_irq_disable(sim);
+ /*Add the state judgement to ensure the maybe complete has been impletment in the above "if" case*/
+ if (sim->state == SIM_STATE_RECEIVING) {
+ sim->state = SIM_STATE_RECEIVE_DONE;
+ complete(&sim->xfer_done);
+ }
+ }
+ }
+
+ if ((rx_status & SIM_RCV_STATUS_CWT) ||
+ (rx_status & SIM_RCV_STATUS_BWT) ||
+ (rx_status & SIM_RCV_STATUS_BGT)) {
+
+ /*Disable the BWT timer and CWT timer right now*/
+ sim_set_cwt(sim, 0);
+ sim_set_bwt(sim, 0);
+ sim_rx_irq_disable(sim);
+
+ if (rx_status & SIM_RCV_STATUS_BWT) {
+ sim->errval |= SIM_ERROR_BWT;
+ }
+ if (rx_status & SIM_RCV_STATUS_CWT)
+ sim->errval |= SIM_ERROR_CWT;
+ if (rx_status & SIM_RCV_STATUS_BGT)
+ sim->errval |= SIM_ERROR_BGT;
+
+ sim_rcv_read_fifo(sim);
+ /*Add the state judgement to ensure the maybe complete has been impletment in the above "if" case*/
+ if (sim->state == SIM_STATE_RECEIVING) {
+ sim->state = SIM_STATE_RECEIVE_DONE;
+ complete(&sim->xfer_done);
+ }
+ }
+ }
+
+ else if ((sim->state == SIM_STATE_RESET_SEQUENCY) &&
+ (tx_status & SIM_XMT_STATUS_GPCNT))
+ complete(&sim->xfer_done);
+ else if (rx_status & SIM_RCV_STATUS_RDRF) {
+ pr_err("unexpected status %d\n", sim->state);
+ sim_rcv_read_fifo(sim);
+ }
+
+ return IRQ_HANDLED;
+};
+
+static void sim_start(struct sim_t *sim)
+{
+ u32 reg_data, clk_rate, clk_div = 0;
+ pr_debug("%s entering.\n", __func__);
+
+ if (sim->port_index == 1)
+ __raw_writel(SIM_SETUP_SPS_PORT1, sim->ioaddr + SETUP);
+ else
+ __raw_writel(SIM_SETUP_SPS_PORT0, sim->ioaddr + SETUP);
+
+ /*1 ~ 5 MHz */
+ clk_rate = clk_get_rate(sim->clk);
+ clk_div = (clk_rate + sim->clk_rate - 1) / sim->clk_rate;
+ __raw_writel(clk_div, sim->ioaddr + CLK_PRESCALER);
+
+ /*Set the port pin to be open drained*/
+ reg_data = __raw_readl(sim->ioaddr + OD_CONFIG);
+ if (sim->port_index == 1)
+ reg_data |= SIM_OD_CONFIG_OD_P1;
+ else
+ reg_data |= SIM_OD_CONFIG_OD_P0;
+
+ __raw_writel(reg_data, sim->ioaddr + OD_CONFIG);
+
+ reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+
+ /*One pin mode*/
+ reg_data |= SIM_PORT_CNTL_3VOLT | SIM_PORT_CNTL_STEN;
+ __raw_writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+
+ /* presense detect */
+ pr_debug("%s p0_det is 0x%x \n", __func__,
+ __raw_readl(sim->ioaddr + sim->port_detect_reg));
+ if (__raw_readl(sim->ioaddr + sim->port_detect_reg)
+ & SIM_PORT_DETECT_SPDP) {
+ reg_data = __raw_readl(sim->ioaddr + sim->port_detect_reg);
+ reg_data &= ~SIM_PORT_DETECT_SPDS;
+ __raw_writel(reg_data, sim->ioaddr + sim->port_detect_reg);
+ sim->present = SIM_PRESENT_REMOVED;
+ sim->state = SIM_STATE_REMOVED;
+ } else {
+ reg_data = __raw_readl(sim->ioaddr + sim->port_detect_reg);
+ reg_data |= SIM_PORT_DETECT_SPDS;
+ __raw_writel(reg_data, sim->ioaddr + sim->port_detect_reg);
+ sim->present = SIM_PRESENT_DETECTED;
+ sim->state = SIM_STATE_DETECTED;
+ };
+
+ /*enable card interrupt. clear interrupt status*/
+ reg_data = __raw_readl(sim->ioaddr + sim->port_detect_reg);
+ reg_data |= SIM_PORT_DETECT_SDI;
+ reg_data |= SIM_PORT_DETECT_SDIM;
+ __raw_writel(reg_data, sim->ioaddr + sim->port_detect_reg);
+};
+
+static void sim_cold_reset_sequency(struct sim_t *sim)
+{
+ u32 reg_data;
+
+ sim->state = SIM_STATE_RESET_SEQUENCY;
+
+ /*set VCC*/
+ reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+ if (sim->sven_low_active)
+ reg_data &= ~SIM_PORT_CNTL_SVEN;
+ else
+ reg_data |= SIM_PORT_CNTL_SVEN;
+ __raw_writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+
+ msleep(9);
+
+ /*enable CLK*/
+ reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+ reg_data |= SIM_PORT_CNTL_SCEN;
+ __raw_writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+
+ /*RST low time*/
+ sim_reset_low_timing(sim, EMV_RESET_LOW_CYCLES);
+
+ /*RST high*/
+ reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+ reg_data |= SIM_PORT_CNTL_SRST;
+ __raw_writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+
+ /*wait for ATR*/
+ sim_set_gpc_timer(sim, ATR_MAX_DELAY_CLK);
+};
+
+static void sim_deactivate(struct sim_t *sim)
+{
+ u32 reg_data;
+
+ pr_debug("%s entering.\n", __func__);
+ /* Auto powdown to implement the deactivate sequence */
+ if (sim->present != SIM_PRESENT_REMOVED) {
+ if (sim->sven_low_active) {
+ /*Set the RESET to be low*/
+ reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+ reg_data &= ~SIM_PORT_CNTL_SRST;
+ writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+ usleep_range(2, 5);
+
+ /*Set the clock to be low*/
+ reg_data &= ~SIM_PORT_CNTL_SCEN;
+ writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+ usleep_range(2, 5);
+
+ /*Set the sven to be high*/
+ reg_data |= SIM_PORT_CNTL_SVEN;
+ writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+
+ } else {
+ reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+ reg_data |= SIM_PORT_CNTL_SAPD;
+ __raw_writel(reg_data,
+ sim->ioaddr + sim->port_ctrl_reg);
+ reg_data |= SIM_PORT_CNTL_SFPD;
+ __raw_writel(reg_data,
+ sim->ioaddr + sim->port_ctrl_reg);
+ }
+ } else
+ pr_err(">>>No card%s\n", __func__);
+};
+
+static void sim_cold_reset(struct sim_t *sim)
+{
+ if (sim->present != SIM_PRESENT_REMOVED) {
+ sim->state = SIM_STATE_DETECTED;
+ sim->present = SIM_PRESENT_DETECTED;
+ sim_cold_reset_sequency(sim);
+ sim_receive_atr_set(sim);
+ } else {
+ pr_err("No card%s\n", __func__);
+ }
+};
+
+static void sim_warm_reset_sequency(struct sim_t *sim)
+{
+ u32 reg_data;
+
+ sim->state = SIM_STATE_RESET_SEQUENCY;
+ reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+ reg_data |= (SIM_PORT_CNTL_SRST | SIM_PORT_CNTL_SCEN);
+ if (sim->sven_low_active)
+ reg_data &= ~SIM_PORT_CNTL_SVEN;
+ else
+ reg_data |= SIM_PORT_CNTL_SVEN;
+ __raw_writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+
+ usleep_range(20, 25);
+
+ reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+ reg_data &= ~SIM_PORT_CNTL_SRST;
+ __raw_writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+
+ sim_reset_low_timing(sim, EMV_RESET_LOW_CYCLES);
+
+ reg_data = __raw_readl(sim->ioaddr + sim->port_ctrl_reg);
+ reg_data |= SIM_PORT_CNTL_SRST;
+ __raw_writel(reg_data, sim->ioaddr + sim->port_ctrl_reg);
+ sim_set_gpc_timer(sim, ATR_MAX_DELAY_CLK);
+}
+
+static void sim_warm_reset(struct sim_t *sim)
+{
+ if (sim->present != SIM_PRESENT_REMOVED) {
+ sim_data_reset(sim);
+ sim_warm_reset_sequency(sim);
+ sim_receive_atr_set(sim);
+ } else {
+ pr_err("No card%s\n", __func__);
+ }
+};
+
+
+static int sim_card_lock(struct sim_t *sim)
+{
+ int errval;
+
+ /* place holder for true physcial locking */
+ if (sim->present != SIM_PRESENT_REMOVED)
+ errval = SIM_OK;
+ else
+ errval = -SIM_E_NOCARD;
+ return errval;
+};
+
+static int sim_card_eject(struct sim_t *sim)
+{
+ int errval;
+
+ pr_debug("%s entering.\n", __func__);
+ /* place holder for true physcial locking */
+ if (sim->present != SIM_PRESENT_REMOVED)
+ errval = SIM_OK;
+ else
+ errval = -SIM_E_NOCARD;
+ return errval;
+};
+
+static int sim_check_baud_rate(sim_baud_t *baud_rate)
+{
+ /*
+ * The valid value is decribed in the 8.3.3.1 in EMV 4.3
+ */
+ if (baud_rate->fi == 1 && (baud_rate->di == 1 ||
+ baud_rate->di == 2 || baud_rate->di == 3))
+ return 0;
+
+ return -EINVAL;
+}
+
+static int sim_set_baud_rate(struct sim_t *sim)
+{
+ u32 reg_data;
+ reg_data = __raw_readl(sim->ioaddr + CNTL);
+ reg_data &= ~(SIM_CNTL_BAUD_SEL_MASK);
+
+ switch (sim->baud_rate.di) {
+ case 1:
+ reg_data |= SIM_CNTL_BAUD_SEL(0);
+ break;
+ case 2:
+ reg_data |= SIM_CNTL_BAUD_SEL(1);
+ break;
+ case 3:
+ reg_data |= SIM_CNTL_BAUD_SEL(2);
+ break;
+ default:
+ pr_err("Invalid baud Di, Using default 372 / 1\n");
+ reg_data |= SIM_CNTL_BAUD_SEL(0);
+ break;
+ }
+
+ __raw_writel(reg_data, sim->ioaddr + CNTL);
+
+ return 0;
+}
+
+static int sim_check_timing_data(sim_timing_t *timing_data)
+{
+ if (timing_data->wwt > 0xFFFF ||
+ timing_data->cwt > 0xFFFF ||
+ timing_data->bgt > 0xFFFF ||
+ timing_data->cgt > 0xFF) {
+ /*Check whether the counter is out of the scope of SIM IP*/
+ pr_err("The timing value is out of scope of IP\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void sim_set_timer_counter(struct sim_t *sim)
+{
+ if (sim->timing_data.wwt != 0 &&
+ sim->protocol_type == SIM_PROTOCOL_T0) {
+ sim->timing_data.cwt = sim->timing_data.wwt;
+ sim->timing_data.bwt = sim->timing_data.wwt;
+ }
+
+
+ if (sim->timing_data.bgt != 0) {
+ __raw_writel(sim->timing_data.bgt, sim->ioaddr + BGT);
+ }
+
+ if (sim->timing_data.cwt != 0)
+ __raw_writel(sim->timing_data.cwt, sim->ioaddr + CHAR_WAIT);
+
+ if (sim->timing_data.bwt != 0) {
+
+ __raw_writel(sim->timing_data.bwt & 0x0000FFFF, sim->ioaddr + BWT);
+ __raw_writel((sim->timing_data.bwt >> 16) & 0x0000FFFF,
+ sim->ioaddr + BWT_H);
+ }
+
+ if (sim->timing_data.cgt == 0xFF && sim->protocol_type == SIM_PROTOCOL_T0)
+ /* From EMV4.3 , CGT =0xFF in T0 mode means 12 ETU.
+ * Set register to be 12 ETU for transmitting and receiving.
+ */
+ __raw_writel(0 , sim->ioaddr + GUARD_CNTL);
+ else if (sim->timing_data.cgt == 0xFF && sim->protocol_type == SIM_PROTOCOL_T1)
+ /* From EMV4.3 , CGT =0xFF in T1 mode means 11 ETU.
+ * Set register to be 12 ETU for transmitting and receiving.
+ */
+ __raw_writel(0x1FF , sim->ioaddr + GUARD_CNTL);
+
+ /*For the T1 mode, use 11ETU to receive.*/
+ else if (sim->protocol_type == SIM_PROTOCOL_T1)
+ __raw_writel((sim->timing_data.cgt | SIM_GUARD_CNTL_RCVR11), sim->ioaddr + GUARD_CNTL);
+
+ else
+ /*sim->protocol_type == SIM_PROTOCOL_T0*/
+ __raw_writel(sim->timing_data.cgt, sim->ioaddr + GUARD_CNTL);
+}
+
+static void sim_xmt_start(struct sim_t *sim)
+{
+ u32 reg_val;
+
+ /*Set TX threshold if there are remaing data*/
+ if (sim->xmt_remaining != 0) {
+ reg_val = __raw_readl(sim->ioaddr + XMT_THRESHOLD);
+ reg_val &= ~SIM_XMT_THRESHOLD_TDT_MASK;
+ reg_val |= SIM_XMT_THRESHOLD_TDT(TX_FIFO_THRESHOLD);
+ __raw_writel(reg_val, sim->ioaddr + XMT_THRESHOLD);
+ }
+ sim_tx_irq_enable(sim);
+
+ /*Enable BWT and disalbe CWT timers when tx*/
+ sim_set_bwt(sim, 1);
+ sim_set_cwt(sim, 0);
+
+ /*Disalbe RX*/
+ sim_set_rx(sim, 0);
+
+ /*Enable TX*/
+ sim_set_tx(sim, 1);
+}
+
+static void sim_flush_fifo(struct sim_t *sim, u8 flush_tx, u8 flush_rx)
+{
+ u32 reg_val;
+
+ reg_val = __raw_readl(sim->ioaddr + RESET_CNTL);
+
+ if (flush_tx)
+ reg_val |= SIM_RESET_CNTL_FLUSH_XMT;
+ if (flush_rx)
+ reg_val |= SIM_RESET_CNTL_FLUSH_RCV;
+ __raw_writel(reg_val, sim->ioaddr + RESET_CNTL);
+
+ usleep_range(2, 3);
+
+ if (flush_tx)
+ reg_val &= ~(SIM_RESET_CNTL_FLUSH_XMT);
+ if (flush_rx)
+ reg_val &= ~(SIM_RESET_CNTL_FLUSH_RCV);
+ __raw_writel(reg_val, sim->ioaddr + RESET_CNTL);
+}
+
+static void sim_change_rcv_threshold(struct sim_t *sim)
+{
+ u32 rx_threshold = 0;
+ u32 reg_val = 0;
+
+ if (sim->is_fixed_len_rec) {
+ rx_threshold = sim->expected_rcv_cnt - sim->rcv_count;
+ reg_val = __raw_readl(sim->ioaddr + RCV_THRESHOLD);
+ reg_val &= ~(SIM_RCV_THRESHOLD_RDT_MASK);
+ reg_val |= SIM_RCV_THRESHOLD_RDT(rx_threshold);
+ __raw_writel(reg_val, sim->ioaddr + RCV_THRESHOLD);
+ }
+}
+
+static void sim_start_rcv(struct sim_t *sim)
+{
+ sim_set_baud_rate(sim);
+ if (sim->protocol_type == SIM_PROTOCOL_T0)
+ sim_set_nack(sim, 1);
+ else if (sim->protocol_type == SIM_PROTOCOL_T1)
+ sim_set_nack(sim, 0);
+
+ /*Set RX threshold*/
+ if (sim->protocol_type == SIM_PROTOCOL_T0)
+ __raw_writel(SIM_RCV_THRESHOLD_RTH(sim->nack_threshold) |
+ SIM_RCV_THRESHOLD_RDT(RX_FIFO_THRESHOLD), sim->ioaddr + RCV_THRESHOLD);
+ else
+ __raw_writel(SIM_RCV_THRESHOLD_RDT(RX_FIFO_THRESHOLD), sim->ioaddr + RCV_THRESHOLD);
+
+ /*Clear status and enable interrupt*/
+ sim_rx_irq_enable(sim);
+
+ /*Disalbe TX and Enable Rx*/
+ sim_set_rx(sim, 1);
+ sim_set_tx(sim, 0);
+}
+
+static void sim_polling_delay(struct sim_t *sim, u32 delay)
+{
+ u32 reg_data;
+
+ /*Reset the timer*/
+ reg_data = __raw_readl(sim->ioaddr + CNTL);
+ reg_data &= ~SIM_CNTL_GPCNT_CLK_SEL_MASK;
+ reg_data |= SIM_CNTL_GPCNT_CLK_SEL(0);
+ __raw_writel(reg_data, sim->ioaddr + CNTL);
+
+ /*Clear the interrupt status*/
+ __raw_writel(SIM_XMT_STATUS_GPCNT, sim->ioaddr + XMT_STATUS);
+
+ /*Disable timer interrupt*/
+ reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+ reg_data |= SIM_INT_MASK_GPCM;
+ __raw_writel(reg_data, sim->ioaddr + INT_MASK);
+
+ __raw_writel(delay, sim->ioaddr + GPCNT);
+
+ /*Set the ETU as clock source and start timer*/
+ reg_data = __raw_readl(sim->ioaddr + CNTL);
+ reg_data &= ~SIM_CNTL_GPCNT_CLK_SEL_MASK;
+ reg_data |= SIM_CNTL_GPCNT_CLK_SEL(3);
+ __raw_writel(reg_data, sim->ioaddr + CNTL);
+
+ /*Loop for timeout*/
+ while (!(__raw_readl(sim->ioaddr + XMT_STATUS) & SIM_XMT_STATUS_GPCNT))
+ usleep_range(10, 20);
+ __raw_writel(SIM_XMT_STATUS_GPCNT, sim->ioaddr + XMT_STATUS);
+}
+
+void sim_clear_rx_buf(struct sim_t *sim)
+{
+ unsigned int i;
+ for (i = 0; i < SIM_RCV_BUFFER_SIZE; i++)
+ sim->rcv_buffer[i] = 0;
+ sim->rcv_count = 0;
+ sim->rcv_head = 0;
+}
+
+static long sim_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret, errval = SIM_OK;
+ unsigned long timeout;
+ u32 reg_data;
+ u32 delay;
+ u32 copy_cnt, val;
+ unsigned long flags;
+ unsigned char __user *atr_buffer;
+ unsigned char __user *xmt_buffer;
+ unsigned char __user *rcv_buffer;
+
+ struct sim_t *sim = (struct sim_t *) file->private_data;
+
+ pr_debug("%s entering.\n", __func__);
+ switch (cmd) {
+
+ case SIM_IOCTL_GET_ATR:
+ if (sim->present != SIM_PRESENT_DETECTED) {
+ pr_err("NO card ...\n");
+ errval = -SIM_E_NOCARD;
+ break;
+ };
+ sim->timeout = ATR_TIMEOUT * HZ;
+ val = 0;
+ ret = copy_to_user(&(((sim_atr_t *)arg)->size), &val,
+ sizeof((((sim_atr_t *)arg)->size)));
+
+ timeout = wait_for_completion_interruptible_timeout(&sim->xfer_done,
+ sim->timeout);
+ /*Disalbe the GPCNT timer and CWT timer right now*/
+ reg_data = __raw_readl(sim->ioaddr + CNTL);
+ reg_data &= ~(SIM_CNTL_GPCNT_CLK_SEL_MASK | SIM_CNTL_CWTEN);
+ __raw_writel(reg_data, sim->ioaddr + CNTL);
+
+ reg_data = __raw_readl(sim->ioaddr + INT_MASK);
+ reg_data |= (SIM_INT_MASK_GPCM | SIM_INT_MASK_CWTM);
+ __raw_writel(reg_data, sim->ioaddr + INT_MASK);
+
+ if (timeout == 0) {
+ pr_err("ATR timeout\n");
+ errval = -SIM_E_TIMEOUT;
+ break;
+ }
+
+ ret = copy_to_user(&(((sim_atr_t *)arg)->size), &sim->rcv_count,
+ sizeof(sim->rcv_count));
+ if (ret) {
+ pr_err("ATR ACCESS rcv_count Error, %d\n", ret);
+ errval = -SIM_E_ACCESS;
+ break;
+ }
+
+ __get_user(atr_buffer, &((sim_atr_t __user *)arg)->atr_buffer);
+ ret = copy_to_user(atr_buffer, sim->rcv_buffer, sim->rcv_count);
+ if (ret) {
+ pr_err("ATR ACCESS buffer Error %d %d\n", sim->rcv_count, ret);
+ errval = -SIM_E_ACCESS;
+ break;
+ }
+
+ ret = copy_to_user(&(((sim_atr_t *)arg)->errval), &sim->errval,
+ sizeof(sim->errval));
+ if (ret) {
+ pr_err("ATR ACCESS Error\n");
+ errval = -SIM_E_ACCESS;
+ break;
+ }
+ sim->rcv_count = 0;
+ sim->rcv_head = 0;
+ sim->errval = 0;
+
+ break;
+
+ case SIM_IOCTL_DEACTIVATE:
+
+ sim_deactivate(sim);
+ break;
+
+ case SIM_IOCTL_COLD_RESET:
+ sim->present = SIM_PRESENT_REMOVED;
+ sim->state = SIM_STATE_REMOVED;
+ sim_reset_module(sim);
+ sim_data_reset(sim);
+ sim_start(sim);
+ sim_cold_reset(sim);
+
+ break;
+
+ case SIM_IOCTL_WARM_RESET:
+ sim_warm_reset(sim);
+ break;
+
+ case SIM_IOCTL_XMT:
+ ret = copy_from_user(&sim->xmt_remaining, &(((sim_xmt_t *)arg)->xmt_length),
+ sizeof(uint32_t));
+ if (ret || sim->xmt_remaining > SIM_XMT_BUFFER_SIZE) {
+ pr_err("copy error or to big buffer\n");
+ errval = -EINVAL;
+ break;
+ }
+
+ __get_user(xmt_buffer, &((sim_xmt_t *)arg)->xmt_buffer);
+ ret = copy_from_user(sim->xmt_buffer, xmt_buffer, sim->xmt_remaining);
+
+ if (ret) {
+ pr_err("Copy Error\n");
+ errval = ret;
+ break;
+ }
+
+ sim_clear_rx_buf(sim);
+ sim_set_cwt(sim, 0);
+ sim_set_bwt(sim, 0);
+ /*Flush the tx rx fifo*/
+ sim_flush_fifo(sim, 1, 1);
+ sim->xmt_pos = 0;
+ sim->errval = 0;
+
+ sim_xmt_fill_fifo(sim);
+ sim_set_baud_rate(sim);
+ if (sim->protocol_type == SIM_PROTOCOL_T0)
+ sim_set_nack(sim, 1);
+ else if (sim->protocol_type == SIM_PROTOCOL_T1)
+ sim_set_nack(sim, 0);
+ else {
+ pr_err("Invalid protocol not T0 or T1\n");
+ errval = -EINVAL;
+ break;
+ }
+
+ sim_set_timer_counter(sim);
+ sim_xmt_start(sim);
+ sim->state = SIM_STATE_XMTING;
+
+ sim->timeout = TX_TIMEOUT * HZ;
+ timeout = wait_for_completion_interruptible_timeout(&sim->xfer_done,
+ sim->timeout);
+ if (timeout == 0) {
+ /*Disable the NACK interruptand TX related interrupt*/
+ sim_tx_irq_disable(sim);
+ pr_err("tx timeout\n");
+ }
+
+ if (timeout == 0 || sim->state == SIM_STATE_XMT_ERROR) {
+ pr_err("TX error\n");
+ /*Disable timers*/
+ sim_set_cwt(sim, 0);
+ sim_set_bwt(sim, 0);
+ /*Disable TX*/
+ sim_set_tx(sim, 0);
+ /*Flush the tx fifos*/
+ sim_flush_fifo(sim, 1, 0);
+ if (timeout == 0)
+ errval = -SIM_E_TIMEOUT;
+ else
+ errval = -SIM_E_NACK;
+
+ ret = copy_to_user(&(((sim_atr_t *)arg)->errval), &sim->errval,
+ sizeof(sim->errval));
+ sim->errval = 0;
+ break;
+ }
+
+ /*Copy the error status to user space*/
+ ret = copy_to_user(&(((sim_atr_t *)arg)->errval), &sim->errval,
+ sizeof(sim->errval));
+ sim->last_is_tx = true;
+ /*Start RX*/
+ sim->errval = 0;
+ sim->state = SIM_STATE_RECEIVING;
+ sim_start_rcv(sim);
+
+ break;
+
+ case SIM_IOCTL_RCV:
+ if (sim->present != SIM_PRESENT_DETECTED) {
+ errval = -SIM_E_NOCARD;
+ break;
+ }
+ sim->is_fixed_len_rec = 0;
+ val = 0;
+ ret = copy_from_user(&sim->expected_rcv_cnt, &(((sim_rcv_t *)arg)->rcv_length),
+ sizeof(sim->expected_rcv_cnt));
+
+ /*Set the length to be 0 at first*/
+ ret = copy_to_user(&(((sim_rcv_t *)arg)->rcv_length), &val,
+ sizeof(val));
+
+ /*Set error value to be 0 at first*/
+ ret = copy_to_user(&(((sim_rcv_t *)arg)->errval), &val,
+ sizeof(val));
+
+ if (sim->expected_rcv_cnt != 0)
+ sim->is_fixed_len_rec = 1;
+
+ if (sim->is_fixed_len_rec && sim->rcv_count >= sim->expected_rcv_cnt)
+ goto copy_data;
+
+ if (sim->state != SIM_STATE_RECEIVING) {
+ sim_set_timer_counter(sim);
+ /*Enable CWT BWT*/
+ sim_set_cwt(sim, 1);
+ sim_set_bwt(sim, 1);
+ sim->state = SIM_STATE_RECEIVING;
+ sim_start_rcv(sim);
+ }
+
+ spin_lock_irqsave(&sim->lock, flags);
+ if (sim->is_fixed_len_rec && sim->rcv_count < sim->expected_rcv_cnt)
+ sim_change_rcv_threshold(sim);
+ spin_unlock_irqrestore(&sim->lock, flags);
+ sim->timeout = RX_TIMEOUT * HZ;
+ timeout = wait_for_completion_interruptible_timeout(&sim->xfer_done,
+ sim->timeout);
+
+ if (timeout == 0) {
+ pr_err("Receiving timeout\n");
+ sim_set_cwt(sim, 0);
+ sim_set_bwt(sim, 0);
+ sim_rx_irq_disable(sim);
+ errval = -SIM_E_TIMEOUT;
+ break;
+ }
+
+copy_data:
+ if (sim->is_fixed_len_rec)
+ copy_cnt = sim->rcv_count >= sim->expected_rcv_cnt ? sim->expected_rcv_cnt : sim->rcv_count;
+ else
+ copy_cnt = sim->rcv_count;
+
+ ret = copy_to_user(&(((sim_rcv_t *)arg)->rcv_length), &copy_cnt,
+ sizeof(copy_cnt));
+ if (ret) {
+ pr_err("ATR ACCESS Error\n");
+ errval = -SIM_E_ACCESS;
+ break;
+ }
+
+ __get_user(rcv_buffer, &((sim_rcv_t *)arg)->rcv_buffer);
+ ret = copy_to_user(rcv_buffer, &sim->rcv_buffer[sim->rcv_head], copy_cnt);
+ if (ret) {
+ pr_err("ATR ACCESS Error\n");
+ errval = -SIM_E_ACCESS;
+ break;
+ }
+
+ ret = copy_to_user(&(((sim_rcv_t *)arg)->errval), &sim->errval,
+ sizeof(sim->errval));
+ if (ret) {
+ pr_err("ATR ACCESS Error\n");
+ errval = -SIM_E_ACCESS;
+ break;
+ }
+ /*Reset the receiving count and errval*/
+ spin_lock_irqsave(&sim->lock, flags);
+ sim->rcv_head += copy_cnt;
+ sim->rcv_count -= copy_cnt;
+ sim->errval = 0;
+ spin_unlock_irqrestore(&sim->lock, flags);
+
+ sim->last_is_tx = false;
+
+ break;
+
+ case SIM_IOCTL_SET_PROTOCOL:
+ ret = copy_from_user(&sim->protocol_type, (int *)arg,
+ sizeof(int));
+ if (ret)
+ errval = -SIM_E_ACCESS;
+ break;
+
+ case SIM_IOCTL_SET_TIMING:
+ ret = copy_from_user(&sim->timing_data, (sim_timing_t *)arg,
+ sizeof(sim_timing_t));
+ if (ret) {
+ pr_err("Copy Error\n");
+ errval = ret;
+ break;
+ }
+
+ ret = sim_check_timing_data(&sim->timing_data);
+
+ if (ret)
+ errval = ret;
+
+ break;
+
+ case SIM_IOCTL_SET_BAUD:
+ ret = copy_from_user(&sim->baud_rate, (sim_baud_t *)arg,
+ sizeof(sim_baud_t));
+
+ if (ret) {
+ pr_err("Copy Error\n");
+ errval = ret;
+ break;
+ }
+
+ sim_check_baud_rate(&sim->baud_rate);
+
+ break;
+ case SIM_IOCTL_WAIT:
+ ret = copy_from_user(&delay, (unsigned int *)arg,
+ sizeof(unsigned int));
+
+ if (ret) {
+ pr_err("\nWait Copy Error\n");
+ errval = ret;
+ break;
+ }
+
+ sim_polling_delay(sim, delay);
+ break;
+
+ case SIM_IOCTL_GET_PRESENSE:
+ if (put_user(sim->present, (int *)arg))
+ errval = -SIM_E_ACCESS;
+ break;
+
+ case SIM_IOCTL_CARD_LOCK:
+ errval = sim_card_lock(sim);
+ break;
+
+ case SIM_IOCTL_CARD_EJECT:
+ errval = sim_card_eject(sim);
+ break;
+
+ };
+
+ return errval;
+};
+
+static int sim_open(struct inode *inode, struct file *file)
+{
+ int errval = SIM_OK;
+ struct sim_t *sim = dev_get_drvdata(sim_dev.parent);
+
+ file->private_data = sim;
+ spin_lock_init(&sim->lock);
+
+ pr_debug("%s entering.\n", __func__);
+ if (!sim->ioaddr) {
+ errval = -ENOMEM;
+ return errval;
+ }
+
+ if (!sim->open_cnt)
+ clk_prepare_enable(sim->clk);
+
+ sim->open_cnt = 1;
+
+ errval = sim_reset_module(sim);
+ sim_data_reset(sim);
+
+ return errval;
+};
+
+static int sim_release(struct inode *inode, struct file *file)
+{
+ u32 reg_data;
+ struct sim_t *sim = (struct sim_t *) file->private_data;
+
+ /* disable presense detection */
+ reg_data = __raw_readl(sim->ioaddr + sim->port_detect_reg);
+ __raw_writel(reg_data | SIM_PORT_DETECT_SDIM,
+ sim->ioaddr + sim->port_detect_reg);
+
+ if (sim->present != SIM_PRESENT_REMOVED)
+ sim_deactivate(sim);
+
+
+ if (sim->open_cnt)
+ clk_disable_unprepare(sim->clk);
+
+ sim->open_cnt = 0;
+
+ return 0;
+};
+
+static const struct file_operations sim_fops = {
+ .owner = THIS_MODULE,
+ .open = sim_open,
+ .release = sim_release,
+ .unlocked_ioctl = sim_ioctl,
+};
+
+static struct miscdevice sim_dev = {
+ MISC_DYNAMIC_MINOR,
+ "mxc_sim",
+ &sim_fops
+};
+
+static struct platform_device_id imx_sim_devtype[] = {
+ {
+ .name = "imx7d-sim",
+ .driver_data = 0,
+ }, {
+ .name = "imx6ul-sim",
+ .driver_data = SIM_QUIRK_TKT259347,
+ }, {
+ /* sentinel */
+ }
+};
+
+enum imx_sim_type {
+ IMX7D_SIM = 0,
+ IMX6UL_SIM,
+};
+
+static const struct of_device_id sim_imx_dt_ids[] = {
+ { .compatible = "fsl,imx7d-sim",
+ .data = &imx_sim_devtype[IMX7D_SIM], },
+ { .compatible = "fsl,imx6ul-sim",
+ .data = &imx_sim_devtype[IMX6UL_SIM], },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, sim_imx_dt_ids);
+
+static int sim_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ const struct of_device_id *of_id;
+ struct sim_t *sim = NULL;
+ struct device_node *of_node = pdev->dev.of_node;
+
+ sim = devm_kzalloc(&pdev->dev, sizeof(struct sim_t),
+ GFP_KERNEL);
+ if (!sim) {
+ dev_err(&pdev->dev, "can't allocate enough memory\n");
+ return -ENOMEM;
+ }
+
+
+ of_id = of_match_device(sim_imx_dt_ids, &pdev->dev);
+ if (of_id)
+ pdev->id_entry = of_id->data;
+ else
+ return -EINVAL;
+
+ sim->clk_rate = FCLK_FREQ;
+ sim->open_cnt = 0;
+
+ sim->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!sim->res) {
+ pr_err("Can't get the MEMORY\n");
+ return -ENOMEM;
+ }
+ sim->ioaddr = devm_ioremap_resource(&pdev->dev, sim->res);
+ dev_dbg(&pdev->dev, "mapped base address: 0x%08x\n", (u32)sim->ioaddr);
+ if (IS_ERR(sim->ioaddr)) {
+ dev_err(&pdev->dev,
+ "failed to get ioremap base\n");
+ ret = PTR_ERR(sim->ioaddr);
+ return ret;
+ }
+
+ /* request the sim clk and sim_serial_clk */
+ sim->clk = devm_clk_get(&pdev->dev, "sim");
+ if (IS_ERR(sim->clk)) {
+ ret = PTR_ERR(sim->clk);
+ pr_err("Get CLK ERROR !\n");
+ return ret;
+ }
+ pr_debug("sim clock:%lu\n", clk_get_rate(sim->clk));
+
+ sim->ipb_irq = platform_get_irq(pdev, 0);
+ if (sim->ipb_irq < 0) {
+ dev_err(&pdev->dev, "No ipb irq line provided\n");
+ return -ENOENT;
+ }
+ if (devm_request_irq(&pdev->dev, sim->ipb_irq, sim_irq_handler,
+ 0, "mxc_sim_ipb", sim)) {
+ dev_err(&pdev->dev, "can't claim irq %d\n", sim->ipb_irq);
+ return -ENOENT;
+ }
+
+ sim->sven_low_active = of_property_read_bool(of_node,
+ "sven_low_active");
+
+ ret = of_property_read_u32(of_node, "port", &sim->port_index);
+ if (ret)
+ sim->port_index = 0;
+ sim->port_ctrl_reg = (sim->port_index == 0) ?
+ PORT0_CNTL : PORT1_CNTL;
+ sim->port_detect_reg = (sim->port_index == 0) ?
+ PORT0_DETECT : PORT1_DETECT;
+ sim->quirks = pdev->id_entry->driver_data;
+
+ platform_set_drvdata(pdev, sim);
+
+ /*
+ *@todo: Need to figure a better way if possible.
+ */
+ sim_dev.parent = &(pdev->dev);
+
+ misc_register(&sim_dev);
+
+ return 0;
+}
+
+static int sim_remove(struct platform_device *pdev)
+{
+ struct sim_t *sim = platform_get_drvdata(pdev);
+
+ if (sim->open_cnt)
+ clk_disable_unprepare(sim->clk);
+
+ misc_deregister(&sim_dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int sim_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct sim_t *sim = platform_get_drvdata(pdev);
+
+ if (sim->open_cnt)
+ clk_disable_unprepare(sim->clk);
+
+ pinctrl_pm_select_sleep_state(&pdev->dev);
+
+ return 0;
+}
+
+static int sim_resume(struct platform_device *pdev)
+{
+ struct sim_t *sim = platform_get_drvdata(pdev);
+
+ if (sim->open_cnt)
+ clk_prepare_enable(sim->clk);
+
+ pinctrl_pm_select_default_state(&pdev->dev);
+
+ return 0;
+}
+#else
+#define sim_suspend NULL
+#define sim_resume NULL
+#endif
+
+static struct platform_driver sim_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = sim_imx_dt_ids,
+ },
+ .probe = sim_probe,
+ .remove = sim_remove,
+ .suspend = sim_suspend,
+ .resume = sim_resume,
+ .id_table = imx_sim_devtype,
+};
+
+static int __init sim_drv_init(void)
+{
+ return platform_driver_register(&sim_driver);
+}
+
+static void __exit sim_drv_exit(void)
+{
+ platform_driver_unregister(&sim_driver);
+}
+
+module_init(sim_drv_init);
+module_exit(sim_drv_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC SIM Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/mxc/vpu-decoder-b0/Kconfig b/drivers/mxc/vpu-decoder-b0/Kconfig
new file mode 100755
index 000000000000..094d6566a421
--- /dev/null
+++ b/drivers/mxc/vpu-decoder-b0/Kconfig
@@ -0,0 +1,20 @@
+#
+# Codec configuration
+#
+
+menu "MXC VPU(Video Processing Unit) B0 DECODER support"
+
+config MXC_VPU_DECODER
+ tristate "Support for MXC VPU(Video Processing Unit) DECODER"
+ default y
+ ---help---
+ The VPU codec device provides codec function for H.265 H.264 MPEG2 MPEG4 etc.
+
+config MXC_VPU_DECODER_DEBUG
+ bool "MXC VPU DECODER debugging"
+ depends on MXC_VPU_DECODER != n
+ help
+ This is an option for the developers; most people should
+ say N here. This enables MXC VPU driver debugging.
+
+endmenu
diff --git a/drivers/mxc/vpu-decoder-b0/Makefile b/drivers/mxc/vpu-decoder-b0/Makefile
new file mode 100644
index 000000000000..fc4c91ab4061
--- /dev/null
+++ b/drivers/mxc/vpu-decoder-b0/Makefile
@@ -0,0 +1,15 @@
+##
+## Makefile for the VPU and M0 driver
+##
+DEFINES += -D REBOOT=1 \
+ -D BOOT_ARCH=1
+
+EXTRA_CFLAGS += $(DEFINES)
+
+obj-y = vpu-decoder.o
+vpu-decoder-objs = vpu_b0.o \
+ vpu_rpc.o \
+ insert_startcode.o
+
+clean:
+ rm -rf $(vpu-decoder-objs)
diff --git a/drivers/mxc/vpu-decoder-b0/insert_startcode.c b/drivers/mxc/vpu-decoder-b0/insert_startcode.c
new file mode 100644
index 000000000000..dc2825b63e09
--- /dev/null
+++ b/drivers/mxc/vpu-decoder-b0/insert_startcode.c
@@ -0,0 +1,546 @@
+/*
+ * Copyright 2018 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file insert_startcode.c
+ *
+ * copyright here may be changed later
+ *
+ *
+ */
+#include "insert_startcode.h"
+// Global VC1 ID and version
+u_int32 uVC1CodecID = 0x10; // Simple = 0x10, Main = 0x11
+u_int32 uVC1VersionID = 1;
+
+static int insert_RCV_seqhdr(unsigned char *pHeader, u_int32 *pHeaderLen, unsigned char *src,
+ u_int32 nFrameSize, u_int32 nWidth, u_int32 nHeight, int *pNoError)
+{
+ int nHeaderLen;
+
+ unsigned int nValue;
+ unsigned int HdrExtDataLen;
+ int i = 0;
+ int profile;
+
+ nHeaderLen = RCV_HEADER_LEN;
+
+ //Number of Frames, Header Extension Bit, Codec Version
+ nValue = RCV_NUM_FRAMES | RCV_SET_HDR_EXT | RCV_CODEC_VERSION;
+ pHeader[i++] = (unsigned char)nValue;
+ pHeader[i++] = (unsigned char)(nValue >> 8);
+ pHeader[i++] = (unsigned char)(nValue >> 16);
+#if 0 //1 ???
+ pHeader[i++] = 0xC5;
+#else
+ pHeader[i++] = (unsigned char)(nValue >> 24);
+#endif
+
+ //Header Extension Size
+ //ASF Parser gives 5 bytes whereas the VPU expects only 4 bytes, so limiting it
+ HdrExtDataLen = 4;
+ pHeader[i++] = (unsigned char)HdrExtDataLen;
+ pHeader[i++] = (unsigned char)(HdrExtDataLen >> 8);
+ pHeader[i++] = (unsigned char)(HdrExtDataLen >> 16);
+ pHeader[i++] = (unsigned char)(HdrExtDataLen >> 24);
+
+ profile = (*src)>>4;
+ if ((profile != 0) && (profile != 4) && (profile != 12)) {
+ //it is reasonable to return error immediately since only one sequence header inserted in whole rcv clip
+ *pNoError = 0;
+ }
+ memcpy(pHeader+i, src, HdrExtDataLen);
+ i += HdrExtDataLen;
+
+ //Height
+ pHeader[i++] = (unsigned char)nHeight;
+ pHeader[i++] = (unsigned char)(((nHeight >> 8) & 0xff));
+ pHeader[i++] = (unsigned char)(((nHeight >> 16) & 0xff));
+ pHeader[i++] = (unsigned char)(((nHeight >> 24) & 0xff));
+ //Width
+ pHeader[i++] = (unsigned char)nWidth;
+ pHeader[i++] = (unsigned char)(((nWidth >> 8) & 0xff));
+ pHeader[i++] = (unsigned char)(((nWidth >> 16) & 0xff));
+ pHeader[i++] = (unsigned char)(((nWidth >> 24) & 0xff));
+
+ //Frame Size
+ pHeader[i++] = (unsigned char)nFrameSize;
+ pHeader[i++] = (unsigned char)(nFrameSize >> 8);
+ pHeader[i++] = (unsigned char)(nFrameSize >> 16);
+#if 0 //1 ???
+ pHeader[i++] = (unsigned char)((nFrameSize >> 24));
+#else
+ pHeader[i++] = (unsigned char)((nFrameSize >> 24) | 0x80);
+#endif
+
+ *pHeaderLen = nHeaderLen;
+
+ return 1;
+}
+
+static int insert_RCV_pichdr(unsigned char *pHeader, int *pHeaderLen, unsigned int nInSize)
+{
+ pHeader[0] = (unsigned char)nInSize;
+ pHeader[1] = (unsigned char)(nInSize >> 8);
+ pHeader[2] = (unsigned char)(nInSize >> 16);
+ pHeader[3] = (unsigned char)(nInSize >> 24);
+ *pHeaderLen = 4;
+
+ return 1;
+}
+
+/*
+ * Byte 0-3: Startcode
+ * Byte 4: Payload length bits[23:16]
+ * Byte 5: Payload length bits[15:8]
+ * Byte 6: 0x4e
+ * Byte 7: Payload length bits[7:0]
+ * Byte 8: Codec ID Non-zero
+ * Byte 9: Codec Version ID Non-zero
+ * Byte 10: Picture Width bits[15:8]
+ * Byte 11: Picture Width bits[7:0]
+ * Byte 12: 0x58
+ * Byte 13: Picture Height bits[15:8]
+ * Byte 14: Picture Height bits[7:0]
+ * Byte 15: 0x50
+ */
+
+static void insert_payload_header_vc1(u_int8 *dst, u_int32 uScodeType, u_int32 uPayloadSize, u_int32 uWidth, u_int32 uHeight)
+{
+ // Startcode
+ dst[0] = 0x00;
+ dst[1] = 0x00;
+ dst[2] = 0x01;
+ dst[3] = uScodeType;
+
+ // Length
+ dst[4] = ((uPayloadSize>>16)&0xff);
+ dst[5] = ((uPayloadSize>>8)&0xff);
+ dst[6] = 0x4e;
+ dst[7] = ((uPayloadSize>>0)&0xff);
+
+ // Codec ID and Version
+ dst[8] = uVC1CodecID;
+ dst[9] = uVC1VersionID;
+
+ // Width
+ dst[10] = ((uWidth>>8)&0xff);
+ dst[11] = ((uWidth>>0)&0xff);
+ dst[12] = 0x58;
+
+ // Height
+ dst[13] = ((uHeight>>8)&0xff);
+ dst[14] = ((uHeight>>0)&0xff);
+ dst[15] = 0x50;
+}
+
+static int VC1CreateNALSeqHeader(unsigned char *pHeader, int *pHeaderLen,
+ unsigned char *pCodecPri, int nCodecSize, unsigned int *pData, int nMaxHeader)
+{
+ int nHeaderLen;
+ unsigned char temp[4] = {0x00, 0x00, 0x01, 0x0D};
+
+ nHeaderLen = nCodecSize - 1;
+ if ((4+nHeaderLen) > nMaxHeader) {
+ nHeaderLen = nMaxHeader - 4;
+ vpu_dbg(LVL_ERR, "error: header length %d overrun !!! \r\n", nCodecSize);
+ }
+ memcpy(pHeader, pCodecPri+1, nHeaderLen);
+
+ if (VC1_IS_NOT_NAL(pData[0])) {
+ //insert 0x0000010D at the end of header
+ memcpy(pHeader+nHeaderLen, temp, 4);
+ nHeaderLen += 4;
+ }
+
+ *pHeaderLen = nHeaderLen;
+
+ return 1;
+}
+
+static int VC1CreateNalFrameHeader(unsigned char *pHeader, int *pHeaderLen, unsigned int *pInData)
+{
+ unsigned int VC1Id;
+
+ VC1Id = *pInData;
+ if (VC1_IS_NOT_NAL(VC1Id)) {
+ //need insert header : special ID
+ pHeader[0] = 0x0;
+ pHeader[1] = 0x0;
+ pHeader[2] = 0x01;
+ pHeader[3] = 0x0D;
+ *pHeaderLen = 4;
+ } else {
+ //need not insert header
+ //do nothing
+ *pHeaderLen = 0;
+ }
+
+ return 1;
+}
+
+void vp6_scd_sequence_header(unsigned char *buffer, int pic_width, int pic_height)
+{
+ int Length = 0;
+
+ buffer[0] = 0x00;
+ buffer[1] = 0x00;
+ buffer[2] = 0x01;
+ buffer[3] = 0x31;
+ buffer[4] = (Length+12)>>16;
+ buffer[5] = (Length+12)>>8;
+ buffer[6] = 0x4e;
+ buffer[7] = (Length+12);
+ buffer[8] = 0x36;
+ buffer[9] = 0x1;
+ buffer[10] = pic_width>>8;
+ buffer[11] = pic_width;
+ buffer[12] = 0x58;
+ buffer[13] = pic_height>>8;
+ buffer[14] = pic_height;
+ buffer[15] = 0x50;
+}
+
+void vp6_scd_frame_header(unsigned char *buffer, int pic_width, int pic_height, int Length)
+{
+ buffer[0] = 0x00;
+ buffer[1] = 0x00;
+ buffer[2] = 0x01;
+ buffer[3] = 0x32;
+ buffer[4] = (Length+12)>>16;
+ buffer[5] = (Length+12)>>8;
+ buffer[6] = 0x4e;
+ buffer[7] = (Length+12);
+ buffer[8] = 0x36;
+ buffer[9] = 0x1;
+ buffer[10] = pic_width>>8;
+ buffer[11] = pic_width;
+ buffer[12] = 0x58;
+ buffer[13] = pic_height>>8;
+ buffer[14] = pic_height;
+ buffer[15] = 0x50;
+}
+
+void vp8_ivf_sequence_header(unsigned char *buffer, int pic_width, int pic_height)
+{
+ int Length = 32;
+
+ buffer[0] = 0x44;
+ buffer[1] = 0x4b;
+ buffer[2] = 0x49;
+ buffer[3] = 0x46; //0-3byte signature "DKIF"
+ buffer[4] = 0x00;
+ buffer[5] = 0x00; //4-5byte version 0
+ buffer[6] = Length;
+ buffer[7] = Length >> 8; //length of Header
+ buffer[8] = 0x56;
+ buffer[9] = 0x50;
+ buffer[10] = 0x38;
+ buffer[11] = 0x30; //VP8 fourcc
+ buffer[12] = pic_width;
+ buffer[13] = pic_width >> 8;
+ buffer[14] = pic_height;
+ buffer[15] = pic_height >> 8;
+ buffer[16] = 0xe8;
+ buffer[17] = 0x03;
+ buffer[18] = 0x00;
+ buffer[19] = 0x00; //16-19 frame rate
+ buffer[20] = 0x01;
+ buffer[21] = 0x00;
+ buffer[22] = 0x00;
+ buffer[23] = 0x00; //20-23 time scale
+ buffer[24] = 0xdf;
+ buffer[25] = 0xf9;
+ buffer[26] = 0x09;
+ buffer[27] = 0x00; //24-27 number frames
+ //28-31 unused
+}
+
+void vp8_ivf_frame_header(unsigned char *buffer, u_int32 FrameSize)
+{
+ buffer[0] = FrameSize;
+ buffer[1] = FrameSize >> 8;
+ buffer[2] = FrameSize >> 16;
+ buffer[3] = FrameSize >> 24;
+ //4-11 timestamp
+}
+
+void vp8_scd_sequence_header(unsigned char *buffer, int pic_width, int pic_height)
+{
+ int Length = 32;
+
+ buffer[0] = 0x00;
+ buffer[1] = 0x00;
+ buffer[2] = 0x01;
+ buffer[3] = 0x31;
+ buffer[4] = (Length+12)>>16;
+ buffer[5] = (Length+12)>>8;
+ buffer[6] = 0x4e;
+ buffer[7] = (Length+12);
+ buffer[8] = 0x36;
+ buffer[9] = 0x1;
+ buffer[10] = pic_width>>8;
+ buffer[11] = pic_width;
+ buffer[12] = 0x58;
+ buffer[13] = pic_height>>8;
+ buffer[14] = pic_height;
+ buffer[15] = 0x50;
+}
+void vp8_scd_frame_header(unsigned char *buffer, int pic_width, int pic_height, int Length)
+{
+ buffer[0] = 0x00;
+ buffer[1] = 0x00;
+ buffer[2] = 0x01;
+ buffer[3] = 0x32;
+ buffer[4] = (Length+12)>>16;
+ buffer[5] = (Length+12)>>8;
+ buffer[6] = 0x4e;
+ buffer[7] = (Length+12);
+ buffer[8] = 0x36;
+ buffer[9] = 0x1;
+ buffer[10] = pic_width>>8;
+ buffer[11] = pic_width;
+ buffer[12] = 0x58;
+ buffer[13] = pic_height>>8;
+ buffer[14] = pic_height;
+ buffer[15] = 0x50;
+}
+
+static void insert_payload_header_divx(u_int8 *dst, u_int32 uPayloadSize, u_int32 uWidth, u_int32 uHeight)
+{
+ // Startcode
+ dst[0] = 0x00;
+ dst[1] = 0x00;
+ dst[2] = 0x01;
+ dst[3] = 0x32;
+
+ // Length
+ dst[4] = ((uPayloadSize>>16)&0xff);
+ dst[5] = ((uPayloadSize>>8)&0xff);
+ dst[6] = 0x4e;
+ dst[7] = ((uPayloadSize>>0)&0xff);
+
+ // Codec ID and Version
+ dst[8] = 0x38;
+ dst[9] = 0x01;
+
+ // Width
+ dst[10] = ((uWidth>>8)&0xff);
+ dst[11] = ((uWidth>>0)&0xff);
+ dst[12] = 0x58;
+
+ // Height
+ dst[13] = ((uHeight>>8)&0xff);
+ dst[14] = ((uHeight>>0)&0xff);
+ dst[15] = 0x50;
+}
+
+static void insert_seq_header_spk(u_int8 *dst, u_int32 uPayloadSize, u_int32 uWidth, u_int32 uHeight)
+{
+ // Startcode
+ dst[0] = 0x00;
+ dst[1] = 0x00;
+ dst[2] = 0x01;
+ dst[3] = 0x31;
+
+ // Length
+ dst[4] = ((uPayloadSize>>16)&0xff);
+ dst[5] = ((uPayloadSize>>8)&0xff);
+ dst[6] = 0x4e;
+ dst[7] = ((uPayloadSize>>0)&0xff);
+
+ // Codec ID and Version
+ dst[8] = 0x39;
+ dst[9] = 0x01;
+
+ // Width
+ dst[10] = ((uWidth>>8)&0xff);
+ dst[11] = ((uWidth>>0)&0xff);
+ dst[12] = 0x58;
+
+ // Height
+ dst[13] = ((uHeight>>8)&0xff);
+ dst[14] = ((uHeight>>0)&0xff);
+ dst[15] = 0x50;
+}
+
+static void insert_frame_header_spk(u_int8 *dst, u_int32 uPayloadSize, u_int32 uWidth, u_int32 uHeight)
+{
+ uPayloadSize = 0;
+ // Startcode
+ dst[0] = 0x00;
+ dst[1] = 0x00;
+ dst[2] = 0x01;
+ dst[3] = 0x32;
+
+ // Length
+ dst[4] = ((uPayloadSize>>16)&0xff);
+ dst[5] = ((uPayloadSize>>8)&0xff);
+ dst[6] = 0x4e;
+ dst[7] = ((uPayloadSize>>0)&0xff);
+
+ // Codec ID and Version
+ dst[8] = 0x39;
+ dst[9] = 0x01;
+
+ // Width
+ dst[10] = ((uWidth>>8)&0xff);
+ dst[11] = ((uWidth>>0)&0xff);
+ dst[12] = 0x58;
+
+ // Height
+ dst[13] = ((uHeight>>8)&0xff);
+ dst[14] = ((uHeight>>0)&0xff);
+ dst[15] = 0x50;
+}
+
+u_int32 insert_scode_4_seq(struct vpu_ctx *ctx, u_int8 *src, u_int8 *dst, u_int32 vdec_std, u_int32 uPayloadSize)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ u_int32 length = 0;
+
+ switch (vdec_std) {
+ case VPU_VIDEO_VC1: {
+ if (q_data->fourcc == V4L2_PIX_FMT_VC1_ANNEX_G) {
+ u_int8 Header[VC1_MAX_SEQ_HEADER_SIZE];
+ u_int32 uWidth = q_data->width;
+ u_int32 uHeight = q_data->height; //Width & Height in the generic payload header are ignored
+ u_int32 FrameSize = 0x60;
+ u_int32 HeaderLen, NoError = 1;
+ //insert startcode for vc1
+ insert_payload_header_vc1(dst, VC1_SCODE_NEW_SEQUENCE, 20, uWidth, uHeight);
+ length = 16;
+ //insert RCV sequence header for vc1 v1, length=20
+ insert_RCV_seqhdr(Header, &HeaderLen, src, FrameSize, uWidth, uHeight, &NoError);
+ HeaderLen = RCV_HEADER_LEN - 4;
+ memcpy(dst + 16, Header, HeaderLen);
+ length += HeaderLen;
+ } else {
+ u_int8 Header[VC1_MAX_SEQ_HEADER_SIZE];
+ u_int32 HeaderLen;
+
+ VC1CreateNALSeqHeader(Header, &HeaderLen, src, uPayloadSize,
+ (unsigned int *)src, VC1_MAX_SEQ_HEADER_SIZE);
+ if (VC1_IS_NOT_NAL(((unsigned int *)src)[0]))
+ HeaderLen -= 4;
+ memcpy(dst, Header, HeaderLen);
+ length += HeaderLen;
+ }
+ }
+
+ break;
+ case VPU_VIDEO_VP6: {
+ vp6_scd_sequence_header(dst, q_data->width, q_data->height);
+ length = 16;
+ }
+ break;
+ case VPU_VIDEO_VP8: {
+ u_int8 seq_header[32] = {0};
+ u_int8 frame_header[8] = {0};
+
+ vp8_scd_sequence_header(dst, q_data->width, q_data->height);
+ length = 16;
+ vp8_ivf_sequence_header(seq_header, q_data->width, q_data->height);
+ memcpy(dst+length, seq_header, 32);
+ length += 32;
+ vp8_scd_frame_header(dst + length, q_data->width, q_data->height, uPayloadSize);
+ length += 16;
+ vp8_ivf_frame_header(frame_header, uPayloadSize);
+ memcpy(dst+length, frame_header, 8);
+ length += 8;
+ memcpy(dst+length, src, uPayloadSize);
+ length += uPayloadSize;
+ }
+ break;
+ case VPU_VIDEO_ASP: {
+ if (q_data->fourcc == VPU_PIX_FMT_DIVX) {
+ insert_payload_header_divx(dst, uPayloadSize, q_data->width, q_data->height);
+ length = 16;
+ memcpy(dst+length, src, uPayloadSize);
+ length += uPayloadSize;
+ }
+ }
+ break;
+ case VPU_VIDEO_SPK: {
+ insert_seq_header_spk(dst, uPayloadSize, q_data->width, q_data->height);
+ length = 16;
+ }
+ break;
+ default:
+ break;
+ }
+ return length;
+}
+
+u_int32 insert_scode_4_pic(struct vpu_ctx *ctx, u_int8 *dst, u_int8 *src, u_int32 vdec_std, u_int32 uPayloadSize)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ u_int32 length = 0;
+
+ switch (vdec_std) {
+ case VPU_VIDEO_VC1: {
+ if (q_data->fourcc == V4L2_PIX_FMT_VC1_ANNEX_G) {
+ u_int8 Header[VC1_MAX_FRM_HEADER_SIZE];
+ u_int32 HeaderLen;
+ u_int32 uWidth = q_data->width;
+ u_int32 uHeight = q_data->height; //Width & Height in the generic payload header are ignored
+
+ insert_payload_header_vc1(dst, VC1_SCODE_NEW_PICTURE, uPayloadSize + 4, uWidth, uHeight);
+ insert_RCV_pichdr(Header, &HeaderLen, uPayloadSize);
+ memcpy(dst+16, Header, 4);
+ length = 16 + 4;
+ } else {
+ u_int8 Header[VC1_MAX_FRM_HEADER_SIZE];
+ u_int32 HeaderLen;
+
+ VC1CreateNalFrameHeader(Header, (int *)(&HeaderLen), (unsigned int *)(src));
+ memcpy(dst, Header, HeaderLen);
+ length = HeaderLen;
+ }
+ }
+ break;
+ case VPU_VIDEO_VP6: {
+ vp6_scd_frame_header(dst, q_data->width, q_data->height, uPayloadSize);
+ length = 16;
+ }
+ break;
+ case VPU_VIDEO_VP8: {
+ u_int8 frame_header[8];
+
+ vp8_scd_frame_header(dst, q_data->width, q_data->height, uPayloadSize);
+ length = 16;
+ vp8_ivf_frame_header(frame_header, uPayloadSize);
+ memcpy(dst+length, frame_header, 8);
+ length += 8;
+ }
+ break;
+ case VPU_VIDEO_ASP: {
+ if (q_data->fourcc == VPU_PIX_FMT_DIVX) {
+ insert_payload_header_divx(dst, uPayloadSize, q_data->width, q_data->height);
+ length = 16;
+ }
+ }
+ break;
+ case VPU_VIDEO_SPK: {
+ insert_frame_header_spk(dst, uPayloadSize, q_data->width, q_data->height);
+ length = 16;
+ }
+ break;
+ default:
+ break;
+ }
+ return length;
+}
+
+
+
diff --git a/drivers/mxc/vpu-decoder-b0/insert_startcode.h b/drivers/mxc/vpu-decoder-b0/insert_startcode.h
new file mode 100644
index 000000000000..56d023f9e66c
--- /dev/null
+++ b/drivers/mxc/vpu-decoder-b0/insert_startcode.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2018 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file insert_startcode.h
+ *
+ */
+#ifndef __INSERT_STARTCODE_H__
+#define __INSERT_STARTCODE_H__
+
+#include "vpu_b0.h"
+#include "mediasys_types.h"
+// Startcode insertion types for VC1
+#define VC1_SCODE_NEW_SEQUENCE 0x31
+#define VC1_SCODE_NEW_PICTURE 0x32
+#define VC1_SCODE_NEW_SLICE 0x33
+#define RCV_V2_FRAMESIZE_FLAGS (0xFF000000)
+#define RCV_HEADER_LEN 24
+#define RCV_CODEC_VERSION (0x5 << 24) //FOURCC_WMV3_WMV
+#define RCV_NUM_FRAMES 0xFF
+#define RCV_SET_HDR_EXT 0x80000000
+#define VC1_IS_NOT_NAL(id) ((id & 0x00FFFFFF) != 0x00010000)
+#define VC1_MAX_FRM_HEADER_SIZE 32
+#define VC1_MAX_SEQ_HEADER_SIZE 256
+
+u_int32 insert_scode_4_pic(struct vpu_ctx *ctx, u_int8 *dst, u_int8 *src, u_int32 vdec_std, u_int32 uPayloadSize);
+u_int32 insert_scode_4_seq(struct vpu_ctx *ctx, u_int8 *src, u_int8 *dst, u_int32 vdec_std, u_int32 uPayloadSize);
+
+#endif
diff --git a/drivers/mxc/vpu-decoder-b0/mediasys_types.h b/drivers/mxc/vpu-decoder-b0/mediasys_types.h
new file mode 100644
index 000000000000..aae9fe59bfab
--- /dev/null
+++ b/drivers/mxc/vpu-decoder-b0/mediasys_types.h
@@ -0,0 +1,773 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MEDIASYS_TYPES_H_
+#define _MEDIASYS_TYPES_H_
+
+typedef unsigned int u_int32;
+typedef unsigned char u_int8;
+typedef unsigned long u_int64;
+typedef unsigned int BOOL;
+#define FALSE 0
+#define TRUE 1
+#define VPU_MAX_NUM_STREAMS 3
+#define VID_API_NUM_STREAMS 4
+#define VID_API_MAX_BUF_PER_STR 3
+#define VID_API_MAX_NUM_MVC_VIEWS 4
+#define MEDIAIP_MAX_NUM_MALONES 2
+#define MEDIAIP_MAX_NUM_MALONE_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_WINDSORS 1
+#define MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_CMD_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_MSG_IRQ_PINS 1
+#define MEDIAIP_MAX_NUM_TIMER_IRQ_PINS 4
+#define MEDIAIP_MAX_NUM_TIMER_IRQ_SLOTS 4
+#define VID_API_COMMAND_LIMIT 64
+#define VID_API_MESSAGE_LIMIT 256
+
+#define API_CMD_AVAILABLE 0x0
+#define API_CMD_INCOMPLETE 0x1
+#define API_CMD_BUFFER_ERROR 0x2
+#define API_CMD_UNAVAILABLE 0x3
+#define API_MSG_AVAILABLE 0x0
+#define API_MSG_INCOMPLETE 0x1
+#define API_MSG_BUFFER_ERROR 0x2
+#define API_MSG_UNAVAILABLE 0x3
+
+typedef enum {
+ FRAME_ALLOC = 0,
+ FRAME_FREE,
+ FRAME_DECODED,
+ FRAME_READY,
+ FRAME_RELEASE,
+} FRAME_BUFFER_STAT;
+
+typedef enum {
+ VPU_APP,
+ VPU_DRIVER,
+ VPU_DECODER,
+} FRAME_BUFFER_OWNER;
+
+typedef enum {
+ MEDIAIP_FRAME_REQ = 0,
+ MEDIAIP_MBI_REQ,
+ MEDIAIP_DCP_REQ,
+ MEDIAIP_REQ_LAST = MEDIAIP_DCP_REQ
+
+} MEDIAIP_MEM_REQ;
+
+typedef struct {
+ u_int32 uNum;
+ MEDIAIP_MEM_REQ eType;
+} MEDIA_PLAYER_FSREQ;
+
+typedef struct {
+ u_int32 uFSIdx;
+ MEDIAIP_MEM_REQ eType;
+ BOOL bNotDisplayed;
+} MEDIA_PLAYER_FSREL;
+
+typedef enum {
+ /* Non-Stream Specific messages */
+ MEDIA_PLAYER_API_MODE_INVALID = 0x00,
+ MEDIA_PLAYER_API_MODE_PARSE_STEP = 0x01,
+ MEDIA_PLAYER_API_MODE_DECODE_STEP = 0x02,
+ MEDIA_PLAYER_API_MODE_CONTINUOUS = 0x03
+} MEDIA_PLAYER_API_MODE;
+
+typedef enum {
+ /* Non-Stream Specific messages */
+ MEDIA_PLAYER_FS_CTRL_MODE_INTERNAL = 0x00,
+ MEDIA_PLAYER_FS_CTRL_MODE_EXTERNAL = 0x01
+} MEDIA_PLAYER_FS_CTRL_MODE;
+
+typedef enum {
+ /* Non-Stream Specific messages */
+ VID_API_CMD_NULL = 0x00,
+ VID_API_CMD_PARSE_NEXT_SEQ = 0x01,
+ VID_API_CMD_PARSE_NEXT_I = 0x02,
+ VID_API_CMD_PARSE_NEXT_IP = 0x03,
+ VID_API_CMD_PARSE_NEXT_ANY = 0x04,
+ VID_API_CMD_DEC_PIC = 0x05,
+ VID_API_CMD_UPDATE_ES_WR_PTR = 0x06,
+ VID_API_CMD_UPDATE_ES_RD_PTR = 0x07,
+ VID_API_CMD_UPDATE_UDATA = 0x08,
+ VID_API_CMD_GET_FSINFO = 0x09,
+ VID_API_CMD_SKIP_PIC = 0x0a,
+ VID_API_CMD_DEC_CHUNK = 0x0b,
+ VID_API_CMD_START = 0x10,
+ VID_API_CMD_STOP = 0x11,
+ VID_API_CMD_ABORT = 0x12,
+ VID_API_CMD_RST_BUF = 0x13,
+ VID_API_CMD_FS_RELEASE = 0x15,
+ VID_API_CMD_MEM_REGION_ATTACH = 0x16,
+ VID_API_CMD_MEM_REGION_DETACH = 0x17,
+ VID_API_CMD_MVC_VIEW_SELECT = 0x18,
+ VID_API_CMD_FS_ALLOC = 0x19,
+ VID_API_CMD_DBG_GET_STATUS = 0x1C,
+ VID_API_CMD_DBG_START_LOG = 0x1D,
+ VID_API_CMD_DBG_STOP_LOG = 0x1E,
+ VID_API_CMD_DBG_DUMP_LOG = 0x1F,
+ /* Begin Encode CMDs */
+ VID_API_CMD_YUV_READY = 0x20,
+#if BOOT_ARCH == REBOOT
+ VID_API_CMD_SNAPSHOT = 0xAA,
+ VID_API_CMD_ROLL_SNAPSHOT = 0xAB,
+ VID_API_CMD_LOCK_SCHEDULER = 0xAC,
+ VID_API_CMD_UNLOCK_SCHEDULER = 0xAD,
+#endif
+ VID_API_CMD_CQ_FIFO_DUMP = 0xAE,
+ VID_API_CMD_DBG_FIFO_DUMP = 0xAF,
+ VID_API_CMD_SVC_ILP = 0xBB,
+ VID_API_CMD_INVALID = 0xFF
+
+} TB_API_DEC_CMD;
+
+typedef enum {
+ /* Non-Stream Specific messages */
+ VID_API_EVENT_NULL = 0x00,
+ VID_API_EVENT_RESET_DONE = 0x01,
+ VID_API_EVENT_SEQ_HDR_FOUND = 0x02,
+ VID_API_EVENT_PIC_HDR_FOUND = 0x03,
+ VID_API_EVENT_PIC_DECODED = 0x04,
+ VID_API_EVENT_FIFO_LOW = 0x05,
+ VID_API_EVENT_FIFO_HIGH = 0x06,
+ VID_API_EVENT_FIFO_EMPTY = 0x07,
+ VID_API_EVENT_FIFO_FULL = 0x08,
+ VID_API_EVENT_BS_ERROR = 0x09,
+ VID_API_EVENT_UDATA_FIFO_UPTD = 0x0A,
+ VID_API_EVENT_RES_CHANGE = 0x0B,
+ VID_API_EVENT_FIFO_OVF = 0x0C,
+ VID_API_EVENT_CHUNK_DECODED = 0x0D,
+ VID_API_EVENT_REQ_FRAME_BUFF = 0x10,
+ VID_API_EVENT_FRAME_BUFF_RDY = 0x11,
+ VID_API_EVENT_REL_FRAME_BUFF = 0x12,
+ VID_API_EVENT_STR_BUF_RST = 0x13,
+ VID_API_EVENT_RET_PING = 0x14, /* Temp here - rationalise debug events at bottom */
+ VID_API_EVENT_QMETER = 0x15,
+ VID_API_EVENT_STR_FMT_CHANGE = 0x16,
+ VID_API_EVENT_FIRMWARE_XCPT = 0x17,
+ VID_API_EVENT_START_DONE = 0x18,
+ VID_API_EVENT_STOPPED = 0x19,
+ VID_API_EVENT_ABORT_DONE = 0x1A,
+ VID_API_EVENT_FINISHED = 0x1B,
+ VID_API_EVENT_DBG_STAT_UPDATE = 0x1C,
+ VID_API_EVENT_DBG_LOG_STARTED = 0x1D,
+ VID_API_EVENT_DBG_LOG_STOPPED = 0x1E,
+ VID_API_EVENT_DBG_LOG_UPDATED = 0x1F,
+ VID_API_EVENT_DBG_MSG_DEC = 0x20,
+ VID_API_EVENT_DEC_SC_ERR = 0x21,
+ VID_API_EVENT_CQ_FIFO_DUMP = 0x22,
+ VID_API_EVENT_DBG_FIFO_DUMP = 0x23,
+ VID_API_EVENT_DEC_CHECK_RES = 0x24,
+ VID_API_EVENT_DEC_CFG_INFO = 0x25,
+ VID_API_EVENT_SNAPSHOT_DONE = 0x40,
+ VID_API_EVENT_INVALID = 0xFF
+
+} TB_API_DEC_EVENT;
+
+typedef enum {
+ MEDIAIP_PLAYMODE_CONNECTIVITY = 0,
+ MEDIAIP_PLAYMODE_BROADCAST,
+ MEDIAIP_PLAYMODE_BROADCAST_DSS,
+ MEDIAIP_PLAYMODE_LAST = MEDIAIP_PLAYMODE_BROADCAST_DSS
+
+} MEDIA_IP_PLAYMODE;
+
+typedef enum {
+ MEDIA_IP_FMT_NULL = 0x0,
+ MEDIA_IP_FMT_AVC = 0x1,
+ MEDIA_IP_FMT_VC1 = 0x2,
+ MEDIA_IP_FMT_MP2 = 0x3,
+ MEDIA_IP_FMT_AVS = 0x4,
+ MEDIA_IP_FMT_ASP = 0x5,
+ MEDIA_IP_FMT_JPG = 0x6,
+ MEDIA_IP_FMT_RV = 0x7,
+ MEDIA_IP_FMT_VP6 = 0x8,
+ MEDIA_IP_FMT_SPK = 0x9,
+ MEDIA_IP_FMT_VP8 = 0xA,
+ MEDIA_IP_FMT_MVC = 0xB,
+ MEDIA_IP_FMT_VP3 = 0xC,
+ MEDIA_IP_FMT_HEVC = 0xD,
+ MEDIA_IP_FMT_AUTO_DETECT = 0xAD00,
+ MEDIA_IP_FMT_ALL = (int)0xAAAAAAAA,
+ MEDIA_IP_FMT_UNSUPPORTED = (int)0xFFFFFFFF,
+ MEDIA_IP_FMT_LAST = MEDIA_IP_FMT_UNSUPPORTED
+
+} MEDIA_IP_FORMAT;
+
+typedef enum {
+ VSys_FrmtNull = 0x0,
+ VSys_AvcFrmt = 0x1,
+ VSys_Mp2Frmt = 0x2,
+ VSys_Vc1Frmt = 0x3,
+ VSys_AvsFrmt = 0x4,
+ VSys_AspFrmt = 0x5,
+ VSys_JpgFrmt = 0x6,
+ VSys_RvFrmt = 0x7,
+ VSys_Vp6Frmt = 0x8,
+ VSys_SpkFrmt = 0x9,
+ VSys_Vp8Frmt = 0xA,
+ VSys_HevcFrmt = 0xB,
+ VSys_LastFrmt = VSys_HevcFrmt
+} TB_API_DEC_FMT;
+
+typedef struct {
+ u_int32 bTopFldFirst;
+ u_int32 bRptFstField;
+ u_int32 uDispVerRes;
+ u_int32 uDispHorRes;
+ u_int32 uCentreVerOffset;
+ u_int32 uCentreHorOffset;
+ u_int32 uCropLeftRightOffset;
+ u_int32 uCropTopBotOffset;
+
+} MediaIPFW_Video_PicDispInfo;
+
+typedef struct MediaIPFW_PicPerfInfo {
+ u_int32 uMemCRC;
+ u_int32 uBSCRC;
+ u_int32 uSlcActiveCnt;
+ u_int32 uIBEmptyCnt;
+ u_int32 uBaseMemCRC;
+
+ u_int32 uBaseCRCSkip;
+ u_int32 uBaseCRCDrop;
+ BOOL bBaseCRCValid;
+
+ u_int32 uCRC0;
+ u_int32 uCRC1;
+ u_int32 uCRC2;
+ u_int32 uCRC3;
+ u_int32 uCRC4;
+ u_int32 uCRC5;
+
+ u_int32 uFrameActCount;
+ u_int32 uRbspBytesCount;
+ u_int32 uDpbReadCount;
+ u_int32 uMprWaitCount;
+ u_int32 uAccQP;
+ u_int32 uCacheStat;
+ u_int32 mbq_full;
+ u_int32 mbq_empty;
+ u_int32 slice_cnt;
+ u_int32 mb_count;
+
+ u_int32 uTotalTime_us;
+ u_int32 uTotalFwTime_us;
+
+ u_int32 uProcIaccTotRdCnt;
+ u_int32 uProcDaccTotRdCnt;
+ u_int32 uProcDaccTotWrCnt;
+ u_int32 uProcDaccRegRdCnt;
+ u_int32 uProcDaccRegWrCnt;
+ u_int32 uProcDaccRngRdCnt;
+ u_int32 uProcDaccRngWrCnt;
+
+} MediaIPFW_Video_PicPerfInfo;
+
+typedef struct {
+ u_int32 mb_count;
+ u_int32 slice_cnt;
+
+ /* Front End Metrics */
+ u_int32 uDFEBinsUsed;
+ u_int32 uDFECycleCount;
+ u_int32 uDFESliceCycleCount;
+ u_int32 uDFEIBWaitCount;
+ u_int32 uDFENumBytes;
+
+ u_int32 uProcIaccTotRdCnt;
+ u_int32 uProcDaccTotRdCnt;
+ u_int32 uProcDaccTotWrCnt;
+ u_int32 uProcDaccRegRdCnt;
+ u_int32 uProcDaccRegWrCnt;
+ u_int32 uProcDaccRngRdCnt;
+ u_int32 uProcDaccRngWrCnt;
+
+ /* Back End metrics */
+ u_int32 uNumBEUsed;
+ u_int32 uTotalTime_us;
+ u_int32 uTotalFwTime_us;
+ u_int32 uDBECycleCount[0x2];
+ u_int32 uDBESliceCycleCount[0x2];
+ u_int32 uDBEMprWaitCount[0x2];
+ u_int32 uDBEWaitCount[0x2];
+ u_int32 uDBECRC[0x2];
+ u_int32 uDBETotalTime_us[0x2];
+
+ u_int32 uDBEMPRPRXWaitCount[0x2];
+ u_int32 uDBEPXDPRXWaitCount[0x2];
+ u_int32 uDBEFCHPLQWaitCount[0x2];
+ u_int32 uDBEPXDPLQWaitCount[0x2];
+
+ u_int32 uDBEFchWordsCount[0x2];
+ u_int32 uDBEDpbCRC[0x2];
+ u_int32 uDBEDpbReadCount[0x2];
+ u_int32 uDBECacheStats[0x2];
+
+} MediaIPFW_Video_PicPerfDcpInfo, *pMediaIPFW_Video_PicPerfDcpInfo;
+
+typedef struct {
+ u_int32 uPicType;
+ u_int32 uPicStruct;
+ u_int32 bLastPicNPF;
+ u_int32 uPicStAddr;
+ u_int32 uFrameStoreID;
+ MediaIPFW_Video_PicDispInfo DispInfo;
+ MediaIPFW_Video_PicPerfInfo PerfInfo;
+ MediaIPFW_Video_PicPerfDcpInfo PerfDcpInfo;
+ u_int32 bUserDataAvail;
+ u_int32 uPercentInErr;
+
+ u_int32 uBbdHorActive;
+ u_int32 uBbdVerActive;
+ u_int32 uBbdLogoActive;
+ u_int32 uBbdBotPrev;
+ u_int32 uBbdMinColPrj;
+ u_int32 uBbdMinRowPrj;
+ u_int32 uFSBaseAddr;
+
+ /* Only for RealVideo RPR */
+ u_int32 uRprPicWidth;
+ u_int32 uRprPicHeight;
+
+ /*only for divx3*/
+ u_int32 uFrameRate;
+
+} MediaIPFW_Video_PicInfo;
+
+
+typedef struct {
+ u_int32 bClosedGop;
+ u_int32 bBrokenLink;
+} MediaIPFW_Video_GopInfo;
+
+typedef struct {
+ u_int32 uIQuant;
+ u_int32 uIQuantAvail;
+ u_int32 uGopBitRate;
+ u_int32 uGopBitRateAvail;
+
+} MediaIPFW_Video_QMeterInfo;
+
+typedef struct {
+ u_int32 pPicInfoArrayBase;
+ u_int32 uNumSizeDescriptors;
+} MediaIPFW_Video_PicInfoBuffTabDesc;
+
+typedef struct {
+ u_int32 pGopInfoArrayBase;
+ u_int32 uNumSizeDescriptors;
+} MediaIPFW_Video_GopInfoBuffTabDesc;
+
+typedef struct {
+ u_int32 pQMeterInfoArrayBase;
+ u_int32 uNumSizeDescriptors;
+} MediaIPFW_Video_QMeterInfoTabDesc;
+
+typedef struct {
+ u_int32 uMemChunkBase;
+ u_int32 uMemChunkSize;
+
+} MediaIPFW_Video_FrameBuffer;
+
+typedef struct {
+ u_int32 uUDataBase;
+ u_int32 uUDataTotalSize;
+ u_int32 uUDataSlotSize;
+
+} MediaIPFW_Video_UData;
+
+typedef struct {
+ u_int32 uDecStatusLogBase;
+ u_int32 uDecStatusLogSize;
+ u_int32 uDTVLogBase[VID_API_NUM_STREAMS];
+ u_int32 uDTVLogSize[VID_API_NUM_STREAMS];
+
+} MediaIPFW_Video_DbgLogDesc;
+
+typedef struct {
+ u_int32 uDTVLogBase[VID_API_NUM_STREAMS];
+ u_int32 uDTVLogSize[VID_API_NUM_STREAMS];
+
+} MediaIPFW_Video_EngAccessLogDesc;
+
+typedef struct MediaIPFW_FrameStore {
+ u_int32 uFrameStoreLumaBase;
+ u_int32 uFrameStoreChromaBase;
+
+} MediaIPFW_Video_FrameStore;
+
+typedef struct {
+ u_int32 uAddrFirstDescriptor;
+ u_int32 uNumSizeDescriptors;
+
+} MediaIPFW_Video_StreamBuffTabDesc;
+
+typedef struct {
+ u_int32 uAddrFirstDescriptor;
+ u_int32 uNumSizeDescriptors;
+} MediaIPFW_Video_UserDataBuffTabDesc;
+
+typedef struct {
+ u_int32 uNumRefFrms;
+ u_int32 uNumDPBFrms;
+ u_int32 uNumDFEAreas;
+ u_int32 uColorDesc;
+ u_int32 uProgressive;
+ u_int32 uVerRes;
+ u_int32 uHorRes;
+ u_int32 uParWidth;
+ u_int32 uParHeight;
+ u_int32 FrameRate;
+ u_int32 UDispAspRatio;
+ u_int32 uLevelIDC;
+ u_int32 uVerDecodeRes;
+ u_int32 uHorDecodeRes;
+ u_int32 uOverScan;
+ u_int32 uChromaFmt;
+ u_int32 uPAFF;
+ u_int32 uMBAFF;
+ u_int32 uBitDepthLuma;
+ u_int32 uBitDepthChroma;
+ u_int32 uMVCNumViews;
+ u_int32 uMVCViewList[VID_API_MAX_NUM_MVC_VIEWS];
+ u_int32 uFBCInUse;
+ u_int32 uFrameCropValid;
+ u_int32 uFrameCropLeftOffset;
+ u_int32 uFrameCropRightOffset;
+ u_int32 uFrameCropTopOffset;
+ u_int32 uFrameCropBottomOffset;
+
+} MediaIPFW_Video_SeqInfo;
+
+typedef struct {
+ u_int32 pSeqInfoArrayBase;
+ u_int32 uNumSizeDescriptors;
+} MediaIPFW_Video_SeqInfoBuffTabDesc;
+
+typedef struct {
+ u_int32 wptr;
+ u_int32 rptr;
+ u_int32 start;
+ u_int32 end;
+
+} BUFFER_DESCRIPTOR_TYPE, *pBUFFER_DESCRIPTOR_TYPE;
+
+typedef struct {
+ volatile u_int32 wptr;
+ volatile u_int32 rptr;
+ volatile u_int32 start;
+ volatile u_int32 end;
+ volatile u_int32 LWM;
+
+} STREAM_BUFFER_DESCRIPTOR_TYPE, *pSTREAM_BUFFER_DESCRIPTOR_TYPE;
+
+typedef struct {
+ u_int32 uRotationAngle;
+ u_int32 uHorizScaleFactor;
+ u_int32 uVertScaleFactor;
+ u_int32 uRotationMode;
+ u_int32 uRGBMode;
+ u_int32 uChunkMode; /* 0 ~ 1 */
+ u_int32 uLastChunk; /* 0 ~ 1 */
+ u_int32 uChunkRows; /* 0 ~ 255 */
+ u_int32 uNumBytes;
+ u_int32 uJpgCropXStart;
+ u_int32 uJpgCropYStart;
+ u_int32 uJpgCropWidth;
+ u_int32 uJpgCropHeight;
+ u_int32 uJpgMjpegMode;
+ u_int32 uJpgMjpegInterlaced;
+
+} MediaIPFW_Video_JpegParams;
+
+typedef struct {
+ u_int32 pJpegParamArrayBase;
+ u_int32 uNumSizeDescriptors;
+
+} MediaIPFW_Video_JpegParamTabDesc;
+
+typedef struct {
+ u_int32 uDispImm;
+ u_int32 uFourCC;
+ u_int32 uCodecVersion;
+ u_int32 uFrameRate;
+ u_int32 bbd_logo_width;
+ u_int32 bbd_lum_thr;
+ u_int32 bbd_coring;
+ u_int32 bbd_s_thr_row;
+ u_int32 bbd_p_thr_row;
+ u_int32 bbd_s_thr_logo_row;
+ u_int32 bbd_p_thr_logo_row;
+ u_int32 bbd_s_thr_col;
+ u_int32 bbd_p_thr_col;
+ u_int32 bbd_chr_thr_row;
+ u_int32 bbd_chr_thr_col;
+ u_int32 bbd_uv_mid_level;
+ u_int32 bbd_excl_win_mb_left;
+ u_int32 bbd_excl_win_mb_right;
+
+} MediaIPFW_Video_CodecParams;
+
+typedef struct {
+ u_int32 uFramePitch;
+
+} MediaIPFW_Video_PitchInfo;
+
+typedef struct {
+ u_int32 uWrPtr;
+ u_int32 uRdPtr;
+ u_int32 uStart;
+ u_int32 uEnd;
+ u_int32 uLo;
+ u_int32 uHi;
+
+} MediaIPFW_Video_BufDesc;
+
+typedef struct {
+ u_int32 pCodecParamArrayBase;
+ u_int32 uNumSizeDescriptors;
+
+} MediaIPFW_Video_CodecParamTabDesc;
+
+typedef struct {
+ u_int32 uRC4Key[0x8];
+ u_int32 uMemObfuscVal;
+
+} MediaIPFW_Video_Encrypt_Info, *pMediaIPFW_Video_Encrypt_Info;
+
+typedef struct {
+ u_int32 uCfgCookie;
+
+ u_int32 uNumMalones;
+ u_int32 uMaloneBaseAddress[MEDIAIP_MAX_NUM_MALONES];
+ u_int32 uHifOffset[MEDIAIP_MAX_NUM_MALONES];
+ u_int32 uMaloneIrqPin[MEDIAIP_MAX_NUM_MALONES][MEDIAIP_MAX_NUM_MALONE_IRQ_PINS];
+ u_int32 uMaloneIrqTarget[MEDIAIP_MAX_NUM_MALONES][MEDIAIP_MAX_NUM_MALONE_IRQ_PINS];
+
+ u_int32 uNumWindsors;
+ u_int32 uWindsorBaseAddress[MEDIAIP_MAX_NUM_WINDSORS];
+ u_int32 uWindsorIrqPin[MEDIAIP_MAX_NUM_WINDSORS][MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS];
+ u_int32 uWindsorIrqTarget[MEDIAIP_MAX_NUM_WINDSORS][MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS];
+
+ u_int32 uCmdIrqPin[MEDIAIP_MAX_NUM_CMD_IRQ_PINS];
+ u_int32 uCmdIrqTarget[MEDIAIP_MAX_NUM_CMD_IRQ_PINS];
+
+ u_int32 uMsgIrqPin[MEDIAIP_MAX_NUM_MSG_IRQ_PINS];
+ u_int32 uMsgIrqTarget[MEDIAIP_MAX_NUM_MSG_IRQ_PINS];
+
+ u_int32 uSysClkFreq;
+ u_int32 uNumTimers;
+ u_int32 uTimerBaseAddr;
+ u_int32 uTimerIrqPin[MEDIAIP_MAX_NUM_TIMER_IRQ_PINS];
+ u_int32 uTimerIrqTarget[MEDIAIP_MAX_NUM_TIMER_IRQ_PINS];
+ u_int32 uTimerSlots[MEDIAIP_MAX_NUM_TIMER_IRQ_SLOTS];
+
+ u_int32 uGICBaseAddr;
+ u_int32 uUartBaseAddr;
+
+ u_int32 uDPVBaseAddr;
+ u_int32 uDPVIrqPin;
+ u_int32 uDPVIrqTarget;
+
+ u_int32 uPixIfBaseAddr;
+
+ u_int32 pal_trace_level;
+ u_int32 pal_trace_destination;
+
+ u_int32 pal_trace_level1;
+ u_int32 pal_trace_destination1;
+
+ u_int32 uHeapBase;
+ u_int32 uHeapSize;
+
+ u_int32 uFSLCacheBaseAddr[2];
+
+} MEDIAIP_FW_SYSTEM_CONFIG, *pMEDIAIP_FW_SYSTEM_CONFIG;
+
+typedef struct {
+ u_int32 FwExecBaseAddr;
+ u_int32 FwExecAreaSize;
+ MediaIPFW_Video_BufDesc StreamCmdBufferDesc;
+ MediaIPFW_Video_BufDesc StreamMsgBufferDesc;
+ u_int32 StreamCmdIntEnable[VID_API_NUM_STREAMS];
+ MediaIPFW_Video_PitchInfo StreamPitchInfo[VID_API_NUM_STREAMS];
+ u_int32 StreamConfig[VID_API_NUM_STREAMS];
+ MediaIPFW_Video_CodecParamTabDesc CodecParamTabDesc; /* TODO-KMC should we just go ahead and remove the concept of tabdesc? It is basicaly a bad coding style used for pinkys anyway */
+ MediaIPFW_Video_JpegParamTabDesc JpegParamTabDesc;
+#ifdef COREPLAY_API
+ pBUFFER_DESCRIPTOR_TYPE pStreamBuffDesc[VID_API_NUM_STREAMS][VID_API_MAX_BUF_PER_STR];
+#else
+ u_int32 pStreamBuffDesc[VID_API_NUM_STREAMS][VID_API_MAX_BUF_PER_STR];
+#endif
+ MediaIPFW_Video_SeqInfoBuffTabDesc SeqInfoTabDesc;
+ MediaIPFW_Video_PicInfoBuffTabDesc PicInfoTabDesc;
+ MediaIPFW_Video_GopInfoBuffTabDesc GopInfoTabDesc;
+ MediaIPFW_Video_QMeterInfoTabDesc QMeterInfoTabDesc;
+ u_int32 StreamError[VID_API_NUM_STREAMS];
+ u_int32 FWVersion;
+ u_int32 uMVDMipsOffset;
+ u_int32 uMaxDecoderStreams;
+ MediaIPFW_Video_DbgLogDesc DbgLogDesc;
+ MediaIPFW_Video_FrameBuffer StreamFrameBuffer[VID_API_NUM_STREAMS];
+ MediaIPFW_Video_FrameBuffer StreamDCPBuffer[VID_API_NUM_STREAMS];
+ MediaIPFW_Video_UData UDataBuffer[VID_API_NUM_STREAMS];
+ MediaIPFW_Video_BufDesc DebugBufferDesc;
+ MediaIPFW_Video_BufDesc EngAccessBufferDesc[VID_API_NUM_STREAMS];
+ u_int32 ptEncryptInfo[VID_API_NUM_STREAMS];
+ MEDIAIP_FW_SYSTEM_CONFIG sSystemCfg;
+ u_int32 uApiVersion;
+} DEC_RPC_HOST_IFACE, *pDEC_RPC_HOST_IFACE;
+
+//x means source data , y means destination data
+#define VID_STREAM_CONFIG_FORMAT_MASK 0x0000000F
+#define VID_STREAM_CONFIG_FORMAT_POS 0
+#define VID_STREAM_CONFIG_FORMAT_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_FORMAT_POS)&VID_STREAM_CONFIG_FORMAT_MASK)))
+
+#define VID_STREAM_CONFIG_STRBUFIDX_MASK 0x00000300
+#define VID_STREAM_CONFIG_STRBUFIDX_POS 8
+#define VID_STREAM_CONFIG_STRBUFIDX_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_STRBUFIDX_POS)&VID_STREAM_CONFIG_STRBUFIDX_MASK)))
+
+#define VID_STREAM_CONFIG_NOSEQ_MASK 0x00000400
+#define VID_STREAM_CONFIG_NOSEQ_POS 10
+#define VID_STREAM_CONFIG_NOSEQ_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_NOSEQ_POS)&VID_STREAM_CONFIG_NOSEQ_MASK)))
+
+#define VID_STREAM_CONFIG_DEBLOCK_MASK 0x00000800
+#define VID_STREAM_CONFIG_DEBLOCK_POS 11
+#define VID_STREAM_CONFIG_DEBLOCK_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_DEBLOCK_POS)&VID_STREAM_CONFIG_DEBLOCK_MASK)))
+
+#define VID_STREAM_CONFIG_DERING_MASK 0x00001000
+#define VID_STREAM_CONFIG_DERING_POS 12
+#define VID_STREAM_CONFIG_DERING_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_DERING_POS)&VID_STREAM_CONFIG_DERING_MASK)))
+
+#define VID_STREAM_CONFIG_IBWAIT_MASK 0x00002000
+#define VID_STREAM_CONFIG_IBWAIT_POS 13
+#define VID_STREAM_CONFIG_IBWAIT_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_IBWAIT_POS)&VID_STREAM_CONFIG_IBWAIT_MASK)))
+
+#define VID_STREAM_CONFIG_FBC_MASK 0x00004000
+#define VID_STREAM_CONFIG_FBC_POS 14
+#define VID_STREAM_CONFIG_FBC_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_FBC_POS)&VID_STREAM_CONFIG_FBC_MASK)))
+
+#define VID_STREAM_CONFIG_PLAY_MODE_MASK 0x00030000
+#define VID_STREAM_CONFIG_PLAY_MODE_POS 16
+#define VID_STREAM_CONFIG_PLAY_MODE_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_PLAY_MODE_POS)&VID_STREAM_CONFIG_PLAY_MODE_MASK)))
+
+#define VID_STREAM_CONFIG_ENABLE_DCP_MASK 0x00100000
+#define VID_STREAM_CONFIG_ENABLE_DCP_POS 20
+#define VID_STREAM_CONFIG_ENABLE_DCP_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_ENABLE_DCP_POS)&VID_STREAM_CONFIG_ENABLE_DCP_MASK)))
+
+#define VID_STREAM_CONFIG_NUM_STR_BUF_MASK 0x00600000
+#define VID_STREAM_CONFIG_NUM_STR_BUF_POS 21
+#define VID_STREAM_CONFIG_NUM_STR_BUF_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_NUM_STR_BUF_POS)&VID_STREAM_CONFIG_NUM_STR_BUF_MASK)))
+
+#define VID_STREAM_CONFIG_MALONE_USAGE_MASK 0x01800000
+#define VID_STREAM_CONFIG_MALONE_USAGE_POS 23
+#define VID_STREAM_CONFIG_MALONE_USAGE_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_MALONE_USAGE_POS)&VID_STREAM_CONFIG_MALONE_USAGE_MASK)))
+
+#define VID_STREAM_CONFIG_MULTI_VID_MASK 0x02000000
+#define VID_STREAM_CONFIG_MULTI_VID_POS 25
+#define VID_STREAM_CONFIG_MULTI_VID_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_MULTI_VID_POS)&VID_STREAM_CONFIG_MULTI_VID_MASK)))
+
+#define VID_STREAM_CONFIG_OBFUSC_EN_MASK 0x04000000
+#define VID_STREAM_CONFIG_OBFUSC_EN_POS 26
+#define VID_STREAM_CONFIG_OBFUSC_EN_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_OBFUSC_EN_POS)&VID_STREAM_CONFIG_OBFUSC_EN_MASK)))
+
+#define VID_STREAM_CONFIG_RC4_EN_MASK 0x08000000
+#define VID_STREAM_CONFIG_RC4_EN_POS 27
+#define VID_STREAM_CONFIG_RC4_EN_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_RC4_EN_POS)&VID_STREAM_CONFIG_RC4_EN_MASK)))
+
+#define VID_STREAM_CONFIG_MCX_MASK 0x10000000
+#define VID_STREAM_CONFIG_MCX_POS 28
+#define VID_STREAM_CONFIG_MCX_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_MCX_POS)&VID_STREAM_CONFIG_MCX_MASK)))
+
+#define VID_STREAM_CONFIG_PES_MASK 0x20000000
+#define VID_STREAM_CONFIG_PES_POS 29
+#define VID_STREAM_CONFIG_PES_SET(x, y) ((*y = (*y | ((x << VID_STREAM_CONFIG_PES_POS)&VID_STREAM_CONFIG_PES_MASK))))
+
+#define VID_STREAM_CONFIG_NUM_DBE_MASK 0x40000000
+#define VID_STREAM_CONFIG_NUM_DBE_POS 30
+#define VID_STREAM_CONFIG_NUM_DBE_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_NUM_DBE_POS)&VID_STREAM_CONFIG_NUM_DBE_MASK)))
+
+#define VID_STREAM_CONFIG_FS_CTRL_MODE_MASK 0x80000000
+#define VID_STREAM_CONFIG_FS_CTRL_MODE_POS 31
+#define VID_STREAM_CONFIG_FS_CTRL_MODE_SET(x, y) (*y = (*y | ((x << VID_STREAM_CONFIG_FS_CTRL_MODE_POS)&VID_STREAM_CONFIG_FS_CTRL_MODE_MASK)))
+
+#define SCB_XREG_SLV_BASE 0x00000000
+#define SCB_SCB_BLK_CTRL 0x00070000
+#define SCB_BLK_CTRL_XMEM_RESET_SET 0x00000090
+#define SCB_BLK_CTRL_CACHE_RESET_SET 0x000000A0
+#define SCB_BLK_CTRL_CACHE_RESET_CLR 0x000000A4
+#define SCB_BLK_CTRL_SCB_CLK_ENABLE_SET 0x00000100
+
+#define XMEM_CONTROL 0x00041000
+
+#define DEC_MFD_XREG_SLV_BASE 0x00180000
+
+#define MFD_HIF 0x0001C000
+#define MFD_HIF_MSD_REG_INTERRUPT_STATUS 0x00000018
+#define MFD_SIF 0x0001D000
+#define MFD_SIF_CTRL_STATUS 0x000000F0
+#define MFD_SIF_INTR_STATUS 0x000000F4
+#define MFD_MCX 0x00020800
+#define MFD_MCX_OFF 0x00000020
+
+#define MFD_BLK_CTRL 0x00030000
+#define MFD_BLK_CTRL_MFD_SYS_RESET_SET 0x00000000
+#define MFD_BLK_CTRL_MFD_SYS_RESET_CLR 0x00000004
+#define MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_SET 0x00000100
+#define MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_CLR 0x00000104
+
+#endif
diff --git a/drivers/mxc/vpu-decoder-b0/vpu_b0.c b/drivers/mxc/vpu-decoder-b0/vpu_b0.c
new file mode 100755
index 000000000000..e5601216e2bb
--- /dev/null
+++ b/drivers/mxc/vpu-decoder-b0/vpu_b0.c
@@ -0,0 +1,3243 @@
+/*
+ * Copyright 2018 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file vpu-b0.c
+ *
+ * copyright here may be changed later
+ *
+ *
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/file.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/platform_data/dma-imx.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/pm_runtime.h>
+#include <linux/mx8_mu.h>
+#include <linux/uaccess.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "vpu_b0.h"
+#include "insert_startcode.h"
+
+unsigned int vpu_dbg_level_decoder = 1;
+static int vpu_frm_depth = 100;
+
+/* Generic End of content startcodes to differentiate from those naturally in the stream/file */
+#define EOS_GENERIC_HEVC 0x7c010000
+#define EOS_GENERIC_JPEG 0xefff0000
+#define EOS_GENERIC_MPEG 0xCC010000
+
+static void vpu_api_event_handler(struct vpu_ctx *ctx, u_int32 uStrIdx, u_int32 uEvent, u_int32 *event_data);
+static void v4l2_vpu_send_cmd(struct vpu_ctx *ctx, uint32_t idx, uint32_t cmdid, uint32_t cmdnum, uint32_t *local_cmddata);
+static bool add_scode(struct vpu_ctx *ctx, u_int32 uStrBufIdx, VPU_PADDING_SCODE_TYPE eScodeType);
+static void v4l2_update_stream_addr(struct vpu_ctx *ctx, uint32_t uStrBufIdx);
+static int reset_vpu_firmware(struct vpu_dev *dev);
+
+static char *cmd2str[] = {
+ "VID_API_CMD_NULL", /*0x0*/
+ "VID_API_CMD_PARSE_NEXT_SEQ", /*0x1*/
+ "VID_API_CMD_PARSE_NEXT_I",
+ "VID_API_CMD_PARSE_NEXT_IP",
+ "VID_API_CMD_PARSE_NEXT_ANY",
+ "VID_API_CMD_DEC_PIC",
+ "VID_API_CMD_UPDATE_ES_WR_PTR",
+ "VID_API_CMD_UPDATE_ES_RD_PTR",
+ "VID_API_CMD_UPDATE_UDATA",
+ "VID_API_CMD_GET_FSINFO",
+ "VID_API_CMD_SKIP_PIC",
+ "VID_API_CMD_DEC_CHUNK", /*0x0b*/
+ "VID_API_CMD_UNDEFINED",
+ "VID_API_CMD_UNDEFINED",
+ "VID_API_CMD_UNDEFINED",
+ "VID_API_CMD_UNDEFINED",
+ "VID_API_CMD_START", /*0x10*/
+ "VID_API_CMD_STOP",
+ "VID_API_CMD_ABORT",
+ "VID_API_CMD_RST_BUF",
+ "VID_API_CMD_UNDEFINED",
+ "VID_API_CMD_FS_RELEASE",
+ "VID_API_CMD_MEM_REGION_ATTACH",
+ "VID_API_CMD_MEM_REGION_DETACH",
+ "VID_API_CMD_MVC_VIEW_SELECT",
+ "VID_API_CMD_FS_ALLOC", /*0x19*/
+ "VID_API_CMD_UNDEFINED",
+ "VID_API_CMD_UNDEFINED",
+ "VID_API_CMD_DBG_GET_STATUS", /*0x1C*/
+ "VID_API_CMD_DBG_START_LOG",
+ "VID_API_CMD_DBG_STOP_LOG",
+ "VID_API_CMD_DBG_DUMP_LOG",
+ "VID_API_CMD_YUV_READY", /*0x20*/
+};
+
+static char *event2str[] = {
+ "VID_API_EVENT_NULL", /*0x0*/
+ "VID_API_EVENT_RESET_DONE", /*0x1*/
+ "VID_API_EVENT_SEQ_HDR_FOUND",
+ "VID_API_EVENT_PIC_HDR_FOUND",
+ "VID_API_EVENT_PIC_DECODED",
+ "VID_API_EVENT_FIFO_LOW",
+ "VID_API_EVENT_FIFO_HIGH",
+ "VID_API_EVENT_FIFO_EMPTY",
+ "VID_API_EVENT_FIFO_FULL",
+ "VID_API_EVENT_BS_ERROR",
+ "VID_API_EVENT_UDATA_FIFO_UPTD",
+ "VID_API_EVENT_RES_CHANGE",
+ "VID_API_EVENT_FIFO_OVF",
+ "VID_API_EVENT_CHUNK_DECODED", /*0x0D*/
+ "VID_API_EVENT_UNDEFINED",
+ "VID_API_EVENT_UNDEFINED",
+ "VID_API_EVENT_REQ_FRAME_BUFF", /*0x10*/
+ "VID_API_EVENT_FRAME_BUFF_RDY",
+ "VID_API_EVENT_REL_FRAME_BUFF",
+ "VID_API_EVENT_STR_BUF_RST",
+ "VID_API_EVENT_RET_PING",
+ "VID_API_EVENT_QMETER",
+ "VID_API_EVENT_STR_FMT_CHANGED",
+ "VID_API_EVENT_FIRMWARE_XCPT",
+ "VID_API_EVENT_START_DONE",
+ "VID_API_EVENT_STOPPED",
+ "VID_API_EVENT_ABORT_DONE",
+ "VID_API_EVENT_FINISHED",
+ "VID_API_EVENT_DBG_STAT_UPDATE",
+ "VID_API_EVENT_DBG_LOG_STARTED",
+ "VID_API_EVENT_DBG_LOG_STOPPED",
+ "VID_API_EVENT_DBG_LOG_UPFATED",
+ "VID_API_EVENT_DBG_MSG_DEC", /*0x20*/
+ "VID_API_EVENT_DEC_SC_ERR",
+ "VID_API_EVENT_CQ_FIFO_DUMP",
+ "VID_API_EVENT_DBG_FIFO_DUMP",
+ "VID_API_EVENT_DEC_CHECK_RES",
+ "VID_API_EVENT_DEC_CFG_INFO", /*0x25*/
+};
+
+static char *bufstat[] = {
+ "FRAME_ALLOC",
+ "FRAME_FREE",
+ "FRAME_DECODED",
+ "FRAME_READY",
+ "FRAME_RELEASE",
+};
+
+static void vpu_log_event(u_int32 uEvent, u_int32 ctxid)
+{
+ if (uEvent > ARRAY_SIZE(event2str)-1)
+ vpu_dbg(LVL_EVENT, "reveive event: 0x%X, ctx id:%d\n", uEvent, ctxid);
+ else
+ vpu_dbg(LVL_EVENT, "recevie event: %s, ctx id:%d\n", event2str[uEvent], ctxid);
+}
+
+static void vpu_log_cmd(u_int32 cmdid, u_int32 ctxid)
+{
+ if (cmdid > ARRAY_SIZE(cmd2str)-1)
+ vpu_dbg(LVL_EVENT, "send cmd: 0x%X, ctx id:%d\n", cmdid, ctxid);
+ else
+ vpu_dbg(LVL_EVENT, "send cmd: %s ctx id:%d\n", cmd2str[cmdid], ctxid);
+}
+
+static void vpu_log_buffer_state(struct vpu_ctx *ctx)
+{
+ struct vb2_data_req *p_data_req;
+ int i;
+
+ for (i = 0; i < VPU_MAX_BUFFER; i++) {
+ p_data_req = &ctx->q_data[V4L2_DST].vb2_reqs[i];
+ if (p_data_req->vb2_buf != NULL)
+ vpu_dbg(LVL_INFO, "ctx: %d, buffer[%d] status: %s\n", ctx->str_index, i, bufstat[p_data_req->status]);
+ }
+}
+
+static int find_buffer_id(struct vpu_ctx *ctx, u_int32 addr)
+{
+ struct vb2_data_req *p_data_req;
+ u_int32 LumaAddr;
+ u_int32 *pphy_address;
+ u_int32 i;
+
+ for (i = 0; i < VPU_MAX_BUFFER; i++) {
+ p_data_req = &ctx->q_data[V4L2_DST].vb2_reqs[i];
+ if (p_data_req->vb2_buf != NULL) {
+ pphy_address = (u_int32 *)vb2_plane_cookie(p_data_req->vb2_buf, 0);
+ if (pphy_address != NULL) {
+ LumaAddr = *pphy_address;
+ if (LumaAddr == addr - ctx->dev->cm_offset)
+ return i;
+ } else
+ vpu_dbg(LVL_ERR, "error: %s() buffer (%d) is NULL\n", __func__, i);
+ }
+ }
+
+ vpu_dbg(LVL_ERR, "error: %s() can't find suitable id based on address(0x%x)\n", __func__, addr);
+ return -1;
+}
+
+static void MU_sendMesgToFW(void __iomem *base, MSG_Type type, uint32_t value)
+{
+ MU_SendMessage(base, 1, value);
+ MU_SendMessage(base, 0, type);
+}
+#ifdef DEBUG
+static void vpu_log_shared_mem(struct vpu_ctx *ctx)
+{
+ struct vpu_dev *dev = ctx->dev;
+ struct shared_addr *This = &dev->shared_mem;
+ pDEC_RPC_HOST_IFACE pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
+ MediaIPFW_Video_BufDesc *pMsgDesc = &pSharedInterface->StreamMsgBufferDesc;
+ MediaIPFW_Video_BufDesc *pCmdDesc = &pSharedInterface->StreamCmdBufferDesc;
+ pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+ u_int32 index = ctx->str_index;
+
+ vpu_dbg(LVL_INFO, "msg: wr: 0x%x, rd: 0x%x, cmd: wr : 0x%x, rd: 0x%x\n",
+ pMsgDesc->uWrPtr, pMsgDesc->uRdPtr, pCmdDesc->uWrPtr, pCmdDesc->uRdPtr);
+
+ pStrBufDesc = dev->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * index;
+ vpu_dbg(LVL_INFO, "data: wptr(0x%x) rptr(0x%x) start(0x%x) end(0x%x) uStrIdx(%d)\n",
+ pStrBufDesc->wptr, pStrBufDesc->rptr, pStrBufDesc->start, pStrBufDesc->end, index);
+}
+#endif
+/*
+ * v4l2 ioctl() operation
+ *
+ */
+static struct vpu_v4l2_fmt formats_compressed_dec[] = {
+ {
+ .name = "H264 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .num_planes = 1,
+ .vdec_std = VPU_VIDEO_AVC,
+ },
+ {
+ .name = "VC1 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
+ .num_planes = 1,
+ .vdec_std = VPU_VIDEO_VC1,
+ },
+ {
+ .name = "VC1 RCV Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
+ .num_planes = 1,
+ .vdec_std = VPU_VIDEO_VC1,
+ },
+ {
+ .name = "MPEG2 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_MPEG2,
+ .num_planes = 1,
+ .vdec_std = VPU_VIDEO_MPEG2,
+ },
+
+ {
+ .name = "AVS Encoded Stream",
+ .fourcc = VPU_PIX_FMT_AVS,
+ .num_planes = 1,
+ .vdec_std = VPU_VIDEO_AVS,
+ },
+ {
+ .name = "MPEG4 ASP Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .num_planes = 1,
+ .vdec_std = VPU_VIDEO_ASP,
+ },
+ {
+ .name = "DIVX Encoded Stream",
+ .fourcc = VPU_PIX_FMT_DIVX,
+ .num_planes = 1,
+ .vdec_std = VPU_VIDEO_ASP,
+ },
+ {
+ .name = "JPEG stills",
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .num_planes = 1,
+ .vdec_std = VPU_VIDEO_JPEG,
+ },
+ {
+ .name = "RV Encoded Stream",
+ .fourcc = VPU_PIX_FMT_RV,
+ .num_planes = 1,
+ .vdec_std = VPU_VIDEO_RV,
+ },
+ {
+ .name = "VP6 Encoded Stream",
+ .fourcc = VPU_PIX_FMT_VP6,
+ .num_planes = 1,
+ .vdec_std = VPU_VIDEO_VP6,
+ },
+ {
+ .name = "SPK Encoded Stream",
+ .fourcc = VPU_PIX_FMT_SPK,
+ .num_planes = 1,
+ .vdec_std = VPU_VIDEO_SPK,
+ },
+ {
+ .name = "H263 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H263,
+ .num_planes = 1,
+ .vdec_std = VPU_VIDEO_ASP,
+ },
+ {
+ .name = "VP8 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_VP8,
+ .num_planes = 1,
+ .vdec_std = VPU_VIDEO_VP8,
+ },
+ {
+ .name = "H264/MVC Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H264_MVC,
+ .num_planes = 1,
+ .vdec_std = VPU_VIDEO_AVC_MVC,
+ },
+ {
+ .name = "H265 HEVC Encoded Stream",
+ .fourcc = VPU_PIX_FMT_HEVC,
+ .num_planes = 1,
+ .vdec_std = VPU_VIDEO_HEVC,
+ },
+ {
+ .name = "Logo",
+ .fourcc = VPU_PIX_FMT_LOGO,
+ .num_planes = 1,
+ .vdec_std = VPU_VIDEO_UNDEFINED,
+ },
+};
+
+static struct vpu_v4l2_fmt formats_yuv_dec[] = {
+ {
+ .name = "4:2:0 2 Planes Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .num_planes = 2,
+ .vdec_std = VPU_PF_YUV420_SEMIPLANAR,
+ },
+ {
+ .name = "4:2:0 2 Planes Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV12_10BIT,
+ .num_planes = 2,
+ .vdec_std = VPU_PF_YUV420_SEMIPLANAR,
+ },
+};
+
+static int v4l2_ioctl_querycap(struct file *file,
+ void *fh,
+ struct v4l2_capability *cap
+ )
+{
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+ strncpy(cap->driver, "vpu B0", sizeof(cap->driver) - 1);
+ strlcpy(cap->card, "vpu B0", sizeof(cap->card));
+ strlcpy(cap->bus_info, "platform:", sizeof(cap->bus_info));
+ cap->version = KERNEL_VERSION(0, 0, 1);
+ cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+static int v4l2_ioctl_enum_fmt_vid_cap_mplane(struct file *file,
+ void *fh,
+ struct v4l2_fmtdesc *f
+ )
+{
+ struct vpu_v4l2_fmt *fmt;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+ if (f->index >= ARRAY_SIZE(formats_yuv_dec))
+ return -EINVAL;
+
+ fmt = &formats_yuv_dec[f->index];
+ strlcpy(f->description, fmt->name, sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ return 0;
+}
+static int v4l2_ioctl_enum_fmt_vid_out_mplane(struct file *file,
+ void *fh,
+ struct v4l2_fmtdesc *f
+ )
+{
+ struct vpu_v4l2_fmt *fmt;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+ if (f->index >= ARRAY_SIZE(formats_compressed_dec))
+ return -EINVAL;
+
+ fmt = &formats_compressed_dec[f->index];
+ strlcpy(f->description, fmt->name, sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ f->flags |= V4L2_FMT_FLAG_COMPRESSED;
+ return 0;
+}
+
+static void caculate_frame_size(struct vpu_ctx *ctx)
+{
+ u_int32 width = ctx->pSeqinfo->uHorDecodeRes;
+ u_int32 height = ctx->pSeqinfo->uVerDecodeRes;
+ u_int32 luma_size;
+ u_int32 chroma_size;
+ u_int32 chroma_height;
+ u_int32 uVertAlign = 256-1;
+ bool b10BitFormat = (ctx->pSeqinfo->uBitDepthLuma > 8) || (ctx->pSeqinfo->uBitDepthChroma > 8);
+
+ struct queue_data *q_data;
+
+ q_data = &ctx->q_data[V4L2_DST];
+
+ width = b10BitFormat?(width + ((width + 3) >> 2)):width;
+ width = ((width + uVertAlign) & ~uVertAlign);
+ q_data->stride = width;
+
+ height = ((height + uVertAlign) & ~uVertAlign);
+ if (ctx->pSeqinfo->uProgressive)
+ chroma_height = height >> 1;
+ else
+ chroma_height = height;
+ luma_size = width * height;
+ chroma_size = width * chroma_height;
+ ctx->q_data[V4L2_DST].sizeimage[0] = luma_size;
+ ctx->q_data[V4L2_DST].sizeimage[1] = chroma_size;
+}
+
+static int v4l2_ioctl_g_fmt(struct file *file,
+ void *fh,
+ struct v4l2_format *f
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ unsigned int i;
+ struct queue_data *q_data;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ q_data = &ctx->q_data[V4L2_DST];
+ if ((ctx->pSeqinfo->uBitDepthLuma > 8) || (ctx->pSeqinfo->uBitDepthChroma > 8))
+ pix_mp->pixelformat = V4L2_PIX_FMT_NV12_10BIT;
+ else
+ pix_mp->pixelformat = V4L2_PIX_FMT_NV12;
+ pix_mp->width = ctx->pSeqinfo->uHorRes > 0?ctx->pSeqinfo->uHorRes:q_data->width;
+ pix_mp->height = ctx->pSeqinfo->uVerRes > 0?ctx->pSeqinfo->uVerRes:q_data->height;
+ pix_mp->field = V4L2_FIELD_NONE;
+ pix_mp->num_planes = 2;
+ pix_mp->colorspace = V4L2_COLORSPACE_REC709;
+
+ for (i = 0; i < pix_mp->num_planes; i++) {
+ pix_mp->plane_fmt[i].bytesperline = q_data->stride;
+ pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+ }
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ q_data = &ctx->q_data[V4L2_SRC];
+ pix_mp->width = q_data->width;
+ pix_mp->height = q_data->height;
+ pix_mp->field = V4L2_FIELD_NONE;
+ pix_mp->num_planes = q_data->num_planes;
+ for (i = 0; i < pix_mp->num_planes; i++) {
+ pix_mp->plane_fmt[i].bytesperline = q_data->stride;
+ pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+
+ }
+ pix_mp->pixelformat = q_data->fourcc;
+ } else
+ return -EINVAL;
+ return 0;
+}
+
+static void set_video_standard(struct queue_data *q_data,
+ struct v4l2_format *f,
+ struct vpu_v4l2_fmt *pformat_table,
+ uint32_t table_size)
+{
+ unsigned int i;
+
+ for (i = 0; i < table_size; i++) {
+ if (pformat_table[i].fourcc == f->fmt.pix_mp.pixelformat)
+ q_data->vdec_std = pformat_table[i].vdec_std;
+ }
+}
+
+static int v4l2_ioctl_s_fmt(struct file *file,
+ void *fh,
+ struct v4l2_format *f
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct queue_data *q_data;
+ u_int32 i;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ q_data = &ctx->q_data[V4L2_DST];
+ set_video_standard(q_data, f, formats_yuv_dec, ARRAY_SIZE(formats_yuv_dec));
+ pix_mp->num_planes = 2;
+ pix_mp->colorspace = V4L2_COLORSPACE_REC709;
+ for (i = 0; i < pix_mp->num_planes; i++) {
+ if (ctx->q_data[V4L2_DST].stride > 0)
+ pix_mp->plane_fmt[i].bytesperline = ctx->q_data[V4L2_DST].stride;
+ if (ctx->q_data[V4L2_DST].sizeimage[i] > 0)
+ pix_mp->plane_fmt[i].sizeimage = ctx->q_data[V4L2_DST].sizeimage[i];
+ }
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ q_data = &ctx->q_data[V4L2_SRC];
+ set_video_standard(q_data, f, formats_compressed_dec, ARRAY_SIZE(formats_compressed_dec));
+ } else
+ return -EINVAL;
+
+ q_data->num_planes = pix_mp->num_planes;
+ for (i = 0; i < q_data->num_planes; i++) {
+ q_data->stride = pix_mp->plane_fmt[i].bytesperline;
+ q_data->sizeimage[i] = pix_mp->plane_fmt[i].sizeimage;
+ }
+ q_data->fourcc = pix_mp->pixelformat;
+ q_data->width = pix_mp->width;
+ q_data->height = pix_mp->height;
+ q_data->rect.left = 0;
+ q_data->rect.top = 0;
+ q_data->rect.width = pix_mp->width;
+ q_data->rect.height = pix_mp->height;
+
+ return 0;
+}
+
+static int v4l2_ioctl_expbuf(struct file *file,
+ void *fh,
+ struct v4l2_exportbuffer *buf
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct queue_data *q_data;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ q_data = &ctx->q_data[V4L2_SRC];
+ else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ q_data = &ctx->q_data[V4L2_DST];
+ else
+ return -EINVAL;
+
+ return (vb2_expbuf(&q_data->vb2_q,
+ buf
+ ));
+}
+
+static int v4l2_ioctl_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub
+ )
+{
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ switch (sub->type) {
+ case V4L2_EVENT_EOS:
+ return v4l2_event_subscribe(fh, sub, 0, NULL);
+ case V4L2_EVENT_SOURCE_CHANGE:
+ return v4l2_src_change_event_subscribe(fh, sub);
+ default:
+ return -EINVAL;
+ }
+}
+static void alloc_mbi_buffer(struct vpu_ctx *ctx,
+ struct queue_data *This,
+ u_int32 count)
+{
+ u_int32 uAlign = 0x800-1;
+ u_int32 mbi_num;
+ u_int32 mbi_size;
+ u_int32 i;
+
+
+ if (count >= MAX_MBI_NUM)
+ mbi_num = MAX_MBI_NUM;
+ else
+ mbi_num = count;
+ ctx->mbi_num = mbi_num;
+
+ mbi_size = (This->sizeimage[0]+This->sizeimage[1])/4;
+ mbi_size = ((mbi_size + uAlign) & ~uAlign);
+ ctx->mbi_size = mbi_size;
+ for (i = 0; i < mbi_num; i++) {
+ ctx->mbi_dma_virt[i] = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+ ctx->mbi_size,
+ (dma_addr_t *)&ctx->mbi_dma_phy[i],
+ GFP_KERNEL | GFP_DMA32
+ );
+ if (!ctx->mbi_dma_virt[i])
+ vpu_dbg(LVL_ERR, "error: %s() mbi buffer alloc size(%x) fail!\n", __func__, mbi_size);
+ }
+}
+static int v4l2_ioctl_reqbufs(struct file *file,
+ void *fh,
+ struct v4l2_requestbuffers *reqbuf
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct queue_data *q_data;
+ u_int32 i;
+ int ret;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ q_data = &ctx->q_data[V4L2_SRC];
+ else if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ q_data = &ctx->q_data[V4L2_DST];
+ else
+ return -EINVAL;
+
+ if (reqbuf->count == 0)
+ ctx->buffer_null = true;
+ else
+ ctx->buffer_null = false;
+
+ ret = vb2_reqbufs(&q_data->vb2_q, reqbuf);
+ if (!ret) {
+ if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (reqbuf->count == 0) {
+ for (i = 0; i < MAX_MBI_NUM; i++)
+ if (ctx->mbi_dma_virt[i] != NULL) {
+ dma_free_coherent(&ctx->dev->plat_dev->dev,
+ ctx->mbi_size,
+ ctx->mbi_dma_virt[i],
+ ctx->mbi_dma_phy[i]
+ );
+ ctx->mbi_dma_virt[i] = NULL;
+ }
+ } else {
+ for (i = 0; i < reqbuf->count; i++)
+ q_data->vb2_reqs[i].status = FRAME_ALLOC;
+ alloc_mbi_buffer(ctx, q_data, reqbuf->count);
+ }
+ }
+ } else if (reqbuf->count != 0)
+ vpu_dbg(LVL_ERR, "error: %s() can't request (%d) buffer ret=%d\n", __func__, reqbuf->count, ret);
+
+ return ret;
+}
+
+static int v4l2_ioctl_querybuf(struct file *file,
+ void *fh,
+ struct v4l2_buffer *buf
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct queue_data *q_data;
+ unsigned int i;
+ int ret;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ q_data = &ctx->q_data[V4L2_SRC];
+ else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ q_data = &ctx->q_data[V4L2_DST];
+ else
+ return -EINVAL;
+
+ ret = vb2_querybuf(&q_data->vb2_q, buf);
+ if (!ret) {
+ if (buf->memory == V4L2_MEMORY_MMAP) {
+ if (V4L2_TYPE_IS_MULTIPLANAR(buf->type)) {
+ for (i = 0; i < buf->length; i++)
+ buf->m.planes[i].m.mem_offset |= (q_data->type << MMAP_BUF_TYPE_SHIFT);
+ } else
+ buf->m.offset |= (q_data->type << MMAP_BUF_TYPE_SHIFT);
+ }
+ } else
+ vpu_dbg(LVL_ERR, "error: %s() return ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int v4l2_ioctl_qbuf(struct file *file,
+ void *fh,
+ struct v4l2_buffer *buf
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct queue_data *q_data;
+ int ret;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ vpu_dbg(LVL_INFO, "%s: input %d bytes \n", __func__, buf->m.planes[0].bytesused);
+ q_data = &ctx->q_data[V4L2_SRC];
+ v4l2_update_stream_addr(ctx, 0);
+ } else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ q_data = &ctx->q_data[V4L2_DST];
+ else
+ return -EINVAL;
+
+ ret = vb2_qbuf(&q_data->vb2_q, buf);
+ if (!ret) {
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ wake_up_interruptible(&ctx->buffer_wq);
+ v4l2_update_stream_addr(ctx, 0);
+ } else
+ vpu_dbg(LVL_ERR, "error: %s() return ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int v4l2_ioctl_dqbuf(struct file *file,
+ void *fh,
+ struct v4l2_buffer *buf
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct queue_data *q_data;
+ int ret;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ q_data = &ctx->q_data[V4L2_SRC];
+ else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ q_data = &ctx->q_data[V4L2_DST];
+ else
+ return -EINVAL;
+
+ ret = vb2_dqbuf(&q_data->vb2_q, buf, file->f_flags & O_NONBLOCK);
+
+ if (!ret) {
+ if (q_data->vb2_reqs[buf->index].bfield)
+ buf->field = V4L2_FIELD_INTERLACED;
+ else
+ buf->field = V4L2_FIELD_NONE;
+ v4l2_update_stream_addr(ctx, 0);
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ if ((ctx->pSeqinfo->uBitDepthLuma > 8) || (ctx->pSeqinfo->uBitDepthChroma > 8))
+ buf->reserved = 1;
+ } else
+ vpu_dbg(LVL_ERR, "error: %s() return ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static bool format_is_support(struct vpu_v4l2_fmt *format_table,
+ unsigned int table_size,
+ struct v4l2_format *f)
+{
+ unsigned int i;
+
+ for (i = 0; i < table_size; i++) {
+ if (format_table[i].fourcc == f->fmt.pix_mp.pixelformat)
+ return true;
+ }
+ return false;
+}
+
+static int v4l2_ioctl_try_fmt(struct file *file,
+ void *fh,
+ struct v4l2_format *f
+ )
+{
+ unsigned int table_size;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ table_size = ARRAY_SIZE(formats_compressed_dec);
+ if (!format_is_support(formats_compressed_dec, table_size, f))
+ return -EINVAL;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ table_size = ARRAY_SIZE(formats_yuv_dec);
+ if (!format_is_support(formats_yuv_dec, table_size, f))
+ return -EINVAL;
+ } else
+ return -EINVAL;
+
+ return 0;
+}
+
+static int v4l2_ioctl_g_crop(struct file *file,
+ void *fh,
+ struct v4l2_crop *cr
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+ cr->c.left = ctx->pSeqinfo->uFrameCropLeftOffset;
+ cr->c.top = ctx->pSeqinfo->uFrameCropTopOffset;
+ cr->c.width = ctx->pSeqinfo->uHorRes;
+ cr->c.height = ctx->pSeqinfo->uVerRes;
+
+ return 0;
+}
+
+static int v4l2_ioctl_decoder_cmd(struct file *file,
+ void *fh,
+ struct v4l2_decoder_cmd *cmd
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ switch (cmd->cmd) {
+ case V4L2_DEC_CMD_START:
+ break;
+ case V4L2_DEC_CMD_STOP: {
+ vpu_dbg(LVL_EVENT, "ctx[%d]: receive V4L2_DEC_CMD_STOP\n", ctx->str_index);
+ if (!ctx->firmware_stopped) {
+ vpu_dbg(LVL_EVENT, "ctx[%d]: insert eos directly\n", ctx->str_index);
+ ctx->eos_stop_added = true;
+ v4l2_update_stream_addr(ctx, 0);
+ add_scode(ctx, 0, EOS_PADDING_TYPE);
+ } else {
+ vpu_dbg(LVL_ERR, "Firmware already stopped !\n");
+ }
+ } break;
+ case V4L2_DEC_CMD_PAUSE:
+ break;
+ case V4L2_DEC_CMD_RESUME:
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int v4l2_ioctl_streamon(struct file *file,
+ void *fh,
+ enum v4l2_buf_type i
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct queue_data *q_data;
+ int ret;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ q_data = &ctx->q_data[V4L2_SRC];
+ else if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ q_data = &ctx->q_data[V4L2_DST];
+ else
+ return -EINVAL;
+
+ ctx->firmware_finished = false;
+
+ ret = vb2_streamon(&q_data->vb2_q, i);
+ if (!ret) {
+ if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ wake_up_interruptible(&ctx->buffer_wq);
+
+ v4l2_update_stream_addr(ctx, 0);
+ } else
+ vpu_dbg(LVL_ERR, "error: %s() return ret=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int v4l2_ioctl_streamoff(struct file *file,
+ void *fh,
+ enum v4l2_buf_type i
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct queue_data *q_data;
+ int ret;
+
+ vpu_dbg(LVL_EVENT, "%s(): ctx[%d]\n", __func__, ctx->str_index);
+
+ if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ q_data = &ctx->q_data[V4L2_SRC];
+ else if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ q_data = &ctx->q_data[V4L2_DST];
+ else
+ return -EINVAL;
+
+ if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (ctx->firmware_stopped) {
+ vpu_dbg(LVL_ERR, "v4l2_ioctl_streamoff() - IGNORE - stopped(%d), finished(%d), eos_added(%d)\n",
+ ctx->firmware_stopped, ctx->firmware_finished, ctx->eos_stop_added);
+ } else {
+ ctx->wait_rst_done = true;
+ vpu_dbg(LVL_INFO, "v4l2_ioctl_streamoff(): send VID_API_CMD_ABORT\n");
+
+ v4l2_vpu_send_cmd(ctx, ctx->str_index, VID_API_CMD_ABORT, 0, NULL);
+
+ wake_up_interruptible(&ctx->buffer_wq);
+ if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) {
+ mutex_lock(&ctx->dev->dev_mutex);
+ set_bit(ctx->str_index, &ctx->dev->hang_mask);
+ mutex_unlock(&ctx->dev->dev_mutex);
+
+ vpu_dbg(LVL_ERR, "the path id:%d firmware hang after send VID_API_CMD_ABORT, stopped(%d), finished(%d), eos_added(%d)\n", ctx->str_index,
+ ctx->firmware_stopped, ctx->firmware_finished, ctx->eos_stop_added);
+ }
+ vpu_dbg(LVL_INFO, "receive abort done\n");
+ }
+ }
+
+ ret = vb2_streamoff(&q_data->vb2_q,
+ i);
+
+ if (ctx->dev->hang_mask & (1 << ctx->str_index)) {
+ vpu_dbg(LVL_ERR, "%s(): not succeed and some instance are blocked\n", __func__);
+ return -EINVAL;
+ } else if (ctx->firmware_stopped) {
+ vpu_dbg(LVL_ERR, "%s(): not succeed and firmware is stopped\n", __func__);
+ return -EINVAL;
+ } else
+ return ret;
+}
+
+static const struct v4l2_ioctl_ops v4l2_decoder_ioctl_ops = {
+ .vidioc_querycap = v4l2_ioctl_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = v4l2_ioctl_enum_fmt_vid_cap_mplane,
+ .vidioc_enum_fmt_vid_out_mplane = v4l2_ioctl_enum_fmt_vid_out_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = v4l2_ioctl_g_fmt,
+ .vidioc_g_fmt_vid_out_mplane = v4l2_ioctl_g_fmt,
+ .vidioc_try_fmt_vid_cap_mplane = v4l2_ioctl_try_fmt,
+ .vidioc_try_fmt_vid_out_mplane = v4l2_ioctl_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = v4l2_ioctl_s_fmt,
+ .vidioc_s_fmt_vid_out_mplane = v4l2_ioctl_s_fmt,
+ .vidioc_expbuf = v4l2_ioctl_expbuf,
+ .vidioc_g_crop = v4l2_ioctl_g_crop,
+ .vidioc_decoder_cmd = v4l2_ioctl_decoder_cmd,
+ .vidioc_subscribe_event = v4l2_ioctl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+ .vidioc_reqbufs = v4l2_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_ioctl_querybuf,
+ .vidioc_qbuf = v4l2_ioctl_qbuf,
+ .vidioc_dqbuf = v4l2_ioctl_dqbuf,
+ .vidioc_streamon = v4l2_ioctl_streamon,
+ .vidioc_streamoff = v4l2_ioctl_streamoff,
+};
+
+// Set/Get controls - v4l2 control framework
+
+static struct vpu_v4l2_control vpu_controls_dec[] = {
+ {
+ .id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 32,
+ .step = 1,
+ .default_value = 4,
+ .is_volatile = true,
+ },
+};
+
+#define NUM_CTRLS_DEC ARRAY_SIZE(vpu_controls_dec)
+
+static int v4l2_dec_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ switch (ctrl->id) {
+ default:
+ vpu_dbg(LVL_INFO, "%s() Invalid control(%d)\n",
+ __func__, ctrl->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int v4l2_dec_g_v_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+
+ vpu_dbg(LVL_INFO, "%s() control(%d)\n",
+ __func__, ctrl->id);
+
+ switch (ctrl->id) {
+ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
+ ctrl->val = ctx->pSeqinfo->uNumDPBFrms + ctx->pSeqinfo->uNumRefFrms;
+ break;
+ default:
+ vpu_dbg(LVL_INFO, "%s() Invalid control(%d)\n",
+ __func__, ctrl->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops vpu_dec_ctrl_ops = {
+ .s_ctrl = v4l2_dec_s_ctrl,
+ .g_volatile_ctrl = v4l2_dec_g_v_ctrl,
+};
+
+static int ctrls_setup_decoder(struct vpu_ctx *This)
+{
+ int i;
+
+ v4l2_ctrl_handler_init(&This->ctrl_handler,
+ NUM_CTRLS_DEC + 1
+ );
+ if (This->ctrl_handler.error) {
+ vpu_dbg(LVL_ERR, "%s() v4l2_ctrl_handler_init failed(%d)\n",
+ __func__, This->ctrl_handler.error);
+
+ return This->ctrl_handler.error;
+ } else {
+ vpu_dbg(LVL_INFO, "%s() v4l2_ctrl_handler_init ctrls(%ld)\n",
+ __func__, NUM_CTRLS_DEC);
+ This->ctrl_inited = true;
+ }
+
+ for (i = 0; i < NUM_CTRLS_DEC; i++) {
+ This->ctrls[i] = v4l2_ctrl_new_std(&This->ctrl_handler,
+ &vpu_dec_ctrl_ops,
+ vpu_controls_dec[i].id,
+ vpu_controls_dec[i].minimum,
+ vpu_controls_dec[i].maximum,
+ vpu_controls_dec[i].step,
+ vpu_controls_dec[i].default_value
+ );
+ if (This->ctrl_handler.error ||
+ !This->ctrls[i]
+ ) {
+ vpu_dbg(LVL_ERR, "%s() v4l2_ctrl_new_std failed(%d) This->ctrls[%d](%p)\n",
+ __func__, This->ctrl_handler.error, i, This->ctrls[i]);
+ return This->ctrl_handler.error;
+ }
+
+ if (vpu_controls_dec[i].is_volatile &&
+ This->ctrls[i]
+ )
+ This->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE;
+ }
+
+ v4l2_ctrl_handler_setup(&This->ctrl_handler);
+
+ return 0;
+}
+
+static void ctrls_delete_decoder(struct vpu_ctx *This)
+{
+ int i;
+
+ if (This->ctrl_inited) {
+ v4l2_ctrl_handler_free(&This->ctrl_handler);
+ This->ctrl_inited = false;
+ }
+ for (i = 0; i < NUM_CTRLS_DEC; i++)
+ This->ctrls[i] = NULL;
+}
+
+/* Insert either the codec specific EOS type or a special scode to mark that this frame should be flushed/pushed directly for decode */
+static bool add_scode(struct vpu_ctx *ctx, u_int32 uStrBufIdx, VPU_PADDING_SCODE_TYPE eScodeType)
+{
+ struct vpu_dev *dev = ctx->dev;
+ pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ uint32_t start;
+ uint32_t end;
+ uint32_t wptr;
+ uint32_t rptr;
+ uint8_t *pbbuffer;
+ uint32_t *plbuffer;
+ uint32_t last;
+ uint32_t last2 = 0x0;
+ uint32_t pad_bytes;
+ static uint8_t *buffer;
+
+ vpu_dbg(LVL_INFO, "enter %s\n", __func__);
+ pStrBufDesc = ctx->dev->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * ctx->str_index;
+ start = pStrBufDesc->start;
+ end = pStrBufDesc->end;
+ wptr = pStrBufDesc->wptr;
+ rptr = pStrBufDesc->rptr;
+
+ buffer = kzalloc(MIN_SPACE, GFP_KERNEL); //for eos data
+ if (!buffer) {
+ vpu_dbg(LVL_ERR, "error: eos buffer alloc fail\n");
+ return false;
+ }
+ plbuffer = (uint32_t *)buffer;
+ if (wptr - start < ctx->stream_buffer_size)
+ pbbuffer = (uint8_t *)(ctx->stream_buffer_virt + wptr - start);
+ else {
+ vpu_dbg(LVL_ERR, "error: return wptr(0x%x), start(0x%x) is not valid\n", wptr, start);
+ return false;
+ }
+
+ // Word align
+ if (((u_int64)pbbuffer)%4 != 0) {
+ int i;
+ if (end%4 != 0) {
+ vpu_dbg(LVL_ERR, "end address of stream not aligned by 4 bytes !\n");
+ return false;
+ }
+ pad_bytes = 4 - (((u_int64)pbbuffer)%4);
+ for (i = 0; i < pad_bytes; i++)
+ pbbuffer[i] = 0;
+ pbbuffer += pad_bytes;
+ wptr += pad_bytes;
+ if (wptr == end) {
+ wptr = start;
+ pbbuffer = (uint8_t *)ctx->stream_buffer_virt;
+ }
+ }
+
+ if (eScodeType == EOS_PADDING_TYPE) {
+ switch (q_data->vdec_std) {
+ case VPU_VIDEO_AVC:
+ last = 0x0B010000;
+ break;
+ case VPU_VIDEO_VC1:
+ last = 0x0a010000;
+ break;
+ case VPU_VIDEO_MPEG2:
+ //last = 0xb7010000;
+ last = EOS_GENERIC_MPEG;
+ break;
+ case VPU_VIDEO_ASP:
+ last = 0xb1010000;
+ break;
+ case VPU_VIDEO_SPK:
+ case VPU_VIDEO_VP6:
+ case VPU_VIDEO_VP8:
+ case VPU_VIDEO_RV:
+ last = 0x34010000;
+ break;
+ case VPU_VIDEO_JPEG:
+ last = EOS_GENERIC_JPEG;
+ break;
+ case VPU_VIDEO_HEVC:
+ last = 0x4A010000;
+ last2 = 0x20;
+ break;
+ default:
+ last = 0x0;
+ break;
+ }
+ } else {
+ if (q_data->vdec_std == VPU_VIDEO_AVC) {
+ last = 0x15010000;
+ last2 = 0x0;
+ } else {
+ /* all other standards do not support the frame flush mechanism so just return */
+ vpu_dbg(LVL_WARN, "warning: format(%d) not support frame flush mechanism !\n", q_data->vdec_std);
+ return true;
+ }
+ }
+ plbuffer[0] = last;
+ plbuffer[1] = last2;
+
+#if 0
+ for (i = 2; i < MIN_SPACE >> 2; i++)
+ plbuffer[i] = 0;
+#endif
+
+ if ((wptr == rptr) || (wptr > rptr)) {
+ if (end - wptr >= MIN_SPACE) {
+ memcpy(pbbuffer, buffer, MIN_SPACE);
+ wptr += MIN_SPACE;
+ if (wptr == end)
+ wptr = start;
+ } else {
+ memcpy(pbbuffer, buffer, end-wptr);
+ memcpy(ctx->stream_buffer_virt, buffer + (end-wptr), MIN_SPACE - (end-wptr));
+ wptr = start + MIN_SPACE-(end-wptr);
+ }
+ } else {
+ if (rptr - wptr >= MIN_SPACE) {
+ memcpy(pbbuffer, buffer, MIN_SPACE);
+ wptr += MIN_SPACE;
+ } else {
+ //shouldn't enter here: suppose space is enough since add_eos() only be called in FIFO LOW
+ memcpy(pbbuffer, buffer, rptr - wptr);
+ wptr += (rptr - wptr);
+ vpu_dbg(LVL_ERR, "No enough space to insert EOS !\n");
+ }
+ }
+ mb();
+
+ pStrBufDesc->wptr = wptr;
+ dev->shared_mem.pSharedInterface->pStreamBuffDesc[ctx->str_index][uStrBufIdx] =
+ (VPU_REG_BASE + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * ctx->str_index);
+ kfree(buffer);
+ vpu_dbg(LVL_INFO, "add_scode done type (%d) MCX address virt=%p, phy=0x%x, index=%d\n", eScodeType, pStrBufDesc, dev->shared_mem.pSharedInterface->pStreamBuffDesc[ctx->str_index][uStrBufIdx], ctx->str_index);
+ return true;
+}
+
+TB_API_DEC_FMT vpu_format_remap(uint32_t vdec_std)
+{
+ TB_API_DEC_FMT malone_format = VSys_FrmtNull;
+
+ switch (vdec_std) {
+ case VPU_VIDEO_AVC:
+ malone_format = VSys_AvcFrmt;
+ vpu_dbg(LVL_INFO, "format translated to AVC");
+ break;
+ case VPU_VIDEO_VC1:
+ malone_format = VSys_Vc1Frmt;
+ vpu_dbg(LVL_INFO, "format translated to VC1");
+ break;
+ case VPU_VIDEO_MPEG2:
+ malone_format = VSys_Mp2Frmt;
+ vpu_dbg(LVL_INFO, "format translated to MP2");
+ break;
+ case VPU_VIDEO_AVS:
+ malone_format = VSys_AvsFrmt;
+ vpu_dbg(LVL_INFO, "format translated to AVS");
+ break;
+ case VPU_VIDEO_ASP:
+ malone_format = VSys_AspFrmt;
+ vpu_dbg(LVL_INFO, "format translated to ASP");
+ break;
+ case VPU_VIDEO_JPEG:
+ malone_format = VSys_JpgFrmt;
+ vpu_dbg(LVL_INFO, "format translated to JPG");
+ break;
+ case VPU_VIDEO_VP6:
+ malone_format = VSys_Vp6Frmt;
+ vpu_dbg(LVL_INFO, "format translated to VP6");
+ break;
+ case VPU_VIDEO_SPK:
+ malone_format = VSys_SpkFrmt;
+ vpu_dbg(LVL_INFO, "format translated to SPK");
+ break;
+ case VPU_VIDEO_VP8:
+ malone_format = VSys_Vp8Frmt;
+ vpu_dbg(LVL_INFO, "format translated to VP8");
+ break;
+ case VPU_VIDEO_HEVC:
+ malone_format = VSys_HevcFrmt;
+ vpu_dbg(LVL_INFO, "format translated to HEVC");
+ break;
+ case VPU_VIDEO_RV:
+ malone_format = VSys_RvFrmt;
+ vpu_dbg(LVL_INFO, "format translated to RV");
+ break;
+ case VPU_VIDEO_AVC_MVC:
+ malone_format = VSys_AvcFrmt;
+ vpu_dbg(LVL_INFO, "format translated to AVC");
+ break;
+ default:
+ malone_format = VSys_FrmtNull;
+ vpu_dbg(LVL_INFO, "unspport format");
+ break;
+ }
+ vpu_dbg(LVL_INFO, "\n");
+
+ return malone_format;
+}
+
+static void v4l2_vpu_send_cmd(struct vpu_ctx *ctx, uint32_t idx, uint32_t cmdid, uint32_t cmdnum, uint32_t *local_cmddata)
+{
+ vpu_log_cmd(cmdid, idx);
+ mutex_lock(&ctx->dev->cmd_mutex);
+ rpc_send_cmd_buf(&ctx->dev->shared_mem, idx, cmdid, cmdnum, local_cmddata);
+ mutex_unlock(&ctx->dev->cmd_mutex);
+ mb();
+ MU_SendMessage(ctx->dev->mu_base_virtaddr, 0, COMMAND);
+}
+
+static void transfer_buffer_to_firmware(struct vpu_ctx *ctx, void *input_buffer, uint32_t buffer_size, uint32_t vdec_std)
+{
+ pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+ u_int32 uStrBufIdx = 0; //set to be default 0, FIX_ME later
+ MediaIPFW_Video_UData *pUdataBuf =
+ &ctx->dev->shared_mem.pSharedInterface->UDataBuffer[ctx->str_index];
+ pDEC_RPC_HOST_IFACE pSharedInterface = ctx->dev->shared_mem.pSharedInterface;
+ unsigned int *CurrStrfg = &pSharedInterface->StreamConfig[ctx->str_index];
+ u_int32 length;
+
+ vpu_dbg(LVL_INFO, "enter %s, start_flag %d, index=%d, firmware_started=%d\n", __func__, ctx->start_flag, ctx->str_index, ctx->dev->firmware_started);
+
+ vpu_dbg(LVL_WARN, "firmware version is %d.%d.%d\n", (pSharedInterface->FWVersion & 0x00ff0000) >> 16, (pSharedInterface->FWVersion & 0x0000ff00) >> 8, pSharedInterface->FWVersion & 0x000000ff);
+
+
+ if (ctx->stream_buffer_size < buffer_size + MIN_SPACE)
+ vpu_dbg(LVL_INFO, "circular buffer size is too small\n");
+ length = insert_scode_4_seq(ctx, input_buffer, ctx->stream_buffer_virt, vdec_std, buffer_size);
+ if (length == 0) {
+ memcpy(ctx->stream_buffer_virt + length, input_buffer, buffer_size);
+ length = buffer_size;
+ }
+// memcpy(ctx->stream_buffer_virt + length, input_buffer, buffer_size);
+ vpu_dbg(LVL_INFO, "transfer data from virt 0x%p: size:%d\n", ctx->stream_buffer_virt, buffer_size);
+ mb();
+ pStrBufDesc = ctx->dev->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * ctx->str_index;
+ // CAUTION: wptr must not be end
+ pStrBufDesc->wptr = ctx->stream_buffer_phy + length - ctx->dev->cm_offset;
+ pStrBufDesc->rptr = ctx->stream_buffer_phy - ctx->dev->cm_offset;
+ pStrBufDesc->start = ctx->stream_buffer_phy - ctx->dev->cm_offset;
+ pStrBufDesc->end = ctx->stream_buffer_phy + ctx->stream_buffer_size - ctx->dev->cm_offset;
+ pStrBufDesc->LWM = 0x01;
+
+ ctx->dev->shared_mem.pSharedInterface->pStreamBuffDesc[ctx->str_index][uStrBufIdx] =
+ (VPU_REG_BASE + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * ctx->str_index);
+
+ vpu_dbg(LVL_INFO, "transfer MCX address virt=%p, phy=0x%x, index=%d\n", pStrBufDesc, ctx->dev->shared_mem.pSharedInterface->pStreamBuffDesc[ctx->str_index][uStrBufIdx], ctx->str_index);
+ pUdataBuf->uUDataBase = ctx->udata_buffer_phy - ctx->dev->cm_offset;
+ pUdataBuf->uUDataSlotSize = ctx->udata_buffer_size;
+ VID_STREAM_CONFIG_FORMAT_SET(vpu_format_remap(vdec_std), CurrStrfg);
+ if (vdec_std == VPU_VIDEO_JPEG) {
+ MediaIPFW_Video_JpegParams *pJpgPara;
+
+ pJpgPara = (MediaIPFW_Video_JpegParams *)ctx->dev->shared_mem.jpeg_mem_vir;
+ pJpgPara[ctx->str_index].uJpgMjpegMode = 1; //1:JPGD_MJPEG_MODE_A; 2:JPGD_MJPEG_MODE_B
+ pJpgPara[ctx->str_index].uJpgMjpegInterlaced = 0; //0: JPGD_MJPEG_PROGRESSIVE
+ }
+
+ if (ctx->b_dis_reorder) {
+ /* set the shared memory space control with this */
+ MediaIPFW_Video_CodecParams *pCodecPara;
+
+ add_scode(ctx, 0, BUFFLUSH_PADDING_TYPE);
+ pCodecPara = (MediaIPFW_Video_CodecParams *)ctx->dev->shared_mem.codec_mem_vir;
+ pCodecPara[ctx->str_index].uDispImm = 1;
+ } else {
+ MediaIPFW_Video_CodecParams *pCodecPara;
+
+ pCodecPara = (MediaIPFW_Video_CodecParams *)ctx->dev->shared_mem.codec_mem_vir;
+ pCodecPara[ctx->str_index].uDispImm = 0;
+ }
+
+ /*initialize frame count*/
+ ctx->frm_dis_delay = 1;
+ ctx->frm_dec_delay = 1;
+ ctx->frm_total_num = 1;
+
+}
+
+static void v4l2_transfer_buffer_to_firmware(struct queue_data *This, struct vb2_buffer *vb)
+{
+ struct vpu_ctx *ctx = container_of(This, struct vpu_ctx, q_data[V4L2_SRC]);
+ struct vb2_data_req *p_data_req;
+ void *data_mapped;
+ uint32_t buffer_size = vb->planes[0].bytesused;
+
+ data_mapped = (void *)vb2_plane_vaddr(vb, 0);
+
+ if (ctx->start_flag == true) {
+ transfer_buffer_to_firmware(ctx, data_mapped, buffer_size, This->vdec_std);
+#ifdef HANDLE_EOS
+ if (vb->planes[0].bytesused < vb->planes[0].length)
+ vpu_dbg(LVL_INFO, "v4l2_transfer_buffer_to_firmware - set stream_feed_complete - DEBUG 1\n");
+#endif
+ v4l2_vpu_send_cmd(ctx, ctx->str_index, VID_API_CMD_START, 0, NULL);
+ down(&This->drv_q_lock);
+ p_data_req = list_first_entry(&This->drv_q,
+ typeof(*p_data_req), list);
+ list_del(&p_data_req->list);
+ vb2_buffer_done(p_data_req->vb2_buf,
+ VB2_BUF_STATE_DONE
+ );
+ up(&This->drv_q_lock);
+ ctx->start_flag = false;
+ }
+}
+
+static int update_stream_addr(struct vpu_ctx *ctx, void *input_buffer, uint32_t buffer_size, uint32_t uStrBufIdx)
+{
+ struct vpu_dev *dev = ctx->dev;
+ uint32_t index = ctx->str_index;
+ pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ u_int8 payload_header[256];
+ uint32_t nfreespace = 0;
+ uint32_t wptr;
+ uint32_t rptr;
+ uint32_t start;
+ uint32_t end;
+ void *wptr_virt;
+ uint32_t ret = 1;
+ u_int32 length = 0;
+
+ vpu_dbg(LVL_INFO, "enter %s\n", __func__);
+
+ // changed to virtual address and back
+ pStrBufDesc = dev->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * index;
+ vpu_dbg(LVL_INFO, "%s wptr(%x) rptr(%x) start(%x) end(%x) uStrBufIdx(%d)\n",
+ __func__,
+ pStrBufDesc->wptr,
+ pStrBufDesc->rptr,
+ pStrBufDesc->start,
+ pStrBufDesc->end,
+ uStrBufIdx
+ );
+ wptr = pStrBufDesc->wptr;
+ rptr = pStrBufDesc->rptr;
+
+ start = pStrBufDesc->start;
+ end = pStrBufDesc->end;
+ wptr_virt = (void *)ctx->stream_buffer_virt + wptr - start;
+
+ vpu_dbg(LVL_INFO, "update_stream_addr down\n");
+
+ if (wptr == rptr)
+ nfreespace = end - start;
+ if (wptr < rptr)
+ nfreespace = rptr - wptr;
+ if (wptr > rptr)
+ nfreespace = (end - wptr) + (rptr - start);
+
+ if (nfreespace-buffer_size < MIN_SPACE)
+ return 0;
+
+ length = insert_scode_4_pic(ctx, payload_header, input_buffer, q_data->vdec_std, buffer_size);
+
+ if (nfreespace >= buffer_size + length) {
+ if ((wptr == rptr) || (wptr > rptr)) {
+ if (end - wptr >= length) {
+ memcpy(wptr_virt, payload_header, length);
+ wptr += length;
+ wptr_virt += length;
+ if (wptr == end) {
+ wptr = start;
+ wptr_virt = (void *)ctx->stream_buffer_virt;
+ }
+ } else {
+ memcpy(wptr_virt, payload_header, end-wptr);
+ memcpy(ctx->stream_buffer_virt, payload_header + (end-wptr), length - (end-wptr));
+ wptr = start + length - (end-wptr);
+ wptr_virt = (void *)ctx->stream_buffer_virt + length - (end-wptr);
+ }
+ if (end - wptr >= buffer_size) {
+ memcpy(wptr_virt, input_buffer, buffer_size);
+ wptr += buffer_size;
+ if (wptr == end)
+ wptr = start;
+ } else {
+ memcpy(wptr_virt, input_buffer, end-wptr);
+ memcpy(ctx->stream_buffer_virt, input_buffer + (end-wptr), buffer_size - (end-wptr));
+ wptr = start + buffer_size - (end-wptr);
+ }
+ } else {
+ memcpy(wptr_virt, input_buffer, buffer_size);
+ wptr += buffer_size;
+ }
+ } else {
+ vpu_dbg(LVL_INFO, "buffer_full: the circular buffer freespace < buffer_size, treat as full");
+ return 0; //do not consider this situation now
+ }
+
+ mb();
+ pStrBufDesc->wptr = wptr;
+ vpu_dbg(LVL_INFO, "update_stream_addr up, wptr 0x%x\n", wptr);
+
+ dev->shared_mem.pSharedInterface->pStreamBuffDesc[index][uStrBufIdx] =
+ (VPU_REG_BASE + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * index);
+
+ vpu_dbg(LVL_INFO, "update address virt=%p, phy=0x%x, index=%d\n", pStrBufDesc, dev->shared_mem.pSharedInterface->pStreamBuffDesc[ctx->str_index][uStrBufIdx], ctx->str_index);
+ return ret;
+}
+//warn uStrIdx need to refine how to handle it
+static void v4l2_update_stream_addr(struct vpu_ctx *ctx, uint32_t uStrBufIdx)
+{
+ struct vb2_data_req *p_data_req;
+ struct queue_data *This = &ctx->q_data[V4L2_SRC];
+ void *input_buffer;
+ uint32_t buffer_size;
+
+ down(&This->drv_q_lock);
+ while (!list_empty(&This->drv_q) && (ctx->frm_dec_delay < vpu_frm_depth)) {
+ p_data_req = list_first_entry(&This->drv_q,
+ typeof(*p_data_req), list);
+
+ buffer_size = p_data_req->vb2_buf->planes[0].bytesused;
+ input_buffer = (void *)vb2_plane_vaddr(p_data_req->vb2_buf, 0);
+ if (!update_stream_addr(ctx, input_buffer, buffer_size, uStrBufIdx)) {
+ up(&This->drv_q_lock);
+ vpu_dbg(LVL_INFO, " %s no space to write\n", __func__);
+ return;
+ } else {
+ if (ctx->b_dis_reorder) {
+ /* frame successfully written into the stream buffer if in special low latency mode
+ mark that this frame should be flushed for decode immediately */
+ add_scode(ctx, 0, BUFFLUSH_PADDING_TYPE);
+ }
+ ctx->frm_dec_delay++;
+ ctx->frm_dis_delay++;
+ ctx->frm_total_num++;
+ }
+#ifdef HANDLE_EOS
+ if (buffer_size < p_data_req->vb2_buf->planes[0].length)
+ vpu_dbg(LVL_INFO, "v4l2_transfer_buffer_to_firmware - set stream_feed_complete - DEBUG 2\n");
+#endif
+ list_del(&p_data_req->list);
+ vb2_buffer_done(p_data_req->vb2_buf,
+ VB2_BUF_STATE_DONE
+ );
+ }
+ up(&This->drv_q_lock);
+
+}
+
+static void report_buffer_done(struct vpu_ctx *ctx, void *frame_info)
+{
+ struct vb2_data_req *p_data_req;
+ struct queue_data *This = &ctx->q_data[V4L2_DST];
+ u_int32 *FrameInfo = (u_int32 *)frame_info;
+ u_int32 fs_id = FrameInfo[0x0];
+ uint32_t stride = FrameInfo[3];
+ bool b10BitFormat = (ctx->pSeqinfo->uBitDepthLuma > 8) || (ctx->pSeqinfo->uBitDepthChroma > 8);
+ int buffer_id;
+
+ vpu_dbg(LVL_INFO, "report_buffer_done fs_id=%d, ulFsLumaBase[0]=%x, stride=%d, b10BitFormat=%d, ctx->pSeqinfo->uBitDepthLuma=%d\n", fs_id, FrameInfo[1], stride, b10BitFormat, ctx->pSeqinfo->uBitDepthLuma);
+ v4l2_update_stream_addr(ctx, 0);
+
+ buffer_id = find_buffer_id(ctx, FrameInfo[1]);
+
+ if (buffer_id == -1)
+ return;
+
+ if (buffer_id != fs_id)
+ vpu_dbg(LVL_ERR, "error: find buffer_id(%d) and firmware return id(%d) doesn't match\n",
+ buffer_id, fs_id);
+ if (ctx->q_data[V4L2_DST].vb2_reqs[buffer_id].status != FRAME_DECODED)
+ vpu_dbg(LVL_ERR, "error: buffer(%d) need to set FRAME_READY, but previous state %s is not FRAME_DECODED\n",
+ buffer_id, bufstat[ctx->q_data[V4L2_DST].vb2_reqs[buffer_id].status]);
+
+ ctx->q_data[V4L2_DST].vb2_reqs[buffer_id].status = FRAME_READY;
+ ctx->frm_dis_delay--;
+ vpu_dbg(LVL_INFO, "frame total: %d; depth: %d; delay: [dec, dis] = [%d, %d]\n", ctx->frm_total_num,
+ vpu_frm_depth, ctx->frm_dec_delay, ctx->frm_dis_delay);
+
+ down(&This->drv_q_lock);
+ p_data_req = &This->vb2_reqs[buffer_id];
+ p_data_req->vb2_buf->planes[0].bytesused = This->sizeimage[0];
+ p_data_req->vb2_buf->planes[1].bytesused = This->sizeimage[1];
+ if (p_data_req->vb2_buf->state == VB2_BUF_STATE_ACTIVE)
+ vb2_buffer_done(p_data_req->vb2_buf,
+ VB2_BUF_STATE_DONE
+ );
+ else
+ vpu_dbg(LVL_ERR, "warning: wait_rst_done(%d) check buffer(%d) state(%d)\n", ctx->wait_rst_done, buffer_id, p_data_req->vb2_buf->state);
+ up(&This->drv_q_lock);
+ vpu_dbg(LVL_INFO, "leave %s\n", __func__);
+}
+
+/*
+ * this is used for waiting the right status buffer in the queue list
+ * true means find right buffer, false means not
+ */
+static bool wait_right_buffer(struct queue_data *This)
+{
+ struct vb2_data_req *p_data_req, *p_temp;
+
+ down(&This->drv_q_lock);
+ if (!list_empty(&This->drv_q)) {
+ list_for_each_entry_safe(p_data_req, p_temp, &This->drv_q, list)
+ if (p_data_req->status == FRAME_ALLOC
+ || p_data_req->status == FRAME_RELEASE) {
+ up(&This->drv_q_lock);
+ return true;
+ }
+ }
+ up(&This->drv_q_lock);
+
+ return false;
+}
+
+static void vpu_api_event_handler(struct vpu_ctx *ctx, u_int32 uStrIdx, u_int32 uEvent, u_int32 *event_data)
+{
+ struct vpu_dev *dev;
+ pDEC_RPC_HOST_IFACE pSharedInterface;
+
+ vpu_log_event(uEvent, uStrIdx);
+
+ if (ctx == NULL) {
+ vpu_dbg(LVL_ERR, "receive event: 0x%X after instance released, ignore it\n", uEvent);
+ return;
+ }
+
+ if (ctx->firmware_stopped) {
+ vpu_dbg(LVL_ERR, "receive event: 0x%X after stopped, ignore it\n", uEvent);
+ return;
+ }
+ dev = ctx->dev;
+ pSharedInterface = (pDEC_RPC_HOST_IFACE)dev->shared_mem.shared_mem_vir;
+
+ switch (uEvent) {
+ case VID_API_EVENT_START_DONE:
+ break;
+ case VID_API_EVENT_STOPPED: {
+ vpu_dbg(LVL_INFO, "receive VID_API_EVENT_STOPPED\n");
+ ctx->firmware_stopped = true;
+ complete(&ctx->completion);//reduce possibility of abort hang if decoder enter stop automatically
+ complete(&ctx->stop_cmp);
+ }
+ break;
+ case VID_API_EVENT_RESET_DONE:
+ break;
+ case VID_API_EVENT_PIC_DECODED: {
+ MediaIPFW_Video_QMeterInfo *pQMeterInfo = (MediaIPFW_Video_QMeterInfo *)dev->shared_mem.qmeter_mem_vir;
+ MediaIPFW_Video_PicInfo *pPicInfo = (MediaIPFW_Video_PicInfo *)dev->shared_mem.pic_mem_vir;
+ MediaIPFW_Video_PicDispInfo *pDispInfo = &pPicInfo[uStrIdx].DispInfo;
+ MediaIPFW_Video_PicPerfInfo *pPerfInfo = &pPicInfo[uStrIdx].PerfInfo;
+ MediaIPFW_Video_PicPerfDcpInfo *pPerfDcpInfo = &pPicInfo[uStrIdx].PerfDcpInfo;
+ int buffer_id;
+ u_int32 uDecFrmId = event_data[7];
+ u_int32 uPicStartAddr = event_data[10];
+ struct queue_data *This = &ctx->q_data[V4L2_DST];
+ u_int32 uDpbmcCrc;
+
+ if (ctx->buffer_null == true) {
+ vpu_dbg(LVL_INFO, "frame already released\n");
+ break;
+ }
+
+ if (This->vdec_std == VPU_VIDEO_HEVC)
+ uDpbmcCrc = pPerfDcpInfo->uDBEDpbCRC[0];
+ else
+ uDpbmcCrc = pPerfInfo->uMemCRC;
+ vpu_dbg(LVL_INFO, "PICINFO GET: uPicType:%d uPicStruct:%d uPicStAddr:0x%x uFrameStoreID:%d uPercentInErr:%d, uRbspBytesCount=%d, ulLumBaseAddr[0]=%x, pQMeterInfo:%p, pPicInfo:%p, pDispInfo:%p, pPerfInfo:%p, pPerfDcpInfo:%p, uPicStartAddr=0x%x, uDpbmcCrc:%x\n",
+ pPicInfo[uStrIdx].uPicType, pPicInfo[uStrIdx].uPicStruct,
+ pPicInfo[uStrIdx].uPicStAddr, pPicInfo[uStrIdx].uFrameStoreID,
+ pPicInfo[uStrIdx].uPercentInErr, pPerfInfo->uRbspBytesCount, event_data[0],
+ pQMeterInfo, pPicInfo, pDispInfo, pPerfInfo, pPerfDcpInfo, uPicStartAddr, uDpbmcCrc);
+
+ buffer_id = find_buffer_id(ctx, event_data[0]);
+
+ if (buffer_id == -1)
+ break;
+
+ if (buffer_id != uDecFrmId)
+ vpu_dbg(LVL_ERR, "error: VID_API_EVENT_PIC_DECODED address and id doesn't match\n");
+ if (ctx->q_data[V4L2_DST].vb2_reqs[buffer_id].status != FRAME_FREE)
+ vpu_dbg(LVL_ERR, "error: buffer(%d) need to set FRAME_DECODED, but previous state %s is not FRAME_FREE\n",
+ buffer_id, bufstat[ctx->q_data[V4L2_DST].vb2_reqs[buffer_id].status]);
+ ctx->q_data[V4L2_DST].vb2_reqs[buffer_id].status = FRAME_DECODED;
+ if (ctx->pSeqinfo->uProgressive == 1)
+ ctx->q_data[V4L2_DST].vb2_reqs[buffer_id].bfield = false;
+ else
+ ctx->q_data[V4L2_DST].vb2_reqs[buffer_id].bfield = true;
+ }
+ ctx->frm_dec_delay--;
+ break;
+ case VID_API_EVENT_SEQ_HDR_FOUND: {
+ MediaIPFW_Video_SeqInfo *pSeqInfo = (MediaIPFW_Video_SeqInfo *)dev->shared_mem.seq_mem_vir;
+// MediaIPFW_Video_FrameBuffer *pStreamFrameBuffer = &pSharedInterface->StreamFrameBuffer[uStrIdx];
+// MediaIPFW_Video_FrameBuffer *pStreamDCPBuffer = &pSharedInterface->StreamDCPBuffer[uStrIdx];
+ MediaIPFW_Video_PitchInfo *pStreamPitchInfo = &pSharedInterface->StreamPitchInfo[uStrIdx];
+ unsigned int num = pSharedInterface->SeqInfoTabDesc.uNumSizeDescriptors;
+
+ if (ctx->pSeqinfo == NULL)
+ ctx->pSeqinfo = kzalloc(sizeof(MediaIPFW_Video_SeqInfo), GFP_KERNEL);
+ else
+ vpu_dbg(LVL_INFO, "pSeqinfo is not NULL, need not to realloc\n");
+ memcpy(ctx->pSeqinfo, &pSeqInfo[ctx->str_index], sizeof(MediaIPFW_Video_SeqInfo));
+
+ caculate_frame_size(ctx);
+ vpu_dbg(LVL_INFO, "SEQINFO GET: uHorRes:%d uVerRes:%d uHorDecodeRes:%d uVerDecodeRes:%d uNumDPBFrms:%d, num:%d, uNumRefFrms:%d, uNumDFEAreas:%d\n",
+ ctx->pSeqinfo->uHorRes, ctx->pSeqinfo->uVerRes,
+ ctx->pSeqinfo->uHorDecodeRes, ctx->pSeqinfo->uVerDecodeRes,
+ ctx->pSeqinfo->uNumDPBFrms, num, ctx->pSeqinfo->uNumRefFrms, ctx->pSeqinfo->uNumDFEAreas);
+ if (ctx->b_firstseq) {
+ const struct v4l2_event ev = {
+ .type = V4L2_EVENT_SOURCE_CHANGE,
+ .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION
+ };
+ v4l2_event_queue_fh(&ctx->fh, &ev);
+
+ pStreamPitchInfo->uFramePitch = 0x4000;
+ ctx->b_firstseq = false;
+ }
+ }
+ break;
+ case VID_API_EVENT_PIC_HDR_FOUND:
+ break;
+ case VID_API_EVENT_REQ_FRAME_BUFF: {
+ MEDIA_PLAYER_FSREQ *pFSREQ = (MEDIA_PLAYER_FSREQ *)event_data;
+ u_int32 local_cmddata[10];
+ struct vb2_data_req *p_data_req, *p_temp;
+ struct queue_data *This = &ctx->q_data[V4L2_DST];
+ u_int32 LumaAddr, ChromaAddr;
+ u_int32 *pphy_address;
+ struct vb2_data_req;
+ void *dcp_dma_virt;
+ dma_addr_t dcp_dma_phy;
+ bool buffer_flag = false;
+
+ vpu_dbg(LVL_INFO, "VID_API_EVENT_REQ_FRAME_BUFF, type=%d, size=%ld\n", pFSREQ->eType, sizeof(MEDIA_PLAYER_FSREQ));
+ if (pFSREQ->eType == MEDIAIP_DCP_REQ) {
+ if (ctx->dcp_count >= MAX_DCP_NUM) {
+ vpu_dbg(LVL_ERR, "error: request dcp buffers number is over MAX_DCP_NUM\n");
+ break;
+ }
+ ctx->uDCPSize = DCP_SIZE;
+ dcp_dma_virt = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+ ctx->uDCPSize,
+ (dma_addr_t *)&dcp_dma_phy,
+ GFP_KERNEL | GFP_DMA32
+ );
+ if (!dcp_dma_virt)
+ vpu_dbg(LVL_ERR, "error: %s() dcp buffer alloc size(%x) fail!\n", __func__, DCP_SIZE);
+ ctx->dcp_dma_virt[ctx->dcp_count] = dcp_dma_virt;
+ ctx->dcp_dma_phy[ctx->dcp_count] = dcp_dma_phy;
+
+ local_cmddata[0] = ctx->dcp_count;
+ local_cmddata[1] = dcp_dma_phy - ctx->dev->cm_offset;
+ local_cmddata[2] = DCP_SIZE;
+ local_cmddata[3] = 0;
+ local_cmddata[4] = 0;
+ local_cmddata[5] = 0;
+ local_cmddata[6] = pFSREQ->eType;
+ v4l2_vpu_send_cmd(ctx, uStrIdx, VID_API_CMD_FS_ALLOC, 7, local_cmddata);
+ vpu_dbg(LVL_INFO, "VID_API_CMD_FS_ALLOC, eType=%d, index=%d\n", pFSREQ->eType, ctx->dcp_count);
+ ctx->dcp_count++;
+ } else if (pFSREQ->eType == MEDIAIP_MBI_REQ) {
+ if (ctx->mbi_count >= ctx->mbi_num) {
+ vpu_dbg(LVL_ERR, "error: request mbi buffers number(%d) is over allocted buffer number(%d)\n",
+ ctx->mbi_count, ctx->mbi_num);
+ break;
+ }
+ local_cmddata[0] = ctx->mbi_count;
+ local_cmddata[1] = ctx->mbi_dma_phy[ctx->mbi_count] - ctx->dev->cm_offset;
+ local_cmddata[2] = ctx->mbi_size;
+ local_cmddata[3] = 0;
+ local_cmddata[4] = 0;
+ local_cmddata[5] = 0;
+ local_cmddata[6] = pFSREQ->eType;
+ v4l2_vpu_send_cmd(ctx, uStrIdx, VID_API_CMD_FS_ALLOC, 7, local_cmddata);
+ vpu_dbg(LVL_INFO, "VID_API_CMD_FS_ALLOC, eType=%d, index=%d\n", pFSREQ->eType, ctx->mbi_count);
+ ctx->mbi_count++;
+ } else {
+#if 1
+ while (1) {
+ if (!wait_event_interruptible_timeout(ctx->buffer_wq,
+ ((ctx->wait_rst_done == true) || (wait_right_buffer(This) == true)),
+ msecs_to_jiffies(5000))) {
+ vpu_dbg(LVL_ERR, " warn: wait_event_interruptible_timeout wait 5s timeout\n");
+ vpu_log_buffer_state(ctx);
+ } else
+ break;
+ }
+#endif
+
+ if (ctx->buffer_null == true) {
+ vpu_dbg(LVL_INFO, "frame already released\n");
+ break;
+ }
+
+ if (!list_empty(&This->drv_q) && !ctx->wait_rst_done) {
+ down(&This->drv_q_lock);
+ list_for_each_entry_safe(p_data_req, p_temp, &This->drv_q, list) {
+ if (p_data_req->status == FRAME_ALLOC
+ || p_data_req->status == FRAME_RELEASE){
+ pphy_address = (u_int32 *)vb2_plane_cookie(p_data_req->vb2_buf, 0);
+ LumaAddr = *pphy_address;
+ pphy_address = (u_int32 *)vb2_plane_cookie(p_data_req->vb2_buf, 1);
+ ChromaAddr = *pphy_address;
+ vpu_dbg(LVL_INFO, "%s :LumaAddr(%x) ChromaAddr(%x) buf_id (%d)\n",
+ __func__,
+ LumaAddr,
+ ChromaAddr,
+ p_data_req->id
+ );
+ if (!LumaAddr || !ChromaAddr) {
+ LumaAddr = p_data_req->phy_addr[0];
+ ChromaAddr = p_data_req->phy_addr[1];
+ }
+
+ local_cmddata[0] = p_data_req->id;
+ local_cmddata[1] = LumaAddr - ctx->dev->cm_offset;
+ local_cmddata[2] = local_cmddata[1] + This->sizeimage[0]/2;
+ local_cmddata[3] = ChromaAddr - ctx->dev->cm_offset;
+ local_cmddata[4] = local_cmddata[3] + This->sizeimage[1]/2;
+ local_cmddata[5] = ctx->q_data[V4L2_DST].stride;
+ local_cmddata[6] = pFSREQ->eType;
+ //WARN :need to check the call back VID_API_EVENT_REL_FRAME_BUFF later, when it is received, the corepond id can be released, now just do a temporary workaround
+ if (p_data_req->status == FRAME_RELEASE)
+ v4l2_vpu_send_cmd(ctx, uStrIdx, VID_API_CMD_FS_RELEASE, 1, &p_data_req->id);
+ v4l2_vpu_send_cmd(ctx, uStrIdx, VID_API_CMD_FS_ALLOC, 7, local_cmddata);
+ p_data_req->status = FRAME_FREE;
+ vpu_dbg(LVL_INFO, "VID_API_CMD_FS_ALLOC, data_req->vb2_buf=%p, data_req->id=%d\n", p_data_req->vb2_buf, p_data_req->id);
+ list_del(&p_data_req->list);
+ buffer_flag = true;
+ break;
+ } else {
+ vpu_dbg(LVL_INFO, "buffer %d status=0x%x is not right, find next\n", p_data_req->id, p_data_req->status);
+ continue;
+ }
+ }
+ up(&This->drv_q_lock);
+ if (buffer_flag == false && !ctx->firmware_finished)
+ vpu_dbg(LVL_ERR, "error: don't find the right buffer for VID_API_CMD_FS_ALLOC\n");
+ } else if (ctx->wait_rst_done) {
+ u_int32 i;
+
+ for (i = 0; i < VPU_MAX_BUFFER; i++) {
+ p_data_req = &This->vb2_reqs[i];
+ if (p_data_req->status == FRAME_RELEASE)
+ break;
+ }
+ if (ctx->firmware_finished)
+ break;
+ if (i == VPU_MAX_BUFFER) {
+ vpu_dbg(LVL_ERR, "error: don't find buffer when wait_rst_done is true, ctx->firmware_stopped=%dfin=%d\n", ctx->firmware_stopped, ctx->firmware_finished); //wait_rst_done is true when streamoff or v4l2_release is called
+ break;
+ }
+
+ pphy_address = (u_int32 *)vb2_plane_cookie(p_data_req->vb2_buf, 0);
+ LumaAddr = *pphy_address;
+ pphy_address = (u_int32 *)vb2_plane_cookie(p_data_req->vb2_buf, 1);
+ ChromaAddr = *pphy_address;
+ vpu_dbg(LVL_INFO, "%s :LumaAddr(%x) ChromaAddr(%x) buf_id (%d)\n",
+ __func__,
+ LumaAddr,
+ ChromaAddr,
+ p_data_req->id
+ );
+ if (!LumaAddr || !ChromaAddr) {
+ LumaAddr = p_data_req->phy_addr[0];
+ ChromaAddr = p_data_req->phy_addr[1];
+ }
+ local_cmddata[0] = p_data_req->id;
+ local_cmddata[1] = LumaAddr - ctx->dev->cm_offset;
+ local_cmddata[2] = local_cmddata[1] + This->sizeimage[0]/2;
+ local_cmddata[3] = ChromaAddr - ctx->dev->cm_offset;
+ local_cmddata[4] = local_cmddata[3] + This->sizeimage[1]/2;
+ local_cmddata[5] = ctx->q_data[V4L2_DST].stride;
+ local_cmddata[6] = pFSREQ->eType;
+ //WARN :need to check the call back VID_API_EVENT_REL_FRAME_BUFF later, when it is received, the corepond id can be released, now just do a temporary workaround
+ if (p_data_req->status == FRAME_RELEASE)
+ v4l2_vpu_send_cmd(ctx, uStrIdx, VID_API_CMD_FS_RELEASE, 1, &p_data_req->id);
+ v4l2_vpu_send_cmd(ctx, uStrIdx, VID_API_CMD_FS_ALLOC, 7, local_cmddata);
+ p_data_req->status = FRAME_FREE;
+ vpu_dbg(LVL_INFO, "VID_API_CMD_FS_ALLOC, data_req->vb2_buf=%p, data_req->id=%d\n", p_data_req->vb2_buf, p_data_req->id);
+ } else
+ vpu_dbg(LVL_ERR, "error: the list is still empty");
+ }
+ }
+ break;
+ case VID_API_EVENT_REL_FRAME_BUFF: {
+ MEDIA_PLAYER_FSREL *fsrel = (MEDIA_PLAYER_FSREL *)event_data;
+ struct queue_data *This = &ctx->q_data[V4L2_DST];
+ struct vb2_data_req *p_data_req;
+
+ if (ctx->buffer_null == true) {
+ vpu_dbg(LVL_INFO, "frame already released !!!!!!!!!!!!!!!!!\n");
+ break;
+ }
+
+ if (fsrel->eType == MEDIAIP_FRAME_REQ) {
+ p_data_req = &This->vb2_reqs[fsrel->uFSIdx];
+
+ if (ctx->wait_rst_done != true && p_data_req->status != FRAME_READY)
+ vpu_dbg(LVL_ERR, "error: normal release need to set status to FRAME_RELEASE but previous status %s is not FRAME_READY\n", bufstat[p_data_req->status]);
+ p_data_req->status = FRAME_RELEASE;
+ }
+ vpu_dbg(LVL_INFO, "VID_API_EVENT_REL_FRAME_BUFF uFSIdx=%d, eType=%d, size=%ld\n", fsrel->uFSIdx, fsrel->eType, sizeof(MEDIA_PLAYER_FSREL));
+ } break;
+ case VID_API_EVENT_FRAME_BUFF_RDY: {
+ u_int32 *FrameInfo = (u_int32 *)event_data;
+
+ //when the buffer is not NULL, do report_buffer_done
+ if (ctx->buffer_null == false)
+ report_buffer_done(ctx, FrameInfo);
+ }
+ break;
+ case VID_API_EVENT_CHUNK_DECODED:
+ break;
+ case VID_API_EVENT_FIFO_LOW: {
+ u_int32 uStrBufIdx = 0; //use buffer 0 for the stream
+
+ if (ctx->buffer_null == true) {
+ vpu_dbg(LVL_INFO, "frame already released !!!!!!!!!!!!!!!!!\n");
+ break;
+ }
+ v4l2_update_stream_addr(ctx, uStrBufIdx);
+ } break;
+ case VID_API_EVENT_FIFO_HIGH:
+ break;
+ case VID_API_EVENT_FIFO_EMPTY:
+ break;
+ case VID_API_EVENT_FIFO_FULL:
+ break;
+ case VID_API_EVENT_FIFO_OVF:
+ break;
+ case VID_API_EVENT_BS_ERROR:
+ break;
+ case VID_API_EVENT_UDATA_FIFO_UPTD:
+ break;
+ case VID_API_EVENT_DBG_STAT_UPDATE:
+ break;
+ case VID_API_EVENT_DBG_LOG_STARTED:
+ break;
+ case VID_API_EVENT_DBG_LOG_STOPPED:
+ break;
+ case VID_API_EVENT_ABORT_DONE: {
+ pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+
+ pStrBufDesc = dev->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * ctx->str_index;
+ vpu_dbg(LVL_INFO, "%s AbrtDone StrBuf Curr, wptr(%x) rptr(%x) start(%x) end(%x)\n",
+ __func__,
+ pStrBufDesc->wptr,
+ pStrBufDesc->rptr,
+ pStrBufDesc->start,
+ pStrBufDesc->end
+ );
+ pStrBufDesc->wptr = pStrBufDesc->rptr;
+ ctx->frm_dis_delay = 0;
+ ctx->frm_dec_delay = 0;
+ v4l2_vpu_send_cmd(ctx, uStrIdx, VID_API_CMD_RST_BUF, 0, NULL);
+ }
+ break;
+ case VID_API_EVENT_RES_CHANGE:
+ vpu_dbg(LVL_ERR, "warning: VID_API_EVENT_RES_CHANGE is not handled\n");
+#if 0
+ {
+ const struct v4l2_event ev = {
+ .type = V4L2_EVENT_SOURCE_CHANGE,
+ .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION
+ };
+ v4l2_event_queue_fh(&ctx->fh, &ev);
+ }
+#endif
+ break;
+ case VID_API_EVENT_STR_BUF_RST: {
+ pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+ struct vb2_data_req *p_data_req;
+ u_int32 i;
+
+ pStrBufDesc = dev->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_MCX + MFD_MCX_OFF * ctx->str_index;
+ vpu_dbg(LVL_INFO, "%s wptr(%x) rptr(%x) start(%x) end(%x)\n",
+ __func__,
+ pStrBufDesc->wptr,
+ pStrBufDesc->rptr,
+ pStrBufDesc->start,
+ pStrBufDesc->end
+ );
+ ctx->wait_rst_done = false;
+ for (i = 0; i < VPU_MAX_BUFFER; i++) {
+ p_data_req = &ctx->q_data[V4L2_DST].vb2_reqs[i];
+ if (p_data_req->vb2_buf != NULL)
+ if (p_data_req->status != FRAME_RELEASE)
+ vpu_dbg(LVL_INFO, "buffer(%d) status is %s when receive VID_API_EVENT_STR_BUF_RST\n", i, bufstat[p_data_req->status]);
+ }
+ complete(&ctx->completion);
+ }
+ break;
+ case VID_API_EVENT_RET_PING:
+ break;
+ case VID_API_EVENT_STR_FMT_CHANGE:
+ break;
+ case VID_API_EVENT_FINISHED: {
+ const struct v4l2_event ev = {
+ .type = V4L2_EVENT_EOS
+ };
+
+ if (ctx->eos_stop_added == false)
+ vpu_dbg(LVL_ERR, "warning: receive VID_API_EVENT_FINISHED before eos_stop_added set\n");
+ if (ctx->firmware_finished == true)
+ vpu_dbg(LVL_ERR, "warning: receive VID_API_EVENT_FINISHED when firmware_finished == true\n");
+ ctx->firmware_finished = true;
+ vpu_dbg(LVL_INFO, "receive VID_API_EVENT_FINISHED and notfiy app eos\n");
+ v4l2_event_queue_fh(&ctx->fh, &ev); //notfiy app stream eos reached
+
+ } break;
+ case VID_API_EVENT_FIRMWARE_XCPT: {
+ const struct v4l2_event ev = {
+ .type = V4L2_EVENT_EOS
+ };
+ v4l2_event_queue_fh(&ctx->fh, &ev);
+ vpu_dbg(LVL_ERR, "warning: FIRMWARE hang, and send event VID_API_EVENT_FIRMWARE_XCPT\n");
+ }
+ break;
+ case VID_API_EVENT_DEC_CFG_INFO:
+ break;
+ default:
+ vpu_dbg(LVL_ERR, "warning: uEvent %d is not handled\n", uEvent);
+ break;
+ }
+ vpu_dbg(LVL_INFO, "leave %s, uEvent %d\n", __func__, uEvent);
+}
+
+
+
+//This code is added for MU
+
+static irqreturn_t fsl_vpu_mu_isr(int irq, void *This)
+{
+ struct vpu_dev *dev = This;
+ u32 msg;
+
+ MU_ReceiveMsg(dev->mu_base_virtaddr, 0, &msg);
+ if (msg == 0xaa) {
+#ifdef CM4
+ MU_sendMesgToFW(dev->mu_base_virtaddr, RPC_BUF_OFFSET, dev->m0_rpc_phy); //CM4 use absolute address
+#else
+ MU_sendMesgToFW(dev->mu_base_virtaddr, PRINT_BUF_OFFSET, dev->m0_rpc_phy - dev->m0_p_fw_space_phy + M0_PRINT_OFFSET);
+ MU_sendMesgToFW(dev->mu_base_virtaddr, RPC_BUF_OFFSET, dev->m0_rpc_phy - dev->m0_p_fw_space_phy); //CM0 use relative address
+ MU_sendMesgToFW(dev->mu_base_virtaddr, BOOT_ADDRESS, dev->m0_p_fw_space_phy);
+#endif
+ MU_sendMesgToFW(dev->mu_base_virtaddr, INIT_DONE, 2);
+
+ } else if (msg == 0x55) {
+ dev->firmware_started = true;
+ complete(&dev->start_cmp);
+ } else if (msg == 0xA5) {
+ /*receive snapshot done msg and wakeup complete to suspend*/
+ complete(&dev->snap_done_cmp);
+ } else
+ schedule_work(&dev->msg_work);
+
+ return IRQ_HANDLED;
+}
+
+/* Initialization of the MU code. */
+static int vpu_mu_init(struct vpu_dev *dev)
+{
+ struct device_node *np;
+ unsigned int vpu_mu_id;
+ u32 irq;
+ int ret = 0;
+
+ /*
+ * Get the address of MU to be used for communication with the M0 core
+ */
+#ifdef CM4
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx8-mu0-vpu-m4");
+ if (!np) {
+ vpu_dbg(LVL_ERR, "error: Cannot find MU entry in device tree\n");
+ return -EINVAL;
+ }
+#else
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx8-mu0-vpu-m0");
+ if (!np) {
+ vpu_dbg(LVL_ERR, "error: Cannot find MU entry in device tree\n");
+ return -EINVAL;
+ }
+#endif
+ dev->mu_base_virtaddr = of_iomap(np, 0);
+ WARN_ON(!dev->mu_base_virtaddr);
+
+ ret = of_property_read_u32_index(np,
+ "fsl,vpu_ap_mu_id", 0, &vpu_mu_id);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "error: Cannot get mu_id %d\n", ret);
+ return -EINVAL;
+ }
+
+ dev->vpu_mu_id = vpu_mu_id;
+
+ irq = of_irq_get(np, 0);
+
+ ret = devm_request_irq(&dev->plat_dev->dev, irq, fsl_vpu_mu_isr,
+ IRQF_EARLY_RESUME, "vpu_mu_isr", (void *)dev);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "error: request_irq failed %d, error = %d\n", irq, ret);
+ return -EINVAL;
+ }
+
+ if (!dev->vpu_mu_init) {
+ MU_Init(dev->mu_base_virtaddr);
+ MU_EnableRxFullInt(dev->mu_base_virtaddr, 0);
+ dev->vpu_mu_init = 1;
+ }
+
+ return ret;
+}
+
+/*
+ * Add judge to find if it has available path to decode, if all
+ * path hang, reset vpu and then get one index
+ */
+static int vpu_next_free_instance(struct vpu_dev *dev)
+{
+ int count = 0;
+ unsigned long hang_mask = dev->hang_mask;
+ int idx;
+
+ while (hang_mask) {
+ if (hang_mask & 1)
+ count++;
+ hang_mask >>= 1;
+ }
+ if (count == VPU_MAX_NUM_STREAMS) {
+ dev->hang_mask = 0;
+ dev->instance_mask = 0;
+ reset_vpu_firmware(dev);
+ }
+
+ idx = ffz(dev->instance_mask);
+ if (idx < 0 || idx >= VPU_MAX_NUM_STREAMS)
+ return -EBUSY;
+
+ return idx;
+}
+
+static void send_msg_queue(struct vpu_ctx *ctx, struct event_msg *msg)
+{
+ u_int32 ret;
+
+ ret = kfifo_in(&ctx->msg_fifo, msg, sizeof(struct event_msg));
+ if (ret != sizeof(struct event_msg))
+ vpu_dbg(LVL_ERR, "There is no memory for msg fifo, ret=%d\n", ret);
+}
+
+static bool receive_msg_queue(struct vpu_ctx *ctx, struct event_msg *msg)
+{
+ u_int32 ret;
+
+ if (kfifo_len(&ctx->msg_fifo) >= sizeof(*msg)) {
+ ret = kfifo_out(&ctx->msg_fifo, msg, sizeof(*msg));
+ if (ret != sizeof(*msg)) {
+ vpu_dbg(LVL_ERR, "kfifo_out has error, ret=%d\n", ret);
+ return false;
+ } else
+ return true;
+ } else
+ return false;
+}
+
+extern u_int32 rpc_MediaIPFW_Video_message_check(struct shared_addr *This);
+static void vpu_msg_run_work(struct work_struct *work)
+{
+ struct vpu_dev *dev = container_of(work, struct vpu_dev, msg_work);
+ struct vpu_ctx *ctx;
+ struct event_msg msg;
+ struct shared_addr *This = &dev->shared_mem;
+
+ while (rpc_MediaIPFW_Video_message_check(This) == API_MSG_AVAILABLE) {
+ rpc_receive_msg_buf(This, &msg);
+ mutex_lock(&dev->dev_mutex);
+ ctx = dev->ctx[msg.idx];
+ if (ctx != NULL) {
+ mutex_lock(&ctx->instance_mutex);
+ if (!ctx->ctx_released) {
+ send_msg_queue(ctx, &msg);
+ queue_work(ctx->instance_wq, &ctx->instance_work);
+ }
+ mutex_unlock(&ctx->instance_mutex);
+ }
+ mutex_unlock(&dev->dev_mutex);
+ }
+ if (rpc_MediaIPFW_Video_message_check(This) == API_MSG_BUFFER_ERROR)
+ vpu_dbg(LVL_ERR, "error: message size is too big to handle\n");
+}
+static void vpu_msg_instance_work(struct work_struct *work)
+{
+ struct vpu_ctx *ctx = container_of(work, struct vpu_ctx, instance_work);
+ struct event_msg msg;
+
+ while (receive_msg_queue(ctx, &msg))
+ vpu_api_event_handler(ctx, msg.idx, msg.msgid, msg.msgdata);
+}
+
+static int vpu_queue_setup(struct vb2_queue *vq,
+ unsigned int *buf_count,
+ unsigned int *plane_count,
+ unsigned int psize[],
+ struct device *allocators[])
+{
+ struct queue_data *This = (struct queue_data *)vq->drv_priv;
+
+ vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+
+ if ((vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ||
+ (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ ) {
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ *plane_count = 2;
+ psize[0] = This->sizeimage[0];//check alignment
+ psize[1] = This->sizeimage[1];//check colocated_size
+ } else {
+ psize[0] = This->sizeimage[0] + This->sizeimage[1];
+ *plane_count = 1;
+ }
+ } else {
+ *plane_count = 1;
+ psize[0] = This->sizeimage[0];
+ }
+ return 0;
+}
+
+static int vpu_buf_prepare(struct vb2_buffer *vb)
+{
+ vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+
+ return 0;
+}
+
+
+static int vpu_start_streaming(struct vb2_queue *q,
+ unsigned int count
+ )
+{
+ int ret = 0;
+
+ vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+ return ret;
+}
+
+
+static void vpu_stop_streaming(struct vb2_queue *q)
+{
+ struct queue_data *This = (struct queue_data *)q->drv_priv;
+ struct vb2_data_req *p_data_req = NULL;
+ struct vb2_data_req *p_temp;
+ struct vb2_buffer *vb;
+
+ vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+ down(&This->drv_q_lock);
+ if (!list_empty(&This->drv_q)) {
+ list_for_each_entry_safe(p_data_req, p_temp, &This->drv_q, list) {
+ vpu_dbg(LVL_INFO, "%s(%d) - list_del(%p)\n",
+ __func__,
+ p_data_req->id,
+ p_data_req);
+ list_del(&p_data_req->list);
+ }
+ }
+ if (!list_empty(&q->queued_list))
+ list_for_each_entry(vb, &q->queued_list, queued_entry) {
+ if (vb->state == VB2_BUF_STATE_ACTIVE)
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+ }
+ INIT_LIST_HEAD(&This->drv_q);
+ up(&This->drv_q_lock);
+}
+
+static void vpu_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct queue_data *This = (struct queue_data *)vq->drv_priv;
+ struct vb2_data_req *data_req;
+ u_int32 *pphy_address;
+
+ vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+
+ down(&This->drv_q_lock);
+ vpu_dbg(LVL_INFO, "c_port_buf_queue down\n");
+ data_req = &This->vb2_reqs[vb->index];
+ data_req->vb2_buf = vb;
+ data_req->id = vb->index;
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ pphy_address = (u_int32 *)vb2_plane_cookie(vb, 0);
+ data_req->phy_addr[0] = *pphy_address;
+ pphy_address = (u_int32 *)vb2_plane_cookie(vb, 1);
+ data_req->phy_addr[1] = *pphy_address;
+ }
+ if (data_req->status != FRAME_FREE && data_req->status != FRAME_DECODED)
+ list_add_tail(&data_req->list, &This->drv_q);
+
+ vpu_dbg(LVL_INFO, "before c_port_buf_queue up, vq->type=%d, vb->index=%d\n", vq->type, vb->index);
+ up(&This->drv_q_lock);
+ vpu_dbg(LVL_INFO, "c_port_buf_queue up\n");
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ v4l2_transfer_buffer_to_firmware(This, vb);
+}
+
+static void vpu_prepare(struct vb2_queue *q)
+{
+ vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+}
+
+static void vpu_finish(struct vb2_queue *q)
+{
+ vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+}
+
+struct vb2_ops v4l2_qops = {
+ .queue_setup = vpu_queue_setup,
+ .wait_prepare = vpu_prepare,
+ .wait_finish = vpu_finish,
+ .buf_prepare = vpu_buf_prepare,
+ .start_streaming = vpu_start_streaming,
+ .stop_streaming = vpu_stop_streaming,
+ .buf_queue = vpu_buf_queue,
+};
+
+static void init_vb2_queue(struct queue_data *This, unsigned int type, struct vpu_ctx *ctx)
+{
+ struct vb2_queue *vb2_q = &This->vb2_q;
+ int ret;
+ u_int32 i;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ for (i = 0; i < VPU_MAX_BUFFER; i++)
+ This->vb2_reqs[i].status = 0;
+ // initialze driver queue
+ INIT_LIST_HEAD(&This->drv_q);
+ // initialize vb2 queue
+ vb2_q->type = type;
+ vb2_q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ vb2_q->gfp_flags = GFP_DMA32;
+ vb2_q->ops = &v4l2_qops;
+ vb2_q->drv_priv = This;
+ vb2_q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+ vb2_q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ vb2_q->dev = &ctx->dev->plat_dev->dev;
+ ret = vb2_queue_init(vb2_q);
+ if (ret)
+ vpu_dbg(LVL_ERR, "error: %s vb2_queue_init() failed (%d)!\n",
+ __func__,
+ ret
+ );
+ else
+ This->vb2_q_inited = true;
+}
+
+static void init_queue_data(struct vpu_ctx *ctx)
+{
+ init_vb2_queue(&ctx->q_data[V4L2_SRC], V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, ctx);
+ ctx->q_data[V4L2_SRC].type = V4L2_SRC;
+ sema_init(&ctx->q_data[V4L2_SRC].drv_q_lock, 1);
+ init_vb2_queue(&ctx->q_data[V4L2_DST], V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, ctx);
+ ctx->q_data[V4L2_DST].type = V4L2_DST;
+ sema_init(&ctx->q_data[V4L2_DST].drv_q_lock, 1);
+}
+
+static void flush_drv_q(struct queue_data *This)
+{
+ struct vb2_data_req *p_data_req = NULL;
+ struct vb2_data_req *p_temp;
+
+ vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+ down(&This->drv_q_lock);
+ if (!list_empty(&This->drv_q)) {
+ list_for_each_entry_safe(p_data_req, p_temp, &This->drv_q, list) {
+ vpu_dbg(LVL_INFO, "%s(%d) - list_del(%p)\n",
+ __func__,
+ p_data_req->id,
+ p_data_req);
+ list_del(&p_data_req->list);
+ vb2_buffer_done(p_data_req->vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+ }
+ INIT_LIST_HEAD(&This->drv_q);
+
+ up(&This->drv_q_lock);
+
+}
+
+static void release_queue_data(struct vpu_ctx *ctx)
+{
+ struct queue_data *This = &ctx->q_data[V4L2_SRC];
+
+ if (This->vb2_q_inited) {
+ flush_drv_q(This);
+ vb2_queue_release(&This->vb2_q);
+ }
+ This = &ctx->q_data[V4L2_DST];
+ if (This->vb2_q_inited) {
+ flush_drv_q(This);
+ vb2_queue_release(&This->vb2_q);
+ }
+}
+
+#ifdef CM4
+static int power_CM4_up(struct vpu_dev *dev)
+{
+ sc_ipc_t ipcHndl;
+ sc_rsrc_t core_rsrc, mu_rsrc = -1;
+
+ ipcHndl = dev->mu_ipcHandle;
+ core_rsrc = SC_R_M4_0_PID0;
+ mu_rsrc = SC_R_M4_0_MU_1A;
+
+ if (sc_pm_set_resource_power_mode(ipcHndl, core_rsrc, SC_PM_PW_MODE_ON) != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: failed to power up core_rsrc\n");
+ return -EIO;
+ }
+
+ if (mu_rsrc != -1) {
+ if (sc_pm_set_resource_power_mode(ipcHndl, mu_rsrc, SC_PM_PW_MODE_ON) != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: failed to power up mu_rsrc\n");
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static int boot_CM4_up(struct vpu_dev *dev, void *boot_addr)
+{
+ sc_ipc_t ipcHndl;
+ sc_rsrc_t core_rsrc;
+ sc_faddr_t aux_core_ram;
+ void *core_ram_vir;
+ u32 size;
+
+ ipcHndl = dev->mu_ipcHandle;
+ core_rsrc = SC_R_M4_0_PID0;
+ aux_core_ram = 0x34FE0000;
+ size = SZ_128K;
+
+ core_ram_vir = ioremap_wc(aux_core_ram,
+ size
+ );
+ if (!core_ram_vir)
+ vpu_dbg(LVL_ERR, "error: failed to remap space for core ram\n");
+
+ memcpy((void *)core_ram_vir, (void *)boot_addr, size);
+
+ if (sc_pm_cpu_start(ipcHndl, core_rsrc, true, aux_core_ram) != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: failed to start core_rsrc\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+#endif
+
+static int vpu_firmware_download(struct vpu_dev *This)
+{
+ unsigned char *image;
+ unsigned int FW_Size = 0;
+ void *csr_offset, *csr_cpuwait;
+ int ret = 0;
+ char *p = This->m0_p_fw_space_vir;
+
+ ret = request_firmware((const struct firmware **)&This->m0_pfw,
+ M0FW_FILENAME,
+ This->generic_dev
+ );
+
+ if (ret) {
+ vpu_dbg(LVL_ERR, "error: %s() request fw %s failed(%d)\n",
+ __func__, M0FW_FILENAME, ret);
+
+ if (This->m0_pfw) {
+ release_firmware(This->m0_pfw);
+ This->m0_pfw = NULL;
+ }
+ return ret;
+ } else {
+ vpu_dbg(LVL_INFO, "%s() request fw %s got size(%d)\n",
+ __func__, M0FW_FILENAME, (int)This->m0_pfw->size);
+ image = (uint8_t *)This->m0_pfw->data;
+ FW_Size = This->m0_pfw->size;
+ }
+ memcpy(This->m0_p_fw_space_vir,
+ image,
+ FW_Size
+ );
+#ifdef CM4
+ boot_CM4_up(This, This->m0_p_fw_space_vir);
+#else
+ if (This->plat_type == IMX8QM) { //decoder use M core 0
+ p[16] = IMX8QM;
+ csr_offset = ioremap(0x2d080000, 4);
+ writel(This->m0_p_fw_space_phy, csr_offset);
+ csr_cpuwait = ioremap(0x2d080004, 4);
+ writel(0x0, csr_cpuwait);
+ } else {
+ csr_offset = ioremap(0x2d040000, 4);
+ writel(This->m0_p_fw_space_phy, csr_offset);
+ csr_cpuwait = ioremap(0x2d040004, 4);
+ writel(0x0, csr_cpuwait);
+ }
+#endif
+ return ret;
+}
+
+static int v4l2_open(struct file *filp)
+{
+ struct video_device *vdev = video_devdata(filp);
+ struct vpu_dev *dev = video_get_drvdata(vdev);
+ struct vpu_ctx *ctx = NULL;
+ int idx;
+ int ret;
+ u_int32 i;
+
+ pm_runtime_get_sync(dev->generic_dev);
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+ mutex_lock(&dev->dev_mutex);
+ idx = vpu_next_free_instance(dev);
+ if (idx < 0) {
+ ret = idx;
+ mutex_unlock(&dev->dev_mutex);
+ goto err_find_index;
+ }
+ set_bit(idx, &dev->instance_mask);
+ mutex_unlock(&dev->dev_mutex);
+ init_completion(&ctx->completion);
+ init_completion(&ctx->stop_cmp);
+ init_completion(&ctx->eos_cmp);
+
+ v4l2_fh_init(&ctx->fh, video_devdata(filp));
+ filp->private_data = &ctx->fh;
+ v4l2_fh_add(&ctx->fh);
+
+ ctx->ctrl_inited = false;
+ ctrls_setup_decoder(ctx);
+ ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+
+
+ ctx->instance_wq = alloc_workqueue("vpu_instance", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+ if (!ctx->instance_wq) {
+ vpu_dbg(LVL_ERR, "error: %s unable to alloc workqueue for ctx\n", __func__);
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+ INIT_WORK(&ctx->instance_work, vpu_msg_instance_work);
+
+ mutex_init(&ctx->instance_mutex);
+ if (kfifo_alloc(&ctx->msg_fifo,
+ sizeof(struct event_msg) * VID_API_MESSAGE_LIMIT,
+ GFP_KERNEL)) {
+ vpu_dbg(LVL_ERR, "fail to alloc fifo when open\n");
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+ ctx->dev = dev;
+ ctx->str_index = idx;
+ dev->ctx[idx] = ctx;
+ ctx->b_firstseq = true;
+ ctx->start_flag = true;
+ ctx->wait_rst_done = false;
+ ctx->firmware_stopped = false;
+ ctx->firmware_finished = false;
+ ctx->eos_stop_added = false;
+ ctx->buffer_null = true; //this flag is to judge whether the buffer is null is not, it is used for the workaround that when send stop command still can receive buffer ready event, and true means buffer is null, false not
+ ctx->ctx_released = false;
+ ctx->b_dis_reorder = false;
+ ctx->pSeqinfo = kzalloc(sizeof(MediaIPFW_Video_SeqInfo), GFP_KERNEL);
+ if (!ctx->pSeqinfo)
+ vpu_dbg(LVL_ERR, "error: pSeqinfo alloc fail\n");
+ init_queue_data(ctx);
+ init_waitqueue_head(&ctx->buffer_wq);
+ mutex_lock(&dev->dev_mutex);
+ if (!dev->fw_is_ready) {
+ ret = vpu_firmware_download(dev);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "error: vpu_firmware_download fail\n");
+ mutex_unlock(&dev->dev_mutex);
+ goto err_firmware_load;
+ } else
+ vpu_dbg(LVL_INFO, "done: vpu_firmware_download\n");
+ if (!ctx->dev->firmware_started)
+ wait_for_completion(&ctx->dev->start_cmp);
+ dev->fw_is_ready = true;
+ }
+ mutex_unlock(&dev->dev_mutex);
+
+ rpc_set_stream_cfg_value(dev->shared_mem.pSharedInterface, ctx->str_index);
+
+ for (i = 0; i < MAX_DCP_NUM; i++) {
+ ctx->dcp_dma_virt[i] = NULL;
+ ctx->dcp_dma_phy[i] = 0;
+ }
+ ctx->dcp_count = 0;
+ for (i = 0; i < MAX_MBI_NUM; i++) {
+ ctx->mbi_dma_virt[i] = NULL;
+ ctx->mbi_dma_phy[i] = 0;
+ }
+ ctx->mbi_count = 0;
+ ctx->mbi_num = 0;
+ ctx->mbi_size = 0;
+#ifdef DYNAMIC_MEM
+ ctx->stream_buffer_size = MAX_BUFFER_SIZE;
+ ctx->stream_buffer_virt = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+ ctx->stream_buffer_size,
+ (dma_addr_t *)&ctx->stream_buffer_phy,
+ GFP_KERNEL | GFP_DMA32
+ );
+ if (!ctx->stream_buffer_virt)
+ vpu_dbg(LVL_ERR, "error: %s() stream buffer alloc size(%x) fail!\n", __func__, ctx->stream_buffer_size);
+ else
+ vpu_dbg(LVL_INFO, "%s() stream_buffer_size(%d) stream_buffer_virt(%p) stream_buffer_phy(%p), index(%d)\n",
+ __func__, ctx->stream_buffer_size, ctx->stream_buffer_virt, (void *)ctx->stream_buffer_phy, ctx->str_index);
+#else
+ ctx->stream_buffer_size = dev->str_size/VPU_MAX_NUM_STREAMS;
+ ctx->stream_buffer_phy = dev->str_base_phy + ctx->str_index * ctx->stream_buffer_size;
+ ctx->stream_buffer_virt = dev->str_base_vir + ctx->str_index * ctx->stream_buffer_size;
+#endif
+ ctx->udata_buffer_size = UDATA_BUFFER_SIZE;
+ ctx->udata_buffer_virt = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+ ctx->udata_buffer_size,
+ (dma_addr_t *)&ctx->udata_buffer_phy,
+ GFP_KERNEL | GFP_DMA32
+ );
+
+ if (!ctx->udata_buffer_virt)
+ vpu_dbg(LVL_ERR, "error: %s() udata buffer alloc size(%x) fail!\n", __func__, ctx->udata_buffer_size);
+ else
+ vpu_dbg(LVL_INFO, "%s() udata_buffer_size(%d) udata_buffer_virt(%p) udata_buffer_phy(%p)\n",
+ __func__, ctx->udata_buffer_size, ctx->udata_buffer_virt, (void *)ctx->udata_buffer_phy);
+
+ return 0;
+
+err_firmware_load:
+ release_queue_data(ctx);
+ ctrls_delete_decoder(ctx);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ clear_bit(ctx->str_index, &dev->instance_mask);
+ kfree(ctx);
+ return ret;
+err_find_index:
+ pm_runtime_put_sync(dev->generic_dev);
+ kfree(ctx);
+ return ret;
+err_alloc:
+ pm_runtime_put_sync(dev->generic_dev);
+ kfree(ctx);
+ return ret;
+}
+
+static int v4l2_release(struct file *filp)
+{
+ struct video_device *vdev = video_devdata(filp);
+ struct vpu_dev *dev = video_get_drvdata(vdev);
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+ u_int32 i;
+
+ vpu_dbg(LVL_EVENT, "ctx[%d]: v4l2_release() - stopped(%d), finished(%d), eos_added(%d), total frame: %d\n",
+ ctx->str_index, ctx->firmware_stopped, ctx->firmware_finished, ctx->eos_stop_added, ctx->frm_total_num);
+
+ if (!ctx->firmware_stopped && ctx->start_flag == false) {
+ ctx->wait_rst_done = true;
+ wake_up_interruptible(&ctx->buffer_wq); //workaround: to wakeup event handler who still may receive request frame after reset done
+ vpu_dbg(LVL_INFO, "v4l2_release() - send VID_API_CMD_STOP\n");
+ v4l2_vpu_send_cmd(ctx, ctx->str_index, VID_API_CMD_STOP, 0, NULL);
+ if (!wait_for_completion_timeout(&ctx->stop_cmp, msecs_to_jiffies(1000))) {
+ mutex_lock(&dev->dev_mutex);
+ set_bit(ctx->str_index, &dev->hang_mask);
+ mutex_unlock(&dev->dev_mutex);
+ vpu_dbg(LVL_ERR, "the path id:%d firmware hang after send VID_API_CMD_STOP\n", ctx->str_index);
+ }
+ } else {
+ vpu_dbg(LVL_WARN, "v4l2_release() - stopped(%d): skip VID_API_CMD_STOP\n", ctx->firmware_stopped);
+ }
+
+ release_queue_data(ctx);
+ ctrls_delete_decoder(ctx);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+
+ for (i = 0; i < MAX_DCP_NUM; i++)
+ if (ctx->dcp_dma_virt[i] != NULL)
+ dma_free_coherent(&ctx->dev->plat_dev->dev,
+ ctx->uDCPSize,
+ ctx->dcp_dma_virt[i],
+ ctx->dcp_dma_phy[i]
+ );
+ for (i = 0; i < MAX_MBI_NUM; i++)
+ if (ctx->mbi_dma_virt[i] != NULL)
+ dma_free_coherent(&ctx->dev->plat_dev->dev,
+ ctx->mbi_size,
+ ctx->mbi_dma_virt[i],
+ ctx->mbi_dma_phy[i]
+ );
+#ifdef DYNAMIC_MEM
+ if (ctx->stream_buffer_virt)
+ dma_free_coherent(&ctx->dev->plat_dev->dev,
+ ctx->stream_buffer_size,
+ ctx->stream_buffer_virt,
+ ctx->stream_buffer_phy
+ );
+#endif
+ if (ctx->udata_buffer_virt)
+ dma_free_coherent(&ctx->dev->plat_dev->dev,
+ ctx->udata_buffer_size,
+ ctx->udata_buffer_virt,
+ ctx->udata_buffer_phy
+ );
+
+ if (ctx->pSeqinfo) {
+ kfree(ctx->pSeqinfo);
+ ctx->pSeqinfo = NULL;
+ }
+ mutex_lock(&ctx->instance_mutex);
+ ctx->ctx_released = true;
+ kfifo_free(&ctx->msg_fifo);
+ destroy_workqueue(ctx->instance_wq);
+ mutex_unlock(&ctx->instance_mutex);
+ ctx->stream_buffer_virt = NULL;
+ mutex_lock(&dev->dev_mutex);
+ if (!(dev->hang_mask & (1 << ctx->str_index))) // judge the path is hang or not, if hang, don't clear
+ clear_bit(ctx->str_index, &dev->instance_mask);
+ dev->ctx[ctx->str_index] = NULL;
+ mutex_unlock(&dev->dev_mutex);
+
+ pm_runtime_put_sync(ctx->dev->generic_dev);
+ kfree(ctx);
+ return 0;
+}
+
+static unsigned int v4l2_poll(struct file *filp, poll_table *wait)
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+ struct vb2_queue *src_q, *dst_q;
+ unsigned int rc = 0;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (ctx) {
+ poll_wait(filp, &ctx->fh.wait, wait);
+
+ if (v4l2_event_pending(&ctx->fh)) {
+ vpu_dbg(LVL_INFO, "%s() v4l2_event_pending\n", __func__);
+ rc |= POLLPRI;
+ }
+
+ src_q = &ctx->q_data[V4L2_SRC].vb2_q;
+ dst_q = &ctx->q_data[V4L2_DST].vb2_q;
+
+ if (ctx->firmware_finished && !list_empty(&dst_q->done_list))
+ rc = 0;
+
+ if ((!src_q->streaming || list_empty(&src_q->queued_list))
+ && (!dst_q->streaming || list_empty(&dst_q->queued_list))) {
+ return rc;
+ }
+
+ poll_wait(filp, &src_q->done_wq, wait);
+ if (!list_empty(&src_q->done_list))
+ rc |= POLLOUT | POLLWRNORM;
+ poll_wait(filp, &dst_q->done_wq, wait);
+ if (!list_empty(&dst_q->done_list))
+ rc |= POLLIN | POLLRDNORM;
+ } else
+ rc = POLLERR;
+
+ return rc;
+}
+
+static int v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ long ret = -EPERM;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ struct queue_data *q_data;
+ enum QUEUE_TYPE type;
+
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (ctx) {
+ type = offset >> MMAP_BUF_TYPE_SHIFT;
+ q_data = &ctx->q_data[type];
+
+ offset &= ~MMAP_BUF_TYPE_MASK;
+ offset = offset >> PAGE_SHIFT;
+ vma->vm_pgoff = offset;
+ ret = vb2_mmap(&q_data->vb2_q,
+ vma
+ );
+ }
+
+ return ret;
+}
+
+static const struct v4l2_file_operations v4l2_decoder_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_open,
+ .unlocked_ioctl = video_ioctl2,
+ .release = v4l2_release,
+ .poll = v4l2_poll,
+ .mmap = v4l2_mmap,
+};
+
+static struct video_device v4l2_videodevice_decoder = {
+ .name = "vpu decoder",
+ .fops = &v4l2_decoder_fops,
+ .ioctl_ops = &v4l2_decoder_ioctl_ops,
+ .vfl_dir = VFL_DIR_M2M,
+};
+#if 1
+static int set_vpu_pwr(sc_ipc_t ipcHndl,
+ sc_pm_power_mode_t pm
+ )
+{
+ int rv = -1;
+ sc_err_t sciErr;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+ if (!ipcHndl) {
+ vpu_dbg(LVL_ERR, "error: --- set_vpu_pwr no IPC handle\n");
+ goto set_vpu_pwrexit;
+ }
+
+ // Power on or off DEC, ENC MU
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU, pm);
+ if (sciErr != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU,%d) SCI error! (%d)\n", sciErr, pm);
+ goto set_vpu_pwrexit;
+ }
+#ifdef TEST_BUILD
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_DEC, pm);
+ if (sciErr != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_DEC,%d) SCI error! (%d)\n", sciErr, pm);
+ goto set_vpu_pwrexit;
+ }
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_ENC, pm);
+ if (sciErr != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_ENC,%d) SCI error! (%d)\n", sciErr, pm);
+ goto set_vpu_pwrexit;
+ }
+#else
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_DEC_0, pm);
+ if (sciErr != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_DEC_0,%d) SCI error! (%d)\n", sciErr, pm);
+ goto set_vpu_pwrexit;
+ }
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_ENC_0, pm);
+ if (sciErr != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_ENC_0,%d) SCI error! (%d)\n", sciErr, pm);
+ goto set_vpu_pwrexit;
+ }
+#endif
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_MU_0, pm);
+ if (sciErr != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_MU_0,%d) SCI error! (%d)\n", sciErr, pm);
+ goto set_vpu_pwrexit;
+ }
+
+ rv = 0;
+
+set_vpu_pwrexit:
+ return rv;
+}
+
+static void vpu_set_power(struct vpu_dev *dev, bool on)
+{
+ int ret;
+
+ if (on) {
+ ret = set_vpu_pwr(dev->mu_ipcHandle, SC_PM_PW_MODE_ON);
+ if (ret)
+ vpu_dbg(LVL_ERR, "error: failed to power on\n");
+ pm_runtime_get_sync(dev->generic_dev);
+ } else {
+ pm_runtime_put_sync_suspend(dev->generic_dev);
+ ret = set_vpu_pwr(dev->mu_ipcHandle, SC_PM_PW_MODE_OFF);
+ if (ret)
+ vpu_dbg(LVL_ERR, "error: failed to power off\n");
+ }
+}
+#endif
+
+static void vpu_setup(struct vpu_dev *This)
+{
+ uint32_t read_data = 0;
+
+ vpu_dbg(LVL_INFO, "enter %s\n", __func__);
+ writel(0x1, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_SCB_CLK_ENABLE_SET);
+ writel(0xffffffff, This->regs_base + 0x70190);
+ writel(0xffffffff, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_XMEM_RESET_SET);
+
+ writel(0xE, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_SCB_CLK_ENABLE_SET);
+ writel(0x7, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_CACHE_RESET_SET);
+
+ writel(0x1f, This->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_BLK_CTRL + MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_SET);
+ writel(0xffffffff, This->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_BLK_CTRL + MFD_BLK_CTRL_MFD_SYS_RESET_SET);
+
+ writel(0x102, This->regs_base + XMEM_CONTROL);
+
+ read_data = readl(This->regs_base+0x70108);
+ vpu_dbg(LVL_INFO, "%s read_data=%x\n", __func__, read_data);
+}
+
+static void vpu_reset(struct vpu_dev *This)
+{
+ vpu_dbg(LVL_INFO, "enter %s\n", __func__);
+ writel(0x7, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_CACHE_RESET_CLR);
+ writel(0xffffffff, This->regs_base + DEC_MFD_XREG_SLV_BASE + MFD_BLK_CTRL + MFD_BLK_CTRL_MFD_SYS_RESET_CLR);
+}
+
+static int vpu_enable_hw(struct vpu_dev *This)
+{
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+#if 0
+ This->vpu_clk = clk_get(&This->plat_dev->dev, "vpu_clk");
+ if (IS_ERR(This->vpu_clk)) {
+ vpu_dbg(LVL_ERR, "vpu_clk get error\n");
+ return -ENOENT;
+ }
+ clk_set_rate(This->vpu_clk, 600000000);
+ clk_prepare_enable(This->vpu_clk);
+#endif
+ vpu_setup(This);
+ return 0;
+}
+static void vpu_disable_hw(struct vpu_dev *This)
+{
+ vpu_reset(This);
+#if 0
+ if (This->vpu_clk) {
+ clk_put(This->vpu_clk);
+ }
+#endif
+}
+
+static int reset_vpu_firmware(struct vpu_dev *dev)
+{
+ int ret = 0;
+
+ vpu_dbg(LVL_WARN, "RESET: reset_vpu_firmware\n");
+ vpu_set_power(dev, false);
+ usleep_range(1000, 1100);
+ vpu_set_power(dev, true);
+ dev->fw_is_ready = false;
+ dev->firmware_started = false;
+ vpu_enable_hw(dev);
+
+ rpc_init_shared_memory(&dev->shared_mem, dev->m0_rpc_phy - dev->m0_p_fw_space_phy, dev->m0_rpc_virt, SHARED_SIZE);
+ rpc_set_system_cfg_value(dev->shared_mem.pSharedInterface, VPU_REG_BASE);
+
+ MU_Init(dev->mu_base_virtaddr);
+ MU_EnableRxFullInt(dev->mu_base_virtaddr, 0);
+
+ return ret;
+}
+
+static int vpu_probe(struct platform_device *pdev)
+{
+ struct vpu_dev *dev;
+ struct resource *res;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *reserved_node;
+ struct resource reserved_res;
+ unsigned int mu_id;
+ u_int32 core_type;
+ int ret;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->plat_dev = pdev;
+ dev->generic_dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dev->regs_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dev->regs_base)) {
+ vpu_dbg(LVL_ERR, "error: %s could not map regs_base\n", __func__);
+ return PTR_ERR(dev->regs_base);
+ }
+
+ if (np) {
+ ret = of_property_read_u32(np, "core_type", &core_type);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "error: Cannot get core num %d\n", ret);
+ return -EINVAL;
+ }
+ if (core_type == 2)
+ dev->plat_type = IMX8QM;
+ else
+ dev->plat_type = IMX8QXP;
+ reserved_node = of_parse_phandle(np, "boot-region", 0);
+ if (!reserved_node) {
+ vpu_dbg(LVL_ERR, "error: boot-region of_parse_phandle error\n");
+ return -ENODEV;
+ }
+
+ if (of_address_to_resource(reserved_node, 0, &reserved_res)) {
+ vpu_dbg(LVL_ERR, "error: boot-region of_address_to_resource error\n");
+ return -EINVAL;
+ }
+ dev->m0_p_fw_space_phy = reserved_res.start;
+ dev->cm_offset = 0;
+ reserved_node = of_parse_phandle(np, "rpc-region", 0);
+ if (!reserved_node) {
+ vpu_dbg(LVL_ERR, "error: rpc-region of_parse_phandle error\n");
+ return -ENODEV;
+ }
+
+ if (of_address_to_resource(reserved_node, 0, &reserved_res)) {
+ vpu_dbg(LVL_ERR, "error: rpc-region of_address_to_resource error\n");
+ return -EINVAL;
+ }
+ dev->m0_rpc_phy = reserved_res.start;
+#ifndef DYNAMIC_MEM
+ reserved_node = of_parse_phandle(np, "str-region", 0);
+ if (!reserved_node) {
+ vpu_dbg(LVL_ERR, "error: str-region of_parse_phandle error\n");
+ return -ENODEV;
+ }
+
+ if (of_address_to_resource(reserved_node, 0, &reserved_res)) {
+ vpu_dbg(LVL_ERR, "error: str-region of_address_to_resource error\n");
+ return -EINVAL;
+ }
+ dev->str_base_phy = reserved_res.start;
+ dev->str_size = resource_size(&reserved_res);
+#endif
+ } else
+ vpu_dbg(LVL_ERR, "error: %s of_node is NULL\n", __func__);
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "error: %s unable to register v4l2 dev\n", __func__);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, dev);
+
+ dev->pvpu_decoder_dev = video_device_alloc();
+ if (dev->pvpu_decoder_dev) {
+ strncpy(dev->pvpu_decoder_dev->name, v4l2_videodevice_decoder.name, sizeof(v4l2_videodevice_decoder.name));
+ dev->pvpu_decoder_dev->fops = v4l2_videodevice_decoder.fops;
+ dev->pvpu_decoder_dev->ioctl_ops = v4l2_videodevice_decoder.ioctl_ops;
+ dev->pvpu_decoder_dev->release = video_device_release;
+ dev->pvpu_decoder_dev->vfl_dir = v4l2_videodevice_decoder.vfl_dir;
+ dev->pvpu_decoder_dev->v4l2_dev = &dev->v4l2_dev;
+
+ video_set_drvdata(dev->pvpu_decoder_dev, dev);
+
+ if (video_register_device(dev->pvpu_decoder_dev,
+ VFL_TYPE_GRABBER,
+ -1)) {
+ vpu_dbg(LVL_ERR, "error: %s unable to register video decoder device\n",
+ __func__
+ );
+ video_device_release(dev->pvpu_decoder_dev);
+ dev->pvpu_decoder_dev = NULL;
+ } else {
+ vpu_dbg(LVL_INFO, "%s register video decoder device\n",
+ __func__
+ );
+ }
+ }
+
+ if (!dev->mu_ipcHandle) {
+ ret = sc_ipc_getMuID(&mu_id);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "error: --- sc_ipc_getMuID() cannot obtain mu id SCI error! (%d)\n", ret);
+ return ret;
+ }
+
+ ret = sc_ipc_open(&dev->mu_ipcHandle, mu_id);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "error: --- sc_ipc_getMuID() cannot open MU channel to SCU error! (%d)\n", ret);
+ return ret;
+ }
+ }
+
+ vpu_enable_hw(dev);
+
+ mutex_init(&dev->dev_mutex);
+ mutex_init(&dev->cmd_mutex);
+ init_completion(&dev->start_cmp);
+ init_completion(&dev->snap_done_cmp);
+ dev->firmware_started = false;
+ dev->hang_mask = 0;
+ dev->instance_mask = 0;
+
+ dev->fw_is_ready = false;
+ dev->workqueue = alloc_workqueue("vpu", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+ if (!dev->workqueue) {
+ vpu_dbg(LVL_ERR, "error: %s unable to alloc workqueue\n", __func__);
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ INIT_WORK(&dev->msg_work, vpu_msg_run_work);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+#ifdef CM4
+ ret = power_CM4_up(dev);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "error: failed to power on CM4\n");
+ return ret;
+ }
+#endif
+
+ ret = vpu_mu_init(dev);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "error: %s vpu mu init failed\n", __func__);
+ return ret;
+ }
+
+ //firmware space for M0
+ dev->m0_p_fw_space_vir = ioremap_wc(dev->m0_p_fw_space_phy,
+ M0_BOOT_SIZE
+ );
+ if (!dev->m0_p_fw_space_vir)
+ vpu_dbg(LVL_ERR, "error: failed to remap space for M0 firmware\n");
+
+ memset_io(dev->m0_p_fw_space_vir, 0, M0_BOOT_SIZE);
+
+ dev->m0_rpc_virt = ioremap_wc(dev->m0_rpc_phy,
+ SHARED_SIZE
+ );
+ if (!dev->m0_rpc_virt) {
+ vpu_dbg(LVL_ERR, "error: failed to remap space for rpc shared memory\n");
+ return -ENOMEM;
+ }
+
+ memset_io(dev->m0_rpc_virt, 0, SHARED_SIZE);
+#ifndef DYNAMIC_MEM
+ dev->str_base_vir = ioremap_wc(dev->str_base_phy,
+ dev->str_size
+ );
+ if (!dev->str_base_vir) {
+ vpu_dbg(LVL_ERR, "error: failed to remap space for stream memory\n");
+ return -ENOMEM;
+ }
+
+ memset_io(dev->str_base_vir, 0, dev->str_size);
+#endif
+#ifdef CM4
+ rpc_init_shared_memory(&dev->shared_mem, dev->m0_rpc_phy, dev->m0_rpc_virt, SHARED_SIZE);
+#else
+ rpc_init_shared_memory(&dev->shared_mem, dev->m0_rpc_phy - dev->m0_p_fw_space_phy, dev->m0_rpc_virt, SHARED_SIZE);
+#endif
+ rpc_set_system_cfg_value(dev->shared_mem.pSharedInterface, VPU_REG_BASE);
+
+ pm_runtime_put_sync(&pdev->dev);
+
+ return 0;
+}
+
+static int vpu_remove(struct platform_device *pdev)
+{
+ struct vpu_dev *dev = platform_get_drvdata(pdev);
+
+ destroy_workqueue(dev->workqueue);
+ if (dev->m0_p_fw_space_vir)
+ iounmap(dev->m0_p_fw_space_vir);
+ if (dev->m0_pfw) {
+ release_firmware(dev->m0_pfw);
+ dev->m0_pfw = NULL;
+ }
+ dev->m0_p_fw_space_vir = NULL;
+ dev->m0_p_fw_space_phy = 0;
+ dev->m0_rpc_virt = NULL;
+ dev->m0_rpc_phy = 0;
+ if (dev->shared_mem.shared_mem_vir)
+ iounmap(dev->shared_mem.shared_mem_vir);
+ dev->shared_mem.shared_mem_vir = NULL;
+ dev->shared_mem.shared_mem_phy = 0;
+
+ vpu_disable_hw(dev);
+ pm_runtime_disable(&pdev->dev);
+
+ if (video_get_drvdata(dev->pvpu_decoder_dev))
+ video_unregister_device(dev->pvpu_decoder_dev);
+
+ v4l2_device_unregister(&dev->v4l2_dev);
+ return 0;
+}
+
+static int vpu_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int vpu_runtime_resume(struct device *dev)
+{
+ return 0;
+}
+
+#define CHECK_BIT(var, pos) (((var) >> (pos)) & 1)
+
+static void v4l2_vpu_send_snapshot(struct vpu_dev *dev)
+{
+ int i = 0;
+ int strIdx = (~dev->hang_mask) & (dev->instance_mask);
+ /*figure out the first available instance*/
+ for (i = 0; i < VPU_MAX_NUM_STREAMS; i++) {
+ if (CHECK_BIT(strIdx, i)) {
+ strIdx = i;
+ break;
+ }
+ }
+
+ v4l2_vpu_send_cmd(dev->ctx[strIdx], strIdx, VID_API_CMD_SNAPSHOT, 0, NULL);
+}
+
+static int vpu_suspend(struct device *dev)
+{
+ struct vpu_dev *vpudev = (struct vpu_dev *)dev_get_drvdata(dev);
+
+ if (vpudev->hang_mask != vpudev->instance_mask) {
+
+ /*if there is an available device, send snapshot command to firmware*/
+ v4l2_vpu_send_snapshot(vpudev);
+
+ if (!wait_for_completion_timeout(&vpudev->snap_done_cmp, msecs_to_jiffies(1000))) {
+ vpu_dbg(LVL_ERR, "error: wait for vpu decoder snapdone event timeout!\n");
+ return -1;
+ }
+ }
+
+ vpu_set_power(vpudev, false);
+
+ return 0;
+}
+
+static int vpu_resume(struct device *dev)
+{
+ struct vpu_dev *vpudev = (struct vpu_dev *)dev_get_drvdata(dev);
+ void *csr_offset, *csr_cpuwait;
+
+ vpu_set_power(vpudev, true);
+ vpu_enable_hw(vpudev);
+
+ MU_Init(vpudev->mu_base_virtaddr);
+ MU_EnableRxFullInt(vpudev->mu_base_virtaddr, 0);
+
+ if (vpudev->hang_mask == vpudev->instance_mask) {
+ /*no instance is active before suspend, do reset*/
+ vpudev->fw_is_ready = false;
+ vpudev->firmware_started = false;
+
+ rpc_init_shared_memory(&vpudev->shared_mem, vpudev->m0_rpc_phy - vpudev->m0_p_fw_space_phy, vpudev->m0_rpc_virt, SHARED_SIZE);
+ rpc_set_system_cfg_value(vpudev->shared_mem.pSharedInterface, VPU_REG_BASE);
+ } else {
+ /*resume*/
+ csr_offset = ioremap(0x2d040000, 4);
+ writel(vpudev->m0_p_fw_space_phy, csr_offset);
+ csr_cpuwait = ioremap(0x2d040004, 4);
+ writel(0x0, csr_cpuwait);
+ /*wait for firmware resotre done*/
+ if (!wait_for_completion_timeout(&vpudev->start_cmp, msecs_to_jiffies(1000))) {
+ vpu_dbg(LVL_ERR, "error: wait for vpu decoder resume done timeout!\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static const struct dev_pm_ops vpu_pm_ops = {
+ SET_RUNTIME_PM_OPS(vpu_runtime_suspend, vpu_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(vpu_suspend, vpu_resume)
+};
+
+static const struct of_device_id vpu_of_match[] = {
+ { .compatible = "nxp,imx8qm-b0-vpudec", },
+ { .compatible = "nxp,imx8qxp-b0-vpudec", },
+ {}
+}
+MODULE_DEVICE_TABLE(of, vpu_of_match);
+
+static struct platform_driver vpu_driver = {
+ .probe = vpu_probe,
+ .remove = vpu_remove,
+ .driver = {
+ .name = "vpu-b0",
+ .of_match_table = vpu_of_match,
+ .pm = &vpu_pm_ops,
+ },
+};
+module_platform_driver(vpu_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Linux VPU driver for Freescale i.MX/MXC");
+MODULE_LICENSE("GPL");
+
+module_param(vpu_dbg_level_decoder, int, 0644);
+MODULE_PARM_DESC(vpu_dbg_level_decoder, "Debug level (0-2)");
+module_param(vpu_frm_depth, int, 0644);
+MODULE_PARM_DESC(vpu_frm_depth, "maxium frame number in data pool");
+
diff --git a/drivers/mxc/vpu-decoder-b0/vpu_b0.h b/drivers/mxc/vpu-decoder-b0/vpu_b0.h
new file mode 100755
index 000000000000..5d7f3051288d
--- /dev/null
+++ b/drivers/mxc/vpu-decoder-b0/vpu_b0.h
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2018 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU Lesser General
+ * Public License. You may obtain a copy of the GNU Lesser General
+ * Public License Version 2.1 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/lgpl-license.html
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+/*!
+ * @file vpu_b0.h
+ *
+ * @brief VPU B0 definition
+ *
+ */
+#ifndef __VPU_B0_H
+#define __VPU_B0_H
+
+#include <linux/irqreturn.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-v4l2.h>
+#include <soc/imx8/sc/svc/irq/api.h>
+#include <soc/imx8/sc/ipc.h>
+#include <soc/imx8/sc/sci.h>
+#include <linux/mx8_mu.h>
+#include <media/v4l2-event.h>
+#include <linux/kfifo.h>
+#include "vpu_rpc.h"
+
+extern unsigned int vpu_dbg_level_decoder;
+
+#define v4l2_fh_to_ctx(__fh) \
+ container_of(__fh, struct vpu_ctx, fh)
+#define v4l2_ctrl_to_ctx(__ctrl) \
+ container_of((__ctrl)->handler, struct vpu_ctx, ctrl_handler)
+
+#define MIN_SPACE (4096+64)
+
+#define VPU_MAX_FORMATS 4
+#define VPU_MAX_BUFFER 32
+#define M0FW_FILENAME "vpu/vpu_fw_imx8qxp_dec.bin"
+#define MMAP_BUF_TYPE_SHIFT 28
+#define MMAP_BUF_TYPE_MASK 0xF0000000
+#define M0_BOOT_SIZE 0x1000000
+#define M0_PRINT_OFFSET 0x500000
+#define DCP_SIZE 0x3000000
+#define MAX_BUFFER_SIZE 5242880
+#define UDATA_BUFFER_SIZE 0x1000
+#define SHARED_SIZE 0x00400000
+#define MAX_DCP_NUM 2
+#define MAX_MBI_NUM 18 // same with MEDIA_PLAYER_MAX_MBI_UNIT defined in firmware
+#define MAX_TIMEOUT_COUNT 10
+#ifdef CM4
+#define VPU_REG_BASE 0x2c000000
+#else
+#define VPU_REG_BASE 0x40000000
+#endif
+
+#define V4L2_MAX_CTRLS 12
+#define V4L2_PIX_FMT_NV12_10BIT v4l2_fourcc('N', 'T', '1', '2') /* Y/CbCr 4:2:0 for 10bit */
+
+struct vpu_v4l2_control {
+ uint32_t id;
+ enum v4l2_ctrl_type type;
+ uint32_t minimum;
+ uint32_t maximum;
+ uint32_t step;
+ uint32_t default_value;
+ uint32_t menu_skip_mask;
+ bool is_volatile;
+};
+
+typedef enum{
+ INIT_DONE = 1,
+ RPC_BUF_OFFSET,
+ PRINT_BUF_OFFSET,
+ BOOT_ADDRESS,
+ COMMAND,
+ EVENT
+} MSG_Type;
+
+enum PLAT_TYPE {
+ IMX8QXP = 0,
+ IMX8QM = 1,
+};
+
+enum QUEUE_TYPE {
+ V4L2_SRC = 0,
+ V4L2_DST = 1,
+};
+
+enum vpu_video_standard {
+ VPU_VIDEO_UNDEFINED = 0,
+ VPU_VIDEO_AVC = 1,
+ VPU_VIDEO_VC1 = 2,
+ VPU_VIDEO_MPEG2 = 3,
+ VPU_VIDEO_AVS = 4,
+ VPU_VIDEO_ASP = 5,
+ VPU_VIDEO_JPEG = 6,
+ VPU_VIDEO_RV = 7,
+ VPU_VIDEO_VP6 = 8,
+ VPU_VIDEO_SPK = 9,
+ VPU_VIDEO_VP8 = 10,
+ VPU_VIDEO_AVC_MVC = 11,
+ VPU_VIDEO_HEVC = 12,
+};
+
+typedef enum{
+ EOS_PADDING_TYPE = 1,
+ BUFFLUSH_PADDING_TYPE = 2
+} VPU_PADDING_SCODE_TYPE;
+
+#define VPU_PIX_FMT_AVS v4l2_fourcc('A', 'V', 'S', '0')
+#define VPU_PIX_FMT_ASP v4l2_fourcc('A', 'S', 'P', '0')
+#define VPU_PIX_FMT_RV v4l2_fourcc('R', 'V', '0', '0')
+#define VPU_PIX_FMT_VP6 v4l2_fourcc('V', 'P', '6', '0')
+#define VPU_PIX_FMT_SPK v4l2_fourcc('S', 'P', 'K', '0')
+#define VPU_PIX_FMT_DIVX v4l2_fourcc('D', 'I', 'V', 'X')
+#define VPU_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C')
+#define VPU_PIX_FMT_LOGO v4l2_fourcc('L', 'O', 'G', 'O')
+
+#define VPU_PIX_FMT_TILED_8 v4l2_fourcc('Z', 'T', '0', '8')
+#define VPU_PIX_FMT_TILED_10 v4l2_fourcc('Z', 'T', '1', '0')
+
+enum vpu_pixel_format {
+ VPU_HAS_COLOCATED = 0x00000001,
+ VPU_HAS_SPLIT_FLD = 0x00000002,
+ VPU_PF_MASK = ~(VPU_HAS_COLOCATED | VPU_HAS_SPLIT_FLD),
+
+ VPU_IS_TILED = 0x000000100,
+ VPU_HAS_10BPP = 0x00000200,
+
+ VPU_IS_PLANAR = 0x00001000,
+ VPU_IS_SEMIPLANAR = 0x00002000,
+ VPU_IS_PACKED = 0x00004000,
+
+ // Merged definitions using above flags:
+ VPU_PF_UNDEFINED = 0,
+ VPU_PF_YUV420_SEMIPLANAR = 0x00010000 | VPU_IS_SEMIPLANAR,
+ VPU_PF_YUV420_PLANAR = 0x00020000 | VPU_IS_PLANAR,
+ VPU_PF_UYVY = 0x00040000 | VPU_IS_PACKED,
+ VPU_PF_TILED_8BPP = 0x00080000 | VPU_IS_TILED | VPU_IS_SEMIPLANAR,
+ VPU_PF_TILED_10BPP = 0x00100000 | VPU_IS_TILED | VPU_IS_SEMIPLANAR | VPU_HAS_10BPP,
+};
+
+struct vpu_v4l2_fmt {
+ char *name;
+ unsigned int fourcc;
+ unsigned int num_planes;
+ unsigned int vdec_std;
+};
+
+struct vb2_data_req {
+ struct list_head list;
+ struct vb2_buffer *vb2_buf;
+ int id;
+ u_int32 status;
+ bool bfield;
+ u_int32 phy_addr[2]; //0 for luma, 1 for chroma
+};
+
+struct queue_data {
+ unsigned int width;
+ unsigned int height;
+ unsigned int stride;
+ unsigned int bytesperline;
+ unsigned int num_planes;
+ unsigned int sizeimage[2];
+ unsigned int fourcc;
+ unsigned int vdec_std;
+ struct v4l2_rect rect;
+ int buf_type; // v4l2_buf_type
+ bool vb2_q_inited;
+ struct vb2_queue vb2_q; // vb2 queue
+ struct list_head drv_q; // driver queue
+ struct semaphore drv_q_lock;
+ struct vb2_data_req vb2_reqs[VPU_MAX_BUFFER];
+ enum QUEUE_TYPE type;
+};
+struct vpu_ctx;
+struct vpu_dev {
+ struct device *generic_dev;
+ struct v4l2_device v4l2_dev;
+ struct video_device *pvpu_decoder_dev;
+ struct platform_device *plat_dev;
+ struct firmware *m0_pfw;
+ void *m0_p_fw_space_vir;
+ u_int32 m0_p_fw_space_phy;
+ void *m0_rpc_virt;
+ u_int32 m0_rpc_phy;
+#ifndef DYNAMIC_MEM
+ void *str_base_vir;
+ u_int32 str_base_phy;
+ u_int32 str_size;
+#endif
+ struct mutex dev_mutex;
+ struct mutex cmd_mutex;
+ bool fw_is_ready;
+ bool firmware_started;
+ struct completion start_cmp;
+ struct completion snap_done_cmp;
+ struct workqueue_struct *workqueue;
+ struct work_struct msg_work;
+ unsigned long instance_mask;
+ unsigned long hang_mask; //this is used to deal with hang issue to reset firmware
+ sc_ipc_t mu_ipcHandle;
+ struct clk *vpu_clk;
+ void __iomem *mu_base_virtaddr;
+ unsigned int vpu_mu_id;
+ int vpu_mu_init;
+ u_int32 plat_type;
+
+ struct clk *clk_m0;
+ void __iomem *regs_base;
+ u_int32 cm_offset;
+
+ struct shared_addr shared_mem;
+ struct vpu_ctx *ctx[VPU_MAX_NUM_STREAMS];
+};
+
+struct vpu_ctx {
+ struct vpu_dev *dev;
+ struct v4l2_fh fh;
+
+ struct v4l2_ctrl *ctrls[V4L2_MAX_CTRLS];
+ struct v4l2_ctrl_handler ctrl_handler;
+ bool ctrl_inited;
+
+ int str_index;
+ struct queue_data q_data[2];
+ struct kfifo msg_fifo;
+ struct mutex instance_mutex;
+ struct work_struct instance_work;
+ struct workqueue_struct *instance_wq;
+ struct completion completion;
+ struct completion stop_cmp;
+ struct completion eos_cmp;
+ MediaIPFW_Video_SeqInfo *pSeqinfo;
+ bool b_dis_reorder;
+ bool b_firstseq;
+ bool start_flag;
+ bool wait_abort_done;
+ bool wait_rst_done;
+ bool buffer_null;
+ bool firmware_stopped;
+ bool firmware_finished;
+ bool eos_stop_added;
+ bool ctx_released;
+ wait_queue_head_t buffer_wq;
+ void *dpb_dma_virt;
+ u_int32 uSize;
+ dma_addr_t dpb_dma_phy;
+ void *dcp_dma_virt[MAX_DCP_NUM];
+ u_int32 uDCPSize;
+ dma_addr_t dcp_dma_phy[MAX_DCP_NUM];
+ u_int32 dcp_count;
+ void *mbi_dma_virt[MAX_MBI_NUM];
+ u_int32 mbi_size;
+ dma_addr_t mbi_dma_phy[MAX_MBI_NUM];
+ u_int32 mbi_count;
+ u_int32 mbi_num;
+ void *stream_buffer_virt;
+ u_int32 stream_buffer_size;
+ dma_addr_t stream_buffer_phy;
+ void *udata_buffer_virt;
+ u_int32 udata_buffer_size;
+ dma_addr_t udata_buffer_phy;
+ int frm_dis_delay;
+ int frm_dec_delay;
+ int frm_total_num;
+};
+
+#define LVL_INFO 3
+#define LVL_EVENT 2
+#define LVL_WARN 1
+#define LVL_ERR 0
+
+#define vpu_dbg(level, fmt, arg...) \
+ do { \
+ if (vpu_dbg_level_decoder >= (level)) \
+ printk("[DEBUG]\t " fmt, ## arg); \
+ } while (0)
+
+#endif
diff --git a/drivers/mxc/vpu-decoder-b0/vpu_rpc.c b/drivers/mxc/vpu-decoder-b0/vpu_rpc.c
new file mode 100644
index 000000000000..d3a3b95f23a9
--- /dev/null
+++ b/drivers/mxc/vpu-decoder-b0/vpu_rpc.c
@@ -0,0 +1,353 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "vpu_rpc.h"
+
+void rpc_init_shared_memory(struct shared_addr *This,
+ unsigned long long base_phy_addr,
+ void *base_virt_addr,
+ u_int32 total_size)
+{
+ pDEC_RPC_HOST_IFACE pSharedInterface;
+ unsigned int phy_addr;
+ unsigned int i;
+ MediaIPFW_Video_BufDesc *pSharedCmdBufDescPtr;
+ MediaIPFW_Video_BufDesc *pSharedMsgBufDescPtr;
+ MediaIPFW_Video_BufDesc *pDebugBufferDesc;
+ MediaIPFW_Video_BufDesc *pEngAccessBufferDesc;
+
+ This->shared_mem_phy = base_phy_addr;
+ This->shared_mem_vir = base_virt_addr;
+
+ pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
+ This->pSharedInterface = pSharedInterface;
+
+ pSharedInterface->FwExecBaseAddr = base_phy_addr;
+ pSharedInterface->FwExecAreaSize = total_size;
+
+ pSharedCmdBufDescPtr = (MediaIPFW_Video_BufDesc *)&pSharedInterface->StreamCmdBufferDesc;
+ pSharedMsgBufDescPtr = (MediaIPFW_Video_BufDesc *)&pSharedInterface->StreamMsgBufferDesc;
+
+ phy_addr = base_phy_addr + sizeof(DEC_RPC_HOST_IFACE);
+ This->cmd_mem_phy = phy_addr;
+ This->cmd_mem_vir = This->shared_mem_vir + sizeof(DEC_RPC_HOST_IFACE);
+
+ pSharedCmdBufDescPtr->uWrPtr = phy_addr;
+ pSharedCmdBufDescPtr->uRdPtr = pSharedCmdBufDescPtr->uWrPtr;
+ pSharedCmdBufDescPtr->uStart = pSharedCmdBufDescPtr->uWrPtr;
+ pSharedCmdBufDescPtr->uEnd = pSharedCmdBufDescPtr->uStart + CMD_SIZE;
+
+ phy_addr += CMD_SIZE;
+ This->msg_mem_phy = phy_addr;
+ This->msg_mem_vir = This->cmd_mem_vir + CMD_SIZE;
+
+ pSharedMsgBufDescPtr->uWrPtr = phy_addr;
+ pSharedMsgBufDescPtr->uRdPtr = pSharedMsgBufDescPtr->uWrPtr;
+ pSharedMsgBufDescPtr->uStart = pSharedMsgBufDescPtr->uWrPtr;
+ pSharedMsgBufDescPtr->uEnd = pSharedMsgBufDescPtr->uStart + MSG_SIZE;
+
+ phy_addr += MSG_SIZE;
+ This->codec_mem_phy = phy_addr;
+ This->codec_mem_vir = This->msg_mem_vir + MSG_SIZE;
+ pSharedInterface->CodecParamTabDesc.pCodecParamArrayBase = This->codec_mem_phy;
+
+ phy_addr += CODEC_SIZE;
+ This->jpeg_mem_phy = phy_addr;
+ This->jpeg_mem_vir = This->codec_mem_vir + CODEC_SIZE;
+ pSharedInterface->JpegParamTabDesc.pJpegParamArrayBase = This->jpeg_mem_phy;
+
+ phy_addr += JPEG_SIZE;
+ This->seq_mem_phy = phy_addr;
+ This->seq_mem_vir = This->jpeg_mem_vir + JPEG_SIZE;
+
+ pSharedInterface->SeqInfoTabDesc.pSeqInfoArrayBase = This->seq_mem_phy;
+
+ phy_addr += SEQ_SIZE;
+ This->pic_mem_phy = phy_addr;
+ This->pic_mem_vir = This->seq_mem_vir + SEQ_SIZE;
+
+ pSharedInterface->PicInfoTabDesc.pPicInfoArrayBase = This->pic_mem_phy;
+
+ phy_addr += PIC_SIZE;
+ This->gop_mem_phy = phy_addr;
+ This->gop_mem_vir = This->pic_mem_vir + PIC_SIZE;
+
+ pSharedInterface->GopInfoTabDesc.pGopInfoArrayBase = This->gop_mem_phy;
+
+ phy_addr += GOP_SIZE;
+ This->qmeter_mem_phy = phy_addr;
+ This->qmeter_mem_vir = This->gop_mem_vir + GOP_SIZE;
+
+ pSharedInterface->QMeterInfoTabDesc.pQMeterInfoArrayBase = This->qmeter_mem_phy;
+
+ phy_addr += QMETER_SIZE;
+ pDebugBufferDesc = &pSharedInterface->DebugBufferDesc;
+ pDebugBufferDesc->uWrPtr = phy_addr;
+ pDebugBufferDesc->uRdPtr = pDebugBufferDesc->uWrPtr;
+ pDebugBufferDesc->uStart = pDebugBufferDesc->uWrPtr;
+ pDebugBufferDesc->uEnd = pDebugBufferDesc->uStart + DEBUG_SIZE;
+
+ phy_addr += DEBUG_SIZE;
+ for (i = 0; i < VPU_MAX_NUM_STREAMS; i++) {
+ pEngAccessBufferDesc = &pSharedInterface->EngAccessBufferDesc[i];
+ pEngAccessBufferDesc->uWrPtr = phy_addr;
+ pEngAccessBufferDesc->uRdPtr = pEngAccessBufferDesc->uWrPtr;
+ pEngAccessBufferDesc->uStart = pEngAccessBufferDesc->uWrPtr;
+ pEngAccessBufferDesc->uEnd = pEngAccessBufferDesc->uStart + ENG_SIZE;
+ phy_addr += ENG_SIZE;
+ }
+
+ for (i = 0; i < VPU_MAX_NUM_STREAMS; i++) {
+ pSharedInterface->ptEncryptInfo[i] = phy_addr;
+ phy_addr += sizeof(MediaIPFW_Video_Encrypt_Info);
+ }
+}
+
+void rpc_set_stream_cfg_value(void *Interface, u_int32 str_idx)
+{
+ pDEC_RPC_HOST_IFACE pSharedInterface;
+ u_int32 *CurrStrfg;
+
+ pSharedInterface = (pDEC_RPC_HOST_IFACE)Interface;
+ CurrStrfg = &pSharedInterface->StreamConfig[str_idx];
+ *CurrStrfg = 0;
+ //the value should be passed from application
+ VID_STREAM_CONFIG_STRBUFIDX_SET(0, CurrStrfg);
+ VID_STREAM_CONFIG_NOSEQ_SET(FALSE, CurrStrfg);
+ VID_STREAM_CONFIG_DEBLOCK_SET(FALSE, CurrStrfg);
+ VID_STREAM_CONFIG_DERING_SET(FALSE, CurrStrfg);
+ VID_STREAM_CONFIG_PLAY_MODE_SET(MEDIA_PLAYER_API_MODE_CONTINUOUS, CurrStrfg);
+ VID_STREAM_CONFIG_FS_CTRL_MODE_SET(MEDIA_PLAYER_FS_CTRL_MODE_EXTERNAL, CurrStrfg);
+ VID_STREAM_CONFIG_ENABLE_DCP_SET(TRUE, CurrStrfg);
+ VID_STREAM_CONFIG_NUM_STR_BUF_SET(1, CurrStrfg);
+ VID_STREAM_CONFIG_MALONE_USAGE_SET(1, CurrStrfg);
+ VID_STREAM_CONFIG_MULTI_VID_SET(FALSE, CurrStrfg);
+ VID_STREAM_CONFIG_OBFUSC_EN_SET(FALSE, CurrStrfg);
+ VID_STREAM_CONFIG_RC4_EN_SET(FALSE, CurrStrfg);
+ VID_STREAM_CONFIG_MCX_SET(TRUE, CurrStrfg);
+ VID_STREAM_CONFIG_PES_SET(FALSE, CurrStrfg);
+ VID_STREAM_CONFIG_NUM_DBE_SET(1, CurrStrfg);
+}
+
+void rpc_set_system_cfg_value(void *Interface, u_int32 regs_base)
+{
+ pDEC_RPC_HOST_IFACE pSharedInterface;
+ MEDIAIP_FW_SYSTEM_CONFIG *pSystemCfg;
+
+ pSharedInterface = (pDEC_RPC_HOST_IFACE)Interface;
+ pSystemCfg = &pSharedInterface->sSystemCfg;
+ pSystemCfg->uNumMalones = 1;
+ pSystemCfg->uMaloneBaseAddress[0] = (unsigned int)(regs_base + 0x180000);
+
+ pSystemCfg->uMaloneBaseAddress[0x1] = 0x0;
+ pSystemCfg->uHifOffset[0x0] = 0x1C000;
+ pSystemCfg->uHifOffset[0x1] = 0x0;
+
+ pSystemCfg->uDPVBaseAddr = 0x0;
+ pSystemCfg->uDPVIrqPin = 0x0;
+ pSystemCfg->uPixIfBaseAddr = (unsigned int)(regs_base + 0x180000 + 0x20000);
+ pSystemCfg->uFSLCacheBaseAddr[0] = (unsigned int)(regs_base + 0x60000);
+ pSystemCfg->uFSLCacheBaseAddr[1] = (unsigned int)(regs_base + 0x68000);
+}
+
+u_int32 rpc_MediaIPFW_Video_buffer_space_check(MediaIPFW_Video_BufDesc *pBufDesc,
+ BOOL bFull,
+ u_int32 uSize,
+ u_int32 *puUpdateAddress)
+{
+ u_int32 uPtr1;
+ u_int32 uPtr2;
+ u_int32 uStart;
+ u_int32 uEnd;
+ u_int32 uTemp;
+
+ /* bFull is FALSE when send message, write data */
+ /* bFull is TRUE when process commands, read data */
+ uPtr1 = (bFull) ? pBufDesc->uRdPtr : pBufDesc->uWrPtr;
+ uPtr2 = (bFull) ? pBufDesc->uWrPtr : pBufDesc->uRdPtr;
+
+ if (uPtr1 == uPtr2) {
+ if (bFull)
+ /* No data at all to read */
+ return 0;
+ else {
+ /* wrt pointer equal to read pointer thus the */
+ /* buffer is completely empty for further writes */
+ uStart = pBufDesc->uStart;
+ uEnd = pBufDesc->uEnd;
+ /* The address to be returned in this case is for */
+ /* the updated write pointer. */
+ uTemp = uPtr1 + uSize;
+ if (uTemp >= uEnd)
+ uTemp += (uStart - uEnd);
+ *puUpdateAddress = uTemp;
+ return (uEnd - uStart);
+ }
+ } else if (uPtr1 < uPtr2) {
+ /* return updated rd pointer address */
+ /* In this case if size was too big - we expect the */
+ /* external ftn to compare the size against the */
+ /* space returned.
+ */
+ *puUpdateAddress = uPtr1 + uSize;
+ return (uPtr2 - uPtr1);
+ }
+ /* We know the system has looped!! */
+ uStart = pBufDesc->uStart;
+ uEnd = pBufDesc->uEnd;
+ uTemp = uPtr1 + uSize;
+ if (uTemp >= uEnd)
+ uTemp += (uStart - uEnd);
+ *puUpdateAddress = uTemp;
+ return ((uEnd - uPtr1) + (uPtr2 - uStart));
+}
+
+static void rpc_update_cmd_buffer_ptr(MediaIPFW_Video_BufDesc *pCmdDesc)
+{
+ u_int32 uWritePtr;
+
+ uWritePtr = pCmdDesc->uWrPtr + 4;
+ if (uWritePtr >= pCmdDesc->uEnd)
+ uWritePtr = pCmdDesc->uStart;
+ pCmdDesc->uWrPtr = uWritePtr;
+}
+
+void rpc_send_cmd_buf(struct shared_addr *This,
+ u_int32 idx,
+ u_int32 cmdid,
+ u_int32 cmdnum,
+ u_int32 *local_cmddata)
+{
+ pDEC_RPC_HOST_IFACE pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
+ MediaIPFW_Video_BufDesc *pCmdDesc = &pSharedInterface->StreamCmdBufferDesc;
+ u_int32 *cmddata;
+ u_int32 i;
+ u_int32 *cmdword = (u_int32 *)(This->cmd_mem_vir+pCmdDesc->uWrPtr - pCmdDesc->uStart);
+
+ *cmdword = 0;
+ *cmdword |= ((idx & 0x000000ff) << 24);
+ *cmdword |= ((cmdnum & 0x000000ff) << 16);
+ *cmdword |= ((cmdid & 0x00003fff) << 0);
+ rpc_update_cmd_buffer_ptr(pCmdDesc);
+
+ for (i = 0; i < cmdnum; i++) {
+ cmddata = (u_int32 *)(This->cmd_mem_vir+pCmdDesc->uWrPtr - pCmdDesc->uStart);
+ *cmddata = local_cmddata[i];
+ rpc_update_cmd_buffer_ptr(pCmdDesc);
+ }
+}
+
+u_int32 rpc_MediaIPFW_Video_message_check(struct shared_addr *This)
+{
+ u_int32 uSpace;
+ u_int32 uIgnore;
+ pDEC_RPC_HOST_IFACE pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
+ MediaIPFW_Video_BufDesc *pMsgDesc = &pSharedInterface->StreamMsgBufferDesc;
+ u_int32 msgword;
+ u_int32 msgnum;
+
+ uSpace = rpc_MediaIPFW_Video_buffer_space_check(pMsgDesc, TRUE, 0, &uIgnore);
+ uSpace = (uSpace >> 2);
+ if (uSpace) {
+ /* get current msgword word */
+ msgword = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->uRdPtr - pMsgDesc->uStart));
+ /* Find the number of additional words */
+ msgnum = ((msgword & 0x00ff0000) >> 16);
+
+ /*
+ * * Check the number of message words against
+ * * 1) a limit - some sort of maximum or at least
+ * * the size of the SW buffer the message is read into
+ * * 2) The space reported (where space is write ptr - read ptr in 32bit words)
+ * * It must be less than space (as opposed to <=) because
+ * * the message itself is not included in msgword
+ */
+ if (msgnum < VID_API_MESSAGE_LIMIT) {
+ if (msgnum < uSpace)
+ return API_MSG_AVAILABLE;
+ else
+ return API_MSG_INCOMPLETE;
+ } else
+ return API_MSG_BUFFER_ERROR;
+ }
+ return API_MSG_UNAVAILABLE;
+}
+
+static void rpc_update_msg_buffer_ptr(MediaIPFW_Video_BufDesc *pMsgDesc)
+{
+ u_int32 uReadPtr;
+
+ uReadPtr = pMsgDesc->uRdPtr + 4;
+ if (uReadPtr >= pMsgDesc->uEnd)
+ uReadPtr = pMsgDesc->uStart;
+ pMsgDesc->uRdPtr = uReadPtr;
+}
+
+void rpc_receive_msg_buf(struct shared_addr *This, struct event_msg *msg)
+{
+ unsigned int i;
+ pDEC_RPC_HOST_IFACE pSharedInterface = (pDEC_RPC_HOST_IFACE)This->shared_mem_vir;
+ MediaIPFW_Video_BufDesc *pMsgDesc = &pSharedInterface->StreamMsgBufferDesc;
+ u_int32 msgword = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->uRdPtr - pMsgDesc->uStart));
+
+ msg->idx = ((msgword & 0xff000000) >> 24);
+ msg->msgnum = ((msgword & 0x00ff0000) >> 16);
+ msg->msgid = ((msgword & 0x00003fff) >> 0);
+ rpc_update_msg_buffer_ptr(pMsgDesc);
+
+ for (i = 0; i < msg->msgnum; i++) {
+ msg->msgdata[i] = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->uRdPtr - pMsgDesc->uStart));
+ rpc_update_msg_buffer_ptr(pMsgDesc);
+ }
+}
diff --git a/drivers/mxc/vpu-decoder-b0/vpu_rpc.h b/drivers/mxc/vpu-decoder-b0/vpu_rpc.h
new file mode 100644
index 000000000000..b777e5852e7c
--- /dev/null
+++ b/drivers/mxc/vpu-decoder-b0/vpu_rpc.h
@@ -0,0 +1,114 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __VPU_IPC_H
+#define __VPU_IPC_H
+
+#include "mediasys_types.h"
+
+#define CMD_SIZE 25600
+#define MSG_SIZE 25600
+#define CODEC_SIZE 0x1000
+#define JPEG_SIZE 0x1000
+#define SEQ_SIZE 0x1000
+#define GOP_SIZE 0x1000
+#define PIC_SIZE 0x1000
+#define QMETER_SIZE 0x1000
+#define DEBUG_SIZE 0x1000
+#define ENG_SIZE 0x1000
+#define LOCAL_MSG_NUM VID_API_MESSAGE_LIMIT
+
+struct shared_addr {
+ pDEC_RPC_HOST_IFACE pSharedInterface;
+ unsigned long long shared_mem_phy;
+ void *shared_mem_vir;
+ unsigned long long cmd_mem_phy;
+ void *cmd_mem_vir;
+ unsigned long long msg_mem_phy;
+ void *msg_mem_vir;
+ unsigned long long codec_mem_phy;
+ void *codec_mem_vir;
+ unsigned long long jpeg_mem_phy;
+ void *jpeg_mem_vir;
+ unsigned long long seq_mem_phy;
+ void *seq_mem_vir;
+ unsigned long long pic_mem_phy;
+ void *pic_mem_vir;
+ unsigned long long gop_mem_phy;
+ void *gop_mem_vir;
+ unsigned long long qmeter_mem_phy;
+ void *qmeter_mem_vir;
+};
+
+struct event_msg {
+ u_int32 idx;
+ u_int32 msgnum;
+ u_int32 msgid;
+ u_int32 msgdata[LOCAL_MSG_NUM];
+};
+
+void rpc_init_shared_memory(struct shared_addr *This,
+ unsigned long long base_phy_addr,
+ void *base_virt_addr,
+ u_int32 total_size);
+void rpc_set_system_cfg_value(void *Interface, u_int32 regs_base);
+void rpc_set_stream_cfg_value(void *Interface, u_int32 str_idx);
+void rpc_send_cmd_buf(struct shared_addr *This,
+ u_int32 idx,
+ u_int32 cmdid,
+ u_int32 cmdnum,
+ u_int32 *local_cmddata);
+void rpc_receive_msg_buf(struct shared_addr *This, struct event_msg *msg);
+
+#endif
diff --git a/drivers/mxc/vpu-encoder-b0/Kconfig b/drivers/mxc/vpu-encoder-b0/Kconfig
new file mode 100755
index 000000000000..40b1fcecd86f
--- /dev/null
+++ b/drivers/mxc/vpu-encoder-b0/Kconfig
@@ -0,0 +1,20 @@
+#
+# Codec configuration
+#
+
+menu "MXC VPU(Video Processing Unit) B0 ENCODER support"
+
+config MXC_VPU_ENCODER
+ tristate "Support for MXC VPU(Video Processing Unit) ENCODER"
+ default y
+ ---help---
+ The VPU codec device provides codec function for H.264 etc.
+
+config MXC_VPU_ENCODER_DEBUG
+ bool "MXC VPU ENCODER debugging"
+ depends on MXC_VPU_ENCODER != n
+ help
+ This is an option for the developers; most people should
+ say N here. This enables MXC VPU driver debugging.
+
+endmenu
diff --git a/drivers/mxc/vpu-encoder-b0/Makefile b/drivers/mxc/vpu-encoder-b0/Makefile
new file mode 100644
index 000000000000..b8a8fc117d93
--- /dev/null
+++ b/drivers/mxc/vpu-encoder-b0/Makefile
@@ -0,0 +1,12 @@
+##
+## Makefile for the VPU and M0 driver
+##
+
+EXTRA_CFLAGS += $(DEFINES)
+
+obj-y = vpu-encoder.o
+vpu-encoder-objs = vpu_encoder_b0.o \
+ vpu_encoder_rpc.o
+
+clean:
+ rm -rf $(vpu-encoder-objs)
diff --git a/drivers/mxc/vpu-encoder-b0/mediasys_types.h b/drivers/mxc/vpu-encoder-b0/mediasys_types.h
new file mode 100644
index 000000000000..4800f9a884e3
--- /dev/null
+++ b/drivers/mxc/vpu-encoder-b0/mediasys_types.h
@@ -0,0 +1,701 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _MEDIASYS_TYPES_H_
+#define _MEDIASYS_TYPES_H_
+
+typedef unsigned int u_int32;
+typedef unsigned char u_int8;
+typedef unsigned long u_int64;
+typedef unsigned int BOOL;
+typedef int int32;
+#define FALSE 0
+#define TRUE 1
+#define VPU_MAX_NUM_STREAMS 3
+#define VID_API_NUM_STREAMS 4
+#define VID_API_MAX_BUF_PER_STR 3
+#define VID_API_MAX_NUM_MVC_VIEWS 4
+#define MEDIAIP_MAX_NUM_MALONES 2
+#define MEDIAIP_MAX_NUM_MALONE_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_WINDSORS 1
+#define MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_CMD_IRQ_PINS 2
+#define MEDIAIP_MAX_NUM_MSG_IRQ_PINS 1
+#define MEDIAIP_MAX_NUM_TIMER_IRQ_PINS 4
+#define MEDIAIP_MAX_NUM_TIMER_IRQ_SLOTS 4
+#define VID_API_COMMAND_LIMIT 64
+#define VID_API_MESSAGE_LIMIT 256
+
+#define API_CMD_AVAILABLE 0x0
+#define API_CMD_INCOMPLETE 0x1
+#define API_CMD_BUFFER_ERROR 0x2
+#define API_CMD_UNAVAILABLE 0x3
+#define API_MSG_AVAILABLE 0x0
+#define API_MSG_INCOMPLETE 0x1
+#define API_MSG_BUFFER_ERROR 0x2
+#define API_MSG_UNAVAILABLE 0x3
+#define MEDIAIP_ENC_USER_DATA_WORDS 16
+#define MEDIAIP_MAX_NUM_WINDSOR_SRC_FRAMES 0x6
+#define MEDIAIP_MAX_NUM_WINDSOR_REF_FRAMES 0x3
+
+typedef enum {
+ GTB_ENC_CMD_NOOP = 0x0,
+ GTB_ENC_CMD_STREAM_START,
+ GTB_ENC_CMD_FRAME_ENCODE,
+ GTB_ENC_CMD_FRAME_SKIP,
+ GTB_ENC_CMD_STREAM_STOP,
+ GTB_ENC_CMD_PARAMETER_UPD,
+ GTB_ENC_CMD_TERMINATE,
+ GTB_ENC_CMD_SNAPSHOT,
+ GTB_ENC_CMD_ROLL_SNAPSHOT,
+ GTB_ENC_CMD_LOCK_SCHEDULER,
+ GTB_ENC_CMD_UNLOCK_SCHEDULER,
+ GTB_ENC_CMD_CONFIGURE_CODEC,
+ GTB_ENC_CMD_DEAD_MARK
+} GTB_ENC_CMD;
+
+typedef enum {
+ VID_API_ENC_EVENT_RESET_DONE = 0x1,
+ VID_API_ENC_EVENT_START_DONE,
+ VID_API_ENC_EVENT_STOP_DONE,
+ VID_API_ENC_EVENT_TERMINATE_DONE,
+ VID_API_ENC_EVENT_FRAME_INPUT_DONE,
+ VID_API_ENC_EVENT_FRAME_DONE,
+ VID_API_ENC_EVENT_FRAME_RELEASE,
+ VID_API_ENC_EVENT_PARA_UPD_DONE,
+ VID_API_ENC_EVENT_MEM_REQUEST
+
+} ENC_TB_API_ENC_EVENT;
+
+typedef enum {
+ MEDIAIP_ENC_PIC_TYPE_B_FRAME = 0,
+ MEDIAIP_ENC_PIC_TYPE_P_FRAME,
+ MEDIAIP_ENC_PIC_TYPE_I_FRAME,
+ MEDIAIP_ENC_PIC_TYPE_IDR_FRAME,
+ MEDIAIP_ENC_PIC_TYPE_BI_FRAME
+
+} MEDIAIP_ENC_PIC_TYPE, *pMEDIAIP_ENC_PIC_TYPE;
+
+typedef struct {
+ u_int32 uMemPhysAddr;
+ u_int32 uMemVirtAddr;
+ u_int32 uMemSize;
+} MEDIAIP_ENC_MEM_RESOURCE, *pMEDIAIP_ENC_MEM_RESOURCE;
+
+typedef struct {
+ u_int32 uEncFrmSize;
+ u_int32 uEncFrmNum;
+ u_int32 uRefFrmSize;
+ u_int32 uRefFrmNum;
+ u_int32 uActBufSize;
+} MEDIAIP_ENC_MEM_REQ_DATA, *pMEDIAIP_ENC_MEM_REQ_DATA;
+
+typedef struct {
+ MEDIAIP_ENC_MEM_RESOURCE tEncFrameBuffers[MEDIAIP_MAX_NUM_WINDSOR_SRC_FRAMES];
+ MEDIAIP_ENC_MEM_RESOURCE tRefFrameBuffers[MEDIAIP_MAX_NUM_WINDSOR_REF_FRAMES];
+ MEDIAIP_ENC_MEM_RESOURCE tActFrameBufferArea;
+} MEDIAIP_ENC_MEM_POOL, *pMEDIAIP_ENC_MEM_POOL;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_PIC_TYPE
+
+typedef struct {
+ u_int32 uFrameID;
+ u_int32 uPicEncodDone;
+ MEDIAIP_ENC_PIC_TYPE ePicType;
+ u_int32 uSkippedFrame;
+ u_int32 uErrorFlag;
+ u_int32 uPSNR;
+ u_int32 uFlushDone;
+ u_int32 uMBy;
+ u_int32 uMBx;
+ u_int32 uFrameSize;
+ u_int32 uFrameEncTtlCycles;
+ u_int32 uFrameEncTtlFrmCycles;
+ u_int32 uFrameEncTtlSlcCycles;
+ u_int32 uFrameEncTtlEncCycles;
+ u_int32 uFrameEncTtlHmeCycles;
+ u_int32 uFrameEncTtlDsaCycles;
+ u_int32 uFrameEncFwCycles;
+ u_int32 uFrameCrc;
+ u_int32 uNumInterrupts_1;
+ u_int32 uNumInterrupts_2;
+ u_int32 uH264POC;
+ u_int32 uRefInfo;
+ u_int32 uPicNum;
+ u_int32 uPicActivity;
+ u_int32 uSceneChange;
+ u_int32 uMBStats;
+ u_int32 uEncCacheCount0;
+ u_int32 uEncCacheCount1;
+ u_int32 uMtlWrStrbCnt;
+ u_int32 uMtlRdStrbCnt;
+ u_int32 uStrBuffWrPtr;
+ u_int32 uDiagnosticEvents;
+
+ u_int32 uProcIaccTotRdCnt;
+ u_int32 uProcDaccTotRdCnt;
+ u_int32 uProcDaccTotWrCnt;
+ u_int32 uProcDaccRegRdCnt;
+ u_int32 uProcDaccRegWrCnt;
+ u_int32 uProcDaccRngRdCnt;
+ u_int32 uProcDaccRngWrCnt;
+
+} MEDIAIP_ENC_PIC_INFO, *pMEDIAIP_ENC_PIC_INFO;
+
+typedef enum {
+ MEDIAIP_PLAYMODE_CONNECTIVITY = 0,
+ MEDIAIP_PLAYMODE_BROADCAST,
+ MEDIAIP_PLAYMODE_BROADCAST_DSS,
+ MEDIAIP_PLAYMODE_LAST = MEDIAIP_PLAYMODE_BROADCAST_DSS
+
+} MEDIA_IP_PLAYMODE;
+
+typedef struct {
+ u_int32 wptr;
+ u_int32 rptr;
+ u_int32 start;
+ u_int32 end;
+
+} BUFFER_DESCRIPTOR_TYPE, *pBUFFER_DESCRIPTOR_TYPE;
+
+typedef struct {
+ u_int32 uWrPtr;
+ u_int32 uRdPtr;
+ u_int32 uStart;
+ u_int32 uEnd;
+ u_int32 uLo;
+ u_int32 uHi;
+
+} MediaIPFW_Video_BufDesc;
+
+typedef struct {
+ u_int32 uCfgCookie;
+
+ u_int32 uNumMalones;
+ u_int32 uMaloneBaseAddress[MEDIAIP_MAX_NUM_MALONES];
+ u_int32 uHifOffset[MEDIAIP_MAX_NUM_MALONES];
+ u_int32 uMaloneIrqPin[MEDIAIP_MAX_NUM_MALONES][MEDIAIP_MAX_NUM_MALONE_IRQ_PINS];
+ u_int32 uMaloneIrqTarget[MEDIAIP_MAX_NUM_MALONES][MEDIAIP_MAX_NUM_MALONE_IRQ_PINS];
+
+ u_int32 uNumWindsors;
+ u_int32 uWindsorBaseAddress[MEDIAIP_MAX_NUM_WINDSORS];
+ u_int32 uWindsorIrqPin[MEDIAIP_MAX_NUM_WINDSORS][MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS];
+ u_int32 uWindsorIrqTarget[MEDIAIP_MAX_NUM_WINDSORS][MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS];
+
+ u_int32 uCmdIrqPin[MEDIAIP_MAX_NUM_CMD_IRQ_PINS];
+ u_int32 uCmdIrqTarget[MEDIAIP_MAX_NUM_CMD_IRQ_PINS];
+
+ u_int32 uMsgIrqPin[MEDIAIP_MAX_NUM_MSG_IRQ_PINS];
+ u_int32 uMsgIrqTarget[MEDIAIP_MAX_NUM_MSG_IRQ_PINS];
+
+ u_int32 uSysClkFreq;
+ u_int32 uNumTimers;
+ u_int32 uTimerBaseAddr;
+ u_int32 uTimerIrqPin[MEDIAIP_MAX_NUM_TIMER_IRQ_PINS];
+ u_int32 uTimerIrqTarget[MEDIAIP_MAX_NUM_TIMER_IRQ_PINS];
+ u_int32 uTimerSlots[MEDIAIP_MAX_NUM_TIMER_IRQ_SLOTS];
+
+ u_int32 uGICBaseAddr;
+ u_int32 uUartBaseAddr;
+
+ u_int32 uDPVBaseAddr;
+ u_int32 uDPVIrqPin;
+ u_int32 uDPVIrqTarget;
+
+ u_int32 uPixIfBaseAddr;
+
+ u_int32 pal_trace_level;
+ u_int32 pal_trace_destination;
+
+ u_int32 pal_trace_level1;
+ u_int32 pal_trace_destination1;
+
+ u_int32 uHeapBase;
+ u_int32 uHeapSize;
+
+ u_int32 uFSLCacheBaseAddr[2];
+
+} MEDIAIP_FW_SYSTEM_CONFIG, *pMEDIAIP_FW_SYSTEM_CONFIG;
+
+typedef struct {
+ u_int32 uFrameID;
+ u_int32 uLumaBase;
+ u_int32 uChromaBase;
+ u_int32 uParamIdx;
+
+} MEDIAIP_ENC_YUV_BUFFER_DESC, *pMEDIAIP_ENC_YUV_BUFFER_DESC;
+
+typedef struct {
+ u_int32 use_ame;
+
+ u_int32 cme_mvx_max;
+ u_int32 cme_mvy_max;
+ u_int32 ame_prefresh_y0;
+ u_int32 ame_prefresh_y1;
+ u_int32 fme_min_sad;
+ u_int32 cme_min_sad;
+
+ u_int32 fme_pred_int_weight;
+ u_int32 fme_pred_hp_weight;
+ u_int32 fme_pred_qp_weight;
+ u_int32 fme_cost_weight;
+ u_int32 fme_act_thold;
+ u_int32 fme_sad_thold;
+ u_int32 fme_zero_sad_thold;
+
+ u_int32 fme_lrg_mvx_lmt;
+ u_int32 fme_lrg_mvy_lmt;
+ u_int32 fme_force_mode;
+ u_int32 fme_force4mvcost;
+ u_int32 fme_force2mvcost;
+
+ u_int32 h264_inter_thrd;
+
+ u_int32 i16x16_mode_cost;
+ u_int32 i4x4_mode_lambda;
+ u_int32 i8x8_mode_lambda;
+
+ u_int32 inter_mod_mult;
+ u_int32 inter_sel_mult;
+ u_int32 inter_bid_cost;
+ u_int32 inter_bwd_cost;
+ u_int32 inter_4mv_cost;
+ int32 one_mv_i16_cost;
+ int32 one_mv_i4x4_cost;
+ int32 one_mv_i8x8_cost;
+ int32 two_mv_i16_cost;
+ int32 two_mv_i4x4_cost;
+ int32 two_mv_i8x8_cost;
+ int32 four_mv_i16_cost;
+ int32 four_mv_i4x4_cost;
+ int32 four_mv_i8x8_cost;
+
+ u_int32 intra_pred_enab;
+ u_int32 intra_chr_pred;
+ u_int32 intra16_pred;
+ u_int32 intra4x4_pred;
+ u_int32 intra8x8_pred;
+
+ u_int32 cb_base;
+ u_int32 cb_size;
+ u_int32 cb_head_room;
+
+ u_int32 mem_page_width;
+ u_int32 mem_page_height;
+ u_int32 mem_total_size;
+ u_int32 mem_chunk_phys_addr;
+ u_int32 mem_chunk_virt_addr;
+ u_int32 mem_chunk_size;
+ u_int32 mem_y_stride;
+ u_int32 mem_uv_stride;
+
+ u_int32 split_wr_enab;
+ u_int32 split_wr_req_size;
+ u_int32 split_rd_enab;
+ u_int32 split_rd_req_size;
+
+} MEDIAIP_ENC_CALIB_PARAMS, *pMEDIAIP_ENC_CALIB_PARAMS;
+
+typedef struct {
+ u_int32 ParamChange;
+
+ u_int32 start_frame; // These variables are for debugging purposes only
+ u_int32 end_frame;
+
+ u_int32 userdata_enable;
+ u_int32 userdata_id[4];
+ u_int32 userdata_message[MEDIAIP_ENC_USER_DATA_WORDS];
+ u_int32 userdata_length;
+
+ u_int32 h264_profile_idc;
+ u_int32 h264_level_idc;
+ u_int32 h264_au_delimiter; // Enable the use of Access Unit Delimiters
+ u_int32 h264_seq_end_code; // Enable the use of Sequence End Codes
+ u_int32 h264_recovery_points; // Enable the use of Recovery Points (must be with a fixed GOP structure)
+ u_int32 h264_vui_parameters; // Enable the use of VUI parameters (for rate control purposes)
+ u_int32 h264_aspect_ratio_present;
+ u_int32 h264_aspect_ratio_sar_width;
+ u_int32 h264_aspect_ratio_sar_height;
+ u_int32 h264_overscan_present;
+ u_int32 h264_video_type_present;
+ u_int32 h264_video_format;
+ u_int32 h264_video_full_range;
+ u_int32 h264_video_colour_descriptor;
+ u_int32 h264_video_colour_primaries;
+ u_int32 h264_video_transfer_char;
+ u_int32 h264_video_matrix_coeff;
+ u_int32 h264_chroma_loc_info_present;
+ u_int32 h264_chroma_loc_type_top;
+ u_int32 h264_chroma_loc_type_bot;
+ u_int32 h264_timing_info_present;
+ u_int32 h264_buffering_period_present;
+ u_int32 h264_low_delay_hrd_flag;
+
+ u_int32 aspect_ratio;
+ u_int32 test_mode; // Automated firmware test mode
+ u_int32 dsa_test_mode; // Automated test mode for the DSA.
+ u_int32 fme_test_mode; // Automated test mode for the fme
+
+ u_int32 cbr_row_mode; //0: FW mode; 1: HW mode
+ u_int32 windsor_mode; //0: normal mode; 1: intra only mode; 2: intra+0MV mode
+ u_int32 encode_mode; // H264, VC1, MPEG2, DIVX
+ u_int32 frame_width; // display width
+ u_int32 frame_height; // display height
+ u_int32 enc_frame_width; // encoding width, should be 16-pix align
+ u_int32 enc_frame_height; // encoding height, should be 16-pix aligned for progressive and 32-pix aligned for interlace
+ u_int32 frame_rate_num;
+ u_int32 frame_rate_den;
+
+ u_int32 vi_field_source; // vi input source is frame or field
+ u_int32 vi_frame_width;
+ u_int32 vi_frame_height;
+ u_int32 crop_frame_width;
+ u_int32 crop_frame_height;
+ u_int32 crop_x_start_posn;
+ u_int32 crop_y_start_posn;
+ u_int32 mode422;
+ u_int32 mode_yuy2;
+ u_int32 dsa_luma_en;
+ u_int32 dsa_chroma_en;
+ u_int32 dsa_ext_hfilt_en;
+ u_int32 dsa_di_en;
+ u_int32 dsa_di_top_ref;
+ u_int32 dsa_vertf_disable; // disable the vertical filter.
+ u_int32 dsa_disable_pwb;
+ u_int32 dsa_hor_phase;
+ u_int32 dsa_ver_phase;
+
+ u_int32 dsa_iac_enable; // IAC / DSA cannot operate independently in FW so this variable controls
+ u_int32 iac_sc_threshold;
+ u_int32 iac_vm_threshold;
+ u_int32 iac_skip_mode;
+ u_int32 iac_grp_width;
+ u_int32 iac_grp_height;
+
+ u_int32 rate_control_mode;
+ u_int32 rate_control_resolution;
+ u_int32 buffer_size;
+ u_int32 buffer_level_init;
+ u_int32 buffer_I_bit_budget;
+
+ u_int32 top_field_first;
+
+ u_int32 intra_lum_qoffset;
+ u_int32 intra_chr_qoffset;
+ u_int32 inter_lum_qoffset;
+ u_int32 inter_chr_qoffset;
+ u_int32 use_def_scaling_mtx;
+
+ u_int32 inter_8x8_enab;
+ u_int32 inter_4x4_enab;
+
+ u_int32 fme_enable_qpel;
+ u_int32 fme_enable_hpel;
+ u_int32 fme_nozeromv; // can force the FME not to do the (0,0) search.
+ u_int32 fme_predmv_en;
+ u_int32 fme_pred_2mv4mv;
+ u_int32 fme_smallsadthresh;
+
+ u_int32 ame_en_lmvc;
+ u_int32 ame_x_mult;
+ u_int32 cme_enable_4mv; // Enable the use of 4MV partitioning
+ u_int32 cme_enable_1mv;
+ u_int32 hme_enable_16x8mv;
+ u_int32 hme_enable_8x16mv;
+ u_int32 cme_mv_weight; // CME motion vector decisions are made by combining these
+ u_int32 cme_mv_cost; // cost and weight variables
+ u_int32 ame_mult_mv;
+ u_int32 ame_shift_mv;
+
+ u_int32 hme_forceto1mv_en;
+ u_int32 hme_2mv_cost; // the cost of choosing a 2MV mode over 1MV.
+ u_int32 hme_pred_mode;
+ u_int32 hme_sc_rnge;
+ u_int32 hme_sw_rnge;
+
+ // for windsor pes , add by fulin
+ u_int32 output_format; // 0: output ES; 1: output PES
+ u_int32 timestamp_enab; // 0: have timestamps in all frame; 1: have timestamps in I and P frame; 2: have timestamps only in I frame
+ u_int32 initial_PTS_enab; // if enabled , use following value,else compute by fw
+ u_int32 initial_PTS; // the initial value of PTS in the first frame (ms)
+
+} MEDIAIP_ENC_CONFIG_PARAMS, *pMEDIAIP_ENC_CONFIG_PARAMS;
+
+typedef struct {
+ u_int32 ParamChange;
+
+ u_int32 gop_length;
+
+ u_int32 rate_control_bitrate;
+ u_int32 rate_control_bitrate_min;
+ u_int32 rate_control_bitrate_max;
+ u_int32 rate_control_content_models;
+ u_int32 rate_control_iframe_maxsize; // Maximum size of I frame generated by BPM in comparison to ideal (/4)
+ u_int32 rate_control_qp_init;
+ u_int32 rate_control_islice_qp;
+ u_int32 rate_control_pslice_qp;
+ u_int32 rate_control_bslice_qp;
+
+ u_int32 adaptive_quantization; // Enable the use of activity measures from VIPP in QP assignment
+ u_int32 aq_variance;
+ u_int32 cost_optimization; // Enable picture/frame level adjustments of the cost parameters by FW.
+ u_int32 fdlp_mode; // Frequency-domain low-pass filter control, 0: off, 1-4: specific, 5: adaptive
+ u_int32 enable_isegbframes; // Enable the use of B frames in the first segment of a GOP
+ u_int32 enable_adaptive_keyratio; // Enable the use of an adaptive I to P/B ratio (aims to reduce distortion)
+ u_int32 keyratio_imin; // Clamps applied to picture size ratios
+ u_int32 keyratio_imax;
+ u_int32 keyratio_pmin;
+ u_int32 keyratio_pmax;
+ u_int32 keyratio_bmin;
+ u_int32 keyratio_bmax;
+ int32 keyratio_istep;
+ int32 keyratio_pstep;
+ int32 keyratio_bstep;
+
+ u_int32 enable_paff; // Enable Picture Adaptive Frame/Field
+ u_int32 enable_b_frame_ref; // Enable B frame as references
+ u_int32 enable_adaptive_gop; // Enable an adaptive GOP structure
+ u_int32 enable_closed_gop; // Enable a closed GOP structure
+ // i.e. if enabled, the first consecutive B frames following
+ // an I frame in each GOP will be intra or backwards only coded
+ // and do not rely on previous reference pictures.
+ u_int32 open_gop_refresh_freq; // Controls the insertion of closed GOP's (or IDR GOP's in H.264)
+ u_int32 enable_adaptive_sc; // Enable adaptive scene change GOP structure (0:off, 1:adaptive, 2:IDR)
+ u_int32 enable_fade_detection; // Enable fade detection and associated motion estimation restrictions
+ int32 fade_detection_threshold; // Threshold at which the activity slope indicates a possible fading event
+ u_int32 enable_repeat_b; // Enalbe the repeated B frame mode at CBR
+ u_int32 enable_low_delay_b; // Use low delay-b frames with an IPPPP style GOP
+
+} MEDIAIP_ENC_STATIC_PARAMS, *pMEDIAIP_ENC_STATIC_PARAMS;
+
+typedef struct {
+ u_int32 ParamChange;
+
+ u_int32 rows_per_slice;
+
+ u_int32 mbaff_enable; // Macroblock adaptive frame/field enable
+ u_int32 dbf_enable; // Enable the deblocking filter
+
+ u_int32 field_source; // progressive/interlaced control
+ u_int32 gop_b_length; // Number of B frames between anchor frames
+ // (only to be changed at a GOP segment boundary)
+ u_int32 mb_group_size; // Number of macroblocks normally assigned to a group
+ // (implications for performance, interrupts and rate control)
+
+ u_int32 cbr_rows_per_group;
+
+ u_int32 skip_enable; // Enable the use of skipped macroblocks
+
+ u_int32 pts_bits_0_to_31; // TO BE REMOVED...
+ u_int32 pts_bit_32;
+
+ u_int32 rm_expsv_cff;
+ u_int32 const_ipred;
+ int32 chr_qp_offset;
+ u_int32 intra_mb_qp_offset;
+
+ u_int32 h264_cabac_init_method;
+ u_int32 h264_cabac_init_idc;
+ u_int32 h264_cabac_enable; // Main and stream
+
+ int32 alpha_c0_offset_div2;
+ int32 beta_offset_div2;
+
+ u_int32 intra_prefresh_y0; // for setting intra limits for prog refresh.
+ u_int32 intra_prefresh_y1;
+
+ u_int32 dbg_dump_rec_src;
+
+} MEDIAIP_ENC_DYN_PARAMS, *pMEDIAIP_ENC_DYN_PARAMS;
+
+typedef struct {
+ MEDIAIP_ENC_CALIB_PARAMS Calib;
+ MEDIAIP_ENC_CONFIG_PARAMS Config;
+ MEDIAIP_ENC_STATIC_PARAMS Static;
+ MEDIAIP_ENC_DYN_PARAMS Dynamic;
+} MEDIAIP_ENC_EXPERT_MODE_PARAM, *pMEDIAIP_ENC_EXPERT_MODE_PARAM;
+
+typedef enum {
+ MEDIAIP_ENC_FMT_H264 = 0,
+ MEDIAIP_ENC_FMT_VC1,
+ MEDIAIP_ENC_FMT_MPEG2,
+ MEDIAIP_ENC_FMT_MPEG4SP,
+ MEDIAIP_ENC_FMT_H263,
+ MEDIAIP_ENC_FMT_MPEG1,
+ MEDIAIP_ENC_FMT_SHORT_HEADER,
+ MEDIAIP_ENC_FMT_NULL
+
+} MEDIAIP_ENC_FMT;
+
+typedef enum {
+ MEDIAIP_ENC_PROF_MPEG2_SP = 0,
+ MEDIAIP_ENC_PROF_MPEG2_MP,
+ MEDIAIP_ENC_PROF_MPEG2_HP,
+ MEDIAIP_ENC_PROF_H264_BP,
+ MEDIAIP_ENC_PROF_H264_MP,
+ MEDIAIP_ENC_PROF_H264_HP,
+ MEDIAIP_ENC_PROF_MPEG4_SP,
+ MEDIAIP_ENC_PROF_MPEG4_ASP,
+ MEDIAIP_ENC_PROF_VC1_SP,
+ MEDIAIP_ENC_PROF_VC1_MP,
+ MEDIAIP_ENC_PROF_VC1_AP
+
+} MEDIAIP_ENC_PROFILE;
+
+typedef enum {
+ MEDIAIP_ENC_BITRATECONTROLMODE_VBR = 0x00000001,
+ MEDIAIP_ENC_BITRATECONTROLMODE_CBR = 0x00000002,
+ MEDIAIP_ENC_BITRATECONTROLMODE_CONSTANT_QP = 0x00000004 /* Only in debug mode */
+
+} MEDIAIP_ENC_BITRATE_MODE, *pMEDIAIP_ENC_BITRATE_MODE;
+
+typedef struct {
+ MEDIAIP_ENC_FMT eCodecMode;
+ MEDIAIP_ENC_PROFILE eProfile;
+ u_int32 uLevel;
+
+ MEDIAIP_ENC_MEM_RESOURCE tEncMemDesc;
+
+ u_int32 uFrameRate;
+ u_int32 uSrcStride;
+ u_int32 uSrcWidth;
+ u_int32 uSrcHeight;
+ u_int32 uSrcOffset_x;
+ u_int32 uSrcOffset_y;
+ u_int32 uSrcCropWidth;
+ u_int32 uSrcCropHeight;
+ u_int32 uOutWidth;
+ u_int32 uOutHeight;
+ u_int32 uIFrameInterval;
+ u_int32 uGopBLength;
+ u_int32 uLowLatencyMode;
+
+ MEDIAIP_ENC_BITRATE_MODE eBitRateMode;
+ u_int32 uTargetBitrate;
+ u_int32 uMaxBitRate;
+ u_int32 uMinBitRate;
+ u_int32 uInitSliceQP;
+
+} MEDIAIP_ENC_PARAM, *pMEDIAIP_ENC_PARAM;
+
+typedef struct {
+ u_int32 uFrameID;
+ u_int32 uErrorFlag; //Error type
+ u_int32 uMBy;
+ u_int32 uMBx;
+ u_int32 uReserved[12];
+
+} ENC_ENCODING_STATUS, *pENC_ENCODING_STATUS;
+
+typedef struct {
+ u_int32 uFrameID;
+ u_int32 uDsaCyle;
+ u_int32 uMBy;
+ u_int32 uMBx;
+ u_int32 uReserved[4];
+
+} ENC_DSA_STATUS_t, *pENC_DSA_STATUS_t;
+
+typedef struct {
+ u_int32 pEncYUVBufferDesc;
+ u_int32 pEncStreamBufferDesc;
+ u_int32 pEncExpertModeParam;
+ u_int32 pEncParam;
+ u_int32 pEncMemPool;
+ /* Status information for master to read */
+ u_int32 pEncEncodingStatus;
+ u_int32 pEncDSAStatus;
+} MEDIA_ENC_API_CONTROL_INTERFACE, *pMEDIA_ENC_API_CONTROL_INTERFACE;
+
+typedef struct {
+ u_int32 FwExecBaseAddr;
+ u_int32 FwExecAreaSize;
+ BUFFER_DESCRIPTOR_TYPE StreamCmdBufferDesc;
+ BUFFER_DESCRIPTOR_TYPE StreamMsgBufferDesc;
+ u_int32 StreamCmdIntEnable[VID_API_NUM_STREAMS];
+ u_int32 FWVersion;
+ u_int32 uMVDFWOffset;
+ u_int32 uMaxEncoderStreams;
+ u_int32 pEncCtrlInterface[VID_API_NUM_STREAMS];
+ MEDIAIP_FW_SYSTEM_CONFIG sSystemCfg;
+ u_int32 uApiVersion;
+} ENC_RPC_HOST_IFACE, *pENC_RPC_HOST_IFACE;
+
+#define SCB_XREG_SLV_BASE 0x00000000
+#define SCB_SCB_BLK_CTRL 0x00070000
+#define SCB_BLK_CTRL_XMEM_RESET_SET 0x00000090
+#define SCB_BLK_CTRL_CACHE_RESET_SET 0x000000A0
+#define SCB_BLK_CTRL_CACHE_RESET_CLR 0x000000A4
+#define SCB_BLK_CTRL_SCB_CLK_ENABLE_SET 0x00000100
+
+#define XMEM_CONTROL 0x00041000
+
+#define DEC_MFD_XREG_SLV_BASE 0x00180000
+
+#define MFD_HIF 0x0001C000
+#define MFD_HIF_MSD_REG_INTERRUPT_STATUS 0x00000018
+#define MFD_SIF 0x0001D000
+#define MFD_SIF_CTRL_STATUS 0x000000F0
+#define MFD_SIF_INTR_STATUS 0x000000F4
+#define MFD_MCX 0x00020800
+#define MFD_MCX_OFF 0x00000020
+
+#define MFD_BLK_CTRL 0x00030000
+#define MFD_BLK_CTRL_MFD_SYS_RESET_SET 0x00000000
+#define MFD_BLK_CTRL_MFD_SYS_RESET_CLR 0x00000004
+#define MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_SET 0x00000100
+#define MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_CLR 0x00000104
+
+#endif
diff --git a/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.c b/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.c
new file mode 100644
index 000000000000..c57cdf563670
--- /dev/null
+++ b/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.c
@@ -0,0 +1,2408 @@
+/*
+ * Copyright 2018 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file vpu_encoder_b0.c
+ *
+ * copyright here may be changed later
+ *
+ *
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/file.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/platform_data/dma-imx.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/pm_runtime.h>
+#include <linux/mx8_mu.h>
+#include <linux/uaccess.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "vpu_encoder_b0.h"
+
+unsigned int vpu_dbg_level_encoder = 1;
+#ifdef DUMP_DATA
+#define DATA_NUM 10
+#endif
+
+static char *mu_cmp[] = {
+ "fsl,imx8-mu1-vpu-m0",
+ "fsl,imx8-mu2-vpu-m0"
+};
+
+// H264 level is maped like level 5.1 to uLevel 51, except level 1b to uLevel 14
+u_int32 h264_lvl[] = {10, 14, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41, 42, 50, 51};
+
+static char *cmd2str[] = {
+ "GTB_ENC_CMD_NOOP", /*0x0*/
+ "GTB_ENC_CMD_STREAM_START",
+ "GTB_ENC_CMD_FRAME_ENCODE",
+ "GTB_ENC_CMD_FRAME_SKIP",
+ "GTB_ENC_CMD_STREAM_STOP",
+ "GTB_ENC_CMD_PARAMETER_UPD",
+ "GTB_ENC_CMD_TERMINATE",
+ "GTB_ENC_CMD_SNAPSHOT",
+ "GTB_ENC_CMD_ROLL_SNAPSHOT",
+ "GTB_ENC_CMD_LOCK_SCHEDULER",
+ "GTB_ENC_CMD_UNLOCK_SCHEDULER",
+ "GTB_ENC_CMD_CONFIGURE_CODEC",
+ "GTB_ENC_CMD_DEAD_MARK",
+};
+
+static char *event2str[] = {
+ "VID_API_EVENT_UNDEFINED", /*0x1*/
+ "VID_API_ENC_EVENT_RESET_DONE", /*0x1*/
+ "VID_API_ENC_EVENT_START_DONE",
+ "VID_API_ENC_EVENT_STOP_DONE",
+ "VID_API_ENC_EVENT_TERMINATE_DONE",
+ "VID_API_ENC_EVENT_FRAME_INPUT_DONE",
+ "VID_API_ENC_EVENT_FRAME_DONE",
+ "VID_API_ENC_EVENT_FRAME_RELEASE",
+ "VID_API_ENC_EVENT_PARA_UPD_DONE",
+ "VID_API_ENC_EVENT_MEM_REQUEST",
+};
+
+static void vpu_log_event(u_int32 uEvent, u_int32 ctxid)
+{
+ if (uEvent > ARRAY_SIZE(event2str)-1)
+ vpu_dbg(LVL_INFO, "reveive event: 0x%X, ctx id:%d\n", uEvent, ctxid);
+ else
+ vpu_dbg(LVL_INFO, "recevie event: %s, ctx id:%d\n", event2str[uEvent], ctxid);
+}
+
+static void vpu_log_cmd(u_int32 cmdid, u_int32 ctxid)
+{
+ if (cmdid > ARRAY_SIZE(cmd2str)-1)
+ vpu_dbg(LVL_INFO, "send cmd: 0x%X, ctx id:%d\n", cmdid, ctxid);
+ else
+ vpu_dbg(LVL_INFO, "send cmd: %s ctx id:%d\n", cmd2str[cmdid], ctxid);
+}
+
+/*
+ * v4l2 ioctl() operation
+ *
+ */
+static struct vpu_v4l2_fmt formats_compressed_enc[] = {
+ {
+ .name = "H264 Encoded Stream",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .num_planes = 1,
+ .venc_std = VPU_VIDEO_AVC,
+ },
+};
+
+static struct vpu_v4l2_fmt formats_yuv_enc[] = {
+ {
+ .name = "4:2:0 2 Planes Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .num_planes = 2,
+ .venc_std = VPU_PF_YUV420_SEMIPLANAR,
+ },
+};
+static void v4l2_vpu_send_cmd(struct vpu_ctx *ctx, uint32_t idx, uint32_t cmdid, uint32_t cmdnum, uint32_t *local_cmddata);
+
+static void MU_sendMesgToFW(void __iomem *base, MSG_Type type, uint32_t value)
+{
+ MU_SendMessage(base, 1, value);
+ MU_SendMessage(base, 0, type);
+}
+
+static int v4l2_ioctl_querycap(struct file *file,
+ void *fh,
+ struct v4l2_capability *cap
+ )
+{
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+ strncpy(cap->driver, "vpu encoder", sizeof(cap->driver) - 1);
+ strlcpy(cap->card, "vpu encoder", sizeof(cap->card));
+ strlcpy(cap->bus_info, "platform:", sizeof(cap->bus_info));
+ cap->version = KERNEL_VERSION(0, 0, 1);
+ cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+static int v4l2_ioctl_enum_fmt_vid_cap_mplane(struct file *file,
+ void *fh,
+ struct v4l2_fmtdesc *f
+ )
+{
+ struct vpu_v4l2_fmt *fmt;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+ if (f->index >= ARRAY_SIZE(formats_compressed_enc))
+ return -EINVAL;
+
+ fmt = &formats_compressed_enc[f->index];
+ strlcpy(f->description, fmt->name, sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ f->flags |= V4L2_FMT_FLAG_COMPRESSED;
+ return 0;
+}
+static int v4l2_ioctl_enum_fmt_vid_out_mplane(struct file *file,
+ void *fh,
+ struct v4l2_fmtdesc *f
+ )
+{
+ struct vpu_v4l2_fmt *fmt;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (f->index >= ARRAY_SIZE(formats_yuv_enc))
+ return -EINVAL;
+
+ fmt = &formats_yuv_enc[f->index];
+ strlcpy(f->description, fmt->name, sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ return 0;
+}
+
+static int v4l2_ioctl_g_fmt(struct file *file,
+ void *fh,
+ struct v4l2_format *f
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ unsigned int i;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ pix_mp->pixelformat = V4L2_PIX_FMT_NV12;
+ pix_mp->width = ctx->q_data[V4L2_SRC].width;
+ pix_mp->height = ctx->q_data[V4L2_SRC].height;
+ pix_mp->field = V4L2_FIELD_ANY;
+ pix_mp->num_planes = 2;
+ pix_mp->colorspace = V4L2_COLORSPACE_REC709;
+
+ for (i = 0; i < pix_mp->num_planes; i++)
+ pix_mp->plane_fmt[i].sizeimage = ctx->q_data[V4L2_SRC].sizeimage[i];
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ pix_mp->width = ctx->q_data[V4L2_DST].width;
+ pix_mp->height = ctx->q_data[V4L2_DST].height;
+ pix_mp->field = V4L2_FIELD_ANY;
+ pix_mp->plane_fmt[0].bytesperline = ctx->q_data[V4L2_DST].width;
+ pix_mp->plane_fmt[0].sizeimage = ctx->q_data[V4L2_DST].sizeimage[0];
+ pix_mp->pixelformat = V4L2_PIX_FMT_H264;
+ pix_mp->num_planes = 1;
+ } else
+ return -EINVAL;
+ return 0;
+}
+
+static void get_param_from_v4l2(pMEDIAIP_ENC_PARAM pEncParam,
+ struct v4l2_pix_format_mplane *pix_mp,
+ struct vpu_ctx *ctx
+ )
+{
+ //get the param and update gpParameters
+ pEncParam->eCodecMode = MEDIAIP_ENC_FMT_H264;
+
+ pEncParam->tEncMemDesc.uMemPhysAddr = ctx->encoder_mem.phy_addr;
+ pEncParam->tEncMemDesc.uMemVirtAddr = ctx->encoder_mem.phy_addr;
+ pEncParam->tEncMemDesc.uMemSize = ctx->encoder_mem.size;
+
+ pEncParam->uFrameRate = 30;
+ pEncParam->uSrcStride = pix_mp->width;
+ pEncParam->uSrcWidth = pix_mp->width;
+ pEncParam->uSrcHeight = pix_mp->height;
+ pEncParam->uSrcOffset_x = 0;
+ pEncParam->uSrcOffset_y = 0;
+ pEncParam->uSrcCropWidth = pix_mp->width;
+ pEncParam->uSrcCropHeight = pix_mp->height;
+ pEncParam->uOutWidth = pix_mp->width;
+ pEncParam->uOutHeight = pix_mp->height;
+ pEncParam->uLowLatencyMode = 0;
+
+ pEncParam->uIFrameInterval = 10;
+
+ vpu_dbg(LVL_INFO, "eCodecMode(%d) eProfile(%d) uSrcStride(%d) uSrcWidth(%d) uSrcHeight(%d) uSrcOffset_x(%d) uSrcOffset_y(%d) uSrcCropWidth(%d) uSrcCropHeight(%d) uOutWidth(%d) uOutHeight(%d) uGopBLength(%d) uLowLatencyMode(%d) uInitSliceQP(%d) uIFrameInterval(%d) eBitRateMode(%d) uTargetBitrate(%d) uMaxBitRate(%d) uMinBitRate(%d) uFrameRate(%d)\n",
+ pEncParam->eCodecMode, pEncParam->eProfile, pEncParam->uSrcStride, pEncParam->uSrcWidth,
+ pEncParam->uSrcHeight, pEncParam->uSrcOffset_x, pEncParam->uSrcOffset_y, pEncParam->uSrcCropWidth, pEncParam->uSrcCropHeight,
+ pEncParam->uOutWidth, pEncParam->uOutHeight, pEncParam->uGopBLength, pEncParam->uLowLatencyMode, pEncParam->uInitSliceQP, pEncParam->uIFrameInterval, pEncParam->eBitRateMode, pEncParam->uTargetBitrate, pEncParam->uMaxBitRate, pEncParam->uMinBitRate, pEncParam->uFrameRate);
+}
+
+static void *phy_to_virt(u_int32 src, unsigned long long offset)
+{
+ void *result;
+
+ result = (void *)(src + offset);
+ return result;
+}
+
+static int v4l2_ioctl_s_fmt(struct file *file,
+ void *fh,
+ struct v4l2_format *f
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ int ret = 0;
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct queue_data *q_data;
+ struct core_device *dev = &ctx->dev->core_dev[ctx->core_id];
+ pENC_RPC_HOST_IFACE pSharedInterface = dev->shared_mem.pSharedInterface;
+ pMEDIA_ENC_API_CONTROL_INTERFACE pEncCtrlInterface;
+ pMEDIAIP_ENC_PARAM pEncParam;
+ pMEDIAIP_ENC_EXPERT_MODE_PARAM pEncExpertModeParam;
+ u_int32 i;
+
+ pEncCtrlInterface = (pMEDIA_ENC_API_CONTROL_INTERFACE)phy_to_virt(pSharedInterface->pEncCtrlInterface[ctx->str_index],
+ dev->shared_mem.base_offset);
+ pEncParam = (pMEDIAIP_ENC_PARAM)phy_to_virt(pEncCtrlInterface->pEncParam,
+ dev->shared_mem.base_offset);
+ pEncExpertModeParam = (pMEDIAIP_ENC_EXPERT_MODE_PARAM)phy_to_virt(pEncCtrlInterface->pEncExpertModeParam,
+ dev->shared_mem.base_offset);
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ q_data = &ctx->q_data[V4L2_SRC];
+
+ get_param_from_v4l2(pEncParam, pix_mp, ctx);
+ q_data->fourcc = pix_mp->pixelformat;
+ q_data->width = pix_mp->width;
+ q_data->height = pix_mp->height;
+ q_data->rect.left = 0;
+ q_data->rect.top = 0;
+ q_data->rect.width = pix_mp->width;
+ q_data->rect.height = pix_mp->height;
+ q_data->sizeimage[0] = pix_mp->width * pix_mp->height;
+ q_data->sizeimage[1] = pix_mp->width * pix_mp->height / 2;
+ pix_mp->num_planes = 2;
+ for (i = 0; i < pix_mp->num_planes; i++)
+ pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ q_data = &ctx->q_data[V4L2_DST];
+ q_data->fourcc = pix_mp->pixelformat;
+ q_data->width = pix_mp->width;
+ q_data->height = pix_mp->height;
+ q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage;
+ } else
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static int v4l2_ioctl_expbuf(struct file *file,
+ void *fh,
+ struct v4l2_exportbuffer *buf
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct queue_data *q_data;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ q_data = &ctx->q_data[V4L2_SRC];
+ else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ q_data = &ctx->q_data[V4L2_DST];
+ else
+ return -EINVAL;
+
+ return (vb2_expbuf(&q_data->vb2_q,
+ buf
+ ));
+}
+
+static int v4l2_ioctl_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub
+ )
+{
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ switch (sub->type) {
+ case V4L2_EVENT_EOS:
+ return v4l2_event_subscribe(fh, sub, 0, NULL);
+ case V4L2_EVENT_SOURCE_CHANGE:
+ return v4l2_src_change_event_subscribe(fh, sub);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int v4l2_ioctl_reqbufs(struct file *file,
+ void *fh,
+ struct v4l2_requestbuffers *reqbuf
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct queue_data *q_data;
+ int ret;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ q_data = &ctx->q_data[V4L2_SRC];
+ else if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ q_data = &ctx->q_data[V4L2_DST];
+ else
+ return -EINVAL;
+
+ ret = vb2_reqbufs(&q_data->vb2_q, reqbuf);
+
+ vpu_dbg(LVL_INFO, "%s() c_port_req_buf(%d)\n",
+ __func__, ret);
+
+ return ret;
+}
+
+static int v4l2_ioctl_querybuf(struct file *file,
+ void *fh,
+ struct v4l2_buffer *buf
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct queue_data *q_data;
+ unsigned int i;
+ int ret;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ q_data = &ctx->q_data[V4L2_SRC];
+ else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ q_data = &ctx->q_data[V4L2_DST];
+ else
+ return -EINVAL;
+
+ ret = vb2_querybuf(&q_data->vb2_q, buf);
+ if (!ret) {
+ if (buf->memory == V4L2_MEMORY_MMAP) {
+ if (V4L2_TYPE_IS_MULTIPLANAR(buf->type)) {
+ for (i = 0; i < buf->length; i++)
+ buf->m.planes[i].m.mem_offset |= (q_data->type << MMAP_BUF_TYPE_SHIFT);
+ } else
+ buf->m.offset |= (q_data->type << MMAP_BUF_TYPE_SHIFT);
+ }
+ }
+
+ return ret;
+}
+
+static int v4l2_ioctl_qbuf(struct file *file,
+ void *fh,
+ struct v4l2_buffer *buf
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct queue_data *q_data;
+ int ret;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ q_data = &ctx->q_data[V4L2_SRC];
+ else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ q_data = &ctx->q_data[V4L2_DST];
+ else
+ return -EINVAL;
+
+ ret = vb2_qbuf(&q_data->vb2_q, buf);
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ wake_up_interruptible(&ctx->buffer_wq_output);
+ else
+ wake_up_interruptible(&ctx->buffer_wq_input);
+
+ return ret;
+}
+
+static int v4l2_ioctl_dqbuf(struct file *file,
+ void *fh,
+ struct v4l2_buffer *buf
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct queue_data *q_data;
+ int ret;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ q_data = &ctx->q_data[V4L2_SRC];
+ else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ q_data = &ctx->q_data[V4L2_DST];
+ else
+ return -EINVAL;
+
+ ret = vb2_dqbuf(&q_data->vb2_q, buf, file->f_flags & O_NONBLOCK);
+
+ if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ buf->flags = q_data->vb2_reqs[buf->index].buffer_flags;
+
+ return ret;
+}
+
+static bool format_is_support(struct vpu_v4l2_fmt *format_table,
+ unsigned int table_size,
+ struct v4l2_format *f)
+{
+ unsigned int i;
+
+ for (i = 0; i < table_size; i++) {
+ if (format_table[i].fourcc == f->fmt.pix_mp.pixelformat)
+ return true;
+ }
+ return false;
+}
+
+static int v4l2_ioctl_try_fmt(struct file *file,
+ void *fh,
+ struct v4l2_format *f
+ )
+{
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ unsigned int table_size;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ table_size = ARRAY_SIZE(formats_compressed_enc);
+ if (!format_is_support(formats_compressed_enc, table_size, f))
+ return -EINVAL;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ pix_mp->field = V4L2_FIELD_ANY;
+ pix_mp->colorspace = V4L2_COLORSPACE_REC709;
+ table_size = ARRAY_SIZE(formats_yuv_enc);
+ if (!format_is_support(formats_yuv_enc, table_size, f))
+ return -EINVAL;
+ } else
+ return -EINVAL;
+
+ return 0;
+}
+
+static int v4l2_ioctl_g_crop(struct file *file,
+ void *fh,
+ struct v4l2_crop *cr
+ )
+{
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+ cr->c.left = 0;
+ cr->c.top = 0;
+ cr->c.width = 0;
+ cr->c.height = 0;
+
+ return 0;
+}
+
+static int v4l2_ioctl_encoder_cmd(struct file *file,
+ void *fh,
+ struct v4l2_encoder_cmd *cmd
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ u_int32 uStrIdx = ctx->str_index;
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ switch (cmd->cmd) {
+ case V4L2_ENC_CMD_START:
+ break;
+ case V4L2_ENC_CMD_STOP:
+ ctx->forceStop = true;
+ v4l2_vpu_send_cmd(ctx, uStrIdx, GTB_ENC_CMD_STREAM_STOP, 0, NULL);
+ wake_up_interruptible(&ctx->buffer_wq_input);
+ wake_up_interruptible(&ctx->buffer_wq_output);
+ break;
+ case V4L2_ENC_CMD_PAUSE:
+ break;
+ case V4L2_ENC_CMD_RESUME:
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int v4l2_ioctl_streamon(struct file *file,
+ void *fh,
+ enum v4l2_buf_type i
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct queue_data *q_data;
+ int ret;
+
+ vpu_dbg(LVL_INFO, "%s(), type=%d\n", __func__, i);
+
+ if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ q_data = &ctx->q_data[V4L2_SRC];
+ else if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ q_data = &ctx->q_data[V4L2_DST];
+ else
+ return -EINVAL;
+ ret = vb2_streamon(&q_data->vb2_q,
+ i);
+ ctx->forceStop = false;
+ return ret;
+}
+
+static int v4l2_ioctl_streamoff(struct file *file,
+ void *fh,
+ enum v4l2_buf_type i
+ )
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(fh);
+ struct queue_data *q_data;
+ int ret;
+
+ vpu_dbg(LVL_INFO, "%s(), type=%d\n", __func__, i);
+
+ if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ q_data = &ctx->q_data[V4L2_SRC];
+ else if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ q_data = &ctx->q_data[V4L2_DST];
+ else
+ return -EINVAL;
+
+ if (!ctx->start_flag) {
+ if (!ctx->forceStop) {
+ ctx->forceStop = true;
+ v4l2_vpu_send_cmd(ctx, ctx->str_index, GTB_ENC_CMD_STREAM_STOP, 0, NULL);
+ wake_up_interruptible(&ctx->buffer_wq_input);
+ wake_up_interruptible(&ctx->buffer_wq_output);
+ }
+
+ if (!ctx->firmware_stopped)
+ wait_for_completion(&ctx->stop_cmp);
+
+ ctx->start_flag = true;
+ }
+ ret = vb2_streamoff(&q_data->vb2_q,
+ i);
+ return ret;
+}
+
+static const struct v4l2_ioctl_ops v4l2_encoder_ioctl_ops = {
+ .vidioc_querycap = v4l2_ioctl_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = v4l2_ioctl_enum_fmt_vid_cap_mplane,
+ .vidioc_enum_fmt_vid_out_mplane = v4l2_ioctl_enum_fmt_vid_out_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = v4l2_ioctl_g_fmt,
+ .vidioc_g_fmt_vid_out_mplane = v4l2_ioctl_g_fmt,
+ .vidioc_try_fmt_vid_cap_mplane = v4l2_ioctl_try_fmt,
+ .vidioc_try_fmt_vid_out_mplane = v4l2_ioctl_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = v4l2_ioctl_s_fmt,
+ .vidioc_s_fmt_vid_out_mplane = v4l2_ioctl_s_fmt,
+ .vidioc_expbuf = v4l2_ioctl_expbuf,
+ .vidioc_g_crop = v4l2_ioctl_g_crop,
+ .vidioc_encoder_cmd = v4l2_ioctl_encoder_cmd,
+ .vidioc_subscribe_event = v4l2_ioctl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+ .vidioc_reqbufs = v4l2_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_ioctl_querybuf,
+ .vidioc_qbuf = v4l2_ioctl_qbuf,
+ .vidioc_dqbuf = v4l2_ioctl_dqbuf,
+ .vidioc_streamon = v4l2_ioctl_streamon,
+ .vidioc_streamoff = v4l2_ioctl_streamoff,
+};
+
+static int v4l2_enc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vpu_ctx *ctx = v4l2_ctrl_to_ctx(ctrl);
+ struct core_device *dev = &ctx->dev->core_dev[ctx->core_id];
+ pENC_RPC_HOST_IFACE pSharedInterface = dev->shared_mem.pSharedInterface;
+ pMEDIA_ENC_API_CONTROL_INTERFACE pEncCtrlInterface;
+ pMEDIAIP_ENC_PARAM pEncParam;
+ pMEDIAIP_ENC_EXPERT_MODE_PARAM pEncExpertModeParam;
+
+ pEncCtrlInterface = (pMEDIA_ENC_API_CONTROL_INTERFACE)phy_to_virt(pSharedInterface->pEncCtrlInterface[ctx->str_index],
+ dev->shared_mem.base_offset);
+ pEncParam = (pMEDIAIP_ENC_PARAM)phy_to_virt(pEncCtrlInterface->pEncParam,
+ dev->shared_mem.base_offset);
+ pEncExpertModeParam = (pMEDIAIP_ENC_EXPERT_MODE_PARAM)phy_to_virt(pEncCtrlInterface->pEncExpertModeParam,
+ dev->shared_mem.base_offset);
+
+ vpu_dbg(LVL_INFO, "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: {
+ if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
+ pEncParam->eBitRateMode = MEDIAIP_ENC_BITRATECONTROLMODE_CONSTANT_QP;
+
+ // Not used for CQ mode - set zero
+ pEncParam->uTargetBitrate = 0;
+ pEncParam->uMaxBitRate = 0;
+ pEncParam->uMinBitRate = 0;
+ } else if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) {
+ pEncParam->eBitRateMode = MEDIAIP_ENC_BITRATECONTROLMODE_CBR;
+ if (!pEncParam->uTargetBitrate) {
+ // Setup some default values if not set, these should really be
+ // resolution specific
+ pEncParam->uTargetBitrate = ctx->q_data[V4L2_SRC].height * ctx->q_data[V4L2_SRC].width * 12 * 30 / 100000;
+ pEncParam->uMaxBitRate = ctx->q_data[V4L2_SRC].height * ctx->q_data[V4L2_SRC].width * 12 * 30 / 10000;
+ pEncParam->uMinBitRate = ctx->q_data[V4L2_SRC].height * ctx->q_data[V4L2_SRC].width * 12 * 30 / 1000000;
+ }
+ } else
+ // Only CQ and CBR supported at present, force CQ mode
+ pEncParam->eBitRateMode = MEDIAIP_ENC_BITRATECONTROLMODE_CONSTANT_QP;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ if ((V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE == ctrl->val) || (V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE == ctrl->val))
+ pEncParam->eProfile = MEDIAIP_ENC_PROF_H264_BP;
+ else if (V4L2_MPEG_VIDEO_H264_PROFILE_MAIN == ctrl->val)
+ pEncParam->eProfile = MEDIAIP_ENC_PROF_H264_MP;
+ else if (V4L2_MPEG_VIDEO_H264_PROFILE_HIGH == ctrl->val)
+ pEncParam->eProfile = MEDIAIP_ENC_PROF_H264_HP;
+ else {
+ vpu_dbg(LVL_INFO, "not support h264 profile %d, set default: BP\n", ctrl->val);
+ pEncParam->eProfile = MEDIAIP_ENC_PROF_H264_BP;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ pEncParam->uLevel = h264_lvl[ctrl->val];
+ vpu_dbg(LVL_INFO, "V4L2_CID_MPEG_VIDEO_H264_LEVEL set val = %d\n", ctrl->val);
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ pEncParam->uTargetBitrate = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ pEncParam->uIFrameInterval = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+ pEncParam->uInitSliceQP = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+ pEncParam->uInitSliceQP = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+ pEncParam->uInitSliceQP = ctrl->val;
+ break;
+ }
+ return 0;
+}
+
+static int v4l2_enc_g_ctrl(struct v4l2_ctrl *ctrl)
+{
+ vpu_dbg(LVL_INFO, "g_ctrl: id = %d\n", ctrl->id);
+
+ switch (ctrl->id) {
+ case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
+ ctrl->val = MIN_BUFFER_COUNT;
+ break;
+ default:
+ vpu_dbg(LVL_INFO, "%s() Invalid control(%d)\n",
+ __func__, ctrl->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops vpu_enc_ctrl_ops = {
+ .s_ctrl = v4l2_enc_s_ctrl,
+ .g_volatile_ctrl = v4l2_enc_g_ctrl,
+};
+
+static void vpu_encoder_ctrls(struct vpu_ctx *ctx)
+{
+ v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0x0,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+ v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH, 0x0,
+ V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE
+ );
+ v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ V4L2_MPEG_VIDEO_H264_LEVEL_5_1, 0x0,
+ V4L2_MPEG_VIDEO_H264_LEVEL_1_0
+ );
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0);
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16);
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25);
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 0, 51, 1, 25);
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, 0, 51, 1, 25);
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &vpu_enc_ctrl_ops,
+ V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 0, 32, 1, MIN_BUFFER_COUNT);
+}
+
+static int ctrls_setup_encoder(struct vpu_ctx *ctx)
+{
+ v4l2_ctrl_handler_init(&ctx->ctrl_handler, 2);
+ vpu_encoder_ctrls(ctx);
+ if (ctx->ctrl_handler.error) {
+ vpu_dbg(LVL_ERR,
+ "control initialization error (%d)",
+ ctx->ctrl_handler.error);
+ return -EINVAL;
+ } else
+ ctx->ctrl_inited = true;
+
+ return v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+}
+
+static void ctrls_delete_encoder(struct vpu_ctx *This)
+{
+ int i;
+
+ if (This->ctrl_inited) {
+ v4l2_ctrl_handler_free(&This->ctrl_handler);
+ This->ctrl_inited = false;
+ }
+ for (i = 0; i < 2; i++)
+ This->ctrls[i] = NULL;
+}
+
+static void v4l2_vpu_send_cmd(struct vpu_ctx *ctx, uint32_t idx, uint32_t cmdid, uint32_t cmdnum, uint32_t *local_cmddata)
+{
+
+ struct core_device *dev = &ctx->dev->core_dev[ctx->core_id];
+ vpu_log_cmd(cmdid, idx);
+ mutex_lock(&dev->cmd_mutex);
+ rpc_send_cmd_buf_encoder(&dev->shared_mem, idx, cmdid, cmdnum, local_cmddata);
+ mutex_unlock(&dev->cmd_mutex);
+ mb();
+ MU_SendMessage(dev->mu_base_virtaddr, 0, COMMAND);
+}
+
+static void v4l2_transfer_buffer_to_firmware(struct queue_data *This, struct vb2_buffer *vb)
+{
+ struct vpu_ctx *ctx = container_of(This, struct vpu_ctx, q_data[V4L2_SRC]);
+#ifdef DUMP_DATA
+ char *read_data;
+ u_int32 read_idx;
+#endif
+ pBUFFER_DESCRIPTOR_TYPE pEncStrBuffDesc;
+ pMEDIAIP_ENC_EXPERT_MODE_PARAM pEncExpertModeParam;
+ struct core_device *dev = &ctx->dev->core_dev[ctx->core_id];
+ pENC_RPC_HOST_IFACE pSharedInterface = dev->shared_mem.pSharedInterface;
+ pMEDIA_ENC_API_CONTROL_INTERFACE pEncCtrlInterface;
+ u_int32 uStrIdx = ctx->str_index;
+
+ vpu_dbg(LVL_INFO, "ENC_RPC_HOST_IFACE(%ld)MEDIA_ENC_API_CONTROL_INTERFACE(%ld) EncYUVBufferDesc(%ld) expertParam(%ld) encparam(%ld) MEDIAIP_ENC_FMT(%ld)\n",
+ sizeof(ENC_RPC_HOST_IFACE), sizeof(MEDIA_ENC_API_CONTROL_INTERFACE),
+ sizeof(BUFFER_DESCRIPTOR_TYPE), sizeof(MEDIAIP_ENC_EXPERT_MODE_PARAM),
+ sizeof(MEDIAIP_ENC_PARAM), sizeof(MEDIAIP_ENC_FMT)
+ );
+ if (ctx->start_flag == true) {
+ pEncCtrlInterface = (pMEDIA_ENC_API_CONTROL_INTERFACE)phy_to_virt(pSharedInterface->pEncCtrlInterface[uStrIdx],
+ dev->shared_mem.base_offset);
+ pEncStrBuffDesc = (pBUFFER_DESCRIPTOR_TYPE)phy_to_virt(pEncCtrlInterface->pEncStreamBufferDesc,
+ dev->shared_mem.base_offset);
+ pEncStrBuffDesc->start = ctx->encoder_stream.phy_addr;
+ pEncStrBuffDesc->wptr = pEncStrBuffDesc->start;
+ pEncStrBuffDesc->rptr = pEncStrBuffDesc->start;
+ pEncStrBuffDesc->end = ctx->encoder_stream.phy_addr + ctx->encoder_stream.size;
+
+ vpu_dbg(LVL_INFO, "pEncStrBuffDesc->start=%x, pEncStrBuffDesc->wptr=0x%x, pEncStrBuffDesc->rptr=%x, pEncStrBuffDesc->end=%x\n", pEncStrBuffDesc->start, pEncStrBuffDesc->wptr, pEncStrBuffDesc->rptr, pEncStrBuffDesc->end);
+
+ pEncExpertModeParam = (pMEDIAIP_ENC_EXPERT_MODE_PARAM)phy_to_virt(pEncCtrlInterface->pEncExpertModeParam,
+ dev->shared_mem.base_offset);
+ pEncExpertModeParam->Calib.mem_chunk_phys_addr = ctx->encoder_mem.phy_addr;
+ pEncExpertModeParam->Calib.mem_chunk_virt_addr = ctx->encoder_mem.phy_addr;
+ pEncExpertModeParam->Calib.mem_chunk_size = ctx->encoder_mem.size;
+ pEncExpertModeParam->Calib.cb_base = ctx->encoder_stream.phy_addr;
+ pEncExpertModeParam->Calib.cb_size = ctx->encoder_stream.size;
+
+#ifdef DUMP_DATA
+ read_data = (char *)vb2_plane_vaddr(vb, 0);
+ vpu_dbg(LVL_INFO, "transfer data from virt 0x%p: ", read_data);
+ for (read_idx = 0; read_idx < DATA_NUM; read_idx++)
+ vpu_dbg(LVL_INFO, " 0x%x", read_data[read_idx]);
+ vpu_dbg(LVL_INFO, "\n");
+ #endif
+ vpu_dbg(LVL_INFO, "enter %s, start_flag %d, index=%d,firmware_started=%d\n",
+ __func__, ctx->start_flag, ctx->str_index,
+ dev->firmware_started);
+
+ vpu_dbg(LVL_ALL, "vpu encoder firmware version is %d.%d.%d\n",
+ (pSharedInterface->FWVersion & 0x00ff0000) >> 16,
+ (pSharedInterface->FWVersion & 0x0000ff00) >> 8,
+ pSharedInterface->FWVersion & 0x000000ff);
+
+ v4l2_vpu_send_cmd(ctx, ctx->str_index, GTB_ENC_CMD_CONFIGURE_CODEC, 0, NULL);
+ vpu_dbg(LVL_INFO, "send command GTB_ENC_CMD_CONFIGURE_CODEC\n");
+
+ ctx->start_flag = false;
+ }
+}
+
+static bool update_yuv_addr(struct vpu_ctx *ctx, u_int32 uStrIdx)
+{
+ bool bGotAFrame = FALSE;
+
+ struct vb2_data_req *p_data_req;
+ struct queue_data *This = &ctx->q_data[V4L2_SRC];
+
+ struct core_device *dev = &ctx->dev->core_dev[ctx->core_id];
+ pENC_RPC_HOST_IFACE pSharedInterface = dev->shared_mem.pSharedInterface;
+ pMEDIA_ENC_API_CONTROL_INTERFACE pEncCtrlInterface;
+ pMEDIAIP_ENC_YUV_BUFFER_DESC pParamYuvBuffDesc;
+ u_int32 *pphy_address;
+#ifdef DUMP_DATA
+ char *read_data;
+ u_int32 read_idx;
+#endif
+
+ pEncCtrlInterface = (pMEDIA_ENC_API_CONTROL_INTERFACE)phy_to_virt(pSharedInterface->pEncCtrlInterface[uStrIdx],
+ dev->shared_mem.base_offset);
+ pParamYuvBuffDesc = (pMEDIAIP_ENC_YUV_BUFFER_DESC)phy_to_virt(pEncCtrlInterface->pEncYUVBufferDesc,
+ dev->shared_mem.base_offset);
+
+ while (1) {
+ if (!wait_event_interruptible_timeout(ctx->buffer_wq_input,
+ (!list_empty(&This->drv_q)) || ctx->forceStop,
+ msecs_to_jiffies(5000))) {
+ if (!ctx->forceStop)
+ vpu_dbg(LVL_ERR, " warn: yuv wait_event_interruptible_timeout wait 5s timeout\n");
+ else
+ break;
+ }
+ else
+ break;
+ }
+ if (ctx->forceStop)
+ return false;
+
+ down(&This->drv_q_lock);
+ if (!list_empty(&This->drv_q)) {
+ p_data_req = list_first_entry(&This->drv_q,
+ typeof(*p_data_req), list);
+
+#ifdef DUMP_DATA
+ read_data = (char *)vb2_plane_vaddr(p_data_req->vb2_buf, 0);
+ vpu_dbg(LVL_INFO, "transfer data from virt 0x%p: ", read_data);
+ for (read_idx = 0; read_idx < DATA_NUM; read_idx++)
+ vpu_dbg(LVL_INFO, " 0x%x", read_data[read_idx]);
+ vpu_dbg(LVL_INFO, "\n");
+ #endif
+ pphy_address = (u_int32 *)vb2_plane_cookie(p_data_req->vb2_buf, 0);
+ pParamYuvBuffDesc->uLumaBase = *pphy_address;
+ pphy_address = (u_int32 *)vb2_plane_cookie(p_data_req->vb2_buf, 1);
+ pParamYuvBuffDesc->uChromaBase = *pphy_address;
+ /* Not sure what the test should be here for a valid frame return from vb2_plane_cookie */
+ if (pParamYuvBuffDesc->uLumaBase != 0)
+ bGotAFrame = TRUE;
+
+ /* keeps increasing, so just a frame input count rather than a Frame buffer ID */
+ pParamYuvBuffDesc->uFrameID = p_data_req->id;
+ list_del(&p_data_req->list);
+ }
+ up(&This->drv_q_lock);
+ return bGotAFrame;
+
+}
+
+static void report_stream_done(struct vpu_ctx *ctx, MEDIAIP_ENC_PIC_INFO *pEncPicInfo)
+{
+ struct vb2_data_req *p_data_req;
+ struct queue_data *This = &ctx->q_data[V4L2_DST];
+ u_int32 wptr;
+ u_int32 rptr;
+ u_int32 start;
+ u_int32 end;
+
+ void *data_mapped;
+ u_int32 length;
+ u_int32 data_length = 0;
+ void *rptr_virt;
+
+ pBUFFER_DESCRIPTOR_TYPE pEncStrBuffDesc;
+ pMEDIA_ENC_API_CONTROL_INTERFACE pEncCtrlInterface;
+ struct core_device *dev = &ctx->dev->core_dev[ctx->core_id];
+ pENC_RPC_HOST_IFACE pSharedInterface = dev->shared_mem.pSharedInterface;
+
+ /* Windsor stream buffer descriptor
+ * pEncStrBuffDesc = &RecCmdData.tEncStreamBufferDesc;
+ *
+ * VPU driver stream buffer descriptor with full address
+ * pVpuEncStrBuffDesc
+ * *
+ * Note the wprt is updated prior to calling this function
+ */
+ pEncCtrlInterface = (pMEDIA_ENC_API_CONTROL_INTERFACE)phy_to_virt(pSharedInterface->pEncCtrlInterface[ctx->str_index],
+ dev->shared_mem.base_offset);
+ pEncStrBuffDesc = (pBUFFER_DESCRIPTOR_TYPE)phy_to_virt(pEncCtrlInterface->pEncStreamBufferDesc,
+ dev->shared_mem.base_offset);
+
+
+ wptr = pEncStrBuffDesc->wptr | 0x80000000;
+ rptr = pEncStrBuffDesc->rptr | 0x80000000;
+ start = pEncStrBuffDesc->start | 0x80000000;
+ end = pEncStrBuffDesc->end | 0x80000000;
+ rptr_virt = ctx->encoder_stream.virt_addr + rptr - start;
+
+ vpu_dbg(LVL_INFO, "report_stream_done eptr=%x, rptr=%x, start=%x, end=%x\n", wptr, rptr, start, end);
+ while (1) {
+ if (!wait_event_interruptible_timeout(ctx->buffer_wq_output,
+ (!list_empty(&This->drv_q)),
+ msecs_to_jiffies(5000))) {
+ if (!ctx->forceStop)
+ vpu_dbg(LVL_ERR, " warn: stream wait_event_interruptible_timeout wait 5s timeout\n");
+ else
+ break;
+ }
+ else
+ break;
+ }
+
+ if (!list_empty(&This->drv_q)) {
+ down(&This->drv_q_lock);
+
+ vpu_dbg(LVL_INFO, "report_stream_done down\n");
+
+ p_data_req = list_first_entry(&This->drv_q, typeof(*p_data_req), list);
+
+ vpu_dbg(LVL_INFO, "%s :p_data_req(%p)\n", __func__, p_data_req);
+ vpu_dbg(LVL_INFO, "%s buf_id %d\n", __func__, p_data_req->vb2_buf->index);
+
+ // Calculate length - the amount of space remaining in output stream buffer
+ length = p_data_req->vb2_buf->planes[0].length;
+ data_mapped = (void *)vb2_plane_vaddr(p_data_req->vb2_buf, 0);
+ if (wptr == rptr && rptr != start)
+ data_length = end - start;
+ else if (rptr < wptr)
+ data_length = wptr - rptr;
+ else if (rptr > wptr)
+ data_length = (end - rptr) + (wptr - start);
+
+ //update the bytesused for the output buffer
+ if (data_length >= length)
+ p_data_req->vb2_buf->planes[0].bytesused = length;
+ else
+ p_data_req->vb2_buf->planes[0].bytesused = data_length;
+
+ vpu_dbg(LVL_INFO, "%s data_length %d, length %d\n", __func__, data_length, length);
+ /* Following calculations determine how much data we can transfer into p_vb2_buf
+ * and then only copy that ammount, so rptr is the actual consumed ammount at the end*/
+ if ((wptr == rptr) || (rptr > wptr)) {
+ if (end - rptr >= length) {
+ memcpy(data_mapped, rptr_virt, length);
+ rptr += length;
+ if (rptr == end)
+ rptr = start;
+ } else {
+ memcpy(data_mapped, rptr_virt, end-rptr);
+ if ((length-(end-rptr)) >= (wptr-start)) {
+ memcpy(data_mapped + (end-rptr), ctx->encoder_stream.virt_addr, wptr-start);
+ rptr = wptr;
+ } else {
+ memcpy(data_mapped + (end-rptr), ctx->encoder_stream.virt_addr, length-(end-rptr));
+ rptr = start+length-(end-rptr);
+ }
+ }
+ } else {
+ if (wptr - rptr >= length) {
+ memcpy(data_mapped, rptr_virt, length);
+ rptr += length;
+ } else {
+ memcpy(data_mapped, rptr_virt, wptr - rptr);
+ rptr = wptr;
+ }
+ }
+
+ /* Update VPU stream buffer descriptor and Windsor FW stream buffer descriptors respectively*/
+ pEncStrBuffDesc->rptr = rptr;
+
+ list_del(&p_data_req->list);
+ up(&This->drv_q_lock);
+
+ if (pEncPicInfo->ePicType == MEDIAIP_ENC_PIC_TYPE_IDR_FRAME || pEncPicInfo->ePicType == MEDIAIP_ENC_PIC_TYPE_I_FRAME)
+ p_data_req->buffer_flags = V4L2_BUF_FLAG_KEYFRAME;
+ else if (pEncPicInfo->ePicType == MEDIAIP_ENC_PIC_TYPE_P_FRAME)
+ p_data_req->buffer_flags = V4L2_BUF_FLAG_PFRAME;
+ else if (pEncPicInfo->ePicType == MEDIAIP_ENC_PIC_TYPE_B_FRAME)
+ p_data_req->buffer_flags = V4L2_BUF_FLAG_BFRAME;
+ //memcpy to vb2 buffer from encpicinfo
+ if (p_data_req->vb2_buf->state == VB2_BUF_STATE_ACTIVE)
+ vb2_buffer_done(p_data_req->vb2_buf, VB2_BUF_STATE_DONE);
+ }
+ vpu_dbg(LVL_INFO, "report_buffer_done return\n");
+}
+
+static void enc_mem_alloc(struct vpu_ctx *ctx, MEDIAIP_ENC_MEM_REQ_DATA *req_data)
+{
+ pMEDIA_ENC_API_CONTROL_INTERFACE pEncCtrlInterface;
+ pMEDIAIP_ENC_MEM_POOL pEncMemPool;
+ struct core_device *core_dev = &ctx->dev->core_dev[ctx->core_id];
+ pENC_RPC_HOST_IFACE pSharedInterface = core_dev->shared_mem.pSharedInterface;
+ u_int32 i;
+
+ pEncCtrlInterface = (pMEDIA_ENC_API_CONTROL_INTERFACE)phy_to_virt(pSharedInterface->pEncCtrlInterface[ctx->str_index],
+ core_dev->shared_mem.base_offset);
+ pEncMemPool = (pMEDIAIP_ENC_MEM_POOL)phy_to_virt(pEncCtrlInterface->pEncMemPool,
+ core_dev->shared_mem.base_offset);
+
+ for (i = 0; i < req_data->uEncFrmNum; i++) {
+ ctx->encFrame[i].size = req_data->uEncFrmSize;
+ if (!ctx->encFrame[i].virt_addr) {
+ ctx->encFrame[i].virt_addr = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+ ctx->encFrame[i].size,
+ (dma_addr_t *)&ctx->encFrame[i].phy_addr,
+ GFP_KERNEL | GFP_DMA32
+ );
+ if (!ctx->encFrame[i].virt_addr)
+ vpu_dbg(LVL_ERR, "%s() encFrame alloc size(%x) fail!\n", __func__, ctx->encFrame[i].size);
+ else
+ vpu_dbg(LVL_INFO, "%s() encFrame size(%d) encFrame virt(%p) encFrame phy(%p)\n", __func__, ctx->encFrame[i].size, ctx->encFrame[i].virt_addr, (void *)ctx->encFrame[i].phy_addr);
+ }
+
+ pEncMemPool->tEncFrameBuffers[i].uMemPhysAddr = ctx->encFrame[i].phy_addr;
+#ifdef CM4
+ pEncMemPool->tEncFrameBuffers[i].uMemVirtAddr = ctx->encFrame[i].phy_addr;
+#else
+ pEncMemPool->tEncFrameBuffers[i].uMemVirtAddr = ctx->encFrame[i].phy_addr - core_dev->m0_p_fw_space_phy;
+#endif
+ pEncMemPool->tEncFrameBuffers[i].uMemSize = ctx->encFrame[i].size;
+ }
+
+ for (i = 0; i < req_data->uRefFrmNum; i++) {
+ ctx->refFrame[i].size = req_data->uRefFrmSize;
+ if (!ctx->refFrame[i].virt_addr) {
+ ctx->refFrame[i].virt_addr = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+ ctx->refFrame[i].size,
+ (dma_addr_t *)&ctx->refFrame[i].phy_addr,
+ GFP_KERNEL | GFP_DMA32
+ );
+
+ if (!ctx->refFrame[i].virt_addr)
+ vpu_dbg(LVL_ERR, "%s() refFrame alloc size(%x) fail!\n", __func__, ctx->refFrame[i].size);
+ else
+ vpu_dbg(LVL_INFO, "%s() refFrame size(%d) refFrame virt(%p) refFrame phy(%p)\n", __func__, ctx->refFrame[i].size, ctx->refFrame[i].virt_addr, (void *)ctx->refFrame[i].phy_addr);
+ }
+
+ pEncMemPool->tRefFrameBuffers[i].uMemPhysAddr = ctx->refFrame[i].phy_addr;
+#ifdef CM4
+ pEncMemPool->tRefFrameBuffers[i].uMemVirtAddr = ctx->refFrame[i].phy_addr;
+#else
+ pEncMemPool->tRefFrameBuffers[i].uMemVirtAddr = ctx->refFrame[i].phy_addr - core_dev->m0_p_fw_space_phy;
+#endif
+ pEncMemPool->tRefFrameBuffers[i].uMemSize = ctx->refFrame[i].size;
+ }
+
+ ctx->actFrame.size = req_data->uActBufSize;
+ if (!ctx->actFrame.virt_addr) {
+ ctx->actFrame.virt_addr = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+ ctx->actFrame.size,
+ (dma_addr_t *)&ctx->actFrame.phy_addr,
+ GFP_KERNEL | GFP_DMA32
+ );
+
+ if (!ctx->actFrame.virt_addr)
+ vpu_dbg(LVL_ERR, "%s() actFrame alloc size(%x) fail!\n", __func__, ctx->actFrame.size);
+ else
+ vpu_dbg(LVL_INFO, "%s() actFrame size(%d) actFrame virt(%p) actFrame phy(%p)\n", __func__, ctx->actFrame.size, ctx->actFrame.virt_addr, (void *)ctx->actFrame.phy_addr);
+ }
+
+ pEncMemPool->tActFrameBufferArea.uMemPhysAddr = ctx->actFrame.phy_addr;
+#ifdef CM4
+ pEncMemPool->tActFrameBufferArea.uMemVirtAddr = ctx->actFrame.phy_addr;
+#else
+ pEncMemPool->tActFrameBufferArea.uMemVirtAddr = ctx->actFrame.phy_addr - core_dev->m0_p_fw_space_phy;
+#endif
+ pEncMemPool->tActFrameBufferArea.uMemSize = ctx->actFrame.size;
+
+}
+
+static void vpu_api_event_handler(struct vpu_ctx *ctx, u_int32 uStrIdx, u_int32 uEvent, u_int32 *event_data)
+{
+ vpu_log_event(uEvent, uStrIdx);
+ if (uStrIdx < VID_API_NUM_STREAMS) {
+ switch (uEvent) {
+ case VID_API_ENC_EVENT_START_DONE: {
+ if (update_yuv_addr(ctx, uStrIdx))
+ v4l2_vpu_send_cmd(ctx, uStrIdx, GTB_ENC_CMD_FRAME_ENCODE, 0, NULL);
+ } break;
+ case VID_API_ENC_EVENT_MEM_REQUEST: {
+ MEDIAIP_ENC_MEM_REQ_DATA *req_data = (MEDIAIP_ENC_MEM_REQ_DATA *)event_data;
+ vpu_dbg(LVL_INFO, "uEncFrmSize = %d, uEncFrmNum=%d, uRefFrmSize=%d, uRefFrmNum=%d, uActBufSize=%d\n", req_data->uEncFrmSize, req_data->uEncFrmNum, req_data->uRefFrmSize, req_data->uRefFrmNum, req_data->uActBufSize);
+ enc_mem_alloc(ctx, req_data);
+ //update_yuv_addr(ctx,0);
+ v4l2_vpu_send_cmd(ctx, uStrIdx, GTB_ENC_CMD_STREAM_START, 0, NULL);
+ } break;
+ case VID_API_ENC_EVENT_PARA_UPD_DONE:
+ break;
+ case VID_API_ENC_EVENT_FRAME_DONE: {
+ MEDIAIP_ENC_PIC_INFO *pEncPicInfo = (MEDIAIP_ENC_PIC_INFO *)event_data;
+
+ vpu_dbg(LVL_INFO, "VID_API_ENC_EVENT_FRAME_DONE pEncPicInfo->uPicEncodDone=%d: Encode picture done\n", pEncPicInfo->uPicEncodDone);
+ if (pEncPicInfo->uPicEncodDone) {
+#ifdef TB_REC_DBG
+ vpu_dbg(LVL_INFO, " - Frame ID : 0x%x\n", pEncPicInfo->uFrameID);
+
+ vpu_dbg(LVL_INFO, " - Picture Type : %s\n", pEncPicInfo->ePicType == MEDIAIP_ENC_PIC_TYPE_B_FRAME ? "B picture" :
+ pEncPicInfo->ePicType == MEDIAIP_ENC_PIC_TYPE_P_FRAME ? "P picture" :
+ pEncPicInfo->ePicType == MEDIAIP_ENC_PIC_TYPE_I_FRAME ? "I picture" :
+ pEncPicInfo->ePicType == MEDIAIP_ENC_PIC_TYPE_IDR_FRAME ? "IDR picture" : "BI picture");
+ vpu_dbg(LVL_INFO, " - Skipped frame : 0x%x\n", pEncPicInfo->uSkippedFrame);
+ vpu_dbg(LVL_INFO, " - Frame size : 0x%x\n", pEncPicInfo->uFrameSize);
+ vpu_dbg(LVL_INFO, " - Frame CRC : 0x%x\n", pEncPicInfo->uFrameCrc);
+#endif
+
+ /* Sync the write pointer to the local view of it */
+
+ report_stream_done(ctx, pEncPicInfo);
+ }
+ } break;
+ case VID_API_ENC_EVENT_FRAME_RELEASE: {
+ struct queue_data *This = &ctx->q_data[V4L2_SRC];
+ u_int32 *uFrameID = (u_int32 *)event_data;
+ struct vb2_data_req *p_data_req;
+
+ vpu_dbg(LVL_INFO, "VID_API_ENC_EVENT_FRAME_RELEASE : Frame release - uFrameID = 0x%x\n", *uFrameID);
+ p_data_req = &This->vb2_reqs[*uFrameID];
+ if (p_data_req->vb2_buf->state == VB2_BUF_STATE_ACTIVE)
+ vb2_buffer_done(p_data_req->vb2_buf,
+ VB2_BUF_STATE_DONE
+ );
+
+ } break;
+ case VID_API_ENC_EVENT_STOP_DONE: {
+ const struct v4l2_event ev = {
+ .type = V4L2_EVENT_EOS
+ };
+ ctx->firmware_stopped = true;
+ complete_all(&ctx->stop_cmp);
+ v4l2_event_queue_fh(&ctx->fh, &ev);
+ }
+ break;
+ case VID_API_ENC_EVENT_FRAME_INPUT_DONE: {
+ if (update_yuv_addr(ctx, uStrIdx))
+ v4l2_vpu_send_cmd(ctx, uStrIdx, GTB_ENC_CMD_FRAME_ENCODE, 0, NULL);
+ } break;
+ case VID_API_ENC_EVENT_TERMINATE_DONE:
+ break;
+ default:
+ vpu_dbg(LVL_INFO, "........unknown event : 0x%x\n", uEvent);
+ break;
+ }
+ }
+}
+
+//This code is added for MU
+static irqreturn_t fsl_vpu_mu_isr(int irq, void *This)
+{
+ struct core_device *dev = This;
+ u32 msg;
+
+ MU_ReceiveMsg(dev->mu_base_virtaddr, 0, &msg);
+ if (msg == 0xaa) {
+ MU_sendMesgToFW(dev->mu_base_virtaddr, PRINT_BUF_OFFSET, dev->m0_rpc_phy - dev->m0_p_fw_space_phy + M0_PRINT_OFFSET);
+ MU_sendMesgToFW(dev->mu_base_virtaddr, RPC_BUF_OFFSET, dev->m0_rpc_phy - dev->m0_p_fw_space_phy); //CM0 use relative address
+ MU_sendMesgToFW(dev->mu_base_virtaddr, BOOT_ADDRESS, dev->m0_p_fw_space_phy);
+ MU_sendMesgToFW(dev->mu_base_virtaddr, INIT_DONE, 2);
+ } else if (msg == 0x55) {
+ dev->firmware_started = true;
+ complete(&dev->start_cmp);
+ } else if (msg == 0xA5) {
+ /*receive snapshot done msg and wakeup complete to suspend*/
+ complete(&dev->snap_done_cmp);
+ } else
+ schedule_work(&dev->msg_work);
+ return IRQ_HANDLED;
+}
+
+/* Initialization of the MU code. */
+static int vpu_mu_init(struct vpu_dev *dev, u_int32 id)
+{
+ struct device_node *np;
+ unsigned int vpu_mu_id;
+ u32 irq;
+ struct core_device *core_dev = &dev->core_dev[id];
+ int ret = 0;
+
+ /*
+ * Get the address of MU to be used for communication with the M0 core
+ */
+#ifdef CM4
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx8-mu0-vpu-m4");
+ if (!np) {
+ vpu_dbg(LVL_ERR, "error: Cannot find MU entry in device tree\n");
+ return -EINVAL;
+ }
+#else
+ np = of_find_compatible_node(NULL, NULL, mu_cmp[id]);
+ if (!np) {
+ vpu_dbg(LVL_ERR, "error: Cannot find MU entry in device tree\n");
+ return -EINVAL;
+ }
+#endif
+ core_dev->mu_base_virtaddr = of_iomap(np, 0);
+ WARN_ON(!core_dev->mu_base_virtaddr);
+
+ ret = of_property_read_u32_index(np,
+ "fsl,vpu_ap_mu_id", 0, &vpu_mu_id);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "Cannot get mu_id %d\n", ret);
+ return -EINVAL;
+ }
+
+ core_dev->vpu_mu_id = vpu_mu_id;
+
+ irq = of_irq_get(np, 0);
+
+ ret = devm_request_irq(&dev->plat_dev->dev, irq, fsl_vpu_mu_isr,
+ IRQF_EARLY_RESUME, "vpu_mu_isr", (void *)core_dev);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "request_irq failed %d, error = %d\n", irq, ret);
+ return -EINVAL;
+ }
+
+ if (!core_dev->vpu_mu_init) {
+ MU_Init(core_dev->mu_base_virtaddr);
+ MU_EnableRxFullInt(core_dev->mu_base_virtaddr, 0);
+ core_dev->vpu_mu_init = 1;
+ }
+
+ return ret;
+}
+
+static int vpu_next_free_instance(struct vpu_dev *dev, struct vpu_ctx *ctx)
+{
+ int idx;
+ int idx0 = hweight32(dev->core_dev[0].instance_mask);
+ int idx1 = hweight32(dev->core_dev[1].instance_mask);
+
+ if (idx0 <= idx1 && idx0 < VPU_MAX_NUM_STREAMS) {
+ idx = ffz(dev->core_dev[0].instance_mask);
+ ctx->core_id = 0;
+ } else if (idx1 < VPU_MAX_NUM_STREAMS) {
+ idx = ffz(dev->core_dev[1].instance_mask);
+ ctx->core_id = 1;
+ } else
+ return -EBUSY;
+
+ return idx;
+}
+
+static void send_msg_queue(struct vpu_ctx *ctx, struct event_msg *msg)
+{
+ u_int32 ret;
+
+ ret = kfifo_in(&ctx->msg_fifo, msg, sizeof(struct event_msg));
+ if (ret != sizeof(struct event_msg))
+ vpu_dbg(LVL_ERR, "There is no memory for msg fifo, ret=%d\n", ret);
+}
+
+static bool receive_msg_queue(struct vpu_ctx *ctx, struct event_msg *msg)
+{
+ u_int32 ret;
+
+ if (kfifo_len(&ctx->msg_fifo) >= sizeof(*msg)) {
+ ret = kfifo_out(&ctx->msg_fifo, msg, sizeof(*msg));
+ if (ret != sizeof(*msg)) {
+ vpu_dbg(LVL_ERR, "kfifo_out has error, ret=%d\n", ret);
+ return false;
+ } else
+ return true;
+ } else
+ return false;
+}
+
+extern u_int32 rpc_MediaIPFW_Video_message_check_encoder(struct shared_addr *This);
+static void vpu_msg_run_work(struct work_struct *work)
+{
+ struct core_device *dev = container_of(work, struct core_device, msg_work);
+ struct vpu_ctx *ctx;
+ struct event_msg msg;
+ struct shared_addr *This = &dev->shared_mem;
+
+ while (rpc_MediaIPFW_Video_message_check_encoder(This) == API_MSG_AVAILABLE) {
+ rpc_receive_msg_buf_encoder(This, &msg);
+ mutex_lock(&dev->core_mutex);
+ ctx = dev->ctx[msg.idx];
+ if (ctx != NULL) {
+ mutex_lock(&ctx->instance_mutex);
+ if (!ctx->ctx_released) {
+ send_msg_queue(ctx, &msg);
+ queue_work(ctx->instance_wq, &ctx->instance_work);
+ }
+ mutex_unlock(&ctx->instance_mutex);
+ }
+ mutex_unlock(&dev->core_mutex);
+ }
+ if (rpc_MediaIPFW_Video_message_check_encoder(This) == API_MSG_BUFFER_ERROR)
+ vpu_dbg(LVL_ERR, "MSG num is too big to handle");
+
+}
+static void vpu_msg_instance_work(struct work_struct *work)
+{
+ struct vpu_ctx *ctx = container_of(work, struct vpu_ctx, instance_work);
+ struct event_msg msg;
+
+ while (receive_msg_queue(ctx, &msg))
+ vpu_api_event_handler(ctx, msg.idx, msg.msgid, msg.msgdata);
+}
+
+static int vpu_queue_setup(struct vb2_queue *vq,
+ unsigned int *buf_count,
+ unsigned int *plane_count,
+ unsigned int psize[],
+ struct device *allocators[])
+{
+ struct queue_data *This = (struct queue_data *)vq->drv_priv;
+
+ vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+
+ if ((vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ||
+ (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ ) {
+ *plane_count = 1;
+ psize[0] = This->sizeimage[0];//check alignment
+ } else {
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ *plane_count = 2;
+ psize[0] = This->sizeimage[0];//check alignment
+ psize[1] = This->sizeimage[1];//check colocated_size
+ } else {
+ psize[0] = This->sizeimage[0] + This->sizeimage[1];
+ *plane_count = 1;
+ }
+ }
+ return 0;
+}
+
+static int vpu_buf_prepare(struct vb2_buffer *vb)
+{
+ vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+ return 0;
+}
+
+
+static int vpu_start_streaming(struct vb2_queue *q,
+ unsigned int count
+ )
+{
+ vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+ return 0;
+}
+
+
+static void vpu_stop_streaming(struct vb2_queue *q)
+{
+ struct queue_data *This = (struct queue_data *)q->drv_priv;
+ struct vb2_data_req *p_data_req;
+ struct vb2_data_req *p_temp;
+ struct vb2_buffer *vb;
+
+ vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+
+ down(&This->drv_q_lock);
+ if (!list_empty(&This->drv_q)) {
+ list_for_each_entry_safe(p_data_req, p_temp, &This->drv_q, list) {
+ vpu_dbg(LVL_INFO, "%s(%d) - list_del(%p)\n",
+ __func__,
+ p_data_req->id,
+ p_data_req
+ );
+ list_del(&p_data_req->list);
+ }
+ }
+ if (!list_empty(&q->queued_list))
+ list_for_each_entry(vb, &q->queued_list, queued_entry)
+ if (vb->state == VB2_BUF_STATE_ACTIVE)
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+ INIT_LIST_HEAD(&This->drv_q);
+ up(&This->drv_q_lock);
+}
+
+static void vpu_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct queue_data *This = (struct queue_data *)vq->drv_priv;
+ struct vb2_data_req *data_req;
+
+ vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+
+ down(&This->drv_q_lock);
+ vpu_dbg(LVL_INFO, "c_port_buf_queue down\n");
+ data_req = &This->vb2_reqs[vb->index];
+ data_req->vb2_buf = vb;
+ data_req->id = vb->index;
+ list_add_tail(&data_req->list, &This->drv_q);
+
+ up(&This->drv_q_lock);
+ vpu_dbg(LVL_INFO, "c_port_buf_queue up vq->type=%d\n", vq->type);
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ v4l2_transfer_buffer_to_firmware(This, vb);
+}
+
+static void vpu_prepare(struct vb2_queue *q)
+{
+ vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+}
+
+static void vpu_finish(struct vb2_queue *q)
+{
+ vpu_dbg(LVL_INFO, "%s() is called\n", __func__);
+}
+
+static struct vb2_ops v4l2_qops = {
+ .queue_setup = vpu_queue_setup,
+ .wait_prepare = vpu_prepare,
+ .wait_finish = vpu_finish,
+ .buf_prepare = vpu_buf_prepare,
+ .start_streaming = vpu_start_streaming,
+ .stop_streaming = vpu_stop_streaming,
+ .buf_queue = vpu_buf_queue,
+};
+
+static void init_vb2_queue(struct queue_data *This, unsigned int type, struct vpu_ctx *ctx)
+{
+ struct vb2_queue *vb2_q = &This->vb2_q;
+ int ret;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ // initialze driver queue
+ INIT_LIST_HEAD(&This->drv_q);
+ // initialize vb2 queue
+ vb2_q->type = type;
+ vb2_q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ vb2_q->gfp_flags = GFP_DMA32;
+ vb2_q->ops = &v4l2_qops;
+ vb2_q->drv_priv = This;
+ vb2_q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+ vb2_q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ vb2_q->dev = &ctx->dev->plat_dev->dev;
+ ret = vb2_queue_init(vb2_q);
+ if (ret)
+ vpu_dbg(LVL_ERR, "%s vb2_queue_init() failed (%d)!\n",
+ __func__,
+ ret
+ );
+ else
+ This->vb2_q_inited = true;
+}
+
+static void init_queue_data(struct vpu_ctx *ctx)
+{
+ init_vb2_queue(&ctx->q_data[V4L2_SRC], V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, ctx);
+ ctx->q_data[V4L2_SRC].type = V4L2_SRC;
+ sema_init(&ctx->q_data[V4L2_SRC].drv_q_lock, 1);
+ init_vb2_queue(&ctx->q_data[V4L2_DST], V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, ctx);
+ ctx->q_data[V4L2_DST].type = V4L2_DST;
+ sema_init(&ctx->q_data[V4L2_DST].drv_q_lock, 1);
+}
+
+static void release_queue_data(struct vpu_ctx *ctx)
+{
+ struct queue_data *This = &ctx->q_data[V4L2_SRC];
+
+ if (This->vb2_q_inited)
+ vb2_queue_release(&This->vb2_q);
+ This = &ctx->q_data[V4L2_DST];
+ if (This->vb2_q_inited)
+ vb2_queue_release(&This->vb2_q);
+}
+
+#ifdef CM4
+static int power_CM4_up(struct vpu_dev *dev)
+{
+ sc_ipc_t ipcHndl;
+ sc_rsrc_t core_rsrc, mu_rsrc = -1;
+
+ ipcHndl = dev->mu_ipcHandle;
+ core_rsrc = SC_R_M4_0_PID0;
+ mu_rsrc = SC_R_M4_0_MU_1A;
+
+ if (sc_pm_set_resource_power_mode(ipcHndl, core_rsrc, SC_PM_PW_MODE_ON) != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: failed to power up core_rsrc\n");
+ return -EIO;
+ }
+
+ if (mu_rsrc != -1) {
+ if (sc_pm_set_resource_power_mode(ipcHndl, mu_rsrc, SC_PM_PW_MODE_ON) != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: failed to power up mu_rsrc\n");
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static int boot_CM4_up(struct vpu_dev *dev, void *boot_addr)
+{
+ sc_ipc_t ipcHndl;
+ sc_rsrc_t core_rsrc;
+ sc_faddr_t aux_core_ram;
+ void *core_ram_vir;
+ u32 size;
+
+ ipcHndl = dev->mu_ipcHandle;
+ core_rsrc = SC_R_M4_0_PID0;
+ aux_core_ram = 0x34FE0000;
+ size = SZ_128K;
+
+ core_ram_vir = ioremap_wc(aux_core_ram,
+ size
+ );
+ if (!core_ram_vir)
+ vpu_dbg(LVL_ERR, "error: failed to remap space for core ram\n");
+
+ memcpy((void *)core_ram_vir, (void *)boot_addr, size);
+
+ if (sc_pm_cpu_start(ipcHndl, core_rsrc, true, aux_core_ram) != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: failed to start core_rsrc\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+#endif
+
+static int vpu_firmware_download(struct vpu_dev *This, u_int32 core_id)
+{
+ unsigned char *image;
+ unsigned int FW_Size = 0;
+ void *csr_offset, *csr_cpuwait;
+ int ret = 0;
+ char *p = This->core_dev[core_id].m0_p_fw_space_vir;
+
+ ret = request_firmware((const struct firmware **)&This->m0_pfw,
+ M0FW_FILENAME,
+ This->generic_dev
+ );
+ if (ret) {
+ vpu_dbg(LVL_ERR, "%s() request fw %s failed(%d)\n",
+ __func__, M0FW_FILENAME, ret);
+
+ if (This->m0_pfw) {
+ release_firmware(This->m0_pfw);
+ This->m0_pfw = NULL;
+ }
+ return ret;
+ } else {
+ vpu_dbg(LVL_INFO, "%s() request fw %s got size(%d)\n",
+ __func__, M0FW_FILENAME, (int)This->m0_pfw->size);
+ image = (uint8_t *)This->m0_pfw->data;
+ FW_Size = This->m0_pfw->size;
+ }
+ memcpy(This->core_dev[core_id].m0_p_fw_space_vir,
+ image,
+ FW_Size
+ );
+ if (This->plat_type == IMX8QM) { //encoder use core 1,2
+ if (core_id == 0) {
+ p[16] = IMX8QM;
+ p[17] = core_id + 1;
+ csr_offset = ioremap(0x2d090000, 4);
+ writel(This->core_dev[core_id].m0_p_fw_space_phy, csr_offset);
+ csr_cpuwait = ioremap(0x2d090004, 4);
+ writel(0x0, csr_cpuwait);
+ } else {
+ p[16] = IMX8QM;
+ p[17] = core_id + 1;
+ csr_offset = ioremap(0x2d0a0000, 4);
+ writel(This->core_dev[core_id].m0_p_fw_space_phy, csr_offset);
+ csr_cpuwait = ioremap(0x2d0a0004, 4);
+ writel(0x0, csr_cpuwait);
+ }
+ } else {
+ p[16] = IMX8QXP;
+ p[17] = core_id + 1;
+ csr_offset = ioremap(0x2d050000, 4);
+ writel(This->core_dev[core_id].m0_p_fw_space_phy, csr_offset);
+ csr_cpuwait = ioremap(0x2d050004, 4);
+ writel(0x0, csr_cpuwait);
+ }
+
+ return ret;
+}
+
+static int v4l2_open(struct file *filp)
+{
+ struct video_device *vdev = video_devdata(filp);
+ struct vpu_dev *dev = video_get_drvdata(vdev);
+ struct vpu_ctx *ctx = NULL;
+ int idx;
+ int ret;
+ u_int32 i;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ pm_runtime_get_sync(dev->generic_dev);
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+ mutex_lock(&dev->dev_mutex);
+ idx = vpu_next_free_instance(dev, ctx);
+ if (idx < 0) {
+ ret = idx;
+ mutex_unlock(&dev->dev_mutex);
+ goto err_find_index;
+ }
+ set_bit(idx, &dev->core_dev[ctx->core_id].instance_mask);
+ mutex_unlock(&dev->dev_mutex);
+ init_completion(&ctx->completion);
+ init_completion(&ctx->stop_cmp);
+
+ v4l2_fh_init(&ctx->fh, video_devdata(filp));
+ filp->private_data = &ctx->fh;
+ v4l2_fh_add(&ctx->fh);
+
+ ctx->str_index = idx;
+ ctx->dev = dev;
+ ctx->ctrl_inited = false;
+ ctrls_setup_encoder(ctx);
+ ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+
+ ctx->instance_wq = alloc_workqueue("vpu_instance", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+ if (!ctx->instance_wq) {
+ vpu_dbg(LVL_ERR, "error: %s unable to alloc workqueue for ctx\n", __func__);
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+ INIT_WORK(&ctx->instance_work, vpu_msg_instance_work);
+
+ mutex_init(&ctx->instance_mutex);
+ if (kfifo_alloc(&ctx->msg_fifo,
+ sizeof(struct event_msg) * VID_API_MESSAGE_LIMIT,
+ GFP_KERNEL)) {
+ vpu_dbg(LVL_ERR, "fail to alloc fifo when open\n");
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+ dev->core_dev[ctx->core_id].ctx[idx] = ctx;
+ ctx->b_firstseq = true;
+ ctx->start_flag = true;
+ ctx->forceStop = false;
+ ctx->firmware_stopped = false;
+ ctx->ctx_released = false;
+ init_queue_data(ctx);
+ init_waitqueue_head(&ctx->buffer_wq_output);
+ init_waitqueue_head(&ctx->buffer_wq_input);
+ mutex_lock(&dev->dev_mutex);
+ if (!dev->core_dev[ctx->core_id].fw_is_ready) {
+ ret = vpu_firmware_download(dev, ctx->core_id);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "error: vpu_firmware_download fail\n");
+ mutex_unlock(&dev->dev_mutex);
+ goto err_firmware_load;
+ }
+
+ if (!ctx->dev->core_dev[ctx->core_id].firmware_started)
+ wait_for_completion(&ctx->dev->core_dev[ctx->core_id].start_cmp);
+ dev->core_dev[ctx->core_id].fw_is_ready = true;
+ }
+ mutex_unlock(&dev->dev_mutex);
+ ctx->encoder_stream.size = STREAM_SIZE;
+ ctx->encoder_stream.virt_addr = dma_alloc_coherent(&ctx->dev->plat_dev->dev,
+ ctx->encoder_stream.size,
+ (dma_addr_t *)&ctx->encoder_stream.phy_addr,
+ GFP_KERNEL | GFP_DMA32
+ );
+
+ if (!ctx->encoder_stream.virt_addr)
+ vpu_dbg(LVL_ERR, "%s() encoder stream buffer alloc size(%x) fail!\n", __func__, ctx->encoder_stream.size);
+ else
+ vpu_dbg(LVL_INFO, "%s() encoder_stream_size(%d) encoder_stream_virt(%p) encoder_stream_phy(%p)\n", __func__, ctx->encoder_stream.size, ctx->encoder_stream.virt_addr, (void *)ctx->encoder_stream.phy_addr);
+
+ ctx->encoder_mem.size = 0;
+ ctx->encoder_mem.virt_addr = NULL;
+ ctx->encoder_mem.phy_addr = 0;
+
+ for (i = 0; i < MEDIAIP_MAX_NUM_WINDSOR_SRC_FRAMES; i++) {
+ ctx->encFrame[i].virt_addr = NULL;
+ ctx->encFrame[i].phy_addr = 0;
+ ctx->encFrame[i].size = 0;
+ }
+
+ for (i = 0; i < MEDIAIP_MAX_NUM_WINDSOR_REF_FRAMES; i++) {
+ ctx->refFrame[i].virt_addr = NULL;
+ ctx->refFrame[i].phy_addr = 0;
+ ctx->refFrame[i].size = 0;
+ }
+ ctx->actFrame.virt_addr = NULL;
+ ctx->actFrame.phy_addr = 0;
+ ctx->actFrame.size = 0;
+
+ return 0;
+
+err_firmware_load:
+ release_queue_data(ctx);
+ ctrls_delete_encoder(ctx);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ clear_bit(ctx->str_index, &dev->core_dev[ctx->core_id].instance_mask);
+
+err_find_index:
+ pm_runtime_put_sync(dev->generic_dev);
+ kfree(ctx);
+ return ret;
+err_alloc:
+ pm_runtime_put_sync(dev->generic_dev);
+ kfree(ctx);
+ return ret;
+}
+
+static int v4l2_release(struct file *filp)
+{
+ struct video_device *vdev = video_devdata(filp);
+ struct vpu_dev *dev = video_get_drvdata(vdev);
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+ struct core_device *core_dev = &dev->core_dev[ctx->core_id];
+ u_int32 i;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (!ctx->forceStop && !ctx->start_flag) {
+ //need send stop if app call release without calling of V4L2_ENC_CMD_STOP
+ ctx->forceStop = true;
+ v4l2_vpu_send_cmd(ctx, ctx->str_index, GTB_ENC_CMD_STREAM_STOP, 0, NULL);
+ wake_up_interruptible(&ctx->buffer_wq_input);
+ wake_up_interruptible(&ctx->buffer_wq_output);
+ }
+
+ if (!ctx->firmware_stopped && ctx->start_flag == false)
+ wait_for_completion(&ctx->stop_cmp);
+
+ release_queue_data(ctx);
+ ctrls_delete_encoder(ctx);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+
+ mutex_lock(&core_dev->core_mutex);
+ clear_bit(ctx->str_index, &core_dev->instance_mask);
+ mutex_unlock(&core_dev->core_mutex);
+
+ dma_free_coherent(&ctx->dev->plat_dev->dev,
+ ctx->encoder_stream.size,
+ ctx->encoder_stream.virt_addr,
+ ctx->encoder_stream.phy_addr
+ );
+ for (i = 0; i < MEDIAIP_MAX_NUM_WINDSOR_SRC_FRAMES; i++)
+ if (ctx->encFrame[i].virt_addr != NULL)
+ dma_free_coherent(&ctx->dev->plat_dev->dev,
+ ctx->encFrame[i].size,
+ ctx->encFrame[i].virt_addr,
+ ctx->encFrame[i].phy_addr
+ );
+ for (i = 0; i < MEDIAIP_MAX_NUM_WINDSOR_REF_FRAMES; i++)
+ if (ctx->refFrame[i].virt_addr != NULL)
+ dma_free_coherent(&ctx->dev->plat_dev->dev,
+ ctx->refFrame[i].size,
+ ctx->refFrame[i].virt_addr,
+ ctx->refFrame[i].phy_addr
+ );
+ if (ctx->actFrame.virt_addr != NULL)
+ dma_free_coherent(&ctx->dev->plat_dev->dev,
+ ctx->actFrame.size,
+ ctx->actFrame.virt_addr,
+ ctx->actFrame.phy_addr
+ );
+ mutex_lock(&ctx->instance_mutex);
+ ctx->ctx_released = true;
+ kfifo_free(&ctx->msg_fifo);
+ destroy_workqueue(ctx->instance_wq);
+ mutex_unlock(&ctx->instance_mutex);
+ mutex_lock(&core_dev->core_mutex);
+ if (!(core_dev->hang_mask & (1 << ctx->str_index))) // judge the path is hang or not, if hang, don't clear
+ clear_bit(ctx->str_index, &core_dev->instance_mask);
+// dev->ctx[ctx->str_index] = NULL;
+ mutex_unlock(&core_dev->core_mutex);
+
+ pm_runtime_put_sync(dev->generic_dev);
+ kfree(ctx);
+ return 0;
+}
+
+static unsigned int v4l2_poll(struct file *filp, poll_table *wait)
+{
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+ struct vb2_queue *src_q, *dst_q;
+ unsigned int rc = 0;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (ctx) {
+ poll_wait(filp, &ctx->fh.wait, wait);
+
+ if (v4l2_event_pending(&ctx->fh)) {
+ vpu_dbg(LVL_INFO, "%s() v4l2_event_pending\n", __func__);
+ rc |= POLLPRI;
+ }
+
+ src_q = &ctx->q_data[V4L2_SRC].vb2_q;
+ dst_q = &ctx->q_data[V4L2_DST].vb2_q;
+
+ if ((!src_q->streaming || list_empty(&src_q->queued_list))
+ && (!dst_q->streaming || list_empty(&dst_q->queued_list))) {
+ return rc;
+ }
+
+ poll_wait(filp, &src_q->done_wq, wait);
+ if (!list_empty(&src_q->done_list))
+ rc |= POLLOUT | POLLWRNORM;
+ poll_wait(filp, &dst_q->done_wq, wait);
+ if (!list_empty(&dst_q->done_list))
+ rc |= POLLIN | POLLRDNORM;
+ } else
+ rc = POLLERR;
+
+ return rc;
+}
+
+static int v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ long ret = -EPERM;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ struct queue_data *q_data;
+ enum QUEUE_TYPE type;
+
+ struct vpu_ctx *ctx = v4l2_fh_to_ctx(filp->private_data);
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+
+ if (ctx) {
+ type = offset >> MMAP_BUF_TYPE_SHIFT;
+ q_data = &ctx->q_data[type];
+
+ offset &= ~MMAP_BUF_TYPE_MASK;
+ offset = offset >> PAGE_SHIFT;
+ vma->vm_pgoff = offset;
+ ret = vb2_mmap(&q_data->vb2_q,
+ vma
+ );
+ }
+
+ return ret;
+}
+
+static const struct v4l2_file_operations v4l2_encoder_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_open,
+ .unlocked_ioctl = video_ioctl2,
+ .release = v4l2_release,
+ .poll = v4l2_poll,
+ .mmap = v4l2_mmap,
+};
+
+static struct video_device v4l2_videodevice_encoder = {
+ .name = "vpu encoder",
+ .fops = &v4l2_encoder_fops,
+ .ioctl_ops = &v4l2_encoder_ioctl_ops,
+ .vfl_dir = VFL_DIR_M2M,
+};
+#if 1
+static int set_vpu_pwr(sc_ipc_t ipcHndl,
+ sc_pm_power_mode_t pm,
+ u_int32 core_id
+ )
+{
+ int rv = -1;
+ sc_err_t sciErr;
+
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+ if (!ipcHndl) {
+ vpu_dbg(LVL_ERR, "error: --- set_vpu_pwr no IPC handle\n");
+ goto set_vpu_pwrexit;
+ }
+
+ // Power on or off VPU, ENC and MU1
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU, pm);
+ if (sciErr != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU,%d) SCI error! (%d)\n", sciErr, pm);
+ goto set_vpu_pwrexit;
+ }
+#ifdef TEST_BUILD
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_ENC, pm);
+ if (sciErr != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_ENC,%d) SCI error! (%d)\n", sciErr, pm);
+ goto set_vpu_pwrexit;
+ }
+#else
+ if (core_id == 0) {
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_ENC_0, pm);
+ if (sciErr != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_ENC_0,%d) SCI error! (%d)\n", sciErr, pm);
+ goto set_vpu_pwrexit;
+ }
+ } else {
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_ENC_1, pm);
+ if (sciErr != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_ENC_1,%d) SCI error! (%d)\n", sciErr, pm);
+ goto set_vpu_pwrexit;
+ }
+ }
+#endif
+ if (core_id == 0) {
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_MU_1, pm);
+ if (sciErr != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_MU_1,%d) SCI error! (%d)\n", sciErr, pm);
+ goto set_vpu_pwrexit;
+ }
+ } else {
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_MU_2, pm);
+ if (sciErr != SC_ERR_NONE) {
+ vpu_dbg(LVL_ERR, "error: --- sc_pm_set_resource_power_mode(SC_R_VPU_MU_2,%d) SCI error! (%d)\n", sciErr, pm);
+ goto set_vpu_pwrexit;
+ }
+ }
+ rv = 0;
+
+set_vpu_pwrexit:
+ return rv;
+}
+
+static void vpu_set_power(struct vpu_dev *dev, bool on, u_int32 core_id)
+{
+ int ret;
+
+ if (on) {
+ ret = set_vpu_pwr(dev->mu_ipcHandle, SC_PM_PW_MODE_ON, core_id);
+ if (ret)
+ vpu_dbg(LVL_ERR, "error: failed to power on\n");
+ pm_runtime_get_sync(dev->generic_dev);
+ } else {
+ pm_runtime_put_sync_suspend(dev->generic_dev);
+ ret = set_vpu_pwr(dev->mu_ipcHandle, SC_PM_PW_MODE_OFF, core_id);
+ if (ret)
+ vpu_dbg(LVL_ERR, "error: failed to power off\n");
+ }
+}
+#endif
+
+static void vpu_setup(struct vpu_dev *This)
+{
+ uint32_t read_data = 0;
+
+ vpu_dbg(LVL_INFO, "enter %s\n", __func__);
+ writel(0x1, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_SCB_CLK_ENABLE_SET);
+ writel(0xffffffff, This->regs_base + 0x70190);
+ writel(0xffffffff, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_XMEM_RESET_SET);
+
+ writel(0xE, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_SCB_CLK_ENABLE_SET);
+ writel(0x7, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_CACHE_RESET_SET);
+
+ writel(0x102, This->regs_base + XMEM_CONTROL);
+
+ read_data = readl(This->regs_base+0x70108);
+ vpu_dbg(LVL_IRQ, "%s read_data=%x\n", __func__, read_data);
+}
+
+static void vpu_reset(struct vpu_dev *This)
+{
+ vpu_dbg(LVL_INFO, "enter %s\n", __func__);
+ writel(0x7, This->regs_base + SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_CACHE_RESET_CLR);
+}
+
+static int vpu_enable_hw(struct vpu_dev *This)
+{
+ vpu_dbg(LVL_INFO, "%s()\n", __func__);
+#if 0
+ This->vpu_clk = clk_get(&This->plat_dev->dev, "vpu_encoder_clk");
+ if (IS_ERR(This->vpu_clk)) {
+ vpu_dbg(LVL_ERR, "vpu_clk get error\n");
+ return -ENOENT;
+ }
+#endif
+ vpu_setup(This);
+ return 0;
+}
+
+static void vpu_disable_hw(struct vpu_dev *This)
+{
+ vpu_reset(This);
+ if (This->regs_base) {
+ devm_iounmap(&This->plat_dev->dev,
+ This->regs_base);
+ }
+#if 0
+ if (This->vpu_clk) {
+ clk_put(This->vpu_clk);
+ }
+#endif
+}
+
+static int vpu_probe(struct platform_device *pdev)
+{
+ struct vpu_dev *dev;
+ struct resource *res;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *reserved_node;
+ struct resource reserved_res;
+ unsigned int mu_id;
+ u_int32 core_type;
+ u_int32 i;
+ int ret;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+ dev->plat_dev = pdev;
+ dev->generic_dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dev->regs_base = ioremap(ENC_REG_BASE, 0x1000000);
+ if (!dev->regs_base) {
+ vpu_dbg(LVL_ERR, "%s could not map regs_base\n", __func__);
+ return PTR_ERR(dev->regs_base);
+ }
+
+ if (np) {
+ ret = of_property_read_u32(np, "core_type", &core_type);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "error: Cannot get core num %d\n", ret);
+ return -EINVAL;
+ }
+ if (core_type == 2)
+ dev->plat_type = IMX8QM;
+ else
+ dev->plat_type = IMX8QXP;
+ reserved_node = of_parse_phandle(np, "boot-region", 0);
+ if (!reserved_node) {
+ vpu_dbg(LVL_ERR, "error: boot-region of_parse_phandle error\n");
+ return -ENODEV;
+ }
+
+ if (of_address_to_resource(reserved_node, 0, &reserved_res)) {
+ vpu_dbg(LVL_ERR, "error: boot-region of_address_to_resource error\n");
+ return -EINVAL;
+ }
+ dev->core_dev[0].m0_p_fw_space_phy = reserved_res.start;
+ dev->core_dev[1].m0_p_fw_space_phy = reserved_res.start + M0_BOOT_SIZE;
+ reserved_node = of_parse_phandle(np, "rpc-region", 0);
+ if (!reserved_node) {
+ vpu_dbg(LVL_ERR, "error: rpc-region of_parse_phandle error\n");
+ return -ENODEV;
+ }
+
+ if (of_address_to_resource(reserved_node, 0, &reserved_res)) {
+ vpu_dbg(LVL_ERR, "error: rpc-region of_address_to_resource error\n");
+ return -EINVAL;
+ }
+ dev->core_dev[0].m0_rpc_phy = reserved_res.start;
+ dev->core_dev[1].m0_rpc_phy = reserved_res.start + SHARED_SIZE;
+ } else
+ vpu_dbg(LVL_ERR, "error: %s of_node is NULL\n", __func__);
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "%s unable to register v4l2 dev\n", __func__);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, dev);
+
+ dev->pvpu_encoder_dev = video_device_alloc();
+ if (dev->pvpu_encoder_dev) {
+ strncpy(dev->pvpu_encoder_dev->name, v4l2_videodevice_encoder.name, sizeof(v4l2_videodevice_encoder.name));
+ dev->pvpu_encoder_dev->fops = v4l2_videodevice_encoder.fops;
+ dev->pvpu_encoder_dev->ioctl_ops = v4l2_videodevice_encoder.ioctl_ops;
+ dev->pvpu_encoder_dev->release = video_device_release;
+ dev->pvpu_encoder_dev->vfl_dir = v4l2_videodevice_encoder.vfl_dir;
+ dev->pvpu_encoder_dev->v4l2_dev = &dev->v4l2_dev;
+
+ video_set_drvdata(dev->pvpu_encoder_dev, dev);
+
+ if (video_register_device(dev->pvpu_encoder_dev,
+ VFL_TYPE_GRABBER,
+ -1)) {
+ vpu_dbg(LVL_ERR, "%s unable to register video encoder device\n",
+ __func__
+ );
+ video_device_release(dev->pvpu_encoder_dev);
+ dev->pvpu_encoder_dev = NULL;
+ } else {
+ vpu_dbg(LVL_INFO, "%s register video encoder device\n",
+ __func__
+ );
+ }
+ }
+
+ if (!dev->mu_ipcHandle) {
+ ret = sc_ipc_getMuID(&mu_id);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "--- sc_ipc_getMuID() cannot obtain mu id SCI error! (%d)\n", ret);
+ return ret;
+ }
+
+ ret = sc_ipc_open(&dev->mu_ipcHandle, mu_id);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "--- sc_ipc_getMuID() cannot open MU channel to SCU error! (%d)\n", ret);
+ return ret;
+ }
+ }
+
+ if (core_type == 2) {
+ vpu_set_power(dev, true, 0);
+ vpu_set_power(dev, true, 1);
+ } else
+ vpu_set_power(dev, true, 0);
+
+ vpu_enable_hw(dev);
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
+ mutex_init(&dev->dev_mutex);
+ for (i = 0; i < core_type; i++) {
+ struct core_device *core_dev;
+
+ core_dev = &dev->core_dev[i];
+ mutex_init(&core_dev->core_mutex);
+ mutex_init(&core_dev->cmd_mutex);
+ init_completion(&core_dev->start_cmp);
+ init_completion(&core_dev->snap_done_cmp);
+ core_dev->firmware_started = false;
+
+ core_dev->fw_is_ready = false;
+ core_dev->workqueue = alloc_workqueue("vpu", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+ if (!core_dev->workqueue) {
+ vpu_dbg(LVL_ERR, "%s unable to alloc workqueue\n", __func__);
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ INIT_WORK(&core_dev->msg_work, vpu_msg_run_work);
+
+ ret = vpu_mu_init(dev, i);
+ if (ret) {
+ vpu_dbg(LVL_ERR, "%s vpu mu init failed\n", __func__);
+ return ret;
+ }
+ //firmware space for M0
+ core_dev->m0_p_fw_space_vir = ioremap_wc(core_dev->m0_p_fw_space_phy,
+ M0_BOOT_SIZE
+ );
+ if (!core_dev->m0_p_fw_space_vir)
+ vpu_dbg(LVL_ERR, "failed to remap space for M0 firmware\n");
+
+ memset_io(core_dev->m0_p_fw_space_vir, 0, M0_BOOT_SIZE);
+
+ core_dev->m0_rpc_virt = ioremap_wc(core_dev->m0_rpc_phy,
+ SHARED_SIZE
+ );
+ if (!core_dev->m0_rpc_virt)
+ vpu_dbg(LVL_ERR, "failed to remap space for shared memory\n");
+
+ memset_io(core_dev->m0_rpc_virt, 0, SHARED_SIZE);
+
+ rpc_init_shared_memory_encoder(&core_dev->shared_mem, core_dev->m0_rpc_phy - core_dev->m0_p_fw_space_phy, core_dev->m0_rpc_virt, SHARED_SIZE);
+ rpc_set_system_cfg_value_encoder(core_dev->shared_mem.pSharedInterface, VPU_REG_BASE, i);
+ }
+ pm_runtime_put_sync(&pdev->dev);
+ return 0;
+}
+
+static int vpu_remove(struct platform_device *pdev)
+{
+ struct vpu_dev *dev = platform_get_drvdata(pdev);
+ u_int32 core_num;
+ u_int32 i;
+
+ if (dev->plat_type == IMX8QM) {
+ destroy_workqueue(dev->core_dev[0].workqueue);
+ destroy_workqueue(dev->core_dev[1].workqueue);
+ core_num = 2;
+ } else {
+ destroy_workqueue(dev->core_dev[0].workqueue);
+ core_num = 1;
+ }
+
+ for (i = 0; i < core_num; i++) {
+ if (dev->core_dev[i].m0_p_fw_space_vir)
+ iounmap(dev->core_dev[i].m0_p_fw_space_vir);
+ dev->core_dev[i].m0_p_fw_space_vir = NULL;
+ dev->core_dev[i].m0_p_fw_space_phy = 0;
+ if (dev->core_dev[i].shared_mem.shared_mem_vir)
+ iounmap(dev->core_dev[i].shared_mem.shared_mem_vir);
+ dev->core_dev[i].shared_mem.shared_mem_vir = NULL;
+ dev->core_dev[i].shared_mem.shared_mem_phy = 0;
+ }
+ if (dev->m0_pfw) {
+ release_firmware(dev->m0_pfw);
+ dev->m0_pfw = NULL;
+ }
+ vpu_disable_hw(dev);
+ pm_runtime_disable(&pdev->dev);
+
+ if (video_get_drvdata(dev->pvpu_encoder_dev))
+ video_unregister_device(dev->pvpu_encoder_dev);
+
+ v4l2_device_unregister(&dev->v4l2_dev);
+ return 0;
+}
+
+static int vpu_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int vpu_runtime_resume(struct device *dev)
+{
+ return 0;
+}
+#if 0
+static int vpu_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int vpu_resume(struct device *dev)
+{
+ return 0;
+}
+#endif
+#define CHECK_BIT(var, pos) (((var) >> (pos)) & 1)
+static void v4l2_vpu_send_snapshot(struct core_device *dev)
+{
+ int i = 0;
+ int strIdx = (~dev->hang_mask) & (dev->instance_mask);
+ /*figure out the first available instance*/
+ for (i = 0; i < VPU_MAX_NUM_STREAMS; i++) {
+ if (CHECK_BIT(strIdx, i)) {
+ strIdx = i;
+ break;
+ }
+ }
+
+ v4l2_vpu_send_cmd(dev->ctx[strIdx], strIdx, GTB_ENC_CMD_SNAPSHOT, 0, NULL);
+}
+
+static int vpu_suspend(struct device *dev)
+{
+ struct vpu_dev *vpudev = (struct vpu_dev *)dev_get_drvdata(dev);
+ struct core_device *core_dev;
+ u_int32 core_num, i;
+
+ if (vpudev->plat_type == IMX8QM)
+ core_num = 2;
+ else
+ core_num = 1;
+
+ for (i = 0; i < core_num; i++) {
+ vpu_set_power(vpudev, false, i);
+ core_dev = &vpudev->core_dev[i];
+ if (core_dev->hang_mask != core_dev->instance_mask) {
+
+ /*if there is an available device, send snapshot command to firmware*/
+ v4l2_vpu_send_snapshot(core_dev);
+
+ if (!wait_for_completion_timeout(&core_dev->snap_done_cmp, msecs_to_jiffies(1000))) {
+ vpu_dbg(LVL_ERR, "error: wait for vpu encoder snapdone event timeout!\n");
+ return -1;
+ }
+ }
+ }
+
+// vpu_set_power(vpudev, false);
+
+ return 0;
+}
+
+static int vpu_resume(struct device *dev)
+{
+ struct vpu_dev *vpudev = (struct vpu_dev *)dev_get_drvdata(dev);
+ void *csr_offset, *csr_cpuwait;
+ struct core_device *core_dev;
+ u_int32 core_num;
+ u_int32 i;
+
+ if (vpudev->plat_type == IMX8QM) {
+ core_num = 2;
+ vpu_set_power(vpudev, true, 0);
+ vpu_set_power(vpudev, true, 1);
+ vpu_enable_hw(vpudev);
+ } else {
+ core_num = 1;
+ vpu_set_power(vpudev, true, 0);
+ vpu_enable_hw(vpudev);
+ }
+ for (i = 0; i < core_num; i++) {
+ core_dev = &vpudev->core_dev[i];
+ MU_Init(core_dev->mu_base_virtaddr);
+ MU_EnableRxFullInt(core_dev->mu_base_virtaddr, 0);
+
+ if (core_dev->hang_mask == core_dev->instance_mask) {
+ /*no instance is active before suspend, do reset*/
+ core_dev->fw_is_ready = false;
+ core_dev->firmware_started = false;
+
+ rpc_init_shared_memory_encoder(&core_dev->shared_mem, core_dev->m0_rpc_phy - core_dev->m0_p_fw_space_phy, core_dev->m0_rpc_virt, SHARED_SIZE);
+ rpc_set_system_cfg_value_encoder(core_dev->shared_mem.pSharedInterface, VPU_REG_BASE, i);
+ } else {
+ /*resume*/
+ if (vpudev->plat_type == IMX8QXP) {
+ csr_offset = ioremap(0x2d050000, 4);
+ writel(core_dev->m0_p_fw_space_phy, csr_offset);
+ csr_cpuwait = ioremap(0x2d050004, 4);
+ writel(0x0, csr_cpuwait);
+ } else {
+ if (i == 0) {
+ csr_offset = ioremap(0x2d090000, 4);
+ writel(core_dev->m0_p_fw_space_phy, csr_offset);
+ csr_cpuwait = ioremap(0x2d090004, 4);
+ writel(0x0, csr_cpuwait);
+ } else {
+ csr_offset = ioremap(0x2d0a0000, 4);
+ writel(core_dev->m0_p_fw_space_phy, csr_offset);
+ csr_cpuwait = ioremap(0x2d0a0004, 4);
+ writel(0x0, csr_cpuwait);
+ }
+ }
+ /*wait for firmware resotre done*/
+ if (!wait_for_completion_timeout(&core_dev->start_cmp, msecs_to_jiffies(1000))) {
+ vpu_dbg(LVL_ERR, "error: wait for vpu encoder resume done timeout!\n");
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+static const struct dev_pm_ops vpu_pm_ops = {
+ SET_RUNTIME_PM_OPS(vpu_runtime_suspend, vpu_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(vpu_suspend, vpu_resume)
+};
+
+static const struct of_device_id vpu_of_match[] = {
+ { .compatible = "nxp,imx8qm-b0-vpuenc", },
+ { .compatible = "nxp,imx8qxp-b0-vpuenc", },
+ {}
+}
+MODULE_DEVICE_TABLE(of, vpu_of_match);
+
+static struct platform_driver vpu_driver = {
+ .probe = vpu_probe,
+ .remove = vpu_remove,
+ .driver = {
+ .name = "vpu-b0-encoder",
+ .of_match_table = vpu_of_match,
+ .pm = &vpu_pm_ops,
+ },
+};
+module_platform_driver(vpu_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Linux VPU driver for Freescale i.MX/MXC");
+MODULE_LICENSE("GPL");
+
+module_param(vpu_dbg_level_encoder, int, 0644);
+MODULE_PARM_DESC(vpu_dbg_level_encoder, "Debug level (0-2)");
+
diff --git a/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.h b/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.h
new file mode 100644
index 000000000000..9880d33993e7
--- /dev/null
+++ b/drivers/mxc/vpu-encoder-b0/vpu_encoder_b0.h
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2018 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file vpu_encoder_b0.h
+ *
+ * @brief VPU ENCODER B0 definition
+ *
+ */
+#ifndef __VPU_ENCODER_B0_H__
+#define __VPU_ENCODER_B0_H__
+
+#include <linux/irqreturn.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-v4l2.h>
+#include <soc/imx8/sc/svc/irq/api.h>
+#include <soc/imx8/sc/ipc.h>
+#include <soc/imx8/sc/sci.h>
+#include <linux/mx8_mu.h>
+#include <media/v4l2-event.h>
+#include <linux/kfifo.h>
+#include "vpu_encoder_rpc.h"
+
+extern unsigned int vpu_dbg_level_encoder;
+
+#define v4l2_fh_to_ctx(__fh) \
+ container_of(__fh, struct vpu_ctx, fh)
+#define v4l2_ctrl_to_ctx(__ctrl) \
+ container_of((__ctrl)->handler, struct vpu_ctx, ctrl_handler)
+
+#define MIN_SPACE 2048
+
+#define VPU_MAX_FORMATS 4
+#define VPU_MAX_BUFFER 32
+#define M0FW_FILENAME "vpu/vpu_fw_imx8qxp_enc.bin"
+#define MMAP_BUF_TYPE_SHIFT 28
+#define MMAP_BUF_TYPE_MASK 0xF0000000
+#define M0_BOOT_SIZE 0x1000000
+#define M0_PRINT_OFFSET 0x500000
+#define SHARED_SIZE 0x00400000
+#define MEM_SIZE 0x2800000
+#define YUV_SIZE 0x4000000
+#define STREAM_SIZE 0x300000
+#ifdef CM4
+#define VPU_REG_BASE 0x2c000000
+#else
+#define VPU_REG_BASE 0x40000000
+#endif
+#define ENC_REG_BASE 0x2c000000
+#define MIN_BUFFER_COUNT 3
+#define V4L2_MAX_CTRLS 12
+struct vpu_v4l2_control {
+ uint32_t id;
+ enum v4l2_ctrl_type type;
+ uint32_t minimum;
+ uint32_t maximum;
+ uint32_t step;
+ uint32_t default_value;
+ uint32_t menu_skip_mask;
+ bool is_volatile;
+};
+
+typedef enum{
+ INIT_DONE = 1,
+ RPC_BUF_OFFSET,
+ PRINT_BUF_OFFSET,
+ BOOT_ADDRESS,
+ COMMAND,
+ EVENT
+} MSG_Type;
+
+enum PLAT_TYPE {
+ IMX8QXP = 0,
+ IMX8QM = 1,
+};
+
+enum QUEUE_TYPE {
+ V4L2_SRC = 0,
+ V4L2_DST = 1,
+};
+
+enum vpu_video_standard {
+ VPU_VIDEO_UNDEFINED = 0,
+ VPU_VIDEO_AVC = 1,
+ VPU_VIDEO_VC1 = 2,
+ VPU_VIDEO_MPEG2 = 3,
+ VPU_VIDEO_AVS = 4,
+ VPU_VIDEO_ASP = 5,
+ VPU_VIDEO_JPEG = 6,
+ VPU_VIDEO_RV8 = 7,
+ VPU_VIDEO_RV9 = 8,
+ VPU_VIDEO_VP6 = 9,
+ VPU_VIDEO_SPK = 10,
+ VPU_VIDEO_VP8 = 11,
+ VPU_VIDEO_AVC_MVC = 12,
+ VPU_VIDEO_HEVC = 13,
+ VPU_VIDEO_VP9 = 14,
+};
+
+#define VPU_PIX_FMT_AVS v4l2_fourcc('A', 'V', 'S', '0')
+#define VPU_PIX_FMT_ASP v4l2_fourcc('A', 'S', 'P', '0')
+#define VPU_PIX_FMT_RV8 v4l2_fourcc('R', 'V', '8', '0')
+#define VPU_PIX_FMT_RV9 v4l2_fourcc('R', 'V', '9', '0')
+#define VPU_PIX_FMT_VP6 v4l2_fourcc('V', 'P', '6', '0')
+#define VPU_PIX_FMT_SPK v4l2_fourcc('S', 'P', 'K', '0')
+#define VPU_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C')
+#define VPU_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0')
+#define VPU_PIX_FMT_LOGO v4l2_fourcc('L', 'O', 'G', 'O')
+
+#define VPU_PIX_FMT_TILED_8 v4l2_fourcc('Z', 'T', '0', '8')
+#define VPU_PIX_FMT_TILED_10 v4l2_fourcc('Z', 'T', '1', '0')
+
+enum vpu_pixel_format {
+ VPU_HAS_COLOCATED = 0x00000001,
+ VPU_HAS_SPLIT_FLD = 0x00000002,
+ VPU_PF_MASK = ~(VPU_HAS_COLOCATED | VPU_HAS_SPLIT_FLD),
+
+ VPU_IS_TILED = 0x000000100,
+ VPU_HAS_10BPP = 0x00000200,
+
+ VPU_IS_PLANAR = 0x00001000,
+ VPU_IS_SEMIPLANAR = 0x00002000,
+ VPU_IS_PACKED = 0x00004000,
+
+ // Merged definitions using above flags:
+ VPU_PF_UNDEFINED = 0,
+ VPU_PF_YUV420_SEMIPLANAR = 0x00010000 | VPU_IS_SEMIPLANAR,
+ VPU_PF_YUV420_PLANAR = 0x00020000 | VPU_IS_PLANAR,
+ VPU_PF_UYVY = 0x00040000 | VPU_IS_PACKED,
+ VPU_PF_TILED_8BPP = 0x00080000 | VPU_IS_TILED | VPU_IS_SEMIPLANAR,
+ VPU_PF_TILED_10BPP = 0x00100000 | VPU_IS_TILED | VPU_IS_SEMIPLANAR | VPU_HAS_10BPP,
+};
+
+struct vpu_v4l2_fmt {
+ char *name;
+ unsigned int fourcc;
+ unsigned int num_planes;
+ unsigned int venc_std;
+};
+
+struct vb2_data_req {
+ struct list_head list;
+ struct vb2_buffer *vb2_buf;
+ int id;
+ u_int32 buffer_flags;
+};
+
+struct queue_data {
+ unsigned int width;
+ unsigned int height;
+ unsigned int bytesperline;
+ unsigned int sizeimage[2];
+ unsigned int fourcc;
+ unsigned int vdec_std;
+ struct v4l2_rect rect;
+ int buf_type; // v4l2_buf_type
+ bool vb2_q_inited;
+ struct vb2_queue vb2_q; // vb2 queue
+ struct list_head drv_q; // driver queue
+ struct semaphore drv_q_lock;
+ struct vb2_data_req vb2_reqs[VPU_MAX_BUFFER];
+ enum QUEUE_TYPE type;
+};
+struct vpu_ctx;
+struct core_device {
+ struct firmware *m0_pfw;
+ void *m0_p_fw_space_vir;
+ u_int32 m0_p_fw_space_phy;
+ void *m0_rpc_virt;
+ u_int32 m0_rpc_phy;
+ struct mutex core_mutex;
+ struct mutex cmd_mutex;
+ bool fw_is_ready;
+ bool firmware_started;
+ struct completion start_cmp;
+ struct completion snap_done_cmp;
+ struct workqueue_struct *workqueue;
+ struct work_struct msg_work;
+ unsigned long instance_mask;
+ unsigned long hang_mask; //this is used to deal with hang issue to reset firmware
+ void __iomem *mu_base_virtaddr;
+ unsigned int vpu_mu_id;
+ int vpu_mu_init;
+
+ struct vpu_ctx *ctx[VPU_MAX_NUM_STREAMS];
+ struct shared_addr shared_mem;
+};
+struct vpu_dev {
+ struct device *generic_dev;
+ struct v4l2_device v4l2_dev;
+ struct video_device *pvpu_encoder_dev;
+ struct platform_device *plat_dev;
+ sc_ipc_t mu_ipcHandle;
+ struct clk *clk_m0;
+ struct firmware *m0_pfw;
+ struct clk *vpu_clk;
+ void __iomem *regs_base;
+ struct mutex dev_mutex;
+ struct core_device core_dev[2];
+ u_int32 plat_type;
+// struct vpu_ctx *ctx[VPU_MAX_NUM_STREAMS];
+};
+
+struct buffer_addr {
+ void *virt_addr;
+ dma_addr_t phy_addr;
+ u_int32 size;
+};
+
+struct vpu_ctx {
+ struct vpu_dev *dev;
+ struct v4l2_fh fh;
+
+ struct v4l2_ctrl *ctrls[V4L2_MAX_CTRLS];
+ struct v4l2_ctrl_handler ctrl_handler;
+ bool ctrl_inited;
+
+ int str_index;
+ struct queue_data q_data[2];
+ struct kfifo msg_fifo;
+ struct mutex instance_mutex;
+ struct work_struct instance_work;
+ struct workqueue_struct *instance_wq;
+ struct completion completion;
+ struct completion stop_cmp;
+ bool b_firstseq;
+ bool start_flag;
+ bool firmware_stopped;
+ bool ctx_released;
+ bool forceStop;
+ wait_queue_head_t buffer_wq_output;
+ wait_queue_head_t buffer_wq_input;
+ struct buffer_addr encoder_buffer;
+ struct buffer_addr encoder_stream;
+ struct buffer_addr encoder_mem;
+ struct buffer_addr encFrame[MEDIAIP_MAX_NUM_WINDSOR_SRC_FRAMES];
+ struct buffer_addr refFrame[MEDIAIP_MAX_NUM_WINDSOR_REF_FRAMES];
+ struct buffer_addr actFrame;
+ u_int32 core_id;
+
+};
+
+#define LVL_INFO 3
+#define LVL_IRQ 2
+#define LVL_ALL 1
+#define LVL_ERR 0
+
+#define vpu_dbg(level, fmt, arg...) \
+ do { \
+ if (vpu_dbg_level_encoder >= (level)) \
+ printk("[DEBUG]\t " fmt, ## arg); \
+ } while (0)
+
+#endif
diff --git a/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.c b/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.c
new file mode 100644
index 000000000000..cb6ac330c5c6
--- /dev/null
+++ b/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.c
@@ -0,0 +1,303 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "vpu_encoder_rpc.h"
+
+void rpc_init_shared_memory_encoder(struct shared_addr *This,
+ unsigned long long base_phy_addr,
+ void *base_virt_addr,
+ u_int32 total_size)
+{
+ pENC_RPC_HOST_IFACE pSharedInterface;
+ unsigned int phy_addr;
+ unsigned int i;
+ unsigned int temp_addr;
+ BUFFER_DESCRIPTOR_TYPE *pSharedCmdBufDescPtr;
+ BUFFER_DESCRIPTOR_TYPE *pSharedMsgBufDescPtr;
+ pMEDIA_ENC_API_CONTROL_INTERFACE pEncCtrlInterface;
+
+ This->shared_mem_phy = base_phy_addr;
+ This->shared_mem_vir = base_virt_addr;
+ This->base_offset = (unsigned long long)(base_virt_addr - base_phy_addr);
+
+ pSharedInterface = (pENC_RPC_HOST_IFACE)This->shared_mem_vir;
+ This->pSharedInterface = pSharedInterface;
+
+ pSharedInterface->FwExecBaseAddr = base_phy_addr;
+ pSharedInterface->FwExecAreaSize = total_size;
+
+ pSharedCmdBufDescPtr = (BUFFER_DESCRIPTOR_TYPE *)&pSharedInterface->StreamCmdBufferDesc;
+ pSharedMsgBufDescPtr = (BUFFER_DESCRIPTOR_TYPE *)&pSharedInterface->StreamMsgBufferDesc;
+
+ phy_addr = base_phy_addr + sizeof(ENC_RPC_HOST_IFACE);
+ This->cmd_mem_phy = phy_addr;
+ This->cmd_mem_vir = This->shared_mem_vir + sizeof(ENC_RPC_HOST_IFACE);
+
+ pSharedCmdBufDescPtr->wptr = phy_addr;
+ pSharedCmdBufDescPtr->rptr = pSharedCmdBufDescPtr->wptr;
+ pSharedCmdBufDescPtr->start = pSharedCmdBufDescPtr->wptr;
+ pSharedCmdBufDescPtr->end = pSharedCmdBufDescPtr->start + CMD_SIZE;
+
+ phy_addr += CMD_SIZE;
+ This->msg_mem_phy = phy_addr;
+ This->msg_mem_vir = This->cmd_mem_vir + CMD_SIZE;
+
+ pSharedMsgBufDescPtr->wptr = phy_addr;
+ pSharedMsgBufDescPtr->rptr = pSharedMsgBufDescPtr->wptr;
+ pSharedMsgBufDescPtr->start = pSharedMsgBufDescPtr->wptr;
+ pSharedMsgBufDescPtr->end = pSharedMsgBufDescPtr->start + MSG_SIZE;
+
+ phy_addr += MSG_SIZE;
+
+ for (i = 0; i < VPU_MAX_NUM_STREAMS; i++) {
+ pSharedInterface->pEncCtrlInterface[i] = phy_addr;
+ phy_addr += sizeof(MEDIA_ENC_API_CONTROL_INTERFACE);
+ }
+
+ for (i = 0; i < VPU_MAX_NUM_STREAMS; i++) {
+ temp_addr = pSharedInterface->pEncCtrlInterface[i];
+ pEncCtrlInterface = (pMEDIA_ENC_API_CONTROL_INTERFACE)(temp_addr + This->base_offset);
+ pEncCtrlInterface->pEncYUVBufferDesc = phy_addr;
+ phy_addr += sizeof(MEDIAIP_ENC_YUV_BUFFER_DESC);
+ pEncCtrlInterface->pEncStreamBufferDesc = phy_addr;
+ phy_addr += sizeof(BUFFER_DESCRIPTOR_TYPE);
+ pEncCtrlInterface->pEncExpertModeParam = phy_addr;
+ phy_addr += sizeof(MEDIAIP_ENC_EXPERT_MODE_PARAM);
+ pEncCtrlInterface->pEncParam = phy_addr;
+ phy_addr += sizeof(MEDIAIP_ENC_PARAM);
+ pEncCtrlInterface->pEncMemPool = phy_addr;
+ phy_addr += sizeof(MEDIAIP_ENC_MEM_POOL);
+ pEncCtrlInterface->pEncEncodingStatus = phy_addr;
+ phy_addr += sizeof(ENC_ENCODING_STATUS);
+ pEncCtrlInterface->pEncDSAStatus = phy_addr;
+ phy_addr += sizeof(ENC_DSA_STATUS_t);
+ }
+}
+
+void rpc_set_system_cfg_value_encoder(void *Interface, u_int32 regs_base, u_int32 core_id)
+{
+ pENC_RPC_HOST_IFACE pSharedInterface;
+ MEDIAIP_FW_SYSTEM_CONFIG *pSystemCfg;
+
+ pSharedInterface = (pENC_RPC_HOST_IFACE)Interface;
+ pSystemCfg = &pSharedInterface->sSystemCfg;
+ pSystemCfg->uNumWindsors = 1;
+ pSystemCfg->uWindsorIrqPin[0x0][0x0] = 0x4; // PAL_IRQ_WINDSOR_LOW
+ pSystemCfg->uWindsorIrqPin[0x0][0x1] = 0x5; // PAL_IRQ_WINDSOR_HI
+ pSystemCfg->uMaloneBaseAddress[0] = (unsigned int)(regs_base + 0x180000);
+ if (core_id == 0)
+ pSystemCfg->uWindsorBaseAddress[0] = (unsigned int)(regs_base + 0x800000);
+ else
+ pSystemCfg->uWindsorBaseAddress[0] = (unsigned int)(regs_base + 0xa00000);
+ pSystemCfg->uMaloneBaseAddress[0x1] = 0x0;
+ pSystemCfg->uHifOffset[0x0] = 0x1C000;
+ pSystemCfg->uHifOffset[0x1] = 0x0;
+
+ pSystemCfg->uDPVBaseAddr = 0x0;
+ pSystemCfg->uDPVIrqPin = 0x0;
+ pSystemCfg->uPixIfBaseAddr = (unsigned int)(regs_base + 0x180000 + 0x20000);
+ pSystemCfg->uFSLCacheBaseAddr[0] = (unsigned int)(regs_base + 0x60000);
+ pSystemCfg->uFSLCacheBaseAddr[1] = (unsigned int)(regs_base + 0x68000);
+}
+
+u_int32 rpc_MediaIPFW_Video_buffer_space_check_encoder(BUFFER_DESCRIPTOR_TYPE *pBufDesc,
+ BOOL bFull,
+ u_int32 uSize,
+ u_int32 *puUpdateAddress)
+{
+ u_int32 uPtr1;
+ u_int32 uPtr2;
+ u_int32 start;
+ u_int32 end;
+ u_int32 uTemp;
+
+ /* bFull is FALSE when send message, write data */
+ /* bFull is TRUE when process commands, read data */
+ uPtr1 = (bFull) ? pBufDesc->rptr : pBufDesc->wptr;
+ uPtr2 = (bFull) ? pBufDesc->wptr : pBufDesc->rptr;
+
+ if (uPtr1 == uPtr2) {
+ if (bFull)
+ /* No data at all to read */
+ return 0;
+ else {
+ /* wrt pointer equal to read pointer thus the */
+ /* buffer is completely empty for further writes */
+ start = pBufDesc->start;
+ end = pBufDesc->end;
+ /* The address to be returned in this case is for */
+ /* the updated write pointer. */
+ uTemp = uPtr1 + uSize;
+ if (uTemp >= end)
+ uTemp += (start - end);
+ *puUpdateAddress = uTemp;
+ return (end - start);
+ }
+ } else if (uPtr1 < uPtr2) {
+ /* return updated rd pointer address */
+ /* In this case if size was too big - we expect the */
+ /* external ftn to compare the size against the */
+ /* space returned.
+ */
+ *puUpdateAddress = uPtr1 + uSize;
+ return (uPtr2 - uPtr1);
+ }
+ /* We know the system has looped!! */
+ start = pBufDesc->start;
+ end = pBufDesc->end;
+ uTemp = uPtr1 + uSize;
+ if (uTemp >= end)
+ uTemp += (start - end);
+ *puUpdateAddress = uTemp;
+ return ((end - uPtr1) + (uPtr2 - start));
+}
+
+static void rpc_update_cmd_buffer_ptr_encoder(BUFFER_DESCRIPTOR_TYPE *pCmdDesc)
+{
+ u_int32 uWritePtr;
+
+ uWritePtr = pCmdDesc->wptr + 4;
+ if (uWritePtr >= pCmdDesc->end)
+ uWritePtr = pCmdDesc->start;
+ pCmdDesc->wptr = uWritePtr;
+}
+
+void rpc_send_cmd_buf_encoder(struct shared_addr *This,
+ u_int32 idx,
+ u_int32 cmdid,
+ u_int32 cmdnum,
+ u_int32 *local_cmddata)
+{
+ pENC_RPC_HOST_IFACE pSharedInterface = (pENC_RPC_HOST_IFACE)This->shared_mem_vir;
+ BUFFER_DESCRIPTOR_TYPE *pCmdDesc = &pSharedInterface->StreamCmdBufferDesc;
+ u_int32 *cmddata;
+ u_int32 i;
+ u_int32 *cmdword = (u_int32 *)(This->cmd_mem_vir+pCmdDesc->wptr - pCmdDesc->start);
+
+ *cmdword = 0;
+ *cmdword |= ((idx & 0x000000ff) << 24);
+ *cmdword |= ((cmdnum & 0x000000ff) << 16);
+ *cmdword |= ((cmdid & 0x00003fff) << 0);
+ rpc_update_cmd_buffer_ptr_encoder(pCmdDesc);
+
+ for (i = 0; i < cmdnum; i++) {
+ cmddata = (u_int32 *)(This->cmd_mem_vir+pCmdDesc->wptr - pCmdDesc->start);
+ *cmddata = local_cmddata[i];
+ rpc_update_cmd_buffer_ptr_encoder(pCmdDesc);
+ }
+}
+
+u_int32 rpc_MediaIPFW_Video_message_check_encoder(struct shared_addr *This)
+{
+ u_int32 uSpace;
+ u_int32 uIgnore;
+ pENC_RPC_HOST_IFACE pSharedInterface = (pENC_RPC_HOST_IFACE)This->shared_mem_vir;
+ BUFFER_DESCRIPTOR_TYPE *pMsgDesc = &pSharedInterface->StreamMsgBufferDesc;
+ u_int32 msgword;
+ u_int32 msgnum;
+
+ uSpace = rpc_MediaIPFW_Video_buffer_space_check_encoder(pMsgDesc, TRUE, 0, &uIgnore);
+ uSpace = (uSpace >> 2);
+ if (uSpace) {
+ /* get current msgword word */
+ msgword = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->rptr - pMsgDesc->start));
+ /* Find the number of additional words */
+ msgnum = ((msgword & 0x00ff0000) >> 16);
+
+ /*
+ * * Check the number of message words against
+ * * 1) a limit - some sort of maximum or at least
+ * * the size of the SW buffer the message is read into
+ * * 2) The space reported (where space is write ptr - read ptr in 32bit words)
+ * * It must be less than space (as opposed to <=) because
+ * * the message itself is not included in msgword
+ */
+ if (msgnum < VID_API_MESSAGE_LIMIT) {
+ if (msgnum < uSpace)
+ return API_MSG_AVAILABLE;
+ else
+ return API_MSG_INCOMPLETE;
+ } else
+ return API_MSG_BUFFER_ERROR;
+ }
+ return API_MSG_UNAVAILABLE;
+}
+
+static void rpc_update_msg_buffer_ptr_encoder(BUFFER_DESCRIPTOR_TYPE *pMsgDesc)
+{
+ u_int32 uReadPtr;
+
+ uReadPtr = pMsgDesc->rptr + 4;
+ if (uReadPtr >= pMsgDesc->end)
+ uReadPtr = pMsgDesc->start;
+ pMsgDesc->rptr = uReadPtr;
+}
+
+void rpc_receive_msg_buf_encoder(struct shared_addr *This, struct event_msg *msg)
+{
+ unsigned int i;
+ pENC_RPC_HOST_IFACE pSharedInterface = (pENC_RPC_HOST_IFACE)This->shared_mem_vir;
+ BUFFER_DESCRIPTOR_TYPE *pMsgDesc = &pSharedInterface->StreamMsgBufferDesc;
+ u_int32 msgword = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->rptr - pMsgDesc->start));
+
+ msg->idx = ((msgword & 0xff000000) >> 24);
+ msg->msgnum = ((msgword & 0x00ff0000) >> 16);
+ msg->msgid = ((msgword & 0x00003fff) >> 0);
+ rpc_update_msg_buffer_ptr_encoder(pMsgDesc);
+
+ for (i = 0; i < msg->msgnum; i++) {
+ msg->msgdata[i] = *((u_int32 *)(This->msg_mem_vir+pMsgDesc->rptr - pMsgDesc->start));
+ rpc_update_msg_buffer_ptr_encoder(pMsgDesc);
+ }
+}
diff --git a/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.h b/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.h
new file mode 100644
index 000000000000..515d9ad2f012
--- /dev/null
+++ b/drivers/mxc/vpu-encoder-b0/vpu_encoder_rpc.h
@@ -0,0 +1,114 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2018 NXP. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __VPU_ENCODER_RPC_H__
+#define __VPU_ENCODER_RPC_H__
+
+#include "mediasys_types.h"
+
+#define CMD_SIZE 2560
+#define MSG_SIZE 25600
+#define CODEC_SIZE 0x1000
+#define JPEG_SIZE 0x1000
+#define SEQ_SIZE 0x1000
+#define GOP_SIZE 0x1000
+#define PIC_SIZE 0x1000
+#define QMETER_SIZE 0x1000
+#define DEBUG_SIZE 0x1000
+#define ENG_SIZE 0x1000
+#define LOCAL_MSG_NUM VID_API_MESSAGE_LIMIT
+
+struct shared_addr {
+ pENC_RPC_HOST_IFACE pSharedInterface;
+ unsigned long long shared_mem_phy;
+ void *shared_mem_vir;
+ unsigned long long cmd_mem_phy;
+ void *cmd_mem_vir;
+ unsigned long long msg_mem_phy;
+ void *msg_mem_vir;
+ unsigned long long codec_mem_phy;
+ void *codec_mem_vir;
+ unsigned long long jpeg_mem_phy;
+ void *jpeg_mem_vir;
+ unsigned long long seq_mem_phy;
+ void *seq_mem_vir;
+ unsigned long long pic_mem_phy;
+ void *pic_mem_vir;
+ unsigned long long gop_mem_phy;
+ void *gop_mem_vir;
+ unsigned long long qmeter_mem_phy;
+ void *qmeter_mem_vir;
+ unsigned long long base_offset;
+};
+
+struct event_msg {
+ u_int32 idx;
+ u_int32 msgnum;
+ u_int32 msgid;
+ u_int32 msgdata[LOCAL_MSG_NUM];
+};
+
+void rpc_init_shared_memory_encoder(struct shared_addr *This,
+ unsigned long long base_phy_addr,
+ void *base_virt_addr,
+ u_int32 total_size);
+void rpc_set_system_cfg_value_encoder(void *Interface, u_int32 regs_base, u_int32 core_id);
+void rpc_send_cmd_buf_encoder(struct shared_addr *This,
+ u_int32 idx,
+ u_int32 cmdid,
+ u_int32 cmdnum,
+ u_int32 *local_cmddata);
+void rpc_receive_msg_buf_encoder(struct shared_addr *This, struct event_msg *msg);
+
+#endif
diff --git a/drivers/mxc/vpu-malone/Kconfig b/drivers/mxc/vpu-malone/Kconfig
new file mode 100755
index 000000000000..3ba5c5615219
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Kconfig
@@ -0,0 +1,20 @@
+#
+# Codec configuration
+#
+
+menu "MXC VPU(Video Processing Unit) MALONE support"
+
+config MXC_VPU_MALONE
+ tristate "Support for MXC VPU(Video Processing Unit) MALONE"
+ default y
+ ---help---
+ The VPU codec device provides codec function for H.265/H.264/MPEG4/H.263 etc.
+
+config MXC_VPU_MALONE_DEBUG
+ bool "MXC VPU MALONE debugging"
+ depends on MXC_VPU_MALONE != n
+ help
+ This is an option for the developers; most people should
+ say N here. This enables MXC VPU driver debugging.
+
+endmenu
diff --git a/drivers/mxc/vpu-malone/Makefile b/drivers/mxc/vpu-malone/Makefile
new file mode 100755
index 000000000000..9c46537b6adf
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Makefile
@@ -0,0 +1,197 @@
+#
+# Makefile for VPU driver.
+#
+
+MALONE_ROOT = $(srctree)/drivers/mxc/vpu-malone/Malone_Firmware
+
+#---------------------------------------------------------------------------
+# Header Include Paths
+
+MALONE_KERN_HEADER = \
+ -I$(MALONE_ROOT)/DecKLib/KernelIF \
+ -I$(MALONE_ROOT)/DecKLib/Control \
+ -I$(MALONE_ROOT)/DecKLib/Incl
+
+SYS_HEADER = -I$(MALONE_ROOT)/Incl \
+ -I$(MALONE_ROOT)/PAL/Incl \
+ -I$(srctree)/drivers/mxc/vpu-malone
+
+MALONE_KERN_HEADER += $(SYS_HEADER)
+
+
+#---------------------------------------------------------------------------
+# Actual Source and Library control
+
+MAL_KERN_OBJECTS = \
+ Malone_Firmware/DecKLib/KernelIF/DecKernelLib.o \
+ Malone_Firmware/DecKLib/KernelIF/DecKernelLibPrivate.o \
+ Malone_Firmware/DecKLib/Control/DecKernelLibHWControl.o \
+ Malone_Firmware/DecKLib/Control/DecKernelLibHWIsr.o
+
+MAL_KERN_OBJECTS += Malone_Firmware/PAL/pal.o
+
+#---------------------------------------------------------------------------
+# Build flags
+
+DEFINES = -DDTV_GATHER_PERF_METRICS \
+ -DMVD_DTV_USERDATA \
+ -DMVD_WAIT_BOB_INACTIVE \
+ -DDECLIB_FORCE_HW_STOP \
+ -DMVD_NO_BSDMA_SAFETY_MARGIN \
+ -DMVD_CQ_ENABLE_REFILL \
+ -DMVD_SPP_HW_GOULOMB \
+ -DSVC_SFA_ADD_ERROR_CHECKING \
+ -DMVC_SFA_ADD_ERROR_CHECKING \
+ -DSVC_SPP_SAVE_CTX_PER_VCL_NAL \
+ -DMVD_CQ_CQSR \
+ -DAVC_SUPPORT_THRU_MVC \
+ -DMVC_ERROR_CONTROL_INSERT_SKIP_START_CONTROLS \
+ -DDECLIB_CTX_FLUSH_AFTER_SAVE \
+ -DDECLIB_SERVICE_EOS \
+ -DMVD_PERF_MEASURE \
+ -DVC1_ENABLED \
+ -DHEVC_ENABLED \
+ -DHEVC_CM_WORKAROUND \
+ -DHEVC_NEW_OUTPUT_TRIGGER \
+ -DHEVC_ALL_PICS_REF \
+ -DHEVC_SCAL_LIST_USE_YCRCB_XREF \
+ -DHEVC_SFA_ADD_ERROR_CHECKING \
+ -DMVD_DFE_DBG \
+ -DHEVC_JVT_MODEL=100 \
+ -DPAL_CLOCK_API \
+ -DSVC_ADDITIONAL_DEBUG \
+ -DDIAG_SUPPORT_ENABLED \
+ -DENABLE_PERF_TIMER \
+ -DFW_API_VERSION=19 \
+ -DGLOBAL_USE_RUN_TIME_CFG \
+ -DENABLE_TRACE_IN_RELEASE=0 \
+ -DYES=1 \
+ -DNO=0 \
+ -DNONE=0 \
+ -DNUP=1 \
+ -DUCOS=2 \
+ -DUCOS3=3 \
+ -DRTOS=0 \
+ -DUSE_DECODER \
+ -DARM=0 \
+ -DMIPS=1 \
+ -DX86=2 \
+ -DOR1K=3 \
+ -DCPU=0 \
+ -DNO_AL=0 \
+ -DCNXT_KAL=1 \
+ -DNXP_OSAL=2 \
+ -DOSAL=0 \
+ -DARM926=0 \
+ -DARMR5=1 \
+ -DARMA53=2 \
+ -DARM_CPU_TYPE=2 \
+ -DADS=0 \
+ -DRVDS=1 \
+ -DGNU_MIPS=2 \
+ -DGNU_MIPS_LNX=3 \
+ -DGNU_ARM=4 \
+ -DGNU_ARM_SOURCERY=5 \
+ -DGNU_X86=6 \
+ -DWIN_X86=7 \
+ -DDS5=8 \
+ -DGNU_OR32=9 \
+ -DGNU_ARM_LINARO=10 \
+ -DGNU_OR1K=11 \
+ -DTOOLSET=10 \
+ -DNO_DEBUG=0 \
+ -DBUILD_DEBUG=1 \
+ -DARRAY_DEBUG=2 \
+ -DFULL_DEBUG=3 \
+ -DDEBUG_CAPS=0 \
+ -DGENTB_PLATFORM=0 \
+ -DWIN_LIB=1 \
+ -DGEN_TB_ENC=2 \
+ -DTARGET_PLATFORM=0 \
+ -DVIDEO_TRANS=0 \
+ -DGTB_TRANS=1 \
+ -DGTB_DEC=2 \
+ -DWINDSOR_LIB=3 \
+ -DGTB_ENC=4 \
+ -DMEDIA_DEC=5 \
+ -DMEDIA_LIB=6 \
+ -DVPU_TEST_APP=7 \
+ -DTARGET_APP=7 \
+ -DPAL_CLOCK_API \
+ -DSVC_ADDITIONAL_DEBUG \
+ -DDIAG_SUPPORT_ENABLED \
+ -DENABLE_PERF_TIMER \
+ -DFW_API_VERSION=19 \
+ -DGLOBAL_USE_RUN_TIME_CFG \
+ -DDISABLE_TRACE \
+ -DENABLE_TRACE_IN_RELEASE=0 \
+ -DYES=1 \
+ -DNO=0 \
+ -DNONE=0 \
+ -DNUP=1 \
+ -DUCOS=2 \
+ -DUCOS3=3 \
+ -DRTOS=0 \
+ -DUSE_DECODER \
+ -DCHIP=0 \
+ -DEMULATION=1 \
+ -DHAPS=2 \
+ -DSIMULATION=3 \
+ -DCMODEL=4 \
+ -DTARGET_LEVEL=0 \
+ -DSVC_DISABLED=0 \
+ -DSVC_ENABLED=1 \
+ -DSVC_SUPPORT=0 \
+ -DMVC_DISABLED=0 \
+ -DMVC_ENABLED=1 \
+ -DMVC_SUPPORT=1 \
+ -DSFA_DISABLED=0 \
+ -DSFA_ENABLED=1 \
+ -DSFA_SUPPORT=1 \
+ -DCNXT_HW=0 \
+ -DNXP_HW=1 \
+ -DHWLIB=1 \
+ -DDTV=0 \
+ -DSTB=1 \
+ -DPLAYMODE=0 \
+ -DSTANDARD=0 \
+ -DREBOOT=1 \
+ -DBOOT_ARCH=0 \
+ -DTBPLAYER_FLOW_CHANGE_ON_REF_FRMS \
+ -DPULSAR_MERGE \
+ -DFSLCACHE_ENABLED \
+ -DDECLIB_ENABLE_DFE -DDECLIB_ENABLE_DBE \
+ -DDECLIB_ENABLE_DCP -DMVD_DCP_DYNAMIC_CONFIG \
+ -DDECLIB_4K_SUPPORTED -DHEVC_LEVEL_5PT0_SUPPORT \
+ -DPLAYER_LOCAL_THREAD \
+ -DDECLIB_ISR_IN_THREAD_CTX \
+ -DJPG_ENABLED \
+ -DJPGD_AUTO_DOWN_SCALE \
+ -DSPARK_ENABLED \
+ -DRV_ENABLED \
+ -DVP6_ENABLED \
+ -DVP8_ENABLED \
+ -DJPG_DPV_ENABLED \
+ -DMALONE_64BIT_ADDR \
+ -DDISABLE_TRACE
+
+MALONE_KERN_DEFINEFLAGS = $(DEFINES)
+MALONE_KERN_DEFINEFLAGS += -DVPU_KERNEL_BUILD
+
+EXTRA_CFLAGS += $(MALONE_KERN_DEFINEFLAGS)
+EXTRA_CFLAGS += $(MALONE_KERN_HEADER)
+
+ifeq ($(CONFIG_MXC_VPU_MALONE_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
+obj-$(CONFIG_MXC_VPU_MALONE) = decoder.o
+
+decoder-objs = mxc_vpu-malone.o \
+ $(MAL_KERN_OBJECTS)
+
+cmd_files := $(foreach f,$(decoder-objs),$(dir $(f)).$(notdir $(f)).cmd)
+clean:
+ rm -rf $(decoder-objs) $(cmd_files) *.o .*.cmd modules.builtin modules.order
+
+
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Control/DecKernelLibHWControl.c b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Control/DecKernelLibHWControl.c
new file mode 100755
index 000000000000..7861d545e577
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Control/DecKernelLibHWControl.c
@@ -0,0 +1,326 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+
+ Author : Media IP FW team ( Belfast and Shanghai )
+ File name : DecLibHWControl.c
+ Notes : Processes commands from decoder lib scheduler
+ Establishes context for and makes calls to
+ the base decoders
+ This file provides the hardware facing aspect to
+ the interface. It is part of a group with
+ DecLibStreamControl.c which provides the
+ HW funtionality
+
+ ******************************************************/
+
+/////////////////////////////////////////////////////////////////////////////////
+// Header Files
+/////////////////////////////////////////////////////////////////////////////////
+
+#include "basetype.h"
+#include "mediaip_fw_types.h"
+#include "pal.h"
+
+#include "mvd_types.h"
+#include "mvd_reg_map.h"
+#include "mvd_sif_control.h"
+
+#include "DecKernelLibPrivate.h"
+#include "DecKernelLibHWControl.h"
+
+/////////////////////////////////////////////////////////////////////////////////
+// Extern Function Prototypes
+/////////////////////////////////////////////////////////////////////////////////
+
+extern MEDIAIP_IRQ_RETCODE mvd_kernel_hw_primary_isr ( u_int32 irq_val );
+extern MEDIAIP_IRQ_RETCODE mvd_kernel_hw_secondary_isr ( u_int32 irq_val );
+
+/////////////////////////////////////////////////////////////////////////////////
+// Private Function Prototypes
+/////////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Variables
+/////////////////////////////////////////////////////////////////////////////////;
+
+extern DEC_KERNEL_LIB gDecKernelLib;
+ MALONE_KERNEL_HW_SESSION gMvdKernelHw[(DECODERLIB_MAX_MALONES + 1)];
+ pMALONE_KERNEL_HW_SESSION pgMVDKernelHw;
+
+u_int32 gMaloneList[(DECODERLIB_MAX_MALONES + 1)] = { MALONE_HW_1,
+#if DECODERLIB_MAX_MALONES > 1
+ MALONE_HW_2,
+#endif
+ MALONE_SW };
+
+static u_int32 uSWMaloneRegSpace[2048]; /* Until we are sure we have eliminated register access */
+ /* for functions using the 'SW Malone', point them here */
+
+extern u_int32 uDecLibIrqPin[DECODERLIB_MAX_MALONES][0x2];
+
+/////////////////////////////////////////////////////////////////////////////////
+// Code
+/////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: mvd_kernel_hw_control_init //
+// //
+// DESCRIPTION: Perform all HW initialisation and shared structure setup //
+// //
+// INPUTS: uMaloneID - The ID of the Malone for which the info is to //
+// be restored //
+// pCtxArea - Pointer to area of memory from which data is to be //
+// read //
+// //
+// OUTPUTS: None. //
+// //
+// RETURNS: None. //
+// //
+// NOTES: None. //
+// //
+// CONTEXT: This function must be called from non-interrupt context //
+// //
+////////////////////////////////////////////////////////////////////////////////////
+
+void mvd_kernel_hw_control_init ( DECODERLIB_KERNEL_CFG * pCfg )
+{
+ /* Init the handles */
+ /* This sets up the reg pointers so do it first */
+ mvd_kernel_hw_init_handles ( pCfg,
+ TRUE );
+
+ /* Default global pointers to a 1st Malone focus */
+ mvd_kernel_hw_set_focus ( MALONE_HW_1, &pgMVDKernelHw );
+
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: mvd_kernel_hw_set_malone_instance //
+// //
+// DESCRIPTION: Look for the most appropriate Malone instance to service //
+// the command for a specified stream //
+// //
+// INPUTS: uStrId - The Stream ID //
+// bSWCmd - is the command to be carried out for this stream //
+// capable of being handled without using the HW engine? //
+// uHWIndex - HW Index suggested by scheduler //
+// bUseSch - Set to guarantee scheduler suggested unit is used //
+// //
+// OUTPUTS: None. //
+// //
+// RETURNS: The most suitable Malone ID to be used //
+// //
+// NOTES: This function must return a value. //
+// //
+// CONTEXT: This function must be called from non-interrupt context //
+// //
+////////////////////////////////////////////////////////////////////////////////////
+
+u_int32 mvd_kernel_hw_set_malone_instance ( u_int32 uStrId,
+ bool bSWCmd,
+ u_int32 uHWIndex,
+ bool bUseSch
+ )
+{
+ u_int32 uIdx = 0;
+
+ if ( bUseSch )
+ {
+ return uHWIndex;
+ }
+
+ for ( uIdx = 0; uIdx < gDecKernelLib.uNumMalones; uIdx++ )
+ {
+ /* Even if there is no command active, this is a valid check as */
+ /* it avoids need for a context change if it matches */
+ if ( gMvdKernelHw[uIdx].uStrID == uStrId )
+ {
+ return uIdx;
+ }
+ }
+
+ if ( bSWCmd ) return MALONE_SW;
+
+ /* Look for free Malone - this function should not be called */
+ /* unless this is a SW command or there is a free Malone */
+
+ for ( uIdx = 0; uIdx < gDecKernelLib.uNumMalones; uIdx++ )
+ {
+ /* Even if there is no command active, this is a valid check as */
+ /* it avoids need for a context change if it matches */
+ if ( gMvdKernelHw[uIdx].eState == MALONE_INACTIVE )
+ {
+ break;
+ }
+ }
+
+ /* Do not assign this stream and do NOT make it active yet */
+ /* Only make this malone active when the command is issued */
+ /* This is necessary so we we can trigger context switches */
+
+ /* We should set the global pointer though so calls to sif */
+ /* etc can get correct functions!! */
+
+ mvd_kernel_hw_set_focus ( uIdx, &pgMVDKernelHw );
+
+ return uIdx;
+
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: mvd_kernel_hw_set_focus //
+// //
+// DESCRIPTION: Changes focus to the selected Malone HW unit //
+// //
+// INPUTS: uMaloneID - The ID of the Malone //
+// //
+// OUTPUTS: ppMVDHw - Pointer to a HW session structure for the specified //
+// Malone //
+// //
+// RETURNS: None. //
+// //
+// NOTES: Only makes sense in multi-malone configs //
+// //
+// CONTEXT: This function may be called from any context //
+// //
+////////////////////////////////////////////////////////////////////////////////////
+
+void mvd_kernel_hw_set_focus ( u_int32 uMaloneID, pMALONE_KERNEL_HW_SESSION * ppMVDHw )
+{
+ *ppMVDHw = ( MALONE_KERNEL_HW_SESSION * )&gMvdKernelHw[uMaloneID];
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: mvd_kernel_hw_init_handles //
+// //
+// DESCRIPTION: Initialise the HW session handles //
+// //
+// INPUTS: pCfg - A pointer to the DecLib Config structure //
+// bSoftInit - If set, the FW pointers get established - leave //
+// FALSE when restarting from a snapshot //
+// //
+// OUTPUTS: None. //
+// //
+// RETURNS: None. //
+// //
+// NOTES: None. //
+// //
+// CONTEXT: This function must be called from non-interrupt context //
+// //
+////////////////////////////////////////////////////////////////////////////////////
+
+void mvd_kernel_hw_init_handles ( DECODERLIB_KERNEL_CFG * pCfg,
+ bool bSoftInit
+ )
+{
+ u_int32 uIdx;
+ pMALONE_KERNEL_HW_SESSION pMVDHw;
+ MvdHwRegMap *pMvdReg;
+
+ for ( uIdx = 0; uIdx < (gDecKernelLib.uNumMalones + 1); uIdx++ )
+ {
+ /* If we have set up all the HW handles then move to the SW */
+ /* handle and set it up */
+ if ( uIdx == gDecKernelLib.uNumMalones ) uIdx = DECODERLIB_MAX_MALONES;
+
+ pMVDHw = &gMvdKernelHw[uIdx];
+
+ if ( bSoftInit )
+ {
+ pMVDHw->eState = MALONE_INACTIVE;
+ pMVDHw->uStrID = 0;
+ pMVDHw->uForceFIQ = 0;
+ pMVDHw->uForceDFEFIQ = 0;
+
+ /* Malone ID that the instance uses, normally fixed... */
+ pMVDHw->uMaloneID = gMaloneList[uIdx];
+ }
+
+ if ( pMVDHw->uMaloneID == DECODERLIB_MAX_MALONES )
+ {
+ pMvdReg = ( MvdHwRegMap * )uSWMaloneRegSpace;
+ }
+ else if ( pMVDHw->uMaloneID == MALONE_HW_2 )
+ {
+ pMvdReg = ( MvdHwRegMap * ) ( pCfg->uMaloneBaseAddr[0x1] + pCfg->uMaloneHifOffset[0x1] );
+ }
+ else
+ {
+ pMvdReg = ( MvdHwRegMap * ) ( pCfg->uMaloneBaseAddr[0x0] + pCfg->uMaloneHifOffset[0x0] );
+ }
+
+ if ( pMVDHw->uMaloneID == MALONE_SW )
+ {
+ pMVDHw->msd_regp = ( MvdHwRegMap * )pMvdReg;
+ pMVDHw->hif_regp = ( MvdHwRegHifMap * )pMvdReg;
+ pMVDHw->sif_regp = ( MvdHwRegSifMap * )pMvdReg;
+ pMVDHw->ctx_regp = ( MvdHwRegCtxMap * )pMvdReg;
+ pMVDHw->rsb_regp = ( MvdHwReg * )pMvdReg;
+ pMVDHw->rpr_regp = ( MvdHwRegRprMap * )pMvdReg;
+ pMVDHw->spp_regp = ( MvdHwRegSppMap * )pMvdReg;
+ pMVDHw->avc_regp = ( MvdHwRegH264Map * )pMvdReg;
+ pMVDHw->mp2d_regp = ( MvdHwRegMp2dMap * )pMvdReg;
+ pMVDHw->avsd_regp = ( MvdHwRegAvsdMap * )pMvdReg;
+ pMVDHw->aspd_regp = ( MvdHwRegAspdMap * )pMvdReg;
+ pMVDHw->vc1d_regp = ( MvdHwRegVc1dMap * )pMvdReg;
+ pMVDHw->jpgd_regp = ( MvdHwRegAspdMap * )pMvdReg;
+ pMVDHw->rvid_regp = ( MvdHwRegRvidMap * )pMvdReg;
+ pMVDHw->hevc_regp = ( MvdHwRegHevcMap * )pMvdReg;
+ pMVDHw->on2d_regp = ( MvdHwRegOn2dMap * )pMvdReg;
+ pMVDHw->cq_regp = ( MvdHwRegCqMap * )pMvdReg;
+ pMVDHw->rc4_regp = ( MvdHwRegRC4Map * )pMvdReg;
+ pMVDHw->dfe_regp = ( MvdHwRegDfeMap * )pMvdReg;
+ pMVDHw->dbe_regp[0x0] = ( MvdHwRegDbeMap * )pMvdReg;
+ pMVDHw->dbe_regp[0x1] = ( MvdHwRegDbeMap * )pMvdReg;
+
+ }
+ else
+ {
+ pMVDHw->msd_regp = pMvdReg;
+ pMVDHw->hif_regp = &( pMvdReg->HifMap.hif_map );
+ pMVDHw->sif_regp = &( pMvdReg->SifMap.sif_map );
+ pMVDHw->ctx_regp = &( pMvdReg->CtxMap.ctx_map );
+ pMVDHw->rpr_regp = &( pMvdReg->RprMap.rpr_map );
+ pMVDHw->spp_regp = &( pMvdReg->SppMap.spp_map );
+ pMVDHw->avc_regp = &( pMvdReg->DecMap.h264_map );
+ pMVDHw->mp2d_regp = &( pMvdReg->DecMap.mp2d_map );
+ pMVDHw->aspd_regp = &( pMvdReg->DecMap.aspd_map );
+ pMVDHw->avsd_regp = &( pMvdReg->DecMap.avsd_map );
+ pMVDHw->vc1d_regp = &( pMvdReg->DecMap.vc1d_map );
+ pMVDHw->jpgd_regp = &( pMvdReg->DecMap.aspd_map );
+ pMVDHw->on2d_regp = &( pMvdReg->DecMap.on2d_map );
+ pMVDHw->rvid_regp = &( pMvdReg->DecMap.rvid_map );
+ pMVDHw->hevc_regp = &( pMvdReg->DecMap.hevc_map );
+ pMVDHw->bbd_regp = &( pMvdReg->BbdMap.bbd_map );
+ pMVDHw->cq_regp = &( pMvdReg->CqMap.cq_map );
+ pMVDHw->rc4_regp = &( pMvdReg->RC4Map.RC4_map );
+ pMVDHw->dfe_regp = &( pMvdReg->DcpMap.dfe_map );
+ pMVDHw->dbe_regp[0x0] = &( pMvdReg->DcpMap.dbe_map[0x0] );
+ pMVDHw->dbe_regp[0x1] = &( pMvdReg->DcpMap.dbe_map[0x1] );
+
+ if ( pMVDHw->uMaloneID == MALONE_HW_2 )
+ {
+ pMVDHw->rsb_regp = ( MvdHwReg * ) pCfg->uMaloneBaseAddr[0x1] ;
+ }
+ else
+ {
+ pMVDHw->rsb_regp = ( MvdHwReg * ) pCfg->uMaloneBaseAddr[0x0] ;
+ }
+ }
+ }
+}
+
+/* End of File */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Control/DecKernelLibHWControl.h b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Control/DecKernelLibHWControl.h
new file mode 100755
index 000000000000..4ef9b0f0b08e
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Control/DecKernelLibHWControl.h
@@ -0,0 +1,175 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+
+ Filename: DecLibHWControl.h
+ Description:
+
+ **************************************************/
+
+/////////////////////////////////////////////////////////////////////////////////
+// Header files
+/////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _DECODER_LIB_HW_CONTROL_H_
+#define _DECODER_LIB_HW_CONTROL_H_
+
+#include "mvd_types.h"
+#include "mvd_reg_map.h"
+#include "DecKernelLib.h"
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Macros
+/////////////////////////////////////////////////////////////////////////////////
+
+#define MALONE_HW_1 0 /* Identifiers for the Malone units */
+#define MALONE_HW_2 1
+#define MALONE_SW DECODERLIB_MAX_MALONES /* Sw Malone does not exist! Simply a */
+ /* control structure for carrying out */
+ /* commands which do not need a HW unit */
+#define MALONE_SW_IRQ 0xdeaf
+
+#define DECODERLIB_ISR_QU_SIZE ( DECODERLIB_MAX_MALONES * 4 )
+#define DECODERLIB_SECONDARY_ISR_EVENT 0x80000000
+#define DECODERLIB_EVENT_MASK 0x7FFFFFFF
+
+#define DECODERLIB_FORCEIRQ_BIT_SET( uVal ) (( uVal & 0x1 ) << 30 )
+#define DECODERLIB_FORCEIRQ_BIT_GET( uVal ) (( uVal >> 30 ) & 0x1 )
+#define DECODERLIB_FORCEDFEIRQ_BIT_SET( uVal ) (( uVal & 0x1 ) << 29 )
+#define DECODERLIB_FORCEDFEIRQ_BIT_GET( uVal ) (( uVal >> 29 ) & 0x1 )
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Types
+/////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////
+// Decoder Library HW State
+
+typedef enum
+{
+ MALONE_INACTIVE = 0,
+ MALONE_ACTIVE,
+ MALONE_BE_ACTIVE
+
+} MALONE_STATE;
+
+//////////////////////////////////////////////////////////////
+// Decoder Library HW Control Context Info
+
+typedef struct
+{
+
+ MALONE_STATE eState;
+ u_int32 uStrID;
+
+ u_int32 uForceFIQ;
+ u_int32 uForceDFEFIQ;
+ u_int32 uChipVer; /* Hold "malone" version to be filled in from Malone HW register */
+ u_int32 uChipMnrVer; /* Hold "malone" minor version to be filled in from Malone HW register */
+ u_int32 uChipSubVer; /* Hold metal version to be filled in by higher level control */
+ u_int32 uHWFeatures;
+ u_int32 uForceCacheFlush; /* Cache reset issue workaround purpose for Kronos and Fusion RevA */
+ u_int32 bPreparser; /* Set TRUE to indicate a preparser is in place */
+ u_int32 bCQ; /* Set TRUE to indicate a command queue is in place */
+ u_int32 bDCP; /* Set TRUE to indicate unit can operate in decoupled mode */
+ u_int32 uNumDBEs; /* Indicates the number of decoupled back ends available */
+ u_int32 bFBC; /* Set TRUE to indicate Frame buffer Compression support */
+ u_int32 uRSBSize;
+ u_int32 uMaloneID;
+ u_int32 bPixIf;
+ u_int32 bXBUS;
+
+ u_int32 uCQProcType[DECODERLIB_MAX_CQ_PER_MALONE]; /* Specifies what type of processing each of the CQ units is doing */
+
+ MALONE_STATE eDFEState; /* If the front end of the HW is active in isolation - specifies state */
+ u_int8 usDFEStrID; /* If the front end of the HW is active in isolation - specifies */
+ /* which stream is assigned */
+
+ u_int32 uDmaMemSize;
+ void * pDmaMemArea;
+
+ MvdHwRegMap * msd_regp;
+ MvdHwRegHifMap * hif_regp;
+ MvdHwRegSifMap * sif_regp;
+ MvdHwRegCtxMap * ctx_regp;
+ MvdHwReg * rsb_regp;
+ MvdHwRegRprMap * rpr_regp;
+ MvdHwRegSppMap * spp_regp;
+ MvdHwRegH264Map * avc_regp;
+ MvdHwRegMp2dMap * mp2d_regp;
+ MvdHwRegAvsdMap * avsd_regp;
+ MvdHwRegAspdMap * aspd_regp;
+ MvdHwRegVc1dMap * vc1d_regp;
+ MvdHwRegAspdMap * jpgd_regp;
+ MvdHwRegOn2dMap * on2d_regp;
+ MvdHwRegRvidMap * rvid_regp;
+ MvdHwRegHevcMap * hevc_regp;
+ MvdHwRegBbdMap * bbd_regp;
+ MvdHwRegDbgMap * dbg_regp;
+ MvdHwRegCqMap * cq_regp;
+ MvdHwRegRC4Map * rc4_regp;
+ MvdHwRegDfeMap * dfe_regp;
+ MvdHwRegDbeMap * dbe_regp[DECODERLIB_MAX_DBE_UNITS];
+
+} MALONE_KERNEL_HW_SESSION, *pMALONE_KERNEL_HW_SESSION;
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Function definitions
+/////////////////////////////////////////////////////////////////////////////////
+
+
+void mvd_kernel_hw_control_init ( DECODERLIB_KERNEL_CFG * pCfg );
+
+////////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: mvd_kernel_hw_set_focus //
+// //
+// DESCRIPTION: Changes focus to the selected Malone HW unit //
+// //
+// INPUTS: uMaloneID - The ID of the Malone //
+// //
+// OUTPUTS: ppMVDHw - Pointer to a HW session structure for the specified //
+// Malone //
+// //
+// RETURNS: None. //
+// //
+// NOTES: Only makes sense in multi-malone configs //
+// //
+// CONTEXT: This function may be called from any context //
+// //
+////////////////////////////////////////////////////////////////////////////////////
+
+void mvd_kernel_hw_set_focus ( u_int32 uMaloneID, pMALONE_KERNEL_HW_SESSION * ppMVDHw );
+
+////////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: mvd_kernel_hw_init_handles //
+// //
+// DESCRIPTION: Initialise the HW session handles //
+// //
+// INPUTS: pCfg - A pointer to the DecLib Config structure //
+// bSoftInit - If set, the FW pointers get established - leave //
+// FALSE when restarting from a snapshot //
+// //
+// OUTPUTS: None. //
+// //
+// RETURNS: None. //
+// //
+// NOTES: None. //
+// //
+// CONTEXT: This function must be called from non-interrupt context //
+// //
+////////////////////////////////////////////////////////////////////////////////////
+
+void mvd_kernel_hw_init_handles ( DECODERLIB_KERNEL_CFG * pCfg,
+ bool bSoftInit );
+
+#endif /* _DECODER_LIB_HW_CONTROL_H_ */
+
+/* End of file */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Control/DecKernelLibHWIsr.c b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Control/DecKernelLibHWIsr.c
new file mode 100755
index 000000000000..68b33384c769
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Control/DecKernelLibHWIsr.c
@@ -0,0 +1,514 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+
+ File name : DecLibHWIsr.c
+ Notes : Provides the HW Interrupt Service Routines
+
+ *******************************************************/
+
+/////////////////////////////////////////////////////////////////////////////////
+// Header Files
+/////////////////////////////////////////////////////////////////////////////////
+
+#include "basetype.h"
+#include "mediaip_fw_types.h"
+#include "pal.h"
+
+#include "mvd.h"
+#include "mvd_types.h"
+#include "mvd_reg_map.h"
+#include "mvd_sif_control.h"
+
+#include "DecKernelLibHWControl.h"
+#include "DecKernelLibPrivate.h"
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Variables
+/////////////////////////////////////////////////////////////////////////////////
+
+extern pMALONE_KERNEL_HW_SESSION pgMVDKernelHw;
+extern u_int32 uMvdKernelIrqPin[DECODERLIB_MAX_MALONES][0x2];
+extern DEC_KERNEL_LIB gDecKernelLib;
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Macros
+/////////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////////
+// Private Prototypes
+/////////////////////////////////////////////////////////////////////////////////
+
+void mvd_kernel_hw_isr_event ( u_int32 uMaloneIdx,
+ u_int32 * puIrqStatus );
+
+/////////////////////////////////////////////////////////////////////////////////
+// Extern Prototypes
+/////////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////////
+// Code
+/////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: mvd_hw_sesh_isr //
+// //
+// DESCRIPTION: Malone HW ISR //
+// //
+// INPUTS: irq_val - Identification Parameter from which source of call //
+// may be ascertained //
+// //
+// OUTPUTS: None. //
+// //
+// RETURNS: MEDIAIP_IRQ_RETCODE //
+// //
+// NOTES: None. //
+// //
+// CONTEXT: This function may be called from any context //
+// Since it is an isr, that may be strange but it can be called to //
+// handle SW commands in thread context only //
+// //
+////////////////////////////////////////////////////////////////////////////////////
+
+#define CTX_DBG(x)
+
+MEDIAIP_IRQ_RETCODE mvd_kernel_hw_primary_isr ( u_int32 irq_val )
+{
+ u_int32 sif_irq_status[0x3] = { 0x0 };
+ u_int32 uActMaloneID;
+#if ( TARGET_APP == GTB_DEC ) || ( TARGET_APP == MEDIA_DEC ) || ( TARGET_APP == VIDEO_TRANS ) || ( TARGET_APP == GTB_TRANS )
+ u_int32 uIrqTarget0, uIrqTarget1;
+#endif
+ u_int32 uForceFIQ = 0, uForceDFEFIQ = 0;
+ u_int32 uHEVCActive;
+
+ /* Future Proof... */
+ /* If we have two levels of interrupt or we process interrupts in thread context */
+ /* we need to save and restore HW focus */
+ pMALONE_KERNEL_HW_SESSION pLocMVDHw = pgMVDKernelHw;
+
+ /* Work out which Malone instance caused this isr and set HW focus accordingly */
+
+#if ( TARGET_APP == GTB_DEC ) || ( TARGET_APP == MEDIA_DEC ) || ( TARGET_APP == VIDEO_TRANS ) || ( TARGET_APP == GTB_TRANS )
+
+ pal_int_get_irq_line ( uMvdKernelIrqPin[0x0][0x0],
+ &uIrqTarget0
+ );
+ pal_int_get_irq_line ( uMvdKernelIrqPin[0x0][0x1],
+ &uIrqTarget1
+ );
+
+ uActMaloneID = ( irq_val == MALONE_SW_IRQ ) ? MALONE_SW :
+ (( irq_val == uIrqTarget0 ) | ( irq_val == uIrqTarget1 )) ? MALONE_HW_1 :
+ MALONE_HW_2;
+
+#else
+
+ uActMaloneID = ( irq_val == MALONE_SW_IRQ ) ? MALONE_SW :
+ (( irq_val == uMvdKernelIrqPin[0x0][0x0] ) | ( irq_val == uMvdKernelIrqPin[0x0][0x1] )) ? MALONE_HW_1 :
+ MALONE_HW_2;
+
+#endif
+
+ mvd_kernel_hw_set_focus ( uActMaloneID, &pgMVDKernelHw );
+
+ /* work out if HEVC active, as if not we don't care about irq_status3 DBE*/
+ MVD_REG_READ( pgMVDKernelHw, DECLIB_DBG_REG_CTX, pgMVDKernelHw->ctx_regp->ctx_status, uHEVCActive );
+
+ if(uHEVCActive&0x400)
+ uHEVCActive = 1;
+ else
+ uHEVCActive = 0;
+
+
+
+#if 1
+ MVD_REG_READ( pgMVDKernelHw, DECLIB_DBG_REG_SIF, pgMVDKernelHw->sif_regp->msd_data0_reg, uForceFIQ );
+ MVD_REG_READ( pgMVDKernelHw, DECLIB_DBG_REG_SIF, pgMVDKernelHw->sif_regp->msd_data1_reg, uForceDFEFIQ );
+
+ if ( uForceFIQ )
+ {
+ MVD_REG_WRITE( pgMVDKernelHw, DECLIB_DBG_REG_SIF, pgMVDKernelHw->sif_regp->msd_data0_reg, 0 );
+ }
+
+ if ( uForceDFEFIQ )
+ {
+ MVD_REG_WRITE( pgMVDKernelHw, DECLIB_DBG_REG_SIF, pgMVDKernelHw->sif_regp->msd_data1_reg, 0 );
+ }
+#else
+ MVD_REG_READ( pgMVDKernelHw, DECLIB_DBG_REG_SIF, pgMVDKernelHw->sif_regp->msd_data0_reg, uData );
+
+ MVD_REG_WRITE( pgMVDKernelHw, DECLIB_DBG_REG_SIF, pgMVDKernelHw->sif_regp->msd_data0_reg, 0 );
+
+ uForceFIQ = ( uData & 0x1 ) ? 1 : 0;
+ uForceDFEFIQ = ( uData & 0x2 ) ? 1 : 0;
+#endif
+
+ if ( uActMaloneID != MALONE_SW )
+ {
+ u_int32 uClearVal;
+
+ /* Break down sif IRQ sources */
+ MVD_REG_READ( pgMVDKernelHw, DECLIB_DBG_REG_SIF, pgMVDKernelHw->sif_regp->intr_status, sif_irq_status[0x0] );
+ MVD_REG_READ( pgMVDKernelHw, DECLIB_DBG_REG_SIF, pgMVDKernelHw->sif_regp->intr2_status, sif_irq_status[0x1] );
+ MVD_REG_READ( pgMVDKernelHw, DECLIB_DBG_REG_SIF, pgMVDKernelHw->sif_regp->intr3_status, sif_irq_status[0x2] );
+
+ pal_trace( DECODER_TL_INFO, "mvd_kernel_hw_primary_isr(%d): opening sif_irq_status = 0x%x\n", irq_val, sif_irq_status[0x0]);
+ pal_trace( DECODER_TL_INFO, "mvd_kernel_hw_primary_isr(%d): opening sif_irq_status[0x1] = 0x%x\n", irq_val, sif_irq_status[0x1]);
+ pal_trace( DECODER_TL_INFO, "mvd_kernel_hw_primary_isr(%d): opening sif_irq_status[0x2] = 0x%x\n", irq_val, sif_irq_status[0x2]);
+
+ /* Clear the interrupt bits we're going to handle here */
+
+#ifdef FW_PES_PARSE_AS_FIQ
+
+ uClearVal = sif_irq_status[0x0] & ( MSD_SIF_INTR_BSDMA_BIT |
+ MSD_SIF_INTR_FORCE_EXIT_BIT |
+ MSD_SIF_INTR_DISPQ_PULL_BIT |
+ MSD_SIF_INTR_SEMAPHORE_BIT |
+ MSD_SIF_INTR_IMAGE_DONE_BIT |
+ MSD_SIF_INTR_SLICE_DONE_BIT |
+ MSD_SIF_INTR_FORCE_ENTRY_BIT
+ );
+
+ MVD_REG_WRITE( pgMVDKernelHw, DECLIB_DBG_REG_SIF, pgMVDKernelHw->sif_regp->intr_status, uClearVal );
+
+#else
+
+ uClearVal = sif_irq_status[0x0] & ( MSD_SIF_INTR_BSDMA_BIT |
+ MSD_SIF_INTR_PES_BIT |
+ MSD_SIF_INTR_SCODE_FOUND_BIT |
+ MSD_SIF_INTR_DISPQ_PULL_BIT |
+ MSD_SIF_INTR_SEMAPHORE_BIT |
+ MSD_SIF_INTR_IMAGE_DONE_BIT |
+ MSD_SIF_INTR_SLICE_DONE_BIT |
+ MSD_SIF_INTR_FORCE_ENTRY_BIT
+ );
+
+ MVD_REG_WRITE( pgMVDKernelHw, DECLIB_DBG_REG_SIF, pgMVDKernelHw->sif_regp->intr_status, uClearVal );
+
+#endif /* FW_PES_PARSE_AS_FIQ */
+
+ /* Read it back to ensure write has made it to Malone */
+ MVD_REG_READ( pgMVDKernelHw, DECLIB_DBG_REG_SIF, pgMVDKernelHw->sif_regp->intr_status, uClearVal );
+
+ /* Also re-clear the INTC bit which brought us in here since */
+ /* it will have been reset. */
+ pal_int_clear ( irq_val,
+ TRUE
+ );
+
+#ifdef FW_PARSE_PES
+#ifdef FW_PES_PARSE_AS_FIQ
+
+ /* Pes FW handling done at higher level */
+ /* Re-maps the force-exit ISR as the startcode */
+
+ /* TODO-KMC */
+ /* Does this mean a normal engine startcode is mapped as a force-exit? I guess it does */
+ /* So if we were parsing PES as an FIQ we would not actually be in this function if it */
+ /* were a PES startcode and so the below event must be a normal startcode? */
+
+ if ( sif_irq_status[0x0] & MSD_SIF_INTR_FORCE_EXIT_BIT )
+ {
+ sif_irq_status[0x0] |= MSD_SIF_INTR_SCODE_FOUND_BIT;
+ }
+#else
+ /* PES isr */
+ if ( sif_irq_status[0x0] & MSD_SIF_INTR_SCODE_FOUND_BIT )
+ {
+ u_int32 scode_status;
+
+ MVD_REG_READ( pgMVDKernelHw, DECLIB_DBG_REG_SIF, pgMVDKernelHw->sif_regp->bs2rbsp_status, scode_status );
+
+ if ( scode_status & MSD_SIF_BS2RBSP_GOT_PESSCODE )
+ {
+ sesh_pes_isr ( irq_val );
+ }
+
+ /* If it was just a PES startcode, then don't tell the engine */
+ /* that there was a startcode, as will get handled later */
+ if (( scode_status & MSD_SIF_BS2RBSP_GOT_SCODE ) == 0 )
+ {
+ sif_irq_status[0x0] &= ~(MSD_SIF_INTR_SCODE_FOUND_BIT);
+ }
+ }
+#endif
+#endif
+
+ if ( sif_irq_status[0x1] & ( MSD_SIF_INTR2_CSC_BIT ) )
+ {
+ MVD_REG_WRITE( pgMVDKernelHw, 0x0 /*DECLIB_DBG_REG_SIF*/, pgMVDKernelHw->sif_regp->intr2_status, sif_irq_status[0x1] & ( MSD_SIF_INTR2_CSC_BIT ) );
+ }
+
+ if ( sif_irq_status[0x1] & ( MSD_SIF_INTR2_CQ_BIT ) )
+ {
+ MVD_REG_WRITE( pgMVDKernelHw, 0x0 /*DECLIB_DBG_REG_SIF*/, pgMVDKernelHw->sif_regp->intr2_status, sif_irq_status[0x1] & ( MSD_SIF_INTR2_CQ_BIT ) );
+ }
+
+ if ( sif_irq_status[0x1] & ( MSD_SIF_INTR2_DFE_DONE_BIT ) )
+ {
+ MVD_REG_WRITE( pgMVDKernelHw, 0x0 /*DECLIB_DBG_REG_SIF*/, pgMVDKernelHw->sif_regp->intr2_status, sif_irq_status[0x1] & ( MSD_SIF_INTR2_DFE_DONE_BIT ) );
+ MVD_REG_WRITE( pgMVDKernelHw, 0x0 /*DECLIB_DBG_REG_SIF*/, pgMVDKernelHw->sif_regp->intr2_status, sif_irq_status[0x1] & ( MSD_SIF_INTR2_DFE_SLC_DONE_BIT ) );
+ }
+
+ if ( sif_irq_status[0x1] & MSD_SIF_INTR2_DFE_SLC_DONE_BIT )
+ {
+ MVD_REG_WRITE( pgMVDKernelHw, 0x0 /*DECLIB_DBG_REG_SIF*/, pgMVDKernelHw->sif_regp->intr2_status, sif_irq_status[0x1] & ( MSD_SIF_INTR2_DFE_SLC_DONE_BIT ) );
+ }
+
+ if ( sif_irq_status[0x2] & MSD_SIF_INTR3_DBE0_CQ_BIT )
+ {
+ MVD_REG_WRITE( pgMVDKernelHw, 0x0 /*DECLIB_DBG_REG_SIF*/, pgMVDKernelHw->sif_regp->intr3_status, sif_irq_status[0x2] & ( MSD_SIF_INTR3_DBE0_CQ_BIT ) );
+ }
+
+ if ( sif_irq_status[0x2] & MSD_SIF_INTR3_DBE1_CQ_BIT )
+ {
+ MVD_REG_WRITE( pgMVDKernelHw, 0x0 /*DECLIB_DBG_REG_SIF*/, pgMVDKernelHw->sif_regp->intr3_status, sif_irq_status[0x2] & ( MSD_SIF_INTR3_DBE1_CQ_BIT ) );
+ }
+
+ if ( sif_irq_status[0x2] &
+ ( MSD_SIF_INTR3_DBE0_DONE_BIT | MSD_SIF_INTR3_DBE1_DONE_BIT )
+ )
+ {
+ u_int32 uMask = ( MSD_SIF_INTR3_DBE0_DONE_BIT |
+ MSD_SIF_INTR3_DBE1_DONE_BIT );
+
+ if (( sif_irq_status[0x0] & MSD_SIF_INTR_IMAGE_DONE_BIT )||(uHEVCActive==0))
+ {
+ MVD_REG_WRITE( pgMVDKernelHw, 0x0 /*DECLIB_DBG_REG_SIF*/, pgMVDKernelHw->sif_regp->intr3_status, sif_irq_status[0x2] & uMask );
+ }
+ else
+ {
+ sif_irq_status[0x2] &= ~uMask;
+ }
+ }
+
+ if ( sif_irq_status[0x2] &
+ ( MSD_SIF_INTR3_DBE0_SLC_DONE_BIT | MSD_SIF_INTR3_DBE1_SLC_DONE_BIT )
+ )
+ {
+ u_int32 uMask = ( MSD_SIF_INTR3_DBE0_SLC_DONE_BIT |
+ MSD_SIF_INTR3_DBE1_SLC_DONE_BIT );
+
+ if (( sif_irq_status[0x0] & MSD_SIF_INTR_SLICE_DONE_BIT )|| (uHEVCActive==0))
+ {
+ MVD_REG_WRITE( pgMVDKernelHw, 0x0 /*DECLIB_DBG_REG_SIF*/, pgMVDKernelHw->sif_regp->intr3_status, sif_irq_status[0x2] & uMask );
+ }
+ else
+ {
+ sif_irq_status[0x2] &= ~uMask;
+ }
+ }
+ }
+ else /* We wish to process a command without accessing HW */
+ {
+ sif_irq_status[0x0] = 0;
+ }
+
+ pal_trace( DECODER_TL_DEBUG, "-> mvd_kernel_hw_primary_isr( ) : uForceFIQ = 0x%x\n", uForceFIQ );
+
+ /* Decode engine IRQs */
+ if (( uActMaloneID == MALONE_SW ) ||
+ ( uForceFIQ ) ||
+ ( uForceDFEFIQ ) ||
+ ( sif_irq_status[0x0] & ( MSD_SIF_INTR_IMAGE_DONE_BIT | MSD_SIF_INTR_SLICE_DONE_BIT | MSD_SIF_INTR_SCODE_FOUND_BIT | MSD_SIF_INTR_FORCE_ENTRY_BIT | MSD_SIF_INTR_BSDMA_BIT )) ||
+ ( sif_irq_status[0x1] & ( MSD_SIF_INTR2_CSC_BIT | MSD_SIF_INTR2_DFE_DONE_BIT | MSD_SIF_INTR2_DFE_SLC_DONE_BIT | MSD_SIF_INTR2_CQ_BIT )) ||
+ ( sif_irq_status[0x2] & ( MSD_SIF_INTR3_DBE0_DONE_BIT | MSD_SIF_INTR3_DBE1_DONE_BIT | MSD_SIF_INTR3_DBE0_SLC_DONE_BIT | MSD_SIF_INTR3_DBE1_SLC_DONE_BIT | MSD_SIF_INTR3_DBE0_CQ_BIT | MSD_SIF_INTR3_DBE1_CQ_BIT ))
+ )
+ {
+ pal_trace ( DECODER_TL_DEBUG,
+ "-> mvd_kernel_hw_primary_isr( ) : sif_irq_status[0x0] = 0x%x : sif_irq_status[0x1] = 0x%x : sif_irq_status[0x2] = 0x%x : uForceFIQ = 0x%x\n",
+ sif_irq_status[0x0],
+ sif_irq_status[0x1],
+ sif_irq_status[0x2],
+ uForceFIQ
+ );
+
+ /* Only pass events not serviced inline in this isr */
+
+ sif_irq_status[0x0] &= ( MSD_SIF_INTR_IMAGE_DONE_BIT | MSD_SIF_INTR_SLICE_DONE_BIT | MSD_SIF_INTR_SCODE_FOUND_BIT | MSD_SIF_INTR_FORCE_ENTRY_BIT | MSD_SIF_INTR_BSDMA_BIT );
+ sif_irq_status[0x1] &= ( MSD_SIF_INTR2_CSC_BIT | MSD_SIF_INTR2_DFE_DONE_BIT | MSD_SIF_INTR2_DFE_SLC_DONE_BIT | MSD_SIF_INTR2_CQ_BIT);
+ sif_irq_status[0x2] &= ( MSD_SIF_INTR3_DBE0_DONE_BIT | MSD_SIF_INTR3_DBE1_DONE_BIT | MSD_SIF_INTR3_DBE0_SLC_DONE_BIT | MSD_SIF_INTR3_DBE1_SLC_DONE_BIT | MSD_SIF_INTR3_DBE0_CQ_BIT | MSD_SIF_INTR3_DBE1_CQ_BIT );
+
+ /* When passing to thread - explicitly set that a force irq has been set */
+ /* so that the thread function knows after which interrupt it can reset */
+ /* pMVDHw->uForceFIQ */
+
+ sif_irq_status[0x0] |= DECODERLIB_FORCEIRQ_BIT_SET( uForceFIQ );
+ sif_irq_status[0x0] |= DECODERLIB_FORCEDFEIRQ_BIT_SET( uForceDFEFIQ );
+
+ if (( sif_irq_status[0x0] ) ||
+ ( sif_irq_status[0x1] ) ||
+ ( sif_irq_status[0x2] )
+ )
+ {
+ mvd_kernel_hw_isr_event ( uActMaloneID,
+ sif_irq_status );
+ }
+ }
+
+ /* Future Proof - Restore pgMVDKernelHw */
+ pgMVDKernelHw = pLocMVDHw;
+
+ return MEDIAIP_FW_STATUS_OK;
+
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: mvd_kernel_hw_secondary_isr //
+// //
+// DESCRIPTION: Malone HW ISR 2 //
+// //
+// INPUTS: irq_val - Identification Parameter from which source of call //
+// may be ascertained //
+// //
+// OUTPUTS: None. //
+// //
+// RETURNS: MEDIAIP_IRQ_RETCODE //
+// //
+// NOTES: None. //
+// //
+// CONTEXT: This function may be called from any context //
+// Since it is an isr, that may be strange but it can be called to //
+// handle SW commands in thread context only //
+// //
+////////////////////////////////////////////////////////////////////////////////////
+
+MEDIAIP_IRQ_RETCODE mvd_kernel_hw_secondary_isr ( u_int32 irq_val )
+{
+ u_int32 uActMaloneID;
+ u_int32 uTemp;
+ u_int32 sif_irq_status[0x3] = { 0x0 };
+#if ( TARGET_APP == GTB_DEC ) || ( TARGET_APP == MEDIA_DEC ) || ( TARGET_APP == VIDEO_TRANS ) || ( TARGET_APP == GTB_TRANS )
+ u_int32 uIrqTarget0, uIrqTarget1;
+#endif
+
+ /* Future Proof... */
+ /* If we have two levels of interrupt we need to save and restore HW focus */
+ pMALONE_KERNEL_HW_SESSION pLocMVDHw = pgMVDKernelHw;
+
+ /* Work out which Malone instance cause this isr and set HW focus accordingly */
+
+#if ( TARGET_APP == GTB_DEC ) || ( TARGET_APP == MEDIA_DEC ) || ( TARGET_APP == VIDEO_TRANS ) || ( TARGET_APP == GTB_TRANS )
+
+ pal_int_get_irq_line ( uMvdKernelIrqPin[0x0][0x0],
+ &uIrqTarget0
+ );
+ pal_int_get_irq_line ( uMvdKernelIrqPin[0x0][0x1],
+ &uIrqTarget1
+ );
+
+ uActMaloneID = ( irq_val == MALONE_SW_IRQ ) ? MALONE_SW :
+ (( irq_val == uIrqTarget0 ) | ( irq_val == uIrqTarget1 )) ? MALONE_HW_1 :
+ MALONE_HW_2;
+
+#else
+
+ uActMaloneID = ( irq_val == MALONE_SW_IRQ ) ? MALONE_SW :
+ (( irq_val == uMvdKernelIrqPin[0x0][0x0] ) | ( irq_val == uMvdKernelIrqPin[0x0][0x1] )) ? MALONE_HW_1 :
+ MALONE_HW_2;
+
+#endif
+
+ mvd_kernel_hw_set_focus ( uActMaloneID, &pgMVDKernelHw );
+
+ if ( uActMaloneID != MALONE_SW )
+ {
+ /* Break down sif IRQ sources */
+ APB_REG_READ( pgMVDKernelHw->sif_regp->intr_status, sif_irq_status[0x0] );
+
+ /* Clear those we will handle here */
+ MVD_REG_WRITE( pgMVDKernelHw, 0x0 /*DECLIB_DBG_REG_SIF*/, pgMVDKernelHw->sif_regp->intr_status, sif_irq_status[0x0] & MSD_SIF_INTR2_EXTENSION_BIT_2 );
+
+ /* Read it back to ensure write has made it to Malone */
+ /* Using uActMaloneID as read dsetination as it is no longer */
+ /* required */
+ APB_REG_READ( pgMVDKernelHw->sif_regp->intr_status, uTemp );
+
+ /* Also re-clear the INTC bit which brought us in here since */
+ /* it will have been reset. */
+ pal_int_clear ( irq_val,
+ TRUE );
+
+ if ( sif_irq_status[0x0] & MSD_SIF_INTR2_EXTENSION_BIT_2 )
+ {
+ /* Break down extension IRQ sources */
+ APB_REG_READ( pgMVDKernelHw->sif_regp->intr2_status, sif_irq_status[0x1]);
+
+ /* Clear those we will handle here */
+ MVD_REG_WRITE( pgMVDKernelHw, DECLIB_DBG_REG_SIF, pgMVDKernelHw->sif_regp->intr2_status, sif_irq_status[0x1] & ( MSD_SIF_CTRL2_SPP_SCODE_INTR_ENAB_BIT |
+ MSD_SIF_CTRL2_SPP_PESSC_INTR_ENAB_BIT |
+ MSD_SIF_CTRL2_SPP_BSDMA_INTR_ENAB_BIT ));
+
+ /* Bugzilla 237 - PES Interupt enable inadvertantly set through a RMW of sif_regp->control */
+ if ( sif_irq_status[0x1] & MSD_SIF_CTRL2_SPP_PESSC_INTR_ENAB_BIT )
+ {
+ u_int32 pes_status;
+
+ APB_REG_READ ( pgMVDKernelHw->spp_regp->pes_status, pes_status );
+
+ if ( MSD_SIF_PES_STATUS_GET_STATE( pes_status ) == pes_WaitClear )
+ {
+ /* Pending DTS/PTS looks like it is locked out reception of another startcode */
+ MVD_REG_WRITE( pgMVDKernelHw, 0x0 /*DECLIB_DBG_REG_SPP*/, pgMVDKernelHw->spp_regp->pes_ctrl, 0x0 );
+ }
+ }
+
+ sif_irq_status[0x0] |= DECODERLIB_SECONDARY_ISR_EVENT;
+
+ mvd_kernel_hw_isr_event ( uActMaloneID,
+ sif_irq_status );
+
+ }
+
+ /* What other interrupts might we wish to handle in a seperate context? */
+ /* Only PES is known so far */
+
+ }
+
+ /* Future Proof - Restore pgMVDKernelHw */
+ pgMVDKernelHw = pLocMVDHw;
+
+ return MEDIAIP_FW_STATUS_OK;
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: internal_decoder_kernel_lib_isr_event //
+// //
+// DESCRIPTION: Callback function for base decoder to schedule the //
+// processing of the isr in thread context //
+// //
+// INPUTS: None //
+// //
+// OUTPUTS: None //
+// //
+// RETURNS: None //
+// //
+// NOTES: Will be called in ISR or thread context by base decoders //
+// //
+////////////////////////////////////////////////////////////////////////////////
+
+void mvd_kernel_hw_isr_event ( u_int32 uMaloneIdx,
+ u_int32 * puIrqStatus )
+{
+ DECODER_KERNEL_LIB_ISR_EVENT_DATA sData;
+
+ sData.uMalIdx = uMaloneIdx;
+ sData.uIrqStatus[0x0] = puIrqStatus[0x0];
+ sData.uIrqStatus[0x1] = puIrqStatus[0x1];
+ sData.uIrqStatus[0x2] = puIrqStatus[0x2];
+
+ gDecKernelLib.pfCallback[uMaloneIdx] ( &sData );
+
+}
+
+/* End of file */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/DecKernelLib.h b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/DecKernelLib.h
new file mode 100755
index 000000000000..b924aa44f50f
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/DecKernelLib.h
@@ -0,0 +1,121 @@
+/////////////////////////////////////////////////////////////////////////////////
+/// @author Copyright (c) 2015 Amphion Semiconductor Ltd
+/////////////////////////////////////////////////////////////////////////////////
+// The code contained herein is licensed under the GNU General Public
+// License. You may obtain a copy of the GNU General Public License
+// Version 2 or later at the following locations:
+//
+// http://www.opensource.org/licenses/gpl-license.html
+// http://www.gnu.org/copyleft/gpl.html
+////////////////////////////////////////////////////////////////////////////////
+//
+/// @file DecLib.h
+/// @brief Main DecLib public header file
+/// @ingroup DecLib
+/// @defgroup DecLib DecLib API
+/// @{
+/// Decoder Library API level - Exported header file
+/// called by the Player level and passing data back
+/// via registered callbacks
+/// @}
+//
+/////////////////////////////////////////////////////////////////////////////////
+// $Id:
+/////////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////////
+// Header files
+/////////////////////////////////////////////////////////////////////////////////
+
+#include "basetype.h"
+#include "mediaip_fw_types.h"
+#include "pal.h"
+#include "DecKernelLibCfg.h"
+
+#ifndef _DECODER_KLIB_H_
+#define _DECODER_KLIB_H_
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Macros
+/////////////////////////////////////////////////////////////////////////////////
+
+#define DECLIB_FSID_INVALID 0xbad
+
+#define DECLIB_DBG_SESSION_STATE 0x1
+#define DECLIB_DBG_DECODER_STATE 0x2
+#define DECLIB_DBG_SYNTAX_ELEMENT 0x4
+#define DECLIB_DBG_REG_ACCESS 0x8
+#define DECLIB_DBG_CQ_FIFO 0x10
+
+#define DECLIB_DBG_REG_HIF 0x1
+#define DECLIB_DBG_REG_SIF 0x2
+#define DECLIB_DBG_REG_CTX 0x4
+#define DECLIB_DBG_REG_RPR 0x8
+#define DECLIB_DBG_REG_SPP 0x10
+#define DECLIB_DBG_REG_DEC 0x20
+#define DECLIB_DBG_REG_CQ 0x40
+#define DECLIB_DBG_REG_RSB 0x80
+#define DECLIB_DBG_REG_DFE 0x80
+
+#ifdef MVD_DIAG_LOG_REG_ACCESS
+#define DECLIB_DBG_MASK 0x1F
+#define DECLIB_DBG_REG_MASK 0x1FF
+#else
+#define DECLIB_DBG_MASK 0x7
+#define DECLIB_DBG_REG_MASK 0x0
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Types
+/////////////////////////////////////////////////////////////////////////////////
+
+typedef struct
+{
+ u_int32 uMalIdx;
+ u_int32 uIrqStatus[0x3];
+
+} DECODER_KERNEL_LIB_ISR_EVENT_DATA;
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Function definitions
+/////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////
+/// Decoder Event info callback
+
+typedef void ( * DecKernelLib_Isr_Callback_t )( DECODER_KERNEL_LIB_ISR_EVENT_DATA *ptEventData );
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Configuration Type
+/////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////
+/// DecoderLib Configuration structure
+
+typedef struct
+{
+ /* Malone hardware details */
+ u_int32 uNumMalones;
+ u_int32 uMaloneHifOffset[DECODERLIB_MAX_MALONES];
+ uint_addr uMaloneBaseAddr[DECODERLIB_MAX_MALONES];
+ u_int32 uMaloneIrqPin[DECODERLIB_MAX_MALONES][0x2];
+ u_int32 uNumDPVUnits; /* 0 or 1 - could infer this from base address but for clarity */
+ uint_addr uDPVBaseAddr;
+ u_int32 uDPVIrqPin;
+} DECODERLIB_KERNEL_CFG, * pDECODERLIB_KERNEL_CFG;
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Function Prototypes
+/////////////////////////////////////////////////////////////////////////////////
+
+MEDIAIP_FW_STATUS decoder_kernel_lib_init ( DECODERLIB_KERNEL_CFG * pCfg );
+
+MEDIAIP_FW_STATUS decoder_kernel_lib_term ( void );
+
+MEDIAIP_FW_STATUS decoder_kernel_lib_register_isr_callback ( u_int32 uMalIdx,
+ DecKernelLib_Isr_Callback_t pfCallback );
+
+
+#endif /* _DECODER_KLIB_H_ */
+
+/* End of File */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/mvd.h b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/mvd.h
new file mode 100755
index 000000000000..956f69e93f70
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/mvd.h
@@ -0,0 +1,157 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+
+ Author : Media IP FW team
+ File name : mvd.h
+ Notes : Replaces misnamed "global.h"
+
+ ***********************************************/
+
+#ifndef _MVD_H_
+#define _MVD_H_
+
+/////////////////////////////////////////////////////////////////////////////////
+// Header files
+/////////////////////////////////////////////////////////////////////////////////
+
+#include "basetype.h"
+#include "DecKernelLibCfg.h"
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Variables
+/////////////////////////////////////////////////////////////////////////////////
+extern u_int32 uMvdKernelIrqPin[DECODERLIB_MAX_MALONES][0x2];
+
+/////////////////////////////////////////////////////////////////////////////////
+// Macros
+/////////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////////
+// Register access model
+//
+
+///////////////////////////////////////////////////
+// This is the option used for most builds
+
+#ifndef MVD_DEBUG_REG_ACCESS
+#if TARGET_LEVEL == CMODEL
+ extern u_int32 dec_model_malone_reg_write ( u_int32 * puRegAddr, u_int32 uWrtData );
+ extern u_int32 dec_model_malone_reg_read ( u_int32 * puRegAddr, u_int32 uReadData );
+
+ #define APB_REGISTER_WRITE(a,b) dec_model_malone_reg_write ( ( u_int32 * )a, ( u_int32 )b )
+ #define APB_REGISTER_READ(a,b) b = *a; dec_model_malone_reg_read ( ( u_int32 * )a, ( u_int32 )b )
+ #define APB_REG_WRITE(a,b) dec_model_malone_reg_write ( ( u_int32 * )&a, ( u_int32 )b )
+ #define APB_REG_READ(a,b) b = a; dec_model_malone_reg_read ( ( u_int32 * )&a, ( u_int32 )b )
+#else
+
+
+
+#if 0
+#include "VPU_debug.h"
+//static u_int32 c;
+
+#define APB_REGISTER_WRITE(a,b) c = b; *a = c; printk("write reg 0x%p, val 0x%x, in %s\n", a, c, __FUNCTION__)
+#define APB_REGISTER_READ(a,b) c = *a; b = c; printk("read reg 0x%p, val 0x%x, in %s\n", a, c, __FUNCTION__)
+#define APB_REG_WRITE(a,b) c = b; a = c; printk("write reg 0x%p, val 0x%x, in %s\n", &a, c, __FUNCTION__)
+#define APB_REG_READ(a,b) c = a; b = c; printk("read reg 0x%p, val 0x%x, in %s\n", &a, c, __FUNCTION__)
+#else
+
+ #define APB_REGISTER_WRITE(a,b) *a = b
+ #define APB_REGISTER_READ(a,b) b = *a
+ #define APB_REG_WRITE(a,b) a = b
+ #define APB_REG_READ(a,b) b = a
+#endif
+
+#endif
+#else
+ // Store reg acesses in simple debug array for dumping from debugger
+ extern void decoderlib_debug_reg( volatile u_int32 * puRegAddr, u_int32 uVal);
+ #define APB_REGISTER_WRITE(a,b) *a = b
+ #define APB_REGISTER_READ(a,b) b = *a
+ #define APB_REG_WRITE(a,b) decoderlib_debug_reg(( u_int32 * )&a,b)
+ #define APB_REG_READ(a,b) b = a
+#endif
+
+
+#ifdef MVD_DIAG_LOG_REG_ACCESS
+
+#define DIAG_CQ_ID DECLIB_DBG_REG_CQ
+
+extern void decoderlib_dbg_core_log_write ( volatile u_int32 * puRegAddr, u_int32 uVal, void * pMVDHw, u_int32 uAuxData, bool bActive );
+extern void decoderlib_dbg_core_log_read ( volatile u_int32 * puRegAddr, u_int32 *puVal, void * pMVDHw, u_int32 uAuxData, bool bActive );
+extern u_int32 decoderlib_dbg_get_reg_mask ( u_int32 uStrIdx );
+
+#define MVD_REG_WRITE(pMvdHw,aux,addr,val) decoderlib_dbg_core_log_write ( ( u_int32 * )&addr, val, ( void * )pMvdHw, aux, gbLogRegAccessActive )
+#define MVD_REG_READ(pMvdHw,aux,addr,val) decoderlib_dbg_core_log_read ( ( u_int32 * )&addr, &val, ( void * )pMvdHw, 0x0, gbLogRegAccessActive )
+#define MVD_ADDRESS_WRITE(pMvdHw,aux,addr,val) decoderlib_dbg_core_log_write ( ( u_int32 * )addr, val, ( void * )pMvdHw, aux, gbLogRegAccessActive )
+#define MVD_ADDRESS_READ(pMvdHw,aux,addr,val) decoderlib_dbg_core_log_read ( ( u_int32 * )addr, &val, ( void * )pMvdHw, 0x0, gbLogRegAccessActive )
+
+#else
+
+#define MVD_REG_WRITE(pMvdHw,aux,addr,val) APB_REG_WRITE(addr,val)
+#define MVD_REG_READ(pMvdHw,aux,addr,val) APB_REG_READ(addr,val)
+#define MVD_ADDRESS_WRITE(pMvdHw,aux,addr,val) APB_REGISTER_WRITE(addr,val)
+#define MVD_ADDRESS_READ(pMvdHw,aux,addr,val) APB_REGISTER_READ(addr,val)
+
+#endif /* MVD_DIAG_LOG_REG_WRITES */
+
+#define APB_REGISTER_POLL(s,p,v,m)
+#define APB_SEEK_EVENT(e)
+#define APB_REG_SET(a,m,b) ((a)) = ((((a)) & ~(m)) | ((b) & (m)))
+
+///////////////////////////
+// System functions
+//
+
+///////////////////////////
+// MULT_U(a,b)
+//
+// a * b
+
+#define MULT_U(a,b) (a)*(b)
+
+///////////////////////////
+// LDIV_MOD_U(a,b)
+//
+// a / b, mod = a % b
+
+#define LDIV_MOD_U(a,b,mod) (a)/(b), mod = (a)%(b)
+
+///////////////////////////
+// MEMORY_BLOCK_COPY(a,b,c,d)
+//
+// a : int - 1 for load, 0: store
+// b : int - size of transfer in bytes
+// c : void * - source address
+// d : void * - destination address
+
+#define MEMORY_BLOCK_COPY(a,b,c,d) pal_memcpy(d,c,b)
+
+//////////////////////////////////////////////////
+// Implementation running defines
+//
+
+#define FORCE_DECODE_HANDLE_IRQ { \
+ pgCtrlMVDHw->uForceFIQ = 1; \
+ if ( pgCtrlMVDHw->uMaloneID == 0 ) \
+ { \
+ pal_int_set ( uDecLibIrqPin[0x0][0x0] ); \
+ } \
+ else \
+ { \
+ pal_int_set ( uDecLibIrqPin[0x1][0x0] ); \
+ } \
+ }
+
+#endif /* _MVD_H_ */
+
+/* End of file */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/mvd_reg_map.h b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/mvd_reg_map.h
new file mode 100755
index 000000000000..5464cd240458
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/mvd_reg_map.h
@@ -0,0 +1,1676 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+
+ Author : VCodec FW team
+ File name : mvd_reg_map.h
+ Function : Register map file
+
+ ************************************************/
+
+#ifndef _MVD_REG_MAP_H_
+#define _MVD_REG_MAP_H_
+
+/////////////////////////////////////////////////////////////////
+// HIF address index
+//
+
+typedef struct MvdHwRegHifMapTag
+{
+ // 0x00 --> 0x0f
+ MvdHwReg control;
+ MvdHwReg status;
+ MvdHwReg config;
+ MvdHwReg config2;
+ MvdHwReg test;
+ MvdHwReg host_interrupt_enable;
+ MvdHwReg interrupt_status;
+ MvdHwReg fast_interrupt_enable;
+ MvdHwReg dq_unused[4];
+ MvdHwReg security;
+ MvdHwReg format_disable;
+ MvdHwReg system_data;
+ MvdHwReg spp_security;
+ // 0x10 --> 0x1f
+ MvdHwReg dfe_security;
+ MvdHwReg hif_unused[15];
+
+ // the rest are not used
+ // MvdHwReg unused_0x60[96];
+
+} MvdHwRegHifMap;
+
+
+/////////////////////////////////////////////////////////////////
+// SIF address index
+//
+
+typedef struct MvdHwRegSifMapTag
+{
+ // 0x00 --> 0x0f
+ MvdHwReg semaphore_read; // R
+ MvdHwReg intr_mask_read; // R
+ MvdHwReg semaphore_set; // W
+ MvdHwReg semaphore_clr; // W
+ MvdHwReg intr_mask_set; // W
+ MvdHwReg intr_mask_clr; // W
+ MvdHwReg host_data0_reg; // R
+ MvdHwReg msd_data0_reg; // R/W
+ MvdHwReg host_data1_reg; // R
+ MvdHwReg msd_data1_reg; // R/W
+ MvdHwReg frame_active_count;
+ MvdHwReg slice_active_count;
+ MvdHwReg rbsp_bytes_count;
+ MvdHwReg sib_wait_count;
+ MvdHwReg dpb_read_count;
+ MvdHwReg mpr_wait_count;
+ // 0x10 --> 0x1f
+ MvdHwReg intr3_control; // W/R
+ MvdHwReg dpb_fs_size; // R/W
+ MvdHwReg dpb_frm_size; // R/W
+ MvdHwReg dpb_fs_size_ext; // R/W
+ MvdHwReg rsb_mprr_mprc_base; // R/W
+ MvdHwReg rsb_bsd_dbfc_base; // R/W
+ MvdHwReg rsb_pwt_pxd_base; // R/W
+ MvdHwReg frm_dangling; // W
+ MvdHwReg rsb_dfe_base; // R/W
+ MvdHwReg dpb_lut_load; // W
+ MvdHwReg bbb_crc; // R
+ MvdHwReg load_dpb_numb; // W
+ MvdHwReg dpb_frm_size_ext; // R/W
+ MvdHwReg dec_status; // R
+ MvdHwReg mbq_full_count;
+ MvdHwReg mbq_empty_count;
+ // 0x20 --> 0x2f
+ MvdHwReg dispq_push[16];
+ // 0x30 --> 0x3f
+ MvdHwReg intr3_status;
+ MvdHwReg intr3_force;
+ MvdHwReg bs2rbsp_status; // R
+ MvdHwReg bs2rbsp_feed_control;// W/R
+ MvdHwReg bs2rbsp_scode; // R
+ MvdHwReg bs2rbsp_scdctrl; // W/R
+ MvdHwReg rpr_wr_uv_offset;
+ MvdHwReg dispd_cnt_tag; // R
+ MvdHwReg frame_request; // R
+ MvdHwReg intr2_control; // W/R
+ MvdHwReg intr2_status; // R/W
+ MvdHwReg intr2_force;
+ MvdHwReg control; // W/R
+ MvdHwReg intr_status; // R/W
+ MvdHwReg intr_force;
+ MvdHwReg soft_reset; // W
+ // 0x40 --> 0x4f
+ MvdHwReg pes_setup; // W/R
+ MvdHwReg pes_status; // W/R
+ MvdHwReg pes_ctrl; // W
+ MvdHwReg pes_set_state; // W
+ MvdHwReg pes_peek_data; // R
+ MvdHwReg pes_read_data; // R
+ MvdHwReg pes_pts; // R
+ MvdHwReg pes_dts; // R
+ MvdHwReg bs_read; // R
+ MvdHwReg dpbmc_setup; // W
+ MvdHwReg dpbmc_crc_data; // R
+ MvdHwReg rsb_ctrl_stat;
+ MvdHwReg ext_rsb_base;
+ MvdHwReg ext_xfr_param;
+ MvdHwReg vmif_rsb_arb_ctrl;
+ MvdHwReg vmif_stride;
+
+ // 0x50 --> 0x5f
+ MvdHwReg vmif_uv_offset;
+ MvdHwReg vmif_options;
+ MvdHwReg vmif_base_offset;
+ MvdHwReg vmif_mbi_cache;
+ MvdHwReg lmem_config;
+ MvdHwReg qp_acc;
+ MvdHwReg vmif_mbi_xmem;
+ MvdHwReg vmif_4kcache_stride;
+ MvdHwReg dpbmc_setup2;
+ MvdHwReg rpr_rd_uv_offset;
+ MvdHwReg slow_feed_wt_val;
+ MvdHwReg unused_0x5b;
+ MvdHwReg unused_0x5c;
+ MvdHwReg dpbmc_crc2_data; // R
+ MvdHwReg errgen_config; // W
+ MvdHwReg errgen_seeds; // W
+ // 0x60 --> 0x6f
+ MvdHwReg bsdma_command;
+ MvdHwReg bsdma_options;
+ MvdHwReg bsdma_status;
+ MvdHwReg bsdma_des;
+ MvdHwReg bsdma_bwp;
+ MvdHwReg bsdma_brp;
+ MvdHwReg bsdma_bsa;
+ MvdHwReg bsdma_bea;
+ MvdHwReg bsdma_blw;
+ MvdHwReg bsdma_bup;
+ MvdHwReg bsdma_peek;
+ MvdHwReg bsdma_bhw;
+ MvdHwReg bsdma_trc;
+ MvdHwReg bsdma_ext_options;
+ MvdHwReg bsdma_lvl;
+ MvdHwReg unused_0x6f;
+ // 0x70 --> 0x7f
+ // MvdHwReg unused_16[16];
+} MvdHwRegSifMap;
+
+/////////////////////////////////////////////////////////////////
+// Context Reg Map
+//
+
+#define MVD_CTX_POC_RESTORE_WORDS 62
+
+typedef struct MvdHwRegCtxMapTag
+{
+ // 0x00 --> 0x0f
+ MvdHwReg ctx_command;
+ MvdHwReg ctx_next_sf;
+ MvdHwReg ctx_spp_command;
+ MvdHwReg align_7[4];
+ MvdHwReg ctx_status;
+ MvdHwReg align_8[8];
+
+ // 0x10 --> 0x1f
+ MvdHwReg ctx_addr_spp[16]; /* PreParser (if it is configured in) */
+// MvdHwReg align_9[4];
+
+ // 0x20 --> 0x2f
+ MvdHwReg ctx_addr_bbb[2]; /* Active BBB */
+ MvdHwReg align_10[14];
+
+ // 0x30 --> 0x3f
+ MvdHwReg ctx_addr_bsi[13]; /* SCD/PES/FIFO */
+ MvdHwReg align_11[3];
+
+ // 0x40 --> 0x7f
+ MvdHwReg h264_poc_restore[MVD_CTX_POC_RESTORE_WORDS];
+ MvdHwReg unused_poc[64-MVD_CTX_POC_RESTORE_WORDS];
+
+} MvdHwRegCtxMap;
+
+
+/////////////////////////////////////////////////////////////////
+// Resampler Reg Map
+//
+
+typedef struct MvdHwRegRprMapTag
+{
+ // 0x0 --> 0xf
+ MvdHwReg rpr_status_addr; // R
+ MvdHwReg rpr_ctl_start;
+ MvdHwReg rpr_in_size;
+ MvdHwReg rpr_out_size;
+ MvdHwReg rpr_fill_value;
+ MvdHwReg rpr_ax_ini_y;
+ MvdHwReg rpr_ax_ini_uv;
+ MvdHwReg rpr_ax_inc;
+ MvdHwReg rpr_iuyl_num_y;
+ MvdHwReg rpr_iuyl_num_uv;
+ MvdHwReg rpr_iuyl_inc;
+ MvdHwReg rpr_options_addr;
+ MvdHwReg csc_status;
+ MvdHwReg csc_ctrl_start;
+ MvdHwReg csc_fs_size;
+ MvdHwReg csc_fs_idc;
+ MvdHwReg csc_fs_stride;
+ MvdHwReg rpr_rd_fs_stride;
+ MvdHwReg rpr_wr_fs_stride;
+ MvdHwReg dpv_status;
+ MvdHwReg dpv_ctrl_start;
+ MvdHwReg dpv_fs_size;
+ MvdHwReg dpv_init_val;
+ MvdHwReg dpv_crc_val;
+
+ // approx 1KB space not used (1KB - rpr register)
+ // MsdHwReg unused_0x90[240];
+
+} MvdHwRegRprMap;
+
+/////////////////////////////////////////////////////////////////
+// RC4 Decryption Reg Map
+//
+
+typedef struct MvdHwRegRC4MapTag
+{
+
+ MvdHwReg Key0Word0;
+ MvdHwReg Key0Word1;
+ MvdHwReg Key0Word2;
+ MvdHwReg Key0Word3;
+ MvdHwReg Key1Word0;
+ MvdHwReg Key1Word1;
+ MvdHwReg Key1Word2;
+ MvdHwReg Key1Word3;
+ MvdHwReg RC4Enable;
+ MvdHwReg unused_rc4_0[12-9];
+ MvdHwReg RC4Ctx0;
+ MvdHwReg RC4Ctx1;
+ MvdHwReg RC4Ctx2;
+ MvdHwReg unused_rc4_1;
+
+} MvdHwRegRC4Map;
+
+
+/////////////////////////////////////////////////////////////////
+// Black Bar Detector Reg Map
+//
+/*-- BBD registers (common to all formats) */
+
+typedef struct MvdHwRegBbdMapTag
+{
+ MvdHwReg bbd_cfg_ctrl;
+ MvdHwReg bbd_logo_width;
+ MvdHwReg bbd_pix_thr;
+ MvdHwReg bbd_s_thr_row;
+ MvdHwReg bbd_p_thr_row;
+ MvdHwReg bbd_s_thr_logo_row;
+ MvdHwReg bbd_p_thr_logo_row;
+ MvdHwReg bbd_s_thr_col;
+ MvdHwReg bbd_p_thr_col;
+ MvdHwReg bbd_chr_thr;
+ MvdHwReg bbd_excl_win_mb;
+ MvdHwReg unused;
+ MvdHwReg bbd_hor_active;
+ MvdHwReg bbd_ver_active;
+ MvdHwReg bbd_logo_active;
+ MvdHwReg bbd_botprev_active;
+ MvdHwReg bbd_min_col_proj;
+ MvdHwReg bbd_min_row_proj;
+
+
+} MvdHwRegBbdMap;
+
+/////////////////////////////////////////////////////////////////
+// Debug Reg Map
+//
+
+typedef struct MvdHwRegDbgMapTag
+{
+ // 0x0 --> 0x1f
+ union
+ {
+ MvdHwReg msk0_lo;
+ MvdHwReg fifo0;
+ MvdHwReg status0;
+ } fifo0_up;
+ union
+ {
+ MvdHwReg msk0_hi;
+ MvdHwReg fifo1;
+ MvdHwReg status1;
+ } fifo1_up;
+ union
+ {
+ MvdHwReg msk1_lo;
+ MvdHwReg fifo2;
+ MvdHwReg status2;
+ } fifo2_up;
+ union
+ {
+ MvdHwReg msk1_hi;
+ MvdHwReg fifo3;
+ MvdHwReg status3;
+ } fifo3_up;
+ union
+ {
+ MvdHwReg msk2_lo;
+ MvdHwReg fifo4;
+ MvdHwReg status4;
+ } fifo4_up;
+ union
+ {
+ MvdHwReg msk2_hi;
+ MvdHwReg fifo5;
+ MvdHwReg status5;
+ } fifo5_up;
+ union
+ {
+ MvdHwReg mode;
+ MvdHwReg fifo6;
+ MvdHwReg status6;
+ } fifo6_up;
+ union
+ {
+ MvdHwReg unused2;
+ MvdHwReg fifo7;
+ MvdHwReg status7;
+ } fifo7_up;
+ union
+ {
+ MvdHwReg crc0;
+ MvdHwReg fifo8;
+ MvdHwReg status8;
+ } crc0_up;
+ union
+ {
+ MvdHwReg crc1;
+ MvdHwReg fifo9;
+ MvdHwReg status9;
+ } crc1_up;
+ union
+ {
+ MvdHwReg crc2;
+ MvdHwReg fifo10;
+ MvdHwReg status10;
+ } crc2_up;
+ union
+ {
+ MvdHwReg crc3;
+ MvdHwReg fifo11;
+ MvdHwReg status11;
+ } crc3_up;
+ union
+ {
+ MvdHwReg crc4;
+ MvdHwReg fifo12;
+ MvdHwReg status12;
+ } crc4_up;
+ union
+ {
+ MvdHwReg crc5;
+ MvdHwReg fifo13;
+ MvdHwReg status13;
+ } crc5_up;
+ union
+ {
+ MvdHwReg crc6;
+ MvdHwReg fifo14;
+ MvdHwReg status14;
+ } crc6_up;
+ union
+ {
+ MvdHwReg crc7;
+ MvdHwReg clr_crc;
+ MvdHwReg fifo15;
+ MvdHwReg status15;
+ } crc7_up;
+ union
+ {
+ MvdHwReg crc8;
+ MvdHwReg fifo16;
+ MvdHwReg status16;
+ } crc8_up;
+ union
+ {
+ MvdHwReg crc9;
+ MvdHwReg fifo17;
+ MvdHwReg status17;
+ } crc9_up;
+ union
+ {
+ MvdHwReg crc10;
+ } crc10_up;
+ union
+ {
+ MvdHwReg crc11;
+ } crc11_up;
+
+ MvdHwReg crc12;
+ MvdHwReg crc13;
+ MvdHwReg crc14;
+ MvdHwReg dbg_unused_31to23[9];
+
+} MvdHwRegDbgMap;
+
+/////////////////////////////////////////////////////////////////
+//Command Queues Reg Map
+//
+
+typedef struct MvdHwRegCqMapTag
+{
+
+ MvdHwReg cq_status;
+ MvdHwReg cq_grp;
+ MvdHwReg cq_clr;
+ MvdHwReg cq_data;
+ MvdHwReg cq_data_last;
+ MvdHwReg cq_data_mask;
+ MvdHwReg cq_data_test;
+ MvdHwReg cq_opts;
+ MvdHwReg cq_push;
+ MvdHwReg cq_dummy;
+ MvdHwReg cq_cmdq_base;
+ MvdHwReg cq_cmdq_amax;
+ MvdHwReg cq_cmdq_wptr;
+ MvdHwReg cq_cmdq_rptr;
+ MvdHwReg cq_cmdq_level;
+ MvdHwReg cq_rdq_base;
+ MvdHwReg cq_rdq_amax;
+ MvdHwReg cq_rdq_wptr;
+ MvdHwReg cq_rdq_rptr;
+ MvdHwReg cq_rdq_level;
+ MvdHwReg cq_poll_param;
+ MvdHwReg cq_grp_level;
+ MvdHwReg cq_exec;
+ MvdHwReg cq_lwm;
+ MvdHwReg cq_dataq_base;
+ MvdHwReg cq_dataq_amax;
+ MvdHwReg cq_dataq_rptr;
+ MvdHwReg cq_special_en;
+ MvdHwReg cq_wdata_opt;
+ MvdHwReg cq_sgrp_base_addr;
+ MvdHwReg cq_sgrp_num_cmds;
+ MvdHwReg cq_status2;
+
+} MvdHwRegCqMap;
+
+
+/////////////////////////////////////////////////////////////////
+// Stream Preparser Reg Map
+//
+
+typedef struct MvdHwRegSppMapTag
+{
+ // 0x0 --> 0x07
+ MvdHwReg bbb_showbits; // R
+ MvdHwReg bbb_status; // R
+ MvdHwReg config; // W/R
+ MvdHwReg bs2rbsp_status; // R
+ MvdHwReg bs2rbsp_feed_control;// W/R
+ MvdHwReg bs2rbsp_scode; // R
+ MvdHwReg bs2rbsp_scdctrl; // W/R
+ MvdHwReg bbb_crc; // R
+
+ // 0x08 --> 0x0f
+ MvdHwReg pes_setup; // W/R
+ MvdHwReg pes_status; // W/R
+ MvdHwReg pes_ctrl; // W
+ MvdHwReg pes_set_state; // W
+ MvdHwReg pes_peek_data; // R
+ MvdHwReg pes_read_data; // R
+ MvdHwReg pes_pts; // R
+ MvdHwReg pes_dts; // R
+
+ // 0x10 --> 0x1f
+ MvdHwReg bsdma_command;
+ MvdHwReg bsdma_options;
+ MvdHwReg bsdma_status;
+ MvdHwReg bsdma_des;
+ MvdHwReg bsdma_bwp;
+ MvdHwReg bsdma_brp;
+ MvdHwReg bsdma_bsa;
+ MvdHwReg bsdma_bea;
+ MvdHwReg bsdma_blw;
+ MvdHwReg bsdma_bup;
+ MvdHwReg bsdma_peek;
+ MvdHwReg bsdma_bhw;
+ MvdHwReg bsdma_trc;
+ MvdHwReg bsdma_ext_options;
+ MvdHwReg bsdma_lvl;
+ MvdHwReg unused_0x1f;
+
+ // 0x20 --> 0x3f
+ union
+ {
+ MvdHwReg bsd_byte_align;
+ MvdHwReg bsd_getbits[32];
+ } get_bits;
+
+ // 0x40 --> 0x4f
+ MvdHwReg egd_ue;
+ MvdHwReg egd_se;
+ MvdHwReg egd_me_intra;
+ MvdHwReg egd_me_inter;
+ MvdHwReg data_reg; /* R/W */
+ MvdHwReg num_bits_pulled; /* R */
+ MvdHwReg bit_puller;
+ MvdHwReg unused_spp1[16-7];
+
+ // 0x50 --> 0x5f
+ MvdHwReg Key0Word0;
+ MvdHwReg Key0Word1;
+ MvdHwReg Key0Word2;
+ MvdHwReg Key0Word3;
+ MvdHwReg Key1Word0;
+ MvdHwReg Key1Word1;
+ MvdHwReg Key1Word2;
+ MvdHwReg Key1Word3;
+ MvdHwReg RC4Enable;
+ MvdHwReg unused_rc4_0[12-9];
+ MvdHwReg RC4Ctx0;
+ MvdHwReg RC4Ctx1;
+ MvdHwReg RC4Ctx2;
+ MvdHwReg unused_rc4_1;
+
+} MvdHwRegSppMap;
+
+/////////////////////////////////////////////////////////////////
+// Stream Frame Buffer Compression Reg Map
+//
+
+typedef struct MvdHwRegFbcMapTag
+{
+ // 0x0 --> 0x0f
+ MvdHwReg fbc_start;
+ MvdHwReg fbc_config;
+ MvdHwReg fbc_param1;
+ MvdHwReg fbc_param2;
+ MvdHwReg fbc_ctb_tile_px4;
+ MvdHwReg fbc_ctb_tile_py4;
+ MvdHwReg fbc_ctb_tile_px8;
+ MvdHwReg fbc_ctb_tile_py8;
+ MvdHwReg fbc_ctb_tile_px9_y10;
+ MvdHwReg fbc_ot_offset;
+ MvdHwReg fbc_field_offset;
+ MvdHwReg fbc_uv_offset;
+ MvdHwReg fbc_field_list;
+ MvdHwReg fbc_luma_pad_list;
+ MvdHwReg fbc_chroma_pad_list;
+ MvdHwReg fbc_write_count;
+ MvdHwReg fbc_read_count_0;
+ MvdHwReg fbc_read_count_1;
+ MvdHwReg fbc_write_chksum;
+ MvdHwReg fbc_read_chksum_0;
+ MvdHwReg fbc_read_chksum_1;
+ MvdHwReg fbc_param3;
+ MvdHwReg fbc_fs_height;
+ MvdHwReg fbc_read_dbg_gen;
+ MvdHwReg fbc_read_dbg_blk;
+ MvdHwReg fbd_ot_offset;
+ MvdHwReg fbd_fld_offset;
+ MvdHwReg fbd_uv_offset;
+ MvdHwReg fbc_unused[62-28];
+ MvdHwReg unused_fbc_0[2];
+} MvdHwRegFbcMap;
+
+
+/////////////////////////////////////////////////////////////////
+// Decoupled Front End Register Map
+// ( 1K incl debug registers )
+
+typedef struct MvdHwRegDfeMapTag
+{
+ // 0x0 --> 0x07
+ MvdHwReg bbb_showbits; // R
+ MvdHwReg bbb_status; // R
+ MvdHwReg config; // W/R
+ MvdHwReg bs2rbsp_status; // R
+ MvdHwReg bs2rbsp_feed_control;// W/R
+ MvdHwReg bs2rbsp_scode; // R
+ MvdHwReg bs2rbsp_scdctrl; // W/R
+ MvdHwReg bbb_crc; // R
+
+ // 0x08 --> 0x0f
+ MvdHwReg pes_setup; // W/R
+ MvdHwReg pes_status; // W/R
+ MvdHwReg pes_ctrl; // W
+ MvdHwReg pes_set_state; // W
+ MvdHwReg pes_peek_data; // R
+ MvdHwReg pes_read_data; // R
+ MvdHwReg pes_pts; // R
+ MvdHwReg pes_dts; // R
+
+ // 0x10 --> 0x1f
+ MvdHwReg bsdma_command;
+ MvdHwReg bsdma_options;
+ MvdHwReg bsdma_status;
+ MvdHwReg bsdma_des;
+ MvdHwReg bsdma_bwp;
+ MvdHwReg bsdma_brp;
+ MvdHwReg bsdma_bsa;
+ MvdHwReg bsdma_bea;
+ MvdHwReg bsdma_blw;
+ MvdHwReg bsdma_bup;
+ MvdHwReg bsdma_peek;
+ MvdHwReg bsdma_bhw;
+ MvdHwReg bsdma_trc;
+ MvdHwReg bsdma_ext_options;
+ MvdHwReg bsdma_lvl;
+ MvdHwReg unused_0x1f;
+
+ /* BSD address, 0x20 --> 0x5f */
+ MvdHwReg bsd_options;
+ MvdHwReg bsd_dec_status;
+ MvdHwReg bsd_ctb_coord;
+ MvdHwReg bsd_slice_start;
+ MvdHwReg bsd_dec_param1;
+ MvdHwReg bsd_dec_param2;
+ MvdHwReg bsd_dec_ctb_cnt;
+ MvdHwReg bsd_dec_err_ctb_cnt;
+ MvdHwReg bsd_dec_ctb_qp_sum;
+
+ MvdHwReg Unused_9;
+ MvdHwReg Unused_A;
+
+ MvdHwReg bsd_ue;
+ MvdHwReg bsd_se;
+ MvdHwReg Unused_D;
+ MvdHwReg Unused_E;
+ MvdHwReg bsd_data;
+
+ MvdHwReg Unused_10;
+ MvdHwReg bsd_ctb_tile_px4;
+ MvdHwReg bsd_ctb_tile_py4;
+ MvdHwReg bsd_ctb_tile_px8;
+ MvdHwReg bsd_ctb_tile_py8;
+ MvdHwReg bsd_ctb_tile_px9_y10;
+ MvdHwReg bsd_sc_list_usage;
+ MvdHwReg bsd_sc_list_base;
+ MvdHwReg bsd_sc_list_idx[4];
+ MvdHwReg bsd_ei_flags_mask;
+ MvdHwReg bsd_bit_puller;
+ MvdHwReg bsd_is_trailing;
+ MvdHwReg bsd_bbb_status;
+
+ union
+ {
+ MvdHwReg bsd_byte_align;
+ MvdHwReg bsd_getbits[32];
+ } get_bits;
+
+ /* 0x60 --> 0x6f */
+ MvdHwReg Key0Word0;
+ MvdHwReg Key0Word1;
+ MvdHwReg Key0Word2;
+ MvdHwReg Key0Word3;
+ MvdHwReg Key1Word0;
+ MvdHwReg Key1Word1;
+ MvdHwReg Key1Word2;
+ MvdHwReg Key1Word3;
+ MvdHwReg RC4Enable;
+ MvdHwReg unused_rc4_0[12-9];
+ MvdHwReg RC4Ctx0;
+ MvdHwReg RC4Ctx1;
+ MvdHwReg RC4Ctx2;
+ MvdHwReg unused_rc4_1;
+
+ /* 0x70-0x7f */
+ MvdHwReg dfe_ctx_cmd;
+ MvdHwReg unused_dfe_ctx_1;
+ MvdHwReg dfe_ctx_addr_bbb[2]; /* Active BBB */
+ MvdHwReg unused_dfe_ctx_2[12];
+
+ /* 0x80 --> 0x8f */
+ MvdHwReg dfe_ctx_addr_bsi[13]; /* SCD/PES/FIFO */
+ MvdHwReg unused_dfe_ctx_3[3];
+
+ /* 0x90 --> 0x9F */
+ MvdHwReg dfe_img_cfg;
+ MvdHwReg dfe_slice_cfg;
+ MvdHwReg dfe_frm_size;
+ MvdHwReg dfe_status;
+ MvdHwReg dfe_frm_act_count;
+ MvdHwReg dfe_slice_act_count;
+ MvdHwReg dfe_rbsp_bytes_count;
+ MvdHwReg dfe_sib_wait_count;
+ MvdHwReg dfe_bsd_wait_count;
+ MvdHwReg unused_dfe[16-9];
+
+ /* 0xA0 -> 0xBF */
+ MvdHwRegCqMap DFECQ;
+
+ /* 0xC0 -> 0xDF */
+ MvdHwReg unused_0xc0_0xdf[32];
+
+ /* 0xE0 -> 0xFF */
+ MvdHwReg dfe_dbg[32];
+
+} MvdHwRegDfeMap;
+
+/////////////////////////////////////////////////////////////////
+// Decoupled Back End Register Map
+// ( 4K incl debug registers )
+
+typedef struct MvdHwRegDbeMapTag
+{
+
+ /* TOP address, 0x00 --> 0x3f */
+ MvdHwReg image_config; // R/W
+ MvdHwReg slice_config; // R/W
+ MvdHwReg top_ctb_tile_info; // R/W
+ MvdHwReg mbi_wr_base; // R/W
+ MvdHwReg mbi_rd_base; // R/W
+
+ MvdHwReg dec_cfg; // R/W Addr in CQ : 0x605
+ MvdHwReg dbg_cfg; // R/W
+ MvdHwReg dbf1_cfg; // R/W
+ MvdHwReg dbf2_cfg; // R/W
+ MvdHwReg dbe_frm_size; // R/W
+ MvdHwReg prb_pack_base; // R/W
+ MvdHwReg prb_bin_cfg; // R/W
+ MvdHwReg dcp_bin_cfg; // R/W
+
+ MvdHwReg unused_top[64-13];
+
+ /* DBE address, 0x40 --> 0x7F */
+ MvdHwReg dbe_status; // R
+ MvdHwReg dbe_frm_act_count; // R
+ MvdHwReg dbe_slice_act_count; // R
+ MvdHwReg dbe_wait_count; // R
+ MvdHwReg dbe_fetch_crc; // R
+ MvdHwReg dbe_mpr_prx_wait; // R
+ MvdHwReg dbe_pxd_prx_wait; // R
+ MvdHwReg dbe_fch_plq_wait; // R
+ MvdHwReg dbe_pxd_plq_wait; // R
+ MvdHwReg dbe_mpr_wait_count; // R
+ MvdHwReg dbe_fch_words_count; // R
+ MvdHwReg unused_dbe[64-11];
+
+ /* MPR address, 0x80 --> 0xBF */
+ MvdHwReg mpr_config;
+ MvdHwReg mpr_slice_param;
+
+ MvdHwReg Unused_82_9F[30];
+
+ MvdHwReg mpr_list[32];
+
+ MvdHwReg Unused_0xC0_FF[64];
+
+ /* CQ address, 0x100 --> 0x11F */
+ MvdHwRegCqMap DBECQ;
+ MvdHwReg Unused_0x120_13F[32];
+
+ MvdHwReg Unused_0x140_17F[64];
+
+ MvdHwReg mpr_dbg;
+ MvdHwReg pxd_dbg;
+ MvdHwReg dbf_dbg;
+
+ /* Not quite sure what debug is in here */
+ MvdHwReg Unused_DbeDbg[61];
+
+ MvdHwReg Unused_0x1C0_1FF[64];
+
+} MvdHwRegDbeMap;
+
+
+/////////////////////////////////////////////////////////////////
+// H.264 Reg Map
+//
+
+typedef struct MvdHwRegH264MapTag
+{
+ //------- TOP address, 0x00 --> 0x3f
+ MvdHwReg options; // R/W
+ MvdHwReg mbi_wr_base; // R/W
+ MvdHwReg mbi_rd_base; // R/W
+ MvdHwReg bli_wr_base; // R/W
+ MvdHwReg bli_wr_stride; // R/W
+ MvdHwReg unused_top[64-5];
+ //------- BSD address, 0x40 --> 0x7f
+ // 0x40 --> 0x4f
+ MvdHwReg bsd_dec_options; // W/R
+ MvdHwReg bsd_dec_status; // R
+ MvdHwReg bsd_curr_coord;
+ MvdHwReg bsd_slice_start;
+ MvdHwReg bsd_slice_param1;
+ MvdHwReg bsd_slice_param2;
+ MvdHwReg qm_dec_start;
+ MvdHwReg qm_dec_status;
+ MvdHwReg qm_load_start;
+ MvdHwReg qm_load_value;
+ MvdHwReg bsd_pwt_dec; // W
+ MvdHwReg bsd_egd_ue;
+ MvdHwReg bsd_egd_se;
+ MvdHwReg bsd_egd_me_intra;
+ MvdHwReg bsd_egd_me_inter;
+ MvdHwReg bsd_data_reg; // R/W
+ // 0x50 --> 0x5f
+ MvdHwReg ibb_buf_mode;
+ MvdHwReg ibb_buf_ctrl;
+ MvdHwReg ibb_buf_status;
+ MvdHwReg bsd_image_init;
+ MvdHwReg unused_bsd_0[4];
+ MvdHwReg bsd_pause;
+ MvdHwReg unused_bsd[16-9-4];
+ MvdHwReg bsd_err_mask;
+ MvdHwReg bsd_bit_puller;
+ MvdHwReg bsd_is_trailing;
+ MvdHwReg bsd_bbb_status; // R
+ // 0x60 --> 0x7f
+ union
+ {
+ MvdHwReg bsd_byte_align;
+ MvdHwReg bsd_getbits[32];
+ } get_bits;
+ //------- MPR/PXD address
+ // 0x80 --> 0x9f
+ MvdHwReg mpr_top_poc;
+ MvdHwReg mpr_bot_poc;
+ MvdHwReg unused_mpr[32-2];
+ // 0xa0 --> 0xbf
+ MvdHwReg mpr_list[32];
+ //------- DBF address
+ // 0xc0 --> 0xff
+ MvdHwReg unused_dbf[64];
+ // 0x100 --> 0x1bf not used
+ MvdHwReg unsued_spare_128[128];
+ MvdHwReg bsd_debug;
+ MvdHwReg pxd_debug;
+ MvdHwReg arb_wr_debug;
+ MvdHwReg arb_rd_debug;
+ MvdHwReg arb_mbi_debug;
+ MvdHwReg unsued_spare[59];
+
+} MvdHwRegH264Map;
+
+/////////////////////////////////////////////////////////////////
+// VC-1 Reg Map
+//
+
+typedef struct MvdHwRegVc1dMapTag
+{
+ //------- TOP address, 0x00 --> 0x3f
+ MvdHwReg unused_gen64[64];
+ //-- BSP address, 0x40 --> 0x7f
+ // 0x40 --> 0x5f
+ union
+ {
+ MvdHwReg bsp_byte_align;
+ MvdHwReg bsp_getbits[32];
+ } get_bits;
+ // 0x60 --> 0x6f
+ MvdHwReg bsp_status;
+ MvdHwReg bsp_control;
+ MvdHwReg bsp_showbits;
+ MvdHwReg bsp_showbitsflipped;
+ MvdHwReg bsp_ignorebbblevel;
+ MvdHwReg unused_bsp11[11];
+ // 0x70 --> 0x7f
+ MvdHwReg bsp_hdrvlc_ptype;
+ MvdHwReg bsp_hdrvlc_pptype;
+ MvdHwReg bsp_hdrvlc_mvrange;
+ MvdHwReg bsp_hdrvlc_mvmode;
+ MvdHwReg bsp_hdrvlc_mvmode2;
+ MvdHwReg bsp_hdrvlc_dmvrange;
+ MvdHwReg bsp_hdrvlc_bppmode;
+ MvdHwReg bsp_hdrvlc_bppvlc2;
+ MvdHwReg bsp_hdrvlc_bppvlc6;
+ MvdHwReg bsp_hdrvlc_bfract;
+ MvdHwReg bsp_hdrvlc_refdist;
+ MvdHwReg unused_bsp5[5];
+ // 0x80 --> 0x8f
+ MvdHwReg spr_general;
+ MvdHwReg spr_stream_format1;
+ MvdHwReg spr_coded_size;
+ MvdHwReg spr_stream_format2;
+ MvdHwReg spr_entrypoint1;
+ MvdHwReg spr_range_map;
+ MvdHwReg spr_frame_type;
+ MvdHwReg spr_recon_control;
+ MvdHwReg spr_mv_control;
+ MvdHwReg spr_int_comp_fwd_topnorm;
+ MvdHwReg spr_ref_bfraction;
+ MvdHwReg spr_blk_control;
+ MvdHwReg spr_trans_data;
+ MvdHwReg spr_vop_dquant;
+ MvdHwReg spr_curref_frm_id;
+ MvdHwReg spr_curdisp_frm_id;
+ // 0x90 --> 0x9f
+ MvdHwReg spr_fwdref_frm_id;
+ MvdHwReg spr_bwdref_frm_id;
+ MvdHwReg spr_fieldref_ctrl_id;
+ MvdHwReg spr_auxfrmctrl;
+ MvdHwReg spr_imgstruct;
+ MvdHwReg spr_alt_frame_type;
+ MvdHwReg spr_int_comp_fwd_bot;
+ MvdHwReg spr_int_comp_bwd_top;
+ MvdHwReg spr_int_comp_bwd_bot;
+ MvdHwReg unused_spr7[7];
+ // 0xa0 --> 0xbf
+ MvdHwReg unused_spr32[32];
+ // 0xc0 --> 0xcf
+ MvdHwReg mbd_status;
+ MvdHwReg mbd_frm_start;
+ MvdHwReg mbd_fwdebug;
+ MvdHwReg mbd_mbqdebug;
+ MvdHwReg mbd_mprdebug;
+ MvdHwReg mbd_masdebug;
+ MvdHwReg mbd_bppdebug;
+ MvdHwReg mbd_dpbmcdebug;
+ MvdHwReg mbd_gendebug;
+ MvdHwReg mbd_fw_rw;
+ MvdHwReg unused_6[6];
+ // 0xd0 --> 0xdf
+ MvdHwReg mbd_error_control;
+ MvdHwReg unused_mbd15[15];
+ // 0xe0 --> 0xff;
+ MvdHwReg unused_mbd32[32];
+ //------- BPP address
+ // 0x100 --> 0x10f
+ MvdHwReg bpp_control_status;
+ MvdHwReg bpp_datain_status;
+ MvdHwReg bpp_datain_value;
+ MvdHwReg bpp_datain_possize;
+ MvdHwReg bpp_bcachetag0;
+ MvdHwReg bpp_bcachetag1;
+ MvdHwReg bpp_bcachetag2;
+ MvdHwReg unused_0x107[9];
+ // 0x110 --> 0x1bf not used
+ MvdHwReg unsued_spare[176];
+
+} MvdHwRegVc1dMap;
+
+/////////////////////////////////////////////////////////////////
+// MPEG-2 Reg Map
+//
+
+typedef struct MvdHwRegMp2dMapTag
+{
+ //------- TOP address, 0x00 --> 0x3f
+ // 0x00 --> 0x3f
+ MvdHwReg top_seq_param;
+ MvdHwReg top_frame_ptr;
+ MvdHwReg top_pic_start;
+ MvdHwReg unused_top[64-3];
+ //------- BSD address, 0x40 --> 0x7f
+ // 0x40 --> 0x5f
+ MvdHwReg bsd_show_bits;
+ MvdHwReg bsd_dec_status;
+ MvdHwReg bsd_bbb_status;
+ MvdHwReg bsd_qm_status;
+ MvdHwReg bsd_qm_load;
+ MvdHwReg bsd_pic_param;
+ MvdHwReg bsd_slice_start;
+ MvdHwReg bsd_curr_mbcoord;
+ MvdHwReg unused_bsd[32-8];
+ // 0x60 --> 0x7f
+ union
+ {
+ MvdHwReg bsd_byte_align;
+ MvdHwReg bsd_getbits[32];
+ } get_bits;
+ // 0x80 --> 0xff
+ MvdHwReg unused_128[128];
+ //------- DBF address
+ // 0x100 --> 0x17f
+ MvdHwReg unused_dbf16[16];
+ MvdHwReg dbf_ctrl0;
+ MvdHwReg dbf_ctrl1;
+ MvdHwReg dbf_ctrl2;
+ MvdHwReg dbf_ctrl3;
+ MvdHwReg unused_dbf[128-20];
+ //------ DEBUG address
+ // 0x180 --> 0x1bf
+ MvdHwReg debug_bsd;
+ MvdHwReg debug_pxd_idct;
+ MvdHwReg debug_wr_arbiter;
+ MvdHwReg debug_rd_arbiter;
+ MvdHwReg unused_debug[64-4];
+
+} MvdHwRegMp2dMap;
+
+/////////////////////////////////////////////////////////////////
+// AVS Reg Map
+//
+
+// `define AVSD_APB_ADDR_TOP_PREFIX 3'h1 // 0x40
+// `define AVSD_APB_ADDR_BSD_PREFIX 3'h0 // 0x00
+// `define AVSD_APB_ADDR_MPR_PREFIX 3'h2 // 0x80
+#define MVD_AVSD_TOP_MIN_ADDR 0x00
+#define MVD_AVSD_BSD_MIN_ADDR 0x40
+#define MVD_AVSD_MPR_MIN_ADDR 0x80
+
+//-- Top level Register address
+#define MVD_AVSD_TOP_SEQ_PARAM_ADDR 0x00 // W/R, Chroma422
+#define MVD_AVSD_TOP_FRAME_PTR_ADDR 0x01 // W/R, cur_dec_ptr, bwd_ref_ptr, fwd_ref_ptr
+#define MVD_AVSD_TOP_PICT_START_ADDR 0x02 // W/R, is_2nd_fld, top_fild_1st, coding_type, pict_struct
+#define MVD_AVSD_TOP_PICT_PARAM_ADDR 0x03 // W/R
+
+//-- BSD Register address
+#define MVD_AVSD_BSD_SHOW_BITS_ADDR 0x40 // R, show available bits (up to 31), lsb aligned
+#define MVD_AVSD_BSD_DEC_STATUS_ADDR 0x41 // R, returns {1'b0, vld_mb_y, 1'b0, vld_mb_x, VldState, vld_error, img_in_prog, slice_in_prog}
+#define MVD_AVSD_BSD_BBB_STATUS_ADDR 0x42 // R, returns {6'd0, bits_ei_flag, bbb_underflow, 6'd0, bbb_is_stuffing, bits_ended, 10'd0, num_bits_in_bbb}
+#define MVD_AVSD_BSD_SCEPB_CTRL_ADDR 0x43 // W/R, {scepb_disab, scepb_delay}
+#define MVD_AVSD_BSD_EGDUE_START_ADDR 0x44 // R, start UE decode, [0]: ready in 3 ticks, [1]: out of range(dec not performed)
+#define MVD_AVSD_BSD_EGDSE_START_ADDR 0x45 // R, start SE decode, [0]: ready in 3 ticks, [1]: out of range(dec not performed)
+#define MVD_AVSD_BSD_SLC_START_ADDR 0x46 // W/R, {24'd0, vld_recover, vld_new_mbrow}
+#define MVD_AVSD_BSD_CURR_MBCOORD_ADDR 0x47 // R/W
+#define MVD_AVSD_BSD_EGD_VALUE_ADDR 0x48 // R, exp-golumn decode value
+#define MVD_AVSD_BSD_ERRCHK_MASK_ADDR 0x49 // R/W
+#define MVD_AVSD_BSD_ERROR_STAT_ADDR 0x4a // R, cleard at start of a slice
+
+#define MVD_AVSD_BSD_BYTE_ALIGN_ADDR 0x60
+#define MVD_AVSD_BSD_GETBITS_MIN_ADDR 0x60 // MVD_AVSD_BSD_ALIGN_BYTE_ADDR
+#define MVD_AVSD_BSD_GETBITS_MAX_ADDR 0x7f // 31 bits
+
+//-- MPR register address
+#define MVD_AVSD_MPR_WT_PARAM0_ADDR 0x80 // R/W
+#define MVD_AVSD_MPR_WT_PARAM1_ADDR 0x81 // R/W
+#define MVD_AVSD_MPR_WT_PARAM2_ADDR 0x82 // R/W
+#define MVD_AVSD_MPR_WT_PARAM3_ADDR 0x83 // R/W
+#define MVD_AVSD_MPR_BWD_DIST_ADDR 0x84 // when P picture, use bwd0,1 as fwd0,1
+#define MVD_AVSD_MPR_FWD_DIST_ADDR 0x85 // when P picture, use fwd0,1 as fwd2,3
+#define MVD_AVSD_MPR_REF01_DIST_ADDR 0x86
+#define MVD_AVSD_MPR_REF23_DIST_ADDR 0x87
+#define MVD_AVSD_MPR_BWD_DISTIDX_ADDR 0x88 // when P picture, use bwd0,1 as fwd0,1
+#define MVD_AVSD_MPR_FWD_DISTIDX_ADDR 0x89 // when P picture, use fwd0,1 as fwd2,3
+#define MVD_AVSD_MPR_REF01_DISTIDX_ADDR 0x8a
+#define MVD_AVSD_MPR_REF23_DISTIDX_ADDR 0x8b
+#define MVD_AVSD_MPR_CONFIG_OPTS_ADDR 0x8c
+
+typedef struct MvdHwRegAvsdMapTag {
+ //------- TOP address, 0x00 --> 0x3f
+ // 0x00 --> 0x3f
+ MvdHwReg top_seq_param;
+ MvdHwReg top_frame_ptr;
+ MvdHwReg top_pict_start;
+ MvdHwReg top_pict_param;
+ MvdHwReg unused_top[64-4];
+ //------- BSD address, 0x40 --> 0x7f
+ // 0x40 --> 0x5f
+ MvdHwReg bsd_show_bits;
+ MvdHwReg bsd_dec_status;
+ MvdHwReg bsd_bbb_status;
+ MvdHwReg bsd_scepb_ctrl;
+ MvdHwReg bsd_egdue_start;
+ MvdHwReg bsd_egdse_start;
+ MvdHwReg bsd_slc_start;
+ MvdHwReg bsd_curr_mbcoord;
+ MvdHwReg bsd_egd_value;
+ MvdHwReg bsd_errchk_mask;
+ MvdHwReg bsd_error_stat;
+ MvdHwReg bsd_qp_delta_uv;
+ MvdHwReg bsd_wqm1_low;
+ MvdHwReg bsd_wqm1_high;
+ MvdHwReg bsd_wqm2_low;
+ MvdHwReg bsd_wqm2_high;
+ MvdHwReg bsd_qp_ctr;
+ MvdHwReg unused_bsd[32-17];
+ //MvdHwReg unused_bsd[32-11];
+ // 0x60 --> 0x7f
+ union
+ {
+ MvdHwReg bsd_byte_align;
+ MvdHwReg bsd_getbits[32];
+ } get_bits;
+ //------- MPR address
+ // 0x80 --> 0xbf
+ MvdHwReg mpr_wt_param[4];
+ MvdHwReg mpr_bwd_dist;
+ MvdHwReg mpr_fwd_dist;
+ MvdHwReg mpr_ref01_dist;
+ MvdHwReg mpr_ref23_dist;
+ MvdHwReg mpr_bwd_distidx;
+ MvdHwReg mpr_fwd_distidx;
+ MvdHwReg mpr_ref01_distidx;
+ MvdHwReg mpr_ref23_distidx;
+ MvdHwReg mpr_config_opts;
+ MvdHwReg unused_mpr[64-13];
+ // 0xc0 --> 0x1bf not used
+ MvdHwReg unsued_spare[256];
+
+} MvdHwRegAvsdMap;
+
+/////////////////////////////////////////////////////////////////
+// ASPD/DIVX/JPEG Reg Map
+//
+
+//`define ASPD_APB_ADDR_TOP_PREFIX 3'h0 // 0x00
+//`define ASPD_APB_ADDR_BSD_PREFIX 3'h1 // 0x40
+//`define ASPD_APB_ADDR_MPR_PREFIX 3'h2 // 0x80
+//`define ASPD_APB_ADDR_PXD_PREFIX 3'h3 // 0xc0
+//`define ASPD_APB_ADDR_DBF_PREFIX 3'h4 // 0x100
+#define MVD_ASPD_TOP_MIN_ADDR 0x00
+#define MVD_ASPD_BSD_MIN_ADDR 0x40
+#define MVD_ASPD_MPR_MIN_ADDR 0x80
+#define MVD_ASPD_DBF_MIN_ADDR 0x100
+
+//-- Top level Register address
+#define MVD_ASPD_TOP_IMG_START_ADDR 0x00
+#define MVD_ASPD_TOP_VO_PARAM_ADDR 0x01
+#define MVD_ASPD_TOP_FRAME_PTR_ADDR 0x02 // W/R, cur_dec_ptr, bwd_ref_ptr, fwd_ref_ptr
+#define MVD_ASPD_TOP_VPARAM1_ADDR 0x03
+#define MVD_ASPD_TOP_VPARAM2_ADDR 0x04
+#define MVD_ASPD_TOP_VPARAM3_ADDR 0x05
+#define MVD_ASPD_TOP_VO_PARAM_EXT_ADDR 0x06
+
+//-- BSD Register address
+#define MVD_ASPD_BSD_SHOW_BITS_ADDR 0x40 // R, show available bits (up to 31), lsb aligned
+#define MVD_ASPD_BSD_DEC_STATUS_ADDR 0x41 // R, returns {1'b0, vld_mb_y, 1'b0, vld_mb_x, VldState, vld_error, img_in_prog, slice_in_prog}
+#define MVD_ASPD_BSD_BBB_STATUS_ADDR 0x42 // R, returns {6'd0, bits_ei_flag, bbb_underflow, 6'd0, bbb_is_stuffing, bits_ended, 10'd0, num_bits_in_bbb}
+#define MVD_ASPD_BSD_SLC_START_ADDR 0x46 // W/R, {24'd0, vld_recover, vld_new_mbrow}
+#define MVD_ASPD_BSD_CURR_MBCOORD_ADDR 0x47 // R/W
+#define MVD_ASPD_BSD_OPTIONS_ADDR 0x49 // R/W
+
+// JPEG DC Predictor registers
+#define MVD_ASPB_BSD_JPEG_CTX0_ADDR 0x4a // R/W, must be backup when doing multiple JPEG images
+#define MVD_ASPB_BSD_JPEG_CTX1_ADDR 0x4b // R/W, must be backup when doing multiple JPEG images
+
+#define MVD_ASPD_BSD_BYTE_ALIGN_ADDR 0x60
+#define MVD_ASPD_BSD_GETBITS_MIN_ADDR 0x60 // MVD_ASPD_BSD_ALIGN_BYTE_ADDR
+#define MVD_ASPD_BSD_GETBITS_MAX_ADDR 0x7f // 31 bits
+
+//-- MPR GMC register address
+#define MVD_ASPD_GMC_ATLUM_X0_ADDR 0x90 // R/W, atlum->X0, 18 bits, signed
+#define MVD_ASPD_GMC_ATLUM_Y0_ADDR 0x91 // R/W, atlum->Y0, 18 bits, signed
+#define MVD_ASPD_GMC_ATLUM_YXXX_ADDR 0x92 // R/W, {atlum->YX, atlum->XX}, 16 bits each, signed
+#define MVD_ASPD_GMC_ATLUM_XYYY_ADDR 0x93 // R/W, {atlum->XY, atlum->YY}, 16 bits each, signed
+#define MVD_ASPD_GMC_ATCHR_X0_ADDR 0x94 // R/W, atchr->X0, 28 bits, signed
+#define MVD_ASPD_GMC_ATCHR_Y0_ADDR 0x95 // R/W, atchr->Y0, 28 bits, signed
+#define MVD_ASPD_GMC_ATCHR_YXXX_ADDR 0x96 // R/W, {atchr->YX, atchr->XX}, 16 bits each, signed
+#define MVD_ASPD_GMC_ATCHR_XYYY_ADDR 0x97 // R/W, {atchr->XY, atchr->YY}, 16 bits each, signed
+#define MVD_ASPD_GMC_PARAM_ADDR 0x98 // R/W, {5'd0, fcode_gmc, 6'd0, warp_accuracy, 3'd0, atchr_shift, 3'd0, atlum_shift}
+
+#define MVD_ASPD_MPR_OPTS_ADDR 0x99 // R/W {26'b0,mpr_opts}
+
+#define ASPD_PXD_STATUS_ADDR 0xc0
+#define ASPD_PXD_QM_CTRL_ADDR 0xc1
+#define ASPD_PXD_WR_QMDATA_ADDR 0xc2
+
+//-- DBF registers -- these are the same as those for MP2D
+#define MVD_ASPD_DBF_CTRL0_ADDR 0x110 // Kevin Lim's POSTP_DEBLK_CTRL0
+#define MVD_ASPD_DBF_CTRL1_ADDR 0x111 // Kevin Lim's POSTP_DEBLK_CTRL1
+#define MVD_ASPD_DBF_CTRL2_ADDR 0x112 // Kevin Lim's POSTP_DEBLK_CTRL2
+#define MVD_ASPD_DBF_CTRL3_ADDR 0x113 // Kevin Lim's POSTP_DEBLK_CTRL3
+
+typedef struct MvdHwRegAspdMapTag
+{
+ //------- TOP address, 0x00 --> 0x3f
+ // 0x00 --> 0x3f
+ MvdHwReg top_img_start;
+ MvdHwReg top_vo_param;
+ MvdHwReg top_frame_ptr;
+ MvdHwReg top_vparam1;
+ MvdHwReg top_vparam2;
+ MvdHwReg top_vparam3;
+ MvdHwReg top_vo_param_ext;
+ MvdHwReg top_vparam4;
+ MvdHwReg top_vparam5;
+ MvdHwReg unused_top[64-9];
+ //------- BSD address, 0x40 --> 0x7f
+ // 0x40 --> 0x5f
+ MvdHwReg bsd_show_bits;
+ MvdHwReg bsd_dec_status;
+ MvdHwReg bsd_bbb_status;
+ MvdHwReg bsd_scepb_ctrl;
+ MvdHwReg unused_0x04;
+ MvdHwReg unused_0x05;
+ MvdHwReg bsd_slc_start;
+ MvdHwReg bsd_curr_mbcoord;
+ MvdHwReg unused_0x08;
+ MvdHwReg bsd_options;
+ MvdHwReg bsd_jpeg_ctx0;
+ MvdHwReg bsd_jpeg_ctx1;
+ MvdHwReg unused_bsd[32-12];
+ // 0x60 --> 0x7f
+ union
+ {
+ MvdHwReg bsd_byte_align;
+ MvdHwReg bsd_getbits[32];
+ } get_bits;
+ //------- MPR/PXD/GMC address
+ // 0x80 --> 0xbf
+ MvdHwReg unused_mpr16[16];
+ MvdHwReg gmc_atlum_x0;
+ MvdHwReg gmc_atlum_y0;
+ MvdHwReg gmc_atlum_yxxx;
+ MvdHwReg gmc_atlum_xyyy;
+ MvdHwReg gmc_atchr_x0;
+ MvdHwReg gmc_atchr_y0;
+ MvdHwReg gmc_atchr_yxxx;
+ MvdHwReg gmc_atchr_xyyy;
+ MvdHwReg gmc_param;
+ MvdHwReg mpr_opts;
+ MvdHwReg unused_mpr38[64-16-10];
+ // 0xc0 --> 0xff
+ MvdHwReg pxd_qm_status;
+ MvdHwReg pxd_qm_ctrl;
+ MvdHwReg pxd_qm_data;
+ MvdHwReg unused_pxd61[61];
+ //------- DBF address
+ // 0x100 --> 0x17f
+ MvdHwReg unused_dbf16[16];
+ MvdHwReg dbf_ctrl0;
+ MvdHwReg dbf_ctrl1;
+ MvdHwReg dbf_ctrl2;
+ MvdHwReg dbf_ctrl3;
+ MvdHwReg unused_dbf108[108];
+ // 0x180 --> 0x1bf not used
+ MvdHwReg dbg_a;
+ MvdHwReg dbg_b;
+ MvdHwReg dbg_arb_wr;
+ MvdHwReg dbg_arb_rd;
+ MvdHwReg dbg_arb_mbi;
+ MvdHwReg unsued_spare[59];
+
+} MvdHwRegAspdMap;
+
+/////////////////////////////////////////////////////////////////
+// On2 Reg Map
+//
+
+typedef struct MvdHwRegOn2dMapTag {
+ //------- TOP address, 0x00 --> 0x3f
+ // 0x00 --> 0x3f
+ MvdHwReg top_img_start;
+ MvdHwReg top_param1;
+ MvdHwReg top_frame_ptr;
+ MvdHwReg top_param2;
+ MvdHwReg top_param3;
+ MvdHwReg top_param4;
+ MvdHwReg top_param5;
+ MvdHwReg top_param6;
+ MvdHwReg top_param7;
+ MvdHwReg top_param8;
+ MvdHwReg top_param9;
+ MvdHwReg top_param10;
+ MvdHwReg top_param11;
+ MvdHwReg top_param12;
+ MvdHwReg top_param13;
+ MvdHwReg top_param14;
+ MvdHwReg top_param15;
+ MvdHwReg top_param16;
+ MvdHwReg top_param17;
+ MvdHwReg top_param18;
+ MvdHwReg top_param19;
+ MvdHwReg top_param20;
+ MvdHwReg top_param21;
+ MvdHwReg top_param22;
+ MvdHwReg top_param23;
+ MvdHwReg top_param24;
+ MvdHwReg top_param25;
+ MvdHwReg top_param26;
+ MvdHwReg unused_top[64-28];
+
+ //------- BSD address, 0x40 --> 0x7f
+ // 0x40 --> 0x5f
+ MvdHwReg bsd_show_bits;
+ MvdHwReg bsd_dec_status;
+ MvdHwReg bsd_bbb_status;
+ MvdHwReg unused_0x03;
+ MvdHwReg bsd_mbd_status;
+ MvdHwReg unused_0x05;
+ MvdHwReg bsd_slc_start;
+ MvdHwReg bsd_curr_mbcoord;
+ MvdHwReg unused_0x08;
+ MvdHwReg bsd_options;
+ MvdHwReg bsd_arith_config;
+ MvdHwReg unused_0x0B;
+ MvdHwReg bsd_scan_start;
+ MvdHwReg bsd_scan_data;
+ MvdHwReg bsd_prob_start;
+ MvdHwReg bsd_prob_data;
+ MvdHwReg bsd_prob_status;
+ MvdHwReg unused_0x11;
+ MvdHwReg unused_0x12;
+ MvdHwReg unused_0x13;
+ MvdHwReg unused_0x14;
+ MvdHwReg unused_0x15;
+ MvdHwReg unused_0x16;
+ MvdHwReg unused_0x17;
+ MvdHwReg debug_status;
+ MvdHwReg debug_data0;
+ MvdHwReg debug_data1;
+ MvdHwReg unused_bsd[32-27];
+ // 0x60 --> 0x7f
+ union
+ {
+ MvdHwReg bsd_byte_align;
+ MvdHwReg bsd_getbits[32];
+ } get_bits;
+ // the rest are not used
+} MvdHwRegOn2dMap;
+
+/////////////////////////////////////////////////////////////////
+// RVid Reg Map
+//
+
+typedef struct MvdHwRegRvidMapTag
+{
+ //------- TOP address, 0x00 --> 0x3f
+ // 0x00 --> 0x3f
+ MvdHwReg top_img_start;
+ MvdHwReg top_param1;
+ MvdHwReg top_frame_ptr;
+ MvdHwReg top_param2;
+ MvdHwReg top_param3;
+ MvdHwReg top_param4;
+ MvdHwReg unused_top[64-6];
+
+ //------- BSD address, 0x40 --> 0x7f
+ // 0x40 --> 0x5f
+ MvdHwReg bsd_show_bits;
+ MvdHwReg bsd_dec_status;
+ MvdHwReg bsd_bbb_status;
+ MvdHwReg unused_0x03;
+ MvdHwReg bsd_mbd_status;
+ MvdHwReg unused_0x05;
+ MvdHwReg bsd_slc_start;
+ MvdHwReg bsd_curr_mbcoord;
+ MvdHwReg unused_0x08;
+ MvdHwReg bsd_options;
+ MvdHwReg bsd_rsb_missing;
+ MvdHwReg bsd_mb_qp;
+ MvdHwReg unused_bsd[32-12];
+ // 0x60 --> 0x7f
+ union
+ {
+ MvdHwReg bsd_byte_align;
+ MvdHwReg bsd_getbits[32];
+ } get_bits;
+ // the rest are not used
+} MvdHwRegRvidMap;
+
+/////////////////////////////////////////////////////////////////
+// HEVC Reg Map
+//
+
+typedef struct MvdHwRegHevcMapTag
+{
+
+ /* TOP address, 0x00 --> 0x3f */
+ MvdHwReg image_config; // R/W
+ MvdHwReg slice_config; // R/W
+ MvdHwReg top_ctb_tile_info; // R/W
+ MvdHwReg mbi_wr_base; // R/W
+ MvdHwReg mbi_rd_base; // R/W
+
+ MvdHwReg dec_cfg; // R/W
+ MvdHwReg dbg_cfg; // R/W
+ MvdHwReg dbf1_cfg; // R/W
+ MvdHwReg dbf2_cfg; // R/W
+ MvdHwReg dbe_frm_size; // R/W
+ MvdHwReg prb_pack_base; // R/W
+ MvdHwReg prb_bin_cfg; // R/W
+ MvdHwReg dcp_bin_cfg; // R/W
+
+ MvdHwReg unused_top[64-13];
+
+ /* BSD address, 0x40 --> 0x7f */
+ MvdHwReg bsd_options;
+ MvdHwReg bsd_dec_status;
+ MvdHwReg bsd_ctb_coord;
+ MvdHwReg bsd_slice_start;
+ MvdHwReg bsd_dec_param1;
+ MvdHwReg bsd_dec_param2;
+ MvdHwReg bsd_dec_ctb_cnt;
+ MvdHwReg bsd_dec_err_ctb_cnt;
+ MvdHwReg bsd_dec_ctb_qp_sum;
+
+ MvdHwReg bsd_plq_levels;
+ MvdHwReg Unused_A;
+
+ MvdHwReg bsd_ue;
+ MvdHwReg bsd_se;
+ MvdHwReg Unused_D;
+ MvdHwReg Unused_E;
+ MvdHwReg bsd_data;
+
+ MvdHwReg Unused_10;
+ MvdHwReg bsd_ctb_tile_px4;
+ MvdHwReg bsd_ctb_tile_py4;
+ MvdHwReg bsd_ctb_tile_px8;
+ MvdHwReg bsd_ctb_tile_py8;
+ MvdHwReg bsd_ctb_tile_px9_y10;
+ MvdHwReg bsd_sc_list_usage;
+ MvdHwReg bsd_sc_list_base;
+ MvdHwReg bsd_sc_list_idx[4];
+ MvdHwReg bsd_ei_flags_mask;
+ MvdHwReg bsd_bit_puller;
+ MvdHwReg bsd_is_trailing;
+ MvdHwReg bsd_bbb_status;
+
+ union
+ {
+ MvdHwReg bsd_byte_align;
+ MvdHwReg bsd_getbits[32];
+ } get_bits;
+
+ /* MPR address, 0x80 --> 0xBF */
+ MvdHwReg mpr_config;
+ MvdHwReg mpr_slice_param;
+
+ MvdHwReg Unused_82_9F[30];
+
+ MvdHwReg mpr_list[32];
+
+ MvdHwReg Unused_0xC0_FF[64];
+
+ /* dfe address, 0x100 --> 0x103 */
+ MvdHwReg dfe_status;
+ MvdHwReg dfe_num_pr_bits;
+ MvdHwReg dfe_row_crc;
+ MvdHwReg dfe_num_bins_used;
+ MvdHwReg Unused_DFE[60];
+
+ MvdHwReg Unused_0x140_17F[64];
+
+ MvdHwReg mpr_dbg;
+ MvdHwReg pxd_dbg;
+ MvdHwReg dbf_dbg;
+ MvdHwReg wr_arb_dbg;
+ MvdHwReg rd_arb_dbg;
+ MvdHwReg mbi_rd_arb_dbg;
+ MvdHwReg mbi_wr_arb_dbg;
+ MvdHwReg Unused_DBG[64-7];
+
+} MvdHwRegHevcMap;
+
+///////////////////////////////////////////////////////////////////////////////////////
+// Top address mapping struct
+//
+// The base decoder address to be passed should be that of the HIF registers
+// not the RSB registers
+//
+// Minor non-backwards compatible address map change between Kronos
+// and Krome...
+
+/* *********************************************************** */
+/* Kronos */
+/* */
+/* MvdHwReg hif[1024]; */
+/* MvdHwReg sif[128]; */
+/* MvdHwReg ctx[128]; */
+/* MvdHwReg rpr[32]; */
+/* MvdHwReg unused[32]; */
+/* MvdHwReg bbd[32]; -- BL only -- */
+/* MvdHwReg dbg[32]; -- EL only -- */
+/* MvdHwReg spp[128]; */
+/* MvdHwReg dec[512-64]; */
+/* */
+/* *********************************************************** */
+
+/* *********************************************************** */
+/* Krome */
+/* */
+/* Base Malone: Enhancement Malone */
+/* */
+/* MvdHwReg hif[1024]; MvdHwReg hif[1024]; */
+/* MvdHwReg sif[128]; MvdHwReg sif[128]; */
+/* MvdHwReg ctx[128]; MvdHwReg ctx[128]; */
+/* MvdHwReg rpr[32]; MvdHwReg rpr[32]; */
+/* MvdHwReg unused[32]; MvdHwReg unused[32]; */
+/* MvdHwReg bbd[32]; MvdHwReg dbg[32]; */
+/* MvdHwReg cq[32]; MvdHwReg cq[32]; */
+/* MvdHwReg spp[128]; MvdHwReg spp[128]; */
+/* MvdHwReg dec[512-64]; MvdHwReg dec[512-64]; */
+/* */
+/* *********************************************************** */
+
+typedef struct MvdHwRegMapTag
+{
+ //------------- 8KB MSD address -------------
+ /* 4KB HIF address space */
+ union
+ {
+ MvdHwReg hif[1024];
+ MvdHwRegHifMap hif_map;
+ } HifMap;
+
+ /* 0.5KB SIF address space */
+ union
+ {
+ MvdHwReg sif[128];
+ MvdHwRegSifMap sif_map;
+ } SifMap;
+
+ /* 0.5KB CTX address space */
+ union
+ {
+ MvdHwReg ctx[128];
+ MvdHwRegCtxMap ctx_map;
+ } CtxMap;
+
+ /* 128 B RPR address space */
+ union
+ {
+ MvdHwReg rpr[32];
+ MvdHwRegRprMap rpr_map;
+ } RprMap;
+
+ /* 128 B RC4 address space */
+ union
+ {
+ MvdHwReg RC4[32];
+ MvdHwRegRC4Map RC4_map;
+ } RC4Map;
+
+ /* 128 B DBG address space */
+ union
+ {
+ MvdHwReg dbg[32];
+ MvdHwRegDbgMap dbg_map;
+ } DbgMap;
+
+ /* 128 B CQ address space */
+ union
+ {
+ MvdHwReg cq[32];
+ MvdHwRegCqMap cq_map;
+ MvdHwRegDbgMap dbg_map;
+ } CqMap;
+
+ /* 0.5KB SPP address space */
+ union
+ {
+ MvdHwReg spp[128];
+ MvdHwRegSppMap spp_map;
+ } SppMap;
+
+ /* 1.75KB decoder address space */
+ union
+ {
+ MvdHwReg dec[512-64];
+ MvdHwRegH264Map h264_map;
+ MvdHwRegVc1dMap vc1d_map;
+ MvdHwRegMp2dMap mp2d_map;
+ MvdHwRegAvsdMap avsd_map;
+ MvdHwRegAspdMap aspd_map;
+ MvdHwRegRvidMap rvid_map;
+ MvdHwRegOn2dMap on2d_map;
+ MvdHwRegHevcMap hevc_map;
+ } DecMap;
+
+ /* 0.25kB BBD address space */
+ union
+ {
+ MvdHwReg bbd[64];
+ MvdHwRegBbdMap bbd_map;
+ MvdHwRegDbgMap dbg_map;
+ } BbdMap;
+
+ /* 4KB Decoupled unit space */
+ union
+ {
+ MvdHwReg dcp[1024];
+ MvdHwRegDfeMap dfe_map;
+ MvdHwRegDbeMap dbe_map[2];
+ } DcpMap;
+
+ /* 0.25 KB FBC address space */
+ union
+ {
+ MvdHwReg fbc[64];
+ MvdHwRegFbcMap fbc_map;
+ } FbcMap;
+
+ /* 3.75 KB Special address */
+ MvdHwReg spc[1024 - 64];
+
+} MvdHwRegMap;
+
+///////////////////////////////////////////////////////////////////////////////////////
+// DPV address map
+//
+
+typedef struct
+{
+ MvdHwReg YFrameCRC;
+ MvdHwReg YTopFieldCRC;
+ MvdHwReg YBotFieldCRC;
+ MvdHwReg UVFrameCRC;
+ MvdHwReg UVTopFieldCRC;
+ MvdHwReg UVBotFieldCRC;
+
+} MvdHwRegA3CRCRegMap;
+
+
+typedef struct
+{
+ MvdHwReg YWordLower;
+ MvdHwReg UWordLower;
+ MvdHwReg VWordLower;
+ MvdHwReg YWordUpper;
+ MvdHwReg UWordUpper;
+ MvdHwReg VWordUpper;
+
+} MvdHwRegMD5RegMap;
+
+typedef struct
+{
+ MvdHwReg YFrameCRC;
+ MvdHwReg UFrameCRC;
+ MvdHwReg VFrameCRC;
+
+} MvdHwRegHashCRCRegMap;
+
+typedef struct
+{
+ MvdHwReg YCheckSum;
+ MvdHwReg UCheckSum;
+ MvdHwReg VCheckSum;
+
+} MvdHwRegHashChkSumRegMap;
+
+typedef struct
+{ //DCSN_CFG_BASE_MMIO | 0x1FC000 => 0xE07FC000
+ MvdHwReg Control;
+ MvdHwReg Status;
+ MvdHwReg DTLReadCalib;
+ MvdHwReg CropTopLeft;
+ MvdHwReg CropBotRight;
+ MvdHwReg LumaBase;
+ MvdHwReg ChromaBase;
+
+ union
+ {
+ MvdHwReg Digest[0x6];
+ MvdHwRegA3CRCRegMap A3CRC;
+ MvdHwRegMD5RegMap MD5;
+ MvdHwRegHashCRCRegMap HashCRC;
+ MvdHwRegHashChkSumRegMap HashCheckSum;
+
+ } DigestMap0;
+
+ MvdHwReg Stride;
+
+ /* For code readability - this is added as a union */
+ /* but in fact the registers are valid only in MD5 mode */
+ union
+ {
+ MvdHwReg Digest[0x6];
+ MvdHwRegA3CRCRegMap A3CRC;
+ MvdHwRegMD5RegMap MD5;
+ MvdHwRegHashCRCRegMap HashCRC;
+ MvdHwRegHashChkSumRegMap HashCheckSum;
+
+ } DigestMap1;
+
+ MvdHwReg Scratch[0x4];
+
+} MvdHwDPVRegMap;
+
+#endif /* _MVD_REG_MAP_H_ */
+
+/* End of file */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/mvd_sif_control.h b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/mvd_sif_control.h
new file mode 100755
index 000000000000..80dc48d6f40d
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/mvd_sif_control.h
@@ -0,0 +1,975 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+
+ Filename: mvd_sif_control.h
+ Description: Malone system interface
+ Notes:
+
+ ****************************************************/
+
+#ifndef _MVD_SIF_CONTROL_H_
+#define _MVD_SIF_CONTROL_H_
+
+/////////////////////////////////////////////////////////////////////////////////
+// Header files
+/////////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Macros
+/////////////////////////////////////////////////////////////////////////////////
+
+// SIF data range definitions
+#define MSD_SIF_FS_KBYTES_BITS(r) (((r)&0xFFFF0000)>>16)
+#define MSD_SIF_FRAME_SIZE_MB_BITS(r) ((r)&0xFFFF)
+#define MSD_PUT_SIF_FRAME_SIZE_MB_BITS(w) ((w)&0xFFFF)
+#define MSD_PUT_SIF_FS_KBYTES_BITS(w) (((w)&0xFFFF)<<16)
+
+#define MSD_PUT_FRAME_WIDTH_MB_BITS(w) ((w)&0xFF)
+#define MSD_PUT_FRAME_HEIGHT_MB_BITS(w) (((w)&0xFF)<<8)
+#define MSD_PUT_FRAME_SIZE_MB_BITS(w) (((w)&0xFFFF)<<16)
+
+#define MSD_DPB_IN_KBYTES_BITS(r) ((r)&0xFFFF)
+
+#define MPD_SIF_DISP_Q_CNT_BITS(r) ((r)&0xFF)
+#define MPD_SIF_DISP_Q_FULL_BITS(r) ((r>>8)&0x1)
+#define MPD_SIF_DISP_Q_REQ_BIT(r) ((r>>16)&0x1)
+
+#define MPD_SIF_DISP_Q_PUSH_FS_IDC_BITS(w) ((w)&0x1F)
+#define MPD_SIF_DISP_Q_PUSH_SPS_IDC_BITS(w) (((w)&0x7)<<16)
+#define MPD_SIF_DISP_Q_PUSH_DANG_FIELD_BIT(w) (((w)&0x1)<<19)
+#define MPD_SIF_DISP_Q_PUSH_FIELD_MODE_BIT(w) (((w)&0x2)<<19)
+#define MPD_SIF_DISP_Q_PUSH_BOT_FIRST_BIT(w) (((w)&0x1)<<21)
+#define MPD_SIF_DISP_Q_PUSH_SKIP_PIC_BITS(w) (((w)&0x3)<<22)
+#define MPD_SIF_DISP_Q_SYS_DATA_BITS(w) (((w)&0xFF)<<24)
+
+#define MPD_SIF_DISP_Q_PUSH_CRC_MODE_BIT(w) (((w)&0x1)<<20)
+
+#define MPD_SIF_FS_PACK_UNIT_BITS(r) ((r)&0x7)
+#define MPD_SIF_FS_BASE_UNIT_BITS(r) ((r>>12)&0x7)
+#define MPD_SIF_SYS_DATA_EDGE_BIT(r) ((r>>16)&0x1)
+#define MPD_SIF_BS_SYNC_USED_BIT(r) ((r>>17)&0x1)
+
+#define MPD_SIF_SYS_DATA_BITS(r) ((r)&0xFF)
+
+#define MPD_SIF_FRAME_DEC_IRQ_POS 1
+#define MPD_SIF_SLICE_DEC_IRQ_POS 2
+#define MPD_SIF_START_CODE_IRQ_POS 3
+#define MPD_SIF_SEMAPHORE_IRQ_BIT(r) ((r)&0x1)
+#define MPD_SIF_FRAME_DEC_IRQ_BIT(r) (((r)&0x2)>>1)
+#define MPD_SIF_SLICE_DEC_IRQ_BIT(r) (((r)&0x4)>>2)
+#define MPD_SIF_START_CODE_IRQ_BIT(r) (((r)&0x8)>>3)
+
+
+#define MSD_SIF_QPULL_IRQ_BIT(r) (((r)&0x10)>>4)
+#define MSD_SIF_QPULL_SHIFT 4
+#define MSD_SIF_QPULL_MASK 0x10
+#define MPD_SIF_BSDMA_IRQ_BIT(r) (((r)&0x80)>>7)
+#define PUT_MSD_STREAM_ID(w) ((w)&0xF)
+#define PUT_MSD_FORMAT(w) (((w)&0x3)<<4)
+
+// Sempahore reg bits
+#define FRAME_DISPLAYED_BITS(r) ((r)&0x1)
+
+// MSD_SIF_DPB_FS_SIZE_ADDR
+#define MSD_SIF_DPB_FS_WIDTH_IN_MB_POS 0
+#define MSD_SIF_DPB_FS_WIDTH_IN_MB_SIZE 8
+#define MSD_SIF_DPB_FS_WIDTH_IN_MB_MASK 0xff
+#define MSD_SIF_DPB_FS_HEIGHT_IN_MB_POS 8
+#define MSD_SIF_DPB_FS_HEIGHT_IN_MB_SIZE 8
+#define MSD_SIF_DPB_FS_HEIGHT_IN_MB_MASK 0xff
+#define MSD_SIF_DPB_FS_SIZE_KBYTES_POS 16
+#define MSD_SIF_DPB_FS_SIZE_KBYTES_SIZE 14
+#define MSD_SIF_DPB_FS_SIZE_KBYTES_MASK 0x3fff
+#define MSD_SIF_DPB_FS_SIZE_WIDTH_INMBS_GET(val) ((val>>MSD_SIF_DPB_FS_WIDTH_IN_MB_POS)&MSD_SIF_DPB_FS_WIDTH_IN_MB_MASK)
+#define MSD_SIF_DPB_FS_SIZE_HEIGHT_INMBS_GET(val) ((val>>MSD_SIF_DPB_FS_HEIGHT_IN_MB_POS)&MSD_SIF_DPB_FS_HEIGHT_IN_MB_MASK)
+#define MSD_SIF_DPB_FS_SIZE_KBYTES(val) ((val>>MSD_SIF_DPB_FS_SIZE_KBYTES_POS)&MSD_SIF_DPB_FS_SIZE_KBYTES_MASK)
+
+// MSD_SIF_DPB_FS_SIZE_EXT_ADDR
+#define MSD_SIF_DPB_FS_WIDTH_IN_MB_EXT_POS 0
+#define MSD_SIF_DPB_FS_WIDTH_IN_MB_EXT_SIZE 2
+#define MSD_SIF_DPB_FS_WIDTH_IN_MB_EXT_MASK 0x3
+#define MSD_SIF_DPB_FS_HEIGHT_IN_MB_EXT_POS 2
+#define MSD_SIF_DPB_FS_HEIGHT_IN_MB_EXT_SIZE 2
+#define MSD_SIF_DPB_FS_HEIGHT_IN_MB_EXT_MASK 0x3
+#define MSD_SIF_DPB_FS_SIZE_KBYTES_EXT_POS 4
+#define MSD_SIF_DPB_FS_SIZE_KBYTES_EXT_SIZE 3
+#define MSD_SIF_DPB_FS_SIZE_KBYTES_EXT_MASK 0x7
+#define MSD_SIF_DPB_FS_SIZE_WIDTH_INMBS_EXT_GET(val) ((val>>MSD_SIF_DPB_FS_WIDTH_IN_MB_POS)&MSD_SIF_DPB_FS_WIDTH_IN_MB_EXT_MASK)
+#define MSD_SIF_DPB_FS_SIZE_HEIGHT_INMBS_EXT_GET(val) ((val>>MSD_SIF_DPB_FS_HEIGHT_IN_MB_POS)&MSD_SIF_DPB_FS_HEIGHT_IN_MB_EXT_MASK)
+#define MSD_SIF_DPB_FS_SIZE_KBYTES_EXT(val) ((val>>MSD_SIF_DPB_FS_SIZE_KBYTES_POS)&MSD_SIF_DPB_FS_SIZE_KBYTES_MASK)
+
+//MSD_SIF_DPB_FRM_SIZE_ADDR
+#define MSD_SIF_DPB_FRM_WIDTH_IN_MB_POS 0
+#define MSD_SIF_DPB_FRM_WIDTH_IN_MB_SIZE 8
+#define MSD_SIF_DPB_FRM_WIDTH_IN_MB_MASK 0xff
+#define MSD_SIF_DPB_FRM_HEIGHT_IN_MB_POS 8
+#define MSD_SIF_DPB_FRM_HEIGHT_IN_MB_SIZE 8
+#define MSD_SIF_DPB_FRM_HEIGHT_IN_MB_MASK 0xff
+#define MSD_SIF_DPB_FRM_SIZE_MBS_POS 16
+#define MSD_SIF_DPB_FRM_SIZE_MBS_SIZE 16
+#define MSD_SIF_DPB_FRM_SIZE_MBS_MASK 0xffff
+#define MSD_SIF_DPB_FRM_SIZE_INMBS(val) ((val>>MSD_SIF_DPB_FRM_SIZE_MBS_POS)&MSD_SIF_DPB_FRM_SIZE_MBS_MASK)
+#define MSD_SIF_DPB_FRM_WIDTH_INMBS_GET(val) ((val>>MSD_SIF_DPB_FRM_WIDTH_IN_MB_POS)&MSD_SIF_DPB_FRM_WIDTH_IN_MB_MASK)
+#define MSD_SIF_DPB_FRM_HEIGHT_INMBS_GET(val) ((val>>MSD_SIF_DPB_FRM_HEIGHT_IN_MB_POS)&MSD_SIF_DPB_FRM_HEIGHT_IN_MB_MASK)
+
+//MSD_SIF_DPB_FRM_SIZE_EXT_ADDR
+#define MSD_SIF_DPB_FRM_WIDTH_IN_MB_EXT_POS 0
+#define MSD_SIF_DPB_FRM_WIDTH_IN_MB_EXT_SIZE 1
+#define MSD_SIF_DPB_FRM_WIDTH_IN_MB_EXT_MASK 0x1
+#define MSD_SIF_DPB_FRM_HEIGHT_IN_MB_EXT_POS 1
+#define MSD_SIF_DPB_FRM_HEIGHT_IN_MB_EXT_SIZE 1
+#define MSD_SIF_DPB_FRM_HEIGHT_IN_MB_EXT_MASK 0x1
+#define MSD_SIF_DPB_FRM_SIZE_MBS_EXT_POS 2
+#define MSD_SIF_DPB_FRM_SIZE_MBS_EXT_SIZE 3
+#define MSD_SIF_DPB_FRM_SIZE_MBS_EXT_MASK 0x7
+#define MSD_SIF_DPB_FRM_SIZE_INMBS_EXT(val) ((val>>MSD_SIF_DPB_FRM_SIZE_MBS_POS)&MSD_SIF_DPB_FRM_WIDTH_IN_MB_EXT_MASK)
+#define MSD_SIF_DPB_FRM_WIDTH_INMBS_EXT_GET(val) ((val>>MSD_SIF_DPB_FRM_WIDTH_IN_MB_POS)&MSD_SIF_DPB_FRM_HEIGHT_IN_MB_EXT_MASK)
+#define MSD_SIF_DPB_FRM_HEIGHT_INMBS_EXT_GET(val) ((val>>MSD_SIF_DPB_FRM_HEIGHT_IN_MB_POS)&MSD_SIF_DPB_FRM_SIZE_MBS_EXT_MASK)
+#define MSD_PUT_FRAME_WIDTH_MB_EXT_BITS(val) (((val>>8)&MSD_SIF_DPB_FRM_WIDTH_IN_MB_EXT_MASK)<<MSD_SIF_DPB_FRM_WIDTH_IN_MB_EXT_POS)
+#define MSD_PUT_FRAME_HEIGHT_MB_EXT_BITS(val) (((val>>8)&MSD_SIF_DPB_FRM_HEIGHT_IN_MB_EXT_MASK)<<MSD_SIF_DPB_FRM_HEIGHT_IN_MB_EXT_POS)
+#define MSD_PUT_FRAME_SIZE_MB_EXT_BITS(val) (((val>>16)&MSD_SIF_DPB_FRM_SIZE_MBS_EXT_MASK)<<MSD_SIF_DPB_FRM_SIZE_MBS_EXT_POS)
+
+
+//MSD_SIF_DPB_FS_SETTING_ADDR
+#define MSD_SIF_FS_PACK_UNIT_POS 0
+#define MSD_SIF_FS_PACK_UNIT_SIZE 3
+#define MSD_SIF_FS_PACK_UNIT(val) ((val>>MSD_SIF_FS_PACK_UNIT_POS)&0x7)
+#define MSD_SIF_FS_PACK_WIDTH_POS 4
+#define MSD_SIF_FS_PACK_WIDTH_SIZE 3
+#define MSD_SIF_FS_PACK_ID (1<<8)
+#define MSD_SIF_FRM_SYNC_EDGE (1<<16)
+#define MSD_SIF_BS_SYNC_USED (1<<17)
+#define MSD_SIF_FS_BASE_UNIT_POS 12
+#define MSD_SIF_FS_BASE_UNIT(val) ((val>>MSD_SIF_FS_BASE_UNIT_POS)&0x7)
+
+// Standard pack unit sizes
+#define SIF_SPB_BASE_UNITS_1KBYTES 0x4
+#define SIF_SPB_BASE_UNITS_2KBYTES 0x5
+#define SIF_SPB_BASE_UNITS_4KBYTES 0x6
+#define SIF_SPB_BASE_UNITS_8KBYTES 0x7
+
+//MSD_SIF_DPB_OFFSET_ADDR
+//MSD_SIF_FRM_SYNC_DATA_ADDR
+//MSD_SIF_FRM_DANGLING_ADDR
+
+//MSD_SIF_DPB_CONFIG_ADDR
+#define MSD_SIF_DPB_LUT_ENAB (1<<0)
+#define MSD_SIF_DPB_LUT_ADDR_MSB (1<<1)
+#define MSD_SIF_DPB_USE_FS_IDC (1<<2)
+#define MSD_SIF_DPB_RSHIFT_CA_POS 3
+#define MSD_SIF_DPB_RSHIFT_CA_SIZE 3
+
+//MSD_SIF_DPB_LUT_LOAD_ADDR
+#define MSD_SIF_DPB_LUT_VALUE_POS 0
+#define MSD_SIF_DPB_LUT_VALUE_SIZE 20
+#define MSD_SIF_DPB_LUT_ADDR_POS 24
+#define MSD_SIF_DPB_LUT_ADDR_SIZE 6
+
+//MSD_SIF_LOAD_DPB_NUMB_ADDR
+#define MSD_SIF_LOAD_DPB_NUMB_NUMB_POS 0
+#define MSD_SIF_LOAD_DPB_NUMB_NUMB_SIZE 5
+#define MSD_SIF_LOAD_DPB_NUMB_NUMB(val) ((val>>MSD_SIF_LOAD_DPB_NUMB_NUMB_POS)&0x1f)
+#define MSD_SIF_LOAD_DPB_NUMB_SID_POS 12
+#define MSD_SIF_LOAD_DPB_NUMB_SID_SIZE 4
+
+//MSD_SIF_DEC_STATUS_ADDR
+#define MSD_SIF_DEC_STATUS_SLC_PROG_POS 0
+#define MSD_SIF_DEC_STATUS_SLC_PROG_SIZE 1
+#define MSD_SIF_DEC_STATUS_SLC_PROG(val) ((val>>MSD_SIF_DEC_STATUS_SLC_PROG_POS)&0x1)
+
+#define MSD_SIF_DEC_STATUS_IMG_PROG_POS 1
+#define MSD_SIF_DEC_STATUS_IMG_PROG_SIZE 1
+#define MSD_SIF_DEC_STATUS_IMG_PROG(val) ((val>>MSD_SIF_DEC_STATUS_IMG_PROG_POS)&0x1)
+
+#define MSD_SIF_DEC_STATUS_FRM_PROG_POS 2
+#define MSD_SIF_DEC_STATUS_FRM_PROG_SIZE 1
+#define MSD_SIF_DEC_STATUS_FRM_PROG(val) ((val>>MSD_SIF_DEC_STATUS_FRM_PROG_POS)&0x1)
+
+#define MSD_SIF_DEC_STATUS_VPMD_BUSY_POS 3
+#define MSD_SIF_DEC_STATUS_VPMD_BUSY_SIZE 1
+#define MSD_SIF_DEC_STATUS_VPMD_BUSY(val) ((val>>MSD_SIF_DEC_STATUS_VPMD_BUSY_POS)&0x1)
+
+#define MSD_SIF_DEC_STATUS_VDBF_BUSY_POS 4
+#define MSD_SIF_DEC_STATUS_VDBF_BUSY_SIZE 1
+#define MSD_SIF_DEC_STATUS_VDBF_BUSY(val) ((val>>MSD_SIF_DEC_STATUS_VDBF_BUSY_POS)&0x1)
+
+#define MSD_SIF_DEC_STATUS_XOB_IDLE_POS 5
+#define MSD_SIF_DEC_STATUS_XOB_IDLE_SIZE 1
+#define MSD_SIF_DEC_STATUS_XOB_IDLE(val) ((val>>MSD_SIF_DEC_STATUS_XOB_IDLE_POS)&0x1)
+
+#define MSD_SIF_DEC_STATUS_DPBMC_IDLE_POS 6
+#define MSD_SIF_DEC_STATUS_DPBMC_IDLE_SIZE 1
+#define MSD_SIF_DEC_STATUS_DPBMC_IDLE(val) ((val>>MSD_SIF_DEC_STATUS_DPBMC_IDLE_POS)&0x1)
+
+#define MSD_SIF_DEC_STATUS_BS_EMPTY_POS 7
+#define MSD_SIF_DEC_STATUS_BS_EMPTY_SIZE 1
+#define MSD_SIF_DEC_STATUS_BS_EMPTY(val) ((val>>MSD_SIF_DEC_STATUS_BS_EMPTY_POS)&0x1)
+
+/* From Kronos Rev.B */
+#define MSD_SIF_DEC_STATUS_MBQ_STAT_POS 8
+#define MSD_SIF_DEC_STATUS_MBQ_STAT_SIZE 2
+#define MSD_SIF_DEC_STATUS_MBQ_STAT(val) ((val>>MSD_SIF_DEC_STATUS_MBQ_STAT_POS)&0x3)
+
+#define MSD_SIF_DEC_STATUS_MPR_FIFO_POS 10
+#define MSD_SIF_DEC_STATUS_MPR_FIFO_SIZE 6
+
+#define MSD_SIF_DEC_STATUS_MPR_FIFOS_NEMPTY_POS 16
+#define MSD_SIF_DEC_STATUS_MPR_FIFOS_NEMPTY_SIZE 1
+
+#define MSD_SIF_DEC_STATUS_VMIF_CLSET_IDLE_POS 17
+#define MSD_SIF_DEC_STATUS_VMIF_CLSET_IDLE_SIZE 2
+
+#define MSD_SIF_DEC_STATUS_PIXIF_IDLE_POS 19
+#define MSD_SIF_DEC_STATUS_PIXIF_IDLE_SIZE 1
+
+#define MSD_SIF_DEC_STATUS_MBIWR_TAGFIFO_EMPTY_POS 22
+#define MSD_SIF_DEC_STATUS_MBIWR_TAGFIFO_EMPTY_SIZE 1
+#define MSD_SIF_DEC_STATUS_MBIWR_TAGFIFO_EMPTY(val) ((val>>MSD_SIF_DEC_STATUS_MBIWR_TAGFIFO_EMPTY_POS)&0x1)
+
+
+//MSD_SIF_BS2RBSP_STATUS_ADDR 6'h32 // R, bs2rbsp status -- [bs_sync frm_sync_data] got_start_code, nal_unit_done, buf_level
+// BSD data range definitions
+#define MSD_SIF_BS2RBSP_GOT_START_CODE_BITS(r) ((r)&0x1)
+#define MSD_SIF_BS2RBSP_NAL_UNIT_DONE_BIT(r) (((r)&0x2)>>1)
+#define MSD_SIF_BS2RBSP_CBUF_LEVEL_BITS(r) (((r)&0x1FC)>>2)
+#define MSD_SIF_BS2RBSP_GOT_START_CODE_MASK 0x1
+#define MSD_SIF_BS2RBSP_GOT_SCODE (1<<0)
+#define MSD_SIF_BS2RBSP_NALU_FINISH (1<<1)
+#define MSD_SIF_BS2RBSP_EMPTY (1<<2)
+#define MSD_SIF_BS2RBSP_BUF_LEVEL_POS 3
+#define MSD_SIF_BS2RBSP_BUF_LEVEL_SIZE 4
+#define MSD_SIF_BS2RBSP_BUF_LEVEL(val) ((val>>MSD_SIF_BS2RBSP_BUF_LEVEL_POS)&0xf)
+#define MSD_SIF_BS2RBSP_GOT_PESSCODE 1<<8
+#define MSD_SIF_BS2RBSP_SCD_LEVEL_POS 10
+#define MSD_SIF_BS2RBSP_SCD_LEVEL_MASK 0x3
+#define MSD_SIF_BS2RBSP_3RD_BTYE_POS 12
+#define MSD_SIF_BS2RBSP_3RD_BTYE_MASK 0xFF
+#define MSD_SIF_BS2RBSP_SCD_DIS_POS 20
+#define MSD_SIF_BS2RBSP_SCD_DIS_MASK 0x1
+#define MSD_SIF_BS2RBSP_LONG_SCODE_POS 21
+#define MSD_SIF_BS2RBSP_LONG_SCODE_MASK 0x1
+#define MSD_SIF_BS2RBSP_SHORT_SYNC_POS 22
+#define MSD_SIF_BS2RBSP_SHORT_SYNC_MASK 0x1
+
+#define MSD_SIF_BS2RBSP_SCD_LEVEL(val) ((val >> MSD_SIF_BS2RBSP_SCD_LEVEL_POS ) & MSD_SIF_BS2RBSP_SCD_LEVEL_MASK )
+#define MSD_SIF_BS2RBSP_SCD_3RD_BTYE(val) ((val >> MSD_SIF_BS2RBSP_3RD_BTYE_POS ) & MSD_SIF_BS2RBSP_3RD_BTYE_MASK )
+#define MSD_SIF_BS2RBSP_SCD_DIS(val) ((val >> MSD_SIF_BS2RBSP_SCD_DIS_POS ) & MSD_SIF_BS2RBSP_SCD_DIS_MASK )
+#define MSD_SIF_BS2RBSP_LONG_SCODE(val) ((val >> MSD_SIF_BS2RBSP_LONG_SCODE_POS ) & MSD_SIF_BS2RBSP_LONG_SCODE_MASK )
+#define MSD_SIF_BS2RBSP_SHORT_SYNC(val) ((val >> MSD_SIF_BS2RBSP_SHORT_SYNC_POS ) & MSD_SIF_BS2RBSP_SHORT_SYNC_MASK )
+
+//MSD_SIF_BS2RBSP_FEED_ADDR
+#define MSD_SIF_BS2RBSP_FEED_CTRL (1<<0) // W: RBSP feed start & stop control,
+#define MSD_SIF_BS2RBSP_NAL_EI_FLAG (1<<1) // R only, on nalu bases, cleared by HW at start of nalu,
+#define MSD_SIF_BS2RBSP_FEED_STOP ((~MSD_SIF_BS2RBSP_FEED_CTRL)&1)
+
+//MSD_SIF_BS2RBSP_SCODE_ADDR
+#define MSD_SIF_BS2RBSP_START_CODE_POS 0
+#define MSD_SIF_BS2RBSP_START_CODE_SIZE 8
+#define MSD_SIF_BS2RBSP_START_CODE(val) ((val>>MSD_SIF_BS2RBSP_START_CODE_POS)&0xff)
+#define MSD_SIF_RS2RBSP_SHORT_SC_POS 8
+#define MSD_SIF_RS2RBSP_SHORT_SC_SIZE 1
+#define MSD_SIF_RS2RBSP_SHORT_SC_FLAG(val) ((val>>MSD_SIF_RS2RBSP_SHORT_SC_POS)&0x1)
+#define MSD_SIF_BS2RBSP_SYNC_DATA_POS 16
+#define MSD_SIF_BS2RBSP_SYNC_DATA(val) ((val & 0xff0000) >> MSD_SIF_BS2RBSP_SYNC_DATA_POS)
+#define MSD_SIF_BS2RBSP_SYNC_DATA_SET(val) ((val<<MSD_SIF_BS2RBSP_SYNC_DATA_POS) & 0xff0000)
+
+#define MSD_SIF_BS2RBSP_SYNC_DATA_SIZE 8
+#define MSD_SIF_BS2RBSP_SYNC_DATA_PTSDTSFLAGS_POS 0
+#define MSD_SIF_BS2RBSP_SYNC_DATA_DTS_POS 2
+#define MSD_SIF_BS2RBSP_SYNC_DATA_PTS_POS 3
+#define MSD_SIF_BS2RBSP_SYNC_DATA_ERR_POS 7
+#define MSD_SIF_BS2RBSP_SYNC_DATA_ERR (1<<MSD_SIF_BS2RBSP_SYNC_DATA_ERR_POS)
+#define MSD_SIF_BS2RBSP_SYNC_FLAG (1<<24) // 0 if bs_sync_used is set to '0'
+
+//MSD_SIF_BS2RBSP_SCDCTRL_ADDR
+#define MSD_SIF_BS2RBSP_SCDCTRL_EXPLICIT_CTRL_POS 0
+#define MSD_SIF_BS2RBSP_SCDCTRL_ERR_SLCMRG_POS 3
+#define MSD_SIF_BS2RBSP_SCDCTRL_DETECT_JPEG_MARKERS_POS 5
+#define MSD_SIF_BS2RBSP_SCDCTRL_STOP_SLICE_ON_SYNC_POS 6
+#define MSD_SIF_BS2RBSP_SCDCTRL_USE_OLD_EMUL_PREVENT_POS 7
+#define MSD_SIF_BS2RBSP_SCDCTRL_SCODE_DETECT_DISABLE_PERIOD_POS 8
+#define MSD_SIF_BS2RBSP_SCDCTRL_EXPLICIT_CTRL (1<<MSD_SIF_BS2RBSP_SCDCTRL_EXPLICIT_CTRL_POS)
+#define MSD_SIF_BS2RBSP_SCDCTRL_ERR_SLCMRG (1<<MSD_SIF_BS2RBSP_SCDCTRL_ERR_SLCMRG_POS)
+#define MSD_SIF_BS2RBSP_SCDCTRL_DETECT_JPEG_MARKERS (1<<MSD_SIF_BS2RBSP_SCDCTRL_DETECT_JPEG_MARKERS_POS)
+#define MSD_SIF_BS2RBSP_SCDCTRL_STOP_SLICE_ON_SYNC (1<<MSD_SIF_BS2RBSP_SCDCTRL_STOP_SLICE_ON_SYNC_POS)
+
+//MSD_SIF_CTRL_STATUS_ADDR
+#define MSD_SIF_CTRL_SEMAPHORE_INTR_BIT (1<<0) // Read Only, '1'
+#define MSD_SIF_CTRL_IMAGE_INTR_ENAB_BIT (1<<1)
+#define MSD_SIF_CTRL_SLICE_INTR_ENAB_BIT (1<<2)
+#define MSD_SIF_CTRL_SCODE_INTR_ENAB_BIT (1<<3)
+#define MSD_SIF_CTRL_QPULL_INTR_ENAB_BIT (1<<4)
+#define MSD_SIF_CTRL_DTLERR_INTR_ENAB_BIT (1<<5) // Took over FORCE_ENTRY bit as not needed in status
+#define MSD_SIF_CTRL_PESSC_INTR_ENAB_BIT (1<<6) // Took over FORCE_ENTRY bit as not needed in status
+#define MSD_SIF_CTRL_BSDMA_INTR_ENAB_BIT (1<<7)
+#define MSD_SIF_CTRL_MP2D_SLC_MERGE_BIT (1<<8)
+#define MSD_SIF_CTRL_BS2RBSP_ENAB_BIT (1<<9)
+#define MSD_SIF_CTRL_SCODE_IN_FEED_BIT (1<<10)
+#define MSD_SIF_CTRL_SLC_RESYNC_DISAB_BIT (1<<11)
+#define MSD_SIF_CTRL_ALT_IRQ_CLR_BIT (1<<12)
+#define MSD_SIF_CTRL_ASPD_SSC_ENAB_BIT (1<<13) // SPD short start code enable
+#define MSD_SIF_CTRL_BBB_RSCMD_DISAB_BIT (1<<14) // BBB read-sensitive command disable - if set, BBB get_bits and exp-golumb commands require write first
+#define MSD_SIF_CTRL_RSBXFR_INTR_ENAB_BIT (1<<15)
+#define MSD_SIF_CTRL_IRQ_SELECT_BITS_SHIFT (16)
+
+//MSD_SIF_INTR_STATUS_ADDR
+#define MSD_SIF_INTR_SEMAPHORE_BIT (1<<0) // Controlled by semaphore interrupt mask, cannot be disabled or forced
+#define MSD_SIF_INTR_IMAGE_DONE_BIT (1<<1)
+#define MSD_SIF_INTR_SLICE_DONE_BIT (1<<2)
+#define MSD_SIF_INTR_SCODE_FOUND_BIT (1<<3)
+#define MSD_SIF_INTR_DISPQ_PULL_BIT (1<<4)
+#define MSD_SIF_INTR_FORCE_ENTRY_BIT (1<<5) // Always enabled
+#define MSD_SIF_INTR_PES_BIT (1<<6)
+#define MSD_SIF_INTR_BSDMA_BIT (1<<7)
+#define MSD_SIF_INTR_FORCE_EXIT_BIT (1<<8) // Always enabled
+#define MSD_SIF_INTR_DTL_ERR_BIT (1<<9)
+#define MSD_SIF_INTR2_EXTENSION_BITS (3<<10) // Always Enabled
+#define MSD_SIF_INTR2_EXTENSION_BIT_1 (1<<10) // Always Enabled
+#define MSD_SIF_INTR2_EXTENSION_BIT_2 (1<<11) // Always Enabled
+#define MSD_SIF_INTR3_EXTENSION_BITS (3<<12) // Always Enabled
+#define MSD_SIF_INTR3_EXTENSION_BIT_1 (1<<12) // Always Enabled
+#define MSD_SIF_INTR3_EXTENSION_BIT_2 (1<<13) // Always Enabled
+#define MSD_SIF_INTR_RSBXFR_DONE_BIT (1<<15)
+
+//MSD_SIF_CTRL2_STATUS_ADDR
+#define MSD_SIF_CTRL2_IRQ_MASK 0x80000000
+#define MSD_SIF_CTRL2_RPR_DONE_INTR_ENAB_BIT ((1<<4)|MSD_SIF_CTRL2_IRQ_MASK)
+#define MSD_SIF_CTRL2_BSD_DONE_BIT ((1<<5)|MSD_SIF_CTRL2_IRQ_MASK)
+#define MSD_SIF_CTRL2_SPP_SCODE_INTR_ENAB_BIT ((1<<6)|MSD_SIF_CTRL2_IRQ_MASK)
+#define MSD_SIF_CTRL2_SPP_PESSC_INTR_ENAB_BIT ((1<<7)|MSD_SIF_CTRL2_IRQ_MASK)
+#define MSD_SIF_CTRL2_SPP_BSDMA_INTR_ENAB_BIT ((1<<8)|MSD_SIF_CTRL2_IRQ_MASK)
+#define MSD_SIF_CTRL2_CSC_DONE_ENAB_BIT ((1<<9) |MSD_SIF_CTRL2_IRQ_MASK)
+#define MSD_SIF_CTRL2_CQ_ENAB_BIT ((1<<10)|MSD_SIF_CTRL2_IRQ_MASK)
+#define MSD_SIF_CTRL2_DFE_DONE_ENAB_BIT ((1<<13)|MSD_SIF_CTRL2_IRQ_MASK)
+#define MSD_SIF_CTRL2_DFE_SLC_DONE_ENAB_BIT ((1<<14)|MSD_SIF_CTRL2_IRQ_MASK)
+
+//MSD_SIF_INTR2_STATUS_ADDR
+#define MSD_SIF_INTR2_RPR_BIT (1<<4)
+#define MSD_SIF_INTR2_SPP_SCODE_FOUND_BIT (1<<6)
+#define MSD_SIF_INTR2_SPP_PESSC_FOUND_BIT (1<<7)
+#define MSD_SIF_INTR2_SPP_BSDMA_BIT (1<<8)
+#define MSD_SIF_INTR2_CSC_BIT (1<<9)
+#define MSD_SIF_INTR2_CQ_BIT (1<<10)
+#define MSD_SIF_INTR2_DFE_DONE_BIT (1<<13)
+#define MSD_SIF_INTR2_DFE_SLC_DONE_BIT (1<<14)
+
+//MSD_SIF_CTRL3_STATUS_ADDR
+#define MSD_SIF_CTRL3_IRQ_MASK 0x40000000
+#define MSD_SIF_CTRL3_DBE0_CQ_ENAB_BIT ((1<<0)|MSD_SIF_CTRL3_IRQ_MASK)
+#define MSD_SIF_CTRL3_DBE1_CQ_ENAB_BIT ((1<<1)|MSD_SIF_CTRL3_IRQ_MASK)
+#define MSD_SIF_CTRL3_DBE0_DONE_ENAB_BIT ((1<<4)|MSD_SIF_CTRL3_IRQ_MASK)
+#define MSD_SIF_CTRL3_DBE1_DONE_ENAB_BIT ((1<<5)|MSD_SIF_CTRL3_IRQ_MASK)
+#define MSD_SIF_CTRL3_DBE0_SLC_DONE_ENAB_BIT ((1<<8)|MSD_SIF_CTRL3_IRQ_MASK)
+#define MSD_SIF_CTRL3_DBE1_SLC_DONE_ENAB_BIT ((1<<9)|MSD_SIF_CTRL3_IRQ_MASK)
+
+//MSD_SIF_INTR3_STATUS_ADDR
+#define MSD_SIF_INTR3_DBE0_CQ_BIT (1<<0)
+#define MSD_SIF_INTR3_DBE1_CQ_BIT (1<<1)
+#define MSD_SIF_INTR3_DBE0_DONE_BIT (1<<4)
+#define MSD_SIF_INTR3_DBE1_DONE_BIT (1<<5)
+#define MSD_SIF_INTR3_DBE0_SLC_DONE_BIT (1<<8)
+#define MSD_SIF_INTR3_DBE1_SLC_DONE_BIT (1<<9)
+
+//MSD_SIF_RESET_COMMAND_ADDR
+#define MSD_SIF_RESET_DEC_ENGINE_BIT (1<<0)
+#define MSD_SIF_RESET_BS_INBUF_BIT (1<<1)
+#define MSD_SIF_RESET_DISP_QUEUE_BIT (1<<2)
+#define MSD_SIF_RESET_DTL_CACHE_BIT (1<<3)
+#define MSD_SIF_RESET_SLICE_BIT (1<<4)
+#define MSD_SIF_RESET_SPP_BIT (1<<5)
+#define MSD_SIF_RESET_DTL_4K_CACHE_BIT (1<<6) /* TODO - useme */
+#define MSD_SIF_RESET_DBE_BIT (1<<7)
+#define MSD_SIF_RESET_DFE_BIT (1<<8)
+
+//MSD_CTX_NEXT_SF_ADDR
+#define MSD_CTX_NEXT_BS_IDC_POS 0
+#define MSD_CTX_NEXT_BS_IDC_MASK 0xF
+#define MSD_CTX_NEXT_FORMAT_POS 4
+#define MSD_CTX_NEXT_FORMAT_MASK 0x1F
+
+// PES control
+//volatile u_int32 pes_setup;
+#define MSD_SIF_PES_SETUP_STRMID_POS 0
+#define MSD_SIF_PES_SETUP_SET_STRMID(id) ((id&0xff)<<MSD_SIF_PES_SETUP_STRMID_POS)
+#define MSD_SIF_PES_SETUP_STRMIDMASK_POS 8
+#define MSD_SIF_PES_SETUP_SET_STRMIDMASK(mask) ((mask&0xff)<<MSD_SIF_PES_SETUP_STRMIDMASK_POS)
+#define MSD_SIF_PES_SETUP_PESIRQEN_POS 16
+#define MSD_SIF_PES_SETUP_PESIRQEN (1<<MSD_SIF_PES_SETUP_PESIRQEN_POS)
+#define MSD_SIF_PES_SETUP_WAITPESHDR_POS 17
+#define MSD_SIF_PES_SETUP_WAITPESHDR (1<<MSD_SIF_PES_SETUP_WAITPESHDR_POS)
+#define MSD_SIF_PES_SETUP_ERRORMODE_POS 18
+#define MSD_SIF_PES_SETUP_SET_ERRORMODE(type) ((type&0x3)<<MSD_SIF_PES_SETUP_ERRORMODE_POS)
+#define MSD_SIF_PES_SETUP_ERRORMODE_NONE 0x0
+#define MSD_SIF_PES_SETUP_ERRORMODE_EIFLAG 0x2
+#define MSD_SIF_PES_SETUP_ERRORMODE_DISCONMARK 0x1
+#define MSD_SIF_PES_SETUP_PESEN_POS 20
+#define MSD_SIF_PES_SETUP_PESEN (1<<MSD_SIF_PES_SETUP_PESEN_POS)
+#define MSD_SIF_PES_SETUP_CHKPKTLEN_POS 21
+#define MSD_SIF_PES_SETUP_CHKPKTLEN (1<<MSD_SIF_PES_SETUP_CHKPKTLEN_POS)
+#define MSD_SIF_PES_SETUP_SYNC_ALWAYS_POS 22
+#define MSD_SIF_PES_SETUP_SYNC_ALWAYS (1<<MSD_SIF_PES_SETUP_SYNC_ALWAYS_POS)
+#define MSD_SIF_PES_SETUP_HOLD_DODGY_PTS_POS 23
+#define MSD_SIF_PES_SETUP_HOLD_DODGY_PTS (1<<MSD_SIF_PES_SETUP_HOLD_DODGY_PTS_POS)
+// Optionally disallow match inside PKT, to support artificial streams that do not have emulation prevention bytes
+#define MSD_SIF_PES_SETUP_ENFORCE_PKTLEN_POS 24
+#define MSD_SIF_PES_SETUP_ENFORCE_PKTLEN (1<<MSD_SIF_PES_SETUP_ENFORCE_PKTLEN_POS)
+
+//volatile u_int32 pes_status;
+#define MSD_SIF_PES_STATUS_STATE_POS 0
+#define MSD_SIF_PES_STATUS_GET_STATE(status) ((status>>MSD_SIF_PES_STATUS_STATE_POS)&0x3f)
+#define MSD_SIF_PES_STATUS_EVENT_POS 6
+#define MSD_SIF_PES_STATUS_GET_EVENT(status) ((status>>MSD_SIF_PES_STATUS_EVENT_POS)&0x3)
+#define MSD_SIF_PES_STATUS_PTS_PRESENT 0x2
+#define MSD_SIF_PES_STATUS_PTSDTS_PRESENT 0x3
+#define MSD_SIF_PES_STATUS_ERROR_PRESENT 0x1
+#define MSD_SIF_PES_STATUS_TOPDTS_POS 8
+#define MSD_SIF_PES_STATUS_GET_TOPDTS(status) ((status>>MSD_SIF_PES_STATUS_TOPDTS_POS)&0x1)
+#define MSD_SIF_PES_STATUS_SET_TOPDTS(status) ((status & 1) << MSD_SIF_PES_STATUS_TOPDTS_POS)
+#define MSD_SIF_PES_STATUS_TOPPTS_POS 9
+#define MSD_SIF_PES_STATUS_GET_TOPPTS(status) ((status>>MSD_SIF_PES_STATUS_TOPPTS_POS)&0x1)
+#define MSD_SIF_PES_STATUS_SET_TOPPTS(status) ((status & 1) << MSD_SIF_PES_STATUS_TOPPTS_POS)
+#define MSD_SIF_PES_STATUS_STALLED_POS 10
+#define MSD_SIF_PES_STATUS_GET_STALLED(status) ((status>>MSD_SIF_PES_STATUS_STALLED_POS)&0x1)
+#define MSD_SIF_PES_STATUS_STREAM_ID_MASK 0xFF
+#define MSD_SIF_PES_STATUS_STREAM_ID_POS 12
+#define MSD_SIF_PES_STATUS_GET_STREAMID(status) ((status>>MSD_SIF_PES_STATUS_STREAM_ID_POS)&MSD_SIF_PES_STATUS_STREAM_ID_MASK)
+#define MSD_SIF_PES_STATUS_TIMEBASE_ID_MASK 0x7
+#define MSD_SIF_PES_STATUS_TIMEBASE_ID_POS 12
+#define MSD_SIF_PES_STATUS_GET_TIMEBASE(status) ((status>>MSD_SIF_PES_STATUS_TIMEBASE_ID_POS)&MSD_SIF_PES_STATUS_TIMEBASE_ID_MASK)
+#define MSD_SIF_PES_STATUS_PARITY_MASK 0x1
+#define MSD_SIF_PES_STATUS_PARITY_POS 15
+#define MSD_SIF_PES_STATUS_GET_PARITY(status) ((status>>MSD_SIF_PES_STATUS_PARITY_POS)&MSD_SIF_PES_STATUS_PARITY_MASK)
+
+typedef enum
+{
+ pes_Seek = 4, // 6'b0001_00, // Wait for initial start pes start code
+ pes_DumpPrefix = 8, // 6'b0010_00, // Dumping the 0x00_00_01. Move on when get the 0x01
+ pes_DumpStrmID = 12, // 6'b0011_00, // Dumping the 0x00_00_01. Move on when get the 0x01
+ pes_WaitClear = 16, // 6'b0100_00, // Stalled waiting for firmware to clear the previous PTS
+ pes_PackLenH = 20, // 6'b0101_00, //
+ pes_PackLenL = 24, // 6'b0110_00, //
+ pes_Discon_0 = 28, // 6'b0111_00, // Output 0x00 from internally generates discontinuity
+ pes_Discon_1 = 32, // 6'b1000_00, // Output 0x00
+ pes_Discon_2 = 36, // 6'b1001_00, // Output 0x01
+ pes_Discon_3 = 40, // 6'b1010_00, // Output 0xB4
+ pes_ParseFW = 60, // 6'b1111_00, // Just let firmware read the data one at a time
+ pes_Flags1 = 1, // 6'b0000_01,
+ pes_Flags2 = 5, // 6'b0001_01,
+ pes_HdrLen = 9, // 6'b0010_01,
+ pes_PTS1 = 3, // 6'b0000_11,
+ pes_PTS2 = 7, // 6'b0001_11,
+ pes_PTS3 = 11, // 6'b0010_11,
+ pes_PTS4 = 15, // 6'b0011_11,
+ pes_PTS5 = 19, // 6'b0100_11,
+ pes_DTS1 = 23, // 6'b0101_11,
+ pes_DTS2 = 27, // 6'b0110_11,
+ pes_DTS3 = 31, // 6'b0111_11,
+ pes_DTS4 = 35, // 6'b1000_11,
+ pes_DTS5 = 39, // 6'b1001_11,
+ pes_DumpHdr = 43, // 6'b1010_11, // Skipping over remainder of headre
+ pes_PayloadSync = 45, // 6'b1011_01, // Outputting first payload byte to SCD
+ pes_Payload = 49 // 6'b1100_01 // Outputting payload to SCD
+
+} PES_STATE;
+
+// BSDMA Control
+//volatile u_int32 bsdma_command;
+#define MSD_SIF_BSDMA_CMND_START 0x1
+#define MSD_SIF_BSDMA_CMND_FETCHSTRDESC 0x2
+#define MSD_SIF_BSDMA_CMND_STOP 0x4
+#define MSD_SIF_BSDMA_CMND_CLEAR 0x8
+#define MSD_SIF_BSDMA_CMND_FORCE_DESC_UPDATE 0x10
+#define MSD_SIF_BSDMA_CMND_FORCE_CALC_LEVEL 0x20
+
+//volatile u_int32 bsdma_options;
+#define MSD_SIF_BSDMA_OPT_ENABLE 0x1
+#define MSD_SIF_BSDMA_OPT_PERIEN 0x2
+#define MSD_SIF_BSDMA_OPT_OFLIRQEN 0x4
+#define MSD_SIF_BSDMA_OPT_DISCONEN 0x8
+#define MSD_SIF_BSDMA_OPT_DESCUPPER_POS 4
+#define MSD_SIF_BSDMA_OPT_LOCBUFSIZE_POS 8
+#define MSD_SIF_BSDMA_OPT_LOCBUFOFFSET_POS 16
+#define MSD_SIF_BSDMA_OPT_DEBUG_FEED (1<<24)
+#define MSD_SIF_BSDMA_OPT_BURST (1<<25)
+
+#define MSD_SIF_BSDMA_OPT_SAFEREADMARGIN_POS 26
+#define MSD_SIF_BSDMA_OPT_TRACEBACK_POS 28
+#define MSD_BSDMA_STRIDE_END_IRQ_P0S 30 // Interrupt when all data read
+#define MSD_BSDMA_STRIDE_END_IRQ (1<<MSD_BSDMA_STRIDE_END_IRQ_P0S)
+#define MSD_BSDMA_STRIDE_DONE_IRQ_POS 31 // Interrupt when all data used
+#define MSD_BSDMA_STRIDE_DONE_IRQ ((u_int32)(1<<MSD_BSDMA_STRIDE_DONE_IRQ_POS))
+
+
+#define MSD_SIF_BSDMA_OPT_0B_SAFEMARGIN (0<<MSD_SIF_BSDMA_OPT_SAFEREADMARGIN_POS)
+#define MSD_SIF_BSDMA_OPT_128B_SAFEMARGIN (1<<MSD_SIF_BSDMA_OPT_SAFEREADMARGIN_POS)
+#define MSD_SIF_BSDMA_OPT_2KB_SAFEMARGIN (2<<MSD_SIF_BSDMA_OPT_SAFEREADMARGIN_POS)
+#define MSD_SIF_BSDMA_OPT_32KB_SAFEMARGIN (3<<MSD_SIF_BSDMA_OPT_SAFEREADMARGIN_POS)
+
+#define MSD_SIF_BSDMA_OPT_TRACEBACK_0 (0<<MSD_SIF_BSDMA_OPT_TRACEBACK_POS)
+#define MSD_SIF_BSDMA_OPT_TRACEBACK_16K (1<<MSD_SIF_BSDMA_OPT_TRACEBACK_POS)
+#define MSD_SIF_BSDMA_OPT_TRACEBACK_256K (2<<MSD_SIF_BSDMA_OPT_TRACEBACK_POS)
+#define MSD_SIF_BSDMA_OPT_TRACEBACK_4M (3<<MSD_SIF_BSDMA_OPT_TRACEBACK_POS)
+
+/* Constant defines on the 160/128 64-bit words of IBB memory */
+/* Split between the BSDMA stream buffer and the H.264 IBB usage */
+#define IBBBUF_SIZE 128
+#define IBBBUF_SIZE_LARGE 160
+#define BSDMA_IBBBUF_USAGE 16
+
+//volatile u_int32 bsdma_status;
+#define MSD_SIF_BSDMA_STATUS_CB_LEVEL (0xFF)
+#define MSD_SIF_BSDMA_STATUS_NMEMWORDS (0x1f<<8)
+#define MSD_SIF_BSDMA_STATUS_BELOW_LWM (0x1<<13) // Currently below Low Water Mark
+#define MSD_SIF_BSDMA_STATUS_BELOW_LWMH (0x1<<14) // Below Low Water Mark since last cleared
+#define MSD_SIF_BSDMA_STATUS_BUFOFLOW (0x1<<15)
+#define MSD_SIF_BSDMA_STATUS_DMA_STATE (0x1F<<16)
+#define MSD_SIF_BSDMA_STATUS_MCX_STATE (0x3F<<21)
+#define MSD_SIF_BSDMA_STATUS_RQ_STATE (0x1<<27)
+#define MSD_SIF_BSDMA_STATUS_ABOVE_HWM (0x1<<28) // Currently above High Water Mark
+#define MSD_SIF_BSDMA_STATUS_ABOVE_HWMH (0x1<<29) // Above High Water Mark since last cleared
+#define MSD_SIF_BSDMA_STATUS_STRIDE_END (0x1<<30) // all data fed
+#define MSD_SIF_BSDMA_STATUS_STRIDE_DONE ((u_int32)(0x1<<31)) // all data used
+
+#define MSD_SIF_BSDMA_EXTOPT_LOOPBIT_POS 0x0
+#define MSD_SIF_BSDMA_EXTOPT_CB_MIN_POS 3
+#define MSD_SIF_BSDMA_EXTOPT_REQ_8 (1<<10)
+#define MSD_SIF_BSDMA_EXTOPT_SINGLE_STRIDE (1<<11)
+#define MSD_SIF_BSDMA_EXTOPT_INIT_IRQ (1<<12)
+#define MSD_SIF_BSDMA_EXTOPT_MIN_UPDATES (1<<13)
+#define MSD_SIF_BSDMA_EXTOPT_CHECK_WPTR (1<<14)
+
+//volatile u_int32 bsdma_ext_options;
+#define MSD_SIF_BSDMA_EXTOPT_LOOPBIT_SET(w) ((w&0x7)<<MSD_SIF_BSDMA_EXTOPT_LOOPBIT_POS)
+#define MSD_SIF_BSDMA_EXTOPT_LOOPBIT_GET(r) ((r>>MSD_SIF_BSDMA_EXTOPT_LOOPBIT_POS)&0x7)
+#define MSD_SIF_BSDMA_EXTOPT_SINGLESHOTEXITMODE MSD_SIF_BSDMA_EXTOPT_SINGLE_STRIDE
+
+// This define is used only when FW controls how close the RP can get to the WP
+// For pecos we are assuming at least two full burst of distance
+//#define BSDMA_WP_AHEAD_OF_RP_MARGIN (2*16*8)
+#define BSDMA_WP_AHEAD_OF_RP_MARGIN (8*16*8)
+#define BSDMA_DESC_REAL_ADDR(x) (x&0xfffffff)
+#define BSDMA_DESC_WRAP_ADDR(x) (x&0xf0000000)
+#define BSDMA_DESC_NOPARITY_MASK 0xfffffffe
+
+
+#define MSD_FORMAT_H264 (0x1 <<MSD_CTX_NEXT_FORMAT_POS)
+#define MSD_FORMAT_VC1 (0x2 <<MSD_CTX_NEXT_FORMAT_POS)
+#define MSD_FORMAT_MP2 (0x3 <<MSD_CTX_NEXT_FORMAT_POS)
+#define MSD_FORMAT_AVS (0x4 <<MSD_CTX_NEXT_FORMAT_POS)
+#define MSD_FORMAT_ASP (0x5 <<MSD_CTX_NEXT_FORMAT_POS)
+#define MSD_FORMAT_JPG (0xD <<MSD_CTX_NEXT_FORMAT_POS) // Uses aspd HW and ext. format flag
+#define MSD_FORMAT_RV8 (0x6 <<MSD_CTX_NEXT_FORMAT_POS)
+#define MSD_FORMAT_RV9 (0xE <<MSD_CTX_NEXT_FORMAT_POS)
+#define MSD_FORMAT_VP6 (0x7 <<MSD_CTX_NEXT_FORMAT_POS)
+#define MSD_FORMAT_VP8 (0xF <<MSD_CTX_NEXT_FORMAT_POS)
+#define MSD_FORMAT_VP3 (0x7 <<MSD_CTX_NEXT_FORMAT_POS)
+#define MSD_FORMAT_HEVC (0x10 <<MSD_CTX_NEXT_FORMAT_POS)
+#define MSD_FORMAT_NULL (0x0 <<MSD_CTX_NEXT_FORMAT_POS)
+
+//MSD_SIF_DPBMC_SETUP_ADDR
+#define MSD_SIF_DPBMC_SET_CRC_TYPE(datasrc,datatype) (((0x3&datatype)<<2)|(datasrc&0x3))
+
+#define MSD_SIF_DPBMC_CLEAR_CRC2_TYPE_MASK 0xFF0FFFFF
+#define MSD_SIF_DPBMC_SET_CRC2_TYPE(datasrc,datatype) (((0x3&datatype)<<22)|((datasrc&0x3)<<20))
+// Alternate method of setup
+
+#define MSD_SIF_DPBMC_CLEAR_CRC2_MAJOR_MINOR_TYPE_MASK 0x87CFFFFF
+#define MSD_SIF_DPBMC_SET_CRC2_TYPE_MAJOR(datatype) (( 0x3 & datatype ) << 20 )
+#define MSD_SIF_DPBMC_SET_CRC2_TYPE_MINOR(datasrc) (( 0xf & datasrc ) << 27 )
+#define MSD_SIF_DPBMC_GET_CRC2_TYPE_MAJOR(datatype) (( datatype >> 20 ) & 0x3 )
+#define MSD_SIF_DPBMC_GET_CRC2_TYPE_MINOR(datasrc) (( datasrc >> 27) & 0xf )
+#define MSD_SIF_DPBMC_SET_CRC_ALT_TYPE_MAJOR(datatype) (( 0x3 & datatype ) << 2 )
+#define MSD_SIF_DPBMC_SET_CRC_ALT_TYPE_MINOR(datasrc) (( 0xf & datasrc ) << 23 )
+#define MSD_SIF_DPBMC_SET_CRC_USE_ALT_TYPE(use) (( use & 0x1 ) << 22 )
+
+#define MSD_SIF_DPBMC_CRC_RDDATA_TYPE 0x0
+#define MSD_SIF_DPBMC_CRC_WRDATA_TYPE 0x1
+#define MSD_SIF_DPBMC_CRC_RDADDR_TYPE 0x2
+#define MSD_SIF_DPBMC_CRC_WRADDR_TYPE 0x3
+#define MSD_SIF_DPBMC_CRC_BPP_SRCTYPE 0x3
+#define MSD_SIF_DPBMC_CRC_MBI_SRCTYPE 0x2
+#define MSD_SIF_DPBMC_CRC_PIXEL_SRCTYPE 0x0
+
+#define MSD_SIF_DPBMC_CRC_ALT_DBE1_SRCTYPE 0xf
+#define MSD_SIF_DPBMC_CRC_ALT_TES_SRCTYPE 0xe
+#define MSD_SIF_DPBMC_CRC_ALT_DFE_SRCTYPE 0xd
+#define MSD_SIF_DPBMC_CRC_ALT_MPSDBF_UV_SRCTYPE 0xc
+#define MSD_SIF_DPBMC_CRC_ALT_SVC_RSMP_SRCTYPE 0xb
+#define MSD_SIF_DPBMC_CRC_ALT_SVC_META_SRCTYPE 0xa
+#define MSD_SIF_DPBMC_CRC_ALT_MBQ_SRCTYPE 0x9
+#define MSD_SIF_DPBMC_CRC_ALT_CSC_SRCTYPE 0x8
+#define MSD_SIF_DPBMC_CRC_ALT_RPR_SRCTYPE 0x7
+#define MSD_SIF_DPBMC_CRC_ALT_MPSDBF_SRCTYPE 0x6
+#define MSD_SIF_DPBMC_CRC_ALT_MBI_SRCTYPE 0x5
+#define MSD_SIF_DPBMC_CRC_ALT_MX12_SRCTYPE 0x4
+#define MSD_SIF_DPBMC_CRC_ALT_MX34_SRCTYPE 0x3
+#define MSD_SIF_DPBMC_CRC_ALT_RSB_SRCTYPE 0x2
+#define MSD_SIF_DPBMC_CRC_ALT_MCX_SRCTYPE 0x1
+#define MSD_SIF_DPBMC_CRC_ALT_BSD_SRCTYPE 0x0
+
+#define MSD_SIF_DPBMC_OUTSTAND_REQ_POS 4
+#define MSD_SIF_DPBMC_OUTSTAND_REQ_MASK 0x7
+#define MSD_SIF_DPBMC_SET_OUTSTAND_REQ(num_req) ((num_req&MSD_SIF_DPBMC_OUTSTAND_REQ_MASK)<<MSD_SIF_DPBMC_OUTSTAND_REQ_POS)
+#define MSD_SIF_DPBMC_OUTSTAND_WR_REQ_POS 7
+#define MSD_SIF_DPBMC_OUTSTAND_WR_REQ_MASK 0x3
+#define MSD_SIF_DPBMC_SET_OUTSTAND_WR_REQ(num_req) ((num_req&MSD_SIF_DPBMC_OUTSTAND_WR_REQ_MASK)<<MSD_SIF_DPBMC_OUTSTAND_WR_REQ_POS)
+#define MSD_SIF_DPBMC_DBFAL_MODE_POS 9
+#define MSD_SIF_DPBMC_DBFAL_MODE_MASK 0x3
+#define MSD_SIF_DPBMC_SET_DBFAL_MODE(num_req) ((num_req&MSD_SIF_DPBMC_DBFAL_MODE_MASK)<<MSD_SIF_DPBMC_DBFAL_MODE_POS)
+#define MSD_SIF_DPBMC_SET_USE_CHROMA_DPATH_POS 0x0
+#define MSD_SIF_DPBMC_SET_USE_CHROMA_DPATH_MASK 0x1
+#define MSD_SIF_DPBMC_SET_USE_CHROMA_DPATH(a) ((a&MSD_SIF_DPBMC_SET_USE_CHROMA_DPATH_MASK)<<MSD_SIF_DPBMC_SET_USE_CHROMA_DPATH_POS)
+#define MSD_SIF_DPBMC_SET_CLR_CHROMA_DPATH (~(MSD_SIF_DPBMC_SET_USE_CHROMA_DPATH_MASK << MSD_SIF_DPBMC_SET_USE_CHROMA_DPATH_POS))
+
+
+// VMIF MBI CACHE
+#define MSD_VMIF_MBI_CACHE_RDCLR_POS 0
+#define MSD_VMIF_MBI_CACHE_RDCLR_MASK 0x7
+#define MSD_VMIF_MBI_CACHE_RDDIS_POS 3
+#define MSD_VMIF_MBI_CACHE_RDDIS_MASK 0x7
+#define MSD_VMIF_MBI_CACHE_RDSCLR_DIS_POS 6
+#define MSD_VMIF_MBI_CACHE_RDSCLR_DIS_MASK 0x7
+#define MSD_VMIF_MBI_CACHE_WRCLR_POS 9
+#define MSD_VMIF_MBI_CACHE_WRCLR_MASK 0x7
+#define MSD_VMIF_MBI_CACHE_WRDIS_POS 12
+#define MSD_VMIF_MBI_CACHE_WRDIS_MASK 0x7
+#define MSD_VMIF_MBI_CACHE_WRFLSH_POS 15
+#define MSD_VMIF_MBI_CACHE_WRFLSH_MASK 0x7
+
+#define MSD_VMIF_MBI_CACHE_SET_RDCLR(w) ((w&MSD_VMIF_MBI_CACHE_RDCLR_MASK)<<MSD_VMIF_MBI_CACHE_RDCLR_POS)
+#define MSD_VMIF_MBI_CACHE_SET_RDDIS(w) ((w&MSD_VMIF_MBI_CACHE_RDDIS_MASK)<<MSD_VMIF_MBI_CACHE_RDDIS_POS)
+#define MSD_VMIF_MBI_CACHE_SET_RDSCLR_DIS(w) ((w&MSD_VMIF_MBI_CACHE_RDSCLR_DIS_MASK)<<MSD_VMIF_MBI_CACHE_RDSCLR_DIS_POS)
+#define MSD_VMIF_MBI_CACHE_SET_WRCLR(w) ((w&MSD_VMIF_MBI_CACHE_WRCLR_MASK)<<MSD_VMIF_MBI_CACHE_WRCLR_POS)
+#define MSD_VMIF_MBI_CACHE_SET_WRDIS(w) ((w&MSD_VMIF_MBI_CACHE_WRDIS_MASK)<<MSD_VMIF_MBI_CACHE_WRDIS_POS)
+#define MSD_VMIF_MBI_CACHE_SET_WRFLSH(w) ((w&MSD_SIF_DPBMC_OUTSTAND_WR_REQ_MASK)<<MSD_VMIF_MBI_CACHE_WRFLSH_POS)
+
+
+// DPBMC SETUP 2
+#define MSD_SIF_DPBMC_SET_OUTSTAND_MBIRD_MASK 0x3
+#define MSD_SIF_DPBMC_SET_OUTSTAND_MBIRD_POS 14
+#define MSD_VMIF_MPSAL_MODE_DISOB_BIT 13
+#define MSD_VMIF_MPSAL_MODE_REQ16_BIT 10
+#define MSD_VMIF_MPSAL_MODE_16PIX_POS 9
+// MSD_SIF_COUNT_STRB_SEL_BITS 8:1
+#define MSD_SIF_COUNT_RD_CMD_STRB_SEL 7
+#define MSD_SIF_COUNT_WR_CMD_STRB_SEL 6
+#define MSD_SIF_COUNT_WR_STRB_SEL 5
+#define MSD_SIF_COUNT_RD_STRB_SEL 4
+#define MSD_SIF_COUNT_UV_RD_STRB_SEL 3
+#define MSD_SIF_COUNT_RSMP_RD_STRB_SEL 2
+#define MSD_SIF_COUNT_RSMP_MBMETA_STRB_SEL 1
+#define MSD_SIF_COUNT_MBI_RD_STRB_SEL 0
+
+#define MSD_SIF_COUNT_STRB_SEL_MASK 0x1
+#define MSD_SIF_COUNT_STRB_SET_USE_RD_CMD_STRB(a) (((a&MSD_SIF_COUNT_STRB_SEL_MASK) <<MSD_SIF_COUNT_RD_CMD_STRB_SEL )<<1)
+#define MSD_SIF_COUNT_STRB_SET_USE_WR_CMD_STRB(a) (((a&MSD_SIF_COUNT_STRB_SEL_MASK) <<MSD_SIF_COUNT_WR_CMD_STRB_SEL )<<1)
+#define MSD_SIF_COUNT_STRB_SET_USE_WR_STRB(a) (((a&MSD_SIF_COUNT_STRB_SEL_MASK) <<MSD_SIF_COUNT_WR_STRB_SEL )<<1)
+#define MSD_SIF_COUNT_STRB_SET_USE_RD_STRB(a) (((a&MSD_SIF_COUNT_STRB_SEL_MASK) <<MSD_SIF_COUNT_RD_STRB_SEL )<<1)
+#define MSD_SIF_COUNT_STRB_SET_USE_UV_RD_STRB(a) (((a&MSD_SIF_COUNT_STRB_SEL_MASK) <<MSD_SIF_COUNT_UV_RD_STRB_SEL )<<1)
+#define MSD_SIF_COUNT_STRB_SET_USE_RSMP_RD_STRB(a) (((a&MSD_SIF_COUNT_STRB_SEL_MASK) <<MSD_SIF_COUNT_RSMP_RD_STRB_SEL )<<1)
+#define MSD_SIF_COUNT_STRB_SET_USE_RSMP_MBMETA_STRB(a) (((a&MSD_SIF_COUNT_STRB_SEL_MASK) <<MSD_SIF_COUNT_RSMP_MBMETA_STRB_SEL )<<1)
+#define MSD_SIF_COUNT_STRB_SET_USE_MBI_RD_STRB(a) (((a&MSD_SIF_COUNT_STRB_SEL_MASK) <<MSD_SIF_COUNT_MBI_RD_STRB_SEL )<<1)
+#define MSD_SIF_DPBMC_SET_OUTSTAND_MBIRD(a) ((a&MSD_SIF_DPBMC_SET_OUTSTAND_MBIRD_MASK)<<MSD_SIF_DPBMC_SET_OUTSTAND_MBIRD_POS)
+
+
+#define MSD_DPBMC_DPBCOH_POS 9
+#define MSD_DPBMC_DPBCOH_MASK 0x1
+#define MSD_DPBMC_DPBCOH_SET(a) ((a&MSD_DPBMC_DPBCOH_MASK)<<MSD_DPBMC_DPBCOH_POS)
+#define MSD_DPBMC_MBICOH_POS 10
+#define MSD_DPBMC_MBICOH_MASK 0x1
+#define MSD_DPBMC_MBICOH_SET(a) ((a&MSD_DPBMC_MBICOH_MASK)<<MSD_DPBMC_MBICOH_POS)
+#define MSD_DPBMC_RSBCOH_POS 11
+#define MSD_DPBMC_RSBCOH_MASK 0x1
+#define MSD_DPBMC_RSBCOH_SET(a) ((a&MSD_DPBMC_RSBCOH_MASK)<<MSD_DPBMC_RSBCOH_POS)
+#define MSD_SIF_DPBMC_BASE_UNIT_POS 12
+#define MSD_SIF_DPBMC_BASE_UNIT_MASK 0x7
+#define MSD_SIF_DPBMC_SET_BASE_UNIT(base) ((base&MSD_SIF_DPBMC_BASE_UNIT_MASK)<<MSD_SIF_DPBMC_BASE_UNIT_POS)
+#define MSD_DPBMC_INT_WAIT_IDLE_POS 15
+#define MSD_DPBMC_INT_WAIT_IDLE_MASK 0x1
+#define MSD_DPBMC_INT_WAIT_IDLE_SET(a) ((a&MSD_DPBMC_INT_WAIT_IDLE_MASK)<<MSD_DPBMC_INT_WAIT_IDLE_POS)
+#define MSD_DPBMC_SC_INT_WAIT_IDLE_SET_POS 31
+#define MSD_DPBMC_SC_INT_WAIT_IDLE_SET_MASK 0x1
+#define MSD_DPBMC_SC_INT_WAIT_IDLE_SET(a) ((a&MSD_DPBMC_SC_INT_WAIT_IDLE_SET_MASK)<<MSD_DPBMC_SC_INT_WAIT_IDLE_SET_POS)
+#define MSD_DPBMC_ARB_MCX_POS 16
+#define MSD_DPBMC_ARB_MCX_MASK 0x1
+#define MSD_DPBMC_ARB_MCX_SET(a) ((a&MSD_DPBMC_ARB_MCX_MASK)<<MSD_DPBMC_ARB_MCX_POS)
+#define MSD_DPBMC_ARB_MCX_CLR(a) (~((a&MSD_DPBMC_ARB_MCX_MASK)<<MSD_DPBMC_ARB_MCX_POS))
+#define MSD_DPBMC_ARB_BSDMA_POS 17
+#define MSD_DPBMC_ARB_BSDMA_MASK 0x1
+#define MSD_DPBMC_ARB_BSDMA_SET(a) ((a&MSD_DPBMC_ARB_BSDMA_MASK)<<MSD_DPBMC_ARB_BSDMA_POS)
+#define MSD_DPBMC_ARB_BSDMA_CLR(a) (~((a&MSD_DPBMC_ARB_BSDMA_MASK)<<MSD_DPBMC_ARB_BSDMA_POS))
+#define MSD_DPBMC_DIS_CRC_AUTO_RESET_POS 19
+#define MSD_DPBMC_DIS_CRC_AUTO_RESET_MASK 0x1
+#define MSD_DPBMC_DIS_CRC_AUTO_RESET_SET(a) ((a&MSD_DPBMC_DIS_CRC_AUTO_RESET_MASK)<<MSD_DPBMC_DIS_CRC_AUTO_RESET_POS)
+#define MSD_DPBMC_DIS_CRC_AUTO_RESET_CLR(a) (~((a&MSD_DPBMC_DIS_CRC_AUTO_RESET_MASK)<<MSD_DPBMC_DIS_CRC_AUTO_RESET_POS))
+
+// Local memory configuration (power down)
+#define MSD_SIF_LMEM_CONFIG_PD_MASK 0x1
+#define MSD_SIF_LMEM_CONFIG_PD_CCHE0_POS 0
+#define MSD_SIF_LMEM_CONFIG_PD_RSB_POS 1
+#define MSD_SIF_LMEM_CONFIG_PD_AVSD_POS 2
+#define MSD_SIF_LMEM_CONFIG_PD_MPGD_POS 3
+#define MSD_SIF_LMEM_CONFIG_PD_VC1D_POS 4
+#define MSD_SIF_LMEM_CONFIG_PD_AVCD_POS 5
+#define MSD_SIF_LMEM_CONFIG_PD_COMM_POS 6
+#define MSD_SIF_LMEM_CONFIG_PD_RPR_POS 7
+#define MSD_SIF_LMEM_CONFIG_PD_CCHE1_POS 14
+#define MSD_SIF_LMEM_CONFIG_PD_HEVD_POS 15
+#define MSD_SIF_LMEM_CONFIG_PD_VMIF_POS 17
+
+#define MSD_SIF_LMEM_CONFIG_SET_PD_CCHE0(a) ((a&MSD_SIF_LMEM_CONFIG_PD_MASK) <<MSD_SIF_LMEM_CONFIG_PD_CCHE0_POS )
+#define MSD_SIF_LMEM_CONFIG_SET_PD_RSB(a) ((a&MSD_SIF_LMEM_CONFIG_PD_MASK) <<MSD_SIF_LMEM_CONFIG_PD_RSB_POS )
+#define MSD_SIF_LMEM_CONFIG_SET_PD_AVSD(a) ((a&MSD_SIF_LMEM_CONFIG_PD_MASK) <<MSD_SIF_LMEM_CONFIG_PD_AVSD_POS )
+#define MSD_SIF_LMEM_CONFIG_SET_PD_MPGD(a) ((a&MSD_SIF_LMEM_CONFIG_PD_MASK) <<MSD_SIF_LMEM_CONFIG_PD_MPGD_POS )
+#define MSD_SIF_LMEM_CONFIG_SET_PD_VC1D(a) ((a&MSD_SIF_LMEM_CONFIG_PD_MASK) <<MSD_SIF_LMEM_CONFIG_PD_VC1D_POS )
+#define MSD_SIF_LMEM_CONFIG_SET_PD_AVCD(a) ((a&MSD_SIF_LMEM_CONFIG_PD_MASK) <<MSD_SIF_LMEM_CONFIG_PD_AVCD_POS )
+#define MSD_SIF_LMEM_CONFIG_SET_PD_COMM(a) ((a&MSD_SIF_LMEM_CONFIG_PD_MASK) <<MSD_SIF_LMEM_CONFIG_PD_COMM_POS )
+#define MSD_SIF_LMEM_CONFIG_SET_PD_RPR(a) ((a&MSD_SIF_LMEM_CONFIG_PD_MASK) <<MSD_SIF_LMEM_CONFIG_PD_RPR_POS )
+#define MSD_SIF_LMEM_CONFIG_SET_PD_CCHE1(a) ((a&MSD_SIF_LMEM_CONFIG_PD_MASK) <<MSD_SIF_LMEM_CONFIG_PD_CCHE1_POS )
+#define MSD_SIF_LMEM_CONFIG_SET_PD_HEVD(a) ((a&MSD_SIF_LMEM_CONFIG_PD_MASK) <<MSD_SIF_LMEM_CONFIG_PD_HEVD_POS )
+#define MSD_SIF_LMEM_CONFIG_SET_PD_VMIF(a) ((a&MSD_SIF_LMEM_CONFIG_PD_MASK) <<MSD_SIF_LMEM_CONFIG_PD_VMIF_POS )
+
+#define MSD_SIF_LMEM_CONFIG_RESET_PD_CCHE0(a) (a & (~(MSD_SIF_LMEM_CONFIG_PD_MASK << MSD_SIF_LMEM_CONFIG_PD_CCHE0_POS )))
+#define MSD_SIF_LMEM_CONFIG_RESET_PD_RSB(a) (a & (~(MSD_SIF_LMEM_CONFIG_PD_MASK << MSD_SIF_LMEM_CONFIG_PD_RSB_POS )))
+#define MSD_SIF_LMEM_CONFIG_RESET_PD_AVSD(a) (a & (~(MSD_SIF_LMEM_CONFIG_PD_MASK << MSD_SIF_LMEM_CONFIG_PD_AVSD_POS )))
+#define MSD_SIF_LMEM_CONFIG_RESET_PD_MPGD(a) (a & (~(MSD_SIF_LMEM_CONFIG_PD_MASK << MSD_SIF_LMEM_CONFIG_PD_MPGD_POS )))
+#define MSD_SIF_LMEM_CONFIG_RESET_PD_VC1D(a) (a & (~(MSD_SIF_LMEM_CONFIG_PD_MASK << MSD_SIF_LMEM_CONFIG_PD_VC1D_POS )))
+#define MSD_SIF_LMEM_CONFIG_RESET_PD_AVCD(a) (a & (~(MSD_SIF_LMEM_CONFIG_PD_MASK << MSD_SIF_LMEM_CONFIG_PD_AVCD_POS )))
+#define MSD_SIF_LMEM_CONFIG_RESET_PD_COMM(a) (a & (~(MSD_SIF_LMEM_CONFIG_PD_MASK << MSD_SIF_LMEM_CONFIG_PD_COMM_POS )))
+#define MSD_SIF_LMEM_CONFIG_RESET_PD_RPR(a) (a & (~(MSD_SIF_LMEM_CONFIG_PD_MASK << MSD_SIF_LMEM_CONFIG_PD_RPR_POS )))
+#define MSD_SIF_LMEM_CONFIG_RESET_PD_CCHE1(a) (a & (~(MSD_SIF_LMEM_CONFIG_PD_MASK << MSD_SIF_LMEM_CONFIG_PD_CCHE1_POS )))
+#define MSD_SIF_LMEM_CONFIG_RESET_PD_HEVD(a) (a & (~(MSD_SIF_LMEM_CONFIG_PD_MASK << MSD_SIF_LMEM_CONFIG_PD_HEVD_POS )))
+#define MSD_SIF_LMEM_CONFIG_RESET_PD_VMIF(a) (a & (~(MSD_SIF_LMEM_CONFIG_PD_MASK << MSD_SIF_LMEM_CONFIG_PD_VMIF_POS )))
+
+
+
+// Row-store buffer control
+//--------------------------
+// MSD_SIF_RSB_CTRL_STAT_ADDR (0x6e) //0x1b8
+#define MSD_SIF_RSB_SWITCH_REGION_ACCESS_POS 0x0
+#define MSD_SIF_RSB_SWITCH_REGION_ACCESS_MASK 0x1
+#define MSD_SIF_RSB_SWITCH_REGION_ACCESS_GET(r) (( r >> MSD_SIF_RSB_SWITCH_REGION_ACCESS_POS ) & MSD_SIF_RSB_SWITCH_REGION_ACCESS_MASK )
+#define MSD_SIF_RSB_SWITCH_REGION_ACCESS_SET(w) (( w & MSD_SIF_RSB_SWITCH_REGION_ACCESS_MASK ) << MSD_SIF_RSB_SWITCH_REGION_ACCESS_POS )
+#define MSD_SIF_RSB_INT_BASE_ADDR_SET(a) ((0x1fff & a)<<0) // 12:0
+#define MSD_SIF_RSB_XFR_XNUM_MASK ((0xff )<<13)
+#define MSD_SIF_RSB_XFR_XNUM_SET(a) ((0xff & a )<<13) //20:13
+#define MSD_SIF_RSB_XFR_YNUM_MASK ((0x7 )<<21) // 23:21
+#define MSD_SIF_RSB_XFR_YNUM_SET(a) ((0x7 & a)<<21) // 23:21
+#define MSD_SIF_RSB_SPLIT_FACTOR_MASK ((0x3 )<<24) //25:24
+#define MSD_SIF_RSB_SPLIT_FACTOR_SET(a) ((0x3 & a)<<24) //25:24
+#define MSD_SIF_RSB_XFR_MODE_MASK ((0x3 )<<26) //27:26
+#define MSD_SIF_RSB_XFR_MODE_SET(a) ((0x3 & a)<<26) //27:26
+#define MSD_SIF_RSB_XFR_START_MASK ((0x1 )<<28) //28
+#define MSD_SIF_RSB_XFR_START_SET(a) ((0x1 & a)<<28) //28
+#define MSD_SIF_RSB_APB_ACC_EN_MASK ((0x1 )<<31) //31
+#define MSD_SIF_RSB_APB_ACC_EN_SET(a) ((0x1 & a)<<31) //31
+
+#define MSD_SIF_RSB_XFR_PROG_GET(a) (( a >>29) & 0x1) //29
+#define MSD_SIF_RSB_XFR_DONE_GET(a) (( a >>30) & 0x1) //30
+#define MSD_SIF_RSB_XFR_MODE_GET(a) (( a >>26) & 0x3) //27:26
+
+
+// Ancillary RSB transfer defines
+//-------------------------------
+#define MSD_SIF_RSB_INT_BASE_ADDR_MASK 0x1FFFF
+
+//MSD_SIF_EXT_RSB_BASE_ADDR (0X6f) //0x1bc
+#define MSD_SIF_EXT_RSB_BASE_ADDR_SET(a) (a & 0xffffff) // 31:3
+//MSD_SIF_EXT_XFR_PARAMS_ADDR (0x70) 0x1c0
+#define MSD_SIF_EXT_XFR_PARAM_TF_TYPE_MASK ((0x3) <<30 ) //31:30 0:2DLU; 1:2DCR 2:MINF 3:1DTF ;
+#define MSD_SIF_EXT_XFR_PARAM_TF_TYPE(a) ((a & 0x3) <<30 ) //31:30 0:2DLU; 1:2DCR 2:MINF 3:1DTF ;
+#define MSD_SIF_EXT_XFR_PARAM_TYPE_GET(a) (( a >>30) & 0x3) //31:30
+// 2D transferred
+#define MSD_SIF_EXT_XFR_PARAM_FIELD_FRAME_MASK ((0x01)<<29) //29 : field 1 ; 0 frame
+#define MSD_SIF_EXT_XFR_PARAM_TOP_ROW_POS_MASK ((0x7ff)<<18) // row position in frame of top row of data in the transfer
+#define MSD_SIF_EXT_XFR_PARAM_COL_LFT_POS_MASK ((0xff )<<10) // collumn position in frame of left-most word in the transfer
+#define MSD_SIF_EXT_XFR_PARAM_NUM_ROW_MASK ((0x1f )<<5) // number of rows in a tile to be transferred
+#define MSD_SIF_EXT_XFR_PARAM_NUM_PER_ROW_MASK ((0x3) <<0) // number of words per row in a tile to be transferred
+
+#define MSD_SIF_EXT_XFR_PARAM_FIELD_FRAME(a) ((a & 0x01)<<29) //29 : field 1 ; 0 frame
+#define MSD_SIF_EXT_XFR_PARAM_TOP_ROW_POS(a) ((a & 0x7ff)<<18) // row position in frame of top row of data in the transfer
+#define MSD_SIF_EXT_XFR_PARAM_COL_LFT_POS(a) ((a & 0xff )<<10) // collumn position in frame of left-most word in the transfer
+#define MSD_SIF_EXT_XFR_PARAM_NUM_ROW(a) ((a & 0x1f )<<5) // number of rows in a tile to be transferred
+#define MSD_SIF_EXT_XFR_PARAM_NUM_PER_ROW(a) ((a & 0x3) <<0) // number of words per row in a tile to be transferred
+// 1D transferred
+#define MSD_SIF_EXT_XFR_PARAM_NUM_WORDS_MASK ((0x1fff)<<0) // number of words to be transferred under 1D
+#define MSD_SIF_EXT_XFR_PARAM_NUM_WORDS(a) ((a & 0x1fff)<<0) // number of words to be transferred under 1D
+#define MSD_SIF_EXT_XFR_BASE_ADDR_SET(a) ( a & 0xffffff) // 31:3
+
+#define MSD_SIF_PWT_BASE_ADDR_POS 0x0
+#define MSD_SIF_PWT_BASE_ADDR_MASK 0x3FFF
+#define MSD_SIF_PXD_BASE_ADDR_POS 0x10
+#define MSD_SIF_PXD_BASE_ADDR_MASK 0x3FFF
+
+#define MSD_SIF_PUT_PWT_BASE(w) (( w & MSD_SIF_PWT_BASE_ADDR_MASK ) << MSD_SIF_PWT_BASE_ADDR_POS )
+#define MSD_SIF_PUT_PXD_BASE(w) (( w & MSD_SIF_PXD_BASE_ADDR_MASK ) << MSD_SIF_PXD_BASE_ADDR_POS )
+
+#define MSD_SIF_BSD_BASE_ADDR_POS 0x0
+#define MSD_SIF_BSD_BASE_ADDR_MASK 0x3FFF
+#define MSD_SIF_DBFC_BASE_ADDR_POS 0x10
+#define MSD_SIF_DBFC_BASE_ADDR_MASK 0x3FFF
+#define MSD_SIF_RSB_USE_APB_OFF_POS 0x1F
+#define MSD_SIF_RSB_USE_APB_OFF_MASK 0x1
+
+#define MSD_SIF_PUT_BSD_BASE(w) (( w & MSD_SIF_BSD_BASE_ADDR_MASK ) << MSD_SIF_BSD_BASE_ADDR_POS )
+#define MSD_SIF_PUT_DBFC_BASE(w) (( w & MSD_SIF_DBFC_BASE_ADDR_MASK ) << MSD_SIF_DBFC_BASE_ADDR_POS )
+#define MSD_SIF_PUT_RSB_USE_APB(w) (( w & MSD_SIF_RSB_USE_APB_OFF_MASK ) << MSD_SIF_RSB_USE_APB_OFF_POS )
+
+#define MSD_SIF_MPRR_BASE_ADDR_POS 0x0
+#define MSD_SIF_MPRR_BASE_ADDR_MASK 0x3FFF
+#define MSD_SIF_MPRC_BASE_ADDR_POS 0x10
+#define MSD_SIF_MPRC_BASE_ADDR_MASK 0x3FFF
+
+#define MSD_SIF_PUT_MPRR_BASE(w) (( w & MSD_SIF_MPRR_BASE_ADDR_MASK ) << MSD_SIF_MPRR_BASE_ADDR_POS )
+#define MSD_SIF_PUT_MPRC_BASE(w) (( w & MSD_SIF_MPRC_BASE_ADDR_MASK ) << MSD_SIF_MPRC_BASE_ADDR_POS )
+
+
+/* MVD VMIF Options */
+#define MSD_VMIF_TAG_ACK_ON_FLUSH_POS 0
+#define MSD_VMIF_MAX_RD_REQ_SIZE_POS 1
+#define MSD_VMIF_CACHE_ENAB_POS 3
+#define MSD_VMIF_CACHE_RST_STAT_POS 4
+#define MSD_VMIF_SPLIT_READS_POS 5
+#define MSD_VMIF_SPLIT_WRITES_POS 6
+#define MSD_VMIF_FS_OFFSET_8PIX_POS 7
+#define MSD_VMIF_FS_OFFSET_CHROMA_8PIX_POS 8
+#define MSD_VMIF_CACHE_16WAY_MODE_POS 9
+#define MSD_VMIF_SCALE_MODE_POS 10
+#define MSD_VMIF_RSB_EXT_CACHE_ENAB 11
+#define MSD_VMIF_MAX_RD_SIZE_CONFIG_POS 12
+#define MSD_VMIF_MBI_RD_BUS_ENAB_POS 13
+#define MSD_VMIF_CACHE_DIS_AUTO_RST_POS 15
+#define MSD_VMIF_MBI_WR_BUS_ENAB_POS 16
+
+#define MSD_VMIF_DISABLE_BIT_POS 18
+#define MSD_VMIF_USE_RPR_STRIDES_POS 19
+#define MSD_VMIF_DBG_SEL_POS 20
+#define MSD_VMIF_USE_4K_CACHE_CTRL_POS 23
+#define MSD_VMIF_4K_CACHE_ENAB_POS 24
+#define MSD_VMIF_4K_CACHE_RST_STAT_POS 25
+#define MSD_VMIF_4K_CACHE_DIS_AUTO_RST_POS 26
+#define MSD_VMIF_PACK_FORMAT_POS 27
+#define MSD_VMIF_CACHE_MODE_POS 28
+#define MSD_VMIF_MPSAL_POS 30
+#define MSD_VMIF_CLR_FSBA_POS 31
+
+/* Extension : MVD VMIF Options */
+/* With the introduction of Pixif some of thee bits have been re-used */
+#define MSD_VMIF_USE_FBC_RPR_MASK 0x08000000 /* Bit 27 */
+#define MSD_VMIF_USE_FBC_RPR_POS 27
+
+#define MSD_VMIF_USE_MBI_RD_RPR_POS 13
+#define MSD_VMIF_USE_MBI_RD_CSC_POS 14
+#define MSD_VMIF_USE_MBI_RD_MASK 0x0006000 /* Bits 14: 13 */
+
+#define MSD_VMIF_USE_MBI_WR_RPR_POS 23
+#define MSD_VMIF_USE_MBI_WR_CSC_POS 24
+#define MSD_VMIF_USE_MBI_WR_JPG_DBF_POS 25
+#define MSD_VMIF_USE_MBI_WR_MP2_VC1_POS 26
+#define MSD_VMIF_USE_MBI_WR_MASK 0x7800000 /* Bits 26: 23 */
+
+#define MSD_VMIF_MAX_RD_128 0
+#define MSD_VMIF_MAX_RD_256 1
+#define MSD_VMIF_MAX_RD_512 2
+
+/* MVD VMIF RSB ERT ARBITER CONTROL */
+
+#define MSD_VMIF_RSB_CLIENT_DBF 0x0
+#define MSD_VMIF_RSB_CLIENT_MPR 0x1
+#define MSD_VMIF_RSB_CLIENT_PXD 0x2
+#define MSD_VMIF_RSB_CLIENT_BSD 0x3
+#define MSD_VMIF_RSB_CLIENT_PWT 0x4
+#define MSD_VMIF_RSB_CLIENT_HUF 0x5
+#define MSD_VMIF_RSB_CLIENT_MTL 0x6
+#define MSD_VMIF_RSB_CLIENT_APB 0x7
+#define MSD_VMIF_RSB_CLIENT_XFR 0x8
+#define MSD_VMIF_RSB_CLIENT_BBD 0x9
+#define MSD_VMIF_RSB_CLIENT_CQ 0xa
+#define MSD_VMIF_RSB_CLIENT_BOB 0xb
+#define MSD_VMIF_RSB_CLIENT_DFE 0xb /* Yes this is deliberately the same - they replace the other in certain core configs */
+#define MSD_VMIF_RSB_CLIENT_CQBE 0xc
+
+#define MVD_RSB_ARB_CLIENT_MASK 0xFFFF
+#define MVD_RSB_ARB_READ_CLIENT_SHIFT 0x10
+
+/* RSB Defines */
+
+#define MSD_RSB_XFR_TYPE_LUMA 0x0
+#define MSD_RSB_XFR_TYPE_CHROMA 0x1
+#define MSD_RSB_XFR_TYPE_MBINFO 0x2
+#define MSD_RSB_XFR_TYPE_DATA 0x3
+
+#define MSD_RSB_MODE_ONCHIP_TOEXT 0x0 // direct is chip to ext ; is chip transaction with ext ;
+#define MSD_RSB_MODE_OFFCHIP_TOEXT 0x1 // direct is OFF chip to ext ; is off RSB transaction with ext ; off RSB is usable ; on chip not used
+#define MSD_RSB_MODE_ONCHIP_FREXT 0x2 // direct is ext to chip ; is chip transaction with ext ;
+#define MSD_RSB_MODE_OFFCHIP_FREXT 0x3 // direct is ext to off RSB ; is off RSB transaction with ext ;off RSB is usable ; on chip not used
+#define MSD_RSB_APB_ACC_EN_BIT 0x80000000
+
+
+/* MSD RPR Defines */
+#define MSD_RPR_SIZE_WIDTH_POS 0
+#define MSD_RPR_SIZE_HEIGHT_POS 16
+#define MSD_RPR_SIZE_WIDTH_MASK 0x3fff //14 bits
+
+#define MSD_RPR_FILL_VALUE_Y_POS 0
+#define MSD_RPR_FILL_VALUE_U_POS 8
+#define MSD_RPR_FILL_VALUE_V_POS 16
+#define MSD_RPR_FILL_VALUE_MASK 0xff // 8bits
+
+#define MSD_RPR_CTRL_START_POS 0
+#define MSD_RPR_CTL_FILL_MODE_POS 1
+#define MSD_RPR_CTL_ROUNDING_POS 2
+#define MSD_RPR_CTL_H_PRIME_M_POS 8
+#define MSD_RPR_CTL_V_PRIME_N_POS 12
+#define MSD_RPR_CTL_PRIME_MASK 0xf
+#define MSD_RPR_CTL_IN_FS_IDC_POS 16
+#define MSD_RPR_CTL_OUT_FS_IDC_POS 24
+#define MSD_RPR_CTL_FS_IDC_MASK 0x1f
+
+#define MSD_RPR_CTRL_START_BIT 1
+
+#define MSD_RPR_STATUS_IN_PROG_POS 29
+
+
+/* Decoupled data packing */
+/* Pack Base Set */
+#define MSD_SIF_PLQ_PACK_ADDR_MASK 0xFFFFFFFF
+#define MSD_SIF_PLQ_PACK_ADDR_SHIFT 0x0
+
+#define MSD_SIF_SET_PLQ_PACK_ADDR( w ) (( w & MSD_SIF_PLQ_WRPACK_ADDR_MASK ) << MSD_SIF_PLQ_WRPACK_ADDR_SHIFT )
+
+/* PRB Bin configuration */
+#define MSD_SIF_PLQ_BIN_SIZE_MASK 0x3FFFFF
+#define MSD_SIF_PLQ_BIN_SIZE_SHIFT 0x0
+#define MSD_SIF_PLQ_NUM_BINS_MASK 0x3FF
+#define MSD_SIF_PLQ_NUM_BINS_SHIFT 0x16
+
+#define MSD_SIF_SET_PLQ_BIN_SIZE( w ) (( w & MSD_SIF_PLQ_BIN_SIZE_MASK ) << MSD_SIF_PLQ_BIN_SIZE_SHIFT )
+#define MSD_SIF_SET_PLQ_NUM_BINS( w ) (( w & MSD_SIF_PLQ_NUM_BINS_MASK ) << MSD_SIF_PLQ_NUM_BINS_SHIFT )
+
+/* DCP Bin configuration */
+#define MSD_SIF_DCP_START_BINDEX_MASK 0x3FF
+#define MSD_SIF_DCP_START_BINDEX_SHIFT 0x0
+#define MSD_SIF_DCP_NUM_BINS_MASK 0x3FF
+#define MSD_SIF_DCP_NUM_BINS_SHIFT 0xA
+
+#define MSD_SIF_SET_DCP_START_BINDEX( w )(( w & MSD_SIF_DCP_START_BINDEX_MASK ) << MSD_SIF_DCP_START_BINDEX_SHIFT )
+#define MSD_SIF_SET_DCP_NUM_BINS( w ) (( w & MSD_SIF_DCP_NUM_BINS_MASK ) << MSD_SIF_DCP_NUM_BINS_SHIFT )
+
+
+/////////////////////////////////////////////////////////////////////////////////
+// Function Prototypes
+/////////////////////////////////////////////////////////////////////////////////
+
+#endif /* _MVD_SIF_CONTROL_H_ */
+
+/* End of file */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/mvd_types.h b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/mvd_types.h
new file mode 100755
index 000000000000..ccd93d3e1d0f
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/Incl/mvd_types.h
@@ -0,0 +1,132 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+
+ Author : MediaIP FW Team
+ File name : mvd_types.h
+ Function : Used as a home for generic MVD base decoder
+ types
+
+ ***************************************************/
+
+#ifndef _MVD_TYPES_H_
+#define _MVD_TYPES_H_
+
+#include "basetype.h"
+
+///////////////////////////////////////////////////////
+// tAuxCRCData
+
+typedef struct
+{
+ u_int32 uDpbCRC2;
+ u_int32 uBSCRC;
+ u_int32 uCRC0;
+ u_int32 uCRC1;
+ u_int32 uCRC2;
+ u_int32 uCRC3;
+ u_int32 uCRC4;
+ u_int32 uCRC5;
+ u_int32 uCRC6;
+ u_int32 uCRC7;
+
+} tAuxCRCData, *ptAuxCRCData;
+
+///////////////////////////////////////////////////////
+// tAuxCRC2Data
+
+typedef struct
+{
+ u_int32 uCRC8;
+ u_int32 uCRC9;
+ u_int32 uCRC10;
+ u_int32 uCRC11;
+ u_int32 uCRC12;
+ u_int32 uCRC13;
+ u_int32 uCRC14;
+
+} tAuxCRC2Data, *ptAuxCRC2Data;
+
+#define MVD_TRUE 0x1UL
+#define MVD_FALSE 0x0UL
+
+typedef float MvdFloat; // fVariableName, *pfPointerName
+typedef double MvdDouble; // dVariableName, *pdPointerName
+
+typedef volatile u_int32 MvdHwReg; // rVariableName, *prPointerName
+typedef volatile u_int32 *MvdHwAddr;
+
+/* ************** */
+/* Debug arrays */
+/* ************** */
+typedef struct
+{
+ int32 index;
+ int32 array[512];
+} DBG_ARRAY_512;
+
+typedef struct
+{
+ int32 index;
+ int32 array[1024];
+} DBG_ARRAY_1024;
+
+typedef struct
+{
+ int32 index;
+ int32 array[2048];
+} DBG_ARRAY_2048;
+
+typedef struct
+{
+ int32 index;
+ int32 array[4096];
+} DBG_ARRAY_4096;
+
+///////////////////////////////////////////////////////
+// Metadata structs
+
+///////////////////////////////////////////////////////
+// TimeStamp Metadata
+
+typedef struct
+{
+ u_int32 uPTS;
+ u_int32 uDTS;
+ u_int32 uPESFlags;
+ bool bValid;
+
+} tMVD_METADATA_TS, *ptMVD_METADATA_TS;
+
+///////////////////////////////////////////////////////
+// Pic Struct Metadata
+
+typedef struct
+{
+ u_int32 uDummy;
+ bool bValid;
+
+} tMVD_METADATA_PIC_STRUCT, *ptMVD_METADATA_PIC_STRUCT;
+
+///////////////////////////////////////////////////////
+// UData Metadata
+
+typedef struct
+{
+ bool bValid;
+ void * pUDataMemChunk;
+ u_int32 uWrPtr;
+
+} tMVD_METADATA_UDATA, *ptMVD_METADATA_UDATA;
+
+#endif /* _MVD_TYPES_H_ */
+
+/* End of file */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/KernelIF/DecKernelLib.c b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/KernelIF/DecKernelLib.c
new file mode 100755
index 000000000000..ca7d70b55814
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/KernelIF/DecKernelLib.c
@@ -0,0 +1,152 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+
+ Filename: DecoderLib.c
+ Description: Decoder Library API level
+ Author: Media IP FW team (Belfast & Shanghai)
+
+ ****************************************************/
+
+/////////////////////////////////////////////////////////////////////////////////
+// Header files
+/////////////////////////////////////////////////////////////////////////////////
+
+#include "basetype.h"
+#include "mediaip_fw_types.h"
+#include "pal.h"
+#include "DecKernelLib.h"
+#include "DecKernelLibPrivate.h"
+#include "DecKernelLibCfg.h"
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Variables
+/////////////////////////////////////////////////////////////////////////////////
+
+DEC_KERNEL_LIB gDecKernelLib = { 0x0 };
+
+/////////////////////////////////////////////////////////////////////////////////
+// Code
+/////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: decoder_kernel_lib_init //
+// //
+// DESCRIPTION: This function initialises the decoder library //
+// to be called from kernel space //
+// It's only purpose is to post interrupts via callback to a queue //
+// for processing in userspace //
+// //
+// INPUTS: pCfg - Pointer to a static configuration structure for the //
+// library //
+// //
+// OUTPUTS: None. //
+// //
+// RETURNS: MEDIAIP_FW_STATUS_ //
+// OK - Success. //
+// ALREADY_INIT - This function has already been called and no //
+// subsequent call to decoderlib_term made //
+// //
+// NOTES: None. //
+// //
+// CONTEXT: This function must be called from non-interrupt context //
+// //
+////////////////////////////////////////////////////////////////////////////////////
+
+MEDIAIP_FW_STATUS decoder_kernel_lib_init ( DECODERLIB_KERNEL_CFG * pCfg )
+{
+ MEDIAIP_FW_STATUS eRetCode = MEDIAIP_FW_STATUS_OK;
+
+ if ( gDecKernelLib.bInit == FALSE )
+ {
+ gDecKernelLib.bInit = TRUE;
+
+ /* Make all necessary init calls */
+ internal_decoder_kernel_lib_init ( pCfg );
+ }
+ else
+ {
+ eRetCode = MEDIAIP_FW_STATUS_ALREADY_INIT;
+ }
+
+ return eRetCode;
+
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: decoderlib_register_event_callback //
+// //
+// DESCRIPTION: This function registers a handler for reporting decoder events //
+// //
+// INPUTS: hHandle - handle for the stream with which to register the //
+// callbacks //
+// pfCallback - Function ponter to be executed when a decoder //
+// event is raised //
+// //
+// OUTPUTS: None. //
+// //
+// RETURNS: MEDIAIP_FW_STATUS_ //
+// OK - Success. //
+// BAD_HANDLE - hHandle is not a valid decoder library //
+// handle //
+// //
+// NOTES: None. //
+// //
+// CONTEXT: Unknown if there are any constraints here as yet //
+// //
+////////////////////////////////////////////////////////////////////////////////////
+
+MEDIAIP_FW_STATUS decoder_kernel_lib_register_isr_callback ( u_int32 uMalIdx,
+ DecKernelLib_Isr_Callback_t pfCallback )
+{
+
+ if ( gDecKernelLib.bInit == FALSE )
+ {
+ pal_trace( DECODER_TL_WARNING, "DECODER_LIB: decoder_kernel_lib_register_isr_callback : Invalid Malone\n", uMalIdx );
+
+ return MEDIAIP_FW_STATUS_BAD_HANDLE;
+ }
+
+ internal_decoder_kernel_lib_register_isr_callback ( uMalIdx,
+ pfCallback );
+
+ return MEDIAIP_FW_STATUS_OK;
+
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: decoderlib_term //
+// //
+// DESCRIPTION: Deinitialises decode library //
+// //
+// INPUTS: None //
+// //
+// OUTPUTS: None. //
+// //
+// RETURNS: MEDIAIP_FW_STATUS_ //
+// OK - Success. //
+// //
+// NOTES: None. //
+// //
+// CONTEXT: This function must be called from non-interrupt context //
+// //
+////////////////////////////////////////////////////////////////////////////////////
+
+MEDIAIP_FW_STATUS decoder_kernel_lib_term ( )
+{
+ MEDIAIP_FW_STATUS eRetCode = MEDIAIP_FW_STATUS_OK;
+
+ gDecKernelLib.bInit = FALSE;
+
+ return eRetCode;
+
+}
+
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/KernelIF/DecKernelLibCfg.h b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/KernelIF/DecKernelLibCfg.h
new file mode 100755
index 000000000000..8cee711dc10c
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/KernelIF/DecKernelLibCfg.h
@@ -0,0 +1,95 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+
+ Filename: DecLibCfg.h
+ Description: Decoder Library Configuration
+ Author: Media IP FW team (Belfast & Shanghai)
+
+ *******************************************************/
+
+#ifndef _DECODER_LIB_CFG_H_
+#define _DECODER_LIB_CFG_H_
+
+/////////////////////////////////////////////////////////////////////////////////
+// Header files
+/////////////////////////////////////////////////////////////////////////////////
+
+#ifndef VPU_KERNEL_BUILD
+#include "video_subsystem.h"
+#endif
+#include "mediaip_fw_types.h"
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Macros
+/////////////////////////////////////////////////////////////////////////////////
+
+/* Local defines cast to those in global cfg file */
+#define DECODERLIB_MAX_MALONES MEDIAIP_MAX_NUM_MALONES
+#define DECODERLIB_MAX_DBE_UNITS 0x2
+
+/* These don't really need to be passed in the cfg methinks... */
+#define DECODERLIB_NUM_STREAMS NUM_DECODER_STREAMS
+#define DECODERLIB_MAX_NUM_FRAMES MAX_NUM_FRAMES_PER_STREAM
+#if HEVC_JVT_MODEL < 92
+#define DECODERLIB_MAX_MBI_FRAMES 0x12
+#else
+#define DECODERLIB_MAX_MBI_FRAMES 0x11
+#endif
+#define DECODERLIB_MAX_DFE_AREAS 0x1
+#define DECODERLIB_MAX_NUM_OVLP_FRMS 1
+#define DECODERLIB_METADATA_AREA_NULL 0xFF
+#define DECODERLIB_NUM_EVENTS_PER_STREAM 4
+#define DECODERLIB_NUM_CMDS_PER_STREAM 4
+
+#define DECODERLIB_MAX_MVC_DPID 1
+#define DECODERLIB_MAX_MVC_TARGET_VIEWS 2
+#define DECODERLIB_MAX_MVC_VIEWS 4
+
+#define DECODERLIB_MAX_DPVS 0x1
+#define DECODERLIB_PIXIF_MAX_UPIX_TARGETS 0x2
+#define DECODERLIB_PIXIF_MAX_FBC_TARGETS 0x2
+#define DECODERLIB_MAX_STREAM_LEVELS DECODERLIB_MAX_MVC_VIEWS
+
+
+#define DECODERLIB_MAX_STR_BUFFERS DECODERLIB_MAX_STREAM_LEVELS
+#define DECODERLIB_RC4_CONTEXT_VALS 66
+
+#if ( TARGET_LEVEL == HAPS ) || ( TARGET_LEVEL == SIMULATION )
+#define DECODERLIB_NUM_DBG_FIFOS 26
+#else
+#define DECODERLIB_NUM_DBG_FIFOS 1
+#endif
+
+#ifdef DECLIB_ENABLE_DCP
+#define DECODERLIB_MAX_CQ_PER_MALONE 0x3
+#else
+#define DECODERLIB_MAX_CQ_PER_MALONE 0x1
+#endif
+
+// Enable processing of PAFF streams
+// If defined Field frame storage choice is made at a picture level
+// otherwise it is made as a sequence level
+//#define PIXIF_STORE_AS_PAFF
+
+//-------------------------------------------------
+// Some options for testing different HW Configs
+//-------------------------------------------------
+//#define FSLCACHE0_BYPASS
+#define ALLOW_CHROMA_DP
+#define ALLOW_MPS_ALIGN
+#define ALLOW_OFFSET_FS
+//#define FORCE_UNCACHED_8x8
+//-------------------------------------------------
+
+#endif /* _DECODER_LIB_CFG_H_ */
+
+/* End of File */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/KernelIF/DecKernelLibPrivate.c b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/KernelIF/DecKernelLibPrivate.c
new file mode 100755
index 000000000000..1aee23588cc0
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/KernelIF/DecKernelLibPrivate.c
@@ -0,0 +1,171 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+
+ Filename: DecoderLibPrivate.c
+ Description: Decoder Library API level
+ Author: Kyle McAdoo - Media IP FW Team ( Belfast & Shanghai )
+
+ ***************************************************/
+
+/////////////////////////////////////////////////////////////////////////////////
+// Header files
+/////////////////////////////////////////////////////////////////////////////////
+
+#include "basetype.h"
+#include "mediaip_fw_types.h"
+#include "pal.h"
+#include "DecKernelLibPrivate.h"
+#include "DecKernelLibHWControl.h"
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Variables
+/////////////////////////////////////////////////////////////////////////////////
+
+u_int32 uMvdKernelIrqPin[DECODERLIB_MAX_MALONES][0x2];
+
+/////////////////////////////////////////////////////////////////////////////////
+// Extern function prototypes
+/////////////////////////////////////////////////////////////////////////////////
+
+extern DEC_KERNEL_LIB gDecKernelLib;
+extern MALONE_KERNEL_HW_SESSION gMvdKernelHw[(DECODERLIB_MAX_MALONES + 1)];
+
+extern MEDIAIP_IRQ_RETCODE mvd_kernel_hw_primary_isr ( u_int32 irq_val );
+extern MEDIAIP_IRQ_RETCODE mvd_kernel_hw_secondary_isr ( u_int32 irq_val );
+
+/////////////////////////////////////////////////////////////////////////////////
+// Code
+/////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: internal_decoder_kernel_lib_init //
+// //
+// DESCRIPTION: This function initialises the decoder library //
+// more notes to follow when it works... //
+// //
+// INPUTS: None //
+// //
+// OUTPUTS: None. //
+// //
+// RETURNS: MEDIAIP_FW_STATUS_ //
+// OK - Success. //
+// BAD_PARAMETER - Configuration structure not initialised //
+// ALREADY_INIT - //
+// //
+// NOTES: None. //
+// //
+// CONTEXT: This function must be called from non-interrupt context //
+// //
+////////////////////////////////////////////////////////////////////////////////////
+
+MEDIAIP_FW_STATUS internal_decoder_kernel_lib_init ( DECODERLIB_KERNEL_CFG * pCfg )
+{
+ MEDIAIP_FW_STATUS RetCode = MEDIAIP_FW_STATUS_OK;
+
+ /* Parse interrupt config */
+ internal_decoder_kernel_lib_parse_cfg ( pCfg,
+ FALSE );
+
+ /* Setup hardware view of Malone */
+ mvd_kernel_hw_control_init ( pCfg );
+
+ return RetCode;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: internal_decoder_kernel_lib_register_isr_callback //
+// //
+// DESCRIPTION: This function registers handlers for event processing //
+// more notes to follow when it works... //
+// //
+// INPUTS: hHandle - handle for the stream with which to register the //
+// callbacks //
+// pfCallback - Function ponter to be executed when a decoder //
+// event is raised //
+// //
+// OUTPUTS: None. //
+// //
+// RETURNS: None. //
+// //
+// NOTES: None. //
+// //
+// CONTEXT: Unknown if there are any constraints here as yet //
+// //
+////////////////////////////////////////////////////////////////////////////////////
+
+void internal_decoder_kernel_lib_register_isr_callback ( u_int32 uMalIdx,
+ DecKernelLib_Isr_Callback_t pfCallback
+ )
+{
+ gDecKernelLib.pfCallback[uMalIdx] = pfCallback;
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: internal_decoder_kernel_lib_parse_cfg //
+// //
+// DESCRIPTION: Update DecoderLib structs with info from the configuration //
+// //
+// INPUTS: pCfg - The DecLib configuration //
+// bCheck - A control variable which allows prints on changes in //
+// //
+// OUTPUTS: None. //
+// //
+// RETURNS: None. //
+// //
+// NOTES: Set bCheck in snapshot restarts to see what may be different //
+// in the configuration of the generation and restart platforms //
+// //
+// CONTEXT: Call from thread context //
+// //
+////////////////////////////////////////////////////////////////////////////////////
+
+void internal_decoder_kernel_lib_parse_cfg ( DECODERLIB_KERNEL_CFG * pCfg,
+ bool bCheck
+ )
+{
+ PAL_PFNISR pFnDecodeIsr;
+ u_int32 uMalIdx;
+
+ gDecKernelLib.uNumMalones = pCfg->uNumMalones;
+
+ for ( uMalIdx = 0x0; uMalIdx < gDecKernelLib.uNumMalones; uMalIdx++ )
+ {
+ uMvdKernelIrqPin[uMalIdx][0x0] = pCfg->uMaloneIrqPin[uMalIdx][0x0];
+ uMvdKernelIrqPin[uMalIdx][0x1] = pCfg->uMaloneIrqPin[uMalIdx][0x1];
+ }
+
+ /* Finally claim the interrupts */
+ pFnDecodeIsr = ( PAL_PFNISR )mvd_kernel_hw_primary_isr;
+ pal_int_register ( uMvdKernelIrqPin[0x0][0x0], pFnDecodeIsr, FALSE );
+ pFnDecodeIsr = ( PAL_PFNISR )mvd_kernel_hw_secondary_isr;
+
+ /* This is a safety check in case a lazy player does not setup the second irq */
+ if ( uMvdKernelIrqPin[0x0][0x0] != uMvdKernelIrqPin[0x0][0x1] )
+ {
+ pal_int_register ( uMvdKernelIrqPin[0x0][0x1], pFnDecodeIsr, FALSE );
+ }
+
+ if ( gDecKernelLib.uNumMalones > 0x1 )
+ {
+ pFnDecodeIsr = ( PAL_PFNISR )mvd_kernel_hw_primary_isr;
+ pal_int_register ( uMvdKernelIrqPin[0x1][0x0], pFnDecodeIsr, FALSE );
+ pFnDecodeIsr = ( PAL_PFNISR )mvd_kernel_hw_secondary_isr;
+
+ if ( uMvdKernelIrqPin[0x1][0x0] != uMvdKernelIrqPin[0x1][0x1] )
+ {
+ pal_int_register ( uMvdKernelIrqPin[0x1][0x1], pFnDecodeIsr, FALSE );
+ }
+ }
+}
+
+
+/* End of file */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/KernelIF/DecKernelLibPrivate.h b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/KernelIF/DecKernelLibPrivate.h
new file mode 100755
index 000000000000..a3dd00f62272
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/DecKLib/KernelIF/DecKernelLibPrivate.h
@@ -0,0 +1,69 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+
+ Filename: DecKernelPrivate.h
+ Description: Decoder Library Private header file - not
+ for inclusion by code outside of decoder lib.
+ Author: Media IP FW team (Belfast & Shanghai)
+
+ *******************************************************/
+
+/////////////////////////////////////////////////////////////////////////////////
+// Header files
+/////////////////////////////////////////////////////////////////////////////////
+
+#include "DecKernelLib.h"
+
+/* Include NO other files here */
+
+#ifndef _DECODER_KERN_LIB_PRIV_H_
+#define _DECODER_KERN_LIB_PRIV_H_
+
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Macros
+/////////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////////
+// Global Structures
+/////////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////
+// DecoderLib Context structure
+
+typedef struct decoderlib_inst
+{
+ bool bInit;
+ u_int32 uNumMalones;
+ /* One per Malone, kernel lib only has concept of Malone hardware, not */
+ /* the individual streams running on it! */
+ DecKernelLib_Isr_Callback_t pfCallback[DECODERLIB_MAX_MALONES];
+
+} DEC_KERNEL_LIB;
+
+/////////////////////////////////////////////////////////////////////////////////
+// Function Prototypes
+/////////////////////////////////////////////////////////////////////////////////
+
+MEDIAIP_FW_STATUS internal_decoder_kernel_lib_init ( DECODERLIB_KERNEL_CFG * pCfg );
+
+void internal_decoder_kernel_lib_register_isr_callback ( u_int32 uMalIdx,
+ DecKernelLib_Isr_Callback_t pfCallback
+ );
+
+ void internal_decoder_kernel_lib_parse_cfg ( DECODERLIB_KERNEL_CFG * pCfg,
+ bool bCheck
+ );
+
+#endif /* _DECODER_KERN_LIB_PRIV_H_ */
+
+/* End of File */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/Incl/basetype.h b/drivers/mxc/vpu-malone/Malone_Firmware/Incl/basetype.h
new file mode 100755
index 000000000000..a90567ce278c
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/Incl/basetype.h
@@ -0,0 +1,343 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+ Filename: basetype.h
+ Description: Public header file for use in all FW
+ Author: Media IP FW team (Belfast)
+
+ ************************************************/
+
+#ifndef _BASETYPE_H_
+#define _BASETYPE_H_
+#ifndef VPU_KERNEL_BUILD
+#include <stdint.h>
+#include <stdio.h>
+#else
+#include <linux/types.h>
+#include <linux/kernel.h>
+#endif
+
+#ifdef WIN32
+#if _MSC_VER
+typedef unsigned __int64 u_int64;
+#else
+typedef unsigned long long u_int64;
+#endif
+#else
+typedef unsigned long long u_int64;
+#endif
+
+#ifdef MALONE_64BIT_ADDR
+typedef uint64_t uint_addr;
+#else
+typedef uint32_t uint_addr;
+#endif
+
+typedef uint32_t u_int32;
+typedef uint16_t u_int16;
+typedef uint8_t u_int8;
+
+//Alignment Macro
+#define ALIGN_SIZE(x) (((x)+sizeof(u_int32) - 1)/(sizeof(u_int32)))
+
+#ifdef WIN32
+#if _MSC_VER
+typedef signed __int64 int64;
+#else
+typedef signed long long int64;
+#endif
+#else
+typedef signed long long int64;
+#endif
+
+typedef int32_t int32;
+typedef int16_t int16;
+typedef int8_t int8;
+typedef unsigned char BYTE;
+
+// XXX:TAS No idea what all this ifdefing is about
+// should just need the C++ ifdef
+#ifndef HOST_BUILD
+#ifndef COREPLAY_API
+#ifndef _MSC_VER
+#ifndef VPU_KERNEL_BUILD
+typedef unsigned int bool;
+#endif
+#endif
+#else
+#ifndef _MSC_VER
+typedef unsigned int bool;
+#endif
+#endif
+#else
+ #ifndef __cplusplus
+ // bool is defined in cpp
+ typedef unsigned int bool;
+ #endif /* __cplusplus */
+#endif
+
+typedef unsigned char BOOLEAN;
+
+#define VOID_PARAMS void
+
+#define INT32 int32
+
+#define UINT8 u_int8
+#define UINT16 u_int16
+#define UINT32 u_int32
+#define UINT64 u_int64
+#ifdef _MSC_VER
+#define BOOL int
+#else
+#define BOOL bool
+#endif
+#define SINT8 int8
+#define SINT16 int16
+#define SINT32 int32
+#ifdef WIN32
+#define SINT64 int64
+#define SINT64_MIN (-9223372036854775807i64 - 1i64)
+#else
+#define SINT64 int64
+#define SINT64_MIN (-9223372036854775807LL - 1LL)
+#endif
+
+#ifndef VPU_KERNEL_BUILD
+#define SUCCESS 0
+#define FAILURE -1
+#endif
+
+#ifdef __cplusplus
+#ifndef FALSE
+ #define FALSE 0
+#endif
+#ifndef TRUE
+ #define TRUE 1
+#endif
+#else // 'C'
+#ifndef false
+ #define false 0
+#endif
+#ifndef true
+ #define true 1
+#endif
+
+#ifndef FALSE
+ #define FALSE 0
+#endif
+#ifndef TRUE
+ #define TRUE 1
+#endif
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef OKAY
+#define OKAY 0
+#endif
+
+#ifndef ZERO
+#define ZERO 0
+#endif
+
+// Define more error types as used - 1st is generic
+#define MEDIAIP_ERROR_FLAG 1
+#define MEDIAIP_END_ES 2
+#define MEDIAIP_DECODER_EXIT 3
+#define MEDIAIP_ENCODER_EXIT 4
+#define MEDIAIP_VC1D_NOFREEFRAMES 5
+#define MEDIAIP_DECODER_SKIP 6
+
+/* Alignment macros - align address to a specific byte alignment */
+#define MEDIAIP_ALIGN_16(addr) addr = (addr + (( 0x1 << 0x4 ) - 0x1 ) ) & ~((( 0x1 << 0x4 ) - 0x1 ))
+#define MEDIAIP_ALIGN_32(addr) addr = (addr + (( 0x1 << 0x5 ) - 0x1 ) ) & ~((( 0x1 << 0x5 ) - 0x1 ))
+#define MEDIAIP_ALIGN_64(addr) addr = (addr + (( 0x1 << 0x6 ) - 0x1 ) ) & ~((( 0x1 << 0x6 ) - 0x1 ))
+#define MEDIAIP_ALIGN_128(addr) addr = (addr + (( 0x1 << 0x7 ) - 0x1 ) ) & ~((( 0x1 << 0x7 ) - 0x1 ))
+#define MEDIAIP_ALIGN_256(addr) addr = (addr + (( 0x1 << 0x8 ) - 0x1 ) ) & ~((( 0x1 << 0x8 ) - 0x1 ))
+#define MEDIAIP_ALIGN_512(addr) addr = (addr + (( 0x1 << 0x9 ) - 0x1 ) ) & ~((( 0x1 << 0x9 ) - 0x1 ))
+
+/* used when declaring single bitfields
+*/
+#define FLAG 1
+
+#ifndef WIN32
+ #if CPU == MIPS
+ #define DOUBLE_ALIGN __attribute__((aligned(8)))
+ #define SECTION(sec) __attribute__ ((section (#sec)))
+ #define ALIGNED(ali) __attribute__ ((aligned (ali)))
+ #else
+ #define DOUBLE_ALIGN
+ #endif
+#endif // win32
+/* We need to stop defining ARM and use only CPU == ARM !!! */
+/* Lose all #ifdef ARM from code */
+
+/* - Only for RCVCT */
+#ifdef __CC_ARM
+ #define ALIGN_8_u_int8 __align(8) u_int8
+ #define ALIGN_8_u_int16 __align(8) u_int16
+ #define ALIGN_8_u_int32 __align(8) u_int32
+ #define ALIGN_256_u_int16 __align(256) u_int16
+ #define ALIGN_256_u_int32 __align(256) u_int32
+ #define ALIGN_1024_u_int32 __align(1024) u_int32
+ #define ALIGN_1024_u_int64 __align(1024) u_int64
+ #define ALIGN_1024 __align(1024)
+#else
+/* All others? */
+ #define ALIGN_8_u_int8 u_int8 __attribute__((aligned(8)))
+ #define ALIGN_8_u_int16 u_int16 __attribute__((aligned(8)))
+ #define ALIGN_8_u_int32 u_int32 __attribute__((aligned(8)))
+ #define ALIGN_256_u_int16 u_int16 __attribute__((aligned(256)))
+ #define ALIGN_256_u_int32 u_int32 __attribute__((aligned(256)))
+ #define ALIGN_1024_u_int32 u_int32 __attribute__((aligned(1024)))
+ #define ALIGN_1024_u_int64 u_int64 __attribute__((aligned(1024)))
+ #define ALIGN_1024 __attribute__((aligned(1024)))
+#endif
+
+#ifndef COREPLAY_API
+#if RTOS == UCOS
+
+/* Additions for uCOS */
+
+typedef unsigned char INT8U; /* Unsigned 8 bit quantity */
+typedef signed char INT8S; /* Signed 8 bit quantity */
+typedef unsigned int INT16U; /* Unsigned 16 bit quantity */
+typedef signed int INT16S; /* Signed 16 bit quantity */
+typedef unsigned long INT32U; /* Unsigned 32 bit quantity */
+typedef signed long INT32S; /* Signed 32 bit quantity */
+typedef float FP32; /* Single precision floating point */
+typedef double FP64; /* Double precision floating point */
+
+typedef unsigned int OS_STK; /* Each stack entry is 16-bit wide */
+typedef unsigned int OS_CPU_SR; /* Define size of CPU status register (PSR = 32 bits) */
+
+#define UBYTE INT8U /* ... to uC/OS V1.xx. Not actually needed for ... */
+#define WORD INT16S /* ... uC/OS-II. */
+#define UWORD INT16U
+#define LONG INT32S
+#define ULONG INT32U
+
+#endif
+
+typedef signed short int SHORT; /* Signed 16 bit quantity */
+typedef unsigned short USHORT;
+
+#endif /* COREPLAY_API */
+
+/****************************************************************************/
+/* */
+/* Hardware register access macros */
+/* */
+/****************************************************************************/
+
+#define RMO(y) \
+ ( ((y) & 0x00000001) ? 0 : \
+ ( ((y) & 0x00000002) ? 1 : \
+ ( ((y) & 0x00000004) ? 2 : \
+ ( ((y) & 0x00000008) ? 3 : \
+ ( ((y) & 0x00000010) ? 4 : \
+ ( ((y) & 0x00000020) ? 5 : \
+ ( ((y) & 0x00000040) ? 6 : \
+ ( ((y) & 0x00000080) ? 7 : \
+ ( ((y) & 0x00000100) ? 8 : \
+ ( ((y) & 0x00000200) ? 9 : \
+ ( ((y) & 0x00000400) ? 10 : \
+ ( ((y) & 0x00000800) ? 11 : \
+ ( ((y) & 0x00001000) ? 12 : \
+ ( ((y) & 0x00002000) ? 13 : \
+ ( ((y) & 0x00004000) ? 14 : \
+ ( ((y) & 0x00008000) ? 15 : \
+ ( ((y) & 0x00010000) ? 16 : \
+ ( ((y) & 0x00020000) ? 17 : \
+ ( ((y) & 0x00040000) ? 18 : \
+ ( ((y) & 0x00080000) ? 19 : \
+ ( ((y) & 0x00100000) ? 20 : \
+ ( ((y) & 0x00200000) ? 21 : \
+ ( ((y) & 0x00400000) ? 22 : \
+ ( ((y) & 0x00800000) ? 23 : \
+ ( ((y) & 0x01000000) ? 24 : \
+ ( ((y) & 0x02000000) ? 25 : \
+ ( ((y) & 0x04000000) ? 26 : \
+ ( ((y) & 0x08000000) ? 27 : \
+ ( ((y) & 0x10000000) ? 28 : \
+ ( ((y) & 0x20000000) ? 29 : \
+ ( ((y) & 0x40000000) ? 30 : \
+ ( ((y) & 0x80000000) ? 31 : 0 ))))))))))))))))))))))))))))))))
+
+/*
+ * Access macros used to get, set/clear bits within a hardware register.
+ * These macros *do not* perform any automatic shifting of bits and are
+ * meant to be used with bit definitions which include their encoded bit
+ * position within the register definition (e.g. an enable bit).
+ */
+
+#ifdef VSIM_ENV
+ UINT32 MEDIAIP_GET(UINT32,UINT32);
+ void MEDIAIP_SET(UINT32,UINT32,UINT32);
+ #define MEDIAIP_PUT(reg,mask,val) { \
+ VSimAPI_WriteRegister((UINT32) reg, val); \
+ }
+ UINT32 MEDIAIP_SM_GET(volatile UINT32 *);
+ void MEDIAIP_SM_SET(volatile UINT32 *, UINT32, UINT32 );
+ void MEDIAIP_SM_PUT(volatile UINT32 *, UINT32 );
+
+#else
+
+ #define MEDIAIP_GET(reg,mask) (*(LPREG)(reg) & (mask))
+ #define MEDIAIP_SET(reg,mask,val) (*(LPREG)(reg)) = ((*(LPREG)(reg) & ~(mask)) | ((val) & (mask)))
+ #define MEDIAIP_PUT(reg,val) (*(LPREG)(reg)) = (val)
+ #define MEDIAIP_SM_GET(x) (*(x))
+ #define MEDIAIP_SM_SET(a,b,c) (*(a)) = (((*(a)) & ~(b)) | ((c) & (b)))
+ #define MEDIAIP_SM_PUT(a,b) (*(a)) = (b)
+
+// IDJ: Consider using this?
+// No- there are only a few instances where this would make a difference.
+//efine MEDIAIP_SET(reg,mask,val) (*(LPREG)(reg)) = ((~(mask) ? 0 : (*(LPREG)(reg) & ~(mask))) | ((val) & (mask)))
+
+#endif
+
+/*
+ * Access macros used to get & set a numerical value within a hardware
+ * register. These macros perform automatic shifting (based on the mask)
+ * of the numerical value used. These macros are useful for setting a
+ * numerical value into a multi-bit contiguous field within a register.
+ */
+#define MEDIAIP_GET_VAL(reg,mask) ((*(LPREG)(reg) & (mask)) >> RMO(mask))
+#define MEDIAIP_SET_VAL(reg,mask,val) (*(LPREG)(reg)) = \
+ ((*(LPREG)(reg) & ~(mask)) | (((unsigned long)(val) << RMO(mask)) & (mask)))
+
+#define MEDIAIP_REGWRITE(reg,val) *((LPREG)(reg)) = (val)
+#define MEDIAIP_REGREAD(reg) *((LPREG)(reg))
+
+
+#define MEDIAIP_SET_REG(reg,mask,val) reg = ((reg & ~(mask)) | ((val) & (mask)))
+#define MEDIAIP_GET_REG(reg,mask) reg & mask
+
+typedef unsigned long HW_DWORD; /* was u_int32; */
+typedef unsigned short HW_WORD; /* was u_int16; */
+typedef unsigned char HW_BYTE; /* was u_int8; */
+typedef unsigned int HW_BOOL; /* was bool; */
+typedef void HW_VOID;
+
+typedef volatile u_int32 *LPREG;
+
+#ifdef __CC_ARM
+#define FUNC_INLINE __inline
+#else
+#define FUNC_INLINE inline
+#endif
+
+#endif /* _BASETYPE_H_ */
+
+/* End of File */
+
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/Incl/mediaip_fw_defines.h b/drivers/mxc/vpu-malone/Malone_Firmware/Incl/mediaip_fw_defines.h
new file mode 100755
index 000000000000..ed825ce6e7f8
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/Incl/mediaip_fw_defines.h
@@ -0,0 +1,249 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+
+ Filename: mediaip_fw_defines.h
+ Description: Contains general definitions for
+ module based architecture
+ Author: Media IP FW team - Belfast
+
+ TODO-KMC - Should remove this file!!
+ **************************************************/
+
+#ifndef _MEDIAIP_FW_DEFINES_H_
+#define _MEDIAIP_FW_DEFINES_H_
+
+/* In use MACROS for use by types shared across modules */
+/* When adding new modules, endeavour to maintain the same 'position' as that suggested by the */
+/* module's position in the MEDIAIP_FW_HANDLE_TYPE enumeration - see Modules/Public/handle.h */
+
+#define IN_USE_DECODER ( 1 << 0x0 )
+#define IN_USE_ENCODER ( 1 << 0x1 )
+#define IN_USE_IMG_PORT ( 1 << 0x2 )
+#define IN_USE_DISPLAY ( 1 << 0x3 )
+#define IN_USE_VAMUX ( 1 << 0x4 )
+#define IN_USE_VIPP ( 1 << 0x5 )
+#define IN_USE_SYS_API ( 1 << 0x10 )
+
+/////////////////////////////////////////////////
+// Frame Store Display Data make-up
+
+// Read
+#define FRAME_STORE_DISP_DATA_FSID(r) ((r>>0)&0x3f)
+#define FRAME_STORE_DISP_DATA_RPT_FIRST_FLD(r) ((r>>15)&0x1) // IDJ: Pass RFF (borrow a bit from unused base addr field)
+#define FRAME_STORE_DISP_DATA_SPS_IDC_BITS(r) ((r>>16)&0x7)
+#define FRAME_STORE_DISP_DATA_DANG_FIELD_BIT(r) ((r>>19)&0x1)
+#define FRAME_STORE_DISP_DATA_FIELD_MODE_BIT(r) ((r>>20)&0x1)
+#define FRAME_STORE_DISP_DATA_BOT_FIRST_BIT(r) ((r>>21)&0x1)
+#define FRAME_STORE_DISP_DATA_SKIP_PIC_BITS(r) ((r>>22)&0x3)
+#define FRAME_STORE_DISP_DATA_SYS_DATA_BITS(r) ((r>>24)&0xFF)
+#define FRAME_STORE_DISP_DATA_FRAME_BADDR(r) ((r>>0)&0x7FFF)
+#define FRAME_STORE_DATAFIELDS(a) (a&0xffff8000) // IDJ - bit 15 used above
+
+// Write
+#define FRAME_STORE_DISP_DATA_PUT_FSID(a) ((a&0x3f) << 0)
+#define FRAME_STORE_DISP_DATA_PUT_FRAME_BADDR(a) ((a&0x7fff) << 0)
+#define FRAME_STORE_DISP_DATA_PUT_DUPLC_FRAME_SENT(a) ((a&0x1) << 14) // RayC/JKD: but used to control when duplicate frames are sent
+#define FRAME_STORE_DISP_DATA_PUT_DUPLC_FRAME_SENT_GET(a) ((a>>14)&0x1)
+#define FRAME_STORE_DISP_DATA_PUT_RPT_FIRST_FIELD(a) ((a&0x1) << 15) // IDJ Borrow a bit from BADDR field (not used)
+#define FRAME_STORE_DISP_DATA_PUT_DISP_PARAM_ID(a) ((a&0x7) << 16)
+#define FRAME_STORE_DISP_DATA_PUT_DANGLING_FIELD(a) ((a&0x1) << 19)
+#define FRAME_STORE_DISP_DATA_PUT_FIELD_MODE(a) ((a&0x1) << 20)
+#define FRAME_STORE_DISP_DATA_PUT_BOT_FIELD_FIRST(a) ((a&0x1) << 21)
+#define FRAME_STORE_DISP_DATA_PUT_TOP_SKIPPED(a) ((a&0x1) << 22)
+#define FRAME_STORE_DISP_DATA_PUT_BOT_SKIPPED(a) ((a&0x1) << 23)
+#define FRAME_STORE_DISP_DATA_PUT_SYS_DATA(a) ((a&0xff) << 24)
+
+#define NUM_DISP_PUSHES_MASK 0xFF00
+#define NUM_DISP_PUSHES_POS 8
+#define NUM_DISP_PUSHES_SET(x) (x<<NUM_DISP_PUSHES_POS)
+#define NUM_DISP_PUSHES_GET(x) ( (x&NUM_DISP_PUSHES_MASK) >> NUM_DISP_PUSHES_POS)
+
+/////////////////////////////////////////////////
+// Display Params
+
+#define DISP_INFO_USER_DATA_ATTACHED_MASK 0x1
+#define DISP_INFO_USER_DATA_ATTACHED_POS 0
+#define DISP_INFO_GET_USER_DATA_ATTACHED(x) ((x&DISP_INFO_USER_DATA_ATTACHED_MASK)>>DISP_INFO_USER_DATA_ATTACHED_POS)
+#define DISP_INFO_USER_DATA_MASK 0xFFFF
+#define DISP_INFO_USER_DATA_POS 16
+#define DISP_INFO_GET_USER_DATA(x) ((x>>DISP_INFO_USER_DATA_POS)&DISP_INFO_USER_DATA_MASK)
+
+// uScanFormat defines
+
+#define DISP_SCAN_FORMAT_INTERLACED 0x0
+#define DISP_SCAN_FORMAT_PROGRESSIVE 0x1
+#define DISP_SCAN_FORMAT_VALID_GET(r) (r&0x1)
+#define DISP_SCAN_FORMAT_GET(r) ((r&0x2)>>1)
+#define DISP_SCAN_FORMAT_VALID_SET(r) ((r&0x1)<<0)
+#define DISP_SCAN_FORMAT_SET(r) ((r&0x1)<<1)
+
+/////////////////////////////////////////////////
+// General defines - base on Stream descriptor for Pecos
+
+#define STOP_IMMEDIATE 0x0
+#define STOP_COMPLETE_DISPLAY 0x1
+
+#define FORMAT_VC1 0x2
+#define FORMAT_MPEG2 0x1
+#define FORMAT_MPEG4 0x0
+#define FORMAT_MPEG2_DBEN 0x1
+#define FORMAT_MPEG2_DBDRNGEN 0x2
+
+#define STREAM_MODE_ES 0x1
+#define STREAM_MODE_PES 0x0
+
+#define DELIVERY_MODE_TSP_DIRECT 0x0
+#define DELIVERY_MODE_BSP 0x1
+#define DELIVERY_MODE_BSDMA 0x2
+
+// Buffer Indices
+#define SD_BUFIND_ESBUF_MASK 0xFF
+#define SD_BUFIND_ESBUF_SHIFT 0
+#define SD_BUFIND_STC_MASK 0x30000
+#define SD_BUFIND_STC_SHIFT 16
+#define SD_BUFIND_ESBUF_GET(x) ((x&SD_BUFIND_ESBUF_MASK)>>SD_BUFIND_ESBUF_SHIFT)
+#define SD_BUFIND_STC_GET(x) ((x&SD_BUFIND_STC_MASK)>>SD_BUFIND_STC_SHIFT)
+
+#define UD_ORDER_DECODE 0x1
+#define UD_ORDER_DISPLAY 0x2
+#define UD_ORDER_DECODEANDDISPLAY 0x3
+
+#define PRINT_UART4(a,b,c,d)
+#define PRINT_UART5(a,b,c,d,e)
+
+#define DISPLAY_ASPECT_RATIO_4_3 0x2
+#define DISPLAY_ASPECT_RATIO_16_9 0x3
+
+
+/////////////////////////////////////////////////
+// PTS capture descriptor flags
+#define PTS_DESCRIPTOR_PTS_LO 0x00000000
+#define PTS_DESCRIPTOR_DTS_LO 0x00000004
+#define PTS_DESCRIPTOR_FLAGS 0x00000008
+#define PTS_DESCRIPTOR_WRAP_COUNT 0x00000009
+#define PTS_DESCRIPTOR_TIMEBASE_ID 0x0000000A
+#define PTS_DESCRIPTOR_MATURITY_ADDRESS 0x0000000C
+
+#define PTS_DESCRIPTOR_FLAG_PTS_HI_MASK 0x00000001
+#define PTS_DESCRIPTOR_FLAG_PTS_HI_BIT 0
+#define PTS_DESCRIPTOR_FLAG_DTS_HI_MASK 0x00000002
+#define PTS_DESCRIPTOR_FLAG_DTS_HI_BIT 1
+#define PTS_DESCRIPTOR_FLAG_STC_PARITY_MASK 0x00000004
+#define PTS_DESCRIPTOR_FLAG_STC_PARITY_BIT 2
+#define PTS_DESCRIPTOR_FLAG_PENDING_MASK 0x00000008
+#define PTS_DESCRIPTOR_FLAG_PENDING_BIT 3
+#define PTS_DESCRIPTOR_FLAG_PESERROR_MASK 0x00000010
+#define PTS_DESCRIPTOR_FLAG_PESERROR_BIT 4
+
+#define PTS_DESCRIPTOR_FLAG_ADDRESS_WRAP_COUNT_BIT 8
+#define PTS_DESCRIPTOR_FLAG_ADDRESS_WRAP_COUNT_MASK 0x0000FF00
+#define PTS_DESCRIPTOR_FLAG_TIMEBASE_ID_BIT 16
+#define PTS_DESCRIPTOR_FLAG_TIMEBASE_ID_MASK 0x000F0000
+#define PTS_DESCRIPTOR_FLAG_AVC_TAG_BIT 24
+#define PTS_DESCRIPTOR_FLAG_AVC_TAG_MASK 0xFF000000
+
+// PTS debug descriptor extensions
+#define PTS_DESCRIPTOR_DEBUG 0x00000010
+#define PTS_DESCRIPTOR_DEBUG_PTS_DTS 0x00000010
+#define PTS_DESCRIPTOR_DEBUG_STC_SNAPSHOT 0x00000014
+#define PTS_DESCRIPTOR_DEBUG_DIFFERENCE 0x00000018
+#define PTS_DESCRIPTOR_DEBUG_FLAGS 0x0000001C
+
+#define PTS_DESCRIPTOR_DEBUG_FLAG_NO_PTS 0x00000001
+#define PTS_DESCRIPTOR_DEBUG_FLAG_NO_STC 0x00000002
+#define PTS_DESCRIPTOR_DEBUG_FLAG_IS_DTS 0x00000004
+#define PTS_DESCRIPTOR_DEBUG_FLAG_RUNNING 0x00000008
+#define PTS_DESCRIPTOR_DEBUG_FLAG_INSANE 0x00000010
+#define PTS_DESCRIPTOR_DEBUG_FLAG_STC_B 0x00000020
+#define PTS_DESCRIPTOR_DEBUG_FLAG_STC_CURRENT 0x00000040
+#define PTS_DESCRIPTOR_DEBUG_FLAG_TIMEBASE_MISMATCH 0x00000080
+#define PTS_DESCRIPTOR_DEBUG_FLAG_LATE 0x00000100
+#define PTS_DESCRIPTOR_DEBUG_FLAG_EARLY 0x00000200
+#define PTS_DESCRIPTOR_DEBUG_FLAG_VERY_LATE 0x00000100
+
+/////////////////////////////////////////////////
+// Tag descriptor defines
+// Flag definitions
+#define TAGLIST_SEI_PIC_STRUCT_FLAG_MASK 0x1
+#define TAGLIST_SEI_PIC_STRUCT_FLAG_SHIFT 0
+#define TAGLIST_SEI_FRAME_FREEZE_FLAG_MASK 0x2
+#define TAGLIST_SEI_FRAME_FREEZE_FLAG_SHIFT 1
+#define TAGLIST_SEI_FRAME_RELEASE_FLAG_MASK 0x4
+#define TAGLIST_SEI_FRAME_RELEASE_FLAG_SHIFT 2
+#define TAGLIST_SEI_SKIP_FLAG_MASK 0x8
+#define TAGLIST_SEI_SKIP_FLAG_SHIFT 3
+
+//////////////////////////////////////////////////////////////
+// Frame status ~ TEMP
+#define FRAME_INUSE_BYIPP 0x1
+#define FRAME_FREE 0x0
+
+//////////////////////////////////////////////////////////////
+// Scan format ~ TEMP
+#define SCAN_FORMAT_INTERLACED 0x0
+#define SCAN_FORMAT_PROGRESSIVE 0x1
+#define SCAN_FORMAT_VALID_GET(r) (r&0x1)
+#define SCAN_FORMAT_GET(r) ((r&0x2)>>1)
+#define SCAN_FORMAT_VALID_SET(r) ((r&0x1)<<0)
+#define SCAN_FORMAT_SET(r) ((r&0x1)<<1)
+
+//////////////////////////////////////////////////////////////
+// Internal System Control Defines
+
+#define NO_INTERNAL_CONTROL 0xFF
+#define SFD_INTERNAL_CONTROL 0x1
+#define AUTORECOVER_INTERNAL_CONTROL 0x2
+
+//////////////////////////////////////////////////////////////
+// SVC specific defines
+#define MEDIAIP_MAX_SVC_DID 0x3
+#define MEDIAIP_MAX_SVC_STR_BUFFERS 0x3
+
+//////////////////////////////////////////////////////////////
+// Malone specific defines
+#define MEDIAIP_MAX_NUM_MALONES 0x2
+#define MEDIAIP_MAX_NUM_MALONE_IRQ_PINS 0x2
+
+#define MEDIAIP_MAX_NUM_FSLCACHES 0x4
+
+//////////////////////////////////////////////////////////////
+// Windsor specific defines
+#define MEDIAIP_MAX_NUM_WINDSORS 0x1
+#define MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS 0x2
+
+//////////////////////////////////////////////////////////////
+// Subsystem specific defines
+#define MEDIAIP_MAX_NUM_IRQ_PINS 0x10
+#define MEDIAIP_MAX_NUM_CMD_IRQ_PINS 0x2
+#define MEDIAIP_MAX_NUM_MSG_IRQ_PINS 0x1
+#define MEDIAIP_MAX_NUM_TIMER_IRQ_PINS 0x4
+#define MEDIAIP_MAX_NUM_TIMER_IRQ_SLOTS 0x4
+
+#define SUBSYSTEM_CFG_MAGIC_COOKIE 0xB0B1B2B3
+
+//////////////////////////////////////////////////////////////
+// Max supported picture resolution, except H.264 and JPEG
+
+#define MEDIAIP_MAX_PIC_WIDTH 2048
+#define MEDIAIP_MAX_PIC_HEIGHT 2048
+
+//////////////////////////////////////////////////////////////
+// Encoder user data programming vals
+
+#define MEDIAIP_ENC_USER_DATA_WORDS 16
+#define MEDIAIP_ENC_USER_DATA_BYTES ( MEDIAIP_ENC_USER_DATA_WORDS << 2 )
+
+
+
+#endif /* _MEDIAIP_FW_DEFINES_H_ */
+
+/* End of File */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/Incl/mediaip_fw_types.h b/drivers/mxc/vpu-malone/Malone_Firmware/Incl/mediaip_fw_types.h
new file mode 100755
index 000000000000..98ff57773a27
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/Incl/mediaip_fw_types.h
@@ -0,0 +1,1991 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+
+ Filename: mediaip_fw_types.h
+ Description: Contains structure definitions common
+ to multiple modules / layers
+ Author: Media IP FW team - Belfast / Shanghai
+
+ ****************************************************/
+
+#ifndef _MEDIAIP_FW_TYPES_H_
+#define _MEDIAIP_FW_TYPES_H_
+
+#include "basetype.h"
+#include "mediaip_fw_defines.h"
+
+//////////////////////////////////////////////////////////////
+// Generic Stream format
+
+typedef enum
+{
+ MEDIA_IP_FMT_NULL = 0x0,
+ MEDIA_IP_FMT_AVC = 0x1,
+ MEDIA_IP_FMT_VC1 = 0x2,
+ MEDIA_IP_FMT_MP2 = 0x3,
+ MEDIA_IP_FMT_AVS = 0x4,
+ MEDIA_IP_FMT_ASP = 0x5,
+ MEDIA_IP_FMT_JPG = 0x6,
+ MEDIA_IP_FMT_RV = 0x7,
+ MEDIA_IP_FMT_VP6 = 0x8,
+ MEDIA_IP_FMT_SPK = 0x9,
+ MEDIA_IP_FMT_VP8 = 0xA,
+ MEDIA_IP_FMT_MVC = 0xB,
+ MEDIA_IP_FMT_VP3 = 0xC,
+ MEDIA_IP_FMT_HEVC = 0xD,
+ MEDIA_IP_FMT_AUTO_DETECT = 0xAD00,
+ MEDIA_IP_FMT_ALL = (int)0xAAAAAAAA,
+ MEDIA_IP_FMT_UNSUPPORTED = (int)0xFFFFFFFF,
+ MEDIA_IP_FMT_LAST = MEDIA_IP_FMT_UNSUPPORTED
+
+} MEDIA_IP_FORMAT;
+
+//////////////////////////////////////////////////////////////
+// Generic picture Structure
+
+typedef enum
+{
+ MEDIAIP_TOP_FIELD,
+ MEDIAIP_BOT_FIELD,
+ MEDIAIP_TWO_FIELDS,
+ MEDIAIP_FRAME_PICTURE
+
+} MEDIAIP_PIC_STRUCT;
+
+//////////////////////////////////////////////////////////////
+// Generic picture type
+
+typedef enum
+{
+ MEDIAIP_I_PICTYPE = 1,
+ MEDIAIP_P_PICTYPE,
+ MEDIAIP_B_PICTYPE,
+ MEDIAIP_UNDEF_PICTYPE
+
+} MEDIAIP_PIC_TYPE;
+
+//////////////////////////////////////////////////////////////
+// Stream Layer
+
+typedef enum
+{
+ MEDIAIP_BASE_LAYER = 0,
+ MEDIAIP_ENHANCEMENT_LAYER
+
+} MEDIAIP_LAYER;
+
+//////////////////////////////////////////////////////////////
+// Display module - sync state
+
+typedef enum
+{
+ DISP_SYNC_UNINITIALISED = 0,
+ DISP_SYNC_ACQUIRING,
+ DISP_SYNC_ACQUIRED,
+ DISP_SYNC_LOST,
+ DISP_SYNC_LOST_INVALID,
+ DISP_SYNC_LOST_INSANE
+
+} MEDIAIP_DISP_SYNC_STATE;
+
+//////////////////////////////////////////////////////////////
+// PES HW state
+
+typedef enum
+{
+ PES_STATE_NORMAL = 0,
+ PES_STATE_PTS_BACKTOBACK,
+ PES_STATE_PTS_WITH_SLICE,
+ PES_STATE_PTS_WITH_PIC
+
+} MEDIAIP_PES_STATE;
+
+//////////////////////////////////////////////////////////////
+// Playback mode
+
+typedef enum
+{
+ MEDIAIP_PLAYMODE_CONNECTIVITY = 0,
+ MEDIAIP_PLAYMODE_BROADCAST,
+ MEDIAIP_PLAYMODE_BROADCAST_DSS,
+ MEDIAIP_PLAYMODE_LAST = MEDIAIP_PLAYMODE_BROADCAST_DSS
+
+} MEDIA_IP_PLAYMODE;
+
+//////////////////////////////////////////////////////////////
+// System mode
+
+typedef enum
+{
+ MEDIAIP_SYSMODE_DTV = 0,
+ MEDIAIP_SYSMODE_STB,
+ MEDIAIP_SYSMODE_LAST = MEDIAIP_SYSMODE_STB
+
+} MEDIA_IP_SYSMODE;
+
+//////////////////////////////////////////////////////////////
+// Encoder Output Info
+typedef struct
+{
+ u_int32 uStrIndex;
+ BOOL bLastFrame;
+ BOOL bEndOfGOP;
+ u_int32 uEsStruct;
+ u_int32 uMsbPTS;
+ u_int32 uPTS;
+ u_int32 uVesSize;
+ u_int32 uCbFrmStartAddr;
+
+} MEDIAIP_ENCODER_OUTPUT_INFO;
+
+//////////////////////////////////////////////////////////////
+// YUV Output Info
+
+#ifndef HOST_BUILD
+#ifndef _MSC_VER
+typedef enum
+{
+ YUV420 = 0x0,
+ YUV422,
+ YUV400
+
+} MEDIAIP_FW_FRAME_FMT;
+#endif // _MSC_VER
+#endif
+
+//////////////////////////////////////////////////////////////
+// Frame Display info
+
+typedef struct
+{
+ u_int32 top_field_first;
+ u_int32 repeat_first_field;
+ u_int32 disp_vert_res;
+ u_int32 disp_horiz_res;
+ u_int32 centre_vert_offset;
+ u_int32 centre_horiz_offset;
+
+} MEDIAIP_PIC_DISP_INFO;
+
+//////////////////////////////////////////////////////////////
+// Frame info
+
+typedef struct
+{
+ MEDIAIP_PIC_TYPE pic_type;
+ u_int32 pic_struct;
+ u_int32 pic_st_addr;
+ u_int32 last_pic_npf;
+ u_int32 user_data_avail;
+ u_int32 frame_store_id;
+ u_int32 uPercentInErr;
+ u_int32 view_id; /* H264 MVC */
+ u_int32 uVOIdx; /* H264 MVC */
+#if MVC_SUPPORT == MVC_ENABLED
+ u_int32 uViewId;
+#endif
+ u_int32 uSkipInProg;
+
+} MEDIAIP_PIC_INFO;
+
+//////////////////////////////////////////////////////////////
+// Memory request type enum
+
+typedef enum
+{
+ MEDIAIP_FRAME_REQ = 0,
+ MEDIAIP_MBI_REQ,
+ MEDIAIP_DCP_REQ,
+ MEDIAIP_REQ_LAST = MEDIAIP_DCP_REQ
+
+} MEDIAIP_MEM_REQ;
+
+//////////////////////////////////////////////////////////////
+// Memory request ctrl
+
+typedef struct
+{
+ u_int32 uLayerIdx;
+ MEDIAIP_MEM_REQ eType;
+
+} MEDIAIP_MEM_REQ_CTRL, *pMEDIAIP_MEM_REQ_CTRL;
+
+//////////////////////////////////////////////////////////////
+// Memory release ctrl
+
+typedef struct
+{
+ u_int32 uLayerIdx;
+ u_int32 uFSIdx;
+ MEDIAIP_MEM_REQ eType;
+
+} MEDIAIP_MEM_REL_CTRL, *pMEDIAIP_MEM_REL_CTRL;
+
+////////////////////////////////////////////////////////
+// Media IP mem alloc struct
+
+typedef struct
+{
+ MEDIAIP_MEM_REQ eType;
+ u_int32 uLayerIdx;
+
+ u_int32 uFSHandle;
+ u_int32 uBaseAddr;
+ u_int32 uStride;
+ u_int32 uChromaOffset;
+
+} MEDIAIP_MEM_ALLOC_CTRL, *pMEDIAIP_MEM_ALLOC_CTRL;
+
+//////////////////////////////////////////////////////////////
+// Decoder metrics info
+
+typedef struct
+{
+ u_int32 uDpbmcCrc;
+ u_int32 uFrameActiveCount;
+ u_int32 uSliceActiveCount;
+ u_int32 uRbspBytesCount;
+ u_int32 uSibWaitCount;
+ u_int32 uDpbReadCount;
+ u_int32 uMprWaitCount;
+ u_int32 uBBBCrc;
+ u_int32 uAccQP;
+ u_int32 uCacheStat;
+ u_int32 uCRCSkip;
+ u_int32 uCRCDrop;
+ BOOL bCRCValid;
+
+ u_int32 uBaseDpbMcCrc;
+ u_int32 uByteStreamCrc;
+
+ u_int32 uCRC0;
+ u_int32 uCRC1;
+ u_int32 uCRC2;
+ u_int32 uCRC3;
+ u_int32 uCRC4;
+ u_int32 uCRC5;
+ u_int32 uCRC6;
+ u_int32 uCRC7;
+ u_int32 uCRC8;
+ u_int32 uCRC9;
+ u_int32 uCRC10;
+ u_int32 uCRC11;
+ u_int32 uCRC12;
+ u_int32 uCRC13;
+ u_int32 uCRC14;
+
+ u_int32 mbq_full;
+ u_int32 mbq_empty;
+ u_int32 slice_cnt;
+ u_int32 mb_count;
+
+ u_int32 uTotalTime_us;
+ u_int32 uTotalFwTime_us;
+
+ u_int32 uSTCAtFrameDone;
+
+ u_int32 uProcIaccTotRdCnt;
+ u_int32 uProcDaccTotRdCnt;
+ u_int32 uProcDaccTotWrCnt;
+ u_int32 uProcDaccRegRdCnt;
+ u_int32 uProcDaccRegWrCnt;
+ u_int32 uProcDaccRngRdCnt;
+ u_int32 uProcDaccRngWrCnt;
+
+} MEDIAIP_DEC_METRICS_INFO, *pMEDIAIP_DEC_METRICS_INFO;
+
+//////////////////////////////////////////////////////////////
+// GOP info
+
+typedef struct
+{
+ u_int32 closed_gop;
+ u_int32 broken_link;
+
+} MEDIAIP_GOP_INFO;
+
+//////////////////////////////////////////////////////////////
+// Stream frequency
+
+typedef enum
+{
+ MEDIAIP_FR_UNKNOWN = 0,
+ MEDIAIP_FR_23_97_HZ = 1,
+ MEDIAIP_FR_24_HZ = 2,
+ MEDIAIP_FR_25_HZ = 3,
+ MEDIAIP_FR_29_97_HZ = 4,
+ MEDIAIP_FR_30_HZ = 5,
+ MEDIAIP_FR_50_HZ = 6,
+ MEDIAIP_FR_59_94_HZ = 7,
+ MEDIAIP_FR_60_HZ = 8,
+ MEDIAIP_FR_7P992_HZ = 9,
+ MEDIAIP_FR_8_HZ = 10,
+ MEDIAIP_FR_8P33_HZ = 11,
+ MEDIAIP_FR_9P99_HZ = 12,
+ MEDIAIP_FR_10_HZ = 13,
+ MEDIAIP_FR_11P988_HZ= 14,
+ MEDIAIP_FR_12_HZ = 15,
+ MEDIAIP_FR_12P5_HZ = 16,
+ MEDIAIP_FR_14P985_HZ= 17,
+ MEDIAIP_FR_15_HZ = 18
+
+} MEDIAIP_OUTPUT_FREQ;
+
+//////////////////////////////////////////////////////////////
+// Scan info
+
+typedef enum
+{
+ MEDIAIP_PROGRESSIVE,
+ MEDIAIP_INTERLACE
+
+} MEDIAIP_SCAN_INFO;
+
+//////////////////////////////////////////////////////////////
+// Pipeline type enumeration
+
+typedef enum
+{
+ MEDIAIP_VIDEO_DECODE_PIPELINE = 0x0,
+ MEDIAIP_VIDEO_ENCODE_PIPELINE,
+ MEDIAIP_VIDEO_TRANSCODE_PIPELINE,
+ MEDIAIP_VIDEO_TRANSDISP_PIPELINE,
+ MEDIAIP_VIDEO_NULL_PIPELINE
+
+} MEDIAIP_VIDEO_PIPELINE_TYPE;
+
+//////////////////////////////////////////////////////////////
+// Decode info
+
+/* TODO-KMC */
+/* Why do these structures break the protocol in case used for naming ? */
+
+typedef enum
+{
+ MediaIPFW_DEC_CodingTypeI = 1,
+ MediaIPFW_DEC_CodingTypeP,
+ MediaIPFW_DEC_CodingTypeAny,
+ MediaIPFW_DEC_CodingTypeIP,
+ MediaIPFW_DEC_CodingTypeSkip,
+ MediaIPFW_DEC_CodingTypeLast
+
+} MediaIPFW_DEC_CodingType;
+
+//////////////////////////////////////////////////////////////
+// Decode Command Mode
+
+typedef enum
+{
+ MediaIPFW_DEC_ModeSplit = 0,
+ MediaIPFW_DEC_ModeNoSplit
+
+} MediaIPFW_DEC_Mode;
+
+//////////////////////////////////////////////////////////////
+// Tag structures
+
+typedef enum
+{
+ TAG_FREE = 0,
+ TAG_IN_USE
+
+} TAG_STATUS;
+
+typedef struct
+{
+
+ u_int32 pts; // TSP aspect of the structure
+ u_int32 dts;
+ u_int32 pts_flags;
+#ifdef PES_INPUT_ENABLE
+#else
+ u_int32 maturity_address;
+#endif
+ u_int32 scode_loc; // Possibly this variable could be combined with maturity_address
+ // They are the same thing, but come from very different places
+ BOOL bValid;
+
+} DEMUX_INFO, *pDEMUX_INFO;
+
+// This struct is AVC specific - needs to be generic or at least cast as generic
+typedef struct
+{
+
+ u_int32 sei_flags; // Display aspect
+ u_int32 sei_pic_struct;
+
+} DISP_INFO, *pDISP_INFO;
+
+typedef struct
+{
+ u_int32 fs_idc;
+ u_int32 uUseFrameCRC;
+ u_int32 uBotFirst;
+ u_int32 uTopData[2];
+ u_int32 uBotData[2];
+ u_int32 uReported;
+
+ u_int32 uDpbmcCRC; // Internal MC interface CRC
+ u_int32 uBsCRC; // Byte Stream CRC
+
+ u_int32 uDPBLevel; // DPB Level at frame start
+
+ u_int16 fs_is_used;
+ u_int16 Monochrome;
+
+ u_int32 control;
+
+} CRC_INFO, *pCRC_INFO;
+
+typedef struct
+{
+ u_int32 frame_size_inmbs; // {Size[15:0],Height[7:0],Width[7:0]}
+ u_int32 bs_ib_empty;
+ u_int32 frm_dec_active;
+ u_int32 slc_dec_active;
+ u_int32 stc_at_decode;
+ u_int32 stc_at_display;
+ u_int32 num_slc_overlapped;
+ u_int32 num_mb_overlapped;
+ u_int32 luma_address;
+ u_int32 cpb_min_level;
+ u_int32 rbsp_byte_count;
+ u_int32 dpb_read_count;
+ u_int32 mpr_wait_count;
+ u_int32 slice_count;
+ u_int16 drm_pull_count;
+ u_int16 drm_pap_pts_cnt;
+ u_int16 drm_pap_skip_cnt;
+ u_int16 drm_pap_dang_cnt;
+
+} PERF_INFO, *pPERF_INFO;
+
+typedef struct
+{
+ u_int32 uNumSlices;
+ u_int32 uSumQP;
+
+}QMETER_INFO, *pQMETER_INFO;
+
+typedef struct
+{
+
+ DEMUX_INFO TspInfo;
+ DISP_INFO DispInfo;
+ CRC_INFO CRCInfo;
+ TAG_STATUS Status; // General info on the structure - free or taken...
+ QMETER_INFO QMeterInfo;
+ u_int32 uPercentMBInErr;
+#ifdef PERF_DEBUG
+ PERF_INFO PerfInfo;
+#endif
+
+} TAG, *pTAG;
+
+typedef struct
+{
+
+ u_int32 uLastTSP;
+ u_int32 uLastNonTSP;
+ u_int32 uInUse;
+
+} TAG_CTRL, *pTAG_CTRL;
+
+
+// Film Grain technology support
+typedef struct
+{
+ BOOL bFGS_Flag;
+ u_int32 log2_scale_factor;
+ u_int32 pic_order_count;
+ u_int32 pic_order_offset;
+ u_int16 fgs_lut[3][256];
+
+}USERDATA_FILMGRAIN_CONTROL;
+
+#define DIAG_ARRAY_SIZE 26
+
+typedef struct
+{
+
+ int32 nAvcDiagState;
+ int32 nTSPDiagState;
+ u_int32 uFailurePt;
+ u_int32 uFailData[4];
+ int32 nLastCall;
+ int32 nDecodeBegan;
+ int32 nEngStart;
+ u_int32 uLastStart;
+ int32 DPBCount;
+ int32 DPBAnomaly;
+ int32 DPBAnomalyCnt;
+ int32 nEntryIndex;
+ int32 nEntryArray[DIAG_ARRAY_SIZE];
+ int32 nExitIndex;
+ int32 nExitArray[DIAG_ARRAY_SIZE];
+
+} DiagInfo, *pDiagInfo;
+
+
+////////////////////////////////////////////////////////
+// Frame store structure -
+// Common to multiple modules will hold all information
+// which needs to be transferred between any two modules
+// in relation to a picture buffer
+
+typedef struct mediaip_fw_frame_store
+{
+ struct mediaip_fw_frame_store * pNext; // Not entirely sure I need this - we will see as the architecture evolves...
+
+ /* Frame store description */
+ u_int32 uBaseAddr; // Base Address - Luma base for a image store, address for MBI or BLI
+ u_int32 uChromaOffset;
+ u_int32 uPitch;
+ u_int32 uDimsMBs;
+
+ // Module usage
+ u_int32 uModUsage; // 1 bit set for each module that considers this frame store to be in use by it
+ // For a real time display / transcode situation this could be more than 2
+
+ // Last Frame flag
+ BOOL bLastFrame; // Flag to indicate whether this is the last frame store decoded by the decoder.
+ // Important when stopping a transcode pipeline or reaching the last frame of a bitstream
+ // so that we can tell the encoder not to expect any more frames and hence empty it's
+ // pipeline.
+
+ // Display params
+ u_int32 uDispData; // Bottom field first etc - normally to be filled in by decode module
+
+ // Frame store
+ u_int32 uFSID; // An ID used to cross reference with a local structure - filled in by the capture unit, decoder or
+ // image capture unit, etc
+
+ pTAG pFSTag; // A pointer to a tag for the frame store - normally allocated by the decoder so that unit should
+ // set the pointer
+
+ USERDATA_FILMGRAIN_CONTROL ud_filmgrain; // Filmgrain support structure
+
+ // Want to give anything that may be managed by the resource layer a generic resource tag!
+ // Until I can be bothered working out how to do this I will go with the 3 below...
+
+ u_int8 uDynBuffType; // What is the buffer type of the currently allocayted frame store
+ // Could be worked out from uFSInternBufNum - Remember if we have to
+ // hold a frames over a channel change not all uDynBuffType members
+ // will be the same in each stream's group of frame stores
+
+ u_int8 uFSInternBufStart;
+ u_int8 uFSInternBufNum;
+
+} MEDIAIP_FW_FRAME_STORE;
+
+typedef MEDIAIP_FW_FRAME_STORE MEDIAIP_FW_ENCODER_REF_FRAME_STORE;
+typedef MEDIAIP_FW_FRAME_STORE MEDIAIP_FW_ENCODER_FRAME_ACT_STORE;
+
+
+////////////////////////////////////////////////////////
+// MetaData store structure -
+// Defines an area which may be passed to a base module for its own internal use
+
+typedef struct
+{
+ u_int32 uMetadataBase;
+ u_int32 uMetadataSize;
+
+} MEDIAIP_FW_METADATA_STORE, *pMEDIAIP_FW_METADATA_STORE;
+
+////////////////////////////////////////////////////////
+// Stream Frequency enumeration -
+
+
+typedef enum {
+
+ STREAM_FR_UNKNOWN = 0,
+ STREAM_FR_23_97_HZ = 1,
+ STREAM_FR_24_HZ = 2,
+ STREAM_FR_25_HZ = 3,
+ STREAM_FR_29_97_HZ = 4,
+ STREAM_FR_30_HZ = 5,
+ STREAM_FR_50_HZ = 6,
+ STREAM_FR_59_94_HZ = 7,
+ STREAM_FR_60_HZ = 8
+
+ } STREAM_SCAN_FREQ;
+
+////////////////////////////////////////////////////////
+// Digital Encode Mode ( at the tv encoder)
+
+typedef enum {
+ MODE_240p = 0x0,
+ MODE_240i = 0x1,
+ MODE_480p = 0x2,
+ MODE_NTSC = 0x3,
+ MODE_PALp = 0x4,
+ MODE_PAL = 0x5,
+ MODE_720p = 0x6,
+ MODE_720p_50Hz = 0x7,
+ MODE_720i = 0x8,
+ MODE_720i_25Hz = 0x9,
+ MODE_720i_50Hz = 0xa,
+ MODE_720i_60Hz = 0xb,
+ MODE_1080p = 0xc,
+ MODE_1080p_25Hz = 0xd,
+ MODE_1080i = 0xe,
+ MODE_1080i_25Hz = 0xf,
+ MODE_2Kp = 0x10,
+ MODE_1080p_24Hz = 0x11,
+ MODE_UNKNOWN = 0xff
+
+ } TV_ENC_MODE;
+
+////////////////////////////////////////////////////////
+// Stream Display parameters
+
+typedef struct
+{
+ u_int32 uTargetLevel;
+ u_int32 uHorDecodeRes;
+ u_int32 uVerDecodeRes;
+ u_int32 uHorDispRes;
+ u_int32 uVerDispRes;
+ u_int32 uDispWidthMBs;
+ u_int32 uDispHeightMBs;
+ u_int32 uBufWidthMBs;
+ u_int32 uBufHeightMBs;
+ u_int32 uAspectRatio;
+ u_int32 uSizeMBs;
+ u_int32 uYUVFmt;
+ u_int32 uScanFormat;
+ STREAM_SCAN_FREQ sFreq;
+ u_int32 uNumRefFrms;
+ u_int32 uNumDPBFrms;
+ u_int32 uNumDFEAreas;
+ u_int32 uProfLevelIDC;
+ MEDIAIP_OUTPUT_FREQ eOutputFreq;
+ MEDIAIP_SCAN_INFO eScanInfo;
+ u_int32 uAR;
+ u_int32 uColorDesc;
+ u_int32 uBitDepthLuma;
+ u_int32 uBitDepthChroma;
+ u_int32 uNumViews;
+ u_int32 uViewList;
+
+} MEDIAIP_FW_STREAM_DISPLAY_PARAMS;
+
+
+////////////////////////////////////////////////////////
+// Frame decoded parameters
+
+typedef struct
+{
+ BOOL bTopFieldFirst;
+ BOOL bRepeatFirstField;
+ MEDIAIP_PIC_TYPE ePicType;
+ MEDIAIP_PIC_STRUCT ePicStruct;
+
+ u_int32 uFSHandle;
+
+ u_int32 uPicStartAddr;
+ u_int32 uPercentMBsInErr;
+
+ u_int32 uPTSLo;
+ u_int32 uPTSHi;
+ BOOL bPTSValid;
+
+ BOOL bQMeterValid;
+ u_int32 uQMeter;
+ BOOL bGopBitRateAvail;
+ u_int32 uGopBitRate;
+
+ u_int32 bTemporalRef;
+
+ u_int32 uBbdHorActive;
+ u_int32 uBbdVerActive;
+ u_int32 uBbdLogoActive;
+ u_int32 uBbdBotPrev;
+ u_int32 uBbdMinColPrj;
+ u_int32 uBbdMinRowPrj;
+
+ u_int32 uFSBaseAddr;
+ BOOL bDangling;
+ BOOL bTopFieldPresent;
+
+ /* Only for RealVideo RPR */
+ u_int32 uRprPicWidth;
+ u_int32 uRprPicHeight;
+
+ /* Only for DivX3 */
+ u_int32 uFrameRate;
+
+ /* For decode time yuv gathering */
+ u_int32 ulTopLumBaseAddr;
+ u_int32 ulTopChrBaseAddr;
+ u_int32 ulBotLumBaseAddr;
+ u_int32 ulBotChrBaseAddr;
+
+ u_int32 ulStride;
+
+ void * pAltView;
+ u_int32 uMVCTargetViewIdx;
+} MEDIAIP_FW_FRAME_DEC_PARAMS , *pMEDIAIP_FW_FRAME_DEC_PARAMS;
+
+////////////////////////////////////////////////////////
+// SVC Seq parameters
+
+typedef struct
+{
+ u_int32 uNumValidLayers;
+ MEDIAIP_FW_STREAM_DISPLAY_PARAMS tLayerParams[MEDIAIP_MAX_SVC_DID];
+
+} MEDIAIP_FW_SVC_STREAM_PARAMS;
+
+//////////////////////////////////////////////////////////////
+// IRQ Event data
+
+typedef struct
+{
+ void * pMVDHw;
+ u_int32 uIrqStatus[0x3];
+
+} MEDIAIP_FW_IRQ_DATA, *pMEDIAIP_FW_IRQ_DATA;
+
+
+//////////////////////////////////////////////////////////////
+// CMD Event data
+
+typedef struct
+{
+ u_int32 uCmdData;
+
+}MEDIAIP_FW_CMD_DATA, *pMEDIAIP_FW_CMD_DATA;
+
+//////////////////////////////////////////////////////////////
+// Callback Request Data
+
+typedef struct
+{
+ u_int32 uReason;
+
+}MEDIAIP_FW_CBACK_DATA, *pMEDIAIP_FW_CBACK_DATA;
+
+////////////////////////////////////////////////////////
+// Interface descriptor
+// Generic descriptor type as initially defined by Tempest
+// module
+
+typedef struct
+{
+
+ volatile u_int32 address;
+ volatile u_int32 parameters;
+
+} INTERFACE_DESCRIPTOR_TYPE, *pINTERFACE_DESCRIPTOR_TYPE;
+
+////////////////////////////////////////////////////////
+// Buffer descriptor
+// Generic buffer descriptor as initially defined by Tempest
+// module
+
+typedef struct
+{
+ u_int32 descriptor_number;
+ u_int32 descriptor_size;
+ u_int32 descriptor_ptr;
+
+} BUFFER_TBL_DESCRIPTOR, *BUFFER_TBL_DESCRIPTOR_PTR;
+
+////////////////////////////////////////////////////////
+// Buffer descriptor
+// Generic buffer descriptor as initially defined by Tempest
+// module
+
+typedef struct
+{
+ u_int32 wptr;
+ u_int32 rptr;
+ u_int32 start;
+ u_int32 end;
+
+} BUFFER_DESCRIPTOR_TYPE, *pBUFFER_DESCRIPTOR_TYPE;
+
+////////////////////////////////////////////////////////
+// Stream Buffer descriptor
+// Specific buffer descriptor for stream data
+
+typedef struct
+{
+ volatile u_int32 wptr;
+ volatile u_int32 rptr;
+ volatile u_int32 start;
+ volatile u_int32 end;
+ volatile u_int32 LWM;
+
+} STREAM_BUFFER_DESCRIPTOR_TYPE, *pSTREAM_BUFFER_DESCRIPTOR_TYPE;
+
+#ifdef TCODE_API_TEST
+// Defined specific for PCI ,for its access unit is 64 bits
+typedef struct
+{
+ volatile u_int32 wptr;
+ volatile u_int32 wptr_res;
+ volatile u_int32 rptr;
+ volatile u_int32 rptr_res;
+ volatile u_int32 start;
+ volatile u_int32 end;
+
+} BUF_DES_PCI_SHARE_TYPE, BUF_DES_PCI_SHARE_TYPE_PTR;
+
+#endif
+////////////////////////////////////////////////////////
+// Stream Buffer descriptor
+// Buffer descriptor as used by the encoder
+// module
+
+typedef struct
+{
+
+ u_int32 stream_index;
+ u_int32 stream_buffer_size;
+ u_int32 stream_buffer_base;
+
+} STREAM_BUFFER_DESCRIPTOR, *STREAM_BUFFER_DESCRIPTOR_PTR;
+
+typedef STREAM_BUFFER_DESCRIPTOR MEDIAIP_FW_ENCODER_STREAM_BUFFER_DESC;
+
+////////////////////////////////////////////////////////
+// PTS debug descriptor
+// This descriptor is as initially defined by Tempest
+// module
+
+typedef struct
+{
+ volatile u_int32 pts_lo;
+ volatile u_int32 stc_lo;
+ volatile int32 error;
+ volatile u_int32 flags;
+
+} PTS_DEBUG_DESCRIPTOR_TYPE, *pPTS_DEBUG_DESCRIPTOR_TYPE;
+
+////////////////////////////////////////////////////////
+// PTS descriptor
+// This descriptor is as initially defined by Tempest
+// module
+
+typedef struct
+{
+ volatile u_int32 pts_lo;
+ volatile u_int32 dts_lo;
+ volatile int32 flags;
+ volatile u_int32 maturity_addr;
+
+} PTS_DESCRIPTOR_TYPE, *pPTS_DESCRIPTOR_TYPE;
+
+//////////////////////////////////////////////////////////////
+// Video Stream Status structure
+//
+// Note : I am putting this in the communal include file because we may wish to let
+// module base FW update such a structure directly as opposed to sending messages
+// back to the public FW level...
+// We may also wish to lump all module's status into this one structure
+
+// Why are these volatiles? Should consider removing their volatility!!...
+typedef struct
+{
+ //////////////////////
+ // Pipeline variables
+ volatile u_int32 run;
+ volatile u_int32 pause;
+
+ //////////////////////
+ // Decoder variables
+ volatile u_int32 mpeg_format;
+ volatile u_int32 DSS;
+ volatile u_int32 native_sd;
+ volatile u_int32 stop;
+ volatile u_int32 stop_pending;
+ volatile u_int32 stream_terminate_type;
+ volatile u_int32 ES;
+ volatile u_int32 PAL;
+ volatile u_int32 CRC;
+ volatile u_int32 update_offset;
+ volatile u_int32 pcr_sent;
+ volatile u_int32 PVRMode;
+ volatile u_int32 malone_mp2_dbdrng_en;
+ volatile u_int32 uWaitFlush;
+
+ volatile u_int32 pvr_type; /* These are new - need to be fixed */
+ volatile u_int32 valid_frame_mask;
+
+ //////////////////////
+ // Display variables
+ volatile u_int32 force_interlace;
+ volatile u_int32 sync_stc;
+ volatile int32 nTrinityDisc;
+ volatile u_int32 uTrinityDiscPCRLo;
+ volatile u_int32 display_mode_status;
+ volatile u_int32 sync;
+
+} MEDIAIP_FW_STREAM_STATUS, *MEDIAIP_FW_STREAM_STATUS_PTR;
+
+//////////////////////////////////////////////////////////////
+// Stream Descriptor Structure
+//
+// Currently this is basically the stream descriptor structure
+// from the decoder FW interface with the host SW
+// This needs to evolve to suit our needs better
+#if ( TARGET_PLATFORM == GENTB_PLATFORM )
+
+typedef struct
+{
+ volatile u_int32 Control;
+ volatile u_int32 Buffer_Indices;
+ volatile u_int32 Message_Filter;
+ volatile u_int32 Extended_Message_Filter;
+ volatile u_int32 Tempest_Command_Filter;
+ volatile u_int32 Status;
+ volatile u_int32 Bitstream_Error;
+ volatile u_int32 Skip_Count;
+ volatile u_int32 Repeat_Count;
+ volatile u_int32 Frame_Count;
+ volatile u_int32 Bitstream_Timeout;
+ volatile u_int32 Max_Frame_Dpb_Size; // For dynamic frame allocation this actually means the start of the allocated memory
+ volatile u_int32 Decode_Buffer_Count; // For dynamic frame allocation this actually means the size of allocated memory
+ volatile u_int32 Buffer_Pitch; // For dynamic frame allocation this actually means the memory controller tile width
+ volatile INTERFACE_DESCRIPTOR_TYPE DPB_Base_Address_dec; // For dynamic frame allocation this actually means the MB info address
+ volatile u_int32 PTS_DTS_Offset;
+ volatile u_int32 Internal_PTS_Delay;
+ volatile u_int32 Sync_Window_Start;
+ volatile u_int32 Sync_Window_End;
+ volatile u_int32 Sync_Sanity_Limit;
+ volatile u_int32 trick_speed;
+ INTERFACE_DESCRIPTOR_TYPE user_data_desc;
+
+ INTERFACE_DESCRIPTOR_TYPE FrameStoreDesc;
+ INTERFACE_DESCRIPTOR_TYPE frame_buffer_control_desc;
+
+ INTERFACE_DESCRIPTOR_TYPE pvr_command_list_desc;
+ volatile u_int32 Pad[2];
+
+ pPTS_DESCRIPTOR_TYPE pts_table_desc;
+ pPTS_DEBUG_DESCRIPTOR_TYPE pts_debug_table_desc;
+
+ volatile u_int32 PVR_Control;
+ volatile u_int32 RAI;
+
+ // For PecosB onwards this is the security control word
+ volatile u_int32 security_control;
+ // Status variables for a stream
+ volatile u_int32 sd_changed_control;
+ volatile u_int32 ud_type_mask;
+ MEDIAIP_FW_STREAM_STATUS stream_status;
+
+#if TARGET_APP == VIDEO_TRANS
+ volatile u_int32 FrameStoreCount;
+ // Second set of image buffers ( only required in a dual MC situation )
+ volatile u_int32 FrameStoreCount2;
+ volatile INTERFACE_DESCRIPTOR_TYPE FrameStoreDesc2;
+
+ // Encoder Reference buffers
+ volatile u_int32 EncRefCount;
+ volatile INTERFACE_DESCRIPTOR_TYPE EncRefDesc;
+
+ // Encoder Image Activity buffers
+ volatile u_int32 EncActCount;
+ volatile INTERFACE_DESCRIPTOR_TYPE EncActDesc;
+
+ // Stream buffer descriptor index - for encoder and decoder
+ volatile u_int32 uDecStrmBufIdx; // Current decode FW expects that the buffer used will match the SDIndex
+ volatile u_int32 uEncOutBufIdx;
+
+ // Only enc, vamux interDesc used at present to pass params
+ volatile INTERFACE_DESCRIPTOR_TYPE uDecParamSet;
+ volatile INTERFACE_DESCRIPTOR_TYPE uEncParamSet;
+ volatile INTERFACE_DESCRIPTOR_TYPE uVamuxParamSet;
+
+ // Hardware Interface to system layer
+ INTERFACE_DESCRIPTOR_TYPE system_config_desc;
+
+#ifdef TCODE_API_TEST
+ volatile INTERFACE_DESCRIPTOR_TYPE uBitRateDispSet;
+#endif
+
+ volatile u_int32 streamdes_id;
+
+#else
+
+#if PLAYMODE == STB
+ volatile u_int32 streamdes_id;
+#endif
+#endif
+
+} STREAM_DESCRIPTOR, *STREAM_DESCRIPTOR_PTR;
+
+#else
+
+typedef struct
+{
+ volatile u_int32 Control; // 0
+ volatile u_int32 Buffer_Indices;
+ volatile u_int32 Message_Filter;
+ volatile u_int32 Extended_Message_Filter;
+ volatile u_int32 Tempest_Command_Filter;
+ volatile u_int32 Status;
+ volatile u_int32 Bitstream_Error;
+ volatile u_int32 Skip_Count;
+ volatile u_int32 Repeat_Count;
+ volatile u_int32 Frame_Count;
+ volatile u_int32 Bitstream_Timeout;
+ volatile u_int32 Max_Frame_Dpb_Size;
+ volatile u_int32 Buffer_Pitch;
+ volatile u_int32 Decode_Buffer_Count;
+ volatile u_int32 PTS_DTS_Offset;
+ volatile u_int32 Internal_PTS_Delay;
+ volatile u_int32 Sync_Window_Start;
+ volatile u_int32 Sync_Window_End;
+ volatile u_int32 Sync_Sanity_Limit;
+ volatile u_int32 trick_speed; // 20
+
+ // Image buffers
+ volatile u_int32 FrameStoreCount;
+ volatile INTERFACE_DESCRIPTOR_TYPE FrameStoreDesc;
+
+ // Second set of image buffers ( only required in a dual MC situation )
+ volatile u_int32 FrameStoreCount2;
+ volatile INTERFACE_DESCRIPTOR_TYPE FrameStoreDesc2;
+
+ // Encoder Reference buffers
+ volatile u_int32 EncRefCount;
+ volatile INTERFACE_DESCRIPTOR_TYPE EncRefDesc;
+
+ // Encoder Image Activity buffers
+ volatile u_int32 EncActCount; // 30
+ volatile INTERFACE_DESCRIPTOR_TYPE EncActDesc;
+
+ // Stream buffer descriptor index - for encoder and decoder
+ volatile u_int32 uDecStrmBufIdx; // Current decode FW expects that the buffer used will match the SDIndex
+ volatile u_int32 uEncOutBufIdx;
+
+ // Only enc, vamux interDesc used at present to pass params
+ volatile INTERFACE_DESCRIPTOR_TYPE uDecParamSet;
+ volatile INTERFACE_DESCRIPTOR_TYPE uEncParamSet;
+ volatile INTERFACE_DESCRIPTOR_TYPE uVamuxParamSet;
+
+ INTERFACE_DESCRIPTOR_TYPE user_data_desc;
+ INTERFACE_DESCRIPTOR_TYPE frame_buffer_attribute_desc; // Address of the attribute table used by the display process
+ // Who fills this in?? Do I give a shite in module architecture?
+ INTERFACE_DESCRIPTOR_TYPE frame_buffer_control_desc;
+ BUFFER_DESCRIPTOR_TYPE pvr_command_list_desc;
+ pPTS_DESCRIPTOR_TYPE pts_table_desc;
+ pPTS_DEBUG_DESCRIPTOR_TYPE pts_debug_table_desc;
+
+ // Hardware Interface to system layer
+ INTERFACE_DESCRIPTOR_TYPE system_config_desc;
+
+ // Status variables for a stream
+ volatile u_int32 sd_changed_control;
+ MEDIAIP_FW_STREAM_STATUS stream_status;
+
+ volatile u_int32 RAI;
+
+
+#ifdef DRM_AV_SYNC_DEBUG
+ volatile u_int32 DRMPath_Take_Snapshot; // Only used when DRM_AV_SYNC_DEBUG defined but included
+ volatile u_int32 DRMPath_Snapshot_Addr; // in all builds to enable more transparent api
+ volatile u_int32 DRMPath_Snapshot_Index; // operations
+#endif
+
+#ifdef TCODE_API_TEST
+ volatile INTERFACE_DESCRIPTOR_TYPE uBitRateDispSet;
+#endif
+
+ volatile u_int32 streamdes_id;
+
+ /* Following have been removed from official descriptor area
+ INTERFACE_DESCRIPTOR_TYPE sps_td;
+ INTERFACE_DESCRIPTOR_TYPE pps_td;
+ INTERFACE_DESCRIPTOR_TYPE spds_td;
+ */
+
+} STREAM_DESCRIPTOR, *STREAM_DESCRIPTOR_PTR;
+
+#endif
+
+#define CRC_DEBUG_NUM 1024
+#define PERF_DEBUG_NUM 2048 // 68secs
+#define CRC_FRAME 0
+#define CRC_FIELD_TOP 1
+#define CRC_FIELD_BOT 3
+
+typedef struct
+{
+
+ u_int32 abort_type;
+ u_int32 mode;
+ u_int32 link_reg;
+ u_int32 stack_pointer;
+
+}ExceptionDesc, pExceptionDesc;
+
+#ifndef VIDEO_SOFTWARE
+/* Structure below needs to be in shared memory header file for SW apps */
+typedef enum
+{
+ MVDDecoderOK = 0x0,
+ MVDDecoderServiceIrq,
+ MVDDecoderCmdPending,
+ MVDDecoderFWLoop,
+ MVDDecoderHWActive,
+ MVDDecoderHWActiveStreamStall,
+ MVDDecoderHWActiveMemStall,
+ MVDDecoderFWHWDeadlock,
+ MVDDecoderFWHWAutoRec,
+ MVDDecoderHWBSDMAIssue,
+ MVDDecoderUnknown,
+ MVDDecoderLast = MVDDecoderUnknown
+
+} MEDIAIP_FW_DECODER_STATUS;
+
+#endif
+
+typedef struct
+
+{
+
+ u_int32 size; // Size of this structure
+ u_int32 index; // Current index into array
+ u_int32 loops; // Number of times we looped
+ u_int32 num_frames; // Number of frames in a loop
+ u_int32 frame_size_inmbs; // {Size[15:0],Height[7:0],Width[7:0]}
+
+ u_int32 not_first_time;
+ u_int32 prev_vsync_count;
+ u_int32 worst_frame;
+ u_int32 loop_key; // Value used to decide when stream has looped
+ u_int32 skip_start;
+
+
+ u_int32 luma_mismatches; //
+ u_int32 chroma_mismatches; //
+ u_int32 dpbmc_mismatches; //
+ u_int32 bs_mismatches; //
+ u_int32 skip_count; //
+ u_int32 repeat_count; //
+ u_int32 loop_lu_crc; // Merge of CRCs
+ u_int32 loop_ch_crc; // Merge of CRCs
+
+ // Most recent captured Info
+ u_int32 crc_type[PERF_DEBUG_NUM];
+ u_int32 idr_pic[PERF_DEBUG_NUM];
+ u_int32 poc[PERF_DEBUG_NUM];
+ u_int32 luma_crc[PERF_DEBUG_NUM];
+ u_int32 chroma_crc[PERF_DEBUG_NUM];
+ u_int32 dpbmc_crc[PERF_DEBUG_NUM]; // Only valid for BBV & above
+ u_int32 bs_crc[PERF_DEBUG_NUM]; // Only valid for BBV & above
+
+ // Mismatches & skips
+ u_int32 luma_mismatch[PERF_DEBUG_NUM];
+ u_int32 chroma_mismatch[PERF_DEBUG_NUM];
+ u_int32 dpbmc_mismatch[PERF_DEBUG_NUM]; // Only valid for BBV & above
+ u_int32 bs_mismatch[PERF_DEBUG_NUM]; // Only valid for BBV & above
+
+ u_int32 mismatch_fs_idc[32];
+ u_int32 skip[PERF_DEBUG_NUM];
+ u_int32 repeat[PERF_DEBUG_NUM];
+
+
+ // Performance metrics & the associated CRCs for first loop
+ u_int32 crc_type_l0[PERF_DEBUG_NUM];
+ u_int32 idr_pic_l0[PERF_DEBUG_NUM];
+ u_int32 poc_l0[PERF_DEBUG_NUM];
+ u_int32 luma_crc_l0[PERF_DEBUG_NUM];
+ u_int32 chroma_crc_l0[PERF_DEBUG_NUM];
+ u_int32 dpbmc_crc_l0[PERF_DEBUG_NUM]; // Only valid for BBV & above
+ u_int32 bs_crc_l0[PERF_DEBUG_NUM]; // Only valid for BBV & above
+
+ // Max of metrics
+ u_int32 max_slc_dec_active;
+ u_int32 max_dpb_read_count;
+ u_int32 max_mpr_wait_count;
+ u_int32 max_rbsp_byte_count;
+ u_int32 max_bs_ib_empty;
+ u_int32 max_slice_count;
+ u_int32 max_mb_overlapped;
+ u_int32 min_stc_diff;
+ u_int32 max_frm_dec_active;
+ u_int32 max_frm_dec_active_2;
+ u_int32 max_frm_dec_active_4;
+ u_int32 max_frm_dec_active_8;
+
+ // Max of metrics assiciated with worst frame
+ u_int32 mfda_bs_ib_empty;
+ u_int32 mfda_mpr_wait_count;
+ u_int32 mfda_dpb_read_count;
+ u_int32 mfda_rbsp_byte_count;
+ u_int32 mfda_slice_count;
+ u_int32 mfda_slc_dec_active;
+ u_int32 mfda_mb_overlapped;
+
+ // Will effectively be averages
+ u_int32 Av_frm_dec_active;
+ u_int32 Av_slc_dec_active;
+ u_int32 Av_mpr_wait_count;
+ u_int32 Av_dpb_read_count;
+ u_int32 Av_rbsp_byte_count;
+ u_int32 Av_bs_ib_empty;
+ u_int32 Av_slice_count;
+ u_int32 Av_mb_overlapped;
+
+ u_int32 stc_diff[PERF_DEBUG_NUM];
+ u_int32 frm_dec_active[PERF_DEBUG_NUM];
+ u_int32 bs_ib_empty[PERF_DEBUG_NUM];
+ u_int32 slc_dec_active[PERF_DEBUG_NUM];
+ u_int32 num_slc_overlapped[PERF_DEBUG_NUM]; // Only valid for BBV & above
+ u_int32 num_mb_overlapped[PERF_DEBUG_NUM]; // Only valid for BBV & above
+ u_int32 cpb_min_level[PERF_DEBUG_NUM];
+ u_int32 rbsp_byte_count[PERF_DEBUG_NUM];
+ u_int32 dpb_read_count[PERF_DEBUG_NUM];
+ u_int32 mpr_wait_count[PERF_DEBUG_NUM];
+ u_int16 drm_pull_count[PERF_DEBUG_NUM];
+ u_int16 drm_pap_pts_cnt[PERF_DEBUG_NUM];
+ u_int16 drm_pap_skip_cnt[PERF_DEBUG_NUM];
+ u_int16 drm_pap_dang_cnt[PERF_DEBUG_NUM];
+
+ u_int32 initial_dpb_level[PERF_DEBUG_NUM]; // DPB level at frame start
+
+} PerfDebug;
+
+typedef struct
+
+{
+
+ u_int32 loops; // Number of times we looped
+ u_int32 loop_frames; // Number of frames in a loop
+ u_int32 num_frames; // Position in current loop
+ u_int32 loop_dpbmc_crc; // Merge of CRCs
+ u_int32 loop_stream_crc; // Merge of CRCs
+ u_int32 LoopCyCntD1024; // Sum of frm_dec_active/1024
+ u_int32 MaxDecActive; // Max frm_dec_active
+ u_int32 not_first_time;
+ u_int32 first_crc;
+ u_int32 WorstFrame;
+
+} DecDebug;
+
+
+///////////////////////////////////////////
+// System Configuration structure
+
+typedef struct
+{
+ u_int32 uCfgCookie;
+
+ u_int32 uNumMalones;
+ u_int32 uMaloneBaseAddress[MEDIAIP_MAX_NUM_MALONES];
+ u_int32 uHifOffset[MEDIAIP_MAX_NUM_MALONES];
+ u_int32 uMaloneIrqPin[MEDIAIP_MAX_NUM_MALONES][MEDIAIP_MAX_NUM_MALONE_IRQ_PINS];
+ u_int32 uMaloneIrqTarget[MEDIAIP_MAX_NUM_MALONES][MEDIAIP_MAX_NUM_MALONE_IRQ_PINS];
+
+ u_int32 uNumWindsors;
+ u_int32 uWindsorBaseAddress[MEDIAIP_MAX_NUM_WINDSORS];
+ u_int32 uWindsorIrqPin[MEDIAIP_MAX_NUM_WINDSORS][MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS];
+ u_int32 uWindsorIrqTarget[MEDIAIP_MAX_NUM_WINDSORS][MEDIAIP_MAX_NUM_WINDSOR_IRQ_PINS];
+
+ u_int32 uCmdIrqPin[MEDIAIP_MAX_NUM_CMD_IRQ_PINS];
+ u_int32 uCmdIrqTarget[MEDIAIP_MAX_NUM_CMD_IRQ_PINS];
+
+ u_int32 uMsgIrqPin[MEDIAIP_MAX_NUM_MSG_IRQ_PINS];
+ u_int32 uMsgIrqTarget[MEDIAIP_MAX_NUM_MSG_IRQ_PINS];
+
+ u_int32 uSysClkFreq;
+ u_int32 uNumTimers;
+ u_int32 uTimerBaseAddr;
+ u_int32 uTimerIrqPin[MEDIAIP_MAX_NUM_TIMER_IRQ_PINS];
+ u_int32 uTimerIrqTarget[MEDIAIP_MAX_NUM_TIMER_IRQ_PINS];
+ u_int32 uTimerSlots[MEDIAIP_MAX_NUM_TIMER_IRQ_SLOTS];
+
+ u_int32 uGICBaseAddr;
+ u_int32 uUartBaseAddr;
+
+ u_int32 uDPVBaseAddr;
+ u_int32 uDPVIrqPin;
+ u_int32 uDPVIrqTarget;
+
+ u_int32 uPixIfBaseAddr;
+
+ u_int32 pal_trace_level;
+ u_int32 pal_trace_destination;
+
+ u_int32 pal_trace_level1;
+ u_int32 pal_trace_destination1;
+
+ u_int32 uHeapBase;
+ u_int32 uHeapSize;
+
+ u_int32 uFSLCacheBaseAddr;
+
+} MEDIAIP_FW_SYSTEM_CONFIG, *pMEDIAIP_FW_SYSTEM_CONFIG;
+
+
+///////////////////////////////////////////
+// Encoder types to be globally used across
+// all encode / transcode apps and components
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_FMT
+
+typedef enum
+{
+ MEDIAIP_ENC_FMT_H264 = 0,
+ MEDIAIP_ENC_FMT_VC1,
+ MEDIAIP_ENC_FMT_MPEG2,
+ MEDIAIP_ENC_FMT_MPEG4SP,
+ MEDIAIP_ENC_FMT_H263,
+ MEDIAIP_ENC_FMT_MPEG1,
+ MEDIAIP_ENC_FMT_SHORT_HEADER,
+ MEDIAIP_ENC_FMT_NULL
+
+} MEDIAIP_ENC_FMT;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_PROFILE
+
+typedef enum
+{
+ MEDIAIP_ENC_PROF_MPEG2_SP = 0,
+ MEDIAIP_ENC_PROF_MPEG2_MP,
+ MEDIAIP_ENC_PROF_MPEG2_HP,
+ MEDIAIP_ENC_PROF_H264_BP,
+ MEDIAIP_ENC_PROF_H264_MP,
+ MEDIAIP_ENC_PROF_H264_HP,
+ MEDIAIP_ENC_PROF_MPEG4_SP,
+ MEDIAIP_ENC_PROF_MPEG4_ASP,
+ MEDIAIP_ENC_PROF_VC1_SP,
+ MEDIAIP_ENC_PROF_VC1_MP,
+ MEDIAIP_ENC_PROF_VC1_AP
+
+} MEDIAIP_ENC_PROFILE;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_CONFIG_CODEC_PARAMETER
+
+typedef struct
+{
+ MEDIAIP_ENC_FMT eCodecMode;
+ MEDIAIP_ENC_PROFILE eProfile;
+ u_int32 uReserved[2];
+
+} MEDIAIP_ENC_CONFIG_CODEC_PARAMETER, *pMEDIAIP_ENC_CONFIG_CODEC_PARAMETER; //8 words
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_PIXEL_FORMAT
+
+typedef enum
+{
+ MEDIAIP_ENC_PLANAR = 0,
+ MEDIAIP_ENC_SEMIPLANAR
+
+} MEDIAIP_ENC_PIXEL_FORMAT;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_CHROMA_FMT
+
+typedef enum
+{
+ MODE_420=0,
+ MODE_422,
+ MODE_444
+
+} MEDIAIP_ENC_CHROMA_FMT;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_FRAME_STRUCT
+
+typedef struct
+{
+ u_int32 uSrcFieldModeForDsa;
+ u_int32 uDstFieldModeForEnc;
+ u_int32 uReserved[2];
+
+} MEDIAIP_ENC_FRAME_STRUCT, *pMEDIAIP_ENC_FRAME_STRUCT;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_FRAME_DIMENSIONS
+
+typedef struct
+{
+ /* Input picture features */
+ u_int32 uSrcWidth;
+ u_int32 uSrcHeight;
+ u_int32 uYStride;
+ u_int32 uUVStride;
+
+ /* Clipping information */
+ u_int32 uClipFlag; /*Note: 0: don't clip, 1: clip. encode only a part of input frame */
+ u_int32 uOffset_x;
+ u_int32 uOffset_y;
+ u_int32 uClipPicWidth;
+ u_int32 uClipPicHeight;
+
+ /* Output picture features */
+ u_int32 uDstWidth;
+ u_int32 uDstHeight;
+ u_int32 uTileMode; /* 0: scan raster mode 1: tile mode. */
+ u_int32 uTileWidth; /* Note: In tile mode, uYStride should be calculated depend on uTileWidth */
+ u_int32 uTileHeight;
+
+} MEDIAIP_ENC_FRAME_DIMENSIONS, *pMEDIAIP_ENC_FRAME_DIMENSIONS;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_BITRATE_MODE
+
+typedef enum
+{
+ MEDIAIP_ENC_BITRATECONTROLMODE_VBR = 0x00000001,
+ MEDIAIP_ENC_BITRATECONTROLMODE_CBR = 0x00000002,
+ MEDIAIP_ENC_BITRATECONTROLMODE_CONSTANT_QP = 0x00000004 /* Only in debug mode */
+
+} MEDIAIP_ENC_BITRATE_MODE, *pMEDIAIP_ENC_BITRATE_MODE;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_BITRATE_CONTROL
+
+typedef struct
+{
+ MEDIAIP_ENC_BITRATE_MODE eBitRateMode;
+ u_int32 uTargetBitrate;
+ u_int32 uMaxBitRate;
+ u_int32 uMinBitRate; /* Requested by Windsor, for soft encoder, it is useless */
+ u_int32 uSliceQP;
+
+} MEDIAIP_ENC_BITRATE_CONTROL, *pMEDIAIP_ENC_BITRATE_CONTROL;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_GOP_STRUCTURE
+
+typedef struct
+{
+ u_int32 uFrameRateNum;
+ u_int32 uFrameRateDen;
+ u_int32 uIFrameInterval;
+ u_int32 uGopBLength; /* How many B frames between I or P frames, max is 4 for Windsor */
+ u_int32 uLowLatencyMode; /* Switch off scene change mode, no B frame, only in VBR Mode */
+ /* TODO-KMC */
+ /* Remove the crap below */
+ u_int32 reserved[3];
+
+} MEDIAIP_ENC_GOP_STRUCTURE, *pMEDIAIP_ENC_GOP_STRUCTURE;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_STREAM_PARAMETER
+
+typedef struct
+{
+ MEDIAIP_ENC_CHROMA_FMT eVideoFormat;
+ MEDIAIP_ENC_PIXEL_FORMAT ePixelFormat;
+
+ MEDIAIP_ENC_GOP_STRUCTURE mGOPStructure;
+ MEDIAIP_ENC_FRAME_STRUCT mFrameStructure;
+ MEDIAIP_ENC_FRAME_DIMENSIONS mFrameSize;
+ MEDIAIP_ENC_BITRATE_CONTROL mBitRateControl;
+ u_int32 uExpertModeEnable; /* Enable expert mode */
+ u_int32 uMemChunkAddr; /* Start address of memory chunk */
+ u_int32 uMemChunkSize; /* Size of memory chunk */
+ u_int32 uStreamFinish;
+ /* TODO-KMC */
+ /* Remove the crap below */
+ u_int32 reserved[64 - 40];
+
+} MEDIAIP_ENC_STREAM_PARAMETER, *pMEDIAIP_ENC_STREAM_PARAMETER;
+
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_YUV_BUFFER_DESC
+
+typedef struct
+{
+ u_int32 uFrameID;
+ u_int32 uLumaBase;
+ u_int32 uChromaBase;
+ u_int32 uParamIdx;
+
+} MEDIAIP_ENC_YUV_BUFFER_DESC, *pMEDIAIP_ENC_YUV_BUFFER_DESC;
+
+///////////////////////////////////////////
+// eMEDIAIP_ENC_PIC_TYPE
+
+typedef enum
+{
+ MEDIAIP_ENC_PIC_TYPE_B_FRAME = 0,
+ MEDIAIP_ENC_PIC_TYPE_P_FRAME,
+ MEDIAIP_ENC_PIC_TYPE_I_FRAME,
+ MEDIAIP_ENC_PIC_TYPE_IDR_FRAME,
+ MEDIAIP_ENC_PIC_TYPE_BI_FRAME
+
+} MEDIAIP_ENC_PIC_TYPE, *pMEDIAIP_ENC_PIC_TYPE;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_PIC_TYPE
+
+typedef struct
+{
+ u_int32 uFrameID;
+ u_int32 uPicEncodDone;
+ MEDIAIP_ENC_PIC_TYPE ePicType;
+ u_int32 uSkippedFrame;
+ u_int32 uErrorFlag;
+ u_int32 uPSNR;
+ u_int32 uFlushDone;
+ u_int32 uMBy;
+ u_int32 uMBx;
+ u_int32 uFrameSize;
+ u_int32 uFrameEncTtlFrmCycles;
+ u_int32 uFrameEncTtlSlcCycles;
+ u_int32 uFrameEncTtlEncCycles;
+ u_int32 uFrameEncTtlHmeCycles;
+ u_int32 uFrameEncTtlDsaCycles;
+ u_int32 uFrameEncFwCycles;
+ u_int32 uFrameCrc;
+ u_int32 uNumInterrupts_1;
+ u_int32 uNumInterrupts_2;
+ u_int32 uH264POC;
+ u_int32 uRefInfo;
+ u_int32 uPicNum;
+ u_int32 uPicActivity;
+ u_int32 uSceneChange;
+ u_int32 uMBStats;
+ u_int32 uEncCacheCount0;
+ u_int32 uEncCacheCount1;
+ u_int32 uMtlWrStrbCnt;
+ u_int32 uMtlRdStrbCnt;
+ u_int32 uStrBuffWrPtr;
+ u_int32 uDiagnosticEvents;
+ u_int32 uProcIaccTotRdCnt;
+ u_int32 uProcDaccTotRdCnt;
+ u_int32 uProcDaccTotWrCnt;
+ u_int32 uProcDaccRegRdCnt;
+ u_int32 uProcDaccRegWrCnt;
+ u_int32 uProcDaccRngRdCnt;
+ u_int32 uProcDaccRngWrCnt;
+
+} MEDIAIP_ENC_PIC_INFO, *pMEDIAIP_ENC_PIC_INFO;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_DSA_INFO
+
+typedef struct
+{
+ u_int32 uHeight;
+ u_int32 uWidth;
+ u_int32 uCropWidth;
+ u_int32 uCropHeight;
+ u_int32 uCropPixelXOffset;
+ u_int8 * pImgBuffer;
+ u_int32 uStride;
+ u_int32 uOffset2Chroma;
+ u_int32 uOffset2Decimate;
+
+} MEDIAIP_ENC_DSA_INFO, *pMEDIAIP_ENC_DSA_INFO;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_PIC_PARAM_UPD
+
+typedef struct
+{
+ /* Each bit indicate corresponding parameter should be updated */
+ u_int32 uMaskflag;
+
+ /* ENC_GOP_STRUCTURE variables */
+ u_int32 uFrameRateNum;
+ u_int32 uFrameRateDen;
+
+ /* MEDIAIP_ENC_FRAME_STRUCT variables */
+ u_int32 uSrcFieldModeForDsa;
+ u_int32 uDstFieldModeForEnc;
+
+ /* MEDIAIP_ENC_FRAME_DIMENSIONS variables */
+ u_int32 uSrcWidth;
+ u_int32 uSrcHeight;
+ u_int32 uYStride;
+ u_int32 uUVStride;
+ u_int32 uOffset_x;
+ u_int32 uOffset_y;
+ u_int32 uClipPicWidth;
+ u_int32 uClipPicHeight;
+ u_int32 uDstWidth;
+ u_int32 uDstHeight;
+ u_int32 uIFrameInterval;
+ u_int32 uGopBLength;
+ u_int32 uLowLatencyMode;
+
+ /* MEDIAIP_ENC_BITRATE_CONTROL variables */
+ MEDIAIP_ENC_BITRATE_MODE eBitRateMode;
+ u_int32 uTargetBitrate;
+ u_int32 uMaxBitRate;
+ u_int32 uMinBitRate;
+ u_int32 uSliceQP;
+ u_int32 uReserved[32-23];
+
+} MEDIAIP_ENC_PIC_PARAM_UPD, *pMEDIAIP_ENC_PIC_PARAM_UPD;
+
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_CALIB_PARAMS
+//
+// Encoder Hardware calibration parameters
+
+typedef struct
+{
+ u_int32 use_ame;
+
+ u_int32 cme_mvx_max;
+ u_int32 cme_mvy_max;
+ u_int32 ame_prefresh_y0;
+ u_int32 ame_prefresh_y1;
+ u_int32 fme_min_sad;
+ u_int32 cme_min_sad;
+
+ u_int32 fme_pred_int_weight;
+ u_int32 fme_pred_hp_weight;
+ u_int32 fme_pred_qp_weight;
+ u_int32 fme_cost_weight;
+ u_int32 fme_act_thold;
+ u_int32 fme_sad_thold;
+ u_int32 fme_zero_sad_thold;
+
+ u_int32 fme_lrg_mvx_lmt;
+ u_int32 fme_lrg_mvy_lmt;
+ u_int32 fme_force_mode;
+ u_int32 fme_force4mvcost;
+ u_int32 fme_force2mvcost;
+
+ u_int32 h264_inter_thrd;
+
+ u_int32 i16x16_mode_cost;
+ u_int32 i4x4_mode_lambda;
+ u_int32 i8x8_mode_lambda;
+
+ u_int32 inter_mod_mult;
+ u_int32 inter_sel_mult;
+ u_int32 inter_bid_cost;
+ u_int32 inter_bwd_cost;
+ u_int32 inter_4mv_cost;
+ int32 one_mv_i16_cost;
+ int32 one_mv_i4x4_cost;
+ int32 one_mv_i8x8_cost;
+ int32 two_mv_i16_cost;
+ int32 two_mv_i4x4_cost;
+ int32 two_mv_i8x8_cost;
+ int32 four_mv_i16_cost;
+ int32 four_mv_i4x4_cost;
+ int32 four_mv_i8x8_cost;
+
+ u_int32 intra_pred_enab;
+ u_int32 intra_chr_pred;
+ u_int32 intra16_pred;
+ u_int32 intra4x4_pred;
+ u_int32 intra8x8_pred;
+
+ u_int32 cb_base;
+ u_int32 cb_size;
+ u_int32 cb_head_room;
+
+ u_int32 mem_page_width;
+ u_int32 mem_page_height;
+ u_int32 mem_total_size;
+ u_int32 mem_chunk_addr;
+ u_int32 mem_chunk_size;
+ u_int32 mem_y_stride;
+ u_int32 mem_uv_stride;
+
+ u_int32 split_wr_enab;
+ u_int32 split_wr_req_size;
+ u_int32 split_rd_enab;
+ u_int32 split_rd_req_size;
+
+} MEDIAIP_ENC_CALIB_PARAMS, *pMEDIAIP_ENC_CALIB_PARAMS;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_CONFIG_PARAMS
+//
+// Stream-specific configuration parameters
+
+typedef struct
+{
+ u_int32 ParamChange;
+
+ u_int32 start_frame; // These variables are for debugging purposes only
+ u_int32 end_frame;
+
+ u_int32 userdata_enable;
+ u_int32 userdata_id[4];
+ u_int32 userdata_message[MEDIAIP_ENC_USER_DATA_WORDS];
+ u_int32 userdata_length;
+
+ u_int32 h264_profile_idc;
+ u_int32 h264_level_idc;
+ u_int32 h264_au_delimiter; // Enable the use of Access Unit Delimiters
+ u_int32 h264_seq_end_code; // Enable the use of Sequence End Codes
+ u_int32 h264_recovery_points; // Enable the use of Recovery Points (must be with a fixed GOP structure)
+ u_int32 h264_vui_parameters; // Enable the use of VUI parameters (for rate control purposes)
+ u_int32 h264_aspect_ratio_present;
+ u_int32 h264_aspect_ratio_sar_width;
+ u_int32 h264_aspect_ratio_sar_height;
+ u_int32 h264_overscan_present;
+ u_int32 h264_video_type_present;
+ u_int32 h264_video_format;
+ u_int32 h264_video_full_range;
+ u_int32 h264_video_colour_descriptor;
+ u_int32 h264_video_colour_primaries;
+ u_int32 h264_video_transfer_char;
+ u_int32 h264_video_matrix_coeff;
+ u_int32 h264_chroma_loc_info_present;
+ u_int32 h264_chroma_loc_type_top;
+ u_int32 h264_chroma_loc_type_bot;
+ u_int32 h264_timing_info_present;
+ u_int32 h264_buffering_period_present;
+ u_int32 h264_low_delay_hrd_flag;
+
+ u_int32 aspect_ratio;
+ u_int32 test_mode; // Automated firmware test mode
+ u_int32 dsa_test_mode; // Automated test mode for the DSA.
+ u_int32 fme_test_mode; // Automated test mode for the fme
+
+ u_int32 cbr_row_mode; //0: FW mode; 1: HW mode
+ u_int32 windsor_mode; //0: normal mode; 1: intra only mode; 2: intra+0MV mode
+ u_int32 encode_mode; // H264, VC1, MPEG2, DIVX
+ u_int32 frame_width; // display width
+ u_int32 frame_height; // display height
+ u_int32 enc_frame_width; // encoding width, should be 16-pix align
+ u_int32 enc_frame_height; // encoding height, should be 16-pix aligned for progressive and 32-pix aligned for interlace
+ u_int32 frame_rate_num;
+ u_int32 frame_rate_den;
+
+ u_int32 vi_field_source; // vi input source is frame or field
+ u_int32 vi_frame_width;
+ u_int32 vi_frame_height;
+ u_int32 crop_frame_width;
+ u_int32 crop_frame_height;
+ u_int32 crop_x_start_posn;
+ u_int32 crop_y_start_posn;
+ u_int32 mode422;
+ u_int32 mode_yuy2;
+ u_int32 dsa_luma_en;
+ u_int32 dsa_chroma_en;
+ u_int32 dsa_ext_hfilt_en;
+ u_int32 dsa_di_en;
+ u_int32 dsa_di_top_ref;
+ u_int32 dsa_vertf_disable; // disable the vertical filter.
+ u_int32 dsa_disable_pwb;
+ u_int32 dsa_hor_phase;
+ u_int32 dsa_ver_phase;
+
+ u_int32 dsa_iac_enable; // IAC / DSA cannot operate independently in FW so this variable controls
+ u_int32 iac_sc_threshold;
+ u_int32 iac_vm_threshold;
+ u_int32 iac_skip_mode;
+ u_int32 iac_grp_width;
+ u_int32 iac_grp_height;
+
+ u_int32 rate_control_mode;
+ u_int32 rate_control_resolution;
+ u_int32 buffer_size;
+ u_int32 buffer_level_init;
+ u_int32 buffer_I_bit_budget;
+
+ u_int32 top_field_first;
+
+ u_int32 intra_lum_qoffset;
+ u_int32 intra_chr_qoffset;
+ u_int32 inter_lum_qoffset;
+ u_int32 inter_chr_qoffset;
+ u_int32 use_def_scaling_mtx;
+
+ u_int32 inter_8x8_enab;
+ u_int32 inter_4x4_enab;
+
+ u_int32 fme_enable_qpel;
+ u_int32 fme_enable_hpel;
+ u_int32 fme_nozeromv; // can force the FME not to do the (0,0) search.
+ u_int32 fme_predmv_en;
+ u_int32 fme_pred_2mv4mv;
+ u_int32 fme_smallsadthresh;
+
+ u_int32 ame_en_lmvc;
+ u_int32 ame_x_mult;
+ u_int32 cme_enable_4mv; // Enable the use of 4MV partitioning
+ u_int32 cme_enable_1mv;
+ u_int32 hme_enable_16x8mv;
+ u_int32 hme_enable_8x16mv;
+ u_int32 cme_mv_weight; // CME motion vector decisions are made by combining these
+ u_int32 cme_mv_cost; // cost and weight variables
+ u_int32 ame_mult_mv;
+ u_int32 ame_shift_mv;
+
+ u_int32 hme_forceto1mv_en;
+ u_int32 hme_2mv_cost; // the cost of choosing a 2MV mode over 1MV.
+ u_int32 hme_pred_mode;
+ u_int32 hme_sc_rnge;
+ u_int32 hme_sw_rnge;
+
+ // for windsor pes , add by fulin
+ u_int32 output_format; // 0: output ES; 1: output PES
+ u_int32 timestamp_enab; // 0: have timestamps in all frame; 1: have timestamps in I and P frame; 2: have timestamps only in I frame
+ u_int32 initial_PTS_enab; // if enabled , use following value,else compute by fw
+ u_int32 initial_PTS; // the initial value of PTS in the first frame (ms)
+
+} MEDIAIP_ENC_CONFIG_PARAMS, *pMEDIAIP_ENC_CONFIG_PARAMS;
+
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_STATIC_PARAMS
+//
+// Static parameters ( may change at the GOP level )
+
+typedef struct
+{
+ u_int32 ParamChange;
+
+ u_int32 gop_length;
+
+ u_int32 rate_control_bitrate;
+ u_int32 rate_control_bitrate_min;
+ u_int32 rate_control_bitrate_max;
+ u_int32 rate_control_content_models;
+ u_int32 rate_control_iframe_maxsize; // Maximum size of I frame generated by BPM in comparison to ideal (/4)
+ u_int32 rate_control_qp_init;
+ u_int32 rate_control_islice_qp;
+ u_int32 rate_control_pslice_qp;
+ u_int32 rate_control_bslice_qp;
+
+ u_int32 adaptive_quantization; // Enable the use of activity measures from VIPP in QP assignment
+ u_int32 aq_variance;
+ u_int32 cost_optimization; // Enable picture/frame level adjustments of the cost parameters by FW.
+ u_int32 fdlp_mode; // Frequency-domain low-pass filter control, 0: off, 1-4: specific, 5: adaptive
+ u_int32 enable_isegbframes; // Enable the use of B frames in the first segment of a GOP
+ u_int32 enable_adaptive_keyratio; // Enable the use of an adaptive I to P/B ratio (aims to reduce distortion)
+ u_int32 keyratio_imin; // Clamps applied to picture size ratios
+ u_int32 keyratio_imax;
+ u_int32 keyratio_pmin;
+ u_int32 keyratio_pmax;
+ u_int32 keyratio_bmin;
+ u_int32 keyratio_bmax;
+ int32 keyratio_istep;
+ int32 keyratio_pstep;
+ int32 keyratio_bstep;
+
+ u_int32 enable_paff; // Enable Picture Adaptive Frame/Field
+ u_int32 enable_b_frame_ref; // Enable B frame as references
+ u_int32 enable_adaptive_gop; // Enable an adaptive GOP structure
+ u_int32 enable_closed_gop; // Enable a closed GOP structure
+ // i.e. if enabled, the first consecutive B frames following
+ // an I frame in each GOP will be intra or backwards only coded
+ // and do not rely on previous reference pictures.
+ u_int32 open_gop_refresh_freq; // Controls the insertion of closed GOP's (or IDR GOP's in H.264)
+ u_int32 enable_adaptive_sc; // Enable adaptive scene change GOP structure (0:off, 1:adaptive, 2:IDR)
+ u_int32 enable_fade_detection; // Enable fade detection and associated motion estimation restrictions
+ int32 fade_detection_threshold; // Threshold at which the activity slope indicates a possible fading event
+ u_int32 enable_repeat_b; // Enalbe the repeated B frame mode at CBR
+
+} MEDIAIP_ENC_STATIC_PARAMS, *pMEDIAIP_ENC_STATIC_PARAMS;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_DYN_PARAMS
+//
+// Dynamic parameters (may change at the frame level)
+
+typedef struct
+{
+ u_int32 ParamChange;
+
+ u_int32 rows_per_slice;
+
+ u_int32 mbaff_enable; // Macroblock adaptive frame/field enable
+ u_int32 dbf_enable; // Enable the deblocking filter
+
+ u_int32 field_source; // progressive/interlaced control
+ u_int32 gop_b_length; // Number of B frames between anchor frames
+ // (only to be changed at a GOP segment boundary)
+ u_int32 mb_group_size; // Number of macroblocks normally assigned to a group
+ // (implications for performance, interrupts and rate control)
+
+ u_int32 cbr_rows_per_group;
+
+ u_int32 skip_enable; // Enable the use of skipped macroblocks
+
+ u_int32 pts_bits_0_to_31; // TO BE REMOVED...
+ u_int32 pts_bit_32;
+
+ u_int32 rm_expsv_cff;
+ u_int32 const_ipred;
+ int32 chr_qp_offset;
+ u_int32 intra_mb_qp_offset;
+
+ u_int32 h264_cabac_init_method;
+ u_int32 h264_cabac_init_idc;
+ u_int32 h264_cabac_enable; // Main and stream
+
+ int32 alpha_c0_offset_div2;
+ int32 beta_offset_div2;
+
+ u_int32 intra_prefresh_y0; // for setting intra limits for prog refresh.
+ u_int32 intra_prefresh_y1;
+
+ u_int32 dbg_dump_rec_src;
+
+} MEDIAIP_ENC_DYN_PARAMS, *pMEDIAIP_ENC_DYN_PARAMS;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_EXPERT_MODE_PARAM
+
+typedef struct
+{
+ MEDIAIP_ENC_CALIB_PARAMS Calib;
+ MEDIAIP_ENC_CONFIG_PARAMS Config;
+ MEDIAIP_ENC_STATIC_PARAMS Static;
+ MEDIAIP_ENC_DYN_PARAMS Dynamic;
+} MEDIAIP_ENC_EXPERT_MODE_PARAM, *pMEDIAIP_ENC_EXPERT_MODE_PARAM;
+
+///////////////////////////////////////////
+// MEDIAIP_ENC_PARAM
+
+typedef struct
+{
+ MEDIAIP_ENC_FMT eCodecMode;
+ MEDIAIP_ENC_PROFILE eProfile;
+
+ u_int32 uMemChunkAddr;
+ u_int32 uMemChunkSize;
+
+ u_int32 uFrameRate;
+ u_int32 uSrcStride;
+ u_int32 uSrcWidth;
+ u_int32 uSrcHeight;
+ u_int32 uSrcOffset_x;
+ u_int32 uSrcOffset_y;
+ u_int32 uSrcCropWidth;
+ u_int32 uSrcCropHeight;
+ u_int32 uOutWidth;
+ u_int32 uOutHeight;
+ u_int32 uIFrameInterval;
+ u_int32 uGopBLength;
+ u_int32 uLowLatencyMode;
+
+ MEDIAIP_ENC_BITRATE_MODE eBitRateMode;
+ u_int32 uTargetBitrate;
+ u_int32 uMaxBitRate;
+ u_int32 uMinBitRate;
+ u_int32 uInitSliceQP;
+
+} MEDIAIP_ENC_PARAM, *pMEDIAIP_ENC_PARAM;
+
+#endif /* _MEDIAIP_FW_TYPES_H_ */
+
+/* End of File */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/Incl/pal.h b/drivers/mxc/vpu-malone/Malone_Firmware/Incl/pal.h
new file mode 100755
index 000000000000..66c21417a891
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/Incl/pal.h
@@ -0,0 +1,337 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+ Filename : pal.h
+ Description : Public header file for the
+ Platform Abstraction Layer
+ Author: Media IP FW team (Belfast)
+
+ ***************************************************/
+
+#ifndef _PAL_H_
+#define _PAL_H_
+
+/////////////////////////////////////////////////////////////////////////////////
+// Header Files
+/////////////////////////////////////////////////////////////////////////////////
+
+#ifndef VPU_KERNEL_BUILD
+#include "stdio.h"
+#include "video_subsystem.h"
+#include "pal_os_al.h"
+/* For va_list */
+#include <stdarg.h>
+#endif
+#include "basetype.h"
+#include "pal_types.h"
+
+#if ( TARGET_APP == VPU_TEST_APP )
+/* thread, semaphore and queue funcitons */
+#include "pal_linux_map.h"
+#endif
+
+/* For buffer descriptor */
+#include "mediaip_fw_types.h"
+
+/* For va_list */
+#include <stdarg.h>
+
+/////////////////////////////////////////////////////////////////////////////////
+// Function prototypes
+/////////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////
+// Initialisation Functions
+//
+
+#if RTOS == NONE
+
+MEDIAIP_FW_STATUS pal_initialise ( psPALConfig pconfig );
+
+#else
+
+void pal_early_initialise ( void );
+
+MEDIAIP_FW_STATUS pal_initialise ( void );
+
+#endif
+
+//////////////////////////////////////////////////
+// Assert function
+//
+void pal_assert_impl(u_int32 uAssertPC, u_int32 uAssertInfo);
+
+///////////////////////////////////////////////////
+// Critical section functions
+//
+
+MEDIAIP_FW_STATUS pal_critical_section_begin ( PAL_CRIT_STATE *pState );
+
+MEDIAIP_FW_STATUS pal_critical_section_end ( PAL_CRIT_STATE PreviousState );
+
+///////////////////////////////////////////////////
+// Interrupt Functions
+//
+
+MEDIAIP_FW_STATUS pal_int_register ( u_int32 dwIntID,
+ PAL_PFNISR pfnHandler,
+ BOOL bFIQ );
+
+MEDIAIP_FW_STATUS pal_int_enable ( u_int32 dwIntID );
+
+void pal_int_set ( u_int32 dwIntID );
+
+#if ( TARGET_PLATFORM == GENTB_PLATFORM ) || ( TARGET_PLATFORM == GEN_TB_ENC ) || ( TARGET_PLATFORM == WIN_LIB )
+
+void pal_int_clear ( u_int32 dwIntID,
+ BOOL bDirect );
+
+MEDIAIP_FW_STATUS pal_int_get_irq_line ( u_int32 uFWIrq,
+ u_int32 *puIrqLine );
+
+#else
+
+void pal_int_clear ( u_int32 dwIntID );
+
+#endif
+
+void pal_int_clear_host ( u_int32 dwIntID );
+
+
+///////////////////////////////////////////////////
+// Processor Cache Control Functions
+//
+
+MEDIAIP_FW_STATUS pal_clean_d_cache ( void );
+
+MEDIAIP_FW_STATUS pal_disable_d_cache ( void );
+
+void pal_wait_for_interrupt ( void );
+
+///////////////////////////////////////////////////
+// Malone Cache Control Functions
+//
+void pal_set_malone_cache ( u_int32 uMalID );
+
+///////////////////////////////////////////////////
+// C Runtime Wrappers
+//
+
+MEDIAIP_FW_STATUS pal_memcpy ( void *pDest,
+ const void *pSrc,
+ u_int32 uSize );
+
+void pal_memset ( void *pDest, int32 nChar, u_int32 uCount );
+
+BOOL pal_memcompare ( void *pArea1, void *pArea2, u_int32 uSizeInWords );
+
+///////////////////////////////////////////////////
+// Hardware Timer Service APIs
+//
+
+MEDIAIP_FW_STATUS pal_timer_create ( PAL_PFNTIMER pfnCallback,
+ void * pUserData,
+ PAL_TIMER_ID * pTimer );
+
+MEDIAIP_FW_STATUS pal_timer_destroy( PAL_TIMER_ID Timer );
+
+///////////////////////////////////////////////////
+// Perf Counter APIs
+//
+
+MEDIAIP_FW_STATUS pal_perf_counter_create ( const char * pszName,
+ PAL_PERF_ID * pPCId );
+
+MEDIAIP_FW_STATUS pal_perf_counter_destroy ( PAL_PERF_ID PCId );
+
+MEDIAIP_FW_STATUS pal_perf_counter_start ( PAL_PERF_ID PCId );
+
+MEDIAIP_FW_STATUS pal_perf_counter_stop ( PAL_PERF_ID PCId );
+
+MEDIAIP_FW_STATUS pal_perf_counter_pause_control ( PAL_PERF_ID PCId , bool bStartPause);
+
+MEDIAIP_FW_STATUS pal_perf_counter_read ( PAL_PERF_ID PerfId,
+ u_int32 * puCountVal );
+
+///////////////////////////////////////////////////
+// Trace / Error / Message log functions
+//
+
+/* Error logging */
+#if !(DEBUG_CAPS == FULL_DEBUG ) && (ENABLE_TRACE_IN_RELEASE == NO)
+
+/* Non-debug case */
+MEDIAIP_FW_STATUS pal_error_log ( u_int32 uError );
+
+#else
+
+/* Debug case - wrap in macros so that we can add file and line number automatically */
+#ifdef _MSC_VER
+int pal_debug_error_log (
+#else
+MEDIAIP_FW_STATUS pal_debug_error_log (
+#endif
+ u_int32 uError,
+ char *pszFile,
+ int32 nLineNum );
+#ifndef _MSC_VER
+#define pal_error_log(x) pal_debug_error_log((x), __FILE__, __LINE__)
+#endif // _MSC_VER
+#endif
+
+/* Size of trace print buffer */
+#define FW_PRT_BUFF_SIZE 512
+
+#ifdef DISABLE_TRACE
+/* Declare pal_trace as an empty statement and cast to void to avoid a "no-effect" warning. */
+/* This soaks up the trailing semi-colon and avoids leaving them dangling. */
+#define pal_trace(...) (void)(0)
+#else
+#if ( TARGET_APP == VPU_TEST_APP )
+#ifdef NXP_MX_REAL_TARGET
+#define pal_trace(flags, fmt, arg...) dprintf(LVL_FUNC, fmt, ## arg)
+#else
+void pal_trace ( u_int32 uFlags, const char *psz_format, ...);
+#endif
+#else
+void pal_trace ( u_int32 uFlags, const char *psz_format, ...);
+#endif
+#endif
+
+int pal_vsnprintf ( char *str, int size, const char *format, va_list args );
+
+int pal_sprintf ( char *str, int size, const char *psz_format, ...);
+
+#ifdef PAL_DEBUG_LOG
+void pal_debug_log ( u_int32 uCode );
+#else
+#define pal_debug_log(...) (void)(0)
+#endif
+
+MEDIAIP_FW_STATUS pal_trace_set_level ( u_int32 uLevel,
+ BOOL bTimestamp,
+ MEDIAIP_TRACE_FLAGS * pFlags );
+
+MEDIAIP_FW_STATUS pal_trace_set_module_flag ( u_int32 uModuleID,
+ BOOL bEnable,
+ MEDIAIP_TRACE_FLAGS * pFlags );
+
+MEDIAIP_FW_STATUS pal_trace_is_module_enabled ( u_int32 uModuleID,
+ BOOL * pbEnabled );
+
+void pal_checkpoint_str(char *pMsg );
+void pal_checkpoint_hex(unsigned uData);
+#define CHECKPOINT_STR pal_checkpoint_str
+#define CHECKPOINT_HEX pal_checkpoint_hex
+
+
+///////////////////////////////////////////////////
+// Clock functions - often very platform specific
+//
+
+#ifdef PAL_CLOCK_API
+
+MEDIAIP_FW_STATUS pal_malone_clock_reg_init ( void );
+
+MEDIAIP_FW_STATUS pal_malone_clock_enable_common ( bool bEnable );
+
+MEDIAIP_FW_STATUS pal_malone_clock_enable_avc ( bool bEnable );
+
+MEDIAIP_FW_STATUS pal_malone_clock_enable_vc1 ( bool bEnable );
+
+MEDIAIP_FW_STATUS pal_malone_clock_enable_mpg ( bool bEnable );
+
+MEDIAIP_FW_STATUS pal_malone_clock_enable_avs ( bool bEnable );
+
+#endif /* PAL_CLOCK_API */
+
+///////////////////////////////////////////////////
+// Miscellaneous functions
+//
+
+void pal_fatal_exit_internal ( u_int32 uCosmicConstant,
+ char * pszFilename,
+ int iLineNum );
+
+//#define pal_fatal_exit(x) pal_fatal_exit_internal((x), __FILE__, __LINE__)
+#ifdef VPU_KERNEL_BUILD
+#define pal_fatal_exit(x) while (1) {printk("pal_fatal_exit in %s file %s line %d\n", __FUNCTION__, __FILE__, __LINE__);}
+#else
+#define pal_fatal_exit(x) while (1) {printf("pal_fatal_exit in %s file %s line %d\n", __FUNCTION__, __FILE__, __LINE__);}
+#endif
+
+
+
+u_int32 pal_find_highest_bit ( u_int32 uValue );
+
+extern u_int32 _return_pc ( void );
+
+#define pal_return_pc _return_pc
+
+u_int32 pal_get_fw_base ( void );
+
+u_int32 pal_get_target_version ( void );
+
+///////////////////////////////////////////////////
+// Memory management abstraction functions
+//
+#if ( TARGET_APP == VPU_TEST_APP )
+/* sPALMemDesc Added by NXP for their PAL implementation */
+typedef struct {
+ u_int32 size;
+ u_int32 phy_addr;
+ uint_addr virt_addr;
+#ifdef USE_ION
+ int32 ion_buf_fd;
+#endif
+} sPALMemDesc, *psPALMemDesc;
+
+MEDIAIP_FW_STATUS pal_get_phy_buf(psPALMemDesc pbuf);
+MEDIAIP_FW_STATUS pal_free_phy_buf(psPALMemDesc pbuf);
+#endif
+
+u_int32 pal_va2pa ( u_int32 * pAddr );
+
+u_int32 * pal_return_uncached_addr ( u_int32 * puAddress );
+
+u_int32 * pal_return_cacheable_addr ( u_int32 * puAddress );
+
+u_int32 * pal_return_mmu_bypass_addr ( u_int32 * puAddress );
+
+u_int32 pal_read_uncached ( u_int32 * puAddress );
+
+#if RTOS != NONE
+/* Need to add in the prototypes for the PAL ftns which invoke an OS */
+/* Abstraction layer call */
+
+#include "pal_os_al.h"
+
+#endif
+
+///////////////////////////////////////////////////
+// Miscellaneous macros
+//
+
+#ifdef PERF_MEASURE_ENABLE_ENC
+u_int32 GetCountVal();
+u_int32 SetCountVal(u_int32 CountVal);
+#endif
+
+#if ( TARGET_APP == VPU_TEST_APP )
+#define INT_ID_MALONE_LOW 0
+#define INT_ID_MALONE_HI 1
+#define INT_ID_MAX 2
+extern PAL_PFNISR int_handlers[INT_ID_MAX];
+#endif
+
+#endif /* _PAL_H_ */
+
+/* End of File */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/Incl/status_codes.h b/drivers/mxc/vpu-malone/Malone_Firmware/Incl/status_codes.h
new file mode 100755
index 000000000000..cc53a566948c
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/Incl/status_codes.h
@@ -0,0 +1,99 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+ Filename : status_codes.h
+ Description : Public header file for FW & SW status codes
+ including those used by relevant abstraction layers
+ Author : Kyle McAdoo
+
+ *****************************************************/
+
+#ifndef _STATUS_CODES_H_
+#define _STATUS_CODES_H_
+
+typedef enum
+{
+ /* 0 0x00 */ MEDIAIP_FW_STATUS_OK = 0,
+ /* 1 0x01 */ MEDIAIP_FW_STATUS_ALREADY_INIT,
+ /* 2 0x02 */ MEDIAIP_FW_STATUS_NOT_INIT,
+ /* 3 0x03 */ MEDIAIP_FW_STATUS_INTERNAL_ERROR,
+ /* 4 0x04 */ MEDIAIP_FW_STATUS_BAD_HANDLE,
+ /* 5 0x05 */ MEDIAIP_FW_STATUS_BAD_PARAMETER,
+ /* 6 0x06 */ MEDIAIP_FW_STATUS_BAD_LENGTH,
+ /* 7 0x07 */ MEDIAIP_FW_STATUS_BAD_UNIT,
+ /* 8 0x08 */ MEDIAIP_FW_STATUS_RESOURCE_ERROR,
+ /* 9 0x09 */ MEDIAIP_FW_STATUS_CLOSED_HANDLE,
+ /* 10 0x0A */ MEDIAIP_FW_STATUS_TIMEOUT,
+ /* 11 0x0B */ MEDIAIP_FW_STATUS_NOT_ATTACHED,
+ /* 12 0x0C */ MEDIAIP_FW_STATUS_NOT_SUPPORTED,
+ /* 13 0x0D */ MEDIAIP_FW_STATUS_REOPENED_HANDLE,
+ /* 14 0x0E */ MEDIAIP_FW_STATUS_INVALID,
+ /* 15 0x0F */ MEDIAIP_FW_STATUS_DESTROYED,
+ /* 16 0x10 */ MEDIAIP_FW_STATUS_DISCONNECTED,
+ /* 17 0x11 */ MEDIAIP_FW_STATUS_BUSY,
+ /* 18 0x12 */ MEDIAIP_FW_STATUS_IN_USE,
+ /* 19 0x13 */ MEDIAIP_FW_STATUS_CANCELLED,
+ /* 20 0x14 */ MEDIAIP_FW_STATUS_UNDEFINED,
+ /* 21 0x15 */ MEDIAIP_FW_STATUS_UNKNOWN,
+ /* 22 0x16 */ MEDIAIP_FW_STATUS_NOT_FOUND,
+ /* 23 0x17 */ MEDIAIP_FW_STATUS_NOT_AVAILABLE,
+ /* 24 0x18 */ MEDIAIP_FW_STATUS_NOT_COMPATIBLE,
+ /* 25 0x19 */ MEDIAIP_FW_STATUS_NOT_IMPLEMENTED,
+ /* 26 0x1A */ MEDIAIP_FW_STATUS_EMPTY,
+ /* 27 0x1B */ MEDIAIP_FW_STATUS_FULL,
+ /* 28 0x1C */ MEDIAIP_FW_STATUS_FAILURE,
+ /* 29 0x1D */ MEDIAIP_FW_STATUS_ALREADY_ATTACHED,
+ /* 30 0x1E */ MEDIAIP_FW_STATUS_ALREADY_DONE,
+ /* 31 0x1F */ MEDIAIP_FW_STATUS_ASLEEP,
+ /* 32 0x20 */ MEDIAIP_FW_STATUS_BAD_ATTACHMENT,
+ /* 33 0x21 */ MEDIAIP_FW_STATUS_BAD_COMMAND,
+ /* 34 0x22 */ MEDIAIP_FW_STATUS_INT_HANDLED,
+ /* 35 0x23 */ MEDIAIP_FW_STATUS_INT_NOT_HANDLED,
+ /* 36 0x24 */ MEDIAIP_FW_STATUS_NOT_SET,
+ /* 37 0x25 */ MEDIAIP_FW_STATUS_NOT_HOOKED,
+ /* 38 0x26 */ MEDIAIP_FW_STATUS_COMPLETE,
+ /* 39 0x27 */ MEDIAIP_FW_STATUS_INVALID_NODE,
+ /* 40 0x28 */ MEDIAIP_FW_STATUS_DUPLICATE_NODE,
+ /* 41 0x29 */ MEDIAIP_FW_STATUS_HARDWARE_NOT_FOUND,
+ /* 42 0x2A */ MEDIAIP_FW_STATUS_ILLEGAL_OPERATION,
+ /* 43 0x2B */ MEDIAIP_FW_STATUS_INCOMPATIBLE_FORMATS,
+ /* 44 0x2C */ MEDIAIP_FW_STATUS_INVALID_DEVICE,
+ /* 45 0x2D */ MEDIAIP_FW_STATUS_INVALID_EDGE,
+ /* 46 0x2E */ MEDIAIP_FW_STATUS_INVALID_NUMBER,
+ /* 47 0x2F */ MEDIAIP_FW_STATUS_INVALID_STATE,
+ /* 48 0x30 */ MEDIAIP_FW_STATUS_INVALID_TYPE,
+ /* 49 0x31 */ MEDIAIP_FW_STATUS_STOPPED,
+ /* 50 0x32 */ MEDIAIP_FW_STATUS_SUSPENDED,
+ /* 51 0x33 */ MEDIAIP_FW_STATUS_TERMINATED,
+ /* 52 0x34 */ MEDIAIP_FW_STATUS_FRAMESTORE_NOT_HANDLED,
+ /* Last Entry */ MEDIAIP_FW_STATUS_CODE_LAST = MEDIAIP_FW_STATUS_FRAMESTORE_NOT_HANDLED
+} MEDIAIP_FW_STATUS;
+
+#if RTOS != NONE
+
+#if OSAL == CNXT_KAL
+#include "cnxt_kal_status_codes.h"
+typedef MEDIAIP_OSAL_STATUS CNXT_IRQ_RETCODE;
+typedef MEDIAIP_FW_STATUS MEDIAIP_IRQ_RETCODE;
+#endif
+
+#if OSAL == NXP_OSAL
+#include "nxp_osal_status_codes.h"
+typedef MEDIAIP_OSAL_STATUS MEDIAIP_IRQ_RETCODE;
+#endif
+
+#else
+typedef MEDIAIP_FW_STATUS MEDIAIP_IRQ_RETCODE;
+#endif
+
+#endif /* _STATUS_CODES_H_ */
+
+/* End of File */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/Incl/trace_types.h b/drivers/mxc/vpu-malone/Malone_Firmware/Incl/trace_types.h
new file mode 100755
index 000000000000..18a3cb381c53
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/Incl/trace_types.h
@@ -0,0 +1,261 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+ Filename : trace_types.h
+ Description : Public header file containing type definitions and labels
+ related to debug trace functions
+ Author : Dave Wilson
+ Modified for Transcode FW by K McAdoo (from version 1.41)
+ This is no longer only for RTOS builds
+ ************************************************/
+
+#ifndef _TRACE_TYPES_H_
+#define _TRACE_TYPES_H_
+
+#include "basetype.h"
+
+/* Flag indicating a fatal error - top bit of error_num */
+#define MEDIAIP_ERROR_FATAL 0x80000000
+#define MEDIAIP_ERROR_WARNING 0x00000000
+
+/* Flags for trace levels */
+#define MEDIAIP_TRACE_MASK_MODULE 0x0FFFFFFF
+#define MEDIAIP_TRACE_MASK_LEVEL 0x70000000
+#define MEDIAIP_TRACE_MASK_TIMESTAMP 0x80000000
+
+#define MEDIAIP_TRACE_SHIFT_LEVEL 28
+#define MEDIAIP_TRACE_SHIFT_TIMESTAMP 31
+
+#define MEDIAIP_TRACE_LEVEL_NEVER 0x00000000
+#define MEDIAIP_TRACE_LEVEL_1 0x10000000
+#define MEDIAIP_TRACE_LEVEL_2 0x20000000
+#define MEDIAIP_TRACE_LEVEL_3 0x30000000
+#define MEDIAIP_TRACE_LEVEL_4 0x40000000
+#define MEDIAIP_TRACE_LEVEL_5 0x50000000
+#define MEDIAIP_TRACE_LEVEL_6 0x60000000
+#define MEDIAIP_TRACE_LEVEL_ALWAYS 0x70000000
+
+/* Disable the timestamp */
+#define MEDIAIP_TRACE_NO_TIMESTAMP 0x80000000
+
+/* Module identifiers */
+#define MEDIAIP_TRACE_DECODER 0x00000001
+#define MEDIAIP_TRACE_DISPLAY 0x00000002
+#define MEDIAIP_TRACE_ENCODER 0x00000003
+#define MEDIAIP_TRACE_HANDLE 0x00000004
+#define MEDIAIP_TRACE_IMGPORT 0x00000005
+#define MEDIAIP_TRACE_PAL 0x00000006
+#define MEDIAIP_TRACE_KAL 0x00000006
+#define MEDIAIP_TRACE_MEMMOVE 0x00000007
+#define MEDIAIP_TRACE_QUEUE 0x00000008
+#define MEDIAIP_TRACE_VAMUX 0x00000009
+
+/* Control Layer identifiers */
+#define MEDIAIP_TRACE_VIDEO_LAYER 0x00000050
+#define MEDIAIP_TRACE_SYSTEM_LAYER 0x00000051
+#define MEDIAIP_TRACE_PROC_LAYER 0x00000052
+#define MEDIAIP_TRACE_API_LAYER 0x00000053
+
+/* Additional IDs for application use */
+#define MEDIAIP_TRACE_APPLICATION 0x00000060
+#define MEDIAIP_TRACE_TEST 0x00000061
+
+/* The upper supported value of a trace module identifier. Make sure that
+ there are no trace IDs defined above this value since it is used to
+ determine the amount of storage required for trace flags! */
+#define MEDIAIP_TRACE_MAX 0x0000009F
+
+/* ID indicating that message should be displayed regardless of the
+ modules which are currently enabled. */
+#define MEDIAIP_TRACE_ANY 0x00000000
+
+/* Trace message color codes */
+
+#define MEDIAIP_TRACE_FG_LIGHT_BLUE "\033[1;34m"
+#define MEDIAIP_TRACE_FG_LIGHT_GREEN "\033[1;32m"
+#define MEDIAIP_TRACE_FG_LIGHT_CYAN "\033[1;36m"
+#define MEDIAIP_TRACE_FG_LIGHT_RED "\033[1;31m"
+#define MEDIAIP_TRACE_FG_WHITE "\033[1;37m"
+#define MEDIAIP_TRACE_FG_NORMAL MEDIAIP_TRACE_FG_WHITE
+#define MEDIAIP_TRACE_BG_GRAY "\033[0;47m"
+#define MEDIAIP_TRACE_BG_BLACK "\033[0;40m"
+
+/* The number of 32bit words needed to store our trace flags */
+#define MEDIAIP_TRACE_FLAGS_WORDS ((MEDIAIP_TRACE_MAX+31)/32)
+
+/* Data structure used to store trace flags */
+typedef struct
+{
+
+ u_int32 Flags[MEDIAIP_TRACE_FLAGS_WORDS];
+
+} MEDIAIP_TRACE_FLAGS;
+
+
+/////////////////////////////////////////////////////////////////////////////////
+// Module / Application and System Trace level definitions
+
+#define DECODER_TL_CATASTROPHE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ANY)
+#define DECODER_TL_SEVERE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_DECODER)
+#define DECODER_TL_ERROR (MEDIAIP_TRACE_LEVEL_6 | MEDIAIP_TRACE_DECODER)
+#define DECODER_TL_WARNING (MEDIAIP_TRACE_LEVEL_5 | MEDIAIP_TRACE_DECODER)
+#define DECODER_TL_FUNC (MEDIAIP_TRACE_LEVEL_4 | MEDIAIP_TRACE_DECODER)
+#define DECODER_TL_INFO (MEDIAIP_TRACE_LEVEL_3 | MEDIAIP_TRACE_DECODER)
+#define DECODER_TL_VERBOSE (MEDIAIP_TRACE_LEVEL_2 | MEDIAIP_TRACE_DECODER)
+#define DECODER_TL_DEBUG (MEDIAIP_TRACE_LEVEL_1 | MEDIAIP_TRACE_DECODER)
+
+#define DISPLAY_TL_CATASTROPHE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ANY)
+#define DISPLAY_TL_SEVERE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_DISPLAY)
+#define DISPLAY_TL_ERROR (MEDIAIP_TRACE_LEVEL_6 | MEDIAIP_TRACE_DISPLAY)
+#define DISPLAY_TL_WARNING (MEDIAIP_TRACE_LEVEL_5 | MEDIAIP_TRACE_DISPLAY)
+#define DISPLAY_TL_FUNC (MEDIAIP_TRACE_LEVEL_4 | MEDIAIP_TRACE_DISPLAY)
+#define DISPLAY_TL_INFO (MEDIAIP_TRACE_LEVEL_3 | MEDIAIP_TRACE_DISPLAY)
+#define DISPLAY_TL_VERBOSE (MEDIAIP_TRACE_LEVEL_2 | MEDIAIP_TRACE_DISPLAY)
+#define DISPLAY_TL_DEBUG (MEDIAIP_TRACE_LEVEL_1 | MEDIAIP_TRACE_DISPLAY)
+
+#define ENCODER_TL_CATASTROPHE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ANY)
+#define ENCODER_TL_SEVERE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ENCODER)
+#define ENCODER_TL_ERROR (MEDIAIP_TRACE_LEVEL_6 | MEDIAIP_TRACE_ENCODER)
+#define ENCODER_TL_WARNING (MEDIAIP_TRACE_LEVEL_5 | MEDIAIP_TRACE_ENCODER)
+#define ENCODER_TL_FUNC (MEDIAIP_TRACE_LEVEL_4 | MEDIAIP_TRACE_ENCODER)
+#define ENCODER_TL_INFO (MEDIAIP_TRACE_LEVEL_3 | MEDIAIP_TRACE_ENCODER)
+#define ENCODER_TL_VERBOSE (MEDIAIP_TRACE_LEVEL_2 | MEDIAIP_TRACE_ENCODER)
+#define ENCODER_TL_DEBUG (MEDIAIP_TRACE_LEVEL_1 | MEDIAIP_TRACE_ENCODER)
+
+#define HANDLE_TL_CATASTROPHE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ANY)
+#define HANDLE_TL_SEVERE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_HANDLE)
+#define HANDLE_TL_ERROR (MEDIAIP_TRACE_LEVEL_6 | MEDIAIP_TRACE_HANDLE)
+#define HANDLE_TL_WARNING (MEDIAIP_TRACE_LEVEL_5 | MEDIAIP_TRACE_HANDLE)
+#define HANDLE_TL_FUNC (MEDIAIP_TRACE_LEVEL_4 | MEDIAIP_TRACE_HANDLE)
+#define HANDLE_TL_INFO (MEDIAIP_TRACE_LEVEL_3 | MEDIAIP_TRACE_HANDLE)
+#define HANDLE_TL_VERBOSE (MEDIAIP_TRACE_LEVEL_2 | MEDIAIP_TRACE_HANDLE)
+#define HANDLE_TL_DEBUG (MEDIAIP_TRACE_LEVEL_1 | MEDIAIP_TRACE_HANDLE)
+
+#define IMGPORT_TL_CATASTROPHE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ANY)
+#define IMGPORT_TL_SEVERE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_IMGPORT)
+#define IMGPORT_TL_ERROR (MEDIAIP_TRACE_LEVEL_6 | MEDIAIP_TRACE_IMGPORT)
+#define IMGPORT_TL_WARNING (MEDIAIP_TRACE_LEVEL_5 | MEDIAIP_TRACE_IMGPORT)
+#define IMGPORT_TL_FUNC (MEDIAIP_TRACE_LEVEL_4 | MEDIAIP_TRACE_IMGPORT)
+#define IMGPORT_TL_INFO (MEDIAIP_TRACE_LEVEL_3 | MEDIAIP_TRACE_IMGPORT)
+#define IMGPORT_TL_VERBOSE (MEDIAIP_TRACE_LEVEL_2 | MEDIAIP_TRACE_IMGPORT)
+#define IMGPORT_TL_DEBUG (MEDIAIP_TRACE_LEVEL_1 | MEDIAIP_TRACE_IMGPORT)
+
+#define KAL_TL_CATASTROPHE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ANY)
+#define KAL_TL_SEVERE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_KAL)
+#define KAL_TL_ERROR (MEDIAIP_TRACE_LEVEL_6 | MEDIAIP_TRACE_KAL)
+#define KAL_TL_WARNING (MEDIAIP_TRACE_LEVEL_5 | MEDIAIP_TRACE_KAL)
+#define KAL_TL_FUNC (MEDIAIP_TRACE_LEVEL_4 | MEDIAIP_TRACE_KAL)
+#define KAL_TL_INFO (MEDIAIP_TRACE_LEVEL_3 | MEDIAIP_TRACE_KAL)
+#define KAL_TL_VERBOSE (MEDIAIP_TRACE_LEVEL_2 | MEDIAIP_TRACE_KAL)
+#define KAL_TL_DEBUG (MEDIAIP_TRACE_LEVEL_1 | MEDIAIP_TRACE_KAL)
+
+#define PAL_TL_CATASTROPHE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ANY)
+#define PAL_TL_SEVERE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_PAL)
+#define PAL_TL_ERROR (MEDIAIP_TRACE_LEVEL_6 | MEDIAIP_TRACE_PAL)
+#define PAL_TL_WARNING (MEDIAIP_TRACE_LEVEL_5 | MEDIAIP_TRACE_PAL)
+#define PAL_TL_FUNC (MEDIAIP_TRACE_LEVEL_4 | MEDIAIP_TRACE_PAL)
+#define PAL_TL_INFO (MEDIAIP_TRACE_LEVEL_3 | MEDIAIP_TRACE_PAL)
+#define PAL_TL_VERBOSE (MEDIAIP_TRACE_LEVEL_2 | MEDIAIP_TRACE_PAL)
+#define PAL_TL_DEBUG (MEDIAIP_TRACE_LEVEL_1 | MEDIAIP_TRACE_PAL)
+
+#define MEMMOVE_TL_CATASTROPHE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ANY)
+#define MEMMOVE_TL_SEVERE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_MEMMOVE)
+#define MEMMOVE_TL_ERROR (MEDIAIP_TRACE_LEVEL_6 | MEDIAIP_TRACE_MEMMOVE)
+#define MEMMOVE_TL_WARNING (MEDIAIP_TRACE_LEVEL_5 | MEDIAIP_TRACE_MEMMOVE)
+#define MEMMOVE_TL_FUNC (MEDIAIP_TRACE_LEVEL_4 | MEDIAIP_TRACE_MEMMOVE)
+#define MEMMOVE_TL_INFO (MEDIAIP_TRACE_LEVEL_3 | MEDIAIP_TRACE_MEMMOVE)
+#define MEMMOVE_TL_VERBOSE (MEDIAIP_TRACE_LEVEL_2 | MEDIAIP_TRACE_MEMMOVE)
+#define MEMMOVE_TL_DEBUG (MEDIAIP_TRACE_LEVEL_1 | MEDIAIP_TRACE_MEMMOVE)
+
+#define QUEUE_TL_CATASTROPHE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ANY)
+#define QUEUE_TL_SEVERE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_QUEUE)
+#define QUEUE_TL_ERROR (MEDIAIP_TRACE_LEVEL_6 | MEDIAIP_TRACE_QUEUE)
+#define QUEUE_TL_WARNING (MEDIAIP_TRACE_LEVEL_5 | MEDIAIP_TRACE_QUEUE)
+#define QUEUE_TL_FUNC (MEDIAIP_TRACE_LEVEL_4 | MEDIAIP_TRACE_QUEUE)
+#define QUEUE_TL_INFO (MEDIAIP_TRACE_LEVEL_3 | MEDIAIP_TRACE_QUEUE)
+#define QUEUE_TL_VERBOSE (MEDIAIP_TRACE_LEVEL_2 | MEDIAIP_TRACE_QUEUE)
+#define QUEUE_TL_DEBUG (MEDIAIP_TRACE_LEVEL_1 | MEDIAIP_TRACE_QUEUE)
+
+#define VAMUX_TL_CATASTROPHE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ANY)
+#define VAMUX_TL_SEVERE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_VAMUX)
+#define VAMUX_TL_ERROR (MEDIAIP_TRACE_LEVEL_6 | MEDIAIP_TRACE_VAMUX)
+#define VAMUX_TL_WARNING (MEDIAIP_TRACE_LEVEL_5 | MEDIAIP_TRACE_VAMUX)
+#define VAMUX_TL_FUNC (MEDIAIP_TRACE_LEVEL_4 | MEDIAIP_TRACE_VAMUX)
+#define VAMUX_TL_INFO (MEDIAIP_TRACE_LEVEL_3 | MEDIAIP_TRACE_VAMUX)
+#define VAMUX_TL_VERBOSE (MEDIAIP_TRACE_LEVEL_2 | MEDIAIP_TRACE_VAMUX)
+#define VAMUX_TL_DEBUG (MEDIAIP_TRACE_LEVEL_1 | MEDIAIP_TRACE_VAMUX)
+
+#define VIDEO_TL_CATASTROPHE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ANY)
+#define VIDEO_TL_SEVERE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_VIDEO_LAYER)
+#define VIDEO_TL_ERROR (MEDIAIP_TRACE_LEVEL_6 | MEDIAIP_TRACE_VIDEO_LAYER)
+#define VIDEO_TL_WARNING (MEDIAIP_TRACE_LEVEL_5 | MEDIAIP_TRACE_VIDEO_LAYER)
+#define VIDEO_TL_FUNC (MEDIAIP_TRACE_LEVEL_4 | MEDIAIP_TRACE_VIDEO_LAYER)
+#define VIDEO_TL_INFO (MEDIAIP_TRACE_LEVEL_3 | MEDIAIP_TRACE_VIDEO_LAYER)
+#define VIDEO_TL_VERBOSE (MEDIAIP_TRACE_LEVEL_2 | MEDIAIP_TRACE_VIDEO_LAYER)
+#define VIDEO_TL_DEBUG (MEDIAIP_TRACE_LEVEL_1 | MEDIAIP_TRACE_VIDEO_LAYER)
+
+#define SYSTEM_TL_CATASTROPHE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ANY)
+#define SYSTEM_TL_SEVERE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_SYSTEM_LAYER)
+#define SYSTEM_TL_ERROR (MEDIAIP_TRACE_LEVEL_6 | MEDIAIP_TRACE_SYSTEM_LAYER)
+#define SYSTEM_TL_WARNING (MEDIAIP_TRACE_LEVEL_5 | MEDIAIP_TRACE_SYSTEM_LAYER)
+#define SYSTEM_TL_FUNC (MEDIAIP_TRACE_LEVEL_4 | MEDIAIP_TRACE_SYSTEM_LAYER)
+#define SYSTEM_TL_INFO (MEDIAIP_TRACE_LEVEL_3 | MEDIAIP_TRACE_SYSTEM_LAYER)
+#define SYSTEM_TL_VERBOSE (MEDIAIP_TRACE_LEVEL_2 | MEDIAIP_TRACE_SYSTEM_LAYER)
+#define SYSTEM_TL_DEBUG (MEDIAIP_TRACE_LEVEL_1 | MEDIAIP_TRACE_SYSTEM_LAYER)
+
+#define PROC_TL_CATASTROPHE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ANY)
+#define PROC_TL_SEVERE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_PROC_LAYER)
+#define PROC_TL_ERROR (MEDIAIP_TRACE_LEVEL_6 | MEDIAIP_TRACE_PROC_LAYER)
+#define PROC_TL_WARNING (MEDIAIP_TRACE_LEVEL_5 | MEDIAIP_TRACE_PROC_LAYER)
+#define PROC_TL_FUNC (MEDIAIP_TRACE_LEVEL_4 | MEDIAIP_TRACE_PROC_LAYER)
+#define PROC_TL_INFO (MEDIAIP_TRACE_LEVEL_3 | MEDIAIP_TRACE_PROC_LAYER)
+#define PROC_TL_VERBOSE (MEDIAIP_TRACE_LEVEL_2 | MEDIAIP_TRACE_PROC_LAYER)
+#define PROC_TL_DEBUG (MEDIAIP_TRACE_LEVEL_1 | MEDIAIP_TRACE_PROC_LAYER)
+
+#define API_TL_CATASTROPHE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ANY)
+#define API_TL_SEVERE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_API_LAYER)
+#define API_TL_ERROR (MEDIAIP_TRACE_LEVEL_6 | MEDIAIP_TRACE_API_LAYER)
+#define API_TL_WARNING (MEDIAIP_TRACE_LEVEL_5 | MEDIAIP_TRACE_API_LAYER)
+#define API_TL_FUNC (MEDIAIP_TRACE_LEVEL_4 | MEDIAIP_TRACE_API_LAYER)
+#define API_TL_INFO (MEDIAIP_TRACE_LEVEL_3 | MEDIAIP_TRACE_API_LAYER)
+#define API_TL_VERBOSE (MEDIAIP_TRACE_LEVEL_2 | MEDIAIP_TRACE_API_LAYER)
+#define API_TL_DEBUG (MEDIAIP_TRACE_LEVEL_1 | MEDIAIP_TRACE_API_LAYER)
+
+#define APP_TL_CATASTROPHE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ANY)
+#define APP_TL_SEVERE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_APPLICATION)
+#define APP_TL_ERROR (MEDIAIP_TRACE_LEVEL_6 | MEDIAIP_TRACE_APPLICATION)
+#define APP_TL_WARNING (MEDIAIP_TRACE_LEVEL_5 | MEDIAIP_TRACE_APPLICATION)
+#define APP_TL_FUNC (MEDIAIP_TRACE_LEVEL_4 | MEDIAIP_TRACE_APPLICATION)
+#define APP_TL_INFO (MEDIAIP_TRACE_LEVEL_3 | MEDIAIP_TRACE_APPLICATION)
+#define APP_TL_VERBOSE (MEDIAIP_TRACE_LEVEL_2 | MEDIAIP_TRACE_APPLICATION)
+#define APP_TL_DEBUG (MEDIAIP_TRACE_LEVEL_1 | MEDIAIP_TRACE_APPLICATION)
+
+#define TEST_TL_CATASTROPHE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_ANY)
+#define TEST_TL_SEVERE (MEDIAIP_TRACE_LEVEL_ALWAYS | MEDIAIP_TRACE_TEST)
+#define TEST_TL_ERROR (MEDIAIP_TRACE_LEVEL_6 | MEDIAIP_TRACE_TEST)
+#define TEST_TL_WARNING (MEDIAIP_TRACE_LEVEL_5 | MEDIAIP_TRACE_TEST)
+#define TEST_TL_FUNC (MEDIAIP_TRACE_LEVEL_4 | MEDIAIP_TRACE_TEST)
+#define TEST_TL_INFO (MEDIAIP_TRACE_LEVEL_3 | MEDIAIP_TRACE_TEST)
+#define TEST_TL_VERBOSE (MEDIAIP_TRACE_LEVEL_2 | MEDIAIP_TRACE_TEST)
+#define TEST_TL_DEBUG (MEDIAIP_TRACE_LEVEL_1 | MEDIAIP_TRACE_TEST)
+
+#if RTOS != NONE
+#if OSAL == CNXT_KAL
+
+typedef MEDIAIP_TRACE_FLAGS CNXT_TRACE_FLAGS;
+
+#endif /* OSAL == CNXT_KAL */
+#endif /* RTOS != NOOS */
+
+#endif /* _TRACE_TYPES_H_ */
+
+
+/* End of file */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/PAL/Incl/pal_linux_map.h b/drivers/mxc/vpu-malone/Malone_Firmware/PAL/Incl/pal_linux_map.h
new file mode 100755
index 000000000000..8e6563091809
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/PAL/Incl/pal_linux_map.h
@@ -0,0 +1,149 @@
+/***********************************************
+ * Copyright (c) 2015 Amphion Semiconductor Ltd *
+ ***********************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+ *
+ * Filename: pal_linux_map.h
+ * Description: Maps the abstraction layer type from the
+ * PAL to Linux defines, though a variation of CNXT KAL
+ * for implementing NXP PAL implementaiton layer
+ * Author: Media IP FW team (Belfast)
+ *
+ ******************************************************************************
+ * $Id:
+ ******************************************************************************/
+
+/* Note : At the moment I have done no real comparison and merge of the
+ different abstarction layers supported in the PAL layer so this
+ file is simply a direct map - currently its only ftn is to
+ remove compiler warnings and to get the code structure correct for
+ the future
+*/
+
+#ifndef _PAL_LINUX_MAP_H_
+#define _PAL_LINUX_MAP_H_
+
+#include "status_codes.h"
+
+/*******************/
+/* Resource Limits */
+/*******************/
+
+#if 0
+/* Maximum length of an OS object name string */
+#define PAL_MAX_OBJ_NAME_LENGTH CNXT_KAL_MAX_OBJ_NAME_LENGTH
+#endif
+
+#define PAL_NO_WAIT 0
+#define PAL_WAIT_FOREVER ((u_int32)-1)
+
+#if 0
+/* Macro to assign task priority based on RTOS */
+#define PAL_THREAD_PRIO(Prio, UCOS_Prio) CNXT_KAL_THREAD_PRIO(Prio, UCOS_Prio)
+
+/* Task Priority Limits. */
+#define PAL_DEFAULT_PRIORITY CNXT_KAL_DEFAULT_PRIORITY
+#define PAL_MAX_THREAD_PRIORITY CNXT_KAL_MAX_THREAD_PRIORITY
+#define PAL_MIN_THREAD_PRIORITY CNXT_KAL_MIN_THREAD_PRIORITY
+#endif
+
+/* Object identifiers, KAL originated */
+typedef u_int32 CNXT_QUEUE_ID;
+typedef u_int32 CNXT_THREAD_ID;
+typedef u_int32 CNXT_SEM_ID;
+typedef u_int32 CNXT_MUTEX_ID;
+typedef u_int32 CNXT_POOL_ID;
+typedef u_int16 CNXT_EVENTS;
+typedef u_int32 CNXT_TICK_ID;
+typedef u_int32 CNXT_TIMER_ID;
+typedef bool CNXT_CRIT_STATE;
+
+#define PAL_QUEUE_ID CNXT_QUEUE_ID
+#define PAL_THREAD_ID CNXT_THREAD_ID
+#define PAL_SEM_ID CNXT_SEM_ID
+#define PAL_POOL_ID CNXT_POOL_ID
+#define PAL_EVENTS CNXT_EVENTS
+#define PAL_TICK_ID CNXT_TICK_ID
+#define PAL_TIMER_ID CNXT_TIMER_ID
+#define PAL_CRIT_STATE CNXT_CRIT_STATE
+
+
+typedef enum
+{
+ PAL_CB_LOW_PRIORITY,
+ PAL_CB_LOW_PRIORITY_NO_BLOCK,
+ PAL_CB_HIGH_PRIORITY,
+ PAL_CB_HIGH_PRIORITY_NO_BLOCK,
+ PAL_CB_PRIORITY_LAST = PAL_CB_HIGH_PRIORITY_NO_BLOCK
+} PAL_CB_PRIORITY;
+
+#define PAL_PFNTHREAD PFNTHREAD
+#define PAL_PFNISR PFNISR
+#define PAL_PFNTHREADCALLBACK PFNTHREADCALLBACK
+typedef void (*PFNTHREAD)(int, void **);
+typedef MEDIAIP_FW_STATUS (*PFNISR)(u_int32);
+typedef void (*PFNTHREADCALLBACK)(u_int32, u_int32, void *);
+
+
+
+
+
+/*****************************************************************/
+/** PAL functions exporting OS abstraction layer functionality **/
+/*****************************************************************/
+
+MEDIAIP_FW_STATUS pal_thread_create ( PAL_PFNTHREAD pfnEntryPoint,
+ int nArgC,
+ void **ppArgV,
+ u_int32 uStackSize,
+ u_int8 uPrio,
+ const char *pszName,
+ PAL_THREAD_ID *pId );
+
+MEDIAIP_FW_STATUS pal_thread_terminate ( PAL_THREAD_ID *pId );
+
+MEDIAIP_FW_STATUS pal_make_async_thread_callback (
+ PAL_PFNTHREADCALLBACK pfnCallback,
+ PAL_CB_PRIORITY Priority,
+ u_int32 uParam1,
+ u_int32 uParam2,
+ void *pData );
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Semaphore functions
+////////////////////////////////////////////////////////////////////////////////
+
+MEDIAIP_FW_STATUS pal_sem_create ( u_int32 uInitialValue,
+ const char *pszName,
+ PAL_SEM_ID *pSem);
+
+////////////////////////////////////////////////////////////////////////////////
+// Queue functions
+////////////////////////////////////////////////////////////////////////////////
+
+MEDIAIP_FW_STATUS pal_qu_create ( unsigned int nMaxElements,
+ const char *pszName,
+ PAL_QUEUE_ID *pQuId );
+
+MEDIAIP_FW_STATUS pal_qu_destroy ( PAL_QUEUE_ID QuId );
+
+MEDIAIP_FW_STATUS pal_qu_send ( PAL_QUEUE_ID QuId,
+ void *pMessage );
+
+MEDIAIP_FW_STATUS pal_qu_receive ( PAL_QUEUE_ID QuId,
+ u_int32 uTimeoutMs,
+ void *pMessage );
+
+
+#endif /* _PAL_CNXT_KAL_MAP_H_ */
+
+/* End of File */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/PAL/Incl/pal_types.h b/drivers/mxc/vpu-malone/Malone_Firmware/PAL/Incl/pal_types.h
new file mode 100755
index 000000000000..0177427fa590
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/PAL/Incl/pal_types.h
@@ -0,0 +1,170 @@
+/***************************************************
+ Copyright (c) 2015 Amphion Semiconductor Ltd
+ All rights reserved.
+ ***************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+
+ Filename: pal_types.h
+ Description: Public header file for PAL type definitions
+ Common between all platforms
+ Author: Media IP FW team (Belfast)
+
+ ****************************************************/
+
+#ifndef _PAL_TYPES_H_
+#define _PAL_TYPES_H_
+
+/////////////////////////////////////////////////////////////////////////////////
+// Header Files
+/////////////////////////////////////////////////////////////////////////////////
+
+#include "basetype.h"
+#include "status_codes.h"
+#include "trace_types.h"
+
+/////////////////////////////////////////////////////////////////////////////////
+// Macros
+/////////////////////////////////////////////////////////////////////////////////
+
+// Define the magic cookie
+#define PAL_CONFIG_MAGIC 0x434C4150 // "PALC", little endian
+
+// Values for pal_trace_destination
+#define PAL_TRACE_TO_DEVNULL 0
+#define PAL_TRACE_TO_UART 1
+#define PAL_TRACE_TO_MESSAGE 2
+#define PAL_TRACE_TO_CIRCULARBUF 3
+
+#if ( TARGET_PLATFORM == GENTB_PLATFORM ) || ( TARGET_PLATFORM == WIN_LIB ) || ( TARGET_PLATFORM == GEN_TB_ENC )
+
+#define PAL_CONFIG_MAX_IRQS 0x12
+#define PAL_CONFIG_MAX_MALONES 0x2
+#define PAL_CONFIG_MAX_WINDSORS 0x1
+#define PAL_CONFIG_MAX_TIMER_IRQS 0x4
+#define PAL_CONFIG_MAX_TIMER_SLOTS 0x4
+
+/* Define the entry locations in the irq vector */
+#define PAL_IRQ_MALONE0_LOW 0x0
+#define PAL_IRQ_MALONE0_HI 0x1
+#define PAL_IRQ_MALONE1_LOW 0x2
+#define PAL_IRQ_MALONE1_HI 0x3
+#define PAL_IRQ_WINDSOR_LOW 0x4
+#define PAL_IRQ_WINDSOR_HI 0x5
+#define PAL_IRQ_HOST_CMD_LO 0x6
+#define PAL_IRQ_HOST_CMD_HI 0x7
+#define PAL_IRQ_HOST_MSG 0x9
+#define PAL_IRQ_DPV 0xA
+#define PAL_IRQ_TIMER_0 0xE
+#define PAL_IRQ_TIMER_1 0xF
+#define PAL_IRQ_TIMER_2 0x10
+#define PAL_IRQ_TIMER_3 0x11
+
+#else
+
+#define PAL_CONFIG_MAX_INITS 4 // Number of init slots
+#define PAL_CONFIG_MAX_IRQS 2 // Number of incoming irq lines supported
+
+#endif /* TARGET_PLATFORM == TB_PLATFORM */
+
+/////////////////////////////////////////////////////////////////////////////////
+// Structure definitions
+/////////////////////////////////////////////////////////////////////////////////
+
+#if OSAL == NO_AL
+/* Function pointer types */
+typedef u_int32 PAL_TIMER_ID;
+typedef u_int32 PAL_CRIT_STATE;
+
+typedef MEDIAIP_IRQ_RETCODE (*PAL_PFNISR)(u_int32);
+typedef void (*PAL_PFNTIMER)(PAL_TIMER_ID, void *);
+
+#endif
+
+typedef u_int32 PAL_PERF_ID;
+
+/////////////////////////////////////////////////////////////////////////////////
+// PAL Configuration structure
+
+#if ( TARGET_PLATFORM == GENTB_PLATFORM ) || ( TARGET_PLATFORM == WIN_LIB ) || ( TARGET_PLATFORM == GEN_TB_ENC )
+
+typedef struct _PALConfig
+{
+ u_int32 uPalConfigMagicCookie;
+
+ u_int32 uGICBaseAddr;
+ u_int32 uIrqLines[PAL_CONFIG_MAX_IRQS];
+ u_int32 uIrqTarget[PAL_CONFIG_MAX_IRQS];
+
+ u_int32 uUartBaseAddr;
+
+ u_int32 uSysClkFreq;
+ u_int32 uNumTimers;
+ u_int32 uTimerBaseAddr;
+ u_int32 uTimerSlots[PAL_CONFIG_MAX_TIMER_SLOTS];
+
+ /* Do we need this in the PAL config? Only for checking mmu setup */
+ /* perhaps - otherwise its more naturtal home is in the DECLIB_CFG */
+ /* structure */
+ u_int32 uNumMalones;
+ u_int32 uMaloneBaseAddr[PAL_CONFIG_MAX_MALONES];
+ u_int32 uHifOffset[PAL_CONFIG_MAX_MALONES];
+
+ u_int32 uNumWindsors;
+ u_int32 uWindsorBaseAddr[PAL_CONFIG_MAX_WINDSORS];
+
+ u_int32 uDPVBaseAddr;
+ u_int32 uPixIfAddr;
+
+ u_int32 pal_trace_level;
+// u_int32 pal_trace_destination;
+// u_int32 pal_trace_CBDescAddr[3]; // 3 separate circular buffers for PAL_TRACE_TO_CIRCULARBUF
+ // 0: normal 1: irq 2: fiq
+ u_int32 uHeapBase;
+ u_int32 uHeapSize;
+
+ u_int32 uFSLCacheBaseAddr;
+
+} sPALConfig, *psPALConfig;
+
+#else
+
+typedef struct _PALConfig
+{
+ u_int32 pal_config_magic_cookie;
+ u_int32 cmd_irq_line[PAL_CONFIG_MAX_IRQS];
+ u_int32 cmd_irq_clear_addr[PAL_CONFIG_MAX_INITS];
+ u_int32 cmd_irq_clear_mask[PAL_CONFIG_MAX_INITS];
+ u_int32 cmd_irq_clear_val[PAL_CONFIG_MAX_INITS];
+ u_int32 msg_irq_init_addr[PAL_CONFIG_MAX_INITS];
+ u_int32 msg_irq_init_mask[PAL_CONFIG_MAX_INITS];
+ u_int32 msg_irq_init_val[PAL_CONFIG_MAX_INITS];
+ u_int32 msg_irq_raise_addr;
+ u_int32 msg_irq_raise_mask;
+ u_int32 msg_irq_raise_val;
+ u_int32 uart_init_addr[PAL_CONFIG_MAX_INITS];
+ u_int32 uart_init_mask[PAL_CONFIG_MAX_INITS];
+ u_int32 uart_init_val[PAL_CONFIG_MAX_INITS];
+ u_int32 uart_check_addr;
+ u_int32 uart_check_mask;
+ u_int32 uart_check_val;
+ u_int32 uart_put_addr;
+ u_int32 pal_trace_level;
+ u_int32 pal_trace_destination;
+ MEDIAIP_TRACE_FLAGS pal_trace_flags; // Currently 5 words
+ u_int32 pal_trace_CBDescAddr[3]; // 3 separate circular buffers for PAL_TRACE_TO_CIRCULARBUF
+ // 0: normal 1: irq 2: fiq
+} sPALConfig, *psPALConfig;
+
+#endif /* TARGET_PLATFORM == TB_PLATFORM */
+
+
+#endif /* _PAL_TYPES_H_ */
+
+
+/* End of File */
diff --git a/drivers/mxc/vpu-malone/Malone_Firmware/PAL/pal.c b/drivers/mxc/vpu-malone/Malone_Firmware/PAL/pal.c
new file mode 100755
index 000000000000..d75db10b5606
--- /dev/null
+++ b/drivers/mxc/vpu-malone/Malone_Firmware/PAL/pal.c
@@ -0,0 +1,780 @@
+/***************************************************
+ * Copyright (c) 2015 Amphion Semiconductor Ltd
+ * All rights reserved.
+ ****************************************************
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ ****************************************************
+ *
+ * Filename : pal.c
+ * Description : Code implementing Platform Abstraction Layer
+ *
+ * Author : Media IP FW team (Belfast)
+ *
+ ****************************************************/
+
+/////////////////////////////////////////////////////////////////////////////////
+//// Header Files
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef VPU_KERNEL_BUILD
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/errno.h>
+#include "VPU_io.h"
+#else
+#undef ARM
+#undef SUCCESS
+#include <linux/io.h>
+#include <linux/kfifo.h>
+#include <linux/kthread.h>
+
+#endif
+#include "pal.h"
+#include "VPU_regdef.h"
+#include "VPU_debug.h"
+#include "mvd.h"
+
+
+///////////////////////////////////////////////////////////////////////////////////
+//// External Function Prototypes
+///////////////////////////////////////////////////////////////////////////////////
+
+// The function declared in pal.h is set to be empty
+// and need to be defined later
+
+//volatile u_int32 guPlayerFlag[MEDIA_PLAYER_NUM_STREAMS];
+
+#ifdef VPU_KERNEL_BUILD
+extern void __iomem *vpu_base;
+#define VPU_REG_WR(reg, val) writel(val, vpu_base + reg)
+#define VPU_REG_RD(reg) readl(vpu_base + reg)
+#else
+#define VPU_REG_WR(reg, val) VpuWriteReg(reg, val)
+#define VPU_REG_RD(reg) VpuReadReg(reg)
+#endif
+
+PAL_PFNISR int_handlers[INT_ID_MAX];
+
+#ifdef ENABLE_CRIT_SECTIONS
+static int ulCriticalNesting = 0;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Assert function, implementation to be defined but we want to use this to trap logical errors
+//
+bool gbAssertExit = FALSE;
+void pal_assert_impl(u_int32 uAssertPC, u_int32 uAssertInfo)
+{
+ /* AssertInfo could be the offset address of the calling function or something else? */
+ while(gbAssertExit==FALSE)
+ {
+ /* wait to allow debug */
+ }
+}
+
+
+MEDIAIP_FW_STATUS pal_critical_section_begin ( PAL_CRIT_STATE *pState )
+{
+#ifdef ENABLE_CRIT_SECTIONS
+ //ENTER_FUNC();
+ if(ulCriticalNesting>0)
+ dprintf(LVL_FUNC, "Nested %d\n", ulCriticalNesting);
+ // FIXME: might need MFD_HIF_MSD_REG_HOST_INTERRUPT_ENABLE 0x1000
+ *pState = VPU_REG_RD((DEC_MFD_XREG_SLV_BASE + MFD_HIF + MFD_HIF_MSD_REG_FAST_INTERRUPT_ENABLE));
+ VPU_REG_WR((DEC_MFD_XREG_SLV_BASE + MFD_HIF + MFD_HIF_MSD_REG_FAST_INTERRUPT_ENABLE), *pState & ~0x20);
+ //dprintf(LVL_FUNC, "save to State 0x%lx, expect 0x20 outside irq or 0 inside irq\n", *pState);
+ ulCriticalNesting++;
+#endif
+
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_critical_section_end ( PAL_CRIT_STATE PreviousState )
+{
+#ifdef ENABLE_CRIT_SECTIONS
+ ulCriticalNesting--;
+ //ENTER_FUNC();
+ //dprintf(LVL_FUNC, "Nest %d\n", ulCriticalNesting);
+ //dprintf(LVL_FUNC, "restore from State 0x%lx, expect 0x20 outside irq or 0 inside irq\n", PreviousState);
+ VPU_REG_WR((DEC_MFD_XREG_SLV_BASE + MFD_HIF + MFD_HIF_MSD_REG_FAST_INTERRUPT_ENABLE), PreviousState);
+#endif
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_int_register ( u_int32 dwIntID,
+ PAL_PFNISR pfnHandler,
+ BOOL bFIQ )
+{
+ ENTER_FUNC();
+ if (pfnHandler == NULL)
+ return MEDIAIP_FW_STATUS_BAD_PARAMETER;
+
+ if (dwIntID == PAL_IRQ_MALONE0_LOW) {
+ int_handlers[INT_ID_MALONE_LOW] = pfnHandler;
+ } else if (dwIntID == PAL_IRQ_MALONE0_HI) {
+ int_handlers[INT_ID_MALONE_HI] = pfnHandler;
+ } else {
+ err_msg("wrong dwIntID 0x%x\n", dwIntID);
+ return MEDIAIP_FW_STATUS_INT_NOT_HANDLED;
+ }
+ dprintf(LVL_FUNC, "pal pfnHandler 0x%p\n", pfnHandler);
+
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+
+MEDIAIP_FW_STATUS pal_int_enable ( u_int32 dwIntID )
+{
+ ENTER_FUNC();
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+void pal_int_set ( u_int32 dwIntID )
+{
+ ENTER_FUNC();
+ dprintf(LVL_FUNC, "dwIntID %d\n", dwIntID);
+
+ if (dwIntID != PAL_IRQ_MALONE0_LOW) {
+ err_msg("ERROR: not PAL_IRQ_MALONE0_LOW!!!\n");
+ EXIT_FUNC();
+ return;
+ }
+
+ VPU_REG_WR((DEC_MFD_XREG_SLV_BASE + MFD_SIF + MFD_SIF_INTR_FORCE), 0x100);
+
+ EXIT_FUNC();
+}
+
+void pal_int_clear ( u_int32 dwIntID,
+ BOOL bDirect )
+{
+ ENTER_FUNC();
+}
+
+MEDIAIP_FW_STATUS pal_int_get_irq_line ( u_int32 uFWIrq,
+ u_int32 *puIrqLine )
+{
+ ENTER_FUNC();
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_memcpy ( void *pDest,
+ const void *pSrc,
+ u_int32 uSize )
+{
+ ENTER_FUNC();
+ if (pDest == NULL || pSrc == NULL)
+ return MEDIAIP_FW_STATUS_BAD_PARAMETER;
+
+ memcpy(pDest, pSrc, uSize);
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+void pal_memset ( void *pDest, int32 nChar, u_int32 uCount )
+{
+ ENTER_FUNC();
+ dprintf(LVL_FUNC, "pDest 0x%p, nChar %d, uCount %d\n", pDest, nChar, uCount);
+ if (pDest == NULL)
+ return;
+
+ memset(pDest, nChar, uCount);
+}
+
+BOOL pal_memcompare ( void *pArea1, void *pArea2, u_int32 uSizeInWords )
+{
+ u_int32 i;
+ u_int32 *ptr0, *ptr1;
+ u_int32 uChange;
+
+ ENTER_FUNC();
+ if (pArea1 == NULL || pArea2 == NULL)
+ return FALSE;
+
+ ptr0 = ( u_int32 * ) pArea1;
+ ptr1 = ( u_int32 * ) pArea2;
+
+ for ( i = 0, uChange = 0; ( i < uSizeInWords ) && ( uChange == 0 ); i++ )
+ {
+ if ( ptr0[i] != ptr1[i] )
+ {
+ uChange = 1;
+ }
+ }
+
+ return ( uChange ) ? TRUE : FALSE;
+}
+
+MEDIAIP_FW_STATUS pal_timer_create ( PAL_PFNTIMER pfnCallback,
+ void * pUserData,
+ PAL_TIMER_ID * pTimer )
+{
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_timer_destroy( PAL_TIMER_ID Timer )
+{
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: pal_memalloc //
+// //
+// DESCRIPTION: //
+// allocates size bytes and returns a pointer to the allocated memory. //
+// The memory is not cleared. //
+// //
+// INPUT PARAMETERS: //
+// uSize - Size of memory in bytes to alloc //
+// //
+// OUTPUT PARAMETERS: //
+// //
+// RETURN VALUES: //
+// //
+// NOTES: //
+// //
+// CONTEXT: //
+// This function may be called from any context //
+// //
+////////////////////////////////////////////////////////////////////////////////
+#ifndef VPU_KERNEL_BUILD
+
+void * pal_memalloc ( size_t uSize )
+{
+ void * pPtr = malloc ( uSize );
+
+ return pPtr;
+}
+#endif
+////////////////////////////////////////////////////////////////////////////////
+// FUNCTION: pal_memfree //
+// //
+// DESCRIPTION: //
+// frees the memory space pointed to by ptr, which must have been //
+// returned by a previous call to malloc(), calloc() or realloc(). //
+// Otherwise, or if free(ptr) has already been called before, undefined //
+// behaviour occurs. If ptr is NULL, no operation is performed. //
+// //
+// //
+// INPUT PARAMETERS: //
+// pPtr - Pointer to memory to free //
+// //
+// OUTPUT PARAMETERS: //
+// //
+// RETURN VALUES: //
+// //
+// NOTES: //
+// //
+// CONTEXT: //
+// This function may be called from any context //
+// //
+////////////////////////////////////////////////////////////////////////////////
+#ifndef VPU_KERNEL_BUILD
+
+void pal_memfree ( void * pPtr )
+{
+ free ( pPtr );
+}
+#endif
+u_int32 pal_find_highest_bit ( u_int32 uValue )
+{
+ u_int32 mask = 0x80000000;
+ u_int32 ret = 31;
+
+ ENTER_FUNC();
+
+ while (mask && ((uValue & mask) == 0)) {
+ mask >>= 1;
+ ret--;
+ }
+
+ return ret;
+}
+
+MEDIAIP_FW_STATUS pal_perf_counter_create ( const char * pszName,
+ PAL_PERF_ID * pPCId )
+{
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_perf_counter_destroy ( PAL_PERF_ID PCId )
+{
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_perf_counter_start ( PAL_PERF_ID PCId )
+{
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+
+MEDIAIP_FW_STATUS pal_perf_counter_pause_control ( PAL_PERF_ID PCId , bool bStartPause)
+{
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_perf_counter_read ( PAL_PERF_ID PerfId,
+ u_int32 * puCountVal )
+{
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_malone_clock_reg_init ( void )
+{
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+static void mfd_clock_enable(unsigned int mask, bool bEnable)
+{
+ if (bEnable)
+ VPU_REG_WR((DEC_MFD_XREG_SLV_BASE + MFD_BLK_CTRL + MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_SET), mask);
+ else
+ VPU_REG_WR((DEC_MFD_XREG_SLV_BASE + MFD_BLK_CTRL + MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_CLR), mask);
+}
+
+MEDIAIP_FW_STATUS pal_malone_clock_enable_common ( bool bEnable )
+{
+ ENTER_FUNC();
+ mfd_clock_enable(0x10, bEnable);
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_malone_clock_enable_avc ( bool bEnable )
+{
+ ENTER_FUNC();
+ mfd_clock_enable(0x1, bEnable);
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_malone_clock_enable_vc1 ( bool bEnable )
+{
+ ENTER_FUNC();
+ mfd_clock_enable(0x2, bEnable);
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_malone_clock_enable_mpg ( bool bEnable )
+{
+ ENTER_FUNC();
+ mfd_clock_enable(0x4, bEnable);
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_malone_clock_enable_avs ( bool bEnable )
+{
+ ENTER_FUNC();
+ mfd_clock_enable(0x8, bEnable);
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+u_int32 pal_get_target_version ( void )
+{
+ return 0;
+}
+
+#ifndef VPU_KERNEL_BUILD
+MEDIAIP_FW_STATUS pal_get_phy_buf(psPALMemDesc pbuf)
+{
+ vpu_mem_desc mem_desc = {0};
+ int ret;
+
+ ENTER_FUNC();
+
+ mem_desc.size = pbuf->size;
+ ret = IOGetPhyMem(&mem_desc);
+ if (ret) {
+ err_msg("Unable to obtain physical mem\n");
+ return MEDIAIP_FW_STATUS_RESOURCE_ERROR;
+ }
+
+ if (IOGetVirtMem(&mem_desc) == -1) {
+ err_msg("Unable to obtain virtual mem\n");
+ IOFreePhyMem(&mem_desc);
+ return MEDIAIP_FW_STATUS_RESOURCE_ERROR;
+ }
+
+ pbuf->phy_addr = mem_desc.phy_addr;
+ pbuf->virt_addr = mem_desc.virt_uaddr;
+#ifdef USE_ION
+ pbuf->ion_buf_fd = mem_desc.ion_buf_fd;
+#endif
+
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_free_phy_buf(psPALMemDesc pbuf)
+{
+ vpu_mem_desc mem_desc = {0};
+
+ ENTER_FUNC();
+
+ mem_desc.size = pbuf->size;
+ mem_desc.phy_addr = pbuf->phy_addr;
+ mem_desc.virt_uaddr = pbuf->virt_addr;
+#ifdef USE_ION
+ mem_desc.ion_buf_fd = pbuf->ion_buf_fd;
+#endif
+
+ IOFreeVirtMem(&mem_desc);
+ IOFreePhyMem(&mem_desc);
+
+ return MEDIAIP_FW_STATUS_OK;
+}
+#endif
+
+u_int32 pal_va2pa ( u_int32 * pAddr )
+{
+ /* CAUTION: pAddr shall be physical address already*/
+ dprintf(LVL_FUNC, "pAddr 0x%p shall be physical!!!\n", pAddr);
+ return (u_int32)(uint_addr)pAddr;
+}
+
+u_int32 * pal_return_uncached_addr ( u_int32 * puAddress )
+{
+ dprintf(LVL_FUNC, "puAddress 0x%p\n", puAddress);
+ return puAddress;
+}
+
+u_int32 * pal_return_cacheable_addr ( u_int32 * puAddress )
+{
+ dprintf(LVL_FUNC, "puAddress 0x%p\n", puAddress);
+ return puAddress;
+}
+
+u_int32 pal_read_uncached ( u_int32 * puAddress )
+{
+ dprintf(LVL_FUNC, "puAddress 0x%p\n", puAddress);
+
+ if (puAddress == NULL)
+ return MEDIAIP_FW_STATUS_BAD_PARAMETER;
+
+ return (*puAddress);
+}
+
+int pal_vsnprintf ( char *str, int size, const char *format, va_list args )
+{
+ ENTER_FUNC();
+ return 0;
+}
+
+int pal_sprintf ( char *str, int size, const char *psz_format, ...)
+{
+ ENTER_FUNC();
+ return 0;
+}
+
+static void mfd_cache_clock_enable(unsigned int enable)
+{
+ ENTER_FUNC();
+ VPU_REG_WR((SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_SCB_CLK_ENABLE_SET),enable);
+}
+
+void pal_set_malone_cache ( u_int32 uMalID )
+{
+ ENTER_FUNC();
+ mfd_cache_clock_enable(0xE);
+}
+
+#define MAX_QUEUE_NUM 10
+static PAL_QUEUE_ID gQuId = 0;
+
+MEDIAIP_FW_STATUS pal_sem_create ( u_int32 uInitialValue,
+ const char *pszName,
+ PAL_SEM_ID *pSem)
+{
+ /* CAUTION: if in use */
+ ENTER_FUNC();
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+#ifdef VPU_KERNEL_BUILD
+
+static struct kfifo irq_fifo[MAX_QUEUE_NUM];
+static spinlock_t irq_lock[MAX_QUEUE_NUM];
+static struct task_struct *msg_thread;
+static wait_queue_head_t irq_wq[MAX_QUEUE_NUM];
+
+MEDIAIP_FW_STATUS pal_thread_create ( PAL_PFNTHREAD pfnEntryPoint,
+ int nArgC,
+ void **ppArgV,
+ u_int32 uStackSize,
+ u_int8 uPrio,
+ const char *pszName,
+ PAL_THREAD_ID *pId )
+{
+ typedef int (*INTFUNC)(void *);
+
+ /* CAUTION: shall not enter twice due to global msg_thread */
+ ENTER_FUNC();
+ //struct task_struct *msg_thread;
+ msg_thread = kthread_run((INTFUNC)pfnEntryPoint , NULL, pszName);
+ if(IS_ERR( msg_thread ))
+ return MEDIAIP_FW_STATUS_FAILURE;
+
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_thread_terminate ( PAL_THREAD_ID *pId )
+{
+ ENTER_FUNC();
+
+ kthread_stop(msg_thread);
+
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_qu_create ( unsigned int nMaxElements,
+ const char *pszName,
+ PAL_QUEUE_ID *pQuId )
+{
+ /* CAUTION: message length shall be 4 * sizeof(uint_addr) */
+ ENTER_FUNC();
+ *pQuId = gQuId;
+ spin_lock_init(&irq_lock[*pQuId]);
+ init_waitqueue_head(&irq_wq[*pQuId]);
+ if(kfifo_alloc(&irq_fifo[*pQuId],
+ nMaxElements * 4 * sizeof(uint_addr),
+ GFP_KERNEL))
+ {
+ err_msg("fail to alloc fifo in pal\n");
+ return MEDIAIP_FW_STATUS_FAILURE;
+ }
+
+ gQuId++;
+ if( MAX_QUEUE_NUM == gQuId)
+ gQuId=0;
+ dprintf(LVL_FUNC, "create QuId:%d\n",
+ *pQuId
+ );
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_qu_destroy ( PAL_QUEUE_ID QuId )
+{
+ ENTER_FUNC();
+ dprintf(LVL_FUNC, "destory QuId:%d\n",
+ QuId
+ );
+ kfifo_free(&irq_fifo[QuId]);
+
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_qu_send ( PAL_QUEUE_ID QuId,
+ void *pMessage)
+{
+ u_int32 retval;
+ ENTER_FUNC();
+ dprintf(LVL_FUNC, "QuId %d\n", QuId);
+
+ /* CAUTION: if message is not 4 * sizeof(uint_addr) */
+ retval = kfifo_in_locked(&irq_fifo[QuId], pMessage, 4 * sizeof(uint_addr),&irq_lock[QuId]);
+ dprintf(LVL_FUNC, "message send: 0x%llx, 0x%llx, 0x%llx, 0x%llx\n", *(uint_addr *)pMessage, *((uint_addr *)pMessage+1), *((uint_addr *)pMessage+2), *((uint_addr *)pMessage+3));
+ if(retval != 4*sizeof(uint_addr))
+ return MEDIAIP_FW_STATUS_FAILURE;
+ wake_up(&irq_wq[QuId]);
+
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_qu_receive ( PAL_QUEUE_ID QuId,
+ u_int32 uTimeoutMs,
+ void *pMessage )
+{
+ u_int32 retval;
+ long ret;
+
+ ENTER_FUNC();
+ dprintf(LVL_FUNC, "QuId %d\n", QuId);
+/* while (kfifo_len(&irq_fifo) < sizeof(*pMessage)) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ }*/
+ ret = wait_event_interruptible_timeout(irq_wq[QuId],
+ kfifo_len(&irq_fifo[QuId])>=4*sizeof(uint_addr)
+ /* || kthread_should_stop() */,
+ //uTimeoutMs
+ msecs_to_jiffies(uTimeoutMs)
+ );
+
+ if (ret == 0) {
+ dprintf(LVL_FUNC, "timeout %d ms\n", uTimeoutMs);
+ return MEDIAIP_FW_STATUS_TIMEOUT;
+ } else if (ret == -ERESTARTSYS) {
+ dprintf(LVL_FUNC, "ERROR interrupted by a signal!!\n");
+ return MEDIAIP_FW_STATUS_FAILURE;
+ } else {
+ dprintf(LVL_FUNC, "%ld returned from wait event\n", ret);
+ }
+
+ //if(kthread_should_stop())
+ // return MEDIAIP_FW_STATUS_STOPPED;
+
+ if (kfifo_len(&irq_fifo[QuId])>=4*sizeof(uint_addr))
+ {
+ retval = kfifo_out_locked(&irq_fifo[QuId], pMessage, 4*sizeof(uint_addr),&irq_lock[QuId]);
+ dprintf(LVL_FUNC, "message receive: 0x%llx, 0x%llx, 0x%llx, 0x%llx\n", *(uint_addr *)pMessage, *((uint_addr *)pMessage+1), *((uint_addr *)pMessage+2), *((uint_addr *)pMessage+3));
+ }
+ else
+ {
+ dprintf(LVL_FUNC, "ERROR interrupted by a signal!!\n");
+ }
+
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+#else
+
+#define FN_MSG_FIFO "/dev/shm/vpu_msg_fifo"
+static char fn_fifo[MAX_QUEUE_NUM][64] = {0};
+static int fd_send[MAX_QUEUE_NUM] = {0};
+static int fd_receive[MAX_QUEUE_NUM] = {0};
+
+MEDIAIP_FW_STATUS pal_thread_create ( PAL_PFNTHREAD pfnEntryPoint,
+ int nArgC,
+ void **ppArgV,
+ u_int32 uStackSize,
+ u_int8 uPrio,
+ const char *pszName,
+ PAL_THREAD_ID *pId )
+{
+ int err;
+ pthread_t msg_tid;
+
+ ENTER_FUNC();
+ err = pthread_create(&msg_tid, NULL, (void *)pfnEntryPoint, NULL);
+ if (err)
+ return MEDIAIP_FW_STATUS_FAILURE;
+
+ *pId = msg_tid;
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_thread_terminate ( PAL_THREAD_ID *pId )
+{
+ pthread_t msg_tid = *pId;
+
+ ENTER_FUNC();
+
+ if (msg_tid == 0)
+ return MEDIAIP_FW_STATUS_BAD_PARAMETER;
+
+ pthread_cancel(msg_tid);
+ pthread_join(msg_tid, NULL);
+
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_qu_create ( unsigned int nMaxElements,
+ const char *pszName,
+ PAL_QUEUE_ID *pQuId )
+{
+ /* CAUTION: message length shall be 4 * sizeof(uint_addr) */
+ ENTER_FUNC();
+ *pQuId = gQuId;
+ sprintf(fn_fifo[gQuId], "%s%d", FN_MSG_FIFO, gQuId);
+ if(access(fn_fifo[gQuId], F_OK) == -1)
+ {
+ if(mkfifo(fn_fifo[gQuId], 0777))
+ {
+ err_msg("failed to alloc fifo %s in pal\n", fn_fifo[gQuId]);
+ return MEDIAIP_FW_STATUS_FAILURE;
+ }
+ dprintf(LVL_FUNC, "created fifo %s\n", fn_fifo[gQuId]);
+ } else {
+ dprintf(LVL_FUNC, "exist fifo %s\n", fn_fifo[gQuId]);
+ }
+
+ gQuId++;
+ if( MAX_QUEUE_NUM == gQuId)
+ gQuId=0;
+ dprintf(LVL_FUNC, "create QuId:%d\n",
+ *pQuId
+ );
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_qu_destroy ( PAL_QUEUE_ID QuId )
+{
+ ENTER_FUNC();
+ dprintf(LVL_FUNC, "destory QuId:%d\n",
+ QuId
+ );
+ if (fd_send[QuId]) {
+ close(fd_send[QuId]);
+ fd_send[QuId] = 0;
+ }
+ if (fd_receive[QuId]) {
+ close(fd_receive[QuId]);
+ fd_receive[QuId] = 0;
+ }
+
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_qu_send ( PAL_QUEUE_ID QuId,
+ void *pMessage)
+{
+ u_int32 retval;
+ ENTER_FUNC();
+ dprintf(LVL_FUNC, "QuId %d\n", QuId);
+
+ /* CAUTION: if message is not 4 * sizeof(uint_addr) */
+ if (fd_send[QuId] == 0) {
+ fd_send[QuId] = open(fn_fifo[QuId], O_WRONLY);
+ if (fd_send[QuId] == -1) {
+ err_msg("failed to open fifo %s to send\n", fn_fifo[QuId]);
+ return MEDIAIP_FW_STATUS_FAILURE;
+ } else {
+ dprintf(LVL_FUNC, "opened fifo %s to send\n", fn_fifo[QuId]);
+ }
+ }
+ retval = write(fd_send[QuId], pMessage, 4 * sizeof(uint_addr));
+ if(retval != 4*sizeof(uint_addr))
+ {
+ err_msg("%s\n", strerror(errno));
+ return MEDIAIP_FW_STATUS_FAILURE;
+ }
+ dprintf(LVL_FUNC, "message send: 0x%lx, 0x%lx, 0x%lx, 0x%lx\n", *(uint_addr *)pMessage, *((uint_addr *)pMessage+1), *((uint_addr *)pMessage+2), *((uint_addr *)pMessage+3));
+
+ return MEDIAIP_FW_STATUS_OK;
+}
+
+MEDIAIP_FW_STATUS pal_qu_receive ( PAL_QUEUE_ID QuId,
+ u_int32 uTimeoutMs,
+ void *pMessage )
+{
+ u_int32 retval;
+
+ ENTER_FUNC();
+ dprintf(LVL_FUNC, "QuId %d\n", QuId);
+ // TODO: time out case
+ if (fd_receive[QuId] == 0) {
+ fd_receive[QuId] = open(fn_fifo[QuId], O_RDONLY);
+ if (fd_receive[QuId] == -1) {
+ err_msg("failed to open fifo %s to receive\n", fn_fifo[QuId]);
+ return MEDIAIP_FW_STATUS_FAILURE;
+ } else {
+ dprintf(LVL_FUNC, "opened fifo %s to receive\n", fn_fifo[QuId]);
+ }
+ }
+ retval = read(fd_receive[QuId], pMessage, 4*sizeof(uint_addr));
+ if(retval != 4*sizeof(uint_addr))
+ {
+ err_msg("%s\n", strerror(errno));
+ return MEDIAIP_FW_STATUS_FAILURE;
+ }
+ dprintf(LVL_FUNC, "message receive: 0x%lx, 0x%lx, 0x%lx, 0x%lx\n", *(uint_addr *)pMessage, *((uint_addr *)pMessage+1), *((uint_addr *)pMessage+2), *((uint_addr *)pMessage+3));
+
+ return MEDIAIP_FW_STATUS_OK;
+}
+#endif
+
diff --git a/drivers/mxc/vpu-malone/VPU_debug.h b/drivers/mxc/vpu-malone/VPU_debug.h
new file mode 100755
index 000000000000..1b2fd26c9572
--- /dev/null
+++ b/drivers/mxc/vpu-malone/VPU_debug.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2017 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU Lesser General
+ * Public License. You may obtain a copy of the GNU Lesser General
+ * Public License Version 2.1 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/lgpl-license.html
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+/*!
+ * @file vpu_debug.h
+ *
+ * @brief VPU debug definition
+ *
+ * @ingroup VPU
+ */
+
+#ifndef __VPU_DEBUG_H
+#define __VPU_DEBUG_H
+
+
+
+#define LVL_NOPRINT 0
+#define LVL_ISR 2
+#define LVL_CRI 3
+#define LVL_FUNC 5
+#define LVL_PRINTALL 10
+
+
+
+#ifdef VPU_KERNEL_BUILD
+
+#include <linux/io.h>
+
+//#define vpu_lib_dbg_level LVL_PRINTALL
+
+#define vpu_lib_dbg_level LVL_NOPRINT
+
+#define err_msg(fmt, arg...) do { if (vpu_lib_dbg_level > LVL_NOPRINT) \
+ printk("[ERR]\t%s:%d " fmt, __FILE__, __LINE__, ## arg); else \
+ printk("[ERR]\t" fmt, ## arg); \
+ } while (0)
+#define info_msg(fmt, arg...) do { if (vpu_lib_dbg_level > LVL_NOPRINT) \
+ printk("[INFO]\t%s:%d " fmt, __FILE__, __LINE__, ## arg); else \
+ printk("[INFO]\t" fmt, ## arg); \
+ } while (0)
+#define warn_msg(fmt, arg...) do { if (vpu_lib_dbg_level > LVL_NOPRINT) \
+ printk("[WARN]\t%s:%d " fmt, __FILE__, __LINE__, ## arg); else \
+ printk("[WARN]\t" fmt, ## arg); \
+ } while (0)
+
+#define dprintf(level, fmt, arg...) do {if (level <= vpu_lib_dbg_level) printk("[DEBUG]\t%s " fmt, __FUNCTION__, ## arg);} while(0)
+
+
+
+#define ENTER_FUNC() dprintf(LVL_FUNC, "enter %s()\n", __func__)
+#define EXIT_FUNC() dprintf(LVL_FUNC, "exit %s()\n", __func__)
+
+#else
+
+#include <stdio.h>
+
+#include "VPU_lib.h"
+
+
+//#define vpu_lib_dbg_level LVL_PRINTALL
+
+#define vpu_lib_dbg_level LVL_CRI
+
+#define err_msg(fmt, arg...) do { if (vpu_lib_dbg_level > LVL_NOPRINT) \
+ printf("[ERR]\t%s:%d " fmt, __FILE__, __LINE__, ## arg); else \
+ printf("[ERR]\t" fmt, ## arg); \
+ } while (0)
+#define info_msg(fmt, arg...) do { if (vpu_lib_dbg_level > LVL_NOPRINT) \
+ printf("[INFO]\t%s:%d " fmt, __FILE__, __LINE__, ## arg); else \
+ printf("[INFO]\t" fmt, ## arg); \
+ } while (0)
+#define warn_msg(fmt, arg...) do { if (vpu_lib_dbg_level > LVL_NOPRINT) \
+ printf("[WARN]\t%s:%d " fmt, __FILE__, __LINE__, ## arg); else \
+ printf("[WARN]\t" fmt, ## arg); \
+ } while (0)
+
+//#define dprintf(level, fmt, arg...) do {if (level <= vpu_lib_dbg_level) printf("[DEBUG]\t%s " fmt, __FUNCTION__, ## arg);} while(0)
+#define dprintf(level, fmt, arg...) do { if (vpu_lib_dbg_level >= level) printf("[DEBUG]\t%s:%d " fmt, __FILE__, __LINE__, ## arg); } while (0)
+
+#define ENTER_FUNC() dprintf(LVL_FUNC, "enter %s()\n", __func__)
+#define EXIT_FUNC() dprintf(LVL_FUNC, "exit %s()\n", __func__)
+
+#endif
+
+#endif
diff --git a/drivers/mxc/vpu-malone/VPU_regdef.h b/drivers/mxc/vpu-malone/VPU_regdef.h
new file mode 100755
index 000000000000..4753a900f7a8
--- /dev/null
+++ b/drivers/mxc/vpu-malone/VPU_regdef.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017 NXP
+ */
+
+/* The following programs are the sole property of NXP Semiconductor Inc.,
+ * and contain its proprietary and confidential information. */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// vpu_regdef.h
+//
+// Description:
+//
+// Register definition
+//
+// Authors:
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef __VPU_REGDEF_H__
+#define __VPU_REGDEF_H__
+
+#define SCB_XREG_SLV_BASE 0x00000000
+#define SCB_SCB_BLK_CTRL 0x00070000
+#define SCB_BLK_CTRL_XMEM_RESET_SET 0x00000090
+#define SCB_BLK_CTRL_CACHE_RESET_SET 0x000000A0
+#define SCB_BLK_CTRL_CACHE_RESET_CLR 0x000000A4
+#define SCB_BLK_CTRL_SCB_CLK_ENABLE_SET 0x00000100
+
+#define XMEM_CONTROL 0x00041000
+
+#define DEC_MFD_XREG_SLV_BASE 0x00180000
+
+#define MFD_HIF 0x0001C000
+#define MFD_HIF_MSD_REG_HOST_INTERRUPT_ENABLE 0x00000014
+#define MFD_HIF_MSD_REG_INTERRUPT_STATUS 0x00000018
+#define MFD_HIF_MSD_REG_FAST_INTERRUPT_ENABLE 0x0000001C
+#define MFD_SIF 0x0001D000
+#define MFD_SIF_CTRL_STATUS 0x000000F0
+#define MFD_SIF_INTR_STATUS 0x000000F4
+#define MFD_SIF_INTR_FORCE 0x000000F8
+#define MFD_MCX 0x00020800
+
+#define MFD_BLK_CTRL 0x00030000
+#define MFD_BLK_CTRL_MFD_SYS_RESET_SET 0x00000000
+#define MFD_BLK_CTRL_MFD_SYS_RESET_CLR 0x00000004
+#define MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_SET 0x00000100
+#define MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_CLR 0x00000104
+
+#endif //__VPU_REGDEF_H__
diff --git a/drivers/mxc/vpu-malone/mxc_vpu-malone.c b/drivers/mxc/vpu-malone/mxc_vpu-malone.c
new file mode 100755
index 000000000000..8ce2787e6050
--- /dev/null
+++ b/drivers/mxc/vpu-malone/mxc_vpu-malone.c
@@ -0,0 +1,1344 @@
+/*
+ * Copyright 2017 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file mxc_vpu-malone.c
+ *
+ * @brief VPU system initialization and file operation implementation
+ *
+ * @ingroup VPU
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/stat.h>
+#include <linux/platform_device.h>
+#include <linux/kdev_t.h>
+#include <linux/dma-mapping.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/fsl_devices.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/regulator/consumer.h>
+#include <linux/page-flags.h>
+#include <linux/mm_types.h>
+#include <linux/types.h>
+#include <linux/memblock.h>
+#include <linux/memory.h>
+#include <linux/version.h>
+#include <asm/page.h>
+
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/sizes.h>
+
+#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/genalloc.h>
+#include <linux/mxc_vpu-malone.h>
+#include <linux/of.h>
+#include <linux/reset.h>
+
+#include <soc/imx8/sc/svc/pm/api.h>
+#include <soc/imx8/sc/ipc.h>
+
+#include "VPU_regdef.h"
+#include "pal.h"
+#include "mvd.h"
+#include "DecKernelLib.h"
+
+struct vpu_priv {
+ struct fasync_struct *async_queue;
+ struct work_struct work;
+ struct workqueue_struct *workqueue;
+ struct mutex lock;
+};
+
+/* To track the allocated memory buffer */
+struct memalloc_record {
+ struct list_head list;
+ struct vpu_mem_desc mem;
+};
+
+static LIST_HEAD(head);
+
+static int vpu_major;
+static struct class *vpu_class;
+static struct vpu_priv vpu_data;
+static u8 open_count;
+static struct clk *vpu_clk;
+static struct vpu_mem_desc share_mem = { 0 };
+static struct vpu_mem_desc vshare_mem = { 0 };
+
+void __iomem *vpu_base;
+static u32 phy_vpu_base_addr;
+static int vpu_dec_irq;
+static int vpu_dec_fiq;
+
+static struct device *vpu_dev;
+
+/* implement the blocking ioctl */
+static int irq_status;
+static wait_queue_head_t vpu_queue;
+
+static int vpu_clk_usercount;
+static atomic_t clk_cnt_from_ioc = ATOMIC_INIT(0);
+
+static sc_ipc_t ipcHndl;
+
+#define ISR_EVENT_QU_SIZE 64
+
+static PAL_QUEUE_ID gIsrEventQu;
+static DECODER_KERNEL_LIB_ISR_EVENT_DATA gIsrEventData[ISR_EVENT_QU_SIZE];
+static u32 uIsrEventQuWrIdx = 0;
+static DECODERLIB_KERNEL_CFG gtKernelCfg;
+
+#define READ_REG(x) readl_relaxed(vpu_base + x)
+#define WRITE_REG(val, x) writel_relaxed(val, vpu_base + x)
+
+static void vpu_reset(void)
+{
+#if 0
+ int ret;
+
+ ret = device_reset(vpu_dev);
+#endif
+}
+
+/*!
+ * Private function to change the power mode of VPU to pm
+ * @return status 0 success.
+ */
+static int setVPUPwr(sc_ipc_t ipcHndl,
+ sc_pm_power_mode_t pm
+ )
+{
+ int rv = -1;
+ sc_err_t sciErr;
+
+ dev_dbg(vpu_dev, "enter %s()\n", __FUNCTION__);
+ if (!ipcHndl)
+ {
+ dev_err(vpu_dev, "--- setVPUPwr no IPC handle\n");
+ goto setVPUPwrExit;
+ }
+
+ /* Power on or off PID0, DEC, ENC */
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU, pm);
+ if (sciErr != SC_ERR_NONE)
+ {
+ dev_err(vpu_dev, "--- sc_pm_set_resource_power_mode(SC_R_VPU,%d) SCI error! (%d)\n", pm, sciErr);
+ goto setVPUPwrExit;
+ }
+#if 0
+ /* FIXME: no need of PID1-7? */
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID1, pm);
+ if (sciErr != SC_ERR_NONE)
+ {
+ dev_err(vpu_dev, "--- sc_pm_set_resource_power_mode(SC_R_VPU_PID1,%d) SCI error! (%d)\n", pm, sciErr);
+ goto setVPUPwrExit;
+ }
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl,SC_R_VPU_PID2, pm);
+ if (sciErr != SC_ERR_NONE)
+ {
+ dev_err(vpu_dev, "--- sc_pm_set_resource_power_mode(SC_R_VPU_PID2,%d) SCI error! (%d)\n", pm, sciErr);
+ goto setVPUPwrExit;
+ }
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID3, pm);
+ if (sciErr != SC_ERR_NONE)
+ {
+ dev_err(vpu_dev, "--- sc_pm_set_resource_power_mode(SC_R_VPU_PID3,%d) SCI error! (%d)\n", pm, sciErr);
+ goto setVPUPwrExit;
+ }
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID4, pm);
+ if (sciErr != SC_ERR_NONE)
+ {
+ dev_err(vpu_dev, "--- sc_pm_set_resource_power_mode(SC_R_VPU_PID4,%d) SCI error! (%d)\n", pm, sciErr);
+ goto setVPUPwrExit;
+ }
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID5, pm);
+ if (sciErr != SC_ERR_NONE)
+ {
+ dev_err(vpu_dev, "--- sc_pm_set_resource_power_mode(SC_R_VPU_PID5,%d) SCI error! (%d)\n", pm, sciErr);
+ goto setVPUPwrExit;
+ }
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID6, pm);
+ if (sciErr != SC_ERR_NONE)
+ {
+ dev_err(vpu_dev, "--- sc_pm_set_resource_power_mode(SC_R_VPU_PID6,%d) SCI error! (%d)\n", pm, sciErr);
+ goto setVPUPwrExit;
+ }
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_PID7, pm);
+ if (sciErr != SC_ERR_NONE)
+ {
+ dev_err(vpu_dev, "--- sc_pm_set_resource_power_mode(SC_R_VPU_PID7,%d) SCI error! (%d)\n", pm, sciErr);
+ goto setVPUPwrExit;
+ }
+#endif
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_DEC_0, pm);
+ if (sciErr != SC_ERR_NONE)
+ {
+ dev_err(vpu_dev, "--- sc_pm_set_resource_power_mode(SC_R_VPU_DEC_0,%d) SCI error! (%d)\n", pm, sciErr);
+ goto setVPUPwrExit;
+ }
+ sciErr = sc_pm_set_resource_power_mode(ipcHndl, SC_R_VPU_ENC_0, pm);
+ if (sciErr != SC_ERR_NONE)
+ {
+ dev_err(vpu_dev, "--- sc_pm_set_resource_power_mode(SC_R_VPU_ENC_0,%d) SCI error! (%d)\n", pm, sciErr);
+ goto setVPUPwrExit;
+ }
+
+ rv = 0;
+
+setVPUPwrExit:
+ return (rv);
+}
+
+#if 0
+/*!
+ * Private function to return the power mode of VPU
+ * @return <0 if there were errors.
+ */
+static sc_pm_power_mode_t getVPUPwr(sc_ipc_t ipcHndl)
+{
+ sc_pm_power_mode_t rv = -1;
+ sc_err_t sciErr;
+
+ if (!ipcHndl)
+ {
+ dev_err(vpu_dev, "--- getVPUPwr no IPC handle\n");
+ return (rv);
+ }
+
+ sciErr = sc_pm_get_resource_power_mode(ipcHndl, SC_R_VPU, &rv);
+ if (sciErr != SC_ERR_NONE)
+ {
+ dev_err(vpu_dev, "--- sc_pm_get_resource_power_mode(SC_R_VPU) SCI error! (%d)\n", sciErr);
+ rv = -1;
+ }
+
+ return (rv);
+}
+#endif
+
+static long vpu_power_get(bool on)
+{
+ return 0;
+}
+
+static void vpu_power_up(bool on)
+{
+ int err;
+
+ if (on) {
+ err = setVPUPwr(ipcHndl, SC_PM_PW_MODE_ON);
+ if (err)
+ dev_err(vpu_dev, "failed to power on\n");
+ pm_runtime_get_sync(vpu_dev);
+ /* TODO: before or after clk enable? */
+ clk_set_rate(vpu_clk, 600000000);
+ } else {
+ pm_runtime_put_sync_suspend(vpu_dev);
+ err = setVPUPwr(ipcHndl, SC_PM_PW_MODE_OFF);
+ if (err)
+ dev_err(vpu_dev, "failed to power off\n");
+ }
+}
+
+#define VM_RESERVED 0
+
+/*!
+ * Private function to alloc dma buffer
+ * @return status 0 success.
+ */
+static int vpu_alloc_dma_buffer(struct vpu_mem_desc *mem)
+{
+ mem->cpu_addr = dma_alloc_coherent(vpu_dev, PAGE_ALIGN(mem->size),
+ &mem->phy_addr,
+ GFP_DMA | GFP_KERNEL);
+ dev_dbg(vpu_dev, "[ALLOC] mem alloc cpu_addr = 0x%p\n", mem->cpu_addr);
+ if (mem->cpu_addr == NULL) {
+ dev_err(vpu_dev, "Physical memory allocation error!\n");
+ return -1;
+ }
+ return 0;
+}
+
+/*!
+ * Private function to free dma buffer
+ */
+static void vpu_free_dma_buffer(struct vpu_mem_desc *mem)
+{
+ if (mem->cpu_addr != NULL) {
+ dma_free_coherent(vpu_dev, PAGE_ALIGN(mem->size),
+ mem->cpu_addr, mem->phy_addr);
+ }
+}
+
+/*!
+ * Private function to free buffers
+ * @return status 0 success.
+ */
+static int vpu_free_buffers(void)
+{
+ struct memalloc_record *rec, *n;
+ struct vpu_mem_desc mem;
+
+ list_for_each_entry_safe(rec, n, &head, list) {
+ mem = rec->mem;
+ if (mem.cpu_addr != NULL) {
+ vpu_free_dma_buffer(&mem);
+ dev_dbg(vpu_dev, "[FREE] freed paddr=0x%08llX\n", mem.phy_addr);
+ /* delete from list */
+ list_del(&rec->list);
+ kfree(rec);
+ }
+ }
+
+ return 0;
+}
+
+static inline void vpu_worker_callback(struct work_struct *w)
+{
+ struct vpu_priv *dev = container_of(w, struct vpu_priv,
+ work);
+
+ if (dev->async_queue)
+ kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
+
+ irq_status = 1;
+
+ wake_up_interruptible(&vpu_queue);
+}
+
+#if 0
+/*!
+ * @brief vpu interrupt handler
+ */
+static irqreturn_t vpu_ipi_irq_handler(int irq, void *dev_id)
+{
+ struct vpu_priv *dev = dev_id;
+
+ queue_work(dev->workqueue, &dev->work);
+
+ return IRQ_HANDLED;
+}
+#endif
+
+/*!
+ * @brief vpu fiq handler
+ */
+static irqreturn_t vpu_dec_fiq_handler(int irq, void *dev_id)
+{
+ dev_dbg(vpu_dev, "enter %s\n", __FUNCTION__);
+
+ /* NXP using this bit in pal_int_enable() which is FORCE_EXIT, not hanlded within the ISR routing itself */
+ WRITE_REG(0x100, DEC_MFD_XREG_SLV_BASE + MFD_SIF + MFD_SIF_INTR_STATUS);
+
+ int_handlers[INT_ID_MALONE_LOW](uMvdKernelIrqPin[0][0]);
+
+ return IRQ_HANDLED;
+}
+
+/*!
+ * @brief vpu irq handler
+ */
+static irqreturn_t vpu_dec_irq_handler(int irq, void *dev_id)
+{
+ dev_dbg(vpu_dev, "enter %s\n", __FUNCTION__);
+
+ int_handlers[INT_ID_MALONE_HI](uMvdKernelIrqPin[0][1]);
+
+ return IRQ_HANDLED;
+}
+
+static int vpu_isr_event_qu_init(void)
+{
+ int ret;
+
+ dev_dbg(vpu_dev, "enter %s\n", __FUNCTION__);
+
+ ret = pal_qu_create(ISR_EVENT_QU_SIZE,
+ NULL,
+ &gIsrEventQu);
+
+ return ret;
+}
+
+static int vpu_isr_event_qu_send(DECODER_KERNEL_LIB_ISR_EVENT_DATA *pIsrEventData)
+{
+ int ret;
+ uint_addr ulMsg[4];
+
+ dev_dbg(vpu_dev, "enter %s\n", __FUNCTION__);
+
+ mutex_lock(&vpu_data.lock);
+
+ /* Need to take care of copying over the data */
+ gIsrEventData[uIsrEventQuWrIdx] = *pIsrEventData;
+
+ /* Fill message */
+ ulMsg[0] = (uint_addr)&gIsrEventData[uIsrEventQuWrIdx];
+ ulMsg[1] = 0;
+ ulMsg[2] = 0;
+ ulMsg[3] = 0;
+
+ uIsrEventQuWrIdx++;
+ if (uIsrEventQuWrIdx == ISR_EVENT_QU_SIZE) uIsrEventQuWrIdx = 0;
+
+ ret = pal_qu_send (gIsrEventQu,
+ ulMsg);
+
+ mutex_unlock(&vpu_data.lock);
+
+ dev_dbg(vpu_dev, "leave %s\n", __FUNCTION__);
+ return ret;
+}
+
+static int vpu_isr_event_qu_receive(DECODER_KERNEL_LIB_ISR_EVENT_DATA *pIsrEventData)
+{
+ int ret;
+ uint_addr uMsg[4];
+
+ dev_dbg(vpu_dev, "enter %s\n", __FUNCTION__);
+
+ ret = pal_qu_receive(gIsrEventQu,
+ 1000,
+ uMsg);
+
+ if (ret == MEDIAIP_FW_STATUS_OK)
+ *pIsrEventData = *(DECODER_KERNEL_LIB_ISR_EVENT_DATA *)uMsg[0];
+
+ dev_dbg(vpu_dev, "leave %s\n", __FUNCTION__);
+ return ret;
+}
+
+static int vpu_isr_event_qu_uninit(void)
+{
+ int ret;
+
+ dev_dbg(vpu_dev, "enter %s\n", __FUNCTION__);
+
+ ret = pal_qu_destroy(gIsrEventQu);
+
+ return ret;
+}
+
+static void vpu_isr_event_callback(DECODER_KERNEL_LIB_ISR_EVENT_DATA *ptEventData)
+{
+ int err;
+
+ dev_dbg(vpu_dev, "enter %s\n", __FUNCTION__);
+
+ err = vpu_isr_event_qu_send(ptEventData);
+ if (err)
+ dev_err(vpu_dev, "failed to send isr event\n");
+
+ dev_dbg(vpu_dev, "leave %s\n", __FUNCTION__);
+}
+
+static void vpu_set_kernel_cfg(pDECODERLIB_KERNEL_CFG ptKernelCfg)
+{
+ ptKernelCfg->uNumMalones = 1;
+
+ ptKernelCfg->uMaloneBaseAddr[0] = (uint_addr)(vpu_base + 0x180000);
+ ptKernelCfg->uMaloneHifOffset[0] = 0x1C000;
+
+ /* Pass Decoder a PAL index, not an actual GIC position */
+ /* The PAL will take care of the rest */
+ ptKernelCfg->uMaloneIrqPin[0][0x0] = PAL_IRQ_MALONE0_LOW;
+ ptKernelCfg->uMaloneIrqPin[0][0x1] = PAL_IRQ_MALONE0_HI;
+
+ ptKernelCfg->uDPVBaseAddr = 0;
+ ptKernelCfg->uDPVIrqPin = 0;
+}
+
+static void vpu_prepare(void)
+{
+ dev_dbg(vpu_dev, "enter %s\n", __FUNCTION__);
+
+ WRITE_REG(0x1, SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_SCB_CLK_ENABLE_SET);
+ WRITE_REG(0xffffffff, SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_XMEM_RESET_SET);
+
+ WRITE_REG(0xE, SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_SCB_CLK_ENABLE_SET);
+ WRITE_REG(0x7, SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_CACHE_RESET_SET);
+
+ WRITE_REG(0x1f, DEC_MFD_XREG_SLV_BASE + MFD_BLK_CTRL + MFD_BLK_CTRL_MFD_SYS_CLOCK_ENABLE_SET);
+ WRITE_REG(0xffffffff, DEC_MFD_XREG_SLV_BASE + MFD_BLK_CTRL + MFD_BLK_CTRL_MFD_SYS_RESET_SET);
+
+ WRITE_REG(0x102, XMEM_CONTROL);
+}
+
+static void vpu_unprepare(void)
+{
+ dev_dbg(vpu_dev, "enter %s\n", __FUNCTION__);
+
+ WRITE_REG(0x7, SCB_XREG_SLV_BASE + SCB_SCB_BLK_CTRL + SCB_BLK_CTRL_CACHE_RESET_CLR);
+ WRITE_REG(0xffffffff, DEC_MFD_XREG_SLV_BASE + MFD_BLK_CTRL + MFD_BLK_CTRL_MFD_SYS_RESET_CLR);
+}
+
+/*!
+ * @brief open function for vpu file operation
+ *
+ * @return 0 on success or negative error code on error
+ */
+static int vpu_open(struct inode *inode, struct file *filp)
+{
+ u32 mu_id;
+ int err;
+
+ mutex_lock(&vpu_data.lock);
+
+ if (open_count++ == 0) {
+ err = sc_ipc_getMuID(&mu_id);;
+ if(err != SC_ERR_NONE)
+ {
+ dev_err(vpu_dev, "--- sc_ipc_getMuID() cannot obtain mu id SCI error! (%d)\n", err);
+ return -EFAULT;
+ }
+
+ err = sc_ipc_open(&ipcHndl, mu_id);
+ if(err != SC_ERR_NONE)
+ {
+ dev_err(vpu_dev, "--- sc_ipc_getMuID() cannot open MU channel to SCU error! (%d)\n", err);
+ return -EFAULT;
+ }
+ vpu_power_up(true);
+ clk_prepare_enable(vpu_clk);
+ vpu_prepare();
+ err = vpu_isr_event_qu_init();
+ if(err)
+ {
+ dev_err(vpu_dev, "failed to init isr event qu\n");
+ return -EFAULT;
+ }
+ vpu_set_kernel_cfg(&gtKernelCfg);
+ decoder_kernel_lib_init(&gtKernelCfg);
+ decoder_kernel_lib_register_isr_callback(0, &vpu_isr_event_callback);
+
+#if 0
+ WRITE_REG(0x1000, DEC_MFD_XREG_SLV_BASE + MFD_HIF + 0x014);
+ WRITE_REG(0x20, DEC_MFD_XREG_SLV_BASE + MFD_HIF + 0x01C);
+ WRITE_REG(0x1000, DEC_MFD_XREG_SLV_BASE + MFD_SIF + MFD_SIF_CTRL_STATUS);
+ pal_int_set(PAL_IRQ_MALONE0_LOW);
+#endif
+ } else {
+ dev_err(vpu_dev, "open more than once is forbidden now\n");
+ }
+
+ filp->private_data = (void *)(&vpu_data);
+
+ mutex_unlock(&vpu_data.lock);
+
+ return 0;
+}
+
+/*!
+ * @brief IO ctrl function for vpu file operation
+ * @param cmd IO ctrl command
+ * @return 0 on success or negative error code on error
+ */
+
+#ifdef VPU_KERNEL_DBG_ISR
+int guDbgIsrArray[1024][3] ;
+int guDbgIsrArrayWrtIdx = 0 ;
+#endif
+
+static long vpu_ioctl(struct file *filp, u_int cmd,
+ u_long arg)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case VPU_IOC_PHYMEM_ALLOC:
+ {
+ struct memalloc_record *rec;
+
+ rec = kzalloc(sizeof(*rec), GFP_KERNEL);
+ if (!rec)
+ return -ENOMEM;
+
+ ret = copy_from_user(&(rec->mem),
+ (struct vpu_mem_desc *)arg,
+ sizeof(struct vpu_mem_desc));
+ if (ret) {
+ kfree(rec);
+ return -EFAULT;
+ }
+
+ dev_dbg(vpu_dev, "[ALLOC] mem alloc size = 0x%x\n",
+ rec->mem.size);
+
+ ret = vpu_alloc_dma_buffer(&(rec->mem));
+ if (ret == -1) {
+ kfree(rec);
+ dev_err(vpu_dev,
+ "Physical memory allocation error!\n");
+ break;
+ }
+ ret = copy_to_user((void __user *)arg, &(rec->mem),
+ sizeof(struct vpu_mem_desc));
+ if (ret) {
+ kfree(rec);
+ ret = -EFAULT;
+ break;
+ }
+
+ mutex_lock(&vpu_data.lock);
+ list_add(&rec->list, &head);
+ mutex_unlock(&vpu_data.lock);
+
+ break;
+ }
+ case VPU_IOC_PHYMEM_FREE:
+ {
+ struct memalloc_record *rec, *n;
+ struct vpu_mem_desc vpu_mem;
+
+ ret = copy_from_user(&vpu_mem,
+ (struct vpu_mem_desc *)arg,
+ sizeof(struct vpu_mem_desc));
+ if (ret)
+ return -EACCES;
+
+ dev_dbg(vpu_dev, "[FREE] mem freed cpu_addr = 0x%p\n",
+ vpu_mem.cpu_addr);
+ if (vpu_mem.cpu_addr != NULL)
+ vpu_free_dma_buffer(&vpu_mem);
+
+ mutex_lock(&vpu_data.lock);
+ list_for_each_entry_safe(rec, n, &head, list) {
+ if (rec->mem.cpu_addr == vpu_mem.cpu_addr) {
+ /* delete from list */
+ list_del(&rec->list);
+ kfree(rec);
+ break;
+ }
+ }
+ mutex_unlock(&vpu_data.lock);
+
+ break;
+ }
+ case VPU_IOC_WAIT4INT:
+ {
+ DECODER_KERNEL_LIB_ISR_EVENT_DATA IsrEventData;
+
+ ret = vpu_isr_event_qu_receive(&IsrEventData);
+ if (ret)
+ {
+ dev_info(vpu_dev, "no isr event\n");
+ ret = -EFAULT;
+ break;
+ }
+#ifdef VPU_KERNEL_DBG_ISR
+ else
+ {
+ dev_dbg(vpu_dev, "isr events= %x %x %x\n", IsrEventData.uIrqStatus[0],IsrEventData.uIrqStatus[1], IsrEventData.uIrqStatus[2]);
+ }
+
+ guDbgIsrArray[guDbgIsrArrayWrtIdx][0] = IsrEventData.uIrqStatus[0];
+ guDbgIsrArray[guDbgIsrArrayWrtIdx][1] = IsrEventData.uIrqStatus[1];
+ guDbgIsrArray[guDbgIsrArrayWrtIdx][2] = IsrEventData.uIrqStatus[2];
+ guDbgIsrArrayWrtIdx++;
+ guDbgIsrArrayWrtIdx = (guDbgIsrArrayWrtIdx==1024) ? 0 : guDbgIsrArrayWrtIdx;
+#endif
+
+ ret = copy_to_user((void __user *)arg, &IsrEventData, sizeof(DECODER_KERNEL_LIB_ISR_EVENT_DATA));
+
+ if (ret)
+ ret = -EFAULT;
+#if 0
+ u_long timeout = (u_long) arg;
+ if (!wait_event_interruptible_timeout
+ (vpu_queue, irq_status != 0,
+ msecs_to_jiffies(timeout))) {
+ dev_warn(vpu_dev, "VPU blocking: timeout.\n");
+ ret = -ETIME;
+ } else if (signal_pending(current)) {
+ dev_warn(vpu_dev, "Other interrupt received.\n");
+ ret = -ERESTARTSYS;
+ } else
+ irq_status = 0;
+#endif
+ break;
+ }
+ case VPU_IOC_CLKGATE_SETTING:
+ {
+ u32 clkgate_en;
+
+ if (get_user(clkgate_en, (u32 __user *) arg))
+ return -EFAULT;
+
+ if (clkgate_en) {
+ clk_prepare_enable(vpu_clk);
+ atomic_inc(&clk_cnt_from_ioc);
+ } else {
+ clk_disable_unprepare(vpu_clk);
+ atomic_dec(&clk_cnt_from_ioc);
+ }
+
+ break;
+ }
+ case VPU_IOC_GET_SHARE_MEM:
+ {
+ mutex_lock(&vpu_data.lock);
+ if (share_mem.cpu_addr != NULL) {
+ ret = copy_to_user((void __user *)arg,
+ &share_mem,
+ sizeof(struct vpu_mem_desc));
+ mutex_unlock(&vpu_data.lock);
+ break;
+ } else {
+ if (copy_from_user(&share_mem,
+ (struct vpu_mem_desc *)arg,
+ sizeof(struct vpu_mem_desc))) {
+ mutex_unlock(&vpu_data.lock);
+ return -EFAULT;
+ }
+ if (vpu_alloc_dma_buffer(&share_mem) == -1)
+ ret = -EFAULT;
+ else {
+ if (copy_to_user((void __user *)arg,
+ &share_mem,
+ sizeof(struct
+ vpu_mem_desc)))
+ ret = -EFAULT;
+ }
+ }
+ mutex_unlock(&vpu_data.lock);
+ break;
+ }
+ case VPU_IOC_REQ_VSHARE_MEM:
+ {
+ mutex_lock(&vpu_data.lock);
+ if (vshare_mem.cpu_addr != NULL) {
+ ret = copy_to_user((void __user *)arg,
+ &vshare_mem,
+ sizeof(struct vpu_mem_desc));
+ mutex_unlock(&vpu_data.lock);
+ break;
+ } else {
+ if (copy_from_user(&vshare_mem,
+ (struct vpu_mem_desc *)arg,
+ sizeof(struct
+ vpu_mem_desc))) {
+ mutex_unlock(&vpu_data.lock);
+ return -EFAULT;
+ }
+ /* vmalloc shared memory if not allocated */
+ if (!vshare_mem.cpu_addr)
+ vshare_mem.cpu_addr =
+ vmalloc_user(vshare_mem.size);
+ if (copy_to_user
+ ((void __user *)arg, &vshare_mem,
+ sizeof(struct vpu_mem_desc)))
+ ret = -EFAULT;
+ }
+ mutex_unlock(&vpu_data.lock);
+ break;
+ }
+ case VPU_IOC_SYS_SW_RESET:
+ {
+ vpu_reset();
+ break;
+ }
+ case VPU_IOC_LOCK_DEV:
+ {
+ u32 lock_en;
+
+ if (get_user(lock_en, (u32 __user *) arg))
+ return -EFAULT;
+
+ if (lock_en)
+ mutex_lock(&vpu_data.lock);
+ else
+ mutex_unlock(&vpu_data.lock);
+
+ break;
+ }
+ default:
+ {
+ dev_err(vpu_dev, "No such IOCTL, cmd is %d\n", cmd);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ return ret;
+}
+
+/*!
+ * @brief Release function for vpu file operation
+ * @return 0 on success or negative error code on error
+ */
+static int vpu_release(struct inode *inode, struct file *filp)
+{
+ int i;
+ unsigned long timeout;
+ int err;
+
+ mutex_lock(&vpu_data.lock);
+
+ if (open_count > 0 && !(--open_count)) {
+
+ /* Wait for vpu go to idle state */
+ clk_prepare_enable(vpu_clk);
+ timeout = jiffies + HZ;
+ /* checking busy */
+ while (0) {
+ msleep(1);
+ if (time_after(jiffies, timeout)) {
+ dev_warn(vpu_dev, "VPU timeout during release\n");
+ break;
+ }
+ }
+
+ /* Clean up interrupt */
+#if 0
+ cancel_work_sync(&vpu_data.work);
+ flush_workqueue(vpu_data.workqueue);
+ irq_status = 0;
+#endif
+
+ /* reset if busy */
+ if (0) {
+ vpu_reset();
+ }
+ clk_disable_unprepare(vpu_clk);
+
+ vpu_free_buffers();
+
+ /* Free shared memory when vpu device is idle */
+ vpu_free_dma_buffer(&share_mem);
+ share_mem.cpu_addr = NULL;
+ vfree(vshare_mem.cpu_addr);
+ vshare_mem.cpu_addr = NULL;
+
+ vpu_clk_usercount = atomic_read(&clk_cnt_from_ioc);
+ for (i = 0; i < vpu_clk_usercount; i++) {
+ clk_disable_unprepare(vpu_clk);
+ atomic_dec(&clk_cnt_from_ioc);
+ }
+
+ err = vpu_isr_event_qu_uninit();
+ if (err)
+ dev_err(vpu_dev, "failed to uninit isr event qu\n");
+ vpu_unprepare();
+ clk_disable_unprepare(vpu_clk);
+ vpu_power_up(false);
+ sc_ipc_close(ipcHndl);
+ }
+ mutex_unlock(&vpu_data.lock);
+
+ return 0;
+}
+
+/*!
+ * @brief fasync function for vpu file operation
+ * @return 0 on success or negative error code on error
+ */
+static int vpu_fasync(int fd, struct file *filp, int mode)
+{
+ struct vpu_priv *dev = (struct vpu_priv *)filp->private_data;
+ return fasync_helper(fd, filp, mode, &dev->async_queue);
+}
+
+/*!
+ * @brief memory map function of harware registers for vpu file operation
+ * @return 0 on success or negative error code on error
+ */
+static int vpu_map_hwregs(struct file *fp, struct vm_area_struct *vm)
+{
+ unsigned long pfn;
+
+ vm->vm_flags |= VM_IO | VM_RESERVED;
+ /*
+ * Since vpu registers have been mapped with ioremap() at probe
+ * which L_PTE_XN is 1, and the same physical address must be
+ * mapped multiple times with same type, so set L_PTE_XN to 1 here.
+ * Otherwise, there may be unexpected result in video codec.
+ */
+ vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);
+ pfn = phy_vpu_base_addr >> PAGE_SHIFT;
+ dev_dbg(vpu_dev, "size=0x%x, page no.=0x%x\n",
+ (int)(vm->vm_end - vm->vm_start), (int)pfn);
+ return remap_pfn_range(vm, vm->vm_start, pfn, vm->vm_end - vm->vm_start,
+ vm->vm_page_prot) ? -EAGAIN : 0;
+}
+
+/*!
+ * @brief memory map function of memory for vpu file operation
+ * @return 0 on success or negative error code on error
+ */
+static int vpu_map_dma_mem(struct file *fp, struct vm_area_struct *vm)
+{
+ int request_size;
+ request_size = vm->vm_end - vm->vm_start;
+
+ dev_dbg(vpu_dev, "start=0x%x, pgoff=0x%x, size=0x%x\n",
+ (unsigned int)(vm->vm_start), (unsigned int)(vm->vm_pgoff),
+ request_size);
+
+ vm->vm_flags |= VM_IO | VM_RESERVED;
+ vm->vm_page_prot = pgprot_writecombine(vm->vm_page_prot);
+
+ return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff,
+ request_size, vm->vm_page_prot) ? -EAGAIN : 0;
+
+}
+
+/* !
+ * @brief memory map function of vmalloced share memory
+ * @return 0 on success or negative error code on error
+ */
+static int vpu_map_vshare_mem(struct file *fp, struct vm_area_struct *vm)
+{
+ int ret = -EINVAL;
+
+ ret = remap_vmalloc_range(vm, (void *)(vm->vm_pgoff << PAGE_SHIFT), 0);
+ vm->vm_flags |= VM_IO;
+
+ return ret;
+}
+/*!
+ * @brief memory map interface for vpu file operation
+ * @return 0 on success or negative error code on error
+ */
+static int vpu_mmap(struct file *fp, struct vm_area_struct *vm)
+{
+ u64 offset;
+
+ offset = (u64)((s64)vshare_mem.cpu_addr >> PAGE_SHIFT);
+ if (vm->vm_pgoff && (vm->vm_pgoff == offset || vm->vm_pgoff == (offset & 0xFFFFFFFF))){
+ if(vm->vm_pgoff == (offset & 0xFFFFFFFF))
+ vm->vm_pgoff = offset;
+ return vpu_map_vshare_mem(fp, vm);
+ }else if (vm->vm_pgoff)
+ return vpu_map_dma_mem(fp, vm);
+ else
+ return vpu_map_hwregs(fp, vm);
+}
+
+#ifdef CONFIG_COMPAT
+struct vpu_mem_desc_32 {
+ u32 size;
+ u32 phy_addr;
+ u32 cpu_addr; /* cpu address to free the dma mem */
+ u32 virt_uaddr; /* virtual user space address */
+};
+static int get_vpu_mem_desc_32(struct vpu_mem_desc *kp, struct vpu_mem_desc_32 __user *up)
+{
+ u32 tmp_phy;
+ u32 tmp_cpu;
+ u32 tmp_virt;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(struct vpu_mem_desc_32)) ||
+ get_user(kp->size, &up->size) ||
+ get_user(tmp_phy, &up->phy_addr) ||
+ get_user(tmp_cpu, &up->cpu_addr) ||
+ get_user(tmp_virt, &up->virt_uaddr)) {
+ return -EFAULT;
+ }
+ kp->phy_addr = (__force dma_addr_t)compat_ptr(tmp_phy);
+ kp->cpu_addr = (__force void *)compat_ptr(tmp_cpu);
+ kp->virt_uaddr = (__force u64)compat_ptr(tmp_virt);
+
+ return 0;
+}
+
+static int put_vpu_mem_desc_32(struct vpu_mem_desc *kp, struct vpu_mem_desc_32 __user *up)
+{
+ u32 tmp_phy = (u32)((unsigned long)kp->phy_addr);
+ u32 tmp_cpu = (u32)((unsigned long)kp->cpu_addr);
+ u32 tmp_virt = (u32)((unsigned long)kp->virt_uaddr);
+
+ if (!access_ok(VERIFY_WRITE, up, sizeof(struct vpu_mem_desc_32)) ||
+ put_user(kp->size, &up->size) ||
+ put_user(tmp_phy, &up->phy_addr) ||
+ put_user(tmp_cpu, &up->cpu_addr) ||
+ put_user(tmp_virt, &up->virt_uaddr)) {
+ return -EFAULT;
+ }
+ return 0;
+}
+struct ISR_EVENT_DATA
+{
+ u_int32 uMalIdx;
+ u_int32 uIrqStatus[0x3];
+};
+struct ISR_EVENT_DATA_32
+{
+ u_int32 uMalIdx;
+ u_int32 uIrqStatus[0x3];
+};
+
+static int get_isr_event_32(struct ISR_EVENT_DATA *kp, struct ISR_EVENT_DATA_32 __user *up)
+{
+ if (!access_ok(VERIFY_READ, up, sizeof(struct ISR_EVENT_DATA_32)) ||
+ get_user(kp->uMalIdx, &up->uMalIdx) ||
+ get_user(kp->uIrqStatus[0], &up->uIrqStatus[0]) ||
+ get_user(kp->uIrqStatus[1], &up->uIrqStatus[1]) ||
+ get_user(kp->uIrqStatus[2], &up->uIrqStatus[2])) {
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int put_isr_event_32(struct ISR_EVENT_DATA *kp, struct ISR_EVENT_DATA_32 __user *up)
+{
+ if (!access_ok(VERIFY_WRITE, up, sizeof(struct ISR_EVENT_DATA_32)) ||
+ put_user(kp->uMalIdx, &up->uMalIdx) ||
+ put_user(kp->uIrqStatus[0], &up->uIrqStatus[0]) ||
+ put_user(kp->uIrqStatus[1], &up->uIrqStatus[1]) ||
+ put_user(kp->uIrqStatus[2], &up->uIrqStatus[2])) {
+ return -EFAULT;
+ }
+ return 0;
+}
+static long vpu_ioctl32(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+#define VPU_IOCTL32(err, filp, cmd, arg) { \
+ mm_segment_t old_fs = get_fs(); \
+ set_fs(KERNEL_DS); \
+ err = vpu_ioctl(filp, cmd, arg); \
+ if (err) \
+ return err; \
+ set_fs(old_fs); \
+ }
+
+ union {
+ struct vpu_mem_desc kcore;
+ struct ISR_EVENT_DATA kevent;
+ unsigned long kux;
+ unsigned int kui;
+ } karg;
+ void __user *up = compat_ptr(arg);
+ long err = 0;
+
+ switch (_IOC_NR(cmd)) {
+ case _IOC_NR(VPU_IOC_CLKGATE_SETTING):
+ case _IOC_NR(VPU_IOC_LOCK_DEV):
+ err = get_user(karg.kui, (s32 __user *)up);
+ if (err)
+ return err;
+ VPU_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+ err = put_user(((s32)karg.kui), (s32 __user *)up);
+ break;
+ case _IOC_NR(VPU_IOC_PHYMEM_ALLOC):
+ case _IOC_NR(VPU_IOC_PHYMEM_FREE):
+ case _IOC_NR(VPU_IOC_GET_SHARE_MEM):
+ case _IOC_NR(VPU_IOC_REQ_VSHARE_MEM):
+ err = get_vpu_mem_desc_32(&karg.kcore, up);
+ if (err)
+ return err;
+ VPU_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+ err = put_vpu_mem_desc_32(&karg.kcore, up);
+ break;
+ case _IOC_NR(VPU_IOC_WAIT4INT):
+ err = get_isr_event_32(&karg.kevent, up);
+ if (err)
+ return err;
+ VPU_IOCTL32(err, filp, cmd, (unsigned long)&karg);
+ err = put_isr_event_32(&karg.kevent, up);
+ break;
+ default:
+ err = vpu_ioctl(filp, cmd, (unsigned long)up);
+ break;
+ }
+
+ return err;
+}
+
+#endif //ifdef CONFIG_COMPAT
+
+const struct file_operations vpu_fops = {
+ .owner = THIS_MODULE,
+ .open = vpu_open,
+ .unlocked_ioctl = vpu_ioctl,
+ .release = vpu_release,
+ .fasync = vpu_fasync,
+ .mmap = vpu_mmap,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = vpu_ioctl32,
+#endif
+};
+
+/*!
+ * This function is called by the driver framework to initialize the vpu device.
+ * @param dev The device structure for the vpu passed in by the framework.
+ * @return 0 on success or negative error code on error
+ */
+static int vpu_dev_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ struct device *temp_class;
+ struct resource *res;
+
+ vpu_dev = &pdev->dev;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu_regs");
+ if (!res) {
+ dev_err(vpu_dev, "vpu: unable to get vpu base addr\n");
+ return -ENODEV;
+ }
+ phy_vpu_base_addr = res->start;
+ vpu_base = devm_ioremap_resource(vpu_dev, res);
+
+ vpu_major = register_chrdev(vpu_major, "mxc_vpu_malone", &vpu_fops);
+ if (vpu_major < 0) {
+ dev_err(vpu_dev, "vpu: unable to get a major for VPU\n");
+ err = -EBUSY;
+ goto error;
+ }
+
+ vpu_class = class_create(THIS_MODULE, "mxc_vpu_malone");
+ if (IS_ERR(vpu_class)) {
+ err = PTR_ERR(vpu_class);
+ goto err_out_chrdev;
+ }
+
+ temp_class = device_create(vpu_class, NULL, MKDEV(vpu_major, 0),
+ NULL, "mxc_vpu_malone");
+ if (IS_ERR(temp_class)) {
+ err = PTR_ERR(temp_class);
+ goto err_out_class;
+ }
+
+ vpu_clk = clk_get(&pdev->dev, "vpu_clk");
+ if (IS_ERR(vpu_clk)) {
+ err = -ENOENT;
+ goto err_out_class;
+ }
+
+ vpu_dec_irq = platform_get_irq_byname(pdev, "dec_irq");
+ if (vpu_dec_irq < 0) {
+ dev_err(vpu_dev, "dec_irq is not found\n");
+ err = -ENXIO;
+ goto err_out_class;
+ }
+ err = devm_request_threaded_irq(vpu_dev, vpu_dec_irq, vpu_dec_irq_handler,
+ NULL, 0, "VPU DEC IRQ", (void*)(&vpu_data));
+ if (err < 0) {
+ dev_err(vpu_dev, "failed to request irq for dec_irq\n");
+ goto err_out_class;
+ }
+
+ vpu_dec_fiq = platform_get_irq_byname(pdev, "dec_fiq");
+ if (vpu_dec_fiq < 0) {
+ dev_err(vpu_dev, "dec_fiq is not found\n");
+ err = -ENXIO;
+ goto err_out_class;
+ }
+ err = devm_request_threaded_irq(vpu_dev, vpu_dec_fiq, vpu_dec_fiq_handler,
+ NULL, 0, "VPU DEC FIQ", (void*)(&vpu_data));
+ if (err < 0)
+ dev_err(vpu_dev, "failed to request irq for dec_fiq\n");
+
+ if (vpu_power_get(true)) {
+ dev_err(vpu_dev, "failed to get vpu power\n");
+ goto err_out_class;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ vpu_data.workqueue = create_workqueue("vpu_wq");
+ INIT_WORK(&vpu_data.work, vpu_worker_callback);
+ mutex_init(&vpu_data.lock);
+ dev_info(vpu_dev, "VPU initialized\n");
+
+ goto out;
+
+err_out_class:
+ device_destroy(vpu_class, MKDEV(vpu_major, 0));
+ class_destroy(vpu_class);
+err_out_chrdev:
+ unregister_chrdev(vpu_major, "mxc_vpu_malone");
+error:
+ devm_iounmap(vpu_dev, vpu_base);
+out:
+ return err;
+}
+
+static int vpu_dev_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+ devm_free_irq(&pdev->dev, vpu_dec_irq, &vpu_data);
+ devm_free_irq(&pdev->dev, vpu_dec_fiq, &vpu_data);
+ cancel_work_sync(&vpu_data.work);
+ flush_workqueue(vpu_data.workqueue);
+ destroy_workqueue(vpu_data.workqueue);
+
+ devm_iounmap(&pdev->dev, vpu_base);
+
+ vpu_power_get(false);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int vpu_suspend(struct device *dev)
+{
+ int i;
+ unsigned long timeout;
+
+ mutex_lock(&vpu_data.lock);
+ if (open_count != 0) {
+ /* Wait for vpu go to idle state, suspect vpu cannot be changed
+ to idle state after about 1 sec */
+ timeout = jiffies + HZ;
+ clk_prepare_enable(vpu_clk);
+ /* checking busy */
+ while (0) {
+ msleep(1);
+ if (time_after(jiffies, timeout)) {
+ clk_disable_unprepare(vpu_clk);
+ mutex_unlock(&vpu_data.lock);
+ return -EAGAIN;
+ }
+ }
+ clk_disable_unprepare(vpu_clk);
+
+ /* Make sure clock is disabled before suspend */
+ vpu_clk_usercount = atomic_read(&clk_cnt_from_ioc);
+ for (i = 0; i < vpu_clk_usercount; i++) {
+ clk_disable_unprepare(vpu_clk);
+ }
+
+ clk_prepare_enable(vpu_clk);
+ /* Save registers */
+ clk_disable_unprepare(vpu_clk);
+
+ /* If VPU is working before suspend, disable
+ * regulator to make usecount right. */
+ vpu_power_up(false);
+ }
+
+ mutex_unlock(&vpu_data.lock);
+ return 0;
+}
+
+static int vpu_resume(struct device *dev)
+{
+ int i;
+
+ mutex_lock(&vpu_data.lock);
+ if (open_count != 0) {
+ /* If VPU is working before suspend, enable
+ * regulator to make usecount right. */
+ vpu_power_up(true);
+
+ clk_prepare_enable(vpu_clk);
+
+ /* Restore registers */
+
+ clk_disable_unprepare(vpu_clk);
+
+ /* Recover vpu clock */
+ for (i = 0; i < vpu_clk_usercount; i++) {
+ clk_prepare_enable(vpu_clk);
+ }
+ }
+
+ mutex_unlock(&vpu_data.lock);
+ return 0;
+}
+
+static int vpu_runtime_suspend(struct device *dev)
+{
+ release_bus_freq(BUS_FREQ_HIGH);
+ return 0;
+}
+
+static int vpu_runtime_resume(struct device *dev)
+{
+ request_bus_freq(BUS_FREQ_HIGH);
+ return 0;
+}
+
+static const struct dev_pm_ops vpu_pm_ops = {
+ SET_RUNTIME_PM_OPS(vpu_runtime_suspend, vpu_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(vpu_suspend, vpu_resume)
+};
+
+#else
+#define vpu_suspend NULL
+#define vpu_resume NULL
+#endif /* !CONFIG_PM */
+
+static const struct of_device_id vpu_of_match[] = {
+ { .compatible = "nxp,imx8qm-vpu", },
+ { .compatible = "nxp,imx8qxp-vpu", },
+ {/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, vpu_of_match);
+
+/*! Driver definition
+ *
+ */
+static struct platform_driver mxcvpu_driver = {
+ .driver = {
+ .name = "mxc_vpu_malone",
+ .of_match_table = vpu_of_match,
+#ifdef CONFIG_PM
+ .pm = &vpu_pm_ops,
+#endif
+ },
+ .probe = vpu_dev_probe,
+ .remove = vpu_dev_remove,
+};
+
+static int __init vpu_init(void)
+{
+ int ret = platform_driver_register(&mxcvpu_driver);
+
+ init_waitqueue_head(&vpu_queue);
+
+ return ret;
+}
+
+static void __exit vpu_exit(void)
+{
+ if (vpu_major > 0) {
+ device_destroy(vpu_class, MKDEV(vpu_major, 0));
+ class_destroy(vpu_class);
+ unregister_chrdev(vpu_major, "mxc_vpu_malone");
+ vpu_major = 0;
+ }
+
+ /* reset VPU state */
+ vpu_power_up(true);
+ clk_prepare_enable(vpu_clk);
+ vpu_reset();
+ clk_disable_unprepare(vpu_clk);
+ vpu_power_up(false);
+
+ clk_put(vpu_clk);
+
+ platform_driver_unregister(&mxcvpu_driver);
+ return;
+}
+
+MODULE_AUTHOR("NXP");
+MODULE_DESCRIPTION("Linux VPU driver for NXP i.MX/MXC");
+MODULE_LICENSE("GPL");
+
+module_init(vpu_init);
+module_exit(vpu_exit);
diff --git a/drivers/mxc/vpu/Kconfig b/drivers/mxc/vpu/Kconfig
new file mode 100644
index 000000000000..520209601dbe
--- /dev/null
+++ b/drivers/mxc/vpu/Kconfig
@@ -0,0 +1,31 @@
+#
+# Codec configuration
+#
+
+menu "MXC VPU(Video Processing Unit) support"
+
+config MXC_VPU
+ tristate "Support for MXC VPU(Video Processing Unit)"
+ depends on (SOC_IMX27 || SOC_IMX5 || SOC_IMX6Q)
+ default y
+ ---help---
+ The VPU codec device provides codec function for H.264/MPEG4/H.263,
+ as well as MPEG2/VC-1/DivX on some platforms.
+
+config MXC_VPU_DEBUG
+ bool "MXC VPU debugging"
+ depends on MXC_VPU != n
+ help
+ This is an option for the developers; most people should
+ say N here. This enables MXC VPU driver debugging.
+
+config MX6_VPU_352M
+ bool "MX6 VPU 352M"
+ depends on MXC_VPU
+ default n
+ help
+ Increase VPU frequncy to 352M, the config will disable bus frequency
+ adjust dynamic, and CPU lowest setpoint will be 352Mhz.
+ This config is used for special VPU use case.
+
+endmenu
diff --git a/drivers/mxc/vpu/Makefile b/drivers/mxc/vpu/Makefile
new file mode 100644
index 000000000000..1a821f4921cb
--- /dev/null
+++ b/drivers/mxc/vpu/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the VPU drivers.
+#
+
+obj-$(CONFIG_MXC_VPU) += mxc_vpu.o
+
+ifeq ($(CONFIG_MXC_VPU_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/mxc/vpu/mxc_vpu.c b/drivers/mxc/vpu/mxc_vpu.c
new file mode 100644
index 000000000000..2c9152d9c80e
--- /dev/null
+++ b/drivers/mxc/vpu/mxc_vpu.c
@@ -0,0 +1,1348 @@
+/*
+ * Copyright 2006-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file mxc_vpu.c
+ *
+ * @brief VPU system initialization and file operation implementation
+ *
+ * @ingroup VPU
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/stat.h>
+#include <linux/platform_device.h>
+#include <linux/kdev_t.h>
+#include <linux/dma-mapping.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/fsl_devices.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/regulator/consumer.h>
+#include <linux/page-flags.h>
+#include <linux/mm_types.h>
+#include <linux/types.h>
+#include <linux/memblock.h>
+#include <linux/memory.h>
+#include <linux/version.h>
+#include <asm/page.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/sizes.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
+#include <linux/iram_alloc.h>
+#include <mach/clock.h>
+#include <mach/hardware.h>
+#include <mach/mxc_vpu.h>
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/genalloc.h>
+#include <linux/mxc_vpu.h>
+#include <linux/of.h>
+#include <linux/reset.h>
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+#include <mach/busfreq.h>
+#include <mach/common.h>
+#else
+#include <asm/sizes.h>
+#endif
+
+/* Define one new pgprot which combined uncached and XN(never executable) */
+#define pgprot_noncachedxn(prot) \
+ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED | L_PTE_XN)
+
+struct vpu_priv {
+ struct fasync_struct *async_queue;
+ struct work_struct work;
+ struct workqueue_struct *workqueue;
+ struct mutex lock;
+};
+
+/* To track the allocated memory buffer */
+struct memalloc_record {
+ struct list_head list;
+ struct vpu_mem_desc mem;
+};
+
+struct iram_setting {
+ u32 start;
+ u32 end;
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+static struct gen_pool *iram_pool;
+static u32 iram_base;
+#endif
+
+static LIST_HEAD(head);
+
+static int vpu_major;
+static int vpu_clk_usercount;
+static struct class *vpu_class;
+static struct vpu_priv vpu_data;
+static u8 open_count;
+static struct clk *vpu_clk;
+static struct vpu_mem_desc bitwork_mem = { 0 };
+static struct vpu_mem_desc pic_para_mem = { 0 };
+static struct vpu_mem_desc user_data_mem = { 0 };
+static struct vpu_mem_desc share_mem = { 0 };
+static struct vpu_mem_desc vshare_mem = { 0 };
+
+static void __iomem *vpu_base;
+static int vpu_ipi_irq;
+static u32 phy_vpu_base_addr;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+static phys_addr_t top_address_DRAM;
+static struct mxc_vpu_platform_data *vpu_plat;
+#endif
+
+static struct device *vpu_dev;
+
+/* IRAM setting */
+static struct iram_setting iram;
+
+/* implement the blocking ioctl */
+static int irq_status;
+static int codec_done;
+static wait_queue_head_t vpu_queue;
+
+#ifdef CONFIG_SOC_IMX6Q
+#define MXC_VPU_HAS_JPU
+#endif
+
+#ifdef MXC_VPU_HAS_JPU
+static int vpu_jpu_irq;
+#endif
+
+#ifdef CONFIG_PM
+static unsigned int regBk[64];
+static unsigned int pc_before_suspend;
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+static struct regulator *vpu_regulator;
+#endif
+#endif
+static atomic_t clk_cnt_from_ioc = ATOMIC_INIT(0);
+
+#define READ_REG(x) readl_relaxed(vpu_base + x)
+#define WRITE_REG(val, x) writel_relaxed(val, vpu_base + x)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+/* redirect to static functions */
+static int cpu_is_mx6dl(void)
+{
+ int ret;
+ ret = of_machine_is_compatible("fsl,imx6dl");
+ return ret;
+}
+
+static int cpu_is_mx6q(void)
+{
+ int ret;
+ ret = of_machine_is_compatible("fsl,imx6q");
+ return ret;
+}
+#endif
+
+static void vpu_reset(void)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+ int ret;
+
+ ret = device_reset(vpu_dev);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ imx_src_reset_vpu();
+#else
+ if (vpu_plat->reset)
+ vpu_plat->reset();
+#endif
+}
+
+static long vpu_power_get(bool on)
+{
+ long ret = 0;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
+ if (on) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+ vpu_regulator = regulator_get(NULL, "cpu_vddvpu");
+ ret = IS_ERR(vpu_regulator);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+ vpu_regulator = devm_regulator_get(vpu_dev, "pu");
+ ret = IS_ERR(vpu_regulator);
+#endif
+ } else {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+ if (!IS_ERR(vpu_regulator))
+ regulator_put(vpu_regulator);
+#endif
+ }
+#endif
+ return ret;
+}
+
+static void vpu_power_up(bool on)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ if (on)
+ pm_runtime_get_sync(vpu_dev);
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+ if (on) {
+ if (!IS_ERR(vpu_regulator)) {
+ if (regulator_enable(vpu_regulator))
+ dev_err(vpu_dev, "failed to power up vpu\n");
+ }
+ } else {
+ if (!IS_ERR(vpu_regulator)) {
+ if (regulator_disable(vpu_regulator))
+ dev_err(vpu_dev, "failed to power down vpu\n");
+ }
+ }
+#else
+ imx_gpc_power_up_pu(on);
+#endif
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ if (!on)
+ pm_runtime_put_sync_suspend(vpu_dev);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+static int cpu_is_mx53(void)
+{
+ return 0;
+}
+
+static int cpu_is_mx51(void)
+{
+ return 0;
+}
+
+#define VM_RESERVED 0
+#endif
+
+/*!
+ * Private function to alloc dma buffer
+ * @return status 0 success.
+ */
+static int vpu_alloc_dma_buffer(struct vpu_mem_desc *mem)
+{
+ mem->cpu_addr = (unsigned long)
+ dma_alloc_coherent(NULL, PAGE_ALIGN(mem->size),
+ (dma_addr_t *) (&mem->phy_addr),
+ GFP_DMA | GFP_KERNEL);
+ dev_dbg(vpu_dev, "[ALLOC] mem alloc cpu_addr = 0x%x\n", mem->cpu_addr);
+ if ((void *)(mem->cpu_addr) == NULL) {
+ dev_err(vpu_dev, "Physical memory allocation error!\n");
+ return -1;
+ }
+ return 0;
+}
+
+/*!
+ * Private function to free dma buffer
+ */
+static void vpu_free_dma_buffer(struct vpu_mem_desc *mem)
+{
+ if (mem->cpu_addr != 0) {
+ dma_free_coherent(0, PAGE_ALIGN(mem->size),
+ (void *)mem->cpu_addr, mem->phy_addr);
+ }
+}
+
+/*!
+ * Private function to free buffers
+ * @return status 0 success.
+ */
+static int vpu_free_buffers(void)
+{
+ struct memalloc_record *rec, *n;
+ struct vpu_mem_desc mem;
+
+ list_for_each_entry_safe(rec, n, &head, list) {
+ mem = rec->mem;
+ if (mem.cpu_addr != 0) {
+ vpu_free_dma_buffer(&mem);
+ dev_dbg(vpu_dev, "[FREE] freed paddr=0x%08X\n", mem.phy_addr);
+ /* delete from list */
+ list_del(&rec->list);
+ kfree(rec);
+ }
+ }
+
+ return 0;
+}
+
+static inline void vpu_worker_callback(struct work_struct *w)
+{
+ struct vpu_priv *dev = container_of(w, struct vpu_priv,
+ work);
+
+ if (dev->async_queue)
+ kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
+
+ irq_status = 1;
+ /*
+ * Clock is gated on when dec/enc started, gate it off when
+ * codec is done.
+ */
+ if (codec_done)
+ codec_done = 0;
+
+ wake_up_interruptible(&vpu_queue);
+}
+
+/*!
+ * @brief vpu interrupt handler
+ */
+static irqreturn_t vpu_ipi_irq_handler(int irq, void *dev_id)
+{
+ struct vpu_priv *dev = dev_id;
+ unsigned long reg;
+
+ reg = READ_REG(BIT_INT_REASON);
+ if (reg & 0x8)
+ codec_done = 1;
+ WRITE_REG(0x1, BIT_INT_CLEAR);
+
+ queue_work(dev->workqueue, &dev->work);
+
+ return IRQ_HANDLED;
+}
+
+/*!
+ * @brief vpu jpu interrupt handler
+ */
+#ifdef MXC_VPU_HAS_JPU
+static irqreturn_t vpu_jpu_irq_handler(int irq, void *dev_id)
+{
+ struct vpu_priv *dev = dev_id;
+ unsigned long reg;
+
+ reg = READ_REG(MJPEG_PIC_STATUS_REG);
+ if (reg & 0x3)
+ codec_done = 1;
+
+ queue_work(dev->workqueue, &dev->work);
+
+ return IRQ_HANDLED;
+}
+#endif
+
+/*!
+ * @brief check phy memory prepare to pass to vpu is valid or not, we
+ * already address some issue that if pass a wrong address to vpu
+ * (like virtual address), system will hang.
+ *
+ * @return true return is a valid phy memory address, false return not.
+ */
+bool vpu_is_valid_phy_memory(u32 paddr)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+ if (paddr > top_address_DRAM)
+ return false;
+#endif
+
+ return true;
+}
+
+/*!
+ * @brief open function for vpu file operation
+ *
+ * @return 0 on success or negative error code on error
+ */
+static int vpu_open(struct inode *inode, struct file *filp)
+{
+
+ mutex_lock(&vpu_data.lock);
+
+ if (open_count++ == 0) {
+ vpu_power_up(true);
+
+#ifdef CONFIG_SOC_IMX6Q
+ clk_prepare(vpu_clk);
+ clk_enable(vpu_clk);
+ if (READ_REG(BIT_CUR_PC))
+ dev_dbg(vpu_dev, "Not power off before vpu open!\n");
+ clk_disable(vpu_clk);
+ clk_unprepare(vpu_clk);
+#endif
+ }
+
+ filp->private_data = (void *)(&vpu_data);
+ mutex_unlock(&vpu_data.lock);
+ return 0;
+}
+
+/*!
+ * @brief IO ctrl function for vpu file operation
+ * @param cmd IO ctrl command
+ * @return 0 on success or negative error code on error
+ */
+static long vpu_ioctl(struct file *filp, u_int cmd,
+ u_long arg)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case VPU_IOC_PHYMEM_ALLOC:
+ {
+ struct memalloc_record *rec;
+
+ rec = kzalloc(sizeof(*rec), GFP_KERNEL);
+ if (!rec)
+ return -ENOMEM;
+
+ ret = copy_from_user(&(rec->mem),
+ (struct vpu_mem_desc *)arg,
+ sizeof(struct vpu_mem_desc));
+ if (ret) {
+ kfree(rec);
+ return -EFAULT;
+ }
+
+ dev_dbg(vpu_dev, "[ALLOC] mem alloc size = 0x%x\n",
+ rec->mem.size);
+
+ ret = vpu_alloc_dma_buffer(&(rec->mem));
+ if (ret == -1) {
+ kfree(rec);
+ dev_err(vpu_dev,
+ "Physical memory allocation error!\n");
+ break;
+ }
+ ret = copy_to_user((void __user *)arg, &(rec->mem),
+ sizeof(struct vpu_mem_desc));
+ if (ret) {
+ kfree(rec);
+ ret = -EFAULT;
+ break;
+ }
+
+ mutex_lock(&vpu_data.lock);
+ list_add(&rec->list, &head);
+ mutex_unlock(&vpu_data.lock);
+
+ break;
+ }
+ case VPU_IOC_PHYMEM_FREE:
+ {
+ struct memalloc_record *rec, *n;
+ struct vpu_mem_desc vpu_mem;
+
+ ret = copy_from_user(&vpu_mem,
+ (struct vpu_mem_desc *)arg,
+ sizeof(struct vpu_mem_desc));
+ if (ret)
+ return -EACCES;
+
+ dev_dbg(vpu_dev, "[FREE] mem freed cpu_addr = 0x%x\n",
+ vpu_mem.cpu_addr);
+ if ((void *)vpu_mem.cpu_addr != NULL)
+ vpu_free_dma_buffer(&vpu_mem);
+
+ mutex_lock(&vpu_data.lock);
+ list_for_each_entry_safe(rec, n, &head, list) {
+ if (rec->mem.cpu_addr == vpu_mem.cpu_addr) {
+ /* delete from list */
+ list_del(&rec->list);
+ kfree(rec);
+ break;
+ }
+ }
+ mutex_unlock(&vpu_data.lock);
+
+ break;
+ }
+ case VPU_IOC_WAIT4INT:
+ {
+ u_long timeout = (u_long) arg;
+ if (!wait_event_interruptible_timeout
+ (vpu_queue, irq_status != 0,
+ msecs_to_jiffies(timeout))) {
+ dev_warn(vpu_dev, "VPU blocking: timeout.\n");
+ ret = -ETIME;
+ } else if (signal_pending(current)) {
+ dev_warn(vpu_dev, "VPU interrupt received.\n");
+ ret = -ERESTARTSYS;
+ } else
+ irq_status = 0;
+ break;
+ }
+ case VPU_IOC_IRAM_SETTING:
+ {
+ ret = copy_to_user((void __user *)arg, &iram,
+ sizeof(struct iram_setting));
+ if (ret)
+ ret = -EFAULT;
+
+ break;
+ }
+ case VPU_IOC_CLKGATE_SETTING:
+ {
+ u32 clkgate_en;
+
+ if (get_user(clkgate_en, (u32 __user *) arg))
+ return -EFAULT;
+
+ if (clkgate_en) {
+ clk_prepare(vpu_clk);
+ clk_enable(vpu_clk);
+ atomic_inc(&clk_cnt_from_ioc);
+ } else {
+ clk_disable(vpu_clk);
+ clk_unprepare(vpu_clk);
+ atomic_dec(&clk_cnt_from_ioc);
+ }
+
+ break;
+ }
+ case VPU_IOC_GET_SHARE_MEM:
+ {
+ mutex_lock(&vpu_data.lock);
+ if (share_mem.cpu_addr != 0) {
+ ret = copy_to_user((void __user *)arg,
+ &share_mem,
+ sizeof(struct vpu_mem_desc));
+ mutex_unlock(&vpu_data.lock);
+ break;
+ } else {
+ if (copy_from_user(&share_mem,
+ (struct vpu_mem_desc *)arg,
+ sizeof(struct vpu_mem_desc))) {
+ mutex_unlock(&vpu_data.lock);
+ return -EFAULT;
+ }
+ if (vpu_alloc_dma_buffer(&share_mem) == -1)
+ ret = -EFAULT;
+ else {
+ if (copy_to_user((void __user *)arg,
+ &share_mem,
+ sizeof(struct
+ vpu_mem_desc)))
+ ret = -EFAULT;
+ }
+ }
+ mutex_unlock(&vpu_data.lock);
+ break;
+ }
+ case VPU_IOC_REQ_VSHARE_MEM:
+ {
+ mutex_lock(&vpu_data.lock);
+ if (vshare_mem.cpu_addr != 0) {
+ ret = copy_to_user((void __user *)arg,
+ &vshare_mem,
+ sizeof(struct vpu_mem_desc));
+ mutex_unlock(&vpu_data.lock);
+ break;
+ } else {
+ if (copy_from_user(&vshare_mem,
+ (struct vpu_mem_desc *)arg,
+ sizeof(struct
+ vpu_mem_desc))) {
+ mutex_unlock(&vpu_data.lock);
+ return -EFAULT;
+ }
+ /* vmalloc shared memory if not allocated */
+ if (!vshare_mem.cpu_addr)
+ vshare_mem.cpu_addr =
+ (unsigned long)
+ vmalloc_user(vshare_mem.size);
+ if (copy_to_user
+ ((void __user *)arg, &vshare_mem,
+ sizeof(struct vpu_mem_desc)))
+ ret = -EFAULT;
+ }
+ mutex_unlock(&vpu_data.lock);
+ break;
+ }
+ case VPU_IOC_GET_WORK_ADDR:
+ {
+ if (bitwork_mem.cpu_addr != 0) {
+ ret =
+ copy_to_user((void __user *)arg,
+ &bitwork_mem,
+ sizeof(struct vpu_mem_desc));
+ break;
+ } else {
+ if (copy_from_user(&bitwork_mem,
+ (struct vpu_mem_desc *)arg,
+ sizeof(struct vpu_mem_desc)))
+ return -EFAULT;
+
+ if (vpu_alloc_dma_buffer(&bitwork_mem) == -1)
+ ret = -EFAULT;
+ else if (copy_to_user((void __user *)arg,
+ &bitwork_mem,
+ sizeof(struct
+ vpu_mem_desc)))
+ ret = -EFAULT;
+ }
+ break;
+ }
+ /*
+ * The following two ioctl is used when user allocates working buffer
+ * and register it to vpu driver.
+ */
+ case VPU_IOC_QUERY_BITWORK_MEM:
+ {
+ if (copy_to_user((void __user *)arg,
+ &bitwork_mem,
+ sizeof(struct vpu_mem_desc)))
+ ret = -EFAULT;
+ break;
+ }
+ case VPU_IOC_SET_BITWORK_MEM:
+ {
+ if (copy_from_user(&bitwork_mem,
+ (struct vpu_mem_desc *)arg,
+ sizeof(struct vpu_mem_desc)))
+ ret = -EFAULT;
+ break;
+ }
+ case VPU_IOC_SYS_SW_RESET:
+ {
+ vpu_reset();
+ break;
+ }
+ case VPU_IOC_REG_DUMP:
+ break;
+ case VPU_IOC_PHYMEM_DUMP:
+ break;
+ case VPU_IOC_PHYMEM_CHECK:
+ {
+ struct vpu_mem_desc check_memory;
+ ret = copy_from_user(&check_memory,
+ (void __user *)arg,
+ sizeof(struct vpu_mem_desc));
+ if (ret != 0) {
+ dev_err(vpu_dev, "copy from user failure:%d\n", ret);
+ ret = -EFAULT;
+ break;
+ }
+ ret = vpu_is_valid_phy_memory((u32)check_memory.phy_addr);
+
+ dev_dbg(vpu_dev, "vpu: memory phy:0x%x %s phy memory\n",
+ check_memory.phy_addr, (ret ? "is" : "isn't"));
+ /* borrow .size to pass back the result. */
+ check_memory.size = ret;
+ ret = copy_to_user((void __user *)arg, &check_memory,
+ sizeof(struct vpu_mem_desc));
+ if (ret) {
+ ret = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case VPU_IOC_LOCK_DEV:
+ {
+ u32 lock_en;
+
+ if (get_user(lock_en, (u32 __user *) arg))
+ return -EFAULT;
+
+ if (lock_en)
+ mutex_lock(&vpu_data.lock);
+ else
+ mutex_unlock(&vpu_data.lock);
+
+ break;
+ }
+ default:
+ {
+ dev_err(vpu_dev, "No such IOCTL, cmd is %d\n", cmd);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ return ret;
+}
+
+/*!
+ * @brief Release function for vpu file operation
+ * @return 0 on success or negative error code on error
+ */
+static int vpu_release(struct inode *inode, struct file *filp)
+{
+ int i;
+ unsigned long timeout;
+
+ mutex_lock(&vpu_data.lock);
+
+ if (open_count > 0 && !(--open_count)) {
+
+ /* Wait for vpu go to idle state */
+ clk_prepare(vpu_clk);
+ clk_enable(vpu_clk);
+ if (READ_REG(BIT_CUR_PC)) {
+
+ timeout = jiffies + HZ;
+ while (READ_REG(BIT_BUSY_FLAG)) {
+ msleep(1);
+ if (time_after(jiffies, timeout)) {
+ dev_warn(vpu_dev, "VPU timeout during release\n");
+ break;
+ }
+ }
+ clk_disable(vpu_clk);
+ clk_unprepare(vpu_clk);
+
+ /* Clean up interrupt */
+ cancel_work_sync(&vpu_data.work);
+ flush_workqueue(vpu_data.workqueue);
+ irq_status = 0;
+
+ clk_prepare(vpu_clk);
+ clk_enable(vpu_clk);
+ if (READ_REG(BIT_BUSY_FLAG)) {
+
+ if (cpu_is_mx51() || cpu_is_mx53()) {
+ dev_err(vpu_dev,
+ "fatal error: can't gate/power off when VPU is busy\n");
+ clk_disable(vpu_clk);
+ clk_unprepare(vpu_clk);
+ mutex_unlock(&vpu_data.lock);
+ return -EFAULT;
+ }
+
+#ifdef CONFIG_SOC_IMX6Q
+ if (cpu_is_mx6dl() || cpu_is_mx6q()) {
+ WRITE_REG(0x11, 0x10F0);
+ timeout = jiffies + HZ;
+ while (READ_REG(0x10F4) != 0x77) {
+ msleep(1);
+ if (time_after(jiffies, timeout))
+ break;
+ }
+
+ if (READ_REG(0x10F4) != 0x77) {
+ dev_err(vpu_dev,
+ "fatal error: can't gate/power off when VPU is busy\n");
+ WRITE_REG(0x0, 0x10F0);
+ clk_disable(vpu_clk);
+ clk_unprepare(vpu_clk);
+ mutex_unlock(&vpu_data.lock);
+ return -EFAULT;
+ } else
+ vpu_reset();
+ }
+#endif
+ }
+ }
+ clk_disable(vpu_clk);
+ clk_unprepare(vpu_clk);
+
+ vpu_free_buffers();
+
+ /* Free shared memory when vpu device is idle */
+ vpu_free_dma_buffer(&share_mem);
+ share_mem.cpu_addr = 0;
+ vfree((void *)vshare_mem.cpu_addr);
+ vshare_mem.cpu_addr = 0;
+
+ vpu_clk_usercount = atomic_read(&clk_cnt_from_ioc);
+ for (i = 0; i < vpu_clk_usercount; i++) {
+ clk_disable(vpu_clk);
+ clk_unprepare(vpu_clk);
+ atomic_dec(&clk_cnt_from_ioc);
+ }
+
+ vpu_power_up(false);
+ }
+ mutex_unlock(&vpu_data.lock);
+
+ return 0;
+}
+
+/*!
+ * @brief fasync function for vpu file operation
+ * @return 0 on success or negative error code on error
+ */
+static int vpu_fasync(int fd, struct file *filp, int mode)
+{
+ struct vpu_priv *dev = (struct vpu_priv *)filp->private_data;
+ return fasync_helper(fd, filp, mode, &dev->async_queue);
+}
+
+/*!
+ * @brief memory map function of harware registers for vpu file operation
+ * @return 0 on success or negative error code on error
+ */
+static int vpu_map_hwregs(struct file *fp, struct vm_area_struct *vm)
+{
+ unsigned long pfn;
+
+ vm->vm_flags |= VM_IO | VM_RESERVED;
+ /*
+ * Since vpu registers have been mapped with ioremap() at probe
+ * which L_PTE_XN is 1, and the same physical address must be
+ * mapped multiple times with same type, so set L_PTE_XN to 1 here.
+ * Otherwise, there may be unexpected result in video codec.
+ */
+ vm->vm_page_prot = pgprot_noncachedxn(vm->vm_page_prot);
+ pfn = phy_vpu_base_addr >> PAGE_SHIFT;
+ dev_dbg(vpu_dev, "size=0x%x, page no.=0x%x\n",
+ (int)(vm->vm_end - vm->vm_start), (int)pfn);
+ return remap_pfn_range(vm, vm->vm_start, pfn, vm->vm_end - vm->vm_start,
+ vm->vm_page_prot) ? -EAGAIN : 0;
+}
+
+/*!
+ * @brief memory map function of memory for vpu file operation
+ * @return 0 on success or negative error code on error
+ */
+static int vpu_map_dma_mem(struct file *fp, struct vm_area_struct *vm)
+{
+ int request_size;
+ request_size = vm->vm_end - vm->vm_start;
+
+ dev_dbg(vpu_dev, "start=0x%x, pgoff=0x%x, size=0x%x\n",
+ (unsigned int)(vm->vm_start), (unsigned int)(vm->vm_pgoff),
+ request_size);
+
+ vm->vm_flags |= VM_IO | VM_RESERVED;
+ vm->vm_page_prot = pgprot_writecombine(vm->vm_page_prot);
+
+ return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff,
+ request_size, vm->vm_page_prot) ? -EAGAIN : 0;
+
+}
+
+/* !
+ * @brief memory map function of vmalloced share memory
+ * @return 0 on success or negative error code on error
+ */
+static int vpu_map_vshare_mem(struct file *fp, struct vm_area_struct *vm)
+{
+ int ret = -EINVAL;
+
+ ret = remap_vmalloc_range(vm, (void *)(vm->vm_pgoff << PAGE_SHIFT), 0);
+ vm->vm_flags |= VM_IO;
+
+ return ret;
+}
+/*!
+ * @brief memory map interface for vpu file operation
+ * @return 0 on success or negative error code on error
+ */
+static int vpu_mmap(struct file *fp, struct vm_area_struct *vm)
+{
+ unsigned long offset;
+
+ offset = vshare_mem.cpu_addr >> PAGE_SHIFT;
+
+ if (vm->vm_pgoff && (vm->vm_pgoff == offset))
+ return vpu_map_vshare_mem(fp, vm);
+ else if (vm->vm_pgoff)
+ return vpu_map_dma_mem(fp, vm);
+ else
+ return vpu_map_hwregs(fp, vm);
+}
+
+const struct file_operations vpu_fops = {
+ .owner = THIS_MODULE,
+ .open = vpu_open,
+ .unlocked_ioctl = vpu_ioctl,
+ .release = vpu_release,
+ .fasync = vpu_fasync,
+ .mmap = vpu_mmap,
+};
+
+/*!
+ * This function is called by the driver framework to initialize the vpu device.
+ * @param dev The device structure for the vpu passed in by the framework.
+ * @return 0 on success or negative error code on error
+ */
+static int vpu_dev_probe(struct platform_device *pdev)
+{
+ int err = 0;
+ struct device *temp_class;
+ struct resource *res;
+ unsigned long addr = 0;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ struct device_node *np = pdev->dev.of_node;
+ u32 iramsize;
+
+ err = of_property_read_u32(np, "iramsize", (u32 *)&iramsize);
+ if (!err && iramsize)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+ {
+ iram_pool = of_gen_pool_get(np, "iram", 0);
+ if (!iram_pool) {
+ dev_err(&pdev->dev, "iram pool not available\n");
+ return -ENOMEM;
+ }
+
+ iram_base = gen_pool_alloc(iram_pool, iramsize);
+ if (!iram_base) {
+ dev_err(&pdev->dev, "unable to alloc iram\n");
+ return -ENOMEM;
+ }
+
+ addr = gen_pool_virt_to_phys(iram_pool, iram_base);
+ }
+#else
+ iram_alloc(iramsize, &addr);
+#endif
+ if (addr == 0)
+ iram.start = iram.end = 0;
+ else {
+ iram.start = addr;
+ iram.end = addr + iramsize - 1;
+ }
+#else
+
+ vpu_plat = pdev->dev.platform_data;
+
+ if (vpu_plat && vpu_plat->iram_enable && vpu_plat->iram_size)
+ iram_alloc(vpu_plat->iram_size, &addr);
+ if (addr == 0)
+ iram.start = iram.end = 0;
+ else {
+ iram.start = addr;
+ iram.end = addr + vpu_plat->iram_size - 1;
+ }
+#endif
+
+ vpu_dev = &pdev->dev;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu_regs");
+ if (!res) {
+ dev_err(vpu_dev, "vpu: unable to get vpu base addr\n");
+ return -ENODEV;
+ }
+ phy_vpu_base_addr = res->start;
+ vpu_base = ioremap(res->start, res->end - res->start);
+
+ vpu_major = register_chrdev(vpu_major, "mxc_vpu", &vpu_fops);
+ if (vpu_major < 0) {
+ dev_err(vpu_dev, "vpu: unable to get a major for VPU\n");
+ err = -EBUSY;
+ goto error;
+ }
+
+ vpu_class = class_create(THIS_MODULE, "mxc_vpu");
+ if (IS_ERR(vpu_class)) {
+ err = PTR_ERR(vpu_class);
+ goto err_out_chrdev;
+ }
+
+ temp_class = device_create(vpu_class, NULL, MKDEV(vpu_major, 0),
+ NULL, "mxc_vpu");
+ if (IS_ERR(temp_class)) {
+ err = PTR_ERR(temp_class);
+ goto err_out_class;
+ }
+
+ vpu_clk = clk_get(&pdev->dev, "vpu_clk");
+ if (IS_ERR(vpu_clk)) {
+ err = -ENOENT;
+ goto err_out_class;
+ }
+
+ vpu_ipi_irq = platform_get_irq_byname(pdev, "vpu_ipi_irq");
+ if (vpu_ipi_irq < 0) {
+ dev_err(vpu_dev, "vpu: unable to get vpu interrupt\n");
+ err = -ENXIO;
+ goto err_out_class;
+ }
+ err = request_irq(vpu_ipi_irq, vpu_ipi_irq_handler, 0, "VPU_CODEC_IRQ",
+ (void *)(&vpu_data));
+ if (err)
+ goto err_out_class;
+ if (vpu_power_get(true)) {
+ if (!(cpu_is_mx51() || cpu_is_mx53())) {
+ dev_err(vpu_dev, "failed to get vpu power\n");
+ goto err_out_class;
+ } else {
+ /* regulator_get will return error on MX5x,
+ * just igore it everywhere*/
+ dev_warn(vpu_dev, "failed to get vpu power\n");
+ }
+ }
+
+#ifdef MXC_VPU_HAS_JPU
+ vpu_jpu_irq = platform_get_irq_byname(pdev, "vpu_jpu_irq");
+ if (vpu_jpu_irq < 0) {
+ dev_err(vpu_dev, "vpu: unable to get vpu jpu interrupt\n");
+ err = -ENXIO;
+ free_irq(vpu_ipi_irq, &vpu_data);
+ goto err_out_class;
+ }
+ err = request_irq(vpu_jpu_irq, vpu_jpu_irq_handler, IRQF_TRIGGER_RISING,
+ "VPU_JPG_IRQ", (void *)(&vpu_data));
+ if (err) {
+ free_irq(vpu_ipi_irq, &vpu_data);
+ goto err_out_class;
+ }
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ pm_runtime_enable(&pdev->dev);
+#endif
+
+ vpu_data.workqueue = create_workqueue("vpu_wq");
+ INIT_WORK(&vpu_data.work, vpu_worker_callback);
+ mutex_init(&vpu_data.lock);
+ dev_info(vpu_dev, "VPU initialized\n");
+ goto out;
+
+err_out_class:
+ device_destroy(vpu_class, MKDEV(vpu_major, 0));
+ class_destroy(vpu_class);
+err_out_chrdev:
+ unregister_chrdev(vpu_major, "mxc_vpu");
+error:
+ iounmap(vpu_base);
+out:
+ return err;
+}
+
+static int vpu_dev_remove(struct platform_device *pdev)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ pm_runtime_disable(&pdev->dev);
+#endif
+ free_irq(vpu_ipi_irq, &vpu_data);
+#ifdef MXC_VPU_HAS_JPU
+ free_irq(vpu_jpu_irq, &vpu_data);
+#endif
+ cancel_work_sync(&vpu_data.work);
+ flush_workqueue(vpu_data.workqueue);
+ destroy_workqueue(vpu_data.workqueue);
+
+ iounmap(vpu_base);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ if (iram.start)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+ gen_pool_free(iram_pool, iram_base, iram.end-iram.start+1);
+#else
+ iram_free(iram.start, iram.end-iram.start+1);
+#endif
+#else
+ if (vpu_plat && vpu_plat->iram_enable && vpu_plat->iram_size)
+ iram_free(iram.start, vpu_plat->iram_size);
+#endif
+
+ vpu_power_get(false);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+static int vpu_suspend(struct device *dev)
+#else
+static int vpu_suspend(struct platform_device *pdev, pm_message_t state)
+#endif
+{
+ int i;
+ unsigned long timeout;
+
+ mutex_lock(&vpu_data.lock);
+ if (open_count == 0) {
+ /* VPU is released (all instances are freed),
+ * clock is already off, context is no longer needed,
+ * power is already off on MX6,
+ * gate power on MX51 */
+ if (cpu_is_mx51()) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+ if (vpu_plat->pg)
+ vpu_plat->pg(1);
+#endif
+ }
+ } else {
+ /* Wait for vpu go to idle state, suspect vpu cannot be changed
+ to idle state after about 1 sec */
+ timeout = jiffies + HZ;
+ clk_prepare(vpu_clk);
+ clk_enable(vpu_clk);
+ while (READ_REG(BIT_BUSY_FLAG)) {
+ msleep(1);
+ if (time_after(jiffies, timeout)) {
+ clk_disable(vpu_clk);
+ clk_unprepare(vpu_clk);
+ mutex_unlock(&vpu_data.lock);
+ return -EAGAIN;
+ }
+ }
+ clk_disable(vpu_clk);
+ clk_unprepare(vpu_clk);
+
+ /* Make sure clock is disabled before suspend */
+ vpu_clk_usercount = atomic_read(&clk_cnt_from_ioc);
+ for (i = 0; i < vpu_clk_usercount; i++) {
+ clk_disable(vpu_clk);
+ clk_unprepare(vpu_clk);
+ }
+
+ if (cpu_is_mx53()) {
+ mutex_unlock(&vpu_data.lock);
+ return 0;
+ }
+
+ if (bitwork_mem.cpu_addr != 0) {
+ clk_prepare(vpu_clk);
+ clk_enable(vpu_clk);
+ /* Save 64 registers from BIT_CODE_BUF_ADDR */
+ for (i = 0; i < 64; i++)
+ regBk[i] = READ_REG(BIT_CODE_BUF_ADDR + (i * 4));
+ pc_before_suspend = READ_REG(BIT_CUR_PC);
+ clk_disable(vpu_clk);
+ clk_unprepare(vpu_clk);
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+ if (vpu_plat->pg)
+ vpu_plat->pg(1);
+#endif
+
+ /* If VPU is working before suspend, disable
+ * regulator to make usecount right. */
+ vpu_power_up(false);
+ }
+
+ mutex_unlock(&vpu_data.lock);
+ return 0;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+static int vpu_resume(struct device *dev)
+#else
+static int vpu_resume(struct platform_device *pdev)
+#endif
+{
+ int i;
+
+ mutex_lock(&vpu_data.lock);
+ if (open_count == 0) {
+ /* VPU is released (all instances are freed),
+ * clock should be kept off, context is no longer needed,
+ * power should be kept off on MX6,
+ * disable power gating on MX51 */
+ if (cpu_is_mx51()) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+ if (vpu_plat->pg)
+ vpu_plat->pg(0);
+#endif
+ }
+ } else {
+ if (cpu_is_mx53())
+ goto recover_clk;
+
+ /* If VPU is working before suspend, enable
+ * regulator to make usecount right. */
+ vpu_power_up(true);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+ if (vpu_plat->pg)
+ vpu_plat->pg(0);
+#endif
+
+ if (bitwork_mem.cpu_addr != 0) {
+ u32 *p = (u32 *) bitwork_mem.cpu_addr;
+ u32 data, pc;
+ u16 data_hi;
+ u16 data_lo;
+
+ clk_prepare(vpu_clk);
+ clk_enable(vpu_clk);
+
+ pc = READ_REG(BIT_CUR_PC);
+ if (pc) {
+ dev_warn(vpu_dev, "Not power off after suspend (PC=0x%x)\n", pc);
+ clk_disable(vpu_clk);
+ clk_unprepare(vpu_clk);
+ goto recover_clk;
+ }
+
+ /* Restore registers */
+ for (i = 0; i < 64; i++)
+ WRITE_REG(regBk[i], BIT_CODE_BUF_ADDR + (i * 4));
+
+ WRITE_REG(0x0, BIT_RESET_CTRL);
+ WRITE_REG(0x0, BIT_CODE_RUN);
+ /* MX6 RTL has a bug not to init MBC_SET_SUBBLK_EN on reset */
+#ifdef CONFIG_SOC_IMX6Q
+ WRITE_REG(0x0, MBC_SET_SUBBLK_EN);
+#endif
+
+ /*
+ * Re-load boot code, from the codebuffer in external RAM.
+ * Thankfully, we only need 4096 bytes, same for all platforms.
+ */
+ for (i = 0; i < 2048; i += 4) {
+ data = p[(i / 2) + 1];
+ data_hi = (data >> 16) & 0xFFFF;
+ data_lo = data & 0xFFFF;
+ WRITE_REG((i << 16) | data_hi, BIT_CODE_DOWN);
+ WRITE_REG(((i + 1) << 16) | data_lo,
+ BIT_CODE_DOWN);
+
+ data = p[i / 2];
+ data_hi = (data >> 16) & 0xFFFF;
+ data_lo = data & 0xFFFF;
+ WRITE_REG(((i + 2) << 16) | data_hi,
+ BIT_CODE_DOWN);
+ WRITE_REG(((i + 3) << 16) | data_lo,
+ BIT_CODE_DOWN);
+ }
+
+ if (pc_before_suspend) {
+ WRITE_REG(0x1, BIT_BUSY_FLAG);
+ WRITE_REG(0x1, BIT_CODE_RUN);
+ while (READ_REG(BIT_BUSY_FLAG))
+ ;
+ } else {
+ dev_warn(vpu_dev, "PC=0 before suspend\n");
+ }
+ clk_disable(vpu_clk);
+ clk_unprepare(vpu_clk);
+ }
+
+recover_clk:
+ /* Recover vpu clock */
+ for (i = 0; i < vpu_clk_usercount; i++) {
+ clk_prepare(vpu_clk);
+ clk_enable(vpu_clk);
+ }
+ }
+
+ mutex_unlock(&vpu_data.lock);
+ return 0;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+static int vpu_runtime_suspend(struct device *dev)
+{
+ release_bus_freq(BUS_FREQ_HIGH);
+ return 0;
+}
+
+static int vpu_runtime_resume(struct device *dev)
+{
+ request_bus_freq(BUS_FREQ_HIGH);
+ return 0;
+}
+
+static const struct dev_pm_ops vpu_pm_ops = {
+ SET_RUNTIME_PM_OPS(vpu_runtime_suspend, vpu_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(vpu_suspend, vpu_resume)
+};
+#endif
+
+#else
+#define vpu_suspend NULL
+#define vpu_resume NULL
+#endif /* !CONFIG_PM */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+static const struct of_device_id vpu_of_match[] = {
+ { .compatible = "fsl,imx6-vpu", },
+ {/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, vpu_of_match);
+#endif
+
+/*! Driver definition
+ *
+ */
+static struct platform_driver mxcvpu_driver = {
+ .driver = {
+ .name = "mxc_vpu",
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
+ .of_match_table = vpu_of_match,
+#ifdef CONFIG_PM
+ .pm = &vpu_pm_ops,
+#endif
+#endif
+ },
+ .probe = vpu_dev_probe,
+ .remove = vpu_dev_remove,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+ .suspend = vpu_suspend,
+ .resume = vpu_resume,
+#endif
+};
+
+static int __init vpu_init(void)
+{
+ int ret = platform_driver_register(&mxcvpu_driver);
+
+ init_waitqueue_head(&vpu_queue);
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
+ memblock_analyze();
+ top_address_DRAM = memblock_end_of_DRAM_with_reserved();
+#endif
+
+ return ret;
+}
+
+static void __exit vpu_exit(void)
+{
+ if (vpu_major > 0) {
+ device_destroy(vpu_class, MKDEV(vpu_major, 0));
+ class_destroy(vpu_class);
+ unregister_chrdev(vpu_major, "mxc_vpu");
+ vpu_major = 0;
+ }
+
+ vpu_free_dma_buffer(&bitwork_mem);
+ vpu_free_dma_buffer(&pic_para_mem);
+ vpu_free_dma_buffer(&user_data_mem);
+
+ /* reset VPU state */
+ vpu_power_up(true);
+ clk_prepare(vpu_clk);
+ clk_enable(vpu_clk);
+ vpu_reset();
+ clk_disable(vpu_clk);
+ clk_unprepare(vpu_clk);
+ vpu_power_up(false);
+
+ clk_put(vpu_clk);
+
+ platform_driver_unregister(&mxcvpu_driver);
+ return;
+}
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Linux VPU driver for Freescale i.MX/MXC");
+MODULE_LICENSE("GPL");
+
+module_init(vpu_init);
+module_exit(vpu_exit);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index db28e22edbf9..6ab8454c9683 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -454,4 +454,8 @@ config FUJITSU_ES
source "drivers/net/hyperv/Kconfig"
+config IVSHMEM_NET
+ tristate "IVSHMEM virtual network device"
+ depends on PCI
+
endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 7336cbd3ef5d..7236ec2b0056 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -72,3 +72,5 @@ obj-$(CONFIG_HYPERV_NET) += hyperv/
obj-$(CONFIG_NTB_NETDEV) += ntb_netdev.o
obj-$(CONFIG_FUJITSU_ES) += fjes/
+
+obj-$(CONFIG_IVSHMEM_NET) += ivshmem-net.o
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 22570ea3a8d2..1a61cb0df6ed 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -81,7 +81,7 @@ config CAN_BFIN
config CAN_FLEXCAN
tristate "Support for Freescale FLEXCAN based chips"
- depends on ARM || PPC
+ depends on ARM || ARM64 || PPC
---help---
Say Y here if you want to support for Freescale FlexCAN.
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 47f43bdecd51..7abab349f54d 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -24,15 +24,24 @@
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/can/led.h>
+#include <linux/can/platform/flexcan.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+#include <linux/regmap.h>
#define DRV_NAME "flexcan"
@@ -58,6 +67,7 @@
#define FLEXCAN_MCR_BCC BIT(16)
#define FLEXCAN_MCR_LPRIO_EN BIT(13)
#define FLEXCAN_MCR_AEN BIT(12)
+#define FLEXCAN_MCR_FDEN BIT(11)
#define FLEXCAN_MCR_MAXMB(x) ((x) & 0x7f)
#define FLEXCAN_MCR_IDAM_A (0x0 << 8)
#define FLEXCAN_MCR_IDAM_B (0x1 << 8)
@@ -139,8 +149,25 @@
(FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE)
#define FLEXCAN_ESR_ALL_INT \
(FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | \
- FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT)
-
+ FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT | \
+ FLEXCAN_ESR_WAK_INT)
+
+/* FLEXCAN Bit Timing register (CBT) bits */
+#define FLEXCAN_CBT_BTF BIT(31)
+#define FLEXCAN_CBT_EPRESDIV(x) (((x) & 0x3ff) << 21)
+#define FLEXCAN_CBT_ERJW(x) (((x) & 0x1f) << 16)
+#define FLEXCAN_CBT_EPROPSEG(x) (((x) & 0x3f) << 10)
+#define FLEXCAN_CBT_EPSEG1(x) (((x) & 0x1f) << 5)
+#define FLEXCAN_CBT_EPSEG2(x) ((x) & 0x1f)
+
+/* FLEXCAN FD Bit Timing register (FDCBT) bits */
+#define FLEXCAN_FDCBT_FPRESDIV(x) (((x) & 0x3ff) << 20)
+#define FLEXCAN_FDCBT_FRJW(x) (((x) & 0x07) << 16)
+#define FLEXCAN_FDCBT_FPROPSEG(x) (((x) & 0x1f) << 10)
+#define FLEXCAN_FDCBT_FPSEG1(x) (((x) & 0x07) << 5)
+#define FLEXCAN_FDCBT_FPSEG2(x) ((x) & 0x07)
+
+#define FLEXCAN_RX_BUF_ID 0
/* FLEXCAN interrupt flag register (IFLAG) bits */
/* Errata ERR005829 step7: Reserve first valid MB */
#define FLEXCAN_TX_BUF_RESERVED 8
@@ -149,17 +176,29 @@
#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7)
#define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6)
#define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5)
-#define FLEXCAN_IFLAG_DEFAULT \
+/* FIFO mode using MB0 as the Message Output Buffer */
+#define FLEXCAN_RX_BUF_FIFO 0
+
+#define FLEXCAN_RX_BUF_INT \
+ FLEXCAN_IFLAG_BUF(FLEXCAN_RX_BUF_ID)
+#define FLEXCAN_TX_BUF_INT \
+ FLEXCAN_IFLAG_BUF(FLEXCAN_TX_BUF_ID)
+#define FLEXCAN_IFLAG_DEFAULT_FIFO \
(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | FLEXCAN_IFLAG_RX_FIFO_AVAILABLE | \
- FLEXCAN_IFLAG_BUF(FLEXCAN_TX_BUF_ID))
+ FLEXCAN_TX_BUF_INT)
+#define FLEXCAN_IFLAG_DEFAULT_MB \
+ (FLEXCAN_RX_BUF_INT | FLEXCAN_TX_BUF_INT)
/* FLEXCAN message buffers */
+#define FLEXCAN_MB_CNT_EDL BIT(31)
+#define FLEXCAN_MB_CNT_BRS BIT(30)
+#define FLEXCAN_MB_CNT_ESI BIT(29)
+
#define FLEXCAN_MB_CODE_RX_INACTIVE (0x0 << 24)
#define FLEXCAN_MB_CODE_RX_EMPTY (0x4 << 24)
#define FLEXCAN_MB_CODE_RX_FULL (0x2 << 24)
#define FLEXCAN_MB_CODE_RX_OVERRUN (0x6 << 24)
#define FLEXCAN_MB_CODE_RX_RANSWER (0xa << 24)
-
#define FLEXCAN_MB_CODE_TX_INACTIVE (0x8 << 24)
#define FLEXCAN_MB_CODE_TX_ABORT (0x9 << 24)
#define FLEXCAN_MB_CODE_TX_DATA (0xc << 24)
@@ -173,6 +212,8 @@
#define FLEXCAN_TIMEOUT_US (50)
+#define FLEXCAN_FDCTRL_FDRATE BIT(31)
+
/* FLEXCAN hardware feature flags
*
* Below is some version info we got:
@@ -190,76 +231,141 @@
#define FLEXCAN_QUIRK_BROKEN_ERR_STATE BIT(1) /* [TR]WRN_INT not connected */
#define FLEXCAN_QUIRK_DISABLE_RXFG BIT(2) /* Disable RX FIFO Global mask */
#define FLEXCAN_QUIRK_DISABLE_MECR BIT(3) /* Disble Memory error detection */
+#define FLEXCAN_QUIRK_DISABLE_RX_FIFO BIT(4) /* Disable RX FIFO mode */
+#define FLEXCAN_QUIRK_SUPPORT_CANFD BIT(5) /* Support CAN FD mode */
-/* Structure of the message buffer */
-struct flexcan_mb {
- u32 can_ctrl;
- u32 can_id;
- u32 data[2];
-};
-/* Structure of the hardware registers */
-struct flexcan_regs {
- u32 mcr; /* 0x00 */
- u32 ctrl; /* 0x04 */
- u32 timer; /* 0x08 */
- u32 _reserved1; /* 0x0c */
- u32 rxgmask; /* 0x10 */
- u32 rx14mask; /* 0x14 */
- u32 rx15mask; /* 0x18 */
- u32 ecr; /* 0x1c */
- u32 esr; /* 0x20 */
- u32 imask2; /* 0x24 */
- u32 imask1; /* 0x28 */
- u32 iflag2; /* 0x2c */
- u32 iflag1; /* 0x30 */
- u32 ctrl2; /* 0x34 */
- u32 esr2; /* 0x38 */
- u32 imeur; /* 0x3c */
- u32 lrfr; /* 0x40 */
- u32 crcr; /* 0x44 */
- u32 rxfgmask; /* 0x48 */
- u32 rxfir; /* 0x4c */
- u32 _reserved3[12]; /* 0x50 */
- struct flexcan_mb mb[64]; /* 0x80 */
- /* FIFO-mode:
- * MB
- * 0x080...0x08f 0 RX message buffer
- * 0x090...0x0df 1-5 reserverd
- * 0x0e0...0x0ff 6-7 8 entry ID table
- * (mx25, mx28, mx35, mx53)
- * 0x0e0...0x2df 6-7..37 8..128 entry ID table
- * size conf'ed via ctrl2::RFFN
- * (mx6, vf610)
- */
- u32 _reserved4[408];
- u32 mecr; /* 0xae0 */
- u32 erriar; /* 0xae4 */
- u32 erridpr; /* 0xae8 */
- u32 errippr; /* 0xaec */
- u32 rerrar; /* 0xaf0 */
- u32 rerrdr; /* 0xaf4 */
- u32 rerrsynr; /* 0xaf8 */
- u32 errsr; /* 0xafc */
+/* Message Buffer */
+#define FLEXCAN_MB_CTRL 0x0
+#define FLEXCAN_MB_ID 0x4
+#define FLEXCAN_MB_DATA(n) (0x8 + ((n) << 2))
+
+#define FLEXCAN_MB_NUM 64
+#define FLEXCAN_MB_FD_NUM 14
+#define FLEXCAN_MB_SIZE 16
+#define FLEXCAN_MB_FD_SIZE 72
+
+/* CAN FD Memory Partition
+ *
+ * When CAN FD is enabled, the FlexCAN RAM can be partitioned in
+ * blocks of 512 bytes. Each block can accommodate a number of
+ * Message Buffers which depends on the configuration provided
+ * by CAN_FDCTRL[MBDSRn] bit fields where we all set to 64 bytes
+ * per Message Buffer and 7 MBs per Block by default.
+ *
+ * There're two RAM blocks: RAM block 0,1
+ */
+#define FLEXCAN_CANFD_MB_OFFSET(n) (((n) / 7) * 512 + ((n) % 7) * \
+ FLEXCAN_MB_FD_SIZE)
+#define FLEXCAN_CANFD_MBDSR_MASK 0x6db0000
+#define FLEXCAN_CANFD_MBDSR_SHIFT 16
+#define FLEXCAN_CANFD_MBDSR_DEFAULT 0x6db
+
+/*
+ * NOTE:
+ * To minimize errors when processing FD frames, use the same value
+ * for FPRESDIV and PRESDIV (in CAN_CBT or CAN_CTRL1).
+ * For more details refer to the first NOTE in section CAN FD frames.
+ *
+ * CAN FD supported rates combinations
+ *
+ * Combination 1:
+ * Bitrate: 225000 375000 400000 425000 500000 875000
+ * Data rate: 1000000
+ *
+ * Combination 2:
+ * Bitrate: 550000 600000 625000 650000 675000 750000 775000
+ * 800000 850000 925000 950000 975000 1000000
+ * Data rate: 1500000 2000000 2500000 3000000 3500000 4000000
+ * 5000000
+ */
+
+/* registers definition
+ *
+ * FIFO-MODE:
+ * MB
+ * 0X080...0X08F 0 RX MESSAGE BUFFER
+ * 0X090...0X0DF 1-5 RESERVERD
+ * 0X0E0...0X0FF 6-7 8 ENTRY ID TABLE
+ * (MX25, MX28, MX35, MX53)
+ * 0X0E0...0X2DF 6-7..37 8..128 ENTRY ID TABLE
+ * SIZE CONF'ED VIA CTRL2::RFFN
+ * (MX6, VF610)
+ */
+
+enum flexcan_reg {
+ FLEXCAN_MCR = 0x00,
+ FLEXCAN_CTRL = 0x04,
+ FLEXCAN_TIMER = 0x08,
+ FLEXCAN_RXGMASK = 0x10,
+ FLEXCAN_RX14MASK = 0x14,
+ FLEXCAN_RX15MASK = 0x18,
+ FLEXCAN_ECR = 0x1c,
+ FLEXCAN_ESR = 0x20,
+ FLEXCAN_IMASK2 = 0x24,
+ FLEXCAN_IMASK1 = 0x28,
+ FLEXCAN_IFLAG2 = 0x2c,
+ FLEXCAN_IFLAG1 = 0x30,
+ FLEXCAN_CTRL2 = 0x34,
+ FLEXCAN_ESR2 = 0x38,
+ FLEXCAN_IMEUR = 0x3c,
+ FLEXCAN_LRFR = 0x40,
+ FLEXCAN_CRCR = 0x44,
+ FLEXCAN_RXFGMASK = 0x48,
+ FLEXCAN_RXFIR = 0x4c,
+ FLEXCAN_CBT = 0x50,
+ FLEXCAN_MB = 0x80,
+ FLEXCAN_MECR = 0xae0,
+ FLEXCAN_ERRIAR = 0xae4,
+ FLEXCAN_ERRIDPR = 0xae8,
+ FLEXCAN_ERRIPPR = 0xaeC,
+ FLEXCAN_RERRAR = 0xaf0,
+ FLEXCAN_RERRDR = 0xaf4,
+ FLEXCAN_RERRSYNR = 0xaf8,
+ FLEXCAN_ERRSR = 0xafC,
+ FLEXCAN_FDCTRL = 0xc00,
+ FLEXCAN_FDCBT = 0xc04,
+ FLEXCAN_FDCRC = 0xc08,
};
struct flexcan_devtype_data {
u32 quirks; /* quirks needed for different IP cores */
};
+struct flexcan_stop_mode {
+ struct regmap *gpr;
+ u8 req_gpr;
+ u8 req_bit;
+ u8 ack_gpr;
+ u8 ack_bit;
+};
struct flexcan_priv {
struct can_priv can;
struct napi_struct napi;
- struct flexcan_regs __iomem *regs;
+ void __iomem *base;
u32 reg_esr;
u32 reg_ctrl_default;
+ struct device *dev;
struct clk *clk_ipg;
struct clk *clk_per;
struct flexcan_platform_data *pdata;
const struct flexcan_devtype_data *devtype_data;
struct regulator *reg_xceiver;
+ int id;
+ struct flexcan_stop_mode stm;
+
+ bool mb_mode;
+ u32 iflag_default;
+ /* Rx interrupt can be either Rx fifo or Rx buffer interrupt */
+ u32 rx_int;
+
+ u32 mb_size;
+ u32 mb_num;
+
+ /* Selects the clock source to PE, 1 by default */
+ u32 clk_src;
};
static struct flexcan_devtype_data fsl_p1010_devtype_data = {
@@ -272,6 +378,11 @@ static struct flexcan_devtype_data fsl_imx6q_devtype_data = {
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG,
};
+static struct flexcan_devtype_data fsl_imx8qm_devtype_data = {
+ .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_DISABLE_RX_FIFO |
+ FLEXCAN_QUIRK_SUPPORT_CANFD,
+};
+
static struct flexcan_devtype_data fsl_vf610_devtype_data = {
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_DISABLE_MECR,
};
@@ -288,35 +399,151 @@ static const struct can_bittiming_const flexcan_bittiming_const = {
.brp_inc = 1,
};
+static const struct can_bittiming_const flexcan_fd_bittiming_const = {
+ .name = DRV_NAME,
+ .tseg1_min = 2,
+ .tseg1_max = 64,
+ .tseg2_min = 1,
+ .tseg2_max = 32,
+ .sjw_max = 32,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+};
+
+static const struct can_bittiming_const flexcan_fd_data_bittiming_const = {
+ .name = DRV_NAME,
+ .tseg1_min = 1,
+ .tseg1_max = 39,
+ .tseg2_min = 1,
+ .tseg2_max = 8,
+ .sjw_max = 8,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+};
+
/* Abstract off the read/write for arm versus ppc. This
* assumes that PPC uses big-endian registers and everything
* else uses little-endian registers, independent of CPU
* endianness.
*/
#if defined(CONFIG_PPC)
-static inline u32 flexcan_read(void __iomem *addr)
+static inline u32 flexcan_read(const struct flexcan_priv *priv,
+ enum flexcan_reg reg)
+{
+ return in_be32(priv->base + reg);
+}
+
+static inline void flexcan_write(const struct flexcan_priv *priv,
+ enum flexcan_reg reg, u32 val)
+{
+ out_be32(priv->base + reg, val);
+}
+
+static inline u32 flexcan_mb_read(const struct flexcan_priv *priv,
+ u32 index, unsigned int offset)
{
- return in_be32(addr);
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
+ return in_be32(priv->base + FLEXCAN_MB +
+ FLEXCAN_CANFD_MB_OFFSET(index) + offset);
+ else
+ return in_be32(priv->base + FLEXCAN_MB +
+ priv->mb_size * index + offset);
}
-static inline void flexcan_write(u32 val, void __iomem *addr)
+static inline void flexcan_mb_write(const struct flexcan_priv *priv,
+ u32 index, unsigned int offset,
+ u32 val)
{
- out_be32(addr, val);
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
+ out_be32(val, priv->base + FLEXCAN_MB +
+ FLEXCAN_CANFD_MB_OFFSET(index) + offset);
+ else
+ out_be32(val, priv->base + FLEXCAN_MB +
+ priv->mb_size * index + offset);
}
#else
-static inline u32 flexcan_read(void __iomem *addr)
+static inline u32 flexcan_read(const struct flexcan_priv *priv,
+ enum flexcan_reg reg)
+{
+ return readl(priv->base + reg);
+}
+
+static inline void flexcan_write(const struct flexcan_priv *priv,
+ enum flexcan_reg reg, u32 val)
{
- return readl(addr);
+ writel(val, priv->base + reg);
}
-static inline void flexcan_write(u32 val, void __iomem *addr)
+static inline u32 flexcan_mb_read(const struct flexcan_priv *priv,
+ u32 index, unsigned int offset)
{
- writel(val, addr);
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
+ return readl(priv->base + FLEXCAN_MB +
+ FLEXCAN_CANFD_MB_OFFSET(index) + offset);
+ else
+ return readl(priv->base + FLEXCAN_MB +
+ priv->mb_size * index + offset);
+}
+
+static inline void flexcan_mb_write(const struct flexcan_priv *priv,
+ u32 index, unsigned int offset,
+ u32 val)
+{
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
+ writel(val, priv->base + FLEXCAN_MB +
+ FLEXCAN_CANFD_MB_OFFSET(index) + offset);
+ else
+ writel(val, priv->base + FLEXCAN_MB +
+ priv->mb_size * index + offset);
}
#endif
+static int flexcan_clks_enable(const struct flexcan_priv *priv)
+{
+ int err;
+
+ err = clk_prepare_enable(priv->clk_ipg);
+ if (err)
+ return err;
+
+ err = clk_prepare_enable(priv->clk_per);
+ if (err)
+ clk_disable_unprepare(priv->clk_ipg);
+
+ return err;
+}
+
+static void flexcan_clks_disable(const struct flexcan_priv *priv)
+{
+ clk_disable_unprepare(priv->clk_ipg);
+ clk_disable_unprepare(priv->clk_per);
+}
+
+static inline void flexcan_enter_stop_mode(struct flexcan_priv *priv)
+{
+ /* enable stop request */
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG)
+ regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
+ 1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
+}
+
+static inline void flexcan_exit_stop_mode(struct flexcan_priv *priv)
+{
+ /* remove stop request */
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG)
+ regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
+ 1 << priv->stm.req_bit, 0);
+}
+
static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv)
{
+ if (priv->pdata && priv->pdata->transceiver_switch) {
+ priv->pdata->transceiver_switch(1);
+ return 0;
+ }
+
if (!priv->reg_xceiver)
return 0;
@@ -325,6 +552,11 @@ static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv)
static inline int flexcan_transceiver_disable(const struct flexcan_priv *priv)
{
+ if (priv->pdata && priv->pdata->transceiver_switch) {
+ priv->pdata->transceiver_switch(0);
+ return 0;
+ }
+
if (!priv->reg_xceiver)
return 0;
@@ -340,18 +572,18 @@ static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
static int flexcan_chip_enable(struct flexcan_priv *priv)
{
- struct flexcan_regs __iomem *regs = priv->regs;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg;
- reg = flexcan_read(&regs->mcr);
+ reg = flexcan_read(priv, FLEXCAN_MCR);
reg &= ~FLEXCAN_MCR_MDIS;
- flexcan_write(reg, &regs->mcr);
+ flexcan_write(priv, FLEXCAN_MCR, reg);
- while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+ while (timeout-- &&
+ (flexcan_read(priv, FLEXCAN_MCR) & FLEXCAN_MCR_LPM_ACK))
udelay(10);
- if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK)
+ if (flexcan_read(priv, FLEXCAN_MCR) & FLEXCAN_MCR_LPM_ACK)
return -ETIMEDOUT;
return 0;
@@ -359,18 +591,18 @@ static int flexcan_chip_enable(struct flexcan_priv *priv)
static int flexcan_chip_disable(struct flexcan_priv *priv)
{
- struct flexcan_regs __iomem *regs = priv->regs;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg;
- reg = flexcan_read(&regs->mcr);
+ reg = flexcan_read(priv, FLEXCAN_MCR);
reg |= FLEXCAN_MCR_MDIS;
- flexcan_write(reg, &regs->mcr);
+ flexcan_write(priv, FLEXCAN_MCR, reg);
- while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+ while (timeout-- &&
+ !(flexcan_read(priv, FLEXCAN_MCR) & FLEXCAN_MCR_LPM_ACK))
udelay(10);
- if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+ if (!(flexcan_read(priv, FLEXCAN_MCR) & FLEXCAN_MCR_LPM_ACK))
return -ETIMEDOUT;
return 0;
@@ -378,18 +610,18 @@ static int flexcan_chip_disable(struct flexcan_priv *priv)
static int flexcan_chip_freeze(struct flexcan_priv *priv)
{
- struct flexcan_regs __iomem *regs = priv->regs;
unsigned int timeout = 1000 * 1000 * 10 / priv->can.bittiming.bitrate;
u32 reg;
- reg = flexcan_read(&regs->mcr);
+ reg = flexcan_read(priv, FLEXCAN_MCR);
reg |= FLEXCAN_MCR_HALT;
- flexcan_write(reg, &regs->mcr);
+ flexcan_write(priv, FLEXCAN_MCR, reg);
- while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+ while (timeout-- &&
+ !(flexcan_read(priv, FLEXCAN_MCR) & FLEXCAN_MCR_FRZ_ACK))
udelay(100);
- if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+ if (!(flexcan_read(priv, FLEXCAN_MCR) & FLEXCAN_MCR_FRZ_ACK))
return -ETIMEDOUT;
return 0;
@@ -397,18 +629,18 @@ static int flexcan_chip_freeze(struct flexcan_priv *priv)
static int flexcan_chip_unfreeze(struct flexcan_priv *priv)
{
- struct flexcan_regs __iomem *regs = priv->regs;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
u32 reg;
- reg = flexcan_read(&regs->mcr);
+ reg = flexcan_read(priv, FLEXCAN_MCR);
reg &= ~FLEXCAN_MCR_HALT;
- flexcan_write(reg, &regs->mcr);
+ flexcan_write(priv, FLEXCAN_MCR, reg);
- while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
- udelay(10);
+ while (timeout-- &&
+ (flexcan_read(priv, FLEXCAN_MCR) & FLEXCAN_MCR_FRZ_ACK))
+ udelay(20);
- if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK)
+ if (flexcan_read(priv, FLEXCAN_MCR) & FLEXCAN_MCR_FRZ_ACK)
return -ETIMEDOUT;
return 0;
@@ -416,14 +648,14 @@ static int flexcan_chip_unfreeze(struct flexcan_priv *priv)
static int flexcan_chip_softreset(struct flexcan_priv *priv)
{
- struct flexcan_regs __iomem *regs = priv->regs;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
- flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr);
- while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_SOFTRST))
+ flexcan_write(priv, FLEXCAN_MCR, FLEXCAN_MCR_SOFTRST);
+ while (timeout-- &&
+ (flexcan_read(priv, FLEXCAN_MCR) & FLEXCAN_MCR_SOFTRST))
udelay(10);
- if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_SOFTRST)
+ if (flexcan_read(priv, FLEXCAN_MCR) & FLEXCAN_MCR_SOFTRST)
return -ETIMEDOUT;
return 0;
@@ -433,8 +665,7 @@ static int __flexcan_get_berr_counter(const struct net_device *dev,
struct can_berr_counter *bec)
{
const struct flexcan_priv *priv = netdev_priv(dev);
- struct flexcan_regs __iomem *regs = priv->regs;
- u32 reg = flexcan_read(&regs->ecr);
+ u32 reg = flexcan_read(priv, FLEXCAN_ECR);
bec->txerr = (reg >> 0) & 0xff;
bec->rxerr = (reg >> 8) & 0xff;
@@ -448,19 +679,11 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
const struct flexcan_priv *priv = netdev_priv(dev);
int err;
- err = clk_prepare_enable(priv->clk_ipg);
- if (err)
- return err;
-
- err = clk_prepare_enable(priv->clk_per);
- if (err)
- goto out_disable_ipg;
+ pm_runtime_get_sync(priv->dev);
err = __flexcan_get_berr_counter(dev, bec);
- clk_disable_unprepare(priv->clk_per);
- out_disable_ipg:
- clk_disable_unprepare(priv->clk_ipg);
+ pm_runtime_put(priv->dev);
return err;
}
@@ -468,11 +691,11 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
const struct flexcan_priv *priv = netdev_priv(dev);
- struct flexcan_regs __iomem *regs = priv->regs;
- struct can_frame *cf = (struct can_frame *)skb->data;
- u32 can_id;
+ struct canfd_frame *cf = (struct canfd_frame *)skb->data;
+ u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (can_len2dlc(cf->len) << 16);
+ u32 can_id, reg_fdctrl;
u32 data;
- u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cf->can_dlc << 16);
+ int i;
if (can_dropped_invalid_skb(dev, skb))
return NETDEV_TX_OK;
@@ -489,27 +712,38 @@ static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (cf->can_id & CAN_RTR_FLAG)
ctrl |= FLEXCAN_MB_CNT_RTR;
- if (cf->can_dlc > 0) {
- data = be32_to_cpup((__be32 *)&cf->data[0]);
- flexcan_write(data, &regs->mb[FLEXCAN_TX_BUF_ID].data[0]);
- }
- if (cf->can_dlc > 4) {
- data = be32_to_cpup((__be32 *)&cf->data[4]);
- flexcan_write(data, &regs->mb[FLEXCAN_TX_BUF_ID].data[1]);
+ for (i = 0; i < cf->len; i += 4) {
+ data = be32_to_cpup((__be32 *)&cf->data[i]);
+ flexcan_mb_write(priv, FLEXCAN_TX_BUF_ID,
+ FLEXCAN_MB_DATA(i / 4), data);
}
can_put_echo_skb(skb, dev, 0);
- flexcan_write(can_id, &regs->mb[FLEXCAN_TX_BUF_ID].can_id);
- flexcan_write(ctrl, &regs->mb[FLEXCAN_TX_BUF_ID].can_ctrl);
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ if (can_is_canfd_skb(skb)) {
+ reg_fdctrl = flexcan_read(priv, FLEXCAN_FDCTRL) &
+ ~FLEXCAN_FDCTRL_FDRATE;
+ if (cf->flags & CANFD_BRS) {
+ reg_fdctrl |= FLEXCAN_FDCTRL_FDRATE;
+ ctrl |= FLEXCAN_MB_CNT_BRS;
+ }
+ flexcan_write(priv, FLEXCAN_FDCTRL, reg_fdctrl);
+ ctrl |= FLEXCAN_MB_CNT_EDL;
+ }
+ }
+
+ flexcan_mb_write(priv, FLEXCAN_TX_BUF_ID, FLEXCAN_MB_ID, can_id);
+ flexcan_mb_write(priv, FLEXCAN_TX_BUF_ID, FLEXCAN_MB_CTRL, ctrl);
/* Errata ERR005829 step8:
* Write twice INACTIVE(0x8) code to first MB.
*/
- flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
- &regs->mb[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
- flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
- &regs->mb[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
+ flexcan_mb_write(priv, FLEXCAN_TX_BUF_RESERVED, FLEXCAN_MB_CTRL,
+ FLEXCAN_MB_CODE_TX_INACTIVE);
+
+ flexcan_mb_write(priv, FLEXCAN_TX_BUF_RESERVED, FLEXCAN_MB_CTRL,
+ FLEXCAN_MB_CODE_TX_INACTIVE);
return NETDEV_TX_OK;
}
@@ -624,49 +858,75 @@ static int flexcan_poll_state(struct net_device *dev, u32 reg_esr)
return 1;
}
-static void flexcan_read_fifo(const struct net_device *dev,
- struct can_frame *cf)
+static void flexcan_read_mb(const struct net_device *dev,
+ struct canfd_frame *cf)
{
const struct flexcan_priv *priv = netdev_priv(dev);
- struct flexcan_regs __iomem *regs = priv->regs;
- struct flexcan_mb __iomem *mb = &regs->mb[0];
u32 reg_ctrl, reg_id;
+ u32 index;
+ int i;
- reg_ctrl = flexcan_read(&mb->can_ctrl);
- reg_id = flexcan_read(&mb->can_id);
+ index = priv->mb_mode ? FLEXCAN_RX_BUF_ID : FLEXCAN_RX_BUF_FIFO;
+ reg_ctrl = flexcan_mb_read(priv, index, FLEXCAN_MB_CTRL);
+ reg_id = flexcan_mb_read(priv, index, FLEXCAN_MB_ID);
if (reg_ctrl & FLEXCAN_MB_CNT_IDE)
cf->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
cf->can_id = (reg_id >> 18) & CAN_SFF_MASK;
- if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
+ if (reg_ctrl & FLEXCAN_MB_CNT_EDL)
+ cf->len = can_dlc2len((reg_ctrl >> 16) & 0x0F);
+ else
+ cf->len = get_can_dlc((reg_ctrl >> 16) & 0x0F);
+
+ if (reg_ctrl & FLEXCAN_MB_CNT_ESI) {
+ cf->flags |= CANFD_ESI;
+ netdev_warn(dev, "ESI Error\n");
+ }
+
+ if (!(reg_ctrl & FLEXCAN_MB_CNT_EDL) && reg_ctrl & FLEXCAN_MB_CNT_RTR) {
cf->can_id |= CAN_RTR_FLAG;
- cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf);
+ } else {
+ if (reg_ctrl & FLEXCAN_MB_CNT_BRS)
+ cf->flags |= CANFD_BRS;
- *(__be32 *)(cf->data + 0) = cpu_to_be32(flexcan_read(&mb->data[0]));
- *(__be32 *)(cf->data + 4) = cpu_to_be32(flexcan_read(&mb->data[1]));
+ for (i = 0; i < cf->len; i += 4)
+ *(__be32 *)(cf->data + i) =
+ cpu_to_be32(flexcan_mb_read(priv, index,
+ FLEXCAN_MB_DATA(i / 4)));
+ }
/* mark as read */
- flexcan_write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->iflag1);
- flexcan_read(&regs->timer);
+ flexcan_write(priv, FLEXCAN_IFLAG1, priv->rx_int);
+ flexcan_read(priv, FLEXCAN_TIMER);
}
static int flexcan_read_frame(struct net_device *dev)
{
struct net_device_stats *stats = &dev->stats;
- struct can_frame *cf;
+ const struct flexcan_priv *priv = netdev_priv(dev);
+ struct canfd_frame *cf;
struct sk_buff *skb;
+ u32 reg_ctrl;
+ u32 index;
+
+ index = priv->mb_mode ? FLEXCAN_RX_BUF_ID : FLEXCAN_RX_BUF_FIFO;
+ reg_ctrl = flexcan_mb_read(priv, index, FLEXCAN_MB_CTRL);
+
+ if (reg_ctrl & FLEXCAN_MB_CNT_EDL)
+ skb = alloc_canfd_skb(dev, &cf);
+ else
+ skb = alloc_can_skb(dev, (struct can_frame **)&cf);
- skb = alloc_can_skb(dev, &cf);
if (unlikely(!skb)) {
stats->rx_dropped++;
return 0;
}
- flexcan_read_fifo(dev, cf);
+ flexcan_read_mb(dev, cf);
stats->rx_packets++;
- stats->rx_bytes += cf->can_dlc;
+ stats->rx_bytes += cf->len;
netif_receive_skb(skb);
can_led_event(dev, CAN_LED_EVENT_RX);
@@ -678,24 +938,22 @@ static int flexcan_poll(struct napi_struct *napi, int quota)
{
struct net_device *dev = napi->dev;
const struct flexcan_priv *priv = netdev_priv(dev);
- struct flexcan_regs __iomem *regs = priv->regs;
u32 reg_iflag1, reg_esr;
int work_done = 0;
/* The error bits are cleared on read,
* use saved value from irq handler.
*/
- reg_esr = flexcan_read(&regs->esr) | priv->reg_esr;
+ reg_esr = flexcan_read(priv, FLEXCAN_ESR) | priv->reg_esr;
/* handle state changes */
work_done += flexcan_poll_state(dev, reg_esr);
- /* handle RX-FIFO */
- reg_iflag1 = flexcan_read(&regs->iflag1);
- while (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE &&
- work_done < quota) {
+ /* handle RX MB */
+ reg_iflag1 = flexcan_read(priv, FLEXCAN_IFLAG1);
+ while (reg_iflag1 & priv->rx_int && work_done < quota) {
work_done += flexcan_read_frame(dev);
- reg_iflag1 = flexcan_read(&regs->iflag1);
+ reg_iflag1 = flexcan_read(priv, FLEXCAN_IFLAG1);
}
/* report bus errors */
@@ -705,8 +963,8 @@ static int flexcan_poll(struct napi_struct *napi, int quota)
if (work_done < quota) {
napi_complete(napi);
/* enable IRQs */
- flexcan_write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
- flexcan_write(priv->reg_ctrl_default, &regs->ctrl);
+ flexcan_write(priv, FLEXCAN_IMASK1, priv->iflag_default);
+ flexcan_write(priv, FLEXCAN_CTRL, priv->reg_ctrl_default);
}
return work_done;
@@ -717,38 +975,41 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
struct net_device *dev = dev_id;
struct net_device_stats *stats = &dev->stats;
struct flexcan_priv *priv = netdev_priv(dev);
- struct flexcan_regs __iomem *regs = priv->regs;
u32 reg_iflag1, reg_esr;
- reg_iflag1 = flexcan_read(&regs->iflag1);
- reg_esr = flexcan_read(&regs->esr);
+ reg_iflag1 = flexcan_read(priv, FLEXCAN_IFLAG1);
+ reg_esr = flexcan_read(priv, FLEXCAN_ESR);
/* ACK all bus error and state change IRQ sources */
if (reg_esr & FLEXCAN_ESR_ALL_INT)
- flexcan_write(reg_esr & FLEXCAN_ESR_ALL_INT, &regs->esr);
+ flexcan_write(priv, FLEXCAN_ESR, reg_esr & FLEXCAN_ESR_ALL_INT);
+
+ if (reg_esr & FLEXCAN_ESR_WAK_INT)
+ flexcan_exit_stop_mode(priv);
/* schedule NAPI in case of:
* - rx IRQ
* - state change IRQ
* - bus error IRQ and bus error reporting is activated
*/
- if ((reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) ||
+ if ((reg_iflag1 & priv->rx_int) ||
(reg_esr & FLEXCAN_ESR_ERR_STATE) ||
flexcan_has_and_handle_berr(priv, reg_esr)) {
/* The error bits are cleared on read,
* save them for later use.
*/
priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS;
- flexcan_write(FLEXCAN_IFLAG_DEFAULT &
- ~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->imask1);
- flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
- &regs->ctrl);
+ flexcan_write(priv, FLEXCAN_IMASK1, priv->iflag_default &
+ ~priv->rx_int);
+ flexcan_write(priv, FLEXCAN_CTRL, priv->reg_ctrl_default &
+ ~FLEXCAN_CTRL_ERR_ALL);
napi_schedule(&priv->napi);
}
/* FIFO overflow */
if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) {
- flexcan_write(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW, &regs->iflag1);
+ flexcan_write(priv, FLEXCAN_IFLAG1,
+ FLEXCAN_IFLAG_RX_FIFO_OVERFLOW);
dev->stats.rx_over_errors++;
dev->stats.rx_errors++;
}
@@ -760,9 +1021,9 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
can_led_event(dev, CAN_LED_EVENT_TX);
/* after sending a RTR frame MB is in RX mode */
- flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
- &regs->mb[FLEXCAN_TX_BUF_ID].can_ctrl);
- flexcan_write((1 << FLEXCAN_TX_BUF_ID), &regs->iflag1);
+ flexcan_mb_write(priv, FLEXCAN_TX_BUF_ID, FLEXCAN_MB_CTRL,
+ FLEXCAN_MB_CODE_TX_INACTIVE);
+ flexcan_write(priv, FLEXCAN_IFLAG1, 1 << FLEXCAN_TX_BUF_ID);
netif_wake_queue(dev);
}
@@ -773,38 +1034,75 @@ static void flexcan_set_bittiming(struct net_device *dev)
{
const struct flexcan_priv *priv = netdev_priv(dev);
const struct can_bittiming *bt = &priv->can.bittiming;
- struct flexcan_regs __iomem *regs = priv->regs;
+ const struct can_bittiming *dbt = &priv->can.data_bittiming;
u32 reg;
- reg = flexcan_read(&regs->ctrl);
- reg &= ~(FLEXCAN_CTRL_PRESDIV(0xff) |
- FLEXCAN_CTRL_RJW(0x3) |
- FLEXCAN_CTRL_PSEG1(0x7) |
- FLEXCAN_CTRL_PSEG2(0x7) |
- FLEXCAN_CTRL_PROPSEG(0x7) |
- FLEXCAN_CTRL_LPB |
- FLEXCAN_CTRL_SMP |
- FLEXCAN_CTRL_LOM);
-
- reg |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) |
- FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) |
- FLEXCAN_CTRL_PSEG2(bt->phase_seg2 - 1) |
- FLEXCAN_CTRL_RJW(bt->sjw - 1) |
- FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1);
-
+ reg = flexcan_read(priv, FLEXCAN_CTRL);
+ reg &= ~(FLEXCAN_CTRL_LPB | FLEXCAN_CTRL_SMP | FLEXCAN_CTRL_LOM);
if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
reg |= FLEXCAN_CTRL_LPB;
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
reg |= FLEXCAN_CTRL_LOM;
if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
reg |= FLEXCAN_CTRL_SMP;
-
- netdev_dbg(dev, "writing ctrl=0x%08x\n", reg);
- flexcan_write(reg, &regs->ctrl);
-
- /* print chip status */
- netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
- flexcan_read(&regs->mcr), flexcan_read(&regs->ctrl));
+ flexcan_write(priv, FLEXCAN_CTRL, reg);
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ reg = FLEXCAN_CBT_EPRESDIV(bt->brp - 1) |
+ FLEXCAN_CBT_EPSEG1(bt->phase_seg1 - 1) |
+ FLEXCAN_CBT_EPSEG2(bt->phase_seg2 - 1) |
+ FLEXCAN_CBT_ERJW(bt->sjw - 1) |
+ FLEXCAN_CBT_EPROPSEG(bt->prop_seg - 1) |
+ FLEXCAN_CBT_BTF;
+ flexcan_write(priv, FLEXCAN_CBT, reg);
+
+ netdev_dbg(dev, "bt: prediv %d seg1 %d seg2 %d rjw %d propseg %d\n",
+ bt->brp - 1, bt->phase_seg1 - 1, bt->phase_seg2 - 1,
+ bt->sjw - 1, bt->prop_seg - 1);
+
+ reg = FLEXCAN_FDCBT_FPRESDIV(dbt->brp - 1) |
+ FLEXCAN_FDCBT_FPSEG1(dbt->phase_seg1 - 1) |
+ FLEXCAN_FDCBT_FPSEG2(dbt->phase_seg2 - 1) |
+ FLEXCAN_FDCBT_FRJW(dbt->sjw - 1) |
+ FLEXCAN_FDCBT_FPROPSEG(dbt->prop_seg);
+ flexcan_write(priv, FLEXCAN_FDCBT, reg);
+
+ if (bt->brp != dbt->brp)
+ netdev_warn(dev, "PRESDIV not the same, may risk transfer errors\n");
+
+ netdev_dbg(dev, "fdbt: prediv %d seg1 %d seg2 %d rjw %d propseg %d\n",
+ dbt->brp - 1, dbt->phase_seg1 - 1, dbt->phase_seg2 - 1,
+ dbt->sjw - 1, dbt->prop_seg);
+
+ netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x cbt=0x%08x fdcbt=0x%08x\n",
+ __func__, flexcan_read(priv, FLEXCAN_MCR),
+ flexcan_read(priv, FLEXCAN_CTRL),
+ flexcan_read(priv, FLEXCAN_CBT),
+ flexcan_read(priv, FLEXCAN_FDCBT));
+ } else {
+ reg = flexcan_read(priv, FLEXCAN_CTRL);
+ reg &= ~(FLEXCAN_CTRL_PRESDIV(0xff) |
+ FLEXCAN_CTRL_RJW(0x3) |
+ FLEXCAN_CTRL_PSEG1(0x7) |
+ FLEXCAN_CTRL_PSEG2(0x7) |
+ FLEXCAN_CTRL_PROPSEG(0x7));
+
+ reg |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) |
+ FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) |
+ FLEXCAN_CTRL_PSEG2(bt->phase_seg2 - 1) |
+ FLEXCAN_CTRL_RJW(bt->sjw - 1) |
+ FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1);
+ flexcan_write(priv, FLEXCAN_CTRL, reg);
+
+ netdev_dbg(dev, "bt: prediv %d seg1 %d seg2 %d rjw %d propseg %d\n",
+ bt->brp - 1, bt->phase_seg1 - 1, bt->phase_seg2 - 1,
+ bt->sjw - 1, bt->prop_seg - 1);
+
+ /* print chip status */
+ netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
+ flexcan_read(priv, FLEXCAN_MCR),
+ flexcan_read(priv, FLEXCAN_CTRL));
+ }
}
/* flexcan_chip_start
@@ -815,8 +1113,7 @@ static void flexcan_set_bittiming(struct net_device *dev)
static int flexcan_chip_start(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
- struct flexcan_regs __iomem *regs = priv->regs;
- u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr;
+ u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr, reg_fdctrl;
int err, i;
/* enable module */
@@ -841,14 +1138,21 @@ static int flexcan_chip_start(struct net_device *dev)
* disable local echo
* choose format C
* set max mailbox number
+ * enable self wakeup
*/
- reg_mcr = flexcan_read(&regs->mcr);
+ reg_mcr = flexcan_read(priv, FLEXCAN_MCR);
reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff);
- reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
- FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_SRX_DIS |
- FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID);
+ reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
+ FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
+ FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_SRX_DIS |
+ FLEXCAN_MCR_WAK_MSK | FLEXCAN_MCR_SLF_WAK |
+ FLEXCAN_MCR_MAXMB(FLEXCAN_TX_BUF_ID);
+
+ if (!priv->mb_mode)
+ reg_mcr |= FLEXCAN_MCR_FEN;
+
netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr);
- flexcan_write(reg_mcr, &regs->mcr);
+ flexcan_write(priv, FLEXCAN_MCR, reg_mcr);
/* CTRL
*
@@ -861,7 +1165,7 @@ static int flexcan_chip_start(struct net_device *dev)
* enable bus off interrupt
* (== FLEXCAN_CTRL_ERR_STATE)
*/
- reg_ctrl = flexcan_read(&regs->ctrl);
+ reg_ctrl = flexcan_read(priv, FLEXCAN_CTRL);
reg_ctrl &= ~FLEXCAN_CTRL_TSYN;
reg_ctrl |= FLEXCAN_CTRL_BOFF_REC | FLEXCAN_CTRL_LBUF |
FLEXCAN_CTRL_ERR_STATE;
@@ -881,29 +1185,73 @@ static int flexcan_chip_start(struct net_device *dev)
/* leave interrupts disabled for now */
reg_ctrl &= ~FLEXCAN_CTRL_ERR_ALL;
netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl);
- flexcan_write(reg_ctrl, &regs->ctrl);
+ flexcan_write(priv, FLEXCAN_CTRL, reg_ctrl);
+
+ /* CAN FD initialization
+ *
+ * disable BRS by default
+ * Message Buffer Data Size 64 bytes per MB
+ * disable Transceiver Delay Compensation
+ * Configure Message Buffer according to CAN FD mode enabled or not
+ */
+ if ((priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) &&
+ !(priv->can.ctrlmode & CAN_CTRLMODE_FD)) {
+ netdev_err(dev, "fd mode must be enabled\n");
+ err = -EOPNOTSUPP;
+ goto out_chip_disable;
+ }
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_FD) {
+ reg_fdctrl = flexcan_read(priv, FLEXCAN_FDCTRL) &
+ ~FLEXCAN_CANFD_MBDSR_MASK;
+ reg_fdctrl |= FLEXCAN_CANFD_MBDSR_DEFAULT <<
+ FLEXCAN_CANFD_MBDSR_SHIFT;
+ flexcan_write(priv, FLEXCAN_FDCTRL, reg_fdctrl);
+ reg_mcr = flexcan_read(priv, FLEXCAN_MCR);
+ flexcan_write(priv, FLEXCAN_MCR, reg_mcr | FLEXCAN_MCR_FDEN);
+
+ priv->mb_size = FLEXCAN_MB_FD_SIZE;
+ priv->mb_num = FLEXCAN_MB_FD_NUM;
+ } else {
+ priv->mb_size = FLEXCAN_MB_SIZE;
+ priv->mb_num = FLEXCAN_MB_NUM;
+ }
/* clear and invalidate all mailboxes first */
- for (i = FLEXCAN_TX_BUF_ID; i < ARRAY_SIZE(regs->mb); i++) {
- flexcan_write(FLEXCAN_MB_CODE_RX_INACTIVE,
- &regs->mb[i].can_ctrl);
+ i = priv->mb_mode ? 0 : FLEXCAN_TX_BUF_ID;
+ for (; i < priv->mb_num; i++) {
+ flexcan_mb_write(priv, i, FLEXCAN_MB_CTRL,
+ FLEXCAN_MB_CODE_RX_INACTIVE);
}
/* Errata ERR005829: mark first TX mailbox as INACTIVE */
- flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
- &regs->mb[FLEXCAN_TX_BUF_RESERVED].can_ctrl);
+ flexcan_mb_write(priv, FLEXCAN_TX_BUF_RESERVED, FLEXCAN_MB_CTRL,
+ FLEXCAN_MB_CODE_TX_INACTIVE);
/* mark TX mailbox as INACTIVE */
- flexcan_write(FLEXCAN_MB_CODE_TX_INACTIVE,
- &regs->mb[FLEXCAN_TX_BUF_ID].can_ctrl);
+ flexcan_mb_write(priv, FLEXCAN_TX_BUF_ID, FLEXCAN_MB_CTRL,
+ FLEXCAN_MB_CODE_TX_INACTIVE);
+
+ if (priv->mb_mode) {
+ /* mark RX mailbox as INACTIVE */
+ flexcan_mb_write(priv, FLEXCAN_RX_BUF_ID, FLEXCAN_MB_CTRL,
+ FLEXCAN_MB_CODE_RX_EMPTY);
+
+ /* store Remote Request Frame */
+ reg_ctrl2 = flexcan_read(priv, FLEXCAN_CTRL2);
+ reg_ctrl2 |= FLEXCAN_CTRL2_RRS;
+ /* enable Entire Frame Arbitration Field Comparison */
+ reg_ctrl2 |= FLEXCAN_CTRL2_EACEN;
+ flexcan_write(priv, FLEXCAN_CTRL2, reg_ctrl2);
+ }
/* acceptance mask/acceptance code (accept everything) */
- flexcan_write(0x0, &regs->rxgmask);
- flexcan_write(0x0, &regs->rx14mask);
- flexcan_write(0x0, &regs->rx15mask);
+ flexcan_write(priv, FLEXCAN_RXGMASK, 0x0);
+ flexcan_write(priv, FLEXCAN_RX14MASK, 0x0);
+ flexcan_write(priv, FLEXCAN_RX15MASK, 0x0);
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG)
- flexcan_write(0x0, &regs->rxfgmask);
+ flexcan_write(priv, FLEXCAN_RXFGMASK, 0x0);
/* On Vybrid, disable memory error detection interrupts
* and freeze mode.
@@ -916,16 +1264,16 @@ static int flexcan_chip_start(struct net_device *dev)
* and Correction of Memory Errors" to write to
* MECR register
*/
- reg_ctrl2 = flexcan_read(&regs->ctrl2);
+ reg_ctrl2 = flexcan_read(priv, FLEXCAN_CTRL2);
reg_ctrl2 |= FLEXCAN_CTRL2_ECRWRE;
- flexcan_write(reg_ctrl2, &regs->ctrl2);
+ flexcan_write(priv, FLEXCAN_CTRL2, reg_ctrl2);
- reg_mecr = flexcan_read(&regs->mecr);
+ reg_mecr = flexcan_read(priv, FLEXCAN_MECR);
reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS;
- flexcan_write(reg_mecr, &regs->mecr);
+ flexcan_write(priv, FLEXCAN_MECR, reg_mecr);
reg_mecr &= ~(FLEXCAN_MECR_NCEFAFRZ | FLEXCAN_MECR_HANCEI_MSK |
FLEXCAN_MECR_FANCEI_MSK);
- flexcan_write(reg_mecr, &regs->mecr);
+ flexcan_write(priv, FLEXCAN_MECR, reg_mecr);
}
err = flexcan_transceiver_enable(priv);
@@ -941,13 +1289,14 @@ static int flexcan_chip_start(struct net_device *dev)
/* enable interrupts atomically */
disable_irq(dev->irq);
- flexcan_write(priv->reg_ctrl_default, &regs->ctrl);
- flexcan_write(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
+ flexcan_write(priv, FLEXCAN_CTRL, priv->reg_ctrl_default);
+ flexcan_write(priv, FLEXCAN_IMASK1, priv->iflag_default);
enable_irq(dev->irq);
/* print chip status */
netdev_dbg(dev, "%s: reading mcr=0x%08x ctrl=0x%08x\n", __func__,
- flexcan_read(&regs->mcr), flexcan_read(&regs->ctrl));
+ flexcan_read(priv, FLEXCAN_MCR),
+ flexcan_read(priv, FLEXCAN_CTRL));
return 0;
@@ -955,6 +1304,7 @@ static int flexcan_chip_start(struct net_device *dev)
flexcan_transceiver_disable(priv);
out_chip_disable:
flexcan_chip_disable(priv);
+
return err;
}
@@ -965,16 +1315,15 @@ static int flexcan_chip_start(struct net_device *dev)
static void flexcan_chip_stop(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
- struct flexcan_regs __iomem *regs = priv->regs;
/* freeze + disable module */
flexcan_chip_freeze(priv);
flexcan_chip_disable(priv);
/* Disable all interrupts */
- flexcan_write(0, &regs->imask1);
- flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
- &regs->ctrl);
+ flexcan_write(priv, FLEXCAN_IMASK1, 0);
+ flexcan_write(priv, FLEXCAN_CTRL, priv->reg_ctrl_default &
+ ~FLEXCAN_CTRL_ERR_ALL);
flexcan_transceiver_disable(priv);
priv->can.state = CAN_STATE_STOPPED;
@@ -985,17 +1334,13 @@ static int flexcan_open(struct net_device *dev)
struct flexcan_priv *priv = netdev_priv(dev);
int err;
- err = clk_prepare_enable(priv->clk_ipg);
+ err = pm_runtime_get_sync(priv->dev);
if (err)
return err;
- err = clk_prepare_enable(priv->clk_per);
- if (err)
- goto out_disable_ipg;
-
err = open_candev(dev);
if (err)
- goto out_disable_per;
+ goto out_pm_runtime;
err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
if (err)
@@ -1017,10 +1362,9 @@ static int flexcan_open(struct net_device *dev)
free_irq(dev->irq, dev);
out_close:
close_candev(dev);
- out_disable_per:
- clk_disable_unprepare(priv->clk_per);
- out_disable_ipg:
- clk_disable_unprepare(priv->clk_ipg);
+
+ out_pm_runtime:
+ pm_runtime_put(priv->dev);
return err;
}
@@ -1034,13 +1378,13 @@ static int flexcan_close(struct net_device *dev)
flexcan_chip_stop(dev);
free_irq(dev->irq, dev);
- clk_disable_unprepare(priv->clk_per);
- clk_disable_unprepare(priv->clk_ipg);
close_candev(dev);
can_led_event(dev, CAN_LED_EVENT_STOP);
+ pm_runtime_put(priv->dev);
+
return 0;
}
@@ -1074,44 +1418,44 @@ static const struct net_device_ops flexcan_netdev_ops = {
static int register_flexcandev(struct net_device *dev)
{
struct flexcan_priv *priv = netdev_priv(dev);
- struct flexcan_regs __iomem *regs = priv->regs;
u32 reg, err;
- err = clk_prepare_enable(priv->clk_ipg);
- if (err)
- return err;
-
- err = clk_prepare_enable(priv->clk_per);
- if (err)
- goto out_disable_ipg;
-
/* select "bus clock", chip must be disabled */
err = flexcan_chip_disable(priv);
if (err)
- goto out_disable_per;
- reg = flexcan_read(&regs->ctrl);
- reg |= FLEXCAN_CTRL_CLK_SRC;
- flexcan_write(reg, &regs->ctrl);
+ return err;
+
+ if (priv->clk_src) {
+ reg = flexcan_read(priv, FLEXCAN_CTRL);
+ reg |= FLEXCAN_CTRL_CLK_SRC;
+ flexcan_write(priv, FLEXCAN_CTRL, reg);
+ }
err = flexcan_chip_enable(priv);
if (err)
goto out_chip_disable;
/* set freeze, halt and activate FIFO, restrict register access */
- reg = flexcan_read(&regs->mcr);
+ reg = flexcan_read(priv, FLEXCAN_MCR);
reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
- FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
- flexcan_write(reg, &regs->mcr);
+ FLEXCAN_MCR_SUPV;
+
+ if (!priv->mb_mode)
+ reg |= FLEXCAN_MCR_FEN;
+
+ flexcan_write(priv, FLEXCAN_MCR, reg);
/* Currently we only support newer versions of this core
* featuring a RX FIFO. Older cores found on some Coldfire
* derivates are not yet supported.
*/
- reg = flexcan_read(&regs->mcr);
- if (!(reg & FLEXCAN_MCR_FEN)) {
- netdev_err(dev, "Could not enable RX FIFO, unsupported core\n");
- err = -ENODEV;
- goto out_chip_disable;
+ if (!priv->mb_mode) {
+ reg = flexcan_read(priv, FLEXCAN_MCR);
+ if (!(reg & FLEXCAN_MCR_FEN)) {
+ netdev_err(dev, "Could not enable RX FIFO, unsupported core\n");
+ err = -ENODEV;
+ goto out_chip_disable;
+ }
}
err = register_candev(dev);
@@ -1119,10 +1463,6 @@ static int register_flexcandev(struct net_device *dev)
/* disable core and turn off clocks */
out_chip_disable:
flexcan_chip_disable(priv);
- out_disable_per:
- clk_disable_unprepare(priv->clk_per);
- out_disable_ipg:
- clk_disable_unprepare(priv->clk_ipg);
return err;
}
@@ -1132,7 +1472,58 @@ static void unregister_flexcandev(struct net_device *dev)
unregister_candev(dev);
}
+static int flexcan_of_parse_stop_mode(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *node;
+ struct flexcan_priv *priv;
+ phandle phandle;
+ u32 out_val[5];
+ int ret;
+
+ if (!np)
+ return -EINVAL;
+ /*
+ * stop mode property format is:
+ * <&gpr req_gpr req_bit ack_gpr ack_bit>.
+ */
+ ret = of_property_read_u32_array(np, "stop-mode", out_val, 5);
+ if (ret) {
+ dev_dbg(&pdev->dev, "no stop-mode property\n");
+ return ret;
+ }
+ phandle = *out_val;
+
+ node = of_find_node_by_phandle(phandle);
+ if (!node) {
+ dev_dbg(&pdev->dev, "could not find gpr node by phandle\n");
+ return PTR_ERR(node);
+ }
+
+ priv = netdev_priv(dev);
+ priv->stm.gpr = syscon_node_to_regmap(node);
+ if (IS_ERR(priv->stm.gpr)) {
+ dev_dbg(&pdev->dev, "could not find gpr regmap\n");
+ return PTR_ERR(priv->stm.gpr);
+ }
+
+ of_node_put(node);
+
+ priv->stm.req_gpr = out_val[1];
+ priv->stm.req_bit = out_val[2];
+ priv->stm.ack_gpr = out_val[3];
+ priv->stm.ack_bit = out_val[4];
+
+ dev_dbg(&pdev->dev, "gpr %s req_gpr 0x%x req_bit %u ack_gpr 0x%x ack_bit %u\n",
+ node->full_name, priv->stm.req_gpr,
+ priv->stm.req_bit, priv->stm.ack_gpr,
+ priv->stm.ack_bit);
+ return 0;
+}
+
static const struct of_device_id flexcan_of_match[] = {
+ { .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, },
{ .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, },
{ .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, },
{ .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, },
@@ -1151,14 +1542,17 @@ static int flexcan_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id;
const struct flexcan_devtype_data *devtype_data;
+ struct device_node *np = pdev->dev.of_node;
struct net_device *dev;
struct flexcan_priv *priv;
struct regulator *reg_xceiver;
struct resource *mem;
struct clk *clk_ipg = NULL, *clk_per = NULL;
- struct flexcan_regs __iomem *regs;
+ void __iomem *regs;
int err, irq;
u32 clock_freq = 0;
+ u32 clk_src = 1;
+ int wakeup = 1;
reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver");
if (PTR_ERR(reg_xceiver) == -EPROBE_DEFER)
@@ -1166,9 +1560,12 @@ static int flexcan_probe(struct platform_device *pdev)
else if (IS_ERR(reg_xceiver))
reg_xceiver = NULL;
- if (pdev->dev.of_node)
+ if (pdev->dev.of_node) {
of_property_read_u32(pdev->dev.of_node,
"clock-frequency", &clock_freq);
+ of_property_read_u32(pdev->dev.of_node,
+ "clk-src", &clk_src);
+ }
if (!clock_freq) {
clk_ipg = devm_clk_get(&pdev->dev, "ipg");
@@ -1213,14 +1610,17 @@ static int flexcan_probe(struct platform_device *pdev)
dev->flags |= IFF_ECHO;
priv = netdev_priv(dev);
+ priv->dev = &pdev->dev;
+ priv->clk_src = clk_src;
priv->can.clock.freq = clock_freq;
priv->can.bittiming_const = &flexcan_bittiming_const;
+ priv->can.data_bittiming_const = &flexcan_fd_data_bittiming_const;
priv->can.do_set_mode = flexcan_set_mode;
priv->can.do_get_berr_counter = flexcan_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_BERR_REPORTING;
- priv->regs = regs;
+ priv->base = regs;
priv->clk_ipg = clk_ipg;
priv->clk_per = clk_per;
priv->pdata = dev_get_platdata(&pdev->dev);
@@ -1232,21 +1632,69 @@ static int flexcan_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RX_FIFO) {
+ priv->mb_mode = true;
+ priv->rx_int = FLEXCAN_RX_BUF_INT;
+ priv->iflag_default = FLEXCAN_IFLAG_DEFAULT_MB;
+ } else {
+ priv->mb_mode = false;
+ priv->rx_int = FLEXCAN_IFLAG_RX_FIFO_AVAILABLE;
+ priv->iflag_default = FLEXCAN_IFLAG_DEFAULT_FIFO;
+ }
+
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_CANFD) {
+ if (!(of_find_property(np, "disable-fd-mode", NULL))) {
+ priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD;
+ priv->can.bittiming_const = &flexcan_fd_bittiming_const;
+ if (!(priv->devtype_data->quirks &
+ FLEXCAN_QUIRK_DISABLE_RX_FIFO)) {
+ dev_err(&pdev->dev, "canfd mode can't work on fifo mode\n");
+ err = -EINVAL;
+ goto failed_register;
+ }
+ }
+ }
+
+ pm_runtime_enable(&pdev->dev);
+ err = pm_runtime_get_sync(&pdev->dev);
+ if (err < 0) {
+ dev_err(&pdev->dev, "pm_runtime_get failed(%d)\n", err);
+ goto failed_rpm_disable;
+ }
+
err = register_flexcandev(dev);
if (err) {
dev_err(&pdev->dev, "registering netdev failed\n");
- goto failed_register;
+ goto failed_rpm_put;
}
devm_can_led_init(dev);
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG) {
+ err = flexcan_of_parse_stop_mode(pdev);
+ if (err) {
+ wakeup = 0;
+ dev_dbg(&pdev->dev, "failed to parse stop-mode\n");
+ }
+
+ }
+
+ device_set_wakeup_capable(&pdev->dev, wakeup);
+
+ pm_runtime_put(&pdev->dev);
+
dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
- priv->regs, dev->irq);
+ priv->base, dev->irq);
return 0;
+ failed_rpm_put:
+ pm_runtime_put(priv->dev);
+ failed_rpm_disable:
+ pm_runtime_disable(&pdev->dev);
failed_register:
free_candev(dev);
+
return err;
}
@@ -1256,6 +1704,7 @@ static int flexcan_remove(struct platform_device *pdev)
struct flexcan_priv *priv = netdev_priv(dev);
unregister_flexcandev(dev);
+ pm_runtime_disable(&pdev->dev);
netif_napi_del(&priv->napi);
free_candev(dev);
@@ -1266,38 +1715,82 @@ static int __maybe_unused flexcan_suspend(struct device *device)
{
struct net_device *dev = dev_get_drvdata(device);
struct flexcan_priv *priv = netdev_priv(dev);
- int err;
+ int ret = 0;
if (netif_running(dev)) {
- err = flexcan_chip_disable(priv);
- if (err)
- return err;
netif_stop_queue(dev);
netif_device_detach(dev);
+ /*
+ * if wakeup is enabled, enter stop mode
+ * else enter disabled mode.
+ */
+ if (device_may_wakeup(device)) {
+ enable_irq_wake(dev->irq);
+ flexcan_enter_stop_mode(priv);
+ } else {
+ flexcan_chip_stop(dev);
+ ret = pm_runtime_force_suspend(device);
+ }
}
priv->can.state = CAN_STATE_SLEEPING;
- return 0;
+ pinctrl_pm_select_sleep_state(device);
+
+ return ret;
}
static int __maybe_unused flexcan_resume(struct device *device)
{
struct net_device *dev = dev_get_drvdata(device);
struct flexcan_priv *priv = netdev_priv(dev);
- int err;
+ int err = 0;
+
+ pinctrl_pm_select_default_state(device);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
if (netif_running(dev)) {
- netif_device_attach(dev);
- netif_start_queue(dev);
- err = flexcan_chip_enable(priv);
+ err = pm_runtime_force_resume(device);
if (err)
return err;
+
+ netif_device_attach(dev);
+ netif_start_queue(dev);
+
+ if (device_may_wakeup(device)) {
+ disable_irq_wake(dev->irq);
+ flexcan_exit_stop_mode(priv);
+ }
+
+ err = flexcan_chip_start(dev);
}
+
+ return err;
+}
+
+static int __maybe_unused flexcan_runtime_suspend(struct device *device)
+{
+ struct net_device *dev = dev_get_drvdata(device);
+ struct flexcan_priv *priv = netdev_priv(dev);
+
+ flexcan_clks_disable(priv);
+
+ return 0;
+}
+
+static int __maybe_unused flexcan_runtime_resume(struct device *device)
+{
+ struct net_device *dev = dev_get_drvdata(device);
+ struct flexcan_priv *priv = netdev_priv(dev);
+
+ flexcan_clks_enable(priv);
+
return 0;
}
-static SIMPLE_DEV_PM_OPS(flexcan_pm_ops, flexcan_suspend, flexcan_resume);
+static const struct dev_pm_ops flexcan_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(flexcan_suspend, flexcan_resume)
+ SET_RUNTIME_PM_OPS(flexcan_runtime_suspend, flexcan_runtime_resume, NULL)
+};
static struct platform_driver flexcan_driver = {
.driver = {
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
index d1ca45fbb164..3ad3e5f88b58 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -8,7 +8,7 @@ config NET_VENDOR_FREESCALE
depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \
M523x || M527x || M5272 || M528x || M520x || M532x || \
ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) || \
- ARCH_LAYERSCAPE
+ ARCH_LAYERSCAPE || ARCH_MXC_ARM64
---help---
If you have a network (Ethernet) card belonging to this class, say Y.
@@ -22,8 +22,8 @@ if NET_VENDOR_FREESCALE
config FEC
tristate "FEC ethernet controller (of ColdFire and some i.MX CPUs)"
depends on (M523x || M527x || M5272 || M528x || M520x || M532x || \
- ARCH_MXC || SOC_IMX28)
- default ARCH_MXC || SOC_IMX28 if ARM
+ ARM || ARM64)
+ default y
select PHYLIB
select PTP_1588_CLOCK
---help---
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
index cbe21dc7e37e..7f022dd178e6 100644
--- a/drivers/net/ethernet/freescale/Makefile
+++ b/drivers/net/ethernet/freescale/Makefile
@@ -3,7 +3,7 @@
#
obj-$(CONFIG_FEC) += fec.o
-fec-objs :=fec_main.o fec_ptp.o
+fec-objs :=fec_main.o fec_fixup.o fec_ptp.o
CFLAGS_fec_main.o := -D__CHECK_ENDIAN__
CFLAGS_fec_ptp.o := -D__CHECK_ENDIAN__
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 5ea740b4cf14..0e8c915db794 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -15,11 +15,13 @@
#include <linux/clocksource.h>
#include <linux/net_tstamp.h>
+#include <linux/pm_qos.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/timecounter.h>
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
- defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM)
+ defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \
+ defined(CONFIG_ARM64)
/*
* Just figures, Motorola would have to change the offsets for
* registers in the same peripheral device on different models
@@ -75,6 +77,8 @@
#define FEC_R_DES_ACTIVE_2 0x1e8 /* Rx descriptor active for ring 2 */
#define FEC_X_DES_ACTIVE_2 0x1ec /* Tx descriptor active for ring 2 */
#define FEC_QOS_SCHEME 0x1f0 /* Set multi queues Qos scheme */
+#define FEC_LPI_SLEEP 0x1f4 /* Set IEEE802.3az LPI Sleep Ts time */
+#define FEC_LPI_WAKE 0x1f8 /* Set IEEE802.3az LPI Wake Tw time */
#define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */
#define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */
@@ -194,7 +198,7 @@
* Evidently, ARM SoCs have the FEC block generated in a
* little endian mode so adjust endianness accordingly.
*/
-#if defined(CONFIG_ARM)
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
#define fec32_to_cpu le32_to_cpu
#define fec16_to_cpu le16_to_cpu
#define cpu_to_fec32 cpu_to_le32
@@ -292,7 +296,7 @@ struct bufdesc_ex {
/* This device has up to three irqs on some platforms */
-#define FEC_IRQ_NUM 3
+#define FEC_IRQ_NUM 4
/* Maximum number of queues supported
* ENET with AVB IP can support up to 3 independent tx queues and rx queues.
@@ -353,6 +357,8 @@ struct bufdesc_ex {
#define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
#define FLAG_RX_CSUM_ERROR (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
+#define FEC0_MII_BUS_SHARE_TRUE 1
+
/* Interrupt events/masks. */
#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */
#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */
@@ -378,6 +384,10 @@ struct bufdesc_ex {
#define FEC_NAPI_IMASK (FEC_ENET_MII | FEC_ENET_TS_TIMER)
#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
+#define FEC_ENET_ETHEREN ((uint)0x00000002)
+#define FEC_ENET_TXC_DLY ((uint)0x00010000)
+#define FEC_ENET_RXC_DLY ((uint)0x00020000)
+
/* ENET interrupt coalescing macro define */
#define FEC_ITR_CLK_SEL (0x1 << 30)
#define FEC_ITR_EN (0x1 << 31)
@@ -446,6 +456,30 @@ struct bufdesc_ex {
#define FEC_QUIRK_HAS_COALESCE (1 << 13)
/* Interrupt doesn't wake CPU from deep idle */
#define FEC_QUIRK_ERR006687 (1 << 14)
+/*
+ * i.MX6Q/DL ENET cannot wake up system in wait mode because ENET tx & rx
+ * interrupt signal don't connect to GPC. So use pm qos to avoid cpu enter
+ * to wait mode.
+ */
+#define FEC_QUIRK_BUG_WAITMODE (1 << 15)
+
+/* PHY fixup flag define */
+#define FEC_QUIRK_AR8031_FIXUP (1 << 16)
+
+/* i.MX8QM/QXP ENET IP version add new feture to generate delayed TXC/RXC
+ * as an alternative option to make sure it can work well with various PHYs.
+ * - For the implementation of delayed TXC, ENET will take synchronized 250/125MHz
+ * clocks to generate 2ns delay by registering original TXC with positive edge
+ * of inverted 250MHz clock.
+ * - For the implementation of delayed RXC, there will be buffers in the subsystem
+ * level. The exact length of delay buffers will be decided when closing I/O timing.
+ */
+#define FEC_QUIRK_DELAYED_CLKS_SUPPORT (1 << 17)
+/* i.MX8MQ ENET IP version add new feature to support IEEE 802.3az EEE
+ * standard. For the transmission, MAC supply two user registers to set
+ * Sleep (TS) and Wake (TW) time.
+ */
+#define FEC_QUIRK_HAS_EEE (1 << 18)
struct bufdesc_prop {
int qid;
@@ -460,6 +494,12 @@ struct bufdesc_prop {
unsigned char dsize_log2;
};
+struct fec_enet_stop_mode {
+ struct regmap *gpr;
+ u8 req_gpr;
+ u8 req_bit;
+};
+
struct fec_enet_priv_tx_q {
struct bufdesc_prop bd;
unsigned char *tx_bounce[TX_RING_SIZE];
@@ -497,6 +537,7 @@ struct fec_enet_private {
struct clk *clk_ref;
struct clk *clk_enet_out;
struct clk *clk_ptp;
+ struct clk *clk_2x_txclk;
bool ptp_clk_on;
struct mutex ptp_clk_mutex;
@@ -522,10 +563,15 @@ struct fec_enet_private {
/* Phylib and MDIO interface */
struct mii_bus *mii_bus;
int mii_timeout;
+ int mii_bus_share;
+ bool active_in_suspend;
uint phy_speed;
phy_interface_t phy_interface;
struct device_node *phy_node;
int link;
+ bool fixed_link;
+ bool rgmii_txc_dly;
+ bool rgmii_rxc_dly;
int full_duplex;
int speed;
struct completion mdio_done;
@@ -533,7 +579,9 @@ struct fec_enet_private {
bool bufdesc_ex;
int pause_flag;
int wol_flag;
+ int wake_irq;
u32 quirks;
+ u32 fixups;
struct napi_struct napi;
int csum_flags;
@@ -553,6 +601,7 @@ struct fec_enet_private {
int hwts_tx_en;
struct delayed_work time_keep;
struct regulator *reg_phy;
+ struct pm_qos_request pm_qos_req;
unsigned int tx_align;
unsigned int rx_align;
@@ -564,6 +613,10 @@ struct fec_enet_private {
unsigned int tx_time_itr;
unsigned int itr_clk_rate;
+ /* tx lpi eee mode */
+ struct ethtool_eee eee;
+ unsigned int clk_ref_rate;
+
u32 rx_copybreak;
/* ptp clock period in ns*/
@@ -575,6 +628,8 @@ struct fec_enet_private {
int pps_enable;
unsigned int next_counter;
+ struct fec_enet_stop_mode gpr;
+
u64 ethtool_stats[0];
};
@@ -584,6 +639,10 @@ void fec_ptp_start_cyclecounter(struct net_device *ndev);
int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr);
int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr);
uint fec_ptp_check_pps_event(struct fec_enet_private *fep);
+void fec_enet_register_fixup(struct net_device *ndev);
+int of_fec_enet_parse_fixup(struct device_node *np);
+void fec_enet_get_mac_from_fuse(struct device_node *np, unsigned char *mac);
+void fec_enet_ipg_stop_misc_set(struct device_node *np, bool enabled);
/****************************************************************************/
#endif /* FEC_H */
diff --git a/drivers/net/ethernet/freescale/fec_fixup.c b/drivers/net/ethernet/freescale/fec_fixup.c
new file mode 100644
index 000000000000..1781019d77ae
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fec_fixup.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#ifdef CONFIG_ARCH_MXC_ARM64
+#include <soc/imx8/sc/sci.h>
+#endif
+#include "fec.h"
+
+#define PHY_ID_AR8031 0x004dd074
+
+#define IMX8QM_FUSE_MAC0_WORD0 452
+#define IMX8QM_FUSE_MAC0_WORD1 453
+#define IMX8QM_FUSE_MAC1_WORD0 454
+#define IMX8QM_FUSE_MAC1_WORD1 455
+#define IMX8QXP_FUSE_MAC0_WORD0 708
+#define IMX8QXP_FUSE_MAC0_WORD1 709
+#define IMX8QXP_FUSE_MAC1_WORD0 710
+#define IMX8QXP_FUSE_MAC1_WORD1 711
+#define IMX8M_OCOTP_MAC_ADDR0_OFF 0x640
+#define IMX8M_OCOTP_MAC_ADDR1_OFF 0x650
+
+enum imx_soc_type {
+ IMX8QM_FUSE = 0,
+ IMX8QXP_FUSE,
+};
+
+struct imx_fuse_mac_addr {
+ u32 fuse_mac0_word0;
+ u32 fuse_mac0_word1;
+ u32 fuse_mac1_word0;
+ u32 fuse_mac1_word1;
+};
+
+static struct imx_fuse_mac_addr imx8_fuse_mapping[] = {
+ {
+ .fuse_mac0_word0 = IMX8QM_FUSE_MAC0_WORD0,
+ .fuse_mac0_word1 = IMX8QM_FUSE_MAC0_WORD1,
+ .fuse_mac1_word0 = IMX8QM_FUSE_MAC1_WORD0,
+ .fuse_mac1_word1 = IMX8QM_FUSE_MAC1_WORD1,
+ }, {
+ .fuse_mac0_word0 = IMX8QXP_FUSE_MAC0_WORD0,
+ .fuse_mac0_word1 = IMX8QXP_FUSE_MAC0_WORD1,
+ .fuse_mac1_word0 = IMX8QXP_FUSE_MAC1_WORD0,
+ .fuse_mac1_word1 = IMX8QXP_FUSE_MAC1_WORD1,
+ }, {
+ /* sentinel */
+ }
+};
+
+static int ar8031_phy_fixup(struct phy_device *dev)
+{
+ u16 val;
+
+ /* Set RGMII IO voltage to 1.8V */
+ phy_write(dev, 0x1d, 0x1f);
+ phy_write(dev, 0x1e, 0x8);
+
+ /* Disable phy AR8031 SmartEEE function */
+ phy_write(dev, 0xd, 0x3);
+ phy_write(dev, 0xe, 0x805d);
+ phy_write(dev, 0xd, 0x4003);
+ val = phy_read(dev, 0xe);
+ val &= ~(0x1 << 8);
+ phy_write(dev, 0xe, val);
+
+ /* Introduce tx clock delay */
+ phy_write(dev, 0x1d, 0x5);
+ phy_write(dev, 0x1e, 0x100);
+
+ return 0;
+}
+
+void fec_enet_register_fixup(struct net_device *ndev)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ int err;
+
+ if (!IS_BUILTIN(CONFIG_PHYLIB))
+ return;
+
+ if (fep->fixups & FEC_QUIRK_AR8031_FIXUP) {
+ static int ar8031_registered = 0;
+
+ if (ar8031_registered)
+ return;
+ err = phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffef,
+ ar8031_phy_fixup);
+ if (err)
+ netdev_info(ndev, "Cannot register PHY board fixup\n");
+ ar8031_registered = 1;
+ }
+}
+
+int of_fec_enet_parse_fixup(struct device_node *np)
+{
+ int fixups = 0;
+
+ if (of_get_property(np, "fsl,ar8031-phy-fixup", NULL))
+ fixups |= FEC_QUIRK_AR8031_FIXUP;
+
+ return fixups;
+}
+
+static void imx8mq_get_mac_from_fuse(int dev_id, unsigned char *mac)
+{
+ struct device_node *ocotp_np;
+ void __iomem *base;
+ u32 value;
+
+ ocotp_np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-ocotp");
+ if (!ocotp_np) {
+ pr_warn("failed to find ocotp node\n");
+ return;
+ }
+
+ base = of_iomap(ocotp_np, 0);
+ if (!base) {
+ pr_warn("failed to map ocotp\n");
+ goto put_ocotp_node;
+ }
+
+ value = readl_relaxed(base + IMX8M_OCOTP_MAC_ADDR1_OFF);
+ mac[0] = (value >> 8);
+ mac[1] = value;
+
+ value = readl_relaxed(base + IMX8M_OCOTP_MAC_ADDR0_OFF);
+ mac[2] = value >> 24;
+ mac[3] = value >> 16;
+ mac[4] = value >> 8;
+ mac[5] = value;
+
+put_ocotp_node:
+ of_node_put(ocotp_np);
+}
+
+#ifdef CONFIG_ARCH_MXC_ARM64
+static void imx8qm_get_mac_from_fuse(int dev_id, unsigned char *mac,
+ struct imx_fuse_mac_addr *fuse_mapping)
+{
+ uint32_t mu_id;
+ sc_ipc_t ipc_handle;
+ sc_err_t sc_err = SC_ERR_NONE;
+ uint32_t val1 = 0, val2 = 0;
+ uint32_t word1, word2;
+
+ sc_err = sc_ipc_getMuID(&mu_id);
+ if (sc_err != SC_ERR_NONE) {
+ pr_err("FEC MAC fuse: Get MU ID failed\n");
+ return;
+ }
+
+ sc_err = sc_ipc_open(&ipc_handle, mu_id);
+ if (sc_err != SC_ERR_NONE) {
+ pr_err("FEC MAC fuse: Open MU channel failed\n");
+ return;
+ }
+
+ if (dev_id == 0) {
+ word1 = fuse_mapping->fuse_mac0_word0;
+ word2 = fuse_mapping->fuse_mac0_word1;
+ } else {
+ word1 = fuse_mapping->fuse_mac1_word0;
+ word2 = fuse_mapping->fuse_mac1_word1;
+ }
+
+ sc_err = sc_misc_otp_fuse_read(ipc_handle, word1, &val1);
+ if (sc_err != SC_ERR_NONE) {
+ pr_err("FEC MAC fuse %d read error: %d\n", word1, sc_err);
+ sc_ipc_close(ipc_handle);
+ return;
+ }
+
+ sc_err = sc_misc_otp_fuse_read(ipc_handle, word2, &val2);
+ if (sc_err != SC_ERR_NONE) {
+ pr_err("FEC MAC fuse %d read error: %d\n", word2, sc_err);
+ sc_ipc_close(ipc_handle);
+ return;
+ }
+
+ mac[0] = val1;
+ mac[1] = val1 >> 8;
+ mac[2] = val1 >> 16;
+ mac[3] = val1 >> 24;
+ mac[4] = val2;
+ mac[5] = val2 >> 8;
+
+ sc_ipc_close(ipc_handle);
+}
+
+static void imx8qm_ipg_stop_enable(int dev_id, bool enabled)
+{
+ uint32_t mu_id;
+ sc_ipc_t ipc_handle;
+ sc_err_t sc_err = SC_ERR_NONE;
+ uint32_t rsrc_id, val;
+
+ sc_err = sc_ipc_getMuID(&mu_id);
+ if (sc_err != SC_ERR_NONE) {
+ pr_err("FEC ipg stop: Get MU ID failed\n");
+ return;
+ }
+
+ sc_err = sc_ipc_open(&ipc_handle, mu_id);
+ if (sc_err != SC_ERR_NONE) {
+ pr_err("FEC ipg stop: Open MU channel failed\n");
+ return;
+ }
+
+ if (dev_id == 0)
+ rsrc_id = SC_R_ENET_0;
+ else
+ rsrc_id = SC_R_ENET_1;
+
+ val = enabled ? 1 : 0;
+ sc_err = sc_misc_set_control(ipc_handle, rsrc_id, SC_C_IPG_STOP, val);
+ if (sc_err != SC_ERR_NONE)
+ pr_err("FEC ipg stop set error: %d\n", sc_err);
+
+ sc_ipc_close(ipc_handle);
+}
+#else
+static void imx8qm_get_mac_from_fuse(int dev_id, unsigned char *mac,
+ struct imx_fuse_mac_addr *fuse_mapping) {}
+static void imx8qm_ipg_stop_enable(int dev_id, bool enabled) {}
+#endif
+
+void fec_enet_get_mac_from_fuse(struct device_node *np, unsigned char *mac)
+{
+ int idx;
+
+ if (!np)
+ return;
+
+ idx = of_alias_get_id(np, "ethernet");
+ if (idx < 0)
+ idx = 0;
+
+ if (of_machine_is_compatible("fsl,imx8qm"))
+ imx8qm_get_mac_from_fuse(idx, mac,
+ &imx8_fuse_mapping[IMX8QM_FUSE]);
+ else if (of_machine_is_compatible("fsl,imx8qxp"))
+ imx8qm_get_mac_from_fuse(idx, mac,
+ &imx8_fuse_mapping[IMX8QXP_FUSE]);
+ else if (of_machine_is_compatible("fsl,imx8mq"))
+ imx8mq_get_mac_from_fuse(idx, mac);
+}
+
+void fec_enet_ipg_stop_misc_set(struct device_node *np, bool enabled)
+{
+ int idx;
+
+ if (!np)
+ return;
+
+ idx = of_alias_get_id(np, "ethernet");
+ if (idx < 0)
+ idx = 0;
+
+ if (of_machine_is_compatible("fsl,imx8qm") ||
+ of_machine_is_compatible("fsl,imx8qxp"))
+ imx8qm_ipg_stop_enable(idx, enabled);
+}
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index fe00f71bc6b4..816c872c6c02 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -18,13 +18,14 @@
* Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be)
* Copyright (c) 2004-2006 Macq Electronique SA.
*
- * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2010-2014 Freescale Semiconductor, Inc.
+ *
+ * Copyright 2017 NXP
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/pm_runtime.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
@@ -47,6 +48,7 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/clk.h>
+#include <linux/clk/clk-conf.h>
#include <linux/platform_device.h>
#include <linux/mdio.h>
#include <linux/phy.h>
@@ -59,10 +61,14 @@
#include <linux/regulator/consumer.h>
#include <linux/if_vlan.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/busfreq-imx.h>
#include <linux/prefetch.h>
-#include <soc/imx/cpuidle.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
#include <asm/cacheflush.h>
+#include <soc/imx/cpuidle.h>
#include "fec.h"
@@ -72,6 +78,7 @@ static void fec_enet_itr_coal_init(struct net_device *ndev);
#define DRIVER_NAME "fec"
#define FEC_ENET_GET_QUQUE(_x) ((_x == 0) ? 1 : ((_x == 1) ? 2 : 0))
+static const u16 fec_enet_vlan_pri_to_queue[8] = {1, 1, 1, 1, 2, 2, 2, 2};
/* Pause frame feild and FIFO threshold */
#define FEC_ENET_FCE (1 << 5)
@@ -102,7 +109,7 @@ static struct platform_device_id fec_devtype[] = {
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 |
- FEC_QUIRK_HAS_RACC,
+ FEC_QUIRK_HAS_RACC | FEC_QUIRK_BUG_WAITMODE,
}, {
.name = "mvf600-fec",
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC,
@@ -120,6 +127,22 @@ static struct platform_device_id fec_devtype[] = {
FEC_QUIRK_HAS_VLAN | FEC_QUIRK_BUG_CAPTURE |
FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE,
}, {
+ .name = "imx8qm-fec",
+ .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
+ FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
+ FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE |
+ FEC_QUIRK_DELAYED_CLKS_SUPPORT,
+ }, {
+ .name = "imx8mq-fec",
+ .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
+ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
+ FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
+ FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE |
+ FEC_QUIRK_HAS_EEE,
+ }, {
/* sentinel */
}
};
@@ -133,6 +156,8 @@ enum imx_fec_type {
MVF600_FEC,
IMX6SX_FEC,
IMX6UL_FEC,
+ IMX8QM_FEC,
+ IMX8MQ_FEC,
};
static const struct of_device_id fec_dt_ids[] = {
@@ -143,6 +168,8 @@ static const struct of_device_id fec_dt_ids[] = {
{ .compatible = "fsl,mvf600-fec", .data = &fec_devtype[MVF600_FEC], },
{ .compatible = "fsl,imx6sx-fec", .data = &fec_devtype[IMX6SX_FEC], },
{ .compatible = "fsl,imx6ul-fec", .data = &fec_devtype[IMX6UL_FEC], },
+ { .compatible = "fsl,imx8qm-fec", .data = &fec_devtype[IMX8QM_FEC], },
+ { .compatible = "fsl,imx8mq-fec", .data = &fec_devtype[IMX8MQ_FEC], },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fec_dt_ids);
@@ -191,7 +218,8 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
* account when setting it.
*/
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
- defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM)
+ defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \
+ defined(CONFIG_ARM64)
#define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16)
#else
#define OPT_FRAME_SIZE 0
@@ -220,7 +248,15 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
#define FEC_WOL_FLAG_ENABLE (0x1 << 1)
#define FEC_WOL_FLAG_SLEEP_ON (0x1 << 2)
-#define COPYBREAK_DEFAULT 256
+/* By default, set the copybreak to 1518,
+ * then the RX path always keep DMA memory unchanged, and
+ * allocate one new skb and copy DMA memory data to the new skb
+ * buffer, which can improve the performance when SMMU is enabled.
+ *
+ * The driver support .set_tunable() interface for ethtool, user
+ * can dynamicly change the copybreak value.
+ */
+#define COPYBREAK_DEFAULT 1518
#define TSO_HEADER_SIZE 128
/* Max number of allowed TCP segments for software TSO */
@@ -237,14 +273,14 @@ static struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp,
struct bufdesc_prop *bd)
{
return (bdp >= bd->last) ? bd->base
- : (struct bufdesc *)(((unsigned)bdp) + bd->dsize);
+ : (struct bufdesc *)(((void *)bdp) + bd->dsize);
}
static struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp,
struct bufdesc_prop *bd)
{
return (bdp <= bd->base) ? bd->last
- : (struct bufdesc *)(((unsigned)bdp) - bd->dsize);
+ : (struct bufdesc *)(((void *)bdp) - bd->dsize);
}
static int fec_enet_get_bd_index(struct bufdesc *bdp,
@@ -904,7 +940,7 @@ fec_restart(struct net_device *ndev)
u32 val;
u32 temp_mac[2];
u32 rcntl = OPT_FRAME_SIZE | 0x04;
- u32 ecntl = 0x2; /* ETHEREN */
+ u32 ecntl = FEC_ENET_ETHEREN; /* ETHEREN */
/* Whack a reset. We should wait for this.
* For i.MX6SX SOC, enet use AXI bus, we use disable MAC
@@ -963,6 +999,7 @@ fec_restart(struct net_device *ndev)
writel(val, fep->hwp + FEC_RACC);
writel(PKT_MAXBUF_SIZE, fep->hwp + FEC_FTRL);
}
+ writel(PKT_MAXBUF_SIZE, fep->hwp + FEC_FTRL);
#endif
/*
@@ -1058,6 +1095,13 @@ fec_restart(struct net_device *ndev)
if (fep->bufdesc_ex)
ecntl |= (1 << 4);
+ if (fep->quirks & FEC_QUIRK_DELAYED_CLKS_SUPPORT &&
+ fep->rgmii_txc_dly)
+ ecntl |= FEC_ENET_TXC_DLY;
+ if (fep->quirks & FEC_QUIRK_DELAYED_CLKS_SUPPORT &&
+ fep->rgmii_rxc_dly)
+ ecntl |= FEC_ENET_RXC_DLY;
+
#ifndef CONFIG_M5272
/* Enable the MIB statistic event counters */
writel(0 << 31, fep->hwp + FEC_MIB_CTRLSTAT);
@@ -1081,11 +1125,40 @@ fec_restart(struct net_device *ndev)
}
+static int fec_enet_stop_mode(struct fec_enet_private *fep, bool enabled)
+{
+ struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
+ struct device_node *np = fep->pdev->dev.of_node;
+
+ if (fep->gpr.gpr) {
+ if (enabled)
+ regmap_update_bits(fep->gpr.gpr, fep->gpr.req_gpr,
+ 1 << fep->gpr.req_bit,
+ 1 << fep->gpr.req_bit);
+ else
+ regmap_update_bits(fep->gpr.gpr, fep->gpr.req_gpr,
+ 1 << fep->gpr.req_bit,
+ 0);
+ } else if (pdata && pdata->sleep_mode_enable) {
+ pdata->sleep_mode_enable(enabled);
+ } else {
+ fec_enet_ipg_stop_misc_set(np, enabled);
+ }
+
+ return 0;
+}
+
+static inline void fec_irqs_disable(struct net_device *ndev)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+
+ writel(0, fep->hwp + FEC_IMASK);
+}
+
static void
fec_stop(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
- struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8);
u32 val;
@@ -1108,15 +1181,14 @@ fec_stop(struct net_device *ndev)
writel(1, fep->hwp + FEC_ECNTRL);
udelay(10);
}
- writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+ writel(FEC_ENET_MII, fep->hwp + FEC_IMASK);
} else {
- writel(FEC_DEFAULT_IMASK | FEC_ENET_WAKEUP, fep->hwp + FEC_IMASK);
+ writel(FEC_ENET_MII | FEC_ENET_WAKEUP, fep->hwp + FEC_IMASK);
val = readl(fep->hwp + FEC_ECNTRL);
val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
writel(val, fep->hwp + FEC_ECNTRL);
- if (pdata && pdata->sleep_mode_enable)
- pdata->sleep_mode_enable(true);
+ fec_enet_stop_mode(fep, true);
}
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
@@ -1634,7 +1706,7 @@ static void fec_get_mac(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct fec_platform_data *pdata = dev_get_platdata(&fep->pdev->dev);
- unsigned char *iap, tmpaddr[ETH_ALEN];
+ unsigned char *iap, tmpaddr[ETH_ALEN] = {0};
/*
* try to get mac address in following order:
@@ -1664,8 +1736,14 @@ static void fec_get_mac(struct net_device *ndev)
if (FEC_FLASHMAC)
iap = (unsigned char *)FEC_FLASHMAC;
#else
- if (pdata)
+ if (pdata) {
iap = (unsigned char *)&pdata->mac;
+ } else {
+ struct device_node *np = fep->pdev->dev.of_node;
+
+ fec_enet_get_mac_from_fuse(np, tmpaddr);
+ iap = &tmpaddr[0];
+ }
#endif
}
@@ -1769,6 +1847,7 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
struct fec_enet_private *fep = bus->priv;
struct device *dev = &fep->pdev->dev;
unsigned long time_left;
+ uint int_events;
int ret = 0;
ret = pm_runtime_get_sync(dev);
@@ -1788,9 +1867,12 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
usecs_to_jiffies(FEC_MII_TIMEOUT));
if (time_left == 0) {
fep->mii_timeout = 1;
- netdev_err(fep->netdev, "MDIO read timeout\n");
- ret = -ETIMEDOUT;
- goto out;
+ int_events = readl(fep->hwp + FEC_IEVENT);
+ if (!(int_events & FEC_ENET_MII)) {
+ netdev_err(fep->netdev, "MDIO read timeout\n");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
}
ret = FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA));
@@ -1846,13 +1928,10 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
int ret;
if (enable) {
- ret = clk_prepare_enable(fep->clk_ahb);
- if (ret)
- return ret;
if (fep->clk_enet_out) {
ret = clk_prepare_enable(fep->clk_enet_out);
if (ret)
- goto failed_clk_enet_out;
+ return ret;
}
if (fep->clk_ptp) {
mutex_lock(&fep->ptp_clk_mutex);
@@ -1870,8 +1949,12 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
if (ret)
goto failed_clk_ref;
}
+ if (fep->clk_2x_txclk) {
+ ret = clk_prepare_enable(fep->clk_2x_txclk);
+ if (ret)
+ goto failed_clk_2x_txclk;
+ }
} else {
- clk_disable_unprepare(fep->clk_ahb);
if (fep->clk_enet_out)
clk_disable_unprepare(fep->clk_enet_out);
if (fep->clk_ptp) {
@@ -1882,22 +1965,44 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
}
if (fep->clk_ref)
clk_disable_unprepare(fep->clk_ref);
+ if (fep->clk_2x_txclk)
+ clk_disable_unprepare(fep->clk_2x_txclk);
}
return 0;
-failed_clk_ref:
+failed_clk_2x_txclk:
if (fep->clk_ref)
clk_disable_unprepare(fep->clk_ref);
+failed_clk_ref:
+ if (fep->clk_ptp)
+ clk_disable_unprepare(fep->clk_ptp);
failed_clk_ptp:
if (fep->clk_enet_out)
clk_disable_unprepare(fep->clk_enet_out);
-failed_clk_enet_out:
- clk_disable_unprepare(fep->clk_ahb);
return ret;
}
+static int fec_restore_mii_bus(struct net_device *ndev)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ int ret;
+
+ ret = pm_runtime_get_sync(&fep->pdev->dev);
+ if (ret < 0)
+ return ret;
+
+ writel(0xffc00000, fep->hwp + FEC_IEVENT);
+ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
+ writel(FEC_ENET_MII, fep->hwp + FEC_IMASK);
+ writel(FEC_ENET_ETHEREN, fep->hwp + FEC_ECNTRL);
+
+ pm_runtime_mark_last_busy(&fep->pdev->dev);
+ pm_runtime_put_autosuspend(&fep->pdev->dev);
+ return 0;
+}
+
static int fec_enet_mii_probe(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
@@ -1965,6 +2070,7 @@ static int fec_enet_mii_probe(struct net_device *ndev)
static int fec_enet_mii_init(struct platform_device *pdev)
{
static struct mii_bus *fec0_mii_bus;
+ static int *fec_mii_bus_share;
struct net_device *ndev = platform_get_drvdata(pdev);
struct fec_enet_private *fep = netdev_priv(ndev);
struct device_node *node;
@@ -1991,6 +2097,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
/* fec1 uses fec0 mii_bus */
if (mii_cnt && fec0_mii_bus) {
fep->mii_bus = fec0_mii_bus;
+ *fec_mii_bus_share = FEC0_MII_BUS_SHARE_TRUE;
mii_cnt++;
return 0;
}
@@ -2054,6 +2161,8 @@ static int fec_enet_mii_init(struct platform_device *pdev)
if (node) {
err = of_mdiobus_register(fep->mii_bus, node);
of_node_put(node);
+ } else if (fep->phy_node && !fep->fixed_link) {
+ err = -EPROBE_DEFER;
} else {
err = mdiobus_register(fep->mii_bus);
}
@@ -2064,8 +2173,10 @@ static int fec_enet_mii_init(struct platform_device *pdev)
mii_cnt++;
/* save fec0 mii_bus */
- if (fep->quirks & FEC_QUIRK_SINGLE_MDIO)
+ if (fep->quirks & FEC_QUIRK_SINGLE_MDIO) {
fec0_mii_bus = fep->mii_bus;
+ fec_mii_bus_share = &fep->mii_bus_share;
+ }
return 0;
@@ -2109,7 +2220,8 @@ static int fec_enet_get_regs_len(struct net_device *ndev)
/* List of registers that can be safety be read to dump them with ethtool */
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
- defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM)
+ defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \
+ defined(CONFIG_ARM64)
static u32 fec_enet_register_offset[] = {
FEC_IEVENT, FEC_IMASK, FEC_R_DES_ACTIVE_0, FEC_X_DES_ACTIVE_0,
FEC_ECNTRL, FEC_MII_DATA, FEC_MII_SPEED, FEC_MIB_CTRLSTAT, FEC_R_CNTRL,
@@ -2544,6 +2656,92 @@ static int fec_enet_set_tunable(struct net_device *netdev,
return ret;
}
+/* LPI Sleep Ts count base on tx clk (clk_ref).
+ * The lpi sleep cnt value = X us / (cycle_ns)
+ */
+static int fec_enet_us_to_tx_cycle(struct net_device *ndev, int us)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+
+ return us * (fep->clk_ref_rate / 1000) / 1000;
+}
+
+static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ struct ethtool_eee *p = &fep->eee;
+ unsigned int sleep_cycle, wake_cycle;
+ int ret = 0;
+
+ if (enable) {
+ ret = phy_init_eee(ndev->phydev, 0);
+ if (ret)
+ return ret;
+
+ sleep_cycle = fec_enet_us_to_tx_cycle(ndev, p->tx_lpi_timer);
+ wake_cycle = sleep_cycle;
+ } else {
+ sleep_cycle = 0;
+ wake_cycle = 0;
+ }
+
+ p->tx_lpi_enabled = enable;
+ p->eee_enabled = enable;
+ p->eee_active = enable;
+
+ writel(sleep_cycle, fep->hwp + FEC_LPI_SLEEP);
+ writel(wake_cycle, fep->hwp + FEC_LPI_WAKE);
+
+ return 0;
+}
+
+static int
+fec_enet_get_eee(struct net_device *ndev, struct ethtool_eee *edata)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ struct ethtool_eee *p = &fep->eee;
+
+ if (!(fep->quirks & FEC_QUIRK_HAS_EEE))
+ return -EOPNOTSUPP;
+
+ if (!netif_running(ndev))
+ return -ENETDOWN;
+
+ edata->eee_enabled = p->eee_enabled;
+ edata->eee_active = p->eee_active;
+ edata->tx_lpi_timer = p->tx_lpi_timer;
+ edata->tx_lpi_enabled = p->tx_lpi_enabled;
+
+ return phy_ethtool_get_eee(ndev->phydev, edata);
+}
+
+static int
+fec_enet_set_eee(struct net_device *ndev, struct ethtool_eee *edata)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ struct ethtool_eee *p = &fep->eee;
+ int ret = 0;
+
+ if (!(fep->quirks & FEC_QUIRK_HAS_EEE))
+ return -EOPNOTSUPP;
+
+ if (!netif_running(ndev))
+ return -ENETDOWN;
+
+ p->tx_lpi_timer = edata->tx_lpi_timer;
+
+ if (!edata->eee_enabled || !edata->tx_lpi_enabled ||
+ !edata->tx_lpi_timer)
+ ret = fec_enet_eee_mode_set(ndev, false);
+ else
+ ret = fec_enet_eee_mode_set(ndev, true);
+
+ if (ret)
+ return ret;
+
+ return phy_ethtool_set_eee(ndev->phydev, edata);
+}
+
static void
fec_enet_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
{
@@ -2569,15 +2767,10 @@ fec_enet_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
return -EINVAL;
device_set_wakeup_enable(&ndev->dev, wol->wolopts & WAKE_MAGIC);
- if (device_may_wakeup(&ndev->dev)) {
+ if (device_may_wakeup(&ndev->dev))
fep->wol_flag |= FEC_WOL_FLAG_ENABLE;
- if (fep->irq[0] > 0)
- enable_irq_wake(fep->irq[0]);
- } else {
+ else
fep->wol_flag &= (~FEC_WOL_FLAG_ENABLE);
- if (fep->irq[0] > 0)
- disable_irq_wake(fep->irq[0]);
- }
return 0;
}
@@ -2602,6 +2795,8 @@ static const struct ethtool_ops fec_enet_ethtool_ops = {
.set_tunable = fec_enet_set_tunable,
.get_wol = fec_enet_get_wol,
.set_wol = fec_enet_set_wol,
+ .get_eee = fec_enet_get_eee,
+ .set_eee = fec_enet_set_eee,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings,
};
@@ -2676,7 +2871,7 @@ static void fec_enet_free_queue(struct net_device *ndev)
for (i = 0; i < fep->num_tx_queues; i++)
if (fep->tx_queue[i] && fep->tx_queue[i]->tso_hdrs) {
txq = fep->tx_queue[i];
- dma_free_coherent(NULL,
+ dma_free_coherent(&fep->pdev->dev,
txq->bd.ring_size * TSO_HEADER_SIZE,
txq->tso_hdrs,
txq->tso_hdrs_dma);
@@ -2710,7 +2905,7 @@ static int fec_enet_alloc_queue(struct net_device *ndev)
txq->tx_wake_threshold =
(txq->bd.ring_size - txq->tx_stop_threshold) / 2;
- txq->tso_hdrs = dma_alloc_coherent(NULL,
+ txq->tso_hdrs = dma_alloc_coherent(&fep->pdev->dev,
txq->bd.ring_size * TSO_HEADER_SIZE,
&txq->tso_hdrs_dma,
GFP_KERNEL);
@@ -2832,10 +3027,29 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
return 0;
}
+static inline bool fec_enet_irq_workaround(struct fec_enet_private *fep)
+{
+ struct device_node *np = fep->pdev->dev.of_node;
+ struct device_node *intr_node;
+
+ intr_node = of_parse_phandle(np, "interrupts-extended", 0);
+ if (intr_node && !strcmp(intr_node->name, "gpio")) {
+ /*
+ * If the interrupt controller is a GPIO node, it must have
+ * applied the workaround for WAIT mode bug.
+ */
+ return true;
+ }
+
+ return false;
+}
+
static int
fec_enet_open(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
+ const struct platform_device_id *id_entry =
+ platform_get_device_id(fep->pdev);
int ret;
ret = pm_runtime_get_sync(&fep->pdev->dev);
@@ -2870,6 +3084,16 @@ fec_enet_open(struct net_device *ndev)
phy_start(ndev->phydev);
netif_tx_start_all_queues(ndev);
+ if ((id_entry->driver_data & FEC_QUIRK_BUG_WAITMODE) &&
+ !fec_enet_irq_workaround(fep))
+ pm_qos_add_request(&fep->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY,
+ 0);
+ else
+ pm_qos_add_request(&fep->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
+
device_set_wakeup_enable(&ndev->dev, fep->wol_flag &
FEC_WOL_FLAG_ENABLE);
@@ -2882,7 +3106,8 @@ err_enet_alloc:
clk_enable:
pm_runtime_mark_last_busy(&fep->pdev->dev);
pm_runtime_put_autosuspend(&fep->pdev->dev);
- pinctrl_pm_select_sleep_state(&fep->pdev->dev);
+ if (!fep->mii_bus_share)
+ pinctrl_pm_select_sleep_state(&fep->pdev->dev);
return ret;
}
@@ -2900,6 +3125,7 @@ fec_enet_close(struct net_device *ndev)
}
phy_disconnect(ndev->phydev);
+ ndev->phydev = NULL;
if (fep->quirks & FEC_QUIRK_ERR006687)
imx6q_cpuidle_fec_irqs_unused();
@@ -2907,7 +3133,9 @@ fec_enet_close(struct net_device *ndev)
fec_enet_update_ethtool_stats(ndev);
fec_enet_clk_enable(ndev, false);
- pinctrl_pm_select_sleep_state(&fep->pdev->dev);
+ pm_qos_remove_request(&fep->pm_qos_req);
+ if (!fep->mii_bus_share)
+ pinctrl_pm_select_sleep_state(&fep->pdev->dev);
pm_runtime_mark_last_busy(&fep->pdev->dev);
pm_runtime_put_autosuspend(&fep->pdev->dev);
@@ -3077,10 +3305,42 @@ static int fec_set_features(struct net_device *netdev,
return 0;
}
+u16 fec_enet_get_raw_vlan_tci(struct sk_buff *skb)
+{
+ struct vlan_ethhdr *vhdr;
+ unsigned short vlan_TCI = 0;
+
+ if (skb->protocol == ntohs(ETH_P_ALL)) {
+ vhdr = (struct vlan_ethhdr *)(skb->data);
+ vlan_TCI = ntohs(vhdr->h_vlan_TCI);
+ }
+
+ return vlan_TCI;
+}
+
+u16 fec_enet_select_queue(struct net_device *ndev, struct sk_buff *skb,
+ void *accel_priv, select_queue_fallback_t fallback)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+ const struct platform_device_id *id_entry =
+ platform_get_device_id(fep->pdev);
+ u16 vlan_tag;
+
+ if (!(id_entry->driver_data & FEC_QUIRK_HAS_AVB))
+ return skb_tx_hash(ndev, skb);
+
+ vlan_tag = fec_enet_get_raw_vlan_tci(skb);
+ if (!vlan_tag)
+ return vlan_tag;
+
+ return fec_enet_vlan_pri_to_queue[vlan_tag >> 13];
+}
+
static const struct net_device_ops fec_netdev_ops = {
.ndo_open = fec_enet_open,
.ndo_stop = fec_enet_close,
.ndo_start_xmit = fec_enet_start_xmit,
+ .ndo_select_queue = fec_enet_select_queue,
.ndo_set_rx_mode = set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
@@ -3117,7 +3377,7 @@ static int fec_enet_init(struct net_device *ndev)
unsigned dsize_log2 = __fls(dsize);
WARN_ON(dsize != (1 << dsize_log2));
-#if defined(CONFIG_ARM)
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
fep->rx_align = 0xf;
fep->tx_align = 0xf;
#else
@@ -3223,9 +3483,9 @@ static int fec_reset_phy(struct platform_device *pdev)
if (!np)
return 0;
- of_property_read_u32(np, "phy-reset-duration", &msec);
+ err = of_property_read_u32(np, "phy-reset-duration", &msec);
/* A sane reset duration should not be longer than 1s */
- if (msec > 1000)
+ if (!err && msec > 1000)
msec = 1;
phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
@@ -3295,6 +3555,41 @@ fec_enet_get_queue_num(struct platform_device *pdev, int *num_tx, int *num_rx)
}
+static void fec_enet_of_parse_stop_mode(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct device_node *np = pdev->dev.of_node;
+ struct fec_enet_private *fep = netdev_priv(dev);
+ struct device_node *node;
+ phandle phandle;
+ u32 out_val[3];
+ int ret;
+
+ ret = of_property_read_u32_array(np, "stop-mode", out_val, 3);
+ if (ret) {
+ dev_dbg(&pdev->dev, "no stop-mode property\n");
+ return;
+ }
+
+ phandle = *out_val;
+ node = of_find_node_by_phandle(phandle);
+ if (!node) {
+ dev_dbg(&pdev->dev, "could not find gpr node by phandle\n");
+ return;
+ }
+
+ fep->gpr.gpr = syscon_node_to_regmap(node);
+ if (IS_ERR(fep->gpr.gpr)) {
+ dev_dbg(&pdev->dev, "could not find gpr regmap\n");
+ return;
+ }
+
+ of_node_put(node);
+
+ fep->gpr.req_gpr = out_val[1];
+ fep->gpr.req_bit = out_val[2];
+}
+
static int
fec_probe(struct platform_device *pdev)
{
@@ -3309,6 +3604,8 @@ fec_probe(struct platform_device *pdev)
int num_tx_qs;
int num_rx_qs;
+ of_dma_configure(&pdev->dev, np);
+
fec_enet_get_queue_num(pdev, &num_tx_qs, &num_rx_qs);
/* Init network device */
@@ -3357,9 +3654,17 @@ fec_probe(struct platform_device *pdev)
!of_property_read_bool(np, "fsl,err006687-workaround-present"))
fep->quirks |= FEC_QUIRK_ERR006687;
+ fec_enet_of_parse_stop_mode(pdev);
+
if (of_get_property(np, "fsl,magic-packet", NULL))
fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET;
+ if (of_get_property(np, "fsl,rgmii_txc_dly", NULL))
+ fep->rgmii_txc_dly = true;
+
+ if (of_get_property(np, "fsl,rgmii_rxc_dly", NULL))
+ fep->rgmii_rxc_dly = true;
+
phy_node = of_parse_phandle(np, "phy-handle", 0);
if (!phy_node && of_phy_is_fixed_link(np)) {
ret = of_phy_register_fixed_link(np);
@@ -3369,6 +3674,7 @@ fec_probe(struct platform_device *pdev)
goto failed_phy;
}
phy_node = of_node_get(np);
+ fep->fixed_link = true;
}
fep->phy_node = phy_node;
@@ -3383,6 +3689,8 @@ fec_probe(struct platform_device *pdev)
fep->phy_interface = ret;
}
+ request_bus_freq(BUS_FREQ_HIGH);
+
fep->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(fep->clk_ipg)) {
ret = PTR_ERR(fep->clk_ipg);
@@ -3394,7 +3702,6 @@ fec_probe(struct platform_device *pdev)
ret = PTR_ERR(fep->clk_ahb);
goto failed_clk;
}
-
fep->itr_clk_rate = clk_get_rate(fep->clk_ahb);
/* enet_out is optional, depends on board */
@@ -3409,6 +3716,12 @@ fec_probe(struct platform_device *pdev)
fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref");
if (IS_ERR(fep->clk_ref))
fep->clk_ref = NULL;
+ fep->clk_ref_rate = clk_get_rate(fep->clk_ref);
+
+ /* clk_2x_txclk is optional, depends on board */
+ fep->clk_2x_txclk = devm_clk_get(&pdev->dev, "enet_2x_txclk");
+ if (IS_ERR(fep->clk_2x_txclk))
+ fep->clk_2x_txclk = NULL;
fep->bufdesc_ex = fep->quirks & FEC_QUIRK_HAS_BUFDESC_EX;
fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
@@ -3424,6 +3737,9 @@ fec_probe(struct platform_device *pdev)
ret = clk_prepare_enable(fep->clk_ipg);
if (ret)
goto failed_clk_ipg;
+ ret = clk_prepare_enable(fep->clk_ahb);
+ if (ret)
+ goto failed_clk_ahb;
fep->reg_phy = devm_regulator_get(&pdev->dev, "phy");
if (!IS_ERR(fep->reg_phy)) {
@@ -3431,10 +3747,13 @@ fec_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev,
"Failed to enable phy regulator: %d\n", ret);
- clk_disable_unprepare(fep->clk_ipg);
goto failed_regulator;
}
} else {
+ if (PTR_ERR(fep->reg_phy) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto failed_regulator;
+ }
fep->reg_phy = NULL;
}
@@ -3471,7 +3790,17 @@ fec_probe(struct platform_device *pdev)
fep->irq[i] = irq;
}
+ ret = of_property_read_u32(np, "fsl,wakeup_irq", &irq);
+ if (!ret && irq < FEC_IRQ_NUM)
+ fep->wake_irq = fep->irq[irq];
+ else
+ fep->wake_irq = fep->irq[0];
+
init_completion(&fep->mdio_done);
+
+ /* board only enable one mii bus in default */
+ if (!of_get_property(np, "fsl,mii-exclusive", NULL))
+ fep->quirks |= FEC_QUIRK_SINGLE_MDIO;
ret = fec_enet_mii_init(pdev);
if (ret)
goto failed_mii_init;
@@ -3485,6 +3814,11 @@ fec_probe(struct platform_device *pdev)
if (ret)
goto failed_register;
+ if (!fep->fixed_link) {
+ fep->fixups = of_fec_enet_parse_fixup(np);
+ fec_enet_register_fixup(ndev);
+ }
+
device_init_wakeup(&ndev->dev, fep->wol_flag &
FEC_WOL_HAS_MAGIC_PACKET);
@@ -3508,16 +3842,19 @@ failed_init:
if (fep->reg_phy)
regulator_disable(fep->reg_phy);
failed_reset:
- pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
failed_regulator:
+ clk_disable_unprepare(fep->clk_ahb);
+failed_clk_ahb:
+ clk_disable_unprepare(fep->clk_ipg);
failed_clk_ipg:
fec_enet_clk_enable(ndev, false);
failed_clk:
if (of_phy_is_fixed_link(np))
of_phy_deregister_fixed_link(np);
-failed_phy:
of_node_put(phy_node);
+failed_phy:
+ dev_id--;
failed_ioremap:
free_netdev(ndev);
@@ -3551,6 +3888,7 @@ static int __maybe_unused fec_suspend(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct fec_enet_private *fep = netdev_priv(ndev);
+ int ret = 0;
rtnl_lock();
if (netif_running(ndev)) {
@@ -3562,9 +3900,21 @@ static int __maybe_unused fec_suspend(struct device *dev)
netif_device_detach(ndev);
netif_tx_unlock_bh(ndev);
fec_stop(ndev);
- fec_enet_clk_enable(ndev, false);
- if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE))
+ if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) {
+ fec_irqs_disable(ndev);
pinctrl_pm_select_sleep_state(&fep->pdev->dev);
+ } else {
+ disable_irq(fep->wake_irq);
+ enable_irq_wake(fep->wake_irq);
+ }
+ fec_enet_clk_enable(ndev, false);
+ fep->active_in_suspend = !pm_runtime_status_suspended(dev);
+ if (fep->active_in_suspend)
+ ret = pm_runtime_force_suspend(dev);
+ if (ret < 0)
+ return ret;
+ } else if (fep->mii_bus_share && !ndev->phydev) {
+ pinctrl_pm_select_sleep_state(&fep->pdev->dev);
}
rtnl_unlock();
@@ -3584,8 +3934,7 @@ static int __maybe_unused fec_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct fec_enet_private *fep = netdev_priv(ndev);
- struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
- int ret;
+ int ret = 0;
int val;
if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) {
@@ -3596,14 +3945,18 @@ static int __maybe_unused fec_resume(struct device *dev)
rtnl_lock();
if (netif_running(ndev)) {
+ if (fep->active_in_suspend)
+ pm_runtime_force_resume(dev);
ret = fec_enet_clk_enable(ndev, true);
if (ret) {
rtnl_unlock();
goto failed_clk;
}
+
if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) {
- if (pdata && pdata->sleep_mode_enable)
- pdata->sleep_mode_enable(false);
+ disable_irq_wake(fep->wake_irq);
+ fec_enet_stop_mode(fep, false);
+ enable_irq(fep->wake_irq);
val = readl(fep->hwp + FEC_ECNTRL);
val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
writel(val, fep->hwp + FEC_ECNTRL);
@@ -3617,10 +3970,14 @@ static int __maybe_unused fec_resume(struct device *dev)
netif_tx_unlock_bh(ndev);
napi_enable(&fep->napi);
phy_start(ndev->phydev);
+ } else if (fep->mii_bus_share && !ndev->phydev) {
+ pinctrl_pm_select_default_state(&fep->pdev->dev);
+ /* And then recovery mii bus */
+ ret = fec_restore_mii_bus(ndev);
}
rtnl_unlock();
- return 0;
+ return ret;
failed_clk:
if (fep->reg_phy)
@@ -3633,7 +3990,9 @@ static int __maybe_unused fec_runtime_suspend(struct device *dev)
struct net_device *ndev = dev_get_drvdata(dev);
struct fec_enet_private *fep = netdev_priv(ndev);
+ clk_disable_unprepare(fep->clk_ahb);
clk_disable_unprepare(fep->clk_ipg);
+ release_bus_freq(BUS_FREQ_HIGH);
return 0;
}
@@ -3642,8 +4001,21 @@ static int __maybe_unused fec_runtime_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct fec_enet_private *fep = netdev_priv(ndev);
+ int ret;
+
+ request_bus_freq(BUS_FREQ_HIGH);
+ ret = clk_prepare_enable(fep->clk_ahb);
+ if (ret)
+ return ret;
+ ret = clk_prepare_enable(fep->clk_ipg);
+ if (ret)
+ goto failed_clk_ipg;
+
+ return 0;
- return clk_prepare_enable(fep->clk_ipg);
+failed_clk_ipg:
+ clk_disable_unprepare(fep->clk_ahb);
+ return ret;
}
static const struct dev_pm_ops fec_pm_ops = {
diff --git a/drivers/net/ivshmem-net.c b/drivers/net/ivshmem-net.c
new file mode 100644
index 000000000000..aba77c232c48
--- /dev/null
+++ b/drivers/net/ivshmem-net.c
@@ -0,0 +1,984 @@
+/*
+ * Copyright 2016 Mans Rullgard <mans@mansr.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/virtio_ring.h>
+
+#define DRV_NAME "ivshmem-net"
+
+#define JAILHOUSE_CFG_SHMEM_PTR 0x40
+#define JAILHOUSE_CFG_SHMEM_SZ 0x48
+
+#define IVSHMEM_INTX_ENABLE 0x1
+
+#define IVSHM_NET_STATE_RESET 0
+#define IVSHM_NET_STATE_INIT 1
+#define IVSHM_NET_STATE_READY 2
+#define IVSHM_NET_STATE_RUN 3
+
+#define IVSHM_NET_FLAG_RUN 0
+
+#define IVSHM_NET_MTU_MIN 256
+#define IVSHM_NET_MTU_MAX 65535
+#define IVSHM_NET_MTU_DEF 16384
+
+#define IVSHM_NET_FRAME_SIZE(s) ALIGN(18 + (s), SMP_CACHE_BYTES)
+
+#define IVSHM_NET_VQ_ALIGN 64
+
+struct ivshmem_regs {
+ u32 intxctrl;
+ u32 istat;
+ u32 ivpos;
+ u32 doorbell;
+ u32 lstate;
+ u32 rstate;
+};
+
+struct ivshm_net_queue {
+ struct vring vr;
+ u32 free_head;
+ u32 num_free;
+ u32 num_added;
+ u16 last_avail_idx;
+ u16 last_used_idx;
+
+ void *data;
+ void *end;
+ u32 size;
+ u32 head;
+ u32 tail;
+};
+
+struct ivshm_net_stats {
+ u32 interrupts;
+ u32 tx_packets;
+ u32 tx_notify;
+ u32 tx_pause;
+ u32 rx_packets;
+ u32 rx_notify;
+ u32 napi_poll;
+ u32 napi_complete;
+ u32 napi_poll_n[10];
+};
+
+struct ivshm_net {
+ struct ivshm_net_queue rx;
+ struct ivshm_net_queue tx;
+
+ u32 vrsize;
+ u32 qlen;
+ u32 qsize;
+
+ spinlock_t tx_free_lock;
+ spinlock_t tx_clean_lock;
+
+ struct napi_struct napi;
+
+ u32 lstate;
+ u32 rstate;
+
+ unsigned long flags;
+
+ struct workqueue_struct *state_wq;
+ struct work_struct state_work;
+
+ struct ivshm_net_stats stats;
+
+ struct ivshmem_regs __iomem *ivshm_regs;
+ void *shm;
+ phys_addr_t shmaddr;
+ resource_size_t shmlen;
+ u32 peer_id;
+
+ struct pci_dev *pdev;
+};
+
+static void *ivshm_net_desc_data(struct ivshm_net *in,
+ struct ivshm_net_queue *q,
+ struct vring_desc *desc,
+ u32 *len)
+{
+ u64 offs = READ_ONCE(desc->addr);
+ u32 dlen = READ_ONCE(desc->len);
+ u16 flags = READ_ONCE(desc->flags);
+ void *data;
+
+ if (flags)
+ return NULL;
+
+ if (offs >= in->shmlen)
+ return NULL;
+
+ data = in->shm + offs;
+
+ if (data < q->data || data >= q->end)
+ return NULL;
+
+ if (dlen > q->end - data)
+ return NULL;
+
+ *len = dlen;
+
+ return data;
+}
+
+static void ivshm_net_init_queue(struct ivshm_net *in,
+ struct ivshm_net_queue *q,
+ void *mem, unsigned int len)
+{
+ memset(q, 0, sizeof(*q));
+
+ vring_init(&q->vr, len, mem, IVSHM_NET_VQ_ALIGN);
+ q->data = mem + in->vrsize;
+ q->end = q->data + in->qsize;
+ q->size = in->qsize;
+}
+
+static void ivshm_net_init_queues(struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+ int ivpos = readl(&in->ivshm_regs->ivpos);
+ void *tx;
+ void *rx;
+ int i;
+
+ tx = in->shm + ivpos * in->shmlen / 2;
+ rx = in->shm + !ivpos * in->shmlen / 2;
+
+ memset(tx, 0, in->shmlen / 2);
+
+ ivshm_net_init_queue(in, &in->rx, rx, in->qlen);
+ ivshm_net_init_queue(in, &in->tx, tx, in->qlen);
+
+ swap(in->rx.vr.used, in->tx.vr.used);
+
+ in->tx.num_free = in->tx.vr.num;
+
+ for (i = 0; i < in->tx.vr.num - 1; i++)
+ in->tx.vr.desc[i].next = i + 1;
+}
+
+static int ivshm_net_calc_qsize(struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+ unsigned int vrsize;
+ unsigned int qsize;
+ unsigned int qlen;
+
+ for (qlen = 4096; qlen > 32; qlen >>= 1) {
+ vrsize = vring_size(qlen, IVSHM_NET_VQ_ALIGN);
+ vrsize = ALIGN(vrsize, IVSHM_NET_VQ_ALIGN);
+ if (vrsize < in->shmlen / 16)
+ break;
+ }
+
+ if (vrsize > in->shmlen / 2)
+ return -EINVAL;
+
+ qsize = in->shmlen / 2 - vrsize;
+
+ if (qsize < 4 * IVSHM_NET_MTU_MIN)
+ return -EINVAL;
+
+ in->vrsize = vrsize;
+ in->qlen = qlen;
+ in->qsize = qsize;
+
+ return 0;
+}
+
+static void ivshm_net_notify_tx(struct ivshm_net *in, unsigned int num)
+{
+ u16 evt, old, new;
+
+ virt_mb();
+
+ evt = READ_ONCE(vring_avail_event(&in->tx.vr));
+ old = in->tx.last_avail_idx - num;
+ new = in->tx.last_avail_idx;
+
+ if (vring_need_event(evt, new, old)) {
+ writel(in->peer_id << 16, &in->ivshm_regs->doorbell);
+ in->stats.tx_notify++;
+ }
+}
+
+static void ivshm_net_enable_rx_irq(struct ivshm_net *in)
+{
+ vring_avail_event(&in->rx.vr) = in->rx.last_avail_idx;
+ virt_wmb();
+}
+
+static void ivshm_net_notify_rx(struct ivshm_net *in, unsigned int num)
+{
+ u16 evt, old, new;
+
+ virt_mb();
+
+ evt = vring_used_event(&in->rx.vr);
+ old = in->rx.last_used_idx - num;
+ new = in->rx.last_used_idx;
+
+ if (vring_need_event(evt, new, old)) {
+ writel(in->peer_id << 16, &in->ivshm_regs->doorbell);
+ in->stats.rx_notify++;
+ }
+}
+
+static void ivshm_net_enable_tx_irq(struct ivshm_net *in)
+{
+ vring_used_event(&in->tx.vr) = in->tx.last_used_idx;
+ virt_wmb();
+}
+
+static bool ivshm_net_rx_avail(struct ivshm_net *in)
+{
+ virt_mb();
+ return READ_ONCE(in->rx.vr.avail->idx) != in->rx.last_avail_idx;
+}
+
+static size_t ivshm_net_tx_space(struct ivshm_net *in)
+{
+ struct ivshm_net_queue *tx = &in->tx;
+ u32 tail = tx->tail;
+ u32 head = tx->head;
+ u32 space;
+
+ if (head < tail)
+ space = tail - head;
+ else
+ space = max(tx->size - head, tail);
+
+ return space;
+}
+
+static bool ivshm_net_tx_ok(struct ivshm_net *in, unsigned int mtu)
+{
+ return in->tx.num_free >= 2 &&
+ ivshm_net_tx_space(in) >= 2 * IVSHM_NET_FRAME_SIZE(mtu);
+}
+
+static u32 ivshm_net_tx_advance(struct ivshm_net_queue *q, u32 *pos, u32 len)
+{
+ u32 p = *pos;
+
+ len = IVSHM_NET_FRAME_SIZE(len);
+
+ if (q->size - p < len)
+ p = 0;
+ *pos = p + len;
+
+ return p;
+}
+
+static int ivshm_net_tx_frame(struct net_device *ndev, struct sk_buff *skb)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+ struct ivshm_net_queue *tx = &in->tx;
+ struct vring *vr = &tx->vr;
+ struct vring_desc *desc;
+ unsigned int desc_idx;
+ unsigned int avail;
+ u32 head;
+ void *buf;
+
+ BUG_ON(tx->num_free < 1);
+
+ spin_lock(&in->tx_free_lock);
+ desc_idx = tx->free_head;
+ desc = &vr->desc[desc_idx];
+ tx->free_head = desc->next;
+ tx->num_free--;
+ spin_unlock(&in->tx_free_lock);
+
+ head = ivshm_net_tx_advance(tx, &tx->head, skb->len);
+
+ buf = tx->data + head;
+ skb_copy_and_csum_dev(skb, buf);
+
+ desc->addr = buf - in->shm;
+ desc->len = skb->len;
+ desc->flags = 0;
+
+ avail = tx->last_avail_idx++ & (vr->num - 1);
+ vr->avail->ring[avail] = desc_idx;
+ tx->num_added++;
+
+ if (!skb->xmit_more) {
+ virt_store_release(&vr->avail->idx, tx->last_avail_idx);
+ ivshm_net_notify_tx(in, tx->num_added);
+ tx->num_added = 0;
+ }
+
+ return 0;
+}
+
+static void ivshm_net_tx_clean(struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+ struct ivshm_net_queue *tx = &in->tx;
+ struct vring_used_elem *used;
+ struct vring *vr = &tx->vr;
+ struct vring_desc *desc;
+ struct vring_desc *fdesc;
+ unsigned int num;
+ u16 used_idx;
+ u16 last;
+ u32 fhead;
+
+ if (!spin_trylock(&in->tx_clean_lock))
+ return;
+
+ used_idx = virt_load_acquire(&vr->used->idx);
+ last = tx->last_used_idx;
+
+ fdesc = NULL;
+ fhead = 0;
+ num = 0;
+
+ while (last != used_idx) {
+ void *data;
+ u32 len;
+ u32 tail;
+
+ used = vr->used->ring + (last % vr->num);
+ if (used->id >= vr->num || used->len != 1) {
+ netdev_err(ndev, "invalid tx used->id %d ->len %d\n",
+ used->id, used->len);
+ break;
+ }
+
+ desc = &vr->desc[used->id];
+
+ data = ivshm_net_desc_data(in, &in->tx, desc, &len);
+ if (!data) {
+ netdev_err(ndev, "bad tx descriptor, data == NULL\n");
+ break;
+ }
+
+ tail = ivshm_net_tx_advance(tx, &tx->tail, len);
+ if (data != tx->data + tail) {
+ netdev_err(ndev, "bad tx descriptor\n");
+ break;
+ }
+
+ if (!num)
+ fdesc = desc;
+ else
+ desc->next = fhead;
+
+ fhead = used->id;
+ last++;
+ num++;
+ }
+
+ tx->last_used_idx = last;
+
+ spin_unlock(&in->tx_clean_lock);
+
+ if (num) {
+ spin_lock(&in->tx_free_lock);
+ fdesc->next = tx->free_head;
+ tx->free_head = fhead;
+ tx->num_free += num;
+ BUG_ON(tx->num_free > vr->num);
+ spin_unlock(&in->tx_free_lock);
+ }
+}
+
+static struct vring_desc *ivshm_net_rx_desc(struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+ struct ivshm_net_queue *rx = &in->rx;
+ struct vring *vr = &rx->vr;
+ unsigned int avail;
+ u16 avail_idx;
+
+ avail_idx = virt_load_acquire(&vr->avail->idx);
+
+ if (avail_idx == rx->last_avail_idx)
+ return NULL;
+
+ avail = vr->avail->ring[rx->last_avail_idx++ & (vr->num - 1)];
+ if (avail >= vr->num) {
+ netdev_err(ndev, "invalid rx avail %d\n", avail);
+ return NULL;
+ }
+
+ return &vr->desc[avail];
+}
+
+static void ivshm_net_rx_finish(struct ivshm_net *in, struct vring_desc *desc)
+{
+ struct ivshm_net_queue *rx = &in->rx;
+ struct vring *vr = &rx->vr;
+ unsigned int desc_id = desc - vr->desc;
+ unsigned int used;
+
+ used = rx->last_used_idx++ & (vr->num - 1);
+ vr->used->ring[used].id = desc_id;
+ vr->used->ring[used].len = 1;
+
+ virt_store_release(&vr->used->idx, rx->last_used_idx);
+}
+
+static int ivshm_net_poll(struct napi_struct *napi, int budget)
+{
+ struct net_device *ndev = napi->dev;
+ struct ivshm_net *in = container_of(napi, struct ivshm_net, napi);
+ int received = 0;
+
+ in->stats.napi_poll++;
+
+ ivshm_net_tx_clean(ndev);
+
+ while (received < budget) {
+ struct vring_desc *desc;
+ struct sk_buff *skb;
+ void *data;
+ u32 len;
+
+ desc = ivshm_net_rx_desc(ndev);
+ if (!desc)
+ break;
+
+ data = ivshm_net_desc_data(in, &in->rx, desc, &len);
+ if (!data) {
+ netdev_err(ndev, "bad rx descriptor\n");
+ break;
+ }
+
+ skb = napi_alloc_skb(napi, len);
+
+ if (skb) {
+ memcpy(skb_put(skb, len), data, len);
+ skb->protocol = eth_type_trans(skb, ndev);
+ napi_gro_receive(napi, skb);
+ }
+
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += len;
+
+ ivshm_net_rx_finish(in, desc);
+ received++;
+ }
+
+ if (received < budget) {
+ in->stats.napi_complete++;
+ napi_complete_done(napi, received);
+ ivshm_net_enable_rx_irq(in);
+ if (ivshm_net_rx_avail(in))
+ napi_schedule(napi);
+ }
+
+ if (received)
+ ivshm_net_notify_rx(in, received);
+
+ in->stats.rx_packets += received;
+ in->stats.napi_poll_n[received ? 1 + min(ilog2(received), 8) : 0]++;
+
+ if (ivshm_net_tx_ok(in, ndev->mtu))
+ netif_wake_queue(ndev);
+
+ return received;
+}
+
+static netdev_tx_t ivshm_net_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+
+ ivshm_net_tx_clean(ndev);
+
+ if (!ivshm_net_tx_ok(in, ndev->mtu)) {
+ ivshm_net_enable_tx_irq(in);
+ netif_stop_queue(ndev);
+ skb->xmit_more = 0;
+ in->stats.tx_pause++;
+ }
+
+ ivshm_net_tx_frame(ndev, skb);
+
+ in->stats.tx_packets++;
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += skb->len;
+
+ dev_consume_skb_any(skb);
+
+ return NETDEV_TX_OK;
+}
+
+static void ivshm_net_set_state(struct ivshm_net *in, u32 state)
+{
+ virt_wmb();
+ WRITE_ONCE(in->lstate, state);
+ writel(state, &in->ivshm_regs->lstate);
+}
+
+static void ivshm_net_run(struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+
+ if (in->lstate < IVSHM_NET_STATE_READY)
+ return;
+
+ if (!netif_running(ndev))
+ return;
+
+ if (test_and_set_bit(IVSHM_NET_FLAG_RUN, &in->flags))
+ return;
+
+ netif_start_queue(ndev);
+ napi_enable(&in->napi);
+ napi_schedule(&in->napi);
+ ivshm_net_set_state(in, IVSHM_NET_STATE_RUN);
+}
+
+static void ivshm_net_do_stop(struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+
+ ivshm_net_set_state(in, IVSHM_NET_STATE_RESET);
+
+ if (!test_and_clear_bit(IVSHM_NET_FLAG_RUN, &in->flags))
+ return;
+
+ netif_stop_queue(ndev);
+ napi_disable(&in->napi);
+}
+
+static void ivshm_net_state_change(struct work_struct *work)
+{
+ struct ivshm_net *in = container_of(work, struct ivshm_net, state_work);
+ struct net_device *ndev = in->napi.dev;
+ u32 rstate = readl(&in->ivshm_regs->rstate);
+
+ switch (in->lstate) {
+ case IVSHM_NET_STATE_RESET:
+ /*
+ * Wait for the remote to leave READY/RUN before transitioning
+ * to INIT.
+ */
+ if (rstate < IVSHM_NET_STATE_READY)
+ ivshm_net_set_state(in, IVSHM_NET_STATE_INIT);
+ break;
+
+ case IVSHM_NET_STATE_INIT:
+ /*
+ * Wait for the remote to leave RESET before performing the
+ * initialization and moving to READY.
+ */
+ if (rstate > IVSHM_NET_STATE_RESET) {
+ ivshm_net_init_queues(ndev);
+ ivshm_net_set_state(in, IVSHM_NET_STATE_READY);
+
+ rtnl_lock();
+ call_netdevice_notifiers(NETDEV_CHANGEADDR, ndev);
+ rtnl_unlock();
+ }
+ break;
+
+ case IVSHM_NET_STATE_READY:
+ /*
+ * Link is up and we are running once the remote is in READY or
+ * RUN.
+ */
+ if (rstate >= IVSHM_NET_STATE_READY) {
+ netif_carrier_on(ndev);
+ ivshm_net_run(ndev);
+ break;
+ }
+ /* fall through */
+ case IVSHM_NET_STATE_RUN:
+ /*
+ * If the remote goes to RESET, we need to follow immediately.
+ */
+ if (rstate == IVSHM_NET_STATE_RESET) {
+ netif_carrier_off(ndev);
+ ivshm_net_do_stop(ndev);
+ }
+ break;
+ }
+
+ virt_wmb();
+ WRITE_ONCE(in->rstate, rstate);
+}
+
+static void ivshm_net_check_state(struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+ u32 rstate = readl(&in->ivshm_regs->rstate);
+
+ if (rstate != in->rstate || !test_bit(IVSHM_NET_FLAG_RUN, &in->flags))
+ queue_work(in->state_wq, &in->state_work);
+}
+
+static irqreturn_t ivshm_net_int(int irq, void *data)
+{
+ struct net_device *ndev = data;
+ struct ivshm_net *in = netdev_priv(ndev);
+
+ in->stats.interrupts++;
+
+ ivshm_net_check_state(ndev);
+ napi_schedule_irqoff(&in->napi);
+
+ return IRQ_HANDLED;
+}
+
+static int ivshm_net_open(struct net_device *ndev)
+{
+ netdev_reset_queue(ndev);
+ ndev->operstate = IF_OPER_UP;
+ ivshm_net_run(ndev);
+
+ return 0;
+}
+
+static int ivshm_net_stop(struct net_device *ndev)
+{
+ ndev->operstate = IF_OPER_DOWN;
+ ivshm_net_do_stop(ndev);
+
+ return 0;
+}
+
+static int ivshm_net_change_mtu(struct net_device *ndev, int mtu)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+ struct ivshm_net_queue *tx = &in->tx;
+
+ if (mtu < IVSHM_NET_MTU_MIN || mtu > IVSHM_NET_MTU_MAX)
+ return -EINVAL;
+
+ if (in->tx.size / mtu < 4)
+ return -EINVAL;
+
+ if (ivshm_net_tx_space(in) < 2 * IVSHM_NET_FRAME_SIZE(mtu))
+ return -EBUSY;
+
+ if (in->tx.size - tx->head < IVSHM_NET_FRAME_SIZE(mtu) &&
+ tx->head < tx->tail)
+ return -EBUSY;
+
+ netif_tx_lock_bh(ndev);
+ if (in->tx.size - tx->head < IVSHM_NET_FRAME_SIZE(mtu))
+ tx->head = 0;
+ netif_tx_unlock_bh(ndev);
+
+ ndev->mtu = mtu;
+
+ return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void ivshm_net_poll_controller(struct net_device *ndev)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+
+ napi_schedule(&in->napi);
+}
+#endif
+
+static const struct net_device_ops ivshm_net_ops = {
+ .ndo_open = ivshm_net_open,
+ .ndo_stop = ivshm_net_stop,
+ .ndo_start_xmit = ivshm_net_xmit,
+ .ndo_change_mtu = ivshm_net_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = ivshm_net_poll_controller,
+#endif
+};
+
+static const char ivshm_net_stats[][ETH_GSTRING_LEN] = {
+ "interrupts",
+ "tx_packets",
+ "tx_notify",
+ "tx_pause",
+ "rx_packets",
+ "rx_notify",
+ "napi_poll",
+ "napi_complete",
+ "napi_poll_0",
+ "napi_poll_1",
+ "napi_poll_2",
+ "napi_poll_4",
+ "napi_poll_8",
+ "napi_poll_16",
+ "napi_poll_32",
+ "napi_poll_64",
+ "napi_poll_128",
+ "napi_poll_256",
+};
+
+#define NUM_STATS ARRAY_SIZE(ivshm_net_stats)
+
+static int ivshm_net_get_sset_count(struct net_device *ndev, int sset)
+{
+ if (sset == ETH_SS_STATS)
+ return NUM_STATS;
+
+ return -EOPNOTSUPP;
+}
+
+static void ivshm_net_get_strings(struct net_device *ndev, u32 sset, u8 *buf)
+{
+ if (sset == ETH_SS_STATS)
+ memcpy(buf, &ivshm_net_stats, sizeof(ivshm_net_stats));
+}
+
+static void ivshm_net_get_ethtool_stats(struct net_device *ndev,
+ struct ethtool_stats *estats, u64 *st)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+ unsigned int n = 0;
+ unsigned int i;
+
+ st[n++] = in->stats.interrupts;
+ st[n++] = in->stats.tx_packets;
+ st[n++] = in->stats.tx_notify;
+ st[n++] = in->stats.tx_pause;
+ st[n++] = in->stats.rx_packets;
+ st[n++] = in->stats.rx_notify;
+ st[n++] = in->stats.napi_poll;
+ st[n++] = in->stats.napi_complete;
+
+ for (i = 0; i < ARRAY_SIZE(in->stats.napi_poll_n); i++)
+ st[n++] = in->stats.napi_poll_n[i];
+
+ memset(&in->stats, 0, sizeof(in->stats));
+}
+
+#define IVSHM_NET_REGS_LEN (3 * sizeof(u32) + 6 * sizeof(u16))
+
+static int ivshm_net_get_regs_len(struct net_device *ndev)
+{
+ return IVSHM_NET_REGS_LEN;
+}
+
+static void ivshm_net_get_regs(struct net_device *ndev,
+ struct ethtool_regs *regs, void *p)
+{
+ struct ivshm_net *in = netdev_priv(ndev);
+ u32 *reg32 = p;
+ u16 *reg16;
+
+ *reg32++ = in->lstate;
+ *reg32++ = in->rstate;
+ *reg32++ = in->qlen;
+
+ reg16 = (u16 *)reg32;
+
+ *reg16++ = in->tx.vr.avail ? in->tx.vr.avail->idx : 0;
+ *reg16++ = in->tx.vr.used ? in->tx.vr.used->idx : 0;
+ *reg16++ = in->tx.vr.avail ? vring_avail_event(&in->tx.vr) : 0;
+
+ *reg16++ = in->rx.vr.avail ? in->rx.vr.avail->idx : 0;
+ *reg16++ = in->rx.vr.used ? in->rx.vr.used->idx : 0;
+ *reg16++ = in->rx.vr.avail ? vring_avail_event(&in->rx.vr) : 0;
+}
+
+static const struct ethtool_ops ivshm_net_ethtool_ops = {
+ .get_sset_count = ivshm_net_get_sset_count,
+ .get_strings = ivshm_net_get_strings,
+ .get_ethtool_stats = ivshm_net_get_ethtool_stats,
+ .get_regs_len = ivshm_net_get_regs_len,
+ .get_regs = ivshm_net_get_regs,
+};
+
+static int ivshm_net_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct net_device *ndev;
+ struct ivshm_net *in;
+ struct ivshmem_regs __iomem *regs;
+ resource_size_t shmaddr;
+ resource_size_t shmlen;
+ char *device_name;
+ void *shm;
+ u32 ivpos;
+ int ret;
+
+ ret = pcim_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "pci_enable_device: %d\n", ret);
+ return ret;
+ }
+
+ ret = pcim_iomap_regions(pdev, BIT(0), DRV_NAME);
+ if (ret) {
+ dev_err(&pdev->dev, "pcim_iomap_regions: %d\n", ret);
+ return ret;
+ }
+
+ regs = pcim_iomap_table(pdev)[0];
+
+ shmlen = pci_resource_len(pdev, 2);
+
+ if (shmlen) {
+ shmaddr = pci_resource_start(pdev, 2);
+ } else {
+ union { u64 v; u32 hl[2]; } val;
+
+ pci_read_config_dword(pdev, JAILHOUSE_CFG_SHMEM_PTR,
+ &val.hl[0]);
+ pci_read_config_dword(pdev, JAILHOUSE_CFG_SHMEM_PTR + 4,
+ &val.hl[1]);
+ shmaddr = val.v;
+
+ pci_read_config_dword(pdev, JAILHOUSE_CFG_SHMEM_SZ,
+ &val.hl[0]);
+ pci_read_config_dword(pdev, JAILHOUSE_CFG_SHMEM_SZ + 4,
+ &val.hl[1]);
+ shmlen = val.v;
+ }
+
+
+ if (!devm_request_mem_region(&pdev->dev, shmaddr, shmlen, DRV_NAME))
+ return -EBUSY;
+
+ shm = devm_memremap(&pdev->dev, shmaddr, shmlen, MEMREMAP_WB);
+ if (!shm)
+ return -ENOMEM;
+
+ ivpos = readl(&regs->ivpos);
+ if (ivpos > 1) {
+ dev_err(&pdev->dev, "invalid IVPosition %d\n", ivpos);
+ return -EINVAL;
+ }
+
+ device_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s[%s]", DRV_NAME,
+ dev_name(&pdev->dev));
+ if (!device_name)
+ return -ENOMEM;
+
+ ndev = alloc_etherdev(sizeof(*in));
+ if (!ndev)
+ return -ENOMEM;
+
+ pci_set_drvdata(pdev, ndev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ in = netdev_priv(ndev);
+ in->ivshm_regs = regs;
+ in->shm = shm;
+ in->shmaddr = shmaddr;
+ in->shmlen = shmlen;
+ in->peer_id = !ivpos;
+ in->pdev = pdev;
+ spin_lock_init(&in->tx_free_lock);
+ spin_lock_init(&in->tx_clean_lock);
+
+ ret = ivshm_net_calc_qsize(ndev);
+ if (ret)
+ goto err_free;
+
+ in->state_wq = alloc_ordered_workqueue(device_name, 0);
+ if (!in->state_wq)
+ goto err_free;
+
+ INIT_WORK(&in->state_work, ivshm_net_state_change);
+
+ eth_random_addr(ndev->dev_addr);
+ ndev->netdev_ops = &ivshm_net_ops;
+ ndev->ethtool_ops = &ivshm_net_ethtool_ops;
+ ndev->mtu = min_t(u32, IVSHM_NET_MTU_DEF, in->qsize / 16);
+ ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG;
+ ndev->features = ndev->hw_features;
+
+ netif_carrier_off(ndev);
+ netif_napi_add(ndev, &in->napi, ivshm_net_poll, NAPI_POLL_WEIGHT);
+
+ ret = register_netdev(ndev);
+ if (ret)
+ goto err_wq;
+
+ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY | PCI_IRQ_MSIX);
+ if (ret < 0)
+ goto err_alloc_irq;
+
+ ret = request_irq(pci_irq_vector(pdev, 0), ivshm_net_int, 0,
+ device_name, ndev);
+ if (ret)
+ goto err_request_irq;
+
+ pci_set_master(pdev);
+ if (!pdev->msix_enabled)
+ writel(IVSHMEM_INTX_ENABLE, &in->ivshm_regs->intxctrl);
+
+ writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->lstate);
+ ivshm_net_check_state(ndev);
+
+ return 0;
+
+err_request_irq:
+ pci_free_irq_vectors(pdev);
+err_alloc_irq:
+ unregister_netdev(ndev);
+err_wq:
+ destroy_workqueue(in->state_wq);
+err_free:
+ free_netdev(ndev);
+
+ return ret;
+}
+
+static void ivshm_net_remove(struct pci_dev *pdev)
+{
+ struct net_device *ndev = pci_get_drvdata(pdev);
+ struct ivshm_net *in = netdev_priv(ndev);
+
+ writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->lstate);
+
+ if (!pdev->msix_enabled)
+ writel(0, &in->ivshm_regs->intxctrl);
+ free_irq(pci_irq_vector(pdev, 0), ndev);
+ pci_free_irq_vectors(pdev);
+
+ unregister_netdev(ndev);
+ cancel_work_sync(&in->state_work);
+ destroy_workqueue(in->state_wq);
+ free_netdev(ndev);
+}
+
+static const struct pci_device_id ivshm_net_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_REDHAT_QUMRANET, 0x1110),
+ (PCI_CLASS_OTHERS << 16) | (0x01 << 8), 0xffff00 },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, ivshm_net_id_table);
+
+static struct pci_driver ivshm_net_driver = {
+ .name = DRV_NAME,
+ .id_table = ivshm_net_id_table,
+ .probe = ivshm_net_probe,
+ .remove = ivshm_net_remove,
+};
+module_pci_driver(ivshm_net_driver);
+
+MODULE_AUTHOR("Mans Rullgard <mans@mansr.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 2651c8d8de2f..77bb673a9ff2 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -284,6 +284,11 @@ config NATIONAL_PHY
---help---
Currently supports the DP83865 PHY.
+config NXP_TJA110X_PHY
+ tristate "NXP TJA110X PHY support"
+ ---help---
+ Currently supports the TJA110X PHY.
+
config QSEMI_PHY
tristate "Quality Semiconductor PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index e58667d111e7..d00b451d57d0 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_MICREL_PHY) += micrel.o
obj-$(CONFIG_MICROCHIP_PHY) += microchip.o
obj-$(CONFIG_MICROSEMI_PHY) += mscc.o
obj-$(CONFIG_NATIONAL_PHY) += national.o
+obj-$(CONFIG_NXP_TJA110X_PHY) += tja110x.o
obj-$(CONFIG_QSEMI_PHY) += qsemi.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_SMSC_PHY) += smsc.o
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index 3603eec7217f..5a0a23d59aab 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -18,6 +18,7 @@
#include <linux/etherdevice.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
+#include <linux/phy.h>
#define AT803X_INTR_ENABLE 0x12
#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15)
@@ -39,11 +40,13 @@
#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C
#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A
+#define AT803X_SMARTEEE_CTL3_OFFSET 0x805D
#define AT803X_MMD_ACCESS_CONTROL 0x0D
#define AT803X_MMD_ACCESS_CONTROL_DATA 0x0E
#define AT803X_FUNC_DATA 0x4003
#define AT803X_REG_CHIP_CONFIG 0x1f
#define AT803X_BT_BX_REG_SEL 0x8000
+#define AT803X_SMARTEEE_DISABLED_VAL 0x1000
#define AT803X_DEBUG_ADDR 0x1D
#define AT803X_DEBUG_DATA 0x1E
@@ -60,10 +63,21 @@
#define AT803X_DEBUG_REG_5 0x05
#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
+#define AT803X_DEBUG_REG_31 0x1f
+#define AT803X_VDDIO_1P8V_EN 0x8
+
#define ATH8030_PHY_ID 0x004dd076
#define ATH8031_PHY_ID 0x004dd074
#define ATH8035_PHY_ID 0x004dd072
+/* LED_ACT is busy on blinding even if no any frame transferring,
+ * it may cause by PHY/RJ45 power supply issue, the fixup flag just
+ * to do sw workaround for the issue.
+ */
+#define AT803X_LED_ACT_BLINDING_WORKAROUND (1 << 0)
+#define AT803X_EEE_FEATURE_DISABLE (1 << 1)
+#define AT803X_VDDIO_1P8V (1 << 2)
+
MODULE_DESCRIPTION("Atheros 803x PHY driver");
MODULE_AUTHOR("Matus Ujhelyi");
MODULE_LICENSE("GPL");
@@ -71,6 +85,7 @@ MODULE_LICENSE("GPL");
struct at803x_priv {
bool phy_reset:1;
struct gpio_desc *gpiod_reset;
+ u32 quirks;
};
struct at803x_context {
@@ -110,16 +125,57 @@ static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
return phy_write(phydev, AT803X_DEBUG_DATA, val);
}
-static inline int at803x_enable_rx_delay(struct phy_device *phydev)
+static inline int at803x_set_rx_delay(struct phy_device *phydev, bool is_enabled)
{
- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
- AT803X_DEBUG_RX_CLK_DLY_EN);
+ if (is_enabled)
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
+ AT803X_DEBUG_RX_CLK_DLY_EN);
+ else
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
+ AT803X_DEBUG_RX_CLK_DLY_EN, 0);
}
-static inline int at803x_enable_tx_delay(struct phy_device *phydev)
+static inline int at803x_set_tx_delay(struct phy_device *phydev, bool is_enabled)
{
- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
- AT803X_DEBUG_TX_CLK_DLY_EN);
+ if (is_enabled)
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
+ AT803X_DEBUG_TX_CLK_DLY_EN);
+ else
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5,
+ AT803X_DEBUG_TX_CLK_DLY_EN, 0);
+}
+
+static inline int at803x_set_vddio_1p8v(struct phy_device *phydev)
+{
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_31, 0,
+ AT803X_VDDIO_1P8V_EN);
+}
+
+static int at803x_disable_eee(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
+ AT803X_DEVICE_ADDR);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
+ AT803X_SMARTEEE_CTL3_OFFSET);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
+ AT803X_FUNC_DATA);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
+ AT803X_SMARTEEE_DISABLED_VAL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
/* save relevant PHY registers to private copy */
@@ -259,6 +315,15 @@ static int at803x_probe(struct phy_device *phydev)
if (!priv)
return -ENOMEM;
+ if (of_property_read_bool(dev->of_node, "at803x,led-act-blind-workaround"))
+ priv->quirks |= AT803X_LED_ACT_BLINDING_WORKAROUND;
+
+ if (of_property_read_bool(dev->of_node, "at803x,eee-disabled"))
+ priv->quirks |= AT803X_EEE_FEATURE_DISABLE;
+
+ if (of_property_read_bool(dev->of_node, "at803x,vddio-1p8v"))
+ priv->quirks |= AT803X_VDDIO_1P8V;
+
if (phydev->drv->phy_id != ATH8030_PHY_ID)
goto does_not_require_reset_workaround;
@@ -277,21 +342,44 @@ does_not_require_reset_workaround:
static int at803x_config_init(struct phy_device *phydev)
{
int ret;
+ struct at803x_priv *priv = phydev->priv;
ret = genphy_config_init(phydev);
if (ret < 0)
return ret;
+ /* Firstly clear the default status in HW reset or
+ * the bits set by bootloader.
+ */
+ ret = at803x_set_rx_delay(phydev, false);
+ if (ret < 0)
+ return ret;
+ ret = at803x_set_tx_delay(phydev, false);
+ if (ret < 0)
+ return ret;
+
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
- ret = at803x_enable_rx_delay(phydev);
+ ret = at803x_set_rx_delay(phydev, true);
if (ret < 0)
return ret;
}
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
- ret = at803x_enable_tx_delay(phydev);
+ ret = at803x_set_tx_delay(phydev, true);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (priv->quirks & AT803X_VDDIO_1P8V) {
+ ret = at803x_set_vddio_1p8v(phydev);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (priv->quirks & AT803X_EEE_FEATURE_DISABLE) {
+ ret = at803x_disable_eee(phydev);
if (ret < 0)
return ret;
}
@@ -363,6 +451,37 @@ static void at803x_link_change_notify(struct phy_device *phydev)
}
}
+int at803x_config_aneg(struct phy_device *phydev)
+{
+ struct at803x_priv *priv = phydev->priv;
+ int result;
+
+ /* Only restart aneg if we are advertising something different
+ * than we were before.
+ */
+ result = genphy_config_aneg_check(phydev);
+ if (result > 0) {
+ /* do autonegotiation here */
+ result = phy_read(phydev, MII_BMCR);
+ if (result < 0)
+ return result;
+
+ /* firstly power down here */
+ if (priv->quirks & AT803X_LED_ACT_BLINDING_WORKAROUND) {
+ phy_write(phydev, MII_BMCR, BMCR_PDOWN);
+ msleep(1);
+ }
+
+ result |= BMCR_ANENABLE | BMCR_ANRESTART;
+ /* Don't isolate the PHY if we're negotiating */
+ result &= ~BMCR_ISOLATE;
+
+ result = phy_write(phydev, MII_BMCR, result);
+ }
+
+ return result;
+}
+
static int at803x_aneg_done(struct phy_device *phydev)
{
int ccr;
@@ -442,7 +561,7 @@ static struct phy_driver at803x_driver[] = {
.resume = at803x_resume,
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
- .config_aneg = genphy_config_aneg,
+ .config_aneg = at803x_config_aneg,
.read_status = genphy_read_status,
.aneg_done = at803x_aneg_done,
.ack_interrupt = &at803x_ack_interrupt,
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 707190d3ada0..aa75f59ce3c8 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -788,6 +788,22 @@ static int kszphy_probe(struct phy_device *phydev)
return 0;
}
+static int ksz8081_resume(struct phy_device *phydev)
+{
+ int value;
+
+ mutex_lock(&phydev->lock);
+ value = phy_read(phydev, MII_BMCR);
+ phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
+
+ value = phy_scan_fixups(phydev);
+ if (value < 0)
+ return value;
+ mutex_unlock(&phydev->lock);
+
+ return 0;
+}
+
static struct phy_driver ksphy_driver[] = {
{
.phy_id = PHY_ID_KS8737,
@@ -933,7 +949,7 @@ static struct phy_driver ksphy_driver[] = {
.get_strings = kszphy_get_strings,
.get_stats = kszphy_get_stats,
.suspend = kszphy_suspend,
- .resume = kszphy_resume,
+ .resume = ksz8081_resume,
}, {
.phy_id = PHY_ID_KSZ8061,
.name = "Micrel KSZ8061",
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index b131e555d3c2..ec656d91f14b 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -89,13 +89,23 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
if (!drv || !phydrv->suspend)
return false;
- /* PHY not attached? May suspend if the PHY has not already been
- * suspended as part of a prior call to phy_disconnect() ->
- * phy_detach() -> phy_suspend() because the parent netdev might be the
- * MDIO bus driver and clock gated at this point.
+ /*
+ * netdev is NULL has three cases:
+ * - phy is not found
+ * - phy is found, match to general phy driver
+ * - phy is found, match to specifical phy driver
+ *
+ * Case 1: phy is not found, cannot communicate by MDIO bus.
+ * Case 2: phy is found:
+ * if phy dev driver probe/bind err, netdev is not __open__ status,
+ * mdio bus is unregistered.
+ * if phy is detached, phy had entered suspended status.
+ * Case 3: phy is found, phy is detached, phy had entered suspended status.
+ *
+ * So, in here, it shouldn't set phy to suspend by calling mdio bus.
*/
if (!netdev)
- return !phydev->suspended;
+ return false;
/* Don't suspend PHY if the attached netdev parent may wakeup.
* The parent may point to a PCI device, as in tg3 driver.
@@ -252,7 +262,7 @@ static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup)
}
/* Runs any matching fixups for this phydev */
-static int phy_scan_fixups(struct phy_device *phydev)
+int phy_scan_fixups(struct phy_device *phydev)
{
struct phy_fixup *fixup;
@@ -272,6 +282,7 @@ static int phy_scan_fixups(struct phy_device *phydev)
return 0;
}
+EXPORT_SYMBOL(phy_scan_fixups);
static int phy_bus_match(struct device *dev, struct device_driver *drv)
{
@@ -1230,15 +1241,7 @@ int genphy_restart_aneg(struct phy_device *phydev)
}
EXPORT_SYMBOL(genphy_restart_aneg);
-/**
- * genphy_config_aneg - restart auto-negotiation or write BMCR
- * @phydev: target phy_device struct
- *
- * Description: If auto-negotiation is enabled, we configure the
- * advertising, and then restart auto-negotiation. If it is not
- * enabled, then we write the BMCR.
- */
-int genphy_config_aneg(struct phy_device *phydev)
+int genphy_config_aneg_check(struct phy_device *phydev)
{
int err, changed;
@@ -1266,11 +1269,28 @@ int genphy_config_aneg(struct phy_device *phydev)
changed = 1; /* do restart aneg */
}
+ return changed;
+}
+EXPORT_SYMBOL(genphy_config_aneg_check);
+
+/**
+ * genphy_config_aneg - restart auto-negotiation or write BMCR
+ * @phydev: target phy_device struct
+ *
+ * Description: If auto-negotiation is enabled, we configure the
+ * advertising, and then restart auto-negotiation. If it is not
+ * enabled, then we write the BMCR.
+ */
+int genphy_config_aneg(struct phy_device *phydev)
+{
+ int result;
+
/* Only restart aneg if we are advertising something different
* than we were before.
*/
- if (changed > 0)
- return genphy_restart_aneg(phydev);
+ result = genphy_config_aneg_check(phydev);
+ if (result > 0)
+ result = genphy_restart_aneg(phydev);
return 0;
}
diff --git a/drivers/net/phy/tja110x.c b/drivers/net/phy/tja110x.c
new file mode 100644
index 000000000000..bf680ecf3d7b
--- /dev/null
+++ b/drivers/net/phy/tja110x.c
@@ -0,0 +1,2547 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/of_mdio.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/delay.h>
+
+#include "tja110x.h"
+
+/* load driver for TJA1102p1. It needs to be ensured,
+ * that no other mdio device with phy id 0 is present
+ */
+#define CONFIG_TJA1102_FIX
+
+/* listen for NETDEV_GOING_DOWN and NETDEV_UP of the ethernet interface,
+ * that controls the mdio bus to which the nxp phy(s) is/are connected to.
+ * Polling is stopped/started accordingly, to prevent mdio read timeouts
+ * This fix requires MDIO_INTERFACE_NAME and MII_BUS_NAME to be set
+ */
+#define NETDEV_NOTIFICATION_FIX
+
+/* Name of the eth interface, that controlls the mdio bus,
+ * to which the phy(s) is/are connected to
+ */
+#ifndef MDIO_INTERFACE_NAME
+#define MDIO_INTERFACE_NAME "eth0"
+#endif
+
+/* Name of the mdio bus,
+ * to which the phy(s) is/are connected to
+ */
+#ifndef MII_BUS_NAME
+#define MII_BUS_NAME "fec_enet_mii_bus"
+#endif
+
+#define TJA110X_REFCLK_IN (1 << 0)
+
+/* Variable can be modified via parameter passed at load time
+ * A nonzero value indicates that we should operate in managed mode
+ */
+static int managed_mode;
+/* Permission: do not show up in sysfs */
+module_param(managed_mode, int, 0000);
+MODULE_PARM_DESC(managed_mode, "Use PHY in managed or autonomous mode");
+
+/* A nonzero value indicates that we should not poll the interrupt register */
+static int no_poll;
+/* Permission: do not show up in sysfs */
+module_param(no_poll, int, 0000);
+MODULE_PARM_DESC(no_poll, "Do not poll the interrupt register");
+
+/* Detemines the level of verbosity for debug messages */
+static int verbosity;
+/* Permission: do not show up in sysfs */
+module_param(verbosity, int, 0000);
+MODULE_PARM_DESC(verbosity, "Set verbosity level");
+
+/* Called to initialize the PHY,
+ * including after a reset
+ */
+static int nxp_config_init(struct phy_device *phydev)
+{
+ struct nxp_specific_data *nxp_specific = phydev->priv;
+ int reg_val;
+ int reg_name, reg_value = -1, reg_mask;
+ int err;
+
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev, "initializing phy %x\n", phydev->mdio.addr);
+
+ /* set features of the PHY */
+ reg_val = phy_read(phydev, MII_BMSR);
+ if (reg_val < 0)
+ goto phy_read_error;
+ if (reg_val & BMSR_ESTATEN) {
+ reg_val = phy_read(phydev, MII_ESTATUS);
+
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ if (reg_val & ESTATUS_100T1_FULL) {
+ /* update phydev to include the supported features */
+ phydev->supported |= SUPPORTED_100BASET1_FULL;
+ phydev->advertising |= ADVERTISED_100BASET1_FULL;
+ }
+ }
+
+ /* enable configuration register access once during initialization */
+ err = phy_configure_bit(phydev, MII_ECTRL, ECTRL_CONFIG_EN, 1);
+ if (err < 0)
+ goto phy_configure_error;
+
+ /* -enter managed or autonomous mode,
+ * depending on the value of managed_mode.
+ * The register layout changed between TJA1100 and TJA1102
+ * -configure LED mode (only tja1100 has LEDs)
+ */
+ switch (phydev->phy_id & NXP_PHY_ID_MASK) {
+ case NXP_PHY_ID_TJA1100:
+ reg_name = MII_CFG1;
+ reg_value = TJA1100_CFG1_LED_EN | CFG1_LED_LINKUP;
+ if (!managed_mode)
+ reg_value |= TJA1100_CFG1_AUTO_OP;
+ reg_mask = TJA1100_CFG1_AUTO_OP |
+ TJA1100_CFG1_LED_EN | TJA1100_CFG1_LED_MODE;
+
+ if (nxp_specific->quirks & TJA110X_REFCLK_IN) {
+ reg_value |= TJA1100_CFG1_MII_MODE_REFCLK_IN;
+ reg_mask |= CFG1_MII_MODE;
+ }
+ break;
+ case NXP_PHY_ID_TJA1101:
+ /* fall through */
+ case NXP_PHY_ID_TJA1102P0:
+ reg_name = MII_COMMCFG;
+ reg_value = 0;
+ if (!managed_mode)
+ reg_value |= COMMCFG_AUTO_OP;
+ reg_mask = COMMCFG_AUTO_OP;
+ break;
+
+ case NXP_PHY_ID_TJA1102P1:
+ /* does not have an auto_op bit */
+ break;
+
+ default:
+ goto unsupported_phy_error;
+ }
+
+ /* only configure the phys that have an auto_op bit or leds */
+ if (reg_value != -1) {
+ err = phy_configure_bits(phydev, reg_name, reg_mask, reg_value);
+ if (err < 0)
+ goto phy_configure_error;
+ }
+
+ /* enable sleep confirm */
+ err = phy_configure_bit(phydev, MII_CFG1, CFG1_SLEEP_CONFIRM, 1);
+ if (err < 0)
+ goto phy_configure_error;
+
+ /* set sleep request timeout to 16ms */
+ err = phy_configure_bits(phydev, MII_CFG2, CFG2_SLEEP_REQUEST_TO,
+ SLEEP_REQUEST_TO_16MS);
+ if (err < 0)
+ goto phy_configure_error;
+
+ /* if in managed mode:
+ * -go to normal mode, if currently in standby
+ * (PHY might be pinstrapped to managed mode,
+ * and therefore not in normal mode yet)
+ * -enable link control
+ */
+ if (managed_mode) {
+ reg_val = phy_read(phydev, MII_ECTRL);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ /* mask power mode bits */
+ reg_val &= ECTRL_POWER_MODE;
+
+ if (reg_val == POWER_MODE_STANDBY) {
+ err = phydev->drv->resume(phydev);
+ if (err < 0)
+ goto phy_pmode_transit_error;
+ }
+
+ set_link_control(phydev, 1);
+ }
+
+ /* clear any pending interrupts */
+ phydev->drv->ack_interrupt(phydev);
+
+ phydev->irq = PHY_POLL;
+
+ /* enable all interrupts */
+ phydev->interrupts = PHY_INTERRUPT_ENABLED;
+ phydev->drv->config_intr(phydev);
+
+ /* Setup and queue a polling function */
+ if (!no_poll) {
+ setup_polling(phydev);
+ start_polling(phydev);
+ }
+
+ return 0;
+
+/* error handling */
+phy_read_error:
+ dev_err(&phydev->mdio.dev, "read error: config_init failed\n");
+ return reg_val;
+
+phy_pmode_transit_error:
+ dev_err(&phydev->mdio.dev, "pmode error: config_init failed\n");
+ return err;
+
+phy_configure_error:
+ dev_err(&phydev->mdio.dev, "read/write error: config_init failed\n");
+ return err;
+
+unsupported_phy_error:
+ dev_err(&phydev->mdio.dev, "unsupported phy, config_init failed\n");
+ return -1;
+}
+
+/* Called during discovery.
+ * Used to set up device-specific structures
+ */
+static int nxp_probe(struct phy_device *phydev)
+{
+ int err;
+ struct device *dev = &phydev->mdio.dev;
+ struct nxp_specific_data *nxp_specific;
+
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev, "probing PHY %x\n", phydev->mdio.addr);
+
+ nxp_specific = kzalloc(sizeof(*nxp_specific), GFP_KERNEL);
+ if (!nxp_specific)
+ goto phy_allocation_error;
+
+ if (of_property_read_bool(dev->of_node, "tja110x,refclk_in"))
+ nxp_specific->quirks |= TJA110X_REFCLK_IN;
+
+ nxp_specific->is_master = get_master_cfg(phydev);
+ nxp_specific->is_polling = 0;
+ nxp_specific->is_poll_setup = 0;
+
+ phydev->priv = nxp_specific;
+
+ /* register sysfs files */
+ err = sysfs_create_group(&phydev->mdio.dev.kobj, &nxp_attribute_group);
+ if (err)
+ goto register_sysfs_error;
+
+ return 0;
+
+/* error handling */
+register_sysfs_error:
+ dev_err(&phydev->mdio.dev, "sysfs file creation failed\n");
+ return -ENOMEM;
+
+phy_allocation_error:
+ dev_err(&phydev->mdio.dev, "memory allocation for priv data failed\n");
+ return -ENOMEM;
+}
+
+/* Clears up any memory, removes sysfs nodes and cancels polling */
+static void nxp_remove(struct phy_device *phydev)
+{
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev, "removing PHY %x\n", phydev->mdio.addr);
+
+ /* unregister sysfs files */
+ sysfs_remove_group(&phydev->mdio.dev.kobj, &nxp_attribute_group);
+
+ if (!no_poll)
+ stop_polling(phydev);
+
+ /* free custom data struct */
+ if (phydev->priv) {
+ kzfree(phydev->priv);
+ phydev->priv = NULL;
+ }
+}
+
+/* Clears any pending interrupts */
+static int nxp_ack_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ if (verbosity > 3)
+ dev_alert(&phydev->mdio.dev, "acknowledging interrupt of PHY %x\n",
+ phydev->mdio.addr);
+
+ /* interrupts are acknowledged by reading, ie. clearing MII_INTSRC */
+ err = phy_read(phydev, MII_INTSRC);
+ if (err < 0)
+ goto phy_read_error;
+ return 0;
+
+/* error handling */
+phy_read_error:
+ dev_err(&phydev->mdio.dev, "read error: ack_interrupt failed\n");
+ return err;
+}
+
+/* Checks if the PHY generated an interrupt */
+static int nxp_did_interrupt(struct phy_device *phydev)
+{
+ int reg_val;
+
+ reg_val = phy_read(phydev, MII_INTSRC);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ /* return bitmask of possible interrupts bits that are set */
+ return (reg_val & INTERRUPT_ALL);
+
+/* error handling */
+phy_read_error:
+ dev_err(&phydev->mdio.dev, "read error: did_interrupt failed\n");
+ return 0;
+}
+
+/* Enables or disables interrupts */
+static int nxp_config_intr(struct phy_device *phydev)
+{
+ int err;
+ int interrupts;
+
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev,
+ "configuring interrupts of phy %x to [%x]\n",
+ phydev->mdio.addr, phydev->interrupts);
+
+ interrupts = phydev->interrupts;
+
+ if (interrupts == PHY_INTERRUPT_ENABLED) {
+ /* enable all interrupts
+ * PHY_INTERRUPT_ENABLED macro does not interfere with any
+ * of the possible interrupt source macros
+ */
+ err = phy_write(phydev, MII_INTMASK, INTERRUPT_ALL);
+ } else if (interrupts == PHY_INTERRUPT_DISABLED) {
+ /* disable all interrupts */
+ err = phy_write(phydev, MII_INTMASK, INTERRUPT_NONE);
+ } else {
+ /* interpret value of interrupts as interrupt mask */
+ err = phy_write(phydev, MII_INTMASK, interrupts);
+ }
+
+ if (err < 0)
+ goto phy_write_error;
+ return 0;
+
+phy_write_error:
+ dev_err(&phydev->mdio.dev, "write error: config_intr failed\n");
+ return err;
+}
+
+/* interrupt handler for pwon interrupts */
+static inline void handle_pwon_interrupt(struct phy_device *phydev)
+{
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev,
+ "reinitializing phy [%08x] @ [%04x] after powerdown\n",
+ phydev->phy_id, phydev->mdio.addr);
+ /* after a power down reinitialize the phy */
+ phydev->drv->config_init(phydev);
+
+ /* update master/slave setting */
+ ((struct nxp_specific_data *)phydev->priv)->is_master =
+ get_master_cfg(phydev);
+
+ /* For TJA1102, pwon interrupts only exist on TJA1102p0
+ * Find TJA1102p1 to reinitialize it too
+ */
+ if ((phydev->phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1102P0) {
+ int p1_addr = phydev->mdio.addr + 1;
+ struct phy_device *phydevp1;
+
+ if (p1_addr >= PHY_MAX_ADDR)
+ return;
+
+ phydevp1 = mdiobus_get_phy(phydev->mdio.bus, p1_addr);
+ if (!phydevp1)
+ return;
+
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev,
+ "reinit phy [%08x] @ [%04x] after pDown\n",
+ phydevp1->phy_id, phydevp1->mdio.addr);
+ phydevp1->drv->config_init(phydevp1);
+ ((struct nxp_specific_data *)phydevp1->priv)->is_master =
+ get_master_cfg(phydevp1);
+ }
+}
+
+/* interrupt handler for undervoltage recovery interrupts */
+static inline void handle_uvr_interrupt(struct phy_device *phydev)
+{
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev,
+ "resuming phy [%08x] @ [%04x] after uvr\n",
+ phydev->phy_id, phydev->mdio.addr);
+ phydev->drv->resume(phydev);
+
+ /* For TJA1102, UVR interrupts only exist on TJA1102p0
+ * Find TJA1102p1 to resume it too
+ */
+ if ((phydev->phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1102P0) {
+ int p1_addr = phydev->mdio.addr + 1;
+ struct phy_device *phydevp1;
+
+ if (p1_addr >= PHY_MAX_ADDR)
+ return;
+
+ phydevp1 = mdiobus_get_phy(phydev->mdio.bus, p1_addr);
+ if (!phydevp1)
+ return;
+
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev,
+ "resuming phy [%08x] @ [%04x] after uvr\n",
+ phydevp1->phy_id, phydevp1->mdio.addr);
+ phydevp1->drv->resume(phydevp1);
+ }
+}
+
+/* polling function, that is executed regularly to handle phy interrupts */
+static void poll(struct work_struct *work)
+{
+ int interrupts, interrupt_mask;
+ struct phy_device *phydev =
+ container_of(work, struct phy_device, phy_queue);
+
+ /* query phy for interrupts */
+ interrupts = nxp_did_interrupt(phydev);
+
+ /* mask out all disabled interrupts */
+ interrupt_mask = phy_read(phydev, MII_INTMASK);
+ if (verbosity > 4)
+ dev_alert(&phydev->mdio.dev,
+ "interrupt on phy [%08x]@[%04x], mask [%08x], ISR [%08x]\n",
+ phydev->phy_id, phydev->mdio.addr, interrupt_mask, interrupts);
+
+ interrupts &= interrupt_mask;
+
+ /* handle interrupts
+ * - reinitialize after power down
+ * - resume PHY after an external WAKEUP was received
+ * - resume PHY after an undervoltage recovery
+ * - adjust state on link changes
+ * - check for some PHY errors
+ */
+
+ /* SMI not disabled and read was successful */
+ if ((interrupts != 0xffff) && (interrupt_mask >= 0)) {
+ if (interrupts & INTERRUPT_PWON)
+ handle_pwon_interrupt(phydev);
+ else if (interrupts & INTERRUPT_UV_RECOVERY)
+ handle_uvr_interrupt(phydev);
+ else if (interrupts & INTERRUPT_WAKEUP)
+ phydev->drv->resume(phydev);
+
+ /* warnings */
+ if (interrupts & INTERRUPT_PHY_INIT_FAIL)
+ dev_err(&phydev->mdio.dev, "PHY initialization failed\n");
+ if (interrupts & INTERRUPT_LINK_STATUS_FAIL)
+ dev_err(&phydev->mdio.dev, "PHY link status failed\n");
+ if (interrupts & INTERRUPT_SYM_ERR)
+ dev_err(&phydev->mdio.dev, "PHY symbol error detected\n");
+ if (interrupts & INTERRUPT_SNR_WARNING)
+ dev_err(&phydev->mdio.dev, "PHY SNR warning\n");
+ if (interrupts & INTERRUPT_CONTROL_ERROR)
+ dev_err(&phydev->mdio.dev, "PHY control error\n");
+ if (interrupts & INTERRUPT_UV_ERR)
+ dev_err(&phydev->mdio.dev, "PHY undervoltage error\n");
+ if (interrupts & INTERRUPT_TEMP_ERROR)
+ dev_err(&phydev->mdio.dev, "PHY temperature error\n");
+
+ /* Notify state machine about any link changes */
+ if (interrupts & INTERRUPT_LINK_STATUS_UP ||
+ interrupts & INTERRUPT_LINK_STATUS_FAIL) {
+ mutex_lock(&phydev->lock);
+
+ /* only indicate a link change to state machine
+ * if phydev is attached to a netdevice
+ */
+ if (phydev->attached_dev)
+ phydev->state = PHY_CHANGELINK;
+
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev,
+ "state was %d, now going %s\n", phydev->state,
+ (interrupts & INTERRUPT_LINK_STATUS_UP) ?
+ "UP":"DOWN");
+ phydev->link =
+ (interrupts & INTERRUPT_LINK_STATUS_UP) ? 1 : 0;
+ mutex_unlock(&phydev->lock);
+ }
+ }
+
+ /* requeue poll function */
+ msleep(POLL_PAUSE); /* msleep is non-blocking */
+ queue_work(system_power_efficient_wq, &phydev->phy_queue);
+}
+
+static void setup_polling(struct phy_device *phydev)
+{
+ /*
+ * The phy_queue is normally used to schedule the interrupt handler
+ * from interrupt context after an irq has been received.
+ * Here it is repurposed as scheduling mechanism for the poll function
+ */
+ struct nxp_specific_data *priv = phydev->priv;
+
+ if (!priv->is_poll_setup) {
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev,
+ "initialize polling for PHY %x\n", phydev->mdio.addr);
+ cancel_work_sync(&phydev->phy_queue);
+ INIT_WORK(&phydev->phy_queue, poll);
+ priv->is_poll_setup = 1;
+ }
+}
+
+static void start_polling(struct phy_device *phydev)
+{
+ struct nxp_specific_data *priv = phydev->priv;
+
+ if (priv->is_poll_setup && !priv->is_polling) {
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev, "start polling PHY %x\n",
+ phydev->mdio.addr);
+ /* schedule execution of polling function */
+ queue_work(system_power_efficient_wq, &phydev->phy_queue);
+ priv->is_polling = 1;
+ }
+}
+
+static void stop_polling(struct phy_device *phydev)
+{
+ struct nxp_specific_data *priv = phydev->priv;
+
+ if (priv->is_poll_setup && priv->is_polling) {
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev, "stop polling PHY %x\n",
+ phydev->mdio.addr);
+ /* cancel scheduled work */
+ cancel_work_sync(&phydev->phy_queue);
+ priv->is_polling = 0;
+ }
+}
+
+/* helper function, waits until a given condition is met
+ *
+ * The function delays until the part of the register at reg_addr,
+ * defined by reg_mask equals cond, or a timeout (timeout*DELAY_LENGTH) occurs.
+ * @return 0 if condition is met, <0 if timeout or read error occurred
+ */
+static int wait_on_condition(struct phy_device *phydev, int reg_addr,
+ int reg_mask, int cond, int timeout)
+{
+ int reg_val;
+
+ if (verbosity > 3)
+ dev_alert(&phydev->mdio.dev, "waiting on condidition\n");
+
+ do {
+ udelay(DELAY_LENGTH);
+ reg_val = phy_read(phydev, reg_addr);
+ if (reg_val < 0)
+ return reg_val;
+ } while ((reg_val & reg_mask) != cond && --timeout);
+
+ if (verbosity > 3)
+ dev_alert(&phydev->mdio.dev, "%s",
+ (timeout?"condidition met\n" : "timeout occured\n"));
+
+ if (timeout)
+ return 0;
+ return -1;
+}
+
+/* helper function, enables or disables link control */
+static void set_link_control(struct phy_device *phydev, int enable_link_control)
+{
+ int err;
+
+ err = phy_configure_bit(phydev, MII_ECTRL, ECTRL_LINK_CONTROL,
+ enable_link_control);
+ if (err < 0)
+ goto phy_configure_error;
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev,
+ "set link ctrl to [%d] for phy %x completed\n",
+ enable_link_control, phydev->mdio.addr);
+
+ return;
+
+phy_configure_error:
+ dev_err(&phydev->mdio.dev, "phy r/w error: setting link control failed\n");
+ return;
+}
+
+/* Helper function, configures phy as master or slave
+ * @param phydev the phy to be configured
+ * @param setMaster ==0: set to slave
+ * !=0: set to master
+ * @return 0 on success, error code on failure
+ */
+static int set_master_cfg(struct phy_device *phydev, int setMaster)
+{
+ int err;
+
+ /* disable link control prior to master/slave cfg */
+ set_link_control(phydev, 0);
+
+ /* write configuration to the phy */
+ err = phy_configure_bit(phydev, MII_CFG1, CFG1_MASTER_SLAVE, setMaster);
+ if (err < 0)
+ goto phy_configure_error;
+
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev, "set master cfg completed\n");
+
+ /* enable link control after master/slave cfg was set */
+ set_link_control(phydev, 1);
+
+ return 0;
+
+/* error handling */
+phy_configure_error:
+ dev_err(&phydev->mdio.dev, "phy r/w error: set_master_cfg failed\n");
+ return err;
+}
+
+/* Helper function, reads master/slave configuration of phy
+ * @param phydev the phy to be read
+ *
+ * @return ==0: is slave
+ * !=0: is master
+ */
+static int get_master_cfg(struct phy_device *phydev)
+{
+ int reg_val;
+
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev, "getting master cfg PHY %x\n",
+ phydev->mdio.addr);
+
+ /* read the current configuration */
+ reg_val = phy_read(phydev, MII_CFG1);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ return reg_val & CFG1_MASTER_SLAVE;
+
+/* error handling */
+phy_read_error:
+ dev_err(&phydev->mdio.dev, "read error: get_master_cfg failed\n");
+ return reg_val;
+}
+
+/* retrieves the link status from COMMSTAT register */
+static int get_link_status(struct phy_device *phydev)
+{
+ int reg_val;
+
+ reg_val = phy_read(phydev, MII_COMMSTAT);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ if (verbosity > 0) {
+ if (reg_val & COMMSTAT_LOC_RCVR_STATUS)
+ dev_alert(&phydev->mdio.dev, "local receiver OK\n");
+ else
+ dev_alert(&phydev->mdio.dev, "local receiver NOT OK\n");
+ }
+
+ return reg_val & COMMSTAT_LINK_UP;
+
+/* error handling */
+phy_read_error:
+ dev_err(&phydev->mdio.dev, "read error: get_link_status failed\n");
+ return reg_val;
+}
+
+/* issues a sleep request, if in managed mode */
+static int nxp_sleep(struct phy_device *phydev)
+{
+ int err;
+
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev, "PHY %x going to sleep\n",
+ phydev->mdio.addr);
+
+ if (!managed_mode)
+ goto phy_auto_op_error;
+
+ /* clear power mode bits and set them to sleep request */
+ err = phy_configure_bits(phydev, MII_ECTRL, ECTRL_POWER_MODE,
+ POWER_MODE_SLEEPREQUEST);
+ if (err < 0)
+ goto phy_configure_error;
+
+ if ((phydev->phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1102P0 ||
+ (phydev->phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1102P1 ||
+ (phydev->phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1101) {
+ /* tja1102 and tja1102 have an extra sleep state indicator
+ * in ECTRL.
+ * If transition is successful this can be detected immediately,
+ * without waiting for SLEEP_REQUEST_TO to pass
+ */
+ err = wait_on_condition(phydev, MII_ECTRL, ECTRL_POWER_MODE,
+ POWER_MODE_SLEEP, SLEEP_REQUEST_TO);
+ if (err < 0)
+ goto phy_transition_error;
+ } else if ((phydev->phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1100) {
+ /* TJA1100 disables SMI when entering SLEEP
+ * The SMI bus is pulled up, that means every
+ * SMI read will return 0xffff.
+ * We can use this to check if PHY entered SLEEP.
+ */
+ err = wait_on_condition(phydev, MII_ECTRL,
+ 0xffff, 0xffff, SLEEP_REQUEST_TO);
+ if (err < 0)
+ goto phy_transition_error;
+ }
+
+ return 0;
+
+/* error handling */
+phy_auto_op_error:
+ dev_info(&phydev->mdio.dev, "phy is in auto mode: sleep not possible\n");
+ return 0;
+
+phy_configure_error:
+ dev_err(&phydev->mdio.dev, "phy r/w error: entering sleep failed\n");
+ return err;
+
+phy_transition_error:
+ dev_err(&phydev->mdio.dev, "sleep request timed out\n");
+ return err;
+}
+
+/* wakes up the phy from sleep mode */
+static int wakeup_from_sleep(struct phy_device *phydev)
+{
+ int err;
+ unsigned long wakeup_delay;
+ struct nxp_specific_data *nxp_specific = phydev->priv;
+
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev, "PHY %x waking up from sleep\n",
+ phydev->mdio.addr);
+
+ if (!managed_mode)
+ goto phy_auto_op_error;
+
+ /* set power mode bits to standby mode */
+ err = phy_configure_bits(phydev, MII_ECTRL, ECTRL_POWER_MODE,
+ POWER_MODE_STANDBY);
+ if (err < 0)
+ goto phy_configure_error;
+
+ /* wait until power mode transition is completed */
+ err = wait_on_condition(phydev, MII_ECTRL, ECTRL_POWER_MODE,
+ POWER_MODE_STANDBY, POWER_MODE_TIMEOUT);
+ if (err < 0)
+ goto phy_transition_error;
+
+ /* set power mode bits to normal mode */
+ err = phy_configure_bits(phydev, MII_ECTRL, ECTRL_POWER_MODE,
+ POWER_MODE_NORMAL);
+ if (err < 0)
+ goto phy_configure_error;
+
+ if (!(nxp_specific->quirks & TJA110X_REFCLK_IN)) {
+ /* wait until the PLL is locked, indicating a completed transition */
+ err = wait_on_condition(phydev, MII_GENSTAT, GENSTAT_PLL_LOCKED,
+ GENSTAT_PLL_LOCKED, POWER_MODE_TIMEOUT);
+ if (err < 0)
+ goto phy_transition_error;
+ }
+
+ /* if phy is configured as slave, also send a wakeup request
+ * to master
+ */
+ if (!((struct nxp_specific_data *)phydev->priv)->is_master) {
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev,
+ "Phy is slave, send wakeup request master\n");
+ /* link control must be reset for wake request */
+ set_link_control(phydev, 0);
+
+ /* start sending bus wakeup signal */
+ err = phy_configure_bit(phydev, MII_ECTRL,
+ ECTRL_WAKE_REQUEST, 1);
+ if (err < 0)
+ goto phy_configure_error;
+
+ switch (phydev->phy_id & NXP_PHY_ID_MASK) {
+ case NXP_PHY_ID_TJA1100:
+ wakeup_delay = TJA100_WAKE_REQUEST_TIMEOUT_US;
+ break;
+ case NXP_PHY_ID_TJA1102P0:
+ /* fall through */
+ case NXP_PHY_ID_TJA1101:
+ /* fall through */
+ case NXP_PHY_ID_TJA1102P1:
+ wakeup_delay = TJA102_WAKE_REQUEST_TIMEOUT_US;
+ break;
+ default:
+ goto unsupported_phy_error;
+ }
+
+ /* wait until link partner is guranteed to be awake */
+ usleep_range(wakeup_delay, wakeup_delay + 1U);
+
+ /* stop sending bus wakeup signal */
+ err = phy_configure_bit(phydev, MII_ECTRL,
+ ECTRL_WAKE_REQUEST, 0);
+ if (err < 0)
+ goto phy_configure_error;
+ }
+
+ /* reenable link control */
+ set_link_control(phydev, 1);
+
+ return 0;
+
+/* error handling */
+phy_auto_op_error:
+ dev_dbg(&phydev->mdio.dev, "phy is in auto mode: wakeup not possible\n");
+ return 0;
+
+phy_configure_error:
+ dev_err(&phydev->mdio.dev, "phy r/w error: wakeup failed\n");
+ return err;
+
+phy_transition_error:
+ dev_err(&phydev->mdio.dev, "power mode transition failed\n");
+ return err;
+
+unsupported_phy_error:
+ dev_err(&phydev->mdio.dev, "unsupported phy, wakeup failed\n");
+ return -1;
+}
+
+/* send a wakeup request to the link partner */
+static int wakeup_from_normal(struct phy_device *phydev)
+{
+ int err;
+
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev,
+ "PHY %x waking up from normal (send wur)\n", phydev->mdio.addr);
+
+ /* start sending bus wakeup signal */
+ err = phy_configure_bit(phydev, MII_ECTRL, ECTRL_WAKE_REQUEST, 1);
+ if (err < 0)
+ goto phy_configure_error;
+
+ /* stop sending bus wakeup signal */
+ err = phy_configure_bit(phydev, MII_ECTRL, ECTRL_WAKE_REQUEST, 0);
+ if (err < 0)
+ goto phy_configure_error;
+
+ return 0;
+
+/* error handling */
+phy_configure_error:
+ dev_err(&phydev->mdio.dev, "phy r/w error: wakeup_from_normal failed\n");
+ return err;
+}
+
+/* wake up phy if is in sleep mode, send wakeup request if in normal mode */
+static int nxp_wakeup(struct phy_device *phydev)
+{
+ int reg_val;
+ int err = 0;
+
+ reg_val = phy_read(phydev, MII_ECTRL);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ reg_val &= ECTRL_POWER_MODE;
+ switch (reg_val) {
+ case POWER_MODE_NORMAL:
+ err = wakeup_from_normal(phydev);
+ break;
+ case POWER_MODE_SLEEP:
+ err = wakeup_from_sleep(phydev);
+ break;
+ case 0xffff & ECTRL_POWER_MODE:
+ /* TJA1100 disables SMI during sleep */
+ goto phy_SMI_disabled;
+ default:
+ break;
+ }
+ if (err < 0)
+ goto phy_configure_error;
+
+ return 0;
+
+/* error handling */
+phy_read_error:
+ dev_err(&phydev->mdio.dev, "read error: nxp_wakeup failed\n");
+ return reg_val;
+
+phy_SMI_disabled:
+ dev_err(&phydev->mdio.dev, "SMI interface disabled, cannot be woken up\n");
+ return 0;
+
+phy_configure_error:
+ dev_err(&phydev->mdio.dev, "phy r/w error: wakeup_from_normal failed\n");
+ return err;
+}
+
+/* power mode transition to standby */
+static int nxp_suspend(struct phy_device *phydev)
+{
+ int err = 0;
+
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev, "suspending PHY %x\n", phydev->mdio.addr);
+
+ if (!managed_mode)
+ goto phy_auto_op_error;
+
+ mutex_lock(&phydev->lock);
+ /* set BMCR_PDOWN bit in MII_BMCR register */
+ err = phy_configure_bit(phydev, MII_BMCR, BMCR_PDOWN, 1);
+ if (err < 0)
+ dev_err(&phydev->mdio.dev, "phy r/w error: resume failed\n");
+ mutex_unlock(&phydev->lock);
+
+ return err;
+
+phy_auto_op_error:
+ dev_dbg(&phydev->mdio.dev, "phy is in auto mode: suspend not possible\n");
+ return 0;
+}
+
+/* power mode transition from standby to normal */
+static int nxp_resume(struct phy_device *phydev)
+{
+ int err;
+ struct nxp_specific_data *nxp_specific = phydev->priv;
+
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev, "resuming PHY %x\n", phydev->mdio.addr);
+
+ mutex_lock(&phydev->lock);
+ /* clear BMCR_PDOWN bit in MII_BMCR register */
+ err = phy_configure_bit(phydev, MII_BMCR, BMCR_PDOWN, 0);
+ if (err < 0)
+ goto phy_configure_error;
+
+ /* transit to normal mode */
+ err = phy_configure_bits(phydev, MII_ECTRL, ECTRL_POWER_MODE,
+ POWER_MODE_NORMAL);
+ if (err < 0)
+ goto phy_configure_error;
+
+ /* wait until power mode transition is completed */
+ err = wait_on_condition(phydev, MII_ECTRL, ECTRL_POWER_MODE,
+ POWER_MODE_NORMAL, POWER_MODE_TIMEOUT);
+ if (err < 0)
+ goto phy_transition_error;
+
+ if (!(nxp_specific->quirks & TJA110X_REFCLK_IN)) {
+ /* wait until the PLL is locked, indicating a completed transition */
+ err = wait_on_condition(phydev, MII_GENSTAT, GENSTAT_PLL_LOCKED,
+ GENSTAT_PLL_LOCKED, POWER_MODE_TIMEOUT);
+ if (err < 0)
+ goto phy_pll_error;
+ }
+
+ /* reenable link control */
+ set_link_control(phydev, 1);
+ mutex_unlock(&phydev->lock);
+
+ return 0;
+
+/* error handling */
+phy_configure_error:
+ mutex_unlock(&phydev->lock);
+ dev_err(&phydev->mdio.dev, "phy r/w error: resume failed\n");
+ return err;
+
+phy_transition_error:
+ mutex_unlock(&phydev->lock);
+ dev_err(&phydev->mdio.dev, "power mode transition failed\n");
+ return err;
+
+phy_pll_error:
+ mutex_unlock(&phydev->lock);
+ dev_err(&phydev->mdio.dev, "Error: PLL is unstable and not locked\n");
+ return err;
+}
+
+/* Configures the autonegotiation capabilities */
+static int nxp_config_aneg(struct phy_device *phydev)
+{
+ if (verbosity > 0)
+ dev_alert(&phydev->mdio.dev, "configuring autoneg\n");
+
+ /* disable autoneg and manually configure speed, duplex, pause frames */
+ phydev->autoneg = 0;
+
+ phydev->speed = SPEED_100;
+ phydev->duplex = DUPLEX_FULL;
+
+ phydev->pause = 0;
+ phydev->asym_pause = 0;
+
+ return 0;
+}
+
+/* helper function, enters the test mode specified by tmode
+ * @return 0 if test mode was entered, <0 on read or write error
+ */
+static int enter_test_mode(struct phy_device *phydev, enum test_mode tmode)
+{
+ int reg_val = -1;
+ int err;
+
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev, "phy %x entering test mode: %d\n",
+ phydev->mdio.addr, tmode);
+ switch (tmode) {
+ case NO_TMODE:
+ reg_val = ECTRL_NO_TMODE;
+ break;
+ case TMODE1:
+ reg_val = ECTRL_TMODE1;
+ break;
+ case TMODE2:
+ reg_val = ECTRL_TMODE2;
+ break;
+ case TMODE3:
+ reg_val = ECTRL_TMODE3;
+ break;
+ case TMODE4:
+ reg_val = ECTRL_TMODE4;
+ break;
+ case TMODE5:
+ reg_val = ECTRL_TMODE5;
+ break;
+ case TMODE6:
+ reg_val = ECTRL_TMODE6;
+ break;
+ default:
+ break;
+ }
+
+ if (reg_val >= 0) {
+ /* set test mode bits accordingly */
+ err = phy_configure_bits(phydev, MII_ECTRL, ECTRL_TEST_MODE,
+ reg_val);
+ if (err < 0)
+ goto phy_configure_error;
+ }
+
+ return 0;
+
+/* error handling */
+phy_configure_error:
+ dev_err(&phydev->mdio.dev, "phy r/w error: setting test mode failed\n");
+ return err;
+}
+
+/* helper function, enables or disables loopback mode
+ * @return 0 if loopback mode was configured, <0 on read or write error
+ */
+static int set_loopback(struct phy_device *phydev, int enable_loopback)
+{
+ int err;
+
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev, "phy %x setting loopback: %d\n",
+ phydev->mdio.addr, enable_loopback);
+ err = phy_configure_bit(phydev, MII_BMCR, BMCR_LOOPBACK,
+ enable_loopback);
+ if (err < 0)
+ goto phy_configure_error;
+
+ return 0;
+
+/* error handling */
+phy_configure_error:
+ dev_err(&phydev->mdio.dev, "phy r/w error: configuring loopback failed\n");
+ return err;
+}
+
+/* helper function, enters the loopback mode specified by lmode
+ * @return 0 if loopback mode was entered, <0 on read or write error
+ */
+static int enter_loopback_mode(struct phy_device *phydev,
+ enum loopback_mode lmode)
+{
+ int reg_val = -1;
+ int err;
+
+ /* disable link control prior to loopback cfg */
+ set_link_control(phydev, 0);
+
+ switch (lmode) {
+ case NO_LMODE:
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev,
+ "phy %x disabling loopback mode\n", phydev->mdio.addr);
+ /* disable loopback */
+ err = set_loopback(phydev, 0);
+ if (err < 0)
+ goto phy_set_loopback_error;
+ break;
+ case INTERNAL_LMODE:
+ reg_val = ECTRL_INTERNAL_LMODE;
+ break;
+ case EXTERNAL_LMODE:
+ reg_val = ECTRL_EXTERNAL_LMODE;
+ break;
+ case REMOTE_LMODE:
+ reg_val = ECTRL_REMOTE_LMODE;
+ break;
+ default:
+ break;
+ }
+
+ if (reg_val >= 0) {
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev, "setting loopback mode %d\n",
+ lmode);
+ err = phy_configure_bits(phydev, MII_ECTRL,
+ ECTRL_LOOPBACK_MODE, reg_val);
+ if (err < 0)
+ goto phy_configure_error;
+
+ /* enable loopback */
+ err = set_loopback(phydev, 1);
+ if (err < 0)
+ goto phy_set_loopback_error;
+ }
+
+ /* enable link control after loopback cfg was set */
+ set_link_control(phydev, 1);
+
+ return 0;
+
+/* error handling */
+phy_set_loopback_error:
+ dev_err(&phydev->mdio.dev, "error: enable/disable loopback failed\n");
+ return err;
+
+phy_configure_error:
+ dev_err(&phydev->mdio.dev, "phy r/w error: setting loopback mode failed\n");
+ return err;
+}
+
+/* helper function, enters the led mode specified by lmode
+ * @return 0 if led mode was entered, <0 on read or write error
+ */
+static int enter_led_mode(struct phy_device *phydev, enum led_mode lmode)
+{
+ int reg_val = -1;
+ int err;
+
+ switch (lmode) {
+ case NO_LED_MODE:
+ /* disable led */
+ err = phy_configure_bit(phydev, MII_CFG1,
+ TJA1100_CFG1_LED_EN, 0);
+ if (err < 0)
+ goto phy_configure_error;
+ break;
+ case LINKUP_LED_MODE:
+ reg_val = CFG1_LED_LINKUP;
+ break;
+ case FRAMEREC_LED_MODE:
+ reg_val = CFG1_LED_FRAMEREC;
+ break;
+ case SYMERR_LED_MODE:
+ reg_val = CFG1_LED_SYMERR;
+ break;
+ case CRSSIG_LED_MODE:
+ reg_val = CFG1_LED_CRSSIG;
+ break;
+ default:
+ break;
+ }
+
+ if (reg_val >= 0) {
+ err = phy_configure_bits(phydev, MII_CFG1,
+ TJA1100_CFG1_LED_MODE, reg_val);
+ if (err < 0)
+ goto phy_configure_error;
+
+ /* enable led */
+ err = phy_configure_bit(phydev, MII_CFG1,
+ TJA1100_CFG1_LED_EN, 1);
+ if (err < 0)
+ goto phy_configure_error;
+ }
+
+ return 0;
+
+/* error handling */
+phy_configure_error:
+ dev_err(&phydev->mdio.dev, "phy r/w error: setting led mode failed\n");
+ return err;
+}
+
+/* This function handles read accesses to the node 'master_cfg' in
+ * sysfs.
+ * Depending on current configuration of the phy, the node reads
+ * 'master' or 'slave'
+ */
+static ssize_t sysfs_get_master_cfg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int is_master;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ is_master = get_master_cfg(phydev);
+
+ /* write result into the buffer */
+ return scnprintf(buf, PAGE_SIZE, "%s\n",
+ is_master ? "master" : "slave");
+}
+
+/* This function handles write accesses to the node 'master_cfg' in sysfs.
+ * Depending on the value written to it, the phy is configured as
+ * master or slave
+ */
+static ssize_t sysfs_set_master_cfg(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err;
+ int setMaster;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev, "setting master cfg PHY %x\n",
+ phydev->mdio.addr);
+
+ /* parse the buffer */
+ err = kstrtoint(buf, 10, &setMaster);
+ if (err < 0)
+ goto phy_parse_error;
+
+ /* write configuration to the phy */
+ err = set_master_cfg(phydev, setMaster);
+ if (err < 0)
+ goto phy_cfg_error;
+
+ /* update phydev */
+ ((struct nxp_specific_data *)phydev->priv)->is_master = setMaster;
+
+ return count;
+
+/* error handling */
+phy_parse_error:
+ dev_err(&phydev->mdio.dev, "parse error: sysfs_set_master_cfg failed\n");
+ return err;
+
+phy_cfg_error:
+ dev_err(&phydev->mdio.dev, "phy cfg error: sysfs_set_master_cfg failed\n");
+ return err;
+}
+
+/* This function handles read accesses to the node 'power_cfg' in sysfs.
+ * Reading the node returns the current power state
+ */
+static ssize_t sysfs_get_power_cfg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int reg_val;
+ char *pmode;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev, "getting power cfg\n");
+
+ reg_val = phy_read(phydev, MII_ECTRL);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ /* mask power mode bits */
+ reg_val &= ECTRL_POWER_MODE;
+
+ switch (reg_val) {
+ case POWER_MODE_NORMAL:
+ pmode = "POWER_MODE_NORMAL\n";
+ break;
+ case POWER_MODE_SLEEPREQUEST:
+ pmode = "POWER_MODE_SLEEPREQUEST\n";
+ break;
+ case POWER_MODE_SLEEP:
+ pmode = "POWER_MODE_SLEEP\n";
+ break;
+ case POWER_MODE_SILENT:
+ pmode = "POWER_MODE_SILENT\n";
+ break;
+ case POWER_MODE_STANDBY:
+ pmode = "POWER_MODE_STANDBY\n";
+ break;
+ case POWER_MODE_NOCHANGE:
+ pmode = "POWER_MODE_NOCHANGE\n";
+ break;
+ default:
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev,
+ "unknown reg val is [%08x]\n", reg_val);
+ pmode = "unknown\n";
+ }
+
+ /* write result into the buffer */
+ return scnprintf(buf, PAGE_SIZE, pmode);
+
+/* error handling */
+phy_read_error:
+ dev_err(&phydev->mdio.dev, "read error: sysfs_get_power_cfg failed\n");
+ return reg_val;
+}
+
+/* This function handles write accesses to the node 'power_cfg' in
+ * sysfs.
+ * Depending on the value written to it, the phy enters a certain
+ * power state.
+ */
+static ssize_t sysfs_set_power_cfg(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err;
+ int pmode;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ /* parse the buffer */
+ err = kstrtoint(buf, 10, &pmode);
+ if (err < 0)
+ goto phy_parse_error;
+
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev, "set pmode to %d\n", pmode);
+
+ switch (pmode) {
+ case 0:
+ err = phydev->drv->suspend(phydev);
+ break;
+ case 1:
+ err = phydev->drv->resume(phydev);
+ break;
+ case 2:
+ err = nxp_sleep(phydev);
+ break;
+ case 3:
+ err = nxp_wakeup(phydev);
+ break;
+ default:
+ break;
+ }
+
+ if (err)
+ goto phy_pmode_transit_error;
+
+ return count;
+
+/* error handling */
+phy_parse_error:
+ dev_err(&phydev->mdio.dev, "parse error: sysfs_set_power_cfg failed\n");
+ return err;
+
+phy_pmode_transit_error:
+ dev_err(&phydev->mdio.dev, "pmode error: sysfs_set_power_cfg failed\n");
+ return err;
+}
+
+/* This function handles read accesses to the node 'loopback_cfg' in sysfs
+ * Reading the node returns the current loopback configuration
+ */
+static ssize_t sysfs_get_loopback_cfg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int reg_val;
+ char *lmode;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev, "getting loopback cfg\n");
+
+ reg_val = phy_read(phydev, MII_BMCR);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ if (reg_val & BMCR_LOOPBACK) {
+ /* loopback enabled */
+ reg_val = phy_read(phydev, MII_ECTRL);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ /* mask loopback mode bits */
+ reg_val &= ECTRL_LOOPBACK_MODE;
+
+ switch (reg_val) {
+ case ECTRL_INTERNAL_LMODE:
+ lmode = "INTERNAL_LOOPBACK\n";
+ break;
+ case ECTRL_EXTERNAL_LMODE:
+ lmode = "EXTERNAL_LOOPBACK\n";
+ break;
+ case ECTRL_REMOTE_LMODE:
+ lmode = "REMOTE_LOOPBACK\n";
+ break;
+ default:
+ lmode = "unknown\n";
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev,
+ "unknown reg val is [%08x]\n", reg_val);
+ }
+ } else {
+ /* loopback disabled */
+ lmode = "LOOPBACK_DISABLED\n";
+ }
+
+ /* write result into the buffer */
+ return scnprintf(buf, PAGE_SIZE, lmode);
+
+/* error handling */
+phy_read_error:
+ dev_err(&phydev->mdio.dev, "read error: sysfs_get_loopback_cfg failed\n");
+ return reg_val;
+}
+
+/* This function handles write accesses to the node 'loopback_cfg'
+ * in sysfs.
+ * Depending on the value written to it, the phy enters a certain
+ * loopback state.
+ */
+static ssize_t sysfs_set_loopback_cfg(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err;
+ int lmode;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ if (!managed_mode)
+ goto phy_auto_op_error;
+
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev, "setting loopback cfg PHY %x\n",
+ phydev->mdio.addr);
+
+ /* parse the buffer */
+ err = kstrtoint(buf, 10, &lmode);
+ if (err < 0)
+ goto phy_parse_error;
+
+ switch (lmode) {
+ case 0:
+ err = enter_loopback_mode(phydev, NO_LMODE);
+ if (!no_poll)
+ start_polling(phydev);
+ break;
+ case 1:
+ if (!no_poll)
+ stop_polling(phydev);
+ err = enter_loopback_mode(phydev, INTERNAL_LMODE);
+ break;
+ case 2:
+ if (!no_poll)
+ stop_polling(phydev);
+ err = enter_loopback_mode(phydev, EXTERNAL_LMODE);
+ break;
+ case 3:
+ if (!no_poll)
+ stop_polling(phydev);
+ err = enter_loopback_mode(phydev, REMOTE_LMODE);
+ break;
+ default:
+ break;
+ }
+
+ if (err)
+ goto phy_lmode_transit_error;
+
+ return count;
+
+/* error handling */
+phy_auto_op_error:
+ dev_info(&phydev->mdio.dev, "phy is in auto mode: loopback not available\n");
+ return count;
+
+phy_parse_error:
+ dev_err(&phydev->mdio.dev, "parse error: sysfs_set_loopback_cfg failed\n");
+ return err;
+
+phy_lmode_transit_error:
+ dev_err(&phydev->mdio.dev, "lmode error: sysfs_set_loopback_cfg failed\n");
+ return err;
+}
+
+/* This function handles read accesses to the node 'cable_test' in sysfs
+ * Reading the node executes a cable test and returns the result
+ */
+static ssize_t sysfs_get_cable_test(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int reg_val;
+ int err;
+ char *c_test_result;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ if (!managed_mode)
+ goto phy_auto_op_error;
+
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev, "phy %x executing cable test\n",
+ phydev->mdio.addr);
+
+ /* disable link control prior to cable test */
+ set_link_control(phydev, 0);
+
+ /* execute a cable test */
+ err = phy_configure_bit(phydev, MII_ECTRL, ECTRL_CABLE_TEST, 1);
+ if (err < 0)
+ goto phy_configure_error;
+
+ /* wait until test is completed */
+ err = wait_on_condition(phydev, MII_ECTRL, ECTRL_CABLE_TEST,
+ 0, CABLE_TEST_TIMEOUT);
+ if (err < 0)
+ goto phy_transition_error;
+
+ /* evaluate the test results */
+ reg_val = phy_read(phydev, MII_EXTERNAL_STATUS);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ if (reg_val & EXTSTAT_SHORT_DETECT)
+ c_test_result = "SHORT_DETECT\n";
+ else if (reg_val & EXTSTAT_OPEN_DETECT)
+ c_test_result = "OPEN_DETECT\n";
+ else
+ c_test_result = "NO_ERROR\n";
+
+ /* reenable link control after cable test */
+ set_link_control(phydev, 1);
+
+ /* write result into the buffer */
+ return scnprintf(buf, PAGE_SIZE, c_test_result);
+
+/* error handling */
+phy_auto_op_error:
+ dev_info(&phydev->mdio.dev, "phy is in auto mode: cabletest not available\n");
+ return 0;
+
+phy_read_error:
+ dev_err(&phydev->mdio.dev, "read error: sysfs_get_cable_test failed\n");
+ return reg_val;
+
+phy_configure_error:
+ dev_err(&phydev->mdio.dev, "phy r/w error: sysfs_get_cable_test failed\n");
+ return err;
+
+phy_transition_error:
+ dev_err(&phydev->mdio.dev, "Timeout: cable test failed to finish in time\n");
+ return err;
+}
+
+/* This function handles read accesses to the node 'test_mode' in sysfs
+ * Reading the node returns the current test mode configuration
+ */
+static ssize_t sysfs_get_test_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int reg_val;
+ char *tmode;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ reg_val = phy_read(phydev, MII_ECTRL);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ /* mask test mode bits */
+ reg_val &= ECTRL_TEST_MODE;
+
+ switch (reg_val) {
+ case ECTRL_NO_TMODE:
+ tmode = "NO_TMODE\n";
+ break;
+ case ECTRL_TMODE1:
+ tmode = "TMODE1\n";
+ break;
+ case ECTRL_TMODE2:
+ tmode = "TMODE2\n";
+ break;
+ case ECTRL_TMODE3:
+ tmode = "TMODE3\n";
+ break;
+ case ECTRL_TMODE4:
+ tmode = "TMODE4\n";
+ break;
+ case ECTRL_TMODE5:
+ tmode = "TMODE5\n";
+ break;
+ case ECTRL_TMODE6:
+ tmode = "TMODE6\n";
+ break;
+ default:
+ tmode = "unknown\n";
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev,
+ "unknown reg val is [%08x]\n", reg_val);
+ }
+
+ /* write result into the buffer */
+ return scnprintf(buf, PAGE_SIZE, tmode);
+
+/* error handling */
+phy_read_error:
+ dev_err(&phydev->mdio.dev, "read error: sysfs_get_test_mode failed\n");
+ return reg_val;
+}
+
+/* This function handles write accesses to the node 'test_mode' in sysfs
+ * Depending on the value written to it, the phy enters a certain test mode
+ */
+static ssize_t sysfs_set_test_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err;
+ int tmode;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ if (!managed_mode)
+ goto phy_auto_op_error;
+
+ /* parse the buffer */
+ err = kstrtoint(buf, 10, &tmode);
+ if (err < 0)
+ goto phy_parse_error;
+
+ switch (tmode) {
+ case 0:
+ err = enter_test_mode(phydev, NO_TMODE);
+ /* enable link control after exiting test */
+ set_link_control(phydev, 1);
+ break;
+ case 1:
+ /* disbale link control before entering test */
+ set_link_control(phydev, 0);
+ err = enter_test_mode(phydev, TMODE1);
+ break;
+ case 2:
+ /* disbale link control before entering test */
+ set_link_control(phydev, 0);
+ err = enter_test_mode(phydev, TMODE2);
+ break;
+ case 3:
+ /* disbale link control before entering test */
+ set_link_control(phydev, 0);
+ err = enter_test_mode(phydev, TMODE3);
+ break;
+ case 4:
+ /* disbale link control before entering test */
+ set_link_control(phydev, 0);
+ err = enter_test_mode(phydev, TMODE4);
+ break;
+ case 5:
+ /* disbale link control before entering test */
+ set_link_control(phydev, 0);
+ err = enter_test_mode(phydev, TMODE5);
+ break;
+ case 6:
+ /* disbale link control before entering test */
+ set_link_control(phydev, 0);
+ err = enter_test_mode(phydev, TMODE6);
+ break;
+ default:
+ break;
+ }
+
+ if (err)
+ goto phy_tmode_transit_error;
+
+ return count;
+
+/* error handling */
+phy_auto_op_error:
+ dev_info(&phydev->mdio.dev, "phy is in auto mode: testmodes not available\n");
+ return count;
+
+phy_parse_error:
+ dev_err(&phydev->mdio.dev, "parse error: sysfs_get_test_mode failed\n");
+ return err;
+
+phy_tmode_transit_error:
+ dev_err(&phydev->mdio.dev, "tmode error: sysfs_get_test_mode failed\n");
+ return err;
+}
+
+/* This function handles read accesses to the node 'led_cfg' in sysfs.
+ * Reading the node returns the current led configuration
+ */
+static ssize_t sysfs_get_led_cfg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int reg_val;
+ char *lmode;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ lmode = "DISABLED\n";
+
+ /* only TJA1100 has leds */
+ if ((phydev->phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1100) {
+ reg_val = phy_read(phydev, MII_CFG1);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ if (reg_val & TJA1100_CFG1_LED_EN) {
+ /* mask led mode bits */
+ reg_val &= TJA1100_CFG1_LED_MODE;
+
+ switch (reg_val) {
+ case CFG1_LED_LINKUP:
+ lmode = "LINKUP\n";
+ break;
+ case CFG1_LED_FRAMEREC:
+ lmode = "FRAMEREC\n";
+ break;
+ case CFG1_LED_SYMERR:
+ lmode = "SYMERR\n";
+ break;
+ case CFG1_LED_CRSSIG:
+ lmode = "CRSSIG\n";
+ break;
+ default:
+ lmode = "unknown\n";
+ if (verbosity > 1)
+ dev_alert(&phydev->mdio.dev,
+ "unknown reg val is [%08x]\n", reg_val);
+ }
+ }
+ }
+
+ /* write result into the buffer */
+ return scnprintf(buf, PAGE_SIZE, lmode);
+
+/* error handling */
+phy_read_error:
+ dev_err(&phydev->mdio.dev, "read error: sysfs_get_led_cfg failed\n");
+ return reg_val;
+}
+
+/* This function handles write accesses to the node 'led_cfg' in sysfs
+ * Depending on the value written to it, the led mode is configured
+ * accordingly.
+ */
+static ssize_t sysfs_set_led_cfg(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err;
+ int lmode;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ if ((phydev->phy_id & NXP_PHY_ID_MASK) != NXP_PHY_ID_TJA1100)
+ goto no_led_error;
+
+ /* parse the buffer */
+ err = kstrtoint(buf, 10, &lmode);
+ if (err < 0)
+ goto phy_parse_error;
+
+ switch (lmode) {
+ case 0:
+ err = enter_led_mode(phydev, NO_LED_MODE);
+ break;
+ case 1:
+ err = enter_led_mode(phydev, LINKUP_LED_MODE);
+ break;
+ case 2:
+ err = enter_led_mode(phydev, FRAMEREC_LED_MODE);
+ break;
+ case 3:
+ err = enter_led_mode(phydev, SYMERR_LED_MODE);
+ break;
+ case 4:
+ err = enter_led_mode(phydev, CRSSIG_LED_MODE);
+ break;
+ default:
+ break;
+ }
+
+ if (err)
+ goto phy_lmode_transit_error;
+
+ return count;
+
+/* error handling */
+phy_parse_error:
+ dev_err(&phydev->mdio.dev, "parse error: sysfs_set_led_cfg failed\n");
+ return err;
+
+phy_lmode_transit_error:
+ dev_err(&phydev->mdio.dev, "lmode error: sysfs_set_led_cfg failed\n");
+ return err;
+
+no_led_error:
+ dev_info(&phydev->mdio.dev, "phy has no led support\n");
+ return count;
+}
+
+/* This function handles read accesses to the node 'link_status' in sysfs
+ * Depending on current link status of the phy, the node reads
+ * 'up' or 'down'
+ */
+static ssize_t sysfs_get_link_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int linkup;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ linkup = get_link_status(phydev);
+
+ /* write result into the buffer */
+ return scnprintf(buf, PAGE_SIZE, "%s\n", linkup ? "up" : "down");
+}
+
+/* This function handles read accesses to the node 'wakeup_cfg' in sysfs
+ * Reading the node returns the current status of the bits
+ * FWDPHYLOC, REMWUPHY, LOCWUPHY, FWDPHYREM
+ */
+static ssize_t sysfs_get_wakeup_cfg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int reg_val;
+ int fwdphyloc_en, remwuphy_en, locwuphy_en, fwdphyrem_en;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ if ((phydev->phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1102P0 ||
+ (phydev->phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1102P1 ||
+ (phydev->phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1101) {
+ reg_val = phy_read(phydev, MII_CFG1);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ fwdphyloc_en = 0;
+ remwuphy_en = 0;
+ locwuphy_en = 0;
+ fwdphyrem_en = 0;
+
+ if (reg_val & TJA1102_CFG1_FWDPHYLOC)
+ fwdphyloc_en = 1;
+ if (reg_val & CFG1_REMWUPHY)
+ remwuphy_en = 1;
+ if (reg_val & CFG1_LOCWUPHY)
+ locwuphy_en = 1;
+ if (reg_val & CFG1_FWDPHYREM)
+ fwdphyrem_en = 1;
+ } else if ((phydev->phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1100) {
+ remwuphy_en = 1; /* not configurable, always enabled */
+ fwdphyloc_en = 0; /* not supported */
+
+ /* The status LED and WAKE input share a pin, so ultimately
+ * configuration depends on the hardware setup.
+ * If LED is disabled, we assume the pin is used for WAKE.
+ * In this case, the phy wakes up upon local wakeup event
+ * via the WAKE pin and also forwards it.
+ */
+ reg_val = phy_read(phydev, MII_CFG1);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ if (reg_val & TJA1100_CFG1_LED_EN) {
+ locwuphy_en = 0;
+ fwdphyrem_en = 0;
+ } else {
+ locwuphy_en = 1;
+ fwdphyrem_en = 1;
+ }
+ } else {
+ goto unsupported_phy_error;
+ }
+
+ /* write result into the buffer */
+ return scnprintf(buf, PAGE_SIZE,
+ "fwdphyloc[%s], remwuphy[%s], locwuphy[%s], fwdphyrem[%s]\n",
+ (fwdphyloc_en ? "on" : "off"),
+ (remwuphy_en ? "on" : "off"),
+ (locwuphy_en ? "on" : "off"),
+ (fwdphyrem_en ? "on" : "off"));
+
+/* error handling */
+phy_read_error:
+ dev_err(&phydev->mdio.dev, "read error: sysfs_get_wakeup_cfg failed\n");
+ return reg_val;
+
+unsupported_phy_error:
+ dev_err(&phydev->mdio.dev, "unsupported phy, sysfs_get_wakeup_cfg failed\n");
+ return -1;
+}
+
+/* This function handles write accesses to the node 'wakeup_cfg' in sysfs
+ * Depending on the hexadecimal value written, the bits
+ * FWDPHYLOC, REMWUPHY, LOCWUPHY, FWDPHYREM are configured
+ */
+static ssize_t sysfs_set_wakeup_cfg(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err, reg_val, reg_mask, wakeup_cfg;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ /* parse the buffer */
+ err = kstrtoint(buf, 16, &wakeup_cfg);
+ if (err < 0)
+ goto phy_parse_error;
+
+ if ((phydev->phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1102P0 ||
+ (phydev->phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1102P1 ||
+ (phydev->phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1101) {
+ reg_val = 0;
+
+ /* the first 4 bits of the supplied hexadecimal value
+ * are interpreted as the wakeup configuration
+ */
+ if (wakeup_cfg & SYSFS_FWDPHYLOC)
+ reg_val |= TJA1102_CFG1_FWDPHYLOC;
+ if (wakeup_cfg & SYSFS_REMWUPHY)
+ reg_val |= CFG1_REMWUPHY;
+ if (wakeup_cfg & SYSFS_LOCWUPHY)
+ reg_val |= CFG1_LOCWUPHY;
+ if (wakeup_cfg & SYSFS_FWDPHYREM)
+ reg_val |= CFG1_FWDPHYREM;
+
+ reg_mask = (TJA1102_CFG1_FWDPHYLOC | CFG1_REMWUPHY |
+ CFG1_LOCWUPHY | CFG1_FWDPHYREM);
+
+ err = phy_configure_bits(phydev, MII_CFG1, reg_mask, reg_val);
+ if (err < 0)
+ goto phy_configure_error;
+ } else if ((phydev->phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1100) {
+ /* FWDPHYLOC MUST be off
+ * REMWUPHY MUST be on
+ * only LOCWUPHY and FWDPHYREM are configurable
+ * Possible configurations:
+ * - BOTH enabled (then led MUST be off)
+ * - BOTH disabled (then led CAN be on)
+ * all other configurations are invalid.
+ *
+ * Therefore valid values to write to sysfs are:
+ * - 2 (LOCWUPHY and FWDPHYREM off)
+ * - E (LOCWUPHY and FWDPHYREM on)
+ */
+ if (((wakeup_cfg & SYSFS_LOCWUPHY) !=
+ (wakeup_cfg & SYSFS_FWDPHYREM)) ||
+ wakeup_cfg & SYSFS_FWDPHYLOC ||
+ !(wakeup_cfg & SYSFS_REMWUPHY)) {
+ dev_alert(&phydev->mdio.dev, "Invalid configuration\n");
+ } else if (wakeup_cfg & SYSFS_LOCWUPHY &&
+ wakeup_cfg & SYSFS_FWDPHYREM) {
+ err = enter_led_mode(phydev, NO_LED_MODE);
+ if (err)
+ goto phy_lmode_transit_error;
+ }
+ }
+
+ return count;
+
+/* error handling */
+phy_parse_error:
+ dev_err(&phydev->mdio.dev, "parse error: sysfs_set_wakeup_cfg failed\n");
+ return err;
+
+phy_configure_error:
+ dev_err(&phydev->mdio.dev, "phy r/w error: sysfs_set_wakeup_cfg failed\n");
+ return err;
+
+phy_lmode_transit_error:
+ dev_err(&phydev->mdio.dev, "lmode error: sysfs_set_wakeup_cfg failed\n");
+ return err;
+}
+
+/* This function handles read accesses to the node 'snr_wlimit_cfg' in sysfs.
+ * Reading the node returns the current snr warning limit.
+ */
+static ssize_t sysfs_get_snr_wlimit_cfg(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int reg_val;
+ char *snr_limit;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ reg_val = phy_read(phydev, MII_CFG2);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ /* mask snr wlimit bits */
+ reg_val &= CFG2_SNR_WLIMIT;
+
+ switch (reg_val) {
+ case SNR_CLASS_NONE:
+ snr_limit = "no fail limit\n";
+ break;
+ case SNR_CLASS_A:
+ snr_limit = "CLASS_A\n";
+ break;
+ case SNR_CLASS_B:
+ snr_limit = "CLASS_B\n";
+ break;
+ case SNR_CLASS_C:
+ snr_limit = "CLASS_C\n";
+ break;
+ case SNR_CLASS_D:
+ snr_limit = "CLASS_D\n";
+ break;
+ case SNR_CLASS_E:
+ snr_limit = "CLASS_E\n";
+ break;
+ case SNR_CLASS_F:
+ snr_limit = "CLASS_F\n";
+ break;
+ case SNR_CLASS_G:
+ snr_limit = "CLASS_G\n";
+ break;
+ default:
+ snr_limit = "unknown\n";
+ }
+
+ /* write result into the buffer */
+ return scnprintf(buf, PAGE_SIZE, snr_limit);
+
+/* error handling */
+phy_read_error:
+ dev_err(&phydev->mdio.dev, "read error: sysfs_get_snr_wlimit_cfg failed\n");
+ return reg_val;
+}
+
+/* This function handles write accesses to the node 'snr_wlimit_cfg' in sysfs
+ * Depending on the value written to it, the snr warning limit is configured
+ * accordingly.
+ */
+static ssize_t sysfs_set_snr_wlimit_cfg(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err, snr_limit, reg_val;
+ struct phy_device *phydev = to_phy_device(dev);
+
+ /* parse the buffer */
+ err = kstrtoint(buf, 10, &snr_limit);
+ if (err < 0)
+ goto phy_parse_error;
+
+ switch (snr_limit) {
+ case 0:
+ reg_val = SNR_CLASS_NONE;
+ break;
+ case 1:
+ reg_val = SNR_CLASS_A;
+ break;
+ case 2:
+ reg_val = SNR_CLASS_B;
+ break;
+ case 3:
+ reg_val = SNR_CLASS_C;
+ break;
+ case 4:
+ reg_val = SNR_CLASS_D;
+ break;
+ case 5:
+ reg_val = SNR_CLASS_E;
+ break;
+ case 6:
+ reg_val = SNR_CLASS_F;
+ break;
+ case 7:
+ reg_val = SNR_CLASS_G;
+ break;
+ default:
+ reg_val = -1;
+ break;
+ }
+
+ if (reg_val != -1) {
+ err = phy_configure_bits(phydev, MII_CFG2,
+ CFG2_SNR_WLIMIT, reg_val);
+ if (err)
+ goto phy_configure_error;
+ }
+
+ return count;
+
+/* error handling */
+phy_parse_error:
+ dev_err(&phydev->mdio.dev, "parse error: sysfs_set_snr_wlimit_cfg failed\n");
+ return err;
+
+phy_configure_error:
+ dev_err(&phydev->mdio.dev,
+ "phy r/w error: sysfs_set_snr_wlimit_cfg failed\n");
+ return err;
+}
+
+/* r/w access for everyone */
+static DEVICE_ATTR(master_cfg, S_IWUSR | S_IRUSR,
+ sysfs_get_master_cfg, sysfs_set_master_cfg);
+static DEVICE_ATTR(power_cfg, S_IWUSR | S_IRUSR,
+ sysfs_get_power_cfg, sysfs_set_power_cfg);
+static DEVICE_ATTR(loopback_cfg, S_IWUSR | S_IRUSR,
+ sysfs_get_loopback_cfg, sysfs_set_loopback_cfg);
+static DEVICE_ATTR(cable_test, S_IRUSR, sysfs_get_cable_test, NULL);
+static DEVICE_ATTR(test_mode, S_IWUSR | S_IRUSR,
+ sysfs_get_test_mode, sysfs_set_test_mode);
+static DEVICE_ATTR(led_cfg, S_IWUSR | S_IRUSR,
+ sysfs_get_led_cfg, sysfs_set_led_cfg);
+static DEVICE_ATTR(link_status, S_IRUSR, sysfs_get_link_status, NULL);
+static DEVICE_ATTR(wakeup_cfg, S_IWUSR | S_IRUSR,
+ sysfs_get_wakeup_cfg, sysfs_set_wakeup_cfg);
+static DEVICE_ATTR(snr_wlimit_cfg, S_IWUSR | S_IRUSR,
+ sysfs_get_snr_wlimit_cfg, sysfs_set_snr_wlimit_cfg);
+
+static struct attribute *nxp_sysfs_entries[] = {
+ &dev_attr_master_cfg.attr,
+ &dev_attr_power_cfg.attr,
+ &dev_attr_loopback_cfg.attr,
+ &dev_attr_cable_test.attr,
+ &dev_attr_test_mode.attr,
+ &dev_attr_led_cfg.attr,
+ &dev_attr_link_status.attr,
+ &dev_attr_wakeup_cfg.attr,
+ &dev_attr_snr_wlimit_cfg.attr,
+ NULL
+};
+
+static struct attribute_group nxp_attribute_group = {
+ .name = "configuration",
+ .attrs = nxp_sysfs_entries,
+};
+
+/* helper function, configures a register of phydev
+ *
+ * The function sets the bit of register reg_name,
+ * defined by bit_mask to 0 if (bit_value == 0), else to 1
+ * @return 0 if configuration completed, <0 if read/write
+ * error occurred
+ */
+static inline int phy_configure_bit(struct phy_device *phydev, int reg_name,
+ int bit_mask, int bit_value)
+{
+ int reg_val, err;
+
+ if (verbosity > 2)
+ dev_alert(&phydev->mdio.dev, "%s bit on mask [%08x] of reg [%d] of phy %x\n", (bit_value?"enabling":"disabling"),
+ bit_mask, reg_name, phydev->mdio.addr);
+
+ reg_val = phy_read(phydev, reg_name);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ if (bit_value)
+ reg_val |= bit_mask;
+ else
+ reg_val &= ~bit_mask;
+
+ err = phy_write(phydev, reg_name, reg_val);
+ if (err < 0)
+ goto phy_write_error;
+
+ return 0;
+
+/* error handling */
+phy_read_error:
+ dev_err(&phydev->mdio.dev, "read error: phy config failed\n");
+ return reg_val;
+
+phy_write_error:
+ dev_err(&phydev->mdio.dev, "write error: phy config failed\n");
+ return err;
+}
+
+/* helper function, configures a register of phydev
+ *
+ * The function sets the bits of register reg_name,
+ * defined by bit_mask to bit_value
+ * @return 0 if configuration completed, <0 if read/write
+ * error occurred
+ */
+static inline int phy_configure_bits(struct phy_device *phydev, int reg_name,
+ int bit_mask, int bit_value)
+{
+ int reg_val, err;
+
+ if (verbosity > 2)
+ dev_alert(&phydev->mdio.dev, "set mask [%08x] of reg [%d] of phy %x to value [%08x]\n",
+ bit_mask, reg_name, phydev->mdio.addr, bit_value);
+
+ reg_val = phy_read(phydev, reg_name);
+ if (reg_val < 0)
+ goto phy_read_error;
+
+ reg_val &= ~bit_mask;
+ reg_val |= bit_value;
+
+ err = phy_write(phydev, reg_name, reg_val);
+ if (err < 0)
+ goto phy_write_error;
+
+ return 0;
+
+/* error handling */
+phy_read_error:
+ dev_err(&phydev->mdio.dev, "read error: phy config failed\n");
+ return reg_val;
+
+phy_write_error:
+ dev_err(&phydev->mdio.dev, "write error: phy config failed\n");
+ return err;
+}
+
+#ifdef NETDEV_NOTIFICATION_FIX
+static struct class *bus_class_from_net_device(struct net_device *net_device,
+ const char *required_name)
+{
+ struct class *bus_class;
+
+ if (!net_device ||
+ !net_device->phydev ||
+ !net_device->phydev->mdio.bus ||
+ !net_device->phydev->mdio.bus->dev.class ||
+ !net_device->phydev->mdio.bus->dev.class->name)
+ return NULL;
+
+ bus_class = net_device->phydev->mdio.bus->dev.class;
+ if (strcmp(bus_class->name, required_name) != 0)
+ return NULL;
+
+ return bus_class;
+}
+
+static int mdio_bus_name_matches(struct device *found_device,
+ const void *desired_name)
+{
+ struct mii_bus *mdio_bus;
+
+ /* Since we know 'found_dev' belongs to a class with the name
+ 'mdio_bus', we assume it is a member of a 'struct mii_bus',
+ and therefore it is safe to call container_of */
+ mdio_bus = container_of(found_device, struct mii_bus, dev);
+
+ /* Double check that this is indeed a 'struct mii_bus'. If it is,
+ it's state should be MDIO_REGISTERED at this point. If it is not, it is
+ either not a 'struct mii_bus', either it is in an undesired state. */
+ if (mdio_bus->state != MDIOBUS_REGISTERED)
+ return 0;
+
+ if (strcmp(mdio_bus->name, (char *)desired_name) == 0)
+ return 1;
+ return 0;
+}
+
+static struct mii_bus *find_mdio_bus_by_name(const char *name,
+ struct class *mdio_bus_class)
+{
+ struct device *found_device;
+
+ found_device = class_find_device(mdio_bus_class,
+ NULL,
+ (void *)name,
+ mdio_bus_name_matches);
+ if (found_device)
+ return container_of(found_device, struct mii_bus, dev);
+ else
+ return NULL;
+}
+
+/* helper function, check if given phy id belongs to a nxp phy
+ *
+ * @return 0 if not an nxp phy, != 0 else
+ */
+static int is_nxp_phy(int phy_id)
+{
+ return ((phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1100 ||
+ (phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1101 ||
+ (phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1102P0 ||
+ (phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1102P1 ||
+ (phy_id & NXP_PHY_ID_MASK) == NXP_PHY_ID_TJA1102S);
+
+}
+
+/* traverse the phy_map of the given mdio_bus, and manipulate any phys found
+ * that are found according to the value of the event, ie.
+ * - start (resume) on NETDEV_UP
+ * - stop (suspend) on NETDEV_GOING_DOWN
+ */
+static void mdio_netdev_change_event(struct mii_bus *mdio_bus, int event)
+{
+ /* normally on NETDEV_GOING_DOWN the kernel calls ndo_stop()
+ * of the eth controller, which stops and disconnects the one phy
+ * that is associated with the ethernet controller
+ * [see fec_enet_close() in fec_main.c l 2740].
+ * We need to do this manually for every NXP phy,
+ * however we do not (necessarily) have an attached_dev, so phy_detach,
+ * which is called by phy_disconnect(), would crash
+ */
+ int phy_addr;
+ struct phy_device *phydev;
+
+ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+ phydev = mdiobus_get_phy(mdio_bus, phy_addr);
+ if (!phydev)
+ continue;
+
+ if (!is_nxp_phy(phydev->phy_id) || !phydev->priv)
+ continue;
+
+ if (event == NETDEV_GOING_DOWN) {
+ /* stop polling,
+ * as mdio bus will become unavailable as soon as
+ * fec_runtime_suspend() (fec_main.c l4801) is called
+ */
+ if (!no_poll)
+ stop_polling(phydev);
+
+ /* sets state to PHY_HALTED */
+ phy_stop(phydev);
+ } else if (event == NETDEV_UP) {
+ /* updates the phy state and resumes,
+ * if state previously was PHY_HALTED
+ */
+ phy_start(phydev);
+
+ if (!no_poll)
+ start_polling(phydev);
+ }
+ }
+}
+
+/* callback, called whenever a netdev changes its state.
+ *
+ * Handles only NETDEV_GOING_DOWN and NETDEV_UP events of interface called
+ * MDIO_INTERFACE_NAME. Phys on the mdio bus "fec_enet_mii_bus"
+ * are stopped (suspended) and started (resumed) accordingly.
+ *
+ * @return NOTIFY_DONE
+ */
+static int netdev_state_change_event(struct notifier_block *unused,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ struct mii_bus *mdio_bus;
+ struct class *bus_class;
+ struct net_device *net_device;
+
+ /* currently the eth0 interface controlls the mdio bus.
+ * However as CONFIG_FIXED_PHY is configured,
+ * eth0 is associated with "Fixed MDIO Bus", but the phydev
+ * is associated with "fec_enet_mii_bus". If eth0 goes down,
+ * only devices on "Fixed MDIO Bus" are notified (ie removed).
+ * We need to manually listen to eth0 events
+ * stops the phy and the polling
+ */
+ if (event != NETDEV_GOING_DOWN && event != NETDEV_UP)
+ goto skip;
+
+ if (strcmp(dev->name, MDIO_INTERFACE_NAME) != 0)
+ goto skip;
+
+ net_device = first_net_device(&init_net);
+ do {
+ bus_class = bus_class_from_net_device(net_device, "mdio_bus");
+ if (!bus_class)
+ continue;
+ mdio_bus = find_mdio_bus_by_name(MII_BUS_NAME, bus_class);
+ if (!mdio_bus)
+ continue;
+
+ if (verbosity > 0)
+ pr_alert("NXP PHY: received event [%lx] for [%s]: Notifying phys on bus [%s]\n",
+ event, dev->name, mdio_bus->name);
+
+ mdio_netdev_change_event(mdio_bus, event);
+ } while ((net_device = next_net_device(net_device)));
+
+skip:
+ return NOTIFY_DONE;
+}
+
+/* netdev notification infrastructure */
+struct notifier_block netdev_notifier = {
+ .notifier_call = netdev_state_change_event
+};
+#endif
+
+static struct phy_driver nxp_drivers[] = {
+{
+ .phy_id = NXP_PHY_ID_TJA1100,
+ .name = "TJA1100",
+ .phy_id_mask = NXP_PHY_ID_MASK,
+ .features = (SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_100BASET1_FULL),
+ .flags = 0,
+ .probe = &nxp_probe,
+ .remove = &nxp_remove,
+ .config_init = &nxp_config_init,
+ .config_aneg = &nxp_config_aneg,
+ .read_status = &genphy_read_status,
+ .resume = &nxp_resume,
+ .suspend = &nxp_suspend,
+ .config_intr = &nxp_config_intr,
+ .ack_interrupt = &nxp_ack_interrupt,
+ .did_interrupt = &nxp_did_interrupt,
+}, {
+ .phy_id = NXP_PHY_ID_TJA1102P0,
+ .name = "TJA1102_p0",
+ .phy_id_mask = NXP_PHY_ID_MASK,
+ .features = (SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_100BASET1_FULL),
+ .flags = 0,
+ .probe = &nxp_probe,
+ .remove = &nxp_remove,
+ .config_init = &nxp_config_init,
+ .config_aneg = &nxp_config_aneg,
+ .read_status = &genphy_read_status,
+ .resume = &nxp_resume,
+ .suspend = &nxp_suspend,
+ .config_intr = &nxp_config_intr,
+ .ack_interrupt = &nxp_ack_interrupt,
+ .did_interrupt = &nxp_did_interrupt,
+}, {
+ .phy_id = NXP_PHY_ID_TJA1101,
+ .name = "TJA1101",
+ .phy_id_mask = NXP_PHY_ID_MASK,
+ .features = (SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_100BASET1_FULL),
+ .flags = 0,
+ .probe = &nxp_probe,
+ .remove = &nxp_remove,
+ .config_init = &nxp_config_init,
+ .config_aneg = &nxp_config_aneg,
+ .read_status = &genphy_read_status,
+ .resume = &nxp_resume,
+ .suspend = &nxp_suspend,
+ .config_intr = &nxp_config_intr,
+ .ack_interrupt = &nxp_ack_interrupt,
+ .did_interrupt = &nxp_did_interrupt,
+}, {
+ .phy_id = NXP_PHY_ID_TJA1102S,
+ .name = "TJA1102S",
+ .phy_id_mask = NXP_PHY_ID_MASK,
+ .features = (SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_100BASET1_FULL),
+ .flags = 0,
+ .probe = &nxp_probe,
+ .remove = &nxp_remove,
+ .config_init = &nxp_config_init,
+ .config_aneg = &nxp_config_aneg,
+ .read_status = &genphy_read_status,
+ .resume = &nxp_resume,
+ .suspend = &nxp_suspend,
+ .config_intr = &nxp_config_intr,
+ .ack_interrupt = &nxp_ack_interrupt,
+ .did_interrupt = &nxp_did_interrupt,
+#ifdef CONFIG_TJA1102_FIX
+}, {
+ .phy_id = NXP_PHY_ID_TJA1102P1,
+ .name = "TJA1102_p1",
+ .phy_id_mask = NXP_PHY_ID_MASK,
+ .features = (SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_100BASET1_FULL),
+ .flags = 0,
+ .probe = &nxp_probe,
+ .remove = &nxp_remove,
+ .config_init = &nxp_config_init,
+ .config_aneg = &nxp_config_aneg,
+ .read_status = &genphy_read_status,
+ .resume = &nxp_resume,
+ .suspend = &nxp_suspend,
+ .config_intr = &nxp_config_intr,
+ .ack_interrupt = &nxp_ack_interrupt,
+ .did_interrupt = &nxp_did_interrupt,
+#endif
+} };
+
+/* module init function */
+static int __init nxp_init(void)
+{
+ int err;
+
+ pr_alert("NXP PHY: loading NXP PHY driver: [%s%s]\n",
+ (managed_mode ? "managed mode" : "autonomous mode"),
+ (no_poll ? ", polling disabled" : ""));
+
+ err = phy_drivers_register(nxp_drivers, ARRAY_SIZE(nxp_drivers), THIS_MODULE);
+ if (err)
+ goto drv_registration_error;
+
+#ifdef NETDEV_NOTIFICATION_FIX
+ if (!no_poll) {
+ err = register_netdevice_notifier(&netdev_notifier);
+ if (err)
+ goto notification_registration_error;
+ }
+#endif
+
+ return 0;
+
+/* error handling */
+drv_registration_error:
+ pr_err("NXP PHY: driver registration failed\n");
+ return err;
+
+#ifdef NETDEV_NOTIFICATION_FIX
+notification_registration_error:
+ pr_err("NXP PHY: could not register notification handler\n");
+ unregister_netdevice_notifier(&netdev_notifier);
+ return err;
+#endif
+}
+
+module_init(nxp_init);
+
+/* module exit function */
+static void __exit nxp_exit(void)
+{
+ pr_alert("NXP PHY: unloading NXP PHY driver\n");
+#ifdef NETDEV_NOTIFICATION_FIX
+ if (!no_poll)
+ unregister_netdevice_notifier(&netdev_notifier);
+#endif
+ phy_drivers_unregister(nxp_drivers, ARRAY_SIZE(nxp_drivers));
+}
+
+module_exit(nxp_exit);
+
+/* use module device table for hotplugging support */
+static struct mdio_device_id __maybe_unused nxp_tbl[] = {
+ {NXP_PHY_ID_TJA1100, NXP_PHY_ID_MASK},
+ {NXP_PHY_ID_TJA1102P0, NXP_PHY_ID_MASK},
+ {NXP_PHY_ID_TJA1102S, NXP_PHY_ID_MASK},
+ {}
+};
+
+MODULE_DEVICE_TABLE(mdio, nxp_tbl);
+
+MODULE_DESCRIPTION("NXP PHY driver");
+MODULE_AUTHOR("Marco Hartmann");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.3");
diff --git a/drivers/net/phy/tja110x.h b/drivers/net/phy/tja110x.h
new file mode 100644
index 000000000000..113dd14d5585
--- /dev/null
+++ b/drivers/net/phy/tja110x.h
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; 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 _NXP_PHY_H
+#define _NXP_PHY_H
+
+ /* PHY IDs */
+#define NXP_PHY_ID_TJA1100 (0x0180DC40U)
+#define NXP_PHY_ID_TJA1101 (0x0180DD00U)
+#define NXP_PHY_ID_TJA1102P0 (0x0180DC80U)
+#define NXP_PHY_ID_TJA1102P1 (0x00000000U)
+#define NXP_PHY_ID_TJA1102S (0x0180DC90U) /* only P0 is available */
+
+/* masks out the revision number */
+#define NXP_PHY_ID_MASK (0xFFFFFFF0U)
+
+#endif /* _NXP_PHY_H */
+
+/* NXP specific registers */
+
+/* extended_control register (TJA1100 and TJA1102) */
+#define MII_ECTRL (0x11U)
+/* configuration_1 register (TJA1100 and TJA1102) */
+#define MII_CFG1 (0x12U)
+/* configuration_2 register (TJA1100 and TJA1102) */
+#define MII_CFG2 (0x13U)
+/* symbol_error_counter register (TJA1100 and TJA1102) */
+#define MII_SYMERRCNT (0x14U)
+/* interrupt_source_flag register (TJA1100 and TJA1102) */
+#define MII_INTSRC (0x15U)
+/* interrupt_mask register (TJA1100 and TJA1102) */
+#define MII_INTMASK (0x16U)
+/* communication_status register (TJA1100 and TJA1102) */
+#define MII_COMMSTAT (0x17U)
+/* general_status register (TJA1100 and TJA1102) */
+#define MII_GENSTAT (0x18U)
+/* external_status register (TJA1100 and TJA1102) */
+#define MII_EXTERNAL_STATUS (0x19U)
+/* link_fail_counter register (TJA1100 and TJA1102) */
+#define MII_LINK_FAIL_COUNTER (0x1AU)
+/* common_configuration register (only TJA1102) */
+#define MII_COMMCFG (0x1BU)
+/* configuration_3 register (only TJA1102) */
+#define MII_CONFIGURATION_3 (0x1CU)
+
+/* extended_control register */
+#define ECTRL_LINK_CONTROL BIT(15)
+#define ECTRL_POWER_MODE (0x00007800U)
+#define ECTRL_SLAVE_JITTER_TEST BIT(10)
+#define ECTRL_TRAINING_RESTART BIT(9)
+#define ECTRL_TEST_MODE (0x000001C0U)
+#define ECTRL_CABLE_TEST BIT(5)
+#define ECTRL_LOOPBACK_MODE (0x00000018U)
+#define ECTRL_CONFIG_EN BIT(2)
+#define ECTRL_WAKE_REQUEST BIT(0)
+#define CABLE_TEST_TIMEOUT 1U /* cable test takes <= 1*100us */
+
+/* register values of the different power modes */
+#define POWER_MODE_NOCHANGE (0x00000000U)
+#define POWER_MODE_NORMAL (0x00001800U)
+#define POWER_MODE_SLEEPREQUEST (0x00005800U)
+#define POWER_MODE_STANDBY (0x00006000U)
+#define POWER_MODE_SILENT (0x00004800U)
+#define POWER_MODE_SLEEP (0x00005000U)
+
+/* timeouts for different power mode transitions */
+#define POWER_MODE_TIMEOUT 200U
+#define SLEEP_REQUEST_TO 160U /* 16ms = 160*100us */
+
+/* duration necessary for a reliable wake up of the link partner (in us) */
+#define TJA100_WAKE_REQUEST_TIMEOUT_US 5000U
+#define TJA102_WAKE_REQUEST_TIMEOUT_US 1300U
+
+/* configuration_1 register */
+#define CFG1_MASTER_SLAVE BIT(15)
+#define TJA1100_CFG1_AUTO_OP BIT(14)
+#define TJA1102_CFG1_FWDPHYLOC BIT(14)
+#define CFG1_LINK_LENGTH (0x00003000U)
+#define CFG1_REMWUPHY BIT(11)
+#define CFG1_LOCWUPHY BIT(10)
+#define CFG1_MII_MODE (0x00000300U)
+#define TJA1100_CFG1_MII_MODE_REFCLK_IN 0x100
+#define CFG1_MII_DRIVER BIT(7)
+#define CFG1_SLEEP_CONFIRM BIT(6)
+#define TJA1100_CFG1_LED_MODE (0x00000030U)
+#define TJA1100_CFG1_LED_EN BIT(3)
+#define CFG1_FWDPHYREM BIT(2)
+#define CFG1_AUTO_PWD BIT(1)
+#define CFG1_LPS_ACTIVE BIT(0)
+
+/* configuration_2 register */
+#define CFG2_PHYAD (0x0000F800U)
+#define CFG2_SNR_AVERAGING (0x00000600U)
+#define CFG2_SNR_WLIMIT (0x000001C0U)
+#define CFG2_SNR_FAILLIMIT (0x00000038U)
+#define CFG2_JUMBO_ENABLE BIT(2)
+#define CFG2_SLEEP_REQUEST_TO (0x00000003U)
+
+#define SLEEP_REQUEST_TO_16MS (0x00000003U)
+
+/* symbol_error_counter register */
+#define SYMERRCNT_SYM_ERR_CNT (0xFFFFFFFFU)
+
+/* interrupt_source_flag register */
+#define INTERRUPT_PWON BIT(15)
+#define INTERRUPT_WAKEUP BIT(14)
+#define INTERRUPT_WUR_RECEIVED BIT(13)
+#define INTERRUPT_LPS_RECEIVED BIT(12)
+#define INTERRUPT_PHY_INIT_FAIL BIT(11)
+#define INTERRUPT_LINK_STATUS_FAIL BIT(10)
+#define INTERRUPT_LINK_STATUS_UP BIT(9)
+#define INTERRUPT_SYM_ERR BIT(8)
+#define INTERRUPT_TRAINING_FAILED BIT(7)
+#define INTERRUPT_SNR_WARNING BIT(6)
+#define INTERRUPT_CONTROL_ERROR BIT(5)
+#define INTERRUPT_TXEN_CLAMPED BIT(4)
+#define INTERRUPT_UV_ERR BIT(3)
+#define INTERRUPT_UV_RECOVERY BIT(2)
+#define INTERRUPT_TEMP_ERROR BIT(1)
+#define INTERRUPT_SLEEP_ABORT BIT(0)
+#define INTERRUPT_NONE (0x00000000U)
+#define INTERRUPT_ALL (0x0000FFFFU)
+
+/* communication_status register */
+#define COMMSTAT_LINK_UP BIT(15)
+#define COMMSTAT_TX_MODE (0x00006000U)
+#define COMMSTAT_LOC_RCVR_STATUS BIT(12)
+#define COMMSTAT_REM_RCVR_STATUS BIT(11)
+#define COMMSTAT_SCR_LOCKED BIT(10)
+#define COMMSTAT_SSD_ERROR BIT(9)
+#define COMMSTAT_ESD_ERROR BIT(8)
+#define COMMSTAT_SNR (0x000000E0U)
+#define COMMSTAT_RECEIVE_ERROR BIT(4)
+#define COMMSTAT_TRANSMIT_ERROR BIT(3)
+#define COMMSTAT_PHY_STATE (0x00000007U)
+
+/* register category general_status */
+#define GENSTAT_INT_STATUS BIT(15)
+#define GENSTAT_PLL_LOCKED BIT(14)
+#define GENSTAT_LOCAL_WU BIT(13)
+#define GENSTAT_REMOTE_WU BIT(12)
+#define GENSTAT_DATA_DET_WU BIT(11)
+#define GENSTAT_EN_STATUS BIT(10)
+#define GENSTAT_RESET_STATUS BIT(9)
+#define GENSTAT_LINKFAIL_CNT (0x000000F8U)
+
+/* common_configuration register */
+#define COMMCFG_AUTO_OP BIT(15)
+
+/* External status register */
+#define EXTSTAT_OPEN_DETECT BIT(7)
+#define EXTSTAT_SHORT_DETECT BIT(8)
+
+/*
+ * Indicator for BRR support in ESTATUS register
+ * and in phydev->supported member.
+ * Not yet present in include/uapi/linux/mii.h and
+ * include/uapi/linux/ethtool.h
+ */
+#define ESTATUS_100T1_FULL BIT(7)
+#define SUPPORTED_100BASET1_FULL BIT(27)
+#define ADVERTISED_100BASET1_FULL BIT(27)
+
+/* length of delay during one loop iteration in
+ * wait_on_condition (in us)
+ */
+#define DELAY_LENGTH 100U
+
+/* length of delay during two pollings (in ms) */
+#define POLL_PAUSE 50U
+
+/* possible test modes of the PHY */
+enum test_mode {
+ NO_TMODE = 1,
+ TMODE1,
+ TMODE2,
+ TMODE3,
+ TMODE4,
+ TMODE5,
+ TMODE6
+};
+
+ /* register values of the different test modes */
+ #define ECTRL_NO_TMODE (0x000000U) /* no test mode */
+ #define ECTRL_TMODE1 (0x000040U)
+ #define ECTRL_TMODE2 (0x000080U)
+ #define ECTRL_TMODE3 (0x0000C0U)
+ #define ECTRL_TMODE4 (0x000100U)
+ #define ECTRL_TMODE5 (0x000140U)
+ /* scrambler, descrambler bypassed */
+ #define ECTRL_TMODE6 (0x000180U)
+
+/* possible loopback modes of the PHY */
+enum loopback_mode {
+ NO_LMODE = 1,
+ INTERNAL_LMODE,
+ EXTERNAL_LMODE,
+ REMOTE_LMODE
+};
+
+/* register values of the different loopback modes */
+#define ECTRL_INTERNAL_LMODE (0x000000U)
+#define ECTRL_EXTERNAL_LMODE (0x000008U)
+#define ECTRL_REMOTE_LMODE (0x000018U)
+
+/* possible led modes of the PHY */
+enum led_mode {
+ NO_LED_MODE = 1,
+ LINKUP_LED_MODE,
+ FRAMEREC_LED_MODE,
+ SYMERR_LED_MODE,
+ CRSSIG_LED_MODE
+};
+
+/* register values of the different led modes */
+#define CFG1_LED_LINKUP (0x00000000U)
+#define CFG1_LED_FRAMEREC (0x00000010U)
+#define CFG1_LED_SYMERR (0x00000020U)
+#define CFG1_LED_CRSSIG (0x00000030U)
+
+/* values written to sysfs nodes */
+#define SYSFS_FWDPHYLOC BIT(0)
+#define SYSFS_REMWUPHY BIT(1)
+#define SYSFS_LOCWUPHY BIT(2)
+#define SYSFS_FWDPHYREM BIT(3)
+
+/* nxp specific data */
+struct nxp_specific_data {
+ int is_master;
+ int is_poll_setup;
+ int is_polling;
+
+ u32 quirks;
+};
+
+/* register values of the different led modes */
+#define SNR_CLASS_NONE (0x00000000U)
+#define SNR_CLASS_A (0x00000040U)
+#define SNR_CLASS_B (0x00000080U)
+#define SNR_CLASS_C (0x000000C0U)
+#define SNR_CLASS_D (0x00000100U)
+#define SNR_CLASS_E (0x00000140U)
+#define SNR_CLASS_F (0x00000180U)
+#define SNR_CLASS_G (0x000001C0U)
+
+/* Helper Function prototypes */
+static int set_master_cfg(struct phy_device *phydev, int setMaster);
+static int get_master_cfg(struct phy_device *phydev);
+static int wait_on_condition(struct phy_device *phydev, int reg_addr,
+ int reg_mask, int cond, int timeout);
+static void set_link_control(struct phy_device *phydev,
+ int enable_link_control);
+static inline int phy_configure_bit(struct phy_device *phydev,
+ int reg_name, int bit_mask,
+ int bit_value);
+static inline int phy_configure_bits(struct phy_device *phydev,
+ int reg_name, int bit_mask,
+ int bit_value);
+static int nxp_resume(struct phy_device *phydev);
+static int nxp_ack_interrupt(struct phy_device *phydev);
+static void poll(struct work_struct *work);
+static void setup_polling(struct phy_device *phydev);
+static void start_polling(struct phy_device *phydev);
+static void stop_polling(struct phy_device *phydev);
+
+static struct attribute *nxp_sysfs_entries[];
+static struct attribute_group nxp_attribute_group;
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 8c8edaf1bba6..591686ba802b 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -21,6 +21,8 @@ source "drivers/net/wireless/admtek/Kconfig"
source "drivers/net/wireless/ath/Kconfig"
source "drivers/net/wireless/atmel/Kconfig"
source "drivers/net/wireless/broadcom/Kconfig"
+source "drivers/net/wireless/bcmdhd/Kconfig"
+source "drivers/net/wireless/bcmdhd_1363/Kconfig"
source "drivers/net/wireless/cisco/Kconfig"
source "drivers/net/wireless/intel/Kconfig"
source "drivers/net/wireless/intersil/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index f00d42953fb8..c2e5addeecd3 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -5,6 +5,8 @@
obj-$(CONFIG_WLAN_VENDOR_ADMTEK) += admtek/
obj-$(CONFIG_WLAN_VENDOR_ATH) += ath/
obj-$(CONFIG_WLAN_VENDOR_ATMEL) += atmel/
+obj-$(CONFIG_BCMDHD) += bcmdhd/
+obj-$(CONFIG_BCMDHD_1363) += bcmdhd_1363/
obj-$(CONFIG_WLAN_VENDOR_BROADCOM) += broadcom/
obj-$(CONFIG_WLAN_VENDOR_CISCO) += cisco/
obj-$(CONFIG_WLAN_VENDOR_INTEL) += intel/
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 65ad7a130ca1..e5f04487b5cc 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -696,6 +696,7 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar)
"boot get otp board id result 0x%08x board_id %d chip_id %d\n",
result, board_id, chip_id);
+ /* Murata -- https:/patchwork.kernel.org/patch/9486941/ ; */
if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0 ||
(board_id == 0)) {
ath10k_warn(ar, "board id is not exist in otp, ignore it\n");
@@ -1043,7 +1044,7 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,
out:
if (!ar->normal_mode_fw.board_data || !ar->normal_mode_fw.board_len) {
- ath10k_err(ar,
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
"failed to fetch board data for %s from %s/%s\n",
boardname, ar->hw_params.fw.dir, filename);
ret = -ENODATA;
@@ -1123,7 +1124,7 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name,
fw_file->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,
name);
if (IS_ERR(fw_file->firmware)) {
- ath10k_err(ar, "could not fetch firmware file '%s/%s': %ld\n",
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "could not fetch firmware file '%s/%s': %ld\n",
ar->hw_params.fw.dir, name,
PTR_ERR(fw_file->firmware));
return PTR_ERR(fw_file->firmware);
@@ -1291,44 +1292,41 @@ err:
return ret;
}
+/* Murata -- add this function */
+static void ath10k_core_get_fw_name(struct ath10k *ar, char *fw_name,
+ size_t fw_name_len, int fw_api)
+{
+ scnprintf(fw_name, fw_name_len, "%s-%d.bin", ATH10K_FW_FILE_BASE, fw_api);
+}
+
+/* Murata -- make significant changes to following function to pull correct firmware file */
static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
{
- int ret;
+ int ret, i;
+ char fw_name[100];
/* calibration file is optional, don't check for any errors */
ath10k_fetch_cal_file(ar);
- ar->fw_api = 5;
- ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+ for (i = ATH10K_FW_API_MAX; i >= ATH10K_FW_API_MIN; i--) {
+ ar->fw_api = i;
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n",
+ ar->fw_api);
- ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API5_FILE,
- &ar->normal_mode_fw.fw_file);
- if (ret == 0)
- goto success;
-
- ar->fw_api = 4;
- ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
-
- ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API4_FILE,
- &ar->normal_mode_fw.fw_file);
- if (ret == 0)
- goto success;
-
- ar->fw_api = 3;
- ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+ ath10k_core_get_fw_name(ar, fw_name, sizeof(fw_name), ar->fw_api);
+ ret = ath10k_core_fetch_firmware_api_n(ar, fw_name,
+ &ar->normal_mode_fw.fw_file);
+ if (!ret)
+ goto success;
+ }
- ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API3_FILE,
- &ar->normal_mode_fw.fw_file);
- if (ret == 0)
- goto success;
+ /* we end up here if we couldn't fetch any firmware */
- ar->fw_api = 2;
- ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+ ath10k_err(ar, "Failed to find firmware-N.bin (N between %d and %d) from %s: %d",
+ ATH10K_FW_API_MIN, ATH10K_FW_API_MAX, ar->hw_params.fw.dir,
+ ret);
- ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE,
- &ar->normal_mode_fw.fw_file);
- if (ret)
- return ret;
+ return ret;
success:
ath10k_dbg(ar, ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);
@@ -2097,7 +2095,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
ret = ath10k_core_fetch_firmware_files(ar);
if (ret) {
- ath10k_err(ar, "could not fetch firmware files (%d)\n", ret);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "could not fetch firmware files (%d)\n", ret);
goto err_power_down;
}
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 6038b7486f1d..347243e4cb74 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -128,6 +128,12 @@ enum qca9377_chip_id_rev {
#define QCA4019_HW_1_0_BOARD_DATA_FILE "board.bin"
#define QCA4019_HW_1_0_PATCH_LOAD_ADDR 0x1234
+/* Murata: QCA recommended patch */
+#define ATH10K_FW_FILE_BASE "firmware"
+/* Murata -- bump up to look for 6 instead of 5 */
+#define ATH10K_FW_API_MAX 6
+#define ATH10K_FW_API_MIN 2
+
#define ATH10K_FW_API2_FILE "firmware-2.bin"
#define ATH10K_FW_API3_FILE "firmware-3.bin"
@@ -137,6 +143,9 @@ enum qca9377_chip_id_rev {
/* HTT id conflict fix for management frames over HTT */
#define ATH10K_FW_API5_FILE "firmware-5.bin"
+/* Murata -- the firmware-6.bin blob */
+#define ATH10K_FW_API6_FILE "firmware-6.bin"
+
#define ATH10K_FW_UTF_FILE "utf.bin"
#define ATH10K_FW_UTF_API2_FILE "utf-2.bin"
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 25b8d501d437..05ef6bac3ac2 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1782,6 +1782,8 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
ath10k_pci_irq_disable(ar);
ath10k_pci_irq_sync(ar);
ath10k_pci_flush(ar);
+ ath10k_pci_sleep_sync(ar);
+
napi_synchronize(&ar->napi);
napi_disable(&ar->napi);
@@ -3430,6 +3432,8 @@ MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_BOARD_API2_FILE);
/* QCA6174 3.1 firmware files */
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API4_FILE);
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API5_FILE);
+/* Murata -- patch to load firmware 6 version */
+MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API6_FILE);
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE);
MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_BOARD_API2_FILE);
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index f69b98f4276b..925faecad264 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -553,7 +553,8 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
ath10k_wmi_tlv_event_tx_pause(ar, skb);
break;
default:
- ath10k_warn(ar, "Unknown eventid: %d\n", id);
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "Unknown eventid: %d\n", id);
break;
}
diff --git a/drivers/net/wireless/bcmdhd/Kconfig b/drivers/net/wireless/bcmdhd/Kconfig
new file mode 100644
index 000000000000..a69ecc376391
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/Kconfig
@@ -0,0 +1,60 @@
+config BCMDHD
+ tristate "Broadcom FullMAC wireless cards support v1.141"
+ ---help---
+ This module adds support for wireless adapters based on
+ Broadcom FullMAC chipset.
+
+ If you choose to build a module, it'll be called dhd. Say M if
+ unsure.
+
+config BCMDHD_SDIO
+ tristate "SDIO bus interface support"
+ depends on BCMDHD && MMC
+
+config BCM4339
+ tristate "BCM4339 support"
+ depends on BCMDHD
+
+config BCM43340
+ tristate "BCM43340 support"
+ depends on BCMDHD
+
+config BCM4354
+ tristate "BCM4354 support"
+ depends on BCMDHD
+
+config BCMDHD_FW_PATH
+ depends on BCMDHD
+ string "Firmware path"
+ default "/system/vendor/firmware/fw_bcmdhd.bin"
+ ---help---
+ Path to the firmware file.
+
+config BCMDHD_NVRAM_PATH
+ depends on BCMDHD
+ string "NVRAM path"
+ default "/system/etc/wifi/bcmdhd.cal"
+ ---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
+
+config DHD_USE_STATIC_BUF
+ bool "Enable memory preallocation"
+ depends on BCMDHD
+ default n
+ ---help---
+ Use memory preallocated in platform
+
+config DHD_USE_SCHED_SCAN
+ bool "Use CFG80211 sched scan"
+ depends on BCMDHD && CFG80211
+ default n
+ ---help---
+ Use CFG80211 sched scan
diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile
new file mode 100644
index 000000000000..c9542d945948
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/Makefile
@@ -0,0 +1,229 @@
+# bcmdhd
+#####################
+# SDIO Basic feature
+#####################
+
+DHDCFLAGS += -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \
+ -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \
+ -DDHDTHREAD -DSHOW_EVENTS -DBCMDBG -DWLP2P \
+ -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \
+ -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT \
+ -DEMBEDDED_PLATFORM -DPNO_SUPPORT \
+ -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT \
+ -DCUSTOMER_HW2 -DGET_CUSTOM_MAC_ENABLE
+
+#################
+# Common feature
+#################
+DHDCFLAGS += -DWL_CFG80211
+# Print out kernel panic point of file and line info when assertion happened
+DHDCFLAGS += -DBCMASSERT_LOG
+
+# keepalive
+DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=28000
+
+DHDCFLAGS += -DVSDB
+DHDCFLAGS += -DPROP_TXSTATUS
+
+# For p2p connection issue
+DHDCFLAGS += -DWL_SCB_TIMEOUT=10
+
+# TDLS enable
+DHDCFLAGS += -DWLTDLS -DWLTDLS_AUTO_ENABLE
+# For TDLS tear down inactive time 40 sec
+DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=40000
+# for TDLS RSSI HIGH for establishing TDLS link
+DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-60
+# for TDLS RSSI HIGH for tearing down TDLS link
+DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-70
+
+# Roaming
+DHDCFLAGS += -DROAM_AP_ENV_DETECTION
+DHDCFLAGS += -DROAM_ENABLE -DROAM_CHANNEL_CACHE -DROAM_API
+DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND
+# Roaming trigger
+DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-75
+DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=10
+# Set PM 2 always regardless suspend/resume
+DHDCFLAGS += -DSUPPORT_PM2_ONLY
+
+# For special PNO Event keep wake lock for 10sec
+DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10
+DHDCFLAGS += -DMIRACAST_AMPDU_SIZE=8
+
+# Early suspend
+DHDCFLAGS += -DDHD_USE_EARLYSUSPEND
+
+# For Scan result patch
+DHDCFLAGS += -DESCAN_RESULT_PATCH
+
+# For Static Buffer
+ifeq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),y)
+ DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF
+ DHDCFLAGS += -DENHANCED_STATIC_BUF
+ DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT
+endif
+ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),)
+DHDCFLAGS += -DWL_SCHED_SCAN
+endif
+
+# Ioctl timeout 5000ms
+DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000
+
+# Prevent rx thread monopolize
+DHDCFLAGS += -DWAIT_DEQUEUE
+
+# Config PM Control
+DHDCFLAGS += -DCONFIG_CONTROL_PM
+
+# idle count
+DHDCFLAGS += -DDHD_USE_IDLECOUNT
+
+# Wi-Fi Direct
+DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+DHDCFLAGS += -DWL_CFG80211_STA_EVENT
+DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS
+# DHDCFLAGS += -DWL_ENABLE_P2P_IF
+
+# For APSTA virtual interface
+DHDCFLAGS += -DWL_VIRTUAL_APSTA
+
+##########################
+# platform type
+# imx: NXP iMX platform
+##########################
+DHDPLATFORM ?= imx
+ifeq ($(DHDPLATFORM), imx)
+ DHDCFLAGS += -DCONFIG_DTS -DCUSTOMER_IMX
+else
+ # XXX Disable for NXP-iMX platforms
+ # SKB TAILPAD to avoid out of boundary memory access
+ DHDCFLAGS += -DDHDENABLE_TAILPAD
+endif
+
+##########################
+# driver type
+# m: module type driver
+# y: built-in type driver
+##########################
+#DRIVER_TYPE ?= y
+
+ifeq ($(CONFIG_BCMDHD_SDIO), y)
+ DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD
+else
+ DHDCFLAGS += -DNO_SDIO_RESET
+endif
+
+#########################
+# Chip dependent feature
+#########################
+ifneq ($(CONFIG_BCM4354),)
+ DHDCFLAGS += -DBCM4354_CHIP -DHW_OOB
+
+# tput enhancement
+ DHDTXGLOM ?= y
+ MAX_TXGLOM ?= 40
+ DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128
+ DHDCFLAGS += -DDHDTCPACK_SUPPRESS
+ DHDCFLAGS += -DUSE_WL_TXBF
+ DHDCFLAGS += -DUSE_WL_FRAMEBURST
+ DHDCFLAGS += -DRXFRAME_THREAD
+ DHDCFLAGS += -DREPEAT_READFRAME
+ DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64
+ DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0
+# DHDCFLAGS += -DPROP_TXSTATUS_VSDB
+ DHDCFLAGS += -DMAX_HDR_READ=128
+ DHDCFLAGS += -DDHD_FIRSTREAD=128
+ DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16
+
+# New Features
+ DHDCFLAGS += -DWL11U -DPMF
+ DHDCFLAGS += -DDHD_ENABLE_LPC
+ DHDCFLAGS += -DSAR_SUPPORT
+ DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30
+endif
+
+ifneq ($(CONFIG_BCM4339),)
+ DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB
+
+ # tput enhancement
+ DHDTXGLOM ?= y
+ DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128
+ DHDCFLAGS += -DDHDTCPACK_SUPPRESS
+ DHDCFLAGS += -DUSE_WL_TXBF
+ DHDCFLAGS += -DUSE_WL_FRAMEBURST
+ DHDCFLAGS += -DRXFRAME_THREAD
+ DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64
+ DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0
+# DHDCFLAGS += -DPROP_TXSTATUS_VSDB
+
+ # New Features
+ DHDCFLAGS += -DWL11U
+ DHDCFLAGS += -DDHD_ENABLE_LPC
+ DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30
+endif
+
+##########################
+# SDIO TX glomming
+# y: enable
+# n: disable
+##########################
+DHDTXGLOM ?= n
+ifeq ($(DHDTXGLOM), y)
+ MAX_TXGLOM ?= 32
+ DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1
+ DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED
+ DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=$(MAX_TXGLOM)
+endif
+
+# Murata: need the following define to handle BCM43340 edge interrupt (vs level interrupt on other chipsets).
+# Define is in imx_v7_defconfig.
+ifeq ($(CONFIG_BCM43340),)
+ DHDCFLAGS += -DHW_OOB
+endif
+
+ifneq ($(CONFIG_BCMDHD_SDIO),)
+ DHDCFLAGS += -DBDC -DOOB_INTR_ONLY -DDHD_BCMEVENTS -DMMC_SDIO_ABORT -DOOB_PARAM
+ DHDCFLAGS += -DBCMSDIO -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR -DDHD_VERSION_NO_DATE_TIME
+endif
+
+ifneq ($(CONFIG_BCMDHD_PCIE),)
+ DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1
+endif
+
+#EXTRA_LDFLAGS += --strip-debug
+
+EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG
+EXTRA_CFLAGS += -DSRCBASE=\"$(src)\"
+EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/
+KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd)
+
+DHDOFILES := dhd_pno.o dhd_common.o dhd_ip.o dhd_custom_gpio.o \
+ dhd_linux.o dhd_linux_sched.o dhd_cfg80211.o dhd_linux_wq.o aiutils.o bcmevent.o \
+ bcmutils.o bcmwifi_channels.o hndpmu.o linux_osl.o sbutils.o siutils.o \
+ wl_android.o wl_cfg80211.o wl_cfgp2p.o wl_cfg_btcoex.o wldev_common.o wl_linux_mon.o \
+ dhd_linux_platdev.o dhd_pno.o dhd_linux_wq.o wl_cfg_btcoex.o wl_cfgvendor.o
+
+ifneq ($(CONFIG_BCMDHD_SDIO),)
+ DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o
+ DHDOFILES += dhd_cdc.o dhd_wlfc.o dhd_sdio.o
+endif
+
+ifneq ($(CONFIG_BCMDHD_PCIE),)
+ DHDOFILES += dhd_pcie.o dhd_pcie_linux.o dhd_msgbuf.o dhd_log.o circularbuf.o
+endif
+
+bcmdhd-objs := $(DHDOFILES)
+obj-$(CONFIG_BCMDHD_SDIO) += bcmdhd.o
+
+all:
+ @echo "$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules"
+ @$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules
+
+clean:
+ rm -rf *.o *.ko *.mod.c *~ .*.cmd *.o.cmd .*.o.cmd \
+ Module.symvers modules.order .tmp_versions modules.builtin
+
+install:
+ @$(MAKE) --no-print-directory -C $(KDIR) \
+ SUBDIRS=$(CURDIR) modules_install
diff --git a/drivers/net/wireless/bcmdhd/aiutils.c b/drivers/net/wireless/bcmdhd/aiutils.c
new file mode 100644
index 000000000000..85c034b56ba8
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/aiutils.c
@@ -0,0 +1,1012 @@
+/*
+ * Misc utility routines for accessing chip-specific features
+ * of the SiliconBackplane-based Broadcom chips.
+ *
+ * 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: aiutils.c 530682 2015-01-30 18:48:21Z $
+ */
+#include <bcm_cfg.h>
+#include <typedefs.h>
+#include <bcmdefs.h>
+#include <osl.h>
+#include <bcmutils.h>
+#include <siutils.h>
+#include <hndsoc.h>
+#include <sbchipc.h>
+#include <pcicfg.h>
+
+#include "siutils_priv.h"
+
+#define BCM47162_DMP() (0)
+#define BCM5357_DMP() (0)
+#define BCM4707_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;
+
+ 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;
+}
+
+static void
+ai_hwfixup(si_info_t *sii)
+{
+}
+
+
+/* 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;
+
+ 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;
+
+ case SPI_BUS:
+ case SDIO_BUS:
+ eromptr = (uint32 *)(uintptr)erombase;
+ break;
+
+ 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));
+
+ SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n",
+ regs, erombase, eromptr, 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));
+ ai_hwfixup(sii);
+ 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, eromptr - 1, nmw, nsw, nmp, nsp));
+#else
+ BCM_REFERENCE(crev);
+#endif
+
+ if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0))
+ 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)
+ 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;
+ }
+
+ /* 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);
+ 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;
+ }
+
+
+ /* Don't record bridges */
+ if (br)
+ continue;
+
+ /* Done with core */
+ sii->numcores++;
+ }
+
+ SI_ERROR(("Reached end of erom without finding END"));
+
+error:
+ sii->numcores = 0;
+ return;
+}
+
+/* This function changes the logical "focus" to the indicated core.
+ * Return the current core's virtual address.
+ */
+void *
+ai_setcoreidx(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 addr, wrap;
+ void *regs;
+
+ if (coreidx >= MIN(sii->numcores, SI_MAXCORES))
+ return (NULL);
+
+ addr = cores_info->coresba[coreidx];
+ wrap = cores_info->wrapba[coreidx];
+
+ /*
+ * 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, SI_CORE_SIZE);
+ 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]));
+ }
+ sii->curwrap = cores_info->wrappers[coreidx];
+ break;
+
+ case PCI_BUS:
+ /* 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 (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;
+
+ case SPI_BUS:
+ case SDIO_BUS:
+ sii->curmap = regs = (void *)((uintptr)addr);
+ sii->curwrap = (void *)((uintptr)wrap);
+ break;
+
+ case PCMCIA_BUS:
+ default:
+ ASSERT(0);
+ regs = NULL;
+ break;
+ }
+
+ sii->curmap = regs;
+ sii->curidx = coreidx;
+
+ return regs;
+}
+
+
+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)
+{
+ 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 (BCM47162_DMP()) {
+ SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__));
+ return sii->curidx;
+ }
+ 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;
+ }
+ ai = sii->curwrap;
+
+ 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 (BCM47162_DMP()) {
+ SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__));
+ return sii->curidx;
+ }
+ 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;
+ }
+ 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)
+{
+}
+
+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;
+ 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 = (uint32 *)((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 = (uint32 *)((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 = (uint32 *)((char *)sii->curmap +
+ PCI_16KB0_PCIREGS_OFFSET + regoff);
+ else
+ r = (uint32 *)((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 = (uint32*) ((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.
+ */
+uint32 *
+ai_corereg_addr(si_t *sih, uint coreidx, uint regoff)
+{
+ 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 = (uint32 *)((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 = (uint32 *)((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 = (uint32 *)((char *)sii->curmap +
+ PCI_16KB0_PCIREGS_OFFSET + regoff);
+ else
+ r = (uint32 *)((char *)sii->curmap +
+ ((regoff >= SBCONFIGOFF) ?
+ PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) +
+ regoff);
+ }
+ }
+
+ if (!fast)
+ return 0;
+
+ 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
+ */
+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;
+
+ /* 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_cflags_wo(si_t *sih, uint32 mask, uint32 val)
+{
+ si_info_t *sii = SI_INFO(sih);
+ aidmp_t *ai;
+ uint32 w;
+
+
+ if (BCM47162_DMP()) {
+ SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0",
+ __FUNCTION__));
+ return;
+ }
+ 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;
+ }
+
+ 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 (BCM47162_DMP()) {
+ SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0",
+ __FUNCTION__));
+ return 0;
+ }
+ 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;
+ }
+
+ 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 (BCM47162_DMP()) {
+ SI_ERROR(("%s: Accessing MIPS DMP register (iostatus) on 47162a0",
+ __FUNCTION__));
+ return 0;
+ }
+ 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;
+ }
+
+ 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);
+}
diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c
new file mode 100644
index 000000000000..d1f8abe5ff0e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmevent.c
@@ -0,0 +1,242 @@
+/*
+ * bcmevent read-only data shared by kernel or app layers
+ *
+ * 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: bcmevent.c 662961 2016-11-24 01:22:35Z $
+ */
+
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <proto/ethernet.h>
+#include <proto/bcmeth.h>
+#include <proto/bcmevent.h>
+#include <proto/802.11.h>
+
+#if WLC_E_LAST != 165
+#error "You need to add an entry to bcmevent_names[] for the new event"
+#endif
+
+/* Use the actual name for event tracing */
+#define BCMEVENT_NAME(_event) {(_event), #_event}
+
+const bcmevent_name_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_NET_LOST),
+#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),
+#ifdef WIFI_ACT_FRAME
+ BCMEVENT_NAME(WLC_E_ACTION_FRAME),
+ BCMEVENT_NAME(WLC_E_ACTION_FRAME_RX),
+ BCMEVENT_NAME(WLC_E_ACTION_FRAME_COMPLETE),
+#endif
+ 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_ACTION_FRAME_RX_NDIS),
+ 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_TXFAIL_THRESH),
+ BCMEVENT_NAME(WLC_E_RMC_EVENT),
+ BCMEVENT_NAME(WLC_E_PKT_FILTER),
+};
+
+const int bcmevent_names_size = ARRAYSIZE(bcmevent_names);
+
+/*
+ * 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,
+ wl_event_msg_t *out_event)
+{
+ uint16 len;
+ uint16 subtype;
+ uint16 usr_subtype;
+ bcm_event_t *bcm_event;
+ uint8 *pktend;
+ int err = BCME_OK;
+
+ 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 */
+ len = ntoh16_ua((void *)&bcm_event->bcm_hdr.length);
+
+ /* 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);
+ if (usr_subtype == BCMILCP_BCM_SUBTYPE_EVENT) {
+ if (pktlen < sizeof(bcm_event_t)) {
+ err = BCME_BADLEN;
+ goto done;
+ }
+ len = (uint16)sizeof(bcm_event_t) +
+ (uint16)ntoh32_ua((void *)&bcm_event->event.datalen);
+ if ((uint8 *)pktdata + len > pktend) {
+ 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, &bcm_event->event, sizeof(wl_event_msg_t));
+ }
+ }
+ else {
+ err = BCME_NOTFOUND;
+ goto done;
+ }
+
+done:
+ return err;
+}
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh.c b/drivers/net/wireless/bcmdhd/bcmsdh.c
new file mode 100644
index 000000000000..7f4cbcb2fdd7
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmsdh.c
@@ -0,0 +1,705 @@
+/*
+ * BCMSDH interface glue
+ * implement bcmsdh API for SDIOH driver
+ *
+ * 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: bcmsdh.c 455573 2014-02-14 17:49:31Z $
+ */
+
+/**
+ * @file bcmsdh.c
+ */
+
+/* ****************** BCMSDH Interface Functions *************************** */
+
+#include <typedefs.h>
+#include <bcmdevs.h>
+#include <bcmendian.h>
+#include <bcmutils.h>
+#include <hndsoc.h>
+#include <siutils.h>
+#include <osl.h>
+
+#include <bcmsdh.h> /* BRCM API for SDIO clients (such as wl, dhd) */
+#include <bcmsdbus.h> /* common SDIO/controller interface */
+#include <sbsdio.h> /* SDIO device core hardware definitions. */
+#include <sdio.h> /* SDIO Device and Protocol Specs */
+
+#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(OOB_INTR_ONLY) && defined(HW_OOB)
+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
+
+/* 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;
+
+ /* 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;
+ 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;
+ 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;
+}
+
+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));
+}
+
+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
+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, uint32 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, ", __FUNCTION__, addr));
+
+ if (!bcmsdh)
+ bcmsdh = l_bcmsdh;
+
+ ASSERT(bcmsdh->init_success);
+
+ if (bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))
+ 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%04x size %d\n", __FUNCTION__, addr, size));
+ return 0xFFFFFFFF;
+}
+
+uint32
+bcmsdh_reg_write(void *sdh, uint32 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__, addr, size*8, data));
+
+ if (!bcmsdh)
+ bcmsdh = l_bcmsdh;
+
+ ASSERT(bcmsdh->init_success);
+
+ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)))
+ 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, 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);
+}
+
+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);
+}
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
new file mode 100644
index 000000000000..87c00c2f82be
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
@@ -0,0 +1,473 @@
+/*
+ * SDIO access interface for drivers - linux specific (pci only)
+ *
+ * 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: bcmsdh_linux.c 662739 2016-11-08 09:20:31Z $
+ */
+
+/**
+ * @file bcmsdh_linux.c
+ */
+
+#define __UNDEF_NO_VERSION__
+
+#include <typedefs.h>
+#include <linuxver.h>
+#include <linux/pci.h>
+#include <linux/completion.h>
+
+#include <osl.h>
+#include <pcicfg.h>
+#include <bcmdefs.h>
+#include <bcmdevs.h>
+#include <linux/irq.h>
+extern void dhdsdio_isr(void * args);
+#include <bcmutils.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#if defined(CONFIG_ARCH_ODIN)
+#include <linux/platform_data/gpio-odin.h>
+#endif /* defined(CONFIG_ARCH_ODIN) */
+
+#include <dhd_linux.h>
+
+/* 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_MSG(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;
+#ifdef OOB_PARAM
+ wifi_adapter_info_t *adapter = (wifi_adapter_info_t *)adapter_info;
+#endif /* OOB_PARAM */
+
+ bcmsdh = bcmsdh_attach(osh, sdioh, &regs);
+ if (bcmsdh == NULL) {
+ SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
+ goto err;
+ }
+ bcmsdh_osinfo = MALLOC(osh, sizeof(bcmsdh_os_info_t));
+ if (bcmsdh_osinfo == NULL) {
+ SDLX_MSG(("%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)
+ OOB_PARAM_IF(!(adapter->oob_disable)) {
+ 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_MSG(("%s: Host OOB irq is not defined\n", __FUNCTION__));
+ goto err;
+ }
+ }
+#endif /* defined(OOB_INTR_ONLY) */
+
+ /* 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_MSG(("%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;
+}
+
+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_MSG(("%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;
+
+ SDLX_MSG(("%s: Enter\n", __FUNCTION__));
+ if (bcmsdh_osinfo->oob_irq_registered) {
+ SDLX_MSG(("%s: irq is already registered\n", __FUNCTION__));
+ return -EBUSY;
+ }
+ SDLX_MSG(("%s OOB irq=%d flags=%X \n", __FUNCTION__,
+ (int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags));
+ 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_MSG(("%s: request_irq failed with %d\n", __FUNCTION__, err));
+ bcmsdh_osinfo->oob_irq_enabled = FALSE;
+ bcmsdh_osinfo->oob_irq_registered = FALSE;
+ return err;
+ }
+
+ err = enable_irq_wake(bcmsdh_osinfo->oob_irq_num);
+ if (!err)
+ bcmsdh_osinfo->oob_irq_wake_enabled = TRUE;
+ return err;
+}
+
+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);
+
+#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
+
+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/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
new file mode 100644
index 000000000000..bf94aaada44e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
@@ -0,0 +1,1491 @@
+/*
+ * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
+ *
+ * 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: bcmsdh_sdmmc.c 662739 2016-11-08 09:20:31Z $
+ */
+#include <typedefs.h>
+
+#include <bcmdevs.h>
+#include <bcmendian.h>
+#include <bcmutils.h>
+#include <osl.h>
+#include <sdio.h> /* SDIO Device and Protocol Specs */
+#include <sdioh.h> /* Standard SDIO Host Controller Specification */
+#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
+#include <sdiovar.h> /* ioctl/iovars */
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+
+#include <dngl_stats.h>
+#include <dhd.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
+#include <linux/suspend.h>
+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) || defined(OOB_PARAM)
+static void IRQHandler(struct sdio_func *func);
+static void IRQHandlerF2(struct sdio_func *func);
+#endif /* !defined(OOB_INTR_ONLY) || defined(OOB_PARAM) */
+static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr);
+
+#ifdef OOB_PARAM
+extern int sdioh_get_oob_disable(sdioh_info_t *sd);
+#endif /* OOB_PRARM */
+
+#if defined(NO_SDIO_RESET)
+static int sdio_reset_comm(struct mmc_card *card)
+{
+ return 0;
+}
+#else
+extern int sdio_reset_comm(struct mmc_card *card);
+#endif /* NO_SDIO_RESET */
+
+#define DEFAULT_SDIO_F2_BLKSIZE 512
+#ifndef CUSTOM_SDIO_F2_BLKSIZE
+#define CUSTOM_SDIO_F2_BLKSIZE DEFAULT_SDIO_F2_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_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);
+
+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", 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;
+ sd->func[1] = func->card->sdio_func[0];
+ sd->func[2] = func->card->sdio_func[1];
+ 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] = 64;
+ err_ret = sdio_set_block_size(sd->func[1], 64);
+ 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;
+ 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;
+ }
+
+ 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);
+ 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);
+ /* 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) || defined(OOB_PARAM)
+ OOB_PARAM_IF(dhd_get_oob_disable(argh)) {
+ 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]);
+ }
+ } OOB_PARAM_ELSE()
+#endif /* !defined(OOB_INTR_ONLY) || defined(OOB_PARAM) */
+#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
+ {
+ sdioh_enable_func_intr(sd);
+ }
+#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
+
+ 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) || defined(OOB_PARAM)
+ OOB_PARAM_IF(sd->intr_handler_valid) {
+ 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;
+ } OOB_PARAM_ELSE()
+#endif /* !defined(OOB_INTR_ONLY) || defined(OOB_PARAM) */
+#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
+ {
+ sdioh_disable_func_intr(sd);
+ }
+#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
+ 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, IOVT_UINT32, 0 },
+ {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 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 },
+ {"sd_rxchain", IOV_RXCHAIN, 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;
+
+ 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;
+
+ 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):
+ sd_divisor = int_val;
+ 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;
+
+ case IOV_GVAL(IOV_HOSTREG):
+ {
+ sdreg_t *sd_ptr = (sdreg_t *)params;
+
+ if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
+ sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
+ bcmerror = BCME_BADARG;
+ break;
+ }
+
+ sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__,
+ (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
+ sd_ptr->offset));
+ if (sd_ptr->offset & 1)
+ int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */
+ else if (sd_ptr->offset & 2)
+ int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */
+ else
+ int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */
+
+ bcopy(&int_val, arg, sizeof(int_val));
+ break;
+ }
+
+ case IOV_SVAL(IOV_HOSTREG):
+ {
+ sdreg_t *sd_ptr = (sdreg_t *)params;
+
+ if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
+ sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
+ bcmerror = BCME_BADARG;
+ break;
+ }
+
+ sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value,
+ (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
+ sd_ptr->offset));
+ break;
+ }
+
+ case IOV_GVAL(IOV_DEVREG):
+ {
+ sdreg_t *sd_ptr = (sdreg_t *)params;
+ uint8 data = 0;
+
+ 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;
+ }
+
+ default:
+ bcmerror = BCME_UNSUPPORTED;
+ break;
+ }
+exit:
+
+ return bcmerror;
+}
+
+#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
+
+SDIOH_API_RC
+sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
+{
+ SDIOH_API_RC status;
+ uint8 data;
+
+ if (enable)
+ data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI;
+ 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, &regdata)) != 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_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
+
+ 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 (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",
+ 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",
+ err_ret));
+ }
+ }
+ sdio_release_host(sd->func[2]);
+ }
+ }
+#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 */
+ 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));
+ }
+ }
+
+ return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
+}
+
+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;
+#if defined(MMC_SDIO_ABORT)
+ int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT;
+#endif
+
+ 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_ret);
+ sdio_release_host(sd->func[0]);
+ }
+ if (!err_ret)
+ break;
+ }
+ if (err_ret)
+#endif /* MMC_SDIO_ABORT */
+ {
+ sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x",
+ rw ? "Write" : "Read", err_ret));
+ }
+ }
+
+ return ((err_ret == 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;
+
+ 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);
+
+ 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;
+
+ 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\n", __FUNCTION__));
+ 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;
+ }
+ }
+
+ 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;
+
+ sd_trace(("%s: Enter\n", __FUNCTION__));
+ ASSERT(buf);
+
+ /* 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__));
+ 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;
+
+ sd_trace(("%s: Enter\n", __FUNCTION__));
+ DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait);
+ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
+
+ 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_err(("%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);
+
+ 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 {
+ sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize);
+ if (regsize == 2)
+ *data &= 0xffff;
+
+ sd_data(("%s: word read data=0x%08x\n",
+ __FUNCTION__, *data));
+ }
+
+ return SUCCESS;
+}
+
+#if !defined(OOB_INTR_ONLY) || defined(OOB_PARAM)
+/* 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) || defined(OOB_PARAM) */
+
+#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 ((ret = sdio_reset_comm(sd->func[0]->card))) {
+ sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
+ return ret;
+ }
+ else {
+ 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;
+ 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) || defined(OOB_PARAM)
+ OOB_PARAM_IF(sdioh_get_oob_disable(sd)) {
+ 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]);
+ } OOB_PARAM_ELSE()
+#endif /* !defined(OOB_INTR_ONLY) || defined(OOB_PARAM) */
+#if defined(OOB_INTR_ONLY)
+ {
+#if defined(HW_OOB)
+ sdioh_enable_func_intr(sd);
+#endif /* defined(HW_OOB) */
+ 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) || defined(OOB_PARAM)
+ OOB_PARAM_IF(sdioh_get_oob_disable(sd)) {
+ 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]);
+ } OOB_PARAM_ELSE()
+#endif /* !defined(OOB_INTR_ONLY) || defined(OOB_PARAM) */
+#if 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;
+}
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
new file mode 100644
index 000000000000..f4af5d7ab860
--- /dev/null
+++ b/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-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: bcmsdh_sdmmc_linux.c 662758 2016-11-10 08:03:26Z $
+ */
+
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <sdio.h> /* SDIO Device and Protocol Specs */
+#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
+#include <sdiovar.h> /* to get msglevel bit values */
+
+#include <linux/sched.h> /* request_irq() */
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <dhd_linux.h>
+#include <bcmsdh_sdmmc.h>
+#include <dhd_dbg.h>
+
+#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");
+
+/* 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));
+ 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;
+ }
+
+ 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(("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));
+
+ /* 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) },
+ { /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids);
+
+#ifdef OOB_PARAM
+uint
+sdioh_get_oob_disable(sdioh_info_t *sd)
+{
+ int host_idx = sd->func[0]->card->host->index;
+ uint32 rca = sd->func[0]->card->rca;
+ wifi_adapter_info_t *adapter;
+
+ adapter = dhd_wifi_platform_get_adapter(SDIO_BUS, host_idx, rca);
+
+ return adapter->oob_disable;
+}
+#endif /* OOB_PARAM */
+
+#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;
+
+ sd_err(("%s Enter\n", __FUNCTION__));
+ if (func->num != 2)
+ return 0;
+
+ dhd_mmc_suspend = TRUE;
+ sdioh = sdio_get_drvdata(func);
+ err = bcmsdh_suspend(sdioh->bcmsdh);
+ if (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;
+ }
+#if defined(OOB_INTR_ONLY)
+ OOB_PARAM_IF(!(sdioh_get_oob_disable(sdioh))) {
+ bcmsdh_oob_intr_set(sdioh->bcmsdh, FALSE);
+ }
+#endif
+ smp_mb();
+
+ return 0;
+}
+
+static int bcmsdh_sdmmc_resume(struct device *pdev)
+{
+ sdioh_info_t *sdioh;
+ struct sdio_func *func = dev_to_sdio_func(pdev);
+
+ sd_err(("%s Enter\n", __FUNCTION__));
+ if (func->num != 2)
+ return 0;
+
+ sdioh = sdio_get_drvdata(func);
+ dhd_mmc_suspend = FALSE;
+ bcmsdh_resume(sdioh->bcmsdh);
+
+ smp_mb();
+ 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/drivers/net/wireless/bcmdhd/bcmsdspi_linux.c b/drivers/net/wireless/bcmdhd/bcmsdspi_linux.c
new file mode 100644
index 000000000000..8343d3b9586e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmsdspi_linux.c
@@ -0,0 +1,249 @@
+/*
+ * Broadcom SPI Host Controller Driver - Linux Per-port
+ *
+ * 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: bcmsdspi_linux.c 406045 2013-06-05 22:09:52Z $
+ */
+
+#include <typedefs.h>
+#include <bcmutils.h>
+
+#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
+#include <sdiovar.h> /* to get msglevel bit values */
+
+#include <pcicfg.h>
+#include <sdio.h> /* SDIO Device and Protocol Specs */
+#include <linux/sched.h> /* request_irq(), free_irq() */
+#include <bcmsdspi.h>
+#include <bcmspi.h>
+
+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/drivers/net/wireless/bcmdhd/bcmspibrcm.c b/drivers/net/wireless/bcmdhd/bcmspibrcm.c
new file mode 100644
index 000000000000..c3ba9d8eefe7
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmspibrcm.c
@@ -0,0 +1,1814 @@
+/*
+ * Broadcom BCMSDH to gSPI Protocol Conversion 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: bcmspibrcm.c 662541 2016-10-28 03:22:57Z $
+ */
+
+#define HSMODE
+
+#include <typedefs.h>
+
+#include <bcmdevs.h>
+#include <bcmendian.h>
+#include <bcmutils.h>
+#include <osl.h>
+#include <hndsoc.h>
+#include <siutils.h>
+#include <sbchipc.h>
+#include <sbsdio.h> /* SDIO device core hardware definitions. */
+#include <spid.h>
+
+#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
+#include <sdiovar.h> /* ioctl/iovars */
+#include <sdio.h> /* SDIO Device and Protocol Specs */
+
+#include <pcicfg.h>
+
+
+#include <bcmspibrcm.h>
+#include <bcmspi.h>
+
+/* 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
+
+#define DWORDMODE_ON (sd->chip == BCM4329_CHIP_ID) && (sd->chiprev == 2) && (sd->dwordmode == TRUE)
+
+/* 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) || defined(OOB_PARAM)
+ OOB_PARAM_IF(dhd_get_oob_disable(argh)) {
+ sd->intr_handler = fn;
+ sd->intr_handler_arg = argh;
+ sd->intr_handler_valid = TRUE;
+ }
+#endif /* !defined(OOB_INTR_ONLY) || defined(OOB_PARAM) */
+ 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) || defined(OOB_PARAM)
+ OOB_PARAM_IF(sd->intr_handler_valid) {
+ sd->intr_handler_valid = FALSE;
+ sd->intr_handler = NULL;
+ sd->intr_handler_arg = NULL;
+ }
+#endif /* !defined(OOB_INTR_ONLY) || defined(OOB_PARAM) */
+ 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
+
+extern SDIOH_API_RC
+sdioh_query_device(sdioh_info_t *sd)
+{
+ /* Return a BRCM ID appropriate to the dongle class */
+ return (sd->num_funcs > 1) ? BCM4329_D11N_ID : BCM4318_D11G_ID;
+}
+
+/* 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, &reg)) !=
+ 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, &reg)) !=
+ 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, &regdata)) != 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, &regdata); \
+ 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, &regdata); \
+ 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, &regdata);
+ 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, &regdata)) !=
+ 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, &regdata)) != 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,
+ &regdata)) != SUCCESS)
+ return FALSE;
+ }
+ OSL_DELAY(1000);
+ }
+
+ /* Change to host controller intr-polarity of active-low */
+ wrregdata &= ~INTR_POLARITY;
+ 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, &regdata)) != 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, &regdata)) != 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, &regdata)) != 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, &regdata)) != 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));
+
+ if (DWORDMODE_ON) {
+ spilen = GFIELD(cmd_arg, SPI_LEN);
+ if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_0) ||
+ (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_1))
+ dstatus_idx = spilen * 3;
+
+ if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) &&
+ (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) {
+ spilen = spilen << 2;
+ dstatus_idx = (spilen % 16) ? (16 - (spilen % 16)) : 0;
+ /* convert len to mod16 size */
+ spilen = ROUNDUP(spilen, 16);
+ cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2));
+ }
+ }
+
+ /* 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 (DWORDMODE_ON) {
+ if (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) {
+ ptr = (uint16 *)&data[0];
+ templen = *ptr;
+ /* ASSERT(*ptr == ~*(ptr + 1)); */
+ templen = ROUNDUP(templen, 16);
+ *ptr = templen;
+ sd_trace(("actual tx len = %d\n", (uint16)(~*(ptr+1))));
+ }
+ }
+
+ 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]);
+ }
+ }
+
+ if ((DWORDMODE_ON) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) {
+ ptr = (uint16 *)&data[0];
+ templen = *ptr;
+ buslen = len = ~(*(ptr + 1));
+ buslen = ROUNDUP(buslen, 16);
+ /* populate actual len in hw-header */
+ if (templen == buslen)
+ *ptr = len;
+ }
+ }
+ }
+
+ /* Restore back the len field of the hw header */
+ if (DWORDMODE_ON) {
+ if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) &&
+ (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) {
+ ptr = (uint16 *)&data[0];
+ *ptr = (uint16)(~*(ptr+1));
+ }
+ }
+
+ 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/drivers/net/wireless/bcmdhd/bcmutils.c b/drivers/net/wireless/bcmdhd/bcmutils.c
new file mode 100644
index 000000000000..1d5c6a07a00c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmutils.c
@@ -0,0 +1,3084 @@
+/*
+ * Driver O/S-independent utility routines
+ *
+ * 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: bcmutils.c 658506 2016-09-08 06:44:19Z $
+ */
+
+#include <bcm_cfg.h>
+#include <typedefs.h>
+#include <bcmdefs.h>
+#include <stdarg.h>
+#ifdef BCMDRIVER
+
+#include <osl.h>
+#include <bcmutils.h>
+#if defined(BCMNVRAM)
+#include <siutils.h>
+#include <bcmnvram.h>
+#endif
+
+#else /* !BCMDRIVER */
+
+#include <stdio.h>
+#include <string.h>
+#include <bcmutils.h>
+
+#if defined(BCMEXTSUP)
+#include <bcm_osl.h>
+#endif
+
+#ifndef ASSERT
+#define ASSERT(exp)
+#endif
+
+#endif /* !BCMDRIVER */
+
+#include <bcmendian.h>
+#include <bcmdevs.h>
+#include <proto/ethernet.h>
+#include <proto/vlan.h>
+#include <proto/bcmip.h>
+#include <proto/802.1d.h>
+#include <proto/802.11.h>
+
+
+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;
+}
+
+/*
+ * 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;
+
+ 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;
+
+ return p;
+}
+
+void * BCMFASTPATH
+pktq_penq_head(struct pktq *pq, int prec, void *p)
+{
+ struct pktq_prec *q;
+
+ 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;
+
+ return p;
+}
+
+void * BCMFASTPATH
+pktq_pdeq(struct pktq *pq, int prec)
+{
+ struct pktq_prec *q;
+ void *p;
+
+ ASSERT(prec >= 0 && prec < pq->num_prec);
+
+ q = &pq->q[prec];
+
+ if ((p = q->head) == NULL)
+ return NULL;
+
+ if ((q->head = PKTLINK(p)) == NULL)
+ q->tail = NULL;
+
+ q->len--;
+
+ pq->len--;
+
+ PKTSETLINK(p, NULL);
+
+ return p;
+}
+
+void * BCMFASTPATH
+pktq_pdeq_prev(struct pktq *pq, int prec, void *prev_p)
+{
+ struct pktq_prec *q;
+ void *p;
+
+ ASSERT(prec >= 0 && prec < pq->num_prec);
+
+ q = &pq->q[prec];
+
+ if (prev_p == NULL)
+ return NULL;
+
+ if ((p = PKTLINK(prev_p)) == NULL)
+ return NULL;
+
+ q->len--;
+
+ pq->len--;
+
+ PKTSETLINK(prev_p, PKTLINK(p));
+ PKTSETLINK(p, 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;
+
+ 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;
+
+ 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;
+}
+
+void * BCMFASTPATH
+pktq_pdeq_tail(struct pktq *pq, int prec)
+{
+ struct pktq_prec *q;
+ void *p, *prev;
+
+ ASSERT(prec >= 0 && prec < pq->num_prec);
+
+ q = &pq->q[prec];
+
+ if ((p = q->head) == NULL)
+ return NULL;
+
+ 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--;
+
+ return p;
+}
+
+void
+pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg)
+{
+ struct pktq_prec *q;
+ void *p, *prev = NULL;
+
+ q = &pq->q[prec];
+ p = q->head;
+ while (p) {
+ if (fn == NULL || (*fn)(p, arg)) {
+ bool head = (p == q->head);
+ if (head)
+ q->head = PKTLINK(p);
+ else
+ PKTSETLINK(prev, PKTLINK(p));
+ PKTSETLINK(p, NULL);
+ PKTFREE(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;
+ }
+}
+
+bool BCMFASTPATH
+pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
+{
+ struct pktq_prec *q;
+ void *p;
+
+ ASSERT(prec >= 0 && prec < pq->num_prec);
+
+ if (!pktbuf)
+ return FALSE;
+
+ 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)
+ return FALSE;
+
+ PKTSETLINK(p, PKTLINK(pktbuf));
+ if (q->tail == pktbuf)
+ q->tail = p;
+ }
+
+ q->len--;
+ pq->len--;
+ PKTSETLINK(pktbuf, NULL);
+ return TRUE;
+}
+
+void
+pktq_init(struct pktq *pq, int num_prec, int max_len)
+{
+ int prec;
+
+ 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;
+}
+
+void
+pktq_set_max_plen(struct pktq *pq, int prec, int max_len)
+{
+ ASSERT(prec >= 0 && prec < pq->num_prec);
+
+ if (prec < pq->num_prec)
+ pq->q[prec].max = (uint16)max_len;
+}
+
+void * BCMFASTPATH
+pktq_deq(struct pktq *pq, int *prec_out)
+{
+ struct pktq_prec *q;
+ void *p;
+ int prec;
+
+ if (pq->len == 0)
+ return NULL;
+
+ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
+ pq->hi_prec--;
+
+ q = &pq->q[prec];
+
+ if ((p = q->head) == NULL)
+ return NULL;
+
+ if ((q->head = PKTLINK(p)) == NULL)
+ q->tail = NULL;
+
+ q->len--;
+
+ pq->len--;
+
+ if (prec_out)
+ *prec_out = prec;
+
+ PKTSETLINK(p, NULL);
+
+ return p;
+}
+
+void * BCMFASTPATH
+pktq_deq_tail(struct pktq *pq, int *prec_out)
+{
+ struct pktq_prec *q;
+ void *p, *prev;
+ int prec;
+
+ if (pq->len == 0)
+ return NULL;
+
+ for (prec = 0; prec < pq->hi_prec; prec++)
+ if (pq->q[prec].head)
+ break;
+
+ q = &pq->q[prec];
+
+ if ((p = q->head) == NULL)
+ return NULL;
+
+ 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);
+
+ return p;
+}
+
+void *
+pktq_peek(struct pktq *pq, int *prec_out)
+{
+ int prec;
+
+ if (pq->len == 0)
+ return NULL;
+
+ while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
+ pq->hi_prec--;
+
+ if (prec_out)
+ *prec_out = prec;
+
+ return (pq->q[prec].head);
+}
+
+void *
+pktq_peek_tail(struct pktq *pq, int *prec_out)
+{
+ int prec;
+
+ if (pq->len == 0)
+ return NULL;
+
+ for (prec = 0; prec < pq->hi_prec; prec++)
+ if (pq->q[prec].head)
+ break;
+
+ if (prec_out)
+ *prec_out = prec;
+
+ return (pq->q[prec].tail);
+}
+
+void
+pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
+{
+ int prec;
+
+ /* 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++)
+ pktq_pflush(osh, pq, prec, dir, fn, arg);
+ if (fn == NULL)
+ ASSERT(pq->len == 0);
+}
+
+/* Return sum of lengths of a specific set of precedences */
+int
+pktq_mlen(struct pktq *pq, uint prec_bmp)
+{
+ int prec, len;
+
+ len = 0;
+
+ for (prec = 0; prec <= pq->hi_prec; prec++)
+ if (prec_bmp & (1 << prec))
+ len += pq->q[prec].len;
+
+ 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;
+ int prec;
+
+ if (pq->len == 0)
+ {
+ return NULL;
+ }
+ 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)
+ return NULL;
+
+ q = &pq->q[prec];
+
+ if ((p = q->head) == NULL)
+ return NULL;
+
+ if (prec_out)
+ *prec_out = prec;
+
+ 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;
+ int prec;
+
+ if (pq->len == 0)
+ return NULL;
+
+ 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)
+ return NULL;
+
+ q = &pq->q[prec];
+
+ if ((p = q->head) == NULL)
+ return NULL;
+
+ if ((q->head = PKTLINK(p)) == NULL)
+ q->tail = NULL;
+
+ q->len--;
+
+ if (prec_out)
+ *prec_out = prec;
+
+ pq->len--;
+
+ PKTSETLINK(p, NULL);
+
+ 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)
+ 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 = strlen(needle);
+ len = 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 *
+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)) {
+ 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;
+ }
+ } else if (eh->ether_type == hton16(ETHER_TYPE_IP)) {
+ 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);
+}
+
+
+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 */
+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;
+
+ /* 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 */
+
+
+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;
+}
+
+/*
+ * 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, 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, " %04d: ", 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",
+ "WAPI",
+ "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 = 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(char *name, char *data, uint datalen, char *buf, uint buflen)
+{
+ uint len;
+
+ len = strlen(name) + 1;
+
+ if ((len + datalen) > buflen)
+ return 0;
+
+ strncpy(buf, name, buflen);
+
+ /* append data onto the end of the name string */
+ if (data) {
+ 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;
+}
+
+#ifdef BCMDRIVER
+
+/* 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);
+
+ /* 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;
+ }
+
+ va_end(ap);
+
+ return r;
+}
+
+void
+bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, 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 */
+
+/*
+ * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
+ * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\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;
+
+ dp = varbuf;
+
+ findNewline = FALSE;
+ column = 0;
+
+ for (n = 0; n < len; n++) {
+ if (varbuf[n] == '\r')
+ continue;
+ if (findNewline && varbuf[n] != '\n')
+ continue;
+ findNewline = FALSE;
+ if (varbuf[n] == '#') {
+ findNewline = TRUE;
+ continue;
+ }
+ if (varbuf[n] == '\n') {
+ if (column == 0)
+ continue;
+ *dp++ = 0;
+ column = 0;
+ continue;
+ }
+ *dp++ = varbuf[n];
+ column++;
+ }
+ buf_len = (unsigned int)(dp - varbuf);
+ if (buf_len % 4) {
+ pad = 4 - buf_len % 4;
+ if (pad && (buf_len + pad <= len)) {
+ buf_len += pad;
+ }
+ }
+
+ while (dp < varbuf + n)
+ *dp++ = 0;
+
+ return buf_len;
+}
+
+/* calculate a * b + c */
+void
+bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c)
+{
+#define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;}
+ uint32 r1, r0;
+ uint32 a1, a0, b1, b0, t, cc = 0;
+
+ a1 = a >> 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
+bcm_bitprint32(const uint32 u32)
+{
+ int i;
+ for (i = NBITS(uint32) - 1; i >= 0; i--) {
+ isbitset(u32, i) ? printf("1") : printf("0");
+ if ((i % NBBY) == 0) printf(" ");
+ }
+ printf("\n");
+}
+
+#ifdef BCMDRIVER
+/*
+ * 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 (4 * 1024) /* May increase to 16K */
+
+#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 */
+ int16 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 = (int16)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
+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
+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(free_cnt == mwbmap_p->ifree);
+}
+/* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */
+
+#endif /* BCMDRIVER */
+
+/* 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) --;
+}
+
+#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 */
diff --git a/drivers/net/wireless/bcmdhd/bcmwifi_channels.c b/drivers/net/wireless/bcmdhd/bcmwifi_channels.c
new file mode 100644
index 000000000000..0aba9deaa329
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmwifi_channels.c
@@ -0,0 +1,1206 @@
+/*
+ * 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-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: bcmwifi_channels.c 309193 2012-01-19 00:03:57Z $
+ */
+
+#include <bcm_cfg.h>
+#include <typedefs.h>
+#include <bcmutils.h>
+
+#ifdef BCMDRIVER
+#include <osl.h>
+#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
+#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifndef ASSERT
+#define ASSERT(exp)
+#endif
+#endif /* BCMDRIVER */
+
+#include <bcmwifi_channels.h>
+
+#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
+#include <bcmstdlib.h> /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */
+#endif
+
+/* Definitions for D11AC capable Chanspec type */
+
+/* Chanspec ASCII representation with 802.11ac capability:
+ * [<band> 'g'] <channel> ['/'<bandwidth> [<ctl-sideband>]['/'<1st80channel>'-'<2nd80channel>]]
+ *
+ * <band>:
+ * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively.
+ * Default value is 2g if channel <= 14, otherwise 5g.
+ * <channel>:
+ * channel number of the 5MHz, 10MHz, 20MHz channel,
+ * or primary channel of 40MHz, 80MHz, 160MHz, or 80+80MHz channel.
+ * <bandwidth>:
+ * (optional) 5, 10, 20, 40, 80, 160, or 80+80. Default value is 20.
+ * <primary-sideband>:
+ * (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: <channel><ctl-sideband>
+ *
+ * <channel>:
+ * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz
+ * <ctl-sideband>:
+ * "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",
+ "na"
+};
+
+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))
+
+
+/* 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;
+}
+
+/* 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 == 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 <band>g<chan>/<bw>
+ * Can now be followed by u/l if bw = 40,
+ * or '+80' if bw = 80, to make '80+80' 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 */
+ static 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++) {
+ 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;
+ }
+
+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 (chspec_bw == WL_CHANSPEC_BW_20) {
+ 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;
+
+ ch1_id = channel_80mhz_to_id(ch1);
+ ch2_id = channel_80mhz_to_id(ch2);
+
+ /* validate channels */
+ if (ch1 >= ch2 || ch1_id < 0 || ch2_id < 0)
+ return 0;
+
+ /* combined channel in chspec */
+ chspec_ch = (((uint16)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) |
+ ((uint16)ch2_id << WL_CHANSPEC_CHAN2_SHIFT));
+
+ /* figure out ctl sideband */
+
+ /* does the primary channel fit with the 1st 80MHz channel ? */
+ sb = channel_to_sb(ch1, ctl_ch, bw);
+ if (sb < 0) {
+ /* no, so does the primary channel fit with the 2nd 80MHz channel ? */
+ sb = channel_to_sb(ch2, ctl_ch, bw);
+ if (sb < 0) {
+ /* no match for ctl_ch to either 80MHz center channel */
+ return 0;
+ }
+ /* sb index is 0-3 for the low 80MHz channel, and 4-7 for
+ * the high 80MHz channel. Add 4 to to shift to high set.
+ */
+ sb += 4;
+ }
+
+ 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 (chspec_bw != WL_CHANSPEC_BW_20 &&
+ chspec_bw != WL_CHANSPEC_BW_40) {
+ return TRUE;
+ }
+ } else if (CHSPEC_IS5G(chanspec)) {
+ if (chspec_bw == WL_CHANSPEC_BW_8080) {
+ uint ch1_id, ch2_id;
+
+ /* channel number 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;
+
+ /* ch2 must be above ch1 for the chanspec */
+ if (ch2_id <= ch1_id)
+ return TRUE;
+ } else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 ||
+ chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) {
+
+ 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 (chspec_bw == WL_CHANSPEC_BW_20) {
+ 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) {
+ if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU)
+ return TRUE;
+ }
+
+ 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 (chspec_bw == WL_CHANSPEC_BW_20) {
+ 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,
+ * and ch2 above ch1 for the chanspec
+ */
+ if (ch2 > ch1 + CH_80MHZ_APART)
+ return TRUE;
+ } else {
+ const uint8 *center_ch;
+ uint num_ch, i;
+
+ if (chspec_bw == WL_CHANSPEC_BW_20 || 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 {
+ /* invalid bandwidth */
+ return FALSE;
+ }
+
+ /* check for a valid center channel */
+ if (chspec_bw == WL_CHANSPEC_BW_20) {
+ /* 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_IS20(chspec)) {
+ return CHSPEC_CHANNEL(chspec);
+ } else {
+ sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT;
+
+ if (CHSPEC_IS8080(chspec)) {
+ bw_mhz = 80;
+
+ if (sb < 4) {
+ center_chan = CHSPEC_CHAN1(chspec);
+ }
+ else {
+ center_chan = CHSPEC_CHAN2(chspec);
+ sb -= 4;
+ }
+
+ /* convert from channel index to channel number */
+ center_chan = wf_5g_80m_chans[center_chan];
+ }
+ 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 */
+char *
+wf_chspec_to_bw_str(chanspec_t chspec)
+{
+ return (char *)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_IS20(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 == WL_CHANSPEC_BW_20) {
+ 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 (CHSPEC_IS80(chspec)) {
+ center_chan = CHSPEC_CHANNEL(chspec);
+ sb = CHSPEC_CTL_SB(chspec);
+
+ if (sb == WL_CHANSPEC_CTL_SB_UL) {
+ /* Primary 40MHz is on upper side */
+ sb = WL_CHANSPEC_CTL_SB_L;
+ center_chan += CH_20MHZ_APART;
+ } else if (sb == WL_CHANSPEC_CTL_SB_UU) {
+ /* Primary 40MHz is on upper side */
+ sb = WL_CHANSPEC_CTL_SB_U;
+ center_chan += CH_20MHZ_APART;
+ } else {
+ /* Primary 40MHz is on lower side */
+ /* sideband bits are the same for LL/LU and L/U */
+ center_chan -= CH_20MHZ_APART;
+ }
+
+ /* 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;
+}
+
+/*
+ * Returns the 80+80 chanspec corresponding to the following input parameters
+ *
+ * primary_20mhz - Primary 20 Mhz channel
+ * chan1 - channel number of first 80 Mhz band
+ * chan2 - channel number of second 80 Mhz band
+ *
+ * parameters chan1 and chan2 are channel numbers in {42, 58, 106, 122, 138, 155}
+ *
+ * returns INVCHANSPEC in case of error
+ */
+
+chanspec_t
+wf_chspec_get8080_chspec(uint8 primary_20mhz, uint8 chan1, uint8 chan2)
+{
+ int sb = 0;
+ uint16 chanspec = 0;
+ int chan1_id = 0, chan2_id = 0;
+
+ /* does the primary channel fit with the 1st 80MHz channel ? */
+ sb = channel_to_sb(chan1, primary_20mhz, 80);
+ if (sb < 0) {
+ /* no, so does the primary channel fit with the 2nd 80MHz channel ? */
+ sb = channel_to_sb(chan2, primary_20mhz, 80);
+ if (sb < 0) {
+ /* no match for ctl_ch to either 80MHz center channel */
+ return INVCHANSPEC;
+ }
+ /* sb index is 0-3 for the low 80MHz channel, and 4-7 for
+ * the high 80MHz channel. Add 4 to to shift to high set.
+ */
+ sb += 4;
+ }
+ chan1_id = channel_80mhz_to_id(chan1);
+ chan2_id = channel_80mhz_to_id(chan2);
+ if (chan1_id == -1 || chan2_id == -1)
+ return INVCHANSPEC;
+
+ chanspec = (chan1_id << WL_CHANSPEC_CHAN1_SHIFT)|
+ (chan2_id << 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 chan1 = 0, chan2 = 0, primary_20mhz = 0, primary80_chan = 0;
+ int sb = 0;
+
+ primary_20mhz = wf_chspec_ctlchan(chanspec);
+
+ if (CHSPEC_IS80(chanspec)) {
+ primary80_chan = CHSPEC_CHANNEL(chanspec);
+ }
+ else if (CHSPEC_IS8080(chanspec)) {
+ chan1 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec));
+ chan2 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec));
+
+ /* does the primary channel fit with the 1st 80MHz channel ? */
+ sb = channel_to_sb(chan1, primary_20mhz, 80);
+ if (sb < 0) {
+ /* no, so does the primary channel fit with the 2nd 80MHz channel ? */
+ sb = channel_to_sb(chan2, primary_20mhz, 80);
+ if (!(sb < 0)) {
+ primary80_chan = chan2;
+ }
+ }
+ else {
+ primary80_chan = chan1;
+ }
+ }
+ else if (CHSPEC_IS160(chanspec)) {
+ chan1 = CHSPEC_CHANNEL(chanspec);
+ sb = channel_to_sb(chan1, primary_20mhz, 160);
+ if (!(sb < 0)) {
+ /* 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 = chan1 - CH_40MHZ_APART;
+ }
+ /* if sb is in range 4 to 7 the lower band is the 80Mhz primary band */
+ else
+ {
+ primary80_chan = chan1 + 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 Mhz chanspec
+ */
+uint8
+wf_chspec_secondary80_channel(chanspec_t chanspec)
+{
+ uint8 chan1 = 0, chan2 = 0, primary_20mhz = 0, secondary80_chan = 0;
+ int sb = 0;
+
+ primary_20mhz = wf_chspec_ctlchan(chanspec);
+ if (CHSPEC_IS80(chanspec)) {
+ secondary80_chan = -1;
+ }
+ else if (CHSPEC_IS8080(chanspec)) {
+ chan1 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec));
+ chan2 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec));
+
+ /* does the primary channel fit with the 1st 80MHz channel ? */
+ sb = channel_to_sb(chan1, primary_20mhz, 80);
+ if (sb < 0) {
+ /* no, so does the primary channel fit with the 2nd 80MHz channel ? */
+ sb = channel_to_sb(chan2, primary_20mhz, 80);
+ if (!(sb < 0)) {
+ secondary80_chan = chan1;
+ }
+ }
+ else {
+ secondary80_chan = chan2;
+ }
+ }
+ else if (CHSPEC_IS160(chanspec)) {
+ chan1 = CHSPEC_CHANNEL(chanspec);
+ sb = channel_to_sb(chan1, primary_20mhz, 160);
+ if (!(sb < 0)) {
+ /* 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 = chan1 + CH_40MHZ_APART;
+ }
+ /* if sb is in range 4 to 7 the lower band is the secondary 80Mhz band */
+ else
+ {
+ secondary80_chan = chan1 - CH_40MHZ_APART;
+ }
+ }
+ }
+ else {
+ /* for 20 and 40 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 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, chan1 = 0, chan2 = 0;
+ uint sb;
+
+ ASSERT(!wf_chspec_malformed(chspec));
+ if (CHSPEC_IS8080(chspec)) {
+ chan1 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec));
+ chan2 = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chspec));
+
+ sb = CHSPEC_CTL_SB(chspec);
+
+ if (sb < 4) {
+ /* Primary 80MHz is on lower side */
+ center_chan = chan1;
+ }
+ else
+ {
+ /* Primary 80MHz is on upper side */
+ center_chan = chan2;
+ sb -= 4;
+ }
+ /* 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 < 4) {
+ /* Primary 80MHz is on upper side */
+ center_chan -= CH_40MHZ_APART;
+ }
+ else
+ {
+ /* Primary 80MHz is on lower side */
+ center_chan += CH_40MHZ_APART;
+ sb -= 4;
+ }
+ /* Create primary 80MHz chanspec */
+ chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan);
+ }
+ else
+ {
+ chspec80 = INVCHANSPEC;
+ }
+ return chspec80;
+}
diff --git a/drivers/net/wireless/bcmdhd/bcmwifi_channels.h b/drivers/net/wireless/bcmdhd/bcmwifi_channels.h
new file mode 100644
index 000000000000..0fbe5052b42a
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmwifi_channels.h
@@ -0,0 +1,495 @@
+/*
+ * 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-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: bcmwifi_channels.h 309193 2012-01-19 00:03:57Z $
+ */
+
+#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 */
+#define MAXCHANNEL 224 /* max # supported channels. The max channel no is 216,
+ * this is that + 1 rounded up to a multiple of NBBY (8).
+ * DO NOT MAKE it > 255: channels are uint8's all over
+ */
+#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_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
+
+/* 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 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)
+
+/* simple MACROs to get different fields of chanspec */
+#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK))
+#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
+
+#define CHSPEC_IS10(chspec) 0
+#define CHSPEC_IS20(chspec) 1
+#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
+
+#else /* !WL11N_20MHZONLY */
+
+#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10)
+#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20)
+#ifndef CHSPEC_IS40
+#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)
+#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
+
+#endif /* !WL11N_20MHZONLY */
+
+#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G)
+#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G)
+#define CHSPEC_SB_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.
+*/
+#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))
+
+#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))
+
+#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))
+
+#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))
+
+/* 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 */
+
+/**
+ * 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
+ *
+ * @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 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);
+
+/**
+ * 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 chanspec corresponding to the following input parameters
+ *
+ * primary_20mhz - Primary 20 Mhz channel
+ * chan1 - channel number of first 80 Mhz band
+ * chan2 - channel number of second 80 Mhz band
+ *
+ * parameters chan1 and chan2 are channel numbers in {42, 58, 106, 122, 138, 155}
+ *
+ * returns INVCHANSPEC in case of error
+ */
+
+extern chanspec_t wf_chspec_get8080_chspec(uint8 primary_20mhz,
+uint8 chan1_80Mhz, uint8 chan2_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);
+
+
+#endif /* _bcmwifi_channels_h_ */
diff --git a/drivers/net/wireless/bcmdhd/bcmwifi_rates.h b/drivers/net/wireless/bcmdhd/bcmwifi_rates.h
new file mode 100644
index 000000000000..707cf44a6510
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmwifi_rates.h
@@ -0,0 +1,458 @@
+/*
+ * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates
+ *
+ * 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: bcmwifi_rates.h 5187 2012-06-29 06:17:50Z $
+ */
+
+#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_HT_MCS 8
+#define WL_RATESET_SZ_VHT_MCS 10
+
+#define WL_TX_CHAINS_MAX 3
+
+#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_160,
+ WL_TX_BW_20IN40,
+ WL_TX_BW_20IN80,
+ WL_TX_BW_40IN80,
+ WL_TX_BW_20IN160,
+ WL_TX_BW_40IN160,
+ WL_TX_BW_80IN160,
+ WL_TX_BW_ALL
+} 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_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_t;
+
+
+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_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,
+
+
+ /************
+ * 2 chains *
+ ************
+ */
+
+ /* 1 Stream expanded + 1 */
+ WL_RATE_1X2_DSSS_1 = 22,
+ WL_RATE_1X2_DSSS_2 = 23,
+ WL_RATE_1X2_DSSS_5_5 = 24,
+ WL_RATE_1X2_DSSS_11 = 25,
+
+ WL_RATE_1X2_CDD_OFDM_6 = 26,
+ WL_RATE_1X2_CDD_OFDM_9 = 27,
+ WL_RATE_1X2_CDD_OFDM_12 = 28,
+ WL_RATE_1X2_CDD_OFDM_18 = 29,
+ WL_RATE_1X2_CDD_OFDM_24 = 30,
+ WL_RATE_1X2_CDD_OFDM_36 = 31,
+ WL_RATE_1X2_CDD_OFDM_48 = 32,
+ WL_RATE_1X2_CDD_OFDM_54 = 33,
+
+ WL_RATE_1X2_CDD_MCS0 = 34,
+ WL_RATE_1X2_CDD_MCS1 = 35,
+ WL_RATE_1X2_CDD_MCS2 = 36,
+ WL_RATE_1X2_CDD_MCS3 = 37,
+ WL_RATE_1X2_CDD_MCS4 = 38,
+ WL_RATE_1X2_CDD_MCS5 = 39,
+ WL_RATE_1X2_CDD_MCS6 = 40,
+ WL_RATE_1X2_CDD_MCS7 = 41,
+
+ WL_RATE_1X2_VHT0SS1 = 34,
+ WL_RATE_1X2_VHT1SS1 = 35,
+ WL_RATE_1X2_VHT2SS1 = 36,
+ WL_RATE_1X2_VHT3SS1 = 37,
+ WL_RATE_1X2_VHT4SS1 = 38,
+ WL_RATE_1X2_VHT5SS1 = 39,
+ WL_RATE_1X2_VHT6SS1 = 40,
+ WL_RATE_1X2_VHT7SS1 = 41,
+ WL_RATE_1X2_VHT8SS1 = 42,
+ WL_RATE_1X2_VHT9SS1 = 43,
+
+ /* 2 Streams */
+ WL_RATE_2X2_STBC_MCS0 = 44,
+ WL_RATE_2X2_STBC_MCS1 = 45,
+ WL_RATE_2X2_STBC_MCS2 = 46,
+ WL_RATE_2X2_STBC_MCS3 = 47,
+ WL_RATE_2X2_STBC_MCS4 = 48,
+ WL_RATE_2X2_STBC_MCS5 = 49,
+ WL_RATE_2X2_STBC_MCS6 = 50,
+ WL_RATE_2X2_STBC_MCS7 = 51,
+
+ WL_RATE_2X2_STBC_VHT0SS1 = 44,
+ WL_RATE_2X2_STBC_VHT1SS1 = 45,
+ WL_RATE_2X2_STBC_VHT2SS1 = 46,
+ WL_RATE_2X2_STBC_VHT3SS1 = 47,
+ WL_RATE_2X2_STBC_VHT4SS1 = 48,
+ WL_RATE_2X2_STBC_VHT5SS1 = 49,
+ WL_RATE_2X2_STBC_VHT6SS1 = 50,
+ WL_RATE_2X2_STBC_VHT7SS1 = 51,
+ WL_RATE_2X2_STBC_VHT8SS1 = 52,
+ WL_RATE_2X2_STBC_VHT9SS1 = 53,
+
+ WL_RATE_2X2_SDM_MCS8 = 54,
+ WL_RATE_2X2_SDM_MCS9 = 55,
+ WL_RATE_2X2_SDM_MCS10 = 56,
+ WL_RATE_2X2_SDM_MCS11 = 57,
+ WL_RATE_2X2_SDM_MCS12 = 58,
+ WL_RATE_2X2_SDM_MCS13 = 59,
+ WL_RATE_2X2_SDM_MCS14 = 60,
+ WL_RATE_2X2_SDM_MCS15 = 61,
+
+ WL_RATE_2X2_VHT0SS2 = 54,
+ WL_RATE_2X2_VHT1SS2 = 55,
+ WL_RATE_2X2_VHT2SS2 = 56,
+ WL_RATE_2X2_VHT3SS2 = 57,
+ WL_RATE_2X2_VHT4SS2 = 58,
+ WL_RATE_2X2_VHT5SS2 = 59,
+ WL_RATE_2X2_VHT6SS2 = 60,
+ WL_RATE_2X2_VHT7SS2 = 61,
+ WL_RATE_2X2_VHT8SS2 = 62,
+ WL_RATE_2X2_VHT9SS2 = 63,
+
+ /************
+ * 3 chains *
+ ************
+ */
+
+ /* 1 Stream expanded + 2 */
+ WL_RATE_1X3_DSSS_1 = 64,
+ WL_RATE_1X3_DSSS_2 = 65,
+ WL_RATE_1X3_DSSS_5_5 = 66,
+ WL_RATE_1X3_DSSS_11 = 67,
+
+ WL_RATE_1X3_CDD_OFDM_6 = 68,
+ WL_RATE_1X3_CDD_OFDM_9 = 69,
+ WL_RATE_1X3_CDD_OFDM_12 = 70,
+ WL_RATE_1X3_CDD_OFDM_18 = 71,
+ WL_RATE_1X3_CDD_OFDM_24 = 72,
+ WL_RATE_1X3_CDD_OFDM_36 = 73,
+ WL_RATE_1X3_CDD_OFDM_48 = 74,
+ WL_RATE_1X3_CDD_OFDM_54 = 75,
+
+ WL_RATE_1X3_CDD_MCS0 = 76,
+ WL_RATE_1X3_CDD_MCS1 = 77,
+ WL_RATE_1X3_CDD_MCS2 = 78,
+ WL_RATE_1X3_CDD_MCS3 = 79,
+ WL_RATE_1X3_CDD_MCS4 = 80,
+ WL_RATE_1X3_CDD_MCS5 = 81,
+ WL_RATE_1X3_CDD_MCS6 = 82,
+ WL_RATE_1X3_CDD_MCS7 = 83,
+
+ WL_RATE_1X3_VHT0SS1 = 76,
+ WL_RATE_1X3_VHT1SS1 = 77,
+ WL_RATE_1X3_VHT2SS1 = 78,
+ WL_RATE_1X3_VHT3SS1 = 79,
+ WL_RATE_1X3_VHT4SS1 = 80,
+ WL_RATE_1X3_VHT5SS1 = 81,
+ WL_RATE_1X3_VHT6SS1 = 82,
+ WL_RATE_1X3_VHT7SS1 = 83,
+ WL_RATE_1X3_VHT8SS1 = 84,
+ WL_RATE_1X3_VHT9SS1 = 85,
+
+ /* 2 Streams expanded + 1 */
+ WL_RATE_2X3_STBC_MCS0 = 86,
+ WL_RATE_2X3_STBC_MCS1 = 87,
+ WL_RATE_2X3_STBC_MCS2 = 88,
+ WL_RATE_2X3_STBC_MCS3 = 89,
+ WL_RATE_2X3_STBC_MCS4 = 90,
+ WL_RATE_2X3_STBC_MCS5 = 91,
+ WL_RATE_2X3_STBC_MCS6 = 92,
+ WL_RATE_2X3_STBC_MCS7 = 93,
+
+ WL_RATE_2X3_STBC_VHT0SS1 = 86,
+ WL_RATE_2X3_STBC_VHT1SS1 = 87,
+ WL_RATE_2X3_STBC_VHT2SS1 = 88,
+ WL_RATE_2X3_STBC_VHT3SS1 = 89,
+ WL_RATE_2X3_STBC_VHT4SS1 = 90,
+ WL_RATE_2X3_STBC_VHT5SS1 = 91,
+ WL_RATE_2X3_STBC_VHT6SS1 = 92,
+ WL_RATE_2X3_STBC_VHT7SS1 = 93,
+ WL_RATE_2X3_STBC_VHT8SS1 = 94,
+ WL_RATE_2X3_STBC_VHT9SS1 = 95,
+
+ WL_RATE_2X3_SDM_MCS8 = 96,
+ WL_RATE_2X3_SDM_MCS9 = 97,
+ WL_RATE_2X3_SDM_MCS10 = 98,
+ WL_RATE_2X3_SDM_MCS11 = 99,
+ WL_RATE_2X3_SDM_MCS12 = 100,
+ WL_RATE_2X3_SDM_MCS13 = 101,
+ WL_RATE_2X3_SDM_MCS14 = 102,
+ WL_RATE_2X3_SDM_MCS15 = 103,
+
+ WL_RATE_2X3_VHT0SS2 = 96,
+ WL_RATE_2X3_VHT1SS2 = 97,
+ WL_RATE_2X3_VHT2SS2 = 98,
+ WL_RATE_2X3_VHT3SS2 = 99,
+ WL_RATE_2X3_VHT4SS2 = 100,
+ WL_RATE_2X3_VHT5SS2 = 101,
+ WL_RATE_2X3_VHT6SS2 = 102,
+ WL_RATE_2X3_VHT7SS2 = 103,
+ WL_RATE_2X3_VHT8SS2 = 104,
+ WL_RATE_2X3_VHT9SS2 = 105,
+
+ /* 3 Streams */
+ WL_RATE_3X3_SDM_MCS16 = 106,
+ WL_RATE_3X3_SDM_MCS17 = 107,
+ WL_RATE_3X3_SDM_MCS18 = 108,
+ WL_RATE_3X3_SDM_MCS19 = 109,
+ WL_RATE_3X3_SDM_MCS20 = 110,
+ WL_RATE_3X3_SDM_MCS21 = 111,
+ WL_RATE_3X3_SDM_MCS22 = 112,
+ WL_RATE_3X3_SDM_MCS23 = 113,
+
+ WL_RATE_3X3_VHT0SS3 = 106,
+ WL_RATE_3X3_VHT1SS3 = 107,
+ WL_RATE_3X3_VHT2SS3 = 108,
+ WL_RATE_3X3_VHT3SS3 = 109,
+ WL_RATE_3X3_VHT4SS3 = 110,
+ WL_RATE_3X3_VHT5SS3 = 111,
+ WL_RATE_3X3_VHT6SS3 = 112,
+ WL_RATE_3X3_VHT7SS3 = 113,
+ WL_RATE_3X3_VHT8SS3 = 114,
+ WL_RATE_3X3_VHT9SS3 = 115,
+
+
+ /****************************
+ * TX Beamforming, 2 chains *
+ ****************************
+ */
+
+ /* 1 Stream expanded + 1 */
+
+ WL_RATE_1X2_TXBF_OFDM_6 = 116,
+ WL_RATE_1X2_TXBF_OFDM_9 = 117,
+ WL_RATE_1X2_TXBF_OFDM_12 = 118,
+ WL_RATE_1X2_TXBF_OFDM_18 = 119,
+ WL_RATE_1X2_TXBF_OFDM_24 = 120,
+ WL_RATE_1X2_TXBF_OFDM_36 = 121,
+ WL_RATE_1X2_TXBF_OFDM_48 = 122,
+ WL_RATE_1X2_TXBF_OFDM_54 = 123,
+
+ WL_RATE_1X2_TXBF_MCS0 = 124,
+ WL_RATE_1X2_TXBF_MCS1 = 125,
+ WL_RATE_1X2_TXBF_MCS2 = 126,
+ WL_RATE_1X2_TXBF_MCS3 = 127,
+ WL_RATE_1X2_TXBF_MCS4 = 128,
+ WL_RATE_1X2_TXBF_MCS5 = 129,
+ WL_RATE_1X2_TXBF_MCS6 = 130,
+ WL_RATE_1X2_TXBF_MCS7 = 131,
+
+ WL_RATE_1X2_TXBF_VHT0SS1 = 124,
+ WL_RATE_1X2_TXBF_VHT1SS1 = 125,
+ WL_RATE_1X2_TXBF_VHT2SS1 = 126,
+ WL_RATE_1X2_TXBF_VHT3SS1 = 127,
+ WL_RATE_1X2_TXBF_VHT4SS1 = 128,
+ WL_RATE_1X2_TXBF_VHT5SS1 = 129,
+ WL_RATE_1X2_TXBF_VHT6SS1 = 130,
+ WL_RATE_1X2_TXBF_VHT7SS1 = 131,
+ WL_RATE_1X2_TXBF_VHT8SS1 = 132,
+ WL_RATE_1X2_TXBF_VHT9SS1 = 133,
+
+ /* 2 Streams */
+
+ WL_RATE_2X2_TXBF_SDM_MCS8 = 134,
+ WL_RATE_2X2_TXBF_SDM_MCS9 = 135,
+ WL_RATE_2X2_TXBF_SDM_MCS10 = 136,
+ WL_RATE_2X2_TXBF_SDM_MCS11 = 137,
+ WL_RATE_2X2_TXBF_SDM_MCS12 = 138,
+ WL_RATE_2X2_TXBF_SDM_MCS13 = 139,
+ WL_RATE_2X2_TXBF_SDM_MCS14 = 140,
+ WL_RATE_2X2_TXBF_SDM_MCS15 = 141,
+
+ WL_RATE_2X2_TXBF_VHT0SS2 = 134,
+ WL_RATE_2X2_TXBF_VHT1SS2 = 135,
+ WL_RATE_2X2_TXBF_VHT2SS2 = 136,
+ WL_RATE_2X2_TXBF_VHT3SS2 = 137,
+ WL_RATE_2X2_TXBF_VHT4SS2 = 138,
+ WL_RATE_2X2_TXBF_VHT5SS2 = 139,
+ WL_RATE_2X2_TXBF_VHT6SS2 = 140,
+ WL_RATE_2X2_TXBF_VHT7SS2 = 141,
+
+
+ /****************************
+ * TX Beamforming, 3 chains *
+ ****************************
+ */
+
+ /* 1 Stream expanded + 2 */
+
+ WL_RATE_1X3_TXBF_OFDM_6 = 142,
+ WL_RATE_1X3_TXBF_OFDM_9 = 143,
+ WL_RATE_1X3_TXBF_OFDM_12 = 144,
+ WL_RATE_1X3_TXBF_OFDM_18 = 145,
+ WL_RATE_1X3_TXBF_OFDM_24 = 146,
+ WL_RATE_1X3_TXBF_OFDM_36 = 147,
+ WL_RATE_1X3_TXBF_OFDM_48 = 148,
+ WL_RATE_1X3_TXBF_OFDM_54 = 149,
+
+ WL_RATE_1X3_TXBF_MCS0 = 150,
+ WL_RATE_1X3_TXBF_MCS1 = 151,
+ WL_RATE_1X3_TXBF_MCS2 = 152,
+ WL_RATE_1X3_TXBF_MCS3 = 153,
+ WL_RATE_1X3_TXBF_MCS4 = 154,
+ WL_RATE_1X3_TXBF_MCS5 = 155,
+ WL_RATE_1X3_TXBF_MCS6 = 156,
+ WL_RATE_1X3_TXBF_MCS7 = 157,
+
+ WL_RATE_1X3_TXBF_VHT0SS1 = 150,
+ WL_RATE_1X3_TXBF_VHT1SS1 = 151,
+ WL_RATE_1X3_TXBF_VHT2SS1 = 152,
+ WL_RATE_1X3_TXBF_VHT3SS1 = 153,
+ WL_RATE_1X3_TXBF_VHT4SS1 = 154,
+ WL_RATE_1X3_TXBF_VHT5SS1 = 155,
+ WL_RATE_1X3_TXBF_VHT6SS1 = 156,
+ WL_RATE_1X3_TXBF_VHT7SS1 = 157,
+ WL_RATE_1X3_TXBF_VHT8SS1 = 158,
+ WL_RATE_1X3_TXBF_VHT9SS1 = 159,
+
+ /* 2 Streams expanded + 1 */
+
+ WL_RATE_2X3_TXBF_SDM_MCS8 = 160,
+ WL_RATE_2X3_TXBF_SDM_MCS9 = 161,
+ WL_RATE_2X3_TXBF_SDM_MCS10 = 162,
+ WL_RATE_2X3_TXBF_SDM_MCS11 = 163,
+ WL_RATE_2X3_TXBF_SDM_MCS12 = 164,
+ WL_RATE_2X3_TXBF_SDM_MCS13 = 165,
+ WL_RATE_2X3_TXBF_SDM_MCS14 = 166,
+ WL_RATE_2X3_TXBF_SDM_MCS15 = 167,
+
+ WL_RATE_2X3_TXBF_VHT0SS2 = 160,
+ WL_RATE_2X3_TXBF_VHT1SS2 = 161,
+ WL_RATE_2X3_TXBF_VHT2SS2 = 162,
+ WL_RATE_2X3_TXBF_VHT3SS2 = 163,
+ WL_RATE_2X3_TXBF_VHT4SS2 = 164,
+ WL_RATE_2X3_TXBF_VHT5SS2 = 165,
+ WL_RATE_2X3_TXBF_VHT6SS2 = 166,
+ WL_RATE_2X3_TXBF_VHT7SS2 = 167,
+ WL_RATE_2X3_TXBF_VHT8SS2 = 168,
+ WL_RATE_2X3_TXBF_VHT9SS2 = 169,
+
+ /* 3 Streams */
+
+ WL_RATE_3X3_TXBF_SDM_MCS16 = 170,
+ WL_RATE_3X3_TXBF_SDM_MCS17 = 171,
+ WL_RATE_3X3_TXBF_SDM_MCS18 = 172,
+ WL_RATE_3X3_TXBF_SDM_MCS19 = 173,
+ WL_RATE_3X3_TXBF_SDM_MCS20 = 174,
+ WL_RATE_3X3_TXBF_SDM_MCS21 = 175,
+ WL_RATE_3X3_TXBF_SDM_MCS22 = 176,
+ WL_RATE_3X3_TXBF_SDM_MCS23 = 177,
+
+ WL_RATE_3X3_TXBF_VHT0SS3 = 170,
+ WL_RATE_3X3_TXBF_VHT1SS3 = 171,
+ WL_RATE_3X3_TXBF_VHT2SS3 = 172,
+ WL_RATE_3X3_TXBF_VHT3SS3 = 173,
+ WL_RATE_3X3_TXBF_VHT4SS3 = 174,
+ WL_RATE_3X3_TXBF_VHT5SS3 = 175,
+ WL_RATE_3X3_TXBF_VHT6SS3 = 176,
+ WL_RATE_3X3_TXBF_VHT7SS3 = 177
+} clm_rates_t;
+
+/* Number of rate codes */
+#define WL_NUMRATES 178
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _bcmwifi_rates_h_ */
diff --git a/drivers/net/wireless/bcmdhd/circularbuf.c b/drivers/net/wireless/bcmdhd/circularbuf.c
new file mode 100644
index 000000000000..30c60db3bf6a
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/circularbuf.c
@@ -0,0 +1,326 @@
+/*
+ * Initialization and support routines for self-booting compressed image.
+ *
+ * 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: circularbuf.c 452261 2014-01-29 19:30:23Z $
+ */
+
+#include <circularbuf.h>
+#include <bcmmsgbuf.h>
+#include <osl.h>
+
+#define CIRCULARBUF_READ_SPACE_AT_END(x) \
+ ((x->w_ptr >= x->rp_ptr) ? (x->w_ptr - x->rp_ptr) : (x->e_ptr - x->rp_ptr))
+
+#define CIRCULARBUF_READ_SPACE_AVAIL(x) \
+ (((CIRCULARBUF_READ_SPACE_AT_END(x) == 0) && (x->w_ptr < x->rp_ptr)) ? \
+ x->w_ptr : CIRCULARBUF_READ_SPACE_AT_END(x))
+
+int cbuf_msg_level = CBUF_ERROR_VAL | CBUF_TRACE_VAL | CBUF_INFORM_VAL;
+
+/* #define CBUF_DEBUG */
+#ifdef CBUF_DEBUG
+#define CBUF_DEBUG_CHECK(x) x
+#else
+#define CBUF_DEBUG_CHECK(x)
+#endif /* CBUF_DEBUG */
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function : circularbuf_init
+ * Description:
+ *
+ *
+ * Input Args :
+ *
+ *
+ * Return Values :
+ *
+ * -----------------------------------------------------------------------------
+ */
+void
+circularbuf_init(circularbuf_t *handle, void *buf_base_addr, uint16 total_buf_len)
+{
+ handle->buf_addr = buf_base_addr;
+
+ handle->depth = handle->e_ptr = HTOL32(total_buf_len);
+
+ /* Initialize Read and Write pointers */
+ handle->w_ptr = handle->r_ptr = handle->wp_ptr = handle->rp_ptr = HTOL32(0);
+ handle->mb_ring_bell = NULL;
+ handle->mb_ctx = NULL;
+
+ return;
+}
+
+void
+circularbuf_register_cb(circularbuf_t *handle, mb_ring_t mb_ring_func, void *ctx)
+{
+ handle->mb_ring_bell = mb_ring_func;
+ handle->mb_ctx = ctx;
+}
+
+#ifdef CBUF_DEBUG
+static void
+circularbuf_check_sanity(circularbuf_t *handle)
+{
+ if ((handle->e_ptr > handle->depth) ||
+ (handle->r_ptr > handle->e_ptr) ||
+ (handle->rp_ptr > handle->e_ptr) ||
+ (handle->w_ptr > handle->e_ptr))
+ {
+ printf("%s:%d: Pointers are corrupted.\n", __FUNCTION__, __LINE__);
+ circularbuf_debug_print(handle);
+ ASSERT(0);
+ }
+ return;
+}
+#endif /* CBUF_DEBUG */
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function : circularbuf_reserve_for_write
+ *
+ * Description:
+ * This function reserves N bytes for write in the circular buffer. The circularbuf
+ * implementation will only reserve space in the ciruclar buffer and return
+ * the pointer to the address where the new data can be written.
+ * The actual write implementation (bcopy/dma) is outside the scope of
+ * circularbuf implementation.
+ *
+ * Input Args :
+ * size - No. of bytes to reserve for write
+ *
+ * Return Values :
+ * void * : Pointer to the reserved location. This is the address
+ * that will be used for write (dma/bcopy)
+ *
+ * -----------------------------------------------------------------------------
+ */
+void * BCMFASTPATH
+circularbuf_reserve_for_write(circularbuf_t *handle, uint16 size)
+{
+ int16 avail_space;
+ void *ret_ptr = NULL;
+
+ CBUF_DEBUG_CHECK(circularbuf_check_sanity(handle));
+ ASSERT(size < handle->depth);
+
+ if (handle->wp_ptr >= handle->r_ptr)
+ avail_space = handle->depth - handle->wp_ptr;
+ else
+ avail_space = handle->r_ptr - handle->wp_ptr;
+
+ ASSERT(avail_space <= handle->depth);
+ if (avail_space > size)
+ {
+ /* Great. We have enough space. */
+ ret_ptr = CIRCULARBUF_START(handle) + handle->wp_ptr;
+
+ /*
+ * We need to update the wp_ptr for the next guy to write.
+ *
+ * Please Note : We are not updating the write pointer here. This can be
+ * done only after write is complete (In case of DMA, we can only schedule
+ * the DMA. Actual completion will be known only on DMA complete interrupt).
+ */
+ handle->wp_ptr += size;
+ return ret_ptr;
+ }
+
+ /*
+ * If there is no available space, we should check if there is some space left
+ * in the beginning of the circular buffer. Wrap-around case, where there is
+ * not enough space in the end of the circular buffer. But, there might be
+ * room in the beginning of the buffer.
+ */
+ if (handle->wp_ptr >= handle->r_ptr)
+ {
+ avail_space = handle->r_ptr;
+ if (avail_space > size)
+ {
+ /* OK. There is room in the beginning. Let's go ahead and use that.
+ * But, before that, we have left a hole at the end of the circular
+ * buffer as that was not sufficient to accomodate the requested
+ * size. Let's make sure this is updated in the circularbuf structure
+ * so that consumer does not use the hole.
+ */
+ handle->e_ptr = handle->wp_ptr;
+ handle->wp_ptr = size;
+
+ return CIRCULARBUF_START(handle);
+ }
+ }
+
+ /* We have tried enough to accomodate the new packet. There is no room for now. */
+ return NULL;
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function : circularbuf_write_complete
+ *
+ * Description:
+ * This function has to be called by the producer end of circularbuf to indicate to
+ * the circularbuf layer that data has been written and the write pointer can be
+ * updated. In the process, if there was a doorbell callback registered, that
+ * function would also be invoked.
+ *
+ * Input Args :
+ * dest_addr : Address where the data was written. This would be the
+ * same address that was reserved earlier.
+ * bytes_written : Length of data written
+ *
+ * -----------------------------------------------------------------------------
+ */
+void BCMFASTPATH
+circularbuf_write_complete(circularbuf_t *handle, uint16 bytes_written)
+{
+ CBUF_DEBUG_CHECK(circularbuf_check_sanity(handle));
+
+ /* Update the write pointer */
+ if ((handle->w_ptr + bytes_written) >= handle->depth) {
+ OSL_CACHE_FLUSH((void *) CIRCULARBUF_START(handle), bytes_written);
+ handle->w_ptr = bytes_written;
+ } else {
+ OSL_CACHE_FLUSH((void *) (CIRCULARBUF_START(handle) + handle->w_ptr),
+ bytes_written);
+ handle->w_ptr += bytes_written;
+ }
+
+ /* And ring the door bell (mail box interrupt) to indicate to the peer that
+ * message is available for consumption.
+ */
+ if (handle->mb_ring_bell)
+ handle->mb_ring_bell(handle->mb_ctx);
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function : circularbuf_get_read_ptr
+ *
+ * Description:
+ * This function will be called by the consumer of circularbuf for reading data from
+ * the circular buffer. This will typically be invoked when the consumer gets a
+ * doorbell interrupt.
+ * Please note that the function only returns the pointer (and length) from
+ * where the data can be read. Actual read implementation is upto the
+ * consumer. It could be a bcopy or dma.
+ *
+ * Input Args :
+ * void * : Address from where the data can be read.
+ * available_len : Length of data available for read.
+ *
+ * -----------------------------------------------------------------------------
+ */
+void * BCMFASTPATH
+circularbuf_get_read_ptr(circularbuf_t *handle, uint16 *available_len)
+{
+ uint8 *ret_addr;
+
+ CBUF_DEBUG_CHECK(circularbuf_check_sanity(handle));
+
+ /* First check if there is any data available in the circular buffer */
+ *available_len = CIRCULARBUF_READ_SPACE_AVAIL(handle);
+ if (*available_len == 0)
+ return NULL;
+
+ /*
+ * Although there might be data in the circular buffer for read, in
+ * cases of write wrap-around and read still in the end of the circular
+ * buffer, we might have to wrap around the read pending pointer also.
+ */
+ if (CIRCULARBUF_READ_SPACE_AT_END(handle) == 0)
+ handle->rp_ptr = 0;
+
+ ret_addr = CIRCULARBUF_START(handle) + handle->rp_ptr;
+
+ /*
+ * Please note that we do not update the read pointer here. Only
+ * read pending pointer is updated, so that next reader knows where
+ * to read data from.
+ * read pointer can only be updated when the read is complete.
+ */
+ handle->rp_ptr = (uint16)(ret_addr - CIRCULARBUF_START(handle) + *available_len);
+
+ ASSERT(*available_len <= handle->depth);
+
+ OSL_CACHE_INV((void *) ret_addr, *available_len);
+
+ return ret_addr;
+}
+
+/*
+ * -----------------------------------------------------------------------------
+ * Function : circularbuf_read_complete
+ * Description:
+ * This function has to be called by the consumer end of circularbuf to indicate
+ * that data has been consumed and the read pointer can be updated.
+ *
+ * Input Args :
+ * bytes_read : No. of bytes consumed by the consumer. This has to match
+ * the length returned by circularbuf_get_read_ptr
+ *
+ * Return Values :
+ * CIRCULARBUF_SUCCESS : Otherwise
+ *
+ * -----------------------------------------------------------------------------
+ */
+circularbuf_ret_t BCMFASTPATH
+circularbuf_read_complete(circularbuf_t *handle, uint16 bytes_read)
+{
+ CBUF_DEBUG_CHECK(circularbuf_check_sanity(handle));
+ ASSERT(bytes_read < handle->depth);
+
+ /* Update the read pointer */
+ if ((handle->r_ptr + bytes_read) >= handle->depth)
+ handle->r_ptr = bytes_read;
+ else
+ handle->r_ptr += bytes_read;
+
+ return CIRCULARBUF_SUCCESS;
+}
+/*
+ * -----------------------------------------------------------------------------
+ * Function : circularbuf_revert_rp_ptr
+ *
+ * Description:
+ * The rp_ptr update during circularbuf_get_read_ptr() is done to reflect the amount of data
+ * that is sent out to be read by the consumer. But the consumer may not always read the
+ * entire data. In such a case, the rp_ptr needs to be reverted back by 'left' bytes, where
+ * 'left' is the no. of bytes left unread.
+ *
+ * Input args:
+ * bytes : The no. of bytes left unread by the consumer
+ *
+ * -----------------------------------------------------------------------------
+ */
+circularbuf_ret_t
+circularbuf_revert_rp_ptr(circularbuf_t *handle, uint16 bytes)
+{
+ CBUF_DEBUG_CHECK(circularbuf_check_sanity(handle));
+ ASSERT(bytes < handle->depth);
+
+ handle->rp_ptr -= bytes;
+
+ return CIRCULARBUF_SUCCESS;
+}
diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h
new file mode 100644
index 000000000000..cb327a6ba67f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd.h
@@ -0,0 +1,931 @@
+/*
+ * 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-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: dhd.h 662786 2016-11-11 09:06:37Z $
+ */
+
+/****************
+ * Common types *
+ */
+
+#ifndef _dhd_h_
+#define _dhd_h_
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK)
+#include <linux/wakelock.h>
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */
+/* The kernel threading is sdio-specific */
+struct task_struct;
+struct sched_param;
+int setScheduler(struct task_struct *p, int policy, struct sched_param *param);
+int get_scheduler_policy(struct task_struct *p);
+
+#define ALL_INTERFACES 0xff
+
+#include <wlioctl.h>
+#include <wlfc_proto.h>
+
+
+#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;
+
+/* 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 */
+};
+
+
+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),
+ 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))
+};
+
+/* 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 */
+
+#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
+
+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
+};
+
+enum dhd_prealloc_index {
+ DHD_PREALLOC_PROT = 0,
+ DHD_PREALLOC_RXBUF,
+ DHD_PREALLOC_DATABUF,
+ DHD_PREALLOC_OSL_BUF,
+ DHD_PREALLOC_WIPHY_ESCAN0 = 5,
+ DHD_PREALLOC_WIPHY_ESCAN1 = 6,
+ DHD_PREALLOC_DHD_INFO = 7,
+ DHD_PREALLOC_DHD_WLFC_INFO = 8,
+ DHD_PREALLOC_SECTION_MAX = DHD_PREALLOC_DHD_WLFC_INFO
+};
+
+#define PREALLOC_MASK_LEN 4
+
+/* Packet alignment for most efficient SDIO (can change based on platform) */
+#ifndef DHD_SDALIGN
+#define DHD_SDALIGN 32
+#endif
+
+#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
+
+/* 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;
+
+#if defined(OOB_PARAM)
+#if !defined(OOB_INTR_ONLY)
+#error OOB_PARAM must be defined with OOB_INTR_ONLY!!
+#endif /* !defined(OOB_INTR_ONLY) */
+
+#define OOB_PARAM_IF(x) if (x)
+#define OOB_PARAM_ELSE() else
+
+#else /* defined(OOB_PARAM) */
+
+#define OOB_PARAM_IF(x)
+#define OOB_PARAM_ELSE()
+#endif /* defined(OOB_PARAM) */
+
+#ifdef DHDTCPACK_SUPPRESS
+#define TCPACK_SUP_OFF 0 /* TCPACK suppress off */
+/* Replace TCPACK in txq when new coming one has higher ACK number. */
+#define TCPACK_SUP_REPLACE 1
+/* 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 do not need to hurry delivered remains longer in TXQ so can be suppressed.
+ */
+#define TCPACK_SUP_DELAYTX 2
+#endif /* DHDTCPACK_SUPPRESS */
+
+/* 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 */
+
+ /* to NDIS developer, the structure dhd_common is redundant,
+ * please do NOT merge it back from other branches !!!
+ */
+
+
+ /* Internal dhd items */
+ bool up; /* Driver up/down (to OS) */
+ bool txoff; /* Transmit flow-controlled */
+ bool dongle_reset; /* TRUE = DEVRESET put dongle into reset */
+ enum dhd_bus_state busstate;
+ 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_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_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 */
+
+ /* 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 */
+ char eventmask[WL_EVENTING_MASK_LEN];
+ char prealloc_malloc_mask[PREALLOC_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;
+ /*
+ * implement below functions in each platform if needed.
+ */
+ /* platform specific function whether to skip flow control */
+ bool (*skip_fc)(void);
+ /* platform specific function for wlfc_enable and wlfc_deinit */
+ void (*plat_init)(void *dhd);
+ void (*plat_deinit)(void *dhd);
+#endif /* PROP_TXSTATUS */
+#ifdef PNO_SUPPORT
+ void *pno_state;
+#endif
+#ifdef ROAM_AP_ENV_DETECTION
+ bool roam_env_detection;
+#endif
+ bool dongle_isolation;
+ bool dongle_trap_occured; /* flag for sending HANG event to upper layer */
+ int hang_was_sent;
+ int rxcnt_timeout; /* counter rxcnt timeout to send HANG */
+ int txcnt_timeout; /* counter txcnt timeout to send HANG */
+ bool hang_report; /* enable hang report by default */
+#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];
+ char fw_capabilities[WLC_IOCTL_SMLEN];
+ #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 */
+#endif /* DHDTCPACK_SUPPRESS */
+#if defined(ARP_OFFLOAD_SUPPORT)
+ uint32 arp_version;
+#endif
+#ifdef CUSTOM_SET_CPUCORE
+ struct task_struct * current_dpc;
+ struct task_struct * current_rxf;
+ int chan_isvht80;
+#endif /* CUSTOM_SET_CPUCORE */
+#ifdef OOB_PARAM
+ uint oob_disable;
+#endif /* OOB_PARAM */
+} dhd_pub_t;
+
+
+ #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)
+ #ifdef CUSTOMER_HW4
+ #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)
+ #else
+ #define DHD_PM_RESUME_RETURN_ERROR(a) do { \
+ if (dhd_mmc_suspend) return a; } while (0)
+ #endif
+ #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) */
+
+unsigned long dhd_os_spin_lock(dhd_pub_t *pub);
+void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags);
+#ifdef PNO_SUPPORT
+int dhd_pno_clean(dhd_pub_t *dhd);
+#endif /* PNO_SUPPORT */
+/*
+ * 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_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);
+
+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 DHD_OS_WAKE_LOCK(pub) dhd_os_wake_lock(pub)
+#define DHD_OS_WAKE_UNLOCK(pub) dhd_os_wake_unlock(pub)
+#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub)
+#define DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(pub, val) \
+ dhd_os_wake_lock_rx_timeout_enable(pub, val)
+#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(pub, val) \
+ dhd_os_wake_lock_ctrl_timeout_enable(pub, val)
+#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL(pub) \
+ dhd_os_wake_lock_ctrl_timeout_cancel(pub)
+
+#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)
+#define DHD_PACKET_TIMEOUT_MS 500
+#define DHD_EVENT_TIMEOUT_MS 1500
+
+
+/* interface operations (register, remove) should be atomic, use this lock to prevent race
+ * condition among wifi on/off and interface operation functions
+ */
+void dhd_net_if_lock(struct net_device *dev);
+void dhd_net_if_unlock(struct net_device *dev);
+
+
+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_STATE_DONE = 0x200
+} 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);
+#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);
+
+/* 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);
+
+/* Receive frame for delivery to OS. Callee disposes of rxp. */
+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);
+
+/* 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);
+
+/* OS independent layer functions */
+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, bool * pending);
+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 int dhd_os_get_image_block(char * buf, int len, void * image);
+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);
+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);
+#ifdef DHDTCPACK_SUPPRESS
+extern void dhd_os_tcpacklock(dhd_pub_t *pub);
+extern void dhd_os_tcpackunlock(dhd_pub_t *pub);
+#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);
+extern void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec);
+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);
+
+#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 */
+
+
+#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
+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 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);
+#endif /* PKT_FILTER_SUPPORT */
+
+extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd);
+extern bool dhd_support_sta_mode(dhd_pub_t *dhd);
+
+#ifdef DHD_DEBUG
+extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size);
+#endif /* DHD_DEBUG */
+
+extern void dhd_os_sdtxlock(dhd_pub_t * pub);
+extern void dhd_os_sdtxunlock(dhd_pub_t * pub);
+
+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 ramstart;
+ uint32 rodata_start;
+ uint32 rodata_end;
+ char *rom_raw_sstr;
+ uint32 rom_ramstart;
+ uint32 rom_rodata_start;
+ uint32 rom_rodata_end;
+} dhd_event_log_t;
+#endif /* SHOW_LOGTRACE */
+
+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 wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, uint16 pktlen,
+ wl_event_msg_t *, void **data_ptr, void *raw_event);
+extern void wl_event_to_host_order(wl_event_msg_t * evt);
+extern int wl_host_event_get_data(void *pktdata, uint pktlen, wl_event_msg_t *evt);
+
+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 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 struct net_device* dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name,
+ uint8 *mac, uint8 bssidx, bool need_rtnl_lock, 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, uint 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);
+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);
+
+#if defined(KEEP_ALIVE)
+extern int dhd_keep_alive_onoff(dhd_pub_t *dhd);
+#endif /* KEEP_ALIVE */
+
+extern bool dhd_is_concurrent_mode(dhd_pub_t *dhd);
+extern int dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set);
+typedef enum cust_gpio_modes {
+ WLAN_RESET_ON,
+ WLAN_RESET_OFF,
+ WLAN_POWER_ON,
+ WLAN_POWER_OFF
+} cust_gpio_modes_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;
+
+#if defined(DHD_DEBUG)
+/* Console output poll interval */
+extern uint dhd_console_ms;
+extern uint wl_msg_level;
+#endif /* defined(DHD_DEBUG) */
+
+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;
+
+/* Override to force tx queueing all the time */
+extern uint dhd_force_tx_queueing;
+/* 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 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 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 */
+
+#ifdef DHD_DEBUG
+extern int dhd_start_join_timer(dhd_pub_t *pub);
+extern int dhd_del_join_timer(dhd_pub_t *pub);
+extern int dhd_set_join_timeout(dhd_pub_t *pub, uint32 timeout);
+extern uint32 dhd_get_join_timeout(dhd_pub_t *pub);
+extern int dhd_add_scan_timer(dhd_pub_t *dhd_pub);
+extern int dhd_del_scan_timer(dhd_pub_t *dhd_pub);
+extern int dhd_set_scan_timeout(dhd_pub_t *pub, uint32 timeout);
+extern uint32 dhd_get_scan_timeout(dhd_pub_t *pub);
+#endif /* DHD_DEBUG */
+
+#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
+#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
+
+#ifdef SOFTAP
+extern char fw_path2[MOD_PARAM_PATHLEN];
+#endif
+
+/* Flag to indicate if we should download firmware on driver load */
+extern uint dhd_download_fw_on_driverload;
+
+
+/* For supporting multiple interfaces */
+#define DHD_MAX_IFS 16
+#define DHD_DEL_IF -0xe
+#define DHD_BAD_IF -0xf
+
+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);
+#endif
+/* Neighbor Discovery Offload Support */
+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);
+/* 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);
+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 */
+
+uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail);
+void dhd_os_prefree(dhd_pub_t *dhdpub, int section, void *addr, uint size);
+
+#if defined(CONFIG_DHD_USE_STATIC_BUF)
+#define DHD_OS_PREALLOC(dhdpub, section, size) dhd_os_prealloc(dhdpub, section, size, TRUE)
+#define DHD_OS_PREFREE(dhdpub, section, addr, size) dhd_os_prefree(dhdpub, section, addr, size)
+#else
+#define DHD_OS_PREALLOC(dhdpub, section, size) MALLOC(dhdpub->osh, size)
+#define DHD_OS_PREFREE(dhdpub, section, addr, size) MFREE(dhdpub->osh, addr, size)
+#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */
+
+
+#ifdef OOB_PARAM
+extern uint dhd_get_oob_disable(struct dhd_bus* bus);
+#endif /* OOB_PARAM */
+
+#endif /* _dhd_h_ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_bta.c b/drivers/net/wireless/bcmdhd/dhd_bta.c
new file mode 100644
index 000000000000..878af0eece40
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_bta.c
@@ -0,0 +1,337 @@
+/*
+ * BT-AMP support routines
+ *
+ * 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: dhd_bta.c 434656 2013-11-07 01:11:33Z $
+ */
+#error "WLBTAMP is not defined"
+
+#include <typedefs.h>
+#include <osl.h>
+#include <bcmcdc.h>
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <proto/802.11.h>
+#include <proto/802.11_bta.h>
+#include <proto/bt_amp_hci.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_bus.h>
+#include <dhd_proto.h>
+#include <dhdioctl.h>
+#include <dhd_dbg.h>
+
+#include <dhd_bta.h>
+
+
+#ifdef SEND_HCI_CMD_VIA_IOCTL
+#define BTA_HCI_CMD_MAX_LEN HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE
+
+/* Send HCI cmd via wl iovar HCI_cmd to the dongle. */
+int
+dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len)
+{
+ amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf;
+ uint8 buf[BTA_HCI_CMD_MAX_LEN + 16];
+ uint len = sizeof(buf);
+ wl_ioctl_t ioc;
+
+ if (cmd_len < HCI_CMD_PREAMBLE_SIZE)
+ return BCME_BADLEN;
+
+ if ((uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE > cmd_len)
+ return BCME_BADLEN;
+
+ len = bcm_mkiovar("HCI_cmd",
+ (char *)cmd, (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, (char *)buf, len);
+
+
+ memset(&ioc, 0, sizeof(ioc));
+
+ ioc.cmd = WLC_SET_VAR;
+ ioc.buf = buf;
+ ioc.len = len;
+ ioc.set = TRUE;
+
+ return dhd_wl_ioctl(pub, &ioc, ioc.buf, ioc.len);
+}
+#else /* !SEND_HCI_CMD_VIA_IOCTL */
+
+static void
+dhd_bta_flush_hcidata(dhd_pub_t *pub, uint16 llh)
+{
+ int prec;
+ struct pktq *q;
+ uint count = 0;
+
+ q = dhd_bus_txq(pub->bus);
+ if (q == NULL)
+ return;
+
+ DHD_BTA(("dhd: flushing HCI ACL data for logical link %u...\n", llh));
+
+ dhd_os_sdlock_txq(pub);
+
+ /* Walk through the txq and toss all HCI ACL data packets */
+ PKTQ_PREC_ITER(q, prec) {
+ void *head_pkt = NULL;
+
+ while (pktq_ppeek(q, prec) != head_pkt) {
+ void *pkt = pktq_pdeq(q, prec);
+ int ifidx;
+
+ dhd_prot_hdrpull(pub, &ifidx, pkt, NULL, NULL);
+
+ if (PKTLEN(pub->osh, pkt) >= RFC1042_HDR_LEN) {
+ struct ether_header *eh =
+ (struct ether_header *)PKTDATA(pub->osh, pkt);
+
+ if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) {
+ struct dot11_llc_snap_header *lsh =
+ (struct dot11_llc_snap_header *)&eh[1];
+
+ if (bcmp(lsh, BT_SIG_SNAP_MPROT,
+ DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
+ ntoh16(lsh->type) == BTA_PROT_L2CAP) {
+ amp_hci_ACL_data_t *ACL_data =
+ (amp_hci_ACL_data_t *)&lsh[1];
+ uint16 handle = ltoh16(ACL_data->handle);
+
+ if (HCI_ACL_DATA_HANDLE(handle) == llh) {
+ PKTFREE(pub->osh, pkt, TRUE);
+ count ++;
+ continue;
+ }
+ }
+ }
+ }
+
+ dhd_prot_hdrpush(pub, ifidx, pkt);
+
+ if (head_pkt == NULL)
+ head_pkt = pkt;
+ pktq_penq(q, prec, pkt);
+ }
+ }
+
+ dhd_os_sdunlock_txq(pub);
+
+ DHD_BTA(("dhd: flushed %u packet(s) for logical link %u...\n", count, llh));
+}
+
+/* Handle HCI cmd locally.
+ * Return 0: continue to send the cmd across SDIO
+ * < 0: stop, fail
+ * > 0: stop, succuess
+ */
+static int
+_dhd_bta_docmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd)
+{
+ int status = 0;
+
+ switch (ltoh16_ua((uint8 *)&cmd->opcode)) {
+ case HCI_Enhanced_Flush: {
+ eflush_cmd_parms_t *cmdparms = (eflush_cmd_parms_t *)cmd->parms;
+ dhd_bta_flush_hcidata(pub, ltoh16_ua(cmdparms->llh));
+ break;
+ }
+ default:
+ break;
+ }
+
+ return status;
+}
+
+/* Send HCI cmd encapsulated in BT-SIG frame via data channel to the dongle. */
+int
+dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len)
+{
+ amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf;
+ struct ether_header *eh;
+ struct dot11_llc_snap_header *lsh;
+ osl_t *osh = pub->osh;
+ uint len;
+ void *p;
+ int status;
+
+ if (cmd_len < HCI_CMD_PREAMBLE_SIZE) {
+ DHD_ERROR(("dhd_bta_docmd: short command, cmd_len %u\n", cmd_len));
+ return BCME_BADLEN;
+ }
+
+ if ((len = (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE) > cmd_len) {
+ DHD_ERROR(("dhd_bta_docmd: malformed command, len %u cmd_len %u\n",
+ len, cmd_len));
+ /* return BCME_BADLEN; */
+ }
+
+ p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE);
+ if (p == NULL) {
+ DHD_ERROR(("dhd_bta_docmd: out of memory\n"));
+ return BCME_NOMEM;
+ }
+
+
+ /* intercept and handle the HCI cmd locally */
+ if ((status = _dhd_bta_docmd(pub, cmd)) > 0)
+ return 0;
+ else if (status < 0)
+ return status;
+
+ /* copy in HCI cmd */
+ PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN);
+ bcopy(cmd, PKTDATA(osh, p), len);
+
+ /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */
+ PKTPUSH(osh, p, RFC1042_HDR_LEN);
+ eh = (struct ether_header *)PKTDATA(osh, p);
+ bzero(eh->ether_dhost, ETHER_ADDR_LEN);
+ ETHER_SET_LOCALADDR(eh->ether_dhost);
+ bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN);
+ eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN);
+ lsh = (struct dot11_llc_snap_header *)&eh[1];
+ bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2);
+ lsh->type = 0;
+
+ return dhd_sendpkt(pub, 0, p);
+}
+#endif /* !SEND_HCI_CMD_VIA_IOCTL */
+
+/* Send HCI ACL data to dongle via data channel */
+int
+dhd_bta_tx_hcidata(dhd_pub_t *pub, void *data_buf, uint data_len)
+{
+ amp_hci_ACL_data_t *data = (amp_hci_ACL_data_t *)data_buf;
+ struct ether_header *eh;
+ struct dot11_llc_snap_header *lsh;
+ osl_t *osh = pub->osh;
+ uint len;
+ void *p;
+
+ if (data_len < HCI_ACL_DATA_PREAMBLE_SIZE) {
+ DHD_ERROR(("dhd_bta_tx_hcidata: short data_buf, data_len %u\n", data_len));
+ return BCME_BADLEN;
+ }
+
+ if ((len = (uint)ltoh16(data->dlen) + HCI_ACL_DATA_PREAMBLE_SIZE) > data_len) {
+ DHD_ERROR(("dhd_bta_tx_hcidata: malformed hci data, len %u data_len %u\n",
+ len, data_len));
+ /* return BCME_BADLEN; */
+ }
+
+ p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE);
+ if (p == NULL) {
+ DHD_ERROR(("dhd_bta_tx_hcidata: out of memory\n"));
+ return BCME_NOMEM;
+ }
+
+
+ /* copy in HCI ACL data header and HCI ACL data */
+ PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN);
+ bcopy(data, PKTDATA(osh, p), len);
+
+ /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */
+ PKTPUSH(osh, p, RFC1042_HDR_LEN);
+ eh = (struct ether_header *)PKTDATA(osh, p);
+ bzero(eh->ether_dhost, ETHER_ADDR_LEN);
+ bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN);
+ eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN);
+ lsh = (struct dot11_llc_snap_header *)&eh[1];
+ bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2);
+ lsh->type = HTON16(BTA_PROT_L2CAP);
+
+ return dhd_sendpkt(pub, 0, p);
+}
+
+/* txcomplete callback */
+void
+dhd_bta_tx_hcidata_complete(dhd_pub_t *dhdp, void *txp, bool success)
+{
+ uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, txp);
+ amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)(pktdata + RFC1042_HDR_LEN);
+ uint16 handle = ltoh16(ACL_data->handle);
+ uint16 llh = HCI_ACL_DATA_HANDLE(handle);
+
+ wl_event_msg_t event;
+ uint8 data[HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t)];
+ amp_hci_event_t *evt;
+ num_completed_data_blocks_evt_parms_t *parms;
+
+ uint16 len = HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t);
+
+ /* update the event struct */
+ memset(&event, 0, sizeof(event));
+ event.version = hton16(BCM_EVENT_MSG_VERSION);
+ event.event_type = hton32(WLC_E_BTA_HCI_EVENT);
+ event.status = 0;
+ event.reason = 0;
+ event.auth_type = 0;
+ event.datalen = hton32(len);
+ event.flags = 0;
+
+ /* generate Number of Completed Blocks event */
+ evt = (amp_hci_event_t *)data;
+ evt->ecode = HCI_Number_of_Completed_Data_Blocks;
+ evt->plen = sizeof(num_completed_data_blocks_evt_parms_t);
+
+ parms = (num_completed_data_blocks_evt_parms_t *)evt->parms;
+ htol16_ua_store(dhdp->maxdatablks, (uint8 *)&parms->num_blocks);
+ parms->num_handles = 1;
+ htol16_ua_store(llh, (uint8 *)&parms->completed[0].handle);
+ parms->completed[0].pkts = 1;
+ parms->completed[0].blocks = 1;
+
+ dhd_sendup_event_common(dhdp, &event, data);
+}
+
+/* event callback */
+void
+dhd_bta_doevt(dhd_pub_t *dhdp, void *data_buf, uint data_len)
+{
+ amp_hci_event_t *evt = (amp_hci_event_t *)data_buf;
+
+ ASSERT(dhdp);
+ ASSERT(evt);
+
+ switch (evt->ecode) {
+ case HCI_Command_Complete: {
+ cmd_complete_parms_t *parms = (cmd_complete_parms_t *)evt->parms;
+ switch (ltoh16_ua((uint8 *)&parms->opcode)) {
+ case HCI_Read_Data_Block_Size: {
+ read_data_block_size_evt_parms_t *parms2 =
+ (read_data_block_size_evt_parms_t *)parms->parms;
+ dhdp->maxdatablks = ltoh16_ua((uint8 *)&parms2->data_block_num);
+ break;
+ }
+ }
+ break;
+ }
+
+ case HCI_Flush_Occurred: {
+ flush_occurred_evt_parms_t *evt_parms = (flush_occurred_evt_parms_t *)evt->parms;
+ dhd_bta_flush_hcidata(dhdp, ltoh16_ua((uint8 *)&evt_parms->handle));
+ break;
+ }
+ default:
+ break;
+ }
+}
diff --git a/drivers/net/wireless/bcmdhd/dhd_bta.h b/drivers/net/wireless/bcmdhd/dhd_bta.h
new file mode 100644
index 000000000000..2f93802adb3d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_bta.h
@@ -0,0 +1,39 @@
+/*
+ * BT-AMP support routines
+ *
+ * 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: dhd_bta.h 291086 2011-10-21 01:17:24Z $
+ */
+#ifndef __dhd_bta_h__
+#define __dhd_bta_h__
+
+struct dhd_pub;
+
+extern int dhd_bta_docmd(struct dhd_pub *pub, void *cmd_buf, uint cmd_len);
+
+extern void dhd_bta_doevt(struct dhd_pub *pub, void *data_buf, uint data_len);
+
+extern int dhd_bta_tx_hcidata(struct dhd_pub *pub, void *data_buf, uint data_len);
+extern void dhd_bta_tx_hcidata_complete(struct dhd_pub *dhdp, void *txp, bool success);
+
+
+#endif /* __dhd_bta_h__ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_bus.h b/drivers/net/wireless/bcmdhd/dhd_bus.h
new file mode 100644
index 000000000000..f47e916813b6
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_bus.h
@@ -0,0 +1,158 @@
+/*
+ * 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-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: dhd_bus.h 457888 2014-02-25 03:34:39Z $
+ */
+
+#ifndef _dhd_bus_h_
+#define _dhd_bus_h_
+
+/*
+ * 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);
+
+/* 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);
+
+/* 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
+
+
+/* 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);
+
+#if defined(DHD_DEBUG)
+/* Device console input function */
+extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen);
+#endif /* defined(DHD_DEBUG) */
+
+/* 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 void *dhd_bus_sih(struct dhd_bus *bus);
+extern uint dhd_bus_hdrlen(struct dhd_bus *bus);
+extern void dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val);
+
+#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);
+
+#ifdef BCMPCIE
+enum {
+ DNGL_TO_HOST_BUF_IOCT,
+ DNGL_TO_HOST_BUF_ADDR,
+ HOST_TO_DNGL_BUF_ADDR,
+ HOST_TO_DNGL_WPTR,
+ HOST_TO_DNGL_RPTR,
+ DNGL_TO_HOST_WPTR,
+ DNGL_TO_HOST_RPTR,
+ TOTAL_LFRAG_PACKET_CNT,
+ HOST_TO_DNGL_CTRLBUF_ADDR,
+ DNGL_TO_HOST_CTRLBUF_ADDR,
+ HTOD_CTRL_RPTR,
+ HTOD_CTRL_WPTR,
+ DTOH_CTRL_RPTR,
+ DTOH_CTRL_WPTR,
+ HTOD_MB_DATA,
+ DTOH_MB_DATA,
+ MAX_HOST_RXBUFS
+};
+typedef void (*dhd_mb_ring_t) (struct dhd_bus *, uint32);
+extern void dhd_bus_cmn_writeshared(struct dhd_bus *bus, void * data, uint32 len, uint8 type);
+extern void dhd_bus_ringbell(struct dhd_bus *bus, uint32 value);
+extern void dhd_bus_cmn_readshared(struct dhd_bus *bus, void* data, uint8 type);
+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 void dhd_bus_update_retlen(struct dhd_bus *bus, uint32 retlen, uint32 cmd_id, uint32 status,
+ uint32 inline_data);
+extern dhd_mb_ring_t dhd_bus_get_mbintr_fn(struct dhd_bus *bus);
+#endif /* BCMPCIE */
+#endif /* _dhd_bus_h_ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c
new file mode 100644
index 000000000000..c776089b04c6
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_cdc.c
@@ -0,0 +1,789 @@
+/*
+ * DHD Protocol Module for CDC and BDC.
+ *
+ * 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: dhd_cdc.c 657232 2016-08-31 11:02:44Z $
+ *
+ * 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 <typedefs.h>
+#include <osl.h>
+
+#include <bcmutils.h>
+#include <bcmcdc.h>
+#include <bcmendian.h>
+
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_proto.h>
+#include <dhd_bus.h>
+#include <dhd_dbg.h>
+
+
+#ifdef PROP_TXSTATUS
+#include <wlfc_proto.h>
+#include <dhd_wlfc.h>
+#endif
+
+
+#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;
+ 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)
+{
+ 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 */
+ err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len);
+
+ DHD_OS_WAKE_UNLOCK(dhd);
+ return err;
+}
+
+static int
+dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
+{
+ int ret;
+ int cdc_len = len + sizeof(cdc_ioctl_t);
+ dhd_prot_t *prot = dhd->prot;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+
+ do {
+ ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len);
+ if (ret < 0)
+ break;
+ } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id);
+
+
+ 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;
+ }
+
+ 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);
+
+ 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;
+ }
+
+ /* Check the ERROR flag */
+ if (flags & CDCF_IOC_ERROR)
+ {
+ ret = ltoh32(msg->status);
+ /* Cache error from dongle */
+ dhd->dongle_error = ret;
+ }
+
+done:
+ return ret;
+}
+
+
+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;
+
+ if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) {
+ DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
+ 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", (char*)buf));
+ }
+ 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);
+ }
+
+ /* 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 */
+
+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);
+
+ }
+#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, DHD_PREALLOC_PROT, 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_PREALLOC_PROT, dhd->prot, sizeof(dhd_prot_t));
+ dhd->prot = NULL;
+}
+
+void
+dhd_prot_dstats(dhd_pub_t *dhd)
+{
+/* No stats from dongle added yet, 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_prot_init(dhd_pub_t *dhd)
+{
+ int ret = 0;
+ wlc_rev_info_t revinfo;
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+
+ /* 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;
+
+
+ ret = dhd_preinit_ioctls(dhd);
+
+ /* Always assumes wl for now */
+ dhd->iswl = TRUE;
+
+done:
+ return ret;
+}
+
+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/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c
new file mode 100644
index 000000000000..17e68663df6a
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c
@@ -0,0 +1,301 @@
+/*
+ * Linux cfg80211 driver - Dongle Host Driver (DHD) related
+ *
+ * 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: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $
+ */
+
+#include <linux/vmalloc.h>
+#include <net/rtnetlink.h>
+
+#include <bcmutils.h>
+#include <wldev_common.h>
+#include <wl_cfg80211.h>
+#include <brcm_nl80211.h>
+#include <dhd_cfg80211.h>
+
+#ifdef PKT_FILTER_SUPPORT
+#include <dngl_stats.h>
+#include <dhd.h>
+#endif
+extern struct bcm_cfg80211 *g_bcm_cfg;
+
+#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 <dngl_stats.h>
+#include <dhd.h>
+#include <dhdioctl.h>
+#include <wlioctl.h>
+#include <dhd_cfg80211.h>
+
+static s32 wl_dongle_up(struct net_device *ndev, u32 up);
+
+/**
+ * Function implementations
+ */
+
+s32 dhd_cfg80211_init(struct 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)
+{
+ 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, char *name,
+ uint8 *mac, uint8 bssidx, 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)
+{
+ return dhd_register_if(cfg->pub, ifidx, FALSE);
+}
+
+int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev)
+{
+ return dhd_remove_if(cfg->pub, ifidx, FALSE);
+}
+
+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, u32 up)
+{
+ s32 err = 0;
+
+ err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_UP error (%d)\n", err));
+ }
+ return err;
+}
+
+s32 dhd_config_dongle(struct 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, 0);
+ if (unlikely(err)) {
+ WL_ERR(("wl_dongle_up failed\n"));
+ goto default_conf_out;
+ }
+ dhd_dongle_up = true;
+
+default_conf_out:
+
+ return err;
+
+}
+
+#ifdef CONFIG_NL80211_TESTMODE
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, void *data, int len)
+#else
+int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
+{
+ struct sk_buff *reply;
+ struct bcm_cfg80211 *cfg;
+ dhd_pub_t *dhd;
+ struct bcm_nlmsg_hdr *nlioc = data;
+ dhd_ioctl_t ioc = { 0 };
+ int err = 0;
+ void *buf = NULL, *cur;
+ u16 buflen;
+ u16 maxmsglen = PAGE_SIZE - 0x100;
+ bool newbuf = false;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+ int8 index = 0;
+ struct net_device *ndev = NULL;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
+
+ WL_TRACE(("entry: cmd = %d\n", nlioc->cmd));
+ cfg = wiphy_priv(wiphy);
+ 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);
+ }
+
+ len -= sizeof(struct bcm_nlmsg_hdr);
+
+ if (nlioc->len > 0) {
+ if (nlioc->len <= len) {
+ buf = (void *)nlioc + nlioc->offset;
+ *(char *)(buf + nlioc->len) = '\0';
+ } else {
+ if (nlioc->len > DHD_IOCTL_MAXLEN)
+ nlioc->len = DHD_IOCTL_MAXLEN;
+ buf = vzalloc(nlioc->len);
+ if (!buf)
+ return -ENOMEM;
+ newbuf = true;
+ memcpy(buf, (void *)nlioc + nlioc->offset, len);
+ *(char *)(buf + len) = '\0';
+ }
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+ 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));
+ return BCME_ERROR;
+}
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
+
+ ioc.cmd = nlioc->cmd;
+ ioc.len = nlioc->len;
+ ioc.set = nlioc->set;
+ ioc.driver = nlioc->magic;
+ err = dhd_ioctl_process(dhd, 0, &ioc, buf);
+ if (err) {
+ WL_TRACE(("dhd_ioctl_process return err %d\n", err));
+ err = OSL_ERROR(err);
+ goto done;
+ }
+
+ cur = buf;
+ while (nlioc->len > 0) {
+ buflen = nlioc->len > maxmsglen ? maxmsglen : nlioc->len;
+ nlioc->len -= buflen;
+ reply = cfg80211_testmode_alloc_reply_skb(wiphy, buflen+4);
+ if (!reply) {
+ WL_ERR(("Failed to allocate reply msg\n"));
+ err = -ENOMEM;
+ break;
+ }
+
+ if (nla_put(reply, BCM_NLATTR_DATA, buflen, cur) ||
+ nla_put_u16(reply, BCM_NLATTR_LEN, buflen)) {
+ kfree_skb(reply);
+ err = -ENOBUFS;
+ break;
+ }
+
+ do {
+ err = cfg80211_testmode_reply(reply);
+ } while (err == -EAGAIN);
+ if (err) {
+ WL_ERR(("testmode reply failed:%d\n", err));
+ break;
+ }
+ cur += buflen;
+ }
+
+done:
+ if (newbuf)
+ vfree(buf);
+ DHD_OS_WAKE_UNLOCK(dhd);
+ return err;
+}
+#endif /* CONFIG_NL80211_TESTMODE */
diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd/dhd_cfg80211.h
new file mode 100644
index 000000000000..f839700218e2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.h
@@ -0,0 +1,59 @@
+/*
+ * Linux cfg80211 driver - Dongle Host Driver (DHD) related
+ *
+ * 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: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $
+ */
+
+
+#ifndef __DHD_CFG80211__
+#define __DHD_CFG80211__
+
+#include <wl_cfg80211.h>
+#include <wl_cfgp2p.h>
+
+s32 dhd_cfg80211_init(struct 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);
+
+#ifdef CONFIG_NL80211_TESTMODE
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, void *data, int len);
+#else
+int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, void *data, int len);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
+#else
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+static inline int
+dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, void *data, int len)
+#else
+static inline int dhd_cfg80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
+{
+ return 0;
+}
+#endif /* CONFIG_NL80211_TESTMODE */
+
+#endif /* __DHD_CFG80211__ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c
new file mode 100644
index 000000000000..c45b1e166375
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_common.c
@@ -0,0 +1,2640 @@
+/*
+ * Broadcom Dongle Host Driver (DHD), common DHD core.
+ *
+ * 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: dhd_common.c 662961 2016-11-24 01:22:35Z $
+ */
+#include <typedefs.h>
+#include <osl.h>
+
+#include <epivers.h>
+#include <bcmutils.h>
+
+#include <bcmendian.h>
+#include <dngl_stats.h>
+#include <wlioctl.h>
+#include <dhd.h>
+#include <dhd_ip.h>
+
+#include <proto/bcmevent.h>
+
+#ifdef SHOW_LOGTRACE
+#include <event_log.h>
+#endif /* SHOW_LOGTRACE */
+
+#include <dhd_bus.h>
+#include <dhd_proto.h>
+#include <dhd_dbg.h>
+#include <msgtrace.h>
+
+#ifdef WL_CFG80211
+#include <wl_cfg80211.h>
+#endif
+#ifdef PNO_SUPPORT
+#include <dhd_pno.h>
+#endif
+#ifdef SET_RANDOM_MAC_SOFTAP
+#include <linux/random.h>
+#include <linux/jiffies.h>
+#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 <wlfc_proto.h>
+#include <dhd_wlfc.h>
+#endif
+
+#ifdef WLMEDIA_HTSF
+extern void htsf_update(struct dhd_info *dhd, void *data);
+#endif
+int dhd_msg_level = DHD_ERROR_VAL;
+
+
+#include <wl_iw.h>
+
+#ifdef SOFTAP
+char fw_path2[MOD_PARAM_PATHLEN];
+extern bool softap_enabled;
+#endif
+
+/* 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
+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 */
+
+#if defined(DHD_VERSION_NO_DATE_TIME)
+const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR DHD_COMPILED;
+#else
+#if defined(DHD_DEBUG)
+const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR
+ DHD_COMPILED " on " __DATE__ " at " __TIME__;
+#else
+const char dhd_version[] = "\nDongle Host Driver, version " EPI_VERSION_STR "\nCompiled from ";
+#endif
+#endif /* DHD_VERSION_NO_DATE_TIME */
+
+void dhd_set_timer(void *bus, uint wdtick);
+
+/* IOVar table */
+enum {
+ IOV_VERSION = 1,
+ IOV_MSGLEVEL,
+ IOV_BCMERRORSTR,
+ IOV_BCMERROR,
+ IOV_WDTICK,
+ IOV_DUMP,
+ IOV_CLEARCOUNTS,
+ IOV_LOGDUMP,
+ IOV_LOGCAL,
+ IOV_LOGSTAMP,
+ IOV_GPIOOB,
+ IOV_IOCTLTIMEOUT,
+#if defined(DHD_DEBUG)
+ IOV_CONS,
+ IOV_DCONSOLE_POLL,
+ IOV_DHD_JOIN_TIMEOUT_DBG,
+ IOV_SCAN_TIMEOUT,
+#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 */
+ IOV_LAST
+};
+
+const bcm_iovar_t dhd_iovars[] = {
+ {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) },
+#ifdef DHD_DEBUG
+ {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 },
+#endif /* DHD_DEBUG */
+ {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN },
+ {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 },
+ {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 },
+ {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
+#ifdef DHD_DEBUG
+ {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 },
+ {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 },
+ {"scan_timeout", IOV_SCAN_TIMEOUT, 0, IOVT_UINT32, 0 },
+ {"join_timeout_dbg", IOV_DHD_JOIN_TIMEOUT_DBG, 0, IOVT_UINT32, 0 },
+#endif
+ {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 },
+ {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 },
+ {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 },
+#ifdef PROP_TXSTATUS
+ {"proptx", IOV_PROPTXSTATUS_ENABLE, 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, IOVT_UINT32, 0 },
+ {"proptx_opt", IOV_PROPTXSTATUS_OPT, 0, IOVT_UINT32, 0 },
+ {"pmodule_ignore", IOV_PROPTXSTATUS_MODULE_IGNORE, 0, IOVT_BOOL, 0 },
+ {"pcredit_ignore", IOV_PROPTXSTATUS_CREDIT_IGNORE, 0, IOVT_BOOL, 0 },
+ {"ptxstatus_ignore", IOV_PROPTXSTATUS_TXSTATUS_IGNORE, 0, IOVT_BOOL, 0 },
+ {"rxpkt_chk", IOV_PROPTXSTATUS_RXPKT_CHK, 0, IOVT_BOOL, 0 },
+#endif /* PROP_TXSTATUS */
+ {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0},
+#ifdef WLMEDIA_HTSF
+ {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 },
+#endif
+ {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 },
+ {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, IOVT_BUFFER,
+ (WLHOST_REORDERDATA_MAXFLOWS + 1) },
+#ifdef DHDTCPACK_SUPPRESS
+ {"tcpack_suppress", IOV_TCPACK_SUPPRESS, 0, IOVT_UINT8, 0 },
+#endif /* DHDTCPACK_SUPPRESS */
+ {NULL, 0, 0, 0, 0 }
+};
+
+#define DHD_IOVAR_BUF_SIZE 128
+
+/* to NDIS developer, the structure dhd_common is redundant,
+ * please do NOT merge it back from other branches !!!
+ */
+
+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_multicast %lu tx_errors %lu\n",
+ dhdp->tx_packets, 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, "\n");
+
+ /* Add any prot info */
+ dhd_prot_dump(dhdp, strbuf);
+ bcm_bprintf(strbuf, "\n");
+
+ /* Add any bus info */
+ dhd_bus_dump(dhdp, strbuf);
+
+ return (!strbuf->size ? BCME_BUFTOOSHORT : 0);
+}
+
+int
+dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifindex)
+{
+ wl_ioctl_t ioc;
+
+ ioc.cmd = cmd;
+ ioc.buf = arg;
+ ioc.len = len;
+ ioc.set = set;
+
+ return dhd_wl_ioctl(dhd_pub, ifindex, &ioc, arg, len);
+}
+
+
+int
+dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len)
+{
+ int ret = 0;
+
+ if (dhd_os_proto_block(dhd_pub))
+ {
+
+ ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len);
+ if ((ret) && (dhd_pub->up))
+ /* Send hang event only if dhd_open() was success */
+ dhd_os_check_hang(dhd_pub, ifindex, 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;
+ }
+
+ dhd_os_proto_unblock(dhd_pub);
+
+
+ }
+
+ return ret;
+}
+
+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;
+
+ 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 */
+ bcm_strncpy_s((char*)arg, len, dhd_version, len);
+ break;
+
+ case IOV_GVAL(IOV_MSGLEVEL):
+ int_val = (int32)dhd_msg_level;
+ bcopy(&int_val, arg, val_size);
+ break;
+
+ case IOV_SVAL(IOV_MSGLEVEL):
+#ifdef WL_CFG80211
+ /* Enable DHD and WL logs in oneshot */
+ if (int_val & DHD_WL_VAL2)
+ wl_cfg80211_enable_trace(TRUE, int_val & (~DHD_WL_VAL2));
+ else if (int_val & DHD_WL_VAL)
+ wl_cfg80211_enable_trace(FALSE, WL_DBG_DBG);
+ if (!(int_val & DHD_WL_VAL2))
+#endif /* WL_CFG80211 */
+ 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;
+
+ case IOV_GVAL(IOV_WDTICK):
+ int_val = (int32)dhd_watchdog_ms;
+ bcopy(&int_val, arg, val_size);
+ break;
+
+ case IOV_SVAL(IOV_WDTICK):
+ if (!dhd_pub->up) {
+ bcmerror = BCME_NOTUP;
+ break;
+ }
+ dhd_os_wd_timer(dhd_pub, (uint)int_val);
+ break;
+
+ case IOV_GVAL(IOV_DUMP):
+ bcmerror = dhd_dump(dhd_pub, arg, len);
+ break;
+
+#ifdef DHD_DEBUG
+ case IOV_GVAL(IOV_SCAN_TIMEOUT):
+ {
+ uint32 scan_timeout = dhd_get_scan_timeout(dhd_pub);
+ bcopy(&scan_timeout, arg, sizeof(scan_timeout));
+ break;
+ }
+ case IOV_SVAL(IOV_SCAN_TIMEOUT):
+ {
+ uint32 scan_timeout;
+ bcopy(((uint8*)params), &scan_timeout, sizeof(scan_timeout));
+ dhd_set_scan_timeout(dhd_pub, scan_timeout);
+ break;
+ }
+ case IOV_GVAL(IOV_DHD_JOIN_TIMEOUT_DBG):
+ {
+ uint32 join_timeout = dhd_get_join_timeout(dhd_pub);
+ bcopy(&join_timeout, arg, sizeof(join_timeout));
+ break;
+ }
+ case IOV_SVAL(IOV_DHD_JOIN_TIMEOUT_DBG):
+ {
+ uint32 join_timeout;
+ bcopy(((uint8*)params), &join_timeout, sizeof(join_timeout));
+ dhd_set_join_timeout(dhd_pub, join_timeout);
+ break;
+ }
+#endif /* DHD_DEBUG */
+
+#ifdef DHD_DEBUG
+ 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)
+ bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1);
+ break;
+#endif /* DHD_DEBUG */
+
+ 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->rx_dropped = 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 */
+ 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 BCMDHDUSB
+ int_val = BUS_TYPE_USB;
+#endif
+ int_val = BUS_TYPE_SDIO;
+#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 */
+
+ 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;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ if (!buf) {
+ return BCME_BADARG;
+ }
+
+ 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;
+
+ /* scan past the name to any arguments */
+ for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--)
+ ;
+
+ if (*arg) {
+ bcmerror = BCME_BUFTOOSHORT;
+ break;
+ }
+
+ /* 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)
+ break;
+
+ /* 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)
+ break;
+
+ /* 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);
+ }
+
+ break;
+ }
+ default:
+ bcmerror = BCME_UNSUPPORTED;
+ }
+
+ return bcmerror;
+}
+
+#ifdef SHOW_EVENTS
+#ifdef SHOW_LOGTRACE
+
+#define MAX_NO_OF_ARG 16
+
+#define FMTSTR_SIZE 100
+#define SIZE_LOC_STR 50
+#define MIN_DLEN 4
+#define TAG_BYTES 12
+#define TAG_WORDS 3
+
+static int
+check_event_log_sequence_number(uint32 seq_no)
+{
+ int32 diff;
+ uint32 ret;
+ static uint32 logtrace_seqnum_prev = 0;
+
+ diff = ntoh32(seq_no)-logtrace_seqnum_prev;
+ switch (diff)
+ {
+ case 0:
+ ret = -1; /* duplicate packet . drop */
+ break;
+
+ case 1:
+ ret =0; /* in order */
+ break;
+
+ default:
+ if ((ntoh32(seq_no) == 0) &&
+ (logtrace_seqnum_prev == 0xFFFFFFFF) ) { /* in-order - Roll over */
+ ret = 0;
+ } else {
+
+ if (diff > 0) {
+ DHD_EVENT(("WLC_E_TRACE:"
+ "Event lost (log) seqnum %d nblost %d\n",
+ ntoh32(seq_no), (diff-1)));
+ } else {
+ DHD_EVENT(("WLC_E_TRACE:"
+ "Event Packets coming out of order!!\n"));
+ }
+ ret = 0;
+ }
+ }
+
+ logtrace_seqnum_prev = ntoh32(seq_no);
+
+ return ret;
+}
+
+static void
+dhd_eventmsg_print(dhd_pub_t *dhd_pub, void *event_data, void *raw_event_ptr,
+ uint datalen, const char *event_name)
+{
+ msgtrace_hdr_t hdr;
+ uint32 nblost;
+ uint8 count;
+ char *s, *p;
+ static uint32 seqnum_prev = 0;
+ uint32 *log_ptr = NULL;
+ uchar *buf;
+ event_log_hdr_t event_hdr;
+ uint32 i;
+ int32 j;
+
+ dhd_event_log_t *raw_event = (dhd_event_log_t *) raw_event_ptr;
+
+ char fmtstr_loc_buf[FMTSTR_SIZE] = {0};
+ char (*str_buf)[SIZE_LOC_STR] = NULL;
+ char * str_tmpptr = NULL;
+ uint32 addr = 0;
+ uint32 **hdr_ptr = NULL;
+ uint32 h_i = 0;
+ uint32 hdr_ptr_len = 0;
+
+ typedef union {
+ uint32 val;
+ char * addr;
+ } u_arg;
+ u_arg arg[MAX_NO_OF_ARG] = {{0}};
+ char *c_ptr = NULL;
+
+ buf = (uchar *) event_data;
+ memcpy(&hdr, buf, MSGTRACE_HDRLEN);
+
+ if (hdr.version != MSGTRACE_VERSION) {
+ DHD_EVENT(("\nMACEVENT: %s [unsupported version --> "
+ "dhd version:%d dongle version:%d]\n",
+ event_name, MSGTRACE_VERSION, hdr.version));
+ /* Reset datalen to avoid display below */
+ datalen = 0;
+ return;
+ }
+
+ if (hdr.trace_type == MSGTRACE_HDR_TYPE_MSG) {
+ /* There are 2 bytes available at the end of data */
+ buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0';
+
+ if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) {
+ DHD_EVENT(("WLC_E_TRACE: [Discarded traces in dongle -->"
+ "discarded_bytes %d discarded_printf %d]\n",
+ ntoh32(hdr.discarded_bytes),
+ ntoh32(hdr.discarded_printf)));
+ }
+
+ nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1;
+ if (nblost > 0) {
+ DHD_EVENT(("WLC_E_TRACE:"
+ "[Event lost (msg) --> seqnum %d nblost %d\n",
+ ntoh32(hdr.seqnum), nblost));
+ }
+ seqnum_prev = ntoh32(hdr.seqnum);
+
+ /* Display the trace buffer. Advance from
+ * \n to \n to avoid display big
+ * printf (issue with Linux printk )
+ */
+ p = (char *)&buf[MSGTRACE_HDRLEN];
+ while (*p != '\0' && (s = strstr(p, "\n")) != NULL) {
+ *s = '\0';
+ DHD_EVENT(("%s\n", p));
+ p = s+1;
+ }
+ if (*p)
+ DHD_EVENT(("%s", p));
+
+ /* Reset datalen to avoid display below */
+ datalen = 0;
+
+ } else if (hdr.trace_type == MSGTRACE_HDR_TYPE_LOG) {
+ /* Let the standard event printing work for now */
+ uint32 timestamp, w;
+
+ if (check_event_log_sequence_number(hdr.seqnum)) {
+ DHD_EVENT(("%s: WLC_E_TRACE:"
+ "[Event duplicate (log) %d] dropping!!\n",
+ __FUNCTION__, hdr.seqnum));
+ return; /* drop duplicate events */
+ }
+
+ p = (char *)&buf[MSGTRACE_HDRLEN];
+ datalen -= MSGTRACE_HDRLEN;
+ w = ntoh32((uint32)*p);
+ p += MIN_DLEN;
+ datalen -= MIN_DLEN;
+ timestamp = ntoh32((uint32)*p);
+ BCM_REFERENCE(timestamp);
+ BCM_REFERENCE(w);
+
+ /*
+ * Allocating max possible number of event TAGs in the received buffer
+ * considering that each event requires minimum of TAG_BYTES.
+ */
+ hdr_ptr_len = ((datalen/TAG_BYTES)+1) * sizeof(uint32*);
+
+ if ((raw_event->fmts)) {
+ if (!(str_buf = MALLOC(dhd_pub->osh, (MAX_NO_OF_ARG * SIZE_LOC_STR)))) {
+ DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
+ }
+
+ if (!(hdr_ptr = MALLOC(dhd_pub->osh, hdr_ptr_len))) {
+ DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
+ }
+ }
+
+ DHD_EVENT(("timestamp %x%x\n", timestamp, w));
+ if ((!raw_event->fmts) || (!str_buf) || (!hdr_ptr)) {
+ while (datalen > MIN_DLEN) {
+ p += MIN_DLEN;
+ datalen -= MIN_DLEN;
+ /* Print each word. DO NOT ntoh it. */
+ DHD_EVENT((" %8.8x", *((uint32 *) p)));
+ }
+ DHD_EVENT(("\n"));
+ datalen = 0;
+ if (str_buf) {
+ MFREE(dhd_pub->osh, str_buf, (MAX_NO_OF_ARG * SIZE_LOC_STR));
+ }
+ if (hdr_ptr) {
+ MFREE(dhd_pub->osh, hdr_ptr, hdr_ptr_len);
+ }
+ return;
+ }
+
+ /* (raw_event->fmts) has value */
+
+ log_ptr = (uint32 *) (p + datalen);
+
+ while (datalen > MIN_DLEN) {
+ log_ptr--;
+ datalen -= MIN_DLEN;
+ event_hdr.t = *log_ptr;
+ /*
+ * Check for partially overriten entries
+ */
+ if (log_ptr - (uint32 *) p < event_hdr.count) {
+ break;
+ }
+ /*
+ * Check for end of the Frame.
+ */
+ if (event_hdr.tag == EVENT_LOG_TAG_NULL) {
+ continue;
+ }
+ /*
+ * Check For Special Time Stamp Packet
+ */
+ if (event_hdr.tag == EVENT_LOG_TAG_TS) {
+ datalen -= TAG_BYTES;
+ log_ptr = log_ptr - TAG_WORDS;
+ continue;
+ }
+
+ log_ptr[0] = event_hdr.t;
+ if (h_i < (hdr_ptr_len / sizeof(uint32*))) {
+ hdr_ptr[h_i++] = log_ptr;
+ }
+ if (event_hdr.count > MAX_NO_OF_ARG) {
+ break;
+ }
+
+ /* Now place the header at the front
+ * and copy back.
+ */
+ log_ptr -= event_hdr.count;
+
+ c_ptr = NULL;
+ datalen = datalen - (event_hdr.count * MIN_DLEN);
+ }
+ datalen = 0;
+
+ for (j = (h_i-1); j >= 0; j--) {
+ if (!(hdr_ptr[j])) {
+ break;
+ }
+
+ event_hdr.t = *hdr_ptr[j];
+
+ log_ptr = hdr_ptr[j];
+
+ /* Now place the header at the front
+ * and copy back.
+ */
+ log_ptr -= event_hdr.count;
+
+ /* Copy the format string to parse %s and add "CONSOLE: " ??? */
+ if ((event_hdr.fmt_num >> 2) < raw_event->num_fmts) {
+ snprintf(fmtstr_loc_buf, FMTSTR_SIZE,
+ "CONSOLE: [0x%x] %s", log_ptr[event_hdr.count-1],
+ raw_event->fmts[event_hdr.fmt_num >> 2]);
+ c_ptr = fmtstr_loc_buf;
+ }
+
+ for (count = 0; count < (event_hdr.count-1); count++) {
+ if (c_ptr != NULL) {
+ if ((c_ptr = strstr(c_ptr, "%")) != NULL) {
+ c_ptr++;
+ }
+ }
+
+ if ((c_ptr != NULL) && (*c_ptr == 's')) {
+ 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];
+ }
+ }
+
+ DHD_EVENT((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]));
+
+ for (i = 0; i < MAX_NO_OF_ARG; i++) {
+ arg[i].addr = 0;
+ }
+ for (i = 0; i < MAX_NO_OF_ARG; i++) {
+ memset(str_buf[i], 0, SIZE_LOC_STR);
+ }
+
+ }
+
+ if (str_buf) {
+ MFREE(dhd_pub->osh, str_buf, (MAX_NO_OF_ARG * SIZE_LOC_STR));
+ }
+
+ if (hdr_ptr) {
+ MFREE(dhd_pub->osh, hdr_ptr, hdr_ptr_len);
+ }
+ }
+}
+
+#endif /* SHOW_LOGTRACE */
+
+static void
+wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data,
+ void *raw_event_ptr)
+{
+ uint i, status, reason;
+ bool group = FALSE, flush_txq = FALSE, link = FALSE;
+ 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 = "UNKNOWN";
+ for (i = 0; i < (uint)bcmevent_names_size; i++)
+ if (bcmevent_names[i].event == event_type)
+ event_name = bcmevent_names[i].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));
+ } else 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\n", event_name, eabuf));
+ break;
+
+ case WLC_E_SCAN_COMPLETE:
+ case WLC_E_ASSOC_REQ_IE:
+ case WLC_E_ASSOC_RESP_IE:
+ case WLC_E_PMKID_CACHE:
+ DHD_EVENT(("MACEVENT: %s\n", event_name));
+ break;
+
+ 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:
+ 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));
+ 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_eventmsg_print(dhd_pub, event_data, raw_event_ptr, datalen, event_name);
+ 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;
+
+ 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_PKT_FILTER:
+ if (status == WLC_E_PKT_FILTER_TIMEOUT)
+ DHD_EVENT(("MACEVENT: %s, Timeout(Pkt Filter Id=%d)\n", event_name, reason));
+ else
+ DHD_EVENT(("MACEVENT: %s, status %d reason %d\n", event_name, status, reason));
+ break;
+
+ 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 (DHD_BYTES_ON() && DHD_EVENT_ON() && datalen) {
+ buf = (uchar *) event_data;
+ DHD_EVENT((" data (%d) : ", datalen));
+ for (i = 0; i < datalen; i++)
+ DHD_EVENT((" 0x%02x ", *buf++));
+ DHD_EVENT(("\n"));
+ }
+}
+#endif /* SHOW_EVENTS */
+
+/* Check whether packet is a BRCM event pkt. If it is, record event data. */
+int
+wl_host_event_get_data(void *pktdata, uint pktlen, wl_event_msg_t *evt)
+{
+ int ret;
+
+ ret = is_wlc_event_frame(pktdata, pktlen, 0, evt);
+ if (ret != BCME_OK) {
+ DHD_ERROR(("%s: Invalid event frame, err = %d\n",
+ __FUNCTION__, ret));
+ }
+
+ return ret;
+}
+
+int
+wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint16 pktlen,
+ wl_event_msg_t *event, void **data_ptr, void *raw_event)
+{
+ /* check whether packet is a BRCM event pkt */
+ bcm_event_t *pvt_data = (bcm_event_t *)pktdata;
+ uint8 *event_data;
+ uint32 type, status, datalen;
+ uint16 flags;
+ uint evlen;
+ int ret;
+
+ ret = wl_host_event_get_data(pktdata, pktlen, event);
+ if (ret != BCME_OK) {
+ return ret;
+ }
+
+ *data_ptr = &pvt_data[1];
+ event_data = *data_ptr;
+
+ /* memcpy since BRCM event pkt may be unaligned. */
+ memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t));
+
+ 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);
+
+ if (datalen > pktlen)
+ return (BCME_ERROR);
+
+ evlen = datalen + sizeof(bcm_event_t);
+
+ if (evlen > pktlen)
+ return (BCME_ERROR);
+
+ switch (type) {
+#ifdef DHD_DEBUG
+ case WLC_E_JOIN_START:
+ case WLC_E_ROAM_START:
+ dhd_start_join_timer(dhd_pub);
+ break;
+ case WLC_E_ASSOC:
+ case WLC_E_REASSOC:
+ if ((status != WLC_E_STATUS_TIMEOUT) && (status != WLC_E_STATUS_FAIL))
+ break;
+ case WLC_E_SET_SSID:
+ if (status != WLC_E_STATUS_SUCCESS)
+ break;
+ case WLC_E_JOIN:
+ case WLC_E_ROAM:
+ dhd_del_join_timer(dhd_pub);
+ break;
+
+ case WLC_E_SCAN_CONFIRM_IND:
+ dhd_add_scan_timer(dhd_pub);
+ break;
+
+ case WLC_E_ESCAN_RESULT:
+ dhd_del_scan_timer(dhd_pub);
+ break;
+#endif /* DHD_DEBUG */
+#ifdef PROP_TXSTATUS
+ case WLC_E_FIFO_CREDIT_MAP:
+ if (dhd_wlfc_enable(dhd_pub) != BCME_OK) {
+ DHD_ERROR(("%s: dhd_wlfc_enable failed\n", __FUNCTION__));
+ return (BCME_ERROR);
+ }
+ 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;
+#endif /* PROP_TXSTATUS */
+
+ 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 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) {
+ dhd_event_ifdel(dhd_pub->info, ifevent, event->ifname,
+ event->addr.octet);
+ } else if (ifevent->opcode == WLC_E_IF_CHANGE) {
+#ifdef WL_CFG80211
+ wl_cfg80211_notify_ifchange(ifevent->ifidx,
+ event->ifname, event->addr.octet, ifevent->bssidx);
+#endif /* WL_CFG80211 */
+ }
+ } else {
+#ifndef PROP_TXSTATUS
+ DHD_ERROR(("%s: Invalid ifidx %d for %s\n",
+ __FUNCTION__, ifevent->ifidx, event->ifname));
+#endif /* !PROP_TXSTATUS */
+ }
+
+ /* 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: {
+ uint32 temp = hton32(WLC_E_LINK);
+
+ memcpy((void *)(&pvt_data->event.event_type), &temp,
+ sizeof(pvt_data->event.event_type));
+ }
+ case WLC_E_PFN_NET_FOUND:
+ case WLC_E_PFN_NET_LOST:
+ break;
+#if defined(PNO_SUPPORT)
+ case WLC_E_PFN_BSSID_NET_FOUND:
+ case WLC_E_PFN_BSSID_NET_LOST:
+ case WLC_E_PFN_BEST_BATCHING:
+ dhd_pno_event_handler(dhd_pub, event, (void *)event_data);
+ break;
+#endif
+ /* These are what external supplicant/authenticator wants */
+ /* fall through */
+ case WLC_E_LINK:
+ case WLC_E_DEAUTH:
+ case WLC_E_DEAUTH_IND:
+ case WLC_E_DISASSOC:
+ case WLC_E_DISASSOC_IND:
+ DHD_EVENT(("%s: Link event %d, flags %x, status %x\n",
+ __FUNCTION__, type, flags, status));
+ /* fall through */
+ default:
+ *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
+ /* 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;
+ }
+
+#ifdef SHOW_EVENTS
+ wl_show_host_event(dhd_pub, event, (void *)event_data, raw_event);
+#endif /* SHOW_EVENTS */
+
+ return (BCME_OK);
+}
+
+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
+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
+
+#ifdef PKT_FILTER_SUPPORT
+/* Convert user's input in hex pattern to byte-size mask */
+static 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;
+}
+
+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[128];
+ 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: kmalloc 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), str, str_len);
+ buf[str_len] = '\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));
+
+ /* 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_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
+ __FUNCTION__, arg, rc));
+ else
+ DHD_TRACE(("%s: successfully added pktfilter %s\n",
+ __FUNCTION__, arg));
+
+ /* Contorl the master mode */
+ bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf));
+ rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
+ rc = rc >= 0 ? 0 : rc;
+ if (rc)
+ DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
+ __FUNCTION__, arg, rc));
+
+fail:
+ if (arg_org)
+ MFREE(dhd->osh, arg_org, strlen(arg) + 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[8], * 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: kmalloc failed\n", __FUNCTION__));
+ goto fail;
+ }
+
+ arg_org = arg_save;
+
+ if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) {
+ DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+ goto fail;
+ }
+
+ 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 (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 (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);
+
+ rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
+ rc = rc >= 0 ? 0 : rc;
+
+ if (rc)
+ DHD_TRACE(("%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)
+{
+ char iovbuf[32];
+ int ret;
+
+ bcm_mkiovar("pkt_filter_delete", (char *)&id, 4, iovbuf, sizeof(iovbuf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ if (ret < 0) {
+ DHD_ERROR(("%s: Failed to delete filter ID:%d, ret=%d\n",
+ __FUNCTION__, id, ret));
+ }
+}
+#endif /* PKT_FILTER_SUPPORT */
+
+/* ========================== */
+/* ==== ARP OFFLOAD SUPPORT = */
+/* ========================== */
+#ifdef ARP_OFFLOAD_SUPPORT
+void
+dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode)
+{
+ char iovbuf[DHD_IOVAR_BUF_SIZE];
+ int iovar_len;
+ int retcode;
+
+ iovar_len = bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
+ if (!iovar_len) {
+ DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
+ __FUNCTION__, sizeof(iovbuf)));
+ return;
+ }
+
+ retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iovar_len, TRUE, 0);
+ retcode = retcode >= 0 ? 0 : retcode;
+ if (retcode)
+ DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n",
+ __FUNCTION__, arp_mode, retcode));
+ else
+ DHD_TRACE(("%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)
+{
+ char iovbuf[DHD_IOVAR_BUF_SIZE];
+ int iovar_len;
+ int retcode;
+
+ iovar_len = bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf));
+ if (!iovar_len) {
+ DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
+ __FUNCTION__, sizeof(iovbuf)));
+ return;
+ }
+
+ retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iovar_len, TRUE, 0);
+ retcode = retcode >= 0 ? 0 : retcode;
+ if (retcode)
+ DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n",
+ __FUNCTION__, arp_enable, retcode));
+ else
+ DHD_TRACE(("%s: successfully enabed ARP offload to %d\n",
+ __FUNCTION__, arp_enable));
+ if (arp_enable) {
+ uint32 version;
+ bcm_mkiovar("arp_version", 0, 0, iovbuf, sizeof(iovbuf));
+ retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
+ if (retcode) {
+ DHD_INFO(("%s: fail to get version (maybe version 1:retcode = %d\n",
+ __FUNCTION__, retcode));
+ dhd->arp_version = 1;
+ }
+ else {
+ memcpy(&version, iovbuf, sizeof(version));
+ 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;
+ int iov_len = 0;
+ char iovbuf[DHD_IOVAR_BUF_SIZE];
+
+ if (dhd == NULL) return;
+ if (dhd->arp_version == 1)
+ idx = 0;
+
+ iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf));
+ if (!iov_len) {
+ DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
+ __FUNCTION__, sizeof(iovbuf)));
+ return;
+ }
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 0)
+ DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
+}
+
+void
+dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx)
+{
+ int ret = 0;
+ int iov_len = 0;
+ char iovbuf[DHD_IOVAR_BUF_SIZE];
+
+ if (dhd == NULL) return;
+ if (dhd->arp_version == 1)
+ idx = 0;
+
+ iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf));
+ if (!iov_len) {
+ DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
+ __FUNCTION__, sizeof(iovbuf)));
+ return;
+ }
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 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 iov_len = 0;
+ char iovbuf[DHD_IOVAR_BUF_SIZE];
+ int retcode;
+
+
+ if (dhd == NULL) return;
+ if (dhd->arp_version == 1)
+ idx = 0;
+ iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr,
+ sizeof(ipaddr), iovbuf, sizeof(iovbuf));
+ if (!iov_len) {
+ DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
+ __FUNCTION__, sizeof(iovbuf)));
+ return;
+ }
+ retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
+
+ if (retcode)
+ DHD_TRACE(("%s: ARP ip addr add failed, retcode = %d\n",
+ __FUNCTION__, retcode));
+ else
+ DHD_TRACE(("%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 retcode, i;
+ int iov_len;
+ uint32 *ptr32 = buf;
+ bool clr_bottom = FALSE;
+
+ if (!buf)
+ return -1;
+ if (dhd == NULL) return -1;
+ if (dhd->arp_version == 1)
+ idx = 0;
+
+ iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen);
+ BCM_REFERENCE(iov_len);
+ retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, idx);
+
+ if (retcode) {
+ DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n",
+ __FUNCTION__, retcode));
+
+ 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)
+{
+ char iovbuf[DHD_IOVAR_BUF_SIZE];
+ int iov_len;
+ int retcode;
+
+ if (dhd == NULL)
+ return -1;
+
+ iov_len = bcm_mkiovar("ndoe", (char *)&ndo_enable, 4, 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, 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];
+ 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];
+ 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;
+}
+
+/* send up locally generated event */
+void
+dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
+{
+ switch (ntoh32(event->event_type)) {
+ default:
+ break;
+ }
+
+ /* Call per-port handler. */
+ dhd_sendup_event(dhdp, event, data);
+}
+
+
+/*
+ * 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 */
+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 eixt */
+ if (dtim_period == 0) {
+ goto exit;
+ }
+
+ /* 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));
+ }
+
+ 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;
+}
+
+/* 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[256];
+ const char *str;
+ wl_mkeep_alive_pkt_t mkeep_alive_pkt = {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, str_len);
+ buf[ str_len ] = '\0';
+ mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1);
+ mkeep_alive_pkt.period_msec = CUSTOM_KEEP_ALIVE_SETTING;
+ 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) */
+/* 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;
+}
+
+/*
+ * SSIDs list parsing from cscan tlv list
+ */
+int
+wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_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;
+
+ 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;
+
+ 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;
+}
+
+/* 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;
+}
diff --git a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c
new file mode 100644
index 000000000000..307d2f1b8b8d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c
@@ -0,0 +1,300 @@
+/*
+* Customer code to add GPIO control during WLAN start/stop
+* 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: dhd_custom_gpio.c 493803 2014-07-29 12:31:48Z $
+*/
+
+#include <typedefs.h>
+#include <linuxver.h>
+#include <osl.h>
+#include <bcmutils.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_linux.h>
+
+#include <wlioctl.h>
+#include <wl_iw.h>
+
+#define WL_ERROR(x) printf x
+#define WL_TRACE(x)
+
+#if defined(CUSTOMER_HW2)
+
+
+#endif
+
+#if defined(OOB_INTR_ONLY)
+
+#if defined(BCMLXSDMMC)
+extern int sdioh_mmc_irq(int irq);
+#endif /* (BCMLXSDMMC) */
+
+#if defined(CUSTOMER_HW3)
+#include <mach/gpio.h>
+#endif
+
+/* 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));
+
+#if defined(CUSTOMER_HW3)
+ gpio_request(dhd_oob_gpio_num, "oob irq");
+ host_oob_irq = gpio_to_irq(dhd_oob_gpio_num);
+ gpio_direction_input(dhd_oob_gpio_num);
+#endif /* defined CUSTOMER_HW3 */
+#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 get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec)
+{
+#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+
+ struct cntry_locales_custom *cloc_ptr;
+
+ if (!cspec)
+ return;
+
+ cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_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/drivers/net/wireless/bcmdhd/dhd_dbg.h b/drivers/net/wireless/bcmdhd/dhd_dbg.h
new file mode 100644
index 000000000000..164f8aa8c07e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_dbg.h
@@ -0,0 +1,123 @@
+/*
+ * Debug/trace/assert driver definitions for Dongle Host Driver.
+ *
+ * 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: dhd_dbg.h 424863 2013-09-19 20:06:14Z $
+ */
+
+#ifndef _dhd_dbg_
+#define _dhd_dbg_
+
+#define USE_NET_RATELIMIT 1
+
+#if defined(DHD_DEBUG)
+
+#define DHD_ERROR(args) do {if ((dhd_msg_level & DHD_ERROR_VAL) && USE_NET_RATELIMIT) \
+ printf args;} while (0)
+#define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) printf args;} while (0)
+#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0)
+#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0)
+#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)
+#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0)
+#define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) printf args;} while (0)
+#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_TRACE_HW4 DHD_TRACE
+
+#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_BTA_ON() (dhd_msg_level & DHD_BTA_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)
+
+#else /* defined(BCMDBG) || defined(DHD_DEBUG) */
+
+#define DHD_ERROR(args) do {if (USE_NET_RATELIMIT) printf args;} while (0)
+#define DHD_TRACE(args)
+#define DHD_INFO(args)
+#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)
+#define DHD_EVENT(args)
+#define DHD_BTA(args)
+#define DHD_ISCAN(args)
+#define DHD_ARPOE(args)
+#define DHD_REORDER(args)
+#define DHD_PNO(args)
+
+#define DHD_TRACE_HW4 DHD_TRACE
+
+#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_BTA_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
+
+#endif
+
+#define DHD_LOG(args)
+
+#define DHD_BLOG(cp, size)
+
+#define DHD_NONE(args)
+extern int dhd_msg_level;
+
+/* Defines msg bits */
+#include <dhdioctl.h>
+
+#endif /* _dhd_dbg_ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_ip.c b/drivers/net/wireless/bcmdhd/dhd_ip.c
new file mode 100644
index 000000000000..45d26c5b40ba
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_ip.c
@@ -0,0 +1,965 @@
+/*
+ * IP Packet Parser Module.
+ *
+ * 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: dhd_ip.c 529177 2015-01-26 12:49:53Z $
+ */
+#include <typedefs.h>
+#include <osl.h>
+
+#include <proto/ethernet.h>
+#include <proto/vlan.h>
+#include <proto/802.3.h>
+#include <proto/bcmip.h>
+#include <bcmendian.h>
+
+#include <dhd_dbg.h>
+
+#include <dhd_ip.h>
+
+#ifdef DHDTCPACK_SUPPRESS
+#include <dhd_bus.h>
+#include <proto/bcmtcp.h>
+#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 */
+} 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;
+}
+
+int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode)
+{
+ int ret = BCME_OK;
+
+ dhd_os_tcpacklock(dhdp);
+
+ if (dhdp->tcpack_sup_mode == mode) {
+ DHD_ERROR(("%s %d: already set to %d\n", __FUNCTION__, __LINE__, mode));
+ goto exit;
+ }
+
+ if (mode > TCPACK_SUP_DELAYTX) {
+ DHD_ERROR(("%s %d: Invalid mode %d\n", __FUNCTION__, __LINE__, mode));
+ ret = BCME_BADARG;
+ goto exit;
+ }
+
+ DHD_TRACE(("%s: %d -> %d\n",
+ __FUNCTION__, dhdp->tcpack_sup_mode, mode));
+
+ /* Old tcpack_sup_mode is TCPACK_SUP_DELAYTX */
+ if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX) {
+ tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module;
+ /* We won't need tdata_psh_info pool and tcpddata_info_tbl anymore */
+ _tdata_psh_info_pool_deinit(dhdp, tcpack_sup_mod);
+ tcpack_sup_mod->tcpdata_info_cnt = 0;
+ bzero(tcpack_sup_mod->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);
+ }
+
+ dhdp->tcpack_sup_mode = mode;
+
+ if (mode == TCPACK_SUP_OFF) {
+ ASSERT(dhdp->tcpack_sup_module != NULL);
+ MFREE(dhdp->osh, dhdp->tcpack_sup_module, sizeof(tcpack_sup_module_t));
+ dhdp->tcpack_sup_module = NULL;
+ goto exit;
+ }
+
+ if (dhdp->tcpack_sup_module == NULL) {
+ tcpack_sup_module_t *tcpack_sup_mod =
+ MALLOC(dhdp->osh, sizeof(tcpack_sup_module_t));
+ if (tcpack_sup_mod == NULL) {
+ DHD_ERROR(("%s %d: No MEM\n", __FUNCTION__, __LINE__));
+ dhdp->tcpack_sup_mode = TCPACK_SUP_OFF;
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+ bzero(tcpack_sup_mod, sizeof(tcpack_sup_module_t));
+ dhdp->tcpack_sup_module = tcpack_sup_mod;
+ }
+
+ if (mode == TCPACK_SUP_DELAYTX) {
+ ret = _tdata_psh_info_pool_init(dhdp, dhdp->tcpack_sup_module);
+ if (ret != BCME_OK)
+ DHD_ERROR(("%s %d: pool init fail with %d\n", __FUNCTION__, __LINE__, ret));
+ else if (dhdp->bus)
+ dhd_bus_set_dotxinrx(dhdp->bus, FALSE);
+ }
+
+exit:
+ dhd_os_tcpackunlock(dhdp);
+ return ret;
+}
+
+void
+dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp)
+{
+ tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module;
+
+ if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF)
+ goto exit;
+
+ dhd_os_tcpacklock(dhdp);
+
+ if (!tcpack_sup_mod) {
+ DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n",
+ __FUNCTION__, __LINE__));
+ dhd_os_tcpackunlock(dhdp);
+ goto exit;
+ }
+
+ 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);
+
+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;
+ uint pushed_len;
+ int ret = BCME_OK;
+ void *pdata;
+ uint32 pktlen;
+
+ if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF)
+ goto exit;
+
+ pdata = PKTDATA(dhdp->osh, pkt);
+
+ /* Length of BDC(+WLFC) headers pushed */
+ pushed_len = BDC_HEADER_LEN + (((struct bdc_header *)pdata)->dataOffset * 4);
+ pktlen = PKTLEN(dhdp->osh, pkt) - pushed_len;
+
+ 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;
+ }
+
+ 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);
+ 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);
+
+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;
+
+ 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 */
+ 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);
+ 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
+ DHD_TRACE(("%s %d: lenth mismatch %d != %d || %d != %d\n",
+ __FUNCTION__, __LINE__, new_ip_hdr_len, old_ip_hdr_len,
+ new_tcp_hdr_len, old_tcp_hdr_len));
+ } 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);
+ 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);
+
+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;
+
+ 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]));
+
+ 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);
+ 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);
+ 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);
+ 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);
+
+exit:
+ return ret;
+}
+
+#endif /* DHDTCPACK_SUPPRESS */
diff --git a/drivers/net/wireless/bcmdhd/dhd_ip.h b/drivers/net/wireless/bcmdhd/dhd_ip.h
new file mode 100644
index 000000000000..6ba19ba10849
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_ip.h
@@ -0,0 +1,71 @@
+/*
+ * Header file describing the common ip parser function.
+ *
+ * Provides type definitions and function prototypes used to parse ip packet.
+ *
+ * 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: dhd_ip.h 457888 2014-02-25 03:34:39Z $
+ */
+
+#ifndef _dhd_ip_h_
+#define _dhd_ip_h_
+
+#ifdef DHDTCPACK_SUPPRESS
+#include <dngl_stats.h>
+#include <bcmutils.h>
+#include <dhd.h>
+#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) */
+
+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);
+
+#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/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
new file mode 100644
index 000000000000..caaa5483caa9
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -0,0 +1,8008 @@
+/*
+ * Broadcom Dongle Host Driver (DHD), Linux-specific network interface
+ * Basically selected code segments from usb-cdc.c and usb-rndis.c
+ *
+ * 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: dhd_linux.c 663029 2016-11-30 03:37:26Z $
+ */
+
+#include <typedefs.h>
+#include <linuxver.h>
+#include <osl.h>
+#ifdef SHOW_LOGTRACE
+#include <linux/syscalls.h>
+#include <event_log.h>
+#endif /* SHOW_LOGTRACE */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/etherdevice.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/ip.h>
+#include <net/addrconf.h>
+#include <linux/cpufreq.h>
+
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+#include <epivers.h>
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <bcmdevs.h>
+
+#include <proto/ethernet.h>
+#include <proto/bcmevent.h>
+#include <dngl_stats.h>
+#include <dhd_linux_wq.h>
+#include <dhd.h>
+#include <dhd_linux.h>
+#include <dhd_bus.h>
+#include <dhd_proto.h>
+#include <dhd_dbg.h>
+#ifdef CONFIG_HAS_WAKELOCK
+#include <linux/wakelock.h>
+#endif
+#ifdef WL_CFG80211
+#include <wl_cfg80211.h>
+#endif
+#ifdef CUSTOM_COUNTRY_CODE
+#include <wl_iw.h>
+#endif
+#ifdef P2PONEINT
+#include <wl_cfgp2p.h>
+#endif
+#ifdef PNO_SUPPORT
+#include <dhd_pno.h>
+#endif
+
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+#endif
+
+#ifdef DHDTCPACK_SUPPRESS
+#include <dhd_ip.h>
+#endif /* DHDTCPACK_SUPPRESS */
+
+
+#ifdef WLMEDIA_HTSF
+#include <linux/time.h>
+#include <htsf.h>
+
+#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 */
+
+
+
+#if defined(SOFTAP)
+extern bool ap_cfg_running;
+extern bool ap_fw_loaded;
+#endif
+
+
+#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 <bcm_rpc.h>
+#include <bcm_rpc_tp.h>
+#endif
+#ifdef PROP_TXSTATUS
+#include <wlfc_proto.h>
+#include <dhd_wlfc.h>
+#endif
+
+#include <wl_android.h>
+
+
+#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 */
+
+static 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;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
+#include <linux/suspend.h>
+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)
+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 v2");
+#endif /* LinuxVer */
+
+#include <dhd_bus.h>
+
+#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);
+extern void dhd_wlfc_plat_init(void *dhd);
+extern void dhd_wlfc_plat_deinit(void *dhd);
+#endif /* PROP_TXSTATUS */
+
+#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 <wl_iw.h>
+extern wl_iw_extra_params_t g_wl_iw_params;
+#endif /* defined(WL_WIRELESS_EXT) */
+
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
+#include <linux/earlysuspend.h>
+#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+#include <linux/nl80211.h>
+#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
+
+extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd);
+
+#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
+
+
+#ifdef READ_MACADDR
+extern int dhd_read_macaddr(struct dhd_info *dhd);
+#else
+static inline int dhd_read_macaddr(struct dhd_info *dhd) { return 0; }
+#endif
+#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
+
+#ifdef ENABLE_CONTROL_SCHED
+#ifndef ENABLE_ADAPTIVE_SCHED
+#error ENABLE_ADAPTIVE_SCHED not define.
+#endif /* ENABLE_ADAPTIVE_SCHED */
+static int dhd_sysfs_create_node(struct net_device *net);
+static void dhd_sysfs_destroy_node(struct net_device *net);
+#endif /* ENABLE_CONTROL_SCHED */
+
+
+
+
+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;
+ struct net_device_stats stats;
+ int idx; /* iface idx in dongle */
+ uint subunit; /* subunit */
+ uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */
+ 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 */
+ uint8 bssidx; /* bsscfg index for the interface */
+ bool set_macaddress;
+ bool set_multicast;
+} 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[16];
+ unsigned long event;
+};
+
+/* 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;
+ void *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 */
+
+ /* For supporting multiple interfaces */
+ dhd_if_t *iflist[DHD_MAX_IFS];
+
+ struct semaphore proto_sem;
+#ifdef PROP_TXSTATUS
+ spinlock_t wlfc_spinlock;
+
+#endif /* PROP_TXSTATUS */
+#ifdef WLMEDIA_HTSF
+ htsf_t htsf;
+#endif
+ wait_queue_head_t ioctl_resp_wait;
+ uint32 default_wd_interval;
+
+ struct timer_list timer;
+ bool wd_timer_valid;
+ struct tasklet_struct tasklet;
+ spinlock_t sdlock;
+ spinlock_t txqlock;
+ spinlock_t dhd_lock;
+
+ struct semaphore sdsem;
+ tsk_ctl_t thr_dpc_ctl;
+ tsk_ctl_t thr_wdt_ctl;
+
+ 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 */
+#endif
+
+#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;
+#endif
+ spinlock_t wakelock_spinlock;
+ uint32 wakelock_counter;
+ bool waive_wakelock;
+ uint32 wakelock_before_waive;
+ int wakelock_wd_counter;
+ int wakelock_rx_timeout_enable;
+ int wakelock_ctrl_timeout_enable;
+
+ /* 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;
+ struct timer_list rpcth_timer;
+ bool rpcth_timer_active;
+ bool fdaggr;
+#endif
+#ifdef DHDTCPACK_SUPPRESS
+ spinlock_t tcpack_lock;
+#endif /* DHDTCPACK_SUPPRESS */
+ 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 SAR_SUPPORT
+ struct notifier_block sar_notifier;
+#endif
+#ifdef DHD_DEBUG
+ struct timer_list join_timer;
+ u32 join_timeout_val;
+ bool join_timer_active;
+ uint scan_time_count;
+ struct timer_list scan_timer;
+ bool scan_timer_active;
+#endif
+
+} dhd_info_t;
+
+/* 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];
+
+/* 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)
+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);
+static void dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event);
+
+#ifdef WL_CFG80211
+extern void dhd_netdev_free(struct net_device *ndev);
+#endif /* WL_CFG80211 */
+
+/* Error bits */
+module_param(dhd_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 */
+
+uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY;
+
+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);
+
+/* Watchdog interval */
+
+/* extend watchdog expiration to 2 seconds when DPC is running */
+#define WATCHDOG_EXTEND_INTERVAL (2000)
+
+uint dhd_watchdog_ms = 10;
+module_param(dhd_watchdog_ms, uint, 0);
+
+#if defined(DHD_DEBUG)
+/* Console poll interval */
+uint dhd_console_ms = 0;
+module_param(dhd_console_ms, uint, 0644);
+#endif /* defined(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 */
+uint dhd_master_mode = TRUE;
+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(BCMDHDUSB)
+extern int dhd_dongle_ramsize;
+module_param(dhd_dongle_ramsize, int, 0);
+#endif /* BCMDHDUSB */
+
+/* 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);
+
+/* Control fw roaming */
+uint dhd_roam_disable = 0;
+
+/* 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;
+
+/* 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);
+
+/* 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);
+
+#ifdef BCMDBGFS
+extern void dhd_dbg_init(dhd_pub_t *dhdp);
+extern void dhd_dbg_remove(void);
+#endif /* BCMDBGFS */
+
+
+
+#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 */
+
+
+extern char dhd_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);
+
+#ifdef DHD_DEBUG
+static void dhd_scan_timeout(ulong data);
+static void dhd_join_timeout(ulong data);
+#endif
+
+
+#if defined(WL_WIRELESS_EXT)
+struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
+#endif /* defined(WL_WIRELESS_EXT) */
+
+static void dhd_dpc(ulong data);
+/* 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(SUPPORT_P2P_GO_PS)
+#ifdef PROP_TXSTATUS
+static int dhd_wakelock_waive(dhd_info_t *dhdinfo);
+static int dhd_wakelock_restore(dhd_info_t *dhdinfo);
+#endif
+#endif /* defined(SUPPORT_P2P_GO_PS) */
+
+#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;
+ dhd_info_t *dhdinfo = (dhd_info_t*)container_of(nfb, struct dhd_info, pm_notifier);
+
+ BCM_REFERENCE(dhdinfo);
+ switch (action) {
+ case PM_HIBERNATION_PREPARE:
+ case PM_SUSPEND_PREPARE:
+ suspend = TRUE;
+ break;
+ case PM_POST_HIBERNATION:
+ case PM_POST_SUSPEND:
+ suspend = FALSE;
+ break;
+ }
+
+#if defined(SUPPORT_P2P_GO_PS)
+#ifdef PROP_TXSTATUS
+ if (suspend) {
+ dhd_wakelock_waive(dhdinfo);
+ dhd_wlfc_suspend(&dhdinfo->pub);
+ dhd_wakelock_restore(dhdinfo);
+ } else {
+ dhd_wlfc_resume(&dhdinfo->pub);
+ }
+
+#endif
+#endif /* defined(SUPPORT_P2P_GO_PS) */
+
+#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 /* defined(CONFIG_PM_SLEEP) */
+
+#ifdef SAR_SUPPORT
+static int dhd_sar_callback(struct notifier_block *nfb, unsigned long action, void *ignored)
+{
+ dhd_info_t *dhd = (dhd_info_t*)container_of(nfb, struct dhd_info, sar_notifier);
+ char iovbuf[32];
+ s32 sar_enable;
+ int ret = 0;
+
+ /* '1' means activate sarlimit and '0' means back to normal state (deactivate
+ * sarlimit)
+ */
+ sar_enable = action ? 1 : 0;
+
+ bcm_mkiovar("sar_enable", (char *)&sar_enable, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s wl sar_enable %d failed %d\n", __FUNCTION__, sar_enable, ret));
+
+ return NOTIFY_DONE;
+}
+
+static bool dhd_sar_notifier_registered = FALSE;
+
+extern int register_notifier_by_sar(struct notifier_block *nb);
+extern int unregister_notifier_by_sar(struct notifier_block *nb);
+#endif /* defined(SAR_SUPPORT) */
+
+/* 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);
+
+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;
+}
+
+static int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost)
+{
+ dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
+
+ if (prepost) { /* pre process */
+ dhd_read_macaddr(dhd);
+ } else { /* post process */
+ dhd_write_macaddr(&dhd->pub.mac);
+ }
+
+ return 0;
+}
+
+#if defined(PKT_FILTER_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER)
+static bool
+_turn_on_arp_filter(dhd_pub_t *dhd, int op_mode)
+{
+ bool _apply = FALSE;
+ /* In case of IBSS mode, apply arp pkt filter */
+ if (op_mode & 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 defined(ARP_OFFLOAD_SUPPORT)
+ if ((dhd->arp_version == 1) &&
+#else
+ if (
+#endif
+ (op_mode & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE))) {
+ _apply = TRUE;
+ goto exit;
+ }
+
+exit:
+ return _apply;
+}
+#endif /* PKT_FILTER_SUPPORT && !GAN_LITE_NAT_KEEPALIVE_FILTER */
+
+void dhd_set_packet_filter(dhd_pub_t *dhd)
+{
+#ifdef PKT_FILTER_SUPPORT
+ 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]);
+ }
+ }
+#endif /* PKT_FILTER_SUPPORT */
+}
+
+void dhd_enable_packet_filter(int value, dhd_pub_t *dhd)
+{
+#ifdef PKT_FILTER_SUPPORT
+ int i;
+
+ DHD_TRACE(("%s: enter, value = %d\n", __FUNCTION__, value));
+ /* 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)))
+ {
+ for (i = 0; i < dhd->pktfilter_count; i++) {
+#ifndef 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);
+ }
+ }
+#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 */
+ /* wl_pkt_filter_enable_t enable_parm; */
+ char iovbuf[32];
+ int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */
+#ifndef ENABLE_FW_ROAM_SUSPEND
+ uint roamvar = 1;
+#endif /* ENABLE_FW_ROAM_SUSPEND */
+ uint nd_ra_filter = 0;
+ int ret = 0;
+
+#ifdef DYNAMIC_SWOOB_DURATION
+#ifndef CUSTOM_INTR_WIDTH
+#define CUSTOM_INTR_WIDTH 100
+#endif /* CUSTOM_INTR_WIDTH */
+ int intr_width = 0;
+#endif /* DYNAMIC_SWOOB_DURATION */
+ if (!dhd)
+ return -ENODEV;
+
+ 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 */
+
+ /* Enable packet filter, only allow unicast packet to send up */
+ dhd_enable_packet_filter(1, dhd);
+
+
+ /* If DTIM skip is set up as default, force it to wake
+ * each third DTIM for better power savings. Note that
+ * one side effect is a chance to miss BC/MC packet.
+ */
+ bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd);
+ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
+ 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf),
+ TRUE, 0) < 0)
+ DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__));
+
+#ifndef ENABLE_FW_ROAM_SUSPEND
+ /* Disable firmware roaming during suspend */
+ bcm_mkiovar("roam_off", (char *)&roamvar, 4,
+ iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* ENABLE_FW_ROAM_SUSPEND */
+ if (FW_SUPPORTED(dhd, ndoe)) {
+ /* enable IPv6 RA filter in firmware during suspend */
+ nd_ra_filter = 1;
+ bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4,
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("failed to set nd_ra_filter (%d)\n",
+ ret));
+ }
+#ifdef DYNAMIC_SWOOB_DURATION
+ intr_width = CUSTOM_INTR_WIDTH;
+ bcm_mkiovar("bus:intr_width", (char *)&intr_width, 4,
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("failed to set intr_width (%d)\n", ret));
+#endif /* DYNAMIC_SWOOB_DURATION */
+ } else {
+#ifdef PKT_FILTER_SUPPORT
+ dhd->early_suspended = 0;
+#endif
+ /* Kernel resumed */
+ DHD_ERROR(("%s: Remove extra suspend setting \n", __FUNCTION__));
+#ifdef DYNAMIC_SWOOB_DURATION
+ intr_width = 0;
+ bcm_mkiovar("bus:intr_width", (char *)&intr_width, 4,
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 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);
+#endif /* PKT_FILTER_SUPPORT */
+
+ /* restore pre-suspend setting for dtim_skip */
+ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
+ 4, iovbuf, sizeof(iovbuf));
+
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#ifndef ENABLE_FW_ROAM_SUSPEND
+ roamvar = dhd_roam_disable;
+ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf,
+ sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* ENABLE_FW_ROAM_SUSPEND */
+ if (FW_SUPPORTED(dhd, ndoe)) {
+ /* disable IPv6 RA filter in firmware during suspend */
+ nd_ra_filter = 0;
+ bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4,
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("failed to set nd_ra_filter (%d)\n",
+ ret));
+ }
+ }
+ }
+ 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);
+ /* Set flag when early suspend was called */
+ dhdp->in_suspend = val;
+ if ((force || !dhdp->suspend_disable_flag) &&
+ dhd_support_sta_mode(dhdp))
+ {
+ ret = dhd_set_suspend(val, dhdp);
+ }
+
+ DHD_OS_WAKE_UNLOCK(dhdp);
+ return ret;
+}
+
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
+static void dhd_early_suspend(struct early_suspend *h)
+{
+ struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
+ DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__));
+
+ if (dhd)
+ dhd_suspend_resume_helper(dhd, 1, 0);
+}
+
+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_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);
+ 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;
+
+ ASSERT(dhd);
+ 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_bad>";
+ }
+
+ if (dhd->iflist[ifidx] == NULL) {
+ DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx));
+ return "<if_null>";
+ }
+
+ if (dhd->iflist[ifidx]->net)
+ return dhd->iflist[ifidx]->net->name;
+
+ return "<if_none>";
+}
+
+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
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+ cnt = netdev_mc_count(dev);
+#else
+ cnt = dev->mc_count;
+#endif /* LINUX_VERSION_CODE */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ netif_addr_unlock_bh(dev);
+#endif
+
+ /* Determine initial value of allmulti flag */
+ allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE;
+
+ /* 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
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
+ netdev_for_each_mc_addr(ha, dev) {
+ if (!cnt)
+ break;
+ memcpy(bufp, ha->addr, ETHER_ADDR_LEN);
+ bufp += ETHER_ADDR_LEN;
+ cnt--;
+ }
+#else
+ 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_VERSION_CODE */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+ netif_addr_unlock_bh(dev);
+#endif
+
+ 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...
+ */
+
+ buflen = sizeof("allmulti") + sizeof(allmulti);
+ if (!(buf = MALLOC(dhd->pub.osh, buflen))) {
+ DHD_ERROR(("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx)));
+ return;
+ }
+ allmulti = htol32(allmulti);
+
+ if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) {
+ DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
+ dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen));
+ MFREE(dhd->pub.osh, buf, buflen);
+ return;
+ }
+
+
+ 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 allmulti %d failed\n",
+ dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
+ }
+
+ MFREE(dhd->pub.osh, buf, buflen);
+
+ /* 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)
+{
+ char buf[32];
+ wl_ioctl_t ioc;
+ int ret;
+
+ if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) {
+ DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx)));
+ return -1;
+ }
+ memset(&ioc, 0, sizeof(ioc));
+ ioc.cmd = WLC_SET_VAR;
+ ioc.buf = buf;
+ ioc.len = 32;
+ ioc.set = TRUE;
+
+ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ 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 SOFTAP
+extern struct net_device *ap_net_dev;
+extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 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:
+ return NL80211_IFTYPE_ADHOC;
+ default:
+ return NL80211_IFTYPE_UNSPECIFIED;
+ }
+}
+#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 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 (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+ struct wireless_dev *vwdev, *primary_wdev;
+ struct net_device *primary_ndev;
+#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 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);
+
+ ifidx = if_event->event.ifidx;
+ bssidx = if_event->event.bssidx;
+ DHD_TRACE(("%s: registering if with ifidx %d\n", __FUNCTION__, ifidx));
+
+ 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;
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+ vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
+ if (unlikely(!vwdev)) {
+ DHD_ERROR(("Could not allocate wireless device\n"));
+ goto done;
+ }
+ primary_ndev = dhd->pub.info->iflist[0]->net;
+ primary_wdev = ndev_to_wdev(primary_ndev);
+ vwdev->wiphy = primary_wdev->wiphy;
+ vwdev->iftype = dhd_role_to_nl80211_iftype(if_event->event.role);
+ vwdev->netdev = ndev;
+ ndev->ieee80211_ptr = vwdev;
+ SET_NETDEV_DEV(ndev, wiphy_dev(vwdev->wiphy));
+ DHD_ERROR(("virtual interface(%s) is created\n", if_event->name));
+#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
+
+ ret = dhd_register_if(&dhd->pub, ifidx, TRUE);
+ if (ret != BCME_OK) {
+ DHD_ERROR(("%s: dhd_register_if failed\n", __FUNCTION__));
+ dhd_remove_if(&dhd->pub, ifidx, TRUE);
+ }
+done:
+ MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t));
+
+ 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);
+
+ ifidx = if_event->event.ifidx;
+ DHD_TRACE(("Removing interface with idx %d\n", ifidx));
+
+ dhd_remove_if(&dhd->pub, ifidx, TRUE);
+
+ MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t));
+
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ dhd_net_if_unlock_local(dhd);
+}
+
+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;
+
+#ifdef SOFTAP
+ unsigned long flags;
+ bool in_ap = FALSE;
+#endif
+
+ 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;
+ }
+
+#ifdef SOFTAP
+ flags = dhd_os_spin_lock(&dhd->pub);
+ in_ap = (ap_net_dev != NULL);
+ dhd_os_spin_unlock(&dhd->pub, flags);
+
+ if (in_ap) {
+ DHD_ERROR(("attempt to set MAC for %s in AP Mode, blocked. \n",
+ ifp->net->name));
+ return;
+ }
+#endif
+ dhd_net_if_lock_local(dhd);
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+
+ 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_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;
+
+#ifdef SOFTAP
+ bool in_ap = FALSE;
+ unsigned long flags;
+#endif
+
+ 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;
+ }
+
+#ifdef SOFTAP
+ ifp = dhd->iflist[ifidx];
+ flags = dhd_os_spin_lock(&dhd->pub);
+ in_ap = (ap_net_dev != NULL);
+ dhd_os_spin_unlock(&dhd->pub, flags);
+
+ if (in_ap) {
+ DHD_ERROR(("set MULTICAST list for %s in AP Mode, blocked. \n",
+ ifp->net->name));
+ ifp->set_multicast = FALSE;
+ return;
+ }
+#endif
+
+ dhd_net_if_lock_local(dhd);
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+
+ /* Be sure to make corresponding (dhd_if_t*) pointer after lock() */
+ ifp = dhd->iflist[ifidx];
+
+ 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_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_info_t **)netdev_priv(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((void *)dhdif, DHD_WQ_WORK_SET_MAC,
+ dhd_set_mac_addr_handler, DHD_WORK_PRIORITY_LOW);
+ return ret;
+}
+
+static void
+dhd_set_multicast_list(struct net_device *dev)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+ int ifidx;
+
+ ifidx = dhd_net2idx(dhd, dev);
+ if (ifidx == DHD_BAD_IF)
+ return;
+
+ dhd->iflist[ifidx]->set_multicast = TRUE;
+ dhd_deferred_schedule_work((void *)((long int)ifidx), DHD_WQ_WORK_SET_MCAST_LIST,
+ dhd_set_mcast_list_handler, DHD_WORK_PRIORITY_LOW);
+}
+
+#ifdef PROP_TXSTATUS
+int
+dhd_os_wlfc_block(dhd_pub_t *pub)
+{
+ dhd_info_t *di = (dhd_info_t *)(pub->info);
+ ASSERT(di != NULL);
+ spin_lock_bh(&di->wlfc_spinlock);
+ return 1;
+}
+
+int
+dhd_os_wlfc_unblock(dhd_pub_t *pub)
+{
+ dhd_info_t *di = (dhd_info_t *)(pub->info);
+
+ ASSERT(di != NULL);
+ spin_unlock_bh(&di->wlfc_spinlock);
+ return 1;
+}
+
+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)]]
+
+#endif /* PROP_TXSTATUS */
+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;
+
+ /* Reject if down */
+ if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) {
+ /* free the packet here since the caller won't */
+ PKTFREE(dhdp->osh, pktbuf, TRUE);
+ return -ENODEV;
+ }
+
+ /* 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)
+ atomic_inc(&dhd->pend_8021x_cnt);
+ } else {
+ PKTFREE(dhd->pub.osh, pktbuf, TRUE);
+ return BCME_ERROR;
+ }
+
+#ifdef DHDTCPACK_SUPPRESS
+ /* If this packet has replaced another packet and got freed, just return */
+ if (dhd_tcpack_suppress(dhdp, pktbuf))
+ return ret;
+#endif /* DHDTCPACK_SUPPRESS */
+
+ /* Look into the packet and update the packet priority */
+#ifndef PKTPRIO_OVERRIDE
+ if (PKTPRIO(pktbuf) == 0)
+#endif
+ pktsetprio(pktbuf, FALSE);
+
+#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 */
+ ret = dhd_bus_txdata(dhdp->bus, pktbuf);
+ }
+ }
+#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 */
+
+ return ret;
+}
+
+int BCMFASTPATH
+dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
+{
+ int ret;
+ uint datalen;
+ void *pktbuf;
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
+ dhd_if_t *ifp = NULL;
+ int ifidx;
+#ifdef WLMEDIA_HTSF
+ uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz;
+#else
+ uint8 htsfdlystat_sz = 0;
+#endif
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+
+ /* Reject if down */
+ if (dhd->pub.busstate == DHD_BUS_DOWN || dhd->pub.hang_was_sent) {
+ 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_ERROR(("%s: Event HANG sent up\n", __FUNCTION__));
+ net_os_send_hang_message(net);
+ }
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
+ return -ENODEV;
+#else
+ return NETDEV_TX_BUSY;
+#endif
+ }
+
+ ifidx = dhd_net2idx(dhd, net);
+ if (ifidx == DHD_BAD_IF) {
+ DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx));
+ netif_stop_queue(net);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
+ return -ENODEV;
+#else
+ return NETDEV_TX_BUSY;
+#endif
+ }
+
+ /* re-align socket buffer if "skb->data" is odd adress */
+ 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);
+ }
+
+ ifp = dhd->iflist[ifidx];
+ 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++;
+
+ 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;
+ }
+ }
+
+ /* Convert to packet */
+ if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) {
+ DHD_ERROR(("%s: PKTFRMNATIVE failed\n",
+ dhd_ifname(&dhd->pub, ifidx)));
+ dev_kfree_skb_any(skb);
+ ret = -ENOMEM;
+ goto done;
+ }
+#ifdef 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
+
+ ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf);
+
+done:
+ if (ret) {
+ ifp->stats.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_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);
+
+ 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_RX_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;
+}
+#endif /* DHD_RX_DUMP */
+
+
+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;
+#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP)
+ char *dump_data;
+ uint16 protocol;
+#endif /* DHD_RX_DUMP || DHD_8021X_DUMP */
+
+ 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);
+
+ ifp = dhd->iflist[ifidx];
+ if (ifp == NULL) {
+ DHD_ERROR(("%s: ifp is NULL. drop packet\n",
+ __FUNCTION__));
+ PKTFREE(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__));
+ PKTFREE(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
+ */
+ PKTFREE(dhdp->osh, pktbuf, FALSE);
+ continue;
+ }
+#endif
+#ifdef DHDTCPACK_SUPPRESS
+ dhd_tcpdata_info_get(dhdp, pktbuf);
+#endif
+ skb = PKTTONATIVE(dhdp->osh, pktbuf);
+
+ ifp = dhd->iflist[ifidx];
+ if (ifp == NULL)
+ ifp = dhd->iflist[0];
+
+ ASSERT(ifp);
+ skb->dev = ifp->net;
+
+
+ /* 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;
+
+#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP)
+ dump_data = skb->data;
+ protocol = (dump_data[12] << 8) | dump_data[13];
+
+ if (protocol == ETHER_TYPE_802_1X) {
+ DHD_ERROR(("ETHER_TYPE_802_1X: "
+ "ver %d, type %d, replay %d\n",
+ dump_data[14], dump_data[15],
+ dump_data[30]));
+ }
+#endif /* DHD_RX_DUMP || DHD_8021X_DUMP */
+#if defined(DHD_RX_DUMP)
+ DHD_ERROR(("RX DUMP - %s\n", _get_packet_type_str(protocol)));
+ if (protocol != ETHER_TYPE_BRCM) {
+ if (dump_data[0] == 0xFF) {
+ DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__));
+
+ if ((dump_data[12] == 8) &&
+ (dump_data[13] == 6)) {
+ DHD_ERROR(("%s: ARP %d\n",
+ __FUNCTION__, dump_data[0x15]));
+ }
+ } else if (dump_data[0] & 1) {
+ DHD_ERROR(("%s: MULTICAST: " MACDBG "\n",
+ __FUNCTION__, MAC2STRDBG(dump_data)));
+ }
+#ifdef DHD_RX_FULL_DUMP
+ {
+ int k;
+ for (k = 0; k < skb->len; k++) {
+ DHD_ERROR(("%02X ", dump_data[k]));
+ if ((k & 15) == 15)
+ DHD_ERROR(("\n"));
+ }
+ DHD_ERROR(("\n"));
+ }
+#endif /* DHD_RX_FULL_DUMP */
+ }
+#endif /* DHD_RX_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
+ /* 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) {
+ 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 > ETHER_TYPE_LEN ? len - ETHER_TYPE_LEN : 0,
+ &event,
+ &data);
+
+ wl_event_to_host_order(&event);
+ if (!tout_ctrl)
+ tout_ctrl = DHD_PACKET_TIMEOUT_MS;
+
+#if defined(PNO_SUPPORT)
+ if (event.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 */
+
+#ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT
+ PKTFREE(dhdp->osh, pktbuf, FALSE);
+ 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 */
+ }
+
+ ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
+ ifp = dhd->iflist[ifidx];
+
+ if (ifp->net)
+ ifp->net->last_rx = jiffies;
+
+ 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()) {
+ netif_rx(skb);
+ } 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.
+ */
+#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 (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, uint 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)
+ 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 (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_info_t **)netdev_priv(net);
+ dhd_if_t *ifp;
+ int ifidx;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ ifidx = dhd_net2idx(dhd, net);
+ if (ifidx == DHD_BAD_IF) {
+ DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__));
+
+ memset(&net->stats, 0, sizeof(net->stats));
+ return &net->stats;
+ }
+
+ ifp = dhd->iflist[ifidx];
+ ASSERT(dhd && ifp);
+
+ if (dhd->pub.up) {
+ /* Use the protocol to get dongle stats */
+ dhd_prot_dstats(&dhd->pub);
+ }
+ return &ifp->stats;
+}
+
+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, &param);
+ }
+
+ 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;
+ }
+
+ dhd_os_sdlock(&dhd->pub);
+ if (dhd->pub.dongle_reset == FALSE) {
+ DHD_TIMER(("%s:\n", __FUNCTION__));
+
+ /* Call the bus module watchdog */
+ dhd_bus_watchdog(&dhd->pub);
+
+ flags = dhd_os_spin_lock(&dhd->pub);
+ /* Count the tick for reference */
+ dhd->pub.tickcnt++;
+ 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_os_spin_unlock(&dhd->pub, flags);
+ }
+ dhd_os_sdunlock(&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_sdlock(&dhd->pub);
+ /* Call the bus module watchdog */
+ dhd_bus_watchdog(&dhd->pub);
+
+ flags = dhd_os_spin_lock(&dhd->pub);
+ /* Count the tick for reference */
+ dhd->pub.tickcnt++;
+
+ /* Reschedule the watchdog */
+ if (dhd->wd_timer_valid)
+ mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms));
+ dhd_os_spin_unlock(&dhd->pub, flags);
+ dhd_os_sdunlock(&dhd->pub);
+}
+
+#ifdef ENABLE_ADAPTIVE_SCHED
+/* DPC thread policy */
+static int dhd_dpc_poli = SCHED_FIFO;
+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, &param);
+ } else {
+ if (get_scheduler_policy(current) != SCHED_FIFO) {
+ param.sched_priority = (prio < MAX_RT_PRIO)? prio : (MAX_RT_PRIO-1);
+ setScheduler(current, dhd_dpc_poli, &param);
+ }
+ }
+}
+#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, &param);
+ }
+
+#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 (!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) {
+ dhd_os_wd_timer_extend(&dhd->pub, TRUE);
+ while (dhd_bus_dpc(dhd->pub.bus)) {
+ /* process all data */
+ }
+ 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;
+ dhd_pub_t *pub = &dhd->pub;
+#if defined(WAIT_DEQUEUE)
+#define RXF_WATCHDOG_TIME 250 /* BARK_TIME(1000) / */
+ ulong watchdogTime = OSL_SYSUPTIME(); /* msec */
+#endif
+
+ /* 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, &param);
+ }
+
+
+#ifdef CUSTOM_SET_CPUCORE
+ dhd->pub.current_rxf = current;
+#endif /* CUSTOM_SET_CPUCORE */
+ /* Run until signal received */
+ while (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);
+
+#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);
+}
+
+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 (dhd_bus_dpc(dhd->pub.bus))
+ tasklet_schedule(&dhd->tasklet);
+ else
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ } else {
+ dhd_bus_stop(dhd->pub.bus, TRUE);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ }
+}
+
+void
+dhd_sched_dpc(dhd_pub_t *dhdp)
+{
+ dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
+
+ DHD_OS_WAKE_LOCK(dhdp);
+ if (dhd->thr_dpc_ctl.thr_pid >= 0) {
+ /* 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);
+ }
+}
+
+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);
+ 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 */
+}
+
+#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)
+{
+ wl_ioctl_t ioc;
+ char buf[32];
+ int ret;
+
+ memset(&ioc, 0, sizeof(ioc));
+
+ ioc.cmd = WLC_GET_VAR;
+ ioc.buf = buf;
+ ioc.len = (uint)sizeof(buf);
+ ioc.set = FALSE;
+
+ strncpy(buf, "toe_ol", sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
+ /* Check for older dongle image that doesn't support toe_ol */
+ 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)
+{
+ wl_ioctl_t ioc;
+ char buf[32];
+ int toe, ret;
+
+ memset(&ioc, 0, sizeof(ioc));
+
+ ioc.cmd = WLC_SET_VAR;
+ ioc.buf = buf;
+ ioc.len = (uint)sizeof(buf);
+ ioc.set = TRUE;
+
+ /* Set toe_ol as requested */
+
+ strncpy(buf, "toe_ol", sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+ memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32));
+
+ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 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);
+
+ strcpy(buf, "toe");
+ memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32));
+
+ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
+ DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
+ return ret;
+ }
+
+ return 0;
+}
+#endif /* TOE */
+
+#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_info_t **)netdev_priv(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)
+{
+ dhd_info_t *dhd;
+
+ if (!dhdp) {
+ DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ if (!dhdp->up)
+ return FALSE;
+
+ dhd = (dhd_info_t *)dhdp->info;
+#if !defined(BCMPCIE)
+ if (dhd->thr_dpc_ctl.thr_pid < 0) {
+ DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__));
+ return FALSE;
+ }
+#endif
+
+ if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) ||
+ ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) {
+ 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));
+ net_os_send_hang_message(net);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+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;
+
+ net = dhd_idx2net(pub, ifidx);
+ if (!net) {
+ bcmerror = BCME_BADARG;
+ goto done;
+ }
+
+ if (data_buf)
+ buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN);
+
+ /* check for local dhd ioctl and handle it */
+ if (ioc->driver == DHD_IOCTL_MAGIC) {
+ bcmerror = dhd_ioctl((void *)pub, ioc, data_buf, buflen);
+ if (bcmerror)
+ pub->bcmerror = bcmerror;
+ goto done;
+ }
+
+
+ /* send to dongle (must be up, and wl). */
+ if (pub->busstate != DHD_BUS_DATA) {
+ bcmerror = BCME_DONGLE_DOWN;
+ goto done;
+ }
+
+ if (!pub->iswl) {
+ bcmerror = BCME_DONGLE_DOWN;
+ goto done;
+ }
+
+ /*
+ * 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);
+
+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_info_t **)netdev_priv(net);
+ dhd_ioctl_t ioc;
+ int bcmerror = 0;
+ int ifidx;
+ int ret;
+ void *local_buf = NULL;
+ u16 buflen = 0;
+
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+
+ /* send to dongle only if we are not waiting for reload already */
+ if (dhd->pub.hang_was_sent) {
+ DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__));
+ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ return OSL_ERROR(BCME_DONGLE_DOWN);
+ }
+
+ 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_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_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_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_OS_WAKE_UNLOCK(&dhd->pub);
+ return ret;
+ }
+
+ if (cmd != SIOCDEVPRIVATE) {
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ return -EOPNOTSUPP;
+ }
+
+ memset(&ioc, 0, sizeof(ioc));
+
+#ifdef CONFIG_COMPAT
+ if (is_compat_task()) {
+ 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;
+ 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;
+ }
+ } 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;
+ }
+
+ /* 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;
+ }
+ }
+
+ if (!capable(CAP_NET_ADMIN)) {
+ bcmerror = BCME_EPERM;
+ goto done;
+ }
+
+ 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;
+ }
+ if (copy_from_user(local_buf, ioc.buf, buflen)) {
+ bcmerror = BCME_BADADDR;
+ goto done;
+ }
+ *(char *)(local_buf + buflen) = '\0';
+ }
+
+ bcmerror = dhd_ioctl_process(&dhd->pub, ifidx, &ioc, local_buf);
+
+ if (!bcmerror && buflen && local_buf && ioc.buf) {
+ if (copy_to_user(ioc.buf, local_buf, buflen))
+ bcmerror = -EFAULT;
+ }
+
+done:
+ if (local_buf)
+ MFREE(dhd->pub.osh, local_buf, buflen+1);
+
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+
+ return OSL_ERROR(bcmerror);
+}
+
+
+
+
+static int
+dhd_stop(struct net_device *net)
+{
+ int ifidx = 0;
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
+
+
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+ DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net));
+ if (dhd->pub.up == 0) {
+ goto exit;
+ }
+
+
+ ifidx = dhd_net2idx(dhd, net);
+ BCM_REFERENCE(ifidx);
+
+ /* Set state and stop OS transmissions */
+ netif_stop_queue(net);
+ dhd->pub.up = 0;
+
+#ifdef ENABLE_CONTROL_SCHED
+ dhd_sysfs_destroy_node(net);
+ dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING;
+ dhd_dpc_poli = SCHED_FIFO;
+#endif /* ENABLE_CONTROL_SCHED */
+
+#ifdef WL_CFG80211
+ if (ifidx == 0) {
+ wl_cfg80211_down(NULL);
+
+ /*
+ * 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;
+
+
+ dhd_net_if_lock_local(dhd);
+ for (i = 1; i < DHD_MAX_IFS; i++)
+ dhd_remove_if(&dhd->pub, i, FALSE);
+ dhd_net_if_unlock_local(dhd);
+ }
+ cancel_work_sync(dhd->dhd_deferred_wq);
+ }
+ }
+#endif /* WL_CFG80211 */
+
+#ifdef PROP_TXSTATUS
+ dhd_wlfc_cleanup(&dhd->pub, NULL, 0);
+#endif
+ /* Stop the protocol module */
+ dhd_prot_stop(&dhd->pub);
+
+ OLD_MOD_DEC_USE_COUNT;
+exit:
+#if defined(WL_CFG80211)
+ if (ifidx == 0 && !dhd_download_fw_on_driverload)
+ wl_android_wifi_off(net);
+#endif
+ dhd->pub.rxcnt_timeout = 0;
+ dhd->pub.txcnt_timeout = 0;
+
+ 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;
+ }
+
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ return 0;
+}
+
+#if defined(WL_CFG80211) && (defined(USE_INITIAL_2G_SCAN) || \
+ defined(USE_INITIAL_SHORT_DWELL_TIME))
+extern bool g_first_broadcast_scan;
+#endif /* OEM_ANDROID && WL_CFG80211 && (USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME) */
+
+#ifdef WL11U
+static int dhd_interworking_enable(dhd_pub_t *dhd)
+{
+ char iovbuf[WLC_IOCTL_SMLEN];
+ uint32 enable = true;
+ int ret = BCME_OK;
+
+ bcm_mkiovar("interworking", (char *)&enable, sizeof(enable), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s: enableing interworking failed, ret=%d\n", __FUNCTION__, ret));
+ }
+
+ if (ret == BCME_OK) {
+ /* basic capabilities for HS20 REL2 */
+ uint32 cap = WL_WNM_BSSTRANS | WL_WNM_NOTIF;
+ bcm_mkiovar("wnm", (char *)&cap, sizeof(cap), 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 WNM info, ret=%d\n", __FUNCTION__, ret));
+ }
+ }
+
+ return ret;
+}
+#endif /* WL11u */
+
+#ifdef ENABLE_CONTROL_SCHED
+static ssize_t
+read_dpc_prio(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count)
+{
+ DHD_INFO(("%s: read cur_prio(%d), cur_poli(%d)\n",
+ __FUNCTION__, dhd_dpc_prio, dhd_dpc_poli));
+ memset(buf, 0, sizeof(uint32));
+ count += snprintf(buf, sizeof(uint32), "%d", dhd_dpc_prio + (dhd_dpc_poli * 100));
+ return count;
+}
+
+static ssize_t
+write_dpc_prio(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf, loff_t off, size_t size)
+{
+ uint32 new_prio = 0;
+ uint32 cur_prio = dhd_dpc_prio + (dhd_dpc_poli * 100);
+
+ memcpy(&new_prio, buf, sizeof(uint32));
+ new_prio = bcm_atoi((char*)&new_prio);
+
+ if (new_prio < 0 || new_prio > 199) {
+ DHD_ERROR(("%s: ERROR invalid new_prio(%d)\n",
+ __FUNCTION__, new_prio));
+ return -EINVAL;
+ }
+
+ if (cur_prio != new_prio) {
+ dhd_dpc_prio = new_prio % 100;
+ dhd_dpc_poli = new_prio / 100;
+ DHD_INFO(("%s: write new_prio(%d), new_policy(%d)\n",
+ __FUNCTION__, dhd_dpc_prio, dhd_dpc_poli));
+ }
+
+ return sizeof(uint32);
+}
+
+static struct bin_attribute dpc_prio_attr = {
+ .attr = {.name = "dpc_prio", .mode = 0644},
+ .size = sizeof(uint32),
+ .read = read_dpc_prio,
+ .write = write_dpc_prio,
+};
+
+static int
+dhd_sysfs_create_node(struct net_device *net)
+{
+ int ret;
+
+ DHD_INFO(("%s Enter\n", __func__));
+ ret = sysfs_create_bin_file(&net->dev.kobj, &dpc_prio_attr);
+
+ if (ret) {
+ DHD_ERROR(("%s: create dpc_prio sysfs fail, ret(%d)\n", __FUNCTION__, ret));
+ return ret;
+ }
+ return 0;
+}
+
+static void
+dhd_sysfs_destroy_node(struct net_device *net)
+{
+ DHD_INFO(("%s Enter\n", __FUNCTION__));
+ sysfs_remove_bin_file(&net->dev.kobj, &dpc_prio_attr);
+}
+#endif /* ENABLE_CONTROL_SCHED */
+
+
+static int
+dhd_open(struct net_device *net)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
+#ifdef TOE
+ uint32 toe_ol;
+#endif
+ int ifidx;
+ int32 ret = 0;
+
+
+
+
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+ dhd->pub.dongle_trap_occured = 0;
+ dhd->pub.hang_was_sent = 0;
+
+#ifdef ENABLE_CONTROL_SCHED
+ ret = dhd_sysfs_create_node(net);
+ if (ret) {
+ DHD_ERROR(("%s: Failed to setup dpc_prio ret(%d)\n", __FUNCTION__, ret));
+ goto exit;
+ }
+#endif /* ENABLE_CONTROL_SCHED */
+
+#if !defined(WL_CFG80211)
+ /*
+ * Force start if ifconfig_up gets called before START command
+ * We keep WEXT's wl_control_wl_start to provide backward compatibility
+ * This should be removed in the future
+ */
+ 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 defined(WL_CFG80211)
+ if (!dhd_download_fw_on_driverload) {
+ DHD_ERROR(("\n%s\n", dhd_version));
+#if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME)
+ g_first_broadcast_scan = TRUE;
+#endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */
+ ret = wl_android_wifi_on(net);
+ if (ret != 0) {
+ DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n",
+ __FUNCTION__, ret));
+ ret = -1;
+ goto exit;
+ }
+ }
+#endif
+
+ if (dhd->pub.busstate != DHD_BUS_DATA) {
+
+ /* try to bring up bus */
+ if ((ret = dhd_bus_start(&dhd->pub)) != 0) {
+ DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
+ ret = -1;
+ goto exit;
+ }
+
+ }
+
+ /* dhd_prot_init 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(WL_CFG80211)
+ if (unlikely(wl_cfg80211_up(NULL))) {
+ DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__));
+ ret = -1;
+ goto exit;
+ }
+#endif /* WL_CFG80211 */
+ }
+
+ /* Allow transmit calls */
+ netif_start_queue(net);
+ dhd->pub.up = 1;
+
+#ifdef BCMDBGFS
+ dhd_dbg_init(&dhd->pub);
+#endif
+
+ OLD_MOD_INC_USE_COUNT;
+exit:
+ if (ret)
+ dhd_stop(net);
+
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+
+
+ return ret;
+}
+
+int dhd_do_driver_init(struct net_device *net)
+{
+ dhd_info_t *dhd = NULL;
+
+ if (!net) {
+ DHD_ERROR(("Primary Interface not initialized \n"));
+ return -EINVAL;
+ }
+
+
+ /* && defined(OEM_ANDROID) && defined(BCMSDIO) */
+ dhd = *(dhd_info_t **)netdev_priv(net);
+
+ /* If driver is already initialized, do nothing
+ */
+ if (dhd->pub.busstate == DHD_BUS_DATA) {
+ DHD_TRACE(("Driver already Inititalized. Nothing to do"));
+ return 0;
+ }
+
+ if (dhd_open(net) < 0) {
+ DHD_ERROR(("Driver Init Failed \n"));
+ return -1;
+ }
+
+ return 0;
+}
+
+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(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((void *)if_event, DHD_WQ_WORK_IF_ADD,
+ dhd_ifadd_event_handler, DHD_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;
+
+#if defined(WL_CFG80211) && !defined(P2PONEINT)
+ if (wl_cfg80211_notify_ifdel(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((void *)if_event, DHD_WQ_WORK_IF_DEL,
+ dhd_ifdel_event_handler, DHD_WORK_PRIORITY_LOW);
+
+ 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, char *name,
+ uint8 *mac, uint8 bssidx, bool need_rtnl_lock, 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\n", __FUNCTION__, ifp->net->name));
+
+ /* 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;
+ if (mac != NULL)
+ memcpy(&ifp->mac_addr, mac, ETHER_ADDR_LEN);
+
+ /* Allocate etherdev, including space for private structure */
+ ifp->net = alloc_etherdev(sizeof(dhdinfo));
+ if (ifp->net == NULL) {
+ DHD_ERROR(("%s: OOM - alloc_etherdev(%zu)\n", __FUNCTION__, sizeof(dhdinfo)));
+ goto fail;
+ }
+ memcpy(netdev_priv(ifp->net), &dhdinfo, sizeof(dhdinfo));
+ if (name && name[0]) {
+ strncpy(ifp->net->name, name, IFNAMSIZ);
+ ifp->net->name[IFNAMSIZ - 1] = '\0';
+ }
+#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
+ strncpy(ifp->dngl_name, name, IFNAMSIZ);
+
+ return ifp->net;
+
+fail:
+ if (ifp != NULL) {
+ if (ifp->net != NULL) {
+ 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;
+
+ ifp = dhdinfo->iflist[ifidx];
+ if (ifp != NULL) {
+ if (ifp->net != NULL) {
+ DHD_ERROR(("deleting interface '%s' idx %d\n", ifp->net->name, ifp->idx));
+
+ /* 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;
+ }
+
+ dhdinfo->iflist[ifidx] = NULL;
+ MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp));
+
+ }
+
+ 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
+};
+
+#ifdef P2PONEINT
+extern int wl_cfgp2p_if_open(struct net_device *net);
+extern int wl_cfgp2p_if_stop(struct net_device *net);
+
+static struct net_device_ops dhd_cfgp2p_ops_virt = {
+ .ndo_open = wl_cfgp2p_if_open,
+ .ndo_stop = wl_cfgp2p_if_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
+};
+#endif /* P2PONEINT */
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */
+
+#ifdef DEBUGGER
+extern void debugger_init(void *bus_handle);
+#endif
+
+
+#ifdef SHOW_LOGTRACE
+static char *logstrs_path = "/root/logstrs.bin";
+static char *st_str_file_path = "/root/rtecdc.bin";
+static char *map_file_path = "/root/rtecdc.map";
+static char *rom_st_str_file_path = "/root/roml.bin";
+static char *rom_map_file_path = "/root/roml.map";
+
+#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 */
+static char *ram_file_str = "rtecdc";
+static char *rom_file_str = "roml";
+#define RAMSTART_BIT 0x01
+#define RDSTART_BIT 0x02
+#define RDEND_BIT 0x04
+#define ALL_MAP_VAL (RAMSTART_BIT | RDSTART_BIT | RDEND_BIT)
+
+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 void
+dhd_init_logstrs_array(dhd_event_log_t *temp)
+{
+ struct file *filep = NULL;
+ struct kstat stat;
+ mm_segment_t fs;
+ char *raw_fmts = NULL;
+ int logstrs_size = 0;
+
+ logstr_header_t *hdr = NULL;
+ uint32 *lognums = NULL;
+ char *logstrs = NULL;
+ int ram_index = 0;
+ char **fmts;
+ int num_fmts = 0;
+ uint32 i = 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;
+
+ raw_fmts = kmalloc(logstrs_size, GFP_KERNEL);
+ 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", __FUNCTION__, logstrs_path));
+ goto fail;
+ }
+
+ /* 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 = kmalloc(num_fmts * sizeof(char *), GFP_KERNEL);
+ if (fmts == NULL) {
+ DHD_ERROR(("Failed to allocate fmts memory"));
+ goto fail;
+ }
+
+ 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]];
+ }
+ temp->fmts = fmts;
+ temp->raw_fmts = raw_fmts;
+ temp->num_fmts = num_fmts;
+ filp_close(filep, NULL);
+ set_fs(fs);
+ return;
+fail:
+ if (raw_fmts) {
+ kfree(raw_fmts);
+ raw_fmts = NULL;
+ }
+ if (!IS_ERR(filep))
+ filp_close(filep, NULL);
+ set_fs(fs);
+ temp->fmts = NULL;
+ return;
+}
+
+static int
+dhd_read_map(char *fname, uint32 *ramstart, uint32 *rodata_start,
+ uint32 *rodata_end)
+{
+ struct file *filep = NULL;
+ mm_segment_t fs;
+ 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;
+
+ 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;
+ }
+
+ raw_fmts = kmalloc(read_size, GFP_KERNEL);
+ 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 = vfs_read(filep, raw_fmts, read_size, (&filep->f_pos));
+ if (error < 0) {
+ DHD_ERROR(("%s: read failed %s err:%d \n", __FUNCTION__,
+ map_file_path, error));
+ goto fail;
+ }
+
+ if (error < read_size) {
+ /*
+ * since we reset file pos back to earlier pos by
+ * GO_BACK_FILE_POS_NUM_BYTES bytes we won't reach EOF.
+ * So if ret value is less than read_size, reached EOF don't read further
+ */
+ break;
+ }
+
+ /* 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;
+ }
+ 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.
+ */
+ filep->f_pos = filep->f_pos - GO_BACK_FILE_POS_NUM_BYTES;
+ }
+
+ DHD_ERROR(("---ramstart: 0x%x, rodata_start: 0x%x, rodata_end:0x%x\n",
+ *ramstart, *rodata_start, *rodata_end));
+
+ DHD_ERROR(("readmap over \n"));
+
+fail:
+ if (raw_fmts) {
+ kfree(raw_fmts);
+ raw_fmts = NULL;
+ }
+ if (!IS_ERR(filep))
+ filp_close(filep, NULL);
+
+ set_fs(fs);
+ if (count == ALL_MAP_VAL) {
+ return BCME_OK;
+ }
+ DHD_ERROR(("readmap error 0X%x \n", count));
+ return BCME_ERROR;
+}
+
+static void
+dhd_init_static_strs_array(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(map_file, &ramstart, &rodata_start, &rodata_end);
+ if (error == BCME_ERROR) {
+ DHD_ERROR(("readmap Error!! \n"));
+ /* don't do event log parsing in actual case */
+ temp->raw_sstr = NULL;
+ return;
+ }
+ 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;
+
+ raw_fmts = kmalloc(logstrs_size, GFP_KERNEL);
+ 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->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_ramstart = ramstart;
+ temp->rom_rodata_start = rodata_start;
+ temp->rom_rodata_end = rodata_end;
+ }
+
+ filp_close(filep, NULL);
+ set_fs(fs);
+
+ return;
+fail:
+ if (raw_fmts) {
+ kfree(raw_fmts);
+ raw_fmts = NULL;
+ }
+ 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;
+}
+
+#endif /* SHOW_LOGTRACE */
+
+dhd_pub_t *
+dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
+{
+ dhd_info_t *dhd = NULL;
+ struct net_device *net = NULL;
+ char if_name[IFNAMSIZ] = {'\0'};
+ uint32 bus_type = -1;
+ uint32 bus_num = -1;
+ uint32 slot_num = -1;
+ wifi_adapter_info_t *adapter = NULL;
+#ifdef CUSTOM_COUNTRY_CODE
+ struct cntry_locales_custom *cloc_ptr = NULL;
+#endif /* CUSTOM_COUNTRY_CODE */
+
+ dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT;
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ /* will implement get_ids for DBUS later */
+ dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num);
+ adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num);
+
+ /* 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 fail;
+ }
+ }
+ memset(dhd, 0, sizeof(dhd_info_t));
+ dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC;
+
+ dhd->pub.osh = osh;
+ dhd->adapter = adapter;
+
+#ifdef OOB_PARAM
+ dhd->pub.oob_disable = adapter->oob_disable;
+#endif /* OOB_PARAM */
+
+#ifdef GET_CUSTOM_MAC_ENABLE
+ wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet);
+#endif /* GET_CUSTOM_MAC_ENABLE */
+#ifdef CUSTOM_COUNTRY_CODE
+ cloc_ptr = wifi_platform_get_country_code(dhd->adapter, dhd->pub.dhd_cspec.ccode);
+ if (cloc_ptr) {
+ strlcpy(dhd->pub.dhd_cspec.country_abbrev, cloc_ptr->iso_abbrev, WLC_CNTRY_BUF_SZ);
+ strlcpy(dhd->pub.dhd_cspec.ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ);
+ dhd->pub.dhd_cspec.rev = cloc_ptr->custom_locale_rev;
+ get_customized_country_code(dhd->adapter, dhd->pub.dhd_cspec.ccode,
+ &dhd->pub.dhd_cspec);
+ }
+#endif /* CUSTOM_COUNTRY_CODE */
+ dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID;
+ dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID;
+
+ /* Initialize thread based operation and lock */
+ sema_init(&dhd->sdsem, 1);
+
+ /* 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);
+
+ /* Link to info module */
+ dhd->pub.info = dhd;
+ /* Link to bus module */
+ dhd->pub.bus = bus;
+ dhd->pub.hdrlen = bus_hdrlen;
+
+ /* 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))
+ strcat(if_name, "%d");
+ }
+ 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;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
+ net->open = NULL;
+#else
+ net->netdev_ops = NULL;
+#endif
+
+ sema_init(&dhd->proto_sem, 1);
+
+#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;
+#endif /* PROP_TXSTATUS */
+
+ /* Initialize other structure content */
+ init_waitqueue_head(&dhd->ioctl_resp_wait);
+ init_waitqueue_head(&dhd->ctrl_wait);
+
+ /* Initialize the spinlocks */
+ spin_lock_init(&dhd->sdlock);
+ spin_lock_init(&dhd->txqlock);
+ spin_lock_init(&dhd->dhd_lock);
+ spin_lock_init(&dhd->rxf_lock);
+#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);
+ dhd->wakelock_counter = 0;
+ dhd->wakelock_wd_counter = 0;
+ dhd->wakelock_rx_timeout_enable = 0;
+ dhd->wakelock_ctrl_timeout_enable = 0;
+ dhd->waive_wakelock = FALSE;
+#ifdef CONFIG_HAS_WAKELOCK
+ wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake");
+ wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake");
+ wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake");
+ 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);
+#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 WL_CFG80211
+ /* 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
+#if defined(WL_WIRELESS_EXT)
+ /* Attach and link in the iw */
+ if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) {
+ if (wl_iw_attach(net, (void *)&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
+ dhd_init_logstrs_array(&dhd->event_data);
+ dhd_init_static_strs_array(&dhd->event_data, st_str_file_path, map_file_path);
+ dhd_init_static_strs_array(&dhd->event_data, rom_st_str_file_path, rom_map_file_path);
+#endif /* SHOW_LOGTRACE */
+
+
+ /* Set up the watchdog timer */
+ init_timer(&dhd->timer);
+ dhd->timer.data = (ulong)dhd;
+ dhd->timer.function = dhd_watchdog;
+ 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 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;
+ }
+ }
+
+ dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
+
+ /*
+ * Save the dhd_info into the priv
+ */
+ memcpy(netdev_priv(net), &dhd, sizeof(dhd));
+
+#if defined(CONFIG_PM_SLEEP)
+ dhd->pm_notifier.notifier_call = dhd_pm_callback;
+ dhd->pm_notifier.priority = 10;
+ if (!dhd_pm_notifier_registered) {
+ dhd_pm_notifier_registered = TRUE;
+ register_pm_notifier(&dhd->pm_notifier);
+ }
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef SAR_SUPPORT
+ dhd->sar_notifier.notifier_call = dhd_sar_callback;
+ if (!dhd_sar_notifier_registered) {
+ dhd_sar_notifier_registered = TRUE;
+ register_notifier_by_sar(&dhd->sar_notifier);
+ }
+#endif
+
+#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 (!dhd_inet6addr_notifier_registered) {
+ dhd_inet6addr_notifier_registered = TRUE;
+ register_inet6addr_notifier(&dhd_inet6addr_notifier);
+ }
+ 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_DELAYTX);
+#endif /* DHDTCPACK_SUPPRESS */
+#ifdef DHD_DEBUG
+ dhd->join_timeout_val = DHD_JOIN_MAX_TIME_DEFAULT;
+ dhd->scan_time_count = DHD_SCAN_DEF_TIMEOUT;
+#endif
+ dhd_state |= DHD_ATTACH_STATE_DONE;
+ dhd->dhd_state = dhd_state;
+
+ dhd->unit = dhd_found + instance_base;
+ 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);
+ }
+
+ 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;
+}
+
+bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo)
+{
+ int fw_len;
+ int nv_len;
+ const char *fw = NULL;
+ const char *nv = NULL;
+ wifi_adapter_info_t *adapter = dhdinfo->adapter;
+
+
+ /* 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 (adapter && adapter->fw_path && adapter->fw_path[0] != '\0')
+ fw = adapter->fw_path;
+
+ if (adapter && adapter->nv_path && adapter->nv_path[0] != '\0')
+ nv = adapter->nv_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 (fw && fw[0] != '\0') {
+ fw_len = strlen(fw);
+ if (fw_len >= sizeof(dhdinfo->fw_path)) {
+ DHD_ERROR(("fw path len exceeds max len of dhdinfo->fw_path\n"));
+ return FALSE;
+ }
+ strncpy(dhdinfo->fw_path, fw, sizeof(dhdinfo->fw_path));
+ 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 >= sizeof(dhdinfo->nv_path)) {
+ DHD_ERROR(("nvram path len exceeds max len of dhdinfo->nv_path\n"));
+ return FALSE;
+ }
+ strncpy(dhdinfo->nv_path, nv, sizeof(dhdinfo->nv_path));
+ if (dhdinfo->nv_path[nv_len-1] == '\n')
+ dhdinfo->nv_path[nv_len-1] = '\0';
+ }
+
+ /* clear the path in module parameter */
+ firmware_path[0] = '\0';
+ nvram_path[0] = '\0';
+
+ 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;
+ }
+
+ return TRUE;
+}
+
+
+int
+dhd_bus_start(dhd_pub_t *dhdp)
+{
+ int ret = -1;
+ dhd_info_t *dhd = (dhd_info_t*)dhdp->info;
+ unsigned long flags;
+
+ ASSERT(dhd);
+
+ DHD_TRACE(("Enter %s:\n", __FUNCTION__));
+
+ /* try to download image and nvram to the dongle */
+ if (dhd->pub.busstate == DHD_BUS_DOWN && dhd_update_fw_nv_path(dhd)) {
+ DHD_INFO(("%s download fw %s, nv %s\n", __FUNCTION__, dhd->fw_path, dhd->nv_path));
+ ret = dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh,
+ dhd->fw_path, dhd->nv_path);
+ if (ret < 0) {
+ DHD_ERROR(("%s: failed to download firmware %s\n",
+ __FUNCTION__, dhd->fw_path));
+ return ret;
+ }
+ }
+ if (dhd->pub.busstate != DHD_BUS_LOAD) {
+ return -ENETDOWN;
+ }
+
+ dhd_os_sdlock(dhdp);
+
+ /* 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));
+ dhd_os_sdunlock(dhdp);
+ return ret;
+ }
+#if defined(OOB_INTR_ONLY)
+ OOB_PARAM_IF(!(dhd->pub.oob_disable)) {
+ /* Host registration for OOB interrupt */
+ if (dhd_bus_oob_intr_register(dhdp)) {
+ /* deactivate timer and wait for the handler to finish */
+
+ flags = dhd_os_spin_lock(&dhd->pub);
+ dhd->wd_timer_valid = FALSE;
+ dhd_os_spin_unlock(&dhd->pub, flags);
+ del_timer_sync(&dhd->timer);
+
+ DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__));
+ dhd_os_sdunlock(dhdp);
+ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
+ return -ENODEV;
+ }
+
+ /* Enable oob at firmware */
+ dhd_enable_oob_intr(dhd->pub.bus, TRUE);
+ }
+#endif
+
+ /* If bus is not ready, can't come up */
+ if (dhd->pub.busstate != DHD_BUS_DATA) {
+ flags = dhd_os_spin_lock(&dhd->pub);
+ dhd->wd_timer_valid = FALSE;
+ dhd_os_spin_unlock(&dhd->pub, flags);
+ del_timer_sync(&dhd->timer);
+ DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__));
+ dhd_os_sdunlock(dhdp);
+ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
+ return -ENODEV;
+ }
+
+ dhd_os_sdunlock(dhdp);
+
+ dhd_process_cid_mac(dhdp, TRUE);
+
+ /* Bus is ready, do any protocol initialization */
+ if ((ret = dhd_prot_init(&dhd->pub)) < 0)
+ return ret;
+
+ dhd_process_cid_mac(dhdp, FALSE);
+
+#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 */
+
+ return 0;
+}
+#ifdef WLTDLS
+int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac)
+{
+ char iovbuf[WLC_IOCTL_SMLEN];
+ 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;
+ bcm_mkiovar("tdls_enable", (char *)&tdls, sizeof(tdls), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 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;
+ bcm_mkiovar("tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op),
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret));
+ goto exit;
+ }
+
+ if (tdls_auto_op) {
+ bcm_mkiovar("tdls_idle_time", (char *)&tdls_idle_time,
+ sizeof(tdls_idle_time), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret));
+ goto exit;
+ }
+ bcm_mkiovar("tdls_rssi_high", (char *)&tdls_rssi_high, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s: tdls_rssi_high failed %d\n", __FUNCTION__, ret));
+ goto exit;
+ }
+ bcm_mkiovar("tdls_rssi_low", (char *)&tdls_rssi_low, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 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_info_t **)netdev_priv(dev);
+ int ret = 0;
+ if (dhd)
+ ret = _dhd_tdls_enable(&dhd->pub, tdls_on, auto_on, mac);
+ else
+ ret = BCME_ERROR;
+ return ret;
+}
+#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));
+ bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
+ FALSE, 0)) < 0) {
+ DHD_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 defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
+ /* For customer_hw4, although ICS,
+ * we still support concurrent mode
+ */
+ return ret;
+#else
+ return 0;
+#endif
+ }
+ }
+ }
+ return 0;
+}
+#endif
+
+
+int
+dhd_preinit_ioctls(dhd_pub_t *dhd)
+{
+ int ret = 0;
+ char eventmask[WL_EVENTING_MASK_LEN];
+ char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
+ uint8 msglen;
+ eventmsgs_ext_t *eventmask_msg;
+ char iov_buf[WLC_IOCTL_SMLEN];
+ uint32 buf_key_b4_m4 = 1;
+ int ret2 = 0;
+#if defined(CUSTOM_AMPDU_BA_WSIZE)
+ uint32 ampdu_ba_wsize = 0;
+#endif
+#if defined(CUSTOM_AMPDU_MPDU)
+ uint32 ampdu_mpdu = 0;
+#endif
+
+#ifdef PROP_TXSTATUS
+ int wlfc_enable = TRUE;
+#ifndef DISABLE_11N
+ uint32 hostreorder = 1;
+#endif /* DISABLE_11N */
+#endif /* PROP_TXSTATUS */
+
+#ifdef DHD_ENABLE_LPC
+ uint32 lpc = 1;
+#endif /* DHD_ENABLE_LPC */
+ uint power_mode = PM_FAST;
+ uint32 dongle_align = DHD_SDALIGN;
+ uint32 glom = CUSTOM_GLOM_SETTING;
+#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL)
+ uint32 credall = 1;
+#endif
+#if defined(VSDB) || defined(ROAM_ENABLE)
+ uint bcn_timeout = 8;
+#else
+ uint bcn_timeout = 4;
+#endif
+ uint retry_max = 7;
+#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 */
+#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 ROAM_AP_ENV_DETECTION
+ int roam_env_mode = AP_ENV_INDETERMINATE;
+#endif /* ROAM_AP_ENV_DETECTION */
+#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 */
+#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))
+ uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
+ struct ether_addr p2p_ea;
+#endif
+
+#if defined(AP) || defined(WLP2P)
+ uint32 apsta = 1; /* Enable APSTA mode */
+#endif /* defined(AP) || defined(WLP2P) */
+#ifdef GET_CUSTOM_MAC_ENABLE
+ struct ether_addr ea_addr;
+#endif /* GET_CUSTOM_MAC_ENABLE */
+
+#ifdef DISABLE_11N
+ uint32 nmode = 0;
+#endif /* DISABLE_11N */
+
+#ifdef USE_WL_TXBF
+ uint32 txbf = 1;
+#endif /* USE_WL_TXBF */
+#ifdef USE_WL_FRAMEBURST
+ uint32 frameburst = 1;
+#endif /* USE_WL_FRAMEBURST */
+#ifdef CUSTOM_PSPRETEND_THR
+ uint32 pspretend_thr = CUSTOM_PSPRETEND_THR;
+#endif
+#ifdef DISABLE_AUTOCOUNTRY
+ uint32 autocountry = 0;
+#endif /* DISABLE_AUTOCOUNTRY */
+
+#ifdef PKT_FILTER_SUPPORT
+ dhd_pkt_filter_enable = TRUE;
+#endif /* PKT_FILTER_SUPPORT */
+#ifdef WLTDLS
+ dhd->tdls_enable = FALSE;
+#endif /* WLTDLS */
+ dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM;
+ DHD_TRACE(("Enter %s\n", __FUNCTION__));
+ dhd->op_mode = 0;
+ if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) ||
+ (op_mode == DHD_FLAG_MFG_MODE)) {
+ /* 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
+ ret = wifi_platform_get_mac_addr(dhd->info->adapter, ea_addr.octet);
+ if (!ret) {
+ memset(buf, 0, sizeof(buf));
+ bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
+ if (ret < 0) {
+ DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
+ return BCME_NOTUP;
+ }
+ memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN);
+ } else {
+#endif /* GET_CUSTOM_MAC_ENABLE */
+ /* Get the default device MAC address directly from firmware */
+ 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));
+ return BCME_NOTUP;
+ }
+ /* Update public MAC address after reading from Firmware */
+ memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
+
+#ifdef GET_CUSTOM_MAC_ENABLE
+ }
+#endif /* GET_CUSTOM_MAC_ENABLE */
+ /* get a capabilities from firmware */
+ memset(dhd->fw_capabilities, 0, sizeof(dhd->fw_capabilities));
+ bcm_mkiovar("cap", 0, 0, dhd->fw_capabilities, sizeof(dhd->fw_capabilities));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, dhd->fw_capabilities,
+ sizeof(dhd->fw_capabilities), FALSE, 0)) < 0) {
+ DHD_ERROR(("%s: Get Capability failed (error=%d)\n",
+ __FUNCTION__, ret));
+ return 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
+ dhd->op_mode = DHD_FLAG_HOSTAP_MODE;
+#if defined(ARP_OFFLOAD_SUPPORT)
+ arpoe = 0;
+#endif
+#ifdef PKT_FILTER_SUPPORT
+ dhd_pkt_filter_enable = FALSE;
+#endif
+#ifdef SET_RANDOM_MAC_SOFTAP
+ SRANDOM32((uint)jiffies);
+ rand_mac = RANDOM32();
+ iovbuf[0] = 0x02; /* locally administered bit */
+ iovbuf[1] = 0x1A;
+ iovbuf[2] = 0x11;
+ iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0;
+ iovbuf[4] = (unsigned char)(rand_mac >> 8);
+ iovbuf[5] = (unsigned char)(rand_mac >> 16);
+
+ bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
+ if (ret < 0) {
+ DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
+ } else
+ memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
+#endif /* SET_RANDOM_MAC_SOFTAP */
+#if !defined(AP) && defined(WL_CFG80211)
+ /* Turn off MPC in AP mode */
+ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret));
+ }
+#endif
+ } 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;
+ } 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) {
+ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret));
+ }
+
+ memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN);
+ ETHER_SET_LOCALADDR(&p2p_ea);
+ bcm_mkiovar("p2p_da_override", (char *)&p2p_ea,
+ ETHER_ADDR_LEN, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 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
+ }
+
+ DHD_ERROR(("Firmware up: op_mode=0x%04x, MAC="MACDBG"\n",
+ dhd->op_mode, MAC2STRDBG(dhd->mac.octet)));
+ /* Set Country code */
+ if (dhd->dhd_cspec.ccode[0] != 0) {
+ bcm_mkiovar("country", (char *)&dhd->dhd_cspec,
+ sizeof(wl_country_t), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
+ }
+
+#if defined(DISABLE_AUTOCOUNTRY)
+ /* disable setting country to AP's country */
+ bcm_mkiovar("autocountry", (char *)&autocountry, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s disabling autocountry failed %d\n", __FUNCTION__, ret));
+#endif /* DISABLE_AUTOCOUNTRY */
+
+
+ /* Set Listen Interval */
+ bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret));
+
+#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM)
+ /* Disable built-in roaming to allowed ext supplicant to take care of roaming */
+ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */
+#if defined(ROAM_ENABLE)
+ 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));
+ bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret));
+#ifdef ROAM_AP_ENV_DETECTION
+ if (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER) {
+ bcm_mkiovar("roam_env_detection", (char *)&roam_env_mode,
+ 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) == BCME_OK)
+ dhd->roam_env_detection = TRUE;
+ else {
+ dhd->roam_env_detection = FALSE;
+ }
+ }
+#endif /* ROAM_AP_ENV_DETECTION */
+#endif /* ROAM_ENABLE */
+
+#ifdef WLTDLS
+ /* by default TDLS on and auto mode off */
+ _dhd_tdls_enable(dhd, true, false, NULL);
+#endif /* WLTDLS */
+
+#ifdef DHD_ENABLE_LPC
+ /* Set lpc 1 */
+ bcm_mkiovar("lpc", (char *)&lpc, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set lpc failed %d\n", __FUNCTION__, ret));
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+ 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));
+
+ bcm_mkiovar("lpc", (char *)&lpc, 4, iovbuf, sizeof(iovbuf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ DHD_ERROR(("%s Set lpc ret --> %d\n", __FUNCTION__, ret));
+ }
+#endif
+ }
+#endif /* DHD_ENABLE_LPC */
+
+ /* Set PowerSave mode */
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0);
+
+ /* Match Host and Dongle rx alignment */
+ bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
+#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL)
+ /* enable credall to reduce the chance of no bus credit happened. */
+ bcm_mkiovar("bus:credall", (char *)&credall, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif
+
+ if (glom != DEFAULT_GLOM_VALUE) {
+ DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom));
+ bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ }
+
+ /* Setup timeout if Beacons are lost and roam is off to report link down */
+ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ /* Setup assoc_retry_max count to reconnect target AP in dongle */
+ bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#if defined(AP) && !defined(WLP2P)
+ /* Turn off MPC in AP mode */
+ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* defined(AP) && !defined(WLP2P) */
+
+
+
+#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
+ bcm_mkiovar("txbf", (char *)&txbf, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set txbf failed %d\n", __FUNCTION__, ret));
+ }
+#endif /* USE_WL_TXBF */
+#ifdef USE_WL_FRAMEBURST
+#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_ERROR(("%s Set frameburst failed %d\n", __FUNCTION__, ret));
+ }
+#endif /* USE_WL_FRAMEBURST */
+#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) {
+ bcm_mkiovar("ampdu_ba_wsize", (char *)&ampdu_ba_wsize, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed %d\n",
+ __FUNCTION__, ampdu_ba_wsize, ret));
+ }
+ }
+#endif
+
+
+#if defined(CUSTOM_AMPDU_MPDU)
+ ampdu_mpdu = CUSTOM_AMPDU_MPDU;
+ if (ampdu_mpdu != 0 && (ampdu_mpdu <= ampdu_ba_wsize)) {
+ bcm_mkiovar("ampdu_mpdu", (char *)&ampdu_mpdu, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set ampdu_mpdu to %d failed %d\n",
+ __FUNCTION__, CUSTOM_AMPDU_MPDU, ret));
+ }
+ }
+#endif /* CUSTOM_AMPDU_MPDU */
+
+#ifdef CUSTOM_PSPRETEND_THR
+ /* Turn off MPC in AP mode */
+ bcm_mkiovar("pspretend_threshold", (char *)&pspretend_thr, 4,
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s pspretend_threshold for HostAPD failed %d\n",
+ __FUNCTION__, ret));
+ }
+#endif
+
+ bcm_mkiovar("buf_key_b4_m4", (char *)&buf_key_b4_m4, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s buf_key_b4_m4 set failed %d\n", __FUNCTION__, ret));
+ }
+
+ /* Read event_msgs mask */
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 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_ASSOC);
+ setbit(eventmask, WLC_E_REASSOC);
+ setbit(eventmask, WLC_E_REASSOC_IND);
+ 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_START);
+ setbit(eventmask, WLC_E_ASSOC_IND);
+ setbit(eventmask, WLC_E_PSK_SUP);
+ setbit(eventmask, WLC_E_LINK);
+ setbit(eventmask, WLC_E_NDIS_LINK);
+ setbit(eventmask, WLC_E_MIC_ERROR);
+ setbit(eventmask, WLC_E_ASSOC_REQ_IE);
+ setbit(eventmask, WLC_E_ASSOC_RESP_IE);
+#ifndef WL_CFG80211
+ setbit(eventmask, WLC_E_PMKID_CACHE);
+ setbit(eventmask, WLC_E_TXFAIL);
+#endif
+ setbit(eventmask, WLC_E_JOIN_START);
+ setbit(eventmask, WLC_E_SCAN_COMPLETE);
+#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);
+ setbit(eventmask, WLC_E_BSSID);
+#ifdef WLTDLS
+ setbit(eventmask, WLC_E_TDLS_PEER_EVENT);
+#endif /* WLTDLS */
+#ifdef WL_CFG80211
+ setbit(eventmask, WLC_E_ESCAN_RESULT);
+ if (dhd->op_mode & DHD_FLAG_P2P_MODE) {
+ setbit(eventmask, WLC_E_ACTION_FRAME_RX);
+ setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE);
+ }
+#endif /* WL_CFG80211 */
+ setbit(eventmask, WLC_E_TRACE);
+ setbit(eventmask, WLC_E_CSA_COMPLETE_IND);
+
+ /* Write updated Event mask */
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 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));
+ return BCME_NOMEM;
+ }
+ bzero(eventmask_msg, msglen);
+ eventmask_msg->ver = EVENTMSGS_VER;
+ eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY;
+
+ /* Read event_msgs_ext mask */
+ bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg, msglen, iov_buf, sizeof(iov_buf));
+ ret2 = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iov_buf, sizeof(iov_buf), FALSE, 0);
+ if (ret2 != BCME_UNSUPPORTED)
+ ret = ret2;
+ if (ret2 == 0) { /* event_msgs_ext must be supported */
+ bcopy(iov_buf, eventmask_msg, msglen);
+
+ /* Enable required event mask */
+ setbit(eventmask_msg->mask, WLC_E_PKT_FILTER);
+
+ /* Write updated Event mask */
+ eventmask_msg->ver = EVENTMSGS_VER;
+ eventmask_msg->command = EVENTMSGS_SET_MASK;
+ eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY;
+ bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg,
+ msglen, iov_buf, sizeof(iov_buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iov_buf, sizeof(iov_buf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s write event mask ext failed %d\n", __FUNCTION__, ret));
+ kfree(eventmask_msg);
+ goto done;
+ }
+ } else if (ret2 < 0 && ret2 != BCME_UNSUPPORTED) {
+ DHD_ERROR(("%s read event mask ext failed %d\n", __FUNCTION__, ret2));
+ kfree(eventmask_msg);
+ goto done;
+ } /* unsupported is ok */
+ kfree(eventmask_msg);
+
+ 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 */
+ dhd->pktfilter_count = 6;
+ /* Setup filter to allow only unicast */
+ dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00";
+ dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL;
+ dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL;
+ dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL;
+ /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */
+ dhd->pktfilter[DHD_MDNS_FILTER_NUM] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB";
+ /* apply APP pktfilter */
+ dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806";
+
+
+#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
+ bcm_mkiovar("nmode", (char *)&nmode, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret));
+#endif /* DISABLE_11N */
+
+
+ /* query for 'ver' to get version info from firmware */
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0)
+ DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
+ else {
+ bcmstrtok(&ptr, "\n", 0);
+ /* Print fw version info */
+ DHD_ERROR(("Firmware version = %s\n", buf));
+ dhd_set_version_info(dhd, buf);
+ }
+
+ dhd_txglom_enable(dhd, TRUE);
+
+#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;
+ }
+
+#ifndef DISABLE_11N
+ bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, iovbuf, sizeof(iovbuf));
+ if ((ret2 = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s wl ampdu_hostreorder failed %d\n", __FUNCTION__, ret2));
+ if (ret2 != BCME_UNSUPPORTED)
+ ret = ret2;
+#if defined(CUSTOM_PLATFORM_NV_TEGRA)
+ 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));
+
+ bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4,
+ iovbuf, sizeof(iovbuf));
+ ret2 = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ DHD_ERROR(("%s wl ampdu_hostreorder. ret --> %d\n", __FUNCTION__, ret2));
+ if (ret2 != BCME_UNSUPPORTED)
+ ret = ret2;
+ }
+#endif
+ if (ret2 != BCME_OK)
+ hostreorder = 0;
+ }
+#endif /* DISABLE_11N */
+ if (wlfc_enable)
+ dhd_wlfc_init(dhd);
+#ifndef DISABLE_11N
+ else if (hostreorder)
+ dhd_wlfc_hostreorder_init(dhd);
+#endif /* DISABLE_11N */
+
+#endif /* PROP_TXSTATUS */
+#ifdef PNO_SUPPORT
+ if (!dhd->pno_state) {
+ dhd_pno_init(dhd);
+ }
+#endif
+#ifdef WL11U
+ dhd_interworking_enable(dhd);
+#endif /* WL11U */
+
+done:
+ return ret;
+}
+
+
+int
+dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set)
+{
+ char buf[strlen(name) + 1 + cmd_len];
+ int len = sizeof(buf);
+ wl_ioctl_t ioc;
+ int ret;
+
+ len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len);
+
+ memset(&ioc, 0, sizeof(ioc));
+
+ ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR;
+ ioc.buf = buf;
+ ioc.len = len;
+ ioc.set = set;
+
+ ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len);
+ if (!set && ret >= 0)
+ memcpy(cmd_buf, buf, cmd_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", 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_info_t **)netdev_priv(ifa->ifa_dev->dev);
+ if (!dhd)
+ return NOTIFY_DONE;
+
+ dhd_pub = &dhd->pub;
+
+#if defined(ARP_OFFLOAD_SUPPORT)
+ if (dhd_pub->arp_version == 1) {
+ idx = 0;
+ }
+ else {
+#else
+ {
+#endif
+ 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 */
+ 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__));
+ aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx);
+#else
+ dhd_aoe_hostip_clr(&dhd->pub, idx);
+ dhd_aoe_arp_clr(&dhd->pub, idx);
+#endif /* AOE_IP_ALIAS_SUPPORT */
+ 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 */
+
+/* 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_pub_t *pub = &((dhd_info_t *)dhd_info)->pub;
+ int ret;
+
+ if (event != DHD_WQ_WORK_IPV6_NDO) {
+ DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
+ return;
+ }
+
+ if (!ndo_work) {
+ DHD_ERROR(("%s: ipv6 work info is not initialized \n", __FUNCTION__));
+ return;
+ }
+
+ if (!pub) {
+ DHD_ERROR(("%s: dhd pub is not initialized \n", __FUNCTION__));
+ return;
+ }
+
+ if (ndo_work->if_idx) {
+ DHD_ERROR(("%s: idx %d \n", __FUNCTION__, ndo_work->if_idx));
+ return;
+ }
+
+ switch (ndo_work->event) {
+ case NETDEV_UP:
+ DHD_TRACE(("%s: Enable NDO and add ipv6 into table \n ", __FUNCTION__));
+ ret = dhd_ndo_enable(pub, TRUE);
+ if (ret < 0) {
+ DHD_ERROR(("%s: Enabling NDO Failed %d\n", __FUNCTION__, ret));
+ }
+
+ ret = dhd_ndo_add_ip(pub, &ndo_work->ipv6_addr[0], ndo_work->if_idx);
+ if (ret < 0) {
+ DHD_ERROR(("%s: Adding host ip for NDO failed %d\n",
+ __FUNCTION__, ret));
+ }
+ break;
+ case NETDEV_DOWN:
+ DHD_TRACE(("%s: clear ipv6 table \n", __FUNCTION__));
+ ret = dhd_ndo_remove_ip(pub, ndo_work->if_idx);
+ if (ret < 0) {
+ DHD_ERROR(("%s: Removing host ip for NDO failed %d\n",
+ __FUNCTION__, ret));
+ goto done;
+ }
+
+ ret = dhd_ndo_enable(pub, FALSE);
+ if (ret < 0) {
+ DHD_ERROR(("%s: disabling NDO Failed %d\n", __FUNCTION__, ret));
+ goto done;
+ }
+ break;
+ default:
+ DHD_ERROR(("%s: unknown notifier event \n", __FUNCTION__));
+ break;
+ }
+done:
+ /* free ndo_work. alloced while scheduling the work */
+ kfree(ndo_work);
+
+ return;
+}
+
+/*
+ * Neighbor Discovery Offload: Called when an interface
+ * is assigned with ipv6 address.
+ * Handles only primary interface
+ */
+static int dhd_inet6addr_notifier_call(struct notifier_block *this,
+ unsigned long event,
+ void *ptr)
+{
+ dhd_info_t *dhd;
+ dhd_pub_t *dhd_pub;
+ struct inet6_ifaddr *inet6_ifa = ptr;
+ struct in6_addr *ipv6_addr = &inet6_ifa->addr;
+ struct ipv6_work_info_t *ndo_info;
+ int idx = 0; /* REVISIT */
+
+#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_info_t **)netdev_priv(inet6_ifa->idev->dev);
+ if (!dhd)
+ return NOTIFY_DONE;
+
+ if (dhd->iflist[idx] && dhd->iflist[idx]->net != inet6_ifa->idev->dev)
+ return NOTIFY_DONE;
+ dhd_pub = &dhd->pub;
+ if (!FW_SUPPORTED(dhd_pub, 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;
+ }
+
+ ndo_info->event = event;
+ ndo_info->if_idx = idx;
+ memcpy(&ndo_info->ipv6_addr[0], ipv6_addr, IPV6_ADDR_LEN);
+
+ /* defer the work to thread as it may block kernel */
+ dhd_deferred_schedule_work((void *)ndo_info, DHD_WQ_WORK_IPV6_NDO,
+ dhd_inet6_work_handler, DHD_WORK_PRIORITY_LOW);
+ return NOTIFY_DONE;
+}
+
+int
+dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock)
+{
+ dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
+ 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));
+
+ ASSERT(dhd && dhd->iflist[ifidx]);
+ net = dhd->iflist[ifidx]->net;
+ ASSERT(net);
+
+#ifndef P2PONEINT
+#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) */
+#else
+ net->netdev_ops = &dhd_cfgp2p_ops_virt;
+#endif /* P2PONEINT */
+
+ /* 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, dhd->iflist[ifidx]->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 = (struct iw_handler_def *)&wl_iw_handler_def;
+#endif /* WIRELESS_EXT > 12 */
+#endif /* defined(WL_WIRELESS_EXT) */
+
+ dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net);
+
+ memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
+
+ if (ifidx == 0)
+ printf("%s\n", dhd_version);
+
+ 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;
+ }
+
+
+ printf("Register interface [%s] MAC: "MACDBG"\n\n", net->name,
+ MAC2STRDBG(net->dev_addr));
+
+#if defined(SOFTAP) && defined(WL_WIRELESS_EXT) && !defined(WL_CFG80211)
+ wl_iw_iscan_set_scan_broadcast_prep(net, 1);
+#endif
+
+#if defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ if (ifidx == 0) {
+#ifdef BCMLXSDMMC
+ up(&dhd_registration_sem);
+#endif
+ if (!dhd_download_fw_on_driverload) {
+#ifdef WL_CFG80211
+ wl_terminate_event_handler();
+#endif /* WL_CFG80211 */
+ dhd_net_bus_devreset(net, TRUE);
+ dhd_net_bus_suspend(net);
+ wifi_platform_set_power(dhdp->info->adapter, FALSE, WIFI_TURNOFF_DELAY);
+ }
+ }
+#endif /* OEM_ANDROID && BCMLXSDMMC && (LINUX_VERSION_CODE >= 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) {
+ /* Stop the protocol module */
+ dhd_prot_stop(&dhd->pub);
+
+ /* Stop the bus module */
+ dhd_bus_stop(dhd->pub.bus, TRUE);
+ }
+
+#if defined(OOB_INTR_ONLY)
+ OOB_PARAM_IF(!(dhdp->oob_disable)) {
+ 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;
+
+ if (!dhdp)
+ return;
+
+ dhd = (dhd_info_t *)dhdp->info;
+ if (!dhd)
+ return;
+
+ 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 WL_CFG80211
+ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
+ wl_cfg80211_down(NULL);
+ }
+#endif /* WL_CFG80211 */
+
+ if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) {
+ dhd_bus_detach(dhdp);
+
+ if (dhdp->prot)
+ dhd_prot_detach(dhdp);
+ }
+
+#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 (dhd_inet6addr_notifier_registered) {
+ dhd_inet6addr_notifier_registered = FALSE;
+ unregister_inet6addr_notifier(&dhd_inet6addr_notifier);
+ }
+
+#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();
+ }
+#endif /* defined(WL_WIRELESS_EXT) */
+
+ /* 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) {
+ /* 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
+ unregister_netdev(ifp->net);
+ ifp->net = NULL;
+ MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
+ dhd->iflist[0] = NULL;
+ }
+ }
+
+ /* Clear the watchdog timer */
+ flags = dhd_os_spin_lock(&dhd->pub);
+ timer_valid = dhd->wd_timer_valid;
+ dhd->wd_timer_valid = FALSE;
+ dhd_os_spin_unlock(&dhd->pub, flags);
+ if (timer_valid)
+ del_timer_sync(&dhd->timer);
+
+ if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) {
+ 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);
+ }
+#ifdef WL_CFG80211
+ if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
+ wl_cfg80211_detach(NULL);
+ dhd_monitor_uninit();
+ }
+#endif
+ /* free deferred work queue */
+ dhd_deferred_work_deinit(dhd->dhd_deferred_wq);
+ dhd->dhd_deferred_wq = NULL;
+
+#ifdef SHOW_LOGTRACE
+ if (dhd->event_data.fmts)
+ kfree(dhd->event_data.fmts);
+ if (dhd->event_data.raw_fmts)
+ kfree(dhd->event_data.raw_fmts);
+ if (dhd->event_data.raw_sstr)
+ kfree(dhd->event_data.raw_sstr);
+#endif /* SHOW_LOGTRACE */
+#ifdef PNO_SUPPORT
+ if (dhdp->pno_state)
+ dhd_pno_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 SAR_SUPPORT
+ if (dhd_sar_notifier_registered) {
+ unregister_notifier_by_sar(&dhd->sar_notifier);
+ dhd_sar_notifier_registered = FALSE;
+ }
+#endif
+#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
+ if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) {
+ DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter));
+#ifdef CONFIG_HAS_WAKELOCK
+ dhd->wakelock_counter = 0;
+ dhd->wakelock_wd_counter = 0;
+ dhd->wakelock_rx_timeout_enable = 0;
+ dhd->wakelock_ctrl_timeout_enable = 0;
+ wake_lock_destroy(&dhd->wl_wifi);
+ wake_lock_destroy(&dhd->wl_rxwake);
+ wake_lock_destroy(&dhd->wl_ctrlwake);
+ wake_lock_destroy(&dhd->wl_wdwake);
+#endif /* CONFIG_HAS_WAKELOCK */
+ }
+
+
+#ifdef DHDTCPACK_SUPPRESS
+ /* This will free all MEM allocated for TCPACK SUPPRESS */
+ dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF);
+#endif /* DHDTCPACK_SUPPRESS */
+}
+
+
+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 = (dhd_info_t *)dhdp->info;
+ /* If pointer is allocated by dhd_os_prealloc then avoid MFREE */
+ if (dhd &&
+ dhd != (dhd_info_t *)dhd_os_prealloc(dhdp, DHD_PREALLOC_DHD_INFO, 0, FALSE))
+ MFREE(dhd->pub.osh, dhd, sizeof(*dhd));
+ dhd = NULL;
+ }
+}
+
+static void __exit
+dhd_module_cleanup(void)
+{
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ dhd_bus_unregister();
+
+ wl_android_exit();
+
+ dhd_wifi_platform_unregister_drv();
+}
+
+static int __init
+dhd_module_init(void)
+{
+ int err;
+
+ DHD_ERROR(("%s in\n", __FUNCTION__));
+ err = dhd_wifi_platform_register_drv();
+
+ return err;
+}
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+#if defined(CONFIG_DEFERRED_INITCALLS)
+deferred_module_init(dhd_module_init);
+#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_cleanup);
+
+/*
+ * 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) {
+ down(&dhd->proto_sem);
+ 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;
+}
+
+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, bool *pending)
+{
+ 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
+
+ timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout);
+ 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;
+}
+
+void
+dhd_os_wd_timer_extend(void *bus, bool extend)
+{
+ 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);
+}
+
+
+void
+dhd_os_wd_timer(void *bus, uint wdtick)
+{
+ 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;
+ }
+
+ flags = dhd_os_spin_lock(pub);
+
+ /* don't start the wd until fw is loaded */
+ if (pub->busstate == DHD_BUS_DOWN) {
+ dhd_os_spin_unlock(pub, flags);
+ if (!wdtick)
+ DHD_OS_WD_WAKE_UNLOCK(pub);
+ return;
+ }
+
+ /* Totally stop the timer */
+ if (!wdtick && dhd->wd_timer_valid == TRUE) {
+ dhd->wd_timer_valid = FALSE;
+ dhd_os_spin_unlock(pub, flags);
+ del_timer_sync(&dhd->timer);
+ DHD_OS_WD_WAKE_UNLOCK(pub);
+ return;
+ }
+
+ if (wdtick) {
+ DHD_OS_WD_WAKE_LOCK(pub);
+ 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_os_spin_unlock(pub, flags);
+}
+
+void *
+dhd_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
+dhd_os_get_image_block(char *buf, int len, void *image)
+{
+ struct file *fp = (struct file *)image;
+ int rdlen;
+
+ if (!image)
+ return 0;
+
+ rdlen = kernel_read(fp, fp->f_pos, buf, len);
+ if (rdlen > 0)
+ fp->f_pos += rdlen;
+
+ return rdlen;
+}
+
+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);
+
+ if (dhd_dpc_prio >= 0)
+ down(&dhd->sdsem);
+ else
+ spin_lock_bh(&dhd->sdlock);
+}
+
+void
+dhd_os_sdunlock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+
+ if (dhd_dpc_prio >= 0)
+ up(&dhd->sdsem);
+ else
+ spin_unlock_bh(&dhd->sdlock);
+}
+
+void
+dhd_os_sdlock_txq(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+ spin_lock_bh(&dhd->txqlock);
+}
+
+void
+dhd_os_sdunlock_txq(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+ spin_unlock_bh(&dhd->txqlock);
+}
+
+void
+dhd_os_sdlock_rxq(dhd_pub_t *pub)
+{
+}
+
+void
+dhd_os_sdunlock_rxq(dhd_pub_t *pub)
+{
+}
+
+void
+dhd_os_sdtxlock(dhd_pub_t *pub)
+{
+ dhd_os_sdlock(pub);
+}
+
+void
+dhd_os_sdtxunlock(dhd_pub_t *pub)
+{
+ dhd_os_sdunlock(pub);
+}
+
+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
+void
+dhd_os_tcpacklock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+ spin_lock_bh(&dhd->tcpack_lock);
+
+}
+
+void
+dhd_os_tcpackunlock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+ spin_unlock_bh(&dhd->tcpack_lock);
+}
+#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;
+
+ if (section > DHD_PREALLOC_SECTION_MAX) {
+ DHD_ERROR(("%s: Invalid Section ID: %d\n", __FUNCTION__, section));
+ return NULL;
+ }
+
+ buf = (uint8*)wifi_platform_prealloc(dhdpub->info->adapter, section, size);
+ if (buf == NULL && kmalloc_if_fail) {
+ if (isset(dhdpub->prealloc_malloc_mask, section)) {
+ DHD_ERROR(("%s: Section %d(size: %d) is already allocated\n",
+ __FUNCTION__, section, size));
+ return NULL;
+ }
+
+ buf = kmalloc(size, flags);
+ if (buf) {
+ DHD_ERROR(("%s: Preallocated memory section %d(size: %d)"
+ "allocated by kmalloc\n", __FUNCTION__,
+ section, size));
+ setbit(dhdpub->prealloc_malloc_mask, section);
+ }
+ }
+
+ return buf;
+}
+
+void dhd_os_prefree(dhd_pub_t *dhdpub, int section, void *addr, uint size)
+{
+ if (section > DHD_PREALLOC_SECTION_MAX) {
+ DHD_ERROR(("%s: Invalid Section ID: %d\n", __FUNCTION__, section));
+ return;
+ }
+
+ if (addr && isset(dhdpub->prealloc_malloc_mask, section)) {
+ DHD_ERROR(("%s: Preallocated memory section %d(size: %d)"
+ "memory is freed by kfree\n", __FUNCTION__,
+ section, size));
+ clrbit(dhdpub->prealloc_malloc_mask, section);
+ kfree(addr);
+ }
+}
+
+#if defined(WL_WIRELESS_EXT)
+struct iw_statistics *
+dhd_get_wireless_stats(struct net_device *dev)
+{
+ int res = 0;
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(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;
+ ASSERT(dhd != NULL);
+
+#ifdef SHOW_LOGTRACE
+ bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, pktlen, event, data, &dhd->event_data);
+#else
+ bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, pktlen, event, data, NULL);
+#endif /* SHOW_LOGTRACE */
+
+ if (bcmerror != BCME_OK)
+ return (bcmerror);
+
+#if defined(WL_WIRELESS_EXT)
+ if (event->bsscfgidx == 0) {
+ /*
+ * Wireless ext is on primary interface only
+ */
+
+ ASSERT(dhd->iflist[*ifidx] != NULL);
+ ASSERT(dhd->iflist[*ifidx]->net != NULL);
+
+ if (dhd->iflist[*ifidx]->net) {
+ wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
+ }
+ }
+#endif /* defined(WL_WIRELESS_EXT) */
+
+#ifdef WL_CFG80211
+ ASSERT(dhd->iflist[*ifidx] != NULL);
+ ASSERT(dhd->iflist[*ifidx]->net != NULL);
+ if (dhd->iflist[*ifidx]->net)
+ wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data);
+#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)
+{
+ switch (ntoh32(event->event_type)) {
+
+ default:
+ break;
+ }
+}
+
+#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, &eth.ether_dhost, ETHER_ADDR_LEN);
+ bcopy(&dhdp->mac, &eth.ether_shost, ETHER_ADDR_LEN);
+ ETHER_TOGGLE_LOCALADDR(&eth.ether_shost);
+ eth.ether_type = hton16(ETHER_TYPE_BRCM);
+
+ bcopy((void *)&eth, 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);
+
+ /* 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", __FUNCTION__));
+ }
+}
+#endif /* LOG_INTO_TCPDUMP */
+
+void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+ struct dhd_info *dhdinfo = dhd->info;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ int timeout = msecs_to_jiffies(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
+ return;
+}
+
+void dhd_wait_event_wakeup(dhd_pub_t *dhd)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+ struct dhd_info *dhdinfo = dhd->info;
+ if (waitqueue_active(&dhdinfo->ctrl_wait))
+ wake_up(&dhdinfo->ctrl_wait);
+#endif
+ return;
+}
+
+int
+dhd_net_bus_devreset(struct net_device *dev, uint8 flag)
+{
+ int ret;
+
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(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
+ }
+
+ 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);
+ }
+
+ ret = dhd_bus_devreset(&dhd->pub, flag);
+ if (ret) {
+ DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret));
+ return ret;
+ }
+
+ return ret;
+}
+
+int
+dhd_net_bus_suspend(struct net_device *dev)
+{
+ dhd_info_t *dhdinfo = *(dhd_info_t **)netdev_priv(dev);
+ return dhd_bus_suspend(&dhdinfo->pub);
+}
+
+int
+dhd_net_bus_resume(struct net_device *dev, uint8 stage)
+{
+ dhd_info_t *dhdinfo = *(dhd_info_t **)netdev_priv(dev);
+ return dhd_bus_resume(&dhdinfo->pub, stage);
+}
+
+int net_os_set_suspend_disable(struct net_device *dev, int val)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(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_info_t **)netdev_priv(dev);
+
+ if (dhd) {
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
+ ret = dhd_set_suspend(val, &dhd->pub);
+#else
+ ret = dhd_suspend_resume_helper(dhd, val, force);
+#endif
+#ifdef WL_CFG80211
+ wl_cfg80211_update_power_mode(dev);
+#endif
+ }
+ return ret;
+}
+
+int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+
+ if (dhd)
+ dhd->pub.suspend_bcn_li_dtim = val;
+
+ return 0;
+}
+
+#ifdef PKT_FILTER_SUPPORT
+int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+ char *filterp = NULL;
+ int filter_id = 0;
+ int ret = 0;
+
+ if (!dhd || (num == DHD_UNICAST_FILTER_NUM) ||
+ (num == DHD_MDNS_FILTER_NUM))
+ return ret;
+ if (num >= dhd->pub.pktfilter_count)
+ return -EINVAL;
+ switch (num) {
+ case DHD_BROADCAST_FILTER_NUM:
+ filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF";
+ filter_id = 101;
+ break;
+ case DHD_MULTICAST4_FILTER_NUM:
+ filterp = "102 0 0 0 0xFFFFFF 0x01005E";
+ filter_id = 102;
+ break;
+ case DHD_MULTICAST6_FILTER_NUM:
+ filterp = "103 0 0 0 0xFFFF 0x3333";
+ filter_id = 103;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Add filter */
+ if (add_remove) {
+ dhd->pub.pktfilter[num] = filterp;
+ dhd_pktfilter_offload_set(&dhd->pub, dhd->pub.pktfilter[num]);
+ } else { /* Delete filter */
+ if (dhd->pub.pktfilter[num] != NULL) {
+ dhd_pktfilter_offload_delete(&dhd->pub, filter_id);
+ dhd->pub.pktfilter[num] = NULL;
+ }
+ }
+ 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_info_t **)netdev_priv(dev);
+
+ 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_info_t **)netdev_priv(dev);
+ int ret;
+
+ dhd_process_cid_mac(&dhd->pub, TRUE);
+
+ if ((ret = dhd_prot_init(&dhd->pub)) < 0)
+ goto done;
+
+ dhd_process_cid_mac(&dhd->pub, FALSE);
+
+done:
+ return ret;
+}
+
+#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_info_t **)netdev_priv(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_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_info_t **)netdev_priv(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_info_t **)netdev_priv(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_info_t **)netdev_priv(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_info_t **)netdev_priv(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_info_t **)netdev_priv(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_info_t **)netdev_priv(dev);
+ return (dhd_pno_get_for_batch(&dhd->pub, buf, bufsize, PNO_STATUS_NORMAL));
+}
+#endif /* PNO_SUPPORT */
+
+#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;
+ dev = dhd->iflist[0]->net;
+
+ if (dev) {
+ rtnl_lock();
+ dev_close(dev);
+ rtnl_unlock();
+#if defined(WL_WIRELESS_EXT)
+ wl_iw_send_priv_event(dev, "HANG");
+#endif
+#if defined(WL_CFG80211)
+ wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
+#endif
+ }
+}
+
+int dhd_os_send_hang_message(dhd_pub_t *dhdp)
+{
+ int ret = 0;
+ if (dhdp) {
+ if (!dhdp->hang_was_sent) {
+ dhdp->hang_was_sent = 1;
+ dhd_deferred_schedule_work((void *)dhdp, DHD_WQ_WORK_HANG_MSG,
+ dhd_hang_process, DHD_WORK_PRIORITY_HIGH);
+ }
+ }
+ return ret;
+}
+
+int net_os_send_hang_message(struct net_device *dev)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+ int ret = 0;
+
+ if (dhd) {
+ /* Report FW problem when enabled */
+ if (dhd->pub.hang_report) {
+#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
+ } else {
+ DHD_ERROR(("%s: FW HANG ignored (for testing purpose) and not sent up\n",
+ __FUNCTION__));
+ /* Enforce bus down to stop any future traffic */
+ dhd->pub.busstate = DHD_BUS_DOWN;
+ }
+ }
+ return ret;
+}
+#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 *dhdinfo = *(dhd_info_t **)netdev_priv(dev);
+ return wifi_platform_set_power(dhdinfo->adapter, on, delay_msec);
+}
+
+void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code,
+ wl_country_t *cspec)
+{
+ dhd_info_t *dhdinfo = *(dhd_info_t **)netdev_priv(dev);
+ get_customized_country_code(dhdinfo->adapter, country_iso_code, cspec);
+}
+void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+ if (dhd && dhd->pub.up) {
+ memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
+#ifdef WL_CFG80211
+ wl_update_wiphybands(NULL, notify);
+#endif
+ }
+}
+
+void dhd_bus_band_set(struct net_device *dev, uint band)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+ if (dhd && dhd->pub.up) {
+#ifdef WL_CFG80211
+ wl_update_wiphybands(NULL, true);
+#endif
+ }
+}
+
+int dhd_net_set_fw_path(struct net_device *dev, char *fw)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(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_info_t **)netdev_priv(dev);
+ dhd_net_if_lock_local(dhd);
+}
+
+void dhd_net_if_unlock(struct net_device *dev)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(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_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_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);
+}
+
+static int
+dhd_get_pend_8021x_cnt(dhd_info_t *dhd)
+{
+ return (atomic_read(&dhd->pend_8021x_cnt));
+}
+
+#define MAX_WAIT_FOR_8021X_TX 50
+
+int
+dhd_wait_pend8021x(struct net_device *dev)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(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);
+ schedule_timeout(timeout);
+ 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;
+}
+
+#ifdef DHD_DEBUG
+int
+write_to_file(dhd_pub_t *dhd, uint8 *buf, int size)
+{
+ int ret = 0;
+ struct file *fp;
+ 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("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640);
+ if (!fp) {
+ printf("%s: open file error\n", __FUNCTION__);
+ ret = -1;
+ goto exit;
+ }
+
+ /* Write buf to file */
+ fp->f_op->write(fp, buf, size, &pos);
+
+exit:
+ /* free buf before return */
+ MFREE(dhd->osh, buf, size);
+ /* close file before return */
+ if (fp)
+ filp_close(fp, current->files);
+ /* restore previous address limit */
+ set_fs(old_fs);
+
+ return ret;
+}
+
+static void dhd_join_timeout(ulong data)
+{
+ dhd_info_t *dhd = (dhd_info_t *)data;
+ if (dhd->join_timer_active)
+ DHD_ERROR(("DHD: %s: JOIN TIMEOUT\n",
+ __FUNCTION__));
+}
+
+int dhd_start_join_timer(dhd_pub_t *pub)
+{
+ int ret;
+ dhd_info_t *dhd = (dhd_info_t *)pub->info;
+ DHD_INFO(("DHD: Join Timer Started:%s:\n", __FUNCTION__));
+ if (!dhd->join_timeout_val)
+ dhd->join_timeout_val = DHD_JOIN_MAX_TIME_DEFAULT;
+ init_timer(&dhd->join_timer);
+ dhd->join_timer.data = (ulong)dhd;
+ dhd->join_timer.function = dhd_join_timeout;
+ dhd->join_timer_active = TRUE;
+ ret = mod_timer(&dhd->join_timer, jiffies + msecs_to_jiffies(dhd->join_timeout_val));
+ return ret;
+}
+int dhd_del_join_timer(dhd_pub_t *pub)
+{
+ int ret = BCME_OK;
+ dhd_info_t *dhd = (dhd_info_t *)pub->info;
+ if (dhd->join_timer_active) {
+ ret = del_timer(&dhd->join_timer);
+ DHD_INFO(("DHD: Join Timer Stopped:%s:\n", __FUNCTION__));
+ }
+ return ret;
+}
+int dhd_set_join_timeout(dhd_pub_t *pub, uint32 timeout)
+{
+ int ret = BCME_OK;
+ dhd_info_t *dhd = (dhd_info_t *)pub->info;
+ if (timeout) {
+ dhd->join_timeout_val = timeout;
+ return ret;
+ }
+ DHD_ERROR(("DHD: Join Timer Can not be zero:%s:\n", __FUNCTION__));
+ return BCME_ERROR;
+}
+uint32 dhd_get_join_timeout(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd = (dhd_info_t *)pub->info;
+ return dhd->join_timeout_val;
+}
+
+static void dhd_scan_timeout(ulong data)
+{
+ dhd_info_t *dhd = (dhd_info_t *)data;
+ if (dhd->scan_timer_active) {
+ DHD_ERROR(("DHD: %s: SCAN TIMEOUT\n",
+ __FUNCTION__));
+ }
+}
+int dhd_add_scan_timer(dhd_pub_t *pub)
+{
+ int ret;
+ dhd_info_t *dhd = (dhd_info_t *)pub->info;
+ DHD_ERROR(("DHD: Scan Timer Started:%s:\n", __FUNCTION__));
+ if (!dhd->scan_time_count)
+ dhd->scan_time_count = DHD_SCAN_DEF_TIMEOUT;
+ init_timer(&dhd->scan_timer);
+ dhd->scan_timer.data = (ulong)dhd;
+ dhd->scan_timer.function = dhd_scan_timeout;
+ dhd->scan_timer_active = TRUE;
+ ret = mod_timer(&dhd->scan_timer, jiffies + msecs_to_jiffies(dhd->scan_time_count));
+ return ret;
+}
+int dhd_del_scan_timer(dhd_pub_t *pub)
+{
+ int ret = BCME_OK;
+ dhd_info_t *dhd = (dhd_info_t *)pub->info;
+ if (dhd->scan_timer_active) {
+ ret = del_timer(&dhd->scan_timer);
+ DHD_INFO(("DHD: Scan Timer Stopped:%s:\n", __FUNCTION__));
+ }
+ return ret;
+}
+
+int dhd_set_scan_timeout(dhd_pub_t *pub, uint32 timeout)
+{
+ int ret = BCME_OK;
+ dhd_info_t *dhd = (dhd_info_t *)pub->info;
+ if (timeout) {
+ dhd->scan_time_count = timeout;
+ return ret;
+ }
+ DHD_ERROR(("DHD: Scan Timer Can not be zero:%s:\n", __FUNCTION__));
+ return BCME_ERROR;
+}
+uint32 dhd_get_scan_timeout(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd = (dhd_info_t *)pub->info;
+ return dhd->scan_time_count;
+}
+#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) {
+ 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_info_t **)netdev_priv(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) {
+ 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) {
+ 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) {
+ 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_info_t **)netdev_priv(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_info_t **)netdev_priv(dev);
+ int ret = 0;
+
+ if (dhd)
+ ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val);
+ return ret;
+}
+
+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) {
+ 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 (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
+ dhd_bus_dev_pm_stay_awake(pub);
+#endif
+ }
+ dhd->wakelock_counter++;
+ ret = dhd->wakelock_counter;
+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
+ }
+ return ret;
+}
+
+int net_os_wake_lock(struct net_device *dev)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(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) {
+ spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
+ if (dhd->wakelock_counter > 0) {
+ dhd->wakelock_counter--;
+ if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) {
+#ifdef CONFIG_HAS_WAKELOCK
+ wake_unlock(&dhd->wl_wifi);
+#elif (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;
+}
+
+int dhd_os_check_wakelock(dhd_pub_t *pub)
+{
+#if defined(CONFIG_HAS_WAKELOCK) || (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 (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 net_os_wake_unlock(struct net_device *dev)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(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);
+ if (dhd->wakelock_wd_counter == 0 && !dhd->waive_wakelock) {
+#ifdef CONFIG_HAS_WAKELOCK
+ /* if wakelock_wd_counter was never used : lock it at once */
+ 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 > 0) {
+ dhd->wakelock_wd_counter = 0;
+ if (!dhd->waive_wakelock) {
+#ifdef CONFIG_HAS_WAKELOCK
+ wake_unlock(&dhd->wl_wdwake);
+#endif
+ }
+ }
+ spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
+ }
+ return ret;
+}
+
+#ifdef PROP_TXSTATUS
+/* 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_wakelock_waive(dhd_info_t *dhdinfo)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&dhdinfo->wakelock_spinlock, flags);
+ /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */
+ if (dhdinfo->waive_wakelock)
+ goto exit;
+ /* record current lock status */
+ dhdinfo->wakelock_before_waive = dhdinfo->wakelock_counter;
+ dhdinfo->waive_wakelock = TRUE;
+
+exit:
+ ret = dhdinfo->wakelock_wd_counter;
+ spin_unlock_irqrestore(&dhdinfo->wakelock_spinlock, flags);
+ return ret;
+}
+
+int dhd_wakelock_restore(dhd_info_t *dhdinfo)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&dhdinfo->wakelock_spinlock, flags);
+ /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */
+ if (!dhdinfo->waive_wakelock)
+ goto exit;
+
+ dhdinfo->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
+ */
+ if (dhdinfo->wakelock_before_waive == 0 && dhdinfo->wakelock_counter > 0) {
+#ifdef CONFIG_HAS_WAKELOCK
+ wake_lock(&dhdinfo->wl_wifi);
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
+ dhd_bus_dev_pm_stay_awake(&dhdinfo->pub);
+#endif
+ } else if (dhdinfo->wakelock_before_waive > 0 && dhdinfo->wakelock_counter == 0) {
+#ifdef CONFIG_HAS_WAKELOCK
+ wake_unlock(&dhdinfo->wl_wifi);
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
+ dhd_bus_dev_pm_relax(&dhdinfo->pub);
+#endif
+ }
+ dhdinfo->wakelock_before_waive = 0;
+exit:
+ ret = dhdinfo->wakelock_wd_counter;
+ spin_unlock_irqrestore(&dhdinfo->wakelock_spinlock, flags);
+ return ret;
+}
+#endif /* PROP_TXSTATUS */
+
+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 ", EPI_VERSION_STR, fw);
+
+ if (!dhdp)
+ return;
+
+ i = snprintf(&info_string[i], sizeof(info_string) - i,
+ "\n Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp),
+ dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(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 || !netdev_priv(net)) {
+ DHD_ERROR(("%s invalid parameter\n", __FUNCTION__));
+ return -EINVAL;
+ }
+
+ dhd = *(dhd_info_t **)netdev_priv(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);
+ ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len);
+ dhd_check_hang(net, &dhd->pub, ret);
+ 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);
+}
+
+
+#ifdef PROP_TXSTATUS
+
+void dhd_wlfc_plat_init(void *dhd)
+{
+ return;
+}
+
+void dhd_wlfc_plat_deinit(void *dhd)
+{
+ return;
+}
+
+bool dhd_wlfc_skip_fc(void)
+{
+ return FALSE;
+}
+#endif /* PROP_TXSTATUS */
+
+#ifdef BCMDBGFS
+
+#include <linux/debugfs.h>
+
+extern uint32 dhd_readregl(void *bp, uint32 addr);
+extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data);
+
+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;
+
+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_dbg_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_dbg_init(dhd_pub_t *dhdp)
+{
+ int err;
+
+ 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)) {
+ err = PTR_ERR(g_dbgfs.debugfs_dir);
+ g_dbgfs.debugfs_dir = NULL;
+ return;
+ }
+
+ dhd_dbg_create();
+
+ return;
+}
+
+void dhd_dbg_remove(void)
+{
+ debugfs_remove(g_dbgfs.debugfs_mem);
+ debugfs_remove(g_dbgfs.debugfs_dir);
+
+ bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs));
+
+}
+#endif /* ifdef 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)
+{
+ wl_ioctl_t ioc;
+ char buf[32];
+ int ret;
+ uint32 s1, s2;
+
+ struct tsf {
+ uint32 low;
+ uint32 high;
+ } tsf_buf;
+
+ memset(&ioc, 0, sizeof(ioc));
+ memset(&tsf_buf, 0, sizeof(tsf_buf));
+
+ ioc.cmd = WLC_GET_VAR;
+ ioc.buf = buf;
+ ioc.len = (uint)sizeof(buf);
+ ioc.set = FALSE;
+
+ strncpy(buf, "tsf", sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+ s1 = dhd_get_htsf(dhd, 0);
+ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 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 */
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.h b/drivers/net/wireless/bcmdhd/dhd_linux.h
new file mode 100644
index 000000000000..f5df9cb03346
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.h
@@ -0,0 +1,77 @@
+/*
+ * DHD Linux header file (dhd_linux exports for cfg80211 and other components)
+ *
+ * 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: dhd_linux.h 399301 2013-04-29 21:41:52Z $
+ */
+
+/* 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+
+#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */
+
+typedef struct wifi_adapter_info {
+ const char *name;
+ uint irq_num;
+ uint intr_flags;
+ const char *fw_path;
+ const char *nv_path;
+ void *wifi_plat_data; /* wifi ctrl func, for backward compatibility */
+ uint bus_type;
+ uint bus_num;
+ uint slot_num;
+#ifdef OOB_PARAM
+ uint oob_disable;
+#endif /* OOB_PARAM */
+} wifi_adapter_info_t;
+
+typedef struct bcmdhd_wifi_platdata {
+ uint num_adapters;
+ wifi_adapter_info_t *adapters;
+} bcmdhd_wifi_platdata_t;
+
+int dhd_wifi_platform_register_drv(void);
+void dhd_wifi_platform_unregister_drv(void);
+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);
+void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode);
+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);
+
+#endif /* __DHD_LINUX_H__ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c b/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c
new file mode 100644
index 000000000000..4720083af6a2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_linux_platdev.c
@@ -0,0 +1,821 @@
+/*
+ * Linux platform device for DHD WLAN adapter
+ *
+ * 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: dhd_linux_platdev.c 401742 2013-05-13 15:03:21Z $
+ */
+#include <typedefs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <bcmutils.h>
+#include <linux_osl.h>
+#include <dhd_dbg.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_bus.h>
+#include <dhd_linux.h>
+#include <wl_android.h>
+#if defined(CONFIG_WIFI_CONTROL_FUNC)
+#include <linux/wlan_plat.h>
+#endif
+#ifdef CONFIG_DTS
+#include<linux/regulator/consumer.h>
+#include<linux/of_gpio.h>
+#endif /* CONFIG_DTS */
+
+#if !defined(CONFIG_WIFI_CONTROL_FUNC)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 58))
+#define WLAN_PLAT_NODFS_FLAG 0x01
+#endif
+struct wifi_platform_data {
+ int (*set_power)(int val);
+ 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);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 58))
+ void *(*get_country_code)(char *ccode, u32 flags);
+#else
+ void *(*get_country_code)(char *ccode);
+#endif
+};
+#endif /* CONFIG_WIFI_CONTROL_FUNC */
+
+#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;
+#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;
+struct resource dhd_wlan_resources = {0};
+struct wifi_platform_data dhd_wlan_control = {0};
+#endif /* CONFIG_OF && !defined(CONFIG_ARCH_MSM) */
+#endif /* !defind(CONFIG_DTS) */
+
+static int dhd_wifi_platform_load(void);
+
+extern void* wl_cfg80211_get_dhdp(void);
+
+#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_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;
+ }
+ }
+
+ 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;
+#ifdef CONFIG_DTS
+ if (on) {
+ err = regulator_enable(wifi_regulator);
+ is_power_on = TRUE;
+ }
+ else {
+ err = regulator_disable(wifi_regulator);
+ is_power_on = FALSE;
+ }
+ if (err < 0)
+ DHD_ERROR(("%s: regulator enable/disable failed", __FUNCTION__));
+#else
+ struct wifi_platform_data *plat_data;
+
+ if (!adapter || !adapter->wifi_plat_data)
+ return -EINVAL;
+ 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 */
+
+ err = plat_data->set_power(on);
+ }
+
+ if (msec && !err)
+ OSL_SLEEP(msec);
+
+ if (on && !err)
+ is_power_on = TRUE;
+ else
+ is_power_on = FALSE;
+
+#endif /* CONFIG_DTS */
+
+ return err;
+}
+#if defined(CUSTOMER_IMX)
+
+extern void wifi_card_detect(bool);
+int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present)
+{
+ int err = 0;
+ struct wifi_platform_data *plat_data;
+
+ if (!adapter) {
+ pr_err("!!!! %s: failed! adapter variable is NULL!!!!!\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ DHD_ERROR(("%s device present %d\n", __FUNCTION__, device_present));
+
+ if (!adapter->wifi_plat_data) {
+ wifi_card_detect(device_present); /* hook for card_detect */
+ } else {
+ plat_data = adapter->wifi_plat_data;
+ if (plat_data->set_carddetect)
+ err = plat_data->set_carddetect(device_present);
+ }
+
+ return 0; /* force success status returned */
+}
+
+#else
+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;
+
+}
+#endif /* CUSTOMER_IMX */
+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 *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode)
+{
+ /* 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) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 58))
+ return plat_data->get_country_code(ccode, WLAN_PLAT_NODFS_FLAG);
+#else
+ return plat_data->get_country_code(ccode);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 58)) */
+ }
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */
+
+ return NULL;
+}
+
+static int wifi_plat_dev_drv_probe(struct platform_device *pdev)
+{
+ struct resource *resource;
+ wifi_adapter_info_t *adapter;
+#ifdef CONFIG_DTS
+#if defined(OOB_INTR_ONLY)
+ int irq, gpio;
+#endif /* defined(OOB_INTR_ONLY) */
+ int ret = 0;
+#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];
+ adapter->wifi_plat_data = (struct wifi_platform_data *)(pdev->dev.platform_data);
+
+ 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;
+ }
+
+#ifdef OOB_PARAM
+ adapter->oob_disable = FALSE;
+#endif /* OOB_PARAM */
+
+#ifdef CONFIG_DTS
+ /* get firmware from dts */
+ ret = of_property_read_string(pdev->dev.of_node, "bcmdhd_fw", &adapter->fw_path);
+ if (!ret)
+ DHD_INFO(("fw path:%s\n", adapter->fw_path));
+ ret = of_property_read_string(pdev->dev.of_node, "bcmdhd_nv", &adapter->nv_path);
+ if (!ret)
+ DHD_INFO(("nv path:%s\n", adapter->nv_path));
+
+ wifi_regulator = regulator_get(&pdev->dev, "wlreg_on");
+ if (wifi_regulator == NULL) {
+ DHD_ERROR(("%s regulator is null\n", __FUNCTION__));
+ return -1;
+ }
+#if defined(OOB_INTR_ONLY)
+ OOB_PARAM_IF(!(adapter->oob_disable)) {
+ /* This is to get the irq for the OOB */
+ gpio = of_get_gpio(pdev->dev.of_node, 0);
+
+ if (gpio < 0) {
+ DHD_ERROR(("%s no GPIO for OOB in device tree.\n", __FUNCTION__));
+#if defined(OOB_PARAM)
+ DHD_ERROR(("%s continue with non-OOB mode.\n", __FUNCTION__));
+ adapter->oob_disable = TRUE;
+ goto out;
+#else
+ return -1;
+#endif /* defined(OOB_PARAM) */
+ }
+
+ irq = gpio_to_irq(gpio);
+ if (irq < 0) {
+ DHD_ERROR(("%s irq information is incorrect\n", __FUNCTION__));
+ return -1;
+ }
+
+ adapter->irq_num = irq;
+
+ /* Murata -- HW_OOB define depends on chipset.
+ * HW_OOB makes host interrupt level-sensitive versus edge-sensitive.
+ * ZP (BCM4339), 1DX (BCM4343W), 1FX (BCM43364), ZX/SN8000 (BCM43362)
+ * are level-sensitive (HW_OOB defined).
+ * Type 1BW (BCM43340) is edge-sensitive (HW_OOB NOT defined).
+ */
+#ifdef HW_OOB /* HW_OOB defined means level sensitive interrupts */
+ adapter->intr_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL |
+ IORESOURCE_IRQ_SHAREABLE;
+#else
+ adapter->intr_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
+ IORESOURCE_IRQ_SHAREABLE;
+#endif /* HW_OOB */
+ }
+#if defined(OOB_PARAM)
+out:
+#endif /* defined(OOB_PARAM) */
+#endif /* defined(OOB_INTR_ONLY) */
+#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) {
+ wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY);
+ wifi_platform_bus_enumerate(adapter, FALSE);
+ }
+
+#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)
+{
+#ifdef OOB_PARAM
+ wifi_adapter_info_t *adapter;
+ adapter = &dhd_wifi_platdata->adapters[0];
+#endif /* OOB_PARAM */
+
+ DHD_TRACE(("##> %s\n", __FUNCTION__));
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
+ OOB_PARAM_IF(!(adapter->oob_disable)) {
+ bcmsdh_oob_intr_set(0);
+ }
+#endif /* (OOB_INTR_ONLY) */
+ return 0;
+}
+
+static int wifi_plat_dev_drv_resume(struct platform_device *pdev)
+{
+#ifdef OOB_PARAM
+ wifi_adapter_info_t *adapter;
+ adapter = &dhd_wifi_platdata->adapters[0];
+#endif /* OOB_PARAM */
+
+ DHD_TRACE(("##> %s\n", __FUNCTION__));
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
+ OOB_PARAM_IF(!(adapter->oob_disable)) {
+ 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;
+ struct platform_device *pdev = to_platform_device(dev);
+
+ if (strcmp(pdev->name, name) == 0) {
+ DHD_ERROR(("found wifi platform device %s\n", name));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int wifi_ctrlfunc_register_drv(void)
+{
+ int err = 0;
+ struct device *dev1, *dev2;
+ wifi_adapter_info_t *adapter;
+
+ 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 !defined(CONFIG_DTS)
+ 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);
+ 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;
+
+ 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;
+ }
+ }
+
+#if !defined(CONFIG_DTS)
+ if (dts_enabled) {
+ struct resource *resource;
+ adapter->wifi_plat_data = (void *)&dhd_wlan_control;
+ resource = &dhd_wlan_resources;
+ adapter->irq_num = resource->start;
+ adapter->intr_flags = resource->flags;
+ wifi_plat_dev_probe_ret = dhd_wifi_platform_load();
+ }
+#endif /* !defined(CONFIG_DTS) */
+
+
+#ifdef CONFIG_DTS
+ 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)
+{
+
+#ifdef CONFIG_DTS
+ DHD_ERROR(("unregister wifi platform drivers\n"));
+ platform_driver_unregister(&wifi_platform_dev_driver);
+#else
+ 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;
+
+ DHD_ERROR(("unregister wifi platform drivers\n"));
+ if (dev1)
+ platform_driver_unregister(&wifi_platform_dev_driver);
+ if (dev2)
+ platform_driver_unregister(&wifi_platform_dev_driver_legacy);
+ if (dts_enabled) {
+ wifi_adapter_info_t *adapter;
+ 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) */
+
+ kfree(dhd_wifi_platdata->adapters);
+ dhd_wifi_platdata->adapters = NULL;
+ dhd_wifi_platdata->num_adapters = 0;
+ kfree(dhd_wifi_platdata);
+ dhd_wifi_platdata = NULL;
+}
+
+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,
+ }
+};
+
+int dhd_wifi_platform_register_drv(void)
+{
+ int err = 0;
+ 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 {
+ 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;
+ err = dhd_bus_register();
+ return err;
+}
+#else
+static int dhd_wifi_platform_load_pcie(void)
+{
+ return 0;
+}
+#endif /* BCMPCIE */
+
+
+void dhd_wifi_platform_unregister_drv(void)
+{
+ if (cfg_multichip)
+ platform_driver_unregister(&dhd_wifi_platform_dev_driver);
+ else
+ wifi_ctrlfunc_unregister_drv();
+}
+
+extern int dhd_watchdog_prio;
+extern int dhd_dpc_prio;
+extern uint dhd_deferred_tx;
+#if defined(BCMLXSDMMC)
+extern struct semaphore dhd_registration_sem;
+#endif
+
+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)
+ if (dhd_wifi_platdata == NULL) {
+ DHD_ERROR(("DHD wifi platform data is required for Android build\n"));
+ return -EINVAL;
+ }
+
+ sema_init(&dhd_registration_sem, 0);
+ /* 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;
+ }
+ err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY);
+ if (err) {
+ /* 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);
+ err = 0;
+ }
+
+ 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;
+}
+
+static int dhd_wifi_platform_load_usb(void)
+{
+ return 0;
+}
+
+static int dhd_wifi_platform_load()
+{
+ int err = 0;
+
+ 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();
+ else
+ wl_android_post_init();
+
+ return err;
+}
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_sched.c b/drivers/net/wireless/bcmdhd/dhd_linux_sched.c
new file mode 100644
index 000000000000..2ff7d6c1af09
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_linux_sched.c
@@ -0,0 +1,48 @@
+/*
+ * Expose some of the kernel scheduler routines
+ *
+ * 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: dhd_linux_sched.c 457596 2014-02-24 02:24:14Z $
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <typedefs.h>
+#include <linuxver.h>
+
+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/drivers/net/wireless/bcmdhd/dhd_linux_wq.c b/drivers/net/wireless/bcmdhd/dhd_linux_wq.c
new file mode 100644
index 000000000000..60018349fac0
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_linux_wq.c
@@ -0,0 +1,316 @@
+/*
+ * Broadcom Dongle Host Driver (DHD), Generic work queue framework
+ * Generic interface to handle dhd deferred work events
+ *
+ * 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: dhd_linux_wq.c 589976 2015-10-01 07:01:27Z $
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/ip.h>
+#include <linux/kfifo.h>
+
+#include <linuxver.h>
+#include <osl.h>
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <bcmdevs.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_dbg.h>
+#include <dhd_linux_wq.h>
+
+struct dhd_deferred_event_t {
+ u8 event; /* holds the event */
+ void *event_data; /* Holds event specific data */
+ event_handler_t event_handler;
+};
+#define DEFRD_EVT_SIZE sizeof(struct dhd_deferred_event_t)
+
+struct dhd_deferred_wq {
+ struct work_struct deferred_work; /* should be the first member */
+
+ /*
+ * work events may occur simultaneously.
+ * Can hold upto 64 low priority events and 4 high priority events
+ */
+#define DHD_PRIO_WORK_FIFO_SIZE (4 * sizeof(struct dhd_deferred_event_t))
+#define DHD_WORK_FIFO_SIZE (64 * sizeof(struct dhd_deferred_event_t))
+ 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 */
+};
+struct dhd_deferred_wq *deferred_wq = NULL;
+
+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
+ return fifo;
+}
+
+static inline void
+dhd_kfifo_free(struct kfifo *fifo)
+{
+ kfifo_free(fifo);
+}
+
+/* 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;
+ deferred_wq = work;
+ 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 alread \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);
+
+ /* deinit internal reference pointer */
+ deferred_wq = NULL;
+}
+
+/*
+ * Prepares event to be queued
+ * Schedules the event
+ */
+int
+dhd_deferred_schedule_work(void *event_data, u8 event, event_handler_t event_handler, u8 priority)
+{
+ struct dhd_deferred_event_t deferred_event;
+ int status;
+
+ 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 \n", __FUNCTION__));
+ return DHD_WQ_STS_UNKNOWN_EVENT;
+ }
+
+ /*
+ * 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;
+
+ if (priority == DHD_WORK_PRIORITY_HIGH) {
+ status = kfifo_in_spinlocked(deferred_wq->prio_fifo, &deferred_event,
+ DEFRD_EVT_SIZE, &deferred_wq->work_lock);
+ } else {
+ status = kfifo_in_spinlocked(deferred_wq->work_fifo, &deferred_event,
+ DEFRD_EVT_SIZE, &deferred_wq->work_lock);
+ }
+
+ if (!status) {
+ return DHD_WQ_STS_SCHED_FAILED;
+ }
+ schedule_work((struct work_struct *)deferred_wq);
+ return DHD_WQ_STS_OK;
+}
+
+static int
+dhd_get_scheduled_work(struct dhd_deferred_event_t *event)
+{
+ int status = 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);
+
+ /* first read priorit event fifo */
+ status = kfifo_out_spinlocked(deferred_wq->prio_fifo, event,
+ DEFRD_EVT_SIZE, &deferred_wq->work_lock);
+
+ if (!status) {
+ /* priority fifo is empty. Now read low prio work fifo */
+ status = kfifo_out_spinlocked(deferred_wq->work_fifo, event,
+ DEFRD_EVT_SIZE, &deferred_wq->work_lock);
+ }
+
+ return status;
+}
+
+/*
+ * 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;
+ struct dhd_deferred_event_t work_event;
+ int status;
+
+ if (!deferred_work) {
+ DHD_ERROR(("%s: work queue not initialized\n", __FUNCTION__));
+ return;
+ }
+
+ do {
+ status = dhd_get_scheduled_work(&work_event);
+ DHD_TRACE(("%s: event to handle %d \n", __FUNCTION__, status));
+ if (!status) {
+ DHD_TRACE(("%s: No event to handle %d \n", __FUNCTION__, status));
+ break;
+ }
+
+ if (work_event.event > DHD_MAX_WQ_EVENTS) {
+ DHD_TRACE(("%s: Unknown event %d \n", __FUNCTION__, work_event.event));
+ break;
+ }
+
+ 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 not defined %d\n", __FUNCTION__, work_event.event));
+ }
+ } while (1);
+ return;
+}
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_wq.h b/drivers/net/wireless/bcmdhd/dhd_linux_wq.h
new file mode 100644
index 000000000000..4396ee129e26
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_linux_wq.h
@@ -0,0 +1,64 @@
+/*
+ * Broadcom Dongle Host Driver (DHD), Generic work queue framework
+ * Generic interface to handle dhd deferred work events
+ *
+ * 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: dhd_linux_wq.h 408802 2013-06-20 19:08:47Z $
+ */
+#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_MAX_WQ_EVENTS
+};
+
+/*
+ * Work event priority
+ */
+#define DHD_WORK_PRIORITY_LOW 0
+#define DHD_WORK_PRIORITY_HIGH 1
+
+/*
+ * 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
+
+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 *work);
+int dhd_deferred_schedule_work(void *event_data, u8 event,
+ event_handler_t evt_handler, u8 priority);
+#endif /* _dhd_linux_wq_h_ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_msgbuf.c b/drivers/net/wireless/bcmdhd/dhd_msgbuf.c
new file mode 100644
index 000000000000..76745f9d4a23
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_msgbuf.c
@@ -0,0 +1,1755 @@
+/*
+ * 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-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: dhd_msgbuf.c 452261 2014-01-29 19:30:23Z $
+ */
+#include <typedefs.h>
+#include <osl.h>
+
+#include <bcmutils.h>
+#include <circularbuf.h>
+#include <bcmmsgbuf.h>
+#include <bcmendian.h>
+
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_proto.h>
+#include <dhd_bus.h>
+#include <dhd_dbg.h>
+
+
+#ifdef PROP_TXSTATUS
+#include <wlfc_proto.h>
+#include <dhd_wlfc.h>
+#endif
+#include <pcie_core.h>
+#include <bcmpcie.h>
+
+#define RETRIES 2 /* # of retries to retrieve matching ioctl response */
+#define IOCTL_HDR_LEN 12
+
+#define DEFAULT_RX_BUFFERS_TO_POST 255
+#define RXBUFPOST_THRESHOLD 16
+#define RX_BUF_BURST 8
+
+#define DHD_STOP_QUEUE_THRESHOLD 24
+#define DHD_START_QUEUE_THRESHOLD 32
+#define MAX_INLINE_IOCTL_LEN 64 /* anything beyond this len will not be inline reqst */
+
+/* Required for Native to PktId mapping incase of 64bit hosts */
+#define MAX_PKTID_ITEMS (2048)
+
+/* Given packet pointer and physical address, macro should return unique 32 bit pktid */
+/* And given 32bit pktid, macro should return packet pointer and physical address */
+extern void *pktid_map_init(void *osh, uint32 count);
+extern void pktid_map_uninit(void *pktid_map_handle);
+extern uint32 pktid_map_unique(void *pktid_map_handle,
+ void *pkt, dmaaddr_t physaddr, uint32 physlen, uint32 dma);
+extern void *pktid_get_packet(void *pktid_map_handle,
+ uint32 id, dmaaddr_t *physaddr, uint32 *physlen);
+
+#define NATIVE_TO_PKTID_INIT(osh, count) pktid_map_init(osh, count)
+#define NATIVE_TO_PKTID_UNINIT(pktid_map_handle) pktid_map_uninit(pktid_map_handle)
+
+#define NATIVE_TO_PKTID(pktid_map_handle, pkt, pa, pa_len, dma) \
+ pktid_map_unique((pktid_map_handle), (void *)(pkt), (pa), (uint32) (pa_len), (uint32)dma)
+#define PKTID_TO_NATIVE(pktid_map_handle, id, pa, pa_len) \
+ pktid_get_packet((pktid_map_handle), (uint32)(id), (void *)&(pa), (uint32 *) &(pa_len))
+
+#define MODX(x, n) ((x) & ((n) -1))
+#define align(x, n) (MODX(x, n) ? ((x) - MODX(x, n) + (n)) : ((x) - MODX(x, n)))
+#define RX_DMA_OFFSET 8
+#define IOCT_RETBUF_SIZE (RX_DMA_OFFSET + WLC_IOCTL_MAXLEN)
+
+typedef struct dhd_prot {
+ uint32 reqid;
+ uint16 hdr_len;
+ uint32 lastcmd;
+ uint32 pending;
+ uint16 rxbufpost;
+ uint16 max_rxbufpost;
+ uint16 active_tx_count;
+ uint16 max_tx_count;
+ dmaaddr_t htod_physaddr;
+ dmaaddr_t dtoh_physaddr;
+ bool txflow_en;
+ circularbuf_t *dtohbuf;
+ circularbuf_t *htodbuf;
+ uint32 rx_dataoffset;
+ void* retbuf;
+ dmaaddr_t retbuf_phys;
+ void* ioctbuf; /* For holding ioct request buf */
+ dmaaddr_t ioctbuf_phys; /* physical address for ioctbuf */
+ dhd_mb_ring_t mb_ring_fn;
+ void *htod_ring;
+ void *dtoh_ring;
+ /* Flag to check if splitbuf support is enabled. */
+ /* Set to False at dhd_prot_attach. Set to True at dhd_prot_init */
+ bool htodsplit;
+ bool dtohsplit;
+ /* H2D/D2H Ctrl rings */
+ dmaaddr_t htod_ctrl_physaddr; /* DMA mapped physical addr ofr H2D ctrl ring */
+ dmaaddr_t dtoh_ctrl_physaddr; /* DMA mapped phys addr for D2H ctrl ring */
+ circularbuf_t *htod_ctrlbuf; /* Cbuf handle for H2D ctrl ring */
+ circularbuf_t *dtoh_ctrlbuf; /* Cbuf handle for D2H ctrl ring */
+ void *htod_ctrl_ring; /* address for H2D control buf */
+ void *dtoh_ctrl_ring; /* address for D2H control buf */
+
+
+ uint16 ioctl_seq_no;
+ uint16 data_seq_no;
+ void *pktid_map_handle;
+} dhd_prot_t;
+
+static int dhdmsgbuf_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 dhdmsgbuf_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len, void* buf, void* retbuf);
+static int dhd_msgbuf_init_dtoh(dhd_pub_t *dhd);
+
+static int dhd_msgbuf_rxbuf_post(dhd_pub_t *dhd);
+static int dhd_msgbuf_init_htod(dhd_pub_t *dhd);
+static int dhd_msgbuf_init_htod_ctrl(dhd_pub_t *dhd);
+static int dhd_msgbuf_init_dtoh_ctrl(dhd_pub_t *dhd);
+static int dhd_prot_rxbufpost(dhd_pub_t *dhd, uint32 count);
+static void dhd_prot_return_rxbuf(dhd_pub_t *dhd, uint16 rxcnt);
+static void dhd_prot_rxcmplt_process(dhd_pub_t *dhd, void* buf);
+static void dhd_prot_event_process(dhd_pub_t *dhd, uint8* buf, uint16 len);
+static void dhd_prot_process_msgtype(dhd_pub_t *dhd, uint8* buf, uint16 len);
+static void dhd_process_msgtype(dhd_pub_t *dhd, uint8* buf, uint16 len);
+
+static void dhd_prot_txstatus_process(dhd_pub_t *dhd, void * buf);
+static void dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void * buf);
+void* dhd_alloc_circularbuf_space(dhd_pub_t *dhd, circularbuf_t *handle, uint16 msglen, uint path);
+static int dhd_fillup_ioct_reqst(dhd_pub_t *dhd, uint16 len, uint cmd, void* buf, int ifidx);
+static int dhd_fillup_ioct_reqst_ptrbased(dhd_pub_t *dhd, uint16 len, uint cmd, void* buf,
+ int ifidx);
+static INLINE void dhd_prot_packet_free(dhd_pub_t *dhd, uint32 pktid);
+static INLINE void *dhd_prot_packet_get(dhd_pub_t *dhd, uint32 pktid);
+
+/* Linkage, sets prot link and updates hdrlen in pub */
+int dhd_prot_attach(dhd_pub_t *dhd)
+{
+ uint alloced = 0;
+
+ dhd_prot_t *msg_buf;
+ if (!(msg_buf = (dhd_prot_t *)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_PROT,
+ sizeof(dhd_prot_t)))) {
+ DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
+ goto fail;
+ }
+ memset(msg_buf, 0, sizeof(dhd_prot_t));
+
+ msg_buf->hdr_len = sizeof(ioctl_req_hdr_t) + sizeof(cmn_msg_hdr_t) + sizeof(ret_buf_t);
+ msg_buf->dtohbuf = MALLOC(dhd->osh, sizeof(circularbuf_t));
+ msg_buf->htodbuf = MALLOC(dhd->osh, sizeof(circularbuf_t));
+
+ memset(msg_buf->dtohbuf, 0, sizeof(circularbuf_t));
+ memset(msg_buf->htodbuf, 0, sizeof(circularbuf_t));
+
+ dhd->prot = msg_buf;
+ dhd->maxctl = WLC_IOCTL_MAXLEN + msg_buf->hdr_len;
+
+ /* ret buf for ioctl */
+ msg_buf->retbuf = DMA_ALLOC_CONSISTENT(dhd->osh, IOCT_RETBUF_SIZE, 4,
+ &alloced, &msg_buf->retbuf_phys, NULL);
+ if (msg_buf->retbuf == NULL) {
+ ASSERT(0);
+ return BCME_NOMEM;
+ }
+
+ ASSERT(MODX((unsigned long)msg_buf->retbuf, 4) == 0);
+
+ msg_buf->ioctbuf = DMA_ALLOC_CONSISTENT(dhd->osh, MSGBUF_MAX_MSG_SIZE, 4,
+ &alloced, &msg_buf->ioctbuf_phys, NULL);
+
+ if (msg_buf->ioctbuf == NULL) {
+ ASSERT(0);
+ return BCME_NOMEM;
+ }
+
+ ASSERT(MODX((unsigned long)msg_buf->ioctbuf, 4) == 0);
+
+ msg_buf->pktid_map_handle = NATIVE_TO_PKTID_INIT(dhd->osh, MAX_PKTID_ITEMS);
+ if (msg_buf->pktid_map_handle == NULL) {
+ ASSERT(0);
+ return BCME_NOMEM;
+ }
+
+ msg_buf->htod_ring = DMA_ALLOC_CONSISTENT(dhd->osh, HOST_TO_DNGL_MSGBUF_SZ, 4,
+ &alloced, &msg_buf->htod_physaddr, NULL);
+ if (msg_buf->htod_ring == NULL) {
+ ASSERT(0);
+ return BCME_NOMEM;
+ }
+
+ ASSERT(MODX((unsigned long)msg_buf->htod_ring, 4) == 0);
+
+ msg_buf->dtoh_ring = DMA_ALLOC_CONSISTENT(dhd->osh, DNGL_TO_HOST_MSGBUF_SZ, 4,
+ &alloced, &msg_buf->dtoh_physaddr, NULL);
+ if (msg_buf->dtoh_ring == NULL) {
+ ASSERT(0);
+ return BCME_NOMEM;
+ }
+
+ ASSERT(MODX((unsigned long)msg_buf->dtoh_ring, 4) == 0);
+
+ /* At this point we assume splitbuf is not supported by dongle */
+ msg_buf->htodsplit = FALSE;
+ msg_buf->dtohsplit = FALSE;
+
+
+ return 0;
+
+fail:
+#ifndef CONFIG_DHD_USE_STATIC_BUF
+ if (msg_buf != NULL)
+ MFREE(dhd->osh, msg_buf, sizeof(dhd_prot_t));
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
+ return BCME_NOMEM;
+}
+
+/* Unlink, frees allocated protocol memory (including dhd_prot) */
+void dhd_prot_detach(dhd_pub_t *dhd)
+{
+ /* Stop the protocol module */
+ if (dhd->prot) {
+
+ if (dhd->prot->dtoh_ring) {
+ DMA_FREE_CONSISTENT(dhd->osh, dhd->prot->dtoh_ring,
+ DNGL_TO_HOST_MSGBUF_SZ, dhd->prot->dtoh_physaddr, NULL);
+
+ dhd->prot->dtoh_ring = NULL;
+ PHYSADDRHISET(dhd->prot->dtoh_physaddr, 0);
+ PHYSADDRLOSET(dhd->prot->dtoh_physaddr, 0);
+ }
+
+ if (dhd->prot->htod_ring) {
+ DMA_FREE_CONSISTENT(dhd->osh, dhd->prot->htod_ring,
+ HOST_TO_DNGL_MSGBUF_SZ, dhd->prot->htod_physaddr, NULL);
+
+ dhd->prot->htod_ring = NULL;
+ PHYSADDRHISET(dhd->prot->htod_physaddr, 0);
+ PHYSADDRLOSET(dhd->prot->htod_physaddr, 0);
+ }
+
+ if (dhd->prot->dtohbuf) {
+ MFREE(dhd->osh, dhd->prot->dtohbuf, sizeof(circularbuf_t));
+ dhd->prot->dtohbuf = NULL;
+ }
+
+ if (dhd->prot->htodbuf) {
+ MFREE(dhd->osh, dhd->prot->htodbuf, sizeof(circularbuf_t));
+ dhd->prot->htodbuf = NULL;
+ }
+
+ if (dhd->prot->htod_ctrl_ring) {
+ DMA_FREE_CONSISTENT(dhd->osh, dhd->prot->htod_ctrl_ring,
+ HOST_TO_DNGL_CTRLRING_SZ, dhd->prot->htod_ctrl_physaddr, NULL);
+
+ dhd->prot->htod_ctrl_ring = NULL;
+ dhd->prot->htod_ctrl_physaddr = 0;
+ }
+
+ if (dhd->prot->dtoh_ctrl_ring) {
+ DMA_FREE_CONSISTENT(dhd->osh, dhd->prot->dtoh_ctrl_ring,
+ DNGL_TO_HOST_CTRLRING_SZ, dhd->prot->dtoh_ctrl_physaddr, NULL);
+
+ dhd->prot->dtoh_ctrl_ring = NULL;
+ dhd->prot->dtoh_ctrl_physaddr = 0;
+ }
+
+ if (dhd->prot->htod_ctrlbuf) {
+ MFREE(dhd->osh, dhd->prot->htod_ctrlbuf, sizeof(circularbuf_t));
+ dhd->prot->htod_ctrlbuf = NULL;
+ }
+
+ if (dhd->prot->dtoh_ctrlbuf) {
+ MFREE(dhd->osh, dhd->prot->dtoh_ctrlbuf, sizeof(circularbuf_t));
+ dhd->prot->dtoh_ctrlbuf = NULL;
+ }
+
+ if (dhd->prot->retbuf) {
+ DMA_FREE_CONSISTENT(dhd->osh, dhd->prot->retbuf,
+ IOCT_RETBUF_SIZE, dhd->prot->retbuf_phys, NULL);
+ dhd->prot->retbuf = NULL;
+ }
+
+ if (dhd->prot->ioctbuf) {
+ DMA_FREE_CONSISTENT(dhd->osh, dhd->prot->ioctbuf,
+ MSGBUF_MAX_MSG_SIZE, dhd->prot->ioctbuf_phys, NULL);
+
+ dhd->prot->ioctbuf = NULL;
+ }
+
+ NATIVE_TO_PKTID_UNINIT(dhd->prot->pktid_map_handle);
+
+#ifndef CONFIG_DHD_USE_STATIC_BUF
+ MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t));
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
+
+ dhd->prot = NULL;
+ }
+}
+
+void
+dhd_prot_rx_dataoffset(dhd_pub_t *dhd, uint32 rx_offset)
+{
+ dhd_prot_t *prot = dhd->prot;
+ prot->rx_dataoffset = rx_offset;
+}
+
+
+/* Initialize protocol: sync w/dongle state.
+ * Sets dongle media info (iswl, drv_version, mac address).
+ */
+int dhd_prot_init(dhd_pub_t *dhd)
+{
+ int ret = 0;
+ wlc_rev_info_t revinfo;
+ dhd_prot_t *prot = dhd->prot;
+ uint32 shared_flags;
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ dhd_bus_cmn_readshared(dhd->bus, &prot->max_tx_count, TOTAL_LFRAG_PACKET_CNT);
+ if (prot->max_tx_count == 0) {
+ /* This can happen if LFrag pool is not enabled for the LFRAG's */
+ /* on the dongle. Let's use some default value */
+ prot->max_tx_count = 64;
+ }
+ DHD_INFO(("%s:%d: MAX_TX_COUNT = %d\n", __FUNCTION__, __LINE__, prot->max_tx_count));
+
+ dhd_bus_cmn_readshared(dhd->bus, &prot->max_rxbufpost, MAX_HOST_RXBUFS);
+ 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));
+
+ prot->active_tx_count = 0;
+ prot->txflow_en = FALSE;
+ prot->mb_ring_fn = dhd_bus_get_mbintr_fn(dhd->bus);
+ prot->data_seq_no = 0;
+ prot->ioctl_seq_no = 0;
+ /* initialise msgbufs */
+ shared_flags = dhd_bus_get_sharedflags(dhd->bus);
+ if (shared_flags & PCIE_SHARED_HTOD_SPLIT) {
+ prot->htodsplit = TRUE;
+ if (dhd_msgbuf_init_htod_ctrl(dhd) == BCME_NOMEM)
+ {
+ prot->htodsplit = FALSE;
+ DHD_ERROR(("%s:%d: HTOD ctrl ring alloc failed!\n",
+ __FUNCTION__, __LINE__));
+ }
+ }
+ if (shared_flags & PCIE_SHARED_DTOH_SPLIT) {
+ prot->dtohsplit = TRUE;
+ if (dhd_msgbuf_init_dtoh_ctrl(dhd) == BCME_NOMEM)
+ {
+ prot->dtohsplit = FALSE;
+ DHD_ERROR(("%s:%d: DTOH ctrl ring alloc failed!\n",
+ __FUNCTION__, __LINE__));
+ }
+ }
+ ret = dhd_msgbuf_init_htod(dhd);
+ ret = dhd_msgbuf_init_dtoh(dhd);
+ ret = dhd_msgbuf_rxbuf_post(dhd);
+
+
+ /* 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(WL_CFG80211)
+ if (dhd_download_fw_on_driverload)
+#endif /* defined(WL_CFG80211) */
+ ret = dhd_preinit_ioctls(dhd);
+ /* Always assumes wl for now */
+ dhd->iswl = TRUE;
+done:
+ return ret;
+
+}
+
+static INLINE void BCMFASTPATH
+dhd_prot_packet_free(dhd_pub_t *dhd, uint32 pktid)
+{
+ void *PKTBUF;
+ dmaaddr_t pa;
+ uint32 pa_len;
+ PKTBUF = PKTID_TO_NATIVE(dhd->prot->pktid_map_handle, pktid, pa, pa_len);
+ DMA_UNMAP(dhd->osh, (uint) pa, (uint) pa_len, DMA_TX, 0, 0);
+ PKTFREE(dhd->osh, PKTBUF, TRUE);
+ return;
+}
+
+static INLINE void * BCMFASTPATH
+dhd_prot_packet_get(dhd_pub_t *dhd, uint32 pktid)
+{
+ void *PKTBUF;
+ ulong pa;
+ uint32 pa_len;
+ PKTBUF = PKTID_TO_NATIVE(dhd->prot->pktid_map_handle, pktid, pa, pa_len);
+ DMA_UNMAP(dhd->osh, (uint) pa, (uint) pa_len, DMA_RX, 0, 0);
+ return PKTBUF;
+}
+
+static int BCMFASTPATH
+dhd_msgbuf_rxbuf_post(dhd_pub_t *dhd)
+{
+ dhd_prot_t *prot = dhd->prot;
+ unsigned long flags;
+ uint32 fillbufs;
+ uint32 i;
+ fillbufs = prot->max_rxbufpost - prot->rxbufpost;
+
+ for (i = 0; i < fillbufs; ) {
+ int retcount;
+ uint32 buf_count = (fillbufs - i) > RX_BUF_BURST ? RX_BUF_BURST : (fillbufs - i);
+
+ flags = dhd_os_spin_lock(dhd);
+ retcount = dhd_prot_rxbufpost(dhd, buf_count);
+ if (retcount > 0) {
+ prot->rxbufpost += (uint16)retcount;
+ i += (uint16)retcount;
+ dhd_os_spin_unlock(dhd, flags);
+ } else {
+ dhd_os_spin_unlock(dhd, flags);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int BCMFASTPATH
+dhd_prot_rxbufpost(dhd_pub_t *dhd, uint32 count)
+{
+ void *p;
+ uint16 pktsz = 2048;
+ uint32 i;
+ rxdesc_msghdr_t *rxbuf_post;
+ rx_lenptr_tup_t *rx_tup;
+ dmaaddr_t physaddr;
+ uint32 pktlen;
+ uint32 msglen = sizeof(rxdesc_msghdr_t) + count * sizeof(rx_lenptr_tup_t);
+
+ dhd_prot_t *prot = dhd->prot;
+ circularbuf_t *htod_msgbuf = (circularbuf_t *)prot->htodbuf;
+
+ rxbuf_post = (rxdesc_msghdr_t *)dhd_alloc_circularbuf_space(dhd,
+ htod_msgbuf, (uint16)msglen, HOST_TO_DNGL_DATA);
+ if (rxbuf_post == NULL) {
+ DHD_INFO(("%s:%d: HTOD Msgbuf Not available\n",
+ __FUNCTION__, __LINE__));
+ return -1;
+ }
+
+ /* CMN msg header */
+ rxbuf_post->msg.msglen = htol16((uint16)msglen);
+ rxbuf_post->msg.msgtype = MSG_TYPE_RXBUF_POST;
+ rxbuf_post->msg.ifidx = 0;
+ rxbuf_post->msg.u.seq.seq_no = htol16(++prot->data_seq_no);
+
+ /* RX specific hdr */
+ rxbuf_post->rsvd0 = 0;
+ rxbuf_post->rsvd1 = 0;
+ rxbuf_post->descnt = (uint8)count;
+
+ rx_tup = (rx_lenptr_tup_t *) &(rxbuf_post->rx_tup[0]);
+
+ 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__));
+ printf("%s:%d: PKTGET for rxbuf failed. Need to handle this gracefully\n",
+ __FUNCTION__, __LINE__);
+ return -1;
+ }
+
+ pktlen = PKTLEN(dhd->osh, p);
+ physaddr = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, DMA_RX, 0, 0);
+ if (physaddr == 0) {
+ DHD_ERROR(("Something really bad, unless 0 is a valid phyaddr\n"));
+ ASSERT(0);
+ }
+ /* Each bufid-len-ptr tuple */
+ rx_tup->rxbufid = htol32(NATIVE_TO_PKTID(dhd->prot->pktid_map_handle,
+ p, physaddr, pktlen, DMA_RX));
+ rx_tup->len = htol16((uint16)PKTLEN(dhd->osh, p));
+ rx_tup->rsvd2 = 0;
+ rx_tup->ret_buf.high_addr = htol32(PHYSADDRHI(physaddr));
+ rx_tup->ret_buf.low_addr = htol32(PHYSADDRLO(physaddr));
+
+ rx_tup++;
+ }
+
+ /* Since, we are filling the data directly into the bufptr obtained
+ * from the msgbuf, we can directly call the write_complete
+ */
+ circularbuf_write_complete(htod_msgbuf, (uint16)msglen);
+
+ return count;
+}
+
+void BCMFASTPATH
+dhd_msgbuf_ringbell(void *ctx)
+{
+ dhd_pub_t *dhd = (dhd_pub_t *) ctx;
+ dhd_prot_t *prot = dhd->prot;
+ circularbuf_t *htod_msgbuf = (circularbuf_t *)prot->htodbuf;
+
+ /* Following will take care of writing both the Write and End pointers (32 bits) */
+ dhd_bus_cmn_writeshared(dhd->bus, &(CIRCULARBUF_WRITE_PTR(htod_msgbuf)),
+ sizeof(uint32), HOST_TO_DNGL_WPTR);
+
+ prot->mb_ring_fn(dhd->bus, *(uint32 *) &(CIRCULARBUF_WRITE_PTR(htod_msgbuf)));
+}
+
+void BCMFASTPATH
+dhd_ctrlbuf_ringbell(void *ctx)
+{
+ dhd_pub_t *dhd = (dhd_pub_t *) ctx;
+ dhd_prot_t *prot = dhd->prot;
+ circularbuf_t *htod_ctrlbuf = (circularbuf_t *)prot->htod_ctrlbuf;
+
+ /* Following will take care of writing both the Write and End pointers (32 bits) */
+ dhd_bus_cmn_writeshared(dhd->bus, &(CIRCULARBUF_WRITE_PTR(htod_ctrlbuf)),
+ sizeof(uint32), HTOD_CTRL_WPTR);
+
+ prot->mb_ring_fn(dhd->bus, *(uint32 *) &(CIRCULARBUF_WRITE_PTR(htod_ctrlbuf)));
+}
+
+static int
+dhd_msgbuf_init_htod(dhd_pub_t *dhd)
+{
+ dhd_prot_t *prot = dhd->prot;
+ circularbuf_t *htod_msgbuf = (circularbuf_t *)prot->htodbuf;
+
+ circularbuf_init(htod_msgbuf, prot->htod_ring, HOST_TO_DNGL_MSGBUF_SZ);
+ circularbuf_register_cb(htod_msgbuf, dhd_msgbuf_ringbell, (void *)dhd);
+ dhd_bus_cmn_writeshared(dhd->bus, &prot->htod_physaddr,
+ sizeof(prot->htod_physaddr), HOST_TO_DNGL_BUF_ADDR);
+
+ dhd_bus_cmn_writeshared(dhd->bus, &(CIRCULARBUF_WRITE_PTR(htod_msgbuf)),
+ sizeof(uint32), HOST_TO_DNGL_WPTR);
+
+ return 0;
+
+}
+static int
+dhd_msgbuf_init_dtoh(dhd_pub_t *dhd)
+{
+ dhd_prot_t *prot = dhd->prot;
+ circularbuf_t *dtoh_msgbuf = (circularbuf_t *)prot->dtohbuf;
+
+ prot->rxbufpost = 0;
+ circularbuf_init(dtoh_msgbuf, prot->dtoh_ring, DNGL_TO_HOST_MSGBUF_SZ);
+ dhd_bus_cmn_writeshared(dhd->bus, &prot->dtoh_physaddr,
+ sizeof(prot->dtoh_physaddr), DNGL_TO_HOST_BUF_ADDR);
+
+ dhd_bus_cmn_writeshared(dhd->bus, &CIRCULARBUF_READ_PTR(dtoh_msgbuf),
+ sizeof(uint16), DNGL_TO_HOST_RPTR);
+
+ /* One dummy interrupt to the device. This would trigger */
+ /* the msgbuf initializations at the device side. */
+ /* Send dummy intr to device here, only if support for split data/ctrl rings is disabled */
+ /* Else send the dummy initialization intr at dtoh ctrl buf init */
+
+ dhd_bus_ringbell(dhd->bus, PCIE_INTB);
+ return 0;
+}
+
+/* Allocate space for HTOD ctrl ring on host and initialize handle/doorbell for the same */
+static int dhd_msgbuf_init_htod_ctrl(dhd_pub_t *dhd)
+{
+ uint alloced;
+ dhd_prot_t *prot = dhd->prot;
+ prot->htod_ctrlbuf = MALLOC(dhd->osh, sizeof(circularbuf_t));
+ memset(prot->htod_ctrlbuf, 0, sizeof(circularbuf_t));
+
+ prot->htod_ctrl_ring = DMA_ALLOC_CONSISTENT(dhd->osh, HOST_TO_DNGL_CTRLRING_SZ, 4,
+ &alloced, &prot->htod_ctrl_physaddr, NULL);
+ if (prot->htod_ctrl_ring == NULL) {
+ return BCME_NOMEM;
+ }
+
+ ASSERT(MODX((unsigned long)prot->htod_ctrl_ring, 4) == 0);
+
+ circularbuf_init(prot->htod_ctrlbuf, prot->htod_ctrl_ring, HOST_TO_DNGL_CTRLRING_SZ);
+ circularbuf_register_cb(prot->htod_ctrlbuf, dhd_ctrlbuf_ringbell, (void *)dhd);
+ dhd_bus_cmn_writeshared(dhd->bus, &prot->htod_ctrl_physaddr,
+ sizeof(prot->htod_ctrl_physaddr), HOST_TO_DNGL_CTRLBUF_ADDR);
+
+ dhd_bus_cmn_writeshared(dhd->bus, &(CIRCULARBUF_WRITE_PTR(prot->htod_ctrlbuf)),
+ sizeof(uint32), HTOD_CTRL_WPTR);
+
+ return 0;
+}
+/* Allocate space for DTOH ctrl ring on host and initialize msgbuf handle in dhd_prot_t */
+static int dhd_msgbuf_init_dtoh_ctrl(dhd_pub_t *dhd)
+{
+ uint alloced;
+ dhd_prot_t *prot = dhd->prot;
+ prot->dtoh_ctrlbuf = MALLOC(dhd->osh, sizeof(circularbuf_t));
+ memset(prot->dtoh_ctrlbuf, 0, sizeof(circularbuf_t));
+
+ prot->dtoh_ctrl_ring = DMA_ALLOC_CONSISTENT(dhd->osh, DNGL_TO_HOST_CTRLRING_SZ, 4,
+ &alloced, &prot->dtoh_ctrl_physaddr, NULL);
+ if (prot->dtoh_ctrl_ring == NULL) {
+ return BCME_NOMEM;
+ }
+ ASSERT(MODX((unsigned long)prot->dtoh_ctrl_ring, 4) == 0);
+
+ circularbuf_init(prot->dtoh_ctrlbuf, prot->dtoh_ctrl_ring, DNGL_TO_HOST_CTRLRING_SZ);
+ dhd_bus_cmn_writeshared(dhd->bus, &prot->dtoh_ctrl_physaddr,
+ sizeof(prot->dtoh_ctrl_physaddr), DNGL_TO_HOST_CTRLBUF_ADDR);
+
+ dhd_bus_cmn_writeshared(dhd->bus, &(CIRCULARBUF_READ_PTR(prot->dtoh_ctrlbuf)),
+ sizeof(uint32), DTOH_CTRL_RPTR);
+ return 0;
+}
+
+int BCMFASTPATH
+dhd_prot_process_msgbuf(dhd_pub_t *dhd)
+{
+ dhd_prot_t *prot = dhd->prot;
+ circularbuf_t *dtoh_msgbuf = (circularbuf_t *)prot->dtohbuf;
+
+ dhd_bus_cmn_readshared(dhd->bus, &CIRCULARBUF_WRITE_PTR(dtoh_msgbuf), DNGL_TO_HOST_WPTR);
+
+ /* Process all the messages - DTOH direction */
+ while (TRUE) {
+ uint8 *src_addr;
+ uint16 src_len;
+
+ src_addr = circularbuf_get_read_ptr(dtoh_msgbuf, &src_len);
+ if (src_addr == NULL)
+ break;
+
+ /* Prefetch data to populate the cache */
+ OSL_PREFETCH(src_addr);
+
+ dhd_prot_process_msgtype(dhd, src_addr, src_len);
+ circularbuf_read_complete(dtoh_msgbuf, src_len);
+
+ /* Write to dngl rd ptr */
+ dhd_bus_cmn_writeshared(dhd->bus, &CIRCULARBUF_READ_PTR(dtoh_msgbuf),
+ sizeof(uint16), DNGL_TO_HOST_RPTR);
+ }
+
+ return 0;
+}
+
+int BCMFASTPATH
+dhd_prot_process_ctrlbuf(dhd_pub_t * dhd)
+{
+ dhd_prot_t *prot = dhd->prot;
+ circularbuf_t *dtoh_ctrlbuf = (circularbuf_t *)prot->dtoh_ctrlbuf;
+
+ dhd_bus_cmn_readshared(dhd->bus, &CIRCULARBUF_WRITE_PTR(dtoh_ctrlbuf), DTOH_CTRL_WPTR);
+
+ /* Process all the messages - DTOH direction */
+ while (TRUE) {
+ uint8 *src_addr;
+ uint16 src_len;
+
+ src_addr = circularbuf_get_read_ptr(dtoh_ctrlbuf, &src_len);
+ if (src_addr == NULL) {
+ break;
+ }
+ /* Prefetch data to populate the cache */
+ OSL_PREFETCH(src_addr);
+
+ dhd_prot_process_msgtype(dhd, src_addr, src_len);
+ circularbuf_read_complete(dtoh_ctrlbuf, src_len);
+
+ /* Write to dngl rd ptr */
+ dhd_bus_cmn_writeshared(dhd->bus, &CIRCULARBUF_READ_PTR(dtoh_ctrlbuf),
+ sizeof(uint16), DTOH_CTRL_RPTR);
+ }
+
+ return 0;
+}
+
+static void BCMFASTPATH
+dhd_prot_process_msgtype(dhd_pub_t *dhd, uint8* buf, uint16 len)
+{
+ dhd_prot_t *prot = dhd->prot;
+ uint32 cur_dma_len = 0;
+
+ DHD_TRACE(("%s: process msgbuf of len %d\n", __FUNCTION__, len));
+
+ while (len > 0) {
+ ASSERT(len > (sizeof(cmn_msg_hdr_t) + prot->rx_dataoffset));
+ if (prot->rx_dataoffset) {
+ cur_dma_len = *(uint32 *) buf;
+ ASSERT(cur_dma_len <= len);
+ buf += prot->rx_dataoffset;
+ len -= (uint16)prot->rx_dataoffset;
+ }
+ else {
+ cur_dma_len = len;
+ }
+ dhd_process_msgtype(dhd, buf, (uint16)cur_dma_len);
+ len -= (uint16)cur_dma_len;
+ buf += cur_dma_len;
+ }
+}
+
+
+static void
+dhd_check_sequence_num(cmn_msg_hdr_t *msg)
+{
+ static uint32 ioctl_seq_no_old = 0;
+ static uint32 data_seq_no_old = 0;
+
+ switch (msg->msgtype) {
+ case MSG_TYPE_IOCTL_CMPLT:
+ if (msg->u.seq.seq_no && msg->u.seq.seq_no != (ioctl_seq_no_old + 1))
+ {
+ DHD_ERROR(("Error in IOCTL MsgBuf Sequence number!!"
+ "new seq no %u, old seq number %u\n",
+ msg->u.seq.seq_no, ioctl_seq_no_old));
+ }
+ ioctl_seq_no_old = msg->u.seq.seq_no;
+ break;
+
+ case MSG_TYPE_RX_CMPLT:
+ case MSG_TYPE_WL_EVENT :
+ case MSG_TYPE_TX_STATUS :
+ case MSG_TYPE_LOOPBACK:
+ if (msg->u.seq.seq_no && msg->u.seq.seq_no != (data_seq_no_old + 1))
+ {
+ DHD_ERROR(("Error in DATA MsgBuf Sequence number!!"
+ "new seq no %u old seq number %u\n",
+ msg->u.seq.seq_no, data_seq_no_old));
+ }
+ data_seq_no_old = msg->u.seq.seq_no;
+ break;
+
+ default:
+ printf("Unknown MSGTYPE in %s \n", __FUNCTION__);
+ break;
+
+ }
+}
+
+static void BCMFASTPATH
+dhd_process_msgtype(dhd_pub_t *dhd, uint8* buf, uint16 len)
+{
+ uint16 pktlen = len;
+ uint16 msglen;
+ uint8 msgtype;
+ cmn_msg_hdr_t *msg = NULL;
+ while (pktlen > 0) {
+ msg = (cmn_msg_hdr_t *)buf;
+ msgtype = msg->msgtype;
+ msglen = msg->msglen;
+
+ /* Prefetch data to populate the cache */
+ OSL_PREFETCH(buf+msglen);
+
+ dhd_check_sequence_num(msg);
+
+ DHD_INFO(("msgtype %d, msglen is %d \n", msgtype, msglen));
+ switch (msgtype) {
+ case MSG_TYPE_IOCTL_CMPLT:
+ DHD_INFO((" MSG_TYPE_IOCTL_CMPLT\n"));
+ dhd_prot_ioctcmplt_process(dhd, buf);
+ break;
+ case MSG_TYPE_RX_CMPLT:
+ DHD_INFO((" MSG_TYPE_RX_CMPLT\n"));
+ dhd_prot_rxcmplt_process(dhd, buf);
+ break;
+ case MSG_TYPE_WL_EVENT:
+ DHD_INFO((" MSG_TYPE_WL_EVENT\n"));
+ dhd_prot_event_process(dhd, buf, msglen);
+ break;
+ case MSG_TYPE_TX_STATUS:
+ DHD_INFO((" MSG_TYPE_TX_STATUS\n"));
+ dhd_prot_txstatus_process(dhd, buf);
+ break;
+ case MSG_TYPE_LOOPBACK:
+ bcm_print_bytes("LPBK RESP: ", (uint8 *)msg, msglen);
+ DHD_ERROR((" MSG_TYPE_LOOPBACK, len %d\n", msglen));
+ break;
+ default :
+ DHD_ERROR(("Unknown state in %s,"
+ "rxoffset %d\n", __FUNCTION__, dhd->prot->rx_dataoffset));
+ bcm_print_bytes("UNKNOWN msg", (uchar *)msg, msglen);
+ break;
+
+ }
+
+ DHD_INFO(("pktlen is %d, msglen is %d\n", pktlen, msglen));
+ if (pktlen < msglen) {
+ return;
+ }
+ pktlen = pktlen - msglen;
+ buf = buf + msglen;
+ }
+}
+static void
+dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void * buf)
+{
+ uint32 retlen, status, inline_data = 0;
+ uint32 pkt_id, xt_id;
+
+ ioct_resp_hdr_t * ioct_resp = (ioct_resp_hdr_t *)buf;
+ retlen = ltoh32(ioct_resp->ret_len);
+ pkt_id = ltoh32(ioct_resp->pkt_id);
+ xt_id = ltoh32(ioct_resp->xt_id);
+ status = ioct_resp->status;
+ if (retlen <= 4) {
+ inline_data = ltoh32(ioct_resp->inline_data);
+ } else {
+ OSL_CACHE_INV((void *) dhd->prot->retbuf, retlen);
+ }
+ DHD_CTL(("status from the pkt_id is %d, ioctl is %d, ret_len is %d, xt_id %d\n",
+ pkt_id, status, retlen, xt_id));
+
+ if (retlen == 0)
+ retlen = 1;
+
+ dhd_bus_update_retlen(dhd->bus, retlen, pkt_id, status, inline_data);
+ dhd_os_ioctl_resp_wake(dhd);
+}
+
+static void BCMFASTPATH
+dhd_prot_txstatus_process(dhd_pub_t *dhd, void * buf)
+{
+ dhd_prot_t *prot = dhd->prot;
+ txstatus_hdr_t * txstatus;
+ unsigned long flags;
+ uint32 pktid;
+
+ /* locks required to protect circular buffer accesses */
+ flags = dhd_os_spin_lock(dhd);
+
+ txstatus = (txstatus_hdr_t *)buf;
+ pktid = ltoh32(txstatus->pktid);
+
+ prot->active_tx_count--;
+
+ ASSERT(pktid != 0);
+ dhd_prot_packet_free(dhd, pktid);
+
+ if (prot->txflow_en == TRUE) {
+ /* If the pktpool availability is above the high watermark, */
+ /* let's resume the flow of packets to dongle. */
+ if ((prot->max_tx_count - prot->active_tx_count) > DHD_START_QUEUE_THRESHOLD) {
+ dhd_bus_start_queue(dhd->bus);
+ prot->txflow_en = FALSE;
+ }
+ }
+
+ dhd_os_spin_unlock(dhd, flags);
+ return;
+}
+
+static void
+dhd_prot_event_process(dhd_pub_t *dhd, uint8* buf, uint16 len)
+{
+ wl_event_hdr_t * evnt;
+ uint32 bufid;
+ uint16 buflen;
+ int ifidx = 0;
+ uint pkt_count = 1;
+ void* pkt;
+ unsigned long flags;
+
+ /* Event complete header */
+ evnt = (wl_event_hdr_t *)buf;
+ bufid = ltoh32(evnt->rxbufid);
+ buflen = ltoh16(evnt->retbuf_len);
+
+ /* Post another rxbuf to the device */
+ dhd_prot_return_rxbuf(dhd, 1);
+
+ /* locks required to protect pktid_map */
+ flags = dhd_os_spin_lock(dhd);
+
+ pkt = dhd_prot_packet_get(dhd, ltoh32(bufid));
+
+ dhd_os_spin_unlock(dhd, flags);
+
+ /* 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);
+
+ /* remove WL header */
+ PKTPULL(dhd->osh, pkt, 4); /* WL Header */
+
+ dhd_bus_rx_frame(dhd->bus, pkt, ifidx, pkt_count);
+}
+
+static void BCMFASTPATH
+dhd_prot_rxcmplt_process(dhd_pub_t *dhd, void* buf)
+{
+ rxcmplt_hdr_t *rxcmplt_h;
+ rxcmplt_tup_t *rx_tup;
+ uint32 bufid;
+ uint16 buflen, cmpltcnt;
+ uint16 data_offset; /* offset at which data starts */
+ void * pkt;
+ int ifidx = 0;
+ uint pkt_count = 0;
+ uint32 i;
+ void *pkthead = NULL;
+ void *pkttail = NULL;
+
+ /* RXCMPLT HDR */
+ rxcmplt_h = (rxcmplt_hdr_t *)buf;
+ cmpltcnt = ltoh16(rxcmplt_h->rxcmpltcnt);
+
+ /* Post another set of rxbufs to the device */
+ dhd_prot_return_rxbuf(dhd, cmpltcnt);
+ ifidx = rxcmplt_h->msg.ifidx;
+
+ rx_tup = (rxcmplt_tup_t *) &(rxcmplt_h->rx_tup[0]);
+ for (i = 0; i < cmpltcnt; i++) {
+ unsigned long flags;
+
+ bufid = ltoh32(rx_tup->rxbufid);
+ buflen = ltoh16(rx_tup->retbuf_len);
+
+ /* offset from which data starts is populated in rxstatus0 */
+ data_offset = ltoh16(rx_tup->data_offset);
+
+ /* locks required to protect pktid_map */
+ flags = dhd_os_spin_lock(dhd);
+ pkt = dhd_prot_packet_get(dhd, ltoh32(bufid));
+ dhd_os_spin_unlock(dhd, flags);
+
+ /* data_offset from buf start */
+ if (data_offset) {
+ /* data offset given from dongle after split rx */
+ PKTPULL(dhd->osh, pkt, data_offset); /* data offset */
+ } else {
+ /* DMA RX offset updated through shared area */
+ if (dhd->prot->rx_dataoffset)
+ PKTPULL(dhd->osh, pkt, dhd->prot->rx_dataoffset);
+ }
+
+ /* Actual length of the packet */
+ PKTSETLEN(dhd->osh, pkt, buflen);
+
+ /* remove WL header */
+ PKTPULL(dhd->osh, pkt, 4); /* WL Header */
+
+ pkt_count++;
+ rx_tup++;
+
+ /* Chain the packets and release in one shot to dhd_linux. */
+ /* Interface and destination checks are not required here. */
+ PKTSETNEXT(dhd->osh, pkt, NULL);
+ if (pkttail == NULL) {
+ pkthead = pkttail = pkt;
+ } else {
+ PKTSETNEXT(dhd->osh, pkttail, pkt);
+ pkttail = pkt;
+ }
+ }
+
+ if (pkthead) {
+ /* Release the packets to dhd_linux */
+ dhd_bus_rx_frame(dhd->bus, pkthead, ifidx, pkt_count);
+ }
+}
+/* Stop protocol: sync w/dongle state. */
+void dhd_prot_stop(dhd_pub_t *dhd)
+{
+ /* nothing to do for pcie */
+}
+
+/* Add any protocol-specific data header.
+ * Caller must reserve prot_hdrlen prepend space.
+ */
+void dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *PKTBUF)
+{
+ return;
+}
+
+#define PKTBUF pktbuf
+
+int BCMFASTPATH
+dhd_prot_txdata(dhd_pub_t *dhd, void *PKTBUF, uint8 ifidx)
+{
+ unsigned long flags;
+ dhd_prot_t *prot = dhd->prot;
+ circularbuf_t *htod_msgbuf = (circularbuf_t *)prot->htodbuf;
+ txdescr_msghdr_t *txdesc = NULL;
+ tx_lenptr_tup_t *tx_tup;
+ dmaaddr_t physaddr;
+ uint8 *pktdata;
+ uint8 *etherhdr;
+ uint16 pktlen;
+ uint16 hdrlen;
+ uint32 pktid;
+
+ /* Extract the data pointer and length information */
+ pktdata = PKTDATA(dhd->osh, PKTBUF);
+ pktlen = (uint16)PKTLEN(dhd->osh, PKTBUF);
+
+ /* Extract the ethernet header and adjust the data pointer and length */
+ etherhdr = pktdata;
+ pktdata += ETHER_HDR_LEN;
+ pktlen -= ETHER_HDR_LEN;
+
+
+ flags = dhd_os_spin_lock(dhd);
+
+ /* Map the data pointer to a DMA-able address */
+ physaddr = DMA_MAP(dhd->osh, pktdata, pktlen, DMA_TX, 0, 0);
+ if (physaddr == 0) {
+ DHD_ERROR(("Something really bad, unless 0 is a valid phyaddr\n"));
+ ASSERT(0);
+ }
+
+ /* Create a unique 32-bit packet id */
+ pktid = NATIVE_TO_PKTID(dhd->prot->pktid_map_handle, PKTBUF, physaddr, pktlen, DMA_TX);
+
+ /* Reserve space in the circular buffer */
+ hdrlen = sizeof(txdescr_msghdr_t) + (1 * sizeof(tx_lenptr_tup_t));
+
+ txdesc = (txdescr_msghdr_t *)dhd_alloc_circularbuf_space(dhd,
+ htod_msgbuf, hdrlen, HOST_TO_DNGL_DATA);
+ if (txdesc == NULL) {
+ dhd_prot_packet_free(dhd, pktid);
+ dhd_os_spin_unlock(dhd, flags);
+
+ DHD_INFO(("%s:%d: HTOD Msgbuf Not available TxCount = %d\n",
+ __FUNCTION__, __LINE__, prot->active_tx_count));
+ return BCME_NORESOURCE;
+ }
+
+ /* Form the Tx descriptor message buffer */
+
+ /* Common message hdr */
+ txdesc->txcmn.msg.msglen = htol16(hdrlen);
+ txdesc->txcmn.msg.msgtype = MSG_TYPE_TX_POST;
+ txdesc->txcmn.msg.u.seq.seq_no = htol16(++prot->data_seq_no);
+
+ /* Ethernet header */
+ txdesc->txcmn.hdrlen = htol16(ETHER_HDR_LEN);
+ bcopy(etherhdr, txdesc->txhdr, ETHER_HDR_LEN);
+
+ /* Packet ID */
+ txdesc->txcmn.pktid = htol32(pktid);
+
+ /* Descriptor count - Linux needs only one */
+ txdesc->txcmn.descrcnt = 0x1;
+
+ tx_tup = (tx_lenptr_tup_t *) &(txdesc->tx_tup);
+
+ /* Descriptor - 0 */
+ tx_tup->pktlen = htol16(pktlen);
+ tx_tup->ret_buf.high_addr = htol32(PHYSADDRHI(physaddr));
+ tx_tup->ret_buf.low_addr = htol32(PHYSADDRLO(physaddr));
+ /* Descriptor 1 - should be filled here - if required */
+
+ /* Reserved for future use */
+ txdesc->txcmn.priority = (uint8)PKTPRIO(PKTBUF);
+ txdesc->txcmn.flowid = 0;
+ txdesc->txcmn.msg.ifidx = ifidx;
+
+ /* Since, we are filling the data directly into the bufptr obtained
+ * from the circularbuf, we can directly call the write_complete
+ */
+ circularbuf_write_complete(htod_msgbuf, hdrlen);
+
+ prot->active_tx_count++;
+
+ /* If we have accounted for most of the lfrag packets on the dongle, */
+ /* it's time to stop the packet flow - Assert flow control. */
+ if ((prot->max_tx_count - prot->active_tx_count) < DHD_STOP_QUEUE_THRESHOLD) {
+ dhd_bus_stop_queue(dhd->bus);
+ prot->txflow_en = TRUE;
+ }
+
+ dhd_os_spin_unlock(dhd, flags);
+
+ return BCME_OK;
+}
+
+#undef PKTBUF /* Only defined in the above routine */
+int dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pkt, uchar *buf, uint *len)
+{
+ return 0;
+}
+
+static void BCMFASTPATH
+dhd_prot_return_rxbuf(dhd_pub_t *dhd, uint16 rxcnt)
+{
+ dhd_prot_t *prot = dhd->prot;
+
+ prot->rxbufpost -= rxcnt;
+ if (prot->rxbufpost <= (prot->max_rxbufpost - RXBUFPOST_THRESHOLD))
+ dhd_msgbuf_rxbuf_post(dhd);
+
+ return;
+}
+
+/* Use protocol to issue ioctl to dongle */
+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;
+
+ if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) {
+ DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
+ 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(("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", (char*)buf));
+ }
+ goto done;
+ }
+
+ prot->pending = TRUE;
+ prot->lastcmd = ioc->cmd;
+ action = ioc->set;
+ if (action & WL_IOCTL_ACTION_SET) {
+ ret = dhd_msgbuf_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action);
+ } else {
+ ret = dhdmsgbuf_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;
+ }
+
+ /* 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
+dhdmsgbuf_lpbk_req(dhd_pub_t *dhd, uint len)
+{
+ unsigned long flags;
+ dhd_prot_t *prot = dhd->prot;
+ circularbuf_t *htod_msgbuf;
+
+ ioct_reqst_hdr_t *ioct_rqst;
+
+ uint16 hdrlen = sizeof(ioct_reqst_hdr_t);
+ uint16 msglen = len + hdrlen;
+
+ if (dhd->prot->htodsplit)
+ htod_msgbuf = (circularbuf_t *) prot->htod_ctrlbuf;
+ else
+ htod_msgbuf = (circularbuf_t *) prot->htodbuf;
+
+ if (msglen > MSGBUF_MAX_MSG_SIZE)
+ msglen = MSGBUF_MAX_MSG_SIZE;
+
+ msglen = align(msglen, 4);
+
+ /* locks required to protect circular buffer accesses */
+ flags = dhd_os_spin_lock(dhd);
+
+ if (dhd->prot->htodsplit) {
+ ioct_rqst = (ioct_reqst_hdr_t *)dhd_alloc_circularbuf_space(dhd,
+ htod_msgbuf, msglen, HOST_TO_DNGL_CTRL);
+ }
+ else {
+ ioct_rqst = (ioct_reqst_hdr_t *)dhd_alloc_circularbuf_space(dhd,
+ htod_msgbuf, msglen, HOST_TO_DNGL_DATA);
+ }
+
+ if (ioct_rqst == NULL) {
+ dhd_os_spin_unlock(dhd, flags);
+ 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.msglen = htol16(msglen);
+ ioct_rqst->msg.msgtype = MSG_TYPE_LOOPBACK;
+ ioct_rqst->msg.ifidx = 0;
+ ioct_rqst->msg.u.seq.seq_no = htol16(++prot->data_seq_no);
+
+ bcm_print_bytes("LPBK REQ: ", (uint8 *)ioct_rqst, msglen);
+
+ circularbuf_write_complete(htod_msgbuf, msglen);
+
+ dhd_os_spin_unlock(dhd, flags);
+
+ return 0;
+}
+
+
+static int
+dhdmsgbuf_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action)
+{
+ dhd_prot_t *prot = dhd->prot;
+
+ int ret = 0;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ /* 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;
+ }
+ }
+
+ /* Fill up msgbuf for ioctl req */
+ if (len < MAX_INLINE_IOCTL_LEN) {
+ /* Inline ioct resuest */
+ ret = dhd_fillup_ioct_reqst(dhd, (uint16)len, cmd, buf, ifidx);
+ } else {
+ /* Non inline ioct resuest */
+ ret = dhd_fillup_ioct_reqst_ptrbased(dhd, (uint16)len, cmd, buf, ifidx);
+ }
+
+ DHD_INFO(("ACTION %d ifdix %d cmd %d len %d \n",
+ action, ifidx, cmd, len));
+
+ /* wait for interrupt and get first fragment */
+ ret = dhdmsgbuf_cmplt(dhd, prot->reqid, len, buf, prot->retbuf);
+
+done:
+ return ret;
+}
+static int
+dhdmsgbuf_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len, void* buf, void* retbuf)
+{
+ dhd_prot_t *prot = dhd->prot;
+ ioct_resp_hdr_t ioct_resp;
+ uint8* data;
+ int retlen;
+ int msgbuf_len = 0;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ retlen = dhd_bus_rxctl(dhd->bus, (uchar*)&ioct_resp, msgbuf_len);
+
+ if (retlen <= 0)
+ return -1;
+
+ /* get ret buf */
+ if (buf != NULL) {
+ if (retlen <= 4) {
+ bcopy((void*)&ioct_resp.inline_data, buf, retlen);
+ DHD_INFO(("%s: data is %d, ret_len is %d\n",
+ __FUNCTION__, ioct_resp.inline_data, retlen));
+ }
+ else {
+ data = (uint8*)retbuf;
+ bcopy((void*)&data[prot->rx_dataoffset], buf, retlen);
+ }
+ }
+ return ioct_resp.status;
+}
+static int
+dhd_msgbuf_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action)
+{
+ dhd_prot_t *prot = dhd->prot;
+
+ int ret = 0;
+
+ DHD_TRACE(("%s: Enter \n", __FUNCTION__));
+ DHD_TRACE(("%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;
+ }
+
+ /* Fill up msgbuf for ioctl req */
+ if (len < MAX_INLINE_IOCTL_LEN) {
+ /* Inline ioct resuest */
+ ret = dhd_fillup_ioct_reqst(dhd, (uint16)len, cmd, buf, ifidx);
+ } else {
+ /* Non inline ioct resuest */
+ ret = dhd_fillup_ioct_reqst_ptrbased(dhd, (uint16)len, cmd, buf, ifidx);
+ }
+
+ DHD_INFO(("ACTIOn %d ifdix %d cmd %d len %d \n",
+ action, ifidx, cmd, len));
+
+ ret = dhdmsgbuf_cmplt(dhd, prot->reqid, len, buf, prot->retbuf);
+
+ return ret;
+}
+/* Handles a protocol control response asynchronously */
+int dhd_prot_ctl_complete(dhd_pub_t *dhd)
+{
+ return 0;
+}
+
+/* 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 *strbuf)
+{
+
+}
+
+/* Update local copy of dongle statistics */
+void dhd_prot_dstats(dhd_pub_t *dhd)
+{
+ return;
+}
+
+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;
+}
+/* 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 msglen = sizeof(hostevent_hdr_t);
+
+ dhd_prot_t *prot = dhd->prot;
+ circularbuf_t *htod_msgbuf;
+
+ /* locks required to protect circular buffer accesses */
+ flags = dhd_os_spin_lock(dhd);
+ if (dhd->prot->htodsplit) {
+ htod_msgbuf = (circularbuf_t *)prot->htod_ctrlbuf;
+ hevent = (hostevent_hdr_t *)dhd_alloc_circularbuf_space(dhd,
+ htod_msgbuf, msglen, HOST_TO_DNGL_CTRL);
+ }
+ else {
+ htod_msgbuf = (circularbuf_t *)prot->htodbuf;
+ hevent = (hostevent_hdr_t *)dhd_alloc_circularbuf_space(dhd,
+ htod_msgbuf, msglen, HOST_TO_DNGL_DATA);
+ }
+
+ if (hevent == NULL) {
+ dhd_os_spin_unlock(dhd, flags);
+ return -1;
+ }
+
+ /* CMN msg header */
+ hevent->msg.msglen = htol16(msglen);
+ hevent->msg.msgtype = MSG_TYPE_HOST_EVNT;
+ hevent->msg.ifidx = 0;
+ hevent->msg.u.seq.seq_no = htol16(++prot->data_seq_no);
+
+ /* 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
+ */
+ circularbuf_write_complete(htod_msgbuf, msglen);
+ dhd_os_spin_unlock(dhd, flags);
+
+ return 0;
+}
+void * BCMFASTPATH
+dhd_alloc_circularbuf_space(dhd_pub_t *dhd, circularbuf_t *handle, uint16 msglen, uint path)
+{
+ void * ret_buf;
+
+ ret_buf = circularbuf_reserve_for_write(handle, msglen);
+ if (ret_buf == NULL) {
+ /* Try again after updating the read ptr from dongle */
+ if (path == HOST_TO_DNGL_DATA)
+ dhd_bus_cmn_readshared(dhd->bus, &(CIRCULARBUF_READ_PTR(handle)),
+ HOST_TO_DNGL_RPTR);
+ else if (path == HOST_TO_DNGL_CTRL)
+ dhd_bus_cmn_readshared(dhd->bus, &(CIRCULARBUF_READ_PTR(handle)),
+ HTOD_CTRL_RPTR);
+ else
+ DHD_ERROR(("%s:%d: Unknown path value \n", __FUNCTION__, __LINE__));
+ ret_buf = circularbuf_reserve_for_write(handle, msglen);
+ if (ret_buf == NULL) {
+ DHD_INFO(("%s:%d: HTOD Msgbuf Not available \n", __FUNCTION__, __LINE__));
+ return NULL;
+ }
+ }
+
+ return ret_buf;
+}
+INLINE bool
+dhd_prot_dtohsplit(dhd_pub_t* dhd)
+{
+ return dhd->prot->dtohsplit;
+}
+static int
+dhd_fillup_ioct_reqst(dhd_pub_t *dhd, uint16 len, uint cmd, void* buf, int ifidx)
+{
+ dhd_prot_t *prot = dhd->prot;
+ ioct_reqst_hdr_t *ioct_rqst;
+ uint16 hdrlen = sizeof(ioct_reqst_hdr_t);
+ uint16 msglen = len + hdrlen;
+ circularbuf_t *htod_msgbuf;
+ unsigned long flags;
+ uint16 rqstlen = len;
+
+ /* Limit ioct request to MSGBUF_MAX_MSG_SIZE bytes including hdrs */
+ if (rqstlen + hdrlen > MSGBUF_MAX_MSG_SIZE)
+ rqstlen = MSGBUF_MAX_MSG_SIZE - hdrlen;
+
+ /* Messge = hdr + rqstbuf */
+ msglen = rqstlen + hdrlen;
+
+ /* align it to 4 bytes, so that all start addr form cbuf is 4 byte aligned */
+ msglen = align(msglen, 4);
+
+ /* locks required to protect circular buffer accesses */
+ flags = dhd_os_spin_lock(dhd);
+
+ /* Request for cbuf space */
+ if (dhd->prot->htodsplit) {
+ htod_msgbuf = (circularbuf_t *)prot->htod_ctrlbuf;
+ ioct_rqst = (ioct_reqst_hdr_t *)dhd_alloc_circularbuf_space(dhd,
+ htod_msgbuf, msglen, HOST_TO_DNGL_CTRL);
+ }
+ else {
+ htod_msgbuf = (circularbuf_t *)prot->htodbuf;
+ ioct_rqst = (ioct_reqst_hdr_t *)dhd_alloc_circularbuf_space(dhd,
+ htod_msgbuf, msglen, HOST_TO_DNGL_DATA);
+ }
+
+ if (ioct_rqst == NULL) {
+ dhd_os_spin_unlock(dhd, flags);
+ return -1;
+ }
+
+ /* Common msg buf hdr */
+ ioct_rqst->msg.msglen = htol16(msglen);
+ ioct_rqst->msg.msgtype = MSG_TYPE_IOCTL_REQ;
+ ioct_rqst->msg.ifidx = (uint8)ifidx;
+ ioct_rqst->msg.u.seq.seq_no = htol16(++prot->ioctl_seq_no);
+
+ /* Ioctl specific Message buf header */
+ ioct_rqst->ioct_hdr.cmd = htol32(cmd);
+ ioct_rqst->ioct_hdr.pkt_id = htol32(++prot->reqid);
+ ioct_rqst->ioct_hdr.retbuf_len = htol16(len);
+ ioct_rqst->ioct_hdr.xt_id = (uint16)ioct_rqst->ioct_hdr.pkt_id;
+ DHD_CTL(("sending IOCTL_REQ cmd %d, pkt_id %d xt_id %d\n",
+ ioct_rqst->ioct_hdr.cmd, ioct_rqst->ioct_hdr.pkt_id, ioct_rqst->ioct_hdr.xt_id));
+
+ /* Ret buf ptr */
+ ioct_rqst->ret_buf.high_addr = htol32(PHYSADDRHI(prot->retbuf_phys));
+ ioct_rqst->ret_buf.low_addr = htol32(PHYSADDRLO(prot->retbuf_phys));
+
+ /* copy ioct payload */
+ if (buf)
+ memcpy(&ioct_rqst[1], buf, rqstlen);
+
+ /* upd wrt ptr and raise interrupt */
+ circularbuf_write_complete(htod_msgbuf, msglen);
+ dhd_os_spin_unlock(dhd, flags);
+
+ return 0;
+}
+/* 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_ptrbased(dhd_pub_t *dhd, uint16 len, uint cmd, void* buf, int ifidx)
+{
+ dhd_prot_t *prot = dhd->prot;
+ ioctptr_reqst_hdr_t *ioct_rqst;
+ uint16 msglen = sizeof(ioctptr_reqst_hdr_t);
+ circularbuf_t * htod_msgbuf;
+ cmn_msg_hdr_t * ioct_buf; /* For ioctl payload */
+ uint16 alignlen, rqstlen = len;
+ unsigned long flags;
+
+ /* Limit ioct request to MSGBUF_MAX_MSG_SIZE bytes including hdrs */
+ if ((rqstlen + sizeof(cmn_msg_hdr_t)) > MSGBUF_MAX_MSG_SIZE)
+ rqstlen = MSGBUF_MAX_MSG_SIZE - sizeof(cmn_msg_hdr_t);
+
+ /* align it to 4 bytes, so that all start addr form cbuf is 4 byte aligned */
+ alignlen = align(rqstlen, 4);
+
+ /* locks required to protect circular buffer accesses */
+ flags = dhd_os_spin_lock(dhd);
+ /* Request for cbuf space */
+ if (dhd->prot->htodsplit) {
+ htod_msgbuf = (circularbuf_t *)prot->htod_ctrlbuf;
+ ioct_rqst = (ioctptr_reqst_hdr_t*)dhd_alloc_circularbuf_space(dhd,
+ htod_msgbuf, msglen, HOST_TO_DNGL_CTRL);
+ }
+ else {
+ htod_msgbuf = (circularbuf_t *)prot->htodbuf;
+ ioct_rqst = (ioctptr_reqst_hdr_t*)dhd_alloc_circularbuf_space(dhd,
+ htod_msgbuf, msglen, HOST_TO_DNGL_DATA);
+ }
+ if (ioct_rqst == NULL) {
+ dhd_os_spin_unlock(dhd, flags);
+ return -1;
+ }
+
+ /* Common msg buf hdr */
+ ioct_rqst->msg.msglen = htol16(msglen);
+ ioct_rqst->msg.msgtype = MSG_TYPE_IOCTLPTR_REQ;
+ ioct_rqst->msg.ifidx = (uint8)ifidx;
+ ioct_rqst->msg.u.seq.seq_no = htol16(++prot->ioctl_seq_no);
+
+ /* Ioctl specific Message buf header */
+ ioct_rqst->ioct_hdr.cmd = htol32(cmd);
+ ioct_rqst->ioct_hdr.pkt_id = htol32(++prot->reqid);
+ ioct_rqst->ioct_hdr.retbuf_len = htol16(len);
+ ioct_rqst->ioct_hdr.xt_id = (uint16)ioct_rqst->ioct_hdr.pkt_id;
+
+ DHD_CTL(("sending IOCTL_PTRREQ cmd %d, pkt_id %d xt_id %d\n",
+ ioct_rqst->ioct_hdr.cmd, ioct_rqst->ioct_hdr.pkt_id, ioct_rqst->ioct_hdr.xt_id));
+
+ /* Ret buf ptr */
+ ioct_rqst->ret_buf.high_addr = htol32(PHYSADDRHI(prot->retbuf_phys));
+ ioct_rqst->ret_buf.low_addr = htol32(PHYSADDRLO(prot->retbuf_phys));
+
+ /* copy ioct payload */
+ ioct_buf = (cmn_msg_hdr_t *) prot->ioctbuf;
+ ioct_buf->msglen = htol16(alignlen + sizeof(cmn_msg_hdr_t));
+ ioct_buf->msgtype = MSG_TYPE_IOCT_PYLD;
+
+ if (buf) {
+ memcpy(&ioct_buf[1], buf, rqstlen);
+ OSL_CACHE_FLUSH((void *) prot->ioctbuf, rqstlen+sizeof(cmn_msg_hdr_t));
+ }
+
+ if ((ulong)ioct_buf % 4)
+ printf("host ioct address unaligned !!!!! \n");
+
+ /* populate ioctl buffer info */
+ ioct_rqst->ioct_hdr.buflen = htol16(alignlen + sizeof(cmn_msg_hdr_t));
+ ioct_rqst->ioct_buf.high_addr = htol32(PHYSADDRHI(prot->ioctbuf_phys));
+ ioct_rqst->ioct_buf.low_addr = htol32(PHYSADDRLO(prot->ioctbuf_phys));
+
+ /* upd wrt ptr and raise interrupt */
+ circularbuf_write_complete(htod_msgbuf, msglen);
+
+ dhd_os_spin_unlock(dhd, flags);
+
+ return 0;
+}
+
+/* Packet to PacketID mapper */
+typedef struct {
+ ulong native;
+ dmaaddr_t pa;
+ uint32 pa_len;
+ uchar dma;
+} pktid_t;
+
+typedef struct {
+ void *osh;
+ void *mwbmap_hdl;
+ pktid_t *pktid_list;
+ uint32 count;
+} pktid_map_t;
+
+
+void *pktid_map_init(void *osh, uint32 count)
+{
+ pktid_map_t *handle;
+
+ handle = (pktid_map_t *) MALLOC(osh, sizeof(pktid_map_t));
+ if (handle == NULL) {
+ printf("%s:%d: MALLOC failed for size %d\n",
+ __FUNCTION__, __LINE__, (uint32) sizeof(pktid_map_t));
+ return NULL;
+ }
+ handle->osh = osh;
+ handle->count = count;
+ handle->mwbmap_hdl = bcm_mwbmap_init(osh, count);
+ if (handle->mwbmap_hdl == NULL) {
+ printf("%s:%d: bcm_mwbmap_init failed for count %d\n",
+ __FUNCTION__, __LINE__, count);
+ MFREE(osh, handle, sizeof(pktid_map_t));
+ return NULL;
+ }
+
+ handle->pktid_list = (pktid_t *) MALLOC(osh, sizeof(pktid_t) * (count+1));
+ if (handle->pktid_list == NULL) {
+ printf("%s:%d: MALLOC failed for count %d / total = %d\n",
+ __FUNCTION__, __LINE__, count, (uint32) sizeof(pktid_t) * count);
+ bcm_mwbmap_fini(osh, handle->mwbmap_hdl);
+ MFREE(osh, handle, sizeof(pktid_map_t));
+ return NULL;
+ }
+
+ return handle;
+}
+
+void
+pktid_map_uninit(void *pktid_map_handle)
+{
+ pktid_map_t *handle = (pktid_map_t *) pktid_map_handle;
+ uint32 ix;
+
+ if (handle != NULL) {
+ void *osh = handle->osh;
+ for (ix = 0; ix < MAX_PKTID_ITEMS; ix++)
+ {
+ if (!bcm_mwbmap_isfree(handle->mwbmap_hdl, ix)) {
+ /* Mark the slot as free */
+ bcm_mwbmap_free(handle->mwbmap_hdl, ix);
+ /*
+ Here we can do dma unmapping for 32 bit also.
+ Since this in removal path, it will not affect performance
+ */
+ DMA_UNMAP(osh, (uint) handle->pktid_list[ix+1].pa,
+ (uint) handle->pktid_list[ix+1].pa_len,
+ handle->pktid_list[ix+1].dma, 0, 0);
+ PKTFREE(osh,
+ (unsigned long*)handle->pktid_list[ix+1].native, TRUE);
+ }
+ }
+ bcm_mwbmap_fini(osh, handle->mwbmap_hdl);
+ MFREE(osh, handle->pktid_list, sizeof(pktid_t) * (handle->count+1));
+ MFREE(osh, handle, sizeof(pktid_map_t));
+ }
+ return;
+}
+
+uint32 BCMFASTPATH
+pktid_map_unique(void *pktid_map_handle, void *pkt, dmaaddr_t physaddr, uint32 physlen, uint32 dma)
+{
+ uint32 id;
+ pktid_map_t *handle = (pktid_map_t *) pktid_map_handle;
+
+ if (handle == NULL) {
+ printf("%s:%d: Error !!! pktid_map_unique called without initing pktid_map\n",
+ __FUNCTION__, __LINE__);
+ return 0;
+ }
+ id = bcm_mwbmap_alloc(handle->mwbmap_hdl);
+ if (id == BCM_MWBMAP_INVALID_IDX) {
+ printf("%s:%d: bcm_mwbmap_alloc failed. Free Count = %d\n",
+ __FUNCTION__, __LINE__, bcm_mwbmap_free_cnt(handle->mwbmap_hdl));
+ return 0;
+ }
+
+ /* id=0 is invalid as we use this for error checking in the dongle */
+ id += 1;
+ handle->pktid_list[id].native = (ulong) pkt;
+ handle->pktid_list[id].pa = physaddr;
+ handle->pktid_list[id].pa_len = (uint32) physlen;
+ handle->pktid_list[id].dma = dma;
+
+ return id;
+}
+
+void * BCMFASTPATH
+pktid_get_packet(void *pktid_map_handle, uint32 id, dmaaddr_t *physaddr, uint32 *physlen)
+{
+ void *native = NULL;
+ pktid_map_t *handle = (pktid_map_t *) pktid_map_handle;
+ if (handle == NULL) {
+ printf("%s:%d: Error !!! pktid_get_packet called without initing pktid_map\n",
+ __FUNCTION__, __LINE__);
+ return NULL;
+ }
+
+ /* Debug check */
+ if (bcm_mwbmap_isfree(handle->mwbmap_hdl, (id-1))) {
+ printf("%s:%d: Error !!!. How can the slot (%d) be free if the app is using it.\n",
+ __FUNCTION__, __LINE__, (id-1));
+ return NULL;
+ }
+
+ native = (void *) handle->pktid_list[id].native;
+ *physaddr = handle->pktid_list[id].pa;
+ *physlen = (uint32) handle->pktid_list[id].pa_len;
+
+ /* Mark the slot as free */
+ bcm_mwbmap_free(handle->mwbmap_hdl, (id-1));
+
+ return native;
+}
diff --git a/drivers/net/wireless/bcmdhd/dhd_pcie.c b/drivers/net/wireless/bcmdhd/dhd_pcie.c
new file mode 100644
index 000000000000..ca02e4ecd90b
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_pcie.c
@@ -0,0 +1,2566 @@
+/*
+ * DHD Bus Module for PCIE
+ *
+ * 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: dhd_pcie.c 662459 2016-10-24 04:35:43Z $
+ */
+
+
+/* include files */
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <bcmdevs.h>
+#include <siutils.h>
+#include <hndsoc.h>
+#include <hndpmu.h>
+#include <sbchipc.h>
+#if defined(DHD_DEBUG)
+#include <hndrte_armtrap.h>
+#include <hndrte_cons.h>
+#endif /* defined(DHD_DEBUG) */
+#include <dngl_stats.h>
+#include <pcie_core.h>
+#include <dhd.h>
+#include <dhd_bus.h>
+#include <dhd_proto.h>
+#include <dhd_dbg.h>
+#include <dhdioctl.h>
+#include <sdiovar.h>
+#include <bcmmsgbuf.h>
+#include <pcicfg.h>
+#include <circularbuf.h>
+#include <dhd_pcie.h>
+#include <bcmpcie.h>
+
+#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
+#define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */
+
+#define ARMCR4REG_BANKIDX (0x40/sizeof(uint32))
+#define ARMCR4REG_BANKPDA (0x4C/sizeof(uint32))
+
+int dhd_dongle_memsize;
+int dhd_dongle_ramsize;
+#ifdef DHD_DEBUG
+static int dhdpcie_bus_readconsole(dhd_bus_t *bus);
+#endif
+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_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 void dhdpcie_bus_process_mailbox_intr(dhd_bus_t *bus, uint32 intstatus);
+static void 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_intr_enable(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);
+static void dhdpcie_bus_wreg32(dhd_bus_t *bus, uint reg, uint32 data);
+static uint32 dhdpcie_bus_rreg32(dhd_bus_t *bus, uint reg);
+static void dhdpcie_bus_cfg_set_bar0_win(dhd_bus_t *bus, uint32 data);
+static void dhdpcie_bus_reg_unmap(osl_t *osh, ulong addr, int size);
+static int dhdpcie_cc_nvmshadow(dhd_bus_t *bus, struct bcmstrbuf *b);
+static void dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data);
+
+#define PCI_VENDOR_ID_BROADCOM 0x14e4
+
+/* IOVar table */
+enum {
+ IOV_INTR = 1,
+ IOV_MEMBYTES,
+ 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_PCIEREG,
+ IOV_PCIECFGREG,
+ IOV_PCIECOREREG,
+ IOV_SBREG,
+ IOV_DONGLEISOLATION,
+ IOV_LTRSLEEPON_UNLOOAD
+};
+
+
+const bcm_iovar_t dhdpcie_iovars[] = {
+ {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
+ {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
+ {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 },
+ {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 },
+ {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
+ {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
+ {"pcie_lpbk", IOV_PCIE_LPBK, 0, IOVT_UINT32, 0 },
+ {"cc_nvmshadow", IOV_CC_NVMSHADOW, 0, IOVT_BUFFER, 0 },
+ {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 },
+ {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 },
+ {"pciereg", IOV_PCIEREG, 0, IOVT_BUFFER, 2 * sizeof(int32) },
+ {"pciecfgreg", IOV_PCIECFGREG, 0, IOVT_BUFFER, 2 * sizeof(int32) },
+ {"pciecorereg", IOV_PCIECOREREG, 0, IOVT_BUFFER, 2 * sizeof(int32) },
+ {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
+ {"sleep_allowed", IOV_SLEEP_ALLOWED, 0, IOVT_BOOL, 0 },
+ {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
+ {"ltrsleep_on_unload", IOV_LTRSLEEPON_UNLOOAD, 0, IOVT_UINT32, 0 },
+ {NULL, 0, 0, 0, 0 }
+};
+
+#define MAX_READ_TIMEOUT 5 * 1000 * 1000
+
+/* 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.
+ */
+
+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, ulong addr, int size)
+{
+ REG_UNMAP((void*)(uintptr)addr);
+ return;
+}
+
+/** '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)
+{
+ dhd_bus_t *bus;
+
+ int ret = 0;
+
+ DHD_TRACE(("%s: ENTER\n", __FUNCTION__));
+
+ do {
+ if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
+ DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
+ break;
+ }
+ bzero(bus, sizeof(dhd_bus_t));
+ bus->regs = regs;
+ bus->tcm = tcm;
+ bus->osh = osh;
+
+ /* Attach pcie shared structure */
+ bus->pcie_sh = MALLOC(osh, sizeof(pciedev_shared_t));
+
+ /* 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;
+
+ /* Attach to the OS network interface */
+ DHD_TRACE(("%s(): Calling dhd_register_if() \n", __FUNCTION__));
+ ret = dhd_register_if(bus->dhd, 0, TRUE);
+ if (ret) {
+ DHD_ERROR(("%s(): ERROR.. dhd_register_if() failed\n", __FUNCTION__));
+ break;
+ }
+ DHD_TRACE(("%s: EXIT SUCCESS\n",
+ __FUNCTION__));
+
+ return bus;
+ } while (0);
+
+ DHD_TRACE(("%s: EXIT FAILURE\n", __FUNCTION__));
+
+ 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;
+}
+
+void *
+dhd_bus_sih(struct dhd_bus *bus)
+{
+ return (void *)bus->sih;
+}
+
+void *
+dhd_bus_txq(struct dhd_bus *bus)
+{
+ return &bus->txq;
+}
+
+
+/*
+
+Name: dhdpcie_bus_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.
+*/
+
+
+int32
+dhdpcie_bus_isr(dhd_bus_t *bus)
+{
+
+ 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->busstate == DHD_BUS_DOWN) {
+ DHD_ERROR(("%s : bus is down. we have nothing to do\n",
+ __FUNCTION__));
+ break;
+ }
+
+
+#ifdef DHD_ALLIRQ
+ /* Lock here covers SMP */
+ dhd_os_sdisrlock(bus->dhd);
+#endif
+ /* Count the interrupt call */
+ bus->intrcount++;
+
+ /* read interrupt status register!! Status bits will be cleared in DPC !! */
+ bus->ipend = TRUE;
+ dhdpcie_bus_intr_disable(bus); /* Disable interrupt!! */
+ bus->intdis = TRUE;
+
+#if defined(DHD_ALLIRQ) || 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(DHD_ALLIRQ) || defined(SDIO_ISR_THREAD) */
+
+#ifdef DHD_ALLIRQ
+ dhd_os_sdisrunlock(bus->dhd);
+#endif
+ DHD_TRACE(("%s: Exit Success DPC Queued\n", __FUNCTION__));
+ return TRUE;
+
+ } while (0);
+
+ DHD_TRACE(("%s: Exit Failure\n", __FUNCTION__));
+ return FALSE;
+}
+
+static bool
+dhdpcie_dongle_attach(dhd_bus_t *bus)
+{
+
+ osl_t *osh = bus->osh;
+ void *regsva = (void*)bus->regs;
+ uint16 devid = bus->cl_devid;
+ uint32 val;
+
+ DHD_TRACE(("%s: ENTER\n",
+ __FUNCTION__));
+
+ bus->alp_only = TRUE;
+ bus->sih = NULL;
+
+ /* Set bar0 window to si_enum_base */
+ dhdpcie_bus_cfg_set_bar0_win(bus, SI_ENUM_BASE);
+
+ /* 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;
+ }
+
+ si_setcore(bus->sih, PCIE2_CORE_ID, 0);
+
+ dhdpcie_bus_wreg32(bus, OFFSETOF(sbpcieregs_t, configaddr), 0x4e0);
+ val = dhdpcie_bus_rreg32(bus, OFFSETOF(sbpcieregs_t, configdata));
+ dhdpcie_bus_wreg32(bus, OFFSETOF(sbpcieregs_t, configdata), val);
+
+ /* Get info on the ARM and SOCRAM cores... */
+ 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:
+ bus->dongle_ram_base = CR4_4335_RAM_BASE;
+ break;
+ case BCM4354_CHIP_ID:
+ case BCM4350_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_ID:
+ /* RAM base changed from 4345c0 (chiprev=6) onwards */
+ bus->dongle_ram_base = (bus->sih->chiprev < 6)
+ ? CR4_4345_LT_C0_RAM_BASE : CR4_4345_GE_C0_RAM_BASE;
+ break;
+ case BCM43602_CHIP_ID:
+ bus->dongle_ram_base = CR4_43602_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;
+
+ DHD_TRACE(("%s: EXIT: SUCCESS\n",
+ __FUNCTION__));
+ return 0;
+
+fail:
+ if (bus->sih != NULL)
+ si_detach(bus->sih);
+ 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(("enable interrupts\n"));
+ if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) ||
+ (bus->sih->buscorerev == 4)) {
+ dhpcie_bus_unmask_interrupt(bus);
+ }
+ else if (bus->sih) {
+ si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxMask,
+ bus->def_intmask, bus->def_intmask);
+ }
+}
+
+void
+dhdpcie_bus_intr_disable(dhd_bus_t *bus)
+{
+
+ DHD_TRACE(("%s Enter\n", __FUNCTION__));
+
+ if (bus) {
+
+ if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) ||
+ (bus->sih->buscorerev == 4)) {
+ dhpcie_bus_mask_interrupt(bus);
+ }
+ else if (bus->sih) {
+ si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxMask,
+ bus->def_intmask, 0);
+ }
+ }
+ 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) {
+ dongle_isolation = bus->dhd->dongle_isolation;
+ dhd_detach(bus->dhd);
+
+ if (bus->intr) {
+ dhdpcie_bus_intr_disable(bus);
+ dhdpcie_free_irq(bus);
+ }
+ dhdpcie_bus_release_dongle(bus, osh, dongle_isolation, TRUE);
+ dhd_free(bus->dhd);
+ bus->dhd = NULL;
+ }
+
+ /* unmap the regs and tcm here!! */
+ if (bus->regs) {
+ dhdpcie_bus_reg_unmap(osh, (ulong)bus->regs, DONGLE_REG_MAP_SIZE);
+ bus->regs = NULL;
+ }
+ if (bus->tcm) {
+ dhdpcie_bus_reg_unmap(osh, (ulong)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));
+
+#ifdef DHD_DEBUG
+
+ if (bus->console.buf != NULL)
+ MFREE(osh, bus->console.buf, bus->console.bufsize);
+#endif
+
+
+ /* Finally free bus info */
+ MFREE(osh, bus, sizeof(dhd_bus_t));
+
+ }
+
+ DHD_TRACE(("%s: Exit\n", __FUNCTION__));
+
+}
+
+
+void
+dhdpcie_bus_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag)
+{
+
+ DHD_TRACE(("%s Enter\n", __FUNCTION__));
+
+ 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) {
+ uint32 val, i;
+ uint16 cfg_offset[] = {0x4, 0x4C, 0x58, 0x5C, 0x60, 0x64, 0xDC,
+ 0x228, 0x248, 0x4e0, 0x4f4};
+ si_corereg(bus->sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, 4);
+ /* apply the WAR: need to restore the config space snoop bus values */
+ OSL_DELAY(100000);
+
+ for (i = 0; i < ARRAYSIZE(cfg_offset); i++) {
+ dhdpcie_bus_wreg32(bus, OFFSETOF(sbpcieregs_t, configaddr),
+ cfg_offset[i]);
+ val = dhdpcie_bus_rreg32(bus,
+ OFFSETOF(sbpcieregs_t, configdata));
+ DHD_INFO(("SNOOP_BUS_UPDATE: config offset 0x%04x, value 0x%04x\n",
+ cfg_offset[i], val));
+ dhdpcie_bus_wreg32(bus, OFFSETOF(sbpcieregs_t, configdata), val);
+ }
+ }
+ if (bus->ltrsleep_on_unload) {
+ si_corereg(bus->sih, bus->sih->buscoreidx,
+ OFFSETOF(sbpcieregs_t, u.pcie2.ltr_state), ~0, 0);
+ }
+ si_detach(bus->sih);
+ 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);
+}
+
+/* 32 bit pio write to device TCM */
+void
+dhdpcie_bus_wreg32(dhd_bus_t *bus, uint reg, uint32 data)
+{
+ *(volatile uint32 *)(bus->regs + reg) = (uint32)data;
+
+}
+
+uint32
+dhdpcie_bus_rreg32(dhd_bus_t *bus, uint reg)
+{
+ uint32 data;
+
+ data = *(volatile uint32 *)(bus->regs + reg);
+ return 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;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ if (!bus->dhd)
+ return;
+
+ if (enforce_mutex)
+ dhd_os_sdlock(bus->dhd);
+
+ bus->dhd->busstate = DHD_BUS_DOWN;
+ dhdpcie_bus_intr_disable(bus);
+ status = dhdpcie_bus_cfg_read_dword(bus, PCIIntstatus, 4);
+ dhdpcie_bus_cfg_write_dword(bus, PCIIntstatus, 4, status);
+
+ /* Clear rx control and wake any waiters */
+ bus->rxlen = 0;
+ dhd_os_ioctl_resp_wake(bus->dhd);
+
+ if (enforce_mutex)
+ dhd_os_sdunlock(bus->dhd);
+
+ return;
+}
+
+/* Watchdog timer function */
+bool dhd_bus_watchdog(dhd_pub_t *dhd)
+{
+#ifdef DHD_DEBUG
+ dhd_bus_t *bus;
+ bus = dhd->bus;
+
+
+
+ /* Poll for console output periodically */
+ if (dhd->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 (dhdpcie_bus_readconsole(bus) < 0)
+ dhd_console_ms = 0; /* On error, stop trying */
+ }
+ }
+#endif /* DHD_DEBUG */
+
+ return FALSE;
+}
+
+/* Download firmware image and nvram image */
+int
+dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
+ char *pfw_path, char *pnv_path)
+{
+ int ret;
+
+ bus->fw_path = pfw_path;
+ bus->nv_path = pnv_path;
+
+ ret = dhdpcie_download_firmware(bus, osh);
+
+ return ret;
+}
+
+static int
+dhdpcie_download_firmware(struct dhd_bus *bus, osl_t *osh)
+{
+ int ret = 0;
+
+ DHD_OS_WAKE_LOCK(bus->dhd);
+
+ 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 = -1;
+ int offset = 0;
+ int len;
+ void *image = NULL;
+ uint8 *memblock = NULL, *memptr;
+
+ DHD_ERROR(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
+
+ image = dhd_os_open_image(pfw_path);
+ if (image == NULL)
+ 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 ((uint32)(uintptr)memblock % DHD_SDALIGN)
+ memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
+
+ /* Download image */
+ while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
+ 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 = dhdpcie_bus_membytes(bus, TRUE, offset, memptr, len);
+ if (bcmerror) {
+ DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
+ __FUNCTION__, bcmerror, MEMBLOCK, offset));
+ goto err;
+ }
+
+ offset += MEMBLOCK;
+ }
+
+err:
+ if (memblock)
+ MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
+
+ if (image)
+ dhd_os_close_image(image);
+
+ return bcmerror;
+}
+
+
+static int
+dhdpcie_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'));
+ if (!nvram_file_exists && (bus->nvram_params == NULL))
+ return (0);
+
+ if (nvram_file_exists) {
+ image = dhd_os_open_image(pnv_path);
+ if (image == NULL)
+ 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;
+ }
+
+ /* Download variables */
+ if (nvram_file_exists) {
+ len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
+ }
+ else {
+ len = strlen(bus->nvram_params);
+ ASSERT(len <= MAX_NVRAMBUF_SIZE);
+ memcpy(memblock, bus->nvram_params, len);
+ }
+ 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 = dhdpcie_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_ERROR;
+ }
+
+err:
+ if (memblock)
+ MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
+
+ if (image)
+ dhd_os_close_image(image);
+
+ return bcmerror;
+}
+
+
+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
+ }
+
+ /* 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;
+}
+
+int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
+{
+ int timeleft;
+ uint rxlen = 0;
+ bool pending;
+
+ 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, &pending);
+ dhd_os_sdlock(bus->dhd);
+ rxlen = bus->rxlen;
+ bcopy(&bus->ioct_resp, msg, sizeof(ioct_resp_hdr_t));
+ bus->rxlen = 0;
+ dhd_os_sdunlock(bus->dhd);
+
+ if (rxlen) {
+ DHD_CTL(("%s: resumed on rxctl frame, got %d\n", __FUNCTION__, rxlen));
+ } else if (timeleft == 0) {
+ DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
+ bus->ioct_resp.pkt_id = 0;
+ bus->ioct_resp.status = 0xffff;
+ } else if (pending == TRUE) {
+ DHD_CTL(("%s: canceled\n", __FUNCTION__));
+ return -ERESTARTSYS;
+ } else {
+ DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
+ }
+ if (timeleft == 0) {
+ bus->dhd->rxcnt_timeout++;
+ DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout));
+ }
+ else
+ bus->dhd->rxcnt_timeout = 0;
+
+ if (rxlen)
+ bus->dhd->rx_ctlpkts++;
+ else
+ bus->dhd->rx_ctlerrs++;
+
+ if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TX_TIMEOUT)
+ return -ETIMEDOUT;
+
+ if (bus->dhd->dongle_trap_occured)
+ return -EREMOTEIO;
+
+ return rxlen ? (int)rxlen : -EIO;
+
+}
+
+#define CONSOLE_LINE_MAX 192
+
+#ifdef DHD_DEBUG
+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(hndrte_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;
+ printf("CONSOLE: %s\n", line);
+ }
+ }
+break2:
+
+ return BCME_OK;
+}
+#endif /* DHD_DEBUG */
+
+/**
+ * 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)
+{
+ int bcmerror = 0;
+ uint dsize;
+ uint i = 0;
+ /* 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 */
+ dsize = sizeof(uint8);
+
+ /* Do the transfer(s) */
+ if (write) {
+ while (size) {
+ dhdpcie_bus_wtcm8(bus, address, *data);
+ /* Adjust for next transfer (if any) */
+ if ((size -= dsize)) {
+ data += dsize;
+ address += dsize;
+ }
+ }
+ } else {
+ while (size) {
+ data[i] = dhdpcie_bus_rtcm8(bus, address);
+ /* Adjust for next transfer (if any) */
+ if ((size -= dsize)) {
+ i++;
+ address += dsize;
+ }
+ }
+ }
+ return bcmerror;
+}
+
+/* Send a data frame to the dongle. Callee disposes of txp. */
+int BCMFASTPATH
+dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx)
+{
+ return dhd_prot_txdata(bus->dhd, txp, ifidx);
+}
+
+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;
+}
+
+void
+dhd_bus_update_retlen(dhd_bus_t *bus, uint32 retlen, uint32 pkt_id, uint32 status,
+ uint32 inline_data)
+{
+ bus->rxlen = retlen;
+ bus->ioct_resp.pkt_id = pkt_id;
+ bus->ioct_resp.status = status;
+ bus->ioct_resp.inline_data = inline_data;
+}
+
+#if defined(DHD_DEBUG)
+/* 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;
+
+ /* Exclusive bus access */
+ dhd_os_sdlock(bus->dhd);
+
+ /* Don't allow input if dongle is in reset */
+ if (bus->dhd->dongle_reset) {
+ dhd_os_sdunlock(bus->dhd);
+ return BCME_NOTREADY;
+ }
+
+ /* Zero cbuf_index */
+ addr = bus->console_addr + OFFSETOF(hndrte_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(hndrte_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(hndrte_cons_t, vcons_in);
+ val = htol32(msglen);
+ if ((rv = dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
+ goto done;
+
+ dhd_post_dummy_msg(bus->dhd);
+done:
+
+ dhd_os_sdunlock(bus->dhd);
+
+ return rv;
+}
+#endif /* defined(DHD_DEBUG) */
+
+/* Process rx frame , Send up the layer to netif */
+void
+dhd_bus_rx_frame(struct dhd_bus *bus, void* pkt, int ifidx, uint pkt_count)
+{
+ dhd_os_sdunlock(bus->dhd);
+ dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, 0);
+ dhd_os_sdlock(bus->dhd);
+}
+
+/** 'offset' is a backplane address */
+void
+dhdpcie_bus_wtcm8(dhd_bus_t *bus, ulong offset, uint8 data)
+{
+ *(volatile uint8 *)(bus->tcm + offset) = (uint8)data;
+}
+
+uint8
+dhdpcie_bus_rtcm8(dhd_bus_t *bus, ulong offset)
+{
+ volatile uint8 data = *(volatile uint8 *)(bus->tcm + offset);
+ return data;
+}
+
+void
+dhdpcie_bus_wtcm32(dhd_bus_t *bus, ulong offset, uint32 data)
+{
+ *(volatile uint32 *)(bus->tcm + offset) = (uint32)data;
+}
+void
+dhdpcie_bus_wtcm16(dhd_bus_t *bus, ulong offset, uint16 data)
+{
+ *(volatile uint16 *)(bus->tcm + offset) = (uint16)data;
+}
+
+uint16
+dhdpcie_bus_rtcm16(dhd_bus_t *bus, ulong offset)
+{
+ volatile uint16 data = *(volatile uint16 *)(bus->tcm + offset);
+ return data;
+}
+
+uint32
+dhdpcie_bus_rtcm32(dhd_bus_t *bus, ulong offset)
+{
+ volatile uint32 data = *(volatile uint32 *)(bus->tcm + offset);
+ return data;
+}
+
+void
+dhd_bus_cmn_writeshared(dhd_bus_t *bus, void * data, uint32 len, uint8 type)
+{
+ uint64 long_data;
+ ulong tcm_offset;
+
+ DHD_INFO(("%s: writing to msgbuf type %d, len %d\n", __FUNCTION__, type, len));
+
+ switch (type) {
+ case DNGL_TO_HOST_BUF_ADDR :
+ long_data = HTOL64(*(uint64 *)data);
+ tcm_offset = bus->d2h_data_ring_mem_addr;
+ tcm_offset += OFFSETOF(ring_mem_t, base_addr);
+ dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len);
+ prhex(__FUNCTION__, data, len);
+ break;
+ case HOST_TO_DNGL_BUF_ADDR :
+ long_data = HTOL64(*(uint64 *)data);
+ tcm_offset = bus->h2d_data_ring_mem_addr;
+ tcm_offset += OFFSETOF(ring_mem_t, base_addr);
+ dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len);
+ prhex(__FUNCTION__, data, len);
+ break;
+ case HOST_TO_DNGL_WPTR :
+ tcm_offset = bus->h2d_data_ring_state_addr;
+ tcm_offset += OFFSETOF(ring_state_t, w_offset);
+ dhdpcie_bus_wtcm32(bus, tcm_offset, (uint32) HTOL32(*(uint32 *)data));
+ break;
+ case DNGL_TO_HOST_RPTR :
+ tcm_offset = bus->d2h_data_ring_state_addr;
+ tcm_offset += OFFSETOF(ring_state_t, r_offset);
+ dhdpcie_bus_wtcm16(bus, tcm_offset, (uint16) HTOL16(*(uint16 *)data));
+ break;
+ case HOST_TO_DNGL_CTRLBUF_ADDR:
+ long_data = HTOL64(*(uint64 *)data);
+ tcm_offset = bus->h2d_ctrl_ring_mem_addr;
+ tcm_offset += OFFSETOF(ring_mem_t, base_addr);
+ dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8 *) &long_data, len);
+ break;
+ case DNGL_TO_HOST_CTRLBUF_ADDR:
+ long_data = HTOL64(*(uint64 *)data);
+ tcm_offset = bus->d2h_ctrl_ring_mem_addr;
+ tcm_offset += OFFSETOF(ring_mem_t, base_addr);
+ dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8 *) &long_data, len);
+ break;
+ case HTOD_CTRL_WPTR:
+ tcm_offset = bus->h2d_ctrl_ring_state_addr;
+ tcm_offset += OFFSETOF(ring_state_t, w_offset);
+ dhdpcie_bus_wtcm32(bus, tcm_offset, (uint32) HTOL32(*(uint32 *)data));
+ break;
+ case DTOH_CTRL_RPTR:
+ tcm_offset = bus->d2h_ctrl_ring_state_addr;
+ tcm_offset += OFFSETOF(ring_state_t, r_offset);
+ dhdpcie_bus_wtcm16(bus, tcm_offset, (uint16) HTOL16(*(uint16 *)data));
+ break;
+ case DTOH_MB_DATA:
+ dhdpcie_bus_wtcm32(bus, bus->d2h_mb_data_ptr_addr,
+ (uint32) HTOL32(*(uint32 *)data));
+ break;
+ case HTOD_MB_DATA:
+ dhdpcie_bus_wtcm32(bus, bus->h2d_mb_data_ptr_addr,
+ (uint32) HTOL32(*(uint32 *)data));
+ break;
+ default:
+ break;
+ }
+}
+
+
+void
+dhd_bus_cmn_readshared(dhd_bus_t *bus, void* data, uint8 type)
+{
+ pciedev_shared_t *sh;
+ ulong tcm_offset;
+
+ sh = (pciedev_shared_t*)bus->shared_addr;
+
+ switch (type) {
+ case HOST_TO_DNGL_RPTR :
+ tcm_offset = bus->h2d_data_ring_state_addr;
+ tcm_offset += OFFSETOF(ring_state_t, r_offset);
+ *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus, tcm_offset));
+ break;
+ case DNGL_TO_HOST_WPTR :
+ tcm_offset = bus->d2h_data_ring_state_addr;
+ tcm_offset += OFFSETOF(ring_state_t, w_offset);
+ *(uint32*)data = LTOH32(dhdpcie_bus_rtcm32(bus, tcm_offset));
+ break;
+ case TOTAL_LFRAG_PACKET_CNT :
+ *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus,
+ (ulong) &sh->total_lfrag_pkt_cnt));
+ break;
+ case HTOD_CTRL_RPTR:
+ tcm_offset = bus->h2d_ctrl_ring_state_addr;
+ tcm_offset += OFFSETOF(ring_state_t, r_offset);
+ *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus, tcm_offset));
+ break;
+ case DTOH_CTRL_WPTR:
+ tcm_offset = bus->d2h_ctrl_ring_state_addr;
+ tcm_offset += OFFSETOF(ring_state_t, w_offset);
+ *(uint32*)data = LTOH32(dhdpcie_bus_rtcm32(bus, tcm_offset));
+ break;
+ case HTOD_MB_DATA:
+ *(uint32*)data = LTOH32(dhdpcie_bus_rtcm32(bus, bus->h2d_mb_data_ptr_addr));
+ break;
+ case DTOH_MB_DATA:
+ *(uint32*)data = LTOH32(dhdpcie_bus_rtcm32(bus, bus->d2h_mb_data_ptr_addr));
+ break;
+ case MAX_HOST_RXBUFS :
+ *(uint16*)data = LTOH16(dhdpcie_bus_rtcm16(bus,
+ (ulong) &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 = 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));
+
+ 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;
+}
+
+
+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;
+
+ /* 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;
+ }
+
+ switch (actionid) {
+
+
+ case IOV_SVAL(IOV_VARS):
+ bcmerror = dhdpcie_downloadvars(bus, arg, len);
+ break;
+
+ case IOV_SVAL(IOV_PCIEREG):
+ si_corereg(bus->sih, bus->sih->buscoreidx, OFFSETOF(sbpcieregs_t, configaddr), ~0,
+ int_val);
+ si_corereg(bus->sih, bus->sih->buscoreidx, OFFSETOF(sbpcieregs_t, configdata), ~0,
+ int_val2);
+ break;
+
+ case IOV_GVAL(IOV_PCIEREG):
+ si_corereg(bus->sih, bus->sih->buscoreidx, OFFSETOF(sbpcieregs_t, configaddr), ~0,
+ int_val);
+ int_val = si_corereg(bus->sih, bus->sih->buscoreidx,
+ OFFSETOF(sbpcieregs_t, configdata), 0, 0);
+ bcopy(&int_val, arg, val_size);
+ break;
+
+ case IOV_SVAL(IOV_PCIECOREREG):
+ si_corereg(bus->sih, bus->sih->buscoreidx, int_val, ~0, int_val2);
+ break;
+
+ case IOV_GVAL(IOV_SBREG):
+ {
+ sdreg_t sdreg;
+ uint32 addr, coreidx;
+
+ bcopy(params, &sdreg, sizeof(sdreg));
+
+ addr = sdreg.offset;
+ coreidx = (addr & 0xF000) >> 12;
+
+ int_val = si_corereg(bus->sih, coreidx, (addr & 0xFFF), 0, 0);
+ bcopy(&int_val, arg, sizeof(int32));
+ break;
+ }
+
+ case IOV_SVAL(IOV_SBREG):
+ {
+ sdreg_t sdreg;
+ uint32 addr, coreidx;
+
+ bcopy(params, &sdreg, sizeof(sdreg));
+
+ addr = sdreg.offset;
+ coreidx = (addr & 0xF000) >> 12;
+
+ si_corereg(bus->sih, coreidx, (addr & 0xFFF), ~0, sdreg.value);
+
+ break;
+ }
+
+
+ case IOV_GVAL(IOV_PCIECOREREG):
+ int_val = si_corereg(bus->sih, bus->sih->buscoreidx, int_val, 0, 0);
+ bcopy(&int_val, arg, val_size);
+ break;
+
+ case IOV_SVAL(IOV_PCIECFGREG):
+ OSL_PCI_WRITE_CONFIG(bus->osh, int_val, 4, int_val2);
+ break;
+
+ case IOV_GVAL(IOV_PCIECFGREG):
+ int_val = OSL_PCI_READ_CONFIG(bus->osh, int_val, 4);
+ bcopy(&int_val, arg, val_size);
+ break;
+
+ case IOV_SVAL(IOV_PCIE_LPBK):
+ bcmerror = dhdpcie_bus_lpback_req(bus, int_val);
+ break;
+
+ case IOV_GVAL(IOV_MEMSIZE):
+ int_val = (int32)bus->ramsize;
+ bcopy(&int_val, arg, val_size);
+ break;
+ case IOV_SVAL(IOV_MEMBYTES):
+ case IOV_GVAL(IOV_MEMBYTES):
+ {
+ uint32 address; /* absolute backplane address */
+ uint size, dsize;
+ uint8 *data;
+
+ bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
+
+ ASSERT(plen >= 2*sizeof(int));
+
+ address = (uint32)int_val;
+ 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) {
+ DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
+ __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
+ bcmerror = BCME_BADARG;
+ break;
+ }
+
+ DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n dsize %d ", __FUNCTION__,
+ (set ? "write" : "read"), size, address, dsize));
+
+ /* 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 (set && address == bus->dongle_ram_base) {
+ bus->resetinstr = *(((uint32*)params) + 2);
+ }
+ } else {
+ /* If we know about SOCRAM, check for a fit */
+ if ((bus->orig_ramsize) &&
+ ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
+ {
+ uint8 enable, protect, remap;
+ si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
+ if (!enable || protect) {
+ DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
+ __FUNCTION__, bus->orig_ramsize, size, address));
+ DHD_ERROR(("%s: socram enable %d, protect %d\n",
+ __FUNCTION__, enable, protect));
+ bcmerror = BCME_BADARG;
+ break;
+ }
+
+ if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) {
+ uint32 devramsize = si_socdevram_size(bus->sih);
+ if ((address < SOCDEVRAM_ARM_ADDR) ||
+ (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) {
+ DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
+ __FUNCTION__, address, size));
+ DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
+ __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize));
+ bcmerror = BCME_BADARG;
+ break;
+ }
+ /* move it such that address is real now */
+ address -= SOCDEVRAM_ARM_ADDR;
+ address += SOCDEVRAM_BP_ADDR;
+ DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
+ __FUNCTION__, (set ? "write" : "read"), size, address));
+ } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) {
+ /* Can not access remap region while devram remap bit is set
+ * ROM content would be returned in this case
+ */
+ DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n",
+ __FUNCTION__, address));
+ bcmerror = BCME_ERROR;
+ break;
+ }
+ }
+ }
+
+ /* Generate the actual data pointer */
+ data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
+
+ /* Call to do the transfer */
+ bcmerror = dhdpcie_bus_membytes(bus, set, address, data, size);
+
+ break;
+ }
+
+ 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_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;
+
+ default:
+ bcmerror = BCME_UNSUPPORTED;
+ break;
+ }
+
+exit:
+
+
+ dhd_os_sdunlock(bus->dhd);
+
+ return bcmerror;
+}
+/* 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(("bus not inited\n"));
+ return 0;
+ }
+ if (bus->dhd->prot == NULL) {
+ DHD_ERROR(("prot is not inited\n"));
+ return 0;
+ }
+ if (bus->dhd->busstate != DHD_BUS_DATA) {
+ DHD_ERROR(("not in a readystate to LPBK is not inited\n"));
+ return 0;
+ }
+ dhdmsgbuf_lpbk_req(bus->dhd, len);
+ return 0;
+}
+
+
+
+static int
+dhdpcie_bus_download_state(dhd_bus_t *bus, bool enter)
+{
+ int bcmerror = 0;
+ uint32 *cr4_regs;
+
+ 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;
+
+ /* 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))) {
+ DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
+ bcmerror = BCME_ERROR;
+ goto fail;
+ }
+
+ 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 (bus->sih->chip == BCM43602_CHIP_ID) {
+ 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, 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 (bus->sih->chip == BCM43602_CHIP_ID) {
+ /* 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;
+ }
+
+
+ /* 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));
+
+ /* 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;
+}
+
+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(("Compare NVRAM dl & ul; varsize=%d\n", 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(("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;
+ bus->nvram_csm = varsizew;
+ } else {
+ varsizew = varsize / 4;
+ varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
+ bus->nvram_csm = varsizew;
+ 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 = dhdpcie_bus_membytes(bus, TRUE, (phys_size - 4),
+ (uint8*)&varsizew, 4);
+
+ return bcmerror;
+}
+
+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);
+err:
+ return bcmerror;
+}
+
+/* Add bus dump output to a buffer */
+void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
+{
+
+}
+
+/* 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(("mailbox communication not supported\n"));
+ return;
+ }
+ /* this is a pcie core register, not the config regsiter */
+ DHD_INFO(("writing a mail box interrupt to the device, through config space\n"));
+ dhdpcie_bus_cfg_write_dword(bus, PCISBMbx, 4, (1 << 0));
+}
+
+/* doorbell ring Function */
+void
+dhd_bus_ringbell(struct dhd_bus *bus, uint32 value)
+{
+ 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(("writing a door bell to the device\n"));
+ si_corereg(bus->sih, bus->sih->buscoreidx, PCIH2D_MailBox, ~0, 0x12345678);
+ }
+}
+
+static void
+dhd_bus_ringbell_fast(struct dhd_bus *bus, uint32 value)
+{
+ W_REG(bus->pcie_mb_intr_osh, bus->pcie_mb_intr_addr, value);
+}
+
+static void
+dhd_bus_ringbell_oldpcie(struct dhd_bus *bus, uint32 value)
+{
+ uint32 w;
+ 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 dhd_bus_ringbell_fast;
+ }
+ }
+ return dhd_bus_ringbell;
+}
+
+bool BCMFASTPATH
+dhd_bus_dpc(struct dhd_bus *bus)
+{
+ uint32 intstatus = 0;
+ uint32 newstatus = 0;
+ bool resched = FALSE; /* Flag indicating resched wanted */
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ if (bus->dhd->busstate == DHD_BUS_DOWN) {
+ DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
+ bus->intstatus = 0;
+ return 0;
+ }
+
+#ifndef DHD_ALLIRQ
+ dhd_os_sdlock(bus->dhd);
+#endif /* DHD_ALLIRQ */
+ intstatus = bus->intstatus;
+
+ if ((bus->sih->buscorerev == 6) || (bus->sih->buscorerev == 4) ||
+ (bus->sih->buscorerev == 2)) {
+ newstatus = dhdpcie_bus_cfg_read_dword(bus, PCIIntstatus, 4);
+ dhdpcie_bus_cfg_write_dword(bus, PCIIntstatus, 4, newstatus);
+ /* Merge new bits with previous */
+ intstatus |= newstatus;
+ bus->intstatus = 0;
+ if (intstatus & I_MB) {
+ dhdpcie_bus_process_mailbox_intr(bus, intstatus);
+ }
+ } else {
+ /* this is a PCIE core register..not a config register... */
+ newstatus = si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, 0, 0);
+ intstatus |= (newstatus & bus->def_intmask);
+ si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxInt, intstatus, intstatus);
+ if (intstatus & bus->def_intmask) {
+ dhdpcie_bus_process_mailbox_intr(bus, intstatus);
+ intstatus &= ~bus->def_intmask;
+ }
+ }
+
+ dhdpcie_bus_intr_enable(bus);
+#ifndef DHD_ALLIRQ
+ dhd_os_sdunlock(bus->dhd);
+#endif /* DHD_ALLIRQ */
+ return resched;
+
+}
+
+
+static void
+dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data)
+{
+ uint32 cur_h2d_mb_data = 0;
+
+ dhd_bus_cmn_readshared(bus, &cur_h2d_mb_data, HTOD_MB_DATA);
+
+ if (cur_h2d_mb_data != 0) {
+ uint32 i = 0;
+ DHD_INFO(("GRRRRRRR: MB transaction is already pending 0x%04x\n", cur_h2d_mb_data));
+ while ((i++ < 100) && cur_h2d_mb_data) {
+ OSL_DELAY(10);
+ dhd_bus_cmn_readshared(bus, &cur_h2d_mb_data, HTOD_MB_DATA);
+ }
+ if (i >= 100)
+ DHD_ERROR(("waited 1ms for the dngl to ack the previous mb transaction\n"));
+ }
+
+ dhd_bus_cmn_writeshared(bus, &h2d_mb_data, sizeof(uint32), HTOD_MB_DATA);
+ dhd_bus_gen_devmb_intr(bus);
+}
+
+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, DTOH_MB_DATA);
+ if (!d2h_mb_data)
+ return;
+
+ dhd_bus_cmn_writeshared(bus, &zero, sizeof(uint32), DTOH_MB_DATA);
+
+ DHD_INFO(("D2H_MB_DATA: 0x%04x\n", d2h_mb_data));
+ if (d2h_mb_data & D2H_DEV_DS_ENTER_REQ) {
+ /* what should we do */
+ DHD_INFO(("D2H_MB_DATA: DEEP SLEEP REQ\n"));
+ dhdpcie_send_mb_data(bus, H2D_HOST_DS_ACK);
+ DHD_INFO(("D2H_MB_DATA: sent DEEP SLEEP ACK\n"));
+ }
+ if (d2h_mb_data & D2H_DEV_DS_EXIT_NOTE) {
+ /* what should we do */
+ DHD_INFO(("D2H_MB_DATA: DEEP SLEEP EXIT\n"));
+ }
+ if (d2h_mb_data & D2H_DEV_D3_ACK) {
+ /* what should we do */
+ DHD_INFO(("D2H_MB_DATA: D3 ACK\n"));
+ }
+}
+
+static void
+dhdpcie_bus_process_mailbox_intr(dhd_bus_t *bus, uint32 intstatus)
+{
+
+ if ((bus->sih->buscorerev == 2) || (bus->sih->buscorerev == 6) ||
+ (bus->sih->buscorerev == 4)) {
+ /* Msg stream interrupt */
+ if (intstatus & I_BIT1) {
+ 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))
+ dhdpcie_handle_mb_data(bus);
+ if (intstatus & PCIE_MB_D2H_MB_MASK)
+ dhdpci_bus_read_frames(bus);
+ }
+
+}
+
+/* Decode dongle to host message stream */
+static void
+dhdpci_bus_read_frames(dhd_bus_t *bus)
+{
+ /* There may be frames in both ctrl buf and data buf; check ctrl buf first */
+ if (dhd_prot_dtohsplit(bus->dhd))
+ dhd_prot_process_ctrlbuf(bus->dhd);
+ dhd_prot_process_msgbuf(bus->dhd);
+}
+
+static int
+dhdpcie_readshared(dhd_bus_t *bus)
+{
+ uint32 addr = 0;
+ int rv;
+ 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 sdpcm_shared structure */
+ if ((rv = dhdpcie_bus_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0)
+ return rv;
+
+ addr = ltoh32(addr);
+ }
+
+ if ((addr == 0) || (addr == bus->nvram_csm)) {
+ DHD_ERROR(("%s: address (0x%08x) of pciedev_shared invalid\n",
+ __FUNCTION__, addr));
+ DHD_ERROR(("Waited %u usec, dongle is not ready\n", tmo.elapsed));
+ return BCME_ERROR;
+ } else {
+ bus->shared_addr = (ulong)addr;
+ DHD_ERROR(("PCIe shared addr read took %u usec "
+ "before dongle is ready\n", tmo.elapsed));
+ }
+
+ /* 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,"
+ "size read %d < %d\n", rv, (int)sizeof(pciedev_shared_t)));
+ 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);
+ /* load bus console address */
+
+#ifdef DHD_DEBUG
+ bus->console_addr = sh->console_addr;
+#endif
+
+ /* Read the dma rx offset */
+ bus->dma_rxoffset = bus->pcie_sh->dma_rxoffset;
+ dhd_prot_rx_dataoffset(bus->dhd, bus->dma_rxoffset);
+
+ DHD_ERROR(("DMA RX offset from shared Area %d\n", bus->dma_rxoffset));
+
+ if ((sh->flags & PCIE_SHARED_VERSION_MASK) > 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,
+ sh->flags & PCIE_SHARED_VERSION_MASK));
+ return BCME_ERROR;
+ }
+ /* get ring_info, ring_state and mb data ptrs and store the addresses in bus structure */
+ {
+ ring_info_t ring_info;
+ uint32 tcm_rmem_loc;
+ uint32 tcm_rstate_loc;
+
+ if ((rv = dhdpcie_bus_membytes(bus, FALSE, sh->rings_info_ptr,
+ (uint8 *)&ring_info, sizeof(ring_info_t))) < 0)
+ return rv;
+ bus->h2d_ring_count = ring_info.h2d_ring_count;
+ bus->d2h_ring_count = ring_info.d2h_ring_count;
+
+ bus->h2d_mb_data_ptr_addr = ltoh32(sh->h2d_mb_data_ptr);
+ bus->d2h_mb_data_ptr_addr = ltoh32(sh->d2h_mb_data_ptr);
+
+ bus->ringmem_ptr = ltoh32(ring_info.ringmem_ptr);
+ bus->ring_state_ptr = ltoh32(ring_info.ring_state_ptr);
+
+ bcm_print_bytes("ring_info_raw", (uchar *)&ring_info, sizeof(ring_info_t));
+ DHD_INFO(("ring_info\n"));
+ DHD_INFO(("h2d_ring_count %d\n", bus->h2d_ring_count));
+ DHD_INFO(("d2h_ring_count %d\n", bus->d2h_ring_count));
+ DHD_INFO(("ringmem_ptr 0x%04x\n", bus->ringmem_ptr));
+ DHD_INFO(("ringstate_ptr 0x%04x\n", bus->ring_state_ptr));
+
+ tcm_rmem_loc = bus->ringmem_ptr;
+ tcm_rstate_loc = bus->ring_state_ptr;
+
+ if (bus->h2d_ring_count > 1) {
+ bus->h2d_ctrl_ring_mem_addr = tcm_rmem_loc;
+ tcm_rmem_loc += sizeof(ring_mem_t);
+ bus->h2d_ctrl_ring_state_addr = tcm_rstate_loc;
+ tcm_rstate_loc += sizeof(ring_state_t);
+ }
+ bus->h2d_data_ring_mem_addr = tcm_rmem_loc;
+ tcm_rmem_loc += sizeof(ring_mem_t);
+ bus->h2d_data_ring_state_addr = tcm_rstate_loc;
+ tcm_rstate_loc += sizeof(ring_state_t);
+
+ if (bus->d2h_ring_count > 1) {
+ bus->d2h_ctrl_ring_mem_addr = tcm_rmem_loc;
+ tcm_rmem_loc += sizeof(ring_mem_t);
+ bus->d2h_ctrl_ring_state_addr = tcm_rstate_loc;
+ tcm_rstate_loc += sizeof(ring_state_t);
+ }
+ bus->d2h_data_ring_mem_addr = tcm_rmem_loc;
+ bus->d2h_data_ring_state_addr = tcm_rstate_loc;
+
+ DHD_INFO(("ring_mem\n"));
+ DHD_INFO(("h2d_data_ring_mem 0x%04x\n", bus->h2d_data_ring_mem_addr));
+ DHD_INFO(("h2d_ctrl_ring_mem 0x%04x\n", bus->h2d_ctrl_ring_mem_addr));
+ DHD_INFO(("d2h_data_ring_mem 0x%04x\n", bus->d2h_data_ring_mem_addr));
+ DHD_INFO(("d2h_ctrl_ring_mem 0x%04x\n", bus->d2h_ctrl_ring_mem_addr));
+
+ DHD_INFO(("ring_state\n"));
+ DHD_INFO(("h2d_data_ring_state 0x%04x\n", bus->h2d_data_ring_state_addr));
+ DHD_INFO(("h2d_ctrl_ring_state 0x%04x\n", bus->h2d_ctrl_ring_state_addr));
+ DHD_INFO(("d2h_data_ring_state 0x%04x\n", bus->d2h_data_ring_state_addr));
+ DHD_INFO(("d2h_ctrl_ring_state 0x%04x\n", bus->d2h_ctrl_ring_state_addr));
+
+ DHD_INFO(("mail box address\n"));
+ DHD_INFO(("h2d_mb_data_ptr_addr 0x%04x\n", bus->h2d_mb_data_ptr_addr));
+ DHD_INFO(("d2h_mb_data_ptr_addr 0x%04x\n", bus->d2h_mb_data_ptr_addr));
+ }
+ return BCME_OK;
+}
+
+
+/* Initialize bus module: prepare for communication w/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;
+
+ if (enforce_mutex)
+ dhd_os_sdlock(bus->dhd);
+
+ /* 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;
+
+ /* Enable the interrupt after device is up */
+ dhdpcie_bus_intr_enable(bus);
+
+ /* bcmsdh_intr_unmask(bus->sdh); */
+
+ if (enforce_mutex)
+ dhd_os_sdunlock(bus->dhd);
+
+ 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;
+ dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val));
+}
+
+
+bool
+dhdpcie_chipmatch(uint16 vendor, uint16 device)
+{
+ if (vendor != PCI_VENDOR_ID_BROADCOM) {
+ DHD_ERROR(("%s: Unsupported vendor %x device %x\n", __FUNCTION__,
+ vendor, device));
+ return (-ENODEV);
+ }
+
+ if ((device == BCM4350_D11AC_ID) || (device == BCM4350_D11AC2G_ID) ||
+ (device == BCM4350_D11AC5G_ID) || BCM4350_CHIP(device))
+ return 0;
+
+ if ((device == BCM4354_D11AC_ID) || (device == BCM4354_D11AC2G_ID) ||
+ (device == BCM4354_D11AC5G_ID) || (device == BCM4354_CHIP_ID))
+ return 0;
+
+ if ((device == BCM4345_D11AC_ID) || (device == BCM4345_D11AC2G_ID) ||
+ (device == BCM4345_D11AC5G_ID) || (device == BCM4345_CHIP_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;
+
+
+ DHD_ERROR(("%s: Unsupported vendor %x device %x\n", __FUNCTION__, vendor, device));
+ return (-ENODEV);
+}
+
+
+/*
+
+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);
+ 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) &&
+ ((uint16)bus->sih->chip != BCM4345_CHIP_ID)) {
+ DHD_ERROR(("%s: cc_nvmdump cmd. supported for 4350/4345 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 */
+ 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 */
+ 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__));
+ }
+ }
+
+ if (((chipcregs->sromcontrol & SRC_PRESENT) == 0) &&
+ ((chipcregs->capabilities & CC_CAP_OTPSIZE) == 0)) {
+ DHD_ERROR(("%s: SPROM and OTP could not be found \n",
+ __FUNCTION__));
+ return BCME_NOTFOUND;
+ }
+
+ /* Check the strapping option in SpromCtrl: Set = OTP otherwise SPROM */
+ if ((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:");
+
+ /* Point to the SPROM/OTP shadow in ChipCommon */
+ nvm_shadow = chipcregs->sromotp;
+
+ /*
+ * 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;
+}
diff --git a/drivers/net/wireless/bcmdhd/dhd_pcie.h b/drivers/net/wireless/bcmdhd/dhd_pcie.h
new file mode 100644
index 000000000000..d51a53d38a1a
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_pcie.h
@@ -0,0 +1,169 @@
+/*
+ * Linux DHD Bus Module for PCIE
+ *
+ * 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: dhd_pcie.h 452261 2014-01-29 19:30:23Z $
+ */
+
+
+#ifndef dhd_pcie_h
+#define dhd_pcie_h
+
+#include <bcmpcie.h>
+
+/* defines */
+
+#define PCMSGBUF_HDRLEN 20
+#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)))
+
+
+/* user defined data structures */
+#ifdef DHD_DEBUG
+/* Device console log buffer state */
+#define CONSOLE_LINE_MAX 192
+#define CONSOLE_BUFFER_MAX 2024
+
+
+typedef struct dhd_console {
+ uint count; /* Poll interval msec counter */
+ uint log_addr; /* Log struct address (fixed) */
+ hndrte_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;
+#endif /* DHD_DEBUG */
+
+typedef struct dhd_bus {
+ dhd_pub_t *dhd;
+ struct pci_dev *dev; /* pci device handle */
+ 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) */
+ 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 */
+ const char *nvram_params; /* user specified nvram params. */
+
+ struct pktq txq; /* Queue length used for flow-control */
+
+ uint rxlen; /* Length of valid data in buffer */
+
+
+ bool intr; /* Use interrupts */
+ 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 */
+
+#ifdef DHD_DEBUG
+ dhd_console_t console; /* Console output polling support */
+ uint console_addr; /* Console address from shared struct */
+#endif /* DHD_DEBUG */
+
+ 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;
+ ioct_resp_hdr_t ioct_resp;
+ 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;
+
+ uint32 *pcie_mb_intr_addr;
+ void *pcie_mb_intr_osh;
+ bool sleep_allowed;
+
+ /* version 3 shared struct related info start */
+ uint8 h2d_ring_count;
+ uint8 d2h_ring_count;
+ uint32 ringmem_ptr;
+ uint32 ring_state_ptr;
+
+ uint32 h2d_data_ring_mem_addr;
+ uint32 h2d_ctrl_ring_mem_addr;
+ uint32 h2d_data_ring_state_addr;
+ uint32 h2d_ctrl_ring_state_addr;
+
+ uint32 d2h_data_ring_mem_addr;
+ uint32 d2h_ctrl_ring_mem_addr;
+ uint32 d2h_data_ring_state_addr;
+ uint32 d2h_ctrl_ring_state_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;
+
+} 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);
+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_disable(struct dhd_bus *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);
+#endif /* dhd_pcie_h */
diff --git a/drivers/net/wireless/bcmdhd/dhd_pcie_linux.c b/drivers/net/wireless/bcmdhd/dhd_pcie_linux.c
new file mode 100644
index 000000000000..85539ae27218
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_pcie_linux.c
@@ -0,0 +1,503 @@
+/*
+ * Linux DHD Bus Module for PCIE
+ *
+ * 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: dhd_pcie_linux.c 452261 2014-01-29 19:30:23Z $
+ */
+
+
+/* include files */
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <bcmdevs.h>
+#include <siutils.h>
+#include <hndsoc.h>
+#include <hndpmu.h>
+#include <sbchipc.h>
+#if defined(DHD_DEBUG)
+#include <hndrte_armtrap.h>
+#include <hndrte_cons.h>
+#endif /* defined(DHD_DEBUG) */
+#include <dngl_stats.h>
+#include <pcie_core.h>
+#include <dhd.h>
+#include <dhd_bus.h>
+#include <dhd_proto.h>
+#include <dhd_dbg.h>
+#include <dhdioctl.h>
+#include <bcmmsgbuf.h>
+#include <pcicfg.h>
+#include <circularbuf.h>
+#include <dhd_pcie.h>
+
+
+#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)
+
+
+/* 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;
+
+} dhdpcie_info_t;
+
+
+struct pcos_info {
+ dhdpcie_info_t *pc;
+ spinlock_t lock;
+ wait_queue_head_t intr_wait_queue;
+ struct timer_list tuning_timer;
+ int tuning_timer_exp;
+ atomic_t timer_enab;
+ struct tasklet_struct tuning_tasklet;
+};
+
+
+/* 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);
+static int dhdpcie_pci_suspend(struct pci_dev *dev);
+static int dhdpcie_pci_resume(struct pci_dev *dev);
+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, }
+};
+MODULE_DEVICE_TABLE(pci, dhdpcie_pci_devid);
+
+static struct pci_driver 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
+ suspend: NULL,
+ resume: NULL,
+};
+
+static int dhdpcie_pci_suspend(struct pci_dev *dev)
+{
+ int ret;
+ pci_save_state(dev);
+ pci_enable_wake(dev, PCI_D0, TRUE);
+ pci_disable_device(dev);
+ ret = pci_set_power_state(dev, PCI_D3hot);
+ return ret;
+}
+
+static int dhdpcie_pci_resume(struct pci_dev *dev)
+{
+ int err = 0;
+ uint32 val;
+ pci_restore_state(dev);
+ err = pci_enable_device(dev);
+ if (err) {
+ printf("%s:pci_enable_device error %d \n", __FUNCTION__, err);
+ return err;
+ }
+ pci_set_master(dev);
+ /*
+ * Suspend/Resume resets the PCI configuration space, so we have to
+ * re-disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state
+ * Code taken from ipw2100 driver
+ */
+ err = pci_set_power_state(dev, PCI_D0);
+ if (err) {
+ printf("%s:pci_set_power_state error %d \n", __FUNCTION__, err);
+ return err;
+ }
+ pci_read_config_dword(dev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(dev, 0x40, val & 0xffff00ff);
+ return err;
+}
+
+int dhdpcie_pci_suspend_resume(struct pci_dev *dev, bool state)
+{
+ int rc;
+
+ if (state)
+ rc = dhdpcie_pci_suspend(dev);
+ else
+ rc = dhdpcie_pci_resume(dev);
+ return rc;
+}
+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;
+#else
+ if (!(error = pci_register_driver(&dhdpcie_driver)))
+ return 0;
+#endif
+
+ DHD_ERROR(("%s: pci_module_init failed 0x%x\n", __FUNCTION__, error));
+
+ 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)
+{
+
+ if (dhdpcie_chipmatch (pdev->vendor, pdev->device)) {
+ DHD_ERROR(("%s: chipmatch failed!!\n", __FUNCTION__));
+ return -ENODEV;
+ }
+ 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__));
+ return -ENODEV;
+ }
+
+ DHD_TRACE(("%s: PCIe Enumeration done!!\n", __FUNCTION__));
+ return 0;
+}
+
+int
+dhdpcie_detach(dhdpcie_info_t *pch)
+{
+ osl_t *osh = pch->osh;
+ if (pch) {
+ MFREE(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__));
+ pch = pci_get_drvdata(pdev);
+ bus = pch->bus;
+
+ dhdpcie_bus_release(bus);
+ pci_disable_device(pdev);
+ /* pcie info detach */
+ dhdpcie_detach(pch);
+ /* osl detach */
+ osl_detach(osh);
+
+
+ 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;
+
+ if (request_irq(pdev->irq, dhdpcie_isr, IRQF_SHARED, "dhdpcie", bus) < 0) {
+ DHD_ERROR(("%s: request_irq() failed\n", __FUNCTION__));
+ return -1;
+ }
+
+ 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;
+ 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 = (volatile char *) REG_MAP(bar1_addr, DONGLE_TCM_MAP_SIZE);
+ dhdpcie_info->tcm_size = DONGLE_TCM_MAP_SIZE;
+
+ if (!dhdpcie_info->regs || !dhdpcie_info->tcm) {
+ DHD_ERROR(("%s:ioremap() failed\n", __FUNCTION__));
+ break;
+ }
+ 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 */
+
+}
+
+int dhdpcie_init(struct pci_dev *pdev)
+{
+
+ osl_t *osh = NULL;
+ dhd_bus_t *bus = NULL;
+ dhdpcie_info_t *dhdpcie_info = NULL;
+
+ do {
+ /* osl attach */
+ if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
+ DHD_ERROR(("%s: osl_attach failed\n", __FUNCTION__));
+ break;
+ }
+
+ /* 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;
+
+ /* 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);
+ if (!bus) {
+ DHD_ERROR(("%s:dhdpcie_bus_attach() failed\n", __FUNCTION__));
+ break;
+ }
+
+ dhdpcie_info->bus = bus;
+ dhdpcie_info->bus->dev = pdev;
+
+ 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 (dhd_download_fw_on_driverload)
+ if (dhd_bus_start(bus->dhd))
+ break;
+
+ /* set private data for pci_dev */
+ pci_set_drvdata(pdev, dhdpcie_info);
+
+ 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);
+
+ if (dhdpcie_info)
+ dhdpcie_detach(dhdpcie_info);
+ pci_disable_device(pdev);
+ if (osh)
+ osl_detach(osh);
+
+ 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;
+ free_irq(pdev->irq, bus);
+ }
+ 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;
+}
diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.c b/drivers/net/wireless/bcmdhd/dhd_pno.c
new file mode 100644
index 000000000000..e1d56e0a566e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_pno.c
@@ -0,0 +1,1899 @@
+/*
+ * Broadcom Dongle Host Driver (DHD)
+ * Prefered Network Offload and Wi-Fi Location Service(WLS) code.
+ *
+ * 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: dhd_pno.c 423669 2013-09-18 13:01:55Z yangj$
+ */
+#ifdef PNO_SUPPORT
+#include <typedefs.h>
+#include <osl.h>
+
+#include <epivers.h>
+#include <bcmutils.h>
+
+#include <bcmendian.h>
+#include <linuxver.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/sort.h>
+#include <dngl_stats.h>
+#include <wlioctl.h>
+
+#include <proto/bcmevent.h>
+#include <dhd.h>
+#include <dhd_pno.h>
+#include <dhd_dbg.h>
+
+#ifdef __BIG_ENDIAN
+#include <bcmendian.h>
+#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 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 ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====")
+#define TIME_MIN_DIFF 5
+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), 1);
+ 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, 1);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to execute pfnclear(error : %d)\n",
+ __FUNCTION__, err));
+ }
+exit:
+ return err;
+}
+
+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), 1);
+ 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), 1);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to execute pfn_set\n", __FUNCTION__));
+ 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;
+ }
+ }
+ 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(30);
+ /* 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;
+ }
+ }
+ }
+ 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;
+ }
+ if (mode == DHD_PNO_BATCH_MODE) {
+ 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), 1);
+ 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", (char *)&_tmp, sizeof(_tmp), 0);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to get pfnmem\n", __FUNCTION__));
+ goto exit;
+ }
+ DHD_PNO((" returned mscan : %d, set bestn : %d\n", _tmp, pfn_param.bestn));
+ pfn_param.mscan = MIN(pfn_param.mscan, _tmp);
+ }
+ err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), 1);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to execute pfn_set\n", __FUNCTION__));
+ 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, wlc_ssid_t* ssids_list, int nssid)
+{
+ int err = BCME_OK;
+ int i = 0;
+ wl_pfn_t pfn_element;
+ NULL_CHECK(dhd, "dhd is NULL", err);
+ if (nssid) {
+ NULL_CHECK(ssids_list, "ssid list is NULL", err);
+ }
+ memset(&pfn_element, 0, sizeof(pfn_element));
+ {
+ int j;
+ for (j = 0; j < nssid; j++) {
+ DHD_PNO(("%d: scan for %s size = %d\n", j,
+ ssids_list[j].SSID, ssids_list[j].SSID_len));
+ }
+ }
+ /* Check for broadcast ssid */
+ for (i = 0; i < nssid; i++) {
+ if (!ssids_list[i].SSID_len) {
+ DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", i));
+ err = BCME_ERROR;
+ goto exit;
+ }
+ }
+ /* set all pfn ssid */
+ for (i = 0; i < nssid; i++) {
+ pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE);
+ pfn_element.auth = (DOT11_OPEN_SYSTEM);
+ pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY);
+ pfn_element.wsec = htod32(0);
+ pfn_element.infra = htod32(1);
+ pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT);
+ memcpy((char *)pfn_element.ssid.SSID, ssids_list[i].SSID,
+ ssids_list[i].SSID_len);
+ pfn_element.ssid.SSID_len = ssids_list[i].SSID_len;
+ err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_element,
+ sizeof(pfn_element), 1);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__));
+ goto exit;
+ }
+ }
+exit:
+ return err;
+}
+/* qsort compare function */
+static int
+_dhd_pno_cmpfunc(const void *a, const void *b)
+{
+ return (*(uint16*)a - *(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);
+ }
+ 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 { /* All channels */
+ if (skip_dfs && is_dfs(dtoh32(list->element[i])))
+ continue;
+ }
+ d_chan_list[j++] = dtoh32(list->element[i]);
+ }
+ *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 = sprintf(bp, "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 */
+ list_for_each_entry_safe(siter, snext,
+ &params_batch->get_batch.expired_scan_results_list, list) {
+ 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<loop : %d, apcount %d>\n", cnt - 1, phead->tot_cnt));
+ /* attribute of the scan */
+ if (phead->reason & PNO_STATUS_ABORT_MASK) {
+ bp += nreadsize = sprintf(bp, "trunc\n");
+ nleftsize -= nreadsize;
+ }
+ list_for_each_entry_safe(iter, next,
+ &phead->entry_list, list) {
+ 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 = sprintf(bp, "bssid=%s\n",
+ bcm_ether_ntoa((const struct ether_addr *)&iter->BSSID, eabuf));
+ nleftsize -= nreadsize;
+ /* SSID */
+ bp += nreadsize = sprintf(bp, "ssid=%s\n", iter->SSID);
+ nleftsize -= nreadsize;
+ /* channel */
+ bp += nreadsize = sprintf(bp, "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 = sprintf(bp, "level=%d\n", iter->RSSI);
+ nleftsize -= nreadsize;
+ /* add the time consumed in Driver to the timestamp of firmware */
+ iter->timestamp += t_delta;
+ bp += nreadsize = sprintf(bp, "age=%d\n", iter->timestamp);
+ nleftsize -= nreadsize;
+ /* RTT0 */
+ bp += nreadsize = sprintf(bp, "dist=%d\n",
+ (iter->rtt0 == 0)? -1 : iter->rtt0);
+ nleftsize -= nreadsize;
+ /* RTT1 */
+ bp += nreadsize = sprintf(bp, "distSd=%d\n",
+ (iter->rtt0 == 0)? -1 : iter->rtt1);
+ nleftsize -= nreadsize;
+ bp += nreadsize = sprintf(bp, "%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 = sprintf(bp, "%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 (list_empty(&params_batch->get_batch.expired_scan_results_list)) {
+ params_batch->get_batch.batch_started = FALSE;
+ bp += sprintf(bp, "%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__));
+ 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);
+ }
+ }
+ 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);
+ }
+ 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 && nchan < WL_NUMCHANNELS; 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), 1);
+ 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) {
+ list_for_each_entry_safe(iter, next,
+ &params->params_legacy.ssid_list, list) {
+ list_del(&iter->list);
+ kfree(iter);
+ }
+ }
+ 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,
+ &params->params_batch.get_batch.scan_results_list, FALSE);
+ _dhd_pno_clear_all_batch_results(dhd,
+ &params->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(&params->params_batch.get_batch.scan_results_list);
+ INIT_LIST_HEAD(&params->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) {
+ list_for_each_entry_safe(iter, next,
+ &params->params_hotlist.bssid_list, list) {
+ list_del(&iter->list);
+ kfree(iter);
+ }
+ }
+ 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, 1);
+ 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;
+ /* 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;
+ dhd_pno_clean(dhd);
+ /* 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 */
+ 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++;
+ }
+ 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:
+ if (p_pfn_bssid)
+ 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));
+}
+
+int
+dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_t* ssid_list, int nssid,
+ uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan)
+{
+ struct dhd_pno_ssid *_pno_ssid;
+ 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;
+ int mode = 0;
+ NULL_CHECK(dhd, "dhd is NULL", err);
+ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
+ _pno_state = PNO_GET_PNOSTATE(dhd);
+
+ if (!dhd_support_sta_mode(dhd)) {
+ err = BCME_BADOPTION;
+ goto exit;
+ }
+ DHD_PNO(("%s enter : scan_fr :%d, pno_repeat :%d,"
+ "pno_freq_expo_max: %d, nchan :%d\n", __FUNCTION__,
+ scan_fr, pno_repeat, pno_freq_expo_max, nchan));
+
+ _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]);
+ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
+ 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));
+ goto exit;
+ }
+ }
+ _pno_state->pno_mode |= DHD_PNO_LEGACY_MODE;
+ 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));
+ goto exit;
+ }
+ memset(_chan_list, 0, sizeof(_chan_list));
+ tot_nchan = nchan;
+ if (tot_nchan > 0 && channel_list) {
+ for (i = 0; i < nchan; i++)
+ _params->params_legacy.chan_list[i] = _chan_list[i] = channel_list[i];
+ }
+ 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 && nchan > 0) {
+ err = _dhd_pno_chan_merge(_chan_list, &tot_nchan,
+ &_params2->params_batch.chan_list[0],
+ _params2->params_batch.nchan,
+ &channel_list[0], 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 && nchan > 0) {
+ err = _dhd_pno_chan_merge(_chan_list, &tot_nchan,
+ &_params2->params_hotlist.chan_list[0],
+ _params2->params_hotlist.nchan,
+ &channel_list[0], 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 = nchan;
+ _params->params_legacy.nssid = nssid;
+ INIT_LIST_HEAD(&_params->params_legacy.ssid_list);
+ 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;
+ }
+ for (i = 0; i < nssid; i++) {
+ _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__));
+ goto exit;
+ }
+ _pno_ssid->SSID_len = ssid_list[i].SSID_len;
+ memcpy(_pno_ssid->SSID, ssid_list[i].SSID, _pno_ssid->SSID_len);
+ list_add_tail(&_pno_ssid->list, &_params->params_legacy.ssid_list);
+
+ }
+ 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_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;
+ int i = 0;
+ dhd_pno_params_t *_params;
+ dhd_pno_params_t *_params2;
+ dhd_pno_status_info_t *_pno_state;
+ wlc_ssid_t *p_ssid_list = NULL;
+ 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) {
+ struct dhd_pno_ssid *iter, *next;
+ 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"));
+ }
+ p_ssid_list = kzalloc(sizeof(wlc_ssid_t) *
+ _params2->params_legacy.nssid, GFP_KERNEL);
+ if (p_ssid_list == NULL) {
+ DHD_ERROR(("%s : failed to allocate wlc_ssid_t array (count: %d)",
+ __FUNCTION__, _params2->params_legacy.nssid));
+ err = BCME_ERROR;
+ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE;
+ goto exit;
+ }
+ i = 0;
+ /* convert dhd_pno_ssid to dhd_pno_ssid */
+ list_for_each_entry_safe(iter, next, &_params2->params_legacy.ssid_list, list) {
+ p_ssid_list[i].SSID_len = iter->SSID_len;
+ memcpy(p_ssid_list->SSID, iter->SSID, p_ssid_list[i].SSID_len);
+ i++;
+ }
+ if ((err = _dhd_pno_add_ssid(dhd, p_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;
+ }
+ if (p_ssid_list)
+ kfree(p_ssid_list);
+ return err;
+}
+
+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_t *plbestnet = NULL;
+ wl_pfn_lnet_info_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);
+ 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;
+ }
+ if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) {
+ DHD_ERROR(("%s: Batching SCAN mode is not enabled\n", __FUNCTION__));
+ goto exit;
+ }
+ 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 */
+ 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);
+ }
+ _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_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN);
+ NULL_CHECK(plbestnet, "failed to allocate buffer for bestnet", err);
+ 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", (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;
+ pbestnet_entry->SSID_len = plnetinfo->pfnsubnet.SSID_len;
+ memcpy(pbestnet_entry->SSID, plnetinfo->pfnsubnet.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.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--;
+ }
+ /* 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 */
+ 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);
+ }
+ /* 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);
+ if (waitqueue_active(&_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__));
+ _pno_state = container_of(work, struct dhd_pno_status_info, work);
+ dhd = _pno_state->dhd;
+ if (dhd == NULL) {
+ DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__));
+ return;
+ }
+ 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;
+ 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 += sprintf(pbuf, "scancount=%d\n", 0);
+ sprintf(pbuf, "%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);
+ 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;
+ wlc_ssid_t *p_ssid_list = 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;
+ }
+ 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;
+ dhd_pno_clean(dhd);
+ _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;
+ struct dhd_pno_ssid *iter, *next;
+ _params_legacy =
+ &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy);
+ p_ssid_list = kzalloc(sizeof(wlc_ssid_t) *
+ _params_legacy->nssid, GFP_KERNEL);
+ if (p_ssid_list == NULL) {
+ DHD_ERROR(("%s : failed to allocate wlc_ssid_t array (count: %d)",
+ __FUNCTION__, _params_legacy->nssid));
+ err = BCME_ERROR;
+ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE;
+ goto exit;
+ }
+ i = 0;
+ /* convert dhd_pno_ssid to dhd_pno_ssid */
+ list_for_each_entry_safe(iter, next, &_params_legacy->ssid_list, list) {
+ p_ssid_list[i].SSID_len = iter->SSID_len;
+ memcpy(p_ssid_list[i].SSID, iter->SSID, p_ssid_list[i].SSID_len);
+ i++;
+ }
+ err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid,
+ _params_legacy->scan_fr, _params_legacy->pno_repeat,
+ _params_legacy->pno_freq_expo_max, _params_legacy->chan_list,
+ _params_legacy->nchan);
+ if (err < 0) {
+ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE;
+ 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 */
+ 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++;
+ }
+ 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);
+ if (p_ssid_list)
+ kfree(p_ssid_list);
+ if (p_pfn_bssid)
+ 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;
+ int i = 0;
+ dhd_pno_status_info_t *_pno_state;
+ dhd_pno_params_t *_params;
+ wlc_ssid_t *p_ssid_list = NULL;
+ 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;
+ struct dhd_pno_ssid *iter, *next;
+ _params_legacy =
+ &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS].params_legacy);
+ p_ssid_list =
+ kzalloc(sizeof(wlc_ssid_t) * _params_legacy->nssid, GFP_KERNEL);
+ if (p_ssid_list == NULL) {
+ DHD_ERROR(("%s : failed to allocate wlc_ssid_t array (count: %d)",
+ __FUNCTION__, _params_legacy->nssid));
+ err = BCME_ERROR;
+ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE;
+ goto exit;
+ }
+ /* convert dhd_pno_ssid to dhd_pno_ssid */
+ list_for_each_entry_safe(iter, next, &_params_legacy->ssid_list, list) {
+ p_ssid_list[i].SSID_len = iter->SSID_len;
+ memcpy(p_ssid_list[i].SSID, iter->SSID, p_ssid_list[i].SSID_len);
+ i++;
+ }
+ err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid,
+ _params_legacy->scan_fr, _params_legacy->pno_repeat,
+ _params_legacy->pno_freq_expo_max, _params_legacy->chan_list,
+ _params_legacy->nchan);
+ if (err < 0) {
+ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE;
+ 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:
+ if (p_ssid_list)
+ kfree(p_ssid_list);
+ return err;
+}
+
+int
+dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data)
+{
+ int err = BCME_OK;
+ uint status, event_type, flags, datalen;
+ 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);
+ flags = ntoh16(event->flags);
+ status = ntoh32(event->status);
+ datalen = ntoh32(event->datalen);
+ 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:
+ {
+ struct dhd_pno_batch_params *params_batch;
+ params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch;
+ if (!waitqueue_active(&_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;
+ }
+ 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;
+ 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);
+ err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, 0);
+ if (err == BCME_UNSUPPORTED) {
+ _pno_state->wls_supported = FALSE;
+ DHD_INFO(("Current firmware doesn't support"
+ " Android Location Service\n"));
+ }
+exit:
+ 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);
+ }
+
+ 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/drivers/net/wireless/bcmdhd/dhd_pno.h b/drivers/net/wireless/bcmdhd/dhd_pno.h
new file mode 100644
index 000000000000..4c9c49ccdbad
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_pno.h
@@ -0,0 +1,253 @@
+/*
+ * Header file of Broadcom Dongle Host Driver (DHD)
+ * Prefered Network Offload code and Wi-Fi Location Service(WLS) code.
+ * 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: dhd_pno.h 423669 2013-09-18 13:01:55Z $
+ */
+
+#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"
+
+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,
+ 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;
+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;
+struct dhd_pno_ssid {
+ uint32 SSID_len;
+ uchar SSID[DOT11_MAX_SSID_LEN];
+ struct list_head list;
+};
+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;
+};
+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;
+} dhd_pno_params_t;
+typedef struct dhd_pno_status_info {
+ dhd_pub_t *dhd;
+ struct work_struct work;
+ struct mutex pno_mutex;
+ 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_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);
+
+/* 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_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);
+#endif
+
+#endif /* __DHD_PNO_H__ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_proto.h b/drivers/net/wireless/bcmdhd/dhd_proto.h
new file mode 100644
index 000000000000..828330079b9e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_proto.h
@@ -0,0 +1,115 @@
+/*
+ * 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-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: dhd_proto.h 455951 2014-02-17 10:52:22Z $
+ */
+
+#ifndef _dhd_proto_h_
+#define _dhd_proto_h_
+
+#include <dhdioctl.h>
+#include <wlioctl.h>
+
+#ifndef IOCTL_RESP_TIMEOUT
+#define IOCTL_RESP_TIMEOUT 2000 /* In milli second default value for Production FW */
+#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 */
+
+/*
+ * 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);
+
+/* 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_prot_init(dhd_pub_t *dhdp);
+
+/* 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);
+
+/* 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);
+
+/* 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 int dhd_prot_process_msgbuf(dhd_pub_t *dhd);
+extern int dhd_prot_process_ctrlbuf(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);
+#endif
+
+/********************************
+ * 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/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c
new file mode 100644
index 000000000000..61a2d9a268b0
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c
@@ -0,0 +1,8343 @@
+/*
+ * DHD Bus Module for SDIO
+ *
+ * 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: dhd_sdio.c 663157 2016-12-08 12:19:27Z $
+ */
+
+#include <typedefs.h>
+#include <osl.h>
+#include <bcmsdh.h>
+
+#ifdef BCMEMBEDIMAGE
+#include BCMEMBEDIMAGE
+#endif /* BCMEMBEDIMAGE */
+
+#include <bcmdefs.h>
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <bcmdevs.h>
+
+#include <siutils.h>
+#include <hndpmu.h>
+#include <hndsoc.h>
+#include <bcmsdpcm.h>
+#if defined(DHD_DEBUG)
+#include <hndrte_armtrap.h>
+#include <hndrte_cons.h>
+#endif /* defined(DHD_DEBUG) */
+#include <sbchipc.h>
+#include <sbhnddma.h>
+
+#include <sdio.h>
+#include <sbsdio.h>
+#include <sbsdpcmdev.h>
+#include <bcmsdpcm.h>
+#include <bcmsdbus.h>
+
+#include <proto/ethernet.h>
+#include <proto/802.1d.h>
+#include <proto/802.11.h>
+
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_bus.h>
+#include <dhd_proto.h>
+#include <dhd_dbg.h>
+#include <dhdioctl.h>
+#include <sdiovar.h>
+
+/* Murata Work-around code for HT Avail failure (due to no external slow clk) */
+#define MURATA_WORKAROUND_FOR_HTAVAIL 1
+
+#ifdef PROP_TXSTATUS
+#include <dhd_wlfc.h>
+#endif
+
+#ifdef DHDTCPACK_SUPPRESS
+#include <dhd_ip.h>
+#endif
+
+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);
+
+#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 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_NVRAMBUF_SIZE 4096 /* max nvram buf size */
+#define MAX_DATA_BUF (64 * 1024) /* Must be large enough to hold biggest possible glom */
+
+#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
+
+/* 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
+#define PMU_TRANSITION_DLY_EXTRA 500000
+#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 DHD_DEBUG
+/* Device console log buffer state */
+#define CONSOLE_LINE_MAX 192
+#define CONSOLE_BUFFER_MAX 2024
+typedef struct dhd_console {
+ uint count; /* Poll interval msec counter */
+ uint log_addr; /* Log struct address (fixed) */
+ hndrte_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;
+#endif /* DHD_DEBUG */
+
+#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_ADDR (SI_ENUM_BASE + 0x618)
+#define MIN_RSRC_SR 0x3
+#define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 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)
+/* 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 */
+ const char *nvram_params; /* user specified nvram params. */
+
+ 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 */
+
+#ifdef DHD_DEBUG
+ dhd_console_t console; /* Console output polling support */
+ uint console_addr; /* Console address from shared struct */
+#endif /* DHD_DEBUG */
+
+ 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 || !OEM_ANDROID) */
+ 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 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 */
+#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
+ 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 */
+ void *pad_pkt;
+#if defined(CUSTOMER_IMX)
+ int bus_wake_on_resume;
+#endif /* CUSTOMER_IMX */
+} dhd_bus_t;
+
+/* 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)
+
+#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 void dhd_os_wd_timer(void *bus, uint wdtick);
+
+/* 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)
+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;
+
+/* To check if there's window offered */
+#define DATAOK(bus) \
+ (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
+ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
+
+/* To check if there's window offered for ctrl frame */
+#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 */
+#define DATABUFCNT(bus) \
+ ((uint8)(bus->tx_max - bus->tx_seq) - 1)
+
+/* 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
+
+#ifdef DHD_DEBUG
+static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
+static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
+#endif /* DHD_DEBUG */
+
+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);
+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);
+
+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);
+
+#ifdef WLMEDIA_HTSF
+#include <htsf.h>
+extern uint32 dhd_get_htsf(void *dhd, int ifidx);
+#endif /* WLMEDIA_HTSF */
+
+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) {
+ /* 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) {
+ core_capext = FALSE;
+ } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
+ (bus->sih->chip == BCM4339_CHIP_ID) ||
+ (bus->sih->chip == BCM43349_CHIP_ID) ||
+ (bus->sih->chip == BCM4345_CHIP_ID) ||
+ (bus->sih->chip == BCM4354_CHIP_ID) ||
+ (bus->sih->chip == BCM4356_CHIP_ID) ||
+ (bus->sih->chip == BCM4350_CHIP_ID)) {
+ core_capext = TRUE;
+ } else {
+ core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 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) ||
+ (bus->sih->chip == BCM4345_CHIP_ID) ||
+ (bus->sih->chip == BCM4354_CHIP_ID) ||
+ (bus->sih->chip == BCM4356_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) ||
+ (bus->sih->chip == BCM4345_CHIP_ID) ||
+ (bus->sih->chip == BCM4356_CHIP_ID) ||
+ (bus->sih->chip == BCM4354_CHIP_ID))
+ enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE;
+
+ if (enabval)
+ cap = TRUE;
+ } else {
+ data = bcmsdh_reg_read(bus->sdh,
+ SI_ENUM_BASE + 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);
+
+ 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 */
+
+ dhdsdio_devcap_set(bus, SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC);
+
+ 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 ERROR_BCME_NODEVICE_MAX 1
+
+#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
+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);
+
+ 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++ < 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 > 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
+ 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 */
+ } 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));
+ err = 0; /* continue anyway */
+ }
+#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)), (10000));
+
+ 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;
+ uint32 delay = PMU_MAX_TRANSITION_DLY;
+
+#ifdef MURATA_WORKAROUND_FOR_HTAVAIL
+ int try_count, try_err;
+#endif /* MURATA_WORKAROUND_FOR_HTAVAIL */
+
+ 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) {
+ 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) || defined(OOB_PARAM)
+ /* Go to pending and await interrupt if appropriate */
+ if (1 &&
+#if defined(OOB_PARAM)
+ bus->dhd->oob_disable &&
+#endif /* OOB_PARAM */
+ !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) || defined(OOB_PARAM) */
+ {
+ 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);
+ }
+ }
+
+ /* Give the 43362 chip a little bit extra time for HT Avail */
+ if (bus->sih->chip == BCM43362_CHIP_ID) {
+ delay += PMU_TRANSITION_DLY_EXTRA;
+ }
+
+#ifdef MURATA_WORKAROUND_FOR_HTAVAIL
+ /* loop 20 times to test condition */
+ for (try_count = 0; try_count < 20; try_count++) {
+ try_err = 0;
+#endif /* MURATA_WORKAROUND_FOR_HTAVAIL */
+ /* 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)),
+ delay);
+ }
+ if (err) {
+ DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
+#ifdef MURATA_WORKAROUND_FOR_HTAVAIL
+ try_err = 1;
+#else
+ return BCME_ERROR;
+#endif /* MURATA_WORKAROUND_FOR_HTAVAIL */
+ }
+ if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
+ DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
+ __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
+#ifdef MURATA_WORKAROUND_FOR_HTAVAIL
+ try_err = 1;
+#else
+ return BCME_ERROR;
+#endif /* MURATA_WORKAROUND_FOR_HTAVAIL */
+ }
+
+#ifdef MURATA_WORKAROUND_FOR_HTAVAIL
+ if (try_err == 0)
+ break;
+ } /* for (try_count = 0; try_count < 20; try_count++) */
+ if (try_err == 1) {
+ DHD_ERROR(("%s: HT Avail request error: retried %d times. UNRECOVERABLE!\n", __FUNCTION__, try_count));
+ return BCME_ERROR;
+ }
+ if (try_count > 0)
+ DHD_ERROR(("%s: HT Avail request NO ERROR: retried %d times.\n", __FUNCTION__, try_count));
+#endif /* MURATA_WORKAROUND_FOR_HTAVAIL */
+
+ /* 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 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;
+ }
+
+ iovalue = bus->sd_mode;
+ err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
+ &iovalue, sizeof(iovalue), TRUE);
+ if (err) {
+ DHD_ERROR(("%s: error changing sd_mode: %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) {
+ if (sd1idle) {
+ /* Change to SD1 mode and turn off clock */
+ iovalue = 1;
+ err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
+ &iovalue, sizeof(iovalue), TRUE);
+ if (err) {
+ DHD_ERROR(("%s: error changing sd_clock: %d\n",
+ __FUNCTION__, err));
+ return BCME_ERROR;
+ }
+ }
+
+ 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:
+ /* 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:
+ /* 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 */
+ if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
+ return BCME_BUSY;
+
+
+ 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, &regs->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 */
+ if (bus->sih->chip != BCM4329_CHIP_ID &&
+ bus->sih->chip != BCM4319_CHIP_ID) {
+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
+ SBSDIO_DEVCTL_PADS_ISO, NULL);
+ }
+ } 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 || !OEM_ANDROID) */
+ } 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, &regs->tosbmailboxdata, retries);
+ if (retries <= retry_limit)
+ W_SDREG(SMB_DEV_INT, &regs->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 */);
+ }
+
+ if (err == 0) {
+ /* Change state */
+ bus->sleeping = FALSE;
+ }
+ }
+
+ return err;
+}
+
+
+#if defined(OOB_INTR_ONLY)
+void
+dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
+{
+#if defined(HW_OOB)
+ 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, &regs->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, &regs->tosbmailboxdata, retries);
+ if (retries <= retry_limit)
+ W_SDREG(SMB_DEV_INT, &regs->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;
+#if defined(DHD_TX_DUMP) || defined(DHD_8021X_DUMP)
+ uint8 *dump_data;
+ uint16 protocol;
+#endif /* DHD_TX_DUMP || DHD_8021X_DUMP */
+
+ 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 */
+
+#if defined(DHD_TX_DUMP) || defined(DHD_8021X_DUMP)
+ dump_data = PKTDATA(osh, pkt);
+ dump_data += 4; /* skip 4 bytes header */
+ protocol = (dump_data[12] << 8) | dump_data[13];
+
+ if (protocol == ETHER_TYPE_802_1X) {
+ DHD_ERROR(("ETHER_TYPE_802_1X [TX]: ver %d, type %d, replay %d\n",
+ dump_data[14], dump_data[15], dump_data[30]));
+ }
+#endif /* DHD_TX_DUMP || DHD_8021X_DUMP */
+
+#if defined(DHD_TX_DUMP) && defined(DHD_TX_FULL_DUMP)
+ {
+ int i;
+ DHD_ERROR(("TX DUMP\n"));
+
+ for (i = 0; i < (datalen - 4); i++) {
+ DHD_ERROR(("%02X ", dump_data[i]));
+ if ((i & 15) == 15)
+ printk("\n");
+ }
+ DHD_ERROR(("\n"));
+ }
+#endif /* DHD_TX_DUMP && DHD_TX_FULL_DUMP */
+
+ prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
+
+ /* 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;
+
+ 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;
+
+ dhd_os_sdlock_txq(bus->dhd);
+ pkq_len = pktq_len(&bus->txq);
+ dhd_os_sdunlock_txq(bus->dhd);
+ if (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) {
+ 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) {
+ bus->activity = FALSE;
+ dhdsdio_clkctl(bus, CLK_NONE, TRUE);
+ }
+
+ 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)
+{
+ 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;
+
+ *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 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 = (ulong)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().
+ */
+ *(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;
+
+ 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;
+
+ 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 (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);
+
+ }
+
+ /* 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);
+ }
+
+ /* 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;
+
+ 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;
+ 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) {
+ num_pkt = MIN((uint32)DATABUFCNT(bus), (uint32)bus->txglomsize);
+ 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, ~bus->flowcontrol, &prec_out);
+ if (!pkts[i]) {
+ DHD_ERROR(("%s: pktg_mlen non-zero when no pkt\n",
+ __FUNCTION__));
+ ASSERT(0);
+ break;
+ }
+ PKTORPHAN(pkts[i]);
+ 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;
+ cnt += i;
+
+ /* In poll mode, need to check for other events */
+ if (!bus->intr && cnt)
+ {
+ /* Check device status, signal pending interrupt */
+ R_SDREG(intstatus, &regs->intstatus, retries);
+ bus->f2txdata++;
+ if (bcmsdh_regfail(bus->sdh))
+ break;
+ if (intstatus & bus->hostintmask)
+ bus->ipend = TRUE;
+ }
+
+ }
+
+ 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;
+ bcmsdh_info_t *sdh = bus->sdh;
+ 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);
+
+ 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));
+ }
+ if (!TXCTLOK(bus)) {
+ DHD_INFO(("%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) {
+ DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
+ __FUNCTION__, bus->dhd->txcnt_timeout));
+ }
+ 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
+ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
+ frame, len, NULL, NULL, NULL, TXRETRIES);
+ if (ret == BCME_OK)
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+ }
+ bus->ctrl_frame_stat = FALSE;
+
+done:
+ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
+ bus->activity = FALSE;
+ dhdsdio_clkctl(bus, CLK_NONE, TRUE);
+ }
+
+ 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;
+ bool pending;
+
+ 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, &pending);
+
+ dhd_os_sdlock(bus->dhd);
+ rxlen = bus->rxlen;
+ bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
+ bus->rxlen = 0;
+ dhd_os_sdunlock(bus->dhd);
+
+ 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 */
+#ifdef DHD_DEBUG
+ dhd_os_sdlock(bus->dhd);
+ dhdsdio_checkdied(bus, NULL, 0);
+ dhd_os_sdunlock(bus->dhd);
+#endif /* DHD_DEBUG */
+ } else if (pending == TRUE) {
+ /* signal pending */
+ DHD_ERROR(("%s: signal pending\n", __FUNCTION__));
+ return -EINTR;
+
+ } else {
+ DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
+#ifdef DHD_DEBUG
+ dhd_os_sdlock(bus->dhd);
+ dhdsdio_checkdied(bus, NULL, 0);
+ dhd_os_sdunlock(bus->dhd);
+#endif /* DHD_DEBUG */
+ }
+ 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));
+ }
+ 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_MEMBYTES,
+ 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
+};
+
+const bcm_iovar_t dhdsdio_iovars[] = {
+ {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
+ {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 },
+ {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 },
+ {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 },
+ {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 },
+ {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 },
+ {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
+ {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 },
+ {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 },
+ {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 },
+ {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 },
+ {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
+ {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 },
+ {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 },
+ {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 },
+ {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 },
+ {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 },
+ {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
+#ifdef DHD_DEBUG
+ {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
+ {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
+ {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
+ {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 },
+ {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
+ {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
+ {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 },
+ {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 },
+#ifdef DHD_DEBUG
+ {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 },
+ {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 },
+#endif /* DHD_DEBUG */
+#endif /* DHD_DEBUG */
+#ifdef SDTEST
+ {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
+ {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
+#endif /* SDTEST */
+#if defined(USE_SDIOFIFO_IOVAR)
+ {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 },
+ {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 },
+#endif /* USE_SDIOFIFO_IOVAR */
+ {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 },
+ {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
+ {"kso", IOV_KSO, 0, IOVT_UINT32, 0 },
+ {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 },
+#ifdef SOFTAP
+ {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 },
+#endif
+ {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 },
+ {"fw_hang_report", IOV_HANGREPORT, 0, IOVT_BOOL, 0 },
+ {"txinrx_thres", IOV_TXINRX_THRES, 0, IOVT_INT32, 0 },
+ {NULL, 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;
+
+ 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);
+ 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
+ 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);
+}
+
+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
+ 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;
+}
+
+#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;
+
+ /* 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 ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
+ DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
+ break;
+ }
+
+ /* 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;
+}
+
+#ifdef DHD_DEBUG
+static int
+dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
+{
+ uint32 addr;
+ int rv, i;
+ uint32 shaddr = 0;
+
+ if (CHIPID(bus->sih->chip) == BCM43430_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);
+
+ 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
+
+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(hndrte_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;
+}
+
+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;
+ trap_t tr;
+ sdpcm_shared_t 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, &sdpcm_shared)) < 0)
+ goto done;
+
+ bcm_binit(&strbuf, data, size);
+
+ bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
+ sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
+
+ if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
+ /* NOTE: Misspelled assert is intentional - DO NOT FIX.
+ * (Avoids conflict with real asserts for programmatic parsing of output.)
+ */
+ bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
+ }
+
+ if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
+ /* NOTE: Misspelled assert is intentional - DO NOT FIX.
+ * (Avoids conflict with real asserts for programmatic parsing of output.)
+ */
+ bcm_bprintf(&strbuf, "No trap%s in dongle",
+ (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
+ ?"/assrt" :"");
+ } else {
+ if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
+ /* Download assert */
+ bcm_bprintf(&strbuf, "Dongle assert");
+ if (sdpcm_shared.assert_exp_addr != 0) {
+ str[0] = '\0';
+ if ((bcmerror = dhdsdio_membytes(bus, FALSE,
+ sdpcm_shared.assert_exp_addr,
+ (uint8 *)str, maxstrlen)) < 0)
+ goto done;
+
+ str[maxstrlen - 1] = '\0';
+ bcm_bprintf(&strbuf, " expr \"%s\"", str);
+ }
+
+ if (sdpcm_shared.assert_file_addr != 0) {
+ str[0] = '\0';
+ if ((bcmerror = dhdsdio_membytes(bus, FALSE,
+ 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 ", sdpcm_shared.assert_line);
+ }
+
+ if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
+ bus->dhd->dongle_trap_occured = TRUE;
+ if ((bcmerror = dhdsdio_membytes(bus, FALSE,
+ sdpcm_shared.trap_addr,
+ (uint8*)&tr, sizeof(trap_t))) < 0)
+ goto done;
+
+ 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(sdpcm_shared.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));
+
+ addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log);
+ if ((rv = dhdsdio_membytes(bus, FALSE, addr,
+ (uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
+ goto printbuf;
+
+ addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size);
+ if ((rv = dhdsdio_membytes(bus, FALSE, addr,
+ (uint8 *)&console_size, sizeof(console_size))) < 0)
+ goto printbuf;
+
+ addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_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 (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
+ DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
+ }
+
+
+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;
+}
+#endif /* #ifdef DHD_DEBUG */
+
+
+int
+dhdsdio_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);
+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__));
+ 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_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;
+ 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) {
+ DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
+ __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
+ bcmerror = BCME_BADARG;
+ break;
+ }
+
+ DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
+ (set ? "write" : "read"), size, address));
+
+ /* check if CR4 */
+ if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
+ /*
+ * If address is start of RAM (i.e. a downloaded image),
+ * store the reset instruction to be written in 0
+ */
+ if (set && address == bus->dongle_ram_base) {
+ bus->resetinstr = *(((uint32*)params) + 2);
+ }
+ } else {
+ /* If we know about SOCRAM, check for a fit */
+ if ((bus->orig_ramsize) &&
+ ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
+ {
+ uint8 enable, protect, remap;
+ si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
+ if (!enable || protect) {
+ DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
+ __FUNCTION__, bus->orig_ramsize, size, address));
+ DHD_ERROR(("%s: socram enable %d, protect %d\n",
+ __FUNCTION__, enable, protect));
+ bcmerror = BCME_BADARG;
+ break;
+ }
+
+ if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) {
+ uint32 devramsize = si_socdevram_size(bus->sih);
+ if ((address < SOCDEVRAM_ARM_ADDR) ||
+ (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) {
+ DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
+ __FUNCTION__, address, size));
+ DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
+ __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize));
+ bcmerror = BCME_BADARG;
+ break;
+ }
+ /* move it such that address is real now */
+ address -= SOCDEVRAM_ARM_ADDR;
+ address += SOCDEVRAM_BP_ADDR;
+ DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
+ __FUNCTION__, (set ? "write" : "read"), size, address));
+ } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) {
+ /* Can not access remap region while devram remap bit is set
+ * ROM content would be returned in this case
+ */
+ DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n",
+ __FUNCTION__, address));
+ bcmerror = BCME_ERROR;
+ break;
+ }
+ }
+ }
+
+ /* Generate the actual data pointer */
+ data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
+
+ /* Call to do the transfer */
+ bcmerror = dhdsdio_membytes(bus, set, address, data, size);
+
+ 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;
+ uint32 addr, size;
+
+ sd_ptr = (sdreg_t *)params;
+
+ addr = (ulong)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;
+ uint32 addr, size;
+
+ sd_ptr = (sdreg_t *)params;
+
+ addr = (ulong)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;
+
+ default:
+ bcmerror = BCME_UNSUPPORTED;
+ break;
+ }
+
+exit:
+ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
+ bus->activity = FALSE;
+ dhdsdio_clkctl(bus, CLK_NONE, TRUE);
+ }
+
+ 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;
+
+ 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);
+#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) {
+ /* 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));
+
+ /* 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) {
+ bus->activity = FALSE;
+ dhdsdio_clkctl(bus, CLK_NONE, TRUE);
+ }
+
+ 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;
+
+ 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);
+
+ /* Change our idea of bus state */
+ bus->dhd->busstate = DHD_BUS_DOWN;
+
+ 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);
+ }
+
+#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 */
+ /* Clear the data packet queues */
+ pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
+ }
+
+ /* 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
+ char buf[256];
+ 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;
+ memset(buf, 0, sizeof(buf));
+ bcm_mkiovar("bus:rxglom", (void *)&rxglom, 4, buf, sizeof(buf));
+ ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
+ 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;
+}
+
+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;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ ASSERT(bus->dhd);
+ if (!bus->dhd)
+ return 0;
+
+ if (enforce_mutex)
+ dhd_os_sdlock(bus->dhd);
+
+ /* 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) {
+ 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 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;
+
+ /* 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, &regs->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;
+ } 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_ERROR(("%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);
+ }
+ }
+ }
+ bus->rxglomframes++;
+ bus->rxglompkts += num;
+ }
+ return num;
+}
+
+
+#ifdef SDHOST3
+static bool
+dhdsdio_pr94636_WAR(dhd_bus_t *bus)
+{
+ uint cd = 0;
+ uint ld = 0;
+ int bcmerror = 0;
+ uint32 l_data[5];
+ uint32 l_addr = (0x18002200 & SBSDIO_SB_OFT_ADDR_MASK);
+
+ /* Read 20 bytes from 0x18002200
+ * the sdiod Tx DMA registers address on AI Backplane.
+ */
+ if ((bcmerror = bcmsdh_rwdata(bus->sdh, FALSE, l_addr, (uint8 *)&l_data[0], 20))) {
+ DHD_ERROR(("%s: bcmsdh_rwdata failed\n", __FUNCTION__));
+ return FALSE;
+ }
+ ld = l_data[1];
+ ld = ld & 0x00001fff;
+ cd = l_data[4];
+ cd = cd & 0x00001fff;
+ if (cd == ld)
+ return TRUE;
+ else
+ return FALSE;
+}
+#endif /* SDHOST3 */
+/* 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_ERROR(("%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;
+ }
+#ifdef SDHOST3
+ if (((((uint16)bus->sih->chip) == BCM4324_CHIP_ID) && (bus->sih->chiprev <= 1)) ||
+ (((uint16)bus->sih->chip) == BCM43340_CHIP_ID) ||
+ (((uint16)bus->sih->chip) == BCM43341_CHIP_ID) ||
+ (((uint16)bus->sih->chip) == BCM4334_CHIP_ID)) {
+ if (dhdsdio_pr94636_WAR(bus) == TRUE) {
+ *finished = TRUE;
+ break;
+ }
+ }
+#endif /* SDHOST3 */
+
+ /* 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_ERROR(("%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);
+ }
+ 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)
+{
+ 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, &regs->tohostmailboxdata, retries);
+ if (retries <= retry_limit)
+ W_SDREG(SMB_INT_ACK, &regs->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;
+ }
+
+#ifdef DHD_DEBUG
+ /* 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;
+ }
+#endif /* DHD_DEBUG */
+
+ /* 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));
+ }
+
+ 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 */
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ dhd_os_sdlock(bus->dhd);
+
+ if (bus->dhd->busstate == DHD_BUS_DOWN) {
+ DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
+ bus->intstatus = 0;
+ dhd_os_sdunlock(bus->dhd);
+ return 0;
+ }
+
+ /* 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;
+ R_SDREG(newstatus, &regs->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, &regs->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, &regs->intstatus, retries);
+ R_SDREG(newstatus, &regs->intstatus, retries);
+ bus->f1regdata += 2;
+ bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
+ intstatus |= (newstatus & bus->hostintmask);
+ }
+
+ /* 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);
+ }
+
+ /* 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)) {
+ DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
+ __FUNCTION__, rxdone, framecnt));
+ bus->intdis = FALSE;
+#if defined(OOB_INTR_ONLY)
+ OOB_PARAM_IF(!(bus->dhd->oob_disable)) {
+ bcmsdh_oob_intr_set(bus->sdh, TRUE);
+ }
+#endif /* defined(OOB_INTR_ONLY) */
+ bcmsdh_intr_enable(sdh);
+ }
+
+#if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
+ OOB_PARAM_IF(!(bus->dhd->oob_disable)) {
+ /* In case of SW-OOB(using edge trigger),
+ * Check interrupt status in the dongle again after enable irq on the host.
+ * and rechedule dpc if interrupt is pended in the dongle.
+ * There is a chance to miss OOB interrupt while irq is disabled on the host.
+ * No need to do this with HW-OOB(level trigger)
+ */
+ R_SDREG(newstatus, &regs->intstatus, retries);
+ if (bcmsdh_regfail(bus->sdh))
+ newstatus = 0;
+ if (newstatus & bus->hostintmask) {
+ bus->ipend = TRUE;
+ resched = TRUE;
+ }
+ }
+#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
+
+#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);
+
+ /* 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)) {
+ framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
+ framecnt = dhdsdio_sendfromq(bus, framecnt);
+ txlimit -= framecnt;
+ }
+ /* Resched the DPC if ctrl cmd is pending on bus credit */
+ if (bus->ctrl_frame_stat)
+ 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)) {
+ bus->activity = FALSE;
+ dhdsdio_clkctl(bus, CLK_NONE, FALSE);
+ }
+
+exit:
+
+ if (!resched && dhd_dpcpoll) {
+ if (dhdsdio_readframes(bus, dhd_rxbound, &rxdone) != 0) {
+ resched = TRUE;
+ }
+ }
+
+ dhd_os_sdunlock(bus->dhd);
+ 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_TRACE(("%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;
+ }
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ /* 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) || defined(OOB_PARAM)
+ OOB_PARAM_IF(bus->dhd->oob_disable) {
+ DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
+ DHD_OS_WAKE_LOCK(bus->dhd);
+ dhdsdio_dpc(bus);
+ DHD_OS_WAKE_UNLOCK(bus->dhd);
+ } OOB_PARAM_ELSE()
+#endif /* defined(SDIO_ISR_THREAD) || defined(OOB_PARAM) */
+#if !defined(SDIO_ISR_THREAD) || defined(OOB_PARAM)
+ {
+ bus->dpc_sched = TRUE;
+ dhd_sched_dpc(bus->dhd);
+ }
+#endif /* !defined(SDIO_ISR_THREAD) || defined(OOB_PARAM) */
+
+
+}
+
+#ifdef SDTEST
+static void
+dhdsdio_pktgen_init(dhd_bus_t *bus)
+{
+ /* Default to specified length, or full range */
+ if (dhd_pktgen_len) {
+ bus->pktgen_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)
+ OOB_PARAM_IF(!(dhdp->oob_disable)) {
+ 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)
+ OOB_PARAM_IF(!(dhdp->oob_disable)) {
+ 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)
+ OOB_PARAM_IF(!(dhdp->oob_disable)) {
+ 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;
+
+ 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;
+
+ if (dhdp->busstate == DHD_BUS_DOWN)
+ return FALSE;
+
+
+#if defined(CUSTOMER_IMX)
+ if (bus->bus_wake_on_resume) {
+ BUS_WAKE(bus);
+ bus->bus_wake_on_resume = 0;
+ }
+#endif /* CUSTOMER_IMX */
+
+
+ /* Poll period: check device if appropriate. */
+ if (!SLPAUTO_ENAB(bus) && (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;
+ }
+
+#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 ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) {
+ DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
+ if (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)) {
+ if (++bus->idlecount >= bus->idletime) {
+ bus->idlecount = 0;
+ if (bus->activity) {
+ bus->activity = FALSE;
+ if (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 */
+
+ return bus->ipend;
+}
+
+#ifdef DHD_DEBUG
+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;
+
+ /* Address could be zero if CONSOLE := 0 in dongle Makefile */
+ if (bus->console_addr == 0)
+ return BCME_UNSUPPORTED;
+
+ /* Exclusive bus access */
+ dhd_os_sdlock(bus->dhd);
+
+ /* Don't allow input if dongle is in reset */
+ if (bus->dhd->dongle_reset) {
+ dhd_os_sdunlock(bus->dhd);
+ return BCME_NOTREADY;
+ }
+
+ /* 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);
+
+ /* Zero cbuf_index */
+ addr = bus->console_addr + OFFSETOF(hndrte_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(hndrte_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(hndrte_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:
+ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
+ bus->activity = FALSE;
+ dhdsdio_clkctl(bus, CLK_NONE, TRUE);
+ }
+
+ dhd_os_sdunlock(bus->dhd);
+
+ return rv;
+}
+#endif /* DHD_DEBUG */
+
+#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 == BCM4325_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4329_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4315_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4319_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4336_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4330_CHIP_ID)
+ return TRUE;
+ if (chipid == 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 (chipid == BCM4345_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4350_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4354_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4356_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM43430_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;
+
+
+ /* 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;
+
+ dhd_doflow = FALSE;
+ 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 BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */
+ case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */
+ case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */
+ DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__));
+ break;
+ case BCM4329_D11N_ID: /* 4329 802.11n dualband device */
+ case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */
+ case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */
+ case 0x4329:
+ DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__));
+ break;
+ case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */
+ case BCM4315_D11G_ID: /* 4315 802.11g id */
+ case BCM4315_D11A_ID: /* 4315 802.11a id */
+ DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__));
+ break;
+ case BCM4319_D11N_ID: /* 4319 802.11n id */
+ case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */
+ case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */
+ DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__));
+ break;
+ 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 */
+
+#if defined(SUPPORT_P2P_GO_PS)
+ init_waitqueue_head(&bus->bus_sleep);
+#endif /* LINUX && (SUPPORT_P2P_GO_PS || !OEM_ANDROID) */
+
+ /* 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;
+ }
+
+ /* 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 (dhd_download_fw_on_driverload) {
+ if ((ret = dhd_bus_start(bus->dhd)) != 0) {
+ DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
+ goto fail;
+ }
+ }
+ /* 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;
+ }
+
+
+ return bus;
+
+fail:
+ dhdsdio_release(bus, osh);
+
+forcereturn:
+
+ return NULL;
+}
+
+static bool
+dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
+ uint16 devid)
+{
+ int err = 0;
+ uint8 clkctl = 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__));
+ }
+
+
+ /* 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;
+ }
+
+#ifdef DHD_DEBUG
+ if (DHD_INFO_ON()) {
+ uint fn, numfn;
+ uint8 *cis[SDIOD_MAX_IOFUNCS];
+ int err = 0;
+
+ 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(65);
+
+ 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;
+ }
+ dhd_dump_cis(fn, cis[fn]);
+ }
+
+ while (fn-- > 0) {
+ ASSERT(cis[fn]);
+ MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
+ }
+
+ if (err) {
+ DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
+ goto fail;
+ }
+ }
+#endif /* DHD_DEBUG */
+
+ /* 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 BCM4356_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_ID:
+ /* RAM base changed from 4345c0 (chiprev=6) onwards */
+ bus->dongle_ram_base = (bus->sih->chiprev < 6)
+ ? CR4_4345_LT_C0_RAM_BASE : CR4_4345_GE_C0_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->rxbuf) {
+ DHD_OS_PREFREE(bus->dhd, DHD_PREALLOC_RXBUF, bus->rxbuf, bus->rxblen);
+ bus->rxbuf = NULL;
+ }
+ goto fail;
+ }
+
+ /* 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 */
+
+ /* 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);
+
+ 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);
+ }
+
+
+ /* 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;
+
+ return TRUE;
+}
+
+int
+dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
+ char *pfw_path, char *pnv_path)
+{
+ int ret;
+
+ bus->fw_path = pfw_path;
+ bus->nv_path = pnv_path;
+
+ ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
+
+
+ return ret;
+}
+
+static int
+dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
+{
+ int ret;
+
+
+ DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n",
+ __FUNCTION__, bus->fw_path, bus->nv_path));
+ DHD_OS_WAKE_LOCK(bus->dhd);
+
+ /* 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
+
+ if (bus->pad_pkt)
+ PKTFREE(osh, bus->pad_pkt, FALSE);
+
+
+ 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->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) {
+#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__));
+
+
+
+ if (bus) {
+ ASSERT(bus->dhd);
+ dhdsdio_release(bus, bus->dhd->osh);
+ }
+
+
+
+ DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
+}
+
+static int
+dhdsdio_suspend(void *context)
+{
+ int ret = 0;
+
+ dhd_bus_t *bus = (dhd_bus_t*)context;
+#if defined(SUPPORT_P2P_GO_PS)
+ int wait_time = 0;
+
+ if (bus->idletime > 0) {
+ wait_time = 2 * (msecs_to_jiffies(bus->idletime * dhd_watchdog_ms));
+ }
+#endif /* SUPPORT_P2P_GO_PS || !OEM_ANDROID */
+ ret = dhd_os_check_wakelock(bus->dhd);
+#if defined(SUPPORT_P2P_GO_PS)
+ /* Sometimes DHD enters into suspend state when bus is still awake due
+ * to absence of wake locks on Non-Android platforms, so perform bus
+ * sleep status check using bus_sleep event to prevent dhd entering
+ * into suspend state when bus is still awake.
+ */
+ if ((!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) {
+ DHD_ERROR(("%s: cannot suspend because bus is awake\n",
+ __FUNCTION__));
+ return -EBUSY;
+ }
+ }
+ }
+#endif /* SUPPORT_P2P_GO_PS || !OEM_ANDROID */
+ return ret;
+}
+
+static int
+dhdsdio_resume(void *context)
+{
+
+#if defined(OOB_INTR_ONLY) || defined(CUSTOMER_IMX)
+ dhd_bus_t *bus = (dhd_bus_t*)context;
+#endif /* defined(OOB_INTR_ONLY)||defined(BCMSPI_ANDROID)||
+ * defined(CUSTOMER_IMX) */
+
+#if defined(OOB_INTR_ONLY)
+
+ OOB_PARAM_IF(!(bus->dhd->oob_disable)) {
+ if (dhd_os_check_if_up(bus->dhd))
+ bcmsdh_oob_intr_set(bus->sdh, TRUE);
+ }
+#endif
+
+#if defined(CUSTOMER_IMX)
+ bus->bus_wake_on_resume = 1;
+ dhd_os_wd_timer(bus->dhd, 1000);
+#endif /* CUSTOMER_IMX */
+
+ 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;
+
+ DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
+
+ image = dhd_os_open_image(pfw_path);
+ if (image == NULL)
+ 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 ((uint32)(uintptr)memblock % DHD_SDALIGN)
+ memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
+
+ /* Download image */
+ while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
+ 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, offset));
+ goto err;
+ }
+
+ offset += MEMBLOCK;
+ }
+
+err:
+ if (memblock)
+ MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
+
+ if (image)
+ dhd_os_close_image(image);
+
+ return bcmerror;
+}
+
+/*
+ EXAMPLE: nvram_array
+ nvram_arry format:
+ name=value
+ Use carriage return at the end of each assignment, and an empty string with
+ carriage return at the end of array.
+
+ For example:
+ unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"};
+ Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
+
+ Search "EXAMPLE: nvram_array" to see how the array is activated.
+*/
+
+void
+dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params)
+{
+ bus->nvram_params = nvram_params;
+}
+
+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'));
+ if (!nvram_file_exists && (bus->nvram_params == NULL))
+ return (0);
+
+ if (nvram_file_exists) {
+ image = dhd_os_open_image(pnv_path);
+ if (image == NULL)
+ 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;
+ }
+
+ /* Download variables */
+ if (nvram_file_exists) {
+ len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
+ }
+ else {
+ len = strlen(bus->nvram_params);
+ ASSERT(len <= MAX_NVRAMBUF_SIZE);
+ memcpy(memblock, bus->nvram_params, len);
+ }
+ 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;
+ }
+
+ /* 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 (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, 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, 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, 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, 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;
+}
+
+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;
+}
+
+void *
+dhd_bus_sih(struct dhd_bus *bus)
+{
+ return (void *)bus->sih;
+}
+
+void *
+dhd_bus_txq(struct dhd_bus *bus)
+{
+ return &bus->txq;
+}
+
+void
+dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val)
+{
+ bus->dotxinrx = val;
+}
+
+int
+dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
+{
+ int bcmerror = 0;
+ dhd_bus_t *bus;
+
+ bus = dhdp->bus;
+
+ if (flag == TRUE) {
+ if (!bus->dhd->dongle_reset) {
+ 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)
+ OOB_PARAM_IF(!(dhdp->oob_disable)) {
+ /* 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_TRACE(("%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 */
+
+ DHD_TRACE(("\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)) {
+ /* 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)
+ OOB_PARAM_IF(!(dhdp->oob_disable)) {
+ dhd_enable_oob_intr(bus, TRUE);
+ bcmsdh_oob_intr_register(bus->sdh,
+ dhdsdio_isr, bus);
+ bcmsdh_oob_intr_set(bus->sdh, 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 {
+ bcmerror = BCME_SDIO_ERROR;
+ DHD_INFO(("%s called when dongle is not in reset\n",
+ __FUNCTION__));
+ DHD_INFO(("Will call dhd_bus_start instead\n"));
+ dhd_bus_resume(dhdp, 1);
+ if ((bcmerror = dhd_bus_start(dhdp)) != 0)
+ DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
+ __FUNCTION__, bcmerror));
+ }
+ }
+ 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;
+
+ 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;
+}
+
+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)
+{
+ bus->fw_path = pfw_path;
+ bus->nv_path = pnv_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, &regs->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, &regs->tosbmailboxdata, retries);
+ if (retries <= retry_limit)
+ W_SDREG(SMB_DEV_INT, &regs->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, NULL, 0);
+ }
+}
+
+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;
+}
+
+#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 */
+
+
+#ifdef OOB_PARAM
+uint
+dhd_get_oob_disable(struct dhd_bus *bus)
+{
+ return bus->dhd->oob_disable;
+}
+#endif /* OOB_PARAM */
diff --git a/drivers/net/wireless/bcmdhd/dhd_wlfc.c b/drivers/net/wireless/bcmdhd/dhd_wlfc.c
new file mode 100644
index 000000000000..8c1436a3ee3f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_wlfc.c
@@ -0,0 +1,4049 @@
+/*
+ * DHD PROP_TXSTATUS Module.
+ *
+ * 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: dhd_wlfc.c 658506 2016-09-08 06:44:19Z $
+ *
+ */
+
+#include <typedefs.h>
+#include <osl.h>
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+
+#include <dngl_stats.h>
+#include <dhd.h>
+
+#include <dhd_bus.h>
+#include <dhd_dbg.h>
+
+#ifdef PROP_TXSTATUS
+#include <wlfc_proto.h>
+#include <dhd_wlfc.h>
+#endif
+#ifdef DHDTCPACK_SUPPRESS
+#include <dhd_ip.h>
+#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.
+ *
+ */
+
+
+#ifdef PROP_TXSTATUS
+
+#define DHD_WLFC_QMON_COMPLETE(entry)
+
+#define LIMIT_BORROW
+
+
+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;
+}
+
+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;
+}
+
+/* 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.
+*/
+static void*
+_dhd_wlfc_hanger_create(osl_t *osh, 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*)MALLOC(osh, 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;
+}
+
+static int
+_dhd_wlfc_hanger_delete(osl_t *osh, void* hanger)
+{
+ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger;
+
+ if (h) {
+ MFREE(osh, h, WLFC_HANGER_SIZE(h->max_items));
+ return BCME_OK;
+ }
+ return BCME_BADARG;
+}
+
+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;
+}
+
+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_INUSE) ||
+ (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) {
+ *gen = h->items[slot_id].gen;
+ }
+ else {
+ rc = BCME_NOTFOUND;
+ }
+ }
+ else
+ rc = BCME_BADARG;
+ return rc;
+}
+
+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->pushed++;
+ }
+ else {
+ h->failed_to_push++;
+ rc = BCME_NOTFOUND;
+ }
+ }
+ else
+ rc = BCME_BADARG;
+ return rc;
+}
+
+static int
+_dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, int remove_from_hanger)
+{
+ 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) {
+ 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;
+}
+
+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;
+}
+
+static void
+_dhd_wlfc_hanger_waitevent_set(void* hanger, uint32 hslot, uint8 waitevent)
+{
+ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger;
+ ASSERT(h && (hslot < (uint32) h->max_items));
+
+ h->items[hslot].waitevent = waitevent;
+}
+
+static uint8
+_dhd_wlfc_hanger_waitevent_decreturn(void* hanger, uint32 hslot)
+{
+ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger;
+ ASSERT(h && (hslot < (uint32) h->max_items));
+
+ h->items[hslot].waitevent--;
+ return h->items[hslot].waitevent;
+}
+
+/* return true if the slot is only waiting for clean */
+static bool
+_dhd_wlfc_hanger_wait_clean(void* hanger, uint32 hslot)
+{
+ wlfc_hanger_t* h = (wlfc_hanger_t*)hanger;
+
+ if ((hslot < (uint32) h->max_items) &&
+ (h->items[hslot].state == WLFC_HANGER_ITEM_STATE_WAIT_CLEAN)) {
+ /* the packet should be already freed by _dhd_wlfc_cleanup */
+ h->items[hslot].state = WLFC_HANGER_ITEM_STATE_FREE;
+ h->items[hslot].pkt = NULL;
+ h->items[hslot].gen = 0xff;
+ h->items[hslot].identifier = 0;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* remove reference of specific packet in hanger */
+static bool
+_dhd_wlfc_hanger_remove_reference(wlfc_hanger_t* h, void* pkt)
+{
+ int i;
+
+ if (!h || !pkt) {
+ return FALSE;
+ }
+
+ for (i = 0; i < h->max_items; i++) {
+ if (pkt == h->items[i].pkt) {
+ if ((h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) ||
+ (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;
+ }
+ }
+
+ return FALSE;
+}
+
+
+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;
+}
+
+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;
+ }
+
+ 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;
+}
+
+static int
+_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void* p, 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;
+
+ 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], &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)));
+ return BCME_OK;
+}
+
+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;
+}
+
+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;
+}
+
+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, 1);
+ 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]--;
+ }
+
+ dhd_txcomplete(dhdp, p, FALSE);
+ PKTFREE(ctx->osh, p, TRUE);
+ ctx->stats.pktout++;
+ ctx->stats.drop_pkts[prec]++;
+
+ return 0;
+}
+
+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]++;
+
+ return TRUE;
+}
+
+
+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;
+}
+
+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_q[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 signle 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;
+}
+
+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())
+ 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;
+}
+
+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;
+ }
+ return rc;
+}
+
+/* Return 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)) {
+
+ if (entry->traffic_pending_bmp & NBITVAL(prec)) {
+ rc = TRUE;
+ entry->traffic_pending_bmp =
+ entry->traffic_pending_bmp & ~ NBITVAL(prec);
+ }
+ }
+ else {
+ 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;
+}
+
+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;
+}
+
+static int
+_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx,
+ wlfc_mac_descriptor_t* entry, void* p, 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;
+
+ *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) {
+ 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) && 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
+ ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].push_time =
+ OSL_SYSUPTIME();
+#endif
+ } else {
+ DHD_ERROR(("%s() hanger_pushpkt() failed, rc: %d\n",
+ __FUNCTION__, rc));
+ }
+ }
+
+ if ((rc == BCME_OK) && header_needed) {
+ /* increment free running sequence count */
+ WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p)));
+ }
+ }
+ *slot = hslot;
+ return rc;
+}
+
+static int
+_dhd_wlfc_is_destination_open(athost_wl_status_info_t* ctx,
+ wlfc_mac_descriptor_t* entry, int prec)
+{
+ if (entry->interface_id >= WLFC_MAX_IFNUM) {
+ ASSERT(&ctx->destination_entries.other == entry);
+ return 1;
+ }
+ if (ctx->destination_entries.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) && (entry->requested_credit == 0) &&
+ (entry->requested_packet == 0)) ||
+ (!(entry->ac_bitmap & (1 << prec)))) {
+ return 0;
+ }
+
+ return 1;
+}
+
+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)
+{
+ dhd_pub_t *dhdp = (dhd_pub_t *)ctx->dhdp;
+ wlfc_mac_descriptor_t* entry;
+ int total_entries;
+ void* p = NULL;
+ int i;
+
+ *entry_out = NULL;
+ /* most cases a packet will count against FIFO credit */
+ *ac_credit_spent = ((prec == AC_COUNT) && !ctx->bcmc_credit_supported) ? 0 : 1;
+
+ /* 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) &&
+ !(WLFC_GET_REORDERSUPP(dhdp->wlfc_mode) && entry->suppressed)) {
+ 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) {
+ if (entry->suppressed == TRUE) {
+ /* skip this entry */
+ continue;
+ }
+ /* De-Q from delay Q */
+ p = pktq_pdeq(&entry->psq, PSQ_DLY_IDX(prec));
+ *needs_hdr = 1;
+ }
+
+ if (p != NULL) {
+ /* 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]--;
+ _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;
+}
+
+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;
+}
+
+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))));
+}
+
+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;
+
+ 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));
+
+ /* 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]++;
+ }
+ }
+}
+
+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) {
+ 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->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);
+ entry->transit_count--;
+ if (entry->suppressed &&
+ (--entry->suppr_transit_count == 0)) {
+ entry->suppressed = FALSE;
+ }
+ _dhd_wlfc_return_implied_credit(ctx, p);
+ ctx->stats.cleanup_fw_cnt++;
+ }
+ PKTSETLINK(p, NULL);
+ dhd_txcomplete(dhdp, p, FALSE);
+ PKTFREE(ctx->osh, p, dir);
+ if (dir) {
+ ctx->stats.pktout++;
+ }
+ 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);
+}
+
+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;
+
+ 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;
+}
+
+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));
+ }
+ entry->transit_count--;
+ if (entry->suppressed &&
+ (--entry->suppr_transit_count == 0)) {
+ entry->suppressed = FALSE;
+ }
+ _dhd_wlfc_return_implied_credit(wlfc, pkt);
+ dhd_txcomplete(dhd, pkt, FALSE);
+ PKTFREE(wlfc->osh, pkt, TRUE);
+ wlfc->stats.pktout++;
+ wlfc->stats.cleanup_txq_cnt++;
+
+ }
+}
+
+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 shoulde be txq -> psq -> hanger/afq, hanger has to be last one
+ */
+ /* flush bus->txq */
+ _dhd_wlfc_cleanup_txq(dhd, fn, arg);
+
+
+ /* 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)) {
+ table = _dhd_wlfc_find_table_entry(wlfc, h->items[i].pkt);
+ table->transit_count--;
+ if (table->suppressed &&
+ (--table->suppr_transit_count == 0)) {
+ table->suppressed = FALSE;
+ }
+ _dhd_wlfc_return_implied_credit(wlfc, h->items[i].pkt);
+ dhd_txcomplete(dhd, h->items[i].pkt, FALSE);
+ PKTFREE(wlfc->osh, h->items[i].pkt, TRUE);
+ wlfc->stats.pktout++;
+ wlfc->stats.cleanup_fw_cnt++;
+ h->items[i].state = WLFC_HANGER_ITEM_STATE_WAIT_CLEAN;
+ }
+ }
+ }
+ }
+
+ return;
+}
+
+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);
+
+#ifdef P2PONEINT
+ if ((action == eWLFC_MAC_ENTRY_ACTION_ADD) ||
+ ((action == eWLFC_MAC_ENTRY_ACTION_UPDATE) && (entry->psq.num_prec == 0))) {
+#else
+ if (action == eWLFC_MAC_ENTRY_ACTION_ADD) {
+#endif
+ dhd_pub_t *dhdp = (dhd_pub_t *)(ctx->dhdp);
+ pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN);
+ 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->suppressed = 0;
+ entry->state = WLFC_STATE_CLOSE;
+ entry->requested_credit = 0;
+ entry->transit_count = 0;
+ entry->suppr_transit_count = 0;
+ 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;
+}
+
+#ifdef LIMIT_BORROW
+static int
+_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, int highest_lender_ac, int borrower_ac)
+{
+ int lender_ac;
+ 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 (ctx->FIFO_credit[lender_ac] > 0) {
+ ctx->credits_borrowed[borrower_ac][lender_ac]++;
+ ctx->FIFO_credit[lender_ac]--;
+ rc = lender_ac;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+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 */
+
+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);
+}
+
+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;
+}
+
+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;
+}
+
+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) {
+ DHD_PKTTAG_WLFCPKT_SET(PKTTAG(commit_info->p), 1);
+ rc = fcommit(commit_ctx, commit_info->p);
+ if (rc == BCME_OK) {
+ uint8 gen = WL_TXSTATUS_GET_GENERATION(
+ DHD_PKTTAG_H2DTAG(PKTTAG(commit_info->p)));
+ if (!WLFC_GET_AFQ(dhdp->wlfc_mode)) {
+ _dhd_wlfc_hanger_waitevent_set(ctx->hanger, hslot,
+ WLFC_HANGER_ITEM_WAIT_EVENT_COUNT);
+ }
+ 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++;
+ } 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, 1);
+ 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;
+}
+
+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;
+}
+
+static int
+_dhd_wlfc_compressed_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info, uint8 len, void** p_mac)
+{
+ uint8 status_flag;
+ uint32 status;
+ int ret = BCME_OK;
+ int 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_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_fromfw = WL_SEQ_GET_FROMFW(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;
+ }
+
+ if (dhd->proptxstatus_txstatus_ignore) {
+ if (!remove_from_hanger) {
+ DHD_ERROR(("suppress txstatus: %d\n", status_flag));
+ }
+ return BCME_OK;
+ }
+
+ while (count < len) {
+ if (WLFC_GET_AFQ(dhd->wlfc_mode)) {
+ ret = _dhd_wlfc_deque_afq(wlfc, hslot, hcnt, fifo_id, &pktbuf);
+ } else {
+ if (_dhd_wlfc_hanger_wait_clean(wlfc->hanger, hslot)) {
+ goto cont;
+ }
+
+ ret = _dhd_wlfc_hanger_poppkt(wlfc->hanger, hslot, &pktbuf, 0);
+ }
+
+ if ((ret != BCME_OK) || !pktbuf) {
+ goto cont;
+ }
+
+ /* 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++;
+#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_FROMDRV(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 {
+ uint8 waitevent = 0;
+ void *pktbuf_tmp = NULL;
+ dhd_txcomplete(dhd, pktbuf, TRUE);
+
+ DHD_WLFC_QMON_COMPLETE(entry);
+ wlfc->stats.pktout++;
+
+ if (!WLFC_GET_AFQ(dhd->wlfc_mode)) {
+ waitevent = _dhd_wlfc_hanger_waitevent_decreturn(wlfc->hanger,
+ hslot);
+ if (!waitevent) {
+ ret = _dhd_wlfc_hanger_poppkt(wlfc->hanger,
+ hslot, &pktbuf_tmp, 1);
+ ASSERT((ret == BCME_OK) && (pktbuf == pktbuf_tmp));
+ }
+ }
+ if (!waitevent) {
+ /* free the packet */
+ PKTFREE(wlfc->osh, pktbuf, TRUE);
+ }
+ }
+ /* pkt back from firmware side */
+ entry->transit_count--;
+ if (entry->suppressed && (--entry->suppr_transit_count == 0)) {
+ 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;
+}
+
+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];
+ }
+ }
+ }
+
+ return BCME_OK;
+}
+
+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);
+
+ /* 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);
+ memcpy(results, &htod, WLFC_CTL_VALUE_LEN_TXSTATUS);
+ if (WLFC_GET_REUSESEQ(dhd->wlfc_mode)) {
+ htodseq = DHD_PKTTAG_H2DSEQ(PKTTAG(pkt));
+ if (WL_SEQ_GET_FROMDRV(htodseq)) {
+ WL_SEQ_SET_FROMFW(htodseq, 1);
+ WL_SEQ_SET_FROMDRV(htodseq, 0);
+ }
+ 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);
+ }
+}
+
+
+static int
+_dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value)
+{
+ uint32 timestamp;
+
+ (void)dhd;
+
+ bcopy(&value[2], &timestamp, sizeof(uint32));
+ 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;
+ }
+}
+
+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;
+ }
+}
+
+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;
+}
+
+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;
+ 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) {
+ /* a fresh PS mode should wipe old ps credits? */
+ desc->requested_credit = 0;
+ if (type == WLFC_CTL_TYPE_MAC_OPEN) {
+ desc->state = WLFC_STATE_OPEN;
+ desc->ac_bitmap = 0xff;
+ DHD_WLFC_CTRINC_MAC_OPEN(desc);
+ _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;
+}
+
+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;
+}
+
+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<<AC_COUNT));
+ _dhd_wlfc_add_requested_entry(wlfc, desc);
+ }
+ else {
+ wlfc->stats.credit_request_failed++;
+ }
+ return BCME_OK;
+}
+
+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<<AC_COUNT));
+ _dhd_wlfc_add_requested_entry(wlfc, desc);
+ }
+ else {
+ wlfc->stats.packet_request_failed++;
+ }
+ return BCME_OK;
+}
+
+static void
+_dhd_wlfc_reorderinfo_indicate(uint8 *val, uint8 len, uchar *info_buf, uint *info_len)
+{
+ if (info_len) {
+ if (info_buf) {
+ 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->osh, WLFC_HANGER_MAXITEMS);
+ if (wlfc->hanger == NULL) {
+ DHD_OS_PREFREE(dhd, DHD_PREALLOC_DHD_WLFC_INFO,
+ 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 */
+ if (dhd->op_mode & DHD_FLAG_IBSS_MODE) {
+ dhd->wlfc_rxpkt_chk = FALSE;
+ } else {
+ dhd->wlfc_rxpkt_chk = TRUE;
+ }
+
+
+ /* 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_os_wlfc_unblock(dhd);
+
+ return rc;
+}
+
+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);
+ }
+
+ 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);
+ }
+ }
+ if (remainder != 0 && wlfc) {
+ /* trouble..., something is not right */
+ wlfc->stats.tlv_parse_failed++;
+ }
+ }
+
+ if (wlfc)
+ wlfc->stats.dhd_hdrpulls++;
+
+ dhd_os_wlfc_unblock(dhd);
+ return BCME_OK;
+}
+
+int
+dhd_wlfc_commit_packets(dhd_pub_t *dhdp, f_commitpkt_t fcommit, void* commit_ctx, void *pktbuf,
+ bool need_toggle_host_if)
+{
+ 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;
+
+ 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;
+
+#ifdef LIMIT_BORROW
+ int lender;
+#endif
+
+ 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 exit2;
+ }
+
+ ctx = (athost_wl_status_info_t*)dhdp->wlfc_state;
+
+
+ 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))
+ PKTFREE(ctx->osh, pktbuf, TRUE);
+ rc = BCME_OK;
+ }
+ goto exit;
+ }
+
+ 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.
+ */
+
+ if (pktbuf) {
+ ac = DHD_PKTTAG_FIFO(PKTTAG(pktbuf));
+ /* 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++;
+ }
+
+ 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;
+ while (FALSE == dhdp->proptxstatus_txoff) {
+ /* 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;
+ }
+ 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) {
+ break;
+ }
+
+ if (!dhdp->proptxstatus_credit_ignore) {
+ 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, fcommit,
+ commit_ctx);
+
+ /* Bus commits may fail (e.g. flow control); abort after retries */
+ if (rc == BCME_OK) {
+ if (commit_info.ac_fifo_credit_spent)
+ ctx->FIFO_credit[ac]--;
+ } else {
+ 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 ((lender = _dhd_wlfc_borrow_credit(ctx, AC_COUNT, ac)) == -1) {
+ 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,
+ fcommit, commit_ctx);
+
+ /* Bus commits may fail (e.g. flow control); abort after retries */
+ if (rc == BCME_OK) {
+
+ 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;
+ }
+ }
+ }
+
+exit:
+ if (need_toggle_host_if && ctx->toggle_host_if) {
+ ctx->toggle_host_if = 0;
+ }
+
+exit2:
+ dhd_os_wlfc_unblock(dhdp);
+ return rc;
+}
+
+int
+dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success)
+{
+ athost_wl_status_info_t* wlfc;
+ void* pout = NULL;
+ int rtn = BCME_OK;
+ if ((dhd == NULL) || (txp == 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)) {
+ 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;
+ }
+
+ if (!success || dhd->proptxstatus_txstatus_ignore) {
+ wlfc_mac_descriptor_t *entry = _dhd_wlfc_find_table_entry(wlfc, txp);
+
+ 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, 1);
+ 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);
+
+ entry->transit_count--;
+ if (entry->suppressed && (--entry->suppr_transit_count == 0)) {
+ entry->suppressed = FALSE;
+ }
+
+ PKTFREE(wlfc->osh, txp, TRUE);
+ wlfc->stats.pktout++;
+ } else {
+ /* bus confirmed pkt went to firmware side */
+ if (WLFC_GET_AFQ(dhd->wlfc_mode)) {
+ _dhd_wlfc_enque_afq(wlfc, txp);
+ } else {
+ int ret;
+ void *pktbuf_tmp = NULL;
+ int hslot = WL_TXSTATUS_GET_HSLOT(DHD_PKTTAG_H2DTAG(PKTTAG(txp)));
+ if (_dhd_wlfc_hanger_waitevent_decreturn(wlfc->hanger, hslot) == 0) {
+ ret = _dhd_wlfc_hanger_poppkt(wlfc->hanger, hslot, &pktbuf_tmp, 1);
+ BCM_REFERENCE(ret);
+ ASSERT((ret == BCME_OK) && pktbuf_tmp && (txp == pktbuf_tmp));
+
+ /* free the packet */
+ PKTFREE(wlfc->osh, txp, TRUE);
+ }
+ }
+ }
+
+EXIT:
+ dhd_os_wlfc_unblock(dhd);
+ return rtn;
+}
+
+int
+dhd_wlfc_init(dhd_pub_t *dhd)
+{
+ char iovbuf[14]; /* Room for "tlv" + '\0' + parameter */
+ /* 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 */
+ bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) {
+ DHD_ERROR(("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n"));
+ }
+ else {
+ /*
+ 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));
+ }
+
+ /* query caps */
+ ret = bcm_mkiovar("wlfc_mode", (char *)&mode, 4, iovbuf, sizeof(iovbuf));
+ if (ret > 0) {
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
+ }
+
+ if (ret >= 0) {
+ fw_caps = *((uint32 *)iovbuf);
+ mode = 0;
+ DHD_ERROR(("%s: query wlfc_mode succeed, fw_caps=0x%x\n", __FUNCTION__, fw_caps));
+
+ if (WLFC_IS_OLD_DEF(fw_caps)) {
+ /* enable proptxtstatus v2 by default */
+ mode = WLFC_MODE_AFQ;
+ } else {
+ WLFC_SET_AFQ(mode, WLFC_GET_AFQ(fw_caps));
+ WLFC_SET_REUSESEQ(mode, WLFC_GET_REUSESEQ(fw_caps));
+ WLFC_SET_REORDERSUPP(mode, WLFC_GET_REORDERSUPP(fw_caps));
+ }
+ ret = bcm_mkiovar("wlfc_mode", (char *)&mode, 4, iovbuf, sizeof(iovbuf));
+ if (ret > 0) {
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), 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));
+
+ dhd_os_wlfc_unblock(dhd);
+
+ if (dhd->plat_init)
+ dhd->plat_init((void *)dhd);
+
+ return BCME_OK;
+}
+
+int
+dhd_wlfc_hostreorder_init(dhd_pub_t *dhd)
+{
+ char iovbuf[14]; /* Room for "tlv" + '\0' + parameter */
+ /* 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 */
+ bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 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);
+
+ return BCME_OK;
+}
+
+#ifdef SUPPORT_P2P_GO_PS
+int
+dhd_wlfc_suspend(dhd_pub_t *dhd)
+{
+
+ uint32 iovbuf[4]; /* Room for "tlv" + '\0' + parameter */
+ uint32 tlv = 0;
+
+ DHD_TRACE(("%s: masking wlfc events\n", __FUNCTION__));
+ if (!dhd->wlfc_enabled)
+ return -1;
+
+ bcm_mkiovar("tlv", 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 bdcv2 tlv signaling\n", __FUNCTION__));
+ return -1;
+ }
+ tlv = iovbuf[0];
+ if ((tlv & (WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS)) == 0)
+ return 0;
+ tlv &= ~(WLFC_FLAGS_RSSI_SIGNALS | WLFC_FLAGS_XONXOFF_SIGNALS);
+ bcm_mkiovar("tlv", (char *)&tlv, 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 bdcv2 tlv signaling to 0x%x\n",
+ __FUNCTION__, tlv));
+ return -1;
+ }
+
+ return 0;
+}
+
+ int
+dhd_wlfc_resume(dhd_pub_t *dhd)
+{
+ uint32 iovbuf[4]; /* Room for "tlv" + '\0' + parameter */
+ uint32 tlv = 0;
+
+ DHD_TRACE(("%s: unmasking wlfc events\n", __FUNCTION__));
+ if (!dhd->wlfc_enabled)
+ return -1;
+
+ bcm_mkiovar("tlv", 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 bdcv2 tlv signaling\n", __FUNCTION__));
+ return -1;
+ }
+ tlv = iovbuf[0];
+ 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);
+ bcm_mkiovar("tlv", (char *)&tlv, 4, (char*)iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, (char*)iovbuf, sizeof(iovbuf), TRUE, 0) < 0) {
+ DHD_ERROR(("%s: failed to set bdcv2 tlv signaling to 0x%x\n",
+ __FUNCTION__, tlv));
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* SUPPORT_P2P_GO_PS */
+
+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;
+ }
+
+ _dhd_wlfc_cleanup_txq(dhd, fn, arg);
+
+ 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)
+{
+ char iovbuf[32]; /* Room for "ampdu_hostreorder" or "tlv" + '\0' + parameter */
+ /* cleanup all psq related resources */
+ athost_wl_status_info_t* wlfc;
+ uint32 tlv = 0;
+ uint32 hostreorder = 0;
+ int ret = BCME_OK;
+
+ 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 */
+ bcm_mkiovar("ampdu_hostreorder", NULL, 0, iovbuf, sizeof(iovbuf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
+ if (ret == BCME_OK)
+ hostreorder = *((uint32 *)iovbuf);
+ else {
+ hostreorder = 0;
+ DHD_ERROR(("%s():%d, ampdu_hostreorder get failed Err = %d\n",
+ __FUNCTION__, __LINE__, ret));
+ }
+
+ 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 */
+ bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
+ if (ret == BCME_OK) {
+ /*
+ Leaving the message for now, it should be removed after a while; once
+ the tlv situation is stable.
+ */
+ DHD_ERROR(("%s():%d successfully %s bdcv2 tlv signaling, %d\n",
+ __FUNCTION__, __LINE__,
+ dhd->wlfc_enabled?"enabled":"disabled", tlv));
+ } else
+ DHD_ERROR(("%s():%d failed to enable/disable bdcv2 tlv signaling Err = %d\n",
+ __FUNCTION__, __LINE__, ret));
+
+ 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;
+
+#ifdef PROP_TXSTATUS_DEBUG
+ 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) {
+ WLFC_DBGMESG(("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n",
+ __FUNCTION__, i, h->items[i].pkt,
+ DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt))));
+ }
+ }
+ }
+#endif
+
+ _dhd_wlfc_cleanup(dhd, NULL, NULL);
+
+ if (!WLFC_GET_AFQ(dhd->wlfc_mode)) {
+ /* delete hanger */
+ _dhd_wlfc_hanger_delete(dhd->osh, wlfc->hanger);
+ }
+
+
+ /* free top structure */
+ DHD_OS_PREFREE(dhd, DHD_PREALLOC_DHD_WLFC_INFO,
+ 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_os_wlfc_unblock(dhd);
+
+ if (dhd->plat_deinit)
+ dhd->plat_deinit((void *)dhd);
+ return BCME_OK;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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 = "<Unknown";
+ else
+ iftype_desc = iftypes[interfaces[i].iftype];
+
+ ea = interfaces[i].ea;
+ bcm_bprintf(strbuf, "INTERFACE[%d].ea = "
+ "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d, type: %s "
+ "netif_flow_control:%s\n", i,
+ ea[0], ea[1], ea[2], ea[3], ea[4], ea[5],
+ interfaces[i].interface_id,
+ iftype_desc, ((wlfc->hostif_flow_state[i] == OFF)
+ ? " OFF":" ON"));
+
+ bcm_bprintf(strbuf, "INTERFACE[%d].PSQ(len,state,credit),(trans,supp_trans)"
+ "= (%d,%s,%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);
+
+ 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)"
+ "= (%d,%s,%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);
+#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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+int dhd_wlfc_set_module_ignore(dhd_pub_t *dhd, int val)
+{
+ char iovbuf[14]; /* Room for "tlv" + '\0' + parameter */
+ 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 */
+ bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 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));
+ }
+ }
+ return BCME_OK;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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/drivers/net/wireless/bcmdhd/dhd_wlfc.h b/drivers/net/wireless/bcmdhd/dhd_wlfc.h
new file mode 100644
index 000000000000..330ac384997d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_wlfc.h
@@ -0,0 +1,513 @@
+/*
+* 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: dhd_wlfc.h 485659 2014-06-16 21:33:12Z $
+*
+*/
+#ifndef __wlfc_host_driver_definitions_h__
+#define __wlfc_host_driver_definitions_h__
+
+
+/* #define OOO_DEBUG */
+
+#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_WAIT_CLEAN 4
+
+#define WLFC_HANGER_ITEM_WAIT_EVENT_COUNT 2
+#define WLFC_HANGER_ITEM_WAIT_EVENT_INVALID 255
+
+typedef enum {
+ Q_TYPE_PSQ,
+ Q_TYPE_AFQ
+} q_type_t;
+
+typedef enum ewlfc_packet_state {
+ eWLFC_PKTTYPE_NEW,
+ eWLFC_PKTTYPE_DELAYED,
+ eWLFC_PKTTYPE_SUPPRESSED,
+ 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 waitevent; /* wait txstatus_update and txcomplete before free a packet */
+ uint8 pad;
+ uint32 identifier;
+ void* pkt;
+#ifdef PROP_TXSTATUS_DEBUG
+ uint32 push_time;
+#endif
+ struct wlfc_hanger_item *next;
+} wlfc_hanger_item_t;
+
+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
+#define WLFC_STATE_CLOSE 2
+
+#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 2048
+
+#define WLFC_FLOWCONTROL_HIWATER (2048 - 256)
+#define WLFC_FLOWCONTROL_LOWATER 256
+
+#define WLFC_LOG_BUF_SIZE (1024*1024)
+
+typedef struct wlfc_mac_descriptor {
+ uint8 occupied;
+ uint8 interface_id;
+ uint8 iftype;
+ uint8 state;
+ uint8 ac_bitmap; /* for APSD */
+ uint8 requested_credit;
+ uint8 requested_packet;
+ 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;
+ struct pktq psq;
+ /* packets at firmware */
+ 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;
+ /* Number of packets at dongle for this entry. */
+ uint transit_count;
+ /* Numbe of suppression to wait before evict from delayQ */
+ uint suppr_transit_count;
+ /* flag. TRUE when in suppress 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;
+
+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_FCMODE_NONE 0
+#define WLFC_FCMODE_IMPLIED_CREDIT 1
+#define WLFC_FCMODE_EXPLICIT_CREDIT 2
+#define WLFC_ONLY_AMPDU_HOSTREORDER 3
+
+/* 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
+
+typedef struct athost_wl_status_info {
+ uint8 last_seqid_to_wlc;
+
+ /* OSL handle */
+ osl_t* osh;
+ /* dhd pub */
+ void* dhdp;
+
+ /* stats */
+ athost_wl_stat_counters_t stats;
+
+ 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;
+ 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];
+ uint8 allow_fc;
+ 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 {
+ /*
+ 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 seq number for every suppress 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)
+
+typedef int (*f_commitpkt_t)(void* ctx, void* p);
+typedef bool (*f_processpkt_t)(void* p, void* arg);
+
+#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
+
+/* 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);
+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);
+int dhd_wlfc_hostreorder_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_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);
+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/drivers/net/wireless/bcmdhd/dngl_stats.h b/drivers/net/wireless/bcmdhd/dngl_stats.h
new file mode 100644
index 000000000000..9546e8042d70
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dngl_stats.h
@@ -0,0 +1,43 @@
+/*
+ * Common stats definitions for clients of dongle
+ * ports
+ *
+ * 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: dngl_stats.h 241182 2011-02-17 21:50:03Z $
+ */
+
+#ifndef _dngl_stats_h_
+#define _dngl_stats_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;
+
+#endif /* _dngl_stats_h_ */
diff --git a/drivers/net/wireless/bcmdhd/dngl_wlhdr.h b/drivers/net/wireless/bcmdhd/dngl_wlhdr.h
new file mode 100644
index 000000000000..8a254f44c9d6
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dngl_wlhdr.h
@@ -0,0 +1,40 @@
+/*
+ * Dongle WL Header 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: dngl_wlhdr.h 241182 2011-02-17 21:50:03Z $
+ */
+
+#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/drivers/net/wireless/bcmdhd/hndpmu.c b/drivers/net/wireless/bcmdhd/hndpmu.c
new file mode 100644
index 000000000000..8268afc90e0b
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/hndpmu.c
@@ -0,0 +1,282 @@
+/*
+ * Misc utility routines for accessing PMU corerev specific features
+ * of the SiliconBackplane-based Broadcom chips.
+ *
+ * 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: hndpmu.c 530682 2015-01-30 18:48:21Z $
+ */
+
+
+/*
+ * 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 <bcm_cfg.h>
+#include <typedefs.h>
+#include <bcmdefs.h>
+#include <osl.h>
+#include <bcmutils.h>
+#include <siutils.h>
+#include <bcmdevs.h>
+#include <hndsoc.h>
+#include <sbchipc.h>
+#include <hndpmu.h>
+
+#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)
+{
+ chipcregs_t *cc;
+ uint origidx, intr_val = 0;
+ 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 */
+
+ if (!(sih->cccaps & CC_CAP_PMU)) {
+ return;
+ }
+
+ /* Remember original core before switch to chipc */
+ cc = (chipcregs_t *) si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val);
+
+ switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) {
+ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
+ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab1;
+ str_mask = 0x30000000;
+ str_shift = 28;
+ break;
+ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
+ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
+ case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4):
+ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2;
+ str_mask = 0x00003800;
+ str_shift = 11;
+ break;
+ case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
+ case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11):
+ if (sih->pmurev == 8) {
+ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3;
+ }
+ else if (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(sih->chip, chn, 8), sih->chiprev, sih->pmurev));
+ break;
+ }
+
+ if (str_tab != NULL && cc != 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, &cc->chipcontrol_addr, PMU_CHIPCTL1);
+ cc_data_temp = R_REG(osh, &cc->chipcontrol_data);
+ cc_data_temp &= ~str_mask;
+ cc_data_temp |= str_tab[i].sel << str_shift;
+ W_REG(osh, &cc->chipcontrol_data, cc_data_temp);
+ if (str_ovr_pmuval) { /* enables the selected drive strength */
+ W_REG(osh, &cc->chipcontrol_addr, str_ovr_pmuctl);
+ OR_REG(osh, &cc->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_restore_core(sih, origidx, intr_val);
+} /* si_sdiod_drive_strength_init */
diff --git a/drivers/net/wireless/bcmdhd/include/Makefile b/drivers/net/wireless/bcmdhd/include/Makefile
new file mode 100644
index 000000000000..bc90f3cab224
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/Makefile
@@ -0,0 +1,53 @@
+#!/bin/bash
+#
+# This script serves following purpose:
+#
+# 1. It generates native version information by querying
+# automerger maintained database to see where src/include
+# came from
+# 2. For select components, as listed in compvers.sh
+# it generates component version files
+#
+# Copyright 2005, Broadcom, Inc.
+#
+# $Id: Makefile 347587 2012-07-27 09:13:31Z $
+#
+
+export SRCBASE:=..
+
+TARGETS := epivers.h
+
+ifdef VERBOSE
+export VERBOSE
+endif
+
+all release: epivers compvers
+
+# Generate epivers.h for native branch url
+epivers:
+ bash epivers.sh
+
+# Generate component versions based on component url
+compvers:
+ @if [ -s "compvers.sh" ]; then \
+ echo "Generating component versions, if any"; \
+ bash compvers.sh; \
+ else \
+ echo "Skipping component version generation"; \
+ fi
+
+# Generate epivers.h for native branch version
+clean_compvers:
+ @if [ -s "compvers.sh" ]; then \
+ echo "bash compvers.sh clean"; \
+ bash compvers.sh clean; \
+ else \
+ echo "Skipping component version clean"; \
+ fi
+
+clean:
+ rm -f $(TARGETS) *.prev
+
+clean_all: clean clean_compvers
+
+.PHONY: all release clean epivers compvers clean_compvers
diff --git a/drivers/net/wireless/bcmdhd/include/aidmp.h b/drivers/net/wireless/bcmdhd/include/aidmp.h
new file mode 100644
index 000000000000..95745e5178c5
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/aidmp.h
@@ -0,0 +1,387 @@
+/*
+ * Broadcom AMBA Interconnect 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: aidmp.h 530682 2015-01-30 18:48:21Z $
+ */
+
+#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
+
+
+#ifndef _LANGUAGE_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 */
+
+/* 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 0xa00
+#define AI_ERRLOGDONE 0xa04
+#define AI_ERRLOGSTATUS 0xa08
+#define AI_ERRLOGADDRLO 0xa0c
+#define AI_ERRLOGADDRHI 0xa10
+#define AI_ERRLOGID 0xa14
+#define AI_ERRLOGUSER 0xa18
+#define AI_ERRLOGFLAGS 0xa1c
+#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
+
+/* 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
+
+#endif /* _AIDMP_H */
diff --git a/drivers/net/wireless/bcmdhd/include/bcm_cfg.h b/drivers/net/wireless/bcmdhd/include/bcm_cfg.h
new file mode 100644
index 000000000000..1fe8da885396
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcm_cfg.h
@@ -0,0 +1,29 @@
+/*
+ * BCM common config options
+ *
+ * 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: bcm_cfg.h 351867 2012-08-21 18:46:16Z $
+ */
+
+#ifndef _bcm_cfg_h_
+#define _bcm_cfg_h_
+#endif /* _bcm_cfg_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h b/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h
new file mode 100644
index 000000000000..f13d94d8aceb
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcm_mpool_pub.h
@@ -0,0 +1,361 @@
+/*
+ * 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-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: bcm_mpool_pub.h 407097 2013-06-11 18:43:16Z $
+ */
+
+#ifndef _BCM_MPOOL_PUB_H
+#define _BCM_MPOOL_PUB_H 1
+
+#include <typedefs.h> /* 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.
+ *
+ */
+int 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/drivers/net/wireless/bcmdhd/include/bcmcdc.h b/drivers/net/wireless/bcmdhd/include/bcmcdc.h
new file mode 100644
index 000000000000..a70ab3f9d044
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmcdc.h
@@ -0,0 +1,132 @@
+/*
+ * CDC network driver ioctl/indication encoding
+ * Broadcom 802.11abg Networking Device Driver
+ *
+ * Definitions subject to change without notice.
+ *
+ * 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: bcmcdc.h 318308 2012-03-02 02:23:42Z $
+ */
+#ifndef _bcmcdc_h_
+#define _bcmcdc_h_
+#include <proto/ethernet.h>
+
+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/drivers/net/wireless/bcmdhd/include/bcmdefs.h b/drivers/net/wireless/bcmdhd/include/bcmdefs.h
new file mode 100644
index 000000000000..a53a793a0d0f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmdefs.h
@@ -0,0 +1,348 @@
+/*
+ * Misc system wide 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: bcmdefs.h 433011 2013-10-30 09:19:54Z $
+ */
+
+#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).
+ */
+
+#define bcmreclaimed 0
+#define _data _data
+#define _fn _fn
+#define BCMPREATTACHDATA(_data) _data
+#define BCMPREATTACHFN(_fn) _fn
+#define _data _data
+#define _fn _fn
+#define _fn _fn
+#define BCMNMIATTACHFN(_fn) _fn
+#define BCMNMIATTACHDATA(_data) _data
+#define CONST const
+
+#undef BCM47XX_CA9
+
+#ifndef BCMFASTPATH
+#if defined(BCM47XX_CA9)
+#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
+
+
+
+/* Put some library data/code into ROM to reduce RAM requirements */
+#define _data _data
+#define BCMROMDAT_NAME(_data) _data
+#define _fn _fn
+#define _fn _fn
+#define STATIC static
+#define BCMROMDAT_ARYSIZ(data) ARRAYSIZE(data)
+#define BCMROMDAT_SIZEOF(data) sizeof(data)
+#define BCMROMDAT_APATCH(data)
+#define BCMROMDAT_SPATCH(data)
+
+/* 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
+
+/* 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
+
+/* 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_0 0xffffffff /* Address mask for 0-bits (hi-part) */
+
+#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)
+
+#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 */
+
+/* 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(BCM47XX_CA9)
+#define BCMEXTRAHDROOM 224
+#else
+#define BCMEXTRAHDROOM 204
+#endif /* linux && BCM47XX_CA9 */
+#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 <NAME>_M BITFIELD_MASK(3)
+ * #define <NAME>_S 4
+ * ...
+ * regval = R_REG(osh, &regs->regfoo);
+ * field = GFIELD(regval, <NAME>);
+ * regval = SFIELD(regval, <NAME>, 1);
+ * W_REG(osh, &regs->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
+#define MAXSZ_NVRAM_VARS 4096
+#endif
+
+
+
+/* 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 BCMSPLITRX /* BCMLFRAG support enab macros */
+ extern bool _bcmsplitrx;
+ #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD)
+ #define BCMSPLITRX_ENAB() (_bcmsplitrx)
+ #elif defined(BCMSPLITRX_DISABLED)
+ #define BCMSPLITRX_ENAB() (0)
+ #else
+ #define BCMSPLITRX_ENAB() (1)
+ #endif
+#else
+ #define BCMSPLITRX_ENAB() (0)
+#endif /* BCMSPLITRX */
+#ifdef BCM_SPLITBUF
+ extern bool _bcmsplitbuf;
+ #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD)
+ #define BCM_SPLITBUF_ENAB() (_bcmsplitbuf)
+ #elif defined(BCM_SPLITBUF_DISABLED)
+ #define BCM_SPLITBUF_ENAB() (0)
+ #else
+ #define BCM_SPLITBUF_ENAB() (1)
+ #endif
+#else
+ #define BCM_SPLITBUF_ENAB() (0)
+#endif /* BCM_SPLITBUF */
+/* 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 */
+
+#ifdef BCMUSBDEV_ENABLED
+extern uint32 gFWID;
+#endif
+
+
+#endif /* _bcmdefs_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmdevs.h b/drivers/net/wireless/bcmdhd/include/bcmdevs.h
new file mode 100644
index 000000000000..99958bf541d4
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmdevs.h
@@ -0,0 +1,688 @@
+/*
+ * Broadcom device-specific manifest constants.
+ *
+ * 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: bcmdevs.h 475454 2014-05-05 20:54:58Z $
+ */
+
+#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_BDC_PID 0x0bdc
+#define BCM_DNGL_JTAG_PID 0x4a44
+
+/* HW USB BLOCK [CPULESS USB] PIDs */
+#define BCM_HWUSB_PID_43239 43239
+
+/* PCI Device IDs */
+#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_D11G_ID 0x4318 /* 4318 802.11b/g id */
+#define BCM4318_D11DUAL_ID 0x4319 /* 4318 802.11a/b/g 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_D11G_ID 0x4320 /* 4306 802.11g */
+#define BCM4306_D11A_ID 0x4321 /* 4306 802.11a */
+#define BCM4306_UART_ID 0x4322 /* 4306 uart */
+#define BCM4306_V90_ID 0x4323 /* 4306 v90 codec */
+#define BCM4306_D11DUAL_ID 0x4324 /* 4306 dual A+B */
+#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 BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */
+#define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db device */
+#define BCM43226_D11N_ID 0x4354 /* 43226 802.11n dualband 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 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 */
+
+/* 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 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 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 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 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) */
+#define BCM4712_MIPS_ID 0x4720 /* 4712 base devid */
+#define BCM4716_DEVICE_ID 0x4722 /* 4716 base devid */
+#define BCM47XX_USB30H_ID 0x472a /* 47xx usb 3.0 host */
+#define BCM47XX_USB30D_ID 0x472b /* 47xx usb 3.0 device */
+#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 */
+
+/* Chip IDs */
+#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 BCM4313_CHIP_ID 0x4313 /* 4313 chip id */
+#define BCM43131_CHIP_ID 43131 /* 43131 chip id (OTP 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 BCM43217_CHIP_ID 43217 /* 43217 chip id (OTP 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 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 BCM43226_CHIP_ID 43226 /* 43226 chipcommon chipid */
+#define BCM43231_CHIP_ID 43231 /* 43231 chipcommon chipid (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 BCM4325_CHIP_ID 0x4325 /* 4325 chip id */
+#define BCM4328_CHIP_ID 0x4328 /* 4328 chip id */
+#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */
+#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 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 BCM43556_CHIP_ID 0xAA24 /* 43556 chipcommon chipid */
+#define BCM43558_CHIP_ID 0xAA26 /* 43558 chipcommon chipid */
+#define BCM43566_CHIP_ID 0xAA2E /* 43566 chipcommon chipid */
+#define BCM43568_CHIP_ID 0xAA30 /* 43568 chipcommon chipid */
+#define BCM43569_CHIP_ID 0xAA31 /* 43569 chipcommon chipid */
+#define BCM4350_CHIP(chipid) ((CHIPID(chipid) == BCM4350_CHIP_ID) || \
+ (CHIPID(chipid) == BCM4354_CHIP_ID) || \
+ (CHIPID(chipid) == BCM4356_CHIP_ID) || \
+ (CHIPID(chipid) == BCM43556_CHIP_ID) || \
+ (CHIPID(chipid) == BCM43558_CHIP_ID) || \
+ (CHIPID(chipid) == BCM43566_CHIP_ID) || \
+ (CHIPID(chipid) == BCM43568_CHIP_ID) || \
+ (CHIPID(chipid) == BCM43569_CHIP_ID)) /* 4350 variations */
+#define BCM4345_CHIP_ID 0x4345 /* 4345 chipcommon chipid */
+#define BCM43430_CHIP_ID 43430 /* 43430 chipcommon chipid */
+
+#define BCM43602_CHIP_ID 0xaa52 /* 43602 chipcommon chipid */
+
+#define BCM4342_CHIP_ID 4342 /* 4342 chipcommon chipid (OTP, RBBU) */
+#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 BCM53018_CHIP_ID 53018 /* 53018 chipcommon chipid */
+#define BCM4707_CHIP(chipid) (((chipid) == BCM4707_CHIP_ID) || ((chipid) == BCM53018_CHIP_ID))
+#define BCM4710_CHIP_ID 0x4710 /* 4710 chipid */
+#define BCM4712_CHIP_ID 0x4712 /* 4712 chipcommon chipid */
+#define BCM4716_CHIP_ID 0x4716 /* 4716 chipcommon chipid */
+#define BCM47162_CHIP_ID 47162 /* 47162 chipcommon chipid */
+#define BCM4748_CHIP_ID 0x4748 /* 4716 chipcommon chipid (OTP, RBBU) */
+#define 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 BCM5354_CHIP_ID 0x5354 /* 5354 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 */
+
+/* Package IDs */
+#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 */
+#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 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)
+
+/* 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 13 radio disable indication, UNUSED */
+#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_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_UNUSED 0x00000200
+#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_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_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 */
+
+/* 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 */
+
+/* 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 */
+
+
+/* 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 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
+
+/* 43602 Boards, unclear yet what boards will be created. */
+#define BCM943602RSVD1_SSID 0x06a5
+#define BCM943602RSVD2_SSID 0x06a6
+
+/* # 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/drivers/net/wireless/bcmdhd/include/bcmendian.h b/drivers/net/wireless/bcmdhd/include/bcmendian.h
new file mode 100644
index 000000000000..48b6e669949e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmendian.h
@@ -0,0 +1,329 @@
+/*
+ * Byte order utilities
+ *
+ * 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: bcmendian.h 402715 2013-05-16 18:50:09Z $
+ *
+ * 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 <typedefs.h>
+
+/* 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/drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h b/drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h
new file mode 100644
index 000000000000..23ef576ba66f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmmsgbuf.h
@@ -0,0 +1,261 @@
+/*
+ * MSGBUF network driver ioctl/indication encoding
+ * Broadcom 802.11abg Networking Device Driver
+ *
+ * Definitions subject to change without notice.
+ *
+ * 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: bcmmsgbuf.h 452261 2014-01-29 19:30:23Z $
+ */
+#ifndef _bcmmsgbuf_h_
+#define _bcmmsgbuf_h_
+#include <proto/ethernet.h>
+#include <wlioctl.h>
+#include <bcmpcie.h>
+#define MSGBUF_MAX_MSG_SIZE ETHER_MAX_LEN
+#define DNGL_TO_HOST_MSGBUF_SZ (8 * 1024) /* Host side ring */
+#define HOST_TO_DNGL_MSGBUF_SZ (8 * 1024) /* Host side ring */
+#define DTOH_LOCAL_MSGBUF_SZ (8 * 1024) /* dongle side ring */
+#define HTOD_LOCAL_MSGBUF_SZ (8 * 1024) /* dongle side ring */
+#define HTOD_LOCAL_CTRLRING_SZ (1 * 1024) /* H2D control ring dongle side */
+#define DTOH_LOCAL_CTRLRING_SZ (1 * 1024) /* D2H control ring dongle side */
+#define HOST_TO_DNGL_CTRLRING_SZ (1 * 1024) /* Host to Device ctrl ring on host */
+#define DNGL_TO_HOST_CTRLRING_SZ (1 * 1024) /* Device to host ctrl ring on host */
+
+enum {
+ DNGL_TO_HOST_MSGBUF,
+ HOST_TO_DNGL_MSGBUF
+};
+
+enum {
+ MSG_TYPE_IOCTL_REQ = 0x1,
+ MSG_TYPE_IOCTLPTR_REQ,
+ MSG_TYPE_IOCTL_CMPLT,
+ MSG_TYPE_WL_EVENT,
+ MSG_TYPE_TX_POST,
+ MSG_TYPE_RXBUF_POST,
+ MSG_TYPE_RX_CMPLT,
+ MSG_TYPE_TX_STATUS,
+ MSG_TYPE_EVENT_PYLD,
+ MSG_TYPE_IOCT_PYLD, /* used only internally inside dongle */
+ MSG_TYPE_RX_PYLD, /* used only internally inside dongle */
+ MSG_TYPE_TX_PYLD, /* To be removed once split header is implemented */
+ MSG_TYPE_HOST_EVNT,
+ MSG_TYPE_LOOPBACK = 15, /* dongle loops the message back to host */
+ MSG_TYPE_LPBK_DMAXFER = 16, /* dongle DMA loopback */
+ MSG_TYPE_TX_BATCH_POST = 17
+};
+
+enum {
+ HOST_TO_DNGL_DATA,
+ HOST_TO_DNGL_CTRL,
+ DNGL_TO_HOST_DATA,
+ DNGL_TO_HOST_CTRL
+};
+
+#define MESSAGE_PAYLOAD(a) (((a) == MSG_TYPE_IOCT_PYLD) | ((a) == MSG_TYPE_RX_PYLD) |\
+ ((a) == MSG_TYPE_EVENT_PYLD) | ((a) == MSG_TYPE_TX_PYLD))
+#define MESSAGE_CTRLPATH(a) (((a) == MSG_TYPE_IOCTL_REQ) | ((a) == MSG_TYPE_IOCTLPTR_REQ) |\
+ ((a) == MSG_TYPE_IOCTL_CMPLT) | ((a) == MSG_TYPE_HOST_EVNT) |\
+ ((a) == MSG_TYPE_LOOPBACK) | ((a) == MSG_TYPE_WL_EVENT))
+
+/* IOCTL req Hdr */
+/* cmn Msg Hdr */
+typedef struct cmn_msg_hdr {
+ uint16 msglen;
+ uint8 msgtype;
+ uint8 ifidx;
+ union seqn {
+ uint32 seq_id;
+ struct sequence {
+ uint16 seq_no;
+ uint8 ring_id;
+ uint8 rsvd;
+ } seq;
+ } u;
+} cmn_msg_hdr_t;
+
+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;
+
+/* ret buf struct */
+typedef struct ret_buf_ptr {
+ uint32 low_addr;
+ uint32 high_addr;
+} ret_buf_t;
+
+/* Complete msgbuf hdr for ioctl from host to dongle */
+typedef struct ioct_reqst_hdr {
+ cmn_msg_hdr_t msg;
+ ioctl_req_hdr_t ioct_hdr;
+ ret_buf_t ret_buf;
+} ioct_reqst_hdr_t;
+
+typedef struct ioctptr_reqst_hdr {
+ cmn_msg_hdr_t msg;
+ ioctl_req_hdr_t ioct_hdr;
+ 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;
+ uint32 pkt_id;
+ uint32 status;
+ uint32 ret_len;
+ uint32 inline_data;
+ uint16 xt_id; /* transaction ID */
+ uint16 rsvd[1];
+} 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 evet 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
+
+#endif /* _bcmmsgbuf_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmnvram.h b/drivers/net/wireless/bcmdhd/include/bcmnvram.h
new file mode 100644
index 000000000000..3f145f271881
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmnvram.h
@@ -0,0 +1,272 @@
+/*
+ * NVRAM variable manipulation
+ *
+ * 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: bcmnvram.h 428512 2013-10-09 02:12:11Z $
+ */
+
+#ifndef _bcmnvram_h_
+#define _bcmnvram_h_
+
+#ifndef _LANGUAGE_ASSEMBLY
+
+#include <typedefs.h>
+#include <bcmdefs.h>
+
+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);
+
+/*
+ * 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);
+ 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);
+ 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);
+
+/*
+ * 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/drivers/net/wireless/bcmdhd/include/bcmpcie.h b/drivers/net/wireless/bcmdhd/include/bcmpcie.h
new file mode 100644
index 000000000000..f243fc30e7a8
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmpcie.h
@@ -0,0 +1,129 @@
+/*
+ * Broadcom PCIE
+ * Software-specific definitions shared between device and host side
+ * Explains the shared area between host and dongle
+ * 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: bcmpcie.h 452261 2014-01-29 19:30:23Z $
+ */
+
+#ifndef _bcmpcie_h_
+#define _bcmpcie_h_
+
+#include <circularbuf.h>
+
+#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;
+
+#define PCIE_SHARED_VERSION 0x0003
+#define PCIE_SHARED_VERSION_MASK 0x00FF
+#define PCIE_SHARED_ASSERT_BUILT 0x0100
+#define PCIE_SHARED_ASSERT 0x0200
+#define PCIE_SHARED_TRAP 0x0400
+#define PCIE_SHARED_IN_BRPT 0x0800
+#define PCIE_SHARED_SET_BRPT 0x1000
+#define PCIE_SHARED_PENDING_BRPT 0x2000
+#define PCIE_SHARED_HTOD_SPLIT 0x4000
+#define PCIE_SHARED_DTOH_SPLIT 0x8000
+
+typedef struct ring_mem {
+ uint8 idx;
+ uint8 rsvd;
+ uint16 size;
+ sh_addr_t base_addr;
+} ring_mem_t;
+
+#define RINGSTATE_INITED 1
+
+typedef struct ring_state {
+ uint8 idx;
+ uint8 state;
+ uint16 r_offset;
+ uint16 w_offset;
+ uint16 e_offset;
+} ring_state_t;
+
+
+typedef struct ring_info {
+ uint8 h2d_ring_count;
+ uint8 d2h_ring_count;
+ uint8 rsvd[2];
+ /* locations in the TCM where the ringmem is and ringstate are defined */
+ uint32 ringmem_ptr; /* h2d_ring_count + d2h_ring_count */
+ uint32 ring_state_ptr; /* h2d_ring_count + d2h_ring_count */
+} ring_info_t;
+
+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 hndrte_cons_t */
+ uint32 msgtrace_addr;
+ uint32 fwid;
+
+ /* Used for debug/flow control */
+ uint16 total_lfrag_pkt_cnt;
+ uint16 max_host_rxbufs;
+ uint32 rsvd1;
+
+ uint32 dma_rxoffset;
+
+ /* 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 dongle to push the status into */
+ sh_addr_t device_rings_stsblk;
+ uint32 device_rings_stsblk_len;
+
+} pciedev_shared_t;
+
+
+/* H2D mail box Data */
+#define H2D_HOST_D3_INFORM 0x00000001
+#define H2D_HOST_DS_ACK 0x00000002
+
+/* D2H mail box Data */
+#define D2H_DEV_D3_ACK 0x00000001
+#define D2H_DEV_DS_ENTER_REQ 0x00000002
+#define D2H_DEV_DS_EXIT_NOTE 0x00000004
+
+
+extern pciedev_shared_t pciedev_shared;
+#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)
+
+#endif /* _bcmpcie_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmpcispi.h b/drivers/net/wireless/bcmdhd/include/bcmpcispi.h
new file mode 100644
index 000000000000..54d0ce0831e2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmpcispi.h
@@ -0,0 +1,181 @@
+/*
+ * Broadcom PCI-SPI Host Controller Register 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: bcmpcispi.h 241182 2011-02-17 21:50:03Z $
+ */
+#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/drivers/net/wireless/bcmdhd/include/bcmperf.h b/drivers/net/wireless/bcmdhd/include/bcmperf.h
new file mode 100644
index 000000000000..1911d8a3e27a
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmperf.h
@@ -0,0 +1,36 @@
+/*
+ * Performance counters software interface.
+ *
+ * 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: bcmperf.h 241182 2011-02-17 21:50:03Z $
+ */
+/* 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/drivers/net/wireless/bcmdhd/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h
new file mode 100644
index 000000000000..28d30c027ef8
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h
@@ -0,0 +1,143 @@
+/*
+ * Definitions for API from sdio common code (bcmsdh) to individual
+ * host controller drivers.
+ *
+ * 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: bcmsdbus.h 408158 2013-06-17 22:15:35Z $
+ */
+
+#ifndef _sdio_api_h_
+#define _sdio_api_h_
+
+
+#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 40
+#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
+
+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 *);
+
+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_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);
+
+#endif /* _sdio_api_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh.h b/drivers/net/wireless/bcmdhd/include/bcmsdh.h
new file mode 100644
index 000000000000..8062bf735b90
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdh.h
@@ -0,0 +1,251 @@
+/*
+ * SDIO host client driver interface of Broadcom HNBU
+ * export functions to client drivers
+ * abstract OS and BUS specific details of SDIO
+ *
+ * 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: bcmsdh.h 662739 2016-11-08 09:20:31Z $
+ */
+
+/**
+ * @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)
+#define BCMSDH_INFO(x)
+
+#if (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 *);
+
+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 */
+};
+
+/* 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);
+
+/* 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, uint32 addr, uint size);
+extern uint32 bcmsdh_reg_write(void *sdh, uint32 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 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/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h
new file mode 100644
index 000000000000..2891b8521eb4
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h
@@ -0,0 +1,117 @@
+/*
+ * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
+ *
+ * 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: bcmsdh_sdmmc.h 444019 2013-12-18 08:36:54Z $
+ */
+
+#ifndef __BCMSDH_SDMMC_H__
+#define __BCMSDH_SDMMC_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_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];
+
+};
+
+/************************************************************
+ * 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);
+#endif /* __BCMSDH_SDMMC_H__ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h
new file mode 100644
index 000000000000..26d064fcd9cc
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h
@@ -0,0 +1,281 @@
+/*
+ * Broadcom SDIO/PCMCIA
+ * Software-specific definitions shared between device and host side
+ *
+ * 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: bcmsdpcm.h 414378 2013-07-24 15:58:50Z $
+ */
+
+#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 */
+#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_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_FC_CHANGE | I_HMB_FRAME_IND | I_HMB_HOST_INT)
+
+/* tohostmailbox bits corresponding to intstatus bits */
+#define HMB_FC_ON (1 << 0) /* To Host Mailbox Flow Control State */
+#define HMB_FC_CHANGE (1 << 1) /* To Host Mailbox Flow Control State Changed */
+#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 */
+
+#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
+
+typedef struct {
+ uint32 flags;
+ uint32 trap_addr;
+ uint32 assert_exp_addr;
+ uint32 assert_file_addr;
+ uint32 assert_line;
+ uint32 console_addr; /* Address of hndrte_cons_t */
+ uint32 msgtrace_addr;
+ uint32 fwid;
+} sdpcm_shared_t;
+
+extern sdpcm_shared_t sdpcm_shared;
+
+/* Function can be used to notify host of FW halt */
+extern void sdpcmd_fwhalt(void);
+
+#endif /* _bcmsdpcm_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdspi.h b/drivers/net/wireless/bcmdhd/include/bcmsdspi.h
new file mode 100644
index 000000000000..3c3a16048043
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdspi.h
@@ -0,0 +1,135 @@
+/*
+ * SD-SPI Protocol Conversion - BCMSDH->SPI Translation 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: bcmsdspi.h 294363 2011-11-06 23:02:20Z $
+ */
+#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/drivers/net/wireless/bcmdhd/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h
new file mode 100644
index 000000000000..3624aaba5171
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h
@@ -0,0 +1,282 @@
+/*
+ * 'Standard' SDIO HOST CONTROLLER driver
+ *
+ * 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: bcmsdstd.h 623513 2016-03-08 06:22:05Z $
+ */
+#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/drivers/net/wireless/bcmdhd/include/bcmspi.h b/drivers/net/wireless/bcmdhd/include/bcmspi.h
new file mode 100644
index 000000000000..3d44d715871f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmspi.h
@@ -0,0 +1,40 @@
+/*
+ * Broadcom SPI Low-Level Hardware Driver API
+ *
+ * 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: bcmspi.h 241182 2011-02-17 21:50:03Z $
+ */
+#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/drivers/net/wireless/bcmdhd/include/bcmspibrcm.h b/drivers/net/wireless/bcmdhd/include/bcmspibrcm.h
new file mode 100644
index 000000000000..5483012f09fb
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmspibrcm.h
@@ -0,0 +1,162 @@
+/*
+ * SD-SPI Protocol Conversion - BCMSDH->gSPI Translation 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: bcmspibrcm.h 373331 2012-12-07 04:46:22Z $
+ */
+#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/drivers/net/wireless/bcmdhd/include/bcmsrom_fmt.h b/drivers/net/wireless/bcmdhd/include/bcmsrom_fmt.h
new file mode 100644
index 000000000000..98b9a4d0ea4f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmsrom_fmt.h
@@ -0,0 +1,633 @@
+/*
+ * SROM format definition.
+ *
+ * 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: bcmsrom_fmt.h 427005 2013-10-02 00:15:10Z $
+ */
+
+#ifndef _bcmsrom_fmt_h_
+#define _bcmsrom_fmt_h_
+
+#define SROM_MAXREV 11 /* max revisiton supported by driver */
+
+/* Maximum srom: 6 Kilobits == 768 bytes */
+#define SROM_MAX 768
+#define SROM_MAXW 384
+#define VARS_MAX 4096
+
+/* 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 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 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 Terrmal 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_SIGN 64
+#define SROM11_CRCREV 233
+
+#define SROM11_WORDS 234
+#define SROM11_SIGNATURE 0x0634
+
+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/drivers/net/wireless/bcmdhd/include/bcmsrom_tbl.h b/drivers/net/wireless/bcmdhd/include/bcmsrom_tbl.h
new file mode 100644
index 000000000000..12ae7284fd59
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmsrom_tbl.h
@@ -0,0 +1,1014 @@
+/*
+ * Table that encodes the srom formats for PCI/PCIe NICs.
+ *
+ * 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: bcmsrom_tbl.h 427005 2013-10-02 00:15:10Z $
+ */
+
+#ifndef _bcmsrom_tbl_h_
+#define _bcmsrom_tbl_h_
+
+#include "sbpcmcia.h"
+#include "wlioctl.h"
+
+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 consective 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[] = {
+#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, 0x00ff},
+ {"regrev", 0x000000e0, 0, SROM5_REGREV, 0x00ff},
+ {"regrev", 0x00000700, 0, SROM8_REGREV, 0x00ff},
+ {"ledbh0", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff},
+ {"ledbh1", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00},
+ {"ledbh2", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff},
+ {"ledbh3", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00},
+ {"ledbh0", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff},
+ {"ledbh1", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00},
+ {"ledbh2", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff},
+ {"ledbh3", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00},
+ {"ledbh0", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff},
+ {"ledbh1", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00},
+ {"ledbh2", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff},
+ {"ledbh3", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00},
+ {"ledbh0", 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},
+ {"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},
+ /* 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, 0x00ff},
+ {"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},
+ /* 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},
+ /* 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},
+
+ {"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},
+ {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", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_2G_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX, SROM11_2G_PA + 2, 0xffff},
+ {"rxgains5gmelnagaina", 0xfffff800, 0, SROM11_RXGAINS1, 0x0007},
+ {"rxgains5gmtrisoa", 0xfffff800, 0, SROM11_RXGAINS1, 0x0078},
+ {"rxgains5gmtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS1, 0x0080},
+ {"rxgains5ghelnagaina", 0xfffff800, 0, SROM11_RXGAINS1, 0x0700},
+ {"rxgains5ghtrisoa", 0xfffff800, 0, SROM11_RXGAINS1, 0x7800},
+ {"rxgains5ghtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS1, 0x8000},
+ {"rxgains2gelnagaina", 0xfffff800, 0, SROM11_RXGAINS, 0x0007},
+ {"rxgains2gtrisoa", 0xfffff800, 0, SROM11_RXGAINS, 0x0078},
+ {"rxgains2gtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS, 0x0080},
+ {"rxgains5gelnagaina", 0xfffff800, 0, SROM11_RXGAINS, 0x0700},
+ {"rxgains5gtrisoa", 0xfffff800, 0, SROM11_RXGAINS, 0x7800},
+ {"rxgains5gtrelnabypa", 0xfffff800, 0, SROM11_RXGAINS, 0x8000},
+ {"maxp5ga", 0xfffff800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0x00ff},
+ {"", 0xfffff800, SRFL_ARRAY, SROM11_5GB1B0_MAXP, 0xff00},
+ {"", 0xfffff800, SRFL_ARRAY, SROM11_5GB3B2_MAXP, 0x00ff},
+ {"", 0xfffff800, 0, SROM11_5GB3B2_MAXP, 0xff00},
+ {"pa5ga", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB0_PA + 2, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB1_PA + 2, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB2_PA + 2, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX | SRFL_ARRAY, SROM11_5GB3_PA + 1, 0xffff},
+ {"", 0xfffff800, SRFL_PRHEX, SROM11_5GB3_PA + 2, 0xffff},
+
+ {NULL, 0, 0, 0, 0}
+};
+
+#if !(defined(PHY_TYPE_HT) && defined(PHY_TYPE_N) && defined(PHY_TYPE_LP))
+#define PHY_TYPE_HT 7 /* HT-Phy value */
+#define PHY_TYPE_N 4 /* N-Phy value */
+#define PHY_TYPE_LP 5 /* LP-Phy value */
+#endif /* !(defined(PHY_TYPE_HT) && defined(PHY_TYPE_N) && defined(PHY_TYPE_LP)) */
+#if !defined(PHY_TYPE_AC)
+#define PHY_TYPE_AC 11 /* AC-Phy value */
+#endif /* !defined(PHY_TYPE_AC) */
+#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"},
+ /* LPPHY */
+ {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_2G, 0, "pa0b0 pa0b1 pa0b2"},
+ {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GL, 0, "pa1lob0 pa1lob1 pa1lob2"},
+ {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GM, 0, "pa1b0 pa1b1 pa1b2"},
+ {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GH, 0, "pa1hib0 pa1hib1 pa1hib2"},
+ /* 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"},
+ {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, ""}
+};
+
+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 */
+ 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 */
+
+static const cis_tuple_t cis_hnbuvars[] = {
+ {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, 13, "4boardflags 4boardflags2 4boardflags3"},
+ {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, 2, "1regrev"},
+ {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, 5, "2cckbw202gpo 2cckbw20ul2gpo"},
+ {HNBU_LEGOFDMBW202GPO, 0xffffffff, 9, "4legofdmbw202gpo 4legofdmbw20ul2gpo"},
+ {HNBU_LEGOFDMBW205GPO, 0xffffffff, 25, "4legofdmbw205glpo 4legofdmbw20ul5glpo "
+ "4legofdmbw205gmpo 4legofdmbw20ul5gmpo 4legofdmbw205ghpo 4legofdmbw20ul5ghpo"},
+ {HNBU_MCS2GPO, 0xffffffff, 13, "4mcsbw202gpo 4mcsbw20ul2gpo 4mcsbw402gpo"},
+ {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, 5, "2dot11agofdmhrbw202gpo 2ofdmlrbw202gpo"},
+ {HNBU_ACPPR_5GPO, 0xfffff800, 31, "4mcsbw805glpo 4mcsbw1605glpo 4mcsbw805gmpo "
+ "4mcsbw1605gmpo 4mcsbw805ghpo 4mcsbw1605ghpo 2mcslr5glpo 2mcslr5gmpo 2mcslr5ghpo"},
+ {HNBU_ACPPR_SBPO, 0xfffff800, 33, "2sb20in40hrpo 2sb20in80and160hr5glpo "
+ "2sb40and80hr5glpo 2sb20in80and160hr5gmpo 2sb40and80hr5gmpo 2sb20in80and160hr5ghpo "
+ "2sb40and80hr5ghpo 2sb20in40lrpo 2sb20in80and160lr5glpo 2sb40and80lr5glpo "
+ "2sb20in80and160lr5gmpo 2sb40and80lr5gmpo 2sb20in80and160lr5ghpo 2sb40and80lr5ghpo "
+ "2dot11agduphrpo 2dot11agduplrpo"},
+ {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_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"},
+ {0xFF, 0xffffffff, 0, ""}
+};
+
+#endif /* _bcmsrom_tbl_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmutils.h b/drivers/net/wireless/bcmdhd/include/bcmutils.h
new file mode 100644
index 000000000000..add3f252b28e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmutils.h
@@ -0,0 +1,1204 @@
+/*
+ * Misc useful os-independent macros and functions.
+ *
+ * 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: bcmutils.h 490613 2014-07-11 05:23:34Z $
+ */
+
+#ifndef _bcmutils_h_
+#define _bcmutils_h_
+
+#define bcm_strcpy_s(dst, noOfElements, src) strcpy((dst), (src))
+#define bcm_strncpy_s(dst, noOfElements, src, count) strncpy((dst), (src), (count))
+#define bcm_strcat_s(dst, noOfElements, src) strcat((dst), (src))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef PKTQ_LOG
+#include <wlioctl.h>
+#endif
+
+/* 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))
+
+/* 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 */
+};
+
+/* ** driver-only section ** */
+#ifdef BCMDRIVER
+#include <osl.h>
+
+#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; \
+ } \
+}
+
+/* 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;
+
+typedef struct {
+ uint32 _prec_log;
+ pktq_counters_t* _prec_cnt[PKTQ_MAX_PREC]; /* Counters per queue */
+} pktq_log_t;
+#endif /* PKTQ_LOG */
+
+
+#define PKTQ_COMMON \
+ 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];
+#ifdef PKTQ_LOG
+ pktq_log_t* pktqlog;
+#endif
+};
+
+/* 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 if */
+typedef bool (*ifpkt_cb_t)(void*, int);
+
+#ifdef BCMPKTPOOL
+#define POOL_ENAB(pool) ((pool) && (pool)->inited)
+#define SHARED_POOL (pktpool_shared)
+#else /* BCMPKTPOOL */
+#define POOL_ENAB(bus) 0
+#define SHARED_POOL ((struct pktpool *)NULL)
+#endif /* BCMPKTPOOL */
+
+#ifdef BCMFRAGPOOL
+#define SHARED_FRAG_POOL (pktpool_shared_lfrag)
+#endif
+#define SHARED_RXFRAG_POOL (pktpool_shared_rxlfrag)
+
+
+#ifndef PKTPOOL_LEN_MAX
+#define PKTPOOL_LEN_MAX 40
+#endif /* PKTPOOL_LEN_MAX */
+#define PKTPOOL_CB_MAX 3
+
+struct pktpool;
+typedef void (*pktpool_cb_t)(struct pktpool *pool, void *arg);
+typedef struct {
+ pktpool_cb_t cb;
+ void *arg;
+} pktpool_cbinfo_t;
+/* call back fn extension to populate host address in pool pkt */
+typedef int (*pktpool_cb_extn_t)(struct pktpool *pool, void *arg, void* pkt);
+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 */
+
+ 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, excluding lbuf|lbuf_frag */
+
+ bool empty;
+ uint8 cbtoggle;
+ uint8 cbcnt;
+ uint8 ecbcnt;
+ bool emptycb_disable;
+ pktpool_cbinfo_t *availcb_excl;
+ pktpool_cbinfo_t cbs[PKTPOOL_CB_MAX];
+ pktpool_cbinfo_t ecbs[PKTPOOL_CB_MAX];
+ pktpool_cbextn_info_t cbext;
+#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_t;
+
+extern pktpool_t *pktpool_shared;
+#ifdef BCMFRAGPOOL
+extern pktpool_t *pktpool_shared_lfrag;
+#endif
+extern pktpool_t *pktpool_shared_rxlfrag;
+
+/* 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);
+int pktpool_hostaddr_fill_register(pktpool_t *pktp, pktpool_cb_extn_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)
+#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) */
+extern pktpool_t *pktpools_registry[PKTPOOL_MAXIMUM_ID + 1];
+
+/* Pool ID to/from Pool Pointer converters */
+#define PKTPOOL_ID2PTR(id) (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 */
+
+/* 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);
+
+/* 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_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len)
+#define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max)
+#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0)
+
+#define pktq_ppeek(pq, prec) ((pq)->q[prec].head)
+#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail)
+
+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);
+/* Empty the queue at particular precedence level */
+extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir,
+ ifpkt_cb_t fn, int arg);
+/* 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_avail(pq) ((int)((pq)->max - (pq)->len))
+#define pktq_full(pq) ((pq)->len >= (pq)->max)
+#define pktq_empty(pq) ((pq)->len == 0)
+
+/* 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 pktqinit(pq, len) pktq_init(((struct pktq *)(void *)pq), 1, len)
+
+extern void pktq_init(struct pktq *pq, int num_prec, int max_len);
+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);
+extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg);
+
+/* 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);
+
+/* Get priority from a packet and pass it back in scb (or equiv) */
+#define PKTPRIO_VDSCP 0x100 /* DSCP prio found after 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);
+
+/* 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 *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);
+
+
+/* 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 */
+#define NVRAM_RECLAIM_CHECK(name)
+
+extern char *getvar(char *vars, const char *name);
+extern int getintvar(char *vars, const char *name);
+extern int getintvararray(char *vars, const char *name, int index);
+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 bcmtslog(tstamp, fmt, a1, a2)
+#define bcmprinttslogs()
+#define bcmprinttstamp(us)
+#define bcmdumptslog(buf, size)
+
+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 */
+ uint16 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);
+#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 */
+
+/* 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_LAST BCME_IE_NOTFOUND
+
+#define BCME_NOTENABLED BCME_DISABLED
+
+/* 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", \
+}
+
+#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 <stddef.h>
+#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 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 */
+
+#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() */
+
+
+/* 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 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]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC2STR(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]
+#define MACSTR "%02x:%02x:%02x"
+#define MAC2STR(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 */
+
+/* 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, uchar *buf, uint len);
+
+/* IE parsing */
+
+/* tag_ID/length/value_buffer tuple */
+typedef struct bcm_tlv {
+ uint8 id;
+ uint8 len;
+ uint8 data[1];
+} bcm_tlv_t;
+
+/* bcm tlv w/ 16 bit id/len */
+typedef struct bcm_xtlv {
+ uint16 id;
+ uint16 len;
+ uint8 data[1];
+} bcm_xtlv_t;
+
+/* descriptor of xtlv data src or dst */
+typedef struct {
+ uint16 type;
+ uint16 len;
+ void *ptr; /* ptr to memory location */
+} xtlv_desc_t;
+
+/* set a var from xtlv buffer */
+typedef int
+(bcm_set_var_from_tlv_cbfn_t)(void *ctx, void **tlv_buf, uint16 type, uint16 len);
+
+struct bcm_tlvbuf {
+ uint16 size;
+ uint8 *head; /* point to head of buffer */
+ uint8 *buf; /* current position of buffer */
+ /* followed by the allocated buffer */
+};
+
+#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))
+#define BCM_XTLV_LEN(elt) ltoh16_ua(&(elt->len))
+#define BCM_XTLV_ID(elt) ltoh16_ua(&(elt->id))
+#define BCM_XTLV_SIZE(elt) (BCM_XTLV_HDR_SIZE + BCM_XTLV_LEN(elt))
+
+/* 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)))
+
+#define bcm_valid_xtlv(elt, buflen) (\
+ ((int)(buflen) >= (int)BCM_XTLV_HDR_SIZE) && \
+ ((int)(buflen) >= (int)BCM_XTLV_SIZE(elt)))
+
+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_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 */
+extern bcm_xtlv_t *bcm_next_xtlv(bcm_xtlv_t *elt, int *buflen);
+extern struct bcm_tlvbuf *bcm_xtlv_buf_alloc(void *osh, uint16 len);
+extern void bcm_xtlv_buf_free(void *osh, struct bcm_tlvbuf *tbuf);
+extern uint16 bcm_xtlv_buf_len(struct bcm_tlvbuf *tbuf);
+extern uint16 bcm_xtlv_buf_rlen(struct bcm_tlvbuf *tbuf);
+extern uint8 *bcm_xtlv_buf(struct bcm_tlvbuf *tbuf);
+extern uint8 *bcm_xtlv_head(struct bcm_tlvbuf *tbuf);
+extern int bcm_xtlv_put_data(struct bcm_tlvbuf *tbuf, uint16 type, const void *data, uint16 dlen);
+extern int bcm_xtlv_put_8(struct bcm_tlvbuf *tbuf, uint16 type, const int8 data);
+extern int bcm_xtlv_put_16(struct bcm_tlvbuf *tbuf, uint16 type, const int16 data);
+extern int bcm_xtlv_put_32(struct bcm_tlvbuf *tbuf, uint16 type, const int32 data);
+extern int bcm_unpack_xtlv_entry(void **tlv_buf, uint16 xpct_type, uint16 xpct_len, void *dst);
+extern int bcm_skip_xtlv(void **tlv_buf);
+extern int bcm_pack_xtlv_entry(void **tlv_buf, uint16 *buflen, uint16 type, uint16 len, void *src);
+extern int bcm_unpack_xtlv_buf(void *ctx,
+ void *tlv_buf, uint16 buflen, bcm_set_var_from_tlv_cbfn_t *cbfn);
+extern int
+bcm_unpack_xtlv_buf_to_mem(void *tlv_buf, int *buflen, xtlv_desc_t *items);
+extern int
+bcm_pack_xtlv_buf_from_mem(void **tlv_buf, uint16 *buflen, xtlv_desc_t *items);
+extern int
+bcm_pack_xtlv_entry_from_hex_string(void **tlv_buf, uint16 *buflen, uint16 type, char *hex);
+
+/* bcmerror */
+extern const char *bcmerrorstr(int bcmerror);
+
+/* 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, 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(char *name, char *data, uint datalen, char *buf, uint len);
+
+unsigned int process_nvram_vars(char *varbuf, unsigned int len);
+
+/* 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 u32)
+{
+ /* function local scope declaration of const _CSBTBL[] */
+ const uint8 * p = (const uint8 *)&u32;
+ 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 u32)
+{
+ int shifts = 0;
+ while (u32) {
+ shifts++; u32 >>= 1;
+ }
+ return (32U - shifts);
+}
+
+#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 u32)
+{
+#if defined(__USE_ASM_CLZ__)
+ int zeros;
+ __asm__ volatile("clz %0, %1 \n" : "=r" (zeros) : "r" (u32));
+ return zeros;
+#else /* C equivalent */
+ return C_bcm_count_leading_zeros(u32);
+#endif /* C equivalent */
+}
+
+/* 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. */
+#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);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#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 */
+
+#endif /* _bcmutils_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/brcm_nl80211.h b/drivers/net/wireless/bcmdhd/include/brcm_nl80211.h
new file mode 100644
index 000000000000..9892b9cc8685
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/brcm_nl80211.h
@@ -0,0 +1,56 @@
+/*
+ * Definitions for nl80211 testmode access to host driver
+ *
+ * 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: brcm_nl80211.h 454792 2014-02-11 20:40:19Z $
+ *
+ */
+
+#ifndef _brcm_nl80211_h_
+#define _brcm_nl80211_h_
+
+struct bcm_nlmsg_hdr {
+ uint cmd; /* common ioctl definition */
+ uint len; /* attached 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/drivers/net/wireless/bcmdhd/include/circularbuf.h b/drivers/net/wireless/bcmdhd/include/circularbuf.h
new file mode 100644
index 000000000000..2d35599342f6
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/circularbuf.h
@@ -0,0 +1,115 @@
+/*
+ * Initialization and support routines for self-booting compressed image.
+ *
+ * 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: circularbuf.h 452261 2014-01-29 19:30:23Z $
+ */
+
+#ifndef __CIRCULARBUF_H_INCLUDED__
+#define __CIRCULARBUF_H_INCLUDED__
+
+#include <osl.h>
+#include <typedefs.h>
+#include <bcmendian.h>
+
+/* Enumerations of return values provided by MsgBuf implementation */
+typedef enum {
+ CIRCULARBUF_FAILURE = -1,
+ CIRCULARBUF_SUCCESS
+} circularbuf_ret_t;
+
+/* Core circularbuf circular buffer structure */
+typedef struct circularbuf_s
+{
+ uint16 depth; /* Depth of circular buffer */
+ uint16 r_ptr; /* Read Ptr */
+ uint16 w_ptr; /* Write Ptr */
+ uint16 e_ptr; /* End Ptr */
+ uint16 wp_ptr; /* wp_ptr/pending - scheduled for DMA. But, not yet complete. */
+ uint16 rp_ptr; /* rp_ptr/pending - scheduled for DMA. But, not yet complete. */
+
+ uint8 *buf_addr;
+ void *mb_ctx;
+ void (*mb_ring_bell)(void *ctx);
+} circularbuf_t;
+
+#define CBUF_ERROR_VAL 0x00000001 /* Error level tracing */
+#define CBUF_TRACE_VAL 0x00000002 /* Function level tracing */
+#define CBUF_INFORM_VAL 0x00000004 /* debug level tracing */
+
+extern int cbuf_msg_level;
+
+#define CBUF_ERROR(args) do {if (cbuf_msg_level & CBUF_ERROR_VAL) printf args;} while (0)
+#define CBUF_TRACE(args) do {if (cbuf_msg_level & CBUF_TRACE_VAL) printf args;} while (0)
+#define CBUF_INFO(args) do {if (cbuf_msg_level & CBUF_INFORM_VAL) printf args;} while (0)
+
+#define CIRCULARBUF_START(x) ((x)->buf_addr)
+#define CIRCULARBUF_WRITE_PTR(x) ((x)->w_ptr)
+#define CIRCULARBUF_READ_PTR(x) ((x)->r_ptr)
+#define CIRCULARBUF_END_PTR(x) ((x)->e_ptr)
+
+#define circularbuf_debug_print(handle) \
+ CBUF_INFO(("%s:%d:\t%p rp=%4d r=%4d wp=%4d w=%4d e=%4d\n", \
+ __FUNCTION__, __LINE__, \
+ (void *) CIRCULARBUF_START(handle), \
+ (int) (handle)->rp_ptr, (int) (handle)->r_ptr, \
+ (int) (handle)->wp_ptr, (int) (handle)->w_ptr, \
+ (int) (handle)->e_ptr));
+
+
+/* Callback registered by application/mail-box with the circularbuf implementation.
+ * This will be invoked by the circularbuf implementation when write is complete and
+ * ready for informing the peer
+ */
+typedef void (*mb_ring_t)(void *ctx);
+
+
+/* Public Functions exposed by circularbuf */
+void
+circularbuf_init(circularbuf_t *handle, void *buf_base_addr, uint16 total_buf_len);
+void
+circularbuf_register_cb(circularbuf_t *handle, mb_ring_t mb_ring_func, void *ctx);
+
+/* Write Functions */
+void *
+circularbuf_reserve_for_write(circularbuf_t *handle, uint16 size);
+void
+circularbuf_write_complete(circularbuf_t *handle, uint16 bytes_written);
+
+/* Read Functions */
+void *
+circularbuf_get_read_ptr(circularbuf_t *handle, uint16 *avail_len);
+circularbuf_ret_t
+circularbuf_read_complete(circularbuf_t *handle, uint16 bytes_read);
+
+/*
+ * circularbuf_get_read_ptr() updates rp_ptr by the amount that the consumer
+ * is supposed to read. The consumer may not read the entire amount.
+ * In such a case, circularbuf_revert_rp_ptr() call follows a corresponding
+ * circularbuf_get_read_ptr() call to revert the rp_ptr back to
+ * the point till which data has actually been processed.
+ * It is not valid if it is preceded by multiple get_read_ptr() calls
+ */
+circularbuf_ret_t
+circularbuf_revert_rp_ptr(circularbuf_t *handle, uint16 bytes);
+
+#endif /* __CIRCULARBUF_H_INCLUDED__ */
diff --git a/drivers/net/wireless/bcmdhd/include/dbus.h b/drivers/net/wireless/bcmdhd/include/dbus.h
new file mode 100644
index 000000000000..841830097945
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/dbus.h
@@ -0,0 +1,582 @@
+/*
+ * Dongle BUS interface Abstraction layer
+ * target serial buses like USB, SDIO, SPI, etc.
+ *
+ * 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.h 423346 2013-09-11 22:38:40Z $
+ */
+
+#ifndef __DBUS_H__
+#define __DBUS_H__
+
+#include "typedefs.h"
+
+#define DBUSTRACE(args)
+#define DBUSERR(args)
+#define DBUSINFO(args)
+#define DBUSDBGLOCK(args)
+
+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
+};
+
+#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
+};
+
+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_TXRXQUEUE
+};
+typedef struct {
+ uint32 config_id;
+ union {
+ bool rxctl_deferrespok;
+ struct {
+ int maxrxq;
+ int rxbufsize;
+ int maxtxq;
+ int txbufsize;
+ } txrxqueue;
+ };
+} 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, 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);
+ bool (*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 dbus_pub_t *dbus_attach(struct osl_info *osh, int rxsize, int nrxq, int ntxq,
+ void *cbarg, dbus_callbacks_t *cbs, dbus_extdl_t *extdl, struct shared_info *sh);
+extern void dbus_detach(dbus_pub_t *pub);
+
+extern int dbus_up(dbus_pub_t *pub);
+extern int dbus_down(dbus_pub_t *pub);
+extern int dbus_stop(dbus_pub_t *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(dbus_pub_t *pub, uint8 *buf, int len);
+extern int dbus_recv_ctl(dbus_pub_t *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_attrib(dbus_pub_t *pub, dbus_attrib_t *attrib);
+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 dbus_iovar_op(dbus_pub_t *pub, 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;
+ int len;
+ void *pkt;
+ 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, 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/drivers/net/wireless/bcmdhd/include/devctrl_if/wlioctl_defs.h b/drivers/net/wireless/bcmdhd/include/devctrl_if/wlioctl_defs.h
new file mode 100644
index 000000000000..d85298b9297c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/devctrl_if/wlioctl_defs.h
@@ -0,0 +1,1987 @@
+/*
+ * Custom OID/ioctl definitions for
+ * Broadcom 802.11abg Networking Device Driver
+ *
+ * Definitions subject to change without notice.
+ *
+ * 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: wlioctl_defs.h 403826 2013-05-22 16:40:55Z $
+ */
+
+
+#ifndef wlioctl_defs_h
+#define wlioctl_defs_h
+
+
+
+
+
+/* All builds use the new 11ac ratespec/chanspec */
+#undef D11AC_IOTYPES
+#define D11AC_IOTYPES
+
+/* WL_RSPEC defines for rate information */
+#define WL_RSPEC_RATE_MASK 0x000000FF /* rate or HT MCS value */
+#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 both 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 */
+
+/* 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
+
+/* 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 HIGHEST_SINGLE_STREAM_MCS 7 /* MCS values greater than this enable multiple streams */
+
+#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_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
+
+#define WL_BSSTYPE_INFRA 1
+#define WL_BSSTYPE_INDEP 0
+#define WL_BSSTYPE_ANY 2
+
+/* 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 */
+
+/* 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_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. */
+
+#define PLC_CMD_FAILOVER 1
+#define PLC_CMD_MAC_COST 2
+#define PLC_CMD_LINK_COST 3
+#define PLC_CMD_NODE_LIST 4
+
+#define NODE_TYPE_UNKNOWN 0 /* Unknown link */
+#define NODE_TYPE_WIFI_ONLY 1 /* Pure Wireless STA node */
+#define NODE_TYPE_PLC_ONLY 2 /* Pure PLC only node */
+#define NODE_TYPE_WIFI_PLC 3 /* WiFi PLC capable node */
+
+/* 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 */
+
+/* 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
+
+#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 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 */
+
+/* wsec macros for operating on the above definitions */
+#define WSEC_WEP_ENABLED(wsec) ((wsec) & WEP_ENABLED)
+#define WSEC_TKIP_ENABLED(wsec) ((wsec) & TKIP_ENABLED)
+#define WSEC_AES_ENABLED(wsec) ((wsec) & AES_ENABLED)
+
+#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
+#define WSEC_SES_OW_ENABLED(wsec) ((wsec) & SES_OW_ENABLED)
+
+#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 */
+//#define WPA2_AUTH_MFP 0x1000 /* MFP (11w) in contrast to CCX */
+#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 WPA_AUTH_PFN_ANY 0xffffffff /* for PFN, match only ssid */
+
+/* pmkid */
+#define MAXPMKID 16
+
+#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)
+#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 */ /* for WAPI, deprecated use iovar instead */
+/* #define WLC_SET_WAI_RESTRICT 314 */ /* for WAPI, deprecated use iovar instead */
+/* #define WLC_SET_WAI_REKEY 315 */ /* for WAPI, deprecated use iovar instead */
+#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_LAST 322
+#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 */
+
+/* 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
+
+/* MAC list modes */
+#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)
+
+/* 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_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)
+
+/* 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
+
+/* 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_ACI_MAX_MODE 15
+
+/* 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_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_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 3 /* max 3 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
+
+/* 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
+
+/* 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 0x00000800 /* retired in TOT on 6/10/2009 */
+#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 0x00020000 /* retired in TOT on 6/10/2009 */
+#define WL_LOFT_VAL 0x00040000 /* retired in TOT on 6/10/2009 */
+#define WL_REGULATORY_VAL 0x00080000
+#define WL_PHYCAL_VAL 0x00100000 /* retired in TOT on 6/10/2009 */
+#define WL_RADAR_VAL 0x00200000 /* retired in TOT on 6/10/2009 */
+#define WL_MPC_VAL 0x00400000
+#define WL_APSTA_VAL 0x00800000
+#define WL_DFS_VAL 0x01000000
+#define WL_BA_VAL 0x02000000 /* retired in TOT on 6/14/2010 */
+#define WL_ACI_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
+
+/* 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
+#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_BTA_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_NIC_VAL 0x00800000
+#define WL_MQ_VAL 0x01000000
+
+/* This level is currently used in Phoenix2 only */
+#define WL_SRSCAN_VAL 0x02000000
+
+#define WL_WNM_VAL 0x04000000
+#define WL_PWRSEL_VAL 0x10000000
+#define WL_NET_DETECT_VAL 0x20000000
+#define WL_PCIE_VAL 0x40000000
+
+/* 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 0x7f /* behavior mask */
+#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
+/* number of bytes needed to define a mask for MAC event reporting */
+#define WL_EVENTING_MASK_LEN (((WLC_E_LAST) / 8) + (((WLC_E_LAST % 8) > 0) ? 1 : 0))
+
+
+/* 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 */
+
+#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 */
+
+/* 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) */
+#define WL_NUMCHANSPECS 110
+
+/* 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_MASK 0xff
+
+#define WL_PKTENG_SYNCHRONOUS 0x100 /* synchronous flag */
+
+#define WL_PKTENG_MAXPKTSZ 16384 /* max pktsz limit for pkteng */
+
+#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_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_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_CUSTOM_FLAG 0x100 /* allow custom IE id */
+
+#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_BTA 4
+#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
+#define CCASTATS_MAX 9
+
+#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_MAX 0x00000200
+
+#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
+
+#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
+
+#define PFN_VERSION 2
+#define PFN_SCANRESULT_VERSION 1
+#define MAX_PFN_LIST_COUNT 16
+
+#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 WL_PFN_SUPPRESSFOUND_MASK 0x08
+#define WL_PFN_SUPPRESSLOST_MASK 0x10
+#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_RESERVED 0xfffffffe /* Remaining reserved for future use */
+
+#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
+
+/* 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 MAX_NUM_WOL_PATTERN 16 /* LOGO requirements min 16 */
+
+/* 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_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_NEG (1U<<30)
+
+
+/* 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_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
+
+#endif /* wlioctl_defs_h */
diff --git a/drivers/net/wireless/bcmdhd/include/dhdioctl.h b/drivers/net/wireless/bcmdhd/include/dhdioctl.h
new file mode 100644
index 000000000000..770de78f5a30
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/dhdioctl.h
@@ -0,0 +1,135 @@
+/*
+ * 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-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: dhdioctl.h 454792 2014-02-11 20:40:19Z $
+ */
+
+#ifndef _dhdioctl_h_
+#define _dhdioctl_h_
+
+#include <typedefs.h>
+
+
+/* require default structure packing */
+#define BWL_DEFAULT_PACKING
+#include <packed_section_start.h>
+
+
+/* Linux network driver ioctl encoding */
+typedef struct dhd_ioctl {
+ uint cmd; /* common ioctl definition */
+ void *buf; /* pointer to user buffer */
+ uint len; /* length of user buffer */
+ bool set; /* get or set request (optional) */
+ uint used; /* bytes read or written (optional) */
+ uint needed; /* bytes needed (optional) */
+ uint driver; /* to identify target driver */
+} 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
+
+#define DHD_IOCTL_MAXLEN 8192 /* 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_WL_VAL 0x10000
+#define DHD_NOCHECKDIED_VAL 0x20000 /* UTF WAR */
+#define DHD_WL_VAL2 0x40000
+#define DHD_PNO_VAL 0x80000
+
+#ifdef SDTEST
+/* For pktgen iovar */
+typedef struct dhd_pktgen {
+ uint version; /* To allow structure change tracking */
+ uint freq; /* Max ticks between tx/rx attempts */
+ uint count; /* Test packets to send/rcv each attempt */
+ uint print; /* Print counts every <print> attempts */
+ uint total; /* Total packets (or bursts) */
+ uint minlen; /* Minimum length of packets to send */
+ uint maxlen; /* Maximum length of packets to send */
+ uint numsent; /* Count of test packets sent */
+ uint numrcvd; /* Count of test packets received */
+ uint numfail; /* Count of test send failures */
+ uint mode; /* Test mode (type of test packets) */
+ uint stop; /* Stop after this many tx failures */
+} 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) */
+
+
+/* require default structure packing */
+#include <packed_section_end.h>
+
+#endif /* _dhdioctl_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h
new file mode 100644
index 000000000000..31e5a916b17f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/epivers.h
@@ -0,0 +1,48 @@
+/*
+ * 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: epivers.h.in,v 13.33 2010-09-08 22:08:53 $
+ *
+*/
+
+#ifndef _epivers_h_
+#define _epivers_h_
+
+#define EPI_MAJOR_VERSION 1
+
+#define EPI_MINOR_VERSION 141
+
+#define EPI_RC_NUMBER 100
+
+#define EPI_INCREMENTAL_NUMBER 6
+
+#define EPI_BUILD_NUMBER 0
+
+#define EPI_VERSION 1, 141, 100, 6
+
+#define EPI_VERSION_NUM 0x018d6406
+
+#define EPI_VERSION_DEV 1.141.100
+
+/* Driver Version String, ASCII, 32 chars max */
+#define EPI_VERSION_STR "1.141.100.6 (r)"
+
+#endif /* _epivers_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/hndpmu.h b/drivers/net/wireless/bcmdhd/include/hndpmu.h
new file mode 100644
index 000000000000..c0d83101c750
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/hndpmu.h
@@ -0,0 +1,36 @@
+/*
+ * HND SiliconBackplane PMU support.
+ *
+ * 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: hndpmu.h 431134 2013-10-22 18:25:42Z $
+ */
+
+#ifndef _hndpmu_h_
+#define _hndpmu_h_
+
+
+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);
+
+#endif /* _hndpmu_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h b/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h
new file mode 100644
index 000000000000..39fdf0f5895c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h
@@ -0,0 +1,88 @@
+/*
+ * HNDRTE arm trap handling.
+ *
+ * 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: hndrte_armtrap.h 261365 2011-05-24 20:42:23Z $
+ */
+
+#ifndef _hndrte_armtrap_h
+#define _hndrte_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_4T__)
+#define MAX_TRAP_TYPE (TR_FIQ + 1)
+#elif defined(__ARM_ARCH_7M__)
+#define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS)
+#endif /* __ARM_ARCH_7M__ */
+
+/* The trap structure is defined here as offsets for assembly */
+#define TR_TYPE 0x00
+#define TR_EPC 0x04
+#define TR_CPSR 0x08
+#define TR_SPSR 0x0c
+#define TR_REGS 0x10
+#define TR_REG(n) (TR_REGS + (n) * 4)
+#define TR_SP TR_REG(13)
+#define TR_LR TR_REG(14)
+#define TR_PC TR_REG(15)
+
+#define TRAP_T_SIZE 80
+
+#ifndef _LANGUAGE_ASSEMBLY
+
+#include <typedefs.h>
+
+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 /* _hndrte_armtrap_h */
diff --git a/drivers/net/wireless/bcmdhd/include/hndrte_cons.h b/drivers/net/wireless/bcmdhd/include/hndrte_cons.h
new file mode 100644
index 000000000000..5cecea53cff2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/hndrte_cons.h
@@ -0,0 +1,78 @@
+/*
+ * Console support for hndrte.
+ *
+ * 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: hndrte_cons.h 427140 2013-10-02 18:07:07Z $
+ */
+#ifndef _HNDRTE_CONS_H
+#define _HNDRTE_CONS_H
+
+#include <typedefs.h>
+
+#if defined(RWL_DONGLE) || defined(UART_REFLECTOR)
+/* For Dongle uart tranport max cmd len is 256 bytes + header length (16 bytes)
+ * In case of ASD commands we are not sure about how much is the command size
+ * To be on the safe side, input buf len CBUF_LEN is increased to max (512) bytes.
+ */
+#define RWL_MAX_DATA_LEN (512 + 8) /* allow some extra bytes for '/n' termination */
+#define CBUF_LEN (RWL_MAX_DATA_LEN + 64) /* allow 64 bytes for header ("rwl...") */
+#else
+#define CBUF_LEN (128)
+#endif /* RWL_DONGLE || UART_REFLECTOR */
+
+#define LOG_BUF_LEN 1024
+
+typedef struct {
+ uint32 buf; /* Can't be pointer on (64-bit) hosts */
+ uint buf_size;
+ uint idx;
+ uint out_idx; /* output index */
+} hndrte_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.
+ */
+ hndrte_log_t log;
+
+ /* Console input line buffer
+ * Characters are read one at a time into cbuf until <CR> is received, then
+ * the buffer is processed as a command line. Also used for virtual UART.
+ */
+ uint cbuf_idx;
+ char cbuf[CBUF_LEN];
+} hndrte_cons_t;
+
+hndrte_cons_t *hndrte_get_active_cons_state(void);
+
+#endif /* _HNDRTE_CONS_H */
diff --git a/drivers/net/wireless/bcmdhd/include/hndsoc.h b/drivers/net/wireless/bcmdhd/include/hndsoc.h
new file mode 100644
index 000000000000..7b32f9627b31
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/hndsoc.h
@@ -0,0 +1,282 @@
+/*
+ * Broadcom HND chip & on-chip-interconnect-related 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: hndsoc.h 432420 2013-10-28 14:14:02Z $
+ */
+
+#ifndef _HNDSOC_H
+#define _HNDSOC_H
+
+/* Include the soci specific files */
+#include <sbconfig.h>
+#include <aidmp.h>
+
+/*
+ * 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_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_ARM_FLASH1 0xffff0000 /* ARM Flash Region 1 */
+#define SI_ARM_FLASH1_SZ 0x00010000 /* ARM Size of Flash Region 1 */
+
+#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
+ */
+/* 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 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 */
+
+/* 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 fast clock 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 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
+
+#ifndef _LANGUAGE_ASSEMBLY
+int soc_boot_dev(void *sih);
+int soc_knl_dev(void *sih);
+#endif /* _LANGUAGE_ASSEMBLY */
+
+#endif /* _HNDSOC_H */
diff --git a/drivers/net/wireless/bcmdhd/include/linux_osl.h b/drivers/net/wireless/bcmdhd/include/linux_osl.h
new file mode 100644
index 000000000000..ba989be9b165
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/linux_osl.h
@@ -0,0 +1,763 @@
+/*
+ * Linux OS Independent 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: linux_osl.h 657415 2016-09-01 05:45:34Z $
+ */
+
+#ifndef _linux_osl_h_
+#define _linux_osl_h_
+
+#include <typedefs.h>
+
+/* 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;
+
+/* 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
+
+/* 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)
+extern uint osl_pci_bus(osl_t *osh);
+extern uint osl_pci_slot(osl_t *osh);
+extern struct pci_dev *osl_pci_device(osl_t *osh);
+
+/* 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;
+
+#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 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 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_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, uint pa, uint size, int direction);
+
+/* API for DMA addressing capability */
+#define OSL_DMADDRWIDTH(osh, addrwidth) ({BCM_REFERENCE(osh); BCM_REFERENCE(addrwidth);})
+
+#if 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)
+#else
+ #define OSL_CACHE_FLUSH(va, len) BCM_REFERENCE(va)
+ #define OSL_CACHE_INV(va, len) BCM_REFERENCE(va)
+ #define OSL_PREFETCH(ptr) prefetch(ptr)
+#endif
+
+/* register access macros */
+ #include <bcmsdh.h>
+ #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))))
+
+ #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
+
+#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 <linuxver.h> /* use current 2.4.x calling conventions */
+#include <linux/kernel.h> /* for vsn/printf's */
+#include <linux/string.h> /* for mem*, str* */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29)
+#define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies))
+#else
+#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ))
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) */
+#define printf(fmt, args...) printk(fmt , ## args)
+#include <linux/kernel.h> /* for vsn/printf's */
+#include <linux/string.h> /* 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 */
+
+#define R_REG(osh, r) (\
+ SELECT_BUS_READ(osh, \
+ ({ \
+ __typeof(*(r)) __osl_v; \
+ 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)) \
+)
+
+#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)
+
+#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_nocache((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 <linuxver.h> /* 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
+#define PKTGET(osh, len, send) osl_pktget((osh), (len))
+#define PKTDUP(osh, skb) osl_pktdup((osh), (skb))
+#endif /* BCMDBG_CTRACE */
+#define PKTLIST_DUMP(osh, buf) BCM_REFERENCE(osh)
+#define PKTDBG_TRACE(osh, pkt, bit) BCM_REFERENCE(osh)
+#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send))
+#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)
+#define PKTORPHAN(skb) skb_orphan(skb)
+#else
+#define PKTORPHAN(skb) ({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;
+ 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, 36)
+#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 */
+
+#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 */
+
+extern void osl_pktfree(osl_t *osh, void *skb, bool send);
+extern void *osl_pktget_static(osl_t *osh, uint len);
+extern void osl_pktfree_static(osl_t *osh, void *skb, bool send);
+
+#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
+extern void *osl_pkt_frmnative(osl_t *osh, void *skb);
+extern void *osl_pktget(osl_t *osh, uint len);
+extern void *osl_pktdup(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 DMA_MAP(osh, va, size, direction, p, dmah) \
+ osl_dma_map((osh), (va), (size), (direction), (p), (dmah))
+
+#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 <stdlib.h>
+
+/* str* and mem* functions */
+#include <string.h>
+
+/* *printf functions */
+#include <stdio.h>
+
+/* 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 */
+
+#endif /* _linux_osl_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h
new file mode 100644
index 000000000000..15071c901e6c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/linuxver.h
@@ -0,0 +1,754 @@
+/*
+ * 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-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: linuxver.h 656961 2016-08-30 13:20:42Z $
+ */
+
+#ifndef _linuxver_h_
+#define _linuxver_h_
+
+#include <typedefs.h>
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
+#include <linux/config.h>
+#else
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33))
+#include <generated/autoconf.h>
+#else
+#include <linux/autoconf.h>
+#endif
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */
+#include <linux/module.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
+#include <linux/kconfig.h>
+#endif
+
+#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 <linux/malloc.h>
+#else
+#include <linux/slab.h>
+#endif
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+#include <linux/semaphore.h>
+#else
+#include <asm/semaphore.h>
+#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 <asm/io.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41))
+#include <linux/workqueue.h>
+#else
+#include <linux/tqueue.h>
+#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 <linux/sched.h>
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+#include <linux/sched/rt.h>
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
+#include <net/lib80211.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
+#include <linux/ieee80211.h>
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
+#include <net/ieee80211.h>
+#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(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_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 <linux/time.h>
+#include <linux/wait.h>
+#else
+#include <linux/sched.h>
+
+#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)) */
+
+#endif /* _linuxver_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/miniopt.h b/drivers/net/wireless/bcmdhd/include/miniopt.h
new file mode 100644
index 000000000000..18e181364db3
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/miniopt.h
@@ -0,0 +1,77 @@
+/*
+ * Command line options parser.
+ *
+ * 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: miniopt.h 241182 2011-02-17 21:50:03Z $
+ */
+
+
+#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/drivers/net/wireless/bcmdhd/include/msgtrace.h b/drivers/net/wireless/bcmdhd/include/msgtrace.h
new file mode 100644
index 000000000000..358cc3b3d0ca
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/msgtrace.h
@@ -0,0 +1,77 @@
+/*
+ * Trace messages sent over HBUS
+ *
+ * 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: msgtrace.h 369735 2012-11-19 22:50:22Z $
+ */
+
+#ifndef _MSGTRACE_H
+#define _MSGTRACE_H
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+#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)
+
+/* The hbus driver generates traces when sending a trace message. This causes endless traces.
+ * This flag must be set to TRUE in any hbus traces. The flag is reset in the function msgtrace_put.
+ * This prevents endless traces but generates hasardous lost of traces only in bus device code.
+ * It is recommendat to set this flag in macro SD_TRACE but not in SD_ERROR for avoiding missing
+ * hbus error traces. hbus error trace should not generates endless traces.
+ */
+extern bool msgtrace_hbus_trace;
+
+typedef void (*msgtrace_func_send_t)(void *hdl1, void *hdl2, uint8 *hdr,
+ uint16 hdrlen, uint8 *buf, uint16 buflen);
+extern void msgtrace_start(void);
+extern void msgtrace_stop(void);
+extern int msgtrace_sent(void);
+extern void msgtrace_put(char *buf, int count);
+extern void msgtrace_init(void *hdl1, void *hdl2, msgtrace_func_send_t func_send);
+extern bool msgtrace_event_enabled(void);
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* _MSGTRACE_H */
diff --git a/drivers/net/wireless/bcmdhd/include/osl.h b/drivers/net/wireless/bcmdhd/include/osl.h
new file mode 100644
index 000000000000..928cbf98e4fb
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/osl.h
@@ -0,0 +1,142 @@
+/*
+ * OS 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: osl.h 424562 2013-09-18 10:57:30Z $
+ */
+
+#ifndef _osl_h_
+#define _osl_h_
+
+/* osl handle type forward declaration */
+typedef struct osl_info osl_t;
+typedef struct osl_dmainfo osldma_t;
+
+#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);
+
+
+#include <linux_osl.h>
+
+#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(PKTC) && !defined(PKTC_DONGLE)
+#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)
+#define PKTSETCHAINED(osh, skb) BCM_REFERENCE(osh)
+#define PKTCLRCHAINED(osh, skb) BCM_REFERENCE(osh)
+#define PKTISCHAINED(skb) FALSE
+#endif
+
+/* Lbuf with fraglist */
+#define PKTFRAGPKTID(osh, lb) (0)
+#define PKTSETFRAGPKTID(osh, lb, id) BCM_REFERENCE(osh)
+#define PKTFRAGTOTNUM(osh, lb) (0)
+#define PKTSETFRAGTOTNUM(osh, lb, tot) BCM_REFERENCE(osh)
+#define PKTFRAGTOTLEN(osh, lb) (0)
+#define PKTSETFRAGTOTLEN(osh, lb, len) BCM_REFERENCE(osh)
+#define PKTFRAGIFINDEX(osh, lb) (0)
+#define PKTSETFRAGIFINDEX(osh, lb, idx) BCM_REFERENCE(osh)
+
+/* in rx path, reuse totlen as used len */
+#define PKTFRAGUSEDLEN(osh, lb) (0)
+#define PKTSETFRAGUSEDLEN(osh, lb, len) BCM_REFERENCE(osh)
+
+#define PKTFRAGLEN(osh, lb, ix) (0)
+#define PKTSETFRAGLEN(osh, lb, ix, len) BCM_REFERENCE(osh)
+#define PKTFRAGDATA_LO(osh, lb, ix) (0)
+#define PKTSETFRAGDATA_LO(osh, lb, ix, addr) BCM_REFERENCE(osh)
+#define PKTFRAGDATA_HI(osh, lb, ix) (0)
+#define PKTSETFRAGDATA_HI(osh, lb, ix, addr) BCM_REFERENCE(osh)
+
+/* RX FRAG */
+#define PKTISRXFRAG(osh, lb) (0)
+#define PKTSETRXFRAG(osh, lb) BCM_REFERENCE(osh)
+#define PKTRESETRXFRAG(osh, lb) BCM_REFERENCE(osh)
+
+/* TX FRAG */
+#define PKTISTXFRAG(osh, lb) (0)
+#define PKTSETTXFRAG(osh, lb) BCM_REFERENCE(osh)
+
+#define PKTISFRAG(osh, lb) (0)
+#define PKTFRAGISCHAINED(osh, i) (0)
+
+#endif /* _osl_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_end.h b/drivers/net/wireless/bcmdhd/include/packed_section_end.h
new file mode 100644
index 000000000000..3ad2eb68486b
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/packed_section_end.h
@@ -0,0 +1,59 @@
+/*
+ * 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 <packed_section_start.h>
+ *
+ * typedef BWL_PRE_PACKED_STRUCT struct foobar_t {
+ * some_struct_members;
+ * } BWL_POST_PACKED_STRUCT foobar_t;
+ *
+ * #include <packed_section_end.h>
+ *
+ *
+ * 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: packed_section_end.h 241182 2011-02-17 21:50:03Z $
+ */
+
+
+/* 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/drivers/net/wireless/bcmdhd/include/packed_section_start.h b/drivers/net/wireless/bcmdhd/include/packed_section_start.h
new file mode 100644
index 000000000000..a8dd120f750c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/packed_section_start.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 <packed_section_start.h>
+ *
+ * typedef BWL_PRE_PACKED_STRUCT struct foobar_t {
+ * some_struct_members;
+ * } BWL_POST_PACKED_STRUCT foobar_t;
+ *
+ * #include <packed_section_end.h>
+ *
+ *
+ * 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: packed_section_start.h 286783 2011-09-29 06:18:57Z $
+ */
+
+
+/* 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/drivers/net/wireless/bcmdhd/include/pcicfg.h b/drivers/net/wireless/bcmdhd/include/pcicfg.h
new file mode 100644
index 000000000000..05849db91b39
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/pcicfg.h
@@ -0,0 +1,101 @@
+/*
+ * pcicfg.h: PCI configuration constants and structures.
+ *
+ * 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: pcicfg.h 413666 2013-07-20 01:16:40Z $
+ */
+
+#ifndef _h_pcicfg_
+#define _h_pcicfg_
+
+/* 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
+#define PCI_CFG_BAR1 0x14
+#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_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 PCI_GPIO_OUTEN 0xb8 /* pci config space gpio output enable (>=rev3) */
+
+#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_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_CONFIG_SPACE_SIZE 256
+#endif /* _h_pcicfg_ */
diff --git a/drivers/net/wireless/bcmdhd/include/pcie_core.h b/drivers/net/wireless/bcmdhd/include/pcie_core.h
new file mode 100644
index 000000000000..36dc875690e7
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/pcie_core.h
@@ -0,0 +1,581 @@
+/*
+ * BCM43XX PCIE core hardware 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: pcie_core.h 430913 2013-10-21 21:46:10Z $
+ */
+#ifndef _PCIE_CORE_H
+#define _PCIE_CORE_H
+#include <sbhnddma.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
+
+/* 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 */
+
+/* dma regs to control the flow between host2dev and dev2host */
+typedef struct pcie_devdmaregs {
+ dma64regs_t tx;
+ uint32 PAD[2];
+ dma64regs_t rx;
+ uint32 PAD[2];
+} pcie_devdmaregs_t;
+
+
+/* door bell register sets */
+typedef struct pcie_doorbell {
+ uint32 host2dev_0;
+ uint32 host2dev_1;
+ uint32 dev2host_0;
+ uint32 dev2host_1;
+} pcie_doorbell_t;
+
+/* SB side: PCIE core and host control registers */
+typedef 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[2];
+ 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 PAD[42];
+
+ 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];
+ } 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 PAD[21]; /* 0x1AC - 0x200 */
+ 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 */
+ } pcie2;
+ } u;
+ uint32 pciecfg[4][64]; /* 0x400 - 0x7FF, PCIE Cfg Space */
+ uint16 sprom[64]; /* SPROM shadow Area */
+} sbpcieregs_t;
+
+/* 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_DISABLE_L1CLK_GATING 0x10
+#define PCIE_DISSPROMLD 0x200 /* DisableSpromLoadOnPerst */
+
+#define PCIE_CFGADDR 0x120 /* offsetof(configaddr) */
+#define PCIE_CFGDATA 0x124 /* offsetof(configdata) */
+
+/* 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 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_DB1 | PCIE_MB_TOPCIE_D2H1_DB1 | \
+ PCIE_MB_TOPCIE_D2H2_DB1 | PCIE_MB_TOPCIE_D2H2_DB1 | \
+ PCIE_MB_TOPCIE_D2H3_DB1 | PCIE_MB_TOPCIE_D2H3_DB1)
+
+/* 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
+
+/* PCIE protocol PHY diagnostic registers */
+#define PCIE_PLP_MODEREG 0x200 /* Mode */
+#define PCIE_PLP_STATUSREG 0x204 /* Status */
+#define PCIE_PLP_LTSSMCTRLREG 0x208 /* LTSSM control */
+#define PCIE_PLP_LTLINKNUMREG 0x20c /* Link Training Link number */
+#define PCIE_PLP_LTLANENUMREG 0x210 /* Link Training Lane number */
+#define PCIE_PLP_LTNFTSREG 0x214 /* Link Training N_FTS */
+#define PCIE_PLP_ATTNREG 0x218 /* Attention */
+#define PCIE_PLP_ATTNMASKREG 0x21C /* Attention Mask */
+#define PCIE_PLP_RXERRCTR 0x220 /* Rx Error */
+#define PCIE_PLP_RXFRMERRCTR 0x224 /* Rx Framing Error */
+#define PCIE_PLP_RXERRTHRESHREG 0x228 /* Rx Error threshold */
+#define PCIE_PLP_TESTCTRLREG 0x22C /* Test Control reg */
+#define PCIE_PLP_SERDESCTRLOVRDREG 0x230 /* SERDES Control Override */
+#define PCIE_PLP_TIMINGOVRDREG 0x234 /* Timing param override */
+#define PCIE_PLP_RXTXSMDIAGREG 0x238 /* RXTX State Machine Diag */
+#define PCIE_PLP_LTSSMDIAGREG 0x23C /* LTSSM State Machine Diag */
+
+/* PCIE protocol DLLP diagnostic registers */
+#define PCIE_DLLP_LCREG 0x100 /* Link Control */
+#define PCIE_DLLP_LSREG 0x104 /* Link Status */
+#define PCIE_DLLP_LAREG 0x108 /* Link Attention */
+#define PCIE_DLLP_LAMASKREG 0x10C /* Link Attention Mask */
+#define PCIE_DLLP_NEXTTXSEQNUMREG 0x110 /* Next Tx Seq Num */
+#define PCIE_DLLP_ACKEDTXSEQNUMREG 0x114 /* Acked Tx Seq Num */
+#define PCIE_DLLP_PURGEDTXSEQNUMREG 0x118 /* Purged Tx Seq Num */
+#define PCIE_DLLP_RXSEQNUMREG 0x11C /* Rx Sequence Number */
+#define PCIE_DLLP_LRREG 0x120 /* Link Replay */
+#define PCIE_DLLP_LACKTOREG 0x124 /* Link Ack Timeout */
+#define PCIE_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */
+#define PCIE_DLLP_RTRYWPREG 0x12C /* Retry buffer write ptr */
+#define PCIE_DLLP_RTRYRPREG 0x130 /* Retry buffer Read ptr */
+#define PCIE_DLLP_RTRYPPREG 0x134 /* Retry buffer Purged ptr */
+#define PCIE_DLLP_RTRRWREG 0x138 /* Retry buffer Read/Write */
+#define PCIE_DLLP_ECTHRESHREG 0x13C /* Error Count Threshold */
+#define PCIE_DLLP_TLPERRCTRREG 0x140 /* TLP Error Counter */
+#define PCIE_DLLP_ERRCTRREG 0x144 /* Error Counter */
+#define PCIE_DLLP_NAKRXCTRREG 0x148 /* NAK Received Counter */
+#define PCIE_DLLP_TESTREG 0x14C /* Test */
+#define PCIE_DLLP_PKTBIST 0x150 /* Packet BIST */
+#define PCIE_DLLP_PCIE11 0x154 /* DLLP PCIE 1.1 reg */
+
+#define PCIE_DLLP_LSREG_LINKUP (1 << 16)
+
+/* PCIE protocol TLP diagnostic registers */
+#define PCIE_TLP_CONFIGREG 0x000 /* Configuration */
+#define PCIE_TLP_WORKAROUNDSREG 0x004 /* TLP Workarounds */
+#define PCIE_TLP_WRDMAUPPER 0x010 /* Write DMA Upper Address */
+#define PCIE_TLP_WRDMALOWER 0x014 /* Write DMA Lower Address */
+#define PCIE_TLP_WRDMAREQ_LBEREG 0x018 /* Write DMA Len/ByteEn Req */
+#define PCIE_TLP_RDDMAUPPER 0x01C /* Read DMA Upper Address */
+#define PCIE_TLP_RDDMALOWER 0x020 /* Read DMA Lower Address */
+#define PCIE_TLP_RDDMALENREG 0x024 /* Read DMA Len Req */
+#define PCIE_TLP_MSIDMAUPPER 0x028 /* MSI DMA Upper Address */
+#define PCIE_TLP_MSIDMALOWER 0x02C /* MSI DMA Lower Address */
+#define PCIE_TLP_MSIDMALENREG 0x030 /* MSI DMA Len Req */
+#define PCIE_TLP_SLVREQLENREG 0x034 /* Slave Request Len */
+#define PCIE_TLP_FCINPUTSREQ 0x038 /* Flow Control Inputs */
+#define PCIE_TLP_TXSMGRSREQ 0x03C /* Tx StateMachine and Gated Req */
+#define PCIE_TLP_ADRACKCNTARBLEN 0x040 /* Address Ack XferCnt and ARB Len */
+#define PCIE_TLP_DMACPLHDR0 0x044 /* DMA Completion Hdr 0 */
+#define PCIE_TLP_DMACPLHDR1 0x048 /* DMA Completion Hdr 1 */
+#define PCIE_TLP_DMACPLHDR2 0x04C /* DMA Completion Hdr 2 */
+#define PCIE_TLP_DMACPLMISC0 0x050 /* DMA Completion Misc0 */
+#define PCIE_TLP_DMACPLMISC1 0x054 /* DMA Completion Misc1 */
+#define PCIE_TLP_DMACPLMISC2 0x058 /* DMA Completion Misc2 */
+#define PCIE_TLP_SPTCTRLLEN 0x05C /* Split Controller Req len */
+#define PCIE_TLP_SPTCTRLMSIC0 0x060 /* Split Controller Misc 0 */
+#define PCIE_TLP_SPTCTRLMSIC1 0x064 /* Split Controller Misc 1 */
+#define PCIE_TLP_BUSDEVFUNC 0x068 /* Bus/Device/Func */
+#define PCIE_TLP_RESETCTR 0x06C /* Reset Counter */
+#define PCIE_TLP_RTRYBUF 0x070 /* Retry Buffer value */
+#define PCIE_TLP_TGTDEBUG1 0x074 /* Target Debug Reg1 */
+#define PCIE_TLP_TGTDEBUG2 0x078 /* Target Debug Reg2 */
+#define PCIE_TLP_TGTDEBUG3 0x07C /* Target Debug Reg3 */
+#define PCIE_TLP_TGTDEBUG4 0x080 /* Target Debug Reg4 */
+
+/* MDIO control */
+#define MDIOCTL_DIVISOR_MASK 0x7f /* clock to be used on MDIO */
+#define MDIOCTL_DIVISOR_VAL 0x2
+#define MDIOCTL_PREAM_EN 0x80 /* Enable preamble sequnce */
+#define MDIOCTL_ACCESS_DONE 0x100 /* 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 0x80000000 /* 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 0xFF00 /* bits 0 - 7 */
+#define PCIE_L1THRESHOLDTIME_MASK 0xFF00 /* 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 0x8000 /* 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 */
+
+/* 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 0xF0000 /* 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 */
+
+/* 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_CAP_LTR0_REG_OFFSET 0x798 /* ltr0_reg offset in pcie cap */
+#define PCIE_CAP_LTR1_REG_OFFSET 0x79C /* ltr1_reg offset in pcie cap */
+#define PCIE_CAP_LTR2_REG_OFFSET 0x7A0 /* ltr2_reg offset in pcie cap */
+#define PCIE_CAP_LTR0_REG 0 /* ltr0_reg */
+#define PCIE_CAP_LTR1_REG 1 /* ltr1_reg */
+#define PCIE_CAP_LTR2_REG 2 /* ltr2_reg */
+
+/* Status reg PCIE_PLP_STATUSREG */
+#define PCIE_PLP_POLARITYINV_STAT 0x10
+
+
+/* PCIE BRCM Vendor CAP REVID reg bits */
+#define BRCMCAP_PCIEREV_CT_MASK 0xF00
+#define BRCMCAP_PCIEREV_CT_SHIFT 8
+#define BRCMCAP_PCIEREV_REVID_MASK 0xFF
+#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_PML1_SUB_CTRL1 0x248
+#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 */
+
+#define PCIECFGREG_PDL_CTRL1 0x1004
+#define PCIECFGREG_REG_PHY_CTL7 0x181c
+/* 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 PCID2H_MailBox 0x148
+#define PCIMailBoxInt 0x48
+#define PCIMailBoxMask 0x4C
+
+#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
+
+/* 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
+
+
+/* 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
+
+#endif /* _PCIE_CORE_H */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11.h b/drivers/net/wireless/bcmdhd/include/proto/802.11.h
new file mode 100644
index 000000000000..823ebe06a290
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.11.h
@@ -0,0 +1,3803 @@
+/*
+ * 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.
+ *
+ * Fundamental types and constants relating to 802.11
+ *
+ * $Id: 802.11.h 444070 2013-12-18 13:20:12Z $
+ */
+
+#ifndef _802_11_H_
+#define _802_11_H_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+#ifndef _NET_ETHERNET_H_
+#include <proto/ethernet.h>
+#endif
+
+#include <proto/wpa.h>
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+
+#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 */
+#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 vender 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;
+#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 */
+
+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;
+
+#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 {
+ uint8 min;
+ uint8 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 inidicates 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;
+#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_CHANNEL_SWITCH_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;
+
+/* 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_MAX 8
+
+#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
+
+BWL_PRE_PACKED_STRUCT struct dot11_extcap {
+ uint8 extcap[DOT11_EXTCAP_LEN_MAX];
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_extcap dot11_extcap_t;
+
+/* 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_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_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;
+ uint8 data[1];
+ } BWL_POST_PACKED_STRUCT rep;
+} BWL_POST_PACKED_STRUCT;
+typedef struct dot11_meas_rep dot11_meas_rep_t;
+
+/* 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))))
+
+/* 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 */
+
+/* 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
+
+/* 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_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_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 */
+
+/* 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_MAX 23 /* Reason codes > 23 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_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_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_EXT_CAP_ID 127 /* d11 mgmt ext capability */
+#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_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_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 */
+
+/* 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-2012 and 802.11ac_D4.0 sec 8.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 */
+
+/* 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
+/* 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
+/* service Interval granularity bit position and mask */
+#define DOT11_EXT_CAP_SI 41
+#define DOT11_EXT_CAP_SI_MASK 0x0E
+/* 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
+
+/* VHT Operating mode bit fields - (11ac D3.0 - 8.4.1.50) */
+#define DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT 0
+#define DOT11_OPER_MODE_CHANNEL_WIDTH_MASK 0x3
+#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_OPER_MODE_CHANNEL_WIDTH(mode) \
+ (((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)\
+ >> DOT11_OPER_MODE_CHANNEL_WIDTH_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_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_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_160MHZ)
+#define DOT11_OPER_MODE_CHANNEL_WIDTH_8080MHZ(mode) (\
+ ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_8080MHZ)
+
+/* 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_NOTIFICATION 17
+#define DOT11_ACTION_CAT_VHT 21 /* VHT action */
+#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 */
+
+/* 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_GAS_CB_REQ 12 /* GAS Comeback Request */
+
+/* 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 */
+
+/* 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 */
+
+/* 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
+
+/* 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-bit26, not used for RRM_IOVAR */
+#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
+
+/* 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 */
+
+/* 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 */
+
+/* Sub-element IDs for Beacon Report */
+#define DOT11_RMREP_BCN_FRM_BODY 1
+
+/* 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;
+
+/* 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;
+
+/* 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;
+
+/* 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;
+
+
+/* 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
+
+/* 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
+
+/* 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
+
+/* 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_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
+
+/* 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 */
+
+/* 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 */
+
+/* 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_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"
+
+
+/* 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 */
+
+
+/* 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_LZWDS 0x4 /* lazy wds enabled */
+#define BRF_BLOCKACK 0x8 /* BlockACK capable */
+
+/* brcm_ie flags1 */
+#define BRF1_AMSDU 0x1 /* A-MSDU 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 inidicates 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 inidicates 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
+
+/* ************* 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 inidicates 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_TX 0x8
+#define HT_CAP_TXBF_CAP_NDP_RX 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 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
+
+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 */
+
+/* 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 */
+
+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
+
+/* 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_MCS_TX_HIGHEST_RATE_MASK 0x1fff
+#define VHT_CAP_SUPP_MCS_TX_HIGHEST_RATE_SHIFT 0
+
+#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
+/* 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)))
+
+#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) ? 0xff : \
+ (mcs_code == VHT_CAP_MCS_MAP_0_8) ? 0x1ff : \
+ (mcs_code == VHT_CAP_MCS_MAP_0_9) ? 0x3ff : 0)
+
+/* Map the mcs bit map to mcs code */
+#define VHT_MCS_MAP_TO_MCS_CODE(mcs_map) \
+ ((mcs_map == 0xff) ? VHT_CAP_MCS_MAP_0_7 : \
+ (mcs_map == 0x1ff) ? VHT_CAP_MCS_MAP_0_8 : \
+ (mcs_map == 0x3ff) ? VHT_CAP_MCS_MAP_0_9 : VHT_CAP_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,
+ VHT_OP_CHAN_WIDTH_80_80 = 3
+} 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)
+
+
+/* ************* 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. ************* */
+
+#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
+
+/* 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 */
+#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_TPK 7 /* TPK(TDLS Peer Key) handshake */
+
+/* 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 */
+
+
+/* 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;
+
+#define BSSID_INVALID "\x00\x00\x00\x00\x00\x00"
+#define BSSID_BROADCAST "\xFF\xFF\xFF\xFF\xFF\xFF"
+
+
+/* ************* 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
+
+/* 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
+
+/* 802.11u advertisement protocol */
+#define ADVP_ANQP_PROTOCOL_ID 0
+
+/* 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_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_SIM 18
+#define REALM_EAP_TTLS 21
+#define REALM_EAP_AKA 23
+#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_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
+
+/* 802.11u 3GPP PLMN */
+#define G3PP_GUD_VERSION 0
+#define G3PP_PLMN_LIST_IE 0
+
+/* 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;
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* _802_11_H_ */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h b/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h
new file mode 100644
index 000000000000..cb27cf90a22f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h
@@ -0,0 +1,45 @@
+/*
+ * BT-AMP (BlueTooth Alternate Mac and Phy) 802.11 PAL (Protocol Adaptation 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: 802.11_bta.h 382882 2013-02-04 23:24:31Z $
+*/
+
+#ifndef _802_11_BTA_H_
+#define _802_11_BTA_H_
+
+#define BT_SIG_SNAP_MPROT "\xAA\xAA\x03\x00\x19\x58"
+
+/* BT-AMP 802.11 PAL Protocols */
+#define BTA_PROT_L2CAP 1
+#define BTA_PROT_ACTIVITY_REPORT 2
+#define BTA_PROT_SECURITY 3
+#define BTA_PROT_LINK_SUPERVISION_REQUEST 4
+#define BTA_PROT_LINK_SUPERVISION_REPLY 5
+
+/* BT-AMP 802.11 PAL AMP_ASSOC Type IDs */
+#define BTA_TYPE_ID_MAC_ADDRESS 1
+#define BTA_TYPE_ID_PREFERRED_CHANNELS 2
+#define BTA_TYPE_ID_CONNECTED_CHANNELS 3
+#define BTA_TYPE_ID_CAPABILITIES 4
+#define BTA_TYPE_ID_VERSION 5
+#endif /* _802_11_bta_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h
new file mode 100644
index 000000000000..4caab96752f4
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h
@@ -0,0 +1,132 @@
+/*
+ * 802.11e protocol header file
+ *
+ * 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: 802.11e.h 382883 2013-02-04 23:26:09Z $
+ */
+
+#ifndef _802_11e_H_
+#define _802_11e_H_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+
+/* 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 <packed_section_end.h>
+
+#endif /* _802_11e_CAC_H_ */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.1d.h b/drivers/net/wireless/bcmdhd/include/proto/802.1d.h
new file mode 100644
index 000000000000..e4e98eb9721f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.1d.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ *
+ * Fundamental types and constants relating to 802.1D
+ *
+ * $Id: 802.1d.h 382882 2013-02-04 23:24:31Z $
+ */
+
+#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/drivers/net/wireless/bcmdhd/include/proto/802.3.h b/drivers/net/wireless/bcmdhd/include/proto/802.3.h
new file mode 100644
index 000000000000..991b85eb62f6
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.3.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ *
+ * Fundamental constants relating to 802.3
+ *
+ * $Id: 802.3.h 417943 2013-08-13 07:54:04Z $
+ */
+
+#ifndef _802_3_h_
+#define _802_3_h_
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+#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 <packed_section_end.h>
+
+#endif /* #ifndef _802_3_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h
new file mode 100644
index 000000000000..891b44d299fb
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h
@@ -0,0 +1,112 @@
+/*
+ * Broadcom Ethernettype protocol 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: bcmeth.h 382882 2013-02-04 23:24:31Z $
+ */
+
+/*
+ * Broadcom Ethernet protocol defines
+ */
+
+#ifndef _BCMETH_H_
+#define _BCMETH_H_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+/* 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_SUBTYPEHDR_MINLENGTH 8
+#define BCMILCP_BCM_SUBTYPEHDR_VERSION 0
+
+/* 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 <packed_section_end.h>
+
+#endif /* _BCMETH_H_ */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
new file mode 100644
index 000000000000..2791636b8ce2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
@@ -0,0 +1,517 @@
+/*
+ * Broadcom Event protocol 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.
+ *
+ * Dependencies: proto/bcmeth.h
+ *
+ * $Id: bcmevent.h 662961 2016-11-24 01:22:35Z $
+ *
+ */
+
+/*
+ * Broadcom Ethernet Events protocol defines
+ *
+ */
+
+#ifndef _BCMEVENT_H_
+#define _BCMEVENT_H_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+/* #include <ethernet.h> -- TODO: req., excluded to overwhelming coupling (break up ethernet.h) */
+#include <proto/bcmeth.h>
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+#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;
+
+#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 attempt occurred: 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 */
+#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
+#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 */
+/* PFN best network batching event, conflict/share with WLC_E_PFN_SCAN_COMPLETE */
+#define WLC_E_PFN_BEST_BATCHING 57
+#define WLC_E_PFN_SCAN_COMPLETE 57 /* PFN completed scan of network list */
+/* PFN best network batching event, conflict/share with WLC_E_PFN_SCAN_COMPLETE */
+#define WLC_E_PFN_BEST_BATCHING 57
+#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 */
+#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_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_RMC_EVENT 139 /* RMC event */
+#define WLC_E_PKT_FILTER 164 /* Packet filter event */
+#define WLC_E_LAST 165 /* highest val + 1 for range checking */
+
+#if (WLC_E_LAST > 165)
+#error "WLC_E_LAST: Invalid value for last event; must be <= 140."
+#endif /* WLC_E_LAST */
+
+
+/* Table of event name strings for UIs and debugging dumps */
+typedef struct {
+ uint event;
+ const char *name;
+} bcmevent_name_t;
+
+extern const bcmevent_name_t bcmevent_names[];
+extern const int bcmevent_names_size;
+
+/* 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,
+ wl_event_msg_t *out_event);
+
+/* 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 */
+
+/* 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 */
+
+/* Roam codes used primarily by CCX */
+#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 */
+#define WLC_E_REASON_REQUESTED_ROAM 11 /* roamed due to BSS Mgmt Transition REQ by AP */
+
+/* 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 */
+
+/* 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 */
+
+/* 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;
+
+/* 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 */
+
+/* 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 */
+
+/* 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
+
+#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
+#endif
+
+
+/* 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
+
+
+/* WLC_E_PKT_FILTER event codes */
+#define WLC_E_PKT_FILTER_TIMEOUT 1 /* Matching packet not received in last timeout seconds */
+
+/* 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;
+
+/* 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 */
+
+/* proxd_event data */
+typedef struct ftm_sample {
+ uint32 value; /* RTT in ns */
+ int8 rssi; /* RSSI */
+} ftm_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 */
+ int 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 */
+ char *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;
+
+
+/* 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;
+
+/* 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;
+
+/* ********** NAN protocol events/subevents ********** */
+#define NAN_EVENT_BUFFER_SIZE 512 /* max size */
+/* nan application events to the host driver */
+enum nan_app_events {
+ WL_NAN_EVENT_START = 1, /* NAN cluster started */
+ WL_NAN_EVENT_JOIN = 2, /* Joined to a NAN cluster */
+ WL_NAN_EVENT_ROLE = 3, /* Role or State changed */
+ WL_NAN_EVENT_SCAN_COMPLETE = 4,
+ WL_NAN_EVENT_DISCOVERY_RESULT = 5,
+ WL_NAN_EVENT_REPLIED = 6,
+ WL_NAN_EVENT_TERMINATED = 7, /* the instance ID will be present in the ev data */
+ WL_NAN_EVENT_RECEIVE = 8,
+ WL_NAN_EVENT_STATUS_CHG = 9, /* generated on any change in nan_mac status */
+ WL_NAN_EVENT_MERGE = 10, /* Merged to a NAN cluster */
+ WL_NAN_EVENT_STOP = 11, /* NAN stopped */
+ WL_NAN_EVENT_INVALID = 12, /* delimiter for max value */
+};
+#define IS_NAN_EVT_ON(var, evt) ((var & (1 << (evt-1))) != 0)
+/* ******************* end of NAN section *************** */
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* _BCMEVENT_H_ */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmip.h b/drivers/net/wireless/bcmdhd/include/proto/bcmip.h
new file mode 100644
index 000000000000..8d54b8bfe21d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmip.h
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ *
+ * Fundamental constants relating to IP Protocol
+ *
+ * $Id: bcmip.h 457888 2014-02-25 03:34:39Z $
+ */
+
+#ifndef _bcmip_h_
+#define _bcmip_h_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+
+/* 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_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_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;
+
+/* 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);
+
+/* 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 <packed_section_end.h>
+
+#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/drivers/net/wireless/bcmdhd/include/proto/bcmipv6.h b/drivers/net/wireless/bcmdhd/include/proto/bcmipv6.h
new file mode 100644
index 000000000000..7701ea2fe6b3
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmipv6.h
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ *
+ * Fundamental constants relating to Neighbor Discovery Protocol
+ *
+ * $Id: bcmipv6.h 399482 2013-04-30 09:24:37Z $
+ */
+
+#ifndef _bcmipv6_h_
+#define _bcmipv6_h_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+/* 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_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 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 <packed_section_end.h>
+
+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/drivers/net/wireless/bcmdhd/include/proto/bcmtcp.h b/drivers/net/wireless/bcmdhd/include/proto/bcmtcp.h
new file mode 100644
index 000000000000..20e7531ff0a8
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmtcp.h
@@ -0,0 +1,90 @@
+/*
+ * Fundamental constants relating to TCP Protocol
+ *
+ * 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: bcmtcp.h 457888 2014-02-25 03:34:39Z $
+ */
+
+#ifndef _bcmtcp_h_
+#define _bcmtcp_h_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+
+#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 <packed_section_end.h>
+
+/* 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/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h b/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h
new file mode 100644
index 000000000000..3fdabec0d770
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h
@@ -0,0 +1,441 @@
+/*
+ * BT-AMP (BlueTooth Alternate Mac and Phy) HCI (Host/Controller Interface)
+ *
+ * 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: bt_amp_hci.h 382882 2013-02-04 23:24:31Z $
+*/
+
+#ifndef _bt_amp_hci_h
+#define _bt_amp_hci_h
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+
+/* AMP HCI CMD packet format */
+typedef BWL_PRE_PACKED_STRUCT struct amp_hci_cmd {
+ uint16 opcode;
+ uint8 plen;
+ uint8 parms[1];
+} BWL_POST_PACKED_STRUCT amp_hci_cmd_t;
+
+#define HCI_CMD_PREAMBLE_SIZE OFFSETOF(amp_hci_cmd_t, parms)
+#define HCI_CMD_DATA_SIZE 255
+
+/* AMP HCI CMD opcode layout */
+#define HCI_CMD_OPCODE(ogf, ocf) ((((ogf) & 0x3F) << 10) | ((ocf) & 0x03FF))
+#define HCI_CMD_OGF(opcode) ((uint8)(((opcode) >> 10) & 0x3F))
+#define HCI_CMD_OCF(opcode) ((opcode) & 0x03FF)
+
+/* AMP HCI command opcodes */
+#define HCI_Read_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0001)
+#define HCI_Reset_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0002)
+#define HCI_Read_Link_Quality HCI_CMD_OPCODE(0x05, 0x0003)
+#define HCI_Read_Local_AMP_Info HCI_CMD_OPCODE(0x05, 0x0009)
+#define HCI_Read_Local_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000A)
+#define HCI_Write_Remote_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000B)
+#define HCI_Create_Physical_Link HCI_CMD_OPCODE(0x01, 0x0035)
+#define HCI_Accept_Physical_Link_Request HCI_CMD_OPCODE(0x01, 0x0036)
+#define HCI_Disconnect_Physical_Link HCI_CMD_OPCODE(0x01, 0x0037)
+#define HCI_Create_Logical_Link HCI_CMD_OPCODE(0x01, 0x0038)
+#define HCI_Accept_Logical_Link HCI_CMD_OPCODE(0x01, 0x0039)
+#define HCI_Disconnect_Logical_Link HCI_CMD_OPCODE(0x01, 0x003A)
+#define HCI_Logical_Link_Cancel HCI_CMD_OPCODE(0x01, 0x003B)
+#define HCI_Flow_Spec_Modify HCI_CMD_OPCODE(0x01, 0x003C)
+#define HCI_Write_Flow_Control_Mode HCI_CMD_OPCODE(0x01, 0x0067)
+#define HCI_Read_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x0069)
+#define HCI_Write_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x006A)
+#define HCI_Short_Range_Mode HCI_CMD_OPCODE(0x01, 0x006B)
+#define HCI_Reset HCI_CMD_OPCODE(0x03, 0x0003)
+#define HCI_Read_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0015)
+#define HCI_Write_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0016)
+#define HCI_Read_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0036)
+#define HCI_Write_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0037)
+#define HCI_Enhanced_Flush HCI_CMD_OPCODE(0x03, 0x005F)
+#define HCI_Read_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0061)
+#define HCI_Write_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0062)
+#define HCI_Set_Event_Mask_Page_2 HCI_CMD_OPCODE(0x03, 0x0063)
+#define HCI_Read_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0064)
+#define HCI_Write_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0065)
+#define HCI_Read_Local_Version_Info HCI_CMD_OPCODE(0x04, 0x0001)
+#define HCI_Read_Local_Supported_Commands HCI_CMD_OPCODE(0x04, 0x0002)
+#define HCI_Read_Buffer_Size HCI_CMD_OPCODE(0x04, 0x0005)
+#define HCI_Read_Data_Block_Size HCI_CMD_OPCODE(0x04, 0x000A)
+
+/* AMP HCI command parameters */
+typedef BWL_PRE_PACKED_STRUCT struct read_local_cmd_parms {
+ uint8 plh;
+ uint8 offset[2]; /* length so far */
+ uint8 max_remote[2];
+} BWL_POST_PACKED_STRUCT read_local_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct write_remote_cmd_parms {
+ uint8 plh;
+ uint8 offset[2];
+ uint8 len[2];
+ uint8 frag[1];
+} BWL_POST_PACKED_STRUCT write_remote_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct phy_link_cmd_parms {
+ uint8 plh;
+ uint8 key_length;
+ uint8 key_type;
+ uint8 key[1];
+} BWL_POST_PACKED_STRUCT phy_link_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_cmd_parms {
+ uint8 plh;
+ uint8 reason;
+} BWL_POST_PACKED_STRUCT dis_phy_link_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct log_link_cmd_parms {
+ uint8 plh;
+ uint8 txflow[16];
+ uint8 rxflow[16];
+} BWL_POST_PACKED_STRUCT log_link_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct ext_flow_spec {
+ uint8 id;
+ uint8 service_type;
+ uint8 max_sdu[2];
+ uint8 sdu_ia_time[4];
+ uint8 access_latency[4];
+ uint8 flush_timeout[4];
+} BWL_POST_PACKED_STRUCT ext_flow_spec_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_cmd_parms {
+ uint8 plh;
+ uint8 tx_fs_ID;
+} BWL_POST_PACKED_STRUCT log_link_cancel_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_cmd_parms {
+ uint8 llh[2];
+ uint8 txflow[16];
+ uint8 rxflow[16];
+} BWL_POST_PACKED_STRUCT flow_spec_mod_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct plh_pad {
+ uint8 plh;
+ uint8 pad;
+} BWL_POST_PACKED_STRUCT plh_pad_t;
+
+typedef BWL_PRE_PACKED_STRUCT union hci_handle {
+ uint16 bredr;
+ plh_pad_t amp;
+} BWL_POST_PACKED_STRUCT hci_handle_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct ls_to_cmd_parms {
+ hci_handle_t handle;
+ uint8 timeout[2];
+} BWL_POST_PACKED_STRUCT ls_to_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct befto_cmd_parms {
+ uint8 llh[2];
+ uint8 befto[4];
+} BWL_POST_PACKED_STRUCT befto_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct srm_cmd_parms {
+ uint8 plh;
+ uint8 srm;
+} BWL_POST_PACKED_STRUCT srm_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct ld_cmd_parms {
+ uint8 ld_aware;
+ uint8 ld[2];
+ uint8 ld_opts;
+ uint8 l_opts;
+} BWL_POST_PACKED_STRUCT ld_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct eflush_cmd_parms {
+ uint8 llh[2];
+ uint8 packet_type;
+} BWL_POST_PACKED_STRUCT eflush_cmd_parms_t;
+
+/* Generic AMP extended flow spec service types */
+#define EFS_SVCTYPE_NO_TRAFFIC 0
+#define EFS_SVCTYPE_BEST_EFFORT 1
+#define EFS_SVCTYPE_GUARANTEED 2
+
+/* AMP HCI event packet format */
+typedef BWL_PRE_PACKED_STRUCT struct amp_hci_event {
+ uint8 ecode;
+ uint8 plen;
+ uint8 parms[1];
+} BWL_POST_PACKED_STRUCT amp_hci_event_t;
+
+#define HCI_EVT_PREAMBLE_SIZE OFFSETOF(amp_hci_event_t, parms)
+
+/* AMP HCI event codes */
+#define HCI_Command_Complete 0x0E
+#define HCI_Command_Status 0x0F
+#define HCI_Flush_Occurred 0x11
+#define HCI_Enhanced_Flush_Complete 0x39
+#define HCI_Physical_Link_Complete 0x40
+#define HCI_Channel_Select 0x41
+#define HCI_Disconnect_Physical_Link_Complete 0x42
+#define HCI_Logical_Link_Complete 0x45
+#define HCI_Disconnect_Logical_Link_Complete 0x46
+#define HCI_Flow_Spec_Modify_Complete 0x47
+#define HCI_Number_of_Completed_Data_Blocks 0x48
+#define HCI_Short_Range_Mode_Change_Complete 0x4C
+#define HCI_Status_Change_Event 0x4D
+#define HCI_Vendor_Specific 0xFF
+
+/* AMP HCI event mask bit positions */
+#define HCI_Physical_Link_Complete_Event_Mask 0x0001
+#define HCI_Channel_Select_Event_Mask 0x0002
+#define HCI_Disconnect_Physical_Link_Complete_Event_Mask 0x0004
+#define HCI_Logical_Link_Complete_Event_Mask 0x0020
+#define HCI_Disconnect_Logical_Link_Complete_Event_Mask 0x0040
+#define HCI_Flow_Spec_Modify_Complete_Event_Mask 0x0080
+#define HCI_Number_of_Completed_Data_Blocks_Event_Mask 0x0100
+#define HCI_Short_Range_Mode_Change_Complete_Event_Mask 0x1000
+#define HCI_Status_Change_Event_Mask 0x2000
+#define HCI_All_Event_Mask 0x31e7
+/* AMP HCI event parameters */
+typedef BWL_PRE_PACKED_STRUCT struct cmd_status_parms {
+ uint8 status;
+ uint8 cmdpkts;
+ uint16 opcode;
+} BWL_POST_PACKED_STRUCT cmd_status_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct cmd_complete_parms {
+ uint8 cmdpkts;
+ uint16 opcode;
+ uint8 parms[1];
+} BWL_POST_PACKED_STRUCT cmd_complete_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct flush_occurred_evt_parms {
+ uint16 handle;
+} BWL_POST_PACKED_STRUCT flush_occurred_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct write_remote_evt_parms {
+ uint8 status;
+ uint8 plh;
+} BWL_POST_PACKED_STRUCT write_remote_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct read_local_evt_parms {
+ uint8 status;
+ uint8 plh;
+ uint16 len;
+ uint8 frag[1];
+} BWL_POST_PACKED_STRUCT read_local_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct read_local_info_evt_parms {
+ uint8 status;
+ uint8 AMP_status;
+ uint32 bandwidth;
+ uint32 gbandwidth;
+ uint32 latency;
+ uint32 PDU_size;
+ uint8 ctrl_type;
+ uint16 PAL_cap;
+ uint16 AMP_ASSOC_len;
+ uint32 max_flush_timeout;
+ uint32 be_flush_timeout;
+} BWL_POST_PACKED_STRUCT read_local_info_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct log_link_evt_parms {
+ uint8 status;
+ uint16 llh;
+ uint8 plh;
+ uint8 tx_fs_ID;
+} BWL_POST_PACKED_STRUCT log_link_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct disc_log_link_evt_parms {
+ uint8 status;
+ uint16 llh;
+ uint8 reason;
+} BWL_POST_PACKED_STRUCT disc_log_link_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_evt_parms {
+ uint8 status;
+ uint8 plh;
+ uint8 tx_fs_ID;
+} BWL_POST_PACKED_STRUCT log_link_cancel_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_evt_parms {
+ uint8 status;
+ uint16 llh;
+} BWL_POST_PACKED_STRUCT flow_spec_mod_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct phy_link_evt_parms {
+ uint8 status;
+ uint8 plh;
+} BWL_POST_PACKED_STRUCT phy_link_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_evt_parms {
+ uint8 status;
+ uint8 plh;
+ uint8 reason;
+} BWL_POST_PACKED_STRUCT dis_phy_link_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct read_ls_to_evt_parms {
+ uint8 status;
+ hci_handle_t handle;
+ uint16 timeout;
+} BWL_POST_PACKED_STRUCT read_ls_to_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct read_lla_ca_to_evt_parms {
+ uint8 status;
+ uint16 timeout;
+} BWL_POST_PACKED_STRUCT read_lla_ca_to_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct read_data_block_size_evt_parms {
+ uint8 status;
+ uint16 ACL_pkt_len;
+ uint16 data_block_len;
+ uint16 data_block_num;
+} BWL_POST_PACKED_STRUCT read_data_block_size_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct data_blocks {
+ uint16 handle;
+ uint16 pkts;
+ uint16 blocks;
+} BWL_POST_PACKED_STRUCT data_blocks_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct num_completed_data_blocks_evt_parms {
+ uint16 num_blocks;
+ uint8 num_handles;
+ data_blocks_t completed[1];
+} BWL_POST_PACKED_STRUCT num_completed_data_blocks_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct befto_evt_parms {
+ uint8 status;
+ uint32 befto;
+} BWL_POST_PACKED_STRUCT befto_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct srm_evt_parms {
+ uint8 status;
+ uint8 plh;
+ uint8 srm;
+} BWL_POST_PACKED_STRUCT srm_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct contact_counter_evt_parms {
+ uint8 status;
+ uint8 llh[2];
+ uint16 counter;
+} BWL_POST_PACKED_STRUCT contact_counter_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct contact_counter_reset_evt_parms {
+ uint8 status;
+ uint8 llh[2];
+} BWL_POST_PACKED_STRUCT contact_counter_reset_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct read_linkq_evt_parms {
+ uint8 status;
+ hci_handle_t handle;
+ uint8 link_quality;
+} BWL_POST_PACKED_STRUCT read_linkq_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct ld_evt_parms {
+ uint8 status;
+ uint8 ld_aware;
+ uint8 ld[2];
+ uint8 ld_opts;
+ uint8 l_opts;
+} BWL_POST_PACKED_STRUCT ld_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct eflush_complete_evt_parms {
+ uint16 handle;
+} BWL_POST_PACKED_STRUCT eflush_complete_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct vendor_specific_evt_parms {
+ uint8 len;
+ uint8 parms[1];
+} BWL_POST_PACKED_STRUCT vendor_specific_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct local_version_info_evt_parms {
+ uint8 status;
+ uint8 hci_version;
+ uint16 hci_revision;
+ uint8 pal_version;
+ uint16 mfg_name;
+ uint16 pal_subversion;
+} BWL_POST_PACKED_STRUCT local_version_info_evt_parms_t;
+
+#define MAX_SUPPORTED_CMD_BYTE 64
+typedef BWL_PRE_PACKED_STRUCT struct local_supported_cmd_evt_parms {
+ uint8 status;
+ uint8 cmd[MAX_SUPPORTED_CMD_BYTE];
+} BWL_POST_PACKED_STRUCT local_supported_cmd_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct status_change_evt_parms {
+ uint8 status;
+ uint8 amp_status;
+} BWL_POST_PACKED_STRUCT status_change_evt_parms_t;
+
+/* AMP HCI error codes */
+#define HCI_SUCCESS 0x00
+#define HCI_ERR_ILLEGAL_COMMAND 0x01
+#define HCI_ERR_NO_CONNECTION 0x02
+#define HCI_ERR_MEMORY_FULL 0x07
+#define HCI_ERR_CONNECTION_TIMEOUT 0x08
+#define HCI_ERR_MAX_NUM_OF_CONNECTIONS 0x09
+#define HCI_ERR_CONNECTION_EXISTS 0x0B
+#define HCI_ERR_CONNECTION_DISALLOWED 0x0C
+#define HCI_ERR_CONNECTION_ACCEPT_TIMEOUT 0x10
+#define HCI_ERR_UNSUPPORTED_VALUE 0x11
+#define HCI_ERR_ILLEGAL_PARAMETER_FMT 0x12
+#define HCI_ERR_CONN_TERM_BY_LOCAL_HOST 0x16
+#define HCI_ERR_UNSPECIFIED 0x1F
+#define HCI_ERR_UNIT_KEY_USED 0x26
+#define HCI_ERR_QOS_REJECTED 0x2D
+#define HCI_ERR_PARAM_OUT_OF_RANGE 0x30
+#define HCI_ERR_NO_SUITABLE_CHANNEL 0x39
+#define HCI_ERR_CHANNEL_MOVE 0xFF
+
+/* AMP HCI ACL Data packet format */
+typedef BWL_PRE_PACKED_STRUCT struct amp_hci_ACL_data {
+ uint16 handle; /* 12-bit connection handle + 2-bit PB and 2-bit BC flags */
+ uint16 dlen; /* data total length */
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT amp_hci_ACL_data_t;
+
+#define HCI_ACL_DATA_PREAMBLE_SIZE OFFSETOF(amp_hci_ACL_data_t, data)
+
+#define HCI_ACL_DATA_BC_FLAGS (0x0 << 14)
+#define HCI_ACL_DATA_PB_FLAGS (0x3 << 12)
+
+#define HCI_ACL_DATA_HANDLE(handle) ((handle) & 0x0fff)
+#define HCI_ACL_DATA_FLAGS(handle) ((handle) >> 12)
+
+/* AMP Activity Report packet formats */
+typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report {
+ uint8 ScheduleKnown;
+ uint8 NumReports;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT amp_hci_activity_report_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report_triple {
+ uint32 StartTime;
+ uint32 Duration;
+ uint32 Periodicity;
+} BWL_POST_PACKED_STRUCT amp_hci_activity_report_triple_t;
+
+#define HCI_AR_SCHEDULE_KNOWN 0x01
+
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* _bt_amp_hci_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/eapol.h b/drivers/net/wireless/bcmdhd/include/proto/eapol.h
new file mode 100644
index 000000000000..0cdde4891921
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/eapol.h
@@ -0,0 +1,211 @@
+/*
+ * 802.1x EAPOL definitions
+ *
+ * See
+ * IEEE Std 802.1X-2001
+ * IEEE 802.1X RADIUS Usage Guidelines
+ *
+ * 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: eapol.h 526865 2015-01-15 07:44:19Z $
+ */
+
+#ifndef _eapol_h_
+#define _eapol_h_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+#include <bcmcrypto/aeskeywrap.h>
+
+/* 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_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 + 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_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 <packed_section_end.h>
+
+#endif /* _eapol_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/ethernet.h b/drivers/net/wireless/bcmdhd/include/proto/ethernet.h
new file mode 100644
index 000000000000..2d025502e291
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/ethernet.h
@@ -0,0 +1,220 @@
+/*
+ * From FreeBSD 2.2.7: Fundamental constants relating to ethernet.
+ *
+ * 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: ethernet.h 403353 2013-05-20 14:05:33Z $
+ */
+
+#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 <packed_section_start.h>
+
+
+/*
+ * 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 */
+#ifdef PLC
+#define ETHER_TYPE_88E1 0x88e1 /* GIGLE */
+#define ETHER_TYPE_8912 0x8912 /* GIGLE */
+#define ETHER_TYPE_GIGLED 0xffff /* GIGLE */
+#endif /* PLC */
+#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_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)
+
+
+
+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 <packed_section_end.h>
+
+#endif /* _NET_ETHERNET_H_ */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/p2p.h b/drivers/net/wireless/bcmdhd/include/proto/p2p.h
new file mode 100644
index 000000000000..678a36a85bd8
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/p2p.h
@@ -0,0 +1,608 @@
+/*
+ * 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.
+ *
+ * Fundamental types and constants relating to WFA P2P (aka WiFi Direct)
+ *
+ * $Id: p2p.h 444066 2013-12-18 12:49:24Z $
+ */
+
+#ifndef _P2P_H_
+#define _P2P_H_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+#include <wlioctl.h>
+#include <proto/802.11.h>
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+
+/* 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 */
+
+/* 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_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 */
+
+/* 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 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 Comback Request AF */
+#define P2PSD_ACTION_ID_GAS_CRESP 0x0d
+ /* Action value for GAS Comback 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_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 <packed_section_end.h>
+
+#endif /* _P2P_H_ */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/sdspi.h b/drivers/net/wireless/bcmdhd/include/proto/sdspi.h
new file mode 100644
index 000000000000..cb761b8eaa3c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/sdspi.h
@@ -0,0 +1,75 @@
+/*
+ * SD-SPI Protocol Standard
+ *
+ * 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: sdspi.h 382882 2013-02-04 23:24:31Z $
+ */
+#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/drivers/net/wireless/bcmdhd/include/proto/vlan.h b/drivers/net/wireless/bcmdhd/include/proto/vlan.h
new file mode 100644
index 000000000000..ba6b0f52cdb3
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/vlan.h
@@ -0,0 +1,95 @@
+/*
+ * 802.1Q VLAN protocol 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: vlan.h 382883 2013-02-04 23:26:09Z $
+ */
+
+#ifndef _vlan_h_
+#define _vlan_h_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+#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 <packed_section_end.h>
+
+#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/drivers/net/wireless/bcmdhd/include/proto/wpa.h b/drivers/net/wireless/bcmdhd/include/proto/wpa.h
new file mode 100644
index 000000000000..0e0db0af0b5f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/wpa.h
@@ -0,0 +1,175 @@
+/*
+ * Fundamental types and constants relating to WPA
+ *
+ * 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: wpa.h 384536 2013-02-12 04:13:09Z $
+ */
+
+#ifndef _proto_wpa_h_
+#define _proto_wpa_h_
+
+#include <typedefs.h>
+#include <proto/ethernet.h>
+
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+/* 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
+
+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];
+
+/* 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 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_TPK)
+
+
+/* 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
+
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* _proto_wpa_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/wps.h b/drivers/net/wireless/bcmdhd/include/proto/wps.h
new file mode 100644
index 000000000000..ac36ede91157
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/wps.h
@@ -0,0 +1,379 @@
+/*
+ * WPS IE 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$
+ */
+
+#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
+
+
+/* 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
+
+/* 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
+
+/* 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
+
+/* 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/drivers/net/wireless/bcmdhd/include/sbchipc.h b/drivers/net/wireless/bcmdhd/include/sbchipc.h
new file mode 100644
index 000000000000..f1549b6466ae
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sbchipc.h
@@ -0,0 +1,3304 @@
+/*
+ * 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 662459 2016-10-24 04:35:43Z $
+ *
+ * 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.
+ */
+
+#ifndef _SBCHIPC_H
+#define _SBCHIPC_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 */
+
+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 PAD[70];
+
+ /* 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[60];
+
+ /* 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 PAD;
+ 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[94];
+ uint16 sromotp[512]; /* 0x800 */
+#ifdef NFLASH_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 /* NFLASH_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_level_polreg; /* 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 PAD[3];
+ uint32 gci_uartescval; /* DD0 */
+ uint32 PAD[3];
+ uint32 gci_secibauddiv; /* DE0 */
+ uint32 gci_secifcr; /* DE4 */
+ uint32 gci_secilcr; /* DE8 */
+ uint32 gci_secimcr; /* DEC */
+ uint32 PAD[2];
+ uint32 gci_baudadj; /* DF8 */
+ uint32 PAD;
+ uint32 gci_chipctrl; /* 0xE00 */
+ uint32 gci_chipsts; /* 0xE04 */
+} chipcregs_t;
+
+#endif /* _LANGUAGE_ASSEMBLY */
+
+
+#define CC_CHIPID 0
+#define CC_CAPABILITIES 4
+#define CC_CHIPST 0x2c
+#define CC_EROMPTR 0xfc
+
+#define CC_OTPST 0x10
+#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_WATCHDOG 0x80
+#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_SYS_CLK_CTL 0xc0
+#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_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
+#define CC_SROM_OTP 0x800 /* SROM/OTP address space */
+#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 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 PMU_RES_STATE 0x60c
+#define PMU_RES_PENDING 0x610
+#define PMU_TIMER 0x614
+#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 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
+
+#ifdef NFLASH_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 /* NFLASH_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_GCI_PRESENT 0x00000004 /* GCI present */
+
+/* WL Channel Info to BT via GCI - bits 40 - 47 */
+#define GCI_WL_CHN_INFO_MASK (0xFF00)
+/* 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 */
+
+/* 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 */
+
+/* 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
+
+/* 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_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_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
+
+/* 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 */
+
+/* Fields in clkdiv */
+#define CLKD_SFLASH 0x0f000000
+#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
+
+/* 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
+
+/* 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_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_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
+
+/* 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
+
+/* 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 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
+
+/* PMU chip control2 register */
+#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)
+
+/* PMU chip control3 register */
+#define PMU_CHIPCTL3 3
+
+/* 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)
+
+#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 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 corerev and chip specific PLL controls.
+ * PMU<rev>_PLL<num>_XX where <rev> is PMU corerev and <num> is an arbitrary number
+ * to differentiate different PLLs controlled by the same PMU rev.
+ */
+/* 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<x>, refcomp_pwrdn, dly_ch<x>, 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
+
+/* m<x>div */
+#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 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)
+
+/* m<x>div, 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_36 0x24
+#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<x> */
+#define PMU1_PLL0_PLLCTL5 5
+#define PMU1_PLL0_PC5_CLK_DRV_MASK 0xffffff00
+#define PMU1_PLL0_PC5_CLK_DRV_SHIFT 8
+
+#define PMU1_PLL0_PLLCTL6 6
+#define PMU1_PLL0_PLLCTL7 7
+
+/* 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<x>, refcomp_pwrdn, dly_ch<x>, 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
+
+/* m<x>div */
+#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
+
+/* m<x>div, 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<x> */
+#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 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_DISABLE_PULLD_BT_SHIFT 2
+#define PMU_VREG0_DISABLE_PULLD_WL_SHIFT 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
+
+#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 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
+
+
+/* 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_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)
+
+
+/* 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
+
+/* 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 */
+
+#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_4350_RAM_BASE (0x180000)
+#define CR4_4360_RAM_BASE (0x0)
+#define CR4_43602_RAM_BASE (0x180000)
+
+/* 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 */
+
+/* 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)
+
+#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))
+
+/* 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_RSVD_16 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 SDIO host_wake */
+#define MUXENAB4350_HOSTWAKE_SHIFT 4
+
+
+/* 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 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_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 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)
+
+/* 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_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)
+
+/* 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
+
+/* 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)
+
+/* 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)
+
+/* 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
+
+/* 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)
+
+/* 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)
+
+
+#define GCI_INTSTATUS_GPIOINT (1 << 25)
+#define GCI_INTSTATUS_GPIOWAKE (1 << 26)
+#define GCI_INTMASK_GPIOINT (1 << 25)
+#define GCI_INTMASK_GPIOWAKE (1 << 26)
+#define GCI_WAKEMASK_GPIOINT (1 << 25)
+#define GCI_WAKEMASK_GPIOWAKE (1 << 26)
+
+
+/* 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)
+
+/*
+* 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
+
+
+/* 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_SIGNOFF_0 0xDB
+#define SECI_SIGNOFF_1 0
+
+/* seci clk_ctl_st bits */
+#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)
+
+/* SECI UART LCR/MCR 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_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)
+
+/* 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 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)
+
+#endif /* _SBCHIPC_H */
diff --git a/drivers/net/wireless/bcmdhd/include/sbconfig.h b/drivers/net/wireless/bcmdhd/include/sbconfig.h
new file mode 100644
index 000000000000..65a3caaca165
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sbconfig.h
@@ -0,0 +1,282 @@
+/*
+ * Broadcom SiliconBackplane hardware register 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: sbconfig.h 241182 2011-02-17 21:50:03Z $
+ */
+
+#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
+
+#ifndef _LANGUAGE_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 */
+
+/* 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/drivers/net/wireless/bcmdhd/include/sbhnddma.h b/drivers/net/wireless/bcmdhd/include/sbhnddma.h
new file mode 100644
index 000000000000..ea9d13f3899b
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sbhnddma.h
@@ -0,0 +1,416 @@
+/*
+ * Generic Broadcom Home Networking Division (HND) DMA engine HW interface
+ * This supports the following chips: BCM42xx, 44xx, 47xx .
+ *
+ * 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: sbhnddma.h 530682 2015-01-30 18:48:21Z $
+ */
+
+#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
+
+/* 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
+
+/* 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_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_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
+
+/* 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 */
+
+/* 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 0x0001ffff /* active descriptor */
+#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/drivers/net/wireless/bcmdhd/include/sbpcmcia.h b/drivers/net/wireless/bcmdhd/include/sbpcmcia.h
new file mode 100644
index 000000000000..4f2d40c7ef1d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sbpcmcia.h
@@ -0,0 +1,113 @@
+/*
+ * BCM43XX Sonics SiliconBackplane PCMCIA core hardware 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: sbpcmcia.h 427964 2013-10-07 07:13:33Z $
+ */
+
+#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
+
+
+/* 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/drivers/net/wireless/bcmdhd/include/sbsdio.h b/drivers/net/wireless/bcmdhd/include/sbsdio.h
new file mode 100644
index 000000000000..ecb5da0dcbed
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sbsdio.h
@@ -0,0 +1,186 @@
+/*
+ * 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-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: sbsdio.h 383835 2013-02-07 23:32:39Z $
+ */
+
+#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/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h
new file mode 100644
index 000000000000..9041f392f3fd
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h
@@ -0,0 +1,295 @@
+/*
+ * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific
+ * device core support
+ *
+ * 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: sbsdpcmdev.h 416730 2013-08-06 09:33:19Z $
+ */
+
+#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[7];
+
+ /* 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/drivers/net/wireless/bcmdhd/include/sbsocram.h b/drivers/net/wireless/bcmdhd/include/sbsocram.h
new file mode 100644
index 000000000000..470307065f3d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sbsocram.h
@@ -0,0 +1,200 @@
+/*
+ * BCM47XX Sonics SiliconBackplane embedded ram core
+ *
+ * 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: sbsocram.h 481592 2014-05-29 22:10:51Z $
+ */
+
+#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_<processorPT>_<backplanePT> */
+#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 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/drivers/net/wireless/bcmdhd/include/sdio.h b/drivers/net/wireless/bcmdhd/include/sdio.h
new file mode 100644
index 000000000000..2ada5ec5f67d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sdio.h
@@ -0,0 +1,619 @@
+/*
+ * SDIO spec header file
+ * Protocol and standard (common) device 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: sdio.h 416730 2013-08-06 09:33:19Z $
+ */
+
+#ifndef _SDIO_H
+#define _SDIO_H
+
+
+/* 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 */
+
+/* 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 */
+
+/* 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_3 3
+#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 /* _SDIO_H */
diff --git a/drivers/net/wireless/bcmdhd/include/sdioh.h b/drivers/net/wireless/bcmdhd/include/sdioh.h
new file mode 100644
index 000000000000..81d57d9efe2c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sdioh.h
@@ -0,0 +1,445 @@
+/*
+ * SDIO Host Controller Spec header file
+ * Register map and definitions for the Standard Host Controller
+ *
+ * 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: sdioh.h 345499 2012-07-18 06:59:05Z $
+ */
+
+#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/drivers/net/wireless/bcmdhd/include/sdiovar.h b/drivers/net/wireless/bcmdhd/include/sdiovar.h
new file mode 100644
index 000000000000..2abd48ec9b0f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sdiovar.h
@@ -0,0 +1,58 @@
+/*
+ * Structure used by apps whose drivers access SDIO drivers.
+ * Pulled out separately so dhdu and wlu can both use it.
+ *
+ * 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: sdiovar.h 241182 2011-02-17 21:50:03Z $
+ */
+
+#ifndef _sdiovar_h_
+#define _sdiovar_h_
+
+#include <typedefs.h>
+
+/* require default structure packing */
+#define BWL_DEFAULT_PACKING
+#include <packed_section_start.h>
+
+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 NUM_PREV_TRANSACTIONS 16
+
+
+#include <packed_section_end.h>
+
+#endif /* _sdiovar_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/siutils.h b/drivers/net/wireless/bcmdhd/include/siutils.h
new file mode 100644
index 000000000000..c6dae8970396
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/siutils.h
@@ -0,0 +1,440 @@
+/*
+ * Misc utility routines for accessing the SOC Interconnects
+ * of Broadcom HNBU chips.
+ *
+ * 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: siutils.h 530682 2015-01-30 18:48:21Z $
+ */
+
+#ifndef _siutils_h_
+#define _siutils_h_
+
+
+#include <bcmutils.h>
+/*
+ * 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;
+
+};
+
+/* 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
+#define SI_PCIUP 3
+
+#define ISSIM_ENAB(sih) FALSE
+
+/* PMU clock/power control */
+#if defined(BCMPMUCTL)
+#define PMUCTL_ENAB(sih) (BCMPMUCTL)
+#else
+#define PMUCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PMU)
+#endif
+
+/* chipcommon clock/power control (exclusive with PMU's) */
+#if defined(BCMPMUCTL) && BCMPMUCTL
+#define CCCTL_ENAB(sih) (0)
+#define CCPLL_ENAB(sih) (0)
+#else
+#define CCCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PWR_CTL)
+#define CCPLL_ENAB(sih) ((sih)->cccaps & CC_CAP_PLL_MASK)
+#endif
+
+typedef void (*gpio_handler_t)(uint32 stat, void *arg);
+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
+
+/* === exported functions === */
+extern si_t *si_attach(uint pcidev, osl_t *osh, 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 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_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val);
+extern uint32 *si_corereg_addr(si_t *sih, uint coreidx, uint regoff);
+extern 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 bool si_iscoreup(si_t *sih);
+extern uint si_numcoreunits(si_t *sih, uint coreid);
+extern uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit);
+extern void *si_setcoreidx(si_t *sih, uint coreidx);
+extern void *si_setcore(si_t *sih, uint coreid, uint coreunit);
+extern 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);
+extern uint32 si_ilp_clock(si_t *sih);
+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 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 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_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_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);
+
+/* GPIO event handlers */
+extern void *si_gpio_handler_register(si_t *sih, uint32 e, bool lev, gpio_handler_t cb, void *arg);
+extern void si_gpio_handler_unregister(si_t *sih, void* gpioh);
+extern void si_gpio_handler_process(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);
+
+/* Wake-on-wireless-LAN (WOWL) */
+extern bool si_pci_pmecap(si_t *sih);
+struct osl_info;
+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_sdio_init(si_t *sih);
+
+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);
+
+#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_seci_init(si_t *sih, uint8 use_seci) {return NULL;}
+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);
+extern bool si_is_sprom_enabled(si_t *sih);
+extern void si_sprom_enable(si_t *sih, bool enable);
+
+/* 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);
+
+/*
+ * 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);
+/* 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 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);
+/* 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_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);
+
+
+
+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 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);
+
+char *si_getnvramflvar(si_t *sih, const char *name);
+
+
+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);
+extern void si_ercx_init(si_t *sih);
+extern void si_wci2_init(si_t *sih, uint baudrate);
+extern void si_gci_seci_init(si_t *sih);
+extern void si_gci_set_functionsel(si_t *sih, uint32 pin, 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 uint16 si_cc_get_reg16(uint32 reg_offs);
+extern uint32 si_cc_get_reg32(uint32 reg_offs);
+extern uint32 si_cc_set_reg32(uint32 reg_offs, uint32 val);
+extern uint32 si_gci_preinit_upd_indirect(uint32 regidx, uint32 setval, uint32 mask);
+extern uint8 si_enable_device_wake(si_t *sih, uint8 *wake_status, uint8 *cur_status);
+
+#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 void si_pcie_ltr_war(si_t *sih);
+
+/* 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)
+
+#endif /* _siutils_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/spid.h b/drivers/net/wireless/bcmdhd/include/spid.h
new file mode 100644
index 000000000000..fb5536f8a184
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/spid.h
@@ -0,0 +1,165 @@
+/*
+ * SPI device spec header file
+ *
+ * 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: spid.h 358377 2012-09-23 11:30:22Z $
+ */
+
+#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/drivers/net/wireless/bcmdhd/include/trxhdr.h b/drivers/net/wireless/bcmdhd/include/trxhdr.h
new file mode 100644
index 000000000000..08010cec69ad
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/trxhdr.h
@@ -0,0 +1,92 @@
+/*
+ * TRX image file header format.
+ *
+ * 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: trxhdr.h 349211 2012-08-07 09:45:24Z $
+ */
+
+#ifndef _TRX_HDR_H
+#define _TRX_HDR_H
+
+#include <typedefs.h>
+
+#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/drivers/net/wireless/bcmdhd/include/typedefs.h b/drivers/net/wireless/bcmdhd/include/typedefs.h
new file mode 100644
index 000000000000..4912b7b438a1
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/typedefs.h
@@ -0,0 +1,344 @@
+/*
+ * 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: typedefs.h 453696 2014-02-06 01:10:20Z $
+ */
+
+#ifndef _TYPEDEFS_H_
+#define _TYPEDEFS_H_
+
+#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
+
+
+
+
+
+#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.
+ */
+#if !defined(LINUX_HYBRID) || defined(LINUX_PORT)
+#define TYPEDEF_UINT
+#ifndef TARGETENV_android
+#define TYPEDEF_USHORT
+#define TYPEDEF_ULONG
+#endif /* TARGETENV_android */
+#ifdef __KERNEL__
+#include <linux/version.h>
+#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 <linux/compiler.h>
+#ifdef noinline_for_stack
+#define TYPEDEF_BOOL
+#endif
+#endif /* == 2.6.18 */
+#endif /* __KERNEL__ */
+#endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */
+
+
+
+
+/* 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 */
+#if !defined(LINUX_HYBRID) || defined(LINUX_PORT)
+#include <linux/types.h> /* sys/types.h and linux/types.h are oil and water */
+#endif /* !defined(LINUX_HYBRID) || defined(LINUX_PORT) */
+
+#else
+
+
+#include <sys/types.h>
+
+#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
+
+/* 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))
+
+/*
+ * Including the bcmdefs.h here, to make sure everyone including typedefs.h
+ * gets this automatically
+*/
+#include <bcmdefs.h>
+#endif /* _TYPEDEFS_H_ */
diff --git a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h
new file mode 100644
index 000000000000..4eb4a3a41a2e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h
@@ -0,0 +1,304 @@
+/*
+* 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: wlfc_proto.h 431159 2013-10-22 19:40:51Z $
+*
+*/
+#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
+ | | | 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
+
+#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
+#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_TRANS_ID 18
+#define WLFC_CTL_TYPE_COMP_TXSTATUS 19
+
+
+#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_SEQ 2
+
+/* 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)
+
+#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)
+
+#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))
+#define WL_SEQ_GET_FROMFW(x) (((x) >> WL_SEQ_FROMFW_SHIFT) & \
+ WL_SEQ_FROMFW_MASK)
+
+#define WL_SEQ_FROMDRV_MASK 0x1 /* allow 1 bit */
+#define WL_SEQ_FROMDRV_SHIFT 12
+#define WL_SEQ_SET_FROMDRV(x, val) ((x) = \
+ ((x) & ~(WL_SEQ_FROMDRV_MASK << WL_SEQ_FROMDRV_SHIFT)) | \
+ (((val) & WL_SEQ_FROMDRV_MASK) << WL_SEQ_FROMDRV_SHIFT))
+#define WL_SEQ_GET_FROMDRV(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
+#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))
+#define WL_SEQ_GET_NUM(x) (((x) >> WL_SEQ_NUM_SHIFT) & \
+ WL_SEQ_NUM_MASK)
+
+/* 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
+
+#define WLFC_D11_STATUS_INTERPRET(txs) \
+ (((txs)->status.suppr_ind != TX_STATUS_SUPR_NONE) ? \
+ WLFC_CTL_PKTFLAG_D11SUPPRESS : \
+ ((txs)->status.was_acked ? \
+ WLFC_CTL_PKTFLAG_DISCARD : WLFC_CTL_PKTFLAG_DISCARD_NOACK))
+
+#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__, __builtin_return_address(0));}} 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 */
+#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))
+#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))
+#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))
+#define WLFC_GET_REORDERSUPP(x) (((x) >> WLFC_MODE_REORDERSUPP_SHIFT) & 1)
+
+#endif /* __wlfc_proto_definitions_h__ */
diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h
new file mode 100644
index 000000000000..cc2d667ec670
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h
@@ -0,0 +1,5008 @@
+/*
+ * Custom OID/ioctl definitions for
+ * Broadcom 802.11abg Networking Device Driver
+ *
+ * Definitions subject to change without notice.
+ *
+ * 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: wlioctl.h 662961 2016-11-24 01:22:35Z $
+ */
+
+#ifndef _wlioctl_h_
+#define _wlioctl_h_
+
+#include <typedefs.h>
+#include <proto/ethernet.h>
+#include <proto/bcmip.h>
+#include <proto/bcmeth.h>
+#include <proto/bcmip.h>
+#include <proto/bcmevent.h>
+#include <proto/802.11.h>
+#include <proto/802.1d.h>
+#include <bcmwifi_channels.h>
+#include <bcmwifi_rates.h>
+#include <devctrl_if/wlioctl_defs.h>
+
+#include <bcm_mpool_pub.h>
+#include <bcmcdc.h>
+
+
+
+
+#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)
+
+typedef struct {
+ uint32 num;
+ chanspec_t list[1];
+} chanspec_list_t;
+
+/* association decision information */
+typedef struct {
+ bool assoc_approved; /* (re)association approved */
+ uint16 reject_reason; /* reason code for rejecting association */
+ struct ether_addr da;
+ int64 sys_time; /* current system time */
+} assoc_decision_t;
+
+#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;
+ 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;
+ uint16 id;
+ struct ether_addr da;
+} wl_sa_query_t;
+
+/* require default structure packing */
+#define BWL_DEFAULT_PACKING
+#include <packed_section_start.h>
+
+
+
+/* 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];
+ struct {
+ uint 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. */
+ uint16 atim_window; /* units are Kusec */
+ uint8 dtim_period; /* DTIM period */
+ int16 RSSI; /* receive signal strength (in dBm) */
+ int8 phy_noise; /* noise (in dBm) */
+ 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];
+ struct {
+ uint 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 */
+ int16 RSSI; /* receive signal strength (in dBm) */
+ int8 phy_noise; /* noise (in dBm) */
+
+ uint8 n_cap; /* BSS is 802.11N Capable */
+ uint32 nbss_cap; /* 802.11N BSS Capabilities (based on HT_CAP_*) */
+ uint8 ctl_ch; /* 802.11N BSS control channel number */
+ 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 */
+ 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];
+ struct {
+ uint 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 */
+ int16 RSSI; /* receive signal strength (in dBm) */
+ int8 phy_noise; /* noise (in dBm) */
+
+ uint8 n_cap; /* BSS is 802.11N Capable */
+ 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 */
+ uint32 ie_length; /* byte length of Information Elements */
+ int16 SNR; /* average SNR of during frame reception */
+ /* Add new fields here */
+ /* variable length Information Elements */
+} wl_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;
+} 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
+
+/* 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;
+ uchar SSID[DOT11_MAX_SSID_LEN];
+} wlc_ssid_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 BWL_PRE_PACKED_STRUCT struct wnm_url {
+ uint8 len;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT 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 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))
+
+/* Used in EXT_STA */
+#define DNGL_RXCTXT_SIZE 45
+
+
+#define ESCAN_REQ_VERSION 1
+
+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))
+
+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))
+
+/* 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))
+
+#define SCANOL_PARAMS_VERSION 1
+
+typedef struct scanol_params {
+ uint32 version;
+ uint32 flags; /* offload scanning flags */
+ 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 idle_rest_time; /* -1 use default, time idle between scan cycle */
+ int32 idle_rest_time_multiplier;
+ int32 active_rest_time;
+ int32 active_rest_time_multiplier;
+ int32 scan_cycle_idle_rest_time;
+ int32 scan_cycle_idle_rest_multiplier;
+ int32 scan_cycle_active_rest_time;
+ int32 scan_cycle_active_rest_multiplier;
+ int32 max_rest_time;
+ int32 max_scan_cycles;
+ int32 nprobes; /* -1 use default, number of probes per channel */
+ int32 scan_start_delay;
+ uint32 nchannels;
+ uint32 ssid_count;
+ wlc_ssid_t ssidlist[1];
+} scanol_params_t;
+
+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 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;
+} 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;
+
+/* 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)
+/* scan params for extended join */
+typedef struct wl_join_scan_params {
+ uint8 scan_type; /* 0 use default, active or passive scan */
+ 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? */
+ uint8 num_secs; /* How many secs worth of data */
+ cca_congest_t secs[1]; /* Data */
+} cca_congest_channel_req_t;
+
+typedef struct {
+ uint32 msrmnt_time; /**< Time for Measurement (msec) */
+ uint32 msrmnt_done; /**< flag set when measurement complete */
+ char buf[1];
+} 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 */
+} 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;
+
+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];
+ int pad_3;
+ int iv_initialized; /* has IV been initialized already? */
+ int pad_4;
+ /* Rx IV */
+ struct {
+ uint32 hi; /* upper 32 bits of IV */
+ uint16 lo; /* lower 16 bits of IV */
+ } rxiv;
+ uint32 pad_5[2];
+ struct ether_addr ea; /* per station */
+} wl_wsec_key_t;
+
+#define WSEC_MIN_PSK_LEN 8
+#define WSEC_MAX_PSK_LEN 64
+
+/* Flag for key material needing passhash'ing */
+#define WSEC_PASSPHRASE (1<<0)
+
+/* receptacle for WLC_SET_WSEC_PMK parameter */
+typedef struct {
+ ushort key_len; /* octets in key material */
+ ushort flags; /* key handling qualification */
+ uint8 key[WSEC_MAX_PSK_LEN]; /* PMK material */
+} wsec_pmk_t;
+
+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;
+} wl_led_info_t;
+
+
+/* srom read/write struct passed through ioctl */
+typedef struct {
+ uint byteoff; /* byte offset */
+ uint nbytes; /* number of bytes */
+ uint16 buf[1];
+} srom_rw_t;
+
+/* similar cis (srom or otp) struct [iovar: may not be aligned] */
+typedef struct {
+ uint32 source; /* cis source */
+ 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 */
+ uint 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)
+
+typedef struct wl_plc_nodelist {
+ uint32 count; /* Number of nodes */
+ struct _node {
+ struct ether_addr ea; /* Node ether address */
+ uint32 node_type; /* Node type */
+ uint32 cost; /* PLC affinity */
+ } node[1];
+} wl_plc_nodelist_t;
+
+typedef struct wl_plc_params {
+ uint32 cmd; /* Command */
+ uint8 plc_failover; /* PLC failover control/status */
+ struct ether_addr node_ea; /* Node ether address */
+ uint32 cost; /* Link cost or mac cost */
+} wl_plc_params_t;
+
+/* Used to get specific link/ac parameters */
+typedef struct {
+ int32 ac;
+ uint8 val;
+ struct ether_addr ea;
+} link_val_t;
+
+
+
+typedef struct {
+ uint16 ver; /* version of this struct */
+ uint16 len; /* length in bytes of this structure */
+ uint16 cap; /* sta's advertised capabilities */
+ uint32 flags; /* flags defined below */
+ uint32 idle; /* time since data pkt rx'd from sta */
+ struct ether_addr ea; /* Station address */
+ 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 packets transmitted */
+ uint32 tx_failures; /* # of packets failed */
+ uint32 rx_ucast_pkts; /* # of unicast packets received */
+ uint32 rx_mcast_pkts; /* # of multicast packets received */
+ uint32 tx_rate; /* Rate of last successful 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 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 */
+ uint32 tx_pkts_retried; /* # of frames where a retry was necessary */
+ uint32 tx_pkts_retry_exhausted; /* # of frames where a retry was
+ * exhausted
+ */
+ int8 rx_lastpkt_rssi[WL_STA_ANT_MAX]; /* Per antenna RSSI of last
+ * received data frame.
+ */
+} sta_info_t;
+
+#define WL_OLD_STAINFO_SIZE OFFSETOF(sta_info_t, tx_tot_pkts)
+
+#define WL_STA_VER 4
+
+#define WLC_NUMRATES 16 /* max # of rates in a rateset */
+
+typedef struct wlc_rateset {
+ uint32 count; /* number of rates in rates[] */
+ uint8 rates[WLC_NUMRATES]; /* rates in 500kbps units w/hi bit set if basic */
+ uint8 htphy_membership; /* HT PHY Membership */
+ uint8 mcs[MCSSET_LEN]; /* supported mcs index bit map */
+ uint16 vht_mcsmap; /* supported vht mcs nss bit map */
+} wlc_rateset_t;
+
+/* Used to get specific STA parameters */
+typedef struct {
+ uint32 val;
+ struct ether_addr ea;
+} 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 {
+ int hw_channel;
+ int target_channel;
+ int scan_channel;
+} channel_info_t;
+
+/* For ioctls that take a list of MAC addresses */
+struct maclist {
+ uint count; /* number of MAC addresses */
+ struct ether_addr ea[1]; /* variable length array of MAC addresses */
+};
+
+/* get pkt count struct passed through ioctl */
+typedef struct get_pktcnt {
+ uint rx_good_pkt;
+ uint rx_bad_pkt;
+ uint tx_good_pkt;
+ uint tx_bad_pkt;
+ uint 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 */
+typedef struct {
+ int rssi[LQ_IDX_LAST]; /* Array to keep min, max, avg rssi */
+ int snr[LQ_IDX_LAST]; /* Array to keep min, max, avg snr */
+ int isvalid; /* Flag indicating whether above data is valid */
+} wl_lq_t; /* Link Quality */
+
+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;
+} 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; /* MAC Specific Rate Histogram command */
+
+/* Get MAC rate histogram response */
+typedef struct {
+ uint32 rate[DOT11_RATE_MAX + 1]; /* Rates */
+ uint32 mcs[WL_RATESET_SZ_HT_MCS * 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 */
+} wl_mac_ratehisto_res_t; /* MAC Specific Rate Histogram Response */
+
+/* Linux network driver ioctl encoding */
+typedef struct wl_ioctl {
+ uint cmd; /* common ioctl definition */
+ void *buf; /* pointer to user buffer */
+ uint len; /* length of user buffer */
+ uint8 set; /* 1=set IOCTL; 0=query IOCTL */
+ uint used; /* bytes read or written (optional) */
+ uint needed; /* bytes needed (optional) */
+} wl_ioctl_t;
+#ifdef CONFIG_COMPAT
+typedef struct compat_wl_ioctl {
+ uint cmd; /* common ioctl definition */
+ uint32 buf; /* pointer to user buffer */
+ uint len; /* length of user buffer */
+ uint8 set; /* 1=set IOCTL; 0=query IOCTL */
+ uint used; /* bytes read or written (optional) */
+ uint needed; /* bytes needed (optional) */
+} compat_wl_ioctl_t;
+#endif /* CONFIG_COMPAT */
+
+
+/*
+ * Structure for passing hardware and software
+ * revision info up from the driver.
+ */
+typedef struct wlc_rev_info {
+ uint vendorid; /* PCI vendor id */
+ uint deviceid; /* device id of chip */
+ uint radiorev; /* radio revision */
+ uint chiprev; /* chip revision */
+ uint corerev; /* core revision */
+ uint boardid; /* board identifier (usu. PCI sub-device id) */
+ uint boardvendor; /* board vendor (usu. PCI sub-vendor id) */
+ uint boardrev; /* board revision */
+ uint driverrev; /* driver version */
+ uint ucoderev; /* microcode version */
+ uint bus; /* bus type */
+ uint chipnum; /* chip number */
+ uint phytype; /* phy type */
+ uint phyrev; /* phy revision */
+ uint anarev; /* anacore rev */
+ uint chippkg; /* chip package info */
+ uint nvramrev; /* nvram revision number */
+} wlc_rev_info_t;
+
+#define WL_REV_INFO_LEGACY_LENGTH 48
+
+#define WL_BRAND_MAX 10
+typedef struct wl_instance_info {
+ uint instance;
+ char brand[WL_BRAND_MAX];
+} 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 30
+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 CONFIG_USBRNDIS_RETAIL
+/* struct passed in for WLC_NDCONFIG_ITEM */
+typedef struct {
+ char *name;
+ void *param;
+} ndconfig_item_t;
+#endif
+
+
+#define WL_PHY_PAVARS_LEN 32 /* Phy type, Band range, chain, a1[0], b0[0], b1[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;
+ 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;
+
+typedef struct wl_aci_args {
+ int enter_aci_thresh; /* Trigger level to start detecting ACI */
+ int exit_aci_thresh; /* Trigger level to exit ACI mode */
+ int usec_spin; /* microsecs to delay between rssi samples */
+ int 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;
+ int cores;
+ /* add'l version 1 fields */
+ uint16 version; /* see definition of WL_SAMPLECOLLECT_T_VERSION */
+ uint16 length; /* length of entire structure */
+ int8 trigger;
+ uint16 timeout;
+ uint16 mode;
+ 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;
+ int bitStart;
+ uint32 gpioCapMask;
+} 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 */
+};
+typedef struct ota_rate_info {
+ uint8 rate_cnt; /* Total number of rates */
+ uint8 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;
+
+/* 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 */
+ 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 */
+} wl_ota_test_args_t;
+
+typedef struct wl_ota_test_vector {
+ 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 */
+} 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 */
+ 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;
+
+/* WL_OTA END */
+
+/* wl_radar_args_t */
+typedef struct {
+ int npulses; /* required number of pulses at n * t_int */
+ int ncontig; /* required number of pulses at t_int */
+ int min_pw; /* minimum pulse width (20 MHz clocks) */
+ int 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 */
+ int npulses_lp; /* Radar detection, minimum long pulses */
+ int min_pw_lp; /* Minimum pulsewidth for long pulses */
+ int max_pw_lp; /* Maximum pulsewidth for long pulses */
+ int min_fm_lp; /* Minimum fm for long pulses */
+ int max_span_lp; /* Maximum deltat for long pulses */
+ int min_deltat; /* Minimum spacing between pulses */
+ int 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 */
+ uint32 version; /* version */
+ uint32 fra_pulse_err; /* sample error margin for detecting French radar pulsed */
+ int npulses_fra; /* Radar detection, minimum French pulses set */
+ int npulses_stg2; /* Radar detection, minimum staggered-2 pulses set */
+ int npulses_stg3; /* Radar detection, minimum staggered-3 pulses set */
+ uint16 percal_mask; /* defines which period cal is masked from radar detection */
+ int 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 */
+ int nskip_rst_lp; /* number of skipped pulses before resetting lp buffer */
+ int max_pw_tol; /* maximum tollerance allowed in detected pulse width for radar detection */
+ uint16 feature_mask; /* 16-bit mask to specify enabled features */
+} 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 */
+#ifdef WL11AC160
+ 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 */
+#endif /* WL11AC160 */
+} wl_radar_thr_t;
+
+#define WL_RADAR_THR_VERSION 2
+
+/* 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;
+
+/* data structure used in 'dfs_status' wl interface, which is used to query dfs status */
+typedef struct {
+ uint state; /* noted by WL_DFS_CACSTATE_XX. */
+ uint 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 uint, add another to uint16 to maintain size */
+ uint16 pad;
+} wl_dfs_status_t;
+
+/* data structure used in 'radar_status' wl interface, which is use to query radar det status */
+typedef struct {
+ bool detected;
+ int count;
+ bool pretended;
+ uint32 radartype;
+ uint32 timenow;
+ uint32 timefromL;
+ int lp_csect_single;
+ int detected_pulse_index;
+ int nconsecq_pulses;
+ chanspec_t ch;
+ int pw[10];
+ int intv[10];
+ int 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 */
+} tx_power_legacy2_t;
+
+/* TX Power index defines */
+#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
+
+#define WLC_NUM_RATES_CCK WL_NUM_RATES_CCK
+#define WLC_NUM_RATES_OFDM WL_NUM_RATES_OFDM
+#define WLC_NUM_RATES_MCS_1_STREAM WL_NUM_RATES_MCS_1STREAM
+#define WLC_NUM_RATES_MCS_2_STREAM WL_NUM_RATES_MCS_1STREAM
+#define WLC_NUM_RATES_MCS32 WL_NUM_RATES_MCS32
+#define WL_TX_POWER_CCK_NUM WL_NUM_RATES_CCK
+#define WL_TX_POWER_OFDM_NUM WL_NUM_RATES_OFDM
+#define WL_TX_POWER_MCS_1_STREAM_NUM WL_NUM_RATES_MCS_1STREAM
+#define WL_TX_POWER_MCS_2_STREAM_NUM WL_NUM_RATES_MCS_1STREAM
+#define WL_TX_POWER_MCS_32_NUM WL_NUM_RATES_MCS32
+
+#define WL_NUM_2x2_ELEMENTS 4
+#define WL_NUM_3x3_ELEMENTS 6
+
+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 44
+
+
+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
+
+/*
+ * 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 NFIFO 6 /* # tx/rx fifopairs */
+#define NREINITREASONCOUNT 8
+#define REINITREASONIDX(_x) (((_x) < NREINITREASONCOUNT) ? (_x) : 0)
+
+#define WL_CNT_T_VERSION 10 /* current version of wl_cnt_t struct */
+
+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 */
+} wl_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;
+ 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_six_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;
+
+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;
+};
+
+typedef struct wl_mkeep_alive_pkt {
+ uint16 version; /* Version for mkeep_alive */
+ uint16 length; /* length of fixed parameters in the structure */
+ uint32 period_msec;
+ 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
+
+/* 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 */
+} 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 */
+ uchar packet[1];
+} wake_info_t;
+
+typedef struct wake_pkt {
+ uint32 wake_pkt_len; /* size of packet */
+ uchar packet[1];
+} 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 per-tid, per-mode ampdu control */
+struct ampdu_tid_control_mode {
+ struct ampdu_tid_control control[NUMPRIO]; /* tid will be 0xff for not used element */
+ char mode_name[8]; /* supported mode : AIBSS */
+};
+
+/* structure for identifying ea/tid for sending addba/delba */
+struct ampdu_ea_tid {
+ struct ether_addr ea; /* Station address */
+ uint8 tid; /* tid */
+};
+/* structure for identifying retry/tid for retry_limit_tid/rr_retry_limit_tid */
+struct ampdu_retry_tid {
+ uint8 tid; /* tid */
+ uint8 retry; /* retry value */
+};
+
+/* structure for dpt iovars */
+typedef struct dpt_iovar {
+ struct ether_addr ea; /* Station address */
+ uint8 mode; /* mode: depends on iovar */
+ uint32 pad; /* future */
+} dpt_iovar_t;
+
+#define DPT_FNAME_LEN 48 /* Max length of friendly name */
+
+typedef struct dpt_status {
+ uint8 status; /* flags to indicate status */
+ uint8 fnlen; /* length of friendly name */
+ uchar name[DPT_FNAME_LEN]; /* friendly name */
+ uint32 rssi; /* RSSI of the link */
+ sta_info_t sta; /* sta info */
+} dpt_status_t;
+
+/* structure for dpt list */
+typedef struct dpt_list {
+ uint32 num; /* number of entries in struct */
+ dpt_status_t status[1]; /* per station info */
+} dpt_list_t;
+
+/* structure for dpt friendly name */
+typedef struct dpt_fname {
+ uint8 len; /* length of friendly name */
+ uchar name[DPT_FNAME_LEN]; /* friendly name */
+} dpt_fname_t;
+
+#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 {
+ int count; /* number of tspecs */
+ struct tsinfo_arg tsinfo[1]; /* variable length array of tsinfo */
+};
+
+#ifdef WLTDLS
+/* structure for tdls iovars */
+typedef struct tdls_iovar {
+ struct ether_addr ea; /* Station address */
+ uint8 mode; /* mode: depends on iovar */
+ chanspec_t chanspec;
+ 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;
+ 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 */
+ uint flag; /* bit field */
+ /* TSPEC Arguments */
+ struct tsinfo_arg tsinfo; /* TS Info bit field */
+ uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */
+ uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */
+ uint min_srv_interval; /* Minimum Service Interval (us) */
+ uint max_srv_interval; /* Maximum Service Interval (us) */
+ uint inactivity_interval; /* Inactivity Interval (us) */
+ uint suspension_interval; /* Suspension Interval (us) */
+ uint srv_start_time; /* Service Start Time (us) */
+ uint min_data_rate; /* Minimum Data Rate (bps) */
+ uint mean_data_rate; /* Mean Data Rate (bps) */
+ uint peak_data_rate; /* Peak Data Rate (bps) */
+ uint max_burst_size; /* Maximum Burst Size (bytes) */
+ uint delay_bound; /* Delay Bound (us) */
+ uint 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 */
+} tspec_arg_t;
+
+/* tspec arg for desired station */
+typedef struct tspec_per_sta_arg {
+ struct ether_addr ea;
+ 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;
+
+/* 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_SCANRESULT_VERSION 1
+#define MAX_PFN_LIST_COUNT 16
+
+#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
+
+/* PFN network info structure */
+typedef struct wl_pfn_subnet_info {
+ struct ether_addr BSSID;
+ uint8 channel; /* channel number only */
+ uint8 SSID_len;
+ uint8 SSID[32];
+} wl_pfn_subnet_info_t;
+
+typedef struct wl_pfn_net_info {
+ wl_pfn_subnet_info_t pfnsubnet;
+ int16 RSSI; /* receive signal strength (in dBm) */
+ uint16 timestamp; /* age in seconds */
+} wl_pfn_net_info_t;
+
+typedef struct wl_pfn_lnet_info {
+ wl_pfn_subnet_info_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_t;
+
+typedef struct wl_pfn_lscanresults {
+ uint32 version;
+ uint32 status;
+ uint32 count;
+ wl_pfn_lnet_info_t netinfo[1];
+} wl_pfn_lscanresults_t;
+
+typedef struct wl_pfn_scanresults {
+ uint32 version;
+ uint32 status;
+ uint32 count;
+ wl_pfn_net_info_t netinfo[1];
+} wl_pfn_scanresults_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;
+#define WL_PFN_SUPPRESSFOUND_MASK 0x08
+#define WL_PFN_SUPPRESSLOST_MASK 0x10
+#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_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;
+
+typedef BWL_PRE_PACKED_STRUCT struct pfn_olmsg_params_t {
+ wlc_ssid_t ssid;
+ uint32 cipher_type;
+ uint32 auth_type;
+ uint8 channels[4];
+} BWL_POST_PACKED_STRUCT pfn_olmsg_params;
+
+#define WL_PFN_HIDDEN_BIT 2
+#define WL_PFN_HIDDEN_MASK 0x4
+
+#ifndef BESTN_MAX
+#define BESTN_MAX 3
+#endif
+
+#ifndef MSCAN_MAX
+#define MSCAN_MAX 90
+#endif
+
+/* 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[1];
+} wl_p2po_qr_t;
+
+typedef struct {
+ uint16 period; /* extended listen period */
+ uint16 interval; /* extended listen interval */
+} wl_p2po_listen_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 {
+ bool is_clear; /* set to clear list (not used on GET) */
+ 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 {
+ bool is_clear; /* set to clear list (not used on GET) */
+ uint16 count; /* number of addr in list */
+ struct ether_addr bssid[1]; /* 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 */
+};
+
+/*
+ * 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)
+
+
+/*
+ * 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;
+ uchar 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_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 }
+
+/* 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[1]; /* Variable length mask and pattern data. mask starts
+ * at offset 0. Pattern immediately follows mask.
+ */
+} 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[1]; /* Variable number of list elements */
+} wl_pkt_filter_pattern_list_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_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)
+
+/* 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[<count>] */
+} 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_KCK_LENGTH 16
+#define RSN_KEK_LENGTH 16
+#define RSN_REPLAY_LEN 8
+typedef struct _gtkrefresh {
+ uchar KCK[RSN_KCK_LENGTH];
+ uchar KEK[RSN_KEK_LENGTH];
+ uchar 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 */
+} wl_pkteng_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 */
+} wl_pkteng_stats_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 {
+ uint 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;
+
+typedef struct {
+ uint32 pktlen; /* size of packet */
+ void *sdu;
+} tcp_keepalive_wake_pkt_infop_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.
+ */
+} wl_rssi_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
+
+typedef struct {
+ uint32 num_addrs;
+ char addr_type[WL_IOV_MAC_PARAM_LEN];
+ struct ether_addr ea[WL_IOV_MAC_PARAM_LEN];
+} wl_iov_mac_params_t;
+
+/* 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[1];
+} 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[1];
+} 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)
+
+/*
+ * SCB_BS_DATA iovar definitions start.
+ */
+#define SCB_BS_DATA_STRUCT_VERSION 1
+
+/* The actual counters maintained for each station */
+typedef BWL_PRE_PACKED_STRUCT 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 */
+} BWL_POST_PACKED_STRUCT iov_bs_data_counters_t;
+
+/* The structure for individual station information. */
+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;
+
+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;
+
+/* 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 {
+ int max_number;
+ uint16 module; /* bitmap */
+ uint8 level;
+ uint8 flag;
+ uint16 version;
+} wlc_extlog_cfg_t;
+
+typedef struct log_record {
+ uint32 time;
+ uint16 module;
+ uint16 id;
+ uint8 level;
+ uint8 sub_unit;
+ uint8 seq_num;
+ int32 arg;
+ char str[MAX_ARGSTR_LEN];
+} 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;
+
+#ifdef DONGLEOVERLAYS
+typedef struct {
+ uint32 flags_idx; /* lower 8 bits: overlay index; upper 24 bits: flags */
+ uint32 offset; /* offset into overlay region to write code */
+ uint32 len; /* overlay code len */
+ /* overlay code follows this struct */
+} wl_ioctl_overlay_t;
+#endif /* DONGLEOVERLAYS */
+
+/* 11k Neighbor Report element */
+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;
+
+/* no default structure packing */
+#include <packed_section_end.h>
+
+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)
+
+/* require strict packing */
+#include <packed_section_start.h>
+
+
+/* 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))
+
+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;
+
+typedef BWL_PRE_PACKED_STRUCT struct {
+ int 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;
+
+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;
+
+/* tag_ID/length/value_buffer tuple */
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint8 id;
+ uint8 len;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT tlv_t;
+
+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;
+
+typedef BWL_PRE_PACKED_STRUCT struct {
+ int 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;
+
+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;
+
+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;
+
+/* structures used to define format of wps ie data from probe requests */
+/* passed up to applications via iovar "prbreq_wpsie" */
+typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_hdr {
+ struct ether_addr staAddr;
+ uint16 ieLen;
+} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_hdr_t;
+
+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;
+
+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;
+
+
+#ifdef WLMEDIA_TXFAILEVENT
+typedef BWL_PRE_PACKED_STRUCT struct {
+ char dest[ETHER_ADDR_LEN]; /* destination MAC */
+ uint8 prio; /* Packet Priority */
+ uint8 flags; /* Flags */
+ uint32 tsf_l; /* TSF timer low */
+ uint32 tsf_h; /* TSF timer high */
+ uint16 rates; /* Main Rates */
+ uint16 txstatus; /* TX Status */
+} BWL_POST_PACKED_STRUCT txfailinfo_t;
+#endif /* WLMEDIA_TXFAILEVENT */
+
+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 */
+ uint tx_power_max_rate_ind[4]; /* Index of the rate with the max target power */
+ int8 clm_limits[WL_NUMRATES]; /* regulatory limits - 20, 40 or 80MHz */
+ int8 clm_limits_subchan1[WL_NUMRATES]; /* regulatory limits - 20in40 or 40in80 */
+ int8 clm_limits_subchan2[WL_NUMRATES]; /* regulatory limits - 20in80MHz */
+ 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 */
+ uint user_target; /* user limit */
+ uint32 board_limit_len; /* length of board limit buffer */
+ uint32 target_len; /* length of target power buffer */
+ int8 SARLIMIT[MAX_STREAMS_SUPPORTED];
+ uint8 pprdata[1]; /* ppr serialization buffer */
+} BWL_POST_PACKED_STRUCT tx_pwr_rpt_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct {
+ struct ipv4_addr ipv4_addr;
+ struct ether_addr nexthop;
+} BWL_POST_PACKED_STRUCT ibss_route_entry_t;
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint32 num_entry;
+ ibss_route_entry_t route_entry[1];
+} BWL_POST_PACKED_STRUCT ibss_route_tbl_t;
+
+#define MAX_IBSS_ROUTE_TBL_ENTRY 64
+
+#define TXPWR_TARGET_VERSION 0
+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;
+
+#define BSS_PEER_INFO_PARAM_CUR_VER 0
+/* Input structure for IOV_BSS_PEER_INFO */
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint16 version;
+ struct ether_addr ea; /* peer MAC address */
+} BWL_POST_PACKED_STRUCT bss_peer_info_param_t;
+
+#define BSS_PEER_INFO_CUR_VER 0
+
+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;
+
+#define BSS_PEER_LIST_INFO_CUR_VER 0
+
+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;
+
+#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 */
+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;
+
+#define AIBSS_TXFAIL_CONFIG_VER_0 0
+
+/* structure used to configure aibss tx fail event */
+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 */
+} BWL_POST_PACKED_STRUCT aibss_txfail_config_t;
+
+/* no strict structure packing */
+#include <packed_section_end.h>
+
+ /* Global ASSERT Logging */
+#define ASSERTLOG_CUR_VER 0x0100
+#define MAX_ASSRTSTR_LEN 64
+
+ typedef struct assert_record {
+ uint32 time;
+ uint8 seq_num;
+ char 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))
+
+
+ /* chanim acs record */
+ typedef struct {
+ bool valid;
+ uint8 trigger;
+ chanspec_t selected_chspc;
+ int8 bgnoise;
+ uint32 glitch_cnt;
+ uint8 ccastats;
+ uint timestamp;
+ } chanim_acs_record_t;
+
+ typedef struct {
+ chanim_acs_record_t acs_record[CHANIM_ACS_RECORD];
+ uint8 count;
+ uint timestamp;
+ } wl_acs_record_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) */
+ chanspec_t chanspec;
+ uint32 timestamp;
+ uint32 bphy_glitchcnt; /* normalized as per second count */
+ uint32 bphy_badplcp; /* normalized as per second count */
+ uint8 chan_idle; /* normalized as 0~255 */
+ } chanim_stats_t;
+
+#define WL_CHANIM_STATS_VERSION 2
+
+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 */
+} 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 */
+ 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 {
+ int version;
+ int8 num_phy_cores; /* number of cores */
+ int8 curr_temperature; /* on-chip temperature sensor reading */
+ chanspec_t chspec; /* channspec for this state */
+ bool aci_state; /* ACI state: ON/OFF */
+ 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 */
+ 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 */
+ chanspec_t chspec; /* for p2p_ifadd GO */
+} wl_p2p_if_t;
+
+/* i/f query */
+typedef struct wl_p2p_ifq {
+ uint 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 */
+ wl_p2p_sched_desc_t desc[1];
+} wl_p2p_sched_t;
+
+typedef struct wl_bcmdcs_data {
+ uint reason;
+ chanspec_t chspec;
+} wl_bcmdcs_data_t;
+
+
+/* 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 */
+ 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 {
+ uint op; /* operation code */
+ bool pub_if; /* set for public if, clear for private if */
+ nat_if_info_t if_info; /* interface info */
+} nat_cfg_t;
+
+typedef struct {
+ int state; /* NAT state returned */
+} nat_state_t;
+
+
+#define BTA_STATE_LOG_SZ 64
+
+/* BTAMP Statemachine states */
+enum {
+ HCIReset = 1,
+ HCIReadLocalAMPInfo,
+ HCIReadLocalAMPASSOC,
+ HCIWriteRemoteAMPASSOC,
+ HCICreatePhysicalLink,
+ HCIAcceptPhysicalLinkRequest,
+ HCIDisconnectPhysicalLink,
+ HCICreateLogicalLink,
+ HCIAcceptLogicalLink,
+ HCIDisconnectLogicalLink,
+ HCILogicalLinkCancel,
+ HCIAmpStateChange,
+ HCIWriteLogicalLinkAcceptTimeout
+};
+
+typedef struct flush_txfifo {
+ uint32 txfifobmp;
+ uint32 hwtxfifoflush;
+ struct ether_addr ea;
+} 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_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;
+
+/* IOVAR "mempool" parameter. Used to retrieve a list of memory pool statistics. */
+typedef struct wl_mempool_stats {
+ int 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 */
+ 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 statisics 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;
+
+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 */
+} powersel_params_t;
+
+typedef struct lpc_params {
+ /* 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 */
+} scb_delay_stats_t;
+
+/* structure for txdelay event */
+typedef struct txdelay_event {
+ uint8 status;
+ int 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 */
+} txdelay_params_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[1];
+} 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_resp" argument programming behavior after BSSTRANS Req reception */
+enum {
+ WL_BSSTRANS_RESP_ROAM_ALWAYS = 0, /* Roam (or disassociate) in all cases */
+ WL_BSSTRANS_RESP_ROAM_IF_MODE = 1, /* Roam only if requested by Request Mode field */
+ WL_BSSTRANS_RESP_ROAM_IF_PREF = 2, /* Roam only if Preferred BSS provided */
+ WL_BSSTRANS_RESP_WAIT = 3 /* Wait for deauth and send Accepted status */
+};
+
+/* 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 */
+} 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 */
+ 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_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_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 */
+ 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 */
+ 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 */
+ 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 */
+} 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;
+
+/* Transmitter Info */
+typedef struct wl_rmc_trans_info {
+ struct ether_addr addr; /* transmitter mac */
+ uint32 time_val; /* timer val in case aging of entry is required */
+ uint16 seq; /* last seq number of packet received from transmitter */
+ uint16 artmo;
+} wl_rmc_trans_info_t;
+
+/* Multicast Group */
+typedef struct wl_rmc_grp_entry {
+ struct ether_addr mcaddr; /* multi-cast group mac */
+ struct ether_addr ar; /* active receiver for the group */
+ wl_rmc_trans_info_t tr_info[WL_RMC_MAX_TRS_PER_GROUP];
+} wl_rmc_grp_entry_t;
+
+/* RMC ACKALL Table */
+typedef struct wl_rmc_ackall_entry {
+ struct ether_addr ar; /* active receiver for the entry */
+ wl_rmc_trans_info_t tr_info[WL_RMC_NUM_OF_MC_STREAMS];
+} wl_rmc_ackall_entry_t;
+
+/* RMC Peers Table */
+typedef struct wl_rmc_gbl_table {
+ uint8 activeMask; /* mask to denote the entry(s) that are active */
+ wl_rmc_ackall_entry_t ackAll; /* structure to keep info related to ACK all */
+ wl_rmc_grp_entry_t mc_entry[WL_RMC_NUM_OF_MC_STREAMS];
+} wl_rmc_gbl_table_t;
+
+/* To update vendor specific ie for RMC */
+typedef struct wl_rmc_vsie {
+ uint8 oui[DOT11_OUI_LEN];
+ 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_RANDOM_WAKEUP 0x8000
+
+typedef struct wl_proxd_iovar {
+ uint16 method; /* Proxmity 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
+ */
+
+/* require strict packing */
+#include <packed_section_start.h>
+
+typedef BWL_PRE_PACKED_STRUCT 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) */
+} BWL_POST_PACKED_STRUCT wl_proxd_params_common_t;
+
+typedef BWL_PRE_PACKED_STRUCT 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 BWL_PRE_PACKED_STRUCT 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 */
+} BWL_POST_PACKED_STRUCT wl_proxd_params_tof_method_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_tof_tune {
+ 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 force_K; /* set to force value of K */
+ 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 */
+} BWL_POST_PACKED_STRUCT wl_proxd_params_tof_tune_t;
+
+typedef struct wl_proxd_params_iovar {
+ uint16 method; /* Proxmity 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 meothod parameters */
+ /* tune parameters */
+ wl_proxd_params_tof_tune_t tof_tune; /* TOF tune parameters */
+ } 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
+
+typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_query {
+ uint32 method; /* method */
+ uint8 request; /* Query request. */
+ uint8 status; /* 0 -- disable, 1 -- enable collection, */
+ /* 2 -- enable collection & debug */
+ uint16 index; /* The current frame index [0 to total_frames - 1]. */
+ uint16 mode; /* Initiator or Target */
+ bool busy; /* tof sm is busy */
+ bool remote; /* Remote collect data */
+} BWL_POST_PACKED_STRUCT wl_proxd_collect_query_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_header {
+ uint16 total_frames; /* The totral 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 loaclMacAddr; /* 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;
+
+/* ********************** NAN wl interface struct types and defs ******************** */
+
+#define WL_NAN_IOCTL_VERSION 0x1
+
+/* wl_nan_sub_cmd may also be used in dhd */
+typedef struct wl_nan_sub_cmd wl_nan_sub_cmd_t;
+typedef int (cmd_handler_t)(void *wl, const wl_nan_sub_cmd_t *cmd, char **argv);
+/* nan cmd list entry */
+struct wl_nan_sub_cmd {
+ char *name;
+ uint8 version; /* cmd version */
+ uint16 id; /* id for the dongle f/w switch/case */
+ uint16 type; /* base type of argument */
+ cmd_handler_t *handler; /* cmd handler */
+};
+
+/* container for nan iovtls & events */
+typedef BWL_PRE_PACKED_STRUCT 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[] */
+ uint8 data [1]; /* var len payload of bcm_xtlv_t type */
+} BWL_POST_PACKED_STRUCT wl_nan_ioc_t;
+
+typedef struct wl_nan_status {
+ uint8 inited;
+ uint8 joined;
+ uint8 role;
+ uint8 hop_count;
+ uint32 chspec;
+ 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 */
+ struct ether_addr cid;
+} wl_nan_status_t;
+
+/* various params and ctl swithce for nan_debug instance */
+typedef struct nan_debug_params {
+ uint8 enabled; /* runtime debuging enabled */
+ uint8 collect; /* enables debug svc sdf monitor mode */
+ uint16 cmd; /* debug cmd to perform a debug action */
+ uint32 msglevel; /* msg level if enabled */
+ uint16 status;
+} nan_debug_params_t;
+
+
+/* nan passive scan params */
+#define NAN_SCAN_MAX_CHCNT 8
+typedef BWL_PRE_PACKED_STRUCT 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;
+ chanspec_t chspec_list[NAN_SCAN_MAX_CHCNT]; /* act. used 3, 5 rfu */
+} BWL_POST_PACKED_STRUCT nan_scan_params_t;
+
+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
+};
+#define NAN_MASTER_RANK_LEN 8
+/* 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,
+ /* 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_DEBUG = 60,
+ WL_NAN_CMD_TEST1 = 61,
+ WL_NAN_CMD_TEST2 = 62,
+ WL_NAN_CMD_TEST3 = 63
+};
+
+/*
+ * tlv IDs uniquely identifies cmd parameters
+ * packed into wl_nan_ioc_t container
+ */
+enum wl_nan_cmd_xtlv_id {
+ /* 0x00 ~ 0xFF: standard TLV ID whose data format is the same as NAN attribute TLV */
+ WL_NAN_XTLV_ZERO = 0, /* used as tlv buf end marker */
+#ifdef NAN_STD_TLV /* rfu, don't use yet */
+ WL_NAN_XTLV_MASTER_IND = 1, /* == NAN_ATTR_MASTER_IND, */
+ WL_NAN_XTLV_CLUSTER = 2, /* == NAN_ATTR_CLUSTER, */
+ WL_NAN_XTLV_VENDOR = 221, /* == NAN_ATTR_VENDOR, */
+#endif
+ /* 0x02 ~ 0xFF: reserved. In case to use with the same data format as NAN attribute TLV */
+ /* 0x100 ~ : private TLV ID defined just for NAN command */
+ /* common types */
+ WL_NAN_XTLV_BUFFER = 0x101, /* generic type, function depends on cmd context */
+ WL_NAN_XTLV_MAC_ADDR = 0x102, /* used in various cmds */
+ WL_NAN_XTLV_REASON = 0x103,
+ WL_NAN_XTLV_ENABLE = 0x104,
+ /* explicit types, primarily for discovery engine iovars */
+ WL_NAN_XTLV_SVC_PARAMS = 0x120, /* Contains required params: wl_nan_disc_params_t */
+ WL_NAN_XTLV_MATCH_RX = 0x121, /* Matching filter to evaluate on receive */
+ WL_NAN_XTLV_MATCH_TX = 0x122, /* Matching filter to send */
+ WL_NAN_XTLV_SVC_INFO = 0x123, /* Service specific info */
+ WL_NAN_XTLV_SVC_NAME = 0x124, /* Optional UTF-8 service name, for debugging. */
+ WL_NAN_XTLV_INSTANCE_ID = 0x125, /* Identifies unique publish or subscribe instance */
+ WL_NAN_XTLV_PRIORITY = 0x126, /* used in transmit cmd context */
+ WL_NAN_XTLV_REQUESTOR_ID = 0x127, /* Requestor instance ID */
+ WL_NAN_XTLV_VNDR = 0x128, /* Vendor specific attribute */
+ /* explicit types, primarily for NAN MAC iovars */
+ WL_NAN_XTLV_DW_LEN = 0x140, /* discovery win length */
+ WL_NAN_XTLV_BCN_INTERVAL = 0x141, /* beacon interval, both sync and descovery bcns? */
+ WL_NAN_XTLV_CLUSTER_ID = 0x142,
+ WL_NAN_XTLV_IF_ADDR = 0x143,
+ WL_NAN_XTLV_MC_ADDR = 0x144,
+ WL_NAN_XTLV_ROLE = 0x145,
+ WL_NAN_XTLV_START = 0x146,
+
+ WL_NAN_XTLV_MASTER_PREF = 0x147,
+ WL_NAN_XTLV_DW_INTERVAL = 0x148,
+ WL_NAN_XTLV_PTBTT_OVERRIDE = 0x149,
+ /* nan status command xtlvs */
+ WL_NAN_XTLV_MAC_INITED = 0x14a,
+ WL_NAN_XTLV_MAC_ENABLED = 0x14b,
+ WL_NAN_XTLV_MAC_CHANSPEC = 0x14c,
+ WL_NAN_XTLV_MAC_AMR = 0x14d, /* anchormaster rank u8 amr[8] */
+ WL_NAN_XTLV_MAC_HOPCNT = 0x14e,
+ WL_NAN_XTLV_MAC_AMBTT = 0x14f,
+ WL_NAN_XTLV_MAC_TXRATE = 0x150,
+ WL_NAN_XTLV_MAC_STATUS = 0x151, /* xtlv payload is nan_status_t */
+ WL_NAN_XTLV_NAN_SCANPARAMS = 0x152, /* payload is nan_scan_params_t */
+ WL_NAN_XTLV_DEBUGPARAMS = 0x153, /* payload is nan_scan_params_t */
+ WL_NAN_XTLV_SUBSCR_ID = 0x154, /* subscriber id */
+ WL_NAN_XTLV_PUBLR_ID = 0x155, /* publisher id */
+ WL_NAN_XTLV_EVENT_MASK = 0x156,
+ WL_NAN_XTLV_MERGE = 0x157
+};
+
+/* Flag bits for Publish and Subscribe (wl_nan_disc_params_t flags) */
+#define WL_NAN_RANGE_LIMITED 0x0040
+/* Bits specific to Publish */
+/* Unsolicited transmissions */
+#define WL_NAN_PUB_UNSOLICIT 0x1000
+/* Solicited transmissions */
+#define WL_NAN_PUB_SOLICIT 0x2000
+#define WL_NAN_PUB_BOTH 0x3000
+/* Set for broadcast solicited transmission
+ * Do not set for unicast solicited transmission
+ */
+#define WL_NAN_PUB_BCAST 0x4000
+/* Generate event on each solicited transmission */
+#define WL_NAN_PUB_EVENT 0x8000
+/* Used for one-time solicited Publish functions to indicate transmision occurred */
+#define WL_NAN_PUB_SOLICIT_PENDING 0x10000
+/* Follow-up frames */
+#define WL_NAN_FOLLOWUP 0x20000
+/* Bits specific to Subscribe */
+/* Active subscribe mode (Leave unset for passive) */
+#define WL_NAN_SUB_ACTIVE 0x1000
+
+/* Special values for time to live (ttl) parameter */
+#define WL_NAN_TTL_UNTIL_CANCEL 0xFFFFFFFF
+/* Publish - runs until first transmission
+ * Subscribe - runs until first DiscoveryResult event
+ */
+#define WL_NAN_TTL_FIRST 0
+
+/* The service hash (service id) is exactly this many bytes. */
+#define WL_NAN_SVC_HASH_LEN 6
+
+/* Instance ID type (unique identifier) */
+typedef uint8 wl_nan_instance_id_t;
+
+/* Mandatory parameters for publish/subscribe iovars - NAN_TLV_SVC_PARAMS */
+typedef struct wl_nan_disc_params_s {
+ /* Periodicity of unsolicited/query transmissions, in DWs */
+ uint32 period;
+ /* Time to live in DWs */
+ uint32 ttl;
+ /* Flag bits */
+ uint32 flags;
+ /* Publish or subscribe service id, i.e. hash of the service name */
+ uint8 svc_hash[WL_NAN_SVC_HASH_LEN];
+ /* Publish or subscribe id */
+ wl_nan_instance_id_t instance_id;
+} wl_nan_disc_params_t;
+
+/*
+* desovery interface event structures *
+*/
+
+/* 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 */
+} 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 */
+} 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;
+
+/* ********************* end of NAN section ******************************** */
+
+#define RSSI_THRESHOLD_SIZE 16
+#define MAX_IMP_RESP_SIZE 256
+
+typedef BWL_PRE_PACKED_STRUCT 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) */
+} BWL_POST_PACKED_STRUCT wl_proxd_rssi_bias_t;
+
+typedef BWL_PRE_PACKED_STRUCT 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 */
+} BWL_POST_PACKED_STRUCT wl_proxd_rssi_bias_avg_t;
+
+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 */
+#ifdef RSSI_REFINE
+ wl_proxd_rssi_bias_t rssi_bias; /* RSSI refinement info */
+#endif
+ int16 nfft; /* number of samples stored in H */
+
+} BWL_POST_PACKED_STRUCT wl_proxd_collect_info_t;
+
+#define k_tof_collect_H_pad 1
+#define k_tof_collect_H_size (256+16+k_tof_collect_H_pad)
+#define k_tof_collect_Hraw_size (2*k_tof_collect_H_size)
+typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_data {
+ wl_proxd_collect_info_t info;
+ uint32 H[k_tof_collect_H_size]; /* raw data read from phy used to adjust timestamps */
+
+} BWL_POST_PACKED_STRUCT wl_proxd_collect_data_t;
+
+typedef BWL_PRE_PACKED_STRUCT 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 */
+} BWL_POST_PACKED_STRUCT 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),
+ /* add per-BSS properties above */
+ WL_WSEC_INFO_MAX = 0xffff
+} wl_wsec_info_type_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;
+
+/* no default structure packing */
+#include <packed_section_end.h>
+
+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 */
+ 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 */
+ 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 {
+ bool wowl_enabled;
+ bool net_detect_enabled;
+ bool 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[0];
+} net_detect_profile_list_t;
+
+typedef struct net_detect_config {
+ bool nd_enabled;
+ uint32 scan_interval;
+ uint32 wait_period;
+ bool wake_if_connected;
+ bool wake_if_disconnected;
+ 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 */
+
+typedef struct bcnreq {
+ uint8 bcn_mode;
+ int dur;
+ int channel;
+ struct ether_addr da;
+ uint16 random_int;
+ wlc_ssid_t ssid;
+ uint16 reps;
+} bcnreq_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;
+ uint16 reps;
+} statreq_t;
+
+typedef struct wlc_l2keepalive_ol_params {
+ uint8 flags;
+ uint8 prio;
+ uint16 period_ms;
+} wlc_l2keepalive_ol_params_t;
+
+typedef struct wlc_dwds_config {
+ uint32 enable;
+ uint32 mode; /* STA/AP interface */
+ struct ether_addr ea;
+} wlc_dwds_config_t;
+
+typedef struct wl_el_set_params_s {
+ uint8 set; /* Set number */
+ 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
+} 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;
+} wlc_stamon_sta_config_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 {
+ bool is_static;
+ uint16 sta_count;
+ uint8 chan_util;
+ uint16 aac;
+} wl_bssload_static_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;
+
+#endif /* _wlioctl_h_ */
diff --git a/drivers/net/wireless/bcmdhd/linux_osl.c b/drivers/net/wireless/bcmdhd/linux_osl.c
new file mode 100644
index 000000000000..5b0008d77a46
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/linux_osl.c
@@ -0,0 +1,1529 @@
+/*
+ * Linux OS Independent 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: linux_osl.c 658506 2016-09-08 06:44:19Z $
+ */
+
+#define LINUX_PORT
+
+#include <typedefs.h>
+#include <bcmendian.h>
+#include <linuxver.h>
+#include <bcmdefs.h>
+
+#ifdef __ARM_ARCH_7A__
+#include <asm/cacheflush.h>
+#endif /* __ARM_ARCH_7A__ */
+
+#include <osl.h>
+#include <bcmutils.h>
+#include <linux/delay.h>
+#include <pcicfg.h>
+
+
+
+#include <linux/fs.h>
+
+#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
+
+#ifdef CONFIG_DHD_USE_STATIC_BUF
+#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 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;
+
+#define STATIC_PKT_MAX_NUM 8
+#if 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 /* ENHANCED_STATIC_BUF */
+
+typedef struct bcm_static_pkt {
+ struct sk_buff *skb_4k[STATIC_PKT_MAX_NUM];
+ struct sk_buff *skb_8k[STATIC_PKT_MAX_NUM];
+#ifdef ENHANCED_STATIC_BUF
+ struct sk_buff *skb_16k;
+#endif
+ struct semaphore osl_pkt_sem;
+ unsigned char pkt_use[STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_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;
+ 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;
+#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 */
+};
+
+#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)
+
+/* PCMCIA attribute space access macros */
+
+/* Global ASSERT type flag */
+uint32 g_assert_type = FALSE;
+
+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 */
+
+/* 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 != -52
+#error "You need to add a OS error translation in the linuxbcmerrormap \
+ for new error code defined in bcmutils.h"
+#endif
+};
+
+/* 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];
+}
+#ifdef SHARED_OSL_CMN
+osl_t *
+osl_attach(void *pdev, uint bustype, bool pkttag, void **osl_cmn)
+{
+#else
+osl_t *
+osl_attach(void *pdev, uint bustype, bool pkttag)
+{
+ void **osl_cmn = NULL;
+#endif /* SHARED_OSL_CMN */
+ osl_t *osh;
+ gfp_t flags;
+
+ 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);
+
+ /* 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;
+
+ 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)
+{
+#if defined(CONFIG_DHD_USE_STATIC_BUF)
+ if (!bcm_static_buf && adapter) {
+ if (!(bcm_static_buf = (bcm_static_buf_t *)wifi_platform_prealloc(adapter,
+ 3, STATIC_BUF_SIZE + STATIC_BUF_TOTAL_LEN))) {
+ printk("can not alloc static buf!\n");
+ bcm_static_skb = NULL;
+ ASSERT(osh->magic == OS_HANDLE_MAGIC);
+ kfree(osh);
+ 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 (!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, 4, 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);
+ kfree(osh);
+ return -ENOMEM;
+ }
+
+ bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) *
+ (STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM));
+ for (i = 0; i < STATIC_PKT_MAX_NUM * 2 + STATIC_PKT_4PAGE_NUM; i++)
+ bcm_static_skb->pkt_use[i] = 0;
+
+ sema_init(&bcm_static_skb->osl_pkt_sem, 1);
+ }
+#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;
+
+ 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;
+ }
+ if (bcm_static_skb) {
+ bcm_static_skb = 0;
+ }
+#endif
+ return 0;
+}
+
+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;
+#if defined(CONFIG_SPARSEMEM) && defined(CONFIG_ZONE_DMA)
+ flags |= GFP_ATOMIC;
+#endif
+ 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;
+
+ 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->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;
+ }
+ if (bcm_static_skb) {
+ bcm_static_skb = 0;
+ }
+#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 */
+/* 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
+ */
+#ifdef BCMDBG_CTRACE
+void * BCMFASTPATH
+osl_pkt_frmnative(osl_t *osh, void *pkt, int line, char *file)
+#else
+void * BCMFASTPATH
+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 */
+#ifdef BCMDBG_CTRACE
+void * BCMFASTPATH
+osl_pktget(osl_t *osh, uint len, int line, char *file)
+#else
+void * BCMFASTPATH
+osl_pktget(osl_t *osh, uint len)
+#endif /* BCMDBG_CTRACE */
+{
+ struct sk_buff *skb;
+
+#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);
+ }
+
+ 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);
+
+ /* 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
+osl_pktfree(osl_t *osh, void *p, bool send)
+{
+ 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);
+
+ /* 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 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
+ {
+ if (skb->destructor)
+ /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
+ * destructor exists
+ */
+ dev_kfree_skb_any(skb);
+ else
+ /* can free immediately (even in_irq()) if destructor
+ * does not exist
+ */
+ dev_kfree_skb(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;
+
+ if (len > DHD_SKB_MAX_BUFSIZE) {
+ printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len);
+ return osl_pktget(osh, len);
+ }
+
+ down(&bcm_static_skb->osl_pkt_sem);
+
+ if (len <= DHD_SKB_1PAGE_BUFSIZE) {
+ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
+ if (bcm_static_skb->pkt_use[i] == 0)
+ break;
+ }
+
+ if (i != STATIC_PKT_MAX_NUM) {
+ bcm_static_skb->pkt_use[i] = 1;
+
+ skb = bcm_static_skb->skb_4k[i];
+ skb_set_tail_pointer(skb, len);
+ skb->len = len;
+
+ up(&bcm_static_skb->osl_pkt_sem);
+ return skb;
+ }
+ }
+
+ if (len <= DHD_SKB_2PAGE_BUFSIZE) {
+ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
+ if (bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM]
+ == 0)
+ break;
+ }
+
+ if (i != STATIC_PKT_MAX_NUM) {
+ bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 1;
+ skb = bcm_static_skb->skb_8k[i];
+ skb_set_tail_pointer(skb, len);
+ skb->len = len;
+
+ up(&bcm_static_skb->osl_pkt_sem);
+ return skb;
+ }
+ }
+
+#if defined(ENHANCED_STATIC_BUF)
+ if (bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] == 0) {
+ bcm_static_skb->pkt_use[STATIC_PKT_MAX_NUM * 2] = 1;
+
+ skb = bcm_static_skb->skb_16k;
+ skb_set_tail_pointer(skb, len);
+ skb->len = len;
+
+ up(&bcm_static_skb->osl_pkt_sem);
+ return skb;
+ }
+#endif
+
+ up(&bcm_static_skb->osl_pkt_sem);
+ printk("%s: all static pkt in use!\n", __FUNCTION__);
+ return osl_pktget(osh, len);
+}
+
+void
+osl_pktfree_static(osl_t *osh, void *p, bool send)
+{
+ int i;
+ if (!bcm_static_skb) {
+ osl_pktfree(osh, p, send);
+ return;
+ }
+
+ down(&bcm_static_skb->osl_pkt_sem);
+ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
+ if (p == bcm_static_skb->skb_4k[i]) {
+ bcm_static_skb->pkt_use[i] = 0;
+ up(&bcm_static_skb->osl_pkt_sem);
+ return;
+ }
+ }
+
+ for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
+ if (p == bcm_static_skb->skb_8k[i]) {
+ bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 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 * 2] = 0;
+ up(&bcm_static_skb->osl_pkt_sem);
+ return;
+ }
+#endif
+ up(&bcm_static_skb->osl_pkt_sem);
+ 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);
+
+ return ((struct pci_dev *)osh->pdev)->bus->number;
+}
+
+/* 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 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);
+}
+
+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;
+
+#ifdef __ARM_ARCH_7A__
+ va = kmalloc(size, GFP_ATOMIC | __GFP_ZERO);
+ if (va)
+ *pap = (ulong)__virt_to_phys((ulong)va);
+#else
+ {
+ dma_addr_t pap_lin;
+ va = pci_alloc_consistent(osh->pdev, size, &pap_lin);
+ *pap = (dmaaddr_t)pap_lin;
+ }
+#endif
+ return va;
+}
+
+void
+osl_dma_free_consistent(osl_t *osh, void *va, uint size, dmaaddr_t pa)
+{
+ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
+
+#ifdef __ARM_ARCH_7A__
+ kfree(va);
+#else
+ pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa);
+#endif
+}
+
+dmaaddr_t BCMFASTPATH
+osl_dma_map(osl_t *osh, void *va, uint size, int direction, void *p, hnddma_seg_map_t *dmah)
+{
+ int dir;
+
+ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
+ dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
+
+#if defined(__ARM_ARCH_7A__) && defined(BCMDMASGLISTOSL)
+ if (dmah != NULL) {
+ int32 nsegs, i, totsegs = 0, totlen = 0;
+ struct scatterlist *sg, _sg[MAX_DMA_SEGS * 2];
+ struct sk_buff *skb;
+ for (skb = (struct sk_buff *)p; skb != NULL; skb = PKTNEXT(osh, skb)) {
+ sg = &_sg[totsegs];
+ if (skb_is_nonlinear(skb)) {
+ nsegs = skb_to_sgvec(skb, sg, 0, PKTLEN(osh, skb));
+ ASSERT((nsegs > 0) && (totsegs + nsegs <= MAX_DMA_SEGS));
+ pci_map_sg(osh->pdev, sg, nsegs, dir);
+ } else {
+ nsegs = 1;
+ ASSERT(totsegs + nsegs <= MAX_DMA_SEGS);
+ sg->page_link = 0;
+ sg_set_buf(sg, PKTDATA(osh, skb), PKTLEN(osh, skb));
+ pci_map_single(osh->pdev, PKTDATA(osh, skb), PKTLEN(osh, skb), dir);
+ }
+ totsegs += nsegs;
+ totlen += PKTLEN(osh, skb);
+ }
+ dmah->nsegs = totsegs;
+ dmah->origsize = totlen;
+ for (i = 0, sg = _sg; i < totsegs; i++, sg++) {
+ dmah->segs[i].addr = sg_phys(sg);
+ dmah->segs[i].length = sg->length;
+ }
+ return dmah->segs[0].addr;
+ }
+#endif /* __ARM_ARCH_7A__ && BCMDMASGLISTOSL */
+
+ return (pci_map_single(osh->pdev, va, size, dir));
+}
+
+void BCMFASTPATH
+osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction)
+{
+ int dir;
+
+ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
+ dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
+ pci_unmap_single(osh->pdev, (uint32)pa, size, dir);
+}
+
+
+#if defined(__ARM_ARCH_7A__)
+
+inline void BCMFASTPATH
+osl_cache_flush(void *va, uint size)
+{
+ dma_sync_single_for_device(OSH_NULL, virt_to_dma(OSH_NULL, va), size, DMA_TX);
+}
+
+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_RX);
+}
+
+inline void osl_prefetch(const void *ptr)
+{
+ __asm__ __volatile__("pld\t%0" :: "o"(*(char *)ptr) : "cc");
+}
+#endif
+
+#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);
+ printk("%s", tempbuf);
+#endif /* BCMASSERT_LOG */
+
+
+}
+#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);
+}
+
+
+
+/* Clone a packet.
+ * The pkttag contents are NOT cloned.
+ */
+#ifdef BCMDBG_CTRACE
+void *
+osl_pktdup(osl_t *osh, void *skb, int line, char *file)
+#else
+void *
+osl_pktdup(osl_t *osh, void *skb)
+#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 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;
+}
+
+/* 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;
+
+ rdlen = kernel_read(fp, fp->f_pos, buf, len);
+ if (rdlen > 0)
+ fp->f_pos += rdlen;
+
+ 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 */
diff --git a/drivers/net/wireless/bcmdhd/sbutils.c b/drivers/net/wireless/bcmdhd/sbutils.c
new file mode 100644
index 000000000000..bd99a9fd4ff2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/sbutils.c
@@ -0,0 +1,1063 @@
+/*
+ * Misc utility routines for accessing chip-specific features
+ * of the SiliconBackplane-based Broadcom chips.
+ *
+ * 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: sbutils.c 431423 2013-10-23 16:07:35Z $
+ */
+
+#include <bcm_cfg.h>
+#include <typedefs.h>
+#include <bcmdefs.h>
+#include <osl.h>
+#include <bcmutils.h>
+#include <siutils.h>
+#include <bcmdevs.h>
+#include <hndsoc.h>
+#include <sbchipc.h>
+#include <pcicfg.h>
+#include <sbpcmcia.h>
+
+#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, void *regs, uint bus, uint32 sbba,
+ uint ncores);
+static uint32 _sb_coresba(si_info_t *sii);
+static 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*) ((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)
+{
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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)
+{
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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;
+ }
+
+ case SPI_BUS:
+ case SDIO_BUS:
+ sbaddr = (uint32)(uintptr)sii->curmap;
+ break;
+
+
+ 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;
+ 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 = (uint32 *)((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 = (uint32 *)((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 = (uint32 *)((char *)sii->curmap +
+ PCI_16KB0_PCIREGS_OFFSET + regoff);
+ else
+ r = (uint32 *)((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 = (uint32*) ((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 {
+ if ((CHIPID(sii->pub.chip) == BCM5354_CHIP_ID) &&
+ (coreidx == SI_CC_IDX) &&
+ (regoff == OFFSETOF(chipcregs_t, watchdog))) {
+ w = val;
+ } 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.
+ */
+uint32 *
+sb_corereg_addr(si_t *sih, uint coreidx, uint regoff)
+{
+ 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 = (uint32 *)((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 = (uint32 *)((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 = (uint32 *)((char *)sii->curmap +
+ PCI_16KB0_PCIREGS_OFFSET + regoff);
+ else
+ r = (uint32 *)((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, 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 == BCM4306_CHIP_ID) /* < 4306c0 */
+ numcores = 6;
+ else 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, void *regs, uint devid)
+{
+ uint32 origsba;
+ sbconfig_t *sb;
+ si_info_t *sii = SI_INFO(sih);
+
+ 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
+ */
+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 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];
+ 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;
+ }
+ 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;
+
+
+ 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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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:
+ case SDIO_BUS:
+ 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);
+}
diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd/siutils.c
new file mode 100644
index 000000000000..d6ff5763918a
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/siutils.c
@@ -0,0 +1,2877 @@
+/*
+ * Misc utility routines for accessing chip-specific features
+ * of the SiliconBackplane-based Broadcom chips.
+ *
+ * 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: siutils.c 550969 2015-04-22 00:27:43Z $
+ */
+
+#include <bcm_cfg.h>
+#include <typedefs.h>
+#include <bcmdefs.h>
+#include <osl.h>
+#include <bcmutils.h>
+#include <siutils.h>
+#include <bcmdevs.h>
+#include <hndsoc.h>
+#include <sbchipc.h>
+#include <pcicfg.h>
+#include <sbpcmcia.h>
+#include <sbsocram.h>
+#include <bcmsdh.h>
+#include <sdio.h>
+#include <sbsdio.h>
+#include <sbhnddma.h>
+#include <sbsdpcmdev.h>
+#include <bcmsdpcm.h>
+#include <hndpmu.h>
+
+#ifdef BCM_SDRBL
+#include <hndcpu.h>
+#endif /* BCM_SDRBL */
+
+#include "siutils_priv.h"
+
+/* local prototypes */
+static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, 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, void *regs);
+
+
+
+/* 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() */
+
+int do_4360_pcie2_war = 0;
+
+/* global kernel resource */
+static si_info_t ksii;
+static si_cores_info_t ksii_cores_info;
+
+/**
+ * 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, 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",
+ ksii.pub.ccrev, wd_msticks));
+ }
+
+ return &ksii.pub;
+}
+
+
+static bool
+si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh)
+{
+ /* need to set memseg flag for CF card first before any sb registers access */
+ if (BUSTYPE(bustype) == PCMCIA_BUS)
+ sii->memseg = TRUE;
+
+
+ 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);
+ }
+
+
+ return TRUE;
+}
+
+static bool
+si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin,
+ uint *origidx, 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;
+
+ 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 (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 (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) {
+ 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",
+ 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 ((CHIPID(sii->pub.chip) == BCM43602_CHIP_ID) ||
+ ((CHIPID(sii->pub.chip) == BCM4345_CHIP_ID) &&
+ 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;
+ }
+ 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;
+ }
+
+ /* 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)
+ pci = FALSE;
+#endif
+ 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;
+ }
+
+ SI_VMSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype,
+ sii->pub.buscorerev));
+
+ if (BUSTYPE(sii->pub.bustype) == SI_BUS && (CHIPID(sii->pub.chip) == BCM4712_CHIP_ID) &&
+ (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (CHIPREV(sii->pub.chiprev) <= 3))
+ OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL);
+
+
+ /* 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);
+ }
+
+ /* return to the original core */
+ si_setcoreidx(&sii->pub, *origidx);
+
+ return TRUE;
+}
+
+
+
+
+/**
+ * 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, 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->curmap = regs;
+ sii->sdh = sdh;
+ sii->osh = osh;
+
+
+ /* 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;
+ } else if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) {
+ cc = (chipcregs_t *)sii->curmap;
+ } else {
+ cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE);
+ }
+
+ sih->bustype = bustype;
+
+ /* 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 ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 0) &&
+ (sih->chippkg != BCM4329_289PIN_PKG_ID)) {
+ sih->chippkg = BCM4329_182PIN_PKG_ID;
+ }
+ 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 */
+ 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;
+ }
+
+#if !defined(_CFEZ_) || defined(CFG_WL)
+ if (CHIPID(sih->chip) == BCM4322_CHIP_ID && (((sih->chipst & CST4322_SPROM_OTP_SEL_MASK)
+ >> CST4322_SPROM_OTP_SEL_SHIFT) == (CST4322_OTP_PRESENT |
+ CST4322_SPROM_PRESENT))) {
+ SI_ERROR(("%s: Invalid setting: both SPROM and OTP strapped.\n", __FUNCTION__));
+ return NULL;
+ }
+
+ /* assume current core is CC */
+ if ((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 (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));
+
+
+ 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(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;
+}
+
+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;
+}
+
+/** 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)
+{
+ 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) {
+ found++;
+ }
+
+ return (found == 0? 0: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 */
+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
+ */
+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;
+ }
+}
+
+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 */
+void *
+si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val)
+{
+ void *cc;
+ si_info_t *sii = SI_INFO(sih);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+
+ 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 (void *)CCREGS_FAST(sii);
+ else if (coreid == sih->buscoretype)
+ return (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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+
+ if (SI_FAST(sii) && ((coreid == CC_CORE_ID) || (coreid == 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;
+ }
+}
+
+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;
+}
+
+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;
+ }
+}
+
+/*
+ * 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.
+ */
+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;
+}
+
+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 BCM43602_CHIP_ID:
+ 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_ID:
+ 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 BCM4350_CHIP_ID:
+ case BCM4354_CHIP_ID:
+ case BCM4356_CHIP_ID:
+ case BCM43556_CHIP_ID:
+ case BCM43558_CHIP_ID:
+ case BCM43566_CHIP_ID:
+ case BCM43568_CHIP_ID:
+ case BCM43569_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;
+
+ if (PMUCTL_ENAB(sih)) {
+
+#if !defined(_CFEZ_) || defined(CFG_WL)
+ if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) &&
+ (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) {
+ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), ~0, 0x2);
+ si_setcore(sih, USB20D_CORE_ID, 0);
+ si_core_disable(sih, 1);
+ si_setcore(sih, CC_CORE_ID, 0);
+ }
+#endif
+
+ nb = (sih->ccrev < 26) ? 16 : ((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;
+
+ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, 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 (sii->pub.ccrev < 6) {
+ if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) &&
+ (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32)) &
+ PCI_CFG_GPIO_SCS))
+ return (SCC_SS_PCI);
+ else
+ return (SCC_SS_XTAL);
+ } else if (sii->pub.ccrev < 10) {
+ cc = (chipcregs_t *)si_setcoreidx(&sii->pub, sii->curidx);
+ 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 (sii->pub.ccrev < 6) {
+ if (slowclk == SCC_SS_PCI)
+ return (max_freq ? (PCIMAXFREQ / 64) : (PCIMINFREQ / 64));
+ else
+ return (max_freq ? (XTALMAXFREQ / 32) : (XTALMINFREQ / 32));
+ } else if (sii->pub.ccrev < 10) {
+ div = 4 *
+ (((R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1);
+ if (slowclk == SCC_SS_LPO)
+ return (max_freq ? LPOMAXFREQ : LPOMINFREQ);
+ else if (slowclk == SCC_SS_XTAL)
+ return (max_freq ? (XTALMAXFREQ / div) : (XTALMINFREQ / div));
+ else if (slowclk == SCC_SS_PCI)
+ return (max_freq ? (PCIMAXFREQ / div) : (PCIMINFREQ / div));
+ else
+ ASSERT(0);
+ } else {
+ /* Chipc rev 10 is InstaClock */
+ div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT;
+ div = 4 * (div + 1);
+ return (max_freq ? XTALMAXFREQ : (XTALMINFREQ / div));
+ }
+ return (0);
+}
+
+static void
+si_clkctl_setdelay(si_info_t *sii, void *chipcregs)
+{
+ chipcregs_t *cc = (chipcregs_t *)chipcregs;
+ uint slowmaxfreq, pll_delay, slowclk;
+ uint pll_on_delay, fref_sel_delay;
+
+ pll_delay = PLL_DELAY;
+
+ /* If the slow clock is not sourced by the xtal then add the xtal_on_delay
+ * since the xtal will also be powered down by dynamic clk control logic.
+ */
+
+ slowclk = si_slowclk_src(sii);
+ if (slowclk != SCC_SS_XTAL)
+ pll_delay += XTAL_ON_DELAY;
+
+ /* Starting with 4318 it is ILP that is used for the delays */
+ slowmaxfreq = si_slowclk_freq(sii, (sii->pub.ccrev >= 10) ? FALSE : TRUE, cc);
+
+ pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
+ fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000;
+
+ W_REG(sii->osh, &cc->pll_on_delay, pll_on_delay);
+ W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay);
+}
+
+/** initialize power control delay registers */
+void
+si_clkctl_init(si_t *sih)
+{
+ si_info_t *sii;
+ uint origidx = 0;
+ chipcregs_t *cc;
+ bool fast;
+
+ if (!CCCTL_ENAB(sih))
+ return;
+
+ sii = SI_INFO(sih);
+ fast = SI_FAST(sii);
+ if (!fast) {
+ origidx = sii->curidx;
+ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL)
+ return;
+ } else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL)
+ return;
+ ASSERT(cc != NULL);
+
+ /* set all Instaclk chip ILP to 1 MHz */
+ if (sih->ccrev >= 10)
+ SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK,
+ (ILP_DIV_1MHZ << SYCC_CD_SHIFT));
+
+ si_clkctl_setdelay(sii, (void *)(uintptr)cc);
+
+ OSL_DELAY(20000);
+
+ if (!fast)
+ si_setcoreidx(sih, origidx);
+}
+
+
+/** change logical "focus" to the gpio core for optimized access */
+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));
+}
+
+/* assign the gpio to an led */
+uint32
+si_gpioled(si_t *sih, uint32 mask, uint32 val)
+{
+ if (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 (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 (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 (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));
+}
+
+void *
+si_gpio_handler_register(si_t *sih, uint32 event,
+ bool level, gpio_handler_t cb, void *arg)
+{
+ si_info_t *sii = SI_INFO(sih);
+ gpioh_item_t *gi;
+
+ ASSERT(event);
+ ASSERT(cb != NULL);
+
+ if (sih->ccrev < 11)
+ return NULL;
+
+ if ((gi = MALLOC(sii->osh, sizeof(gpioh_item_t))) == NULL)
+ return NULL;
+
+ bzero(gi, sizeof(gpioh_item_t));
+ gi->event = event;
+ gi->handler = cb;
+ gi->arg = arg;
+ gi->level = level;
+
+ gi->next = sii->gpioh_head;
+ sii->gpioh_head = gi;
+
+ return (void *)(gi);
+}
+
+void
+si_gpio_handler_unregister(si_t *sih, void *gpioh)
+{
+ si_info_t *sii = SI_INFO(sih);
+ gpioh_item_t *p, *n;
+
+ if (sih->ccrev < 11)
+ return;
+
+ ASSERT(sii->gpioh_head != NULL);
+ if ((void*)sii->gpioh_head == gpioh) {
+ sii->gpioh_head = sii->gpioh_head->next;
+ MFREE(sii->osh, gpioh, sizeof(gpioh_item_t));
+ return;
+ } else {
+ p = sii->gpioh_head;
+ n = p->next;
+ while (n) {
+ if ((void*)n == gpioh) {
+ p->next = n->next;
+ MFREE(sii->osh, gpioh, sizeof(gpioh_item_t));
+ return;
+ }
+ p = n;
+ n = n->next;
+ }
+ }
+
+ ASSERT(0); /* Not found in list */
+}
+
+void
+si_gpio_handler_process(si_t *sih)
+{
+ si_info_t *sii = SI_INFO(sih);
+ gpioh_item_t *h;
+ uint32 level = si_gpioin(sih);
+ uint32 levelp = si_gpiointpolarity(sih, 0, 0, 0);
+ uint32 edge = si_gpioevent(sih, GPIO_REGEVT, 0, 0);
+ uint32 edgep = si_gpioevent(sih, GPIO_REGEVT_INTPOL, 0, 0);
+
+ for (h = sii->gpioh_head; h != NULL; h = h->next) {
+ if (h->handler) {
+ uint32 status = (h->level ? level : edge) & h->event;
+ uint32 polarity = (h->level ? levelp : edgep) & h->event;
+
+ /* polarity bitval is opposite of status bitval */
+ if (status ^ polarity)
+ h->handler(status, h->arg);
+ }
+ }
+
+ si_gpioevent(sih, GPIO_REGEVT, edge, edge); /* clear edge-trigger status */
+}
+
+uint32
+si_gpio_int_enable(si_t *sih, bool enable)
+{
+ uint offs;
+
+ if (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 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, &regs->bankidx, bankidx);
+ bankinfo = R_REG(sii->osh, &regs->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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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, &regs->bankidx, bankidx);
+ W_REG(sii->osh, &regs->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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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, &regs->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, &regs->bankidx, bankidx);
+ bankinfo = R_REG(sii->osh, &regs->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, &regs->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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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, &regs->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, &regs->bankidx, bankidx);
+ bankinfo = R_REG(sii->osh, &regs->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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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, &regs->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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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, &regs->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, &regs->bankidx, bankidx);
+ bankinfo = R_REG(sii->osh, &regs->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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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, &regs->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 = (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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ uint origidx;
+ uint intr_val = 0;
+ uint8 *regs;
+ bool wasup;
+ uint32 corecap;
+ uint memsize = 0;
+ uint32 nab = 0;
+ uint32 nbb = 0;
+ uint32 totb = 0;
+ uint32 bxinfo = 0;
+ uint32 idx = 0;
+ uint32 *arm_cap_reg;
+ uint32 *arm_bidx;
+ 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 = (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 = (uint32 *)(regs + SI_CR4_BANKIDX);
+ arm_binfo = (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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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) {
+ 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, &regs->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, &regs->bankidx, i);
+ if (R_REG(sii->osh, &regs->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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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 (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_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)
+{
+}
+
+/** 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);
+}
+
+/** check if the device is removed */
+bool
+si_deviceremoved(si_t *sih)
+{
+ uint32 w;
+
+ 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_sprom_available(si_t *sih)
+{
+ if (sih->ccrev >= 31) {
+ si_info_t *sii;
+ uint origidx;
+ chipcregs_t *cc;
+ uint32 sromctrl;
+
+ if ((sih->cccaps & CC_CAP_SROM) == 0)
+ return FALSE;
+
+ sii = SI_INFO(sih);
+ origidx = sii->curidx;
+ cc = si_setcoreidx(sih, SI_CC_IDX);
+ ASSERT(cc);
+ sromctrl = R_REG(sii->osh, &cc->sromcontrol);
+ si_setcoreidx(sih, origidx);
+ return (sromctrl & SRC_PRESENT);
+ }
+
+ switch (CHIPID(sih->chip)) {
+ case BCM4312_CHIP_ID:
+ return ((sih->chipst & CST4312_SPROM_OTP_SEL_MASK) != CST4312_OTP_SEL);
+ case BCM4325_CHIP_ID:
+ return (sih->chipst & CST4325_SPROM_SEL) != 0;
+ case BCM4322_CHIP_ID: case BCM43221_CHIP_ID: case BCM43231_CHIP_ID:
+ case BCM43222_CHIP_ID: case BCM43111_CHIP_ID: case BCM43112_CHIP_ID:
+ case BCM4342_CHIP_ID: {
+ uint32 spromotp;
+ spromotp = (sih->chipst & CST4322_SPROM_OTP_SEL_MASK) >>
+ CST4322_SPROM_OTP_SEL_SHIFT;
+ return (spromotp & CST4322_SPROM_PRESENT) != 0;
+ }
+ case BCM4329_CHIP_ID:
+ return (sih->chipst & CST4329_SPROM_SEL) != 0;
+ case BCM4315_CHIP_ID:
+ return (sih->chipst & CST4315_SPROM_SEL) != 0;
+ case BCM4319_CHIP_ID:
+ return (sih->chipst & CST4319_SPROM_SEL) != 0;
+ case BCM4336_CHIP_ID:
+ case BCM43362_CHIP_ID:
+ return (sih->chipst & CST4336_SPROM_PRESENT) != 0;
+ case BCM4330_CHIP_ID:
+ return (sih->chipst & CST4330_SPROM_PRESENT) != 0;
+ case BCM4313_CHIP_ID:
+ return (sih->chipst & CST4313_SPROM_PRESENT) != 0;
+ case 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_ID:
+ return ((sih->chipst & CST4335_SPROM_MASK) &&
+ !(sih->chipst & CST4335_SFLASH_MASK));
+ case BCM4350_CHIP_ID:
+ case BCM4354_CHIP_ID:
+ case BCM4356_CHIP_ID:
+ case BCM43556_CHIP_ID:
+ case BCM43558_CHIP_ID:
+ case BCM43566_CHIP_ID:
+ case BCM43568_CHIP_ID:
+ case BCM43569_CHIP_ID:
+ return (sih->chipst & CST4350_SPROM_PRESENT) != 0;
+ case BCM43602_CHIP_ID:
+ 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;
+ 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);
+
+ cc = si_setcoreidx(sih, SI_CC_IDX);
+ ASSERT((uintptr)cc);
+
+ /* get chipcommon rev */
+ if (si_corerev(sih) < 32)
+ return BCME_UNSUPPORTED;
+
+ W_REG(osh, &cc->sromcontrol, value);
+
+ /* return to the original core */
+ si_setcoreidx(sih, origidx);
+ return BCME_OK;
+
+}
+
+uint
+si_core_wrapperreg(si_t *sih, uint32 coreidx, uint32 offset, uint32 mask, uint32 val)
+{
+ uint origidx;
+ uint ret_val;
+
+ origidx = si_coreidx(sih);
+
+ si_setcoreidx(sih, coreidx);
+
+ ret_val = si_wrapperreg(sih, offset, mask, val);
+
+ /* return to the original core */
+ si_setcoreidx(sih, origidx);
+ return ret_val;
+}
+
+
+/* cleanup the hndrte 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;
+ if (CHIPID(sih->chip) != BCM4328_CHIP_ID)
+ mask <<= 14;
+ /* clear mask bits */
+ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, res_req_timer), mask, 0);
+ /* readback to ensure write completes */
+ return si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, 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)
+{
+ si_info_t *sii = SI_INFO(sih);
+ chipcregs_t *cc;
+ uint32 origidx, i;
+
+ origidx = si_coreidx(sih);
+ cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
+ /* issue a watchdog reset */
+ W_REG(sii->osh, &cc->pmuwatchdog, 2);
+ /* do busy wait for 20ms */
+ for (i = 0; i < 2000; i++) {
+ OSL_DELAY(10);
+ }
+ si_setcoreidx(sih, origidx);
+}
+#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 */
+}
+
+void
+si_pcie_ltr_war(si_t *sih)
+{
+}
diff --git a/drivers/net/wireless/bcmdhd/siutils_priv.h b/drivers/net/wireless/bcmdhd/siutils_priv.h
new file mode 100644
index 000000000000..0bfb9d98b8f6
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/siutils_priv.h
@@ -0,0 +1,272 @@
+/*
+ * Include file private to the SOC Interconnect support files.
+ *
+ * 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: siutils_priv.h 431423 2013-10-23 16:07:35Z $
+ */
+
+#ifndef _siutils_priv_h_
+#define _siutils_priv_h_
+
+#define SI_ERROR(args)
+
+#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);
+
+typedef struct gpioh_item {
+ void *arg;
+ bool level;
+ gpio_handler_t handler;
+ uint32 event;
+ struct gpioh_item *next;
+} gpioh_item_t;
+
+
+#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;
+
+
+typedef struct si_cores_info {
+ 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 */
+
+ 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 */
+
+ gpioh_item_t *gpioh_head; /* GPIO event handlers list */
+
+ bool memseg; /* flag to toggle MEM_SEG register */
+
+ char *vars;
+ uint varsz;
+
+ 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 */
+
+ void *cores_info;
+ gci_gpio_item_t *gci_gpio_head; /* gci gpio interrupts head */
+} 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 PCIEREGS(si) (((char *)((si)->curmap) + PCI_16KB0_PCIREGS_OFFSET))
+#define CCREGS_FAST(si) (((char *)((si)->curmap) + PCI_16KB0_CCREGS_OFFSET))
+
+/*
+ * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts before/
+ * after core switching to avoid invalid register accesss inside ISR.
+ */
+#define INTR_OFF(si, intr_val) \
+ if ((si)->intrsoff_fn && (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 && (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 */
+
+/* Force fast clock for 4360b0 */
+#define PCI_FORCEHT(si) \
+ (((PCIE_GEN1(si)) && (si->pub.chip == BCM4311_CHIP_ID) && ((si->pub.chiprev <= 1))) || \
+ ((PCI(si) || PCIE_GEN1(si)) && (si->pub.chip == BCM4321_CHIP_ID)) || \
+ (PCIE_GEN1(si) && (si->pub.chip == BCM4716_CHIP_ID)) || \
+ (PCIE_GEN1(si) && (si->pub.chip == BCM4748_CHIP_ID)))
+
+/* GPIO Based LED powersave defines */
+#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */
+#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */
+
+#ifndef DEFAULT_GPIOTIMERVAL
+#define DEFAULT_GPIOTIMERVAL ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME)
+#endif
+
+/* Silicon Backplane externs */
+extern void sb_scan(si_t *sih, 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 uint32 *sb_corereg_addr(si_t *sih, uint coreidx, uint regoff);
+extern bool sb_iscoreup(si_t *sih);
+extern 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);
+
+
+/* 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 uint32 *ai_corereg_addr(si_t *sih, uint coreidx, uint regoff);
+extern bool ai_iscoreup(si_t *sih);
+extern void *ai_setcoreidx(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_core_disable(si_t *sih, uint32 bits);
+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);
+
+
+
+#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/drivers/net/wireless/bcmdhd/uamp_api.h b/drivers/net/wireless/bcmdhd/uamp_api.h
new file mode 100644
index 000000000000..9a4ec5fad19d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/uamp_api.h
@@ -0,0 +1,176 @@
+/*
+ * Name: uamp_api.h
+ *
+ * Description: Universal AMP API
+ *
+ * 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: uamp_api.h 294267 2011-11-04 23:41:52Z $
+ *
+ */
+#ifndef UAMP_API_H
+#define UAMP_API_H
+
+
+#include "typedefs.h"
+
+
+/*****************************************************************************
+** Constant and Type Definitions
+******************************************************************************
+*/
+
+#define BT_API
+
+/* Types. */
+typedef bool BOOLEAN;
+typedef uint8 UINT8;
+typedef uint16 UINT16;
+
+
+/* UAMP identifiers */
+#define UAMP_ID_1 1
+#define UAMP_ID_2 2
+typedef UINT8 tUAMP_ID;
+
+/* UAMP event ids (used by UAMP_CBACK) */
+#define UAMP_EVT_RX_READY 0 /* Data from AMP controller is ready to be read */
+#define UAMP_EVT_CTLR_REMOVED 1 /* Controller removed */
+#define UAMP_EVT_CTLR_READY 2 /* Controller added/ready */
+typedef UINT8 tUAMP_EVT;
+
+
+/* UAMP Channels */
+#define UAMP_CH_HCI_CMD 0 /* HCI Command channel */
+#define UAMP_CH_HCI_EVT 1 /* HCI Event channel */
+#define UAMP_CH_HCI_DATA 2 /* HCI ACL Data channel */
+typedef UINT8 tUAMP_CH;
+
+/* tUAMP_EVT_DATA: union for event-specific data, used by UAMP_CBACK */
+typedef union {
+ tUAMP_CH channel; /* UAMP_EVT_RX_READY: channel for which rx occured */
+} tUAMP_EVT_DATA;
+
+
+/*****************************************************************************
+**
+** Function: UAMP_CBACK
+**
+** Description: Callback for events. Register callback using UAMP_Init.
+**
+** Parameters amp_id: AMP device identifier that generated the event
+** amp_evt: event id
+** p_amp_evt_data: pointer to event-specific data
+**
+******************************************************************************
+*/
+typedef void (*tUAMP_CBACK)(tUAMP_ID amp_id, tUAMP_EVT amp_evt, tUAMP_EVT_DATA *p_amp_evt_data);
+
+/*****************************************************************************
+** external function declarations
+******************************************************************************
+*/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+**
+** Function: UAMP_Init
+**
+** Description: Initialize UAMP driver
+**
+** Parameters p_cback: Callback function for UAMP event notification
+**
+******************************************************************************
+*/
+BT_API BOOLEAN UAMP_Init(tUAMP_CBACK p_cback);
+
+
+/*****************************************************************************
+**
+** Function: UAMP_Open
+**
+** Description: Open connection to local AMP device.
+**
+** Parameters app_id: Application specific AMP identifer. This value
+** will be included in AMP messages sent to the
+** BTU task, to identify source of the message
+**
+******************************************************************************
+*/
+BT_API BOOLEAN UAMP_Open(tUAMP_ID amp_id);
+
+/*****************************************************************************
+**
+** Function: UAMP_Close
+**
+** Description: Close connection to local AMP device.
+**
+** Parameters app_id: Application specific AMP identifer.
+**
+******************************************************************************
+*/
+BT_API void UAMP_Close(tUAMP_ID amp_id);
+
+
+/*****************************************************************************
+**
+** Function: UAMP_Write
+**
+** Description: Send buffer to AMP device. Frees GKI buffer when done.
+**
+**
+** Parameters: app_id: AMP identifer.
+** p_buf: pointer to buffer to write
+** num_bytes: number of bytes to write
+** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_CMD
+**
+** Returns: number of bytes written
+**
+******************************************************************************
+*/
+BT_API UINT16 UAMP_Write(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 num_bytes, tUAMP_CH channel);
+
+/*****************************************************************************
+**
+** Function: UAMP_Read
+**
+** Description: Read incoming data from AMP. Call after receiving a
+** UAMP_EVT_RX_READY callback event.
+**
+** Parameters: app_id: AMP identifer.
+** p_buf: pointer to buffer for holding incoming AMP data
+** buf_size: size of p_buf
+** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_EVT
+**
+** Returns: number of bytes read
+**
+******************************************************************************
+*/
+BT_API UINT16 UAMP_Read(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 buf_size, tUAMP_CH channel);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UAMP_API_H */
diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c
new file mode 100644
index 000000000000..9d3580e48f9a
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_android.c
@@ -0,0 +1,2331 @@
+/*
+ * Linux cfg80211 driver - Android related functions
+ *
+ * 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: wl_android.c 662786 2016-11-11 09:06:37Z $
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <net/netlink.h>
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+#endif
+
+#include <wl_android.h>
+#include <wldev_common.h>
+#include <wlioctl.h>
+#include <bcmutils.h>
+#include <linux_osl.h>
+#include <dhd_dbg.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <proto/bcmip.h>
+#ifdef PNO_SUPPORT
+#include <dhd_pno.h>
+#endif
+#include <bcmsdbus.h>
+#ifdef WL_CFG80211
+#include <wl_cfg80211.h>
+#endif
+#ifdef WL_NAN
+#include <wl_cfgnan.h>
+#endif /* WL_NAN */
+
+/*
+ * 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_P2P_DEV_ADDR "P2P_DEV_ADDR"
+#define CMD_SETFWPATH "SETFWPATH"
+#define CMD_SETBAND "SETBAND"
+#define CMD_GETBAND "GETBAND"
+#define CMD_COUNTRY "COUNTRY"
+#define CMD_P2P_SET_NOA "P2P_SET_NOA"
+#if !defined WL_ENABLE_P2P_IF
+#define CMD_P2P_GET_NOA "P2P_GET_NOA"
+#endif /* WL_ENABLE_P2P_IF */
+#define CMD_P2P_SD_OFFLOAD "P2P_SD_"
+#define CMD_P2P_SET_PS "P2P_SET_PS"
+#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE"
+#define CMD_SETROAMMODE "SETROAMMODE"
+#define CMD_SETIBSSBEACONOUIDATA "SETIBSSBEACONOUIDATA"
+#define CMD_ADDIE "add_ie"
+#define CMD_DELIE "del_ie"
+#define CMD_MIRACAST "MIRACAST"
+#define CMD_NAN "NAN_"
+#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"
+#define CMD_KEEP_ALIVE "KEEPALIVE"
+
+
+/* CCX Private Commands */
+
+#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_OKC_SET_PMK "SET_PMK"
+#define CMD_OKC_ENABLE "OKC_ENABLE"
+
+#define CMD_HAPD_MAC_FILTER "HAPD_MAC_FILTER"
+
+
+
+
+#define CMD_ROAM_OFFLOAD "SETROAMOFFLOAD"
+
+#ifdef WLTDLS
+#define CMD_TDLS_RESET "TDLS_RESET"
+#endif /* WLTDLS */
+
+#define CMD_INTERFACE_CREATE "INTERFACE_CREATE"
+#define CMD_INTERFACE_DELETE "INTERFACE_DELETE"
+
+/* 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 */
+
+static LIST_HEAD(miracast_resume_list);
+static u8 miracast_cur_mode;
+
+struct io_cfg {
+ s8 *iovar;
+ s32 param;
+ u32 ioctl;
+ void *arg;
+ u32 len;
+ struct list_head list;
+};
+
+typedef struct _android_wifi_priv_cmd {
+ char *buf;
+ int used_len;
+ int total_len;
+} android_wifi_priv_cmd;
+
+#ifdef CONFIG_COMPAT
+typedef struct _compat_android_wifi_priv_cmd {
+ compat_caddr_t buf;
+ int used_len;
+ int total_len;
+} compat_android_wifi_priv_cmd;
+#endif /* CONFIG_COMPAT */
+
+#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 */
+
+
+/**
+ * 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; }
+#endif /* WK_CFG80211 */
+
+
+#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;
+#if defined(CUSTOMER_HW2)
+extern char iface_name[IFNAMSIZ];
+#endif
+
+/**
+ * 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
+ */
+static int g_wifi_on = TRUE;
+
+/**
+ * Local (static) function definitions
+ */
+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)
+ return -1;
+
+ /* Convert Kbps to Android Mbps */
+ link_speed = link_speed / 1000;
+ bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
+ DHD_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};
+ int bytes_written = 0;
+ int error = 0;
+ scb_val_t scbval;
+ char *delim = NULL;
+
+ delim = strchr(command, ' ');
+ /* For Ap mode rssi command would be
+ * driver rssi <sta_mac_addr>
+ * for STA/GC mode
+ * driver rssi
+ */
+ if (delim) {
+ /* Ap/GO mode
+ * driver rssi <sta_mac_addr>
+ */
+ DHD_TRACE(("%s: cmd:%s\n", __FUNCTION__, delim));
+ /* skip space from delim after finding char */
+ delim++;
+ if (!(bcm_ether_atoe((delim), &scbval.ea)))
+ {
+ DHD_ERROR(("%s:address err\n", __FUNCTION__));
+ return -1;
+ }
+ scbval.val = htod32(0);
+ DHD_TRACE(("%s: address:"MACDBG, __FUNCTION__, MAC2STRDBG(scbval.ea.octet)));
+ }
+ else {
+ /* STA/GC mode */
+ memset(&scbval, 0, sizeof(scb_val_t));
+ }
+
+ error = wldev_get_rssi(net, &scbval);
+ if (error)
+ return -1;
+
+ error = wldev_get_ssid(net, &ssid);
+ if (error)
+ return -1;
+ if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
+ DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__));
+ } else {
+ memcpy(command, ssid.SSID, ssid.SSID_len);
+ bytes_written = ssid.SSID_len;
+ }
+ bytes_written += snprintf(&command[bytes_written], total_len, " rssi %d", scbval.val);
+ DHD_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)))
+ DHD_INFO(("%s: Suspend Flag %d -> %d\n",
+ __FUNCTION__, ret_now, suspend_flag));
+ else
+ DHD_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)))
+ DHD_INFO(("%s: Suspend Mode %d\n", __FUNCTION__, suspend_flag));
+ else
+ DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
+#endif
+
+ return ret;
+}
+
+int wl_android_get_80211_mode(struct net_device *dev, char *command, int total_len)
+{
+ uint8 mode[4];
+ int error = 0;
+ int bytes_written = 0;
+
+ error = wldev_get_mode(dev, mode);
+ if (error)
+ return -1;
+
+ DHD_INFO(("%s: mode:%s\n", __FUNCTION__, mode));
+ bytes_written = snprintf(command, total_len, "%s %s", CMD_80211_MODE, mode);
+ DHD_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);
+ DHD_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;
+
+ DHD_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);
+
+ DHD_INFO(("%s: command:%s EXIT\n", __FUNCTION__, command));
+ return bytes_written;
+
+}
+
+/* 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;
+
+ DHD_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;
+
+ DHD_TRACE(("%s: ENTER\n", __FUNCTION__));
+
+ assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
+
+ error = wldev_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf), false);
+ 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;
+
+}
+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;
+ char buf[32];
+ u32 chnsp = 0;
+ int err = 0;
+
+ DHD_INFO(("%s: command:%s\n", __FUNCTION__, command));
+
+ command = (command + strlen(CMD_SET_CSA));
+ /* Order is mode, count channel */
+ if (!*++command) {
+ DHD_ERROR(("%s:error missing arguments\n", __FUNCTION__));
+ return -1;
+ }
+ csa_arg.mode = bcm_atoi(command);
+ if (csa_arg.mode != 0 && csa_arg.mode != 1) {
+ DHD_ERROR(("Invalid mode\n"));
+ return -1;
+ } if (!*++command) {
+ DHD_ERROR(("%s:error missing count\n", __FUNCTION__));
+ return -1;
+ }
+ command++;
+ csa_arg.count = bcm_atoi(command);
+ if (!*++command) {
+ DHD_ERROR(("%s:error missing channel\n", __FUNCTION__));
+ return -1;
+ }
+ csa_arg.reg = 0;
+ csa_arg.chspec = 0;
+ command += 2;
+ if (sizeof(buf) > strlen(command))
+ bcm_strncpy_s(buf, sizeof(buf), command, strlen(command));
+ else {
+ DHD_ERROR(("%s:command is invalid\n", __FUNCTION__));
+ return -1;
+ }
+ chnsp = wf_chspec_aton(buf);
+ if (chnsp == 0) {
+ DHD_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)) {
+ DHD_ERROR(("Channel is radar sensitive\n"));
+ return -1;
+ }
+ if (chanspec == 0) {
+ DHD_ERROR(("Invalid hw channel\n"));
+ return -1;
+ }
+ } else {
+ DHD_ERROR(("does not support per_chan_info\n"));
+ return -1;
+ }
+ DHD_INFO(("non radar sensitivity\n"));
+ }
+ error = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg),
+ smbuf, sizeof(smbuf), NULL);
+ if (error) {
+ DHD_ERROR(("%s:set csa failed:%d\n", __FUNCTION__, error));
+ return -1;
+ }
+ return 0;
+}
+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 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;
+ DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
+ if (total_len < strlen(CMD_WLS_BATCHING)) {
+ DHD_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);
+ DHD_PNO(("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);
+ DHD_PNO(("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);
+ DHD_PNO(("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;
+ DHD_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;
+ DHD_PNO(("band : %s\n",
+ (*token2 == 'A')? "A" : "B"));
+ } else {
+ if ((batch_params.nchan >= WL_NUMCHANNELS) ||
+ (i >= WL_NUMCHANNELS)) {
+ DHD_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++;
+ DHD_PNO(("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);
+ DHD_PNO(("rtt : %d\n", batch_params.rtt));
+ } else {
+ DHD_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) {
+ DHD_ERROR(("failed to configure batch scan\n"));
+ } else {
+ memset(command, 0, total_len);
+ err = sprintf(command, "%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) {
+ DHD_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) {
+ DHD_ERROR(("failed to stop batching scan\n"));
+ } else {
+ memset(command, 0, total_len);
+ err = sprintf(command, "OK");
+ }
+ } else {
+ DHD_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_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 */
+ DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
+
+ if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
+ DHD_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_iw_parse_ssid_list_tlv(&str_ptr, ssids_local,
+ MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
+ DHD_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)) {
+ DHD_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);
+ DHD_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
+
+ if (str_ptr[0] != 0) {
+ if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
+ DHD_ERROR(("%s pno repeat : corrupted field\n",
+ __FUNCTION__));
+ goto exit_proc;
+ }
+ str_ptr++;
+ pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
+ DHD_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
+ if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
+ DHD_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);
+ DHD_PNO(("%s: pno_freq_expo_max=%d\n",
+ __FUNCTION__, pno_freq_expo_max));
+ }
+ }
+ } else {
+ DHD_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;
+}
+
+
+#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) {
+ DHD_ERROR(("Disable tdls failed. %d\n", ret));
+ return ret;
+ }
+ ret = dhd_tdls_enable(dev, true, true, NULL);
+ if (ret < 0) {
+ DHD_ERROR(("enable tdls failed. %d\n", ret));
+ return ret;
+ }
+ return 0;
+}
+#endif /* WLTDLS */
+
+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(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode), true)) != 0) {
+ DHD_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(dev, WLC_SET_MACLIST, maclist,
+ sizeof(int) + sizeof(struct ether_addr) * maclist->count, true)) != 0) {
+ DHD_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(dev, WLC_GET_ASSOCLIST, assoc_maclist,
+ sizeof(mac_buf), false)) != 0) {
+ DHD_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++) {
+ DHD_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(dev,
+ WLC_SCB_DEAUTHENTICATE_FOR_REASON,
+ &scbval, sizeof(scb_val_t), true)) != 0)
+ DHD_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, const char* str)
+{
+ int i;
+ int ret = 0;
+ int macnum = 0;
+ int macmode = MACLIST_MODE_DISABLED;
+ struct maclist *list;
+ char eabuf[ETHER_ADDR_STR_LEN];
+ 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) {
+ DHD_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) {
+ DHD_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) {
+ DHD_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]))) {
+ DHD_ERROR(("%s : mac parsing err index=%d, addr=%s\n",
+ __FUNCTION__, i, eabuf));
+ list->count--;
+ break;
+ }
+ DHD_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)
+ DHD_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;
+
+ DHD_ERROR(("%s in\n", __FUNCTION__));
+ if (!dev) {
+ DHD_ERROR(("%s: dev is null\n", __FUNCTION__));
+ return -EINVAL;
+ }
+
+ dhd_net_if_lock(dev);
+ if (!g_wifi_on) {
+ do {
+ dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY);
+ ret = dhd_net_bus_resume(dev, 0);
+ if (ret == 0)
+ break;
+ DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n",
+ retry+1));
+ dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
+ } while (retry-- >= 0);
+ if (ret != 0) {
+ DHD_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n"));
+ goto exit;
+ }
+ ret = dhd_net_bus_devreset(dev, FALSE);
+ dhd_net_bus_resume(dev, 1);
+ if (!ret) {
+ if (dhd_dev_init_ioctl(dev) < 0)
+ ret = -EFAULT;
+ }
+ g_wifi_on = TRUE;
+ }
+
+exit:
+ dhd_net_if_unlock(dev);
+
+ return ret;
+}
+
+int wl_android_wifi_off(struct net_device *dev)
+{
+ int ret = 0;
+
+ DHD_ERROR(("%s in\n", __FUNCTION__));
+ if (!dev) {
+ DHD_TRACE(("%s: dev is null\n", __FUNCTION__));
+ return -EINVAL;
+ }
+
+ dhd_net_if_lock(dev);
+ if (g_wifi_on) {
+ ret = dhd_net_bus_devreset(dev, TRUE);
+ dhd_net_bus_suspend(dev);
+ dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
+ g_wifi_on = FALSE;
+ }
+ 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(&param, 0, sizeof(param));
+ memset(result, 0, sizeof(result));
+
+ param.buflen = htod32(sizeof(wl_chanim_stats_t));
+ param.count = htod32(WL_CHANIM_COUNT_ONE);
+
+ if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)&param, sizeof(wl_chanim_stats_t),
+ (char*)result, sizeof(result), 0)) < 0) {
+ WL_ERR(("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) {
+ WL_ERR(("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);
+
+ WL_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)
+{
+ wl_cnt_t* cnt = NULL;
+ int link_speed = 0;
+ struct connection_stats *output;
+ unsigned int bufsize = 0;
+ int bytes_written = 0;
+ int ret = 0;
+
+ WL_INFO(("%s: enter Get Connection Stats\n", __FUNCTION__));
+
+ if (total_len <= 0) {
+ WL_ERR(("%s: invalid buffer size %d\n", __FUNCTION__, total_len));
+ goto error;
+ }
+
+ bufsize = total_len;
+ if (bufsize < sizeof(struct connection_stats)) {
+ WL_ERR(("%s: not enough buffer size, provided=%u, requires=%u\n",
+ __FUNCTION__, bufsize,
+ sizeof(struct connection_stats)));
+ goto error;
+ }
+
+ if ((cnt = kmalloc(sizeof(*cnt), GFP_KERNEL)) == NULL) {
+ WL_ERR(("kmalloc failed\n"));
+ return -1;
+ }
+ memset(cnt, 0, sizeof(*cnt));
+
+ ret = wldev_iovar_getbuf(dev, "counters", NULL, 0, (char *)cnt, sizeof(wl_cnt_t), NULL);
+ if (ret) {
+ WL_ERR(("%s: wldev_iovar_getbuf() failed, ret=%d\n",
+ __FUNCTION__, ret));
+ goto error;
+ }
+
+ if (dtoh16(cnt->version) > WL_CNT_T_VERSION) {
+ WL_ERR(("%s: incorrect version of wl_cnt_t, expected=%u got=%u\n",
+ __FUNCTION__, WL_CNT_T_VERSION, cnt->version));
+ goto error;
+ }
+
+ /* link_speed is in kbps */
+ ret = wldev_get_link_speed(dev, &link_speed);
+ if (ret || link_speed < 0) {
+ WL_ERR(("%s: wldev_get_link_speed() failed, ret=%d, speed=%d\n",
+ __FUNCTION__, ret, link_speed));
+ goto error;
+ }
+
+ output = (struct connection_stats *)command;
+ output->txframe = dtoh32(cnt->txframe);
+ output->txbyte = dtoh32(cnt->txbyte);
+ output->txerror = dtoh32(cnt->txerror);
+ output->rxframe = dtoh32(cnt->rxframe);
+ output->rxbyte = dtoh32(cnt->rxbyte);
+ output->txfail = dtoh32(cnt->txfail);
+ output->txretry = dtoh32(cnt->txretry);
+ output->txretrie = dtoh32(cnt->txretrie);
+ output->txrts = dtoh32(cnt->txrts);
+ output->txnocts = dtoh32(cnt->txnocts);
+ output->txexptime = dtoh32(cnt->txexptime);
+ output->txrate = link_speed;
+
+ /* Channel idle ratio. */
+ if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) {
+ output->chan_idle = 0;
+ };
+
+ kfree(cnt);
+
+ bytes_written = sizeof(struct connection_stats);
+ return bytes_written;
+
+error:
+ if (cnt) {
+ kfree(cnt);
+ }
+ return -1;
+}
+#endif /* CONNECTION_STATISTICS */
+
+static int
+wl_android_set_pmk(struct net_device *dev, char *command, int total_len)
+{
+ uchar pmk[33];
+ int error = 0;
+ char smbuf[WLC_IOCTL_SMLEN];
+#ifdef OKC_DEBUG
+ int i = 0;
+#endif
+
+ bzero(pmk, sizeof(pmk));
+ memcpy((char *)pmk, command + strlen("SET_PMK "), 32);
+ error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL);
+ if (error) {
+ DHD_ERROR(("Failed to set PMK for OKC, error = %d\n", error));
+ }
+#ifdef OKC_DEBUG
+ DHD_ERROR(("PMK is "));
+ for (i = 0; i < 32; i++)
+ DHD_ERROR(("%02X ", pmk[i]));
+
+ DHD_ERROR(("\n"));
+#endif
+ return error;
+}
+
+static int
+wl_android_okc_enable(struct net_device *dev, char *command, int total_len)
+{
+ int error = 0;
+ char okc_enable = 0;
+
+ okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0';
+ error = wldev_iovar_setint(dev, "okc_enable", okc_enable);
+ if (error) {
+ DHD_ERROR(("Failed to %s OKC, error = %d\n",
+ okc_enable ? "enable" : "disable", error));
+ }
+
+ wldev_iovar_setint(dev, "ccx_enable", 0);
+
+ return error;
+}
+
+
+
+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) {
+ DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
+ return -1;
+ }
+
+ error = wldev_iovar_setint(dev, "roam_off", mode);
+ if (error) {
+ DHD_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n",
+ __FUNCTION__, mode, error));
+ return -1;
+ }
+ else
+ DHD_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n",
+ __FUNCTION__, mode, error));
+ return 0;
+}
+
+int wl_android_add_vendor_ie(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;
+
+ pcmd = command + strlen(CMD_ADDIE) + 1;
+
+ pktflag = simple_strtoul(pcmd, &pcmd, 16);
+
+ pcmd = pcmd + 1;
+
+ for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
+ 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++;
+ }
+
+ tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1);
+ vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags);
+ if (!vndr_ie) {
+ WL_ERR(("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 the appropriate frame will contain this IE */
+ pktflag = htod32(1<<pktflag);
+ 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;
+
+ /* Set the OUI */
+ memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
+ DOT11_OUI_LEN);
+ /* Set the Data */
+ 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) {
+ WL_ERR(("ioctl memory alloc failed\n"));
+ if (vndr_ie)
+ kfree(vndr_ie);
+ return -ENOMEM;
+ }
+ memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */
+ err = wldev_iovar_setbuf(dev, "ie", vndr_ie, tot_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
+
+ 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(vndr_ie, tot_len);
+ }
+
+ if (ioctl_buf)
+ kfree(ioctl_buf);
+
+ return err;
+}
+
+int wl_android_del_vendor_ie(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;
+
+ pcmd = command + strlen(CMD_ADDIE) + 1;
+
+ pktflag = simple_strtoul(pcmd, &pcmd, 16);
+
+ pcmd = pcmd + 1;
+ for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
+ 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++;
+ }
+
+ tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1);
+ vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags);
+ if (!vndr_ie) {
+ WL_ERR(("IE memory alloc failed\n"));
+ return -ENOMEM;
+ }
+ /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
+ strncpy(vndr_ie->cmd, "del", 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 the appropriate frame will contain this IE */
+ pktflag = htod32(1<<pktflag);
+ 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;
+
+ /* Set the OUI */
+ memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
+ DOT11_OUI_LEN);
+ /* Set the Data */
+ 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) {
+ WL_ERR(("ioctl memory alloc failed\n"));
+ if (vndr_ie)
+ kfree(vndr_ie);
+ return -ENOMEM;
+ }
+ memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */
+ err = wldev_iovar_setbuf(dev, "ie", vndr_ie, tot_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
+
+ 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(vndr_ie, tot_len);
+ }
+
+ if (ioctl_buf)
+ kfree(ioctl_buf);
+ return err;
+}
+
+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;
+
+ /* 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;
+ }
+
+ pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1;
+ for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
+ 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++;
+ }
+ tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1);
+ vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags);
+ if (!vndr_ie) {
+ WL_ERR(("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) {
+ WL_ERR(("ioctl memory alloc failed\n"));
+ if (vndr_ie) {
+ kfree(vndr_ie);
+ }
+ return -ENOMEM;
+ }
+ memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */
+ err = wldev_iovar_setbuf(dev, "ie", vndr_ie, tot_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
+
+
+ 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(vndr_ie, tot_len);
+ }
+
+ if (ioctl_buf) {
+ kfree(ioctl_buf);
+ }
+
+ return err;
+}
+
+#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);
+ /* 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 {
+ DHD_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) {
+ DHD_ERROR(("Failed to set join_pref, error = %d\n", error));
+ }
+ return error;
+}
+#endif /* defined(BCMFW_ROAM_ENABLE */
+
+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) {
+ DHD_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) {
+ DHD_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(dev, config->ioctl, resume_cfg->arg, config->len, false);
+ if (ret) {
+ DHD_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__,
+ config->ioctl));
+ goto error;
+ }
+ ret = wldev_ioctl(dev, config->ioctl + 1, config->arg, config->len, true);
+ if (ret) {
+ DHD_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;
+
+ list_for_each_safe(cur, q, head) {
+ config = list_entry(cur, struct io_cfg, list);
+ if (config->iovar) {
+ if (!ret)
+ ret = wldev_iovar_setint(dev, config->iovar,
+ config->param);
+ } else {
+ if (!ret)
+ ret = wldev_ioctl(dev, config->ioctl + 1,
+ config->arg, config->len, true);
+ if (config->ioctl + 1 == WLC_SET_PM)
+ wl_cfg80211_update_power_mode(dev);
+ kfree(config->arg);
+ }
+ list_del(cur);
+ kfree(config);
+ }
+}
+
+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) {
+ DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
+ return -1;
+ }
+
+ DHD_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(dev, WLC_GET_BCNPRD, &val, sizeof(int), false);
+ if (!ret && val > 100) {
+ config.param = 0;
+ DHD_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(dev, WLC_GET_PM, &val, sizeof(val), false);
+ 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:
+ DHD_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret));
+ wl_android_iolist_resume(dev, &miracast_resume_list);
+ return ret;
+}
+
+#define NETLINK_OXYGEN 30
+#define AIBSS_BEACON_TIMEOUT 10
+
+static struct sock *nl_sk = NULL;
+
+static void wl_netlink_recv(struct sk_buff *skb)
+{
+ WL_ERR(("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) {
+ WL_ERR(("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) {
+ WL_ERR(("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, void *data, size_t size)
+{
+ struct sk_buff *skb = NULL;
+ struct nlmsghdr *nlh = NULL;
+ int ret = -1;
+
+ if (nl_sk == NULL) {
+ WL_ERR(("nl_sk was not initialized\n"));
+ goto nlmsg_failure;
+ }
+
+ skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC);
+ if (skb == NULL) {
+ WL_ERR(("failed to allocate memory\n"));
+ goto nlmsg_failure;
+ }
+
+ nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
+ if (nlh == NULL) {
+ WL_ERR(("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);
+ WL_DBG(("netlink_unicast() pid=%d, ret=%d\n", pid, ret));
+
+nlmsg_failure:
+ return ret;
+}
+
+
+int wl_keep_alive_set(struct net_device *dev, char* extra, int total_len)
+{
+ char buf[256];
+ const char *str;
+ wl_mkeep_alive_pkt_t mkeep_alive_pkt;
+ wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
+ int buf_len;
+ int str_len;
+ int res = -1;
+ uint period_msec = 0;
+
+ if (extra == NULL)
+ {
+ DHD_ERROR(("%s: extra is NULL\n", __FUNCTION__));
+ return -1;
+ }
+ if (sscanf(extra, "%d", &period_msec) != 1)
+ {
+ DHD_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__));
+ return -EINVAL;
+ }
+ DHD_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec));
+
+ memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t));
+
+ str = "mkeep_alive";
+ str_len = strlen(str);
+ strncpy(buf, str, str_len);
+ buf[ str_len ] = '\0';
+ mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1);
+ mkeep_alive_pkt.period_msec = 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);
+
+ /* 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;
+ /* 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);
+
+ if ((res = wldev_ioctl(dev, WLC_SET_VAR, buf, buf_len, TRUE)) < 0)
+ {
+ DHD_ERROR(("%s:keep_alive set failed. res[%d]\n", __FUNCTION__, res));
+ }
+ else
+ {
+ DHD_ERROR(("%s:keep_alive set ok. res[%d]\n", __FUNCTION__, res));
+ }
+
+ return res;
+}
+
+int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
+{
+#define PRIVATE_COMMAND_MAX_LEN 8192
+ int ret = 0;
+ char *command = NULL;
+ int bytes_written = 0;
+ android_wifi_priv_cmd priv_cmd;
+
+ net_os_wake_lock(net);
+
+ if (!capable(CAP_NET_ADMIN)) {
+ ret = -EPERM;
+ goto exit;
+ }
+
+ if (!ifr->ifr_data) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+#ifdef CONFIG_COMPAT
+ if (is_compat_task()) {
+ compat_android_wifi_priv_cmd compat_priv_cmd;
+ if (copy_from_user(&compat_priv_cmd, ifr->ifr_data,
+ sizeof(compat_android_wifi_priv_cmd))) {
+ ret = -EFAULT;
+ goto exit;
+
+ }
+ priv_cmd.buf = compat_ptr(compat_priv_cmd.buf);
+ priv_cmd.used_len = compat_priv_cmd.used_len;
+ priv_cmd.total_len = compat_priv_cmd.total_len;
+ } else
+#endif /* CONFIG_COMPAT */
+ {
+ if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
+ ret = -EFAULT;
+ goto exit;
+ }
+ }
+ if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) {
+ DHD_ERROR(("%s: invalid length of private command : %d\n",
+ __FUNCTION__, priv_cmd.total_len));
+ ret = -EINVAL;
+ goto exit;
+ }
+ command = kmalloc((priv_cmd.total_len + 1), GFP_KERNEL);
+ if (!command)
+ {
+ DHD_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
+ ret = -ENOMEM;
+ goto exit;
+ }
+ if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
+ ret = -EFAULT;
+ goto exit;
+ }
+ command[priv_cmd.total_len] = '\0';
+
+ DHD_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name));
+
+ if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
+ DHD_INFO(("%s, Received regular START command\n", __FUNCTION__));
+ bytes_written = wl_android_wifi_on(net);
+ }
+ else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
+ bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
+ }
+
+ if (!g_wifi_on) {
+ DHD_ERROR(("%s: Ignore private cmd \"%s\" - iface %s is down\n",
+ __FUNCTION__, command, ifr->ifr_name));
+ ret = 0;
+ goto exit;
+ }
+
+ if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
+ bytes_written = wl_android_wifi_off(net);
+ }
+ else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
+ /* TBD: SCAN-ACTIVE */
+ }
+ else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
+ /* TBD: SCAN-PASSIVE */
+ }
+ else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
+ bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
+ bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
+ }
+#ifdef PKT_FILTER_SUPPORT
+ else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
+ bytes_written = net_os_enable_packet_filter(net, 1);
+ }
+ else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
+ bytes_written = net_os_enable_packet_filter(net, 0);
+ }
+ else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
+ int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
+ bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
+ }
+ else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
+ int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
+ bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
+ }
+#endif /* PKT_FILTER_SUPPORT */
+ else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
+ /* TBD: BTCOEXSCAN-START */
+ }
+ else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
+ /* TBD: BTCOEXSCAN-STOP */
+ }
+ else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
+#ifdef WL_CFG80211
+ void *dhdp = wl_cfg80211_get_dhdp();
+ bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command);
+#else
+#ifdef PKT_FILTER_SUPPORT
+ uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
+
+ if (mode == 1)
+ net_os_enable_packet_filter(net, 0); /* DHCP starts */
+ else
+ net_os_enable_packet_filter(net, 1); /* DHCP ends */
+#endif /* PKT_FILTER_SUPPORT */
+#endif /* WL_CFG80211 */
+ }
+ else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
+ bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
+ bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
+ uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
+ bytes_written = wldev_set_band(net, band);
+ }
+ else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
+ bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
+ }
+#ifdef WL_CFG80211
+ /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
+ else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
+ char *country_code = command + strlen(CMD_COUNTRY) + 1;
+ bytes_written = wldev_set_country(net, country_code, true, true);
+ }
+#endif /* WL_CFG80211 */
+ else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) {
+ bytes_written = wl_android_set_csa(net, command, priv_cmd.total_len);
+ } else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) {
+ bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len);
+ } else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) {
+ bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len);
+ } else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) {
+ bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len);
+ } else if (strnicmp(command, CMD_ASSOC_CLIENTS, strlen(CMD_ASSOC_CLIENTS)) == 0) {
+ bytes_written = wl_android_get_assoclist(net, command, priv_cmd.total_len);
+ }
+
+#ifdef PNO_SUPPORT
+ else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
+ bytes_written = dhd_dev_pno_stop_for_ssid(net);
+ }
+#ifndef WL_SCHED_SCAN
+ else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
+ bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
+ }
+#endif /* !WL_SCHED_SCAN */
+ else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
+ int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
+ bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net);
+ }
+ else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) {
+ bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len);
+ }
+#endif /* PNO_SUPPORT */
+ else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
+ bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
+ int skip = strlen(CMD_P2P_SET_NOA) + 1;
+ bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
+ priv_cmd.total_len - skip);
+ }
+#ifdef WL_NAN
+ else if (strnicmp(command, CMD_NAN, strlen(CMD_NAN)) == 0) {
+ bytes_written = wl_cfg80211_nan_cmd_handler(net, command,
+ priv_cmd.total_len);
+ }
+#endif /* WL_NAN */
+#if !defined WL_ENABLE_P2P_IF
+ else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
+ bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
+ }
+#endif /* WL_ENABLE_P2P_IF */
+ else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
+ int skip = strlen(CMD_P2P_SET_PS) + 1;
+ bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
+ priv_cmd.total_len - skip);
+ }
+#ifdef WL_CFG80211
+ else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
+ strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
+ int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
+ bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
+ priv_cmd.total_len - skip, *(command + skip - 2) - '0');
+ }
+#endif /* WL_CFG80211 */
+ else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0)
+ bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len);
+ else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0)
+ bytes_written = wl_android_okc_enable(net, command, priv_cmd.total_len);
+#if defined(WL_SUPPORT_AUTO_CHANNEL)
+ else if (strnicmp(command, CMD_GET_BEST_CHANNELS,
+ strlen(CMD_GET_BEST_CHANNELS)) == 0) {
+ bytes_written = wl_cfg80211_get_best_channels(net, command,
+ priv_cmd.total_len);
+ }
+#endif /* WL_SUPPORT_AUTO_CHANNEL */
+ else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) {
+ int skip = strlen(CMD_HAPD_MAC_FILTER) + 1;
+ wl_android_set_mac_address_filter(net, (const char*)command+skip);
+ }
+ else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0)
+ bytes_written = wl_android_set_roam_mode(net, command, priv_cmd.total_len);
+#if defined(BCMFW_ROAM_ENABLE)
+ else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) {
+ bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len);
+ }
+#endif /* BCMFW_ROAM_ENABLE */
+ else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0)
+ bytes_written = wl_android_set_miracast(net, command, priv_cmd.total_len);
+ else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0)
+ bytes_written = wl_android_set_ibss_beacon_ouidata(net,
+ command, priv_cmd.total_len);
+ else if (strnicmp(command, CMD_ADDIE, strlen(CMD_ADDIE)) == 0)
+ bytes_written = wl_android_add_vendor_ie(net, command, priv_cmd.total_len);
+ else if (strnicmp(command, CMD_DELIE, strlen(CMD_DELIE)) == 0)
+ bytes_written = wl_android_del_vendor_ie(net, command, priv_cmd.total_len);
+ else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
+ int skip = strlen(CMD_KEEP_ALIVE) + 1;
+ bytes_written = wl_keep_alive_set(net, command + skip, priv_cmd.total_len - skip);
+ }
+ else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) {
+ int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
+ bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
+ }
+#if defined(WL_VIRTUAL_APSTA)
+ else if (strnicmp(command, CMD_INTERFACE_CREATE, strlen(CMD_INTERFACE_CREATE)) == 0) {
+ char *name = (command + strlen(CMD_INTERFACE_CREATE) +1);
+ WL_INFO(("Creating %s interface\n", name));
+ bytes_written = wl_cfg80211_interface_create(net, name);
+ }
+ else if (strnicmp(command, CMD_INTERFACE_DELETE, strlen(CMD_INTERFACE_DELETE)) == 0) {
+ char *name = (command + strlen(CMD_INTERFACE_DELETE) +1);
+ WL_INFO(("Deleteing %s interface\n", name));
+ bytes_written = wl_cfg80211_interface_delete(net, name);
+ }
+#endif /* defined (WL_VIRTUAL_APSTA) */
+#ifdef CONNECTION_STATISTICS
+ else if (strnicmp(command, CMD_GET_CONNECTION_STATS,
+ strlen(CMD_GET_CONNECTION_STATS)) == 0) {
+ bytes_written = wl_android_get_connection_stats(net, command,
+ priv_cmd.total_len);
+ }
+#endif
+#ifdef WLTDLS
+ else if (strnicmp(command, CMD_TDLS_RESET, strlen(CMD_TDLS_RESET)) == 0) {
+ bytes_written = wl_android_tdls_reset(net);
+ }
+#endif /* WLTDLS */
+ else {
+ DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
+ snprintf(command, 3, "OK");
+ bytes_written = strlen("OK");
+ }
+
+ if (bytes_written >= 0) {
+ if ((bytes_written == 0) && (priv_cmd.total_len > 0))
+ command[0] = '\0';
+ if (bytes_written >= priv_cmd.total_len) {
+ DHD_ERROR(("%s: bytes_written = %d\n", __FUNCTION__, bytes_written));
+ bytes_written = priv_cmd.total_len;
+ } else {
+ bytes_written++;
+ }
+ priv_cmd.used_len = bytes_written;
+ if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
+ DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
+ ret = -EFAULT;
+ }
+ }
+ else {
+ ret = bytes_written;
+ }
+
+exit:
+ net_os_wake_unlock(net);
+ if (command) {
+ kfree(command);
+ }
+
+ return ret;
+}
+
+int wl_android_init(void)
+{
+ int ret = 0;
+
+#ifdef ENABLE_INSMOD_NO_FW_LOAD
+ dhd_download_fw_on_driverload = FALSE;
+#endif /* ENABLE_INSMOD_NO_FW_LOAD */
+#if defined(CUSTOMER_HW2)
+ if (!iface_name[0]) {
+ memset(iface_name, 0, IFNAMSIZ);
+ bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
+ }
+#endif
+
+ wl_netlink_init();
+
+ return ret;
+}
+
+int wl_android_exit(void)
+{
+ int ret = 0;
+ struct io_cfg *cur, *q;
+
+ wl_netlink_deinit();
+
+ list_for_each_entry_safe(cur, q, &miracast_resume_list, list) {
+ list_del(&cur->list);
+ kfree(cur);
+ }
+
+ return ret;
+}
+
+void wl_android_post_init(void)
+{
+
+#ifdef ENABLE_4335BT_WAR
+ bcm_bt_unlock(lock_cookie_wifi);
+ printk("%s: btlock released\n", __FUNCTION__);
+#endif /* ENABLE_4335BT_WAR */
+
+ if (!dhd_download_fw_on_driverload)
+ g_wifi_on = FALSE;
+}
diff --git a/drivers/net/wireless/bcmdhd/wl_android.h b/drivers/net/wireless/bcmdhd/wl_android.h
new file mode 100644
index 000000000000..e925156e5d46
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_android.h
@@ -0,0 +1,77 @@
+/*
+ * Linux cfg80211 driver - Android related functions
+ *
+ * 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: wl_android.h 513422 2014-11-06 11:06:57Z $
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <wldev_common.h>
+
+/* If any feature uses the Generic Netlink Interface, put it here to enable WL_GENL
+ * automatically
+ */
+#if defined(WL_NAN)
+#define WL_GENL
+#endif
+
+
+
+/**
+ * Android platform dependent functions, feel free to add Android specific functions here
+ * (save the macros in dhd). Please do NOT declare functions that are NOT exposed to dhd
+ * or cfg, define them as static in wl_android.c
+ */
+
+/**
+ * wl_android_init will be called from module init function (dhd_module_init now), similarly
+ * wl_android_exit will be called from module exit function (dhd_module_cleanup now)
+ */
+int wl_android_init(void);
+int wl_android_exit(void);
+void wl_android_post_init(void);
+int wl_android_wifi_on(struct net_device *dev);
+int wl_android_wifi_off(struct net_device *dev);
+int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd);
+
+s32 wl_netlink_send_msg(int pid, int type, int seq, void *data, size_t size);
+
+/* hostap mac mode */
+#define MACLIST_MODE_DISABLED 0
+#define MACLIST_MODE_DENY 1
+#define MACLIST_MODE_ALLOW 2
+
+/* max number of assoc list */
+#define MAX_NUM_OF_ASSOCLIST 64
+
+/* Bandwidth */
+#define WL_CH_BANDWIDTH_20MHZ 20
+#define WL_CH_BANDWIDTH_40MHZ 40
+#define WL_CH_BANDWIDTH_80MHZ 80
+
+/* max number of mac filter list
+ * restrict max number to 10 as maximum cmd string size is 255
+ */
+#define MAX_NUM_MAC_FILT 10
+
+int wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist);
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
new file mode 100644
index 000000000000..3958b2332faa
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
@@ -0,0 +1,14425 @@
+/*
+ * Linux cfg80211 driver
+ *
+ * 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: wl_cfg80211.c 662965 2016-11-24 03:53:15Z $
+ */
+/* */
+#include <typedefs.h>
+#include <linuxver.h>
+#include <osl.h>
+#include <linux/kernel.h>
+
+#include <bcmutils.h>
+#include <bcmwifi_channels.h>
+#include <bcmendian.h>
+#include <proto/ethernet.h>
+#include <proto/802.11.h>
+#include <linux/if_arp.h>
+#include <asm/uaccess.h>
+
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_linux.h>
+#include <dhdioctl.h>
+#include <wlioctl.h>
+#include <dhd_cfg80211.h>
+#ifdef PNO_SUPPORT
+#include <dhd_pno.h>
+#endif /* PNO_SUPPORT */
+
+#include <proto/ethernet.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <linux/wait.h>
+#include <net/cfg80211.h>
+#include <net/rtnetlink.h>
+
+#include <wlioctl.h>
+#include <wldev_common.h>
+#include <wl_cfg80211.h>
+#include <wl_cfgp2p.h>
+#include <wl_android.h>
+
+#ifdef WL_NAN
+#include <wl_cfgnan.h>
+#endif /* WL_NAN */
+#ifdef PROP_TXSTATUS
+#include <dhd_wlfc.h>
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
+#include <wl_cfgvendor.h>
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
+#ifdef WL11U
+#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF)
+#error You should enable 'WL_ENABLE_P2P_IF' or 'WL_CFG80211_P2P_DEV_IF' \
+ according to Kernel version and is supported only in Android-JB
+#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */
+#endif /* WL11U */
+
+
+#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
+
+
+
+static struct device *cfg80211_parent_dev = NULL;
+/* g_bcm_cfg should be static. Do not change */
+static struct bcm_cfg80211 *g_bcm_cfg = NULL;
+u32 wl_dbg_level = WL_DBG_ERR;
+
+#ifdef VSDB
+/* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */
+#define DEFAULT_SLEEP_TIME_VSDB 120
+#define OFF_CHAN_TIME_THRESHOLD_MS 200
+#define AF_RETRY_DELAY_TIME 40
+
+/* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */
+#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) \
+ do { \
+ if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) || \
+ wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { \
+ OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB); \
+ } \
+ } while (0)
+#else /* VSDB */
+/* if not VSDB, do nothing */
+#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg)
+#endif /* VSDB */
+
+#ifdef WL_CFG80211_SYNC_GON
+#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) \
+ (wl_get_drv_status_all(cfg, SENDING_ACT_FRM) || \
+ wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN))
+#else
+#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) wl_get_drv_status_all(cfg, SENDING_ACT_FRM)
+#endif /* WL_CFG80211_SYNC_GON */
+#define WL_IS_P2P_DEV_EVENT(e) ((e->emsg.ifidx == 0) && \
+ (e->emsg.bsscfgidx == P2PAPI_BSSCFG_DEVICE))
+
+#define COEX_DHCP
+
+#define WLAN_EID_SSID 0
+#define CH_MIN_5G_CHANNEL 34
+#define CH_MIN_2G_CHANNEL 1
+
+
+#ifdef WL_RELMCAST
+enum rmc_event_type {
+ RMC_EVENT_NONE,
+ RMC_EVENT_LEADER_CHECK_FAIL
+};
+#endif /* WL_RELMCAST */
+
+/* This is to override regulatory domains defined in cfg80211 module (reg.c)
+ * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
+ * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
+ * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels.
+ * All the chnages in world regulatory domain are to be done here.
+ */
+static const struct ieee80211_regdomain brcm_regdom = {
+ .n_reg_rules = 4,
+ .alpha2 = "99",
+ .reg_rules = {
+ /* IEEE 802.11b/g, channels 1..11 */
+ REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
+ /* If any */
+ /* IEEE 802.11 channel 14 - Only JP enables
+ * this and for 802.11b only
+ */
+ REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
+ /* IEEE 802.11a, channel 36..64 */
+ REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
+ /* IEEE 802.11a, channel 100..165 */
+ REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
+};
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
+ (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
+/*
+ * Possible interface combinations supported by driver
+ *
+ * ADHOC Mode - #ADHOC <= 1 on channels = 1
+ * SoftAP Mode - #AP <= 1 on channels = 1
+ * STA + P2P Mode - #STA <= 2, #{P2P-GO, P2P-client} <= 1, #P2P-device <= 1
+ * on channels = 2
+ */
+static const struct ieee80211_iface_limit common_if_limits[] = {
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_AP),
+ },
+ {
+ /*
+ * During P2P-GO removal, P2P-GO is first changed to STA and later only
+ * removed. So setting maximum possible number of STA interfaces according
+ * to kernel version.
+ *
+ * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x)
+ * linux-3.8 and above - max:2 (wlan0 + group removal of p2p-wlan0-x)
+ */
+#ifdef WL_ENABLE_P2P_IF
+ .max = 3,
+#else
+ .max = 2,
+#endif /* WL_ENABLE_P2P_IF */
+ .types = BIT(NL80211_IFTYPE_STATION),
+ },
+ {
+ .max = 2,
+ .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT),
+ },
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
+ },
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_ADHOC),
+ },
+};
+#ifdef BCM4330_CHIP
+#define NUM_DIFF_CHANNELS 1
+#else
+#define NUM_DIFF_CHANNELS 2
+#endif
+static const struct ieee80211_iface_combination
+common_iface_combinations[] = {
+ {
+ .num_different_channels = NUM_DIFF_CHANNELS,
+ .max_interfaces = 4,
+ .limits = common_if_limits,
+ .n_limits = ARRAY_SIZE(common_if_limits),
+ },
+};
+#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
+
+/* Data Element Definitions */
+#define WPS_ID_CONFIG_METHODS 0x1008
+#define WPS_ID_REQ_TYPE 0x103A
+#define WPS_ID_DEVICE_NAME 0x1011
+#define WPS_ID_VERSION 0x104A
+#define WPS_ID_DEVICE_PWD_ID 0x1012
+#define WPS_ID_REQ_DEV_TYPE 0x106A
+#define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053
+#define WPS_ID_PRIM_DEV_TYPE 0x1054
+
+/* Device Password ID */
+#define DEV_PW_DEFAULT 0x0000
+#define DEV_PW_USER_SPECIFIED 0x0001,
+#define DEV_PW_MACHINE_SPECIFIED 0x0002
+#define DEV_PW_REKEY 0x0003
+#define DEV_PW_PUSHBUTTON 0x0004
+#define DEV_PW_REGISTRAR_SPECIFIED 0x0005
+
+/* Config Methods */
+#define WPS_CONFIG_USBA 0x0001
+#define WPS_CONFIG_ETHERNET 0x0002
+#define WPS_CONFIG_LABEL 0x0004
+#define WPS_CONFIG_DISPLAY 0x0008
+#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
+#define WPS_CONFIG_INT_NFC_TOKEN 0x0020
+#define WPS_CONFIG_NFC_INTERFACE 0x0040
+#define WPS_CONFIG_PUSHBUTTON 0x0080
+#define WPS_CONFIG_KEYPAD 0x0100
+#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
+#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
+#define WPS_CONFIG_VIRT_DISPLAY 0x2008
+#define WPS_CONFIG_PHY_DISPLAY 0x4008
+
+
+#define WL_AKM_SUITE_SHA256_1X 0x000FAC05
+#define WL_AKM_SUITE_SHA256_PSK 0x000FAC06
+#define WL_MFP_CAPABLE 0x1
+#define WL_MFP_REQUIRED 0x2
+
+#ifndef IBSS_COALESCE_ALLOWED
+#define IBSS_COALESCE_ALLOWED 0
+#endif
+
+#ifndef IBSS_INITIAL_SCAN_ALLOWED
+#define IBSS_INITIAL_SCAN_ALLOWED 0
+#endif
+
+#define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */
+#define LONG_LISTEN_TIME 2000
+
+#define MAX_SCAN_ABORT_WAIT_CNT 20
+#define WAIT_SCAN_ABORT_OSL_SLEEP_TIME 10
+
+/*
+ * cfg80211_ops api/callback list
+ */
+static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da,
+ const struct ether_addr *sa, const struct ether_addr *bssid,
+ u8 **pheader, u32 *body_len, u8 *pbody);
+static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request,
+ struct cfg80211_ssid *this_ssid);
+#if defined(WL_CFG80211_P2P_DEV_IF)
+static s32
+wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request);
+#else
+static s32
+wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
+static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ibss_params *params);
+static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy,
+ struct net_device *dev);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
+ struct net_device *dev, const u8 *mac,
+ struct station_info *sinfo);
+#else
+static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
+ struct net_device *dev, u8 *mac,
+ struct station_info *sinfo);
+#endif
+static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *dev, bool enabled,
+ s32 timeout);
+static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code);
+#if defined(WL_CFG80211_P2P_DEV_IF)
+static s32
+wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+ enum nl80211_tx_power_setting type, s32 mbm);
+#else
+static s32
+wl_cfg80211_set_tx_power(struct wiphy *wiphy,
+ enum nl80211_tx_power_setting type, s32 dbm);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+#if defined(WL_CFG80211_P2P_DEV_IF)
+static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
+ struct wireless_dev *wdev, s32 *dbm);
+#else
+static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
+ struct net_device *dev,
+ u8 key_idx, bool unicast, bool multicast);
+static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr,
+ struct key_params *params);
+static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr);
+static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr,
+ void *cookie, void (*callback) (void *cookie,
+ struct key_params *params));
+static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
+ struct net_device *dev, u8 key_idx);
+static s32 wl_cfg80211_resume(struct wiphy *wiphy);
+#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
+ 2, 0))
+static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
+ bcm_struct_cfgdev *cfgdev, u64 cookie);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
+static s32 wl_cfg80211_del_station(
+ struct wiphy *wiphy, struct net_device *ndev,
+ struct station_del_parameters *params);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
+ struct net_device *ndev, const u8* mac_addr);
+#else
+static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
+ struct net_device *ndev, u8* mac_addr);
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
+ struct net_device *dev, const u8 *mac, struct station_parameters *params);
+#else
+static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
+ struct net_device *dev, u8 *mac, struct station_parameters *params);
+#endif
+#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
+static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
+#else
+static s32 wl_cfg80211_suspend(struct wiphy *wiphy);
+#endif
+static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_pmksa *pmksa);
+static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_pmksa *pmksa);
+static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
+ struct net_device *dev);
+#ifdef P2PONEINT
+void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg);
+#else
+static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg);
+#endif
+static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg,
+ struct net_device *ndev, bool aborted, bool fw_abort);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0))
+static s32
+wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
+ u32 peer_capability, bool initiator, const u8 *data, size_t len);
+#else
+#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
+static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
+ u32 peer_capability, const u8 *data, size_t len);
+#else
+static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *data,
+ size_t len);
+#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0) */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static s32
+wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *peer, enum nl80211_tdls_operation oper);
+#else
+static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, enum nl80211_tdls_operation oper);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) */
+#endif
+#ifdef WL_SCHED_SCAN
+static int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev);
+#endif
+chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec);
+
+#if defined(WL_VIRTUAL_APSTA)
+bcm_struct_cfgdev*
+wl_cfg80211_create_iface(struct wiphy *wiphy, enum nl80211_iftype
+ iface_type, u8 *mac_addr, const char *name);
+s32
+wl_cfg80211_del_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev);
+#endif /* defined(WL_VIRTUAL_APSTA) */
+
+s32 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
+ struct net_device *ndev, s32 bsscfg_idx,
+ enum nl80211_iftype iface_type, s32 del, u8 *addr);
+
+/*
+ * event & event Q handlers for cfg80211 interfaces
+ */
+static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg);
+static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg);
+static s32 wl_event_handler(void *data);
+static void wl_init_eq(struct bcm_cfg80211 *cfg);
+static void wl_flush_eq(struct bcm_cfg80211 *cfg);
+static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg);
+static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags);
+static void wl_init_eq_lock(struct bcm_cfg80211 *cfg);
+static void wl_init_event_handler(struct bcm_cfg80211 *cfg);
+static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg);
+static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 type,
+ const wl_event_msg_t *msg, void *data);
+static void wl_put_event(struct wl_event_q *e);
+static void wl_wakeup_event(struct bcm_cfg80211 *cfg);
+static s32 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data);
+static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg,
+ bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
+static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg,
+ bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
+static s32 wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data, bool completed);
+static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data);
+static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+#ifdef WL_SCHED_SCAN
+static s32
+wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data);
+#endif /* WL_SCHED_SCAN */
+#ifdef PNO_SUPPORT
+static s32 wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+#endif /* PNO_SUPPORT */
+static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
+ enum wl_status state, bool set);
+
+#ifdef WLTDLS
+static s32 wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+#endif /* WLTDLS */
+/*
+ * register/deregister parent device
+ */
+static void wl_cfg80211_clear_parent_dev(void);
+
+/*
+ * ioctl utilites
+ */
+
+/*
+ * cfg80211 set_wiphy_params utilities
+ */
+static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold);
+static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold);
+static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l);
+
+/*
+ * cfg profile utilities
+ */
+static s32 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data, s32 item);
+static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item);
+static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev);
+
+/*
+ * cfg80211 connect utilites
+ */
+static s32 wl_set_wpa_version(struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+static s32 wl_set_auth_type(struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+static s32 wl_set_set_cipher(struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+static s32 wl_set_key_mgmt(struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+static s32 wl_set_set_sharedkey(struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev);
+static void wl_ch_to_chanspec(int ch,
+ struct wl_join_params *join_params, size_t *join_params_size);
+
+/*
+ * information element utilities
+ */
+static void wl_rst_ie(struct bcm_cfg80211 *cfg);
+static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v);
+static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size, bool roam);
+static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size);
+static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size);
+static u32 wl_get_ielen(struct bcm_cfg80211 *cfg);
+
+#ifdef WL11U
+bcm_tlv_t *
+wl_cfg80211_find_interworking_ie(u8 *parse, u32 len);
+static s32
+wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag,
+ uint8 ie_id, uint8 *data, uint8 data_len);
+#endif /* WL11U */
+
+static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, void *data);
+static void wl_free_wdev(struct bcm_cfg80211 *cfg);
+#ifdef CONFIG_CFG80211_INTERNAL_REGDB
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
+static int
+#else
+static void
+#endif /* kernel version < 3.10.11 */
+wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
+#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
+
+static s32 wl_inform_bss(struct bcm_cfg80211 *cfg);
+static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam);
+static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam);
+#ifdef P2PONEINT
+chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
+#else
+static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
+#endif
+s32 wl_cfg80211_channel_to_freq(u32 channel);
+
+
+static void wl_cfg80211_work_handler(struct work_struct *work);
+static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, const u8 *mac_addr,
+ struct key_params *params);
+/*
+ * key indianess swap utilities
+ */
+static void swap_key_from_BE(struct wl_wsec_key *key);
+static void swap_key_to_BE(struct wl_wsec_key *key);
+
+/*
+ * bcm_cfg80211 memory init/deinit utilities
+ */
+static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg);
+static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg);
+
+static void wl_delay(u32 ms);
+
+/*
+ * ibss mode utilities
+ */
+static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev);
+static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg);
+
+/*
+ * link up/down , default configuration utilities
+ */
+static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg);
+static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg);
+static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
+static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e,
+ struct net_device *ndev);
+static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
+static void wl_link_up(struct bcm_cfg80211 *cfg);
+static void wl_link_down(struct bcm_cfg80211 *cfg);
+static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 iftype);
+static void wl_init_conf(struct wl_conf *conf);
+static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *if_event_info,
+ struct net_device* ndev);
+
+int wl_cfg80211_get_ioctl_version(void);
+
+/*
+ * find most significant bit set
+ */
+static __used u32 wl_find_msb(u16 bit16);
+
+/*
+ * rfkill support
+ */
+static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup);
+static int wl_rfkill_set(void *data, bool blocked);
+#ifdef DEBUGFS_CFG80211
+static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg);
+static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg);
+#endif
+
+static wl_scan_params_t *wl_cfg80211_scan_alloc_params(int channel,
+ int nprobes, int *out_params_size);
+static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role);
+
+#ifdef WL_CFG80211_ACL
+/* ACL */
+static int wl_cfg80211_set_mac_acl(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
+ const struct cfg80211_acl_data *acl);
+#endif /* WL_CFG80211_ACL */
+
+/*
+ * Some external functions, TODO: move them to dhd_linux.h
+ */
+int dhd_add_monitor(char *name, struct net_device **new_ndev);
+int dhd_del_monitor(struct net_device *ndev);
+int dhd_monitor_init(void *dhd_pub);
+int dhd_monitor_uninit(void);
+int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
+
+
+static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const struct ether_addr *bssid);
+
+static s32 wl_cfg80211_parse_vndr_ies(u8 *parse, u32 len, struct parsed_vndr_ies *vndr_ies);
+
+
+#define RETURN_EIO_IF_NOT_UP(wlpriv) \
+do { \
+ struct net_device *checkSysUpNDev = bcmcfg_to_prmry_ndev(wlpriv); \
+ if (unlikely(!wl_get_drv_status(wlpriv, READY, checkSysUpNDev))) { \
+ WL_INFO(("device is not ready\n")); \
+ return -EIO; \
+ } \
+} while (0)
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0))
+#define CFG80211_DISCONNECTED(dev, reason, ie, len, loc_gen, gfp) \
+ cfg80211_disconnected(dev, reason, ie, len, gfp);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0))
+#define CFG80211_DISCONNECTED(dev, reason, ie, len, loc_gen, gfp) \
+ cfg80211_disconnected(dev, reason, ie, len, loc_gen, gfp);
+#endif
+
+#ifdef RSSI_OFFSET
+static s32 wl_rssi_offset(s32 rssi)
+{
+ rssi += RSSI_OFFSET;
+ if (rssi > 0)
+ rssi = 0;
+ return rssi;
+}
+#else
+#define wl_rssi_offset(x) x
+#endif
+
+#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \
+ (akm) == RSN_AKM_UNSPECIFIED || \
+ (akm) == RSN_AKM_PSK)
+
+
+extern int dhd_wait_pend8021x(struct net_device *dev);
+#ifdef PROP_TXSTATUS_VSDB
+extern int disable_proptx;
+#endif /* PROP_TXSTATUS_VSDB */
+static s32
+wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+const wl_event_msg_t *e, void *data);
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, \
+ 0)))
+struct chan_info {
+ int freq;
+ int chan_type;
+};
+#endif
+
+
+#if (WL_DBG_LEVEL > 0)
+#define WL_DBG_ESTR_MAX 50
+static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = {
+ "SET_SSID", "JOIN", "START", "AUTH", "AUTH_IND",
+ "DEAUTH", "DEAUTH_IND", "ASSOC", "ASSOC_IND", "REASSOC",
+ "REASSOC_IND", "DISASSOC", "DISASSOC_IND", "QUIET_START", "QUIET_END",
+ "BEACON_RX", "LINK", "MIC_ERROR", "NDIS_LINK", "ROAM",
+ "TXFAIL", "PMKID_CACHE", "RETROGRADE_TSF", "PRUNE", "AUTOAUTH",
+ "EAPOL_MSG", "SCAN_COMPLETE", "ADDTS_IND", "DELTS_IND", "BCNSENT_IND",
+ "BCNRX_MSG", "BCNLOST_MSG", "ROAM_PREP", "PFN_NET_FOUND",
+ "PFN_NET_LOST",
+ "RESET_COMPLETE", "JOIN_START", "ROAM_START", "ASSOC_START",
+ "IBSS_ASSOC",
+ "RADIO", "PSM_WATCHDOG", "WLC_E_CCX_ASSOC_START", "WLC_E_CCX_ASSOC_ABORT",
+ "PROBREQ_MSG",
+ "SCAN_CONFIRM_IND", "PSK_SUP", "COUNTRY_CODE_CHANGED",
+ "EXCEEDED_MEDIUM_TIME", "ICV_ERROR",
+ "UNICAST_DECODE_ERROR", "MULTICAST_DECODE_ERROR", "TRACE",
+ "WLC_E_BTA_HCI_EVENT", "IF", "WLC_E_P2P_DISC_LISTEN_COMPLETE",
+ "RSSI", "PFN_SCAN_COMPLETE", "WLC_E_EXTLOG_MSG",
+ "ACTION_FRAME", "ACTION_FRAME_COMPLETE", "WLC_E_PRE_ASSOC_IND",
+ "WLC_E_PRE_REASSOC_IND", "WLC_E_CHANNEL_ADOPTED", "WLC_E_AP_STARTED",
+ "WLC_E_DFS_AP_STOP", "WLC_E_DFS_AP_RESUME", "WLC_E_WAI_STA_EVENT",
+ "WLC_E_WAI_MSG", "WLC_E_ESCAN_RESULT", "WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE",
+ "WLC_E_PROBRESP_MSG", "WLC_E_P2P_PROBREQ_MSG", "WLC_E_DCS_REQUEST", "WLC_E_FIFO_CREDIT_MAP",
+ "WLC_E_ACTION_FRAME_RX", "WLC_E_WAKE_EVENT", "WLC_E_RM_COMPLETE"
+};
+#endif /* WL_DBG_LEVEL */
+
+#define CHAN2G(_channel, _freq, _flags) { \
+ .band = NL80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+#define CHAN5G(_channel, _flags) { \
+ .band = NL80211_BAND_5GHZ, \
+ .center_freq = 5000 + (5 * (_channel)), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
+#define RATETAB_ENT(_rateid, _flags) \
+ { \
+ .bitrate = RATE_TO_BASE100KBPS(_rateid), \
+ .hw_value = (_rateid), \
+ .flags = (_flags), \
+ }
+
+static struct ieee80211_rate __wl_rates[] = {
+ RATETAB_ENT(DOT11_RATE_1M, 0),
+ RATETAB_ENT(DOT11_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(DOT11_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(DOT11_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(DOT11_RATE_6M, 0),
+ RATETAB_ENT(DOT11_RATE_9M, 0),
+ RATETAB_ENT(DOT11_RATE_12M, 0),
+ RATETAB_ENT(DOT11_RATE_18M, 0),
+ RATETAB_ENT(DOT11_RATE_24M, 0),
+ RATETAB_ENT(DOT11_RATE_36M, 0),
+ RATETAB_ENT(DOT11_RATE_48M, 0),
+ RATETAB_ENT(DOT11_RATE_54M, 0)
+};
+
+#define wl_a_rates (__wl_rates + 4)
+#define wl_a_rates_size 8
+#define wl_g_rates (__wl_rates + 0)
+#define wl_g_rates_size 12
+
+static struct ieee80211_channel __wl_2ghz_channels[] = {
+ CHAN2G(1, 2412, 0),
+ CHAN2G(2, 2417, 0),
+ CHAN2G(3, 2422, 0),
+ CHAN2G(4, 2427, 0),
+ CHAN2G(5, 2432, 0),
+ CHAN2G(6, 2437, 0),
+ CHAN2G(7, 2442, 0),
+ CHAN2G(8, 2447, 0),
+ CHAN2G(9, 2452, 0),
+ CHAN2G(10, 2457, 0),
+ CHAN2G(11, 2462, 0),
+ CHAN2G(12, 2467, 0),
+ CHAN2G(13, 2472, 0),
+ CHAN2G(14, 2484, 0)
+};
+
+static struct ieee80211_channel __wl_5ghz_a_channels[] = {
+ CHAN5G(34, 0), CHAN5G(36, 0),
+ CHAN5G(38, 0), CHAN5G(40, 0),
+ CHAN5G(42, 0), CHAN5G(44, 0),
+ CHAN5G(46, 0), CHAN5G(48, 0),
+ CHAN5G(52, 0), CHAN5G(56, 0),
+ CHAN5G(60, 0), CHAN5G(64, 0),
+ CHAN5G(100, 0), CHAN5G(104, 0),
+ CHAN5G(108, 0), CHAN5G(112, 0),
+ CHAN5G(116, 0), CHAN5G(120, 0),
+ CHAN5G(124, 0), CHAN5G(128, 0),
+ CHAN5G(132, 0), CHAN5G(136, 0),
+ CHAN5G(140, 0), CHAN5G(144, 0),
+ CHAN5G(149, 0), CHAN5G(153, 0),
+ CHAN5G(157, 0), CHAN5G(161, 0),
+ CHAN5G(165, 0)
+};
+
+static struct ieee80211_supported_band __wl_band_2ghz = {
+ .band = NL80211_BAND_2GHZ,
+ .channels = __wl_2ghz_channels,
+ .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
+ .bitrates = wl_g_rates,
+ .n_bitrates = wl_g_rates_size
+};
+
+static struct ieee80211_supported_band __wl_band_5ghz_a = {
+ .band = NL80211_BAND_5GHZ,
+ .channels = __wl_5ghz_a_channels,
+ .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
+ .bitrates = wl_a_rates,
+ .n_bitrates = wl_a_rates_size
+};
+
+static const u32 __wl_cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+ WLAN_CIPHER_SUITE_AES_CMAC,
+};
+
+#ifdef WL_SUPPORT_ACS
+/*
+ * The firmware code required for this feature to work is currently under
+ * BCMINTERNAL flag. In future if this is to enabled we need to bring the
+ * required firmware code out of the BCMINTERNAL flag.
+ */
+struct wl_dump_survey {
+ u32 obss;
+ u32 ibss;
+ u32 no_ctg;
+ u32 no_pckt;
+ u32 tx;
+ u32 idle;
+};
+#endif /* WL_SUPPORT_ACS */
+
+#ifdef WL_SUPPORT_ACS
+uint8 g_hostap_chan_count;
+uint16 g_hostap_chan_cache[50];
+#endif /* WL_SUPPORT_ACS */
+
+
+#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
+static int maxrxpktglom = 0;
+#endif
+
+/* IOCtl version read from targeted driver */
+static int ioctl_version;
+#ifdef DEBUGFS_CFG80211
+#define S_SUBLOGLEVEL 20
+static const struct {
+ u32 log_level;
+ char *sublogname;
+} sublogname_map[] = {
+ {WL_DBG_ERR, "ERR"},
+ {WL_DBG_INFO, "INFO"},
+ {WL_DBG_DBG, "DBG"},
+ {WL_DBG_SCAN, "SCAN"},
+ {WL_DBG_TRACE, "TRACE"},
+ {WL_DBG_P2P_ACTION, "P2PACTION"}
+};
+#endif
+
+
+static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg, bool add_remove,
+ enum wl_handler_del_type type)
+{
+ if (cfg == NULL)
+ return;
+
+ if (cfg->pm_enable_work_on) {
+ if (add_remove) {
+ schedule_delayed_work(&cfg->pm_enable_work,
+ msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT));
+ } else {
+ cancel_delayed_work_sync(&cfg->pm_enable_work);
+ switch (type) {
+ case WL_HANDLER_MAINTAIN:
+ schedule_delayed_work(&cfg->pm_enable_work,
+ msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT));
+ break;
+ case WL_HANDLER_PEND:
+ schedule_delayed_work(&cfg->pm_enable_work,
+ msecs_to_jiffies(WL_PM_ENABLE_TIMEOUT*2));
+ break;
+ case WL_HANDLER_DEL:
+ default:
+ cfg->pm_enable_work_on = false;
+ break;
+ }
+ }
+ }
+}
+
+/* Return a new chanspec given a legacy chanspec
+ * Returns INVCHANSPEC on error
+ */
+static chanspec_t
+wl_chspec_from_legacy(chanspec_t legacy_chspec)
+{
+ chanspec_t chspec;
+
+ /* get the channel number */
+ chspec = LCHSPEC_CHANNEL(legacy_chspec);
+
+ /* convert the band */
+ if (LCHSPEC_IS2G(legacy_chspec)) {
+ chspec |= WL_CHANSPEC_BAND_2G;
+ } else {
+ chspec |= WL_CHANSPEC_BAND_5G;
+ }
+
+ /* convert the bw and sideband */
+ if (LCHSPEC_IS20(legacy_chspec)) {
+ chspec |= WL_CHANSPEC_BW_20;
+ } else {
+ chspec |= WL_CHANSPEC_BW_40;
+ if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
+ chspec |= WL_CHANSPEC_CTL_SB_L;
+ } else {
+ chspec |= WL_CHANSPEC_CTL_SB_U;
+ }
+ }
+
+ if (wf_chspec_malformed(chspec)) {
+ WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
+ chspec));
+ return INVCHANSPEC;
+ }
+
+ return chspec;
+}
+
+/* Return a legacy chanspec given a new chanspec
+ * Returns INVCHANSPEC on error
+ */
+static chanspec_t
+wl_chspec_to_legacy(chanspec_t chspec)
+{
+ chanspec_t lchspec;
+
+ if (wf_chspec_malformed(chspec)) {
+ WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
+ chspec));
+ return INVCHANSPEC;
+ }
+
+ /* get the channel number */
+ lchspec = CHSPEC_CHANNEL(chspec);
+
+ /* convert the band */
+ if (CHSPEC_IS2G(chspec)) {
+ lchspec |= WL_LCHANSPEC_BAND_2G;
+ } else {
+ lchspec |= WL_LCHANSPEC_BAND_5G;
+ }
+
+ /* convert the bw and sideband */
+ if (CHSPEC_IS20(chspec)) {
+ lchspec |= WL_LCHANSPEC_BW_20;
+ lchspec |= WL_LCHANSPEC_CTL_SB_NONE;
+ } else if (CHSPEC_IS40(chspec)) {
+ lchspec |= WL_LCHANSPEC_BW_40;
+ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) {
+ lchspec |= WL_LCHANSPEC_CTL_SB_LOWER;
+ } else {
+ lchspec |= WL_LCHANSPEC_CTL_SB_UPPER;
+ }
+ } else {
+ /* cannot express the bandwidth */
+ char chanbuf[CHANSPEC_STR_LEN];
+ WL_ERR((
+ "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
+ "to pre-11ac format\n",
+ wf_chspec_ntoa(chspec, chanbuf), chspec));
+ return INVCHANSPEC;
+ }
+
+ return lchspec;
+}
+
+/* given a chanspec value, do the endian and chanspec version conversion to
+ * a chanspec_t value
+ * Returns INVCHANSPEC on error
+ */
+chanspec_t
+wl_chspec_host_to_driver(chanspec_t chanspec)
+{
+ if (ioctl_version == 1) {
+ chanspec = wl_chspec_to_legacy(chanspec);
+ if (chanspec == INVCHANSPEC) {
+ return chanspec;
+ }
+ }
+ chanspec = htodchanspec(chanspec);
+
+ return chanspec;
+}
+
+/* given a channel value, do the endian and chanspec version conversion to
+ * a chanspec_t value
+ * Returns INVCHANSPEC on error
+ */
+chanspec_t
+wl_ch_host_to_driver(u16 channel)
+{
+
+ chanspec_t chanspec;
+
+ chanspec = channel & WL_CHANSPEC_CHAN_MASK;
+
+ if (channel <= CH_MAX_2G_CHANNEL)
+ chanspec |= WL_CHANSPEC_BAND_2G;
+ else
+ chanspec |= WL_CHANSPEC_BAND_5G;
+
+ chanspec |= WL_CHANSPEC_BW_20;
+ chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+
+ return wl_chspec_host_to_driver(chanspec);
+}
+
+/* given a chanspec value from the driver, do the endian and chanspec version conversion to
+ * a chanspec_t value
+ * Returns INVCHANSPEC on error
+ */
+chanspec_t
+wl_chspec_driver_to_host(chanspec_t chanspec)
+{
+ chanspec = dtohchanspec(chanspec);
+ if (ioctl_version == 1) {
+ chanspec = wl_chspec_from_legacy(chanspec);
+ }
+
+ return chanspec;
+}
+
+/*
+ * convert ASCII string to MAC address (colon-delimited format)
+ * eg: 00:11:22:33:44:55
+ */
+int
+wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n)
+{
+ char *c = NULL;
+ int count = 0;
+
+ memset(n, 0, ETHER_ADDR_LEN);
+ for (;;) {
+ n->octet[count++] = (uint8)simple_strtoul(a, &c, 16);
+ if (!*c++ || count == ETHER_ADDR_LEN)
+ break;
+ a = c;
+ }
+ return (count == ETHER_ADDR_LEN);
+}
+
+/* convert hex string buffer to binary */
+int
+wl_cfg80211_hex_str_to_bin(unsigned char *data, int dlen, char *str)
+{
+ int count, slen;
+ int hvalue;
+ char tmp[3] = {0};
+ char *ptr = str, *endp = NULL;
+
+ if (!data || !str || !dlen) {
+ WL_DBG((" passed buffer is empty \n"));
+ return 0;
+ }
+
+ slen = strlen(str);
+ if (dlen * 2 < slen) {
+ WL_DBG((" destination buffer too short \n"));
+ return 0;
+ }
+
+ if (slen % 2) {
+ WL_DBG((" source buffer is of odd length \n"));
+ return 0;
+ }
+
+ for (count = 0; count < slen; count += 2) {
+ memcpy(tmp, ptr, 2);
+ hvalue = simple_strtol(tmp, &endp, 16);
+ if (*endp != '\0') {
+ WL_DBG((" non hexadecimal character encountered \n"));
+ return 0;
+ }
+ *data++ = (unsigned char)hvalue;
+ ptr += 2;
+ }
+
+ return (slen / 2);
+}
+
+/* There isn't a lot of sense in it, but you can transmit anything you like */
+static const struct ieee80211_txrx_stypes
+wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_ADHOC] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+ [NL80211_IFTYPE_STATION] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_AP] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+ [NL80211_IFTYPE_AP_VLAN] = {
+ /* copy AP */
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_P2P_GO] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ [NL80211_IFTYPE_P2P_DEVICE] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+#endif /* WL_CFG80211_P2P_DEV_IF */
+};
+
+static void swap_key_from_BE(struct wl_wsec_key *key)
+{
+ key->index = htod32(key->index);
+ key->len = htod32(key->len);
+ key->algo = htod32(key->algo);
+ key->flags = htod32(key->flags);
+ key->rxiv.hi = htod32(key->rxiv.hi);
+ key->rxiv.lo = htod16(key->rxiv.lo);
+ key->iv_initialized = htod32(key->iv_initialized);
+}
+
+static void swap_key_to_BE(struct wl_wsec_key *key)
+{
+ key->index = dtoh32(key->index);
+ key->len = dtoh32(key->len);
+ key->algo = dtoh32(key->algo);
+ key->flags = dtoh32(key->flags);
+ key->rxiv.hi = dtoh32(key->rxiv.hi);
+ key->rxiv.lo = dtoh16(key->rxiv.lo);
+ key->iv_initialized = dtoh32(key->iv_initialized);
+}
+
+/* Dump the contents of the encoded wps ie buffer and get pbc value */
+static void
+wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc)
+{
+ #define WPS_IE_FIXED_LEN 6
+ u16 len;
+ u8 *subel = NULL;
+ u16 subelt_id;
+ u16 subelt_len;
+ u16 val;
+ u8 *valptr = (uint8*) &val;
+ if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) {
+ WL_ERR(("invalid argument : NULL\n"));
+ return;
+ }
+ len = (u16)wps_ie[TLV_LEN_OFF];
+
+ if (len > wps_ie_len) {
+ WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len));
+ return;
+ }
+ WL_DBG(("wps_ie len=%d\n", len));
+ len -= 4; /* for the WPS IE's OUI, oui_type fields */
+ subel = wps_ie + WPS_IE_FIXED_LEN;
+ while (len >= 4) { /* must have attr id, attr len fields */
+ valptr[0] = *subel++;
+ valptr[1] = *subel++;
+ subelt_id = HTON16(val);
+
+ valptr[0] = *subel++;
+ valptr[1] = *subel++;
+ subelt_len = HTON16(val);
+
+ len -= 4; /* for the attr id, attr len fields */
+
+ if (len < subelt_len) {
+ WL_ERR(("not enough data, len %d, subelt_len %d\n", len,
+ subelt_len));
+ break;
+ }
+ len -= subelt_len; /* for the remaining fields in this attribute */
+
+ WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n",
+ subel, subelt_id, subelt_len));
+
+ if (subelt_id == WPS_ID_VERSION) {
+ WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel));
+ } else if (subelt_id == WPS_ID_REQ_TYPE) {
+ WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel));
+ } else if (subelt_id == WPS_ID_CONFIG_METHODS) {
+ valptr[0] = *subel;
+ valptr[1] = *(subel + 1);
+ WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val)));
+ } else if (subelt_id == WPS_ID_DEVICE_NAME) {
+ char devname[100];
+ int namelen = MIN(subelt_len, (sizeof(devname) - 1));
+
+ if (namelen) {
+ memcpy(devname, subel, namelen);
+ devname[namelen] = '\0';
+ /* Printing len as rx'ed in the IE */
+ WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
+ devname, subelt_len));
+ }
+ } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) {
+ valptr[0] = *subel;
+ valptr[1] = *(subel + 1);
+ WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val)));
+ *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false;
+ } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) {
+ valptr[0] = *subel;
+ valptr[1] = *(subel + 1);
+ WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val)));
+ valptr[0] = *(subel + 6);
+ valptr[1] = *(subel + 7);
+ WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val)));
+ } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) {
+ valptr[0] = *subel;
+ valptr[1] = *(subel + 1);
+ WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val)));
+ valptr[0] = *(subel + 6);
+ valptr[1] = *(subel + 7);
+ WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val)));
+ } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) {
+ valptr[0] = *subel;
+ valptr[1] = *(subel + 1);
+ WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS"
+ ": cat=%u\n", HTON16(val)));
+ } else {
+ WL_DBG((" unknown attr 0x%x\n", subelt_id));
+ }
+
+ subel += subelt_len;
+ }
+}
+
+s32 wl_set_tx_power(struct net_device *dev,
+ enum nl80211_tx_power_setting type, s32 dbm)
+{
+ s32 err = 0;
+ s32 disable = 0;
+ s32 txpwrqdbm;
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+#ifdef TEST_TX_POWER_CONTROL
+ char *tmppwr_str;
+#endif /* TEST_TX_POWER_CONTROL */
+
+ /* Make sure radio is off or on as far as software is concerned */
+ disable = WL_RADIO_SW_DISABLE << 16;
+ disable = htod32(disable);
+ err = wldev_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable), true);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
+ return err;
+ }
+
+ if (dbm > 0xffff)
+ dbm = 0xffff;
+ txpwrqdbm = dbm * 4;
+
+ err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm,
+ sizeof(txpwrqdbm), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
+ &cfg->ioctl_buf_sync);
+
+ if (unlikely(err))
+ WL_ERR(("qtxpower error (%d)\n", err));
+ else
+ WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm));
+
+ return err;
+}
+
+s32 wl_get_tx_power(struct net_device *dev, s32 *dbm)
+{
+ s32 err = 0;
+ s32 txpwrdbm;
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+
+ err = wldev_iovar_getint(dev, "qtxpower", &txpwrdbm);
+ err = wldev_iovar_getbuf_bsscfg(dev, "qtxpower",
+ NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+
+ memcpy(&txpwrdbm, cfg->ioctl_buf, sizeof(txpwrdbm));
+ txpwrdbm = dtoh32(txpwrdbm);
+ *dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 4;
+
+ WL_INFO(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm));
+
+ return err;
+}
+
+#ifdef P2PONEINT
+chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
+#else
+static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
+#endif
+{
+ chanspec_t chspec;
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
+ struct ether_addr bssid;
+ struct wl_bss_info *bss = NULL;
+
+ if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) {
+ int chspc;
+ /* STA interface is not associated. So start the new interface on a temp
+ * channel . Later proper channel will be applied by the above framework
+ * via set_channel (cfg80211 API).
+ */
+ WL_DBG(("Not associated. Return first channel from supported channel list. \n"));
+ err = wldev_iovar_getint(dev, "chanspec", &chspc);
+ if (!err) {
+ return chspc;
+ } else {
+
+ return wl_ch_host_to_driver(WL_P2P_TEMP_CHAN);
+ }
+ }
+
+ *(u32 *) cfg->extra_buf = htod32(WL_EXTRA_BUF_MAX);
+ if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, cfg->extra_buf,
+ WL_EXTRA_BUF_MAX, false))) {
+ WL_ERR(("Failed to get associated bss info, use temp channel \n"));
+ chspec = wl_ch_host_to_driver(WL_P2P_TEMP_CHAN);
+ }
+ else {
+ bss = (struct wl_bss_info *) (cfg->extra_buf + 4);
+ chspec = bss->chanspec;
+
+ WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec));
+ }
+ return chspec;
+}
+
+static bcm_struct_cfgdev *
+wl_cfg80211_add_monitor_if(char *name)
+{
+#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
+ WL_INFO(("wl_cfg80211_add_monitor_if: No more support monitor interface\n"));
+ return ERR_PTR(-EOPNOTSUPP);
+#else
+ struct net_device* ndev = NULL;
+
+ dhd_add_monitor(name, &ndev);
+ WL_INFO(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
+ return ndev_to_cfgdev(ndev);
+#endif /* WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF */
+}
+
+static bcm_struct_cfgdev *
+wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ const char *name,
+#else
+ char *name,
+#endif /* WL_CFG80211_P2P_DEV_IF */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
+ unsigned char name_assign_type,
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ s32 err;
+ s32 timeout = -1;
+ s32 wlif_type = -1;
+ s32 mode = 0;
+ s32 val = 0;
+ s32 dhd_mode = 0;
+ chanspec_t chspec;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *primary_ndev;
+ struct net_device *new_ndev;
+ struct ether_addr primary_mac;
+#ifdef PROP_TXSTATUS_VSDB
+ s32 up = 1;
+ dhd_pub_t *dhd;
+ bool enabled;
+#endif /* PROP_TXSTATUS_VSDB */
+#ifdef WL_VIRTUAL_APSTA
+ bcm_struct_cfgdev *new_cfgdev;
+#endif /* WL_VIRTUAL_APSTA */
+
+ if (!cfg)
+ return ERR_PTR(-EINVAL);
+
+#ifdef PROP_TXSTATUS_VSDB
+ dhd = (dhd_pub_t *)(cfg->pub);
+#endif /* PROP_TXSTATUS_VSDB */
+
+
+ /* Use primary I/F for sending cmds down to firmware */
+ primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+
+ if (unlikely(!wl_get_drv_status(cfg, READY, primary_ndev))) {
+ WL_ERR(("device is not ready\n"));
+ return ERR_PTR(-ENODEV);
+ }
+
+ WL_DBG(("if name: %s, type: %d\n", name, type));
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MESH_POINT:
+ WL_ERR(("Unsupported interface type\n"));
+ mode = WL_MODE_IBSS;
+ return NULL;
+ case NL80211_IFTYPE_MONITOR:
+ return wl_cfg80211_add_monitor_if((char *)name);
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ case NL80211_IFTYPE_P2P_DEVICE:
+ return wl_cfgp2p_add_p2p_disc_if(cfg);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ case NL80211_IFTYPE_STATION:
+#ifdef WL_VIRTUAL_APSTA
+ if (!name) {
+ WL_ERR(("Interface name not provided \n"));
+ return ERR_PTR(-ENODEV);
+ }
+
+ if (wl_cfgp2p_vif_created(cfg)) {
+ WL_ERR(("Could not create new iface."
+ "Already one p2p interface is running"));
+ return ERR_PTR(-ENODEV);
+ }
+ new_cfgdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
+ NL80211_IFTYPE_STATION, NULL, name);
+ if (!new_cfgdev)
+ return ERR_PTR(-ENOMEM);
+ else
+ return new_cfgdev;
+#endif /* WL_VIRTUAL_APSTA */
+ case NL80211_IFTYPE_P2P_CLIENT:
+ wlif_type = WL_P2P_IF_CLIENT;
+ mode = WL_MODE_BSS;
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_AP:
+ WL_DBG(("Add virtual interface for AP (%d)\n", type));
+ wlif_type = WL_P2P_IF_GO;
+ mode = WL_MODE_AP;
+ break;
+ default:
+ WL_ERR(("Unsupported interface type\n"));
+ return NULL;
+ break;
+ }
+
+ if (!name) {
+ WL_ERR(("name is NULL\n"));
+ return NULL;
+ }
+ if (cfg->p2p_supported && (wlif_type != -1)) {
+ ASSERT(cfg->p2p); /* ensure expectation of p2p initialization */
+
+#ifdef PROP_TXSTATUS_VSDB
+ if (!dhd)
+ return ERR_PTR(-ENODEV);
+#endif /* PROP_TXSTATUS_VSDB */
+ if (!cfg->p2p)
+ return ERR_PTR(-ENODEV);
+
+ if (cfg->p2p && !cfg->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
+ p2p_on(cfg) = true;
+ wl_cfgp2p_set_firm_p2p(cfg);
+ wl_cfgp2p_init_discovery(cfg);
+ get_primary_mac(cfg, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(&primary_mac,
+ &cfg->p2p->dev_addr, &cfg->p2p->int_addr);
+ }
+
+ memset(cfg->p2p->vir_ifname, 0, IFNAMSIZ);
+ strncpy(cfg->p2p->vir_ifname, name, IFNAMSIZ - 1);
+
+ wl_cfg80211_scan_abort(cfg);
+#ifdef PROP_TXSTATUS_VSDB
+ if (!cfg->wlfc_on && !disable_proptx) {
+ dhd_wlfc_get_enable(dhd, &enabled);
+ if (!enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
+ dhd->op_mode != DHD_FLAG_IBSS_MODE) {
+ dhd_wlfc_init(dhd);
+ err = wldev_ioctl(primary_ndev, WLC_UP, &up, sizeof(s32), true);
+ if (err < 0)
+ WL_ERR(("WLC_UP return err:%d\n", err));
+ }
+ cfg->wlfc_on = true;
+ }
+#endif /* PROP_TXSTATUS_VSDB */
+
+ /* In concurrency case, STA may be already associated in a particular channel.
+ * so retrieve the current channel of primary interface and then start the virtual
+ * interface on that.
+ */
+ chspec = wl_cfg80211_get_shared_freq(wiphy);
+
+ /* For P2P mode, use P2P-specific driver features to create the
+ * bss: "cfg p2p_ifadd"
+ */
+ wl_set_p2p_status(cfg, IF_ADDING);
+ memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
+ if (wlif_type == WL_P2P_IF_GO)
+ wldev_iovar_setint(primary_ndev, "mpc", 0);
+ err = wl_cfgp2p_ifadd(cfg, &cfg->p2p->int_addr, htod32(wlif_type), chspec);
+ if (unlikely(err)) {
+ wl_clr_p2p_status(cfg, IF_ADDING);
+ WL_ERR((" virtual iface add failed (%d) \n", err));
+ return ERR_PTR(-ENOMEM);
+ }
+
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+ (wl_get_p2p_status(cfg, IF_ADDING) == false),
+ msecs_to_jiffies(MAX_WAIT_TIME));
+ if (timeout == 0) {
+ WL_ERR(("%d timeout waiting for IF_ADD.\n", __LINE__));
+ }
+
+ if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) {
+ struct wireless_dev *vwdev;
+ int pm_mode = PM_ENABLE;
+ wl_if_event_info *event = &cfg->if_event_info;
+
+ /* IF_ADD event has come back, we can proceed to to register
+ * the new interface now, use the interface name provided by caller (thus
+ * ignore the one from wlc)
+ */
+ strncpy(cfg->if_event_info.name, name, IFNAMSIZ - 1);
+ new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, cfg->p2p->vir_ifname,
+ event->mac, event->bssidx, event->name);
+ if (new_ndev == NULL)
+ goto fail;
+
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) = new_ndev;
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) = event->bssidx;
+ vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
+ if (unlikely(!vwdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ goto fail;
+ }
+ vwdev->wiphy = cfg->wdev->wiphy;
+ WL_INFO(("virtual interface(%s) is created\n", cfg->p2p->vir_ifname));
+ vwdev->iftype = type;
+ vwdev->netdev = new_ndev;
+ new_ndev->ieee80211_ptr = vwdev;
+ SET_NETDEV_DEV(new_ndev, wiphy_dev(vwdev->wiphy));
+ wl_set_drv_status(cfg, READY, new_ndev);
+ wl_set_mode_by_netdev(cfg, new_ndev, mode);
+
+ if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) {
+ wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev);
+ goto fail;
+ }
+ wl_alloc_netinfo(cfg, new_ndev, vwdev, mode, pm_mode, event->bssidx);
+ val = 1;
+ /* Disable firmware roaming for P2P interface */
+ wldev_iovar_setint(new_ndev, "roam_off", val);
+
+ if (mode != WL_MODE_AP)
+ wldev_iovar_setint(new_ndev, "buf_key_b4_m4", 1);
+
+ WL_ERR((" virtual interface(%s) is "
+ "created net attach done\n", cfg->p2p->vir_ifname));
+ if (mode == WL_MODE_AP)
+ wl_set_drv_status(cfg, CONNECTED, new_ndev);
+ if (type == NL80211_IFTYPE_P2P_CLIENT)
+ dhd_mode = DHD_FLAG_P2P_GC_MODE;
+ else if (type == NL80211_IFTYPE_P2P_GO)
+ dhd_mode = DHD_FLAG_P2P_GO_MODE;
+ DNGL_FUNC(dhd_cfg80211_set_p2p_info, (cfg, dhd_mode));
+ /* reinitialize completion to clear previous count */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
+ INIT_COMPLETION(cfg->iface_disable);
+#else
+ init_completion(&cfg->iface_disable);
+#endif
+ return ndev_to_cfgdev(new_ndev);
+ } else {
+ wl_clr_p2p_status(cfg, IF_ADDING);
+ WL_ERR((" virtual interface(%s) is not created \n", cfg->p2p->vir_ifname));
+
+ WL_ERR(("left timeout : %d\n", timeout));
+ WL_ERR(("IF_ADDING status : %d\n", wl_get_p2p_status(cfg, IF_ADDING)));
+ WL_ERR(("event valid : %d\n", cfg->if_event_info.valid));
+
+ wl_clr_p2p_status(cfg, GO_NEG_PHASE);
+ wl_set_p2p_status(cfg, IF_DELETING);
+
+ err = wl_cfgp2p_ifdel(cfg, &cfg->p2p->int_addr);
+ if (err == BCME_OK) {
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+ (wl_get_p2p_status(cfg, IF_DELETING) == false),
+ msecs_to_jiffies(MAX_WAIT_TIME));
+ if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
+ cfg->if_event_info.valid) {
+ WL_ERR(("IFDEL operation done\n"));
+ } else {
+ WL_ERR(("IFDEL didn't complete properly\n"));
+ err = BCME_ERROR;
+ }
+ }
+ if (err != BCME_OK) {
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+
+ WL_ERR(("p2p_ifdel failed, error %d, sent HANG event to %s\n",
+ err, ndev->name));
+ net_os_send_hang_message(ndev);
+ }
+
+ memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ);
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) = -1;
+#ifdef PROP_TXSTATUS_VSDB
+ dhd_wlfc_get_enable(dhd, &enabled);
+ if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
+ dhd->op_mode != DHD_FLAG_IBSS_MODE) {
+ dhd_wlfc_deinit(dhd);
+ cfg->wlfc_on = false;
+ }
+#endif /* PROP_TXSTATUS_VSDB */
+ }
+ }
+
+fail:
+ if (wlif_type == WL_P2P_IF_GO)
+ wldev_iovar_setint(primary_ndev, "mpc", 1);
+ return ERR_PTR(-ENODEV);
+}
+
+static s32
+wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
+{
+ struct net_device *dev = NULL;
+ struct ether_addr p2p_mac;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 timeout = -1;
+ s32 ret = 0;
+ s32 index = -1;
+#ifdef CUSTOM_SET_CPUCORE
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+#endif /* CUSTOM_SET_CPUCORE */
+ WL_DBG(("Enter\n"));
+
+#ifdef CUSTOM_SET_CPUCORE
+ dhd->chan_isvht80 &= ~DHD_FLAG_P2P_MODE;
+ if (!(dhd->chan_isvht80))
+ dhd_set_cpucore(dhd, FALSE);
+#endif /* CUSTOM_SET_CPUCORE */
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
+ return wl_cfgp2p_del_p2p_disc_if(cfgdev, cfg);
+ }
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+#ifdef WL_VIRTUAL_APSTA
+ if (cfgdev == cfg->bss_cfgdev) {
+ return wl_cfg80211_del_iface(wiphy, cfgdev);
+ }
+#endif /* WL_VIRTUAL_APSTA */
+ if ((index = wl_get_bssidx_by_wdev(cfg, ndev_to_wdev(dev))) < 0) {
+ WL_ERR(("Find p2p index from wdev failed\n"));
+ return BCME_ERROR;
+ }
+ if (cfg->p2p_supported) {
+ memcpy(p2p_mac.octet, cfg->p2p->int_addr.octet, ETHER_ADDR_LEN);
+
+ /* Clear GO_NEG_PHASE bit to take care of GO-NEG-FAIL cases
+ */
+ WL_DBG(("P2P: GO_NEG_PHASE status cleared "));
+ wl_clr_p2p_status(cfg, GO_NEG_PHASE);
+ if (wl_cfgp2p_vif_created(cfg)) {
+ if (wl_get_drv_status(cfg, SCANNING, dev)) {
+ wl_notify_escan_complete(cfg, dev, true, true);
+ }
+ wldev_iovar_setint(dev, "mpc", 1);
+ /* Delete pm_enable_work */
+ wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL);
+
+ /* for GC */
+ if (wl_get_drv_status(cfg, DISCONNECTING, dev) &&
+ (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP)) {
+ WL_ERR(("Wait for Link Down event for GC !\n"));
+ wait_for_completion_timeout
+ (&cfg->iface_disable, msecs_to_jiffies(500));
+ }
+
+ memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
+ wl_set_p2p_status(cfg, IF_DELETING);
+ DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (cfg));
+
+ /* for GO */
+ if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false);
+ /* disable interface before bsscfg free */
+ ret = wl_cfgp2p_ifdisable(cfg, &p2p_mac);
+ /* if fw doesn't support "ifdis",
+ do not wait for link down of ap mode
+ */
+ if (ret == 0) {
+ WL_ERR(("Wait for Link Down event for GO !!!\n"));
+ wait_for_completion_timeout(&cfg->iface_disable,
+ msecs_to_jiffies(500));
+ } else if (ret != BCME_UNSUPPORTED) {
+ msleep(300);
+ }
+ }
+ wl_cfg80211_clear_per_bss_ies(cfg, index);
+
+ if (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP)
+ wldev_iovar_setint(dev, "buf_key_b4_m4", 0);
+
+ /* delete interface after link down */
+ ret = wl_cfgp2p_ifdel(cfg, &p2p_mac);
+
+ if (ret != BCME_OK) {
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+
+ WL_ERR(("p2p_ifdel failed, error %d, sent HANG event to %s\n",
+ ret, ndev->name));
+ #if defined(BCMDONGLEHOST) && defined(OEM_ANDROID)
+ net_os_send_hang_message(ndev);
+ #endif
+ } else {
+ /* Wait for IF_DEL operation to be finished */
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+ (wl_get_p2p_status(cfg, IF_DELETING) == false),
+ msecs_to_jiffies(MAX_WAIT_TIME));
+ if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
+ cfg->if_event_info.valid) {
+
+ WL_DBG(("IFDEL operation done\n"));
+ wl_cfg80211_handle_ifdel(cfg, &cfg->if_event_info, dev);
+ } else {
+ WL_ERR(("IFDEL didn't complete properly\n"));
+ }
+ }
+
+ ret = dhd_del_monitor(dev);
+ if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
+ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL((dhd_pub_t *)(cfg->pub));
+ }
+ }
+ }
+ return ret;
+}
+
+static s32
+wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ s32 ap = 0;
+ s32 infra = 0;
+ s32 ibss = 0;
+ s32 wlif_type;
+ s32 mode = 0;
+ s32 err = BCME_OK;
+ chanspec_t chspec;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+ WL_DBG(("Enter type %d\n", type));
+ switch (type) {
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MESH_POINT:
+ ap = 1;
+ WL_ERR(("type (%d) : currently we do not support this type\n",
+ type));
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ mode = WL_MODE_IBSS;
+ ibss = 1;
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ mode = WL_MODE_BSS;
+ infra = 1;
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_P2P_GO:
+ mode = WL_MODE_AP;
+ ap = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (!dhd)
+ return -EINVAL;
+
+ /* If any scan is going on, abort it */
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ int wait_cnt = MAX_SCAN_ABORT_WAIT_CNT;
+ WL_ERR(("Scan in progress. Aborting the scan!\n"));
+ wl_cfg80211_scan_abort(cfg);
+ while (wl_get_drv_status_all(cfg, SCANNING) && wait_cnt) {
+ WL_DBG(("Waiting for SCANNING terminated, wait_cnt: %d\n", wait_cnt));
+ wait_cnt--;
+ OSL_SLEEP(WAIT_SCAN_ABORT_OSL_SLEEP_TIME);
+ }
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
+ }
+ }
+
+ if (ap) {
+ wl_set_mode_by_netdev(cfg, ndev, mode);
+ if (is_p2p_group_iface(ndev->ieee80211_ptr) &&
+ cfg->p2p_supported && wl_cfgp2p_vif_created(cfg)) {
+ WL_DBG(("p2p_vif_created p2p_on (%d)\n", p2p_on(cfg)));
+ wldev_iovar_setint(ndev, "mpc", 0);
+ wl_notify_escan_complete(cfg, ndev, true, true);
+
+ /* In concurrency case, STA may be already associated in a particular
+ * channel. so retrieve the current channel of primary interface and
+ * then start the virtual interface on that.
+ */
+ chspec = wl_cfg80211_get_shared_freq(wiphy);
+
+ wlif_type = WL_P2P_IF_GO;
+ WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n",
+ ndev->name, ap, infra, type));
+ wl_set_p2p_status(cfg, IF_CHANGING);
+ wl_clr_p2p_status(cfg, IF_CHANGED);
+ wl_cfgp2p_ifchange(cfg, &cfg->p2p->int_addr, htod32(wlif_type), chspec);
+ wait_event_interruptible_timeout(cfg->netif_change_event,
+ (wl_get_p2p_status(cfg, IF_CHANGED) == true),
+ msecs_to_jiffies(MAX_WAIT_TIME));
+ wl_set_mode_by_netdev(cfg, ndev, mode);
+ dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE;
+ dhd->op_mode |= DHD_FLAG_P2P_GO_MODE;
+ wl_clr_p2p_status(cfg, IF_CHANGING);
+ wl_clr_p2p_status(cfg, IF_CHANGED);
+ if (mode == WL_MODE_AP)
+ wl_set_drv_status(cfg, CONNECTED, ndev);
+ } else if (((ndev == bcmcfg_to_prmry_ndev(cfg)) ||
+ (ndev == ((struct net_device *)cfgdev_to_wlc_ndev(cfg->bss_cfgdev, cfg)))) &&
+ !wl_get_drv_status(cfg, AP_CREATED, ndev)) {
+ dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
+ wl_set_drv_status(cfg, AP_CREATING, ndev);
+ } else {
+ WL_ERR(("Cannot change the interface for GO or SOFTAP\n"));
+ return -EINVAL;
+ }
+ } else {
+ WL_DBG(("Change_virtual_iface for transition from GO/AP to client/STA"));
+#ifdef P2PONEINT /* Cindy: Compare the change with add_virtual_iface */
+ wl_set_mode_by_netdev(cfg, ndev, mode);
+ if (cfg->p2p_supported && wl_cfgp2p_vif_created(cfg)) {
+ WL_DBG(("p2p_vif_created p2p_on (%d)\n", p2p_on(cfg)));
+ wldev_iovar_setint(ndev, "mpc", 0);
+ wl_notify_escan_complete(cfg, ndev, true, true);
+
+ /* In concurrency case, STA may be already associated in a particular
+ * channel. so retrieve the current channel of primary interface and
+ * then start the virtual interface on that.
+ */
+ chspec = wl_cfg80211_get_shared_freq(wiphy);
+
+ wlif_type = WL_P2P_IF_CLIENT;
+ WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d) chspec 0x%x \n",
+ ndev->name, ap, infra, type, chspec));
+ wl_set_p2p_status(cfg, IF_CHANGING);
+ wl_clr_p2p_status(cfg, IF_CHANGED);
+ wl_cfgp2p_ifchange(cfg, &cfg->p2p->int_addr, htod32(wlif_type), chspec);
+ wait_event_interruptible_timeout(cfg->netif_change_event,
+ (wl_get_p2p_status(cfg, IF_CHANGED) == true),
+ msecs_to_jiffies(MAX_WAIT_TIME));
+ wl_set_mode_by_netdev(cfg, ndev, mode);
+ dhd->op_mode |= DHD_FLAG_P2P_GC_MODE;
+ dhd->op_mode &= ~DHD_FLAG_P2P_GO_MODE;
+ wl_clr_p2p_status(cfg, IF_CHANGING);
+ wl_clr_p2p_status(cfg, IF_CHANGED);
+
+#define INIT_IE(IE_TYPE, BSS_TYPE) \
+ do { \
+ memset(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \
+ sizeof(wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \
+ wl_to_p2p_bss_saved_ie(cfg, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \
+ } while (0);
+
+ INIT_IE(probe_req, P2PAPI_BSSCFG_CONNECTION);
+ INIT_IE(probe_res, P2PAPI_BSSCFG_CONNECTION);
+ INIT_IE(assoc_req, P2PAPI_BSSCFG_CONNECTION);
+ INIT_IE(assoc_res, P2PAPI_BSSCFG_CONNECTION);
+ INIT_IE(beacon, P2PAPI_BSSCFG_CONNECTION);
+ }
+#endif /* P2PONEINT */
+ }
+
+ if (ibss || infra) {
+ wl_set_mode_by_netdev(cfg, ndev, mode);
+ err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(s32), true);
+ if (err < 0) {
+ WL_ERR(("SET Adhoc error %d\n", err));
+ return -EINVAL;
+ }
+ }
+
+ ndev->ieee80211_ptr->iftype = type;
+ return 0;
+}
+
+s32
+wl_cfg80211_notify_ifadd(int ifidx, char *name, uint8 *mac, uint8 bssidx)
+{
+ bool ifadd_expected = FALSE;
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+
+ /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd")
+ * redirect the IF_ADD event to ifchange as it is not a real "new" interface
+ */
+ if (wl_get_p2p_status(cfg, IF_CHANGING))
+ return wl_cfg80211_notify_ifchange(ifidx, name, mac, bssidx);
+
+ /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */
+ if (wl_get_p2p_status(cfg, IF_ADDING)) {
+ ifadd_expected = TRUE;
+ wl_clr_p2p_status(cfg, IF_ADDING);
+ } else if (cfg->bss_pending_op) {
+ ifadd_expected = TRUE;
+ cfg->bss_pending_op = FALSE;
+ }
+
+ if (ifadd_expected) {
+ wl_if_event_info *if_event_info = &cfg->if_event_info;
+
+ if_event_info->valid = TRUE;
+ if_event_info->ifidx = ifidx;
+ if_event_info->bssidx = bssidx;
+ strncpy(if_event_info->name, name, IFNAMSIZ);
+ if_event_info->name[IFNAMSIZ] = '\0';
+ if (mac)
+ memcpy(if_event_info->mac, mac, ETHER_ADDR_LEN);
+
+ wake_up_interruptible(&cfg->netif_change_event);
+ return BCME_OK;
+ }
+
+ return BCME_ERROR;
+}
+
+s32
+wl_cfg80211_notify_ifdel(int ifidx, char *name, uint8 *mac, uint8 bssidx)
+{
+ bool ifdel_expected = FALSE;
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ wl_if_event_info *if_event_info = &cfg->if_event_info;
+
+ WL_INFO(("%d: Enter %s\n", __LINE__, name));
+ if (wl_get_p2p_status(cfg, IF_DELETING)) {
+ ifdel_expected = TRUE;
+ wl_clr_p2p_status(cfg, IF_DELETING);
+ } else if (cfg->bss_pending_op) {
+ ifdel_expected = TRUE;
+ cfg->bss_pending_op = FALSE;
+ }
+
+ if (ifdel_expected) {
+ if_event_info->valid = TRUE;
+ if_event_info->ifidx = ifidx;
+ if_event_info->bssidx = bssidx;
+ wake_up_interruptible(&cfg->netif_change_event);
+ return BCME_OK;
+ }
+
+ return BCME_ERROR;
+}
+
+s32
+wl_cfg80211_notify_ifchange(int ifidx, char *name, uint8 *mac, uint8 bssidx)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+
+ if (wl_get_p2p_status(cfg, IF_CHANGING)) {
+ wl_set_p2p_status(cfg, IF_CHANGED);
+ wake_up_interruptible(&cfg->netif_change_event);
+ return BCME_OK;
+ }
+
+ return BCME_ERROR;
+}
+
+static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *if_event_info,
+ struct net_device* ndev)
+{
+ s32 type = -1;
+ s32 bssidx = -1;
+#ifdef PROP_TXSTATUS_VSDB
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+ bool enabled;
+#endif /* PROP_TXSTATUS_VSDB */
+
+ bssidx = if_event_info->bssidx;
+ if ((bssidx != wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION)) &&
+ (bssidx != cfg->cfgdev_bssidx)) {
+ WL_ERR(("got IF_DEL for if %d, not owned by cfg driver\n", bssidx));
+ return BCME_ERROR;
+ }
+
+ if (p2p_is_on(cfg) && wl_cfgp2p_vif_created(cfg)) {
+
+ if (cfg->scan_request && (cfg->escan_info.ndev == ndev)) {
+ /* Abort any pending scan requests */
+ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+ WL_DBG(("ESCAN COMPLETED\n"));
+ wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, false);
+ }
+
+ memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ);
+ if (wl_cfgp2p_find_type(cfg, bssidx, &type) != BCME_OK) {
+ WL_ERR(("Find p2p type from bssidx(%d) failed\n", bssidx));
+ return BCME_ERROR;
+ }
+ wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, type));
+ wl_to_p2p_bss_ndev(cfg, type) = NULL;
+ wl_to_p2p_bss_bssidx(cfg, type) = WL_INVALID;
+
+#ifdef PROP_TXSTATUS_VSDB
+ dhd_wlfc_get_enable(dhd, &enabled);
+ if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
+ dhd->op_mode != DHD_FLAG_IBSS_MODE) {
+ dhd_wlfc_deinit(dhd);
+ cfg->wlfc_on = false;
+ }
+#endif /* PROP_TXSTATUS_VSDB */
+ }
+
+ dhd_net_if_lock(ndev);
+ wl_cfg80211_remove_if(cfg, if_event_info->ifidx, ndev);
+ dhd_net_if_unlock(ndev);
+
+ return BCME_OK;
+}
+
+/* Find listen channel */
+static s32 wl_find_listen_channel(struct bcm_cfg80211 *cfg,
+ const u8 *ie, u32 ie_len)
+{
+ wifi_p2p_ie_t *p2p_ie;
+ u8 *end, *pos;
+ s32 listen_channel;
+
+ pos = (u8 *)ie;
+ p2p_ie = wl_cfgp2p_find_p2pie(pos, ie_len);
+
+ if (p2p_ie == NULL)
+ return 0;
+
+ pos = p2p_ie->subelts;
+ end = p2p_ie->subelts + (p2p_ie->len - 4);
+
+ CFGP2P_DBG((" found p2p ie ! lenth %d \n",
+ p2p_ie->len));
+
+ while (pos < end) {
+ uint16 attr_len;
+ if (pos + 2 >= end) {
+ CFGP2P_DBG((" -- Invalid P2P attribute"));
+ return 0;
+ }
+ attr_len = ((uint16) (((pos + 1)[1] << 8) | (pos + 1)[0]));
+
+ if (pos + 3 + attr_len > end) {
+ CFGP2P_DBG(("P2P: Attribute underflow "
+ "(len=%u left=%d)",
+ attr_len, (int) (end - pos - 3)));
+ return 0;
+ }
+
+ /* if Listen Channel att id is 6 and the vailue is valid,
+ * return the listen channel
+ */
+ if (pos[0] == 6) {
+ /* listen channel subel length format
+ * 1(id) + 2(len) + 3(country) + 1(op. class) + 1(chan num)
+ */
+ listen_channel = pos[1 + 2 + 3 + 1];
+
+ if (listen_channel == SOCIAL_CHAN_1 ||
+ listen_channel == SOCIAL_CHAN_2 ||
+ listen_channel == SOCIAL_CHAN_3) {
+ CFGP2P_DBG((" Found my Listen Channel %d \n", listen_channel));
+ return listen_channel;
+ }
+ }
+ pos += 3 + attr_len;
+ }
+ return 0;
+}
+
+static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request)
+{
+ u32 n_ssids;
+ u32 n_channels;
+ u16 channel;
+ chanspec_t chanspec;
+ s32 i = 0, j = 0, offset;
+ char *ptr;
+ wlc_ssid_t ssid;
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+
+ memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
+ params->bss_type = DOT11_BSSTYPE_ANY;
+ params->scan_type = 0;
+ params->nprobes = -1;
+ params->active_time = -1;
+ params->passive_time = -1;
+ params->home_time = -1;
+ params->channel_num = 0;
+ memset(&params->ssid, 0, sizeof(wlc_ssid_t));
+
+ WL_SCAN(("Preparing Scan request\n"));
+ WL_SCAN(("nprobes=%d\n", params->nprobes));
+ WL_SCAN(("active_time=%d\n", params->active_time));
+ WL_SCAN(("passive_time=%d\n", params->passive_time));
+ WL_SCAN(("home_time=%d\n", params->home_time));
+ WL_SCAN(("scan_type=%d\n", params->scan_type));
+
+ params->nprobes = htod32(params->nprobes);
+ params->active_time = htod32(params->active_time);
+ params->passive_time = htod32(params->passive_time);
+ params->home_time = htod32(params->home_time);
+
+ /* if request is null just exit so it will be all channel broadcast scan */
+ if (!request)
+ return;
+
+ n_ssids = request->n_ssids;
+ n_channels = request->n_channels;
+
+ /* Copy channel array if applicable */
+ WL_SCAN(("### List of channelspecs to scan ###\n"));
+ if (n_channels > 0) {
+ for (i = 0; i < n_channels; i++) {
+ chanspec = 0;
+ channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq);
+ /* SKIP DFS channels for Secondary interface */
+ if ((cfg->escan_info.ndev != bcmcfg_to_prmry_ndev(cfg)) &&
+ (request->channels[i]->flags &
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
+ (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN)))
+#else
+ (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR)))
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) */
+ continue;
+
+ if (request->channels[i]->band == NL80211_BAND_2GHZ) {
+ chanspec |= WL_CHANSPEC_BAND_2G;
+ } else {
+ chanspec |= WL_CHANSPEC_BAND_5G;
+ }
+
+ chanspec |= WL_CHANSPEC_BW_20;
+ chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+
+ params->channel_list[j] = channel;
+ params->channel_list[j] &= WL_CHANSPEC_CHAN_MASK;
+ params->channel_list[j] |= chanspec;
+ WL_SCAN(("Chan : %d, Channel spec: %x \n",
+ channel, params->channel_list[j]));
+ params->channel_list[j] = wl_chspec_host_to_driver(params->channel_list[j]);
+ j++;
+ }
+ } else {
+ WL_SCAN(("Scanning all channels\n"));
+ }
+ n_channels = j;
+ /* Copy ssid array if applicable */
+ WL_SCAN(("### List of SSIDs to scan ###\n"));
+ if (n_ssids > 0) {
+ offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16);
+ offset = roundup(offset, sizeof(u32));
+ ptr = (char*)params + offset;
+ for (i = 0; i < n_ssids; i++) {
+ memset(&ssid, 0, sizeof(wlc_ssid_t));
+ ssid.SSID_len = MIN(request->ssids[i].ssid_len, DOT11_MAX_SSID_LEN);
+ memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len);
+ if (!ssid.SSID_len)
+ WL_SCAN(("%d: Broadcast scan\n", i));
+ else
+ WL_SCAN(("%d: scan for %s size =%d\n", i,
+ ssid.SSID, ssid.SSID_len));
+ memcpy(ptr, &ssid, sizeof(wlc_ssid_t));
+ ptr += sizeof(wlc_ssid_t);
+ }
+ } else {
+ WL_SCAN(("Broadcast scan\n"));
+ }
+ /* Adding mask to channel numbers */
+ params->channel_num =
+ htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) |
+ (n_channels & WL_SCAN_PARAMS_COUNT_MASK));
+
+ if (n_channels == 1) {
+ params->active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS);
+ params->nprobes = htod32(params->active_time / WL_SCAN_JOIN_PROBE_INTERVAL_MS);
+ }
+}
+
+static s32
+wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size)
+{
+ wl_uint32_list_t *list;
+ s32 err = BCME_OK;
+ if (valid_chan_list == NULL || size <= 0)
+ return -ENOMEM;
+
+ memset(valid_chan_list, 0, size);
+ list = (wl_uint32_list_t *)(void *) valid_chan_list;
+ list->count = htod32(WL_NUMCHANNELS);
+ err = wldev_ioctl(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size, false);
+ if (err != 0) {
+ WL_ERR(("get channels failed with %d\n", err));
+ }
+
+ return err;
+}
+
+#if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME)
+#define FIRST_SCAN_ACTIVE_DWELL_TIME_MS 40
+bool g_first_broadcast_scan = TRUE;
+#endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */
+
+static s32
+wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ struct cfg80211_scan_request *request, uint16 action)
+{
+ s32 err = BCME_OK;
+ u32 n_channels;
+ u32 n_ssids;
+ s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params));
+ wl_escan_params_t *params = NULL;
+ u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)];
+ u32 num_chans = 0;
+ s32 channel;
+ u32 n_valid_chan;
+ s32 search_state = WL_P2P_DISC_ST_SCAN;
+ u32 i, j, n_nodfs = 0;
+ u16 *default_chan_list = NULL;
+ wl_uint32_list_t *list;
+ struct net_device *dev = NULL;
+#if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME)
+ bool is_first_init_2g_scan = false;
+#endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */
+ p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_PURPOSE_MIN;
+
+ WL_DBG(("Enter \n"));
+
+ /* scan request can come with empty request : perform all default scan */
+ if (!cfg) {
+ err = -EINVAL;
+ goto exit;
+ }
+ if (!cfg->p2p_supported || !p2p_scan(cfg)) {
+ /* LEGACY SCAN TRIGGER */
+ WL_SCAN((" LEGACY E-SCAN START\n"));
+
+#if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME)
+ if (!request) {
+ err = -EINVAL;
+ goto exit;
+ }
+ if (ndev == bcmcfg_to_prmry_ndev(cfg) && g_first_broadcast_scan == true) {
+#ifdef USE_INITIAL_2G_SCAN
+ struct ieee80211_channel tmp_channel_list[CH_MAX_2G_CHANNEL];
+ /* allow one 5G channel to add previous connected channel in 5G */
+ bool allow_one_5g_channel = TRUE;
+ j = 0;
+ for (i = 0; i < request->n_channels; i++) {
+ int tmp_chan = ieee80211_frequency_to_channel
+ (request->channels[i]->center_freq);
+ if (tmp_chan > CH_MAX_2G_CHANNEL) {
+ if (allow_one_5g_channel)
+ allow_one_5g_channel = FALSE;
+ else
+ continue;
+ }
+ if (j >= CH_MAX_2G_CHANNEL) {
+ WL_ERR(("Index %d exceeds max 2.4GHz channels %d"
+ " and previous 5G connected channel\n",
+ j, CH_MAX_2G_CHANNEL));
+ break;
+ }
+ bcopy(request->channels[i], &tmp_channel_list[j],
+ sizeof(struct ieee80211_channel));
+ WL_SCAN(("channel of request->channels[%d]=%d\n", i, tmp_chan));
+ j++;
+ }
+ if ((j > 0) && (j <= CH_MAX_2G_CHANNEL)) {
+ for (i = 0; i < j; i++)
+ bcopy(&tmp_channel_list[i], request->channels[i],
+ sizeof(struct ieee80211_channel));
+
+ request->n_channels = j;
+ is_first_init_2g_scan = true;
+ }
+ else
+ WL_ERR(("Invalid number of 2.4GHz channels %d\n", j));
+
+ WL_SCAN(("request->n_channels=%d\n", request->n_channels));
+#else /* USE_INITIAL_SHORT_DWELL_TIME */
+ is_first_init_2g_scan = true;
+#endif /* USE_INITIAL_2G_SCAN */
+ g_first_broadcast_scan = false;
+ }
+#endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */
+
+ /* if scan request is not empty parse scan request paramters */
+ if (request != NULL) {
+ n_channels = request->n_channels;
+ n_ssids = request->n_ssids;
+ if (n_channels % 2)
+ /* If n_channels is odd, add a padd of u16 */
+ params_size += sizeof(u16) * (n_channels + 1);
+ else
+ params_size += sizeof(u16) * n_channels;
+
+ /* Allocate space for populating ssids in wl_escan_params_t struct */
+ params_size += sizeof(struct wlc_ssid) * n_ssids;
+ }
+ params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL);
+ if (params == NULL) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ wl_scan_prep(&params->params, request);
+
+#if defined(USE_INITIAL_2G_SCAN) || defined(USE_INITIAL_SHORT_DWELL_TIME)
+ /* Override active_time to reduce scan time if it's first bradcast scan. */
+ if (is_first_init_2g_scan)
+ params->params.active_time = FIRST_SCAN_ACTIVE_DWELL_TIME_MS;
+#endif /* USE_INITIAL_2G_SCAN || USE_INITIAL_SHORT_DWELL_TIME */
+
+ params->version = htod32(ESCAN_REQ_VERSION);
+ params->action = htod16(action);
+ wl_escan_set_sync_id(params->sync_id, cfg);
+ wl_escan_set_type(cfg, WL_SCANTYPE_LEGACY);
+ if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) {
+ WL_ERR(("ioctl buffer length not sufficient\n"));
+ kfree(params);
+ err = -ENOMEM;
+ goto exit;
+ }
+ err = wldev_iovar_setbuf(ndev, "escan", params, params_size,
+ cfg->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
+ if (unlikely(err)) {
+ if (err == BCME_EPERM)
+ /* Scan Not permitted at this point of time */
+ WL_DBG((" Escan not permitted at this time (%d)\n", err));
+ else
+ WL_ERR((" Escan set error (%d)\n", err));
+ }
+ kfree(params);
+ }
+ else if (p2p_is_on(cfg) && p2p_scan(cfg)) {
+ /* P2P SCAN TRIGGER */
+ s32 _freq = 0;
+ n_nodfs = 0;
+ if (request && request->n_channels) {
+ num_chans = request->n_channels;
+ WL_SCAN((" chann number : %d\n", num_chans));
+ default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list),
+ GFP_KERNEL);
+ if (default_chan_list == NULL) {
+ WL_ERR(("channel list allocation failed \n"));
+ err = -ENOMEM;
+ goto exit;
+ }
+ if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) {
+ list = (wl_uint32_list_t *) chan_buf;
+ n_valid_chan = dtoh32(list->count);
+ for (i = 0; i < num_chans; i++)
+ {
+ _freq = request->channels[i]->center_freq;
+ channel = ieee80211_frequency_to_channel(_freq);
+
+ /* ignore DFS channels */
+ if (request->channels[i]->flags &
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+ (IEEE80211_CHAN_NO_IR
+ | IEEE80211_CHAN_RADAR))
+#else
+ (IEEE80211_CHAN_RADAR
+ | IEEE80211_CHAN_PASSIVE_SCAN))
+#endif
+ continue;
+
+ for (j = 0; j < n_valid_chan; j++) {
+ /* allows only supported channel on
+ * current reguatory
+ */
+ if (channel == (dtoh32(list->element[j])))
+ default_chan_list[n_nodfs++] =
+ channel;
+ }
+
+ }
+ }
+ if (num_chans == SOCIAL_CHAN_CNT && (
+ (default_chan_list[0] == SOCIAL_CHAN_1) &&
+ (default_chan_list[1] == SOCIAL_CHAN_2) &&
+ (default_chan_list[2] == SOCIAL_CHAN_3))) {
+ /* SOCIAL CHANNELS 1, 6, 11 */
+ search_state = WL_P2P_DISC_ST_SEARCH;
+ p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL;
+ WL_INFO(("P2P SEARCH PHASE START \n"));
+ } else if ((dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION)) &&
+ (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) {
+ /* If you are already a GO, then do SEARCH only */
+ WL_INFO(("Already a GO. Do SEARCH Only"));
+ search_state = WL_P2P_DISC_ST_SEARCH;
+ num_chans = n_nodfs;
+ p2p_scan_purpose = P2P_SCAN_NORMAL;
+
+ } else if (num_chans == 1) {
+ p2p_scan_purpose = P2P_SCAN_CONNECT_TRY;
+ } else if (num_chans == SOCIAL_CHAN_CNT + 1) {
+ /* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan supported by
+ * the supplicant
+ */
+ p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL;
+ } else {
+ WL_INFO(("P2P SCAN STATE START \n"));
+ num_chans = n_nodfs;
+ p2p_scan_purpose = P2P_SCAN_NORMAL;
+ }
+ } else {
+ err = -EINVAL;
+ goto exit;
+ }
+ err = wl_cfgp2p_escan(cfg, ndev, cfg->active_scan, num_chans, default_chan_list,
+ search_state, action,
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE), NULL,
+ p2p_scan_purpose);
+
+ if (!err)
+ cfg->p2p->search_state = search_state;
+
+ kfree(default_chan_list);
+ }
+exit:
+ if (unlikely(err)) {
+ /* Don't print Error incase of Scan suppress */
+ if ((err == BCME_EPERM) && cfg->scan_suppressed)
+ WL_DBG(("Escan failed: Scan Suppressed \n"));
+ else
+ WL_ERR(("error (%d)\n", err));
+ }
+ return err;
+}
+
+
+static s32
+wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request)
+{
+ s32 err = BCME_OK;
+ s32 passive_scan;
+ wl_scan_results_t *results;
+ WL_SCAN(("Enter \n"));
+ mutex_lock(&cfg->usr_sync);
+
+ results = wl_escan_get_buf(cfg, FALSE);
+ results->version = 0;
+ results->count = 0;
+ results->buflen = WL_SCAN_RESULTS_FIXED_SIZE;
+
+ cfg->escan_info.ndev = ndev;
+ cfg->escan_info.wiphy = wiphy;
+ cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANING;
+ passive_scan = cfg->active_scan ? 0 : 1;
+ err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
+ &passive_scan, sizeof(passive_scan), true);
+ if (unlikely(err)) {
+ WL_ERR(("error (%d)\n", err));
+ goto exit;
+ }
+
+ err = wl_run_escan(cfg, ndev, request, WL_SCAN_ACTION_START);
+exit:
+ mutex_unlock(&cfg->usr_sync);
+ return err;
+}
+
+static s32
+__wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request,
+ struct cfg80211_ssid *this_ssid)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct cfg80211_ssid *ssids;
+ struct ether_addr primary_mac;
+ bool p2p_ssid;
+#ifdef WL11U
+ bcm_tlv_t *interworking_ie;
+#endif
+ s32 err = 0;
+ s32 bssidx = -1;
+ s32 i;
+
+ unsigned long flags;
+ static s32 busy_count = 0;
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ struct net_device *remain_on_channel_ndev = NULL;
+#endif
+
+#ifdef WL_SUPPORT_ACS
+ /*
+ * Hostapd triggers scan before starting automatic channel selection
+ * to collect channel characteristics. However firmware scan engine
+ * doesn't support any channel characteristics collection along with
+ * scan. Hence return scan success.
+ */
+ if (request && (scan_req_iftype(request) == NL80211_IFTYPE_AP)) {
+ struct cfg80211_scan_info info = {
+ .aborted = 0,
+ };
+ /*
+ * In case of ACS, store the channel number that hostap
+ * interested in. can be used to filter out when
+ * wl_cfg80211_dump_survey() handler is called.
+ */
+ { struct ieee80211_channel *chan = request->channels[0];
+ g_hostap_chan_count = 0;
+ while (g_hostap_chan_count < request->n_channels)
+ {
+ g_hostap_chan_cache[g_hostap_chan_count] =
+ chan[g_hostap_chan_count].center_freq;
+ g_hostap_chan_count++;
+ }
+ WL_DBG(("channel count hostapd interested in %d",
+ g_hostap_chan_count));
+ }
+ /* Indicate cfg80211 that we are done with scan */
+ cfg80211_scan_done(request, &info);
+ WL_INFO(("Scan Command on SoftAP Interface. Ignoring...\n"));
+ return 0;
+ }
+#endif /* WL_SUPPORT_ACS */
+
+ ndev = ndev_to_wlc_ndev(ndev, cfg);
+
+ if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
+ WL_ERR(("Sending Action Frames. Try it again.\n"));
+ return -EAGAIN;
+ }
+
+ WL_DBG(("Enter wiphy (%p)\n", wiphy));
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ if (cfg->scan_request == NULL) {
+ wl_clr_drv_status_all(cfg, SCANNING);
+ WL_DBG(("<<<<<<<<<<<Force Clear Scanning Status>>>>>>>>>>>\n"));
+ } else {
+ WL_ERR(("Scanning already\n"));
+ return -EAGAIN;
+ }
+ }
+ if (wl_get_drv_status(cfg, SCAN_ABORTING, ndev)) {
+ WL_ERR(("Scanning being aborted\n"));
+ return -EAGAIN;
+ }
+ if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) {
+ WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
+ return -EOPNOTSUPP;
+ }
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ remain_on_channel_ndev = wl_cfg80211_get_remain_on_channel_ndev(cfg);
+ if (remain_on_channel_ndev) {
+ WL_DBG(("Remain_on_channel bit is set, somehow it didn't get cleared\n"));
+ wl_notify_escan_complete(cfg, remain_on_channel_ndev, true, true);
+ }
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+
+
+ /* Arm scan timeout timer */
+ mod_timer(&cfg->scan_timeout, jiffies + msecs_to_jiffies(WL_SCAN_TIMER_INTERVAL_MS));
+ if (request) { /* scan bss */
+ ssids = request->ssids;
+ p2p_ssid = false;
+ for (i = 0; i < request->n_ssids; i++) {
+ if (ssids[i].ssid_len &&
+ IS_P2P_SSID(ssids[i].ssid, ssids[i].ssid_len)) {
+ p2p_ssid = true;
+ break;
+ }
+ }
+ if (p2p_ssid) {
+ if (cfg->p2p_supported) {
+ /* p2p scan trigger */
+ if (p2p_on(cfg) == false) {
+ /* p2p on at the first time */
+ p2p_on(cfg) = true;
+ wl_cfgp2p_set_firm_p2p(cfg);
+ get_primary_mac(cfg, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(&primary_mac,
+ &cfg->p2p->dev_addr, &cfg->p2p->int_addr);
+ }
+ wl_clr_p2p_status(cfg, GO_NEG_PHASE);
+ WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
+ p2p_scan(cfg) = true;
+ }
+ } else {
+ /* legacy scan trigger
+ * So, we have to disable p2p discovery if p2p discovery is on
+ */
+ if (cfg->p2p_supported) {
+ p2p_scan(cfg) = false;
+ /* If Netdevice is not equals to primary and p2p is on
+ * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE.
+ */
+
+ if (p2p_scan(cfg) == false) {
+ if (wl_get_p2p_status(cfg, DISCOVERY_ON)) {
+ err = wl_cfgp2p_discover_enable_search(cfg,
+ false);
+ if (unlikely(err)) {
+ goto scan_out;
+ }
+
+ }
+ }
+ }
+ if (!cfg->p2p_supported || !p2p_scan(cfg)) {
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg,
+ ndev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n",
+ ndev->ieee80211_ptr));
+ err = BCME_ERROR;
+ goto scan_out;
+ }
+#ifdef WL11U
+ if ((interworking_ie = wl_cfg80211_find_interworking_ie(
+ (u8 *)request->ie, request->ie_len)) != NULL) {
+ err = wl_cfg80211_add_iw_ie(cfg, ndev, bssidx,
+ VNDR_IE_CUSTOM_FLAG, interworking_ie->id,
+ interworking_ie->data, interworking_ie->len);
+
+ if (unlikely(err)) {
+ WL_ERR(("Failed to add interworking IE"));
+ }
+ } else if (cfg->iw_ie_len != 0) {
+ /* we have to clear IW IE and disable gratuitous APR */
+ wl_cfg80211_add_iw_ie(cfg, ndev, bssidx,
+ VNDR_IE_CUSTOM_FLAG,
+ DOT11_MNG_INTERWORKING_ID,
+ 0, 0);
+
+ err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 0,
+ bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("Set grat_arp error (%d)\n", err));
+ goto scan_out;
+ }
+
+ cfg->iw_ie_len = 0;
+ memset(cfg->iw_ie, 0, IW_IES_MAX_BUF_LEN);
+
+ cfg->wl11u = FALSE;
+ /* we don't care about error */
+ }
+#endif /* WL11U */
+ err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev, bssidx,
+ VNDR_IE_PRBREQ_FLAG, (u8 *)request->ie,
+ request->ie_len);
+
+ if (unlikely(err)) {
+ goto scan_out;
+ }
+
+ }
+ }
+ } else { /* scan in ibss */
+ ssids = this_ssid;
+ }
+
+ if (request && cfg->p2p && !p2p_scan(cfg)) {
+ WL_TRACE_HW4(("START SCAN\n"));
+ }
+
+ cfg->scan_request = request;
+ wl_set_drv_status(cfg, SCANNING, ndev);
+
+ if (cfg->p2p_supported) {
+ if (p2p_on(cfg) && p2p_scan(cfg)) {
+
+ /* find my listen channel */
+ cfg->afx_hdl->my_listen_chan =
+ wl_find_listen_channel(cfg, request->ie,
+ request->ie_len);
+ err = wl_cfgp2p_enable_discovery(cfg, ndev,
+ request->ie, request->ie_len);
+
+ if (unlikely(err)) {
+ goto scan_out;
+ }
+ }
+ }
+ err = wl_do_escan(cfg, wiphy, ndev, request);
+ if (likely(!err))
+ goto scan_success;
+ else
+ goto scan_out;
+
+scan_success:
+ busy_count = 0;
+
+ return 0;
+
+scan_out:
+ if (err == BCME_BUSY || err == BCME_NOTREADY) {
+ WL_ERR(("Scan err = (%d), busy?%d", err, -EBUSY));
+ err = -EBUSY;
+ } else if ((err == BCME_EPERM) && cfg->scan_suppressed) {
+ WL_ERR(("Scan not permitted due to scan suppress\n"));
+ err = -EPERM;
+ } else {
+ /* For all other fw errors, use a generic error code as return
+ * value to cfg80211 stack
+ */
+ err = -EAGAIN;
+ }
+
+#define SCAN_EBUSY_RETRY_LIMIT 10
+ if (err == -EBUSY) {
+ if (busy_count++ > SCAN_EBUSY_RETRY_LIMIT) {
+ struct ether_addr bssid;
+ s32 ret = 0;
+ busy_count = 0;
+ WL_ERR(("Unusual continuous EBUSY error, %d %d %d %d %d %d %d %d %d\n",
+ wl_get_drv_status(cfg, SCANNING, ndev),
+ wl_get_drv_status(cfg, SCAN_ABORTING, ndev),
+ wl_get_drv_status(cfg, CONNECTING, ndev),
+ wl_get_drv_status(cfg, CONNECTED, ndev),
+ wl_get_drv_status(cfg, DISCONNECTING, ndev),
+ wl_get_drv_status(cfg, AP_CREATING, ndev),
+ wl_get_drv_status(cfg, AP_CREATED, ndev),
+ wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev),
+ wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev)));
+
+ bzero(&bssid, sizeof(bssid));
+ if ((ret = wldev_ioctl(ndev, WLC_GET_BSSID,
+ &bssid, ETHER_ADDR_LEN, false)) == 0)
+ WL_ERR(("FW is connected with " MACDBG "/n",
+ MAC2STRDBG(bssid.octet)));
+ else
+ WL_ERR(("GET BSSID failed with %d\n", ret));
+
+ wl_cfg80211_scan_abort(cfg);
+
+ }
+ } else {
+ busy_count = 0;
+ }
+
+ wl_clr_drv_status(cfg, SCANNING, ndev);
+ if (timer_pending(&cfg->scan_timeout))
+ del_timer_sync(&cfg->scan_timeout);
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+ cfg->scan_request = NULL;
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+
+ return err;
+}
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+static s32
+wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
+#else
+static s32
+wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request)
+#endif /* WL_CFG80211_P2P_DEV_IF */
+{
+ s32 err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ struct net_device *ndev = wdev_to_wlc_ndev(request->wdev, cfg);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+ WL_DBG(("Enter \n"));
+ RETURN_EIO_IF_NOT_UP(cfg);
+
+#ifdef P2PONEINT
+ ndev = bcmcfg_to_prmry_ndev(cfg);
+ WL_DBG(("scan use [dev name %s ] \n", ndev->name));
+#endif
+
+ err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
+ if (unlikely(err)) {
+ WL_ERR(("scan error (%d)\n", err));
+ return err;
+ }
+
+ return err;
+}
+
+static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
+{
+ s32 err = 0;
+
+ err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold);
+ if (unlikely(err)) {
+ WL_ERR(("Error (%d)\n", err));
+ return err;
+ }
+ return err;
+}
+
+static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
+{
+ s32 err = 0;
+
+ err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0);
+ if (unlikely(err)) {
+ WL_ERR(("Error (%d)\n", err));
+ return err;
+ }
+ return err;
+}
+
+static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l)
+{
+ s32 err = 0;
+ u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
+
+ retry = htod32(retry);
+ err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), true);
+ if (unlikely(err)) {
+ WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
+ return err;
+ }
+ return err;
+}
+
+static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ s32 err = 0;
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+ WL_DBG(("Enter\n"));
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
+ (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
+ cfg->conf->rts_threshold = wiphy->rts_threshold;
+ err = wl_set_rts(ndev, cfg->conf->rts_threshold);
+ if (!err)
+ return err;
+ }
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
+ (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
+ cfg->conf->frag_threshold = wiphy->frag_threshold;
+ err = wl_set_frag(ndev, cfg->conf->frag_threshold);
+ if (!err)
+ return err;
+ }
+ if (changed & WIPHY_PARAM_RETRY_LONG &&
+ (cfg->conf->retry_long != wiphy->retry_long)) {
+ cfg->conf->retry_long = wiphy->retry_long;
+ err = wl_set_retry(ndev, cfg->conf->retry_long, true);
+ if (!err)
+ return err;
+ }
+ if (changed & WIPHY_PARAM_RETRY_SHORT &&
+ (cfg->conf->retry_short != wiphy->retry_short)) {
+ cfg->conf->retry_short = wiphy->retry_short;
+ err = wl_set_retry(ndev, cfg->conf->retry_short, false);
+ if (!err) {
+ return err;
+ }
+ }
+
+ return err;
+}
+static chanspec_t
+channel_to_chanspec(struct wiphy *wiphy, struct net_device *dev, u32 channel, u32 bw_cap)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ u8 *buf = NULL;
+ wl_uint32_list_t *list;
+ int err = BCME_OK;
+ chanspec_t c = 0, ret_c = 0;
+ int bw = 0, tmp_bw = 0;
+ int i;
+ u32 tmp_c, sb;
+ u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
+#define LOCAL_BUF_SIZE 1024
+ buf = (u8 *) kzalloc(LOCAL_BUF_SIZE, kflags);
+ if (!buf) {
+ WL_ERR(("buf memory alloc failed\n"));
+ goto exit;
+ }
+ list = (wl_uint32_list_t *)(void *)buf;
+ list->count = htod32(WL_NUMCHANSPECS);
+ err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
+ 0, buf, LOCAL_BUF_SIZE, 0, &cfg->ioctl_buf_sync);
+ if (err != BCME_OK) {
+ WL_ERR(("get chanspecs failed with %d\n", err));
+ goto exit;
+ }
+ for (i = 0; i < dtoh32(list->count); i++) {
+ c = dtoh32(list->element[i]);
+ if (channel <= CH_MAX_2G_CHANNEL) {
+ if (!CHSPEC_IS20(c))
+ continue;
+ if (channel == CHSPEC_CHANNEL(c)) {
+ ret_c = c;
+ bw = 20;
+ goto exit;
+ }
+ }
+ if (CHSPEC_IS20(c)) {
+ tmp_c = CHSPEC_CHANNEL(c);
+ tmp_bw = WLC_BW_CAP_20MHZ;
+ }
+ else if (CHSPEC_IS40(c)) {
+ tmp_c = CHSPEC_CHANNEL(c);
+ if (CHSPEC_SB_UPPER(c)) {
+ tmp_c += CH_10MHZ_APART;
+ } else {
+ tmp_c -= CH_10MHZ_APART;
+ }
+ tmp_bw = WLC_BW_CAP_40MHZ;
+ }
+ else {
+ tmp_c = CHSPEC_CHANNEL(c);
+ sb = c & WL_CHANSPEC_CTL_SB_MASK;
+ if (sb == WL_CHANSPEC_CTL_SB_LL) {
+ tmp_c -= (CH_10MHZ_APART + CH_20MHZ_APART);
+ } else if (sb == WL_CHANSPEC_CTL_SB_LU) {
+ tmp_c -= CH_10MHZ_APART;
+ } else if (sb == WL_CHANSPEC_CTL_SB_UL) {
+ tmp_c += CH_10MHZ_APART;
+ } else {
+ /* WL_CHANSPEC_CTL_SB_UU */
+ tmp_c += (CH_10MHZ_APART + CH_20MHZ_APART);
+ }
+ tmp_bw = WLC_BW_CAP_80MHZ;
+ }
+ if (tmp_c != channel)
+ continue;
+
+ if ((tmp_bw > bw) && (tmp_bw <= bw_cap)) {
+ bw = tmp_bw;
+ ret_c = c;
+ if (bw == bw_cap)
+ goto exit;
+ }
+ }
+exit:
+ if (buf)
+ kfree(buf);
+#undef LOCAL_BUF_SIZE
+ WL_INFO(("return chanspec %x %d\n", ret_c, bw));
+ return ret_c;
+}
+
+void
+wl_cfg80211_ibss_vsie_set_buffer(vndr_ie_setbuf_t *ibss_vsie, int ibss_vsie_len)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+
+ if (cfg != NULL && ibss_vsie != NULL) {
+ if (cfg->ibss_vsie != NULL) {
+ kfree(cfg->ibss_vsie);
+ }
+ cfg->ibss_vsie = ibss_vsie;
+ cfg->ibss_vsie_len = ibss_vsie_len;
+ }
+}
+
+static void
+wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 *cfg)
+{
+ /* free & initiralize VSIE (Vendor Specific IE) */
+ if (cfg->ibss_vsie != NULL) {
+ kfree(cfg->ibss_vsie);
+ cfg->ibss_vsie = NULL;
+ cfg->ibss_vsie_len = 0;
+ }
+}
+
+s32
+wl_cfg80211_ibss_vsie_delete(struct net_device *dev)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ char *ioctl_buf = NULL;
+ s32 ret = BCME_OK;
+
+ if (cfg != NULL && cfg->ibss_vsie != NULL) {
+ ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
+ if (!ioctl_buf) {
+ WL_ERR(("ioctl memory alloc failed\n"));
+ return -ENOMEM;
+ }
+
+ /* change the command from "add" to "del" */
+ strncpy(cfg->ibss_vsie->cmd, "del", VNDR_IE_CMD_LEN - 1);
+ cfg->ibss_vsie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
+
+ ret = wldev_iovar_setbuf(dev, "ie",
+ cfg->ibss_vsie, cfg->ibss_vsie_len,
+ ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
+ WL_ERR(("ret=%d\n", ret));
+
+ if (ret == BCME_OK) {
+ /* free & initiralize VSIE */
+ kfree(cfg->ibss_vsie);
+ cfg->ibss_vsie = NULL;
+ cfg->ibss_vsie_len = 0;
+ }
+
+ if (ioctl_buf) {
+ kfree(ioctl_buf);
+ }
+ }
+
+ return ret;
+}
+
+static s32
+wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ibss_params *params)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct cfg80211_bss *bss;
+ struct ieee80211_channel *chan;
+ struct wl_join_params join_params;
+ int scan_suppress;
+ struct cfg80211_ssid ssid;
+ s32 scan_retry = 0;
+ s32 err = 0;
+ size_t join_params_size;
+ chanspec_t chanspec = 0;
+ u32 param[2] = {0, 0};
+ u32 bw_cap = 0;
+
+ WL_TRACE(("In\n"));
+ RETURN_EIO_IF_NOT_UP(cfg);
+ WL_INFO(("JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid)));
+ if (!params->ssid || params->ssid_len <= 0 ||
+ params->ssid_len > DOT11_MAX_SSID_LEN) {
+ WL_ERR(("Invalid parameter\n"));
+ return -EINVAL;
+ }
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ chan = params->chandef.chan;
+#else
+ chan = params->channel;
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ if (chan)
+ cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
+ if (wl_get_drv_status(cfg, CONNECTED, dev)) {
+ struct wlc_ssid *ssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID);
+ u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID);
+ u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN);
+ if (!params->bssid || ((memcmp(params->bssid, bssid, ETHER_ADDR_LEN) == 0) &&
+ (memcmp(params->ssid, ssid->SSID, ssid->SSID_len) == 0) &&
+ (*channel == cfg->channel))) {
+ WL_ERR(("Connection already existed to " MACDBG "\n",
+ MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID))));
+ return -EISCONN;
+ }
+ WL_ERR(("Ignore Previous connecton to %s (" MACDBG ")\n",
+ ssid->SSID, MAC2STRDBG(bssid)));
+ }
+
+ /* remove the VSIE */
+ wl_cfg80211_ibss_vsie_delete(dev);
+
+ bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
+ if (!bss) {
+ if (IBSS_INITIAL_SCAN_ALLOWED == TRUE) {
+ memcpy(ssid.ssid, params->ssid, params->ssid_len);
+ ssid.ssid_len = params->ssid_len;
+ do {
+ if (unlikely
+ (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
+ -EBUSY)) {
+ wl_delay(150);
+ } else {
+ break;
+ }
+ } while (++scan_retry < WL_SCAN_RETRY_MAX);
+
+ /* rtnl lock code is removed here. don't see why rtnl lock
+ * needs to be released.
+ */
+
+ /* wait 4 secons till scan done.... */
+ schedule_timeout_interruptible(msecs_to_jiffies(4000));
+
+ bss = cfg80211_get_ibss(wiphy, NULL,
+ params->ssid, params->ssid_len);
+ }
+ }
+ if (bss && ((IBSS_COALESCE_ALLOWED == TRUE) ||
+ ((IBSS_COALESCE_ALLOWED == FALSE) && params->bssid &&
+ !memcmp(bss->bssid, params->bssid, ETHER_ADDR_LEN)))) {
+ cfg->ibss_starter = false;
+ WL_DBG(("Found IBSS\n"));
+ } else {
+ cfg->ibss_starter = true;
+ }
+ if (chan) {
+ if (chan->band == NL80211_BAND_5GHZ)
+ param[0] = WLC_BAND_5G;
+ else if (chan->band == NL80211_BAND_2GHZ)
+ param[0] = WLC_BAND_2G;
+ err = wldev_iovar_getint(dev, "bw_cap", param);
+ if (unlikely(err)) {
+ WL_ERR(("Get bw_cap Failed (%d)\n", err));
+ return err;
+ }
+ bw_cap = param[0];
+ chanspec = channel_to_chanspec(wiphy, dev, cfg->channel, bw_cap);
+ }
+ /*
+ * Join with specific BSSID and cached SSID
+ * If SSID is zero join based on BSSID only
+ */
+ memset(&join_params, 0, sizeof(join_params));
+ memcpy((void *)join_params.ssid.SSID, (void *)params->ssid,
+ params->ssid_len);
+ join_params.ssid.SSID_len = htod32(params->ssid_len);
+ if (params->bssid) {
+ memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);
+ err = wldev_ioctl(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid,
+ ETHER_ADDR_LEN, true);
+ if (unlikely(err)) {
+ WL_ERR(("Error (%d)\n", err));
+ return err;
+ }
+ } else
+ memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);
+ wldev_iovar_setint(dev, "ibss_coalesce_allowed", IBSS_COALESCE_ALLOWED);
+
+ if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
+ scan_suppress = TRUE;
+ /* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */
+ err = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS,
+ &scan_suppress, sizeof(int), true);
+ if (unlikely(err)) {
+ WL_ERR(("Scan Suppress Setting Failed (%d)\n", err));
+ return err;
+ }
+ }
+
+ join_params.params.chanspec_list[0] = chanspec;
+ join_params.params.chanspec_num = 1;
+ wldev_iovar_setint(dev, "chanspec", chanspec);
+ join_params_size = sizeof(join_params);
+
+ /* Disable Authentication, IBSS will add key if it required */
+ wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
+ wldev_iovar_setint(dev, "wsec", 0);
+
+
+ err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
+ join_params_size, true);
+ if (unlikely(err)) {
+ WL_ERR(("Error (%d)\n", err));
+ return err;
+ }
+
+ if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
+ scan_suppress = FALSE;
+ /* Reset the SCAN SUPPRESS Flag */
+ err = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS,
+ &scan_suppress, sizeof(int), true);
+ if (unlikely(err)) {
+ WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err));
+ return err;
+ }
+ }
+ wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
+ wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN);
+#ifdef WL_RELMCAST
+ cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */
+#endif /* WL_RELMCAST */
+ return err;
+}
+
+static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 err = 0;
+ scb_val_t scbval;
+ u8 *curbssid;
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+ wl_link_down(cfg);
+
+ WL_ERR(("Leave IBSS\n"));
+ curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
+ wl_set_drv_status(cfg, DISCONNECTING, dev);
+ scbval.val = 0;
+ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
+ err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
+ sizeof(scb_val_t), true);
+ if (unlikely(err)) {
+ wl_clr_drv_status(cfg, DISCONNECTING, dev);
+ WL_ERR(("error(%d)\n", err));
+ return err;
+ }
+
+ /* remove the VSIE */
+ wl_cfg80211_ibss_vsie_delete(dev);
+
+ return err;
+}
+
+s32
+wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
+ struct net_device *ndev, s32 bsscfg_idx,
+ enum nl80211_iftype iface_type, s32 del, u8 *addr)
+{
+ s32 ret = BCME_OK;
+ s32 val = 0;
+
+ struct {
+ s32 cfg;
+ s32 val;
+ struct ether_addr ea;
+ } bss_setbuf;
+
+ WL_INFO(("iface_type:%d del:%d \n", iface_type, del));
+
+ bzero(&bss_setbuf, sizeof(bss_setbuf));
+
+ /* AP=3, STA=2, up=1, down=0, val=-1 */
+ if (del) {
+ val = -1;
+ } else if (iface_type == NL80211_IFTYPE_AP) {
+ /* AP Interface */
+ WL_DBG(("Adding AP Interface \n"));
+ val = 3;
+ } else if (iface_type == NL80211_IFTYPE_STATION) {
+ WL_DBG(("Adding STA Interface \n"));
+ val = 2;
+ } else {
+ WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", iface_type));
+ return -EINVAL;
+ }
+
+ bss_setbuf.cfg = htod32(bsscfg_idx);
+ bss_setbuf.val = htod32(val);
+
+ if (addr) {
+ memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN);
+ }
+
+ ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (ret != 0)
+ WL_ERR(("'bss %d' failed with %d\n", val, ret));
+
+ return ret;
+}
+
+#if defined(WL_VIRTUAL_APSTA)
+/* Create a Generic Network Interface and initialize it depending up on
+ * the interface type
+ */
+bcm_struct_cfgdev*
+wl_cfg80211_create_iface(struct wiphy *wiphy,
+ enum nl80211_iftype iface_type,
+ u8 *mac_addr, const char *name)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *new_ndev = NULL;
+ struct net_device *primary_ndev = NULL;
+ s32 ret = BCME_OK;
+ s32 bsscfg_idx = 0;
+ u32 timeout;
+ wl_if_event_info *event = NULL;
+ struct wireless_dev *wdev = NULL;
+ u8 addr[ETH_ALEN];
+
+ WL_DBG(("Enter\n"));
+
+ if (!name) {
+ WL_ERR(("Interface name not provided\n"));
+ return NULL;
+ }
+
+ if (cfg->bss_cfgdev) {
+ WL_ERR(("More than one virtual interface is not needed/supported\n"));
+ return NULL;
+ }
+
+#ifdef DHD_IFDEBUG
+ primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+ WL_ERR(("cfg=%p, primary_ndev=%p, ifname=%s\n", cfg, primary_ndev, name));
+#endif
+
+ /* If any scan is going on, abort it */
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ int wait_cnt = MAX_SCAN_ABORT_WAIT_CNT;
+ WL_ERR(("Scan in progress. Aborting the scan!\n"));
+ wl_cfg80211_scan_abort(cfg);
+ while (wl_get_drv_status_all(cfg, SCANNING) && wait_cnt) {
+ WL_DBG(("Waiting for SCANNING terminated, wait_cnt: %d\n", wait_cnt));
+ wait_cnt--;
+ OSL_SLEEP(WAIT_SCAN_ABORT_OSL_SLEEP_TIME);
+ }
+ if (!wait_cnt && wl_get_drv_status_all(cfg, SCANNING)) {
+ WL_ERR(("Failed to abort scan\n"));
+ return NULL;
+ }
+ }
+
+ primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+ if (likely(!mac_addr)) {
+ /* Use primary MAC with the locally administered bit for the
+ * Secondary STA I/F
+ */
+ memcpy(addr, primary_ndev->dev_addr, ETH_ALEN);
+ addr[0] |= 0x02;
+
+ /* MAC Adress for virtual interface
+ */
+ addr[3] ^= 0xA0;
+ } else {
+ /* Use the application provided mac address (if any) */
+ memcpy(addr, mac_addr, ETH_ALEN);
+ }
+
+ if ((iface_type != NL80211_IFTYPE_STATION) && (iface_type != NL80211_IFTYPE_AP)) {
+ WL_ERR(("IFACE type:%d not supported. STA "
+ "or AP IFACE is only supported\n", iface_type));
+ return NULL;
+ }
+
+ cfg->bss_pending_op = TRUE;
+ memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
+
+ /* p2p-disc takes bsscfgidx=1 */
+ bsscfg_idx = 2;
+
+ /*
+ * Intialize the firmware I/F.
+ */
+ if ((ret = wl_cfg80211_add_del_bss(cfg, primary_ndev,
+ bsscfg_idx, iface_type, 0, addr)) < 0) {
+ WL_ERR(("Interface create failed!! ret(%d)\n", ret));
+ return NULL;
+ }
+
+ WL_DBG(("Interface created!! bssidx:%d \n", bsscfg_idx));
+
+ /*
+ * Wait till the firmware send a confirmation event back.
+ */
+ WL_DBG(("Wait for the FW I/F Event\n"));
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+ !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
+ if (timeout <= 0 || cfg->bss_pending_op) {
+ WL_ERR(("timeout in waiting IF_ADD event\n"));
+ goto fail;
+ }
+
+ /*
+ * Since FW operation is successful,we can go ahead with the
+ * the host interface creation.
+ */
+ event = &cfg->if_event_info;
+ new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx,
+ (char*)name, addr, event->bssidx, event->name);
+ if (!new_ndev) {
+ WL_ERR(("I/F allocation failed! \n"));
+ goto fail;
+ } else {
+ WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n",
+ event->ifidx, event->bssidx));
+ }
+
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (!wdev) {
+ WL_ERR(("wireless_dev alloc failed! \n"));
+ goto fail;
+ }
+
+ wdev->wiphy = wiphy;
+ wdev->iftype = iface_type;
+ new_ndev->ieee80211_ptr = wdev;
+ SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
+
+#ifdef DHD_IFDEBUG
+ WL_ERR(("wdev=%p, new_ndev=%p\n", wdev, new_ndev));
+#endif
+
+ /* RTNL lock must have been acquired. */
+ ASSERT_RTNL();
+
+ /* Set the locally administed mac addr, if not applied already */
+ if (memcmp(addr, event->mac, ETH_ALEN) != 0) {
+ ret = wldev_iovar_setbuf_bsscfg(new_ndev, "cur_etheraddr",
+ addr, ETH_ALEN, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
+ event->bssidx, &cfg->ioctl_buf_sync);
+ if (unlikely(ret)) {
+ WL_ERR(("set cur_etheraddr Error (%d)\n", ret));
+ goto fail;
+ }
+ memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
+ }
+
+ if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) {
+ WL_ERR(("IFACE register failed \n"));
+ goto fail;
+ }
+
+ /* Initialize with the station mode params */
+ wl_alloc_netinfo(cfg, new_ndev, wdev,
+ (iface_type == NL80211_IFTYPE_STATION) ?
+ WL_MODE_BSS : WL_MODE_AP, PM_ENABLE, event->bssidx);
+ cfg->bss_cfgdev = ndev_to_cfgdev(new_ndev);
+ cfg->cfgdev_bssidx = event->bssidx;
+
+ WL_DBG(("Host Network Interface for Secondary I/F created"));
+
+#ifdef DHD_IFDEBUG
+ WL_ERR(("cfg->bss_cfgdev=%p\n", cfg->bss_cfgdev));
+#endif
+
+ return cfg->bss_cfgdev;
+
+fail:
+ cfg->bss_pending_op = FALSE;
+ cfg->cfgdev_bssidx = -1;
+ if (wdev)
+ kfree(wdev);
+ if (new_ndev)
+ wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev);
+
+#ifdef DHD_IFDEBUG
+ WL_ERR(("failed!!!\n"));
+#endif
+
+ return NULL;
+}
+
+s32
+wl_cfg80211_del_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *ndev = NULL;
+#ifdef DHD_IFDEBUG
+ struct net_device *primary_ndev = NULL;
+#endif
+ s32 ret = BCME_OK;
+ u32 timeout = 0;
+ enum nl80211_iftype iface_type = NL80211_IFTYPE_STATION;
+
+ WL_ERR(("Enter\n"));
+
+ if (!cfg->bss_cfgdev) {
+ WL_ERR(("There is no virtual interface found\n"));
+ return 0;
+ }
+
+ /* If any scan is going on, abort it */
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ WL_ERR(("Scan in progress. Aborting the scan!\n"));
+ wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
+ }
+
+ ndev = (struct net_device *)cfgdev_to_wlc_ndev(cfg->bss_cfgdev, cfg);
+#ifdef DHD_IFDEBUG
+ primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+ WL_ERR(("cfg->bss_cfgdev=%p, ndev=%p, primary_ndev=%p\n",
+ cfg->bss_cfgdev, ndev, primary_ndev));
+#endif
+
+ cfg->bss_pending_op = TRUE;
+ memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
+
+ /* Delete the firmware interface. "interface_remove" command
+ * should go on the interface to be deleted
+ */
+ if ((ret = wl_cfg80211_add_del_bss(cfg, ndev,
+ cfg->cfgdev_bssidx, iface_type, true, NULL)) < 0) {
+ WL_ERR(("DEL bss failed ret:%d \n", ret));
+ goto exit;
+ }
+
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+ !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
+ if (timeout <= 0 || cfg->bss_pending_op) {
+ WL_ERR(("timeout in waiting IF_DEL event\n"));
+ }
+
+exit:
+ cfg->bss_cfgdev = NULL;
+ cfg->cfgdev_bssidx = -1;
+ cfg->bss_pending_op = FALSE;
+
+ WL_ERR(("IF_DEL Done.\n"));
+
+ return ret;
+}
+#endif /* defined(WL_VIRTUAL_APSTA) */
+
+
+static s32
+wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ struct wl_security *sec;
+ s32 val = 0;
+ s32 err = 0;
+ s32 bssidx;
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ return BCME_ERROR;
+ }
+
+ if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ val = WPA_AUTH_PSK |
+ WPA_AUTH_UNSPECIFIED;
+ else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ val = WPA2_AUTH_PSK|
+ WPA2_AUTH_UNSPECIFIED;
+ else
+ val = WPA_AUTH_DISABLED;
+
+ if (is_wps_conn(sme))
+ val = WPA_AUTH_DISABLED;
+
+ WL_DBG(("setting wpa_auth to 0x%0x\n", val));
+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("set wpa_auth failed (%d)\n", err));
+ return err;
+ }
+ sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
+ sec->wpa_versions = sme->crypto.wpa_versions;
+ return err;
+}
+
+
+static s32
+wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ struct wl_security *sec;
+ s32 val = 0;
+ s32 err = 0;
+ s32 bssidx;
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ return BCME_ERROR;
+ }
+
+ switch (sme->auth_type) {
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ val = WL_AUTH_OPEN_SYSTEM;
+ WL_DBG(("open system\n"));
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ val = WL_AUTH_SHARED_KEY;
+ WL_DBG(("shared key\n"));
+ break;
+ case NL80211_AUTHTYPE_AUTOMATIC:
+ val = WL_AUTH_OPEN_SHARED;
+ WL_DBG(("automatic\n"));
+ break;
+ default:
+ val = 2;
+ WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
+ break;
+ }
+
+ err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("set auth failed (%d)\n", err));
+ return err;
+ }
+ sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
+ sec->auth_type = sme->auth_type;
+ return err;
+}
+
+static s32
+wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ struct wl_security *sec;
+ s32 pval = 0;
+ s32 gval = 0;
+ s32 err = 0;
+ s32 wsec_val = 0;
+
+ s32 bssidx;
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ return BCME_ERROR;
+ }
+
+ if (sme->crypto.n_ciphers_pairwise) {
+ switch (sme->crypto.ciphers_pairwise[0]) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ pval = WEP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ pval = TKIP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ pval = AES_ENABLED;
+ break;
+ default:
+ WL_ERR(("invalid cipher pairwise (%d)\n",
+ sme->crypto.ciphers_pairwise[0]));
+ return -EINVAL;
+ }
+ }
+ if (sme->crypto.cipher_group) {
+ switch (sme->crypto.cipher_group) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ gval = WEP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ gval = TKIP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ gval = AES_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ gval = AES_ENABLED;
+ break;
+ default:
+ WL_ERR(("invalid cipher group (%d)\n",
+ sme->crypto.cipher_group));
+ return -EINVAL;
+ }
+ }
+
+ WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
+
+ if (is_wps_conn(sme)) {
+ if (sme->privacy)
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx);
+ else
+ /* WPS-2.0 allows no security */
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx);
+ } else {
+ WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
+ wsec_val = pval | gval;
+
+ WL_DBG((" Set WSEC to fW 0x%x \n", wsec_val));
+ err = wldev_iovar_setint_bsscfg(dev, "wsec",
+ wsec_val, bssidx);
+ }
+ if (unlikely(err)) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+
+ sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
+ sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
+ sec->cipher_group = sme->crypto.cipher_group;
+
+ return err;
+}
+
+static s32
+wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ struct wl_security *sec;
+ s32 val = 0;
+ s32 err = 0;
+ s32 bssidx;
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ return BCME_ERROR;
+ }
+
+ if (sme->crypto.n_akm_suites) {
+ err = wldev_iovar_getint(dev, "wpa_auth", &val);
+ if (unlikely(err)) {
+ WL_ERR(("could not get wpa_auth (%d)\n", err));
+ return err;
+ }
+ if (val & (WPA_AUTH_PSK |
+ WPA_AUTH_UNSPECIFIED)) {
+ switch (sme->crypto.akm_suites[0]) {
+ case WLAN_AKM_SUITE_8021X:
+ val = WPA_AUTH_UNSPECIFIED;
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ val = WPA_AUTH_PSK;
+ break;
+ default:
+ WL_ERR(("invalid akm suite (0x%x)\n",
+ sme->crypto.akm_suites[0]));
+ return -EINVAL;
+ }
+ } else if (val & (WPA2_AUTH_PSK |
+ WPA2_AUTH_UNSPECIFIED)) {
+ switch (sme->crypto.akm_suites[0]) {
+ case WLAN_AKM_SUITE_8021X:
+ val = WPA2_AUTH_UNSPECIFIED;
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ val = WPA2_AUTH_PSK;
+ break;
+ default:
+ WL_ERR(("invalid akm suite (0x%x)\n",
+ sme->crypto.akm_suites[0]));
+ return -EINVAL;
+ }
+ }
+ WL_DBG(("setting wpa_auth to %d\n", val));
+
+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("could not set wpa_auth (%d)\n", err));
+ return err;
+ }
+ }
+ sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
+ sec->wpa_auth = sme->crypto.akm_suites[0];
+
+ return err;
+}
+
+static s32
+wl_set_set_sharedkey(struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ struct wl_security *sec;
+ struct wl_wsec_key key;
+ s32 val;
+ s32 err = 0;
+ s32 bssidx;
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ return BCME_ERROR;
+ }
+
+ WL_DBG(("key len (%d)\n", sme->key_len));
+ if (sme->key_len) {
+ sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
+ WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
+ sec->wpa_versions, sec->cipher_pairwise));
+ if ((!(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
+ NL80211_WPA_VERSION_2))) &&
+ (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
+ WLAN_CIPHER_SUITE_WEP104)))
+ {
+ memset(&key, 0, sizeof(key));
+ key.len = (u32) sme->key_len;
+ key.index = (u32) sme->key_idx;
+ if (unlikely(key.len > sizeof(key.data))) {
+ WL_ERR(("Too long key length (%u)\n", key.len));
+ return -EINVAL;
+ }
+ memcpy(key.data, sme->key, key.len);
+ key.flags = WL_PRIMARY_KEY;
+ switch (sec->cipher_pairwise) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key.algo = CRYPTO_ALGO_WEP1;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ key.algo = CRYPTO_ALGO_WEP128;
+ break;
+ default:
+ WL_ERR(("Invalid algorithm (%d)\n",
+ sme->crypto.ciphers_pairwise[0]));
+ return -EINVAL;
+ }
+ /* Set the new key/index */
+ WL_DBG(("key length (%d) key index (%d) algo (%d)\n",
+ key.len, key.index, key.algo));
+ WL_DBG(("key \"%s\"\n", key.data));
+ swap_key_from_BE(&key);
+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ return err;
+ }
+ if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
+ WL_DBG(("set auth_type to shared key\n"));
+ val = WL_AUTH_SHARED_KEY; /* shared key */
+ err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("set auth failed (%d)\n", err));
+ return err;
+ }
+ }
+ }
+ }
+ return err;
+}
+
+#if defined(ESCAN_RESULT_PATCH)
+static u8 connect_req_bssid[6];
+static u8 broad_bssid[6];
+#endif /* ESCAN_RESULT_PATCH */
+
+
+
+#if defined(CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX)
+static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd)
+{
+ u32 chanspec = 0;
+ bool isvht80 = 0;
+
+ if (wldev_iovar_getint(net, "chanspec", (s32 *)&chanspec) == BCME_OK)
+ chanspec = wl_chspec_driver_to_host(chanspec);
+
+ isvht80 = chanspec & WL_CHANSPEC_BW_80;
+ WL_INFO(("%s: chanspec(%x:%d)\n", __FUNCTION__, chanspec, isvht80));
+
+ return isvht80;
+}
+#endif /* CUSTOM_SET_CPUCORE || CONFIG_TCPACK_FASTTX */
+
+static s32
+wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct ieee80211_channel *chan = sme->channel;
+ wl_extjoin_params_t *ext_join_params;
+ struct wl_join_params join_params;
+ size_t join_params_size;
+#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+ s32 roam_trigger[2] = {0, 0};
+#endif /* ROAM_AP_ENV_DETECTION */
+ s32 err = 0;
+ wpa_ie_fixed_t *wpa_ie;
+ bcm_tlv_t *wpa2_ie;
+ u8* wpaie = 0;
+ u32 wpaie_len = 0;
+ u32 chan_cnt = 0;
+ struct ether_addr bssid;
+ s32 bssidx;
+ int ret;
+ int wait_cnt;
+
+ WL_DBG(("In\n"));
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
+ if (sme->channel_hint) {
+ chan = sme->channel_hint;
+ WL_DBG(("channel_hint (%d), channel_hint center_freq (%d)\n",
+ ieee80211_frequency_to_channel(sme->channel_hint->center_freq),
+ sme->channel_hint->center_freq));
+ }
+ if (sme->bssid_hint) {
+ sme->bssid = sme->bssid_hint;
+ WL_DBG(("bssid_hint "MACDBG" \n", MAC2STRDBG(sme->bssid_hint)));
+ }
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
+ if (unlikely(!sme->ssid)) {
+ WL_ERR(("Invalid ssid\n"));
+ return -EOPNOTSUPP;
+ }
+
+ if (unlikely(sme->ssid_len > DOT11_MAX_SSID_LEN)) {
+ WL_ERR(("Invalid SSID info: SSID=%s, length=%zd\n",
+ sme->ssid, sme->ssid_len));
+ return -EINVAL;
+ }
+
+ WL_DBG(("SME IE : len=%zu\n", sme->ie_len));
+ if (sme->ie != NULL && sme->ie_len > 0 && (wl_dbg_level & WL_DBG_DBG)) {
+ prhex(NULL, (void *)sme->ie, sme->ie_len);
+ }
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+
+ /*
+ * Cancel ongoing scan to sync up with sme state machine of cfg80211.
+ */
+#if !defined(ESCAN_RESULT_PATCH)
+ if (cfg->scan_request) {
+ wl_notify_escan_complete(cfg, dev, true, true);
+ }
+#endif
+#ifdef WL_SCHED_SCAN
+ if (cfg->sched_scan_req) {
+ wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg));
+ }
+#endif
+#if defined(ESCAN_RESULT_PATCH)
+ if (sme->bssid)
+ memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN);
+ else
+ bzero(connect_req_bssid, ETHER_ADDR_LEN);
+ bzero(broad_bssid, ETHER_ADDR_LEN);
+#endif
+#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
+ maxrxpktglom = 0;
+#endif
+ bzero(&bssid, sizeof(bssid));
+ if (!wl_get_drv_status(cfg, CONNECTED, dev)&&
+ (ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false)) == 0) {
+ if (!ETHER_ISNULLADDR(&bssid)) {
+ scb_val_t scbval;
+ wl_set_drv_status(cfg, DISCONNECTING, dev);
+ scbval.val = DOT11_RC_DISASSOC_LEAVING;
+ memcpy(&scbval.ea, &bssid, ETHER_ADDR_LEN);
+ scbval.val = htod32(scbval.val);
+
+ WL_DBG(("drv status CONNECTED is not set, but connected in FW!" MACDBG "/n",
+ MAC2STRDBG(bssid.octet)));
+ err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
+ sizeof(scb_val_t), true);
+ if (unlikely(err)) {
+ wl_clr_drv_status(cfg, DISCONNECTING, dev);
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+ wait_cnt = 500/10;
+ while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
+ WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n",
+ wait_cnt));
+ wait_cnt--;
+ OSL_SLEEP(10);
+ }
+ } else
+ WL_DBG(("Currently not associated!\n"));
+ } else {
+ /* if status is DISCONNECTING, wait for disconnection terminated max 500 ms */
+ wait_cnt = 200/10;
+ while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
+ WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n", wait_cnt));
+ wait_cnt--;
+ OSL_SLEEP(10);
+ }
+ if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
+ WL_ERR(("Force clear DISCONNECTING status!\n"));
+ wl_clr_drv_status(cfg, DISCONNECTING, dev);
+ }
+ }
+
+ /* Clean BSSID */
+ bzero(&bssid, sizeof(bssid));
+ if (!wl_get_drv_status(cfg, DISCONNECTING, dev))
+ wl_update_prof(cfg, dev, NULL, (void *)&bssid, WL_PROF_BSSID);
+
+ if (p2p_is_on(cfg) && (dev != bcmcfg_to_prmry_ndev(cfg))) {
+ /* we only allow to connect using virtual interface in case of P2P */
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+ wl_cfg80211_set_mgmt_vndr_ies(cfg, dev, bssidx,
+ VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
+ } else if (dev == bcmcfg_to_prmry_ndev(cfg)) {
+ /* find the RSN_IE */
+ if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len,
+ DOT11_MNG_RSN_ID)) != NULL) {
+ WL_DBG((" WPA2 IE is found\n"));
+ }
+ /* find the WPA_IE */
+ if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)sme->ie,
+ sme->ie_len)) != NULL) {
+ WL_DBG((" WPA IE is found\n"));
+ }
+ if (wpa_ie != NULL || wpa2_ie != NULL) {
+ wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie;
+ wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
+ wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
+ wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ } else {
+ wldev_iovar_setbuf(dev, "wpaie", NULL, 0,
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ }
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+ err = wl_cfg80211_set_mgmt_vndr_ies(cfg, dev, bssidx,
+ VNDR_IE_ASSOCREQ_FLAG, (u8 *)sme->ie, sme->ie_len);
+ if (unlikely(err)) {
+ return err;
+ }
+ }
+#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
+ if (dhd->roam_env_detection) {
+ bool is_roamtrig_reset = TRUE;
+ bool is_roam_env_ok = (wldev_iovar_setint(dev, "roam_env_detection",
+ AP_ENV_DETECT_NOT_USED) == BCME_OK);
+ if (is_roamtrig_reset && is_roam_env_ok) {
+ roam_trigger[0] = WL_AUTO_ROAM_TRIGGER;
+ roam_trigger[1] = WLC_BAND_ALL;
+ err = wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
+ sizeof(roam_trigger), true);
+ if (unlikely(err)) {
+ WL_ERR((" failed to restore roam_trigger for auto env"
+ " detection\n"));
+ }
+ }
+ }
+#endif /* ROAM_ENABLE && ROAM_AP_ENV_DETECTION */
+ if (chan) {
+ cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
+ chan_cnt = 1;
+ WL_DBG(("channel (%d), center_req (%d), %d channels\n", cfg->channel,
+ chan->center_freq, chan_cnt));
+ } else
+ cfg->channel = 0;
+
+ WL_DBG(("3. set wapi version \n"));
+ err = wl_set_wpa_version(dev, sme);
+ if (unlikely(err)) {
+ WL_ERR(("Invalid wpa_version\n"));
+ return err;
+ }
+ err = wl_set_auth_type(dev, sme);
+ if (unlikely(err)) {
+ WL_ERR(("Invalid auth type\n"));
+ return err;
+ }
+
+ err = wl_set_set_cipher(dev, sme);
+ if (unlikely(err)) {
+ WL_ERR(("Invalid ciper\n"));
+ return err;
+ }
+
+ err = wl_set_key_mgmt(dev, sme);
+ if (unlikely(err)) {
+ WL_ERR(("Invalid key mgmt\n"));
+ return err;
+ }
+
+ err = wl_set_set_sharedkey(dev, sme);
+ if (unlikely(err)) {
+ WL_ERR(("Invalid shared key\n"));
+ return err;
+ }
+
+ /*
+ * Join with specific BSSID and cached SSID
+ * If SSID is zero join based on BSSID only
+ */
+ join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
+ chan_cnt * sizeof(chanspec_t);
+ ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL);
+ if (ext_join_params == NULL) {
+ err = -ENOMEM;
+ wl_clr_drv_status(cfg, CONNECTING, dev);
+ goto exit;
+ }
+ ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len);
+ memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len);
+ wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID);
+ ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
+ /* increate dwell time to receive probe response or detect Beacon
+ * from target AP at a noisy air only during connect command
+ */
+ ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1;
+ ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
+ /* Set up join scan parameters */
+ ext_join_params->scan.scan_type = -1;
+ ext_join_params->scan.nprobes = chan_cnt ?
+ (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1;
+ ext_join_params->scan.home_time = -1;
+
+ if (sme->bssid)
+ memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN);
+ else
+ memcpy(&ext_join_params->assoc.bssid, &ether_bcast, ETH_ALEN);
+ ext_join_params->assoc.chanspec_num = chan_cnt;
+ if (chan_cnt) {
+ u16 channel, band, bw, ctl_sb;
+ chanspec_t chspec;
+ channel = cfg->channel;
+ band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G
+ : WL_CHANSPEC_BAND_5G;
+ bw = WL_CHANSPEC_BW_20;
+ ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
+ chspec = (channel | band | bw | ctl_sb);
+ ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
+ ext_join_params->assoc.chanspec_list[0] |= chspec;
+ ext_join_params->assoc.chanspec_list[0] =
+ wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]);
+ }
+ ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num);
+ if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
+ WL_INFO(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
+ ext_join_params->ssid.SSID_len));
+ }
+ wl_set_drv_status(cfg, CONNECTING, dev);
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ kfree(ext_join_params);
+ return BCME_ERROR;
+ }
+ err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size,
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+
+ WL_ERR(("Connecting with" MACDBG " channel (%d) ssid \"%s\", len (%d)\n\n",
+ MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)), cfg->channel,
+ ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len));
+
+ kfree(ext_join_params);
+ if (err) {
+ wl_clr_drv_status(cfg, CONNECTING, dev);
+ if (err == BCME_UNSUPPORTED) {
+ WL_DBG(("join iovar is not supported\n"));
+ goto set_ssid;
+ } else {
+ WL_ERR(("error (%d)\n", err));
+ goto exit;
+ }
+ } else
+ goto exit;
+
+set_ssid:
+ memset(&join_params, 0, sizeof(join_params));
+ join_params_size = sizeof(join_params.ssid);
+
+ join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len);
+ memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
+ join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
+ wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
+ if (sme->bssid)
+ memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN);
+ else
+ memcpy(&join_params.params.bssid, &ether_bcast, ETH_ALEN);
+
+ wl_ch_to_chanspec(cfg->channel, &join_params, &join_params_size);
+ WL_DBG(("join_param_size %zu\n", join_params_size));
+
+ if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
+ WL_INFO(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
+ join_params.ssid.SSID_len));
+ }
+ wl_set_drv_status(cfg, CONNECTING, dev);
+ err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true);
+ if (err) {
+ WL_ERR(("error (%d)\n", err));
+ wl_clr_drv_status(cfg, CONNECTING, dev);
+ }
+exit:
+ return err;
+}
+
+static s32
+wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ scb_val_t scbval;
+ bool act = false;
+ s32 err = 0;
+ u8 *curbssid;
+#ifdef CUSTOM_SET_CPUCORE
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+#endif /* CUSTOM_SET_CPUCORE */
+ WL_ERR(("Reason %d\n", reason_code));
+ RETURN_EIO_IF_NOT_UP(cfg);
+ act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT);
+ curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
+ if (act) {
+ /*
+ * Cancel ongoing scan to sync up with sme state machine of cfg80211.
+ */
+#if !defined(ESCAN_RESULT_PATCH)
+ /* Let scan aborted by F/W */
+ if (cfg->scan_request) {
+ wl_notify_escan_complete(cfg, dev, true, true);
+ }
+#endif /* ESCAN_RESULT_PATCH */
+ if (wl_get_drv_status(cfg, CONNECTING, dev) ||
+ wl_get_drv_status(cfg, CONNECTED, dev)) {
+ wl_set_drv_status(cfg, DISCONNECTING, dev);
+ scbval.val = reason_code;
+ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
+ scbval.val = htod32(scbval.val);
+ err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
+ sizeof(scb_val_t), true);
+ if (unlikely(err)) {
+ wl_clr_drv_status(cfg, DISCONNECTING, dev);
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+ }
+ }
+#ifdef CUSTOM_SET_CPUCORE
+ /* set default cpucore */
+ if (dev == bcmcfg_to_prmry_ndev(cfg)) {
+ dhd->chan_isvht80 &= ~DHD_FLAG_STA_MODE;
+ if (!(dhd->chan_isvht80))
+ dhd_set_cpucore(dhd, FALSE);
+ }
+#endif /* CUSTOM_SET_CPUCORE */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+ /* cfg80211 expects disconnect event from DHD to release wdev->current_bss */
+ CFG80211_DISCONNECTED(dev, reason_code, NULL, 0, false, GFP_KERNEL);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
+
+ return err;
+}
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+static s32
+wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+ enum nl80211_tx_power_setting type, s32 mbm)
+#else
+static s32
+wl_cfg80211_set_tx_power(struct wiphy *wiphy,
+ enum nl80211_tx_power_setting type, s32 dbm)
+#endif /* WL_CFG80211_P2P_DEV_IF */
+{
+
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ s32 err = 0;
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ s32 dbm = MBM_TO_DBM(mbm);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
+ defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES)
+ dbm = MBM_TO_DBM(dbm);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+ switch (type) {
+ case NL80211_TX_POWER_AUTOMATIC:
+ break;
+ case NL80211_TX_POWER_LIMITED:
+ if (dbm < 0) {
+ WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n"));
+ return -EINVAL;
+ }
+ break;
+ case NL80211_TX_POWER_FIXED:
+ if (dbm < 0) {
+ WL_ERR(("TX_POWER_FIXED - dbm is negative..\n"));
+ return -EINVAL;
+ }
+ break;
+ }
+
+ err = wl_set_tx_power(ndev, type, dbm);
+ if (unlikely(err)) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+
+ cfg->conf->tx_power = dbm;
+
+ return err;
+}
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
+ struct wireless_dev *wdev, s32 *dbm)
+#else
+static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
+#endif /* WL_CFG80211_P2P_DEV_IF */
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ s32 err = 0;
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+ err = wl_get_tx_power(ndev, dbm);
+ if (unlikely(err))
+ WL_ERR(("error (%d)\n", err));
+
+ return err;
+}
+
+static s32
+wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, bool unicast, bool multicast)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ u32 index;
+ s32 wsec;
+ s32 err = 0;
+ s32 bssidx;
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ return BCME_ERROR;
+ }
+
+ WL_DBG(("key index (%d)\n", key_idx));
+ RETURN_EIO_IF_NOT_UP(cfg);
+ err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
+ return err;
+ }
+ if (wsec == WEP_ENABLED) {
+ /* Just select a new current key */
+ index = (u32) key_idx;
+ index = htod32(index);
+ err = wldev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index,
+ sizeof(index), true);
+ if (unlikely(err)) {
+ WL_ERR(("error (%d)\n", err));
+ }
+ }
+ return err;
+}
+
+static s32
+wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, const u8 *mac_addr, struct key_params *params)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct wl_wsec_key key;
+ s32 err = 0;
+ s32 bssidx;
+ s32 mode = wl_get_mode_by_netdev(cfg, dev);
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ return BCME_ERROR;
+ }
+ memset(&key, 0, sizeof(key));
+ key.index = (u32) key_idx;
+
+ if (!ETHER_ISMULTI(mac_addr))
+ memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN);
+ key.len = (u32) params->key_len;
+
+ /* check for key index change */
+ if (key.len == 0) {
+ /* key delete */
+ swap_key_from_BE(&key);
+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("key delete error (%d)\n", err));
+ return err;
+ }
+ } else {
+ if (key.len > sizeof(key.data)) {
+ WL_ERR(("Invalid key length (%d)\n", key.len));
+ return -EINVAL;
+ }
+ WL_DBG(("Setting the key index %d\n", key.index));
+ memcpy(key.data, params->key, key.len);
+
+ if ((mode == WL_MODE_BSS) &&
+ (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
+ u8 keybuf[8];
+ memcpy(keybuf, &key.data[24], sizeof(keybuf));
+ memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
+ memcpy(&key.data[16], keybuf, sizeof(keybuf));
+ }
+
+ /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
+ if (params->seq && params->seq_len == 6) {
+ /* rx iv */
+ u8 *ivptr;
+ ivptr = (u8 *) params->seq;
+ key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
+ (ivptr[3] << 8) | ivptr[2];
+ key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
+ key.iv_initialized = true;
+ }
+
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key.algo = CRYPTO_ALGO_WEP1;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ key.algo = CRYPTO_ALGO_WEP128;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ key.algo = CRYPTO_ALGO_TKIP;
+ WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
+ break;
+ default:
+ WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
+ return -EINVAL;
+ }
+ swap_key_from_BE(&key);
+ /* need to guarantee EAPOL 4/4 send out before set key */
+ dhd_wait_pend8021x(dev);
+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ return err;
+ }
+ }
+ return err;
+}
+
+int
+wl_cfg80211_enable_roam_offload(struct net_device *dev, bool enable)
+{
+ int err;
+ wl_eventmsg_buf_t ev_buf;
+
+ if (dev != bcmcfg_to_prmry_ndev(g_bcm_cfg)) {
+ /* roam offload is only for the primary device */
+ return -1;
+ }
+ err = wldev_iovar_setint(dev, "roam_offload", (int)enable);
+ if (err)
+ return err;
+
+ bzero(&ev_buf, sizeof(wl_eventmsg_buf_t));
+ wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_PSK_SUP, !enable);
+ wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable);
+ wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable);
+ wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable);
+ wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable);
+ wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable);
+ err = wl_cfg80211_apply_eventbuffer(dev, g_bcm_cfg, &ev_buf);
+ if (!err) {
+ g_bcm_cfg->roam_offload = enable;
+ }
+ return err;
+}
+
+#if defined(WL_VIRTUAL_APSTA)
+int
+wl_cfg80211_interface_create(struct net_device *dev, char *name)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ bcm_struct_cfgdev *new_cfgdev;
+
+ new_cfgdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
+ NL80211_IFTYPE_STATION, NULL, name);
+ if (!new_cfgdev) {
+ return BCME_ERROR;
+ }
+ else {
+ WL_DBG(("Iface %s created successfuly\n", name));
+ return BCME_OK;
+ }
+}
+
+int
+wl_cfg80211_interface_delete(struct net_device *dev, char *name)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ struct net_info *iter, *next;
+ int err = BCME_ERROR;
+
+ if (name == NULL) {
+ WL_ERR(("Iface name is NULL.\n"));
+ return BCME_ERROR;
+ }
+
+ for_each_ndev(cfg, iter, next) {
+ if (iter->ndev) {
+ if (strcmp(iter->ndev->name, name) == 0) {
+ err = wl_cfg80211_del_iface(cfg->wdev->wiphy, cfg->bss_cfgdev);
+ break;
+ }
+ }
+ }
+ if (!err) {
+ WL_DBG(("Iface %s deleted successfuly", name));
+ }
+ return err;
+}
+#endif /* defined (WL_VIRTUAL_APSTA) */
+
+static s32
+wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr,
+ struct key_params *params)
+{
+ struct wl_wsec_key key;
+ s32 val = 0;
+ s32 wsec = 0;
+ s32 err = 0;
+ u8 keybuf[8];
+ s32 bssidx = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 mode = wl_get_mode_by_netdev(cfg, dev);
+ WL_DBG(("key index (%d)\n", key_idx));
+ RETURN_EIO_IF_NOT_UP(cfg);
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ return BCME_ERROR;
+ }
+
+ if (mac_addr &&
+ ((params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
+ (params->cipher != WLAN_CIPHER_SUITE_WEP104))) {
+ wl_add_keyext(wiphy, dev, key_idx, mac_addr, params);
+ goto exit;
+ }
+ memset(&key, 0, sizeof(key));
+
+ key.len = (u32) params->key_len;
+ key.index = (u32) key_idx;
+
+ if (unlikely(key.len > sizeof(key.data))) {
+ WL_ERR(("Too long key length (%u)\n", key.len));
+ return -EINVAL;
+ }
+ memcpy(key.data, params->key, key.len);
+
+ key.flags = WL_PRIMARY_KEY;
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key.algo = CRYPTO_ALGO_WEP1;
+ val = WEP_ENABLED;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ key.algo = CRYPTO_ALGO_WEP128;
+ val = WEP_ENABLED;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ key.algo = CRYPTO_ALGO_TKIP;
+ val = TKIP_ENABLED;
+ /* wpa_supplicant switches the third and fourth quarters of the TKIP key */
+ if (mode == WL_MODE_BSS) {
+ bcopy(&key.data[24], keybuf, sizeof(keybuf));
+ bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
+ bcopy(keybuf, &key.data[16], sizeof(keybuf));
+ }
+ WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ val = AES_ENABLED;
+ WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ val = AES_ENABLED;
+ WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
+ break;
+ default:
+ WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
+ return -EINVAL;
+ }
+
+ /* Set the new key/index */
+ if ((mode == WL_MODE_IBSS) && (val & (TKIP_ENABLED | AES_ENABLED))) {
+ WL_ERR(("IBSS KEY setted\n"));
+ wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_NONE);
+ }
+ swap_key_from_BE(&key);
+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
+ WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ return err;
+ }
+
+exit:
+ err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("get wsec error (%d)\n", err));
+ return err;
+ }
+
+ wsec |= val;
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("set wsec error (%d)\n", err));
+ return err;
+ }
+
+ return err;
+}
+
+static s32
+wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr)
+{
+ struct wl_wsec_key key;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 err = 0;
+ s32 bssidx;
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ return BCME_ERROR;
+ }
+ WL_DBG(("Enter\n"));
+
+ if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2))
+ return -EINVAL;
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+ memset(&key, 0, sizeof(key));
+
+ key.flags = WL_PRIMARY_KEY;
+ key.algo = CRYPTO_ALGO_OFF;
+ key.index = (u32) key_idx;
+
+ WL_DBG(("key index (%d)\n", key_idx));
+ /* Set the new key/index */
+ swap_key_from_BE(&key);
+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
+ WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ if (err == -EINVAL) {
+ if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
+ /* we ignore this key index in this case */
+ WL_DBG(("invalid key index (%d)\n", key_idx));
+ }
+ } else {
+ WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ }
+ return err;
+ }
+ return err;
+}
+
+static s32
+wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
+ void (*callback) (void *cookie, struct key_params * params))
+{
+ struct key_params params;
+ struct wl_wsec_key key;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct wl_security *sec;
+ s32 wsec;
+ s32 err = 0;
+ s32 bssidx;
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ return BCME_ERROR;
+ }
+ WL_DBG(("key index (%d)\n", key_idx));
+ RETURN_EIO_IF_NOT_UP(cfg);
+ memset(&key, 0, sizeof(key));
+ key.index = key_idx;
+ swap_key_to_BE(&key);
+ memset(&params, 0, sizeof(params));
+ params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len);
+ memcpy((void *)params.key, key.data, params.key_len);
+
+ err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
+ return err;
+ }
+ switch (wsec & ~SES_OW_ENABLED) {
+ case WEP_ENABLED:
+ sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
+ if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
+ params.cipher = WLAN_CIPHER_SUITE_WEP40;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
+ } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
+ params.cipher = WLAN_CIPHER_SUITE_WEP104;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
+ }
+ break;
+ case TKIP_ENABLED:
+ params.cipher = WLAN_CIPHER_SUITE_TKIP;
+ WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
+ break;
+ case AES_ENABLED:
+ params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
+ WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
+ break;
+ default:
+ WL_ERR(("Invalid algo (0x%x)\n", wsec));
+ return -EINVAL;
+ }
+
+ callback(cookie, &params);
+ return err;
+}
+
+static s32
+wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
+ struct net_device *dev, u8 key_idx)
+{
+ WL_DBG(("not supported"));
+ return -EOPNOTSUPP;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static s32
+wl_cfg80211_get_station(struct wiphy *wiphy,
+ struct net_device *dev, const u8 *mac,
+ struct station_info *sinfo)
+#else
+static s32
+wl_cfg80211_get_station(struct wiphy *wiphy,
+ struct net_device *dev, u8 *mac,
+ struct station_info *sinfo)
+#endif
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ scb_val_t scb_val;
+ s32 rssi;
+ s32 rate;
+ s32 err = 0;
+ sta_info_t *sta;
+ struct ether_addr bssid;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
+ s8 eabuf[ETHER_ADDR_STR_LEN];
+#endif
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+ RETURN_EIO_IF_NOT_UP(cfg);
+ if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
+ err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac,
+ ETHER_ADDR_LEN, cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
+ if (err < 0) {
+ WL_ERR(("GET STA INFO failed, %d\n", err));
+ return err;
+ }
+ sinfo->filled = STA_INFO_BIT(INFO_INACTIVE_TIME);
+ sta = (sta_info_t *)cfg->ioctl_buf;
+ sta->len = dtoh16(sta->len);
+ sta->cap = dtoh16(sta->cap);
+ sta->flags = dtoh32(sta->flags);
+ sta->idle = dtoh32(sta->idle);
+ sta->in = dtoh32(sta->in);
+ sinfo->inactive_time = sta->idle * 1000;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
+ if (sta->flags & WL_STA_ASSOC) {
+ sinfo->filled |= STA_INFO_BIT(INFO_CONNECTED_TIME);
+ sinfo->connected_time = sta->in;
+ }
+ WL_INFO(("STA %s : idle time : %d sec, connected time :%d ms\n",
+ bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time,
+ sta->idle * 1000));
+#endif
+ } else if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_BSS ||
+ wl_get_mode_by_netdev(cfg, dev) == WL_MODE_IBSS) {
+ get_pktcnt_t pktcnt;
+ u8 *curmacp;
+
+ if (cfg->roam_offload) {
+ err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+ if (err) {
+ WL_ERR(("Failed to get current BSSID\n"));
+ } else {
+ if (!ETHER_ISNULLADDR(&bssid.octet) &&
+ memcmp(mac, &bssid.octet, ETHER_ADDR_LEN) != 0) {
+ /* roaming is detected */
+ err = wl_cfg80211_delayed_roam(cfg, dev, &bssid);
+ if (err)
+ WL_ERR(("Failed to handle the delayed roam, "
+ "err=%d", err));
+ mac = (u8 *)bssid.octet;
+ }
+ }
+ }
+ if (!wl_get_drv_status(cfg, CONNECTED, dev) ||
+ (dhd_is_associated(dhd, 0, &err) == FALSE)) {
+ WL_ERR(("NOT assoc\n"));
+ if (err == -ERESTARTSYS)
+ return err;
+ err = -ENODEV;
+ return err;
+ }
+ curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID);
+ if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
+ WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n",
+ MAC2STRDBG(mac), MAC2STRDBG(curmacp)));
+ }
+
+ /* Report the current tx rate */
+ err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
+ if (err) {
+ WL_ERR(("Could not get rate (%d)\n", err));
+ } else {
+#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
+ int rxpktglom;
+#endif
+ rate = dtoh32(rate);
+ sinfo->filled |= STA_INFO_BIT(INFO_TX_BITRATE);
+ sinfo->txrate.legacy = rate * 5;
+ WL_DBG(("Rate %d Mbps\n", (rate / 2)));
+#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
+ rxpktglom = ((rate/2) > 150) ? 20 : 10;
+
+ if (maxrxpktglom != rxpktglom) {
+ maxrxpktglom = rxpktglom;
+ WL_DBG(("Rate %d Mbps, update bus:maxtxpktglom=%d\n", (rate/2),
+ maxrxpktglom));
+ err = wldev_iovar_setbuf(dev, "bus:maxtxpktglom",
+ (char*)&maxrxpktglom, 4, cfg->ioctl_buf,
+ WLC_IOCTL_MAXLEN, NULL);
+ if (err < 0) {
+ WL_ERR(("set bus:maxtxpktglom failed, %d\n", err));
+ }
+ }
+#endif
+ }
+
+ memset(&scb_val, 0, sizeof(scb_val));
+ scb_val.val = 0;
+ err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val,
+ sizeof(scb_val_t), false);
+ if (err) {
+ WL_ERR(("Could not get rssi (%d)\n", err));
+ goto get_station_err;
+ }
+ rssi = wl_rssi_offset(dtoh32(scb_val.val));
+ sinfo->filled |= STA_INFO_BIT(INFO_SIGNAL);
+ sinfo->signal = rssi;
+ WL_DBG(("RSSI %d dBm\n", rssi));
+ err = wldev_ioctl(dev, WLC_GET_PKTCNTS, &pktcnt,
+ sizeof(pktcnt), false);
+ if (!err) {
+ sinfo->filled |= (STA_INFO_BIT(INFO_RX_PACKETS) |
+ STA_INFO_BIT(INFO_RX_DROP_MISC) |
+ STA_INFO_BIT(INFO_TX_PACKETS) |
+ STA_INFO_BIT(INFO_TX_FAILED));
+ sinfo->rx_packets = pktcnt.rx_good_pkt;
+ sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt;
+ sinfo->tx_packets = pktcnt.tx_good_pkt;
+ sinfo->tx_failed = pktcnt.tx_bad_pkt;
+ }
+get_station_err:
+ if (err && (err != -ERESTARTSYS)) {
+ /* Disconnect due to zero BSSID or error to get RSSI */
+ WL_ERR(("force cfg80211_disconnected: %d\n", err));
+ wl_clr_drv_status(cfg, CONNECTED, dev);
+ CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
+ wl_link_down(cfg);
+ }
+ }
+ else {
+ WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg, dev)));
+ }
+
+ return err;
+}
+
+static s32
+wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ bool enabled, s32 timeout)
+{
+ s32 pm;
+ s32 err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev);
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+ WL_DBG(("Enter\n"));
+ if (cfg->p2p_net == dev || _net_info == NULL || cfg->vsdb_mode ||
+ !wl_get_drv_status(cfg, CONNECTED, dev)) {
+ return err;
+ }
+
+ /* Delete pm_enable_work */
+ wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_PEND);
+
+ pm = enabled ? PM_FAST : PM_OFF;
+ if (_net_info->pm_block) {
+ WL_ERR(("%s:Do not enable the power save for pm_block %d\n",
+ dev->name, _net_info->pm_block));
+ pm = PM_OFF;
+ }
+ pm = htod32(pm);
+ WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled")));
+ err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true);
+ if (unlikely(err)) {
+ if (err == -ENODEV)
+ WL_DBG(("net_device is not ready yet\n"));
+ else
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+ wl_cfg80211_update_power_mode(dev);
+ return err;
+}
+
+void wl_cfg80211_update_power_mode(struct net_device *dev)
+{
+ int err, pm = -1;
+
+ err = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), true);
+ if (err)
+ WL_ERR(("%s:error (%d)\n", __FUNCTION__, err));
+ else if (pm != -1 && dev->ieee80211_ptr)
+ dev->ieee80211_ptr->ps = (pm == PM_OFF) ? false : true;
+}
+
+static __used u32 wl_find_msb(u16 bit16)
+{
+ u32 ret = 0;
+
+ if (bit16 & 0xff00) {
+ ret += 8;
+ bit16 >>= 8;
+ }
+
+ if (bit16 & 0xf0) {
+ ret += 4;
+ bit16 >>= 4;
+ }
+
+ if (bit16 & 0xc) {
+ ret += 2;
+ bit16 >>= 2;
+ }
+
+ if (bit16 & 2)
+ ret += bit16 & 2;
+ else if (bit16)
+ ret += bit16;
+
+ return ret;
+}
+
+static s32 wl_cfg80211_resume(struct wiphy *wiphy)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ s32 err = BCME_OK;
+
+ if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
+ WL_INFO(("device is not ready\n"));
+ return err;
+ }
+
+
+ return err;
+}
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
+static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
+#else
+static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
+#endif
+{
+ s32 err = BCME_OK;
+#ifdef DHD_CLEAR_ON_SUSPEND
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_info *iter, *next;
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ unsigned long flags;
+ if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
+ WL_INFO(("device is not ready : status (%d)\n",
+ (int)cfg->status));
+ return err;
+ }
+ for_each_ndev(cfg, iter, next)
+ wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+ if (cfg->scan_request) {
+ struct cfg80211_scan_info info = {e
+ .aborted = true,
+ };
+
+ cfg80211_scan_done(cfg->scan_request, &info);
+ cfg->scan_request = NULL;
+ }
+ for_each_ndev(cfg, iter, next) {
+ wl_clr_drv_status(cfg, SCANNING, iter->ndev);
+ wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
+ }
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+ for_each_ndev(cfg, iter, next) {
+ if (wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
+ wl_bss_connect_done(cfg, iter->ndev, NULL, NULL, false);
+ }
+ }
+#endif /* DHD_CLEAR_ON_SUSPEND */
+
+
+ return err;
+}
+
+static s32
+wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
+ s32 err)
+{
+ int i, j;
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
+
+ if (!pmk_list) {
+ printk("pmk_list is NULL\n");
+ return -EINVAL;
+ }
+ /* pmk list is supported only for STA interface i.e. primary interface
+ * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
+ */
+ if (primary_dev != dev) {
+ WL_INFO(("Not supporting Flushing pmklist on virtual"
+ " interfaces than primary interface\n"));
+ return err;
+ }
+
+ WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid));
+ for (i = 0; i < pmk_list->pmkids.npmkid; i++) {
+ WL_DBG(("PMKID[%d]: %pM =\n", i,
+ &pmk_list->pmkids.pmkid[i].BSSID));
+ for (j = 0; j < WPA2_PMKID_LEN; j++) {
+ WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]));
+ }
+ }
+ if (likely(!err)) {
+ err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
+ sizeof(*pmk_list), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ }
+
+ return err;
+}
+
+static s32
+wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_pmksa *pmksa)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 err = 0;
+ int i;
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+ for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++)
+ if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
+ ETHER_ADDR_LEN))
+ break;
+ if (i < WL_NUM_PMKIDS_MAX) {
+ memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid,
+ ETHER_ADDR_LEN);
+ memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid,
+ WPA2_PMKID_LEN);
+ if (i == cfg->pmk_list->pmkids.npmkid)
+ cfg->pmk_list->pmkids.npmkid++;
+ } else {
+ err = -EINVAL;
+ }
+ WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
+ &cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1].BSSID));
+ for (i = 0; i < WPA2_PMKID_LEN; i++) {
+ WL_DBG(("%02x\n",
+ cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1].
+ PMKID[i]));
+ }
+
+ err = wl_update_pmklist(dev, cfg->pmk_list, err);
+
+ return err;
+}
+
+static s32
+wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_pmksa *pmksa)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct _pmkid_list pmkid = {0};
+ s32 err = 0;
+ int i;
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+ memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN);
+ memcpy(pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN);
+
+ WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
+ &pmkid.pmkid[0].BSSID));
+ for (i = 0; i < WPA2_PMKID_LEN; i++) {
+ WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i]));
+ }
+
+ for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++)
+ if (!memcmp
+ (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
+ ETHER_ADDR_LEN))
+ break;
+
+ if ((cfg->pmk_list->pmkids.npmkid > 0) &&
+ (i < cfg->pmk_list->pmkids.npmkid)) {
+ memset(&cfg->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t));
+ for (; i < (cfg->pmk_list->pmkids.npmkid - 1); i++) {
+ memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
+ &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
+ ETHER_ADDR_LEN);
+ memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
+ &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
+ WPA2_PMKID_LEN);
+ }
+ cfg->pmk_list->pmkids.npmkid--;
+ } else {
+ err = -EINVAL;
+ }
+
+ err = wl_update_pmklist(dev, cfg->pmk_list, err);
+
+ return err;
+
+}
+
+static s32
+wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 err = 0;
+ RETURN_EIO_IF_NOT_UP(cfg);
+ memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
+ err = wl_update_pmklist(dev, cfg->pmk_list, err);
+ return err;
+
+}
+
+static wl_scan_params_t *
+wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size)
+{
+ wl_scan_params_t *params;
+ int params_size;
+ int num_chans;
+
+ *out_params_size = 0;
+
+ /* Our scan params only need space for 1 channel and 0 ssids */
+ params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16);
+ params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL);
+ if (params == NULL) {
+ WL_ERR(("mem alloc failed (%d bytes)\n", params_size));
+ return params;
+ }
+ memset(params, 0, params_size);
+ params->nprobes = nprobes;
+
+ num_chans = (channel == 0) ? 0 : 1;
+
+ memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
+ params->bss_type = DOT11_BSSTYPE_ANY;
+ params->scan_type = DOT11_SCANTYPE_ACTIVE;
+ params->nprobes = htod32(1);
+ params->active_time = htod32(-1);
+ params->passive_time = htod32(-1);
+ params->home_time = htod32(10);
+ if (channel == -1)
+ params->channel_list[0] = htodchanspec(channel);
+ else
+ params->channel_list[0] = wl_ch_host_to_driver(channel);
+
+ /* Our scan params have 1 channel and 0 ssids */
+ params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
+ (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
+
+ *out_params_size = params_size; /* rtn size to the caller */
+ return params;
+}
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+static s32
+wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
+ struct ieee80211_channel *channel, unsigned int duration, u64 *cookie)
+#else
+static s32
+wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
+ struct ieee80211_channel * channel,
+ enum nl80211_channel_type channel_type,
+ unsigned int duration, u64 *cookie)
+#endif /* WL_CFG80211_P2P_DEV_IF */
+{
+ s32 target_channel;
+ u32 id;
+ s32 err = BCME_OK;
+ struct ether_addr primary_mac;
+ struct net_device *ndev = NULL;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ WL_DBG(("Enter, channel: %d, duration ms (%d) SCANNING ?? %s \n",
+ ieee80211_frequency_to_channel(channel->center_freq),
+ duration, (wl_get_drv_status(cfg, SCANNING, ndev)) ? "YES":"NO"));
+
+ if (!cfg->p2p) {
+ WL_ERR(("cfg->p2p is not initialized\n"));
+ err = BCME_ERROR;
+ goto exit;
+ }
+
+#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
+ }
+#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+
+ target_channel = ieee80211_frequency_to_channel(channel->center_freq);
+ memcpy(&cfg->remain_on_chan, channel, sizeof(struct ieee80211_channel));
+#if defined(WL_ENABLE_P2P_IF)
+ cfg->remain_on_chan_type = channel_type;
+#endif /* WL_ENABLE_P2P_IF */
+ id = ++cfg->last_roc_id;
+ if (id == 0)
+ id = ++cfg->last_roc_id;
+ *cookie = id;
+
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ if (wl_get_drv_status(cfg, SCANNING, ndev)) {
+ struct timer_list *_timer;
+ WL_DBG(("scan is running. go to fake listen state\n"));
+
+ if (duration > LONG_LISTEN_TIME) {
+ wl_cfg80211_scan_abort(cfg);
+ } else {
+ wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
+
+ if (timer_pending(&cfg->p2p->listen_timer)) {
+ WL_DBG(("cancel current listen timer \n"));
+ del_timer_sync(&cfg->p2p->listen_timer);
+ }
+
+ _timer = &cfg->p2p->listen_timer;
+ wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
+
+ INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0);
+
+ err = BCME_OK;
+ goto exit;
+ }
+ }
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+
+#ifdef WL_CFG80211_SYNC_GON
+ if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
+ /* do not enter listen mode again if we are in listen mode already for next af.
+ * remain on channel completion will be returned by waiting next af completion.
+ */
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
+#else
+ wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+ goto exit;
+ }
+#endif /* WL_CFG80211_SYNC_GON */
+ if (cfg->p2p && !cfg->p2p->on) {
+ /* In case of p2p_listen command, supplicant send remain_on_channel
+ * without turning on P2P
+ */
+ get_primary_mac(cfg, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(&primary_mac, &cfg->p2p->dev_addr, &cfg->p2p->int_addr);
+ p2p_on(cfg) = true;
+ }
+
+ if (p2p_is_on(cfg)) {
+ err = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
+ if (unlikely(err)) {
+ goto exit;
+ }
+#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
+#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+ err = wl_cfgp2p_discover_listen(cfg, target_channel, duration);
+
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ if (err == BCME_OK) {
+ wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
+ } else {
+ /* if failed, firmware may be internal scanning state.
+ * so other scan request shall not abort it
+ */
+ wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
+ }
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+ /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant
+ * and expire timer will send a completion to the upper layer
+ */
+ err = BCME_OK;
+ }
+
+exit:
+ if (err == BCME_OK) {
+ WL_INFO(("Success\n"));
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ cfg80211_ready_on_channel(cfgdev, *cookie, channel,
+ duration, GFP_KERNEL);
+#else
+ cfg80211_ready_on_channel(cfgdev, *cookie, channel,
+ channel_type, duration, GFP_KERNEL);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ } else {
+ WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie));
+ }
+ return err;
+}
+
+static s32
+wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
+ bcm_struct_cfgdev *cfgdev, u64 cookie)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 err = 0;
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
+ WL_DBG((" enter ) on P2P dedicated discover interface\n"));
+ }
+#else
+ WL_DBG((" enter ) netdev_ifidx: %d \n", cfgdev->ifindex));
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+ if (cfg->last_roc_id == cookie) {
+ wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
+ } else {
+ WL_ERR(("%s : ignore, request cookie(%llu) is not matched. (cur : %llu)\n",
+ __FUNCTION__, cookie, cfg->last_roc_id));
+ }
+
+ return err;
+}
+
+static void
+wl_cfg80211_afx_handler(struct work_struct *work)
+{
+ struct afx_hdl *afx_instance;
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ s32 ret = BCME_OK;
+
+ afx_instance = container_of(work, struct afx_hdl, work);
+ if (afx_instance != NULL && cfg->afx_hdl->is_active) {
+ if (cfg->afx_hdl->is_listen && cfg->afx_hdl->my_listen_chan) {
+ ret = wl_cfgp2p_discover_listen(cfg, cfg->afx_hdl->my_listen_chan,
+ (100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */
+ } else {
+ ret = wl_cfgp2p_act_frm_search(cfg, cfg->afx_hdl->dev,
+ cfg->afx_hdl->bssidx, cfg->afx_hdl->peer_listen_chan,
+ NULL);
+ }
+ if (unlikely(ret != BCME_OK)) {
+ WL_ERR(("ERROR occurred! returned value is (%d)\n", ret));
+ if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL))
+ complete(&cfg->act_frm_scan);
+ }
+ }
+}
+
+static s32
+wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg, struct net_device *dev)
+{
+ u32 max_retry = WL_CHANNEL_SYNC_RETRY;
+
+ if (dev == NULL)
+ return -1;
+
+ WL_DBG((" enter ) \n"));
+
+ wl_set_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
+ cfg->afx_hdl->is_active = TRUE;
+
+ /* Loop to wait until we find a peer's channel or the
+ * pending action frame tx is cancelled.
+ */
+ while ((cfg->afx_hdl->retry < max_retry) &&
+ (cfg->afx_hdl->peer_chan == WL_INVALID)) {
+ cfg->afx_hdl->is_listen = FALSE;
+ wl_set_drv_status(cfg, SCANNING, dev);
+ WL_DBG(("Scheduling the action frame for sending.. retry %d\n",
+ cfg->afx_hdl->retry));
+ /* search peer on peer's listen channel */
+ schedule_work(&cfg->afx_hdl->work);
+ wait_for_completion_timeout(&cfg->act_frm_scan,
+ msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
+
+ if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
+ !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
+ break;
+
+ if (cfg->afx_hdl->my_listen_chan) {
+ WL_DBG(("Scheduling Listen peer in my listen channel = %d\n",
+ cfg->afx_hdl->my_listen_chan));
+ /* listen on my listen channel */
+ cfg->afx_hdl->is_listen = TRUE;
+ schedule_work(&cfg->afx_hdl->work);
+ wait_for_completion_timeout(&cfg->act_frm_scan,
+ msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
+ }
+ if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
+ !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
+ break;
+
+ cfg->afx_hdl->retry++;
+
+ WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
+ }
+
+ cfg->afx_hdl->is_active = FALSE;
+
+ wl_clr_drv_status(cfg, SCANNING, dev);
+ wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
+
+ return (cfg->afx_hdl->peer_chan);
+}
+
+struct p2p_config_af_params {
+ s32 max_tx_retry; /* max tx retry count if tx no ack */
+ /* To make sure to send successfully action frame, we have to turn off mpc
+ * 0: off, 1: on, (-1): do nothing
+ */
+ s32 mpc_onoff;
+#ifdef WL_CFG80211_SYNC_GON
+ bool extra_listen;
+#endif
+ bool search_channel; /* 1: search peer's channel to send af */
+};
+
+static s32
+wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy,
+ wl_action_frame_t *action_frame, wl_af_params_t *af_params,
+ struct p2p_config_af_params *config_af_params)
+{
+ s32 err = BCME_OK;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ wifi_p2p_pub_act_frame_t *act_frm =
+ (wifi_p2p_pub_act_frame_t *) (action_frame->data);
+
+ /* initialize default value */
+#ifdef WL_CFG80211_SYNC_GON
+ config_af_params->extra_listen = true;
+#endif
+ config_af_params->search_channel = false;
+ config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY;
+ config_af_params->mpc_onoff = -1;
+ cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
+
+ switch (act_frm->subtype) {
+ case P2P_PAF_GON_REQ: {
+ WL_DBG(("P2P: GO_NEG_PHASE status set \n"));
+ wl_set_p2p_status(cfg, GO_NEG_PHASE);
+
+ config_af_params->mpc_onoff = 0;
+ config_af_params->search_channel = true;
+ cfg->next_af_subtype = act_frm->subtype + 1;
+
+ /* increase dwell time to wait for RESP frame */
+ af_params->dwell_time = WL_MED_DWELL_TIME;
+
+ break;
+ }
+ case P2P_PAF_GON_RSP: {
+ cfg->next_af_subtype = act_frm->subtype + 1;
+ /* increase dwell time to wait for CONF frame */
+ af_params->dwell_time = WL_MED_DWELL_TIME + 100;
+ break;
+ }
+ case P2P_PAF_GON_CONF: {
+ /* If we reached till GO Neg confirmation reset the filter */
+ WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
+ wl_clr_p2p_status(cfg, GO_NEG_PHASE);
+
+ /* turn on mpc again if go nego is done */
+ config_af_params->mpc_onoff = 1;
+
+ /* minimize dwell time */
+ af_params->dwell_time = WL_MIN_DWELL_TIME;
+
+#ifdef WL_CFG80211_SYNC_GON
+ config_af_params->extra_listen = false;
+#endif /* WL_CFG80211_SYNC_GON */
+ break;
+ }
+ case P2P_PAF_INVITE_REQ: {
+ config_af_params->search_channel = true;
+ cfg->next_af_subtype = act_frm->subtype + 1;
+
+ /* increase dwell time */
+ af_params->dwell_time = WL_MED_DWELL_TIME;
+ break;
+ }
+ case P2P_PAF_INVITE_RSP:
+ /* minimize dwell time */
+ af_params->dwell_time = WL_MIN_DWELL_TIME;
+#ifdef WL_CFG80211_SYNC_GON
+ config_af_params->extra_listen = false;
+#endif /* WL_CFG80211_SYNC_GON */
+ break;
+ case P2P_PAF_DEVDIS_REQ: {
+ if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
+ action_frame->len)) {
+ config_af_params->search_channel = true;
+ }
+
+ cfg->next_af_subtype = act_frm->subtype + 1;
+ /* maximize dwell time to wait for RESP frame */
+ af_params->dwell_time = WL_LONG_DWELL_TIME;
+ break;
+ }
+ case P2P_PAF_DEVDIS_RSP:
+ /* minimize dwell time */
+ af_params->dwell_time = WL_MIN_DWELL_TIME;
+#ifdef WL_CFG80211_SYNC_GON
+ config_af_params->extra_listen = false;
+#endif /* WL_CFG80211_SYNC_GON */
+ break;
+ case P2P_PAF_PROVDIS_REQ: {
+ if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
+ action_frame->len)) {
+ config_af_params->search_channel = true;
+ }
+
+ config_af_params->mpc_onoff = 0;
+ cfg->next_af_subtype = act_frm->subtype + 1;
+ /* increase dwell time to wait for RESP frame */
+ af_params->dwell_time = WL_MED_DWELL_TIME;
+ break;
+ }
+ case P2P_PAF_PROVDIS_RSP: {
+ cfg->next_af_subtype = P2P_PAF_GON_REQ;
+ af_params->dwell_time = WL_MIN_DWELL_TIME;
+#ifdef WL_CFG80211_SYNC_GON
+ config_af_params->extra_listen = false;
+#endif /* WL_CFG80211_SYNC_GON */
+ break;
+ }
+ default:
+ WL_DBG(("Unknown p2p pub act frame subtype: %d\n",
+ act_frm->subtype));
+ err = BCME_BADARG;
+ }
+ return err;
+}
+
+#ifdef WL11U
+static bool
+wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg, wl_af_params_t *af_params,
+ void *frame, u16 frame_len)
+{
+ struct wl_scan_results *bss_list;
+ struct wl_bss_info *bi = NULL;
+ bool result = false;
+ s32 i;
+ chanspec_t chanspec;
+
+ /* If DFS channel is 52~148, check to block it or not */
+ if (af_params &&
+ (af_params->channel >= 52 && af_params->channel <= 148)) {
+ if (!wl_cfgp2p_is_p2p_action(frame, frame_len)) {
+ bss_list = cfg->bss_list;
+ bi = next_bss(bss_list, bi);
+ for_each_bss(bss_list, bi, i) {
+ chanspec = wl_chspec_driver_to_host(bi->chanspec);
+ if (CHSPEC_IS5G(chanspec) &&
+ ((bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(chanspec))
+ == af_params->channel)) {
+ result = true; /* do not block the action frame */
+ break;
+ }
+ }
+ }
+ }
+ else {
+ result = true;
+ }
+
+ WL_DBG(("result=%s", result?"true":"false"));
+ return result;
+}
+#endif /* WL11U */
+
+
+static bool
+wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
+ bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params,
+ wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx)
+{
+#ifdef WL11U
+ struct net_device *ndev = NULL;
+#endif /* WL11U */
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ bool ack = false;
+ u8 category, action;
+ s32 tx_retry;
+ struct p2p_config_af_params config_af_params;
+#ifdef VSDB
+ ulong off_chan_started_jiffies = 0;
+#endif
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+
+ int32 requested_dwell = af_params->dwell_time;
+
+ /* Add the default dwell time
+ * Dwell time to stay off-channel to wait for a response action frame
+ * after transmitting an GO Negotiation action frame
+ */
+ af_params->dwell_time = WL_DWELL_TIME;
+
+#ifdef WL11U
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ ndev = dev;
+#else
+ ndev = ndev_to_cfgdev(cfgdev);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+#endif /* WL11U */
+
+ category = action_frame->data[DOT11_ACTION_CAT_OFF];
+ action = action_frame->data[DOT11_ACTION_ACT_OFF];
+
+ /* initialize variables */
+ tx_retry = 0;
+ cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
+ config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
+ config_af_params.mpc_onoff = -1;
+ config_af_params.search_channel = false;
+#ifdef WL_CFG80211_SYNC_GON
+ config_af_params.extra_listen = false;
+#endif
+
+ /* config parameters */
+ /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */
+ if (category == DOT11_ACTION_CAT_PUBLIC) {
+ if ((action == P2P_PUB_AF_ACTION) &&
+ (action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) {
+ /* p2p public action frame process */
+ if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy,
+ action_frame, af_params, &config_af_params)) {
+ WL_DBG(("Unknown subtype.\n"));
+ }
+
+ } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) {
+ /* service discovery process */
+ if (action == P2PSD_ACTION_ID_GAS_IREQ ||
+ action == P2PSD_ACTION_ID_GAS_CREQ) {
+ /* configure service discovery query frame */
+
+ config_af_params.search_channel = true;
+
+ /* save next af suptype to cancel remained dwell time */
+ cfg->next_af_subtype = action + 1;
+
+ af_params->dwell_time = WL_MED_DWELL_TIME;
+ if (requested_dwell & CUSTOM_RETRY_MASK) {
+ config_af_params.max_tx_retry =
+ (requested_dwell & CUSTOM_RETRY_MASK) >> 24;
+ af_params->dwell_time =
+ (requested_dwell & ~CUSTOM_RETRY_MASK);
+ WL_DBG(("Custom retry(%d) and dwell time(%d) is set.\n",
+ config_af_params.max_tx_retry,
+ af_params->dwell_time));
+ }
+ } else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
+ action == P2PSD_ACTION_ID_GAS_CRESP) {
+ /* configure service discovery response frame */
+ af_params->dwell_time = WL_MIN_DWELL_TIME;
+ } else {
+ WL_DBG(("Unknown action type: %d\n", action));
+ }
+ } else {
+ WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n",
+ category, action, action_frame_len));
+ }
+ } else if (category == P2P_AF_CATEGORY) {
+ /* do not configure anything. it will be sent with a default configuration */
+ } else {
+ WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n",
+ category, action));
+ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
+ wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
+ return false;
+ }
+ }
+
+ /* To make sure to send successfully action frame, we have to turn off mpc */
+ if (config_af_params.mpc_onoff == 0) {
+ wldev_iovar_setint(dev, "mpc", 0);
+ }
+
+ /* validate channel and p2p ies */
+ if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) &&
+ wl_to_p2p_bss_saved_ie(cfg, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) {
+ config_af_params.search_channel = true;
+ } else {
+ config_af_params.search_channel = false;
+ }
+#ifdef WL11U
+ if (ndev == bcmcfg_to_prmry_ndev(cfg))
+ config_af_params.search_channel = false;
+#endif /* WL11U */
+
+#ifdef VSDB
+ /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */
+ if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {
+ OSL_SLEEP(50);
+ }
+#endif
+
+ /* if scan is ongoing, abort current scan. */
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
+ }
+
+ /* Abort P2P listen */
+ if (discover_cfgdev(cfgdev, cfg)) {
+ if (cfg->p2p_supported && cfg->p2p) {
+ wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
+ }
+ }
+
+#ifdef WL11U
+ /* handling DFS channel exceptions */
+ if (!wl_cfg80211_check_DFS_channel(cfg, af_params, action_frame->data, action_frame->len)) {
+ return false; /* the action frame was blocked */
+ }
+#endif /* WL11U */
+
+ /* set status and destination address before sending af */
+ if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
+ /* set this status to cancel the remained dwell time in rx process */
+ wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
+ }
+ wl_set_drv_status(cfg, SENDING_ACT_FRM, dev);
+ memcpy(cfg->afx_hdl->tx_dst_addr.octet,
+ af_params->action_frame.da.octet,
+ sizeof(cfg->afx_hdl->tx_dst_addr.octet));
+
+ /* save af_params for rx process */
+ cfg->afx_hdl->pending_tx_act_frm = af_params;
+
+ if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len)) {
+ WL_DBG(("Set GAS action frame config.\n"));
+ config_af_params.search_channel = false;
+ config_af_params.max_tx_retry = 1;
+ }
+
+ /* search peer's channel */
+ if (config_af_params.search_channel) {
+ /* initialize afx_hdl */
+ if ((cfg->afx_hdl->bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ goto exit;
+ }
+ cfg->afx_hdl->dev = dev;
+ cfg->afx_hdl->retry = 0;
+ cfg->afx_hdl->peer_chan = WL_INVALID;
+
+ if (wl_cfg80211_af_searching_channel(cfg, dev) == WL_INVALID) {
+ WL_ERR(("couldn't find peer's channel.\n"));
+ wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len,
+ af_params->channel);
+ goto exit;
+ }
+
+ wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
+ /*
+ * Abort scan even for VSDB scenarios. Scan gets aborted in firmware
+ * but after the check of piggyback algorithm.
+ * To take care of current piggback algo, lets abort the scan here itself.
+ */
+ wl_notify_escan_complete(cfg, dev, true, true);
+ /* Suspend P2P discovery's search-listen to prevent it from
+ * starting a scan or changing the channel.
+ */
+ wl_cfgp2p_discover_enable_search(cfg, false);
+
+ /* update channel */
+ af_params->channel = cfg->afx_hdl->peer_chan;
+ }
+
+#ifdef VSDB
+ off_chan_started_jiffies = jiffies;
+#endif /* VSDB */
+
+ wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, af_params->channel);
+
+ wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len, true);
+
+ /* Now send a tx action frame */
+ ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false : true;
+
+ /* if failed, retry it. tx_retry_max value is configure by .... */
+ while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry)) {
+#ifdef VSDB
+ if (af_params->channel) {
+ if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) >
+ OFF_CHAN_TIME_THRESHOLD_MS) {
+ WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
+ off_chan_started_jiffies = jiffies;
+ } else
+ OSL_SLEEP(AF_RETRY_DELAY_TIME);
+ }
+#endif /* VSDB */
+ ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ?
+ false : true;
+ }
+
+ if (ack == false) {
+ WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry));
+ }
+ WL_DBG(("Complete to send action frame\n"));
+exit:
+ /* Clear SENDING_ACT_FRM after all sending af is done */
+ wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
+
+#ifdef WL_CFG80211_SYNC_GON
+ /* WAR: sometimes dongle does not keep the dwell time of 'actframe'.
+ * if we coundn't get the next action response frame and dongle does not keep
+ * the dwell time, go to listen state again to get next action response frame.
+ */
+ if (ack && config_af_params.extra_listen &&
+ wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM) &&
+ cfg->af_sent_channel == cfg->afx_hdl->my_listen_chan) {
+ s32 extar_listen_time;
+
+ extar_listen_time = af_params->dwell_time -
+ jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies);
+
+ if (extar_listen_time > 50) {
+ wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
+ WL_DBG(("Wait more time! actual af time:%d,"
+ "calculated extar listen:%d\n",
+ af_params->dwell_time, extar_listen_time));
+ if (wl_cfgp2p_discover_listen(cfg, cfg->af_sent_channel,
+ extar_listen_time + 100) == BCME_OK) {
+ wait_for_completion_timeout(&cfg->wait_next_af,
+ msecs_to_jiffies(extar_listen_time + 100 + 300));
+ }
+ wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
+ }
+ }
+#endif /* WL_CFG80211_SYNC_GON */
+ wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
+
+ if (cfg->afx_hdl->pending_tx_act_frm)
+ cfg->afx_hdl->pending_tx_act_frm = NULL;
+
+ WL_INFO(("-- sending Action Frame is %s, listen chan: %d\n",
+ (ack) ? "Succeeded!!":"Failed!!", cfg->afx_hdl->my_listen_chan));
+
+
+ /* if all done, turn mpc on again */
+ if (config_af_params.mpc_onoff == 1) {
+ wldev_iovar_setint(dev, "mpc", 1);
+ }
+
+ return ack;
+}
+
+#define MAX_NUM_OF_ASSOCIATED_DEV 64
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+static s32
+wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
+ struct cfg80211_mgmt_tx_params *params, u64 *cookie)
+#else
+static s32
+wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
+ struct ieee80211_channel *channel, bool offchan,
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0))
+ enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) */
+ unsigned int wait, const u8* buf, size_t len,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+ bool no_cck,
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+ bool dont_wait_for_ack,
+#endif
+ u64 *cookie)
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
+{
+ wl_action_frame_t *action_frame;
+ wl_af_params_t *af_params;
+ scb_val_t scb_val;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+ struct ieee80211_channel *channel = params->chan;
+ const u8 *buf = params->buf;
+ size_t len = params->len;
+#endif
+ const struct ieee80211_mgmt *mgmt;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *dev = NULL;
+ s32 err = BCME_OK;
+ s32 bssidx = 0;
+ u32 id;
+ bool ack = false;
+ s8 eabuf[ETHER_ADDR_STR_LEN];
+
+ WL_DBG(("Enter \n"));
+
+ dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */
+ if (discover_cfgdev(cfgdev, cfg)) {
+ bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+ }
+ else {
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, ndev_to_wdev(dev))) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ return BCME_ERROR;
+ }
+ }
+
+ WL_DBG(("TX target bssidx=%d\n", bssidx));
+
+ if (p2p_is_on(cfg)) {
+ /* Suspend P2P discovery search-listen to prevent it from changing the
+ * channel.
+ */
+ if ((err = wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
+ WL_ERR(("Can not disable discovery mode\n"));
+ return -EFAULT;
+ }
+ }
+ *cookie = 0;
+ id = cfg->send_action_id++;
+ if (id == 0)
+ id = cfg->send_action_id++;
+ *cookie = id;
+ mgmt = (const struct ieee80211_mgmt *)buf;
+ if (ieee80211_is_mgmt(mgmt->frame_control)) {
+ if (ieee80211_is_probe_resp(mgmt->frame_control)) {
+ s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
+ s32 ie_len = len - ie_offset;
+#ifdef P2PONEINT
+ if (dev == wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION))
+ dev = bcmcfg_to_prmry_ndev(cfg);
+#endif
+ if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) {
+ bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+ }
+ wl_cfg80211_set_mgmt_vndr_ies(cfg, dev, bssidx,
+ VNDR_IE_PRBRSP_FLAG, (u8 *)(buf + ie_offset), ie_len);
+ cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
+ goto exit;
+ } else if (ieee80211_is_disassoc(mgmt->frame_control) ||
+ ieee80211_is_deauth(mgmt->frame_control)) {
+ char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
+ sizeof(struct ether_addr) + sizeof(uint)] = {0};
+ int num_associated = 0;
+ struct maclist *assoc_maclist = (struct maclist *)mac_buf;
+ if (!bcmp((const uint8 *)BSSID_BROADCAST,
+ (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) {
+ assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
+ err = wldev_ioctl(dev, WLC_GET_ASSOCLIST,
+ assoc_maclist, sizeof(mac_buf), false);
+ if (err < 0)
+ WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
+ else
+ num_associated = assoc_maclist->count;
+ }
+ memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN);
+ scb_val.val = mgmt->u.disassoc.reason_code;
+ err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
+ sizeof(scb_val_t), true);
+ if (err < 0)
+ WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err));
+ WL_ERR(("Disconnect STA : %s scb_val.val %d\n",
+ bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf),
+ scb_val.val));
+
+ if (num_associated > 0 && ETHER_ISBCAST(mgmt->da))
+ wl_delay(400);
+
+ cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
+ goto exit;
+
+ } else if (ieee80211_is_action(mgmt->frame_control)) {
+ /* Abort the dwell time of any previous off-channel
+ * action frame that may be still in effect. Sending
+ * off-channel action frames relies on the driver's
+ * scan engine. If a previous off-channel action frame
+ * tx is still in progress (including the dwell time),
+ * then this new action frame will not be sent out.
+ */
+/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary.
+ * And previous off-channel action frame must be ended before new af tx.
+ */
+#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ wl_notify_escan_complete(cfg, dev, true, true);
+#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+ }
+
+ } else {
+ WL_ERR(("Driver only allows MGMT packet type\n"));
+ goto exit;
+ }
+
+ af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL);
+
+ if (af_params == NULL)
+ {
+ WL_ERR(("unable to allocate frame\n"));
+ return -ENOMEM;
+ }
+
+ action_frame = &af_params->action_frame;
+
+ /* Add the packet Id */
+ action_frame->packetId = *cookie;
+ WL_DBG(("action frame %d\n", action_frame->packetId));
+ /* Add BSSID */
+ memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN);
+ memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN);
+
+ /* Add the length exepted for 802.11 header */
+ action_frame->len = len - DOT11_MGMT_HDR_LEN;
+ WL_DBG(("action_frame->len: %d\n", action_frame->len));
+
+ /* Add the channel */
+ af_params->channel =
+ ieee80211_frequency_to_channel(channel->center_freq);
+ /* Save listen_chan for searching common channel */
+ cfg->afx_hdl->peer_listen_chan = af_params->channel;
+ WL_DBG(("channel from upper layer %d\n", cfg->afx_hdl->peer_listen_chan));
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+ af_params->dwell_time = params->wait;
+#else
+ af_params->dwell_time = wait;
+#endif
+
+ memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
+
+ ack = wl_cfg80211_send_action_frame(wiphy, dev, cfgdev, af_params,
+ action_frame, action_frame->len, bssidx);
+ cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
+
+ kfree(af_params);
+exit:
+ return err;
+}
+
+
+static void
+wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
+ u16 frame_type, bool reg)
+{
+
+ WL_DBG(("frame_type: %x, reg: %d\n", frame_type, reg));
+
+ if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
+ return;
+
+ return;
+}
+
+
+static s32
+wl_cfg80211_change_bss(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct bss_parameters *params)
+{
+ s32 err = 0;
+ s32 ap_isolate = 0;
+
+ if (params->use_cts_prot >= 0) {
+ }
+
+ if (params->use_short_preamble >= 0) {
+ }
+
+ if (params->use_short_slot_time >= 0) {
+ }
+
+ if (params->basic_rates) {
+ }
+
+ if (params->ap_isolate >= 0) {
+ ap_isolate = params->ap_isolate;
+ err = wldev_iovar_setint(dev, "ap_isolate", ap_isolate);
+ if (unlikely(err))
+ {
+ WL_ERR(("set ap_isolate Error (%d)\n", err));
+ }
+ }
+
+ if (params->ht_opmode >= 0) {
+ }
+
+
+ return 0;
+}
+
+static s32
+wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ s32 _chan;
+ chanspec_t chspec = 0;
+ chanspec_t fw_chspec = 0;
+ u32 bw = WL_CHANSPEC_BW_20;
+
+ s32 err = BCME_OK;
+ s32 bw_cap = 0;
+ struct {
+ u32 band;
+ u32 bw_cap;
+ } param = {0, 0};
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+#ifdef CUSTOM_SET_CPUCORE
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+#endif /* CUSTOM_SET_CPUCORE */
+
+#ifndef P2PONEINT
+ dev = ndev_to_wlc_ndev(dev, cfg);
+#endif
+ _chan = ieee80211_frequency_to_channel(chan->center_freq);
+ WL_ERR(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
+ dev->ifindex, channel_type, _chan));
+
+
+ if (chan->band == NL80211_BAND_5GHZ) {
+ param.band = WLC_BAND_5G;
+ err = wldev_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
+ cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
+ if (err) {
+ if (err != BCME_UNSUPPORTED) {
+ WL_ERR(("bw_cap failed, %d\n", err));
+ return err;
+ } else {
+ err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
+ if (err) {
+ WL_ERR(("error get mimo_bw_cap (%d)\n", err));
+ }
+ if (bw_cap != WLC_N_BW_20ALL)
+ bw = WL_CHANSPEC_BW_40;
+ }
+ } else {
+ if (WL_BW_CAP_80MHZ(cfg->ioctl_buf[0]))
+ bw = WL_CHANSPEC_BW_80;
+ else if (WL_BW_CAP_40MHZ(cfg->ioctl_buf[0]))
+ bw = WL_CHANSPEC_BW_40;
+ else
+ bw = WL_CHANSPEC_BW_20;
+
+ }
+
+ } else if (chan->band == NL80211_BAND_2GHZ)
+ bw = WL_CHANSPEC_BW_20;
+set_channel:
+ chspec = wf_channel2chspec(_chan, bw);
+ if (wf_chspec_valid(chspec)) {
+ fw_chspec = wl_chspec_host_to_driver(chspec);
+ if (fw_chspec != INVCHANSPEC) {
+ if ((err = wldev_iovar_setint(dev, "chanspec",
+ fw_chspec)) == BCME_BADCHAN) {
+ if (bw == WL_CHANSPEC_BW_80)
+ goto change_bw;
+ err = wldev_ioctl(dev, WLC_SET_CHANNEL,
+ &_chan, sizeof(_chan), true);
+ if (err < 0) {
+ WL_ERR(("WLC_SET_CHANNEL error %d"
+ "chip may not be supporting this channel\n", err));
+ }
+ } else if (err) {
+ WL_ERR(("failed to set chanspec error %d\n", err));
+ }
+ } else {
+ WL_ERR(("failed to convert host chanspec to fw chanspec\n"));
+ err = BCME_ERROR;
+ }
+ } else {
+change_bw:
+ if (bw == WL_CHANSPEC_BW_80)
+ bw = WL_CHANSPEC_BW_40;
+ else if (bw == WL_CHANSPEC_BW_40)
+ bw = WL_CHANSPEC_BW_20;
+ else
+ bw = 0;
+ if (bw)
+ goto set_channel;
+ WL_ERR(("Invalid chanspec 0x%x\n", chspec));
+ err = BCME_ERROR;
+ }
+#ifdef CUSTOM_SET_CPUCORE
+ if (dhd->op_mode == DHD_FLAG_HOSTAP_MODE) {
+ WL_DBG(("SoftAP mode do not need to set cpucore\n"));
+ } else if (chspec & WL_CHANSPEC_BW_80) {
+ /* SoftAp only mode do not need to set cpucore */
+ if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) &&
+ dev != bcmcfg_to_prmry_ndev(cfg)) {
+ /* Soft AP on virtual Iface (AP+STA case) */
+ dhd->chan_isvht80 |= DHD_FLAG_HOSTAP_MODE;
+ dhd_set_cpucore(dhd, TRUE);
+ } else if (is_p2p_group_iface(dev->ieee80211_ptr)) {
+ /* If P2P IF is vht80 */
+ dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE;
+ dhd_set_cpucore(dhd, TRUE);
+ }
+ }
+#endif
+ return err;
+}
+
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+struct net_device *
+wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg)
+{
+ struct net_info *_net_info, *next;
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ if (_net_info->ndev &&
+ test_bit(WL_STATUS_REMAINING_ON_CHANNEL, &_net_info->sme_state))
+ return _net_info->ndev;
+ }
+ return NULL;
+}
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+
+static s32
+wl_validate_opensecurity(struct net_device *dev, s32 bssidx)
+{
+ s32 err = BCME_OK;
+
+ /* set auth */
+ err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx);
+ if (err < 0) {
+ WL_ERR(("auth error %d\n", err));
+ return BCME_ERROR;
+ }
+ /* set wsec */
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx);
+ if (err < 0) {
+ WL_ERR(("wsec error %d\n", err));
+ return BCME_ERROR;
+ }
+
+ /* set upper-layer auth */
+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", WPA_AUTH_NONE, bssidx);
+ if (err < 0) {
+ WL_ERR(("wpa_auth error %d\n", err));
+ return BCME_ERROR;
+ }
+
+ return 0;
+}
+
+static s32
+wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
+{
+ s32 len = 0;
+ s32 err = BCME_OK;
+ u16 auth = 0; /* d11 open authentication */
+ u32 wsec;
+ u32 pval = 0;
+ u32 gval = 0;
+ u32 wpa_auth = 0;
+ wpa_suite_mcast_t *mcast;
+ wpa_suite_ucast_t *ucast;
+ wpa_suite_auth_key_mgmt_t *mgmt;
+ int cnt = 0;
+
+ u16 suite_count;
+ u8 rsn_cap[2];
+ u32 wme_bss_disable;
+
+ if (wpa2ie == NULL)
+ goto exit;
+
+ WL_DBG(("Enter \n"));
+ len = wpa2ie->len;
+ /* check the mcast cipher */
+ mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
+ switch (mcast->type) {
+ case WPA_CIPHER_NONE:
+ gval = 0;
+ break;
+ case WPA_CIPHER_WEP_40:
+ case WPA_CIPHER_WEP_104:
+ gval = WEP_ENABLED;
+ break;
+ case WPA_CIPHER_TKIP:
+ gval = TKIP_ENABLED;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ gval = AES_ENABLED;
+ break;
+ default:
+ WL_ERR(("No Security Info\n"));
+ break;
+ }
+ if ((len -= WPA_SUITE_LEN) <= 0)
+ return BCME_BADLEN;
+
+ /* check the unicast cipher */
+ ucast = (wpa_suite_ucast_t *)&mcast[1];
+ suite_count = ltoh16_ua(&ucast->count);
+ switch (ucast->list[0].type) {
+ case WPA_CIPHER_NONE:
+ pval = 0;
+ break;
+ case WPA_CIPHER_WEP_40:
+ case WPA_CIPHER_WEP_104:
+ pval = WEP_ENABLED;
+ break;
+ case WPA_CIPHER_TKIP:
+ pval = TKIP_ENABLED;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ pval = AES_ENABLED;
+ break;
+ default:
+ WL_ERR(("No Security Info\n"));
+ }
+ if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0)
+ return BCME_BADLEN;
+
+ /* FOR WPS , set SEC_OW_ENABLED */
+ wsec = (pval | gval | SES_OW_ENABLED);
+ /* check the AKM */
+ mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
+ suite_count = cnt = ltoh16_ua(&mgmt->count);
+ while (cnt--) {
+ switch (mgmt->list[cnt].type) {
+ case RSN_AKM_NONE:
+ wpa_auth |= WPA_AUTH_NONE;
+ break;
+ case RSN_AKM_UNSPECIFIED:
+ wpa_auth |= WPA2_AUTH_UNSPECIFIED;
+ break;
+ case RSN_AKM_PSK:
+ wpa_auth |= WPA2_AUTH_PSK;
+ break;
+ default:
+ WL_ERR(("No Key Mgmt Info\n"));
+ }
+ }
+
+ if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
+ rsn_cap[0] = *(u8 *)&mgmt->list[suite_count];
+ rsn_cap[1] = *((u8 *)&mgmt->list[suite_count] + 1);
+
+ if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
+ wme_bss_disable = 0;
+ } else {
+ wme_bss_disable = 1;
+ }
+
+
+ /* set wme_bss_disable to sync RSN Capabilities */
+ err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx);
+ if (err < 0) {
+ WL_ERR(("wme_bss_disable error %d\n", err));
+ return BCME_ERROR;
+ }
+ } else {
+ WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
+ }
+
+ /* set auth */
+ err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
+ if (err < 0) {
+ WL_ERR(("auth error %d\n", err));
+ return BCME_ERROR;
+ }
+
+ /* set wsec */
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
+ if (err < 0) {
+ WL_ERR(("wsec error %d\n", err));
+ return BCME_ERROR;
+ }
+
+
+ /* set upper-layer auth */
+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
+ if (err < 0) {
+ WL_ERR(("wpa_auth error %d\n", err));
+ return BCME_ERROR;
+ }
+exit:
+ return 0;
+}
+
+static s32
+wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx)
+{
+ wpa_suite_mcast_t *mcast;
+ wpa_suite_ucast_t *ucast;
+ wpa_suite_auth_key_mgmt_t *mgmt;
+ u16 auth = 0; /* d11 open authentication */
+ u16 count;
+ s32 err = BCME_OK;
+ s32 len = 0;
+ u32 i;
+ u32 wsec;
+ u32 pval = 0;
+ u32 gval = 0;
+ u32 wpa_auth = 0;
+ u32 tmp = 0;
+
+ if (wpaie == NULL)
+ goto exit;
+ WL_DBG(("Enter \n"));
+ len = wpaie->length; /* value length */
+ len -= WPA_IE_TAG_FIXED_LEN;
+ /* check for multicast cipher suite */
+ if (len < WPA_SUITE_LEN) {
+ WL_INFO(("no multicast cipher suite\n"));
+ goto exit;
+ }
+
+ /* pick up multicast cipher */
+ mcast = (wpa_suite_mcast_t *)&wpaie[1];
+ len -= WPA_SUITE_LEN;
+ if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
+ if (IS_WPA_CIPHER(mcast->type)) {
+ tmp = 0;
+ switch (mcast->type) {
+ case WPA_CIPHER_NONE:
+ tmp = 0;
+ break;
+ case WPA_CIPHER_WEP_40:
+ case WPA_CIPHER_WEP_104:
+ tmp = WEP_ENABLED;
+ break;
+ case WPA_CIPHER_TKIP:
+ tmp = TKIP_ENABLED;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ tmp = AES_ENABLED;
+ break;
+ default:
+ WL_ERR(("No Security Info\n"));
+ }
+ gval |= tmp;
+ }
+ }
+ /* Check for unicast suite(s) */
+ if (len < WPA_IE_SUITE_COUNT_LEN) {
+ WL_INFO(("no unicast suite\n"));
+ goto exit;
+ }
+ /* walk thru unicast cipher list and pick up what we recognize */
+ ucast = (wpa_suite_ucast_t *)&mcast[1];
+ count = ltoh16_ua(&ucast->count);
+ len -= WPA_IE_SUITE_COUNT_LEN;
+ for (i = 0; i < count && len >= WPA_SUITE_LEN;
+ i++, len -= WPA_SUITE_LEN) {
+ if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
+ if (IS_WPA_CIPHER(ucast->list[i].type)) {
+ tmp = 0;
+ switch (ucast->list[i].type) {
+ case WPA_CIPHER_NONE:
+ tmp = 0;
+ break;
+ case WPA_CIPHER_WEP_40:
+ case WPA_CIPHER_WEP_104:
+ tmp = WEP_ENABLED;
+ break;
+ case WPA_CIPHER_TKIP:
+ tmp = TKIP_ENABLED;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ tmp = AES_ENABLED;
+ break;
+ default:
+ WL_ERR(("No Security Info\n"));
+ }
+ pval |= tmp;
+ }
+ }
+ }
+ len -= (count - i) * WPA_SUITE_LEN;
+ /* Check for auth key management suite(s) */
+ if (len < WPA_IE_SUITE_COUNT_LEN) {
+ WL_INFO((" no auth key mgmt suite\n"));
+ goto exit;
+ }
+ /* walk thru auth management suite list and pick up what we recognize */
+ mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
+ count = ltoh16_ua(&mgmt->count);
+ len -= WPA_IE_SUITE_COUNT_LEN;
+ for (i = 0; i < count && len >= WPA_SUITE_LEN;
+ i++, len -= WPA_SUITE_LEN) {
+ if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
+ if (IS_WPA_AKM(mgmt->list[i].type)) {
+ tmp = 0;
+ switch (mgmt->list[i].type) {
+ case RSN_AKM_NONE:
+ tmp = WPA_AUTH_NONE;
+ break;
+ case RSN_AKM_UNSPECIFIED:
+ tmp = WPA_AUTH_UNSPECIFIED;
+ break;
+ case RSN_AKM_PSK:
+ tmp = WPA_AUTH_PSK;
+ break;
+ default:
+ WL_ERR(("No Key Mgmt Info\n"));
+ }
+ wpa_auth |= tmp;
+ }
+ }
+
+ }
+ /* FOR WPS , set SEC_OW_ENABLED */
+ wsec = (pval | gval | SES_OW_ENABLED);
+ /* set auth */
+ err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
+ if (err < 0) {
+ WL_ERR(("auth error %d\n", err));
+ return BCME_ERROR;
+ }
+ /* set wsec */
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
+ if (err < 0) {
+ WL_ERR(("wsec error %d\n", err));
+ return BCME_ERROR;
+ }
+ /* set upper-layer auth */
+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
+ if (err < 0) {
+ WL_ERR(("wpa_auth error %d\n", err));
+ return BCME_ERROR;
+ }
+exit:
+ return 0;
+}
+
+
+static s32
+wl_cfg80211_bcn_validate_sec(
+ struct net_device *dev,
+ struct parsed_ies *ies,
+ u32 dev_role,
+ s32 bssidx)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
+
+ if (!bss) {
+ WL_ERR(("cfgbss is NULL \n"));
+ return BCME_ERROR;
+ }
+
+ if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) {
+ /* For P2P GO, the sec type is WPA2-PSK */
+ WL_DBG(("P2P GO: validating wpa2_ie"));
+ if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0)
+ return BCME_ERROR;
+
+ } else if (dev_role == NL80211_IFTYPE_AP) {
+
+ WL_DBG(("SoftAP: validating security"));
+ /* If wpa2_ie or wpa_ie is present validate it */
+
+ if ((ies->wpa2_ie || ies->wpa_ie) &&
+ ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
+ wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) {
+ bss->security_mode = false;
+ return BCME_ERROR;
+ }
+
+ bss->security_mode = true;
+ if (bss->rsn_ie) {
+ kfree(bss->rsn_ie);
+ bss->rsn_ie = NULL;
+ }
+ if (bss->wpa_ie) {
+ kfree(bss->wpa_ie);
+ bss->wpa_ie = NULL;
+ }
+ if (bss->wps_ie) {
+ kfree(bss->wps_ie);
+ bss->wps_ie = NULL;
+ }
+ if (ies->wpa_ie != NULL) {
+ /* WPAIE */
+ bss->rsn_ie = NULL;
+ bss->wpa_ie = kmemdup(ies->wpa_ie,
+ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ } else if (ies->wpa2_ie != NULL) {
+ /* RSNIE */
+ bss->wpa_ie = NULL;
+ bss->rsn_ie = kmemdup(ies->wpa2_ie,
+ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ }
+ if (!ies->wpa2_ie && !ies->wpa_ie) {
+ wl_validate_opensecurity(dev, bssidx);
+ bss->security_mode = false;
+ }
+
+ if (ies->wps_ie) {
+ bss->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
+ }
+ }
+
+ return 0;
+
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
+static s32 wl_cfg80211_bcn_set_params(
+ struct cfg80211_ap_settings *info,
+ struct net_device *dev,
+ u32 dev_role, s32 bssidx)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ s32 err = BCME_OK;
+
+ WL_DBG(("interval (%d) \ndtim_period (%d) \n",
+ info->beacon_interval, info->dtim_period));
+
+ if (info->beacon_interval) {
+ if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD,
+ &info->beacon_interval, sizeof(s32), true)) < 0) {
+ WL_ERR(("Beacon Interval Set Error, %d\n", err));
+ return err;
+ }
+ }
+
+ if (info->dtim_period) {
+ if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD,
+ &info->dtim_period, sizeof(s32), true)) < 0) {
+ WL_ERR(("DTIM Interval Set Error, %d\n", err));
+ return err;
+ }
+ }
+
+ if ((info->ssid) && (info->ssid_len > 0) &&
+ (info->ssid_len <= DOT11_MAX_SSID_LEN)) {
+ WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len));
+ if (dev_role == NL80211_IFTYPE_AP) {
+ /* Store the hostapd SSID */
+ memset(cfg->hostapd_ssid.SSID, 0x00, DOT11_MAX_SSID_LEN);
+ memcpy(cfg->hostapd_ssid.SSID, info->ssid, info->ssid_len);
+ cfg->hostapd_ssid.SSID_len = info->ssid_len;
+ } else {
+ /* P2P GO */
+ memset(cfg->p2p->ssid.SSID, 0x00, DOT11_MAX_SSID_LEN);
+ memcpy(cfg->p2p->ssid.SSID, info->ssid, info->ssid_len);
+ cfg->p2p->ssid.SSID_len = info->ssid_len;
+ }
+ }
+
+ if (info->hidden_ssid) {
+ if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0)
+ WL_ERR(("failed to set hidden : %d\n", err));
+ WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid));
+ }
+
+ return err;
+}
+#endif
+
+static s32
+wl_cfg80211_parse_ies(u8 *ptr, u32 len, struct parsed_ies *ies)
+{
+ s32 err = BCME_OK;
+
+ memset(ies, 0, sizeof(struct parsed_ies));
+
+ /* find the WPSIE */
+ if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) {
+ WL_DBG(("WPSIE in beacon \n"));
+ ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
+ } else {
+ WL_ERR(("No WPSIE in beacon \n"));
+ }
+
+ /* find the RSN_IE */
+ if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len,
+ DOT11_MNG_RSN_ID)) != NULL) {
+ WL_DBG((" WPA2 IE found\n"));
+ ies->wpa2_ie_len = ies->wpa2_ie->len;
+ }
+
+ /* find the WPA_IE */
+ if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) {
+ WL_DBG((" WPA found\n"));
+ ies->wpa_ie_len = ies->wpa_ie->length;
+ }
+
+ return err;
+
+}
+
+static s32
+wl_cfg80211_bcn_bringup_ap(
+ struct net_device *dev,
+ struct parsed_ies *ies,
+ u32 dev_role, s32 bssidx)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ struct wl_join_params join_params;
+ bool is_bssup = false;
+ s32 infra = 1;
+ s32 join_params_size = 0;
+ s32 ap = 1;
+ s32 pm;
+ s32 err = BCME_OK;
+
+ WL_DBG(("Enter dev_role:%d bssidx:%d\n", dev_role, bssidx));
+
+ /* Common code for SoftAP and P2P GO */
+ wldev_iovar_setint(dev, "mpc", 0);
+
+ if (dev_role == NL80211_IFTYPE_P2P_GO) {
+ is_bssup = wl_cfgp2p_bss_isup(dev, bssidx);
+ if (!is_bssup && (ies->wpa2_ie != NULL)) {
+
+ err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
+ if (err < 0) {
+ WL_ERR(("SET INFRA error %d\n", err));
+ goto exit;
+ }
+
+ err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &cfg->p2p->ssid,
+ sizeof(cfg->p2p->ssid), cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
+ bssidx, &cfg->ioctl_buf_sync);
+ if (err < 0) {
+ WL_ERR(("GO SSID setting error %d\n", err));
+ goto exit;
+ }
+
+ /* Do abort scan before creating GO */
+ wl_cfg80211_scan_abort(cfg);
+
+ if ((err = wl_cfgp2p_bss(cfg, dev, bssidx, 1)) < 0) {
+ WL_ERR(("GO Bring up error %d\n", err));
+ goto exit;
+ }
+ } else
+ WL_DBG(("Bss is already up\n"));
+ } else if ((dev_role == NL80211_IFTYPE_AP) &&
+ (wl_get_drv_status(cfg, AP_CREATING, dev))) {
+
+ /* Device role SoftAP */
+ WL_DBG(("Creating AP bssidx:%d dev_role:%d\n", bssidx, dev_role));
+
+ if (bssidx == 0) {
+ if ((err = wl_cfg80211_add_del_bss(cfg, dev, bssidx,
+ NL80211_IFTYPE_AP, 0, NULL)) < 0) {
+ WL_DBG(("wl add_del_bss returned error (%d)\n", err));
+ err = wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true);
+ if (err < 0) {
+ WL_ERR(("WLC_DOWN error %d\n", err));
+ goto exit;
+ }
+ if ((err = wldev_iovar_setint(dev, "apsta", 0)) < 0) {
+ WL_ERR(("wl apsta 0 error %d\n", err));
+ goto exit;
+ }
+ if ((err = wldev_ioctl(dev,
+ WLC_SET_AP, &ap, sizeof(s32), true)) < 0) {
+ WL_ERR(("setting AP mode failed %d \n", err));
+ goto exit;
+ }
+ }
+
+ pm = 0;
+ if ((err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true)) != 0) {
+ WL_ERR(("wl PM 0 returned error:%d\n", err));
+ goto exit;
+ }
+
+ err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
+ if (err < 0) {
+ WL_ERR(("SET INFRA error %d\n", err));
+ goto exit;
+ }
+ } else if (cfg->cfgdev_bssidx && (bssidx == cfg->cfgdev_bssidx)) {
+
+ WL_DBG(("Bringup SoftAP on virtual Interface bssidx:%d \n", bssidx));
+
+ if ((err = wl_cfg80211_add_del_bss(cfg, dev,
+ bssidx, NL80211_IFTYPE_AP, 0, NULL)) < 0) {
+ WL_ERR(("wl bss ap returned error:%d\n", err));
+ goto exit;
+ }
+ }
+
+
+ err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_UP error (%d)\n", err));
+ goto exit;
+ }
+
+ memset(&join_params, 0, sizeof(join_params));
+ /* join parameters starts with ssid */
+ join_params_size = sizeof(join_params.ssid);
+ join_params.ssid.SSID_len = MIN(cfg->hostapd_ssid.SSID_len,
+ (uint32)DOT11_MAX_SSID_LEN);
+ memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID,
+ join_params.ssid.SSID_len);
+ join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
+
+ /* create softap */
+ if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
+ join_params_size, true)) == 0) {
+ WL_DBG(("SoftAP set SSID (%s) success\n", join_params.ssid.SSID));
+ wl_clr_drv_status(cfg, AP_CREATING, dev);
+ wl_set_drv_status(cfg, AP_CREATED, dev);
+ } else {
+ WL_ERR(("SoftAP set SSID (%s) failed!\n", join_params.ssid.SSID));
+ }
+ }
+
+
+exit:
+ return err;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
+s32
+wl_cfg80211_parse_ap_ies(
+ struct net_device *dev,
+ struct cfg80211_beacon_data *info,
+ struct parsed_ies *ies)
+{
+ struct parsed_ies prb_ies;
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+ u8 *vndr = NULL;
+ u32 vndr_ie_len = 0;
+ s32 err = BCME_OK;
+
+ /* Parse Beacon IEs */
+ if (wl_cfg80211_parse_ies((u8 *)info->tail,
+ info->tail_len, ies) < 0) {
+ WL_ERR(("Beacon get IEs failed \n"));
+ err = -EINVAL;
+ goto fail;
+ }
+
+ vndr = (u8 *)info->proberesp_ies;
+ vndr_ie_len = info->proberesp_ies_len;
+
+ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
+ /* SoftAP mode */
+ struct ieee80211_mgmt *mgmt;
+ mgmt = (struct ieee80211_mgmt *)info->probe_resp;
+ if (mgmt != NULL) {
+ vndr = (u8 *)&mgmt->u.probe_resp.variable;
+ vndr_ie_len = info->probe_resp_len -
+ offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+ }
+ }
+
+ /* Parse Probe Response IEs */
+ if (wl_cfg80211_parse_ies(vndr, vndr_ie_len, &prb_ies) < 0) {
+ WL_ERR(("PROBE RESP get IEs failed \n"));
+ err = -EINVAL;
+ }
+
+fail:
+
+ return err;
+}
+
+s32
+wl_cfg80211_set_ies(
+ struct net_device *dev,
+ struct cfg80211_beacon_data *info,
+ s32 bssidx)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+ u8 *vndr = NULL;
+ u32 vndr_ie_len = 0;
+ s32 err = BCME_OK;
+
+ /* Set Beacon IEs to FW */
+ if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, dev, bssidx,
+ VNDR_IE_BEACON_FLAG, (u8 *)info->tail,
+ info->tail_len)) < 0) {
+ WL_ERR(("Set Beacon IE Failed \n"));
+ } else {
+ WL_DBG(("Applied Vndr IEs for Beacon \n"));
+ }
+
+ vndr = (u8 *)info->proberesp_ies;
+ vndr_ie_len = info->proberesp_ies_len;
+
+ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
+ /* SoftAP mode */
+ struct ieee80211_mgmt *mgmt;
+ mgmt = (struct ieee80211_mgmt *)info->probe_resp;
+ if (mgmt != NULL) {
+ vndr = (u8 *)&mgmt->u.probe_resp.variable;
+ vndr_ie_len = info->probe_resp_len -
+ offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+ }
+ }
+
+ /* Set Probe Response IEs to FW */
+ if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, dev, bssidx,
+ VNDR_IE_PRBRSP_FLAG, vndr, vndr_ie_len)) < 0) {
+ WL_ERR(("Set Probe Resp IE Failed \n"));
+ } else {
+ WL_DBG(("Applied Vndr IEs for Probe Resp \n"));
+ }
+
+ return err;
+}
+#endif
+
+static s32 wl_cfg80211_hostapd_sec(
+ struct net_device *dev,
+ struct parsed_ies *ies,
+ s32 bssidx)
+{
+ bool update_bss = 0;
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
+
+ if (!bss) {
+ WL_ERR(("cfgbss is NULL \n"));
+ return -EINVAL;
+ }
+
+ if (ies->wps_ie) {
+ if (bss->wps_ie &&
+ memcmp(bss->wps_ie, ies->wps_ie, ies->wps_ie_len)) {
+ WL_DBG((" WPS IE is changed\n"));
+ kfree(bss->wps_ie);
+ bss->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
+ } else if (bss->wps_ie == NULL) {
+ WL_DBG((" WPS IE is added\n"));
+ bss->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
+ }
+
+ if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) {
+ if (!bss->security_mode) {
+ /* change from open mode to security mode */
+ update_bss = true;
+ if (ies->wpa_ie != NULL) {
+ bss->wpa_ie = kmemdup(ies->wpa_ie,
+ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ } else {
+ bss->rsn_ie = kmemdup(ies->wpa2_ie,
+ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ }
+ } else if (bss->wpa_ie) {
+ /* change from WPA2 mode to WPA mode */
+ if (ies->wpa_ie != NULL) {
+ update_bss = true;
+ kfree(bss->rsn_ie);
+ bss->rsn_ie = NULL;
+ bss->wpa_ie = kmemdup(ies->wpa_ie,
+ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ } else if (memcmp(bss->rsn_ie,
+ ies->wpa2_ie, ies->wpa2_ie->len
+ + WPA_RSN_IE_TAG_FIXED_LEN)) {
+ update_bss = true;
+ kfree(bss->rsn_ie);
+ bss->rsn_ie = kmemdup(ies->wpa2_ie,
+ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ bss->wpa_ie = NULL;
+ }
+ }
+ if (update_bss) {
+ bss->security_mode = true;
+ wl_cfgp2p_bss(cfg, dev, bssidx, 0);
+ if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
+ wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) {
+ return BCME_ERROR;
+ }
+ wl_cfgp2p_bss(cfg, dev, bssidx, 1);
+ }
+ }
+ } else {
+ WL_ERR(("No WPSIE in beacon \n"));
+ }
+ return 0;
+}
+
+#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
+ 2, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
+static s32 wl_cfg80211_del_station(
+ struct wiphy *wiphy, struct net_device *ndev,
+ struct station_del_parameters *params)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static s32
+wl_cfg80211_del_station(struct wiphy *wiphy,
+ struct net_device *ndev, const u8* mac_addr)
+#else
+static s32
+wl_cfg80211_del_station(struct wiphy *wiphy,
+ struct net_device *ndev, u8* mac_addr)
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
+{
+ struct net_device *dev;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ scb_val_t scb_val;
+ s8 eabuf[ETHER_ADDR_STR_LEN];
+ int err;
+ char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
+ sizeof(struct ether_addr) + sizeof(uint)] = {0};
+ struct maclist *assoc_maclist = (struct maclist *)mac_buf;
+ int num_associated = 0;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
+ const u8 *mac_addr = params->mac;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
+
+ WL_DBG(("Entry\n"));
+ if (mac_addr == NULL) {
+ WL_DBG(("mac_addr is NULL ignore it\n"));
+ return 0;
+ }
+
+ dev = ndev_to_wlc_ndev(ndev, cfg);
+
+ if (p2p_is_on(cfg)) {
+ /* Suspend P2P discovery search-listen to prevent it from changing the
+ * channel.
+ */
+ if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
+ WL_ERR(("Can not disable discovery mode\n"));
+ return -EFAULT;
+ }
+ }
+
+ assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
+ err = wldev_ioctl(ndev, WLC_GET_ASSOCLIST,
+ assoc_maclist, sizeof(mac_buf), false);
+ if (err < 0)
+ WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
+ else
+ num_associated = assoc_maclist->count;
+
+#ifdef REMOVE_P2PIE_BEFORE_DELIF
+ if (num_associated > 0 && ETHER_ISBCAST(mac_addr) && p2p_is_on(cfg))
+ {
+ s32 bssidx = -1;
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from ndev(%p) failed\n", dev));
+ } else {
+ wl_cfg80211_clear_per_bss_ies(cfg, bssidx);
+ }
+ }
+#endif /* REMOVE_P2PIE_BEFORE_DELIF */
+
+ memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN);
+ scb_val.val = DOT11_RC_DEAUTH_LEAVING;
+ err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
+ sizeof(scb_val_t), true);
+ if (err < 0)
+ WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
+ WL_ERR(("Disconnect STA : %s scb_val.val %d\n",
+ bcm_ether_ntoa((const struct ether_addr *)mac_addr, eabuf),
+ scb_val.val));
+
+ if (num_associated > 0 && ETHER_ISBCAST(mac_addr))
+ wl_delay(400);
+
+ return 0;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static s32
+wl_cfg80211_change_station(struct wiphy *wiphy,
+ struct net_device *dev, const u8 *mac, struct station_parameters *params)
+#else
+static s32
+wl_cfg80211_change_station(struct wiphy *wiphy,
+ struct net_device *dev, u8 *mac, struct station_parameters *params)
+#endif
+{
+ int err;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+
+ /* Processing only authorize/de-authorize flag for now */
+ if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
+ return -ENOTSUPP;
+
+ if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+ err = wldev_ioctl(primary_ndev, WLC_SCB_AUTHORIZE, (u8 *)mac, ETH_ALEN, true);
+#else
+ err = wldev_ioctl(primary_ndev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN, true);
+#endif
+ if (err)
+ WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err));
+ return err;
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+ err = wldev_ioctl(primary_ndev, WLC_SCB_AUTHORIZE, (u8 *)mac, ETH_ALEN, true);
+#else
+ err = wldev_ioctl(primary_ndev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN, true);
+#endif
+ if (err)
+ WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err));
+ return err;
+}
+#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
+static s32
+wl_cfg80211_start_ap(
+ struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_ap_settings *info)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 err = BCME_OK;
+ struct parsed_ies ies;
+ s32 bssidx = 0;
+ u32 dev_role = 0;
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+
+#ifdef WL11U
+ bcm_tlv_t *interworking_ie;
+#endif
+
+ WL_DBG(("Enter \n"));
+
+ if ((dev == bcmcfg_to_prmry_ndev(cfg)) ||
+ (dev == ((struct net_device *)cfgdev_to_wlc_ndev(cfg->bss_cfgdev, cfg)))) {
+ WL_DBG(("Start AP req on primary iface: Softap\n"));
+ dev_role = NL80211_IFTYPE_AP;
+ }
+#if defined(WL_ENABLE_P2P_IF)
+ else if (dev == cfg->p2p_net) {
+ /* Group Add request on p2p0 */
+ WL_DBG(("Start AP req on P2P iface: GO\n"));
+#ifndef P2PONEINT
+ dev = bcmcfg_to_prmry_ndev(cfg);
+#endif
+ dev_role = NL80211_IFTYPE_P2P_GO;
+ }
+#endif /* WL_ENABLE_P2P_IF */
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ return BCME_ERROR;
+ }
+
+ if (p2p_is_on(cfg) && (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO)) {
+ dev_role = NL80211_IFTYPE_P2P_GO;
+ WL_DBG(("Start AP req on P2P connection iface\n"));
+ } else if (dev_role == NL80211_IFTYPE_AP) {
+ WL_DBG(("Start AP req\n"));
+ dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
+
+#ifdef PKT_FILTER_SUPPORT
+ /* Disable packet filter */
+ if (dhd->early_suspended) {
+ WL_ERR(("Disable pkt_filter\n"));
+ dhd_enable_packet_filter(0, dhd);
+ }
+#endif /* PKT_FILTER_SUPPORT */
+#ifdef ARP_OFFLOAD_SUPPORT
+ /* IF SoftAP is enabled, disable arpoe */
+ if (dhd->op_mode & DHD_FLAG_STA_MODE) {
+ dhd_arp_offload_set(dhd, 0);
+ dhd_arp_offload_enable(dhd, FALSE);
+ }
+#endif /* ARP_OFFLOAD_SUPPORT */
+ } else {
+ /* only AP or GO role need to be handled here. */
+ err = -EINVAL;
+ goto fail;
+ }
+
+ if (!check_dev_role_integrity(cfg, dev_role))
+ goto fail;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ if ((err = wl_cfg80211_set_channel(wiphy, dev,
+ dev->ieee80211_ptr->preset_chandef.chan,
+ NL80211_CHAN_HT20) < 0)) {
+ WL_ERR(("Set channel failed \n"));
+ goto fail;
+ }
+#endif
+
+ if ((err = wl_cfg80211_bcn_set_params(info, dev,
+ dev_role, bssidx)) < 0) {
+ WL_ERR(("Beacon params set failed \n"));
+ goto fail;
+ }
+
+ /* Parse IEs */
+ if ((err = wl_cfg80211_parse_ap_ies(dev, &info->beacon, &ies)) < 0) {
+ WL_ERR(("Set IEs failed \n"));
+ goto fail;
+ }
+
+ if ((wl_cfg80211_bcn_validate_sec(dev, &ies,
+ dev_role, bssidx)) < 0)
+ {
+ WL_ERR(("Beacon set security failed \n"));
+ goto fail;
+ }
+
+ if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies,
+ dev_role, bssidx)) < 0) {
+ WL_ERR(("Beacon bring up AP/GO failed \n"));
+ goto fail;
+ }
+
+ WL_DBG(("** AP/GO Created **\n"));
+
+#ifdef WL_CFG80211_ACL
+ /* Enfoce Admission Control. */
+ if ((err = wl_cfg80211_set_mac_acl(wiphy, dev, info->acl)) < 0) {
+ WL_ERR(("Set ACL failed\n"));
+ }
+#endif /* WL_CFG80211_ACL */
+
+#ifdef WL11U
+ /* Add interworking IE from beacon data */
+ if ((interworking_ie = wl_cfg80211_find_interworking_ie(
+ (u8 *)info->beacon.beacon_ies, info->beacon.beacon_ies_len)) != NULL) {
+ err = wl_cfg80211_add_iw_ie(cfg, dev, bssidx,
+ VNDR_IE_CUSTOM_FLAG, interworking_ie->id,
+ interworking_ie->data, interworking_ie->len);
+ if (unlikely(err)) {
+ WL_ERR(("Failed to add interworking IE"));
+ }
+ } else if (cfg->iw_ie_len != 0) {
+ /* we have to clear IW IE and disable gratuitous APR */
+ wl_cfg80211_add_iw_ie(cfg, dev, bssidx,
+ VNDR_IE_CUSTOM_FLAG,
+ DOT11_MNG_INTERWORKING_ID,
+ 0, 0);
+
+ (void)wldev_iovar_setint_bsscfg(dev, "grat_arp", 0, bssidx);
+ cfg->wl11u = FALSE;
+ cfg->iw_ie_len = 0;
+ memset(cfg->iw_ie, 0, IW_IES_MAX_BUF_LEN);
+ /* we don't care about error */
+ }
+#endif /* WL11U */
+
+ /* Set IEs to FW */
+ if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0)
+ WL_ERR(("Set IEs failed \n"));
+
+ /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
+ if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
+ bool pbc = 0;
+ wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc);
+ if (pbc) {
+ WL_DBG(("set WLC_E_PROBREQ_MSG\n"));
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
+ }
+ }
+
+fail:
+ if (err) {
+ WL_ERR(("ADD/SET beacon failed\n"));
+ wldev_iovar_setint(dev, "mpc", 1);
+ }
+
+ return err;
+}
+
+static s32
+wl_cfg80211_stop_ap(
+ struct wiphy *wiphy,
+ struct net_device *dev)
+{
+ int err = 0;
+ u32 dev_role = 0;
+ int infra = 0;
+ int ap = 0;
+ s32 bssidx = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+
+ WL_DBG(("Enter \n"));
+
+ wl_clr_drv_status(cfg, AP_CREATING, dev);
+ wl_clr_drv_status(cfg, AP_CREATED, dev);
+
+ if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
+ dev_role = NL80211_IFTYPE_AP;
+ WL_DBG(("stopping AP operation\n"));
+ } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
+ dev_role = NL80211_IFTYPE_P2P_GO;
+ WL_DBG(("stopping P2P GO operation\n"));
+ } else {
+ WL_ERR(("no AP/P2P GO interface is operational.\n"));
+ return -EINVAL;
+ }
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("find bss index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+
+ if (!check_dev_role_integrity(cfg, dev_role))
+ goto exit;
+
+ if ((err = wl_cfgp2p_bss(cfg, dev, bssidx, 0)) < 0) {
+ WL_ERR(("bss down error %d\n", err));
+ }
+
+ if (dev_role == NL80211_IFTYPE_AP) {
+ /* SoftAp on primary Interface.
+ * Shut down AP and turn on MPC
+ */
+
+#ifdef PKT_FILTER_SUPPORT
+ /* Enable packet filter */
+ if (dhd->early_suspended) {
+ WL_ERR(("Enable pkt_filter\n"));
+ dhd_enable_packet_filter(1, dhd);
+ }
+#endif /* PKT_FILTER_SUPPORT */
+#ifdef ARP_OFFLOAD_SUPPORT
+ /* IF SoftAP is disabled, enable arpoe back for STA mode. */
+ if (dhd->op_mode & DHD_FLAG_STA_MODE) {
+ dhd_arp_offload_set(dhd, dhd_arp_mode);
+ dhd_arp_offload_enable(dhd, TRUE);
+ }
+#endif /* ARP_OFFLOAD_SUPPORT */
+
+ /*
+ * Bring down the AP interface by changing role to STA.
+ * Don't do a down or "WLC_SET_AP 0" since the shared
+ * interface may be still running
+ */
+
+ WL_DBG(("Bring down AP interface by changing role to STA\n"));
+
+ if ((err = wl_cfg80211_add_del_bss(cfg, dev,
+ bssidx, NL80211_IFTYPE_STATION, 0, NULL)) < 0) {
+ WL_DBG(("wl add_del_bss returned error (%d)\n", err));
+ if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) {
+ WL_ERR(("setting AP mode failed %d \n", err));
+ err = -ENOTSUPP;
+ goto exit;
+ }
+ err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
+ if (err < 0) {
+ WL_ERR(("SET INFRA error %d\n", err));
+ err = -ENOTSUPP;
+ goto exit;
+ }
+
+ err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_UP error (%d)\n", err));
+ err = -EINVAL;
+ goto exit;
+ }
+ }
+
+ /* Turn on the MPC */
+ wldev_iovar_setint(dev, "mpc", 1);
+
+ wl_cfg80211_clear_per_bss_ies(cfg, bssidx);
+ } else {
+ WL_DBG(("Stopping P2P GO \n"));
+ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t *)(cfg->pub),
+ DHD_EVENT_TIMEOUT_MS*3);
+ DHD_OS_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub));
+ }
+
+exit:
+ if (dev_role == NL80211_IFTYPE_AP) {
+ /* clear the AP mode */
+ dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
+ }
+ return err;
+}
+
+static s32
+wl_cfg80211_change_beacon(
+ struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_beacon_data *info)
+{
+ s32 err = BCME_OK;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct parsed_ies ies;
+ u32 dev_role = 0;
+ s32 bssidx = 0;
+ bool pbc = 0;
+#ifdef WL11U
+ bcm_tlv_t *interworking_ie;
+#endif
+
+ WL_DBG(("Enter \n"));
+
+ if ((dev == bcmcfg_to_prmry_ndev(cfg)) ||
+ (dev == ((struct net_device *)cfgdev_to_wlc_ndev(cfg->bss_cfgdev, cfg)))) {
+ dev_role = NL80211_IFTYPE_AP;
+ }
+#if defined(WL_ENABLE_P2P_IF)
+ else if (dev == cfg->p2p_net) {
+ /* Group Add request on p2p0 */
+#ifndef P2PONEINT
+ dev = bcmcfg_to_prmry_ndev(cfg);
+#endif
+ dev_role = NL80211_IFTYPE_P2P_GO;
+ }
+#endif /* WL_ENABLE_P2P_IF */
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ return BCME_ERROR;
+ }
+
+ if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
+ dev_role = NL80211_IFTYPE_P2P_GO;
+ }
+
+ if (!check_dev_role_integrity(cfg, dev_role))
+ goto fail;
+
+ /* Parse IEs */
+ if ((err = wl_cfg80211_parse_ap_ies(dev, info, &ies)) < 0) {
+ WL_ERR(("Parse IEs failed \n"));
+ goto fail;
+ }
+
+ /* Set IEs to FW */
+ if ((err = wl_cfg80211_set_ies(dev, info, bssidx)) < 0) {
+ WL_ERR(("Set IEs failed \n"));
+ goto fail;
+ }
+#ifdef WL11U
+ /* Add interworking IE from beacon data */
+ if ((interworking_ie = wl_cfg80211_find_interworking_ie(
+ (u8 *)info->beacon_ies, info->beacon_ies_len)) != NULL) {
+ err = wl_cfg80211_add_iw_ie(cfg, dev, bssidx,
+ VNDR_IE_CUSTOM_FLAG, interworking_ie->id,
+ interworking_ie->data, interworking_ie->len);
+ if (unlikely(err)) {
+ WL_ERR(("Failed to add interworking IE"));
+ }
+ } else if (cfg->iw_ie_len != 0) {
+ /* we have to clear IW IE and disable gratuitous APR */
+ wl_cfg80211_add_iw_ie(cfg, dev, bssidx,
+ VNDR_IE_CUSTOM_FLAG,
+ DOT11_MNG_INTERWORKING_ID,
+ 0, 0);
+
+ (void)wldev_iovar_setint_bsscfg(dev, "grat_arp", 0, bssidx);
+ cfg->wl11u = FALSE;
+ cfg->iw_ie_len = 0;
+ memset(cfg->iw_ie, 0, IW_IES_MAX_BUF_LEN);
+ /* we don't care about error */
+ }
+#endif /* WL11U */
+
+
+ if (dev_role == NL80211_IFTYPE_AP) {
+ if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
+ WL_ERR(("Hostapd update sec failed \n"));
+ err = -EINVAL;
+ goto fail;
+ }
+ /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
+ if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
+ wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc);
+ WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc));
+ if (pbc)
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
+ else
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false);
+ }
+ }
+
+fail:
+ return err;
+}
+#else
+static s32
+wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *info)
+{
+ s32 err = BCME_OK;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 ie_offset = 0;
+ s32 bssidx = 0;
+ u32 dev_role = NL80211_IFTYPE_AP;
+ struct parsed_ies ies;
+ bcm_tlv_t *ssid_ie;
+ bool pbc = 0;
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+
+ WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
+ info->interval, info->dtim_period, info->head_len, info->tail_len));
+
+ if (dev == bcmcfg_to_prmry_ndev(cfg)) {
+ dev_role = NL80211_IFTYPE_AP;
+ }
+#if defined(WL_ENABLE_P2P_IF)
+ else if (dev == cfg->p2p_net) {
+ /* Group Add request on p2p0 */
+#ifndef P2PONEINT
+ dev = bcmcfg_to_prmry_ndev(cfg);
+#endif
+ dev_role = NL80211_IFTYPE_P2P_GO;
+ }
+#endif /* WL_ENABLE_P2P_IF */
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ return BCME_ERROR;
+ }
+
+ if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
+ dev_role = NL80211_IFTYPE_P2P_GO;
+ } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
+ dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
+ }
+
+ if (!check_dev_role_integrity(cfg, dev_role))
+ goto fail;
+
+ ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
+ /* find the SSID */
+ if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset],
+ info->head_len - ie_offset,
+ DOT11_MNG_SSID_ID)) != NULL) {
+ if (dev_role == NL80211_IFTYPE_AP) {
+ /* Store the hostapd SSID */
+ memset(&cfg->hostapd_ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN);
+ cfg->hostapd_ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
+ memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data,
+ cfg->hostapd_ssid.SSID_len);
+ } else {
+ /* P2P GO */
+ memset(&cfg->p2p->ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN);
+ cfg->p2p->ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
+ memcpy(cfg->p2p->ssid.SSID, ssid_ie->data,
+ cfg->p2p->ssid.SSID_len);
+ }
+ }
+
+ if (wl_cfg80211_parse_ies((u8 *)info->tail,
+ info->tail_len, &ies) < 0) {
+ WL_ERR(("Beacon get IEs failed \n"));
+ err = -EINVAL;
+ goto fail;
+ }
+
+ if (wl_cfg80211_set_mgmt_vndr_ies(cfg, dev, bssidx,
+ VNDR_IE_BEACON_FLAG, (u8 *)info->tail,
+ info->tail_len) < 0) {
+ WL_ERR(("Beacon set IEs failed \n"));
+ goto fail;
+ } else {
+ WL_DBG(("Applied Vndr IEs for Beacon \n"));
+ }
+ if (!wl_cfgp2p_bss_isup(dev, bssidx) &&
+ (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx) < 0))
+ {
+ WL_ERR(("Beacon set security failed \n"));
+ goto fail;
+ }
+
+ /* Set BI and DTIM period */
+ if (info->interval) {
+ if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD,
+ &info->interval, sizeof(s32), true)) < 0) {
+ WL_ERR(("Beacon Interval Set Error, %d\n", err));
+ return err;
+ }
+ }
+ if (info->dtim_period) {
+ if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD,
+ &info->dtim_period, sizeof(s32), true)) < 0) {
+ WL_ERR(("DTIM Interval Set Error, %d\n", err));
+ return err;
+ }
+ }
+
+ if (wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx) < 0) {
+ WL_ERR(("Beacon bring up AP/GO failed \n"));
+ goto fail;
+ }
+
+ if (wl_get_drv_status(cfg, AP_CREATED, dev)) {
+ /* Soft AP already running. Update changed params */
+ if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
+ WL_ERR(("Hostapd update sec failed \n"));
+ err = -EINVAL;
+ goto fail;
+ }
+ }
+
+ /* Enable Probe Req filter */
+ if (((dev_role == NL80211_IFTYPE_P2P_GO) ||
+ (dev_role == NL80211_IFTYPE_AP)) && (ies.wps_ie != NULL)) {
+ wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc);
+ if (pbc)
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
+ }
+
+ WL_DBG(("** ADD/SET beacon done **\n"));
+
+fail:
+ if (err) {
+ WL_ERR(("ADD/SET beacon failed\n"));
+ wldev_iovar_setint(dev, "mpc", 1);
+ }
+ return err;
+
+}
+#endif
+
+#ifdef WL_SCHED_SCAN
+#define PNO_TIME 30
+#define PNO_REPEAT 4
+#define PNO_FREQ_EXPO_MAX 2
+static int
+wl_cfg80211_sched_scan_start(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_sched_scan_request *request)
+{
+ ushort pno_time = PNO_TIME;
+ int pno_repeat = PNO_REPEAT;
+ int pno_freq_expo_max = PNO_FREQ_EXPO_MAX;
+ wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct cfg80211_ssid *ssid = NULL;
+ int ssid_count = 0;
+ int i;
+ int ret = 0;
+
+ if (!request) {
+ WL_ERR(("Sched scan request was NULL\n"));
+ return -EINVAL;
+ }
+
+ WL_DBG(("Enter \n"));
+ WL_PNO((">>> SCHED SCAN START\n"));
+ WL_PNO(("Enter n_match_sets:%d n_ssids:%d \n",
+ request->n_match_sets, request->n_ssids));
+ WL_PNO(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n",
+ request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max));
+
+
+ if (!request->n_ssids || !request->n_match_sets) {
+ WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids));
+ return -EINVAL;
+ }
+
+ memset(&ssids_local, 0, sizeof(ssids_local));
+
+ if (request->n_match_sets > 0) {
+ for (i = 0; i < request->n_match_sets; i++) {
+ ssid = &request->match_sets[i].ssid;
+ ssids_local[ssid_count].SSID_len = MIN(ssid->ssid_len,
+ (uint32)DOT11_MAX_SSID_LEN);
+ memcpy(ssids_local[ssid_count].SSID, ssid->ssid,
+ ssids_local[ssid_count].SSID_len);
+ WL_PNO((">>> PNO filter set for ssid (%s) \n", ssid->ssid));
+ ssid_count++;
+ }
+ }
+
+ if (request->n_ssids > 0) {
+ for (i = 0; i < request->n_ssids; i++) {
+ /* Active scan req for ssids */
+ WL_PNO((">>> Active scan req for ssid (%s) \n", request->ssids[i].ssid));
+
+ /* match_set ssids is a supert set of n_ssid list, so we need
+ * not add these set seperately
+ */
+ }
+ }
+
+ if (ssid_count) {
+ if ((ret = dhd_dev_pno_set_for_ssid(dev, ssids_local, request->n_match_sets,
+ pno_time, pno_repeat, pno_freq_expo_max, NULL, 0)) < 0) {
+ WL_ERR(("PNO setup failed!! ret=%d \n", ret));
+ return -EINVAL;
+ }
+ cfg->sched_scan_req = request;
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+
+ WL_DBG(("Enter \n"));
+ WL_PNO((">>> SCHED SCAN STOP\n"));
+
+ if (dhd_dev_pno_stop_for_ssid(dev) < 0)
+ WL_ERR(("PNO Stop for SSID failed"));
+
+ if (cfg->scan_request && cfg->sched_scan_running) {
+ WL_PNO((">>> Sched scan running. Aborting it..\n"));
+ wl_notify_escan_complete(cfg, dev, true, true);
+ }
+
+ cfg->sched_scan_req = NULL;
+ cfg->sched_scan_running = FALSE;
+
+ return 0;
+}
+#endif /* WL_SCHED_SCAN */
+
+#ifdef WL_SUPPORT_ACS
+/*
+ * Currently the dump_obss IOVAR is returning string as output so we need to
+ * parse the output buffer in an unoptimized way. Going forward if we get the
+ * IOVAR output in binary format this method can be optimized
+ */
+static int wl_parse_dump_obss(char *buf, struct wl_dump_survey *survey)
+{
+ int i;
+ char *token;
+ char delim[] = " \n";
+
+ token = strsep(&buf, delim);
+ while (token != NULL) {
+ if (!strcmp(token, "OBSS")) {
+ for (i = 0; i < OBSS_TOKEN_IDX; i++)
+ token = strsep(&buf, delim);
+ survey->obss = simple_strtoul(token, NULL, 10);
+ }
+
+ if (!strcmp(token, "IBSS")) {
+ for (i = 0; i < IBSS_TOKEN_IDX; i++)
+ token = strsep(&buf, delim);
+ survey->ibss = simple_strtoul(token, NULL, 10);
+ }
+
+ if (!strcmp(token, "TXDur")) {
+ for (i = 0; i < TX_TOKEN_IDX; i++)
+ token = strsep(&buf, delim);
+ survey->tx = simple_strtoul(token, NULL, 10);
+ }
+
+ if (!strcmp(token, "Category")) {
+ for (i = 0; i < CTG_TOKEN_IDX; i++)
+ token = strsep(&buf, delim);
+ survey->no_ctg = simple_strtoul(token, NULL, 10);
+ }
+
+ if (!strcmp(token, "Packet")) {
+ for (i = 0; i < PKT_TOKEN_IDX; i++)
+ token = strsep(&buf, delim);
+ survey->no_pckt = simple_strtoul(token, NULL, 10);
+ }
+
+ if (!strcmp(token, "Opp(time):")) {
+ for (i = 0; i < IDLE_TOKEN_IDX; i++)
+ token = strsep(&buf, delim);
+ survey->idle = simple_strtoul(token, NULL, 10);
+ }
+
+ token = strsep(&buf, delim);
+ }
+
+ return 0;
+}
+
+static int wl_dump_obss(struct net_device *ndev, cca_msrmnt_query req,
+ struct wl_dump_survey *survey)
+{
+ cca_stats_n_flags *results;
+ char *buf;
+ int retry, err;
+
+ buf = kzalloc(sizeof(char) * WLC_IOCTL_MAXLEN, GFP_KERNEL);
+ if (unlikely(!buf)) {
+ WL_ERR(("%s: buf alloc failed\n", __func__));
+ return -ENOMEM;
+ }
+
+ retry = IOCTL_RETRY_COUNT;
+ while (retry--) {
+ err = wldev_iovar_getbuf(ndev, "dump_obss", &req, sizeof(req),
+ buf, WLC_IOCTL_MAXLEN, NULL);
+ if (err >= 0) {
+ break;
+ }
+ WL_DBG(("attempt = %d, err = %d, \n",
+ (IOCTL_RETRY_COUNT - retry), err));
+ }
+
+ if (retry <= 0) {
+ WL_ERR(("failure, dump_obss IOVAR failed\n"));
+ err = -EINVAL;
+ goto exit;
+ }
+
+ results = (cca_stats_n_flags *)(buf);
+ wl_parse_dump_obss(results->buf, survey);
+ kfree(buf);
+
+ return 0;
+exit:
+ kfree(buf);
+ return err;
+}
+
+static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
+ int idx, struct survey_info *info)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct wl_dump_survey *survey;
+ struct ieee80211_supported_band *band;
+ struct ieee80211_channel*chan;
+ cca_msrmnt_query req;
+ int val, err, noise, retry;
+ uint8 cache_idx;
+
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+ if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
+ return -ENOENT;
+ }
+ band = wiphy->bands[NL80211_BAND_2GHZ];
+ if (band && idx >= band->n_channels) {
+ idx -= band->n_channels;
+ band = NULL;
+ }
+
+ if (!band || idx >= band->n_channels) {
+ /* Move to 5G band */
+ band = wiphy->bands[NL80211_BAND_5GHZ];
+ if (!band || idx >= band->n_channels) {
+ return -ENOENT;
+ }
+ }
+
+ chan = &band->channels[idx];
+ /*
+ * Avoid unnecessary time spent on getting obss on channels
+ * which are not used by hostapd in current mode.
+ */
+ for (cache_idx = 0; cache_idx < g_hostap_chan_count; cache_idx++) {
+ if (g_hostap_chan_cache[cache_idx] == chan->center_freq)
+ break;
+ }
+ if (cache_idx == g_hostap_chan_count)
+ {
+ WL_DBG(("%s channel %d is ignored & dummy value is passed \n",
+ __func__, ieee80211_frequency_to_channel(chan->center_freq)));
+ info->channel = chan;
+ info->noise = 0;
+ info->channel_time = 0;
+ info->channel_time_busy = 0;
+ info->channel_time_rx = 0;
+ info->channel_time_tx = 0;
+ info->filled = SURVEY_INFO_NOISE_DBM |SURVEY_INFO_CHANNEL_TIME |
+ SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX |
+ SURVEY_INFO_CHANNEL_TIME_TX;
+ return 0;
+ }
+
+ /* Setting current channel to the requested channel */
+ if ((err = wl_cfg80211_set_channel(wiphy, ndev, chan,
+ NL80211_CHAN_HT20) < 0)) {
+ WL_ERR(("Set channel failed \n"));
+ }
+
+ if (!idx) {
+ /* Disable mpc */
+ val = 0;
+ err = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val,
+ sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
+ &cfg->ioctl_buf_sync);
+ if (err < 0) {
+ WL_ERR(("set 'mpc' failed, error = %d\n", err));
+ }
+
+ /* Set interface up, explicitly. */
+ val = 1;
+ err = wldev_ioctl(ndev, WLC_UP, (void *)&val, sizeof(val), true);
+ if (err < 0) {
+ WL_ERR(("set interface up failed, error = %d\n", err));
+ }
+ }
+
+ /* Get noise value */
+ retry = IOCTL_RETRY_COUNT;
+ while (retry--) {
+ err = wldev_ioctl(ndev, WLC_GET_PHY_NOISE, &noise,
+ sizeof(noise), false);
+ if (err >= 0) {
+ break;
+ }
+ WL_DBG(("attempt = %d, err = %d, \n",
+ (IOCTL_RETRY_COUNT - retry), err));
+ }
+
+ if (retry <= 0) {
+ WL_ERR(("Get Phy Noise failed, error = %d\n", err));
+ noise = CHAN_NOISE_DUMMY;
+ }
+
+ survey = (struct wl_dump_survey *) kzalloc(sizeof(struct wl_dump_survey),
+ GFP_KERNEL);
+ if (unlikely(!survey)) {
+ WL_ERR(("%s: alloc failed\n", __func__));
+ return -ENOMEM;
+ }
+
+ /* Start Measurement for obss stats on current channel */
+ req.msrmnt_query = 0;
+ req.time_req = ACS_MSRMNT_DELAY;
+ if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
+ goto exit;
+ }
+
+ /*
+ * Wait for the meaurement to complete, adding a buffer value of 10 to take
+ * into consideration any delay in IOVAR completion
+ */
+ msleep(ACS_MSRMNT_DELAY + 10);
+
+ /* Issue IOVAR to collect measurement results */
+ req.msrmnt_query = 1;
+ if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
+ goto exit;
+ }
+
+ info->channel = chan;
+ info->noise = noise;
+ info->channel_time = ACS_MSRMNT_DELAY;
+ info->channel_time_busy = ACS_MSRMNT_DELAY - survey->idle;
+ info->channel_time_rx = survey->obss + survey->ibss + survey->no_ctg +
+ survey->no_pckt;
+ info->channel_time_tx = survey->tx;
+ info->filled = SURVEY_INFO_NOISE_DBM |SURVEY_INFO_CHANNEL_TIME |
+ SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX |
+ SURVEY_INFO_CHANNEL_TIME_TX;
+ kfree(survey);
+
+ return 0;
+exit:
+ kfree(survey);
+ return err;
+}
+#endif /* WL_SUPPORT_ACS */
+
+static struct cfg80211_ops wl_cfg80211_ops = {
+ .add_virtual_intf = wl_cfg80211_add_virtual_iface,
+ .del_virtual_intf = wl_cfg80211_del_virtual_iface,
+ .change_virtual_intf = wl_cfg80211_change_virtual_iface,
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ .start_p2p_device = wl_cfgp2p_start_p2p_device,
+ .stop_p2p_device = wl_cfgp2p_stop_p2p_device,
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ .scan = wl_cfg80211_scan,
+ .set_wiphy_params = wl_cfg80211_set_wiphy_params,
+ .join_ibss = wl_cfg80211_join_ibss,
+ .leave_ibss = wl_cfg80211_leave_ibss,
+ .get_station = wl_cfg80211_get_station,
+ .set_tx_power = wl_cfg80211_set_tx_power,
+ .get_tx_power = wl_cfg80211_get_tx_power,
+ .add_key = wl_cfg80211_add_key,
+ .del_key = wl_cfg80211_del_key,
+ .get_key = wl_cfg80211_get_key,
+ .set_default_key = wl_cfg80211_config_default_key,
+ .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
+ .set_power_mgmt = wl_cfg80211_set_power_mgmt,
+ .connect = wl_cfg80211_connect,
+ .disconnect = wl_cfg80211_disconnect,
+ .suspend = wl_cfg80211_suspend,
+ .resume = wl_cfg80211_resume,
+ .set_pmksa = wl_cfg80211_set_pmksa,
+ .del_pmksa = wl_cfg80211_del_pmksa,
+ .flush_pmksa = wl_cfg80211_flush_pmksa,
+ .remain_on_channel = wl_cfg80211_remain_on_channel,
+ .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel,
+ .mgmt_tx = wl_cfg80211_mgmt_tx,
+ .mgmt_frame_register = wl_cfg80211_mgmt_frame_register,
+ .change_bss = wl_cfg80211_change_bss,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
+ .set_channel = wl_cfg80211_set_channel,
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
+ .set_beacon = wl_cfg80211_add_set_beacon,
+ .add_beacon = wl_cfg80211_add_set_beacon,
+#else
+ .change_beacon = wl_cfg80211_change_beacon,
+ .start_ap = wl_cfg80211_start_ap,
+ .stop_ap = wl_cfg80211_stop_ap,
+#endif
+#ifdef WL_SCHED_SCAN
+ .sched_scan_start = wl_cfg80211_sched_scan_start,
+ .sched_scan_stop = wl_cfg80211_sched_scan_stop,
+#endif /* WL_SCHED_SCAN */
+#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
+ 2, 0))
+ .del_station = wl_cfg80211_del_station,
+ .change_station = wl_cfg80211_change_station,
+ .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait,
+#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0))
+ .tdls_mgmt = wl_cfg80211_tdls_mgmt,
+ .tdls_oper = wl_cfg80211_tdls_oper,
+#endif
+#ifdef WL_SUPPORT_ACS
+ .dump_survey = wl_cfg80211_dump_survey,
+#endif /* WL_SUPPORT_ACS */
+#ifdef WL_CFG80211_ACL
+ .set_mac_acl = wl_cfg80211_set_mac_acl,
+#endif /* WL_CFG80211_ACL */
+ CFG80211_TESTMODE_CMD(dhd_cfg80211_testmode_cmd)
+};
+
+s32 wl_mode_to_nl80211_iftype(s32 mode)
+{
+ s32 err = 0;
+
+ switch (mode) {
+ case WL_MODE_BSS:
+ return NL80211_IFTYPE_STATION;
+ case WL_MODE_IBSS:
+ return NL80211_IFTYPE_ADHOC;
+ case WL_MODE_AP:
+ return NL80211_IFTYPE_AP;
+ default:
+ return NL80211_IFTYPE_UNSPECIFIED;
+ }
+
+ return err;
+}
+
+#ifdef CONFIG_CFG80211_INTERNAL_REGDB
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
+static int
+#else
+static void
+#endif /* kernel version < 3.9.0 */
+wl_cfg80211_reg_notifier(
+ struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
+ int ret = 0;
+
+ if (!request || !cfg) {
+ WL_ERR(("Invalid arg\n"));
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
+ return -EINVAL;
+#else
+ return;
+#endif /* kernel version < 3.9.0 */
+ }
+
+ WL_DBG(("ccode: %c%c Initiator: %d\n",
+ request->alpha2[0], request->alpha2[1], request->initiator));
+
+ /* We support only REGDOM_SET_BY_USER as of now */
+ if ((request->initiator != NL80211_REGDOM_SET_BY_USER) &&
+ (request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
+ WL_ERR(("reg_notifier for intiator:%d not supported : set default\n",
+ request->initiator));
+ /* in case of no supported country by regdb
+ lets driver setup platform default Locale
+ */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
+ return -EINVAL;
+#else
+ return;
+#endif /* kernel version < 3.9.0 */
+ }
+
+ WL_ERR(("Set country code %c%c from %s\n",
+ request->alpha2[0], request->alpha2[1],
+ ((request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) ? " 11d AP" : "User")));
+
+ if ((ret = wldev_set_country(bcmcfg_to_prmry_ndev(cfg), request->alpha2,
+ false, (request->initiator == NL80211_REGDOM_SET_BY_USER ? true : false))) < 0) {
+ WL_ERR(("set country Failed :%d\n", ret));
+ }
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
+ return ret;
+#else
+ return;
+#endif /* kernel version < 3.9.0 */
+}
+#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
+
+#ifdef CONFIG_PM
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+static const struct wiphy_wowlan_support brcm_wowlan_support = {
+ .flags = WIPHY_WOWLAN_ANY,
+ .n_patterns = WL_WOWLAN_MAX_PATTERNS,
+ .pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN,
+ .pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+ .max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN,
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+};
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */
+#endif /* CONFIG_PM */
+
+static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, void *context)
+{
+ s32 err = 0;
+#ifdef CONFIG_PM
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+ struct cfg80211_wowlan *brcm_wowlan_config = NULL;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
+#endif /* CONFIG_PM */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
+ dhd_pub_t *dhd = (dhd_pub_t *)context;
+ BCM_REFERENCE(dhd);
+
+ if (!dhd) {
+ WL_ERR(("DHD is NULL!!"));
+ err = -ENODEV;
+ return err;
+ }
+#endif
+
+ wdev->wiphy =
+ wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211));
+ if (unlikely(!wdev->wiphy)) {
+ WL_ERR(("Couldn not allocate wiphy device\n"));
+ err = -ENOMEM;
+ return err;
+ }
+ set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
+ wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
+ /* Report how many SSIDs Driver can support per Scan request */
+ wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
+ wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
+#ifdef WL_SCHED_SCAN
+ wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT;
+ wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT;
+ wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX;
+ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+#endif /* WL_SCHED_SCAN */
+ wdev->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_STATION)
+ | BIT(NL80211_IFTYPE_ADHOC)
+#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF)
+ | BIT(NL80211_IFTYPE_MONITOR)
+#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */
+#if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)
+ | BIT(NL80211_IFTYPE_P2P_CLIENT)
+ | BIT(NL80211_IFTYPE_P2P_GO)
+#endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ | BIT(NL80211_IFTYPE_P2P_DEVICE)
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ | BIT(NL80211_IFTYPE_AP);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
+ (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
+ WL_DBG(("Setting interface combinations for common mode\n"));
+ wdev->wiphy->iface_combinations = common_iface_combinations;
+ wdev->wiphy->n_iface_combinations =
+ ARRAY_SIZE(common_iface_combinations);
+#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
+
+ wdev->wiphy->bands[NL80211_BAND_2GHZ] = &__wl_band_2ghz;
+
+ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wdev->wiphy->cipher_suites = __wl_cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
+ wdev->wiphy->max_remain_on_channel_duration = 5000;
+ wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes;
+#ifndef WL_POWERSAVE_DISABLED
+ wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
+#else
+ wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+#endif /* !WL_POWERSAVE_DISABLED */
+ wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK |
+ WIPHY_FLAG_4ADDR_AP |
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39))
+ WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
+#endif
+ WIPHY_FLAG_4ADDR_STATION;
+#if (defined(ROAM_ENABLE) || defined(BCMFW_ROAM_ENABLE)) && (LINUX_VERSION_CODE >= \
+ KERNEL_VERSION(3, 2, 0))
+ /* Please use supplicant ver >= 76 if FW_ROAM is enabled
+ * If driver advertises FW_ROAM, older supplicant wouldn't
+ * send the BSSID & Freq in the connect req command. This
+ * will delay the ASSOC as the FW need to do a full scan
+ * before attempting to connect. Supplicant >=76 has patch
+ * to allow bssid & freq to be sent down to driver even if
+ * FW ROAM is advertised.
+ */
+ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
+ wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+ WIPHY_FLAG_OFFCHAN_TX;
+#endif
+#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
+ 4, 0))
+ /* From 3.4 kernel ownards AP_SME flag can be advertised
+ * to remove the patch from supplicant
+ */
+ wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
+
+#ifdef WL_CFG80211_ACL
+ /* Configure ACL capabilities. */
+ wdev->wiphy->max_acl_mac_addrs = MAX_NUM_MAC_FILT;
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
+ /* Supplicant distinguish between the SoftAP mode and other
+ * modes (e.g. P2P, WPS, HS2.0) when it builds the probe
+ * response frame from Supplicant MR1 and Kernel 3.4.0 or
+ * later version. To add Vendor specific IE into the
+ * probe response frame in case of SoftAP mode,
+ * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable.
+ */
+ if (dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) {
+ wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
+ wdev->wiphy->probe_resp_offload = 0;
+ }
+#endif
+#endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */
+
+#ifdef CONFIG_CFG80211_INTERNAL_REGDB
+ wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier;
+#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0))
+ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
+#endif
+
+#if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
+ /*
+ * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the
+ * disconnection of connected network before suspend. So a dummy wowlan
+ * filter is configured for kernels linux-3.8 and above.
+ */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+ wdev->wiphy->wowlan = &brcm_wowlan_support;
+
+ /* If this is not provided cfg stack will get disconnect
+ * during suspend.
+ */
+ brcm_wowlan_config = kzalloc(sizeof(struct cfg80211_wowlan), GFP_KERNEL);
+ if (brcm_wowlan_config) {
+ brcm_wowlan_config->disconnect = true;
+ brcm_wowlan_config->gtk_rekey_failure = true;
+ brcm_wowlan_config->eap_identity_req = true;
+ brcm_wowlan_config->four_way_handshake = true;
+ brcm_wowlan_config->patterns = NULL;
+ brcm_wowlan_config->n_patterns = 0;
+ brcm_wowlan_config->tcp = NULL;
+ } else {
+ WL_ERR(("Can not allocate memory for brcm_wowlan_config,"
+ " So wiphy->wowlan_config is set to NULL\n"));
+ }
+ wdev->wiphy->wowlan_config = brcm_wowlan_config;
+#else
+ wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
+ wdev->wiphy->wowlan.n_patterns = WL_WOWLAN_MAX_PATTERNS;
+ wdev->wiphy->wowlan.pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN;
+ wdev->wiphy->wowlan.pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+ wdev->wiphy->wowlan.max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
+#endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
+
+ WL_DBG(("Registering custom regulatory)\n"));
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+ wdev->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
+#else
+ wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+#endif
+ wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
+ WL_INFO(("Registering Vendor80211)\n"));
+ err = wl_cfgvendor_attach(wdev->wiphy);
+ if (unlikely(err < 0)) {
+ WL_ERR(("Couldn not attach vendor commands (%d)\n", err));
+ }
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
+
+
+ /* Now we can register wiphy with cfg80211 module */
+ err = wiphy_register(wdev->wiphy);
+ if (unlikely(err < 0)) {
+ WL_ERR(("Couldn not register wiphy device (%d)\n", err));
+ wiphy_free(wdev->wiphy);
+ }
+
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \
+ KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS)
+ wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS;
+#endif
+
+ return err;
+}
+
+static void wl_free_wdev(struct bcm_cfg80211 *cfg)
+{
+ struct wireless_dev *wdev = cfg->wdev;
+ struct wiphy *wiphy = NULL;
+ if (!wdev) {
+ WL_ERR(("wdev is invalid\n"));
+ return;
+ }
+ if (wdev->wiphy) {
+ wiphy = wdev->wiphy;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
+ wl_cfgvendor_detach(wdev->wiphy);
+ wdev->wiphy->wowlan = NULL;
+#endif /* if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
+ wiphy_unregister(wdev->wiphy);
+ wdev->wiphy->dev.parent = NULL;
+ wdev->wiphy = NULL;
+ }
+
+ wl_delete_all_netinfo(cfg);
+ if (wiphy)
+ wiphy_free(wiphy);
+ /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg",
+ * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!!
+ */
+}
+
+static s32 wl_inform_bss(struct bcm_cfg80211 *cfg)
+{
+ struct wl_scan_results *bss_list;
+ struct wl_bss_info *bi = NULL; /* must be initialized */
+ s32 err = 0;
+ s32 i;
+
+ bss_list = cfg->bss_list;
+ WL_DBG(("scanned AP count (%d)\n", bss_list->count));
+ bi = next_bss(bss_list, bi);
+ for_each_bss(bss_list, bi, i) {
+ err = wl_inform_single_bss(cfg, bi, false);
+ if (unlikely(err))
+ break;
+ }
+ return err;
+}
+
+static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam)
+{
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ struct ieee80211_mgmt *mgmt;
+ struct ieee80211_channel *channel;
+ struct ieee80211_supported_band *band;
+ struct wl_cfg80211_bss_info *notif_bss_info;
+ struct wl_scan_req *sr = wl_to_sr(cfg);
+ struct beacon_proberesp *beacon_proberesp;
+ struct cfg80211_bss *cbss = NULL;
+ s32 mgmt_type;
+ s32 signal;
+ u32 freq;
+ s32 err = 0;
+ gfp_t aflags;
+
+ if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) {
+ WL_DBG(("Beacon is larger than buffer. Discarding\n"));
+ return err;
+ }
+ aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
+ notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt)
+ - sizeof(u8) + WL_BSS_INFO_MAX, aflags);
+ if (unlikely(!notif_bss_info)) {
+ WL_ERR(("notif_bss_info alloc failed\n"));
+ return -ENOMEM;
+ }
+ mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf;
+ notif_bss_info->channel =
+ bi->ctl_ch ? bi->ctl_ch : wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
+
+ if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[NL80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[NL80211_BAND_5GHZ];
+ if (!band) {
+ WL_ERR(("No valid band"));
+ kfree(notif_bss_info);
+ return -EINVAL;
+ }
+ notif_bss_info->rssi = wl_rssi_offset(dtoh16(bi->RSSI));
+ memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN);
+ mgmt_type = cfg->active_scan ?
+ IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON;
+ if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) {
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type);
+ }
+ beacon_proberesp = cfg->active_scan ?
+ (struct beacon_proberesp *)&mgmt->u.probe_resp :
+ (struct beacon_proberesp *)&mgmt->u.beacon;
+ beacon_proberesp->timestamp = 0;
+ beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period);
+ beacon_proberesp->capab_info = cpu_to_le16(bi->capability);
+ wl_rst_ie(cfg);
+ wl_update_hidden_ap_ie(bi, ((u8 *) bi) + bi->ie_offset, &bi->ie_length, roam);
+ wl_mrg_ie(cfg, ((u8 *) bi) + bi->ie_offset, bi->ie_length);
+ wl_cp_ie(cfg, beacon_proberesp->variable, WL_BSS_INFO_MAX -
+ offsetof(struct wl_cfg80211_bss_info, frame_buf));
+ notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt,
+ u.beacon.variable) + wl_get_ielen(cfg);
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38)
+ freq = ieee80211_channel_to_frequency(notif_bss_info->channel);
+ (void)band->band;
+#else
+ freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band);
+#endif
+ if (freq == 0) {
+ WL_ERR(("Invalid channel, fail to chcnage channel to freq\n"));
+ kfree(notif_bss_info);
+ return -EINVAL;
+ }
+ channel = ieee80211_get_channel(wiphy, freq);
+ if (unlikely(!channel)) {
+ WL_ERR(("ieee80211_get_channel error\n"));
+ kfree(notif_bss_info);
+ return -EINVAL;
+ }
+ WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM"
+ "mgmt_type %d frame_len %d\n", bi->SSID,
+ notif_bss_info->rssi, notif_bss_info->channel,
+ mgmt->u.beacon.capab_info, &bi->BSSID, mgmt_type,
+ notif_bss_info->frame_len));
+
+ signal = notif_bss_info->rssi * 100;
+ if (!mgmt->u.probe_resp.timestamp) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+ struct timespec ts;
+ get_monotonic_boottime(&ts);
+ mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000)
+ + ts.tv_nsec / 1000;
+#else
+ struct timeval tv;
+ do_gettimeofday(&tv);
+ mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec*1000000)
+ + tv.tv_usec;
+#endif
+ }
+
+
+ cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt,
+ le16_to_cpu(notif_bss_info->frame_len), signal, aflags);
+ if (unlikely(!cbss)) {
+ WL_ERR(("cfg80211_inform_bss_frame error\n"));
+ kfree(notif_bss_info);
+ return -EINVAL;
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+ cfg80211_put_bss(wiphy, cbss);
+#else
+ cfg80211_put_bss(cbss);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+ kfree(notif_bss_info);
+ return err;
+}
+
+static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, struct net_device *ndev)
+{
+ u32 event = ntoh32(e->event_type);
+ u32 status = ntoh32(e->status);
+ u16 flags = ntoh16(e->flags);
+
+ WL_DBG(("event %d, status %d flags %x\n", event, status, flags));
+ if (event == WLC_E_SET_SSID) {
+ if (status == WLC_E_STATUS_SUCCESS) {
+ if (!wl_is_ibssmode(cfg, ndev))
+ return true;
+ }
+ } else if (event == WLC_E_LINK) {
+ if (flags & WLC_EVENT_MSG_LINK)
+ return true;
+ }
+
+ WL_DBG(("wl_is_linkup false\n"));
+ return false;
+}
+
+static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
+{
+ u32 event = ntoh32(e->event_type);
+ u16 flags = ntoh16(e->flags);
+
+ if (event == WLC_E_DEAUTH_IND ||
+ event == WLC_E_DISASSOC_IND ||
+ event == WLC_E_DISASSOC ||
+ event == WLC_E_DEAUTH) {
+#if (WL_DBG_LEVEL > 0)
+ WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event]));
+#endif /* (WL_DBG_LEVEL > 0) */
+ return true;
+ } else if (event == WLC_E_LINK) {
+ if (!(flags & WLC_EVENT_MSG_LINK)) {
+#if (WL_DBG_LEVEL > 0)
+ WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event]));
+#endif /* (WL_DBG_LEVEL > 0) */
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
+{
+ u32 event = ntoh32(e->event_type);
+ u32 status = ntoh32(e->status);
+
+ if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS)
+ return true;
+ if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS)
+ return true;
+
+ return false;
+}
+
+/* The mainline kernel >= 3.2.0 has support for indicating new/del station
+ * to AP/P2P GO via events. If this change is backported to kernel for which
+ * this driver is being built, then define WL_CFG80211_STA_EVENT. You
+ * should use this new/del sta event mechanism for BRCM supplicant >= 22.
+ */
+static s32
+wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data)
+{
+ s32 err = 0;
+ u32 event = ntoh32(e->event_type);
+ u32 reason = ntoh32(e->reason);
+ u32 len = ntoh32(e->datalen);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT)
+ bool isfree = false;
+ u8 *mgmt_frame;
+ u8 bsscfgidx = e->bsscfgidx;
+ s32 freq;
+ s32 channel;
+ u8 *body = NULL;
+ u16 fc = 0;
+
+ struct ieee80211_supported_band *band;
+ struct ether_addr da;
+ struct ether_addr bssid;
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ channel_info_t ci;
+#else
+ struct station_info sinfo;
+#endif
+
+ WL_DBG(("event %d status %d reason %d\n", event, ntoh32(e->status), reason));
+ /* if link down, bsscfg is disabled. */
+ if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS &&
+ wl_get_p2p_status(cfg, IF_DELETING) && (ndev != bcmcfg_to_prmry_ndev(cfg))) {
+ wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
+ WL_INFO(("AP mode link down !! \n"));
+ complete(&cfg->iface_disable);
+ return 0;
+ }
+
+ if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) {
+ WL_ERR(("event %s(%d) status %d reason %d\n",
+ bcmevent_names[event].name, event, ntoh32(e->status), reason));
+ }
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT)
+ WL_DBG(("Enter \n"));
+ if (!len && (event == WLC_E_DEAUTH)) {
+ len = 2; /* reason code field */
+ data = &reason;
+ }
+ if (len) {
+ body = kzalloc(len, GFP_KERNEL);
+
+ if (body == NULL) {
+ WL_ERR(("wl_notify_connect_status: Failed to allocate body\n"));
+ return WL_INVALID;
+ }
+ }
+ memset(&bssid, 0, ETHER_ADDR_LEN);
+ WL_DBG(("Enter event %d ndev %p\n", event, ndev));
+ if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
+ kfree(body);
+ return WL_INVALID;
+ }
+ if (len)
+ memcpy(body, data, len);
+
+ wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
+ NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync);
+ memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN);
+ err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+ switch (event) {
+ case WLC_E_ASSOC_IND:
+ fc = FC_ASSOC_REQ;
+ break;
+ case WLC_E_REASSOC_IND:
+ fc = FC_REASSOC_REQ;
+ break;
+ case WLC_E_DISASSOC_IND:
+ fc = FC_DISASSOC;
+ break;
+ case WLC_E_DEAUTH_IND:
+ fc = FC_DISASSOC;
+ break;
+ case WLC_E_DEAUTH:
+ fc = FC_DISASSOC;
+ break;
+ default:
+ fc = 0;
+ goto exit;
+ }
+ if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) {
+ kfree(body);
+ return err;
+ }
+
+ channel = dtoh32(ci.hw_channel);
+ if (channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[NL80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[NL80211_BAND_5GHZ];
+ if (!band) {
+ WL_ERR(("No valid band"));
+ if (body)
+ kfree(body);
+ return -EINVAL;
+ }
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38)
+ freq = ieee80211_channel_to_frequency(channel);
+ (void)band->band;
+#else
+ freq = ieee80211_channel_to_frequency(channel, band->band);
+#endif
+
+ err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid,
+ &mgmt_frame, &len, body);
+ if (err < 0)
+ goto exit;
+ isfree = true;
+
+ if ((event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) ||
+ (event == WLC_E_DISASSOC_IND) ||
+ ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH))) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
+ defined(WL_COMPAT_WIRELESS)
+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
+#else
+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+#endif
+ } else if (event == WLC_E_DISASSOC_IND) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
+#else
+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+#endif
+ } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, 0, GFP_ATOMIC);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
+#else
+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+#endif
+ }
+exit:
+ if (isfree)
+ kfree(mgmt_frame);
+ if (body)
+ kfree(body);
+#else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
+ sinfo.filled = 0;
+ if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
+ reason == DOT11_SC_SUCCESS) {
+ /* Linux ver >= 4.0 assoc_req_ies_len is used instead of
+ * STATION_INFO_ASSOC_REQ_IES flag
+ */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
+ sinfo.filled = STA_INFO_BIT(INFO_ASSOC_REQ_IES);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
+ if (!data) {
+ WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
+ return -EINVAL;
+ }
+ sinfo.assoc_req_ies = data;
+ sinfo.assoc_req_ies_len = len;
+ cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
+ } else if (event == WLC_E_DISASSOC_IND) {
+ cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
+ } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
+ cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
+ }
+#endif
+ return err;
+}
+
+static s32
+wl_get_auth_assoc_status(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e)
+{
+ u32 reason = ntoh32(e->reason);
+ u32 event = ntoh32(e->event_type);
+ struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
+ WL_DBG(("event type : %d, reason : %d\n", event, reason));
+ if (sec) {
+ switch (event) {
+ case WLC_E_ASSOC:
+ case WLC_E_AUTH:
+ sec->auth_assoc_res_status = reason;
+ default:
+ break;
+ }
+ } else
+ WL_ERR(("sec is NULL\n"));
+ return 0;
+}
+
+static s32
+wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data)
+{
+ s32 err = 0;
+ u32 event = ntoh32(e->event_type);
+ u16 flags = ntoh16(e->flags);
+ u32 status = ntoh32(e->status);
+ bool active;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ struct ieee80211_channel *channel = NULL;
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ u32 chanspec, chan;
+ u32 freq, band;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
+
+ if (event == WLC_E_JOIN) {
+ WL_DBG(("joined in IBSS network\n"));
+ }
+ if (event == WLC_E_START) {
+ WL_DBG(("started IBSS network\n"));
+ }
+ if (event == WLC_E_JOIN || event == WLC_E_START ||
+ (event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
+ if (unlikely(err)) {
+ WL_ERR(("Could not get chanspec %d\n", err));
+ return err;
+ }
+ chan = wf_chspec_ctlchan(wl_chspec_driver_to_host(chanspec));
+ band = (chan <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
+ freq = ieee80211_channel_to_frequency(chan, band);
+ channel = ieee80211_get_channel(wiphy, freq);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
+ if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
+ /* ROAM or Redundant */
+ u8 *cur_bssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+ if (memcmp(cur_bssid, &e->addr, ETHER_ADDR_LEN) == 0) {
+ WL_DBG(("IBSS connected event from same BSSID("
+ MACDBG "), ignore it\n", MAC2STRDBG(cur_bssid)));
+ return err;
+ }
+ WL_INFO(("IBSS BSSID is changed from " MACDBG " to " MACDBG "\n",
+ MAC2STRDBG(cur_bssid), MAC2STRDBG((u8 *)&e->addr)));
+ wl_get_assoc_ies(cfg, ndev);
+ wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
+ wl_update_bss_info(cfg, ndev, false);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ cfg80211_ibss_joined(ndev, (s8 *)&e->addr, channel, GFP_KERNEL);
+#else
+ cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL);
+#endif
+ }
+ else {
+ /* New connection */
+ WL_INFO(("IBSS connected to " MACDBG "\n", MAC2STRDBG((u8 *)&e->addr)));
+ wl_link_up(cfg);
+ wl_get_assoc_ies(cfg, ndev);
+ wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
+ wl_update_bss_info(cfg, ndev, false);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ cfg80211_ibss_joined(ndev, (s8 *)&e->addr, channel, GFP_KERNEL);
+#else
+ cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL);
+#endif
+ wl_set_drv_status(cfg, CONNECTED, ndev);
+ active = true;
+ wl_update_prof(cfg, ndev, NULL, (void *)&active, WL_PROF_ACT);
+ }
+ } else if ((event == WLC_E_LINK && !(flags & WLC_EVENT_MSG_LINK)) ||
+ event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
+ wl_clr_drv_status(cfg, CONNECTED, ndev);
+ wl_clr_drv_status(cfg, DISCONNECTING, ndev);
+ wl_link_down(cfg);
+ wl_init_prof(cfg, ndev);
+ }
+ else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) {
+ WL_DBG(("no action - join fail (IBSS mode)\n"));
+ }
+ else {
+ WL_DBG(("no action (IBSS mode)\n"));
+}
+ return err;
+}
+
+static s32
+wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ bool act;
+ struct net_device *ndev = NULL;
+ s32 err = 0;
+ u32 event = ntoh32(e->event_type);
+ struct wiphy *wiphy = NULL;
+ struct cfg80211_bss *bss = NULL;
+ struct wlc_ssid *ssid = NULL;
+ u8 *bssid = 0;
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
+ err = wl_notify_connect_status_ap(cfg, ndev, e, data);
+ } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS) {
+ err = wl_notify_connect_status_ibss(cfg, ndev, e, data);
+ } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_BSS) {
+ WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n",
+ ntoh32(e->event_type), ntoh32(e->status), ndev));
+ if (event == WLC_E_ASSOC || event == WLC_E_AUTH) {
+ wl_get_auth_assoc_status(cfg, ndev, e);
+ return 0;
+ }
+ if (wl_is_linkup(cfg, e, ndev)) {
+ wl_link_up(cfg);
+ act = true;
+ if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
+ printk("wl_bss_connect_done succeeded with " MACDBG "\n",
+ MAC2STRDBG((u8*)(&e->addr)));
+ wl_bss_connect_done(cfg, ndev, e, data, true);
+ WL_DBG(("joined in BSS network \"%s\"\n",
+ ((struct wlc_ssid *)
+ wl_read_prof(cfg, ndev, WL_PROF_SSID))->SSID));
+ }
+ wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
+ wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
+
+ } else if (wl_is_linkdown(cfg, e)) {
+ if (cfg->scan_request)
+ wl_notify_escan_complete(cfg, ndev, true, true);
+ /* Explicitly calling unlink to remove BSS in CFG */
+ wiphy = bcmcfg_to_wiphy(cfg);
+ ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
+ bssid = (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+ if (ssid && bssid) {
+ bss = cfg80211_get_bss(wiphy, NULL, bssid,
+ ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS,
+ WLAN_CAPABILITY_ESS);
+ if (bss) {
+ cfg80211_unlink_bss(wiphy, bss);
+ }
+ }
+ if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
+ scb_val_t scbval;
+ u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+ s32 reason = 0;
+ struct ether_addr bssid;
+
+ if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND)
+ reason = ntoh32(e->reason);
+ /* WLAN_REASON_UNSPECIFIED is used for hang up event in Android */
+ reason = (reason == WLAN_REASON_UNSPECIFIED)? 0 : reason;
+
+ printk("link down if %s may call cfg80211_disconnected. "
+ "event : %d, reason=%d from " MACDBG "\n",
+ ndev->name, event, ntoh32(e->reason),
+ MAC2STRDBG((u8*)(&e->addr)));
+
+ /* roam offload does not synch BSSID always, get it from dongle */
+ if (cfg->roam_offload) {
+ if (wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, sizeof(bssid),
+ false) == BCME_OK) {
+ curbssid = (u8 *)&bssid;
+ }
+ }
+
+ if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
+ WL_ERR(("BSSID of event is not the connected BSSID"
+ "(ignore it) cur: " MACDBG " event: " MACDBG"\n",
+ MAC2STRDBG(curbssid), MAC2STRDBG((u8*)(&e->addr))));
+ return 0;
+ }
+
+ wl_clr_drv_status(cfg, CONNECTED, ndev);
+
+ if (! wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
+ /* To make sure disconnect, explictly send dissassoc
+ * for BSSID 00:00:00:00:00:00 issue
+ */
+ scbval.val = WLAN_REASON_DEAUTH_LEAVING;
+
+ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
+ scbval.val = htod32(scbval.val);
+ err = wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
+ sizeof(scb_val_t), true);
+ if (err < 0) {
+ WL_ERR(("WLC_DISASSOC error %d\n", err));
+ err = 0;
+ }
+ CFG80211_DISCONNECTED(ndev, reason, NULL, 0,
+ false, GFP_KERNEL);
+ wl_link_down(cfg);
+ wl_init_prof(cfg, ndev);
+ }
+ }
+ else if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
+ printk("link down, during connecting\n");
+#ifdef ESCAN_RESULT_PATCH
+ if ((memcmp(connect_req_bssid, broad_bssid, ETHER_ADDR_LEN) == 0) ||
+ (memcmp(&e->addr, broad_bssid, ETHER_ADDR_LEN) == 0) ||
+ (memcmp(&e->addr, connect_req_bssid, ETHER_ADDR_LEN) == 0))
+ /* In case this event comes while associating another AP */
+#endif /* ESCAN_RESULT_PATCH */
+ wl_bss_connect_done(cfg, ndev, e, data, false);
+ }
+ wl_clr_drv_status(cfg, DISCONNECTING, ndev);
+
+ /* if link down, bsscfg is diabled */
+ if (ndev != bcmcfg_to_prmry_ndev(cfg))
+ complete(&cfg->iface_disable);
+
+ } else if (wl_is_nonetwork(cfg, e)) {
+ printk("connect failed event=%d e->status %d e->reason %d \n",
+ event, (int)ntoh32(e->status), (int)ntoh32(e->reason));
+ /* Clean up any pending scan request */
+ if (cfg->scan_request)
+ wl_notify_escan_complete(cfg, ndev, true, true);
+ if (wl_get_drv_status(cfg, CONNECTING, ndev))
+ wl_bss_connect_done(cfg, ndev, e, data, false);
+ } else {
+ WL_DBG(("%s nothing\n", __FUNCTION__));
+ }
+ }
+ else {
+ WL_ERR(("Invalid ndev status %d\n", wl_get_mode_by_netdev(cfg, ndev)));
+ }
+ return err;
+}
+
+#ifdef WL_RELMCAST
+void wl_cfg80211_set_rmc_pid(int pid)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ if (pid > 0)
+ cfg->rmc_event_pid = pid;
+ WL_DBG(("set pid for rmc event : pid=%d\n", pid));
+}
+#endif /* WL_RELMCAST */
+
+
+#ifdef WL_RELMCAST
+static s32
+wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ u32 evt = ntoh32(e->event_type);
+ u32 reason = ntoh32(e->reason);
+ int ret = -1;
+
+ switch (reason) {
+ case WLC_E_REASON_RMC_AR_LOST:
+ case WLC_E_REASON_RMC_AR_NO_ACK:
+ if (cfg->rmc_event_pid != 0) {
+ ret = wl_netlink_send_msg(cfg->rmc_event_pid,
+ RMC_EVENT_LEADER_CHECK_FAIL,
+ cfg->rmc_event_seq++, NULL, 0);
+ }
+ break;
+ default:
+ break;
+ }
+ WL_DBG(("rmcevent : evt=%d, pid=%d, ret=%d\n", evt, cfg->rmc_event_pid, ret));
+ return ret;
+}
+#endif /* WL_RELMCAST */
+
+static s32
+wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ bool act;
+ struct net_device *ndev = NULL;
+ s32 err = 0;
+ u32 event = be32_to_cpu(e->event_type);
+ u32 status = be32_to_cpu(e->status);
+ WL_DBG(("Enter \n"));
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ if ((!cfg->disable_roam_event) && (event == WLC_E_BSSID)) {
+ wl_add_remove_eventmsg(ndev, WLC_E_ROAM, false);
+ cfg->disable_roam_event = TRUE;
+ }
+
+ if ((cfg->disable_roam_event) && (event == WLC_E_ROAM))
+ return err;
+
+ if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status == WLC_E_STATUS_SUCCESS) {
+ if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
+ if (cfg->roam_offload &&
+ memcmp(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN) == 0) {
+ WL_INFO(("BSSID already updated\n"));
+ return err;
+ }
+ wl_bss_roaming_done(cfg, ndev, e, data);
+ memcpy(&cfg->last_roamed_addr, (void *)&e->addr, ETHER_ADDR_LEN);
+ } else {
+ wl_bss_connect_done(cfg, ndev, e, data, true);
+ }
+ act = true;
+ wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
+ wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);
+ }
+ return err;
+}
+
+static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ wl_assoc_info_t assoc_info;
+ struct wl_connect_info *conn_info = wl_to_conn(cfg);
+ s32 err = 0;
+
+ WL_DBG(("Enter \n"));
+ err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, cfg->extra_buf,
+ WL_ASSOC_INFO_MAX, NULL);
+ if (unlikely(err)) {
+ WL_ERR(("could not get assoc info (%d)\n", err));
+ return err;
+ }
+ memcpy(&assoc_info, cfg->extra_buf, sizeof(wl_assoc_info_t));
+ assoc_info.req_len = htod32(assoc_info.req_len);
+ assoc_info.resp_len = htod32(assoc_info.resp_len);
+ assoc_info.flags = htod32(assoc_info.flags);
+ if (conn_info->req_ie_len) {
+ conn_info->req_ie_len = 0;
+ bzero(conn_info->req_ie, sizeof(conn_info->req_ie));
+ }
+ if (conn_info->resp_ie_len) {
+ conn_info->resp_ie_len = 0;
+ bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
+ }
+ if (assoc_info.req_len) {
+ err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf,
+ WL_ASSOC_INFO_MAX, NULL);
+ if (unlikely(err)) {
+ WL_ERR(("could not get assoc req (%d)\n", err));
+ return err;
+ }
+ conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req);
+ if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
+ conn_info->req_ie_len -= ETHER_ADDR_LEN;
+ }
+ if (conn_info->req_ie_len <= MAX_REQ_LINE)
+ memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len);
+ else {
+ WL_ERR(("IE size %d above max %d size \n",
+ conn_info->req_ie_len, MAX_REQ_LINE));
+ return err;
+ }
+ } else {
+ conn_info->req_ie_len = 0;
+ }
+ if (assoc_info.resp_len) {
+ err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf,
+ WL_ASSOC_INFO_MAX, NULL);
+ if (unlikely(err)) {
+ WL_ERR(("could not get assoc resp (%d)\n", err));
+ return err;
+ }
+ conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp);
+ if (conn_info->resp_ie_len <= MAX_REQ_LINE)
+ memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len);
+ else {
+ WL_ERR(("IE size %d above max %d size \n",
+ conn_info->resp_ie_len, MAX_REQ_LINE));
+ return err;
+ }
+ } else {
+ conn_info->resp_ie_len = 0;
+ }
+ WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len,
+ conn_info->resp_ie_len));
+
+ return err;
+}
+
+static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params,
+ size_t *join_params_size)
+{
+ chanspec_t chanspec = 0;
+ if (ch != 0) {
+ join_params->params.chanspec_num = 1;
+ join_params->params.chanspec_list[0] = ch;
+
+ if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
+ chanspec |= WL_CHANSPEC_BAND_2G;
+ else
+ chanspec |= WL_CHANSPEC_BAND_5G;
+
+ chanspec |= WL_CHANSPEC_BW_20;
+ chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+
+ *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
+ join_params->params.chanspec_num * sizeof(chanspec_t);
+
+ join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
+ join_params->params.chanspec_list[0] |= chanspec;
+ join_params->params.chanspec_list[0] =
+ wl_chspec_host_to_driver(join_params->params.chanspec_list[0]);
+
+ join_params->params.chanspec_num =
+ htod32(join_params->params.chanspec_num);
+ WL_DBG(("join_params->params.chanspec_list[0]= %X, %d channels\n",
+ join_params->params.chanspec_list[0],
+ join_params->params.chanspec_num));
+ }
+}
+
+static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam)
+{
+ struct cfg80211_bss *bss;
+ struct wl_bss_info *bi;
+ struct wlc_ssid *ssid;
+ struct bcm_tlv *tim;
+ s32 beacon_interval;
+ s32 dtim_period;
+ size_t ie_len;
+ u8 *ie;
+ u8 *curbssid;
+ s32 err = 0;
+ struct wiphy *wiphy;
+ u32 channel;
+
+ wiphy = bcmcfg_to_wiphy(cfg);
+
+ ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
+ curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+ bss = cfg80211_get_bss(wiphy, NULL, curbssid,
+ ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS,
+ WLAN_CAPABILITY_ESS);
+
+ mutex_lock(&cfg->usr_sync);
+
+ *(u32 *) cfg->extra_buf = htod32(WL_EXTRA_BUF_MAX);
+ err = wldev_ioctl(ndev, WLC_GET_BSS_INFO,
+ cfg->extra_buf, WL_EXTRA_BUF_MAX, false);
+ if (unlikely(err)) {
+ WL_ERR(("Could not get bss info %d\n", err));
+ goto update_bss_info_out;
+ }
+ bi = (struct wl_bss_info *)(cfg->extra_buf + 4);
+ channel = bi->ctl_ch ? bi->ctl_ch :
+ CHSPEC_CHANNEL(wl_chspec_driver_to_host(bi->chanspec));
+ wl_update_prof(cfg, ndev, NULL, &channel, WL_PROF_CHAN);
+
+ if (!bss) {
+ WL_DBG(("Could not find the AP\n"));
+ if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) {
+ WL_ERR(("Bssid doesn't match\n"));
+ err = -EIO;
+ goto update_bss_info_out;
+ }
+ err = wl_inform_single_bss(cfg, bi, roam);
+ if (unlikely(err))
+ goto update_bss_info_out;
+
+ ie = ((u8 *)bi) + bi->ie_offset;
+ ie_len = bi->ie_length;
+ beacon_interval = cpu_to_le16(bi->beacon_period);
+ } else {
+ WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid));
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ ie = (u8 *)bss->ies->data;
+ ie_len = bss->ies->len;
+#else
+ ie = bss->information_elements;
+ ie_len = bss->len_information_elements;
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ beacon_interval = bss->beacon_interval;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+ cfg80211_put_bss(wiphy, bss);
+#else
+ cfg80211_put_bss(bss);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+ }
+
+ tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
+ if (tim) {
+ dtim_period = tim->data[1];
+ } else {
+ /*
+ * active scan was done so we could not get dtim
+ * information out of probe response.
+ * so we speficially query dtim information.
+ */
+ err = wldev_ioctl(ndev, WLC_GET_DTIMPRD,
+ &dtim_period, sizeof(dtim_period), false);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
+ goto update_bss_info_out;
+ }
+ }
+
+ wl_update_prof(cfg, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT);
+ wl_update_prof(cfg, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
+
+update_bss_info_out:
+ if (unlikely(err)) {
+ WL_ERR(("Failed with error %d\n", err));
+ }
+ mutex_unlock(&cfg->usr_sync);
+ return err;
+}
+
+static s32
+wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data)
+{
+ struct wl_connect_info *conn_info = wl_to_conn(cfg);
+ s32 err = 0;
+ u8 *curbssid;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ struct ieee80211_supported_band *band;
+ struct ieee80211_channel *notify_channel = NULL;
+ u32 *channel;
+ u32 freq;
+#endif
+
+
+ wl_get_assoc_ies(cfg, ndev);
+ wl_update_prof(cfg, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
+ curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+ wl_update_bss_info(cfg, ndev, true);
+ wl_update_pmklist(ndev, cfg->pmk_list, err);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
+ /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */
+ channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
+ if (*channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[NL80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[NL80211_BAND_5GHZ];
+ freq = ieee80211_channel_to_frequency(*channel, band->band);
+ notify_channel = ieee80211_get_channel(wiphy, freq);
+#endif
+ printk("wl_bss_roaming_done succeeded to " MACDBG "\n",
+ MAC2STRDBG((u8*)(&e->addr)));
+
+ cfg80211_roamed(ndev,
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39))
+ notify_channel,
+#endif
+ curbssid,
+ conn_info->req_ie, conn_info->req_ie_len,
+ conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
+ WL_DBG(("Report roaming result\n"));
+
+ wl_set_drv_status(cfg, CONNECTED, ndev);
+
+ return err;
+}
+
+static s32
+wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data, bool completed)
+{
+ struct wl_connect_info *conn_info = wl_to_conn(cfg);
+ struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
+#if (defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)) || \
+ defined(CUSTOM_SET_CPUCORE)
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+#endif /* (ROAM_ENABLE && ROAM_AP_ENV_DETECTION) || CUSTOM_SET_CPUCORE */
+ s32 err = 0;
+ u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+ if (!sec) {
+ WL_ERR(("sec is NULL\n"));
+ return -ENODEV;
+ }
+ WL_DBG((" enter\n"));
+#ifdef ESCAN_RESULT_PATCH
+ if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
+ if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) {
+ WL_DBG((" Connected event of connected device e=%d s=%d, ignore it\n",
+ ntoh32(e->event_type), ntoh32(e->status)));
+ return err;
+ }
+ }
+ if (memcmp(curbssid, broad_bssid, ETHER_ADDR_LEN) == 0 &&
+ memcmp(broad_bssid, connect_req_bssid, ETHER_ADDR_LEN) != 0) {
+ WL_DBG(("copy bssid\n"));
+ memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN);
+ }
+
+#else
+ if (cfg->scan_request) {
+ wl_notify_escan_complete(cfg, ndev, true, true);
+ }
+#endif /* ESCAN_RESULT_PATCH */
+ if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
+ wl_cfg80211_scan_abort(cfg);
+ wl_clr_drv_status(cfg, CONNECTING, ndev);
+ if (completed) {
+ wl_get_assoc_ies(cfg, ndev);
+ wl_update_prof(cfg, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
+ curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+ wl_update_bss_info(cfg, ndev, false);
+ wl_update_pmklist(ndev, cfg->pmk_list, err);
+ wl_set_drv_status(cfg, CONNECTED, ndev);
+#if defined(ROAM_ENABLE) && defined(ROAM_AP_ENV_DETECTION)
+ if (dhd->roam_env_detection)
+ wldev_iovar_setint(ndev, "roam_env_detection",
+ AP_ENV_INDETERMINATE);
+#endif /* ROAM_AP_ENV_DETECTION */
+ if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
+ init_completion(&cfg->iface_disable);
+#else
+ /* reinitialize completion to clear previous count */
+ INIT_COMPLETION(cfg->iface_disable);
+#endif
+ }
+#ifdef CUSTOM_SET_CPUCORE
+ if (wl_get_chan_isvht80(ndev, dhd)) {
+ if (ndev == bcmcfg_to_prmry_ndev(cfg))
+ dhd->chan_isvht80 |= DHD_FLAG_STA_MODE; /* STA mode */
+ else if (is_p2p_group_iface(dev->ieee80211_ptr))
+ dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE; /* p2p mode */
+ dhd_set_cpucore(dhd, TRUE);
+ }
+#endif /* CUSTOM_SET_CPUCORE */
+ memset(&cfg->last_roamed_addr, 0, ETHER_ADDR_LEN);
+ }
+ cfg80211_connect_result(ndev,
+ curbssid,
+ conn_info->req_ie,
+ conn_info->req_ie_len,
+ conn_info->resp_ie,
+ conn_info->resp_ie_len,
+ completed ? WLAN_STATUS_SUCCESS :
+ (sec->auth_assoc_res_status) ?
+ sec->auth_assoc_res_status :
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
+ if (completed)
+ WL_INFO(("Report connect result - connection succeeded\n"));
+ else
+ WL_ERR(("Report connect result - connection failed\n"));
+ }
+#ifdef CONFIG_TCPACK_FASTTX
+ if (wl_get_chan_isvht80(ndev, dhd))
+ wldev_iovar_setint(ndev, "tcpack_fast_tx", 0);
+ else
+ wldev_iovar_setint(ndev, "tcpack_fast_tx", 1);
+#endif /* CONFIG_TCPACK_FASTTX */
+
+ return err;
+}
+
+static s32
+wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ struct net_device *ndev = NULL;
+ u16 flags = ntoh16(e->flags);
+ enum nl80211_key_type key_type;
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ mutex_lock(&cfg->usr_sync);
+ if (flags & WLC_EVENT_MSG_GROUP)
+ key_type = NL80211_KEYTYPE_GROUP;
+ else
+ key_type = NL80211_KEYTYPE_PAIRWISE;
+
+ cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1,
+ NULL, GFP_KERNEL);
+ mutex_unlock(&cfg->usr_sync);
+
+ return 0;
+}
+
+#ifdef PNO_SUPPORT
+static s32
+wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ struct net_device *ndev = NULL;
+
+ WL_ERR((">>> PNO Event\n"));
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+#ifndef WL_SCHED_SCAN
+ mutex_lock(&cfg->usr_sync);
+ /* TODO: Use cfg80211_sched_scan_results(wiphy); */
+ CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
+ mutex_unlock(&cfg->usr_sync);
+#else
+ /* If cfg80211 scheduled scan is supported, report the pno results via sched
+ * scan results
+ */
+ wl_notify_sched_scan_results(cfg, ndev, e, data);
+#endif /* WL_SCHED_SCAN */
+ return 0;
+}
+#endif /* PNO_SUPPORT */
+
+static s32
+wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ struct channel_info channel_inform;
+ struct wl_scan_results *bss_list;
+ struct net_device *ndev = NULL;
+ u32 len = WL_SCAN_BUF_MAX;
+ s32 err = 0;
+ unsigned long flags;
+
+ WL_DBG(("Enter \n"));
+ if (!wl_get_drv_status(cfg, SCANNING, ndev)) {
+ WL_ERR(("scan is not ready \n"));
+ return err;
+ }
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ mutex_lock(&cfg->usr_sync);
+ wl_clr_drv_status(cfg, SCANNING, ndev);
+ err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform,
+ sizeof(channel_inform), false);
+ if (unlikely(err)) {
+ WL_ERR(("scan busy (%d)\n", err));
+ goto scan_done_out;
+ }
+ channel_inform.scan_channel = dtoh32(channel_inform.scan_channel);
+ if (unlikely(channel_inform.scan_channel)) {
+
+ WL_DBG(("channel_inform.scan_channel (%d)\n",
+ channel_inform.scan_channel));
+ }
+ cfg->bss_list = cfg->scan_results;
+ bss_list = cfg->bss_list;
+ memset(bss_list, 0, len);
+ bss_list->buflen = htod32(len);
+ err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, false);
+ if (unlikely(err) && unlikely(!cfg->scan_suppressed)) {
+ WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err));
+ err = -EINVAL;
+ goto scan_done_out;
+ }
+ bss_list->buflen = dtoh32(bss_list->buflen);
+ bss_list->version = dtoh32(bss_list->version);
+ bss_list->count = dtoh32(bss_list->count);
+
+ err = wl_inform_bss(cfg);
+
+scan_done_out:
+ del_timer_sync(&cfg->scan_timeout);
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+ if (cfg->scan_request) {
+ struct cfg80211_scan_info info = {
+ .aborted = false,
+ };
+
+ cfg80211_scan_done(cfg->scan_request, &info);
+ cfg->scan_request = NULL;
+ }
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+ WL_DBG(("cfg80211_scan_done\n"));
+ mutex_unlock(&cfg->usr_sync);
+ return err;
+}
+
+static s32
+wl_frame_get_mgmt(u16 fc, const struct ether_addr *da,
+ const struct ether_addr *sa, const struct ether_addr *bssid,
+ u8 **pheader, u32 *body_len, u8 *pbody)
+{
+ struct dot11_management_header *hdr;
+ u32 totlen = 0;
+ s32 err = 0;
+ u8 *offset;
+ u32 prebody_len = *body_len;
+ switch (fc) {
+ case FC_ASSOC_REQ:
+ /* capability , listen interval */
+ totlen = DOT11_ASSOC_REQ_FIXED_LEN;
+ *body_len += DOT11_ASSOC_REQ_FIXED_LEN;
+ break;
+
+ case FC_REASSOC_REQ:
+ /* capability, listen inteval, ap address */
+ totlen = DOT11_REASSOC_REQ_FIXED_LEN;
+ *body_len += DOT11_REASSOC_REQ_FIXED_LEN;
+ break;
+ }
+ totlen += DOT11_MGMT_HDR_LEN + prebody_len;
+ *pheader = kzalloc(totlen, GFP_KERNEL);
+ if (*pheader == NULL) {
+ WL_ERR(("memory alloc failed \n"));
+ return -ENOMEM;
+ }
+ hdr = (struct dot11_management_header *) (*pheader);
+ hdr->fc = htol16(fc);
+ hdr->durid = 0;
+ hdr->seq = 0;
+ offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len);
+ bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN);
+ bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN);
+ bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN);
+ if ((pbody != NULL) && prebody_len)
+ bcopy((const char*)pbody, offset, prebody_len);
+ *body_len = totlen;
+ return err;
+}
+
+
+void
+wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
+ if (timer_pending(&cfg->p2p->listen_timer)) {
+ del_timer_sync(&cfg->p2p->listen_timer);
+ }
+ if (cfg->afx_hdl != NULL) {
+ if (cfg->afx_hdl->dev != NULL) {
+ wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
+ wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, cfg->afx_hdl->dev);
+ }
+ cfg->afx_hdl->peer_chan = WL_INVALID;
+ }
+ complete(&cfg->act_frm_scan);
+ WL_DBG(("*** Wake UP ** Working afx searching is cleared\n"));
+ } else if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) {
+ if (!(wl_get_p2p_status(cfg, ACTION_TX_COMPLETED) ||
+ wl_get_p2p_status(cfg, ACTION_TX_NOACK)))
+ wl_set_p2p_status(cfg, ACTION_TX_COMPLETED);
+
+ WL_DBG(("*** Wake UP ** abort actframe iovar\n"));
+ /* if channel is not zero, "actfame" uses off channel scan.
+ * So abort scan for off channel completion.
+ */
+ if (cfg->af_sent_channel)
+ wl_cfg80211_scan_abort(cfg);
+ }
+#ifdef WL_CFG80211_SYNC_GON
+ else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
+ WL_DBG(("*** Wake UP ** abort listen for next af frame\n"));
+ /* So abort scan to cancel listen */
+ wl_cfg80211_scan_abort(cfg);
+ }
+#endif /* WL_CFG80211_SYNC_GON */
+}
+
+
+int wl_cfg80211_get_ioctl_version(void)
+{
+ return ioctl_version;
+}
+
+static s32
+wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ struct ieee80211_supported_band *band;
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ struct ether_addr da;
+ struct ether_addr bssid;
+ bool isfree = false;
+ s32 err = 0;
+ s32 freq;
+ struct net_device *ndev = NULL;
+ wifi_p2p_pub_act_frame_t *act_frm = NULL;
+ wifi_p2p_action_frame_t *p2p_act_frm = NULL;
+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
+ wl_event_rx_frame_data_t *rxframe =
+ (wl_event_rx_frame_data_t*)data;
+ u32 event = ntoh32(e->event_type);
+ u8 *mgmt_frame;
+ u8 bsscfgidx = e->bsscfgidx;
+ u32 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t);
+ u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK));
+ bool retval;
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
+
+ memset(&bssid, 0, ETHER_ADDR_LEN);
+
+ if (cfg->bss_cfgdev &&
+ (dhdp->op_mode & DHD_FLAG_HOSTAP_MODE) &&
+ event == WLC_E_PROBREQ_MSG) {
+ /* Handle probe reqs frame
+ * WPS-AP certification 4.2.13
+ */
+ ndev = cfgdev_to_wlc_ndev(cfg->bss_cfgdev, cfg);
+ cfgdev = cfg->bss_cfgdev;
+ } else {
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+ }
+#ifdef P2PONEINT
+ WL_DBG((" device name is ndev %s \n", ndev->name));
+#endif
+
+ if (channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[NL80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[NL80211_BAND_5GHZ];
+ if (!band) {
+ WL_ERR(("No valid band"));
+ return -EINVAL;
+ }
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38)
+ freq = ieee80211_channel_to_frequency(channel);
+ (void)band->band;
+#else
+ freq = ieee80211_channel_to_frequency(channel, band->band);
+#endif
+ if (event == WLC_E_ACTION_FRAME_RX) {
+ wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
+ NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync);
+
+ err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+ if (err < 0)
+ WL_ERR(("WLC_GET_BSSID error %d\n", err));
+ memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN);
+ err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid,
+ &mgmt_frame, &mgmt_frame_len,
+ (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
+ if (err < 0) {
+ WL_ERR(("Error in receiving action frame len %d channel %d freq %d\n",
+ mgmt_frame_len, channel, freq));
+ goto exit;
+ }
+ isfree = true;
+ if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
+ act_frm = (wifi_p2p_pub_act_frame_t *)
+ (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+ } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
+ p2p_act_frm = (wifi_p2p_action_frame_t *)
+ (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+ (void) p2p_act_frm;
+ } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
+
+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)
+ (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+ if (sd_act_frm && wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
+ if (cfg->next_af_subtype == sd_act_frm->action) {
+ WL_DBG(("We got a right next frame of SD!(%d)\n",
+ sd_act_frm->action));
+ wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
+
+ /* Stop waiting for next AF. */
+ wl_stop_wait_next_action_frame(cfg, ndev);
+ }
+ }
+ (void) sd_act_frm;
+#ifdef WLTDLS
+ } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) {
+ WL_DBG((" TDLS Action Frame Received type = %d \n",
+ mgmt_frame[DOT11_MGMT_HDR_LEN + 1]));
+
+ if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) {
+ cfg->tdls_mgmt_frame = mgmt_frame;
+ cfg->tdls_mgmt_frame_len = mgmt_frame_len;
+ cfg->tdls_mgmt_freq = freq;
+ return 0;
+ }
+
+ } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_VENDOR_SPECIFIC) {
+ WL_DBG((" TDLS Vendor Specific Received type \n"));
+#endif
+ } else {
+
+ if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
+ u8 action = 0;
+ if (wl_get_public_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN, &action) != BCME_OK) {
+ WL_DBG(("Recived action is not public action frame\n"));
+ } else if (cfg->next_af_subtype == action) {
+ WL_DBG(("Recived action is the waiting action(%d)\n",
+ action));
+ wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
+
+ /* Stop waiting for next AF. */
+ wl_stop_wait_next_action_frame(cfg, ndev);
+ }
+ }
+ }
+
+ if (act_frm) {
+
+ if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
+ if (cfg->next_af_subtype == act_frm->subtype) {
+ WL_DBG(("We got a right next frame!(%d)\n",
+ act_frm->subtype));
+ wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
+
+ if (cfg->next_af_subtype == P2P_PAF_GON_CONF) {
+ OSL_SLEEP(20);
+ }
+
+ /* Stop waiting for next AF. */
+ wl_stop_wait_next_action_frame(cfg, ndev);
+ }
+ }
+ }
+
+ wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN, channel);
+ /*
+ * After complete GO Negotiation, roll back to mpc mode
+ */
+ if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) ||
+ (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) {
+ wldev_iovar_setint(ndev, "mpc", 1);
+ }
+ if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) {
+ WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
+ wl_clr_p2p_status(cfg, GO_NEG_PHASE);
+ }
+ } else if (event == WLC_E_PROBREQ_MSG) {
+
+ /* Handle probe reqs frame
+ * WPS-AP certification 4.2.13
+ */
+ struct parsed_ies prbreq_ies;
+ u32 prbreq_ie_len = 0;
+ bool pbc = 0;
+
+ WL_DBG((" Event WLC_E_PROBREQ_MSG received\n"));
+ mgmt_frame = (u8 *)(data);
+ mgmt_frame_len = ntoh32(e->datalen);
+
+ prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN;
+
+ /* Parse prob_req IEs */
+ if (wl_cfg80211_parse_ies(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ prbreq_ie_len, &prbreq_ies) < 0) {
+ WL_ERR(("Prob req get IEs failed\n"));
+ return 0;
+ }
+ if (prbreq_ies.wps_ie != NULL) {
+ wl_validate_wps_ie((char *)prbreq_ies.wps_ie, prbreq_ies.wps_ie_len, &pbc);
+ WL_DBG((" wps_ie exist pbc = %d\n", pbc));
+ /* if pbc method, send prob_req mgmt frame to upper layer */
+ if (!pbc)
+ return 0;
+ } else
+ return 0;
+ } else {
+ mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
+
+ /* wpa supplicant use probe request event for restarting another GON Req.
+ * but it makes GON Req repetition.
+ * so if src addr of prb req is same as my target device,
+ * do not send probe request event during sending action frame.
+ */
+ if (event == WLC_E_P2P_PROBREQ_MSG) {
+ WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ?
+ "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG"));
+
+
+ /* Filter any P2P probe reqs arriving during the
+ * GO-NEG Phase
+ */
+ if (cfg->p2p &&
+ wl_get_p2p_status(cfg, GO_NEG_PHASE)) {
+ WL_DBG(("Filtering P2P probe_req while "
+ "being in GO-Neg state\n"));
+ return 0;
+ }
+ }
+ }
+
+#ifdef P2PONEINT
+ if (ndev == cfg->p2p_net && ndev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
+ ndev = bcmcfg_to_prmry_ndev(cfg);
+ cfgdev = ndev_to_cfgdev(ndev);
+ }
+ WL_DBG((" device name is ndev %s \n", ndev->name));
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+ retval = cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+ retval = cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
+ defined(WL_COMPAT_WIRELESS)
+ retval = cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
+#else
+ retval = cfg80211_rx_mgmt(cfgdev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
+#endif /* LINUX_VERSION >= VERSION(3, 18, 0) */
+
+ WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d) retval (%d)\n",
+ mgmt_frame_len, ntoh32(e->datalen), channel, freq, retval));
+exit:
+ if (isfree)
+ kfree(mgmt_frame);
+ return 0;
+}
+
+#ifdef WL_SCHED_SCAN
+/* If target scan is not reliable, set the below define to "1" to do a
+ * full escan
+ */
+#define FULL_ESCAN_ON_PFN_NET_FOUND 0
+static s32
+wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data)
+{
+ wl_pfn_net_info_t *netinfo, *pnetinfo;
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ int err = 0;
+ struct cfg80211_scan_request *request = NULL;
+ struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT];
+ struct ieee80211_channel *channel = NULL;
+ int channel_req = 0;
+ int band = 0;
+ struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data;
+ int n_pfn_results = pfn_result->count;
+
+ WL_DBG(("Enter\n"));
+
+ if ((e->event_type == WLC_E_PFN_NET_LOST) || !data) {
+ WL_PNO(("Do Nothing %d\n", e->event_type));
+ return 0;
+ }
+ if (pfn_result->version != PFN_SCANRESULT_VERSION) {
+ WL_ERR(("Incorrect version %d, expected %d\n", pfn_result->version,
+ PFN_SCANRESULT_VERSION));
+ return 0;
+ }
+ WL_PNO((">>> PFN NET FOUND event. count:%d \n", n_pfn_results));
+ if (n_pfn_results > 0) {
+ int i;
+
+ if (n_pfn_results > MAX_PFN_LIST_COUNT)
+ n_pfn_results = MAX_PFN_LIST_COUNT;
+ pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t)
+ - sizeof(wl_pfn_net_info_t));
+
+ memset(&ssid, 0x00, sizeof(ssid));
+
+ request = kzalloc(sizeof(*request)
+ + sizeof(*request->channels) * n_pfn_results,
+ GFP_KERNEL);
+ channel = (struct ieee80211_channel *)kzalloc(
+ (sizeof(struct ieee80211_channel) * n_pfn_results),
+ GFP_KERNEL);
+ if (!request || !channel) {
+ WL_ERR(("No memory"));
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ request->wiphy = wiphy;
+
+ for (i = 0; i < n_pfn_results; i++) {
+ netinfo = &pnetinfo[i];
+ if (!netinfo) {
+ WL_ERR(("Invalid netinfo ptr. index:%d", i));
+ err = -EINVAL;
+ goto out_err;
+ }
+ WL_PNO((">>> SSID:%s Channel:%d \n",
+ netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel));
+ /* PFN result doesn't have all the info which are required by the supplicant
+ * (For e.g IEs) Do a target Escan so that sched scan results are reported
+ * via wl_inform_single_bss in the required format. Escan does require the
+ * scan request in the form of cfg80211_scan_request. For timebeing, create
+ * cfg80211_scan_request one out of the received PNO event.
+ */
+ ssid[i].ssid_len = MIN(netinfo->pfnsubnet.SSID_len, DOT11_MAX_SSID_LEN);
+ memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID, ssid[i].ssid_len);
+ request->n_ssids++;
+
+ channel_req = netinfo->pfnsubnet.channel;
+ band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ
+ : NL80211_BAND_5GHZ;
+ channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band);
+ channel[i].band = band;
+ channel[i].flags |= IEEE80211_CHAN_NO_HT40;
+ request->channels[i] = &channel[i];
+ request->n_channels++;
+ }
+
+ /* assign parsed ssid array */
+ if (request->n_ssids)
+ request->ssids = &ssid[0];
+
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ /* Abort any on-going scan */
+ wl_notify_escan_complete(cfg, ndev, true, true);
+ }
+
+ if (wl_get_p2p_status(cfg, DISCOVERY_ON)) {
+ WL_PNO((">>> P2P discovery was ON. Disabling it\n"));
+ err = wl_cfgp2p_discover_enable_search(cfg, false);
+ if (unlikely(err)) {
+ wl_clr_drv_status(cfg, SCANNING, ndev);
+ goto out_err;
+ }
+ p2p_scan(cfg) = false;
+ }
+
+ wl_set_drv_status(cfg, SCANNING, ndev);
+#if FULL_ESCAN_ON_PFN_NET_FOUND
+ WL_PNO((">>> Doing Full ESCAN on PNO event\n"));
+ err = wl_do_escan(cfg, wiphy, ndev, NULL);
+#else
+ WL_PNO((">>> Doing targeted ESCAN on PNO event\n"));
+ err = wl_do_escan(cfg, wiphy, ndev, request);
+#endif
+ if (err) {
+ wl_clr_drv_status(cfg, SCANNING, ndev);
+ goto out_err;
+ }
+ cfg->sched_scan_running = TRUE;
+ }
+ else {
+ WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n"));
+ }
+out_err:
+ if (request)
+ kfree(request);
+ if (channel)
+ kfree(channel);
+ return err;
+}
+#endif /* WL_SCHED_SCAN */
+
+static void wl_init_conf(struct wl_conf *conf)
+{
+ WL_DBG(("Enter \n"));
+ conf->frag_threshold = (u32)-1;
+ conf->rts_threshold = (u32)-1;
+ conf->retry_short = (u32)-1;
+ conf->retry_long = (u32)-1;
+ conf->tx_power = -1;
+}
+
+static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ unsigned long flags;
+ struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
+
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+ memset(profile, 0, sizeof(struct wl_profile));
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+}
+
+static void wl_init_event_handler(struct bcm_cfg80211 *cfg)
+{
+ memset(cfg->evt_handler, 0, sizeof(cfg->evt_handler));
+
+ cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
+ cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_LINK] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status;
+ cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
+ cfg->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame;
+ cfg->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
+ cfg->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
+ cfg->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
+ cfg->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
+ cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
+ cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_START] = wl_notify_connect_status;
+#ifdef PNO_SUPPORT
+ cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
+#endif /* PNO_SUPPORT */
+#ifdef WLTDLS
+ cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler;
+#endif /* WLTDLS */
+ cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status;
+#ifdef WL_RELMCAST
+ cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status;
+#endif /* WL_RELMCAST */
+#ifdef WL_NAN
+ cfg->evt_handler[WLC_E_NAN] = wl_cfgnan_notify_nan_status;
+ cfg->evt_handler[WLC_E_PROXD] = wl_cfgnan_notify_proxd_status;
+#endif /* WL_NAN */
+
+ cfg->evt_handler[WLC_E_CSA_COMPLETE_IND] = wl_csa_complete_ind;
+}
+
+#if defined(STATIC_WL_PRIV_STRUCT)
+static int
+wl_init_escan_result_buf(struct bcm_cfg80211 *cfg)
+{
+ cfg->escan_info.escan_buf = DHD_OS_PREALLOC(cfg->pub,
+ DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
+ if (cfg->escan_info.escan_buf == NULL) {
+ WL_ERR(("Failed to alloc ESCAN_BUF\n"));
+ return -ENOMEM;
+ }
+ bzero(cfg->escan_info.escan_buf, ESCAN_BUF_SIZE);
+
+ return 0;
+}
+
+static void
+wl_deinit_escan_result_buf(struct bcm_cfg80211 *cfg)
+{
+ if (cfg->escan_info.escan_buf != NULL) {
+ DHD_OS_PREFREE(cfg->pub, DHD_PREALLOC_WIPHY_ESCAN0,
+ cfg->escan_info.escan_buf, ESCAN_BUF_SIZE);
+ cfg->escan_info.escan_buf = NULL;
+ }
+}
+#endif /* STATIC_WL_PRIV_STRUCT */
+
+static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg)
+{
+ WL_DBG(("Enter \n"));
+ cfg->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
+ if (unlikely(!cfg->scan_results)) {
+ WL_ERR(("Scan results alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ cfg->conf = (void *)kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
+ if (unlikely(!cfg->conf)) {
+ WL_ERR(("wl_conf alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ cfg->scan_req_int =
+ (void *)kzalloc(sizeof(*cfg->scan_req_int), GFP_KERNEL);
+ if (unlikely(!cfg->scan_req_int)) {
+ WL_ERR(("Scan req alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ cfg->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
+ if (unlikely(!cfg->ioctl_buf)) {
+ WL_ERR(("Ioctl buf alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ cfg->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
+ if (unlikely(!cfg->escan_ioctl_buf)) {
+ WL_ERR(("Ioctl buf alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ cfg->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
+ if (unlikely(!cfg->extra_buf)) {
+ WL_ERR(("Extra buf alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ cfg->pmk_list = (void *)kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
+ if (unlikely(!cfg->pmk_list)) {
+ WL_ERR(("pmk list alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+
+#if defined(STATIC_WL_PRIV_STRUCT)
+ cfg->conn_info = (void *)kzalloc(sizeof(*cfg->conn_info), GFP_KERNEL);
+ if (unlikely(!cfg->conn_info)) {
+ WL_ERR(("cfg->conn_info alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ cfg->ie = (void *)kzalloc(sizeof(*cfg->ie), GFP_KERNEL);
+ if (unlikely(!cfg->ie)) {
+ WL_ERR(("cfg->ie alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ if (unlikely(wl_init_escan_result_buf(cfg))) {
+ WL_ERR(("Failed to init escan result buf\n"));
+ goto init_priv_mem_out;
+ }
+#endif /* STATIC_WL_PRIV_STRUCT */
+ cfg->afx_hdl = (void *)kzalloc(sizeof(*cfg->afx_hdl), GFP_KERNEL);
+ if (unlikely(!cfg->afx_hdl)) {
+ WL_ERR(("afx hdl alloc failed\n"));
+ goto init_priv_mem_out;
+ } else {
+ init_completion(&cfg->act_frm_scan);
+ init_completion(&cfg->wait_next_af);
+
+ INIT_WORK(&cfg->afx_hdl->work, wl_cfg80211_afx_handler);
+ }
+ return 0;
+
+init_priv_mem_out:
+ wl_deinit_priv_mem(cfg);
+
+ return -ENOMEM;
+}
+
+static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg)
+{
+ kfree(cfg->scan_results);
+ cfg->scan_results = NULL;
+ kfree(cfg->conf);
+ cfg->conf = NULL;
+ kfree(cfg->scan_req_int);
+ cfg->scan_req_int = NULL;
+ kfree(cfg->ioctl_buf);
+ cfg->ioctl_buf = NULL;
+ kfree(cfg->escan_ioctl_buf);
+ cfg->escan_ioctl_buf = NULL;
+ kfree(cfg->extra_buf);
+ cfg->extra_buf = NULL;
+ kfree(cfg->pmk_list);
+ cfg->pmk_list = NULL;
+#if defined(STATIC_WL_PRIV_STRUCT)
+ kfree(cfg->conn_info);
+ cfg->conn_info = NULL;
+ kfree(cfg->ie);
+ cfg->ie = NULL;
+ wl_deinit_escan_result_buf(cfg);
+#endif /* STATIC_WL_PRIV_STRUCT */
+ if (cfg->afx_hdl) {
+ cancel_work_sync(&cfg->afx_hdl->work);
+ kfree(cfg->afx_hdl);
+ cfg->afx_hdl = NULL;
+ }
+
+#ifdef WLTDLS
+ if (cfg->tdls_mgmt_frame) {
+ kfree(cfg->tdls_mgmt_frame);
+ cfg->tdls_mgmt_frame = NULL;
+ }
+#endif /* WLTDLS */
+}
+
+static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg)
+{
+ int ret = 0;
+ WL_DBG(("Enter \n"));
+
+ /* Do not use DHD in cfg driver */
+ cfg->event_tsk.thr_pid = -1;
+
+ PROC_START(wl_event_handler, cfg, &cfg->event_tsk, 0, "wl_event_handler");
+ if (cfg->event_tsk.thr_pid < 0)
+ ret = -ENOMEM;
+ return ret;
+}
+
+static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg)
+{
+ if (cfg->event_tsk.thr_pid >= 0)
+ PROC_STOP(&cfg->event_tsk);
+}
+
+void wl_terminate_event_handler(void)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+
+ if (cfg) {
+ wl_destroy_event_handler(cfg);
+ }
+}
+
+static void wl_scan_timeout(unsigned long data)
+{
+ wl_event_msg_t msg;
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
+
+ if (!(cfg->scan_request)) {
+ WL_ERR(("timer expired but no scan request\n"));
+ return;
+ }
+ bzero(&msg, sizeof(wl_event_msg_t));
+ WL_ERR(("timer expired\n"));
+ msg.event_type = hton32(WLC_E_ESCAN_RESULT);
+ msg.status = hton32(WLC_E_STATUS_TIMEOUT);
+ msg.reason = 0xFFFFFFFF;
+ wl_cfg80211_event(bcmcfg_to_prmry_ndev(cfg), &msg, NULL);
+}
+
+static s32
+wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
+ unsigned long state,
+ void *ptr)
+{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
+ struct net_device *dev = ptr;
+#else
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+#endif /* LINUX_VERSION < VERSION(3, 11, 0) */
+ struct wireless_dev *wdev = ndev_to_wdev(dev);
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+
+ WL_DBG(("Enter \n"));
+
+ if (!wdev || !cfg || dev == bcmcfg_to_prmry_ndev(cfg))
+ return NOTIFY_DONE;
+
+ switch (state) {
+ case NETDEV_DOWN:
+ {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
+ int max_wait_timeout = 2;
+ int max_wait_count = 100;
+ int refcnt = 0;
+ unsigned long limit = jiffies + max_wait_timeout * HZ;
+ while (work_pending(&wdev->cleanup_work)) {
+ if (refcnt%5 == 0) {
+ WL_ERR(("[NETDEV_DOWN] wait for "
+ "complete of cleanup_work"
+ " (%d th)\n", refcnt));
+ }
+ if (!time_before(jiffies, limit)) {
+ WL_ERR(("[NETDEV_DOWN] cleanup_work"
+ " of CFG80211 is not"
+ " completed in %d sec\n",
+ max_wait_timeout));
+ break;
+ }
+ if (refcnt >= max_wait_count) {
+ WL_ERR(("[NETDEV_DOWN] cleanup_work"
+ " of CFG80211 is not"
+ " completed in %d loop\n",
+ max_wait_count));
+ break;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(100);
+ set_current_state(TASK_RUNNING);
+ refcnt++;
+ }
+#endif /* LINUX_VERSION < VERSION(3, 11, 0) */
+ break;
+ }
+
+ case NETDEV_UNREGISTER:
+ /* after calling list_del_rcu(&wdev->list) */
+ wl_cfg80211_clear_per_bss_ies(cfg,
+ wl_get_bssidx_by_wdev(cfg, wdev));
+ wl_dealloc_netinfo_by_wdev(cfg, wdev);
+ break;
+ case NETDEV_GOING_DOWN:
+ /* At NETDEV_DOWN state, wdev_cleanup_work work will be called.
+ * In front of door, the function checks
+ * whether current scan is working or not.
+ * If the scanning is still working, wdev_cleanup_work call WARN_ON and
+ * make the scan done forcibly.
+ */
+ if (wl_get_drv_status(cfg, SCANNING, dev))
+ wl_notify_escan_complete(cfg, dev, true, true);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+static struct notifier_block wl_cfg80211_netdev_notifier = {
+ .notifier_call = wl_cfg80211_netdev_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 wl_cfg80211_netdev_notifier_registered = FALSE;
+
+#ifdef P2PONEINT
+void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg)
+#else
+static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg)
+#endif
+{
+ wl_scan_params_t *params = NULL;
+ s32 params_size = 0;
+ s32 err = BCME_OK;
+ struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
+ if (!in_atomic()) {
+ /* Our scan params only need space for 1 channel and 0 ssids */
+ params = wl_cfg80211_scan_alloc_params(-1, 0, &params_size);
+ if (params == NULL) {
+ WL_ERR(("scan params allocation failed \n"));
+ err = -ENOMEM;
+ } else {
+ /* Do a scan abort to stop the driver's scan engine */
+ err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true);
+ if (err < 0) {
+ WL_ERR(("scan abort failed \n"));
+ }
+ kfree(params);
+ }
+ }
+}
+
+static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg,
+ struct net_device *ndev,
+ bool aborted, bool fw_abort)
+{
+ s32 err = BCME_OK;
+ unsigned long flags;
+ struct net_device *dev;
+
+ WL_DBG(("Enter \n"));
+ if (!ndev) {
+ WL_ERR(("ndev is null\n"));
+ err = BCME_ERROR;
+ return err;
+ }
+
+ if (cfg->escan_info.ndev != ndev) {
+ WL_ERR(("ndev is different %p %p\n", cfg->escan_info.ndev, ndev));
+ err = BCME_ERROR;
+ return err;
+ }
+
+ if (cfg->scan_request) {
+ dev = bcmcfg_to_prmry_ndev(cfg);
+#if defined(WL_ENABLE_P2P_IF)
+ if (cfg->scan_request->dev != cfg->p2p_net)
+ dev = cfg->scan_request->dev;
+#endif /* WL_ENABLE_P2P_IF */
+ }
+ else {
+ WL_DBG(("cfg->scan_request is NULL may be internal scan."
+ "doing scan_abort for ndev %p primary %p",
+ ndev, bcmcfg_to_prmry_ndev(cfg)));
+ dev = ndev;
+ }
+ if (fw_abort && !in_atomic())
+ wl_cfg80211_scan_abort(cfg);
+ if (timer_pending(&cfg->scan_timeout))
+ del_timer_sync(&cfg->scan_timeout);
+#if defined(ESCAN_RESULT_PATCH)
+ if (likely(cfg->scan_request)) {
+ cfg->bss_list = wl_escan_get_buf(cfg, aborted);
+ wl_inform_bss(cfg);
+ }
+#endif /* ESCAN_RESULT_PATCH */
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+#ifdef WL_SCHED_SCAN
+ if (cfg->sched_scan_req && !cfg->scan_request) {
+ WL_PNO((">>> REPORTING SCHED SCAN RESULTS \n"));
+ if (!aborted)
+ cfg80211_sched_scan_results(cfg->sched_scan_req->wiphy);
+ cfg->sched_scan_running = FALSE;
+ cfg->sched_scan_req = NULL;
+ }
+#endif /* WL_SCHED_SCAN */
+ if (likely(cfg->scan_request)) {
+ struct cfg80211_scan_info info = {
+ .aborted = aborted,
+ };
+
+ cfg80211_scan_done(cfg->scan_request, &info);
+ cfg->scan_request = NULL;
+ }
+ if (p2p_is_on(cfg))
+ wl_clr_p2p_status(cfg, SCANNING);
+ wl_clr_drv_status(cfg, SCANNING, dev);
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+
+ return err;
+}
+
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+static void
+wl_cfg80211_find_removal_candidate(wl_bss_info_t *bss, removal_element_t *candidate)
+{
+ int idx;
+ for (idx = 0; idx < BUF_OVERFLOW_MGMT_COUNT; idx++) {
+ int len = BUF_OVERFLOW_MGMT_COUNT - idx - 1;
+ if (bss->RSSI < candidate[idx].RSSI) {
+ if (len)
+ memcpy(&candidate[idx + 1], &candidate[idx],
+ sizeof(removal_element_t) * len);
+ candidate[idx].RSSI = bss->RSSI;
+ candidate[idx].length = bss->length;
+ memcpy(&candidate[idx].BSSID, &bss->BSSID, ETHER_ADDR_LEN);
+ return;
+ }
+ }
+}
+
+static void
+wl_cfg80211_remove_lowRSSI_info(wl_scan_results_t *list, removal_element_t *candidate,
+ wl_bss_info_t *bi)
+{
+ int idx1, idx2;
+ int total_delete_len = 0;
+ for (idx1 = 0; idx1 < BUF_OVERFLOW_MGMT_COUNT; idx1++) {
+ int cur_len = WL_SCAN_RESULTS_FIXED_SIZE;
+ wl_bss_info_t *bss = NULL;
+ if (candidate[idx1].RSSI >= bi->RSSI)
+ continue;
+ for (idx2 = 0; idx2 < list->count; idx2++) {
+ bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) :
+ list->bss_info;
+ if (!bcmp(&candidate[idx1].BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
+ candidate[idx1].RSSI == bss->RSSI &&
+ candidate[idx1].length == dtoh32(bss->length)) {
+ u32 delete_len = dtoh32(bss->length);
+ WL_DBG(("delete scan info of " MACDBG " to add new AP\n",
+ MAC2STRDBG(bss->BSSID.octet)));
+ if (idx2 < list->count -1) {
+ memmove((u8 *)bss, (u8 *)bss + delete_len,
+ list->buflen - cur_len - delete_len);
+ }
+ list->buflen -= delete_len;
+ list->count--;
+ total_delete_len += delete_len;
+ /* if delete_len is greater than or equal to result length */
+ if (total_delete_len >= bi->length) {
+ return;
+ }
+ break;
+ }
+ cur_len += dtoh32(bss->length);
+ }
+ }
+}
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
+
+static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ s32 err = BCME_OK;
+ s32 status = ntoh32(e->status);
+ wl_bss_info_t *bi;
+ wl_escan_result_t *escan_result;
+ wl_bss_info_t *bss = NULL;
+ wl_scan_results_t *list;
+ wifi_p2p_ie_t * p2p_ie;
+ struct net_device *ndev = NULL;
+ u32 bi_length;
+ u32 i;
+ u8 *p2p_dev_addr = NULL;
+
+ WL_DBG((" enter event type : %d, status : %d \n",
+ ntoh32(e->event_type), ntoh32(e->status)));
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ mutex_lock(&cfg->usr_sync);
+ /* P2P SCAN is coming from primary interface */
+ if (wl_get_p2p_status(cfg, SCANNING)) {
+ if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM))
+ ndev = cfg->afx_hdl->dev;
+ else
+ ndev = cfg->escan_info.ndev;
+
+ }
+ if (!ndev || (!wl_get_drv_status(cfg, SCANNING, ndev) && !cfg->sched_scan_running)) {
+ WL_ERR(("escan is not ready ndev %p drv_status 0x%x e_type %d e_states %d\n",
+ ndev, wl_get_drv_status(cfg, SCANNING, ndev),
+ ntoh32(e->event_type), ntoh32(e->status)));
+ goto exit;
+ }
+ escan_result = (wl_escan_result_t *)data;
+
+ if (status == WLC_E_STATUS_PARTIAL) {
+ WL_INFO(("WLC_E_STATUS_PARTIAL \n"));
+ if (!escan_result) {
+ WL_ERR(("Invalid escan result (NULL pointer)\n"));
+ goto exit;
+ }
+ if (dtoh16(escan_result->bss_count) != 1) {
+ WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count));
+ goto exit;
+ }
+ bi = escan_result->bss_info;
+ if (!bi) {
+ WL_ERR(("Invalid escan bss info (NULL pointer)\n"));
+ goto exit;
+ }
+ bi_length = dtoh32(bi->length);
+ if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) {
+ WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length));
+ goto exit;
+ }
+ if (wl_escan_check_sync_id(status, escan_result->sync_id,
+ cfg->escan_info.cur_sync_id) < 0)
+ goto exit;
+
+ if (!(bcmcfg_to_wiphy(cfg)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) {
+ if (dtoh16(bi->capability) & DOT11_CAP_IBSS) {
+ WL_DBG(("Ignoring IBSS result\n"));
+ goto exit;
+ }
+ }
+
+ if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
+ p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length);
+ if (p2p_dev_addr && !memcmp(p2p_dev_addr,
+ cfg->afx_hdl->tx_dst_addr.octet, ETHER_ADDR_LEN)) {
+ s32 channel = wf_chspec_ctlchan(
+ wl_chspec_driver_to_host(bi->chanspec));
+
+ if ((channel > MAXCHANNEL) || (channel <= 0))
+ channel = WL_INVALID;
+ else
+ WL_ERR(("ACTION FRAME SCAN : Peer " MACDBG " found,"
+ " channel : %d\n",
+ MAC2STRDBG(cfg->afx_hdl->tx_dst_addr.octet),
+ channel));
+
+ wl_clr_p2p_status(cfg, SCANNING);
+ cfg->afx_hdl->peer_chan = channel;
+ complete(&cfg->act_frm_scan);
+ goto exit;
+ }
+
+ } else {
+ int cur_len = WL_SCAN_RESULTS_FIXED_SIZE;
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+ removal_element_t candidate[BUF_OVERFLOW_MGMT_COUNT];
+ int remove_lower_rssi = FALSE;
+
+ bzero(candidate, sizeof(removal_element_t)*BUF_OVERFLOW_MGMT_COUNT);
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
+
+ list = wl_escan_get_buf(cfg, FALSE);
+ if (scan_req_match(cfg)) {
+ /* p2p scan && allow only probe response */
+ if ((cfg->p2p->search_state != WL_P2P_DISC_ST_SCAN) &&
+ (bi->flags & WL_BSS_FLAGS_FROM_BEACON))
+ goto exit;
+ if ((p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset,
+ bi->ie_length)) == NULL) {
+ WL_ERR(("Couldn't find P2PIE in probe"
+ " response/beacon\n"));
+ goto exit;
+ }
+ }
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+ if (bi_length > ESCAN_BUF_SIZE - list->buflen)
+ remove_lower_rssi = TRUE;
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
+
+ for (i = 0; i < list->count; i++) {
+ bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
+ : list->bss_info;
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+ WL_TRACE(("%s("MACDBG"), i=%d bss: RSSI %d list->count %d\n",
+ bss->SSID, MAC2STRDBG(bss->BSSID.octet),
+ i, bss->RSSI, list->count));
+
+ if (remove_lower_rssi)
+ wl_cfg80211_find_removal_candidate(bss, candidate);
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
+
+ if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
+ (CHSPEC_BAND(wl_chspec_driver_to_host(bi->chanspec))
+ == CHSPEC_BAND(wl_chspec_driver_to_host(bss->chanspec))) &&
+ bi->SSID_len == bss->SSID_len &&
+ !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) {
+
+ /* do not allow beacon data to update
+ *the data recd from a probe response
+ */
+ if (!(bss->flags & WL_BSS_FLAGS_FROM_BEACON) &&
+ (bi->flags & WL_BSS_FLAGS_FROM_BEACON))
+ goto exit;
+
+ WL_DBG(("%s("MACDBG"), i=%d prev: RSSI %d"
+ " flags 0x%x, new: RSSI %d flags 0x%x\n",
+ bss->SSID, MAC2STRDBG(bi->BSSID.octet), i,
+ bss->RSSI, bss->flags, bi->RSSI, bi->flags));
+
+ if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) ==
+ (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) {
+ /* preserve max RSSI if the measurements are
+ * both on-channel or both off-channel
+ */
+ WL_SCAN(("%s("MACDBG"), same onchan"
+ ", RSSI: prev %d new %d\n",
+ bss->SSID, MAC2STRDBG(bi->BSSID.octet),
+ bss->RSSI, bi->RSSI));
+ bi->RSSI = MAX(bss->RSSI, bi->RSSI);
+ } else if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) &&
+ (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) {
+ /* preserve the on-channel rssi measurement
+ * if the new measurement is off channel
+ */
+ WL_SCAN(("%s("MACDBG"), prev onchan"
+ ", RSSI: prev %d new %d\n",
+ bss->SSID, MAC2STRDBG(bi->BSSID.octet),
+ bss->RSSI, bi->RSSI));
+ bi->RSSI = bss->RSSI;
+ bi->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL;
+ }
+ if (dtoh32(bss->length) != bi_length) {
+ u32 prev_len = dtoh32(bss->length);
+
+ WL_SCAN(("bss info replacement"
+ " is occured(bcast:%d->probresp%d)\n",
+ bss->ie_length, bi->ie_length));
+ WL_DBG(("%s("MACDBG"), replacement!(%d -> %d)\n",
+ bss->SSID, MAC2STRDBG(bi->BSSID.octet),
+ prev_len, bi_length));
+
+ if (list->buflen - prev_len + bi_length
+ > ESCAN_BUF_SIZE) {
+ WL_ERR(("Buffer is too small: keep the"
+ " previous result of this AP\n"));
+ /* Only update RSSI */
+ bss->RSSI = bi->RSSI;
+ bss->flags |= (bi->flags
+ & WL_BSS_FLAGS_RSSI_ONCHANNEL);
+ goto exit;
+ }
+
+ if (i < list->count - 1) {
+ /* memory copy required by this case only */
+ memmove((u8 *)bss + bi_length,
+ (u8 *)bss + prev_len,
+ list->buflen - cur_len - prev_len);
+ }
+ list->buflen -= prev_len;
+ list->buflen += bi_length;
+ }
+ list->version = dtoh32(bi->version);
+ memcpy((u8 *)bss, (u8 *)bi, bi_length);
+ goto exit;
+ }
+ cur_len += dtoh32(bss->length);
+ }
+ if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+ wl_cfg80211_remove_lowRSSI_info(list, candidate, bi);
+ if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
+ WL_DBG(("RSSI(" MACDBG ") is too low(%d) to add Buffer\n",
+ MAC2STRDBG(bi->BSSID.octet), bi->RSSI));
+ goto exit;
+ }
+#else
+ WL_ERR(("Buffer is too small: ignoring\n"));
+ goto exit;
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
+ }
+
+ memcpy(&(((char *)list)[list->buflen]), bi, bi_length);
+ list->version = dtoh32(bi->version);
+ list->buflen += bi_length;
+ list->count++;
+
+ /*
+ * !Broadcast && number of ssid = 1 && number of channels =1
+ * means specific scan to association
+ */
+ if (wl_cfgp2p_is_p2p_specific_scan(cfg->scan_request)) {
+ WL_ERR(("P2P assoc scan fast aborted.\n"));
+ wl_notify_escan_complete(cfg, cfg->escan_info.ndev, false, true);
+ goto exit;
+ }
+ }
+
+ }
+ else if (status == WLC_E_STATUS_SUCCESS) {
+ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+ wl_escan_print_sync_id(status, cfg->escan_info.cur_sync_id,
+ escan_result->sync_id);
+
+ if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
+ WL_INFO(("ACTION FRAME SCAN DONE\n"));
+ wl_clr_p2p_status(cfg, SCANNING);
+ wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
+ if (cfg->afx_hdl->peer_chan == WL_INVALID)
+ complete(&cfg->act_frm_scan);
+ } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
+ WL_INFO(("ESCAN COMPLETED\n"));
+ cfg->bss_list = wl_escan_get_buf(cfg, FALSE);
+ if (!scan_req_match(cfg)) {
+ WL_TRACE_HW4(("SCAN COMPLETED: scanned AP count=%d\n",
+ cfg->bss_list->count));
+ }
+ wl_inform_bss(cfg);
+ wl_notify_escan_complete(cfg, ndev, false, false);
+ }
+ wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT);
+ }
+ else if (status == WLC_E_STATUS_ABORT) {
+ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+ wl_escan_print_sync_id(status, escan_result->sync_id,
+ cfg->escan_info.cur_sync_id);
+ if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
+ WL_INFO(("ACTION FRAME SCAN DONE\n"));
+ wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
+ wl_clr_p2p_status(cfg, SCANNING);
+ if (cfg->afx_hdl->peer_chan == WL_INVALID)
+ complete(&cfg->act_frm_scan);
+ } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
+ WL_INFO(("ESCAN ABORTED\n"));
+ cfg->bss_list = wl_escan_get_buf(cfg, TRUE);
+ if (!scan_req_match(cfg)) {
+ WL_TRACE_HW4(("SCAN ABORTED: scanned AP count=%d\n",
+ cfg->bss_list->count));
+ }
+ wl_inform_bss(cfg);
+ wl_notify_escan_complete(cfg, ndev, true, false);
+ }
+ wl_escan_increment_sync_id(cfg, SCAN_BUF_CNT);
+ } else if (status == WLC_E_STATUS_NEWSCAN) {
+ WL_ERR(("WLC_E_STATUS_NEWSCAN : scan_request[%p]\n", cfg->scan_request));
+ WL_ERR(("sync_id[%d], bss_count[%d]\n", escan_result->sync_id,
+ escan_result->bss_count));
+ } else if (status == WLC_E_STATUS_TIMEOUT) {
+ WL_ERR(("WLC_E_STATUS_TIMEOUT : scan_request[%p]\n", cfg->scan_request));
+ WL_ERR(("reason[0x%x]\n", e->reason));
+ if (e->reason == 0xFFFFFFFF) {
+ wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
+ }
+ } else {
+ WL_ERR(("unexpected Escan Event %d : abort\n", status));
+ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+ wl_escan_print_sync_id(status, escan_result->sync_id,
+ cfg->escan_info.cur_sync_id);
+ if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
+ WL_INFO(("ACTION FRAME SCAN DONE\n"));
+ wl_clr_p2p_status(cfg, SCANNING);
+ wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
+ if (cfg->afx_hdl->peer_chan == WL_INVALID)
+ complete(&cfg->act_frm_scan);
+ } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
+ cfg->bss_list = wl_escan_get_buf(cfg, TRUE);
+ if (!scan_req_match(cfg)) {
+ WL_TRACE_HW4(("SCAN ABORTED(UNEXPECTED): "
+ "scanned AP count=%d\n",
+ cfg->bss_list->count));
+ }
+ wl_inform_bss(cfg);
+ wl_notify_escan_complete(cfg, ndev, true, false);
+ }
+ wl_escan_increment_sync_id(cfg, 2);
+ }
+exit:
+ mutex_unlock(&cfg->usr_sync);
+ return err;
+}
+
+static void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable)
+{
+ u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
+ struct net_info *iter, *next;
+ int err;
+
+ if (!cfg->roamoff_on_concurrent)
+ return;
+ if (enable && connected_cnt > 1) {
+ for_each_ndev(cfg, iter, next) {
+ /* Save the current roam setting */
+ if ((err = wldev_iovar_getint(iter->ndev, "roam_off",
+ (s32 *)&iter->roam_off)) != BCME_OK) {
+ WL_ERR(("%s:Failed to get current roam setting err %d\n",
+ iter->ndev->name, err));
+ continue;
+ }
+ if ((err = wldev_iovar_setint(iter->ndev, "roam_off", 1)) != BCME_OK) {
+ WL_ERR((" %s:failed to set roam_off : %d\n",
+ iter->ndev->name, err));
+ }
+ }
+ }
+ else if (!enable) {
+ for_each_ndev(cfg, iter, next) {
+ if (iter->roam_off != WL_INVALID) {
+ if ((err = wldev_iovar_setint(iter->ndev, "roam_off",
+ iter->roam_off)) == BCME_OK)
+ iter->roam_off = WL_INVALID;
+ else {
+ WL_ERR((" %s:failed to set roam_off : %d\n",
+ iter->ndev->name, err));
+ }
+ }
+ }
+ }
+ return;
+}
+
+static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg)
+{
+ struct net_info *iter, *next;
+ u32 ctl_chan = 0;
+ u32 chanspec = 0;
+ u32 pre_ctl_chan = 0;
+ u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
+ cfg->vsdb_mode = false;
+
+ if (connected_cnt <= 1) {
+ return;
+ }
+ for_each_ndev(cfg, iter, next) {
+ /* p2p discovery iface ndev could be null */
+ if (iter->ndev) {
+ chanspec = 0;
+ ctl_chan = 0;
+ if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
+ if (wldev_iovar_getint(iter->ndev, "chanspec",
+ (s32 *)&chanspec) == BCME_OK) {
+ chanspec = wl_chspec_driver_to_host(chanspec);
+ ctl_chan = wf_chspec_ctlchan(chanspec);
+ wl_update_prof(cfg, iter->ndev, NULL,
+ &ctl_chan, WL_PROF_CHAN);
+ }
+ if (!cfg->vsdb_mode) {
+ if (!pre_ctl_chan && ctl_chan)
+ pre_ctl_chan = ctl_chan;
+ else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan)) {
+ cfg->vsdb_mode = true;
+ }
+ }
+ }
+ }
+ }
+ WL_ERR(("%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel"));
+ return;
+}
+
+static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
+ enum wl_status state, bool set)
+{
+ s32 pm = PM_FAST;
+ s32 err = BCME_OK;
+ u32 mode;
+ u32 chan = 0;
+ struct net_info *iter, *next;
+ struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
+ WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n",
+ state, set, _net_info->pm_restore, _net_info->ndev->name));
+
+ if (state != WL_STATUS_CONNECTED)
+ return 0;
+ mode = wl_get_mode_by_netdev(cfg, _net_info->ndev);
+ if (set) {
+ wl_cfg80211_concurrent_roam(cfg, 1);
+
+ if (mode == WL_MODE_AP) {
+
+ if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false))
+ WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
+ }
+ wl_cfg80211_determine_vsdb_mode(cfg);
+ if (cfg->vsdb_mode || _net_info->pm_block) {
+ /* Delete pm_enable_work */
+ wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_MAINTAIN);
+ /* save PM_FAST in _net_info to restore this
+ * if _net_info->pm_block is false
+ */
+ if (!_net_info->pm_block && (mode == WL_MODE_BSS)) {
+ _net_info->pm = PM_FAST;
+ _net_info->pm_restore = true;
+ }
+ pm = PM_OFF;
+ for_each_ndev(cfg, iter, next) {
+ if (iter->pm_restore || (iter->ndev == NULL))
+ continue;
+ /* Save the current power mode */
+ err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm,
+ sizeof(iter->pm), false);
+ WL_DBG(("%s:power save %s\n", iter->ndev->name,
+ iter->pm ? "enabled" : "disabled"));
+ if (!err && iter->pm) {
+ iter->pm_restore = true;
+ }
+
+ }
+ for_each_ndev(cfg, iter, next) {
+ if (iter->ndev) {
+ if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev))
+ continue;
+ if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm,
+ sizeof(pm), true)) != 0) {
+ if (err == -ENODEV)
+ WL_DBG(("%s:netdev not ready\n", iter->ndev->name));
+ else
+ WL_ERR(("%s:error (%d)\n", iter->ndev->name, err));
+ wl_cfg80211_update_power_mode(iter->ndev);
+ }
+ }
+ }
+ } else {
+ /* add PM Enable timer to go to power save mode
+ * if supplicant control pm mode, it will be cleared or
+ * updated by wl_cfg80211_set_power_mgmt() if not - for static IP & HW4 P2P,
+ * PM will be configured when timer expired
+ */
+
+ /*
+ * before calling pm_enable_timer, we need to set PM -1 for all ndev
+ */
+ pm = PM_OFF;
+ if (!_net_info->pm_block) {
+ for_each_ndev(cfg, iter, next) {
+ if (iter->pm_restore || (iter->ndev == NULL))
+ continue;
+ /* Save the current power mode */
+ err = wldev_ioctl(iter->ndev, WLC_GET_PM, &iter->pm,
+ sizeof(iter->pm), false);
+ WL_DBG(("%s:power save %s\n", iter->ndev->name,
+ iter->pm ? "enabled" : "disabled"));
+ if (!err && iter->pm) {
+ iter->pm_restore = true;
+ }
+ }
+ }
+ for_each_ndev(cfg, iter, next) {
+ /* p2p discovery iface ndev ptr could be null */
+ if (iter->ndev) {
+ if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev))
+ continue;
+ if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM, &pm,
+ sizeof(pm), true)) != 0) {
+ if (err == -ENODEV)
+ WL_DBG(("%s:netdev not ready\n", iter->ndev->name));
+ else
+ WL_ERR(("%s:error (%d)\n", iter->ndev->name, err));
+ }
+ }
+ }
+
+ if (cfg->pm_enable_work_on) {
+ wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL);
+ }
+
+ cfg->pm_enable_work_on = true;
+ wl_add_remove_pm_enable_work(cfg, TRUE, WL_HANDLER_NOTUSE);
+ }
+#if defined(WLTDLS)
+#if defined(DISABLE_TDLS_IN_P2P)
+ if (cfg->vsdb_mode || p2p_is_on(cfg))
+#else
+ if (cfg->vsdb_mode)
+#endif /* defined(DISABLE_TDLS_IN_P2P) */
+ {
+
+ err = wldev_iovar_setint(primary_dev, "tdls_enable", 0);
+ }
+#endif /* defined(WLTDLS) */
+ }
+ else { /* clear */
+ chan = 0;
+ /* clear chan information when the net device is disconnected */
+ wl_update_prof(cfg, _net_info->ndev, NULL, &chan, WL_PROF_CHAN);
+ wl_cfg80211_determine_vsdb_mode(cfg);
+ for_each_ndev(cfg, iter, next) {
+ /* p2p discovery iface ndev ptr could be null */
+ if (iter->ndev) {
+ if (iter->pm_restore && iter->pm) {
+ WL_DBG(("%s:restoring power save %s\n",
+ iter->ndev->name, (iter->pm ? "enabled" : "disabled")));
+ err = wldev_ioctl(iter->ndev,
+ WLC_SET_PM, &iter->pm, sizeof(iter->pm), true);
+ if (unlikely(err)) {
+ if (err == -ENODEV)
+ WL_DBG(("%s:netdev not ready\n", iter->ndev->name));
+ else
+ WL_ERR(("%s:error(%d)\n", iter->ndev->name, err));
+ break;
+ }
+ iter->pm_restore = 0;
+ wl_cfg80211_update_power_mode(iter->ndev);
+ }
+ }
+ }
+ wl_cfg80211_concurrent_roam(cfg, 0);
+#if defined(WLTDLS)
+ if (!cfg->vsdb_mode) {
+ err = wldev_iovar_setint(primary_dev, "tdls_enable", 1);
+ }
+#endif /* defined(WLTDLS) */
+ }
+ return err;
+}
+static s32 wl_init_scan(struct bcm_cfg80211 *cfg)
+{
+ int err = 0;
+
+ cfg->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler;
+ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+ wl_escan_init_sync_id(cfg);
+
+ /* Init scan_timeout timer */
+ init_timer(&cfg->scan_timeout);
+ cfg->scan_timeout.data = (unsigned long) cfg;
+ cfg->scan_timeout.function = wl_scan_timeout;
+
+ return err;
+}
+
+static s32 wl_init_priv(struct bcm_cfg80211 *cfg)
+{
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ s32 err = 0;
+
+ cfg->scan_request = NULL;
+ cfg->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
+ cfg->roam_on = false;
+ cfg->active_scan = true;
+ cfg->rf_blocked = false;
+ cfg->vsdb_mode = false;
+ cfg->wlfc_on = false;
+ cfg->roamoff_on_concurrent = true;
+ cfg->disable_roam_event = false;
+ cfg->cfgdev_bssidx = -1;
+ /* register interested state */
+ set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state);
+ spin_lock_init(&cfg->cfgdrv_lock);
+ mutex_init(&cfg->ioctl_buf_sync);
+ init_waitqueue_head(&cfg->netif_change_event);
+ init_completion(&cfg->send_af_done);
+ init_completion(&cfg->iface_disable);
+ wl_init_eq(cfg);
+ err = wl_init_priv_mem(cfg);
+ if (err)
+ return err;
+ if (wl_create_event_handler(cfg))
+ return -ENOMEM;
+ wl_init_event_handler(cfg);
+ mutex_init(&cfg->usr_sync);
+ mutex_init(&cfg->event_sync);
+ err = wl_init_scan(cfg);
+ if (err)
+ return err;
+ wl_init_conf(cfg->conf);
+ wl_init_prof(cfg, ndev);
+ wl_link_down(cfg);
+ DNGL_FUNC(dhd_cfg80211_init, (cfg));
+
+ return err;
+}
+
+static void wl_deinit_priv(struct bcm_cfg80211 *cfg)
+{
+ DNGL_FUNC(dhd_cfg80211_deinit, (cfg));
+ wl_destroy_event_handler(cfg);
+ wl_flush_eq(cfg);
+ wl_link_down(cfg);
+ del_timer_sync(&cfg->scan_timeout);
+ wl_deinit_priv_mem(cfg);
+ if (wl_cfg80211_netdev_notifier_registered) {
+ wl_cfg80211_netdev_notifier_registered = FALSE;
+ unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier);
+ }
+}
+
+#if defined(WL_ENABLE_P2P_IF) || defined(P2PONEINT)
+static s32 wl_cfg80211_attach_p2p(void)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+
+ WL_TRACE(("Enter \n"));
+
+ if (wl_cfgp2p_register_ndev(cfg) < 0) {
+ WL_ERR(("P2P attach failed. \n"));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+#endif
+
+#if defined(WL_ENABLE_P2P_IF)
+static s32 wl_cfg80211_detach_p2p(void)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ struct wireless_dev *wdev;
+
+ WL_DBG(("Enter \n"));
+ if (!cfg) {
+ WL_ERR(("Invalid Ptr\n"));
+ return -EINVAL;
+ } else
+ wdev = cfg->p2p_wdev;
+
+ if (!wdev) {
+ WL_ERR(("Invalid Ptr\n"));
+ return -EINVAL;
+ }
+
+ wl_cfgp2p_unregister_ndev(cfg);
+
+ cfg->p2p_wdev = NULL;
+ cfg->p2p_net = NULL;
+ WL_DBG(("Freeing 0x%p \n", wdev));
+ kfree(wdev);
+
+ return 0;
+}
+#endif
+
+s32 wl_cfg80211_attach_post(struct net_device *ndev)
+{
+ struct bcm_cfg80211 * cfg = NULL;
+ s32 err = 0;
+ s32 ret = 0;
+ WL_TRACE(("In\n"));
+ if (unlikely(!ndev)) {
+ WL_ERR(("ndev is invaild\n"));
+ return -ENODEV;
+ }
+ cfg = g_bcm_cfg;
+ if (unlikely(!cfg)) {
+ WL_ERR(("cfg is invaild\n"));
+ return -EINVAL;
+ }
+ if (!wl_get_drv_status(cfg, READY, ndev)) {
+ if (cfg->wdev) {
+ ret = wl_cfgp2p_supported(cfg, ndev);
+ if (ret > 0) {
+#if !defined(WL_ENABLE_P2P_IF)
+ cfg->wdev->wiphy->interface_modes |=
+ (BIT(NL80211_IFTYPE_P2P_CLIENT)|
+ BIT(NL80211_IFTYPE_P2P_GO));
+#endif /* !WL_ENABLE_P2P_IF */
+ if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
+ goto fail;
+
+#ifdef P2PONEINT
+ if (!cfg->p2p_net) {
+ cfg->p2p_supported = true;
+
+ err = wl_cfg80211_attach_p2p();
+ if (err)
+ goto fail;
+
+ cfg->p2p_supported = true;
+ }
+#endif
+#if defined(WL_ENABLE_P2P_IF) || defined(P2PONEINT)
+ if (cfg->p2p_net) {
+ /* Update MAC addr for p2p0 interface here. */
+ memcpy(cfg->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN);
+ cfg->p2p_net->dev_addr[0] |= 0x02;
+ WL_ERR(("%s: p2p_dev_addr="MACDBG "\n",
+ cfg->p2p_net->name,
+ MAC2STRDBG(cfg->p2p_net->dev_addr)));
+ } else {
+ WL_ERR(("p2p_net not yet populated."
+ " Couldn't update the MAC Address for p2p0 \n"));
+ return -ENODEV;
+ }
+#endif /* WL_ENABLE_P2P_IF */
+#ifndef P2PONEINT
+ cfg->p2p_supported = true;
+#endif
+ } else if (ret == 0) {
+ if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
+ goto fail;
+ } else {
+ /* SDIO bus timeout */
+ err = -ENODEV;
+ goto fail;
+ }
+ }
+ }
+ wl_set_drv_status(cfg, READY, ndev);
+fail:
+ return err;
+}
+
+s32 wl_cfg80211_attach(struct net_device *ndev, void *context)
+{
+ struct wireless_dev *wdev;
+ struct bcm_cfg80211 *cfg;
+ s32 err = 0;
+ struct device *dev;
+
+ WL_TRACE(("In\n"));
+ if (!ndev) {
+ WL_ERR(("ndev is invaild\n"));
+ return -ENODEV;
+ }
+ WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
+ dev = wl_cfg80211_get_parent_dev();
+
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (unlikely(!wdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ return -ENOMEM;
+ }
+ err = wl_setup_wiphy(wdev, dev, context);
+ if (unlikely(err)) {
+ kfree(wdev);
+ return -ENOMEM;
+ }
+ wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
+ cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy);
+ cfg->wdev = wdev;
+ cfg->pub = context;
+ INIT_LIST_HEAD(&cfg->net_list);
+ spin_lock_init(&cfg->net_list_sync);
+ ndev->ieee80211_ptr = wdev;
+ SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
+ wdev->netdev = ndev;
+ cfg->state_notifier = wl_notifier_change_state;
+ err = wl_alloc_netinfo(cfg, ndev, wdev, WL_MODE_BSS, PM_ENABLE, 0);
+ if (err) {
+ WL_ERR(("Failed to alloc net_info (%d)\n", err));
+ goto cfg80211_attach_out;
+ }
+ err = wl_init_priv(cfg);
+ if (err) {
+ WL_ERR(("Failed to init iwm_priv (%d)\n", err));
+ goto cfg80211_attach_out;
+ }
+
+ err = wl_setup_rfkill(cfg, TRUE);
+ if (err) {
+ WL_ERR(("Failed to setup rfkill %d\n", err));
+ goto cfg80211_attach_out;
+ }
+#ifdef DEBUGFS_CFG80211
+ err = wl_setup_debugfs(cfg);
+ if (err) {
+ WL_ERR(("Failed to setup debugfs %d\n", err));
+ goto cfg80211_attach_out;
+ }
+#endif
+ if (!wl_cfg80211_netdev_notifier_registered) {
+ wl_cfg80211_netdev_notifier_registered = TRUE;
+ err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier);
+ if (err) {
+ wl_cfg80211_netdev_notifier_registered = FALSE;
+ WL_ERR(("Failed to register notifierl %d\n", err));
+ goto cfg80211_attach_out;
+ }
+ }
+#if defined(COEX_DHCP)
+ cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev);
+ if (!cfg->btcoex_info)
+ goto cfg80211_attach_out;
+#endif
+
+ g_bcm_cfg = cfg;
+
+#if defined(WL_ENABLE_P2P_IF)
+#ifndef P2PONEINT
+ err = wl_cfg80211_attach_p2p();
+ if (err)
+ goto cfg80211_attach_out;
+#endif
+#endif
+
+ return err;
+
+cfg80211_attach_out:
+ wl_setup_rfkill(cfg, FALSE);
+ wl_free_wdev(cfg);
+ return err;
+}
+
+void wl_cfg80211_detach(void *para)
+{
+ struct bcm_cfg80211 *cfg;
+
+ (void)para;
+ cfg = g_bcm_cfg;
+
+ WL_TRACE(("In\n"));
+
+ wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL);
+
+#if defined(COEX_DHCP)
+ wl_cfg80211_btcoex_deinit();
+ cfg->btcoex_info = NULL;
+#endif
+
+ wl_setup_rfkill(cfg, FALSE);
+#ifdef DEBUGFS_CFG80211
+ wl_free_debugfs(cfg);
+#endif
+ if (cfg->p2p_supported) {
+ if (timer_pending(&cfg->p2p->listen_timer))
+ del_timer_sync(&cfg->p2p->listen_timer);
+ wl_cfgp2p_deinit_priv(cfg);
+ }
+
+ if (timer_pending(&cfg->scan_timeout))
+ del_timer_sync(&cfg->scan_timeout);
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+#if defined(WL_ENABLE_P2P_IF)
+ wl_cfg80211_detach_p2p();
+#endif
+
+ wl_cfg80211_ibss_vsie_free(cfg);
+ wl_cfg80211_clear_mgmt_vndr_ies(cfg);
+ wl_deinit_priv(cfg);
+ g_bcm_cfg = NULL;
+ wl_cfg80211_clear_parent_dev();
+ wl_free_wdev(cfg);
+ /* PLEASE do NOT call any function after wl_free_wdev, the driver's private
+ * structure "cfg", which is the private part of wiphy, has been freed in
+ * wl_free_wdev !!!!!!!!!!!
+ */
+}
+
+static void wl_wakeup_event(struct bcm_cfg80211 *cfg)
+{
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+
+ if (dhd->up && (cfg->event_tsk.thr_pid >= 0)) {
+ DHD_OS_WAKE_LOCK(cfg->pub);
+ up(&cfg->event_tsk.sema);
+ }
+}
+
+#if defined(P2PONEINT)
+static int wl_is_p2p_event(struct wl_event_q *e)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+
+ switch (e->etype) {
+ case WLC_E_IF:
+ WL_TRACE(("P2P event(%d) on interface(ifidx:%d)\n",
+ e->etype, e->emsg.ifidx));
+
+ (void)schedule_timeout(20);
+
+ if (wl_get_p2p_status(cfg, IF_ADDING) ||
+ wl_get_p2p_status(cfg, IF_DELETING) ||
+ wl_get_p2p_status(cfg, IF_CHANGING) ||
+ wl_get_p2p_status(cfg, IF_CHANGED)) {
+ WL_TRACE(("P2P Event on Primary I/F (ifidx:%d)."
+ " Sent it to p2p0 \n", e->emsg.ifidx));
+ return TRUE;
+ } else {
+ WL_TRACE(("Event is Not p2p event return False \n"));
+ return FALSE;
+ }
+
+ case WLC_E_P2P_PROBREQ_MSG:
+ case WLC_E_P2P_DISC_LISTEN_COMPLETE:
+ case WLC_E_ACTION_FRAME_RX:
+ case WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE:
+ case WLC_E_ACTION_FRAME_COMPLETE:
+
+ if (e->emsg.ifidx != 0) {
+ WL_TRACE(("P2P event(%d) on virtual interface(ifidx:%d)\n",
+ e->etype, e->emsg.ifidx));
+ return FALSE;
+ } else {
+ WL_TRACE(("P2P event(%d) on interface(ifidx:%d)\n",
+ e->etype, e->emsg.ifidx));
+ return TRUE;
+ }
+ break;
+
+ default:
+ WL_TRACE(("NON-P2P event(%d) on interface(ifidx:%d)\n",
+ e->etype, e->emsg.ifidx));
+ return FALSE;
+ }
+}
+#endif
+
+static s32 wl_event_handler(void *data)
+{
+ struct bcm_cfg80211 *cfg = NULL;
+ struct wl_event_q *e;
+ tsk_ctl_t *tsk = (tsk_ctl_t *)data;
+ bcm_struct_cfgdev *cfgdev = NULL;
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ struct net_device *ndev = NULL;
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+ cfg = (struct bcm_cfg80211 *)tsk->parent;
+
+ WL_INFO(("tsk Enter, tsk = 0x%p\n", tsk));
+
+ while (down_interruptible (&tsk->sema) == 0) {
+ SMP_RD_BARRIER_DEPENDS();
+ if (tsk->terminated) {
+ DHD_OS_WAKE_UNLOCK(cfg->pub);
+ break;
+ }
+ while ((e = wl_deq_event(cfg))) {
+ WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx));
+ /* All P2P device address related events comes on primary interface since
+ * there is no corresponding bsscfg for P2P interface. Map it to p2p0
+ * interface.
+ */
+#if defined(WL_CFG80211_P2P_DEV_IF)
+#ifdef P2PONEINT
+ if ((wl_is_p2p_event(e) == TRUE) && (cfg->p2p_wdev)) {
+#else
+ if (WL_IS_P2P_DEV_EVENT(e) && (cfg->p2p_wdev)) {
+#endif
+ cfgdev = bcmcfg_to_p2p_wdev(cfg);
+ } else if (cfg->bss_cfgdev && (e->emsg.bsscfgidx == cfg->cfgdev_bssidx)) {
+ /* STA / AP on virtual interface */
+ cfgdev = (ndev = cfgdev_to_wlc_ndev(cfg->bss_cfgdev, cfg)) ?
+ ndev_to_wdev(ndev) : NULL;
+ } else {
+
+ ndev = dhd_idx2net((struct dhd_pub *)(cfg->pub), e->emsg.ifidx);
+ if (ndev)
+ cfgdev = ndev_to_wdev(ndev);
+#ifdef P2PONEINT
+ else if (e->etype == WLC_E_IF) {
+ wl_put_event(e);
+ DHD_OS_WAKE_UNLOCK(cfg->pub);
+ continue;
+ }
+
+ if (cfgdev == NULL) {
+ if (e->etype == WLC_E_IF)
+ cfgdev = bcmcfg_to_prmry_wdev(cfg);
+ else {
+ cfgdev = ndev_to_wdev(wl_to_p2p_bss_ndev(cfg,
+ P2PAPI_BSSCFG_CONNECTION));
+ }
+ }
+#endif
+ }
+#elif defined(WL_ENABLE_P2P_IF)
+ if (WL_IS_P2P_DEV_EVENT(e) && (cfg->p2p_net)) {
+ cfgdev = cfg->p2p_net;
+ } else if (cfg->bss_cfgdev && (e->emsg.bsscfgidx == cfg->cfgdev_bssidx)) {
+ /* STA / AP on virtual interface */
+ cfgdev = cfgdev_to_wlc_ndev(cfg->bss_cfgdev, cfg);
+ } else {
+ cfgdev = dhd_idx2net((struct dhd_pub *)(cfg->pub),
+ e->emsg.ifidx);
+ }
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+ if (!cfgdev) {
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ cfgdev = bcmcfg_to_prmry_wdev(cfg);
+#elif defined(WL_ENABLE_P2P_IF)
+ cfgdev = bcmcfg_to_prmry_ndev(cfg);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ }
+ if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) {
+ dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub);
+ if (dhd->busstate == DHD_BUS_DOWN) {
+ WL_ERR((": BUS is DOWN.\n"));
+ } else
+ cfg->evt_handler[e->etype](cfg, cfgdev, &e->emsg, e->edata);
+ } else {
+ WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
+ }
+ wl_put_event(e);
+ }
+ DHD_OS_WAKE_UNLOCK(cfg->pub);
+ }
+ WL_INFO(("was terminated\n"));
+ complete_and_exit(&tsk->completed, 0);
+ return 0;
+}
+
+void
+wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
+{
+ u32 event_type = ntoh32(e->event_type);
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ struct net_info *netinfo;
+
+#if (WL_DBG_LEVEL > 0)
+ s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ?
+ wl_dbg_estr[event_type] : (s8 *) "Unknown";
+ WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr));
+#endif /* (WL_DBG_LEVEL > 0) */
+
+ if ((cfg == NULL) || (cfg->p2p_supported && cfg->p2p == NULL)) {
+ WL_ERR(("Stale event ignored\n"));
+ return;
+ }
+ if (wl_get_p2p_status(cfg, IF_CHANGING) || wl_get_p2p_status(cfg, IF_ADDING)) {
+ WL_ERR(("during IF change, ignore event %d\n", event_type));
+ return;
+ }
+
+#ifdef DHD_IFDEBUG
+ if (event_type != WLC_E_ESCAN_RESULT) {
+ WL_ERR(("Event_type %d , status : %d, reason : %d, bssidx:%d \n",
+ event_type, ntoh32(e->status), ntoh32(e->reason), e->bsscfgidx));
+ }
+#endif
+ netinfo = wl_get_netinfo_by_bssidx(cfg, e->bsscfgidx);
+ if (!netinfo) {
+ /* Since the netinfo entry is not there, the netdev entry is not
+ * created via cfg80211 interface. so the event is not of interest
+ * to the cfg80211 layer.
+ */
+ WL_ERR(("%d : ignore event %d, not interested\n", __LINE__, event_type));
+ return;
+ }
+
+ if (event_type == WLC_E_PFN_NET_FOUND) {
+ WL_DBG((" PNOEVENT: PNO_NET_FOUND\n"));
+ }
+ else if (event_type == WLC_E_PFN_NET_LOST) {
+ WL_DBG((" PNOEVENT: PNO_NET_LOST\n"));
+ }
+
+ if (likely(!wl_enq_event(cfg, ndev, event_type, e, data)))
+ wl_wakeup_event(cfg);
+}
+
+static void wl_init_eq(struct bcm_cfg80211 *cfg)
+{
+ wl_init_eq_lock(cfg);
+ INIT_LIST_HEAD(&cfg->eq_list);
+}
+
+static void wl_flush_eq(struct bcm_cfg80211 *cfg)
+{
+ struct wl_event_q *e;
+ unsigned long flags;
+
+ flags = wl_lock_eq(cfg);
+ while (!list_empty(&cfg->eq_list)) {
+ e = list_first_entry(&cfg->eq_list, struct wl_event_q, eq_list);
+ list_del(&e->eq_list);
+ kfree(e);
+ }
+ wl_unlock_eq(cfg, flags);
+}
+
+/*
+* retrieve first queued event from head
+*/
+
+static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg)
+{
+ struct wl_event_q *e = NULL;
+ unsigned long flags;
+
+ flags = wl_lock_eq(cfg);
+ if (likely(!list_empty(&cfg->eq_list))) {
+ e = list_first_entry(&cfg->eq_list, struct wl_event_q, eq_list);
+ list_del(&e->eq_list);
+ }
+ wl_unlock_eq(cfg, flags);
+
+ return e;
+}
+
+/*
+ * push event to tail of the queue
+ */
+
+static s32
+wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 event,
+ const wl_event_msg_t *msg, void *data)
+{
+ struct wl_event_q *e;
+ s32 err = 0;
+ uint32 evtq_size;
+ uint32 data_len;
+ unsigned long flags;
+ gfp_t aflags;
+
+ data_len = 0;
+ if (data)
+ data_len = ntoh32(msg->datalen);
+ evtq_size = sizeof(struct wl_event_q) + data_len;
+ aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
+ e = kzalloc(evtq_size, aflags);
+ if (unlikely(!e)) {
+ WL_ERR(("event alloc failed\n"));
+ return -ENOMEM;
+ }
+ e->etype = event;
+ memcpy(&e->emsg, msg, sizeof(wl_event_msg_t));
+ if (data)
+ memcpy(e->edata, data, data_len);
+ flags = wl_lock_eq(cfg);
+ list_add_tail(&e->eq_list, &cfg->eq_list);
+ wl_unlock_eq(cfg, flags);
+
+ return err;
+}
+
+static void wl_put_event(struct wl_event_q *e)
+{
+ kfree(e);
+}
+
+static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 iftype)
+{
+ s32 infra = 0;
+ s32 err = 0;
+ s32 mode = 0;
+ switch (iftype) {
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_WDS:
+ WL_ERR(("type (%d) : currently we do not support this mode\n",
+ iftype));
+ err = -EINVAL;
+ return err;
+ case NL80211_IFTYPE_ADHOC:
+ mode = WL_MODE_IBSS;
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ mode = WL_MODE_BSS;
+ infra = 1;
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ mode = WL_MODE_AP;
+ infra = 1;
+ break;
+ default:
+ err = -EINVAL;
+ WL_ERR(("invalid type (%d)\n", iftype));
+ return err;
+ }
+ infra = htod32(infra);
+ err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
+ return err;
+ }
+
+ wl_set_mode_by_netdev(cfg, ndev, mode);
+
+ return 0;
+}
+
+void wl_cfg80211_add_to_eventbuffer(struct wl_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 {
+ WL_ERR(("evenbuffer doesn't support > %u events. Update"
+ " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM));
+ ASSERT(0);
+ }
+}
+
+s32 wl_cfg80211_apply_eventbuffer(
+ struct net_device *ndev,
+ struct bcm_cfg80211 *cfg,
+ wl_eventmsg_buf_t *ev)
+{
+ char eventmask[WL_EVENTING_MASK_LEN];
+ int i, ret = 0;
+ s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
+
+ if (!ev || (!ev->num))
+ return -EINVAL;
+
+ mutex_lock(&cfg->event_sync);
+
+ /* Read event_msgs mask */
+ bcm_mkiovar("event_msgs", NULL, 0, iovbuf,
+ sizeof(iovbuf));
+ ret = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false);
+ if (unlikely(ret)) {
+ WL_ERR(("Get event_msgs error (%d)\n", ret));
+ goto exit;
+ }
+ memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
+
+ /* 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 */
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
+ sizeof(iovbuf));
+ ret = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+ if (unlikely(ret)) {
+ WL_ERR(("Set event_msgs error (%d)\n", ret));
+ }
+
+exit:
+ mutex_unlock(&cfg->event_sync);
+ return ret;
+}
+
+s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
+{
+ s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
+ s8 eventmask[WL_EVENTING_MASK_LEN];
+ s32 err = 0;
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+
+ if (!ndev || !cfg)
+ return -ENODEV;
+
+ mutex_lock(&cfg->event_sync);
+
+ /* Setup event_msgs */
+ bcm_mkiovar("event_msgs", NULL, 0, iovbuf,
+ sizeof(iovbuf));
+ err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false);
+ if (unlikely(err)) {
+ WL_ERR(("Get event_msgs error (%d)\n", err));
+ goto eventmsg_out;
+ }
+ memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
+ if (add) {
+ setbit(eventmask, event);
+ } else {
+ clrbit(eventmask, event);
+ }
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
+ sizeof(iovbuf));
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+ if (unlikely(err)) {
+ WL_ERR(("Set event_msgs error (%d)\n", err));
+ goto eventmsg_out;
+ }
+
+eventmsg_out:
+ mutex_unlock(&cfg->event_sync);
+ return err;
+}
+
+static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap)
+{
+ struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
+ struct ieee80211_channel *band_chan_arr = NULL;
+ wl_uint32_list_t *list;
+ u32 i, j, index, n_2g, n_5g, band, channel, array_size;
+ u32 *n_cnt = NULL;
+ chanspec_t c = 0;
+ s32 err = BCME_OK;
+ bool update;
+ bool ht40_allowed;
+ u8 *pbuf = NULL;
+ bool dfs_radar_disabled = FALSE;
+
+#define LOCAL_BUF_LEN 1024
+ pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL);
+
+ if (pbuf == NULL) {
+ WL_ERR(("failed to allocate local buf\n"));
+ return -ENOMEM;
+ }
+ list = (wl_uint32_list_t *)(void *)pbuf;
+ list->count = htod32(WL_NUMCHANSPECS);
+
+
+ err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
+ 0, pbuf, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync);
+ if (err != 0) {
+ WL_ERR(("get chanspecs failed with %d\n", err));
+ kfree(pbuf);
+ return err;
+ }
+#undef LOCAL_BUF_LEN
+
+ list = (wl_uint32_list_t *)(void *)pbuf;
+ band = array_size = n_2g = n_5g = 0;
+ for (i = 0; i < dtoh32(list->count); i++) {
+ index = 0;
+ update = false;
+ ht40_allowed = false;
+ c = (chanspec_t)dtoh32(list->element[i]);
+ c = wl_chspec_driver_to_host(c);
+ channel = CHSPEC_CHANNEL(c);
+ if (CHSPEC_IS40(c)) {
+ if (CHSPEC_SB_UPPER(c))
+ channel += CH_10MHZ_APART;
+ else
+ channel -= CH_10MHZ_APART;
+ } else if (CHSPEC_IS80(c)) {
+ WL_DBG(("HT80 center channel : %d\n", channel));
+ continue;
+ }
+ if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) &&
+ (channel <= CH_MAX_2G_CHANNEL)) {
+ band_chan_arr = __wl_2ghz_channels;
+ array_size = ARRAYSIZE(__wl_2ghz_channels);
+ n_cnt = &n_2g;
+ band = NL80211_BAND_2GHZ;
+ ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false;
+ } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) {
+ band_chan_arr = __wl_5ghz_a_channels;
+ array_size = ARRAYSIZE(__wl_5ghz_a_channels);
+ n_cnt = &n_5g;
+ band = NL80211_BAND_5GHZ;
+ ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true;
+ } else {
+ WL_ERR(("Invalid channel Sepc. 0x%x.\n", c));
+ continue;
+ }
+ if (!ht40_allowed && CHSPEC_IS40(c))
+ continue;
+ for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
+ if (band_chan_arr[j].hw_value == channel) {
+ update = true;
+ break;
+ }
+ }
+ if (update)
+ index = j;
+ else
+ index = *n_cnt;
+ if (index < array_size) {
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38)
+ band_chan_arr[index].center_freq =
+ ieee80211_channel_to_frequency(channel);
+#else
+ band_chan_arr[index].center_freq =
+ ieee80211_channel_to_frequency(channel, band);
+#endif
+ band_chan_arr[index].hw_value = channel;
+
+ if (CHSPEC_IS40(c) && ht40_allowed) {
+ /* assuming the order is HT20, HT40 Upper,
+ * HT40 lower from chanspecs
+ */
+ u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40;
+ if (CHSPEC_SB_UPPER(c)) {
+ if (ht40_flag == IEEE80211_CHAN_NO_HT40)
+ band_chan_arr[index].flags &=
+ ~IEEE80211_CHAN_NO_HT40;
+ band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS;
+ } else {
+ /* It should be one of
+ * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS
+ */
+ band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
+ if (ht40_flag == IEEE80211_CHAN_NO_HT40)
+ band_chan_arr[index].flags |=
+ IEEE80211_CHAN_NO_HT40MINUS;
+ }
+ } else {
+ band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40;
+ if (!dfs_radar_disabled) {
+ if (band == NL80211_BAND_2GHZ)
+ channel |= WL_CHANSPEC_BAND_2G;
+ else
+ channel |= WL_CHANSPEC_BAND_5G;
+ channel |= WL_CHANSPEC_BW_20;
+ channel = wl_chspec_host_to_driver(channel);
+ err = wldev_iovar_getint(dev, "per_chan_info", &channel);
+ if (!err) {
+ if (channel & WL_CHAN_RADAR) {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
+ band_chan_arr[index].flags |=
+ (IEEE80211_CHAN_RADAR
+ | IEEE80211_CHAN_NO_IBSS);
+#else
+ band_chan_arr[index].flags |=
+ IEEE80211_CHAN_RADAR;
+#endif
+ }
+
+ if (channel & WL_CHAN_PASSIVE)
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
+ band_chan_arr[index].flags |=
+ IEEE80211_CHAN_PASSIVE_SCAN;
+#else
+ band_chan_arr[index].flags |=
+ IEEE80211_CHAN_NO_IR;
+#endif
+ } else if (err == BCME_UNSUPPORTED) {
+ dfs_radar_disabled = TRUE;
+ WL_ERR(("does not support per_chan_info\n"));
+ }
+ }
+ }
+ if (!update)
+ (*n_cnt)++;
+ }
+
+ }
+ __wl_band_2ghz.n_channels = n_2g;
+ __wl_band_5ghz_a.n_channels = n_5g;
+ kfree(pbuf);
+ return err;
+}
+
+s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify)
+{
+ struct wiphy *wiphy;
+ struct net_device *dev;
+ u32 bandlist[3];
+ u32 nband = 0;
+ u32 i = 0;
+ s32 err = 0;
+ s32 index = 0;
+ s32 nmode = 0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ u32 j = 0;
+ s32 vhtmode = 0;
+ s32 txstreams = 0;
+ s32 rxstreams = 0;
+ s32 ldpc_cap = 0;
+ s32 stbc_rx = 0;
+ s32 stbc_tx = 0;
+ s32 txbf_bfe_cap = 0;
+ s32 txbf_bfr_cap = 0;
+#endif
+ bool rollback_lock = false;
+ s32 bw_cap = 0;
+ s32 cur_band = -1;
+ struct ieee80211_supported_band *bands[NUM_NL80211_BANDS] = {NULL, };
+
+ if (cfg == NULL) {
+ cfg = g_bcm_cfg;
+ mutex_lock(&cfg->usr_sync);
+ rollback_lock = true;
+ }
+ dev = bcmcfg_to_prmry_ndev(cfg);
+
+ memset(bandlist, 0, sizeof(bandlist));
+ err = wldev_ioctl(dev, WLC_GET_BANDLIST, bandlist,
+ sizeof(bandlist), false);
+ if (unlikely(err)) {
+ WL_ERR(("error read bandlist (%d)\n", err));
+ goto end_bands;
+ }
+ err = wldev_ioctl(dev, WLC_GET_BAND, &cur_band,
+ sizeof(s32), false);
+ if (unlikely(err)) {
+ WL_ERR(("error (%d)\n", err));
+ goto end_bands;
+ }
+
+ err = wldev_iovar_getint(dev, "nmode", &nmode);
+ if (unlikely(err)) {
+ WL_ERR(("error reading nmode (%d)\n", err));
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ err = wldev_iovar_getint(dev, "vhtmode", &vhtmode);
+ if (unlikely(err)) {
+ WL_ERR(("error reading vhtmode (%d)\n", err));
+ }
+
+ if (vhtmode) {
+ err = wldev_iovar_getint(dev, "txstreams", &txstreams);
+ if (unlikely(err)) {
+ WL_ERR(("error reading txstreams (%d)\n", err));
+ }
+
+ err = wldev_iovar_getint(dev, "rxstreams", &rxstreams);
+ if (unlikely(err)) {
+ WL_ERR(("error reading rxstreams (%d)\n", err));
+ }
+
+ err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap);
+ if (unlikely(err)) {
+ WL_ERR(("error reading ldpc_cap (%d)\n", err));
+ }
+
+ err = wldev_iovar_getint(dev, "stbc_rx", &stbc_rx);
+ if (unlikely(err)) {
+ WL_ERR(("error reading stbc_rx (%d)\n", err));
+ }
+
+ err = wldev_iovar_getint(dev, "stbc_tx", &stbc_tx);
+ if (unlikely(err)) {
+ WL_ERR(("error reading stbc_tx (%d)\n", err));
+ }
+
+ err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap);
+ if (unlikely(err)) {
+ WL_ERR(("error reading txbf_bfe_cap (%d)\n", err));
+ }
+
+ err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap);
+ if (unlikely(err)) {
+ WL_ERR(("error reading txbf_bfr_cap (%d)\n", err));
+ }
+ }
+#endif
+
+ /* For nmode and vhtmode check bw cap */
+ if (nmode ||
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ vhtmode ||
+#endif
+ 0) {
+ err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
+ if (unlikely(err)) {
+ WL_ERR(("error get mimo_bw_cap (%d)\n", err));
+ }
+ }
+
+ err = wl_construct_reginfo(cfg, bw_cap);
+ if (err) {
+ WL_ERR(("wl_construct_reginfo() fails err=%d\n", err));
+ if (err != BCME_UNSUPPORTED)
+ goto end_bands;
+ err = 0;
+ }
+ wiphy = bcmcfg_to_wiphy(cfg);
+ nband = bandlist[0];
+
+ for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) {
+ index = -1;
+ if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) {
+ bands[NL80211_BAND_5GHZ] =
+ &__wl_band_5ghz_a;
+ index = NL80211_BAND_5GHZ;
+ if (nmode && (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G))
+ bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ /* VHT capabilities. */
+ if (vhtmode) {
+ /* Supported */
+ bands[index]->vht_cap.vht_supported = TRUE;
+
+ for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) {
+ /* TX stream rates. */
+ if (j <= txstreams) {
+ VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
+ bands[index]->vht_cap.vht_mcs.tx_mcs_map);
+ } else {
+ VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
+ bands[index]->vht_cap.vht_mcs.tx_mcs_map);
+ }
+
+ /* RX stream rates. */
+ if (j <= rxstreams) {
+ VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
+ bands[index]->vht_cap.vht_mcs.rx_mcs_map);
+ } else {
+ VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
+ bands[index]->vht_cap.vht_mcs.rx_mcs_map);
+ }
+ }
+
+
+ /* Capabilities */
+ /* 80 MHz is mandatory */
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_SHORT_GI_80;
+
+ if (WL_BW_CAP_160MHZ(bw_cap)) {
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_SHORT_GI_160;
+ }
+
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
+
+ if (ldpc_cap)
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_RXLDPC;
+
+ if (stbc_tx)
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_TXSTBC;
+
+ if (stbc_rx)
+ bands[index]->vht_cap.cap |=
+ (stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT);
+
+ if (txbf_bfe_cap)
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
+
+ if (txbf_bfr_cap) {
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
+ }
+
+ if (txbf_bfe_cap || txbf_bfr_cap) {
+ bands[index]->vht_cap.cap |=
+ (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT);
+ bands[index]->vht_cap.cap |=
+ ((txstreams - 1) <<
+ VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT);
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
+ }
+
+ /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */
+ bands[index]->vht_cap.cap |=
+ (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT);
+ WL_INFO(("%s band[%d] vht_enab=%d vht_cap=%08x "
+ "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n",
+ __FUNCTION__, index,
+ bands[index]->vht_cap.vht_supported,
+ bands[index]->vht_cap.cap,
+ bands[index]->vht_cap.vht_mcs.rx_mcs_map,
+ bands[index]->vht_cap.vht_mcs.tx_mcs_map));
+ }
+#endif
+ }
+ else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) {
+ bands[NL80211_BAND_2GHZ] =
+ &__wl_band_2ghz;
+ index = NL80211_BAND_2GHZ;
+ if (bw_cap == WLC_N_BW_40ALL)
+ bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+ }
+
+ if ((index >= 0) && nmode) {
+ bands[index]->ht_cap.cap |=
+ (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40);
+ bands[index]->ht_cap.ht_supported = TRUE;
+ bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
+ /* An HT shall support all EQM rates for one spatial stream */
+ bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
+ }
+
+ }
+
+ wiphy->bands[NL80211_BAND_2GHZ] = bands[NL80211_BAND_2GHZ];
+ wiphy->bands[NL80211_BAND_5GHZ] = bands[NL80211_BAND_5GHZ];
+
+ /* check if any bands populated otherwise makes 2Ghz as default */
+ if (wiphy->bands[NL80211_BAND_2GHZ] == NULL &&
+ wiphy->bands[NL80211_BAND_5GHZ] == NULL) {
+ /* Setup 2Ghz band as default */
+ wiphy->bands[NL80211_BAND_2GHZ] = &__wl_band_2ghz;
+ }
+
+ if (notify) {
+ struct ieee80211_supported_band *sband;
+ enum nl80211_band wiphy_band;
+ struct ieee80211_channel *chan;
+ for (wiphy_band = 0; wiphy_band < NUM_NL80211_BANDS;
+ wiphy_band++) {
+ sband = wiphy->bands[wiphy_band];
+ if (!sband)
+ continue;
+ for (i = 0; i < sband->n_channels; i++) {
+ chan = &sband->channels[i];
+ chan->beacon_found = false;
+ }
+ }
+ wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
+ }
+
+ end_bands:
+ if (rollback_lock)
+ mutex_unlock(&cfg->usr_sync);
+ return err;
+}
+
+static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg)
+{
+ s32 err = 0;
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
+
+ WL_DBG(("In\n"));
+
+ err = dhd_config_dongle(cfg);
+ if (unlikely(err))
+ return err;
+
+ err = wl_config_ifmode(cfg, ndev, wdev->iftype);
+ if (unlikely(err && err != -EINPROGRESS)) {
+ WL_ERR(("wl_config_ifmode failed\n"));
+ if (err == -1) {
+ WL_ERR(("return error %d\n", err));
+ return err;
+ }
+ }
+ err = wl_update_wiphybands(cfg, true);
+ if (unlikely(err)) {
+ WL_ERR(("wl_update_wiphybands failed\n"));
+ if (err == -1) {
+ WL_ERR(("return error %d\n", err));
+ return err;
+ }
+ }
+ if (!dhd_download_fw_on_driverload) {
+ err = wl_create_event_handler(cfg);
+ if (err) {
+ WL_ERR(("wl_create_event_handler failed\n"));
+ return err;
+ }
+ wl_init_event_handler(cfg);
+ }
+
+ err = wl_init_scan(cfg);
+ if (err) {
+ WL_ERR(("wl_init_scan failed\n"));
+ return err;
+ }
+
+ err = dhd_monitor_init(cfg->pub);
+
+ INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
+ wl_set_drv_status(cfg, READY, ndev);
+ return err;
+}
+
+static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
+{
+ s32 err = 0;
+ unsigned long flags;
+ struct net_info *iter, *next;
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+#if defined(WL_CFG80211) && defined(WL_ENABLE_P2P_IF) && !defined(PLATFORM_SLP)
+ struct net_device *p2p_net = cfg->p2p_net;
+#endif
+#ifdef PROP_TXSTATUS_VSDB
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+#endif /* PROP_TXSTATUS_VSDB */
+ WL_DBG(("In\n"));
+ /* Delete pm_enable_work */
+ wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL);
+
+#ifdef WL_NAN
+ wl_cfgnan_stop_handler(ndev, g_bcm_cfg, NULL, NULL);
+#endif /* WL_NAN */
+
+ if (cfg->p2p_supported) {
+ wl_clr_p2p_status(cfg, GO_NEG_PHASE);
+#ifdef PROP_TXSTATUS_VSDB
+ if (wl_cfgp2p_vif_created(cfg)) {
+ bool enabled = false;
+ dhd_wlfc_get_enable(dhd, &enabled);
+ if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
+ dhd->op_mode != DHD_FLAG_IBSS_MODE) {
+ dhd_wlfc_deinit(dhd);
+ cfg->wlfc_on = false;
+ }
+ }
+#endif /* PROP_TXSTATUS_VSDB */
+ }
+
+ /* Check if cfg80211 interface is already down */
+ if (!wl_get_drv_status(cfg, READY, ndev)) {
+ WL_DBG(("cfg80211 interface is already down"));
+ return err; /* it is even not ready */
+ }
+
+
+ /* If primary BSS is operational (for e.g SoftAP), bring it down */
+ if (wl_cfgp2p_bss_isup(ndev, 0)) {
+ if (wl_cfgp2p_bss(cfg, ndev, 0, 0) < 0)
+ WL_ERR(("BSS down failed \n"));
+ }
+
+ for_each_ndev(cfg, iter, next) {
+ /* p2p discovery iface ndev ptr could be null */
+ if (iter->ndev) {
+ wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
+ }
+ }
+
+
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+ if (cfg->scan_request) {
+ struct cfg80211_scan_info info = {
+ .aborted = true,
+ };
+
+ cfg80211_scan_done(cfg->scan_request, &info);
+ cfg->scan_request = NULL;
+ }
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+
+ for_each_ndev(cfg, iter, next) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+ if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
+ CFG80211_DISCONNECTED(iter->ndev, 0, NULL, 0, false, GFP_KERNEL);
+ }
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) */
+ wl_clr_drv_status(cfg, READY, iter->ndev);
+ wl_clr_drv_status(cfg, SCANNING, iter->ndev);
+ wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
+ wl_clr_drv_status(cfg, CONNECTING, iter->ndev);
+ wl_clr_drv_status(cfg, CONNECTED, iter->ndev);
+ wl_clr_drv_status(cfg, DISCONNECTING, iter->ndev);
+ wl_clr_drv_status(cfg, AP_CREATED, iter->ndev);
+ wl_clr_drv_status(cfg, AP_CREATING, iter->ndev);
+ }
+ bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype =
+ NL80211_IFTYPE_STATION;
+#if defined(WL_CFG80211) && defined(WL_ENABLE_P2P_IF) && !defined(PLATFORM_SLP)
+ if (p2p_net)
+ dev_close(p2p_net);
+#endif
+ DNGL_FUNC(dhd_cfg80211_down, (cfg));
+
+ if (!dhd_download_fw_on_driverload) {
+ /* Avoid deadlock from wl_cfg80211_down */
+ mutex_unlock(&cfg->usr_sync);
+ wl_destroy_event_handler(cfg);
+ mutex_lock(&cfg->usr_sync);
+ }
+ wl_flush_eq(cfg);
+ wl_link_down(cfg);
+ if (cfg->p2p_supported) {
+ if (timer_pending(&cfg->p2p->listen_timer))
+ del_timer_sync(&cfg->p2p->listen_timer);
+ wl_cfgp2p_down(cfg);
+ }
+
+ if (timer_pending(&cfg->scan_timeout)) {
+ del_timer_sync(&cfg->scan_timeout);
+ }
+
+ dhd_monitor_uninit();
+
+#if defined(WL_VIRTUAL_APSTA)
+ /* Clean up if not removed already */
+ if (cfg->bss_cfgdev) {
+ wl_cfg80211_del_iface(cfg->wdev->wiphy, cfg->bss_cfgdev);
+ }
+#endif /* defined (WL_VIRTUAL_APSTA) */
+
+#ifdef WL11U
+ /* Clear interworking element. */
+ if (cfg->wl11u) {
+ cfg->wl11u = FALSE;
+ cfg->iw_ie_len = 0;
+ memset(cfg->iw_ie, 0, IW_IES_MAX_BUF_LEN);
+ }
+#endif /* WL11U */
+
+#ifdef DHD_IFDEBUG
+ /* Printout all netinfo entries */
+ wl_probe_wdev_all(cfg);
+#endif /* DHD_IFDEBUG */
+
+ return err;
+}
+
+s32 wl_cfg80211_up(void *para)
+{
+ struct bcm_cfg80211 *cfg;
+ s32 err = 0;
+ int val = 1;
+ dhd_pub_t *dhd;
+ (void)para;
+ WL_DBG(("In\n"));
+ cfg = g_bcm_cfg;
+
+ if ((err = wldev_ioctl(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val,
+ sizeof(int), false) < 0)) {
+ WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err));
+ return err;
+ }
+ val = dtoh32(val);
+ if (val != WLC_IOCTL_VERSION && val != 1) {
+ WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n",
+ val, WLC_IOCTL_VERSION));
+ return BCME_VERSION;
+ }
+ ioctl_version = val;
+ WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version));
+
+ mutex_lock(&cfg->usr_sync);
+ dhd = (dhd_pub_t *)(cfg->pub);
+ if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
+ err = wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg));
+ if (unlikely(err)) {
+ mutex_unlock(&cfg->usr_sync);
+ return err;
+ }
+ } else {
+ WL_ERR(("Disable p2p support in hostap mode\n"));
+ cfg->p2p_supported = FALSE;
+ }
+ err = __wl_cfg80211_up(cfg);
+ if (unlikely(err))
+ WL_ERR(("__wl_cfg80211_up failed\n"));
+
+
+ mutex_unlock(&cfg->usr_sync);
+ return err;
+}
+
+/* Private Event to Supplicant with indication that chip hangs */
+int wl_cfg80211_hang(struct net_device *dev, u16 reason)
+{
+ struct bcm_cfg80211 *cfg;
+#if defined(SOFTAP_SEND_HANGEVT)
+ /* specifc mac address used for hang event */
+ uint8 hang_mac[ETHER_ADDR_LEN] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
+ dhd_pub_t *dhd;
+#endif /* SOFTAP_SEND_HANGEVT */
+ if (!g_bcm_cfg) {
+ return BCME_ERROR;
+ }
+ cfg = g_bcm_cfg;
+
+ WL_ERR(("In : chip crash eventing\n"));
+ wl_add_remove_pm_enable_work(cfg, FALSE, WL_HANDLER_DEL);
+#if defined(SOFTAP_SEND_HANGEVT)
+ dhd = (dhd_pub_t *)(cfg->pub);
+ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
+ cfg80211_del_sta(dev, hang_mac, GFP_ATOMIC);
+ } else
+#endif /* SOFTAP_SEND_HANGEVT */
+ {
+ CFG80211_DISCONNECTED(dev, reason, NULL, 0, false, GFP_KERNEL);
+ }
+ if (cfg != NULL) {
+ wl_link_down(cfg);
+ }
+ return 0;
+}
+
+s32 wl_cfg80211_down(void *para)
+{
+ struct bcm_cfg80211 *cfg;
+ s32 err = 0;
+
+ (void)para;
+ WL_DBG(("In\n"));
+ cfg = g_bcm_cfg;
+ mutex_lock(&cfg->usr_sync);
+ err = __wl_cfg80211_down(cfg);
+ mutex_unlock(&cfg->usr_sync);
+
+ return err;
+}
+
+static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item)
+{
+ unsigned long flags;
+ void *rptr = NULL;
+ struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
+
+ if (!profile)
+ return NULL;
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+ switch (item) {
+ case WL_PROF_SEC:
+ rptr = &profile->sec;
+ break;
+ case WL_PROF_ACT:
+ rptr = &profile->active;
+ break;
+ case WL_PROF_BSSID:
+ rptr = profile->bssid;
+ break;
+ case WL_PROF_SSID:
+ rptr = &profile->ssid;
+ break;
+ case WL_PROF_CHAN:
+ rptr = &profile->channel;
+ break;
+ }
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+ if (!rptr)
+ WL_ERR(("invalid item (%d)\n", item));
+ return rptr;
+}
+
+static s32
+wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data, s32 item)
+{
+ s32 err = 0;
+ struct wlc_ssid *ssid;
+ unsigned long flags;
+ struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
+
+ if (!profile)
+ return WL_INVALID;
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+ switch (item) {
+ case WL_PROF_SSID:
+ ssid = (wlc_ssid_t *) data;
+ memset(profile->ssid.SSID, 0,
+ sizeof(profile->ssid.SSID));
+ profile->ssid.SSID_len = MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN);
+ memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len);
+ break;
+ case WL_PROF_BSSID:
+ if (data)
+ memcpy(profile->bssid, data, ETHER_ADDR_LEN);
+ else
+ memset(profile->bssid, 0, ETHER_ADDR_LEN);
+ break;
+ case WL_PROF_SEC:
+ memcpy(&profile->sec, data, sizeof(profile->sec));
+ break;
+ case WL_PROF_ACT:
+ profile->active = *(bool *)data;
+ break;
+ case WL_PROF_BEACONINT:
+ profile->beacon_interval = *(u16 *)data;
+ break;
+ case WL_PROF_DTIMPERIOD:
+ profile->dtim_period = *(u8 *)data;
+ break;
+ case WL_PROF_CHAN:
+ profile->channel = *(u32*)data;
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+
+ if (err == -EOPNOTSUPP)
+ WL_ERR(("unsupported item (%d)\n", item));
+
+ return err;
+}
+
+void wl_cfg80211_dbg_level(u32 level)
+{
+ /*
+ * prohibit to change debug level
+ * by insmod parameter.
+ * eventually debug level will be configured
+ * in compile time by using CONFIG_XXX
+ */
+ /* wl_dbg_level = level; */
+}
+
+static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ return wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS;
+}
+
+static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg)
+{
+ return cfg->ibss_starter;
+}
+
+static void wl_rst_ie(struct bcm_cfg80211 *cfg)
+{
+ struct wl_ie *ie = wl_to_ie(cfg);
+
+ ie->offset = 0;
+}
+
+static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v)
+{
+ struct wl_ie *ie = wl_to_ie(cfg);
+ s32 err = 0;
+
+ if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) {
+ WL_ERR(("ei crosses buffer boundary\n"));
+ return -ENOSPC;
+ }
+ ie->buf[ie->offset] = t;
+ ie->buf[ie->offset + 1] = l;
+ memcpy(&ie->buf[ie->offset + 2], v, l);
+ ie->offset += l + 2;
+
+ return err;
+}
+
+static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, u8 *ie_stream, u32 *ie_size, bool roam)
+{
+ u8 *ssidie;
+ int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN);
+ int32 remaining_ie_buf_len, available_buffer_len;
+ ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size);
+
+ /* ERROR out if
+ * 1. No ssid IE is FOUND or
+ * 2. New ssid length is > what was allocated for existing ssid (as
+ * we do not want to overwrite the rest of the IEs) or
+ * 3. If in case of erroneous buffer input where ssid length doesnt match the space
+ * allocated to it.
+ */
+ if (!ssidie)
+ return;
+ available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream);
+ remaining_ie_buf_len = available_buffer_len - (int)ssidie[1];
+ if ((ssid_len > ssidie[1]) ||
+ (ssidie[1] > available_buffer_len)) {
+ return;
+ }
+ if (ssidie[1] != ssid_len) {
+ if (ssidie[1]) {
+ WL_ERR(("%s: Wrong SSID len: %d != %d\n",
+ __FUNCTION__, ssidie[1], bi->SSID_len));
+ }
+ if (roam) {
+ WL_ERR(("Changing the SSID Info.\n"));
+ memmove(ssidie + ssid_len + 2,
+ (ssidie + 2) + ssidie[1],
+ *ie_size - (ssidie + 2 + ssidie[1] - ie_stream));
+ memcpy(ssidie + 2, bi->SSID, ssid_len);
+ *ie_size = *ie_size + ssid_len - ssidie[1];
+ ssidie[1] = ssid_len;
+ }
+ return;
+ }
+ if (*(ssidie + 2) == '\0')
+ memcpy(ssidie + 2, bi->SSID, ssid_len);
+ return;
+}
+
+static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size)
+{
+ struct wl_ie *ie = wl_to_ie(cfg);
+ s32 err = 0;
+
+ if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) {
+ WL_ERR(("ei_stream crosses buffer boundary\n"));
+ return -ENOSPC;
+ }
+ memcpy(&ie->buf[ie->offset], ie_stream, ie_size);
+ ie->offset += ie_size;
+
+ return err;
+}
+
+static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size)
+{
+ struct wl_ie *ie = wl_to_ie(cfg);
+ s32 err = 0;
+
+ if (unlikely(ie->offset > dst_size)) {
+ WL_ERR(("dst_size is not enough\n"));
+ return -ENOSPC;
+ }
+ memcpy(dst, &ie->buf[0], ie->offset);
+
+ return err;
+}
+
+static u32 wl_get_ielen(struct bcm_cfg80211 *cfg)
+{
+ struct wl_ie *ie = wl_to_ie(cfg);
+
+ return ie->offset;
+}
+
+static void wl_link_up(struct bcm_cfg80211 *cfg)
+{
+ cfg->link_up = true;
+}
+
+static void wl_link_down(struct bcm_cfg80211 *cfg)
+{
+ struct wl_connect_info *conn_info = wl_to_conn(cfg);
+
+ WL_DBG(("In\n"));
+ cfg->link_up = false;
+ conn_info->req_ie_len = 0;
+ conn_info->resp_ie_len = 0;
+}
+
+static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cfg->eq_lock, flags);
+ return flags;
+}
+
+static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags)
+{
+ spin_unlock_irqrestore(&cfg->eq_lock, flags);
+}
+
+static void wl_init_eq_lock(struct bcm_cfg80211 *cfg)
+{
+ spin_lock_init(&cfg->eq_lock);
+}
+
+static void wl_delay(u32 ms)
+{
+ if (in_atomic() || (ms < jiffies_to_msecs(1))) {
+ OSL_DELAY(ms*1000);
+ } else {
+ OSL_SLEEP(ms);
+ }
+}
+
+s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ struct ether_addr p2pif_addr;
+ struct ether_addr primary_mac;
+ if (!cfg->p2p)
+ return -1;
+ if (!p2p_is_on(cfg)) {
+ get_primary_mac(cfg, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr);
+ } else {
+ memcpy(p2pdev_addr->octet,
+ cfg->p2p->dev_addr.octet, ETHER_ADDR_LEN);
+ }
+
+
+ return 0;
+}
+s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
+{
+ struct bcm_cfg80211 *cfg;
+
+ cfg = g_bcm_cfg;
+
+ return wl_cfgp2p_set_p2p_noa(cfg, net, buf, len);
+}
+
+s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
+{
+ struct bcm_cfg80211 *cfg;
+ cfg = g_bcm_cfg;
+
+ return wl_cfgp2p_get_p2p_noa(cfg, net, buf, len);
+}
+
+s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
+{
+ struct bcm_cfg80211 *cfg;
+ cfg = g_bcm_cfg;
+
+ return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len);
+}
+
+s32 wl_cfg80211_channel_to_freq(u32 channel)
+{
+ int freq = 0;
+
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38)
+ freq = ieee80211_channel_to_frequency(channel);
+#else
+ {
+ u16 band = 0;
+ if (channel <= CH_MAX_2G_CHANNEL)
+ band = NL80211_BAND_2GHZ;
+ else
+ band = NL80211_BAND_5GHZ;
+ freq = ieee80211_channel_to_frequency(channel, band);
+ }
+#endif
+ return freq;
+}
+
+
+#ifdef WLTDLS
+static s32
+wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data) {
+
+ struct net_device *ndev = NULL;
+ u32 reason = ntoh32(e->reason);
+ s8 *msg = NULL;
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ switch (reason) {
+ case WLC_E_TDLS_PEER_DISCOVERED :
+ msg = " TDLS PEER DISCOVERD ";
+ break;
+ case WLC_E_TDLS_PEER_CONNECTED :
+ if (cfg->tdls_mgmt_frame) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+ cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
+ cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, 0);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+ cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
+ cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, 0,
+ GFP_ATOMIC);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
+ defined(WL_COMPAT_WIRELESS)
+ cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
+ cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
+ GFP_ATOMIC);
+#else
+ cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq,
+ cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len, GFP_ATOMIC);
+
+#endif
+ }
+ msg = " TDLS PEER CONNECTED ";
+ break;
+ case WLC_E_TDLS_PEER_DISCONNECTED :
+ if (cfg->tdls_mgmt_frame) {
+ kfree(cfg->tdls_mgmt_frame);
+ cfg->tdls_mgmt_frame = NULL;
+ cfg->tdls_mgmt_freq = 0;
+ }
+ msg = "TDLS PEER DISCONNECTED ";
+ break;
+ }
+ if (msg) {
+ WL_ERR(("%s: " MACDBG " on %s ndev\n", msg, MAC2STRDBG((u8*)(&e->addr)),
+ (bcmcfg_to_prmry_ndev(cfg) == ndev) ? "primary" : "secondary"));
+ }
+ return 0;
+
+}
+#endif /* WLTDLS */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0))
+static s32
+wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
+ u32 peer_capability, bool initiator, const u8 *data, size_t len)
+#else
+static s32
+#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
+wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
+ u32 peer_capability, const u8 *data, size_t len)
+#else
+wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *data,
+ size_t len)
+#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) */
+{
+ s32 ret = 0;
+#ifdef WLTDLS
+ struct bcm_cfg80211 *cfg;
+ tdls_wfd_ie_iovar_t info;
+ memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t));
+ cfg = g_bcm_cfg;
+
+#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
+ /* Some customer platform back ported this feature from kernel 3.15 to kernel 3.10
+ * and that cuases build error
+ */
+ BCM_REFERENCE(peer_capability);
+#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
+
+ switch (action_code) {
+ /* We need to set TDLS Wifi Display IE to firmware
+ * using tdls_wfd_ie iovar
+ */
+ case WLAN_TDLS_SET_PROBE_WFD_IE:
+ info.mode = TDLS_WFD_PROBE_IE_TX;
+ memcpy(&info.data, data, len);
+ info.length = len;
+ break;
+ case WLAN_TDLS_SET_SETUP_WFD_IE:
+ info.mode = TDLS_WFD_IE_TX;
+ memcpy(&info.data, data, len);
+ info.length = len;
+ break;
+ default:
+ WL_ERR(("Unsupported action code : %d\n", action_code));
+ goto out;
+ }
+
+ ret = wldev_iovar_setbuf(dev, "tdls_wfd_ie", &info, sizeof(info),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+
+ if (ret) {
+ WL_ERR(("tdls_wfd_ie error %d\n", ret));
+ }
+out:
+#endif /* WLTDLS */
+ return ret;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static s32
+wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *peer, enum nl80211_tdls_operation oper)
+#else
+static s32
+wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, enum nl80211_tdls_operation oper)
+#endif
+{
+ s32 ret = 0;
+#ifdef WLTDLS
+ struct bcm_cfg80211 *cfg;
+ tdls_iovar_t info;
+ cfg = g_bcm_cfg;
+ memset(&info, 0, sizeof(tdls_iovar_t));
+ if (peer) {
+ memcpy(&info.ea, peer, ETHER_ADDR_LEN);
+ } else {
+ return -1;
+ }
+ switch (oper) {
+ case NL80211_TDLS_DISCOVERY_REQ:
+ /* turn on TDLS */
+ ret = dhd_tdls_enable(dev, true, false, NULL);
+ if (ret < 0)
+ return ret;
+ /* If the discovery request is broadcast then we need to set
+ * info.mode to Tunneled Probe Request
+ */
+ if (memcmp(peer, (const uint8 *)BSSID_BROADCAST, ETHER_ADDR_LEN) == 0) {
+ info.mode = TDLS_MANUAL_EP_WFD_TPQ;
+ }
+ else {
+ info.mode = TDLS_MANUAL_EP_DISCOVERY;
+ }
+ break;
+ case NL80211_TDLS_SETUP:
+ /* auto mode on */
+ ret = dhd_tdls_enable(dev, true, true, (struct ether_addr *)peer);
+ if (ret < 0)
+ return ret;
+ break;
+ case NL80211_TDLS_TEARDOWN:
+ info.mode = TDLS_MANUAL_EP_DELETE;
+ /* auto mode off */
+ ret = dhd_tdls_enable(dev, true, false, (struct ether_addr *)peer);
+ if (ret < 0)
+ return ret;
+ break;
+ default:
+ WL_ERR(("Unsupported operation : %d\n", oper));
+ goto out;
+ }
+ if (info.mode) {
+ ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (ret) {
+ WL_ERR(("tdls_endpoint error %d\n", ret));
+ }
+ }
+out:
+#endif /* WLTDLS */
+ return ret;
+}
+#endif
+
+s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
+ enum wl_management_type type)
+{
+ struct bcm_cfg80211 *cfg;
+ struct net_device *ndev = NULL;
+ struct ether_addr primary_mac;
+ s32 ret = 0;
+ s32 bssidx = 0;
+ s32 pktflag = 0;
+ cfg = g_bcm_cfg;
+
+ if (wl_get_drv_status(cfg, AP_CREATING, net)) {
+ /* Vendor IEs should be set to FW
+ * after SoftAP interface is brought up
+ */
+ goto exit;
+ } else if (wl_get_drv_status(cfg, AP_CREATED, net)) {
+ ndev = net;
+ bssidx = 0;
+ } else if (cfg->p2p) {
+ net = ndev_to_wlc_ndev(net, cfg);
+ if (!cfg->p2p->on) {
+ get_primary_mac(cfg, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(&primary_mac, &cfg->p2p->dev_addr,
+ &cfg->p2p->int_addr);
+ /* In case of p2p_listen command, supplicant send remain_on_channel
+ * without turning on P2P
+ */
+
+ p2p_on(cfg) = true;
+ ret = wl_cfgp2p_enable_discovery(cfg, net, NULL, 0);
+
+ if (unlikely(ret)) {
+ goto exit;
+ }
+ }
+ if (net == bcmcfg_to_prmry_ndev(cfg)) {
+ ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
+ bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+ } else {
+ ndev = net;
+ bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
+ }
+ }
+ if (ndev != NULL) {
+ switch (type) {
+ case WL_BEACON:
+ pktflag = VNDR_IE_BEACON_FLAG;
+ break;
+ case WL_PROBE_RESP:
+ pktflag = VNDR_IE_PRBRSP_FLAG;
+ break;
+ case WL_ASSOC_RESP:
+ pktflag = VNDR_IE_ASSOCRSP_FLAG;
+ break;
+ }
+ if (pktflag)
+ ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev, bssidx, pktflag, buf, len);
+ }
+exit:
+ return ret;
+}
+
+#ifdef WL_SUPPORT_AUTO_CHANNEL
+static s32
+wl_cfg80211_set_auto_channel_scan_state(struct net_device *ndev)
+{
+ u32 val = 0;
+ s32 ret = BCME_ERROR;
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+
+ /* Disable mpc, to avoid automatic interface down. */
+ val = 0;
+
+ ret = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val,
+ sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
+ &cfg->ioctl_buf_sync);
+ if (ret < 0) {
+ WL_ERR(("set 'mpc' failed, error = %d\n", ret));
+ goto done;
+ }
+
+ /* Set interface up, explicitly. */
+ val = 1;
+
+ ret = wldev_ioctl(ndev, WLC_UP, (void *)&val, sizeof(val), true);
+ if (ret < 0) {
+ WL_ERR(("set interface up failed, error = %d\n", ret));
+ goto done;
+ }
+
+ /* Stop all scan explicitly, till auto channel selection complete. */
+ wl_set_drv_status(cfg, SCANNING, ndev);
+ if (cfg->escan_info.ndev == NULL) {
+ ret = BCME_OK;
+ goto done;
+ }
+ ret = wl_notify_escan_complete(cfg, ndev, true, true);
+ if (ret < 0) {
+ WL_ERR(("set scan abort failed, error = %d\n", ret));
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+static bool
+wl_cfg80211_valid_chanspec_p2p(chanspec_t chanspec)
+{
+ bool valid = false;
+
+ if (ioctl_version != 1) {
+ if ((chanspec = wl_chspec_to_legacy(chanspec)) == INVCHANSPEC) {
+ return valid;
+ }
+ }
+
+ /* channel 1 to 14 */
+ if ((chanspec >= 0x2b01) && (chanspec <= 0x2b0e)) {
+ valid = true;
+ }
+ /* channel 36 to 48 */
+ else if ((chanspec >= 0x1b24) && (chanspec <= 0x1b30)) {
+ valid = true;
+ }
+ /* channel 149 to 161 */
+ else if ((chanspec >= 0x1b95) && (chanspec <= 0x1ba1)) {
+ valid = true;
+ }
+ else {
+ valid = false;
+ WL_INFO(("invalid P2P chanspec, channel = %d, chanspec = %04x\n",
+ CHSPEC_CHANNEL(chanspec), chanspec));
+ }
+
+ return valid;
+}
+
+s32
+wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen)
+{
+ s32 ret = BCME_ERROR;
+ struct bcm_cfg80211 *cfg = NULL;
+ wl_uint32_list_t *list = NULL;
+ chanspec_t chanspec = 0;
+
+ memset(buf, 0, buflen);
+
+ cfg = g_bcm_cfg;
+ list = (wl_uint32_list_t *)buf;
+ list->count = htod32(WL_NUMCHANSPECS);
+
+ /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */
+ chanspec |= (WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 |
+ WL_CHANSPEC_CTL_SB_NONE);
+ chanspec = wl_chspec_host_to_driver(chanspec);
+
+ ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
+ sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
+ if (ret < 0) {
+ WL_ERR(("get 'chanspecs' failed, error = %d\n", ret));
+ }
+
+ return ret;
+}
+
+s32
+wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen)
+{
+ u32 channel = 0;
+ s32 ret = BCME_ERROR;
+ s32 i = 0;
+ s32 j = 0;
+ struct bcm_cfg80211 *cfg = NULL;
+ wl_uint32_list_t *list = NULL;
+ chanspec_t chanspec = 0;
+
+ memset(buf, 0, buflen);
+
+ cfg = g_bcm_cfg;
+ list = (wl_uint32_list_t *)buf;
+ list->count = htod32(WL_NUMCHANSPECS);
+
+ /* Restrict channels to 5GHz, 20MHz BW, no SB. */
+ chanspec |= (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 |
+ WL_CHANSPEC_CTL_SB_NONE);
+ chanspec = wl_chspec_host_to_driver(chanspec);
+
+ ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
+ sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
+ if (ret < 0) {
+ WL_ERR(("get 'chanspecs' failed, error = %d\n", ret));
+ goto done;
+ }
+
+ /* Skip DFS and inavlid P2P channel. */
+ for (i = 0, j = 0; i < dtoh32(list->count); i++) {
+ chanspec = (chanspec_t) dtoh32(list->element[i]);
+ channel = CHSPEC_CHANNEL(chanspec);
+
+ ret = wldev_iovar_getint(ndev, "per_chan_info", &channel);
+ if (ret < 0) {
+ WL_ERR(("get 'per_chan_info' failed, error = %d\n", ret));
+ goto done;
+ }
+
+ if (CHANNEL_IS_RADAR(channel) ||
+ !(wl_cfg80211_valid_chanspec_p2p(chanspec))) {
+ continue;
+ } else {
+ list->element[j] = list->element[i];
+ }
+
+ j++;
+ }
+
+ list->count = j;
+
+done:
+ return ret;
+}
+
+static s32
+wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen,
+ int *channel)
+{
+ s32 ret = BCME_ERROR;
+ int chosen = 0;
+ int retry = 0;
+
+ /* Start auto channel selection scan. */
+ ret = wldev_ioctl(ndev, WLC_START_CHANNEL_SEL, buf, buflen, true);
+ if (ret < 0) {
+ WL_ERR(("can't start auto channel scan, error = %d\n", ret));
+ *channel = 0;
+ goto done;
+ }
+
+ /* Wait for auto channel selection, worst case possible delay is 5250ms. */
+ retry = CHAN_SEL_RETRY_COUNT;
+
+ while (retry--) {
+ OSL_SLEEP(CHAN_SEL_IOCTL_DELAY);
+
+ ret = wldev_ioctl(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen),
+ false);
+ if ((ret == 0) && (dtoh32(chosen) != 0)) {
+ *channel = (u16)(chosen & 0x00FF);
+ WL_INFO(("selected channel = %d\n", *channel));
+ break;
+ }
+ WL_INFO(("attempt = %d, ret = %d, chosen = %d\n",
+ (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen)));
+ }
+
+ if (retry <= 0) {
+ WL_ERR(("failure, auto channel selection timed out\n"));
+ *channel = 0;
+ ret = BCME_ERROR;
+ }
+
+done:
+ return ret;
+}
+
+static s32
+wl_cfg80211_restore_auto_channel_scan_state(struct net_device *ndev)
+{
+ u32 val = 0;
+ s32 ret = BCME_ERROR;
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+
+ /* Clear scan stop driver status. */
+ wl_clr_drv_status(cfg, SCANNING, ndev);
+
+ /* Enable mpc back to 1, irrespective of initial state. */
+ val = 1;
+
+ ret = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val,
+ sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
+ &cfg->ioctl_buf_sync);
+ if (ret < 0) {
+ WL_ERR(("set 'mpc' failed, error = %d\n", ret));
+ }
+
+ return ret;
+}
+
+s32
+wl_cfg80211_get_best_channels(struct net_device *dev, char* cmd, int total_len)
+{
+ int channel = 0;
+ s32 ret = BCME_ERROR;
+ u8 *buf = NULL;
+ char *pos = cmd;
+ struct bcm_cfg80211 *cfg = NULL;
+ struct net_device *ndev = NULL;
+
+ memset(cmd, 0, total_len);
+
+ buf = kmalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL);
+ if (buf == NULL) {
+ WL_ERR(("failed to allocate chanspec buffer\n"));
+ return -ENOMEM;
+ }
+
+ /*
+ * Always use primary interface, irrespective of interface on which
+ * command came.
+ */
+ cfg = g_bcm_cfg;
+ ndev = bcmcfg_to_prmry_ndev(cfg);
+
+ /*
+ * Make sure that FW and driver are in right state to do auto channel
+ * selection scan.
+ */
+ ret = wl_cfg80211_set_auto_channel_scan_state(ndev);
+ if (ret < 0) {
+ WL_ERR(("can't set auto channel scan state, error = %d\n", ret));
+ goto done;
+ }
+
+ /* Best channel selection in 2.4GHz band. */
+ ret = wl_cfg80211_get_chanspecs_2g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
+ if (ret < 0) {
+ WL_ERR(("can't get chanspecs in 2.4GHz, error = %d\n", ret));
+ goto done;
+ }
+
+ ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
+ &channel);
+ if (ret < 0) {
+ WL_ERR(("can't select best channel scan in 2.4GHz, error = %d\n", ret));
+ goto done;
+ }
+
+ if (CHANNEL_IS_2G(channel)) {
+ channel = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
+ } else {
+ WL_ERR(("invalid 2.4GHz channel, channel = %d\n", channel));
+ channel = 0;
+ }
+
+ sprintf(pos, "%04d ", channel);
+ pos += 5;
+
+ /* Best channel selection in 5GHz band. */
+ ret = wl_cfg80211_get_chanspecs_5g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
+ if (ret < 0) {
+ WL_ERR(("can't get chanspecs in 5GHz, error = %d\n", ret));
+ goto done;
+ }
+
+ ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
+ &channel);
+ if (ret < 0) {
+ WL_ERR(("can't select best channel scan in 5GHz, error = %d\n", ret));
+ goto done;
+ }
+
+ if (CHANNEL_IS_5G(channel)) {
+ channel = ieee80211_channel_to_frequency(channel, NL80211_BAND_5GHZ);
+ } else {
+ WL_ERR(("invalid 5GHz channel, channel = %d\n", channel));
+ channel = 0;
+ }
+
+ sprintf(pos, "%04d ", channel);
+ pos += 5;
+
+ /* Set overall best channel same as 5GHz best channel. */
+ sprintf(pos, "%04d ", channel);
+ pos += 5;
+
+done:
+ if (NULL != buf) {
+ kfree(buf);
+ }
+
+ /* Restore FW and driver back to normal state. */
+ ret = wl_cfg80211_restore_auto_channel_scan_state(ndev);
+ if (ret < 0) {
+ WL_ERR(("can't restore auto channel scan state, error = %d\n", ret));
+ }
+
+ return (pos - cmd);
+}
+#endif /* WL_SUPPORT_AUTO_CHANNEL */
+
+static const struct rfkill_ops wl_rfkill_ops = {
+ .set_block = wl_rfkill_set
+};
+
+static int wl_rfkill_set(void *data, bool blocked)
+{
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
+
+ WL_DBG(("Enter \n"));
+ WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked"));
+
+ if (!cfg)
+ return -EINVAL;
+
+ cfg->rf_blocked = blocked;
+
+ return 0;
+}
+
+static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup)
+{
+ s32 err = 0;
+
+ WL_DBG(("Enter \n"));
+ if (!cfg)
+ return -EINVAL;
+ if (setup) {
+ cfg->rfkill = rfkill_alloc("brcmfmac-wifi",
+ wl_cfg80211_get_parent_dev(),
+ RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)cfg);
+
+ if (!cfg->rfkill) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ err = rfkill_register(cfg->rfkill);
+
+ if (err)
+ rfkill_destroy(cfg->rfkill);
+ } else {
+ if (!cfg->rfkill) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ rfkill_unregister(cfg->rfkill);
+ rfkill_destroy(cfg->rfkill);
+ }
+
+err_out:
+ return err;
+}
+
+#ifdef DEBUGFS_CFG80211
+/**
+* Format : echo "SCAN:1 DBG:1" > /sys/kernel/debug/dhd/debug_level
+* to turn on SCAN and DBG log.
+* To turn off SCAN partially, echo "SCAN:0" > /sys/kernel/debug/dhd/debug_level
+* To see current setting of debug level,
+* cat /sys/kernel/debug/dhd/debug_level
+*/
+static ssize_t
+wl_debuglevel_write(struct file *file, const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)], sublog[S_SUBLOGLEVEL];
+ char *params, *token, *colon;
+ uint i, tokens, log_on = 0;
+ memset(tbuf, 0, sizeof(tbuf));
+ memset(sublog, 0, sizeof(sublog));
+ if (copy_from_user(&tbuf, userbuf, min_t(size_t, sizeof(tbuf), count)))
+ return -EFAULT;
+
+ params = &tbuf[0];
+ colon = strchr(params, '\n');
+ if (colon != NULL)
+ *colon = '\0';
+ while ((token = strsep(&params, " ")) != NULL) {
+ memset(sublog, 0, sizeof(sublog));
+ if (token == NULL || !*token)
+ break;
+ if (*token == '\0')
+ continue;
+ colon = strchr(token, ':');
+ if (colon != NULL) {
+ *colon = ' ';
+ }
+ tokens = sscanf(token, "%s %u", sublog, &log_on);
+ if (colon != NULL)
+ *colon = ':';
+
+ if (tokens == 2) {
+ for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
+ if (!strncmp(sublog, sublogname_map[i].sublogname,
+ strlen(sublogname_map[i].sublogname))) {
+ if (log_on)
+ wl_dbg_level |=
+ (sublogname_map[i].log_level);
+ else
+ wl_dbg_level &=
+ ~(sublogname_map[i].log_level);
+ }
+ }
+ } else
+ WL_ERR(("%s: can't parse '%s' as a "
+ "SUBMODULE:LEVEL (%d tokens)\n",
+ tbuf, token, tokens));
+
+
+ }
+ return count;
+}
+
+static ssize_t
+wl_debuglevel_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char *param;
+ char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)];
+ uint i;
+ memset(tbuf, 0, sizeof(tbuf));
+ param = &tbuf[0];
+ for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
+ param += snprintf(param, sizeof(tbuf) - 1, "%s:%d ",
+ sublogname_map[i].sublogname,
+ (wl_dbg_level & sublogname_map[i].log_level) ? 1 : 0);
+ }
+ *param = '\n';
+ return simple_read_from_buffer(user_buf, count, ppos, tbuf, strlen(&tbuf[0]));
+
+}
+static const struct file_operations fops_debuglevel = {
+ .open = NULL,
+ .write = wl_debuglevel_write,
+ .read = wl_debuglevel_read,
+ .owner = THIS_MODULE,
+ .llseek = NULL,
+};
+
+static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg)
+{
+ s32 err = 0;
+ struct dentry *_dentry;
+ if (!cfg)
+ return -EINVAL;
+ cfg->debugfs = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ if (!cfg->debugfs || IS_ERR(cfg->debugfs)) {
+ if (cfg->debugfs == ERR_PTR(-ENODEV))
+ WL_ERR(("Debugfs is not enabled on this kernel\n"));
+ else
+ WL_ERR(("Can not create debugfs directory\n"));
+ cfg->debugfs = NULL;
+ goto exit;
+
+ }
+ _dentry = debugfs_create_file("debug_level", S_IRUSR | S_IWUSR,
+ cfg->debugfs, cfg, &fops_debuglevel);
+ if (!_dentry || IS_ERR(_dentry)) {
+ WL_ERR(("failed to create debug_level debug file\n"));
+ wl_free_debugfs(cfg);
+ }
+exit:
+ return err;
+}
+static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg)
+{
+ if (!cfg)
+ return -EINVAL;
+ if (cfg->debugfs)
+ debugfs_remove_recursive(cfg->debugfs);
+ cfg->debugfs = NULL;
+ return 0;
+}
+#endif /* DEBUGFS_CFG80211 */
+
+struct device *wl_cfg80211_get_parent_dev(void)
+{
+ return cfg80211_parent_dev;
+}
+
+void wl_cfg80211_set_parent_dev(void *dev)
+{
+ cfg80211_parent_dev = dev;
+}
+
+static void wl_cfg80211_clear_parent_dev(void)
+{
+ cfg80211_parent_dev = NULL;
+}
+
+void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
+{
+ wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg), "cur_etheraddr", NULL,
+ 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
+ memcpy(mac->octet, cfg->ioctl_buf, ETHER_ADDR_LEN);
+}
+static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role)
+{
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+ if (((dev_role == NL80211_IFTYPE_AP) &&
+ !(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) ||
+ ((dev_role == NL80211_IFTYPE_P2P_GO) &&
+ !(dhd->op_mode & DHD_FLAG_P2P_GO_MODE)))
+ {
+ WL_ERR(("device role select failed role:%d op_mode:%d \n", dev_role, dhd->op_mode));
+ return false;
+ }
+ return true;
+}
+
+int wl_cfg80211_do_driver_init(struct net_device *net)
+{
+ struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net);
+
+ if (!cfg || !cfg->wdev)
+ return -EINVAL;
+
+#if !defined(P2PONEINT)
+ if (dhd_do_driver_init(cfg->wdev->netdev) < 0)
+ return -1;
+#endif /* BCMDONGLEHOST */
+
+ return 0;
+}
+
+void wl_cfg80211_enable_trace(bool set, u32 level)
+{
+ if (set)
+ wl_dbg_level = level & WL_DBG_LEVEL;
+ else
+ wl_dbg_level |= (WL_DBG_LEVEL & level);
+}
+#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
+ 2, 0))
+static s32
+wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
+ bcm_struct_cfgdev *cfgdev, u64 cookie)
+{
+ /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION
+ * is passed with CMD_FRAME. This callback is supposed to cancel
+ * the OFFCHANNEL Wait. Since we are already taking care of that
+ * with the tx_mgmt logic, do nothing here.
+ */
+
+ return 0;
+}
+#endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */
+
+#ifdef WL11U
+bcm_tlv_t *
+wl_cfg80211_find_interworking_ie(u8 *parse, u32 len)
+{
+ bcm_tlv_t *ie;
+
+ while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_INTERWORKING_ID))) {
+ return (bcm_tlv_t *)ie;
+ }
+ return NULL;
+}
+
+
+static s32
+wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag,
+ uint8 ie_id, uint8 *data, uint8 data_len)
+{
+ s32 err = BCME_OK;
+ s32 buf_len;
+ s32 iecount;
+ ie_setbuf_t *ie_setbuf;
+
+ if (ie_id != DOT11_MNG_INTERWORKING_ID)
+ return BCME_UNSUPPORTED;
+
+ /* Validate the pktflag parameter */
+ if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG |
+ VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG |
+ VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG|
+ VNDR_IE_CUSTOM_FLAG))) {
+ WL_ERR(("cfg80211 Add IE: Invalid packet flag 0x%x\n", pktflag));
+ return -1;
+ }
+
+ /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */
+ pktflag = htod32(pktflag);
+
+ buf_len = sizeof(ie_setbuf_t) + data_len - 1;
+ ie_setbuf = (ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL);
+
+ if (!ie_setbuf) {
+ WL_ERR(("Error allocating buffer for IE\n"));
+ return -ENOMEM;
+ }
+
+ if (cfg->iw_ie_len == data_len && !memcmp(cfg->iw_ie, data, data_len)) {
+ WL_ERR(("Previous IW IE is equals to current IE\n"));
+ err = BCME_OK;
+ goto exit;
+ }
+
+ strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1);
+ ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
+
+ /* Buffer contains only 1 IE */
+ iecount = htod32(1);
+ memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int));
+ memcpy((void *)&ie_setbuf->ie_buffer.ie_list[0].pktflag, &pktflag, sizeof(uint32));
+
+ /* Now, add the IE to the buffer */
+ ie_setbuf->ie_buffer.ie_list[0].ie_data.id = ie_id;
+
+ /* if already set with previous values, delete it first */
+ if (cfg->iw_ie_len != 0) {
+ WL_DBG(("Different IW_IE was already set. clear first\n"));
+
+ ie_setbuf->ie_buffer.ie_list[0].ie_data.len = 0;
+
+ err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len,
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+
+ if (err != BCME_OK)
+ goto exit;
+ }
+
+ ie_setbuf->ie_buffer.ie_list[0].ie_data.len = data_len;
+ memcpy((uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], data, data_len);
+
+ err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len,
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+
+ if (err == BCME_OK) {
+ memcpy(cfg->iw_ie, data, data_len);
+ cfg->iw_ie_len = data_len;
+ cfg->wl11u = TRUE;
+
+ err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 1, bssidx);
+ }
+
+exit:
+ if (ie_setbuf)
+ kfree(ie_setbuf);
+ return err;
+}
+#endif /* WL11U */
+
+
+
+int wl_cfg80211_scan_stop(bcm_struct_cfgdev *cfgdev)
+{
+ struct bcm_cfg80211 *cfg = NULL;
+ struct net_device *ndev = NULL;
+ unsigned long flags;
+ int clear_flag = 0;
+ int ret = 0;
+
+ WL_TRACE(("Enter\n"));
+
+ cfg = g_bcm_cfg;
+ if (!cfg)
+ return -EINVAL;
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+#ifdef WL_CFG80211_P2P_DEV_IF
+ if (cfg->scan_request && cfg->scan_request->wdev == cfgdev) {
+#else
+ if (cfg->scan_request && cfg->scan_request->dev == cfgdev) {
+#endif
+ struct cfg80211_scan_info info = {
+ .aborted = true,
+ };
+
+ cfg80211_scan_done(cfg->scan_request, &info);
+ cfg->scan_request = NULL;
+ clear_flag = 1;
+ }
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+
+ if (clear_flag)
+ wl_clr_drv_status(cfg, SCANNING, ndev);
+
+ return ret;
+}
+
+bool wl_cfg80211_is_vsdb_mode(void)
+{
+ return (g_bcm_cfg && g_bcm_cfg->vsdb_mode);
+}
+
+void* wl_cfg80211_get_dhdp()
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+
+ return cfg->pub;
+}
+
+bool wl_cfg80211_is_p2p_active(void)
+{
+ return (g_bcm_cfg && g_bcm_cfg->p2p);
+}
+
+static void wl_cfg80211_work_handler(struct work_struct * work)
+{
+ struct bcm_cfg80211 *cfg = NULL;
+ struct net_info *iter, *next;
+ s32 err = BCME_OK;
+ s32 pm = PM_FAST;
+
+ cfg = container_of(work, struct bcm_cfg80211, pm_enable_work.work);
+ WL_DBG(("Enter \n"));
+ if (cfg->pm_enable_work_on) {
+ cfg->pm_enable_work_on = false;
+ for_each_ndev(cfg, iter, next) {
+ /* p2p discovery iface ndev could be null */
+ if (iter->ndev) {
+ if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) ||
+ (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS &&
+ wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_IBSS))
+ continue;
+ if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM,
+ &pm, sizeof(pm), true)) != 0) {
+ if (err == -ENODEV)
+ WL_DBG(("%s:netdev not ready\n", iter->ndev->name));
+ else
+ WL_ERR(("%s:error (%d)\n", iter->ndev->name, err));
+ } else
+ wl_cfg80211_update_power_mode(iter->ndev);
+ }
+ }
+ }
+}
+
+u8
+wl_get_action_category(void *frame, u32 frame_len)
+{
+ u8 category;
+ u8 *ptr = (u8 *)frame;
+ if (frame == NULL)
+ return DOT11_ACTION_CAT_ERR_MASK;
+ if (frame_len < DOT11_ACTION_HDR_LEN)
+ return DOT11_ACTION_CAT_ERR_MASK;
+ category = ptr[DOT11_ACTION_CAT_OFF];
+ WL_INFO(("Action Category: %d\n", category));
+ return category;
+}
+
+int
+wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action)
+{
+ u8 *ptr = (u8 *)frame;
+ if (frame == NULL || ret_action == NULL)
+ return BCME_ERROR;
+ if (frame_len < DOT11_ACTION_HDR_LEN)
+ return BCME_ERROR;
+ if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len))
+ return BCME_ERROR;
+ *ret_action = ptr[DOT11_ACTION_ACT_OFF];
+ WL_INFO(("Public Action : %d\n", *ret_action));
+ return BCME_OK;
+}
+
+static int
+wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const struct ether_addr *bssid)
+{
+ s32 err;
+ wl_event_msg_t e;
+
+ bzero(&e, sizeof(e));
+ e.event_type = cpu_to_be32(WLC_E_ROAM);
+ memcpy(&e.addr, bssid, ETHER_ADDR_LEN);
+ /* trigger the roam event handler */
+ WL_INFO(("Delayed roam to " MACDBG "\n", MAC2STRDBG((u8*)(bssid))));
+ err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL);
+
+ return err;
+}
+
+
+static s32
+wl_cfg80211_parse_vndr_ies(u8 *parse, u32 len,
+ struct parsed_vndr_ies *vndr_ies)
+{
+ s32 err = BCME_OK;
+ vndr_ie_t *vndrie;
+ bcm_tlv_t *ie;
+ struct parsed_vndr_ie_info *parsed_info;
+ u32 count = 0;
+ s32 remained_len;
+
+ remained_len = (s32)len;
+ memset(vndr_ies, 0, sizeof(*vndr_ies));
+
+ WL_INFO(("---> len %d\n", len));
+ ie = (bcm_tlv_t *) parse;
+ if (!bcm_valid_tlv(ie, remained_len))
+ ie = NULL;
+ while (ie) {
+ if (count >= MAX_VNDR_IE_NUMBER)
+ break;
+ if (ie->id == DOT11_MNG_VS_ID) {
+ vndrie = (vndr_ie_t *) ie;
+ /* len should be bigger than OUI length + one data length at least */
+ if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
+ WL_ERR(("%s: invalid vndr ie. length is too small %d\n",
+ __FUNCTION__, vndrie->len));
+ goto end;
+ }
+ /* if wpa or wme ie, do not add ie */
+ if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) &&
+ ((vndrie->data[0] == WPA_OUI_TYPE) ||
+ (vndrie->data[0] == WME_OUI_TYPE))) {
+ CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n"));
+ goto end;
+ }
+
+ parsed_info = &vndr_ies->ie_info[count++];
+
+ /* save vndr ie information */
+ parsed_info->ie_ptr = (char *)vndrie;
+ parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN);
+ memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t));
+ vndr_ies->count = count;
+
+ WL_DBG(("\t ** OUI %02x %02x %02x, type 0x%02x len:%d\n",
+ parsed_info->vndrie.oui[0], parsed_info->vndrie.oui[1],
+ parsed_info->vndrie.oui[2], parsed_info->vndrie.data[0],
+ parsed_info->ie_len));
+ }
+end:
+ ie = bcm_next_tlv(ie, &remained_len);
+ }
+ return err;
+}
+
+s32
+wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 *cfg, s32 bssidx)
+{
+ s32 index;
+ struct net_info *netinfo;
+ s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
+ VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
+
+ netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx);
+ if (!netinfo || !netinfo->wdev) {
+ WL_ERR(("netinfo or netinfo->wdev is NULL\n"));
+ return -1;
+ }
+
+ WL_DBG(("clear management vendor IEs for bssidx:%d \n", bssidx));
+ /* Clear the IEs set in the firmware so that host is in sync with firmware */
+ for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
+ if (wl_cfg80211_set_mgmt_vndr_ies(cfg, netinfo->ndev,
+ bssidx, vndrie_flag[index], NULL, 0) < 0)
+ WL_ERR(("vndr_ies clear failed. Ignoring.. \n"));
+ }
+
+ return 0;
+}
+
+s32
+wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 *cfg)
+{
+ struct net_info *iter, *next;
+
+ WL_DBG(("clear management vendor IEs \n"));
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#endif
+ for_each_ndev(cfg, iter, next) {
+ wl_cfg80211_clear_per_bss_ies(cfg, iter->bssidx);
+ }
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic pop")
+#endif
+ return 0;
+}
+
+#define WL_VNDR_IE_MAXLEN 2048
+static s8 g_mgmt_ie_buf[WL_VNDR_IE_MAXLEN];
+int
+wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ s32 bssidx, s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
+{
+ s32 ret = BCME_OK;
+ u8 *curr_ie_buf = NULL;
+ u8 *mgmt_ie_buf = NULL;
+ u32 mgmt_ie_buf_len = 0;
+ u32 *mgmt_ie_len = 0;
+ u32 del_add_ie_buf_len = 0;
+ u32 total_ie_buf_len = 0;
+ u32 parsed_ie_buf_len = 0;
+ struct parsed_vndr_ies old_vndr_ies;
+ struct parsed_vndr_ies new_vndr_ies;
+ s32 i;
+ u8 *ptr;
+ s32 remained_buf_len;
+ wl_bss_vndr_ies_t *ies = NULL;
+ struct net_info *netinfo;
+
+ WL_DBG(("Enter. pktflag:0x%x bssidx:%x vnd_ie_len:%d \n",
+ pktflag, bssidx, vndr_ie_len));
+
+ if (bssidx > WL_MAX_IFS) {
+ WL_ERR(("bssidx > supported concurrent Ifaces \n"));
+ return -EINVAL;
+ }
+
+ netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx);
+ if (!netinfo) {
+ WL_ERR(("net_info ptr is NULL \n"));
+ return -EINVAL;
+ }
+
+ /* Clear the global buffer */
+ memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf));
+ curr_ie_buf = g_mgmt_ie_buf;
+ ies = &netinfo->bss.ies;
+
+ switch (pktflag) {
+ case VNDR_IE_PRBRSP_FLAG :
+ mgmt_ie_buf = ies->probe_res_ie;
+ mgmt_ie_len = &ies->probe_res_ie_len;
+ mgmt_ie_buf_len = sizeof(ies->probe_res_ie);
+ break;
+ case VNDR_IE_ASSOCRSP_FLAG :
+ mgmt_ie_buf = ies->assoc_res_ie;
+ mgmt_ie_len = &ies->assoc_res_ie_len;
+ mgmt_ie_buf_len = sizeof(ies->assoc_res_ie);
+ break;
+ case VNDR_IE_BEACON_FLAG :
+ mgmt_ie_buf = ies->beacon_ie;
+ mgmt_ie_len = &ies->beacon_ie_len;
+ mgmt_ie_buf_len = sizeof(ies->beacon_ie);
+ break;
+ case VNDR_IE_PRBREQ_FLAG :
+ mgmt_ie_buf = ies->probe_req_ie;
+ mgmt_ie_len = &ies->probe_req_ie_len;
+ mgmt_ie_buf_len = sizeof(ies->probe_req_ie);
+ break;
+ case VNDR_IE_ASSOCREQ_FLAG :
+ mgmt_ie_buf = ies->assoc_req_ie;
+ mgmt_ie_len = &ies->assoc_req_ie_len;
+ mgmt_ie_buf_len = sizeof(ies->assoc_req_ie);
+ break;
+ default:
+ mgmt_ie_buf = NULL;
+ mgmt_ie_len = NULL;
+ WL_ERR(("not suitable packet type (%d)\n", pktflag));
+ return BCME_ERROR;
+ }
+
+ if (vndr_ie_len > mgmt_ie_buf_len) {
+ WL_ERR(("extra IE size too big\n"));
+ ret = -ENOMEM;
+ } else {
+ /* parse and save new vndr_ie in curr_ie_buff before comparing it */
+ if (vndr_ie && vndr_ie_len && curr_ie_buf) {
+ ptr = curr_ie_buf;
+/* must discard vndr_ie constness, attempt to change vndr_ie arg to non-const
+ * causes cascade of errors in other places, fix involves const casts there
+ */
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#endif
+ if ((ret = wl_cfg80211_parse_vndr_ies((u8 *)vndr_ie,
+ vndr_ie_len, &new_vndr_ies)) < 0) {
+ WL_ERR(("parse vndr ie failed \n"));
+ goto exit;
+ }
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic pop")
+#endif
+ for (i = 0; i < new_vndr_ies.count; i++) {
+ struct parsed_vndr_ie_info *vndrie_info =
+ &new_vndr_ies.ie_info[i];
+
+ if ((parsed_ie_buf_len + vndrie_info->ie_len) > WL_VNDR_IE_MAXLEN) {
+ WL_ERR(("IE size is too big (%d > %d)\n",
+ parsed_ie_buf_len, WL_VNDR_IE_MAXLEN));
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
+ vndrie_info->ie_len);
+ parsed_ie_buf_len += vndrie_info->ie_len;
+ }
+ }
+
+ if (mgmt_ie_buf != NULL) {
+ if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
+ (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) {
+ WL_INFO(("Previous mgmt IE is equals to current IE"));
+ goto exit;
+ }
+
+ /* parse old vndr_ie */
+ if ((ret = wl_cfg80211_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len,
+ &old_vndr_ies)) < 0) {
+ WL_ERR(("parse vndr ie failed \n"));
+ goto exit;
+ }
+ /* make a command to delete old ie */
+ for (i = 0; i < old_vndr_ies.count; i++) {
+ struct parsed_vndr_ie_info *vndrie_info =
+ &old_vndr_ies.ie_info[i];
+
+ WL_INFO(("DELETED ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
+ vndrie_info->vndrie.id, vndrie_info->vndrie.len,
+ vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1],
+ vndrie_info->vndrie.oui[2]));
+
+ del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
+ pktflag, vndrie_info->vndrie.oui,
+ vndrie_info->vndrie.id,
+ vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
+ vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
+ "del");
+
+ curr_ie_buf += del_add_ie_buf_len;
+ total_ie_buf_len += del_add_ie_buf_len;
+ }
+ }
+
+ *mgmt_ie_len = 0;
+ /* Add if there is any extra IE */
+ if (mgmt_ie_buf && parsed_ie_buf_len) {
+ ptr = mgmt_ie_buf;
+
+ remained_buf_len = mgmt_ie_buf_len;
+
+ /* make a command to add new ie */
+ for (i = 0; i < new_vndr_ies.count; i++) {
+ struct parsed_vndr_ie_info *vndrie_info =
+ &new_vndr_ies.ie_info[i];
+
+ WL_INFO(("ADDED ID : %d, Len: %d(%d), OUI:%02x:%02x:%02x\n",
+ vndrie_info->vndrie.id, vndrie_info->vndrie.len,
+ vndrie_info->ie_len - 2,
+ vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1],
+ vndrie_info->vndrie.oui[2]));
+
+ del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
+ pktflag, vndrie_info->vndrie.oui,
+ vndrie_info->vndrie.id,
+ vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
+ vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
+ "add");
+
+ /* verify remained buf size before copy data */
+ if (remained_buf_len >= vndrie_info->ie_len) {
+ remained_buf_len -= vndrie_info->ie_len;
+ } else {
+ WL_ERR(("no space in mgmt_ie_buf: pktflag = %d, "
+ "found vndr ies # = %d(cur %d), remained len %d, "
+ "cur mgmt_ie_len %d, new ie len = %d\n",
+ pktflag, new_vndr_ies.count, i, remained_buf_len,
+ *mgmt_ie_len, vndrie_info->ie_len));
+ break;
+ }
+
+ /* save the parsed IE in cfg struct */
+ memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
+ vndrie_info->ie_len);
+ *mgmt_ie_len += vndrie_info->ie_len;
+ curr_ie_buf += del_add_ie_buf_len;
+ total_ie_buf_len += del_add_ie_buf_len;
+ }
+ }
+
+ if (total_ie_buf_len && cfg->ioctl_buf != NULL) {
+ ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf,
+ total_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
+ bssidx, &cfg->ioctl_buf_sync);
+ if (ret)
+ WL_ERR(("vndr ie set error : %d\n", ret));
+ }
+ }
+exit:
+
+return ret;
+}
+
+#ifdef WL_CFG80211_ACL
+static int
+wl_cfg80211_set_mac_acl(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
+ const struct cfg80211_acl_data *acl)
+{
+ int i;
+ int ret = 0;
+ int macnum = 0;
+ int macmode = MACLIST_MODE_DISABLED;
+ struct maclist *list;
+
+ /* get the MAC filter mode */
+ if (acl && acl->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED) {
+ macmode = MACLIST_MODE_ALLOW;
+ } else if (acl && acl->acl_policy == NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
+ acl->n_acl_entries) {
+ macmode = MACLIST_MODE_DENY;
+ }
+
+ /* if acl == NULL, macmode is still disabled.. */
+ if (macmode == MACLIST_MODE_DISABLED) {
+ if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, NULL)) != 0)
+ WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret));
+
+ return ret;
+ }
+
+ macnum = acl->n_acl_entries;
+ if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
+ WL_ERR(("%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) {
+ WL_ERR(("%s : failed to allocate memory\n", __FUNCTION__));
+ return -1;
+ }
+
+ /* prepare the MAC list */
+ list->count = htod32(macnum);
+ for (i = 0; i < macnum; i++) {
+ memcpy(&list->ea[i], &acl->mac_addrs[i], ETHER_ADDR_LEN);
+ }
+ /* set the list */
+ if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, list)) != 0)
+ WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret));
+
+ kfree(list);
+
+ return ret;
+}
+#endif /* WL_CFG80211_ACL */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+int wl_chspec_chandef(chanspec_t chanspec,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
+struct cfg80211_chan_def *chandef,
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
+ \
+ \
+ 0)))
+struct chan_info *chaninfo,
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */
+struct wiphy *wiphy)
+{
+ uint16 freq = 0;
+ int chan_type;
+ int channel = 0;
+
+ if (!chandef) {
+ return -1;
+ }
+ channel = CHSPEC_CHANNEL(chanspec);
+
+ switch (CHSPEC_BW(chanspec)) {
+ case WL_CHANSPEC_BW_20:
+ chan_type = NL80211_CHAN_HT20;
+ break;
+ case WL_CHANSPEC_BW_40:
+ {
+ if (CHSPEC_SB_UPPER(chanspec)) {
+ channel += CH_10MHZ_APART;
+ } else {
+ channel -= CH_10MHZ_APART;
+ }
+ }
+ chan_type = NL80211_CHAN_HT40PLUS;
+ break;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
+ case WL_CHANSPEC_BW_80:
+ case WL_CHANSPEC_BW_8080:
+ {
+ uint16 sb = CHSPEC_CTL_SB(chanspec);
+
+ 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);
+ }
+ }
+
+ chan_type = NL80211_CHAN_WIDTH_80P80;
+ break;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
+ default:
+ chan_type = NL80211_CHAN_HT20;
+ break;
+
+ }
+
+ if (CHSPEC_IS5G(chanspec))
+ freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_5GHZ);
+ else
+ freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
+ cfg80211_chandef_create(chandef, ieee80211_get_channel(wiphy, freq), chan_type);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
+ \
+ \
+ 0)))
+ chaninfo->freq = freq;
+ chaninfo->chan_type = chan_type;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
+ return 0;
+}
+
+void
+wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wiphy *wiphy)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
+ struct cfg80211_chan_def chandef;
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
+ \
+ \
+ 0)))
+ struct chan_info chaninfo;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
+
+ if (!wiphy) {
+ printk("wiphy is null\n");
+ return;
+ }
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
+ if (wl_chspec_chandef(chanspec, &chandef, wiphy)) {
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
+ \
+ \
+ 0)))
+ if (wl_chspec_chandef(chanspec, &chaninfo, wiphy)) {
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
+
+ WL_ERR(("%s:chspec_chandef failed\n", __FUNCTION__));
+ return;
+ }
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
+ cfg80211_ch_switch_notify(dev, &chandef);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
+ \
+ \
+ 0)))
+ cfg80211_ch_switch_notify(dev, chan_info.freq, chan_info.chan_type);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
+ return;
+}
+
+static s32
+wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+const wl_event_msg_t *e, void *data)
+{
+ int error = 0;
+ int chsp = 0;
+ struct net_device *ndev = NULL;
+ struct wiphy *wiphy = NULL;
+ chanspec_t chanspec;
+
+ WL_ERR(("%s\n", __FUNCTION__));
+ if (e->status)
+ return -1;
+ if (cfgdev) {
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+ wiphy = bcmcfg_to_wiphy(cfg);
+ error = wldev_iovar_getint(ndev, "chanspec", &chsp);
+ if (error)
+ return -1;
+ chanspec = wl_chspec_driver_to_host(chsp);
+ wl_cfg80211_ch_switch_notify(ndev, chanspec, wiphy);
+ } else {
+ WL_ERR(("%s:cfgdev is null\n", __FUNCTION__));
+ return -1;
+ }
+
+
+ return 0;
+}
+#else
+static s32
+wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+const wl_event_msg_t *e, void *data)
+{
+ WL_ERR(("%s:Not sup for kernel < 3.5\n", __FUNCTION__));
+ return 0;
+}
+#endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
+
+#ifdef WL_NAN
+int
+wl_cfg80211_nan_cmd_handler(struct net_device *ndev, char *cmd, int cmd_len)
+{
+ return wl_cfgnan_cmd_handler(ndev, g_bcm_cfg, cmd, cmd_len);
+}
+#endif /* WL_NAN */
+#if defined(WL_SUPPORT_AUTO_CHANNEL)
+int
+wl_cfg80211_set_spect(struct net_device *dev, int spect)
+{
+ struct bcm_cfg80211 *cfg = g_bcm_cfg;
+ int down = 1;
+ int up = 1;
+ int err = BCME_OK;
+
+ if (!wl_get_drv_status_all(cfg, CONNECTED)) {
+ err = wldev_ioctl(dev, WLC_DOWN, &down, sizeof(down), true);
+ if (err) {
+ WL_ERR(("%s: WLC_DOWN failed: code: %d\n", __func__, err));
+ return err;
+ }
+
+ err = wldev_ioctl(dev, WLC_SET_SPECT_MANAGMENT, &spect, sizeof(spect), true);
+ if (err) {
+ WL_ERR(("%s: error setting spect: code: %d\n", __func__, err));
+ return err;
+ }
+
+ err = wldev_ioctl(dev, WLC_UP, &up, sizeof(up), true);
+ if (err) {
+ WL_ERR(("%s: WLC_UP failed: code: %d\n", __func__, err));
+ return err;
+ }
+ }
+ return err;
+}
+
+int
+wl_cfg80211_get_sta_channel(struct net_device *dev)
+{
+ if (wl_get_drv_status(g_bcm_cfg, CONNECTED, dev)) {
+ return g_bcm_cfg->channel;
+ }
+ return BCME_OK;
+}
+#endif /* WL_SUPPORT_AUTO_CHANNEL */
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
new file mode 100644
index 000000000000..5f363bfcb111
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
@@ -0,0 +1,1264 @@
+/*
+ * Linux cfg80211 driver
+ *
+ * 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: wl_cfg80211.h 662786 2016-11-11 09:06:37Z $
+ */
+
+#ifndef _wl_cfg80211_h_
+#define _wl_cfg80211_h_
+
+#include <linux/wireless.h>
+#include <typedefs.h>
+#include <proto/ethernet.h>
+#include <wlioctl.h>
+#include <linux/wireless.h>
+#include <net/cfg80211.h>
+#include <linux/rfkill.h>
+
+#include <wl_cfgp2p.h>
+
+struct wl_conf;
+struct wl_iface;
+struct bcm_cfg80211;
+struct wl_security;
+struct wl_ibss;
+
+
+#define htod32(i) (i)
+#define htod16(i) (i)
+#define dtoh32(i) (i)
+#define dtoh16(i) (i)
+#define htodchanspec(i) (i)
+#define dtohchanspec(i) (i)
+
+#define WL_DBG_NONE 0
+#define WL_DBG_P2P_ACTION (1 << 5)
+#define WL_DBG_TRACE (1 << 4)
+#define WL_DBG_SCAN (1 << 3)
+#define WL_DBG_DBG (1 << 2)
+#define WL_DBG_INFO (1 << 1)
+#define WL_DBG_ERR (1 << 0)
+
+/* 0 invalidates all debug messages. default is 1 */
+#define WL_DBG_LEVEL 0xFF
+
+#define CFG80211_ERROR_TEXT "CFG80211-ERROR) "
+
+#define MAX_WAIT_TIME 1500
+#define DNGL_FUNC(func, parameters) func parameters;
+
+#define PM_BLOCK 1
+#define PM_ENABLE 0
+
+#if defined(DHD_DEBUG)
+#define WL_ERR(args) \
+do { \
+ if (wl_dbg_level & WL_DBG_ERR) { \
+ printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \
+ printk args; \
+ } \
+} while (0)
+#else /* defined(DHD_DEBUG) */
+#define WL_ERR(args) \
+do { \
+ if ((wl_dbg_level & WL_DBG_ERR) && net_ratelimit()) { \
+ printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \
+ printk args; \
+ } \
+} while (0)
+#endif /* defined(DHD_DEBUG) */
+
+#ifdef WL_INFO
+#undef WL_INFO
+#endif
+#define WL_INFO(args) \
+do { \
+ if (wl_dbg_level & WL_DBG_INFO) { \
+ printk(KERN_INFO "CFG80211-INFO) %s : ", __func__); \
+ printk args; \
+ } \
+} while (0)
+#ifdef WL_SCAN
+#undef WL_SCAN
+#endif
+#define WL_SCAN(args) \
+do { \
+ if (wl_dbg_level & WL_DBG_SCAN) { \
+ printk(KERN_INFO "CFG80211-SCAN) %s :", __func__); \
+ printk args; \
+ } \
+} while (0)
+#ifdef WL_TRACE
+#undef WL_TRACE
+#endif
+#define WL_TRACE(args) \
+do { \
+ if (wl_dbg_level & WL_DBG_TRACE) { \
+ printk(KERN_INFO "CFG80211-TRACE) %s :", __func__); \
+ printk args; \
+ } \
+} while (0)
+#ifdef WL_TRACE_HW4
+#undef WL_TRACE_HW4
+#endif
+#define WL_TRACE_HW4 WL_TRACE
+#if (WL_DBG_LEVEL > 0)
+#define WL_DBG(args) \
+do { \
+ if (wl_dbg_level & WL_DBG_DBG) { \
+ printk(KERN_DEBUG "CFG80211-DEBUG) %s :", __func__); \
+ printk args; \
+ } \
+} while (0)
+#else /* !(WL_DBG_LEVEL > 0) */
+#define WL_DBG(args)
+#endif /* (WL_DBG_LEVEL > 0) */
+#define WL_PNO(x)
+#define WL_SD(x)
+
+
+#define WL_SCAN_RETRY_MAX 3
+#define WL_NUM_PMKIDS_MAX MAXPMKID
+#define WL_SCAN_BUF_MAX (1024 * 8)
+#define WL_TLV_INFO_MAX 1500
+#define WL_SCAN_IE_LEN_MAX 2048
+#define WL_BSS_INFO_MAX 2048
+#define WL_ASSOC_INFO_MAX 512
+#define WL_IOCTL_LEN_MAX 2048
+#define WL_EXTRA_BUF_MAX 2048
+#define WL_SCAN_ERSULTS_LAST (WL_SCAN_RESULTS_NO_MEM+1)
+#define WL_AP_MAX 256
+#define WL_FILE_NAME_MAX 256
+#define WL_DWELL_TIME 200
+#define WL_MED_DWELL_TIME 400
+#define WL_MIN_DWELL_TIME 100
+#define WL_LONG_DWELL_TIME 1000
+#define IFACE_MAX_CNT 4
+#define WL_SCAN_CONNECT_DWELL_TIME_MS 200
+#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20
+#define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
+#define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
+#define WL_AF_TX_MAX_RETRY 5
+
+#define WL_AF_SEARCH_TIME_MAX 450
+#define WL_AF_TX_EXTRA_TIME_MAX 200
+
+#define WL_SCAN_TIMER_INTERVAL_MS 10000 /* Scan timeout */
+#define WL_CHANNEL_SYNC_RETRY 5
+#define WL_INVALID -1
+
+/* Bring down SCB Timeout to 20secs from 60secs default */
+#ifndef WL_SCB_TIMEOUT
+#define WL_SCB_TIMEOUT 20
+#endif
+
+/* SCAN_SUPPRESS timer values in ms */
+#define WL_SCAN_SUPPRESS_TIMEOUT 31000 /* default Framwork DHCP timeout is 30 sec */
+#define WL_SCAN_SUPPRESS_RETRY 3000
+
+#define WL_PM_ENABLE_TIMEOUT 10000
+
+/* cfg80211 wowlan definitions */
+#define WL_WOWLAN_MAX_PATTERNS 8
+#define WL_WOWLAN_MIN_PATTERN_LEN 1
+#define WL_WOWLAN_MAX_PATTERN_LEN 255
+#define WL_WOWLAN_PKT_FILTER_ID_FIRST 201
+#define WL_WOWLAN_PKT_FILTER_ID_LAST (WL_WOWLAN_PKT_FILTER_ID_FIRST + \
+ WL_WOWLAN_MAX_PATTERNS - 1)
+
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
+#define strnicmp(str1, str2, len) strncasecmp((str1), (str2), (len))
+#define STA_INFO_BIT(info) (1ul << NL80211_STA_ ## info)
+#else
+#define STA_INFO_BIT(info) (STATION_ ## info)
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
+
+/* driver status */
+enum wl_status {
+ WL_STATUS_READY = 0,
+ WL_STATUS_SCANNING,
+ WL_STATUS_SCAN_ABORTING,
+ WL_STATUS_CONNECTING,
+ WL_STATUS_CONNECTED,
+ WL_STATUS_DISCONNECTING,
+ WL_STATUS_AP_CREATING,
+ WL_STATUS_AP_CREATED,
+ /* whole sending action frame procedure:
+ * includes a) 'finding common channel' for public action request frame
+ * and b) 'sending af via 'actframe' iovar'
+ */
+ WL_STATUS_SENDING_ACT_FRM,
+ /* find a peer to go to a common channel before sending public action req frame */
+ WL_STATUS_FINDING_COMMON_CHANNEL,
+ /* waiting for next af to sync time of supplicant.
+ * it includes SENDING_ACT_FRM and WAITING_NEXT_ACT_FRM_LISTEN
+ */
+ WL_STATUS_WAITING_NEXT_ACT_FRM,
+#ifdef WL_CFG80211_SYNC_GON
+ /* go to listen state to wait for next af after SENDING_ACT_FRM */
+ WL_STATUS_WAITING_NEXT_ACT_FRM_LISTEN,
+#endif /* WL_CFG80211_SYNC_GON */
+ /* it will be set when upper layer requests listen and succeed in setting listen mode.
+ * if set, other scan request can abort current listen state
+ */
+ WL_STATUS_REMAINING_ON_CHANNEL,
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ /* it's fake listen state to keep current scan state.
+ * it will be set when upper layer requests listen but scan is running. then just run
+ * a expire timer without actual listen state.
+ * if set, other scan request does not need to abort scan.
+ */
+ WL_STATUS_FAKE_REMAINING_ON_CHANNEL
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+};
+
+/* wi-fi mode */
+enum wl_mode {
+ WL_MODE_BSS,
+ WL_MODE_IBSS,
+ WL_MODE_AP
+};
+
+/* driver profile list */
+enum wl_prof_list {
+ WL_PROF_MODE,
+ WL_PROF_SSID,
+ WL_PROF_SEC,
+ WL_PROF_IBSS,
+ WL_PROF_BAND,
+ WL_PROF_CHAN,
+ WL_PROF_BSSID,
+ WL_PROF_ACT,
+ WL_PROF_BEACONINT,
+ WL_PROF_DTIMPERIOD
+};
+
+/* donlge escan state */
+enum wl_escan_state {
+ WL_ESCAN_STATE_IDLE,
+ WL_ESCAN_STATE_SCANING
+};
+/* fw downloading status */
+enum wl_fw_status {
+ WL_FW_LOADING_DONE,
+ WL_NVRAM_LOADING_DONE
+};
+
+enum wl_management_type {
+ WL_BEACON = 0x1,
+ WL_PROBE_RESP = 0x2,
+ WL_ASSOC_RESP = 0x4
+};
+
+enum wl_handler_del_type {
+ WL_HANDLER_NOTUSE,
+ WL_HANDLER_DEL,
+ WL_HANDLER_MAINTAIN,
+ WL_HANDLER_PEND
+};
+
+/* beacon / probe_response */
+struct beacon_proberesp {
+ __le64 timestamp;
+ __le16 beacon_int;
+ __le16 capab_info;
+ u8 variable[0];
+} __attribute__ ((packed));
+
+/* driver configuration */
+struct wl_conf {
+ u32 frag_threshold;
+ u32 rts_threshold;
+ u32 retry_short;
+ u32 retry_long;
+ s32 tx_power;
+ struct ieee80211_channel channel;
+};
+
+typedef s32(*EVENT_HANDLER) (struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+
+/* bss inform structure for cfg80211 interface */
+struct wl_cfg80211_bss_info {
+ u16 band;
+ u16 channel;
+ s16 rssi;
+ u16 frame_len;
+ u8 frame_buf[1];
+};
+
+/* basic structure of scan request */
+struct wl_scan_req {
+ struct wlc_ssid ssid;
+};
+
+/* basic structure of information element */
+struct wl_ie {
+ u16 offset;
+ u8 buf[WL_TLV_INFO_MAX];
+};
+
+/* event queue for cfg80211 main event */
+struct wl_event_q {
+ struct list_head eq_list;
+ u32 etype;
+ wl_event_msg_t emsg;
+ s8 edata[1];
+};
+
+/* security information with currently associated ap */
+struct wl_security {
+ u32 wpa_versions;
+ u32 auth_type;
+ u32 cipher_pairwise;
+ u32 cipher_group;
+ u32 wpa_auth;
+ u32 auth_assoc_res_status;
+};
+
+/* ibss information for currently joined ibss network */
+struct wl_ibss {
+ u8 beacon_interval; /* in millisecond */
+ u8 atim; /* in millisecond */
+ s8 join_only;
+ u8 band;
+ u8 channel;
+};
+
+typedef struct wl_bss_vndr_ies {
+ u8 probe_req_ie[VNDR_IES_BUF_LEN];
+ u8 probe_res_ie[VNDR_IES_MAX_BUF_LEN];
+ u8 assoc_req_ie[VNDR_IES_BUF_LEN];
+ u8 assoc_res_ie[VNDR_IES_BUF_LEN];
+ u8 beacon_ie[VNDR_IES_MAX_BUF_LEN];
+ u32 probe_req_ie_len;
+ u32 probe_res_ie_len;
+ u32 assoc_req_ie_len;
+ u32 assoc_res_ie_len;
+ u32 beacon_ie_len;
+} wl_bss_vndr_ies_t;
+
+typedef struct wl_cfgbss {
+ u8 *wpa_ie;
+ u8 *rsn_ie;
+ u8 *wps_ie;
+ bool security_mode;
+ struct wl_bss_vndr_ies ies; /* Common for STA, P2P GC, GO, AP, P2P Disc Interface */
+} wl_cfgbss_t;
+
+/* cfg driver profile */
+struct wl_profile {
+ u32 mode;
+ s32 band;
+ u32 channel;
+ struct wlc_ssid ssid;
+ struct wl_security sec;
+ struct wl_ibss ibss;
+ u8 bssid[ETHER_ADDR_LEN];
+ u16 beacon_interval;
+ u8 dtim_period;
+ bool active;
+};
+
+struct net_info {
+ struct net_device *ndev;
+ struct wireless_dev *wdev;
+ struct wl_profile profile;
+ s32 mode;
+ s32 roam_off;
+ unsigned long sme_state;
+ bool pm_restore;
+ bool pm_block;
+ s32 pm;
+ s32 bssidx;
+ wl_cfgbss_t bss;
+ struct list_head list; /* list of all net_info structure */
+};
+
+#ifdef DHD_MAX_IFS
+#define WL_MAX_IFS DHD_MAX_IFS
+#else
+#define WL_MAX_IFS 16
+#endif
+
+/* association inform */
+#define MAX_REQ_LINE 1024
+struct wl_connect_info {
+ u8 req_ie[MAX_REQ_LINE];
+ s32 req_ie_len;
+ u8 resp_ie[MAX_REQ_LINE];
+ s32 resp_ie_len;
+};
+
+/* firmware /nvram downloading controller */
+struct wl_fw_ctrl {
+ const struct firmware *fw_entry;
+ unsigned long status;
+ u32 ptr;
+ s8 fw_name[WL_FILE_NAME_MAX];
+ s8 nvram_name[WL_FILE_NAME_MAX];
+};
+
+/* assoc ie length */
+struct wl_assoc_ielen {
+ u32 req_len;
+ u32 resp_len;
+};
+
+/* wpa2 pmk list */
+struct wl_pmk_list {
+ pmkid_list_t pmkids;
+ pmkid_t foo[MAXPMKID - 1];
+};
+
+
+#define ESCAN_BUF_SIZE (64 * 1024)
+
+struct escan_info {
+ u32 escan_state;
+#ifdef STATIC_WL_PRIV_STRUCT
+#ifndef CONFIG_DHD_USE_STATIC_BUF
+#error STATIC_WL_PRIV_STRUCT should be used with CONFIG_DHD_USE_STATIC_BUF
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
+ u8 *escan_buf;
+#else
+ u8 escan_buf[ESCAN_BUF_SIZE];
+#endif /* STATIC_WL_PRIV_STRUCT */
+ struct wiphy *wiphy;
+ struct net_device *ndev;
+};
+
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+#define BUF_OVERFLOW_MGMT_COUNT 3
+typedef struct {
+ int RSSI;
+ int length;
+ struct ether_addr BSSID;
+} removal_element_t;
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
+
+struct ap_info {
+/* Structure to hold WPS, WPA IEs for a AP */
+ u8 probe_res_ie[VNDR_IES_MAX_BUF_LEN];
+ u8 beacon_ie[VNDR_IES_MAX_BUF_LEN];
+ u8 assoc_res_ie[VNDR_IES_MAX_BUF_LEN];
+ u32 probe_res_ie_len;
+ u32 beacon_ie_len;
+ u32 assoc_res_ie_len;
+ u8 *wpa_ie;
+ u8 *rsn_ie;
+ u8 *wps_ie;
+ bool security_mode;
+};
+
+struct sta_info {
+ /* Structure to hold WPS IE for a STA */
+ u8 probe_req_ie[VNDR_IES_BUF_LEN];
+ u8 assoc_req_ie[VNDR_IES_BUF_LEN];
+ u32 probe_req_ie_len;
+ u32 assoc_req_ie_len;
+};
+
+struct afx_hdl {
+ wl_af_params_t *pending_tx_act_frm;
+ struct ether_addr tx_dst_addr;
+ struct net_device *dev;
+ struct work_struct work;
+ u32 bssidx;
+ u32 retry;
+ s32 peer_chan;
+ s32 peer_listen_chan; /* search channel: configured by upper layer */
+ s32 my_listen_chan; /* listen chanel: extract it from prb req or gon req */
+ bool is_listen;
+ bool ack_recv;
+ bool is_active;
+};
+
+struct parsed_ies {
+ wpa_ie_fixed_t *wps_ie;
+ u32 wps_ie_len;
+ wpa_ie_fixed_t *wpa_ie;
+ u32 wpa_ie_len;
+ bcm_tlv_t *wpa2_ie;
+ u32 wpa2_ie_len;
+};
+
+
+#ifdef WL11U
+/* Max length of Interworking element */
+#define IW_IES_MAX_BUF_LEN 9
+#endif
+#define MAX_EVENT_BUF_NUM 16
+typedef struct wl_eventmsg_buf {
+ u16 num;
+ struct {
+ u16 type;
+ bool set;
+ } event [MAX_EVENT_BUF_NUM];
+} wl_eventmsg_buf_t;
+
+typedef struct wl_if_event_info {
+ bool valid;
+ int ifidx;
+ int bssidx;
+ uint8 mac[ETHER_ADDR_LEN];
+ char name[IFNAMSIZ+1];
+} wl_if_event_info;
+
+/* private data of cfg80211 interface */
+struct bcm_cfg80211 {
+ struct wireless_dev *wdev; /* representing cfg cfg80211 device */
+
+ struct wireless_dev *p2p_wdev; /* representing cfg cfg80211 device for P2P */
+ struct net_device *p2p_net; /* reference to p2p0 interface */
+
+ struct wl_conf *conf;
+ struct cfg80211_scan_request *scan_request; /* scan request object */
+ EVENT_HANDLER evt_handler[WLC_E_LAST];
+ struct list_head eq_list; /* used for event queue */
+ struct list_head net_list; /* used for struct net_info */
+ spinlock_t net_list_sync; /* to protect scan status (and others if needed) */
+ spinlock_t eq_lock; /* for event queue synchronization */
+ spinlock_t cfgdrv_lock; /* to protect scan status (and others if needed) */
+ struct completion act_frm_scan;
+ struct completion iface_disable;
+ struct completion wait_next_af;
+ struct mutex usr_sync; /* maily for up/down synchronization */
+ struct wl_scan_results *bss_list;
+ struct wl_scan_results *scan_results;
+
+ /* scan request object for internal purpose */
+ struct wl_scan_req *scan_req_int;
+ /* information element object for internal purpose */
+#if defined(STATIC_WL_PRIV_STRUCT)
+ struct wl_ie *ie;
+#else
+ struct wl_ie ie;
+#endif
+
+ /* association information container */
+#if defined(STATIC_WL_PRIV_STRUCT)
+ struct wl_connect_info *conn_info;
+#else
+ struct wl_connect_info conn_info;
+#endif
+#ifdef DEBUGFS_CFG80211
+ struct dentry *debugfs;
+#endif /* DEBUGFS_CFG80211 */
+ struct wl_pmk_list *pmk_list; /* wpa2 pmk list */
+ tsk_ctl_t event_tsk; /* task of main event handler thread */
+ void *pub;
+ u32 iface_cnt;
+ u32 channel; /* current channel */
+ u32 af_sent_channel; /* channel action frame is sent */
+ /* next af subtype to cancel the remained dwell time in rx process */
+ u8 next_af_subtype;
+#ifdef WL_CFG80211_SYNC_GON
+ ulong af_tx_sent_jiffies;
+#endif /* WL_CFG80211_SYNC_GON */
+ struct escan_info escan_info; /* escan information */
+ bool active_scan; /* current scan mode */
+ bool ibss_starter; /* indicates this sta is ibss starter */
+ bool link_up; /* link/connection up flag */
+
+ /* indicate whether chip to support power save mode */
+ bool pwr_save;
+ bool roam_on; /* on/off switch for self-roaming */
+ bool scan_tried; /* indicates if first scan attempted */
+ bool wlfc_on;
+ bool vsdb_mode;
+ bool roamoff_on_concurrent;
+ u8 *ioctl_buf; /* ioctl buffer */
+ struct mutex ioctl_buf_sync;
+ u8 *escan_ioctl_buf;
+ u8 *extra_buf; /* maily to grab assoc information */
+ struct dentry *debugfsdir;
+ struct rfkill *rfkill;
+ bool rf_blocked;
+ struct ieee80211_channel remain_on_chan;
+ enum nl80211_channel_type remain_on_chan_type;
+ u64 send_action_id;
+ u64 last_roc_id;
+ wait_queue_head_t netif_change_event;
+ wl_if_event_info if_event_info;
+ struct completion send_af_done;
+ struct afx_hdl *afx_hdl;
+ struct p2p_info *p2p;
+ bool p2p_supported;
+ void *btcoex_info;
+ struct timer_list scan_timeout; /* Timer for catch scan event timeout */
+ s32(*state_notifier) (struct bcm_cfg80211 *cfg,
+ struct net_info *_net_info, enum wl_status state, bool set);
+ unsigned long interrested_state;
+ wlc_ssid_t hostapd_ssid;
+#ifdef WL11U
+ bool wl11u;
+ u8 iw_ie[IW_IES_MAX_BUF_LEN];
+ u32 iw_ie_len;
+#endif /* WL11U */
+ bool sched_scan_running; /* scheduled scan req status */
+#ifdef WL_SCHED_SCAN
+ struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */
+#endif /* WL_SCHED_SCAN */
+ bool scan_suppressed;
+ struct timer_list scan_supp_timer;
+ struct work_struct wlan_work;
+ struct mutex event_sync; /* maily for up/down synchronization */
+ bool disable_roam_event;
+ bool pm_enable_work_on;
+ struct delayed_work pm_enable_work;
+ vndr_ie_setbuf_t *ibss_vsie; /* keep the VSIE for IBSS */
+ int ibss_vsie_len;
+#ifdef WL_RELMCAST
+ u32 rmc_event_pid;
+ u32 rmc_event_seq;
+#endif /* WL_RELMCAST */
+ bool roam_offload;
+ bcm_struct_cfgdev *bss_cfgdev; /* For DUAL STA/STA+AP */
+ s32 cfgdev_bssidx;
+ bool bss_pending_op; /* indicate where there is a pending IF operation */
+#ifdef WLTDLS
+ u8 *tdls_mgmt_frame;
+ u32 tdls_mgmt_frame_len;
+ s32 tdls_mgmt_freq;
+#endif /* WLTDLS */
+ bool nan_running;
+ bool need_wait_afrx;
+ struct ether_addr last_roamed_addr;
+};
+
+
+static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss)
+{
+ return bss = bss ?
+ (struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info;
+}
+
+static inline void
+wl_probe_wdev_all(struct bcm_cfg80211 *cfg)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+ int idx = 0;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ WL_ERR(("%s: net_list[%d] bssidx: %d, "
+ "ndev: %p, wdev: %p \n", __FUNCTION__,
+ idx++, _net_info->bssidx,
+ _net_info->ndev, _net_info->wdev));
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return;
+}
+
+static inline struct net_info *
+wl_get_netinfo_by_bssidx(struct bcm_cfg80211 *cfg, s32 bssidx)
+{
+ struct net_info *_net_info, *next, *info = NULL;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ if ((bssidx >= 0) && (_net_info->bssidx == bssidx)) {
+ info = _net_info;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return info;
+}
+
+static inline void
+wl_dealloc_netinfo_by_wdev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+
+#ifdef DHD_IFDEBUG
+ WL_ERR(("dealloc_netinfo enter wdev=%p \n", wdev));
+#endif
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ if (wdev && (_net_info->wdev == wdev)) {
+ wl_cfgbss_t *bss = &_net_info->bss;
+
+ kfree(bss->wpa_ie);
+ bss->wpa_ie = NULL;
+ kfree(bss->rsn_ie);
+ bss->rsn_ie = NULL;
+ kfree(bss->wps_ie);
+ bss->wps_ie = NULL;
+ list_del(&_net_info->list);
+ cfg->iface_cnt--;
+ kfree(_net_info);
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+#ifdef DHD_IFDEBUG
+ WL_ERR(("dealloc_netinfo exit iface_cnt=%d \n", cfg->iface_cnt));
+#endif
+}
+
+static inline s32
+wl_alloc_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ struct wireless_dev * wdev, s32 mode, bool pm_block, u8 bssidx)
+{
+ struct net_info *_net_info;
+ s32 err = 0;
+ unsigned long int flags;
+
+#ifdef DHD_IFDEBUG
+ WL_ERR(("alloc_netinfo enter bssidx=%d wdev=%p ndev=%p\n", bssidx, wdev, ndev));
+#endif
+ /* Check whether there is any duplicate entry for the
+ * same bssidx *
+ */
+ if ((_net_info = wl_get_netinfo_by_bssidx(cfg, bssidx))) {
+ /* We have a duplicate entry for the same bssidx
+ * already present which shouldn't have been the case.
+ * Attempt recovery.
+ */
+ WL_ERR(("Duplicate entry for bssidx=%d present\n", bssidx));
+ wl_probe_wdev_all(cfg);
+#ifdef DHD_DEBUG
+ ASSERT(0);
+#endif /* DHD_DEBUG */
+ WL_ERR(("Removing the Dup entry for bssidx=%d \n", bssidx));
+ wl_dealloc_netinfo_by_wdev(cfg, _net_info->wdev);
+ }
+ if (cfg->iface_cnt == IFACE_MAX_CNT) {
+ WL_ERR(("Max interfaces (%d) reached.\n", IFACE_MAX_CNT));
+ return -ENOMEM;
+ }
+ _net_info = kzalloc(sizeof(struct net_info), GFP_KERNEL);
+ if (!_net_info) {
+ WL_ERR(("Insufficient memory in the system.\n"));
+ err = -ENOMEM;
+ }
+ else {
+ _net_info->mode = mode;
+ _net_info->ndev = ndev;
+ _net_info->wdev = wdev;
+ _net_info->pm_restore = 0;
+ _net_info->pm = 0;
+ _net_info->pm_block = pm_block;
+ _net_info->roam_off = WL_INVALID;
+ _net_info->bssidx = bssidx;
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ cfg->iface_cnt++;
+ list_add(&_net_info->list, &cfg->net_list);
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ }
+ return err;
+}
+
+static inline void
+wl_delete_all_netinfo(struct bcm_cfg80211 *cfg)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ wl_cfgbss_t *bss = &_net_info->bss;
+
+ kfree(bss->wpa_ie);
+ bss->wpa_ie = NULL;
+ kfree(bss->rsn_ie);
+ bss->rsn_ie = NULL;
+ kfree(bss->wps_ie);
+ bss->wps_ie = NULL;
+ list_del(&_net_info->list);
+ if (_net_info->wdev)
+ kfree(_net_info->wdev);
+ kfree(_net_info);
+ }
+ cfg->iface_cnt = 0;
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+}
+static inline u32
+wl_get_status_all(struct bcm_cfg80211 *cfg, s32 status)
+
+{
+ struct net_info *_net_info, *next;
+ u32 cnt = 0;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ if (_net_info->ndev &&
+ test_bit(status, &_net_info->sme_state))
+ cnt++;
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return cnt;
+}
+static inline void
+wl_set_status_all(struct bcm_cfg80211 *cfg, s32 status, u32 op)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ switch (op) {
+ case 1:
+ return; /* set all status is not allowed */
+ case 2:
+ clear_bit(status, &_net_info->sme_state);
+ if (cfg->state_notifier &&
+ test_bit(status, &(cfg->interrested_state)))
+ cfg->state_notifier(cfg, _net_info, status, false);
+ break;
+ case 4:
+ return; /* change all status is not allowed */
+ default:
+ return; /* unknown operation */
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+}
+static inline void
+wl_set_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status,
+ struct net_device *ndev, u32 op)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev)) {
+ switch (op) {
+ case 1:
+ /*
+ * Release the spinlock before calling notifier. Else there
+ * will be nested calls
+ */
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ set_bit(status, &_net_info->sme_state);
+ if (cfg->state_notifier &&
+ test_bit(status, &(cfg->interrested_state)))
+ cfg->state_notifier(cfg, _net_info, status, true);
+ return;
+ case 2:
+ /*
+ * Release the spinlock before calling notifier. Else there
+ * will be nested calls
+ */
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ clear_bit(status, &_net_info->sme_state);
+ if (cfg->state_notifier &&
+ test_bit(status, &(cfg->interrested_state)))
+ cfg->state_notifier(cfg, _net_info, status, false);
+ return;
+ case 4:
+ change_bit(status, &_net_info->sme_state);
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+}
+
+static inline u32
+wl_get_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status,
+ struct net_device *ndev)
+{
+ struct net_info *_net_info, *next;
+ u32 stat = 0;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev)) {
+ stat = test_bit(status, &_net_info->sme_state);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return stat;
+}
+
+static inline wl_cfgbss_t *
+wl_get_cfgbss_by_wdev(struct bcm_cfg80211 *cfg,
+ struct wireless_dev *wdev)
+{
+ struct net_info *_net_info, *next;
+ wl_cfgbss_t *bss = NULL;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ if (wdev && (_net_info->wdev == wdev)) {
+ bss = &_net_info->bss;
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return bss;
+}
+
+static inline s32
+wl_get_mode_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ struct net_info *_net_info, *next;
+ s32 mode = -1;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev)) {
+ mode = _net_info->mode;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return mode;
+}
+
+
+static inline void
+wl_set_mode_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ s32 mode)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev))
+ _net_info->mode = mode;
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+}
+
+static inline struct wl_profile *
+wl_get_profile_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ struct net_info *_net_info, *next;
+ struct wl_profile *prof = NULL;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev)) {
+ prof = &_net_info->profile;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return prof;
+}
+
+static inline struct net_info *
+wl_get_netinfo_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ struct net_info *_net_info, *next, *info = NULL;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev)) {
+ info = _net_info;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return info;
+}
+
+static inline s32
+wl_get_bssidx_by_wdev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev)
+{
+ struct net_info *_net_info, *next;
+ s32 bssidx = -1;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ if (_net_info->wdev && (_net_info->wdev == wdev)) {
+ bssidx = _net_info->bssidx;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return bssidx;
+}
+
+static inline struct wireless_dev *
+wl_get_wdev_by_bssidx(struct bcm_cfg80211 *cfg, s32 bssidx)
+{
+ struct net_info *_net_info, *next;
+ struct wireless_dev *wdev = NULL;
+ unsigned long int flags;
+
+ if (bssidx < 0)
+ return NULL;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ if (_net_info->bssidx == bssidx) {
+ wdev = _net_info->wdev;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return wdev;
+}
+
+#define is_p2p_group_iface(wdev) (((wdev->iftype == NL80211_IFTYPE_P2P_GO) || \
+ (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) ? 1 : 0)
+#define bcmcfg_to_wiphy(cfg) (cfg->wdev->wiphy)
+#define bcmcfg_to_prmry_ndev(cfg) (cfg->wdev->netdev)
+#define bcmcfg_to_prmry_wdev(cfg) (cfg->wdev)
+#define bcmcfg_to_p2p_wdev(cfg) (cfg->p2p_wdev)
+#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr))
+#define ndev_to_wdev(ndev) (ndev->ieee80211_ptr)
+#define wdev_to_ndev(wdev) (wdev->netdev)
+
+#if defined(WL_ENABLE_P2P_IF)
+#define ndev_to_wlc_ndev(ndev, cfg) ((ndev == cfg->p2p_net) ? \
+ bcmcfg_to_prmry_ndev(cfg) : ndev)
+#else
+#define ndev_to_wlc_ndev(ndev, cfg) (ndev)
+#endif /* WL_ENABLE_P2P_IF */
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+#define wdev_to_wlc_ndev(wdev, cfg) \
+ ((wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) ? \
+ bcmcfg_to_prmry_ndev(cfg) : wdev_to_ndev(wdev))
+#define cfgdev_to_wlc_ndev(cfgdev, cfg) (cfgdev ? wdev_to_wlc_ndev(cfgdev, cfg) : NULL)
+#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) bcmcfg_to_prmry_wdev(cfg)
+#elif defined(WL_ENABLE_P2P_IF)
+#define cfgdev_to_wlc_ndev(cfgdev, cfg) ndev_to_wlc_ndev(cfgdev, cfg)
+#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) bcmcfg_to_prmry_ndev(cfg)
+#else
+#define cfgdev_to_wlc_ndev(cfgdev, cfg) (cfgdev)
+#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) (cfgdev)
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+#define ndev_to_cfgdev(ndev) ndev_to_wdev(ndev)
+#define discover_cfgdev(cfgdev, cfg) (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE)
+#else
+#define ndev_to_cfgdev(ndev) (ndev)
+#define discover_cfgdev(cfgdev, cfg) (cfgdev == cfg->p2p_net)
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+#define scan_req_match(cfg) (((cfg) && (cfg->scan_request) && \
+ (cfg->scan_request->wdev == cfg->p2p_wdev)) ? true : false)
+#elif defined(WL_ENABLE_P2P_IF)
+#define scan_req_match(cfg) (((cfg) && (cfg->scan_request) && \
+ (cfg->scan_request->dev == cfg->p2p_net)) ? true : false)
+#else
+#define scan_req_match(cfg) (((cfg) && p2p_is_on(cfg) && p2p_scan(cfg)) ? \
+ true : false)
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
+#define scan_req_iftype(req) (req->dev->ieee80211_ptr->iftype)
+#else
+#define scan_req_iftype(req) (req->wdev->iftype)
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) */
+
+#define wl_to_sr(w) (w->scan_req_int)
+#if defined(STATIC_WL_PRIV_STRUCT)
+#define wl_to_ie(w) (w->ie)
+#define wl_to_conn(w) (w->conn_info)
+#else
+#define wl_to_ie(w) (&w->ie)
+#define wl_to_conn(w) (&w->conn_info)
+#endif
+#define wiphy_from_scan(w) (w->escan_info.wiphy)
+#define wl_get_drv_status_all(cfg, stat) \
+ (wl_get_status_all(cfg, WL_STATUS_ ## stat))
+#define wl_get_drv_status(cfg, stat, ndev) \
+ (wl_get_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev))
+#define wl_set_drv_status(cfg, stat, ndev) \
+ (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 1))
+#define wl_clr_drv_status(cfg, stat, ndev) \
+ (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 2))
+#define wl_clr_drv_status_all(cfg, stat) \
+ (wl_set_status_all(cfg, WL_STATUS_ ## stat, 2))
+#define wl_chg_drv_status(cfg, stat, ndev) \
+ (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 4))
+
+#define for_each_bss(list, bss, __i) \
+ for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss))
+
+#define for_each_ndev(cfg, iter, next) \
+ list_for_each_entry_safe(iter, next, &cfg->net_list, list)
+
+
+/* In case of WPS from wpa_supplicant, pairwise siute and group suite is 0.
+ * In addtion to that, wpa_version is WPA_VERSION_1
+ */
+#define is_wps_conn(_sme) \
+ ((wl_cfgp2p_find_wpsie((u8 *)_sme->ie, _sme->ie_len) != NULL) && \
+ (!_sme->crypto.n_ciphers_pairwise) && \
+ (!_sme->crypto.cipher_group))
+extern s32 wl_cfg80211_attach(struct net_device *ndev, void *context);
+extern s32 wl_cfg80211_attach_post(struct net_device *ndev);
+extern void wl_cfg80211_detach(void *para);
+
+extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e,
+ void *data);
+void wl_cfg80211_set_parent_dev(void *dev);
+struct device *wl_cfg80211_get_parent_dev(void);
+
+/* clear IEs */
+extern s32 wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 *cfg);
+extern s32 wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 *cfg, s32 bssidx);
+
+extern s32 wl_cfg80211_up(void *para);
+extern s32 wl_cfg80211_down(void *para);
+extern s32 wl_cfg80211_notify_ifadd(int ifidx, char *name, uint8 *mac, uint8 bssidx);
+extern s32 wl_cfg80211_notify_ifdel(int ifidx, char *name, uint8 *mac, uint8 bssidx);
+extern s32 wl_cfg80211_notify_ifchange(int ifidx, char *name, uint8 *mac, uint8 bssidx);
+extern struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, char *name,
+ uint8 *mac, uint8 bssidx, char *dngl_name);
+extern int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev);
+extern int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev);
+extern int wl_cfg80211_scan_stop(bcm_struct_cfgdev *cfgdev);
+extern bool wl_cfg80211_is_vsdb_mode(void);
+extern void* wl_cfg80211_get_dhdp(void);
+extern bool wl_cfg80211_is_p2p_active(void);
+extern void wl_cfg80211_dbg_level(u32 level);
+extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
+extern s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len);
+extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len);
+extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
+ enum wl_management_type type);
+extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len);
+
+/* btcoex functions */
+void* wl_cfg80211_btcoex_init(struct net_device *ndev);
+void wl_cfg80211_btcoex_deinit(void);
+
+#ifdef WL_SUPPORT_AUTO_CHANNEL
+#define CHANSPEC_BUF_SIZE 1024
+#define CHAN_SEL_IOCTL_DELAY 300
+#define CHAN_SEL_RETRY_COUNT 15
+#define CHANNEL_IS_RADAR(channel) (((channel & WL_CHAN_RADAR) || \
+ (channel & WL_CHAN_PASSIVE)) ? true : false)
+#define CHANNEL_IS_2G(channel) (((channel >= 1) && (channel <= 14)) ? \
+ true : false)
+#define CHANNEL_IS_5G(channel) (((channel >= 36) && (channel <= 165)) ? \
+ true : false)
+extern s32 wl_cfg80211_get_best_channels(struct net_device *dev, char* command,
+ int total_len);
+#endif /* WL_SUPPORT_AUTO_CHANNEL */
+
+extern int wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n);
+extern int wl_cfg80211_hex_str_to_bin(unsigned char *data, int dlen, char *str);
+extern int wl_cfg80211_hang(struct net_device *dev, u16 reason);
+extern s32 wl_mode_to_nl80211_iftype(s32 mode);
+int wl_cfg80211_do_driver_init(struct net_device *net);
+void wl_cfg80211_enable_trace(bool set, u32 level);
+extern s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify);
+extern s32 wl_cfg80211_if_is_group_owner(void);
+extern chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec);
+extern chanspec_t wl_ch_host_to_driver(u16 channel);
+extern s32 wl_set_tx_power(struct net_device *dev,
+ enum nl80211_tx_power_setting type, s32 dbm);
+extern s32 wl_get_tx_power(struct net_device *dev, s32 *dbm);
+extern s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add);
+extern void wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev);
+extern void wl_cfg80211_add_to_eventbuffer(wl_eventmsg_buf_t *ev, u16 event, bool set);
+extern s32 wl_cfg80211_apply_eventbuffer(struct net_device *ndev,
+ struct bcm_cfg80211 *cfg, wl_eventmsg_buf_t *ev);
+extern void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac);
+extern void wl_cfg80211_update_power_mode(struct net_device *dev);
+extern void wl_terminate_event_handler(void);
+extern s32
+wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen);
+extern s32
+wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen);
+extern int
+wl_cfg80211_set_spect(struct net_device *dev, int spect);
+extern int
+wl_cfg80211_get_sta_channel(struct net_device *dev);
+
+#define SCAN_BUF_CNT 2
+#define SCAN_BUF_NEXT 1
+#define WL_SCANTYPE_LEGACY 0x1
+#define WL_SCANTYPE_P2P 0x2
+#define wl_escan_set_sync_id(a, b) ((a) = htod16(0x1234))
+#define wl_escan_set_type(a, b)
+#define wl_escan_get_buf(a, b) ((wl_scan_results_t *) (a)->escan_info.escan_buf)
+#define wl_escan_check_sync_id(a, b, c) 0
+#define wl_escan_print_sync_id(a, b, c)
+#define wl_escan_increment_sync_id(a, b)
+#define wl_escan_init_sync_id(a)
+
+extern void wl_cfg80211_ibss_vsie_set_buffer(vndr_ie_setbuf_t *ibss_vsie, int ibss_vsie_len);
+extern s32 wl_cfg80211_ibss_vsie_delete(struct net_device *dev);
+#ifdef WL_RELMCAST
+extern void wl_cfg80211_set_rmc_pid(int pid);
+#endif /* WL_RELMCAST */
+
+extern int wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg,
+ struct net_device *ndev, s32 bssidx, s32 pktflag,
+ const u8 *vndr_ie, u32 vndr_ie_len);
+
+/* Action frame specific functions */
+extern u8 wl_get_action_category(void *frame, u32 frame_len);
+extern int wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action);
+
+#ifdef WL_SUPPORT_ACS
+#define ACS_MSRMNT_DELAY 1000 /* dump_obss delay in ms */
+#define IOCTL_RETRY_COUNT 5
+#define CHAN_NOISE_DUMMY -80
+#define OBSS_TOKEN_IDX 15
+#define IBSS_TOKEN_IDX 15
+#define TX_TOKEN_IDX 14
+#define CTG_TOKEN_IDX 13
+#define PKT_TOKEN_IDX 15
+#define IDLE_TOKEN_IDX 12
+#endif /* WL_SUPPORT_ACS */
+extern int wl_cfg80211_enable_roam_offload(struct net_device *dev, bool enable);
+#ifdef WL_NAN
+extern int wl_cfg80211_nan_cmd_handler(struct net_device *ndev, char *cmd,
+ int cmd_len);
+#endif /* WL_NAN */
+
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+struct net_device *wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg);
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+
+extern int wl_cfg80211_get_ioctl_version(void);
+
+#if defined(WL_VIRTUAL_APSTA)
+extern int wl_cfg80211_interface_create(struct net_device *dev, char *name);
+extern int wl_cfg80211_interface_delete(struct net_device *dev, char *name);
+#endif /* defined (WL_VIRTUAL_APSTA) */
+
+#ifdef WL_CFG80211_P2P_DEV_IF
+extern void wl_cfg80211_del_p2p_wdev(void);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+#endif /* _wl_cfg80211_h_ */
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg_btcoex.c b/drivers/net/wireless/bcmdhd/wl_cfg_btcoex.c
new file mode 100644
index 000000000000..886c2c49dacc
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_cfg_btcoex.c
@@ -0,0 +1,545 @@
+/*
+ * Linux cfg80211 driver - Dongle Host Driver (DHD) related
+ *
+ * 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: wl_cfg_btcoex.c 638311 2016-05-17 09:20:23Z $
+ */
+
+#include <net/rtnetlink.h>
+
+#include <bcmutils.h>
+#include <wldev_common.h>
+#include <wl_cfg80211.h>
+#include <dhd_cfg80211.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhdioctl.h>
+#include <wlioctl.h>
+
+#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
+
+struct btcoex_info {
+ struct timer_list timer;
+ u32 timer_ms;
+ u32 timer_on;
+ u32 ts_dhcp_start; /* ms ts ecord time stats */
+ u32 ts_dhcp_ok; /* ms ts ecord time stats */
+ bool dhcp_done; /* flag, indicates that host done with
+ * dhcp before t1/t2 expiration
+ */
+ s32 bt_state;
+ struct work_struct work;
+ struct net_device *dev;
+};
+
+static struct btcoex_info *btcoex_info_loc = NULL;
+
+/* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */
+
+/* use New SCO/eSCO smart YG suppression */
+#define BT_DHCP_eSCO_FIX
+/* this flag boost wifi pkt priority to max, caution: -not fair to sco */
+#define BT_DHCP_USE_FLAGS
+/* T1 start SCO/ESCo priority suppression */
+#define BT_DHCP_OPPR_WIN_TIME 2500
+/* T2 turn off SCO/SCO supperesion is (timeout) */
+#define BT_DHCP_FLAG_FORCE_TIME 5500
+
+enum wl_cfg80211_btcoex_status {
+ BT_DHCP_IDLE,
+ BT_DHCP_START,
+ BT_DHCP_OPPR_WIN,
+ BT_DHCP_FLAG_FORCE_TIMEOUT
+};
+
+/*
+ * get named driver variable to uint register value and return error indication
+ * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, &reg_value)
+ */
+static int
+dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
+ uint reg, int *retval)
+{
+ union {
+ char buf[WLC_IOCTL_SMLEN];
+ int val;
+ } var;
+ int error;
+
+ bcm_mkiovar(name, (char *)(&reg), sizeof(reg),
+ (char *)(&var), sizeof(var.buf));
+ error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false);
+
+ *retval = dtoh32(var.val);
+ return (error);
+}
+
+static int
+dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
+{
+ char ioctlbuf_local[WLC_IOCTL_SMLEN];
+
+ bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local));
+
+ return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true));
+}
+/*
+get named driver variable to uint register value and return error indication
+calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
+*/
+static int
+dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
+{
+ char reg_addr[8];
+
+ memset(reg_addr, 0, sizeof(reg_addr));
+ memcpy((char *)&reg_addr[0], (char *)addr, 4);
+ memcpy((char *)&reg_addr[4], (char *)val, 4);
+
+ return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
+}
+
+static bool btcoex_is_sco_active(struct net_device *dev)
+{
+ int ioc_res = 0;
+ bool res = FALSE;
+ int sco_id_cnt = 0;
+ int param27;
+ int i;
+
+ for (i = 0; i < 12; i++) {
+
+ ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
+
+ WL_TRACE(("sample[%d], btc params: 27:%x\n", i, param27));
+
+ if (ioc_res < 0) {
+ WL_ERR(("ioc read btc params error\n"));
+ break;
+ }
+
+ if ((param27 & 0x6) == 2) { /* count both sco & esco */
+ sco_id_cnt++;
+ }
+
+ if (sco_id_cnt > 2) {
+ WL_TRACE(("sco/esco detected, pkt id_cnt:%d samples:%d\n",
+ sco_id_cnt, i));
+ res = TRUE;
+ break;
+ }
+
+ OSL_SLEEP(5);
+ }
+
+ return res;
+}
+
+#if defined(BT_DHCP_eSCO_FIX)
+/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
+static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
+{
+ static bool saved_status = FALSE;
+
+ char buf_reg50va_dhcp_on[8] =
+ { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
+ char buf_reg51va_dhcp_on[8] =
+ { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ char buf_reg64va_dhcp_on[8] =
+ { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ char buf_reg65va_dhcp_on[8] =
+ { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ char buf_reg71va_dhcp_on[8] =
+ { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ uint32 regaddr;
+ static uint32 saved_reg50;
+ static uint32 saved_reg51;
+ static uint32 saved_reg64;
+ static uint32 saved_reg65;
+ static uint32 saved_reg71;
+
+ if (trump_sco) {
+ /* this should reduce eSCO agressive retransmit
+ * w/o breaking it
+ */
+
+ /* 1st save current */
+ WL_TRACE(("Do new SCO/eSCO coex algo {save &"
+ "override}\n"));
+ if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
+ saved_status = TRUE;
+ WL_TRACE(("saved bt_params[50,51,64,65,71]:"
+ "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ saved_reg50, saved_reg51,
+ saved_reg64, saved_reg65, saved_reg71));
+ } else {
+ WL_ERR((":%s: save btc_params failed\n",
+ __FUNCTION__));
+ saved_status = FALSE;
+ return -1;
+ }
+
+ WL_TRACE(("override with [50,51,64,65,71]:"
+ "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ *(u32 *)(buf_reg50va_dhcp_on+4),
+ *(u32 *)(buf_reg51va_dhcp_on+4),
+ *(u32 *)(buf_reg64va_dhcp_on+4),
+ *(u32 *)(buf_reg65va_dhcp_on+4),
+ *(u32 *)(buf_reg71va_dhcp_on+4)));
+
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg50va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg51va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg64va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg65va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg71va_dhcp_on[0], 8);
+
+ saved_status = TRUE;
+ } else if (saved_status) {
+ /* restore previously saved bt params */
+ WL_TRACE(("Do new SCO/eSCO coex algo {save &"
+ "override}\n"));
+
+ regaddr = 50;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg50);
+ regaddr = 51;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg51);
+ regaddr = 64;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg64);
+ regaddr = 65;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg65);
+ regaddr = 71;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg71);
+
+ WL_TRACE(("restore bt_params[50,51,64,65,71]:"
+ "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ saved_reg50, saved_reg51, saved_reg64,
+ saved_reg65, saved_reg71));
+
+ saved_status = FALSE;
+ } else {
+ WL_ERR((":%s att to restore not saved BTCOEX params\n",
+ __FUNCTION__));
+ return -1;
+ }
+ return 0;
+}
+#endif /* BT_DHCP_eSCO_FIX */
+
+static void
+wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
+{
+#if defined(BT_DHCP_USE_FLAGS)
+ char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
+ char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
+#endif
+
+
+#if defined(BT_DHCP_eSCO_FIX)
+ /* set = 1, save & turn on 0 - off & restore prev settings */
+ set_btc_esco_params(dev, set);
+#endif
+
+#if defined(BT_DHCP_USE_FLAGS)
+ WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
+ if (set == TRUE)
+ /* Forcing bt_flag7 */
+ dev_wlc_bufvar_set(dev, "btc_flags",
+ (char *)&buf_flag7_dhcp_on[0],
+ sizeof(buf_flag7_dhcp_on));
+ else
+ /* Restoring default bt flag7 */
+ dev_wlc_bufvar_set(dev, "btc_flags",
+ (char *)&buf_flag7_default[0],
+ sizeof(buf_flag7_default));
+#endif
+}
+
+static void wl_cfg80211_bt_timerfunc(ulong data)
+{
+ struct btcoex_info *bt_local = (struct btcoex_info *)data;
+ WL_TRACE(("Enter\n"));
+ bt_local->timer_on = 0;
+ schedule_work(&bt_local->work);
+}
+
+static void wl_cfg80211_bt_handler(struct work_struct *work)
+{
+ struct btcoex_info *btcx_inf;
+
+ btcx_inf = container_of(work, struct btcoex_info, work);
+
+ if (btcx_inf->timer_on) {
+ btcx_inf->timer_on = 0;
+ del_timer_sync(&btcx_inf->timer);
+ }
+
+ switch (btcx_inf->bt_state) {
+ case BT_DHCP_START:
+ /* DHCP started
+ * provide OPPORTUNITY window to get DHCP address
+ */
+ WL_TRACE(("bt_dhcp stm: started \n"));
+
+ btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
+ mod_timer(&btcx_inf->timer,
+ jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME));
+ btcx_inf->timer_on = 1;
+ break;
+
+ case BT_DHCP_OPPR_WIN:
+ if (btcx_inf->dhcp_done) {
+ WL_TRACE(("DHCP Done before T1 expiration\n"));
+ goto btc_coex_idle;
+ }
+
+ /* DHCP is not over yet, start lowering BT priority
+ * enforce btc_params + flags if necessary
+ */
+ WL_TRACE(("DHCP T1:%d expired\n", BT_DHCP_OPPR_WIN_TIME));
+ if (btcx_inf->dev)
+ wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
+ btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
+ mod_timer(&btcx_inf->timer,
+ jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME));
+ btcx_inf->timer_on = 1;
+ break;
+
+ case BT_DHCP_FLAG_FORCE_TIMEOUT:
+ if (btcx_inf->dhcp_done) {
+ WL_TRACE(("DHCP Done before T2 expiration\n"));
+ } else {
+ /* Noo dhcp during T1+T2, restore BT priority */
+ WL_TRACE(("DHCP wait interval T2:%d msec expired\n",
+ BT_DHCP_FLAG_FORCE_TIME));
+ }
+
+ /* Restoring default bt priority */
+ if (btcx_inf->dev)
+ wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
+btc_coex_idle:
+ btcx_inf->bt_state = BT_DHCP_IDLE;
+ btcx_inf->timer_on = 0;
+ break;
+
+ default:
+ WL_ERR(("error g_status=%d !!!\n", btcx_inf->bt_state));
+ if (btcx_inf->dev)
+ wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
+ btcx_inf->bt_state = BT_DHCP_IDLE;
+ btcx_inf->timer_on = 0;
+ break;
+ }
+
+ net_os_wake_unlock(btcx_inf->dev);
+}
+
+void* wl_cfg80211_btcoex_init(struct net_device *ndev)
+{
+ struct btcoex_info *btco_inf = NULL;
+
+ btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
+ if (!btco_inf)
+ return NULL;
+
+ btco_inf->bt_state = BT_DHCP_IDLE;
+ btco_inf->ts_dhcp_start = 0;
+ btco_inf->ts_dhcp_ok = 0;
+ /* Set up timer for BT */
+ btco_inf->timer_ms = 10;
+ init_timer(&btco_inf->timer);
+ btco_inf->timer.data = (ulong)btco_inf;
+ btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
+
+ btco_inf->dev = ndev;
+
+ INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
+
+ btcoex_info_loc = btco_inf;
+ return btco_inf;
+}
+
+void wl_cfg80211_btcoex_deinit()
+{
+ if (!btcoex_info_loc)
+ return;
+
+ if (btcoex_info_loc->timer_on) {
+ btcoex_info_loc->timer_on = 0;
+ del_timer_sync(&btcoex_info_loc->timer);
+ }
+
+ cancel_work_sync(&btcoex_info_loc->work);
+
+ kfree(btcoex_info_loc);
+}
+
+int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command)
+{
+
+ struct btcoex_info *btco_inf = btcoex_info_loc;
+ char powermode_val = 0;
+ char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
+ char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
+ char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
+
+ uint32 regaddr;
+ static uint32 saved_reg66;
+ static uint32 saved_reg41;
+ static uint32 saved_reg68;
+ static bool saved_status = FALSE;
+
+ char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
+
+ /* Figure out powermode 1 or o command */
+ strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1);
+
+ if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
+ WL_TRACE_HW4(("DHCP session starts\n"));
+
+
+#ifdef PKT_FILTER_SUPPORT
+ dhd->dhcp_in_progress = 1;
+
+ if (dhd->early_suspended) {
+ WL_TRACE_HW4(("DHCP in progressing , disable packet filter!!!\n"));
+ dhd_enable_packet_filter(0, dhd);
+ }
+#endif
+
+ /* Retrieve and saved orig regs value */
+ if ((saved_status == FALSE) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) {
+ saved_status = TRUE;
+ WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
+ saved_reg66, saved_reg41, saved_reg68));
+
+ /* Disable PM mode during dhpc session */
+
+ /* Disable PM mode during dhpc session */
+ /* Start BT timer only for SCO connection */
+ if (btcoex_is_sco_active(dev)) {
+ /* btc_params 66 */
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg66va_dhcp_on[0],
+ sizeof(buf_reg66va_dhcp_on));
+ /* btc_params 41 0x33 */
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg41va_dhcp_on[0],
+ sizeof(buf_reg41va_dhcp_on));
+ /* btc_params 68 0x190 */
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg68va_dhcp_on[0],
+ sizeof(buf_reg68va_dhcp_on));
+ saved_status = TRUE;
+
+ btco_inf->bt_state = BT_DHCP_START;
+ btco_inf->timer_on = 1;
+ mod_timer(&btco_inf->timer, btco_inf->timer.expires);
+ WL_TRACE(("enable BT DHCP Timer\n"));
+ }
+ }
+ else if (saved_status == TRUE) {
+ WL_ERR(("was called w/o DHCP OFF. Continue\n"));
+ }
+ }
+ else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
+
+
+
+#ifdef PKT_FILTER_SUPPORT
+ dhd->dhcp_in_progress = 0;
+ WL_TRACE_HW4(("DHCP is complete \n"));
+
+ /* Enable packet filtering */
+ if (dhd->early_suspended) {
+ WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n"));
+ dhd_enable_packet_filter(1, dhd);
+ }
+#endif /* PKT_FILTER_SUPPORT */
+
+ /* Restoring PM mode */
+
+ /* Stop any bt timer because DHCP session is done */
+ WL_TRACE(("disable BT DHCP Timer\n"));
+ if (btco_inf->timer_on) {
+ btco_inf->timer_on = 0;
+ del_timer_sync(&btco_inf->timer);
+
+ if (btco_inf->bt_state != BT_DHCP_IDLE) {
+ /* need to restore original btc flags & extra btc params */
+ WL_TRACE(("bt->bt_state:%d\n", btco_inf->bt_state));
+ /* wake up btcoex thread to restore btlags+params */
+ schedule_work(&btco_inf->work);
+ }
+ }
+
+ /* Restoring btc_flag paramter anyway */
+ if (saved_status == TRUE)
+ dev_wlc_bufvar_set(dev, "btc_flags",
+ (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
+
+ /* Restore original values */
+ if (saved_status == TRUE) {
+ regaddr = 66;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg66);
+ regaddr = 41;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg41);
+ regaddr = 68;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg68);
+
+ WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
+ saved_reg66, saved_reg41, saved_reg68));
+ }
+ saved_status = FALSE;
+
+ }
+ else {
+ WL_ERR(("Unkwown yet power setting, ignored\n"));
+ }
+
+ snprintf(command, 3, "OK");
+
+ return (strlen("OK"));
+}
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
new file mode 100644
index 000000000000..8c3787b97a24
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
@@ -0,0 +1,2539 @@
+/*
+ * Linux cfgp2p driver
+ *
+ * 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: wl_cfgp2p.c 662965 2016-11-24 03:53:15Z $
+ *
+ */
+#include <typedefs.h>
+#include <linuxver.h>
+#include <osl.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/if_arp.h>
+#include <asm/uaccess.h>
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <proto/ethernet.h>
+#include <proto/802.11.h>
+#include <net/rtnetlink.h>
+
+#include <wl_cfg80211.h>
+#include <wl_cfgp2p.h>
+#include <wldev_common.h>
+#include <wl_android.h>
+
+#if defined(P2PONEINT)
+#include <dngl_stats.h>
+#include <dhd.h>
+#endif
+
+static s8 scanparambuf[WLC_IOCTL_SMLEN];
+static bool
+wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
+
+static s32 wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ struct wireless_dev *wdev, bool notify);
+
+#ifdef P2PONEINT
+void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg);
+chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
+s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val);
+int wl_cfgp2p_if_open(struct net_device *net);
+int wl_cfgp2p_if_stop(struct net_device *net);
+#endif
+
+#if defined(WL_ENABLE_P2P_IF)
+static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev);
+static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd);
+static int wl_cfgp2p_if_open(struct net_device *net);
+static int wl_cfgp2p_if_stop(struct net_device *net);
+
+static const struct net_device_ops wl_cfgp2p_if_ops = {
+ .ndo_open = wl_cfgp2p_if_open,
+ .ndo_stop = wl_cfgp2p_if_stop,
+ .ndo_do_ioctl = wl_cfgp2p_do_ioctl,
+#ifndef P2PONEINT
+ .ndo_start_xmit = wl_cfgp2p_start_xmit,
+#endif
+};
+#endif /* WL_ENABLE_P2P_IF */
+
+
+bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len)
+{
+ wifi_p2p_pub_act_frame_t *pact_frm;
+
+ if (frame == NULL)
+ return false;
+ pact_frm = (wifi_p2p_pub_act_frame_t *)frame;
+ if (frame_len < sizeof(wifi_p2p_pub_act_frame_t) -1)
+ return false;
+
+ if (pact_frm->category == P2P_PUB_AF_CATEGORY &&
+ pact_frm->action == P2P_PUB_AF_ACTION &&
+ pact_frm->oui_type == P2P_VER &&
+ memcmp(pact_frm->oui, P2P_OUI, sizeof(pact_frm->oui)) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len)
+{
+ wifi_p2p_action_frame_t *act_frm;
+
+ if (frame == NULL)
+ return false;
+ act_frm = (wifi_p2p_action_frame_t *)frame;
+ if (frame_len < sizeof(wifi_p2p_action_frame_t) -1)
+ return false;
+
+ if (act_frm->category == P2P_AF_CATEGORY &&
+ act_frm->type == P2P_VER &&
+ memcmp(act_frm->OUI, P2P_OUI, DOT11_OUI_LEN) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+#define GAS_RESP_LEN 2
+#define DOUBLE_TLV_BODY_OFF 4
+#define GAS_RESP_OFFSET 4
+#define GAS_CRESP_OFFSET 5
+
+bool wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len)
+{
+ bcm_tlv_t *ie = (bcm_tlv_t *)data;
+ u8 *frame = NULL;
+ u16 id, flen;
+
+ /* Skipped first ANQP Element, if frame has anqp elemnt */
+ ie = bcm_parse_tlvs(ie, (int)len, DOT11_MNG_ADVERTISEMENT_ID);
+
+ if (ie == NULL)
+ return false;
+
+ frame = (uint8 *)ie + ie->len + TLV_HDR_LEN + GAS_RESP_LEN;
+ id = ((u16) (((frame)[1] << 8) | (frame)[0]));
+ flen = ((u16) (((frame)[3] << 8) | (frame)[2]));
+
+ /* If the contents match the OUI and the type */
+ if (flen >= WFA_OUI_LEN + 1 &&
+ id == P2PSD_GAS_NQP_INFOID &&
+ !bcmp(&frame[DOUBLE_TLV_BODY_OFF], (const uint8*)WFA_OUI, WFA_OUI_LEN) &&
+ subtype == frame[DOUBLE_TLV_BODY_OFF+WFA_OUI_LEN]) {
+ return true;
+ }
+
+ return false;
+}
+
+bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len)
+{
+
+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm;
+
+ if (frame == NULL)
+ return false;
+
+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame;
+ if (frame_len < (sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1))
+ return false;
+ if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)
+ return false;
+
+ if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ ||
+ sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP ||
+ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ ||
+ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP)
+ return true;
+ else
+ return false;
+}
+
+bool wl_cfgp2p_is_p2p_gas_action(void *frame, u32 frame_len)
+{
+
+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm;
+
+ if (frame == NULL)
+ return false;
+
+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame;
+ if (frame_len < (sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1))
+ return false;
+ if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)
+ return false;
+
+ if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ)
+ return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE,
+ (u8 *)sd_act_frm->query_data,
+ frame_len);
+ else
+ return false;
+}
+
+void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel)
+{
+ wifi_p2p_pub_act_frame_t *pact_frm;
+ wifi_p2p_action_frame_t *act_frm;
+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm;
+ if (!frame || frame_len <= 2)
+ return;
+
+ if (wl_cfgp2p_is_pub_action(frame, frame_len)) {
+ pact_frm = (wifi_p2p_pub_act_frame_t *)frame;
+ switch (pact_frm->subtype) {
+ case P2P_PAF_GON_REQ:
+ CFGP2P_ACTION(("%s P2P Group Owner Negotiation Req Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_PAF_GON_RSP:
+ CFGP2P_ACTION(("%s P2P Group Owner Negotiation Rsp Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_PAF_GON_CONF:
+ CFGP2P_ACTION(("%s P2P Group Owner Negotiation Confirm Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_PAF_INVITE_REQ:
+ CFGP2P_ACTION(("%s P2P Invitation Request Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_PAF_INVITE_RSP:
+ CFGP2P_ACTION(("%s P2P Invitation Response Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_PAF_DEVDIS_REQ:
+ CFGP2P_ACTION(("%s P2P Device Discoverability Request Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_PAF_DEVDIS_RSP:
+ CFGP2P_ACTION(("%s P2P Device Discoverability Response Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_PAF_PROVDIS_REQ:
+ CFGP2P_ACTION(("%s P2P Provision Discovery Request Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_PAF_PROVDIS_RSP:
+ CFGP2P_ACTION(("%s P2P Provision Discovery Response Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ default:
+ CFGP2P_ACTION(("%s Unknown P2P Public Action Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+
+ }
+
+ } else if (wl_cfgp2p_is_p2p_action(frame, frame_len)) {
+ act_frm = (wifi_p2p_action_frame_t *)frame;
+ switch (act_frm->subtype) {
+ case P2P_AF_NOTICE_OF_ABSENCE:
+ CFGP2P_ACTION(("%s P2P Notice of Absence Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_AF_PRESENCE_REQ:
+ CFGP2P_ACTION(("%s P2P Presence Request Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_AF_PRESENCE_RSP:
+ CFGP2P_ACTION(("%s P2P Presence Response Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_AF_GO_DISC_REQ:
+ CFGP2P_ACTION(("%s P2P Discoverability Request Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ default:
+ CFGP2P_ACTION(("%s Unknown P2P Action Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ }
+
+ } else if (wl_cfgp2p_is_gas_action(frame, frame_len)) {
+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame;
+ switch (sd_act_frm->action) {
+ case P2PSD_ACTION_ID_GAS_IREQ:
+ CFGP2P_ACTION(("%s P2P GAS Initial Request,"
+ " channel=%d\n", (tx)? "TX" : "RX", channel));
+ break;
+ case P2PSD_ACTION_ID_GAS_IRESP:
+ CFGP2P_ACTION(("%s P2P GAS Initial Response,"
+ " channel=%d\n", (tx)? "TX" : "RX", channel));
+ break;
+ case P2PSD_ACTION_ID_GAS_CREQ:
+ CFGP2P_ACTION(("%s P2P GAS Comback Request,"
+ " channel=%d\n", (tx)? "TX" : "RX", channel));
+ break;
+ case P2PSD_ACTION_ID_GAS_CRESP:
+ CFGP2P_ACTION(("%s P2P GAS Comback Response,"
+ " channel=%d\n", (tx)? "TX" : "RX", channel));
+ break;
+ default:
+ CFGP2P_ACTION(("%s Unknown P2P GAS Frame,"
+ " channel=%d\n", (tx)? "TX" : "RX", channel));
+ }
+
+
+ }
+}
+
+/*
+ * Initialize variables related to P2P
+ *
+ */
+s32
+wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg)
+{
+ if (!(cfg->p2p = kzalloc(sizeof(struct p2p_info), GFP_KERNEL))) {
+ CFGP2P_ERR(("struct p2p_info allocation failed\n"));
+ return -ENOMEM;
+ }
+
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY) = bcmcfg_to_prmry_ndev(cfg);
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY) = 0;
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL;
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) = NULL;
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) = -1;
+ return BCME_OK;
+
+}
+/*
+ * Deinitialize variables related to P2P
+ *
+ */
+void
+wl_cfgp2p_deinit_priv(struct bcm_cfg80211 *cfg)
+{
+ CFGP2P_ERR(("In\n"));
+ if (cfg->p2p) {
+ kfree(cfg->p2p);
+ cfg->p2p = NULL;
+ }
+ cfg->p2p_supported = 0;
+}
+/*
+ * Set P2P functions into firmware
+ */
+s32
+wl_cfgp2p_set_firm_p2p(struct bcm_cfg80211 *cfg)
+{
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ struct ether_addr null_eth_addr = { { 0, 0, 0, 0, 0, 0 } };
+ s32 ret = BCME_OK;
+ s32 val = 0;
+ /* Do we have to check whether APSTA is enabled or not ? */
+ ret = wldev_iovar_getint(ndev, "apsta", &val);
+ if (ret < 0) {
+ CFGP2P_ERR(("get apsta error %d\n", ret));
+ return ret;
+ }
+ if (val == 0) {
+ val = 1;
+ ret = wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true);
+ if (ret < 0) {
+ CFGP2P_ERR(("WLC_DOWN error %d\n", ret));
+ return ret;
+ }
+ wldev_iovar_setint(ndev, "apsta", val);
+ ret = wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true);
+ if (ret < 0) {
+ CFGP2P_ERR(("WLC_UP error %d\n", ret));
+ return ret;
+ }
+ }
+
+ /* In case of COB type, firmware has default mac address
+ * After Initializing firmware, we have to set current mac address to
+ * firmware for P2P device address
+ */
+ ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr,
+ sizeof(null_eth_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &cfg->ioctl_buf_sync);
+ if (ret && ret != BCME_UNSUPPORTED) {
+ CFGP2P_ERR(("failed to update device address ret %d\n", ret));
+ }
+ return ret;
+}
+
+/* Create a new P2P BSS.
+ * Parameters:
+ * @mac : MAC address of the BSS to create
+ * @if_type : interface type: WL_P2P_IF_GO or WL_P2P_IF_CLIENT
+ * @chspec : chspec to use if creating a GO BSS.
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_ifadd(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type,
+ chanspec_t chspec)
+{
+ wl_p2p_if_t ifreq;
+ s32 err;
+ u32 scb_timeout = WL_SCB_TIMEOUT;
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+
+ ifreq.type = if_type;
+ ifreq.chspec = chspec;
+ memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
+
+ CFGP2P_DBG(("---cfg p2p_ifadd "MACDBG" %s %u\n",
+ MAC2STRDBG(ifreq.addr.octet),
+ (if_type == WL_P2P_IF_GO) ? "go" : "client",
+ (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
+
+ err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+
+ if (unlikely(err < 0))
+ printk("'cfg p2p_ifadd' error %d\n", err);
+ else if (if_type == WL_P2P_IF_GO) {
+ err = wldev_ioctl(ndev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true);
+ if (unlikely(err < 0))
+ printk("'cfg scb_timeout' error %d\n", err);
+ }
+ return err;
+}
+
+/* Disable a P2P BSS.
+ * Parameters:
+ * @mac : MAC address of the BSS to disable
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_ifdisable(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
+{
+ s32 ret;
+ struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg);
+
+ CFGP2P_INFO(("------primary idx %d : cfg p2p_ifdis "MACDBG"\n",
+ netdev->ifindex, MAC2STRDBG(mac->octet)));
+ ret = wldev_iovar_setbuf(netdev, "p2p_ifdis", mac, sizeof(*mac),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (unlikely(ret < 0)) {
+ printk("'cfg p2p_ifdis' error %d\n", ret);
+ }
+ return ret;
+}
+
+/* Delete a P2P BSS.
+ * Parameters:
+ * @mac : MAC address of the BSS to delete
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_ifdel(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
+{
+ s32 ret;
+ struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg);
+
+ CFGP2P_INFO(("------primary idx %d : cfg p2p_ifdel "MACDBG"\n",
+ netdev->ifindex, MAC2STRDBG(mac->octet)));
+ ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (unlikely(ret < 0)) {
+ printk("'cfg p2p_ifdel' error %d\n", ret);
+ }
+ return ret;
+}
+
+/* Change a P2P Role.
+ * Parameters:
+ * @mac : MAC address of the BSS to change a role
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_ifchange(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type,
+ chanspec_t chspec)
+{
+ wl_p2p_if_t ifreq;
+ s32 err;
+ u32 scb_timeout = WL_SCB_TIMEOUT;
+
+ struct net_device *netdev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION);
+
+ ifreq.type = if_type;
+ ifreq.chspec = chspec;
+ memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
+
+ CFGP2P_INFO(("---cfg p2p_ifchange "MACDBG" %s %u"
+ " chanspec 0x%04x\n", MAC2STRDBG(ifreq.addr.octet),
+ (if_type == WL_P2P_IF_GO) ? "go" : "client",
+ (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT,
+ ifreq.chspec));
+
+ err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+
+ if (unlikely(err < 0)) {
+ printk("'cfg p2p_ifupd' error %d\n", err);
+ } else if (if_type == WL_P2P_IF_GO) {
+ err = wldev_ioctl(netdev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true);
+ if (unlikely(err < 0))
+ printk("'cfg scb_timeout' error %d\n", err);
+ }
+ return err;
+}
+
+
+/* Get the index of a created P2P BSS.
+ * Parameters:
+ * @mac : MAC address of the created BSS
+ * @index : output: index of created BSS
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_ifidx(struct bcm_cfg80211 *cfg, struct ether_addr *mac, s32 *index)
+{
+ s32 ret;
+ u8 getbuf[64];
+ struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
+
+ CFGP2P_INFO(("---cfg p2p_if "MACDBG"\n", MAC2STRDBG(mac->octet)));
+
+ ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf,
+ sizeof(getbuf), wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY), NULL);
+
+ if (ret == 0) {
+ memcpy(index, getbuf, sizeof(s32));
+ CFGP2P_INFO(("---cfg p2p_if ==> %d\n", *index));
+ }
+
+ return ret;
+}
+
+static s32
+wl_cfgp2p_set_discovery(struct bcm_cfg80211 *cfg, s32 on)
+{
+ s32 ret = BCME_OK;
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ CFGP2P_DBG(("enter\n"));
+
+ ret = wldev_iovar_setint(ndev, "p2p_disc", on);
+
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR(("p2p_disc %d error %d\n", on, ret));
+ }
+
+ return ret;
+}
+
+/* Set the WL driver's P2P mode.
+ * Parameters :
+ * @mode : is one of WL_P2P_DISC_ST_{SCAN,LISTEN,SEARCH}.
+ * @channel : the channel to listen
+ * @listen_ms : the time (milli seconds) to wait
+ * @bssidx : bss index for BSSCFG
+ * Returns 0 if success
+ */
+
+s32
+wl_cfgp2p_set_p2p_mode(struct bcm_cfg80211 *cfg, u8 mode, u32 channel, u16 listen_ms, int bssidx)
+{
+ wl_p2p_disc_st_t discovery_mode;
+ s32 ret;
+ struct net_device *dev;
+ CFGP2P_DBG(("enter\n"));
+
+ if (unlikely(bssidx == WL_INVALID)) {
+ CFGP2P_ERR((" %d index out of range\n", bssidx));
+ return -1;
+ }
+
+ dev = wl_cfgp2p_find_ndev(cfg, bssidx);
+ if (unlikely(dev == NULL)) {
+ CFGP2P_ERR(("bssidx %d is not assigned\n", bssidx));
+ return BCME_NOTFOUND;
+ }
+
+ /* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */
+ discovery_mode.state = mode;
+ discovery_mode.chspec = wl_ch_host_to_driver(channel);
+ discovery_mode.dwell = listen_ms;
+ ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode,
+ sizeof(discovery_mode), cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
+ bssidx, &cfg->ioctl_buf_sync);
+
+ return ret;
+}
+
+/* Get the index of the P2P Discovery BSS */
+static s32
+wl_cfgp2p_get_disc_idx(struct bcm_cfg80211 *cfg, s32 *index)
+{
+ s32 ret;
+ struct net_device *dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
+
+ ret = wldev_iovar_getint(dev, "p2p_dev", index);
+ CFGP2P_INFO(("p2p_dev bsscfg_idx=%d ret=%d\n", *index, ret));
+
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR(("'p2p_dev' error %d\n", ret));
+ return ret;
+ }
+ return ret;
+}
+
+s32
+wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg)
+{
+
+ s32 index = 0;
+ s32 ret = BCME_OK;
+
+ CFGP2P_DBG(("enter\n"));
+
+ if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) != 0) {
+ CFGP2P_ERR(("do nothing, already initialized\n"));
+ return ret;
+ }
+
+ ret = wl_cfgp2p_set_discovery(cfg, 1);
+ if (ret < 0) {
+ CFGP2P_ERR(("set discover error\n"));
+ return ret;
+ }
+ /* Enable P2P Discovery in the WL Driver */
+ ret = wl_cfgp2p_get_disc_idx(cfg, &index);
+
+ if (ret < 0) {
+ return ret;
+ }
+ /* In case of CFG80211 case, check if p2p_discovery interface has allocated p2p_wdev */
+ if (!cfg->p2p_wdev) {
+ CFGP2P_ERR(("p2p_wdev is NULL.\n"));
+ return BCME_NODEVICE;
+ }
+ /* Make an entry in the netinfo */
+ wl_alloc_netinfo(cfg, cfg->p2p_net, cfg->p2p_wdev, WL_MODE_BSS, 0, index);
+
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) =
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = index;
+
+ /* Set the initial discovery state to SCAN */
+ ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
+
+ if (unlikely(ret != 0)) {
+ CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n"));
+ wl_cfgp2p_set_discovery(cfg, 0);
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL;
+ return 0;
+ }
+ return ret;
+}
+
+/* Deinitialize P2P Discovery
+ * Parameters :
+ * @cfg : wl_private data
+ * Returns 0 if succes
+ */
+static s32
+wl_cfgp2p_deinit_discovery(struct bcm_cfg80211 *cfg)
+{
+ s32 ret = BCME_OK;
+ CFGP2P_DBG(("enter\n"));
+
+ if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) == 0) {
+ CFGP2P_ERR(("do nothing, not initialized\n"));
+ return -1;
+ }
+ /* Set the discovery state to SCAN */
+ ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
+ /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */
+ ret = wl_cfgp2p_set_discovery(cfg, 0);
+
+ /* Remove the p2p disc entry in the netinfo */
+#ifdef DHD_IFDEBUG
+ WL_ERR(("dealloc_net_info by wdev=%p\n", cfg->p2p_wdev));
+#endif
+ wl_dealloc_netinfo_by_wdev(cfg, cfg->p2p_wdev);
+
+ /* Clear our saved WPS and P2P IEs for the discovery BSS. The driver
+ * deleted these IEs when wl_cfgp2p_set_discovery() deleted the discovery
+ * BSS.
+ */
+
+ /* Clear the saved bsscfg index of the discovery BSSCFG to indicate we
+ * have no discovery BSS.
+ */
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = WL_INVALID;
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL;
+
+ return ret;
+
+}
+/* Enable P2P Discovery
+ * Parameters:
+ * @cfg : wl_private data
+ * @ie : probe request ie (WPS IE + P2P IE)
+ * @ie_len : probe request ie length
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev,
+ const u8 *ie, u32 ie_len)
+{
+ s32 ret = BCME_OK;
+ s32 bssidx;
+
+ CFGP2P_DBG(("enter\n"));
+
+ if (wl_get_p2p_status(cfg, DISCOVERY_ON)) {
+ CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n"));
+ goto set_ie;
+ }
+
+ ret = wl_cfgp2p_init_discovery(cfg);
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR((" init discovery error %d\n", ret));
+ goto exit;
+ }
+
+ wl_set_p2p_status(cfg, DISCOVERY_ON);
+ /* Set wsec to any non-zero value in the discovery bsscfg to ensure our
+ * P2P probe responses have the privacy bit set in the 802.11 WPA IE.
+ * Some peer devices may not initiate WPS with us if this bit is not set.
+ */
+ ret = wldev_iovar_setint_bsscfg(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE),
+ "wsec", AES_ENABLED, wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR((" wsec error %d\n", ret));
+ }
+set_ie:
+ if (ie_len) {
+ if (bcmcfg_to_prmry_ndev(cfg) == dev) {
+ bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+ } else if ((bssidx = wl_get_bssidx_by_wdev(cfg, cfg->p2p_wdev)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev));
+ return BCME_ERROR;
+ }
+
+ ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, dev,
+ bssidx,
+ VNDR_IE_PRBREQ_FLAG, ie, ie_len);
+
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR(("set probreq ie occurs error %d\n", ret));
+ goto exit;
+ }
+ }
+exit:
+ return ret;
+}
+
+/* Disable P2P Discovery
+ * Parameters:
+ * @cfg : wl_private_data
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_disable_discovery(struct bcm_cfg80211 *cfg)
+{
+ s32 ret = BCME_OK;
+ CFGP2P_DBG((" enter\n"));
+ wl_clr_p2p_status(cfg, DISCOVERY_ON);
+
+ if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) == 0) {
+ CFGP2P_ERR((" do nothing, not initialized\n"));
+ goto exit;
+ }
+
+ ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
+
+ if (unlikely(ret < 0)) {
+
+ CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n"));
+ }
+ /* Do a scan abort to stop the driver's scan engine in case it is still
+ * waiting out an action frame tx dwell time.
+ */
+ wl_clr_p2p_status(cfg, DISCOVERY_ON);
+ ret = wl_cfgp2p_deinit_discovery(cfg);
+
+exit:
+ return ret;
+}
+
+s32
+wl_cfgp2p_escan(struct bcm_cfg80211 *cfg, struct net_device *dev, u16 active,
+ u32 num_chans, u16 *channels,
+ s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr,
+ p2p_scan_purpose_t p2p_scan_purpose)
+{
+ s32 ret = BCME_OK;
+ s32 memsize;
+ s32 eparams_size;
+ u32 i;
+ s8 *memblk;
+ wl_p2p_scan_t *p2p_params;
+ wl_escan_params_t *eparams;
+ wlc_ssid_t ssid;
+ /* Scan parameters */
+#define P2PAPI_SCAN_NPROBES 1
+#define P2PAPI_SCAN_DWELL_TIME_MS 80
+#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40
+#define P2PAPI_SCAN_HOME_TIME_MS 60
+#define P2PAPI_SCAN_NPROBS_TIME_MS 30
+#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100
+
+ struct net_device *pri_dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
+ /* Allocate scan params which need space for 3 channels and 0 ssids */
+ eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE +
+ OFFSETOF(wl_escan_params_t, params)) +
+ num_chans * sizeof(eparams->params.channel_list[0]);
+
+ memsize = sizeof(wl_p2p_scan_t) + eparams_size;
+ memblk = scanparambuf;
+ if (memsize > sizeof(scanparambuf)) {
+ CFGP2P_ERR((" scanpar buf too small (%u > %zu)\n",
+ memsize, sizeof(scanparambuf)));
+ return -1;
+ }
+ memset(memblk, 0, memsize);
+ memset(cfg->ioctl_buf, 0, WLC_IOCTL_MAXLEN);
+ if (search_state == WL_P2P_DISC_ST_SEARCH) {
+ /*
+ * If we in SEARCH STATE, we don't need to set SSID explictly
+ * because dongle use P2P WILDCARD internally by default
+ */
+ wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx);
+ /* use null ssid */
+ ssid.SSID_len = 0;
+ memset(&ssid.SSID, 0, sizeof(ssid.SSID));
+ } else if (search_state == WL_P2P_DISC_ST_SCAN) {
+ /* SCAN STATE 802.11 SCAN
+ * WFD Supplicant has p2p_find command with (type=progressive, type= full)
+ * So if P2P_find command with type=progressive,
+ * we have to set ssid to P2P WILDCARD because
+ * we just do broadcast scan unless setting SSID
+ */
+ wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx);
+ /* use wild card ssid */
+ ssid.SSID_len = WL_P2P_WILDCARD_SSID_LEN;
+ memset(&ssid.SSID, 0, sizeof(ssid.SSID));
+ memcpy(&ssid.SSID, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN);
+ } else {
+ CFGP2P_ERR((" invalid search state %d\n", search_state));
+ return -1;
+ }
+
+
+ /* Fill in the P2P scan structure at the start of the iovar param block */
+ p2p_params = (wl_p2p_scan_t*) memblk;
+ p2p_params->type = 'E';
+ /* Fill in the Scan structure that follows the P2P scan structure */
+ eparams = (wl_escan_params_t*) (p2p_params + 1);
+ eparams->params.bss_type = DOT11_BSSTYPE_ANY;
+ if (active)
+ eparams->params.scan_type = DOT11_SCANTYPE_ACTIVE;
+ else
+ eparams->params.scan_type = DOT11_SCANTYPE_PASSIVE;
+
+ if (tx_dst_addr == NULL)
+ memcpy(&eparams->params.bssid, &ether_bcast, ETHER_ADDR_LEN);
+ else
+ memcpy(&eparams->params.bssid, tx_dst_addr, ETHER_ADDR_LEN);
+
+ if (ssid.SSID_len)
+ memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t));
+
+ eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS);
+
+ switch (p2p_scan_purpose) {
+ case P2P_SCAN_SOCIAL_CHANNEL:
+ eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS);
+ break;
+ case P2P_SCAN_AFX_PEER_NORMAL:
+ case P2P_SCAN_AFX_PEER_REDUCED:
+ eparams->params.active_time = htod32(P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS);
+ break;
+ case P2P_SCAN_CONNECT_TRY:
+ eparams->params.active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS);
+ break;
+ default :
+ if (wl_get_drv_status_all(cfg, CONNECTED))
+ eparams->params.active_time = -1;
+ else
+ eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS);
+ break;
+ }
+
+ if (p2p_scan_purpose == P2P_SCAN_CONNECT_TRY)
+ eparams->params.nprobes = htod32(eparams->params.active_time /
+ WL_SCAN_JOIN_PROBE_INTERVAL_MS);
+ else
+ eparams->params.nprobes = htod32((eparams->params.active_time /
+ P2PAPI_SCAN_NPROBS_TIME_MS));
+
+
+ if (eparams->params.nprobes <= 0)
+ eparams->params.nprobes = 1;
+ CFGP2P_DBG(("nprobes # %d, active_time %d\n",
+ eparams->params.nprobes, eparams->params.active_time));
+ eparams->params.passive_time = htod32(-1);
+ eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
+ (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
+
+ for (i = 0; i < num_chans; i++) {
+ eparams->params.channel_list[i] = wl_ch_host_to_driver(channels[i]);
+ }
+ eparams->version = htod32(ESCAN_REQ_VERSION);
+ eparams->action = htod16(action);
+ wl_escan_set_sync_id(eparams->sync_id, cfg);
+ wl_escan_set_type(cfg, WL_SCANTYPE_P2P);
+ CFGP2P_INFO(("SCAN CHANNELS : "));
+
+ for (i = 0; i < num_chans; i++) {
+ if (i == 0) CFGP2P_INFO(("%d", channels[i]));
+ else CFGP2P_INFO((",%d", channels[i]));
+ }
+
+ CFGP2P_INFO(("\n"));
+
+ ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan",
+ memblk, memsize, cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+ if (ret == BCME_OK)
+ wl_set_p2p_status(cfg, SCANNING);
+ return ret;
+}
+
+/* search function to reach at common channel to send action frame
+ * Parameters:
+ * @cfg : wl_private data
+ * @ndev : net device for bssidx
+ * @bssidx : bssidx for BSS
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_act_frm_search(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ s32 bssidx, s32 channel, struct ether_addr *tx_dst_addr)
+{
+ s32 ret = 0;
+ u32 chan_cnt = 0;
+ u16 *default_chan_list = NULL;
+ p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_AFX_PEER_NORMAL;
+ if (!p2p_is_on(cfg) || ndev == NULL || bssidx == WL_INVALID)
+ return -BCME_ERROR;
+ WL_TRACE_HW4((" Enter\n"));
+ if (bssidx == wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY))
+ bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+ if (channel)
+ chan_cnt = AF_PEER_SEARCH_CNT;
+ else
+ chan_cnt = SOCIAL_CHAN_CNT;
+ default_chan_list = kzalloc(chan_cnt * sizeof(*default_chan_list), GFP_KERNEL);
+ if (default_chan_list == NULL) {
+ CFGP2P_ERR(("channel list allocation failed \n"));
+ ret = -ENOMEM;
+ goto exit;
+ }
+ if (channel) {
+ u32 i;
+ /* insert same channel to the chan_list */
+ for (i = 0; i < chan_cnt; i++) {
+ default_chan_list[i] = channel;
+ }
+ } else {
+ default_chan_list[0] = SOCIAL_CHAN_1;
+ default_chan_list[1] = SOCIAL_CHAN_2;
+ default_chan_list[2] = SOCIAL_CHAN_3;
+ }
+ ret = wl_cfgp2p_escan(cfg, ndev, true, chan_cnt,
+ default_chan_list, WL_P2P_DISC_ST_SEARCH,
+ WL_SCAN_ACTION_START, bssidx, NULL, p2p_scan_purpose);
+ kfree(default_chan_list);
+exit:
+ return ret;
+}
+
+/* Check whether pointed-to IE looks like WPA. */
+#define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
+ (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE)
+/* Check whether pointed-to IE looks like WPS. */
+#define wl_cfgp2p_is_wps_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
+ (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE)
+/* Check whether the given IE looks like WFA P2P IE. */
+#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
+ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P)
+/* Check whether the given IE looks like WFA WFDisplay IE. */
+#ifndef WFA_OUI_TYPE_WFD
+#define WFA_OUI_TYPE_WFD 0x0a /* WiFi Display OUI TYPE */
+#endif
+#define wl_cfgp2p_is_wfd_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
+ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_WFD)
+
+
+/* Is any of the tlvs the expected entry? If
+ * not update the tlvs buffer pointer/length.
+ */
+static bool
+wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type)
+{
+ /* If the contents match the OUI and the type */
+ if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
+ !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
+ type == ie[TLV_BODY_OFF + oui_len]) {
+ return TRUE;
+ }
+
+ if (tlvs == NULL)
+ return FALSE;
+ /* point to the next ie */
+ ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
+ /* calculate the length of the rest of the buffer */
+ *tlvs_len -= (int)(ie - *tlvs);
+ /* update the pointer to the start of the buffer */
+ *tlvs = ie;
+
+ return FALSE;
+}
+
+wpa_ie_fixed_t *
+wl_cfgp2p_find_wpaie(u8 *parse, u32 len)
+{
+ bcm_tlv_t *ie;
+
+ while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) {
+ if (wl_cfgp2p_is_wpa_ie((u8*)ie, &parse, &len)) {
+ return (wpa_ie_fixed_t *)ie;
+ }
+ }
+ return NULL;
+}
+
+wpa_ie_fixed_t *
+wl_cfgp2p_find_wpsie(u8 *parse, u32 len)
+{
+ bcm_tlv_t *ie;
+
+ while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) {
+ if (wl_cfgp2p_is_wps_ie((u8*)ie, &parse, &len)) {
+ return (wpa_ie_fixed_t *)ie;
+ }
+ }
+ return NULL;
+}
+
+wifi_p2p_ie_t *
+wl_cfgp2p_find_p2pie(u8 *parse, u32 len)
+{
+ bcm_tlv_t *ie;
+
+ while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) {
+ if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len)) {
+ return (wifi_p2p_ie_t *)ie;
+ }
+ }
+ return NULL;
+}
+
+wifi_wfd_ie_t *
+wl_cfgp2p_find_wfdie(u8 *parse, u32 len)
+{
+ bcm_tlv_t *ie;
+
+ while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) {
+ if (wl_cfgp2p_is_wfd_ie((uint8*)ie, &parse, &len)) {
+ return (wifi_wfd_ie_t *)ie;
+ }
+ }
+ return NULL;
+}
+u32
+wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag,
+ s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd)
+{
+ vndr_ie_setbuf_t hdr; /* aligned temporary vndr_ie buffer header */
+ s32 iecount;
+ u32 data_offset;
+
+ /* Validate the pktflag parameter */
+ if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG |
+ VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG |
+ VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG))) {
+ CFGP2P_ERR(("p2pwl_vndr_ie: Invalid packet flag 0x%x\n", pktflag));
+ return -1;
+ }
+
+ /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
+ strncpy(hdr.cmd, add_del_cmd, VNDR_IE_CMD_LEN - 1);
+ hdr.cmd[VNDR_IE_CMD_LEN - 1] = '\0';
+
+ /* Set the IE count - the buffer contains only 1 IE */
+ iecount = htod32(1);
+ memcpy((void *)&hdr.vndr_ie_buffer.iecount, &iecount, sizeof(s32));
+
+ /* Copy packet flags that indicate which packets will contain this IE */
+ pktflag = htod32(pktflag);
+ memcpy((void *)&hdr.vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
+ sizeof(u32));
+
+ /* Add the IE ID to the buffer */
+ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id;
+
+ /* Add the IE length to the buffer */
+ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len =
+ (uint8) VNDR_IE_MIN_LEN + datalen;
+
+ /* Add the IE OUI to the buffer */
+ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[0] = oui[0];
+ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[1] = oui[1];
+ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[2] = oui[2];
+
+ /* Copy the aligned temporary vndr_ie buffer header to the IE buffer */
+ memcpy(iebuf, &hdr, sizeof(hdr) - 1);
+
+ /* Copy the IE data to the IE buffer */
+ data_offset =
+ (u8*)&hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0] -
+ (u8*)&hdr;
+ memcpy(iebuf + data_offset, data, datalen);
+ return data_offset + datalen;
+
+}
+
+struct net_device *
+wl_cfgp2p_find_ndev(struct bcm_cfg80211 *cfg, s32 bssidx)
+{
+ u32 i;
+ struct net_device *ndev = NULL;
+ if (bssidx < 0) {
+ CFGP2P_ERR((" bsscfg idx is invalid\n"));
+ goto exit;
+ }
+
+ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
+ if (bssidx == wl_to_p2p_bss_bssidx(cfg, i)) {
+ ndev = wl_to_p2p_bss_ndev(cfg, i);
+ break;
+ }
+ }
+
+exit:
+ return ndev;
+}
+/*
+ * Search the driver array idx based on bssidx argument
+ * Parameters:
+ * @cfg : wl_private data
+ * @bssidx : bssidx which indicate bsscfg->idx of firmware.
+ * @type : output arg to store array idx of p2p->bss.
+ * Returns error
+ */
+
+s32
+wl_cfgp2p_find_type(struct bcm_cfg80211 *cfg, s32 bssidx, s32 *type)
+{
+ u32 i;
+ if (bssidx < 0 || type == NULL) {
+ CFGP2P_ERR((" argument is invalid\n"));
+ goto exit;
+ }
+
+ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
+ if (bssidx == wl_to_p2p_bss_bssidx(cfg, i)) {
+ *type = i;
+ return BCME_OK;
+ }
+ }
+
+exit:
+ return BCME_BADARG;
+}
+
+/*
+ * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE
+ */
+s32
+wl_cfgp2p_listen_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ s32 ret = BCME_OK;
+ struct net_device *ndev = NULL;
+
+ if (!cfg || !cfg->p2p || !cfgdev)
+ return BCME_ERROR;
+
+ CFGP2P_DBG((" Enter\n"));
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ if (wl_get_p2p_status(cfg, LISTEN_EXPIRED) == 0) {
+ wl_set_p2p_status(cfg, LISTEN_EXPIRED);
+ if (timer_pending(&cfg->p2p->listen_timer)) {
+ del_timer_sync(&cfg->p2p->listen_timer);
+ }
+
+ if (cfg->afx_hdl->is_listen == TRUE &&
+ wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
+ WL_DBG(("Listen DONE for action frame\n"));
+ complete(&cfg->act_frm_scan);
+ }
+#ifdef WL_CFG80211_SYNC_GON
+ else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
+ wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, ndev);
+ WL_DBG(("Listen DONE and wake up wait_next_af !!(%d)\n",
+ jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies)));
+
+ if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM))
+ wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
+
+ complete(&cfg->wait_next_af);
+ }
+#endif /* WL_CFG80211_SYNC_GON */
+
+#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ if (wl_get_drv_status_all(cfg, REMAINING_ON_CHANNEL)) {
+#else
+ if (wl_get_drv_status_all(cfg, REMAINING_ON_CHANNEL) ||
+ wl_get_drv_status_all(cfg, FAKE_REMAINING_ON_CHANNEL)) {
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+ WL_DBG(("Listen DONE for ramain on channel expired\n"));
+ wl_clr_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ wl_clr_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+ if (ndev && (ndev->ieee80211_ptr != NULL)) {
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ if (bcmcfg_to_p2p_wdev(cfg)) {
+ cfg80211_remain_on_channel_expired(
+ bcmcfg_to_p2p_wdev(cfg), cfg->last_roc_id,
+ &cfg->remain_on_chan, GFP_KERNEL);
+ }
+#else
+ cfg80211_remain_on_channel_expired(cfg->p2p_net, cfg->last_roc_id,
+ &cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ }
+ }
+ if (wl_add_remove_eventmsg(bcmcfg_to_prmry_ndev(cfg),
+ WLC_E_P2P_PROBREQ_MSG, false) != BCME_OK) {
+ CFGP2P_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
+ }
+ } else
+ wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
+
+ return ret;
+
+}
+
+/*
+ * Timer expire callback function for LISTEN
+ * We can't report cfg80211_remain_on_channel_expired from Timer ISR context,
+ * so lets do it from thread context.
+ */
+void
+wl_cfgp2p_listen_expired(unsigned long data)
+{
+ wl_event_msg_t msg;
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *) data;
+ CFGP2P_DBG((" Enter\n"));
+ bzero(&msg, sizeof(wl_event_msg_t));
+ msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE);
+#if defined(WL_ENABLE_P2P_IF)
+ wl_cfg80211_event(cfg->p2p_net ? cfg->p2p_net :
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE), &msg, NULL);
+#else
+ wl_cfg80211_event(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE), &msg,
+ NULL);
+#endif /* WL_ENABLE_P2P_IF */
+}
+/*
+ * Routine for cancelling the P2P LISTEN
+ */
+static s32
+wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ struct wireless_dev *wdev, bool notify)
+{
+ WL_DBG(("Enter \n"));
+ /* Irrespective of whether timer is running or not, reset
+ * the LISTEN state.
+ */
+ if (timer_pending(&cfg->p2p->listen_timer)) {
+ del_timer_sync(&cfg->p2p->listen_timer);
+ if (notify) {
+#if defined(WL_CFG80211_P2P_DEV_IF)
+#ifdef P2PONEINT
+ if (wdev == NULL)
+ wdev = bcmcfg_to_p2p_wdev(cfg);
+#endif
+ if (wdev)
+ cfg80211_remain_on_channel_expired(
+ bcmcfg_to_p2p_wdev(cfg), cfg->last_roc_id,
+ &cfg->remain_on_chan, GFP_KERNEL);
+#else
+ if (ndev && ndev->ieee80211_ptr)
+ cfg80211_remain_on_channel_expired(cfg->p2p_net, cfg->last_roc_id,
+ &cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ }
+ }
+ return 0;
+}
+/*
+ * Do a P2P Listen on the given channel for the given duration.
+ * A listen consists of sitting idle and responding to P2P probe requests
+ * with a P2P probe response.
+ *
+ * This fn assumes dongle p2p device discovery is already enabled.
+ * Parameters :
+ * @cfg : wl_private data
+ * @channel : channel to listen
+ * @duration_ms : the time (milli seconds) to wait
+ */
+s32
+wl_cfgp2p_discover_listen(struct bcm_cfg80211 *cfg, s32 channel, u32 duration_ms)
+{
+#define EXTRA_DELAY_TIME 100
+ s32 ret = BCME_OK;
+ struct timer_list *_timer;
+ s32 extra_delay;
+ struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg);
+
+ CFGP2P_DBG((" Enter Listen Channel : %d, Duration : %d\n", channel, duration_ms));
+ if (unlikely(wl_get_p2p_status(cfg, DISCOVERY_ON) == 0)) {
+
+ CFGP2P_ERR((" Discovery is not set, so we have noting to do\n"));
+
+ ret = BCME_NOTREADY;
+ goto exit;
+ }
+ if (timer_pending(&cfg->p2p->listen_timer)) {
+ CFGP2P_DBG(("previous LISTEN is not completed yet\n"));
+ goto exit;
+
+ }
+#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ else
+ wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
+#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+ if (wl_add_remove_eventmsg(netdev, WLC_E_P2P_PROBREQ_MSG, true) != BCME_OK) {
+ CFGP2P_ERR((" failed to set WLC_E_P2P_PROPREQ_MSG\n"));
+ }
+
+ ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms,
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
+ _timer = &cfg->p2p->listen_timer;
+
+ /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle ,
+ * otherwise we will wait up to duration_ms + 100ms + duration / 10
+ */
+ if (ret == BCME_OK) {
+ extra_delay = EXTRA_DELAY_TIME + (duration_ms / 10);
+ } else {
+ /* if failed to set listen, it doesn't need to wait whole duration. */
+ duration_ms = 100 + duration_ms / 20;
+ extra_delay = 0;
+ }
+
+ INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, extra_delay);
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+
+#undef EXTRA_DELAY_TIME
+exit:
+ return ret;
+}
+
+
+s32
+wl_cfgp2p_discover_enable_search(struct bcm_cfg80211 *cfg, u8 enable)
+{
+ s32 ret = BCME_OK;
+ CFGP2P_DBG((" Enter\n"));
+ if (!wl_get_p2p_status(cfg, DISCOVERY_ON)) {
+
+ CFGP2P_DBG((" do nothing, discovery is off\n"));
+ return ret;
+ }
+ if (wl_get_p2p_status(cfg, SEARCH_ENABLED) == enable) {
+ CFGP2P_DBG(("already : %d\n", enable));
+ return ret;
+ }
+
+ wl_chg_p2p_status(cfg, SEARCH_ENABLED);
+ /* When disabling Search, reset the WL driver's p2p discovery state to
+ * WL_P2P_DISC_ST_SCAN.
+ */
+ if (!enable) {
+ wl_clr_p2p_status(cfg, SCANNING);
+ ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
+ }
+
+ return ret;
+}
+
+/*
+ * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE
+ */
+s32
+wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ s32 ret = BCME_OK;
+ u32 event_type = ntoh32(e->event_type);
+ u32 status = ntoh32(e->status);
+ struct net_device *ndev = NULL;
+ CFGP2P_DBG((" Enter\n"));
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) {
+ if (event_type == WLC_E_ACTION_FRAME_COMPLETE) {
+
+ CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status));
+ if (status == WLC_E_STATUS_SUCCESS) {
+ wl_set_p2p_status(cfg, ACTION_TX_COMPLETED);
+ CFGP2P_DBG(("WLC_E_ACTION_FRAME_COMPLETE : ACK\n"));
+ if (!cfg->need_wait_afrx && cfg->af_sent_channel) {
+ CFGP2P_DBG(("no need to wait next AF.\n"));
+ wl_stop_wait_next_action_frame(cfg, ndev);
+ }
+ }
+ else if (!wl_get_p2p_status(cfg, ACTION_TX_COMPLETED)) {
+ wl_set_p2p_status(cfg, ACTION_TX_NOACK);
+ CFGP2P_INFO(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n"));
+ wl_stop_wait_next_action_frame(cfg, ndev);
+ }
+ } else {
+ CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received,"
+ "status : %d\n", status));
+
+ if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM))
+ complete(&cfg->send_af_done);
+ }
+ }
+ return ret;
+}
+/* Send an action frame immediately without doing channel synchronization.
+ *
+ * This function does not wait for a completion event before returning.
+ * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action
+ * frame is transmitted.
+ * The WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE event will be received when an
+ * 802.11 ack has been received for the sent action frame.
+ */
+s32
+wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev,
+ wl_af_params_t *af_params, s32 bssidx)
+{
+ s32 ret = BCME_OK;
+ s32 evt_ret = BCME_OK;
+ s32 timeout = 0;
+ wl_eventmsg_buf_t buf;
+
+
+ CFGP2P_INFO(("\n"));
+ CFGP2P_INFO(("channel : %u , dwell time : %u\n",
+ af_params->channel, af_params->dwell_time));
+
+ wl_clr_p2p_status(cfg, ACTION_TX_COMPLETED);
+ wl_clr_p2p_status(cfg, ACTION_TX_NOACK);
+
+ bzero(&buf, sizeof(wl_eventmsg_buf_t));
+ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, true);
+ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, true);
+ if ((evt_ret = wl_cfg80211_apply_eventbuffer(bcmcfg_to_prmry_ndev(cfg), cfg, &buf)) < 0)
+ return evt_ret;
+
+ cfg->af_sent_channel = af_params->channel;
+#ifdef WL_CFG80211_SYNC_GON
+ cfg->af_tx_sent_jiffies = jiffies;
+#endif /* WL_CFG80211_SYNC_GON */
+
+ ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+
+ if (ret < 0) {
+ CFGP2P_ERR((" sending action frame is failed\n"));
+ goto exit;
+ }
+
+ timeout = wait_for_completion_timeout(&cfg->send_af_done,
+ msecs_to_jiffies(af_params->dwell_time + WL_AF_TX_EXTRA_TIME_MAX));
+
+ if (timeout >= 0 && wl_get_p2p_status(cfg, ACTION_TX_COMPLETED)) {
+ CFGP2P_INFO(("tx action frame operation is completed\n"));
+ ret = BCME_OK;
+ } else if (ETHER_ISBCAST(&cfg->afx_hdl->tx_dst_addr)) {
+ CFGP2P_INFO(("bcast tx action frame operation is completed\n"));
+ ret = BCME_OK;
+ } else {
+ ret = BCME_ERROR;
+ CFGP2P_INFO(("tx action frame operation is failed\n"));
+ }
+ /* clear status bit for action tx */
+ wl_clr_p2p_status(cfg, ACTION_TX_COMPLETED);
+ wl_clr_p2p_status(cfg, ACTION_TX_NOACK);
+
+exit:
+ CFGP2P_INFO((" via act frame iovar : status = %d\n", ret));
+
+ bzero(&buf, sizeof(wl_eventmsg_buf_t));
+ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, false);
+ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, false);
+ if ((evt_ret = wl_cfg80211_apply_eventbuffer(bcmcfg_to_prmry_ndev(cfg), cfg, &buf)) < 0) {
+ WL_ERR(("TX frame events revert back failed \n"));
+ return evt_ret;
+ }
+
+ return ret;
+}
+
+/* Generate our P2P Device Address and P2P Interface Address from our primary
+ * MAC address.
+ */
+void
+wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr,
+ struct ether_addr *out_dev_addr, struct ether_addr *out_int_addr)
+{
+ memset(out_dev_addr, 0, sizeof(*out_dev_addr));
+ memset(out_int_addr, 0, sizeof(*out_int_addr));
+
+ /* Generate the P2P Device Address. This consists of the device's
+ * primary MAC address with the locally administered bit set.
+ */
+ memcpy(out_dev_addr, primary_addr, sizeof(*out_dev_addr));
+ out_dev_addr->octet[0] |= 0x02;
+
+ /* Generate the P2P Interface Address. If the discovery and connection
+ * BSSCFGs need to simultaneously co-exist, then this address must be
+ * different from the P2P Device Address.
+ */
+ memcpy(out_int_addr, out_dev_addr, sizeof(*out_int_addr));
+#ifndef P2PONEINT
+ out_int_addr->octet[3] ^= 0x80;
+#endif
+
+}
+
+/* P2P IF Address change to Virtual Interface MAC Address */
+void
+wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id)
+{
+ wifi_p2p_ie_t *ie = (wifi_p2p_ie_t*) buf;
+ u16 len = ie->len;
+ u8 *subel;
+ u8 subelt_id;
+ u16 subelt_len;
+ CFGP2P_DBG((" Enter\n"));
+
+ /* Point subel to the P2P IE's subelt field.
+ * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
+ */
+ subel = ie->subelts;
+ len -= 4; /* exclude OUI + OUI_TYPE */
+
+ while (len >= 3) {
+ /* attribute id */
+ subelt_id = *subel;
+ subel += 1;
+ len -= 1;
+
+ /* 2-byte little endian */
+ subelt_len = *subel++;
+ subelt_len |= *subel++ << 8;
+
+ len -= 2;
+ len -= subelt_len; /* for the remaining subelt fields */
+
+ if (subelt_id == element_id) {
+ if (subelt_id == P2P_SEID_INTINTADDR) {
+ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
+ CFGP2P_INFO(("Intended P2P Interface Address ATTR FOUND\n"));
+ } else if (subelt_id == P2P_SEID_DEV_ID) {
+ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
+ CFGP2P_INFO(("Device ID ATTR FOUND\n"));
+ } else if (subelt_id == P2P_SEID_DEV_INFO) {
+ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
+ CFGP2P_INFO(("Device INFO ATTR FOUND\n"));
+ } else if (subelt_id == P2P_SEID_GROUP_ID) {
+ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
+ CFGP2P_INFO(("GROUP ID ATTR FOUND\n"));
+ } return;
+ } else {
+ CFGP2P_DBG(("OTHER id : %d\n", subelt_id));
+ }
+ subel += subelt_len;
+ }
+}
+/*
+ * Check if a BSS is up.
+ * This is a common implementation called by most OSL implementations of
+ * p2posl_bss_isup(). DO NOT call this function directly from the
+ * common code -- call p2posl_bss_isup() instead to allow the OSL to
+ * override the common implementation if necessary.
+ */
+bool
+wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx)
+{
+ s32 result, val;
+ bool isup = false;
+ s8 getbuf[64];
+
+ /* Check if the BSS is up */
+ *(int*)getbuf = -1;
+ result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
+ sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL);
+ if (result != 0) {
+ CFGP2P_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx, result));
+ CFGP2P_ERR(("NOTE: this ioctl error is normal "
+ "when the BSS has not been created yet.\n"));
+ } else {
+ val = *(int*)getbuf;
+ val = dtoh32(val);
+ CFGP2P_INFO(("---cfg bss -C %d ==> %d\n", bsscfg_idx, val));
+ isup = (val ? TRUE : FALSE);
+ }
+ return isup;
+}
+
+
+/* Bring up or down a BSS */
+s32
+wl_cfgp2p_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 up)
+{
+ s32 ret = BCME_OK;
+ s32 val = up ? 1 : 0;
+
+ struct {
+ s32 cfg;
+ s32 val;
+ } bss_setbuf;
+
+ bss_setbuf.cfg = htod32(bsscfg_idx);
+ bss_setbuf.val = htod32(val);
+ CFGP2P_INFO(("---cfg bss -C %d %s\n", bsscfg_idx, up ? "up" : "down"));
+ ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+
+ if (ret != 0) {
+ CFGP2P_ERR(("'bss %d' failed with %d\n", up, ret));
+ }
+
+ return ret;
+}
+
+/* Check if 'p2p' is supported in the driver */
+s32
+wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ s32 ret = BCME_OK;
+ s32 p2p_supported = 0;
+ ret = wldev_iovar_getint(ndev, "p2p",
+ &p2p_supported);
+ if (ret < 0) {
+ if (ret == BCME_UNSUPPORTED) {
+ CFGP2P_INFO(("p2p is unsupported\n"));
+ return 0;
+ } else {
+ CFGP2P_ERR(("cfg p2p error %d\n", ret));
+ return ret;
+ }
+ }
+ if (p2p_supported == 1) {
+ CFGP2P_INFO(("p2p is supported\n"));
+ } else {
+ CFGP2P_INFO(("p2p is unsupported\n"));
+ p2p_supported = 0;
+ }
+ return p2p_supported;
+}
+/* Cleanup P2P resources */
+s32
+wl_cfgp2p_down(struct bcm_cfg80211 *cfg)
+{
+ struct net_device *ndev = NULL;
+ struct wireless_dev *wdev = NULL;
+ s32 i = 0, index = -1;
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ wdev = bcmcfg_to_p2p_wdev(cfg);
+#ifdef P2PONEINT
+ ndev = wdev_to_ndev(wdev);
+#else
+ ndev = bcmcfg_to_prmry_ndev(cfg);
+#endif
+#elif defined(WL_ENABLE_P2P_IF)
+ ndev = cfg->p2p_net ? cfg->p2p_net : bcmcfg_to_prmry_ndev(cfg);
+ wdev = ndev_to_wdev(ndev);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+ wl_cfgp2p_cancel_listen(cfg, ndev, wdev, TRUE);
+ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
+ index = wl_to_p2p_bss_bssidx(cfg, i);
+ if (index != WL_INVALID)
+ wl_cfg80211_clear_per_bss_ies(cfg, index);
+ }
+ wl_cfgp2p_deinit_priv(cfg);
+ return 0;
+}
+
+int wl_cfgp2p_vif_created(struct bcm_cfg80211 *cfg)
+{
+ if (cfg->p2p && (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) != -1))
+ return true;
+ else
+ return false;
+}
+
+s32
+wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len)
+{
+ s32 ret = -1;
+ int count, start, duration;
+ wl_p2p_sched_t dongle_noa;
+
+ CFGP2P_DBG((" Enter\n"));
+
+ memset(&dongle_noa, 0, sizeof(dongle_noa));
+
+ if (wl_cfgp2p_vif_created(cfg)) {
+
+ cfg->p2p->noa.desc[0].start = 0;
+
+ sscanf(buf, "%10d %10d %10d", &count, &start, &duration);
+ CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n",
+ count, start, duration));
+ if (count != -1)
+ cfg->p2p->noa.desc[0].count = count;
+
+ /* supplicant gives interval as start */
+ if (start != -1)
+ cfg->p2p->noa.desc[0].interval = start;
+
+ if (duration != -1)
+ cfg->p2p->noa.desc[0].duration = duration;
+
+ if (cfg->p2p->noa.desc[0].count < 255 && cfg->p2p->noa.desc[0].count > 1) {
+ cfg->p2p->noa.desc[0].start = 0;
+ dongle_noa.type = WL_P2P_SCHED_TYPE_ABS;
+ dongle_noa.action = WL_P2P_SCHED_ACTION_NONE;
+ dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS;
+ }
+ else if (cfg->p2p->noa.desc[0].count == 1) {
+ cfg->p2p->noa.desc[0].start = 200;
+ dongle_noa.type = WL_P2P_SCHED_TYPE_REQ_ABS;
+ dongle_noa.action = WL_P2P_SCHED_ACTION_GOOFF;
+ dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS;
+ }
+ else if (cfg->p2p->noa.desc[0].count == 0) {
+ cfg->p2p->noa.desc[0].start = 0;
+ dongle_noa.action = WL_P2P_SCHED_ACTION_RESET;
+ }
+ else {
+ /* Continuous NoA interval. */
+ dongle_noa.action = WL_P2P_SCHED_ACTION_DOZE;
+ dongle_noa.type = WL_P2P_SCHED_TYPE_ABS;
+ if ((cfg->p2p->noa.desc[0].interval == 102) ||
+ (cfg->p2p->noa.desc[0].interval == 100)) {
+ cfg->p2p->noa.desc[0].start = 100 -
+ cfg->p2p->noa.desc[0].duration;
+ dongle_noa.option = WL_P2P_SCHED_OPTION_BCNPCT;
+ }
+ else {
+ dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL;
+ }
+ }
+ /* Put the noa descriptor in dongle format for dongle */
+ dongle_noa.desc[0].count = htod32(cfg->p2p->noa.desc[0].count);
+ if (dongle_noa.option == WL_P2P_SCHED_OPTION_BCNPCT) {
+ dongle_noa.desc[0].start = htod32(cfg->p2p->noa.desc[0].start);
+ dongle_noa.desc[0].duration = htod32(cfg->p2p->noa.desc[0].duration);
+ }
+ else {
+ dongle_noa.desc[0].start = htod32(cfg->p2p->noa.desc[0].start*1000);
+ dongle_noa.desc[0].duration = htod32(cfg->p2p->noa.desc[0].duration*1000);
+ }
+ dongle_noa.desc[0].interval = htod32(cfg->p2p->noa.desc[0].interval*1000);
+
+ ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION),
+ "p2p_noa", &dongle_noa, sizeof(dongle_noa), cfg->ioctl_buf,
+ WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+
+ if (ret < 0) {
+ CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret));
+ }
+ }
+ else {
+ CFGP2P_ERR(("ERROR: set_noa in non-p2p mode\n"));
+ }
+ return ret;
+}
+s32
+wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int buf_len)
+{
+
+ wifi_p2p_noa_desc_t *noa_desc;
+ int len = 0, i;
+ char _buf[200];
+
+ CFGP2P_DBG((" Enter\n"));
+ buf[0] = '\0';
+ if (wl_cfgp2p_vif_created(cfg)) {
+ if (cfg->p2p->noa.desc[0].count || cfg->p2p->ops.ops) {
+ _buf[0] = 1; /* noa index */
+ _buf[1] = (cfg->p2p->ops.ops ? 0x80: 0) |
+ (cfg->p2p->ops.ctw & 0x7f); /* ops + ctw */
+ len += 2;
+ if (cfg->p2p->noa.desc[0].count) {
+ noa_desc = (wifi_p2p_noa_desc_t*)&_buf[len];
+ noa_desc->cnt_type = cfg->p2p->noa.desc[0].count;
+ noa_desc->duration = cfg->p2p->noa.desc[0].duration;
+ noa_desc->interval = cfg->p2p->noa.desc[0].interval;
+ noa_desc->start = cfg->p2p->noa.desc[0].start;
+ len += sizeof(wifi_p2p_noa_desc_t);
+ }
+ if (buf_len <= len * 2) {
+ CFGP2P_ERR(("ERROR: buf_len %d in not enough for"
+ "returning noa in string format\n", buf_len));
+ return -1;
+ }
+ /* We have to convert the buffer data into ASCII strings */
+ for (i = 0; i < len; i++) {
+ snprintf(buf, 3, "%02x", _buf[i]);
+ buf += 2;
+ }
+ buf[i*2] = '\0';
+ }
+ }
+ else {
+ CFGP2P_ERR(("ERROR: get_noa in non-p2p mode\n"));
+ return -1;
+ }
+ return len * 2;
+}
+s32
+wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len)
+{
+ int ps, ctw;
+ int ret = -1;
+ s32 legacy_ps;
+ struct net_device *dev;
+
+ CFGP2P_DBG((" Enter\n"));
+ if (wl_cfgp2p_vif_created(cfg)) {
+ sscanf(buf, "%10d %10d %10d", &legacy_ps, &ps, &ctw);
+ CFGP2P_DBG((" Enter legacy_ps %d ps %d ctw %d\n", legacy_ps, ps, ctw));
+ dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION);
+ if (ctw != -1) {
+ cfg->p2p->ops.ctw = ctw;
+ ret = 0;
+ }
+ if (ps != -1) {
+ cfg->p2p->ops.ops = ps;
+ ret = wldev_iovar_setbuf(dev,
+ "p2p_ops", &cfg->p2p->ops, sizeof(cfg->p2p->ops),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (ret < 0) {
+ CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret));
+ }
+ }
+
+ if ((legacy_ps != -1) && ((legacy_ps == PM_MAX) || (legacy_ps == PM_OFF))) {
+ ret = wldev_ioctl(dev,
+ WLC_SET_PM, &legacy_ps, sizeof(legacy_ps), true);
+ if (unlikely(ret))
+ CFGP2P_ERR(("error (%d)\n", ret));
+ wl_cfg80211_update_power_mode(dev);
+ }
+ else
+ CFGP2P_ERR(("ilegal setting\n"));
+ }
+ else {
+ CFGP2P_ERR(("ERROR: set_p2p_ps in non-p2p mode\n"));
+ ret = -1;
+ }
+ return ret;
+}
+
+u8 *
+wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id)
+{
+ wifi_p2p_ie_t *ie = NULL;
+ u16 len = 0;
+ u8 *subel;
+ u8 subelt_id;
+ u16 subelt_len;
+
+ if (!buf) {
+ WL_ERR(("P2P IE not present"));
+ return 0;
+ }
+
+ ie = (wifi_p2p_ie_t*) buf;
+ len = ie->len;
+
+ /* Point subel to the P2P IE's subelt field.
+ * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
+ */
+ subel = ie->subelts;
+ len -= 4; /* exclude OUI + OUI_TYPE */
+
+ while (len >= 3) {
+ /* attribute id */
+ subelt_id = *subel;
+ subel += 1;
+ len -= 1;
+
+ /* 2-byte little endian */
+ subelt_len = *subel++;
+ subelt_len |= *subel++ << 8;
+
+ len -= 2;
+ len -= subelt_len; /* for the remaining subelt fields */
+
+ if (subelt_id == element_id) {
+ /* This will point to start of subelement attrib after
+ * attribute id & len
+ */
+ return subel;
+ }
+
+ /* Go to next subelement */
+ subel += subelt_len;
+ }
+
+ /* Not Found */
+ return NULL;
+}
+
+#define P2P_GROUP_CAPAB_GO_BIT 0x01
+
+u8*
+wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib)
+{
+ bcm_tlv_t *ie;
+ u8* pAttrib;
+
+ CFGP2P_INFO(("Starting parsing parse %p attrib %d remaining len %d ", parse, attrib, len));
+ while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) {
+ if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len) == TRUE) {
+ /* Have the P2p ie. Now check for attribute */
+ if ((pAttrib = wl_cfgp2p_retreive_p2pattrib(parse, attrib)) != NULL) {
+ CFGP2P_INFO(("P2P attribute %d was found at parse %p",
+ attrib, parse));
+ return pAttrib;
+ }
+ else {
+ parse += (ie->len + TLV_HDR_LEN);
+ len -= (ie->len + TLV_HDR_LEN);
+ CFGP2P_INFO(("P2P Attribute %d not found Moving parse"
+ " to %p len to %d", attrib, parse, len));
+ }
+ }
+ else {
+ /* It was not p2p IE. parse will get updated automatically to next TLV */
+ CFGP2P_INFO(("IT was NOT P2P IE parse %p len %d", parse, len));
+ }
+ }
+ CFGP2P_ERR(("P2P attribute %d was NOT found", attrib));
+ return NULL;
+}
+
+u8 *
+wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length)
+{
+ u8 *capability = NULL;
+ bool p2p_go = 0;
+ u8 *ptr = NULL;
+
+ if ((capability = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset,
+ bi->ie_length, P2P_SEID_P2P_INFO)) == NULL) {
+ WL_ERR(("P2P Capability attribute not found"));
+ return NULL;
+ }
+
+ /* Check Group capability for Group Owner bit */
+ p2p_go = capability[1] & P2P_GROUP_CAPAB_GO_BIT;
+ if (!p2p_go) {
+ return bi->BSSID.octet;
+ }
+
+ /* In probe responses, DEVICE INFO attribute will be present */
+ if (!(ptr = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset,
+ bi->ie_length, P2P_SEID_DEV_INFO))) {
+ /* If DEVICE_INFO is not found, this might be a beacon frame.
+ * check for DEVICE_ID in the beacon frame.
+ */
+ ptr = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset,
+ bi->ie_length, P2P_SEID_DEV_ID);
+ }
+
+ if (!ptr)
+ WL_ERR((" Both DEVICE_ID & DEVICE_INFO attribute not present in P2P IE "));
+
+ return ptr;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+static void
+wl_cfgp2p_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
+{
+ snprintf(info->driver, sizeof(info->driver), "p2p");
+ snprintf(info->version, sizeof(info->version), "%lu", (unsigned long)(0));
+}
+
+struct ethtool_ops cfgp2p_ethtool_ops = {
+ .get_drvinfo = wl_cfgp2p_ethtool_get_drvinfo
+};
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
+
+#if defined(WL_ENABLE_P2P_IF) || defined(P2PONEINT)
+#ifdef P2PONEINT
+s32
+wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg)
+{
+
+ struct net_device *_ndev;
+ struct ether_addr primary_mac;
+ struct net_device *new_ndev;
+ chanspec_t chspec;
+ uint8 name[IFNAMSIZ];
+ s32 mode = 0;
+ s32 val = 0;
+
+
+ s32 wlif_type = -1;
+ s32 err, timeout = -1;
+
+ memset(name, 0, IFNAMSIZ);
+ strncpy(name, "p2p0", 4);
+ name[IFNAMSIZ - 1] = '\0';
+
+ if (cfg->p2p_net) {
+ CFGP2P_ERR(("p2p_net defined already.\n"));
+ return -EINVAL;
+ }
+
+ if (!cfg->p2p)
+ return -EINVAL;
+
+ if (cfg->p2p && !cfg->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
+ p2p_on(cfg) = true;
+ wl_cfgp2p_set_firm_p2p(cfg);
+ wl_cfgp2p_init_discovery(cfg);
+ get_primary_mac(cfg, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(&primary_mac,
+ &cfg->p2p->dev_addr, &cfg->p2p->int_addr);
+ }
+
+ _ndev = bcmcfg_to_prmry_ndev(cfg);
+ memset(cfg->p2p->vir_ifname, 0, IFNAMSIZ);
+ strncpy(cfg->p2p->vir_ifname, name, IFNAMSIZ - 1);
+
+ wl_cfg80211_scan_abort(cfg);
+
+
+ /* In concurrency case, STA may be already associated in a particular channel.
+ * so retrieve the current channel of primary interface and then start the virtual
+ * interface on that.
+ */
+ chspec = wl_cfg80211_get_shared_freq(cfg->wdev->wiphy);
+
+ /* For P2P mode, use P2P-specific driver features to create the
+ * bss: "cfg p2p_ifadd"
+ */
+ wl_set_p2p_status(cfg, IF_ADDING);
+ memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
+ wlif_type = WL_P2P_IF_CLIENT;
+
+
+ err = wl_cfgp2p_ifadd(cfg, &cfg->p2p->int_addr, htod32(wlif_type), chspec);
+ if (unlikely(err)) {
+ wl_clr_p2p_status(cfg, IF_ADDING);
+ WL_ERR((" virtual iface add failed (%d) \n", err));
+ return -ENOMEM;
+ }
+
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+ (wl_get_p2p_status(cfg, IF_ADDING) == false),
+ msecs_to_jiffies(MAX_WAIT_TIME));
+
+
+ if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) {
+ struct wireless_dev *vwdev;
+ int pm_mode = PM_ENABLE;
+ wl_if_event_info *event = &cfg->if_event_info;
+
+ /* IF_ADD event has come back, we can proceed to to register
+ * the new interface now, use the interface name provided by caller (thus
+ * ignore the one from wlc)
+ */
+ strncpy(cfg->if_event_info.name, name, IFNAMSIZ - 1);
+ new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, cfg->p2p->vir_ifname,
+ event->mac, event->bssidx, event->name);
+ if (new_ndev == NULL)
+ goto fail;
+
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION) = new_ndev;
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION) = event->bssidx;
+
+ vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
+ if (unlikely(!vwdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ goto fail;
+ }
+ vwdev->wiphy = cfg->wdev->wiphy;
+ WL_TRACE(("virtual interface(%s) is created\n", cfg->p2p->vir_ifname));
+ vwdev->iftype = NL80211_IFTYPE_P2P_DEVICE;
+ vwdev->netdev = new_ndev;
+ new_ndev->ieee80211_ptr = vwdev;
+ SET_NETDEV_DEV(new_ndev, wiphy_dev(vwdev->wiphy));
+ wl_set_drv_status(cfg, READY, new_ndev);
+ wl_set_mode_by_netdev(cfg, new_ndev, mode);
+
+ if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) {
+ wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev);
+ goto fail;
+ }
+
+ wl_alloc_netinfo(cfg, new_ndev, vwdev, mode, pm_mode);
+ val = 1;
+ /* Disable firmware roaming for P2P interface */
+ wldev_iovar_setint(new_ndev, "roam_off", val);
+
+ if (mode != WL_MODE_AP)
+ wldev_iovar_setint(new_ndev, "buf_key_b4_m4", 1);
+
+ WL_ERR((" virtual interface(%s) is "
+ "created net attach done\n", cfg->p2p->vir_ifname));
+
+ /* reinitialize completion to clear previous count */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
+ INIT_COMPLETION(cfg->iface_disable);
+#else
+ init_completion(&cfg->iface_disable);
+#endif
+ cfg->p2p_net = new_ndev;
+ cfg->p2p_wdev = vwdev;
+
+ return 0;
+ } else {
+ wl_clr_p2p_status(cfg, IF_ADDING);
+ WL_ERR((" virtual interface(%s) is not created \n", cfg->p2p->vir_ifname));
+ memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ);
+ }
+
+
+fail:
+ if (wlif_type == WL_P2P_IF_GO)
+ wldev_iovar_setint(_ndev, "mpc", 1);
+ return -ENODEV;
+
+}
+#else
+s32
+wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg)
+{
+ int ret = 0;
+ struct net_device* net = NULL;
+ struct wireless_dev *wdev = NULL;
+ uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 };
+
+ if (cfg->p2p_net) {
+ CFGP2P_ERR(("p2p_net defined already.\n"));
+ return -EINVAL;
+ }
+
+ /* Allocate etherdev, including space for private structure */
+ if (!(net = alloc_etherdev(sizeof(struct bcm_cfg80211 *)))) {
+ CFGP2P_ERR(("%s: OOM - alloc_etherdev\n", __FUNCTION__));
+ return -ENODEV;
+ }
+
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (unlikely(!wdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ free_netdev(net);
+ return -ENOMEM;
+ }
+
+ strncpy(net->name, "p2p%d", sizeof(net->name) - 1);
+ net->name[IFNAMSIZ - 1] = '\0';
+
+ /* Copy the reference to bcm_cfg80211 */
+ memcpy((void *)netdev_priv(net), &cfg, sizeof(struct bcm_cfg80211 *));
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
+ ASSERT(!net->open);
+ net->do_ioctl = wl_cfgp2p_do_ioctl;
+ net->hard_start_xmit = wl_cfgp2p_start_xmit;
+ net->open = wl_cfgp2p_if_open;
+ net->stop = wl_cfgp2p_if_stop;
+#else
+ ASSERT(!net->netdev_ops);
+ net->netdev_ops = &wl_cfgp2p_if_ops;
+#endif
+
+ /* Register with a dummy MAC addr */
+ memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
+
+ wdev->wiphy = cfg->wdev->wiphy;
+
+ wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
+
+ net->ieee80211_ptr = wdev;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+ net->ethtool_ops = &cfgp2p_ethtool_ops;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
+
+ SET_NETDEV_DEV(net, wiphy_dev(wdev->wiphy));
+
+ /* Associate p2p0 network interface with new wdev */
+ wdev->netdev = net;
+
+ ret = register_netdev(net);
+ if (ret) {
+ CFGP2P_ERR((" register_netdevice failed (%d)\n", ret));
+ free_netdev(net);
+ kfree(wdev);
+ return -ENODEV;
+ }
+
+ /* store p2p net ptr for further reference. Note that iflist won't have this
+ * entry as there corresponding firmware interface is a "Hidden" interface.
+ */
+ cfg->p2p_wdev = wdev;
+ cfg->p2p_net = net;
+
+ printk("%s: P2P Interface Registered\n", net->name);
+
+ return ret;
+}
+#endif /* P2PONEINT */
+
+s32
+wl_cfgp2p_unregister_ndev(struct bcm_cfg80211 *cfg)
+{
+
+ if (!cfg || !cfg->p2p_net) {
+ CFGP2P_ERR(("Invalid Ptr\n"));
+ return -EINVAL;
+ }
+
+ unregister_netdev(cfg->p2p_net);
+ free_netdev(cfg->p2p_net);
+
+ return 0;
+}
+
+#ifndef P2PONEINT
+static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+
+ if (skb)
+ {
+ CFGP2P_DBG(("(%s) is not used for data operations.Droping the packet.\n",
+ ndev->name));
+ dev_kfree_skb_any(skb);
+ }
+
+ return 0;
+}
+
+static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd)
+{
+ int ret = 0;
+ struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net);
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+
+ /* There is no ifidx corresponding to p2p0 in our firmware. So we should
+ * not Handle any IOCTL cmds on p2p0 other than ANDROID PRIVATE CMDs.
+ * For Android PRIV CMD handling map it to primary I/F
+ */
+ if (cmd == SIOCDEVPRIVATE+1) {
+ ret = wl_android_priv_cmd(ndev, ifr, cmd);
+
+ } else {
+ CFGP2P_ERR(("%s: IOCTL req 0x%x on p2p0 I/F. Ignoring. \n",
+ __FUNCTION__, cmd));
+ return -1;
+ }
+
+ return ret;
+}
+#endif /* P2PONEINT */
+#endif
+
+
+#if defined(WL_ENABLE_P2P_IF) || defined(P2PONEINT)
+#ifdef P2PONEINT
+int wl_cfgp2p_if_open(struct net_device *net)
+#else
+static int wl_cfgp2p_if_open(struct net_device *net)
+#endif /* P2PONEINT */
+{
+ struct wireless_dev *wdev = net->ieee80211_ptr;
+
+ if (!wdev || !wl_cfg80211_is_p2p_active())
+ return -EINVAL;
+ WL_TRACE(("Enter\n"));
+#if !defined(WL_IFACE_COMB_NUM_CHANNELS)
+ /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now,
+ * do it here. This will make sure that in concurrent mode, supplicant
+ * is not dependent on a particular order of interface initialization.
+ * i.e you may give wpa_supp -iwlan0 -N -ip2p0 or wpa_supp -ip2p0 -N
+ * -iwlan0.
+ */
+ wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT)
+ | BIT(NL80211_IFTYPE_P2P_GO));
+#endif /* !WL_IFACE_COMB_NUM_CHANNELS */
+ wl_cfg80211_do_driver_init(net);
+
+ return 0;
+}
+
+#ifdef P2PONEINT
+int wl_cfgp2p_if_stop(struct net_device *net)
+#else
+static int wl_cfgp2p_if_stop(struct net_device *net)
+#endif
+{
+ struct wireless_dev *wdev = net->ieee80211_ptr;
+#ifdef P2PONEINT
+ bcm_struct_cfgdev *cfgdev;
+#endif
+ if (!wdev)
+ return -EINVAL;
+
+#ifdef P2PONEINT
+ cfgdev = ndev_to_cfgdev(net);
+ wl_cfg80211_scan_stop(cfgdev);
+#else
+ wl_cfg80211_scan_stop(net);
+#endif
+
+#if !defined(WL_IFACE_COMB_NUM_CHANNELS)
+ wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes)
+ & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)|
+ BIT(NL80211_IFTYPE_P2P_GO)));
+#endif /* !WL_IFACE_COMB_NUM_CHANNELS */
+
+ return 0;
+}
+#endif /* defined(WL_ENABLE_P2P_IF) || defined(P2PONEINT) */
+
+#if defined(WL_ENABLE_P2P_IF)
+bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops)
+{
+ return (if_ops == &wl_cfgp2p_if_ops);
+}
+#endif /* WL_ENABLE_P2P_IF */
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+struct wireless_dev *
+wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg)
+{
+ struct wireless_dev *wdev = NULL;
+ struct ether_addr primary_mac;
+
+ if (!cfg || !(cfg->p2p))
+ return ERR_PTR(-EINVAL);
+
+ WL_TRACE(("Enter\n"));
+
+ if (cfg->p2p_wdev) {
+ CFGP2P_ERR(("p2p_wdev defined already.\n"));
+ wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg);
+ CFGP2P_ERR(("p2p_wdev deleted.\n"));
+ }
+
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (unlikely(!wdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ return ERR_PTR(-ENOMEM);
+ }
+
+ memset(&primary_mac, 0, sizeof(primary_mac));
+ get_primary_mac(cfg, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(&primary_mac,
+ &cfg->p2p->dev_addr, &cfg->p2p->int_addr);
+
+ wdev->wiphy = cfg->wdev->wiphy;
+ wdev->iftype = NL80211_IFTYPE_P2P_DEVICE;
+ memcpy(wdev->address, &cfg->p2p->dev_addr, ETHER_ADDR_LEN);
+
+
+ /* store p2p wdev ptr for further reference. */
+ cfg->p2p_wdev = wdev;
+
+ CFGP2P_ERR(("P2P interface registered\n"));
+
+
+ return wdev;
+}
+
+int
+wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ int ret = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+
+ if (!cfg)
+ return -EINVAL;
+
+ WL_TRACE(("Enter\n"));
+
+ ret = wl_cfgp2p_set_firm_p2p(cfg);
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR(("Set P2P in firmware failed, ret=%d\n", ret));
+ goto exit;
+ }
+
+ ret = wl_cfgp2p_enable_discovery(cfg, bcmcfg_to_prmry_ndev(cfg), NULL, 0);
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR(("P2P enable discovery failed, ret=%d\n", ret));
+ goto exit;
+ }
+
+ p2p_on(cfg) = true;
+
+ CFGP2P_DBG(("P2P interface started\n"));
+
+exit:
+ return ret;
+}
+
+void
+wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ int ret = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+
+ if (!cfg)
+ return;
+
+ WL_TRACE(("Enter\n"));
+
+ ret = wl_cfg80211_scan_stop(wdev);
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret));
+ }
+
+ if (!cfg->p2p)
+ return;
+
+ ret = wl_cfgp2p_disable_discovery(cfg);
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR(("P2P disable discovery failed, ret=%d\n", ret));
+ }
+
+ p2p_on(cfg) = false;
+
+ CFGP2P_DBG(("P2P interface stopped\n"));
+
+ return;
+}
+
+
+int
+wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev, struct bcm_cfg80211 *cfg)
+{
+ bool rollback_lock = false;
+
+ if (!wdev)
+ return -EINVAL;
+
+#ifdef P2PONEINT
+ return -EINVAL;
+#endif
+
+ WL_TRACE(("Enter\n"));
+
+ if (!rtnl_is_locked()) {
+ rtnl_lock();
+ rollback_lock = true;
+ }
+
+ cfg80211_unregister_wdev(wdev);
+
+ if (rollback_lock)
+ rtnl_unlock();
+
+ synchronize_rcu();
+
+ kfree(wdev);
+
+ if (cfg)
+ cfg->p2p_wdev = NULL;
+
+ CFGP2P_ERR(("P2P interface unregistered\n"));
+
+
+ return 0;
+}
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+void
+wl_cfgp2p_need_wait_actfrmae(struct bcm_cfg80211 *cfg, void *frame, u32 frame_len, bool tx)
+{
+ wifi_p2p_pub_act_frame_t *pact_frm;
+ int status = 0;
+
+ if (!frame || (frame_len < (sizeof(*pact_frm) + WL_P2P_AF_STATUS_OFFSET - 1))) {
+ return;
+ }
+
+ if (wl_cfgp2p_is_pub_action(frame, frame_len)) {
+ pact_frm = (wifi_p2p_pub_act_frame_t *)frame;
+ if (pact_frm->subtype == P2P_PAF_GON_RSP && tx) {
+ CFGP2P_ACTION(("Check TX P2P Group Owner Negotiation Rsp Frame status\n"));
+ status = pact_frm->elts[WL_P2P_AF_STATUS_OFFSET];
+ if (status) {
+ cfg->need_wait_afrx = false;
+ return;
+ }
+ }
+ }
+
+ cfg->need_wait_afrx = true;
+ return;
+}
+
+int
+wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request)
+{
+ if (request && (request->n_ssids == 1) &&
+ (request->n_channels == 1) &&
+ IS_P2P_SSID(request->ssids[0].ssid, WL_P2P_WILDCARD_SSID_LEN) &&
+ (request->ssids[0].ssid_len > WL_P2P_WILDCARD_SSID_LEN)) {
+ return true;
+ }
+ return false;
+}
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
new file mode 100644
index 000000000000..5108c21c6188
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
@@ -0,0 +1,414 @@
+/*
+ * Linux cfgp2p driver
+ *
+ * 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: wl_cfgp2p.h 662786 2016-11-11 09:06:37Z $
+ */
+#ifndef _wl_cfgp2p_h_
+#define _wl_cfgp2p_h_
+#include <proto/802.11.h>
+#include <proto/p2p.h>
+
+struct bcm_cfg80211;
+extern u32 wl_dbg_level;
+
+typedef struct wifi_p2p_ie wifi_wfd_ie_t;
+/* Enumeration of the usages of the BSSCFGs used by the P2P Library. Do not
+ * confuse this with a bsscfg index. This value is an index into the
+ * saved_ie[] array of structures which in turn contains a bsscfg index field.
+ */
+typedef enum {
+ P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */
+ P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */
+ P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */
+ P2PAPI_BSSCFG_MAX
+} p2p_bsscfg_type_t;
+
+typedef enum {
+ P2P_SCAN_PURPOSE_MIN,
+ P2P_SCAN_SOCIAL_CHANNEL, /* scan for social channel */
+ P2P_SCAN_AFX_PEER_NORMAL, /* scan for action frame search */
+ P2P_SCAN_AFX_PEER_REDUCED, /* scan for action frame search with short time */
+ P2P_SCAN_DURING_CONNECTED, /* scan during connected status */
+ P2P_SCAN_CONNECT_TRY, /* scan for connecting */
+ P2P_SCAN_NORMAL, /* scan during not-connected status */
+ P2P_SCAN_PURPOSE_MAX
+} p2p_scan_purpose_t;
+
+/* vendor ies max buffer length for probe response or beacon */
+#define VNDR_IES_MAX_BUF_LEN 1400
+/* normal vendor ies buffer length */
+#define VNDR_IES_BUF_LEN 512
+
+/* Structure to hold all saved P2P and WPS IEs for a BSSCFG */
+struct p2p_saved_ie {
+ u8 p2p_probe_req_ie[VNDR_IES_BUF_LEN];
+ u8 p2p_probe_res_ie[VNDR_IES_MAX_BUF_LEN];
+ u8 p2p_assoc_req_ie[VNDR_IES_BUF_LEN];
+ u8 p2p_assoc_res_ie[VNDR_IES_BUF_LEN];
+ u8 p2p_beacon_ie[VNDR_IES_MAX_BUF_LEN];
+ u32 p2p_probe_req_ie_len;
+ u32 p2p_probe_res_ie_len;
+ u32 p2p_assoc_req_ie_len;
+ u32 p2p_assoc_res_ie_len;
+ u32 p2p_beacon_ie_len;
+};
+
+struct p2p_bss {
+ u32 bssidx;
+ struct net_device *dev;
+ struct p2p_saved_ie saved_ie;
+ void *private_data;
+};
+
+struct p2p_info {
+ bool on; /* p2p on/off switch */
+ bool scan;
+ int16 search_state;
+ s8 vir_ifname[IFNAMSIZ];
+ unsigned long status;
+ struct ether_addr dev_addr;
+ struct ether_addr int_addr;
+ struct p2p_bss bss[P2PAPI_BSSCFG_MAX];
+ struct timer_list listen_timer;
+ wl_p2p_sched_t noa;
+ wl_p2p_ops_t ops;
+ wlc_ssid_t ssid;
+};
+
+#define MAX_VNDR_IE_NUMBER 10
+
+struct parsed_vndr_ie_info {
+ char *ie_ptr;
+ u32 ie_len; /* total length including id & length field */
+ vndr_ie_t vndrie;
+};
+
+struct parsed_vndr_ies {
+ u32 count;
+ struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER];
+};
+
+/* dongle status */
+enum wl_cfgp2p_status {
+ WLP2P_STATUS_DISCOVERY_ON = 0,
+ WLP2P_STATUS_SEARCH_ENABLED,
+ WLP2P_STATUS_IF_ADDING,
+ WLP2P_STATUS_IF_DELETING,
+ WLP2P_STATUS_IF_CHANGING,
+ WLP2P_STATUS_IF_CHANGED,
+ WLP2P_STATUS_LISTEN_EXPIRED,
+ WLP2P_STATUS_ACTION_TX_COMPLETED,
+ WLP2P_STATUS_ACTION_TX_NOACK,
+ WLP2P_STATUS_SCANNING,
+ WLP2P_STATUS_GO_NEG_PHASE,
+ WLP2P_STATUS_DISC_IN_PROGRESS
+};
+
+
+#define wl_to_p2p_bss_ndev(cfg, type) ((cfg)->p2p->bss[type].dev)
+#define wl_to_p2p_bss_bssidx(cfg, type) ((cfg)->p2p->bss[type].bssidx)
+#define wl_to_p2p_bss_saved_ie(cfg, type) ((cfg)->p2p->bss[type].saved_ie)
+#define wl_to_p2p_bss_private(cfg, type) ((cfg)->p2p->bss[type].private_data)
+#define wl_to_p2p_bss(cfg, type) ((cfg)->p2p->bss[type])
+#define wl_get_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \
+ test_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status))
+#define wl_set_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \
+ set_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status))
+#define wl_clr_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \
+ clear_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status))
+#define wl_chg_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \
+ change_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status))
+#define p2p_on(cfg) ((cfg)->p2p->on)
+#define p2p_scan(cfg) ((cfg)->p2p->scan)
+#define p2p_is_on(cfg) ((cfg)->p2p && (cfg)->p2p->on)
+
+/* dword align allocation */
+#define WLC_IOCTL_MAXLEN 8192
+
+#define CFGP2P_ERROR_TEXT "CFGP2P-ERROR) "
+
+
+#define CFGP2P_ERR(args) \
+ do { \
+ if (wl_dbg_level & WL_DBG_ERR) { \
+ printk(KERN_INFO CFGP2P_ERROR_TEXT "%s : ", __func__); \
+ printk args; \
+ } \
+ } while (0)
+#define CFGP2P_INFO(args) \
+ do { \
+ if (wl_dbg_level & WL_DBG_INFO) { \
+ printk(KERN_INFO "CFGP2P-INFO) %s : ", __func__); \
+ printk args; \
+ } \
+ } while (0)
+#define CFGP2P_DBG(args) \
+ do { \
+ if (wl_dbg_level & WL_DBG_DBG) { \
+ printk(KERN_DEBUG "CFGP2P-DEBUG) %s :", __func__); \
+ printk args; \
+ } \
+ } while (0)
+
+#define CFGP2P_ACTION(args) \
+ do { \
+ if (wl_dbg_level & WL_DBG_P2P_ACTION) { \
+ printk(KERN_DEBUG "CFGP2P-ACTION) %s :", __func__); \
+ printk args; \
+ } \
+ } while (0)
+#define INIT_TIMER(timer, func, duration, extra_delay) \
+ do { \
+ init_timer(timer); \
+ timer->function = func; \
+ timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \
+ timer->data = (unsigned long) cfg; \
+ add_timer(timer); \
+ } while (0);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) && !defined(WL_CFG80211_P2P_DEV_IF)
+#define WL_CFG80211_P2P_DEV_IF
+
+#ifdef WL_ENABLE_P2P_IF
+#undef WL_ENABLE_P2P_IF
+#endif
+
+#ifdef WL_SUPPORT_BACKPORTED_KPATCHES
+#undef WL_SUPPORT_BACKPORTED_KPATCHES
+#endif
+#endif /* (LINUX_VERSION >= VERSION(3, 8, 0)) */
+
+#ifndef WL_CFG80211_P2P_DEV_IF
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+#if defined(WL_ENABLE_P2P_IF) && (defined(WL_CFG80211_P2P_DEV_IF) || \
+ (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)))
+#error Disable 'WL_ENABLE_P2P_IF', if 'WL_CFG80211_P2P_DEV_IF' is enabled \
+ or kernel version is 3.8.0 or above
+#endif /* WL_ENABLE_P2P_IF && (WL_CFG80211_P2P_DEV_IF || (LINUX_VERSION >= VERSION(3, 8, 0))) */
+
+#if !defined(WLP2P) && (defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF))
+#error WLP2P not defined
+#endif /* !WLP2P && (WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF) */
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+#define bcm_struct_cfgdev struct wireless_dev
+#else
+#define bcm_struct_cfgdev struct net_device
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+extern void
+wl_cfgp2p_listen_expired(unsigned long data);
+extern bool
+wl_cfgp2p_is_pub_action(void *frame, u32 frame_len);
+extern bool
+wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len);
+extern bool
+wl_cfgp2p_is_gas_action(void *frame, u32 frame_len);
+extern bool
+wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len);
+extern bool
+wl_cfgp2p_is_p2p_gas_action(void *frame, u32 frame_len);
+extern void
+wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel);
+extern s32
+wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg);
+extern void
+wl_cfgp2p_deinit_priv(struct bcm_cfg80211 *cfg);
+extern s32
+wl_cfgp2p_set_firm_p2p(struct bcm_cfg80211 *cfg);
+extern s32
+wl_cfgp2p_set_p2p_mode(struct bcm_cfg80211 *cfg, u8 mode,
+ u32 channel, u16 listen_ms, int bssidx);
+extern s32
+wl_cfgp2p_ifadd(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type,
+ chanspec_t chspec);
+extern s32
+wl_cfgp2p_ifdisable(struct bcm_cfg80211 *cfg, struct ether_addr *mac);
+extern s32
+wl_cfgp2p_ifdel(struct bcm_cfg80211 *cfg, struct ether_addr *mac);
+extern s32
+wl_cfgp2p_ifchange(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type, chanspec_t chspec);
+
+extern s32
+wl_cfgp2p_ifidx(struct bcm_cfg80211 *cfg, struct ether_addr *mac, s32 *index);
+
+extern s32
+wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg);
+extern s32
+wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev, const u8 *ie,
+ u32 ie_len);
+extern s32
+wl_cfgp2p_disable_discovery(struct bcm_cfg80211 *cfg);
+extern s32
+wl_cfgp2p_escan(struct bcm_cfg80211 *cfg, struct net_device *dev, u16 active, u32 num_chans,
+ u16 *channels,
+ s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr,
+ p2p_scan_purpose_t p2p_scan_purpose);
+
+extern s32
+wl_cfgp2p_act_frm_search(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ s32 bssidx, s32 channel, struct ether_addr *tx_dst_addr);
+
+extern wpa_ie_fixed_t *
+wl_cfgp2p_find_wpaie(u8 *parse, u32 len);
+
+extern wpa_ie_fixed_t *
+wl_cfgp2p_find_wpsie(u8 *parse, u32 len);
+
+extern wifi_p2p_ie_t *
+wl_cfgp2p_find_p2pie(u8 *parse, u32 len);
+
+extern wifi_wfd_ie_t *
+wl_cfgp2p_find_wfdie(u8 *parse, u32 len);
+
+extern struct net_device *
+wl_cfgp2p_find_ndev(struct bcm_cfg80211 *cfg, s32 bssidx);
+extern s32
+wl_cfgp2p_find_type(struct bcm_cfg80211 *cfg, s32 bssidx, s32 *type);
+
+
+extern s32
+wl_cfgp2p_listen_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+extern s32
+wl_cfgp2p_discover_listen(struct bcm_cfg80211 *cfg, s32 channel, u32 duration_ms);
+
+extern s32
+wl_cfgp2p_discover_enable_search(struct bcm_cfg80211 *cfg, u8 enable);
+
+extern s32
+wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+
+extern s32
+wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev,
+ wl_af_params_t *af_params, s32 bssidx);
+
+extern void
+wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, struct ether_addr *out_dev_addr,
+ struct ether_addr *out_int_addr);
+
+extern void
+wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id);
+extern bool
+wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx);
+
+extern s32
+wl_cfgp2p_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 up);
+
+
+extern s32
+wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev);
+
+extern s32
+wl_cfgp2p_down(struct bcm_cfg80211 *cfg);
+
+extern s32
+wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len);
+
+extern s32
+wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len);
+
+extern s32
+wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len);
+
+extern u8 *
+wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id);
+
+extern u8*
+wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib);
+
+extern u8 *
+wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length);
+
+extern s32
+wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg);
+
+extern s32
+wl_cfgp2p_unregister_ndev(struct bcm_cfg80211 *cfg);
+
+extern bool
+wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops);
+
+extern u32
+wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag,
+ s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd);
+
+extern
+int wl_cfgp2p_vif_created(struct bcm_cfg80211 *cfg);
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+extern struct wireless_dev *
+wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg);
+
+extern int
+wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev);
+
+extern void
+wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev);
+
+extern int
+wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev, struct bcm_cfg80211 *cfg);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+extern void
+wl_cfgp2p_need_wait_actfrmae(struct bcm_cfg80211 *cfg, void *frame, u32 frame_len, bool tx);
+
+extern int
+wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request);
+
+/* WiFi Direct */
+#define SOCIAL_CHAN_1 1
+#define SOCIAL_CHAN_2 6
+#define SOCIAL_CHAN_3 11
+#define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \
+ (channel == SOCIAL_CHAN_2) || \
+ (channel == SOCIAL_CHAN_3))
+#define SOCIAL_CHAN_CNT 3
+#define AF_PEER_SEARCH_CNT 2
+#define WL_P2P_WILDCARD_SSID "DIRECT-"
+#define WL_P2P_WILDCARD_SSID_LEN 7
+#define WL_P2P_INTERFACE_PREFIX "p2p"
+#define WL_P2P_TEMP_CHAN 11
+#define WL_P2P_AF_STATUS_OFFSET 9
+
+/* If the provision discovery is for JOIN operations,
+ * or the device discoverablity frame is destined to GO
+ * then we need not do an internal scan to find GO.
+ */
+#define IS_ACTPUB_WITHOUT_GROUP_ID(p2p_ie, len) \
+ (wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_GROUP_ID) == NULL)
+
+#define IS_GAS_REQ(frame, len) (wl_cfgp2p_is_gas_action(frame, len) && \
+ ((frame->action == P2PSD_ACTION_ID_GAS_IREQ) || \
+ (frame->action == P2PSD_ACTION_ID_GAS_CREQ)))
+
+#define IS_P2P_PUB_ACT_RSP_SUBTYPE(subtype) ((subtype == P2P_PAF_GON_RSP) || \
+ ((subtype == P2P_PAF_GON_CONF) || \
+ (subtype == P2P_PAF_INVITE_RSP) || \
+ (subtype == P2P_PAF_PROVDIS_RSP)))
+#define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3))
+#define IS_P2P_SSID(ssid, len) (!memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) && \
+ (len == WL_P2P_WILDCARD_SSID_LEN))
+#endif /* _wl_cfgp2p_h_ */
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd/wl_cfgvendor.c
new file mode 100644
index 000000000000..c17a49e137b2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_cfgvendor.c
@@ -0,0 +1,201 @@
+/*
+ * Linux cfg80211 Vendor Extension Code
+ *
+ * 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: wl_cfgvendor.c 455257 2014-02-13 08:10:24Z $
+*/
+
+/*
+ * New vendor interface additon to nl80211/cfg80211 to allow vendors
+ * to implement proprietary features over the cfg80211 stack.
+*/
+
+#include <typedefs.h>
+#include <linuxver.h>
+#include <osl.h>
+#include <linux/kernel.h>
+
+#include <bcmutils.h>
+#include <bcmwifi_channels.h>
+#include <bcmendian.h>
+#include <proto/ethernet.h>
+#include <proto/802.11.h>
+#include <linux/if_arp.h>
+#include <asm/uaccess.h>
+
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhdioctl.h>
+#include <wlioctl.h>
+#include <dhd_cfg80211.h>
+#ifdef PNO_SUPPORT
+#include <dhd_pno.h>
+#endif /* PNO_SUPPORT */
+
+#include <proto/ethernet.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <linux/wait.h>
+#include <net/cfg80211.h>
+#include <net/rtnetlink.h>
+
+#include <wlioctl.h>
+#include <wldev_common.h>
+#include <wl_cfg80211.h>
+#include <wl_cfgp2p.h>
+#include <wl_android.h>
+#include <wl_cfgvendor.h>
+#ifdef PROP_TXSTATUS
+#include <dhd_wlfc.h>
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
+/*
+ * This API is to be used for asynchronous vendor events. This
+ * shouldn't be used in response to a vendor command from its
+ * do_it handler context (instead wl_cfgvendor_send_cmd_reply should
+ * be used).
+ */
+int wl_cfgvendor_send_async_event(struct wiphy *wiphy,
+ struct net_device *dev, int event_id, const void *data, int len)
+{
+ u16 kflags;
+ struct sk_buff *skb;
+
+ kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
+
+ /* Alloc the SKB for vendor_event */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
+ skb = cfg80211_vendor_event_alloc(wiphy, NULL, len, event_id, kflags);
+#else
+ skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, kflags);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
+ if (!skb) {
+ WL_ERR(("skb alloc failed"));
+ return -ENOMEM;
+ }
+
+ /* Push the data to the skb */
+ nla_put_nohdr(skb, len, data);
+
+ cfg80211_vendor_event(skb, kflags);
+
+ return 0;
+}
+
+static int wl_cfgvendor_send_cmd_reply(struct wiphy *wiphy,
+ struct net_device *dev, const void *data, int len)
+{
+ struct sk_buff *skb;
+
+ /* Alloc the SKB for vendor_event */
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
+ if (unlikely(!skb)) {
+ WL_ERR(("skb alloc failed"));
+ return -ENOMEM;
+ }
+
+ /* Push the data to the skb */
+ nla_put_nohdr(skb, len, data);
+
+ return cfg80211_vendor_cmd_reply(skb);
+}
+
+static int wl_cfgvendor_priv_string_handler(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ int err = 0;
+ int data_len = 0;
+
+ WL_INFO(("%s: Enter \n", __func__));
+
+ bzero(cfg->ioctl_buf, WLC_IOCTL_MAXLEN);
+
+ if (strncmp((char *)data, BRCM_VENDOR_SCMD_CAPA, strlen(BRCM_VENDOR_SCMD_CAPA)) == 0) {
+ err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cap", NULL, 0,
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+ data_len = strlen(cfg->ioctl_buf);
+ cfg->ioctl_buf[data_len] = '\0';
+ }
+
+ err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
+ cfg->ioctl_buf, data_len+1);
+ if (unlikely(err))
+ WL_ERR(("Vendor Command reply failed ret:%d \n", err));
+ else
+ WL_INFO(("Vendor Command reply sent successfully!\n"));
+
+ return err;
+}
+
+static const struct wiphy_vendor_command wl_vendor_cmds [] = {
+ {
+ {
+ .vendor_id = OUI_BRCM,
+ .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_priv_string_handler
+ },
+};
+
+static const struct nl80211_vendor_cmd_info wl_vendor_events [] = {
+ { OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC },
+ { OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR },
+};
+
+int wl_cfgvendor_attach(struct wiphy *wiphy)
+{
+
+ WL_INFO(("Vendor: Register BRCM cfg80211 vendor cmd(0x%x) interface \n",
+ NL80211_CMD_VENDOR));
+
+ wiphy->vendor_commands = wl_vendor_cmds;
+ wiphy->n_vendor_commands = ARRAY_SIZE(wl_vendor_cmds);
+ wiphy->vendor_events = wl_vendor_events;
+ wiphy->n_vendor_events = ARRAY_SIZE(wl_vendor_events);
+
+ return 0;
+}
+
+int wl_cfgvendor_detach(struct wiphy *wiphy)
+{
+ WL_INFO(("Vendor: Unregister BRCM cfg80211 vendor interface \n"));
+
+ wiphy->vendor_commands = NULL;
+ wiphy->vendor_events = NULL;
+ wiphy->n_vendor_commands = 0;
+ wiphy->n_vendor_events = 0;
+
+ return 0;
+}
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgvendor.h b/drivers/net/wireless/bcmdhd/wl_cfgvendor.h
new file mode 100644
index 000000000000..349a9f145698
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_cfgvendor.h
@@ -0,0 +1,56 @@
+/*
+ * Linux cfg80211 Vendor Extension Code
+ *
+ * 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: wl_cfgvendor.h 455257 2014-02-13 08:10:24Z $
+ */
+
+/*
+ * New vendor interface additon to nl80211/cfg80211 to allow vendors
+ * to implement proprietary features over the cfg80211 stack.
+ */
+
+#ifndef _wl_cfgvendor_h_
+#define _wl_cfgvendor_h_
+
+#define OUI_BRCM 0x001018
+#define BRCM_VENDOR_SUBCMD_PRIV_STR 1
+
+enum wl_vendor_subcmd {
+ BRCM_VENDOR_SCMD_UNSPEC,
+ BRCM_VENDOR_SCMD_PRIV_STR
+};
+
+enum wl_vendor_event {
+ BRCM_VENDOR_EVENT_UNSPEC,
+ BRCM_VENDOR_EVENT_PRIV_STR
+};
+
+/* Capture the BRCM_VENDOR_SUBCMD_PRIV_STRINGS* here */
+#define BRCM_VENDOR_SCMD_CAPA "cap"
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
+extern int wl_cfgvendor_attach(struct wiphy *wiphy);
+extern int wl_cfgvendor_detach(struct wiphy *wiphy);
+#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
+
+#endif /* _wl_cfgvendor_h_ */
diff --git a/drivers/net/wireless/bcmdhd/wl_dbg.h b/drivers/net/wireless/bcmdhd/wl_dbg.h
new file mode 100644
index 000000000000..cddd29bbdde0
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_dbg.h
@@ -0,0 +1,67 @@
+/*
+ * Minimal debug/trace/assert driver definitions for
+ * Broadcom 802.11 Networking Adapter.
+ *
+ * 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: wl_dbg.h 430628 2013-10-19 04:07:25Z $
+ */
+
+
+#ifndef _wl_dbg_h_
+#define _wl_dbg_h_
+
+/* wl_msg_level is a bit vector with defs in wlioctl.h */
+extern uint32 wl_msg_level;
+extern uint32 wl_msg_level2;
+
+#define WL_TIMESTAMP()
+
+#define WL_PRINT(args) do { WL_TIMESTAMP(); printf args; } while (0)
+
+#if defined(EVENT_LOG_COMPILE) && defined(WLMSG_SRSCAN)
+#define _WL_SRSCAN(fmt, ...) EVENT_LOG(EVENT_LOG_TAG_SRSCAN, fmt, ##__VA_ARGS__)
+#define WL_SRSCAN(args) _WL_SRSCAN args
+#else
+#define WL_SRSCAN(args)
+#endif
+
+
+/* To disable a message completely ... until you need it again */
+#define WL_NONE(args)
+
+#define WL_ERROR(args)
+#define WL_TRACE(args)
+#define WL_APSTA_UPDN(args)
+#define WL_APSTA_RX(args)
+#ifdef WLMSG_WSEC
+#define WL_WSEC(args) WL_PRINT(args)
+#define WL_WSEC_DUMP(args) WL_PRINT(args)
+#else
+#define WL_WSEC(args)
+#define WL_WSEC_DUMP(args)
+#endif
+#define WL_PCIE(args) do {if (wl_msg_level2 & WL_PCIE_VAL) WL_PRINT(args);} while (0)
+#define WL_PCIE_ON() (wl_msg_level2 & WL_PCIE_VAL)
+
+extern uint32 wl_msg_level;
+extern uint32 wl_msg_level2;
+#endif /* _wl_dbg_h_ */
diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c
new file mode 100644
index 000000000000..a14e57155ae9
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_iw.c
@@ -0,0 +1,3689 @@
+/*
+ * Linux Wireless Extensions support
+ *
+ * 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: wl_iw.c 425990 2013-09-26 07:28:16Z $
+ */
+
+#if defined(USE_IW)
+#define LINUX_PORT
+
+#include <typedefs.h>
+#include <linuxver.h>
+#include <osl.h>
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <proto/ethernet.h>
+
+#include <linux/if_arp.h>
+#include <asm/uaccess.h>
+
+typedef const struct si_pub si_t;
+#include <wlioctl.h>
+
+
+#include <wl_dbg.h>
+#include <wl_iw.h>
+
+
+/* Broadcom extensions to WEXT, linux upstream has obsoleted WEXT */
+#ifndef IW_AUTH_KEY_MGMT_FT_802_1X
+#define IW_AUTH_KEY_MGMT_FT_802_1X 0x04
+#endif
+
+#ifndef IW_AUTH_KEY_MGMT_FT_PSK
+#define IW_AUTH_KEY_MGMT_FT_PSK 0x08
+#endif
+
+#ifndef IW_ENC_CAPA_FW_ROAM_ENABLE
+#define IW_ENC_CAPA_FW_ROAM_ENABLE 0x00000020
+#endif
+
+
+/* FC9: wireless.h 2.6.25-14.fc9.i686 is missing these, even though WIRELESS_EXT is set to latest
+ * version 22.
+ */
+#ifndef IW_ENCODE_ALG_PMK
+#define IW_ENCODE_ALG_PMK 4
+#endif
+#ifndef IW_ENC_CAPA_4WAY_HANDSHAKE
+#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010
+#endif
+/* End FC9. */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+#include <linux/rtnetlink.h>
+#endif
+#if defined(SOFTAP)
+struct net_device *ap_net_dev = NULL;
+tsk_ctl_t ap_eth_ctl; /* apsta AP netdev waiter thread */
+#endif /* SOFTAP */
+
+extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status,
+ uint32 reason, char* stringBuf, uint buflen);
+
+uint wl_msg_level = WL_ERROR_VAL;
+
+#define MAX_WLIW_IOCTL_LEN 1024
+
+/* IOCTL swapping mode for Big Endian host with Little Endian dongle. Default to off */
+#define htod32(i) (i)
+#define htod16(i) (i)
+#define dtoh32(i) (i)
+#define dtoh16(i) (i)
+#define htodchanspec(i) (i)
+#define dtohchanspec(i) (i)
+
+extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
+extern int dhd_wait_pend8021x(struct net_device *dev);
+
+#if WIRELESS_EXT < 19
+#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST)
+#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST)
+#endif /* WIRELESS_EXT < 19 */
+
+
+#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) + 1))); \
+ } while (0);
+#endif /* LINUX_VERSION_CODE */
+
+#define ISCAN_STATE_IDLE 0
+#define ISCAN_STATE_SCANING 1
+
+/* the buf lengh can be WLC_IOCTL_MAXLEN (8K) to reduce iteration */
+#define WLC_IW_ISCAN_MAXLEN 2048
+typedef struct iscan_buf {
+ struct iscan_buf * next;
+ char iscan_buf[WLC_IW_ISCAN_MAXLEN];
+} iscan_buf_t;
+
+typedef struct iscan_info {
+ struct net_device *dev;
+ struct timer_list timer;
+ uint32 timer_ms;
+ uint32 timer_on;
+ int iscan_state;
+ iscan_buf_t * list_hdr;
+ iscan_buf_t * list_cur;
+
+ /* Thread to work on iscan */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
+ struct task_struct *kthread;
+#endif
+ long sysioc_pid;
+ struct semaphore sysioc_sem;
+ struct completion sysioc_exited;
+
+
+ char ioctlbuf[WLC_IOCTL_SMLEN];
+} iscan_info_t;
+iscan_info_t *g_iscan = NULL;
+static void wl_iw_timerfunc(ulong data);
+static void wl_iw_set_event_mask(struct net_device *dev);
+static int wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action);
+
+/* priv_link becomes netdev->priv and is the link between netdev and wlif struct */
+typedef struct priv_link {
+ wl_iw_t *wliw;
+} priv_link_t;
+
+/* dev to priv_link */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24))
+#define WL_DEV_LINK(dev) (priv_link_t*)(dev->priv)
+#else
+#define WL_DEV_LINK(dev) (priv_link_t*)netdev_priv(dev)
+#endif
+
+/* dev to wl_iw_t */
+#define IW_DEV_IF(dev) ((wl_iw_t*)(WL_DEV_LINK(dev))->wliw)
+
+static void swap_key_from_BE(
+ wl_wsec_key_t *key
+)
+{
+ key->index = htod32(key->index);
+ key->len = htod32(key->len);
+ key->algo = htod32(key->algo);
+ key->flags = htod32(key->flags);
+ key->rxiv.hi = htod32(key->rxiv.hi);
+ key->rxiv.lo = htod16(key->rxiv.lo);
+ key->iv_initialized = htod32(key->iv_initialized);
+}
+
+static void swap_key_to_BE(
+ wl_wsec_key_t *key
+)
+{
+ key->index = dtoh32(key->index);
+ key->len = dtoh32(key->len);
+ key->algo = dtoh32(key->algo);
+ key->flags = dtoh32(key->flags);
+ key->rxiv.hi = dtoh32(key->rxiv.hi);
+ key->rxiv.lo = dtoh16(key->rxiv.lo);
+ key->iv_initialized = dtoh32(key->iv_initialized);
+}
+
+static int
+dev_wlc_ioctl(
+ struct net_device *dev,
+ int cmd,
+ void *arg,
+ int len
+)
+{
+ struct ifreq ifr;
+ wl_ioctl_t ioc;
+ mm_segment_t fs;
+ int ret;
+
+ memset(&ioc, 0, sizeof(ioc));
+ ioc.cmd = cmd;
+ ioc.buf = arg;
+ ioc.len = len;
+
+ strcpy(ifr.ifr_name, dev->name);
+ ifr.ifr_data = (caddr_t) &ioc;
+
+ fs = get_fs();
+ set_fs(get_ds());
+#if defined(WL_USE_NETDEV_OPS)
+ ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
+#else
+ ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
+#endif
+ set_fs(fs);
+
+ return ret;
+}
+
+/*
+set named driver variable to int value and return error indication
+calling example: dev_wlc_intvar_set(dev, "arate", rate)
+*/
+
+static int
+dev_wlc_intvar_set(
+ struct net_device *dev,
+ char *name,
+ int val)
+{
+ char buf[WLC_IOCTL_SMLEN];
+ uint len;
+
+ val = htod32(val);
+ len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
+ ASSERT(len);
+
+ return (dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len));
+}
+
+static int
+dev_iw_iovar_setbuf(
+ struct net_device *dev,
+ char *iovar,
+ void *param,
+ int paramlen,
+ void *bufptr,
+ int buflen)
+{
+ int iolen;
+
+ iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
+ ASSERT(iolen);
+ BCM_REFERENCE(iolen);
+
+ return (dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen));
+}
+
+static int
+dev_iw_iovar_getbuf(
+ struct net_device *dev,
+ char *iovar,
+ void *param,
+ int paramlen,
+ void *bufptr,
+ int buflen)
+{
+ int iolen;
+
+ iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
+ ASSERT(iolen);
+ BCM_REFERENCE(iolen);
+
+ return (dev_wlc_ioctl(dev, WLC_GET_VAR, bufptr, buflen));
+}
+
+#if WIRELESS_EXT > 17
+static int
+dev_wlc_bufvar_set(
+ struct net_device *dev,
+ char *name,
+ char *buf, int len)
+{
+ char *ioctlbuf;
+ uint buflen;
+ int error;
+
+ ioctlbuf = kmalloc(MAX_WLIW_IOCTL_LEN, GFP_KERNEL);
+ if (!ioctlbuf)
+ return -ENOMEM;
+
+ buflen = bcm_mkiovar(name, buf, len, ioctlbuf, MAX_WLIW_IOCTL_LEN);
+ ASSERT(buflen);
+ error = dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen);
+
+ kfree(ioctlbuf);
+ return error;
+}
+#endif /* WIRELESS_EXT > 17 */
+
+/*
+get named driver variable to int value and return error indication
+calling example: dev_wlc_bufvar_get(dev, "arate", &rate)
+*/
+
+static int
+dev_wlc_bufvar_get(
+ struct net_device *dev,
+ char *name,
+ char *buf, int buflen)
+{
+ char *ioctlbuf;
+ int error;
+
+ uint len;
+
+ ioctlbuf = kmalloc(MAX_WLIW_IOCTL_LEN, GFP_KERNEL);
+ if (!ioctlbuf)
+ return -ENOMEM;
+ len = bcm_mkiovar(name, NULL, 0, ioctlbuf, MAX_WLIW_IOCTL_LEN);
+ ASSERT(len);
+ BCM_REFERENCE(len);
+ error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf, MAX_WLIW_IOCTL_LEN);
+ if (!error)
+ bcopy(ioctlbuf, buf, buflen);
+
+ kfree(ioctlbuf);
+ return (error);
+}
+
+/*
+get named driver variable to int value and return error indication
+calling example: dev_wlc_intvar_get(dev, "arate", &rate)
+*/
+
+static int
+dev_wlc_intvar_get(
+ struct net_device *dev,
+ char *name,
+ int *retval)
+{
+ union {
+ char buf[WLC_IOCTL_SMLEN];
+ int val;
+ } var;
+ int error;
+
+ uint len;
+ uint data_null;
+
+ len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf));
+ ASSERT(len);
+ error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
+
+ *retval = dtoh32(var.val);
+
+ return (error);
+}
+
+/* Maintain backward compatibility */
+#if WIRELESS_EXT < 13
+struct iw_request_info
+{
+ __u16 cmd; /* Wireless Extension command */
+ __u16 flags; /* More to come ;-) */
+};
+
+typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info,
+ void *wrqu, char *extra);
+#endif /* WIRELESS_EXT < 13 */
+
+#if WIRELESS_EXT > 12
+static int
+wl_iw_set_leddc(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ int dc = *(int *)extra;
+ int error;
+
+ error = dev_wlc_intvar_set(dev, "leddc", dc);
+ return error;
+}
+
+static int
+wl_iw_set_vlanmode(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ int mode = *(int *)extra;
+ int error;
+
+ mode = htod32(mode);
+ error = dev_wlc_intvar_set(dev, "vlan_mode", mode);
+ return error;
+}
+
+static int
+wl_iw_set_pm(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ int pm = *(int *)extra;
+ int error;
+
+ pm = htod32(pm);
+ error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
+ return error;
+}
+
+#if WIRELESS_EXT > 17
+#endif /* WIRELESS_EXT > 17 */
+#endif /* WIRELESS_EXT > 12 */
+
+int
+wl_iw_send_priv_event(
+ struct net_device *dev,
+ char *flag
+)
+{
+ union iwreq_data wrqu;
+ char extra[IW_CUSTOM_MAX + 1];
+ int cmd;
+
+ cmd = IWEVCUSTOM;
+ memset(&wrqu, 0, sizeof(wrqu));
+ if (strlen(flag) > sizeof(extra))
+ return -1;
+
+ strcpy(extra, flag);
+ wrqu.data.length = strlen(extra);
+ wireless_send_event(dev, cmd, &wrqu, extra);
+ WL_TRACE(("Send IWEVCUSTOM Event as %s\n", extra));
+
+ return 0;
+}
+
+static int
+wl_iw_config_commit(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ void *zwrq,
+ char *extra
+)
+{
+ wlc_ssid_t ssid;
+ int error;
+ struct sockaddr bssid;
+
+ WL_TRACE(("%s: SIOCSIWCOMMIT\n", dev->name));
+
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid))))
+ return error;
+
+ ssid.SSID_len = dtoh32(ssid.SSID_len);
+
+ if (!ssid.SSID_len)
+ return 0;
+
+ bzero(&bssid, sizeof(struct sockaddr));
+ if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN))) {
+ WL_ERROR(("%s: WLC_REASSOC failed (%d)\n", __FUNCTION__, error));
+ return error;
+ }
+
+ return 0;
+}
+
+static int
+wl_iw_get_name(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *cwrq,
+ char *extra
+)
+{
+ int phytype, err;
+ uint band[3];
+ char cap[5];
+
+ WL_TRACE(("%s: SIOCGIWNAME\n", dev->name));
+
+ cap[0] = 0;
+ if ((err = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype))) < 0)
+ goto done;
+ if ((err = dev_wlc_ioctl(dev, WLC_GET_BANDLIST, band, sizeof(band))) < 0)
+ goto done;
+
+ band[0] = dtoh32(band[0]);
+ switch (phytype) {
+ case WLC_PHY_TYPE_A:
+ strcpy(cap, "a");
+ break;
+ case WLC_PHY_TYPE_B:
+ strcpy(cap, "b");
+ break;
+ case WLC_PHY_TYPE_LP:
+ case WLC_PHY_TYPE_G:
+ if (band[0] >= 2)
+ strcpy(cap, "abg");
+ else
+ strcpy(cap, "bg");
+ break;
+ case WLC_PHY_TYPE_N:
+ if (band[0] >= 2)
+ strcpy(cap, "abgn");
+ else
+ strcpy(cap, "bgn");
+ break;
+ }
+done:
+ snprintf(cwrq->name, IFNAMSIZ, "IEEE 802.11%s", cap);
+ return 0;
+}
+
+static int
+wl_iw_set_freq(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *fwrq,
+ char *extra
+)
+{
+ int error, chan;
+ uint sf = 0;
+
+ WL_TRACE(("%s: SIOCSIWFREQ\n", dev->name));
+
+ /* Setting by channel number */
+ if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) {
+ chan = fwrq->m;
+ }
+
+ /* Setting by frequency */
+ else {
+ /* Convert to MHz as best we can */
+ if (fwrq->e >= 6) {
+ fwrq->e -= 6;
+ while (fwrq->e--)
+ fwrq->m *= 10;
+ } else if (fwrq->e < 6) {
+ while (fwrq->e++ < 6)
+ fwrq->m /= 10;
+ }
+ /* handle 4.9GHz frequencies as Japan 4 GHz based channelization */
+ if (fwrq->m > 4000 && fwrq->m < 5000)
+ sf = WF_CHAN_FACTOR_4_G; /* start factor for 4 GHz */
+
+ chan = wf_mhz2channel(fwrq->m, sf);
+ }
+ chan = htod32(chan);
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan))))
+ return error;
+
+ /* -EINPROGRESS: Call commit handler */
+ return -EINPROGRESS;
+}
+
+static int
+wl_iw_get_freq(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *fwrq,
+ char *extra
+)
+{
+ channel_info_t ci;
+ int error;
+
+ WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name));
+
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
+ return error;
+
+ /* Return radio channel in channel form */
+ fwrq->m = dtoh32(ci.hw_channel);
+ fwrq->e = dtoh32(0);
+ return 0;
+}
+
+static int
+wl_iw_set_mode(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ __u32 *uwrq,
+ char *extra
+)
+{
+ int infra = 0, ap = 0, error = 0;
+
+ WL_TRACE(("%s: SIOCSIWMODE\n", dev->name));
+
+ switch (*uwrq) {
+ case IW_MODE_MASTER:
+ infra = ap = 1;
+ break;
+ case IW_MODE_ADHOC:
+ case IW_MODE_AUTO:
+ break;
+ case IW_MODE_INFRA:
+ infra = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ infra = htod32(infra);
+ ap = htod32(ap);
+
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra))) ||
+ (error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap))))
+ return error;
+
+ /* -EINPROGRESS: Call commit handler */
+ return -EINPROGRESS;
+}
+
+static int
+wl_iw_get_mode(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ __u32 *uwrq,
+ char *extra
+)
+{
+ int error, infra = 0, ap = 0;
+
+ WL_TRACE(("%s: SIOCGIWMODE\n", dev->name));
+
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra))) ||
+ (error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap))))
+ return error;
+
+ infra = dtoh32(infra);
+ ap = dtoh32(ap);
+ *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC;
+
+ return 0;
+}
+
+static int
+wl_iw_get_range(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra
+)
+{
+ struct iw_range *range = (struct iw_range *) extra;
+ static int channels[MAXCHANNEL+1];
+ wl_uint32_list_t *list = (wl_uint32_list_t *) channels;
+ wl_rateset_t rateset;
+ int error, i, k;
+ uint sf, ch;
+
+ int phytype;
+ int bw_cap = 0, sgi_tx = 0, nmode = 0;
+ channel_info_t ci;
+ uint8 nrate_list2copy = 0;
+ uint16 nrate_list[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130},
+ {14, 29, 43, 58, 87, 116, 130, 144},
+ {27, 54, 81, 108, 162, 216, 243, 270},
+ {30, 60, 90, 120, 180, 240, 270, 300}};
+ int fbt_cap = 0;
+
+ WL_TRACE(("%s: SIOCGIWRANGE\n", dev->name));
+
+ if (!extra)
+ return -EINVAL;
+
+ dwrq->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(*range));
+
+ /* We don't use nwids */
+ range->min_nwid = range->max_nwid = 0;
+
+ /* Set available channels/frequencies */
+ list->count = htod32(MAXCHANNEL);
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, sizeof(channels))))
+ return error;
+ for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) {
+ range->freq[i].i = dtoh32(list->element[i]);
+
+ ch = dtoh32(list->element[i]);
+ if (ch <= CH_MAX_2G_CHANNEL)
+ sf = WF_CHAN_FACTOR_2_4_G;
+ else
+ sf = WF_CHAN_FACTOR_5_G;
+
+ range->freq[i].m = wf_channel2mhz(ch, sf);
+ range->freq[i].e = 6;
+ }
+ range->num_frequency = range->num_channels = i;
+
+ /* Link quality (use NDIS cutoffs) */
+ range->max_qual.qual = 5;
+ /* Signal level (use RSSI) */
+ range->max_qual.level = 0x100 - 200; /* -200 dBm */
+ /* Noise level (use noise) */
+ range->max_qual.noise = 0x100 - 200; /* -200 dBm */
+ /* Signal level threshold range (?) */
+ range->sensitivity = 65535;
+
+#if WIRELESS_EXT > 11
+ /* Link quality (use NDIS cutoffs) */
+ range->avg_qual.qual = 3;
+ /* Signal level (use RSSI) */
+ range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD;
+ /* Noise level (use noise) */
+ range->avg_qual.noise = 0x100 - 75; /* -75 dBm */
+#endif /* WIRELESS_EXT > 11 */
+
+ /* Set available bitrates */
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset))))
+ return error;
+ rateset.count = dtoh32(rateset.count);
+ range->num_bitrates = rateset.count;
+ for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++)
+ range->bitrate[i] = (rateset.rates[i] & 0x7f) * 500000; /* convert to bps */
+ if ((error = dev_wlc_intvar_get(dev, "nmode", &nmode)))
+ return error;
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype))))
+ return error;
+ if (nmode == 1 && ((phytype == WLC_PHY_TYPE_SSN) || (phytype == WLC_PHY_TYPE_LCN) ||
+ (phytype == WLC_PHY_TYPE_LCN40))) {
+ if ((error = dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap)))
+ return error;
+ if ((error = dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx)))
+ return error;
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t))))
+ return error;
+ ci.hw_channel = dtoh32(ci.hw_channel);
+
+ if (bw_cap == 0 ||
+ (bw_cap == 2 && ci.hw_channel <= 14)) {
+ if (sgi_tx == 0)
+ nrate_list2copy = 0;
+ else
+ nrate_list2copy = 1;
+ }
+ if (bw_cap == 1 ||
+ (bw_cap == 2 && ci.hw_channel >= 36)) {
+ if (sgi_tx == 0)
+ nrate_list2copy = 2;
+ else
+ nrate_list2copy = 3;
+ }
+ range->num_bitrates += 8;
+ ASSERT(range->num_bitrates < IW_MAX_BITRATES);
+ for (k = 0; i < range->num_bitrates; k++, i++) {
+ /* convert to bps */
+ range->bitrate[i] = (nrate_list[nrate_list2copy][k]) * 500000;
+ }
+ }
+
+ /* Set an indication of the max TCP throughput
+ * in bit/s that we can expect using this interface.
+ * May be use for QoS stuff... Jean II
+ */
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i))))
+ return error;
+ i = dtoh32(i);
+ if (i == WLC_PHY_TYPE_A)
+ range->throughput = 24000000; /* 24 Mbits/s */
+ else
+ range->throughput = 1500000; /* 1.5 Mbits/s */
+
+ /* RTS and fragmentation thresholds */
+ range->min_rts = 0;
+ range->max_rts = 2347;
+ range->min_frag = 256;
+ range->max_frag = 2346;
+
+ range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS;
+ range->num_encoding_sizes = 4;
+ range->encoding_size[0] = WEP1_KEY_SIZE;
+ range->encoding_size[1] = WEP128_KEY_SIZE;
+#if WIRELESS_EXT > 17
+ range->encoding_size[2] = TKIP_KEY_SIZE;
+#else
+ range->encoding_size[2] = 0;
+#endif
+ range->encoding_size[3] = AES_KEY_SIZE;
+
+ /* Do not support power micro-management */
+ range->min_pmp = 0;
+ range->max_pmp = 0;
+ range->min_pmt = 0;
+ range->max_pmt = 0;
+ range->pmp_flags = 0;
+ range->pm_capa = 0;
+
+ /* Transmit Power - values are in mW */
+ range->num_txpower = 2;
+ range->txpower[0] = 1;
+ range->txpower[1] = 255;
+ range->txpower_capa = IW_TXPOW_MWATT;
+
+#if WIRELESS_EXT > 10
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = 19;
+
+ /* Only support retry limits */
+ range->retry_capa = IW_RETRY_LIMIT;
+ range->retry_flags = IW_RETRY_LIMIT;
+ range->r_time_flags = 0;
+ /* SRL and LRL limits */
+ range->min_retry = 1;
+ range->max_retry = 255;
+ /* Retry lifetime limits unsupported */
+ range->min_r_time = 0;
+ range->max_r_time = 0;
+#endif /* WIRELESS_EXT > 10 */
+
+#if WIRELESS_EXT > 17
+ range->enc_capa = IW_ENC_CAPA_WPA;
+ range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
+ range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
+ range->enc_capa |= IW_ENC_CAPA_WPA2;
+
+ /* Determine driver FBT capability. */
+ if (dev_wlc_intvar_get(dev, "fbt_cap", &fbt_cap) == 0) {
+ if (fbt_cap == WLC_FBT_CAP_DRV_4WAY_AND_REASSOC) {
+ /* Tell the host (e.g. wpa_supplicant) to let driver do the handshake */
+ range->enc_capa |= IW_ENC_CAPA_4WAY_HANDSHAKE;
+ }
+ }
+
+#ifdef BCMFW_ROAM_ENABLE_WEXT
+ /* Advertise firmware roam capability to the external supplicant */
+ range->enc_capa |= IW_ENC_CAPA_FW_ROAM_ENABLE;
+#endif /* BCMFW_ROAM_ENABLE_WEXT */
+
+ /* Event capability (kernel) */
+ IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
+ /* Event capability (driver) */
+ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
+ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
+ IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
+ IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE);
+ IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCREQIE);
+ IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCRESPIE);
+ IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND);
+
+#if WIRELESS_EXT >= 22 && defined(IW_SCAN_CAPA_ESSID)
+ /* FC7 wireless.h defines EXT 22 but doesn't define scan_capa bits */
+ range->scan_capa = IW_SCAN_CAPA_ESSID;
+#endif
+#endif /* WIRELESS_EXT > 17 */
+
+ return 0;
+}
+
+static int
+rssi_to_qual(int rssi)
+{
+ if (rssi <= WL_IW_RSSI_NO_SIGNAL)
+ return 0;
+ else if (rssi <= WL_IW_RSSI_VERY_LOW)
+ return 1;
+ else if (rssi <= WL_IW_RSSI_LOW)
+ return 2;
+ else if (rssi <= WL_IW_RSSI_GOOD)
+ return 3;
+ else if (rssi <= WL_IW_RSSI_VERY_GOOD)
+ return 4;
+ else
+ return 5;
+}
+
+static int
+wl_iw_set_spy(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra
+)
+{
+ wl_iw_t *iw = IW_DEV_IF(dev);
+ struct sockaddr *addr = (struct sockaddr *) extra;
+ int i;
+
+ WL_TRACE(("%s: SIOCSIWSPY\n", dev->name));
+
+ if (!extra)
+ return -EINVAL;
+
+ iw->spy_num = MIN(ARRAYSIZE(iw->spy_addr), dwrq->length);
+ for (i = 0; i < iw->spy_num; i++)
+ memcpy(&iw->spy_addr[i], addr[i].sa_data, ETHER_ADDR_LEN);
+ memset(iw->spy_qual, 0, sizeof(iw->spy_qual));
+
+ return 0;
+}
+
+static int
+wl_iw_get_spy(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra
+)
+{
+ wl_iw_t *iw = IW_DEV_IF(dev);
+ struct sockaddr *addr = (struct sockaddr *) extra;
+ struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num];
+ int i;
+
+ WL_TRACE(("%s: SIOCGIWSPY\n", dev->name));
+
+ if (!extra)
+ return -EINVAL;
+
+ dwrq->length = iw->spy_num;
+ for (i = 0; i < iw->spy_num; i++) {
+ memcpy(addr[i].sa_data, &iw->spy_addr[i], ETHER_ADDR_LEN);
+ addr[i].sa_family = AF_UNIX;
+ memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality));
+ iw->spy_qual[i].updated = 0;
+ }
+
+ return 0;
+}
+
+static int
+wl_iw_set_wap(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *awrq,
+ char *extra
+)
+{
+ int error = -EINVAL;
+
+ WL_TRACE(("%s: SIOCSIWAP\n", dev->name));
+
+ if (awrq->sa_family != ARPHRD_ETHER) {
+ WL_ERROR(("%s: Invalid Header...sa_family\n", __FUNCTION__));
+ return -EINVAL;
+ }
+
+ /* Ignore "auto" or "off" */
+ if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) {
+ scb_val_t scbval;
+ bzero(&scbval, sizeof(scb_val_t));
+ if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)))) {
+ WL_ERROR(("%s: WLC_DISASSOC failed (%d).\n", __FUNCTION__, error));
+ }
+ return 0;
+ }
+ /* WL_ASSOC(("Assoc to %s\n", bcm_ether_ntoa((struct ether_addr *)&(awrq->sa_data),
+ * eabuf)));
+ */
+ /* Reassociate to the specified AP */
+ if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, awrq->sa_data, ETHER_ADDR_LEN))) {
+ WL_ERROR(("%s: WLC_REASSOC failed (%d).\n", __FUNCTION__, error));
+ return error;
+ }
+
+ return 0;
+}
+
+static int
+wl_iw_get_wap(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *awrq,
+ char *extra
+)
+{
+ WL_TRACE(("%s: SIOCGIWAP\n", dev->name));
+
+ awrq->sa_family = ARPHRD_ETHER;
+ memset(awrq->sa_data, 0, ETHER_ADDR_LEN);
+
+ /* Ignore error (may be down or disassociated) */
+ (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN);
+
+ return 0;
+}
+
+#if WIRELESS_EXT > 17
+static int
+wl_iw_mlme(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *awrq,
+ char *extra
+)
+{
+ struct iw_mlme *mlme;
+ scb_val_t scbval;
+ int error = -EINVAL;
+
+ WL_TRACE(("%s: SIOCSIWMLME\n", dev->name));
+
+ mlme = (struct iw_mlme *)extra;
+ if (mlme == NULL) {
+ WL_ERROR(("Invalid ioctl data.\n"));
+ return error;
+ }
+
+ scbval.val = mlme->reason_code;
+ bcopy(&mlme->addr.sa_data, &scbval.ea, ETHER_ADDR_LEN);
+
+ if (mlme->cmd == IW_MLME_DISASSOC) {
+ scbval.val = htod32(scbval.val);
+ error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
+ }
+ else if (mlme->cmd == IW_MLME_DEAUTH) {
+ scbval.val = htod32(scbval.val);
+ error = dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
+ sizeof(scb_val_t));
+ }
+ else {
+ WL_ERROR(("%s: Invalid ioctl data.\n", __FUNCTION__));
+ return error;
+ }
+
+ return error;
+}
+#endif /* WIRELESS_EXT > 17 */
+
+static int
+wl_iw_get_aplist(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra
+)
+{
+ wl_scan_results_t *list;
+ struct sockaddr *addr = (struct sockaddr *) extra;
+ struct iw_quality qual[IW_MAX_AP];
+ wl_bss_info_t *bi = NULL;
+ int error, i;
+ uint buflen = dwrq->length;
+
+ WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
+
+ if (!extra)
+ return -EINVAL;
+
+ /* Get scan results (too large to put on the stack) */
+ list = kmalloc(buflen, GFP_KERNEL);
+ if (!list)
+ return -ENOMEM;
+ memset(list, 0, buflen);
+ list->buflen = htod32(buflen);
+ if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) {
+ WL_ERROR(("%d: Scan results error %d\n", __LINE__, error));
+ kfree(list);
+ return error;
+ }
+ list->buflen = dtoh32(list->buflen);
+ list->version = dtoh32(list->version);
+ list->count = dtoh32(list->count);
+ ASSERT(list->version == WL_BSS_INFO_VERSION);
+
+ for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) {
+ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
+ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
+ buflen));
+
+ /* Infrastructure only */
+ if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
+ continue;
+
+ /* BSSID */
+ memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
+ addr[dwrq->length].sa_family = ARPHRD_ETHER;
+ qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
+ qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
+ qual[dwrq->length].noise = 0x100 + bi->phy_noise;
+
+ /* Updated qual, level, and noise */
+#if WIRELESS_EXT > 18
+ qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+#else
+ qual[dwrq->length].updated = 7;
+#endif /* WIRELESS_EXT > 18 */
+
+ dwrq->length++;
+ }
+
+ kfree(list);
+
+ if (dwrq->length) {
+ memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length);
+ /* Provided qual */
+ dwrq->flags = 1;
+ }
+
+ return 0;
+}
+
+static int
+wl_iw_iscan_get_aplist(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra
+)
+{
+ wl_scan_results_t *list;
+ iscan_buf_t * buf;
+ iscan_info_t *iscan = g_iscan;
+
+ struct sockaddr *addr = (struct sockaddr *) extra;
+ struct iw_quality qual[IW_MAX_AP];
+ wl_bss_info_t *bi = NULL;
+ int i;
+
+ WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
+
+ if (!extra)
+ return -EINVAL;
+
+ if ((!iscan) || (iscan->sysioc_pid < 0)) {
+ return wl_iw_get_aplist(dev, info, dwrq, extra);
+ }
+
+ buf = iscan->list_hdr;
+ /* Get scan results (too large to put on the stack) */
+ while (buf) {
+ list = &((wl_iscan_results_t*)buf->iscan_buf)->results;
+ ASSERT(list->version == WL_BSS_INFO_VERSION);
+
+ bi = NULL;
+ for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) {
+ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
+ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
+ WLC_IW_ISCAN_MAXLEN));
+
+ /* Infrastructure only */
+ if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
+ continue;
+
+ /* BSSID */
+ memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
+ addr[dwrq->length].sa_family = ARPHRD_ETHER;
+ qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
+ qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
+ qual[dwrq->length].noise = 0x100 + bi->phy_noise;
+
+ /* Updated qual, level, and noise */
+#if WIRELESS_EXT > 18
+ qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+#else
+ qual[dwrq->length].updated = 7;
+#endif /* WIRELESS_EXT > 18 */
+
+ dwrq->length++;
+ }
+ buf = buf->next;
+ }
+ if (dwrq->length) {
+ memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length);
+ /* Provided qual */
+ dwrq->flags = 1;
+ }
+
+ return 0;
+}
+
+#if WIRELESS_EXT > 13
+static int
+wl_iw_set_scan(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ wlc_ssid_t ssid;
+
+ WL_TRACE(("%s: SIOCSIWSCAN\n", dev->name));
+
+ /* default Broadcast scan */
+ memset(&ssid, 0, sizeof(ssid));
+
+#if WIRELESS_EXT > 17
+ /* check for given essid */
+ if (wrqu->data.length == sizeof(struct iw_scan_req)) {
+ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+ struct iw_scan_req *req = (struct iw_scan_req *)extra;
+ ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len);
+ memcpy(ssid.SSID, req->essid, ssid.SSID_len);
+ ssid.SSID_len = htod32(ssid.SSID_len);
+ }
+ }
+#endif
+ /* Ignore error (most likely scan in progress) */
+ (void) dev_wlc_ioctl(dev, WLC_SCAN, &ssid, sizeof(ssid));
+
+ return 0;
+}
+
+static int
+wl_iw_iscan_set_scan(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra
+)
+{
+ wlc_ssid_t ssid;
+ iscan_info_t *iscan = g_iscan;
+
+ WL_TRACE(("%s: SIOCSIWSCAN\n", dev->name));
+
+ /* use backup if our thread is not successful */
+ if ((!iscan) || (iscan->sysioc_pid < 0)) {
+ return wl_iw_set_scan(dev, info, wrqu, extra);
+ }
+ if (iscan->iscan_state == ISCAN_STATE_SCANING) {
+ return 0;
+ }
+
+ /* default Broadcast scan */
+ memset(&ssid, 0, sizeof(ssid));
+
+#if WIRELESS_EXT > 17
+ /* check for given essid */
+ if (wrqu->data.length == sizeof(struct iw_scan_req)) {
+ if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
+ struct iw_scan_req *req = (struct iw_scan_req *)extra;
+ ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len);
+ memcpy(ssid.SSID, req->essid, ssid.SSID_len);
+ ssid.SSID_len = htod32(ssid.SSID_len);
+ }
+ }
+#endif
+
+ iscan->list_cur = iscan->list_hdr;
+ iscan->iscan_state = ISCAN_STATE_SCANING;
+
+
+ wl_iw_set_event_mask(dev);
+ wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START);
+
+ iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms);
+ add_timer(&iscan->timer);
+ iscan->timer_on = 1;
+
+ return 0;
+}
+
+#if WIRELESS_EXT > 17
+static bool
+ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len)
+{
+/* Is this body of this tlvs entry a WPA entry? If */
+/* not update the tlvs buffer pointer/length */
+ uint8 *ie = *wpaie;
+
+ /* If the contents match the WPA_OUI and type=1 */
+ if ((ie[1] >= 6) &&
+ !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) {
+ return TRUE;
+ }
+
+ /* point to the next ie */
+ ie += ie[1] + 2;
+ /* calculate the length of the rest of the buffer */
+ *tlvs_len -= (int)(ie - *tlvs);
+ /* update the pointer to the start of the buffer */
+ *tlvs = ie;
+ return FALSE;
+}
+
+static bool
+ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len)
+{
+/* Is this body of this tlvs entry a WPS entry? If */
+/* not update the tlvs buffer pointer/length */
+ uint8 *ie = *wpsie;
+
+ /* If the contents match the WPA_OUI and type=4 */
+ if ((ie[1] >= 4) &&
+ !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) {
+ return TRUE;
+ }
+
+ /* point to the next ie */
+ ie += ie[1] + 2;
+ /* calculate the length of the rest of the buffer */
+ *tlvs_len -= (int)(ie - *tlvs);
+ /* update the pointer to the start of the buffer */
+ *tlvs = ie;
+ return FALSE;
+}
+#endif /* WIRELESS_EXT > 17 */
+
+
+static int
+wl_iw_handle_scanresults_ies(char **event_p, char *end,
+ struct iw_request_info *info, wl_bss_info_t *bi)
+{
+#if WIRELESS_EXT > 17
+ struct iw_event iwe;
+ char *event;
+
+ event = *event_p;
+ if (bi->ie_length) {
+ /* look for wpa/rsn ies in the ie list... */
+ bcm_tlv_t *ie;
+ uint8 *ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
+ int ptr_len = bi->ie_length;
+
+ if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID))) {
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = ie->len + 2;
+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
+ }
+ ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
+
+ if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_MDIE_ID))) {
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = ie->len + 2;
+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
+ }
+ ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
+
+ while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
+ /* look for WPS IE */
+ if (ie_is_wps_ie(((uint8 **)&ie), &ptr, &ptr_len)) {
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = ie->len + 2;
+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
+ break;
+ }
+ }
+
+ ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
+ ptr_len = bi->ie_length;
+ while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
+ if (ie_is_wpa_ie(((uint8 **)&ie), &ptr, &ptr_len)) {
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = ie->len + 2;
+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
+ break;
+ }
+ }
+
+ *event_p = event;
+ }
+
+#endif /* WIRELESS_EXT > 17 */
+ return 0;
+}
+static int
+wl_iw_get_scan(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra
+)
+{
+ channel_info_t ci;
+ wl_scan_results_t *list;
+ struct iw_event iwe;
+ wl_bss_info_t *bi = NULL;
+ int error, i, j;
+ char *event = extra, *end = extra + dwrq->length, *value;
+ uint buflen = dwrq->length;
+
+ WL_TRACE(("%s: SIOCGIWSCAN\n", dev->name));
+
+ if (!extra)
+ return -EINVAL;
+
+ /* Check for scan in progress */
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
+ return error;
+ ci.scan_channel = dtoh32(ci.scan_channel);
+ if (ci.scan_channel)
+ return -EAGAIN;
+
+ /* Get scan results (too large to put on the stack) */
+ list = kmalloc(buflen, GFP_KERNEL);
+ if (!list)
+ return -ENOMEM;
+ memset(list, 0, buflen);
+ list->buflen = htod32(buflen);
+ if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) {
+ kfree(list);
+ return error;
+ }
+ list->buflen = dtoh32(list->buflen);
+ list->version = dtoh32(list->version);
+ list->count = dtoh32(list->count);
+
+ ASSERT(list->version == WL_BSS_INFO_VERSION);
+
+ for (i = 0; i < list->count && i < IW_MAX_AP; i++) {
+ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
+ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
+ buflen));
+
+ /* First entry must be the BSSID */
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
+
+ /* SSID */
+ iwe.u.data.length = dtoh32(bi->SSID_len);
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.flags = 1;
+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
+
+ /* Mode */
+ if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
+ iwe.cmd = SIOCGIWMODE;
+ if (dtoh16(bi->capability) & DOT11_CAP_ESS)
+ iwe.u.mode = IW_MODE_INFRA;
+ else
+ iwe.u.mode = IW_MODE_ADHOC;
+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN);
+ }
+
+ /* Channel */
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec),
+ CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ?
+ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
+ iwe.u.freq.e = 6;
+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
+
+ /* Channel quality */
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI));
+ iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI);
+ iwe.u.qual.noise = 0x100 + bi->phy_noise;
+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
+
+ /* WPA, WPA2, WPS, WAPI IEs */
+ wl_iw_handle_scanresults_ies(&event, end, info, bi);
+
+ /* Encryption */
+ iwe.cmd = SIOCGIWENCODE;
+ if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ else
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ iwe.u.data.length = 0;
+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
+
+ /* Rates */
+ if (bi->rateset.count) {
+ value = event + IW_EV_LCP_LEN;
+ iwe.cmd = SIOCGIWRATE;
+ /* Those two flags are ignored... */
+ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+ for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
+ iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000;
+ value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
+ IW_EV_PARAM_LEN);
+ }
+ event = value;
+ }
+ }
+
+ kfree(list);
+
+ dwrq->length = event - extra;
+ dwrq->flags = 0; /* todo */
+
+ return 0;
+}
+
+static int
+wl_iw_iscan_get_scan(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra
+)
+{
+ wl_scan_results_t *list;
+ struct iw_event iwe;
+ wl_bss_info_t *bi = NULL;
+ int ii, j;
+ int apcnt;
+ char *event = extra, *end = extra + dwrq->length, *value;
+ iscan_info_t *iscan = g_iscan;
+ iscan_buf_t * p_buf;
+
+ WL_TRACE(("%s: SIOCGIWSCAN\n", dev->name));
+
+ if (!extra)
+ return -EINVAL;
+
+ /* use backup if our thread is not successful */
+ if ((!iscan) || (iscan->sysioc_pid < 0)) {
+ return wl_iw_get_scan(dev, info, dwrq, extra);
+ }
+
+ /* Check for scan in progress */
+ if (iscan->iscan_state == ISCAN_STATE_SCANING)
+ return -EAGAIN;
+
+ apcnt = 0;
+ p_buf = iscan->list_hdr;
+ /* Get scan results */
+ while (p_buf != iscan->list_cur) {
+ list = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
+
+ if (list->version != WL_BSS_INFO_VERSION) {
+ WL_ERROR(("list->version %d != WL_BSS_INFO_VERSION\n", list->version));
+ }
+
+ bi = NULL;
+ for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) {
+ bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
+ ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
+ WLC_IW_ISCAN_MAXLEN));
+
+ /* overflow check cover fields before wpa IEs */
+ if (event + ETHER_ADDR_LEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN +
+ IW_EV_QUAL_LEN >= end)
+ return -E2BIG;
+ /* First entry must be the BSSID */
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
+
+ /* SSID */
+ iwe.u.data.length = dtoh32(bi->SSID_len);
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.flags = 1;
+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
+
+ /* Mode */
+ if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
+ iwe.cmd = SIOCGIWMODE;
+ if (dtoh16(bi->capability) & DOT11_CAP_ESS)
+ iwe.u.mode = IW_MODE_INFRA;
+ else
+ iwe.u.mode = IW_MODE_ADHOC;
+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN);
+ }
+
+ /* Channel */
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec),
+ CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ?
+ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
+ iwe.u.freq.e = 6;
+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
+
+ /* Channel quality */
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI));
+ iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI);
+ iwe.u.qual.noise = 0x100 + bi->phy_noise;
+ event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
+
+ /* WPA, WPA2, WPS, WAPI IEs */
+ wl_iw_handle_scanresults_ies(&event, end, info, bi);
+
+ /* Encryption */
+ iwe.cmd = SIOCGIWENCODE;
+ if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ else
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ iwe.u.data.length = 0;
+ event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
+
+ /* Rates */
+ if (bi->rateset.count <= sizeof(bi->rateset.rates)) {
+ if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end)
+ return -E2BIG;
+
+ value = event + IW_EV_LCP_LEN;
+ iwe.cmd = SIOCGIWRATE;
+ /* Those two flags are ignored... */
+ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+ for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
+ iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000;
+ value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
+ IW_EV_PARAM_LEN);
+ }
+ event = value;
+ }
+ }
+ p_buf = p_buf->next;
+ } /* while (p_buf) */
+
+ dwrq->length = event - extra;
+ dwrq->flags = 0; /* todo */
+
+ return 0;
+}
+
+#endif /* WIRELESS_EXT > 13 */
+
+
+static int
+wl_iw_set_essid(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra
+)
+{
+ wlc_ssid_t ssid;
+ int error;
+
+ WL_TRACE(("%s: SIOCSIWESSID\n", dev->name));
+
+ /* default Broadcast SSID */
+ memset(&ssid, 0, sizeof(ssid));
+ if (dwrq->length && extra) {
+#if WIRELESS_EXT > 20
+ ssid.SSID_len = MIN(sizeof(ssid.SSID), dwrq->length);
+#else
+ ssid.SSID_len = MIN(sizeof(ssid.SSID), dwrq->length-1);
+#endif
+ memcpy(ssid.SSID, extra, ssid.SSID_len);
+ ssid.SSID_len = htod32(ssid.SSID_len);
+
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid))))
+ return error;
+ }
+ /* If essid null then it is "iwconfig <interface> essid off" command */
+ else {
+ scb_val_t scbval;
+ bzero(&scbval, sizeof(scb_val_t));
+ if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t))))
+ return error;
+ }
+ return 0;
+}
+
+static int
+wl_iw_get_essid(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra
+)
+{
+ wlc_ssid_t ssid;
+ int error;
+
+ WL_TRACE(("%s: SIOCGIWESSID\n", dev->name));
+
+ if (!extra)
+ return -EINVAL;
+
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) {
+ WL_ERROR(("Error getting the SSID\n"));
+ return error;
+ }
+
+ ssid.SSID_len = dtoh32(ssid.SSID_len);
+
+ /* Get the current SSID */
+ memcpy(extra, ssid.SSID, ssid.SSID_len);
+
+ dwrq->length = ssid.SSID_len;
+
+ dwrq->flags = 1; /* active */
+
+ return 0;
+}
+
+static int
+wl_iw_set_nick(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra
+)
+{
+ wl_iw_t *iw = IW_DEV_IF(dev);
+ WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name));
+
+ if (!extra)
+ return -EINVAL;
+
+ /* Check the size of the string */
+ if (dwrq->length > sizeof(iw->nickname))
+ return -E2BIG;
+
+ memcpy(iw->nickname, extra, dwrq->length);
+ iw->nickname[dwrq->length - 1] = '\0';
+
+ return 0;
+}
+
+static int
+wl_iw_get_nick(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra
+)
+{
+ wl_iw_t *iw = IW_DEV_IF(dev);
+ WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name));
+
+ if (!extra)
+ return -EINVAL;
+
+ strcpy(extra, iw->nickname);
+ dwrq->length = strlen(extra) + 1;
+
+ return 0;
+}
+
+static int wl_iw_set_rate(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra
+)
+{
+ wl_rateset_t rateset;
+ int error, rate, i, error_bg, error_a;
+
+ WL_TRACE(("%s: SIOCSIWRATE\n", dev->name));
+
+ /* Get current rateset */
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset))))
+ return error;
+
+ rateset.count = dtoh32(rateset.count);
+
+ if (vwrq->value < 0) {
+ /* Select maximum rate */
+ rate = rateset.rates[rateset.count - 1] & 0x7f;
+ } else if (vwrq->value < rateset.count) {
+ /* Select rate by rateset index */
+ rate = rateset.rates[vwrq->value] & 0x7f;
+ } else {
+ /* Specified rate in bps */
+ rate = vwrq->value / 500000;
+ }
+
+ if (vwrq->fixed) {
+ /*
+ Set rate override,
+ Since the is a/b/g-blind, both a/bg_rate are enforced.
+ */
+ error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate);
+ error_a = dev_wlc_intvar_set(dev, "a_rate", rate);
+
+ if (error_bg && error_a)
+ return (error_bg | error_a);
+ } else {
+ /*
+ clear rate override
+ Since the is a/b/g-blind, both a/bg_rate are enforced.
+ */
+ /* 0 is for clearing rate override */
+ error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0);
+ /* 0 is for clearing rate override */
+ error_a = dev_wlc_intvar_set(dev, "a_rate", 0);
+
+ if (error_bg && error_a)
+ return (error_bg | error_a);
+
+ /* Remove rates above selected rate */
+ for (i = 0; i < rateset.count; i++)
+ if ((rateset.rates[i] & 0x7f) > rate)
+ break;
+ rateset.count = htod32(i);
+
+ /* Set current rateset */
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset, sizeof(rateset))))
+ return error;
+ }
+
+ return 0;
+}
+
+static int wl_iw_get_rate(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra
+)
+{
+ int error, rate;
+
+ WL_TRACE(("%s: SIOCGIWRATE\n", dev->name));
+
+ /* Report the current tx rate */
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate))))
+ return error;
+ rate = dtoh32(rate);
+ vwrq->value = rate * 500000;
+
+ return 0;
+}
+
+static int
+wl_iw_set_rts(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra
+)
+{
+ int error, rts;
+
+ WL_TRACE(("%s: SIOCSIWRTS\n", dev->name));
+
+ if (vwrq->disabled)
+ rts = DOT11_DEFAULT_RTS_LEN;
+ else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN)
+ return -EINVAL;
+ else
+ rts = vwrq->value;
+
+ if ((error = dev_wlc_intvar_set(dev, "rtsthresh", rts)))
+ return error;
+
+ return 0;
+}
+
+static int
+wl_iw_get_rts(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra
+)
+{
+ int error, rts;
+
+ WL_TRACE(("%s: SIOCGIWRTS\n", dev->name));
+
+ if ((error = dev_wlc_intvar_get(dev, "rtsthresh", &rts)))
+ return error;
+
+ vwrq->value = rts;
+ vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN);
+ vwrq->fixed = 1;
+
+ return 0;
+}
+
+static int
+wl_iw_set_frag(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra
+)
+{
+ int error, frag;
+
+ WL_TRACE(("%s: SIOCSIWFRAG\n", dev->name));
+
+ if (vwrq->disabled)
+ frag = DOT11_DEFAULT_FRAG_LEN;
+ else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN)
+ return -EINVAL;
+ else
+ frag = vwrq->value;
+
+ if ((error = dev_wlc_intvar_set(dev, "fragthresh", frag)))
+ return error;
+
+ return 0;
+}
+
+static int
+wl_iw_get_frag(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra
+)
+{
+ int error, fragthreshold;
+
+ WL_TRACE(("%s: SIOCGIWFRAG\n", dev->name));
+
+ if ((error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold)))
+ return error;
+
+ vwrq->value = fragthreshold;
+ vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN);
+ vwrq->fixed = 1;
+
+ return 0;
+}
+
+static int
+wl_iw_set_txpow(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra
+)
+{
+ int error, disable;
+ uint16 txpwrmw;
+ WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name));
+
+ /* Make sure radio is off or on as far as software is concerned */
+ disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0;
+ disable += WL_RADIO_SW_DISABLE << 16;
+
+ disable = htod32(disable);
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable))))
+ return error;
+
+ /* If Radio is off, nothing more to do */
+ if (disable & WL_RADIO_SW_DISABLE)
+ return 0;
+
+ /* Only handle mW */
+ if (!(vwrq->flags & IW_TXPOW_MWATT))
+ return -EINVAL;
+
+ /* Value < 0 means just "on" or "off" */
+ if (vwrq->value < 0)
+ return 0;
+
+ if (vwrq->value > 0xffff) txpwrmw = 0xffff;
+ else txpwrmw = (uint16)vwrq->value;
+
+
+ error = dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw)));
+ return error;
+}
+
+static int
+wl_iw_get_txpow(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra
+)
+{
+ int error, disable, txpwrdbm;
+ uint8 result;
+
+ WL_TRACE(("%s: SIOCGIWTXPOW\n", dev->name));
+
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable))) ||
+ (error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm)))
+ return error;
+
+ disable = dtoh32(disable);
+ result = (uint8)(txpwrdbm & ~WL_TXPWR_OVERRIDE);
+ vwrq->value = (int32)bcm_qdbm_to_mw(result);
+ vwrq->fixed = 0;
+ vwrq->disabled = (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0;
+ vwrq->flags = IW_TXPOW_MWATT;
+
+ return 0;
+}
+
+#if WIRELESS_EXT > 10
+static int
+wl_iw_set_retry(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra
+)
+{
+ int error, lrl, srl;
+
+ WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name));
+
+ /* Do not handle "off" or "lifetime" */
+ if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME))
+ return -EINVAL;
+
+ /* Handle "[min|max] limit" */
+ if (vwrq->flags & IW_RETRY_LIMIT) {
+ /* "max limit" or just "limit" */
+#if WIRELESS_EXT > 20
+ if ((vwrq->flags & IW_RETRY_LONG) ||(vwrq->flags & IW_RETRY_MAX) ||
+ !((vwrq->flags & IW_RETRY_SHORT) || (vwrq->flags & IW_RETRY_MIN))) {
+#else
+ if ((vwrq->flags & IW_RETRY_MAX) || !(vwrq->flags & IW_RETRY_MIN)) {
+#endif /* WIRELESS_EXT > 20 */
+
+ lrl = htod32(vwrq->value);
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(lrl))))
+ return error;
+ }
+ /* "min limit" or just "limit" */
+#if WIRELESS_EXT > 20
+ if ((vwrq->flags & IW_RETRY_SHORT) ||(vwrq->flags & IW_RETRY_MIN) ||
+ !((vwrq->flags & IW_RETRY_LONG) || (vwrq->flags & IW_RETRY_MAX))) {
+#else
+ if ((vwrq->flags & IW_RETRY_MIN) || !(vwrq->flags & IW_RETRY_MAX)) {
+#endif /* WIRELESS_EXT > 20 */
+
+ srl = htod32(vwrq->value);
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl, sizeof(srl))))
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+static int
+wl_iw_get_retry(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra
+)
+{
+ int error, lrl, srl;
+
+ WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name));
+
+ vwrq->disabled = 0; /* Can't be disabled */
+
+ /* Do not handle lifetime queries */
+ if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
+ return -EINVAL;
+
+ /* Get retry limits */
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl))) ||
+ (error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl))))
+ return error;
+
+ lrl = dtoh32(lrl);
+ srl = dtoh32(srl);
+
+ /* Note : by default, display the min retry number */
+ if (vwrq->flags & IW_RETRY_MAX) {
+ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ vwrq->value = lrl;
+ } else {
+ vwrq->flags = IW_RETRY_LIMIT;
+ vwrq->value = srl;
+ if (srl != lrl)
+ vwrq->flags |= IW_RETRY_MIN;
+ }
+
+ return 0;
+}
+#endif /* WIRELESS_EXT > 10 */
+
+static int
+wl_iw_set_encode(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra
+)
+{
+ wl_wsec_key_t key;
+ int error, val, wsec;
+
+ WL_TRACE(("%s: SIOCSIWENCODE\n", dev->name));
+
+ memset(&key, 0, sizeof(key));
+
+ if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
+ /* Find the current key */
+ for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) {
+ val = htod32(key.index);
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val))))
+ return error;
+ val = dtoh32(val);
+ if (val)
+ break;
+ }
+ /* Default to 0 */
+ if (key.index == DOT11_MAX_DEFAULT_KEYS)
+ key.index = 0;
+ } else {
+ key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ if (key.index >= DOT11_MAX_DEFAULT_KEYS)
+ return -EINVAL;
+ }
+
+ /* Interpret "off" to mean no encryption */
+ wsec = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED;
+
+ if ((error = dev_wlc_intvar_set(dev, "wsec", wsec)))
+ return error;
+
+ /* Old API used to pass a NULL pointer instead of IW_ENCODE_NOKEY */
+ if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) {
+ /* Just select a new current key */
+ val = htod32(key.index);
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val, sizeof(val))))
+ return error;
+ } else {
+ key.len = dwrq->length;
+
+ if (dwrq->length > sizeof(key.data))
+ return -EINVAL;
+
+ memcpy(key.data, extra, dwrq->length);
+
+ key.flags = WL_PRIMARY_KEY;
+ switch (key.len) {
+ case WEP1_KEY_SIZE:
+ key.algo = CRYPTO_ALGO_WEP1;
+ break;
+ case WEP128_KEY_SIZE:
+ key.algo = CRYPTO_ALGO_WEP128;
+ break;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
+ case TKIP_KEY_SIZE:
+ key.algo = CRYPTO_ALGO_TKIP;
+ break;
+#endif
+ case AES_KEY_SIZE:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Set the new key/index */
+ swap_key_from_BE(&key);
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key))))
+ return error;
+ }
+
+ /* Interpret "restricted" to mean shared key authentication */
+ val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0;
+ val = htod32(val);
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val))))
+ return error;
+
+ return 0;
+}
+
+static int
+wl_iw_get_encode(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra
+)
+{
+ wl_wsec_key_t key;
+ int error, val, wsec, auth;
+
+ WL_TRACE(("%s: SIOCGIWENCODE\n", dev->name));
+
+ /* assure default values of zero for things we don't touch */
+ bzero(&key, sizeof(wl_wsec_key_t));
+
+ if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
+ /* Find the current key */
+ for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) {
+ val = key.index;
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val))))
+ return error;
+ val = dtoh32(val);
+ if (val)
+ break;
+ }
+ } else
+ key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+
+ if (key.index >= DOT11_MAX_DEFAULT_KEYS)
+ key.index = 0;
+
+ /* Get info */
+
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec))) ||
+ (error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth))))
+ return error;
+
+ swap_key_to_BE(&key);
+
+ wsec = dtoh32(wsec);
+ auth = dtoh32(auth);
+ /* Get key length */
+ dwrq->length = MIN(IW_ENCODING_TOKEN_MAX, key.len);
+
+ /* Get flags */
+ dwrq->flags = key.index + 1;
+ if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))) {
+ /* Interpret "off" to mean no encryption */
+ dwrq->flags |= IW_ENCODE_DISABLED;
+ }
+ if (auth) {
+ /* Interpret "restricted" to mean shared key authentication */
+ dwrq->flags |= IW_ENCODE_RESTRICTED;
+ }
+
+ /* Get key */
+ if (dwrq->length && extra)
+ memcpy(extra, key.data, dwrq->length);
+
+ return 0;
+}
+
+static int
+wl_iw_set_power(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra
+)
+{
+ int error, pm;
+
+ WL_TRACE(("%s: SIOCSIWPOWER\n", dev->name));
+
+ pm = vwrq->disabled ? PM_OFF : PM_MAX;
+
+ pm = htod32(pm);
+ if ((error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm))))
+ return error;
+
+ return 0;
+}
+
+static int
+wl_iw_get_power(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra
+)
+{
+ int error, pm;
+
+ WL_TRACE(("%s: SIOCGIWPOWER\n", dev->name));
+
+ if ((error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))))
+ return error;
+
+ pm = dtoh32(pm);
+ vwrq->disabled = pm ? 0 : 1;
+ vwrq->flags = IW_POWER_ALL_R;
+
+ return 0;
+}
+
+#if WIRELESS_EXT > 17
+static int
+wl_iw_set_wpaie(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *iwp,
+ char *extra
+)
+{
+ dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length);
+
+ return 0;
+}
+
+static int
+wl_iw_get_wpaie(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *iwp,
+ char *extra
+)
+{
+ WL_TRACE(("%s: SIOCGIWGENIE\n", dev->name));
+ iwp->length = 64;
+ dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length);
+ return 0;
+}
+
+static int
+wl_iw_set_encodeext(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra
+)
+{
+ wl_wsec_key_t key;
+ int error;
+ struct iw_encode_ext *iwe;
+
+ WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev->name));
+
+ memset(&key, 0, sizeof(key));
+ iwe = (struct iw_encode_ext *)extra;
+
+ /* disable encryption completely */
+ if (dwrq->flags & IW_ENCODE_DISABLED) {
+
+ }
+
+ /* get the key index */
+ key.index = 0;
+ if (dwrq->flags & IW_ENCODE_INDEX)
+ key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+
+ key.len = iwe->key_len;
+
+ /* Instead of bcast for ea address for default wep keys, driver needs it to be Null */
+ if (!ETHER_ISMULTI(iwe->addr.sa_data))
+ bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea, ETHER_ADDR_LEN);
+
+ /* check for key index change */
+ if (key.len == 0) {
+ if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+ WL_WSEC(("Changing the the primary Key to %d\n", key.index));
+ /* change the key index .... */
+ key.index = htod32(key.index);
+ error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY,
+ &key.index, sizeof(key.index));
+ if (error)
+ return error;
+ }
+ /* key delete */
+ else {
+ swap_key_from_BE(&key);
+ error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
+ if (error)
+ return error;
+ }
+ }
+ /* This case is used to allow an external 802.1x supplicant
+ * to pass the PMK to the in-driver supplicant for use in
+ * the 4-way handshake.
+ */
+ else if (iwe->alg == IW_ENCODE_ALG_PMK) {
+ int j;
+ wsec_pmk_t pmk;
+ char keystring[WSEC_MAX_PSK_LEN + 1];
+ char* charptr = keystring;
+ uint len;
+
+ /* copy the raw hex key to the appropriate format */
+ for (j = 0; j < (WSEC_MAX_PSK_LEN / 2); j++) {
+ sprintf(charptr, "%02x", iwe->key[j]);
+ charptr += 2;
+ }
+ len = strlen(keystring);
+ pmk.key_len = htod16(len);
+ bcopy(keystring, pmk.key, len);
+ pmk.flags = htod16(WSEC_PASSPHRASE);
+
+ error = dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
+ if (error)
+ return error;
+ }
+
+ else {
+ if (iwe->key_len > sizeof(key.data))
+ return -EINVAL;
+
+ WL_WSEC(("Setting the key index %d\n", key.index));
+ if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+ WL_WSEC(("key is a Primary Key\n"));
+ key.flags = WL_PRIMARY_KEY;
+ }
+
+ bcopy((void *)iwe->key, key.data, iwe->key_len);
+
+ if (iwe->alg == IW_ENCODE_ALG_TKIP) {
+ uint8 keybuf[8];
+ bcopy(&key.data[24], keybuf, sizeof(keybuf));
+ bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
+ bcopy(keybuf, &key.data[16], sizeof(keybuf));
+ }
+
+ /* rx iv */
+ if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
+ uchar *ivptr;
+ ivptr = (uchar *)iwe->rx_seq;
+ key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
+ (ivptr[3] << 8) | ivptr[2];
+ key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
+ key.iv_initialized = TRUE;
+ }
+
+ switch (iwe->alg) {
+ case IW_ENCODE_ALG_NONE:
+ key.algo = CRYPTO_ALGO_OFF;
+ break;
+ case IW_ENCODE_ALG_WEP:
+ if (iwe->key_len == WEP1_KEY_SIZE)
+ key.algo = CRYPTO_ALGO_WEP1;
+ else
+ key.algo = CRYPTO_ALGO_WEP128;
+ break;
+ case IW_ENCODE_ALG_TKIP:
+ key.algo = CRYPTO_ALGO_TKIP;
+ break;
+ case IW_ENCODE_ALG_CCMP:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ break;
+ default:
+ break;
+ }
+ swap_key_from_BE(&key);
+
+ dhd_wait_pend8021x(dev);
+
+ error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
+ if (error)
+ return error;
+ }
+ return 0;
+}
+
+
+#if WIRELESS_EXT > 17
+struct {
+ pmkid_list_t pmkids;
+ pmkid_t foo[MAXPMKID-1];
+} pmkid_list;
+static int
+wl_iw_set_pmksa(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra
+)
+{
+ struct iw_pmksa *iwpmksa;
+ uint i;
+ char eabuf[ETHER_ADDR_STR_LEN];
+ pmkid_t * pmkid_array = pmkid_list.pmkids.pmkid;
+
+ WL_TRACE(("%s: SIOCSIWPMKSA\n", dev->name));
+ iwpmksa = (struct iw_pmksa *)extra;
+ bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
+ if (iwpmksa->cmd == IW_PMKSA_FLUSH) {
+ WL_TRACE(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n"));
+ bzero((char *)&pmkid_list, sizeof(pmkid_list));
+ }
+ if (iwpmksa->cmd == IW_PMKSA_REMOVE) {
+ pmkid_list_t pmkid, *pmkidptr;
+ pmkidptr = &pmkid;
+ bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN);
+ bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN);
+ {
+ uint j;
+ WL_TRACE(("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ",
+ bcm_ether_ntoa(&pmkidptr->pmkid[0].BSSID,
+ eabuf)));
+ for (j = 0; j < WPA2_PMKID_LEN; j++)
+ WL_TRACE(("%02x ", pmkidptr->pmkid[0].PMKID[j]));
+ WL_TRACE(("\n"));
+ }
+ for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
+ if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_array[i].BSSID,
+ ETHER_ADDR_LEN))
+ break;
+ for (; i < pmkid_list.pmkids.npmkid; i++) {
+ bcopy(&pmkid_array[i+1].BSSID,
+ &pmkid_array[i].BSSID,
+ ETHER_ADDR_LEN);
+ bcopy(&pmkid_array[i+1].PMKID,
+ &pmkid_array[i].PMKID,
+ WPA2_PMKID_LEN);
+ }
+ pmkid_list.pmkids.npmkid--;
+ }
+ if (iwpmksa->cmd == IW_PMKSA_ADD) {
+ bcopy(&iwpmksa->bssid.sa_data[0],
+ &pmkid_array[pmkid_list.pmkids.npmkid].BSSID,
+ ETHER_ADDR_LEN);
+ bcopy(&iwpmksa->pmkid[0], &pmkid_array[pmkid_list.pmkids.npmkid].PMKID,
+ WPA2_PMKID_LEN);
+ {
+ uint j;
+ uint k;
+ k = pmkid_list.pmkids.npmkid;
+ BCM_REFERENCE(k);
+ WL_TRACE(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ",
+ bcm_ether_ntoa(&pmkid_array[k].BSSID,
+ eabuf)));
+ for (j = 0; j < WPA2_PMKID_LEN; j++)
+ WL_TRACE(("%02x ", pmkid_array[k].PMKID[j]));
+ WL_TRACE(("\n"));
+ }
+ pmkid_list.pmkids.npmkid++;
+ }
+ WL_TRACE(("PRINTING pmkid LIST - No of elements %d\n", pmkid_list.pmkids.npmkid));
+ for (i = 0; i < pmkid_list.pmkids.npmkid; i++) {
+ uint j;
+ WL_TRACE(("PMKID[%d]: %s = ", i,
+ bcm_ether_ntoa(&pmkid_array[i].BSSID,
+ eabuf)));
+ for (j = 0; j < WPA2_PMKID_LEN; j++)
+ WL_TRACE(("%02x ", pmkid_array[i].PMKID[j]));
+ printf("\n");
+ }
+ WL_TRACE(("\n"));
+ dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, sizeof(pmkid_list));
+ return 0;
+}
+#endif /* WIRELESS_EXT > 17 */
+
+static int
+wl_iw_get_encodeext(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra
+)
+{
+ WL_TRACE(("%s: SIOCGIWENCODEEXT\n", dev->name));
+ return 0;
+}
+
+static int
+wl_iw_set_wpaauth(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra
+)
+{
+ int error = 0;
+ int paramid;
+ int paramval;
+ uint32 cipher_combined;
+ int val = 0;
+ wl_iw_t *iw = IW_DEV_IF(dev);
+
+ WL_TRACE(("%s: SIOCSIWAUTH\n", dev->name));
+
+ paramid = vwrq->flags & IW_AUTH_INDEX;
+ paramval = vwrq->value;
+
+ WL_TRACE(("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n",
+ dev->name, paramid, paramval));
+
+ switch (paramid) {
+
+ case IW_AUTH_WPA_VERSION:
+ /* supported wpa version disabled or wpa or wpa2 */
+ if (paramval & IW_AUTH_WPA_VERSION_DISABLED)
+ val = WPA_AUTH_DISABLED;
+ else if (paramval & (IW_AUTH_WPA_VERSION_WPA))
+ val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
+ else if (paramval & IW_AUTH_WPA_VERSION_WPA2)
+ val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
+ WL_TRACE(("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val));
+ if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
+ return error;
+ break;
+
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP: {
+ int fbt_cap = 0;
+
+ if (paramid == IW_AUTH_CIPHER_PAIRWISE) {
+ iw->pwsec = paramval;
+ }
+ else {
+ iw->gwsec = paramval;
+ }
+
+ if ((error = dev_wlc_intvar_get(dev, "wsec", &val)))
+ return error;
+
+ cipher_combined = iw->gwsec | iw->pwsec;
+ val &= ~(WEP_ENABLED | TKIP_ENABLED | AES_ENABLED);
+ if (cipher_combined & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
+ val |= WEP_ENABLED;
+ if (cipher_combined & IW_AUTH_CIPHER_TKIP)
+ val |= TKIP_ENABLED;
+ if (cipher_combined & IW_AUTH_CIPHER_CCMP)
+ val |= AES_ENABLED;
+
+ if (iw->privacy_invoked && !val) {
+ WL_WSEC(("%s: %s: 'Privacy invoked' TRUE but clearing wsec, assuming "
+ "we're a WPS enrollee\n", dev->name, __FUNCTION__));
+ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) {
+ WL_WSEC(("Failed to set iovar is_WPS_enrollee\n"));
+ return error;
+ }
+ } else if (val) {
+ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) {
+ WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n"));
+ return error;
+ }
+ }
+
+ if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
+ return error;
+
+ /* Ensure in-dongle supplicant is turned on when FBT wants to do the 4-way
+ * handshake.
+ */
+ if (dev_wlc_intvar_get(dev, "fbt_cap", &fbt_cap) == 0) {
+ if (fbt_cap == WLC_FBT_CAP_DRV_4WAY_AND_REASSOC) {
+ if ((paramid == IW_AUTH_CIPHER_PAIRWISE) && (val & AES_ENABLED)) {
+ if ((error = dev_wlc_intvar_set(dev, "sup_wpa", 1)))
+ return error;
+ }
+ else if (val == 0) {
+ if ((error = dev_wlc_intvar_set(dev, "sup_wpa", 0)))
+ return error;
+ }
+ }
+ }
+ break;
+ }
+
+ case IW_AUTH_KEY_MGMT:
+ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
+ return error;
+
+ if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
+ if (paramval & (IW_AUTH_KEY_MGMT_FT_PSK | IW_AUTH_KEY_MGMT_PSK))
+ val = WPA_AUTH_PSK;
+ else
+ val = WPA_AUTH_UNSPECIFIED;
+ if (paramval & (IW_AUTH_KEY_MGMT_FT_802_1X | IW_AUTH_KEY_MGMT_FT_PSK))
+ val |= WPA2_AUTH_FT;
+ }
+ else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
+ if (paramval & (IW_AUTH_KEY_MGMT_FT_PSK | IW_AUTH_KEY_MGMT_PSK))
+ val = WPA2_AUTH_PSK;
+ else
+ val = WPA2_AUTH_UNSPECIFIED;
+ if (paramval & (IW_AUTH_KEY_MGMT_FT_802_1X | IW_AUTH_KEY_MGMT_FT_PSK))
+ val |= WPA2_AUTH_FT;
+ }
+ WL_TRACE(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val));
+ if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
+ return error;
+ break;
+
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ dev_wlc_bufvar_set(dev, "tkip_countermeasures", (char *)&paramval, 1);
+ break;
+
+ case IW_AUTH_80211_AUTH_ALG:
+ /* open shared */
+ WL_ERROR(("Setting the D11auth %d\n", paramval));
+ if (paramval & IW_AUTH_ALG_OPEN_SYSTEM)
+ val = 0;
+ else if (paramval & IW_AUTH_ALG_SHARED_KEY)
+ val = 1;
+ else
+ error = 1;
+ if (!error && (error = dev_wlc_intvar_set(dev, "auth", val)))
+ return error;
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+ if (paramval == 0) {
+ val = 0;
+ WL_TRACE(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val));
+ error = dev_wlc_intvar_set(dev, "wpa_auth", val);
+ return error;
+ }
+ else {
+ /* If WPA is enabled, wpa_auth is set elsewhere */
+ }
+ break;
+
+ case IW_AUTH_DROP_UNENCRYPTED:
+ dev_wlc_bufvar_set(dev, "wsec_restrict", (char *)&paramval, 1);
+ break;
+
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol", (char *)&paramval, 1);
+ break;
+
+#if WIRELESS_EXT > 17
+
+ case IW_AUTH_ROAMING_CONTROL:
+ WL_TRACE(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__));
+ /* driver control or user space app control */
+ break;
+
+ case IW_AUTH_PRIVACY_INVOKED: {
+ int wsec;
+
+ if (paramval == 0) {
+ iw->privacy_invoked = FALSE;
+ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) {
+ WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n"));
+ return error;
+ }
+ } else {
+ iw->privacy_invoked = TRUE;
+ if ((error = dev_wlc_intvar_get(dev, "wsec", &wsec)))
+ return error;
+
+ if (!WSEC_ENABLED(wsec)) {
+ /* if privacy is true, but wsec is false, we are a WPS enrollee */
+ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) {
+ WL_WSEC(("Failed to set iovar is_WPS_enrollee\n"));
+ return error;
+ }
+ } else {
+ if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) {
+ WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n"));
+ return error;
+ }
+ }
+ }
+ break;
+ }
+
+
+#endif /* WIRELESS_EXT > 17 */
+
+
+ default:
+ break;
+ }
+ return 0;
+}
+#define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK))
+
+static int
+wl_iw_get_wpaauth(
+ struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq,
+ char *extra
+)
+{
+ int error;
+ int paramid;
+ int paramval = 0;
+ int val;
+ wl_iw_t *iw = IW_DEV_IF(dev);
+
+ WL_TRACE(("%s: SIOCGIWAUTH\n", dev->name));
+
+ paramid = vwrq->flags & IW_AUTH_INDEX;
+
+ switch (paramid) {
+ case IW_AUTH_WPA_VERSION:
+ /* supported wpa version disabled or wpa or wpa2 */
+ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
+ return error;
+ if (val & (WPA_AUTH_NONE | WPA_AUTH_DISABLED))
+ paramval = IW_AUTH_WPA_VERSION_DISABLED;
+ else if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED))
+ paramval = IW_AUTH_WPA_VERSION_WPA;
+ else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED))
+ paramval = IW_AUTH_WPA_VERSION_WPA2;
+ break;
+
+ case IW_AUTH_CIPHER_PAIRWISE:
+ paramval = iw->pwsec;
+ break;
+
+ case IW_AUTH_CIPHER_GROUP:
+ paramval = iw->gwsec;
+ break;
+
+ case IW_AUTH_KEY_MGMT:
+ /* psk, 1x */
+ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
+ return error;
+ if (VAL_PSK(val))
+ paramval = IW_AUTH_KEY_MGMT_PSK;
+ else
+ paramval = IW_AUTH_KEY_MGMT_802_1X;
+
+ break;
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ dev_wlc_bufvar_get(dev, "tkip_countermeasures", (char *)&paramval, 1);
+ break;
+
+ case IW_AUTH_DROP_UNENCRYPTED:
+ dev_wlc_bufvar_get(dev, "wsec_restrict", (char *)&paramval, 1);
+ break;
+
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol", (char *)&paramval, 1);
+ break;
+
+ case IW_AUTH_80211_AUTH_ALG:
+ /* open, shared, leap */
+ if ((error = dev_wlc_intvar_get(dev, "auth", &val)))
+ return error;
+ if (!val)
+ paramval = IW_AUTH_ALG_OPEN_SYSTEM;
+ else
+ paramval = IW_AUTH_ALG_SHARED_KEY;
+ break;
+ case IW_AUTH_WPA_ENABLED:
+ if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
+ return error;
+ if (val)
+ paramval = TRUE;
+ else
+ paramval = FALSE;
+ break;
+
+#if WIRELESS_EXT > 17
+
+ case IW_AUTH_ROAMING_CONTROL:
+ WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__));
+ /* driver control or user space app control */
+ break;
+
+ case IW_AUTH_PRIVACY_INVOKED:
+ paramval = iw->privacy_invoked;
+ break;
+
+#endif /* WIRELESS_EXT > 17 */
+ }
+ vwrq->value = paramval;
+ return 0;
+}
+#endif /* WIRELESS_EXT > 17 */
+
+static const iw_handler wl_iw_handler[] =
+{
+ (iw_handler) wl_iw_config_commit, /* SIOCSIWCOMMIT */
+ (iw_handler) wl_iw_get_name, /* SIOCGIWNAME */
+ (iw_handler) NULL, /* SIOCSIWNWID */
+ (iw_handler) NULL, /* SIOCGIWNWID */
+ (iw_handler) wl_iw_set_freq, /* SIOCSIWFREQ */
+ (iw_handler) wl_iw_get_freq, /* SIOCGIWFREQ */
+ (iw_handler) wl_iw_set_mode, /* SIOCSIWMODE */
+ (iw_handler) wl_iw_get_mode, /* SIOCGIWMODE */
+ (iw_handler) NULL, /* SIOCSIWSENS */
+ (iw_handler) NULL, /* SIOCGIWSENS */
+ (iw_handler) NULL, /* SIOCSIWRANGE */
+ (iw_handler) wl_iw_get_range, /* SIOCGIWRANGE */
+ (iw_handler) NULL, /* SIOCSIWPRIV */
+ (iw_handler) NULL, /* SIOCGIWPRIV */
+ (iw_handler) NULL, /* SIOCSIWSTATS */
+ (iw_handler) NULL, /* SIOCGIWSTATS */
+ (iw_handler) wl_iw_set_spy, /* SIOCSIWSPY */
+ (iw_handler) wl_iw_get_spy, /* SIOCGIWSPY */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) wl_iw_set_wap, /* SIOCSIWAP */
+ (iw_handler) wl_iw_get_wap, /* SIOCGIWAP */
+#if WIRELESS_EXT > 17
+ (iw_handler) wl_iw_mlme, /* SIOCSIWMLME */
+#else
+ (iw_handler) NULL, /* -- hole -- */
+#endif
+ (iw_handler) wl_iw_iscan_get_aplist, /* SIOCGIWAPLIST */
+#if WIRELESS_EXT > 13
+ (iw_handler) wl_iw_iscan_set_scan, /* SIOCSIWSCAN */
+ (iw_handler) wl_iw_iscan_get_scan, /* SIOCGIWSCAN */
+#else /* WIRELESS_EXT > 13 */
+ (iw_handler) NULL, /* SIOCSIWSCAN */
+ (iw_handler) NULL, /* SIOCGIWSCAN */
+#endif /* WIRELESS_EXT > 13 */
+ (iw_handler) wl_iw_set_essid, /* SIOCSIWESSID */
+ (iw_handler) wl_iw_get_essid, /* SIOCGIWESSID */
+ (iw_handler) wl_iw_set_nick, /* SIOCSIWNICKN */
+ (iw_handler) wl_iw_get_nick, /* SIOCGIWNICKN */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) wl_iw_set_rate, /* SIOCSIWRATE */
+ (iw_handler) wl_iw_get_rate, /* SIOCGIWRATE */
+ (iw_handler) wl_iw_set_rts, /* SIOCSIWRTS */
+ (iw_handler) wl_iw_get_rts, /* SIOCGIWRTS */
+ (iw_handler) wl_iw_set_frag, /* SIOCSIWFRAG */
+ (iw_handler) wl_iw_get_frag, /* SIOCGIWFRAG */
+ (iw_handler) wl_iw_set_txpow, /* SIOCSIWTXPOW */
+ (iw_handler) wl_iw_get_txpow, /* SIOCGIWTXPOW */
+#if WIRELESS_EXT > 10
+ (iw_handler) wl_iw_set_retry, /* SIOCSIWRETRY */
+ (iw_handler) wl_iw_get_retry, /* SIOCGIWRETRY */
+#endif /* WIRELESS_EXT > 10 */
+ (iw_handler) wl_iw_set_encode, /* SIOCSIWENCODE */
+ (iw_handler) wl_iw_get_encode, /* SIOCGIWENCODE */
+ (iw_handler) wl_iw_set_power, /* SIOCSIWPOWER */
+ (iw_handler) wl_iw_get_power, /* SIOCGIWPOWER */
+#if WIRELESS_EXT > 17
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) wl_iw_set_wpaie, /* SIOCSIWGENIE */
+ (iw_handler) wl_iw_get_wpaie, /* SIOCGIWGENIE */
+ (iw_handler) wl_iw_set_wpaauth, /* SIOCSIWAUTH */
+ (iw_handler) wl_iw_get_wpaauth, /* SIOCGIWAUTH */
+ (iw_handler) wl_iw_set_encodeext, /* SIOCSIWENCODEEXT */
+ (iw_handler) wl_iw_get_encodeext, /* SIOCGIWENCODEEXT */
+ (iw_handler) wl_iw_set_pmksa, /* SIOCSIWPMKSA */
+#endif /* WIRELESS_EXT > 17 */
+};
+
+#if WIRELESS_EXT > 12
+enum {
+ WL_IW_SET_LEDDC = SIOCIWFIRSTPRIV,
+ WL_IW_SET_VLANMODE,
+ WL_IW_SET_PM,
+#if WIRELESS_EXT > 17
+#endif /* WIRELESS_EXT > 17 */
+ WL_IW_SET_LAST
+};
+
+static iw_handler wl_iw_priv_handler[] = {
+ wl_iw_set_leddc,
+ wl_iw_set_vlanmode,
+ wl_iw_set_pm,
+#if WIRELESS_EXT > 17
+#endif /* WIRELESS_EXT > 17 */
+ NULL
+};
+
+static struct iw_priv_args wl_iw_priv_args[] = {
+ {
+ WL_IW_SET_LEDDC,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ 0,
+ "set_leddc"
+ },
+ {
+ WL_IW_SET_VLANMODE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ 0,
+ "set_vlanmode"
+ },
+ {
+ WL_IW_SET_PM,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ 0,
+ "set_pm"
+ },
+#if WIRELESS_EXT > 17
+#endif /* WIRELESS_EXT > 17 */
+ { 0, 0, 0, { 0 } }
+};
+
+const struct iw_handler_def wl_iw_handler_def =
+{
+ .num_standard = ARRAYSIZE(wl_iw_handler),
+ .num_private = ARRAY_SIZE(wl_iw_priv_handler),
+ .num_private_args = ARRAY_SIZE(wl_iw_priv_args),
+ .standard = (iw_handler *) wl_iw_handler,
+ .private = wl_iw_priv_handler,
+ .private_args = wl_iw_priv_args,
+#if WIRELESS_EXT >= 19
+ get_wireless_stats: dhd_get_wireless_stats,
+#endif /* WIRELESS_EXT >= 19 */
+ };
+#endif /* WIRELESS_EXT > 12 */
+
+int
+wl_iw_ioctl(
+ struct net_device *dev,
+ struct ifreq *rq,
+ int cmd
+)
+{
+ struct iwreq *wrq = (struct iwreq *) rq;
+ struct iw_request_info info;
+ iw_handler handler;
+ char *extra = NULL;
+ size_t token_size = 1;
+ int max_tokens = 0, ret = 0;
+
+ if (cmd < SIOCIWFIRST ||
+ IW_IOCTL_IDX(cmd) >= ARRAYSIZE(wl_iw_handler) ||
+ !(handler = wl_iw_handler[IW_IOCTL_IDX(cmd)]))
+ return -EOPNOTSUPP;
+
+ switch (cmd) {
+
+ case SIOCSIWESSID:
+ case SIOCGIWESSID:
+ case SIOCSIWNICKN:
+ case SIOCGIWNICKN:
+ max_tokens = IW_ESSID_MAX_SIZE + 1;
+ break;
+
+ case SIOCSIWENCODE:
+ case SIOCGIWENCODE:
+#if WIRELESS_EXT > 17
+ case SIOCSIWENCODEEXT:
+ case SIOCGIWENCODEEXT:
+#endif
+ max_tokens = IW_ENCODING_TOKEN_MAX;
+ break;
+
+ case SIOCGIWRANGE:
+ max_tokens = sizeof(struct iw_range);
+ break;
+
+ case SIOCGIWAPLIST:
+ token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality);
+ max_tokens = IW_MAX_AP;
+ break;
+
+#if WIRELESS_EXT > 13
+ case SIOCGIWSCAN:
+ if (g_iscan)
+ max_tokens = wrq->u.data.length;
+ else
+ max_tokens = IW_SCAN_MAX_DATA;
+ break;
+#endif /* WIRELESS_EXT > 13 */
+
+ case SIOCSIWSPY:
+ token_size = sizeof(struct sockaddr);
+ max_tokens = IW_MAX_SPY;
+ break;
+
+ case SIOCGIWSPY:
+ token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality);
+ max_tokens = IW_MAX_SPY;
+ break;
+ default:
+ break;
+ }
+
+ if (max_tokens && wrq->u.data.pointer) {
+ if (wrq->u.data.length > max_tokens)
+ return -E2BIG;
+
+ if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL)))
+ return -ENOMEM;
+
+ if (copy_from_user(extra, wrq->u.data.pointer, wrq->u.data.length * token_size)) {
+ kfree(extra);
+ return -EFAULT;
+ }
+ }
+
+ info.cmd = cmd;
+ info.flags = 0;
+
+ ret = handler(dev, &info, &wrq->u, extra);
+
+ if (extra) {
+ if (copy_to_user(wrq->u.data.pointer, extra, wrq->u.data.length * token_size)) {
+ kfree(extra);
+ return -EFAULT;
+ }
+
+ kfree(extra);
+ }
+
+ return ret;
+}
+
+/* Convert a connection status event into a connection status string.
+ * Returns TRUE if a matching connection status string was found.
+ */
+bool
+wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason,
+ char* stringBuf, uint buflen)
+{
+ typedef struct conn_fail_event_map_t {
+ uint32 inEvent; /* input: event type to match */
+ uint32 inStatus; /* input: event status code to match */
+ uint32 inReason; /* input: event reason code to match */
+ const char* outName; /* output: failure type */
+ const char* outCause; /* output: failure cause */
+ } conn_fail_event_map_t;
+
+ /* Map of WLC_E events to connection failure strings */
+# define WL_IW_DONT_CARE 9999
+ const conn_fail_event_map_t event_map [] = {
+ /* inEvent inStatus inReason */
+ /* outName outCause */
+ {WLC_E_SET_SSID, WLC_E_STATUS_SUCCESS, WL_IW_DONT_CARE,
+ "Conn", "Success"},
+ {WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WL_IW_DONT_CARE,
+ "Conn", "NoNetworks"},
+ {WLC_E_SET_SSID, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
+ "Conn", "ConfigMismatch"},
+ {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_PRUNE_ENCR_MISMATCH,
+ "Conn", "EncrypMismatch"},
+ {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_RSN_MISMATCH,
+ "Conn", "RsnMismatch"},
+ {WLC_E_AUTH, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE,
+ "Conn", "AuthTimeout"},
+ {WLC_E_AUTH, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
+ "Conn", "AuthFail"},
+ {WLC_E_AUTH, WLC_E_STATUS_NO_ACK, WL_IW_DONT_CARE,
+ "Conn", "AuthNoAck"},
+ {WLC_E_REASSOC, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
+ "Conn", "ReassocFail"},
+ {WLC_E_REASSOC, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE,
+ "Conn", "ReassocTimeout"},
+ {WLC_E_REASSOC, WLC_E_STATUS_ABORT, WL_IW_DONT_CARE,
+ "Conn", "ReassocAbort"},
+ {WLC_E_PSK_SUP, WLC_SUP_KEYED, WL_IW_DONT_CARE,
+ "Sup", "ConnSuccess"},
+ {WLC_E_PSK_SUP, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
+ "Sup", "WpaHandshakeFail"},
+ {WLC_E_DEAUTH_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
+ "Conn", "Deauth"},
+ {WLC_E_DISASSOC_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
+ "Conn", "DisassocInd"},
+ {WLC_E_DISASSOC, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
+ "Conn", "Disassoc"}
+ };
+
+ const char* name = "";
+ const char* cause = NULL;
+ int i;
+
+ /* Search the event map table for a matching event */
+ for (i = 0; i < sizeof(event_map)/sizeof(event_map[0]); i++) {
+ const conn_fail_event_map_t* row = &event_map[i];
+ if (row->inEvent == event_type &&
+ (row->inStatus == status || row->inStatus == WL_IW_DONT_CARE) &&
+ (row->inReason == reason || row->inReason == WL_IW_DONT_CARE)) {
+ name = row->outName;
+ cause = row->outCause;
+ break;
+ }
+ }
+
+ /* If found, generate a connection failure string and return TRUE */
+ if (cause) {
+ memset(stringBuf, 0, buflen);
+ snprintf(stringBuf, buflen, "%s %s %02d %02d",
+ name, cause, status, reason);
+ WL_TRACE(("Connection status: %s\n", stringBuf));
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+#if (WIRELESS_EXT > 14)
+/* Check if we have received an event that indicates connection failure
+ * If so, generate a connection failure report string.
+ * The caller supplies a buffer to hold the generated string.
+ */
+static bool
+wl_iw_check_conn_fail(wl_event_msg_t *e, char* stringBuf, uint buflen)
+{
+ uint32 event = ntoh32(e->event_type);
+ uint32 status = ntoh32(e->status);
+ uint32 reason = ntoh32(e->reason);
+
+ if (wl_iw_conn_status_str(event, status, reason, stringBuf, buflen)) {
+ return TRUE;
+ } else
+ {
+ return FALSE;
+ }
+}
+#endif /* WIRELESS_EXT > 14 */
+
+#ifndef IW_CUSTOM_MAX
+#define IW_CUSTOM_MAX 256 /* size of extra buffer used for translation of events */
+#endif /* IW_CUSTOM_MAX */
+
+void
+wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
+{
+#if WIRELESS_EXT > 13
+ union iwreq_data wrqu;
+ char extra[IW_CUSTOM_MAX + 1];
+ int cmd = 0;
+ uint32 event_type = ntoh32(e->event_type);
+ uint16 flags = ntoh16(e->flags);
+ uint32 datalen = ntoh32(e->datalen);
+ uint32 status = ntoh32(e->status);
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ memset(extra, 0, sizeof(extra));
+
+ memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+
+ switch (event_type) {
+ case WLC_E_TXFAIL:
+ cmd = IWEVTXDROP;
+ break;
+#if WIRELESS_EXT > 14
+ case WLC_E_JOIN:
+ case WLC_E_ASSOC_IND:
+ case WLC_E_REASSOC_IND:
+ cmd = IWEVREGISTERED;
+ break;
+ case WLC_E_DEAUTH_IND:
+ case WLC_E_DISASSOC_IND:
+ cmd = SIOCGIWAP;
+ wrqu.data.length = strlen(extra);
+ bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
+ bzero(&extra, ETHER_ADDR_LEN);
+ break;
+
+ case WLC_E_LINK:
+ case WLC_E_NDIS_LINK:
+ cmd = SIOCGIWAP;
+ wrqu.data.length = strlen(extra);
+ if (!(flags & WLC_EVENT_MSG_LINK)) {
+ bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
+ bzero(&extra, ETHER_ADDR_LEN);
+ }
+ break;
+ case WLC_E_ACTION_FRAME:
+ cmd = IWEVCUSTOM;
+ if (datalen + 1 <= sizeof(extra)) {
+ wrqu.data.length = datalen + 1;
+ extra[0] = WLC_E_ACTION_FRAME;
+ memcpy(&extra[1], data, datalen);
+ WL_TRACE(("WLC_E_ACTION_FRAME len %d \n", wrqu.data.length));
+ }
+ break;
+
+ case WLC_E_ACTION_FRAME_COMPLETE:
+ cmd = IWEVCUSTOM;
+ if (sizeof(status) + 1 <= sizeof(extra)) {
+ wrqu.data.length = sizeof(status) + 1;
+ extra[0] = WLC_E_ACTION_FRAME_COMPLETE;
+ memcpy(&extra[1], &status, sizeof(status));
+ WL_TRACE(("wl_iw_event status %d \n", status));
+ }
+ break;
+#endif /* WIRELESS_EXT > 14 */
+#if WIRELESS_EXT > 17
+ case WLC_E_MIC_ERROR: {
+ struct iw_michaelmicfailure *micerrevt = (struct iw_michaelmicfailure *)&extra;
+ cmd = IWEVMICHAELMICFAILURE;
+ wrqu.data.length = sizeof(struct iw_michaelmicfailure);
+ if (flags & WLC_EVENT_MSG_GROUP)
+ micerrevt->flags |= IW_MICFAILURE_GROUP;
+ else
+ micerrevt->flags |= IW_MICFAILURE_PAIRWISE;
+ memcpy(micerrevt->src_addr.sa_data, &e->addr, ETHER_ADDR_LEN);
+ micerrevt->src_addr.sa_family = ARPHRD_ETHER;
+
+ break;
+ }
+
+ case WLC_E_ASSOC_REQ_IE:
+ cmd = IWEVASSOCREQIE;
+ wrqu.data.length = datalen;
+ if (datalen < sizeof(extra))
+ memcpy(extra, data, datalen);
+ break;
+
+ case WLC_E_ASSOC_RESP_IE:
+ cmd = IWEVASSOCRESPIE;
+ wrqu.data.length = datalen;
+ if (datalen < sizeof(extra))
+ memcpy(extra, data, datalen);
+ break;
+
+ case WLC_E_PMKID_CACHE: {
+ struct iw_pmkid_cand *iwpmkidcand = (struct iw_pmkid_cand *)&extra;
+ pmkid_cand_list_t *pmkcandlist;
+ pmkid_cand_t *pmkidcand;
+ int count;
+
+ if (data == NULL)
+ break;
+
+ cmd = IWEVPMKIDCAND;
+ pmkcandlist = data;
+ count = ntoh32_ua((uint8 *)&pmkcandlist->npmkid_cand);
+ wrqu.data.length = sizeof(struct iw_pmkid_cand);
+ pmkidcand = pmkcandlist->pmkid_cand;
+ while (count) {
+ bzero(iwpmkidcand, sizeof(struct iw_pmkid_cand));
+ if (pmkidcand->preauth)
+ iwpmkidcand->flags |= IW_PMKID_CAND_PREAUTH;
+ bcopy(&pmkidcand->BSSID, &iwpmkidcand->bssid.sa_data,
+ ETHER_ADDR_LEN);
+ wireless_send_event(dev, cmd, &wrqu, extra);
+ pmkidcand++;
+ count--;
+ }
+ break;
+ }
+#endif /* WIRELESS_EXT > 17 */
+
+ case WLC_E_SCAN_COMPLETE:
+#if WIRELESS_EXT > 14
+ cmd = SIOCGIWSCAN;
+#endif
+ WL_TRACE(("event WLC_E_SCAN_COMPLETE\n"));
+ if ((g_iscan) && (g_iscan->sysioc_pid >= 0) &&
+ (g_iscan->iscan_state != ISCAN_STATE_IDLE))
+ up(&g_iscan->sysioc_sem);
+ break;
+
+ default:
+ /* Cannot translate event */
+ break;
+ }
+
+ if (cmd) {
+ if (cmd == SIOCGIWSCAN)
+ wireless_send_event(dev, cmd, &wrqu, NULL);
+ else
+ wireless_send_event(dev, cmd, &wrqu, extra);
+ }
+
+#if WIRELESS_EXT > 14
+ /* Look for WLC events that indicate a connection failure.
+ * If found, generate an IWEVCUSTOM event.
+ */
+ memset(extra, 0, sizeof(extra));
+ if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) {
+ cmd = IWEVCUSTOM;
+ wrqu.data.length = strlen(extra);
+ wireless_send_event(dev, cmd, &wrqu, extra);
+ }
+#endif /* WIRELESS_EXT > 14 */
+
+#endif /* WIRELESS_EXT > 13 */
+}
+
+int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats)
+{
+ int res = 0;
+ wl_cnt_t cnt;
+ int phy_noise;
+ int rssi;
+ scb_val_t scb_val;
+
+ phy_noise = 0;
+ if ((res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise, sizeof(phy_noise))))
+ goto done;
+
+ phy_noise = dtoh32(phy_noise);
+ WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n *****", phy_noise));
+
+ scb_val.val = 0;
+ if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t))))
+ goto done;
+
+ rssi = dtoh32(scb_val.val);
+ WL_TRACE(("wl_iw_get_wireless_stats rssi=%d ****** \n", rssi));
+ if (rssi <= WL_IW_RSSI_NO_SIGNAL)
+ wstats->qual.qual = 0;
+ else if (rssi <= WL_IW_RSSI_VERY_LOW)
+ wstats->qual.qual = 1;
+ else if (rssi <= WL_IW_RSSI_LOW)
+ wstats->qual.qual = 2;
+ else if (rssi <= WL_IW_RSSI_GOOD)
+ wstats->qual.qual = 3;
+ else if (rssi <= WL_IW_RSSI_VERY_GOOD)
+ wstats->qual.qual = 4;
+ else
+ wstats->qual.qual = 5;
+
+ /* Wraps to 0 if RSSI is 0 */
+ wstats->qual.level = 0x100 + rssi;
+ wstats->qual.noise = 0x100 + phy_noise;
+#if WIRELESS_EXT > 18
+ wstats->qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM);
+#else
+ wstats->qual.updated |= 7;
+#endif /* WIRELESS_EXT > 18 */
+
+#if WIRELESS_EXT > 11
+ WL_TRACE(("wl_iw_get_wireless_stats counters=%d\n *****", (int)sizeof(wl_cnt_t)));
+
+ memset(&cnt, 0, sizeof(wl_cnt_t));
+ res = dev_wlc_bufvar_get(dev, "counters", (char *)&cnt, sizeof(wl_cnt_t));
+ if (res)
+ {
+ WL_ERROR(("wl_iw_get_wireless_stats counters failed error=%d ****** \n", res));
+ goto done;
+ }
+
+ cnt.version = dtoh16(cnt.version);
+ if (cnt.version != WL_CNT_T_VERSION) {
+ WL_TRACE(("\tIncorrect version of counters struct: expected %d; got %d\n",
+ WL_CNT_T_VERSION, cnt.version));
+ goto done;
+ }
+
+ wstats->discard.nwid = 0;
+ wstats->discard.code = dtoh32(cnt.rxundec);
+ wstats->discard.fragment = dtoh32(cnt.rxfragerr);
+ wstats->discard.retries = dtoh32(cnt.txfail);
+ wstats->discard.misc = dtoh32(cnt.rxrunt) + dtoh32(cnt.rxgiant);
+ wstats->miss.beacon = 0;
+
+ WL_TRACE(("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n",
+ dtoh32(cnt.txframe), dtoh32(cnt.txbyte)));
+ WL_TRACE(("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n", dtoh32(cnt.rxfrmtoolong)));
+ WL_TRACE(("wl_iw_get_wireless_stats counters rxbadplcp=%d\n", dtoh32(cnt.rxbadplcp)));
+ WL_TRACE(("wl_iw_get_wireless_stats counters rxundec=%d\n", dtoh32(cnt.rxundec)));
+ WL_TRACE(("wl_iw_get_wireless_stats counters rxfragerr=%d\n", dtoh32(cnt.rxfragerr)));
+ WL_TRACE(("wl_iw_get_wireless_stats counters txfail=%d\n", dtoh32(cnt.txfail)));
+ WL_TRACE(("wl_iw_get_wireless_stats counters rxrunt=%d\n", dtoh32(cnt.rxrunt)));
+ WL_TRACE(("wl_iw_get_wireless_stats counters rxgiant=%d\n", dtoh32(cnt.rxgiant)));
+
+#endif /* WIRELESS_EXT > 11 */
+
+done:
+ return res;
+}
+
+static void
+wl_iw_timerfunc(ulong data)
+{
+ iscan_info_t *iscan = (iscan_info_t *)data;
+ iscan->timer_on = 0;
+ if (iscan->iscan_state != ISCAN_STATE_IDLE) {
+ WL_TRACE(("timer trigger\n"));
+ up(&iscan->sysioc_sem);
+ }
+}
+
+static void
+wl_iw_set_event_mask(struct net_device *dev)
+{
+ char eventmask[WL_EVENTING_MASK_LEN];
+ char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
+
+ dev_iw_iovar_getbuf(dev, "event_msgs", "", 0, iovbuf, sizeof(iovbuf));
+ bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
+ setbit(eventmask, WLC_E_SCAN_COMPLETE);
+ dev_iw_iovar_setbuf(dev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN,
+ iovbuf, sizeof(iovbuf));
+
+}
+
+static int
+wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid)
+{
+ int err = 0;
+
+ memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
+ params->bss_type = DOT11_BSSTYPE_ANY;
+ params->scan_type = 0;
+ params->nprobes = -1;
+ params->active_time = -1;
+ params->passive_time = -1;
+ params->home_time = -1;
+ params->channel_num = 0;
+
+ params->nprobes = htod32(params->nprobes);
+ params->active_time = htod32(params->active_time);
+ params->passive_time = htod32(params->passive_time);
+ params->home_time = htod32(params->home_time);
+ if (ssid && ssid->SSID_len)
+ memcpy(&params->ssid, ssid, sizeof(wlc_ssid_t));
+
+ return err;
+}
+
+static int
+wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action)
+{
+ int params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params));
+ wl_iscan_params_t *params;
+ int err = 0;
+
+ if (ssid && ssid->SSID_len) {
+ params_size += sizeof(wlc_ssid_t);
+ }
+ params = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL);
+ if (params == NULL) {
+ return -ENOMEM;
+ }
+ memset(params, 0, params_size);
+ ASSERT(params_size < WLC_IOCTL_SMLEN);
+
+ err = wl_iw_iscan_prep(&params->params, ssid);
+
+ if (!err) {
+ params->version = htod32(ISCAN_REQ_VERSION);
+ params->action = htod16(action);
+ params->scan_duration = htod16(0);
+
+ /* params_size += OFFSETOF(wl_iscan_params_t, params); */
+ (void) dev_iw_iovar_setbuf(iscan->dev, "iscan", params, params_size,
+ iscan->ioctlbuf, WLC_IOCTL_SMLEN);
+ }
+
+ kfree(params);
+ return err;
+}
+
+static uint32
+wl_iw_iscan_get(iscan_info_t *iscan)
+{
+ iscan_buf_t * buf;
+ iscan_buf_t * ptr;
+ wl_iscan_results_t * list_buf;
+ wl_iscan_results_t list;
+ wl_scan_results_t *results;
+ uint32 status;
+
+ /* buffers are allocated on demand */
+ if (iscan->list_cur) {
+ buf = iscan->list_cur;
+ iscan->list_cur = buf->next;
+ }
+ else {
+ buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL);
+ if (!buf)
+ return WL_SCAN_RESULTS_ABORTED;
+ buf->next = NULL;
+ if (!iscan->list_hdr)
+ iscan->list_hdr = buf;
+ else {
+ ptr = iscan->list_hdr;
+ while (ptr->next) {
+ ptr = ptr->next;
+ }
+ ptr->next = buf;
+ }
+ }
+ memset(buf->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
+ list_buf = (wl_iscan_results_t*)buf->iscan_buf;
+ results = &list_buf->results;
+ results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
+ results->version = 0;
+ results->count = 0;
+
+ memset(&list, 0, sizeof(list));
+ list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
+ (void) dev_iw_iovar_getbuf(
+ iscan->dev,
+ "iscanresults",
+ &list,
+ WL_ISCAN_RESULTS_FIXED_SIZE,
+ buf->iscan_buf,
+ WLC_IW_ISCAN_MAXLEN);
+ results->buflen = dtoh32(results->buflen);
+ results->version = dtoh32(results->version);
+ results->count = dtoh32(results->count);
+ WL_TRACE(("results->count = %d\n", results->count));
+
+ WL_TRACE(("results->buflen = %d\n", results->buflen));
+ status = dtoh32(list_buf->status);
+ return status;
+}
+
+static void wl_iw_send_scan_complete(iscan_info_t *iscan)
+{
+ union iwreq_data wrqu;
+
+ memset(&wrqu, 0, sizeof(wrqu));
+
+ /* wext expects to get no data for SIOCGIWSCAN Event */
+ wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL);
+}
+
+static int
+_iscan_sysioc_thread(void *data)
+{
+ uint32 status;
+ iscan_info_t *iscan = (iscan_info_t *)data;
+
+ DAEMONIZE("iscan_sysioc");
+
+ status = WL_SCAN_RESULTS_PARTIAL;
+ while (down_interruptible(&iscan->sysioc_sem) == 0) {
+ if (iscan->timer_on) {
+ del_timer(&iscan->timer);
+ iscan->timer_on = 0;
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ rtnl_lock();
+#endif
+ status = wl_iw_iscan_get(iscan);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ rtnl_unlock();
+#endif
+
+ switch (status) {
+ case WL_SCAN_RESULTS_PARTIAL:
+ WL_TRACE(("iscanresults incomplete\n"));
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ rtnl_lock();
+#endif
+ /* make sure our buffer size is enough before going next round */
+ wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+ rtnl_unlock();
+#endif
+ /* Reschedule the timer */
+ iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms);
+ add_timer(&iscan->timer);
+ iscan->timer_on = 1;
+ break;
+ case WL_SCAN_RESULTS_SUCCESS:
+ WL_TRACE(("iscanresults complete\n"));
+ iscan->iscan_state = ISCAN_STATE_IDLE;
+ wl_iw_send_scan_complete(iscan);
+ break;
+ case WL_SCAN_RESULTS_PENDING:
+ WL_TRACE(("iscanresults pending\n"));
+ /* Reschedule the timer */
+ iscan->timer.expires = jiffies + msecs_to_jiffies(iscan->timer_ms);
+ add_timer(&iscan->timer);
+ iscan->timer_on = 1;
+ break;
+ case WL_SCAN_RESULTS_ABORTED:
+ WL_TRACE(("iscanresults aborted\n"));
+ iscan->iscan_state = ISCAN_STATE_IDLE;
+ wl_iw_send_scan_complete(iscan);
+ break;
+ default:
+ WL_TRACE(("iscanresults returned unknown status %d\n", status));
+ break;
+ }
+ }
+ complete_and_exit(&iscan->sysioc_exited, 0);
+}
+
+int
+wl_iw_attach(struct net_device *dev, void * dhdp)
+{
+ iscan_info_t *iscan = NULL;
+
+ if (!dev)
+ return 0;
+
+ iscan = kmalloc(sizeof(iscan_info_t), GFP_KERNEL);
+ if (!iscan)
+ return -ENOMEM;
+ memset(iscan, 0, sizeof(iscan_info_t));
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
+ iscan->kthread = NULL;
+#endif
+ iscan->sysioc_pid = -1;
+ /* we only care about main interface so save a global here */
+ g_iscan = iscan;
+ iscan->dev = dev;
+ iscan->iscan_state = ISCAN_STATE_IDLE;
+
+
+ /* Set up the timer */
+ iscan->timer_ms = 2000;
+ init_timer(&iscan->timer);
+ iscan->timer.data = (ulong)iscan;
+ iscan->timer.function = wl_iw_timerfunc;
+
+ sema_init(&iscan->sysioc_sem, 0);
+ init_completion(&iscan->sysioc_exited);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
+ iscan->kthread = kthread_run(_iscan_sysioc_thread, iscan, "iscan_sysioc");
+ iscan->sysioc_pid = iscan->kthread->pid;
+#else
+ iscan->sysioc_pid = kernel_thread(_iscan_sysioc_thread, iscan, 0);
+#endif
+ if (iscan->sysioc_pid < 0)
+ return -ENOMEM;
+ return 0;
+}
+
+void wl_iw_detach(void)
+{
+ iscan_buf_t *buf;
+ iscan_info_t *iscan = g_iscan;
+ if (!iscan)
+ return;
+ if (iscan->sysioc_pid >= 0) {
+ KILL_PROC(iscan->sysioc_pid, SIGTERM);
+ wait_for_completion(&iscan->sysioc_exited);
+ }
+
+ while (iscan->list_hdr) {
+ buf = iscan->list_hdr->next;
+ kfree(iscan->list_hdr);
+ iscan->list_hdr = buf;
+ }
+ kfree(iscan);
+ g_iscan = NULL;
+}
+
+#endif /* USE_IW */
diff --git a/drivers/net/wireless/bcmdhd/wl_iw.h b/drivers/net/wireless/bcmdhd/wl_iw.h
new file mode 100644
index 000000000000..abdfa8c2e462
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_iw.h
@@ -0,0 +1,159 @@
+/*
+ * Linux Wireless Extensions support
+ *
+ * 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: wl_iw.h 490106 2014-07-09 12:35:17Z $
+ */
+
+#ifndef _wl_iw_h_
+#define _wl_iw_h_
+
+#include <linux/wireless.h>
+
+#include <typedefs.h>
+#include <proto/ethernet.h>
+#include <wlioctl.h>
+
+#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="
+
+#define BAND_GET_CMD "GETBAND"
+#define BAND_SET_CMD "SETBAND"
+#define DTIM_SKIP_GET_CMD "DTIMSKIPGET"
+#define DTIM_SKIP_SET_CMD "DTIMSKIPSET"
+#define SETSUSPEND_CMD "SETSUSPENDOPT"
+#define PNOSSIDCLR_SET_CMD "PNOSSIDCLR"
+/* Lin - Is the extra space needed? */
+#define PNOSETUP_SET_CMD "PNOSETUP " /* TLV command has extra end space */
+#define PNOENABLE_SET_CMD "PNOFORCE"
+#define PNODEBUG_SET_CMD "PNODEBUG"
+#define TXPOWER_SET_CMD "TXPOWER"
+
+
+/* Structure to keep global parameters */
+typedef struct wl_iw_extra_params {
+ int target_channel; /* target channel */
+} wl_iw_extra_params_t;
+
+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 */
+};
+/* ============================================== */
+/* Defines from wlc_pub.h */
+#define WL_IW_RSSI_MINVAL -200 /* Low value, e.g. for forcing roam */
+#define WL_IW_RSSI_NO_SIGNAL -91 /* NDIS RSSI link quality cutoffs */
+#define WL_IW_RSSI_VERY_LOW -80 /* Very low quality cutoffs */
+#define WL_IW_RSSI_LOW -70 /* Low quality cutoffs */
+#define WL_IW_RSSI_GOOD -68 /* Good quality cutoffs */
+#define WL_IW_RSSI_VERY_GOOD -58 /* Very good quality cutoffs */
+#define WL_IW_RSSI_EXCELLENT -57 /* Excellent quality cutoffs */
+#define WL_IW_RSSI_INVALID 0 /* invalid RSSI value */
+#define MAX_WX_STRING 80
+#define SSID_FMT_BUF_LEN ((4 * 32) + 1)
+#define isprint(c) bcm_isprint(c)
+#define WL_IW_SET_ACTIVE_SCAN (SIOCIWFIRSTPRIV+1)
+#define WL_IW_GET_RSSI (SIOCIWFIRSTPRIV+3)
+#define WL_IW_SET_PASSIVE_SCAN (SIOCIWFIRSTPRIV+5)
+#define WL_IW_GET_LINK_SPEED (SIOCIWFIRSTPRIV+7)
+#define WL_IW_GET_CURR_MACADDR (SIOCIWFIRSTPRIV+9)
+#define WL_IW_SET_STOP (SIOCIWFIRSTPRIV+11)
+#define WL_IW_SET_START (SIOCIWFIRSTPRIV+13)
+
+#define G_SCAN_RESULTS 8*1024
+#define WE_ADD_EVENT_FIX 0x80
+#define G_WLAN_SET_ON 0
+#define G_WLAN_SET_OFF 1
+
+
+typedef struct wl_iw {
+ char nickname[IW_ESSID_MAX_SIZE];
+
+ struct iw_statistics wstats;
+
+ int spy_num;
+ uint32 pwsec; /* pairwise wsec setting */
+ uint32 gwsec; /* group wsec setting */
+ bool privacy_invoked; /* IW_AUTH_PRIVACY_INVOKED setting */
+ struct ether_addr spy_addr[IW_MAX_SPY];
+ struct iw_quality spy_qual[IW_MAX_SPY];
+ void *wlinfo;
+} wl_iw_t;
+
+struct wl_ctrl {
+ struct timer_list *timer;
+ struct net_device *dev;
+ long sysioc_pid;
+ struct semaphore sysioc_sem;
+ struct completion sysioc_exited;
+};
+
+
+#if WIRELESS_EXT > 12
+#include <net/iw_handler.h>
+extern const struct iw_handler_def wl_iw_handler_def;
+#endif /* WIRELESS_EXT > 12 */
+
+extern int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+extern void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data);
+extern int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats);
+int wl_iw_attach(struct net_device *dev, void * dhdp);
+int wl_iw_send_priv_event(struct net_device *dev, char *flag);
+
+void wl_iw_detach(void);
+
+#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'
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
+#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \
+ iwe_stream_add_event(info, stream, ends, iwe, extra)
+#define IWE_STREAM_ADD_VALUE(info, event, value, ends, iwe, event_len) \
+ iwe_stream_add_value(info, event, value, ends, iwe, event_len)
+#define IWE_STREAM_ADD_POINT(info, stream, ends, iwe, extra) \
+ iwe_stream_add_point(info, stream, ends, iwe, extra)
+#else
+#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \
+ iwe_stream_add_event(stream, ends, iwe, extra)
+#define IWE_STREAM_ADD_VALUE(info, event, value, ends, iwe, event_len) \
+ iwe_stream_add_value(event, value, ends, iwe, event_len)
+#define IWE_STREAM_ADD_POINT(info, stream, ends, iwe, extra) \
+ iwe_stream_add_point(stream, ends, iwe, extra)
+#endif
+
+#endif /* _wl_iw_h_ */
diff --git a/drivers/net/wireless/bcmdhd/wl_linux_mon.c b/drivers/net/wireless/bcmdhd/wl_linux_mon.c
new file mode 100644
index 000000000000..56817ce1e77c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_linux_mon.c
@@ -0,0 +1,403 @@
+/*
+ * Broadcom Dongle Host Driver (DHD), Linux monitor network interface
+ *
+ * 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: wl_linux_mon.c 425343 2013-09-23 23:04:47Z $
+ */
+
+#include <osl.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/ieee80211.h>
+#include <linux/rtnetlink.h>
+#include <net/ieee80211_radiotap.h>
+
+#include <wlioctl.h>
+#include <bcmutils.h>
+#include <dhd_dbg.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+
+typedef enum monitor_states
+{
+ MONITOR_STATE_DEINIT = 0x0,
+ MONITOR_STATE_INIT = 0x1,
+ MONITOR_STATE_INTERFACE_ADDED = 0x2,
+ MONITOR_STATE_INTERFACE_DELETED = 0x4
+} monitor_states_t;
+int dhd_add_monitor(char *name, struct net_device **new_ndev);
+extern int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
+int dhd_del_monitor(struct net_device *ndev);
+int dhd_monitor_init(void *dhd_pub);
+int dhd_monitor_uninit(void);
+
+/**
+ * Local declarations and defintions (not exposed)
+ */
+#ifndef DHD_MAX_IFS
+#define DHD_MAX_IFS 16
+#endif
+#define MON_PRINT(format, ...) printk("DHD-MON: %s " format, __func__, ##__VA_ARGS__)
+#define MON_TRACE MON_PRINT
+
+typedef struct monitor_interface {
+ int radiotap_enabled;
+ struct net_device* real_ndev; /* The real interface that the monitor is on */
+ struct net_device* mon_ndev;
+} monitor_interface;
+
+typedef struct dhd_linux_monitor {
+ void *dhd_pub;
+ monitor_states_t monitor_state;
+ monitor_interface mon_if[DHD_MAX_IFS];
+ struct mutex lock; /* lock to protect mon_if */
+} dhd_linux_monitor_t;
+
+static dhd_linux_monitor_t g_monitor;
+
+static struct net_device* lookup_real_netdev(char *name);
+static monitor_interface* ndev_to_monif(struct net_device *ndev);
+static int dhd_mon_if_open(struct net_device *ndev);
+static int dhd_mon_if_stop(struct net_device *ndev);
+static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev);
+static void dhd_mon_if_set_multicast_list(struct net_device *ndev);
+static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr);
+
+static const struct net_device_ops dhd_mon_if_ops = {
+ .ndo_open = dhd_mon_if_open,
+ .ndo_stop = dhd_mon_if_stop,
+ .ndo_start_xmit = dhd_mon_if_subif_start_xmit,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+ .ndo_set_rx_mode = dhd_mon_if_set_multicast_list,
+#else
+ .ndo_set_multicast_list = dhd_mon_if_set_multicast_list,
+#endif
+ .ndo_set_mac_address = dhd_mon_if_change_mac,
+};
+
+/**
+ * Local static function defintions
+ */
+
+/* Look up dhd's net device table to find a match (e.g. interface "eth0" is a match for "mon.eth0"
+ * "p2p-eth0-0" is a match for "mon.p2p-eth0-0")
+ */
+static struct net_device* lookup_real_netdev(char *name)
+{
+ struct net_device *ndev_found = NULL;
+
+ int i;
+ int len = 0;
+ int last_name_len = 0;
+ struct net_device *ndev;
+
+ /* We need to find interface "p2p-p2p-0" corresponding to monitor interface "mon-p2p-0",
+ * Once mon iface name reaches IFNAMSIZ, it is reset to p2p0-0 and corresponding mon
+ * iface would be mon-p2p0-0.
+ */
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ ndev = dhd_idx2net(g_monitor.dhd_pub, i);
+
+ /* Skip "p2p" and look for "-p2p0-x" in monitor interface name. If it
+ * it matches, then this netdev is the corresponding real_netdev.
+ */
+ if (ndev && strstr(ndev->name, "p2p-p2p0")) {
+ len = strlen("p2p");
+ } else {
+ /* if p2p- is not present, then the IFNAMSIZ have reached and name
+ * would have got reset. In this casse,look for p2p0-x in mon-p2p0-x
+ */
+ len = 0;
+ }
+ if (ndev && strstr(name, (ndev->name + len))) {
+ if (strlen(ndev->name) > last_name_len) {
+ ndev_found = ndev;
+ last_name_len = strlen(ndev->name);
+ }
+ }
+ }
+
+ return ndev_found;
+}
+
+static monitor_interface* ndev_to_monif(struct net_device *ndev)
+{
+ int i;
+
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ if (g_monitor.mon_if[i].mon_ndev == ndev)
+ return &g_monitor.mon_if[i];
+ }
+
+ return NULL;
+}
+
+static int dhd_mon_if_open(struct net_device *ndev)
+{
+ int ret = 0;
+
+ MON_PRINT("enter\n");
+ return ret;
+}
+
+static int dhd_mon_if_stop(struct net_device *ndev)
+{
+ int ret = 0;
+
+ MON_PRINT("enter\n");
+ return ret;
+}
+
+static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ int ret = 0;
+ int rtap_len;
+ int qos_len = 0;
+ int dot11_hdr_len = 24;
+ int snap_len = 6;
+ unsigned char *pdata;
+ unsigned short frame_ctl;
+ unsigned char src_mac_addr[6];
+ unsigned char dst_mac_addr[6];
+ struct ieee80211_hdr *dot11_hdr;
+ struct ieee80211_radiotap_header *rtap_hdr;
+ monitor_interface* mon_if;
+
+ MON_PRINT("enter\n");
+
+ mon_if = ndev_to_monif(ndev);
+ if (mon_if == NULL || mon_if->real_ndev == NULL) {
+ MON_PRINT(" cannot find matched net dev, skip the packet\n");
+ goto fail;
+ }
+
+ if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
+ goto fail;
+
+ rtap_hdr = (struct ieee80211_radiotap_header *)skb->data;
+ if (unlikely(rtap_hdr->it_version))
+ goto fail;
+
+ rtap_len = ieee80211_get_radiotap_len(skb->data);
+ if (unlikely(skb->len < rtap_len))
+ goto fail;
+
+ MON_PRINT("radiotap len (should be 14): %d\n", rtap_len);
+
+ /* Skip the ratio tap header */
+ skb_pull(skb, rtap_len);
+
+ dot11_hdr = (struct ieee80211_hdr *)skb->data;
+ frame_ctl = le16_to_cpu(dot11_hdr->frame_control);
+ /* Check if the QoS bit is set */
+ if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
+ /* Check if this ia a Wireless Distribution System (WDS) frame
+ * which has 4 MAC addresses
+ */
+ if (dot11_hdr->frame_control & 0x0080)
+ qos_len = 2;
+ if ((dot11_hdr->frame_control & 0x0300) == 0x0300)
+ dot11_hdr_len += 6;
+
+ memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr));
+ memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr));
+
+ /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for
+ * for two MAC addresses
+ */
+ skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2);
+ pdata = (unsigned char*)skb->data;
+ memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr));
+ memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr));
+ PKTSETPRIO(skb, 0);
+
+ MON_PRINT("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
+
+ /* Use the real net device to transmit the packet */
+ ret = dhd_start_xmit(skb, mon_if->real_ndev);
+
+ return ret;
+ }
+fail:
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+static void dhd_mon_if_set_multicast_list(struct net_device *ndev)
+{
+ monitor_interface* mon_if;
+
+ mon_if = ndev_to_monif(ndev);
+ if (mon_if == NULL || mon_if->real_ndev == NULL) {
+ MON_PRINT(" cannot find matched net dev, skip the packet\n");
+ } else {
+ MON_PRINT("enter, if name: %s, matched if name %s\n",
+ ndev->name, mon_if->real_ndev->name);
+ }
+}
+
+static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr)
+{
+ int ret = 0;
+ monitor_interface* mon_if;
+
+ mon_if = ndev_to_monif(ndev);
+ if (mon_if == NULL || mon_if->real_ndev == NULL) {
+ MON_PRINT(" cannot find matched net dev, skip the packet\n");
+ } else {
+ MON_PRINT("enter, if name: %s, matched if name %s\n",
+ ndev->name, mon_if->real_ndev->name);
+ }
+ return ret;
+}
+
+/**
+ * Global function definitions (declared in dhd_linux_mon.h)
+ */
+
+int dhd_add_monitor(char *name, struct net_device **new_ndev)
+{
+ int i;
+ int idx = -1;
+ int ret = 0;
+ struct net_device* ndev = NULL;
+ dhd_linux_monitor_t **dhd_mon;
+
+ mutex_lock(&g_monitor.lock);
+
+ MON_TRACE("enter, if name: %s\n", name);
+ if (!name || !new_ndev) {
+ MON_PRINT("invalid parameters\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * Find a vacancy
+ */
+ for (i = 0; i < DHD_MAX_IFS; i++)
+ if (g_monitor.mon_if[i].mon_ndev == NULL) {
+ idx = i;
+ break;
+ }
+ if (idx == -1) {
+ MON_PRINT("exceeds maximum interfaces\n");
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ndev = alloc_etherdev(sizeof(dhd_linux_monitor_t*));
+ if (!ndev) {
+ MON_PRINT("failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ndev->type = ARPHRD_IEEE80211_RADIOTAP;
+ strncpy(ndev->name, name, IFNAMSIZ);
+ ndev->name[IFNAMSIZ - 1] = 0;
+ ndev->netdev_ops = &dhd_mon_if_ops;
+
+ ret = register_netdevice(ndev);
+ if (ret) {
+ MON_PRINT(" register_netdevice failed (%d)\n", ret);
+ goto out;
+ }
+
+ *new_ndev = ndev;
+ g_monitor.mon_if[idx].radiotap_enabled = TRUE;
+ g_monitor.mon_if[idx].mon_ndev = ndev;
+ g_monitor.mon_if[idx].real_ndev = lookup_real_netdev(name);
+ dhd_mon = (dhd_linux_monitor_t **)netdev_priv(ndev);
+ *dhd_mon = &g_monitor;
+ g_monitor.monitor_state = MONITOR_STATE_INTERFACE_ADDED;
+ MON_PRINT("net device returned: 0x%p\n", ndev);
+ MON_PRINT("found a matched net device, name %s\n", g_monitor.mon_if[idx].real_ndev->name);
+
+out:
+ if (ret && ndev)
+ free_netdev(ndev);
+
+ mutex_unlock(&g_monitor.lock);
+ return ret;
+
+}
+
+int dhd_del_monitor(struct net_device *ndev)
+{
+ int i;
+ if (!ndev)
+ return -EINVAL;
+ mutex_lock(&g_monitor.lock);
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ if (g_monitor.mon_if[i].mon_ndev == ndev ||
+ g_monitor.mon_if[i].real_ndev == ndev) {
+
+ g_monitor.mon_if[i].real_ndev = NULL;
+ unregister_netdevice(g_monitor.mon_if[i].mon_ndev);
+ free_netdev(g_monitor.mon_if[i].mon_ndev);
+ g_monitor.mon_if[i].mon_ndev = NULL;
+ g_monitor.monitor_state = MONITOR_STATE_INTERFACE_DELETED;
+ break;
+ }
+ }
+
+ if (g_monitor.monitor_state != MONITOR_STATE_INTERFACE_DELETED)
+ MON_PRINT("IF not found in monitor array, is this a monitor IF? 0x%p\n", ndev);
+ mutex_unlock(&g_monitor.lock);
+
+ return 0;
+}
+
+int dhd_monitor_init(void *dhd_pub)
+{
+ if (g_monitor.monitor_state == MONITOR_STATE_DEINIT) {
+ g_monitor.dhd_pub = dhd_pub;
+ mutex_init(&g_monitor.lock);
+ g_monitor.monitor_state = MONITOR_STATE_INIT;
+ }
+ return 0;
+}
+
+int dhd_monitor_uninit(void)
+{
+ int i;
+ struct net_device *ndev;
+ mutex_lock(&g_monitor.lock);
+ if (g_monitor.monitor_state != MONITOR_STATE_DEINIT) {
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ ndev = g_monitor.mon_if[i].mon_ndev;
+ if (ndev) {
+ unregister_netdevice(ndev);
+ free_netdev(ndev);
+ g_monitor.mon_if[i].real_ndev = NULL;
+ g_monitor.mon_if[i].mon_ndev = NULL;
+ }
+ }
+ g_monitor.monitor_state = MONITOR_STATE_DEINIT;
+ }
+ mutex_unlock(&g_monitor.lock);
+ return 0;
+}
diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c
new file mode 100644
index 000000000000..64f3443b2a02
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wldev_common.c
@@ -0,0 +1,479 @@
+/*
+ * Common function shared by Linux WEXT, cfg80211 and p2p drivers
+ *
+ * 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: wldev_common.c 657248 2016-08-31 11:29:39Z $
+ */
+
+#include <osl.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+
+#include <wldev_common.h>
+#include <bcmutils.h>
+
+#define htod32(i) (i)
+#define htod16(i) (i)
+#define dtoh32(i) (i)
+#define dtoh16(i) (i)
+#define htodchanspec(i) (i)
+#define dtohchanspec(i) (i)
+
+#define WLDEV_ERROR(args) \
+ do { \
+ printk(KERN_ERR "WLDEV-ERROR) "); \
+ printk args; \
+ } while (0)
+
+#define WLDEV_INFO(args) \
+ do { \
+ printk(KERN_INFO "WLDEV-INFO) "); \
+ printk args; \
+ } while (0)
+
+extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd);
+
+#define MAX_NUM_OF_ASSOCLIST 64
+s32 wldev_ioctl(
+ struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set)
+{
+ s32 ret = 0;
+ struct wl_ioctl ioc;
+
+
+ memset(&ioc, 0, sizeof(ioc));
+ ioc.cmd = cmd;
+ ioc.buf = arg;
+ ioc.len = len;
+ ioc.set = set;
+
+ ret = dhd_ioctl_entry_local(dev, &ioc, cmd);
+
+ return ret;
+}
+
+/* Format a iovar buffer, not bsscfg indexed. The bsscfg index will be
+ * taken care of in dhd_ioctl_entry. Internal use only, not exposed to
+ * wl_iw, wl_cfg80211 and wl_cfgp2p
+ */
+static s32 wldev_mkiovar(
+ s8 *iovar_name, s8 *param, s32 paramlen,
+ s8 *iovar_buf, u32 buflen)
+{
+ s32 iolen = 0;
+
+ iolen = bcm_mkiovar(iovar_name, param, paramlen, iovar_buf, buflen);
+ return iolen;
+}
+
+s32 wldev_iovar_getbuf(
+ struct net_device *dev, s8 *iovar_name,
+ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
+{
+ s32 ret = 0;
+ if (buf_sync) {
+ mutex_lock(buf_sync);
+ }
+ wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
+ ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
+ if (buf_sync)
+ mutex_unlock(buf_sync);
+ return ret;
+}
+
+
+s32 wldev_iovar_setbuf(
+ struct net_device *dev, s8 *iovar_name,
+ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
+{
+ s32 ret = 0;
+ s32 iovar_len;
+ if (buf_sync) {
+ mutex_lock(buf_sync);
+ }
+ iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
+ if (iovar_len > 0)
+ ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE);
+ else
+ ret = BCME_BUFTOOSHORT;
+
+ if (buf_sync)
+ mutex_unlock(buf_sync);
+ return ret;
+}
+
+s32 wldev_iovar_setint(
+ struct net_device *dev, s8 *iovar, s32 val)
+{
+ s8 iovar_buf[WLC_IOCTL_SMLEN];
+
+ val = htod32(val);
+ memset(iovar_buf, 0, sizeof(iovar_buf));
+ return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf,
+ sizeof(iovar_buf), NULL);
+}
+
+
+s32 wldev_iovar_getint(
+ struct net_device *dev, s8 *iovar, s32 *pval)
+{
+ s8 iovar_buf[WLC_IOCTL_SMLEN];
+ s32 err;
+
+ memset(iovar_buf, 0, sizeof(iovar_buf));
+ err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf,
+ sizeof(iovar_buf), NULL);
+ if (err == 0)
+ {
+ memcpy(pval, iovar_buf, sizeof(*pval));
+ *pval = dtoh32(*pval);
+ }
+ return err;
+}
+
+/** Format a bsscfg indexed iovar buffer. The bsscfg index will be
+ * taken care of in dhd_ioctl_entry. Internal use only, not exposed to
+ * wl_iw, wl_cfg80211 and wl_cfgp2p
+ */
+s32 wldev_mkiovar_bsscfg(
+ const s8 *iovar_name, s8 *param, s32 paramlen,
+ s8 *iovar_buf, s32 buflen, s32 bssidx)
+{
+ const s8 *prefix = "bsscfg:";
+ s8 *p;
+ u32 prefixlen;
+ u32 namelen;
+ u32 iolen;
+
+ if (bssidx == 0) {
+ return wldev_mkiovar((s8*)iovar_name, (s8 *)param, paramlen,
+ (s8 *) iovar_buf, buflen);
+ }
+
+ prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */
+ namelen = (u32) strlen(iovar_name) + 1; /* lengh of iovar name + null */
+ iolen = prefixlen + namelen + sizeof(u32) + paramlen;
+
+ if (buflen < 0 || iolen > (u32)buflen)
+ {
+ WLDEV_ERROR(("%s: buffer is too short\n", __FUNCTION__));
+ return BCME_BUFTOOSHORT;
+ }
+
+ p = (s8 *)iovar_buf;
+
+ /* copy prefix, no null */
+ memcpy(p, prefix, prefixlen);
+ p += prefixlen;
+
+ /* copy iovar name including null */
+ memcpy(p, iovar_name, namelen);
+ p += namelen;
+
+ /* bss config index as first param */
+ bssidx = htod32(bssidx);
+ memcpy(p, &bssidx, sizeof(u32));
+ p += sizeof(u32);
+
+ /* parameter buffer follows */
+ if (paramlen)
+ memcpy(p, param, paramlen);
+
+ return iolen;
+
+}
+
+s32 wldev_iovar_getbuf_bsscfg(
+ struct net_device *dev, s8 *iovar_name,
+ void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
+{
+ s32 ret = 0;
+ if (buf_sync) {
+ mutex_lock(buf_sync);
+ }
+
+ wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
+ ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
+ if (buf_sync) {
+ mutex_unlock(buf_sync);
+ }
+ return ret;
+
+}
+
+s32 wldev_iovar_setbuf_bsscfg(
+ struct net_device *dev, s8 *iovar_name,
+ void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
+{
+ s32 ret = 0;
+ s32 iovar_len;
+ if (buf_sync) {
+ mutex_lock(buf_sync);
+ }
+ iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
+ if (iovar_len > 0)
+ ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE);
+ else {
+ ret = BCME_BUFTOOSHORT;
+ }
+
+ if (buf_sync) {
+ mutex_unlock(buf_sync);
+ }
+ return ret;
+}
+
+s32 wldev_iovar_setint_bsscfg(
+ struct net_device *dev, s8 *iovar, s32 val, s32 bssidx)
+{
+ s8 iovar_buf[WLC_IOCTL_SMLEN];
+
+ val = htod32(val);
+ memset(iovar_buf, 0, sizeof(iovar_buf));
+ return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf,
+ sizeof(iovar_buf), bssidx, NULL);
+}
+
+
+s32 wldev_iovar_getint_bsscfg(
+ struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx)
+{
+ s8 iovar_buf[WLC_IOCTL_SMLEN];
+ s32 err;
+
+ memset(iovar_buf, 0, sizeof(iovar_buf));
+ err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf,
+ sizeof(iovar_buf), bssidx, NULL);
+ if (err == 0)
+ {
+ memcpy(pval, iovar_buf, sizeof(*pval));
+ *pval = dtoh32(*pval);
+ }
+ return err;
+}
+
+int wldev_get_link_speed(
+ struct net_device *dev, int *plink_speed)
+{
+ int error;
+
+ if (!plink_speed)
+ return -ENOMEM;
+ error = wldev_ioctl(dev, WLC_GET_RATE, plink_speed, sizeof(int), 0);
+ if (unlikely(error))
+ return error;
+
+ /* Convert internal 500Kbps to Kbps */
+ *plink_speed *= 500;
+ return error;
+}
+
+int wldev_get_rssi(
+ struct net_device *dev, scb_val_t *scb_val)
+{
+ int error;
+
+ if (!scb_val)
+ return -ENOMEM;
+
+ error = wldev_ioctl(dev, WLC_GET_RSSI, scb_val, sizeof(scb_val_t), 0);
+ if (unlikely(error))
+ return error;
+
+ return error;
+}
+
+int wldev_get_ssid(
+ struct net_device *dev, wlc_ssid_t *pssid)
+{
+ int error;
+
+ if (!pssid)
+ return -ENOMEM;
+ error = wldev_ioctl(dev, WLC_GET_SSID, pssid, sizeof(wlc_ssid_t), 0);
+ if (unlikely(error))
+ return error;
+ pssid->SSID_len = dtoh32(pssid->SSID_len);
+ return error;
+}
+
+int wldev_get_band(
+ struct net_device *dev, uint *pband)
+{
+ int error;
+
+ error = wldev_ioctl(dev, WLC_GET_BAND, pband, sizeof(uint), 0);
+ return error;
+}
+
+int wldev_set_band(
+ struct net_device *dev, uint band)
+{
+ int error = -1;
+
+ if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) {
+ error = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true);
+ if (!error)
+ dhd_bus_band_set(dev, band);
+ }
+ return error;
+}
+
+int wldev_get_datarate(struct net_device *dev, int *datarate)
+{
+ int error = 0;
+
+ error = wldev_ioctl(dev, WLC_GET_RATE, datarate, sizeof(int), false);
+ if (error) {
+ return -1;
+ } else {
+ *datarate = dtoh32(*datarate);
+ }
+
+ return error;
+}
+
+extern chanspec_t
+wl_chspec_driver_to_host(chanspec_t chanspec);
+#define WL_EXTRA_BUF_MAX 2048
+int wldev_get_mode(
+ struct net_device *dev, uint8 *cap)
+{
+ int error = 0;
+ int chanspec = 0;
+ uint16 band = 0;
+ uint16 bandwidth = 0;
+ wl_bss_info_t *bss = NULL;
+ char* buf = NULL;
+
+ buf = kmalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
+
+ if (!buf) {
+ WLDEV_ERROR(("%s:NOMEM\n", __FUNCTION__));
+ return -ENOMEM;
+ }
+
+ *(u32*) buf = htod32(WL_EXTRA_BUF_MAX);
+ error = wldev_ioctl(dev, WLC_GET_BSS_INFO, (void*)buf, WL_EXTRA_BUF_MAX, false);
+ if (error) {
+ WLDEV_ERROR(("%s:failed:%d\n", __FUNCTION__, error));
+ kfree(buf);
+ buf = NULL;
+ return error;
+ }
+ bss = (struct wl_bss_info *)(buf + 4);
+ chanspec = wl_chspec_driver_to_host(bss->chanspec);
+
+ band = chanspec & WL_CHANSPEC_BAND_MASK;
+ bandwidth = chanspec & WL_CHANSPEC_BW_MASK;
+
+ if (band == WL_CHANSPEC_BAND_2G) {
+ if (bss->n_cap)
+ strcpy(cap, "n");
+ else
+ strcpy(cap, "bg");
+ } else if (band == WL_CHANSPEC_BAND_5G) {
+ if (bandwidth == WL_CHANSPEC_BW_80)
+ strcpy(cap, "ac");
+ else if ((bandwidth == WL_CHANSPEC_BW_40) || (bandwidth == WL_CHANSPEC_BW_20)) {
+ if ((bss->nbss_cap & 0xf00) && (bss->n_cap))
+ strcpy(cap, "n|ac");
+ else if (bss->n_cap)
+ strcpy(cap, "n");
+ else if (bss->vht_cap)
+ strcpy(cap, "ac");
+ else
+ strcpy(cap, "a");
+ } else {
+ WLDEV_ERROR(("%s:Mode get failed\n", __FUNCTION__));
+ error = BCME_ERROR;
+ }
+
+ }
+ kfree(buf);
+ buf = NULL;
+ return error;
+}
+#define MAX_NUM_OF_ASSOCLIST 64
+int wldev_get_assoclist(
+ struct net_device *dev, struct maclist *assoc_maclist, uint length)
+{
+ int ret = 0;
+
+/* get the current list of associated STAs */
+ assoc_maclist->count = MAX_NUM_OF_ASSOCLIST;
+ if ((ret = wldev_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist,
+ length, false)) != 0) {
+ return ret;
+ }
+ return 0;
+}
+
+int wldev_set_country(
+ struct net_device *dev, char *country_code, bool notify, bool user_enforced)
+{
+ int error = -1;
+ wl_country_t cspec = {{0}, 0, {0}};
+ scb_val_t scbval;
+ char smbuf[WLC_IOCTL_SMLEN];
+
+ if (!country_code)
+ return error;
+
+ bzero(&scbval, sizeof(scb_val_t));
+ error = wldev_iovar_getbuf(dev, "country", NULL, 0, &cspec, sizeof(cspec), NULL);
+ if (error < 0) {
+ WLDEV_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error));
+ return error;
+ }
+
+ if ((error < 0) ||
+ (strncmp(country_code, cspec.ccode, WLC_CNTRY_BUF_SZ) != 0)) {
+
+ if (user_enforced) {
+ bzero(&scbval, sizeof(scb_val_t));
+ error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true);
+ if (error < 0) {
+ WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n",
+ __FUNCTION__, error));
+ return error;
+ }
+ }
+
+ cspec.rev = -1;
+ memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ);
+ memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
+ dhd_get_customized_country_code(dev, (char *)&cspec.country_abbrev, &cspec);
+ error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec),
+ smbuf, sizeof(smbuf), NULL);
+ if (error < 0) {
+ WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n",
+ __FUNCTION__, country_code, cspec.ccode, cspec.rev));
+ return error;
+ }
+ dhd_bus_country_set(dev, &cspec, notify);
+ WLDEV_INFO(("%s: set country for %s as %s rev %d\n",
+ __FUNCTION__, country_code, cspec.ccode, cspec.rev));
+ }
+ return 0;
+}
diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h
new file mode 100644
index 000000000000..65e1f6b5e171
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wldev_common.h
@@ -0,0 +1,121 @@
+/*
+ * Common function shared by Linux WEXT, cfg80211 and p2p drivers
+ *
+ * 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: wldev_common.h 513422 2014-11-06 11:06:57Z $
+ */
+#ifndef __WLDEV_COMMON_H__
+#define __WLDEV_COMMON_H__
+
+#include <wlioctl.h>
+
+/* wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or
+ * netdev_ops->ndo_do_ioctl in new kernels)
+ * @dev: the net_device handle
+ */
+s32 wldev_ioctl(
+ struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set);
+
+/** Retrieve named IOVARs, this function calls wl_dev_ioctl with
+ * WLC_GET_VAR IOCTL code
+ */
+s32 wldev_iovar_getbuf(
+ struct net_device *dev, s8 *iovar_name,
+ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync);
+
+/** Set named IOVARs, this function calls wl_dev_ioctl with
+ * WLC_SET_VAR IOCTL code
+ */
+s32 wldev_iovar_setbuf(
+ struct net_device *dev, s8 *iovar_name,
+ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync);
+
+s32 wldev_iovar_setint(
+ struct net_device *dev, s8 *iovar, s32 val);
+
+s32 wldev_iovar_getint(
+ struct net_device *dev, s8 *iovar, s32 *pval);
+
+/** The following function can be implemented if there is a need for bsscfg
+ * indexed IOVARs
+ */
+
+s32 wldev_mkiovar_bsscfg(
+ const s8 *iovar_name, s8 *param, s32 paramlen,
+ s8 *iovar_buf, s32 buflen, s32 bssidx);
+
+/** Retrieve named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with
+ * WLC_GET_VAR IOCTL code
+ */
+s32 wldev_iovar_getbuf_bsscfg(
+ struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen,
+ void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync);
+
+/** Set named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with
+ * WLC_SET_VAR IOCTL code
+ */
+s32 wldev_iovar_setbuf_bsscfg(
+ struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen,
+ void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync);
+
+s32 wldev_iovar_getint_bsscfg(
+ struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx);
+
+s32 wldev_iovar_setint_bsscfg(
+ struct net_device *dev, s8 *iovar, s32 val, s32 bssidx);
+
+extern int dhd_net_set_fw_path(struct net_device *dev, char *fw);
+extern int dhd_net_bus_suspend(struct net_device *dev);
+extern int dhd_net_bus_resume(struct net_device *dev, uint8 stage);
+extern int dhd_net_wifi_platform_set_power(struct net_device *dev, bool on,
+ unsigned long delay_msec);
+extern void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code,
+ wl_country_t *cspec);
+extern void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify);
+extern void dhd_bus_band_set(struct net_device *dev, uint band);
+extern int wldev_set_country(struct net_device *dev, char *country_code, bool notify,
+ bool user_enforced);
+extern int net_os_wake_lock(struct net_device *dev);
+extern int net_os_wake_unlock(struct net_device *dev);
+extern int net_os_wake_lock_timeout(struct net_device *dev);
+extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val);
+extern int net_os_set_dtim_skip(struct net_device *dev, int val);
+extern int net_os_set_suspend_disable(struct net_device *dev, int val);
+extern int net_os_set_suspend(struct net_device *dev, int val, int force);
+extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid,
+ int max, int *bytes_left);
+
+/* Get the link speed from dongle, speed is in kpbs */
+int wldev_get_link_speed(struct net_device *dev, int *plink_speed);
+
+int wldev_get_rssi(struct net_device *dev, scb_val_t *prssi);
+
+int wldev_get_ssid(struct net_device *dev, wlc_ssid_t *pssid);
+
+int wldev_get_band(struct net_device *dev, uint *pband);
+int wldev_get_mode(struct net_device *dev, uint8 *pband);
+int wldev_get_chanspec(struct net_device *dev, uint16 *pband);
+int wldev_get_datarate(struct net_device *dev, int *datarate);
+int wldev_get_assoclist(struct net_device *dev, struct maclist *maclist, uint length);
+int wldev_set_band(struct net_device *dev, uint band);
+
+#endif /* __WLDEV_COMMON_H__ */
diff --git a/drivers/net/wireless/bcmdhd_1363/Kconfig b/drivers/net/wireless/bcmdhd_1363/Kconfig
new file mode 100644
index 000000000000..9b845cc85acf
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/Kconfig
@@ -0,0 +1,53 @@
+config BCMDHD_1363
+ tristate "Broadcom FullMAC wireless cards support v1.363"
+ depends on !BCMDHD
+ ---help---
+ This module adds support for wireless adapters based on
+ Broadcom FullMAC chipset.
+
+ If you choose to build a module, it'll be called dhd. Say M if
+ unsure.
+
+config BCMDHD_PCIE
+ bool "PCIe bus interface support"
+ depends on BCMDHD_1363 && PCI && !BCMDHD_SDIO
+
+config BCM4359
+ bool "BCM4359 support"
+ depends on BCMDHD_1363
+ default y
+
+config BCMDHD_FW_PATH
+ depends on BCMDHD_1363
+ string "Firmware path"
+ default "/system/vendor/firmware/fw_bcmdhd.bin"
+ ---help---
+ Path to the firmware file.
+
+config BCMDHD_NVRAM_PATH
+ depends on BCMDHD_1363
+ string "NVRAM path"
+ default "/system/etc/wifi/bcmdhd.cal"
+ ---help---
+ Path to the calibration file.
+
+config DHD_USE_STATIC_BUF
+ bool "Enable memory preallocation"
+ depends on BCMDHD_1363
+ default n
+ ---help---
+ Use memory preallocated in platform
+
+config DHD_USE_SCHED_SCAN
+ bool "Use CFG80211 sched scan"
+ depends on BCMDHD_1363 && CFG80211
+ default n
+ ---help---
+ Use CFG80211 sched scan
+
+config DHD_SET_RANDOM_MAC_VAL
+hex "Vendor OUI"
+depends on BCMDHD_1363
+default 0x001A11
+ ---help---
+Set vendor OUI for SoftAP
diff --git a/drivers/net/wireless/bcmdhd_1363/Makefile b/drivers/net/wireless/bcmdhd_1363/Makefile
new file mode 100644
index 000000000000..330509e57ceb
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/Makefile
@@ -0,0 +1,315 @@
+# bcmdhd
+#####################
+# Basic features
+#####################
+
+DHDCFLAGS += -Wall -Wstrict-prototypes -Dlinux -DLINUX -DBCMDRIVER \
+ -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \
+ -DDHDTHREAD -DSHOW_EVENTS -DBCMDBG -DWLP2P \
+ -DWIFI_ACT_FRAME -DKEEP_ALIVE -DCSCAN -DPKT_FILTER_SUPPORT \
+ -DEMBEDDED_PLATFORM -DPNO_SUPPORT \
+ -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT \
+ -DCUSTOMER_HW2 -DGET_CUSTOM_MAC_ENABLE \
+ -DSHOW_LOGTRACE -DSEC_ENHANCEMENT
+
+# ARP offload feature
+#DHDCFLAGS += -DARP_OFFLOAD_SUPPORT
+
+# FW_COREDUMP
+#DHDCFLAGS += -DDHD_FW_COREDUMP
+
+# Enable below macro if __DATE__ & __TIME__ are deprecated by compiler
+DHDCFLAGS += -DDHD_VERSION_NO_DATE_TIME
+
+#################
+# Common feature
+#################
+
+# DT-based architecture
+DHDCFLAGS += -DCONFIG_DTS
+
+DHDCFLAGS += -DWL_VIRTUAL_APSTA
+
+DHDCFLAGS += -DWL_CFG80211
+# Print out kernel panic point of file and line info when assertion happened
+DHDCFLAGS += -DBCMASSERT_LOG
+
+# ARCH specific flags
+# In case of x86 architechture, pls enable below flag
+#DHDCFLAGS += -D__X86
+
+# CUSTOMER4 flags
+DHDCFLAGS += -DDHD_PKTID_AUDIT_ENABLED
+DHDCFLAGS += -DSUPPORT_HIDDEN_AP -DDHD_LOSSLESS_ROAMING
+DHDCFLAGS += -DPASS_ALL_MCAST_PKTS -DESCAN_BUF_OVERFLOW_MGMT -DPKTPRIO_OVERRIDE
+DHDCFLAGS += -DUSE_INITIAL_SHORT_DWELL_TIME -DWL_NEWCFG_PRIVCMD_SUPPORT
+DHDCFLAGS += -DENABLE_BCN_LI_BCN_WAKEUP -DSOFTAP_UAPSD_OFF
+DHDCFLAGS += -DSUPPORT_LTECX -DSUPPORT_2G_VHT
+DHDCFLAGS += -DSUPPORT_WL_TXPOWER -DBLOCK_IPV6_PACKET -DSUPPORT_DEEP_SLEEP
+DHDCFLAGS += -DSUPPORT_AMPDU_MPDU_CMD -DSOFTAP_SEND_HANGEVT -DNUM_SCB_MAX_PROBE=3
+DHDCFLAGS += -DCUSTOM_AMSDU_AGGSF=2
+DHDCFLAGS += -DCUSTOM_IBSS_AMPDU_BA_WSIZE=16
+DHDCFLAGS += -DCUSTOM_TCPACK_DELAY_TIME=10
+DHDCFLAGS += -DDEBUGFS_CFG80211
+DHDCFLAGS += -DSUPPORT_SOFTAP_WPAWPA2_MIXED
+
+# keepalive
+DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=28000
+
+DHDCFLAGS += -DVSDB
+
+# For p2p connection issue
+DHDCFLAGS += -DWL_SCB_TIMEOUT=10
+
+# TDLS enable
+#DHDCFLAGS += -DWLTDLS -DWLTDLS_AUTO_ENABLE
+# For TDLS tear down inactive time 40 sec
+#DHDCFLAGS += -DCUSTOM_TDLS_IDLE_MODE_SETTING=10000
+# for TDLS RSSI HIGH for establishing TDLS link
+#DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_HIGH=-80
+# for TDLS RSSI HIGH for tearing down TDLS link
+#DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85
+
+# Roaming
+DHDCFLAGS += -DROAM_AP_ENV_DETECTION
+DHDCFLAGS += -DROAM_ENABLE -DROAM_CHANNEL_CACHE -DROAM_API
+DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND
+# Roaming trigger
+DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-75
+DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=10
+# Set PM 2 always regardless suspend/resume
+DHDCFLAGS += -DSUPPORT_PM2_ONLY
+
+# For special PNO Event keep wake lock for 10sec
+DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10
+DHDCFLAGS += -DMIRACAST_AMPDU_SIZE=8
+
+# Gscan suppport
+#DHDCFLAGS += -DGSCAN_SUPPORT
+
+# Early suspend
+DHDCFLAGS += -DDHD_USE_EARLYSUSPEND
+
+# For Scan result patch
+DHDCFLAGS += -DESCAN_RESULT_PATCH
+
+# For Static Buffer
+ifeq ($(CONFIG_DHD_USE_STATIC_BUF),y)
+ DHDCFLAGS += -DENHANCED_STATIC_BUF
+ DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT
+endif
+ifneq ($(CONFIG_DHD_USE_SCHED_SCAN),)
+DHDCFLAGS += -DWL_SCHED_SCAN
+endif
+
+# Ioctl timeout 5000ms
+DHDCFLAGS += -DIOCTL_RESP_TIMEOUT=5000
+
+# Prevent rx thread monopolize
+DHDCFLAGS += -DWAIT_DEQUEUE
+
+# Config PM Control
+DHDCFLAGS += -DDHD_PM_CONTROL_FROM_FILE
+
+# idle count
+DHDCFLAGS += -DDHD_USE_IDLECOUNT
+
+# SKB TAILPAD to avoid out of boundary memory access
+DHDCFLAGS += -DDHDENABLE_TAILPAD
+
+# Wi-Fi Direct
+DHDCFLAGS += -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+DHDCFLAGS += -DWL_CFG80211_STA_EVENT
+DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS
+DHDCFLAGS += -DWL_ENABLE_P2P_IF
+#SCAN time
+DHDCFLAGS += -DCUSTOM_SET_SHORT_DWELL_TIME
+DHDCFLAGS += -DCUSTOM_FORCE_NODFS_FLAG
+
+# SoftAP
+DHDCFLAGS += -DDISABLE_11H_SOFTAP
+DHDCFLAGS += -DSET_RANDOM_MAC_SOFTAP
+DHDCFLAGS += -DWL_CFG80211_ACL
+
+#Disable FRAMEBURST on VSDB
+DHDCFLAGS += -DDISABLE_FRAMEBURST_VSDB
+
+##########################
+# driver type
+# m: module type driver
+# y: built-in type driver
+##########################
+DRIVER_TYPE ?= $(CONFIG_BCMDHD_1363)
+DRIVERX_TYPE ?= $(CONFIG_BCMDHDX)
+
+#########################
+# Chip dependent feature
+#########################
+
+ifneq ($(filter y, $(CONFIG_BCM4359)),)
+ DHDCFLAGS += -DUSE_WL_TXBF
+ DHDCFLAGS += -DUSE_WL_FRAMEBURST
+ DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0
+ DHDCFLAGS += -DPROP_TXSTATUS_VSDB
+ DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30
+ DHDCFLAGS += -DMAX_AP_CLIENT_CNT=10
+ DHDCFLAGS += -DMAX_GO_CLIENT_CNT=5
+# New Features
+ DHDCFLAGS += -DWL11U
+ DHDCFLAGS += -DMFP
+ DHDCFLAGS += -DDHD_ENABLE_LPC
+ DHDCFLAGS += -DCUSTOM_COUNTRY_CODE
+ DHDCFLAGS += -DSAR_SUPPORT
+# debug info
+ DHDCFLAGS += -DDHD_WAKE_STATUS
+
+ifneq ($(CONFIG_BCMDHD_PCIE),)
+ DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1
+# tput enhancement
+ DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64
+ DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=48
+ DHDCFLAGS += -DCUSTOM_AMPDU_RELEASE=32
+ DHDCFLAGS += -DPROP_TXSTATUS_VSDB
+# Disable watchdog thread
+ DHDCFLAGS += -DCUSTOM_DHD_WATCHDOG_MS=0
+ DHDCFLAGS += -DMAX_CNTL_TX_TIMEOUT=1
+ DHDCFLAGS += -DSUPPORT_LINKDOWN_RECOVERY
+# Add Load Balance Feature here
+ DHDCFLAGS += -DDHD_LB
+ DHDCFLAGS += -DDHD_LB_RXP
+ DHDCFLAGS += -DDHD_LB_STATS
+endif
+
+ifneq ($(CONFIG_BCMDHD_SDIO),)
+ DHDCFLAGS += -DBDC -DDHD_BCMEVENTS -DMMC_SDIO_ABORT
+# Macros for HW-OOB
+ DHDCFLAGS += -DOOB_INTR_ONLY -DHW_OOB
+# Enable Below macro for In-Band interrupt
+# DHDCFLAGS += -DSDIO_ISR_THREAD
+ DHDCFLAGS += -DBCMSDIO -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR
+ DHDCFLAGS += -DPROP_TXSTATUS
+ DHDCFLAGS += -DCUSTOM_AMPDU_MPDU=16
+ DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64
+# tput enhancement
+ DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1
+ DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128
+ DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED
+ DHDCFLAGS += -DDHDTCPACK_SUPPRESS
+ DHDCFLAGS += -DRXFRAME_THREAD
+ DHDCFLAGS += -DREPEAT_READFRAME
+ DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=40
+ DHDCFLAGS += -DMAX_HDR_READ=128
+ DHDCFLAGS += -DDHD_FIRSTREAD=128
+ # bcn_timeout
+ DHDCFLAGS += -DCUSTOM_BCN_TIMEOUT=5
+ DHDCFLAGS += -DWLFC_STATE_PREALLOC
+endif
+
+ifeq ($(CONFIG_DHD_USE_STATIC_BUF),y)
+ DHDCFLAGS += -DDHD_USE_STATIC_IOCTLBUF
+endif
+ DHDCFLAGS += -DDONGLE_ENABLE_ISOLATION
+# Print 802.1X packets
+ DHDCFLAGS += -DDHD_8021X_DUMP
+# Print DHCP packets
+ DHDCFLAGS += -DDHD_DHCP_DUMP
+endif
+
+ifneq ($(CONFIG_BCM4339),)
+ DHDCFLAGS += -DBCM4339_CHIP -DHW_OOB
+
+ # tput enhancement
+ DHDCFLAGS += -DCUSTOM_GLOM_SETTING=8 -DCUSTOM_RXCHAIN=1
+ DHDCFLAGS += -DUSE_DYNAMIC_F2_BLKSIZE -DDYNAMIC_F2_BLKSIZE_FOR_NONLEGACY=128
+ DHDCFLAGS += -DBCMSDIOH_TXGLOM -DCUSTOM_TXGLOM=1 -DBCMSDIOH_TXGLOM_HIGHSPEED
+ DHDCFLAGS += -DDHDTCPACK_SUPPRESS
+ DHDCFLAGS += -DUSE_WL_TXBF
+ DHDCFLAGS += -DUSE_WL_FRAMEBURST
+ DHDCFLAGS += -DRXFRAME_THREAD
+ DHDCFLAGS += -DCUSTOM_AMPDU_BA_WSIZE=64
+ DHDCFLAGS += -DCUSTOM_DPC_CPUCORE=0
+ DHDCFLAGS += -DPROP_TXSTATUS_VSDB
+ DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32
+
+ # New Features
+ DHDCFLAGS += -DWL11U
+ DHDCFLAGS += -DDHD_ENABLE_LPC
+ DHDCFLAGS += -DCUSTOM_PSPRETEND_THR=30
+endif
+
+
+#EXTRA_LDFLAGS += --strip-debug
+
+ifeq ($(DRIVER_TYPE),y)
+ DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD
+ DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC
+endif
+
+ifeq ($(DRIVERX_TYPE),y)
+ DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD
+ DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC
+endif
+
+ifneq ($(DRIVERX_TYPE),)
+ DHDCFLAGS += -DBCMDHDX
+endif
+
+DHDOFILES := dhd_pno.o dhd_common.o dhd_ip.o dhd_custom_gpio.o \
+ dhd_linux.o dhd_linux_sched.o dhd_cfg80211.o dhd_linux_wq.o aiutils.o bcmevent.o \
+ bcmutils.o bcmwifi_channels.o hndpmu.o linux_osl.o sbutils.o siutils.o \
+ wl_android.o wl_roam.o wl_cfg80211.o wl_cfgp2p.o wl_cfg_btcoex.o wldev_common.o wl_linux_mon.o \
+ dhd_linux_platdev.o dhd_pno.o dhd_linux_wq.o hnd_pktq.o hnd_pktpool.o
+
+# RTT support
+#DHDCFLAGS += -DRTT_SUPPORT -DRTT_DEBUG
+#DHDOFILES += dhd_rtt.o bcmxtlv.o bcm_app_utils.o
+
+# Vendor Extension support
+#DHDCFLAGS += -DWL_VENDOR_EXT_SUPPORT
+#DHDOFILES += wl_cfgvendor.o
+
+# Bandsteer support
+#DHDCFLAGS += -DDHD_BANDSTEER
+#DHDOFILES += dhd_bandsteer.o
+
+# DRIVER start/stop support
+#DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD -DKEEP_WIFION_OPTION
+
+ifneq ($(CONFIG_BCMDHD_PCIE),)
+ DHDOFILES += dhd_pcie.o dhd_pcie_linux.o dhd_msgbuf.o dhd_flowring.o
+ DHDOFILES += pcie_core.o
+endif
+
+
+ifneq ($(CONFIG_BCMDHD_SDIO),)
+ DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o
+ DHDOFILES += dhd_cdc.o dhd_wlfc.o dhd_sdio.o
+endif
+
+
+ifneq ($(CONFIG_BCMDHD_1363),)
+ bcmdhd-objs := $(DHDOFILES)
+ obj-$(DRIVER_TYPE) += bcmdhd.o
+endif
+
+ifneq ($(CONFIG_BCMDHDX),)
+ bcmdhdx-objs := $(DHDOFILES)
+ obj-$(DRIVERX_TYPE) += bcmdhdx.o
+endif
+
+EXTRA_CFLAGS += $(DHDCFLAGS) -DDHD_DEBUG
+EXTRA_CFLAGS += -DSRCBASE=\"$(src)\"
+EXTRA_CFLAGS += -I$(src)/include/ -I$(src)/
+KBUILD_CFLAGS += -I$(LINUXDIR)/include -I$(shell pwd)
+
+all:
+ @echo "$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules"
+ @$(MAKE) --no-print-directory -C $(KDIR) SUBDIRS=$(CURDIR) modules
+
+clean:
+ rm -rf *.o *.ko *.mod.c *~ .*.cmd *.o.cmd .*.o.cmd \
+ Module.symvers modules.order .tmp_versions modules.builtin
+
+install:
+ @$(MAKE) --no-print-directory -C $(KDIR) \
+ SUBDIRS=$(CURDIR) modules_install
diff --git a/drivers/net/wireless/bcmdhd_1363/aiutils.c b/drivers/net/wireless/bcmdhd_1363/aiutils.c
new file mode 100644
index 000000000000..3440dbc71929
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/aiutils.c
@@ -0,0 +1,1284 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: aiutils.c 607900 2015-12-22 13:38:53Z $
+ */
+#include <bcm_cfg.h>
+#include <typedefs.h>
+#include <bcmdefs.h>
+#include <osl.h>
+#include <bcmutils.h>
+#include <siutils.h>
+#include <hndsoc.h>
+#include <sbchipc.h>
+#include <pcicfg.h>
+
+#include "siutils_priv.h"
+
+#define BCM47162_DMP() (0)
+#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;
+
+ 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;
+}
+
+static void
+ai_hwfixup(si_info_t *sii)
+{
+}
+
+
+/* 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;
+
+ 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));
+
+ SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n",
+ regs, erombase, eromptr, 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));
+ ai_hwfixup(sii);
+ 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, eromptr - 1, nmw, nsw, nmp, nsp));
+#else
+ BCM_REFERENCE(crev);
+#endif
+
+ if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0))
+ 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;
+ }
+
+ /* 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;
+ }
+
+
+ /* Don't record bridges */
+ if (br)
+ continue;
+
+ /* Done with core */
+ sii->numcores++;
+ }
+
+ SI_ERROR(("Reached end of erom without finding END"));
+
+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 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;
+ 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];
+
+ /*
+ * 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:
+ /* 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;
+}
+
+void *
+ai_setcoreidx(si_t *sih, uint coreidx)
+{
+ return _ai_setcoreidx(sih, coreidx, 0);
+}
+
+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)
+{
+ 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 (BCM47162_DMP()) {
+ SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__));
+ return sii->curidx;
+ }
+ 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 (BCM47162_DMP()) {
+ SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__));
+ return sii->curidx;
+ }
+ 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)
+{
+}
+
+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;
+ 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 = (uint32 *)((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 = (uint32 *)((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 = (uint32 *)((char *)sii->curmap +
+ PCI_16KB0_PCIREGS_OFFSET + regoff);
+ else
+ r = (uint32 *)((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 = (uint32*) ((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.
+ */
+uint32 *
+ai_corereg_addr(si_t *sih, uint coreidx, uint regoff)
+{
+ 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 = (uint32 *)((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 = (uint32 *)((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 = (uint32 *)((char *)sii->curmap +
+ PCI_16KB0_PCIREGS_OFFSET + regoff);
+ else
+ r = (uint32 *)((char *)sii->curmap +
+ ((regoff >= SBCONFIGOFF) ?
+ PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) +
+ regoff);
+ }
+ }
+
+ if (!fast) {
+ ASSERT(sii->curidx == coreidx);
+ r = (uint32*) ((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;
+#ifdef CUSTOMER_HW4_DEBUG
+ printf("%s: bits: 0x%x, resetbits: 0x%x\n", __FUNCTION__, bits, resetbits);
+#endif
+
+ ASSERT(GOODREGS(sii->curwrap));
+ ai = sii->curwrap;
+
+ /* ensure there are no pending backplane operations */
+ SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300);
+#ifdef CUSTOMER_HW4_DEBUG
+ printf("%s: resetstatus: %p dummy: %x\n", __FUNCTION__, &ai->resetstatus, dummy);
+#endif
+
+
+ /* put core into reset state */
+#ifdef CUSTOMER_HW4_DEBUG
+ printf("%s: resetctrl: %p\n", __FUNCTION__, &ai->resetctrl);
+#endif
+ 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);
+#ifdef CUSTOMER_HW4_DEBUG
+ printf("%s: ioctrl: %p dummy: 0x%x\n", __FUNCTION__, &ai->ioctrl, dummy);
+#endif
+ 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);
+#ifdef CUSTOMER_HW4_DEBUG
+ printf("%s: loop_counter: %d resetstatus: %p resetctrl: %p\n",
+ __FUNCTION__, loop_counter, &ai->resetstatus, &ai->resetctrl);
+#endif
+
+ /* 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);
+#ifdef CUSTOMER_HW4_DEBUG
+ printf("%s: ioctl: %p dummy: 0x%x\n", __FUNCTION__, &ai->ioctrl, dummy);
+#endif
+ 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 (BCM47162_DMP()) {
+ SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0",
+ __FUNCTION__));
+ return;
+ }
+ 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 (BCM47162_DMP()) {
+ SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0",
+ __FUNCTION__));
+ return 0;
+ }
+ 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 (BCM47162_DMP()) {
+ SI_ERROR(("%s: Accessing MIPS DMP register (iostatus) on 47162a0",
+ __FUNCTION__));
+ return 0;
+ }
+ 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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ osl_t *osh;
+ aidmp_t *ai;
+ uint i;
+
+ osh = sii->osh;
+
+ for (i = 0; i < sii->numcores; i++) {
+ si_setcoreidx(&sii->pub, i);
+ ai = sii->curwrap;
+
+ bcm_bprintf(b, "core 0x%x: \n", cores_info->coreid[i]);
+ if (BCM47162_DMP()) {
+ bcm_bprintf(b, "Skipping mips74k in 47162a0\n");
+ continue;
+ }
+ if (BCM5357_DMP()) {
+ bcm_bprintf(b, "Skipping usb20h in 5357\n");
+ continue;
+ }
+ if (BCM4707_DMP()) {
+ bcm_bprintf(b, "Skipping chipcommonb in 4707\n");
+ continue;
+ }
+
+ if (PMU_DMP()) {
+ bcm_bprintf(b, "Skipping pmu core\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",
+ 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));
+ }
+}
+#endif
+
+
+void
+ai_enable_backplane_timeouts(si_t *sih)
+{
+#ifdef AXI_TIMEOUTS
+ si_info_t *sii = SI_INFO(sih);
+ aidmp_t *ai;
+ int i;
+
+ for (i = 0; i < sii->num_br; ++i) {
+ ai = (aidmp_t *) sii->br_wrapba[i];
+ W_REG(sii->osh, &ai->errlogctrl, (1 << AIELC_TO_ENAB_SHIFT) |
+ ((AXI_TO_VAL << AIELC_TO_EXP_SHIFT) & AIELC_TO_EXP_MASK));
+ }
+#endif /* AXI_TIMEOUTS */
+}
+
+void
+ai_clear_backplane_to(si_t *sih)
+{
+#ifdef AXI_TIMEOUTS
+ si_info_t *sii = SI_INFO(sih);
+ aidmp_t *ai;
+ int i;
+ uint32 errlogstatus;
+
+ for (i = 0; i < sii->num_br; ++i) {
+ ai = (aidmp_t *) sii->br_wrapba[i];
+ /* check for backplane timeout & clear backplane hang */
+ errlogstatus = R_REG(sii->osh, &ai->errlogstatus);
+
+ if ((errlogstatus & AIELS_TIMEOUT_MASK) != 0) {
+ /* set ErrDone to clear the condition */
+ W_REG(sii->osh, &ai->errlogdone, AIELD_ERRDONE_MASK);
+
+ /* SPINWAIT on errlogstatus timeout status bits */
+ while (R_REG(sii->osh, &ai->errlogstatus) & AIELS_TIMEOUT_MASK)
+ ;
+
+ /* only reset APB Bridge on timeout (not slave error, or dec error) */
+ switch (errlogstatus & AIELS_TIMEOUT_MASK) {
+ case 0x1:
+ printf("AXI slave error");
+ break;
+ case 0x2:
+ /* 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);
+ printf("AXI timeout");
+ break;
+ case 0x3:
+ printf("AXI decode error");
+ break;
+ default:
+ ; /* should be impossible */
+ }
+ printf("; APB Bridge %d\n", i);
+ printf("\t errlog: lo 0x%08x, hi 0x%08x, id 0x%08x, flags 0x%08x",
+ R_REG(sii->osh, &ai->errlogaddrlo),
+ R_REG(sii->osh, &ai->errlogaddrhi),
+ R_REG(sii->osh, &ai->errlogid),
+ R_REG(sii->osh, &ai->errlogflags));
+ printf(", status 0x%08x\n", errlogstatus);
+ }
+ }
+#endif /* AXI_TIMEOUTS */
+}
diff --git a/drivers/net/wireless/bcmdhd_1363/bcm_app_utils.c b/drivers/net/wireless/bcmdhd_1363/bcm_app_utils.c
new file mode 100644
index 000000000000..b0b0fbeb2d31
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/bcm_app_utils.c
@@ -0,0 +1,1012 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcm_app_utils.c 547371 2015-04-08 12:51:39Z $
+ */
+
+#include <typedefs.h>
+
+#ifdef BCMDRIVER
+#include <osl.h>
+#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
+#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
+#else /* BCMDRIVER */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifndef ASSERT
+#define ASSERT(exp)
+#endif
+#endif /* BCMDRIVER */
+#include <bcmwifi_channels.h>
+
+#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
+#include <bcmstdlib.h> /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */
+#endif
+
+#include <bcmutils.h>
+#include <wlioctl.h>
+#include <wlioctl_utils.h>
+
+#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_IS20(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)
+};
+
+/* 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_T_VERSION) {
+ /* 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) {
+ printf("wl_cntbuf_to_xtlv_format malloc fail!\n");
+ 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");
+ res = BCME_ERROR;
+ }
+
+ /* 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, WL_CNTBUF_MAX_SIZE);
+
+ 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/drivers/net/wireless/bcmdhd_1363/bcmevent.c b/drivers/net/wireless/bcmdhd_1363/bcmevent.c
new file mode 100644
index 000000000000..7b51a02de823
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/bcmevent.c
@@ -0,0 +1,356 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmevent.c 647135 2016-07-04 06:04:52Z $
+ */
+
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <proto/ethernet.h>
+#include <proto/bcmeth.h>
+#include <proto/bcmevent.h>
+#include <proto/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),
+#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_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_SWC),
+#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
+ 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_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 len;
+ uint16 subtype;
+ uint16 usr_subtype;
+ bcm_event_t *bcm_event;
+ uint8 *pktend;
+ int err = BCME_OK;
+
+ 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 */
+ len = ntoh16_ua((void *)&bcm_event->bcm_hdr.length);
+
+ /* 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:
+ if (pktlen < sizeof(bcm_event_t)) {
+ err = BCME_BADLEN;
+ goto done;
+ }
+
+ len = (uint16)sizeof(bcm_event_t) +
+ (uint16)ntoh32_ua((void *)&bcm_event->event.datalen);
+ if ((uint8 *)pktdata + len > pktend) {
+ 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(HEALTH_CHECK) || defined(DNGL_EVENT_SUPPORT)
+ if (pktlen < sizeof(bcm_dngl_event_t)) {
+ err = BCME_BADLEN;
+ goto done;
+ }
+
+ len = sizeof(bcm_dngl_event_t) +
+ ntoh16_ua((void *)&((bcm_dngl_event_t *)pktdata)->dngl_event.datalen);
+ if ((uint8 *)pktdata + len > pktend) {
+ 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 /* HEALTH_CHECK || DNGL_EVENT_SUPPORT */
+
+ default:
+ err = BCME_NOTFOUND;
+ goto done;
+ }
+
+done:
+ return err;
+}
diff --git a/drivers/net/wireless/bcmdhd_1363/bcmsdh.c b/drivers/net/wireless/bcmdhd_1363/bcmsdh.c
new file mode 100644
index 000000000000..9e477b288696
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/bcmsdh.c
@@ -0,0 +1,708 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmsdh.c 514727 2014-11-12 03:02:48Z $
+ */
+
+/**
+ * @file bcmsdh.c
+ */
+
+/* ****************** BCMSDH Interface Functions *************************** */
+
+#include <typedefs.h>
+#include <bcmdevs.h>
+#include <bcmendian.h>
+#include <bcmutils.h>
+#include <hndsoc.h>
+#include <siutils.h>
+#include <osl.h>
+
+#include <bcmsdh.h> /* BRCM API for SDIO clients (such as wl, dhd) */
+#include <bcmsdbus.h> /* common SDIO/controller interface */
+#include <sbsdio.h> /* SDIO device core hardware definitions. */
+#include <sdio.h> /* SDIO Device and Protocol Specs */
+
+#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(OOB_INTR_ONLY) && defined(HW_OOB)
+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
+
+/* 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;
+
+ /* 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;
+ 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;
+ 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;
+}
+
+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));
+}
+
+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
+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, uint32 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, ", __FUNCTION__, addr));
+
+ if (!bcmsdh)
+ bcmsdh = l_bcmsdh;
+
+ ASSERT(bcmsdh->init_success);
+
+ if (bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))
+ 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%04x size %d\n", __FUNCTION__, addr, size));
+ return 0xFFFFFFFF;
+}
+
+uint32
+bcmsdh_reg_write(void *sdh, uint32 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__, addr, size*8, data));
+
+ if (!bcmsdh)
+ bcmsdh = l_bcmsdh;
+
+ ASSERT(bcmsdh->init_success);
+
+ if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)))
+ 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, 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);
+}
+
+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);
+}
diff --git a/drivers/net/wireless/bcmdhd_1363/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd_1363/bcmsdh_linux.c
new file mode 100644
index 000000000000..9addd327ed88
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/bcmsdh_linux.c
@@ -0,0 +1,473 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmsdh_linux.c 662741 2016-11-08 09:37:17Z $
+ */
+
+/**
+ * @file bcmsdh_linux.c
+ */
+
+#define __UNDEF_NO_VERSION__
+
+#include <typedefs.h>
+#include <linuxver.h>
+#include <linux/pci.h>
+#include <linux/completion.h>
+
+#include <osl.h>
+#include <pcicfg.h>
+#include <bcmdefs.h>
+#include <bcmdevs.h>
+#include <linux/irq.h>
+extern void dhdsdio_isr(void * args);
+#include <bcmutils.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#if defined(CONFIG_ARCH_ODIN)
+#include <linux/platform_data/gpio-odin.h>
+#endif /* defined(CONFIG_ARCH_ODIN) */
+#include <dhd_linux.h>
+
+/* 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_MSG(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;
+#ifdef OOB_PARAM
+ wifi_adapter_info_t *adapter = (wifi_adapter_info_t *)adapter_info;
+#endif /* OOB_PARAM */
+
+ bcmsdh = bcmsdh_attach(osh, sdioh, &regs);
+ if (bcmsdh == NULL) {
+ SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
+ goto err;
+ }
+ bcmsdh_osinfo = MALLOC(osh, sizeof(bcmsdh_os_info_t));
+ if (bcmsdh_osinfo == NULL) {
+ SDLX_MSG(("%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)
+ OOB_PARAM_IF(!(adapter->oob_disable)) {
+ 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_MSG(("%s: Host OOB irq is not defined\n", __FUNCTION__));
+ goto err;
+ }
+ }
+#endif /* defined(OOB_INTR_ONLY) */
+
+ /* 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_MSG(("%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;
+}
+
+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_MSG(("%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;
+
+ SDLX_MSG(("%s: Enter\n", __FUNCTION__));
+ if (bcmsdh_osinfo->oob_irq_registered) {
+ SDLX_MSG(("%s: irq is already registered\n", __FUNCTION__));
+ return -EBUSY;
+ }
+ SDLX_MSG(("%s OOB irq=%d flags=%X \n", __FUNCTION__,
+ (int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags));
+ bcmsdh_osinfo->oob_irq_handler = oob_irq_handler;
+ bcmsdh_osinfo->oob_irq_handler_context = oob_irq_handler_context;
+#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_MSG(("%s: request_irq failed with %d\n", __FUNCTION__, err));
+ return err;
+ }
+
+ err = enable_irq_wake(bcmsdh_osinfo->oob_irq_num);
+ if (!err)
+ bcmsdh_osinfo->oob_irq_wake_enabled = TRUE;
+ bcmsdh_osinfo->oob_irq_enabled = TRUE;
+ bcmsdh_osinfo->oob_irq_registered = TRUE;
+ return err;
+}
+
+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);
+
+#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
+
+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/drivers/net/wireless/bcmdhd_1363/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd_1363/bcmsdh_sdmmc.c
new file mode 100644
index 000000000000..9181fc596689
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/bcmsdh_sdmmc.c
@@ -0,0 +1,1509 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary,Open:>>
+ *
+ * $Id: bcmsdh_sdmmc.c 662741 2016-11-08 09:37:17Z $
+ */
+#include <typedefs.h>
+
+#include <bcmdevs.h>
+#include <bcmendian.h>
+#include <bcmutils.h>
+#include <osl.h>
+#include <sdio.h> /* SDIO Device and Protocol Specs */
+#include <sdioh.h> /* Standard SDIO Host Controller Specification */
+#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
+#include <sdiovar.h> /* ioctl/iovars */
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+
+#include <dngl_stats.h>
+#include <dhd.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
+#include <linux/suspend.h>
+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) || defined(OOB_PARAM)
+static void IRQHandler(struct sdio_func *func);
+static void IRQHandlerF2(struct sdio_func *func);
+#endif /* !defined(OOB_INTR_ONLY) || defined(OOB_PARAM) */
+static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr);
+
+#ifdef OOB_PARAM
+extern int sdioh_get_oob_disable(sdioh_info_t *sd);
+#endif /* OOB_PARAM */
+
+#if defined(CUSTOMER_IMX) && defined(NO_SDIO_RESET)
+static int sdio_reset_comm(struct mmc_card *card)
+{
+ return 0;
+}
+#else
+extern int sdio_reset_comm(struct mmc_card *card);
+#endif /* defined(CUSTOMER_IMX) && defined(NO_SDIO_RESET) */
+
+#define DEFAULT_SDIO_F2_BLKSIZE 512
+#ifndef CUSTOM_SDIO_F2_BLKSIZE
+#define CUSTOM_SDIO_F2_BLKSIZE DEFAULT_SDIO_F2_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_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);
+
+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", 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;
+ sd->func[1] = func->card->sdio_func[0];
+ sd->func[2] = func->card->sdio_func[1];
+ 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] = 64;
+ err_ret = sdio_set_block_size(sd->func[1], 64);
+ 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;
+ 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;
+ }
+
+ 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);
+ 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);
+ /* 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) || defined(OOB_PARAM)
+ OOB_PARAM_IF(dhd_get_oob_disable(argh)) {
+ 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]);
+ }
+ } OOB_PARAM_ELSE()
+#endif /* !defined(OOB_INTR_ONLY) || defined(OOB_PARAM) */
+#if defined(OOB_INTR_ONLY)
+ {
+#if defined(HW_OOB)
+ sdioh_enable_func_intr(sd);
+#endif /* defined(HW_OOB) */
+ }
+#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) || defined(OOB_PARAM)
+ OOB_PARAM_IF(sd->intr_handler_valid) {
+ 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;
+ } OOB_PARAM_ELSE()
+#endif /* !defined(OOB_INTR_ONLY) || defined(OOB_PARAM) */
+#if defined(OOB_INTR_ONLY)
+ {
+#if defined(HW_OOB)
+ sdioh_disable_func_intr(sd);
+#endif /* defined(HW_OOB) */
+ }
+#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, IOVT_UINT32, 0 },
+ {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 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 },
+ {"sd_rxchain", IOV_RXCHAIN, 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;
+
+ 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):
+ sd_divisor = int_val;
+ 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;
+
+ case IOV_GVAL(IOV_HOSTREG):
+ {
+ sdreg_t *sd_ptr = (sdreg_t *)params;
+
+ if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
+ sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
+ bcmerror = BCME_BADARG;
+ break;
+ }
+
+ sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__,
+ (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
+ sd_ptr->offset));
+ if (sd_ptr->offset & 1)
+ int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */
+ else if (sd_ptr->offset & 2)
+ int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */
+ else
+ int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */
+
+ bcopy(&int_val, arg, sizeof(int_val));
+ break;
+ }
+
+ case IOV_SVAL(IOV_HOSTREG):
+ {
+ sdreg_t *sd_ptr = (sdreg_t *)params;
+
+ if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
+ sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
+ bcmerror = BCME_BADARG;
+ break;
+ }
+
+ sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value,
+ (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
+ sd_ptr->offset));
+ break;
+ }
+
+ case IOV_GVAL(IOV_DEVREG):
+ {
+ sdreg_t *sd_ptr = (sdreg_t *)params;
+ uint8 data = 0;
+
+ 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;
+ }
+
+ default:
+ bcmerror = BCME_UNSUPPORTED;
+ break;
+ }
+exit:
+
+ return bcmerror;
+}
+
+#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
+
+SDIOH_API_RC
+sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
+{
+ SDIOH_API_RC status;
+ uint8 data;
+
+ if (enable)
+ data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI;
+ 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, &regdata)) != 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_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
+
+ 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 (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",
+ 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",
+ err_ret));
+ }
+ }
+ sdio_release_host(sd->func[2]);
+ }
+ }
+#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 */
+ 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));
+ }
+ }
+
+ return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
+}
+
+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;
+#if defined(MMC_SDIO_ABORT)
+ int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT;
+#endif
+
+ 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_ret);
+ sdio_release_host(sd->func[0]);
+ }
+ if (!err_ret)
+ break;
+ }
+ if (err_ret)
+#endif /* MMC_SDIO_ABORT */
+ {
+ sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x",
+ rw ? "Write" : "Read", err_ret));
+ }
+ }
+
+ return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
+}
+
+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;
+
+ 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);
+
+ 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;
+
+ 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\n", __FUNCTION__));
+ 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;
+ }
+ }
+
+ sd_trace(("%s: Exit\n", __FUNCTION__));
+ return SDIOH_API_RC_SUCCESS;
+}
+
+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;
+
+ sd_trace(("%s: Enter\n", __FUNCTION__));
+ ASSERT(buf);
+
+ /* 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__));
+ 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;
+
+ sd_trace(("%s: Enter\n", __FUNCTION__));
+ DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait);
+ DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
+
+ if (pkt) {
+ /* 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);
+
+ /* 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_err(("%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);
+
+ 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 {
+ sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize);
+ if (regsize == 2)
+ *data &= 0xffff;
+
+ sd_data(("%s: word read data=0x%08x\n",
+ __FUNCTION__, *data));
+ }
+
+ return SUCCESS;
+}
+
+#if !defined(OOB_INTR_ONLY) || defined(OOB_PARAM)
+/* 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) || defined(OOB_PARAM) */
+
+#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 ((ret = sdio_reset_comm(sd->func[0]->card))) {
+ sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
+ return ret;
+ }
+ else {
+ 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;
+ 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) || defined(OOB_PARAM)
+ OOB_PARAM_IF(sdioh_get_oob_disable(sd)) {
+ 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]);
+ } OOB_PARAM_ELSE()
+#endif /* !defined(OOB_INTR_ONLY) || defined(OOB_PARAM) */
+#if defined(OOB_INTR_ONLY)
+ {
+#if defined(HW_OOB)
+ sdioh_enable_func_intr(sd);
+#endif /* defined(HW_OOB) */
+ 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) || defined(OOB_PARAM)
+ OOB_PARAM_IF(sdioh_get_oob_disable(sd)) {
+ 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]);
+ } OOB_PARAM_ELSE()
+#endif /* !defined(OOB_INTR_ONLY) || defined(OOB_PARAM) */
+#if 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;
+}
diff --git a/drivers/net/wireless/bcmdhd_1363/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd_1363/bcmsdh_sdmmc_linux.c
new file mode 100644
index 000000000000..1e91196c205d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/bcmsdh_sdmmc_linux.c
@@ -0,0 +1,409 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary,Open:>>
+ *
+ * $Id: bcmsdh_sdmmc_linux.c 662764 2016-11-10 09:38:01Z $
+ */
+
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <sdio.h> /* SDIO Device and Protocol Specs */
+#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
+#include <sdiovar.h> /* to get msglevel bit values */
+
+#include <linux/sched.h> /* request_irq() */
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <dhd_linux.h>
+#include <bcmsdh_sdmmc.h>
+#include <dhd_dbg.h>
+
+#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");
+
+/* 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));
+ 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;
+ }
+
+ 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(("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));
+
+ /* 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) },
+ { /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids);
+
+#ifdef OOB_PARAM
+uint
+sdioh_get_oob_disable(sdioh_info_t *sd)
+{
+ int host_idx = sd->func[0]->card->host->index;
+ uint32 rca = sd->func[0]->card->rca;
+ wifi_adapter_info_t *adapter;
+
+ adapter = dhd_wifi_platform_get_adapter(SDIO_BUS, host_idx, rca);
+
+ return adapter->oob_disable;
+}
+#endif /* OOB_PARAM */
+
+#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;
+
+ sd_err(("%s Enter\n", __FUNCTION__));
+ if (func->num != 2)
+ return 0;
+
+ dhd_mmc_suspend = TRUE;
+ sdioh = sdio_get_drvdata(func);
+ err = bcmsdh_suspend(sdioh->bcmsdh);
+ if (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;
+ }
+#if defined(OOB_INTR_ONLY)
+ OOB_PARAM_IF(!(sdioh_get_oob_disable(sdioh))) {
+ bcmsdh_oob_intr_set(sdioh->bcmsdh, FALSE);
+ }
+#endif
+ smp_mb();
+
+ return 0;
+}
+
+static int bcmsdh_sdmmc_resume(struct device *pdev)
+{
+ struct sdio_func *func = dev_to_sdio_func(pdev);
+ sdioh_info_t *sdioh;
+
+
+ sd_err(("%s Enter\n", __FUNCTION__));
+ if (func->num != 2)
+ return 0;
+
+ dhd_mmc_suspend = FALSE;
+ sdioh = sdio_get_drvdata(func);
+ bcmsdh_resume(sdioh->bcmsdh);
+
+ smp_mb();
+ 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/drivers/net/wireless/bcmdhd_1363/bcmsdspi_linux.c b/drivers/net/wireless/bcmdhd_1363/bcmsdspi_linux.c
new file mode 100644
index 000000000000..b7091e5985f9
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmsdspi_linux.c 514727 2014-11-12 03:02:48Z $
+ */
+
+#include <typedefs.h>
+#include <bcmutils.h>
+
+#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
+#include <sdiovar.h> /* to get msglevel bit values */
+
+#include <pcicfg.h>
+#include <sdio.h> /* SDIO Device and Protocol Specs */
+#include <linux/sched.h> /* request_irq(), free_irq() */
+#include <bcmsdspi.h>
+#include <bcmspi.h>
+
+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/drivers/net/wireless/bcmdhd_1363/bcmspibrcm.c b/drivers/net/wireless/bcmdhd_1363/bcmspibrcm.c
new file mode 100644
index 000000000000..5b793b0568a2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/bcmspibrcm.c
@@ -0,0 +1,1823 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmspibrcm.c 662542 2016-10-28 03:26:10Z $
+ */
+
+#define HSMODE
+
+#include <typedefs.h>
+
+#include <bcmdevs.h>
+#include <bcmendian.h>
+#include <bcmutils.h>
+#include <osl.h>
+#include <hndsoc.h>
+#include <siutils.h>
+#include <sbchipc.h>
+#include <sbsdio.h> /* SDIO device core hardware definitions. */
+#include <spid.h>
+
+#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
+#include <sdiovar.h> /* ioctl/iovars */
+#include <sdio.h> /* SDIO Device and Protocol Specs */
+
+#include <pcicfg.h>
+
+
+#include <bcmspibrcm.h>
+#include <bcmspi.h>
+
+/* 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
+
+#define DWORDMODE_ON (sd->chip == BCM4329_CHIP_ID) && (sd->chiprev == 2) && (sd->dwordmode == TRUE)
+
+/* 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) || defined(OOB_PARAM)
+ OOB_PARAM_IF(dhd_get_oob_disable(argh)) {
+ sd->intr_handler = fn;
+ sd->intr_handler_arg = argh;
+ sd->intr_handler_valid = TRUE;
+ }
+#endif /* !defined(OOB_INTR_ONLY) || defined(OOB_PARAM) */
+ 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) || defined(OOB_PARAM)
+ OOB_PARAM_IF(sd->intr_handler_valid) {
+ sd->intr_handler_valid = FALSE;
+ sd->intr_handler = NULL;
+ sd->intr_handler_arg = NULL;
+ }
+#endif /* !defined(OOB_INTR_ONLY) || defined(OOB_PARAM) */
+ 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
+
+extern SDIOH_API_RC
+sdioh_query_device(sdioh_info_t *sd)
+{
+ /* Return a BRCM ID appropriate to the dongle class */
+ return (sd->num_funcs > 1) ? BCM4329_D11N_ID : BCM4318_D11G_ID;
+}
+
+/* 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, &reg)) !=
+ 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, &reg)) !=
+ 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, &regdata)) != 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, &regdata); \
+ 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, &regdata); \
+ 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, &regdata);
+ 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, &regdata)) !=
+ 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, &regdata)) != 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,
+ &regdata)) != 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, &regdata)) != 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, &regdata)) != 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, &regdata)) != 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, &regdata)) != 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));
+
+ if (DWORDMODE_ON) {
+ spilen = GFIELD(cmd_arg, SPI_LEN);
+ if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_0) ||
+ (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_1))
+ dstatus_idx = spilen * 3;
+
+ if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) &&
+ (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) {
+ spilen = spilen << 2;
+ dstatus_idx = (spilen % 16) ? (16 - (spilen % 16)) : 0;
+ /* convert len to mod16 size */
+ spilen = ROUNDUP(spilen, 16);
+ cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2));
+ }
+ }
+
+ /* 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 (DWORDMODE_ON) {
+ if (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) {
+ ptr = (uint16 *)&data[0];
+ templen = *ptr;
+ /* ASSERT(*ptr == ~*(ptr + 1)); */
+ templen = ROUNDUP(templen, 16);
+ *ptr = templen;
+ sd_trace(("actual tx len = %d\n", (uint16)(~*(ptr+1))));
+ }
+ }
+
+ 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]);
+ }
+ }
+
+ if ((DWORDMODE_ON) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) {
+ ptr = (uint16 *)&data[0];
+ templen = *ptr;
+ buslen = len = ~(*(ptr + 1));
+ buslen = ROUNDUP(buslen, 16);
+ /* populate actual len in hw-header */
+ if (templen == buslen)
+ *ptr = len;
+ }
+ }
+ }
+
+ /* Restore back the len field of the hw header */
+ if (DWORDMODE_ON) {
+ if ((GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2) &&
+ (GFIELD(cmd_arg, SPI_RW_FLAG) == 1)) {
+ ptr = (uint16 *)&data[0];
+ *ptr = (uint16)(~*(ptr+1));
+ }
+ }
+
+ 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/drivers/net/wireless/bcmdhd_1363/bcmutils.c b/drivers/net/wireless/bcmdhd_1363/bcmutils.c
new file mode 100644
index 000000000000..8f5a154375d6
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/bcmutils.c
@@ -0,0 +1,3581 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmutils.c 665091 2017-05-19 06:11:53Z $
+ */
+
+#include <bcm_cfg.h>
+#include <typedefs.h>
+#include <bcmdefs.h>
+#include <stdarg.h>
+#ifdef BCMDRIVER
+
+#include <osl.h>
+#include <bcmutils.h>
+
+#else /* !BCMDRIVER */
+
+#include <stdio.h>
+#include <string.h>
+#include <bcmutils.h>
+
+#if defined(BCMEXTSUP)
+#include <bcm_osl.h>
+#endif
+
+#ifndef ASSERT
+#define ASSERT(exp)
+#endif
+
+#endif /* !BCMDRIVER */
+
+#include <bcmendian.h>
+#include <bcmdevs.h>
+#include <proto/ethernet.h>
+#include <proto/vlan.h>
+#include <proto/bcmip.h>
+#include <proto/802.1d.h>
+#include <proto/802.11.h>
+
+
+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)
+ 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_atoicrc(const char *p, int *crc)
+{
+ char *ep;
+
+ *crc = bcm_strtoul(p, &ep, 16);
+ p = ep;
+ if (!*p++)
+ return 0;
+ else
+ return -1;
+}
+
+char *Dates[] = { "Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ", "Jul ", "Aug ",
+ "Sep ", "Oct ", "Nov ", "Dec ", 0 };
+
+void
+wipedates(const char *cp, int size)
+{
+ char **dp;
+ char *np;
+ char *ep;
+ for (dp = Dates; *dp; dp++) {
+ np = (void *)bcmstrnstr(cp, size, *dp, strlen(*dp));
+ if (np) {
+ ep = np + strlen(np) + 1;
+ ep += strlen(np);
+ while (np < ep) {
+ *np++ = 0;
+ }
+ }
+ }
+}
+
+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;
+ }
+#ifdef DHD_LOSSLESS_ROAMING
+ } else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) {
+ priority = PRIO_8021D_NC;
+ rc = PKTPRIO_DSCP;
+#endif /* 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;
+}
+
+/* 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;
+
+ /* 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;
+}
+
+/*
+ * 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 = 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, 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",
+#ifdef BCMWAPI_WAI
+ "WAPI",
+#else
+ "UNDEF"
+#endif
+ "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, 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 */
+ 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(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 "<var>=<value>\n" lines read from a file and ending in a NUL.
+ * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\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;
+
+ dp = varbuf;
+
+ findNewline = FALSE;
+ column = 0;
+
+ for (n = 0; n < len; n++) {
+ if (varbuf[n] == '\r')
+ continue;
+ if (findNewline && varbuf[n] != '\n')
+ continue;
+ findNewline = FALSE;
+ if (varbuf[n] == '#') {
+ findNewline = TRUE;
+ continue;
+ }
+ if (varbuf[n] == '\n') {
+ if (column == 0)
+ continue;
+ *dp++ = 0;
+ column = 0;
+ continue;
+ }
+ *dp++ = varbuf[n];
+ column++;
+ }
+ buf_len = (unsigned int)(dp - varbuf);
+ if (buf_len % 4) {
+ pad = 4 - buf_len % 4;
+ if (pad && (buf_len + pad <= len)) {
+ buf_len += pad;
+ }
+ }
+
+ while (dp < varbuf + n)
+ *dp++ = 0;
+
+ return buf_len;
+}
+
+/* calculate a * b + c */
+void
+bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c)
+{
+#define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;}
+ uint32 r1, r0;
+ uint32 a1, a0, b1, b0, t, cc = 0;
+
+ a1 = a >> 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--) {
+ isbitset(u32arg, i) ? printf("1") : 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) --;
+}
+
+#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
diff --git a/drivers/net/wireless/bcmdhd_1363/bcmwifi_channels.c b/drivers/net/wireless/bcmdhd_1363/bcmwifi_channels.c
new file mode 100644
index 000000000000..efe7171a0d15
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/bcmwifi_channels.c
@@ -0,0 +1,1253 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmwifi_channels.c 591285 2015-10-07 11:56:29Z $
+ */
+
+#include <bcm_cfg.h>
+#include <typedefs.h>
+#include <bcmutils.h>
+
+#ifdef BCMDRIVER
+#include <osl.h>
+#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
+#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifndef ASSERT
+#define ASSERT(exp)
+#endif
+#endif /* BCMDRIVER */
+
+#include <bcmwifi_channels.h>
+
+#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
+#include <bcmstdlib.h> /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */
+#endif
+
+/* Definitions for D11AC capable Chanspec type */
+
+/* Chanspec ASCII representation with 802.11ac capability:
+ * [<band> 'g'] <channel> ['/'<bandwidth> [<ctl-sideband>]['/'<1st80channel>'-'<2nd80channel>]]
+ *
+ * <band>:
+ * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively.
+ * Default value is 2g if channel <= 14, otherwise 5g.
+ * <channel>:
+ * channel number of the 5MHz, 10MHz, 20MHz channel,
+ * or primary channel of 40MHz, 80MHz, 160MHz, or 80+80MHz channel.
+ * <bandwidth>:
+ * (optional) 5, 10, 20, 40, 80, 160, or 80+80. Default value is 20.
+ * <primary-sideband>:
+ * (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: <channel><ctl-sideband>
+ *
+ * <channel>:
+ * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz
+ * <ctl-sideband>:
+ * "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))
+
+
+/* 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 <band>g<chan>/<bw>
+ * 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 */
+char *
+wf_chspec_to_bw_str(chanspec_t chspec)
+{
+ return (char *)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 */
diff --git a/drivers/net/wireless/bcmdhd_1363/bcmwifi_channels.h b/drivers/net/wireless/bcmdhd_1363/bcmwifi_channels.h
new file mode 100644
index 000000000000..2ebb32f9a87e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/bcmwifi_channels.h
@@ -0,0 +1,631 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmwifi_channels.h 591285 2015-10-07 11:56:29Z $
+ */
+
+#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
+
+/* 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
+
+#define CHSPEC_IS2P5(chspec) 0
+#define CHSPEC_IS5(chspec) 0
+#define CHSPEC_IS10(chspec) 0
+#define CHSPEC_IS20(chspec) 1
+#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)
+#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 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
+#endif /* _bcmwifi_channels_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/bcmwifi_rates.h b/drivers/net/wireless/bcmdhd_1363/bcmwifi_rates.h
new file mode 100644
index 000000000000..487a4ba7da61
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmwifi_rates.h 591285 2015-10-07 11:56:29Z $
+ */
+
+#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/drivers/net/wireless/bcmdhd_1363/bcmxtlv.c b/drivers/net/wireless/bcmdhd_1363/bcmxtlv.c
new file mode 100644
index 000000000000..a9213b7319be
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmxtlv.c 527361 2015-01-17 01:48:34Z $
+ */
+
+#include <bcm_cfg.h>
+
+#include <typedefs.h>
+#include <bcmdefs.h>
+
+#include <stdarg.h>
+
+#ifdef BCMDRIVER
+#include <osl.h>
+#else /* !BCMDRIVER */
+ #include <stdlib.h> /* AS!!! */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#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 <bcmendian.h>
+#include <bcmutils.h>
+
+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 += 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 += 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 += 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 ((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/drivers/net/wireless/bcmdhd_1363/dhd.h b/drivers/net/wireless/bcmdhd_1363/dhd.h
new file mode 100644
index 000000000000..3fd7f26198f7
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd.h
@@ -0,0 +1,1786 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd.h 665091 2017-05-19 06:11:53Z $
+ */
+
+/****************
+ * Common types *
+ */
+
+#ifndef _dhd_h_
+#define _dhd_h_
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK)
+#include <linux/wakelock.h>
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */
+#include <dhd_buzzz.h>
+/* The kernel threading is sdio-specific */
+struct task_struct;
+struct sched_param;
+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 <wlioctl.h>
+#include <wlfc_proto.h>
+
+#if defined(BCMWDF)
+#include <wdf.h>
+#include <WdfMiniport.h>
+#endif /* (BCMWDF) */
+
+#ifdef DEBUG_DPC_THREAD_WATCHDOG
+#define MAX_RESCHED_CNT 600
+#endif /* DEBUG_DPC_THREAD_WATCHDOG */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) && LINUX_VERSION_CODE < \
+ KERNEL_VERSION(3, 18, 0) || defined(CONFIG_BCMDHD_VENDOR_EXT))
+#define WL_VENDOR_EXT_SUPPORT
+#endif /* 3.13.0 <= LINUX_KERNEL_VERSION < 3.18.0 || 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;
+
+/* 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 */
+};
+
+/*
+ * 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_IN_SUSPEND 0x40
+#define DHD_BUS_BUSY_IN_RESUME 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)
+
+/* Download Types */
+typedef enum download_type {
+ FW,
+ NVRAM,
+ CLM_BLOB,
+ CLMINFO
+} download_type_t;
+
+
+/* For supporting multiple interfaces */
+#define DHD_MAX_IFS 16
+#define DHD_DEL_IF -0xE
+#define DHD_BAD_IF -0xF
+
+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
+#define MAX_NVRAMBUF_SIZE (16 * 1024) /* max nvram buf size */
+#define MAX_CLM_BUF_SIZE (32 * 1024) /* max clm blob size */
+#define MAX_CLMINFO_BUF_SIZE (4 * 1024) /* max clminfo buf 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
+
+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
+};
+
+enum dhd_prealloc_index {
+ DHD_PREALLOC_PROT = 0,
+ DHD_PREALLOC_RXBUF,
+ DHD_PREALLOC_DATABUF,
+ DHD_PREALLOC_OSL_BUF,
+#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,
+ 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
+};
+
+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_SCAN_TIMEOUT,
+ DUMP_TYPE_SCAN_BUSY,
+ DUMP_TYPE_BY_SYSDUMP,
+ DUMP_TYPE_BY_LIVELOCK,
+ DUMP_TYPE_AP_LINKUP_FAILURE,
+ DUMP_TYPE_AP_ABNORMAL_ACCESS
+};
+
+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_PCIE_LINK_DOWN = 0x8005,
+ HANG_REASON_MSGBUF_LIVELOCK = 0x8006,
+ HANG_REASON_P2P_IFACE_DEL_FAILURE = 0x8007,
+ HANG_REASON_HT_AVAIL_ERROR = 0x8008,
+ HANG_REASON_PCIE_RC_LINK_UP_FAIL = 0x8009,
+ HANG_REASON_INVALID_EVENT_OR_DATA = 0x800a,
+ HANG_REASON_MAX = 0x800b
+};
+
+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
+#define MEMBLOCK 2048
+/**
+ * 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;
+
+#if defined(OOB_PARAM)
+#if !defined(OOB_INTR_ONLY)
+#error OOB_PARAM must be defined with OOB_INTR_ONLY!!
+#endif /* !defined(OOB_INTR_ONLY) */
+
+#define OOB_PARAM_IF(x) if (x)
+#define OOB_PARAM_ELSE() else
+
+#else /* defined(OOB_PARAM) */
+
+#define OOB_PARAM_IF(x)
+#define OOB_PARAM_ELSE()
+#endif /* defined(OOB_PARAM) */
+
+#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
+};
+#endif /* DHDTCPACK_SUPPRESS */
+
+
+/*
+ * 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));
+
+/* DMA'ing r/w indices for rings supported */
+#ifdef BCM_INDX_TCM /* FW gets r/w indices in TCM */
+#define DMA_INDX_ENAB(dma_indxsup) 0
+#elif defined BCM_INDX_DMA /* FW gets r/w indices from Host memory */
+#define DMA_INDX_ENAB(dma_indxsup) 1
+#else /* r/w indices in TCM or host memory based on FW/Host agreement */
+#define DMA_INDX_ENAB(dma_indxsup) dma_indxsup
+#endif /* BCM_INDX_TCM */
+
+#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 wraparound;
+ unsigned long max;
+ unsigned int remain;
+ char* present;
+ char* front;
+ char* buffer;
+};
+
+#define DHD_LOG_DUMP_BUFFER_SIZE (1024 * 1024)
+#define DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE 256
+
+extern void dhd_log_dump_print(const char *fmt, ...);
+extern char *dhd_log_dump_get_timestamp(void);
+#endif /* DHD_LOG_DUMP */
+#define DHD_COMMON_DUMP_PATH "/data/misc/wifi/log/"
+
+/* 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 */
+
+ /* to NDIS developer, the structure dhd_common is redundant,
+ * please do NOT merge it back from other branches !!!
+ */
+
+
+ /* Internal dhd items */
+ bool up; /* Driver up/down (to OS) */
+ 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 */
+
+ /* 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
+ u32 dhd_cflags;
+#endif /* CUSTOM_COUNTRY_CODE */
+ 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;
+ /*
+ * implement below functions in each platform if needed.
+ */
+ /* platform specific function whether to skip flow control */
+ bool (*skip_fc)(void *dhd);
+ /* 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;
+#endif
+ bool dongle_isolation;
+ 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 */
+ 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 */
+#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 */
+ 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;
+
+#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 */
+#ifdef DHD_L2_FILTER
+ unsigned long l2_filter_cnt; /* for L2_FILTER ARP table timeout */
+#endif /* DHD_L2_FILTER */
+ 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 */
+#endif /* PCIE_FULL_DONGLE */
+#ifdef CACHE_FW_IMAGES
+ char *cached_fw;
+ int cached_fw_length;
+ char *cached_nvram;
+ int cached_nvram_length;
+#endif
+#ifdef WLTDLS
+ uint32 tdls_mode;
+#endif
+#ifdef DHD_LOSSLESS_ROAMING
+ uint8 dequeue_prec_map;
+ uint8 prio_8021x;
+#endif
+ struct mutex wl_up_lock;
+ bool is_fw_download_done;
+#ifdef DHD_LOG_DUMP
+ struct dhd_log_dump_buf dld_buf;
+ unsigned int dld_enable;
+#endif /* DHD_LOG_DUMP */
+ bool max_dtim_enable; /* use MAX bcn_li_dtim value in suspend mode */
+#ifdef WL_CFG80211
+ /* dual-pcie chip support
+ * reference to private data of cfg80211 structure
+ */
+ void *cfg80211_priv;
+#endif /* WL_CFG80211 */
+
+#ifdef OOB_PARAM
+ uint oob_disable;
+#endif /* OOB_PARAM */
+} dhd_pub_t;
+
+#ifdef WL_CFG80211
+#define DHD_GET_CFG80211_PRIV(dhdp) ((dhdp)->cfg80211_priv)
+#endif /* WL_CFG80211 */
+
+#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 */
+/*
+ * 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 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(dhd_pub_t *pub);
+extern void dhd_txfl_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 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 BCMPCIE_OOB_HOST_WAKE
+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);
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+#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(pub) \
+ do { \
+ PRINT_CALL_INFO("call pm_wake_timeout enable"); \
+ dhd_txfl_wake_lock(pub); \
+ } 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 BCMPCIE_OOB_HOST_WAKE
+#define OOB_WAKE_LOCK_TIMEOUT 500
+#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 */
+#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 */
+#define DHD_PACKET_TIMEOUT_MS 500
+#define DHD_EVENT_TIMEOUT_MS 1500
+#define SCAN_WAKE_LOCK_TIMEOUT 10000
+
+/* 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
+} 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);
+
+
+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_STATE_DONE = 0x200
+} 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);
+#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);
+
+/* Receive frame for delivery to OS. Callee disposes of rxp. */
+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);
+
+/* 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);
+extern void dhd_dpc_enable(dhd_pub_t *dhdp);
+
+#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 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);
+#ifdef CUSTOM_FORCE_NODFS_FLAG
+extern int dhd_dev_set_nodfs(struct net_device *dev, uint nodfs);
+#endif /* CUSTOM_FORCE_NODFS_FLAG */
+/* 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);
+extern int dhd_wakeup_ioctl_event(dhd_pub_t *pub, dhd_ioctl_recieved_status_t reason);
+
+#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 void * dhd_os_open_image(char * filename);
+extern int dhd_os_file_size(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);
+#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);
+#ifdef 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 */
+
+#ifdef SUPPORT_AP_POWERSAVE
+extern int dhd_set_ap_powersave(dhd_pub_t *dhdp, int ifidx, int enable);
+#endif
+
+#if defined(DHD_FW_COREDUMP)
+void dhd_schedule_memdump(dhd_pub_t *dhdp, uint8 *buf, uint32 size);
+#endif /* DHD_FW_COREDUMP */
+
+#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
+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);
+#define DISCARD_IPV4_MCAST "102 1 6 IP4_H:16 0xf0 0xe0";
+#define DISCARD_IPV6_MCAST "103 1 6 IP6_H:24 0xff 0xff";
+#endif /* PKT_FILTER_SUPPORT */
+
+extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd);
+extern bool dhd_support_sta_mode(dhd_pub_t *dhd);
+
+extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size);
+
+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 ramstart;
+ uint32 rodata_start;
+ uint32 rodata_end;
+ char *rom_raw_sstr;
+ uint32 rom_ramstart;
+ uint32 rom_rodata_start;
+ uint32 rom_rodata_end;
+} dhd_event_log_t;
+#endif /* SHOW_LOGTRACE */
+
+#if defined(KEEP_ALIVE)
+extern int dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id, u8 *ip_pkt,
+ u16 ip_pkt_len, u8* src_mac_addr, u8* dst_mac_addr, u32 period_msec);
+extern int dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id);
+#endif /* defined(KEEP_ALIVE) */
+
+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, size_t 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 struct net_device* dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, char *name,
+ uint8 *mac, uint8 bssidx, bool need_rtnl_lock, 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, uint 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) */
+
+#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);
+
+/*
+ * 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 struct dhd_sta *dhd_findadd_sta(void *pub, int ifidx, void *ea);
+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 int dhd_os_d3ack_wait(dhd_pub_t * pub, uint * condition);
+extern int dhd_os_d3ack_wake(dhd_pub_t * pub);
+extern int dhd_os_busbusy_wait_negation(dhd_pub_t * pub, uint * condition);
+extern int dhd_os_busbusy_wake(dhd_pub_t * pub);
+
+extern bool dhd_is_concurrent_mode(dhd_pub_t *dhd);
+extern int dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set);
+typedef enum cust_gpio_modes {
+ WLAN_RESET_ON,
+ WLAN_RESET_OFF,
+ WLAN_POWER_ON,
+ WLAN_POWER_OFF
+} cust_gpio_modes_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;
+
+#ifdef DHD_PCIE_RUNTIMEPM
+extern uint dhd_runtimepm_ms;
+#endif /* DHD_PCIE_RUNTIMEPM */
+
+#if defined(DHD_DEBUG)
+/* Console output poll interval */
+extern uint dhd_console_ms;
+extern uint wl_msg_level;
+#endif /* defined(DHD_DEBUG) */
+
+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 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 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 */
+
+#define DEFAULT_DHD_WATCHDOG_INTERVAL_MS 10 /* msec */
+#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 */
+
+
+#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 */
+
+#define DEFAULT_BCN_TIMEOUT 8
+#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
+#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
+
+#ifdef SOFTAP
+extern char fw_path2[MOD_PARAM_PATHLEN];
+#endif
+
+/* Flag to indicate if we should download firmware on driver load */
+extern uint dhd_download_fw_on_driverload;
+extern int allow_delay_fwdl;
+
+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 */
+
+
+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
+void dhd_tdls_update_peer_info(struct net_device *dev, bool connect_disconnect, uint8 *addr);
+#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);
+/* 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);
+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 */
+
+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)
+
+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 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))
+
+extern void dhd_dump_to_kernelog(dhd_pub_t *dhdp);
+
+
+#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;
+ 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_save_fwdump(dhd_pub_t *dhd_pub, void * buffer, 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_clm_blob(dhd_pub_t *dhd, unsigned char *buf, uint32 len);
+
+int dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path);
+#ifdef DHD_USE_CLMINFO_PARSER
+int dhd_get_clminfo(dhd_pub_t *dhd, char *clm_path);
+#define NUM_OF_COUNTRYS 150
+#endif /* DHD_USE_CLMINFO_PARSER */
+
+#define dhd_is_device_removed(x) FALSE
+#define dhd_os_ind_firmware_stall(x)
+
+#ifdef DHD_FW_COREDUMP
+extern void dhd_get_memdump_info(dhd_pub_t *dhd);
+#endif /* DHD_FW_COREDUMP */
+#ifdef BCMASSERT_LOG
+extern void dhd_get_assert_info(dhd_pub_t *dhd);
+#endif /* BCMASSERT_LOG */
+
+#if defined(DHD_LB_STATS)
+#include <bcmutils.h>
+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)
+/* 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_NOOP do { /* noop */ } while (0)
+#define DHD_LB_STATS_INIT(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_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 */
+
+extern void dhd_memdump_work_schedule(dhd_pub_t *dhdp, unsigned long msecs);
+
+extern bool dhd_query_bus_erros(dhd_pub_t *dhdp);
+
+/*
+ * 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 int dhd_prot_debug_info_print(dhd_pub_t *dhd);
+
+#ifdef ENABLE_TEMP_THROTTLING
+#ifndef TEMP_THROTTLE_CONTROL_BIT
+#define TEMP_THROTTLE_CONTROL_BIT 0xd
+#endif
+#endif /* ENABLE_TEMP_THROTTLING */
+
+#ifdef DHD_PKTID_AUDIT_ENABLED
+void dhd_pktid_audit_fail_cb(dhd_pub_t *dhdp);
+#endif /* DHD_PKTID_AUDIT_ENABLED */
+
+int dhd_android_ap_isolate_getval(struct net_device *dev);
+void dhd_android_ap_isolate_setval(struct net_device *dev, int val);
+
+#ifdef OOB_PARAM
+extern uint dhd_get_oob_disable(struct dhd_bus* bus);
+#endif /* OOB_PARAM */
+
+#endif /* _dhd_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_bandsteer.c b/drivers/net/wireless/bcmdhd_1363/dhd_bandsteer.c
new file mode 100644
index 000000000000..620872a282c3
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_bandsteer.c
@@ -0,0 +1,595 @@
+/*
+ * Band Steering logic
+ *
+ * Feature by which dualband capable PEERs will be
+ * forced move on 5GHz 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.
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $ Copyright Cypress Semiconductor $
+ *
+ * $Id: dhd_bandsteer.c 664149 2017-03-07 13:29:02Z $
+ */
+
+#include <typedefs.h>
+#include <linuxver.h>
+#include <osl.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <bcmutils.h>
+#include <net/cfg80211.h>
+#include <net/rtnetlink.h>
+#include <wl_cfg80211.h>
+#include <wl_android.h>
+#include <wldev_common.h>
+#include <dhd_linux_wq.h>
+#include <dhd_cfg80211.h>
+#include <dhd_bandsteer.h>
+#include <dhd_dbg.h>
+
+/* defines */
+/* BANDSTEER STATE MACHINE STATES */
+#define DHD_BANDSTEER_START 0x0001
+#define DHD_BANDSTEER_WNM_FRAME_SEND 0x0002
+#define DHD_BANDSTEER_WNM_FRAME_RETRY 0x0004
+#define DHD_BANDSTEER_WNM_FRAME_SENT 0x0008
+#define DHD_BANDSTEER_TRIAL_DONE 0x0080
+
+#define DHD_BANDSTEER_ON_PROCESS_MASK (DHD_BANDSTEER_START | DHD_BANDSTEER_WNM_FRAME_SEND \
+ | DHD_BANDSTEER_WNM_FRAME_RETRY | DHD_BANDSTEER_TRIAL_DONE)
+
+#define DHD_BANDSTEER_WNM_FRAME_MAXRETRY 3
+#define DHD_BANDSTEER_WNM_FRAME_DELAY 1000
+#define MAX_NUM_OF_ASSOCLIST 64
+#define DHD_BANDSTEER_MAXIFACES 2
+
+#define CHANNEL_IS_5G(channel) (((channel >= 36) && (channel <= 165)) ? \
+true : false)
+
+/* ********************** Function declaration *********************** */
+static s32
+dhd_bandsteer_addmac_to_monitorlist(dhd_bandsteer_context_t *dhd_bandsteer_cntx, uint8 *mac_addr);
+static s32
+dhd_bandsteer_remove_mac_from_list(dhd_bandsteer_mac_entry_t *dhd_bandsteer_mac, int all);
+static dhd_bandsteer_mac_entry_t*
+dhd_bandsteer_look_for_match(dhd_bandsteer_context_t *dhd_bandsteer_cntx, uint8 *mac_addr);
+static s32
+dhd_bandsteer_tx_wnm_actframe(dhd_bandsteer_mac_entry_t *dhd_bandsteer_mac);
+static void
+dhd_bandsteer_add_to_black_list(dhd_bandsteer_mac_entry_t *dhd_bandsteer_mac);
+
+extern int
+wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist);
+
+/* ********************** Function declartion ends ****************** */
+
+static void
+dhd_bandsteer_add_timer(dhd_bandsteer_mac_entry_t *dhd_bandsteer_mac, unsigned long expires)
+{
+ dhd_bandsteer_mac->dhd_bandsteer_timer.expires = jiffies + msecs_to_jiffies(expires);
+ add_timer(&dhd_bandsteer_mac->dhd_bandsteer_timer);
+}
+
+static void
+dhd_bandsteer_delete_timer(dhd_bandsteer_mac_entry_t *dhd_bandsteer_mac)
+{
+ del_timer(&dhd_bandsteer_mac->dhd_bandsteer_timer);
+}
+
+/*
+ * Idea used to call same callback everytime you conifigure timer
+ * based on the status of the mac entry next step will be taken
+ */
+static void
+dhd_bandsteer_state_machine(ulong arg)
+{
+ dhd_bandsteer_mac_entry_t *dhd_bandsteer_mac = (dhd_bandsteer_mac_entry_t *)arg;
+
+ if (dhd_bandsteer_mac == NULL) {
+ DHD_ERROR(("%s: dhd_bandsteer_mac is null\n", __FUNCTION__));
+ return;
+ }
+
+ DHD_TRACE(("%s: Peer STA BandSteer status 0x%x", __FUNCTION__,
+ dhd_bandsteer_mac->dhd_bandsteer_status));
+
+ switch (dhd_bandsteer_mac->dhd_bandsteer_status) {
+ case DHD_BANDSTEER_START:
+ case DHD_BANDSTEER_WNM_FRAME_RETRY:
+ dhd_bandsteer_mac->dhd_bandsteer_status = DHD_BANDSTEER_WNM_FRAME_SEND;
+ dhd_bandsteer_schedule_work_on_timeout(dhd_bandsteer_mac);
+ break;
+
+ case DHD_BANDSTEER_WNM_FRAME_SEND:
+ dhd_bandsteer_tx_wnm_actframe(dhd_bandsteer_mac);
+ if (dhd_bandsteer_mac->wnm_frame_counter < DHD_BANDSTEER_WNM_FRAME_MAXRETRY) {
+ /* Sending out WNM action frame as soon as assoc indication recieved */
+ dhd_bandsteer_mac->dhd_bandsteer_status = DHD_BANDSTEER_WNM_FRAME_RETRY;
+ }
+ else {
+ dhd_bandsteer_mac->dhd_bandsteer_status = DHD_BANDSTEER_TRIAL_DONE;
+ }
+ break;
+ case DHD_BANDSTEER_TRIAL_DONE:
+ dhd_bandsteer_remove_mac_from_list(dhd_bandsteer_mac, 0);
+ break;
+ }
+ return;
+}
+
+void
+dhd_bandsteer_workqueue_wrapper(void *handle, void *event_info, u8 event)
+{
+ dhd_bandsteer_mac_entry_t *dhd_bandsteer_mac = (dhd_bandsteer_mac_entry_t *)event_info;
+
+ if (event != DHD_WQ_WORK_BANDSTEER_STEP_MOVE) {
+ DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
+ return;
+ }
+
+ dhd_bandsteer_state_machine((ulong)dhd_bandsteer_mac);
+}
+
+/*
+ * This API create and initilize an entry into list which need to be processed later
+ */
+static s32
+dhd_bandsteer_addmac_to_monitorlist(dhd_bandsteer_context_t *dhd_bandsteer_cntx, uint8 *mac_addr)
+{
+ dhd_bandsteer_mac_entry_t *dhd_bandsteer_mac;
+
+ dhd_bandsteer_mac = kzalloc(sizeof(dhd_bandsteer_mac_entry_t), GFP_KERNEL);
+ if (unlikely(!dhd_bandsteer_mac)) {
+ DHD_ERROR(("%s: alloc failed\n", __FUNCTION__));
+ return BCME_NOMEM;
+ }
+ INIT_LIST_HEAD(&dhd_bandsteer_mac->list);
+ /* pointer dhd_bandsteer_cntx for future use */
+ dhd_bandsteer_mac->dhd_bandsteer_cntx = dhd_bandsteer_cntx;
+
+ dhd_bandsteer_mac->dhd_bandsteer_status = DHD_BANDSTEER_START;
+
+ memcpy(&dhd_bandsteer_mac->mac_addr.octet, mac_addr, ETHER_ADDR_LEN);
+
+ /* Configure timer for 20 Sec */
+ init_timer(&dhd_bandsteer_mac->dhd_bandsteer_timer);
+ dhd_bandsteer_mac->dhd_bandsteer_timer.data = (ulong)dhd_bandsteer_mac;
+ dhd_bandsteer_mac->dhd_bandsteer_timer.function = dhd_bandsteer_state_machine;
+ dhd_bandsteer_mac->wnm_frame_counter = 0;
+
+ /* Add new entry into the list */
+ list_add_tail(&dhd_bandsteer_mac->list,
+ &dhd_bandsteer_cntx->dhd_bandsteer_monitor_list);
+
+ DHD_TRACE(("%s: " MACDBG " added into list \n", __FUNCTION__,
+ MAC2STRDBG(dhd_bandsteer_mac->mac_addr.octet)));
+ /* This can be tweaked more */
+ dhd_bandsteer_add_timer(dhd_bandsteer_mac, DHD_BANDSTEER_WNM_FRAME_DELAY);
+
+ return BCME_OK;
+}
+
+/*
+ * This function removes one or all mac entry from the list
+ */
+static s32
+dhd_bandsteer_remove_mac_from_list(dhd_bandsteer_mac_entry_t *dhd_bandsteer_mac, int all)
+{
+ dhd_bandsteer_context_t *dhd_bandsteer_cntx;
+ dhd_bandsteer_mac_entry_t *curr, *next;
+
+ DHD_INFO(("%s: entered \n", __FUNCTION__));
+ /* TODO:probably these sanity lines can be removed */
+ if (dhd_bandsteer_mac == NULL) {
+ DHD_ERROR(("%s: dhd_bandsteer_mac is NULL\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+
+ dhd_bandsteer_cntx = dhd_bandsteer_mac->dhd_bandsteer_cntx;
+
+ list_for_each_entry_safe(curr, next,
+ &dhd_bandsteer_cntx->dhd_bandsteer_monitor_list, list) {
+ if ((curr == dhd_bandsteer_mac) || all) {
+ DHD_ERROR(("%s: " MACDBG " deleted from list \n", __FUNCTION__,
+ MAC2STRDBG(dhd_bandsteer_mac->mac_addr.octet)));
+ list_del(&dhd_bandsteer_mac->list);
+ dhd_bandsteer_delete_timer(dhd_bandsteer_mac);
+ kfree(dhd_bandsteer_mac);
+ if (!all)
+ break;
+ }
+ }
+ return BCME_OK;
+}
+
+/*
+ * Logic to find corresponding node in list based given mac address
+ * Returns null if entry not seen
+ */
+static dhd_bandsteer_mac_entry_t*
+dhd_bandsteer_look_for_match(dhd_bandsteer_context_t *dhd_bandsteer_cntx, uint8 *mac_addr)
+{
+ dhd_bandsteer_mac_entry_t *curr = NULL, *next = NULL;
+
+ list_for_each_entry_safe(curr, next,
+ &dhd_bandsteer_cntx->dhd_bandsteer_monitor_list, list) {
+ if (memcmp(&curr->mac_addr.octet, mac_addr, ETHER_ADDR_LEN) == 0) {
+ return curr;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * This API will send wnm action frame also configure timeout timer
+ */
+static s32
+dhd_bandsteer_tx_wnm_actframe(dhd_bandsteer_mac_entry_t *dhd_bandsteer_mac)
+{
+ dhd_bandsteer_context_t *dhd_bandsteer_cntx = dhd_bandsteer_mac->dhd_bandsteer_cntx;
+ wl_action_frame_t *action_frame = NULL;
+ wl_af_params_t *af_params = NULL;
+ char *smbuf = NULL;
+ int error = BCME_ERROR;
+ uint8 *bp;
+ dhd_bandsteer_iface_info_t *if_info_5g, *if_info_2g;
+
+ if_info_5g = &dhd_bandsteer_cntx->bsd_ifaces[dhd_bandsteer_cntx->ifidx_5g];
+ if_info_2g = &dhd_bandsteer_cntx->bsd_ifaces[!dhd_bandsteer_cntx->ifidx_5g];
+
+ smbuf = kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
+ if (smbuf == NULL) {
+ DHD_ERROR(("%s: failed to allocated memory %d bytes\n", __FUNCTION__,
+ WLC_IOCTL_MAXLEN));
+ goto send_action_frame_out;
+ }
+
+ af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL);
+ if (af_params == NULL) {
+ DHD_ERROR(("%s: unable to allocate frame\n", __FUNCTION__));
+ goto send_action_frame_out;
+ }
+
+ af_params->channel = if_info_2g->channel;
+ af_params->dwell_time = -1;
+ memcpy(&af_params->BSSID, &dhd_bandsteer_mac->mac_addr.octet, ETHER_ADDR_LEN);
+ action_frame = &af_params->action_frame;
+
+ action_frame->packetId = 0;
+ memcpy(&action_frame->da, &dhd_bandsteer_mac->mac_addr.octet, ETHER_ADDR_LEN);
+
+ dhd_bandsteer_mac->wnm_frame_counter++;
+ bp = (uint8 *)action_frame->data;
+ *bp++ = 0xa; /* Category */
+ *bp++ = 0x7; /* Action ID */
+ *bp++ = dhd_bandsteer_mac->wnm_frame_counter; /* Dialog Token */
+ *bp++ = 0x1; /* Request mode */
+ *bp++ = 0x0; /* disassociation timer has two bytes */
+ *bp++ = 0x0;
+ *bp++ = 0x0; /* Validity interval */
+ *bp++ = 0x34; /* Element ID */
+ *bp++ = 0xd; /* Len */
+ memcpy(bp, if_info_5g->macaddr.octet, ETHER_ADDR_LEN);
+ bp += ETHER_ADDR_LEN;
+ bp +=4; /* Skip BSSID info 4 bytes in size */
+ *bp++ = 0x7d; /* Operating class */
+ *bp++ = if_info_5g->channel; /* Channel number */
+ *bp = 0x0; /* Phy Type */
+
+ action_frame->len = (bp - (uint8 *)&action_frame->data) + 1;
+
+ error = wldev_iovar_setbuf(if_info_2g->ndev, "actframe", af_params,
+ sizeof(wl_af_params_t), smbuf, WLC_IOCTL_MAXLEN, NULL);
+ if (error) {
+ DHD_ERROR(("Failed to set action frame, error=%d\n", error));
+ goto send_action_frame_out;
+ }
+ DHD_TRACE(("%s: BSS Trans Req frame sent to " MACDBG " try %d\n", __FUNCTION__,
+ MAC2STRDBG(dhd_bandsteer_mac->mac_addr.octet),
+ dhd_bandsteer_mac->wnm_frame_counter));
+
+send_action_frame_out:
+ /* Re-schedule the timer */
+ dhd_bandsteer_add_timer(dhd_bandsteer_mac, DHD_BANDSTEER_WNM_FRAME_DELAY);
+ if (af_params)
+ kfree(af_params);
+
+ if (smbuf)
+ kfree(smbuf);
+
+ if (error)
+ return BCME_ERROR;
+
+ return BCME_OK;
+}
+
+/*
+ * Call dhd_bandsteer_remove_mac_from_list()
+ * Add into black list of corresponding interace at present 2.4
+ * Uses existing IOVAR calls
+ */
+static void
+dhd_bandsteer_add_to_black_list(dhd_bandsteer_mac_entry_t *dhd_bandsteer_mac)
+{
+ dhd_bandsteer_context_t *dhd_bandsteer_cntx = dhd_bandsteer_mac->dhd_bandsteer_cntx;
+ dhd_bandsteer_iface_info_t *if_info_2g;
+ int err;
+ int macmode = MACLIST_MODE_DENY;
+ struct maclist *maclist;
+ uint8 *pmaclist_ea;
+ uint8 mac_buf[MAX_NUM_OF_ASSOCLIST *
+ sizeof(struct ether_addr) + sizeof(uint)] = {0};
+
+ if_info_2g = &dhd_bandsteer_cntx->bsd_ifaces[!dhd_bandsteer_cntx->ifidx_5g];
+
+ /* Black listing */
+ DHD_INFO(("%s: Black listing " MACDBG " on 2GHz IF\n", __FUNCTION__,
+ MAC2STRDBG(dhd_bandsteer_mac->mac_addr.octet)));
+
+ /* Get current black list */
+ if ((err = wldev_ioctl(if_info_2g->ndev, WLC_GET_MACLIST, mac_buf,
+ sizeof(mac_buf), false)) != 0) {
+ DHD_ERROR(("%s: WLC_GET_MACLIST error=%d\n", __FUNCTION__, err));
+ }
+
+ maclist = (struct maclist *)mac_buf;
+ pmaclist_ea = (uint8*) mac_buf +
+ (sizeof(struct ether_addr) * maclist->count) + sizeof(uint);
+ maclist->count++;
+
+ memcpy(pmaclist_ea, &dhd_bandsteer_mac->mac_addr.octet, ETHER_ADDR_LEN);
+
+ if ((err = wldev_iovar_setint(if_info_2g->ndev, "probresp_mac_filter", 1)) != BCME_OK) {
+ DHD_ERROR(("%s: failed to set probe response filter err %d\n", __FUNCTION__, err));
+ }
+
+ if ((err = wldev_ioctl(if_info_2g->ndev, WLC_SET_MACMODE, &macmode,
+ sizeof(macmode), true)) != 0) {
+ DHD_ERROR(("%s: WLC_SET_MACMODE error=%d\n", __FUNCTION__, err));
+ }
+
+ /* set the MAC filter list */
+ if ((err = wldev_ioctl(if_info_2g->ndev, WLC_SET_MACLIST, maclist,
+ sizeof(int) + sizeof(struct ether_addr) * maclist->count, true)) != 0) {
+ DHD_ERROR(("%s: WLC_SET_MACLIST error=%d\n", __FUNCTION__, err));
+ }
+}
+
+/*
+ * Check if mac association on 2.4 G
+ * If on 2.4
+ * * Ignore if we have already run Bandsteer cycle for this
+ * * Add PEER STA mac monitor_list
+ * * Send BSS transition request frame
+ * Else
+ * * We recieved assoc on 5g from Mac we forced to move onto 5G
+ */
+s32
+dhd_bandsteer_trigger_bandsteer(struct net_device *ndev, uint8 *mac_addr)
+{
+ struct wireless_dev *__wdev = (struct wireless_dev *)(ndev)->ieee80211_ptr;
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(__wdev->wiphy);
+ struct net_device *netdev_5g = NULL;
+ dhd_bandsteer_mac_entry_t *dhd_bandsteer_mac = NULL;
+ dhd_bandsteer_context_t *dhd_bandsteer_cntx = NULL;
+
+ DHD_TRACE(("%s: Start band-steer procedure for " MACDBG "\n", __FUNCTION__,
+ MAC2STRDBG(mac_addr)));
+
+ if (cfg == NULL) {
+ DHD_ERROR(("%s: bcmcfg is null\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+ if (cfg->dhd_bandsteer_cntx == NULL) {
+ DHD_ERROR(("%s: Band Steering not enabled\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+
+ dhd_bandsteer_cntx = cfg->dhd_bandsteer_cntx;
+
+ netdev_5g = dhd_bandsteer_cntx->bsd_ifaces[dhd_bandsteer_cntx->ifidx_5g].ndev;
+ dhd_bandsteer_mac = dhd_bandsteer_look_for_match(dhd_bandsteer_cntx, mac_addr);
+ if (dhd_bandsteer_mac == NULL) {
+ /*
+ * This STA entry not found in list check if bandsteer is already done for this
+ * Check if this on 2.4/5Ghz
+ */
+ if (ndev == netdev_5g) {
+ /* Ignore as device aleady connectd to 5G */
+ DHD_INFO(("%s: " MACDBG " is on 5GHz interface\n", __FUNCTION__,
+ MAC2STRDBG(mac_addr)));
+ return BCME_OK;
+ }
+ else {
+ dhd_bandsteer_addmac_to_monitorlist(dhd_bandsteer_cntx, mac_addr);
+ /*
+ * TODO: Time for us to enable PROB_REQ MSG
+ */
+ }
+ }
+ else {
+ /*
+ * Start post connect process as bandsteer is successful for this entry
+ */
+ if (ndev == netdev_5g) {
+ DHD_INFO(("%s: Band Steer for " MACDBG " successful\n", __FUNCTION__,
+ MAC2STRDBG(mac_addr)));
+ dhd_bandsteer_add_to_black_list(dhd_bandsteer_mac);
+ dhd_bandsteer_remove_mac_from_list(dhd_bandsteer_mac, 0);
+ /* Probabaly add this mac into black list */
+ }
+ }
+ return BCME_OK;
+}
+
+
+
+s32
+dhd_bandsteer_module_init(struct net_device *ndev)
+{
+ /* Initialize */
+ dhd_bandsteer_context_t *dhd_bandsteer_cntx = NULL;
+ struct channel_info ci;
+ uint8 ifidx;
+ struct wireless_dev *__wdev = (struct wireless_dev *)(ndev)->ieee80211_ptr;
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(__wdev->wiphy);
+ int err;
+
+ DHD_INFO(("%s: entered\n", __FUNCTION__));
+
+ if (cfg == NULL) {
+ DHD_ERROR(("%s: bcmcfg is null\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+
+ if (cfg->dhd_bandsteer_cntx != NULL) {
+ DHD_ERROR(("%s: Band Steering already enabled\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+
+ dhd_bandsteer_cntx = (dhd_bandsteer_context_t *)kzalloc(sizeof(dhd_bandsteer_context_t),
+ GFP_KERNEL);
+ if (unlikely(!dhd_bandsteer_cntx)) {
+ DHD_ERROR(("%s: dhd_bandsteer_cntx alloc failed\n", __FUNCTION__));
+ return BCME_NOMEM;
+ }
+
+ if (dhd_bandsteer_get_ifaces(cfg->pub, &dhd_bandsteer_cntx->bsd_ifaces)) {
+ DHD_ERROR(("%s: AP interfaces count != 2", __FUNCTION__));
+ err = BCME_ERROR;
+ goto failed;
+ }
+
+ for (ifidx = 0; ifidx < DHD_BANDSTEER_MAXIFACES; ifidx++) {
+ err = wldev_iovar_getbuf_bsscfg(dhd_bandsteer_cntx->bsd_ifaces[ifidx].ndev,
+ "cur_etheraddr", NULL, 0, cfg->ioctl_buf,
+ WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
+ if (err) {
+ DHD_ERROR(("%s: Failed to get mac address\n", __FUNCTION__));
+ goto failed;
+ }
+
+ memcpy(dhd_bandsteer_cntx->bsd_ifaces[ifidx].macaddr.octet,
+ cfg->ioctl_buf, ETHER_ADDR_LEN);
+
+ memset(&ci, 0, sizeof(struct channel_info));
+ err = wldev_ioctl(dhd_bandsteer_cntx->bsd_ifaces[ifidx].ndev, WLC_GET_CHANNEL,
+ &ci, sizeof(ci), false);
+ if (err) {
+ DHD_ERROR(("%s: Failed to get channel\n", __FUNCTION__));
+ goto failed;
+ }
+ if (CHANNEL_IS_5G(ci.hw_channel))
+ dhd_bandsteer_cntx->ifidx_5g = ifidx;
+
+ dhd_bandsteer_cntx->bsd_ifaces[ifidx].channel = ci.hw_channel;
+ }
+
+ /* Enable software proberesponse on 2GHz interface */
+ if ((err = wldev_iovar_setint(
+ dhd_bandsteer_cntx->bsd_ifaces[!dhd_bandsteer_cntx->ifidx_5g].ndev,
+ "probresp_sw", 1)) != BCME_OK) {
+ DHD_ERROR(("%s: Failed to enable software ProbeRsp err = %d\n", __FUNCTION__, err));
+ }
+
+ if ((err = wldev_iovar_setint(ndev, "bandsteer", 1)) != BCME_OK) {
+ DHD_ERROR(("%s: Failed to enable bandsteer in FW err = %d\n", __FUNCTION__, err));
+ }
+
+
+ INIT_LIST_HEAD(&dhd_bandsteer_cntx->dhd_bandsteer_monitor_list);
+ dhd_bandsteer_cntx->dhd_pub = cfg->pub;
+ cfg->dhd_bandsteer_cntx = (void *) dhd_bandsteer_cntx;
+ return BCME_OK;
+
+failed:
+ kfree(dhd_bandsteer_cntx);
+ return err;
+}
+
+s32
+dhd_bandsteer_module_deinit(struct net_device *ndev)
+{
+ dhd_bandsteer_mac_entry_t *dhd_bandsteer_mac = NULL;
+ dhd_bandsteer_context_t *dhd_bandsteer_cntx = NULL;
+ struct wireless_dev *__wdev = (struct wireless_dev *)(ndev)->ieee80211_ptr;
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(__wdev->wiphy);
+ int macmode = MACLIST_MODE_DISABLED;
+ int err;
+ struct maclist maclist;
+
+ DHD_INFO(("%s: entered\n", __FUNCTION__));
+
+ if (cfg == NULL) {
+ DHD_ERROR(("%s: bcmcfg is null\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+
+ if (cfg->dhd_bandsteer_cntx == NULL) {
+ DHD_ERROR(("%s: Band Steering not enabled\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+
+ dhd_bandsteer_cntx = cfg->dhd_bandsteer_cntx;
+
+ /* Disable mac filter */
+ if ((err = wldev_ioctl(dhd_bandsteer_cntx->bsd_ifaces[!dhd_bandsteer_cntx->ifidx_5g].ndev,
+ WLC_SET_MACMODE, &macmode, sizeof(macmode), true)) != 0) {
+ DHD_ERROR(("%s: WLC_SET_MACMODE error=%d\n", __FUNCTION__, err));
+ }
+
+ /* Set the MAC filter list */
+ memset(&maclist, 0, sizeof(struct maclist));
+ if ((err = wldev_ioctl(dhd_bandsteer_cntx->bsd_ifaces[!dhd_bandsteer_cntx->ifidx_5g].ndev,
+ WLC_SET_MACLIST, &maclist, sizeof(struct maclist), true)) != 0) {
+ DHD_ERROR(("%s: WLC_SET_MACLIST error=%d\n", __FUNCTION__, err));
+ }
+
+ /* Disable software proberesponse on 2GHz interface */
+ if ((err = wldev_iovar_setint(
+ dhd_bandsteer_cntx->bsd_ifaces[!dhd_bandsteer_cntx->ifidx_5g].ndev,
+ "probresp_sw", 0)) != BCME_OK) {
+ DHD_ERROR(("%s: Failed to disable software ProbeRsp err = %d\n",
+ __FUNCTION__, err));
+ }
+
+ if ((err = wldev_iovar_setint(ndev, "bandsteer", 0)) != BCME_OK) {
+ DHD_ERROR(("%s: Failed to disable bandsteer in FW err = %d\n", __FUNCTION__, err));
+ }
+
+ /* Get the first element of the list & pass it to remove */
+ if (dhd_bandsteer_cntx->dhd_bandsteer_monitor_list.next !=
+ &dhd_bandsteer_cntx->dhd_bandsteer_monitor_list) {
+ dhd_bandsteer_mac = (dhd_bandsteer_mac_entry_t *)list_entry(
+ dhd_bandsteer_cntx->dhd_bandsteer_monitor_list.next,
+ dhd_bandsteer_mac_entry_t, list);
+ }
+
+ if (dhd_bandsteer_mac) {
+ dhd_bandsteer_remove_mac_from_list(dhd_bandsteer_mac, 1);
+ }
+
+ kfree(dhd_bandsteer_cntx);
+ cfg->dhd_bandsteer_cntx = NULL;
+ return BCME_OK;
+}
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_bandsteer.h b/drivers/net/wireless/bcmdhd_1363/dhd_bandsteer.h
new file mode 100644
index 000000000000..0467cbf5ed18
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_bandsteer.h
@@ -0,0 +1,75 @@
+/*
+ * Band Steering logic
+ *
+ * Feature by which dualband capable PEERs will be
+ * forced move on 5GHz 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.
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $ Copyright Cypress Semiconductor $
+ *
+ * $Id: dhd_bandsteer.h 664149 2017-03-07 13:29:02Z $
+ */
+
+#ifndef _dhd_bandsteer_h_
+#define _dhd_bandsteer_h_
+
+/* Local Types */
+typedef struct dhd_bandsteer_context dhd_bandsteer_context_t;
+
+typedef struct dhd_bandsteer_iface_info {
+ s32 bssidx;
+ s32 channel;
+ struct ether_addr macaddr;
+ struct net_device *ndev;
+} dhd_bandsteer_iface_info_t;
+
+typedef struct dhd_bandsteer_mac_entry {
+ struct list_head list; // Pointer to head of the list
+ uint32 dhd_bandsteer_status; // Usefull in timer call back
+ dhd_bandsteer_context_t *dhd_bandsteer_cntx;
+ struct timer_list dhd_bandsteer_timer; // Callback to Advance BS STATEMACHINE
+ uint8 wnm_frame_counter;
+ struct ether_addr mac_addr;
+} dhd_bandsteer_mac_entry_t;
+
+struct dhd_bandsteer_context {
+ struct list_head dhd_bandsteer_monitor_list;
+ uint8 ifidx_5g;
+ dhd_bandsteer_iface_info_t bsd_ifaces[2]; /* idx 0 5G, 1 2G */
+ void *dhd_pub;
+};
+
+/* Local Types ends */
+
+/* ********************** Function declaration *********************** */
+void dhd_bandsteer_process_disassoc(dhd_bandsteer_context_t *dhd_bandsteer_cntx,
+ const wl_event_msg_t *e);
+s32 dhd_bandsteer_module_init(struct net_device *ndev);
+s32 dhd_bandsteer_module_deinit(struct net_device *ndev);
+void dhd_bandsteer_schedule_work_on_timeout(dhd_bandsteer_mac_entry_t *dhd_bandsteer_mac);
+void dhd_bandsteer_workqueue_wrapper(void *handle, void *event_info, u8 event);
+s32 dhd_bandsteer_get_ifaces(void *pub, void *ifaces);
+s32 dhd_bandsteer_trigger_bandsteer(struct net_device *, uint8 *);
+/* ********************** Function declartion ends ****************** */
+#endif /* _dhd_bandsteer_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_bta.c b/drivers/net/wireless/bcmdhd_1363/dhd_bta.c
new file mode 100644
index 000000000000..1c2be05d93ae
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_bta.c
@@ -0,0 +1,340 @@
+/*
+ * BT-AMP support 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_bta.c 514727 2014-11-12 03:02:48Z $
+ */
+#error "WLBTAMP is not defined"
+
+#include <typedefs.h>
+#include <osl.h>
+#include <bcmcdc.h>
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <proto/802.11.h>
+#include <proto/802.11_bta.h>
+#include <proto/bt_amp_hci.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_bus.h>
+#include <dhd_proto.h>
+#include <dhdioctl.h>
+#include <dhd_dbg.h>
+
+#include <dhd_bta.h>
+
+
+#ifdef SEND_HCI_CMD_VIA_IOCTL
+#define BTA_HCI_CMD_MAX_LEN HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE
+
+/* Send HCI cmd via wl iovar HCI_cmd to the dongle. */
+int
+dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len)
+{
+ amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf;
+ uint8 buf[BTA_HCI_CMD_MAX_LEN + 16];
+ uint len = sizeof(buf);
+ wl_ioctl_t ioc;
+
+ if (cmd_len < HCI_CMD_PREAMBLE_SIZE)
+ return BCME_BADLEN;
+
+ if ((uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE > cmd_len)
+ return BCME_BADLEN;
+
+ len = bcm_mkiovar("HCI_cmd",
+ (char *)cmd, (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, (char *)buf, len);
+
+
+ memset(&ioc, 0, sizeof(ioc));
+
+ ioc.cmd = WLC_SET_VAR;
+ ioc.buf = buf;
+ ioc.len = len;
+ ioc.set = TRUE;
+
+ return dhd_wl_ioctl(pub, &ioc, ioc.buf, ioc.len);
+}
+#else /* !SEND_HCI_CMD_VIA_IOCTL */
+
+static void
+dhd_bta_flush_hcidata(dhd_pub_t *pub, uint16 llh)
+{
+ int prec;
+ struct pktq *q;
+ uint count = 0;
+
+ q = dhd_bus_txq(pub->bus);
+ if (q == NULL)
+ return;
+
+ DHD_BTA(("dhd: flushing HCI ACL data for logical link %u...\n", llh));
+
+ dhd_os_sdlock_txq(pub);
+
+ /* Walk through the txq and toss all HCI ACL data packets */
+ PKTQ_PREC_ITER(q, prec) {
+ void *head_pkt = NULL;
+
+ while (pktq_ppeek(q, prec) != head_pkt) {
+ void *pkt = pktq_pdeq(q, prec);
+ int ifidx;
+
+ dhd_prot_hdrpull(pub, &ifidx, pkt, NULL, NULL);
+
+ if (PKTLEN(pub->osh, pkt) >= RFC1042_HDR_LEN) {
+ struct ether_header *eh =
+ (struct ether_header *)PKTDATA(pub->osh, pkt);
+
+ if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) {
+ struct dot11_llc_snap_header *lsh =
+ (struct dot11_llc_snap_header *)&eh[1];
+
+ if (bcmp(lsh, BT_SIG_SNAP_MPROT,
+ DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
+ ntoh16(lsh->type) == BTA_PROT_L2CAP) {
+ amp_hci_ACL_data_t *ACL_data =
+ (amp_hci_ACL_data_t *)&lsh[1];
+ uint16 handle = ltoh16(ACL_data->handle);
+
+ if (HCI_ACL_DATA_HANDLE(handle) == llh) {
+ PKTFREE(pub->osh, pkt, TRUE);
+ count ++;
+ continue;
+ }
+ }
+ }
+ }
+
+ dhd_prot_hdrpush(pub, ifidx, pkt);
+
+ if (head_pkt == NULL)
+ head_pkt = pkt;
+ pktq_penq(q, prec, pkt);
+ }
+ }
+
+ dhd_os_sdunlock_txq(pub);
+
+ DHD_BTA(("dhd: flushed %u packet(s) for logical link %u...\n", count, llh));
+}
+
+/* Handle HCI cmd locally.
+ * Return 0: continue to send the cmd across SDIO
+ * < 0: stop, fail
+ * > 0: stop, succuess
+ */
+static int
+_dhd_bta_docmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd)
+{
+ int status = 0;
+
+ switch (ltoh16_ua((uint8 *)&cmd->opcode)) {
+ case HCI_Enhanced_Flush: {
+ eflush_cmd_parms_t *cmdparms = (eflush_cmd_parms_t *)cmd->parms;
+ dhd_bta_flush_hcidata(pub, ltoh16_ua(cmdparms->llh));
+ break;
+ }
+ default:
+ break;
+ }
+
+ return status;
+}
+
+/* Send HCI cmd encapsulated in BT-SIG frame via data channel to the dongle. */
+int
+dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len)
+{
+ amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf;
+ struct ether_header *eh;
+ struct dot11_llc_snap_header *lsh;
+ osl_t *osh = pub->osh;
+ uint len;
+ void *p;
+ int status;
+
+ if (cmd_len < HCI_CMD_PREAMBLE_SIZE) {
+ DHD_ERROR(("dhd_bta_docmd: short command, cmd_len %u\n", cmd_len));
+ return BCME_BADLEN;
+ }
+
+ if ((len = (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE) > cmd_len) {
+ DHD_ERROR(("dhd_bta_docmd: malformed command, len %u cmd_len %u\n",
+ len, cmd_len));
+ /* return BCME_BADLEN; */
+ }
+
+ p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE);
+ if (p == NULL) {
+ DHD_ERROR(("dhd_bta_docmd: out of memory\n"));
+ return BCME_NOMEM;
+ }
+
+
+ /* intercept and handle the HCI cmd locally */
+ if ((status = _dhd_bta_docmd(pub, cmd)) > 0)
+ return 0;
+ else if (status < 0)
+ return status;
+
+ /* copy in HCI cmd */
+ PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN);
+ bcopy(cmd, PKTDATA(osh, p), len);
+
+ /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */
+ PKTPUSH(osh, p, RFC1042_HDR_LEN);
+ eh = (struct ether_header *)PKTDATA(osh, p);
+ bzero(eh->ether_dhost, ETHER_ADDR_LEN);
+ ETHER_SET_LOCALADDR(eh->ether_dhost);
+ bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN);
+ eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN);
+ lsh = (struct dot11_llc_snap_header *)&eh[1];
+ bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2);
+ lsh->type = 0;
+
+ return dhd_sendpkt(pub, 0, p);
+}
+#endif /* !SEND_HCI_CMD_VIA_IOCTL */
+
+/* Send HCI ACL data to dongle via data channel */
+int
+dhd_bta_tx_hcidata(dhd_pub_t *pub, void *data_buf, uint data_len)
+{
+ amp_hci_ACL_data_t *data = (amp_hci_ACL_data_t *)data_buf;
+ struct ether_header *eh;
+ struct dot11_llc_snap_header *lsh;
+ osl_t *osh = pub->osh;
+ uint len;
+ void *p;
+
+ if (data_len < HCI_ACL_DATA_PREAMBLE_SIZE) {
+ DHD_ERROR(("dhd_bta_tx_hcidata: short data_buf, data_len %u\n", data_len));
+ return BCME_BADLEN;
+ }
+
+ if ((len = (uint)ltoh16(data->dlen) + HCI_ACL_DATA_PREAMBLE_SIZE) > data_len) {
+ DHD_ERROR(("dhd_bta_tx_hcidata: malformed hci data, len %u data_len %u\n",
+ len, data_len));
+ /* return BCME_BADLEN; */
+ }
+
+ p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE);
+ if (p == NULL) {
+ DHD_ERROR(("dhd_bta_tx_hcidata: out of memory\n"));
+ return BCME_NOMEM;
+ }
+
+
+ /* copy in HCI ACL data header and HCI ACL data */
+ PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN);
+ bcopy(data, PKTDATA(osh, p), len);
+
+ /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */
+ PKTPUSH(osh, p, RFC1042_HDR_LEN);
+ eh = (struct ether_header *)PKTDATA(osh, p);
+ bzero(eh->ether_dhost, ETHER_ADDR_LEN);
+ bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN);
+ eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN);
+ lsh = (struct dot11_llc_snap_header *)&eh[1];
+ bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2);
+ lsh->type = HTON16(BTA_PROT_L2CAP);
+
+ return dhd_sendpkt(pub, 0, p);
+}
+
+/* txcomplete callback */
+void
+dhd_bta_tx_hcidata_complete(dhd_pub_t *dhdp, void *txp, bool success)
+{
+ uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, txp);
+ amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)(pktdata + RFC1042_HDR_LEN);
+ uint16 handle = ltoh16(ACL_data->handle);
+ uint16 llh = HCI_ACL_DATA_HANDLE(handle);
+
+ wl_event_msg_t event;
+ uint8 data[HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t)];
+ amp_hci_event_t *evt;
+ num_completed_data_blocks_evt_parms_t *parms;
+
+ uint16 len = HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t);
+
+ /* update the event struct */
+ memset(&event, 0, sizeof(event));
+ event.version = hton16(BCM_EVENT_MSG_VERSION);
+ event.event_type = hton32(WLC_E_BTA_HCI_EVENT);
+ event.status = 0;
+ event.reason = 0;
+ event.auth_type = 0;
+ event.datalen = hton32(len);
+ event.flags = 0;
+
+ /* generate Number of Completed Blocks event */
+ evt = (amp_hci_event_t *)data;
+ evt->ecode = HCI_Number_of_Completed_Data_Blocks;
+ evt->plen = sizeof(num_completed_data_blocks_evt_parms_t);
+
+ parms = (num_completed_data_blocks_evt_parms_t *)evt->parms;
+ htol16_ua_store(dhdp->maxdatablks, (uint8 *)&parms->num_blocks);
+ parms->num_handles = 1;
+ htol16_ua_store(llh, (uint8 *)&parms->completed[0].handle);
+ parms->completed[0].pkts = 1;
+ parms->completed[0].blocks = 1;
+
+ dhd_sendup_event_common(dhdp, &event, data);
+}
+
+/* event callback */
+void
+dhd_bta_doevt(dhd_pub_t *dhdp, void *data_buf, uint data_len)
+{
+ amp_hci_event_t *evt = (amp_hci_event_t *)data_buf;
+
+ ASSERT(dhdp);
+ ASSERT(evt);
+
+ switch (evt->ecode) {
+ case HCI_Command_Complete: {
+ cmd_complete_parms_t *parms = (cmd_complete_parms_t *)evt->parms;
+ switch (ltoh16_ua((uint8 *)&parms->opcode)) {
+ case HCI_Read_Data_Block_Size: {
+ read_data_block_size_evt_parms_t *parms2 =
+ (read_data_block_size_evt_parms_t *)parms->parms;
+ dhdp->maxdatablks = ltoh16_ua((uint8 *)&parms2->data_block_num);
+ break;
+ }
+ }
+ break;
+ }
+
+ case HCI_Flush_Occurred: {
+ flush_occurred_evt_parms_t *evt_parms = (flush_occurred_evt_parms_t *)evt->parms;
+ dhd_bta_flush_hcidata(dhdp, ltoh16_ua((uint8 *)&evt_parms->handle));
+ break;
+ }
+ default:
+ break;
+ }
+}
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_bta.h b/drivers/net/wireless/bcmdhd_1363/dhd_bta.h
new file mode 100644
index 000000000000..dcb5e658c45c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_bta.h
@@ -0,0 +1,42 @@
+/*
+ * BT-AMP support 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_bta.h 514727 2014-11-12 03:02:48Z $
+ */
+#ifndef __dhd_bta_h__
+#define __dhd_bta_h__
+
+struct dhd_pub;
+
+extern int dhd_bta_docmd(struct dhd_pub *pub, void *cmd_buf, uint cmd_len);
+
+extern void dhd_bta_doevt(struct dhd_pub *pub, void *data_buf, uint data_len);
+
+extern int dhd_bta_tx_hcidata(struct dhd_pub *pub, void *data_buf, uint data_len);
+extern void dhd_bta_tx_hcidata_complete(struct dhd_pub *dhdp, void *txp, bool success);
+
+
+#endif /* __dhd_bta_h__ */
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_bus.h b/drivers/net/wireless/bcmdhd_1363/dhd_bus.h
new file mode 100644
index 000000000000..679e2086f8fc
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_bus.h
@@ -0,0 +1,220 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_bus.h 647154 2016-07-04 07:23:19Z $
+ */
+
+#ifndef _dhd_bus_h_
+#define _dhd_bus_h_
+
+/*
+ * 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);
+
+/* 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);
+
+/* 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
+
+
+/* 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);
+
+#if defined(DHD_DEBUG)
+/* Device console input function */
+extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen);
+#endif /* defined(DHD_DEBUG) */
+
+/* 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 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);
+
+#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 */
+
+ /* 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
+};
+
+typedef void (*dhd_mb_ring_t) (struct dhd_bus *, uint32);
+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_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 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);
+
+
+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);
+
+
+#ifdef DHD_FW_COREDUMP
+extern int dhd_bus_mem_dump(dhd_pub_t *dhd);
+
+extern struct dhd_bus *g_dhd_bus;
+#ifdef BCMDHDX
+extern int dhdx_dongle_mem_dump(void);
+#else
+extern int dhd_dongle_mem_dump(void);
+#endif /* BCMDHDX */
+#endif /* DHD_FW_COREDUMP */
+
+#endif /* BCMPCIE */
+#endif /* _dhd_bus_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_buzzz.h b/drivers/net/wireless/bcmdhd_1363/dhd_buzzz.h
new file mode 100644
index 000000000000..879a3ddb7046
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_buzzz.h 591283 2015-10-07 11:52:00Z $
+ */
+
+#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/drivers/net/wireless/bcmdhd_1363/dhd_cdc.c b/drivers/net/wireless/bcmdhd_1363/dhd_cdc.c
new file mode 100644
index 000000000000..7f341b63ffd3
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_cdc.c
@@ -0,0 +1,814 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_cdc.c 633939 2016-04-26 06:55:52Z $
+ *
+ * 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 <typedefs.h>
+#include <osl.h>
+
+#include <bcmutils.h>
+#include <bcmcdc.h>
+#include <bcmendian.h>
+
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_proto.h>
+#include <dhd_bus.h>
+#include <dhd_dbg.h>
+
+
+#ifdef PROP_TXSTATUS
+#include <wlfc_proto.h>
+#include <dhd_wlfc.h>
+#endif
+
+
+#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;
+ 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)
+{
+ 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 */
+ err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len);
+
+ DHD_OS_WAKE_UNLOCK(dhd);
+ return err;
+}
+
+static int
+dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
+{
+ int ret;
+ int cdc_len = len + sizeof(cdc_ioctl_t);
+ dhd_prot_t *prot = dhd->prot;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ do {
+ ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len);
+ if (ret < 0)
+ break;
+ } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id);
+
+ 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__, *(char *)buf));
+ }
+
+ 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);
+
+ 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;
+ }
+
+ /* Check the ERROR flag */
+ if (flags & CDCF_IOC_ERROR)
+ {
+ ret = ltoh32(msg->status);
+ /* Cache error from dongle */
+ dhd->dongle_error = ret;
+ }
+
+done:
+ return ret;
+}
+
+
+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;
+
+ if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) {
+ DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
+ 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", (char*)buf));
+ }
+ 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);
+ }
+
+ /* 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);
+
+ }
+#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 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;
+
+
+ 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/drivers/net/wireless/bcmdhd_1363/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd_1363/dhd_cfg80211.c
new file mode 100644
index 000000000000..fb35e6fcb7ae
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_cfg80211.c
@@ -0,0 +1,266 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_cfg80211.c 642340 2016-06-08 09:44:13Z $
+ */
+
+#include <linux/vmalloc.h>
+#include <net/rtnetlink.h>
+
+#include <bcmutils.h>
+#include <wldev_common.h>
+#include <wl_cfg80211.h>
+#include <dhd_cfg80211.h>
+
+#ifdef PKT_FILTER_SUPPORT
+#include <dngl_stats.h>
+#include <dhd.h>
+#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 <dngl_stats.h>
+#include <dhd.h>
+#include <dhdioctl.h>
+#include <wlioctl.h>
+#include <brcm_nl80211.h>
+#include <dhd_cfg80211.h>
+
+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, char *name,
+ uint8 *mac, uint8 bssidx, 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)
+{
+ return dhd_register_if(cfg->pub, ifidx, FALSE);
+}
+
+int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev)
+{
+ return dhd_remove_if(cfg->pub, ifidx, FALSE);
+}
+
+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 up = 0;
+
+ err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_UP error (%d)\n", err));
+ }
+ return err;
+}
+
+static s32
+wl_dongle_down(struct net_device *ndev)
+{
+ s32 err = 0;
+ u32 down = 0;
+
+ err = wldev_ioctl(ndev, WLC_DOWN, &down, sizeof(down), true);
+ 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 };
+ 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;
+ 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/drivers/net/wireless/bcmdhd_1363/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd_1363/dhd_cfg80211.h
new file mode 100644
index 000000000000..ca86f686d8e8
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_cfg80211.h 591285 2015-10-07 11:56:29Z $
+ */
+
+
+#ifndef __DHD_CFG80211__
+#define __DHD_CFG80211__
+
+#include <wl_cfg80211.h>
+#include <wl_cfgp2p.h>
+#include <brcm_nl80211.h>
+
+#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/drivers/net/wireless/bcmdhd_1363/dhd_cfg_vendor.c b/drivers/net/wireless/bcmdhd_1363/dhd_cfg_vendor.c
new file mode 100644
index 000000000000..4ba3827d421a
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_cfg_vendor.c
@@ -0,0 +1,174 @@
+/*
+ * Linux cfg80211 vendor command/event handlers of DHD
+ *
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_cfg_vendor.c 525516 2015-01-09 23:12:53Z $
+ */
+
+#include <linux/vmalloc.h>
+#include <linuxver.h>
+#include <net/cfg80211.h>
+#include <net/netlink.h>
+
+#include <bcmutils.h>
+#include <wl_cfg80211.h>
+#include <wl_cfgvendor.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_dbg.h>
+#include <dhdioctl.h>
+#include <brcm_nl80211.h>
+
+#ifdef VENDOR_EXT_SUPPORT
+static int dhd_cfgvendor_priv_string_handler(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ const struct bcm_nlmsg_hdr *nlioc = data;
+ struct net_device *ndev = NULL;
+ struct bcm_cfg80211 *cfg;
+ struct sk_buff *reply;
+ void *buf = NULL, *cur;
+ dhd_pub_t *dhd;
+ dhd_ioctl_t ioc = { 0 };
+ int ret = 0, ret_len, payload, msglen;
+ int maxmsglen = PAGE_SIZE - 0x100;
+ int8 index;
+
+ WL_TRACE(("entry: cmd = %d\n", nlioc->cmd));
+ DHD_ERROR(("entry: cmd = %d\n", nlioc->cmd));
+
+ cfg = wiphy_priv(wiphy);
+ 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);
+ }
+
+ len -= sizeof(struct bcm_nlmsg_hdr);
+ ret_len = nlioc->len;
+ if (ret_len > 0 || len > 0) {
+ if (len > DHD_IOCTL_MAXLEN) {
+ WL_ERR(("oversize input buffer %d\n", len));
+ len = DHD_IOCTL_MAXLEN;
+ }
+ if (ret_len > DHD_IOCTL_MAXLEN) {
+ WL_ERR(("oversize return buffer %d\n", ret_len));
+ ret_len = DHD_IOCTL_MAXLEN;
+ }
+ payload = max(ret_len, len) + 1;
+ buf = vzalloc(payload);
+ if (!buf) {
+ DHD_OS_WAKE_UNLOCK(dhd);
+ return -ENOMEM;
+ }
+ memcpy(buf, (void *)nlioc + nlioc->offset, len);
+ *(char *)(buf + len) = '\0';
+ }
+
+ 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;
+ 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;
+ }
+
+ cur = buf;
+ while (ret_len > 0) {
+ msglen = nlioc->len > maxmsglen ? maxmsglen : ret_len;
+ ret_len -= msglen;
+ payload = msglen + sizeof(msglen);
+ reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
+ if (!reply) {
+ WL_ERR(("Failed to allocate reply msg\n"));
+ ret = -ENOMEM;
+ break;
+ }
+
+ if (nla_put(reply, BCM_NLATTR_DATA, msglen, cur) ||
+ nla_put_u16(reply, BCM_NLATTR_LEN, msglen)) {
+ kfree_skb(reply);
+ ret = -ENOBUFS;
+ break;
+ }
+
+ ret = cfg80211_vendor_cmd_reply(reply);
+ if (ret) {
+ WL_ERR(("testmode reply failed:%d\n", ret));
+ break;
+ }
+ cur += msglen;
+ }
+
+done:
+ vfree(buf);
+ DHD_OS_WAKE_UNLOCK(dhd);
+ return ret;
+}
+
+const struct wiphy_vendor_command dhd_cfgvendor_cmds [] = {
+ {
+ {
+ .vendor_id = OUI_BRCM,
+ .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = dhd_cfgvendor_priv_string_handler
+ },
+};
+
+int cfgvendor_attach(struct wiphy *wiphy)
+{
+ wiphy->vendor_commands = dhd_cfgvendor_cmds;
+ wiphy->n_vendor_commands = ARRAY_SIZE(dhd_cfgvendor_cmds);
+
+ return 0;
+}
+
+int cfgvendor_detach(struct wiphy *wiphy)
+{
+ wiphy->vendor_commands = NULL;
+ wiphy->n_vendor_commands = 0;
+
+ return 0;
+}
+#endif /* VENDOR_EXT_SUPPORT */
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_common.c b/drivers/net/wireless/bcmdhd_1363/dhd_common.c
new file mode 100644
index 000000000000..79226f8030db
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_common.c
@@ -0,0 +1,4154 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_common.c 665079 2017-05-18 10:09:58Z $
+ */
+#include <typedefs.h>
+#include <osl.h>
+
+#include <epivers.h>
+#include <bcmutils.h>
+
+#include <bcmendian.h>
+#include <dngl_stats.h>
+#include <wlioctl.h>
+#include <dhd.h>
+#include <dhd_ip.h>
+#include <proto/bcmevent.h>
+
+#ifdef SHOW_LOGTRACE
+#include <event_log.h>
+#endif /* SHOW_LOGTRACE */
+
+#ifdef BCMPCIE
+#include <dhd_flowring.h>
+#endif
+
+#include <dhd_bus.h>
+#include <dhd_proto.h>
+#include <dhd_dbg.h>
+#include <msgtrace.h>
+
+#ifdef WL_CFG80211
+#include <wl_cfg80211.h>
+#endif
+#ifdef PNO_SUPPORT
+#include <dhd_pno.h>
+#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 <wlfc_proto.h>
+#include <dhd_wlfc.h>
+#endif
+
+#ifdef DHD_WMF
+#include <dhd_linux.h>
+#include <dhd_wmf_linux.h>
+#endif /* DHD_WMF */
+
+#ifdef DHD_L2_FILTER
+#include <dhd_l2_filter.h>
+#endif /* DHD_L2_FILTER */
+
+#ifdef DHD_PSTA
+#include <dhd_psta.h>
+#endif /* DHD_PSTA */
+
+
+#ifdef WLMEDIA_HTSF
+extern void htsf_update(struct dhd_info *dhd, void *data);
+#endif
+
+#ifdef DHD_LOG_DUMP
+int dhd_msg_level = DHD_ERROR_VAL | DHD_MSGTRACE_VAL | DHD_FWLOG_VAL | DHD_EVENT_VAL;
+#else
+int dhd_msg_level = DHD_ERROR_VAL | DHD_MSGTRACE_VAL | DHD_FWLOG_VAL;
+#endif /* DHD_LOG_DUMP */
+
+
+#if defined(WL_WLC_SHIM)
+#include <wl_shim.h>
+#else
+#endif /* WL_WLC_SHIM */
+
+#if defined(WL_WIRELESS_EXT)
+#include <wl_iw.h>
+#endif
+
+#ifdef SOFTAP
+char fw_path2[MOD_PARAM_PATHLEN];
+extern bool softap_enabled;
+#endif
+
+/* Last connection success/failure status */
+uint32 dhd_conn_event;
+uint32 dhd_conn_status;
+uint32 dhd_conn_reason;
+
+#if defined(SHOW_EVENTS) && defined(SHOW_LOGTRACE)
+static int check_event_log_sequence_number(uint32 seq_no);
+#endif /* defined(SHOW_EVENTS) && defined(SHOW_LOGTRACE) */
+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);
+
+#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
+#else
+#define DHD_COMPILED ""
+#endif /* DHD_DEBUG */
+
+#if defined(DHD_VERSION_NO_DATE_TIME)
+const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR DHD_COMPILED;
+#else
+#if defined(DHD_DEBUG)
+const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR
+ DHD_COMPILED " on " __DATE__ " at " __TIME__;
+#else
+const char dhd_version[] = "\nDongle Host Driver, version " EPI_VERSION_STR "\nCompiled from ";
+#endif
+#endif /* DHD_VERSION_NO_DATE_TIME */
+char fw_version[FW_VER_STR_LEN] = "\0";
+char clm_version[CLM_VER_STR_LEN] = "\0";
+
+void dhd_set_timer(void *bus, uint wdtick);
+
+
+
+/* IOVar table */
+enum {
+ IOV_VERSION = 1,
+ IOV_MSGLEVEL,
+ IOV_BCMERRORSTR,
+ IOV_BCMERROR,
+ IOV_WDTICK,
+ IOV_DUMP,
+ IOV_CLEARCOUNTS,
+ IOV_LOGDUMP,
+ IOV_LOGCAL,
+ IOV_LOGSTAMP,
+ IOV_GPIOOB,
+ IOV_IOCTLTIMEOUT,
+#if defined(DHD_DEBUG)
+ IOV_CONS,
+ IOV_DCONSOLE_POLL,
+ IOV_DHD_JOIN_TIMEOUT_DBG,
+ IOV_SCAN_TIMEOUT,
+#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 */
+#endif /* DHD_WMF */
+ IOV_AP_ISOLATE,
+#ifdef DHD_L2_FILTER
+ IOV_DHCP_UNICAST,
+ IOV_BLOCK_PING,
+ IOV_PROXY_ARP,
+ IOV_GRAT_ARP,
+#endif /* DHD_L2_FILTER */
+#ifdef DHD_PSTA
+ IOV_PSTA,
+#endif /* DHD_PSTA */
+ IOV_CFG80211_OPMODE,
+ IOV_ASSERT_TYPE,
+ IOV_LMTEST,
+ IOV_LAST
+};
+
+const bcm_iovar_t dhd_iovars[] = {
+ {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) },
+#ifdef DHD_DEBUG
+ {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 },
+#endif /* DHD_DEBUG */
+ {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN },
+ {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 },
+ {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 },
+ {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
+#ifdef DHD_DEBUG
+ {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 },
+ {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 },
+#endif
+ {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 },
+ {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 },
+ {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 },
+#ifdef PROP_TXSTATUS
+ {"proptx", IOV_PROPTXSTATUS_ENABLE, 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, IOVT_UINT32, 0 },
+ {"proptx_opt", IOV_PROPTXSTATUS_OPT, 0, IOVT_UINT32, 0 },
+ {"pmodule_ignore", IOV_PROPTXSTATUS_MODULE_IGNORE, 0, IOVT_BOOL, 0 },
+ {"pcredit_ignore", IOV_PROPTXSTATUS_CREDIT_IGNORE, 0, IOVT_BOOL, 0 },
+ {"ptxstatus_ignore", IOV_PROPTXSTATUS_TXSTATUS_IGNORE, 0, IOVT_BOOL, 0 },
+ {"rxpkt_chk", IOV_PROPTXSTATUS_RXPKT_CHK, 0, IOVT_BOOL, 0 },
+#endif /* PROP_TXSTATUS */
+ {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0},
+#ifdef WLMEDIA_HTSF
+ {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 },
+#endif
+ {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 },
+ {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, IOVT_BUFFER,
+ (WLHOST_REORDERDATA_MAXFLOWS + 1) },
+#ifdef DHDTCPACK_SUPPRESS
+ {"tcpack_suppress", IOV_TCPACK_SUPPRESS, 0, IOVT_UINT8, 0 },
+#endif /* DHDTCPACK_SUPPRESS */
+#ifdef DHD_WMF
+ {"wmf_bss_enable", IOV_WMF_BSS_ENAB, 0, IOVT_BOOL, 0 },
+ {"wmf_ucast_igmp", IOV_WMF_UCAST_IGMP, 0, IOVT_BOOL, 0 },
+ {"wmf_mcast_data_sendup", IOV_WMF_MCAST_DATA_SENDUP, 0, IOVT_BOOL, 0 },
+#ifdef WL_IGMP_UCQUERY
+ {"wmf_ucast_igmp_query", IOV_WMF_UCAST_IGMP_QUERY, (0), IOVT_BOOL, 0 },
+#endif /* WL_IGMP_UCQUERY */
+#ifdef DHD_UCAST_UPNP
+ {"wmf_ucast_upnp", IOV_WMF_UCAST_UPNP, (0), IOVT_BOOL, 0 },
+#endif /* DHD_UCAST_UPNP */
+#endif /* DHD_WMF */
+#ifdef DHD_L2_FILTER
+ {"dhcp_unicast", IOV_DHCP_UNICAST, (0), IOVT_BOOL, 0 },
+#endif /* DHD_L2_FILTER */
+ {"ap_isolate", IOV_AP_ISOLATE, (0), IOVT_BOOL, 0},
+#ifdef DHD_L2_FILTER
+ {"block_ping", IOV_BLOCK_PING, (0), IOVT_BOOL, 0},
+ {"proxy_arp", IOV_PROXY_ARP, (0), IOVT_BOOL, 0},
+ {"grat_arp", IOV_GRAT_ARP, (0), IOVT_BOOL, 0},
+#endif /* DHD_L2_FILTER */
+#ifdef DHD_PSTA
+ /* PSTA/PSR Mode configuration. 0: DIABLED 1: PSTA 2: PSR */
+ {"psta", IOV_PSTA, 0, IOVT_UINT32, 0},
+#endif /* DHD PSTA */
+ {"op_mode", IOV_CFG80211_OPMODE, 0, IOVT_UINT32, 0 },
+ {"assert_type", IOV_ASSERT_TYPE, (0), IOVT_UINT32, 0},
+ {"lmtest", IOV_LMTEST, 0, IOVT_UINT32, 0 },
+ {NULL, 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 (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_FW_COREDUMP
+void dhd_save_fwdump(dhd_pub_t *dhd_pub, void * buffer, uint32 length)
+{
+ if (dhd_pub->soc_ram) {
+#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP)
+ DHD_OS_PREFREE(dhd_pub, dhd_pub->soc_ram, dhd_pub->soc_ram_length);
+#else
+ MFREE(dhd_pub->osh, dhd_pub->soc_ram, dhd_pub->soc_ram_length);
+#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */
+ dhd_pub->soc_ram = NULL;
+ dhd_pub->soc_ram_length = 0;
+ }
+
+#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);
+ memset(dhd_pub->soc_ram, 0, length);
+#else
+ dhd_pub->soc_ram = (uint8*) MALLOCZ(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->memdump_success = FALSE;
+ return;
+ }
+
+ dhd_pub->soc_ram_length = length;
+ memcpy(dhd_pub->soc_ram, buffer, length);
+}
+#endif /* DHD_FW_COREDUMP */
+
+/* to NDIS developer, the structure dhd_common is redundant,
+ * please do NOT merge it back from other branches !!!
+ */
+
+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");
+
+ /* 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 */
+
+ 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];
+ int ret = -1;
+ int lval = htol32(val);
+
+ /* memset(iovbuf, 0, sizeof(iovbuf)); */
+ if (bcm_mkiovar(name, (char*)&lval, sizeof(lval), iovbuf, sizeof(iovbuf))) {
+ ret = dhd_wl_ioctl_cmd(dhd_pub, cmd, iovbuf, sizeof(iovbuf), 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;
+
+ if (dhd_os_proto_block(dhd_pub))
+ {
+#ifdef DHD_LOG_DUMP
+ int slen, i, val, rem, lval;
+ char *pval, *pos, *msg;
+ char tmp[64];
+#endif /* DHD_LOG_DUMP */
+ DHD_GENERAL_LOCK(dhd_pub, flags);
+ if (dhd_pub->busstate == DHD_BUS_DOWN ||
+ dhd_pub->busstate == DHD_BUS_DOWN_IN_PROGRESS) {
+ DHD_ERROR(("%s: returning as busstate=%d\n",
+ __FUNCTION__, dhd_pub->busstate));
+ DHD_GENERAL_UNLOCK(dhd_pub, flags);
+ dhd_os_proto_unblock(dhd_pub);
+ return -ENODEV;
+ }
+ dhd_pub->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_IOVAR;
+ DHD_GENERAL_UNLOCK(dhd_pub, flags);
+
+#ifdef DHD_LOG_DUMP
+ /* WLC_GET_VAR */
+ if (ioc->cmd == WLC_GET_VAR) {
+ memset(tmp, 0, sizeof(tmp));
+ bcopy(ioc->buf, tmp, strlen(ioc->buf) + 1);
+ }
+#endif /* DHD_LOG_DUMP */
+#ifdef DHD_PCIE_RUNTIMEPM
+ dhdpcie_runtime_bus_wake(dhd_pub, TRUE, dhd_wl_ioctl);
+#endif /* DHD_PCIE_RUNTIMEPM */
+#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
+ ret = dhd_prot_ioctl(dhd_pub, ifidx, ioc, buf, len);
+#endif /* defined(WL_WLC_SHIM) */
+
+ 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;
+ }
+
+ DHD_GENERAL_LOCK(dhd_pub, flags);
+ dhd_pub->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_IOVAR;
+ dhd_os_busbusy_wake(dhd_pub);
+ DHD_GENERAL_UNLOCK(dhd_pub, flags);
+
+ dhd_os_proto_unblock(dhd_pub);
+
+#ifdef DHD_LOG_DUMP
+ if (ioc->cmd == WLC_GET_VAR || ioc->cmd == WLC_SET_VAR) {
+ lval = 0;
+ slen = strlen(ioc->buf) + 1;
+ msg = (char*)ioc->buf;
+ if (ioc->cmd == WLC_GET_VAR) {
+ msg = tmp;
+ } else {
+ int min_len = MIN(ioc->len - slen, sizeof(int));
+ bcopy((msg + slen), &lval, min_len);
+ }
+ DHD_ERROR_EX(("%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 (ioc->buf != NULL) {
+ val = *(int*)ioc->buf;
+ pval = (char*)ioc->buf;
+ pos = tmp;
+ rem = sizeof(tmp);
+ memset(tmp, 0, sizeof(tmp));
+ for (i = 0; i < slen; i++) {
+ pos += snprintf(pos, rem, "%02x ", pval[i]);
+ rem = sizeof(tmp) - (int)(pos - tmp);
+ if (rem <= 0) {
+ break;
+ }
+ }
+ DHD_ERROR_EX(("WLC_IOCTL: cmd: %d, val: %d(%s), len: %d, set: %d\n",
+ ioc->cmd, val, tmp, ioc->len, ioc->set));
+ } else {
+ DHD_ERROR_EX(("WLC_IOCTL: cmd: %d, buf is NULL\n", ioc->cmd));
+ }
+ }
+#endif /* DHD_LOG_DUMP */
+ }
+
+ 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, char *params, int *idx, char **val)
+{
+ char *prefix = "bsscfg:";
+ uint32 bssidx;
+
+ if (!(strncmp(params, prefix, strlen(prefix)))) {
+ /* per bss setting should be prefixed with 'bsscfg:' */
+ char *p = (char *)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(BCMDHDUSB)
+/* 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, 1);
+
+}
+#endif /* DHD_DEBUG && BCMDHDUSB */
+
+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;
+
+ 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 */
+ bcm_strncpy_s((char*)arg, len, dhd_version, len);
+ break;
+
+ case IOV_GVAL(IOV_MSGLEVEL):
+ int_val = (int32)dhd_msg_level;
+ bcopy(&int_val, arg, val_size);
+ break;
+
+ case IOV_SVAL(IOV_MSGLEVEL):
+#ifdef WL_CFG80211
+ /* Enable DHD and WL logs in oneshot */
+ if (int_val & DHD_WL_VAL2)
+ wl_cfg80211_enable_trace(TRUE, int_val & (~DHD_WL_VAL2));
+ else if (int_val & DHD_WL_VAL)
+ wl_cfg80211_enable_trace(FALSE, WL_DBG_DBG);
+ if (!(int_val & DHD_WL_VAL2))
+#endif /* WL_CFG80211 */
+ 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;
+
+ case IOV_GVAL(IOV_WDTICK):
+ int_val = (int32)dhd_watchdog_ms;
+ bcopy(&int_val, arg, val_size);
+ break;
+
+ 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;
+
+#ifdef DHD_DEBUG
+ 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)
+ bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1);
+ break;
+#endif /* DHD_DEBUG */
+
+ 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 */
+ DHD_LB_STATS_RESET(dhd_pub);
+ 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 BCMDHDUSB
+ int_val = BUS_TYPE_USB;
+#endif
+#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;
+ char *val;
+
+ if (dhd_iovar_parse_bssidx(dhd_pub, (char *)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;
+ char *val;
+
+ if (dhd_iovar_parse_bssidx(dhd_pub, (char *)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 */
+#endif /* DHD_WMF */
+
+
+#ifdef DHD_L2_FILTER
+ case IOV_GVAL(IOV_DHCP_UNICAST): {
+ uint32 bssidx;
+ char *val;
+ if (dhd_iovar_parse_bssidx(dhd_pub, (char *)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;
+ char *val;
+ if (dhd_iovar_parse_bssidx(dhd_pub, (char *)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;
+ char *val;
+
+ if (dhd_iovar_parse_bssidx(dhd_pub, (char *)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;
+ char *val;
+
+ if (dhd_iovar_parse_bssidx(dhd_pub, (char *)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;
+ char *val;
+
+ if (dhd_iovar_parse_bssidx(dhd_pub, (char *)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;
+ char *val;
+ char iobuf[32];
+
+ if (dhd_iovar_parse_bssidx(dhd_pub, (char *)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.
+ */
+ bcm_mkiovar("proxy_arp_advertise", val, sizeof(int_val), iobuf,
+ sizeof(iobuf));
+ bcmerror = dhd_wl_ioctl_cmd(dhd_pub, WLC_SET_VAR, iobuf,
+ sizeof(iobuf), TRUE, bssidx);
+
+ if (bcmerror == BCME_OK) {
+ dhd_set_parp_status(dhd_pub, bssidx, int_val ? 1 : 0);
+ }
+ break;
+ }
+ case IOV_GVAL(IOV_GRAT_ARP): {
+ uint32 bssidx;
+ char *val;
+
+ if (dhd_iovar_parse_bssidx(dhd_pub, (char *)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;
+ char *val;
+
+ if (dhd_iovar_parse_bssidx(dhd_pub, (char *)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_GVAL(IOV_AP_ISOLATE): {
+ uint32 bssidx;
+ 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_ap_isolate(dhd_pub, bssidx);
+ bcopy(&int_val, arg, val_size);
+ break;
+ }
+ case IOV_SVAL(IOV_AP_ISOLATE): {
+ uint32 bssidx;
+ 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_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 */
+ 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;
+
+
+ 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;
+ }
+
+ 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_GENERAL_LOCK(dhd_pub, flags);
+ if (dhd_pub->busstate == DHD_BUS_DOWN ||
+ dhd_pub->busstate == DHD_BUS_DOWN_IN_PROGRESS) {
+ /* 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_pub->is_fw_download_done) {
+ DHD_ERROR(("%s: returning as busstate=%d\n",
+ __FUNCTION__, dhd_pub->busstate));
+ DHD_GENERAL_UNLOCK(dhd_pub, flags);
+ dhd_os_dhdiovar_unlock(dhd_pub);
+ return -ENODEV;
+ }
+ }
+ dhd_pub->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_DHD_IOVAR;
+ DHD_GENERAL_UNLOCK(dhd_pub, flags);
+#ifdef DHD_PCIE_RUNTIMEPM
+ dhdpcie_runtime_bus_wake(dhd_pub, TRUE, dhd_ioctl);
+#endif /* DHD_PCIE_RUNTIMEPM */
+
+ /* 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);
+ }
+ }
+ goto unlock_exit;
+
+ default:
+ bcmerror = BCME_UNSUPPORTED;
+ }
+ dhd_os_dhdiovar_unlock(dhd_pub);
+ return bcmerror;
+
+unlock_exit:
+ DHD_GENERAL_LOCK(dhd_pub, flags);
+ dhd_pub->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_DHD_IOVAR;
+ dhd_os_busbusy_wake(dhd_pub);
+ DHD_GENERAL_UNLOCK(dhd_pub, flags);
+ dhd_os_dhdiovar_unlock(dhd_pub);
+ return bcmerror;
+}
+
+#ifdef SHOW_EVENTS
+#ifdef SHOW_LOGTRACE
+
+#define MAX_NO_OF_ARG 16
+
+#define FMTSTR_SIZE 132
+#define SIZE_LOC_STR 50
+#define MIN_DLEN 4
+#define TAG_BYTES 12
+#define TAG_WORDS 3
+#define ROMSTR_SIZE 200
+
+
+static int
+check_event_log_sequence_number(uint32 seq_no)
+{
+ int32 diff;
+ uint32 ret;
+ static uint32 logtrace_seqnum_prev = 0;
+
+ diff = ntoh32(seq_no)-logtrace_seqnum_prev;
+ switch (diff)
+ {
+ case 0:
+ ret = -1; /* duplicate packet . drop */
+ break;
+
+ case 1:
+ ret =0; /* in order */
+ break;
+
+ default:
+ if ((ntoh32(seq_no) == 0) &&
+ (logtrace_seqnum_prev == 0xFFFFFFFF) ) { /* in-order - Roll over */
+ ret = 0;
+ } else {
+
+ if (diff > 0) {
+ DHD_EVENT(("WLC_E_TRACE:"
+ "Event lost (log) seqnum %d nblost %d\n",
+ ntoh32(seq_no), (diff-1)));
+ } else {
+ DHD_EVENT(("WLC_E_TRACE:"
+ "Event Packets coming out of order!!\n"));
+ }
+ ret = 0;
+ }
+ }
+
+ logtrace_seqnum_prev = ntoh32(seq_no);
+
+ return ret;
+}
+
+static void
+dhd_eventmsg_print(dhd_pub_t *dhd_pub, void *event_data, void *raw_event_ptr,
+ uint datalen, const char *event_name)
+{
+ msgtrace_hdr_t hdr;
+ uint32 nblost;
+ uint8 count;
+ char *s, *p;
+ static uint32 seqnum_prev = 0;
+ uint32 *log_ptr = NULL;
+ uchar *buf;
+ event_log_hdr_t event_hdr;
+ uint32 i;
+ int32 j;
+
+ dhd_event_log_t *raw_event = (dhd_event_log_t *) raw_event_ptr;
+
+ char fmtstr_loc_buf[FMTSTR_SIZE] = {0};
+ char (*str_buf)[SIZE_LOC_STR] = NULL;
+ char * str_tmpptr = NULL;
+ uint32 addr = 0;
+ uint32 **hdr_ptr = NULL;
+ uint32 h_i = 0;
+ uint32 hdr_ptr_len = 0;
+
+ typedef union {
+ uint32 val;
+ char * addr;
+ } u_arg;
+ u_arg arg[MAX_NO_OF_ARG] = {{0}};
+ char *c_ptr = NULL;
+ char rom_log_str[ROMSTR_SIZE] = {0};
+ uint32 rom_str_len = 0;
+
+ BCM_REFERENCE(arg);
+
+ if (!DHD_FWLOG_ON())
+ return;
+
+ buf = (uchar *) event_data;
+ memcpy(&hdr, buf, MSGTRACE_HDRLEN);
+
+ if (hdr.version != MSGTRACE_VERSION) {
+ DHD_EVENT(("\nMACEVENT: %s [unsupported version --> "
+ "dhd version:%d dongle version:%d]\n",
+ event_name, MSGTRACE_VERSION, hdr.version));
+ /* Reset datalen to avoid display below */
+ datalen = 0;
+ return;
+ }
+
+ if (hdr.trace_type == MSGTRACE_HDR_TYPE_MSG) {
+ /* There are 2 bytes available at the end of data */
+ buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0';
+
+ if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) {
+ DHD_FWLOG(("WLC_E_TRACE: [Discarded traces in dongle -->"
+ "discarded_bytes %d discarded_printf %d]\n",
+ ntoh32(hdr.discarded_bytes),
+ ntoh32(hdr.discarded_printf)));
+ }
+
+ nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1;
+ if (nblost > 0) {
+ DHD_FWLOG(("WLC_E_TRACE:"
+ "[Event lost (msg) --> seqnum %d nblost %d\n",
+ ntoh32(hdr.seqnum), nblost));
+ }
+ seqnum_prev = ntoh32(hdr.seqnum);
+
+ /* Display the trace buffer. Advance from
+ * \n to \n to avoid display big
+ * printf (issue with Linux printk )
+ */
+ p = (char *)&buf[MSGTRACE_HDRLEN];
+ while (*p != '\0' && (s = strstr(p, "\n")) != NULL) {
+ *s = '\0';
+ DHD_FWLOG(("[FWLOG] %s\n", p));
+ p = s+1;
+ }
+ if (*p)
+ DHD_FWLOG(("[FWLOG] %s", p));
+
+ /* Reset datalen to avoid display below */
+ datalen = 0;
+
+ } else if (hdr.trace_type == MSGTRACE_HDR_TYPE_LOG) {
+ /* Let the standard event printing work for now */
+ uint32 timestamp, seq, pktlen;
+
+ if (check_event_log_sequence_number(hdr.seqnum)) {
+
+ DHD_EVENT(("%s: WLC_E_TRACE:"
+ "[Event duplicate (log) %d] dropping!!\n",
+ __FUNCTION__, hdr.seqnum));
+ return; /* drop duplicate events */
+ }
+
+ p = (char *)&buf[MSGTRACE_HDRLEN];
+ datalen -= MSGTRACE_HDRLEN;
+ pktlen = ltoh16(*((uint16 *)p));
+ seq = ltoh16(*((uint16 *)(p + 2)));
+ p += MIN_DLEN;
+ datalen -= MIN_DLEN;
+ timestamp = ltoh32(*((uint32 *)p));
+ BCM_REFERENCE(pktlen);
+ BCM_REFERENCE(seq);
+ BCM_REFERENCE(timestamp);
+
+ /*
+ * Allocating max possible number of event TAGs in the received buffer
+ * considering that each event requires minimum of TAG_BYTES.
+ */
+ hdr_ptr_len = ((datalen/TAG_BYTES)+1) * sizeof(uint32*);
+
+ if ((raw_event->fmts)) {
+ if (!(str_buf = MALLOCZ(dhd_pub->osh, (MAX_NO_OF_ARG * SIZE_LOC_STR)))) {
+ DHD_ERROR(("%s: malloc failed str_buf \n", __FUNCTION__));
+ }
+ }
+
+ if (!(hdr_ptr = MALLOCZ(dhd_pub->osh, hdr_ptr_len))) {
+ DHD_ERROR(("%s: malloc failed hdr_ptr \n", __FUNCTION__));
+ }
+
+
+ DHD_MSGTRACE_LOG(("EVENT_LOG_HDR[No.%d]: timestamp 0x%08x length = %d\n",
+ seq, timestamp, pktlen));
+
+ /* (raw_event->fmts) has value */
+
+ log_ptr = (uint32 *) (p + datalen);
+
+ /* Store all hdr pointer while parsing from last of the log buffer
+ * sample format of
+ * 001d3c54 00000064 00000064 001d3c54 001dba08 035d6ce1 0c540639
+ * 001d3c54 00000064 00000064 035d6d89 0c580439
+ * in above example 0c580439 -- 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 parse only from last to first
+ */
+
+ while (datalen > MIN_DLEN) {
+ log_ptr--;
+ datalen -= MIN_DLEN;
+ event_hdr.t = *log_ptr;
+ /*
+ * Check for partially overriten entries
+ */
+ if (log_ptr - (uint32 *) p < event_hdr.count) {
+ break;
+ }
+ /*
+ * Check argument count (only when format is valid)
+ */
+ if ((event_hdr.count > MAX_NO_OF_ARG) &&
+ (event_hdr.fmt_num != 0xffff)) {
+ break;
+ }
+ /*
+ * Check for end of the Frame.
+ */
+ if (event_hdr.tag == EVENT_LOG_TAG_NULL) {
+ continue;
+ }
+ log_ptr[0] = event_hdr.t;
+ if (h_i < (hdr_ptr_len / sizeof(uint32*))) {
+ hdr_ptr[h_i++] = log_ptr;
+ }
+
+ /* Now place the header at the front
+ * and copy back.
+ */
+ log_ptr -= event_hdr.count;
+
+ c_ptr = NULL;
+ datalen = datalen - (event_hdr.count * MIN_DLEN);
+ }
+ datalen = 0;
+
+ /* print all log using stored hdr pointer in reverse order of EL data
+ * which is actually print older log first and then other in order
+ */
+
+ for (j = (h_i-1); j >= 0; j--) {
+ if (!(hdr_ptr[j])) {
+ break;
+ }
+
+ event_hdr.t = *hdr_ptr[j];
+
+ log_ptr = hdr_ptr[j];
+
+ /* Now place the header at the front
+ * and copy back.
+ */
+ log_ptr -= event_hdr.count;
+
+ if (event_hdr.tag == EVENT_LOG_TAG_ROM_PRINTF) {
+
+ rom_str_len = ((event_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(rom_log_str, log_ptr, rom_str_len);
+ /* add end of line at last */
+ rom_log_str[rom_str_len] = '\0';
+
+ DHD_MSGTRACE_LOG(("EVENT_LOG_ROM[0x%08x]: %s",
+ log_ptr[event_hdr.count - 1], rom_log_str));
+
+ /* Add newline if missing */
+ if (rom_log_str[strlen(rom_log_str) - 1] != '\n') {
+ DHD_EVENT(("\n"));
+ }
+
+ memset(rom_log_str, 0, ROMSTR_SIZE);
+
+ continue;
+ }
+
+ /*
+ * Check For Special Time Stamp Packet
+ */
+ if (event_hdr.tag == EVENT_LOG_TAG_TS) {
+ DHD_MSGTRACE_LOG(("EVENT_LOG_TS[0x%08x]: SYS:%08x CPU:%08x\n",
+ log_ptr[event_hdr.count-1], log_ptr[0], log_ptr[1]));
+ continue;
+ }
+
+ /* Simply print out event dump buffer (fmt_num = 0xffff) */
+ if (!str_buf || event_hdr.fmt_num == 0xffff) {
+ /*
+ * Print out raw value if unable to interpret
+ */
+#ifdef DHD_LOG_DUMP
+ char buf[256];
+ char *pos = buf;
+ memset(buf, 0, sizeof(buf));
+ pos += snprintf(pos, 256,
+#else
+ DHD_MSGTRACE_LOG((
+#endif /* DHD_LOG_DUMP */
+ "EVENT_LOG_BUF[0x%08x]: tag=%d len=%d fmt=%04x",
+ log_ptr[event_hdr.count-1], event_hdr.tag,
+ event_hdr.count, event_hdr.fmt_num
+#ifdef DHD_LOG_DUMP
+);
+#else
+));
+#endif /* DHD_LOG_DUMP */
+
+ for (count = 0; count < (event_hdr.count-1); count++) {
+#ifdef DHD_LOG_DUMP
+ if (strlen(buf) >= (256 - 1)) {
+ DHD_MSGTRACE_LOG(("%s\n", buf));
+ memset(buf, 0, sizeof(buf));
+ pos = buf;
+ }
+ pos += snprintf(pos, (256 - (int)(pos-buf)),
+ " %08x", log_ptr[count]);
+#else
+ if (count % 8 == 0)
+ DHD_MSGTRACE_LOG(("\n\t%08x", log_ptr[count]));
+ else
+ DHD_MSGTRACE_LOG((" %08x", log_ptr[count]));
+#endif /* DHD_LOG_DUMP */
+ }
+#ifdef DHD_LOG_DUMP
+ DHD_MSGTRACE_LOG(("%s\n", buf));
+#else
+ DHD_MSGTRACE_LOG(("\n"));
+#endif /* DHD_LOG_DUMP */
+ continue;
+ }
+
+ /* Copy the format string to parse %s and add "EVENT_LOG: */
+ if ((event_hdr.fmt_num >> 2) < raw_event->num_fmts) {
+ snprintf(fmtstr_loc_buf, FMTSTR_SIZE,
+ "EVENT_LOG[0x%08x]: %s", log_ptr[event_hdr.count-1],
+ raw_event->fmts[event_hdr.fmt_num >> 2]);
+ c_ptr = fmtstr_loc_buf;
+ } else {
+ DHD_ERROR(("%s: fmt number out of range \n", __FUNCTION__));
+ continue;
+ }
+
+ for (count = 0; count < (event_hdr.count-1); count++) {
+ if (c_ptr != NULL) {
+ if ((c_ptr = strstr(c_ptr, "%")) != NULL) {
+ c_ptr++;
+ }
+ }
+
+ if ((c_ptr != NULL) && (*c_ptr == 's')) {
+ 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];
+ }
+ }
+
+ DHD_MSGTRACE_LOG((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]));
+
+ if (fmtstr_loc_buf[strlen(fmtstr_loc_buf) - 1] != '\n') {
+ /* Add newline if missing */
+ DHD_MSGTRACE_LOG(("\n"));
+ }
+
+ memset(fmtstr_loc_buf, 0, FMTSTR_SIZE);
+
+ for (i = 0; i < MAX_NO_OF_ARG; i++) {
+ arg[i].addr = 0;
+ }
+ for (i = 0; i < MAX_NO_OF_ARG; i++) {
+ memset(str_buf[i], 0, SIZE_LOC_STR);
+ }
+
+ }
+ DHD_MSGTRACE_LOG(("\n"));
+
+ if (str_buf) {
+ MFREE(dhd_pub->osh, str_buf, (MAX_NO_OF_ARG * SIZE_LOC_STR));
+ }
+
+ if (hdr_ptr) {
+ MFREE(dhd_pub->osh, hdr_ptr, hdr_ptr_len);
+ }
+ }
+}
+
+#endif /* SHOW_LOGTRACE */
+
+#define SDB_ENABLE_AP 0x01
+#define SDB_ENABLE_P2P 0x02
+#define SDB_IS_AP(i) (i & SDB_ENABLE_AP)
+#define SDB_IS_P2P(i) (i & SDB_ENABLE_P2P)
+
+#define WLC_RSDB_MODE_AUTO_MASK 0x80
+#define WLC_RSDB_EXTRACT_MODE(val) ((int8)((val) & (~(WLC_RSDB_MODE_AUTO_MASK))))
+
+static void
+wl_event_sdb_transition_print(void *event_data, const char *event_name)
+{
+ wl_event_sdb_trans_t *rdata;
+ wl_event_sdb_data_t *value;
+ char *sta_mode = "";
+ int i;
+ char chanbuf[CHANSPEC_STR_LEN];
+ rdata = (wl_event_sdb_trans_t *)event_data;
+
+ if (!rdata) {
+ DHD_ERROR(("%s: event_data is NULL\n", __FUNCTION__));
+ return;
+ }
+
+ if (rdata->version != WL_EVENT_SDB_TRANSITION_VER) {
+ DHD_ERROR(("%s: invalid Version(%d)\n", __FUNCTION__, rdata->version));
+ return;
+ }
+
+ if (rdata->rsdb_mode & WLC_RSDB_MODE_AUTO_MASK) {
+ DHD_ERROR((" RSDB Mode : Auto, "));
+ }
+ DHD_ERROR(("Current RSDB Mode : %d\n", WLC_RSDB_EXTRACT_MODE(rdata->rsdb_mode)));
+
+ for (i = 0; i < rdata->enable_bsscfg; i++) {
+ value = &rdata->values[i];
+
+ if (SDB_IS_P2P(value->is_iftype)) {
+ sta_mode = SDB_IS_AP(value->is_iftype) ? "P2P_GO" : "P2P_GC";
+ } else {
+ sta_mode = SDB_IS_AP(value->is_iftype) ? "SoftAP" : "Station";
+ }
+
+ wf_chspec_ntoa_ex(value->chanspec, chanbuf);
+ DHD_ERROR((" wlc%d <%s> \"%s\", %s(0x%04x)\n",
+ value->wlunit, sta_mode,
+ value->ssidbuf, chanbuf, value->chanspec));
+ }
+}
+
+
+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));
+ } else 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:
+ case WLC_E_SCAN_COMPLETE:
+ DHD_EVENT(("MACEVENT: %s\n", event_name));
+ break;
+
+ case WLC_E_PFN_NET_FOUND:
+ case WLC_E_PFN_NET_LOST:
+ case WLC_E_PFN_SCAN_NONE:
+ case WLC_E_PFN_SCAN_ALLGONE:
+ case WLC_E_PFN_GSCAN_FULL_RESULT:
+ case WLC_E_PFN_SWC:
+ 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));
+ 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_eventmsg_print(dhd_pub, event_data, raw_event_ptr, datalen, event_name);
+ 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:
+ {
+#ifndef DHD_IFDEBUG
+ DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d \n",
+ event_name, event_type, eabuf, (int)status));
+#endif
+ }
+ break;
+ case WLC_E_SDB_TRANSITION:
+ DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n",
+ event_name, (int)status, (int)reason));
+ wl_event_sdb_transition_print(event_data, event_name);
+ break;
+ 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++));
+ DHD_EVENT(("\n"));
+ }
+}
+#endif /* SHOW_EVENTS */
+
+/* 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;
+}
+
+
+/* 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_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, size_t 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;
+
+ 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;
+#endif
+
+ 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) {
+ dhd_event_ifdel(dhd_pub->info, ifevent, event->ifname,
+ event->addr.octet);
+ } else if (ifevent->opcode == WLC_E_IF_CHANGE) {
+#ifdef WL_CFG80211
+ wl_cfg80211_notify_ifchange(DHD_GET_CFG80211_PRIV(dhd_pub),
+ ifevent->ifidx, event->ifname, event->addr.octet,
+ ifevent->bssidx);
+#endif /* WL_CFG80211 */
+ }
+ } else {
+#if !defined(PROP_TXSTATUS) && !defined(PCIE_FULL_DONGLE) && defined(WL_CFG80211)
+ DHD_ERROR(("%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
+ /* 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;
+#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
+ case WLC_E_LINK:
+#ifdef PCIE_FULL_DONGLE
+ if (dhd_update_interface_link_status(dhd_pub, (uint8)dhd_ifname2idx(dhd_pub->info,
+ event->ifname), (uint8)flags) != BCME_OK)
+ break;
+ if (!flags) {
+ dhd_flow_rings_delete(dhd_pub, (uint8)dhd_ifname2idx(dhd_pub->info,
+ event->ifname));
+ }
+ /* fall through */
+#endif
+ case WLC_E_DEAUTH:
+ case WLC_E_DEAUTH_IND:
+ case WLC_E_DISASSOC:
+ case WLC_E_DISASSOC_IND:
+ DHD_EVENT(("%s: Link event %d, flags %x, status %x\n",
+ __FUNCTION__, type, flags, status));
+#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_GET_CFG80211_PRIV(dhd_pub)) &&
+ !wl_cfg80211_is_event_from_connected_bssid(
+ DHD_GET_CFG80211_PRIV(dhd_pub), event, *ifidx)) {
+ del_sta = FALSE;
+ }
+#endif /* WL_CFG80211 */
+
+ if (del_sta) {
+ dhd_del_sta(dhd_pub, dhd_ifname2idx(dhd_pub->info,
+ event->ifname), &event->addr.octet);
+ if (role == WLC_E_IF_ROLE_STA) {
+ dhd_flow_rings_delete(dhd_pub, ifindex);
+ } else {
+ dhd_flow_rings_delete_for_peer(dhd_pub, ifindex,
+ &event->addr.octet[0]);
+ }
+ }
+ }
+#endif /* PCIE_FULL_DONGLE */
+ /* fall through */
+ default:
+ *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
+ /* 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;
+ }
+
+#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 (BCME_OK);
+}
+
+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
+
+#ifdef PKT_FILTER_SUPPORT
+/* Convert user's input in hex pattern to byte-size mask */
+static 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;
+}
+
+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));
+
+ /* 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_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
+ __FUNCTION__, arg, rc));
+ else
+ DHD_TRACE(("%s: successfully added pktfilter %s\n",
+ __FUNCTION__, 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 add pktfilter %s, retcode = %d\n",
+ __FUNCTION__, arg, 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;
+ }
+
+ 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 (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_TRACE(("%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));
+ }
+}
+#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_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n",
+ __FUNCTION__, arp_mode, retcode));
+ else
+ DHD_TRACE(("%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_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n",
+ __FUNCTION__, arp_enable, retcode));
+ else
+ DHD_TRACE(("%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;
+ int iov_len = 0;
+ char iovbuf[DHD_IOVAR_BUF_SIZE];
+
+ if (dhd == NULL) return;
+ if (dhd->arp_version == 1)
+ idx = 0;
+
+ iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf));
+ if (!iov_len) {
+ DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
+ __FUNCTION__, sizeof(iovbuf)));
+ return;
+ }
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 0)
+ DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
+}
+
+void
+dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx)
+{
+ int ret = 0;
+ int iov_len = 0;
+ char iovbuf[DHD_IOVAR_BUF_SIZE];
+
+ if (dhd == NULL) return;
+ if (dhd->arp_version == 1)
+ idx = 0;
+
+ iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf));
+ if (!iov_len) {
+ DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
+ __FUNCTION__, sizeof(iovbuf)));
+ return;
+ }
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 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 iov_len = 0;
+ char iovbuf[DHD_IOVAR_BUF_SIZE];
+ int retcode;
+
+
+ if (dhd == NULL) return;
+ if (dhd->arp_version == 1)
+ idx = 0;
+ iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr,
+ sizeof(ipaddr), iovbuf, sizeof(iovbuf));
+ if (!iov_len) {
+ DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
+ __FUNCTION__, sizeof(iovbuf)));
+ return;
+ }
+ retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
+
+ if (retcode)
+ DHD_TRACE(("%s: ARP ip addr add failed, retcode = %d\n",
+ __FUNCTION__, retcode));
+ else
+ DHD_TRACE(("%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 retcode, i;
+ int iov_len;
+ uint32 *ptr32 = buf;
+ bool clr_bottom = FALSE;
+
+ if (!buf)
+ return -1;
+ if (dhd == NULL) return -1;
+ if (dhd->arp_version == 1)
+ idx = 0;
+
+ iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen);
+ BCM_REFERENCE(iov_len);
+ retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, idx);
+
+ if (retcode) {
+ DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n",
+ __FUNCTION__, retcode));
+
+ 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];
+ 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];
+ 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;
+}
+
+
+
+/*
+ * 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 */
+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 eixt */
+ 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));
+ }
+ }
+
+ 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;
+}
+
+/* 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};
+ 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 = CUSTOM_KEEP_ALIVE_SETTING;
+ 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) */
+#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(WL_WIRELESS_EXT) || !defined(WL_SCHED_SCAN)
+
+#define PFN_SCAN_TLV_SSID_IE 'S'
+/*
+ * SSIDs list parsing from PFN scan tlv list
+ */
+int
+wl_iw_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] != PFN_SCAN_TLV_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;
+
+ 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;
+}
+
+#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 {
+ return ret;
+ }
+#endif
+ /* 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) {
+ 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 */
+ len = dhd_os_get_image_block(buf, file_len, image);
+ if ((len <= 0 || len > file_len)) {
+ MFREE(dhd->osh, buf, file_len);
+ goto err;
+ }
+ }
+
+ ret = BCME_OK;
+ *length = len;
+ *buffer = 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;
+ }
+ }
+#endif
+
+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 = len + 8 - (len%8);
+
+ iovar_len = bcm_mkiovar(iovar, 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_clm_blob(dhd_pub_t *dhd, unsigned char *buf, uint32 len)
+{
+ int chunk_len, cumulative_len = 0;
+ 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;
+
+ if ((new_buf = (unsigned char *)MALLOCZ(dhd->osh, size2alloc)) != NULL) {
+ do {
+ if (len >= MAX_CHUNK_LEN)
+ chunk_len = MAX_CHUNK_LEN;
+ else
+ chunk_len = len;
+
+ memcpy(new_buf + data_offset, buf + cumulative_len, chunk_len);
+ cumulative_len += chunk_len;
+
+ if (len - chunk_len == 0)
+ dl_flag |= DL_END;
+
+ err = dhd_download_2_dongle(dhd, "clmload", dl_flag, DL_TYPE_CLM,
+ new_buf, data_offset + chunk_len);
+
+ dl_flag &= ~DL_BEGIN;
+
+ len = len - chunk_len;
+ } while ((len > 0) && (err == 0));
+
+ MFREE(dhd->osh, new_buf, size2alloc);
+ } else {
+ err = BCME_NOMEM;
+ }
+
+ return err;
+}
+
+int
+dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path)
+{
+ char *clm_blob_path;
+ int len;
+ char *memblock = NULL;
+ int err = BCME_OK;
+ char iovbuf[WLC_IOCTL_SMLEN];
+ wl_country_t *cspec;
+
+ if (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.
+ */
+ len = MAX_CLM_BUF_SIZE;
+ dhd_get_download_buffer(dhd, clm_blob_path, CLM_BLOB, &memblock, &len);
+ if ((len > 0) && (len < MAX_CLM_BUF_SIZE) && memblock) {
+ 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__));
+ goto exit;
+ }
+
+ cspec = (wl_country_t *)iovbuf;
+ if ((strncmp(cspec->ccode, WL_CCODE_NULL_COUNTRY, WLC_CNTRY_BUF_SZ)) != 0) {
+ DHD_ERROR(("%s: CLM already exist in F/W, "
+ "new CLM data will be added to the end of existing CLM data!\n",
+ __FUNCTION__));
+ }
+
+ /* Found blob file. Download the file */
+ DHD_TRACE(("clm file download from %s \n", clm_blob_path));
+ err = dhd_download_clm_blob(dhd, memblock, len);
+ 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)));
+ }
+ 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, memblock));
+#ifdef DHD_USE_CLMINFO_PARSER
+ err = BCME_ERROR;
+ goto exit;
+#endif /* DHD_USE_CLMINFO_PARSER */
+ }
+
+ /* Verify country code */
+ 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__));
+ goto exit;
+ }
+
+ cspec = (wl_country_t *)iovbuf;
+ if ((strncmp(cspec->ccode, WL_CCODE_NULL_COUNTRY, WLC_CNTRY_BUF_SZ)) == 0) {
+ /* Country code not initialized or CLM download not proper */
+ DHD_ERROR(("country code not initialized\n"));
+ err = BCME_ERROR;
+ }
+
+exit:
+ if (memblock)
+ MFREE(dhd->osh, memblock, MAX_CLM_BUF_SIZE);
+
+ return err;
+}
+#ifdef DHD_USE_CLMINFO_PARSER
+#define CLMINFO_PATH "/installmedia/.clminfo"
+
+extern struct cntry_locales_custom translate_custom_table[NUM_OF_COUNTRYS];
+
+unsigned int
+process_clarification_vars(char *varbuf, unsigned int varbuf_size)
+{
+ char *dp;
+ bool findNewline;
+ int column;
+ unsigned int buf_len, len;
+
+ dp = varbuf;
+
+ findNewline = FALSE;
+ column = 0;
+
+ for (len = 0; len < varbuf_size; len++) {
+ if ((varbuf[len] == '\r') || (varbuf[len] == ' ')) {
+ continue;
+ }
+ if (findNewline && varbuf[len] != '\n') {
+ continue;
+ }
+ findNewline = FALSE;
+ if (varbuf[len] == '#') {
+ findNewline = TRUE;
+ continue;
+ }
+ if (varbuf[len] == '\n') {
+ if (column == 0)
+ continue;
+ column = 0;
+ continue;
+ }
+ *dp++ = varbuf[len];
+ column++;
+ }
+ buf_len = (unsigned int)(dp - varbuf);
+
+ while (dp < varbuf + len)
+ *dp++ = 0;
+
+ return buf_len;
+}
+
+int
+dhd_get_clminfo(dhd_pub_t *dhd, char *clm_path)
+{
+ int bcmerror = BCME_OK;
+ char *clminfo_path = CLMINFO_PATH;
+
+ char *memblock = NULL;
+ char *bufp;
+ uint len = MAX_CLMINFO_BUF_SIZE;
+ char *temp_buf = NULL;
+
+ int cnt = 0;
+
+ char tokdelim;
+ int parse_step = 0;
+ /*
+ * Read clm info from the .clminfo file
+ * 1st line : CLM blob file path
+ * 2nd ~ end of line: Country locales table
+ */
+ memset(translate_custom_table, 0, sizeof(translate_custom_table));
+
+ if (dhd_get_download_buffer(dhd, clminfo_path, CLMINFO, &memblock, &len) != 0) {
+ DHD_ERROR(("%s: Cannot open .clminfo file\n", __FUNCTION__));
+ bcmerror = BCME_ERROR;
+ goto out;
+ }
+
+ if ((len > 0) && (len <= MAX_CLMINFO_BUF_SIZE) && memblock) {
+ /* Found clminfo file. Parsing the file */
+ DHD_INFO(("clminfo file parsing from %s \n", clminfo_path));
+
+ bufp = (char *) memblock;
+ bufp[len] = 0;
+
+ /* clean up the file */
+ len = process_clarification_vars(bufp, len);
+
+ temp_buf = MALLOCZ(dhd->osh, MAX_CLMINFO_BUF_SIZE);
+
+ temp_buf = bcmstrtok(&bufp, "=", &tokdelim);
+ /* reduce the len of bufp by token byte(1) and ptr length */
+ len -= (strlen(temp_buf) + 1);
+
+ if (strncmp(temp_buf, "clm_path", 8) != 0) {
+ DHD_ERROR(("%s: Cannot found clm_path\n", __FUNCTION__));
+ bcmerror = BCME_ERROR;
+ goto out;
+ }
+
+ /* read clm_path */
+ strcpy(clm_path, bcmstrtok(&bufp, ";", &tokdelim));
+ len -= (strlen(clm_path) + 1);
+
+ DHD_INFO(("%s: Found clm_path %s\n", __FUNCTION__, clm_path));
+
+ if (len <= 0) {
+ DHD_ERROR(("%s: Length is invalid\n", __FUNCTION__));
+ bcmerror = BCME_ERROR;
+ goto out;
+ }
+
+ /* reserved relocale map[0] to XZ/11 */
+ memcpy(translate_custom_table[cnt].custom_locale, "XZ", strlen("XZ"));
+ translate_custom_table[cnt].custom_locale_rev = 11;
+ DHD_INFO(("%s: Relocale map - iso_aabrev %s custom locale %s "
+ "custom locale rev %d\n",
+ __FUNCTION__,
+ translate_custom_table[cnt].iso_abbrev,
+ translate_custom_table[cnt].custom_locale,
+ translate_custom_table[cnt].custom_locale_rev));
+
+ cnt++;
+
+ /* start parsing relocale map */
+ do {
+
+ if ((bufp[0] == 0) && (len > 0)) {
+ DHD_ERROR(("%s: First byte is NULL character\n", __FUNCTION__));
+ bcmerror = BCME_ERROR;
+ goto out;
+ }
+ if ((bufp[0] == '=') || (bufp[0] == '/') || (bufp[0] == ';')) {
+ DHD_ERROR(("%s: Data is invalid\n", __FUNCTION__));
+ bcmerror = BCME_ERROR;
+ goto out;
+ }
+
+ memset(temp_buf, 0, strlen(temp_buf));
+ /* parsing relocale data */
+ temp_buf = bcmstrtok(&bufp, "=/;", &tokdelim);
+ len -= (strlen(temp_buf) + 1);
+
+ if ((parse_step == 0) && (tokdelim == '=')) {
+ memcpy(translate_custom_table[cnt].iso_abbrev,
+ temp_buf, strlen(temp_buf));
+ parse_step++;
+ } else if ((parse_step == 1) && (tokdelim == '/')) {
+ memcpy(translate_custom_table[cnt].custom_locale,
+ temp_buf, strlen(temp_buf));
+ parse_step++;
+ } else if ((parse_step == 2) && (tokdelim == ';')) {
+ char *str, *endptr = NULL;
+ int locale_rev;
+
+ str = temp_buf;
+ locale_rev = (int)strtoul(str, &endptr, 0);
+ if (*endptr != 0) {
+ bcmerror = BCME_ERROR;
+ goto out;
+ }
+
+ translate_custom_table[cnt].custom_locale_rev = locale_rev;
+
+ DHD_INFO(("%s: Relocale map - iso_aabrev %s"
+ " custom locale %s custom locale rev %d\n",
+ __FUNCTION__,
+ translate_custom_table[cnt].iso_abbrev,
+ translate_custom_table[cnt].custom_locale,
+ translate_custom_table[cnt].custom_locale_rev));
+
+ parse_step = 0;
+ cnt++;
+ } else {
+ DHD_ERROR(("%s: CLM info data format is invalid\n", __FUNCTION__));
+ bcmerror = BCME_ERROR;
+ goto out;
+ }
+
+ } while (len > 0);
+ }
+out:
+ if (memblock) {
+ dhd_free_download_buffer(dhd, memblock, MAX_NVRAMBUF_SIZE);
+ }
+ if (temp_buf) {
+ MFREE(dhd->osh, temp_buf, MAX_CLMINFO_BUF_SIZE);
+ }
+ if (bcmerror != BCME_OK) {
+ DHD_ERROR(("%s: .clminfo parsing fail!!\n", __FUNCTION__));
+ }
+
+ return bcmerror;
+}
+#endif /* DHD_USE_CLMINFO_PARSER */
+
+void dhd_free_download_buffer(dhd_pub_t *dhd, void *buffer, int length)
+{
+#ifdef CACHE_FW_IMAGES
+ return;
+#endif
+ MFREE(dhd->osh, buffer, length);
+}
+/* Parse EAPOL 4 way handshake messages */
+void
+dhd_dump_eapol_4way_message(char *ifname, char *dump_data, bool direction)
+{
+ unsigned char type;
+ int pair, ack, mic, kerr, req, sec, install;
+ unsigned short us_tmp;
+ type = dump_data[18];
+ if (type == 2 || type == 254) {
+ 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 (!sec && !mic && ack && !install && pair && !kerr && !req) {
+ DHD_ERROR(("ETHER_TYPE_802_1X[%s] [%s] : M1 of 4way\n",
+ ifname, direction ? "TX" : "RX"));
+ } else if (pair && !install && !ack && mic && !sec && !kerr && !req) {
+ DHD_ERROR(("ETHER_TYPE_802_1X[%s] [%s] : M2 of 4way\n",
+ ifname, direction ? "TX" : "RX"));
+ } else if (pair && ack && mic && sec && !kerr && !req) {
+ DHD_ERROR(("ETHER_TYPE_802_1X[%s] [%s] : M3 of 4way\n",
+ ifname, direction ? "TX" : "RX"));
+ } else if (pair && !install && !ack && mic && sec && !req && !kerr) {
+ DHD_ERROR(("ETHER_TYPE_802_1X[%s] [%s] : M4 of 4way\n",
+ ifname, direction ? "TX" : "RX"));
+ } else {
+ DHD_ERROR(("ETHER_TYPE_802_1X[%s] [%s]: ver %d, type %d, replay %d\n",
+ ifname, direction ? "TX" : "RX",
+ dump_data[14], dump_data[15], dump_data[30]));
+ }
+ } else {
+ DHD_ERROR(("ETHER_TYPE_802_1X[%s] [%s]: ver %d, type %d, replay %d\n",
+ ifname, direction ? "TX" : "RX",
+ dump_data[14], dump_data[15], dump_data[30]));
+ }
+}
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd_1363/dhd_custom_gpio.c
new file mode 100644
index 000000000000..09d47d564904
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_custom_gpio.c
@@ -0,0 +1,309 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_custom_gpio.c 591129 2015-10-07 05:22:14Z $
+ */
+
+#include <typedefs.h>
+#include <linuxver.h>
+#include <osl.h>
+#include <bcmutils.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_linux.h>
+
+#include <wlioctl.h>
+#if defined(WL_WIRELESS_EXT)
+#include <wl_iw.h>
+#endif
+
+#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 */
+
+#if !defined(WL_WIRELESS_EXT)
+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 */
+};
+#endif /* WL_WIRELESS_EXT */
+
+/* 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
+*/
+#ifdef CUSTOM_COUNTRY_CODE
+void get_customized_country_code(void *adapter, char *country_iso_code,
+ wl_country_t *cspec, u32 flags)
+#else
+void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec)
+#endif /* CUSTOM_COUNTRY_CODE */
+{
+#if 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/drivers/net/wireless/bcmdhd_1363/dhd_dbg.h b/drivers/net/wireless/bcmdhd_1363/dhd_dbg.h
new file mode 100644
index 000000000000..ea5889447fa3
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_dbg.h
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_dbg.h 598059 2015-11-07 07:31:52Z $
+ */
+
+#ifndef _dhd_dbg_
+#define _dhd_dbg_
+
+#if defined(DHD_DEBUG)
+#ifdef DHD_LOG_DUMP
+extern void dhd_log_dump_print(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("[%s] %s: ", dhd_log_dump_get_timestamp(), __func__); \
+ dhd_log_dump_print args; \
+ } \
+} while (0)
+#else
+#define DHD_ERROR(args) do {if (dhd_msg_level & DHD_ERROR_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_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0)
+#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0)
+#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
+#define DHD_EVENT(args) \
+do { \
+ if (dhd_msg_level & DHD_EVENT_VAL) { \
+ printf args; \
+ dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __func__); \
+ dhd_log_dump_print args; \
+ } \
+} while (0)
+#else
+#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0)
+#endif /* DHD_LOG_DUMP */
+#define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) printf args;} while (0)
+#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)
+#ifdef DHD_LOG_DUMP
+#define DHD_MSGTRACE_LOG(args) \
+do { \
+ if (dhd_msg_level & DHD_MSGTRACE_VAL) { \
+ printf args; \
+ dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __func__); \
+ dhd_log_dump_print args; \
+ } \
+} while (0)
+#else
+#define DHD_MSGTRACE_LOG(args) do {if (dhd_msg_level & DHD_MSGTRACE_VAL) printf args;} while (0)
+#endif /* DHD_LOG_DUMP */
+#define DHD_FWLOG(args) do {if (dhd_msg_level & DHD_FWLOG_VAL) printf args;} while (0)
+#define DHD_RTT(args) do {if (dhd_msg_level & DHD_RTT_VAL) printf args;} while (0)
+#define DHD_IOV_INFO(args) do {if (dhd_msg_level & DHD_IOV_INFO_VAL) printf args;} while (0)
+
+#ifdef DHD_LOG_DUMP
+#define DHD_ERROR_EX(args) \
+do { \
+ if (dhd_msg_level & DHD_ERROR_VAL) { \
+ dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __func__); \
+ dhd_log_dump_print args; \
+ } \
+} while (0)
+#else
+#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_BTA_ON() (dhd_msg_level & DHD_BTA_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_FWLOG_ON() (dhd_msg_level & DHD_FWLOG_VAL)
+#define DHD_IOV_INFO_ON() (dhd_msg_level & DHD_IOV_INFO_VAL)
+
+#else /* defined(BCMDBG) || defined(DHD_DEBUG) */
+
+#define DHD_ERROR(args) do {printf args;} while (0)
+#define DHD_TRACE(args)
+#define DHD_INFO(args)
+#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)
+#define DHD_EVENT(args)
+#define DHD_BTA(args)
+#define DHD_ISCAN(args)
+#define DHD_ARPOE(args)
+#define DHD_REORDER(args)
+#define DHD_PNO(args)
+#define DHD_MSGTRACE_LOG(args)
+#define DHD_FWLOG(args)
+#define DHD_IOV_INFO(args)
+#define DHD_ERROR_EX(args) DHD_ERROR(args)
+
+#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_BTA_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_FWLOG_ON() 0
+#define DHD_IOV_INFO_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 <dhdioctl.h>
+
+#endif /* _dhd_dbg_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_flowring.c b/drivers/net/wireless/bcmdhd_1363/dhd_flowring.c
new file mode 100644
index 000000000000..c8197748c8ae
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_flowring.c
@@ -0,0 +1,964 @@
+/*
+ * @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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_flowring.c 591285 2015-10-07 11:56:29Z $
+ */
+
+
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <bcmdevs.h>
+
+#include <proto/ethernet.h>
+#include <proto/bcmevent.h>
+#include <dngl_stats.h>
+
+#include <dhd.h>
+
+#include <dhd_flowring.h>
+#include <dhd_bus.h>
+#include <dhd_proto.h>
+#include <dhd_dbg.h>
+#include <proto/802.1d.h>
+#include <pcie_core.h>
+#include <bcmmsgbuf.h>
+#include <dhd_pcie.h>
+
+
+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))
+
+#ifdef 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
+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 */
+
+/** 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);
+ 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);
+
+ queue->failures = 0U;
+ queue->cb = &dhd_flow_queue_overflow;
+}
+
+/** 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));
+
+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));
+
+ 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));
+}
+
+/** 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)
+{
+ flow_queue_t * queue;
+
+ ASSERT(dhdp != (dhd_pub_t*)NULL);
+ ASSERT(queue_budget > 1);
+ ASSERT(cumm_threshold > 1);
+ ASSERT(cumm_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);
+}
+
+/** 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 - FLOW_RING_COMMON, 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);
+ 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);
+ 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 */
+ 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;
+
+ 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)
+{
+ tdls_peer_node_t *cur = dhdp->peer_tbl.node;
+ while (cur != NULL) {
+ if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) {
+ return TRUE;
+ }
+ cur = cur->next;
+ }
+ 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) {
+#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 */
+ 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 *) MALLOC(dhdp->osh, sizeof(flow_hash_info_t));
+ 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) {
+ /* For STA non TDLS 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;
+
+ 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;
+
+
+ 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;
+ }
+
+ /* register this flowid in dhd_pub */
+ dhd_add_flowid(dhdp, ifindex, prio, da, id);
+
+ 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);
+
+ /* 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_PENDING;
+ 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.
+ */
+ if (flow_ring_node->status == FLOW_RING_STATUS_OPEN ||
+ flow_ring_node->status == FLOW_RING_STATUS_PENDING) {
+ *flowid = id;
+ ret = BCME_OK;
+ } else {
+ *flowid = FLOWID_INVALID;
+ ret = BCME_ERROR;
+ }
+
+ 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, eh->ether_shost, 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 e.g. 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_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)) {
+ dhd_bus_flow_ring_delete_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_DELETE_PENDING)) {
+ DHD_INFO(("%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_INFO(("%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_STA) {
+ if_flow_lkup[ifindex].status = TRUE;
+ DHD_INFO(("%s: Mcast Flow ring for ifindex %d role is %d \n",
+ __FUNCTION__, ifindex, role));
+ /* Create Mcast Flow */
+ }
+ } else if (op == WLC_E_IF_DEL) {
+ 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_INFO(("%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 (if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_STA) {
+ 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];
+ 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/drivers/net/wireless/bcmdhd_1363/dhd_flowring.h b/drivers/net/wireless/bcmdhd_1363/dhd_flowring.h
new file mode 100644
index 000000000000..56395286c658
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_flowring.h
@@ -0,0 +1,235 @@
+/*
+ * @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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_flowring.h 591285 2015-10-07 11:56:29Z $
+ */
+
+
+/****************
+ * 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_PENDING 1
+#define FLOW_RING_STATUS_CLOSED 2
+#define FLOW_RING_STATUS_DELETE_PENDING 3
+#define FLOW_RING_STATUS_FLUSH_PENDING 4
+#define FLOW_RING_STATUS_STA_FREEING 5
+
+#define DHD_FLOWRING_RX_BUFPOST_PKTSZ 2048
+
+#define DHD_FLOW_PRIO_AC_MAP 0
+#define DHD_FLOW_PRIO_TID_MAP 1
+#define DHD_FLOW_PRIO_LLR_MAP 2
+
+/* 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_FLOWID(tag, flow) ((tag)->flowid = (uint16)(flow))
+#define DHD_PKTTAG_SET_IFID(tag, idx) ((tag)->ifid = (uint16)(idx))
+#define DHD_PKTTAG_SET_DATAOFF(tag, offset) ((tag)->dataoff = (int)(offset))
+#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_FLOWID(tag) ((tag)->flowid)
+#define DHD_PKTTAG_IFID(tag) ((tag)->ifid)
+#define DHD_PKTTAG_DATAOFF(tag) ((tag)->dataoff)
+#define DHD_PKTTAG_PA(tag) ((tag)->physaddr)
+#define DHD_PKTTAG_PA_LEN(tag) ((tag)->pa_len)
+
+/* 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_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 */
+} 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_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)
+
+/* see wlfc_proto.h for tx status details */
+#define DHD_FLOWRING_MAXSTATUS_MSGS 5
+#define DHD_FLOWRING_TXSTATUS_CNT_UPDATE(bus, flowid, txstatus)
+/** 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 */
+} 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_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);
+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_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/drivers/net/wireless/bcmdhd_1363/dhd_ip.c b/drivers/net/wireless/bcmdhd_1363/dhd_ip.c
new file mode 100644
index 000000000000..14e44465f36a
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_ip.c
@@ -0,0 +1,1274 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_ip.c 612549 2016-01-14 07:39:32Z $
+ */
+#include <typedefs.h>
+#include <osl.h>
+
+#include <proto/ethernet.h>
+#include <proto/vlan.h>
+#include <proto/802.3.h>
+#include <proto/bcmip.h>
+#include <bcmendian.h>
+
+#include <dhd_dbg.h>
+
+#include <dhd_ip.h>
+
+#ifdef DHDTCPACK_SUPPRESS
+#include <dhd_bus.h>
+#include <dhd_proto.h>
+#include <proto/bcmtcp.h>
+#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;
+ struct timer_list 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;
+}
+
+#ifdef BCMSDIO
+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;
+}
+#endif /* BCMSDIO */
+
+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;
+
+ flags = dhd_os_tcpacklock(dhdp);
+
+ if (dhdp->tcpack_sup_mode == mode) {
+ DHD_ERROR(("%s %d: already set to %d\n", __FUNCTION__, __LINE__, mode));
+ goto exit;
+ }
+
+ if (mode >= TCPACK_SUP_LAST_MODE ||
+#ifndef BCMSDIO
+ mode == TCPACK_SUP_DELAYTX ||
+#endif /* !BCMSDIO */
+ FALSE) {
+ DHD_ERROR(("%s %d: Invalid mode %d\n", __FUNCTION__, __LINE__, mode));
+ ret = BCME_BADARG;
+ goto exit;
+ }
+
+ DHD_TRACE(("%s: %d -> %d\n",
+ __FUNCTION__, dhdp->tcpack_sup_mode, mode));
+
+#ifdef BCMSDIO
+ /* Old tcpack_sup_mode is TCPACK_SUP_DELAYTX */
+ if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX) {
+ tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module;
+ /* We won't need tdata_psh_info pool and tcpddata_info_tbl anymore */
+ _tdata_psh_info_pool_deinit(dhdp, tcpack_sup_mod);
+ tcpack_sup_mod->tcpdata_info_cnt = 0;
+ bzero(tcpack_sup_mod->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);
+ }
+#endif /* BCMSDIO */
+ dhdp->tcpack_sup_mode = mode;
+
+ if (mode == TCPACK_SUP_OFF) {
+ ASSERT(dhdp->tcpack_sup_module != NULL);
+ /* Clean up timer/data structure for any remaining/pending packet or timer. */
+ dhd_tcpack_info_tbl_clean(dhdp);
+ MFREE(dhdp->osh, dhdp->tcpack_sup_module, sizeof(tcpack_sup_module_t));
+ dhdp->tcpack_sup_module = NULL;
+ goto exit;
+ }
+
+ if (dhdp->tcpack_sup_module == NULL) {
+ tcpack_sup_module_t *tcpack_sup_mod =
+ MALLOC(dhdp->osh, sizeof(tcpack_sup_module_t));
+ if (tcpack_sup_mod == NULL) {
+ DHD_ERROR(("%s %d: No MEM\n", __FUNCTION__, __LINE__));
+ dhdp->tcpack_sup_mode = TCPACK_SUP_OFF;
+ ret = BCME_NOMEM;
+ goto exit;
+ }
+ bzero(tcpack_sup_mod, sizeof(tcpack_sup_module_t));
+ dhdp->tcpack_sup_module = tcpack_sup_mod;
+ }
+
+#ifdef BCMSDIO
+ if (mode == TCPACK_SUP_DELAYTX) {
+ ret = _tdata_psh_info_pool_init(dhdp, dhdp->tcpack_sup_module);
+ if (ret != BCME_OK)
+ DHD_ERROR(("%s %d: pool init fail with %d\n", __FUNCTION__, __LINE__, ret));
+ else if (dhdp->bus)
+ dhd_bus_set_dotxinrx(dhdp->bus, FALSE);
+ }
+#endif /* BCMSDIO */
+
+ if (mode == TCPACK_SUP_HOLD) {
+ int i;
+ tcpack_sup_module_t *tcpack_sup_mod =
+ (tcpack_sup_module_t *)dhdp->tcpack_sup_module;
+ 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_sup_mod->tcpack_info_tbl[i].dhdp = dhdp;
+ init_timer(&tcpack_sup_mod->tcpack_info_tbl[i].timer);
+ tcpack_sup_mod->tcpack_info_tbl[i].timer.data =
+ (ulong)&tcpack_sup_mod->tcpack_info_tbl[i];
+ tcpack_sup_mod->tcpack_info_tbl[i].timer.function = dhd_tcpack_send;
+ }
+ }
+
+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/drivers/net/wireless/bcmdhd_1363/dhd_ip.h b/drivers/net/wireless/bcmdhd_1363/dhd_ip.h
new file mode 100644
index 000000000000..c794b914ec61
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_ip.h 537119 2015-02-25 04:24:14Z $
+ */
+
+#ifndef _dhd_ip_h_
+#define _dhd_ip_h_
+
+#ifdef DHDTCPACK_SUPPRESS
+#include <dngl_stats.h>
+#include <bcmutils.h>
+#include <dhd.h>
+#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/drivers/net/wireless/bcmdhd_1363/dhd_linux.c b/drivers/net/wireless/bcmdhd_1363/dhd_linux.c
new file mode 100644
index 000000000000..27c931679e18
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_linux.c
@@ -0,0 +1,14471 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_linux.c 665078 2017-05-18 08:51:32Z $
+ */
+
+#include <typedefs.h>
+#include <linuxver.h>
+#include <osl.h>
+#ifdef SHOW_LOGTRACE
+#include <linux/syscalls.h>
+#include <event_log.h>
+#endif /* SHOW_LOGTRACE */
+
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/etherdevice.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/ip.h>
+#include <linux/reboot.h>
+#include <linux/notifier.h>
+#include <net/addrconf.h>
+#ifdef ENABLE_ADAPTIVE_SCHED
+#include <linux/cpufreq.h>
+#endif /* ENABLE_ADAPTIVE_SCHED */
+
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+#include <epivers.h>
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <bcmdevs.h>
+
+#include <proto/ethernet.h>
+#include <proto/bcmevent.h>
+#include <proto/vlan.h>
+#include <proto/802.3.h>
+
+#include <dngl_stats.h>
+#include <dhd_linux_wq.h>
+#include <dhd.h>
+#include <dhd_linux.h>
+#ifdef PCIE_FULL_DONGLE
+#include <dhd_flowring.h>
+#endif
+#include <dhd_bus.h>
+#include <dhd_proto.h>
+#include <dhd_dbg.h>
+#ifdef CONFIG_HAS_WAKELOCK
+#include <linux/wakelock.h>
+#endif
+#ifdef WL_CFG80211
+#include <wl_cfg80211.h>
+#endif
+#ifdef PNO_SUPPORT
+#include <dhd_pno.h>
+#endif
+#ifdef RTT_SUPPORT
+#include <dhd_rtt.h>
+#endif
+
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+#endif
+
+#ifdef DHD_WMF
+#include <dhd_wmf_linux.h>
+#endif /* DHD_WMF */
+
+#ifdef DHD_L2_FILTER
+#include <proto/bcmicmp.h>
+#include <bcm_l2_filter.h>
+#include <dhd_l2_filter.h>
+#endif /* DHD_L2_FILTER */
+
+#ifdef DHD_PSTA
+#include <dhd_psta.h>
+#endif /* DHD_PSTA */
+
+
+#ifdef DHDTCPACK_SUPPRESS
+#include <dhd_ip.h>
+#endif /* DHDTCPACK_SUPPRESS */
+
+#ifdef DHD_BANDSTEER
+#include <dhd_bandsteer.h>
+#endif /* DHD_BANDSTEER */
+
+#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)
+/* Dynamic CPU selection for load balancing */
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/notifier.h>
+#include <linux/workqueue.h>
+#include <asm/atomic.h>
+
+#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 8
+
+#if defined(DHD_LB_RXP)
+static void dhd_rx_napi_dispatcher_fn(struct work_struct * work);
+#endif /* DHD_LB_RXP */
+
+#endif /* DHD_LB */
+
+#ifdef WLMEDIA_HTSF
+#include <linux/time.h>
+#include <htsf.h>
+
+#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 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(char *ifname, char *dump_data, bool direction);
+
+#ifdef FIX_CPU_MIN_CLOCK
+#include <linux/pm_qos.h>
+#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 <bcm_rpc.h>
+#include <bcm_rpc_tp.h>
+#endif
+#ifdef PROP_TXSTATUS
+#include <wlfc_proto.h>
+#include <dhd_wlfc.h>
+#endif
+
+#include <wl_android.h>
+
+/* 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)
+static 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 <linux/suspend.h>
+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)
+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 */
+
+#include <dhd_bus.h>
+
+#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 *dhd);
+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 <wl_iw.h>
+extern wl_iw_extra_params_t g_wl_iw_params;
+#endif /* defined(WL_WIRELESS_EXT) */
+
+#ifdef CONFIG_PARTIALSUSPEND_SLP
+#include <linux/partialsuspend_slp.h>
+#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 <linux/earlysuspend.h>
+#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */
+#endif /* CONFIG_PARTIALSUSPEND_SLP */
+
+extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd);
+
+#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
+
+
+
+
+
+
+#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
+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 <linux/kmod.h>
+#define DHD_DEBUG_UART_EXEC_PATH "/system/bin/wldu"
+static void dhd_debug_uart_exec(char *cmd);
+#endif
+
+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 */
+
+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 */
+#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 */
+} 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[16];
+ unsigned long event;
+};
+
+#ifdef DHD_DEBUG
+typedef struct dhd_dump {
+ uint8 *buf;
+ int bufsize;
+} dhd_dump_t;
+#endif /* DHD_DEBUG */
+
+/* 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 */
+
+ void *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 */
+
+ /* serialize dhd iovars */
+ struct mutex dhd_iovar_mutex;
+
+ struct semaphore proto_sem;
+#ifdef PROP_TXSTATUS
+ spinlock_t wlfc_spinlock;
+
+#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;
+
+ struct timer_list timer;
+ bool wd_timer_valid;
+#ifdef DHD_PCIE_RUNTIMEPM
+ struct timer_list 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 dhd_lock;
+
+ struct semaphore sdsem;
+ tsk_ctl_t thr_dpc_ctl;
+ tsk_ctl_t thr_wdt_ctl;
+
+ 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;
+#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;
+ struct timer_list 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_DEBUG
+ dhd_dump_t *dump;
+ struct timer_list join_timer;
+ u32 join_timeout_val;
+ bool join_timer_active;
+ uint scan_time_count;
+ struct timer_list 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 rx_compl_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[NR_CPUS];
+
+ /* 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[NR_CPUS];
+
+ /* 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[NR_CPUS];
+
+ /* CPU status */
+ /* Number of times each CPU came online */
+ uint32 cpu_online_cnt[NR_CPUS];
+
+ /* Number of times each CPU went offline */
+ uint32 cpu_offline_cnt[NR_CPUS];
+
+ /*
+ * 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[NR_CPUS][HIST_BIN_SIZE];
+ uint32 txc_hist[NR_CPUS][HIST_BIN_SIZE];
+ uint32 rxc_hist[NR_CPUS][HIST_BIN_SIZE];
+#endif /* DHD_LB */
+
+#if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW)
+#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */
+
+ struct kobject dhd_kobj;
+
+ uint32 shub_enable;
+
+ struct delayed_work dhd_memdump_work;
+} dhd_info_t;
+
+#define DHDIF_FWDER(dhdif) FALSE
+
+/* Flag to indicate if we should download firmware on driver load */
+uint dhd_download_fw_on_driverload = TRUE;
+
+/* Flag to indicate if driver is initialized */
+uint dhd_driver_init_done = FALSE;
+
+/* 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];
+
+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);
+
+#if defined(DHD_LB_RXP)
+static int dhd_napi_weight = 32;
+module_param(dhd_napi_weight, int, 0644);
+#endif /* DHD_LB_RXP */
+
+extern int wl_control_wl_start(struct net_device *dev);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(BCMLXSDMMC)
+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);
+#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 */
+
+/* Error bits */
+module_param(dhd_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;
+#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);
+
+/* 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);
+#endif /* defined(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 = TRUE;
+#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);
+
+int passive_channel_skip = 0;
+module_param(passive_channel_skip, int, (S_IRUSR|S_IWUSR));
+
+#if !defined(BCMDHDUSB)
+extern int dhd_dongle_ramsize;
+module_param(dhd_dongle_ramsize, int, 0);
+#endif /* BCMDHDUSB */
+
+/* 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);
+
+/* Takes value of LL of OTP param customvar2=0xKKLLMMNN.
+ * LL is module variant
+ */
+uint32 hw_module_variant = 0;
+module_param(hw_module_variant, uint, 0644);
+
+/* 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);
+
+#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);
+}
+
+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, cpu_num;
+ int ret = 0;
+
+ 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);
+
+ cpu_num = num_possible_cpus();
+ cpus = DHD_LB_PRIMARY_CPUS;
+ for (id = 0; id < cpu_num; id++) {
+ if (isset(&cpus, id))
+ cpumask_set_cpu(id, dhd->cpumask_primary);
+ }
+
+ cpus = DHD_LB_SECONDARY_CPUS;
+ for (id = 0; id < cpu_num; 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 */
+
+ 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
+ */
+ compl_cpu = cpumask_next(napi_cpu, dhd->cpumask_primary_new);
+ if (compl_cpu >= nr_cpu_ids)
+ compl_cpu = 0;
+ }
+
+ DHD_INFO(("%s After primary CPU check napi_cpu %d compl_cpu %d\n",
+ __FUNCTION__, napi_cpu, compl_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);
+ compl_cpu = cpumask_next(napi_cpu, dhd->cpumask_secondary_new);
+ } else if (compl_cpu == 0) {
+ compl_cpu = cpumask_first(dhd->cpumask_secondary_new);
+ }
+
+ /* 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 = 0;
+ compl_cpu = 0;
+ }
+
+ DHD_INFO(("%s After secondary CPU check napi_cpu %d compl_cpu %d\n",
+ __FUNCTION__, napi_cpu, compl_cpu));
+ ASSERT(napi_cpu < nr_cpu_ids);
+ ASSERT(compl_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);
+ 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 int cpu = (unsigned int)(long)hcpu;
+
+ dhd_info_t *dhd = container_of(nfb, dhd_info_t, cpu_notifier);
+
+ switch (action)
+ {
+ case CPU_ONLINE:
+ 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;
+
+ if (dhdp == NULL) {
+ DHD_ERROR(("%s(): Invalid argument dhdp 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_LB_STATS_CLR(dhd->rxc_sched_cnt);
+ DHD_LB_STATS_CLR(dhd->txc_sched_cnt);
+
+ for (i = 0; i < NR_CPUS; i++) {
+ DHD_LB_STATS_CLR(dhd->napi_percpu_run_cnt[i]);
+ DHD_LB_STATS_CLR(dhd->rxc_percpu_run_cnt[i]);
+ DHD_LB_STATS_CLR(dhd->txc_percpu_run_cnt[i]);
+
+ DHD_LB_STATS_CLR(dhd->cpu_online_cnt[i]);
+ DHD_LB_STATS_CLR(dhd->cpu_offline_cnt[i]);
+ }
+
+ for (i = 0; i < NR_CPUS; i++) {
+ for (j = 0; j < HIST_BIN_SIZE; j++) {
+ DHD_LB_STATS_CLR(dhd->napi_rx_hist[i][j]);
+ DHD_LB_STATS_CLR(dhd->txc_hist[i][j]);
+ DHD_LB_STATS_CLR(dhd->rxc_hist[i][j]);
+ }
+ }
+
+ return;
+}
+
+static void dhd_lb_stats_dump_histo(
+ struct bcmstrbuf *strbuf, uint32 (*hist)[HIST_BIN_SIZE])
+{
+ int i, j;
+ uint32 per_cpu_total[NR_CPUS] = {0};
+ uint32 total = 0;
+
+ bcm_bprintf(strbuf, "CPU: \t\t");
+ for (i = 0; i < num_possible_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<<(i+1));
+ for (j = 0; j < num_possible_cpus(); j++) {
+ bcm_bprintf(strbuf, "%d\t", hist[j][i]);
+ }
+ bcm_bprintf(strbuf, "\n");
+ }
+ bcm_bprintf(strbuf, "Per CPU Total \t");
+ total = 0;
+ for (i = 0; i < num_possible_cpus(); i++) {
+ for (j = 0; j < HIST_BIN_SIZE; j++) {
+ per_cpu_total[i] += (hist[i][j] * (1<<(j+1)));
+ }
+ bcm_bprintf(strbuf, "%d\t", per_cpu_total[i]);
+ total += per_cpu_total[i];
+ }
+ bcm_bprintf(strbuf, "\nTotal\t\t%d \n", total);
+
+ return;
+}
+
+static inline void dhd_lb_stats_dump_cpu_array(struct bcmstrbuf *strbuf, uint32 *p)
+{
+ int i;
+
+ bcm_bprintf(strbuf, "CPU: \t");
+ for (i = 0; i < num_possible_cpus(); i++)
+ bcm_bprintf(strbuf, "%d\t", i);
+ bcm_bprintf(strbuf, "\n");
+
+ bcm_bprintf(strbuf, "Val: \t");
+ for (i = 0; i < num_possible_cpus(); i++)
+ bcm_bprintf(strbuf, "%u\t", *(p+i));
+ bcm_bprintf(strbuf, "\n");
+ return;
+}
+
+void dhd_lb_stats_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
+{
+ dhd_info_t *dhd;
+
+ if (dhdp == NULL || strbuf == NULL) {
+ DHD_ERROR(("%s(): Invalid argument dhdp %p strbuf %p \n",
+ __FUNCTION__, dhdp, strbuf));
+ return;
+ }
+
+ dhd = dhdp->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, "cpu_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, "napi_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, "rxc_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, "txc_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 */
+}
+
+static void dhd_lb_stats_update_histo(uint32 *bin, uint32 count)
+{
+ uint32 bin_power;
+ uint32 *p = NULL;
+
+ bin_power = next_larger_power2(count);
+
+ switch (bin_power) {
+ case 0: break;
+ case 1: /* Fall through intentionally */
+ case 2: p = bin + 0; break;
+ case 4: p = bin + 1; break;
+ case 8: p = bin + 2; break;
+ case 16: p = bin + 3; break;
+ case 32: p = bin + 4; break;
+ case 64: p = bin + 5; break;
+ case 128: p = bin + 6; break;
+ default : p = bin + 7; break;
+ }
+ if (p)
+ *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[cpu][0], count);
+
+ 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[cpu][0], count);
+
+ 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[cpu][0], count);
+
+ 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 int dhd_dbg_init(dhd_pub_t *dhdp);
+extern void dhd_dbg_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;
+
+/* 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 */
+
+
+
+/* Allow delayed firmware download for debug purpose */
+int allow_delay_fwdl = FALSE;
+module_param(allow_delay_fwdl, int, 0);
+
+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) */
+
+static void dhd_dpc(ulong data);
+/* 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, size_t 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;
+ dhd_info_t *dhdinfo = (dhd_info_t*)container_of(nfb, struct dhd_info, pm_notifier);
+
+ 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;
+ }
+
+#if defined(SUPPORT_P2P_GO_PS) && defined(PROP_TXSTATUS)
+ if (suspend) {
+ DHD_OS_WAKE_LOCK_WAIVE(&dhdinfo->pub);
+ dhd_wlfc_suspend(&dhdinfo->pub);
+ DHD_OS_WAKE_LOCK_RESTORE(&dhdinfo->pub);
+ } else {
+ dhd_wlfc_resume(&dhdinfo->pub);
+ }
+#endif /* defined(SUPPORT_P2P_GO_PS) && defined(PROP_TXSTATUS) */
+
+#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 */
+} 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)
+
+/** 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;
+}
+
+/** 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 */
+ .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);
+
+ 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), (wofa_t)sta);
+ }
+#endif /* BCM_GMAC3 */
+ list_del(&sta->list);
+ dhd_sta_free(&ifp->info->pub, sta);
+ }
+
+ 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, (wofa_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);
+
+ list_for_each_entry(sta, &ifp->sta_list, list) {
+ if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) {
+ DHD_IF_STA_LIST_UNLOCK(ifp, flags);
+ return sta;
+ }
+ }
+
+ 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;
+ 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, (wofa_t)sta);
+ }
+#endif /* BCM_GMAC3 */
+
+ DHD_IF_STA_LIST_UNLOCK(ifp, flags);
+
+ return sta;
+}
+
+/** 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;
+
+ ASSERT(ea != NULL);
+ ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx);
+ if (ifp == NULL)
+ return;
+
+ DHD_IF_STA_LIST_LOCK(ifp, flags);
+
+ 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, (wofa_t)sta);
+ }
+#endif /* BCM_GMAC3 */
+ list_del(&sta->list);
+ dhd_sta_free(&ifp->info->pub, sta);
+ }
+ }
+
+ 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; }
+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)
+/**
+ * dhd_tasklet_schedule - Function that runs in IPI context of the destination
+ * CPU and schedules a tasklet.
+ * @tasklet: opaque pointer to the tasklet
+ */
+static 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.
+ */
+static 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);
+}
+#endif /* DHD_LB_TXC || DHD_LB_RXC */
+
+
+#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 {
+ schedule_work(&dhd->rx_compl_dispatcher_work);
+ }
+}
+
+static void dhd_rx_compl_dispatcher_fn(struct work_struct * work)
+{
+ struct dhd_info *dhd =
+ container_of(work, struct dhd_info, rx_compl_dispatcher_work);
+ int cpu;
+
+ get_online_cpus();
+ cpu = atomic_read(&dhd->tx_compl_cpu);
+ if (!cpu_online(cpu))
+ dhd_tasklet_schedule(&dhd->rx_compl_tasklet);
+ else
+ dhd_tasklet_schedule_on(&dhd->rx_compl_tasklet, cpu);
+ put_online_cpus();
+}
+
+#endif /* DHD_LB_RXC */
+
+
+#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;
+
+ dhd = container_of(napi, struct dhd_info, rx_napi_struct);
+ 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)
+{
+ struct dhd_info *dhd =
+ container_of(work, struct dhd_info, rx_napi_dispatcher_work);
+ 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 */
+
+static void dhd_memdump_work_handler(struct work_struct * work)
+{
+ struct dhd_info *dhd =
+ container_of(work, struct dhd_info, dhd_memdump_work.work);
+
+ BCM_REFERENCE(dhd);
+#ifdef BCMPCIE
+ dhd_prot_collect_memdump(&dhd->pub);
+#endif
+}
+
+
+/** 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;
+}
+
+#ifdef PKT_FILTER_SUPPORT
+#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER
+static bool
+_turn_on_arp_filter(dhd_pub_t *dhd, int op_mode)
+{
+ bool _apply = FALSE;
+ /* In case of IBSS mode, apply arp pkt filter */
+ if (op_mode & 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 & (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_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)))
+ {
+ for (i = 0; i < dhd->pktfilter_count; i++) {
+#ifndef 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; */
+ char iovbuf[32];
+ int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 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;
+ int ret = 0;
+#endif /* DHD_USE_EARLYSUSPEND */
+#ifdef PASS_ALL_MCAST_PKTS
+ struct dhd_info *dhdinfo;
+ uint32 allmulti;
+ uint i;
+#endif /* PASS_ALL_MCAST_PKTS */
+#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 (!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__));
+
+#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) {
+ bcm_mkiovar("shub_msreq", (char *)&shub_ctl,
+ sizeof(shub_ctl), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s SensorHub MS start: failed %d\n",
+ __FUNCTION__, ret));
+ }
+ }
+#endif /* SUPPORT_SENSORHUB */
+
+#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);
+#endif /* PKT_FILTER_SUPPORT */
+
+#ifdef PASS_ALL_MCAST_PKTS
+ allmulti = 0;
+ bcm_mkiovar("allmulti", (char *)&allmulti, 4,
+ iovbuf, sizeof(iovbuf));
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net)
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, i);
+ }
+#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 */
+ bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd);
+ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
+ 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf),
+ TRUE, 0) < 0)
+ DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__));
+
+#ifdef DHD_USE_EARLYSUSPEND
+#ifdef CUSTOM_BCN_TIMEOUT_IN_SUSPEND
+ bcn_timeout = CUSTOM_BCN_TIMEOUT_IN_SUSPEND;
+ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout,
+ 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* CUSTOM_BCN_TIMEOUT_IN_SUSPEND */
+#ifdef CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND
+ roam_time_thresh = CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND;
+ bcm_mkiovar("roam_time_thresh", (char *)&roam_time_thresh,
+ 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND */
+#ifndef ENABLE_FW_ROAM_SUSPEND
+ /* Disable firmware roaming during suspend */
+ bcm_mkiovar("roam_off", (char *)&roamvar, 4,
+ iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* ENABLE_FW_ROAM_SUSPEND */
+#ifdef ENABLE_BCN_LI_BCN_WAKEUP
+ bcn_li_bcn = 0;
+ bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn,
+ 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* ENABLE_BCN_LI_BCN_WAKEUP */
+ if (FW_SUPPORTED(dhd, ndoe)) {
+ /* enable IPv6 RA filter in firmware during suspend */
+ nd_ra_filter = 1;
+ bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4,
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("failed to set nd_ra_filter (%d)\n",
+ ret));
+ }
+#ifdef DYNAMIC_SWOOB_DURATION
+ intr_width = CUSTOM_INTR_WIDTH;
+ bcm_mkiovar("bus:intr_width", (char *)&intr_width, 4,
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 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) {
+ bcm_mkiovar("shub_msreq", (char *)&shub_ctl,
+ sizeof(shub_ctl), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s SensorHub MS stop: failed %d\n",
+ __FUNCTION__, ret));
+ }
+ }
+#endif /* SUPPORT_SENSORHUB */
+
+
+#ifdef DYNAMIC_SWOOB_DURATION
+ intr_width = 0;
+ bcm_mkiovar("bus:intr_width", (char *)&intr_width, 4,
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 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);
+#endif /* PKT_FILTER_SUPPORT */
+#ifdef PASS_ALL_MCAST_PKTS
+ allmulti = 1;
+ bcm_mkiovar("allmulti", (char *)&allmulti, 4,
+ iovbuf, sizeof(iovbuf));
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net)
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, i);
+ }
+#endif /* PASS_ALL_MCAST_PKTS */
+
+ /* restore pre-suspend setting for dtim_skip */
+ bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
+ 4, iovbuf, sizeof(iovbuf));
+
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#ifdef DHD_USE_EARLYSUSPEND
+#ifdef CUSTOM_BCN_TIMEOUT_IN_SUSPEND
+ bcn_timeout = CUSTOM_BCN_TIMEOUT;
+ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout,
+ 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* CUSTOM_BCN_TIMEOUT_IN_SUSPEND */
+#ifdef CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND
+ roam_time_thresh = 2000;
+ bcm_mkiovar("roam_time_thresh", (char *)&roam_time_thresh,
+ 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND */
+#ifndef ENABLE_FW_ROAM_SUSPEND
+ roamvar = dhd_roam_disable;
+ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf,
+ sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* ENABLE_FW_ROAM_SUSPEND */
+#ifdef ENABLE_BCN_LI_BCN_WAKEUP
+ bcn_li_bcn = 1;
+ bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn,
+ 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* ENABLE_BCN_LI_BCN_WAKEUP */
+ if (FW_SUPPORTED(dhd, ndoe)) {
+ /* disable IPv6 RA filter in firmware during suspend */
+ nd_ra_filter = 0;
+ bcm_mkiovar("nd_ra_filter_enable", (char *)&nd_ra_filter, 4,
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("failed to set nd_ra_filter (%d)\n",
+ ret));
+ }
+#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))
+ {
+ 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_suspend_resume_helper(dhd, 1, 0);
+}
+
+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_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_bad>";
+ }
+
+ if (dhd->iflist[ifidx] == NULL) {
+ DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx));
+ return "<if_null>";
+ }
+
+ if (dhd->iflist[ifidx]->net)
+ return dhd->iflist[ifidx]->net->name;
+
+ return "<if_none>";
+}
+
+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)
+ netdev_for_each_mc_addr(ha, dev) {
+ if (!cnt)
+ break;
+ memcpy(bufp, ha->addr, ETHER_ADDR_LEN);
+ bufp += ETHER_ADDR_LEN;
+ cnt--;
+ }
+#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...
+ */
+
+ buflen = sizeof("allmulti") + sizeof(allmulti);
+ if (!(buf = MALLOC(dhd->pub.osh, buflen))) {
+ DHD_ERROR(("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx)));
+ return;
+ }
+ allmulti = htol32(allmulti);
+
+ if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) {
+ DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
+ dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen));
+ MFREE(dhd->pub.osh, buf, buflen);
+ return;
+ }
+
+
+ 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 allmulti %d failed\n",
+ dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
+ }
+
+ MFREE(dhd->pub.osh, buf, buflen);
+
+ /* 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)
+{
+ char buf[32];
+ wl_ioctl_t ioc;
+ int ret;
+
+ if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) {
+ DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx)));
+ return -1;
+ }
+ memset(&ioc, 0, sizeof(ioc));
+ ioc.cmd = WLC_SET_VAR;
+ ioc.buf = buf;
+ ioc.len = 32;
+ ioc.set = TRUE;
+
+ ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ 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 SOFTAP
+extern struct net_device *ap_net_dev;
+extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */
+#endif
+
+#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 */
+
+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 (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+ struct wireless_dev *vwdev, *primary_wdev;
+ struct net_device *primary_ndev;
+#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 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));
+
+ /* 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;
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+ vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
+ if (unlikely(!vwdev)) {
+ DHD_ERROR(("Could not allocate wireless device\n"));
+ goto done;
+ }
+ primary_ndev = dhd->pub.info->iflist[0]->net;
+ primary_wdev = ndev_to_wdev(primary_ndev);
+ vwdev->wiphy = primary_wdev->wiphy;
+ vwdev->iftype = if_event->event.role;
+ vwdev->netdev = ndev;
+ ndev->ieee80211_ptr = vwdev;
+ SET_NETDEV_DEV(ndev, wiphy_dev(vwdev->wiphy));
+ DHD_ERROR(("virtual interface(%s) is created\n", if_event->name));
+#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */
+
+ 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;
+ }
+#ifdef 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)) {
+ char iovbuf[WLC_IOCTL_SMLEN];
+ uint32 var_int = 1;
+
+ memset(iovbuf, 0, sizeof(iovbuf));
+ bcm_mkiovar("ap_isolate", (char *)&var_int, 4, iovbuf, sizeof(iovbuf));
+ ret = dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, ifidx);
+
+ 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);
+ dhd_remove_if(&dhd->pub, ifidx, TRUE);
+ DHD_PERIM_LOCK(&dhd->pub);
+
+ 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_set_mac_addr_handler(void *handle, void *event_info, u8 event)
+{
+ dhd_info_t *dhd = handle;
+ dhd_if_t *ifp = NULL;
+ int ifidx = (int)((long int)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);
+
+ ifp = dhd->iflist[ifidx];
+ if (ifp == NULL || !dhd->pub.up) {
+ DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__));
+ goto done;
+ }
+
+#if defined(SOFTAP) && defined(USE_IW)
+ {
+ unsigned long flags;
+ DHD_GENERAL_LOCK(&dhd->pub, flags);
+ if (ap_net_dev != NULL) {
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+ DHD_ERROR(("attempt to set MAC for %s in AP Mode, blocked. \n",
+ ifp->net->name));
+ goto done;
+ }
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+ }
+#endif /* SOFTAP && USE_IW */
+ 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;
+ dhd_if_t *ifp = NULL;
+ int ifidx = (int)((long int)event_info);
+
+ 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 defined(SOFTAP) && defined(USE_IW)
+ {
+ unsigned long flags;
+ DHD_GENERAL_LOCK(&dhd->pub, flags);
+ if (ap_net_dev != NULL) {
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+ DHD_ERROR(("set MULTICAST list for %s in AP Mode, blocked. \n",
+ ifp->net->name));
+ ifp->set_multicast = FALSE;
+ goto done;
+ }
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+ }
+#endif /* SOFTAP && USE_IW */
+
+
+ _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 *)((long int)ifidx),
+ DHD_WQ_WORK_SET_MAC, dhd_set_mac_addr_handler, DHD_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_WORK_PRIORITY_LOW);
+}
+
+#ifdef PROP_TXSTATUS
+int
+dhd_os_wlfc_block(dhd_pub_t *pub)
+{
+ dhd_info_t *di = (dhd_info_t *)(pub->info);
+ ASSERT(di != NULL);
+ spin_lock_bh(&di->wlfc_spinlock);
+ return 1;
+}
+
+int
+dhd_os_wlfc_unblock(dhd_pub_t *pub)
+{
+ dhd_info_t *di = (dhd_info_t *)(pub->info);
+
+ ASSERT(di != NULL);
+ spin_unlock_bh(&di->wlfc_spinlock);
+ return 1;
+}
+
+#endif /* PROP_TXSTATUS */
+
+#if defined(DHD_8021X_DUMP)
+void
+dhd_tx_dump(struct net_device *ndev, osl_t *osh, void *pkt)
+{
+ uint8 *dump_data;
+ uint16 protocol;
+ char *ifname;
+
+ dump_data = PKTDATA(osh, pkt);
+ protocol = (dump_data[12] << 8) | dump_data[13];
+ ifname = ndev ? ndev->name : "N/A";
+
+ if (protocol == ETHER_TYPE_802_1X) {
+ dhd_dump_eapol_4way_message(ifname, dump_data, TRUE);
+ }
+}
+#endif /* DHD_8021X_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);
+ wofa_t wofa;
+ ASSERT(ISALIGNED(da, 2));
+
+ wofa = fwder_lookup(ifp->fwdh->mate, da, ifp->idx);
+ if (wofa == FWDER_WOFA_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;
+#ifdef DHD_L2_FILTER
+ dhd_if_t *ifp = dhd_get_ifp(dhdp, ifidx);
+#endif
+#ifdef DHD_8021X_DUMP
+ struct net_device *ndev;
+#endif /* DHD_8021X_DUMP */
+
+ /* 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__));
+ PKTFREE(dhdp->osh, pktbuf, TRUE);
+ return -EBUSY;
+ }
+#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 */
+ atomic_inc(&dhd->pend_8021x_cnt);
+ }
+#ifdef DHD_DHCP_DUMP
+ if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
+ uint16 dump_hex;
+ uint16 source_port;
+ uint16 dest_port;
+ uint16 udp_port_pos;
+ uint8 *ptr8 = (uint8 *)&pktdata[ETHER_HDR_LEN];
+ uint8 ip_header_len = (*ptr8 & 0x0f)<<2;
+ struct net_device *net;
+ char *ifname;
+
+ net = dhd_idx2net(dhdp, ifidx);
+ ifname = net ? net->name : "N/A";
+ udp_port_pos = ETHER_HDR_LEN + ip_header_len;
+ source_port = (pktdata[udp_port_pos] << 8) | pktdata[udp_port_pos+1];
+ dest_port = (pktdata[udp_port_pos+2] << 8) | pktdata[udp_port_pos+3];
+ if (source_port == 0x0044 || dest_port == 0x0044) {
+ dump_hex = (pktdata[udp_port_pos+249] << 8) |
+ pktdata[udp_port_pos+250];
+ if (dump_hex == 0x0101) {
+ DHD_ERROR(("DHCP[%s] - DISCOVER [TX]", ifname));
+ } else if (dump_hex == 0x0102) {
+ DHD_ERROR(("DHCP[%s] - OFFER [TX]", ifname));
+ } else if (dump_hex == 0x0103) {
+ DHD_ERROR(("DHCP[%s] - REQUEST [TX]", ifname));
+ } else if (dump_hex == 0x0105) {
+ DHD_ERROR(("DHCP[%s] - ACK [TX]", ifname));
+ } else {
+ DHD_ERROR(("DHCP[%s] - 0x%X [TX]", ifname, dump_hex));
+ }
+#ifdef DHD_LOSSLESS_ROAMING
+ if (dhdp->dequeue_prec_map != (uint8)ALLPRIO) {
+ DHD_ERROR(("/%d", dhdp->dequeue_prec_map));
+ }
+#endif /* DHD_LOSSLESS_ROAMING */
+ DHD_ERROR(("\n"));
+ } else if (source_port == 0x0043 || dest_port == 0x0043) {
+ DHD_ERROR(("DHCP[%s] - BOOTP [RX]\n", ifname));
+ }
+ }
+#endif /* DHD_DHCP_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 */
+ {
+#ifdef QOS_MAP_SET
+ pktsetprio_qms(pktbuf, wl_get_up_table(DHD_GET_CFG80211_PRIV(dhdp)), FALSE);
+#else
+ pktsetprio(pktbuf, FALSE);
+#endif /* QOS_MAP_SET */
+ }
+
+
+#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
+
+#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
+#if defined(DHD_8021X_DUMP)
+ ndev = dhd_idx2net(dhdp, ifidx);
+ dhd_tx_dump(ndev, dhdp->osh, 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 */
+
+ 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 (dhdp->busstate == DHD_BUS_DOWN ||
+ dhdp->busstate == DHD_BUS_DOWN_IN_PROGRESS) {
+ DHD_ERROR(("%s: returning as busstate=%d\n",
+ __FUNCTION__, dhdp->busstate));
+ DHD_GENERAL_UNLOCK(dhdp, flags);
+ PKTCFREE(dhdp->osh, pktbuf, TRUE);
+ return -ENODEV;
+ }
+ dhdp->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_SEND_PKT;
+ 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 */
+
+ ret = __dhd_sendpkt(dhdp, ifidx, pktbuf);
+
+#ifdef DHD_PCIE_RUNTIMEPM
+exit:
+#endif
+ DHD_GENERAL_LOCK(dhdp, flags);
+ dhdp->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_SEND_PKT;
+ DHD_GENERAL_UNLOCK(dhdp, flags);
+ return ret;
+}
+
+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;
+ }
+
+#ifdef PCIE_FULL_DONGLE
+ DHD_GENERAL_LOCK(&dhd->pub, flags);
+ dhd->pub.dhd_bus_busy_state |= DHD_BUS_BUSY_IN_TX;
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+#endif /* PCIE_FULL_DONGLE */
+
+#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->pub.dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_TX;
+ 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 PCIE_FULL_DONGLE
+ if (dhd->pub.busstate == DHD_BUS_SUSPEND) {
+ dhd->pub.dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_TX;
+ 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 /* PCIE_FULL_DONGLE */
+
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+ DHD_PERIM_LOCK_TRY(DHD_FWDER_UNIT(dhd), lock_taken);
+
+ /* Reject if down */
+ if (dhd->pub.hang_was_sent || dhd->pub.busstate == DHD_BUS_DOWN ||
+ dhd->pub.busstate == DHD_BUS_DOWN_IN_PROGRESS) {
+ 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_ERROR(("%s: Event HANG sent up\n", __FUNCTION__));
+ dhd->pub.hang_reason = HANG_REASON_BUS_DOWN;
+ net_os_send_hang_message(net);
+ }
+#ifdef PCIE_FULL_DONGLE
+ dhd->pub.dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_TX;
+ dhd_os_busbusy_wake(&dhd->pub);
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+#endif /* PCIE_FULL_DONGLE */
+ 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);
+ BUZZZ_LOG(START_XMIT_BGN, 2, (uint32)ifidx, (uintptr)skb);
+
+ if (ifidx == DHD_BAD_IF) {
+ DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx));
+ netif_stop_queue(net);
+#ifdef PCIE_FULL_DONGLE
+ dhd->pub.dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_TX;
+ dhd_os_busbusy_wake(&dhd->pub);
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+#endif /* PCIE_FULL_DONGLE */
+ 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__);
+ }
+
+ /* 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_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;
+#ifdef PCIE_FULL_DONGLE
+ unsigned long flags;
+#endif
+ 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) {
+ 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);
+
+#ifdef PCIE_FULL_DONGLE
+ DHD_GENERAL_LOCK(&dhd->pub, flags);
+ dhd->pub.dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_TX;
+ dhd_os_busbusy_wake(&dhd->pub);
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+#endif /* PCIE_FULL_DONGLE */
+ 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
+ */
+#ifdef PCIE_FULL_DONGLE
+ DHD_GENERAL_LOCK(&dhd->pub, flags);
+ dhd->pub.dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_TX;
+ dhd_os_busbusy_wake(&dhd->pub);
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+#endif /* PCIE_FULL_DONGLE */
+ 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 */
+
+ ret = __dhd_sendpkt(&dhd->pub, ifidx, pktbuf);
+
+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;
+ }
+ }
+
+#ifdef PCIE_FULL_DONGLE
+ DHD_GENERAL_LOCK(&dhd->pub, flags);
+ dhd->pub.dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_TX;
+ dhd_os_busbusy_wake(&dhd->pub);
+ DHD_GENERAL_UNLOCK(&dhd->pub, flags);
+#endif /* PCIE_FULL_DONGLE */
+
+ DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), lock_taken);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+ BUZZZ_LOG(START_XMIT_END, 0);
+
+ /* 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_RX_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" },
+#ifdef BCMWAPI_WAI
+ { ETHER_TYPE_WAI, "WAPI" },
+#endif /* BCMWAPI_WAI */
+ { 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;
+}
+#endif /* DHD_RX_DUMP */
+
+
+#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 */
+
+/** 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;
+#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) || defined(DHD_DHCP_DUMP)
+ char *dump_data;
+ uint16 protocol;
+ char *ifname;
+#endif /* DHD_RX_DUMP || DHD_8021X_DUMP || DHD_DHCP_DUMP */
+
+ 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);
+
+ 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_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_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;
+
+#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) || defined(DHD_DHCP_DUMP)
+ dump_data = skb->data;
+ protocol = (dump_data[12] << 8) | dump_data[13];
+ ifname = skb->dev ? skb->dev->name : "N/A";
+#endif /* DHD_RX_DUMP || DHD_8021X_DUMP || DHD_DHCP_DUMP */
+#ifdef DHD_8021X_DUMP
+ if (protocol == ETHER_TYPE_802_1X) {
+ dhd_dump_eapol_4way_message(ifname, dump_data, FALSE);
+ }
+#endif /* DHD_8021X_DUMP */
+#ifdef DHD_DHCP_DUMP
+ if (protocol != ETHER_TYPE_BRCM && protocol == ETHER_TYPE_IP) {
+ uint16 dump_hex;
+ uint16 source_port;
+ uint16 dest_port;
+ uint16 udp_port_pos;
+ uint8 *ptr8 = (uint8 *)&dump_data[ETHER_HDR_LEN];
+ uint8 ip_header_len = (*ptr8 & 0x0f)<<2;
+
+ udp_port_pos = ETHER_HDR_LEN + ip_header_len;
+ source_port = (dump_data[udp_port_pos] << 8) | dump_data[udp_port_pos+1];
+ dest_port = (dump_data[udp_port_pos+2] << 8) | dump_data[udp_port_pos+3];
+ if (source_port == 0x0044 || dest_port == 0x0044) {
+ dump_hex = (dump_data[udp_port_pos+249] << 8) |
+ dump_data[udp_port_pos+250];
+ if (dump_hex == 0x0101) {
+ DHD_ERROR(("DHCP[%s] - DISCOVER [RX]\n", ifname));
+ } else if (dump_hex == 0x0102) {
+ DHD_ERROR(("DHCP[%s] - OFFER [RX]\n", ifname));
+ } else if (dump_hex == 0x0103) {
+ DHD_ERROR(("DHCP[%s] - REQUEST [RX]\n", ifname));
+ } else if (dump_hex == 0x0105) {
+ DHD_ERROR(("DHCP[%s] - ACK [RX]\n", ifname));
+ } else {
+ DHD_ERROR(("DHCP[%s] - 0x%X [RX]\n", ifname, dump_hex));
+ }
+ } else if (source_port == 0x0043 || dest_port == 0x0043) {
+ DHD_ERROR(("DHCP[%s] - BOOTP [RX]\n", ifname));
+ }
+ }
+#endif /* DHD_DHCP_DUMP */
+#if defined(DHD_RX_DUMP)
+ DHD_ERROR(("RX DUMP[%s] - %s\n", ifname, _get_packet_type_str(protocol)));
+ if (protocol != ETHER_TYPE_BRCM) {
+ if (dump_data[0] == 0xFF) {
+ DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__));
+
+ if ((dump_data[12] == 8) &&
+ (dump_data[13] == 6)) {
+ DHD_ERROR(("%s: ARP %d\n",
+ __FUNCTION__, dump_data[0x15]));
+ }
+ } else if (dump_data[0] & 1) {
+ DHD_ERROR(("%s: MULTICAST: " MACDBG "\n",
+ __FUNCTION__, MAC2STRDBG(dump_data)));
+ }
+#ifdef DHD_RX_FULL_DUMP
+ {
+ int k;
+ for (k = 0; k < skb->len; k++) {
+ DHD_ERROR(("%02X ", dump_data[k]));
+ if ((k & 15) == 15)
+ DHD_ERROR(("\n"));
+ }
+ DHD_ERROR(("\n"));
+ }
+#endif /* DHD_RX_FULL_DUMP */
+ }
+#endif /* DHD_RX_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
+ /* 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) {
+ 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 > ETHER_TYPE_LEN ? len - ETHER_TYPE_LEN : 0,
+ &event,
+ &data);
+
+ wl_event_to_host_order(&event);
+ if (!tout_ctrl)
+ tout_ctrl = DHD_PACKET_TIMEOUT_MS;
+
+#if defined(PNO_SUPPORT)
+ if (event.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 */
+
+#ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT
+#ifdef DHD_USE_STATIC_CTRLBUF
+ PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE);
+#else
+ PKTFREE(dhdp->osh, pktbuf, FALSE);
+#endif /* DHD_USE_STATIC_CTRLBUF */
+ 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 */
+ }
+
+ ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
+ ifp = dhd->iflist[ifidx];
+
+ if (ifp->net)
+ ifp->net->last_rx = jiffies;
+
+ 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) && defined(DHD_LB_RXP)
+ netif_receive_skb(skb);
+#else
+ netif_rx(skb);
+#endif /* !defined(DHD_LB) && !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) && 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
+#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) && !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);
+ DHD_OS_WAKE_LOCK_TIMEOUT(dhdp);
+}
+
+void
+dhd_event(struct dhd_info *dhd, char *evpkt, uint 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__));
+
+ ifidx = dhd_net2idx(dhd, net);
+ if (ifidx == DHD_BAD_IF) {
+ DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__));
+
+ memset(&net->stats, 0, sizeof(net->stats));
+ return &net->stats;
+ }
+
+ ifp = dhd->iflist[ifidx];
+ ASSERT(dhd && ifp);
+
+ if (dhd->pub.up) {
+ /* Use the protocol to get dongle stats */
+ dhd_prot_dstats(&dhd->pub);
+ }
+ return &ifp->stats;
+}
+
+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, &param);
+ }
+
+ 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) {
+ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
+ break;
+ }
+
+ if (dhd->pub.dongle_reset == FALSE) {
+ DHD_TIMER(("%s:\n", __FUNCTION__));
+ dhd_bus_watchdog(&dhd->pub);
+
+ 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->pub.busstate == DHD_BUS_SUSPEND) {
+ DHD_ERROR(("%s wd while suspend in progress \n", __FUNCTION__));
+ 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);
+ 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)
+{
+ 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, &param);
+ } else {
+ if (get_scheduler_policy(current) != SCHED_FIFO) {
+ param.sched_priority = (prio < MAX_RT_PRIO)? prio : (MAX_RT_PRIO-1);
+ setScheduler(current, SCHED_FIFO, &param);
+ }
+ }
+}
+#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, &param);
+ }
+
+#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 (!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, &param);
+ }
+
+ DAEMONIZE("dhd_rxf");
+ /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */
+
+ /* signal: thread has started */
+ complete(&tsk->completed);
+#ifdef CUSTOM_SET_CPUCORE
+ dhd->pub.current_rxf = current;
+#endif /* CUSTOM_SET_CPUCORE */
+ /* Run until signal received */
+ while (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)
+{
+ dhd_info_t *dhd;
+
+ if (!dhdp || !dhdp->info)
+ return;
+ dhd = dhdp->info;
+
+#ifdef DHD_LB
+#ifdef DHD_LB_RXP
+ __skb_queue_head_init(&dhd->rx_pend_queue);
+#endif /* DHD_LB_RXP */
+#ifdef DHD_LB_TXC
+ if (atomic_read(&dhd->tx_compl_tasklet.count) == 1)
+ tasklet_enable(&dhd->tx_compl_tasklet);
+#endif /* DHD_LB_TXC */
+#ifdef DHD_LB_RXC
+ if (atomic_read(&dhd->rx_compl_tasklet.count) == 1)
+ tasklet_enable(&dhd->rx_compl_tasklet);
+#endif /* DHD_LB_RXC */
+#endif /* DHD_LB */
+ if (atomic_read(&dhd->tasklet.count) == 1)
+ tasklet_enable(&dhd->tasklet);
+}
+#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_disable(&dhd->tasklet);
+ tasklet_kill(&dhd->tasklet);
+ DHD_ERROR(("%s: tasklet disabled\n", __FUNCTION__));
+ }
+#if defined(DHD_LB)
+#ifdef DHD_LB_RXP
+ __skb_queue_purge(&dhd->rx_pend_queue);
+#endif /* DHD_LB_RXP */
+ /* Kill the Load Balancing Tasklets */
+#if defined(DHD_LB_TXC)
+ tasklet_disable(&dhd->tx_compl_tasklet);
+ tasklet_kill(&dhd->tx_compl_tasklet);
+#endif /* DHD_LB_TXC */
+#if defined(DHD_LB_RXC)
+ tasklet_disable(&dhd->rx_compl_tasklet);
+ tasklet_kill(&dhd->rx_compl_tasklet);
+#endif /* DHD_LB_RXC */
+#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 (dhd_bus_dpc(dhd->pub.bus)) {
+ DHD_LB_STATS_INCR(dhd->dhd_dpc_cnt);
+ 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);
+ }
+}
+
+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)
+{
+ wl_ioctl_t ioc;
+ char buf[32];
+ int ret;
+
+ memset(&ioc, 0, sizeof(ioc));
+
+ ioc.cmd = WLC_GET_VAR;
+ ioc.buf = buf;
+ ioc.len = (uint)sizeof(buf);
+ ioc.set = FALSE;
+
+ strncpy(buf, "toe_ol", sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
+ /* Check for older dongle image that doesn't support toe_ol */
+ 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)
+{
+ wl_ioctl_t ioc;
+ char buf[32];
+ int toe, ret;
+
+ memset(&ioc, 0, sizeof(ioc));
+
+ ioc.cmd = WLC_SET_VAR;
+ ioc.buf = buf;
+ ioc.len = (uint)sizeof(buf);
+ ioc.set = TRUE;
+
+ /* Set toe_ol as requested */
+
+ strncpy(buf, "toe_ol", sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+ memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32));
+
+ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 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);
+
+ strcpy(buf, "toe");
+ memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32));
+
+ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 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)
+{
+ int ret = 0;
+ wl_scb_probe_t scb_probe;
+ char iovbuf[WL_EVENTING_MASK_LEN + sizeof(wl_scb_probe_t)];
+
+ memset(&scb_probe, 0, sizeof(wl_scb_probe_t));
+
+ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
+ return;
+ }
+
+ bcm_mkiovar("scb_probe", NULL, 0, iovbuf, sizeof(iovbuf));
+
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) {
+ DHD_ERROR(("%s: GET max_scb_probe failed\n", __FUNCTION__));
+ }
+
+ memcpy(&scb_probe, iovbuf, sizeof(wl_scb_probe_t));
+
+ scb_probe.scb_max_probe = NUM_SCB_MAX_PROBE;
+
+ bcm_mkiovar("scb_probe", (char *)&scb_probe,
+ sizeof(wl_scb_probe_t), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 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)
+ if (dhdp->info->thr_dpc_ctl.thr_pid < 0) {
+ DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__));
+ return FALSE;
+ }
+#endif
+
+ 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;
+ }
+ }
+ net_os_send_hang_message(net);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+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;
+
+ net = dhd_idx2net(pub, ifidx);
+ if (!net) {
+ bcmerror = BCME_BADARG;
+ goto done;
+ }
+
+ if (data_buf)
+ buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN);
+
+ /* check for local dhd ioctl and handle it */
+ if (ioc->driver == DHD_IOCTL_MAGIC) {
+ bcmerror = dhd_ioctl((void *)pub, ioc, data_buf, buflen);
+ if (bcmerror)
+ pub->bcmerror = bcmerror;
+ goto done;
+ }
+
+ /* send to dongle (must be up, and wl). */
+ if (pub->busstate == DHD_BUS_DOWN || pub->busstate == DHD_BUS_LOAD) {
+ if (allow_delay_fwdl) {
+ int 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;
+ }
+
+ /*
+ * 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;
+ }
+
+#ifdef DHD_DEBUG
+ if (ioc->cmd != WLC_GET_MAGIC && ioc->cmd != WLC_GET_VERSION) {
+ if (ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) {
+ /* Print IOVAR Information */
+ DHD_IOV_INFO(("%s: IOVAR_INFO name = %s set = %d\n",
+ __FUNCTION__, (char *)data_buf, ioc->set));
+ if ((dhd_msg_level & DHD_IOV_INFO_VAL) && ioc->set && data_buf) {
+ prhex(NULL, data_buf + strlen(data_buf) + 1,
+ buflen - strlen(data_buf) - 1);
+ }
+ } else {
+ /* Print IOCTL Information */
+ DHD_IOV_INFO(("%s: IOCTL_INFO cmd = %d set = %d\n",
+ __FUNCTION__, ioc->cmd, ioc->set));
+ if ((dhd_msg_level & DHD_IOV_INFO_VAL) && ioc->set && data_buf) {
+ prhex(NULL, data_buf, buflen);
+ }
+ }
+ }
+#endif /* DHD_DEBUG */
+
+ bcmerror = dhd_wl_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen);
+
+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 ifidx;
+ int ret;
+ void *local_buf = NULL;
+ u16 buflen = 0;
+#ifdef ENABLE_INSMOD_NO_FW_LOAD
+ allow_delay_fwdl = 1;
+#endif
+
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+ DHD_PERIM_LOCK(&dhd->pub);
+
+#ifndef ENABLE_INSMOD_NO_FW_LOAD
+ /* Interface up check for built-in type */
+ if (!dhd_download_fw_on_driverload && dhd->pub.up == FALSE) {
+ DHD_TRACE(("%s: Interface is down \n", __FUNCTION__));
+ ret = BCME_NOTUP;
+ goto exit;
+ }
+#endif
+
+ /* send to dongle only if we are not waiting for reload already */
+ if (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);
+ ret = BCME_DONGLE_DOWN;
+ goto exit;
+ }
+
+ 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__));
+ ret = -1;
+ goto exit;
+ }
+
+#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);
+ goto exit;
+ }
+#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);
+ goto exit;
+ }
+#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);
+ goto exit;
+ }
+
+ if (cmd != SIOCDEVPRIVATE) {
+ ret = -EOPNOTSUPP;
+ goto exit;
+ }
+
+ memset(&ioc, 0, sizeof(ioc));
+
+#ifdef CONFIG_COMPAT
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)) || ((LINUX_VERSION_CODE >= \
+ KERNEL_VERSION(4, 6, 0)) && !defined(__X86)))
+ if (is_compat_task()) {
+ compat_wl_ioctl_t compat_ioc;
+ if (copy_from_user(&compat_ioc, ifr->ifr_data, sizeof(compat_wl_ioctl_t))) {
+ ret = BCME_BADADDR;
+ goto done;
+ }
+ ioc.cmd = compat_ioc.cmd;
+ 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)) {
+ ret = BCME_BADADDR;
+ goto done;
+ }
+ } else
+#endif /* LINUX_VER < 4.6 || (LINUX_VER >= 4.6 && !defined(__X86)) */
+#endif /* CONFIG_COMPAT */
+ {
+ /* Copy the ioc control structure part of ioctl request */
+ if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) {
+ ret = BCME_BADADDR;
+ goto done;
+ }
+
+ /* 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)) {
+ ret = BCME_BADADDR;
+ goto done;
+ }
+ }
+
+ if (!capable(CAP_NET_ADMIN)) {
+ ret = BCME_EPERM;
+ goto done;
+ }
+
+ if (ioc.len > 0) {
+ buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN);
+ if (!(local_buf = MALLOC(dhd->pub.osh, buflen+1))) {
+ ret = BCME_NOMEM;
+ goto done;
+ }
+
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ if (copy_from_user(local_buf, ioc.buf, buflen)) {
+ DHD_PERIM_LOCK(&dhd->pub);
+ ret = BCME_BADADDR;
+ goto done;
+ }
+ DHD_PERIM_LOCK(&dhd->pub);
+
+ *(char *)(local_buf + buflen) = '\0';
+ }
+
+ ret = dhd_ioctl_process(&dhd->pub, ifidx, &ioc, local_buf);
+
+ if (!ret && buflen && local_buf && ioc.buf) {
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ if (copy_to_user(ioc.buf, local_buf, buflen))
+ ret = -EFAULT;
+ DHD_PERIM_LOCK(&dhd->pub);
+ }
+
+done:
+ if (local_buf)
+ MFREE(dhd->pub.osh, local_buf, buflen+1);
+
+exit:
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+
+ return OSL_ERROR(ret);
+}
+
+
+#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 */
+
+static int
+dhd_stop(struct net_device *net)
+{
+ int ifidx = 0;
+ dhd_info_t *dhd = DHD_DEV_INFO(net);
+ DHD_OS_WAKE_LOCK(&dhd->pub);
+ DHD_PERIM_LOCK(&dhd->pub);
+ DHD_TRACE(("%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;
+ }
+
+ 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);
+ dhd->pub.up = 0;
+
+#ifdef WL_CFG80211
+ if (ifidx == 0) {
+ dhd_if_t *ifp;
+ wl_cfg80211_down(DHD_GET_CFG80211_PRIV(&dhd->pub));
+
+ 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(DHD_GET_CFG80211_PRIV(&dhd->pub));
+#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);
+ }
+ cancel_work_sync(dhd->dhd_deferred_wq);
+#if defined(DHD_LB) && defined(DHD_LB_RXP)
+ __skb_queue_purge(&dhd->rx_pend_queue);
+#endif /* DHD_LB && DHD_LB_RXP */
+ }
+
+#if defined(BCMPCIE) && defined(DHDTCPACK_SUPPRESS)
+ dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF);
+#endif /* BCMPCIE && DHDTCPACK_SUPPRESS */
+#if defined(DHD_LB) && 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 && DHD_LB_RXP */
+
+ }
+#endif /* WL_CFG80211 */
+
+#ifdef PROP_TXSTATUS
+ dhd_wlfc_cleanup(&dhd->pub, NULL, 0);
+#endif
+ /* Stop the protocol module */
+ dhd_prot_stop(&dhd->pub);
+
+ OLD_MOD_DEC_USE_COUNT;
+exit:
+#if defined(WL_CFG80211)
+ if (ifidx == 0 && !dhd_download_fw_on_driverload)
+ wl_android_wifi_off(net, TRUE);
+#endif
+ 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_dbg_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;
+ }
+
+ 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)
+{
+ char iovbuf[WLC_IOCTL_SMLEN];
+ uint32 enable = true;
+ int ret = BCME_OK;
+
+ bcm_mkiovar("interworking", (char *)&enable, sizeof(enable), iovbuf, sizeof(iovbuf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ if (ret < 0) {
+ DHD_ERROR(("%s: enableing interworking failed, ret=%d\n", __FUNCTION__, ret));
+ }
+
+ if (ret == BCME_OK) {
+ /* basic capabilities for HS20 REL2 */
+ uint32 cap = WL_WNM_BSSTRANS | WL_WNM_NOTIF;
+ bcm_mkiovar("wnm", (char *)&cap, sizeof(cap), iovbuf, sizeof(iovbuf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ if (ret < 0) {
+ DHD_ERROR(("%s: set wnm returned (%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 (!dhd_download_fw_on_driverload && !dhd_driver_init_done) {
+ DHD_ERROR(("%s: WLAN driver is not initialized\n", __FUNCTION__));
+ return -1;
+ }
+
+ /* Init wakelock */
+ if (!dhd_download_fw_on_driverload &&
+ !(dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) {
+ DHD_OS_WAKE_LOCK_INIT(dhd);
+ dhd->dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT;
+ }
+
+#ifdef 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 {
+ 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 !defined(WL_CFG80211)
+ /*
+ * Force start if ifconfig_up gets called before START command
+ * We keep WEXT's wl_control_wl_start to provide backward compatibility
+ * This should be removed in the future
+ */
+ 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 defined(WL_CFG80211)
+ if (!dhd_download_fw_on_driverload) {
+ DHD_ERROR(("\n%s\n", dhd_version));
+#if defined(USE_INITIAL_SHORT_DWELL_TIME)
+ g_first_broadcast_scan = TRUE;
+#endif
+ ret = wl_android_wifi_on(net);
+ 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 */
+#endif
+
+ if (dhd->pub.busstate != DHD_BUS_DATA) {
+
+ /* 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;
+ }
+
+ }
+
+#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 */
+
+ /* 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(WL_CFG80211)
+ if (unlikely(wl_cfg80211_up(DHD_GET_CFG80211_PRIV(&dhd->pub)))) {
+ 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 */
+#ifdef DHD_LB
+ DHD_LB_STATS_INIT(&dhd->pub);
+#ifdef DHD_LB_RXP
+ __skb_queue_head_init(&dhd->rx_pend_queue);
+#endif /* DHD_LB_RXP */
+#endif /* DHD_LB */
+ }
+
+#if defined(BCMPCIE) && defined(DHDTCPACK_SUPPRESS)
+#if defined(SET_RPS_CPUS)
+ dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF);
+#else
+ dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_HOLD);
+#endif
+#endif /* BCMPCIE && DHDTCPACK_SUPPRESS */
+#if defined(DHD_LB) && defined(DHD_LB_RXP)
+ 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);
+ }
+#endif /* DHD_LB && DHD_LB_RXP */
+#if defined(NUM_SCB_MAX_PROBE)
+ dhd_set_scb_probe(&dhd->pub);
+#endif /* NUM_SCB_MAX_PROBE */
+#endif /* WL_CFG80211 */
+ }
+
+ /* Allow transmit calls */
+ netif_start_queue(net);
+ dhd->pub.up = 1;
+
+ OLD_MOD_INC_USE_COUNT;
+
+#ifdef BCMDBGFS
+ dhd_dbg_init(&dhd->pub);
+#endif
+
+exit:
+ if (ret) {
+ dhd_stop(net);
+ }
+
+ DHD_PERIM_UNLOCK(&dhd->pub);
+ DHD_OS_WAKE_UNLOCK(&dhd->pub);
+
+
+ return ret;
+}
+
+int dhd_do_driver_init(struct net_device *net)
+{
+ dhd_info_t *dhd = NULL;
+
+ if (!net) {
+ DHD_ERROR(("Primary Interface not initialized \n"));
+ return -EINVAL;
+ }
+
+
+ /* && 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_GET_CFG80211_PRIV(&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_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_GET_CFG80211_PRIV(&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_WORK_PRIORITY_LOW);
+
+ 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, char *name,
+ uint8 *mac, uint8 bssidx, bool need_rtnl_lock, 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\n", __FUNCTION__, ifp->net->name));
+
+ 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;
+ 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';
+ }
+
+#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
+ 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
+ return ifp->net;
+
+fail:
+
+ if (ifp != NULL) {
+ if (ifp->net != NULL) {
+ 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;
+
+ ifp = dhdinfo->iflist[ifidx];
+
+ if (ifp != NULL) {
+ if (ifp->net != NULL) {
+ DHD_ERROR(("deleting interface '%s' idx %d\n", ifp->net->name, ifp->idx));
+
+ /* 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 defined(SET_RPS_CPUS)
+#if (defined(DHDTCPACK_SUPPRESS) && defined(BCMPCIE))
+ dhd_tcpack_suppress_set(dhdpub, TCPACK_SUP_OFF);
+#endif /* DHDTCPACK_SUPPRESS && BCMPCIE */
+#endif
+ if (need_rtnl_lock)
+ unregister_netdev(ifp->net);
+ else
+ unregister_netdevice(ifp->net);
+ }
+ ifp->net = NULL;
+ dhdinfo->iflist[ifidx] = 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);
+
+ 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
+static char *logstrs_path = "/root/logstrs.bin";
+static char *st_str_file_path = "/root/rtecdc.bin";
+static char *map_file_path = "/root/rtecdc.map";
+static char *rom_st_str_file_path = "/root/roml.bin";
+static char *rom_map_file_path = "/root/roml.map";
+
+#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 */
+static char *ram_file_str = "rtecdc";
+static char *rom_file_str = "roml";
+#define RAMSTART_BIT 0x01
+#define RDSTART_BIT 0x02
+#define RDEND_BIT 0x04
+#define ALL_MAP_VAL (RAMSTART_BIT | RDSTART_BIT | RDEND_BIT)
+
+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 void
+dhd_init_logstrs_array(dhd_event_log_t *temp)
+{
+ struct file *filep = NULL;
+ struct kstat stat;
+ mm_segment_t fs;
+ char *raw_fmts = NULL;
+ int logstrs_size = 0;
+
+ logstr_header_t *hdr = NULL;
+ uint32 *lognums = NULL;
+ char *logstrs = NULL;
+ int ram_index = 0;
+ char **fmts;
+ int num_fmts = 0;
+ uint32 i = 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;
+
+ raw_fmts = kmalloc(logstrs_size, GFP_KERNEL);
+ 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", __FUNCTION__, logstrs_path));
+ goto fail;
+ }
+
+ /* 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 = kmalloc(num_fmts * sizeof(char *), GFP_KERNEL);
+ if (fmts == NULL) {
+ DHD_ERROR(("Failed to allocate fmts memory"));
+ goto fail;
+ }
+
+ 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]];
+ }
+ temp->fmts = fmts;
+ temp->raw_fmts = raw_fmts;
+ temp->num_fmts = num_fmts;
+ filp_close(filep, NULL);
+ set_fs(fs);
+ return;
+fail:
+ if (raw_fmts) {
+ kfree(raw_fmts);
+ raw_fmts = NULL;
+ }
+ if (!IS_ERR(filep))
+ filp_close(filep, NULL);
+ set_fs(fs);
+ temp->fmts = NULL;
+ return;
+}
+
+static int
+dhd_read_map(char *fname, uint32 *ramstart, uint32 *rodata_start,
+ uint32 *rodata_end)
+{
+ struct file *filep = NULL;
+ mm_segment_t fs;
+ 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;
+
+ 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;
+ }
+
+ /* Allocate 1 byte more than read_size to terminate it with NULL */
+ raw_fmts = kmalloc(read_size + 1, GFP_KERNEL);
+ 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 = vfs_read(filep, raw_fmts, read_size, (&filep->f_pos));
+ if (error < 0) {
+ DHD_ERROR(("%s: read failed %s err:%d \n", __FUNCTION__,
+ map_file_path, error));
+ goto fail;
+ }
+
+ if (error < read_size) {
+ /*
+ * since we reset file pos back to earlier pos by
+ * GO_BACK_FILE_POS_NUM_BYTES bytes we won't reach EOF.
+ * So if ret value is less than read_size, reached EOF don't read further
+ */
+ break;
+ }
+ /* 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;
+ }
+ 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.
+ */
+ filep->f_pos = filep->f_pos - GO_BACK_FILE_POS_NUM_BYTES;
+ }
+
+ DHD_ERROR(("---ramstart: 0x%x, rodata_start: 0x%x, rodata_end:0x%x\n",
+ *ramstart, *rodata_start, *rodata_end));
+
+ DHD_ERROR(("readmap over \n"));
+
+fail:
+ if (raw_fmts) {
+ kfree(raw_fmts);
+ raw_fmts = NULL;
+ }
+ if (!IS_ERR(filep))
+ filp_close(filep, NULL);
+
+ set_fs(fs);
+ if (count == ALL_MAP_VAL) {
+ return BCME_OK;
+ }
+ DHD_ERROR(("readmap error 0X%x \n", count));
+ return BCME_ERROR;
+}
+
+static void
+dhd_init_static_strs_array(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(map_file, &ramstart, &rodata_start, &rodata_end);
+ if (error == BCME_ERROR) {
+ 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;
+ }
+ 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;
+
+ raw_fmts = kmalloc(logstrs_size, GFP_KERNEL);
+ 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->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_ramstart = ramstart;
+ temp->rom_rodata_start = rodata_start;
+ temp->rom_rodata_end = rodata_end;
+ }
+
+ filp_close(filep, NULL);
+ set_fs(fs);
+
+ return;
+fail:
+ if (raw_fmts) {
+ kfree(raw_fmts);
+ raw_fmts = NULL;
+ }
+ 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;
+}
+
+#endif /* SHOW_LOGTRACE */
+
+
+dhd_pub_t *
+dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen)
+{
+ dhd_info_t *dhd = NULL;
+ struct net_device *net = NULL;
+ char if_name[IFNAMSIZ] = {'\0'};
+ uint32 bus_type = -1;
+ uint32 bus_num = -1;
+ uint32 slot_num = -1;
+ wifi_adapter_info_t *adapter = NULL;
+
+ 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
+ adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num);
+
+ /* 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 fail;
+ }
+ }
+ 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;
+ dhd->adapter = adapter;
+
+#ifdef OOB_PARAM
+ dhd->pub.oob_disable = adapter->oob_disable;
+#endif /* OOB_PARAM */
+
+#ifdef GET_CUSTOM_MAC_ENABLE
+ wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet);
+#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 */
+ dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID;
+ dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID;
+
+ /* Initialize thread based operation and lock */
+ sema_init(&dhd->sdsem, 1);
+
+ /* 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);
+
+ /* Link to info module */
+ dhd->pub.info = dhd;
+
+
+ /* Link to bus module */
+ dhd->pub.bus = bus;
+ dhd->pub.hdrlen = bus_hdrlen;
+
+ /* 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))
+ strcat(if_name, "%d");
+ }
+
+ /* 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 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);
+ 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->dhd_lock);
+ spin_lock_init(&dhd->rxf_lock);
+#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_wd_counter = 0;
+#ifdef CONFIG_HAS_WAKELOCK
+ 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);
+#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 WL_CFG80211
+ /* Attach and link in the cfg80211 */
+ dhd->pub.cfg80211_priv = wl_cfg80211_attach(net, &dhd->pub);
+ if (dhd->pub.cfg80211_priv == NULL) {
+ 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_WIRELESS_EXT)
+ /* Attach and link in the iw */
+ if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) {
+ if (wl_iw_attach(net, (void *)&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
+ dhd_init_logstrs_array(&dhd->event_data);
+ dhd_init_static_strs_array(&dhd->event_data, st_str_file_path, map_file_path);
+ dhd_init_static_strs_array(&dhd->event_data, rom_st_str_file_path, rom_map_file_path);
+#endif /* SHOW_LOGTRACE */
+
+ 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;
+ }
+
+
+
+ /* Set up the watchdog timer */
+ init_timer(&dhd->timer);
+ dhd->timer.data = (ulong)dhd;
+ dhd->timer.function = dhd_watchdog;
+ 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(&dhd->rpm_timer);
+ dhd->rpm_timer.data = (ulong)dhd;
+ dhd->rpm_timer.function = dhd_runtimepm;
+ 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;
+ }
+ }
+
+ 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
+#ifdef BCMSDIO
+ dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_DELAYTX);
+#elif defined(BCMPCIE)
+ dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_HOLD);
+#else
+ dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF);
+#endif /* BCMSDIO */
+#endif /* DHDTCPACK_SUPPRESS */
+
+#if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW)
+#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */
+
+ dhd_state |= DHD_ATTACH_STATE_DONE;
+ dhd->dhd_state = dhd_state;
+
+ dhd_found++;
+#ifdef DHD_DEBUG_PAGEALLOC
+ register_page_corrupt_cb(dhd_page_corrupt_cb, &dhd->pub);
+#endif /* DHD_DEBUG_PAGEALLOC */
+
+#if defined(DHD_LB)
+ DHD_ERROR(("DHD LOAD BALANCING Enabled\n"));
+
+ 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_cpu_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__));
+ }
+
+
+ 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));
+ INIT_WORK(&dhd->rx_compl_dispatcher_work, dhd_rx_compl_dispatcher_fn);
+ 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 */
+
+#endif /* DHD_LB */
+
+ INIT_DELAYED_WORK(&dhd->dhd_memdump_work, dhd_memdump_work_handler);
+
+ (void)dhd_sysfs_init(dhd);
+
+ 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);
+ }
+
+ return NULL;
+}
+
+#include <linux/delay.h>
+
+void dhd_memdump_work_schedule(dhd_pub_t *dhdp, unsigned long msecs)
+{
+ dhd_info_t *dhd = (dhd_info_t*)dhdp->info;
+
+ schedule_delayed_work(&dhd->dhd_memdump_work, msecs_to_jiffies(msecs));
+}
+
+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;
+}
+
+bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo)
+{
+ int fw_len;
+ int nv_len;
+ const char *fw = NULL;
+ const char *nv = NULL;
+ wifi_adapter_info_t *adapter = dhdinfo->adapter;
+
+
+ /* 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 (adapter && adapter->fw_path && adapter->fw_path[0] != '\0')
+ fw = adapter->fw_path;
+
+ if (adapter && adapter->nv_path && adapter->nv_path[0] != '\0')
+ nv = adapter->nv_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 (fw && fw[0] != '\0') {
+ fw_len = strlen(fw);
+ if (fw_len >= sizeof(dhdinfo->fw_path)) {
+ DHD_ERROR(("fw path len exceeds max len of dhdinfo->fw_path\n"));
+ return FALSE;
+ }
+ strncpy(dhdinfo->fw_path, fw, sizeof(dhdinfo->fw_path));
+ 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 >= sizeof(dhdinfo->nv_path)) {
+ DHD_ERROR(("nvram path len exceeds max len of dhdinfo->nv_path\n"));
+ return FALSE;
+ }
+ strncpy(dhdinfo->nv_path, nv, sizeof(dhdinfo->nv_path));
+ if (dhdinfo->nv_path[nv_len-1] == '\n')
+ dhdinfo->nv_path[nv_len-1] = '\0';
+ }
+
+ /* clear the path in module parameter */
+ if (dhd_download_fw_on_driverload) {
+ firmware_path[0] = '\0';
+ nvram_path[0] = '\0';
+ }
+#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;
+}
+
+#ifdef CUSTOMER_HW4_DEBUG
+bool dhd_validate_chipid(dhd_pub_t *dhdp)
+{
+ uint chipid = dhd_bus_chip_id(dhdp);
+ uint config_chipid;
+
+#ifdef 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(BCM4356_CHIP)
+ config_chipid = BCM4356_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(BCM4334W_CHIP)
+ config_chipid = BCM43342_CHIP_ID;
+#elif defined(BCM43455_CHIP)
+ config_chipid = BCM4345_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 */
+
+#if defined(BCM4359_CHIP)
+ if (chipid == BCM4355_CHIP_ID && config_chipid == BCM4359_CHIP_ID) {
+ return TRUE;
+ }
+#endif /* BCM4359_CHIP */
+
+ return config_chipid == chipid;
+}
+#endif /* CUSTOMER_HW4_DEBUG */
+
+int
+dhd_bus_start(dhd_pub_t *dhdp)
+{
+ int ret = -1;
+ dhd_info_t *dhd = (dhd_info_t*)dhdp->info;
+ unsigned long flags;
+
+ ASSERT(dhd);
+
+ DHD_TRACE(("Enter %s:\n", __FUNCTION__));
+
+ DHD_PERIM_LOCK(dhdp);
+
+ /* 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.is_fw_download_done = FALSE;
+ DHD_INFO(("%s download fw %s, nv %s\n", __FUNCTION__, dhd->fw_path, dhd->nv_path));
+ ret = dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh,
+ dhd->fw_path, dhd->nv_path);
+ 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.is_fw_download_done = TRUE;
+ }
+ if (dhd->pub.busstate != DHD_BUS_LOAD) {
+ DHD_PERIM_UNLOCK(dhdp);
+ return -ENETDOWN;
+ }
+
+ dhd_os_sdlock(dhdp);
+
+ /* Start the watchdog timer */
+ dhd->pub.tickcnt = 0;
+ dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms);
+ DHD_ENABLE_RUNTIME_PM(&dhd->pub);
+
+ /* Bring up the bus */
+ if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) {
+
+ DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret));
+ dhd_os_sdunlock(dhdp);
+ DHD_PERIM_UNLOCK(dhdp);
+ return ret;
+ }
+#if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE)
+ OOB_PARAM_IF(!(dhd->pub.oob_disable)) {
+#if defined(BCMPCIE_OOB_HOST_WAKE)
+ dhd_os_sdunlock(dhdp);
+#endif /* 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);
+
+ dhd_os_sdunlock(dhdp);
+#endif /* !BCMPCIE_OOB_HOST_WAKE */
+ DHD_DISABLE_RUNTIME_PM(&dhd->pub);
+ DHD_PERIM_UNLOCK(dhdp);
+ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
+ DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__));
+ return -ENODEV;
+ }
+
+#if defined(BCMPCIE_OOB_HOST_WAKE)
+ dhd_os_sdlock(dhdp);
+ 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 */
+ }
+#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) {
+ dhd_os_sdunlock(dhdp);
+ DHD_PERIM_UNLOCK(dhdp);
+ return ret;
+ }
+ }
+#endif /* PCIE_FULL_DONGLE */
+
+ /* Do protocol initialization necessary for IOCTL/IOVAR */
+#ifdef PCIE_FULL_DONGLE
+ dhd_os_sdunlock(dhdp);
+#endif /* PCIE_FULL_DONGLE */
+ ret = dhd_prot_init(&dhd->pub);
+ if (unlikely(ret) != BCME_OK) {
+ DHD_PERIM_UNLOCK(dhdp);
+ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
+ return ret;
+ }
+#ifdef PCIE_FULL_DONGLE
+ dhd_os_sdlock(dhdp);
+#endif /* PCIE_FULL_DONGLE */
+
+ /* 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);
+ dhd_os_sdunlock(dhdp);
+ DHD_PERIM_UNLOCK(dhdp);
+ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
+ return -ENODEV;
+ }
+
+ dhd_os_sdunlock(dhdp);
+
+ /* Bus is ready, query any dongle information */
+ 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_DISABLE_RUNTIME_PM(&dhd->pub);
+ DHD_OS_WD_WAKE_UNLOCK(&dhd->pub);
+ DHD_PERIM_UNLOCK(dhdp);
+ return ret;
+ }
+
+#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 */
+
+ DHD_PERIM_UNLOCK(dhdp);
+ return 0;
+}
+#ifdef WLTDLS
+int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac)
+{
+ char iovbuf[WLC_IOCTL_SMLEN];
+ 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;
+ bcm_mkiovar("tdls_enable", (char *)&tdls, sizeof(tdls), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 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;
+ bcm_mkiovar("tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op),
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret));
+ goto exit;
+ }
+
+ if (tdls_auto_op) {
+ bcm_mkiovar("tdls_idle_time", (char *)&tdls_idle_time,
+ sizeof(tdls_idle_time), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret));
+ goto exit;
+ }
+ bcm_mkiovar("tdls_rssi_high", (char *)&tdls_rssi_high, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s: tdls_rssi_high failed %d\n", __FUNCTION__, ret));
+ goto exit;
+ }
+ bcm_mkiovar("tdls_rssi_low", (char *)&tdls_rssi_low, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 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)
+{
+ char iovbuf[WLC_IOCTL_SMLEN];
+ 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;
+ }
+
+
+ bcm_mkiovar("tdls_wfd_mode", (char *)&mode, sizeof(mode),
+ iovbuf, sizeof(iovbuf));
+ if (((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 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
+void dhd_tdls_update_peer_info(struct net_device *dev, bool connect, uint8 *da)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ dhd_pub_t *dhdp = (dhd_pub_t *)&dhd->pub;
+ tdls_peer_node_t *cur = dhdp->peer_tbl.node;
+ tdls_peer_node_t *new = NULL, *prev = NULL;
+ dhd_if_t *dhdif;
+ uint8 sa[ETHER_ADDR_LEN];
+ int ifidx = dhd_net2idx(dhd, dev);
+
+ if (ifidx == DHD_BAD_IF)
+ return;
+
+ dhdif = dhd->iflist[ifidx];
+ memcpy(sa, dhdif->mac_addr, ETHER_ADDR_LEN);
+
+ 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;
+ }
+ cur = cur->next;
+ }
+
+ new = MALLOC(dhdp->osh, sizeof(tdls_peer_node_t));
+ if (new == NULL) {
+ DHD_ERROR(("%s: Failed to allocate memory\n", __FUNCTION__));
+ return;
+ }
+ memcpy(new->addr, da, ETHER_ADDR_LEN);
+ new->next = dhdp->peer_tbl.node;
+ dhdp->peer_tbl.node = new;
+ dhdp->peer_tbl.tdls_peer_count++;
+
+ } else {
+ while (cur != NULL) {
+ if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) {
+ dhd_flow_rings_delete_for_peer(dhdp, ifidx, da);
+ if (prev)
+ prev->next = cur->next;
+ else
+ dhdp->peer_tbl.node = cur->next;
+ MFREE(dhdp->osh, cur, sizeof(tdls_peer_node_t));
+ dhdp->peer_tbl.tdls_peer_count--;
+ return;
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+ DHD_ERROR(("%s: TDLS Peer Entry Not found\n", __FUNCTION__));
+ }
+}
+#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));
+ bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
+ FALSE, 0)) < 0) {
+ DHD_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;
+ ret |= DHD_FLAG_MP2P_MODE;
+ /* @TODO Need to refine the usage of this flag
+ * based on firmware limitation of MP2P
+ */
+ }
+ if (FW_SUPPORTED(dhd, mp2p)) {
+ ret |= DHD_FLAG_MP2P_MODE;
+ }
+#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)
+{
+ char iovbuf[128];
+ int32 pps = RXCHAIN_PWRSAVE_PPS;
+ int32 quiet_time = RXCHAIN_PWRSAVE_QUIET_TIME;
+ int32 stas_assoc_check = RXCHAIN_PWRSAVE_STAS_ASSOC_CHECK;
+
+ if (enable) {
+ bcm_mkiovar("rxchain_pwrsave_enable", (char *)&enable, 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
+ DHD_ERROR(("Failed to enable AP power save"));
+ }
+ bcm_mkiovar("rxchain_pwrsave_pps", (char *)&pps, 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
+ DHD_ERROR(("Failed to set pps"));
+ }
+ bcm_mkiovar("rxchain_pwrsave_quiet_time", (char *)&quiet_time,
+ 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
+ DHD_ERROR(("Failed to set quiet time"));
+ }
+ bcm_mkiovar("rxchain_pwrsave_stas_assoc_check", (char *)&stas_assoc_check,
+ 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
+ DHD_ERROR(("Failed to set stas assoc check"));
+ }
+ } else {
+ bcm_mkiovar("rxchain_pwrsave_enable", (char *)&enable, 4, iovbuf, sizeof(iovbuf));
+ if (dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0) != BCME_OK) {
+ DHD_ERROR(("Failed to disable AP power save"));
+ }
+ }
+
+ return 0;
+}
+#endif /* SUPPORT_AP_POWERSAVE */
+
+
+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;
+#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)
+#ifdef PROP_TXSTATUS
+ int wlfc_enable = TRUE;
+#ifndef DISABLE_11N
+ uint32 hostreorder = 1;
+#endif /* DISABLE_11N */
+#endif /* PROP_TXSTATUS */
+#endif
+#ifdef PCIE_FULL_DONGLE
+ uint32 wl_ap_isolate;
+#endif /* PCIE_FULL_DONGLE */
+
+#if defined(BCMSDIO)
+ /* by default frame burst is enabled for PCIe and disabled for SDIO dongles */
+ uint32 frameburst = 0;
+#else
+ uint32 frameburst = 1;
+#endif /* BCMSDIO */
+
+#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
+#if defined(VSDB) || defined(ROAM_ENABLE)
+ uint bcn_timeout = CUSTOM_BCN_TIMEOUT;
+#else
+ uint bcn_timeout = 4;
+#endif /* VSDB || ROAM_ENABLE */
+#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 */
+#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 */
+#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))
+ uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
+ 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;
+#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 */
+#if defined(PROP_TXSTATUS)
+#ifdef USE_WFA_CERT_CONF
+ uint32 proptx = 0;
+#endif /* USE_WFA_CERT_CONF */
+#endif /* PROP_TXSTATUS */
+#ifdef CUSTOM_PSPRETEND_THR
+ uint32 pspretend_thr = CUSTOM_PSPRETEND_THR;
+#endif
+ 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 CUSTOM_EVENT_PM_WAKE
+ uint32 pm_awake_thresh = CUSTOM_EVENT_PM_WAKE;
+#endif /* CUSTOM_EVENT_PM_WAKE */
+#ifdef PKT_FILTER_SUPPORT
+ dhd_pkt_filter_enable = TRUE;
+#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 */
+ DHD_TRACE(("Enter %s\n", __FUNCTION__));
+ dhd->op_mode = 0;
+#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)) {
+#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
+ ret = wifi_platform_get_mac_addr(dhd->info->adapter, ea_addr.octet);
+ if (!ret) {
+ memset(buf, 0, sizeof(buf));
+ bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
+ if (ret < 0) {
+ DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
+ ret = BCME_NOTUP;
+ goto done;
+ }
+ memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN);
+ } else {
+#endif /* GET_CUSTOM_MAC_ENABLE */
+ /* Get the default device MAC address directly from firmware */
+ 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);
+
+#ifdef GET_CUSTOM_MAC_ENABLE
+ }
+#endif /* GET_CUSTOM_MAC_ENABLE */
+
+#ifdef DHD_USE_CLMINFO_PARSER
+ if ((ret = dhd_get_clminfo(dhd, clm_path)) < 0) {
+ DHD_ERROR(("%s: CLM Information load failed. Abort initialization.\n",
+ __FUNCTION__));
+ goto done;
+ }
+#endif /* DHD_USE_CLMINFO_PARSER */
+ if ((ret = dhd_apply_default_clm(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);
+ bcm_mkiovar("cap", 0, 0, dhd->fw_capabilities, cap_buf_size - 1);
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, dhd->fw_capabilities,
+ (cap_buf_size - 1), FALSE, 0)) < 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
+ 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);
+
+ bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
+ if (ret < 0) {
+ DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
+ } else
+ memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
+#endif /* SET_RANDOM_MAC_SOFTAP */
+#if !defined(AP) && defined(WL_CFG80211)
+ /* Turn off MPC in AP mode */
+ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret));
+ }
+#endif
+#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
+ bcm_mkiovar("wme_apsd", (char *)&wme_apsd, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s: set wme_apsd 0 fail (error=%d)\n",
+ __FUNCTION__, ret));
+ }
+#endif /* SOFTAP_UAPSD_OFF */
+ } 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;
+ bcm_mkiovar("rsdb_mode", (char *)&rsdb_mode, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 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) {
+ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s APSTA for 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);
+ bcm_mkiovar("p2p_da_override", (char *)&p2p_ea,
+ ETHER_ADDR_LEN, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 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)) {
+ memset(iovbuf, 0, sizeof(iovbuf));
+ bcm_mkiovar("scan_features", (char *)&scan_features,
+ 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR,
+ iovbuf, sizeof(iovbuf), FALSE, 0)) < 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;
+ memset(iovbuf, 0, sizeof(iovbuf));
+ bcm_mkiovar("scan_features", (char *)&scan_features,
+ 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iovbuf, sizeof(iovbuf), TRUE, 0)) < 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)));
+ #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) {
+ bcm_mkiovar("country", (char *)&dhd->dhd_cspec,
+ sizeof(wl_country_t), iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
+ }
+
+
+ /* Set Listen Interval */
+ bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 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 */
+ bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */
+#if defined(ROAM_ENABLE)
+ 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));
+ bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret));
+#endif /* ROAM_ENABLE */
+
+#ifdef CUSTOM_EVENT_PM_WAKE
+ bcm_mkiovar("const_awake_thresh", (char *)&pm_awake_thresh, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 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 */
+ bcm_mkiovar("lpc", (char *)&lpc, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 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));
+
+ bcm_mkiovar("lpc", (char *)&lpc, 4, iovbuf, sizeof(iovbuf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ DHD_ERROR(("%s Set lpc ret --> %d\n", __FUNCTION__, ret));
+ }
+ }
+#endif /* DHD_ENABLE_LPC */
+
+ /* Set PowerSave mode */
+ 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 */
+ bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+
+#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL)
+ /* enable credall to reduce the chance of no bus credit happened. */
+ bcm_mkiovar("bus:credall", (char *)&credall, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#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));
+ bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ }
+#endif /* defined(BCMSDIO) */
+
+ /* Setup timeout if Beacons are lost and roam is off to report link down */
+ bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ /* Setup assoc_retry_max count to reconnect target AP in dongle */
+ bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#if defined(AP) && !defined(WLP2P)
+ /* Turn off MPC in AP mode */
+ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#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
+ bcm_mkiovar("txbf", (char *)&txbf, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set txbf returned (%d)\n", __FUNCTION__, ret));
+ }
+#endif /* USE_WL_TXBF */
+
+#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));
+ }
+#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) {
+ bcm_mkiovar("ampdu_ba_wsize", (char *)&ampdu_ba_wsize, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed %d\n",
+ __FUNCTION__, ampdu_ba_wsize, ret));
+ }
+ }
+#endif
+
+ 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;
+ }
+#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;
+ bcm_mkiovar("temp_throttle_control", (char *)&temp_control,
+ sizeof(wl_temp_control_t), iov_buf, WLC_IOCTL_SMLEN);
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iov_buf, WLC_IOCTL_SMLEN, TRUE, 0);
+ 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)) {
+ bcm_mkiovar("ampdu_mpdu", (char *)&ampdu_mpdu, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 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)) {
+ bcm_mkiovar("ampdu_release", (char *)&ampdu_release, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 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) {
+ bcm_mkiovar("amsdu_aggsf", (char *)&amsdu_aggsf, 4, iovbuf, sizeof(iovbuf));
+ ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ if (ret < 0) {
+ DHD_ERROR(("%s Set amsdu_aggsf to %d failed %d\n",
+ __FUNCTION__, CUSTOM_AMSDU_AGGSF, ret));
+ }
+ }
+#endif /* CUSTOM_AMSDU_AGGSF */
+
+#ifdef CUSTOM_PSPRETEND_THR
+ /* Turn off MPC in AP mode */
+ bcm_mkiovar("pspretend_threshold", (char *)&pspretend_thr, 4,
+ iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s pspretend_threshold for HostAPD failed %d\n",
+ __FUNCTION__, ret));
+ }
+#endif
+
+ bcm_mkiovar("buf_key_b4_m4", (char *)&buf_key_b4_m4, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
+ sizeof(iovbuf), TRUE, 0)) < 0) {
+ DHD_ERROR(("%s buf_key_b4_m4 set failed %d\n", __FUNCTION__, ret));
+ }
+
+ /* Read event_msgs mask */
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 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_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);
+#ifndef WL_CFG80211
+ setbit(eventmask, WLC_E_PMKID_CACHE);
+ setbit(eventmask, WLC_E_TXFAIL);
+#endif
+ setbit(eventmask, WLC_E_JOIN_START);
+ setbit(eventmask, WLC_E_SCAN_COMPLETE);
+#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);
+ setbit(eventmask, WLC_E_BSSID);
+#ifdef WLTDLS
+ setbit(eventmask, WLC_E_TDLS_PEER_EVENT);
+#endif /* WLTDLS */
+#ifdef WL_CFG80211
+ setbit(eventmask, WLC_E_ESCAN_RESULT);
+ setbit(eventmask, WLC_E_AP_STARTED);
+ if (dhd->op_mode & DHD_FLAG_P2P_MODE) {
+ setbit(eventmask, WLC_E_ACTION_FRAME_RX);
+ 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_LOSSLESS_ROAMING
+ setbit(eventmask, WLC_E_ROAM_PREP);
+#endif
+#ifdef CUSTOM_EVENT_PM_WAKE
+ setbit(eventmask, WLC_E_EXCESS_PM_WAKE_EVENT);
+#endif /* CUSTOM_EVENT_PM_WAKE */
+#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) */
+
+ /* Write updated Event mask */
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 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 */
+ bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg, msglen, iov_buf, WLC_IOCTL_SMLEN);
+ ret2 = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iov_buf, WLC_IOCTL_SMLEN, FALSE, 0);
+ if (ret2 == 0) { /* event_msgs_ext must be supported */
+ bcopy(iov_buf, eventmask_msg, msglen);
+#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_SWC);
+#endif /* GSCAN_SUPPORT */
+#ifdef BT_WIFI_HANDOVER
+ setbit(eventmask_msg->mask, WLC_E_BT_WIFI_HANDOVER_REQ);
+#endif /* BT_WIFI_HANDOVER */
+ setbit(eventmask_msg->mask, WLC_E_SDB_TRANSITION);
+#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;
+ bcm_mkiovar("event_msgs_ext", (char *)eventmask_msg,
+ msglen, iov_buf, WLC_IOCTL_SMLEN);
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
+ iov_buf, WLC_IOCTL_SMLEN, TRUE, 0)) < 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;
+ }
+
+ 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 */
+ 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;
+ 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 */
+
+#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
+ bcm_mkiovar("nmode", (char *)&nmode, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
+ DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret));
+#endif /* DISABLE_11N */
+
+#ifdef ENABLE_BCN_LI_BCN_WAKEUP
+ bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, 4, iovbuf, sizeof(iovbuf));
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+#endif /* ENABLE_BCN_LI_BCN_WAKEUP */
+ /* query for 'clmver' to get clm version info from firmware */
+ memset(buf, 0, sizeof(buf));
+ bcm_mkiovar("clmver", (char *)&buf, 4, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0)
+ DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
+ else {
+ char *clmver_temp_buf = NULL;
+
+ if ((clmver_temp_buf = bcmstrstr(buf, "Data:")) == NULL) {
+ DHD_ERROR(("Couldn't find \"Data:\"\n"));
+ } else {
+ ptr = (clmver_temp_buf + strlen("Data:"));
+ if ((clmver_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);
+ strncpy(clm_version, clmver_temp_buf,
+ MIN(strlen(clmver_temp_buf), CLM_VER_STR_LEN - 1));
+ DHD_ERROR(("clm version = %s\n", clm_version));
+ }
+ }
+ }
+
+ /* query for 'ver' to get version info from firmware */
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0)
+ DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
+ else {
+ bcmstrtok(&ptr, "\n", 0);
+ /* Print fw version info */
+ DHD_ERROR(("Firmware version = %s\n", buf));
+ strncpy(fw_version, buf, FW_VER_STR_LEN);
+ fw_version[FW_VER_STR_LEN-1] = '\0';
+#if defined(BCMSDIO)
+ dhd_set_version_info(dhd, buf);
+#endif /* defined(BCMSDIO) */
+#ifdef WRITE_WLANINFO
+ sec_save_wlinfo(buf, EPI_VERSION_STR, dhd->info->nv_path, clm_version);
+#endif /* WRITE_WLANINFO */
+ }
+
+#if defined(BCMSDIO)
+ dhd_txglom_enable(dhd, TRUE);
+#endif /* defined(BCMSDIO) */
+
+#if defined(BCMSDIO)
+#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;
+ }
+
+#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 */
+
+#ifndef DISABLE_11N
+ bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4, iovbuf, sizeof(iovbuf));
+ if ((ret2 = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 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));
+
+ bcm_mkiovar("ampdu_hostreorder", (char *)&hostreorder, 4,
+ iovbuf, sizeof(iovbuf));
+ ret2 = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
+ 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);
+#ifndef DISABLE_11N
+ else if (hostreorder)
+ dhd_wlfc_hostreorder_init(dhd);
+#endif /* DISABLE_11N */
+
+#endif /* PROP_TXSTATUS */
+#endif /* BCMSDIO || BCMBUS */
+#ifdef 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;
+ bcm_mkiovar("ap_isolate", (char *)&wl_ap_isolate, 4, iovbuf, sizeof(iovbuf));
+ if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 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 WL11U
+ dhd_interworking_enable(dhd);
+#endif /* WL11U */
+
+#ifdef SUPPORT_SENSORHUB
+ bcm_mkiovar("shub", (char *)&(shub_ctl.enable), 4, iovbuf, sizeof(iovbuf));
+ if ((ret2 = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf),
+ FALSE, 0)) < 0) {
+ DHD_ERROR(("%s failed to get shub hub enable information %d\n",
+ __FUNCTION__, ret2));
+ dhd->info->shub_enable = 0;
+ } else {
+ memcpy(&shub_ctl, iovbuf, sizeof(shub_ctl));
+ dhd->info->shub_enable = shub_ctl.enable;
+ DHD_ERROR(("%s: checking sensorhub enable %d\n",
+ __FUNCTION__, dhd->info->shub_enable));
+ }
+#else
+ dhd->info->shub_enable = FALSE;
+ shub_ctl.enable = FALSE;
+ bcm_mkiovar("shub", (char *)&shub_ctl, sizeof(shub_ctl),
+ iovbuf, sizeof(iovbuf));
+ if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf),
+ FALSE, 0)) < 0) {
+ DHD_ERROR(("%s failed to set ShubHub disable\n",
+ __FUNCTION__));
+ }
+#endif /* SUPPORT_SENSORHUB */
+done:
+
+ if (eventmask_msg)
+ kfree(eventmask_msg);
+ if (iov_buf)
+ kfree(iov_buf);
+
+ return ret;
+}
+
+
+int
+dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set)
+{
+ char buf[strlen(name) + 1 + cmd_len];
+ int len = sizeof(buf);
+ wl_ioctl_t ioc;
+ int ret;
+
+ len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len);
+
+ memset(&ioc, 0, sizeof(ioc));
+
+ ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR;
+ ioc.buf = buf;
+ ioc.len = len;
+ ioc.set = set;
+
+ ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len);
+ if (!set && ret >= 0)
+ memcpy(cmd_buf, buf, cmd_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", 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 */
+ 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__));
+ aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx);
+#else
+ dhd_aoe_hostip_clr(&dhd->pub, idx);
+ dhd_aoe_arp_clr(&dhd->pub, idx);
+#endif /* AOE_IP_ALIAS_SUPPORT */
+ 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_pub_t *pub = &((dhd_info_t *)dhd_info)->pub;
+ int ret;
+
+ if (event != DHD_WQ_WORK_IPV6_NDO) {
+ DHD_ERROR(("%s: unexpected event \n", __FUNCTION__));
+ return;
+ }
+
+ if (!ndo_work) {
+ DHD_ERROR(("%s: ipv6 work info is not initialized \n", __FUNCTION__));
+ return;
+ }
+
+ if (!pub) {
+ DHD_ERROR(("%s: dhd pub is not initialized \n", __FUNCTION__));
+ return;
+ }
+
+ if (ndo_work->if_idx) {
+ DHD_ERROR(("%s: idx %d \n", __FUNCTION__, ndo_work->if_idx));
+ return;
+ }
+
+ switch (ndo_work->event) {
+ case NETDEV_UP:
+ DHD_TRACE(("%s: Enable NDO and add ipv6 into table \n ", __FUNCTION__));
+ ret = dhd_ndo_enable(pub, TRUE);
+ if (ret < 0) {
+ DHD_ERROR(("%s: Enabling NDO Failed %d\n", __FUNCTION__, ret));
+ }
+
+ ret = dhd_ndo_add_ip(pub, &ndo_work->ipv6_addr[0], ndo_work->if_idx);
+ if (ret < 0) {
+ DHD_ERROR(("%s: Adding host ip for NDO failed %d\n",
+ __FUNCTION__, ret));
+ }
+ break;
+ case NETDEV_DOWN:
+ DHD_TRACE(("%s: clear ipv6 table \n", __FUNCTION__));
+ ret = dhd_ndo_remove_ip(pub, ndo_work->if_idx);
+ if (ret < 0) {
+ DHD_ERROR(("%s: Removing host ip for NDO failed %d\n",
+ __FUNCTION__, ret));
+ goto done;
+ }
+
+ ret = dhd_ndo_enable(pub, FALSE);
+ if (ret < 0) {
+ DHD_ERROR(("%s: disabling NDO Failed %d\n", __FUNCTION__, ret));
+ goto done;
+ }
+ break;
+ default:
+ DHD_ERROR(("%s: unknown notifier event \n", __FUNCTION__));
+ break;
+ }
+done:
+ /* free ndo_work. alloced while scheduling the work */
+ kfree(ndo_work);
+
+ return;
+}
+
+/*
+ * Neighbor Discovery Offload: Called when an interface
+ * is assigned with ipv6 address.
+ * Handles only primary interface
+ */
+static int dhd_inet6addr_notifier_call(struct notifier_block *this,
+ unsigned long event,
+ void *ptr)
+{
+ dhd_info_t *dhd;
+ dhd_pub_t *dhd_pub;
+ struct inet6_ifaddr *inet6_ifa = ptr;
+ struct in6_addr *ipv6_addr = &inet6_ifa->addr;
+ struct ipv6_work_info_t *ndo_info;
+ int idx = 0; /* REVISIT */
+
+#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;
+
+ if (dhd->iflist[idx] && dhd->iflist[idx]->net != inet6_ifa->idev->dev)
+ return NOTIFY_DONE;
+ dhd_pub = &dhd->pub;
+
+ if (!FW_SUPPORTED(dhd_pub, 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;
+ }
+
+ ndo_info->event = event;
+ ndo_info->if_idx = idx;
+ memcpy(&ndo_info->ipv6_addr[0], ipv6_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_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));
+
+ 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 = (struct iw_handler_def *)&wl_iw_handler_def;
+#endif /* WIRELESS_EXT > 12 */
+#endif /* defined(WL_WIRELESS_EXT) */
+
+ dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net);
+
+ memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
+
+ if (ifidx == 0)
+ printf("%s\n", dhd_version);
+
+ 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;
+ }
+
+
+
+ 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))))
+ if (ifidx == 0) {
+#ifdef BCMLXSDMMC
+ up(&dhd_registration_sem);
+#endif /* BCMLXSDMMC */
+#ifndef ENABLE_INSMOD_NO_FW_LOAD
+ if (!dhd_download_fw_on_driverload) {
+#ifdef WL_CFG80211
+ wl_terminate_event_handler(DHD_GET_CFG80211_PRIV(dhdp));
+#endif /* WL_CFG80211 */
+#if defined(DHD_LB) && defined(DHD_LB_RXP)
+ __skb_queue_purge(&dhd->rx_pend_queue);
+#endif /* DHD_LB && DHD_LB_RXP */
+#if defined(BCMPCIE) && defined(DHDTCPACK_SUPPRESS)
+ dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF);
+#endif /* BCMPCIE && 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);
+ }
+#endif /* ENABLE_INSMOD_NO_FW_LOAD */
+ }
+#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) {
+ /* Stop the protocol module */
+ dhd_prot_stop(&dhd->pub);
+
+ /* Stop the bus module */
+ dhd_bus_stop(dhd->pub.bus, TRUE);
+ }
+
+#if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE)
+ OOB_PARAM_IF(!(dhdp->oob_disable)) {
+ 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;
+
+ 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);
+ }
+
+#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 */
+
+ 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
+ }
+
+#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();
+ }
+#endif /* defined(WL_WIRELESS_EXT) */
+
+ /* 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);
+ }
+
+ /* delete primary interface 0 */
+ ifp = dhd->iflist[0];
+ ASSERT(ifp);
+ ASSERT(ifp->net);
+ if (ifp && ifp->net) {
+
+
+
+ /* 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 {
+#ifdef SET_RPS_CPUS
+ custom_rps_map_clear(ifp->net->_rx);
+#endif /* SET_RPS_CPUS */
+ netif_tx_disable(ifp->net);
+ unregister_netdev(ifp->net);
+ }
+ ifp->net = NULL;
+#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;
+ }
+ dhd_net_if_unlock_local(dhd);
+ }
+
+ /* 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);
+
+ 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);
+#ifdef DHD_LB_RXP
+ __skb_queue_purge(&dhd->rx_pend_queue);
+#endif /* DHD_LB_RXP */
+ }
+ }
+
+#if defined(DHD_LB)
+ /* Kill the Load Balancing Tasklets */
+#if defined(DHD_LB_TXC)
+ tasklet_disable(&dhd->tx_compl_tasklet);
+ tasklet_kill(&dhd->tx_compl_tasklet);
+#endif /* DHD_LB_TXC */
+#if defined(DHD_LB_RXC)
+ tasklet_disable(&dhd->rx_compl_tasklet);
+ 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);
+#endif /* DHD_LB */
+
+#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) {
+ wl_cfg80211_detach(DHD_GET_CFG80211_PRIV(dhdp));
+ dhdp->cfg80211_priv = NULL;
+ dhd_monitor_uninit();
+ }
+#endif
+ /* free deferred work queue */
+ dhd_deferred_work_deinit(dhd->dhd_deferred_wq);
+ dhd->dhd_deferred_wq = NULL;
+
+#ifdef SHOW_LOGTRACE
+ if (dhd->event_data.fmts)
+ kfree(dhd->event_data.fmts);
+ if (dhd->event_data.raw_fmts)
+ kfree(dhd->event_data.raw_fmts);
+ if (dhd->event_data.raw_sstr)
+ kfree(dhd->event_data.raw_sstr);
+#endif /* SHOW_LOGTRACE */
+
+#ifdef PNO_SUPPORT
+ if (dhdp->pno_state)
+ dhd_pno_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
+ if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) {
+ 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);
+#endif /* CONFIG_HAS_WAKELOCK */
+ 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
+
+
+ dhd_sysfs_exit(dhd);
+ dhd->pub.is_fw_download_done = FALSE;
+}
+
+
+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 pointer is allocated by dhd_os_prealloc then avoid MFREE */
+ if (dhd &&
+ 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)
+{
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ dhd_bus_unregister();
+
+ wl_android_exit();
+
+ dhd_wifi_platform_unregister_drv();
+}
+
+static void __exit
+dhd_module_exit(void)
+{
+ dhd_buzzz_detach();
+ dhd_module_cleanup();
+ unregister_reboot_notifier(&dhd_reboot_notifier);
+}
+
+static int __init
+dhd_module_init(void)
+{
+ int err;
+ int retry = POWERUP_MAX_RETRY;
+
+ DHD_ERROR(("%s in\n", __FUNCTION__));
+
+ dhd_buzzz_attach();
+
+ 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--);
+
+ 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;
+ }
+ }
+
+ DHD_ERROR(("%s out\n", __FUNCTION__));
+
+ 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)
+#if defined(CONFIG_MACH_UNIVERSAL7420) || defined(CONFIG_SOC_EXYNOS8890) || \
+ defined(CONFIG_ARCH_MSM8996)
+deferred_module_init_sync(dhd_module_init);
+#else
+deferred_module_init(dhd_module_init);
+#endif /* CONFIG_MACH_UNIVERSAL7420 || CONFIG_SOC_EXYNOS8890 ||
+ * CONFIG_ARCH_MSM8996
+ */
+#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;
+}
+
+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;
+}
+
+int INLINE
+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)
+{
+ 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);
+}
+
+
+void
+dhd_os_wd_timer(void *bus, uint wdtick)
+{
+ 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;
+ }
+
+#if !defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE)
+ DHD_OS_WD_WAKE_LOCK(pub);
+#endif /* !DHD_USE_IDLECOUNT && BCMPCIE */
+ 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);
+#if !defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE)
+ DHD_OS_WD_WAKE_UNLOCK(pub);
+#endif /* !DHD_USE_IDLECOUNT && BCMPCIE */
+ 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);
+ DHD_OS_WD_WAKE_UNLOCK(pub);
+ return;
+ }
+
+ if (wdtick) {
+ DHD_OS_WD_WAKE_LOCK(pub);
+ 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);
+#if !defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE)
+ DHD_OS_WD_WAKE_UNLOCK(pub);
+#endif /* !DHD_USE_IDLECOUNT && BCMPCIE */
+}
+
+#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 (pub->busstate == DHD_BUS_DOWN ||
+ pub->busstate == DHD_BUS_DOWN_IN_PROGRESS) {
+ 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));
+ rdlen = kernel_read(fp, fp->f_pos, buf, MIN(len, size));
+
+ if (len >= size && size != rdlen) {
+ return -EIO;
+ }
+
+ if (rdlen > 0)
+ fp->f_pos += rdlen;
+
+ return rdlen;
+}
+
+void
+dhd_os_close_image(void *image)
+{
+ if (image)
+ filp_close((struct file *)image, NULL);
+}
+
+int dhd_os_file_size(char *filename)
+{
+ struct file *fp = NULL;
+ int size = 0;
+ fp = filp_open(filename, O_RDONLY, 0);
+ if (IS_ERR(fp)) {
+ DHD_ERROR(("%s: File %s doesn't exist\n", __FUNCTION__, filename));
+ return BCME_ERROR;
+ }
+ size = i_size_read(file_inode(fp));
+ if (size <= 0) {
+ DHD_ERROR(("%s: %s file size invalid %d\n", __FUNCTION__, filename, size));
+ }
+ if (fp)
+ filp_close(fp, NULL);
+
+ return size;
+}
+
+void
+dhd_os_sdlock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+
+ if (dhd_dpc_prio >= 0)
+ down(&dhd->sdsem);
+ else
+ spin_lock_bh(&dhd->sdlock);
+}
+
+void
+dhd_os_sdunlock(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+
+ if (dhd_dpc_prio >= 0)
+ up(&dhd->sdsem);
+ else
+ spin_unlock_bh(&dhd->sdlock);
+}
+
+void
+dhd_os_sdlock_txq(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+ spin_lock_bh(&dhd->txqlock);
+}
+
+void
+dhd_os_sdunlock_txq(dhd_pub_t *pub)
+{
+ dhd_info_t *dhd;
+
+ dhd = (dhd_info_t *)(pub->info);
+ spin_unlock_bh(&dhd->txqlock);
+}
+
+void
+dhd_os_sdlock_rxq(dhd_pub_t *pub)
+{
+}
+
+void
+dhd_os_sdunlock_rxq(dhd_pub_t *pub)
+{
+}
+
+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, size_t pktlen,
+ wl_event_msg_t *event, void **data)
+{
+ int bcmerror = 0;
+ ASSERT(dhd != NULL);
+
+#ifdef SHOW_LOGTRACE
+ bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, pktlen, event, data,
+ &dhd->event_data);
+#else
+ bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, pktlen, event, data,
+ NULL);
+#endif /* SHOW_LOGTRACE */
+
+ if (bcmerror != BCME_OK)
+ return (bcmerror);
+
+#if defined(WL_WIRELESS_EXT)
+ if (event->bsscfgidx == 0) {
+ /*
+ * Wireless ext is on primary interface only
+ */
+
+ ASSERT(dhd->iflist[*ifidx] != NULL);
+ ASSERT(dhd->iflist[*ifidx]->net != NULL);
+
+ if (dhd->iflist[*ifidx]->net) {
+ wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
+ }
+ }
+#endif /* defined(WL_WIRELESS_EXT) */
+
+#ifdef WL_CFG80211
+ ASSERT(dhd->iflist[*ifidx] != NULL);
+ ASSERT(dhd->iflist[*ifidx]->net != NULL);
+ if (dhd->iflist[*ifidx]->net)
+ wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data);
+#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)
+{
+ switch (ntoh32(event->event_type)) {
+
+ default:
+ break;
+ }
+}
+
+#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, &eth.ether_dhost, ETHER_ADDR_LEN);
+ bcopy(&dhdp->mac, &eth.ether_shost, ETHER_ADDR_LEN);
+ ETHER_TOGGLE_LOCALADDR(&eth.ether_shost);
+ eth.ether_type = hton16(ETHER_TYPE_BRCM);
+
+ bcopy((void *)&eth, 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", __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)
+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 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);
+ }
+#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 */
+
+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) {
+#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
+ }
+ 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) {
+#ifdef ENABLE_MAX_DTIM_IN_SUSPEND
+ 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 /* ENABLE_MAX_DTIM_IN_SUSPEND */
+ DHD_ERROR(("%s: max_dtim_enable always FALSE\n", __FUNCTION__));
+ dhd->pub.max_dtim_enable = FALSE;
+#endif /* ENABLE_MAX_DTIM_IN_SUSPEND */
+ } 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);
+
+ 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;
+
+#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(CONFIG_WLAN_GRACE) || defined(CONFIG_SEC_GRACEQLTE_PROJECT)
+ DHD_ERROR(("%s: return feature_set = %d\n", __FUNCTION__, feature_set));
+ return feature_set;
+#endif /* CONFIG_WLAN_GRACE || CONFIG_SEC_GRACEQLTE_PROJECT */
+ if (!dhd)
+ return feature_set;
+
+ 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
+ feature_set |= WIFI_FEATURE_D2AP_RTT;
+#endif /* RTT_SUPPORT */
+#ifdef LINKSTAT_SUPPORT
+ feature_set |= WIFI_FEATURE_LINKSTAT;
+#endif /* LINKSTAT_SUPPORT */
+ /* Supports STA + STA always */
+ feature_set |= WIFI_FEATURE_ADDITIONAL_STA;
+#ifdef PNO_SUPPORT
+ if (dhd_is_pno_supported(dhd)) {
+ feature_set |= WIFI_FEATURE_PNO;
+ feature_set |= WIFI_FEATURE_BATCH_SCAN;
+#ifdef GSCAN_SUPPORT
+ feature_set |= WIFI_FEATURE_GSCAN;
+#endif /* GSCAN_SUPPORT */
+ }
+#endif /* PNO_SUPPORT */
+#ifdef WL11U
+ feature_set |= WIFI_FEATURE_HOTSPOT;
+#endif /* WL11U */
+ return feature_set;
+}
+
+
+int *dhd_dev_get_feature_set_matrix(struct net_device *dev, int *num)
+{
+ int feature_set_full, mem_needed;
+ int *ret;
+
+ *num = 0;
+ mem_needed = sizeof(int) * MAX_FEATURE_SET_CONCURRRENT_GROUPS;
+ ret = (int *) kmalloc(mem_needed, GFP_KERNEL);
+ if (!ret) {
+ DHD_ERROR(("%s: failed to allocate %d bytes\n", __FUNCTION__,
+ mem_needed));
+ return ret;
+ }
+
+ feature_set_full = dhd_dev_get_feature_set(dev);
+
+ ret[0] = (feature_set_full & WIFI_FEATURE_INFRA) |
+ (feature_set_full & WIFI_FEATURE_INFRA_5G) |
+ (feature_set_full & WIFI_FEATURE_NAN) |
+ (feature_set_full & WIFI_FEATURE_D2D_RTT) |
+ (feature_set_full & WIFI_FEATURE_D2AP_RTT) |
+ (feature_set_full & WIFI_FEATURE_PNO) |
+ (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) |
+ (feature_set_full & WIFI_FEATURE_EPR);
+
+ ret[1] = (feature_set_full & WIFI_FEATURE_INFRA) |
+ (feature_set_full & WIFI_FEATURE_INFRA_5G) |
+ /* Not yet verified NAN with P2P */
+ /* (feature_set_full & WIFI_FEATURE_NAN) | */
+ (feature_set_full & WIFI_FEATURE_P2P) |
+ (feature_set_full & WIFI_FEATURE_D2AP_RTT) |
+ (feature_set_full & WIFI_FEATURE_D2D_RTT) |
+ (feature_set_full & WIFI_FEATURE_EPR);
+
+ ret[2] = (feature_set_full & WIFI_FEATURE_INFRA) |
+ (feature_set_full & WIFI_FEATURE_INFRA_5G) |
+ (feature_set_full & WIFI_FEATURE_NAN) |
+ (feature_set_full & WIFI_FEATURE_D2D_RTT) |
+ (feature_set_full & WIFI_FEATURE_D2AP_RTT) |
+ (feature_set_full & WIFI_FEATURE_TDLS) |
+ (feature_set_full & WIFI_FEATURE_TDLS_OFFCHANNEL) |
+ (feature_set_full & WIFI_FEATURE_EPR);
+ *num = MAX_FEATURE_SET_CONCURRRENT_GROUPS;
+
+ 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 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));
+}
+/* Linux wrapper to call common dhd_pno_set_mac_oui */
+int
+dhd_dev_pno_set_mac_oui(struct net_device *dev, uint8 *oui)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ return (dhd_pno_set_mac_oui(&dhd->pub, oui));
+}
+#endif /* PNO_SUPPORT */
+
+#if defined(PNO_SUPPORT)
+#ifdef GSCAN_SUPPORT
+/* 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, uint8 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_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));
+}
+
+/* Linux wrapper to call common dhd_wait_batch_results_complete */
+void
+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 */
+void
+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_swc_evt */
+void *
+dhd_dev_swc_scan_event(struct net_device *dev, const void *data, int *send_evt_bytes)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+
+ return (dhd_handle_swc_evt(&dhd->pub, data, send_evt_bytes));
+}
+
+/* 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, int *send_evt_bytes)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+
+ return (dhd_process_full_gscan_result(&dhd->pub, data, 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));
+}
+#endif /* GSCAN_SUPPORT */
+#endif
+#ifdef RTT_SUPPORT
+/* 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));
+}
+
+#endif /* RTT_SUPPORT */
+
+#if defined(KEEP_ALIVE)
+#define TEMP_BUF_SIZE 512
+#define TEMP_FRAME_SIZE 300
+int
+dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id, u8 *ip_pkt, u16 ip_pkt_len,
+ u8* src_mac, u8* dst_mac, u32 period_msec)
+{
+ char *pbuf;
+ const char *str;
+ wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0};
+ wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
+ int buf_len;
+ int str_len;
+ int res = BCME_ERROR;
+ int len_bytes = 0;
+ int i;
+
+ /* ether frame to have both max IP pkt (256 bytes) and ether header */
+ char *pmac_frame;
+
+ /*
+ * 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(TEMP_BUF_SIZE, GFP_KERNEL)) == NULL) {
+ DHD_ERROR(("failed to allocate buf with size %d\n", TEMP_BUF_SIZE));
+ res = BCME_NOMEM;
+ return res;
+ }
+
+ if ((pmac_frame = kzalloc(TEMP_FRAME_SIZE, GFP_KERNEL)) == NULL) {
+ DHD_ERROR(("failed to allocate mac_frame with size %d\n", TEMP_FRAME_SIZE));
+ res = BCME_NOMEM;
+ goto exit;
+ }
+
+ /*
+ * Get current mkeep-alive status.
+ */
+ bcm_mkiovar("mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id),
+ pbuf, TEMP_BUF_SIZE);
+
+ if ((res = dhd_wl_ioctl_cmd(dhd_pub, WLC_GET_VAR, pbuf, TEMP_BUF_SIZE,
+ FALSE, 0)) < 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, 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 + ETHER_TYPE_LEN + ip_pkt_len;
+ /* Get back to the beginning. */
+ pmac_frame -= len_bytes;
+ memcpy(mkeep_alive_pktp->data, pmac_frame, 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);
+ kfree(pbuf);
+ return res;
+}
+
+int
+dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, u8 mkeep_alive_id)
+{
+ char *pbuf;
+ const char *str;
+ wl_mkeep_alive_pkt_t mkeep_alive_pkt;
+ wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
+ int buf_len;
+ int str_len;
+ 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)) {
+ DHD_ERROR(("sta mode not supported \n"));
+ 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 = kzalloc(TEMP_BUF_SIZE, GFP_KERNEL)) == NULL) {
+ DHD_ERROR(("failed to allocate buf with size %d\n", TEMP_BUF_SIZE));
+ return res;
+ }
+
+ bcm_mkiovar("mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id), pbuf, TEMP_BUF_SIZE);
+
+ if ((res = dhd_wl_ioctl_cmd(dhd_pub, WLC_GET_VAR, pbuf, TEMP_BUF_SIZE, FALSE, 0)) < 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));
+ memset(pbuf, 0, 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 = 0;
+ buf_len = str_len + 1;
+ 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;
+ buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
+
+ /*
+ * 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);
+ } else {
+ DHD_ERROR(("%s: ID %u does not exist.\n", __FUNCTION__, mkeep_alive_id));
+ res = BCME_NOTFOUND;
+ }
+exit:
+ kfree(pbuf);
+ return res;
+}
+#endif /* defined(KEEP_ALIVE) */
+
+#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;
+ dev = dhd->iflist[0]->net;
+
+ if (dev) {
+#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 (!dhdp->hang_was_sent) {
+#ifdef DHD_DEBUG_UART
+ /* If PCIe lane has broken, execute the debug uart application
+ * to gether a ramdump data from dongle via uart
+ */
+#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) {
+ dhd_debug_uart_exec("rd");
+#ifdef DHD_LOG_DUMP
+ if (dhdp->memdump_type != DUMP_TYPE_BY_SYSDUMP)
+#endif
+ {
+ BUG_ON(1);
+ }
+ }
+ }
+#endif /* DHD_DEBUG_UART */
+ dhdp->hang_was_sent = 1;
+ dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, (void *)dhdp,
+ DHD_WQ_WORK_HANG_MSG, dhd_hang_process, DHD_WORK_PRIORITY_HIGH);
+ }
+ }
+ 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) {
+#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
+ } 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);
+#ifdef 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 */
+
+
+}
+void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ if (dhd && dhd->pub.up) {
+ memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
+#ifdef WL_CFG80211
+ wl_update_wiphybands(DHD_GET_CFG80211_PRIV(&dhd->pub), notify, true);
+#endif
+ }
+}
+
+void dhd_bus_band_set(struct net_device *dev, uint band)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ if (dhd && dhd->pub.up) {
+#ifdef WL_CFG80211
+ wl_update_wiphybands(DHD_GET_CFG80211_PRIV(&dhd->pub), true, 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;
+}
+
+#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_SCAN_TIMEOUT:
+ type_str = "SCAN_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;
+ default:
+ type_str = "Unknown_type";
+ break;
+ }
+
+ strncpy(buf, type_str, strlen(type_str));
+ buf[strlen(type_str)] = 0;
+}
+
+int
+write_to_file(dhd_pub_t *dhd, uint8 *buf, int size)
+{
+ int ret = 0;
+ struct file *fp = NULL;
+ mm_segment_t old_fs;
+ loff_t pos = 0;
+ char memdump_path[128];
+ char memdump_type[32];
+ struct timeval curtime;
+ uint32 file_mode;
+
+ /* change to KERNEL_DS address limit */
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ /* Init file name */
+ memset(memdump_path, 0, sizeof(memdump_path));
+ memset(memdump_type, 0, sizeof(memdump_type));
+ 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_%ld.%ld",
+ DHD_COMMON_DUMP_PATH "mem_dump", 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_%ld.%ld",
+ "/data/misc/wifi/mem_dump", memdump_type,
+ (unsigned long)curtime.tv_sec, (unsigned long)curtime.tv_usec);
+ file_mode = O_CREAT | O_WRONLY | O_SYNC;
+#else
+ snprintf(memdump_path, sizeof(memdump_path), "%s_%s_%ld.%ld",
+ "/installmedia/mem_dump", 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_DIRECT | O_SYNC | O_TRUNC;
+#endif /* CUSTOMER_HW4_DEBUG */
+
+ /* print SOCRAM dump file path */
+ DHD_ERROR(("%s: memdump_path = %s\n", __FUNCTION__, memdump_path));
+
+ /* open file to write */
+ fp = filp_open(memdump_path, file_mode, 0644);
+ if (IS_ERR(fp)) {
+ ret = PTR_ERR(fp);
+ printf("%s: open file error, err = %d\n", __FUNCTION__, ret);
+ goto exit;
+ }
+
+ /* Write buf to file */
+ fp->f_op->write(fp, buf, size, &pos);
+
+exit:
+ /* close file before return */
+ if (!ret)
+ filp_close(fp, current->files);
+
+ /* restore previous address limit */
+ set_fs(old_fs);
+
+ /* free buf before return */
+#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP)
+ DHD_OS_PREFREE(dhd, buf, size);
+#else
+ MFREE(dhd->osh, buf, size);
+#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */
+
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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 <linux/hashtable.h>
+#else
+#include <linux/hash.h>
+#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:
+ DHD_ERROR(("wakelock lock : %pS lock_counter : %llu\n",
+ (void *)wklock_info->addr, wklock_info->counter));
+ break;
+ case DHD_WAKE_UNLOCK:
+ DHD_ERROR(("wakelock unlock : %pS, unlock_counter : %llu\n",
+ (void *)wklock_info->addr, wklock_info->counter));
+ break;
+ case DHD_WAIVE_LOCK:
+ DHD_ERROR(("wakelock waive : %pS before_waive : %llu\n",
+ (void *)wklock_info->addr, wklock_info->counter));
+ break;
+ case DHD_RESTORE_LOCK:
+ DHD_ERROR(("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;
+
+ DHD_ERROR((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) {
+ 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(dhd_pub_t *pub)
+{
+#ifdef CONFIG_HAS_WAKELOCK
+ dhd_info_t *dhd = (dhd_info_t *)(pub->info);
+
+ if (dhd) {
+ wake_lock(&dhd->wl_txflwake);
+ }
+#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) {
+ 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)
+{
+#ifdef CONFIG_HAS_WAKELOCK
+ int l1, l2, l3, l4, l7, l8, l9;
+ int l5 = 0, l6 = 0;
+ int c, lock_active;
+#endif /* CONFIG_HAS_WAKELOCK */
+#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);
+ 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);
+#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 */
+ l7 = wake_lock_active(&dhd->wl_evtwake);
+ 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 (dhd && 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 /* CONFIG_HAS_WAKELOCK */
+ 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) {
+ 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;
+
+ 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
+ wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake");
+ wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake");
+ wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake");
+ 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;
+ wake_lock_destroy(&dhd->wl_wifi);
+ 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;
+}
+
+#if defined(BCMSDIO)
+/* 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 ", EPI_VERSION_STR, fw);
+
+ if (!dhdp)
+ return;
+
+ i = snprintf(&info_string[i], sizeof(info_string) - i,
+ "\n Chip: %x Rev %x Pkg %x", dhd_bus_chip_id(dhdp),
+ dhd_bus_chiprev_id(dhdp), dhd_bus_chippkg_id(dhdp));
+}
+#endif /* defined(BCMSDIO) */
+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 *dhd)
+{
+#ifdef SKIP_WLFC_ON_CONCURRENT
+#ifdef WL_CFG80211
+ dhd_pub_t *dhdp = (dhd_pub_t *)dhd;
+
+ /* enable flow control in vsdb mode */
+ return !(wl_cfg80211_is_concurrent_mode(DHD_GET_CFG80211_PRIV(dhdp)));
+#else
+ return TRUE; /* skip flow control */
+#endif /* WL_CFG80211 */
+
+#else
+ return FALSE;
+#endif /* SKIP_WLFC_ON_CONCURRENT */
+}
+#endif /* PROP_TXSTATUS */
+
+#ifdef BCMDBGFS
+#include <linux/debugfs.h>
+
+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_dbg_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_dbg_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_dbg_create();
+
+ return;
+}
+
+void dhd_dbg_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)
+{
+ wl_ioctl_t ioc;
+ char buf[32];
+ int ret;
+ uint32 s1, s2;
+
+ struct tsf {
+ uint32 low;
+ uint32 high;
+ } tsf_buf;
+
+ memset(&ioc, 0, sizeof(ioc));
+ memset(&tsf_buf, 0, sizeof(tsf_buf));
+
+ ioc.cmd = WLC_GET_VAR;
+ ioc.buf = buf;
+ ioc.len = (uint)sizeof(buf);
+ ioc.set = FALSE;
+
+ strncpy(buf, "tsf", sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+ s1 = dhd_get_htsf(dhd, 0);
+ if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 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);
+#endif /* DHD_OF_SUPPORT */
+ DHD_TRACE(("%s: set(%d) cpucore success!\n", __FUNCTION__, set));
+
+ return;
+}
+#endif /* CUSTOM_SET_CPUCORE */
+
+/* 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];
+
+ ifp->ap_isolate = val;
+
+ return 0;
+}
+
+int dhd_android_ap_isolate_getval(struct net_device *dev)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ int ifidx, val;
+
+ ifidx = dhd_net2idx(dhd, dev);
+ val = dhd_get_ap_isolate(&dhd->pub, ifidx);
+ return val;
+}
+void dhd_android_ap_isolate_setval(struct net_device *dev, int val)
+{
+ dhd_info_t *dhd = DHD_DEV_INFO(dev);
+ int ifidx;
+
+ ifidx = dhd_net2idx(dhd, dev);
+ dhd_set_ap_isolate(&dhd->pub, ifidx, val);
+}
+#ifdef DHD_FW_COREDUMP
+
+
+#ifdef CUSTOMER_HW4_DEBUG
+#ifdef PLATFORM_SLP
+#define MEMDUMPINFO "/opt/etc/.memdump.info"
+#else
+#define MEMDUMPINFO "/data/.memdump.info"
+#endif /* PLATFORM_SLP */
+#elif defined(CUSTOMER_HW2)
+#define MEMDUMPINFO "/data/misc/wifi/.memdump.info"
+#else
+#define MEMDUMPINFO "/installmedia/.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));
+ goto done;
+ } else {
+ ret = kernel_read(fp, 0, (char *)&mem_val, 4);
+ 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);
+
+ DHD_ERROR(("%s: MEMDUMP ENABLED = %d\n", __FUNCTION__, mem_val));
+ filp_close(fp, NULL);
+ }
+
+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_BUGON;
+#endif /* CUSTOMER_HW4_DEBUG */
+}
+
+
+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_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_to_file(&dhd->pub, dump->buf, dump->bufsize)) {
+ 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
+#ifdef DHD_DEBUG_UART
+ dhd->pub.memdump_success == TRUE &&
+#endif
+ TRUE) {
+ BUG_ON(1);
+ }
+ MFREE(dhd->pub.osh, dump, sizeof(dhd_dump_t));
+}
+#endif /* DHD_FW_COREDUMP */
+
+#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_WORK_PRIORITY_HIGH);
+}
+
+static int
+do_dhd_log_dump(dhd_pub_t *dhdp)
+{
+ int ret = 0;
+ struct file *fp = NULL;
+ mm_segment_t old_fs;
+ loff_t pos = 0;
+ char dump_path[128];
+ char common_info[1024];
+ struct timeval curtime;
+ uint32 file_mode;
+ unsigned long flags = 0;
+
+ if (!dhdp) {
+ return -1;
+ }
+
+ /* Building the additional information like DHD, F/W version */
+ memset(common_info, 0, sizeof(common_info));
+ snprintf(common_info, sizeof(common_info),
+ "---------- Common information ----------\n"
+ "DHD version: %s\n"
+ "F/W version: %s\n"
+ "----------------------------------------\n",
+ dhd_version, 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));
+ 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, 0644);
+ if (IS_ERR(fp)) {
+ ret = PTR_ERR(fp);
+ DHD_ERROR(("open file error, err = %d\n", ret));
+ ret = -1;
+ goto exit;
+ }
+
+ fp->f_op->write(fp, common_info, strlen(common_info), &pos);
+ if (dhdp->dld_buf.wraparound) {
+ fp->f_op->write(fp, dhdp->dld_buf.buffer, DHD_LOG_DUMP_BUFFER_SIZE, &pos);
+ } else {
+ fp->f_op->write(fp, dhdp->dld_buf.buffer,
+ (int)(dhdp->dld_buf.present - dhdp->dld_buf.front), &pos);
+ }
+
+ /* re-init dhd_log_dump_buf structure */
+ spin_lock_irqsave(&dhdp->dld_buf.lock, flags);
+ dhdp->dld_buf.wraparound = 0;
+ dhdp->dld_buf.present = dhdp->dld_buf.front;
+ dhdp->dld_buf.remain = DHD_LOG_DUMP_BUFFER_SIZE;
+ bzero(dhdp->dld_buf.buffer, DHD_LOG_DUMP_BUFFER_SIZE);
+ spin_unlock_irqrestore(&dhdp->dld_buf.lock, flags);
+exit:
+ if (!ret) {
+ filp_close(fp, NULL);
+ }
+ set_fs(old_fs);
+
+ return ret;
+}
+#endif /* DHD_LOG_DUMP */
+
+#ifdef BCMASSERT_LOG
+#ifdef CUSTOMER_HW4_DEBUG
+#ifdef PLATFORM_SLP
+#define ASSERTINFO "/opt/etc/.assert.info"
+#else
+#define ASSERTINFO "/data/.assert.info"
+#endif /* PLATFORM_SLP */
+#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;
+
+ /*
+ * 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 {
+ int mem_val = 0;
+ int ret = kernel_read(fp, 0, (char *)&mem_val, 4);
+ 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));
+ g_assert_type = mem_val;
+ }
+ filp_close(fp, NULL);
+ }
+}
+#endif /* BCMASSERT_LOG */
+
+
+#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(DHD_L2_FILTER)
+bool dhd_sta_associated(dhd_pub_t *dhdp, uint32 bssidx, uint8 *mac)
+{
+ return dhd_find_sta(dhdp, bssidx, mac) ? TRUE : FALSE;
+}
+#endif
+
+#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;
+
+ 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 */
+
+#ifdef DHD_PKTID_AUDIT_ENABLED
+void
+dhd_pktid_audit_fail_cb(dhd_pub_t *dhdp)
+{
+ DHD_ERROR(("%s: Got Pkt Id Audit failure \n", __FUNCTION__));
+ DHD_OS_WAKE_LOCK(dhdp);
+ 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_MEMFILE_BUGON;
+ dhdp->memdump_type = DUMP_TYPE_PKTID_AUDIT_FAILURE;
+ dhd_bus_mem_dump(dhdp);
+#endif /* BCMPCIE && DHD_FW_COREDUMP */
+ DHD_OS_WAKE_UNLOCK(dhdp);
+}
+#endif /* DHD_PKTID_AUDIT_ENABLED */
+
+/* ----------------------------------------------------------------------------
+ * 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 <linux/sysfs.h>
+#include <linux/kobject.h>
+
+#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 */
+
+/*
+ * 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 */
+
+/* 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
+ 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)
+{
+ dhd_info_t *dhd = to_dhd(kobj);
+ struct dhd_attr *d_attr = to_attr(attr);
+ 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)
+{
+ dhd_info_t *dhd = to_dhd(kobj);
+ struct dhd_attr *d_attr = to_attr(attr);
+ 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 */
+ kobject_put(&dhd->dhd_kobj);
+}
+/* ---------------------------- End of sysfs implementation ------------------------------------- */
+
+#ifdef DHD_LOG_DUMP
+void
+dhd_log_dump_init(dhd_pub_t *dhd)
+{
+ spin_lock_init(&dhd->dld_buf.lock);
+#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP)
+ dhd->dld_buf.buffer = DHD_OS_PREALLOC(dhd,
+ DHD_PREALLOC_DHD_LOG_DUMP_BUF, DHD_LOG_DUMP_BUFFER_SIZE);
+#else
+ dhd->dld_buf.buffer = kmalloc(DHD_LOG_DUMP_BUFFER_SIZE, GFP_KERNEL);
+#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */
+
+ if (!dhd->dld_buf.buffer) {
+ dhd->dld_buf.buffer = kmalloc(DHD_LOG_DUMP_BUFFER_SIZE, GFP_KERNEL);
+ DHD_ERROR(("Try to allocate memory using kmalloc().\n"));
+
+ if (!dhd->dld_buf.buffer) {
+ DHD_ERROR(("Failed to allocate memory for dld_buf.\n"));
+ return;
+ }
+ }
+
+ dhd->dld_buf.wraparound = 0;
+ dhd->dld_buf.max = (unsigned long)dhd->dld_buf.buffer + DHD_LOG_DUMP_BUFFER_SIZE;
+ dhd->dld_buf.present = dhd->dld_buf.buffer;
+ dhd->dld_buf.front = dhd->dld_buf.buffer;
+ dhd->dld_buf.remain = DHD_LOG_DUMP_BUFFER_SIZE;
+ dhd->dld_enable = 1;
+}
+
+void
+dhd_log_dump_deinit(dhd_pub_t *dhd)
+{
+ dhd->dld_enable = 0;
+#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP)
+ DHD_OS_PREFREE(dhd,
+ dhd->dld_buf.buffer, DHD_LOG_DUMP_BUFFER_SIZE);
+#else
+ kfree(dhd->dld_buf.buffer);
+#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */
+}
+
+void
+dhd_log_dump_print(const char *fmt, ...)
+{
+ int len = 0;
+ char tmp_buf[DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE] = {0, };
+ va_list args;
+ dhd_pub_t *dhd = NULL;
+ unsigned long flags = 0;
+
+ if (wl_get_bcm_cfg80211_ptr()) {
+ dhd = (dhd_pub_t*)(wl_get_bcm_cfg80211_ptr()->pub);
+ }
+
+ if (!dhd || dhd->dld_enable != 1) {
+ return;
+ }
+
+ va_start(args, fmt);
+
+ len = vsnprintf(tmp_buf, DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE, fmt, args);
+ if (len < 0) {
+ return;
+ }
+
+ /* make a critical section to eliminate race conditions */
+ spin_lock_irqsave(&dhd->dld_buf.lock, flags);
+ if (dhd->dld_buf.remain < len) {
+ dhd->dld_buf.wraparound = 1;
+ dhd->dld_buf.present = dhd->dld_buf.front;
+ dhd->dld_buf.remain = DHD_LOG_DUMP_BUFFER_SIZE;
+ }
+
+ strncpy(dhd->dld_buf.present, tmp_buf, len);
+ dhd->dld_buf.remain -= len;
+ dhd->dld_buf.present += len;
+ spin_unlock_irqrestore(&dhd->dld_buf.lock, flags);
+
+ /* double check invalid memory operation */
+ ASSERT((unsigned long)dhd->dld_buf.present <= dhd->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 */
+
+#ifdef DHD_DEBUG_UART
+static void
+dhd_debug_uart_exec(char *cmd)
+{
+ int ret;
+
+ char *argv[] = {DHD_DEBUG_UART_EXEC_PATH, cmd, NULL};
+ char *envp[] = {"HOME=/", "TERM=linux", "PATH=/sbin:/system/bin", NULL};
+
+ ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
+
+ DHD_ERROR(("DHD: %s - run %s %s ret = %d\n",
+ __FUNCTION__, DHD_DEBUG_UART_EXEC_PATH, cmd, ret));
+}
+#endif
+
+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, 0666);
+ if (IS_ERR(fp)) {
+ DHD_ERROR(("%s: Couldn't open file '%s'\n",
+ __FUNCTION__, filepath));
+ return BCME_ERROR;
+ } else {
+ if (fp->f_mode & FMODE_WRITE) {
+ ret = fp->f_op->write(fp, buf, buf_len, &fp->f_pos);
+ if (ret < 0) {
+ DHD_ERROR(("%s: Couldn't write file '%s'\n",
+ __FUNCTION__, filepath));
+ ret = BCME_ERROR;
+ }
+ }
+ }
+ 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)) {
+ DHD_ERROR(("%s: File %s doesn't exist\n", __FUNCTION__, filepath));
+ return BCME_ERROR;
+ }
+
+ ret = kernel_read(fp, 0, buf, buf_len);
+ 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_BANDSTEER
+/*
+ * Function return true only if there exactly two GO interfaces
+ * TODO: Make it flexible to have AP + AP
+ */
+s32
+dhd_bandsteer_get_ifaces(void *pub, void *ifaces)
+{
+ dhd_if_t *iflist; /* For supporting multiple interfaces */
+ uint8 idx;
+ uint8 ap_idx_count = 0;
+ dhd_pub_t *dhd = (dhd_pub_t *) pub;
+ dhd_bandsteer_iface_info_t *bsd_ifp = (dhd_bandsteer_iface_info_t *)ifaces;
+
+ DHD_INFO(("%s: entered\n", __FUNCTION__));
+ for (idx = 0; idx < DHD_MAX_IFS; idx++) {
+ iflist = dhd->info->iflist[idx];
+ if (iflist == NULL) {
+ continue;
+ }
+
+ if (iflist->net != NULL) {
+ if (iflist->net->ieee80211_ptr != NULL) {
+ if (iflist->net->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
+ ap_idx_count++;
+ if (ap_idx_count > 2) {
+ continue;
+ }
+ bsd_ifp->ndev = iflist->net;
+ bsd_ifp->bssidx = iflist->bssidx;
+ bsd_ifp++;
+ }
+ }
+ }
+ }
+ if (ap_idx_count == 2) {
+ return BCME_OK;
+ } else {
+ return BCME_ERROR;
+ }
+}
+
+void
+dhd_bandsteer_schedule_work_on_timeout(dhd_bandsteer_mac_entry_t *dhd_bandsteer_mac)
+{
+ dhd_bandsteer_context_t *dhd_bandsteer_cntx = dhd_bandsteer_mac->dhd_bandsteer_cntx;
+ dhd_pub_t *dhd = (dhd_pub_t *) dhd_bandsteer_cntx->dhd_pub;
+
+ dhd_deferred_schedule_work(dhd->info->dhd_deferred_wq,
+ (void *)dhd_bandsteer_mac, DHD_WQ_WORK_BANDSTEER_STEP_MOVE,
+ dhd_bandsteer_workqueue_wrapper, DHD_WORK_PRIORITY_LOW);
+}
+#endif /* DHD_BANDSTEER */
+
+#ifdef BCM_AUTO_FWCRC
+/*
+ * extracts CRC field from the firmware binary
+ */
+int dhd_extract_crc(char *filename)
+{
+ struct file *fp = NULL;
+ char crcchk[9] = {0};
+ int crc = 0;
+ int ret = 0;
+
+ fp = filp_open(filename, O_RDONLY, 0);
+ if (IS_ERR(fp)) {
+ DHD_ERROR(("%s: File %s doesn't exist\n", __FUNCTION__, filename));
+ return BCME_ERROR;
+ }
+
+ ret = generic_file_llseek(fp, -(8), SEEK_END);
+ if ((ret < 0) || (ret < 8)) {
+ DHD_ERROR(("%s: file seek failed:%d\n", __FUNCTION__, ret));
+ crc = ret;
+ goto err;
+ }
+
+ ret = kernel_read(fp, ret, crcchk, 8);
+ if (ret < 0) {
+ DHD_ERROR(("read failed\n"));
+ crc = ret;
+ goto err;
+ }
+
+ if (!bcm_atoicrc(crcchk, &crc)) {
+ DHD_INFO(("%s crc:%x\n", __FUNCTION__, crc));
+ } else {
+ DHD_ERROR(("%s crc_int failed\n", __FUNCTION__));
+ crc = BCME_ERROR;
+ goto err;
+ }
+
+ if (!crc || crc == CRC32_INIT_VALUE) {
+ DHD_ERROR(("%s invalid crc\n", __FUNCTION__));
+ crc = BCME_ERROR;
+ }
+
+err: if (fp)
+ filp_close(fp, NULL);
+
+ return crc;
+}
+#define IS_SIZE_VALID(size) (size >= MEMBLOCK ? TRUE:FALSE)
+
+/*
+ * validates firmware image crc
+ */
+int dhd_check_firmware_image(char *memptr, char *filename)
+{
+ char *imgbuf = NULL;
+ int crcval = CRC32_INIT_VALUE;
+ int len = 0;
+ int totlen = 0;
+ int size = 0;
+ int crcchk;
+ int ret = 0;
+
+ if (filename == NULL)
+ return BCME_ERROR;
+
+ size = dhd_os_file_size(filename);
+ if (!IS_SIZE_VALID(size)) {
+ DHD_ERROR(("Invalid file size %s\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+
+ crcchk = dhd_extract_crc(filename);
+ if (crcchk == BCME_ERROR) {
+ ret = BCME_ERROR;
+ goto err;
+ }
+ DHD_INFO(("crcval:%x\n", crcchk));
+
+ if (!memptr) {
+ DHD_ERROR(("%s memory alloc failed\n", __FUNCTION__));
+ ret = BCME_ERROR;
+ goto err;
+ }
+
+ imgbuf = dhd_os_open_image(filename);
+ if (imgbuf == NULL) {
+ DHD_ERROR(("%s file is not proper\n", __FUNCTION__));
+ ret = BCME_ERROR;
+ goto err;
+ }
+
+ 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));
+ break;
+ }
+ wipedates(memptr, MEMBLOCK);
+ totlen += len;
+ if (size == totlen) {
+ len -= 20;
+ totlen -= 20;
+ }
+ crcval = hndcrc32(memptr, len, crcval);
+ }
+
+ DHD_INFO(("%s crcval:%X totlen:%d\n", __FUNCTION__, crcval, totlen));
+
+ if (crcchk == crcval) {
+ DHD_INFO(("%scrc match\n", __FUNCTION__));
+ ret = 0;
+ } else {
+ DHD_ERROR(("%scrc match failure crcchk:%x crcval:%x\n",
+ __FUNCTION__, crcchk, crcval));
+ ret = BCME_ERROR;
+ }
+
+err: if (imgbuf)
+ dhd_os_close_image(imgbuf);
+
+ return ret;
+}
+#endif /* BCM_AUTO_FWCRC */
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_linux.h b/drivers/net/wireless/bcmdhd_1363/dhd_linux.h
new file mode 100644
index 000000000000..1a0ae0e099ca
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_linux.h
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_linux.h 662542 2016-10-28 03:26:10Z $
+ */
+
+/* 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#ifdef DHD_WMF
+#include <dhd_wmf_linux.h>
+#endif
+/* Linux wireless extension support */
+#if defined(WL_WIRELESS_EXT)
+#include <wl_iw.h>
+#endif /* defined(WL_WIRELESS_EXT) */
+#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
+#include <linux/earlysuspend.h>
+#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */
+
+#if defined(CONFIG_WIFI_CONTROL_FUNC)
+#include <linux/wlan_plat.h>
+#endif
+
+#if !defined(CONFIG_WIFI_CONTROL_FUNC)
+#define WLAN_PLAT_NODFS_FLAG 0x01
+struct wifi_platform_data {
+ int (*set_power)(int val);
+ 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);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 58)) || defined(CUSTOM_COUNTRY_CODE)
+ void *(*get_country_code)(char *ccode, u32 flags);
+#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 58)) || defined (CUSTOM_COUNTRY_CODE) */
+ void *(*get_country_code)(char *ccode);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 58)) */
+ };
+#endif /* CONFIG_WIFI_CONTROL_FUNC */
+#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */
+
+typedef struct wifi_adapter_info {
+ const char *name;
+ uint irq_num;
+ uint intr_flags;
+ const char *fw_path;
+ const char *nv_path;
+ void *wifi_plat_data; /* wifi ctrl func, for backward compatibility */
+ uint bus_type;
+ uint bus_num;
+ uint slot_num;
+#ifdef OOB_PARAM
+ uint oob_disable;
+#endif /* OOB_PARAM */
+} wifi_adapter_info_t;
+
+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 */
+} 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_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);
+#endif /* DHD_WMF */
+#endif /* __DHD_LINUX_H__ */
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_linux_platdev.c b/drivers/net/wireless/bcmdhd_1363/dhd_linux_platdev.c
new file mode 100644
index 000000000000..85b6b14d00fc
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_linux_platdev.c
@@ -0,0 +1,901 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_linux_platdev.c 662542 2016-10-28 03:26:10Z $
+ */
+#include <typedefs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <bcmutils.h>
+#include <linux_osl.h>
+#include <dhd_dbg.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_bus.h>
+#include <dhd_linux.h>
+#include <wl_android.h>
+#if defined(CONFIG_WIFI_CONTROL_FUNC)
+#include <linux/wlan_plat.h>
+#endif
+#ifdef CONFIG_DTS
+#include<linux/regulator/consumer.h>
+#include<linux/of_gpio.h>
+#endif /* CONFIG_DTS */
+
+
+#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;
+#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;
+struct resource dhd_wlan_resources = {0};
+struct wifi_platform_data dhd_wlan_control = {0};
+#endif /* CONFIG_OF && !defined(CONFIG_ARCH_MSM) */
+#endif /* !defind(CONFIG_DTS) */
+
+static int dhd_wifi_platform_load(void);
+
+extern void* wl_cfg80211_get_dhdp(void);
+
+#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_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;
+ }
+ }
+
+ 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;
+#ifdef CONFIG_DTS
+ if (on) {
+ err = regulator_enable(wifi_regulator);
+ is_power_on = TRUE;
+ }
+ else {
+ err = regulator_disable(wifi_regulator);
+ is_power_on = FALSE;
+ }
+ if (err < 0)
+ DHD_ERROR(("%s: regulator enable/disable failed", __FUNCTION__));
+#else
+ struct wifi_platform_data *plat_data;
+
+ if (!adapter || !adapter->wifi_plat_data)
+ return -EINVAL;
+ 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 */
+
+ err = plat_data->set_power(on);
+ }
+
+ if (msec && !err)
+ OSL_SLEEP(msec);
+
+ if (on && !err)
+ is_power_on = TRUE;
+ else
+ is_power_on = FALSE;
+
+#endif /* CONFIG_DTS */
+
+ return err;
+}
+#if defined(CUSTOMER_IMX)
+
+extern void wifi_card_detect(bool);
+int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present)
+{
+ int err = 0;
+ struct wifi_platform_data *plat_data;
+
+ if (!adapter) {
+ pr_err("!!!! %s: failed! adapter variable is NULL!!!!!\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ DHD_ERROR(("%s device present %d\n", __FUNCTION__, device_present));
+
+ if (!adapter->wifi_plat_data) {
+ wifi_card_detect(device_present); /* hook for card_detect */
+ } else {
+ plat_data = adapter->wifi_plat_data;
+ if (plat_data->set_carddetect) {
+ err = plat_data->set_carddetect(device_present);
+ BCM_REFERENCE(err);
+ }
+ }
+
+ return 0; /* force success status returned */
+}
+
+#else
+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;
+
+}
+#endif /* CUSTOMER_IMX */
+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;
+}
+#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 */
+{
+ /* 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) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 58))
+ return plat_data->get_country_code(ccode, WLAN_PLAT_NODFS_FLAG);
+#else
+#ifdef CUSTOM_COUNTRY_CODE
+ 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(3, 10, 58)) */
+ }
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */
+
+ return NULL;
+}
+
+static int wifi_plat_dev_drv_probe(struct platform_device *pdev)
+{
+ struct resource *resource;
+ wifi_adapter_info_t *adapter;
+#ifdef CONFIG_DTS
+ int ret = 0;
+#if defined(OOB_INTR_ONLY)
+ int irq, gpio;
+#endif /* defined(OOB_INTR_ONLY) */
+#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];
+ adapter->wifi_plat_data = (struct wifi_platform_data *)(pdev->dev.platform_data);
+
+ 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 OOB_PARAM
+ adapter->oob_disable = FALSE;
+#endif /* OOB_PARAM */
+
+#ifdef CONFIG_DTS
+ /* get firmware from dts */
+ ret = of_property_read_string(pdev->dev.of_node, "bcmdhd_fw",
+ &adapter->fw_path);
+ if (!ret)
+ DHD_INFO(("fw path:%s\n", adapter->fw_path));
+ ret = of_property_read_string(pdev->dev.of_node, "bcmdhd_nv",
+ &adapter->nv_path);
+ if (!ret)
+ DHD_INFO(("nv path:%s\n", adapter->nv_path));
+
+ wifi_regulator = regulator_get(&pdev->dev, "wlreg_on");
+ if (wifi_regulator == NULL) {
+ DHD_ERROR(("%s regulator is null\n", __FUNCTION__));
+ return -1;
+ }
+#if defined(OOB_INTR_ONLY)
+ OOB_PARAM_IF(!(adapter->oob_disable)) {
+ /* This is to get the irq for the OOB */
+ gpio = of_get_gpio(pdev->dev.of_node, 0);
+
+ if (gpio < 0) {
+ DHD_ERROR(("%s no GPIO for OOB in device tree.\n", __FUNCTION__));
+#if defined(OOB_PARAM)
+ DHD_ERROR(("%s continue with non-OOB mode.\n", __FUNCTION__));
+ adapter->oob_disable = TRUE;
+ goto out;
+#else
+ return -1;
+#endif /* defined(OOB_PARAM) */
+ }
+
+ 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 */
+#if defined(HW_OOB)
+ adapter->intr_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL |
+ IORESOURCE_IRQ_SHAREABLE;
+#else
+ adapter->intr_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
+ IORESOURCE_IRQ_SHAREABLE;
+#endif /* defined(HW_OOB) */
+ }
+
+#if defined(OOB_PARAM)
+out:
+#endif /* defined(OOB_PARAM) */
+#endif /* defined(OOB_INTR_ONLY) */
+#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)
+{
+#ifdef OOB_PARAM
+ wifi_adapter_info_t *adapter;
+ adapter = &dhd_wifi_platdata->adapters[0];
+#endif /* OOB_PARAM */
+
+ DHD_TRACE(("##> %s\n", __FUNCTION__));
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && \
+ defined(BCMSDIO)
+ OOB_PARAM_IF(!(adapter->oob_disable)) {
+ bcmsdh_oob_intr_set(0);
+ }
+#endif /* (OOB_INTR_ONLY) */
+ return 0;
+}
+
+static int wifi_plat_dev_drv_resume(struct platform_device *pdev)
+{
+#ifdef OOB_PARAM
+ wifi_adapter_info_t *adapter;
+ adapter = &dhd_wifi_platdata->adapters[0];
+#endif /* OOB_PARAM */
+
+ DHD_TRACE(("##> %s\n", __FUNCTION__));
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && \
+ defined(BCMSDIO)
+ OOB_PARAM_IF(!(adapter->oob_disable)) {
+ if (dhd_os_check_if_up(wl_cfg80211_get_dhdp(NULL)))
+ 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;
+ struct platform_device *pdev = to_platform_device(dev);
+
+ if (strcmp(pdev->name, name) == 0) {
+ DHD_ERROR(("found wifi platform device %s\n", name));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int wifi_ctrlfunc_register_drv(void)
+{
+ int err = 0;
+ struct device *dev1, *dev2;
+ wifi_adapter_info_t *adapter;
+
+ 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 !defined(CONFIG_DTS)
+ 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;
+
+ 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;
+ }
+ }
+
+#if !defined(CONFIG_DTS)
+ if (dts_enabled) {
+ struct resource *resource;
+ adapter->wifi_plat_data = (void *)&dhd_wlan_control;
+ resource = &dhd_wlan_resources;
+ adapter->irq_num = resource->start;
+ adapter->intr_flags = resource->flags & IRQF_TRIGGER_MASK;
+ wifi_plat_dev_probe_ret = dhd_wifi_platform_load();
+ }
+#endif /* !defined(CONFIG_DTS) */
+
+
+#ifdef CONFIG_DTS
+ 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)
+{
+
+#ifdef CONFIG_DTS
+ DHD_ERROR(("unregister wifi platform drivers\n"));
+ platform_driver_unregister(&wifi_platform_dev_driver);
+#else
+ 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;
+
+ DHD_ERROR(("unregister wifi platform drivers\n"));
+ if (dev1)
+ platform_driver_unregister(&wifi_platform_dev_driver);
+ if (dev2)
+ platform_driver_unregister(&wifi_platform_dev_driver_legacy);
+ if (dts_enabled) {
+ wifi_adapter_info_t *adapter;
+ 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) */
+
+ kfree(dhd_wifi_platdata->adapters);
+ dhd_wifi_platdata->adapters = NULL;
+ dhd_wifi_platdata->num_adapters = 0;
+ kfree(dhd_wifi_platdata);
+ dhd_wifi_platdata = NULL;
+}
+
+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,
+ }
+};
+
+int dhd_wifi_platform_register_drv(void)
+{
+ int err = 0;
+ 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 {
+ 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) {
+ 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)
+{
+ if (cfg_multichip)
+ platform_driver_unregister(&dhd_wifi_platform_dev_driver);
+ else
+ wifi_ctrlfunc_unregister_drv();
+}
+
+extern int dhd_watchdog_prio;
+extern int dhd_dpc_prio;
+extern uint dhd_deferred_tx;
+#if defined(BCMLXSDMMC)
+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)
+ if (dhd_wifi_platdata == NULL) {
+ DHD_ERROR(("DHD wifi platform data is required for Android build\n"));
+ return -EINVAL;
+ }
+
+ sema_init(&dhd_registration_sem, 0);
+ /* 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;
+ }
+ err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY);
+ if (err) {
+ /* 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);
+ err = 0;
+ }
+
+ 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 */
+
+static int dhd_wifi_platform_load_usb(void)
+{
+ return 0;
+}
+
+static int dhd_wifi_platform_load()
+{
+ int err = 0;
+
+ 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();
+ else
+ wl_android_post_init();
+
+ return err;
+}
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_linux_sched.c b/drivers/net/wireless/bcmdhd_1363/dhd_linux_sched.c
new file mode 100644
index 000000000000..88c0cce635bd
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_linux_sched.c 514727 2014-11-12 03:02:48Z $
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <typedefs.h>
+#include <linuxver.h>
+
+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/drivers/net/wireless/bcmdhd_1363/dhd_linux_wq.c b/drivers/net/wireless/bcmdhd_1363/dhd_linux_wq.c
new file mode 100644
index 000000000000..abbfe48f88f3
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_linux_wq.c
@@ -0,0 +1,320 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_linux_wq.c 514727 2014-11-12 03:02:48Z $
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/ip.h>
+#include <linux/kfifo.h>
+
+#include <linuxver.h>
+#include <osl.h>
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <bcmdevs.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_dbg.h>
+#include <dhd_linux_wq.h>
+
+struct dhd_deferred_event_t {
+ u8 event; /* holds the event */
+ void *event_data; /* Holds event specific data */
+ event_handler_t event_handler;
+};
+#define DEFRD_EVT_SIZE sizeof(struct dhd_deferred_event_t)
+
+struct dhd_deferred_wq {
+ struct work_struct deferred_work; /* should be the first member */
+
+ /*
+ * work events may occur simultaneously.
+ * Can hold upto 64 low priority events and 4 high priority events
+ */
+#define DHD_PRIO_WORK_FIFO_SIZE (4 * sizeof(struct dhd_deferred_event_t))
+#define DHD_WORK_FIFO_SIZE (64 * sizeof(struct dhd_deferred_event_t))
+ 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 alread \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);
+}
+
+/*
+ * 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 dhd_deferred_event_t deferred_event;
+ int status;
+
+ 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 \n", __FUNCTION__));
+ return DHD_WQ_STS_UNKNOWN_EVENT;
+ }
+
+ /*
+ * 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;
+
+ if (priority == DHD_WORK_PRIORITY_HIGH) {
+ status = kfifo_in_spinlocked(deferred_wq->prio_fifo, &deferred_event,
+ DEFRD_EVT_SIZE, &deferred_wq->work_lock);
+ } else {
+ status = kfifo_in_spinlocked(deferred_wq->work_fifo, &deferred_event,
+ DEFRD_EVT_SIZE, &deferred_wq->work_lock);
+ }
+
+ if (!status) {
+ return DHD_WQ_STS_SCHED_FAILED;
+ }
+ schedule_work((struct work_struct *)deferred_wq);
+ return DHD_WQ_STS_OK;
+}
+
+static int
+dhd_get_scheduled_work(struct dhd_deferred_wq *deferred_wq, struct dhd_deferred_event_t *event)
+{
+ int status = 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);
+
+ /* first read priorit event fifo */
+ status = kfifo_out_spinlocked(deferred_wq->prio_fifo, event,
+ DEFRD_EVT_SIZE, &deferred_wq->work_lock);
+
+ if (!status) {
+ /* priority fifo is empty. Now read low prio work fifo */
+ status = kfifo_out_spinlocked(deferred_wq->work_fifo, event,
+ DEFRD_EVT_SIZE, &deferred_wq->work_lock);
+ }
+
+ return status;
+}
+
+/*
+ * 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;
+ struct dhd_deferred_event_t work_event;
+ int status;
+
+ if (!deferred_work) {
+ DHD_ERROR(("%s: work queue not initialized\n", __FUNCTION__));
+ return;
+ }
+
+ do {
+ status = dhd_get_scheduled_work(deferred_work, &work_event);
+ DHD_TRACE(("%s: event to handle %d \n", __FUNCTION__, status));
+ if (!status) {
+ DHD_TRACE(("%s: No event to handle %d \n", __FUNCTION__, status));
+ break;
+ }
+
+ if (work_event.event > DHD_MAX_WQ_EVENTS) {
+ DHD_TRACE(("%s: Unknown event %d \n", __FUNCTION__, work_event.event));
+ break;
+ }
+
+ 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 not defined %d\n", __FUNCTION__, work_event.event));
+ }
+ } while (1);
+ return;
+}
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_linux_wq.h b/drivers/net/wireless/bcmdhd_1363/dhd_linux_wq.h
new file mode 100644
index 000000000000..194256ef8fe1
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_linux_wq.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_linux_wq.h 653928 2016-08-10 10:32:42Z $
+ */
+#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_BANDSTEER_STEP_MOVE,
+
+ DHD_MAX_WQ_EVENTS
+};
+
+/*
+ * Work event priority
+ */
+#define DHD_WORK_PRIORITY_LOW 0
+#define DHD_WORK_PRIORITY_HIGH 1
+
+/*
+ * 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
+
+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/drivers/net/wireless/bcmdhd_1363/dhd_msgbuf.c b/drivers/net/wireless/bcmdhd_1363/dhd_msgbuf.c
new file mode 100644
index 000000000000..354c9c86f4eb
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_msgbuf.c
@@ -0,0 +1,6427 @@
+/**
+ * @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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_msgbuf.c 664367 2017-03-23 09:23:22Z $
+ */
+
+
+#include <typedefs.h>
+#include <osl.h>
+
+#include <bcmutils.h>
+#include <bcmmsgbuf.h>
+#include <bcmendian.h>
+
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_proto.h>
+
+#include <dhd_bus.h>
+
+#include <dhd_dbg.h>
+#include <siutils.h>
+
+
+#include <dhd_flowring.h>
+
+#include <pcie_core.h>
+#include <bcmpcie.h>
+#include <dhd_pcie.h>
+
+#if defined(DHD_LB)
+#include <linux/cpu.h>
+#include <bcm_ring.h>
+#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 */
+
+
+/**
+ * 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 <address,value>
+ * 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)
+#define FLOWRING_SIZE (H2DRING_TXPOST_MAX_ITEM * H2DRING_TXPOST_ITEMSIZE)
+
+/* 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
+
+#define DHD_FLOWRING_IOCTL_BUFPOST_PKTSZ 8192
+
+#define DHD_FLOWRING_MAX_EVENTBUF_POST 8
+#define DHD_FLOWRING_MAX_IOCTLRESPBUF_POST 8
+
+#define DHD_PROT_FUNCS 37
+
+/* 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
+
+
+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
+
+#if defined(PCIE_D2H_SYNC)
+#define PCIE_D2H_SYNC_WAIT_TRIES (512UL)
+#define PCIE_D2H_SYNC_NUM_OF_STEPS (3UL)
+#define PCIE_D2H_SYNC_DELAY (50UL) /* 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);
+#endif /* PCIE_D2H_SYNC */
+
+
+/*
+ * +----------------------------------------------------------------------------
+ *
+ * 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) \
+ ((ringid) >= 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) \
+ ((DHD_IS_FLOWRING(ringid)) ? DHD_RINGID_TO_FLOWID(ringid) : (ringid))
+
+/* 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.
+ */
+#define DHD_D2H_RING_OFFSET(ringid) \
+ ((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;
+} 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 */
+ uchar name[RING_NAME_MAX_LENGTH];
+} 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))
+
+
+
+/** 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 cur_event_bufs_posted;
+ uint16 cur_ioctlresp_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 max_tx_count;
+ 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 *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 */
+
+ /* 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 host_bus_throughput_buf; /* bus throughput measure buffer */
+
+ dhd_dma_buf_t *flowring_buf; /* pool of flow ring buf */
+ uint32 flowring_num;
+
+#if defined(PCIE_D2H_SYNC)
+ 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 */
+#endif /* PCIE_D2H_SYNC */
+
+ dhd_dmaxfer_t dmaxfer; /* for test/DMA loopback */
+
+ uint16 ioctl_seq_no;
+ uint16 data_seq_no;
+ uint16 ioctl_trans_id;
+ void *pktid_map_handle; /* a pktid maps to a packet and its metadata */
+ 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 */
+#if defined(DHD_LB)
+ /* 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 */
+#endif /* DHD_LB */
+} dhd_prot_t;
+
+/* 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);
+
+/* 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);
+
+/* Allocate DMA-able memory for saving H2D/D2H WR/RD indices */
+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() */
+static 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, bool event_buf, 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 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_rxcmplt_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);
+
+/* Configure a soft doorbell per D2H ring */
+static void dhd_msgbuf_ring_config_d2h_soft_doorbell(dhd_pub_t *dhd);
+static void dhd_prot_d2h_ring_config_cmplt_process(dhd_pub_t *dhd, void *msg);
+
+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,
+ dhd_prot_rxcmplt_process, /* MSG_TYPE_RX_CMPLT */
+ NULL,
+ dhd_msgbuf_dmaxfer_process, /* MSG_TYPE_LPBK_DMAXFER_CMPLT */
+ NULL, /* MSG_TYPE_FLOW_RING_RESUME */
+ NULL, /* MSG_TYPE_FLOW_RING_RESUME_CMPLT */
+ NULL, /* MSG_TYPE_FLOW_RING_SUSPEND */
+ NULL, /* MSG_TYPE_FLOW_RING_SUSPEND_CMPLT */
+ NULL, /* MSG_TYPE_INFO_BUF_POST */
+ NULL, /* MSG_TYPE_INFO_BUF_CMPLT */
+ NULL, /* MSG_TYPE_H2D_RING_CREATE */
+ NULL, /* MSG_TYPE_D2H_RING_CREATE */
+ NULL, /* MSG_TYPE_H2D_RING_CREATE_CMPLT */
+ NULL, /* 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_d2h_ring_config_cmplt_process, /* MSG_TYPE_D2H_RING_CONFIG_CMPLT */
+ NULL, /* MSG_TYPE_H2D_MAILBOX_DATA */
+ NULL, /* MSG_TYPE_D2H_MAILBOX_DATA */
+};
+
+
+#ifdef DHD_RX_CHAINING
+
+#define PKT_CTF_CHAINABLE(dhd, ifidx, evh, prio, h_sa, h_da, h_prio) \
+ (!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))) && \
+ dhd_l2_filter_chainable((dhd), (evh), (ifidx)))
+
+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);
+
+#if defined(PCIE_D2H_SYNC) /* avoids problems related to host CPU cache */
+
+/**
+ * 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, msgbuf_ring_t *ring,
+ uint32 tries, 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);
+
+void dhd_prot_collect_memdump(dhd_pub_t *dhd)
+{
+ DHD_ERROR(("%s(): Collecting mem dump now \r\n", __FUNCTION__));
+#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 */
+#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_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, msgbuf_ring_t *ring, uint32 tries,
+ uchar *msg, int msglen)
+{
+ uint32 seqnum = ring->seqnum;
+
+ DHD_ERROR(("LIVELOCK DHD<%p> name<%s> seqnum<%u:%u> tries<%u> max<%lu> tot<%lu>"
+ "dma_buf va<%p> msg<%p> curr_rd<%d>\n",
+ dhd, ring->name, seqnum, 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", (uchar *)msg, msglen);
+ dhd_dump_to_kernelog(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 */
+#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 = (uint32 *)msg + (num_words - 1); /* last word */
+ 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 = 1; tries <= PCIE_D2H_SYNC_WAIT_TRIES; tries++) {
+ uint32 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 */
+#if defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_SOC_EXYNOS8890)
+ /* For ARM there is no pause in cpu_relax, so add extra delay */
+ OSL_DELAY(delay * step);
+#endif /* defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_SOC_EXYNOS8890) */
+ } /* for PCIE_D2H_SYNC_WAIT_TRIES */
+ } /* for number of steps */
+
+ dhd_prot_d2h_sync_livelock(dhd, ring, total_tries, (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 += total_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 = 1; 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 */
+#if defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_SOC_EXYNOS8890)
+ /* For ARM there is no pause in cpu_relax, so add extra delay */
+ OSL_DELAY(delay * step);
+#endif /* defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_SOC_EXYNOS8890) */
+
+ } /* for PCIE_D2H_SYNC_WAIT_TRIES */
+ } /* for number of steps */
+
+ dhd_prot_d2h_sync_livelock(dhd, ring, total_tries, (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 += total_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;
+}
+
+/**
+ * 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_tx_cpln.seqnum = D2H_EPOCH_INIT_VAL;
+ prot->d2hring_rx_cpln.seqnum = D2H_EPOCH_INIT_VAL;
+
+ if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_SEQNUM) {
+ prot->d2h_sync_cb = dhd_prot_d2h_sync_seqnum;
+ } else if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_XORCSUM) {
+ prot->d2h_sync_cb = dhd_prot_d2h_sync_xorcsum;
+ } else {
+ prot->d2h_sync_cb = dhd_prot_d2h_sync_none;
+ }
+}
+
+#endif /* PCIE_D2H_SYNC */
+
+int INLINE
+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);
+ return 0;
+}
+
+/**
+ * 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_ctrl_subn.seqnum = H2D_EPOCH_INIT_VAL;
+}
+
+/* +----------------- 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 base, end; /* dongle uses 32bit ptr arithmetic */
+
+ ASSERT(dma_buf);
+ base = PHYSADDRLO(dma_buf->pa);
+ ASSERT(base);
+ ASSERT(ISALIGNED(base, DMA_ALIGN_LEN));
+ ASSERT(dma_buf->len != 0);
+
+ /* test 32bit offset arithmetic over dma buffer for loss of carry-over */
+ end = (base + dma_buf->len); /* end address */
+
+ if ((end & 0xFFFFFFFF) < (base & 0xFFFFFFFF)) { /* exclude carryover */
+ DHD_ERROR(("%s: dma_buf %x len %d spans dongle 32bit ptr arithmetic\n",
+ __FUNCTION__, base, 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;
+
+ 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_LEN, &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_PKTID_ITEMS (3072) /* Maximum number of pktids supported */
+
+/* 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,
+ /* dhd_prot_pkt_free no check, if pktid reserved and no space avail case */
+ PKTTYPE_NO_CHECK
+} dhd_pkttype_t;
+
+#define DHD_PKTID_INVALID (0U)
+#define DHD_IOCTL_REQ_PKTID (0xFFFE)
+#define DHD_FAKE_PKTID (0xFACE)
+
+#define DHD_PKTID_FREE_LOCKER (FALSE)
+#define DHD_PKTID_RSV_LOCKER (TRUE)
+
+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, uint32 index);
+
+/* 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 PKTID_MAP_HANDLE (0)
+#define PKTID_MAP_HANDLE_IOCTL (1)
+
+#define DHD_NATIVE_TO_PKTID_INIT(dhd, items, index) dhd_pktid_map_init((dhd), (items), (index))
+#define DHD_NATIVE_TO_PKTID_FINI(dhd, map) dhd_pktid_map_fini((dhd), (map))
+
+#if defined(DHD_PCIE_PKTID)
+
+
+/* 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);
+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 */
+
+/* Packet metadata saved in packet id mapper */
+
+/* The Locker can be 3 states
+ * LOCKER_IS_FREE - Locker is free and can be allocated
+ * LOCKER_IS_BUSY - Locker is assigned and is being used, values in the
+ * locker (buffer address, len, phy addr etc) are populated
+ * with valid values
+ * LOCKER_IS_RSVD - The locker is reserved for future use, but the values
+ * in the locker are not valid. Especially pkt should be
+ * NULL in this state. When the user wants to re-use the
+ * locker dhd_pktid_map_free can be called with a flag
+ * to reserve the pktid for future use, which will clear
+ * the contents of the locker. When the user calls
+ * dhd_pktid_map_save the locker would move to LOCKER_IS_BUSY
+ */
+typedef enum dhd_locker_state {
+ LOCKER_IS_FREE,
+ LOCKER_IS_BUSY,
+ LOCKER_IS_RSVD
+} dhd_locker_state_t;
+
+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 struct dhd_pktid_map {
+ uint32 items; /* total items in map */
+ uint32 avail; /* total available items */
+ int failures; /* lockers unavailable count */
+ /* Spinlock to protect dhd_pktid_map in process/tasklet context */
+ void *pktid_lock; /* Used when USE_DHD_PKTID_LOCK is defined */
+
+#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 */
+
+ uint32 keys[MAX_PKTID_ITEMS + 1]; /* stack of 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_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_NATIVE_TO_PKTID_FINI_IOCTL(dhd, map) dhd_pktid_map_fini_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) dhd_pktid_map_reserve((dhd), (map), (pkt))
+
+/* 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)
+
+static int dhd_pktid_audit(dhd_pub_t *dhd, dhd_pktid_map_t *pktid_map, uint32 pktid,
+ const int test_for, const char *errmsg);
+
+/**
+* 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: "
+
+ const uint32 max_pktid_items = (MAX_PKTID_ITEMS);
+ 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 > max_pktid_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_audit_fail_cb(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__)
+
+#endif /* DHD_PKTID_AUDIT_ENABLED */
+
+/* +------------------ End of PCIE DHD PKTID AUDIT ------------------------+ */
+
+
+/**
+ * +---------------------------------------------------------------------------+
+ * Packet to Packet Id mapper using a <numbered_key, locker> paradigm.
+ *
+ * dhd_pktid_map manages a set of unique Packet Ids range[1..MAX_PKTID_ITEMS].
+ *
+ * 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 <key,locker> 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 <numbered_key, locker> */
+
+static dhd_pktid_map_handle_t *
+dhd_pktid_map_init(dhd_pub_t *dhd, uint32 num_items, uint32 index)
+{
+ void *osh;
+ uint32 nkey;
+ dhd_pktid_map_t *map;
+ uint32 dhd_pktid_map_sz;
+ uint32 map_items;
+#ifdef DHD_USE_STATIC_PKTIDMAP
+ uint32 section;
+#endif /* DHD_USE_STATIC_PKTIDMAP */
+ osh = dhd->osh;
+
+ ASSERT((num_items >= 1) && (num_items <= MAX_PKTID_ITEMS));
+ dhd_pktid_map_sz = DHD_PKTID_MAP_SZ(num_items);
+
+#ifdef DHD_USE_STATIC_PKTIDMAP
+ if (index == PKTID_MAP_HANDLE) {
+ section = DHD_PREALLOC_PKTID_MAP;
+ } else {
+ section = DHD_PREALLOC_PKTID_MAP_IOCTL;
+ }
+
+ map = (dhd_pktid_map_t *)DHD_OS_PREALLOC(dhd, section, dhd_pktid_map_sz);
+#else
+ map = (dhd_pktid_map_t *)MALLOC(osh, dhd_pktid_map_sz);
+#endif /* DHD_USE_STATIC_PKTIDMAP */
+
+ if (map == NULL) {
+ DHD_ERROR(("%s:%d: MALLOC failed for size %d\n",
+ __FUNCTION__, __LINE__, dhd_pktid_map_sz));
+ goto error;
+ }
+
+ bzero(map, dhd_pktid_map_sz);
+
+ /* Initialize the lock that protects this structure */
+ map->pktid_lock = DHD_PKTID_LOCK_INIT(osh);
+ if (map->pktid_lock == NULL) {
+ DHD_ERROR(("%s:%d: Lock init failed \r\n", __FUNCTION__, __LINE__));
+ goto error;
+ }
+
+ map->items = num_items;
+ map->avail = num_items;
+
+ map_items = DHD_PKIDMAP_ITEMS(map->items);
+
+#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 busy */
+ map->lockers[DHD_PKTID_INVALID].state = LOCKER_IS_BUSY;
+ 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->pktid_lock)
+ DHD_PKTID_LOCK_DEINIT(osh, map->pktid_lock);
+
+ MFREE(osh, map, dhd_pktid_map_sz);
+ }
+
+ return (dhd_pktid_map_handle_t *)NULL;
+}
+
+/**
+ * Retrieve all allocated keys and free all <numbered_key, locker>.
+ * 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_fini(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle)
+{
+ void *osh;
+ uint32 nkey;
+ dhd_pktid_map_t *map;
+ uint32 dhd_pktid_map_sz;
+ dhd_pktid_item_t *locker;
+ uint32 map_items;
+ uint32 flags;
+
+ if (handle == NULL) {
+ return;
+ }
+
+ map = (dhd_pktid_map_t *)handle;
+ flags = DHD_PKTID_LOCK(map->pktid_lock);
+ osh = dhd->osh;
+
+ dhd_pktid_map_sz = DHD_PKTID_MAP_SZ(map->items);
+
+ nkey = 1; /* skip reserved KEY #0, and start from 1 */
+ locker = &map->lockers[nkey];
+
+ map_items = DHD_PKIDMAP_ITEMS(map->items);
+
+ for (; nkey <= map_items; nkey++, locker++) {
+
+ if (locker->state == LOCKER_IS_BUSY) { /* numbered key still in use */
+
+ locker->state = LOCKER_IS_FREE; /* force open the locker */
+
+#if defined(DHD_PKTID_AUDIT_ENABLED)
+ DHD_PKTID_AUDIT(dhd, map, nkey, DHD_DUPLICATE_FREE); /* duplicate frees */
+#endif /* DHD_PKTID_AUDIT_ENABLED */
+
+ { /* This could be a callback registered with dhd_pktid_map */
+ DMA_UNMAP(osh, locker->pa, locker->len,
+ locker->dir, 0, DHD_DMAH_NULL);
+ dhd_prot_packet_free(dhd, (ulong*)locker->pkt,
+ locker->pkttype, TRUE);
+ }
+ }
+#if defined(DHD_PKTID_AUDIT_ENABLED)
+ else {
+ DHD_PKTID_AUDIT(dhd, map, nkey, DHD_TEST_IS_FREE);
+ }
+#endif /* DHD_PKTID_AUDIT_ENABLED */
+
+ locker->pkt = NULL; /* clear saved pkt */
+ locker->len = 0;
+ }
+
+#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 */
+
+ DHD_PKTID_UNLOCK(map->pktid_lock, flags);
+ DHD_PKTID_LOCK_DEINIT(osh, map->pktid_lock);
+
+#ifdef DHD_USE_STATIC_PKTIDMAP
+ DHD_OS_PREFREE(dhd, handle, dhd_pktid_map_sz);
+#else
+ MFREE(osh, handle, dhd_pktid_map_sz);
+#endif /* DHD_USE_STATIC_PKTIDMAP */
+}
+
+#ifdef IOCTLRESP_USE_CONSTMEM
+/** Called in detach scenario. Releasing IOCTL buffers. */
+static void
+dhd_pktid_map_fini_ioctl(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle)
+{
+ uint32 nkey;
+ dhd_pktid_map_t *map;
+ uint32 dhd_pktid_map_sz;
+ dhd_pktid_item_t *locker;
+ uint32 map_items;
+ uint32 flags;
+ osl_t *osh = dhd->osh;
+
+ if (handle == NULL) {
+ return;
+ }
+
+ map = (dhd_pktid_map_t *)handle;
+ flags = DHD_PKTID_LOCK(map->pktid_lock);
+
+ dhd_pktid_map_sz = DHD_PKTID_MAP_SZ(map->items);
+
+ nkey = 1; /* skip reserved KEY #0, and start from 1 */
+ locker = &map->lockers[nkey];
+
+ map_items = DHD_PKIDMAP_ITEMS(map->items);
+
+ for (; nkey <= map_items; nkey++, locker++) {
+
+ if (locker->state == LOCKER_IS_BUSY) { /* numbered key still in use */
+
+ locker->state = LOCKER_IS_FREE; /* force open the locker */
+
+#if defined(DHD_PKTID_AUDIT_ENABLED)
+ DHD_PKTID_AUDIT(dhd, map, nkey, DHD_DUPLICATE_FREE); /* duplicate frees */
+#endif /* DHD_PKTID_AUDIT_ENABLED */
+
+ {
+ dhd_dma_buf_t retbuf;
+ 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_PKTID_UNLOCK(map->pktid_lock, flags);
+ free_ioctl_return_buffer(dhd, &retbuf);
+ flags = DHD_PKTID_LOCK(map->pktid_lock);
+ }
+ }
+#if defined(DHD_PKTID_AUDIT_ENABLED)
+ else {
+ DHD_PKTID_AUDIT(dhd, map, nkey, DHD_TEST_IS_FREE);
+ }
+#endif /* DHD_PKTID_AUDIT_ENABLED */
+
+ locker->pkt = NULL; /* clear saved pkt */
+ locker->len = 0;
+ }
+
+#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 */
+
+ DHD_PKTID_UNLOCK(map->pktid_lock, flags);
+ DHD_PKTID_LOCK_DEINIT(osh, map->pktid_lock);
+
+#ifdef DHD_USE_STATIC_PKTIDMAP
+ DHD_OS_PREFREE(dhd, handle, dhd_pktid_map_sz);
+#else
+ MFREE(osh, handle, dhd_pktid_map_sz);
+#endif /* DHD_USE_STATIC_PKTIDMAP */
+}
+#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 flags;
+ uint32 avail;
+
+ ASSERT(handle != NULL);
+ map = (dhd_pktid_map_t *)handle;
+
+ flags = DHD_PKTID_LOCK(map->pktid_lock);
+ avail = map->avail;
+ DHD_PKTID_UNLOCK(map->pktid_lock, flags);
+
+ return avail;
+}
+
+/**
+ * Allocate locker, save pkt contents, and return the locker's numbered key.
+ * dhd_pktid_map_alloc() 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)
+{
+ uint32 nkey;
+ dhd_pktid_map_t *map;
+ dhd_pktid_item_t *locker;
+
+ ASSERT(handle != NULL);
+ map = (dhd_pktid_map_t *)handle;
+
+ if (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 */
+ 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 */
+
+#if defined(DHD_PKTID_AUDIT_MAP)
+ DHD_PKTID_AUDIT(dhd, map, nkey, DHD_DUPLICATE_ALLOC); /* Audit duplicate alloc */
+#endif /* DHD_PKTID_AUDIT_MAP */
+
+ ASSERT(nkey != DHD_PKTID_INVALID);
+ return nkey; /* return locker's numbered key */
+}
+
+
+/**
+ * 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.
+ * Wrapper that takes the required lock when called directly.
+ */
+static INLINE uint32
+dhd_pktid_map_reserve(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, void *pkt)
+{
+ dhd_pktid_map_t *map;
+ uint32 flags;
+ uint32 ret;
+
+ ASSERT(handle != NULL);
+ map = (dhd_pktid_map_t *)handle;
+ flags = DHD_PKTID_LOCK(map->pktid_lock);
+ ret = __dhd_pktid_map_reserve(dhd, handle, pkt);
+ DHD_PKTID_UNLOCK(map->pktid_lock, flags);
+
+ return ret;
+}
+
+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;
+
+ ASSERT((nkey != DHD_PKTID_INVALID) && (nkey <= DHD_PKIDMAP_ITEMS(map->items)));
+
+ locker = &map->lockers[nkey];
+
+ ASSERT(((locker->state == LOCKER_IS_BUSY) && (locker->pkt == pkt)) ||
+ ((locker->state == LOCKER_IS_RSVD) && (locker->pkt == NULL)));
+
+#if defined(DHD_PKTID_AUDIT_MAP)
+ DHD_PKTID_AUDIT(dhd, map, nkey, DHD_TEST_IS_ALLOC); /* apriori, reservation */
+#endif /* DHD_PKTID_AUDIT_MAP */
+
+ /* 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_save - Save a packet's parameters into a locker corresponding
+ * to a previously reserved unique numbered key.
+ * Wrapper that takes the required lock when called directly.
+ */
+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;
+ uint32 flags;
+
+ ASSERT(handle != NULL);
+ map = (dhd_pktid_map_t *)handle;
+ flags = DHD_PKTID_LOCK(map->pktid_lock);
+ __dhd_pktid_map_save(dhd, handle, pkt, nkey, pa, len,
+ dir, dmah, secdma, pkttype);
+ DHD_PKTID_UNLOCK(map->pktid_lock, flags);
+}
+
+/**
+ * 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;
+ uint32 flags;
+ dhd_pktid_map_t *map;
+
+ ASSERT(handle != NULL);
+ map = (dhd_pktid_map_t *)handle;
+
+ flags = DHD_PKTID_LOCK(map->pktid_lock);
+
+ nkey = __dhd_pktid_map_reserve(dhd, handle, pkt);
+ if (nkey != DHD_PKTID_INVALID) {
+ __dhd_pktid_map_save(dhd, handle, pkt, nkey, pa,
+ len, dir, dmah, secdma, pkttype);
+#if defined(DHD_PKTID_AUDIT_MAP)
+ DHD_PKTID_AUDIT(dhd, map, nkey, DHD_TEST_IS_ALLOC); /* apriori, reservation */
+#endif /* DHD_PKTID_AUDIT_MAP */
+ }
+
+ DHD_PKTID_UNLOCK(map->pktid_lock, flags);
+
+ 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;
+ uint32 flags;
+ unsigned long locker_addr;
+
+ ASSERT(handle != NULL);
+
+ map = (dhd_pktid_map_t *)handle;
+
+ flags = DHD_PKTID_LOCK(map->pktid_lock);
+
+ ASSERT((nkey != DHD_PKTID_INVALID) && (nkey <= DHD_PKIDMAP_ITEMS(map->items)));
+
+ 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 */
+
+ if (locker->state == LOCKER_IS_FREE) { /* Debug check for cloned numbered key */
+ DHD_ERROR(("%s:%d: Error! freeing invalid pktid<%u>\n",
+ __FUNCTION__, __LINE__, nkey));
+ ASSERT(locker->state != LOCKER_IS_FREE);
+
+ DHD_PKTID_UNLOCK(map->pktid_lock, flags);
+ 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_PKTID_UNLOCK(map->pktid_lock, flags);
+
+ 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%lx> \n",
+ __FUNCTION__, __LINE__, locker->state, locker->pkttype,
+ pkttype, locker_addr));
+
+ ASSERT(locker->pkttype == pkttype);
+
+ 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;
+
+ DHD_PKTID_UNLOCK(map->pktid_lock, flags);
+ 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, uint32 index)
+{
+ 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) 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;
+
+ /* 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;
+ }
+
+ /* Scratch buffer for dma rx offset */
+ if (dhd_dma_buf_alloc(dhd, &prot->d2h_dma_scratch_buf, DMA_D2H_SCRATCH_BUF_LEN)) {
+ 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
+
+#if defined(DHD_LB)
+
+ /* 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(uint32) * 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 */
+
+#endif /* DHD_LB */
+
+ 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 */
+
+
+/**
+ * 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;
+
+ /* PKTID handle INIT */
+ if (prot->pktid_map_handle != NULL) {
+ DHD_ERROR(("%s: pktid_map_handle already set!\n", __FUNCTION__));
+ ASSERT(0);
+ return BCME_ERROR;
+ }
+
+#ifdef IOCTLRESP_USE_CONSTMEM
+ if (prot->pktid_map_handle_ioctl != NULL) {
+ DHD_ERROR(("%s: pktid_map_handle_ioctl already set!\n", __FUNCTION__));
+ ASSERT(0);
+ return BCME_ERROR;
+ }
+#endif /* IOCTLRESP_USE_CONSTMEM */
+
+ prot->pktid_map_handle = DHD_NATIVE_TO_PKTID_INIT(dhd, MAX_PKTID_ITEMS, PKTID_MAP_HANDLE);
+ if (prot->pktid_map_handle == NULL) {
+ DHD_ERROR(("%s: Unable to map packet id's\n", __FUNCTION__));
+ ASSERT(0);
+ return BCME_NOMEM;
+ }
+
+#ifdef IOCTLRESP_USE_CONSTMEM
+ prot->pktid_map_handle_ioctl = DHD_NATIVE_TO_PKTID_INIT(dhd,
+ DHD_FLOWRING_MAX_IOCTLRESPBUF_POST, PKTID_MAP_HANDLE_IOCTL);
+ if (prot->pktid_map_handle_ioctl == NULL) {
+ DHD_ERROR(("%s: Unable to map ioctl response buffers\n", __FUNCTION__));
+ ASSERT(0);
+ return BCME_NOMEM;
+ }
+#endif /* IOCTLRESP_USE_CONSTMEM */
+
+ /* Max pkts in ring */
+ prot->max_tx_count = H2DRING_TXPOST_MAX_ITEM;
+
+ DHD_INFO(("%s:%d: MAX_TX_COUNT = %d\n", __FUNCTION__, __LINE__, prot->max_tx_count));
+
+ /* 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->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->ioctl_received = IOCTL_WAIT;
+
+ 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;
+
+ prot->ioctl_trans_id = 0;
+
+ /* Register the interrupt function upfront */
+ /* remove corerev checks in data path */
+ prot->mb_ring_fn = dhd_bus_get_mbintr_fn(dhd->bus);
+
+ /* Initialize Common MsgBuf Rings */
+
+ 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);
+ dhd_prot_ring_init(dhd, &prot->d2hring_tx_cpln);
+ dhd_prot_ring_init(dhd, &prot->d2hring_rx_cpln);
+
+#if defined(PCIE_D2H_SYNC)
+ dhd_prot_d2h_sync_init(dhd);
+#endif /* PCIE_D2H_SYNC */
+
+ dhd_prot_h2d_sync_init(dhd);
+
+ /* 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 (DMA_INDX_ENAB(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 (DMA_INDX_ENAB(dhd->dma_h2d_ring_upd_support)) {
+ 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);
+ }
+
+ /*
+ * 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;
+ }
+
+ /* 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);
+ 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); /* ioctl return buffer */
+ dhd_dma_buf_free(dhd, &prot->ioctbuf);
+ dhd_dma_buf_free(dhd, &prot->host_bus_throughput_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);
+
+ /* 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);
+
+ DHD_NATIVE_TO_PKTID_FINI(dhd, dhd->prot->pktid_map_handle);
+
+#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)
+#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 */
+#endif /* DHD_LB */
+
+ 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 through
+ * a 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);
+
+ 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);
+
+ dhd_dma_buf_reset(dhd, &prot->retbuf);
+ dhd_dma_buf_reset(dhd, &prot->ioctbuf);
+ dhd_dma_buf_reset(dhd, &prot->d2h_dma_scratch_buf);
+ 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;
+ prot->ioctl_trans_id = 0;
+
+ /* 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);
+ }
+
+ if (prot->pktid_map_handle) {
+ DHD_NATIVE_TO_PKTID_FINI(dhd, prot->pktid_map_handle);
+ prot->pktid_map_handle = NULL;
+ }
+
+#ifdef IOCTLRESP_USE_CONSTMEM
+ if (prot->pktid_map_handle_ioctl) {
+ DHD_NATIVE_TO_PKTID_FINI_IOCTL(dhd, prot->pktid_map_handle_ioctl);
+ prot->pktid_map_handle_ioctl = NULL;
+ }
+#endif /* IOCTLRESP_USE_CONSTMEM */
+} /* dhd_prot_reset */
+
+
+void
+dhd_prot_rx_dataoffset(dhd_pub_t *dhd, uint32 rx_offset)
+{
+ dhd_prot_t *prot = dhd->prot;
+ prot->rx_dataoffset = rx_offset;
+}
+
+/**
+ * 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);
+
+
+
+#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_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 */
+
+#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);
+
+/**
+ * dhd_lb_dispatch - load balance by dispatch work to other CPU cores
+ * Note: rx_compl_tasklet is dispatched explicitly.
+ */
+static INLINE void
+dhd_lb_dispatch(dhd_pub_t *dhdp, uint16 ring_idx)
+{
+ switch (ring_idx) {
+
+#if defined(DHD_LB_TXC)
+ case BCMPCIE_D2H_MSGRING_TX_COMPLETE:
+ bcm_workq_prod_sync(&dhdp->prot->tx_compl_prod); /* flush WR index */
+ dhd_lb_tx_compl_dispatch(dhdp); /* dispatch tx_compl_tasklet */
+ break;
+#endif /* DHD_LB_TXC */
+
+ case BCMPCIE_D2H_MSGRING_RX_COMPLETE:
+ {
+#if defined(DHD_LB_RXC)
+ 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 */
+ }
+#endif /* DHD_LB_RXC */
+#if defined(DHD_LB_RXP)
+ dhd_lb_rx_napi_dispatch(dhdp); /* dispatch rx_process_napi */
+#endif /* DHD_LB_RXP */
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+
+#if defined(DHD_LB_TXC)
+/**
+ * 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;
+
+ 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)
+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 */
+
+#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) {
+#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);
+ }
+ }
+}
+
+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_map_handle,
+ pktid, pa, len, dmah, secdma, pkttype);
+ } else {
+ PKTBUF = DHD_PKTID_TO_NATIVE_RSV(dhd, dhd->prot->pktid_map_handle,
+ pktid, pa, len, dmah, secdma, pkttype);
+ }
+#else
+ PKTBUF = DHD_PKTID_TO_NATIVE(dhd, dhd->prot->pktid_map_handle, 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);
+ }
+ }
+ }
+
+ 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 /* IOCTLRESP_USE_CONSTMEM */
+
+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;
+ uint16 pktsz = DHD_FLOWRING_RX_BUFPOST_PKTSZ;
+ uint8 *rxbuf_post_tmp;
+ host_rxbuf_post_t *rxbuf_post;
+ void *msg_start;
+ dmaaddr_t pa;
+ uint32 pktlen;
+ uint8 i = 0;
+ uint16 alloced = 0;
+ unsigned long flags;
+ uint32 pktid;
+ dhd_prot_t *prot = dhd->prot;
+ msgbuf_ring_t *ring = &prot->h2dring_rxp_subn;
+
+ 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, TRUE);
+
+ DHD_GENERAL_UNLOCK(dhd, flags);
+
+ if (msg_start == NULL) {
+ DHD_INFO(("%s:%d: Rxbufpost Msgbuf Not available\n", __FUNCTION__, __LINE__));
+ return -1;
+ }
+ /* if msg_start != NULL, we should have alloced space for atleast 1 item */
+ ASSERT(alloced > 0);
+
+ rxbuf_post_tmp = (uint8*)msg_start;
+
+ /* loop through each allocated message in the rxbuf post msgbuf_ring */
+ for (i = 0; i < alloced; i++) {
+ rxbuf_post = (host_rxbuf_post_t *)rxbuf_post_tmp;
+ /* Create a rx buffer */
+ if ((p = PKTGET(dhd->osh, pktsz, FALSE)) == NULL) {
+ DHD_ERROR(("%s:%d: PKTGET for rxbuf failed\n", __FUNCTION__, __LINE__));
+ dhd->rx_pktgetfail++;
+ break;
+ }
+
+ 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);
+ } else {
+ pa = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, DMA_RX, p, 0);
+ }
+
+ if (PHYSADDRISZERO(pa)) {
+ PKTFREE(dhd->osh, p, FALSE);
+ DHD_ERROR(("Invalid phyaddr 0\n"));
+ ASSERT(0);
+ break;
+ }
+
+ PKTPULL(dhd->osh, p, prot->rx_metadata_offset);
+ pktlen = PKTLEN(dhd->osh, p);
+
+ /* 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;
+ ring->seqnum++;
+
+#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_ERROR(("%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;
+ }
+
+ /* Now populate the previous locker with valid information */
+ if (pktid != DHD_PKTID_INVALID) {
+ rxbuf_post->cmn_hdr.request_id = htol32(pktid);
+ DHD_NATIVE_TO_PKTID_SAVE(dhd, dhd->prot->pktid_map_handle, p, pktid,
+ pa, pktlen, DMA_RX, NULL, ring->dma_buf.secdma,
+ PKTTYPE_DATA_RX);
+ }
+ } else
+#endif /* DHD_LB_RXC */
+ {
+#if defined(DHD_LB_RXC)
+alloc_pkt_id:
+#endif
+#if defined(DHD_PCIE_PKTID)
+ /* get the lock before calling DHD_NATIVE_TO_PKTID */
+ DHD_GENERAL_LOCK(dhd, flags);
+#endif
+ pktid = DHD_NATIVE_TO_PKTID(dhd, dhd->prot->pktid_map_handle, p, pa,
+ pktlen, DMA_RX, NULL, ring->dma_buf.secdma, PKTTYPE_DATA_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, 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);
+ }
+
+ PKTFREE(dhd->osh, p, FALSE);
+ DHD_ERROR(("Pktid pool depleted.\n"));
+ break;
+ }
+#endif /* DHD_PCIE_PKTID */
+ }
+
+ rxbuf_post->data_buf_len = htol16((uint16)pktlen);
+ 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;
+ }
+
+#if defined(DHD_PKTID_AUDIT_RING)
+ DHD_PKTID_AUDIT(dhd, prot->pktid_map_handle, 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);
+ }
+
+ alloced = i;
+ }
+
+ /* Update ring's WR index and ring doorbell to dongle */
+ if (alloced > 0) {
+ dhd_prot_ring_write_complete(dhd, ring, msg_start, alloced);
+ }
+
+ return alloced;
+} /* dhd_prot_rxbuf_post */
+
+#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;
+ /* JIRA:SWWLAN-70021 The pa value would be overwritten by the dongle.
+ * Need to reassign before free to pass the check in dhd_dma_buf_audit().
+ */
+ retbuf->pa = DMA_MAP(dhd->osh, retbuf->va, retbuf->len, DMA_RX, NULL, NULL);
+ }
+
+ dhd_dma_buf_free(dhd, retbuf);
+ return;
+}
+#endif /* IOCTLRESP_USE_CONSTMEM */
+
+static int
+dhd_prot_rxbufpost_ctrl(dhd_pub_t *dhd, bool event_buf)
+{
+ 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;
+
+ 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 (event_buf) {
+ /* Allocate packet for event 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 (!event_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__, event_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);
+ } else {
+ pa = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, DMA_RX, p, 0);
+ }
+
+ if (PHYSADDRISZERO(pa)) {
+ DHD_ERROR(("Invalid physaddr 0\n"));
+ ASSERT(0);
+ goto free_pkt_return;
+ }
+ }
+
+ 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 (event_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 */
+ if (event_buf) {
+ rxbuf_post->cmn_hdr.msg_type = MSG_TYPE_EVENT_BUF_POST;
+ } else {
+ rxbuf_post->cmn_hdr.msg_type = MSG_TYPE_IOCTLRESP_BUF_POST;
+ }
+
+#ifdef IOCTLRESP_USE_CONSTMEM
+ if (!event_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, PKTTYPE_IOCTL_RX);
+ } else
+#endif /* IOCTLRESP_USE_CONSTMEM */
+ {
+ map_handle = dhd->prot->pktid_map_handle;
+ pktid = DHD_NATIVE_TO_PKTID(dhd, map_handle,
+ p, pa, pktlen, DMA_RX, dmah, ring->dma_buf.secdma,
+ event_buf ? PKTTYPE_EVENT_RX : PKTTYPE_IOCTL_RX);
+ }
+
+ if (pktid == DHD_PKTID_INVALID) {
+ if (ring->wr == 0) {
+ ring->wr = ring->max_items - 1;
+ } else {
+ ring->wr--;
+ }
+ DHD_GENERAL_UNLOCK(dhd, flags);
+ DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, DHD_DMAH_NULL);
+ goto free_pkt_return;
+ }
+
+#if defined(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++;
+
+#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 {
+ ring->wr--;
+ }
+ DHD_GENERAL_UNLOCK(dhd, flags);
+#ifdef IOCTLRESP_USE_CONSTMEM
+ if (event_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 */
+
+ rxbuf_post->cmn_hdr.flags = 0;
+#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);
+
+ return 1;
+
+free_pkt_return:
+#ifdef IOCTLRESP_USE_CONSTMEM
+ if (!event_buf) {
+ free_ioctl_return_buffer(dhd, &retbuf);
+ } else
+#endif /* IOCTLRESP_USE_CONSTMEM */
+ {
+ dhd_prot_packet_free(dhd, p,
+ event_buf ? PKTTYPE_EVENT_RX : PKTTYPE_IOCTL_RX,
+ FALSE);
+ }
+
+ return -1;
+} /* dhd_prot_rxbufpost_ctrl */
+
+static uint16
+dhd_msgbuf_rxbuf_post_ctrlpath(dhd_pub_t *dhd, bool event_buf, uint32 max_to_post)
+{
+ uint32 i = 0;
+ int32 ret_val;
+
+ DHD_INFO(("max to post %d, event %d \n", max_to_post, event_buf));
+
+ 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, event_buf);
+ if (ret_val < 0) {
+ break;
+ }
+ i++;
+ }
+ DHD_INFO(("posted %d buffers to event_pool/ioctl_resp_pool %d\n", i, event_buf));
+ 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,
+ FALSE, 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;
+
+ max_to_post = prot->max_eventbufpost - prot->cur_event_bufs_posted;
+ if (max_to_post <= 0) {
+ DHD_INFO(("%s: Cannot post more than max event buffers\n",
+ __FUNCTION__));
+ return;
+ }
+ prot->cur_event_bufs_posted += dhd_msgbuf_rxbuf_post_ctrlpath(dhd,
+ TRUE, max_to_post);
+}
+
+/** 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 = TRUE;
+ uint n = 0;
+ msgbuf_ring_t *ring = &dhd->prot->d2hring_rx_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));
+ }
+
+ /* 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;
+}
+
+/**
+ * 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;
+
+ /* Update read pointer */
+ if (DMA_INDX_ENAB(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;
+ }
+ }
+
+ return more;
+}
+
+/** 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)
+{
+ int 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;
+
+ /*
+ * 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 defined(PCIE_D2H_SYNC)
+ /* Wait until DMA completes, then fetch msg_type */
+ msg_type = dhd->prot->d2h_sync_cb(dhd, ring, msg, item_len);
+#else
+ msg_type = msg->msg_type;
+#endif /* !PCIE_D2H_SYNC */
+
+ /* 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
+#if defined(DHD_LB)
+ dhd_lb_dispatch(dhd, ring->idx);
+#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;
+ DHD_ERROR(("ring status: request_id %d, status 0x%04x, flow ring %d, write_idx %d \n",
+ ring_status->cmn_hdr.request_id, ring_status->compl_hdr.status,
+ ring_status->compl_hdr.flow_ring_id, ring_status->write_idx));
+ /* 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)
+{
+ uint32 pktid;
+ ioctl_req_ack_msg_t *ioct_ack = (ioctl_req_ack_msg_t *)msg;
+ unsigned long flags;
+
+ pktid = ltoh32(ioct_ack->cmn_hdr.request_id);
+
+#if defined(DHD_PKTID_AUDIT_RING)
+ /* Skip DHD_IOCTL_REQ_PKTID = 0xFFFE */
+ if (pktid != DHD_IOCTL_REQ_PKTID) {
+ if (DHD_PKTID_AUDIT(dhd, dhd->prot->pktid_map_handle, pktid,
+ DHD_TEST_IS_ALLOC) == BCME_ERROR) {
+ prhex("dhd_prot_ioctack_process:",
+ (uchar *)msg, D2HRING_CTRL_CMPLT_ITEMSIZE);
+ }
+ }
+#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"));
+ }
+}
+
+/** 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;
+
+ memset(&retbuf, 0, sizeof(dhd_dma_buf_t));
+
+ pkt_id = ltoh32(ioct_resp->cmn_hdr.request_id);
+
+#if defined(DHD_PKTID_AUDIT_RING)
+ {
+ int ret;
+#ifndef IOCTLRESP_USE_CONSTMEM
+ ret = DHD_PKTID_AUDIT(dhd, prot->pktid_map_handle, pkt_id,
+ DHD_DUPLICATE_FREE);
+#else
+ ret = DHD_PKTID_AUDIT(dhd, prot->pktid_map_handle_ioctl, pkt_id,
+ DHD_DUPLICATE_FREE);
+#endif /* !IOCTLRESP_USE_CONSTMEM */
+ if (ret == BCME_ERROR) {
+ prhex("dhd_prot_ioctcmplt_process:",
+ (uchar *)msg, D2HRING_CTRL_CMPLT_ITEMSIZE);
+ }
+ }
+#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;
+ }
+#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) {
+ prot->ioctl_state = 0;
+ DHD_GENERAL_UNLOCK(dhd, flags);
+ DHD_ERROR(("%s: received ioctl response with NULL pkt\n", __FUNCTION__));
+ 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) {
+ ASSERT(0);
+ goto exit;
+ }
+
+ 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 */
+}
+
+/** 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 = NULL;
+ dmaaddr_t pa;
+ uint32 len;
+ void *dmah;
+ void *secdma;
+
+ /* locks required to protect circular buffer accesses */
+ DHD_GENERAL_LOCK(dhd, flags);
+
+ txstatus = (host_txbuf_cmpl_t *)msg;
+ pktid = ltoh32(txstatus->cmn_hdr.request_id);
+
+#if defined(DHD_PKTID_AUDIT_RING)
+ if (DHD_PKTID_AUDIT(dhd, dhd->prot->pktid_map_handle, pktid,
+ DHD_DUPLICATE_FREE) == BCME_ERROR) {
+ prhex("dhd_prot_txstatus_process:",
+ (uchar *)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;
+
+ pkt = DHD_PKTID_TO_NATIVE(dhd, dhd->prot->pktid_map_handle,
+ pktid, 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), 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 */
+
+ /*
+ * We can come here if no DHD_LB_TXC is enabled and in case where DHD_LB_TXC is
+ * defined but the tx_compl queue is full.
+ */
+ if (pkt == NULL) {
+ pkt = DHD_PKTID_TO_NATIVE(dhd, dhd->prot->pktid_map_handle,
+ 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);
+ }
+#if defined(BCMPCIE)
+ dhd_txcomplete(dhd, pkt, true);
+#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 */
+ PKTFREE(dhd->osh, pkt, TRUE);
+ DHD_FLOWRING_TXSTATUS_CNT_UPDATE(dhd->bus, txstatus->compl_hdr.flow_ring_id,
+ txstatus->tx_status);
+ }
+
+ 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);
+
+#if defined(DHD_PKTID_AUDIT_RING)
+ if (DHD_PKTID_AUDIT(dhd, dhd->prot->pktid_map_handle, bufid,
+ DHD_DUPLICATE_FREE) == BCME_ERROR) {
+ prhex("dhd_prot_event_process:",
+ (uchar *)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) {
+ 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_RX_CMPLT message received from dongle */
+static void BCMFASTPATH
+dhd_prot_rxcmplt_process(dhd_pub_t *dhd, void *msg)
+{
+ host_rxbuf_cmpl_t *rxcmplt_h;
+ uint16 data_offset; /* offset at which data starts */
+ void *pkt;
+ unsigned long flags;
+ uint ifidx;
+ uint32 pktid;
+#if defined(DHD_LB_RXC)
+ const bool free_pktid = FALSE;
+#else
+ const bool free_pktid = TRUE;
+#endif /* DHD_LB_RXC */
+
+ /* RXCMPLT HDR */
+ rxcmplt_h = (host_rxbuf_cmpl_t *)msg;
+
+ /* offset from which data starts is populated in rxstatus0 */
+ data_offset = ltoh16(rxcmplt_h->data_offset);
+
+ pktid = ltoh32(rxcmplt_h->cmn_hdr.request_id);
+
+#if defined(DHD_PKTID_AUDIT_RING)
+ if (DHD_PKTID_AUDIT(dhd, dhd->prot->pktid_map_handle, pktid,
+ DHD_DUPLICATE_FREE) == BCME_ERROR) {
+ prhex("dhd_prot_rxcmplt_process:",
+ (uchar *)msg, D2HRING_RXCMPLT_ITEMSIZE);
+ }
+#endif /* DHD_PKTID_AUDIT_RING */
+
+ DHD_GENERAL_LOCK(dhd, flags);
+ pkt = dhd_prot_packet_get(dhd, pktid, PKTTYPE_DATA_RX, free_pktid);
+ DHD_GENERAL_UNLOCK(dhd, flags);
+
+ if (!pkt) {
+ return;
+ }
+
+ /* Post another set of rxbufs to the device */
+ dhd_prot_return_rxbuf(dhd, pktid, 1);
+
+ DHD_INFO(("id 0x%04x, offset %d, len %d, idx %d, phase 0x%02x, pktdata %p, metalen %d\n",
+ ltoh32(rxcmplt_h->cmn_hdr.request_id), data_offset, ltoh16(rxcmplt_h->data_len),
+ rxcmplt_h->cmn_hdr.if_id, rxcmplt_h->cmn_hdr.flags, PKTDATA(dhd->osh, pkt),
+ ltoh16(rxcmplt_h->metadata_len)));
+#if DHD_DBG_SHOW_METADATA
+ if (dhd->prot->metadata_dbg &&
+ dhd->prot->rx_metadata_offset && rxcmplt_h->metadata_len) {
+ uchar *ptr;
+ ptr = PKTDATA(dhd->osh, pkt) - (dhd->prot->rx_metadata_offset);
+ /* header followed by data */
+ bcm_print_bytes("rxmetadata", ptr, rxcmplt_h->metadata_len);
+ dhd_prot_print_metadata(dhd, ptr, rxcmplt_h->metadata_len);
+ }
+#endif /* DHD_DBG_SHOW_METADATA */
+
+ if (rxcmplt_h->flags & BCMPCIE_PKT_FLAGS_FRAME_802_11) {
+ DHD_INFO(("D11 frame rxed \n"));
+ }
+
+ /* data_offset from buf start */
+ if (data_offset) {
+ /* data offset given from dongle after split rx */
+ PKTPULL(dhd->osh, pkt, data_offset); /* data offset */
+ } else {
+ /* DMA RX offset updated through shared area */
+ if (dhd->prot->rx_dataoffset) {
+ PKTPULL(dhd->osh, pkt, dhd->prot->rx_dataoffset);
+ }
+ }
+ /* Actual length of the packet */
+ PKTSETLEN(dhd->osh, pkt, ltoh16(rxcmplt_h->data_len));
+
+ ifidx = rxcmplt_h->cmn_hdr.if_id;
+
+#if defined(DHD_LB_RXP)
+ dhd_lb_rx_pkt_enqueue(dhd, pkt, ifidx);
+#else /* ! DHD_LB_RXP */
+#ifdef DHD_RX_CHAINING
+ /* Chain the packets */
+ dhd_rxchain_frame(dhd, pkt, ifidx);
+#else /* ! DHD_RX_CHAINING */
+ /* offset from which data starts is populated in rxstatus0 */
+ dhd_bus_rx_frame(dhd->bus, pkt, ifidx, 1);
+#endif /* ! DHD_RX_CHAINING */
+#endif /* ! DHD_LB_RXP */
+} /* dhd_prot_rxcmplt_process */
+
+/** 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;
+
+
+ DHD_GENERAL_LOCK(dhd, flags);
+
+ /* Create a unique 32-bit packet id */
+ pktid = DHD_NATIVE_TO_PKTID_RSV(dhd, dhd->prot->pktid_map_handle, PKTBUF);
+#if defined(DHD_PCIE_PKTID)
+ if (pktid == DHD_PKTID_INVALID) {
+ DHD_ERROR(("Pktid pool depleted.\n"));
+ /*
+ * 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) {
+#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_map_handle, pktid,
+ pa, pktlen, dmah, secdma, PKTTYPE_NO_CHECK);
+#endif /* DHD_PCIE_PKTID */
+ DHD_INFO(("%s:%d: HTOD Msgbuf Not available TxCount = %d\n",
+ __FUNCTION__, __LINE__, prot->active_tx_count));
+ goto err_no_res_pktfree;
+ }
+
+ /* 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);
+ } else {
+ pa = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, PKTBUF), pktlen, DMA_TX, PKTBUF, 0);
+ }
+
+ if (PHYSADDRISZERO(pa)) {
+ DHD_ERROR(("Something really bad, unless 0 is a valid phyaddr\n"));
+ ASSERT(0);
+ }
+
+ /* No need to lock. Save the rest of the packet's metadata */
+ DHD_NATIVE_TO_PKTID_SAVE(dhd, dhd->prot->pktid_map_handle, 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->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);
+ } else {
+ meta_pa = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, PKTBUF),
+ prot->tx_metadata_offset, DMA_RX, PKTBUF, 0);
+ }
+
+ if (PHYSADDRISZERO(meta_pa)) {
+ DHD_ERROR(("Something really bad, unless 0 is a valid phyaddr\n"));
+ ASSERT(0);
+ }
+
+ /* 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;
+ }
+
+#if defined(DHD_PKTID_AUDIT_RING)
+ DHD_PKTID_AUDIT(dhd, prot->pktid_map_handle, 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(dhd);
+
+ DHD_GENERAL_UNLOCK(dhd, flags);
+
+ return BCME_OK;
+
+err_no_res_pktfree:
+
+
+
+ DHD_GENERAL_UNLOCK(dhd, flags);
+ 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 -= 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 */
+}
+
+/* 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\n", __FUNCTION__));
+ 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__, *(char *)buf));
+ }
+
+ 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_ERROR(("%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);
+
+ 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);
+ 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;
+
+ 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);
+
+ 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 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;
+
+ 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)) {
+ bcm_print_bytes("XFER SRC: ",
+ prot->dmaxfer.srcmem.va, prot->dmaxfer.len);
+ bcm_print_bytes("XFER DST: ",
+ prot->dmaxfer.dstmem.va, prot->dmaxfer.len);
+ } else {
+ DHD_INFO(("DMA successful\n"));
+ }
+ }
+ dmaxfer_free_dmaaddr(dhd, &prot->dmaxfer);
+ 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)
+{
+ 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;
+ }
+
+ 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);
+ 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;
+ 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);
+
+ /* update ring's WR index and ring doorbell to dongle */
+ dhd_prot_ring_write_complete(dhd, ring, dmap, 1);
+ DHD_GENERAL_UNLOCK(dhd, flags);
+
+ DHD_ERROR(("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 (!len || !buf) {
+ DHD_ERROR(("%s(): Zero length bailing\n", __FUNCTION__));
+ ret = BCME_BADARG;
+ goto done;
+ }
+
+ /* Respond "bcmerror" and "bcmerrorstr" with local cache */
+ if (cmd == WLC_GET_VAR) {
+ if ((len >= strlen("bcmerrorstr")) && (!strcmp((char *)buf, "bcmerrorstr"))) {
+ copylen = MIN(len, BCME_STRLEN);
+ strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), copylen);
+ *(uint8 *)(buf + (copylen - 1)) = '\0';
+ goto done;
+ } else if ((len >= strlen("bcmerror")) && !strcmp((char *)buf, "bcmerror")) {
+ store32_ua(buf, dhd->dongle_error);
+ *(uint8 *)(buf + (sizeof(uint32))) = '\0';
+ goto done;
+ }
+ }
+
+ ret = dhd_fillup_ioct_reqst(dhd, (uint16)len, cmd, buf, ifidx);
+
+ DHD_CTL(("query_ioctl: ACTION %d ifdix %d cmd %d len %d \n",
+ action, ifidx, cmd, len));
+
+ /* 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;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ if (dhd_query_bus_erros(dhd)) {
+ ret = -EIO;
+ goto out;
+ }
+
+ if (prot->cur_ioctlresp_bufs_posted) {
+ prot->cur_ioctlresp_bufs_posted--;
+ }
+
+ dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd);
+
+ timeleft = dhd_os_ioctl_resp_wait(dhd, &prot->ioctl_received);
+ if (timeleft == 0) {
+ 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));
+
+ 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 */
+ if (dhd->rxcnt_timeout >= MAX_CNTL_RX_TIMEOUT) {
+#ifdef SUPPORT_LINKDOWN_RECOVERY
+#ifdef CONFIG_ARCH_MSM
+ dhd->bus->no_cfg_restore = 1;
+#endif /* CONFIG_ARCH_MSM */
+#endif /* SUPPORT_LINKDOWN_RECOVERY */
+ DHD_ERROR(("%s: timeout > MAX_CNTL_TX_TIMEOUT\n", __FUNCTION__));
+ }
+ 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 = -ECONNABORTED;
+ goto out;
+ }
+ dhd->rxcnt_timeout = 0;
+ dhd->rx_ctlpkts++;
+ DHD_CTL(("%s: ioctl resp resumed, got %d\n",
+ __FUNCTION__, prot->ioctl_resplen));
+ }
+
+ if (dhd->dongle_trap_occured) {
+#ifdef SUPPORT_LINKDOWN_RECOVERY
+#ifdef CONFIG_ARCH_MSM
+ dhd->bus->no_cfg_restore = 1;
+#endif /* CONFIG_ARCH_MSM */
+#endif /* SUPPORT_LINKDOWN_RECOVERY */
+ DHD_ERROR(("%s: TRAP occurred!!\n", __FUNCTION__));
+ ret = -EREMOTEIO;
+ goto out;
+ }
+
+ 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;
+ }
+
+ /* Fill up msgbuf for ioctl req */
+ ret = dhd_fillup_ioct_reqst(dhd, (uint16)len, cmd, buf, ifidx);
+
+ DHD_CTL(("ACTION %d ifdix %d cmd %d len %d \n",
+ action, ifidx, cmd, len));
+
+ ret = dhd_msgbuf_wait_ioctl_cmplt(dhd, len, buf);
+
+ 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 defined(PCIE_D2H_SYNC)
+ 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);
+#endif /* PCIE_D2H_SYNC */
+
+ bcm_bprintf(b, "\nDongle DMA Indices: h2d %d d2h %d index size %d bytes\n",
+ DMA_INDX_ENAB(dhd->dma_h2d_ring_upd_support),
+ DMA_INDX_ENAB(dhd->dma_d2h_ring_upd_support),
+ dhd->prot->rw_index_sz);
+}
+
+/* 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;
+
+ 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);
+ 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;
+
+ /* 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);
+
+ 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 (DMA_INDX_ENAB(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);
+ }
+
+ /* 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;
+ }
+ }
+
+ /* 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);
+
+ 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);
+ 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);
+ 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 = 0;
+ 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);
+
+ 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;
+
+ 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) && (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;
+}
+
+
+/**
+ * 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;
+ 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)) {
+ SECURE_DMA_UNMAP_ALL(prot->osh, ring->dma_buf.secdma);
+ if (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) && (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.
+ *
+ * +----------------------------------------------------------------------------
+ */
+
+/* Fetch number of H2D flowrings given the total number of h2d rings */
+#define DHD_FLOWRINGS_POOL_TOTAL(h2d_rings_total) \
+ ((h2d_rings_total) - BCMPCIE_H2D_COMMON_MSGRINGS)
+
+/* 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) \
+ for ((flowid) = DHD_FLOWRING_START_FLOWID, \
+ (ring) = DHD_RING_IN_FLOWRINGS_POOL(prot, flowid); \
+ (flowid) < (prot)->h2d_rings_total; \
+ (flowid)++, (ring)++)
+
+/**
+ * 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_FLOWRINGS_POOL_TOTAL(prot->h2d_rings_total);
+
+ 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) {
+ snprintf(ring_name, sizeof(ring_name), "h2dflr_%03u", flowid);
+ ring_name[RING_NAME_MAX_LENGTH - 1] = '\0';
+ if (dhd_prot_ring_attach(dhd, ring, ring_name,
+ H2DRING_TXPOST_MAX_ITEM, 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;
+ msgbuf_ring_t *ring;
+ dhd_prot_t *prot = dhd->prot;
+
+ if (prot->h2d_flowrings_pool == NULL) {
+ ASSERT(prot->h2d_rings_total == 0);
+ return;
+ }
+
+ /* Reset each flowring in the flowring pool */
+ FOREACH_RING_IN_FLOWRINGS_POOL(prot, ring, flowid) {
+ 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;
+ int 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;
+ }
+
+ /* Detach the DMA-able buffer for each flowring in the flowring pool */
+ FOREACH_RING_IN_FLOWRINGS_POOL(prot, ring, flowid) {
+ dhd_prot_ring_detach(dhd, ring);
+ }
+
+ h2d_flowrings_total = DHD_FLOWRINGS_POOL_TOTAL(prot->h2d_rings_total);
+
+ 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;
+
+ 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.
+ */
+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;
+
+ /* cache flush */
+ OSL_CACHE_FLUSH(p, ring->item_len * nitems);
+
+ if (DMA_INDX_ENAB(dhd->dma_h2d_ring_upd_support)) {
+ dhd_prot_dma_indx_set(dhd, ring->wr,
+ H2D_DMA_INDX_WR_UPD, ring->idx);
+ } else {
+ dhd_bus_cmn_writeshared(dhd->bus, &(ring->wr),
+ sizeof(uint16), RING_WR_UPD, ring->idx);
+ }
+
+ /* raise h2d interrupt */
+ 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)
+{
+ /* update read index */
+ /* If dma'ing h2d indices supported
+ * update the r -indices in the
+ * host memory o/w in TCM
+ */
+ if (DMA_INDX_ENAB(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);
+ }
+}
+
+
+/**
+ * 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()
+ */
+static 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;
+
+ 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);
+ 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;
+
+ 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);
+ break;
+
+ case D2H_DMA_INDX_RD_UPD:
+ ptr = (uint8 *)(prot->d2h_dma_indx_rd_buf.va);
+ offset = DHD_D2H_RING_OFFSET(ringid);
+ 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;
+
+ 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 (DMA_INDX_ENAB(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;
+ }
+
+ ASSERT(items < ring->max_items);
+
+ /*
+ * 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->suspended %d bus->wait_for_d3_ack %d \r\n",
+ dhd->busstate, dhd->bus->suspended, dhd->bus->wait_for_d3_ack));
+ DHD_ERROR(("\r\n======================= \r\n"));
+
+ *available_len = 0;
+ 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 */
+
+/** 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;
+
+ /* 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;
+ }
+
+ 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);
+ 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.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(H2DRING_TXPOST_MAX_ITEM);
+ flow_create_rqst->len_item = htol16(H2DRING_TXPOST_ITEMSIZE);
+ 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 (DMA_INDX_ENAB(dhd->dma_h2d_ring_upd_support)) {
+ dhd_prot_dma_indx_set(dhd, flow_ring->wr,
+ H2D_DMA_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);
+
+ 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));
+}
+
+/** 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 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), dma_buf_len);
+}
+
+void dhd_prot_print_info(dhd_pub_t *dhd, struct bcmstrbuf *strbuf)
+{
+ dhd_prot_t *prot = dhd->prot;
+ bcm_bprintf(strbuf,
+ "%8s %4s %4s %5s %17s %17s %7s\n",
+ "Type", "RBP", "RD", "WR", "BASE(VA)", "BASE(PA)", "SIZE");
+ bcm_bprintf(strbuf, "%8s %4s", "CtrlPost", "NA");
+ dhd_prot_print_flow_ring(dhd, &prot->h2dring_ctrl_subn, strbuf,
+ "%5d %5d %17p %8x:%8x %7d\n");
+ bcm_bprintf(strbuf, "%8s %4s", "CtrlCpl", "NA");
+ dhd_prot_print_flow_ring(dhd, &prot->d2hring_ctrl_cpln, strbuf,
+ "%5d %5d %17p %8x:%8x %7d\n");
+ bcm_bprintf(strbuf, "%8s %4d", "RxPost", prot->rxbufpost);
+ dhd_prot_print_flow_ring(dhd, &prot->h2dring_rxp_subn, strbuf,
+ "%5d %5d %17p %8x:%8x %7d\n");
+ bcm_bprintf(strbuf, "%8s %4s", "RxCpl", "NA");
+ dhd_prot_print_flow_ring(dhd, &prot->d2hring_rx_cpln, strbuf,
+ "%5d %5d %17p %8x:%8x %7d\n");
+ bcm_bprintf(strbuf, "%8s %4s", "TxCpl", "NA");
+ dhd_prot_print_flow_ring(dhd, &prot->d2hring_tx_cpln, strbuf,
+ "%5d %5d %17p %8x:%8x %7d\n");
+ bcm_bprintf(strbuf, "active_tx_count %d pktidmap_avail %d\n",
+ dhd->prot->active_tx_count,
+ DHD_PKTID_AVAIL(dhd->prot->pktid_map_handle));
+}
+
+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;
+
+ 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__));
+ 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.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);
+
+ 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);
+}
+
+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;
+
+ 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__));
+ 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.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);
+
+ 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;
+
+ /* 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);
+ 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);
+#endif /* DHD_D2H_SOFT_DOORBELL_SUPPORT */
+}
+
+static void
+dhd_prot_d2h_ring_config_cmplt_process(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_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 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));
+
+ 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));
+
+ 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(("\n ------- DUMPING INTR Status and Masks ------- \r\n"));
+ 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));
+
+ 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 ((!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 */
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_pcie.c b/drivers/net/wireless/bcmdhd_1363/dhd_pcie.c
new file mode 100644
index 000000000000..74926b0ccedc
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_pcie.c
@@ -0,0 +1,6139 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_pcie.c 665078 2017-05-18 08:51:32Z $
+ */
+
+
+/* include files */
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <bcmdevs.h>
+#include <siutils.h>
+#include <hndsoc.h>
+#include <hndpmu.h>
+#include <sbchipc.h>
+#include <hnd_armtrap.h>
+#if defined(DHD_DEBUG)
+#include <hnd_cons.h>
+#endif /* defined(DHD_DEBUG) */
+#include <dngl_stats.h>
+#include <pcie_core.h>
+#include <dhd.h>
+#include <dhd_bus.h>
+#include <dhd_flowring.h>
+#include <dhd_proto.h>
+#include <dhd_dbg.h>
+#include <dhdioctl.h>
+#include <sdiovar.h>
+#include <bcmmsgbuf.h>
+#include <pcicfg.h>
+#include <dhd_pcie.h>
+#include <bcmpcie.h>
+#include <bcmendian.h>
+#ifdef DHDTCPACK_SUPPRESS
+#include <dhd_ip.h>
+#endif /* DHDTCPACK_SUPPRESS */
+
+#ifdef BCMEMBEDIMAGE
+#include BCMEMBEDIMAGE
+#endif /* BCMEMBEDIMAGE */
+
+#ifdef PCIE_OOB
+#include "ftdi_sio_external.h"
+#endif /* PCIE_OOB */
+
+#define CISTPL_BRCM_HNBU 0x80
+#define HNBU_CUSTOM1 0x82
+#define HNBU_CUSTOM2 0x83
+#define CISTPL_NULL 0x00
+#define CISTPL_END 0xff
+#define CISTPL_OFFSET 0xC0
+#ifdef CUSTOMER_HW2
+#define STARTBUSY_BIT_POLL_MAX_TIME 50
+#endif /* CUSTOMER_HW2 */
+
+#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 */
+
+#if defined(SUPPORT_MULTIPLE_BOARD_REV)
+ extern unsigned int system_rev;
+#endif /* SUPPORT_MULTIPLE_BOARD_REV */
+
+/* DHD module parameter */
+extern uint32 hw_module_variant;
+
+int dhd_dongle_memsize;
+int dhd_dongle_ramsize;
+static int dhdpcie_checkdied(dhd_bus_t *bus, char *data, uint size);
+#ifdef DHD_DEBUG
+static int dhdpcie_bus_readconsole(dhd_bus_t *bus);
+#endif /* DHD_DEBUG */
+#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);
+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);
+static void dhdpcie_bus_wtcm64(dhd_bus_t *bus, ulong offset, uint64 data);
+static uint64 dhdpcie_bus_rtcm64(dhd_bus_t *bus, ulong offset);
+static void dhdpcie_bus_cfg_set_bar0_win(dhd_bus_t *bus, uint32 data);
+static void dhdpcie_bus_reg_unmap(osl_t *osh, ulong addr, int size);
+static int dhdpcie_cc_nvmshadow(dhd_bus_t *bus, struct bcmstrbuf *b);
+static int dhdpcie_sromotp_customvar(dhd_bus_t *bus, uint32 *customvar1, uint32 *customvar2);
+static void dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data);
+static void dhd_fillup_ring_sharedptr_info(dhd_bus_t *bus, ring_info_t *ring_info);
+extern void dhd_dpc_kill(dhd_pub_t *dhdp);
+
+#ifdef BCM_AUTO_FWCRC
+extern int dhd_check_firmware_image(char* memptr, char *pfw_path);
+#endif
+#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
+
+static void dhd_bus_set_device_wake(struct dhd_bus *bus, bool val);
+extern void wl_nddbg_wpp_log(const char *format, ...);
+#ifdef PCIE_OOB
+static void dhd_bus_doorbell_timeout_reset(struct dhd_bus *bus);
+
+#define DHD_DEFAULT_DOORBELL_TIMEOUT 200 /* ms */
+static uint dhd_doorbell_timeout = DHD_DEFAULT_DOORBELL_TIMEOUT;
+
+#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 */
+static bool dhdpcie_check_firmware_compatible(uint32 f_api_version, uint32 h_api_version);
+
+/* IOVar table */
+enum {
+ IOV_INTR = 1,
+ IOV_MEMBYTES,
+ 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_PCIEREG,
+ IOV_PCIECFGREG,
+ IOV_PCIECOREREG,
+ IOV_PCIESERDESREG,
+ IOV_BAR0_SECWIN_REG,
+ IOV_SBREG,
+ 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_DB1_FOR_MB,
+ IOV_FLOW_PRIO_MAP,
+#ifdef DHD_PCIE_RUNTIMEPM
+ IOV_IDLETIME,
+#endif /* DHD_PCIE_RUNTIMEPM */
+ IOV_RXBOUND,
+ IOV_TXBOUND,
+ IOV_HANGREPORT,
+#ifdef PCIE_OOB
+ IOV_OOB_BT_REG_ON,
+ IOV_OOB_ENABLE
+#endif /* PCIE_OOB */
+};
+
+
+const bcm_iovar_t dhdpcie_iovars[] = {
+ {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
+ {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
+ {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 },
+ {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 },
+ {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
+ {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
+ {"pcie_lpbk", IOV_PCIE_LPBK, 0, IOVT_UINT32, 0 },
+ {"cc_nvmshadow", IOV_CC_NVMSHADOW, 0, IOVT_BUFFER, 0 },
+ {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 },
+ {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 },
+ {"pciereg", IOV_PCIEREG, 0, IOVT_BUFFER, 2 * sizeof(int32) },
+ {"pciecfgreg", IOV_PCIECFGREG, 0, IOVT_BUFFER, 2 * sizeof(int32) },
+ {"pciecorereg", IOV_PCIECOREREG, 0, IOVT_BUFFER, 2 * sizeof(int32) },
+ {"pcieserdesreg", IOV_PCIESERDESREG, 0, IOVT_BUFFER, 3 * sizeof(int32) },
+ {"bar0secwinreg", IOV_BAR0_SECWIN_REG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
+ {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
+ {"pcie_dmaxfer", IOV_PCIE_DMAXFER, 0, IOVT_BUFFER, 3 * sizeof(int32) },
+ {"pcie_suspend", IOV_PCIE_SUSPEND, 0, IOVT_UINT32, 0 },
+#ifdef PCIE_OOB
+ {"oob_bt_reg_on", IOV_OOB_BT_REG_ON, 0, IOVT_UINT32, 0 },
+ {"oob_enable", IOV_OOB_ENABLE, 0, IOVT_UINT32, 0 },
+#endif /* PCIE_OOB */
+ {"sleep_allowed", IOV_SLEEP_ALLOWED, 0, IOVT_BOOL, 0 },
+ {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
+ {"ltrsleep_on_unload", IOV_LTRSLEEPON_UNLOOAD, 0, IOVT_UINT32, 0 },
+ {"dump_ringupdblk", IOV_DUMP_RINGUPD_BLOCK, 0, IOVT_BUFFER, 0 },
+ {"dma_ring_indices", IOV_DMA_RINGINDICES, 0, IOVT_UINT32, 0},
+ {"metadata_dbg", IOV_METADATA_DBG, 0, IOVT_BOOL, 0 },
+ {"rx_metadata_len", IOV_RX_METADATALEN, 0, IOVT_UINT32, 0 },
+ {"tx_metadata_len", IOV_TX_METADATALEN, 0, IOVT_UINT32, 0 },
+ {"db1_for_mb", IOV_DB1_FOR_MB, 0, IOVT_UINT32, 0 },
+ {"txp_thresh", IOV_TXP_THRESHOLD, 0, IOVT_UINT32, 0 },
+ {"buzzz_dump", IOV_BUZZZ_DUMP, 0, IOVT_UINT32, 0 },
+ {"flow_prio_map", IOV_FLOW_PRIO_MAP, 0, IOVT_UINT32, 0 },
+#ifdef DHD_PCIE_RUNTIMEPM
+ {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 },
+#endif /* DHD_PCIE_RUNTIMEPM */
+ {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
+ {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
+ {"fw_hang_report", IOV_HANGREPORT, 0, IOVT_BOOL, 0 },
+ {NULL, 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
+uint dhd_rxbound = DHD_RXBOUND;
+uint dhd_txbound = DHD_TXBOUND;
+
+/* 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.
+ */
+
+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, ulong addr, int size)
+{
+ REG_UNMAP((void*)(uintptr)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;
+ /* customvar1 and customvar2 are customer configurable CIS tuples in OTP.
+ * In dual chip (PCIE) scenario, customvar2 is used as a hint to detect
+ * the chip variants and load the right firmware and NVRAM
+ */
+ /* Below vars are set to 0x0 as OTPed value can not take 0x0 */
+ uint32 customvar1 = 0x0;
+ uint32 customvar2 = 0x0;
+ uint32 otp_hw_module_variant = 0x0;
+
+ 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->const_flowring);
+
+ /* 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;
+ }
+
+ if (!hw_module_variant) {
+ /* For single wifi module */
+ goto enumerate_module;
+ }
+
+ /* read otp variables customvar1 and customvar2 */
+ if (dhdpcie_sromotp_customvar(bus, &customvar1, &customvar2)) {
+ DHD_ERROR(("%s: dhdpcie_sromotp_customvar failed\n", __FUNCTION__));
+ break;
+ }
+
+ if (!customvar2) {
+ DHD_ERROR(("%s: customvar2 is not OTPed, hw_module_variant=0x%x\n",
+ __FUNCTION__, hw_module_variant));
+ goto enumerate_module;
+ }
+
+ /* customvar2=0xKKLLMMNN, LL is module variant */
+ otp_hw_module_variant = (customvar2 >> 16) & 0x00FF;
+ if (hw_module_variant != otp_hw_module_variant) {
+ DHD_ERROR(("%s: Not going to enumerate this module as "
+ "hw_module_variant=0x%x and "
+ "OTPed-module_variant=0x%x didn't match\n",
+ __FUNCTION__, hw_module_variant, otp_hw_module_variant));
+ break;
+ }
+
+ DHD_TRACE(("%s: Going to enumerate this module as "
+ "hw_module_variant=0x%x and "
+ "OTPed-module_variant=0x%x match\n",
+ __FUNCTION__, hw_module_variant, otp_hw_module_variant));
+
+enumerate_module:
+ /* 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->irq_registered = FALSE;
+
+ bus->d3_ack_war_cnt = 0;
+
+ 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;
+}
+
+void *
+dhd_bus_sih(struct dhd_bus *bus)
+{
+ return (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 interupts disabled or inside isr */
+uint32
+dhdpcie_bus_intstatus(dhd_bus_t *bus)
+{
+ uint32 intstatus = 0;
+ uint32 intmask = 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);
+ 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);
+
+ /* this is a PCIE core register..not a config register... */
+ intmask = si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxMask, 0, 0);
+
+ /*
+ * 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 &= intmask;
+
+ /* Is device removed. intstatus & intmask read 0xffffffff */
+ if (intstatus == (uint32)-1) {
+ DHD_ERROR(("%s: !!!!!!Device Removed or dead chip.\n", __FUNCTION__));
+ intstatus = 0;
+#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 */
+ }
+
+ 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) {
+ DHD_ERROR(("%s: BUS is down, not processing the interrupt \r\n",
+ __FUNCTION__));
+ break;
+ }
+
+ intstatus = dhdpcie_bus_intstatus(bus);
+
+ /* Check if the interrupt is ours or not */
+ if (intstatus == 0) {
+ break;
+ }
+
+ /* save the intstatus */
+ bus->intstatus = intstatus;
+
+ /* 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++;
+
+ /* read interrupt status register!! Status bits will be cleared in DPC !! */
+ bus->ipend = TRUE;
+ dhdpcie_bus_intr_disable(bus); /* Disable interrupt!! */
+ 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;
+}
+
+#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;
+ void *regsva = (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;
+
+ if (bus->sih != NULL) {
+ DHD_INFO(("%s sih is not null\n", __FUNCTION__));
+ return 0;
+ }
+
+ /* 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;
+ }
+
+ /* 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;
+ }
+
+
+ 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)) {
+ 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;
+ } 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 BCM4356_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_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 base 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;
+ 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;
+
+ bus->wait_for_d3_ack = 1;
+ bus->suspended = FALSE;
+
+#ifdef PCIE_OOB
+ 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;
+
+ /* 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);
+#endif /* PCIE_OOB */
+
+ 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(("enable interrupts\n"));
+ 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 {
+ si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxMask,
+ bus->def_intmask, bus->def_intmask);
+ }
+ } else {
+ DHD_ERROR(("****** %s: failed ******\n", __FUNCTION__));
+ DHD_ERROR(("bus: %p sih: %p bus->is_linkdown %d\n",
+ bus, bus ? bus->sih : NULL, bus ? bus->is_linkdown: -1));
+ }
+}
+
+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 {
+ si_corereg(bus->sih, bus->sih->buscoreidx, PCIMailBoxMask,
+ bus->def_intmask, 0);
+ }
+ } else {
+ DHD_ERROR(("****** %s: failed ******\n", __FUNCTION__));
+ DHD_ERROR(("bus: %p sih: %p bus->is_linkdown %d\n",
+ bus, bus ? bus->sih : NULL, bus ? bus->is_linkdown: -1));
+ }
+
+ 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) {
+ DHD_ERROR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n",
+ __FUNCTION__, dhdp->dhd_bus_busy_state));
+ BUG_ON(1);
+ }
+
+ 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);
+
+ if (bus->sih == NULL) {
+ return;
+ }
+
+ dhd_os_sdlock(bus->dhd);
+
+ dhdpcie_bus_intr_disable(bus);
+ if (!bus->dhd->dongle_isolation) {
+ pcie_watchdog_reset(bus->osh, bus->sih, (sbpcieregs_t *)(bus->regs));
+ }
+
+ 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_cleanup(bus->dhd);
+ dongle_isolation = bus->dhd->dongle_isolation;
+ 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, (ulong)bus->regs, DONGLE_REG_MAP_SIZE);
+ bus->regs = NULL;
+ }
+ if (bus->tcm) {
+ dhdpcie_bus_reg_unmap(osh, (ulong)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;
+ }
+
+#ifdef DHD_DEBUG
+
+ if (bus->console.buf != NULL)
+ MFREE(osh, bus->console.buf, bus->console.bufsize);
+#endif
+
+
+ /* 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)
+ pcie_watchdog_reset(bus->osh, bus->sih, (sbpcieregs_t *)(bus->regs));
+
+ 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));
+
+ 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;
+}
+
+/** Watchdog timer function */
+bool dhd_bus_watchdog(dhd_pub_t *dhd)
+{
+ unsigned long flags;
+#ifdef DHD_DEBUG
+ dhd_bus_t *bus;
+ bus = dhd->bus;
+
+ DHD_GENERAL_LOCK(dhd, flags);
+ if (dhd->busstate == DHD_BUS_DOWN ||
+ dhd->busstate == DHD_BUS_DOWN_IN_PROGRESS) {
+ DHD_GENERAL_UNLOCK(dhd, flags);
+ return FALSE;
+ }
+ dhd->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_WD;
+ 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->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 */
+ }
+ }
+#endif /* DHD_DEBUG */
+
+#ifdef PCIE_OOB
+ /* If haven't communicated with device for a while, deassert the Device_Wake GPIO */
+ if (dhd_doorbell_timeout != 0 && !(bus->dhd->busstate == DHD_BUS_SUSPEND) &&
+ dhd_timeout_expired(&bus->doorbell_timer)) {
+ dhd_bus_set_device_wake(bus, FALSE);
+ }
+#endif /* PCIE_OOB */
+
+ DHD_GENERAL_LOCK(dhd, flags);
+ dhd->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_WD;
+ DHD_GENERAL_UNLOCK(dhd, flags);
+
+ return TRUE;
+} /* dhd_bus_watchdog */
+
+
+#define DEADBEEF_PATTERN 0xADDEADDE // "DeadDead"
+#define MEMCHECKINFO "/data/.memcheck.info"
+
+static int
+dhd_get_memcheck_info(void)
+{
+ struct file *fp = NULL;
+ uint32 mem_val = 0;
+ int ret = 0;
+ char *filepath = MEMCHECKINFO;
+
+ fp = filp_open(filepath, O_RDONLY, 0);
+ if (IS_ERR(fp)) {
+ DHD_ERROR(("[WIFI_SEC] %s: File [%s] doesn't exist\n", __FUNCTION__, filepath));
+ goto done;
+ } else {
+ ret = kernel_read(fp, 0, (char *)&mem_val, 4);
+ if (ret < 0) {
+ DHD_ERROR(("[WIFI_SEC] %s: File read error, ret=%d\n", __FUNCTION__, ret));
+ filp_close(fp, NULL);
+ goto done;
+ }
+
+ mem_val = bcm_atoi((char *)&mem_val);
+
+ DHD_ERROR(("[WIFI_SEC]%s: MEMCHECK ENABLED = %d\n", __FUNCTION__, mem_val));
+ filp_close(fp, NULL);
+ }
+done:
+ return mem_val;
+}
+
+static int
+dhdpcie_mem_check(struct dhd_bus *bus)
+{
+ int bcmerror = BCME_OK;
+ int offset = 0;
+ int len = 0;
+ uint8 *memblock = NULL, *memptr;
+ int size = bus->ramsize;
+ int i;
+ uint32 memcheck_enabled;
+
+ /* Read memcheck info from the file */
+ /* 0 : Disable */
+ /* 1 : "Dead Beef" pattern write */
+ /* 2 : "Dead Beef" pattern write and checking the pattern value */
+
+ memcheck_enabled = dhd_get_memcheck_info();
+
+ DHD_ERROR(("%s: memcheck_enabled: %d \n", __FUNCTION__, memcheck_enabled));
+
+ if (memcheck_enabled == 0) {
+ return bcmerror;
+ }
+
+ 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 ((ulong)memblock % DHD_SDALIGN) {
+ memptr += (DHD_SDALIGN - ((ulong)memblock % DHD_SDALIGN));
+ }
+
+ for (i = 0; i < MEMBLOCK; i = i + 4) {
+ *(ulong*)(memptr + i) = DEADBEEF_PATTERN;
+ }
+
+ if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0) ||
+ si_setcore(bus->sih, ARMCA7_CORE_ID, 0)) {
+ if (offset == 0) {
+ /* Add start of RAM address to the address given by user */
+ offset += bus->dongle_ram_base;
+ }
+ }
+
+ /* Write "DeadBeef" pattern with MEMBLOCK size */
+ while (size) {
+ len = MIN(MEMBLOCK, size);
+
+ 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 (memcheck_enabled == 2) {
+ bcmerror = dhdpcie_bus_membytes(bus, FALSE, offset, (uint8 *)memptr, len);
+ if (bcmerror) {
+ DHD_ERROR(("%s: error %d on read %d membytes at 0x%08x\n",
+ __FUNCTION__, bcmerror, MEMBLOCK, offset));
+ goto err;
+ } else {
+ for (i = 0; i < len; i = i+4) {
+ if ((*(uint32*)(memptr + i)) != DEADBEEF_PATTERN) {
+ DHD_ERROR(("%s: error on reading pattern at "
+ "0x%08x\n", __FUNCTION__, (offset + i)));
+ bcmerror = BCME_ERROR;
+ goto err;
+ }
+ }
+ }
+ }
+ offset += MEMBLOCK;
+ size -= MEMBLOCK;
+ }
+
+ DHD_ERROR(("%s: Writing the Dead Beef pattern is Done \n", __FUNCTION__));
+
+err:
+ if (memblock) {
+ MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
+ }
+
+ return bcmerror;
+}
+
+/* Download firmware image and nvram image */
+int
+dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
+ char *pfw_path, char *pnv_path)
+{
+ int ret;
+
+ bus->fw_path = pfw_path;
+ bus->nv_path = pnv_path;
+
+ DHD_ERROR(("%s: firmware path=%s, nvram path=%s\n",
+ __FUNCTION__, bus->fw_path, bus->nv_path));
+
+ dhdpcie_mem_check(bus);
+
+ ret = dhdpcie_download_firmware(bus, osh);
+
+ return ret;
+}
+
+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);
+
+ 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;
+ char *imgbuf = NULL;
+ uint8 *memblock = NULL, *memptr;
+
+ int offset_end = bus->ramsize;
+
+ DHD_ERROR(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
+ 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;
+ }
+
+#ifdef BCM_AUTO_FWCRC
+ /* Firmware binary crc validation before downloading */
+ if (dhd_check_firmware_image(memptr, pfw_path)) {
+ DHD_ERROR(("check image failed\n"));
+ goto err;
+ }
+#endif
+
+ /* 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)
+ goto err;
+
+ if ((uint32)(uintptr)memblock % DHD_SDALIGN)
+ memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
+
+ DHD_INFO_HW4(("%s: dongle_ram_base: 0x%x ramsize: 0x%x tcm: %p\n",
+ __FUNCTION__, bus->dongle_ram_base, bus->ramsize, bus->tcm));
+
+ /* 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;
+ }
+ /* check if CR4/CA7 */
+ if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0) ||
+ si_setcore(bus->sih, ARMCA7_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;
+ offset_end += offset;
+ }
+ }
+ 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;
+ }
+ 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 (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;
+
+ nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
+
+ /* First try UEFI */
+ len = MAX_NVRAMBUF_SIZE;
+ dhd_get_download_buffer(bus->dhd, NULL, NVRAM, &memblock, &len);
+
+ /* If UEFI empty, then read from file system */
+ if ((len == 0) || (memblock[0] == '\0')) {
+
+ if (nvram_file_exists) {
+ len = MAX_NVRAMBUF_SIZE;
+ dhd_get_download_buffer(bus->dhd, pnv_path, NVRAM, &memblock, &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) {
+ 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;
+
+ p_dlarray = dlarray;
+ dlarray_size = sizeof(dlarray);
+ p_dlimagename = dlimagename;
+ p_dlimagever = dlimagever;
+ p_dlimagedate = dlimagedate;
+
+ if ((p_dlarray == 0) || (dlarray_size == 0) ||(dlarray_size > bus->ramsize) ||
+ (p_dlimagename == 0) || (p_dlimagever == 0) || (p_dlimagedate == 0))
+ 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 ((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;
+ }
+
+ 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));
+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_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
+ }
+
+ /* 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
+
+#ifdef DHD_DEBUG
+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;
+ printf("CONSOLE: %s\n", line);
+
+ }
+ }
+break2:
+
+ return BCME_OK;
+} /* dhdpcie_bus_readconsole */
+#endif /* DHD_DEBUG */
+
+static int
+dhdpcie_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;
+ trap_t tr;
+ pciedev_shared_t *pciedev_shared = bus->pcie_sh;
+ 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 = dhdpcie_readshared(bus)) < 0) {
+ goto done;
+ }
+
+ bcm_binit(&strbuf, data, size);
+
+ bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
+ pciedev_shared->msgtrace_addr, pciedev_shared->console_addr);
+
+ if ((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) {
+ 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;
+ }
+
+ 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));
+
+ 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 printbuf;
+ }
+
+ 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 printbuf;
+ }
+
+ 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 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 = dhdpcie_bus_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
+ */
+
+ printf("CONSOLE: %s\n", line);
+ }
+ }
+ }
+ }
+
+printbuf:
+ if (bus->pcie_sh->flags & (PCIE_SHARED_ASSERT | PCIE_SHARED_TRAP)) {
+ printf("%s: %s\n", __FUNCTION__, strbuf.origbuf);
+
+ /* wake up IOCTL wait event */
+ dhd_wakeup_ioctl_event(bus->dhd, IOCTL_RETURN_ON_TRAP);
+
+#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 */
+
+
+ }
+
+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;
+} /* 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;
+ /* 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 was down so skip\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+#endif /* SUPPORT_LINKDOWN_RECOVERY */
+
+ /* Get full mem size */
+ size = bus->ramsize;
+#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP)
+ buf = DHD_OS_PREALLOC(bus->dhd, DHD_PREALLOC_MEMDUMP_BUF, size);
+ bzero(buf, size);
+#else
+ buf = MALLOC(bus->dhd->osh, size);
+#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */
+ 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"));
+ 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));
+ if (buf) {
+ MFREE(bus->dhd->osh, buf, size);
+ }
+ 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_TRACE_HW4(("%s FUNC: Copy fw image to the embedded buffer \n", __FUNCTION__));
+
+ dhd_save_fwdump(bus->dhd, buf, bus->ramsize);
+ dhd_schedule_memdump(bus->dhd, buf, bus->ramsize);
+
+ return ret;
+}
+
+int
+dhd_bus_mem_dump(dhd_pub_t *dhdp)
+{
+ dhd_bus_t *bus = dhdp->bus;
+
+ if (bus->suspended) {
+ DHD_ERROR(("%s: Bus is suspend so skip\n", __FUNCTION__));
+ return 0;
+ }
+
+ return dhdpcie_mem_dump(bus);
+}
+
+#ifdef BCMDHDX
+int
+dhdx_dongle_mem_dump()
+{
+ if (!g_dhd_bus) {
+ DHD_ERROR(("%s: Bus is NULL\n", __FUNCTION__));
+ return -ENODEV;
+ }
+
+ if (g_dhd_bus->suspended) {
+ DHD_ERROR(("%s: Bus is suspend so skip\n", __FUNCTION__));
+ return 0;
+ }
+
+ g_dhd_bus->dhd->memdump_enabled = DUMP_MEMFILE_BUGON;
+ g_dhd_bus->dhd->memdump_type = DUMP_TYPE_AP_ABNORMAL_ACCESS;
+
+ return dhdpcie_mem_dump(g_dhd_bus);
+}
+EXPORT_SYMBOL(dhdx_dongle_mem_dump);
+#else
+int
+dhd_dongle_mem_dump()
+{
+ if (!g_dhd_bus) {
+ DHD_ERROR(("%s: Bus is NULL\n", __FUNCTION__));
+ return -ENODEV;
+ }
+
+ if (g_dhd_bus->suspended) {
+ DHD_ERROR(("%s: Bus is suspend so skip\n", __FUNCTION__));
+ return 0;
+ }
+
+ g_dhd_bus->dhd->memdump_enabled = DUMP_MEMFILE_BUGON;
+ g_dhd_bus->dhd->memdump_type = DUMP_TYPE_AP_ABNORMAL_ACCESS;
+
+ return dhdpcie_mem_dump(g_dhd_bus);
+}
+EXPORT_SYMBOL(dhd_dongle_mem_dump);
+#endif /* BCMDHDX */
+#endif /* DHD_FW_COREDUMP */
+
+int
+dhd_socram_dump(dhd_bus_t *bus)
+{
+#if defined(DHD_FW_COREDUMP)
+ return (dhdpcie_mem_dump(bus));
+#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 */
+ dsize = sizeof(uint64);
+
+ /* Do the transfer(s) */
+ if (write) {
+ while (size) {
+ if (size >= sizeof(uint64) && little_endian &&
+#ifdef CONFIG_64BIT
+ !(address % 8) &&
+#endif /* CONFIG_64BIT */
+ 1) {
+ dhdpcie_bus_wtcm64(bus, address, *((uint64 *)data));
+ } 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) {
+ if (size >= sizeof(uint64) && little_endian &&
+#ifdef CONFIG_64BIT
+ !(address % 8) &&
+#endif /* CONFIG_64BIT */
+ 1) {
+ *(uint64 *)data = dhdpcie_bus_rtcm64(bus, address);
+ } 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_sub_queues) {
+ DHD_ERROR(("%s: flow_id is invalid %d, max %d\n", __FUNCTION__,
+ flow_id, bus->max_sub_queues));
+ 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) {
+ PKTORPHAN(txp);
+
+ /*
+ * 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;
+ 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) ||
+ (!flow_ring_node->active) ||
+ (flow_ring_node->status == FLOW_RING_STATUS_DELETE_PENDING) ||
+ (flow_ring_node->status == FLOW_RING_STATUS_STA_FREEING)) {
+ 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;
+ }
+
+ 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));
+ PKTCFREE(bus->dhd->osh, txp, TRUE);
+ 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;
+}
+
+#if defined(DHD_DEBUG)
+/* 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) {
+ dhd_os_sdunlock(bus->dhd);
+ 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 */
+#endif /* defined(DHD_DEBUG) */
+
+/**
+ * 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)
+{
+ *(volatile uint8 *)(bus->tcm + offset) = (uint8)data;
+}
+
+uint8
+dhdpcie_bus_rtcm8(dhd_bus_t *bus, ulong offset)
+{
+ volatile uint8 data;
+
+ data = *(volatile uint8 *)(bus->tcm + offset);
+
+ return data;
+}
+
+void
+dhdpcie_bus_wtcm32(dhd_bus_t *bus, ulong offset, uint32 data)
+{
+ *(volatile uint32 *)(bus->tcm + offset) = (uint32)data;
+}
+void
+dhdpcie_bus_wtcm16(dhd_bus_t *bus, ulong offset, uint16 data)
+{
+ *(volatile uint16 *)(bus->tcm + offset) = (uint16)data;
+}
+void
+dhdpcie_bus_wtcm64(dhd_bus_t *bus, ulong offset, uint64 data)
+{
+ *(volatile uint64 *)(bus->tcm + offset) = (uint64)data;
+}
+
+uint16
+dhdpcie_bus_rtcm16(dhd_bus_t *bus, ulong offset)
+{
+ volatile uint16 data;
+
+ data = *(volatile uint16 *)(bus->tcm + offset);
+
+ return data;
+}
+
+uint32
+dhdpcie_bus_rtcm32(dhd_bus_t *bus, ulong offset)
+{
+ volatile uint32 data;
+
+ data = *(volatile uint32 *)(bus->tcm + offset);
+
+ return data;
+}
+
+uint64
+dhdpcie_bus_rtcm64(dhd_bus_t *bus, ulong offset)
+{
+ volatile uint64 data;
+
+ data = *(volatile uint64 *)(bus->tcm + offset);
+
+ return data;
+}
+
+/** 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;
+ ulong 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 = (ulong)&(sh->host_dma_scratch_buffer);
+ dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len);
+ prhex(__FUNCTION__, data, len);
+ break;
+ }
+
+ case D2H_DMA_SCRATCH_BUF_LEN:
+ {
+ pciedev_shared_t *sh = (pciedev_shared_t*)bus->shared_addr;
+ tcm_offset = (ulong)&(sh->host_dma_scratch_buffer_len);
+ dhdpcie_bus_wtcm32(bus, tcm_offset, (uint32) HTOL32(*(uint32 *)data));
+ 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 = (ulong)shmem->rings_info_ptr;
+ tcm_offset += OFFSETOF(ring_info_t, h2d_w_idx_hostaddr);
+ dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len);
+ 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 = (ulong)shmem->rings_info_ptr;
+ tcm_offset += OFFSETOF(ring_info_t, h2d_r_idx_hostaddr);
+ dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len);
+ 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 = (ulong)shmem->rings_info_ptr;
+ tcm_offset += OFFSETOF(ring_info_t, d2h_w_idx_hostaddr);
+ dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len);
+ 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 = (ulong)shmem->rings_info_ptr;
+ tcm_offset += OFFSETOF(ring_info_t, d2h_r_idx_hostaddr);
+ dhdpcie_bus_membytes(bus, TRUE, tcm_offset, (uint8*) &long_data, len);
+ 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, 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, 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, tcm_offset, (uint8 *) &long_data, len);
+ prhex(__FUNCTION__, data, len);
+ break;
+
+ case RING_WR_UPD:
+ tcm_offset = bus->ring_sh[ringid].ring_state_w;
+ dhdpcie_bus_wtcm16(bus, tcm_offset, (uint16) HTOL16(*(uint16 *)data));
+ break;
+
+ case RING_RD_UPD:
+ tcm_offset = bus->ring_sh[ringid].ring_state_r;
+ dhdpcie_bus_wtcm16(bus, 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;
+
+ 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) &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) &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 = 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));
+
+ 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 <bcm_buzzz.h>
+
+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("Maximum one argument supported\n");
+ 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("bcm_buzzz_dump total<%u> done\n", total);
+ return;
+ } else {
+ printf("bcm_buzzz_dump total<%u> : part2<%u> + part1<%u>\n",
+ 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("bcm_buzzz_dump done.\n");
+}
+
+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("Page memory allocation failure\n");
+ goto done;
+ }
+ if ((buzzz_p = MALLOC(bus->dhd->osh, sizeof(bcm_buzzz_t))) == NULL) {
+ printf("BCM BUZZZ memory allocation failure\n");
+ 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->buzzz));
+
+ if (sh->buzzz != 0U) { /* Fetch and display dongle BUZZZ Trace */
+
+ dhdpcie_bus_membytes(bus, FALSE, (ulong)sh->buzzz,
+ (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->buzzz,
+ (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("Empty dongle BUZZZ trace\n\n");
+ 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("Buffer memory allocation failure\n");
+ 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("<Evt[%02X]> ", buzzz_p->eventid[ctr]);
+ }
+ printf("<code execution point>\n");
+ }
+
+ dhd_buzzz_dump(buzzz_p, buffer_p, page_p);
+
+ printf("----- End of dongle BCM BUZZZ Trace -----\n\n");
+
+ 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))
+
+static bool
+pcie2_mdiosetblock(dhd_bus_t *bus, uint blk)
+{
+ uint mdiodata, mdioctrl, i = 0;
+ uint pcie_serdes_spinwait = 200;
+
+ mdioctrl = MDIOCTL2_DIVISOR_VAL | (0x1F << MDIOCTL2_REGADDR_SHF);
+ mdiodata = (blk << MDIODATA2_DEVADDR_SHF) | MDIODATA2_DONE;
+
+ si_corereg(bus->sih, bus->sih->buscoreidx, PCIE2_MDIO_CONTROL, ~0, mdioctrl);
+ si_corereg(bus->sih, bus->sih->buscoreidx, PCIE2_MDIO_WR_DATA, ~0, mdiodata);
+
+ OSL_DELAY(10);
+ /* retry till the transaction is complete */
+ while (i < pcie_serdes_spinwait) {
+ uint mdioctrl_read = si_corereg(bus->sih, bus->sih->buscoreidx, PCIE2_MDIO_WR_DATA,
+ 0, 0);
+ if (!(mdioctrl_read & MDIODATA2_DONE)) {
+ break;
+ }
+ OSL_DELAY(1000);
+ i++;
+ }
+
+ if (i >= pcie_serdes_spinwait) {
+ DHD_ERROR(("pcie_mdiosetblock: timed out\n"));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+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_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_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;
+ bus->pci_d3hot_done = 0;
+ 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
+pcie2_mdioop(dhd_bus_t *bus, uint physmedia, uint regaddr, bool write, uint *val,
+ bool slave_bypass)
+{
+ uint pcie_serdes_spinwait = 200, i = 0, mdio_ctrl;
+ uint32 reg32;
+
+ pcie2_mdiosetblock(bus, physmedia);
+
+ /* enable mdio access to SERDES */
+ mdio_ctrl = MDIOCTL2_DIVISOR_VAL;
+ mdio_ctrl |= (regaddr << MDIOCTL2_REGADDR_SHF);
+
+ if (slave_bypass)
+ mdio_ctrl |= MDIOCTL2_SLAVE_BYPASS;
+
+ if (!write)
+ mdio_ctrl |= MDIOCTL2_READ;
+
+ si_corereg(bus->sih, bus->sih->buscoreidx, PCIE2_MDIO_CONTROL, ~0, mdio_ctrl);
+
+ if (write) {
+ reg32 = PCIE2_MDIO_WR_DATA;
+ si_corereg(bus->sih, bus->sih->buscoreidx, PCIE2_MDIO_WR_DATA, ~0,
+ *val | MDIODATA2_DONE);
+ } else
+ reg32 = PCIE2_MDIO_RD_DATA;
+
+ /* retry till the transaction is complete */
+ while (i < pcie_serdes_spinwait) {
+ uint done_val = si_corereg(bus->sih, bus->sih->buscoreidx, reg32, 0, 0);
+ if (!(done_val & MDIODATA2_DONE)) {
+ if (!write) {
+ *val = si_corereg(bus->sih, bus->sih->buscoreidx,
+ PCIE2_MDIO_RD_DATA, 0, 0);
+ *val = *val & MDIODATA2_MASK;
+ }
+ return 0;
+ }
+ OSL_DELAY(1000);
+ i++;
+ }
+ return -1;
+}
+
+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_PCIEREG):
+ si_corereg(bus->sih, bus->sih->buscoreidx, OFFSETOF(sbpcieregs_t, configaddr), ~0,
+ int_val);
+ si_corereg(bus->sih, bus->sih->buscoreidx, OFFSETOF(sbpcieregs_t, configdata), ~0,
+ int_val2);
+ break;
+
+ case IOV_GVAL(IOV_PCIEREG):
+ si_corereg(bus->sih, bus->sih->buscoreidx, OFFSETOF(sbpcieregs_t, configaddr), ~0,
+ int_val);
+ int_val = si_corereg(bus->sih, bus->sih->buscoreidx,
+ OFFSETOF(sbpcieregs_t, configdata), 0, 0);
+ bcopy(&int_val, arg, sizeof(int_val));
+ break;
+
+ case IOV_SVAL(IOV_PCIECOREREG):
+ si_corereg(bus->sih, bus->sih->buscoreidx, int_val, ~0, int_val2);
+ break;
+ case IOV_GVAL(IOV_BAR0_SECWIN_REG):
+ {
+ sdreg_t sdreg;
+ uint32 addr, size;
+
+ bcopy(params, &sdreg, sizeof(sdreg));
+
+ addr = sdreg.offset;
+ size = sdreg.func;
+
+ if (si_backplane_access(bus->sih, addr, size, &int_val, TRUE) != BCME_OK) {
+ DHD_ERROR(("Invalid size/addr combination \n"));
+ bcmerror = BCME_ERROR;
+ break;
+ }
+ bcopy(&int_val, arg, sizeof(int32));
+ break;
+ }
+
+ case IOV_SVAL(IOV_BAR0_SECWIN_REG):
+ {
+ sdreg_t sdreg;
+ uint32 addr, size;
+
+ bcopy(params, &sdreg, sizeof(sdreg));
+
+ addr = sdreg.offset;
+ size = sdreg.func;
+ if (si_backplane_access(bus->sih, addr, size, &sdreg.value, FALSE) != BCME_OK) {
+ DHD_ERROR(("Invalid size/addr combination \n"));
+ bcmerror = BCME_ERROR;
+ }
+ break;
+ }
+
+ case IOV_GVAL(IOV_SBREG):
+ {
+ sdreg_t sdreg;
+ uint32 addr, size;
+
+ bcopy(params, &sdreg, sizeof(sdreg));
+
+ addr = sdreg.offset | SI_ENUM_BASE;
+ size = sdreg.func;
+
+ if (si_backplane_access(bus->sih, addr, size, &int_val, TRUE) != BCME_OK) {
+ DHD_ERROR(("Invalid size/addr combination \n"));
+ bcmerror = BCME_ERROR;
+ break;
+ }
+ bcopy(&int_val, arg, sizeof(int32));
+ break;
+ }
+
+ case IOV_SVAL(IOV_SBREG):
+ {
+ sdreg_t sdreg;
+ uint32 addr, size;
+
+ bcopy(params, &sdreg, sizeof(sdreg));
+
+ addr = sdreg.offset | SI_ENUM_BASE;
+ size = sdreg.func;
+ if (si_backplane_access(bus->sih, addr, size, &sdreg.value, FALSE) != BCME_OK) {
+ DHD_ERROR(("Invalid size/addr combination \n"));
+ bcmerror = BCME_ERROR;
+ }
+ break;
+ }
+
+ case IOV_GVAL(IOV_PCIESERDESREG):
+ {
+ uint val;
+ if (!PCIE_GEN2(bus->sih)) {
+ DHD_ERROR(("supported only in pcie gen2\n"));
+ bcmerror = BCME_ERROR;
+ break;
+ }
+
+ if (!pcie2_mdioop(bus, int_val, int_val2, FALSE, &val, FALSE)) {
+ bcopy(&val, arg, sizeof(int32));
+ } else {
+ DHD_ERROR(("pcie2_mdioop failed.\n"));
+ bcmerror = BCME_ERROR;
+ }
+ break;
+ }
+
+ case IOV_SVAL(IOV_PCIESERDESREG):
+ if (!PCIE_GEN2(bus->sih)) {
+ DHD_ERROR(("supported only in pcie gen2\n"));
+ bcmerror = BCME_ERROR;
+ break;
+ }
+ if (pcie2_mdioop(bus, int_val, int_val2, TRUE, &int_val3, FALSE)) {
+ DHD_ERROR(("pcie2_mdioop failed.\n"));
+ bcmerror = BCME_ERROR;
+ }
+ break;
+ case IOV_GVAL(IOV_PCIECOREREG):
+ int_val = si_corereg(bus->sih, bus->sih->buscoreidx, int_val, 0, 0);
+ bcopy(&int_val, arg, sizeof(int_val));
+ break;
+
+ case IOV_SVAL(IOV_PCIECFGREG):
+ OSL_PCI_WRITE_CONFIG(bus->osh, int_val, 4, int_val2);
+ break;
+
+ case IOV_GVAL(IOV_PCIECFGREG):
+ int_val = OSL_PCI_READ_CONFIG(bus->osh, int_val, 4);
+ bcopy(&int_val, arg, sizeof(int_val));
+ break;
+
+ case IOV_SVAL(IOV_PCIE_LPBK):
+ bcmerror = dhdpcie_bus_lpback_req(bus, int_val);
+ break;
+
+ case IOV_SVAL(IOV_PCIE_DMAXFER):
+ bcmerror = dhdpcie_bus_dmaxfer_req(bus, int_val, int_val2, int_val3);
+ break;
+
+ 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):
+ dhdpcie_bus_suspend(bus, bool_val);
+ break;
+
+ case IOV_GVAL(IOV_MEMSIZE):
+ int_val = (int32)bus->ramsize;
+ bcopy(&int_val, arg, val_size);
+ break;
+ case IOV_SVAL(IOV_MEMBYTES):
+ case IOV_GVAL(IOV_MEMBYTES):
+ {
+ uint32 address; /* absolute backplane address */
+ uint size, dsize;
+ uint8 *data;
+
+ bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
+
+ ASSERT(plen >= 2*sizeof(int));
+
+ address = (uint32)int_val;
+ 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) {
+ DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
+ __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
+ bcmerror = BCME_BADARG;
+ break;
+ }
+
+ DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n dsize %d ", __FUNCTION__,
+ (set ? "write" : "read"), size, address, dsize));
+
+ /* check if CR4 */
+ 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 (set && address == bus->dongle_ram_base) {
+ bus->resetinstr = *(((uint32*)params) + 2);
+ }
+ } else {
+ /* If we know about SOCRAM, check for a fit */
+ if ((bus->orig_ramsize) &&
+ ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
+ {
+ uint8 enable, protect, remap;
+ si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
+ if (!enable || protect) {
+ DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
+ __FUNCTION__, bus->orig_ramsize, size, address));
+ DHD_ERROR(("%s: socram enable %d, protect %d\n",
+ __FUNCTION__, enable, protect));
+ bcmerror = BCME_BADARG;
+ break;
+ }
+
+ if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) {
+ uint32 devramsize = si_socdevram_size(bus->sih);
+ if ((address < SOCDEVRAM_ARM_ADDR) ||
+ (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) {
+ DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
+ __FUNCTION__, address, size));
+ DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
+ __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize));
+ bcmerror = BCME_BADARG;
+ break;
+ }
+ /* move it such that address is real now */
+ address -= SOCDEVRAM_ARM_ADDR;
+ address += SOCDEVRAM_BP_ADDR;
+ DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
+ __FUNCTION__, (set ? "write" : "read"), size, address));
+ } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) {
+ /* Can not access remap region while devram remap bit is set
+ * ROM content would be returned in this case
+ */
+ DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n",
+ __FUNCTION__, address));
+ bcmerror = BCME_ERROR;
+ break;
+ }
+ }
+ }
+
+ /* Generate the actual data pointer */
+ data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
+
+ /* Call to do the transfer */
+ bcmerror = dhdpcie_bus_membytes(bus, set, address, data, 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_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 = DMA_INDX_ENAB(bus->dhd->dma_d2h_ring_upd_support) ? 1 : 0;
+ h2d_support = DMA_INDX_ENAB(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(("Bad argument. Possible values: 0, 1, 2 & 3\n"));
+ 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;
+ }
+ } 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_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;
+ }
+ 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_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_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;
+
+ 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(("bus not inited\n"));
+ return 0;
+ }
+ if (bus->dhd->prot == NULL) {
+ DHD_ERROR(("prot is not inited\n"));
+ return 0;
+ }
+ if (bus->dhd->busstate != DHD_BUS_DATA) {
+ DHD_ERROR(("not in a readystate to LPBK is not inited\n"));
+ return 0;
+ }
+ dhdmsgbuf_lpbk_req(bus->dhd, len);
+ return 0;
+}
+
+int
+dhdpcie_bus_suspend(struct dhd_bus *bus, bool state)
+{
+ int timeleft;
+ unsigned long flags;
+ int rc = 0;
+
+ 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 (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(("not in a readystate to LPBK is not inited\n"));
+ 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;
+ }
+
+ if (bus->suspended == state) { /* Set to same state */
+ DHD_ERROR(("Bus is already in SUSPEND state.\n"));
+ return BCME_OK;
+ }
+
+ 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__));
+ bus->wait_for_d3_ack = 0;
+ bus->suspended = TRUE;
+
+
+ DHD_GENERAL_LOCK(bus->dhd, flags);
+ /* stop all interface network queue. */
+ dhd_bus_stop_queue(bus);
+ bus->dhd->busstate = DHD_BUS_SUSPEND;
+ if (bus->dhd->dhd_bus_busy_state & DHD_BUS_BUSY_IN_TX) {
+ DHD_ERROR(("Tx Request is not ended\n"));
+ bus->dhd->busstate = DHD_BUS_DATA;
+ /* resume all interface network queue. */
+ dhd_bus_start_queue(bus);
+ DHD_GENERAL_UNLOCK(bus->dhd, flags);
+ bus->suspended = FALSE;
+ return -EBUSY;
+ }
+
+ bus->dhd->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_SUSPEND;
+ DHD_GENERAL_UNLOCK(bus->dhd, flags);
+
+ DHD_OS_WAKE_LOCK_WAIVE(bus->dhd);
+ dhd_os_set_ioctl_resp_timeout(D3_ACK_RESP_TIMEOUT);
+ dhdpcie_send_mb_data(bus, H2D_HOST_D3_INFORM);
+ timeleft = dhd_os_d3ack_wait(bus->dhd, &bus->wait_for_d3_ack);
+ dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT);
+ DHD_OS_WAKE_LOCK_RESTORE(bus->dhd);
+
+ {
+ uint32 d2h_mb_data = 0;
+ uint32 zero = 0;
+
+ /* If wait_for_d3_ack was not updated because D2H MB was not received */
+ if (bus->wait_for_d3_ack == 0) {
+ /* Read the Mb data to see if the Dongle has actually sent D3 ACK */
+ dhd_bus_cmn_readshared(bus, &d2h_mb_data, D2H_MB_DATA, 0);
+
+ if (!D2H_DEV_MB_INVALIDATED(d2h_mb_data) &&
+ (d2h_mb_data & D2H_DEV_D3_ACK)) {
+ DHD_ERROR(("*** D3 WAR for missing interrupt ***\r\n"));
+ /* Clear the MB Data */
+ dhd_bus_cmn_writeshared(bus, &zero, sizeof(uint32),
+ D2H_MB_DATA, 0);
+
+ /* Consider that D3 ACK is received */
+ bus->wait_for_d3_ack = 1;
+ bus->d3_ack_war_cnt++;
+
+ } /* d2h_mb_data & D2H_DEV_D3_ACK */
+ } /* bus->wait_for_d3_ack was 0 */
+ }
+
+ /* To allow threads that got pre-empted to complete.
+ */
+ while ((active = dhd_os_check_wakelock_all(bus->dhd)) &&
+ (idle_retry < MAX_WKLK_IDLE_CHECK)) {
+ msleep(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 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.
+ */
+ 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);
+
+ bus->suspended = FALSE;
+ DHD_GENERAL_LOCK(bus->dhd, flags);
+ 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 {
+ 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);
+ dhdpcie_bus_intr_disable(bus);
+ rc = dhdpcie_pci_suspend_resume(bus, state);
+ dhd_bus_set_device_wake(bus, FALSE);
+ }
+ bus->dhd->d3ackcnt_timeout = 0;
+#if defined(BCMPCIE_OOB_HOST_WAKE)
+ dhdpcie_oob_intr_set(bus, TRUE);
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+ } else if (timeleft == 0) {
+ bus->dhd->d3ack_timeout_occured = TRUE;
+ bus->dhd->d3ackcnt_timeout++;
+ DHD_ERROR(("%s: resumed on timeout for D3 ACK d3_inform_cnt %d \n",
+ __FUNCTION__, bus->dhd->d3ackcnt_timeout));
+ 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 */
+ bus->suspended = FALSE;
+ DHD_GENERAL_LOCK(bus->dhd, flags);
+ 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->d3ackcnt_timeout >= MAX_CNTL_D3ACK_TIMEOUT) {
+ DHD_ERROR(("%s: Event HANG send up "
+ "due to PCIe linkdown\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;
+ DHD_GENERAL_LOCK(bus->dhd, flags);
+ bus->dhd->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_SUSPEND;
+ dhd_os_busbusy_wake(bus->dhd);
+ DHD_GENERAL_UNLOCK(bus->dhd, flags);
+ } else {
+ /* Resume */
+#if defined(BCMPCIE_OOB_HOST_WAKE)
+ DHD_OS_OOB_IRQ_WAKE_UNLOCK(bus->dhd);
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+ DHD_GENERAL_LOCK(bus->dhd, flags);
+ bus->dhd->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_RESUME;
+ DHD_GENERAL_UNLOCK(bus->dhd, flags);
+ rc = dhdpcie_pci_suspend_resume(bus, state);
+ if (bus->dhd->busstate == DHD_BUS_SUSPEND) {
+ DHD_OS_WAKE_LOCK_WAIVE(bus->dhd);
+ dhdpcie_send_mb_data(bus, (H2D_HOST_D0_INFORM));
+ DHD_OS_WAKE_LOCK_RESTORE(bus->dhd);
+ dhd_bus_set_device_wake(bus, TRUE);
+ }
+ bus->suspended = FALSE;
+ DHD_GENERAL_LOCK(bus->dhd, flags);
+ bus->dhd->busstate = DHD_BUS_DATA;
+ bus->dhd->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_RESUME;
+#ifdef DHD_PCIE_RUNTIMEPM
+ if (bus->dhd->dhd_bus_busy_state & DHD_BUS_BUSY_RPM_SUSPEND_DONE) {
+ bus->bus_wake = 1;
+ OSL_SMP_WMB();
+ wake_up_interruptible(&bus->rpm_queue);
+ }
+#endif /* DHD_PCIE_RUNTIMEPM */
+ /* resume all interface network queue. */
+ dhd_bus_start_queue(bus);
+ dhd_os_busbusy_wake(bus->dhd);
+ DHD_GENERAL_UNLOCK(bus->dhd, flags);
+ dhdpcie_bus_intr_enable(bus);
+ }
+ return rc;
+}
+
+/** 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)
+{
+ 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->busstate != DHD_BUS_DATA) {
+ DHD_ERROR(("not in a readystate to LPBK is not inited\n"));
+ return BCME_ERROR;
+ }
+
+ if (len < 5 || len > 4194296) {
+ DHD_ERROR(("len is too small or too large\n"));
+ return BCME_ERROR;
+ }
+ return dhdmsgbuf_dmaxfer_req(bus->dhd, len, srcdelay, destdelay);
+}
+
+
+
+static int
+dhdpcie_bus_download_state(dhd_bus_t *bus, bool enter)
+{
+ int bcmerror = 0;
+ 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) {
+ 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;
+ }
+
+ /* 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 */
+ DHD_INFO_HW4(("%s: tcm: %p varaddr: 0x%x varsize: %d\n",
+ __FUNCTION__, bus->tcm, varaddr, varsize));
+ bcmerror = dhdpcie_bus_membytes(bus, TRUE, varaddr, vbuffer, varsize);
+
+ /* Implement read back and verify later */
+#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)
+ 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(("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;
+ bus->nvram_csm = varsizew;
+ } else {
+ varsizew = varsize / 4;
+ varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
+ bus->nvram_csm = varsizew;
+ varsizew = htol32(varsizew);
+ }
+
+ DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
+
+ /* Write the length token to the last word */
+ DHD_INFO_HW4(("%s: tcm: %p phys_size: 0x%x varsizew: %x\n",
+ __FUNCTION__, bus->tcm, phys_size, varsizew));
+ 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);
+
+
+err:
+ return bcmerror;
+}
+
+#ifndef BCMPCIE_OOB_HOST_WAKE
+/* 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);
+}
+#endif /* !BCMPCIE_OOB_HOST_WAKE */
+
+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);
+}
+
+/** 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;
+
+ 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 %10s %4s %4s %17s %17s %7s ",
+ "Num:", "Flow", "If", "Prio", ":Dest_MacAddress:", "Qlen", "CLen",
+ "Overflows", "RD", "WR", "BASE(VA)", "BASE(PA)", "SIZE");
+ 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) {
+ flow_info = &flow_ring_node->flow_info;
+ bcm_bprintf(strbuf,
+ "%3d. %4d %2d %4d %17s %4d %4d %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_FLOW_QUEUE_FAILURES(&flow_ring_node->queue));
+ dhd_prot_print_flow_ring(dhdp, flow_ring_node->prot_info, strbuf,
+ "%4d %4d %17p %8x:%8x %7d ");
+ 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);
+ bcm_bprintf(strbuf, "D3 Ack WAR cnt %d\n", dhdp->bus->d3_ack_war_cnt);
+}
+
+/**
+ * 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;
+
+ DHD_FLOWRING_LIST_LOCK(bus->dhd->flowring_list_lock, flags);
+ for (item = dll_head_p(&bus->const_flowring);
+ (!dhd_is_device_removed(dhd) && !dll_end(&bus->const_flowring, 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(("mailbox communication not supported\n"));
+ return;
+ }
+ if (bus->db1_for_mb) {
+ /* this is a pcie core register, not the config register */
+ DHD_INFO(("writing a mail box interrupt to the device, through doorbell 1\n"));
+ si_corereg(bus->sih, bus->sih->buscoreidx, PCIH2D_DB1, ~0, 0x12345678);
+ } else {
+ DHD_INFO(("writing a mail box interrupt to the device, through config space\n"));
+ dhdpcie_bus_cfg_write_dword(bus, PCISBMbx, 4, (1 << 0));
+ dhdpcie_bus_cfg_write_dword(bus, PCISBMbx, 4, (1 << 0));
+ }
+}
+
+static void
+dhd_bus_set_device_wake(struct dhd_bus *bus, bool val)
+{
+ if (bus->device_wake_state != val)
+ {
+ DHD_INFO(("Set Device_Wake to %d\n", val));
+#ifdef PCIE_OOB
+ if (bus->oob_enabled)
+ {
+ 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);
+ }
+ }
+#endif /* PCIE_OOB */
+ bus->device_wake_state = val;
+ }
+}
+
+#ifdef PCIE_OOB
+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;
+}
+
+static 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 /* PCIE_OOB */
+
+/** mailbox doorbell ring function */
+void
+dhd_bus_ringbell(struct dhd_bus *bus, uint32 value)
+{
+ 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(("writing a door bell to the device\n"));
+ si_corereg(bus->sih, bus->sih->buscoreidx, PCIH2D_MailBox, ~0, 0x12345678);
+ }
+}
+
+void
+dhdpcie_bus_ringbell_fast(struct dhd_bus *bus, uint32 value)
+{
+#ifdef PCIE_OOB
+ dhd_bus_set_device_wake(bus, TRUE);
+ dhd_bus_doorbell_timeout_reset(bus);
+#endif
+ W_REG(bus->pcie_mb_intr_osh, bus->pcie_mb_intr_addr, value);
+}
+
+static void
+dhd_bus_ringbell_oldpcie(struct dhd_bus *bus, uint32 value)
+{
+ uint32 w;
+ 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;
+}
+
+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);
+ return 0;
+ }
+ bus->dhd->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_DPC;
+ DHD_GENERAL_UNLOCK(bus->dhd, flags);
+
+ resched = dhdpcie_bus_process_mailbox_intr(bus, bus->intstatus);
+ if (!resched) {
+ bus->intstatus = 0;
+ if (!bus->pci_d3hot_done) {
+ dhdpcie_bus_intr_enable(bus);
+ } else {
+ DHD_ERROR(("%s: dhdpcie_bus_intr_enable skip in pci D3hot state \n",
+ __FUNCTION__));
+ }
+ }
+
+ DHD_GENERAL_LOCK(bus->dhd, flags);
+ bus->dhd->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_DPC;
+ dhd_os_busbusy_wake(bus->dhd);
+ DHD_GENERAL_UNLOCK(bus->dhd, flags);
+
+ return resched;
+
+}
+
+
+static void
+dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data)
+{
+ uint32 cur_h2d_mb_data = 0;
+
+ 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;
+ }
+
+ dhd_bus_cmn_readshared(bus, &cur_h2d_mb_data, H2D_MB_DATA, 0);
+
+ if (cur_h2d_mb_data != 0) {
+ uint32 i = 0;
+ DHD_INFO(("GRRRRRRR: MB transaction is already pending 0x%04x\n", 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);
+
+ if (h2d_mb_data == H2D_HOST_D3_INFORM) {
+ DHD_INFO_HW4(("%s: send H2D_HOST_D3_INFORM to dongle\n", __FUNCTION__));
+ 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++;
+ }
+}
+
+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_INFO_HW4(("%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(("D2H_MB_DATA: 0x%08x\n", 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(("D2H_MB_DATA: DEEP SLEEP REQ\n"));
+ dhdpcie_send_mb_data(bus, H2D_HOST_DS_ACK);
+ DHD_INFO(("D2H_MB_DATA: sent DEEP SLEEP ACK\n"));
+ }
+ if (d2h_mb_data & D2H_DEV_DS_EXIT_NOTE) {
+ /* what should we do */
+ DHD_INFO(("D2H_MB_DATA: DEEP SLEEP EXIT\n"));
+ }
+ 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) {
+ bus->wait_for_d3_ack = 1;
+ dhd_os_d3ack_wake(bus->dhd);
+ }
+ }
+}
+
+/* Inform Dongle to print HW Registers for Livelock Debug */
+void dhdpcie_bus_dongle_print_hwregs(struct dhd_bus *bus)
+{
+ dhdpcie_send_mb_data(bus, H2D_FW_TRAP);
+}
+
+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))
+ dhdpcie_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;
+
+ /* 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);
+
+ /* 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));
+
+ 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 bool
+dhdpcie_check_firmware_compatible(uint32 firmware_api_version, uint32 host_api_version)
+{
+ DHD_INFO(("firmware api revision %d, host api revision %d\n",
+ firmware_api_version, host_api_version));
+ if (firmware_api_version <= host_api_version)
+ return TRUE;
+ if ((firmware_api_version == 6) && (host_api_version == 5))
+ return TRUE;
+ if ((firmware_api_version == 5) && (host_api_version == 6))
+ return TRUE;
+ return FALSE;
+}
+
+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;
+
+ DHD_INFO_HW4(("%s: ram_base: 0x%x ramsize 0x%x tcm: %p shaddr: 0x%x nvram_csm: 0x%x\n",
+ __FUNCTION__, bus->dongle_ram_base, bus->ramsize,
+ bus->tcm, shaddr, bus->nvram_csm));
+ /* 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(("Waited %u usec, dongle is not ready\n", tmo.elapsed));
+ return BCME_ERROR;
+ } else {
+ bus->shared_addr = (ulong)addr;
+ DHD_ERROR(("PCIe shared addr (0x%08x) read took %u usec "
+ "before dongle is ready\n", addr, tmo.elapsed));
+ }
+
+ /* 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 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);
+
+#ifdef DHD_DEBUG
+ /* load bus console address */
+ bus->console_addr = sh->console_addr;
+#endif
+
+ /* Read the dma rx offset */
+ bus->dma_rxoffset = bus->pcie_sh->dma_rxoffset;
+ dhd_prot_rx_dataoffset(bus->dhd, bus->dma_rxoffset);
+
+ DHD_ERROR(("DMA RX offset from shared Area %d\n", bus->dma_rxoffset));
+
+ if (!(dhdpcie_check_firmware_compatible(sh->flags & PCIE_SHARED_VERSION_MASK,
+ 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,
+ sh->flags & PCIE_SHARED_VERSION_MASK));
+ return BCME_ERROR;
+ }
+
+ bus->rw_index_sz = (sh->flags & PCIE_SHARED_2BYTE_INDICES) ?
+ sizeof(uint16) : sizeof(uint32);
+ DHD_ERROR(("%s: Dongle advertizes %d size indices\n",
+ __FUNCTION__, bus->rw_index_sz));
+
+ /* Does the FW support DMA'ing r/w indices */
+ if (sh->flags & PCIE_SHARED_DMA_INDEX) {
+
+
+ DHD_ERROR(("%s: Host support DMAing indices: H2D:%d - D2H:%d. FW supports it\n",
+ __FUNCTION__,
+ (DMA_INDX_ENAB(bus->dhd->dma_h2d_ring_upd_support) ? 1 : 0),
+ (DMA_INDX_ENAB(bus->dhd->dma_d2h_ring_upd_support) ? 1 : 0)));
+
+ } else if (DMA_INDX_ENAB(bus->dhd->dma_d2h_ring_upd_support) ||
+ DMA_INDX_ENAB(bus->dhd->dma_h2d_ring_upd_support)) {
+
+#ifdef BCM_INDX_DMA
+ DHD_ERROR(("%s: Incompatible FW. FW does not support DMAing indices\n",
+ __FUNCTION__));
+ return BCME_ERROR;
+#endif
+ DHD_ERROR(("%s: Host supports DMAing indices but FW does not\n",
+ __FUNCTION__));
+ bus->dhd->dma_d2h_ring_upd_support = FALSE;
+ bus->dhd->dma_h2d_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);
+
+
+ bus->max_sub_queues = ltoh16(ring_info.max_sub_queues);
+
+ /* 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 (DMA_INDX_ENAB(bus->dhd->dma_h2d_ring_upd_support)) {
+ dma_indx_wr_buf = dhd_prot_dma_indx_init(bus->dhd, bus->rw_index_sz,
+ H2D_DMA_INDX_WR_BUF, bus->max_sub_queues);
+ dma_indx_rd_buf = dhd_prot_dma_indx_init(bus->dhd, bus->rw_index_sz,
+ D2H_DMA_INDX_RD_BUF, BCMPCIE_D2H_COMMON_MSGRINGS);
+
+ 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;
+ }
+ }
+
+ if (DMA_INDX_ENAB(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, BCMPCIE_D2H_COMMON_MSGRINGS);
+ dma_indx_rd_buf = dhd_prot_dma_indx_init(bus->dhd, bus->rw_index_sz,
+ H2D_DMA_INDX_RD_BUF, bus->max_sub_queues);
+
+ 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;
+ }
+ }
+
+ /* read ringmem and ringstate ptrs from shared area and store in host variables */
+ dhd_fillup_ring_sharedptr_info(bus, &ring_info);
+
+ bcm_print_bytes("ring_info_raw", (uchar *)&ring_info, sizeof(ring_info_t));
+ DHD_INFO(("ring_info\n"));
+
+ DHD_ERROR(("%s: max H2D queues %d\n",
+ __FUNCTION__, ltoh16(ring_info.max_sub_queues)));
+
+ 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));
+ }
+
+ bus->dhd->d2h_sync_mode = sh->flags & PCIE_SHARED_D2H_SYNC_MODE_MASK;
+ DHD_INFO(("%s: d2h_sync_mode 0x%08x\n",
+ __FUNCTION__, bus->dhd->d2h_sync_mode));
+
+ 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;
+
+ /* 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(("ring id %d ring mem addr 0x%04x \n",
+ 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(("h2d w/r : idx %d write %x read %x \n", 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(("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));
+ }
+
+ /* Store txflow ring write/read pointers */
+ for (j = 0; j < (bus->max_sub_queues - BCMPCIE_H2D_COMMON_MSGRINGS);
+ 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(("FLOW Rings h2d 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;
+
+ 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);
+#endif /* DHD_PCIE_RUNTIMEPM */
+
+ bus->d3_ack_war_cnt = 0;
+
+ 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 */
+ DHD_INFO_HW4(("%s: tcm: %p, addr: 0x%x val: 0x%x\n", __FUNCTION__, bus->tcm, addr, val));
+ dhdpcie_bus_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val));
+}
+
+
+bool
+dhdpcie_chipmatch(uint16 vendor, uint16 device)
+{
+ if (vendor != PCI_VENDOR_ID_BROADCOM) {
+ DHD_ERROR(("%s: Unsupported vendor %x device %x\n", __FUNCTION__,
+ vendor, device));
+ 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 == BCM4345_D11AC_ID) || (device == BCM4345_D11AC2G_ID) ||
+ (device == BCM4345_D11AC5G_ID) || BCM4345_CHIP(device))
+ 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 == 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;
+
+ DHD_ERROR(("%s: Unsupported vendor %x device %x\n", __FUNCTION__, vendor, device));
+ 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)) {
+ DHD_ERROR(("%s: cc_nvmdump cmd. supported for 4350/4345 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 */
+ 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 */
+ 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__));
+ }
+ }
+
+ if (((chipcregs->sromcontrol & SRC_PRESENT) == 0) &&
+ ((chipcregs->capabilities & CC_CAP_OTPSIZE) == 0)) {
+ DHD_ERROR(("%s: SPROM and OTP could not be found \n",
+ __FUNCTION__));
+ return BCME_NOTFOUND;
+ }
+
+ /* Check the strapping option in SpromCtrl: Set = OTP otherwise SPROM */
+ if ((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:");
+
+ /* Point to the SPROM/OTP shadow in ChipCommon */
+ nvm_shadow = chipcregs->sromotp;
+
+ /*
+ * 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 */
+
+/**
+ * Name: dhdpcie_sromotp_customvar
+ *
+ * Description:
+ * read otp/sprom and parse & store customvar.
+ *
+ * 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_sromotp_customvar(dhd_bus_t *bus, uint32 *customvar1, uint32 *customvar2)
+{
+ 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};
+
+#ifdef CUSTOMER_HW2
+ uint32 otp_start_addr;
+ uint32 otp_end_addr;
+ uint32 cur_addr;
+ uint32 byte_enable;
+ int delay;
+#else
+ volatile uint16 *nvm_shadow;
+#endif /* CUSTOMER_HW2 */
+
+ uint cur_coreid;
+ uint chipc_corerev;
+ chipcregs_t *chipcregs;
+ uint16 *otp_dump;
+ uint8 *cis;
+ uint8 tup, tlen;
+ int i = 0;
+
+ /* 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 != BCM4359_CHIP_ID) &&
+ ((uint16)bus->sih->chip != BCM4349_CHIP_ID)) {
+ DHD_ERROR(("%s: supported for chips"
+ "4350/4345/4355/4364/4349/4359 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;
+ DHD_TRACE(("\nSPROM Present (Size %d bits)\n", sprom_size));
+ }
+
+ if (chipcregs->sromcontrol & SRC_OTPPRESENT) {
+ DHD_TRACE(("\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;
+ DHD_TRACE(("(Size %d bits)\n", otp_size));
+ } else {
+ otp_size = (((chipcregs->capabilities & CC_CAP_OTPSIZE)
+ >> CC_CAP_OTPSIZE_SHIFT) + 1) * 1024;
+ DHD_TRACE(("(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];
+ DHD_TRACE(("(Size %d bits)\n", otp_size));
+ } else {
+ otp_size = otp_size_65nm[(chipcregs->capabilities & CC_CAP_OTPSIZE)
+ >> CC_CAP_OTPSIZE_SHIFT];
+ DHD_TRACE(("(Size %d bits)\n", otp_size));
+ DHD_TRACE(("%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)) {
+
+ DHD_TRACE(("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)) {
+
+ DHD_TRACE(("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;
+ }
+
+#ifdef CUSTOMER_HW2
+
+ /* Use CC backplane interconnect registers to read OTP region */
+ otp_start_addr = si_corebase(bus->sih, GCI_CORE_ID);
+ if (!otp_start_addr) {
+ DHD_ERROR(("%s: Failed to find gci core base addr\n",
+ __FUNCTION__));
+ return BCME_NOTFOUND;
+ }
+
+ otp_dump = kzalloc(dump_size*2, GFP_KERNEL);
+ if (otp_dump == NULL) {
+ DHD_ERROR(("%s: Insufficient system memory of size %d\n",
+ __FUNCTION__, dump_size));
+ return BCME_NOMEM;
+ }
+
+ /* Read 16 bits / iteration.
+ * dump_size is in 16-bit words
+ */
+ otp_end_addr = otp_start_addr + (dump_size * 2);
+ cur_addr = otp_start_addr;
+ /* ByteEnables(3:0) bits represent backplane address and data
+ * locations to read/write in 4-byte width.
+ */
+ byte_enable = 0x03;
+
+ while (cur_addr < otp_end_addr) {
+ W_REG(bus->osh, &chipcregs->bp_addrlow, cur_addr);
+ W_REG(bus->osh, &chipcregs->bp_addrhigh, 0x0);
+ /* 0x0200 will set StartBusy bit to start indirect backplane access */
+ W_REG(bus->osh, &chipcregs->bp_indaccess, 0x0200 | byte_enable);
+
+ for (delay = 0; delay < STARTBUSY_BIT_POLL_MAX_TIME; delay++) {
+ /* Hardware clears StartBusy bit on transfer completion */
+ if (R_REG(bus->osh, &chipcregs->bp_indaccess) == byte_enable)
+ break;
+ OSL_DELAY(100);
+ }
+ if (delay == STARTBUSY_BIT_POLL_MAX_TIME) {
+ DHD_ERROR(("%s: Read from 0x%x didn't complete\n", __FUNCTION__, cur_addr));
+ if (otp_dump) {
+ kfree(otp_dump);
+ otp_dump = NULL;
+ }
+ return BCME_ERROR;
+ }
+
+ if (byte_enable == 0x03) {
+ *(otp_dump + dump_offset) = R_REG(bus->osh, &chipcregs->bp_data) & 0xFFFF;
+ byte_enable = 0x0c;
+ } else {
+ *(otp_dump + dump_offset) =
+ (R_REG(bus->osh, &chipcregs->bp_data) >> 16) & 0xFFFF;
+ byte_enable = 0x03;
+ }
+
+ cur_addr += 2;
+ dump_offset += 1;
+ }
+
+#else /* CUSTOMER_HW2 */
+
+ /* 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;
+ }
+
+ otp_dump = kzalloc(dump_size*2, GFP_KERNEL);
+ if (otp_dump == NULL) {
+ DHD_ERROR(("%s: Insufficient system memory of size %d\n",
+ __FUNCTION__, dump_size));
+ return BCME_NOMEM;
+ }
+
+ /*
+ * Read 16 bits / iteration.
+ * dump_size & dump_offset in 16-bit words
+ */
+ while (dump_offset < dump_size) {
+ *(otp_dump + dump_offset) = *(nvm_shadow + dump_offset);
+ dump_offset += 0x1;
+ }
+
+#endif /* CUSTOMER_HW2 */
+
+ /* Read from cis tuple start address */
+ cis = (uint8 *)otp_dump + CISTPL_OFFSET;
+
+ /* parse value of customvar2 tuple */
+ do {
+ tup = cis[i++];
+ if (tup == CISTPL_NULL || tup == CISTPL_END)
+ tlen = 0;
+ else
+ tlen = cis[i++];
+
+ if ((i + tlen) >= dump_size*2)
+ break;
+
+ switch (tup) {
+ case CISTPL_BRCM_HNBU:
+ switch (cis[i]) {
+ case HNBU_CUSTOM1:
+ *customvar1 = ((cis[i + 4] << 24) +
+ (cis[i + 3] << 16) + (cis[i + 2] << 8) +
+ cis[i + 1]);
+ DHD_TRACE(("%s : customvar1 [%x]\n",
+ __FUNCTION__, *customvar1));
+ break;
+ case HNBU_CUSTOM2:
+ *customvar2 = ((cis[i + 4] << 24) +
+ (cis[i + 3] << 16) + (cis[i + 2] << 8) +
+ cis[i + 1]);
+ DHD_TRACE(("%s : customvar2 [%x]\n",
+ __FUNCTION__, *customvar2));
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ i += tlen;
+ } while (tup != 0xff);
+
+ if (otp_dump) {
+ kfree(otp_dump);
+ otp_dump = NULL;
+ }
+
+ /* Switch back to the original core */
+ si_setcore(bus->sih, cur_coreid, 0);
+
+ return BCME_OK;
+} /* dhdpcie_sromotp_customvar */
+
+/** 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));
+
+ flow_ring_node->status = FLOW_RING_STATUS_CLOSED;
+ flow_ring_node->active = FALSE;
+
+ DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags);
+
+ 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->const_flowring, &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 Flow %d\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;
+
+}
+
+/** This function is not called. Obsolete ? */
+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 Delete\n", __FUNCTION__));
+
+ flow_ring_node = (flow_ring_node_t *)arg;
+ queue = &flow_ring_node->queue; /* queue associated with flow ring */
+
+ DHD_FLOWRING_LOCK(flow_ring_node->lock, flags);
+
+#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);
+
+ flow_ring_node->status = FLOW_RING_STATUS_FLUSH_PENDING;
+ 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_sub_queues;
+}
+
+/* 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;
+}
+
+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;
+}
+
+#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 */
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_pcie.h b/drivers/net/wireless/bcmdhd_1363/dhd_pcie.h
new file mode 100644
index 000000000000..3072ca20279b
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_pcie.h
@@ -0,0 +1,315 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_pcie.h 607608 2015-12-21 13:14:19Z $
+ */
+
+
+#ifndef dhd_pcie_h
+#define dhd_pcie_h
+
+#include <bcmpcie.h>
+#include <hnd_cons.h>
+#ifdef SUPPORT_LINKDOWN_RECOVERY
+#ifdef CONFIG_ARCH_MSM
+#ifdef CONFIG_PCI_MSM
+#include <linux/msm_pcie.h>
+#else
+#include <mach/msm_pcie.h>
+#endif /* CONFIG_PCI_MSM */
+#endif /* CONFIG_ARCH_MSM */
+#ifdef EXYNOS_PCIE_LINKDOWN_RECOVERY
+#ifdef CONFIG_SOC_EXYNOS8890
+#include <linux/exynos-pci-noti.h>
+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 */
+#endif /* EXYNOS_PCIE_LINKDOWN_RECOVERY */
+#endif /* SUPPORT_LINKDOWN_RECOVERY */
+
+#ifdef DHD_PCIE_RUNTIMEPM
+#include <linux/mutex.h>
+#include <linux/wait.h>
+
+#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
+#ifdef CONFIG_SOC_EXYNOS8890
+#define struct_pcie_notify struct exynos_pcie_notify
+#define struct_pcie_register_event struct exynos_pcie_register_event
+#endif /* CONFIG_SOC_EXYNOS8890 */
+#endif /* EXYNOS_PCIE_LINKDOWN_RECOVERY */
+#endif /* SUPPORT_LINKDOWN_RECOVERY */
+
+/*
+ * Router with 4366 can have 128 stations and 16 BSS,
+ * hence (128 stations x 4 access categories for ucast) + 16 bc/mc flowrings
+ */
+#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)
+
+#ifndef MAX_CNTL_D3ACK_TIMEOUT
+#define MAX_CNTL_D3ACK_TIMEOUT 2
+#endif /* MAX_CNTL_D3ACK_TIMEOUT */
+
+#ifdef DHD_DEBUG
+
+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;
+#endif /* DHD_DEBUG */
+typedef struct ring_sh_info {
+ uint32 ring_mem_addr;
+ uint32 ring_state_w;
+ uint32 ring_state_r;
+} ring_sh_info_t;
+
+typedef struct dhd_bus {
+ dhd_pub_t *dhd;
+ struct pci_dev *dev; /* pci device handle */
+ dll_t const_flowring; /* constructed list of tx flowring queues */
+
+ 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) */
+ 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 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 */
+
+#ifdef DHD_DEBUG
+ dhd_console_t console; /* Console output polling support */
+ uint console_addr; /* Console address from shared struct */
+#endif /* DHD_DEBUG */
+
+ 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;
+
+ uint32 *pcie_mb_intr_addr;
+ void *pcie_mb_intr_osh;
+ bool sleep_allowed;
+
+ /* 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;
+ uint32 max_sub_queues;
+ uint32 rw_index_sz;
+ bool db1_for_mb;
+ bool suspended;
+
+ dhd_timeout_t doorbell_timer;
+ bool device_wake_state;
+ bool irq_registered;
+#ifdef PCIE_OOB
+ bool oob_enabled;
+#endif /* PCIE_OOB */
+#ifdef SUPPORT_LINKDOWN_RECOVERY
+#if defined(CONFIG_ARCH_MSM) || (defined(EXYNOS_PCIE_LINKDOWN_RECOVERY) && \
+ defined(CONFIG_SOC_EXYNOS8890))
+#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) */
+#endif /* SUPPORT_LINKDOWN_RECOVERY */
+#ifdef DHD_PCIE_RUNTIMEPM
+ int32 idlecount; /* Activity timeout counter */
+ int32 idletime; /* Control for activity timeout */
+ 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;
+ uint32 d3_ack_war_cnt;
+ uint8 is_linkdown;
+ uint32 pci_d3hot_done;
+} 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 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 int dhdpcie_bus_suspend(struct dhd_bus *bus, bool state);
+extern int dhdpcie_pci_suspend_resume(struct dhd_bus *bus, bool state);
+extern bool dhdpcie_tcm_valid(dhd_bus_t *bus);
+extern void dhdpcie_bus_dongle_print_hwregs(struct dhd_bus *bus);
+#ifndef BCMPCIE_OOB_HOST_WAKE
+extern void dhdpcie_pme_active(osl_t *osh, bool enable);
+#endif /* !BCMPCIE_OOB_HOST_WAKE */
+extern bool dhdpcie_pme_cap(osl_t *osh);
+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_enable_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);
+#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);
+#endif /* PCIE_OOB */
+
+#ifdef USE_EXYNOS_PCIE_RC_PMPATCH
+#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
+#else
+#error "Not supported platform"
+#endif
+#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 */
+
+extern int dhd_buzzz_dump_dngl(dhd_bus_t *bus);
+#endif /* dhd_pcie_h */
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_pcie_linux.c b/drivers/net/wireless/bcmdhd_1363/dhd_pcie_linux.c
new file mode 100644
index 000000000000..aa363b941d37
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_pcie_linux.c
@@ -0,0 +1,1583 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_pcie_linux.c 650724 2016-07-22 08:41:52Z $
+ */
+
+
+/* include files */
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <bcmdevs.h>
+#include <siutils.h>
+#include <hndsoc.h>
+#include <hndpmu.h>
+#include <sbchipc.h>
+#if defined(DHD_DEBUG)
+#include <hnd_armtrap.h>
+#include <hnd_cons.h>
+#endif /* defined(DHD_DEBUG) */
+#include <dngl_stats.h>
+#include <pcie_core.h>
+#include <dhd.h>
+#include <dhd_bus.h>
+#include <dhd_proto.h>
+#include <dhd_dbg.h>
+#include <dhdioctl.h>
+#include <bcmmsgbuf.h>
+#include <pcicfg.h>
+#include <dhd_pcie.h>
+#include <dhd_linux.h>
+#ifdef CONFIG_ARCH_MSM
+#ifdef CONFIG_PCI_MSM
+#include <linux/msm_pcie.h>
+#else
+#include <mach/msm_pcie.h>
+#endif /* CONFIG_PCI_MSM */
+#endif /* CONFIG_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)
+
+
+/* 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 */
+} dhdpcie_info_t;
+
+
+struct pcos_info {
+ dhdpcie_info_t *pc;
+ spinlock_t lock;
+ wait_queue_head_t intr_wait_queue;
+ struct timer_list 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;
+#endif /* BCMPCIE_OOB_HOST_WAKE */
+
+/* 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(struct pci_dev *dev, 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, }
+};
+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: {},
+#ifndef BCMDHDX
+ name: "pcieh",
+#else
+ name: "pciehx",
+#endif /* BCMDHDX */
+ 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 DHD_PCIE_RUNTIMEPM
+static int dhdpcie_pm_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ return dhdpcie_set_suspend_resume(pdev, TRUE);
+}
+
+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);
+ }
+
+ return 0;
+}
+
+static int dhdpcie_pm_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ return dhdpcie_set_suspend_resume(pdev, FALSE);
+}
+
+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)
+{
+ BCM_REFERENCE(state);
+ return dhdpcie_set_suspend_resume(pdev, TRUE);
+}
+
+static int dhdpcie_pci_resume(struct pci_dev *pdev)
+{
+ return dhdpcie_set_suspend_resume(pdev, FALSE);
+}
+
+#endif /* DHD_PCIE_RUNTIMEPM */
+
+static int dhdpcie_set_suspend_resume(struct pci_dev *pdev, bool state)
+{
+ int ret = 0;
+ dhdpcie_info_t *pch = pci_get_drvdata(pdev);
+ dhd_bus_t *bus = NULL;
+
+ if (pch) {
+ bus = pch->bus;
+ }
+
+#ifdef DHD_PCIE_RUNTIMEPM
+ if (bus && !bus->dhd->dongle_reset) {
+ /* 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 && (bus->dhd->busstate == DHD_BUS_DOWN) &&
+ !bus->dhd->dongle_reset) {
+ ret = dhdpcie_pci_suspend_resume(bus, state);
+#ifdef DHD_PCIE_RUNTIMEPM
+ mutex_unlock(&bus->pm_lock);
+#endif /* DHD_PCIE_RUNTIMEPM */
+ return ret;
+ }
+
+ if (bus && ((bus->dhd->busstate == DHD_BUS_SUSPEND)||
+ (bus->dhd->busstate == DHD_BUS_DATA)) &&
+ (bus->suspended != state)) {
+ ret = dhdpcie_bus_suspend(bus, state);
+ }
+
+#ifdef DHD_PCIE_RUNTIMEPM
+ if (bus && !bus->dhd->dongle_reset) {
+ mutex_unlock(&bus->pm_lock);
+ }
+#endif /* DHD_PCIE_RUNTIMEPM */
+ return ret;
+}
+
+extern void dhd_dpc_tasklet_kill(dhd_pub_t *dhdp);
+
+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__));
+ disable_irq(dev->irq);
+ dhd_dpc_tasklet_kill(bus->dhd);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
+ bus->pci_d3hot_done = 1;
+#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 (pci_is_enabled(dev)) {
+ 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));
+ }
+ return ret;
+}
+
+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);
+ dhd_bus_t *bus = pch->bus;
+ 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__));
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0))
+ bus->pci_d3hot_done = 0;
+#endif /* OEM_ANDROID && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */
+ 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:
+ enable_irq(dev->irq);
+ 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 */
+ if (bcmerror < 0) {
+ DHD_ERROR(("%s: PCIe RC resume failed!!! (%d)\n",
+ __FUNCTION__, bcmerror));
+ bus->is_linkdown = 1;
+#ifdef CONFIG_ARCH_MSM
+ bus->no_cfg_restore = 1;
+#endif /* CONFIG_ARCH_MSM */
+ }
+
+ return bcmerror;
+}
+
+static int dhdpcie_suspend_host_dev(dhd_bus_t *bus)
+{
+ int bcmerror = 0;
+#ifdef USE_EXYNOS_PCIE_RC_PMPATCH
+ struct pci_dev *rc_pci_dev;
+ rc_pci_dev = pci_get_device(0x144d, SAMSUNG_PCIE_DEVICE_ID, NULL);
+ if (rc_pci_dev) {
+ pci_save_state(rc_pci_dev);
+ }
+ 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 */
+ return bcmerror;
+}
+
+int dhdpcie_pci_suspend_resume(dhd_bus_t *bus, bool state)
+{
+ int rc;
+
+ struct pci_dev *dev = bus->dev;
+
+ if (state) {
+ if (bus->is_linkdown) {
+ DHD_ERROR(("%s: PCIe link was down\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+#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 (bus->is_linkdown) {
+ 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;
+
+ pcidev = container_of(dev, struct pci_dev, dev);
+ 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)
+{
+#ifndef MULTI_CHIP_SUPPORT
+ /* Don't enumerate more than one device */
+ if (dhdpcie_init_succeeded) {
+ DHD_TRACE(("%s: PCIe Enumeration is already done.\n",
+ __func__));
+ return -ENODEV;
+ }
+#endif /* MULTI_CHIP_SUPPORT */
+
+ if (dhdpcie_chipmatch (pdev->vendor, pdev->device)) {
+ DHD_ERROR(("%s: chipmatch failed!!\n", __FUNCTION__));
+ return -ENODEV;
+ }
+ 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__));
+ return -ENODEV;
+ }
+
+#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__));
+ return 0;
+}
+
+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__));
+ 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 */
+ dhdpcie_bus_release(bus);
+ 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 */
+ /* pcie info detach */
+ dhdpcie_detach(pch);
+ /* osl detach */
+ osl_detach(osh);
+
+ dhdpcie_init_succeeded = FALSE;
+
+ 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;
+
+ if (!bus->irq_registered) {
+ snprintf(dhdpcie_info->pciname, sizeof(dhdpcie_info->pciname),
+ "dhdpcie:%s", pci_name(pdev));
+#ifndef PCIE_INTX_SUPPORT
+ pci_enable_msi(pdev);
+#endif /* !PCIE_INTX_SUPPORT */
+ if (request_irq(pdev->irq, dhdpcie_isr, IRQF_SHARED,
+ dhdpcie_info->pciname, bus) < 0) {
+ DHD_ERROR(("%s: request_irq() failed\n", __FUNCTION__));
+ return -1;
+ } else {
+ bus->irq_registered = TRUE;
+ }
+ } else {
+ DHD_ERROR(("%s: PCI IRQ is already registered\n", __FUNCTION__));
+ }
+
+ DHD_TRACE(("%s %s\n", __FUNCTION__, dhdpcie_info->pciname));
+
+
+ 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;
+ 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 = (volatile char *) REG_MAP(bar1_addr, DONGLE_TCM_MAP_SIZE);
+ dhdpcie_info->tcm_size = DONGLE_TCM_MAP_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) */
+
+ 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))
+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) */
+#endif /* EXYNOS_PCIE_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 */
+
+ 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));
+ 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 */
+
+ /* 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;
+ bus->pci_d3hot_done = 0;
+#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
+#ifdef CONFIG_SOC_EXYNOS8890
+ 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 */
+#endif /* EXYNOS_PCIE_LINKDOWN_RECOVERY */
+#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;
+
+ 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 */
+
+ 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) {
+ return;
+ }
+
+ if (bus->irq_registered) {
+ pdev = bus->dev;
+ free_irq(pdev->irq, bus);
+#ifndef PCIE_INTX_SUPPORT
+ pci_disable_msi(pdev);
+#endif /* !PCIE_INTX_SUPPORT */
+ bus->irq_registered = FALSE;
+ } 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_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
+ 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)) && !defined(CONFIG_SOC_EXYNOS8890)
+ /* Updated with pci_load_and_free_saved_state to compatible
+ * with kernel 3.14 or higher
+ */
+ 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_CODE >= KERNEL_VERSION(3, 14, 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 = (volatile char *) REG_MAP(bar1_addr, DONGLE_TCM_MAP_SIZE);
+ dhdpcie_info->tcm_size = DONGLE_TCM_MAP_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_PCIE_RUNTIMEPM
+ dhdpcie_runtime_bus_wake(bus->dhd, FALSE, wlan_oob_irq);
+#endif /* DHD_PCIE_RUNTIMPM */
+ if (bus->dhd->up && bus->suspended) {
+ 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) {
+ DHD_INFO_HW4(("%s OOB irq=%d flags=%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;
+ }
+ err = enable_irq_wake(dhdpcie_osinfo->oob_irq_num);
+ if (!err) {
+ dhdpcie_osinfo->oob_irq_wake_enabled = TRUE;
+ }
+ 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 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);
+ if (bus->suspended == TRUE) {
+ DHD_GENERAL_UNLOCK(dhd, flags);
+ DHD_INFO(("Bus is already suspended system PM: %d\n", bus->suspended));
+ return FALSE;
+ }
+
+ bus->idlecount++;
+
+ DHD_TRACE(("%s : Enter \n", __FUNCTION__));
+ if ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) {
+ bus->idlecount = 0;
+ if (dhd->dhd_bus_busy_state == 0 && dhd->busstate != DHD_BUS_DOWN &&
+ dhd->busstate != DHD_BUS_DOWN_IN_PROGRESS) {
+ bus->bus_wake = 0;
+ dhd->dhd_bus_busy_state |= DHD_BUS_BUSY_RPM_SUSPEND_IN_PROGRESS;
+ 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->dev, TRUE)) {
+ DHD_ERROR(("%s: exit with wakelock \n", __FUNCTION__));
+ DHD_GENERAL_LOCK(dhd, flags);
+ dhd->dhd_bus_busy_state &= ~DHD_BUS_BUSY_RPM_SUSPEND_IN_PROGRESS;
+ 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->dhd_bus_busy_state &= ~DHD_BUS_BUSY_RPM_SUSPEND_IN_PROGRESS;
+ dhd->dhd_bus_busy_state |= DHD_BUS_BUSY_RPM_SUSPEND_DONE;
+ /* 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->dhd_bus_busy_state &= ~DHD_BUS_BUSY_RPM_SUSPEND_DONE;
+ dhd->dhd_bus_busy_state |= DHD_BUS_BUSY_RPM_RESUME_IN_PROGRESS;
+ DHD_GENERAL_UNLOCK(dhd, flags);
+
+ dhdpcie_set_suspend_resume(bus->dev, FALSE);
+
+ DHD_GENERAL_LOCK(dhd, flags);
+ dhd->dhd_bus_busy_state &= ~DHD_BUS_BUSY_RPM_RESUME_IN_PROGRESS;
+ /* 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 (bus->dhd->dhd_bus_busy_state & DHD_BUS_BUSY_RPM_ALL) {
+ /* Wake up RPM state thread if it is suspend in progress or suspended */
+ if (bus->dhd->dhd_bus_busy_state & DHD_BUS_BUSY_RPM_SUSPEND_IN_PROGRESS ||
+ bus->dhd->dhd_bus_busy_state & DHD_BUS_BUSY_RPM_SUSPEND_DONE) {
+ 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 (bus->dhd->dhd_bus_busy_state & DHD_BUS_BUSY_RPM_RESUME_IN_PROGRESS) {
+ 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 */
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_pno.c b/drivers/net/wireless/bcmdhd_1363/dhd_pno.c
new file mode 100644
index 000000000000..a3c518769b2f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_pno.c
@@ -0,0 +1,3892 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_pno.c 664799 2017-04-24 09:48:40Z $
+ */
+
+#if defined(GSCAN_SUPPORT) && !defined(PNO_SUPPORT)
+#error "GSCAN needs PNO to be enabled!"
+#endif
+
+#ifdef PNO_SUPPORT
+#include <typedefs.h>
+#include <osl.h>
+
+#include <epivers.h>
+#include <bcmutils.h>
+
+#include <bcmendian.h>
+#include <linuxver.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/sort.h>
+#include <dngl_stats.h>
+#include <wlioctl.h>
+
+#include <proto/bcmevent.h>
+#include <dhd.h>
+#include <dhd_pno.h>
+#include <dhd_dbg.h>
+#ifdef GSCAN_SUPPORT
+#include <linux/gcd.h>
+#endif /* GSCAN_SUPPORT */
+
+#ifdef __BIG_ENDIAN
+#include <bcmendian.h>
+#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
+static wlc_ssid_ext_t * dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd,
+ dhd_pno_status_info_t *pno_state);
+#ifdef GSCAN_SUPPORT
+static wl_pfn_gscan_channel_bucket_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 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), 1);
+ 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, 1);
+ 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);
+}
+
+int
+dhd_pno_set_mac_oui(dhd_pub_t *dhd, uint8 *oui)
+{
+ int err = BCME_OK;
+ dhd_pno_status_info_t *_pno_state;
+
+ if (!dhd || !dhd->pno_state) {
+ DHD_ERROR(("NULL POINTER : %s\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+ _pno_state = PNO_GET_PNOSTATE(dhd);
+ if (ETHER_ISMULTI(oui)) {
+ DHD_ERROR(("Expected unicast OUI\n"));
+ err = BCME_ERROR;
+ } else {
+ memcpy(_pno_state->pno_oui, oui, DOT11_OUI_LEN);
+ DHD_PNO(("PNO mac oui to be used - %02x:%02x:%02x\n", _pno_state->pno_oui[0],
+ _pno_state->pno_oui[1], _pno_state->pno_oui[2]));
+ }
+
+ return err;
+}
+
+#ifdef GSCAN_SUPPORT
+static uint64
+convert_fw_rel_time_to_systime(uint32 fw_ts_ms)
+{
+ struct timespec ts;
+
+ get_monotonic_boottime(&ts);
+ return ((uint64)(TIMESPEC_TO_US(ts)) - (uint64)(fw_ts_ms * 1000));
+}
+
+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, 1);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to execute pfncfg_gscan_param\n", __FUNCTION__));
+ goto exit;
+ }
+exit:
+ return err;
+}
+
+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_set_mac_addr(dhd_pub_t *dhd, struct ether_addr *macaddr)
+{
+ int err;
+ wl_pfn_macaddr_cfg_t cfg;
+
+ cfg.version = WL_PFN_MACADDR_CFG_VER;
+ if (ETHER_ISNULLADDR(macaddr)) {
+ cfg.flags = 0;
+ } else {
+ cfg.flags = (WL_PFN_MAC_OUI_ONLY_MASK | WL_PFN_SET_MAC_UNASSOC_MASK);
+ }
+ memcpy(&cfg.macaddr, macaddr, ETHER_ADDR_LEN);
+
+ err = dhd_iovar(dhd, 0, "pfn_macaddr", (char *)&cfg, sizeof(cfg), 1);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to execute pfn_macaddr\n", __FUNCTION__));
+ }
+
+ return err;
+}
+
+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), 1);
+ 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), 1);
+ 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;
+ struct ether_addr macaddr;
+ 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);
+ /* ADAPTIVE turned off */
+ pfn_param.flags &= ~(htod16(ENABLE << ENABLE_ADAPTSCAN_BIT));
+ pfn_param.repeat = 0;
+ pfn_param.exp = 0;
+ pfn_param.slow_freq = 0;
+
+ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
+ dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd);
+ dhd_pno_params_t *_params;
+
+ _params = &(_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS]);
+
+ pfn_param.scan_freq = htod32(MIN(pno_params->params_gscan.scan_fr,
+ _params->params_legacy.scan_fr));
+ }
+
+ 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;
+ }
+ }
+
+ memset(&macaddr, 0, ETHER_ADDR_LEN);
+ memcpy(&macaddr, _pno_state->pno_oui, DOT11_OUI_LEN);
+
+ DHD_PNO(("Setting mac oui to FW - %02x:%02x:%02x\n", _pno_state->pno_oui[0],
+ _pno_state->pno_oui[1], _pno_state->pno_oui[2]));
+ err = dhd_pno_set_mac_addr(dhd, &macaddr);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to set pno mac address, error - %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), 1);
+ 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", (char *)&_tmp, sizeof(_tmp), 0);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to get pfnmem\n", __FUNCTION__));
+ goto exit;
+ }
+ DHD_PNO((" returned mscan : %d, set bestn : %d\n", _tmp, pfn_param.bestn));
+ pfn_param.mscan = MIN(pfn_param.mscan, _tmp);
+ }
+ err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), 1);
+ 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, wlc_ssid_ext_t* ssids_list, int nssid)
+{
+ int err = BCME_OK;
+ int i = 0;
+ wl_pfn_t pfn_element;
+ NULL_CHECK(dhd, "dhd is NULL", err);
+ if (nssid) {
+ NULL_CHECK(ssids_list, "ssid list is NULL", err);
+ }
+ memset(&pfn_element, 0, sizeof(pfn_element));
+ {
+ int j;
+ for (j = 0; j < nssid; j++) {
+ DHD_PNO(("%d: scan for %s size = %d hidden = %d\n", j,
+ ssids_list[j].SSID, ssids_list[j].SSID_len, ssids_list[j].hidden));
+ }
+ }
+ /* Check for broadcast ssid */
+ for (i = 0; i < nssid; i++) {
+ if (!ssids_list[i].SSID_len) {
+ DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", i));
+ err = BCME_ERROR;
+ goto exit;
+ }
+ }
+ /* set all pfn ssid */
+ for (i = 0; i < nssid; i++) {
+ pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE);
+ pfn_element.auth = (DOT11_OPEN_SYSTEM);
+ pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY);
+ pfn_element.wsec = htod32(0);
+ pfn_element.infra = htod32(1);
+ if (ssids_list[i].hidden) {
+ pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT);
+ } else {
+ pfn_element.flags = 0;
+ }
+ memcpy((char *)pfn_element.ssid.SSID, ssids_list[i].SSID,
+ ssids_list[i].SSID_len);
+ pfn_element.ssid.SSID_len = ssids_list[i].SSID_len;
+ err = dhd_iovar(dhd, 0, "pfn_add", (char *)&pfn_element,
+ sizeof(pfn_element), 1);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to execute pfn_add\n", __FUNCTION__));
+ goto exit;
+ }
+ }
+exit:
+ return err;
+}
+/* qsort compare function */
+static int
+_dhd_pno_cmpfunc(const void *a, const void *b)
+{
+ return (*(uint16*)a - *(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);
+ }
+ 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 = sprintf(bp, "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 */
+ list_for_each_entry_safe(siter, snext,
+ &params_batch->get_batch.expired_scan_results_list, list) {
+ 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<loop : %d, apcount %d>\n", cnt - 1, phead->tot_cnt));
+ /* attribute of the scan */
+ if (phead->reason & PNO_STATUS_ABORT_MASK) {
+ bp += nreadsize = sprintf(bp, "trunc\n");
+ nleftsize -= nreadsize;
+ }
+ list_for_each_entry_safe(iter, next,
+ &phead->entry_list, list) {
+ 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 = sprintf(bp, "bssid=%s\n",
+ bcm_ether_ntoa((const struct ether_addr *)&iter->BSSID, eabuf));
+ nleftsize -= nreadsize;
+ /* SSID */
+ bp += nreadsize = sprintf(bp, "ssid=%s\n", iter->SSID);
+ nleftsize -= nreadsize;
+ /* channel */
+ bp += nreadsize = sprintf(bp, "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 = sprintf(bp, "level=%d\n", iter->RSSI);
+ nleftsize -= nreadsize;
+ /* add the time consumed in Driver to the timestamp of firmware */
+ iter->timestamp += t_delta;
+ bp += nreadsize = sprintf(bp, "age=%d\n", iter->timestamp);
+ nleftsize -= nreadsize;
+ /* RTT0 */
+ bp += nreadsize = sprintf(bp, "dist=%d\n",
+ (iter->rtt0 == 0)? -1 : iter->rtt0);
+ nleftsize -= nreadsize;
+ /* RTT1 */
+ bp += nreadsize = sprintf(bp, "distSd=%d\n",
+ (iter->rtt0 == 0)? -1 : iter->rtt1);
+ nleftsize -= nreadsize;
+ bp += nreadsize = sprintf(bp, "%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 = sprintf(bp, "%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 (list_empty(&params_batch->get_batch.expired_scan_results_list)) {
+ params_batch->get_batch.batch_started = FALSE;
+ bp += sprintf(bp, "%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__));
+ 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);
+ }
+ }
+ 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);
+ }
+ 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 && nchan < WL_NUMCHANNELS; 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), 1);
+ 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) {
+ list_for_each_entry_safe(iter, next,
+ &params->params_legacy.ssid_list, list) {
+ list_del(&iter->list);
+ kfree(iter);
+ }
+ }
+ 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,
+ &params->params_batch.get_batch.scan_results_list, FALSE);
+ _dhd_pno_clear_all_batch_results(dhd,
+ &params->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(&params->params_batch.get_batch.scan_results_list);
+ INIT_LIST_HEAD(&params->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) {
+ list_for_each_entry_safe(iter, next,
+ &params->params_hotlist.bssid_list, list) {
+ list_del(&iter->list);
+ kfree(iter);
+ }
+ }
+ 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, 1);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to execute pfn_cfg\n", __FUNCTION__));
+ goto exit;
+ }
+exit:
+ return err;
+}
+
+#ifdef GSCAN_SUPPORT
+static int
+_dhd_pno_add_significant_bssid(dhd_pub_t *dhd,
+ wl_pfn_significant_bssid_t *p_pfn_significant_bssid, int nbssid)
+{
+ int err = BCME_OK;
+ NULL_CHECK(dhd, "dhd is NULL", err);
+
+ if (!nbssid) {
+ err = BCME_ERROR;
+ goto exit;
+ }
+
+ NULL_CHECK(p_pfn_significant_bssid, "bssid list is NULL", err);
+
+ err = dhd_iovar(dhd, 0, "pfn_add_swc_bssid", (char *)p_pfn_significant_bssid,
+ sizeof(wl_pfn_significant_bssid_t) * nbssid, 1);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to execute pfn_significant_bssid %d\n", __FUNCTION__, err));
+ goto exit;
+ }
+exit:
+ return err;
+}
+#endif /* GSCAN_SUPPORT */
+
+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)
+ 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 previous pno_mode */
+ _pno_state->pno_mode = mode;
+ /* 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;
+ dhd_pno_clean(dhd);
+ /* 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 */
+ 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++;
+ }
+ 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 wlc_ssid_ext_t *
+dhd_pno_get_legacy_pno_ssid(dhd_pub_t *dhd, dhd_pno_status_info_t *pno_state)
+{
+ int i;
+ struct dhd_pno_ssid *iter, *next;
+ dhd_pno_params_t *_params1 = &pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS];
+ wlc_ssid_ext_t *p_ssid_list;
+
+ p_ssid_list = kzalloc(sizeof(wlc_ssid_ext_t) *
+ _params1->params_legacy.nssid, GFP_KERNEL);
+ if (p_ssid_list == NULL) {
+ DHD_ERROR(("%s : failed to allocate wlc_ssid_ext_t array (count: %d)",
+ __FUNCTION__, _params1->params_legacy.nssid));
+ pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE;
+ goto exit;
+ }
+ i = 0;
+ /* convert dhd_pno_ssid to wlc_ssid_ext_t */
+ list_for_each_entry_safe(iter, next, &_params1->params_legacy.ssid_list, list) {
+ p_ssid_list[i].SSID_len = iter->SSID_len;
+ p_ssid_list[i].hidden = iter->hidden;
+ memcpy(p_ssid_list[i].SSID, iter->SSID, p_ssid_list[i].SSID_len);
+ i++;
+ }
+exit:
+ return p_ssid_list;
+}
+
+static int
+dhd_pno_add_to_ssid_list(dhd_pno_params_t *params, wlc_ssid_ext_t *ssid_list,
+ int nssid)
+{
+ int ret = 0;
+ 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;
+ }
+ _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;
+ memcpy(_pno_ssid->SSID, ssid_list[i].SSID, _pno_ssid->SSID_len);
+ list_add_tail(&_pno_ssid->list, &params->params_legacy.ssid_list);
+ }
+
+exit:
+ 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_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;
+ int mode = 0;
+ NULL_CHECK(dhd, "dhd is NULL", err);
+ NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
+ _pno_state = PNO_GET_PNOSTATE(dhd);
+
+ if (!dhd_support_sta_mode(dhd)) {
+ err = BCME_BADOPTION;
+ goto exit_no_clear;
+ }
+ DHD_PNO(("%s enter : scan_fr :%d, pno_repeat :%d,"
+ "pno_freq_expo_max: %d, nchan :%d\n", __FUNCTION__,
+ scan_fr, pno_repeat, pno_freq_expo_max, nchan));
+
+ _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));
+ goto exit_no_clear;
+ }
+ }
+ _pno_state->pno_mode |= DHD_PNO_LEGACY_MODE;
+ 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));
+ goto exit_no_clear;
+ }
+ 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), TRUE);
+ 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_no_clear;
+ }
+ /* 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_no_clear;
+ }
+ } 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_no_clear;
+ }
+ }
+ }
+ }
+ _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;
+ _params->params_legacy.nssid = nssid;
+ INIT_LIST_HEAD(&_params->params_legacy.ssid_list);
+#ifdef GSCAN_SUPPORT
+ /* dhd_pno_initiate_gscan_request will handle simultaneous Legacy PNO and GSCAN */
+ if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) {
+ if (dhd_pno_add_to_ssid_list(_params, ssid_list, nssid) < 0) {
+ err = BCME_ERROR;
+ 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 (dhd_pno_add_to_ssid_list(_params, ssid_list, nssid) < 0) {
+ err = BCME_ERROR;
+ 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);
+ }
+exit_no_clear:
+ /* 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;
+ wlc_ssid_ext_t *p_ssid_list = NULL;
+ 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"));
+ }
+ p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state);
+ if (!p_ssid_list) {
+ err = BCME_NOMEM;
+ DHD_ERROR(("failed to get Legacy PNO SSID list\n"));
+ goto exit;
+ }
+ if ((err = _dhd_pno_add_ssid(dhd, p_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;
+ }
+ if (p_ssid_list)
+ kfree(p_ssid_list);
+ return err;
+}
+
+
+#ifdef GSCAN_SUPPORT
+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) {
+ list_for_each_entry_safe(iter, next,
+ &_params->params_gscan.hotlist_bssid_list, list) {
+ list_del(&iter->list);
+ kfree(iter);
+ }
+ }
+ _params->params_gscan.nbssid_hotlist = 0;
+ DHD_PNO(("Flush Hotlist Config\n"));
+ }
+ if (flags & GSCAN_FLUSH_SIGNIFICANT_CFG) {
+ dhd_pno_significant_bssid_t *iter, *next;
+
+ if (_params->params_gscan.nbssid_significant_change > 0) {
+ list_for_each_entry_safe(iter, next,
+ &_params->params_gscan.significant_bssid_list, list) {
+ list_del(&iter->list);
+ kfree(iter);
+ }
+ }
+ _params->params_gscan.nbssid_significant_change = 0;
+ DHD_PNO(("Flush Significant Change Config\n"));
+ }
+
+ return;
+}
+
+void
+dhd_pno_lock_batch_results(dhd_pub_t *dhd)
+{
+ dhd_pno_status_info_t *_pno_state;
+ _pno_state = PNO_GET_PNOSTATE(dhd);
+ mutex_lock(&_pno_state->pno_mutex);
+ return;
+}
+
+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;
+}
+
+void
+dhd_wait_batch_results_complete(dhd_pub_t *dhd)
+{
+ dhd_pno_status_info_t *_pno_state;
+ dhd_pno_params_t *_params;
+
+ _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;
+ int err;
+
+ 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 (!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;
+}
+
+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;
+}
+
+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;
+
+ if (!len) {
+ DHD_ERROR(("%s: len is NULL\n", __FUNCTION__));
+ return ret;
+ }
+
+ 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 = 12;
+ ptr->max_scan_buckets = GSCAN_MAX_CH_BUCKETS;
+ ptr->max_ap_cache_per_scan = 16;
+ ptr->max_rssi_sample_size = PFN_SWC_RSSI_WINDOW_MAX;
+ ptr->max_scan_reporting_threshold = 100;
+ ptr->max_hotlist_aps = PFN_HOTLIST_MAX_NUM_APS;
+ ptr->max_significant_wifi_change_aps = PFN_SWC_MAX_NUM_APS;
+ ret = (void *)ptr;
+ *len = sizeof(dhd_pno_gscan_capabilities_t);
+ break;
+
+ case DHD_PNO_GET_BATCH_RESULTS:
+ ret = dhd_get_gscan_batch_results(dhd, len);
+ break;
+ case DHD_PNO_GET_CHANNEL_LIST:
+ if (info) {
+ uint16 ch_list[WL_NUMCHANNELS];
+ uint32 *ptr, 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;
+ ptr = (uint32 *) kmalloc(mem_needed, GFP_KERNEL);
+ if (!ptr) {
+ DHD_ERROR(("%s: Unable to malloc %d bytes\n",
+ __FUNCTION__, mem_needed));
+ break;
+ }
+ for (i = 0; i < nchan; i++) {
+ ptr[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 = ptr;
+ *len = mem_needed;
+ }
+ } else {
+ *len = 0;
+ DHD_ERROR(("%s: info buffer is NULL\n", __FUNCTION__));
+ }
+ break;
+
+ default:
+ DHD_ERROR(("%s: Unrecognized cmd type - %d\n", __FUNCTION__, type));
+ break;
+ }
+
+ return ret;
+
+}
+
+int
+dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type,
+ void *buf, uint8 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);
+
+ 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);
+ }
+ if ((_params->params_gscan.nbssid_hotlist +
+ ptr->nbssid) > PFN_SWC_MAX_NUM_APS) {
+ DHD_ERROR(("Excessive number of hotlist APs programmed %d\n",
+ (_params->params_gscan.nbssid_hotlist +
+ ptr->nbssid)));
+ err = BCME_RANGE;
+ goto exit;
+ }
+
+ 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_SIGNIFICANT_SCAN_CFG_ID:
+ {
+ gscan_swc_params_t *ptr = (gscan_swc_params_t *)buf;
+ dhd_pno_significant_bssid_t *_pno_significant_change_bssid;
+ wl_pfn_significant_bssid_t *significant_bssid_ptr;
+
+ if (flush) {
+ dhd_pno_reset_cfg_gscan(_params, _pno_state,
+ GSCAN_FLUSH_SIGNIFICANT_CFG);
+ }
+
+ if (!ptr->nbssid) {
+ break;
+ }
+ if (!_params->params_gscan.nbssid_significant_change) {
+ INIT_LIST_HEAD(&_params->params_gscan.significant_bssid_list);
+ }
+ if ((_params->params_gscan.nbssid_significant_change +
+ ptr->nbssid) > PFN_SWC_MAX_NUM_APS) {
+ DHD_ERROR(("Excessive number of SWC APs programmed %d\n",
+ (_params->params_gscan.nbssid_significant_change +
+ ptr->nbssid)));
+ err = BCME_RANGE;
+ goto exit;
+ }
+
+ for (i = 0, significant_bssid_ptr = ptr->bssid_elem_list;
+ i < ptr->nbssid; i++, significant_bssid_ptr++) {
+ _pno_significant_change_bssid =
+ kzalloc(sizeof(dhd_pno_significant_bssid_t),
+ GFP_KERNEL);
+
+ if (!_pno_significant_change_bssid) {
+ DHD_ERROR(("SWC bssidptr is NULL, cannot kalloc %zd bytes",
+ sizeof(dhd_pno_significant_bssid_t)));
+ err = BCME_NOMEM;
+ goto exit;
+ }
+ memcpy(&_pno_significant_change_bssid->BSSID,
+ &significant_bssid_ptr->macaddr, ETHER_ADDR_LEN);
+ _pno_significant_change_bssid->rssi_low_threshold =
+ significant_bssid_ptr->rssi_low_threshold;
+ _pno_significant_change_bssid->rssi_high_threshold =
+ significant_bssid_ptr->rssi_high_threshold;
+ list_add_tail(&_pno_significant_change_bssid->list,
+ &_params->params_gscan.significant_bssid_list);
+ }
+
+ _params->params_gscan.swc_nbssid_threshold = ptr->swc_threshold;
+ _params->params_gscan.swc_rssi_window_size = ptr->rssi_window;
+ _params->params_gscan.lost_ap_window = ptr->lost_ap_window;
+ _params->params_gscan.nbssid_significant_change += ptr->nbssid;
+ break;
+ }
+ case DHD_PNO_SCAN_CFG_ID:
+ {
+ int i, k, valid = 0;
+ uint16 band, min;
+ 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));
+ min = ptr->channel_bucket[0].bucket_freq_multiple;
+ 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;
+ if (ptr->scan_fr ==
+ ptr->channel_bucket[i].bucket_freq_multiple) {
+ valid = 1;
+ }
+ if (ptr->channel_bucket[i].bucket_freq_multiple < min)
+ min = ptr->channel_bucket[i].bucket_freq_multiple;
+
+ DHD_PNO(("band %d report_flag %d\n", ch_bucket[i].band,
+ ch_bucket[i].report_flag));
+ }
+ if (!valid)
+ ptr->scan_fr = min;
+
+ for (i = 0; i < ptr->nchannel_buckets; i++) {
+ ch_bucket[i].bucket_freq_multiple =
+ ch_bucket[i].bucket_freq_multiple/ptr->scan_fr;
+ }
+ _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;
+ }
+ 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, k;
+ uint16 _chan_list[WL_NUMCHANNELS];
+ int tot_nchan = 0;
+ int num_buckets_to_fw, tot_num_buckets, gscan_param_size = 0;
+ dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd);
+ wl_pfn_gscan_channel_bucket_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;
+ wlc_ssid_ext_t *pssid_list = NULL;
+ dhd_pno_params_t *params_legacy;
+ dhd_pno_params_t *_params;
+
+ params_legacy = &_pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS];
+ _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;
+ }
+ /* Create channel list based on channel buckets */
+ if (!(ch_bucket = dhd_pno_gscan_create_channel_list(dhd, _pno_state,
+ _chan_list, &tot_num_buckets, &num_buckets_to_fw))) {
+ goto exit;
+ }
+
+ 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__));
+ goto exit;
+ }
+ /* restore the previous mode */
+ _pno_state->pno_mode = mode;
+ }
+
+ _pno_state->pno_mode |= DHD_PNO_GSCAN_MODE;
+
+ if (_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) {
+ pssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state);
+
+ if (!pssid_list) {
+ err = BCME_NOMEM;
+ DHD_ERROR(("failed to get Legacy PNO SSID list\n"));
+ goto exit;
+ }
+
+ if ((err = _dhd_pno_add_ssid(dhd, pssid_list,
+ params_legacy->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_channel_bucket_t);
+ pfn_gscan_cfg_t = (wl_pfn_gscan_cfg_t *) MALLOC(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;
+ }
+
+
+ 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;
+ }
+ if (gscan_params->nbssid_significant_change) {
+ pfn_gscan_cfg_t->swc_nbssid_threshold = gscan_params->swc_nbssid_threshold;
+ pfn_gscan_cfg_t->swc_rssi_window_size = gscan_params->swc_rssi_window_size;
+ pfn_gscan_cfg_t->lost_ap_window = gscan_params->lost_ap_window;
+ } else {
+ pfn_gscan_cfg_t->swc_nbssid_threshold = 0;
+ pfn_gscan_cfg_t->swc_rssi_window_size = 0;
+ pfn_gscan_cfg_t->lost_ap_window = 0;
+ }
+
+ pfn_gscan_cfg_t->flags =
+ (gscan_params->send_all_results_flag & GSCAN_SEND_ALL_RESULTS_MASK);
+ pfn_gscan_cfg_t->count_of_channel_buckets = num_buckets_to_fw;
+
+
+ for (i = 0, k = 0; i < tot_num_buckets; i++) {
+ if (ch_bucket[i].bucket_end_index != CHANNEL_BUCKET_EMPTY_INDEX) {
+ pfn_gscan_cfg_t->channel_bucket[k].bucket_end_index =
+ ch_bucket[i].bucket_end_index;
+ pfn_gscan_cfg_t->channel_bucket[k].bucket_freq_multiple =
+ ch_bucket[i].bucket_freq_multiple;
+ pfn_gscan_cfg_t->channel_bucket[k].report_flag =
+ ch_bucket[i].report_flag;
+ k++;
+ }
+ }
+
+ 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;
+ }
+ if (gscan_params->nbssid_significant_change) {
+ dhd_pno_significant_bssid_t *iter, *next;
+
+
+ p_pfn_significant_bssid = kzalloc(sizeof(wl_pfn_significant_bssid_t) *
+ gscan_params->nbssid_significant_change, GFP_KERNEL);
+ if (p_pfn_significant_bssid == NULL) {
+ DHD_ERROR(("%s : failed to allocate memory %zd\n",
+ __FUNCTION__,
+ sizeof(wl_pfn_significant_bssid_t) *
+ gscan_params->nbssid_significant_change));
+ err = BCME_NOMEM;
+ goto exit;
+ }
+ i = 0;
+ /* convert dhd_pno_significant_bssid_t to wl_pfn_significant_bssid_t */
+ list_for_each_entry_safe(iter, next, &gscan_params->significant_bssid_list, list) {
+ p_pfn_significant_bssid[i].rssi_low_threshold = iter->rssi_low_threshold;
+ p_pfn_significant_bssid[i].rssi_high_threshold = iter->rssi_high_threshold;
+ memcpy(&p_pfn_significant_bssid[i].macaddr, &iter->BSSID, ETHER_ADDR_LEN);
+ i++;
+ }
+ DHD_PNO(("nbssid_significant_change %d \n",
+ gscan_params->nbssid_significant_change));
+ err = _dhd_pno_add_significant_bssid(dhd, p_pfn_significant_bssid,
+ gscan_params->nbssid_significant_change);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to call _dhd_pno_add_significant_bssid(err :%d)\n",
+ __FUNCTION__, err));
+ goto exit;
+ }
+ }
+
+ 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));
+ list_for_each_entry_safe(iter, next,
+ &gscan_params->hotlist_bssid_list, list) {
+ memcpy(&ptr->macaddr,
+ &iter->macaddr, ETHER_ADDR_LEN);
+ ptr->flags = iter->flags;
+ ptr++;
+ }
+
+ 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(pssid_list);
+ 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_channel_bucket_t)));
+ }
+ return err;
+
+}
+
+
+static void
+dhd_pno_merge_gscan_pno_channels(dhd_pno_status_info_t *pno_state,
+ uint16 *chan_list,
+ uint8 *ch_scratch_pad,
+ wl_pfn_gscan_channel_bucket_t *ch_bucket,
+ uint32 *num_buckets_to_fw,
+ int num_channels)
+{
+ uint16 chan_buf[WL_NUMCHANNELS];
+ int i, j = 0, ch_bucket_idx = 0;
+ dhd_pno_params_t *_params = &pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
+ dhd_pno_params_t *_params1 = &pno_state->pno_params_arr[INDEX_OF_LEGACY_PARAMS];
+ uint16 *legacy_chan_list = _params1->params_legacy.chan_list;
+ bool is_legacy_scan_freq_higher;
+ uint8 report_flag = CH_BUCKET_REPORT_REGULAR;
+
+ if (!_params1->params_legacy.scan_fr)
+ _params1->params_legacy.scan_fr = PNO_SCAN_MIN_FW_SEC;
+
+ is_legacy_scan_freq_higher =
+ _params->params_gscan.scan_fr < _params1->params_legacy.scan_fr;
+
+ /* Calculate new Legacy scan multiple of base scan_freq
+ * The legacy PNO channel bucket is added at the end of the
+ * channel bucket list.
+ */
+ if (is_legacy_scan_freq_higher) {
+ ch_bucket[_params->params_gscan.nchannel_buckets].bucket_freq_multiple =
+ _params1->params_legacy.scan_fr/_params->params_gscan.scan_fr;
+
+ } else {
+ uint16 max = 0;
+
+ /* Calculate new multiple of base scan_freq for gscan buckets */
+ ch_bucket[_params->params_gscan.nchannel_buckets].bucket_freq_multiple = 1;
+ 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 /= _params1->params_legacy.scan_fr;
+ if (max < ch_bucket[i].bucket_freq_multiple)
+ max = ch_bucket[i].bucket_freq_multiple;
+ }
+ _params->params_gscan.max_ch_bucket_freq = max;
+ }
+
+ /* Off to remove duplicates!!
+ * Find channels that are already being serviced by gscan before legacy bucket
+ * These have to be removed from legacy bucket.
+ * !!Assuming chan_list channels are validated list of channels!!
+ * ch_scratch_pad is 1 at gscan bucket locations see dhd_pno_gscan_create_channel_list()
+ */
+ for (i = 0; i < _params1->params_legacy.nchan; i++)
+ ch_scratch_pad[legacy_chan_list[i]] += 2;
+
+ ch_bucket_idx = 0;
+ memcpy(chan_buf, chan_list, num_channels * sizeof(uint16));
+
+ /* Finally create channel list and bucket
+ * At this point ch_scratch_pad can have 4 values:
+ * 0 - Channel not present in either Gscan or Legacy PNO bucket
+ * 1 - Channel present only in Gscan bucket
+ * 2 - Channel present only in Legacy PNO bucket
+ * 3 - Channel present in both Gscan and Legacy PNO buckets
+ * Thus Gscan buckets can have values 1 or 3 and Legacy 2 or 3
+ * For channel buckets with scan_freq < legacy accept all
+ * channels i.e. ch_scratch_pad = 1 and 3
+ * else accept only ch_scratch_pad = 1 and mark rejects as
+ * ch_scratch_pad = 4 so that they go in legacy
+ */
+ for (i = 0; i < _params->params_gscan.nchannel_buckets; i++) {
+ if (ch_bucket[i].bucket_freq_multiple <=
+ ch_bucket[_params->params_gscan.nchannel_buckets].bucket_freq_multiple) {
+ for (; ch_bucket_idx <= ch_bucket[i].bucket_end_index; ch_bucket_idx++, j++)
+ chan_list[j] = chan_buf[ch_bucket_idx];
+
+ ch_bucket[i].bucket_end_index = j - 1;
+ } else {
+ num_channels = 0;
+ for (; ch_bucket_idx <= ch_bucket[i].bucket_end_index; ch_bucket_idx++) {
+ if (ch_scratch_pad[chan_buf[ch_bucket_idx]] == 1) {
+ chan_list[j] = chan_buf[ch_bucket_idx];
+ j++;
+ num_channels++;
+ } else {
+ ch_scratch_pad[chan_buf[ch_bucket_idx]] = 4;
+ /* If Gscan channel is merged off to legacy bucket and
+ * if the gscan channel bucket has a report flag > 0
+ * use the same for legacy
+ */
+ if (report_flag < ch_bucket[i].report_flag)
+ report_flag = ch_bucket[i].report_flag;
+ }
+ }
+
+ if (num_channels) {
+ ch_bucket[i].bucket_end_index = j - 1;
+ } else {
+ ch_bucket[i].bucket_end_index = CHANNEL_BUCKET_EMPTY_INDEX;
+ *num_buckets_to_fw = *num_buckets_to_fw - 1;
+ }
+ }
+
+ }
+
+ num_channels = 0;
+ ch_bucket[_params->params_gscan.nchannel_buckets].report_flag = report_flag;
+ /* Now add channels to the legacy scan bucket
+ * ch_scratch_pad = 0 to 4 at this point, for legacy -> 2,3,4. 2 means exclusively
+ * Legacy so add to bucket. 4 means it is a reject of gscan bucket and must
+ * be added to Legacy bucket,reject 3
+ */
+ for (i = 0; i < _params1->params_legacy.nchan; i++) {
+ if (ch_scratch_pad[legacy_chan_list[i]] != 3) {
+ chan_list[j] = legacy_chan_list[i];
+ j++;
+ num_channels++;
+ }
+ }
+ if (num_channels) {
+ ch_bucket[_params->params_gscan.nchannel_buckets].bucket_end_index = j - 1;
+ }
+ else {
+ ch_bucket[_params->params_gscan.nchannel_buckets].bucket_end_index =
+ CHANNEL_BUCKET_EMPTY_INDEX;
+ *num_buckets_to_fw = *num_buckets_to_fw - 1;
+ }
+
+ return;
+}
+static wl_pfn_gscan_channel_bucket_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;
+ uint16 *ptr = chan_list, max;
+ uint8 *ch_scratch_pad;
+ wl_pfn_gscan_channel_bucket_t *ch_bucket;
+ dhd_pno_params_t *_params = &_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS];
+ bool is_pno_legacy_running = _pno_state->pno_mode & DHD_PNO_LEGACY_MODE;
+ dhd_pno_gscan_channel_bucket_t *gscan_buckets = _params->params_gscan.channel_bucket;
+
+ 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 = *num_buckets;
+
+
+ ch_bucket = (wl_pfn_gscan_channel_bucket_t *) MALLOC(dhd->osh,
+ ((*num_buckets) * sizeof(wl_pfn_gscan_channel_bucket_t)));
+
+ if (!ch_bucket) {
+ DHD_ERROR(("%s: failed to malloc memory of size %zd\n",
+ __FUNCTION__, (*num_buckets) * sizeof(wl_pfn_gscan_channel_bucket_t)));
+ *num_buckets_to_fw = *num_buckets = 0;
+ return NULL;
+ }
+
+ max = gscan_buckets[0].bucket_freq_multiple;
+ num_channels = 0;
+ for (i = 0; i < _params->params_gscan.nchannel_buckets; i++) {
+ if (!gscan_buckets[i].band) {
+ num_channels += gscan_buckets[i].num_channels;
+ memcpy(ptr, gscan_buckets[i].chan_list,
+ gscan_buckets[i].num_channels * sizeof(uint16));
+ ptr = ptr + gscan_buckets[i].num_channels;
+ } 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_channel_bucket_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].report_flag = gscan_buckets[i].report_flag;
+ if (max < gscan_buckets[i].bucket_freq_multiple)
+ max = gscan_buckets[i].bucket_freq_multiple;
+ nchan = WL_NUMCHANNELS - num_channels;
+ DHD_PNO(("end_idx %d freq_mult - %d\n",
+ ch_bucket[i].bucket_end_index, ch_bucket[i].bucket_freq_multiple));
+ }
+
+ ch_scratch_pad = (uint8 *) kzalloc(CHANNEL_5G_MAX, GFP_KERNEL);
+ if (!ch_scratch_pad) {
+ DHD_ERROR(("%s: failed to malloc memory of size %d\n",
+ __FUNCTION__, CHANNEL_5G_MAX));
+ MFREE(dhd->osh, ch_bucket,
+ ((*num_buckets) * sizeof(wl_pfn_gscan_channel_bucket_t)));
+ *num_buckets_to_fw = *num_buckets = 0;
+ return NULL;
+ }
+
+ /* Need to look for duplicates in gscan buckets if the framework programmed
+ * the gscan buckets badly, for now return error if there are duplicates.
+ * Plus as an added bonus, we get all channels in Gscan bucket
+ * set to 1 for dhd_pno_merge_gscan_pno_channels()
+ */
+ for (i = 0; i < num_channels; i++) {
+ if (!ch_scratch_pad[chan_list[i]]) {
+ ch_scratch_pad[chan_list[i]] = 1;
+ } else {
+ DHD_ERROR(("%s: Duplicate channel - %d programmed in channel bucket\n",
+ __FUNCTION__, chan_list[i]));
+ MFREE(dhd->osh, ch_bucket, ((*num_buckets) *
+ sizeof(wl_pfn_gscan_channel_bucket_t)));
+ *num_buckets_to_fw = *num_buckets = 0;
+ kfree(ch_scratch_pad);
+ return NULL;
+ }
+ }
+ _params->params_gscan.max_ch_bucket_freq = max;
+ /* Legacy PNO maybe running, which means we need to create a legacy PNO bucket
+ * Plus need to remove duplicates as the legacy PNO chan_list may have common channels
+ * If channel is to be scanned more frequently as per gscan requirements
+ * remove from legacy PNO ch_bucket. Similarly, if legacy wants a channel scanned
+ * more often, it is removed from the Gscan channel bucket.
+ * In the end both are satisfied.
+ */
+ if (is_pno_legacy_running)
+ dhd_pno_merge_gscan_pno_channels(_pno_state, chan_list,
+ ch_scratch_pad, ch_bucket, num_buckets_to_fw, num_channels);
+
+ kfree(ch_scratch_pad);
+ return ch_bucket;
+}
+
+static int
+dhd_pno_stop_for_gscan(dhd_pub_t *dhd)
+{
+ int err = BCME_OK;
+ int mode;
+ wlc_ssid_ext_t *pssid_list = NULL;
+ 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;
+ }
+ 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;
+ pssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state);
+ if (!pssid_list) {
+ err = BCME_NOMEM;
+ DHD_ERROR(("failed to get Legacy PNO SSID list\n"));
+ goto exit;
+ }
+
+ DHD_PNO(("Restarting Legacy PNO SSID scan...\n"));
+ memcpy(chan_list, params_legacy->chan_list,
+ (params_legacy->nchan * sizeof(uint16)));
+ err = dhd_pno_set_for_ssid(dhd, pssid_list, params_legacy->nssid,
+ params_legacy->scan_fr, params_legacy->pno_repeat,
+ params_legacy->pno_freq_expo_max, chan_list,
+ params_legacy->nchan);
+ if (err < 0) {
+ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE;
+ DHD_ERROR(("%s : failed to restart legacy PNO scan(err: %d)\n",
+ __FUNCTION__, err));
+ goto exit;
+ }
+
+ }
+
+exit:
+ kfree(pssid_list);
+ 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 = &params->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 = &params->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.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;
+}
+
+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 = &params->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_t *plnetinfo;
+ struct dhd_pno_gscan_params *gscan_params;
+ wl_pfn_lscanresults_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, scan_id = 0;
+
+ 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;
+ }
+
+ gscan_params = &params->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_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN);
+
+ mutex_lock(&_pno_state->pno_mutex);
+ iter = gscan_params->gscan_batch_cache;
+ /* If a cache has not been consumed , just delete it */
+ while (iter) {
+ iter->tot_consumed = iter->tot_count;
+ iter = iter->next;
+ }
+ dhd_gscan_batch_cache_cleanup(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", (char *)plbestnet, PNO_BESTNET_LEN, 0);
+ if (err < 0) {
+ DHD_ERROR(("%s : Cannot get all the batch results, err :%d\n",
+ __FUNCTION__, err));
+ goto exit_mutex_unlock;
+ }
+ 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;
+ }
+
+ 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;
+ }
+ 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 *)
+ kzalloc(((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 = ++scan_id;
+ } else {
+ iter->scan_id = scan_id;
+ }
+ DHD_PNO(("scan_id %d tot_count %d\n", scan_id, nAPs_per_scan[i]));
+ iter->tot_count = nAPs_per_scan[i];
+ iter->tot_consumed = 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->ie_length = 0;
+ result->rtt = (uint64) plnetinfo->rtt0;
+ result->rtt_sd = (uint64) plnetinfo->rtt1;
+ result->ts = convert_fw_rel_time_to_systime(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.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);
+ }
+ if (plbestnet) {
+ MFREE(dhd->osh, plbestnet, PNO_BESTNET_LEN);
+ }
+ DHD_PNO(("Batch retrieval done!\n"));
+ return err;
+}
+#endif /* GSCAN_SUPPORT */
+
+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_t *plbestnet = NULL;
+ wl_pfn_lnet_info_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);
+ if (!dhd_support_sta_mode(dhd)) {
+ err = BCME_BADOPTION;
+ goto exit_no_unlock;
+ }
+ 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_no_unlock;
+ }
+#ifdef GSCAN_SUPPORT
+ if (!(_pno_state->pno_mode & (DHD_PNO_BATCH_MODE | DHD_PNO_GSCAN_MODE))) {
+#else
+ if (!(_pno_state->pno_mode & DHD_PNO_BATCH_MODE)) {
+#endif /* GSCAN_SUPPORT */
+ 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 */
+ 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);
+ }
+ _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_t *)MALLOC(dhd->osh, PNO_BESTNET_LEN);
+ NULL_CHECK(plbestnet, "failed to allocate buffer for bestnet", err);
+ 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", (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.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.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 */
+ 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);
+ }
+ /* 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(&_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__));
+ _pno_state = container_of(work, struct dhd_pno_status_info, work);
+ dhd = _pno_state->dhd;
+ if (dhd == NULL) {
+ DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__));
+ return;
+ }
+
+#ifdef GSCAN_SUPPORT
+ if (_pno_state->pno_mode & DHD_PNO_GSCAN_MODE) {
+ _dhd_pno_get_gscan_batch_from_fw(dhd);
+ return;
+ } else
+#endif /* GSCAN_SUPPORT */
+ {
+ 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 += sprintf(pbuf, "scancount=%d\n", 0);
+ sprintf(pbuf, "%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;
+ wlc_ssid_ext_t *p_ssid_list = 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;
+ dhd_pno_clean(dhd);
+ _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);
+ p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state);
+ if (!p_ssid_list) {
+ err = BCME_NOMEM;
+ DHD_ERROR(("failed to get Legacy PNO SSID list\n"));
+ goto exit;
+ }
+ err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid,
+ _params_legacy->scan_fr, _params_legacy->pno_repeat,
+ _params_legacy->pno_freq_expo_max, _params_legacy->chan_list,
+ _params_legacy->nchan);
+ if (err < 0) {
+ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE;
+ 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 */
+ 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++;
+ }
+ 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_ssid_list);
+ 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;
+ wlc_ssid_ext_t *p_ssid_list = NULL;
+ 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);
+ p_ssid_list = dhd_pno_get_legacy_pno_ssid(dhd, _pno_state);
+ if (!p_ssid_list) {
+ err = BCME_NOMEM;
+ DHD_ERROR(("failed to get Legacy PNO SSID list\n"));
+ goto exit;
+ }
+ err = dhd_pno_set_for_ssid(dhd, p_ssid_list, _params_legacy->nssid,
+ _params_legacy->scan_fr, _params_legacy->pno_repeat,
+ _params_legacy->pno_freq_expo_max, _params_legacy->chan_list,
+ _params_legacy->nchan);
+ if (err < 0) {
+ _pno_state->pno_mode &= ~DHD_PNO_LEGACY_MODE;
+ 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:
+ kfree(p_ssid_list);
+ 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;
+ _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;
+ 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;
+}
+
+/* Handle Significant WiFi Change (SWC) event from FW
+ * Send event to HAL when all results arrive from FW
+ */
+void *
+dhd_handle_swc_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes)
+{
+ void *ptr = NULL;
+ dhd_pno_status_info_t *_pno_state = PNO_GET_PNOSTATE(dhd);
+ struct dhd_pno_gscan_params *gscan_params;
+ struct dhd_pno_swc_evt_param *params;
+ wl_pfn_swc_results_t *results = (wl_pfn_swc_results_t *)event_data;
+ wl_pfn_significant_net_t *change_array;
+ int i;
+
+
+ gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan);
+ params = &(gscan_params->param_significant);
+
+ if (!results->total_count) {
+ *send_evt_bytes = 0;
+ return ptr;
+ }
+
+ if (!params->results_rxed_so_far) {
+ if (!params->change_array) {
+ params->change_array = (wl_pfn_significant_net_t *)
+ kmalloc(sizeof(wl_pfn_significant_net_t) * results->total_count,
+ GFP_KERNEL);
+
+ if (!params->change_array) {
+ DHD_ERROR(("%s Cannot Malloc %zd bytes!!\n", __FUNCTION__,
+ sizeof(wl_pfn_significant_net_t) * results->total_count));
+ *send_evt_bytes = 0;
+ return ptr;
+ }
+ } else {
+ DHD_ERROR(("RX'ed WLC_E_PFN_SWC evt from FW, previous evt not complete!!"));
+ *send_evt_bytes = 0;
+ return ptr;
+ }
+
+ }
+
+ DHD_PNO(("%s: pkt_count %d total_count %d\n", __FUNCTION__,
+ results->pkt_count, results->total_count));
+
+ for (i = 0; i < results->pkt_count; i++) {
+ DHD_PNO(("\t %02x:%02x:%02x:%02x:%02x:%02x\n",
+ results->list[i].BSSID.octet[0],
+ results->list[i].BSSID.octet[1],
+ results->list[i].BSSID.octet[2],
+ results->list[i].BSSID.octet[3],
+ results->list[i].BSSID.octet[4],
+ results->list[i].BSSID.octet[5]));
+ }
+
+ change_array = &params->change_array[params->results_rxed_so_far];
+ if ((params->results_rxed_so_far + results->pkt_count) <= results->total_count) {
+ memcpy(change_array, results->list,
+ sizeof(wl_pfn_significant_net_t) * results->pkt_count);
+ params->results_rxed_so_far += results->pkt_count;
+ } else {
+ /* In case of spurious event or invalid data send hang event */
+ dhd->hang_reason = HANG_REASON_INVALID_EVENT_OR_DATA;
+ dhd_os_send_hang_message(dhd);
+ }
+
+ if (params->results_rxed_so_far == results->total_count) {
+ params->results_rxed_so_far = 0;
+ *send_evt_bytes = sizeof(wl_pfn_significant_net_t) * results->total_count;
+ /* Pack up change buffer to send up and reset
+ * results_rxed_so_far, after its done.
+ */
+ ptr = (void *) params->change_array;
+ /* expecting the callee to free this mem chunk */
+ params->change_array = NULL;
+ }
+ else {
+ *send_evt_bytes = 0;
+ }
+
+ return ptr;
+}
+
+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, int *size)
+{
+ wl_bss_info_t *bi = NULL;
+ wl_gscan_result_t *gscan_result;
+ wifi_gscan_result_t *result = NULL;
+ u32 bi_length = 0;
+ uint8 channel;
+ uint32 mem_needed;
+
+ struct timespec ts;
+
+ *size = 0;
+
+ gscan_result = (wl_gscan_result_t *)data;
+
+ if (!gscan_result) {
+ DHD_ERROR(("Invalid gscan result (NULL pointer)\n"));
+ goto exit;
+ }
+ if (!gscan_result->bss_info) {
+ DHD_ERROR(("Invalid gscan bss info (NULL pointer)\n"));
+ 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;
+ }
+ if (bi->SSID_len > DOT11_MAX_SSID_LEN) {
+ DHD_ERROR(("Invalid SSID length %d: trimming it to max\n", bi->SSID_len));
+ bi->SSID_len = DOT11_MAX_SSID_LEN;
+ }
+
+ mem_needed = OFFSETOF(wifi_gscan_result_t, ie_data) + bi->ie_length;
+ result = kmalloc(mem_needed, GFP_KERNEL);
+
+ if (!result) {
+ DHD_ERROR(("%s Cannot malloc scan result buffer %d bytes\n",
+ __FUNCTION__, mem_needed));
+ goto exit;
+ }
+
+ memcpy(result->ssid, bi->SSID, bi->SSID_len);
+ result->ssid[bi->SSID_len] = '\0';
+ channel = wf_chspec_ctlchan(bi->chanspec);
+ result->channel = wf_channel2mhz(channel,
+ (channel <= CH_MAX_2G_CHANNEL?
+ WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G));
+ result->rssi = (int32) bi->RSSI;
+ result->rtt = 0;
+ result->rtt_sd = 0;
+ get_monotonic_boottime(&ts);
+ result->ts = (uint64) TIMESPEC_TO_US(ts);
+ result->beacon_period = dtoh16(bi->beacon_period);
+ result->capability = dtoh16(bi->capability);
+ result->ie_length = dtoh32(bi->ie_length);
+ memcpy(&result->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_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;
+ wl_pfn_scanresults_t *results = (wl_pfn_scanresults_t *)event_data;
+ wifi_gscan_result_t *hotlist_found_array;
+ wl_pfn_net_info_t *plnetinfo;
+ gscan_results_cache_t *gscan_hotlist_cache;
+ int malloc_size = 0, i, total = 0;
+
+ gscan_params = &(_pno_state->pno_params_arr[INDEX_OF_GSCAN_PARAMS].params_gscan);
+
+ if (!results->count) {
+ *send_evt_bytes = 0;
+ return ptr;
+ }
+
+ 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;
+ plnetinfo = results->netinfo;
+
+ for (i = 0; i < results->count; i++, plnetinfo++) {
+ hotlist_found_array = &gscan_hotlist_cache->results[i];
+ 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;
+ /* Info not available & not expected */
+ hotlist_found_array->beacon_period = 0;
+ hotlist_found_array->capability = 0;
+ hotlist_found_array->ie_length = 0;
+
+ hotlist_found_array->ts = convert_fw_rel_time_to_systime(plnetinfo->timestamp);
+ 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.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(&_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;
+ 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 */
+ err = dhd_iovar(dhd, 0, "pfnlbest", NULL, 0, 0);
+ 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:
+ 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/drivers/net/wireless/bcmdhd_1363/dhd_pno.h b/drivers/net/wireless/bcmdhd_1363/dhd_pno.h
new file mode 100644
index 000000000000..87164db5e3bc
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_pno.h
@@ -0,0 +1,498 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_pno.h 591285 2015-10-07 11:56: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
+
+#ifdef GSCAN_SUPPORT
+
+#define GSCAN_MAX_CH_BUCKETS 8
+#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_ALL_CFG (GSCAN_FLUSH_SCAN_CFG | \
+ GSCAN_FLUSH_SIGNIFICANT_CFG | \
+ GSCAN_FLUSH_HOTLIST_CFG)
+/* 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
+#endif /* GSCAN_SUPPORT */
+
+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
+ */
+#ifdef GSCAN_SUPPORT
+ INDEX_OF_GSCAN_PARAMS = INDEX_OF_HOTLIST_PARAMS,
+#endif /* GSCAN_SUPPORT */
+ 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;
+#ifdef GSCAN_SUPPORT
+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,
+ 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_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 */
+struct dhd_pno_ssid {
+ bool hidden;
+ uint32 SSID_len;
+ uchar SSID[DOT11_MAX_SSID_LEN];
+ struct list_head list;
+};
+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;
+};
+#ifdef GSCAN_SUPPORT
+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 chan_list[GSCAN_MAX_CH_BUCKETS];
+} dhd_pno_gscan_channel_bucket_t;
+
+typedef struct dhd_pno_swc_evt_param {
+ uint16 results_rxed_so_far;
+ wl_pfn_significant_net_t *change_array;
+} dhd_pno_swc_evt_param_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 ie_length; /* byte length of Information Elements */
+ char ie_data[1]; /* IE data to follow */
+} wifi_gscan_result_t;
+
+typedef struct gscan_results_cache {
+ struct gscan_results_cache *next;
+ uint8 scan_id;
+ uint8 flag;
+ uint8 tot_count;
+ uint8 tot_consumed;
+ 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;
+} dhd_pno_gscan_capabilities_t;
+
+struct dhd_pno_gscan_params {
+ int32 scan_fr;
+ uint8 bestn;
+ uint8 mscan;
+ uint8 buffer_threshold;
+ uint8 swc_nbssid_threshold;
+ uint8 swc_rssi_window_size;
+ 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_significant_change;
+ uint16 nbssid_hotlist;
+ struct dhd_pno_swc_evt_param param_significant;
+ struct dhd_pno_gscan_channel_bucket channel_bucket[GSCAN_MAX_CH_BUCKETS];
+ struct list_head hotlist_bssid_list;
+ struct list_head significant_bssid_list;
+};
+
+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;
+
+/* SWC (Significant WiFi Change) params */
+typedef struct gscan_swc_params {
+ /* Rssi averaging window size */
+ uint8 rssi_window;
+ /* Number of scans that the AP has to be absent before
+ * being declared LOST
+ */
+ uint8 lost_ap_window;
+ /* if x Aps have a significant change generate an event. */
+ uint8 swc_threshold;
+ uint8 nbssid;
+ wl_pfn_significant_bssid_t bssid_elem_list[1];
+} gscan_swc_params_t;
+
+typedef struct dhd_pno_significant_bssid {
+ struct ether_addr BSSID;
+ int8 rssi_low_threshold;
+ int8 rssi_high_threshold;
+ struct list_head list;
+} dhd_pno_significant_bssid_t;
+#endif /* GSCAN_SUPPORT */
+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;
+#ifdef GSCAN_SUPPORT
+ struct dhd_pno_gscan_params params_gscan;
+#endif /* GSCAN_SUPPORT */
+} dhd_pno_params_t;
+typedef struct dhd_pno_status_info {
+ uint8 pno_oui[DOT11_OUI_LEN];
+ 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 int dhd_dev_pno_set_mac_oui(struct net_device *dev, uint8 *oui);
+#ifdef GSCAN_SUPPORT
+extern int
+dhd_dev_pno_set_cfg_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type,
+ void *buf, uint8 flush);
+extern void *
+dhd_dev_pno_get_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, void *info,
+ uint32 *len);
+void 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);
+extern void * dhd_dev_swc_scan_event(struct net_device *dev, const void *data,
+ int *send_evt_bytes);
+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, 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 void dhd_dev_wait_batch_results_complete(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 int dhd_pno_set_mac_oui(dhd_pub_t *dhd, uint8 *oui);
+#ifdef GSCAN_SUPPORT
+extern int dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type,
+ void *buf, uint8 flush);
+extern void * dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *info,
+ uint32 *len);
+extern void 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_swc_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes);
+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,
+ 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 void dhd_wait_batch_results_complete(dhd_pub_t *dhd);
+#endif /* GSCAN_SUPPORT */
+#endif
+
+#endif /* __DHD_PNO_H__ */
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_proto.h b/drivers/net/wireless/bcmdhd_1363/dhd_proto.h
new file mode 100644
index 000000000000..c752477f95c5
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_proto.h
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_proto.h 604483 2015-12-07 14:47:36Z $
+ */
+
+#ifndef _dhd_proto_h_
+#define _dhd_proto_h_
+
+#include <dhdioctl.h>
+#include <wlioctl.h>
+#ifdef BCMPCIE
+#include <dhd_flowring.h>
+#endif
+
+#define DEFAULT_IOCTL_RESP_TIMEOUT 2000
+#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 4000
+#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 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);
+
+/* 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 int dhd_prot_process_ctrlbuf(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);
+
+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 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 */
+void dhd_prot_collect_memdump(dhd_pub_t *dhd);
+#endif /* BCMPCIE */
+/********************************
+ * 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/drivers/net/wireless/bcmdhd_1363/dhd_rtt.c b/drivers/net/wireless/bcmdhd_1363/dhd_rtt.c
new file mode 100644
index 000000000000..f51eee2f946e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_rtt.c
@@ -0,0 +1,729 @@
+/*
+ * 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: dhd_rtt.c 612549 2016-01-14 07:39:32Z $
+ */
+#ifdef RTT_SUPPORT
+#include <typedefs.h>
+#include <osl.h>
+
+#include <epivers.h>
+#include <bcmutils.h>
+
+#include <bcmendian.h>
+#include <linuxver.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/sort.h>
+#include <dngl_stats.h>
+#include <wlioctl.h>
+
+#include <proto/bcmevent.h>
+#include <dhd.h>
+#include <dhd_rtt.h>
+#include <dhd_dbg.h>
+#define GET_RTTSTATE(dhd) ((rtt_status_info_t *)dhd->rtt_state)
+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_TWO_SIDED(capability) \
+ do { \
+ if ((capability & RTT_CAP_ONE_WAY) == (uint8) (RTT_CAP_ONE_WAY)) \
+ return FALSE; \
+ else \
+ return TRUE; \
+ } while (0)
+#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \
+ (ts).tv_nsec / NSEC_PER_USEC)
+struct rtt_noti_callback {
+ struct list_head list;
+ void *ctx;
+ dhd_rtt_compl_noti_fn noti_fn;
+};
+
+typedef struct rtt_status_info {
+ dhd_pub_t *dhd;
+ int8 status; /* current status for the current entry */
+ int8 cur_idx; /* current entry to do RTT */
+ int32 capability; /* 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;
+
+static int dhd_rtt_start(dhd_pub_t *dhd);
+
+chanspec_t
+dhd_rtt_convert_to_chspec(wifi_channel_info_t channel)
+{
+ int bw;
+ /* 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;
+ break;
+ case WIFI_CHAN_WIDTH_40:
+ bw = WL_CHANSPEC_BW_40;
+ break;
+ case WIFI_CHAN_WIDTH_80:
+ bw = WL_CHANSPEC_BW_80;
+ break;
+ case WIFI_CHAN_WIDTH_160:
+ bw = WL_CHANSPEC_BW_160;
+ break;
+ default:
+ DHD_ERROR(("doesn't support this bandwith : %d", channel.width));
+ bw = -1;
+ break;
+ }
+ return wf_channel2chspec(wf_mhz2channel(channel.center_freq, 0), bw);
+}
+
+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 (rtt_status->capability == RTT_CAP_NONE) {
+ DHD_ERROR(("doesn't support RTT \n"));
+ return BCME_ERROR;
+ }
+ if (rtt_status->status == RTT_STARTED) {
+ DHD_ERROR(("rtt is already started\n"));
+ return BCME_BUSY;
+ }
+ DHD_RTT(("%s enter\n", __FUNCTION__));
+ bcopy(params, &rtt_status->rtt_config, sizeof(rtt_config_params_t));
+ rtt_status->status = RTT_STARTED;
+ /* start to measure RTT from 1th 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;
+ int i = 0, j = 0;
+ rtt_status_info_t *rtt_status;
+
+ 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;
+ }
+ }
+ }
+ mutex_unlock(&rtt_status->rtt_mutex);
+ return err;
+}
+
+static int
+dhd_rtt_start(dhd_pub_t *dhd)
+{
+ int err = BCME_OK;
+ int mpc = 0;
+ int nss, mcs, bw;
+ uint32 rspec = 0;
+ int8 eabuf[ETHER_ADDR_STR_LEN];
+ int8 chanbuf[CHANSPEC_STR_LEN];
+ bool set_mpc = FALSE;
+ wl_proxd_iovar_t proxd_iovar;
+ wl_proxd_params_iovar_t proxd_params;
+ wl_proxd_params_iovar_t proxd_tune;
+ wl_proxd_params_tof_method_t *tof_params = &proxd_params.u.tof_params;
+ rtt_status_info_t *rtt_status;
+ rtt_target_info_t *rtt_target;
+ NULL_CHECK(dhd, "dhd is NULL", err);
+
+ rtt_status = GET_RTTSTATE(dhd);
+ NULL_CHECK(rtt_status, "rtt_status is NULL", err);
+ /* turn off mpc in case of non-associted */
+ if (!dhd_is_associated(dhd, 0, NULL)) {
+ err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), 1);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to set proxd_tune\n", __FUNCTION__));
+ goto exit;
+ }
+ set_mpc = TRUE;
+ }
+
+ if (rtt_status->cur_idx >= rtt_status->rtt_config.rtt_target_cnt) {
+ err = BCME_RANGE;
+ goto exit;
+ }
+ DHD_RTT(("%s enter\n", __FUNCTION__));
+ bzero(&proxd_tune, sizeof(proxd_tune));
+ bzero(&proxd_params, sizeof(proxd_params));
+ 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);
+ /* set role */
+ proxd_iovar.method = PROXD_TOF_METHOD;
+ proxd_iovar.mode = WL_PROXD_MODE_INITIATOR;
+
+ /* make sure that proxd is stop */
+ /* dhd_iovar(dhd, 0, "proxd_stop", (char *)NULL, 0, 1); */
+
+ err = dhd_iovar(dhd, 0, "proxd", (char *)&proxd_iovar, sizeof(proxd_iovar), 1);
+ if (err < 0 && err != BCME_BUSY) {
+ DHD_ERROR(("%s : failed to set proxd %d\n", __FUNCTION__, err));
+ goto exit;
+ }
+ if (err == BCME_BUSY) {
+ DHD_RTT(("BCME_BUSY occurred\n"));
+ }
+ /* mac address */
+ bcopy(&rtt_target->addr, &tof_params->tgt_mac, ETHER_ADDR_LEN);
+ /* frame count */
+ if (rtt_target->ftm_cnt > RTT_MAX_FRAME_CNT) {
+ rtt_target->ftm_cnt = RTT_MAX_FRAME_CNT;
+ }
+
+ if (rtt_target->ftm_cnt) {
+ tof_params->ftm_cnt = htol16(rtt_target->ftm_cnt);
+ } else {
+ tof_params->ftm_cnt = htol16(DEFAULT_FTM_CNT);
+ }
+
+ if (rtt_target->retry_cnt > RTT_MAX_RETRY_CNT) {
+ rtt_target->retry_cnt = RTT_MAX_RETRY_CNT;
+ }
+
+ /* retry count */
+ if (rtt_target->retry_cnt) {
+ tof_params->retry_cnt = htol16(rtt_target->retry_cnt);
+ } else {
+ tof_params->retry_cnt = htol16(DEFAULT_RETRY_CNT);
+ }
+
+ /* chanspec */
+ tof_params->chanspec = htol16(rtt_target->chanspec);
+ /* set parameter */
+ DHD_RTT(("Target addr(Idx %d) %s, Channel : %s for RTT (ftm_cnt %d, rety_cnt : %d)\n",
+ rtt_status->cur_idx,
+ bcm_ether_ntoa((const struct ether_addr *)&rtt_target->addr, eabuf),
+ wf_chspec_ntoa(rtt_target->chanspec, chanbuf), rtt_target->ftm_cnt,
+ rtt_target->retry_cnt));
+
+ if (rtt_target->type == RTT_ONE_WAY) {
+ proxd_tune.u.tof_tune.flags = htol32(WL_PROXD_FLAG_ONEWAY);
+ /* report RTT results for initiator */
+ proxd_tune.u.tof_tune.flags |= htol32(WL_PROXD_FLAG_INITIATOR_RPTRTT);
+ proxd_tune.u.tof_tune.vhtack = 0;
+ tof_params->tx_rate = htol16(WL_RATE_6M);
+ tof_params->vht_rate = htol16((WL_RATE_6M >> 16));
+ } else { /* RTT TWO WAY */
+ /* initiator will send the rtt result to the target */
+ proxd_tune.u.tof_tune.flags = htol32(WL_PROXD_FLAG_INITIATOR_REPORT);
+ tof_params->timeout = 10; /* 10ms for timeout */
+ rspec = WL_RSPEC_ENCODE_VHT; /* 11ac VHT */
+ nss = 1; /* default Nss = 1 */
+ mcs = 0; /* default MCS 0 */
+ rspec |= (nss << WL_RSPEC_VHT_NSS_SHIFT) | mcs;
+ bw = 0;
+ switch (CHSPEC_BW(rtt_target->chanspec)) {
+ case WL_CHANSPEC_BW_20:
+ bw = WL_RSPEC_BW_20MHZ;
+ break;
+ case WL_CHANSPEC_BW_40:
+ bw = WL_RSPEC_BW_40MHZ;
+ break;
+ case WL_CHANSPEC_BW_80:
+ bw = WL_RSPEC_BW_80MHZ;
+ break;
+ case WL_CHANSPEC_BW_160:
+ bw = WL_RSPEC_BW_160MHZ;
+ break;
+ default:
+ DHD_ERROR(("CHSPEC_BW not supported : %d",
+ CHSPEC_BW(rtt_target->chanspec)));
+ goto exit;
+ }
+ rspec |= bw;
+ tof_params->tx_rate = htol16(rspec & 0xffff);
+ tof_params->vht_rate = htol16(rspec >> 16);
+ }
+
+ /* Set Method to TOF */
+ proxd_tune.method = PROXD_TOF_METHOD;
+ err = dhd_iovar(dhd, 0, "proxd_tune", (char *)&proxd_tune, sizeof(proxd_tune), 1);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to set proxd_tune %d\n", __FUNCTION__, err));
+ goto exit;
+ }
+
+ /* Set Method to TOF */
+ proxd_params.method = PROXD_TOF_METHOD;
+ err = dhd_iovar(dhd, 0, "proxd_params", (char *)&proxd_params, sizeof(proxd_params), 1);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to set proxd_params %d\n", __FUNCTION__, err));
+ goto exit;
+ }
+ err = dhd_iovar(dhd, 0, "proxd_find", (char *)NULL, 0, 1);
+ if (err < 0) {
+ DHD_ERROR(("%s : failed to set proxd_find %d\n", __FUNCTION__, err));
+ goto exit;
+ }
+exit:
+ if (err < 0) {
+ rtt_status->status = RTT_STOPPED;
+ if (set_mpc) {
+ /* enable mpc again in case of error */
+ mpc = 1;
+ err = dhd_iovar(dhd, 0, "mpc", (char *)&mpc, sizeof(mpc), 1);
+ }
+ }
+ return err;
+}
+
+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(&noti_list_lock);
+ list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
+ if (iter->noti_fn == noti_fn) {
+ goto exit;
+ }
+ }
+ 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(&noti_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(&noti_list_lock);
+ list_for_each_entry(iter, &rtt_status->noti_fn_list, list) {
+ if (iter->noti_fn == noti_fn) {
+ cb = iter;
+ list_del(&cb->list);
+ break;
+ }
+ }
+ spin_unlock_bh(&noti_list_lock);
+ if (cb) {
+ kfree(cb);
+ }
+ return err;
+}
+
+static int
+dhd_rtt_convert_to_host(rtt_result_t *rtt_results, const wl_proxd_event_data_t* evp)
+{
+ int err = BCME_OK;
+ int i;
+ char eabuf[ETHER_ADDR_STR_LEN];
+ char diststr[40];
+ struct timespec ts;
+ NULL_CHECK(rtt_results, "rtt_results is NULL", err);
+ NULL_CHECK(evp, "evp is NULL", err);
+ DHD_RTT(("%s enter\n", __FUNCTION__));
+ rtt_results->distance = ntoh32(evp->distance);
+ rtt_results->sdrtt = ntoh32(evp->sdrtt);
+ rtt_results->ftm_cnt = ntoh16(evp->ftm_cnt);
+ rtt_results->avg_rssi = ntoh16(evp->avg_rssi);
+ rtt_results->validfrmcnt = ntoh16(evp->validfrmcnt);
+ rtt_results->meanrtt = ntoh32(evp->meanrtt);
+ rtt_results->modertt = ntoh32(evp->modertt);
+ rtt_results->medianrtt = ntoh32(evp->medianrtt);
+ rtt_results->err_code = evp->err_code;
+ rtt_results->tx_rate.preamble = (evp->OFDM_frame_type == TOF_FRAME_RATE_VHT)? 3 : 0;
+ rtt_results->tx_rate.nss = 0; /* 1 x 1 */
+ rtt_results->tx_rate.bw =
+ (evp->bandwidth == TOF_BW_80MHZ)? 2 : (evp->bandwidth == TOF_BW_40MHZ)? 1 : 0;
+ rtt_results->TOF_type = evp->TOF_type;
+ if (evp->TOF_type == TOF_TYPE_ONE_WAY) {
+ /* convert to 100kbps unit */
+ rtt_results->tx_rate.bitrate = WL_RATE_6M * 5;
+ rtt_results->tx_rate.rateMcsIdx = WL_RATE_6M;
+ } else {
+ rtt_results->tx_rate.bitrate = WL_RATE_6M * 5;
+ rtt_results->tx_rate.rateMcsIdx = 0; /* MCS 0 */
+ }
+ memset(diststr, 0, sizeof(diststr));
+ if (rtt_results->distance == 0xffffffff || rtt_results->distance == 0) {
+ sprintf(diststr, "distance=-1m\n");
+ } else {
+ sprintf(diststr, "distance=%d.%d m\n",
+ rtt_results->distance >> 4, ((rtt_results->distance & 0xf) * 125) >> 1);
+ }
+
+ if (ntoh32(evp->mode) == WL_PROXD_MODE_INITIATOR) {
+ DHD_RTT(("Target:(%s) %s;\n", bcm_ether_ntoa((&evp->peer_mac), eabuf), diststr));
+ DHD_RTT(("RTT : mean %d mode %d median %d\n", rtt_results->meanrtt,
+ rtt_results->modertt, rtt_results->medianrtt));
+ } else {
+ DHD_RTT(("Initiator:(%s) %s; ", bcm_ether_ntoa((&evp->peer_mac), eabuf), diststr));
+ }
+ if (rtt_results->sdrtt > 0) {
+ DHD_RTT(("sigma:%d.%d\n", rtt_results->sdrtt/10, rtt_results->sdrtt % 10));
+ } else {
+ DHD_RTT(("sigma:0\n"));
+ }
+
+ DHD_RTT(("rssi:%d validfrmcnt %d, err_code : %d\n", rtt_results->avg_rssi,
+ rtt_results->validfrmcnt, evp->err_code));
+
+ switch (evp->err_code) {
+ case TOF_REASON_OK:
+ rtt_results->err_code = RTT_REASON_SUCCESS;
+ break;
+ case TOF_REASON_TIMEOUT:
+ rtt_results->err_code = RTT_REASON_TIMEOUT;
+ break;
+ case TOF_REASON_NOACK:
+ rtt_results->err_code = RTT_REASON_NO_RSP;
+ break;
+ case TOF_REASON_ABORT:
+ rtt_results->err_code = RTT_REASON_ABORT;
+ break;
+ default:
+ rtt_results->err_code = RTT_REASON_FAILURE;
+ break;
+ }
+ rtt_results->peer_mac = evp->peer_mac;
+ /* get the time elapsed from boot time */
+ get_monotonic_boottime(&ts);
+ rtt_results->ts = (uint64) TIMESPEC_TO_US(ts);
+
+ for (i = 0; i < rtt_results->ftm_cnt; i++) {
+ rtt_results->ftm_buff[i].value = ltoh32(evp->ftm_buff[i].value);
+ rtt_results->ftm_buff[i].rssi = ltoh32(evp->ftm_buff[i].rssi);
+ }
+ return err;
+}
+
+int
+dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data)
+{
+ int err = BCME_OK;
+ int len = 0;
+ int idx;
+ uint event_type, reason, ftm_cnt;
+ rtt_status_info_t *rtt_status;
+ wl_proxd_event_data_t* evp;
+ struct rtt_noti_callback *iter;
+ rtt_result_t *rtt_result, *entry, *next;
+ gfp_t kflags;
+ NULL_CHECK(dhd, "dhd is NULL", err);
+ rtt_status = GET_RTTSTATE(dhd);
+ NULL_CHECK(rtt_status, "rtt_status is NULL", err);
+ event_type = ntoh32_ua((void *)&event->event_type);
+ reason = ntoh32_ua((void *)&event->reason);
+
+ if (event_type != WLC_E_PROXD) {
+ goto exit;
+ }
+ kflags = in_softirq()? GFP_ATOMIC : GFP_KERNEL;
+ evp = (wl_proxd_event_data_t*)event_data;
+ DHD_RTT(("%s enter : mode: %s, reason :%d \n", __FUNCTION__,
+ (ntoh16(evp->mode) == WL_PROXD_MODE_INITIATOR)?
+ "initiator":"target", reason));
+ switch (reason) {
+ case WLC_E_PROXD_STOP:
+ DHD_RTT(("WLC_E_PROXD_STOP\n"));
+ break;
+ case WLC_E_PROXD_ERROR:
+ case WLC_E_PROXD_COMPLETED:
+ if (reason == WLC_E_PROXD_ERROR) {
+ DHD_RTT(("WLC_E_PROXD_ERROR\n"));
+ } else {
+ DHD_RTT(("WLC_E_PROXD_COMPLETED\n"));
+ }
+
+ if (!in_atomic()) {
+ mutex_lock(&rtt_status->rtt_mutex);
+ }
+ ftm_cnt = ntoh16(evp->ftm_cnt);
+
+ if (ftm_cnt > 0) {
+ len = OFFSETOF(rtt_result_t, ftm_buff);
+ } else {
+ len = sizeof(rtt_result_t);
+ }
+ /* check whether the results is already reported or not */
+ list_for_each_entry(entry, &rtt_status->rtt_results_cache, list) {
+ if (!memcmp(&entry->peer_mac, &evp->peer_mac, ETHER_ADDR_LEN)) {
+ if (!in_atomic()) {
+ mutex_unlock(&rtt_status->rtt_mutex);
+ }
+ goto exit;
+ }
+ }
+ rtt_result = kzalloc(len + sizeof(ftm_sample_t) * ftm_cnt, kflags);
+ if (!rtt_result) {
+ if (!in_atomic()) {
+ mutex_unlock(&rtt_status->rtt_mutex);
+ }
+ err = -ENOMEM;
+ goto exit;
+ }
+ /* point to target_info in status struct and increase pointer */
+ rtt_result->target_info = &rtt_status->rtt_config.target_info[rtt_status->cur_idx];
+ /* 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;
+ }
+ }
+ /* convert the event results to host format */
+ dhd_rtt_convert_to_host(rtt_result, evp);
+ list_add_tail(&rtt_result->list, &rtt_status->rtt_results_cache);
+ if (idx < rtt_status->rtt_config.rtt_target_cnt) {
+ /* restart to measure RTT from next device */
+ 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 */
+ 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 */
+ list_for_each_entry_safe(rtt_result, next,
+ &rtt_status->rtt_results_cache, list) {
+ list_del(&rtt_result->list);
+ kfree(rtt_result);
+ }
+ /* reinit the HEAD */
+ INIT_LIST_HEAD(&rtt_status->rtt_results_cache);
+ /* clear information for rtt_config */
+ bzero(&rtt_status->rtt_config, sizeof(rtt_status->rtt_config));
+ rtt_status->cur_idx = 0;
+ }
+ if (!in_atomic()) {
+ mutex_unlock(&rtt_status->rtt_mutex);
+ }
+
+ break;
+ case WLC_E_PROXD_GONE:
+ DHD_RTT(("WLC_E_PROXD_GONE\n"));
+ break;
+ case WLC_E_PROXD_START:
+ /* event for targets / accesspoints */
+ DHD_RTT(("WLC_E_PROXD_START\n"));
+ break;
+ case WLC_E_PROXD_COLLECT_START:
+ DHD_RTT(("WLC_E_PROXD_COLLECT_START\n"));
+ break;
+ case WLC_E_PROXD_COLLECT_STOP:
+ DHD_RTT(("WLC_E_PROXD_COLLECT_STOP\n"));
+ break;
+ case WLC_E_PROXD_COLLECT_COMPLETED:
+ DHD_RTT(("WLC_E_PROXD_COLLECT_COMPLETED\n"));
+ break;
+ case WLC_E_PROXD_COLLECT_ERROR:
+ DHD_RTT(("WLC_E_PROXD_COLLECT_ERROR; "));
+ break;
+ default:
+ DHD_ERROR(("WLC_E_PROXD: supported EVENT reason code:%d\n", reason));
+ break;
+ }
+
+exit:
+ return err;
+}
+
+static void
+dhd_rtt_work(struct work_struct *work)
+{
+ rtt_status_info_t *rtt_status;
+ dhd_pub_t *dhd;
+ rtt_status = container_of(work, rtt_status_info_t, work);
+ 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);
+}
+
+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));
+
+ if (rtt_status->capability & RTT_CAP_ONE_WAY) {
+ capa->rtt_one_sided_supported = 1;
+ }
+ if (rtt_status->capability & RTT_CAP_11V_WAY) {
+ capa->rtt_11v_supported = 1;
+ }
+ if (rtt_status->capability & RTT_CAP_11MC_WAY) {
+ capa->rtt_ftm_supported = 1;
+ }
+ if (rtt_status->capability & RTT_CAP_VS_WAY) {
+ capa->rtt_vs_supported = 1;
+ }
+
+ return err;
+}
+
+int
+dhd_rtt_init(dhd_pub_t *dhd)
+{
+ int err = BCME_OK;
+ rtt_status_info_t *rtt_status;
+ NULL_CHECK(dhd, "dhd is NULL", err);
+ if (dhd->rtt_state) {
+ goto exit;
+ }
+ dhd->rtt_state = MALLOC(dhd->osh, sizeof(rtt_status_info_t));
+ if (dhd->rtt_state == NULL) {
+ DHD_ERROR(("failed to create rtt_state\n"));
+ goto exit;
+ }
+ bzero(dhd->rtt_state, sizeof(rtt_status_info_t));
+ rtt_status = GET_RTTSTATE(dhd);
+ rtt_status->dhd = dhd;
+ err = dhd_iovar(dhd, 0, "proxd_params", NULL, 0, 1);
+ if (err != BCME_UNSUPPORTED) {
+ rtt_status->capability |= RTT_CAP_ONE_WAY;
+ rtt_status->capability |= RTT_CAP_VS_WAY;
+ DHD_ERROR(("%s: Support RTT Service\n", __FUNCTION__));
+ }
+ 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:
+ return err;
+}
+
+int
+dhd_rtt_deinit(dhd_pub_t *dhd)
+{
+ int err = BCME_OK;
+ rtt_status_info_t *rtt_status;
+ rtt_result_t *rtt_result, *next;
+ 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;
+ /* clear evt callback list */
+ 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_result, next, &rtt_status->rtt_results_cache, list) {
+ list_del(&rtt_result->list);
+ kfree(rtt_result);
+ }
+ }
+ MFREE(dhd->osh, dhd->rtt_state, sizeof(rtt_status_info_t));
+ dhd->rtt_state = NULL;
+ return err;
+}
+#endif /* RTT_SUPPORT */
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_rtt.h b/drivers/net/wireless/bcmdhd_1363/dhd_rtt.h
new file mode 100644
index 000000000000..acd4d6ccb9ba
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_rtt.h
@@ -0,0 +1,234 @@
+/*
+ * 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: dhd_rtt.h 558438 2015-05-22 06:05:11Z $
+ */
+#ifndef __DHD_RTT_H__
+#define __DHD_RTT_H__
+
+#include "dngl_stats.h"
+
+#define RTT_MAX_TARGET_CNT 10
+#define RTT_MAX_FRAME_CNT 25
+#define RTT_MAX_RETRY_CNT 10
+#define DEFAULT_FTM_CNT 6
+#define DEFAULT_RETRY_CNT 6
+
+
+/* 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 */
+
+
+enum rtt_role {
+ RTT_INITIATOR = 0,
+ RTT_TARGET = 1
+};
+enum rtt_status {
+ RTT_STOPPED = 0,
+ RTT_STARTED = 1
+};
+typedef int64_t wifi_timestamp; /* In microseconds (us) */
+typedef int64_t wifi_timespan;
+typedef int wifi_rssi;
+
+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_NO_RSP,
+ RTT_REASON_REJECTED,
+ RTT_REASON_NOT_SCHEDULED_YET,
+ RTT_REASON_TIMEOUT,
+ RTT_REASON_AP_ON_DIFF_CH,
+ RTT_REASON_AP_NO_CAP,
+ RTT_REASON_ABORT
+} rtt_reason_t;
+
+typedef enum rtt_capability {
+ RTT_CAP_NONE = 0,
+ RTT_CAP_ONE_WAY = (1 << (0)),
+ RTT_CAP_11V_WAY = (1 << (1)), /* IEEE802.11v */
+ RTT_CAP_11MC_WAY = (1 << (2)), /* IEEE802.11mc */
+ RTT_CAP_VS_WAY = (1 << (3)) /* BRCM vendor specific */
+} rtt_capability_t;
+
+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; /* 0 : 1x1, 1: 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 */
+ int8 continuous; /* 0 = single shot or 1 = continous raging */
+ bool disable; /* disable for RTT measurement */
+ uint32 interval; /* interval of RTT measurement (unit ms) when continuous = true */
+ uint32 measure_cnt; /* total number of RTT measurement when continuous */
+ uint32 ftm_cnt; /* num of packets in each RTT measurement */
+ uint32 retry_cnt; /* num of retries if sampling fails */
+} rtt_target_info_t;
+
+typedef struct rtt_result {
+ struct list_head list;
+ uint16 ver; /* version */
+ rtt_target_info_t *target_info; /* target info */
+ 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 */
+ wifi_rate_t tx_rate; /* tx rate */
+ struct ether_addr peer_mac; /* (e.g for tgt:initiator's */
+ int32 distance; /* dst to tgt, units (meter * 16) */
+ uint32 meanrtt; /* mean delta */
+ uint32 modertt; /* Mode delta */
+ uint32 medianrtt; /* median RTT */
+ uint32 sdrtt; /* Standard deviation of RTT */
+ int16 avg_rssi; /* avg rssi across the ftm frames */
+ int16 validfrmcnt; /* Firmware's valid frame counts */
+ wifi_timestamp ts; /* the time elapsed from boot time when driver get this result */
+ uint16 ftm_cnt; /* num of rtd measurments/length in the ftm buffer */
+ ftm_sample_t ftm_buff[1]; /* 1 ... ftm_cnt */
+} rtt_result_t;
+
+typedef struct rtt_report {
+ struct ether_addr addr;
+ uint num_measurement; /* measurement number in case of continous raging */
+ rtt_reason_t status; /* raging status */
+ rtt_type_t type; /* rtt type */
+ rtt_peer_type_t peer; /* peer type */
+ wifi_channel_info_t channel; /* channel information */
+ wifi_rssi rssi; /* avg rssi accroos the ftm frames */
+ wifi_rssi rssi_spread; /* rssi spread in 0.5 db steps e.g. 5 implies 2.5 spread */
+ wifi_rate_t tx_rate; /* tx rate */
+ wifi_timespan rtt; /* round trip time in nanoseconds */
+ wifi_timespan rtt_sd; /* rtt standard deviation in nanoseconds */
+ wifi_timespan rtt_spread; /* difference between max and min rtt times recorded */
+ int32 distance; /* distance in cm (optional) */
+ int32 distance_sd; /* standard deviation in cm (optional) */
+ int32 distance_spread; /* difference between max and min distance recorded (optional) */
+ wifi_timestamp ts; /* time of the measurement (in microseconds since boot) */
+} rtt_report_t;
+
+/* RTT Capabilities */
+typedef struct rtt_capabilities {
+ uint8 rtt_one_sided_supported; /* if 1-sided rtt data collection is supported */
+ uint8 rtt_11v_supported; /* if 11v rtt data collection is supported */
+ uint8 rtt_ftm_supported; /* if ftm rtt data collection is supported */
+ uint8 rtt_vs_supported; /* if vendor specific data collection supported */
+} rtt_capabilities_t;
+
+typedef struct rtt_config_params {
+ int8 rtt_target_cnt;
+ rtt_target_info_t target_info[RTT_MAX_TARGET_CNT];
+} rtt_config_params_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);
+
+/* export to upper layer */
+chanspec_t
+dhd_rtt_convert_to_chspec(wifi_channel_info_t channel);
+
+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_init(dhd_pub_t *dhd);
+
+int
+dhd_rtt_deinit(dhd_pub_t *dhd);
+#endif /* __DHD_RTT_H__ */
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_sdio.c b/drivers/net/wireless/bcmdhd_1363/dhd_sdio.c
new file mode 100644
index 000000000000..ca663b62e1b1
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_sdio.c
@@ -0,0 +1,8445 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_sdio.c 662780 2016-11-11 06:44:38Z $
+ */
+
+#include <typedefs.h>
+#include <osl.h>
+#include <bcmsdh.h>
+
+#ifdef BCMEMBEDIMAGE
+#include BCMEMBEDIMAGE
+#endif /* BCMEMBEDIMAGE */
+
+#include <bcmdefs.h>
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <bcmdevs.h>
+
+#include <siutils.h>
+#include <hndpmu.h>
+#include <hndsoc.h>
+#include <bcmsdpcm.h>
+#include <hnd_armtrap.h>
+#include <hnd_cons.h>
+#include <sbchipc.h>
+#include <sbhnddma.h>
+
+#include <sdio.h>
+#include <sbsdio.h>
+#include <sbsdpcmdev.h>
+#include <bcmsdpcm.h>
+#include <bcmsdbus.h>
+
+#include <proto/ethernet.h>
+#include <proto/802.1d.h>
+#include <proto/802.11.h>
+
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_bus.h>
+#include <dhd_proto.h>
+#include <dhd_dbg.h>
+#include <dhdioctl.h>
+#include <sdiovar.h>
+
+#ifdef PROP_TXSTATUS
+#include <dhd_wlfc.h>
+#endif
+#ifdef DHDTCPACK_SUPPRESS
+#include <dhd_ip.h>
+#endif /* DHDTCPACK_SUPPRESS */
+
+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);
+
+#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 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_DATA_BUF (64 * 1024) /* Must be large enough to hold biggest possible glom */
+
+#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
+
+/* 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);
+
+
+/* Device console log buffer state */
+#define CONSOLE_LINE_MAX 192
+#define CONSOLE_BUFFER_MAX 2024
+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_ADDR (SI_ENUM_BASE + 0x618)
+#define MIN_RSRC_SR 0x3
+#define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 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)
+/* 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 */
+
+#ifdef DHD_DEBUG
+ dhd_console_t console; /* Console output polling support */
+ uint console_addr; /* Console address from shared struct */
+#endif /* DHD_DEBUG */
+
+ 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 */
+ 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 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 */
+#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 */
+} dhd_bus_t;
+
+/* 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 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)
+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;
+
+/* To check if there's window offered */
+#define DATAOK(bus) \
+ (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \
+ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
+
+/* To check if there's window offered for ctrl frame */
+#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 */
+#define DATABUFCNT(bus) \
+ ((uint8)(bus->tx_max - bus->tx_seq) - 1)
+
+/* 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);
+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);
+
+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);
+
+#ifdef WLMEDIA_HTSF
+#include <htsf.h>
+extern uint32 dhd_get_htsf(void *dhd, int ifidx);
+#endif /* WLMEDIA_HTSF */
+
+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) {
+ /* 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) {
+ core_capext = FALSE;
+ } else if ((bus->sih->chip == BCM4335_CHIP_ID) ||
+ (bus->sih->chip == BCM4339_CHIP_ID) ||
+ (bus->sih->chip == BCM43349_CHIP_ID) ||
+ (bus->sih->chip == BCM4345_CHIP_ID) ||
+ (bus->sih->chip == BCM43454_CHIP_ID) ||
+ (bus->sih->chip == BCM4354_CHIP_ID) ||
+ (bus->sih->chip == BCM4356_CHIP_ID) ||
+ (bus->sih->chip == BCM4358_CHIP_ID) ||
+ (BCM4349_CHIP(bus->sih->chip)) ||
+ (bus->sih->chip == BCM4350_CHIP_ID)) {
+ core_capext = TRUE;
+ } else {
+ core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 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) ||
+ (bus->sih->chip == BCM4345_CHIP_ID) ||
+ (bus->sih->chip == BCM43454_CHIP_ID) ||
+ (bus->sih->chip == BCM4354_CHIP_ID) ||
+ (bus->sih->chip == BCM4356_CHIP_ID) ||
+ (bus->sih->chip == BCM4358_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) ||
+ (bus->sih->chip == BCM4345_CHIP_ID) ||
+ (bus->sih->chip == BCM43454_CHIP_ID) ||
+ (bus->sih->chip == BCM4354_CHIP_ID) ||
+ (bus->sih->chip == BCM4356_CHIP_ID) ||
+ (bus->sih->chip == BCM4358_CHIP_ID))
+ enabval &= CC_CHIPCTRL3_SR_ENG_ENABLE;
+
+ if (enabval)
+ cap = TRUE;
+ } else {
+ data = bcmsdh_reg_read(bus->sdh,
+ SI_ENUM_BASE + 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);
+
+ 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 */
+
+ dhdsdio_devcap_set(bus, SDIOD_CCCR_BRCM_CARDCAP_CMD_NODEC);
+
+ 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);
+
+ 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
+
+
+ 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 */
+ } 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));
+ err = 0; /* continue anyway */
+ }
+
+
+#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)), (10000));
+
+ 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) || defined(OOB_PARAM)
+ /* Go to pending and await interrupt if appropriate */
+ if (1 &&
+#if defined(OOB_PARAM)
+ bus->dhd->oob_disable &&
+#endif /* OOB_PARAM */
+ !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) || defined(OOB_PARAM) */
+ {
+ 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 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;
+ }
+
+ iovalue = bus->sd_mode;
+ err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
+ &iovalue, sizeof(iovalue), TRUE);
+ if (err) {
+ DHD_ERROR(("%s: error changing sd_mode: %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) {
+ if (sd1idle) {
+ /* Change to SD1 mode and turn off clock */
+ iovalue = 1;
+ err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
+ &iovalue, sizeof(iovalue), TRUE);
+ if (err) {
+ DHD_ERROR(("%s: error changing sd_clock: %d\n",
+ __FUNCTION__, err));
+ return BCME_ERROR;
+ }
+ }
+
+ 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:
+ /* 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:
+ /* 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;
+
+
+ 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, &regs->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 */
+ if (bus->sih->chip != BCM4329_CHIP_ID &&
+ bus->sih->chip != BCM4319_CHIP_ID) {
+ bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
+ SBSDIO_DEVCTL_PADS_ISO, NULL);
+ }
+ } 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, &regs->tosbmailboxdata, retries);
+ if (retries <= retry_limit)
+ W_SDREG(SMB_DEV_INT, &regs->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 */);
+ }
+
+ if (err == 0) {
+ /* Change state */
+ bus->sleeping = FALSE;
+ }
+ }
+
+ return err;
+}
+
+#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)
+void
+dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
+{
+#if defined(HW_OOB)
+ 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, &regs->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, &regs->tosbmailboxdata, retries);
+ if (retries <= retry_limit)
+ W_SDREG(SMB_DEV_INT, &regs->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;
+#if defined(DHD_TX_DUMP)
+ uint8 *dump_data;
+ uint16 protocol;
+#endif /* DHD_TX_DUMP */
+
+ 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 */
+
+#if defined(DHD_TX_DUMP)
+ dump_data = PKTDATA(osh, pkt);
+ dump_data += 4; /* skip 4 bytes header */
+ protocol = (dump_data[12] << 8) | dump_data[13];
+
+ if (protocol == ETHER_TYPE_802_1X) {
+ DHD_ERROR(("ETHER_TYPE_802_1X [TX]: ver %d, type %d, replay %d\n",
+ dump_data[14], dump_data[15], dump_data[30]));
+ }
+#endif /* DHD_TX_DUMP */
+
+#if defined(DHD_TX_DUMP) && defined(DHD_TX_FULL_DUMP)
+ {
+ int i;
+ DHD_ERROR(("TX DUMP\n"));
+
+ for (i = 0; i < (datalen - 4); i++) {
+ DHD_ERROR(("%02X ", dump_data[i]));
+ if ((i & 15) == 15)
+ printk("\n");
+ }
+ DHD_ERROR(("\n"));
+ }
+#endif /* DHD_TX_DUMP && DHD_TX_FULL_DUMP */
+
+ prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
+
+ /* 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;
+
+ 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;
+
+ dhd_os_sdlock_txq(bus->dhd);
+ pkq_len = pktq_len(&bus->txq);
+ dhd_os_sdunlock_txq(bus->dhd);
+ if (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) {
+ 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) {
+ bus->activity = FALSE;
+ dhdsdio_clkctl(bus, CLK_NONE, TRUE);
+ }
+
+ 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)
+{
+ 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;
+
+ *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 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 = (ulong)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().
+ */
+ *(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;
+
+ 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;
+
+ 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 (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;
+
+ 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
+ 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;
+ }
+ PKTORPHAN(pkts[i]);
+ 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;
+ cnt += i;
+
+ /* In poll mode, need to check for other events */
+ if (!bus->intr && cnt)
+ {
+ /* Check device status, signal pending interrupt */
+ R_SDREG(intstatus, &regs->intstatus, retries);
+ bus->f2txdata++;
+ if (bcmsdh_regfail(bus->sdh))
+ break;
+ if (intstatus & bus->hostintmask)
+ bus->ipend = TRUE;
+ }
+
+ }
+
+ 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;
+ bcmsdh_info_t *sdh = bus->sdh;
+ 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);
+
+ 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));
+ }
+ if (!TXCTLOK(bus)) {
+ DHD_INFO(("%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));
+ }
+ 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
+ ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
+ frame, len, NULL, NULL, NULL, TXRETRIES);
+ if (ret == BCME_OK)
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
+ }
+ bus->ctrl_frame_stat = FALSE;
+
+done:
+ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
+ bus->activity = FALSE;
+ dhdsdio_clkctl(bus, CLK_NONE, TRUE);
+ }
+
+ 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;
+
+ 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 (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 */
+ 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__));
+ dhd_os_sdlock(bus->dhd);
+ dhdsdio_checkdied(bus, NULL, 0);
+ dhd_os_sdunlock(bus->dhd);
+ }
+ 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));
+ }
+ 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_MEMBYTES,
+ 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
+};
+
+const bcm_iovar_t dhdsdio_iovars[] = {
+ {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
+ {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 },
+ {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 },
+ {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 },
+ {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 },
+ {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 },
+ {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
+ {"ramsize", IOV_RAMSIZE, 0, IOVT_UINT32, 0 },
+ {"ramstart", IOV_RAMSTART, 0, IOVT_UINT32, 0 },
+ {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 },
+ {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 },
+ {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
+ {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 },
+ {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 },
+ {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 },
+ {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 },
+ {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 },
+ {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
+#ifdef DHD_DEBUG
+ {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
+ {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
+ {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
+ {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 },
+ {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
+ {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
+ {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 },
+ {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 },
+#ifdef DHD_DEBUG
+ {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 },
+ {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 },
+#endif /* DHD_DEBUG */
+#endif /* DHD_DEBUG */
+#ifdef SDTEST
+ {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
+ {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
+#endif /* SDTEST */
+#if defined(USE_SDIOFIFO_IOVAR)
+ {"watermark", IOV_WATERMARK, 0, IOVT_UINT32, 0 },
+ {"mesbusyctrl", IOV_MESBUSYCTRL, 0, IOVT_UINT32, 0 },
+#endif /* USE_SDIOFIFO_IOVAR */
+ {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 },
+ {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
+ {"kso", IOV_KSO, 0, IOVT_UINT32, 0 },
+ {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 },
+#ifdef SOFTAP
+ {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 },
+#endif
+ {"txglomsize", IOV_TXGLOMSIZE, 0, IOVT_UINT32, 0 },
+ {"fw_hang_report", IOV_HANGREPORT, 0, IOVT_BOOL, 0 },
+ {"txinrx_thres", IOV_TXINRX_THRES, 0, IOVT_INT32, 0 },
+ {NULL, 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;
+
+ 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);
+ 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);
+}
+
+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;
+}
+
+#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;
+
+ /* 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 ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
+ DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
+ break;
+ }
+
+ /* 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 && !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);
+
+ 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;
+ trap_t tr;
+ sdpcm_shared_t 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, &sdpcm_shared)) < 0)
+ goto done;
+
+ bcm_binit(&strbuf, data, size);
+
+ bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
+ sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
+
+ if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
+ /* NOTE: Misspelled assert is intentional - DO NOT FIX.
+ * (Avoids conflict with real asserts for programmatic parsing of output.)
+ */
+ bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
+ }
+
+ if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
+ /* NOTE: Misspelled assert is intentional - DO NOT FIX.
+ * (Avoids conflict with real asserts for programmatic parsing of output.)
+ */
+ bcm_bprintf(&strbuf, "No trap%s in dongle",
+ (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
+ ?"/assrt" :"");
+ } else {
+ if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
+ /* Download assert */
+ bcm_bprintf(&strbuf, "Dongle assert");
+ if (sdpcm_shared.assert_exp_addr != 0) {
+ str[0] = '\0';
+ if ((bcmerror = dhdsdio_membytes(bus, FALSE,
+ sdpcm_shared.assert_exp_addr,
+ (uint8 *)str, maxstrlen)) < 0)
+ goto done;
+
+ str[maxstrlen - 1] = '\0';
+ bcm_bprintf(&strbuf, " expr \"%s\"", str);
+ }
+
+ if (sdpcm_shared.assert_file_addr != 0) {
+ str[0] = '\0';
+ if ((bcmerror = dhdsdio_membytes(bus, FALSE,
+ 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 ", sdpcm_shared.assert_line);
+ }
+
+ if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
+ bus->dhd->dongle_trap_occured = TRUE;
+ if ((bcmerror = dhdsdio_membytes(bus, FALSE,
+ sdpcm_shared.trap_addr,
+ (uint8*)&tr, sizeof(trap_t))) < 0)
+ goto done;
+
+ 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(sdpcm_shared.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));
+
+ addr = 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 = 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 = 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 (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
+ DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
+ }
+
+#if defined(DHD_FW_COREDUMP)
+ if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
+ /* Mem dump to a file on device */
+ dhdsdio_mem_dump(bus);
+ }
+#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)
+static int
+dhdsdio_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;
+
+ /* Get full mem size */
+ size = bus->ramsize;
+ buf = MALLOC(bus->dhd->osh, size);
+ if (!buf) {
+ printf("%s: Out of memory (%d bytes)\n", __FUNCTION__, size);
+ return -1;
+ }
+
+ /* Read mem content */
+ printf("Dump dongle memory");
+ databuf = buf;
+ while (size)
+ {
+ read_size = MIN(MEMBLOCK, size);
+ if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size)))
+ {
+ printf("%s: Error membytes %d\n", __FUNCTION__, ret);
+ if (buf) {
+ MFREE(bus->dhd->osh, buf, size);
+ }
+ return -1;
+ }
+ /* Decrement size and increment start address */
+ size -= read_size;
+ start += read_size;
+ databuf += read_size;
+ }
+ printf("Done\n");
+
+ dhd_save_fwdump(bus->dhd, buf, bus->ramsize);
+ /* free buf before return !!! */
+ if (write_to_file(bus->dhd, buf, bus->ramsize))
+ {
+ printf("%s: Error writing to files\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* buf free handled in write_to_file, not here */
+ return 0;
+}
+#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__));
+
+ /* 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);
+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__));
+ 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_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;
+ 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) {
+ DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
+ __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
+ bcmerror = BCME_BADARG;
+ break;
+ }
+
+ DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
+ (set ? "write" : "read"), size, address));
+
+ /* check if CR4 */
+ if (si_setcore(bus->sih, ARMCR4_CORE_ID, 0)) {
+ /*
+ * If address is start of RAM (i.e. a downloaded image),
+ * store the reset instruction to be written in 0
+ */
+ if (set && address == bus->dongle_ram_base) {
+ bus->resetinstr = *(((uint32*)params) + 2);
+ }
+ } else {
+ /* If we know about SOCRAM, check for a fit */
+ if ((bus->orig_ramsize) &&
+ ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
+ {
+ uint8 enable, protect, remap;
+ si_socdevram(bus->sih, FALSE, &enable, &protect, &remap);
+ if (!enable || protect) {
+ DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
+ __FUNCTION__, bus->orig_ramsize, size, address));
+ DHD_ERROR(("%s: socram enable %d, protect %d\n",
+ __FUNCTION__, enable, protect));
+ bcmerror = BCME_BADARG;
+ break;
+ }
+
+ if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) {
+ uint32 devramsize = si_socdevram_size(bus->sih);
+ if ((address < SOCDEVRAM_ARM_ADDR) ||
+ (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) {
+ DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
+ __FUNCTION__, address, size));
+ DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
+ __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize));
+ bcmerror = BCME_BADARG;
+ break;
+ }
+ /* move it such that address is real now */
+ address -= SOCDEVRAM_ARM_ADDR;
+ address += SOCDEVRAM_BP_ADDR;
+ DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
+ __FUNCTION__, (set ? "write" : "read"), size, address));
+ } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) {
+ /* Can not access remap region while devram remap bit is set
+ * ROM content would be returned in this case
+ */
+ DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n",
+ __FUNCTION__, address));
+ bcmerror = BCME_ERROR;
+ break;
+ }
+ }
+ }
+
+ /* Generate the actual data pointer */
+ data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
+
+ /* Call to do the transfer */
+ bcmerror = dhdsdio_membytes(bus, set, address, data, size);
+
+ 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;
+ uint32 addr, size;
+
+ sd_ptr = (sdreg_t *)params;
+
+ addr = (uint32)((ulong)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;
+ uint32 addr, size;
+
+ sd_ptr = (sdreg_t *)params;
+
+ addr = (uint32)((ulong)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;
+
+ default:
+ bcmerror = BCME_UNSUPPORTED;
+ break;
+ }
+
+exit:
+ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
+ bus->activity = FALSE;
+ dhdsdio_clkctl(bus, CLK_NONE, TRUE);
+ }
+
+ 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;
+
+ 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);
+#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)
+ 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) {
+ /* 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) {
+ bus->activity = FALSE;
+ dhdsdio_clkctl(bus, CLK_NONE, TRUE);
+ }
+
+ 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;
+
+ 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;
+
+ /* Change our idea of bus state */
+ bus->dhd->busstate = DHD_BUS_DOWN;
+
+ /* 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);
+ }
+
+#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 */
+ /* Clear the data packet queues */
+ pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
+ }
+
+ /* 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
+ char buf[256];
+ 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;
+ memset(buf, 0, sizeof(buf));
+ bcm_mkiovar("bus:rxglom", (void *)&rxglom, 4, buf, sizeof(buf));
+ ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
+ 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;
+}
+
+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;
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ ASSERT(bus->dhd);
+ if (!bus->dhd)
+ return 0;
+
+ if (enforce_mutex)
+ dhd_os_sdlock(bus->dhd);
+
+ /* 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) {
+ 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 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, &regs->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;
+ } 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_ERROR(("%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);
+ }
+ }
+ }
+ 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_ERROR(("%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_ERROR(("%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);
+ }
+ 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)
+{
+ 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, &regs->tohostmailboxdata, retries);
+ if (retries <= retry_limit)
+ W_SDREG(SMB_INT_ACK, &regs->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));
+ }
+
+ 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 */
+#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);
+
+ if (bus->dhd->busstate == DHD_BUS_DOWN) {
+ DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
+ bus->intstatus = 0;
+ dhd_os_sdunlock(bus->dhd);
+ return 0;
+ }
+
+ /* 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;
+ R_SDREG(newstatus, &regs->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, &regs->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, &regs->intstatus, retries);
+ R_SDREG(newstatus, &regs->intstatus, retries);
+ bus->f1regdata += 2;
+ bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
+ intstatus |= (newstatus & bus->hostintmask);
+ }
+
+ /* 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);
+ }
+
+ /* 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)) {
+ DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
+ __FUNCTION__, rxdone, framecnt));
+ bus->intdis = FALSE;
+#if defined(OOB_INTR_ONLY)
+ OOB_PARAM_IF(!(bus->dhd->oob_disable)) {
+ bcmsdh_oob_intr_set(bus->sdh, TRUE);
+ }
+#endif /* defined(OOB_INTR_ONLY) */
+ bcmsdh_intr_enable(sdh);
+ }
+
+#if defined(OOB_INTR_ONLY) && !defined(HW_OOB)
+ OOB_PARAM_IF(!(bus->dhd->oob_disable)) {
+ /* In case of SW-OOB(using edge trigger),
+ * Check interrupt status in the dongle again after enable irq on the host.
+ * and rechedule dpc if interrupt is pended in the dongle.
+ * There is a chance to miss OOB interrupt while irq is disabled on the host.
+ * No need to do this with HW-OOB(level trigger)
+ */
+ R_SDREG(newstatus, &regs->intstatus, retries);
+ if (bcmsdh_regfail(bus->sdh))
+ newstatus = 0;
+ if (newstatus & bus->hostintmask) {
+ bus->ipend = TRUE;
+ resched = TRUE;
+ }
+ }
+#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */
+
+#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);
+
+ /* 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)) {
+ framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
+ framecnt = dhdsdio_sendfromq(bus, framecnt);
+ txlimit -= framecnt;
+ }
+ /* Resched the DPC if ctrl cmd is pending on bus credit */
+ if (bus->ctrl_frame_stat)
+ 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)) {
+ bus->activity = FALSE;
+ dhdsdio_clkctl(bus, CLK_NONE, FALSE);
+ }
+
+exit:
+
+ if (!resched && 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 */
+ }
+ }
+
+ 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 */
+ 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_TRACE(("%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;
+ }
+
+ DHD_TRACE(("%s: Enter\n", __FUNCTION__));
+
+ /* 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) || defined(OOB_PARAM)
+ OOB_PARAM_IF(bus->dhd->oob_disable) {
+ DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
+ DHD_OS_WAKE_LOCK(bus->dhd);
+ dhdsdio_dpc(bus);
+ DHD_OS_WAKE_UNLOCK(bus->dhd);
+ } OOB_PARAM_ELSE()
+#endif /* defined(SDIO_ISR_THREAD) || defined(OOB_PARAM) */
+#if !defined(SDIO_ISR_THREAD) || defined(OOB_PARAM)
+ {
+ bus->dpc_sched = TRUE;
+ dhd_sched_dpc(bus->dhd);
+ }
+#endif /* !defined(SDIO_ISR_THREAD) || defined(OOB_PARAM) */
+
+}
+
+#ifdef SDTEST
+static void
+dhdsdio_pktgen_init(dhd_bus_t *bus)
+{
+ /* Default to specified length, or full range */
+ if (dhd_pktgen_len) {
+ bus->pktgen_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)
+ OOB_PARAM_IF(!(dhdp->oob_disable)) {
+ 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)
+ OOB_PARAM_IF(!(dhdp->oob_disable)) {
+ 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)
+ OOB_PARAM_IF(!(dhdp->oob_disable)) {
+ 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;
+
+ 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;
+
+ if (dhdp->busstate == DHD_BUS_DOWN)
+ return FALSE;
+
+ dhd_os_sdlock(bus->dhd);
+
+ /* Poll period: check device if appropriate. */
+ if (!SLPAUTO_ENAB(bus) && (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;
+ }
+
+#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 ((bus->idletime > 0) && (bus->idlecount >= bus->idletime)) {
+ DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__));
+ if (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)) {
+ if (++bus->idlecount >= bus->idletime) {
+ bus->idlecount = 0;
+ if (bus->activity) {
+ bus->activity = FALSE;
+ if (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);
+
+ return bus->ipend;
+}
+
+#ifdef DHD_DEBUG
+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;
+
+ /* Address could be zero if CONSOLE := 0 in dongle Makefile */
+ if (bus->console_addr == 0)
+ return BCME_UNSUPPORTED;
+
+ /* Exclusive bus access */
+ dhd_os_sdlock(bus->dhd);
+
+ /* Don't allow input if dongle is in reset */
+ if (bus->dhd->dongle_reset) {
+ dhd_os_sdunlock(bus->dhd);
+ return BCME_NOTREADY;
+ }
+
+ /* 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);
+
+ /* 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:
+ if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
+ bus->activity = FALSE;
+ dhdsdio_clkctl(bus, CLK_NONE, TRUE);
+ }
+
+ dhd_os_sdunlock(bus->dhd);
+
+ return rv;
+}
+#endif /* DHD_DEBUG */
+
+#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 == BCM4325_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4329_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4315_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4319_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4336_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4330_CHIP_ID)
+ return TRUE;
+ if (chipid == 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 (chipid == BCM4345_CHIP_ID || chipid == BCM43454_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4350_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4354_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4356_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM4358_CHIP_ID)
+ return TRUE;
+ if (chipid == BCM43430_CHIP_ID)
+ return TRUE;
+ if (BCM4349_CHIP(chipid))
+ 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;
+
+
+ /* 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 BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */
+ case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */
+ case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */
+ DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__));
+ break;
+ case BCM4329_D11N_ID: /* 4329 802.11n dualband device */
+ case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */
+ case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */
+ case 0x4329:
+ DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__));
+ break;
+ case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */
+ case BCM4315_D11G_ID: /* 4315 802.11g id */
+ case BCM4315_D11A_ID: /* 4315 802.11a id */
+ DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__));
+ break;
+ case BCM4319_D11N_ID: /* 4319 802.11n id */
+ case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */
+ case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */
+ DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__));
+ break;
+ 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 */
+
+#if defined(SUPPORT_P2P_GO_PS)
+ init_waitqueue_head(&bus->bus_sleep);
+#endif /* LINUX && SUPPORT_P2P_GO_PS */
+
+ /* 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;
+ }
+
+ /* 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 (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;
+ }
+ /* 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 */
+
+
+ return bus;
+
+fail:
+ dhdsdio_release(bus, osh);
+
+forcereturn:
+
+ return NULL;
+}
+
+static bool
+dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
+ uint16 devid)
+{
+ int err = 0;
+ uint8 clkctl = 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;
+ }
+
+#ifdef DHD_DEBUG
+ if (DHD_INFO_ON()) {
+ uint fn, numfn;
+ uint8 *cis[SDIOD_MAX_IOFUNCS];
+ int err = 0;
+
+ 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(65);
+
+ 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;
+ }
+ dhd_dump_cis(fn, cis[fn]);
+ }
+
+ while (fn-- > 0) {
+ ASSERT(cis[fn]);
+ MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
+ }
+
+ if (err) {
+ DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
+ goto fail;
+ }
+ }
+#endif /* DHD_DEBUG */
+
+ /* 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 BCM4356_CHIP_ID:
+ case BCM4358_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_ID:
+ case BCM43454_CHIP_ID:
+ 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 base 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;
+ 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;
+ }
+
+ /* 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 */
+
+ /* 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;
+
+ return TRUE;
+}
+
+int
+dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
+ char *pfw_path, char *pnv_path)
+{
+ int ret;
+
+ bus->fw_path = pfw_path;
+ bus->nv_path = pnv_path;
+
+ ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
+
+
+ return ret;
+}
+
+static int
+dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
+{
+ int ret;
+
+
+ DHD_TRACE_HW4(("%s: firmware path=%s, nvram path=%s\n",
+ __FUNCTION__, bus->fw_path, bus->nv_path));
+ DHD_OS_WAKE_LOCK(bus->dhd);
+
+ /* 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->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) {
+#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__));
+
+
+
+ if (bus) {
+ ASSERT(bus->dhd);
+ dhdsdio_release(bus, bus->dhd->osh);
+ }
+
+
+
+ DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
+}
+
+static int
+dhdsdio_suspend(void *context)
+{
+ int ret = 0;
+
+ dhd_bus_t *bus = (dhd_bus_t*)context;
+#ifdef SUPPORT_P2P_GO_PS
+ int wait_time = 0;
+
+ 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
+ if ((!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) {
+ return 1;
+ }
+ }
+ }
+#endif /* SUPPORT_P2P_GO_PS */
+ return ret;
+}
+
+static int
+dhdsdio_resume(void *context)
+{
+
+ dhd_bus_t *bus = (dhd_bus_t*)context;
+
+#if defined(OOB_INTR_ONLY)
+ OOB_PARAM_IF(!(bus->dhd->oob_disable)) {
+ if (dhd_os_check_if_up(bus->dhd))
+ bcmsdh_oob_intr_set(bus->sdh, TRUE);
+ }
+#endif
+
+ /* Clear KSO bit to fix suspend/resume current draw issue */
+ dhdsdio_clk_kso_enab(bus, FALSE);
+
+ 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;
+
+ DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
+
+ image = dhd_os_open_image(pfw_path);
+ if (image == NULL)
+ 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 ((uint32)(uintptr)memblock % DHD_SDALIGN)
+ memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
+
+ /* Download image */
+ while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
+ 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, offset));
+ goto err;
+ }
+
+ offset += MEMBLOCK;
+ }
+
+err:
+ if (memblock)
+ MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
+
+ if (image)
+ dhd_os_close_image(image);
+
+ return bcmerror;
+}
+
+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);
+
+ 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, 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, 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, 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, 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;
+}
+
+void *
+dhd_bus_sih(struct dhd_bus *bus)
+{
+ return (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;
+}
+
+int
+dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
+{
+ int bcmerror = 0;
+ dhd_bus_t *bus;
+
+ bus = dhdp->bus;
+
+ if (flag == TRUE) {
+ if (!bus->dhd->dongle_reset) {
+ 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)
+ OOB_PARAM_IF(!(dhdp->oob_disable)) {
+ /* 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_TRACE(("%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 */
+
+ DHD_TRACE(("\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)) {
+ /* 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)
+ OOB_PARAM_IF(!(dhdp->oob_disable)) {
+ dhd_enable_oob_intr(bus, TRUE);
+ bcmsdh_oob_intr_register(bus->sdh,
+ dhdsdio_isr, bus);
+ bcmsdh_oob_intr_set(bus->sdh, 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 {
+ bcmerror = BCME_SDIO_ERROR;
+ DHD_INFO(("%s called when dongle is not in reset\n",
+ __FUNCTION__));
+ DHD_INFO(("Will call dhd_bus_start instead\n"));
+ dhd_bus_resume(dhdp, 1);
+ if ((bcmerror = dhd_bus_start(dhdp)) != 0)
+ DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
+ __FUNCTION__, bcmerror));
+ }
+ }
+ 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;
+
+ 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;
+}
+
+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)
+{
+ bus->fw_path = pfw_path;
+ bus->nv_path = pnv_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, &regs->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, &regs->tosbmailboxdata, retries);
+ if (retries <= retry_limit)
+ W_SDREG(SMB_DEV_INT, &regs->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, NULL, 0);
+ }
+}
+
+#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 */
+
+
+#ifdef OOB_PARAM
+uint
+dhd_get_oob_disable(struct dhd_bus *bus)
+{
+ return bus->dhd->oob_disable;
+}
+#endif /* OOB_PARAM */
diff --git a/drivers/net/wireless/bcmdhd_1363/dhd_wlfc.c b/drivers/net/wireless/bcmdhd_1363/dhd_wlfc.c
new file mode 100644
index 000000000000..6b30c3d29059
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_wlfc.c
@@ -0,0 +1,4510 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_wlfc.c 664810 2017-04-25 05:39:37Z $
+ *
+ */
+
+
+#include <typedefs.h>
+#include <osl.h>
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+
+#include <dngl_stats.h>
+#include <dhd.h>
+
+#include <dhd_bus.h>
+
+#include <dhd_dbg.h>
+
+#ifdef PROP_TXSTATUS /* a form of flow control between host and dongle */
+#include <wlfc_proto.h>
+#include <dhd_wlfc.h>
+#endif
+
+#ifdef DHDTCPACK_SUPPRESS
+#include <dhd_ip.h>
+#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)
+
+#define LIMIT_BORROW
+
+
+/** 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(dhdp))
+ 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;
+ }
+ } else if (!WLFC_GET_AFQ(dhdp->wlfc_mode)) {
+ /* clear hanger state */
+ ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].pkt_state = 0;
+ ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].pkt_txstatus = 0;
+ }
+
+ 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)
+{
+ if (entry->interface_id >= WLFC_MAX_IFNUM) {
+ ASSERT(&ctx->destination_entries.other == entry);
+ return 1;
+ }
+
+ if (ctx->destination_entries.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) && (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 */
+
+
+/** !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 */
+
+/** 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
+ */
+ /* flush bus->txq */
+ _dhd_wlfc_cleanup_txq(dhd, fn, arg);
+
+ /* 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);
+
+ 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 = WL_SEQ_GET_FROMFW(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_FROMDRV(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 */
+
+
+/** !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) {
+ 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 (WL_SEQ_GET_FROMDRV(htodseq)) {
+ WL_SEQ_SET_FROMFW(htodseq, 1);
+ WL_SEQ_SET_FROMDRV(htodseq, 0);
+ }
+ 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 */
+
+static int
+_dhd_wlfc_dbg_senum_check(dhd_pub_t *dhd, uint8 *value)
+{
+ uint32 timestamp;
+
+ (void)dhd;
+
+ bcopy(&value[2], &timestamp, 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<<AC_COUNT));
+ _dhd_wlfc_add_requested_entry(wlfc, desc);
+#if defined(DHD_WLFC_THREAD)
+ if (credit) {
+ _dhd_wlfc_thread_wakeup(dhd);
+ }
+#endif /* DHD_WLFC_THREAD */
+ } else {
+ wlfc->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<<AC_COUNT));
+ _dhd_wlfc_add_requested_entry(wlfc, desc);
+#if defined(DHD_WLFC_THREAD)
+ if (packet_count) {
+ _dhd_wlfc_thread_wakeup(dhd);
+ }
+#endif /* DHD_WLFC_THREAD */
+ } else {
+ wlfc->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_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);
+ }
+
+ 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);
+ }
+ } /* 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;
+} /* dhd_wlfc_parse_header_info */
+
+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;
+
+ 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;
+ while (FALSE == dhdp->proptxstatus_txoff) {
+ /* 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)) {
+ /* 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) {
+ _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++;
+ 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)) {
+ _dhd_wlfc_return_credit(ctx, lender, ac);
+ }
+#endif
+ } else {
+#ifdef LIMIT_BORROW
+ if (lender != -1) {
+ _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 ((lender = _dhd_wlfc_borrow_credit(ctx, AC_COUNT, ac, TRUE)) == -1) {
+ 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;
+
+
+ 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_INFO(("%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_INFO(("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_INFO(("%s: query wlfc_mode succeed, fw_caps=0x%x\n", __FUNCTION__, fw_caps));
+
+ if (WLFC_IS_OLD_DEF(fw_caps)) {
+ /* enable proptxtstatus v2 by default */
+ mode = WLFC_MODE_AFQ;
+ } else {
+ WLFC_SET_AFQ(mode, WLFC_GET_AFQ(fw_caps));
+ 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_INFO(("dhd_wlfc_init(): wlfc_mode=0x%x, ret=%d\n", dhd->wlfc_mode, ret));
+
+ 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);
+
+ 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;
+ }
+
+ _dhd_wlfc_cleanup_txq(dhd, fn, arg);
+
+ 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_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;
+}
+
+/**
+ * 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 = "<Unknown";
+ else
+ iftype_desc = iftypes[interfaces[i].iftype];
+
+ ea = interfaces[i].ea;
+ bcm_bprintf(strbuf, "INTERFACE[%d].ea = "
+ "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d, type: %s "
+ "netif_flow_control:%s\n", i,
+ ea[0], ea[1], ea[2], ea[3], ea[4], ea[5],
+ interfaces[i].interface_id,
+ iftype_desc, ((wlfc->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);
+ }
+
+#if defined(DHD_WLFC_THREAD)
+ _dhd_wlfc_thread_wakeup(dhd);
+#endif /* defined(DHD_WLFC_THREAD) */
+
+ 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));
+ }
+ }
+ 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/drivers/net/wireless/bcmdhd_1363/dhd_wlfc.h b/drivers/net/wireless/bcmdhd_1363/dhd_wlfc.h
new file mode 100644
index 000000000000..fca554375be3
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dhd_wlfc.h
@@ -0,0 +1,554 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhd_wlfc.h 557035 2015-05-15 18:48:57Z $
+ *
+ */
+#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 2048
+
+#define WLFC_FLOWCONTROL_HIWATER (2048 - 256)
+#define WLFC_FLOWCONTROL_LOWATER 256
+
+#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_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 seq number for every suppress 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);
+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/drivers/net/wireless/bcmdhd_1363/dngl_stats.h b/drivers/net/wireless/bcmdhd_1363/dngl_stats.h
new file mode 100644
index 000000000000..d80235463fe0
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/dngl_stats.h
@@ -0,0 +1,324 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dngl_stats.h 629377 2016-04-05 05:22:34Z $
+ */
+
+#ifndef _dngl_stats_h_
+#define _dngl_stats_h_
+
+#include <proto/ethernet.h>
+#include <proto/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 */
+
+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 */
+} __attribute__ ((packed)) 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_v2;
+
+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;
+
+
+/* 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;
+
+/* per rate statistics */
+typedef struct {
+ wifi_rate 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;
+
+typedef struct {
+ uint16 version;
+ uint16 length;
+ uint32 tx_mpdu;
+ uint32 rx_mpdu;
+ uint32 mpdu_lost;
+ uint32 retries;
+ uint32 retries_short;
+ uint32 retries_long;
+ wifi_rate_v2 rate;
+} wifi_rate_stat_v2;
+
+
+/* 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;
+
+#endif /* _dngl_stats_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/dngl_wlhdr.h b/drivers/net/wireless/bcmdhd_1363/dngl_wlhdr.h
new file mode 100644
index 000000000000..96da42e5f570
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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/drivers/net/wireless/bcmdhd_1363/hnd_pktpool.c b/drivers/net/wireless/bcmdhd_1363/hnd_pktpool.c
new file mode 100644
index 000000000000..902533298dfd
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/hnd_pktpool.c
@@ -0,0 +1,1131 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: hnd_pktpool.c 591285 2015-10-07 11:56:29Z $
+ */
+
+#include <typedefs.h>
+#include <osl.h>
+#include <osl_ext.h>
+#include <bcmutils.h>
+#include <hnd_pktpool.h>
+
+/* 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 int 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;
+}
+
+int /* Construct a pool registry to serve a maximum of total_pools */
+pktpool_attach(osl_t *osh, uint32 total_pools)
+{
+ uint32 poolid;
+
+ 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;
+}
+
+int /* Destruct the pool registry. Ascertain all pools were first de-inited */
+pktpool_dettach(osl_t *osh)
+{
+ uint32 poolid;
+
+ 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;
+}
+
+static int /* Register a pool in a free slot; return the registry slot index */
+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 */
+}
+
+static int /* Deregister a pktpool, given the pool pointer; tag slot as free */
+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 sturcture and specifies the number of packets to
+ * be pre-filled into the pool (pplen). The size of all packets in a pool must
+ * be the same and is specified by plen.
+ * 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.
+ */
+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;
+ return err;
+}
+
+/*
+ * 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;
+}
+/* Callback functions for split rx modes */
+/* when evr host posts rxbuffer, invike 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);
+}
+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;
+}
+/* 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;
+}
+
+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;
+}
+
+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)
+{
+ 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;
+
+ 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 int
+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 0;
+ }
+
+ 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 0;
+}
+
+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;
+}
+
+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 <hnd_lbuf.h>
+
+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;
+
+void
+hnd_pktpool_init(osl_t *osh)
+{
+ 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);
+ return;
+ }
+
+ pktpool_shared = MALLOCZ(osh, sizeof(pktpool_t));
+ if (pktpool_shared == NULL) {
+ ASSERT(0);
+ goto error1;
+ }
+
+#if defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED)
+ pktpool_shared_lfrag = MALLOCZ(osh, sizeof(pktpool_t));
+ if (pktpool_shared_lfrag == NULL) {
+ ASSERT(0);
+ goto error2;
+ }
+#endif
+
+#if defined(BCMRXFRAGPOOL) && !defined(BCMRXFRAGPOOL_DISABLED)
+ pktpool_shared_rxlfrag = MALLOCZ(osh, sizeof(pktpool_t));
+ if (pktpool_shared_rxlfrag == NULL) {
+ ASSERT(0);
+ 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 (pktpool_init(osh, pktpool_shared,
+ &n, PKTBUFSZ, FALSE, lbuf_basic) == BCME_ERROR) {
+ ASSERT(0);
+ goto error4;
+ }
+ pktpool_setmaxlen(pktpool_shared, SHARED_POOL_LEN);
+
+#if defined(BCMFRAGPOOL) && !defined(BCMFRAGPOOL_DISABLED)
+ n = 1;
+ if (pktpool_init(osh, pktpool_shared_lfrag,
+ &n, PKTFRAGSZ, TRUE, lbuf_frag) == BCME_ERROR) {
+ ASSERT(0);
+ goto error5;
+ }
+ pktpool_setmaxlen(pktpool_shared_lfrag, SHARED_FRAG_POOL_LEN);
+#endif
+#if defined(BCMRXFRAGPOOL) && !defined(BCMRXFRAGPOOL_DISABLED)
+ n = 1;
+ if (pktpool_init(osh, pktpool_shared_rxlfrag,
+ &n, PKTRXFRAGSZ, TRUE, lbuf_rxfrag) == BCME_ERROR) {
+ ASSERT(0);
+ goto error6;
+ }
+ pktpool_setmaxlen(pktpool_shared_rxlfrag, SHARED_RXFRAG_POOL_LEN);
+#endif
+
+ pktpool_osh = osh;
+
+ return;
+
+#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);
+}
+
+void
+hnd_pktpool_fill(pktpool_t *pktpool, bool minimal)
+{
+ pktpool_fill(pktpool_osh, pktpool, minimal);
+}
+
+/* refill 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)) {
+ 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/drivers/net/wireless/bcmdhd_1363/hnd_pktq.c b/drivers/net/wireless/bcmdhd_1363/hnd_pktq.c
new file mode 100644
index 000000000000..269dd32f999c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/hnd_pktq.c
@@ -0,0 +1,886 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: hnd_pktq.c 657686 2016-09-02 06:39:10Z $
+ */
+
+#include <typedefs.h>
+#include <osl.h>
+#include <osl_ext.h>
+#include <bcmutils.h>
+#include <hnd_pktq.h>
+
+/* 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;
+}
+
+void
+pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg)
+{
+ struct pktq_prec *q;
+ void *p, *next, *prev = NULL;
+
+ /* protect shared resource */
+ if (HND_PKTQ_MUTEX_ACQUIRE(&pq->mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
+ return;
+
+ q = &pq->q[prec];
+ p = q->head;
+ while (p) {
+ next = PKTLINK(p);
+ if (fn == NULL || (*fn)(p, arg)) {
+ bool head = (p == q->head);
+ if (head)
+ q->head = next;
+ else
+ PKTSETLINK(prev, next);
+ PKTSETLINK(p, NULL);
+ PKTFREE(osh, p, dir);
+ q->len--;
+ pq->len--;
+ } else {
+ prev = p;
+ }
+ p = next;
+ }
+
+ q->tail = prev;
+
+ if (q->head == NULL) {
+ ASSERT(q->len == 0);
+ ASSERT(q->tail == NULL);
+ }
+
+ /* protect shared resource */
+ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
+ return;
+}
+
+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;
+}
+
+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)
+{
+ 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_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
+{
+ int prec;
+
+ /* 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)
+ goto done;
+
+ for (prec = 0; prec < pq->num_prec; prec++)
+ pktq_pflush(osh, pq, prec, dir, fn, arg);
+ if (fn == NULL)
+ ASSERT(pq->len == 0);
+
+done:
+ /* protect shared resource */
+ if (HND_PKTQ_MUTEX_RELEASE(&pq->mutex) != OSL_EXT_SUCCESS)
+ return;
+}
+
+/* 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--;
+
+ 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/drivers/net/wireless/bcmdhd_1363/hndpmu.c b/drivers/net/wireless/bcmdhd_1363/hndpmu.c
new file mode 100644
index 000000000000..25018874abe4
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/hndpmu.c
@@ -0,0 +1,292 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: hndpmu.c 530092 2015-01-29 04:44:58Z $
+ */
+
+
+/*
+ * 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 <bcm_cfg.h>
+#include <typedefs.h>
+#include <bcmdefs.h>
+#include <osl.h>
+#include <bcmutils.h>
+#include <siutils.h>
+#include <bcmdevs.h>
+#include <hndsoc.h>
+#include <sbchipc.h>
+#include <hndpmu.h>
+
+#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;
+ }
+
+ /* 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), sih->pmurev)) {
+ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
+ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab1;
+ str_mask = 0x30000000;
+ str_shift = 28;
+ break;
+ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
+ case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
+ case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4):
+ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2;
+ str_mask = 0x00003800;
+ str_shift = 11;
+ break;
+ case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
+ case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11):
+ if (sih->pmurev == 8) {
+ str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3;
+ }
+ else if (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), 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 */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/aidmp.h b/drivers/net/wireless/bcmdhd_1363/include/aidmp.h
new file mode 100644
index 000000000000..bd49c982691f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/aidmp.h
@@ -0,0 +1,402 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: aidmp.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#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_TIMEOUT_MASK 0x3
+
+/* 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)
+
+#endif /* _AIDMP_H */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/bcm_cfg.h b/drivers/net/wireless/bcmdhd_1363/include/bcm_cfg.h
new file mode 100644
index 000000000000..12e3cb2ca27a
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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/drivers/net/wireless/bcmdhd_1363/include/bcm_mpool_pub.h b/drivers/net/wireless/bcmdhd_1363/include/bcm_mpool_pub.h
new file mode 100644
index 000000000000..1e9a3ced5a9e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcm_mpool_pub.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#ifndef _BCM_MPOOL_PUB_H
+#define _BCM_MPOOL_PUB_H 1
+
+#include <typedefs.h> /* 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.
+ *
+ */
+int 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/drivers/net/wireless/bcmdhd_1363/include/bcm_ring.h b/drivers/net/wireless/bcmdhd_1363/include/bcm_ring.h
new file mode 100644
index 000000000000..3681c9d481e2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/bcm_ring.h
@@ -0,0 +1,616 @@
+#ifndef __bcm_ring_included__
+#define __bcm_ring_included__
+
+/*
+ * +----------------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * +----------------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcm_ring.h 591283 2015-10-07 11:52:00Z $
+ *
+ * -*- 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/drivers/net/wireless/bcmdhd_1363/include/bcmcdc.h b/drivers/net/wireless/bcmdhd_1363/include/bcmcdc.h
new file mode 100644
index 000000000000..a7d3d4af6e39
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmcdc.h 514727 2014-11-12 03:02:48Z $
+ */
+#ifndef _bcmcdc_h_
+#define _bcmcdc_h_
+#include <proto/ethernet.h>
+
+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/drivers/net/wireless/bcmdhd_1363/include/bcmdefs.h b/drivers/net/wireless/bcmdhd_1363/include/bcmdefs.h
new file mode 100644
index 000000000000..764f54f0815c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/bcmdefs.h
@@ -0,0 +1,382 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmdefs.h 601026 2015-11-20 06:53:19Z $
+ */
+
+#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).
+ */
+
+#define bcmreclaimed 0
+#define _data _data
+#define _fn _fn
+#define BCMPREATTACHDATA(_data) _data
+#define BCMPREATTACHFN(_fn) _fn
+#define _data _data
+#define _fn _fn
+#define _fn _fn
+#define BCMNMIATTACHFN(_fn) _fn
+#define BCMNMIATTACHDATA(_data) _data
+#define CONST const
+
+#undef BCM47XX_CA9
+
+#ifndef BCMFASTPATH
+#define BCMFASTPATH
+#define BCMFASTPATH_HOST
+#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
+
+/* 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
+
+/* 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)(_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 */
+#define BCMEXTRAHDROOM 204
+#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 <NAME>_M BITFIELD_MASK(3)
+ * #define <NAME>_S 4
+ * ...
+ * regval = R_REG(osh, &regs->regfoo);
+ * field = GFIELD(regval, <NAME>);
+ * regval = SFIELD(regval, <NAME>, 1);
+ * W_REG(osh, &regs->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 */
+#define RXMODE1 1 /* descriptor split */
+#define RXMODE2 2 /* descriptor split + classification */
+#define RXMODE3 3 /* fifo split + classification */
+#define RXMODE4 4 /* fifo split + classification + hdr conversion */
+
+#ifdef BCMSPLITRX /* BCMLFRAG support enab macros */
+ extern bool _bcmsplitrx;
+ extern uint8 _bcmsplitrx_mode;
+ #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD)
+ #define BCMSPLITRX_ENAB() (_bcmsplitrx)
+ #define BCMSPLITRX_MODE() (_bcmsplitrx_mode)
+ #elif defined(BCMSPLITRX_DISABLED)
+ #define BCMSPLITRX_ENAB() (0)
+ #define BCMSPLITRX_MODE() (0)
+ #else
+ #define BCMSPLITRX_ENAB() (1)
+ #define BCMSPLITRX_MODE() (_bcmsplitrx_mode)
+ #endif
+#else
+ #define BCMSPLITRX_ENAB() (0)
+ #define BCMSPLITRX_MODE() (0)
+#endif /* BCMSPLITRX */
+
+#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 SPLIT_RXMODE1() ((BCMSPLITRX_MODE() == RXMODE1))
+#define SPLIT_RXMODE2() ((BCMSPLITRX_MODE() == RXMODE2))
+#define SPLIT_RXMODE3() ((BCMSPLITRX_MODE() == RXMODE3))
+#define SPLIT_RXMODE4() ((BCMSPLITRX_MODE() == RXMODE4))
+
+#define PKT_CLASSIFY() (SPLIT_RXMODE2() || SPLIT_RXMODE3() || SPLIT_RXMODE4())
+#define RXFIFO_SPLIT() (SPLIT_RXMODE3() || SPLIT_RXMODE4())
+#define HDR_CONV() (SPLIT_RXMODE4())
+
+#define PKT_CLASSIFY_EN(x) ((PKT_CLASSIFY()) && (PKT_CLASSIFY_FIFO == (x)))
+#ifdef BCM_SPLITBUF
+ extern bool _bcmsplitbuf;
+ #if defined(WL_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD)
+ #define BCM_SPLITBUF_ENAB() (_bcmsplitbuf)
+ #elif defined(BCM_SPLITBUF_DISABLED)
+ #define BCM_SPLITBUF_ENAB() (0)
+ #else
+ #define BCM_SPLITBUF_ENAB() (1)
+ #endif
+#else
+ #define BCM_SPLITBUF_ENAB() (0)
+#endif /* BCM_SPLITBUF */
+
+/* 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;
+
+
+#endif /* _bcmdefs_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/bcmdevs.h b/drivers/net/wireless/bcmdhd_1363/include/bcmdevs.h
new file mode 100644
index 000000000000..5051abf68cb9
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/bcmdevs.h
@@ -0,0 +1,806 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmdevs.h 627766 2016-03-28 11:12:28Z $
+ */
+
+#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_BDC_PID 0x0bdc
+#define BCM_DNGL_JTAG_PID 0x4a44
+
+/* HW USB BLOCK [CPULESS USB] PIDs */
+#define BCM_HWUSB_PID_43239 43239
+
+/* PCI Device IDs */
+#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_D11G_ID 0x4318 /* 4318 802.11b/g id */
+#define BCM4318_D11DUAL_ID 0x4319 /* 4318 802.11a/b/g 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_D11G_ID 0x4320 /* 4306 802.11g */
+#define BCM4306_D11A_ID 0x4321 /* 4306 802.11a */
+#define BCM4306_UART_ID 0x4322 /* 4306 uart */
+#define BCM4306_V90_ID 0x4323 /* 4306 v90 codec */
+#define BCM4306_D11DUAL_ID 0x4324 /* 4306 dual A+B */
+#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 BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */
+#define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db device */
+#define BCM43226_D11N_ID 0x4354 /* 43226 802.11n dualband 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 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 */
+
+/* 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 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 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) */
+#define BCM4712_MIPS_ID 0x4720 /* 4712 base devid */
+#define BCM4716_DEVICE_ID 0x4722 /* 4716 base devid */
+#define BCM47XX_USB30H_ID 0x472a /* 47xx usb 3.0 host */
+#define BCM47XX_USB30D_ID 0x472b /* 47xx usb 3.0 device */
+#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 */
+
+/* Chip IDs */
+#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 BCM4313_CHIP_ID 0x4313 /* 4313 chip id */
+#define BCM43131_CHIP_ID 43131 /* 43131 chip id (OTP 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 BCM43217_CHIP_ID 43217 /* 43217 chip id (OTP 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 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 BCM43226_CHIP_ID 43226 /* 43226 chipcommon chipid */
+#define BCM43231_CHIP_ID 43231 /* 43231 chipcommon chipid (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 BCM4325_CHIP_ID 0x4325 /* 4325 chip id */
+#define BCM4328_CHIP_ID 0x4328 /* 4328 chip id */
+#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */
+#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 BCM43556_CHIP_ID 0xAA24 /* 43556 chipcommon chipid */
+#define BCM43558_CHIP_ID 0xAA26 /* 43558 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 BCM43012_CHIP_ID 0xA804 /* 43012 chipcommon chipid */
+#define BCM4350_CHIP(chipid) ((CHIPID(chipid) == BCM4350_CHIP_ID) || \
+ (CHIPID(chipid) == BCM4354_CHIP_ID) || \
+ (CHIPID(chipid) == BCM4356_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 BCM43430_CHIP_ID 43430 /* 43430 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 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 BCM4349_CHIP_GRPID BCM4349_CHIP_ID: \
+ case BCM4355_CHIP_ID: \
+ case BCM4359_CHIP_ID
+
+#define BCM4365_CHIP_ID 0x4365 /* 4365 chipcommon chipid */
+#define BCM4366_CHIP_ID 0x4366 /* 4366 chipcommon chipid */
+
+#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 CASE_BCM43602_CHIP case BCM43602_CHIP_ID: /* fallthrough */ \
+ case BCM43462_CHIP_ID: /* fallthrough */ \
+ case BCM43522_CHIP_ID
+
+#define BCM4342_CHIP_ID 4342 /* 4342 chipcommon chipid (OTP, RBBU) */
+#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 BCM4712_CHIP_ID 0x4712 /* 4712 chipcommon chipid */
+#define BCM4716_CHIP_ID 0x4716 /* 4716 chipcommon chipid */
+#define BCM47162_CHIP_ID 47162 /* 47162 chipcommon chipid */
+#define BCM4748_CHIP_ID 0x4748 /* 4716 chipcommon chipid (OTP, RBBU) */
+#define 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 BCM5354_CHIP_ID 0x5354 /* 5354 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 BCM53573_CHIP(chipid) (CHIPID(chipid) == BCM53573_CHIP_ID)
+#define BCM53573_CHIP_GRPID BCM53573_CHIP_ID
+
+/* Package IDs */
+#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 */
+#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 13 radio disable indication, UNUSED */
+#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 */
+
+
+/* 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
+
+/* 43602 Boards, unclear yet what boards will be created. */
+#define BCM943602RSVD1_SSID 0x06a5
+#define BCM943602RSVD2_SSID 0x06a6
+#define BCM943602X87 0X0133
+#define BCM943602X87P2 0X0143
+#define BCM943602X238 0X0132
+#define BCM943602X238D 0X014A
+
+/* # 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/drivers/net/wireless/bcmdhd_1363/include/bcmendian.h b/drivers/net/wireless/bcmdhd_1363/include/bcmendian.h
new file mode 100644
index 000000000000..00adedf1cd97
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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 <typedefs.h>
+
+/* 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/drivers/net/wireless/bcmdhd_1363/include/bcmmsgbuf.h b/drivers/net/wireless/bcmdhd_1363/include/bcmmsgbuf.h
new file mode 100644
index 000000000000..ca0bb21483db
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/bcmmsgbuf.h
@@ -0,0 +1,863 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmmsgbuf.h 541060 2015-03-13 23:28:01Z $
+ */
+#ifndef _bcmmsgbuf_h_
+#define _bcmmsgbuf_h_
+
+#include <proto/ethernet.h>
+#include <wlioctl.h>
+#include <bcmpcie.h>
+
+#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 16
+#define D2HRING_RXCMPLT_ITEMSIZE 32
+#define D2HRING_CTRL_CMPLT_ITEMSIZE 24
+
+#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 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
+
+#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,
+ MSG_TYPE_FLOW_RING_DELETE = 0x5,
+ MSG_TYPE_FLOW_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_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
+} 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;
+
+
+/* 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
+
+
+/* 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;
+
+
+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;
+ uint32 rsvd;
+} 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;
+ uint8 priority;
+ 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;
+ };
+} ring_config_req_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;
+ unsigned char check[H2DRING_CTRL_SUB_ITEMSIZE];
+} ctrl_submit_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 */
+ uint16 flow_ring_id;
+} compl_msg_hdr_t;
+
+/** XOR checksum or a magic number to audit DMA done */
+typedef uint32 dma_done_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
+
+/** 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 tx_flowring_create_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_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 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;
+ unsigned char check[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 */
+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 */
+ dma_done_t marker;
+} 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)
+
+/* 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 */
+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 */
+ dma_done_t marker;
+ };
+} 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;
+
+#endif /* _bcmmsgbuf_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/bcmnvram.h b/drivers/net/wireless/bcmdhd_1363/include/bcmnvram.h
new file mode 100644
index 000000000000..7f6c51be3e04
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/bcmnvram.h
@@ -0,0 +1,310 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmnvram.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#ifndef _bcmnvram_h_
+#define _bcmnvram_h_
+
+#ifndef _LANGUAGE_ASSEMBLY
+
+#include <typedefs.h>
+#include <bcmdefs.h>
+
+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);
+ 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);
+ 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);
+ 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/drivers/net/wireless/bcmdhd_1363/include/bcmpcie.h b/drivers/net/wireless/bcmdhd_1363/include/bcmpcie.h
new file mode 100644
index 000000000000..b75b3017aecf
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/bcmpcie.h
@@ -0,0 +1,318 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmpcie.h 604490 2015-12-07 15:48:45Z $
+ */
+
+
+#ifndef _bcmpcie_h_
+#define _bcmpcie_h_
+
+#include <bcmutils.h>
+
+#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 */
+
+/**
+ * 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 0x00005
+#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
+#define PCIE_SHARED_TXPUSH_SPRT 0x04000
+#define PCIE_SHARED_EVT_SEQNUM 0x08000
+#define PCIE_SHARED_DMA_INDEX 0x10000
+
+/**
+ * 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_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))
+
+/**
+ * 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, e.g. 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_sub_queues; /* maximum number of H2D rings: common + flow */
+ uint16 rsvd;
+} 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 buzzz; /* BUZZZ state format strings and trace buffer */
+
+} pciedev_shared_t;
+
+extern pciedev_shared_t pciedev_shared;
+
+/**
+ * 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 /**< dump HW reg info for Livelock issue */
+#define H2D_HOST_D0_INFORM_IN_USE 0x00000008
+#define H2D_HOST_D0_INFORM 0x00000010
+
+/* 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_MB_MASK (D2H_DEV_D3_ACK | D2H_DEV_DS_ENTER_REQ | \
+ D2H_DEV_DS_EXIT_NOTE | D2H_DEV_FWHALT)
+#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) \
+ MIN(WRITE_SPACE_AVAIL(r, w, d), WRITE_SPACE_AVAIL_CONTINUOUS(r, w, d))
+
+
+#define WRT_PEND(x) ((x)->wr_pending)
+#define DNGL_RING_WPTR(msgbuf) (*((msgbuf)->tcm_rs_w_ptr))
+#define BCMMSGBUF_RING_SET_W_PTR(msgbuf, a) (DNGL_RING_WPTR(msgbuf) = (a))
+
+#define DNGL_RING_RPTR(msgbuf) (*((msgbuf)->tcm_rs_r_ptr))
+#define BCMMSGBUF_RING_SET_R_PTR(msgbuf, a) (DNGL_RING_RPTR(msgbuf) = (a))
+
+#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)
+
+#endif /* _bcmpcie_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/bcmpcispi.h b/drivers/net/wireless/bcmdhd_1363/include/bcmpcispi.h
new file mode 100644
index 000000000000..b3502ea7b884
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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/drivers/net/wireless/bcmdhd_1363/include/bcmperf.h b/drivers/net/wireless/bcmdhd_1363/include/bcmperf.h
new file mode 100644
index 000000000000..09e607fc9b74
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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/drivers/net/wireless/bcmdhd_1363/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd_1363/include/bcmsdbus.h
new file mode 100644
index 000000000000..88635f1eaec2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/bcmsdbus.h
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmsdbus.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#ifndef _sdio_api_h_
+#define _sdio_api_h_
+
+
+#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 40
+#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
+
+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 *);
+
+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_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);
+
+#endif /* _sdio_api_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/bcmsdh.h b/drivers/net/wireless/bcmdhd_1363/include/bcmsdh.h
new file mode 100644
index 000000000000..17d33c6c1eb2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/bcmsdh.h
@@ -0,0 +1,255 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmsdh.h 662741 2016-11-08 09:37: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)
+#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 *);
+
+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 */
+};
+
+/* 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);
+
+/* 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, uint32 addr, uint size);
+extern uint32 bcmsdh_reg_write(void *sdh, uint32 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 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/drivers/net/wireless/bcmdhd_1363/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd_1363/include/bcmsdh_sdmmc.h
new file mode 100644
index 000000000000..102c05c8d083
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/bcmsdh_sdmmc.h
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Proprietary,Open:>>
+ *
+ * $Id: bcmsdh_sdmmc.h 662770 2016-11-11 02:02:03Z $
+ */
+
+#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)
+#define sd_info(x)
+#define sd_debug(x)
+#define sd_data(x)
+#define sd_ctrl(x)
+
+#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];
+
+};
+
+/************************************************************
+ * 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);
+#endif /* __BCMSDH_SDMMC_H__ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd_1363/include/bcmsdpcm.h
new file mode 100644
index 000000000000..78f212ad80f8
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/bcmsdpcm.h
@@ -0,0 +1,281 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmsdpcm.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#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 */
+#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_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_FC_CHANGE | I_HMB_FRAME_IND | I_HMB_HOST_INT)
+
+/* tohostmailbox bits corresponding to intstatus bits */
+#define HMB_FC_ON (1 << 0) /* To Host Mailbox Flow Control State */
+#define HMB_FC_CHANGE (1 << 1) /* To Host Mailbox Flow Control State Changed */
+#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 */
+
+#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
+
+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;
+} sdpcm_shared_t;
+
+extern sdpcm_shared_t sdpcm_shared;
+
+#endif /* _bcmsdpcm_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/bcmsdspi.h b/drivers/net/wireless/bcmdhd_1363/include/bcmsdspi.h
new file mode 100644
index 000000000000..537876c3696d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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/drivers/net/wireless/bcmdhd_1363/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd_1363/include/bcmsdstd.h
new file mode 100644
index 000000000000..ff3b0d1f2750
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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/drivers/net/wireless/bcmdhd_1363/include/bcmspi.h b/drivers/net/wireless/bcmdhd_1363/include/bcmspi.h
new file mode 100644
index 000000000000..9b4bd2d8ac0d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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/drivers/net/wireless/bcmdhd_1363/include/bcmspibrcm.h b/drivers/net/wireless/bcmdhd_1363/include/bcmspibrcm.h
new file mode 100644
index 000000000000..e9735ffc621a
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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/drivers/net/wireless/bcmdhd_1363/include/bcmsrom_fmt.h b/drivers/net/wireless/bcmdhd_1363/include/bcmsrom_fmt.h
new file mode 100644
index 000000000000..2eabfaf62709
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/bcmsrom_fmt.h
@@ -0,0 +1,965 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmsrom_fmt.h 553280 2015-04-29 07:55:29Z $
+ */
+
+#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_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
+
+
+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/drivers/net/wireless/bcmdhd_1363/include/bcmsrom_tbl.h b/drivers/net/wireless/bcmdhd_1363/include/bcmsrom_tbl.h
new file mode 100644
index 000000000000..acc9b91c98da
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/bcmsrom_tbl.h
@@ -0,0 +1,1400 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmsrom_tbl.h 553564 2015-04-30 06:19:30Z $
+ */
+
+#ifndef _bcmsrom_tbl_h_
+#define _bcmsrom_tbl_h_
+
+#include "sbpcmcia.h"
+#include "wlioctl.h"
+#include <bcmsrom_fmt.h>
+
+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, 0x00ff},
+ {"regrev", 0x000000e0, 0, SROM5_REGREV, 0x00ff},
+ {"regrev", 0x00000700, 0, SROM8_REGREV, 0x00ff},
+ {"ledbh0", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff},
+ {"ledbh1", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00},
+ {"ledbh2", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff},
+ {"ledbh3", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00},
+ {"ledbh0", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff},
+ {"ledbh1", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00},
+ {"ledbh2", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff},
+ {"ledbh3", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00},
+ {"ledbh0", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff},
+ {"ledbh1", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00},
+ {"ledbh2", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff},
+ {"ledbh3", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00},
+ {"ledbh0", 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, 0x00ff},
+ {"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},
+ /* 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},
+
+ {"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, 2, "1regrev"},
+ {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"},
+ {0xFF, 0xffffffff, 0, ""}
+};
+
+#endif /* _bcmsrom_tbl_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/bcmutils.h b/drivers/net/wireless/bcmdhd_1363/include/bcmutils.h
new file mode 100644
index 000000000000..e750f30d2e0e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/bcmutils.h
@@ -0,0 +1,1304 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmutils.h 665091 2017-05-19 06:11:53Z $
+ */
+
+#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
+ *
+ */
+
+/* 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 <osl.h>
+#include <hnd_pktq.h>
+#include <hnd_pktpool.h>
+
+#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 BCM_MAC_RXCPL_IDX_BITS 12
+#define BCM_MAX_RXCPL_IDX_INVALID 0
+#define BCM_MAC_RXCPL_IFIDX_BITS 3
+#define BCM_MAC_RXCPL_DOT11_BITS 1
+#define BCM_MAX_RXCPL_IFIDX ((1 << BCM_MAC_RXCPL_IFIDX_BITS) - 1)
+#define BCM_MAC_RXCPL_FLAG_BITS 4
+#define BCM_RXCPL_FLAGS_IN_TRANSIT 0x1
+#define BCM_RXCPL_FLAGS_FIRST_IN_FLUSHLIST 0x2
+#define BCM_RXCPL_FLAGS_RXCPLVALID 0x4
+#define BCM_RXCPL_FLAGS_RSVD 0x8
+
+#define BCM_RXCPL_SET_IN_TRANSIT(a) ((a)->rxcpl_id.flags |= BCM_RXCPL_FLAGS_IN_TRANSIT)
+#define BCM_RXCPL_CLR_IN_TRANSIT(a) ((a)->rxcpl_id.flags &= ~BCM_RXCPL_FLAGS_IN_TRANSIT)
+#define BCM_RXCPL_IN_TRANSIT(a) ((a)->rxcpl_id.flags & BCM_RXCPL_FLAGS_IN_TRANSIT)
+
+#define BCM_RXCPL_SET_FRST_IN_FLUSH(a) ((a)->rxcpl_id.flags |= BCM_RXCPL_FLAGS_FIRST_IN_FLUSHLIST)
+#define BCM_RXCPL_CLR_FRST_IN_FLUSH(a) ((a)->rxcpl_id.flags &= ~BCM_RXCPL_FLAGS_FIRST_IN_FLUSHLIST)
+#define BCM_RXCPL_FRST_IN_FLUSH(a) ((a)->rxcpl_id.flags & BCM_RXCPL_FLAGS_FIRST_IN_FLUSHLIST)
+
+#define BCM_RXCPL_SET_VALID_INFO(a) ((a)->rxcpl_id.flags |= BCM_RXCPL_FLAGS_RXCPLVALID)
+#define BCM_RXCPL_CLR_VALID_INFO(a) ((a)->rxcpl_id.flags &= ~BCM_RXCPL_FLAGS_RXCPLVALID)
+#define BCM_RXCPL_VALID_INFO(a) (((a)->rxcpl_id.flags & BCM_RXCPL_FLAGS_RXCPLVALID) ? TRUE : FALSE)
+
+#define UP_TABLE_MAX ((IPV4_TOS_DSCP_MASK >> IPV4_TOS_DSCP_SHIFT) + 1) /* 64 max */
+
+struct reorder_rxcpl_id_list {
+ uint16 head;
+ uint16 tail;
+ uint32 cnt;
+};
+
+typedef struct rxcpl_id {
+ uint32 idx : BCM_MAC_RXCPL_IDX_BITS;
+ uint32 next_idx : BCM_MAC_RXCPL_IDX_BITS;
+ uint32 ifidx : BCM_MAC_RXCPL_IFIDX_BITS;
+ uint32 dot11 : BCM_MAC_RXCPL_DOT11_BITS;
+ uint32 flags : BCM_MAC_RXCPL_FLAG_BITS;
+} rxcpl_idx_id_t;
+
+typedef struct rxcpl_data_len {
+ uint32 metadata_len_w : 6;
+ uint32 dataoffset: 10;
+ uint32 datalen : 16;
+} rxcpl_data_len_t;
+
+typedef struct rxcpl_info {
+ rxcpl_idx_id_t rxcpl_id;
+ uint32 host_pktref;
+ union {
+ rxcpl_data_len_t rxcpl_len;
+ struct rxcpl_info *free_next;
+ };
+} rxcpl_info_t;
+
+/* rx completion list */
+typedef struct bcm_rxcplid_list {
+ uint32 max;
+ uint32 avail;
+ rxcpl_info_t *rxcpl_ptr;
+ rxcpl_info_t *free_list;
+} bcm_rxcplid_list_t;
+
+extern bool bcm_alloc_rxcplid_list(osl_t *osh, uint32 max);
+extern rxcpl_info_t * bcm_alloc_rxcplinfo(void);
+extern void bcm_free_rxcplinfo(rxcpl_info_t *ptr);
+extern void bcm_chain_rxcplid(uint16 first, uint16 next);
+extern rxcpl_info_t *bcm_id2rxcplinfo(uint16 id);
+extern uint16 bcm_rxcplinfo2id(rxcpl_info_t *ptr);
+extern rxcpl_info_t *bcm_rxcpllist_end(rxcpl_info_t *ptr, uint32 *count);
+
+/* 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);
+
+/* Get priority from a packet and pass it back in scb (or equiv) */
+#define PKTPRIO_VDSCP 0x100 /* DSCP prio found after 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);
+
+/* 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);
+extern int bcm_atoicrc(const char *p, int *crc);
+extern void wipedates(const char *cp, int size);
+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);
+
+
+/* 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 */
+#define NVRAM_RECLAIM_CHECK(name)
+
+extern char *getvar(char *vars, const char *name);
+extern int getintvar(char *vars, const char *name);
+extern int getintvararray(char *vars, const char *name, int index);
+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 */
+ uint16 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);
+#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 */
+
+/* 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_LAST BCME_DATA_NOTFOUND
+
+#define BCME_NOTENABLED BCME_DISABLED
+
+/* 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", \
+}
+
+#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 <stddef.h>
+#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 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 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, uchar *buf, uint len);
+
+/* IE parsing */
+
+/* packing is required if struct is passed across the bus */
+#include <packed_section_start.h>
+/* tag_ID/length/value_buffer tuple */
+typedef struct bcm_tlv {
+ uint8 id;
+ uint8 len;
+ uint8 data[1];
+} bcm_tlv_t;
+
+/* 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 <packed_section_end.h>
+
+
+/* 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_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);
+
+/* 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, 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 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 ID16_INVALID ((uint16)(~0))
+#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);
+
+/* 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);
+
+#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 */
+
+/* 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);
+}
+
+#endif /* _bcmutils_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/brcm_nl80211.h b/drivers/net/wireless/bcmdhd_1363/include/brcm_nl80211.h
new file mode 100644
index 000000000000..43d66609a3a7
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/brcm_nl80211.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: brcm_nl80211.h 556083 2015-05-12 14:03:00Z $
+ *
+ */
+
+#ifndef _brcm_nl80211_h_
+#define _brcm_nl80211_h_
+
+#define OUI_BRCM 0x001018
+
+enum wl_vendor_subcmd {
+ BRCM_VENDOR_SCMD_UNSPEC,
+ BRCM_VENDOR_SCMD_PRIV_STR,
+ BRCM_VENDOR_SCMD_BCM_STR
+};
+
+
+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/drivers/net/wireless/bcmdhd_1363/include/dbus.h b/drivers/net/wireless/bcmdhd_1363/include/dbus.h
new file mode 100644
index 000000000000..de60a317aa91
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/dbus.h
@@ -0,0 +1,591 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dbus.h 553311 2015-04-29 10:23:08Z $
+ */
+
+#ifndef __DBUS_H__
+#define __DBUS_H__
+
+#include "typedefs.h"
+
+#define DBUSTRACE(args)
+#define DBUSERR(args)
+#define DBUSINFO(args)
+#define DBUSDBGLOCK(args)
+
+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
+};
+
+typedef struct {
+ uint32 config_id;
+ union {
+ 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, 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);
+ bool (*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 dbus_pub_t *dbus_attach(struct osl_info *osh, int rxsize, int nrxq, int ntxq,
+ void *cbarg, dbus_callbacks_t *cbs, dbus_extdl_t *extdl, struct shared_info *sh);
+extern void dbus_detach(dbus_pub_t *pub);
+
+extern int dbus_download_firmware(dbus_pub_t *pub);
+extern int dbus_up(dbus_pub_t *pub);
+extern int dbus_down(dbus_pub_t *pub);
+extern int dbus_stop(dbus_pub_t *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(dbus_pub_t *pub, uint8 *buf, int len);
+extern int dbus_recv_ctl(dbus_pub_t *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_attrib(dbus_pub_t *pub, dbus_attrib_t *attrib);
+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 dbus_iovar_op(dbus_pub_t *pub, 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/drivers/net/wireless/bcmdhd_1363/include/devctrl_if/wlioctl_defs.h b/drivers/net/wireless/bcmdhd_1363/include/devctrl_if/wlioctl_defs.h
new file mode 100644
index 000000000000..ca9e332b8afc
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/devctrl_if/wlioctl_defs.h
@@ -0,0 +1,2211 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wlioctl_defs.h 655604 2016-08-22 16:49:21Z $
+ */
+
+
+#ifndef wlioctl_defs_h
+#define wlioctl_defs_h
+
+
+
+
+/* All builds use the new 11ac ratespec/chanspec */
+#undef D11AC_IOTYPES
+#define D11AC_IOTYPES
+
+/* WL_RSPEC defines for rate information */
+#define WL_RSPEC_RATE_MASK 0x000000FF /* rate or HT MCS value */
+#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 both 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 */
+
+/* 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
+
+/* 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 HIGHEST_SINGLE_STREAM_MCS 7 /* MCS values greater than this enable multiple streams */
+#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 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 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 */
+
+#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 */
+/* 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
+#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_BTA_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_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
+
+#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.
+ */
+/* 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_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 */
+
+#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_BTA 4
+#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/drivers/net/wireless/bcmdhd_1363/include/dhdioctl.h b/drivers/net/wireless/bcmdhd_1363/include/dhdioctl.h
new file mode 100644
index 000000000000..561550fadf21
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/dhdioctl.h
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: dhdioctl.h 585723 2015-09-11 06:26:37Z $
+ */
+
+#ifndef _dhdioctl_h_
+#define _dhdioctl_h_
+
+#include <typedefs.h>
+
+
+/* require default structure packing */
+#define BWL_DEFAULT_PACKING
+#include <packed_section_start.h>
+
+
+/* Linux network driver ioctl encoding */
+typedef struct dhd_ioctl {
+ uint cmd; /* common ioctl definition */
+ void *buf; /* pointer to user buffer */
+ uint len; /* length of user buffer */
+ bool set; /* get or set request (optional) */
+ uint used; /* bytes read or written (optional) */
+ uint needed; /* bytes needed (optional) */
+ uint driver; /* to identify target driver */
+} 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
+
+#define DHD_IOCTL_MAXLEN 8192 /* 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_WL_VAL 0x10000
+#define DHD_NOCHECKDIED_VAL 0x20000 /* UTF WAR */
+#define DHD_WL_VAL2 0x40000
+#define DHD_PNO_VAL 0x80000
+#define DHD_MSGTRACE_VAL 0x100000
+#define DHD_FWLOG_VAL 0x400000
+#define DHD_RTT_VAL 0x200000
+#define DHD_IOV_INFO_VAL 0x800000
+
+#ifdef SDTEST
+/* For pktgen iovar */
+typedef struct dhd_pktgen {
+ uint version; /* To allow structure change tracking */
+ uint freq; /* Max ticks between tx/rx attempts */
+ uint count; /* Test packets to send/rcv each attempt */
+ uint print; /* Print counts every <print> attempts */
+ uint total; /* Total packets (or bursts) */
+ uint minlen; /* Minimum length of packets to send */
+ uint maxlen; /* Maximum length of packets to send */
+ uint numsent; /* Count of test packets sent */
+ uint numrcvd; /* Count of test packets received */
+ uint numfail; /* Count of test send failures */
+ uint mode; /* Test mode (type of test packets) */
+ uint stop; /* Stop after this many tx failures */
+} 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) */
+
+
+/* require default structure packing */
+#include <packed_section_end.h>
+
+#endif /* _dhdioctl_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/epivers.h b/drivers/net/wireless/bcmdhd_1363/include/epivers.h
new file mode 100644
index 000000000000..39690c39c0cc
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: epivers.h.in,v 13.33 2010-09-08 22:08:53 $
+ *
+*/
+
+#ifndef _epivers_h_
+#define _epivers_h_
+
+#define EPI_MAJOR_VERSION 1
+
+#define EPI_MINOR_VERSION 363
+
+#define EPI_RC_NUMBER 22
+
+#define EPI_INCREMENTAL_NUMBER 0
+
+#define EPI_BUILD_NUMBER 0
+
+#define EPI_VERSION 1, 363, 22, 0
+
+#define EPI_VERSION_NUM 0x0116b160
+
+#define EPI_VERSION_DEV 1.363.22
+
+/* Driver Version String, ASCII, 32 chars max */
+#define EPI_VERSION_STR "1.363.22 (r)"
+
+#endif /* _epivers_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/event_log.h b/drivers/net/wireless/bcmdhd_1363/include/event_log.h
new file mode 100644
index 000000000000..82f0c902c01e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/event_log.h
@@ -0,0 +1,349 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: event_log.h 591285 2015-10-07 11:56:29Z $
+ */
+
+#ifndef _EVENT_LOG_H_
+#define _EVENT_LOG_H_
+
+#include <typedefs.h>
+#include <proto/event_log_set.h>
+#include <proto/event_log_tag.h>
+
+/* 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
+
+/*
+ * 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 timestamp; /* Timestamp at start of use */
+ uint32 event_logs;
+} event_log_block_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_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 <num_sets> 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.
+ *
+ */
+
+#ifndef EVENT_LOG_DUMPER
+
+#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_LOG_ON(tag) 0
+
+#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 != 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 != 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))
+
+
+#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;
+
+#include <siutils.h>
+
+extern int event_log_init(si_t *sih);
+extern int event_log_set_init(si_t *sih, int set_num, int size);
+extern int event_log_set_expand(si_t *sih, int set_num, int size);
+extern int event_log_set_shrink(si_t *sih, 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);
+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);
+
+#endif /* EVENT_LOG_DUMPER */
+
+#endif /* EVENT_LOG_COMPILE */
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* _EVENT_LOG_H */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/hnd_armtrap.h b/drivers/net/wireless/bcmdhd_1363/include/hnd_armtrap.h
new file mode 100644
index 000000000000..e9ee8ff47581
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/hnd_armtrap.h
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: hnd_armtrap.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#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_4T__)
+#define MAX_TRAP_TYPE (TR_FIQ + 1)
+#elif defined(__ARM_ARCH_7M__)
+#define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS)
+#endif /* __ARM_ARCH_7M__ */
+
+/* The trap structure is defined here as offsets for assembly */
+#define TR_TYPE 0x00
+#define TR_EPC 0x04
+#define TR_CPSR 0x08
+#define TR_SPSR 0x0c
+#define TR_REGS 0x10
+#define TR_REG(n) (TR_REGS + (n) * 4)
+#define TR_SP TR_REG(13)
+#define TR_LR TR_REG(14)
+#define TR_PC TR_REG(15)
+
+#define TRAP_T_SIZE 80
+#define ASSERT_TRAP_SVC_NUMBER 255
+
+#ifndef _LANGUAGE_ASSEMBLY
+
+#include <typedefs.h>
+
+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/drivers/net/wireless/bcmdhd_1363/include/hnd_cons.h b/drivers/net/wireless/bcmdhd_1363/include/hnd_cons.h
new file mode 100644
index 000000000000..7b2b90a67cc4
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/hnd_cons.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: hnd_cons.h 514727 2014-11-12 03:02:48Z $
+ */
+#ifndef _hnd_cons_h_
+#define _hnd_cons_h_
+
+#include <typedefs.h>
+#include <siutils.h>
+
+#define CBUF_LEN (128)
+
+#define LOG_BUF_LEN 1024
+
+#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 <CR> 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/drivers/net/wireless/bcmdhd_1363/include/hnd_pktpool.h b/drivers/net/wireless/bcmdhd_1363/include/hnd_pktpool.h
new file mode 100644
index 000000000000..1b8c9beac67e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: hnd_pktpool.h 591285 2015-10-07 11:56:29Z $
+ */
+
+#ifndef _hnd_pktpool_h_
+#define _hnd_pktpool_h_
+
+#include <osl_ext.h>
+
+#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, 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)
+#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;
+
+void hnd_pktpool_init(osl_t *osh);
+void 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/drivers/net/wireless/bcmdhd_1363/include/hnd_pktq.h b/drivers/net/wireless/bcmdhd_1363/include/hnd_pktq.h
new file mode 100644
index 000000000000..82146f908396
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/hnd_pktq.h
@@ -0,0 +1,214 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: hnd_pktq.h 591283 2015-10-07 11:52:00Z $
+ */
+
+#ifndef _hnd_pktq_h_
+#define _hnd_pktq_h_
+
+#include <osl_ext.h>
+
+#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;
+
+typedef struct {
+ uint32 _prec_log;
+ pktq_counters_t* _prec_cnt[PKTQ_MAX_PREC]; /**< Counters per queue */
+} pktq_log_t;
+#endif /* PKTQ_LOG */
+
+
+#define PKTQ_COMMON \
+ 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];
+ HND_PKTQ_MUTEX_DECL(mutex)
+#ifdef PKTQ_LOG
+ pktq_log_t* pktqlog;
+#endif
+};
+
+/* 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];
+ HND_PKTQ_MUTEX_DECL(mutex)
+};
+
+#define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--)
+
+/* fn(pkt, arg). return true if pkt belongs to if */
+typedef bool (*ifpkt_cb_t)(void*, int);
+
+/* 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);
+/* Empty the queue at particular precedence level */
+extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir,
+ ifpkt_cb_t fn, int arg);
+/* 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) pktq_flush(osh, ((struct pktq *)(void *)pq), TRUE, NULL, 0)
+#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)
+
+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);
+extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _hnd_pktq_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/hndpmu.h b/drivers/net/wireless/bcmdhd_1363/include/hndpmu.h
new file mode 100644
index 000000000000..d9c2774a121d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/hndpmu.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: hndpmu.h 530150 2015-01-29 08:43:40Z $
+ */
+
+#ifndef _hndpmu_h_
+#define _hndpmu_h_
+
+#include <typedefs.h>
+#include <osl_decl.h>
+#include <siutils.h>
+
+
+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);
+
+#endif /* _hndpmu_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/hndsoc.h b/drivers/net/wireless/bcmdhd_1363/include/hndsoc.h
new file mode 100644
index 000000000000..aa32105d2b12
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/hndsoc.h
@@ -0,0 +1,315 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: hndsoc.h 517544 2014-11-26 00:40:42Z $
+ */
+
+#ifndef _HNDSOC_H
+#define _HNDSOC_H
+
+/* Include the soci specific files */
+#include <sbconfig.h>
+#include <aidmp.h>
+
+/*
+ * 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_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_DDRTYPE_MASK 0x10
+#define SI_BCM53573_DDRTYPE_DDR3 0x10
+
+/* 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 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__) */
+
+#endif /* _HNDSOC_H */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/linux_osl.h b/drivers/net/wireless/bcmdhd_1363/include/linux_osl.h
new file mode 100644
index 000000000000..cf95c53c6b70
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/linux_osl.h
@@ -0,0 +1,1088 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: linux_osl.h 601764 2015-11-24 03:47:41Z $
+ */
+
+#ifndef _linux_osl_h_
+#define _linux_osl_h_
+
+#include <typedefs.h>
+#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;
+
+/* 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)
+{
+}
+
+/* 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)
+
+/* 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 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 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 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_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()
+
+#if (!defined(DHD_USE_COHERENT_MEM_FOR_RING) && defined(__ARM_ARCH_7A__)) || \
+ (defined(STBLINUX) && defined(__ARM_ARCH_7A__)) || (defined(CONFIG_ARCH_MSM8996) || \
+ defined(CONFIG_SOC_EXYNOS8890))
+ 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)
+#ifdef __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
+ #define OSL_ARCH_IS_COHERENT() NULL
+ #define OSL_ACP_WAR_ENAB() NULL
+#endif /* __ARM_ARCH_7A__ */
+#else
+ #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 <bcmsdh.h>
+ #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))))
+#endif
+
+#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
+
+#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 <linuxver.h> /* use current 2.4.x calling conventions */
+#include <linux/kernel.h> /* for vsn/printf's */
+#include <linux/string.h> /* for mem*, str* */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29)
+#define OSL_SYSUPTIME() ((uint32)jiffies_to_msecs(jiffies))
+#else
+#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ))
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 29) */
+#define printf(fmt, args...) printk(fmt , ## args)
+#include <linux/kernel.h> /* for vsn/printf's */
+#include <linux/string.h> /* 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 */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 1)) && defined(CONFIG_64BIT) && \
+ defined(CONFIG_X86)
+#define R_REG(osh, r) (\
+ SELECT_BUS_READ(osh, \
+ ({ \
+ __typeof(*(r)) __osl_v; \
+ 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
+#define R_REG(osh, r) (\
+ SELECT_BUS_READ(osh, \
+ ({ \
+ __typeof(*(r)) __osl_v; \
+ 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 /* KERNEL_VERSION(3, 11, 1)) && defined(CONFIG_64BIT) && defined(CONFIG_X86) */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 1)) && defined(CONFIG_64BIT) && \
+ defined(CONFIG_X86)
+#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
+#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 /* KERNEL_VERSION(3, 11, 1)) && defined(CONFIG_64BIT) && defined(CONFIG_X86) */
+
+#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_nocache((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 <linuxver.h> /* 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) osl_pkt_orphan_partial(skb)
+extern void osl_pkt_orphan_partial(struct sk_buff *skb);
+#else
+#define PKTORPHAN(skb) ({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;
+ 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 HWRXOFF sized rx header (etc.h) */
+#define FWDER_HWRXOFF (30)
+
+/** Maximum amount of a pktadat that a downstream forwarder (GMAC) may have
+ * read into the L1 cache (not dirty). This may be used in reduced cache ops.
+ *
+ * Max 56: ET HWRXOFF[30] + BRCMHdr[4] + EtherHdr[14] + VlanHdr[4] + IP[4]
+ */
+#define FWDER_PKTMAPSZ (FWDER_HWRXOFF + 4 + 14 + 4 + 4)
+
+#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);
+
+#define DMA_MAP(osh, va, size, direction, p, dmah) \
+ osl_dma_map((osh), (va), (size), (direction), (p), (dmah))
+
+#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 <stdlib.h>
+
+/* str* and mem* functions */
+#include <string.h>
+
+/* *printf functions */
+#include <stdio.h>
+
+/* 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 */
+
+typedef struct sec_cma_info {
+ struct sec_mem_elem *sec_alloc_list;
+ struct sec_mem_elem *sec_alloc_list_tail;
+} sec_cma_info_t;
+
+/* 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))
+#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 32
+#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_ARMREGION 0x02 /* Region CMA */
+#else
+#define CONT_MIPREGION 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 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))
+
+#endif /* _linux_osl_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/linuxver.h b/drivers/net/wireless/bcmdhd_1363/include/linuxver.h
new file mode 100644
index 000000000000..83deb7926aa3
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/linuxver.h
@@ -0,0 +1,774 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: linuxver.h 604758 2015-12-08 12:01:08Z $
+ */
+
+#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 <typedefs.h>
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
+#include <linux/config.h>
+#else
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33))
+#include <generated/autoconf.h>
+#else
+#include <linux/autoconf.h>
+#endif
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0))
+#include <linux/kconfig.h>
+#endif
+#include <linux/module.h>
+
+#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 <linux/malloc.h>
+#else
+#include <linux/slab.h>
+#endif
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
+#include <linux/semaphore.h>
+#else
+#include <asm/semaphore.h>
+#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 <asm/io.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41))
+#include <linux/workqueue.h>
+#else
+#include <linux/tqueue.h>
+#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 <linux/sched.h>
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+#include <linux/sched/rt.h>
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
+#include <net/lib80211.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
+#include <linux/ieee80211.h>
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
+#include <net/ieee80211.h>
+#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(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_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 <linux/time.h>
+#include <linux/wait.h>
+#else
+#include <linux/sched.h>
+
+#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)) && !defined(WL_COMPAT_WIRELESS)
+#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))
+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/drivers/net/wireless/bcmdhd_1363/include/miniopt.h b/drivers/net/wireless/bcmdhd_1363/include/miniopt.h
new file mode 100644
index 000000000000..6722351436e3
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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/drivers/net/wireless/bcmdhd_1363/include/msgtrace.h b/drivers/net/wireless/bcmdhd_1363/include/msgtrace.h
new file mode 100644
index 000000000000..00e2b0f46bf8
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/msgtrace.h
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: msgtrace.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#ifndef _MSGTRACE_H
+#define _MSGTRACE_H
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+/* for osl_t */
+#include <osl_decl.h>
+#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)
+
+/* The hbus driver generates traces when sending a trace message. This causes endless traces.
+ * This flag must be set to TRUE in any hbus traces. The flag is reset in the function msgtrace_put.
+ * This prevents endless traces but generates hasardous lost of traces only in bus device code.
+ * It is recommendat to set this flag in macro SD_TRACE but not in SD_ERROR for avoiding missing
+ * hbus error traces. hbus error trace should not generates endless traces.
+ */
+extern bool msgtrace_hbus_trace;
+
+typedef void (*msgtrace_func_send_t)(void *hdl1, void *hdl2, uint8 *hdr,
+ uint16 hdrlen, uint8 *buf, uint16 buflen);
+extern void msgtrace_start(void);
+extern void msgtrace_stop(void);
+extern int msgtrace_sent(void);
+extern void msgtrace_put(char *buf, int count);
+extern void msgtrace_init(void *hdl1, void *hdl2, msgtrace_func_send_t func_send);
+extern bool msgtrace_event_enabled(void);
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* _MSGTRACE_H */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/osl.h b/drivers/net/wireless/bcmdhd_1363/include/osl.h
new file mode 100644
index 000000000000..bd08e8a18882
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/osl.h
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: osl.h 526460 2015-01-14 08:25:24Z $
+ */
+
+#ifndef _osl_h_
+#define _osl_h_
+
+#include <osl_decl.h>
+
+#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 <utest_osl.h>
+#else
+#include <linux_osl.h>
+#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 */
+
+#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)
+#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)
+#define PKTSETCHAINED(osh, skb) BCM_REFERENCE(osh)
+#define PKTCLRCHAINED(osh, skb) BCM_REFERENCE(osh)
+#define PKTISCHAINED(skb) FALSE
+#endif
+
+/* Lbuf with fraglist */
+#define PKTFRAGPKTID(osh, lb) (0)
+#define PKTSETFRAGPKTID(osh, lb, id) BCM_REFERENCE(osh)
+#define PKTFRAGTOTNUM(osh, lb) (0)
+#define PKTSETFRAGTOTNUM(osh, lb, tot) BCM_REFERENCE(osh)
+#define PKTFRAGTOTLEN(osh, lb) (0)
+#define PKTSETFRAGTOTLEN(osh, lb, len) BCM_REFERENCE(osh)
+#define PKTIFINDEX(osh, lb) (0)
+#define PKTSETIFINDEX(osh, lb, idx) BCM_REFERENCE(osh)
+#define PKTGETLF(osh, len, send, lbuf_type) (0)
+
+/* in rx path, reuse totlen as used len */
+#define PKTFRAGUSEDLEN(osh, lb) (0)
+#define PKTSETFRAGUSEDLEN(osh, lb, len) BCM_REFERENCE(osh)
+
+#define PKTFRAGLEN(osh, lb, ix) (0)
+#define PKTSETFRAGLEN(osh, lb, ix, len) BCM_REFERENCE(osh)
+#define PKTFRAGDATA_LO(osh, lb, ix) (0)
+#define PKTSETFRAGDATA_LO(osh, lb, ix, addr) BCM_REFERENCE(osh)
+#define PKTFRAGDATA_HI(osh, lb, ix) (0)
+#define PKTSETFRAGDATA_HI(osh, lb, ix, addr) BCM_REFERENCE(osh)
+
+/* RX FRAG */
+#define PKTISRXFRAG(osh, lb) (0)
+#define PKTSETRXFRAG(osh, lb) BCM_REFERENCE(osh)
+#define PKTRESETRXFRAG(osh, lb) BCM_REFERENCE(osh)
+
+/* TX FRAG */
+#define PKTISTXFRAG(osh, lb) (0)
+#define PKTSETTXFRAG(osh, lb) BCM_REFERENCE(osh)
+
+/* Need Rx completion used for AMPDU reordering */
+#define PKTNEEDRXCPL(osh, lb) (TRUE)
+#define PKTSETNORXCPL(osh, lb) BCM_REFERENCE(osh)
+#define PKTRESETNORXCPL(osh, lb) BCM_REFERENCE(osh)
+
+#define PKTISFRAG(osh, lb) (0)
+#define PKTFRAGISCHAINED(osh, i) (0)
+/* TRIM Tail bytes from lfrag */
+#define PKTFRAG_TRIM_TAILBYTES(osh, p, len, type) PKTSETLEN(osh, p, PKTLEN(osh, p) - len)
+
+#ifdef BCM_SECURE_DMA
+#define SECURE_DMA_ENAB(osh) (1)
+#else
+
+#define SECURE_DMA_ENAB(osh) (0)
+#define SECURE_DMA_MAP(osh, va, size, direction, p, dmah, pcma, offset) ((dmaaddr_t) {(0)})
+#define SECURE_DMA_DD_MAP(osh, va, size, direction, p, dmah) 0
+#define SECURE_DMA_MAP_TXMETA(osh, va, size, direction, p, dmah, pcma) ((dmaaddr_t) {(0)})
+#define SECURE_DMA_UNMAP(osh, pa, size, direction, p, dmah, pcma, offset)
+#define SECURE_DMA_UNMAP_ALL(osh, pcma)
+
+#endif
+
+
+#endif /* _osl_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/osl_decl.h b/drivers/net/wireless/bcmdhd_1363/include/osl_decl.h
new file mode 100644
index 000000000000..d859b8c208b6
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: osl_decl.h 591283 2015-10-07 11:52:00Z $
+ */
+
+#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/drivers/net/wireless/bcmdhd_1363/include/osl_ext.h b/drivers/net/wireless/bcmdhd_1363/include/osl_ext.h
new file mode 100644
index 000000000000..13d59b6a2f1f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: osl_ext.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#ifndef _osl_ext_h_
+#define _osl_ext_h_
+
+
+/* ---- Include Files ---------------------------------------------------- */
+
+#if defined(TARGETOS_symbian)
+ #include <e32def.h>
+ #include <symbian_osl_ext.h>
+#elif defined(THREADX)
+ #include <threadx_osl_ext.h>
+#else
+ #define OSL_EXT_DISABLED
+#endif
+
+/* Include base operating system abstraction. */
+#include <osl.h>
+
+#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/drivers/net/wireless/bcmdhd_1363/include/packed_section_end.h b/drivers/net/wireless/bcmdhd_1363/include/packed_section_end.h
new file mode 100644
index 000000000000..4827c709af26
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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 <packed_section_start.h>
+ *
+ * typedef BWL_PRE_PACKED_STRUCT struct foobar_t {
+ * some_struct_members;
+ * } BWL_POST_PACKED_STRUCT foobar_t;
+ *
+ * #include <packed_section_end.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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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/drivers/net/wireless/bcmdhd_1363/include/packed_section_start.h b/drivers/net/wireless/bcmdhd_1363/include/packed_section_start.h
new file mode 100644
index 000000000000..9beb45d5e082
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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 <packed_section_start.h>
+ *
+ * typedef BWL_PRE_PACKED_STRUCT struct foobar_t {
+ * some_struct_members;
+ * } BWL_POST_PACKED_STRUCT foobar_t;
+ *
+ * #include <packed_section_end.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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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/drivers/net/wireless/bcmdhd_1363/include/pcicfg.h b/drivers/net/wireless/bcmdhd_1363/include/pcicfg.h
new file mode 100644
index 000000000000..e4672031240f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/pcicfg.h
@@ -0,0 +1,260 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: pcicfg.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#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
+#define PCI_CFG_BAR1 0x14
+#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
+
+
+/* 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 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_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_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 */
+
+
+/* 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/drivers/net/wireless/bcmdhd_1363/include/pcie_core.h b/drivers/net/wireless/bcmdhd_1363/include/pcie_core.h
new file mode 100644
index 000000000000..5ea5d7569dd8
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/pcie_core.h
@@ -0,0 +1,652 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: pcie_core.h 514727 2014-11-12 03:02:48Z $
+ */
+#ifndef _PCIE_CORE_H
+#define _PCIE_CORE_H
+
+#include <sbhnddma.h>
+#include <siutils.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
+
+/* 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 */
+
+/* dma regs to control the flow between host2dev and dev2host */
+typedef 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;
+
+/* SB side: PCIE core and host control registers */
+typedef 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[2];
+ 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 PAD[42];
+
+ 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];
+ } 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 PAD[13]; /* 0x1AC - 0x1DF */
+ uint32 clk_ctl_st; /* 0x1E0 */
+ uint32 PAD[7]; /* 0x1E4 - 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 */
+ } pcie2;
+ } u;
+ uint32 pciecfg[4][64]; /* 0x400 - 0x7FF, PCIE Cfg Space */
+ uint16 sprom[64]; /* SPROM shadow Area */
+} sbpcieregs_t;
+
+/* 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_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_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_CFGADDR 0x120 /* offsetof(configaddr) */
+#define PCIE_CFGDATA 0x124 /* offsetof(configdata) */
+
+/* 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 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)
+
+/* 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
+
+/* PCIE protocol PHY diagnostic registers */
+#define PCIE_PLP_MODEREG 0x200 /* Mode */
+#define PCIE_PLP_STATUSREG 0x204 /* Status */
+#define PCIE_PLP_LTSSMCTRLREG 0x208 /* LTSSM control */
+#define PCIE_PLP_LTLINKNUMREG 0x20c /* Link Training Link number */
+#define PCIE_PLP_LTLANENUMREG 0x210 /* Link Training Lane number */
+#define PCIE_PLP_LTNFTSREG 0x214 /* Link Training N_FTS */
+#define PCIE_PLP_ATTNREG 0x218 /* Attention */
+#define PCIE_PLP_ATTNMASKREG 0x21C /* Attention Mask */
+#define PCIE_PLP_RXERRCTR 0x220 /* Rx Error */
+#define PCIE_PLP_RXFRMERRCTR 0x224 /* Rx Framing Error */
+#define PCIE_PLP_RXERRTHRESHREG 0x228 /* Rx Error threshold */
+#define PCIE_PLP_TESTCTRLREG 0x22C /* Test Control reg */
+#define PCIE_PLP_SERDESCTRLOVRDREG 0x230 /* SERDES Control Override */
+#define PCIE_PLP_TIMINGOVRDREG 0x234 /* Timing param override */
+#define PCIE_PLP_RXTXSMDIAGREG 0x238 /* RXTX State Machine Diag */
+#define PCIE_PLP_LTSSMDIAGREG 0x23C /* LTSSM State Machine Diag */
+
+/* PCIE protocol DLLP diagnostic registers */
+#define PCIE_DLLP_LCREG 0x100 /* Link Control */
+#define PCIE_DLLP_LSREG 0x104 /* Link Status */
+#define PCIE_DLLP_LAREG 0x108 /* Link Attention */
+#define PCIE_DLLP_LAMASKREG 0x10C /* Link Attention Mask */
+#define PCIE_DLLP_NEXTTXSEQNUMREG 0x110 /* Next Tx Seq Num */
+#define PCIE_DLLP_ACKEDTXSEQNUMREG 0x114 /* Acked Tx Seq Num */
+#define PCIE_DLLP_PURGEDTXSEQNUMREG 0x118 /* Purged Tx Seq Num */
+#define PCIE_DLLP_RXSEQNUMREG 0x11C /* Rx Sequence Number */
+#define PCIE_DLLP_LRREG 0x120 /* Link Replay */
+#define PCIE_DLLP_LACKTOREG 0x124 /* Link Ack Timeout */
+#define PCIE_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */
+#define PCIE_DLLP_RTRYWPREG 0x12C /* Retry buffer write ptr */
+#define PCIE_DLLP_RTRYRPREG 0x130 /* Retry buffer Read ptr */
+#define PCIE_DLLP_RTRYPPREG 0x134 /* Retry buffer Purged ptr */
+#define PCIE_DLLP_RTRRWREG 0x138 /* Retry buffer Read/Write */
+#define PCIE_DLLP_ECTHRESHREG 0x13C /* Error Count Threshold */
+#define PCIE_DLLP_TLPERRCTRREG 0x140 /* TLP Error Counter */
+#define PCIE_DLLP_ERRCTRREG 0x144 /* Error Counter */
+#define PCIE_DLLP_NAKRXCTRREG 0x148 /* NAK Received Counter */
+#define PCIE_DLLP_TESTREG 0x14C /* Test */
+#define PCIE_DLLP_PKTBIST 0x150 /* Packet BIST */
+#define PCIE_DLLP_PCIE11 0x154 /* DLLP PCIE 1.1 reg */
+
+#define PCIE_DLLP_LSREG_LINKUP (1 << 16)
+
+/* PCIE protocol TLP diagnostic registers */
+#define PCIE_TLP_CONFIGREG 0x000 /* Configuration */
+#define PCIE_TLP_WORKAROUNDSREG 0x004 /* TLP Workarounds */
+#define PCIE_TLP_WRDMAUPPER 0x010 /* Write DMA Upper Address */
+#define PCIE_TLP_WRDMALOWER 0x014 /* Write DMA Lower Address */
+#define PCIE_TLP_WRDMAREQ_LBEREG 0x018 /* Write DMA Len/ByteEn Req */
+#define PCIE_TLP_RDDMAUPPER 0x01C /* Read DMA Upper Address */
+#define PCIE_TLP_RDDMALOWER 0x020 /* Read DMA Lower Address */
+#define PCIE_TLP_RDDMALENREG 0x024 /* Read DMA Len Req */
+#define PCIE_TLP_MSIDMAUPPER 0x028 /* MSI DMA Upper Address */
+#define PCIE_TLP_MSIDMALOWER 0x02C /* MSI DMA Lower Address */
+#define PCIE_TLP_MSIDMALENREG 0x030 /* MSI DMA Len Req */
+#define PCIE_TLP_SLVREQLENREG 0x034 /* Slave Request Len */
+#define PCIE_TLP_FCINPUTSREQ 0x038 /* Flow Control Inputs */
+#define PCIE_TLP_TXSMGRSREQ 0x03C /* Tx StateMachine and Gated Req */
+#define PCIE_TLP_ADRACKCNTARBLEN 0x040 /* Address Ack XferCnt and ARB Len */
+#define PCIE_TLP_DMACPLHDR0 0x044 /* DMA Completion Hdr 0 */
+#define PCIE_TLP_DMACPLHDR1 0x048 /* DMA Completion Hdr 1 */
+#define PCIE_TLP_DMACPLHDR2 0x04C /* DMA Completion Hdr 2 */
+#define PCIE_TLP_DMACPLMISC0 0x050 /* DMA Completion Misc0 */
+#define PCIE_TLP_DMACPLMISC1 0x054 /* DMA Completion Misc1 */
+#define PCIE_TLP_DMACPLMISC2 0x058 /* DMA Completion Misc2 */
+#define PCIE_TLP_SPTCTRLLEN 0x05C /* Split Controller Req len */
+#define PCIE_TLP_SPTCTRLMSIC0 0x060 /* Split Controller Misc 0 */
+#define PCIE_TLP_SPTCTRLMSIC1 0x064 /* Split Controller Misc 1 */
+#define PCIE_TLP_BUSDEVFUNC 0x068 /* Bus/Device/Func */
+#define PCIE_TLP_RESETCTR 0x06C /* Reset Counter */
+#define PCIE_TLP_RTRYBUF 0x070 /* Retry Buffer value */
+#define PCIE_TLP_TGTDEBUG1 0x074 /* Target Debug Reg1 */
+#define PCIE_TLP_TGTDEBUG2 0x078 /* Target Debug Reg2 */
+#define PCIE_TLP_TGTDEBUG3 0x07C /* Target Debug Reg3 */
+#define PCIE_TLP_TGTDEBUG4 0x080 /* 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 0x7f /* clock to be used on MDIO */
+#define MDIOCTL_DIVISOR_VAL 0x2
+#define MDIOCTL_PREAM_EN 0x80 /* Enable preamble sequnce */
+#define MDIOCTL_ACCESS_DONE 0x100 /* 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 0x80000000 /* 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 0xFF00 /* bits 0 - 7 */
+#define PCIE_L1THRESHOLDTIME_MASK 0xFF00 /* 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 0x8000 /* 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 */
+
+/* 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 0xF0000 /* 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 */
+
+/* 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 0x844 /* ltr0_reg offset in pcie cap */
+#define PCIE_LTR1_REG_OFFSET 0x848 /* ltr1_reg offset in pcie cap */
+#define PCIE_LTR2_REG_OFFSET 0x84c /* ltr2_reg offset in pcie cap */
+#define PCIE_LTR0_REG_DEFAULT_60 0x883c883c /* active latency default to 60usec */
+#define PCIE_LTR0_REG_DEFAULT_150 0x88968896 /* active latency default to 150usec */
+#define PCIE_LTR1_REG_DEFAULT 0x88648864 /* idle latency default to 100usec */
+#define PCIE_LTR2_REG_DEFAULT 0x90039003 /* 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 0xF00
+#define BRCMCAP_PCIEREV_CT_SHIFT 8
+#define BRCMCAP_PCIEREV_REVID_MASK 0xFF
+#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 0xBC
+#define PCIECFGREG_LINK_STATUS_CTRL2 0xDC
+#define PCIECFGREG_RBAR_CTRL 0x228
+#define PCIECFGREG_PML1_SUB_CTRL1 0x248
+#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
+
+/* 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 PCIMailBoxInt 0x48
+#define PCIMailBoxMask 0x4C
+
+#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_DEVCONTROL_MRRS_SHFT 12
+#define PCIECFGREG_DEVCONTROL_MRRS_MASK (0x7 << PCIECFGREG_DEVCONTROL_MRRS_SHFT)
+
+/* 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
+
+/* 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
+
+#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);
+#endif /* BCMDRIVER */
+
+#endif /* _PCIE_CORE_H */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/proto/802.11.h b/drivers/net/wireless/bcmdhd_1363/include/proto/802.11.h
new file mode 100644
index 000000000000..4fdccb342f9f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/802.11.h
@@ -0,0 +1,4936 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: 802.11.h 654127 2016-08-11 06:56:35Z $
+ */
+
+#ifndef _802_11_H_
+#define _802_11_H_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+#ifndef _NET_ETHERNET_H_
+#include <proto/ethernet.h>
+#endif
+
+#include <proto/wpa.h>
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+
+#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 */
+
+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;
+#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_CHANNEL_SWITCH_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_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
+
+/* 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_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_HE_CAP_ID 201
+#define DOT11_MNG_HE_OP_ID 202
+#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_ID_EXT_ID 255 /* Element ID Extension 11mc D4.3 */
+
+#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-2012 and 802.11ac_D4.0 sec 8.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 */
+
+/* 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 */
+#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 D3.0 - 8.4.1.50) */
+#define DOT11_OPER_MODE_CHANNEL_WIDTH_SHIFT 0
+#define DOT11_OPER_MODE_CHANNEL_WIDTH_MASK 0x3
+#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_OPER_MODE_CHANNEL_WIDTH(mode) \
+ (((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK)\
+ >> DOT11_OPER_MODE_CHANNEL_WIDTH_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_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_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_160MHZ)
+#define DOT11_OPER_MODE_CHANNEL_WIDTH_8080MHZ(mode) (\
+ ((mode) & DOT11_OPER_MODE_CHANNEL_WIDTH_MASK) == DOT11_OPER_MODE_8080MHZ)
+
+/* 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_HE 26 /* HE 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_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 */
+
+/** 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
+
+#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
+
+/** 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
+ */
+
+/* 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 */
+
+/* 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 */
+/* Macros for HT MCS filed 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
+
+/* 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
+
+#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,
+ VHT_OP_CHAN_WIDTH_80_80 = 3
+} 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. ************* */
+
+#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 */
+
+/* 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 */
+ /* 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_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
+
+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
+
+/** 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 <packed_section_end.h>
+
+#endif /* _802_11_H_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/proto/802.11_bta.h b/drivers/net/wireless/bcmdhd_1363/include/proto/802.11_bta.h
new file mode 100644
index 000000000000..981acd896860
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/802.11_bta.h
@@ -0,0 +1,48 @@
+/*
+ * BT-AMP (BlueTooth Alternate Mac and Phy) 802.11 PAL (Protocol Adaptation 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: 802.11_bta.h 518342 2014-12-01 23:21:41Z $
+*/
+
+#ifndef _802_11_BTA_H_
+#define _802_11_BTA_H_
+
+#define BT_SIG_SNAP_MPROT "\xAA\xAA\x03\x00\x19\x58"
+
+/* BT-AMP 802.11 PAL Protocols */
+#define BTA_PROT_L2CAP 1
+#define BTA_PROT_ACTIVITY_REPORT 2
+#define BTA_PROT_SECURITY 3
+#define BTA_PROT_LINK_SUPERVISION_REQUEST 4
+#define BTA_PROT_LINK_SUPERVISION_REPLY 5
+
+/* BT-AMP 802.11 PAL AMP_ASSOC Type IDs */
+#define BTA_TYPE_ID_MAC_ADDRESS 1
+#define BTA_TYPE_ID_PREFERRED_CHANNELS 2
+#define BTA_TYPE_ID_CONNECTED_CHANNELS 3
+#define BTA_TYPE_ID_CAPABILITIES 4
+#define BTA_TYPE_ID_VERSION 5
+#endif /* _802_11_bta_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd_1363/include/proto/802.11e.h
new file mode 100644
index 000000000000..c0ad8e452b82
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: 802.11e.h 572688 2015-07-20 17:49:21Z $
+ */
+
+#ifndef _802_11e_H_
+#define _802_11e_H_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+/* 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 <packed_section_end.h>
+
+#endif /* _802_11e_CAC_H_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/proto/802.1d.h b/drivers/net/wireless/bcmdhd_1363/include/proto/802.1d.h
new file mode 100644
index 000000000000..85fd7e4a2fae
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: 802.1d.h 518342 2014-12-01 23:21:41Z $
+ */
+
+#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/drivers/net/wireless/bcmdhd_1363/include/proto/802.3.h b/drivers/net/wireless/bcmdhd_1363/include/proto/802.3.h
new file mode 100644
index 000000000000..d834cb741f39
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: 802.3.h 518342 2014-12-01 23:21:41Z $
+ */
+
+#ifndef _802_3_h_
+#define _802_3_h_
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+#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 <packed_section_end.h>
+
+#endif /* #ifndef _802_3_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/proto/bcmdhcp.h b/drivers/net/wireless/bcmdhd_1363/include/proto/bcmdhcp.h
new file mode 100644
index 000000000000..90d3c01617f0
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmdhcp.h 597933 2015-11-06 18:52:06Z $
+ */
+
+#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/drivers/net/wireless/bcmdhd_1363/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd_1363/include/proto/bcmeth.h
new file mode 100644
index 000000000000..97f893546b77
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/bcmeth.h
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmeth.h 565501 2015-06-22 14:29:02Z $
+ */
+
+/*
+ * Broadcom Ethernet protocol defines
+ */
+
+#ifndef _BCMETH_H_
+#define _BCMETH_H_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+/* 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
+
+/* 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 <packed_section_end.h>
+
+#endif /* _BCMETH_H_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd_1363/include/proto/bcmevent.h
new file mode 100644
index 000000000000..426ee5dfb425
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/bcmevent.h
@@ -0,0 +1,842 @@
+/*
+ * Broadcom Event protocol definitions
+ *
+ * Dependencies: proto/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmevent.h 660193 2016-09-19 12:56:55Z $
+ *
+ */
+
+/*
+ * Broadcom Ethernet Events protocol defines
+ *
+ */
+
+#ifndef _BCMEVENT_H_
+#define _BCMEVENT_H_
+
+#include <typedefs.h>
+/* #include <ethernet.h> -- TODO: req., excluded to overwhelming coupling (break up ethernet.h) */
+#include <proto/bcmeth.h>
+#if defined(HEALTH_CHECK) || defined(DNGL_EVENT_SUPPORT)
+#include <proto/dnglevent.h>
+#endif /* HEALTH_CHECK || DNGL_EVENT_SUPPORT */
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+#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(HEALTH_CHECK) || defined(DNGL_EVENT_SUPPORT)
+ bcm_dngl_event_msg_t dngl_event;
+#endif /* HEALTH_CHECK || DNGL_EVENT_SUPPORT */
+
+ /* 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 */
+#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_HE_TWT_SETUP 157 /* HE TWT Setup Complete event */
+#define WLC_E_NAN_DATA_IND 158 /* NAN 2.0 data indication */
+#define WLC_E_NAN_DATA_CONF 159 /* NAN 2.0 data confirmation */
+#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_LAST 166 /* highest val + 1 for range checking */
+#if (WLC_E_LAST > 166)
+#error "WLC_E_LAST: Invalid value for last event; must be <= 165."
+#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
+
+/* 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
+
+/* 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 */
+typedef enum wl_nan_events {
+ WL_NAN_EVENT_START = 1, /* NAN cluster started */
+ WL_NAN_EVENT_JOIN = 2, /* Joined to a NAN cluster */
+ WL_NAN_EVENT_ROLE = 3, /* Role changed */
+ WL_NAN_EVENT_SCAN_COMPLETE = 4,
+ WL_NAN_EVENT_DISCOVERY_RESULT = 5,
+ WL_NAN_EVENT_REPLIED = 6,
+ WL_NAN_EVENT_TERMINATED = 7, /* the instance ID will be present in the ev data */
+ WL_NAN_EVENT_RECEIVE = 8,
+ WL_NAN_EVENT_STATUS_CHG = 9, /* generated on any change in nan_mac status */
+ WL_NAN_EVENT_MERGE = 10, /* Merged to a NAN cluster */
+ WL_NAN_EVENT_STOP = 11, /* NAN stopped */
+ WL_NAN_EVENT_P2P = 12, /* NAN P2P EVENT */
+ WL_NAN_EVENT_WINDOW_BEGIN_P2P = 13, /* Event for begin of P2P further availability window */
+ WL_NAN_EVENT_WINDOW_BEGIN_MESH = 14,
+ WL_NAN_EVENT_WINDOW_BEGIN_IBSS = 15,
+ WL_NAN_EVENT_WINDOW_BEGIN_RANGING = 16,
+ WL_NAN_EVENT_POST_DISC = 17, /* Event for post discovery data */
+ WL_NAN_EVENT_DATA_IF_ADD = 18, /* Event for Data IF add */
+ WL_NAN_EVENT_DATA_PEER_ADD = 19, /* Event for peer add */
+ /* nan 2.0 */
+ WL_NAN_EVENT_DATA_IND = 20, /* Will be removed after source code is committed. */
+ WL_NAN_EVENT_PEER_DATAPATH_IND = 20, /* Peer's Datapath request Indication to Host */
+ WL_NAN_EVENT_DATA_CONF = 21, /* Will be removed after source code is committed. */
+ WL_NAN_EVENT_DATAPATH_ESTB = 21, /* Datapath Established to Host */
+ WL_NAN_EVENT_SDF_RX = 22, /* entire service discovery frame */
+ WL_NAN_EVENT_DATA_END = 23, /* Will be removed after source code is committed. */
+ WL_NAN_EVENT_DATAPATH_END = 23, /* Data End to Host */
+ WL_NAN_EVENT_BCN_RX = 24, /* received beacon payload */
+ WL_NAN_EVENT_PEER_DATAPATH_RESP = 25, /* Peer's Data Response indication to Host */
+ WL_NAN_EVENT_PEER_DATAPATH_CONF = 26, /* Peer's Data Confirm indication to Host */
+ WL_NAN_EVENT_INVALID /* delimiter for max value */
+} nan_app_events_e;
+
+#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;
+
+/* 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;
+
+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 <packed_section_end.h>
+
+#endif /* _BCMEVENT_H_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/proto/bcmip.h b/drivers/net/wireless/bcmdhd_1363/include/proto/bcmip.h
new file mode 100644
index 000000000000..fdfd83c9ea9d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/bcmip.h
@@ -0,0 +1,249 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmip.h 594480 2015-10-22 03:14:33Z $
+ */
+
+#ifndef _bcmip_h_
+#define _bcmip_h_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+
+/* 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;
+
+/* 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 <packed_section_end.h>
+
+#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/drivers/net/wireless/bcmdhd_1363/include/proto/bcmipv6.h b/drivers/net/wireless/bcmdhd_1363/include/proto/bcmipv6.h
new file mode 100644
index 000000000000..f446e47bf296
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmipv6.h 518342 2014-12-01 23:21:41Z $
+ */
+
+#ifndef _bcmipv6_h_
+#define _bcmipv6_h_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+/* 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 <packed_section_end.h>
+
+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/drivers/net/wireless/bcmdhd_1363/include/proto/bcmtcp.h b/drivers/net/wireless/bcmdhd_1363/include/proto/bcmtcp.h
new file mode 100644
index 000000000000..931a1a6f8fcf
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmtcp.h 518342 2014-12-01 23:21:41Z $
+ */
+
+#ifndef _bcmtcp_h_
+#define _bcmtcp_h_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+
+#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 <packed_section_end.h>
+
+/* 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/drivers/net/wireless/bcmdhd_1363/include/proto/bcmudp.h b/drivers/net/wireless/bcmdhd_1363/include/proto/bcmudp.h
new file mode 100644
index 000000000000..ae0e8d1226db
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bcmudp.h 597933 2015-11-06 18:52:06Z $
+ */
+
+#ifndef _bcmudp_h_
+#define _bcmudp_h_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+
+/* 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 <packed_section_end.h>
+
+#endif /* #ifndef _bcmudp_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/proto/bt_amp_hci.h b/drivers/net/wireless/bcmdhd_1363/include/proto/bt_amp_hci.h
new file mode 100644
index 000000000000..1a3ccaf83003
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/bt_amp_hci.h
@@ -0,0 +1,444 @@
+/*
+ * BT-AMP (BlueTooth Alternate Mac and Phy) HCI (Host/Controller 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: bt_amp_hci.h 518342 2014-12-01 23:21:41Z $
+*/
+
+#ifndef _bt_amp_hci_h
+#define _bt_amp_hci_h
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+
+/* AMP HCI CMD packet format */
+typedef BWL_PRE_PACKED_STRUCT struct amp_hci_cmd {
+ uint16 opcode;
+ uint8 plen;
+ uint8 parms[1];
+} BWL_POST_PACKED_STRUCT amp_hci_cmd_t;
+
+#define HCI_CMD_PREAMBLE_SIZE OFFSETOF(amp_hci_cmd_t, parms)
+#define HCI_CMD_DATA_SIZE 255
+
+/* AMP HCI CMD opcode layout */
+#define HCI_CMD_OPCODE(ogf, ocf) ((((ogf) & 0x3F) << 10) | ((ocf) & 0x03FF))
+#define HCI_CMD_OGF(opcode) ((uint8)(((opcode) >> 10) & 0x3F))
+#define HCI_CMD_OCF(opcode) ((opcode) & 0x03FF)
+
+/* AMP HCI command opcodes */
+#define HCI_Read_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0001)
+#define HCI_Reset_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0002)
+#define HCI_Read_Link_Quality HCI_CMD_OPCODE(0x05, 0x0003)
+#define HCI_Read_Local_AMP_Info HCI_CMD_OPCODE(0x05, 0x0009)
+#define HCI_Read_Local_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000A)
+#define HCI_Write_Remote_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000B)
+#define HCI_Create_Physical_Link HCI_CMD_OPCODE(0x01, 0x0035)
+#define HCI_Accept_Physical_Link_Request HCI_CMD_OPCODE(0x01, 0x0036)
+#define HCI_Disconnect_Physical_Link HCI_CMD_OPCODE(0x01, 0x0037)
+#define HCI_Create_Logical_Link HCI_CMD_OPCODE(0x01, 0x0038)
+#define HCI_Accept_Logical_Link HCI_CMD_OPCODE(0x01, 0x0039)
+#define HCI_Disconnect_Logical_Link HCI_CMD_OPCODE(0x01, 0x003A)
+#define HCI_Logical_Link_Cancel HCI_CMD_OPCODE(0x01, 0x003B)
+#define HCI_Flow_Spec_Modify HCI_CMD_OPCODE(0x01, 0x003C)
+#define HCI_Write_Flow_Control_Mode HCI_CMD_OPCODE(0x01, 0x0067)
+#define HCI_Read_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x0069)
+#define HCI_Write_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x006A)
+#define HCI_Short_Range_Mode HCI_CMD_OPCODE(0x01, 0x006B)
+#define HCI_Reset HCI_CMD_OPCODE(0x03, 0x0003)
+#define HCI_Read_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0015)
+#define HCI_Write_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0016)
+#define HCI_Read_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0036)
+#define HCI_Write_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0037)
+#define HCI_Enhanced_Flush HCI_CMD_OPCODE(0x03, 0x005F)
+#define HCI_Read_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0061)
+#define HCI_Write_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0062)
+#define HCI_Set_Event_Mask_Page_2 HCI_CMD_OPCODE(0x03, 0x0063)
+#define HCI_Read_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0064)
+#define HCI_Write_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0065)
+#define HCI_Read_Local_Version_Info HCI_CMD_OPCODE(0x04, 0x0001)
+#define HCI_Read_Local_Supported_Commands HCI_CMD_OPCODE(0x04, 0x0002)
+#define HCI_Read_Buffer_Size HCI_CMD_OPCODE(0x04, 0x0005)
+#define HCI_Read_Data_Block_Size HCI_CMD_OPCODE(0x04, 0x000A)
+
+/* AMP HCI command parameters */
+typedef BWL_PRE_PACKED_STRUCT struct read_local_cmd_parms {
+ uint8 plh;
+ uint8 offset[2]; /* length so far */
+ uint8 max_remote[2];
+} BWL_POST_PACKED_STRUCT read_local_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct write_remote_cmd_parms {
+ uint8 plh;
+ uint8 offset[2];
+ uint8 len[2];
+ uint8 frag[1];
+} BWL_POST_PACKED_STRUCT write_remote_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct phy_link_cmd_parms {
+ uint8 plh;
+ uint8 key_length;
+ uint8 key_type;
+ uint8 key[1];
+} BWL_POST_PACKED_STRUCT phy_link_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_cmd_parms {
+ uint8 plh;
+ uint8 reason;
+} BWL_POST_PACKED_STRUCT dis_phy_link_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct log_link_cmd_parms {
+ uint8 plh;
+ uint8 txflow[16];
+ uint8 rxflow[16];
+} BWL_POST_PACKED_STRUCT log_link_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct ext_flow_spec {
+ uint8 id;
+ uint8 service_type;
+ uint8 max_sdu[2];
+ uint8 sdu_ia_time[4];
+ uint8 access_latency[4];
+ uint8 flush_timeout[4];
+} BWL_POST_PACKED_STRUCT ext_flow_spec_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_cmd_parms {
+ uint8 plh;
+ uint8 tx_fs_ID;
+} BWL_POST_PACKED_STRUCT log_link_cancel_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_cmd_parms {
+ uint8 llh[2];
+ uint8 txflow[16];
+ uint8 rxflow[16];
+} BWL_POST_PACKED_STRUCT flow_spec_mod_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct plh_pad {
+ uint8 plh;
+ uint8 pad;
+} BWL_POST_PACKED_STRUCT plh_pad_t;
+
+typedef BWL_PRE_PACKED_STRUCT union hci_handle {
+ uint16 bredr;
+ plh_pad_t amp;
+} BWL_POST_PACKED_STRUCT hci_handle_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct ls_to_cmd_parms {
+ hci_handle_t handle;
+ uint8 timeout[2];
+} BWL_POST_PACKED_STRUCT ls_to_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct befto_cmd_parms {
+ uint8 llh[2];
+ uint8 befto[4];
+} BWL_POST_PACKED_STRUCT befto_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct srm_cmd_parms {
+ uint8 plh;
+ uint8 srm;
+} BWL_POST_PACKED_STRUCT srm_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct ld_cmd_parms {
+ uint8 ld_aware;
+ uint8 ld[2];
+ uint8 ld_opts;
+ uint8 l_opts;
+} BWL_POST_PACKED_STRUCT ld_cmd_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct eflush_cmd_parms {
+ uint8 llh[2];
+ uint8 packet_type;
+} BWL_POST_PACKED_STRUCT eflush_cmd_parms_t;
+
+/* Generic AMP extended flow spec service types */
+#define EFS_SVCTYPE_NO_TRAFFIC 0
+#define EFS_SVCTYPE_BEST_EFFORT 1
+#define EFS_SVCTYPE_GUARANTEED 2
+
+/* AMP HCI event packet format */
+typedef BWL_PRE_PACKED_STRUCT struct amp_hci_event {
+ uint8 ecode;
+ uint8 plen;
+ uint8 parms[1];
+} BWL_POST_PACKED_STRUCT amp_hci_event_t;
+
+#define HCI_EVT_PREAMBLE_SIZE OFFSETOF(amp_hci_event_t, parms)
+
+/* AMP HCI event codes */
+#define HCI_Command_Complete 0x0E
+#define HCI_Command_Status 0x0F
+#define HCI_Flush_Occurred 0x11
+#define HCI_Enhanced_Flush_Complete 0x39
+#define HCI_Physical_Link_Complete 0x40
+#define HCI_Channel_Select 0x41
+#define HCI_Disconnect_Physical_Link_Complete 0x42
+#define HCI_Logical_Link_Complete 0x45
+#define HCI_Disconnect_Logical_Link_Complete 0x46
+#define HCI_Flow_Spec_Modify_Complete 0x47
+#define HCI_Number_of_Completed_Data_Blocks 0x48
+#define HCI_Short_Range_Mode_Change_Complete 0x4C
+#define HCI_Status_Change_Event 0x4D
+#define HCI_Vendor_Specific 0xFF
+
+/* AMP HCI event mask bit positions */
+#define HCI_Physical_Link_Complete_Event_Mask 0x0001
+#define HCI_Channel_Select_Event_Mask 0x0002
+#define HCI_Disconnect_Physical_Link_Complete_Event_Mask 0x0004
+#define HCI_Logical_Link_Complete_Event_Mask 0x0020
+#define HCI_Disconnect_Logical_Link_Complete_Event_Mask 0x0040
+#define HCI_Flow_Spec_Modify_Complete_Event_Mask 0x0080
+#define HCI_Number_of_Completed_Data_Blocks_Event_Mask 0x0100
+#define HCI_Short_Range_Mode_Change_Complete_Event_Mask 0x1000
+#define HCI_Status_Change_Event_Mask 0x2000
+#define HCI_All_Event_Mask 0x31e7
+/* AMP HCI event parameters */
+typedef BWL_PRE_PACKED_STRUCT struct cmd_status_parms {
+ uint8 status;
+ uint8 cmdpkts;
+ uint16 opcode;
+} BWL_POST_PACKED_STRUCT cmd_status_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct cmd_complete_parms {
+ uint8 cmdpkts;
+ uint16 opcode;
+ uint8 parms[1];
+} BWL_POST_PACKED_STRUCT cmd_complete_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct flush_occurred_evt_parms {
+ uint16 handle;
+} BWL_POST_PACKED_STRUCT flush_occurred_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct write_remote_evt_parms {
+ uint8 status;
+ uint8 plh;
+} BWL_POST_PACKED_STRUCT write_remote_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct read_local_evt_parms {
+ uint8 status;
+ uint8 plh;
+ uint16 len;
+ uint8 frag[1];
+} BWL_POST_PACKED_STRUCT read_local_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct read_local_info_evt_parms {
+ uint8 status;
+ uint8 AMP_status;
+ uint32 bandwidth;
+ uint32 gbandwidth;
+ uint32 latency;
+ uint32 PDU_size;
+ uint8 ctrl_type;
+ uint16 PAL_cap;
+ uint16 AMP_ASSOC_len;
+ uint32 max_flush_timeout;
+ uint32 be_flush_timeout;
+} BWL_POST_PACKED_STRUCT read_local_info_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct log_link_evt_parms {
+ uint8 status;
+ uint16 llh;
+ uint8 plh;
+ uint8 tx_fs_ID;
+} BWL_POST_PACKED_STRUCT log_link_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct disc_log_link_evt_parms {
+ uint8 status;
+ uint16 llh;
+ uint8 reason;
+} BWL_POST_PACKED_STRUCT disc_log_link_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_evt_parms {
+ uint8 status;
+ uint8 plh;
+ uint8 tx_fs_ID;
+} BWL_POST_PACKED_STRUCT log_link_cancel_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_evt_parms {
+ uint8 status;
+ uint16 llh;
+} BWL_POST_PACKED_STRUCT flow_spec_mod_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct phy_link_evt_parms {
+ uint8 status;
+ uint8 plh;
+} BWL_POST_PACKED_STRUCT phy_link_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_evt_parms {
+ uint8 status;
+ uint8 plh;
+ uint8 reason;
+} BWL_POST_PACKED_STRUCT dis_phy_link_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct read_ls_to_evt_parms {
+ uint8 status;
+ hci_handle_t handle;
+ uint16 timeout;
+} BWL_POST_PACKED_STRUCT read_ls_to_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct read_lla_ca_to_evt_parms {
+ uint8 status;
+ uint16 timeout;
+} BWL_POST_PACKED_STRUCT read_lla_ca_to_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct read_data_block_size_evt_parms {
+ uint8 status;
+ uint16 ACL_pkt_len;
+ uint16 data_block_len;
+ uint16 data_block_num;
+} BWL_POST_PACKED_STRUCT read_data_block_size_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct data_blocks {
+ uint16 handle;
+ uint16 pkts;
+ uint16 blocks;
+} BWL_POST_PACKED_STRUCT data_blocks_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct num_completed_data_blocks_evt_parms {
+ uint16 num_blocks;
+ uint8 num_handles;
+ data_blocks_t completed[1];
+} BWL_POST_PACKED_STRUCT num_completed_data_blocks_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct befto_evt_parms {
+ uint8 status;
+ uint32 befto;
+} BWL_POST_PACKED_STRUCT befto_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct srm_evt_parms {
+ uint8 status;
+ uint8 plh;
+ uint8 srm;
+} BWL_POST_PACKED_STRUCT srm_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct contact_counter_evt_parms {
+ uint8 status;
+ uint8 llh[2];
+ uint16 counter;
+} BWL_POST_PACKED_STRUCT contact_counter_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct contact_counter_reset_evt_parms {
+ uint8 status;
+ uint8 llh[2];
+} BWL_POST_PACKED_STRUCT contact_counter_reset_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct read_linkq_evt_parms {
+ uint8 status;
+ hci_handle_t handle;
+ uint8 link_quality;
+} BWL_POST_PACKED_STRUCT read_linkq_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct ld_evt_parms {
+ uint8 status;
+ uint8 ld_aware;
+ uint8 ld[2];
+ uint8 ld_opts;
+ uint8 l_opts;
+} BWL_POST_PACKED_STRUCT ld_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct eflush_complete_evt_parms {
+ uint16 handle;
+} BWL_POST_PACKED_STRUCT eflush_complete_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct vendor_specific_evt_parms {
+ uint8 len;
+ uint8 parms[1];
+} BWL_POST_PACKED_STRUCT vendor_specific_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct local_version_info_evt_parms {
+ uint8 status;
+ uint8 hci_version;
+ uint16 hci_revision;
+ uint8 pal_version;
+ uint16 mfg_name;
+ uint16 pal_subversion;
+} BWL_POST_PACKED_STRUCT local_version_info_evt_parms_t;
+
+#define MAX_SUPPORTED_CMD_BYTE 64
+typedef BWL_PRE_PACKED_STRUCT struct local_supported_cmd_evt_parms {
+ uint8 status;
+ uint8 cmd[MAX_SUPPORTED_CMD_BYTE];
+} BWL_POST_PACKED_STRUCT local_supported_cmd_evt_parms_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct status_change_evt_parms {
+ uint8 status;
+ uint8 amp_status;
+} BWL_POST_PACKED_STRUCT status_change_evt_parms_t;
+
+/* AMP HCI error codes */
+#define HCI_SUCCESS 0x00
+#define HCI_ERR_ILLEGAL_COMMAND 0x01
+#define HCI_ERR_NO_CONNECTION 0x02
+#define HCI_ERR_MEMORY_FULL 0x07
+#define HCI_ERR_CONNECTION_TIMEOUT 0x08
+#define HCI_ERR_MAX_NUM_OF_CONNECTIONS 0x09
+#define HCI_ERR_CONNECTION_EXISTS 0x0B
+#define HCI_ERR_CONNECTION_DISALLOWED 0x0C
+#define HCI_ERR_CONNECTION_ACCEPT_TIMEOUT 0x10
+#define HCI_ERR_UNSUPPORTED_VALUE 0x11
+#define HCI_ERR_ILLEGAL_PARAMETER_FMT 0x12
+#define HCI_ERR_CONN_TERM_BY_LOCAL_HOST 0x16
+#define HCI_ERR_UNSPECIFIED 0x1F
+#define HCI_ERR_UNIT_KEY_USED 0x26
+#define HCI_ERR_QOS_REJECTED 0x2D
+#define HCI_ERR_PARAM_OUT_OF_RANGE 0x30
+#define HCI_ERR_NO_SUITABLE_CHANNEL 0x39
+#define HCI_ERR_CHANNEL_MOVE 0xFF
+
+/* AMP HCI ACL Data packet format */
+typedef BWL_PRE_PACKED_STRUCT struct amp_hci_ACL_data {
+ uint16 handle; /* 12-bit connection handle + 2-bit PB and 2-bit BC flags */
+ uint16 dlen; /* data total length */
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT amp_hci_ACL_data_t;
+
+#define HCI_ACL_DATA_PREAMBLE_SIZE OFFSETOF(amp_hci_ACL_data_t, data)
+
+#define HCI_ACL_DATA_BC_FLAGS (0x0 << 14)
+#define HCI_ACL_DATA_PB_FLAGS (0x3 << 12)
+
+#define HCI_ACL_DATA_HANDLE(handle) ((handle) & 0x0fff)
+#define HCI_ACL_DATA_FLAGS(handle) ((handle) >> 12)
+
+/* AMP Activity Report packet formats */
+typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report {
+ uint8 ScheduleKnown;
+ uint8 NumReports;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT amp_hci_activity_report_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report_triple {
+ uint32 StartTime;
+ uint32 Duration;
+ uint32 Periodicity;
+} BWL_POST_PACKED_STRUCT amp_hci_activity_report_triple_t;
+
+#define HCI_AR_SCHEDULE_KNOWN 0x01
+
+
+/* This marks the end of a packed structure section. */
+#include <packed_section_end.h>
+
+#endif /* _bt_amp_hci_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/proto/eapol.h b/drivers/net/wireless/bcmdhd_1363/include/proto/eapol.h
new file mode 100644
index 000000000000..e28496dc5f09
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/eapol.h
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: eapol.h 596466 2015-11-02 00:41:50Z $
+ */
+
+#ifndef _eapol_h_
+#define _eapol_h_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+#include <bcmcrypto/aeskeywrap.h>
+
+/* 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_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 + 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 <packed_section_end.h>
+
+#endif /* _eapol_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/proto/ethernet.h b/drivers/net/wireless/bcmdhd_1363/include/proto/ethernet.h
new file mode 100644
index 000000000000..d3a2e97c26b0
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: ethernet.h 518342 2014-12-01 23:21:41Z $
+ */
+
+#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 <packed_section_start.h>
+
+
+/*
+ * 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 <packed_section_end.h>
+
+#endif /* _NET_ETHERNET_H_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/proto/event_log_set.h b/drivers/net/wireless/bcmdhd_1363/include/proto/event_log_set.h
new file mode 100644
index 000000000000..3e0a129bbbd6
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/event_log_set.h
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: event_log_set.h 585396 2015-09-10 09:04:56Z $
+ */
+
+#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
+#define EVENT_LOG_SET_ECOUNTERS 5 /* Host to instantiate this for ecounters. */
+
+#endif /* _EVENT_LOG_SET_H_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/proto/event_log_tag.h b/drivers/net/wireless/bcmdhd_1363/include/proto/event_log_tag.h
new file mode 100644
index 000000000000..b46372c40185
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/event_log_tag.h
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: event_log_tag.h 658234 2016-09-07 04:42:39Z $
+ */
+
+#ifndef _EVENT_LOG_TAG_H_
+#define _EVENT_LOG_TAG_H_
+
+#include <typedefs.h>
+
+/* 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_AUTH_ERROR 145
+#define EVENT_LOG_TAG_AUTH_INFO 146
+#define EVENT_LOG_TAG_AUTH_DBG 147
+
+
+/* EVENT_LOG_TAG_MAX = Set to the same value of last tag, not last tag + 1 */
+#define EVENT_LOG_TAG_MAX 147
+/* 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/drivers/net/wireless/bcmdhd_1363/include/proto/p2p.h b/drivers/net/wireless/bcmdhd_1363/include/proto/p2p.h
new file mode 100644
index 000000000000..747265b9a2c2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: p2p.h 536785 2015-02-24 08:35:00Z $
+ */
+
+#ifndef _P2P_H_
+#define _P2P_H_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+#include <wlioctl.h>
+#include <proto/802.11.h>
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+
+/* 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 <packed_section_end.h>
+
+#endif /* _P2P_H_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/proto/sdspi.h b/drivers/net/wireless/bcmdhd_1363/include/proto/sdspi.h
new file mode 100644
index 000000000000..ca6e96eac051
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: sdspi.h 518342 2014-12-01 23:21:41Z $
+ */
+#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/drivers/net/wireless/bcmdhd_1363/include/proto/vlan.h b/drivers/net/wireless/bcmdhd_1363/include/proto/vlan.h
new file mode 100644
index 000000000000..062119d1faf2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: vlan.h 518342 2014-12-01 23:21:41Z $
+ */
+
+#ifndef _vlan_h_
+#define _vlan_h_
+
+#ifndef _TYPEDEFS_H_
+#include <typedefs.h>
+#endif
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+#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 <packed_section_end.h>
+
+#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/drivers/net/wireless/bcmdhd_1363/include/proto/wpa.h b/drivers/net/wireless/bcmdhd_1363/include/proto/wpa.h
new file mode 100644
index 000000000000..fc0124138118
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/wpa.h
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wpa.h 518342 2014-12-01 23:21:41Z $
+ */
+
+#ifndef _proto_wpa_h_
+#define _proto_wpa_h_
+
+#include <typedefs.h>
+#include <proto/ethernet.h>
+
+
+/* This marks the start of a packed structure section. */
+#include <packed_section_start.h>
+
+/* 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 */
+
+#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_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 <packed_section_end.h>
+
+#endif /* _proto_wpa_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/proto/wps.h b/drivers/net/wireless/bcmdhd_1363/include/proto/wps.h
new file mode 100644
index 000000000000..aa4cc1b9f0e0
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/proto/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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/drivers/net/wireless/bcmdhd_1363/include/rte_ioctl.h b/drivers/net/wireless/bcmdhd_1363/include/rte_ioctl.h
new file mode 100644
index 000000000000..2176c90d469f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/rte_ioctl.h
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: rte_ioctl.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#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
+};
+
+#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/drivers/net/wireless/bcmdhd_1363/include/sbchipc.h b/drivers/net/wireless/bcmdhd_1363/include/sbchipc.h
new file mode 100644
index 000000000000..ad68de7daf86
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/sbchipc.h
@@ -0,0 +1,3761 @@
+/*
+ * 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 574579 2015-07-27 15:36:37Z $
+ *
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ */
+
+#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;
+ 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 PAD;
+ 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 */
+} 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 PAD[70];
+
+ /* 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[60];
+
+ /* 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 PAD;
+ 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_uartescval; /* 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
+#define CC_SROM_OTP 0x800 /* SROM/OTP address space */
+#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_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)
+/* 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 */
+
+/* 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_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
+
+/* 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
+
+/* 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_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
+
+/* 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
+
+/* 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_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)
+
+
+/* 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
+
+/* 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
+
+
+/* PMU corerev and chip specific PLL controls.
+ * PMU<rev>_PLL<num>_XX where <rev> is PMU corerev and <num> is an arbitrary number
+ * to differentiate different PLLs controlled by the same PMU rev.
+ */
+/* 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<x>, refcomp_pwrdn, dly_ch<x>, 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
+
+/* m<x>div */
+#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)
+
+/* m<x>div, 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_36 0x24
+#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<x> */
+#define PMU1_PLL0_PLLCTL5 5
+#define PMU1_PLL0_PC5_CLK_DRV_MASK 0xffffff00
+#define PMU1_PLL0_PC5_CLK_DRV_SHIFT 8
+
+#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)
+
+/* 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<x>, refcomp_pwrdn, dly_ch<x>, 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
+
+/* m<x>div */
+#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
+
+/* m<x>div, 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<x> */
+#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 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_DISABLE_PULLD_BT_SHIFT 2
+#define PMU_VREG0_DISABLE_PULLD_WL_SHIFT 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)
+
+
+/* 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
+
+#define CR4_4349_RAM_BASE (0x180000)
+#define CR4_4349_RAM_BASE_FROM_REV_9 (0x160000)
+
+/* 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 CC2_4349_VDDM_PWRSW_EN_MASK (1 << 20)
+#define CC2_4349_VDDM_PWRSW_EN_SHIFT (20)
+#define CC2_4349_SDIO_AOS_WAKEUP_MASK (1 << 24)
+#define CC2_4349_SDIO_AOS_WAKEUP_SHIFT (24)
+
+
+#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_ENABLE_L2REFCLKPAD_PWRDWN (1 << 15)
+#define CC6_4349_PMU_EN_MDIO_MASK (1 << 16)
+#define CC6_4349_PMU_EN_ASSERT_L2_MASK (1 << 25)
+
+
+
+/* 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 PMU_MACCORE_0_RES_REQ_TIMER 0x19000000
+#define PMU_MACCORE_0_RES_REQ_MASK 0x5FF2364F
+
+#define PMU_MACCORE_1_RES_REQ_TIMER 0x19000000
+#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_4350_RAM_BASE (0x180000)
+#define CR4_4360_RAM_BASE (0x0)
+#define CR4_43602_RAM_BASE (0x180000)
+#define CA7_4365_RAM_BASE (0x200000)
+
+
+/* 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 */
+
+/* 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 SDIO host_wake */
+#define MUXENAB4350_HOSTWAKE_SHIFT 4
+
+
+/* 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_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)
+
+/* 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
+
+/* 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)
+
+/* 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
+
+/* 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)
+
+/*
+* 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
+
+
+/* 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_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)
+
+#endif /* _SBCHIPC_H */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/sbconfig.h b/drivers/net/wireless/bcmdhd_1363/include/sbconfig.h
new file mode 100644
index 000000000000..ad9c408cd344
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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/drivers/net/wireless/bcmdhd_1363/include/sbhnddma.h b/drivers/net/wireless/bcmdhd_1363/include/sbhnddma.h
new file mode 100644
index 000000000000..d66a0b6172ae
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/sbhnddma.h
@@ -0,0 +1,420 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: sbhnddma.h 530150 2015-01-29 08:43:40Z $
+ */
+
+#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
+
+/* 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
+
+/* 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_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
+
+/* 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 0x0001ffff /**< active descriptor */
+#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/drivers/net/wireless/bcmdhd_1363/include/sbpcmcia.h b/drivers/net/wireless/bcmdhd_1363/include/sbpcmcia.h
new file mode 100644
index 000000000000..121d22c4cec9
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/sbpcmcia.h
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: sbpcmcia.h 521344 2014-12-17 10:03:55Z $
+ */
+
+#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
+
+
+/* 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/drivers/net/wireless/bcmdhd_1363/include/sbsdio.h b/drivers/net/wireless/bcmdhd_1363/include/sbsdio.h
new file mode 100644
index 000000000000..68707c4d489e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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/drivers/net/wireless/bcmdhd_1363/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd_1363/include/sbsdpcmdev.h
new file mode 100644
index 000000000000..8c5fd56705a5
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/sbsdpcmdev.h
@@ -0,0 +1,298 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: sbsdpcmdev.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#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[7];
+
+ /* 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/drivers/net/wireless/bcmdhd_1363/include/sbsocram.h b/drivers/net/wireless/bcmdhd_1363/include/sbsocram.h
new file mode 100644
index 000000000000..e601814e4a91
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/sbsocram.h
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: sbsocram.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#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_<processorPT>_<backplanePT> */
+#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 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/drivers/net/wireless/bcmdhd_1363/include/sbsysmem.h b/drivers/net/wireless/bcmdhd_1363/include/sbsysmem.h
new file mode 100644
index 000000000000..cd62796608bf
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/sbsysmem.h
@@ -0,0 +1,200 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: sbsysmem.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#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_<processorPT>_<backplanePT> */
+#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 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 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
+#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 0x100
+
+#define SYSMEM_BANKIDX_MEMTYPE_SHIFT 8
+/* sysmem bankinfo memtype */
+#define SYSMEM_MEMTYPE_RAM 0
+#define SYSMEM_MEMTYPE_R0M 1
+#define SYSMEM_MEMTYPE_DEVRAM 2
+
+#define SYSMEM_BANKINFO_REG 0x40
+#define SYSMEM_BANKIDX_REG 0x10
+#define SYSMEM_BANKINFO_STDBY_MASK 0x400
+#define SYSMEM_BANKINFO_STDBY_TIMER 0x800
+
+#define SYSMEM_BANKINFO_DEVRAMSEL_SHIFT 13
+#define SYSMEM_BANKINFO_DEVRAMSEL_MASK 0x2000
+#define SYSMEM_BANKINFO_DEVRAMPRO_SHIFT 14
+#define SYSMEM_BANKINFO_DEVRAMPRO_MASK 0x4000
+#define SYSMEM_BANKINFO_SLPSUPP_SHIFT 15
+#define SYSMEM_BANKINFO_SLPSUPP_MASK 0x8000
+#define SYSMEM_BANKINFO_RETNTRAM_SHIFT 16
+#define SYSMEM_BANKINFO_RETNTRAM_MASK 0x00010000
+#define SYSMEM_BANKINFO_PDASZ_SHIFT 17
+#define SYSMEM_BANKINFO_PDASZ_MASK 0x003E0000
+#define SYSMEM_BANKINFO_DEVRAMREMAP_SHIFT 24
+#define SYSMEM_BANKINFO_DEVRAMREMAP_MASK 0x01000000
+
+/* 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/drivers/net/wireless/bcmdhd_1363/include/sdio.h b/drivers/net/wireless/bcmdhd_1363/include/sdio.h
new file mode 100644
index 000000000000..2bb33667872b
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/sdio.h
@@ -0,0 +1,625 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: sdio.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#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 */
+
+/* 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 */
+
+/* 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_3 3
+#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/drivers/net/wireless/bcmdhd_1363/include/sdioh.h b/drivers/net/wireless/bcmdhd_1363/include/sdioh.h
new file mode 100644
index 000000000000..f37c5f62aef7
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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/drivers/net/wireless/bcmdhd_1363/include/sdiovar.h b/drivers/net/wireless/bcmdhd_1363/include/sdiovar.h
new file mode 100644
index 000000000000..4f1d82d7ab0f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/sdiovar.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: sdiovar.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#ifndef _sdiovar_h_
+#define _sdiovar_h_
+
+#include <typedefs.h>
+
+/* require default structure packing */
+#define BWL_DEFAULT_PACKING
+#include <packed_section_start.h>
+
+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 NUM_PREV_TRANSACTIONS 16
+
+
+#include <packed_section_end.h>
+
+#endif /* _sdiovar_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/siutils.h b/drivers/net/wireless/bcmdhd_1363/include/siutils.h
new file mode 100644
index 000000000000..335d1fa555c5
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/siutils.h
@@ -0,0 +1,606 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: siutils.h 663718 2017-01-30 12:10:57Z $
+ */
+
+#ifndef _siutils_h_
+#define _siutils_h_
+
+#ifdef SR_DEBUG
+#include "wlioctl.h"
+#endif /* SR_DEBUG */
+
+
+/**
+ * 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;
+
+};
+
+/* 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 */
+
+#define ISSIM_ENAB(sih) FALSE
+
+/* PMU clock/power control */
+#if defined(BCMPMUCTL)
+#define PMUCTL_ENAB(sih) (BCMPMUCTL)
+#else
+#define PMUCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PMU)
+#endif
+
+#define AOB_ENAB(sih) ((sih)->ccrev >= 35 ? \
+ ((sih)->cccaps_ext & CC_CAP_EXT_AOB_PRESENT) : 0)
+
+/* 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 <osl_decl.h>
+/* === exported functions === */
+extern si_t *si_attach(uint pcidev, osl_t *osh, 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 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 uint32 *si_corereg_addr(si_t *sih, uint coreidx, uint regoff);
+extern 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_d11rsdb_core1_alt_reg_clk_dis(si_t *sih);
+extern void si_d11rsdb_core1_alt_reg_clk_en(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 void *si_setcoreidx(si_t *sih, uint coreidx);
+extern void *si_setcore(si_t *sih, uint coreid, uint coreunit);
+extern 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 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 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_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);
+
+/* 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);
+
+/* Get core base addr from core-id */
+#ifdef CUSTOMER_HW2
+extern uint32 si_corebase(si_t *sih, uint cid);
+#endif /* CUSTOMER_HW2 */
+
+/* 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);
+
+#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_seci_init(si_t *sih, uint8 use_seci) {return NULL;}
+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);
+extern bool si_is_sprom_enabled(si_t *sih);
+extern void si_sprom_enable(si_t *sih, bool enable);
+
+/* 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 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);
+#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);
+
+char *si_getnvramflvar(si_t *sih, const char *name);
+
+
+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);
+extern void si_wci2_init(si_t *sih, uint8 baudrate, uint32 ltecx_mux, uint32 ltecx_padnum,
+ uint32 ltecx_fnsel, uint32 ltecx_gcigpio);
+#endif /* BCMLTECOEX */
+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 uint16 si_cc_get_reg16(uint32 reg_offs);
+extern uint32 si_cc_get_reg32(uint32 reg_offs);
+extern uint32 si_cc_set_reg32(uint32 reg_offs, uint32 val);
+extern uint32 si_gci_preinit_upd_indirect(uint32 regidx, uint32 setval, uint32 mask);
+extern uint8 si_enable_device_wake(si_t *sih, uint8 *wake_status, uint8 *cur_status);
+extern void si_swdenable(si_t *sih, uint32 swdflag);
+
+#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);
+
+#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);
+#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))
+
+/* 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_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)
+
+/* 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_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 */
+
+extern void si_pll_sr_reinit(si_t *sih);
+extern void si_pll_closeloop(si_t *sih);
+
+#endif /* _siutils_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/spid.h b/drivers/net/wireless/bcmdhd_1363/include/spid.h
new file mode 100644
index 000000000000..8fdefa43778b
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $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/drivers/net/wireless/bcmdhd_1363/include/trxhdr.h b/drivers/net/wireless/bcmdhd_1363/include/trxhdr.h
new file mode 100644
index 000000000000..50cd3c1ac952
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: trxhdr.h 520026 2014-12-10 01:29:40Z $
+ */
+
+#ifndef _TRX_HDR_H
+#define _TRX_HDR_H
+
+#include <typedefs.h>
+
+#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/drivers/net/wireless/bcmdhd_1363/include/typedefs.h b/drivers/net/wireless/bcmdhd_1363/include/typedefs.h
new file mode 100644
index 000000000000..650ead427be5
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/typedefs.h
@@ -0,0 +1,339 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: typedefs.h 514727 2014-11-12 03:02:48Z $
+ */
+
+#ifndef _TYPEDEFS_H_
+#define _TYPEDEFS_H_
+
+#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
+
+
+
+
+
+#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 <linux/version.h>
+#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 <linux/compiler.h>
+#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 <linux/types.h> /* sys/types.h and linux/types.h are oil and water */
+
+#else
+
+#include <sys/types.h>
+
+#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))
+
+/*
+ * Including the bcmdefs.h here, to make sure everyone including typedefs.h
+ * gets this automatically
+*/
+#include <bcmdefs.h>
+#endif /* _TYPEDEFS_H_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd_1363/include/wlfc_proto.h
new file mode 100644
index 000000000000..a2d60f41f423
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/wlfc_proto.h
@@ -0,0 +1,350 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wlfc_proto.h 542895 2015-03-22 14:13:12Z $
+ *
+ */
+
+/** 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)
+
+/* Seq number part of AMSDU */
+#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))
+#define WL_SEQ_GET_AMSDU(x) (((x) >> WL_SEQ_AMSDU_SHIFT) & \
+ WL_SEQ_AMSDU_MASK)
+
+/* Seq number is valid coming from FW */
+#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))
+#define WL_SEQ_GET_FROMFW(x) (((x) >> WL_SEQ_FROMFW_SHIFT) & \
+ WL_SEQ_FROMFW_MASK)
+
+/**
+ * Proptxstatus related.
+ *
+ * Pkt from bus layer (DHD for SDIO and pciedev for PCIE)
+ * is re-using seq number previously suppressed
+ * so FW should not assign new one
+ */
+#define WL_SEQ_FROMDRV_MASK 0x1 /* allow 1 bit */
+#define WL_SEQ_FROMDRV_SHIFT 12
+#define WL_SEQ_SET_FROMDRV(x, val) ((x) = \
+ ((x) & ~(WL_SEQ_FROMDRV_MASK << WL_SEQ_FROMDRV_SHIFT)) | \
+ (((val) & WL_SEQ_FROMDRV_MASK) << WL_SEQ_FROMDRV_SHIFT))
+#define WL_SEQ_GET_FROMDRV(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
+#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))
+#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_D11_STATUS_INTERPRET(txs) \
+ ((txs)->status.was_acked ? WLFC_CTL_PKTFLAG_DISCARD : \
+ (TXS_SUPR_MAGG_DONE((txs)->status.suppr_ind) ? \
+ WLFC_CTL_PKTFLAG_DISCARD_NOACK : WLFC_CTL_PKTFLAG_D11SUPPRESS))
+
+
+#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__, __builtin_return_address(0));}} 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))
+#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))
+#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))
+#define WLFC_GET_REORDERSUPP(x) (((x) >> WLFC_MODE_REORDERSUPP_SHIFT) & 1)
+
+#endif /* __wlfc_proto_definitions_h__ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/wlioctl.h b/drivers/net/wireless/bcmdhd_1363/include/wlioctl.h
new file mode 100644
index 000000000000..5865c042bf69
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/wlioctl.h
@@ -0,0 +1,8087 @@
+/*
+ * 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.
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wlioctl.h 633955 2016-04-26 08:17:00Z $
+ */
+
+#ifndef _wlioctl_h_
+#define _wlioctl_h_
+
+#include <typedefs.h>
+#include <proto/ethernet.h>
+#include <proto/bcmip.h>
+#include <proto/bcmeth.h>
+#include <proto/bcmip.h>
+#include <proto/bcmevent.h>
+#include <proto/802.11.h>
+#include <proto/802.1d.h>
+#include <bcmwifi_channels.h>
+#include <bcmwifi_rates.h>
+#include <devctrl_if/wlioctl_defs.h>
+#include <proto/bcmipv6.h>
+
+#include <bcm_mpool_pub.h>
+#include <bcmcdc.h>
+
+
+
+
+
+typedef struct {
+ uint32 num;
+ chanspec_t list[1];
+} chanspec_list_t;
+
+#define RSN_KCK_LENGTH 16
+#define RSN_KEK_LENGTH 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)
+
+
+/* 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)
+#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 {
+ bool assoc_approved; /**< (re)association approved */
+ uint16 reject_reason; /**< reason code for rejecting association */
+ struct ether_addr da;
+ 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;
+ 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;
+ uint16 id;
+ struct ether_addr da;
+} wl_sa_query_t;
+
+/* require default structure packing */
+#define BWL_DEFAULT_PACKING
+#include <packed_section_start.h>
+
+
+/* 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
+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_prot_dynbwsw_config_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint32 version; /**< version field */
+ uint32 config_mask;
+ uint32 reset_mask;
+ wlc_prot_dynbwsw_config_t config_params;
+} BWL_POST_PACKED_STRUCT obss_config_params_t;
+
+
+/* bsscfg type */
+typedef enum bsscfg_type_t {
+ BSSCFG_TYPE_GENERIC = 0, /**< default */
+ BSSCFG_TYPE_P2P = 1, /**< The BSS is for p2p link */
+ BSSCFG_TYPE_BTA = 2,
+ BSSCFG_TYPE_TDLS = 4,
+ BSSCFG_TYPE_AWDL = 5,
+ BSSCFG_TYPE_PROXD = 6,
+ BSSCFG_TYPE_NAN = 7,
+ BSSCFG_TYPE_MAX
+} bsscfg_type_t;
+
+/* bsscfg subtype */
+enum {
+ BSSCFG_GENERIC_STA = 1, /* GENERIC */
+ BSSCFG_GENERIC_AP = 2, /* GENERIC */
+ BSSCFG_P2P_GC = 3, /* P2P */
+ BSSCFG_P2P_GO = 4, /* P2P */
+ BSSCFG_P2P_DISC = 5, /* P2P */
+};
+
+typedef struct wlc_bsscfg_info {
+ uint32 type;
+ uint32 subtype;
+} wlc_bsscfg_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];
+ struct {
+ uint 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. */
+ uint16 atim_window; /**< units are Kusec */
+ uint8 dtim_period; /**< DTIM period */
+ int16 RSSI; /**< receive signal strength (in dBm) */
+ int8 phy_noise; /**< noise (in dBm) */
+ 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];
+ struct {
+ uint 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 */
+ int16 RSSI; /**< receive signal strength (in dBm) */
+ int8 phy_noise; /**< noise (in dBm) */
+
+ uint8 n_cap; /**< BSS is 802.11N Capable */
+ uint32 nbss_cap; /**< 802.11N BSS Capabilities (based on HT_CAP_*) */
+ uint8 ctl_ch; /**< 802.11N BSS control channel number */
+ 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 */
+ 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];
+ struct {
+ uint 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 */
+ int16 RSSI; /**< receive signal strength (in dBm) */
+ int8 phy_noise; /**< noise (in dBm) */
+
+ uint8 n_cap; /**< BSS is 802.11N Capable */
+ 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 */
+ 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_BSS_INFO_VERSION 1 /* current version of wl_gscan_bss_info 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;
+ 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
+
+/* 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;
+ uchar SSID[DOT11_MAX_SSID_LEN];
+} wlc_ssid_t;
+
+typedef struct wlc_ssid_ext {
+ bool hidden;
+ uint32 SSID_len;
+ uchar 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;
+
+#ifdef CUSTOMER_HW_31_1
+
+#define AP_NORM 0
+#define AP_STEALTH 1
+#define STREET_PASS_AP 2
+
+#define NSC_MAX_TGT_SSID 20
+typedef struct nsc_ssid_entry_list {
+ wlc_ssid_t ssid_info;
+ int ssid_type;
+} nsc_ssid_entry_list_t;
+
+typedef struct nsc_ssid_list {
+ uint32 num_entries; /* N wants 150 */
+ nsc_ssid_entry_list_t ssid_entry[1];
+} nsc_ssid_list_t;
+
+#define NSC_TGT_SSID_BUFSZ (sizeof(nsc_ssid_entry_list_t) * \
+ (NSC_MAX_TGT_SSID - 1) + sizeof(nsc_ssid_list_t))
+
+/* Default values from N */
+#define NSC_SCPATT_ARRSZ 32
+
+/* scan types */
+#define UNI_SCAN 0
+#define SP_SCAN_ACTIVE 1
+#define SP_SCAN_PASSIVE 2
+#define DOZE 3
+
+/* what we found */
+typedef struct nsc_scan_results {
+ wlc_ssid_t ssid;
+ struct ether_addr mac;
+ int scantype;
+ uint16 channel;
+} nsc_scan_results_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct nsc_af_body {
+ uint8 type; /* should be 0x7f */
+ uint8 oui[DOT11_OUI_LEN]; /* just like it says */
+ uint8 subtype;
+ uint8 ielen; /* */
+ uint8 data[1]; /* variable */
+} BWL_POST_PACKED_STRUCT nsc_af_body_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct nsc_sdlist {
+ uint8 scantype;
+ uint16 duration;
+ uint16 channel; /* SP only */
+ uint8 ssid_index; /* SP only */
+ uint16 rate; /* SP only */
+} BWL_POST_PACKED_STRUCT nsc_sdlist_t;
+
+typedef struct nsc_scandes {
+ uint32 num_entries; /* number of list entries */
+ nsc_sdlist_t sdlist[1]; /* variable */
+} nsc_scandes_t;
+
+#define NSC_MAX_SDLIST_ENTRIES 8
+#define NSC_SDDESC_BUFSZ (sizeof(nsc_sdlist_t) * \
+ (NSC_MAX_SDLIST_ENTRIES - 1) + sizeof(nsc_scandes_t))
+
+#define SCAN_ARR_END (NSC_MAX_SDLIST_ENTRIES)
+#endif /* CUSTOMER_HW_31_1 */
+
+typedef BWL_PRE_PACKED_STRUCT struct wnm_url {
+ uint8 len;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT wnm_url_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 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;
+
+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_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;
+
+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;
+ 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))
+
+#define SCANOL_PARAMS_VERSION 1
+
+typedef struct scanol_params {
+ uint32 version;
+ uint32 flags; /**< offload scanning flags */
+ 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 idle_rest_time; /**< -1 use default, time idle between scan cycle */
+ int32 idle_rest_time_multiplier;
+ int32 active_rest_time;
+ int32 active_rest_time_multiplier;
+ int32 scan_cycle_idle_rest_time;
+ int32 scan_cycle_idle_rest_multiplier;
+ int32 scan_cycle_active_rest_time;
+ int32 scan_cycle_active_rest_multiplier;
+ int32 max_rest_time;
+ int32 max_scan_cycles;
+ int32 nprobes; /**< -1 use default, number of probes per channel */
+ int32 scan_start_delay;
+ uint32 nchannels;
+ uint32 ssid_count;
+ wlc_ssid_t ssidlist[1];
+} scanol_params_t;
+
+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 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;
+} 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;
+
+/* 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)
+/* scan params for extended join */
+typedef struct wl_join_scan_params {
+ uint8 scan_type; /**< 0 use default, active or passive scan */
+ 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 */
+ int noise; /**< noise floor */
+ };
+} cca_chan_qual_event_t;
+
+
+/* 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];
+ int pad_3;
+ int iv_initialized; /**< has IV been initialized already? */
+ int pad_4;
+ /* Rx IV */
+ struct {
+ uint32 hi; /**< upper 32 bits of IV */
+ uint16 lo; /**< lower 16 bits of IV */
+ } rxiv;
+ uint32 pad_5[2];
+ struct ether_addr ea; /**< per station */
+} wl_wsec_key_t;
+
+#define WSEC_MIN_PSK_LEN 8
+#define WSEC_MAX_PSK_LEN 64
+
+/* Flag for key material needing passhash'ing */
+#define WSEC_PASSPHRASE (1<<0)
+
+/* receptacle for WLC_SET_WSEC_PMK parameter */
+typedef struct {
+ ushort key_len; /**< octets in key material */
+ ushort flags; /**< key handling qualification */
+ uint8 key[WSEC_MAX_PSK_LEN]; /**< PMK material */
+} wsec_pmk_t;
+
+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;
+} wl_led_info_t;
+
+
+/* srom read/write struct passed through ioctl */
+typedef struct {
+ uint byteoff; /**< byte offset */
+ uint nbytes; /**< number of bytes */
+ uint16 buf[1];
+} 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 */
+ uint 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;
+} 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 */
+} wl_pm_mute_tx_t;
+
+
+typedef struct {
+ uint16 ver; /**< version of this struct */
+ uint16 len; /**< length in bytes of this structure */
+ uint16 cap; /**< sta's advertised capabilities */
+ uint32 flags; /**< flags defined below */
+ uint32 idle; /**< time since data pkt rx'd from sta */
+ struct ether_addr ea; /**< Station address */
+ 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 */
+ 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 */
+} sta_info_t;
+
+#define WL_OLD_STAINFO_SIZE OFFSETOF(sta_info_t, tx_tot_pkts)
+
+#define WL_STA_VER 4
+
+typedef struct {
+ 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;
+} wlc_swdiv_stats_t;
+
+#define WLC_NUMRATES 16 /**< max # of rates in a rateset */
+
+typedef struct wlc_rateset {
+ uint32 count; /**< number of rates in rates[] */
+ uint8 rates[WLC_NUMRATES]; /**< rates in 500kbps units w/hi bit set if basic */
+ uint8 htphy_membership; /**< HT PHY Membership */
+ uint8 mcs[MCSSET_LEN]; /**< supported mcs index bit map */
+ uint16 vht_mcsmap; /**< supported vht mcs nss bit map */
+ uint16 vht_mcsmap_prop; /**< supported prop vht mcs nss bit map */
+} wlc_rateset_t;
+
+/* Used to get specific STA parameters */
+typedef struct {
+ uint32 val;
+ struct ether_addr ea;
+} 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 {
+ int hw_channel;
+ int target_channel;
+ int scan_channel;
+} channel_info_t;
+
+/* For ioctls that take a list of MAC addresses */
+typedef struct maclist {
+ uint 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 {
+ uint rx_good_pkt;
+ uint rx_bad_pkt;
+ uint tx_good_pkt;
+ uint tx_bad_pkt;
+ uint 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 */
+typedef struct {
+ int rssi[LQ_IDX_LAST]; /* Array to keep min, max, avg rssi */
+ int snr[LQ_IDX_LAST]; /* Array to keep min, max, avg snr */
+ int isvalid; /* Flag indicating whether above data is valid */
+} wl_lq_t; /* Link Quality */
+
+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;
+} 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; /**< MAC Specific Rate Histogram command */
+
+/* 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; /**< MAC Specific Rate Histogram Response */
+
+/* Linux network driver ioctl encoding */
+typedef struct wl_ioctl {
+ uint cmd; /**< common ioctl definition */
+ void *buf; /**< pointer to user buffer */
+ uint len; /**< length of user buffer */
+ uint8 set; /**< 1=set IOCTL; 0=query IOCTL */
+ uint used; /**< bytes read or written (optional) */
+ uint needed; /**< bytes needed (optional) */
+} wl_ioctl_t;
+
+#ifdef CONFIG_COMPAT
+typedef struct compat_wl_ioctl {
+ uint cmd; /**< common ioctl definition */
+ uint32 buf; /**< pointer to user buffer */
+ uint len; /**< length of user buffer */
+ uint8 set; /**< 1=set IOCTL; 0=query IOCTL */
+ uint used; /**< bytes read or written (optional) */
+ uint 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 {
+ uint vendorid; /**< PCI vendor id */
+ uint deviceid; /**< device id of chip */
+ uint radiorev; /**< radio revision */
+ uint chiprev; /**< chip revision */
+ uint corerev; /**< core revision */
+ uint boardid; /**< board identifier (usu. PCI sub-device id) */
+ uint boardvendor; /**< board vendor (usu. PCI sub-vendor id) */
+ uint boardrev; /**< board revision */
+ uint driverrev; /**< driver version */
+ uint ucoderev; /**< microcode version */
+ uint bus; /**< bus type */
+ uint chipnum; /**< chip number */
+ uint phytype; /**< phy type */
+ uint phyrev; /**< phy revision */
+ uint anarev; /**< anacore rev */
+ uint chippkg; /**< chip package info */
+ uint nvramrev; /**< nvram revision number */
+} wlc_rev_info_t;
+
+#define WL_REV_INFO_LEGACY_LENGTH 48
+
+#define WL_BRAND_MAX 10
+typedef struct wl_instance_info {
+ uint instance;
+ char brand[WL_BRAND_MAX];
+} 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 30
+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 CONFIG_USBRNDIS_RETAIL
+/* struct passed in for WLC_NDCONFIG_ITEM */
+typedef struct {
+ char *name;
+ void *param;
+} ndconfig_item_t;
+#endif
+
+
+
+#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;
+ 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;
+
+typedef struct wl_aci_args {
+ int enter_aci_thresh; /* Trigger level to start detecting ACI */
+ int exit_aci_thresh; /* Trigger level to exit ACI mode */
+ int usec_spin; /* microsecs to delay between rssi samples */
+ int 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;
+ int cores;
+ /* add'l version 1 fields */
+ uint16 version; /* see definition of WL_SAMPLECOLLECT_T_VERSION */
+ uint16 length; /* length of entire structure */
+ int8 trigger;
+ uint16 timeout;
+ uint16 mode;
+ 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;
+ int bitStart;
+ uint32 gpioCapMask;
+} 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 */
+ 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;
+
+/* 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 */
+ 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;
+ /* 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 */
+ 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;
+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 {
+ int npulses; /**< required number of pulses at n * t_int */
+ int ncontig; /**< required number of pulses at t_int */
+ int min_pw; /**< minimum pulse width (20 MHz clocks) */
+ int 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 */
+ int npulses_lp; /* Radar detection, minimum long pulses */
+ int min_pw_lp; /* Minimum pulsewidth for long pulses */
+ int max_pw_lp; /* Maximum pulsewidth for long pulses */
+ int min_fm_lp; /* Minimum fm for long pulses */
+ int max_span_lp; /* Maximum deltat for long pulses */
+ int min_deltat; /* Minimum spacing between pulses */
+ int 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 */
+ uint32 version; /* version */
+ uint32 fra_pulse_err; /**< sample error margin for detecting French radar pulsed */
+ int npulses_fra; /* Radar detection, minimum French pulses set */
+ int npulses_stg2; /* Radar detection, minimum staggered-2 pulses set */
+ int npulses_stg3; /* Radar detection, minimum staggered-3 pulses set */
+ uint16 percal_mask; /**< defines which period cal is masked from radar detection */
+ int 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 */
+ int nskip_rst_lp; /**< number of skipped pulses before resetting lp buffer */
+ int max_pw_tol; /**< maximum tolerance allowd in detected pulse width for radar detection */
+ uint16 feature_mask; /* 16-bit mask to specify enabled features */
+} 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 */
+#ifdef WL11AC160
+ 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 */
+#endif /* WL11AC160 */
+} wl_radar_thr_t;
+
+#define WL_RADAR_THR_VERSION 2
+
+/* 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;
+
+/* data structure used in 'dfs_status' wl interface, which is used to query dfs status */
+typedef struct {
+ uint state; /**< noted by WL_DFS_CACSTATE_XX. */
+ uint 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 uint, add another to uint16 to maintain size */
+ uint16 pad;
+} wl_dfs_status_t;
+
+typedef struct {
+ uint state; /* noted by WL_DFS_CACSTATE_XX */
+ uint 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)
+typedef struct wl_dfs_ap_move_status {
+ 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_t;
+
+
+/* data structure used in 'radar_status' wl interface, which is use to query radar det status */
+typedef struct {
+ bool detected;
+ int count;
+ bool pretended;
+ uint32 radartype;
+ uint32 timenow;
+ uint32 timefromL;
+ int lp_csect_single;
+ int detected_pulse_index;
+ int nconsecq_pulses;
+ chanspec_t ch;
+ int pw[10];
+ int intv[10];
+ int 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 */
+} 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
+
+/*
+ * 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 */
+#define NREINITREASONCOUNT 8
+#define REINITREASONIDX(_x) (((_x) < NREINITREASONCOUNT) ? (_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 WLC_WITH_XTLV_CNT
+
+/*
+ * tlv IDs uniquely identifies counter component
+ * packed into wl_cmd_t container
+ */
+enum wl_cnt_xtlv_id {
+ WL_CNT_XTLV_WLC = 0x100, /**< WLC layer counters */
+ 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 ((uint)sizeof(uint32) * WL_CNT_MCST_VAR_NUM)
+
+#define INVALID_CNT_VAL (uint32)(-1)
+#define WL_CNT_MCXST_STRUCT_SZ ((uint)sizeof(wl_cnt_ge64mcxst_v1_t))
+
+#define WL_XTLV_CNTBUF_MAX_SIZE ((uint)(OFFSETOF(wl_cnt_info_t, data)) + \
+ (uint)BCM_XTLV_HDR_SIZE + (uint)sizeof(wl_cnt_wlc_t) + \
+ (uint)BCM_XTLV_HDR_SIZE + WL_CNT_MCST_STRUCT_SZ + \
+ (uint)BCM_XTLV_HDR_SIZE + WL_CNT_MCXST_STRUCT_SZ)
+
+#define WL_CNTBUF_MAX_SIZE MAX(WL_XTLV_CNTBUF_MAX_SIZE, (uint)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 [1]; /**< 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;
+
+/* 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 */
+} wl_cnt_wlc_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;
+
+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 */
+
+} 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; /* 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;
+ 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;
+
+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;
+};
+
+typedef struct wl_mkeep_alive_pkt {
+ uint16 version; /* Version for mkeep_alive */
+ uint16 length; /* length of fixed parameters in the structure */
+ uint32 period_msec;
+ 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
+
+/* 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 */
+} 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 */
+ uchar packet[1];
+} wake_info_t;
+
+typedef struct wake_pkt {
+ uint32 wake_pkt_len; /* size of packet */
+ uchar packet[1];
+} 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 {
+ int count; /* number of tspecs */
+ struct tsinfo_arg tsinfo[1]; /* variable length array of tsinfo */
+};
+
+#ifdef WLTDLS
+/* structure for tdls iovars */
+typedef struct tdls_iovar {
+ struct ether_addr ea; /* Station address */
+ uint8 mode; /* mode: depends on iovar */
+ chanspec_t chanspec;
+ 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;
+ 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 */
+ uint flag; /* bit field */
+ /* TSPEC Arguments */
+ struct tsinfo_arg tsinfo; /* TS Info bit field */
+ uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */
+ uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */
+ uint min_srv_interval; /* Minimum Service Interval (us) */
+ uint max_srv_interval; /* Maximum Service Interval (us) */
+ uint inactivity_interval; /* Inactivity Interval (us) */
+ uint suspension_interval; /* Suspension Interval (us) */
+ uint srv_start_time; /* Service Start Time (us) */
+ uint min_data_rate; /* Minimum Data Rate (bps) */
+ uint mean_data_rate; /* Mean Data Rate (bps) */
+ uint peak_data_rate; /* Peak Data Rate (bps) */
+ uint max_burst_size; /* Maximum Burst Size (bytes) */
+ uint delay_bound; /* Delay Bound (us) */
+ uint 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 */
+} tspec_arg_t;
+
+/* tspec arg for desired station */
+typedef struct tspec_per_sta_arg {
+ struct ether_addr ea;
+ 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;
+
+
+/* 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_SCANRESULT_VERSION 1
+#define MAX_PFN_LIST_COUNT 16
+
+#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
+
+/* PFN network info structure */
+typedef struct wl_pfn_subnet_info {
+ struct ether_addr BSSID;
+ uint8 channel; /* channel number only */
+ uint8 SSID_len;
+ uint8 SSID[32];
+} wl_pfn_subnet_info_t;
+
+typedef struct wl_pfn_net_info {
+ wl_pfn_subnet_info_t pfnsubnet;
+ int16 RSSI; /* receive signal strength (in dBm) */
+ uint16 timestamp; /* age in seconds */
+} wl_pfn_net_info_t;
+
+typedef struct wl_pfn_lnet_info {
+ wl_pfn_subnet_info_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_t;
+
+typedef struct wl_pfn_lscanresults {
+ uint32 version;
+ uint32 status;
+ uint32 count;
+ wl_pfn_lnet_info_t netinfo[1];
+} wl_pfn_lscanresults_t;
+
+/* this is used to report on 1-* pfn scan results */
+typedef struct wl_pfn_scanresults {
+ uint32 version;
+ uint32 status;
+ uint32 count;
+ wl_pfn_net_info_t netinfo[1];
+} wl_pfn_scanresults_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;
+
+
+typedef struct wl_pfn_swc_results {
+ uint32 version;
+ uint32 pkt_count;
+ uint32 total_count;
+ wl_pfn_significant_net_t list[1];
+} wl_pfn_swc_results_t;
+
+/* used to report exactly one scan result */
+/* plus reports detailed scan info in bss_info */
+typedef struct wl_pfn_scanresult {
+ uint32 version;
+ uint32 status;
+ uint32 count;
+ wl_pfn_net_info_t netinfo;
+ wl_bss_info_t bss_info;
+} wl_pfn_scanresult_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_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 CH_BUCKET_REPORT_REGULAR 0
+#define CH_BUCKET_REPORT_FULL_RESULT 2
+#define CH_BUCKET_GSCAN 4
+
+
+typedef struct wl_pfn_gscan_channel_bucket {
+ uint16 bucket_end_index;
+ uint8 bucket_freq_multiple;
+ uint8 report_flag;
+} wl_pfn_gscan_channel_bucket_t;
+
+#define GSCAN_SEND_ALL_RESULTS_MASK (1 << 0)
+#define GSCAN_CFG_FLAGS_ONLY_MASK (1 << 7)
+
+typedef struct wl_pfn_gscan_cfg {
+ /* BIT0 1 = send probes/beacons to HOST
+ * 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;
+ uint16 count_of_channel_buckets;
+ uint16 lost_ap_window;
+ wl_pfn_gscan_channel_bucket_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 WL_PFN_MAC_OUI_ONLY_MASK 1
+#define WL_PFN_SET_MAC_UNASSOC_MASK 2
+/* 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
+typedef BWL_PRE_PACKED_STRUCT struct pfn_olmsg_params_t {
+ wlc_ssid_t ssid;
+ uint32 cipher_type;
+ uint32 auth_type;
+ uint8 channels[4];
+} BWL_POST_PACKED_STRUCT pfn_olmsg_params;
+
+#define WL_PFN_HIDDEN_BIT 2
+#define WL_PFN_HIDDEN_MASK 0x4
+
+#ifndef BESTN_MAX
+#define BESTN_MAX 3
+#endif
+
+#ifndef MSCAN_MAX
+#define MSCAN_MAX 90
+#endif
+
+/*
+ * 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[1];
+} 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 BWL_PRE_PACKED_STRUCT 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 */
+} BWL_POST_PACKED_STRUCT 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 BWL_PRE_PACKED_STRUCT 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.
+ */
+} BWL_POST_PACKED_STRUCT wl_p2po_wfds_seek_add_t;
+
+/* For deleting a WFDS service to seek */
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint32 seek_hdl; /* delete service specified by id */
+} BWL_POST_PACKED_STRUCT wl_p2po_wfds_seek_del_t;
+
+
+/* For adding a WFDS service to advertise */
+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;
+
+/* For deleting a WFDS service to advertise */
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint32 advertise_hdl; /* delete service specified by hdl */
+} BWL_POST_PACKED_STRUCT 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 {
+ bool is_clear; /* set to clear list (not used on GET) */
+ 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 {
+ bool is_clear; /* set to clear list (not used on GET) */
+ uint16 count; /* number of addr in list */
+ struct ether_addr bssid[1]; /* 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 */
+};
+
+/*
+ * 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)
+
+
+/*
+ * 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;
+ uchar 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_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 }
+
+/* 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[1]; /* 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[1]; /* Variable number of list elements */
+} wl_pkt_filter_pattern_list_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 */
+ } 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)
+
+/* 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[<count>] */
+} 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 {
+ uchar KCK[RSN_KCK_LENGTH];
+ uchar KEK[RSN_KEK_LENGTH];
+ uchar 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 */
+} wl_pkteng_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 */
+} wl_pkteng_stats_t;
+
+typedef struct wl_txcal_params {
+ wl_pkteng_t pkteng;
+ uint8 gidx_start;
+ int8 gidx_step;
+ uint8 gidx_stop;
+} wl_txcal_params_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 {
+ uint 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;
+
+typedef struct {
+ uint32 pktlen; /* size of packet */
+ void *sdu;
+} tcp_keepalive_wake_pkt_infop_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.
+ */
+} wl_rssi_event_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
+
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint32 num_addrs;
+ char 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;
+
+/* This is extra info that follows wl_iov_mac_params_t */
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint32 addr_info[WL_IOV_MAC_PARAM_LEN];
+} BWL_POST_PACKED_STRUCT 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[1];
+} 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[1];
+} 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)
+
+
+#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
+
+
+/*
+ * SCB_BS_DATA iovar definitions start.
+ */
+#define SCB_BS_DATA_STRUCT_VERSION 1
+
+/* The actual counters maintained for each station */
+typedef BWL_PRE_PACKED_STRUCT 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 */
+} BWL_POST_PACKED_STRUCT iov_bs_data_counters_t;
+
+/* The structure for individual station information. */
+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;
+
+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;
+
+/* 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 {
+ int max_number;
+ uint16 module; /* bitmap */
+ uint8 level;
+ uint8 flag;
+ uint16 version;
+} wlc_extlog_cfg_t;
+
+typedef struct log_record {
+ uint32 time;
+ uint16 module;
+ uint16 id;
+ uint8 level;
+ uint8 sub_unit;
+ uint8 seq_num;
+ int32 arg;
+ char str[MAX_ARGSTR_LEN];
+} 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;
+
+#ifdef DONGLEOVERLAYS
+typedef struct {
+ uint32 flags_idx; /* lower 8 bits: overlay index; upper 24 bits: flags */
+ uint32 offset; /* offset into overlay region to write code */
+ uint32 len; /* overlay code len */
+ /* overlay code follows this struct */
+} wl_ioctl_overlay_t;
+#endif /* DONGLEOVERLAYS */
+
+/* 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;
+ uint8 bss_trans_preference;
+ uint8 pad_3[3];
+} 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;
+
+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;
+typedef BWL_PRE_PACKED_STRUCT 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 fo which dma is sucessfully completed within the test time */
+ uint32 count;
+} BWL_POST_PACKED_STRUCT pcie_bus_tput_stats_t;
+
+#define MAX_ROAMOFFL_BSSID_NUM 100
+
+typedef BWL_PRE_PACKED_STRUCT struct roamoffl_bssid_list {
+ int32 cnt;
+ struct ether_addr bssid[1];
+} BWL_POST_PACKED_STRUCT roamoffl_bssid_list_t;
+
+/* no default structure packing */
+#include <packed_section_end.h>
+
+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)
+
+/* require strict packing */
+#include <packed_section_start.h>
+
+/* ##### Power Stats section ##### */
+
+#define WL_PWRSTATS_VERSION 2
+
+/* Input structure for pwrstats IOVAR */
+typedef BWL_PRE_PACKED_STRUCT 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.
+ */
+} BWL_POST_PACKED_STRUCT wl_pwrstats_query_t;
+
+/* This structure is for version 2; version 1 will be deprecated in by FW */
+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;
+#define WL_PWR_STATS_HDRLEN OFFSETOF(wl_pwrstats_t, data)
+
+/* Type values for the data section */
+#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 */
+
+/* Bits for wake reasons */
+#define WLC_PMD_WAKE_SET 0x1
+#define WLC_PMD_PM_AWAKE_BCN 0x2
+#define WLC_PMD_BTA_ACTIVE 0x4
+#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
+#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 BWL_PRE_PACKED_STRUCT struct wlc_pm_debug {
+ uint32 timestamp; /* timestamp in millisecond */
+ uint32 reason; /* reason(s) for staying awake */
+} BWL_POST_PACKED_STRUCT 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) */
+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;
+
+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;
+
+/* WL_PWRSTATS_TYPE_PM_AWAKE2 structures */
+/* Data sent as part of pwrstats IOVAR */
+typedef BWL_PRE_PACKED_STRUCT 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 pad[3];
+ 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 pm_awake_data_v2_t;
+
+typedef BWL_PRE_PACKED_STRUCT 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;
+} BWL_POST_PACKED_STRUCT wl_pwr_pm_awake_stats_v2_t;
+
+/* Original bus structure is for HSIC */
+typedef BWL_PRE_PACKED_STRUCT 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 */
+} BWL_POST_PACKED_STRUCT bus_metrics_t;
+
+/* Bus interface info for USB/HSIC */
+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;
+
+typedef BWL_PRE_PACKED_STRUCT 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 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 */
+ uint32 deepsleep_count; /* # of times chip went to deepsleep */
+ uint32 deepsleep_dur; /* # of msecs chip was in deepsleep */
+} BWL_POST_PACKED_STRUCT pcie_bus_metrics_t;
+
+/* Bus interface info for PCIE */
+typedef BWL_PRE_PACKED_STRUCT 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 */
+} BWL_POST_PACKED_STRUCT wl_pwr_pcie_stats_t;
+
+/* Scan information history per category */
+typedef BWL_PRE_PACKED_STRUCT struct scan_data {
+ uint32 count; /* Number of scans performed */
+ uint32 dur; /* Total time (in us) used */
+} BWL_POST_PACKED_STRUCT scan_data_t;
+
+typedef BWL_PRE_PACKED_STRUCT 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 */
+} BWL_POST_PACKED_STRUCT wl_pwr_scan_stats_t;
+
+typedef BWL_PRE_PACKED_STRUCT 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 */
+} BWL_POST_PACKED_STRUCT wl_pwr_connect_stats_t;
+
+typedef BWL_PRE_PACKED_STRUCT 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 */
+} BWL_POST_PACKED_STRUCT wl_pwr_phy_stats_t;
+
+
+/* ##### End of Power Stats section ##### */
+
+/* IPV4 Arp offloads for ndis context */
+BWL_PRE_PACKED_STRUCT struct hostip_id {
+ struct ipv4_addr ipa;
+ uint8 id;
+} BWL_POST_PACKED_STRUCT;
+
+/* 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 */
+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;
+
+typedef BWL_PRE_PACKED_STRUCT struct wl_pfn_roam_thresh {
+ uint32 pfn_alert_thresh; /* time in ms */
+ uint32 roam_alert_thresh; /* time in ms */
+} BWL_POST_PACKED_STRUCT 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
+
+#define MAX_P2P_BSS_DTIM_PRD 4
+
+/* This structure is for version 3; version 2 will be deprecated in by FW */
+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;
+
+/* 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_t, 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 */
+
+typedef BWL_PRE_PACKED_STRUCT 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 */
+} BWL_POST_PACKED_STRUCT wl_pmalert_fixed_t;
+
+typedef BWL_PRE_PACKED_STRUCT 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];
+} BWL_POST_PACKED_STRUCT wl_pmalert_pmstate_t;
+
+typedef BWL_PRE_PACKED_STRUCT 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];
+} BWL_POST_PACKED_STRUCT wl_pmalert_event_dur_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct wl_pmalert_ucode_dbg {
+ 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];
+} BWL_POST_PACKED_STRUCT wl_pmalert_ucode_dbg_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))
+
+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;
+
+typedef BWL_PRE_PACKED_STRUCT struct {
+ int 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;
+
+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;
+
+/* tag_ID/length/value_buffer tuple */
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint8 id;
+ uint8 len;
+ uint8 data[1];
+} BWL_POST_PACKED_STRUCT tlv_t;
+
+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;
+
+typedef BWL_PRE_PACKED_STRUCT struct {
+ int 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;
+
+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;
+
+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;
+
+/* structures used to define format of wps ie data from probe requests */
+/* passed up to applications via iovar "prbreq_wpsie" */
+typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_hdr {
+ struct ether_addr staAddr;
+ uint16 ieLen;
+} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_hdr_t;
+
+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;
+
+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;
+
+
+#ifdef WLMEDIA_TXFAILEVENT
+typedef BWL_PRE_PACKED_STRUCT struct {
+ char dest[ETHER_ADDR_LEN]; /* destination MAC */
+ uint8 prio; /* Packet Priority */
+ uint8 flags; /* Flags */
+ uint32 tsf_l; /* TSF timer low */
+ uint32 tsf_h; /* TSF timer high */
+ uint16 rates; /* Main Rates */
+ uint16 txstatus; /* TX Status */
+} BWL_POST_PACKED_STRUCT txfailinfo_t;
+#endif /* WLMEDIA_TXFAILEVENT */
+
+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 */
+ uint 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 */
+ uint 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;
+
+typedef BWL_PRE_PACKED_STRUCT struct {
+ struct ipv4_addr ipv4_addr;
+ struct ether_addr nexthop;
+} BWL_POST_PACKED_STRUCT ibss_route_entry_t;
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint32 num_entry;
+ ibss_route_entry_t route_entry[1];
+} BWL_POST_PACKED_STRUCT ibss_route_tbl_t;
+
+#define MAX_IBSS_ROUTE_TBL_ENTRY 64
+
+#define TXPWR_TARGET_VERSION 0
+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;
+
+#define BSS_PEER_INFO_PARAM_CUR_VER 0
+/* Input structure for IOV_BSS_PEER_INFO */
+typedef BWL_PRE_PACKED_STRUCT struct {
+ uint16 version;
+ struct ether_addr ea; /* peer MAC address */
+} BWL_POST_PACKED_STRUCT bss_peer_info_param_t;
+
+#define BSS_PEER_INFO_CUR_VER 0
+
+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;
+
+#define BSS_PEER_LIST_INFO_CUR_VER 0
+
+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;
+
+#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 */
+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;
+
+#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 */
+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;
+
+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;
+
+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;
+
+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;
+
+#define WL_IPFO_ROUTE_TBL_FIXED_LEN 4
+#define WL_MAX_IPFO_ROUTE_TBL_ENTRY 64
+
+/* no strict structure packing */
+#include <packed_section_end.h>
+
+ /* Global ASSERT Logging */
+#define ASSERTLOG_CUR_VER 0x0100
+#define MAX_ASSRTSTR_LEN 64
+
+ typedef struct assert_record {
+ uint32 time;
+ uint8 seq_num;
+ char 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
+#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 {
+ bool valid;
+ uint8 trigger;
+ chanspec_t selected_chspc;
+ int8 bgnoise;
+ uint32 glitch_cnt;
+ uint8 ccastats;
+ uint8 chan_idle;
+ uint timestamp;
+ } chanim_acs_record_t;
+
+ typedef struct {
+ chanim_acs_record_t acs_record[CHANIM_ACS_RECORD];
+ uint8 count;
+ uint timestamp;
+ } wl_acs_record_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) */
+ 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 */
+ } chanim_stats_t;
+
+#define WL_CHANIM_STATS_VERSION 2
+
+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 */
+} 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 */
+ 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 {
+ int version;
+ int8 num_phy_cores; /* number of cores */
+ int8 curr_temperature; /* on-chip temperature sensor reading */
+ chanspec_t chspec; /* channspec for this state */
+ bool aci_state; /* ACI state: ON/OFF */
+ 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 */
+ 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 */
+ chanspec_t chspec; /* for p2p_ifadd GO */
+} wl_p2p_if_t;
+
+/* i/f query */
+typedef struct wl_p2p_ifq {
+ uint 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 */
+ 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];
+} wl_p2p_wfds_hash_t;
+
+typedef struct wl_bcmdcs_data {
+ uint reason;
+ chanspec_t chspec;
+} wl_bcmdcs_data_t;
+
+
+/* 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 */
+ 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 {
+ uint op; /* operation code */
+ bool pub_if; /* set for public if, clear for private if */
+ nat_if_info_t if_info; /* interface info */
+} nat_cfg_t;
+
+typedef struct {
+ int state; /* NAT state returned */
+} nat_state_t;
+
+
+#define BTA_STATE_LOG_SZ 64
+
+/* BTAMP Statemachine states */
+enum {
+ HCIReset = 1,
+ HCIReadLocalAMPInfo,
+ HCIReadLocalAMPASSOC,
+ HCIWriteRemoteAMPASSOC,
+ HCICreatePhysicalLink,
+ HCIAcceptPhysicalLinkRequest,
+ HCIDisconnectPhysicalLink,
+ HCICreateLogicalLink,
+ HCIAcceptLogicalLink,
+ HCIDisconnectLogicalLink,
+ HCILogicalLinkCancel,
+ HCIAmpStateChange,
+ HCIWriteLogicalLinkAcceptTimeout
+};
+
+typedef struct flush_txfifo {
+ uint32 txfifobmp;
+ uint32 hwtxfifoflush;
+ struct ether_addr ea;
+} 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_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 WLC_TXCAL_CORE_MAX 2 /* max number of txcore supports for txcal */
+#define MAX_NUM_TXCAL_MEAS 128
+#define MAX_NUM_PWR_STEP 40
+#define TXCAL_ROUNDING_FIX 1
+typedef struct wl_txcal_meas {
+#ifdef TXCAL_ROUNDING_FIX
+ uint16 tssi[WLC_TXCAL_CORE_MAX][MAX_NUM_TXCAL_MEAS];
+#else
+ uint8 tssi[WLC_TXCAL_CORE_MAX][MAX_NUM_TXCAL_MEAS];
+#endif /* TXCAL_ROUNDING_FIX */
+ int16 pwr[WLC_TXCAL_CORE_MAX][MAX_NUM_TXCAL_MEAS];
+ uint8 valid_cnt;
+} wl_txcal_meas_t;
+
+typedef struct wl_txcal_power_tssi {
+ uint8 set_core;
+ uint8 channel;
+ int16 tempsense[WLC_TXCAL_CORE_MAX];
+ int16 pwr_start[WLC_TXCAL_CORE_MAX];
+ uint8 pwr_start_idx[WLC_TXCAL_CORE_MAX];
+ uint8 num_entries[WLC_TXCAL_CORE_MAX];
+ uint8 tssi[WLC_TXCAL_CORE_MAX][MAX_NUM_PWR_STEP];
+ bool gen_tbl;
+} wl_txcal_power_tssi_t;
+
+/* IOVAR "mempool" parameter. Used to retrieve a list of memory pool statistics. */
+typedef struct wl_mempool_stats {
+ int 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 */
+ 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 statisics 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;
+
+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 */
+} powersel_params_t;
+
+typedef struct lpc_params {
+ /* 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 */
+} scb_delay_stats_t;
+
+/* structure for txdelay event */
+typedef struct txdelay_event {
+ uint8 status;
+ int 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 */
+} txdelay_params_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[1];
+} 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.
+ */
+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 (non-pf) */
+};
+
+/* 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 */
+} 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 */
+ 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 */
+ 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 */
+ 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];
+ 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_RANDOM_WAKEUP 0x8000
+#define WL_PROXD_MAXREPORT 8
+
+typedef struct wl_proxd_iovar {
+ uint16 method; /* Proxmity 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
+ */
+
+/* require strict packing */
+#include <packed_section_start.h>
+
+typedef BWL_PRE_PACKED_STRUCT 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) */
+} BWL_POST_PACKED_STRUCT wl_proxd_params_common_t;
+
+typedef BWL_PRE_PACKED_STRUCT 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 BWL_PRE_PACKED_STRUCT 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 */
+} BWL_POST_PACKED_STRUCT 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;
+
+
+typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_params_tof_tune {
+ 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 force_K; /* set to force value of K */
+ 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;
+} BWL_POST_PACKED_STRUCT wl_proxd_params_tof_tune_t;
+
+typedef struct wl_proxd_params_iovar {
+ uint16 method; /* Proxmity 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 meothod parameters */
+ /* tune parameters */
+ wl_proxd_params_tof_tune_t tof_tune; /* TOF tune parameters */
+ } 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 BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_query {
+ uint32 method; /* method */
+ uint8 request; /* Query request. */
+ uint8 status; /* 0 -- disable, 1 -- enable collection, */
+ /* 2 -- enable collection & debug */
+ uint16 index; /* The current frame index [0 to total_frames - 1]. */
+ uint16 mode; /* Initiator or Target */
+ bool busy; /* tof sm is busy */
+ bool remote; /* Remote collect data */
+} BWL_POST_PACKED_STRUCT wl_proxd_collect_query_t;
+
+typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_header {
+ uint16 total_frames; /* The totral 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 loaclMacAddr; /* 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;
+
+
+#ifdef WL_NAN
+/* ********************** NAN wl interface struct types and defs ******************** */
+
+#define WL_NAN_IOCTL_VERSION 0x1
+#define NAN_IOC_BUFSZ 256 /**< some sufficient ioc buff size for our module */
+#define NAN_IOC_BUFSZ_EXT 1024 /* some sufficient ioc buff size for dump commands */
+
+/* wl_nan_sub_cmd may also be used in dhd */
+typedef struct wl_nan_sub_cmd wl_nan_sub_cmd_t;
+typedef int (cmd_handler_t)(void *wl, const wl_nan_sub_cmd_t *cmd, char **argv);
+/* nan cmd list entry */
+struct wl_nan_sub_cmd {
+ char *name;
+ uint8 version; /* cmd version */
+ uint16 id; /* id for the dongle f/w switch/case */
+ uint16 type; /* base type of argument */
+ cmd_handler_t *handler; /* cmd handler */
+};
+
+/* container for nan iovtls & events */
+typedef BWL_PRE_PACKED_STRUCT 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 [1]; /* var len payload of bcm_xtlv_t type */
+} BWL_POST_PACKED_STRUCT wl_nan_ioc_t;
+
+typedef struct wl_nan_status {
+ uint8 inited;
+ uint8 joined;
+ uint8 role;
+ uint8 hop_count;
+ uint32 chspec;
+ 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 */
+ struct ether_addr cid;
+ uint32 chspec_5g;
+} wl_nan_status_t;
+
+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;
+
+/* various params and ctl swithce for nan_debug instance */
+typedef struct nan_debug_params {
+ uint8 enabled; /* runtime debuging enabled */
+ uint8 collect; /* enables debug svc sdf monitor mode */
+ uint16 cmd; /* debug cmd to perform a debug action */
+ uint32 msglevel; /* msg level if enabled */
+ uint16 status;
+} nan_debug_params_t;
+
+/* time slot */
+#define NAN_MAX_TIMESLOT 32
+typedef struct nan_timeslot {
+ uint32 abitmap; /* available bitmap */
+ uint32 chanlist[NAN_MAX_TIMESLOT];
+} nan_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;
+
+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
+};
+#define NAN_MASTER_RANK_LEN 8
+/* 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_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
+};
+
+/*
+ * tlv IDs uniquely identifies cmd parameters
+ * packed into wl_nan_ioc_t container
+ */
+enum wl_nan_cmd_xtlv_id {
+ /* 0x00 ~ 0xFF: standard TLV ID whose data format is the same as NAN attribute TLV */
+ WL_NAN_XTLV_ZERO = 0, /* used as tlv buf end marker */
+#ifdef NAN_STD_TLV /* rfu, don't use yet */
+ WL_NAN_XTLV_MASTER_IND = 1, /* == NAN_ATTR_MASTER_IND, */
+ WL_NAN_XTLV_CLUSTER = 2, /* == NAN_ATTR_CLUSTER, */
+ WL_NAN_XTLV_VENDOR = 221, /* == NAN_ATTR_VENDOR, */
+#endif
+ /* 0x02 ~ 0xFF: reserved. In case to use with the same data format as NAN attribute TLV */
+ /* 0x100 ~ : private TLV ID defined just for NAN command */
+ /* common types */
+ WL_NAN_XTLV_MAC_ADDR = 0x102, /* used in various cmds */
+ WL_NAN_XTLV_REASON = 0x103,
+ WL_NAN_XTLV_ENABLED = 0x104,
+ /* explicit types, primarily for discovery engine iovars */
+ WL_NAN_XTLV_SVC_PARAMS = 0x120, /* Contains required params: wl_nan_disc_params_t */
+ WL_NAN_XTLV_MATCH_RX = 0x121, /* Matching filter to evaluate on receive */
+ WL_NAN_XTLV_MATCH_TX = 0x122, /* Matching filter to send */
+ WL_NAN_XTLV_SVC_INFO = 0x123, /* Service specific info */
+ WL_NAN_XTLV_SVC_NAME = 0x124, /* Optional UTF-8 service name, for debugging. */
+ WL_NAN_XTLV_INSTANCE_ID = 0x125, /* Identifies unique publish or subscribe instance */
+ WL_NAN_XTLV_PRIORITY = 0x126, /* used in transmit cmd context */
+ WL_NAN_XTLV_REQUESTOR_ID = 0x127, /* Requestor instance ID */
+ WL_NAN_XTLV_VNDR = 0x128, /* Vendor specific attribute */
+ WL_NAN_XTLV_SR_FILTER = 0x129, /* Service Response Filter */
+ WL_NAN_XTLV_FOLLOWUP = 0x130, /* Service Info for Follow-Up SDF */
+ WL_NAN_XTLV_PEER_INSTANCE_ID = 0x131, /* Used to parse remote instance Id */
+ /* explicit types, primarily for NAN MAC iovars */
+ WL_NAN_XTLV_DW_LEN = 0x140, /* discovery win length */
+ WL_NAN_XTLV_BCN_INTERVAL = 0x141, /* beacon interval, both sync and descovery bcns? */
+ WL_NAN_XTLV_CLUSTER_ID = 0x142,
+ WL_NAN_XTLV_IF_ADDR = 0x143,
+ WL_NAN_XTLV_MC_ADDR = 0x144,
+ WL_NAN_XTLV_ROLE = 0x145,
+ WL_NAN_XTLV_START = 0x146,
+
+ WL_NAN_XTLV_MASTER_PREF = 0x147,
+ WL_NAN_XTLV_DW_INTERVAL = 0x148,
+ WL_NAN_XTLV_PTBTT_OVERRIDE = 0x149,
+ /* nan status command xtlvs */
+ WL_NAN_XTLV_MAC_INITED = 0x14a,
+ WL_NAN_XTLV_MAC_ENABLED = 0x14b,
+ WL_NAN_XTLV_MAC_CHANSPEC = 0x14c,
+ WL_NAN_XTLV_MAC_AMR = 0x14d, /* anchormaster rank u8 amr[8] */
+ WL_NAN_XTLV_MAC_HOPCNT = 0x14e,
+ WL_NAN_XTLV_MAC_AMBTT = 0x14f,
+ WL_NAN_XTLV_MAC_TXRATE = 0x150,
+ WL_NAN_XTLV_MAC_STATUS = 0x151, /* xtlv payload is nan_status_t */
+ WL_NAN_XTLV_NAN_SCANPARAMS = 0x152, /* payload is nan_scan_params_t */
+ WL_NAN_XTLV_DEBUGPARAMS = 0x153, /* payload is nan_scan_params_t */
+ WL_NAN_XTLV_SUBSCR_ID = 0x154, /* subscriber id */
+ WL_NAN_XTLV_PUBLR_ID = 0x155, /* publisher id */
+ WL_NAN_XTLV_EVENT_MASK = 0x156,
+ WL_NAN_XTLV_MASTER_RANK = 0x158,
+ WL_NAN_XTLV_WARM_UP_TIME = 0x159,
+ WL_NAN_XTLV_PM_OPTION = 0x15a,
+ WL_NAN_XTLV_OUI = 0x15b, /* NAN OUI */
+ WL_NAN_XTLV_MAC_COUNT = 0x15c, /* xtlv payload is nan_count_t */
+ /* nan timeslot management */
+ WL_NAN_XTLV_TSRESERVE = 0x160,
+ WL_NAN_XTLV_TSRELEASE = 0x161,
+ WL_NAN_XTLV_IDLE_DW_TIMEOUT = 0x162,
+ WL_NAN_XTLV_IDLE_DW_LEN = 0x163,
+ WL_NAN_XTLV_RND_FACTOR = 0x164,
+ WL_NAN_XTLV_SVC_DISC_TXTIME = 0x165, /* svc disc frame tx time in DW */
+ WL_NAN_XTLV_OPERATING_BAND = 0x166,
+ WL_NAN_XTLV_STOP_BCN_TX = 0x167,
+ WL_NAN_XTLV_CONCUR_SCAN = 0x168,
+ WL_NAN_XTLV_DUMP_CLR_TYPE = 0x175, /* wl nan dump/clear subtype */
+ WL_NAN_XTLV_PEER_RSSI = 0x176, /* xtlv payload for wl nan dump rssi */
+ WL_NAN_XTLV_MAC_CHANSPEC_1 = 0x17A, /* to get chanspec[1] */
+ WL_NAN_XTLV_DISC_RESULTS = 0x17B, /* get disc results */
+ WL_NAN_XTLV_MAC_STATS = 0x17C /* xtlv payload for wl nan dump stats */
+};
+
+/* Flag bits for Publish and Subscribe (wl_nan_disc_params_t flags) */
+#define WL_NAN_RANGE_LIMITED 0x0040
+/* Bits specific to Publish */
+/* Unsolicited transmissions */
+#define WL_NAN_PUB_UNSOLICIT 0x1000
+/* Solicited transmissions */
+#define WL_NAN_PUB_SOLICIT 0x2000
+#define WL_NAN_PUB_BOTH 0x3000
+/* Set for broadcast solicited transmission
+ * Do not set for unicast solicited transmission
+ */
+#define WL_NAN_PUB_BCAST 0x4000
+/* Generate event on each solicited transmission */
+#define WL_NAN_PUB_EVENT 0x8000
+/* Used for one-time solicited Publish functions to indicate transmision occurred */
+#define WL_NAN_PUB_SOLICIT_PENDING 0x10000
+/* Follow-up frames */
+#define WL_NAN_FOLLOWUP 0x20000
+/* Bits specific to Subscribe */
+/* Active subscribe mode (Leave unset for passive) */
+#define WL_NAN_SUB_ACTIVE 0x1000
+
+/* Special values for time to live (ttl) parameter */
+#define WL_NAN_TTL_UNTIL_CANCEL 0xFFFFFFFF
+/* Publish - runs until first transmission
+ * Subscribe - runs until first DiscoveryResult event
+ */
+#define WL_NAN_TTL_FIRST 0
+
+/* 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
+
+/* Instance ID type (unique identifier) */
+typedef uint8 wl_nan_instance_id_t;
+
+/* no. of max last disc results */
+#define WL_NAN_MAX_DISC_RESULTS 3
+
+/** Mandatory parameters for publish/subscribe iovars - NAN_TLV_SVC_PARAMS */
+typedef struct wl_nan_disc_params_s {
+ /* Periodicity of unsolicited/query transmissions, in DWs */
+ uint32 period;
+ /* Time to live in DWs */
+ uint32 ttl;
+ /* Flag bits */
+ uint32 flags;
+ /* Publish or subscribe service id, i.e. hash of the service name */
+ uint8 svc_hash[WL_NAN_SVC_HASH_LEN];
+ /* pad to make 4 byte alignment, can be used for something else in the future */
+ uint8 pad;
+ /* Publish or subscribe id */
+ wl_nan_instance_id_t instance_id;
+} wl_nan_disc_params_t;
+
+/* 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;
+
+/*
+* desovery interface event structures *
+*/
+
+/* 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 */
+} 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 */
+} 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_RSSI_DATA = 1,
+ WL_NAN_STATS_DATA = 2,
+/*
+ * ***** ADD before this line ****
+ */
+ WL_NAN_INVALID
+};
+
+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; /* error in txtime */
+ 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 dw interval
+ */
+ /* 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 */
+} 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 */
+ int rssi_raw; /* received rssi value */
+ int 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;
+
+/* ********************* end of NAN section ******************************** */
+#endif /* WL_NAN */
+
+
+#define RSSI_THRESHOLD_SIZE 16
+#define MAX_IMP_RESP_SIZE 256
+
+typedef BWL_PRE_PACKED_STRUCT 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) */
+} BWL_POST_PACKED_STRUCT wl_proxd_rssi_bias_t;
+
+typedef BWL_PRE_PACKED_STRUCT 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 */
+} BWL_POST_PACKED_STRUCT wl_proxd_rssi_bias_avg_t;
+
+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 */
+#ifdef RSSI_REFINE
+ wl_proxd_rssi_bias_t rssi_bias; /* RSSI refinement info */
+#endif
+ int16 nfft; /* number of samples stored in H */
+
+} BWL_POST_PACKED_STRUCT wl_proxd_collect_info_t;
+
+#define k_tof_collect_H_pad 1
+#define k_tof_collect_H_size (256+16+k_tof_collect_H_pad)
+#define k_tof_collect_Hraw_size (2*k_tof_collect_H_size)
+typedef BWL_PRE_PACKED_STRUCT struct wl_proxd_collect_data {
+ wl_proxd_collect_info_t info;
+ uint32 H[k_tof_collect_H_size]; /* raw data read from phy used to adjust timestamps */
+
+} BWL_POST_PACKED_STRUCT wl_proxd_collect_data_t;
+
+typedef BWL_PRE_PACKED_STRUCT 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 */
+} BWL_POST_PACKED_STRUCT 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),
+ /* add per-BSS properties above */
+ WL_WSEC_INFO_MAX = 0xffff
+} wl_wsec_info_type_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;
+
+/*
+ * scan MAC definitions
+ */
+
+/* common iovar struct */
+typedef struct wl_scanmac {
+ uint16 subcmd_id; /* subcommand id */
+ uint16 len; /* total length of data[] */
+ uint8 data[1]; /* 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 */
+
+/* no default structure packing */
+#include <packed_section_end.h>
+
+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 */
+ 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 */
+ 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 {
+ bool wowl_enabled;
+ bool net_detect_enabled;
+ bool 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[0];
+} net_detect_profile_list_t;
+
+typedef struct net_detect_config {
+ bool nd_enabled;
+ uint32 scan_interval;
+ uint32 wait_period;
+ bool wake_if_connected;
+ bool wake_if_disconnected;
+ 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;
+ int dur;
+ int channel;
+ struct ether_addr da;
+ uint16 random_int;
+ wlc_ssid_t ssid;
+ uint16 reps;
+} 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;
+ uint16 reps;
+} statreq_t;
+
+#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 */
+ unsigned char data[WL_RRM_RPT_MAX_PAYLOAD];
+} statrpt_t;
+
+typedef struct wlc_l2keepalive_ol_params {
+ uint8 flags;
+ uint8 prio;
+ uint16 period_ms;
+} wlc_l2keepalive_ol_params_t;
+
+typedef struct wlc_dwds_config {
+ uint32 enable;
+ uint32 mode; /* STA/AP interface */
+ struct ether_addr ea;
+} wlc_dwds_config_t;
+
+typedef struct wl_el_set_params_s {
+ uint8 set; /* Set number */
+ 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
+} 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;
+} 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 /* pmu_reg */
+
+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 */
+ char text[1]; /* 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 {
+ bool is_static;
+ uint16 sta_count;
+ uint8 chan_util;
+ uint16 aac;
+} wl_bssload_static_t;
+
+
+/* IO Var Operations - the Value of iov_op In wlc_ap_doiovar */
+typedef enum wlc_ap_iov_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_oper_t;
+
+/* LTE coex info */
+/* Analogue of HCI Set MWS Signaling cmd */
+typedef struct {
+ uint16 mws_rx_assert_offset;
+ uint16 mws_rx_assert_jitter;
+ uint16 mws_rx_deassert_offset;
+ uint16 mws_rx_deassert_jitter;
+ uint16 mws_tx_assert_offset;
+ uint16 mws_tx_assert_jitter;
+ uint16 mws_tx_deassert_offset;
+ uint16 mws_tx_deassert_jitter;
+ uint16 mws_pattern_assert_offset;
+ uint16 mws_pattern_assert_jitter;
+ uint16 mws_inact_dur_assert_offset;
+ uint16 mws_inact_dur_assert_jitter;
+ uint16 mws_scan_freq_assert_offset;
+ uint16 mws_scan_freq_assert_jitter;
+ uint16 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;
+
+/* MWS wci2 message */
+typedef struct {
+ uint8 mws_wci2_data; /* BT-SIG msg */
+ uint16 mws_wci2_interval; /* Interval in us */
+ uint16 mws_wci2_repeat; /* No of msgs to send */
+} mws_wci2_msg_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))))
+
+#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 */
+}
+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;
+
+/* Version of WLC interface to be returned as a part of wl_wlc_version structure.
+ * For the discussion related to versions update policy refer to
+ * http://hwnbu-twiki.broadcom.com/bin/view/Mwgroup/WlShimAbstractionLayer
+ * For now the policy is to increment WLC_VERSION_MAJOR each time
+ * there is a change that involves both WLC layer and per-port layer.
+ * WLC_VERSION_MINOR is currently not in use.
+ */
+#define WLC_VERSION_MAJOR 3
+#define WLC_VERSION_MINOR 0
+
+/* begin proxd definitions */
+#include <packed_section_start.h>
+
+#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 */
+ WL_PROXD_FLAG_RX_RANGE_REQ = 0x00000002, /* 11mc range requests enabled */
+ WL_PROXD_FLAG_TX_LCI = 0x00000004, /* transmit location, if available */
+ WL_PROXD_FLAG_TX_CIVIC = 0x00000008, /* tx civic loc, if available */
+ WL_PROXD_FLAG_RX_AUTO_BURST = 0x00000010, /* respond to requests w/o host action */
+ WL_PROXD_FLAG_TX_AUTO_BURST = 0x00000020, /* continue requests w/o host action */
+ WL_PROXD_FLAG_AVAIL_PUBLISH = 0x00000040, /* publish availability */
+ WL_PROXD_FLAG_AVAIL_SCHEDULE = 0x00000080, /* schedule using availability */
+ 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_TOF_COMPAT = 0x00000040, /* TOF compatibility - TBD */
+ 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 - cap or rx */
+ 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, /* No channel switching */
+ 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_COLLECT = 0x80000000, /* debug - collect */
+ 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,
+ WL_PROXD_CMD_TUNE = 16,
+ 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
+};
+
+#define WL_PROXD_SID_HOST_MAX 0x7fff
+#define WL_PROXD_SID_HOST_ALLOC(_sid) ((_sid) > 0 && (_sid) <= WL_PROXD_SID_HOST_MAX)
+
+/* 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_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_INVALIDAVB = -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;
+
+/* 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_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 struct wl_proxd_rtt_sample {
+ uint8 id; /* id for the sample - non-zero */
+ wl_proxd_rtt_sample_flags_t flags;
+ int16 rssi;
+ wl_proxd_intvl_t rtt; /* round trip time */
+ uint32 ratespec;
+} 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_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 */
+ uint16 burst_num; /* in a session */
+ uint16 num_rtt; /* 0 if no detail */
+ 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;
+
+/* 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 */
+} 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 BWL_PRE_PACKED_STRUCT wl_proxd_tlv_id_list {
+ uint16 num_ids;
+ uint16 ids[1];
+} BWL_POST_PACKED_STRUCT 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;
+
+/* 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;
+
+/* 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_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;
+} 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_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 */
+
+ /* 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_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_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 <packed_section_end.h>
+/* end proxd definitions */
+
+/* require strict packing */
+#include <packed_section_start.h>
+/* Data returned by the bssload_report iovar.
+ * This is also the WLC_E_BSS_LOAD event data.
+ */
+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;
+
+/* 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.
+ */
+} wl_bssload_cfg_t;
+
+/* Multiple roaming profile suport */
+#define WL_MAX_ROAM_PROF_BRACKETS 4
+
+#define WL_MAX_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
+
+typedef struct wl_roam_prof {
+ int8 roam_flags; /* bit flags */
+ int8 roam_trigger; /* RSSI trigger level per profile/RSSI bracket */
+ int8 rssi_lower;
+ int8 roam_delta;
+ 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; /* nuber 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;
+} wl_roam_prof_t;
+
+typedef struct wl_roam_prof_band {
+ uint32 band; /* Must be just one band */
+ uint16 ver; /* version of this struct */
+ uint16 len; /* length in bytes of this structure */
+ wl_roam_prof_t roam_prof[WL_MAX_ROAM_PROF_BRACKETS];
+} wl_roam_prof_band_t;
+
+/* Data structures for Interface Create/Remove */
+
+#define WL_INTERFACE_CREATE_VER (0)
+
+/*
+ * 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
+ */
+#define WL_INTERFACE_CREATE_STA (0 << 0)
+#define WL_INTERFACE_CREATE_AP (1 << 0)
+
+/*
+ * 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)
+
+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_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;
+
+/* no default structure packing */
+#include <packed_section_end.h>
+
+#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;
+} 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 params */
+#define M_BCNTRIM_N (0) /* Enable/Disable Beacon Trim */
+#define M_BCNTRIM_TIMEND (1) /* Waiting time for TIM IE to end */
+#define M_BCNTRIM_TSFTLRN (2) /* TSF tolerance value (usecs) */
+/* PSM internal use */
+#define M_BCNTRIM_PREVBCNLEN (3) /* Beacon length excluding the TIM IE */
+#define M_BCNTRIM_N_COUNTER (4) /* PSM's local beacon trim counter */
+#define M_BCNTRIM_STATE (5) /* PSM's Beacon trim status register */
+#define M_BCNTRIM_TIMLEN (6) /* TIM IE Length */
+#define M_BCNTRIM_BMPCTL (7) /* Bitmap control word */
+#define M_BCNTRIM_TSF_L (8) /* Lower TSF word */
+#define M_BCNTRIM_TSF_ML (9) /* Lower middle TSF word */
+#define M_BCNTRIM_RSSI (10) /* Partial beacon RSSI */
+#define M_BCNTRIM_CHANNEL (11) /* Partial beacon channel */
+/* Trimming Counters */
+#define M_BCNTRIM_SBCNRXED (12) /* Self-BSSID beacon received */
+#define M_BCNTRIM_CANTRIM (13) /* Num of beacons which can be trimmed */
+#define M_BCNTRIM_TRIMMED (14) /* # beacons which were trimmed */
+#define M_BCNTRIM_BCNLENCNG (15) /* # beacons trimmed due to length change */
+#define M_BCNTRIM_TSFADJ (16) /* # beacons not trimmed due to large TSF delta */
+#define M_BCNTRIM_TIMNOTFOUND (17) /* # beacons not trimmed due to TIM missing */
+#define M_RXTSFTMRVAL_WD0 (18)
+#define M_RXTSFTMRVAL_WD1 (19)
+#define M_RXTSFTMRVAL_WD2 (20)
+#define M_RXTSFTMRVAL_WD3 (21)
+#define BCNTRIM_STATS_NUMPARAMS (22) /* 16 bit words */
+
+#define TXPWRCAP_MAX_NUM_CORES 8
+#define TXPWRCAP_MAX_NUM_ANTENNAS (TXPWRCAP_MAX_NUM_CORES * 2)
+
+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;
+
+/* -------------- dynamic BTCOEX --------------- */
+/* require strict packing */
+#include <packed_section_start.h>
+
+#define DCTL_TROWS 2 /* currently practical number of rows */
+#define DCTL_TROWS_MAX 4 /* 2 extra rows RFU */
+/* DYNCTL profile flags */
+#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 */
+/* for now AGG on/off is handled separately */
+#define DCTL_FLAGS_TX_AGG_OFF (1 << 3) /* TBD: allow TX agg Off */
+#define DCTL_FLAGS_RX_AGG_OFF (1 << 4) /* TBD: allow RX agg Off */
+/* used for dry run testing only */
+#define DCTL_FLAGS_DRYRUN (1 << 7) /* Eenables 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)
+/* 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
+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;
+
+/* dynctl status info */
+typedef BWL_PRE_PACKED_STRUCT struct dynctl_status {
+ bool 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;
+
+/* dynctl simulation (dryrun data) */
+typedef BWL_PRE_PACKED_STRUCT struct dynctl_sim {
+ bool 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 <packed_section_end.h>
+
+/* 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 num;
+ uint32 bitmap;
+ bool addr_raw;
+ uint8 addr_num;
+ uint16 addr[MACDBG_PMAC_ADDR_INPUT_MAXNUM];
+} wl_macdbg_pmac_param_t;
+
+/* 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;
+
+#define WL_NAN_BAND_STR_SIZE 5 /* sizeof ("auto") */
+
+/* Definitions of different NAN Bands */
+enum { /* mode selection for reading/writing tx iqlo cal coefficients */
+ NAN_BAND_AUTO,
+ NAN_BAND_B,
+ NAN_BAND_A,
+ NAN_BAND_INVALID = 0xFF
+};
+
+#if defined(WL_LINKSTAT)
+typedef struct {
+ uint32 preamble;
+ uint32 nss;
+ uint32 bw;
+ uint32 rateMcsIdx;
+ uint32 reserved;
+ uint32 bitrate;
+} wifi_rate;
+
+typedef struct {
+ uint16 version;
+ uint16 length;
+ uint32 tx_mpdu;
+ uint32 rx_mpdu;
+ uint32 mpdu_lost;
+ uint32 retries;
+ uint32 retries_short;
+ uint32 retries_long;
+ wifi_rate rate;
+} wifi_rate_stat_t;
+
+typedef int32 wifi_radio;
+
+typedef struct {
+ uint16 version;
+ uint16 length;
+ 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;
+ uint8 channels[1];
+} wifi_radio_stat;
+#endif /* WL_LINKSTAT */
+
+#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 */
+
+#if defined(WLRCC)
+#define MAX_ROAM_CHANNEL 20
+
+typedef struct {
+ int n;
+ chanspec_t channels[MAX_ROAM_CHANNEL];
+} wl_roam_channel_list_t;
+#endif
+
+
+/*
+ * Neighbor Discover Offload: enable NDO feature
+ * Called by ipv6 event handler when interface comes up
+ * Set RA rate limit interval value(%)
+ */
+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
+
+#define ND_RA_OL_SET "SET"
+#define ND_RA_OL_GET "GET"
+#define ND_PARAM_SIZE 50
+#define ND_VALUE_SIZE 5
+#define ND_PARAMS_DELIMETER " "
+#define ND_PARAM_VALUE_DELLIMETER '='
+#define ND_LIMIT_STR_FMT ("%50s %50s")
+
+#define ND_RA_TYPE "TYPE"
+#define ND_RA_MIN_TIME "MIN"
+#define ND_RA_PER "PER"
+#define ND_RA_HOLD "HOLD"
+
+/*
+ * Temperature Throttling control mode
+ */
+typedef struct wl_temp_control {
+ bool enable;
+ uint16 control_bit;
+} wl_temp_control_t;
+
+/* SensorHub Iovar */
+typedef struct {
+ bool enable;
+ uint16 cmd;
+ uint16 op_mode;
+ uint16 interval;
+} shub_control_t;
+
+#endif /* _wlioctl_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/include/wlioctl_utils.h b/drivers/net/wireless/bcmdhd_1363/include/wlioctl_utils.h
new file mode 100644
index 000000000000..4d632276f640
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/include/wlioctl_utils.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wlioctl_utils.h 555740 2015-05-11 10:16:23Z $
+ */
+
+#ifndef _wlioctl_utils_h_
+#define _wlioctl_utils_h_
+
+#include <wlioctl.h>
+
+#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);
+
+/* 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)
+
+#endif /* _wlioctl_utils_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/linux_osl.c b/drivers/net/wireless/bcmdhd_1363/linux_osl.c
new file mode 100644
index 000000000000..d8f7154b1659
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/linux_osl.c
@@ -0,0 +1,2673 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: linux_osl.c 657686 2016-09-02 06:39:10Z $
+ */
+
+#define LINUX_PORT
+
+#include <typedefs.h>
+#include <bcmendian.h>
+#include <linuxver.h>
+#include <bcmdefs.h>
+
+
+#if !defined(STBLINUX)
+#if defined(__ARM_ARCH_7A__) && !defined(DHD_USE_COHERENT_MEM_FOR_RING)
+#include <asm/cacheflush.h>
+#endif /* __ARM_ARCH_7A__ && !DHD_USE_COHERENT_MEM_FOR_RING */
+#endif /* STBLINUX */
+
+#include <linux/random.h>
+
+#include <osl.h>
+#include <bcmutils.h>
+#include <linux/delay.h>
+#include <pcicfg.h>
+
+
+#ifdef BCM_SECURE_DMA
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/printk.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <asm/io.h>
+#include <linux/skbuff.h>
+#include <linux/vmalloc.h>
+#include <linux/highmem.h>
+#include <linux/dma-mapping.h>
+#include <asm/memory.h>
+#if defined(__ARM_ARCH_7A__)
+#include <arch/arm/include/asm/tlbflush.h>
+#include <arch/arm/mm/mm.h>
+#endif
+#include <linux/brcmstb/cma_driver.h>
+#endif /* BCM_SECURE_DMA */
+
+#include <linux/fs.h>
+
+
+#ifdef BCM_OBJECT_TRACE
+#include <bcmutils.h>
+#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 {
+ struct semaphore static_sem;
+ 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 64
+#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;
+ 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 cma_dev *cma;
+ struct sec_mem_elem *sec_list_512;
+ struct sec_mem_elem *sec_list_base_512;
+ struct sec_mem_elem *sec_list_2048;
+ struct sec_mem_elem *sec_list_base_2048;
+ 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;
+ phys_addr_t contig_delta_va_pa;
+ struct {
+ phys_addr_t pa;
+ void *va;
+ bool avail;
+ } sec_cma_coherent[SEC_CMA_COHERENT_MAX];
+
+#endif /* BCM_SECURE_DMA */
+};
+#ifdef BCM_SECURE_DMA
+phys_addr_t g_contig_delta_va_pa;
+static void osl_sec_dma_setup_contig_mem(osl_t *osh, unsigned long memsize, int regn);
+static int osl_sec_dma_alloc_contig_mem(osl_t *osh, unsigned long memsize, int regn);
+static void osl_sec_dma_free_contig_mem(osl_t *osh, u32 memsize, int regn);
+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 void 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 */
+
+/* Global ASSERT type flag */
+uint32 g_assert_type = 1;
+module_param(g_assert_type, int, 0);
+
+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 */
+
+/* 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 != -53
+#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];
+}
+#ifdef SHARED_OSL_CMN
+osl_t *
+osl_attach(void *pdev, uint bustype, bool pkttag, void **osl_cmn)
+{
+#else
+osl_t *
+osl_attach(void *pdev, uint bustype, bool pkttag)
+{
+ void **osl_cmn = NULL;
+#endif /* SHARED_OSL_CMN */
+ osl_t *osh;
+ gfp_t flags;
+
+ 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
+
+ osl_sec_dma_setup_contig_mem(osh, CMA_MEMBLOCK, CONT_ARMREGION);
+
+ 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);
+
+ 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);
+ osh->contig_base_va = osh->contig_base_alloc_va;
+
+ /*
+ * osl_sec_dma_init_elem_mem_block(osh, CMA_BUFSIZE_512, CMA_BUFNUM, &osh->sec_list_512);
+ * osh->sec_list_base_512 = osh->sec_list_512;
+ * osl_sec_dma_init_elem_mem_block(osh, CMA_BUFSIZE_2K, CMA_BUFNUM, &osh->sec_list_2048);
+ * osh->sec_list_base_2048 = osh->sec_list_2048;
+ */
+ osl_sec_dma_init_elem_mem_block(osh, CMA_BUFSIZE_4K, CMA_BUFNUM, &osh->sec_list_4096);
+ 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,
+ 3, 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);
+ }
+
+ sema_init(&bcm_static_buf->static_sem, 1);
+
+ 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, 4, 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
+ osl_sec_dma_free_contig_mem(osh, CMA_MEMBLOCK, CONT_ARMREGION);
+ osl_sec_dma_deinit_elem_mem_block(osh, CMA_BUFSIZE_512, CMA_BUFNUM, osh->sec_list_base_512);
+ osl_sec_dma_deinit_elem_mem_block(osh, CMA_BUFSIZE_2K, CMA_BUFNUM, osh->sec_list_base_2048);
+ 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_va, CMA_MEMBLOCK);
+#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;
+}
+
+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;
+#if defined(CONFIG_SPARSEMEM) && defined(CONFIG_ZONE_DMA)
+ flags |= GFP_ATOMIC;
+#endif
+#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;
+
+ 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->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.
+ */
+#ifdef BCMDBG_CTRACE
+void BCMFASTPATH
+osl_pkt_frmfwder(osl_t *osh, void *skbs, int skb_cnt, int line, char *file)
+#else
+void BCMFASTPATH
+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
+ */
+#ifdef BCMDBG_CTRACE
+void * BCMFASTPATH
+osl_pkt_frmnative(osl_t *osh, void *pkt, int line, char *file)
+#else
+void * BCMFASTPATH
+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 */
+#ifdef BCMDBG_CTRACE
+void * BCMFASTPATH
+osl_pktget(osl_t *osh, uint len, int line, char *file)
+#else
+#ifdef BCM_OBJECT_TRACE
+void * BCMFASTPATH
+osl_pktget(osl_t *osh, uint len, int line, const char *caller)
+#else
+void * BCMFASTPATH
+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);
+
+ /* 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 */
+#ifdef BCM_OBJECT_TRACE
+void BCMFASTPATH
+osl_pktfree(osl_t *osh, void *p, bool send, int line, const char *caller)
+#else
+void BCMFASTPATH
+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_MAX_NUM; i++) {
+ if (bcm_static_skb->skb_4k[i] &&
+ bcm_static_skb->pkt_use[i] == 0) {
+ break;
+ }
+ }
+
+ if (i != STATIC_PKT_MAX_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);
+ osl_pktfree(osh, p, send);
+#endif /* DHD_USE_STATIC_CTRLBUF */
+}
+#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)
+ {
+ int i = 0;
+ if ((size >= PAGE_SIZE)&&(size <= STATIC_BUF_SIZE))
+ {
+ down(&bcm_static_buf->static_sem);
+
+ for (i = 0; i < STATIC_BUF_MAX_NUM; i++)
+ {
+ if (bcm_static_buf->buf_use[i] == 0)
+ break;
+ }
+
+ if (i == STATIC_BUF_MAX_NUM)
+ {
+ up(&bcm_static_buf->static_sem);
+ printk("all static buff in use!\n");
+ goto original;
+ }
+
+ bcm_static_buf->buf_use[i] = 1;
+ up(&bcm_static_buf->static_sem);
+
+ 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
+ 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;
+
+ down(&bcm_static_buf->static_sem);
+ bcm_static_buf->buf_use[buf_idx] = 0;
+ up(&bcm_static_buf->static_sem);
+
+ 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);
+}
+
+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 = GFP_KERNEL;
+#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();
+}
+
+
+#if (defined(__ARM_ARCH_7A__) && !defined(DHD_USE_COHERENT_MEM_FOR_RING) || \
+ defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_SOC_EXYNOS8890))
+
+#include <asm/dma-mapping.h>
+
+/*
+ * Note that its gauranteed that the Ring is cache line aligned, but
+ * the messages are not. And we see that __dma_inv_range in
+ * arch/arm64/mm/cache.S invalidates only if the request size is
+ * cache line aligned. If not, it will Clean and invalidate.
+ * So we'll better invalidate the whole ring.
+ *
+ * Also, the latest Kernel versions invoke cache maintenance operations
+ * from arch/arm64/mm/dma-mapping.c, __swiotlb_sync_single_for_device
+ * Only if is_device_dma_coherent returns 0. Since we don't have BSP
+ * source, assuming that its the case, since we pass NULL for the dev ptr
+ */
+inline void BCMFASTPATH
+osl_cache_flush(void *va, uint size)
+{
+ /*
+ * using long for address arithmatic is OK, in linux
+ * 32 bit its 4 bytes and 64 bit its 8 bytes
+ */
+ unsigned long end_cache_line_start;
+ unsigned long end_addr;
+ unsigned long next_cache_line_start;
+
+ end_addr = (unsigned long)va + size;
+
+ /* Start address beyond the cache line we plan to operate */
+ end_cache_line_start = (end_addr & ~(L1_CACHE_BYTES - 1));
+ next_cache_line_start = end_cache_line_start + L1_CACHE_BYTES;
+
+ /* Align the start address to cache line boundary */
+ va = (void *)((unsigned long)va & ~(L1_CACHE_BYTES - 1));
+
+ /* Ensure that size is also aligned and extends partial line to full */
+ size = next_cache_line_start - (unsigned long)va;
+
+#ifndef BCM_SECURE_DMA
+
+#ifdef CONFIG_ARM64
+ /*
+ * virt_to_dma is not present in arm64/include/dma-mapping.h
+ * So have to convert the va to pa first and then get the dma addr
+ * of the same.
+ */
+ {
+ phys_addr_t pa;
+ dma_addr_t dma_addr;
+ pa = virt_to_phys(va);
+ dma_addr = phys_to_dma(NULL, pa);
+ if (size > 0)
+ dma_sync_single_for_device(OSH_NULL, dma_addr, size, DMA_TX);
+ }
+#else
+ if (size > 0)
+ dma_sync_single_for_device(OSH_NULL, virt_to_dma(OSH_NULL, va), size, DMA_TX);
+#endif /* !CONFIG_ARM64 */
+#else
+ phys_addr_t orig_pa = (phys_addr_t)(va - g_contig_delta_va_pa);
+ if (size > 0)
+ dma_sync_single_for_device(OSH_NULL, orig_pa, size, DMA_TX);
+#endif /* defined BCM_SECURE_DMA */
+}
+
+inline void BCMFASTPATH
+osl_cache_inv(void *va, uint size)
+{
+ /*
+ * using long for address arithmatic is OK, in linux
+ * 32 bit its 4 bytes and 64 bit its 8 bytes
+ */
+ unsigned long end_cache_line_start;
+ unsigned long end_addr;
+ unsigned long next_cache_line_start;
+
+ end_addr = (unsigned long)va + size;
+
+ /* Start address beyond the cache line we plan to operate */
+ end_cache_line_start = (end_addr & ~(L1_CACHE_BYTES - 1));
+ next_cache_line_start = end_cache_line_start + L1_CACHE_BYTES;
+
+ /* Align the start address to cache line boundary */
+ va = (void *)((unsigned long)va & ~(L1_CACHE_BYTES - 1));
+
+ /* Ensure that size is also aligned and extends partial line to full */
+ size = next_cache_line_start - (unsigned long)va;
+
+#ifndef BCM_SECURE_DMA
+
+#ifdef CONFIG_ARM64
+ /*
+ * virt_to_dma is not present in arm64/include/dma-mapping.h
+ * So have to convert the va to pa first and then get the dma addr
+ * of the same.
+ */
+ {
+ phys_addr_t pa;
+ dma_addr_t dma_addr;
+ pa = virt_to_phys(va);
+ dma_addr = phys_to_dma(NULL, pa);
+ dma_sync_single_for_cpu(OSH_NULL, dma_addr, size, DMA_RX);
+ }
+#else
+ dma_sync_single_for_cpu(OSH_NULL, virt_to_dma(OSH_NULL, va), size, DMA_RX);
+#endif /* !CONFIG_ARM64 */
+#else
+ phys_addr_t orig_pa = (phys_addr_t)(va - g_contig_delta_va_pa);
+ dma_sync_single_for_cpu(OSH_NULL, orig_pa, size, DMA_RX);
+#endif /* defined BCM_SECURE_DMA */
+}
+
+inline void osl_prefetch(const void *ptr)
+{
+ /* PLD instruction is not applicable in ARM 64. We don't care for now */
+#ifndef CONFIG_ARM64
+ __asm__ __volatile__("pld\t%0" :: "o"(*(const char *)ptr) : "cc");
+#endif
+}
+
+int osl_arch_is_coherent(void)
+{
+ return 0;
+}
+
+
+inline int osl_acp_war_enab(void)
+{
+ return 0;
+}
+
+#endif
+
+#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 */
+
+
+#if defined(BCMASSERT_LOG)
+ switch (g_assert_type) {
+ case 0:
+ panic("%s", tempbuf);
+ break;
+ case 1:
+ printk("%s", tempbuf);
+ break;
+ case 2:
+ printk("%s", tempbuf);
+ BUG();
+ break;
+ default:
+ break;
+ }
+#endif
+
+}
+#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);
+}
+
+
+
+/* Clone a packet.
+ * The pkttag contents are NOT cloned.
+ */
+#ifdef BCMDBG_CTRACE
+void *
+osl_pktdup(osl_t *osh, void *skb, int line, char *file)
+#else
+#ifdef BCM_OBJECT_TRACE
+void *
+osl_pktdup(osl_t *osh, void *skb, int line, const char *caller)
+#else
+void *
+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;
+
+ rdlen = kernel_read(fp, fp->f_pos, buf, len);
+ if (rdlen > 0)
+ fp->f_pos += rdlen;
+
+ 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 */
+
+
+/* APIs to set/get specific quirks in OSL layer */
+void
+osl_flag_set(osl_t *osh, uint32 mask)
+{
+ osh->flags |= mask;
+}
+
+bool
+osl_is_flag_set(osl_t *osh, uint32 mask)
+{
+ return (osh->flags & mask);
+}
+
+#ifdef BCM_SECURE_DMA
+
+static void
+osl_sec_dma_setup_contig_mem(osl_t *osh, unsigned long memsize, int regn)
+{
+ int ret;
+
+#if defined(__ARM_ARCH_7A__)
+ if (regn == CONT_ARMREGION) {
+ ret = osl_sec_dma_alloc_contig_mem(osh, memsize, regn);
+ if (ret != BCME_OK)
+ printk("linux_osl.c: CMA memory access failed\n");
+ }
+#endif
+ /* implement the MIPS Here */
+}
+
+static int
+osl_sec_dma_alloc_contig_mem(osl_t *osh, unsigned long memsize, int regn)
+{
+ u64 addr;
+
+ printk("linux_osl.c: The value of cma mem block size = %ld\n", memsize);
+ osh->cma = cma_dev_get_cma_dev(regn);
+ printk("The value of cma = %p\n", osh->cma);
+ if (!osh->cma) {
+ printk("linux_osl.c:contig_region index is invalid\n");
+ return BCME_ERROR;
+ }
+ if (cma_dev_get_mem(osh->cma, &addr, (u32)memsize, SEC_DMA_ALIGN) < 0) {
+ printk("linux_osl.c: contiguous memory block allocation failure\n");
+ return BCME_ERROR;
+ }
+ osh->contig_base_alloc = (phys_addr_t)addr;
+ osh->contig_base = (phys_addr_t)osh->contig_base_alloc;
+ printk("contig base alloc=%lx \n", (ulong)osh->contig_base_alloc);
+
+ return BCME_OK;
+}
+
+static void
+osl_sec_dma_free_contig_mem(osl_t *osh, u32 memsize, int regn)
+{
+ int ret;
+
+ ret = cma_dev_put_mem(osh->cma, (u64)osh->contig_base, memsize);
+ if (ret)
+ printf("%s contig base free failed\n", __FUNCTION__);
+}
+
+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 = (phys_addr_t)(addr - page_to_phys(page));
+ g_contig_delta_va_pa = osh->contig_delta_va_pa;
+ }
+ }
+ 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 = (phys_addr_t)(addr - page_to_phys(page));
+ g_contig_delta_va_pa = osh->contig_delta_va_pa;
+ }
+ }
+
+ 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 void
+osl_sec_dma_init_elem_mem_block(osl_t *osh, size_t mbsize, int max, sec_mem_elem_t **list)
+{
+ int i;
+ 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 = (u32)osh->contig_base_alloc;
+ sec_mem_elem->vac = osh->contig_base_alloc_va;
+
+ osh->contig_base_alloc += mbsize;
+ 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 = (u32)osh->contig_base_alloc;
+ sec_mem_elem->vac = osh->contig_base_alloc_va;
+
+ osh->contig_base_alloc += mbsize;
+ osh->contig_base_alloc_va += mbsize;
+
+ }
+ else
+ printf("%s sec mem elem kmalloc failed\n", __FUNCTION__);
+}
+
+
+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;
+
+ if (size <= 512 && osh->sec_list_512) {
+ sec_mem_elem = osh->sec_list_512;
+ osh->sec_list_512 = sec_mem_elem->next;
+ }
+ else if (size <= 2048 && osh->sec_list_2048) {
+ sec_mem_elem = osh->sec_list_2048;
+ osh->sec_list_2048 = sec_mem_elem->next;
+ }
+ else if (osh->sec_list_4096) {
+ sec_mem_elem = osh->sec_list_4096;
+ osh->sec_list_4096 = sec_mem_elem->next;
+ } else {
+ printf("%s No matching Pool available size=%d \n", __FUNCTION__, size);
+ return NULL;
+ }
+
+ if (sec_mem_elem != NULL) {
+ 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;
+ if (ptr_cma_info->sec_alloc_list == NULL)
+ ptr_cma_info->sec_alloc_list = 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;
+
+ if (sec_mem_elem->size == 512) {
+ sec_mem_elem->next = osh->sec_list_512;
+ osh->sec_list_512 = sec_mem_elem;
+ }
+ else if (sec_mem_elem->size == 2048) {
+ sec_mem_elem->next = osh->sec_list_2048;
+ osh->sec_list_2048 = sec_mem_elem;
+ }
+ else if (sec_mem_elem->size == 4096) {
+ sec_mem_elem->next = osh->sec_list_4096;
+ osh->sec_list_4096 = sec_mem_elem;
+ }
+ else
+ printf("%s free failed size=%d \n", __FUNCTION__, sec_mem_elem->size);
+}
+
+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;
+ }
+
+ 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 = 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->cma->dev, 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;
+ int *fragva;
+ uint buflen = 0;
+ struct sk_buff *skb;
+ dma_addr_t dma_handle = 0x0;
+ uint loffset;
+ int i = 0;
+
+ sec_mem_elem = osl_sec_dma_alloc_mem_elem(osh, va, size, direction, ptr_cma_info, offset);
+
+ if (sec_mem_elem == NULL) {
+ printk("linux_osl.c: osl_sec_dma_map - cma allocation failed\n");
+ return 0;
+ }
+ sec_mem_elem->va = va;
+ sec_mem_elem->direction = direction;
+ 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));
+ /* pa_cma_kmap_va = kmap_atomic(pa_cma_page);
+ * pa_cma_kmap_va += loffset;
+ */
+
+ pa_cma_kmap_va = sec_mem_elem->vac;
+
+ if (direction == DMA_TX) {
+
+ if (p == NULL) {
+
+ memcpy(pa_cma_kmap_va+offset, va, size);
+ buflen = size;
+ }
+ else {
+ for (skb = (struct sk_buff *)p; skb != NULL; skb = PKTNEXT(osh, skb)) {
+ if (skb_is_nonlinear(skb)) {
+
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *f = &skb_shinfo(skb)->frags[i];
+ fragva = kmap_atomic(skb_frag_page(f));
+ memcpy((pa_cma_kmap_va+offset+buflen),
+ (fragva + f->page_offset), skb_frag_size(f));
+ kunmap_atomic(fragva);
+ buflen += skb_frag_size(f);
+ }
+ }
+ else {
+ memcpy((pa_cma_kmap_va+offset+buflen), skb->data, skb->len);
+ buflen += skb->len;
+ }
+ }
+
+ }
+ if (dmah) {
+ dmah->nsegs = 1;
+ dmah->origsize = buflen;
+ }
+ }
+
+ else if (direction == DMA_RX)
+ {
+ buflen = size;
+ if ((p != NULL) && (dmah != NULL)) {
+ dmah->nsegs = 1;
+ dmah->origsize = buflen;
+ }
+ }
+ if (direction == DMA_RX || direction == DMA_TX) {
+
+ dma_handle = dma_map_page(osh->cma->dev, 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 = (phys_addr_t)(va - 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->cma->dev, 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;
+ struct page *pa_cma_page;
+ void *pa_cma_kmap_va = NULL;
+ uint buflen = 0;
+ dma_addr_t pa_cma;
+ void *va;
+ uint loffset = 0;
+ 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);
+ if (sec_mem_elem == NULL) {
+ printf("%s sec_mem_elem is NULL and dma_handle =0x%lx and dir=%d\n",
+ __FUNCTION__, (ulong)dma_handle, direction);
+ return;
+ }
+
+ va = sec_mem_elem->va;
+ va -= offset;
+ pa_cma = sec_mem_elem->pa_cma;
+
+ pa_cma_page = phys_to_page(pa_cma);
+ loffset = sec_mem_elem->pa_cma -(sec_mem_elem->pa_cma & ~(PAGE_SIZE-1));
+
+ 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;
+
+ dma_unmap_page(osh->cma->dev, pa_cma, size, DMA_FROM_DEVICE);
+ memcpy(va, pa_cma_kmap_va, size);
+ /* kunmap_atomic(pa_cma_kmap_va); */
+ }
+ } else {
+ dma_unmap_page(osh->cma->dev, 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->cma->dev, 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 += 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 <linux/kallsyms.h>
+#include <net/sock.h>
+void
+osl_pkt_orphan_partial(struct sk_buff *skb)
+{
+ uint32 fraction;
+ static void *p_tcp_wfree = NULL;
+
+ 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_MULTIPLIER - 1) / TSQ_MULTIPLIER;
+ skb->truesize -= fraction;
+ atomic_sub(fraction, &skb->sk->sk_wmem_alloc);
+}
+#endif /* LINUX_VERSION >= 3.6.0 && TSQ_MULTIPLIER */
diff --git a/drivers/net/wireless/bcmdhd_1363/pcie_core.c b/drivers/net/wireless/bcmdhd_1363/pcie_core.c
new file mode 100644
index 000000000000..8dcf3d177c19
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/pcie_core.c
@@ -0,0 +1,115 @@
+/** @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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: pcie_core.c 591285 2015-10-07 11:56:29Z $
+ */
+
+#include <bcm_cfg.h>
+#include <typedefs.h>
+#include <bcmutils.h>
+#include <bcmdefs.h>
+#include <osl.h>
+#include <siutils.h>
+#include <hndsoc.h>
+#include <sbchipc.h>
+
+#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);
+}
+#endif /* BCMDRIVER */
diff --git a/drivers/net/wireless/bcmdhd_1363/sbutils.c b/drivers/net/wireless/bcmdhd_1363/sbutils.c
new file mode 100644
index 000000000000..25c6cfd0a1b2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/sbutils.c
@@ -0,0 +1,1108 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: sbutils.c 514727 2014-11-12 03:02:48Z $
+ */
+
+#include <bcm_cfg.h>
+#include <typedefs.h>
+#include <bcmdefs.h>
+#include <osl.h>
+#include <bcmutils.h>
+#include <siutils.h>
+#include <bcmdevs.h>
+#include <hndsoc.h>
+#include <sbchipc.h>
+#include <pcicfg.h>
+#include <sbpcmcia.h>
+
+#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, void *regs, uint bus, uint32 sbba,
+ uint ncores);
+static uint32 _sb_coresba(si_info_t *sii);
+static 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*) ((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)
+{
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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)
+{
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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;
+ 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 = (uint32 *)((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 = (uint32 *)((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 = (uint32 *)((char *)sii->curmap +
+ PCI_16KB0_PCIREGS_OFFSET + regoff);
+ else
+ r = (uint32 *)((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 = (uint32*) ((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 {
+ if ((CHIPID(sii->pub.chip) == BCM5354_CHIP_ID) &&
+ (coreidx == SI_CC_IDX) &&
+ (regoff == OFFSETOF(chipcregs_t, watchdog))) {
+ w = val;
+ } 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.
+ */
+uint32 *
+sb_corereg_addr(si_t *sih, uint coreidx, uint regoff)
+{
+ 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 = (uint32 *)((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 = (uint32 *)((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 = (uint32 *)((char *)sii->curmap +
+ PCI_16KB0_PCIREGS_OFFSET + regoff);
+ else
+ r = (uint32 *)((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, 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 == BCM4306_CHIP_ID) /* < 4306c0 */
+ numcores = 6;
+ else 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, void *regs, uint devid)
+{
+ uint32 origsba;
+ sbconfig_t *sb;
+ si_info_t *sii = SI_INFO(sih);
+
+ 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
+ */
+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 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];
+ 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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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/drivers/net/wireless/bcmdhd_1363/siutils.c b/drivers/net/wireless/bcmdhd_1363/siutils.c
new file mode 100644
index 000000000000..44f738ff73f3
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/siutils.c
@@ -0,0 +1,3270 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: siutils.c 663718 2017-01-30 12:10:57Z $
+ */
+
+#include <bcm_cfg.h>
+#include <typedefs.h>
+#include <bcmdefs.h>
+#include <osl.h>
+#include <bcmutils.h>
+#include <siutils.h>
+#include <bcmdevs.h>
+#include <hndsoc.h>
+#include <sbchipc.h>
+#ifdef BCMPCIEDEV
+#include <pciedev.h>
+#endif /* BCMPCIEDEV */
+#include <pcicfg.h>
+#include <sbpcmcia.h>
+#include <sbsysmem.h>
+#include <sbsocram.h>
+#ifdef BCMSDIO
+#include <bcmsdh.h>
+#include <sdio.h>
+#include <sbsdio.h>
+#include <sbhnddma.h>
+#include <sbsdpcmdev.h>
+#include <bcmsdpcm.h>
+#endif /* BCMSDIO */
+#include <hndpmu.h>
+
+#ifdef BCM_SDRBL
+#include <hndcpu.h>
+#endif /* BCM_SDRBL */
+#ifdef HNDGCI
+#include <hndgci.h>
+#endif /* HNDGCI */
+
+#include "siutils_priv.h"
+
+/**
+ * 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))
+
+/* local prototypes */
+static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, 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, void *regs);
+
+
+static bool si_pmu_is_ilp_sensitive(uint32 idx, uint regoff);
+
+#ifdef BCMLTECOEX
+static void si_config_gcigpio(si_t *sih, uint32 gci_pos, uint8 gcigpio,
+ uint8 gpioctl_mask, uint8 gpioctl_val);
+#endif /* BCMLTECOEX */
+
+
+/* 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() */
+#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;
+
+/* global kernel resource */
+static si_info_t ksii;
+static si_cores_info_t ksii_cores_info;
+
+/**
+ * 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, 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",
+ ksii.pub.ccrev, wd_msticks));
+ }
+
+ return &ksii.pub;
+}
+
+
+static bool
+si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh)
+{
+ /* 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;
+}
+
+static bool
+si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin,
+ uint *origidx, 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;
+
+ /* first, enable backplane timeouts */
+ if (CHIPTYPE(sii->pub.socitype) == SOCI_AI)
+ ai_enable_backplane_timeouts(&sii->pub);
+
+ 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 (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 (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;
+ 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);
+ } 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",
+ 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) == BCM4366_CHIP_ID) ||
+ ((CHIPID(sii->pub.chip) == BCM4345_CHIP_ID ||
+ CHIPID(sii->pub.chip) == BCM43454_CHIP_ID) &&
+ 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 (BUSTYPE(sii->pub.bustype) == SI_BUS && (CHIPID(sii->pub.chip) == BCM4712_CHIP_ID) &&
+ (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (CHIPREV(sii->pub.chiprev) <= 3))
+ OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL);
+
+
+#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;
+}
+
+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 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:
+ sii->chipnew = sih->chip; /* save it */
+ sii->pub.chip = BCM4354_CHIP_ID; /* chip class */
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * 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, 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->curmap = regs;
+ sii->sdh = sdh;
+ sii->osh = osh;
+ sii->second_bar0win = ~0x0;
+
+
+ /* 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;
+ if (sih->bustype != BUSTYPE(bustype)) {
+ SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n",
+ sih->bustype, BUSTYPE(bustype)));
+ return NULL;
+ }
+
+ /* 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;
+
+ si_chipid_fixup(sih);
+
+ if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && CHIPREV(sih->chiprev == 0) &&
+ (sih->chippkg != BCM4329_289PIN_PKG_ID)) {
+ sih->chippkg = BCM4329_182PIN_PKG_ID;
+ }
+ 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 */
+ 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;
+ }
+
+#if !defined(_CFEZ_) || defined(CFG_WL)
+ if (CHIPID(sih->chip) == BCM4322_CHIP_ID && (((sih->chipst & CST4322_SPROM_OTP_SEL_MASK)
+ >> CST4322_SPROM_OTP_SEL_SHIFT) == (CST4322_OTP_PRESENT |
+ CST4322_SPROM_PRESENT))) {
+ SI_ERROR(("%s: Invalid setting: both SPROM and OTP strapped.\n", __FUNCTION__));
+ return NULL;
+ }
+
+ /* assume current core is CC */
+ if ((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 (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(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);
+}
+
+#ifdef CUSTOMER_HW2
+uint32
+si_corebase(si_t *sih, uint cid)
+{
+ si_info_t *sii = SI_INFO(sih);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ uint16 idx;
+
+ for (idx = 0; idx < SI_MAXCORES; idx++) {
+ SI_VMSG(("si_corebase cid %d idx %d core-id %d\n", cid, idx,
+ cores_info->coreid[idx]));
+ if (cid == cores_info->coreid[idx]) {
+ return cores_info->coresba[idx];
+ }
+ }
+
+ return 0;
+}
+#endif /* CUSTOMER_HW2 */
+
+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;
+}
+
+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)
+{
+ 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 */
+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
+ */
+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;
+ }
+}
+
+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 */
+void *
+si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val)
+{
+ void *cc;
+ si_info_t *sii = SI_INFO(sih);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+
+ 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 (void *)CCREGS_FAST(sii);
+ else if (coreid == sih->buscoretype)
+ return (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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+
+ if (SI_FAST(sii) && ((coreid == CC_CORE_ID) || (coreid == 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;
+ }
+}
+
+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;
+}
+uint
+si_backplane_access(si_t *sih, uint addr, uint size, uint *val, bool read)
+{
+ 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 = (uint32 *)((char *)sii->curmap + PCI_SECOND_BAR0_OFFSET + addr);
+
+ SI_VMSG(("si curmap %p region %x regaddr %x effective addr %p READ %d\n",
+ (char*)sii->curmap, region, addr, r, read));
+
+ switch (size) {
+ case sizeof(uint8) :
+ if (read)
+ *val = R_REG(sii->osh, (uint8*)r);
+ else
+ W_REG(sii->osh, (uint8*)r, *val);
+ break;
+ case sizeof(uint16) :
+ if (read)
+ *val = R_REG(sii->osh, (uint16*)r);
+ else
+ W_REG(sii->osh, (uint16*)r, *val);
+ break;
+ case sizeof(uint32) :
+ if (read)
+ *val = R_REG(sii->osh, (uint32*)r);
+ else
+ W_REG(sii->osh, (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 && 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.
+ */
+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;
+}
+
+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);
+ }
+ return 0;
+}
+
+/**
+ * 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_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_ID:
+ case BCM43454_CHIP_ID:
+ 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:
+ if (CST4349_CHIPMODE_SDIOD(sih->chipst))
+ hosti = CHIP_HOSTIF_SDIOMODE;
+ else if (CST4349_CHIPMODE_PCIE(sih->chipst))
+ hosti = CHIP_HOSTIF_PCIEMODE;
+ break;
+
+ case BCM4350_CHIP_ID:
+ case BCM4354_CHIP_ID:
+ case BCM4356_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;
+
+ if (PMUCTL_ENAB(sih)) {
+
+#if !defined(_CFEZ_) || defined(CFG_WL)
+ if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) &&
+ (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) {
+ si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), ~0, 0x2);
+ si_setcore(sih, USB20D_CORE_ID, 0);
+ si_core_disable(sih, 1);
+ si_setcore(sih, CC_CORE_ID, 0);
+ }
+#endif
+
+ nb = (sih->ccrev < 26) ? 16 : ((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;
+
+ 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 (sii->pub.ccrev < 6) {
+ if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) &&
+ (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32)) &
+ PCI_CFG_GPIO_SCS))
+ return (SCC_SS_PCI);
+ else
+ return (SCC_SS_XTAL);
+ } else if (sii->pub.ccrev < 10) {
+ cc = (chipcregs_t *)si_setcoreidx(&sii->pub, sii->curidx);
+ 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 (sii->pub.ccrev < 6) {
+ if (slowclk == SCC_SS_PCI)
+ return (max_freq ? (PCIMAXFREQ / 64) : (PCIMINFREQ / 64));
+ else
+ return (max_freq ? (XTALMAXFREQ / 32) : (XTALMINFREQ / 32));
+ } else if (sii->pub.ccrev < 10) {
+ div = 4 *
+ (((R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1);
+ if (slowclk == SCC_SS_LPO)
+ return (max_freq ? LPOMAXFREQ : LPOMINFREQ);
+ else if (slowclk == SCC_SS_XTAL)
+ return (max_freq ? (XTALMAXFREQ / div) : (XTALMINFREQ / div));
+ else if (slowclk == SCC_SS_PCI)
+ return (max_freq ? (PCIMAXFREQ / div) : (PCIMINFREQ / div));
+ else
+ ASSERT(0);
+ } else {
+ /* Chipc rev 10 is InstaClock */
+ div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT;
+ div = 4 * (div + 1);
+ return (max_freq ? XTALMAXFREQ : (XTALMINFREQ / div));
+ }
+ return (0);
+}
+
+static void
+si_clkctl_setdelay(si_info_t *sii, void *chipcregs)
+{
+ chipcregs_t *cc = (chipcregs_t *)chipcregs;
+ uint slowmaxfreq, pll_delay, slowclk;
+ uint pll_on_delay, fref_sel_delay;
+
+ pll_delay = PLL_DELAY;
+
+ /* If the slow clock is not sourced by the xtal then add the xtal_on_delay
+ * since the xtal will also be powered down by dynamic clk control logic.
+ */
+
+ slowclk = si_slowclk_src(sii);
+ if (slowclk != SCC_SS_XTAL)
+ pll_delay += XTAL_ON_DELAY;
+
+ /* Starting with 4318 it is ILP that is used for the delays */
+ slowmaxfreq = si_slowclk_freq(sii, (sii->pub.ccrev >= 10) ? FALSE : TRUE, cc);
+
+ pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
+ fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000;
+
+ W_REG(sii->osh, &cc->pll_on_delay, pll_on_delay);
+ W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay);
+}
+
+/** initialize power control delay registers */
+void
+si_clkctl_init(si_t *sih)
+{
+ si_info_t *sii;
+ uint origidx = 0;
+ chipcregs_t *cc;
+ bool fast;
+
+ if (!CCCTL_ENAB(sih))
+ return;
+
+ sii = SI_INFO(sih);
+ fast = SI_FAST(sii);
+ if (!fast) {
+ origidx = sii->curidx;
+ if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL)
+ return;
+ } else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL)
+ return;
+ ASSERT(cc != NULL);
+
+ /* set all Instaclk chip ILP to 1 MHz */
+ if (sih->ccrev >= 10)
+ SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK,
+ (ILP_DIV_1MHZ << SYCC_CD_SHIFT));
+
+ si_clkctl_setdelay(sii, (void *)(uintptr)cc);
+
+ OSL_DELAY(20000);
+
+ if (!fast)
+ si_setcoreidx(sih, origidx);
+}
+
+
+/** change logical "focus" to the gpio core for optimized access */
+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));
+}
+
+/* assign the gpio to an led */
+uint32
+si_gpioled(si_t *sih, uint32 mask, uint32 val)
+{
+ if (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 (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 (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 (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 (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, uint8 mem_type)
+{
+ uint banksize, bankinfo;
+ uint bankidx = idx | (mem_type << SYSMEM_BANKIDX_MEMTYPE_SHIFT);
+
+ ASSERT(mem_type <= SYSMEM_MEMTYPE_DEVRAM);
+
+ W_REG(sii->osh, &regs->bankidx, bankidx);
+ bankinfo = R_REG(sii->osh, &regs->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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ uint origidx;
+ uint intr_val = 0;
+
+ sysmemregs_t *regs;
+ bool wasup;
+ uint32 coreinfo;
+ uint memsize = 0;
+ uint8 i;
+ uint nb;
+
+ /* 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, &regs->coreinfo);
+
+ nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
+ for (i = 0; i < nb; i++)
+ memsize += sysmem_banksize(sii, regs, i, SYSMEM_MEMTYPE_RAM);
+
+ 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, &regs->bankidx, bankidx);
+ bankinfo = R_REG(sii->osh, &regs->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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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, &regs->bankidx, bankidx);
+ W_REG(sii->osh, &regs->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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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, &regs->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, &regs->bankidx, bankidx);
+ bankinfo = R_REG(sii->osh, &regs->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, &regs->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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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, &regs->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, &regs->bankidx, bankidx);
+ bankinfo = R_REG(sii->osh, &regs->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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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, &regs->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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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, &regs->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, &regs->bankidx, bankidx);
+ bankinfo = R_REG(sii->osh, &regs->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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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, &regs->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 = (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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ uint origidx;
+ uint intr_val = 0;
+ uint8 *regs;
+ bool wasup;
+ uint32 corecap;
+ uint memsize = 0;
+ uint32 nab = 0;
+ uint32 nbb = 0;
+ uint32 totb = 0;
+ uint32 bxinfo = 0;
+ uint32 idx = 0;
+ uint32 *arm_cap_reg;
+ uint32 *arm_bidx;
+ 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 = (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 = (uint32 *)(regs + SI_CR4_BANKIDX);
+ arm_binfo = (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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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) {
+ 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, &regs->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, &regs->bankidx, i);
+ if (R_REG(sii->osh, &regs->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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+ 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_d11rsdb_core1_alt_reg_clk_dis(si_t *sih)
+{
+#if defined(WLRSDB) && !defined(WLRSDB_DISABLED)
+ ai_d11rsdb_core1_alt_reg_clk_dis(sih);
+#endif /* defined(WLRSDB) && !defined(WLRSDB_DISABLED) */
+}
+
+void
+si_d11rsdb_core1_alt_reg_clk_en(si_t *sih)
+{
+#if defined(WLRSDB) && !defined(WLRSDB_DISABLED)
+ ai_d11rsdb_core1_alt_reg_clk_en(sih);
+#endif /* defined(WLRSDB) && !defined(WLRSDB_DISABLED) */
+}
+
+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);
+}
+
+/** check if the device is removed */
+bool
+si_deviceremoved(si_t *sih)
+{
+ uint32 w;
+
+ 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_sprom_available(si_t *sih)
+{
+ if (sih->ccrev >= 31) {
+ si_info_t *sii;
+ uint origidx;
+ chipcregs_t *cc;
+ uint32 sromctrl;
+
+ if ((sih->cccaps & CC_CAP_SROM) == 0)
+ return FALSE;
+
+ sii = SI_INFO(sih);
+ origidx = sii->curidx;
+ cc = si_setcoreidx(sih, SI_CC_IDX);
+ ASSERT(cc);
+ sromctrl = R_REG(sii->osh, &cc->sromcontrol);
+ si_setcoreidx(sih, origidx);
+ return (sromctrl & SRC_PRESENT);
+ }
+
+ switch (CHIPID(sih->chip)) {
+ case BCM4312_CHIP_ID:
+ return ((sih->chipst & CST4312_SPROM_OTP_SEL_MASK) != CST4312_OTP_SEL);
+ case BCM4325_CHIP_ID:
+ return (sih->chipst & CST4325_SPROM_SEL) != 0;
+ case BCM4322_CHIP_ID: case BCM43221_CHIP_ID: case BCM43231_CHIP_ID:
+ case BCM43222_CHIP_ID: case BCM43111_CHIP_ID: case BCM43112_CHIP_ID:
+ case BCM4342_CHIP_ID: {
+ uint32 spromotp;
+ spromotp = (sih->chipst & CST4322_SPROM_OTP_SEL_MASK) >>
+ CST4322_SPROM_OTP_SEL_SHIFT;
+ return (spromotp & CST4322_SPROM_PRESENT) != 0;
+ }
+ case BCM4329_CHIP_ID:
+ return (sih->chipst & CST4329_SPROM_SEL) != 0;
+ case BCM4315_CHIP_ID:
+ return (sih->chipst & CST4315_SPROM_SEL) != 0;
+ case BCM4319_CHIP_ID:
+ return (sih->chipst & CST4319_SPROM_SEL) != 0;
+ case BCM4336_CHIP_ID:
+ case BCM43362_CHIP_ID:
+ return (sih->chipst & CST4336_SPROM_PRESENT) != 0;
+ case BCM4330_CHIP_ID:
+ return (sih->chipst & CST4330_SPROM_PRESENT) != 0;
+ case BCM4313_CHIP_ID:
+ return (sih->chipst & CST4313_SPROM_PRESENT) != 0;
+ case 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_ID:
+ case BCM43454_CHIP_ID:
+ return ((sih->chipst & CST4335_SPROM_MASK) &&
+ !(sih->chipst & CST4335_SFLASH_MASK));
+ case BCM4349_CHIP_GRPID:
+ return (sih->chipst & CST4349_SPROM_PRESENT) != 0;
+ break;
+ case BCM4350_CHIP_ID:
+ case BCM4354_CHIP_ID:
+ case BCM4356_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;
+ 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);
+ si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
+
+ 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;
+ if (CHIPID(sih->chip) != BCM4328_CHIP_ID)
+ 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 */
+}
+
+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)
+{
+}
+
+
+
+void
+si_pll_sr_reinit(si_t *sih)
+{
+}
+
+void
+si_pll_closeloop(si_t *sih)
+{
+#if defined(SAVERESTORE)
+ uint32 data;
+
+ /* disable PLL open loop operation */
+ switch (CHIPID(sih->chip)) {
+#ifdef SAVERESTORE
+ 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
+}
diff --git a/drivers/net/wireless/bcmdhd_1363/siutils_priv.h b/drivers/net/wireless/bcmdhd_1363/siutils_priv.h
new file mode 100644
index 000000000000..56a3664e83f2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/siutils_priv.h
@@ -0,0 +1,294 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: siutils_priv.h 625731 2016-03-17 11:53:31Z $
+ */
+
+#ifndef _siutils_priv_h_
+#define _siutils_priv_h_
+
+#if defined(SI_ERROR_ENFORCE)
+#define SI_ERROR(args) printf args
+#else
+#define SI_ERROR(args)
+#endif
+
+#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;
+
+
+typedef struct si_cores_info {
+ 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;
+
+ 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 */
+
+ void *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;
+} 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 PCIEREGS(si) (((char *)((si)->curmap) + PCI_16KB0_PCIREGS_OFFSET))
+#define CCREGS_FAST(si) (((char *)((si)->curmap) + PCI_16KB0_CCREGS_OFFSET))
+
+/*
+ * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts before/
+ * after core switching to avoid invalid register accesss inside ISR.
+ */
+#define INTR_OFF(si, intr_val) \
+ if ((si)->intrsoff_fn && (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 && (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 */
+
+/* Force fast clock for 4360b0 */
+#define PCI_FORCEHT(si) \
+ (((PCIE_GEN1(si)) && (CHIPID(si->pub.chip) == BCM4311_CHIP_ID) && \
+ ((CHIPREV(si->pub.chiprev) <= 1))) || \
+ ((PCI(si) || PCIE_GEN1(si)) && (CHIPID(si->pub.chip) == BCM4321_CHIP_ID)) || \
+ (PCIE_GEN1(si) && (CHIPID(si->pub.chip) == BCM4716_CHIP_ID)) || \
+ (PCIE_GEN1(si) && (CHIPID(si->pub.chip) == BCM4748_CHIP_ID)))
+
+/* GPIO Based LED powersave defines */
+#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */
+#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */
+
+#ifndef DEFAULT_GPIOTIMERVAL
+#define DEFAULT_GPIOTIMERVAL ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME)
+#endif
+
+/* Silicon Backplane externs */
+extern void sb_scan(si_t *sih, 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 uint32 *sb_corereg_addr(si_t *sih, uint coreidx, uint regoff);
+extern bool sb_iscoreup(si_t *sih);
+extern 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 uint32 *ai_corereg_addr(si_t *sih, uint coreidx, uint regoff);
+extern bool ai_iscoreup(si_t *sih);
+extern void *ai_setcoreidx(si_t *sih, uint coreidx);
+extern 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_d11rsdb_core1_alt_reg_clk_en(si_t *sih);
+extern void ai_d11rsdb_core1_alt_reg_clk_dis(si_t *sih);
+
+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 void ai_clear_backplane_to(si_t *sih);
+
+#if defined(BCMDBG_PHYDUMP)
+extern void ai_dumpregs(si_t *sih, struct bcmstrbuf *b);
+#endif
+
+
+#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/drivers/net/wireless/bcmdhd_1363/uamp_api.h b/drivers/net/wireless/bcmdhd_1363/uamp_api.h
new file mode 100644
index 000000000000..7fe81a859430
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/uamp_api.h
@@ -0,0 +1,181 @@
+/*
+ * Name: uamp_api.h
+ *
+ * Description: Universal AMP 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: uamp_api.h 514727 2014-11-12 03:02:48Z $
+ *
+ */
+
+
+#ifndef UAMP_API_H
+#define UAMP_API_H
+
+
+#include "typedefs.h"
+
+
+/*****************************************************************************
+** Constant and Type Definitions
+******************************************************************************
+*/
+
+#define BT_API
+
+/* Types. */
+typedef bool BOOLEAN;
+typedef uint8 UINT8;
+typedef uint16 UINT16;
+
+
+/* UAMP identifiers */
+#define UAMP_ID_1 1
+#define UAMP_ID_2 2
+typedef UINT8 tUAMP_ID;
+
+/* UAMP event ids (used by UAMP_CBACK) */
+#define UAMP_EVT_RX_READY 0 /* Data from AMP controller is ready to be read */
+#define UAMP_EVT_CTLR_REMOVED 1 /* Controller removed */
+#define UAMP_EVT_CTLR_READY 2 /* Controller added/ready */
+typedef UINT8 tUAMP_EVT;
+
+
+/* UAMP Channels */
+#define UAMP_CH_HCI_CMD 0 /* HCI Command channel */
+#define UAMP_CH_HCI_EVT 1 /* HCI Event channel */
+#define UAMP_CH_HCI_DATA 2 /* HCI ACL Data channel */
+typedef UINT8 tUAMP_CH;
+
+/* tUAMP_EVT_DATA: union for event-specific data, used by UAMP_CBACK */
+typedef union {
+ tUAMP_CH channel; /* UAMP_EVT_RX_READY: channel for which rx occured */
+} tUAMP_EVT_DATA;
+
+
+/*****************************************************************************
+**
+** Function: UAMP_CBACK
+**
+** Description: Callback for events. Register callback using UAMP_Init.
+**
+** Parameters amp_id: AMP device identifier that generated the event
+** amp_evt: event id
+** p_amp_evt_data: pointer to event-specific data
+**
+******************************************************************************
+*/
+typedef void (*tUAMP_CBACK)(tUAMP_ID amp_id, tUAMP_EVT amp_evt, tUAMP_EVT_DATA *p_amp_evt_data);
+
+/*****************************************************************************
+** external function declarations
+******************************************************************************
+*/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****************************************************************************
+**
+** Function: UAMP_Init
+**
+** Description: Initialize UAMP driver
+**
+** Parameters p_cback: Callback function for UAMP event notification
+**
+******************************************************************************
+*/
+BT_API BOOLEAN UAMP_Init(tUAMP_CBACK p_cback);
+
+
+/*****************************************************************************
+**
+** Function: UAMP_Open
+**
+** Description: Open connection to local AMP device.
+**
+** Parameters app_id: Application specific AMP identifer. This value
+** will be included in AMP messages sent to the
+** BTU task, to identify source of the message
+**
+******************************************************************************
+*/
+BT_API BOOLEAN UAMP_Open(tUAMP_ID amp_id);
+
+/*****************************************************************************
+**
+** Function: UAMP_Close
+**
+** Description: Close connection to local AMP device.
+**
+** Parameters app_id: Application specific AMP identifer.
+**
+******************************************************************************
+*/
+BT_API void UAMP_Close(tUAMP_ID amp_id);
+
+
+/*****************************************************************************
+**
+** Function: UAMP_Write
+**
+** Description: Send buffer to AMP device. Frees GKI buffer when done.
+**
+**
+** Parameters: app_id: AMP identifer.
+** p_buf: pointer to buffer to write
+** num_bytes: number of bytes to write
+** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_CMD
+**
+** Returns: number of bytes written
+**
+******************************************************************************
+*/
+BT_API UINT16 UAMP_Write(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 num_bytes, tUAMP_CH channel);
+
+/*****************************************************************************
+**
+** Function: UAMP_Read
+**
+** Description: Read incoming data from AMP. Call after receiving a
+** UAMP_EVT_RX_READY callback event.
+**
+** Parameters: app_id: AMP identifer.
+** p_buf: pointer to buffer for holding incoming AMP data
+** buf_size: size of p_buf
+** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_EVT
+**
+** Returns: number of bytes read
+**
+******************************************************************************
+*/
+BT_API UINT16 UAMP_Read(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 buf_size, tUAMP_CH channel);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UAMP_API_H */
diff --git a/drivers/net/wireless/bcmdhd_1363/wl_android.c b/drivers/net/wireless/bcmdhd_1363/wl_android.c
new file mode 100644
index 000000000000..dcf4c8a79614
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/wl_android.c
@@ -0,0 +1,3861 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wl_android.c 664848 2017-04-28 14:33:00Z $
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <net/netlink.h>
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+#endif
+
+#include <wl_android.h>
+#include <wldev_common.h>
+#include <wlioctl.h>
+#include <bcmutils.h>
+#include <linux_osl.h>
+#include <dhd_dbg.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <proto/bcmip.h>
+#ifdef PNO_SUPPORT
+#include <dhd_pno.h>
+#endif
+#ifdef BCMSDIO
+#include <bcmsdbus.h>
+#endif
+#ifdef WL_CFG80211
+#include <wl_cfg80211.h>
+#endif
+#ifdef WL_NAN
+#include <wl_cfgnan.h>
+#endif /* WL_NAN */
+#ifdef DHDTCPACK_SUPPRESS
+#include <dhd_ip.h>
+#endif /* DHDTCPACK_SUPPRESS */
+
+#ifdef DHD_BANDSTEER
+#include <dhd_bandsteer.h>
+#endif /* DHD_BANDSTEER */
+
+/*
+ * 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"
+#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"
+#ifdef WL_NAN
+#define CMD_NAN "NAN_"
+#endif /* WL_NAN */
+#define CMD_COUNTRY_DELIMITER "/"
+#ifdef WL11ULB
+#define CMD_ULB_MODE "ULB_MODE"
+#define CMD_ULB_BW "ULB_BW"
+#endif /* WL11ULB */
+
+#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 SUPPORT_HIDDEN_AP
+/* Hostapd private command */
+#define CMD_SET_HAPD_MAX_NUM_STA "HAPD_MAX_NUM_STA"
+#define CMD_SET_HAPD_SSID "HAPD_SSID"
+#define CMD_SET_HAPD_HIDE_SSID "HIDE_SSID"
+#endif /* SUPPORT_HIDDEN_AP */
+#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"
+#define CMD_ADDIE "add_ie"
+#define CMD_DELIE "del_ie"
+
+#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"
+
+/* FCC_PWR_LIMIT_2G */
+#define CUSTOMER_HW4_ENABLE 0
+#define CUSTOMER_HW4_DISABLE -1
+#define CUSTOMER_HW4_EN_CONVERT(i) (i += 1)
+
+#ifdef WLTDLS
+#define CMD_TDLS_RESET "TDLS_RESET"
+#endif /* WLTDLS */
+
+#ifdef IPV6_NDO_SUPPORT
+#define CMD_NDRA_LIMIT "NDRA_LIMIT"
+#endif /* IPV6_NDO_SUPPORT */
+
+#endif /* CUSTOMER_HW4_PRIVATE_CMD */
+
+
+#define CMD_ROAM_OFFLOAD "SETROAMOFFLOAD"
+#define CMD_ROAM_OFFLOAD_APLIST "SETROAMOFFLAPLIST"
+#define CMD_INTERFACE_CREATE "INTERFACE_CREATE"
+#define CMD_INTERFACE_DELETE "INTERFACE_DELETE"
+
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
+#define CMD_GET_BSS_INFO "GETBSSINFO"
+#define CMD_GET_ASSOC_REJECT_INFO "GETASSOCREJECTINFO"
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
+
+#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"
+
+#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 DHD_BANDSTEER
+#define CMD_BANDSTEER_ENABLE "BANDSTEER_ENABLE"
+#define CMD_BANDSTEER_TRIGGER "BANDSTEER_TRIGGER"
+#endif /* DHD_BANDSTEER */
+
+/* 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
+
+#define CMD_AP_ISOLATE "AP_ISOLATE"
+
+#define CMD_MAXASSOC "MAXASSOC"
+
+#define CMD_CHANNEL_WIDTH "CHANNEL_WIDTH"
+
+#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 */
+
+static LIST_HEAD(miracast_resume_list);
+static u8 miracast_cur_mode;
+
+#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_TRACE_WAKE_LOCK
+extern void dhd_wk_lock_stats_dump(dhd_pub_t *dhdp);
+#endif /* DHD_TRACE_WAKE_LOCK */
+
+struct io_cfg {
+ s8 *iovar;
+ s32 param;
+ u32 ioctl;
+ void *arg;
+ u32 len;
+ struct list_head list;
+};
+
+typedef struct _android_wifi_priv_cmd {
+ char *buf;
+ int used_len;
+ int total_len;
+} android_wifi_priv_cmd;
+
+#ifdef CONFIG_COMPAT
+typedef struct _compat_android_wifi_priv_cmd {
+ compat_caddr_t buf;
+ int used_len;
+ int total_len;
+} compat_android_wifi_priv_cmd;
+#endif /* CONFIG_COMPAT */
+
+#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 */
+
+
+/**
+ * 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 /* WK_CFG80211 */
+
+
+#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
+ */
+static int g_wifi_on = TRUE;
+
+/**
+ * Local (static) function definitions
+ */
+
+
+static int wl_android_set_ap_isolate(struct net_device *dev, char *command, int total_len)
+{
+ int val = 0, bytes_written = 0;
+
+ if (*(command + strlen(CMD_AP_ISOLATE)) == '\0') {
+ val = dhd_android_ap_isolate_getval(dev);
+ bytes_written = snprintf(command, total_len, "%s %d", CMD_AP_ISOLATE, val);
+ return bytes_written;
+ }
+ command = (command + strlen(CMD_AP_ISOLATE));
+ command++;
+ val = bcm_atoi(command);
+
+ DHD_INFO(("%s : ap_isolate = %d\n", __FUNCTION__, val));
+ dhd_android_ap_isolate_setval(dev, val);
+ return 0;
+}
+
+static int
+wl_android_set_maxassoc_limit(struct net_device *dev, char *command, int total_len)
+{
+ int ret = 0, max_assoc = 0, bytes_written = 0;
+
+ if (*(command + strlen(CMD_MAXASSOC)) == '\0') {
+ ret = wldev_iovar_getint(dev, "maxassoc", &max_assoc);
+ if (ret) {
+ DHD_ERROR(("%s: Failed to get maxassoc limit\n", __FUNCTION__));
+ return ret;
+ }
+ bytes_written = snprintf(command, total_len, "%s %d", CMD_MAXASSOC, max_assoc);
+ return bytes_written;
+ }
+ command = (command + strlen(CMD_MAXASSOC));
+ command++;
+ max_assoc = bcm_atoi(command);
+
+ DHD_INFO(("%s : maxassoc limit = %d\n", __FUNCTION__, max_assoc));
+ ret = wldev_iovar_setint(dev, "maxassoc", max_assoc);
+ if (ret) {
+ DHD_ERROR(("%s: Failed to set maxassoc limit to %d\n", __FUNCTION__, max_assoc));
+ return ret;
+ }
+ return 0;
+}
+
+static int
+wl_android_set_channel_width(struct net_device *dev, char *command, int total_len)
+{
+ u32 channel_width = 0;
+
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy);
+
+ command = (command + strlen(CMD_CHANNEL_WIDTH));
+ command++;
+ channel_width = bcm_atoi(command);
+ if (channel_width == 80)
+ wl_set_chanwidth_by_netdev(cfg, dev, WL_CHANSPEC_BW_80);
+ else if (channel_width == 40)
+ wl_set_chanwidth_by_netdev(cfg, dev, WL_CHANSPEC_BW_40);
+ else if (channel_width == 20)
+ wl_set_chanwidth_by_netdev(cfg, dev, WL_CHANSPEC_BW_20);
+ else
+ return 0;
+
+ DHD_INFO(("%s : channel width = %d\n", __FUNCTION__, channel_width));
+ return 0;
+}
+
+#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) {
+ DHD_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) {
+ DHD_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)
+ return -1;
+
+ /* Convert Kbps to Android Mbps */
+ link_speed = link_speed / 1000;
+ bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
+ DHD_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};
+ int bytes_written = 0;
+ int error = 0;
+ scb_val_t scbval;
+ char *delim = NULL;
+
+ delim = strchr(command, ' ');
+ /* For Ap mode rssi command would be
+ * driver rssi <sta_mac_addr>
+ * for STA/GC mode
+ * driver rssi
+ */
+ if (delim) {
+ /* Ap/GO mode
+ * driver rssi <sta_mac_addr>
+ */
+ DHD_TRACE(("%s: cmd:%s\n", __FUNCTION__, delim));
+ /* skip space from delim after finding char */
+ delim++;
+ if (!(bcm_ether_atoe((delim), &scbval.ea)))
+ {
+ DHD_ERROR(("%s:address err\n", __FUNCTION__));
+ return -1;
+ }
+ scbval.val = htod32(0);
+ DHD_TRACE(("%s: address:"MACDBG, __FUNCTION__, MAC2STRDBG(scbval.ea.octet)));
+ }
+ else {
+ /* STA/GC mode */
+ memset(&scbval, 0, sizeof(scb_val_t));
+ }
+
+ error = wldev_get_rssi(net, &scbval);
+ if (error)
+ return -1;
+
+ error = wldev_get_ssid(net, &ssid);
+ if (error)
+ return -1;
+ if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
+ DHD_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';
+
+ DHD_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))) {
+ DHD_INFO(("%s: Suspend Flag %d -> %d\n",
+ __FUNCTION__, ret_now, suspend_flag));
+ } else {
+ DHD_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)))
+ DHD_INFO(("%s: Suspend Mode %d\n", __FUNCTION__, suspend_flag));
+ else
+ DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
+#endif
+
+ return ret;
+}
+
+static int wl_android_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))) {
+ DHD_TRACE(("%s: use Max bcn_li_dtim in suspend %s\n",
+ __FUNCTION__, (dtim_flag ? "Enable" : "Disable")));
+ } else {
+ DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
+ }
+
+ return ret;
+}
+
+int wl_android_get_80211_mode(struct net_device *dev, char *command, int total_len)
+{
+ uint8 mode[4];
+ int error = 0;
+ int bytes_written = 0;
+
+ error = wldev_get_mode(dev, mode);
+ if (error)
+ return -1;
+
+ DHD_INFO(("%s: mode:%s\n", __FUNCTION__, mode));
+ bytes_written = snprintf(command, total_len, "%s %s", CMD_80211_MODE, mode);
+ DHD_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);
+ DHD_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;
+
+ DHD_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);
+
+ DHD_INFO(("%s: command:%s EXIT\n", __FUNCTION__, command));
+ return bytes_written;
+
+}
+
+/* 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;
+
+ DHD_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;
+
+ DHD_TRACE(("%s: ENTER\n", __FUNCTION__));
+
+ assoc_maclist->count = htod32(MAX_NUM_OF_ASSOCLIST);
+
+ error = wldev_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, sizeof(mac_buf), false);
+ 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;
+
+}
+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;
+
+ DHD_INFO(("%s: command:%s\n", __FUNCTION__, command));
+
+ command = (command + strlen(CMD_SET_CSA));
+ /* Order is mode, count channel */
+ if (!*++command) {
+ DHD_ERROR(("%s:error missing arguments\n", __FUNCTION__));
+ return -1;
+ }
+ csa_arg.mode = bcm_atoi(command);
+
+ if (csa_arg.mode != 0 && csa_arg.mode != 1) {
+ DHD_ERROR(("Invalid mode\n"));
+ return -1;
+ }
+
+ if (!*++command) {
+ DHD_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) {
+ DHD_ERROR(("%s:error missing channel\n", __FUNCTION__));
+ return -1;
+ }
+
+ chnsp = wf_chspec_aton(command);
+ if (chnsp == 0) {
+ DHD_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)) {
+ DHD_ERROR(("Channel is radar sensitive\n"));
+ return -1;
+ }
+ if (chanspec == 0) {
+ DHD_ERROR(("Invalid hw channel\n"));
+ return -1;
+ }
+ } else {
+ DHD_ERROR(("does not support per_chan_info\n"));
+ return -1;
+ }
+ DHD_INFO(("non radar sensitivity\n"));
+ }
+ error = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg),
+ smbuf, sizeof(smbuf), NULL);
+ if (error) {
+ DHD_ERROR(("%s:set csa failed:%d\n", __FUNCTION__, error));
+ return -1;
+ }
+ return 0;
+}
+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;
+}
+
+static int wl_android_add_vendor_ie(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;
+
+ pcmd = command + strlen(CMD_ADDIE) + 1;
+
+ pktflag = simple_strtoul(pcmd, &pcmd, 16);
+
+ pcmd = pcmd + 1;
+
+ for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
+ 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++;
+ }
+
+ tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1);
+ vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags);
+ if (!vndr_ie) {
+ WL_ERR(("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 the appropriate frame will contain this IE */
+ pktflag = htod32(1<<pktflag);
+ 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;
+
+ /* Set the OUI */
+ memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
+ DOT11_OUI_LEN);
+ /* Set the Data */
+ 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) {
+ WL_ERR(("ioctl memory alloc failed\n"));
+ if (vndr_ie) {
+ kfree(vndr_ie);
+ }
+ return -ENOMEM;
+ }
+ memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */
+ err = wldev_iovar_setbuf(dev, "ie", vndr_ie, tot_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
+
+ 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;
+}
+
+static int wl_android_del_vendor_ie(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;
+
+ pcmd = command + strlen(CMD_ADDIE) + 1;
+
+ pktflag = simple_strtoul(pcmd, &pcmd, 16);
+
+ pcmd = pcmd + 1;
+ for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
+ 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++;
+ }
+
+ tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1);
+ vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags);
+ if (!vndr_ie) {
+ WL_ERR(("IE memory alloc failed\n"));
+ return -ENOMEM;
+ }
+ /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
+ strncpy(vndr_ie->cmd, "del", 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 the appropriate frame will contain this IE */
+ pktflag = htod32(1<<pktflag);
+ 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;
+
+ /* Set the OUI */
+ memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
+ DOT11_OUI_LEN);
+ /* Set the Data */
+ 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) {
+ WL_ERR(("ioctl memory alloc failed\n"));
+ if (vndr_ie) {
+ kfree(vndr_ie);
+ }
+ return -ENOMEM;
+ }
+ memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */
+ err = wldev_iovar_setbuf(dev, "ie", vndr_ie, tot_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
+
+ 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;
+}
+
+
+#ifdef CUSTOMER_HW4_PRIVATE_CMD
+
+#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)) {
+ DHD_ERROR(("%s: Invalid data\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+
+ CUSTOMER_HW4_EN_CONVERT(enable);
+
+ DHD_ERROR(("%s: fccpwrlimit2g set (%d)\n", __FUNCTION__, enable));
+ error = wldev_iovar_setint(dev, "fccpwrlimit2g", enable);
+ if (error) {
+ DHD_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) {
+ DHD_ERROR(("%s: fccpwrlimit2g get error (%d)\n", __FUNCTION__, error));
+ return BCME_ERROR;
+ }
+ DHD_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 */
+
+#ifdef IPV6_NDO_SUPPORT
+int
+wl_android_nd_ra_limit(struct net_device *dev, char *command, int total_len)
+{
+ int err = 0;
+ int bytes_written = 0;
+ char *pos, *token, *delim;
+ char smbuf[WLC_IOCTL_SMLEN];
+ char param[ND_PARAM_SIZE+1], value[ND_VALUE_SIZE+1];
+ uint16 type = 0xff, min = 0, per = 0, hold = 0;
+ nd_ra_ol_limits_t ra_ol_limit;
+
+ WL_TRACE(("command=%s, len=%d\n", command, total_len));
+ pos = command + strlen(CMD_NDRA_LIMIT) + 1;
+ memset(&ra_ol_limit, 0, sizeof(nd_ra_ol_limits_t));
+
+ if (!strncmp(pos, ND_RA_OL_SET, strlen(ND_RA_OL_SET))) {
+ WL_TRACE(("SET NDRA_LIMIT\n"));
+ pos += strlen(ND_RA_OL_SET) + 1;
+ while ((token = strsep(&pos, ND_PARAMS_DELIMETER)) != NULL) {
+ memset(param, 0, sizeof(param));
+ memset(value, 0, sizeof(value));
+
+ delim = strchr(token, ND_PARAM_VALUE_DELLIMETER);
+ if (delim != NULL)
+ *delim = ' ';
+
+ if (!strncmp(param, ND_RA_TYPE, strlen(ND_RA_TYPE))) {
+ type = simple_strtol(value, NULL, 0);
+ } else if (!strncmp(param, ND_RA_MIN_TIME, strlen(ND_RA_MIN_TIME))) {
+ min = simple_strtol(value, NULL, 0);
+ } else if (!strncmp(param, ND_RA_PER, strlen(ND_RA_PER))) {
+ per = simple_strtol(value, NULL, 0);
+ if (per > 100) {
+ WL_ERR(("Invalid PERCENT %d\n", per));
+ err = BCME_BADARG;
+ goto exit;
+ }
+ } else if (!strncmp(param, ND_RA_HOLD, strlen(ND_RA_HOLD))) {
+ hold = simple_strtol(value, NULL, 0);
+ }
+ }
+
+ ra_ol_limit.version = htod32(ND_RA_OL_LIMITS_VER);
+ ra_ol_limit.type = htod32(type);
+ if (type == ND_RA_OL_LIMITS_REL_TYPE) {
+ if ((min == 0) || (per == 0)) {
+ WL_ERR(("Invalid min_time %d, percent %d\n", min, per));
+ err = BCME_BADARG;
+ goto exit;
+ }
+ ra_ol_limit.length = htod32(ND_RA_OL_LIMITS_REL_TYPE_LEN);
+ ra_ol_limit.limits.lifetime_relative.min_time = htod32(min);
+ ra_ol_limit.limits.lifetime_relative.lifetime_percent = htod32(per);
+ } else if (type == ND_RA_OL_LIMITS_FIXED_TYPE) {
+ if (hold == 0) {
+ WL_ERR(("Invalid hold_time %d\n", hold));
+ err = BCME_BADARG;
+ goto exit;
+ }
+ ra_ol_limit.length = htod32(ND_RA_OL_LIMITS_FIXED_TYPE_LEN);
+ ra_ol_limit.limits.fixed.hold_time = htod32(hold);
+ } else {
+ WL_ERR(("unknown TYPE %d\n", type));
+ err = BCME_BADARG;
+ goto exit;
+ }
+
+ err = wldev_iovar_setbuf(dev, "nd_ra_limit_intv", &ra_ol_limit,
+ sizeof(nd_ra_ol_limits_t), smbuf, sizeof(smbuf), NULL);
+ if (err) {
+ WL_ERR(("Failed to set nd_ra_limit_intv, error = %d\n", err));
+ goto exit;
+ }
+
+ WL_TRACE(("TYPE %d, MIN %d, PER %d, HOLD %d\n", type, min, per, hold));
+ } else if (!strncmp(pos, ND_RA_OL_GET, strlen(ND_RA_OL_GET))) {
+ WL_TRACE(("GET NDRA_LIMIT\n"));
+ err = wldev_iovar_getbuf(dev, "nd_ra_limit_intv", NULL, 0,
+ smbuf, sizeof(smbuf), NULL);
+ if (err) {
+ WL_ERR(("Failed to get nd_ra_limit_intv, error = %d\n", err));
+ goto exit;
+ }
+
+ memcpy(&ra_ol_limit, (uint8 *)smbuf, sizeof(nd_ra_ol_limits_t));
+ type = ra_ol_limit.type;
+ if (ra_ol_limit.version != ND_RA_OL_LIMITS_VER) {
+ WL_ERR(("Invalid Version %d\n", ra_ol_limit.version));
+ err = BCME_VERSION;
+ goto exit;
+ }
+
+ if (ra_ol_limit.type == ND_RA_OL_LIMITS_REL_TYPE) {
+ min = ra_ol_limit.limits.lifetime_relative.min_time;
+ per = ra_ol_limit.limits.lifetime_relative.lifetime_percent;
+ WL_ERR(("TYPE %d, MIN %d, PER %d\n", type, min, per));
+ bytes_written = snprintf(command, total_len,
+ "%s GET TYPE %d, MIN %d, PER %d", CMD_NDRA_LIMIT, type, min, per);
+ } else if (ra_ol_limit.type == ND_RA_OL_LIMITS_FIXED_TYPE) {
+ hold = ra_ol_limit.limits.fixed.hold_time;
+ WL_ERR(("TYPE %d, HOLD %d\n", type, hold));
+ bytes_written = snprintf(command, total_len,
+ "%s GET TYPE %d, HOLD %d", CMD_NDRA_LIMIT, type, hold);
+ } else {
+ WL_ERR(("unknown TYPE %d\n", type));
+ err = BCME_ERROR;
+ goto exit;
+ }
+
+ return bytes_written;
+ } else {
+ WL_ERR(("unknown command\n"));
+ err = BCME_ERROR;
+ goto exit;
+ }
+
+exit:
+ return err;
+}
+#endif /* IPV6_NDO_SUPPORT */
+#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) {
+ DHD_ERROR(("Disable tdls failed. %d\n", ret));
+ return ret;
+ }
+ ret = dhd_tdls_enable(dev, true, true, NULL);
+ if (ret < 0) {
+ DHD_ERROR(("enable tdls failed. %d\n", ret));
+ return ret;
+ }
+ return 0;
+}
+#endif /* WLTDLS */
+#endif /* CUSTOMER_HW4_PRIVATE_CMD */
+
+#define ROAM_PROF_A "a -70 -75 70 10 -75 -128 0 10"
+#define ROAM_PROF_B "b -60 -75 70 10 -75 -128 0 10"
+#define ROAM_PROF_LEN 64
+
+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];
+
+ argc = sscanf(command+sizeof(CMD_WBTEXT_ENABLE), "%d", &data);
+ if (!argc) {
+ error = wldev_iovar_getint(dev, "wnm_bsstrans_resp", &data);
+ if (error) {
+ DHD_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)? "ENABLED" : "DISABLED");
+ return bytes_written;
+ } else {
+ if (data) {
+ char *roam_prof;
+ char commandp[ROAM_PROF_LEN];
+ snprintf(commandp, ROAM_PROF_LEN, CMD_WBTEXT_PROFILE_CONFIG);
+
+ /* When enable wnm_bsstrans_resp, roam_prof set default value. */
+ roam_prof = ROAM_PROF_A;
+ error = wl_cfg80211_wbtext_config(dev, roam_prof, commandp, ROAM_PROF_LEN);
+ if (error != BCME_OK) {
+ DHD_ERROR(("%s: Failed to set roam_prof %s error = %d\n",
+ __FUNCTION__, roam_prof, error));
+ return error;
+ }
+ roam_prof = ROAM_PROF_B;
+ error = wl_cfg80211_wbtext_config(dev, roam_prof, commandp, ROAM_PROF_LEN);
+ if (error != BCME_OK) {
+ DHD_ERROR(("%s: Failed to set roam_prof %s error = %d\n",
+ __FUNCTION__, roam_prof, error));
+ return error;
+ }
+
+ data = WL_BSSTRANS_POLICY_PRODUCT;
+ }
+
+ if ((error = wldev_iovar_setint(dev, "wnm_bsstrans_resp", data)) != BCME_OK) {
+ DHD_ERROR(("%s: Failed to set wbtext error = %d\n",
+ __FUNCTION__, error));
+ return error;
+ }
+
+ if (!data) {
+ /* 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(dev, WLC_SET_ROAM_TRIGGER, roam_trigger,
+ sizeof(roam_trigger), 1)) != BCME_OK) {
+ DHD_ERROR(("%s: Failed to reset roam trigger = %d\n",
+ __FUNCTION__, error));
+ return error;
+ }
+ }
+ }
+ return error;
+}
+
+#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], value[VALUE_SIZE];
+ struct dhd_pno_batch_params batch_params;
+ DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
+ if (total_len < strlen(CMD_WLS_BATCHING)) {
+ DHD_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);
+ DHD_PNO(("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);
+ DHD_PNO(("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);
+ DHD_PNO(("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;
+ DHD_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;
+ DHD_PNO(("band : %s\n",
+ (*token2 == 'A')? "A" : "B"));
+ } else {
+ batch_params.chan_list[i++] =
+ simple_strtol(token2, NULL, 0);
+ batch_params.nchan++;
+ DHD_PNO(("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);
+ DHD_PNO(("rtt : %d\n", batch_params.rtt));
+ } else {
+ DHD_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) {
+ DHD_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) {
+ DHD_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) {
+ DHD_ERROR(("failed to stop batching scan\n"));
+ } else {
+ memset(command, 0, total_len);
+ err = snprintf(command, total_len, "OK");
+ }
+ } else {
+ DHD_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 */
+ DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
+
+ if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
+ DHD_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_iw_parse_ssid_list_tlv(&str_ptr, ssids_local,
+ MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
+ DHD_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)) {
+ DHD_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);
+ DHD_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
+
+ if (str_ptr[0] != 0) {
+ if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
+ DHD_ERROR(("%s pno repeat : corrupted field\n",
+ __FUNCTION__));
+ goto exit_proc;
+ }
+ str_ptr++;
+ pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
+ DHD_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
+ if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
+ DHD_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);
+ DHD_PNO(("%s: pno_freq_expo_max=%d\n",
+ __FUNCTION__, pno_freq_expo_max));
+ }
+ }
+ } else {
+ DHD_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(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode), true)) != 0) {
+ DHD_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(dev, WLC_SET_MACLIST, maclist,
+ sizeof(int) + sizeof(struct ether_addr) * maclist->count, true)) != 0) {
+ DHD_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(dev, WLC_GET_ASSOCLIST, assoc_maclist,
+ sizeof(mac_buf), false)) != 0) {
+ DHD_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++) {
+ DHD_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(dev,
+ WLC_SCB_DEAUTHENTICATE_FOR_REASON,
+ &scbval, sizeof(scb_val_t), true)) != 0)
+ DHD_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, const char* str)
+{
+ int i;
+ int ret = 0;
+ int macnum = 0;
+ int macmode = MACLIST_MODE_DISABLED;
+ struct maclist *list;
+ char eabuf[ETHER_ADDR_STR_LEN];
+ 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) {
+ DHD_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) {
+ DHD_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) {
+ DHD_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]))) {
+ DHD_ERROR(("%s : mac parsing err index=%d, addr=%s\n",
+ __FUNCTION__, i, eabuf));
+ list->count--;
+ break;
+ }
+ DHD_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)
+ DHD_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;
+
+ DHD_ERROR(("%s in\n", __FUNCTION__));
+ if (!dev) {
+ DHD_ERROR(("%s: dev is null\n", __FUNCTION__));
+ return -EINVAL;
+ }
+
+ dhd_net_if_lock(dev);
+ if (!g_wifi_on) {
+ do {
+ 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;
+ }
+ DHD_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) {
+ DHD_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n"));
+ goto exit;
+ }
+#ifdef BCMSDIO
+ ret = dhd_net_bus_devreset(dev, FALSE);
+ dhd_net_bus_resume(dev, 1);
+#endif /* BCMSDIO */
+
+#ifndef BCMPCIE
+ if (!ret) {
+ if (dhd_dev_init_ioctl(dev) < 0) {
+ ret = -EFAULT;
+ }
+ }
+#endif /* !BCMPCIE */
+ g_wifi_on = TRUE;
+ }
+
+exit:
+ dhd_net_if_unlock(dev);
+
+ return ret;
+}
+
+int wl_android_wifi_off(struct net_device *dev, bool on_failure)
+{
+ int ret = 0;
+
+ DHD_ERROR(("%s in\n", __FUNCTION__));
+ if (!dev) {
+ DHD_TRACE(("%s: dev is null\n", __FUNCTION__));
+ return -EINVAL;
+ }
+
+ dhd_net_if_lock(dev);
+ if (g_wifi_on || on_failure) {
+#if defined(BCMSDIO) || defined(BCMPCIE)
+ ret = dhd_net_bus_devreset(dev, TRUE);
+#ifdef BCMSDIO
+ dhd_net_bus_suspend(dev);
+#endif /* BCMSDIO */
+#endif /* BCMSDIO || BCMPCIE */
+ dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
+ g_wifi_on = FALSE;
+ }
+ 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(&param, 0, sizeof(param));
+ memset(result, 0, sizeof(result));
+
+ param.buflen = htod32(sizeof(wl_chanim_stats_t));
+ param.count = htod32(WL_CHANIM_COUNT_ONE);
+
+ if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)&param, sizeof(wl_chanim_stats_t),
+ (char*)result, sizeof(result), 0)) < 0) {
+ WL_ERR(("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) {
+ WL_ERR(("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);
+
+ WL_INFORM(("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)
+{
+ wl_cnt_t* 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;
+
+ WL_INFORM(("%s: enter Get Connection Stats\n", __FUNCTION__));
+
+ if (total_len <= 0) {
+ WL_ERR(("%s: invalid buffer size %d\n", __FUNCTION__, total_len));
+ goto error;
+ }
+
+ bufsize = total_len;
+ if (bufsize < sizeof(struct connection_stats)) {
+ WL_ERR(("%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) {
+ WL_ERR(("%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) {
+ WL_ERR(("%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 */
+ if ((cnt = kmalloc(sizeof(*cnt), GFP_KERNEL)) == NULL) {
+ WL_ERR(("%s(%d): kmalloc failed\n", __FUNCTION__, __LINE__));
+ goto error;
+ }
+ memset(cnt, 0, sizeof(*cnt));
+
+ ret = wldev_iovar_getbuf(dev, "counters", NULL, 0,
+ (char *)cnt, sizeof(wl_cnt_t), NULL);
+ if (ret) {
+ WL_ERR(("%s: wldev_iovar_getbuf() failed, ret=%d\n",
+ __FUNCTION__, ret));
+ goto error;
+ }
+
+ if (dtoh16(cnt->version) > WL_CNT_T_VERSION) {
+ WL_ERR(("%s: incorrect version of wl_cnt_t, expected=%u got=%u\n",
+ __FUNCTION__, WL_CNT_T_VERSION, cnt->version));
+ goto error;
+ }
+
+ output->txframe = dtoh32(cnt->txframe);
+ output->txbyte = dtoh32(cnt->txbyte);
+ output->txerror = dtoh32(cnt->txerror);
+ output->rxframe = dtoh32(cnt->rxframe);
+ output->rxbyte = dtoh32(cnt->rxbyte);
+ output->txfail = dtoh32(cnt->txfail);
+ output->txretry = dtoh32(cnt->txretry);
+ output->txretrie = dtoh32(cnt->txretrie);
+ output->txrts = dtoh32(cnt->txrts);
+ output->txnocts = dtoh32(cnt->txnocts);
+ output->txexptime = dtoh32(cnt->txexptime);
+#ifndef DISABLE_IF_COUNTERS
+ } else {
+ /* Populate from if_stats. */
+ if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) {
+ WL_ERR(("%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);
+ /* Unavailable */
+ output->txrts = 0;
+ output->txnocts = 0;
+ output->txexptime = 0;
+ }
+#endif /* DISABLE_IF_COUNTERS */
+
+ /* link_speed is in kbps */
+ ret = wldev_get_link_speed(dev, &link_speed);
+ if (ret || link_speed < 0) {
+ WL_ERR(("%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 */
+ if (cnt) {
+ kfree(cnt);
+ }
+
+ return bytes_written;
+}
+#endif /* CONNECTION_STATISTICS */
+
+
+#ifdef CUSTOMER_HW4_PRIVATE_CMD
+#endif /* CUSTOMER_HW4_PRIVATE_CMD */
+
+/* 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
+#if defined(WL_SUPPORT_AUTO_CHANNEL)
+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;
+ uint32 buf_size;
+
+ if (cmd_str) {
+ WL_INFORM(("Command: %s len:%d \n", cmd_str, (int)strlen(cmd_str)));
+ if (strncmp(cmd_str, APCS_BAND_AUTO, strlen(APCS_BAND_AUTO)) == 0) {
+ band = WLC_BAND_AUTO;
+ } else if (strncmp(cmd_str, APCS_BAND_5G, strlen(APCS_BAND_5G)) == 0) {
+ band = WLC_BAND_5G;
+ } else if (strncmp(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 {
+ WL_ERR(("Invalid argument\n"));
+ return -EINVAL;
+ }
+ }
+ } else {
+ /* If no argument is provided, default to 2G */
+ WL_ERR(("No argument given default to 2.4G scan\n"));
+ band = WLC_BAND_2G;
+ }
+ WL_INFORM(("HAPD_AUTO_CHANNEL = %d, band=%d \n", channel, band));
+
+ if ((ret = wldev_ioctl(dev, WLC_GET_SPECT_MANAGMENT, &spect, sizeof(spect), false)) < 0) {
+ WL_ERR(("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)) {
+ WL_ERR(("ACS: error while setting spect\n"));
+ goto done;
+ }
+ }
+
+ reqbuf = kzalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL);
+ if (reqbuf == NULL) {
+ WL_ERR(("failed to allocate chanspec buffer\n"));
+ return -ENOMEM;
+ }
+
+ if (band == WLC_BAND_AUTO) {
+ WL_INFORM(("ACS full channel scan \n"));
+ reqbuf[0] = htod32(0);
+ } else if (band == WLC_BAND_5G) {
+ WL_INFORM(("ACS 5G band scan \n"));
+ if ((ret = wl_cfg80211_get_chanspecs_5g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) {
+ WL_ERR(("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
+ */
+ WL_INFORM(("ACS 2G band scan \n"));
+ if ((ret = wl_cfg80211_get_chanspecs_2g(dev, reqbuf, CHANSPEC_BUF_SIZE)) < 0) {
+ WL_ERR(("ACS 2g chanspec retreival failed! \n"));
+ goto done;
+ }
+ } else {
+ WL_ERR(("ACS: No band chosen\n"));
+ goto done2;
+ }
+
+ buf_size = (band == WLC_BAND_AUTO) ? sizeof(int) : CHANSPEC_BUF_SIZE;
+ ret = wldev_ioctl(dev, WLC_START_CHANNEL_SEL, (void *)reqbuf,
+ buf_size, true);
+ if (ret < 0) {
+ WL_ERR(("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(dev, WLC_GET_CHANNEL_SEL, &chosen,
+ sizeof(chosen), false);
+ 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_ERR(("selected channel = %d\n", channel));
+ break;
+ }
+ }
+ WL_INFORM(("%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;
+ }
+ WL_ERR(("ACS failed. Fall back to default channel (%d) \n", channel));
+ }
+done2:
+ if (spect > 0) {
+ if ((ret = wl_cfg80211_set_spect(dev, spect) < 0)) {
+ WL_ERR(("ACS: error while setting spect\n"));
+ }
+ }
+
+ if (reqbuf) {
+ kfree(reqbuf);
+ }
+
+ if (channel) {
+ snprintf(command, 4, "%d", channel);
+ WL_INFORM(("command result is %s \n", command));
+ return strlen(command);
+ } else {
+ return ret;
+ }
+}
+#endif /* WL_SUPPORT_AUTO_CHANNEL */
+
+#ifdef SUPPORT_HIDDEN_AP
+static int
+wl_android_set_max_num_sta(struct net_device *dev, const char* string_num)
+{
+ int max_assoc;
+
+ max_assoc = bcm_atoi(string_num);
+ DHD_INFO(("%s : HAPD_MAX_NUM_STA = %d\n", __FUNCTION__, max_assoc));
+ wldev_iovar_setint(dev, "maxassoc", max_assoc);
+ return 1;
+}
+
+static int
+wl_android_set_ssid(struct net_device *dev, const char* hapd_ssid)
+{
+ wlc_ssid_t ssid;
+ s32 ret;
+
+ ssid.SSID_len = strlen(hapd_ssid);
+ if (ssid.SSID_len > DOT11_MAX_SSID_LEN) {
+ ssid.SSID_len = DOT11_MAX_SSID_LEN;
+ DHD_ERROR(("%s : Too long SSID Length %zu\n", __FUNCTION__, strlen(hapd_ssid)));
+ }
+ bcm_strncpy_s(ssid.SSID, sizeof(ssid.SSID), hapd_ssid, ssid.SSID_len);
+ DHD_INFO(("%s: HAPD_SSID = %s\n", __FUNCTION__, ssid.SSID));
+ ret = wldev_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(wlc_ssid_t), true);
+ if (ret < 0) {
+ DHD_ERROR(("%s : WLC_SET_SSID Error:%d\n", __FUNCTION__, ret));
+ }
+ return 1;
+
+}
+
+static int
+wl_android_set_hide_ssid(struct net_device *dev, char *command, int total_len)
+{
+ int hide_ssid;
+ int bytes_written = 0;
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy);
+ struct net_info *_netinfo = wl_get_netinfo_by_netdev(cfg, dev);
+
+ if (*(command + strlen(CMD_SET_HAPD_HIDE_SSID)) == '\0') {
+ bytes_written = snprintf(command, total_len, "%s %d",
+ CMD_SET_HAPD_HIDE_SSID, _netinfo->profile.hidden_ssid);
+ return bytes_written;
+ }
+ command = (command + strlen(CMD_SET_HAPD_HIDE_SSID));
+ command++;
+ hide_ssid = bcm_atoi(command);
+ DHD_INFO(("%s: HAPD_HIDE_SSID = %d\n", __FUNCTION__, hide_ssid));
+ _netinfo->profile.hidden_ssid = hide_ssid;
+ wldev_iovar_setint(dev, "closednet", _netinfo->profile.hidden_ssid);
+ return 0;
+}
+
+#endif /* SUPPORT_HIDDEN_AP */
+
+#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);
+ DHD_INFO(("%s : HAPD_LPC_ENABLED = %d\n", __FUNCTION__, lpc_enabled));
+
+ ret = wldev_ioctl(dev, WLC_DOWN, &val, sizeof(s32), true);
+ if (ret < 0)
+ DHD_ERROR(("WLC_DOWN error %d\n", ret));
+
+ wldev_iovar_setint(dev, "lpc", lpc_enabled);
+
+ ret = wldev_ioctl(dev, WLC_UP, &val, sizeof(s32), true);
+ if (ret < 0)
+ DHD_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(dev, WLC_SET_SRL, &srl, sizeof(s32), true);
+ if (error) {
+ DHD_ERROR(("Failed to set SRL, error = %d\n", error));
+ }
+ error = wldev_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(s32), true);
+ if (error) {
+ DHD_ERROR(("Failed to set LRL, error = %d\n", error));
+ }
+ return error;
+}
+
+
+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;
+ DHD_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) {
+ DHD_INFO(("%s: Set auto leader selection mode\n", __FUNCTION__));
+ memset(&rmc_entry, 0, sizeof(wl_rmc_entry_t));
+ } else {
+ DHD_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) {
+ DHD_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) {
+ WL_ERR(("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);
+
+ WL_DBG(("RMC pid=%d\n", pid));
+
+ return err;
+}
+
+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) {
+ DHD_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) {
+ DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
+ return -1;
+ }
+
+ error = wldev_iovar_setint(dev, "scan_ps", mode);
+ if (error) {
+ DHD_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) {
+ DHD_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)) {
+ DHD_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)) {
+ DHD_ERROR(("%s: error (%d)\n", __FUNCTION__, err));
+ return err;
+ }
+
+ bytes_written = snprintf(command, total_len, "%s %d",
+ CMD_TEST_GET_TX_POWER, dbm);
+
+ DHD_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);
+
+ /* As Samsung specific and their requirement, '0' means activate sarlimit
+ * and '-1' means back to normal state (deactivate sarlimit)
+ */
+ if (mode == 0) {
+ DHD_INFO(("%s: SAR limit control activated\n", __FUNCTION__));
+ setval = 1;
+ } else if (mode == -1) {
+ DHD_INFO(("%s: SAR limit control deactivated\n", __FUNCTION__));
+ setval = 0;
+ } else {
+ return -EINVAL;
+ }
+
+ err = wldev_iovar_setint(dev, "sar_enable", setval);
+ if (unlikely(err)) {
+ DHD_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) {
+ DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
+ return -1;
+ }
+
+ error = wldev_iovar_setint(dev, "roam_off", mode);
+ if (error) {
+ DHD_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n",
+ __FUNCTION__, mode, error));
+ return -1;
+ }
+ else
+ DHD_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n",
+ __FUNCTION__, mode, error));
+ return 0;
+}
+
+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;
+
+ /* 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;
+ }
+
+ pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1;
+ for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
+ 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++;
+ }
+ tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1);
+ vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags);
+ if (!vndr_ie) {
+ WL_ERR(("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) {
+ WL_ERR(("ioctl memory alloc failed\n"));
+ if (vndr_ie) {
+ kfree(vndr_ie);
+ }
+ return -ENOMEM;
+ }
+ memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */
+ err = wldev_iovar_setbuf(dev, "ie", vndr_ie, tot_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
+
+
+ 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;
+}
+
+#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) {
+ DHD_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 {
+ DHD_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) {
+ DHD_ERROR(("Failed to set join_pref, error = %d\n", error));
+ }
+ return error;
+}
+#endif /* defined(BCMFW_ROAM_ENABLE */
+
+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) {
+ DHD_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) {
+ DHD_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(dev, config->ioctl, resume_cfg->arg, config->len, false);
+ if (ret) {
+ DHD_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__,
+ config->ioctl));
+ goto error;
+ }
+ ret = wldev_ioctl(dev, config->ioctl + 1, config->arg, config->len, true);
+ if (ret) {
+ DHD_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;
+
+ list_for_each_safe(cur, q, head) {
+ config = list_entry(cur, struct io_cfg, list);
+ if (config->iovar) {
+ if (!ret)
+ ret = wldev_iovar_setint(dev, config->iovar,
+ config->param);
+ } else {
+ if (!ret)
+ ret = wldev_ioctl(dev, config->ioctl + 1,
+ config->arg, config->len, true);
+ 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;
+
+ DHD_INFO(("set ulb mode (%s) \n", command));
+ if (sscanf(command, "%*s %d", &mode) != 1) {
+ DHD_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;
+ DHD_INFO(("set ulb bw (%s) \n", command));
+
+ /*
+ * For sta/ap: IFNAME=<ifname> DRIVER ULB_BW <bw> ifname
+ * For p2p: IFNAME=wlan0 DRIVER ULB_BW <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;
+ }
+
+ DHD_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) {
+ DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
+ return -1;
+ }
+
+ DHD_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(dev, WLC_GET_BCNPRD, &val, sizeof(int), false);
+ if (!ret && val > 100) {
+ config.param = 0;
+ DHD_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(dev, WLC_GET_PM, &val, sizeof(val), false);
+ 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:
+ DHD_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret));
+ wl_android_iolist_resume(dev, &miracast_resume_list);
+ return ret;
+}
+
+#define NETLINK_OXYGEN 30
+#define AIBSS_BEACON_TIMEOUT 10
+
+static struct sock *nl_sk = NULL;
+
+static void wl_netlink_recv(struct sk_buff *skb)
+{
+ WL_ERR(("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) {
+ WL_ERR(("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) {
+ WL_ERR(("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, void *data, size_t size)
+{
+ struct sk_buff *skb = NULL;
+ struct nlmsghdr *nlh = NULL;
+ int ret = -1;
+
+ if (nl_sk == NULL) {
+ WL_ERR(("nl_sk was not initialized\n"));
+ goto nlmsg_failure;
+ }
+
+ skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC);
+ if (skb == NULL) {
+ WL_ERR(("failed to allocate memory\n"));
+ goto nlmsg_failure;
+ }
+
+ nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
+ if (nlh == NULL) {
+ WL_ERR(("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);
+ WL_DBG(("netlink_unicast() pid=%d, ret=%d\n", pid, ret));
+
+nlmsg_failure:
+ return ret;
+}
+
+
+int wl_keep_alive_set(struct net_device *dev, char* extra, int total_len)
+{
+ char buf[256];
+ const char *str;
+ wl_mkeep_alive_pkt_t mkeep_alive_pkt;
+ wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
+ int buf_len;
+ int str_len;
+ int res = -1;
+ uint period_msec = 0;
+
+ if (extra == NULL)
+ {
+ DHD_ERROR(("%s: extra is NULL\n", __FUNCTION__));
+ return -1;
+ }
+ if (sscanf(extra, "%d", &period_msec) != 1)
+ {
+ DHD_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__));
+ return -EINVAL;
+ }
+ DHD_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec));
+
+ memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t));
+
+ str = "mkeep_alive";
+ str_len = strlen(str);
+ strncpy(buf, str, str_len);
+ buf[ str_len ] = '\0';
+ mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1);
+ mkeep_alive_pkt.period_msec = 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);
+
+ /* 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;
+ /* 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);
+
+ if ((res = wldev_ioctl(dev, WLC_SET_VAR, buf, buf_len, TRUE)) < 0)
+ {
+ DHD_ERROR(("%s:keep_alive set failed. res[%d]\n", __FUNCTION__, res));
+ }
+ else
+ {
+ DHD_ERROR(("%s:keep_alive set ok. res[%d]\n", __FUNCTION__, res));
+ }
+
+ return res;
+}
+
+static const char *
+get_string_by_separator(char *result, int result_len, const char *src, char separator)
+{
+ char *end = result + result_len - 1;
+ while ((result != end) && (*src != separator) && (*src)) {
+ *result++ = *src++;
+ }
+ *result = 0;
+ if (*src == separator) {
+ ++src;
+ }
+ return src;
+}
+
+int
+wl_android_set_roam_offload_bssid_list(struct net_device *dev, const char *cmd)
+{
+ char sbuf[32];
+ int i, cnt, size, err, ioctl_buf_len;
+ roamoffl_bssid_list_t *bssid_list;
+ const char *str = cmd;
+ char *ioctl_buf;
+ dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(dev);
+
+ str = get_string_by_separator(sbuf, 32, str, ',');
+ cnt = bcm_atoi(sbuf);
+ cnt = MIN(cnt, MAX_ROAMOFFL_BSSID_NUM);
+
+ if ((cnt > 0) &&
+ (((dhdp->op_mode & DHD_FLAG_STA_MODE) && (dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) ||
+ FALSE)) {
+ WL_ERR(("Can't set ROAMOFFL_BSSID when enabled STA-SoftAP or WES\n"));
+ return -EINVAL;
+ }
+
+ size = sizeof(int32) + sizeof(struct ether_addr) * cnt;
+ WL_ERR(("ROAM OFFLOAD BSSID LIST %d BSSIDs, size %d\n", cnt, size));
+ bssid_list = kmalloc(size, GFP_KERNEL);
+ if (bssid_list == NULL) {
+ WL_ERR(("%s: memory alloc for bssid list(%d) failed\n",
+ __FUNCTION__, size));
+ return -ENOMEM;
+ }
+ ioctl_buf_len = size + 64;
+ ioctl_buf = kmalloc(ioctl_buf_len, GFP_KERNEL);
+ if (ioctl_buf == NULL) {
+ WL_ERR(("%s: memory alloc for ioctl_buf(%d) failed\n",
+ __FUNCTION__, ioctl_buf_len));
+ kfree(bssid_list);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ str = get_string_by_separator(sbuf, 32, str, ',');
+ bcm_ether_atoe(sbuf, &bssid_list->bssid[i]);
+ }
+
+ bssid_list->cnt = (int32)cnt;
+ err = wldev_iovar_setbuf(dev, "roamoffl_bssid_list",
+ bssid_list, size, ioctl_buf, ioctl_buf_len, NULL);
+ kfree(bssid_list);
+ kfree(ioctl_buf);
+
+ return err;
+}
+
+#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) {
+ DHD_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) {
+ DHD_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) {
+ WL_ERR(("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(dev);
+ if (enable) {
+ DHD_TRACE(("%s : set ack suppress. TCPACK_SUP_HOLD.\n", __FUNCTION__));
+ dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_HOLD);
+ } else {
+ DHD_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 */
+#ifdef P2P_LISTEN_OFFLOADING
+s32
+wl_cfg80211_p2plo_offload(struct net_device *dev, char *cmd, char* buf, int len)
+{
+ int ret = 0;
+
+ WL_ERR(("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 {
+ WL_ERR(("Request for Unsupported CMD:%s \n", buf));
+ ret = -EINVAL;
+ }
+ return ret;
+}
+#endif /* P2P_LISTEN_OFFLOADING */
+
+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) {
+ WL_ERR(("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)) {
+ WL_ERR(("Failed to set murx_bfe_cap IOVAR to %d,"
+ "error %d\n", val, err));
+ return err;
+ }
+
+ /* If successful intiate a reassoc */
+ if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false)) < 0) {
+ WL_ERR(("Failed to get bssid, error=%d\n", err));
+ return err;
+ }
+
+ bzero(&params, sizeof(wl_reassoc_params_t));
+ memcpy(&params.bssid, &bssid, ETHER_ADDR_LEN);
+
+ if ((err = wldev_ioctl(dev, WLC_REASSOC, &params,
+ sizeof(wl_reassoc_params_t), true)) < 0) {
+ WL_ERR(("reassoc failed err:%d \n", err));
+ } else {
+ WL_DBG(("reassoc issued successfully\n"));
+ }
+
+ return err;
+}
+
+int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
+{
+#define PRIVATE_COMMAND_MAX_LEN 8192
+#define PRIVATE_COMMAND_DEF_LEN 4096
+ int ret = 0;
+ char *command = NULL;
+ int bytes_written = 0;
+ int buf_size = 0;
+ android_wifi_priv_cmd priv_cmd;
+
+ net_os_wake_lock(net);
+
+ if (!capable(CAP_NET_ADMIN)) {
+ ret = -EPERM;
+ goto exit;
+ }
+
+ if (!ifr->ifr_data) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+#ifdef CONFIG_COMPAT
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)) || ((LINUX_VERSION_CODE >= \
+ KERNEL_VERSION(4, 6, 0)) && !defined(__X86)))
+ if (is_compat_task()) {
+ compat_android_wifi_priv_cmd compat_priv_cmd;
+ if (copy_from_user(&compat_priv_cmd, ifr->ifr_data,
+ sizeof(compat_android_wifi_priv_cmd))) {
+ ret = -EFAULT;
+ goto exit;
+
+ }
+ priv_cmd.buf = compat_ptr(compat_priv_cmd.buf);
+ priv_cmd.used_len = compat_priv_cmd.used_len;
+ priv_cmd.total_len = compat_priv_cmd.total_len;
+ } else
+#endif /* LINUX_VER < 4.6 || (LINUX_VER >= 4.6 && !defined(__X86)) */
+#endif /* CONFIG_COMPAT */
+ {
+ if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
+ ret = -EFAULT;
+ goto exit;
+ }
+ }
+ if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) {
+ DHD_ERROR(("%s: buf length invalid:%d\n", __FUNCTION__, priv_cmd.total_len));
+ ret = -EINVAL;
+ goto exit;
+ }
+ buf_size = max(priv_cmd.total_len, PRIVATE_COMMAND_DEF_LEN);
+ command = kmalloc((buf_size + 1), GFP_KERNEL);
+ if (!command)
+ {
+ DHD_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
+ ret = -ENOMEM;
+ goto exit;
+ }
+ if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
+ ret = -EFAULT;
+ goto exit;
+ }
+ command[priv_cmd.total_len] = '\0';
+
+ DHD_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name));
+
+ if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
+ DHD_INFO(("%s, Received regular START command\n", __FUNCTION__));
+ bytes_written = wl_android_wifi_on(net);
+ }
+ else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
+ bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
+ }
+
+ if (!g_wifi_on) {
+ DHD_ERROR(("%s: Ignore private cmd \"%s\" - iface %s is down\n",
+ __FUNCTION__, command, ifr->ifr_name));
+ ret = 0;
+ goto exit;
+ }
+
+ if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
+ bytes_written = wl_android_wifi_off(net, FALSE);
+ }
+ else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
+ wl_cfg80211_set_passive_scan(net, command);
+ }
+ else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
+ wl_cfg80211_set_passive_scan(net, command);
+ }
+ else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
+ bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
+ bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
+ }
+#ifdef PKT_FILTER_SUPPORT
+ else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
+ bytes_written = net_os_enable_packet_filter(net, 1);
+ }
+ else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
+ bytes_written = net_os_enable_packet_filter(net, 0);
+ }
+ else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
+ int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
+ bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
+ }
+ else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
+ int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
+ bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
+ }
+#endif /* PKT_FILTER_SUPPORT */
+ else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
+ /* TBD: BTCOEXSCAN-START */
+ }
+ else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
+ /* TBD: BTCOEXSCAN-STOP */
+ }
+ else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
+#ifdef WL_CFG80211
+ void *dhdp = wl_cfg80211_get_dhdp(net);
+ bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command);
+#else
+#ifdef PKT_FILTER_SUPPORT
+ uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
+
+ if (mode == 1)
+ net_os_enable_packet_filter(net, 0); /* DHCP starts */
+ else
+ net_os_enable_packet_filter(net, 1); /* DHCP ends */
+#endif /* PKT_FILTER_SUPPORT */
+#endif /* WL_CFG80211 */
+ }
+ else if (strnicmp(command, CMD_ADDIE, strlen(CMD_ADDIE)) == 0) {
+ bytes_written = wl_android_add_vendor_ie(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_DELIE, strlen(CMD_DELIE)) == 0) {
+ bytes_written = wl_android_del_vendor_ie(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
+ bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
+ bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_MAXDTIM_IN_SUSPEND, strlen(CMD_MAXDTIM_IN_SUSPEND)) == 0) {
+ bytes_written = wl_android_set_max_dtim(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
+ uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
+ bytes_written = wldev_set_band(net, band);
+ }
+ else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
+ bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
+ }
+#ifdef WL_CFG80211
+ /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
+ else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
+ /*
+ * Usage examples:
+ * DRIVER COUNTRY US
+ * DRIVER COUNTRY US/7
+ */
+ char *country_code = command + strlen(CMD_COUNTRY) + 1;
+ char *rev_info_delim = country_code + 2; /* 2 bytes of country code */
+ int revinfo = -1;
+ if ((rev_info_delim) &&
+ (strnicmp(rev_info_delim, CMD_COUNTRY_DELIMITER,
+ strlen(CMD_COUNTRY_DELIMITER)) == 0) &&
+ (rev_info_delim + 1)) {
+ revinfo = bcm_atoi(rev_info_delim + 1);
+ }
+ bytes_written = wldev_set_country(net, country_code, true, true, revinfo);
+#ifdef FCC_PWR_LIMIT_2G
+ if (wldev_iovar_setint(net, "fccpwrlimit2g", FALSE)) {
+ DHD_ERROR(("%s: fccpwrlimit2g deactivation is failed\n", __FUNCTION__));
+ } else {
+ DHD_ERROR(("%s: fccpwrlimit2g is deactivated\n", __FUNCTION__));
+ }
+#endif /* FCC_PWR_LIMIT_2G */
+ }
+#endif /* WL_CFG80211 */
+ else if (strnicmp(command, CMD_SET_CSA, strlen(CMD_SET_CSA)) == 0) {
+ bytes_written = wl_android_set_csa(net, command, priv_cmd.total_len);
+ } else if (strnicmp(command, CMD_80211_MODE, strlen(CMD_80211_MODE)) == 0) {
+ bytes_written = wl_android_get_80211_mode(net, command, priv_cmd.total_len);
+ } else if (strnicmp(command, CMD_CHANSPEC, strlen(CMD_CHANSPEC)) == 0) {
+ bytes_written = wl_android_get_chanspec(net, command, priv_cmd.total_len);
+ } else if (strnicmp(command, CMD_DATARATE, strlen(CMD_DATARATE)) == 0) {
+ bytes_written = wl_android_get_datarate(net, command, priv_cmd.total_len);
+ } else if (strnicmp(command, CMD_ASSOC_CLIENTS, strlen(CMD_ASSOC_CLIENTS)) == 0) {
+ bytes_written = wl_android_get_assoclist(net, command, priv_cmd.total_len);
+ }
+
+#ifdef CUSTOMER_HW4_PRIVATE_CMD
+#ifdef WLTDLS
+ else if (strnicmp(command, CMD_TDLS_RESET, strlen(CMD_TDLS_RESET)) == 0) {
+ bytes_written = wl_android_tdls_reset(net);
+ }
+#endif /* WLTDLS */
+#endif /* CUSTOMER_HW4_PRIVATE_CMD */
+
+#ifdef PNO_SUPPORT
+ else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
+ bytes_written = dhd_dev_pno_stop_for_ssid(net);
+ }
+#ifndef WL_SCHED_SCAN
+ else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
+ bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
+ }
+#endif /* !WL_SCHED_SCAN */
+ else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
+ int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
+ bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net);
+ }
+ else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) {
+ bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len);
+ }
+#endif /* PNO_SUPPORT */
+ else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
+ bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
+ int skip = strlen(CMD_P2P_SET_NOA) + 1;
+ bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
+ priv_cmd.total_len - skip);
+ }
+#ifdef P2P_LISTEN_OFFLOADING
+ else if (strnicmp(command, CMD_P2P_LISTEN_OFFLOAD, strlen(CMD_P2P_LISTEN_OFFLOAD)) == 0) {
+ u8 *sub_command = strchr(command, ' ');
+ bytes_written = wl_cfg80211_p2plo_offload(net, command, sub_command,
+ sub_command ? strlen(sub_command) : 0);
+ }
+#endif /* P2P_LISTEN_OFFLOADING */
+#ifdef WL_NAN
+ else if (strnicmp(command, CMD_NAN, strlen(CMD_NAN)) == 0) {
+ bytes_written = wl_cfg80211_nan_cmd_handler(net, command,
+ priv_cmd.total_len);
+ }
+#endif /* WL_NAN */
+#if !defined WL_ENABLE_P2P_IF
+ else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
+ bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
+ }
+#endif /* WL_ENABLE_P2P_IF */
+ else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
+ int skip = strlen(CMD_P2P_SET_PS) + 1;
+ bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
+ priv_cmd.total_len - skip);
+ }
+ else if (strnicmp(command, CMD_P2P_ECSA, strlen(CMD_P2P_ECSA)) == 0) {
+ int skip = strlen(CMD_P2P_ECSA) + 1;
+ bytes_written = wl_cfg80211_set_p2p_ecsa(net, command + skip,
+ priv_cmd.total_len - skip);
+ }
+ else if (strnicmp(command, CMD_P2P_INC_BW, strlen(CMD_P2P_INC_BW)) == 0) {
+ int skip = strlen(CMD_P2P_INC_BW) + 1;
+ bytes_written = wl_cfg80211_increase_p2p_bw(net,
+ command + skip, priv_cmd.total_len - skip);
+ }
+#ifdef WL_CFG80211
+ else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
+ strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
+ int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
+ bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
+ priv_cmd.total_len - skip, *(command + skip - 2) - '0');
+ }
+#endif /* WL_CFG80211 */
+#if defined(WL_SUPPORT_AUTO_CHANNEL)
+ else if (strnicmp(command, CMD_GET_BEST_CHANNELS,
+ strlen(CMD_GET_BEST_CHANNELS)) == 0) {
+ bytes_written = wl_cfg80211_get_best_channels(net, command,
+ priv_cmd.total_len);
+ }
+#endif /* WL_SUPPORT_AUTO_CHANNEL */
+#if defined(WL_SUPPORT_AUTO_CHANNEL)
+ else if (strnicmp(command, CMD_SET_HAPD_AUTO_CHANNEL,
+ strlen(CMD_SET_HAPD_AUTO_CHANNEL)) == 0) {
+ int skip = strlen(CMD_SET_HAPD_AUTO_CHANNEL) + 1;
+ bytes_written = wl_android_set_auto_channel(net, (const char*)command+skip, command,
+ priv_cmd.total_len);
+ }
+#endif /* WL_SUPPORT_AUTO_CHANNEL */
+#ifdef CUSTOMER_HW4_PRIVATE_CMD
+#endif /* CUSTOMER_HW4_PRIVATE_CMD */
+#if defined(SUPPORT_HIDDEN_AP)
+ else if (strnicmp(command, CMD_SET_HAPD_MAX_NUM_STA,
+ strlen(CMD_SET_HAPD_MAX_NUM_STA)) == 0) {
+ int skip = strlen(CMD_SET_HAPD_MAX_NUM_STA) + 3;
+ wl_android_set_max_num_sta(net, (const char*)command+skip);
+ }
+ else if (strnicmp(command, CMD_SET_HAPD_SSID,
+ strlen(CMD_SET_HAPD_SSID)) == 0) {
+ int skip = strlen(CMD_SET_HAPD_SSID) + 3;
+ wl_android_set_ssid(net, (const char*)command+skip);
+ }
+ else if (strnicmp(command, CMD_SET_HAPD_HIDE_SSID,
+ strlen(CMD_SET_HAPD_HIDE_SSID)) == 0) {
+ bytes_written = wl_android_set_hide_ssid(net, command, priv_cmd.total_len);
+ }
+#endif /* SUPPORT_HIDDEN_AP */
+#ifdef CUSTOMER_HW4_PRIVATE_CMD
+#ifdef SUPPORT_SET_LPC
+ else if (strnicmp(command, CMD_HAPD_LPC_ENABLED,
+ strlen(CMD_HAPD_LPC_ENABLED)) == 0) {
+ int skip = strlen(CMD_HAPD_LPC_ENABLED) + 3;
+ wl_android_set_lpc(net, (const char*)command+skip);
+ }
+#endif /* SUPPORT_SET_LPC */
+#ifdef SUPPORT_TRIGGER_HANG_EVENT
+ else if (strnicmp(command, CMD_TEST_FORCE_HANG,
+ strlen(CMD_TEST_FORCE_HANG)) == 0) {
+ int skip = strlen(CMD_TEST_FORCE_HANG) + 1;
+ net_os_send_hang_message_reason(net, (const char*)command+skip);
+ }
+#endif /* SUPPORT_TRIGGER_HANG_EVENT */
+ else if (strnicmp(command, CMD_CHANGE_RL, strlen(CMD_CHANGE_RL)) == 0)
+ bytes_written = wl_android_ch_res_rl(net, true);
+ else if (strnicmp(command, CMD_RESTORE_RL, strlen(CMD_RESTORE_RL)) == 0)
+ bytes_written = wl_android_ch_res_rl(net, false);
+ else if (strnicmp(command, CMD_SET_RMC_ENABLE, strlen(CMD_SET_RMC_ENABLE)) == 0) {
+ int rmc_enable = *(command + strlen(CMD_SET_RMC_ENABLE) + 1) - '0';
+ bytes_written = wl_android_rmc_enable(net, rmc_enable);
+ }
+ else if (strnicmp(command, CMD_SET_RMC_TXRATE, strlen(CMD_SET_RMC_TXRATE)) == 0) {
+ int rmc_txrate;
+ sscanf(command, "%*s %10d", &rmc_txrate);
+ bytes_written = wldev_iovar_setint(net, "rmc_txrate", rmc_txrate * 2);
+ }
+ else if (strnicmp(command, CMD_SET_RMC_ACTPERIOD, strlen(CMD_SET_RMC_ACTPERIOD)) == 0) {
+ int actperiod;
+ sscanf(command, "%*s %10d", &actperiod);
+ bytes_written = wldev_iovar_setint(net, "rmc_actf_time", actperiod);
+ }
+ else if (strnicmp(command, CMD_SET_RMC_IDLEPERIOD, strlen(CMD_SET_RMC_IDLEPERIOD)) == 0) {
+ int acktimeout;
+ sscanf(command, "%*s %10d", &acktimeout);
+ acktimeout *= 1000;
+ bytes_written = wldev_iovar_setint(net, "rmc_acktmo", acktimeout);
+ }
+ else if (strnicmp(command, CMD_SET_RMC_LEADER, strlen(CMD_SET_RMC_LEADER)) == 0) {
+ int skip = strlen(CMD_SET_RMC_LEADER) + 1;
+ bytes_written = wl_android_rmc_set_leader(net, (const char*)command+skip);
+ }
+ else if (strnicmp(command, CMD_SET_RMC_EVENT,
+ strlen(CMD_SET_RMC_EVENT)) == 0)
+ bytes_written = wl_android_set_rmc_event(net, command, priv_cmd.total_len);
+ else if (strnicmp(command, CMD_GET_SCSCAN, strlen(CMD_GET_SCSCAN)) == 0) {
+ bytes_written = wl_android_get_singlecore_scan(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_SET_SCSCAN, strlen(CMD_SET_SCSCAN)) == 0) {
+ bytes_written = wl_android_set_singlecore_scan(net, command, priv_cmd.total_len);
+ }
+#ifdef TEST_TX_POWER_CONTROL
+ else if (strnicmp(command, CMD_TEST_SET_TX_POWER,
+ strlen(CMD_TEST_SET_TX_POWER)) == 0) {
+ int skip = strlen(CMD_TEST_SET_TX_POWER) + 1;
+ wl_android_set_tx_power(net, (const char*)command+skip);
+ }
+ else if (strnicmp(command, CMD_TEST_GET_TX_POWER,
+ strlen(CMD_TEST_GET_TX_POWER)) == 0) {
+ wl_android_get_tx_power(net, command, priv_cmd.total_len);
+ }
+#endif /* TEST_TX_POWER_CONTROL */
+ else if (strnicmp(command, CMD_SARLIMIT_TX_CONTROL,
+ strlen(CMD_SARLIMIT_TX_CONTROL)) == 0) {
+ int skip = strlen(CMD_SARLIMIT_TX_CONTROL) + 1;
+ wl_android_set_sarlimit_txctrl(net, (const char*)command+skip);
+ }
+#ifdef IPV6_NDO_SUPPORT
+ else if (strnicmp(command, CMD_NDRA_LIMIT, strlen(CMD_NDRA_LIMIT)) == 0) {
+ bytes_written = wl_android_nd_ra_limit(net, command, priv_cmd.total_len);
+ }
+#endif /* IPV6_NDO_SUPPORT */
+#endif /* CUSTOMER_HW4_PRIVATE_CMD */
+ else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) {
+ int skip = strlen(CMD_HAPD_MAC_FILTER) + 1;
+ wl_android_set_mac_address_filter(net, (const char*)command+skip);
+ }
+ else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0)
+ bytes_written = wl_android_set_roam_mode(net, command, priv_cmd.total_len);
+#if defined(BCMFW_ROAM_ENABLE)
+ else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) {
+ bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len);
+ }
+#endif /* BCMFW_ROAM_ENABLE */
+ else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0)
+ bytes_written = wl_android_set_miracast(net, command, priv_cmd.total_len);
+#ifdef WL11ULB
+ else if (strnicmp(command, CMD_ULB_MODE, strlen(CMD_ULB_MODE)) == 0)
+ bytes_written = wl_android_set_ulb_mode(net, command, priv_cmd.total_len);
+ else if (strnicmp(command, CMD_ULB_BW, strlen(CMD_ULB_BW)) == 0)
+ bytes_written = wl_android_set_ulb_bw(net, command, priv_cmd.total_len);
+#endif /* WL11ULB */
+ else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0)
+ bytes_written = wl_android_set_ibss_beacon_ouidata(net,
+ command, priv_cmd.total_len);
+ else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
+ int skip = strlen(CMD_KEEP_ALIVE) + 1;
+ bytes_written = wl_keep_alive_set(net, command + skip, priv_cmd.total_len - skip);
+ }
+ else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) {
+ int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
+ bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
+ }
+ else if (strnicmp(command, CMD_ROAM_OFFLOAD_APLIST, strlen(CMD_ROAM_OFFLOAD_APLIST)) == 0) {
+ bytes_written = wl_android_set_roam_offload_bssid_list(net,
+ command + strlen(CMD_ROAM_OFFLOAD_APLIST) + 1);
+ }
+#if defined(WL_VIRTUAL_APSTA)
+ else if (strnicmp(command, CMD_INTERFACE_CREATE, strlen(CMD_INTERFACE_CREATE)) == 0) {
+ char *name = (command + strlen(CMD_INTERFACE_CREATE) +1);
+ WL_INFORM(("Creating %s interface\n", name));
+ bytes_written = wl_cfg80211_interface_create(net, name);
+ }
+ else if (strnicmp(command, CMD_INTERFACE_DELETE, strlen(CMD_INTERFACE_DELETE)) == 0) {
+ char *name = (command + strlen(CMD_INTERFACE_DELETE) +1);
+ WL_INFORM(("Deleteing %s interface\n", name));
+ bytes_written = wl_cfg80211_interface_delete(net, name);
+ }
+#endif /* defined (WL_VIRTUAL_APSTA) */
+#ifdef P2PRESP_WFDIE_SRC
+ else if (strnicmp(command, CMD_P2P_SET_WFDIE_RESP,
+ strlen(CMD_P2P_SET_WFDIE_RESP)) == 0) {
+ int mode = *(command + strlen(CMD_P2P_SET_WFDIE_RESP) + 1) - '0';
+ bytes_written = wl_android_set_wfdie_resp(net, mode);
+ } else if (strnicmp(command, CMD_P2P_GET_WFDIE_RESP,
+ strlen(CMD_P2P_GET_WFDIE_RESP)) == 0) {
+ bytes_written = wl_android_get_wfdie_resp(net, command, priv_cmd.total_len);
+ }
+#endif /* P2PRESP_WFDIE_SRC */
+ else if (strnicmp(command, CMD_DFS_AP_MOVE, strlen(CMD_DFS_AP_MOVE)) == 0) {
+ char *data = (command + strlen(CMD_DFS_AP_MOVE) +1);
+ bytes_written = wl_cfg80211_dfs_ap_move(net, data, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_WBTEXT_ENABLE, strlen(CMD_WBTEXT_ENABLE)) == 0) {
+ bytes_written = wl_android_wbtext(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_WBTEXT_PROFILE_CONFIG,
+ strlen(CMD_WBTEXT_PROFILE_CONFIG)) == 0) {
+ char *data = (command + strlen(CMD_WBTEXT_PROFILE_CONFIG) + 1);
+ bytes_written = wl_cfg80211_wbtext_config(net, data, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_WBTEXT_WEIGHT_CONFIG,
+ strlen(CMD_WBTEXT_WEIGHT_CONFIG)) == 0) {
+ char *data = (command + strlen(CMD_WBTEXT_WEIGHT_CONFIG) + 1);
+ bytes_written = wl_cfg80211_wbtext_weight_config(net, data,
+ command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_WBTEXT_TABLE_CONFIG,
+ strlen(CMD_WBTEXT_TABLE_CONFIG)) == 0) {
+ char *data = (command + strlen(CMD_WBTEXT_TABLE_CONFIG) + 1);
+ bytes_written = wl_cfg80211_wbtext_table_config(net, data,
+ command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_WBTEXT_DELTA_CONFIG,
+ strlen(CMD_WBTEXT_DELTA_CONFIG)) == 0) {
+ char *data = (command + strlen(CMD_WBTEXT_DELTA_CONFIG) + 1);
+ bytes_written = wl_cfg80211_wbtext_delta_config(net, data,
+ command, priv_cmd.total_len);
+ }
+#ifdef SET_RPS_CPUS
+ else if (strnicmp(command, CMD_RPSMODE, strlen(CMD_RPSMODE)) == 0) {
+ bytes_written = wl_android_set_rps_cpus(net, command, priv_cmd.total_len);
+ }
+#endif /* SET_RPS_CPUS */
+#ifdef WLWFDS
+ else if (strnicmp(command, CMD_ADD_WFDS_HASH, strlen(CMD_ADD_WFDS_HASH)) == 0) {
+ bytes_written = wl_android_set_wfds_hash(net, command, priv_cmd.total_len, 1);
+ }
+ else if (strnicmp(command, CMD_DEL_WFDS_HASH, strlen(CMD_DEL_WFDS_HASH)) == 0) {
+ bytes_written = wl_android_set_wfds_hash(net, command, priv_cmd.total_len, 0);
+ }
+#endif /* WLWFDS */
+#ifdef BT_WIFI_HANDOVER
+ else if (strnicmp(command, CMD_TBOW_TEARDOWN, strlen(CMD_TBOW_TEARDOWN)) == 0) {
+ ret = wl_tbow_teardown(net, command, priv_cmd.total_len);
+ }
+#endif /* BT_WIFI_HANDOVER */
+#ifdef FCC_PWR_LIMIT_2G
+ else if (strnicmp(command, CMD_GET_FCC_PWR_LIMIT_2G,
+ strlen(CMD_GET_FCC_PWR_LIMIT_2G)) == 0) {
+ bytes_written = wl_android_get_fcc_pwr_limit_2g(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_SET_FCC_PWR_LIMIT_2G,
+ strlen(CMD_SET_FCC_PWR_LIMIT_2G)) == 0) {
+ bytes_written = wl_android_set_fcc_pwr_limit_2g(net, command, priv_cmd.total_len);
+ }
+#endif /* FCC_PWR_LIMIT_2G */
+ else if (strnicmp(command, CMD_MURX_BFE_CAP,
+ strlen(CMD_MURX_BFE_CAP)) == 0) {
+ uint val = *(command + strlen(CMD_MURX_BFE_CAP) + 1) - '0';
+ bytes_written = wl_android_murx_bfe_cap(net, val);
+ }
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
+ else if (strnicmp(command, CMD_GET_BSS_INFO, strlen(CMD_GET_BSS_INFO)) == 0) {
+ bytes_written = wl_cfg80211_get_bss_info(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_GET_ASSOC_REJECT_INFO, strlen(CMD_GET_ASSOC_REJECT_INFO))
+ == 0) {
+ bytes_written = wl_cfg80211_get_connect_failed_status(net, command,
+ priv_cmd.total_len);
+ }
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
+#if defined(SUPPORT_RANDOM_MAC_SCAN)
+ else if (strnicmp(command, ENABLE_RANDOM_MAC, strlen(ENABLE_RANDOM_MAC)) == 0) {
+ bytes_written = wl_cfg80211_set_random_mac(net, TRUE);
+ } else if (strnicmp(command, DISABLE_RANDOM_MAC, strlen(DISABLE_RANDOM_MAC)) == 0) {
+ bytes_written = wl_cfg80211_set_random_mac(net, FALSE);
+ }
+#endif /* SUPPORT_RANDOM_MAC_SCAN */
+#ifdef DHD_LOG_DUMP
+ else if (strnicmp(command, CMD_NEW_DEBUG_PRINT_DUMP,
+ strlen(CMD_NEW_DEBUG_PRINT_DUMP)) == 0) {
+ dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(net);
+#ifdef DHD_TRACE_WAKE_LOCK
+ dhd_wk_lock_stats_dump(dhdp);
+#endif /* DHD_TRACE_WAKE_LOCK */
+ dhd_schedule_log_dump(dhdp);
+#if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
+ dhdp->memdump_type = DUMP_TYPE_BY_SYSDUMP;
+ dhd_bus_mem_dump(dhdp);
+#endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
+ }
+#endif /* DHD_LOG_DUMP */
+#ifdef DHD_BANDSTEER
+ else if (strnicmp(command, CMD_BANDSTEER_ENABLE, strlen(CMD_BANDSTEER_ENABLE)) == 0) {
+ uint enable = *(command + strlen(CMD_BANDSTEER_ENABLE) + 1) - '0';
+ if (enable < 0 || enable > 1) {
+ ret = BCME_UNSUPPORTED;
+ goto exit;
+ }
+ if (enable) {
+ bytes_written = dhd_bandsteer_module_init(net);
+ }
+ else {
+ bytes_written = dhd_bandsteer_module_deinit(net);
+ }
+ } else if (strnicmp(command, CMD_BANDSTEER_TRIGGER, strlen(CMD_BANDSTEER_TRIGGER)) == 0) {
+ uint8 *p = command + strlen(CMD_BANDSTEER_TRIGGER)+1;
+ struct ether_addr ea;
+ char eabuf[ETHER_ADDR_STR_LEN];
+ bytes_written = 0;
+ ret = BCME_OK;
+
+ bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
+ strncpy(eabuf, p, ETHER_ADDR_STR_LEN - 1);
+
+ if (!(ret = bcm_ether_atoe(eabuf, &ea))) {
+ DHD_ERROR(("BANDSTEER: ERROR while parsing macaddr cmd %s - ignored\n",
+ command));
+ goto exit;
+ }
+ dhd_bandsteer_trigger_bandsteer(net, ea.octet);
+ }
+#endif /* DHD_BANDSTEER */
+ else if (strnicmp(command, CMD_AP_ISOLATE, strlen(CMD_AP_ISOLATE)) == 0) {
+ bytes_written = wl_android_set_ap_isolate(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_MAXASSOC, strlen(CMD_MAXASSOC)) == 0) {
+ bytes_written = wl_android_set_maxassoc_limit(net, command, priv_cmd.total_len);
+ }
+ else if (strnicmp(command, CMD_CHANNEL_WIDTH, strlen(CMD_CHANNEL_WIDTH)) == 0) {
+ bytes_written = wl_android_set_channel_width(net, command, priv_cmd.total_len);
+ }
+ else {
+ DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
+ snprintf(command, 3, "OK");
+ bytes_written = strlen("OK");
+ }
+
+ if (bytes_written >= 0) {
+ if ((bytes_written == 0) && (priv_cmd.total_len > 0))
+ command[0] = '\0';
+ if (bytes_written >= priv_cmd.total_len) {
+ DHD_ERROR(("%s: err. bytes_written:%d >= buf_size:%d \n",
+ __FUNCTION__, bytes_written, buf_size));
+ ret = BCME_BUFTOOSHORT;
+ goto exit;
+ }
+ bytes_written++;
+ priv_cmd.used_len = bytes_written;
+ if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
+ DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
+ ret = -EFAULT;
+ }
+ }
+#ifdef CONNECTION_STATISTICS
+ else if (strnicmp(command, CMD_GET_CONNECTION_STATS,
+ strlen(CMD_GET_CONNECTION_STATS)) == 0) {
+ bytes_written = wl_android_get_connection_stats(net, command,
+ priv_cmd.total_len);
+ }
+#endif
+ else {
+ ret = bytes_written;
+ }
+
+exit:
+ net_os_wake_unlock(net);
+ kfree(command);
+ return ret;
+}
+
+int wl_android_init(void)
+{
+ int ret = 0;
+
+#ifdef ENABLE_INSMOD_NO_FW_LOAD
+ dhd_download_fw_on_driverload = FALSE;
+#endif /* ENABLE_INSMOD_NO_FW_LOAD */
+ if (!iface_name[0]) {
+ memset(iface_name, 0, IFNAMSIZ);
+ bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
+ }
+
+ wl_netlink_init();
+
+ return ret;
+}
+
+int wl_android_exit(void)
+{
+ int ret = 0;
+ struct io_cfg *cur, *q;
+
+ wl_netlink_deinit();
+
+ list_for_each_entry_safe(cur, q, &miracast_resume_list, list) {
+ list_del(&cur->list);
+ kfree(cur);
+ }
+
+ return ret;
+}
+
+void wl_android_post_init(void)
+{
+
+#ifdef ENABLE_4335BT_WAR
+ bcm_bt_unlock(lock_cookie_wifi);
+ printk("%s: btlock released\n", __FUNCTION__);
+#endif /* ENABLE_4335BT_WAR */
+
+ if (!dhd_download_fw_on_driverload)
+ g_wifi_on = FALSE;
+}
diff --git a/drivers/net/wireless/bcmdhd_1363/wl_android.h b/drivers/net/wireless/bcmdhd_1363/wl_android.h
new file mode 100644
index 000000000000..1e25926325e0
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/wl_android.h
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wl_android.h 608194 2015-12-24 04:34:35Z $
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <wldev_common.h>
+
+/* If any feature uses the Generic Netlink Interface, put it here to enable WL_GENL
+ * automatically
+ */
+#if defined(BT_WIFI_HANDOVER) || defined(WL_NAN)
+#define WL_GENL
+#endif
+
+
+
+/**
+ * Android platform dependent functions, feel free to add Android specific functions here
+ * (save the macros in dhd). Please do NOT declare functions that are NOT exposed to dhd
+ * or cfg, define them as static in wl_android.c
+ */
+
+/**
+ * wl_android_init will be called from module init function (dhd_module_init now), similarly
+ * wl_android_exit will be called from module exit function (dhd_module_cleanup now)
+ */
+int wl_android_init(void);
+int wl_android_exit(void);
+void wl_android_post_init(void);
+int wl_android_wifi_on(struct net_device *dev);
+int wl_android_wifi_off(struct net_device *dev, bool on_failure);
+int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd);
+
+s32 wl_netlink_send_msg(int pid, int type, int seq, void *data, size_t size);
+
+/* hostap mac mode */
+#define MACLIST_MODE_DISABLED 0
+#define MACLIST_MODE_DENY 1
+#define MACLIST_MODE_ALLOW 2
+
+/* max number of assoc list */
+#define MAX_NUM_OF_ASSOCLIST 64
+
+/* Bandwidth */
+#define WL_CH_BANDWIDTH_20MHZ 20
+#define WL_CH_BANDWIDTH_40MHZ 40
+#define WL_CH_BANDWIDTH_80MHZ 80
+/* max number of mac filter list
+ * restrict max number to 10 as maximum cmd string size is 255
+ */
+#define MAX_NUM_MAC_FILT 10
+
+int wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist);
+int wl_android_set_roam_offload_bssid_list(struct net_device *dev, const char *cmd);
diff --git a/drivers/net/wireless/bcmdhd_1363/wl_cfg80211.c b/drivers/net/wireless/bcmdhd_1363/wl_cfg80211.c
new file mode 100644
index 000000000000..4b45bed183be
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/wl_cfg80211.c
@@ -0,0 +1,17874 @@
+/*
+ * Linux cfg80211 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wl_cfg80211.c 665077 2017-05-18 07:16:48Z $
+ */
+/* */
+#include <typedefs.h>
+#include <linuxver.h>
+#include <osl.h>
+#include <linux/kernel.h>
+
+#include <bcmutils.h>
+#include <bcmwifi_channels.h>
+#include <bcmendian.h>
+#include <proto/ethernet.h>
+#include <proto/802.11.h>
+#include <linux/if_arp.h>
+#include <asm/uaccess.h>
+
+#include <proto/ethernet.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <linux/wait.h>
+#include <net/cfg80211.h>
+#include <net/rtnetlink.h>
+
+#include <wlioctl.h>
+#include <wldev_common.h>
+#include <wl_cfg80211.h>
+#include <wl_cfgp2p.h>
+#include <wl_android.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_linux.h>
+#include <dhdioctl.h>
+#include <wlioctl.h>
+#include <dhd_cfg80211.h>
+#include <dhd_bus.h>
+#ifdef PNO_SUPPORT
+#include <dhd_pno.h>
+#endif /* PNO_SUPPORT */
+
+#if defined(WL_VENDOR_EXT_SUPPORT)
+#include <wl_cfgvendor.h>
+#endif /* defined(WL_VENDOR_EXT_SUPPORT) */
+
+#ifdef WL_NAN
+#include <wl_cfgnan.h>
+#endif /* WL_NAN */
+
+#ifdef PROP_TXSTATUS
+#include <dhd_wlfc.h>
+#endif
+
+#ifdef BCMPCIE
+#include <dhd_flowring.h>
+#endif
+
+#ifdef DHD_BANDSTEER
+#include <dhd_bandsteer.h>
+#endif /* DHD_BANDSTEER */
+
+#ifdef WL11U
+#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF)
+#error You should enable 'WL_ENABLE_P2P_IF' or 'WL_CFG80211_P2P_DEV_IF' \
+ according to Kernel version and is supported only in Android-JB
+#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */
+#endif /* WL11U */
+
+#ifdef BCMWAPI_WPI
+/* these items should evetually go into wireless.h of the linux system headfile dir */
+#ifndef IW_ENCODE_ALG_SM4
+#define IW_ENCODE_ALG_SM4 0x20
+#endif
+
+#ifndef IW_AUTH_WAPI_ENABLED
+#define IW_AUTH_WAPI_ENABLED 0x20
+#endif
+
+#ifndef IW_AUTH_WAPI_VERSION_1
+#define IW_AUTH_WAPI_VERSION_1 0x00000008
+#endif
+
+#ifndef IW_AUTH_CIPHER_SMS4
+#define IW_AUTH_CIPHER_SMS4 0x00000020
+#endif
+
+#ifndef IW_AUTH_KEY_MGMT_WAPI_PSK
+#define IW_AUTH_KEY_MGMT_WAPI_PSK 4
+#endif
+
+#ifndef IW_AUTH_KEY_MGMT_WAPI_CERT
+#define IW_AUTH_KEY_MGMT_WAPI_CERT 8
+#endif
+
+/*
+ * Defined new macro for WAPI cipher suite to map the corresponding value from
+ * supplicant, since kernel's value of WLAN_CIPHER_SUITE_SMS4 varies for different
+ * kernel versions
+ */
+#define WLAN_DHD_CIPHER_SUITE_SMS4 0x000FAC07
+/*
+ * Defined new macro for WAPI akm suite to map the corresponding value from
+ * supplicant, since corresponding macro does not exist in kernel
+ */
+#define WLAN_DHD_AKM_SUITE_WAPI_PSK 0x000FAC04
+#endif /* BCMWAPI_WPI */
+
+#ifdef BCMWAPI_WPI
+#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED))
+#else /* BCMWAPI_WPI */
+#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
+#endif /* BCMWAPI_WPI */
+
+static struct device *cfg80211_parent_dev = NULL;
+#ifdef CUSTOMER_HW4_DEBUG
+u32 wl_dbg_level = WL_DBG_ERR | WL_DBG_P2P_ACTION;
+#else
+u32 wl_dbg_level = WL_DBG_ERR;
+#endif /* CUSTOMER_HW4_DEBUG */
+
+#define MAX_WAIT_TIME 1500
+#ifdef WLAIBSS_MCHAN
+#define IBSS_IF_NAME "ibss%d"
+#endif /* WLAIBSS_MCHAN */
+
+#ifdef VSDB
+/* sleep time to keep STA's connecting or connection for continuous af tx or finding a peer */
+#define DEFAULT_SLEEP_TIME_VSDB 120
+#define OFF_CHAN_TIME_THRESHOLD_MS 200
+#define AF_RETRY_DELAY_TIME 40
+
+/* if sta is connected or connecting, sleep for a while before retry af tx or finding a peer */
+#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg) \
+ do { \
+ if (wl_get_drv_status(cfg, CONNECTED, bcmcfg_to_prmry_ndev(cfg)) || \
+ wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) { \
+ OSL_SLEEP(DEFAULT_SLEEP_TIME_VSDB); \
+ } \
+ } while (0)
+#else /* VSDB */
+/* if not VSDB, do nothing */
+#define WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg)
+#endif /* VSDB */
+
+#ifdef WL_CFG80211_SYNC_GON
+#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) \
+ (wl_get_drv_status_all(cfg, SENDING_ACT_FRM) || \
+ wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN))
+#else
+#define WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg) wl_get_drv_status_all(cfg, SENDING_ACT_FRM)
+#endif /* WL_CFG80211_SYNC_GON */
+
+#define DNGL_FUNC(func, parameters) func parameters
+#define COEX_DHCP
+
+#define WLAN_EID_SSID 0
+#define CH_MIN_5G_CHANNEL 34
+#define CH_MIN_2G_CHANNEL 1
+#define ACTIVE_SCAN 1
+#define PASSIVE_SCAN 0
+
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+#define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \
+_Pragma("GCC diagnostic push") \
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
+(entry) = list_first_entry((ptr), type, member); \
+_Pragma("GCC diagnostic pop") \
+
+#define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
+_Pragma("GCC diagnostic push") \
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
+entry = container_of((ptr), type, member); \
+_Pragma("GCC diagnostic pop") \
+
+#else
+#define BCM_SET_LIST_FIRST_ENTRY(entry, ptr, type, member) \
+(entry) = list_first_entry((ptr), type, member); \
+
+#define BCM_SET_CONTAINER_OF(entry, ptr, type, member) \
+entry = container_of((ptr), type, member); \
+
+#endif /* STRICT_GCC_WARNINGS */
+
+enum rmc_event_type {
+ RMC_EVENT_NONE,
+ RMC_EVENT_LEADER_CHECK_FAIL
+};
+
+/* This is to override regulatory domains defined in cfg80211 module (reg.c)
+ * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
+ * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
+ * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels.
+ * All the chnages in world regulatory domain are to be done here.
+ *
+ * this definition reuires disabling missing-field-initializer warning
+ * as the ieee80211_regdomain definition differs in plain linux and in Android
+ */
+#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 const struct ieee80211_regdomain brcm_regdom = {
+ .n_reg_rules = 4,
+ .alpha2 = "99",
+ .reg_rules = {
+ /* IEEE 802.11b/g, channels 1..11 */
+ REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
+ /* If any */
+ /* IEEE 802.11 channel 14 - Only JP enables
+ * this and for 802.11b only
+ */
+ REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
+ /* IEEE 802.11a, channel 36..64 */
+ REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
+ /* IEEE 802.11a, channel 100..165 */
+ REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
+};
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic pop")
+#endif
+
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
+ (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
+static const struct ieee80211_iface_limit common_if_limits[] = {
+ {
+ /*
+ * Driver can support up to 2 AP's
+ */
+ .max = 2,
+ .types = BIT(NL80211_IFTYPE_AP),
+ },
+ {
+ /*
+ * During P2P-GO removal, P2P-GO is first changed to STA and later only
+ * removed. So setting maximum possible number of STA interfaces according
+ * to kernel version.
+ *
+ * less than linux-3.8 - max:3 (wlan0 + p2p0 + group removal of p2p-p2p0-x)
+ * linux-3.8 and above - max:2 (wlan0 + group removal of p2p-wlan0-x)
+ */
+#ifdef WL_ENABLE_P2P_IF
+ .max = 3,
+#else
+ .max = 2,
+#endif /* WL_ENABLE_P2P_IF */
+ .types = BIT(NL80211_IFTYPE_STATION),
+ },
+ {
+ .max = 2,
+ .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT),
+ },
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
+ },
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_ADHOC),
+ },
+};
+#ifdef BCM4330_CHIP
+#define NUM_DIFF_CHANNELS 1
+#else
+#define NUM_DIFF_CHANNELS 2
+#endif
+static const struct ieee80211_iface_combination
+common_iface_combinations[] = {
+ {
+ .num_different_channels = NUM_DIFF_CHANNELS,
+ /*
+ * max_interfaces = 4
+ * The max no of interfaces will be used in dual p2p case.
+ * {STA, P2P Device, P2P Group 1, P2P Group 2}. Though we
+ * will not be using the STA functionality in this case, it
+ * will remain registered as it is the primary interface.
+ */
+ .max_interfaces = 4,
+ .limits = common_if_limits,
+ .n_limits = ARRAY_SIZE(common_if_limits),
+ },
+};
+#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
+
+/* Data Element Definitions */
+#define WPS_ID_CONFIG_METHODS 0x1008
+#define WPS_ID_REQ_TYPE 0x103A
+#define WPS_ID_DEVICE_NAME 0x1011
+#define WPS_ID_VERSION 0x104A
+#define WPS_ID_DEVICE_PWD_ID 0x1012
+#define WPS_ID_REQ_DEV_TYPE 0x106A
+#define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053
+#define WPS_ID_PRIM_DEV_TYPE 0x1054
+
+/* Device Password ID */
+#define DEV_PW_DEFAULT 0x0000
+#define DEV_PW_USER_SPECIFIED 0x0001,
+#define DEV_PW_MACHINE_SPECIFIED 0x0002
+#define DEV_PW_REKEY 0x0003
+#define DEV_PW_PUSHBUTTON 0x0004
+#define DEV_PW_REGISTRAR_SPECIFIED 0x0005
+
+/* Config Methods */
+#define WPS_CONFIG_USBA 0x0001
+#define WPS_CONFIG_ETHERNET 0x0002
+#define WPS_CONFIG_LABEL 0x0004
+#define WPS_CONFIG_DISPLAY 0x0008
+#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
+#define WPS_CONFIG_INT_NFC_TOKEN 0x0020
+#define WPS_CONFIG_NFC_INTERFACE 0x0040
+#define WPS_CONFIG_PUSHBUTTON 0x0080
+#define WPS_CONFIG_KEYPAD 0x0100
+#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
+#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
+#define WPS_CONFIG_VIRT_DISPLAY 0x2008
+#define WPS_CONFIG_PHY_DISPLAY 0x4008
+
+#define PM_BLOCK 1
+#define PM_ENABLE 0
+
+
+#define WL_AKM_SUITE_SHA256_1X 0x000FAC05
+#define WL_AKM_SUITE_SHA256_PSK 0x000FAC06
+
+#ifndef IBSS_COALESCE_ALLOWED
+#define IBSS_COALESCE_ALLOWED 0
+#endif
+
+#ifndef IBSS_INITIAL_SCAN_ALLOWED
+#define IBSS_INITIAL_SCAN_ALLOWED 0
+#endif
+
+#define CUSTOM_RETRY_MASK 0xff000000 /* Mask for retry counter of custom dwell time */
+#define LONG_LISTEN_TIME 2000
+
+#define MAX_SCAN_ABORT_WAIT_CNT 20
+#define WAIT_SCAN_ABORT_OSL_SLEEP_TIME 10
+
+#define IDSUP_4WAY_HANDSHAKE_TIMEOUT 10000
+enum idsup_event_type {
+ IDSUP_EVENT_SUCCESS = 0,
+ IDSUP_EVENT_4WAY_HANDSHAKE_TIMEOUT
+};
+/*
+ * cfg80211_ops api/callback list
+ */
+static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da,
+ const struct ether_addr *sa, const struct ether_addr *bssid,
+ u8 **pheader, u32 *body_len, u8 *pbody);
+static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request,
+ struct cfg80211_ssid *this_ssid);
+#if defined(WL_CFG80211_P2P_DEV_IF)
+static s32
+wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request);
+#else
+static s32
+wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
+#ifdef WLAIBSS_MCHAN
+static bcm_struct_cfgdev* bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name);
+static s32 bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev);
+#endif /* WLAIBSS_MCHAN */
+static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ibss_params *params);
+static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy,
+ struct net_device *dev);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
+ struct net_device *dev, const u8 *mac,
+ struct station_info *sinfo);
+#else
+static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
+ struct net_device *dev, u8 *mac,
+ struct station_info *sinfo);
+#endif
+static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *dev, bool enabled,
+ s32 timeout);
+static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code);
+#if defined(WL_CFG80211_P2P_DEV_IF)
+static s32
+wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+ enum nl80211_tx_power_setting type, s32 mbm);
+#else
+static s32
+wl_cfg80211_set_tx_power(struct wiphy *wiphy,
+ enum nl80211_tx_power_setting type, s32 dbm);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+#if defined(WL_CFG80211_P2P_DEV_IF)
+static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
+ struct wireless_dev *wdev, s32 *dbm);
+#else
+static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
+ struct net_device *dev,
+ u8 key_idx, bool unicast, bool multicast);
+static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr,
+ struct key_params *params);
+static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr);
+static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr,
+ void *cookie, void (*callback) (void *cookie,
+ struct key_params *params));
+static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
+ struct net_device *dev, u8 key_idx);
+static s32 wl_cfg80211_resume(struct wiphy *wiphy);
+#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
+ 2, 0))
+static s32 wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
+ bcm_struct_cfgdev *cfgdev, u64 cookie);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
+static s32 wl_cfg80211_del_station(
+ struct wiphy *wiphy, struct net_device *ndev,
+ struct station_del_parameters *params);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
+ struct net_device *ndev, const u8* mac_addr);
+#else
+static s32 wl_cfg80211_del_station(struct wiphy *wiphy,
+ struct net_device *ndev, u8* mac_addr);
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
+ struct net_device *dev, const u8 *mac, struct station_parameters *params);
+#else
+static s32 wl_cfg80211_change_station(struct wiphy *wiphy,
+ struct net_device *dev, u8 *mac, struct station_parameters *params);
+#endif
+#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
+static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
+#else
+static s32 wl_cfg80211_suspend(struct wiphy *wiphy);
+#endif /* KERNEL_VERSION(2, 6, 39) || WL_COMPAT_WIRELES */
+static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_pmksa *pmksa);
+static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_pmksa *pmksa);
+static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
+ struct net_device *dev);
+static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg);
+static void wl_cfg80211_cancel_scan(struct bcm_cfg80211 *cfg);
+static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg,
+ struct net_device *ndev, bool aborted, bool fw_abort);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
+#if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
+ KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
+static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
+ u32 peer_capability, const u8 *data, size_t len);
+#elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
+ (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
+static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
+ u32 peer_capability, const u8 *data, size_t len);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
+ u32 peer_capability, bool initiator, const u8 *data, size_t len);
+#else
+static s32 wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *data,
+ size_t len);
+#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *peer, enum nl80211_tdls_operation oper);
+#else
+static s32 wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, enum nl80211_tdls_operation oper);
+#endif
+#endif /* LINUX_VERSION > KERNEL_VERSION(3,2,0) || WL_COMPAT_WIRELESS */
+#ifdef WL_SCHED_SCAN
+static int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev);
+#endif
+#if defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF)
+bcm_struct_cfgdev*
+wl_cfg80211_create_iface(struct wiphy *wiphy, enum nl80211_iftype
+ iface_type, u8 *mac_addr, const char *name);
+s32
+wl_cfg80211_del_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev);
+#endif /* defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF) */
+
+s32 wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
+ struct net_device *ndev, s32 bsscfg_idx,
+ enum nl80211_iftype iface_type, s32 del, u8 *addr);
+s32 wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
+ struct net_device *ndev, s32 bsscfg_idx,
+ enum nl80211_iftype iface_type, s32 del, u8 *addr);
+chanspec_t wl_chspec_driver_to_host(chanspec_t chanspec);
+chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec);
+#ifdef WL11ULB
+static s32 wl_cfg80211_get_ulb_bw(struct wireless_dev *wdev);
+static chanspec_t wl_cfg80211_ulb_get_min_bw_chspec(struct wireless_dev *wdev, s32 bssidx);
+static s32 wl_cfg80211_ulbbw_to_ulbchspec(u32 ulb_bw);
+#else
+static inline chanspec_t wl_cfg80211_ulb_get_min_bw_chspec(
+ struct wireless_dev *wdev, s32 bssidx)
+{
+ return WL_CHANSPEC_BW_20;
+}
+#endif /* WL11ULB */
+
+/*
+ * event & event Q handlers for cfg80211 interfaces
+ */
+static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg);
+static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg);
+static void wl_event_handler(struct work_struct *work_data);
+static void wl_init_eq(struct bcm_cfg80211 *cfg);
+static void wl_flush_eq(struct bcm_cfg80211 *cfg);
+static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg);
+static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags);
+static void wl_init_eq_lock(struct bcm_cfg80211 *cfg);
+static void wl_init_event_handler(struct bcm_cfg80211 *cfg);
+static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg);
+static s32 wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 type,
+ const wl_event_msg_t *msg, void *data);
+static void wl_put_event(struct wl_event_q *e);
+static s32 wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data);
+static s32 wl_notify_connect_status(struct bcm_cfg80211 *cfg,
+ bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
+static s32 wl_notify_roaming_status(struct bcm_cfg80211 *cfg,
+ bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
+static s32 wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+static s32 wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data, bool completed);
+static s32 wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data);
+static s32 wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+#ifdef BT_WIFI_HANDOVER
+static s32 wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg,
+ bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
+#endif /* BT_WIFI_HANDOVER */
+#ifdef WL_SCHED_SCAN
+static s32
+wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data);
+#endif /* WL_SCHED_SCAN */
+#ifdef PNO_SUPPORT
+static s32 wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+#endif /* PNO_SUPPORT */
+#ifdef GSCAN_SUPPORT
+static s32 wl_notify_gscan_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+#endif /* GSCAN_SUPPORT */
+static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
+ enum wl_status state, bool set);
+#ifdef DHD_LOSSLESS_ROAMING
+static s32 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg,
+ bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data);
+static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg);
+#endif /* DHD_LOSSLESS_ROAMING */
+#ifdef CUSTOM_EVENT_PM_WAKE
+static s32 wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+#endif /* CUSTOM_EVENT_PM_WAKE */
+#ifdef ENABLE_TEMP_THROTTLING
+static s32 wl_check_rx_throttle_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+#endif /* ENABLE_TEMP_THROTTLING */
+
+#ifdef WLTDLS
+static s32 wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+#endif /* WLTDLS */
+/*
+ * register/deregister parent device
+ */
+static void wl_cfg80211_clear_parent_dev(void);
+/*
+ * ioctl utilites
+ */
+
+/*
+ * cfg80211 set_wiphy_params utilities
+ */
+static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold);
+static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold);
+static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l);
+
+/*
+ * cfg profile utilities
+ */
+static s32 wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, const void *data, s32 item);
+static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item);
+static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev);
+
+/*
+ * cfg80211 connect utilites
+ */
+static s32 wl_set_wpa_version(struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+static s32 wl_set_auth_type(struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+static s32 wl_set_set_cipher(struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+static s32 wl_set_key_mgmt(struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+static s32 wl_set_set_sharedkey(struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+#ifdef BCMWAPI_WPI
+static s32 wl_set_set_wapi_ie(struct net_device *dev,
+ struct cfg80211_connect_params *sme);
+#endif
+static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev);
+static s32 wl_ch_to_chanspec(struct net_device *dev, int ch,
+ struct wl_join_params *join_params, size_t *join_params_size);
+void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg);
+
+#if (defined(AP_STA_RSDB_FEASIBILITY_CHK) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, \
+ 0)))
+#error "enable AP_STA_RSDB_FEASIBILITY_CHK for linux version >= 3.6.0"
+#endif /* AP_STA_RSDB_FEASIBILITY_CHK && LINUX_VERSION < KERNEL_VERSION(3, 6, 0) */
+#ifdef AP_STA_RSDB_FEASIBILITY_CHK
+static bool wl_cfg80211_chk_conn_feasibility(struct bcm_cfg80211 *cfg,
+ struct ieee80211_channel *chan);
+#endif /* AP_STA_RSDB_FEASIBILITY_CHK */
+
+/*
+ * information element utilities
+ */
+static void wl_rst_ie(struct bcm_cfg80211 *cfg);
+static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v);
+static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, const u8 *ie_stream, u32 *ie_size,
+ bool roam);
+static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size);
+static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size);
+static u32 wl_get_ielen(struct bcm_cfg80211 *cfg);
+
+#ifdef WL11U
+bcm_tlv_t *
+wl_cfg80211_find_interworking_ie(u8 *parse, u32 len);
+static s32
+wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag,
+ uint8 ie_id, uint8 *data, uint8 data_len);
+#endif /* WL11U */
+
+static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, void *data);
+static void wl_free_wdev(struct bcm_cfg80211 *cfg);
+#ifdef CONFIG_CFG80211_INTERNAL_REGDB
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
+static int
+#else
+static void
+#endif /* kernel version < 3.10.11 */
+wl_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
+#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
+
+static s32 wl_inform_bss(struct bcm_cfg80211 *cfg);
+static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam);
+static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam);
+static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy);
+s32 wl_cfg80211_channel_to_freq(u32 channel);
+
+
+static void wl_cfg80211_work_handler(struct work_struct *work);
+static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, const u8 *mac_addr,
+ struct key_params *params);
+/*
+ * key indianess swap utilities
+ */
+static void swap_key_from_BE(struct wl_wsec_key *key);
+static void swap_key_to_BE(struct wl_wsec_key *key);
+
+/*
+ * bcm_cfg80211 memory init/deinit utilities
+ */
+static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg);
+static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg);
+
+static void wl_delay(u32 ms);
+
+/*
+ * ibss mode utilities
+ */
+static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev);
+static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg);
+
+/*
+ * link up/down , default configuration utilities
+ */
+static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg);
+static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg);
+static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
+static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e,
+ struct net_device *ndev);
+static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e);
+static void wl_link_up(struct bcm_cfg80211 *cfg);
+static void wl_link_down(struct bcm_cfg80211 *cfg);
+static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 iftype);
+static void wl_init_conf(struct wl_conf *conf);
+static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *if_event_info,
+ struct net_device* ndev);
+
+int wl_cfg80211_get_ioctl_version(void);
+
+/*
+ * find most significant bit set
+ */
+static __used u32 wl_find_msb(u16 bit16);
+
+/*
+ * rfkill support
+ */
+static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup);
+static int wl_rfkill_set(void *data, bool blocked);
+#ifdef DEBUGFS_CFG80211
+static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg);
+static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg);
+#endif
+
+static wl_scan_params_t *wl_cfg80211_scan_alloc_params(struct wireless_dev *wdev, int channel,
+ int nprobes, int *out_params_size);
+static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role);
+
+#ifdef WL_CFG80211_ACL
+/* ACL */
+static int wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev,
+ const struct cfg80211_acl_data *acl);
+#endif /* WL_CFG80211_ACL */
+
+/*
+ * Some external functions, TODO: move them to dhd_linux.h
+ */
+int dhd_add_monitor(char *name, struct net_device **new_ndev);
+int dhd_del_monitor(struct net_device *ndev);
+int dhd_monitor_init(void *dhd_pub);
+int dhd_monitor_uninit(void);
+int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
+
+
+#ifdef DHD_IFDEBUG
+void wl_dump_ifinfo(struct bcm_cfg80211 *cfg);
+#endif
+
+#ifdef P2P_LISTEN_OFFLOADING
+s32 wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg);
+#endif /* P2P_LISTEN_OFFLOADING */
+
+#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 /* PKT_FILTER_SUPPORT */
+
+static int wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const struct ether_addr *bssid);
+
+static int bw2cap[] = { 0, 0, WLC_BW_CAP_20MHZ, WLC_BW_CAP_40MHZ, WLC_BW_CAP_80MHZ,
+ WLC_BW_CAP_160MHZ, WLC_BW_CAP_160MHZ };
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0))
+#define CFG80211_DISCONNECTED(dev, reason, ie, len, loc_gen, gfp) \
+ cfg80211_disconnected(dev, reason, ie, len, gfp);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0))
+#define CFG80211_DISCONNECTED(dev, reason, ie, len, loc_gen, gfp) \
+ cfg80211_disconnected(dev, reason, ie, len, loc_gen, gfp);
+#endif
+
+#ifdef RSSI_OFFSET
+static s32 wl_rssi_offset(s32 rssi)
+{
+ rssi += RSSI_OFFSET;
+ if (rssi > 0)
+ rssi = 0;
+ return rssi;
+}
+#else
+#define wl_rssi_offset(x) x
+#endif
+
+#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \
+ (akm) == RSN_AKM_UNSPECIFIED || \
+ (akm) == RSN_AKM_PSK)
+
+
+extern int dhd_wait_pend8021x(struct net_device *dev);
+#ifdef PROP_TXSTATUS_VSDB
+extern int disable_proptx;
+#endif /* PROP_TXSTATUS_VSDB */
+
+
+extern int passive_channel_skip;
+
+static s32
+wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+static s32
+wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0)) && (LINUX_VERSION_CODE <= (3, 7, \
+ 0)))
+struct chan_info {
+ int freq;
+ int chan_type;
+};
+#endif
+
+
+#if (WL_DBG_LEVEL > 0)
+#define WL_DBG_ESTR_MAX 50
+static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = {
+ "SET_SSID", "JOIN", "START", "AUTH", "AUTH_IND",
+ "DEAUTH", "DEAUTH_IND", "ASSOC", "ASSOC_IND", "REASSOC",
+ "REASSOC_IND", "DISASSOC", "DISASSOC_IND", "QUIET_START", "QUIET_END",
+ "BEACON_RX", "LINK", "MIC_ERROR", "NDIS_LINK", "ROAM",
+ "TXFAIL", "PMKID_CACHE", "RETROGRADE_TSF", "PRUNE", "AUTOAUTH",
+ "EAPOL_MSG", "SCAN_COMPLETE", "ADDTS_IND", "DELTS_IND", "BCNSENT_IND",
+ "BCNRX_MSG", "BCNLOST_MSG", "ROAM_PREP", "PFN_NET_FOUND",
+ "PFN_NET_LOST",
+ "RESET_COMPLETE", "JOIN_START", "ROAM_START", "ASSOC_START",
+ "IBSS_ASSOC",
+ "RADIO", "PSM_WATCHDOG",
+ "WLC_E_XXX_ASSOC_START", "WLC_E_XXX_ASSOC_ABORT",
+ "PROBREQ_MSG",
+ "SCAN_CONFIRM_IND", "PSK_SUP", "COUNTRY_CODE_CHANGED",
+ "EXCEEDED_MEDIUM_TIME", "ICV_ERROR",
+ "UNICAST_DECODE_ERROR", "MULTICAST_DECODE_ERROR", "TRACE",
+ "WLC_E_BTA_HCI_EVENT", "IF", "WLC_E_P2P_DISC_LISTEN_COMPLETE",
+ "RSSI", "PFN_SCAN_COMPLETE", "WLC_E_EXTLOG_MSG",
+ "ACTION_FRAME", "ACTION_FRAME_COMPLETE", "WLC_E_PRE_ASSOC_IND",
+ "WLC_E_PRE_REASSOC_IND", "WLC_E_CHANNEL_ADOPTED", "WLC_E_AP_STARTED",
+ "WLC_E_DFS_AP_STOP", "WLC_E_DFS_AP_RESUME", "WLC_E_WAI_STA_EVENT",
+ "WLC_E_WAI_MSG", "WLC_E_ESCAN_RESULT", "WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE",
+ "WLC_E_PROBRESP_MSG", "WLC_E_P2P_PROBREQ_MSG", "WLC_E_DCS_REQUEST", "WLC_E_FIFO_CREDIT_MAP",
+ "WLC_E_ACTION_FRAME_RX", "WLC_E_WAKE_EVENT", "WLC_E_RM_COMPLETE"
+};
+#endif /* WL_DBG_LEVEL */
+
+#define CHAN2G(_channel, _freq, _flags) { \
+ .band = IEEE80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+#define CHAN5G(_channel, _flags) { \
+ .band = IEEE80211_BAND_5GHZ, \
+ .center_freq = 5000 + (5 * (_channel)), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
+#define RATETAB_ENT(_rateid, _flags) \
+ { \
+ .bitrate = RATE_TO_BASE100KBPS(_rateid), \
+ .hw_value = (_rateid), \
+ .flags = (_flags), \
+ }
+
+static struct ieee80211_rate __wl_rates[] = {
+ RATETAB_ENT(DOT11_RATE_1M, 0),
+ RATETAB_ENT(DOT11_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(DOT11_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(DOT11_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATETAB_ENT(DOT11_RATE_6M, 0),
+ RATETAB_ENT(DOT11_RATE_9M, 0),
+ RATETAB_ENT(DOT11_RATE_12M, 0),
+ RATETAB_ENT(DOT11_RATE_18M, 0),
+ RATETAB_ENT(DOT11_RATE_24M, 0),
+ RATETAB_ENT(DOT11_RATE_36M, 0),
+ RATETAB_ENT(DOT11_RATE_48M, 0),
+ RATETAB_ENT(DOT11_RATE_54M, 0)
+};
+
+#define wl_a_rates (__wl_rates + 4)
+#define wl_a_rates_size 8
+#define wl_g_rates (__wl_rates + 0)
+#define wl_g_rates_size 12
+
+static struct ieee80211_channel __wl_2ghz_channels[] = {
+ CHAN2G(1, 2412, 0),
+ CHAN2G(2, 2417, 0),
+ CHAN2G(3, 2422, 0),
+ CHAN2G(4, 2427, 0),
+ CHAN2G(5, 2432, 0),
+ CHAN2G(6, 2437, 0),
+ CHAN2G(7, 2442, 0),
+ CHAN2G(8, 2447, 0),
+ CHAN2G(9, 2452, 0),
+ CHAN2G(10, 2457, 0),
+ CHAN2G(11, 2462, 0),
+ CHAN2G(12, 2467, 0),
+ CHAN2G(13, 2472, 0),
+ CHAN2G(14, 2484, 0)
+};
+
+static struct ieee80211_channel __wl_5ghz_a_channels[] = {
+ CHAN5G(34, 0), CHAN5G(36, 0),
+ CHAN5G(38, 0), CHAN5G(40, 0),
+ CHAN5G(42, 0), CHAN5G(44, 0),
+ CHAN5G(46, 0), CHAN5G(48, 0),
+ CHAN5G(52, 0), CHAN5G(56, 0),
+ CHAN5G(60, 0), CHAN5G(64, 0),
+ CHAN5G(100, 0), CHAN5G(104, 0),
+ CHAN5G(108, 0), CHAN5G(112, 0),
+ CHAN5G(116, 0), CHAN5G(120, 0),
+ CHAN5G(124, 0), CHAN5G(128, 0),
+ CHAN5G(132, 0), CHAN5G(136, 0),
+ CHAN5G(140, 0), CHAN5G(144, 0),
+ CHAN5G(149, 0), CHAN5G(153, 0),
+ CHAN5G(157, 0), CHAN5G(161, 0),
+ CHAN5G(165, 0)
+};
+
+static struct ieee80211_supported_band __wl_band_2ghz = {
+ .band = IEEE80211_BAND_2GHZ,
+ .channels = __wl_2ghz_channels,
+ .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
+ .bitrates = wl_g_rates,
+ .n_bitrates = wl_g_rates_size
+};
+
+static struct ieee80211_supported_band __wl_band_5ghz_a = {
+ .band = IEEE80211_BAND_5GHZ,
+ .channels = __wl_5ghz_a_channels,
+ .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
+ .bitrates = wl_a_rates,
+ .n_bitrates = wl_a_rates_size
+};
+
+static const u32 __wl_cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+ WLAN_CIPHER_SUITE_AES_CMAC,
+#ifdef BCMWAPI_WPI
+ WLAN_CIPHER_SUITE_SMS4,
+ WLAN_DHD_CIPHER_SUITE_SMS4,
+#endif
+};
+
+#ifdef WL_SUPPORT_ACS
+/*
+ * The firmware code required for this feature to work is currently under
+ * BCMINTERNAL flag. In future if this is to enabled we need to bring the
+ * required firmware code out of the BCMINTERNAL flag.
+ */
+struct wl_dump_survey {
+ u32 obss;
+ u32 ibss;
+ u32 no_ctg;
+ u32 no_pckt;
+ u32 tx;
+ u32 idle;
+};
+#endif /* WL_SUPPORT_ACS */
+
+
+#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
+static int maxrxpktglom = 0;
+#endif
+
+/* IOCtl version read from targeted driver */
+static int ioctl_version;
+#ifdef DEBUGFS_CFG80211
+#define S_SUBLOGLEVEL 20
+static const struct {
+ u32 log_level;
+ char *sublogname;
+} sublogname_map[] = {
+ {WL_DBG_ERR, "ERR"},
+ {WL_DBG_INFO, "INFO"},
+ {WL_DBG_DBG, "DBG"},
+ {WL_DBG_SCAN, "SCAN"},
+ {WL_DBG_TRACE, "TRACE"},
+ {WL_DBG_P2P_ACTION, "P2PACTION"}
+};
+#endif
+
+#ifdef CUSTOMER_HW4_DEBUG
+uint prev_dhd_console_ms = 0;
+u32 prev_wl_dbg_level = 0;
+bool wl_scan_timeout_dbg_enabled = 0;
+static void wl_scan_timeout_dbg_set(void);
+static void wl_scan_timeout_dbg_clear(void);
+
+static void wl_scan_timeout_dbg_set(void)
+{
+ WL_ERR(("Enter \n"));
+ prev_dhd_console_ms = dhd_console_ms;
+ prev_wl_dbg_level = wl_dbg_level;
+
+ dhd_console_ms = 1;
+ wl_dbg_level |= (WL_DBG_ERR | WL_DBG_P2P_ACTION | WL_DBG_SCAN);
+
+ wl_scan_timeout_dbg_enabled = 1;
+}
+static void wl_scan_timeout_dbg_clear(void)
+{
+ WL_ERR(("Enter \n"));
+ dhd_console_ms = prev_dhd_console_ms;
+ wl_dbg_level = prev_wl_dbg_level;
+
+ wl_scan_timeout_dbg_enabled = 0;
+}
+#endif /* CUSTOMER_HW4_DEBUG */
+
+/* watchdog timer for disconnecting when fw is not associated for FW_ASSOC_WATCHDOG_TIME ms */
+uint32 fw_assoc_watchdog_ms = 0;
+bool fw_assoc_watchdog_started = 0;
+#define FW_ASSOC_WATCHDOG_TIME 10 * 1000 /* msec */
+
+#ifdef DHD_IFDEBUG
+
+void wl_dump_ifinfo(struct bcm_cfg80211 *cfg)
+{
+ WL_ERR(("cfg=%p\n", cfg));
+ if (cfg) {
+ WL_ERR(("cfg->wdev=%p\n", bcmcfg_to_prmry_wdev(cfg)));
+ if (bcmcfg_to_prmry_wdev(cfg)) {
+ WL_ERR(("cfg->wdev->wiphy=%p\n", bcmcfg_to_wiphy(cfg)));
+ WL_ERR(("cfg->wdev->netdev=%p\n", bcmcfg_to_prmry_ndev(cfg)));
+ }
+ }
+}
+#endif
+
+static void wl_add_remove_pm_enable_work(struct bcm_cfg80211 *cfg,
+ enum wl_pm_workq_act_type type)
+{
+ u16 wq_duration = 0;
+ dhd_pub_t *dhd = NULL;
+
+ if (cfg == NULL)
+ return;
+
+ dhd = (dhd_pub_t *)(cfg->pub);
+
+ mutex_lock(&cfg->pm_sync);
+ /*
+ * Make cancel and schedule work part mutually exclusive
+ * so that while cancelling, we are sure that there is no
+ * work getting scheduled.
+ */
+ if (delayed_work_pending(&cfg->pm_enable_work)) {
+ cancel_delayed_work_sync(&cfg->pm_enable_work);
+ DHD_PM_WAKE_UNLOCK(cfg->pub);
+ }
+
+ if (type == WL_PM_WORKQ_SHORT) {
+ wq_duration = WL_PM_ENABLE_TIMEOUT;
+ } else if (type == WL_PM_WORKQ_LONG) {
+ wq_duration = (WL_PM_ENABLE_TIMEOUT*2);
+ }
+
+ /* It should schedule work item only if driver is up */
+ if (wq_duration && dhd->up) {
+ if (schedule_delayed_work(&cfg->pm_enable_work,
+ msecs_to_jiffies((const unsigned int)wq_duration))) {
+ DHD_PM_WAKE_LOCK_TIMEOUT(cfg->pub,
+ msecs_to_jiffies((const unsigned int)wq_duration));
+ } else {
+ WL_ERR(("Can't schedule pm work handler\n"));
+ }
+ }
+ mutex_unlock(&cfg->pm_sync);
+}
+
+/* Return a new chanspec given a legacy chanspec
+ * Returns INVCHANSPEC on error
+ */
+static chanspec_t
+wl_chspec_from_legacy(chanspec_t legacy_chspec)
+{
+ chanspec_t chspec;
+
+ /* get the channel number */
+ chspec = LCHSPEC_CHANNEL(legacy_chspec);
+
+ /* convert the band */
+ if (LCHSPEC_IS2G(legacy_chspec)) {
+ chspec |= WL_CHANSPEC_BAND_2G;
+ } else {
+ chspec |= WL_CHANSPEC_BAND_5G;
+ }
+
+ /* convert the bw and sideband */
+ if (LCHSPEC_IS20(legacy_chspec)) {
+ chspec |= WL_CHANSPEC_BW_20;
+ } else {
+ chspec |= WL_CHANSPEC_BW_40;
+ if (LCHSPEC_CTL_SB(legacy_chspec) == WL_LCHANSPEC_CTL_SB_LOWER) {
+ chspec |= WL_CHANSPEC_CTL_SB_L;
+ } else {
+ chspec |= WL_CHANSPEC_CTL_SB_U;
+ }
+ }
+
+ if (wf_chspec_malformed(chspec)) {
+ WL_ERR(("wl_chspec_from_legacy: output chanspec (0x%04X) malformed\n",
+ chspec));
+ return INVCHANSPEC;
+ }
+
+ return chspec;
+}
+
+/* Return a legacy chanspec given a new chanspec
+ * Returns INVCHANSPEC on error
+ */
+static chanspec_t
+wl_chspec_to_legacy(chanspec_t chspec)
+{
+ chanspec_t lchspec;
+
+ if (wf_chspec_malformed(chspec)) {
+ WL_ERR(("wl_chspec_to_legacy: input chanspec (0x%04X) malformed\n",
+ chspec));
+ return INVCHANSPEC;
+ }
+
+ /* get the channel number */
+ lchspec = CHSPEC_CHANNEL(chspec);
+
+ /* convert the band */
+ if (CHSPEC_IS2G(chspec)) {
+ lchspec |= WL_LCHANSPEC_BAND_2G;
+ } else {
+ lchspec |= WL_LCHANSPEC_BAND_5G;
+ }
+
+ /* convert the bw and sideband */
+ if (CHSPEC_IS20(chspec)) {
+ lchspec |= WL_LCHANSPEC_BW_20;
+ lchspec |= WL_LCHANSPEC_CTL_SB_NONE;
+ } else if (CHSPEC_IS40(chspec)) {
+ lchspec |= WL_LCHANSPEC_BW_40;
+ if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_L) {
+ lchspec |= WL_LCHANSPEC_CTL_SB_LOWER;
+ } else {
+ lchspec |= WL_LCHANSPEC_CTL_SB_UPPER;
+ }
+ } else {
+ /* cannot express the bandwidth */
+ char chanbuf[CHANSPEC_STR_LEN];
+ WL_ERR((
+ "wl_chspec_to_legacy: unable to convert chanspec %s (0x%04X) "
+ "to pre-11ac format\n",
+ wf_chspec_ntoa(chspec, chanbuf), chspec));
+ return INVCHANSPEC;
+ }
+
+ return lchspec;
+}
+
+/* given a chanspec value, do the endian and chanspec version conversion to
+ * a chanspec_t value
+ * Returns INVCHANSPEC on error
+ */
+chanspec_t
+wl_chspec_host_to_driver(chanspec_t chanspec)
+{
+ if (ioctl_version == 1) {
+ chanspec = wl_chspec_to_legacy(chanspec);
+ if (chanspec == INVCHANSPEC) {
+ return chanspec;
+ }
+ }
+ chanspec = htodchanspec(chanspec);
+
+ return chanspec;
+}
+
+/* given a channel value, do the endian and chanspec version conversion to
+ * a chanspec_t value
+ * Returns INVCHANSPEC on error
+ */
+chanspec_t
+wl_ch_host_to_driver(struct wireless_dev *wdev, s32 bssidx, u16 channel)
+{
+ chanspec_t chanspec;
+
+ chanspec = channel & WL_CHANSPEC_CHAN_MASK;
+
+ if (channel <= CH_MAX_2G_CHANNEL)
+ chanspec |= WL_CHANSPEC_BAND_2G;
+ else
+ chanspec |= WL_CHANSPEC_BAND_5G;
+
+ chanspec |= wl_cfg80211_ulb_get_min_bw_chspec(wdev, bssidx);
+
+ chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+
+ return wl_chspec_host_to_driver(chanspec);
+}
+
+/* given a chanspec value from the driver, do the endian and chanspec version conversion to
+ * a chanspec_t value
+ * Returns INVCHANSPEC on error
+ */
+chanspec_t
+wl_chspec_driver_to_host(chanspec_t chanspec)
+{
+ chanspec = dtohchanspec(chanspec);
+ if (ioctl_version == 1) {
+ chanspec = wl_chspec_from_legacy(chanspec);
+ }
+
+ return chanspec;
+}
+
+/*
+ * convert ASCII string to MAC address (colon-delimited format)
+ * eg: 00:11:22:33:44:55
+ */
+int
+wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n)
+{
+ char *c = NULL;
+ int count = 0;
+
+ memset(n, 0, ETHER_ADDR_LEN);
+ for (;;) {
+ n->octet[count++] = (uint8)simple_strtoul(a, &c, 16);
+ if (!*c++ || count == ETHER_ADDR_LEN)
+ break;
+ a = c;
+ }
+ return (count == ETHER_ADDR_LEN);
+}
+
+/* There isn't a lot of sense in it, but you can transmit anything you like */
+static const struct ieee80211_txrx_stypes
+wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
+ [NL80211_IFTYPE_ADHOC] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+ [NL80211_IFTYPE_STATION] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_AP] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+ [NL80211_IFTYPE_AP_VLAN] = {
+ /* copy AP */
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+ [NL80211_IFTYPE_P2P_CLIENT] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+ [NL80211_IFTYPE_P2P_GO] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+ BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+ BIT(IEEE80211_STYPE_AUTH >> 4) |
+ BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+ BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ [NL80211_IFTYPE_P2P_DEVICE] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+ },
+#endif /* WL_CFG80211_P2P_DEV_IF */
+};
+
+static void swap_key_from_BE(struct wl_wsec_key *key)
+{
+ key->index = htod32(key->index);
+ key->len = htod32(key->len);
+ key->algo = htod32(key->algo);
+ key->flags = htod32(key->flags);
+ key->rxiv.hi = htod32(key->rxiv.hi);
+ key->rxiv.lo = htod16(key->rxiv.lo);
+ key->iv_initialized = htod32(key->iv_initialized);
+}
+
+static void swap_key_to_BE(struct wl_wsec_key *key)
+{
+ key->index = dtoh32(key->index);
+ key->len = dtoh32(key->len);
+ key->algo = dtoh32(key->algo);
+ key->flags = dtoh32(key->flags);
+ key->rxiv.hi = dtoh32(key->rxiv.hi);
+ key->rxiv.lo = dtoh16(key->rxiv.lo);
+ key->iv_initialized = dtoh32(key->iv_initialized);
+}
+
+/* Dump the contents of the encoded wps ie buffer and get pbc value */
+static void
+wl_validate_wps_ie(char *wps_ie, s32 wps_ie_len, bool *pbc)
+{
+ #define WPS_IE_FIXED_LEN 6
+ u16 len;
+ u8 *subel = NULL;
+ u16 subelt_id;
+ u16 subelt_len;
+ u16 val;
+ u8 *valptr = (uint8*) &val;
+ if (wps_ie == NULL || wps_ie_len < WPS_IE_FIXED_LEN) {
+ WL_ERR(("invalid argument : NULL\n"));
+ return;
+ }
+ len = (u16)wps_ie[TLV_LEN_OFF];
+
+ if (len > wps_ie_len) {
+ WL_ERR(("invalid length len %d, wps ie len %d\n", len, wps_ie_len));
+ return;
+ }
+ WL_DBG(("wps_ie len=%d\n", len));
+ len -= 4; /* for the WPS IE's OUI, oui_type fields */
+ subel = wps_ie + WPS_IE_FIXED_LEN;
+ while (len >= 4) { /* must have attr id, attr len fields */
+ valptr[0] = *subel++;
+ valptr[1] = *subel++;
+ subelt_id = HTON16(val);
+
+ valptr[0] = *subel++;
+ valptr[1] = *subel++;
+ subelt_len = HTON16(val);
+
+ len -= 4; /* for the attr id, attr len fields */
+
+ if (len < subelt_len) {
+ WL_ERR(("not enough data, len %d, subelt_len %d\n", len,
+ subelt_len));
+ break;
+ }
+ len -= subelt_len; /* for the remaining fields in this attribute */
+
+ WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n",
+ subel, subelt_id, subelt_len));
+
+ if (subelt_id == WPS_ID_VERSION) {
+ WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel));
+ } else if (subelt_id == WPS_ID_REQ_TYPE) {
+ WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel));
+ } else if (subelt_id == WPS_ID_CONFIG_METHODS) {
+ valptr[0] = *subel;
+ valptr[1] = *(subel + 1);
+ WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val)));
+ } else if (subelt_id == WPS_ID_DEVICE_NAME) {
+ char devname[100];
+ int namelen = MIN(subelt_len, (sizeof(devname) - 1));
+
+ if (namelen) {
+ memcpy(devname, subel, namelen);
+ devname[namelen] = '\0';
+ /* Printing len as rx'ed in the IE */
+ WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
+ devname, subelt_len));
+ }
+ } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) {
+ valptr[0] = *subel;
+ valptr[1] = *(subel + 1);
+ WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val)));
+ *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false;
+ } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) {
+ valptr[0] = *subel;
+ valptr[1] = *(subel + 1);
+ WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val)));
+ valptr[0] = *(subel + 6);
+ valptr[1] = *(subel + 7);
+ WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val)));
+ } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) {
+ valptr[0] = *subel;
+ valptr[1] = *(subel + 1);
+ WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val)));
+ valptr[0] = *(subel + 6);
+ valptr[1] = *(subel + 7);
+ WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val)));
+ } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) {
+ valptr[0] = *subel;
+ valptr[1] = *(subel + 1);
+ WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS"
+ ": cat=%u\n", HTON16(val)));
+ } else {
+ WL_DBG((" unknown attr 0x%x\n", subelt_id));
+ }
+
+ subel += subelt_len;
+ }
+}
+
+s32 wl_set_tx_power(struct net_device *dev,
+ enum nl80211_tx_power_setting type, s32 dbm)
+{
+ s32 err = 0;
+ s32 disable = 0;
+ s32 txpwrqdbm;
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+
+ /* Make sure radio is off or on as far as software is concerned */
+ disable = WL_RADIO_SW_DISABLE << 16;
+ disable = htod32(disable);
+ err = wldev_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable), true);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
+ return err;
+ }
+
+ if (dbm > 0xffff)
+ dbm = 0xffff;
+ txpwrqdbm = dbm * 4;
+ err = wldev_iovar_setbuf_bsscfg(dev, "qtxpower", (void *)&txpwrqdbm,
+ sizeof(txpwrqdbm), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
+ &cfg->ioctl_buf_sync);
+ if (unlikely(err))
+ WL_ERR(("qtxpower error (%d)\n", err));
+ else
+ WL_ERR(("dBm=%d, txpwrqdbm=0x%x\n", dbm, txpwrqdbm));
+
+ return err;
+}
+
+s32 wl_get_tx_power(struct net_device *dev, s32 *dbm)
+{
+ s32 err = 0;
+ s32 txpwrdbm;
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+
+ err = wldev_iovar_getbuf_bsscfg(dev, "qtxpower",
+ NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+
+ memcpy(&txpwrdbm, cfg->ioctl_buf, sizeof(txpwrdbm));
+ txpwrdbm = dtoh32(txpwrdbm);
+ *dbm = (txpwrdbm & ~WL_TXPWR_OVERRIDE) / 4;
+
+ WL_INFORM(("dBm=%d, txpwrdbm=0x%x\n", *dbm, txpwrdbm));
+
+ return err;
+}
+
+static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
+{
+ chanspec_t chspec;
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
+ struct ether_addr bssid;
+ struct wl_bss_info *bss = NULL;
+ s32 bssidx = 0; /* Explicitly set to primary bssidx */
+
+ if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) {
+ /* STA interface is not associated. So start the new interface on a temp
+ * channel . Later proper channel will be applied by the above framework
+ * via set_channel (cfg80211 API).
+ */
+ WL_DBG(("Not associated. Return a temp channel. \n"));
+ return wl_ch_host_to_driver(cfg->wdev, bssidx, WL_P2P_TEMP_CHAN);
+ }
+
+
+ *(u32 *) cfg->extra_buf = htod32(WL_EXTRA_BUF_MAX);
+ if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, cfg->extra_buf,
+ WL_EXTRA_BUF_MAX, false))) {
+ WL_ERR(("Failed to get associated bss info, use temp channel \n"));
+ chspec = wl_ch_host_to_driver(cfg->wdev, bssidx, WL_P2P_TEMP_CHAN);
+ }
+ else {
+ bss = (struct wl_bss_info *) (cfg->extra_buf + 4);
+ chspec = bss->chanspec;
+
+ WL_DBG(("Valid BSS Found. chanspec:%d \n", chspec));
+ }
+ return chspec;
+}
+
+static bcm_struct_cfgdev *
+wl_cfg80211_add_monitor_if(char *name)
+{
+#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF)
+ WL_INFORM(("wl_cfg80211_add_monitor_if: No more support monitor interface\n"));
+ return ERR_PTR(-EOPNOTSUPP);
+#else
+ struct net_device* ndev = NULL;
+
+ dhd_add_monitor(name, &ndev);
+ WL_INFORM(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
+ return ndev_to_cfgdev(ndev);
+#endif /* WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF */
+}
+
+static bcm_struct_cfgdev *
+wl_cfg80211_add_virtual_iface(struct wiphy *wiphy,
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ const char *name,
+#else
+ char *name,
+#endif /* WL_CFG80211_P2P_DEV_IF */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
+ unsigned char name_assign_type,
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) */
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ s32 err = -ENODEV;
+ s32 timeout = -1;
+ s32 wlif_type = -1;
+ s32 mode = 0;
+ s32 val = 0;
+ s32 cfg_type;
+ s32 dhd_mode = 0;
+ s32 is_mp2p_supported = BCME_ERROR;
+ /* @TODO need to refine the usage of this flag based on firmware limitations of MP2P */
+ chanspec_t chspec;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *primary_ndev;
+ struct net_device *new_ndev;
+ struct ether_addr primary_mac;
+#ifdef WL_VIRTUAL_APSTA
+ bcm_struct_cfgdev *new_cfgdev;
+#endif /* WL_VIRTUAL_APSTA */
+#ifdef PROP_TXSTATUS_VSDB
+#if defined(BCMSDIO)
+ s32 up = 1;
+ dhd_pub_t *dhd;
+ bool enabled;
+#endif
+#endif /* PROP_TXSTATUS_VSDB */
+#if defined(SUPPORT_AP_POWERSAVE)
+ dhd_pub_t *dhd;
+#endif /* SUPPORT_AP_POWERSAVE */
+ bool hang_required = false;
+
+ if (!cfg)
+ return ERR_PTR(-EINVAL);
+
+#ifdef PROP_TXSTATUS_VSDB
+#if defined(BCMSDIO)
+ dhd = (dhd_pub_t *)(cfg->pub);
+#endif
+#endif /* PROP_TXSTATUS_VSDB */
+#if defined(SUPPORT_AP_POWERSAVE)
+ dhd = (dhd_pub_t *)(cfg->pub);
+#endif /* SUPPORT_AP_POWERSAVE */
+
+ /* Use primary I/F for sending cmds down to firmware */
+ primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+
+ is_mp2p_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_MP2P_MODE);
+
+
+ if (unlikely(!wl_get_drv_status(cfg, READY, primary_ndev))) {
+ WL_ERR(("device is not ready\n"));
+ return ERR_PTR(-ENODEV);
+ }
+
+ WL_DBG(("if name: %s, type: %d\n", name, type));
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+#ifdef WLAIBSS_MCHAN
+ return bcm_cfg80211_add_ibss_if(wiphy, (char *)name);
+#endif /* WLAIBSS_MCHAN */
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MESH_POINT:
+ WL_ERR(("Unsupported interface type\n"));
+ mode = WL_MODE_IBSS;
+ return NULL;
+ case NL80211_IFTYPE_MONITOR:
+ return wl_cfg80211_add_monitor_if((char *)name);
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ case NL80211_IFTYPE_P2P_DEVICE:
+ cfg->down_disc_if = FALSE;
+ return wl_cfgp2p_add_p2p_disc_if(cfg);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ case NL80211_IFTYPE_STATION:
+#ifdef WL_VIRTUAL_APSTA
+#ifdef WLAIBSS_MCHAN
+ if (cfg->ibss_cfgdev) {
+ WL_ERR(("AIBSS is already operational. "
+ " AIBSS & DUALSTA can't be used together \n"));
+ return ERR_PTR(-ENOMEM);
+ }
+#endif /* WLAIBSS_MCHAN */
+ if (!name) {
+ WL_ERR(("Interface name not provided \n"));
+ return ERR_PTR(-ENODEV);
+ }
+
+ if (wl_cfgp2p_vif_created(cfg)) {
+ WL_ERR(("Could not create new iface."
+ "Already one p2p interface is running"));
+ return ERR_PTR(-ENODEV);
+ }
+ new_cfgdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
+ NL80211_IFTYPE_STATION, NULL, name);
+ if (!new_cfgdev)
+ return ERR_PTR(-ENOMEM);
+ else
+ return new_cfgdev;
+#endif /* WL_VIRTUAL_APSTA */
+ case NL80211_IFTYPE_P2P_CLIENT:
+ wlif_type = WL_P2P_IF_CLIENT;
+ mode = WL_MODE_BSS;
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_AP:
+ wlif_type = WL_P2P_IF_GO;
+ mode = WL_MODE_AP;
+ break;
+ default:
+ WL_ERR(("Unsupported interface type\n"));
+ return ERR_PTR(-ENODEV);
+ break;
+ }
+
+ if (!name) {
+ WL_ERR(("name is NULL\n"));
+ return ERR_PTR(-ENODEV);
+ }
+ if (cfg->p2p_supported && (wlif_type != -1)) {
+ ASSERT(cfg->p2p); /* ensure expectation of p2p initialization */
+
+#ifdef PROP_TXSTATUS_VSDB
+#if defined(BCMSDIO)
+ if (!dhd)
+ return ERR_PTR(-ENODEV);
+#endif
+#endif /* PROP_TXSTATUS_VSDB */
+ if (!cfg->p2p)
+ return ERR_PTR(-ENODEV);
+
+ if (cfg->p2p && !cfg->p2p->on && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
+ p2p_on(cfg) = true;
+ wl_cfgp2p_set_firm_p2p(cfg);
+ wl_cfgp2p_init_discovery(cfg);
+ get_primary_mac(cfg, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
+ }
+
+ strncpy(cfg->p2p->vir_ifname, name, IFNAMSIZ - 1);
+ cfg->p2p->vir_ifname[IFNAMSIZ - 1] = '\0';
+
+ wl_cfg80211_scan_abort(cfg);
+#ifdef PROP_TXSTATUS_VSDB
+#if defined(BCMSDIO)
+ if (!cfg->wlfc_on && !disable_proptx) {
+ dhd_wlfc_get_enable(dhd, &enabled);
+ if (!enabled && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
+ dhd->op_mode != DHD_FLAG_IBSS_MODE) {
+ dhd_wlfc_init(dhd);
+ err = wldev_ioctl(primary_ndev, WLC_UP, &up, sizeof(s32), true);
+ if (err < 0)
+ WL_ERR(("WLC_UP return err:%d\n", err));
+ }
+ cfg->wlfc_on = true;
+ }
+#endif
+#endif /* PROP_TXSTATUS_VSDB */
+
+ /* Dual p2p doesn't support multiple P2PGO interfaces,
+ * p2p_go_count is the counter for GO creation
+ * requests.
+ */
+ if (
+ (!is_mp2p_supported) &&
+ (cfg->p2p->p2p_go_count > 0) && (type == NL80211_IFTYPE_P2P_GO)) {
+
+ WL_ERR(("Fw doesnot support multiple Go"));
+ return ERR_PTR(-ENOMEM);
+ }
+ /* In concurrency case, STA may be already associated in a particular channel.
+ * so retrieve the current channel of primary interface and then start the virtual
+ * interface on that.
+ */
+ chspec = wl_cfg80211_get_shared_freq(wiphy);
+
+ /* For P2P mode, use P2P-specific driver features to create the
+ * bss: "cfg p2p_ifadd"
+ */
+ if (wl_check_dongle_idle(wiphy) != TRUE) {
+ WL_ERR(("FW is busy to add interface"));
+ return ERR_PTR(-ENOMEM);
+ }
+ wl_set_p2p_status(cfg, IF_ADDING);
+ memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
+ if (wlif_type == WL_P2P_IF_GO)
+ wldev_iovar_setint(primary_ndev, "mpc", 0);
+ cfg_type = wl_cfgp2p_get_conn_idx(cfg);
+ if (cfg_type == BCME_ERROR) {
+ wl_clr_p2p_status(cfg, IF_ADDING);
+ WL_ERR(("Failed to get connection idx for p2p interface"));
+ goto fail;
+ }
+ err = wl_cfgp2p_ifadd(cfg, wl_to_p2p_bss_macaddr(cfg, cfg_type),
+ htod32(wlif_type), chspec);
+ if (unlikely(err)) {
+ wl_clr_p2p_status(cfg, IF_ADDING);
+ WL_ERR((" virtual iface add failed (%d) \n", err));
+ return ERR_PTR(-ENOMEM);
+ }
+
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+ ((wl_get_p2p_status(cfg, IF_ADDING) == false) &&
+ (cfg->if_event_info.valid)),
+ msecs_to_jiffies(MAX_WAIT_TIME));
+
+ if (timeout > 0 && !wl_get_p2p_status(cfg, IF_ADDING) && cfg->if_event_info.valid) {
+ struct wireless_dev *vwdev;
+ int pm_mode = PM_ENABLE;
+ wl_if_event_info *event = &cfg->if_event_info;
+ /* IF_ADD event has come back, we can proceed to to register
+ * the new interface now, use the interface name provided by caller (thus
+ * ignore the one from wlc)
+ */
+ new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, cfg->p2p->vir_ifname,
+ event->mac, event->bssidx, event->name);
+ if (new_ndev == NULL)
+ goto fail;
+
+ wl_to_p2p_bss_ndev(cfg, cfg_type) = new_ndev;
+ wl_to_p2p_bss_bssidx(cfg, cfg_type) = event->bssidx;
+ vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
+ if (unlikely(!vwdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ err = -ENOMEM;
+ goto fail;
+ }
+ vwdev->wiphy = cfg->wdev->wiphy;
+ WL_INFORM(("virtual interface(%s) is created\n", cfg->p2p->vir_ifname));
+ if (type == NL80211_IFTYPE_P2P_GO) {
+ cfg->p2p->p2p_go_count++;
+ }
+ vwdev->iftype = type;
+#ifdef DHD_IFDEBUG
+ WL_ERR(("new_ndev: %p\n", new_ndev));
+#endif
+ vwdev->netdev = new_ndev;
+ new_ndev->ieee80211_ptr = vwdev;
+ SET_NETDEV_DEV(new_ndev, wiphy_dev(vwdev->wiphy));
+ wl_set_drv_status(cfg, READY, new_ndev);
+ wl_set_mode_by_netdev(cfg, new_ndev, mode);
+
+ if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) {
+ wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev);
+ err = -ENODEV;
+ goto fail;
+ }
+ err = wl_alloc_netinfo(cfg, new_ndev, vwdev, mode, pm_mode, event->bssidx);
+ if (unlikely(err != 0)) {
+ WL_ERR(("Allocation of netinfo failed (%d) \n", err));
+ goto fail;
+ }
+ val = 1;
+ /* Disable firmware roaming for P2P interface */
+ wldev_iovar_setint(new_ndev, "roam_off", val);
+#ifdef WL11ULB
+ if (cfg->p2p_wdev && is_p2p_group_iface(new_ndev->ieee80211_ptr)) {
+ u32 ulb_bw = wl_cfg80211_get_ulb_bw(cfg->p2p_wdev);
+ if (ulb_bw) {
+ /* Apply ULB BW settings on the newly spawned interface */
+ WL_DBG(("[ULB] Applying ULB BW for the newly"
+ "created P2P interface \n"));
+ if (wl_cfg80211_set_ulb_bw(new_ndev,
+ ulb_bw, new_ndev->name) < 0) {
+ /*
+ * If ulb_bw set failed, fail the iface creation.
+ * wl_dealloc_netinfo_by_wdev will be called by the
+ * unregister notifier.
+ */
+ wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev);
+ err = -EINVAL;
+ goto fail;
+ }
+ }
+ }
+#endif /* WL11ULB */
+
+ if (mode != WL_MODE_AP)
+ wldev_iovar_setint(new_ndev, "buf_key_b4_m4", 1);
+
+ WL_ERR((" virtual interface(%s) is "
+ "created net attach done\n", cfg->p2p->vir_ifname));
+ if (mode == WL_MODE_AP)
+ wl_set_drv_status(cfg, CONNECTED, new_ndev);
+#ifdef SUPPORT_AP_POWERSAVE
+ if (mode == WL_MODE_AP) {
+ dhd_set_ap_powersave(dhd, 0, TRUE);
+ }
+#endif /* SUPPORT_AP_POWERSAVE */
+ if (type == NL80211_IFTYPE_P2P_CLIENT)
+ dhd_mode = DHD_FLAG_P2P_GC_MODE;
+ else if (type == NL80211_IFTYPE_P2P_GO)
+ dhd_mode = DHD_FLAG_P2P_GO_MODE;
+ DNGL_FUNC(dhd_cfg80211_set_p2p_info, (cfg, dhd_mode));
+ /* reinitialize completion to clear previous count */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0))
+ INIT_COMPLETION(cfg->iface_disable);
+#else
+ init_completion(&cfg->iface_disable);
+#endif
+ return ndev_to_cfgdev(new_ndev);
+ } else {
+ wl_clr_p2p_status(cfg, IF_ADDING);
+ WL_ERR((" virtual interface(%s) is not created \n", cfg->p2p->vir_ifname));
+
+ WL_ERR(("left timeout : %d\n", timeout));
+ WL_ERR(("IF_ADDING status : %d\n", wl_get_p2p_status(cfg, IF_ADDING)));
+ WL_ERR(("event valid : %d\n", cfg->if_event_info.valid));
+
+ wl_clr_p2p_status(cfg, GO_NEG_PHASE);
+ wl_set_p2p_status(cfg, IF_DELETING);
+
+ err = wl_cfgp2p_ifdel(cfg, wl_to_p2p_bss_macaddr(cfg, cfg_type));
+ if (err == BCME_OK) {
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+ ((wl_get_p2p_status(cfg, IF_DELETING) == false) &&
+ (cfg->if_event_info.valid)),
+ msecs_to_jiffies(MAX_WAIT_TIME));
+ if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
+ cfg->if_event_info.valid) {
+ /*
+ * Should indicate upper layer this failure case of p2p
+ * interface creation
+ */
+ WL_ERR(("IFDEL operation done\n"));
+ } else {
+ WL_ERR(("IFDEL didn't complete properly\n"));
+ hang_required = true;
+ }
+ } else {
+ hang_required = true;
+ }
+
+ if (hang_required) {
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+
+ WL_ERR(("p2p_ifdel failed, error %d, sent HANG event to %s\n",
+ err, ndev->name));
+ dhd->hang_reason = HANG_REASON_P2P_IFACE_DEL_FAILURE;
+ net_os_send_hang_message(ndev);
+ }
+
+ memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ);
+ wl_to_p2p_bss_bssidx(cfg, cfg_type) = -1;
+#ifdef PROP_TXSTATUS_VSDB
+#if defined(BCMSDIO)
+ dhd_wlfc_get_enable(dhd, &enabled);
+ if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
+ dhd->op_mode != DHD_FLAG_IBSS_MODE) {
+ dhd_wlfc_deinit(dhd);
+ cfg->wlfc_on = false;
+ }
+#endif
+#endif /* PROP_TXSTATUS_VSDB */
+ /*
+ * Returns -ENODEV to upperlayer to indicate that DHD
+ * failed to create p2p interface
+ */
+ err = -ENODEV;
+ }
+ }
+fail:
+ if (wlif_type == WL_P2P_IF_GO)
+ wldev_iovar_setint(primary_ndev, "mpc", 1);
+ return ERR_PTR(err);
+}
+
+static s32
+wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
+{
+ struct net_device *dev = NULL;
+ struct ether_addr p2p_mac;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 timeout = -1;
+ s32 ret = 0;
+ s32 index = -1;
+ s32 type = -1;
+#ifdef CUSTOM_SET_CPUCORE
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+#endif /* CUSTOM_SET_CPUCORE */
+ WL_DBG(("Enter\n"));
+
+#ifdef CUSTOM_SET_CPUCORE
+ dhd->chan_isvht80 &= ~DHD_FLAG_P2P_MODE;
+ if (!(dhd->chan_isvht80))
+ dhd_set_cpucore(dhd, FALSE);
+#endif /* CUSTOM_SET_CPUCORE */
+#ifdef WL_CFG80211_P2P_DEV_IF
+ if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
+ if (dhd_download_fw_on_driverload) {
+ return wl_cfgp2p_del_p2p_disc_if(cfgdev, cfg);
+ } else {
+ cfg->down_disc_if = TRUE;
+ return 0;
+ }
+ }
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+#ifdef WLAIBSS_MCHAN
+ if (cfgdev == cfg->ibss_cfgdev)
+ return bcm_cfg80211_del_ibss_if(wiphy, cfgdev);
+#endif /* WLAIBSS_MCHAN */
+
+#ifdef WL_VIRTUAL_APSTA
+ if (cfgdev_to_wdev(cfgdev)->iftype == NL80211_IFTYPE_AP) {
+ return wl_cfg80211_del_iface(wiphy, cfgdev);
+ }
+#endif /* WL_VIRTUAL_APSTA */
+ if ((index = wl_get_bssidx_by_wdev(cfg, cfgdev_to_wdev(cfgdev))) < 0) {
+ WL_ERR(("Find p2p index from wdev failed\n"));
+ return BCME_ERROR;
+ }
+ if (wl_check_dongle_idle(wiphy) != TRUE) {
+ WL_ERR(("FW is busy to add interface"));
+ return BCME_ERROR;
+ }
+ if (cfg->p2p_supported) {
+ if (wl_cfgp2p_find_type(cfg, index, &type) != BCME_OK)
+ return BCME_ERROR;
+ memcpy(p2p_mac.octet, wl_to_p2p_bss_macaddr(cfg, type).octet, ETHER_ADDR_LEN);
+
+ /* Clear GO_NEG_PHASE bit to take care of GO-NEG-FAIL cases
+ */
+ WL_DBG(("P2P: GO_NEG_PHASE status cleared "));
+ wl_clr_p2p_status(cfg, GO_NEG_PHASE);
+ if (wl_cfgp2p_vif_created(cfg)) {
+ if (wl_get_drv_status(cfg, SCANNING, dev)) {
+ wl_notify_escan_complete(cfg, dev, true, true);
+ }
+ wldev_iovar_setint(dev, "mpc", 1);
+ /* Delete pm_enable_work */
+ wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
+
+ /* for GC */
+ if (wl_get_drv_status(cfg, DISCONNECTING, dev) &&
+ (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP)) {
+ WL_ERR(("Wait for Link Down event for GC !\n"));
+ wait_for_completion_timeout
+ (&cfg->iface_disable, msecs_to_jiffies(500));
+ }
+
+ memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
+ wl_set_p2p_status(cfg, IF_DELETING);
+ DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (cfg));
+
+ /* for GO */
+ if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false);
+ cfg->p2p->p2p_go_count--;
+ /* disable interface before bsscfg free */
+ ret = wl_cfgp2p_ifdisable(cfg, &p2p_mac);
+ /* if fw doesn't support "ifdis",
+ do not wait for link down of ap mode
+ */
+ if (ret == 0) {
+ WL_ERR(("Wait for Link Down event for GO !!!\n"));
+ wait_for_completion_timeout(&cfg->iface_disable,
+ msecs_to_jiffies(500));
+ } else if (ret != BCME_UNSUPPORTED) {
+ msleep(300);
+ }
+ }
+ wl_cfg80211_clear_per_bss_ies(cfg, index);
+
+ if (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_AP)
+ wldev_iovar_setint(dev, "buf_key_b4_m4", 0);
+ memcpy(p2p_mac.octet, wl_to_p2p_bss_macaddr(cfg, type).octet,
+ ETHER_ADDR_LEN);
+ CFGP2P_INFO(("primary idx %d : cfg p2p_ifdis "MACDBG"\n",
+ dev->ifindex, MAC2STRDBG(p2p_mac.octet)));
+
+ /* delete interface after link down */
+ ret = wl_cfgp2p_ifdel(cfg, &p2p_mac);
+ if (ret != BCME_OK) {
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+
+ WL_ERR(("p2p_ifdel failed, error %d, sent HANG event to %s\n",
+ ret, ndev->name));
+ dhd->hang_reason = HANG_REASON_P2P_IFACE_DEL_FAILURE;
+ net_os_send_hang_message(ndev);
+ } else {
+ /* Wait for IF_DEL operation to be finished */
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+ ((wl_get_p2p_status(cfg, IF_DELETING) == false) &&
+ (cfg->if_event_info.valid)),
+ msecs_to_jiffies(MAX_WAIT_TIME));
+ if (timeout > 0 && !wl_get_p2p_status(cfg, IF_DELETING) &&
+ cfg->if_event_info.valid) {
+
+ WL_DBG(("IFDEL operation done\n"));
+ wl_cfg80211_handle_ifdel(cfg, &cfg->if_event_info, dev);
+ } else {
+ WL_ERR(("IFDEL didn't complete properly\n"));
+ }
+ }
+
+ ret = dhd_del_monitor(dev);
+ if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
+ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL((dhd_pub_t *)(cfg->pub));
+ }
+ }
+ }
+ return ret;
+}
+
+static s32
+wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ s32 ap = 0;
+ s32 infra = 0;
+ s32 ibss = 0;
+ s32 wlif_type;
+ s32 mode = 0;
+ s32 err = BCME_OK;
+ s32 index;
+ s32 conn_idx = -1;
+ chanspec_t chspec;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+
+ WL_DBG(("Enter type %d\n", type));
+ switch (type) {
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_MESH_POINT:
+ ap = 1;
+ WL_ERR(("type (%d) : currently we do not support this type\n",
+ type));
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ mode = WL_MODE_IBSS;
+ ibss = 1;
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ mode = WL_MODE_BSS;
+ infra = 1;
+ break;
+ case NL80211_IFTYPE_AP:
+ dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
+ /* intentional fall through */
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_P2P_GO:
+ mode = WL_MODE_AP;
+ ap = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (!dhd)
+ return -EINVAL;
+
+ /* If any scan is going on, abort it */
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ int wait_cnt = MAX_SCAN_ABORT_WAIT_CNT;
+ WL_ERR(("Scan in progress. Aborting the scan!\n"));
+ wl_cfg80211_scan_abort(cfg);
+ while (wl_get_drv_status_all(cfg, SCANNING) && wait_cnt) {
+ WL_DBG(("Waiting for SCANNING terminated, wait_cnt: %d\n", wait_cnt));
+ wait_cnt--;
+ OSL_SLEEP(WAIT_SCAN_ABORT_OSL_SLEEP_TIME);
+ }
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
+ }
+ }
+
+ if (ap) {
+ wl_set_mode_by_netdev(cfg, ndev, mode);
+ if (is_p2p_group_iface(ndev->ieee80211_ptr) &&
+ cfg->p2p && wl_cfgp2p_vif_created(cfg)) {
+ WL_DBG(("p2p_vif_created p2p_on (%d)\n", p2p_on(cfg)));
+ if (wl_check_dongle_idle(wiphy) != TRUE) {
+ WL_ERR(("FW is busy to add interface"));
+ return -EINVAL;
+ }
+ wldev_iovar_setint(ndev, "mpc", 0);
+ wl_notify_escan_complete(cfg, ndev, true, true);
+
+ /* Dual p2p doesn't support multiple P2PGO interfaces,
+ * p2p_go_count is the counter for GO creation
+ * requests.
+ */
+ if ((cfg->p2p->p2p_go_count > 0) && (type == NL80211_IFTYPE_P2P_GO)) {
+ wl_set_mode_by_netdev(cfg, ndev, WL_MODE_BSS);
+ WL_ERR(("Fw doesnot support multiple GO "));
+ return BCME_ERROR;
+ }
+ /* In concurrency case, STA may be already associated in a particular
+ * channel. so retrieve the current channel of primary interface and
+ * then start the virtual interface on that.
+ */
+ chspec = wl_cfg80211_get_shared_freq(wiphy);
+ index = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
+ if (index < 0) {
+ WL_ERR(("Find p2p index from ndev(%p) failed\n", ndev));
+ return BCME_ERROR;
+ }
+ if (wl_cfgp2p_find_type(cfg, index, &conn_idx) != BCME_OK)
+ return BCME_ERROR;
+
+ wlif_type = WL_P2P_IF_GO;
+ WL_DBG(("%s : ap (%d), infra (%d), iftype (%d) conn_idx (%d)\n",
+ ndev->name, ap, infra, type, conn_idx));
+ wl_set_p2p_status(cfg, IF_CHANGING);
+ wl_clr_p2p_status(cfg, IF_CHANGED);
+ wl_cfgp2p_ifchange(cfg, wl_to_p2p_bss_macaddr(cfg, conn_idx),
+ htod32(wlif_type), chspec, conn_idx);
+ wait_event_interruptible_timeout(cfg->netif_change_event,
+ (wl_get_p2p_status(cfg, IF_CHANGED) == true),
+ msecs_to_jiffies(MAX_WAIT_TIME));
+ wl_set_mode_by_netdev(cfg, ndev, mode);
+ dhd->op_mode &= ~DHD_FLAG_P2P_GC_MODE;
+ dhd->op_mode |= DHD_FLAG_P2P_GO_MODE;
+ wl_clr_p2p_status(cfg, IF_CHANGING);
+ wl_clr_p2p_status(cfg, IF_CHANGED);
+ if (mode == WL_MODE_AP)
+ wl_set_drv_status(cfg, CONNECTED, ndev);
+#ifdef SUPPORT_AP_POWERSAVE
+ dhd_set_ap_powersave(dhd, 0, TRUE);
+#endif /* SUPPORT_AP_POWERSAVE */
+ } else if ((wl_get_netinfo_by_netdev(cfg, ndev) != NULL) &&
+ !wl_get_drv_status(cfg, AP_CREATED, ndev)) {
+ wl_set_drv_status(cfg, AP_CREATING, ndev);
+ } else {
+ WL_ERR(("Cannot change the interface for GO or SOFTAP\n"));
+ return -EINVAL;
+ }
+ } else {
+ /* P2P GO interface deletion is handled on the basis of role type (AP).
+ * So avoid changing role for p2p type.
+ */
+ if (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+ wl_set_mode_by_netdev(cfg, ndev, mode);
+ WL_DBG(("Change_virtual_iface for transition from GO/AP to client/STA"));
+#ifdef SUPPORT_AP_POWERSAVE
+ dhd_set_ap_powersave(dhd, 0, FALSE);
+#endif /* SUPPORT_AP_POWERSAVE */
+ }
+
+ if (ibss) {
+ infra = 0;
+ wl_set_mode_by_netdev(cfg, ndev, mode);
+ err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(s32), true);
+ if (err < 0) {
+ WL_ERR(("SET Adhoc error %d\n", err));
+ return -EINVAL;
+ }
+ }
+
+ ndev->ieee80211_ptr->iftype = type;
+ return 0;
+}
+
+s32
+wl_cfg80211_notify_ifadd(void *cfg80211_priv, int ifidx, char *name, uint8 *mac, uint8 bssidx)
+{
+ bool ifadd_expected = FALSE;
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)cfg80211_priv;
+
+ /* P2P may send WLC_E_IF_ADD and/or WLC_E_IF_CHANGE during IF updating ("p2p_ifupd")
+ * redirect the IF_ADD event to ifchange as it is not a real "new" interface
+ */
+ if (wl_get_p2p_status(cfg, IF_CHANGING))
+ return wl_cfg80211_notify_ifchange(cfg80211_priv, ifidx, name, mac, bssidx);
+
+ /* Okay, we are expecting IF_ADD (as IF_ADDING is true) */
+ if (wl_get_p2p_status(cfg, IF_ADDING)) {
+ ifadd_expected = TRUE;
+ wl_clr_p2p_status(cfg, IF_ADDING);
+ } else if (cfg->bss_pending_op) {
+ ifadd_expected = TRUE;
+ cfg->bss_pending_op = FALSE;
+ }
+
+ if (ifadd_expected) {
+ wl_if_event_info *if_event_info = &cfg->if_event_info;
+
+ if_event_info->valid = TRUE;
+ if_event_info->ifidx = ifidx;
+ if_event_info->bssidx = bssidx;
+ strncpy(if_event_info->name, name, IFNAMSIZ);
+ if_event_info->name[IFNAMSIZ] = '\0';
+ if (mac)
+ memcpy(if_event_info->mac, mac, ETHER_ADDR_LEN);
+ wake_up_interruptible(&cfg->netif_change_event);
+ return BCME_OK;
+ }
+
+ return BCME_ERROR;
+}
+
+s32
+wl_cfg80211_notify_ifdel(void *cfg80211_priv, int ifidx, char *name, uint8 *mac, uint8 bssidx)
+{
+ bool ifdel_expected = FALSE;
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)cfg80211_priv;
+ wl_if_event_info *if_event_info = &cfg->if_event_info;
+
+ if (wl_get_p2p_status(cfg, IF_DELETING)) {
+ ifdel_expected = TRUE;
+ wl_clr_p2p_status(cfg, IF_DELETING);
+ } else if (cfg->bss_pending_op) {
+ ifdel_expected = TRUE;
+ cfg->bss_pending_op = FALSE;
+ }
+
+ if (ifdel_expected) {
+ if_event_info->valid = TRUE;
+ if_event_info->ifidx = ifidx;
+ if_event_info->bssidx = bssidx;
+ wake_up_interruptible(&cfg->netif_change_event);
+ return BCME_OK;
+ }
+
+ return BCME_ERROR;
+}
+
+s32
+wl_cfg80211_notify_ifchange(void *cfg80211_priv, int ifidx, char *name, uint8 *mac, uint8 bssidx)
+{
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)cfg80211_priv;
+
+ if (wl_get_p2p_status(cfg, IF_CHANGING)) {
+ wl_set_p2p_status(cfg, IF_CHANGED);
+ wake_up_interruptible(&cfg->netif_change_event);
+ return BCME_OK;
+ }
+
+ return BCME_ERROR;
+}
+
+static s32 wl_cfg80211_handle_ifdel(struct bcm_cfg80211 *cfg, wl_if_event_info *if_event_info,
+ struct net_device* ndev)
+{
+ s32 type = -1;
+ s32 bssidx = -1;
+#ifdef PROP_TXSTATUS_VSDB
+#if defined(BCMSDIO)
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+ bool enabled;
+#endif
+#endif /* PROP_TXSTATUS_VSDB */
+
+ bssidx = if_event_info->bssidx;
+ if (bssidx != wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION1) &&
+ bssidx != wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION2)) {
+ WL_ERR(("got IF_DEL for if %d, not owned by cfg driver\n", bssidx));
+ return BCME_ERROR;
+ }
+
+ if (p2p_is_on(cfg) && wl_cfgp2p_vif_created(cfg)) {
+ if (cfg->scan_request && (cfg->escan_info.ndev == ndev)) {
+ /* Abort any pending scan requests */
+ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+ WL_DBG(("ESCAN COMPLETED\n"));
+ wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, false);
+ }
+
+ memset(cfg->p2p->vir_ifname, '\0', IFNAMSIZ);
+ if (wl_cfgp2p_find_type(cfg, bssidx, &type) == BCME_OK) {
+ /* Update P2P data */
+ wl_clr_drv_status(cfg, CONNECTED, wl_to_p2p_bss_ndev(cfg, type));
+ wl_to_p2p_bss_ndev(cfg, type) = NULL;
+ wl_to_p2p_bss_bssidx(cfg, type) = -1;
+ } else if (wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr) < 0) {
+ WL_ERR(("bssidx not known for the given ndev as per net_info data \n"));
+ return BCME_ERROR;
+ }
+
+#ifdef PROP_TXSTATUS_VSDB
+#if defined(BCMSDIO)
+ dhd_wlfc_get_enable(dhd, &enabled);
+ if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
+ dhd->op_mode != DHD_FLAG_IBSS_MODE) {
+ dhd_wlfc_deinit(dhd);
+ cfg->wlfc_on = false;
+ }
+#endif
+#endif /* PROP_TXSTATUS_VSDB */
+ }
+
+ dhd_net_if_lock(ndev);
+ wl_cfg80211_remove_if(cfg, if_event_info->ifidx, ndev);
+ dhd_net_if_unlock(ndev);
+
+ return BCME_OK;
+}
+
+/* Find listen channel */
+static s32 wl_find_listen_channel(struct bcm_cfg80211 *cfg,
+ const u8 *ie, u32 ie_len)
+{
+ wifi_p2p_ie_t *p2p_ie;
+ u8 *end, *pos;
+ s32 listen_channel;
+
+/* unfortunately const cast required here - function is
+ * a callback so its signature must not be changed
+ * and cascade of changing wl_cfgp2p_find_p2pie
+ * causes need for const cast in other places
+ */
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#endif
+ pos = (u8 *)ie;
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic pop")
+#endif
+ p2p_ie = wl_cfgp2p_find_p2pie(pos, ie_len);
+
+ if (p2p_ie == NULL)
+ return 0;
+
+ pos = p2p_ie->subelts;
+ end = p2p_ie->subelts + (p2p_ie->len - 4);
+
+ CFGP2P_DBG((" found p2p ie ! lenth %d \n",
+ p2p_ie->len));
+
+ while (pos < end) {
+ uint16 attr_len;
+ if (pos + 2 >= end) {
+ CFGP2P_DBG((" -- Invalid P2P attribute"));
+ return 0;
+ }
+ attr_len = ((uint16) (((pos + 1)[1] << 8) | (pos + 1)[0]));
+
+ if (pos + 3 + attr_len > end) {
+ CFGP2P_DBG(("P2P: Attribute underflow "
+ "(len=%u left=%d)",
+ attr_len, (int) (end - pos - 3)));
+ return 0;
+ }
+
+ /* if Listen Channel att id is 6 and the vailue is valid,
+ * return the listen channel
+ */
+ if (pos[0] == 6) {
+ /* listen channel subel length format
+ * 1(id) + 2(len) + 3(country) + 1(op. class) + 1(chan num)
+ */
+ listen_channel = pos[1 + 2 + 3 + 1];
+
+ if (listen_channel == SOCIAL_CHAN_1 ||
+ listen_channel == SOCIAL_CHAN_2 ||
+ listen_channel == SOCIAL_CHAN_3) {
+ CFGP2P_DBG((" Found my Listen Channel %d \n", listen_channel));
+ return listen_channel;
+ }
+ }
+ pos += 3 + attr_len;
+ }
+ return 0;
+}
+
+static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request)
+{
+ u32 n_ssids;
+ u32 n_channels;
+ u16 channel;
+ chanspec_t chanspec;
+ s32 i = 0, j = 0, offset;
+ char *ptr;
+ wlc_ssid_t ssid;
+ struct bcm_cfg80211 *cfg = NULL;
+ struct wireless_dev *wdev;
+
+ memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
+ params->bss_type = DOT11_BSSTYPE_ANY;
+ params->scan_type = 0;
+ params->nprobes = -1;
+ params->active_time = -1;
+ params->passive_time = -1;
+ params->home_time = -1;
+ params->channel_num = 0;
+ memset(&params->ssid, 0, sizeof(wlc_ssid_t));
+
+ WL_SCAN(("Preparing Scan request\n"));
+ WL_SCAN(("nprobes=%d\n", params->nprobes));
+ WL_SCAN(("active_time=%d\n", params->active_time));
+ WL_SCAN(("passive_time=%d\n", params->passive_time));
+ WL_SCAN(("home_time=%d\n", params->home_time));
+ WL_SCAN(("scan_type=%d\n", params->scan_type));
+
+ params->nprobes = htod32(params->nprobes);
+ params->active_time = htod32(params->active_time);
+ params->passive_time = htod32(params->passive_time);
+ params->home_time = htod32(params->home_time);
+
+ /* if request is null just exit so it will be all channel broadcast scan */
+ if (!request)
+ return;
+
+ n_ssids = request->n_ssids;
+ n_channels = request->n_channels;
+
+ /* Copy channel array if applicable */
+ WL_SCAN(("### List of channelspecs to scan ###\n"));
+ if (n_channels > 0) {
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ wdev = request->wdev;
+#else
+ wdev = request->dev->ieee80211_ptr;
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ cfg = WDEV_GET_CFG80211_PRIV(wdev);
+ for (i = 0; i < n_channels; i++) {
+ chanspec = 0;
+ channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq);
+ /* SKIP DFS channels for Secondary interface */
+ if ((cfg->escan_info.ndev != bcmcfg_to_prmry_ndev(cfg)) &&
+ (request->channels[i]->flags &
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
+ (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_PASSIVE_SCAN)))
+#else
+ (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR)))
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0) */
+ continue;
+
+ chanspec = wl_cfg80211_ulb_get_min_bw_chspec(wdev, -1);
+ if (chanspec == INVCHANSPEC) {
+ WL_ERR(("Invalid chanspec! Skipping channel\n"));
+ continue;
+ }
+
+ if (request->channels[i]->band == IEEE80211_BAND_2GHZ) {
+ chanspec |= WL_CHANSPEC_BAND_2G;
+ } else {
+ chanspec |= WL_CHANSPEC_BAND_5G;
+ }
+ params->channel_list[j] = channel;
+ params->channel_list[j] &= WL_CHANSPEC_CHAN_MASK;
+ params->channel_list[j] |= chanspec;
+ WL_SCAN(("Chan : %d, Channel spec: %x \n",
+ channel, params->channel_list[j]));
+ params->channel_list[j] = wl_chspec_host_to_driver(params->channel_list[j]);
+ j++;
+ }
+ } else {
+ WL_SCAN(("Scanning all channels\n"));
+ }
+ n_channels = j;
+ /* Copy ssid array if applicable */
+ WL_SCAN(("### List of SSIDs to scan ###\n"));
+ if (n_ssids > 0) {
+ offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16);
+ offset = roundup(offset, sizeof(u32));
+ ptr = (char*)params + offset;
+ for (i = 0; i < n_ssids; i++) {
+ memset(&ssid, 0, sizeof(wlc_ssid_t));
+ ssid.SSID_len = MIN(request->ssids[i].ssid_len, DOT11_MAX_SSID_LEN);
+ memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len);
+ if (!ssid.SSID_len)
+ WL_SCAN(("%d: Broadcast scan\n", i));
+ else
+ WL_SCAN(("%d: scan for %s size =%d\n", i,
+ ssid.SSID, ssid.SSID_len));
+ memcpy(ptr, &ssid, sizeof(wlc_ssid_t));
+ ptr += sizeof(wlc_ssid_t);
+ }
+ } else {
+ WL_SCAN(("Broadcast scan\n"));
+ }
+ /* Adding mask to channel numbers */
+ params->channel_num =
+ htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) |
+ (n_channels & WL_SCAN_PARAMS_COUNT_MASK));
+
+ if (n_channels == 1) {
+ params->active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS);
+ params->nprobes = htod32(params->active_time / WL_SCAN_JOIN_PROBE_INTERVAL_MS);
+ }
+}
+
+static s32
+wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size)
+{
+ wl_uint32_list_t *list;
+ s32 err = BCME_OK;
+ if (valid_chan_list == NULL || size <= 0)
+ return -ENOMEM;
+
+ memset(valid_chan_list, 0, size);
+ list = (wl_uint32_list_t *)(void *) valid_chan_list;
+ list->count = htod32(WL_NUMCHANNELS);
+ err = wldev_ioctl(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size, false);
+ if (err != 0) {
+ WL_ERR(("get channels failed with %d\n", err));
+ }
+
+ return err;
+}
+
+#if defined(USE_INITIAL_SHORT_DWELL_TIME)
+#define FIRST_SCAN_ACTIVE_DWELL_TIME_MS 40
+bool g_first_broadcast_scan = TRUE;
+#endif
+
+static s32
+wl_run_escan(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ struct cfg80211_scan_request *request, uint16 action)
+{
+ s32 err = BCME_OK;
+ u32 n_channels;
+ u32 n_ssids;
+ s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params));
+ wl_escan_params_t *params = NULL;
+ u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)];
+ u32 num_chans = 0;
+ s32 channel;
+ u32 n_valid_chan;
+ s32 search_state = WL_P2P_DISC_ST_SCAN;
+ u32 i, j, n_nodfs = 0;
+ u16 *default_chan_list = NULL;
+ wl_uint32_list_t *list;
+ s32 bssidx = -1;
+ struct net_device *dev = NULL;
+#if defined(USE_INITIAL_SHORT_DWELL_TIME)
+ bool is_first_init_2g_scan = false;
+#endif
+ p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_PURPOSE_MIN;
+
+ WL_DBG(("Enter \n"));
+
+ /* scan request can come with empty request : perform all default scan */
+ if (!cfg) {
+ err = -EINVAL;
+ goto exit;
+ }
+ if (!cfg->p2p_supported || !p2p_scan(cfg)) {
+ /* LEGACY SCAN TRIGGER */
+ WL_ERR((" LEGACY E-SCAN START\n"));
+
+#if defined(USE_INITIAL_SHORT_DWELL_TIME)
+ if (!request) {
+ err = -EINVAL;
+ goto exit;
+ }
+ if (ndev == bcmcfg_to_prmry_ndev(cfg) && g_first_broadcast_scan == true) {
+ is_first_init_2g_scan = true;
+ g_first_broadcast_scan = false;
+ }
+#endif
+
+ /* if scan request is not empty parse scan request paramters */
+ if (request != NULL) {
+ n_channels = request->n_channels;
+ n_ssids = request->n_ssids;
+ if (n_channels % 2)
+ /* If n_channels is odd, add a padd of u16 */
+ params_size += sizeof(u16) * (n_channels + 1);
+ else
+ params_size += sizeof(u16) * n_channels;
+
+ /* Allocate space for populating ssids in wl_escan_params_t struct */
+ params_size += sizeof(struct wlc_ssid) * n_ssids;
+ }
+ params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL);
+ if (params == NULL) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ wl_scan_prep(&params->params, request);
+
+#if defined(USE_INITIAL_SHORT_DWELL_TIME)
+ /* Override active_time to reduce scan time if it's first bradcast scan. */
+ if (is_first_init_2g_scan)
+ params->params.active_time = FIRST_SCAN_ACTIVE_DWELL_TIME_MS;
+#endif
+
+ params->version = htod32(ESCAN_REQ_VERSION);
+ params->action = htod16(action);
+ wl_escan_set_sync_id(params->sync_id, cfg);
+ wl_escan_set_type(cfg, WL_SCANTYPE_LEGACY);
+ if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) {
+ WL_ERR(("ioctl buffer length not sufficient\n"));
+ kfree(params);
+ err = -ENOMEM;
+ goto exit;
+ }
+ if (cfg->active_scan == PASSIVE_SCAN) {
+ params->params.scan_type = DOT11_SCANTYPE_PASSIVE;
+ WL_DBG(("Passive scan_type %d \n", params->params.scan_type));
+ }
+
+ bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
+
+ err = wldev_iovar_setbuf(ndev, "escan", params, params_size,
+ cfg->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
+ WL_ERR(("LEGACY_SCAN sync ID: %d, bssidx: %d\n", params->sync_id, bssidx));
+ if (unlikely(err)) {
+ if (err == BCME_EPERM)
+ /* Scan Not permitted at this point of time */
+ WL_DBG((" Escan not permitted at this time (%d)\n", err));
+ else
+ WL_ERR((" Escan set error (%d)\n", err));
+ }
+ kfree(params);
+ }
+ else if (p2p_is_on(cfg) && p2p_scan(cfg)) {
+ /* P2P SCAN TRIGGER */
+ s32 _freq = 0;
+ n_nodfs = 0;
+ if (request && request->n_channels) {
+ num_chans = request->n_channels;
+ WL_ERR((" chann number : %d\n", num_chans));
+ default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list),
+ GFP_KERNEL);
+ if (default_chan_list == NULL) {
+ WL_ERR(("channel list allocation failed \n"));
+ err = -ENOMEM;
+ goto exit;
+ }
+ if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) {
+#ifdef P2P_SKIP_DFS
+ int is_printed = false;
+#endif /* P2P_SKIP_DFS */
+ list = (wl_uint32_list_t *) chan_buf;
+ n_valid_chan = dtoh32(list->count);
+ if (n_valid_chan > WL_NUMCHANNELS) {
+ WL_ERR(("wrong n_valid_chan:%d.\n", n_valid_chan));
+ kfree(default_chan_list);
+ err = -EINVAL;
+ goto exit;
+ }
+
+ for (i = 0; i < num_chans; i++)
+ {
+ _freq = request->channels[i]->center_freq;
+ channel = ieee80211_frequency_to_channel(_freq);
+
+ /* ignore DFS channels */
+ if (request->channels[i]->flags &
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+ (IEEE80211_CHAN_NO_IR
+ | IEEE80211_CHAN_RADAR))
+#else
+ (IEEE80211_CHAN_RADAR
+ | IEEE80211_CHAN_PASSIVE_SCAN))
+#endif
+ continue;
+#ifdef P2P_SKIP_DFS
+ if (channel >= 52 && channel <= 144) {
+ if (is_printed == false) {
+ WL_ERR(("SKIP DFS CHANs(52~144)\n"));
+ is_printed = true;
+ }
+ continue;
+ }
+#endif /* P2P_SKIP_DFS */
+
+ for (j = 0; j < n_valid_chan; j++) {
+ /* allows only supported channel on
+ * current reguatory
+ */
+ if (channel == (dtoh32(list->element[j]))) {
+ default_chan_list[n_nodfs++] =
+ channel;
+ break;
+ }
+ }
+
+ }
+ }
+ if (num_chans == SOCIAL_CHAN_CNT && (
+ (default_chan_list[0] == SOCIAL_CHAN_1) &&
+ (default_chan_list[1] == SOCIAL_CHAN_2) &&
+ (default_chan_list[2] == SOCIAL_CHAN_3))) {
+ /* SOCIAL CHANNELS 1, 6, 11 */
+ search_state = WL_P2P_DISC_ST_SEARCH;
+ p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL;
+ WL_INFORM(("P2P SEARCH PHASE START \n"));
+ } else if (((dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1)) &&
+ (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) ||
+ ((dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION2)) &&
+ (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP))) {
+ /* If you are already a GO, then do SEARCH only */
+ WL_INFORM(("Already a GO. Do SEARCH Only"));
+ search_state = WL_P2P_DISC_ST_SEARCH;
+ num_chans = n_nodfs;
+ p2p_scan_purpose = P2P_SCAN_NORMAL;
+
+ } else if (num_chans == 1) {
+ p2p_scan_purpose = P2P_SCAN_CONNECT_TRY;
+ } else if (num_chans == SOCIAL_CHAN_CNT + 1) {
+ /* SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan supported by
+ * the supplicant
+ */
+ p2p_scan_purpose = P2P_SCAN_SOCIAL_CHANNEL;
+ } else {
+ WL_INFORM(("P2P SCAN STATE START \n"));
+ num_chans = n_nodfs;
+ p2p_scan_purpose = P2P_SCAN_NORMAL;
+ }
+ } else {
+ err = -EINVAL;
+ goto exit;
+ }
+ err = wl_cfgp2p_escan(cfg, ndev, ACTIVE_SCAN, num_chans, default_chan_list,
+ search_state, action,
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE), NULL,
+ p2p_scan_purpose);
+
+ if (!err)
+ cfg->p2p->search_state = search_state;
+
+ kfree(default_chan_list);
+ }
+exit:
+ if (unlikely(err)) {
+ /* Don't print Error incase of Scan suppress */
+ if ((err == BCME_EPERM) && cfg->scan_suppressed)
+ WL_DBG(("Escan failed: Scan Suppressed \n"));
+ else
+ WL_ERR(("error (%d)\n", err));
+ }
+ return err;
+}
+
+
+static s32
+wl_do_escan(struct bcm_cfg80211 *cfg, struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request)
+{
+ s32 err = BCME_OK;
+ s32 passive_scan;
+ s32 passive_scan_time;
+ s32 passive_scan_time_org;
+ wl_scan_results_t *results;
+ WL_SCAN(("Enter \n"));
+
+ results = wl_escan_get_buf(cfg, FALSE);
+ results->version = 0;
+ results->count = 0;
+ results->buflen = WL_SCAN_RESULTS_FIXED_SIZE;
+
+ cfg->escan_info.ndev = ndev;
+ cfg->escan_info.wiphy = wiphy;
+ cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANING;
+ passive_scan = cfg->active_scan ? 0 : 1;
+ err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
+ &passive_scan, sizeof(passive_scan), true);
+ if (unlikely(err)) {
+ WL_ERR(("error (%d)\n", err));
+ goto exit;
+ }
+
+ if (passive_channel_skip) {
+
+ err = wldev_ioctl(ndev, WLC_GET_SCAN_PASSIVE_TIME,
+ &passive_scan_time_org, sizeof(passive_scan_time_org), false);
+ if (unlikely(err)) {
+ WL_ERR(("== error (%d)\n", err));
+ goto exit;
+ }
+
+ WL_SCAN(("PASSIVE SCAN time : %d \n", passive_scan_time_org));
+
+ passive_scan_time = 0;
+ err = wldev_ioctl(ndev, WLC_SET_SCAN_PASSIVE_TIME,
+ &passive_scan_time, sizeof(passive_scan_time), true);
+ if (unlikely(err)) {
+ WL_ERR(("== error (%d)\n", err));
+ goto exit;
+ }
+
+ WL_SCAN(("PASSIVE SCAN SKIPED!! (passive_channel_skip:%d) \n",
+ passive_channel_skip));
+ }
+
+ err = wl_run_escan(cfg, ndev, request, WL_SCAN_ACTION_START);
+
+ if (passive_channel_skip) {
+ err = wldev_ioctl(ndev, WLC_SET_SCAN_PASSIVE_TIME,
+ &passive_scan_time_org, sizeof(passive_scan_time_org), true);
+ if (unlikely(err)) {
+ WL_ERR(("== error (%d)\n", err));
+ goto exit;
+ }
+
+ WL_SCAN(("PASSIVE SCAN RECOVERED!! (passive_scan_time_org:%d) \n",
+ passive_scan_time_org));
+ }
+
+exit:
+ return err;
+}
+
+static s32
+__wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request,
+ struct cfg80211_ssid *this_ssid)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct cfg80211_ssid *ssids;
+ struct ether_addr primary_mac;
+ bool p2p_ssid;
+#ifdef WL11U
+ bcm_tlv_t *interworking_ie;
+ u32 iw_ie_len = 0;
+ u8 iw_ie[IW_IES_MAX_BUF_LEN];
+#endif
+ s32 err = 0;
+ s32 bssidx = -1;
+ s32 i;
+
+ unsigned long flags;
+ static s32 busy_count = 0;
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ struct net_device *remain_on_channel_ndev = NULL;
+#endif
+ uint scan_timer_interval_ms = WL_SCAN_TIMER_INTERVAL_MS;
+
+ /*
+ * Hostapd triggers scan before starting automatic channel selection
+ * to collect channel characteristics. However firmware scan engine
+ * doesn't support any channel characteristics collection along with
+ * scan. Hence return scan success.
+ */
+ if (request && (scan_req_iftype(request) == NL80211_IFTYPE_AP)) {
+ WL_INFORM(("Scan Command on SoftAP Interface. Ignoring...\n"));
+ return 0;
+ }
+
+ ndev = ndev_to_wlc_ndev(ndev, cfg);
+
+ if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
+ WL_ERR(("Sending Action Frames. Try it again.\n"));
+ return -EAGAIN;
+ }
+
+ WL_DBG(("Enter wiphy (%p)\n", wiphy));
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ if (cfg->scan_request == NULL) {
+ wl_clr_drv_status_all(cfg, SCANNING);
+ WL_DBG(("<<<<<<<<<<<Force Clear Scanning Status>>>>>>>>>>>\n"));
+ } else {
+ WL_ERR(("Scanning already\n"));
+ return -EAGAIN;
+ }
+ }
+ if (wl_get_drv_status(cfg, SCAN_ABORTING, ndev)) {
+ WL_ERR(("Scanning being aborted\n"));
+ return -EAGAIN;
+ }
+ if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) {
+ WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
+ return -EOPNOTSUPP;
+ }
+
+#ifdef P2P_LISTEN_OFFLOADING
+ if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
+ WL_ERR(("P2P_FIND: Discovery offload is in progress\n"));
+ return -EAGAIN;
+ }
+#endif /* P2P_LISTEN_OFFLOADING */
+
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ remain_on_channel_ndev = wl_cfg80211_get_remain_on_channel_ndev(cfg);
+ if (remain_on_channel_ndev) {
+ WL_DBG(("Remain_on_channel bit is set, somehow it didn't get cleared\n"));
+ wl_notify_escan_complete(cfg, remain_on_channel_ndev, true, true);
+ }
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+
+
+ /* Arm scan timeout timer */
+ mod_timer(&cfg->scan_timeout, jiffies + msecs_to_jiffies(scan_timer_interval_ms));
+ if (request) { /* scan bss */
+ ssids = request->ssids;
+ p2p_ssid = false;
+ for (i = 0; i < request->n_ssids; i++) {
+ if (ssids[i].ssid_len &&
+ IS_P2P_SSID(ssids[i].ssid, ssids[i].ssid_len)) {
+ p2p_ssid = true;
+ break;
+ }
+ }
+ if (p2p_ssid) {
+ if (cfg->p2p_supported) {
+ /* p2p scan trigger */
+ if (p2p_on(cfg) == false) {
+ /* p2p on at the first time */
+ p2p_on(cfg) = true;
+ wl_cfgp2p_set_firm_p2p(cfg);
+ get_primary_mac(cfg, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
+#if defined(P2P_IE_MISSING_FIX)
+ cfg->p2p_prb_noti = false;
+#endif
+ }
+ wl_clr_p2p_status(cfg, GO_NEG_PHASE);
+ WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
+ p2p_scan(cfg) = true;
+ }
+ } else {
+ /* legacy scan trigger
+ * So, we have to disable p2p discovery if p2p discovery is on
+ */
+ if (cfg->p2p_supported) {
+ p2p_scan(cfg) = false;
+ /* If Netdevice is not equals to primary and p2p is on
+ * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE.
+ */
+
+ if (p2p_scan(cfg) == false) {
+ if (wl_get_p2p_status(cfg, DISCOVERY_ON)) {
+ err = wl_cfgp2p_discover_enable_search(cfg,
+ false);
+ if (unlikely(err)) {
+ goto scan_out;
+ }
+
+ }
+ }
+ }
+ if (!cfg->p2p_supported || !p2p_scan(cfg)) {
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg,
+ ndev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from ndev(%p) failed\n",
+ ndev));
+ err = BCME_ERROR;
+ goto scan_out;
+ }
+#ifdef WL11U
+ wl_get_iwdata_by_netdev(cfg, ndev, iw_ie, &iw_ie_len);
+ if ((interworking_ie = wl_cfg80211_find_interworking_ie(
+ (u8 *)request->ie, request->ie_len)) != NULL) {
+ err = wl_cfg80211_add_iw_ie(cfg, ndev, bssidx,
+ VNDR_IE_CUSTOM_FLAG, interworking_ie->id,
+ interworking_ie->data, interworking_ie->len);
+
+ if (unlikely(err)) {
+ WL_ERR(("Failed to add interworking IE"));
+ }
+ } else if (iw_ie_len != 0) {
+ /* we have to clear IW IE and disable gratuitous APR */
+ wl_cfg80211_add_iw_ie(cfg, ndev, bssidx,
+ VNDR_IE_CUSTOM_FLAG,
+ DOT11_MNG_INTERWORKING_ID,
+ 0, 0);
+
+ (void)wldev_iovar_setint_bsscfg(ndev, "grat_arp", 0,
+ bssidx);
+ wl_clear_iwdata_by_netdev(cfg, ndev);
+ /* we don't care about error */
+ }
+#endif /* WL11U */
+ err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(ndev),
+ bssidx, VNDR_IE_PRBREQ_FLAG, request->ie,
+ request->ie_len);
+
+ if (unlikely(err)) {
+ goto scan_out;
+ }
+
+ }
+ }
+ } else { /* scan in ibss */
+ ssids = this_ssid;
+ }
+
+ if (request && cfg->p2p_supported && !p2p_scan(cfg)) {
+ WL_TRACE_HW4(("START SCAN\n"));
+ DHD_OS_SCAN_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub),
+ SCAN_WAKE_LOCK_TIMEOUT);
+ DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)(cfg->pub));
+ }
+
+ if (cfg->p2p_supported) {
+ if (p2p_on(cfg) && p2p_scan(cfg)) {
+
+ /* find my listen channel */
+ cfg->afx_hdl->my_listen_chan =
+ wl_find_listen_channel(cfg, request->ie,
+ request->ie_len);
+ err = wl_cfgp2p_enable_discovery(cfg, ndev,
+ request->ie, request->ie_len);
+
+ if (unlikely(err)) {
+ goto scan_out;
+ }
+ }
+ }
+ err = wl_do_escan(cfg, wiphy, ndev, request);
+ if (likely(!err))
+ goto scan_success;
+ else
+ goto scan_out;
+
+scan_success:
+ busy_count = 0;
+ cfg->scan_request = request;
+ wl_set_drv_status(cfg, SCANNING, ndev);
+
+ return 0;
+
+scan_out:
+ if (err == BCME_BUSY || err == BCME_NOTREADY) {
+ WL_ERR(("Scan err = (%d), busy?%d", err, -EBUSY));
+ err = -EBUSY;
+ } else if ((err == BCME_EPERM) && cfg->scan_suppressed) {
+ WL_ERR(("Scan not permitted due to scan suppress\n"));
+ err = -EPERM;
+ } else {
+ /* For all other fw errors, use a generic error code as return
+ * value to cfg80211 stack
+ */
+ err = -EAGAIN;
+ }
+
+#define SCAN_EBUSY_RETRY_LIMIT 20
+ if (err == -EBUSY) {
+ if (busy_count++ > SCAN_EBUSY_RETRY_LIMIT) {
+ struct ether_addr bssid;
+ s32 ret = 0;
+#if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
+#endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
+ busy_count = 0;
+ WL_ERR(("Unusual continuous EBUSY error, %d %d %d %d %d %d %d %d %d\n",
+ wl_get_drv_status(cfg, SCANNING, ndev),
+ wl_get_drv_status(cfg, SCAN_ABORTING, ndev),
+ wl_get_drv_status(cfg, CONNECTING, ndev),
+ wl_get_drv_status(cfg, CONNECTED, ndev),
+ wl_get_drv_status(cfg, DISCONNECTING, ndev),
+ wl_get_drv_status(cfg, AP_CREATING, ndev),
+ wl_get_drv_status(cfg, AP_CREATED, ndev),
+ wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev),
+ wl_get_drv_status(cfg, SENDING_ACT_FRM, ndev)));
+
+#if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
+ if (dhdp->memdump_enabled) {
+ dhdp->memdump_type = DUMP_TYPE_SCAN_BUSY;
+ dhd_bus_mem_dump(dhdp);
+ }
+#endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
+
+ bzero(&bssid, sizeof(bssid));
+ if ((ret = wldev_ioctl(ndev, WLC_GET_BSSID,
+ &bssid, ETHER_ADDR_LEN, false)) == 0)
+ WL_ERR(("FW is connected with " MACDBG "/n",
+ MAC2STRDBG(bssid.octet)));
+ else
+ WL_ERR(("GET BSSID failed with %d\n", ret));
+
+ wl_cfg80211_scan_abort(cfg);
+
+ } else {
+ /* Hold the context for 400msec, so that 10 subsequent scans
+ * can give a buffer of 4sec which is enough to
+ * cover any on-going scan in the firmware
+ */
+ WL_DBG(("Enforcing delay for EBUSY case \n"));
+ msleep(500);
+ }
+ } else {
+ busy_count = 0;
+ }
+
+ wl_clr_drv_status(cfg, SCANNING, ndev);
+ if (timer_pending(&cfg->scan_timeout))
+ del_timer_sync(&cfg->scan_timeout);
+ DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+ cfg->scan_request = NULL;
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+
+ return err;
+}
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+static s32
+wl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
+#else
+static s32
+wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
+ struct cfg80211_scan_request *request)
+#endif /* WL_CFG80211_P2P_DEV_IF */
+{
+ s32 err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ struct net_device *ndev = wdev_to_wlc_ndev(request->wdev, cfg);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+ WL_DBG(("Enter\n"));
+ RETURN_EIO_IF_NOT_UP(cfg);
+
+ mutex_lock(&cfg->usr_sync);
+ err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
+ if (unlikely(err)) {
+ WL_ERR(("scan error (%d)\n", err));
+ }
+ mutex_unlock(&cfg->usr_sync);
+
+ return err;
+}
+
+static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
+{
+ s32 err = 0;
+
+ err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold);
+ if (unlikely(err)) {
+ WL_ERR(("Error (%d)\n", err));
+ return err;
+ }
+ return err;
+}
+
+static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
+{
+ s32 err = 0;
+
+ err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0);
+ if (unlikely(err)) {
+ WL_ERR(("Error (%d)\n", err));
+ return err;
+ }
+ return err;
+}
+
+static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l)
+{
+ s32 err = 0;
+ u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
+
+ retry = htod32(retry);
+ err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), true);
+ if (unlikely(err)) {
+ WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
+ return err;
+ }
+ return err;
+}
+
+static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ s32 err = 0;
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+ WL_DBG(("Enter\n"));
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
+ (cfg->conf->rts_threshold != wiphy->rts_threshold)) {
+ cfg->conf->rts_threshold = wiphy->rts_threshold;
+ err = wl_set_rts(ndev, cfg->conf->rts_threshold);
+ if (!err)
+ return err;
+ }
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
+ (cfg->conf->frag_threshold != wiphy->frag_threshold)) {
+ cfg->conf->frag_threshold = wiphy->frag_threshold;
+ err = wl_set_frag(ndev, cfg->conf->frag_threshold);
+ if (!err)
+ return err;
+ }
+ if (changed & WIPHY_PARAM_RETRY_LONG &&
+ (cfg->conf->retry_long != wiphy->retry_long)) {
+ cfg->conf->retry_long = wiphy->retry_long;
+ err = wl_set_retry(ndev, cfg->conf->retry_long, true);
+ if (!err)
+ return err;
+ }
+ if (changed & WIPHY_PARAM_RETRY_SHORT &&
+ (cfg->conf->retry_short != wiphy->retry_short)) {
+ cfg->conf->retry_short = wiphy->retry_short;
+ err = wl_set_retry(ndev, cfg->conf->retry_short, false);
+ if (!err) {
+ return err;
+ }
+ }
+
+ return err;
+}
+static chanspec_t
+channel_to_chanspec(struct wiphy *wiphy, struct net_device *dev, u32 channel, u32 bw_cap)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ u8 *buf = NULL;
+ wl_uint32_list_t *list;
+ int err = BCME_OK;
+ chanspec_t c = 0, ret_c = 0;
+ int bw = 0, tmp_bw = 0;
+ int i;
+ u32 tmp_c;
+ u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
+#define LOCAL_BUF_SIZE 1024
+ buf = (u8 *) kzalloc(LOCAL_BUF_SIZE, kflags);
+ if (!buf) {
+ WL_ERR(("buf memory alloc failed\n"));
+ goto exit;
+ }
+ list = (wl_uint32_list_t *)(void *)buf;
+ list->count = htod32(WL_NUMCHANSPECS);
+ err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
+ 0, buf, LOCAL_BUF_SIZE, 0, &cfg->ioctl_buf_sync);
+ if (err != BCME_OK) {
+ WL_ERR(("get chanspecs failed with %d\n", err));
+ goto exit;
+ }
+ for (i = 0; i < dtoh32(list->count); i++) {
+ c = dtoh32(list->element[i]);
+ if (channel <= CH_MAX_2G_CHANNEL) {
+ if (!CHSPEC_IS20(c))
+ continue;
+ if (channel == CHSPEC_CHANNEL(c)) {
+ ret_c = c;
+ bw = 20;
+ goto exit;
+ }
+ }
+ tmp_c = wf_chspec_ctlchan(c);
+ tmp_bw = bw2cap[CHSPEC_BW(c) >> WL_CHANSPEC_BW_SHIFT];
+ if (tmp_c != channel)
+ continue;
+
+ if ((tmp_bw > bw) && (tmp_bw <= bw_cap)) {
+ bw = tmp_bw;
+ ret_c = c;
+ if (bw == bw_cap)
+ goto exit;
+ }
+ }
+exit:
+ if (buf)
+ kfree(buf);
+#undef LOCAL_BUF_SIZE
+ WL_INFORM(("return chanspec %x %d\n", ret_c, bw));
+ return ret_c;
+}
+
+void
+wl_cfg80211_ibss_vsie_set_buffer(struct net_device *dev,
+ vndr_ie_setbuf_t *ibss_vsie, int ibss_vsie_len)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+
+ if (cfg != NULL && ibss_vsie != NULL) {
+ if (cfg->ibss_vsie != NULL) {
+ kfree(cfg->ibss_vsie);
+ }
+ cfg->ibss_vsie = ibss_vsie;
+ cfg->ibss_vsie_len = ibss_vsie_len;
+ }
+}
+
+static void
+wl_cfg80211_ibss_vsie_free(struct bcm_cfg80211 *cfg)
+{
+ /* free & initiralize VSIE (Vendor Specific IE) */
+ if (cfg->ibss_vsie != NULL) {
+ kfree(cfg->ibss_vsie);
+ cfg->ibss_vsie = NULL;
+ cfg->ibss_vsie_len = 0;
+ }
+}
+
+s32
+wl_cfg80211_ibss_vsie_delete(struct net_device *dev)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ char *ioctl_buf = NULL;
+ s32 ret = BCME_OK;
+
+ if (cfg != NULL && cfg->ibss_vsie != NULL) {
+ ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
+ if (!ioctl_buf) {
+ WL_ERR(("ioctl memory alloc failed\n"));
+ return -ENOMEM;
+ }
+
+ /* change the command from "add" to "del" */
+ strncpy(cfg->ibss_vsie->cmd, "del", VNDR_IE_CMD_LEN - 1);
+ cfg->ibss_vsie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
+
+ ret = wldev_iovar_setbuf(dev, "ie",
+ cfg->ibss_vsie, cfg->ibss_vsie_len,
+ ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
+ WL_ERR(("ret=%d\n", ret));
+
+ if (ret == BCME_OK) {
+ /* free & initiralize VSIE */
+ kfree(cfg->ibss_vsie);
+ cfg->ibss_vsie = NULL;
+ cfg->ibss_vsie_len = 0;
+ }
+
+ if (ioctl_buf) {
+ kfree(ioctl_buf);
+ }
+ }
+
+ return ret;
+}
+
+#ifdef WLAIBSS_MCHAN
+static bcm_struct_cfgdev*
+bcm_cfg80211_add_ibss_if(struct wiphy *wiphy, char *name)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct wireless_dev* wdev = NULL;
+ struct net_device *new_ndev = NULL;
+ struct net_device *primary_ndev = NULL;
+ s32 timeout;
+ wl_aibss_if_t aibss_if;
+ wl_if_event_info *event = NULL;
+
+ if (cfg->ibss_cfgdev != NULL) {
+ WL_ERR(("IBSS interface %s already exists\n", name));
+ return NULL;
+ }
+
+ WL_ERR(("Try to create IBSS interface %s\n", name));
+ primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+ /* generate a new MAC address for the IBSS interface */
+ get_primary_mac(cfg, &cfg->ibss_if_addr);
+ cfg->ibss_if_addr.octet[4] ^= 0x40;
+ memset(&aibss_if, sizeof(aibss_if), 0);
+ memcpy(&aibss_if.addr, &cfg->ibss_if_addr, sizeof(aibss_if.addr));
+ aibss_if.chspec = 0;
+ aibss_if.len = sizeof(aibss_if);
+
+ cfg->bss_pending_op = TRUE;
+ memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
+ err = wldev_iovar_setbuf(primary_ndev, "aibss_ifadd", &aibss_if,
+ sizeof(aibss_if), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
+ if (err) {
+ WL_ERR(("IOVAR aibss_ifadd failed with error %d\n", err));
+ goto fail;
+ }
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+ !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
+ if (timeout <= 0 || cfg->bss_pending_op)
+ goto fail;
+
+ event = &cfg->if_event_info;
+ /* By calling wl_cfg80211_allocate_if (dhd_allocate_if eventually) we give the control
+ * over this net_device interface to dhd_linux, hence the interface is managed by dhd_liux
+ * and will be freed by dhd_detach unless it gets unregistered before that. The
+ * wireless_dev instance new_ndev->ieee80211_ptr associated with this net_device will
+ * be freed by wl_dealloc_netinfo
+ */
+ new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx, event->name,
+ event->mac, event->bssidx, event->name);
+ if (new_ndev == NULL)
+ goto fail;
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (wdev == NULL)
+ goto fail;
+ wdev->wiphy = wiphy;
+ wdev->iftype = NL80211_IFTYPE_ADHOC;
+ wdev->netdev = new_ndev;
+ new_ndev->ieee80211_ptr = wdev;
+ SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
+
+ /* rtnl lock must have been acquired, if this is not the case, wl_cfg80211_register_if
+ * needs to be modified to take one parameter (bool need_rtnl_lock)
+ */
+ ASSERT_RTNL();
+ if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK)
+ goto fail;
+
+ wl_alloc_netinfo(cfg, new_ndev, wdev, WL_MODE_IBSS, PM_ENABLE, event->bssidx);
+ cfg->ibss_cfgdev = ndev_to_cfgdev(new_ndev);
+ WL_ERR(("IBSS interface %s created\n", new_ndev->name));
+ return cfg->ibss_cfgdev;
+
+fail:
+ WL_ERR(("failed to create IBSS interface %s \n", name));
+ cfg->bss_pending_op = FALSE;
+ if (new_ndev)
+ wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev);
+ if (wdev)
+ kfree(wdev);
+ return NULL;
+}
+
+static s32
+bcm_cfg80211_del_ibss_if(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *ndev = NULL;
+ struct net_device *primary_ndev = NULL;
+ s32 timeout;
+
+ if (!cfgdev || cfg->ibss_cfgdev != cfgdev || ETHER_ISNULLADDR(&cfg->ibss_if_addr.octet))
+ return -EINVAL;
+ ndev = (struct net_device *)cfgdev_to_ndev(cfg->ibss_cfgdev);
+ primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+
+ cfg->bss_pending_op = TRUE;
+ memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
+ err = wldev_iovar_setbuf(primary_ndev, "aibss_ifdel", &cfg->ibss_if_addr,
+ sizeof(cfg->ibss_if_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, NULL);
+ if (err) {
+ WL_ERR(("IOVAR aibss_ifdel failed with error %d\n", err));
+ goto fail;
+ }
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+ !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
+ if (timeout <= 0 || cfg->bss_pending_op) {
+ WL_ERR(("timeout in waiting IF_DEL event\n"));
+ goto fail;
+ }
+
+ wl_cfg80211_remove_if(cfg, cfg->if_event_info.ifidx, ndev);
+ cfg->ibss_cfgdev = NULL;
+ return 0;
+
+fail:
+ cfg->bss_pending_op = FALSE;
+ return -1;
+}
+#endif /* WLAIBSS_MCHAN */
+
+s32
+wl_cfg80211_interface_ops(struct bcm_cfg80211 *cfg,
+ struct net_device *ndev, s32 bsscfg_idx,
+ enum nl80211_iftype iface_type, s32 del, u8 *addr)
+{
+ wl_interface_create_t iface;
+ s32 ret;
+ wl_interface_info_t *info;
+
+ bzero(&iface, sizeof(wl_interface_create_t));
+
+ iface.ver = WL_INTERFACE_CREATE_VER;
+
+ if (iface_type == NL80211_IFTYPE_AP)
+ iface.flags = WL_INTERFACE_CREATE_AP;
+ else
+ iface.flags = WL_INTERFACE_CREATE_STA;
+
+ if (del) {
+ ret = wldev_iovar_setbuf(ndev, "interface_remove",
+ NULL, 0, cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
+ } else {
+ if (addr) {
+ memcpy(&iface.mac_addr.octet, addr, ETH_ALEN);
+ iface.flags |= WL_INTERFACE_MAC_USE;
+ }
+ ret = wldev_iovar_getbuf(ndev, "interface_create",
+ &iface, sizeof(wl_interface_create_t),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (ret == 0) {
+ /* success */
+ info = (wl_interface_info_t *)cfg->ioctl_buf;
+ WL_DBG(("wl interface create success!! bssidx:%d \n",
+ info->bsscfgidx));
+ ret = info->bsscfgidx;
+ }
+ }
+
+ if (ret < 0)
+ WL_ERR(("Interface %s failed!! ret %d\n",
+ del ? "remove" : "create", ret));
+
+ return ret;
+}
+
+
+s32
+wl_cfg80211_add_del_bss(struct bcm_cfg80211 *cfg,
+ struct net_device *ndev, s32 bsscfg_idx,
+ enum nl80211_iftype iface_type, s32 del, u8 *addr)
+{
+ s32 ret = BCME_OK;
+ s32 val = 0;
+
+ struct {
+ s32 cfg;
+ s32 val;
+ struct ether_addr ea;
+ } bss_setbuf;
+
+ WL_INFORM(("iface_type:%d del:%d \n", iface_type, del));
+
+ bzero(&bss_setbuf, sizeof(bss_setbuf));
+
+ /* AP=3, STA=2, up=1, down=0, val=-1 */
+ if (del) {
+ val = -1;
+ } else if (iface_type == NL80211_IFTYPE_AP) {
+ /* AP Interface */
+ WL_DBG(("Adding AP Interface \n"));
+ val = 3;
+ } else if (iface_type == NL80211_IFTYPE_STATION) {
+ WL_DBG(("Adding STA Interface \n"));
+ val = 2;
+ } else {
+ WL_ERR((" add_del_bss NOT supported for IFACE type:0x%x", iface_type));
+ return -EINVAL;
+ }
+
+ bss_setbuf.cfg = htod32(bsscfg_idx);
+ bss_setbuf.val = htod32(val);
+
+ if (addr) {
+ memcpy(&bss_setbuf.ea.octet, addr, ETH_ALEN);
+ }
+
+ ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (ret != 0)
+ WL_ERR(("'bss %d' failed with %d\n", val, ret));
+
+ return ret;
+}
+
+#if defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF)
+/* Create a Generic Network Interface and initialize it depending up on
+ * the interface type
+ */
+bcm_struct_cfgdev*
+wl_cfg80211_create_iface(struct wiphy *wiphy,
+ enum nl80211_iftype iface_type,
+ u8 *mac_addr, const char *name)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *new_ndev = NULL;
+ struct net_device *primary_ndev = NULL;
+ s32 ret = BCME_OK;
+ s32 bsscfg_idx = 0;
+ u32 timeout;
+ wl_if_event_info *event = NULL;
+ struct wireless_dev *wdev = NULL;
+ u8 addr[ETH_ALEN];
+ static int mac_idx = 0;
+
+ WL_DBG(("Enter\n"));
+
+ if (!name) {
+ WL_ERR(("Interface name not provided\n"));
+ return NULL;
+ }
+
+ primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+
+#ifdef DHD_IFDEBUG
+ WL_ERR(("cfg=%p, primary_ndev=%p, ifname=%s\n", cfg, primary_ndev, name));
+#endif
+
+ /* If any scan is going on, abort it */
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ int wait_cnt = MAX_SCAN_ABORT_WAIT_CNT;
+ WL_ERR(("Scan in progress. Aborting the scan!\n"));
+ wl_cfg80211_scan_abort(cfg);
+ while (wl_get_drv_status_all(cfg, SCANNING) && wait_cnt) {
+ WL_DBG(("Waiting for SCANNING terminated, wait_cnt: %d\n", wait_cnt));
+ wait_cnt--;
+ OSL_SLEEP(WAIT_SCAN_ABORT_OSL_SLEEP_TIME);
+ }
+ if (!wait_cnt && wl_get_drv_status_all(cfg, SCANNING)) {
+ WL_ERR(("Failed to abort scan\n"));
+ return NULL;
+ }
+ }
+
+ primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+ if (likely(!mac_addr)) {
+ /* Use primary MAC with the locally administered bit for the
+ * Secondary STA I/F
+ */
+ memcpy(addr, primary_ndev->dev_addr, ETH_ALEN);
+ addr[0] |= 0x02;
+ /* MAC Adresses for virtual interfaces,
+ * for maximum two virtual interfaces
+ */
+ addr[3] ^= mac_idx ? 0xC0 : 0xA0;
+ mac_idx++;
+ mac_idx = mac_idx % 2;
+ } else {
+ /* Use the application provided mac address (if any) */
+ memcpy(addr, mac_addr, ETH_ALEN);
+ }
+
+ if ((iface_type != NL80211_IFTYPE_STATION) && (iface_type != NL80211_IFTYPE_AP)) {
+ WL_ERR(("IFACE type:%d not supported. STA "
+ "or AP IFACE is only supported\n", iface_type));
+ return NULL;
+ }
+
+ cfg->bss_pending_op = TRUE;
+ memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
+
+ /* De-initialize the p2p discovery interface, if operational */
+ if (p2p_is_on(cfg)) {
+ WL_DBG(("Disabling P2P Discovery Interface \n"));
+#ifdef WL_CFG80211_P2P_DEV_IF
+ ret = wl_cfg80211_scan_stop(bcmcfg_to_p2p_wdev(cfg));
+#else
+ ret = wl_cfg80211_scan_stop(cfg->p2p_net);
+#endif
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret));
+ }
+
+#ifdef DHD_IFDEBUG
+ WL_ERR(("call wl_cfgp2p_disable_discovery()\n"));
+#endif
+ wl_cfgp2p_disable_discovery(cfg);
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
+ p2p_on(cfg) = false;
+ }
+
+ /*
+ * Intialize the firmware I/F.
+ */
+ ret = wl_cfg80211_interface_ops(cfg, primary_ndev, bsscfg_idx,
+ NL80211_IFTYPE_STATION, 0, addr);
+ if (ret == BCME_UNSUPPORTED) {
+ /* Use bssidx 1 by default */
+ bsscfg_idx = 1;
+ if ((ret = wl_cfg80211_add_del_bss(cfg, primary_ndev,
+ bsscfg_idx, iface_type, 0, addr)) < 0) {
+ return NULL;
+ }
+ } else if (ret < 0) {
+ WL_ERR(("Interface create failed!! ret:%d \n", ret));
+ goto fail;
+ } else {
+ /* Success */
+ bsscfg_idx = ret;
+ }
+
+ WL_DBG(("Interface created!! bssidx:%d \n", bsscfg_idx));
+
+ /*
+ * Wait till the firmware send a confirmation event back.
+ */
+ WL_DBG(("Wait for the FW I/F Event\n"));
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+ !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
+ if (timeout <= 0 || cfg->bss_pending_op) {
+ WL_ERR(("ADD_IF event, didn't come. Return \n"));
+ goto fail;
+ }
+
+ /*
+ * Since FW operation is successful,we can go ahead with the
+ * the host interface creation.
+ */
+ event = &cfg->if_event_info;
+ new_ndev = wl_cfg80211_allocate_if(cfg, event->ifidx,
+ (char*)name, addr, event->bssidx, event->name);
+ if (!new_ndev) {
+ WL_ERR(("I/F allocation failed! \n"));
+ goto fail;
+ } else
+ WL_DBG(("I/F allocation succeeded! ifidx:0x%x bssidx:0x%x \n",
+ event->ifidx, event->bssidx));
+
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (!wdev) {
+ WL_ERR(("wireless_dev alloc failed! \n"));
+ goto fail;
+ }
+
+ wdev->wiphy = wiphy;
+ wdev->iftype = iface_type;
+ new_ndev->ieee80211_ptr = wdev;
+ SET_NETDEV_DEV(new_ndev, wiphy_dev(wdev->wiphy));
+
+#ifdef DHD_IFDEBUG
+ WL_ERR(("wdev=%p, new_ndev=%p\n", wdev, new_ndev));
+#endif
+
+ /* RTNL lock must have been acquired. */
+ ASSERT_RTNL();
+
+ /* Set the locally administed mac addr, if not applied already */
+ if (memcmp(addr, event->mac, ETH_ALEN) != 0) {
+ ret = wldev_iovar_setbuf_bsscfg(primary_ndev, "cur_etheraddr",
+ addr, ETH_ALEN, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
+ event->bssidx, &cfg->ioctl_buf_sync);
+ if (unlikely(ret)) {
+ WL_ERR(("set cur_etheraddr Error (%d)\n", ret));
+ goto fail;
+ }
+ memcpy(new_ndev->dev_addr, addr, ETH_ALEN);
+ }
+
+ if (wl_cfg80211_register_if(cfg, event->ifidx, new_ndev) != BCME_OK) {
+ WL_ERR(("IFACE register failed \n"));
+ goto fail;
+ }
+
+ /* Initialize with the station mode params */
+ wl_alloc_netinfo(cfg, new_ndev, wdev,
+ (iface_type == NL80211_IFTYPE_STATION) ?
+ WL_MODE_BSS : WL_MODE_AP, PM_ENABLE, event->bssidx);
+
+ WL_DBG(("Host Network Interface for Secondary I/F created"));
+
+ return ndev_to_cfgdev(new_ndev);
+
+fail:
+ cfg->bss_pending_op = FALSE;
+
+ if (wdev)
+ kfree(wdev);
+ if (new_ndev)
+ wl_cfg80211_remove_if(cfg, event->ifidx, new_ndev);
+
+#ifdef DHD_IFDEBUG
+ WL_ERR(("failed!!!\n"));
+#endif
+
+ return NULL;
+}
+
+s32
+wl_cfg80211_del_iface(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *ndev = NULL;
+#ifdef DHD_IFDEBUG
+ struct net_device *primary_ndev = NULL;
+#endif
+ s32 ret = BCME_OK;
+ s32 bsscfg_idx = 1;
+ u32 timeout;
+ u32 ifidx;
+ enum nl80211_iftype iface_type = NL80211_IFTYPE_STATION;
+
+ WL_ERR(("Enter\n"));
+
+ /* If any scan is going on, abort it */
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ WL_ERR(("Scan in progress. Aborting the scan!\n"));
+ wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
+ }
+
+ ndev = (struct net_device *)cfgdev_to_ndev(cfgdev);
+#ifdef DHD_IFDEBUG
+ primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+ WL_ERR(("cfgdev=%p, ndev=%p, primary_ndev=%p\n",
+ cfgdev, ndev, primary_ndev));
+#endif
+
+ cfg->bss_pending_op = TRUE;
+ memset(&cfg->if_event_info, 0, sizeof(cfg->if_event_info));
+
+ /* Delete the firmware interface. "interface_remove" command
+ * should go on the interface to be deleted
+ */
+ /* Get the bssidx from netd */
+ bsscfg_idx = wl_get_bssidx_by_wdev(cfg, cfgdev_to_wdev(cfgdev));
+ if (bsscfg_idx < 0) {
+ WL_ERR(("DEL bss failed to get bssidx"));
+ goto exit;
+ }
+ ret = wl_cfg80211_interface_ops(cfg, ndev, bsscfg_idx,
+ NL80211_IFTYPE_STATION, 1, NULL);
+ if (ret == BCME_UNSUPPORTED) {
+ if ((ret = wl_cfg80211_add_del_bss(cfg, ndev,
+ bsscfg_idx, iface_type, true, NULL)) < 0) {
+ WL_ERR(("DEL bss failed ret:%d \n", ret));
+ goto exit;
+ }
+ } else if (ret < 0) {
+ WL_ERR(("Interface DEL failed ret:%d \n", ret));
+ goto exit;
+ }
+
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+ !cfg->bss_pending_op, msecs_to_jiffies(MAX_WAIT_TIME));
+ if (timeout <= 0 || cfg->bss_pending_op) {
+ WL_ERR(("timeout in waiting IF_DEL event\n"));
+ }
+
+exit:
+ ifidx = dhd_net2idx(((struct dhd_pub *)(cfg->pub))->info, ndev);
+ if (ifidx >= 0) {
+ wl_cfg80211_remove_if(cfg, ifidx, ndev);
+ }
+ cfg->bss_pending_op = FALSE;
+
+ WL_ERR(("IF_DEL Done.\n"));
+
+ return ret;
+}
+#endif /* defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF) */
+
+static s32
+wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ibss_params *params)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct cfg80211_bss *bss;
+ struct ieee80211_channel *chan;
+ struct wl_join_params join_params;
+ int scan_suppress;
+ struct cfg80211_ssid ssid;
+ s32 scan_retry = 0;
+ s32 err = 0;
+ size_t join_params_size;
+ chanspec_t chanspec = 0;
+ u32 param[2] = {0, 0};
+ u32 bw_cap = 0;
+
+ WL_TRACE(("In\n"));
+ RETURN_EIO_IF_NOT_UP(cfg);
+ WL_INFORM(("JOIN BSSID:" MACDBG "\n", MAC2STRDBG(params->bssid)));
+ if (!params->ssid || params->ssid_len <= 0 ||
+ params->ssid_len > DOT11_MAX_SSID_LEN) {
+ WL_ERR(("Invalid parameter\n"));
+ return -EINVAL;
+ }
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ chan = params->chandef.chan;
+#else
+ chan = params->channel;
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ if (chan)
+ cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
+ if (wl_get_drv_status(cfg, CONNECTED, dev)) {
+ struct wlc_ssid *lssid = (struct wlc_ssid *)wl_read_prof(cfg, dev, WL_PROF_SSID);
+ u8 *bssid = (u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID);
+ u32 *channel = (u32 *)wl_read_prof(cfg, dev, WL_PROF_CHAN);
+ if (!params->bssid || ((memcmp(params->bssid, bssid, ETHER_ADDR_LEN) == 0) &&
+ (memcmp(params->ssid, lssid->SSID, lssid->SSID_len) == 0) &&
+ (*channel == cfg->channel))) {
+ WL_ERR(("Connection already existed to " MACDBG "\n",
+ MAC2STRDBG((u8 *)wl_read_prof(cfg, dev, WL_PROF_BSSID))));
+ return -EISCONN;
+ }
+ WL_ERR(("Ignore Previous connecton to %s (" MACDBG ")\n",
+ lssid->SSID, MAC2STRDBG(bssid)));
+ }
+
+ /* remove the VSIE */
+ wl_cfg80211_ibss_vsie_delete(dev);
+
+ bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
+ if (!bss) {
+ if (IBSS_INITIAL_SCAN_ALLOWED == TRUE) {
+ memcpy(ssid.ssid, params->ssid, params->ssid_len);
+ ssid.ssid_len = params->ssid_len;
+ do {
+ if (unlikely
+ (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
+ -EBUSY)) {
+ wl_delay(150);
+ } else {
+ break;
+ }
+ } while (++scan_retry < WL_SCAN_RETRY_MAX);
+
+ /* rtnl lock code is removed here. don't see why rtnl lock
+ * needs to be released.
+ */
+
+ /* wait 4 secons till scan done.... */
+ schedule_timeout_interruptible(msecs_to_jiffies(4000));
+
+ bss = cfg80211_get_ibss(wiphy, NULL,
+ params->ssid, params->ssid_len);
+ }
+ }
+ if (bss && ((IBSS_COALESCE_ALLOWED == TRUE) ||
+ ((IBSS_COALESCE_ALLOWED == FALSE) && params->bssid &&
+ !memcmp(bss->bssid, params->bssid, ETHER_ADDR_LEN)))) {
+ cfg->ibss_starter = false;
+ WL_DBG(("Found IBSS\n"));
+ } else {
+ cfg->ibss_starter = true;
+ }
+ if (chan) {
+ if (chan->band == IEEE80211_BAND_5GHZ)
+ param[0] = WLC_BAND_5G;
+ else if (chan->band == IEEE80211_BAND_2GHZ)
+ param[0] = WLC_BAND_2G;
+ err = wldev_iovar_getint(dev, "bw_cap", param);
+ if (unlikely(err)) {
+ WL_ERR(("Get bw_cap Failed (%d)\n", err));
+ return err;
+ }
+ bw_cap = param[0];
+ chanspec = channel_to_chanspec(wiphy, dev, cfg->channel, bw_cap);
+ }
+ /*
+ * Join with specific BSSID and cached SSID
+ * If SSID is zero join based on BSSID only
+ */
+ memset(&join_params, 0, sizeof(join_params));
+ memcpy((void *)join_params.ssid.SSID, (void *)params->ssid,
+ params->ssid_len);
+ join_params.ssid.SSID_len = htod32(params->ssid_len);
+ if (params->bssid) {
+ memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);
+ err = wldev_ioctl(dev, WLC_SET_DESIRED_BSSID, &join_params.params.bssid,
+ ETHER_ADDR_LEN, true);
+ if (unlikely(err)) {
+ WL_ERR(("Error (%d)\n", err));
+ return err;
+ }
+ } else
+ memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);
+ wldev_iovar_setint(dev, "ibss_coalesce_allowed", IBSS_COALESCE_ALLOWED);
+
+ if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
+ scan_suppress = TRUE;
+ /* Set the SCAN SUPPRESS Flag in the firmware to skip join scan */
+ err = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS,
+ &scan_suppress, sizeof(int), true);
+ if (unlikely(err)) {
+ WL_ERR(("Scan Suppress Setting Failed (%d)\n", err));
+ return err;
+ }
+ }
+
+ join_params.params.chanspec_list[0] = chanspec;
+ join_params.params.chanspec_num = 1;
+ wldev_iovar_setint(dev, "chanspec", chanspec);
+ join_params_size = sizeof(join_params);
+
+ /* Disable Authentication, IBSS will add key if it required */
+ wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
+ wldev_iovar_setint(dev, "wsec", 0);
+
+
+ err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
+ join_params_size, true);
+ if (unlikely(err)) {
+ WL_ERR(("Error (%d)\n", err));
+ return err;
+ }
+
+ if (IBSS_INITIAL_SCAN_ALLOWED == FALSE) {
+ scan_suppress = FALSE;
+ /* Reset the SCAN SUPPRESS Flag */
+ err = wldev_ioctl(dev, WLC_SET_SCANSUPPRESS,
+ &scan_suppress, sizeof(int), true);
+ if (unlikely(err)) {
+ WL_ERR(("Reset Scan Suppress Flag Failed (%d)\n", err));
+ return err;
+ }
+ }
+ wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
+ wl_update_prof(cfg, dev, NULL, &cfg->channel, WL_PROF_CHAN);
+ cfg->rmc_event_seq = 0; /* initialize rmcfail sequence */
+ return err;
+}
+
+static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 err = 0;
+ scb_val_t scbval;
+ u8 *curbssid;
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+ wl_link_down(cfg);
+
+ WL_ERR(("Leave IBSS\n"));
+ curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
+ wl_set_drv_status(cfg, DISCONNECTING, dev);
+ scbval.val = 0;
+ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
+ err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
+ sizeof(scb_val_t), true);
+ if (unlikely(err)) {
+ wl_clr_drv_status(cfg, DISCONNECTING, dev);
+ WL_ERR(("error(%d)\n", err));
+ return err;
+ }
+
+ /* remove the VSIE */
+ wl_cfg80211_ibss_vsie_delete(dev);
+
+ return err;
+}
+
+
+static s32
+wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ struct wl_security *sec;
+ s32 val = 0;
+ s32 err = 0;
+ s32 bssidx;
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+
+ if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
+ val = WPA_AUTH_PSK |
+ WPA_AUTH_UNSPECIFIED;
+ else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
+ val = WPA2_AUTH_PSK|
+ WPA2_AUTH_UNSPECIFIED;
+ else
+ val = WPA_AUTH_DISABLED;
+
+ if (is_wps_conn(sme))
+ val = WPA_AUTH_DISABLED;
+
+#ifdef BCMWAPI_WPI
+ if (sme->crypto.n_ciphers_pairwise &&
+ (sme->crypto.ciphers_pairwise[0] == WLAN_DHD_CIPHER_SUITE_SMS4)) {
+ WL_DBG((" * wl_set_wpa_version, set wpa_auth"
+ " to WPA_AUTH_WAPI 0x400"));
+ val = WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED;
+ }
+#endif
+ WL_DBG(("setting wpa_auth to 0x%0x\n", val));
+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("set wpa_auth failed (%d)\n", err));
+ return err;
+ }
+ sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
+ sec->wpa_versions = sme->crypto.wpa_versions;
+ return err;
+}
+
+#ifdef BCMWAPI_WPI
+static s32
+wl_set_set_wapi_ie(struct net_device *dev, struct cfg80211_connect_params *sme)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ s32 err = 0;
+ s32 bssidx;
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+
+ WL_DBG((" %s \n", __FUNCTION__));
+
+ if (sme->crypto.n_ciphers_pairwise &&
+ (sme->crypto.ciphers_pairwise[0] == WLAN_DHD_CIPHER_SUITE_SMS4)) {
+ err = wldev_iovar_setbuf_bsscfg(dev, "wapiie", (void*)sme->ie, sme->ie_len,
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+
+ if (unlikely(err)) {
+ WL_ERR(("===> set_wapi_ie Error (%d)\n", err));
+ return err;
+ }
+ } else
+ WL_DBG((" * skip \n"));
+ return err;
+}
+#endif /* BCMWAPI_WPI */
+
+static s32
+wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ struct wl_security *sec;
+ s32 val = 0;
+ s32 err = 0;
+ s32 bssidx;
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+
+ switch (sme->auth_type) {
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ val = WL_AUTH_OPEN_SYSTEM;
+ WL_DBG(("open system\n"));
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ val = WL_AUTH_SHARED_KEY;
+ WL_DBG(("shared key\n"));
+ break;
+ case NL80211_AUTHTYPE_AUTOMATIC:
+ val = WL_AUTH_OPEN_SHARED;
+ WL_DBG(("automatic\n"));
+ break;
+ default:
+ val = 2;
+ WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
+ break;
+ }
+
+ err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("set auth failed (%d)\n", err));
+ return err;
+ }
+ sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
+ sec->auth_type = sme->auth_type;
+ return err;
+}
+
+static s32
+wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ struct wl_security *sec;
+ s32 pval = 0;
+ s32 gval = 0;
+ s32 err = 0;
+ s32 wsec_val = 0;
+
+#ifdef BCMWAPI_WPI
+ s32 val = 0;
+#endif
+ s32 bssidx;
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+
+ if (sme->crypto.n_ciphers_pairwise) {
+ switch (sme->crypto.ciphers_pairwise[0]) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ pval = WEP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ pval = TKIP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ pval = AES_ENABLED;
+ break;
+#ifdef BCMWAPI_WPI
+ case WLAN_DHD_CIPHER_SUITE_SMS4:
+ val = SMS4_ENABLED;
+ pval = SMS4_ENABLED;
+ break;
+#endif
+ default:
+ WL_ERR(("invalid cipher pairwise (%d)\n",
+ sme->crypto.ciphers_pairwise[0]));
+ return -EINVAL;
+ }
+ }
+ if (sme->crypto.cipher_group) {
+ switch (sme->crypto.cipher_group) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ gval = WEP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ gval = TKIP_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ gval = AES_ENABLED;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ gval = AES_ENABLED;
+ break;
+#ifdef BCMWAPI_WPI
+ case WLAN_DHD_CIPHER_SUITE_SMS4:
+ val = SMS4_ENABLED;
+ gval = SMS4_ENABLED;
+ break;
+#endif
+ default:
+ WL_ERR(("invalid cipher group (%d)\n",
+ sme->crypto.cipher_group));
+ return -EINVAL;
+ }
+ }
+
+ WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
+
+ if (is_wps_conn(sme)) {
+ if (sme->privacy)
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx);
+ else
+ /* WPS-2.0 allows no security */
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", 0, bssidx);
+ } else {
+#ifdef BCMWAPI_WPI
+ if (sme->crypto.cipher_group == WLAN_DHD_CIPHER_SUITE_SMS4) {
+ WL_DBG((" NO, is_wps_conn, WAPI set to SMS4_ENABLED"));
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", val, bssidx);
+ } else {
+#endif
+ WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
+ wsec_val = pval | gval;
+
+ WL_DBG((" Set WSEC to fW 0x%x \n", wsec_val));
+ err = wldev_iovar_setint_bsscfg(dev, "wsec",
+ wsec_val, bssidx);
+#ifdef BCMWAPI_WPI
+ }
+#endif
+ }
+ if (unlikely(err)) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+
+ sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
+ sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
+ sec->cipher_group = sme->crypto.cipher_group;
+
+ return err;
+}
+
+static s32
+wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ struct wl_security *sec;
+ s32 val = 0;
+ s32 err = 0;
+ s32 bssidx;
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+
+ if (sme->crypto.n_akm_suites) {
+ err = wldev_iovar_getint(dev, "wpa_auth", &val);
+ if (unlikely(err)) {
+ WL_ERR(("could not get wpa_auth (%d)\n", err));
+ return err;
+ }
+ if (val & (WPA_AUTH_PSK |
+ WPA_AUTH_UNSPECIFIED)) {
+ switch (sme->crypto.akm_suites[0]) {
+ case WLAN_AKM_SUITE_8021X:
+ val = WPA_AUTH_UNSPECIFIED;
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ val = WPA_AUTH_PSK;
+ break;
+ default:
+ WL_ERR(("invalid akm suite (0x%x)\n",
+ sme->crypto.akm_suites[0]));
+ return -EINVAL;
+ }
+ } else if (val & (WPA2_AUTH_PSK |
+ WPA2_AUTH_UNSPECIFIED)) {
+ switch (sme->crypto.akm_suites[0]) {
+ case WLAN_AKM_SUITE_8021X:
+ val = WPA2_AUTH_UNSPECIFIED;
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ val = WPA2_AUTH_PSK;
+ break;
+ default:
+ WL_ERR(("invalid akm suite (0x%x)\n",
+ sme->crypto.akm_suites[0]));
+ return -EINVAL;
+ }
+ }
+#ifdef BCMWAPI_WPI
+ else {
+ if (val & (WAPI_AUTH_PSK | WAPI_AUTH_UNSPECIFIED)) {
+ switch (sme->crypto.akm_suites[0]) {
+ case WAPI_AUTH_UNSPECIFIED:
+ val = WAPI_AUTH_UNSPECIFIED;
+ break;
+ case WLAN_DHD_AKM_SUITE_WAPI_PSK:
+ case WAPI_AUTH_PSK:
+ val = WAPI_AUTH_PSK;
+ break;
+ }
+ }
+ else {
+ WL_ERR(("invalid akm suite (0x%x)\n",
+ sme->crypto.akm_suites[0]));
+ return -EINVAL;
+ }
+ }
+#endif /* BCMWAPI_WPI */
+
+
+ WL_DBG(("setting wpa_auth to 0x%x\n", val));
+
+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("could not set wpa_auth (%d)\n", err));
+ return err;
+ }
+ }
+ sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
+ sec->wpa_auth = sme->crypto.akm_suites[0];
+
+ return err;
+}
+
+static s32
+wl_set_set_sharedkey(struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ struct wl_security *sec;
+ struct wl_wsec_key key;
+ s32 val;
+ s32 err = 0;
+ s32 bssidx;
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+
+ WL_DBG(("key len (%d)\n", sme->key_len));
+ if (sme->key_len) {
+ sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
+ WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
+ sec->wpa_versions, sec->cipher_pairwise));
+ if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
+ NL80211_WPA_VERSION_2)) &&
+ (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
+#ifdef BCMWAPI_WPI
+ WLAN_CIPHER_SUITE_WEP104 | WLAN_DHD_CIPHER_SUITE_SMS4)))
+#else
+ WLAN_CIPHER_SUITE_WEP104)))
+#endif
+ {
+ memset(&key, 0, sizeof(key));
+ key.len = (u32) sme->key_len;
+ key.index = (u32) sme->key_idx;
+ if (unlikely(key.len > sizeof(key.data))) {
+ WL_ERR(("Too long key length (%u)\n", key.len));
+ return -EINVAL;
+ }
+ memcpy(key.data, sme->key, key.len);
+ key.flags = WL_PRIMARY_KEY;
+ switch (sec->cipher_pairwise) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key.algo = CRYPTO_ALGO_WEP1;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ key.algo = CRYPTO_ALGO_WEP128;
+ break;
+#ifdef BCMWAPI_WPI
+ case WLAN_CIPHER_SUITE_SMS4:
+ key.algo = CRYPTO_ALGO_SMS4;
+ break;
+#endif
+ default:
+ WL_ERR(("Invalid algorithm (%d)\n",
+ sme->crypto.ciphers_pairwise[0]));
+ return -EINVAL;
+ }
+ /* Set the new key/index */
+ WL_DBG(("key length (%d) key index (%d) algo (%d)\n",
+ key.len, key.index, key.algo));
+ WL_DBG(("key \"%s\"\n", key.data));
+ swap_key_from_BE(&key);
+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ return err;
+ }
+ if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) {
+ WL_DBG(("set auth_type to shared key\n"));
+ val = WL_AUTH_SHARED_KEY; /* shared key */
+ err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("set auth failed (%d)\n", err));
+ return err;
+ }
+ }
+ }
+ }
+ return err;
+}
+
+#if defined(ESCAN_RESULT_PATCH)
+static u8 connect_req_bssid[6];
+static u8 broad_bssid[6];
+#endif /* ESCAN_RESULT_PATCH */
+
+
+
+#if defined(CUSTOM_SET_CPUCORE) || defined(CONFIG_TCPACK_FASTTX)
+static bool wl_get_chan_isvht80(struct net_device *net, dhd_pub_t *dhd)
+{
+ u32 chanspec = 0;
+ bool isvht80 = 0;
+
+ if (wldev_iovar_getint(net, "chanspec", (s32 *)&chanspec) == BCME_OK)
+ chanspec = wl_chspec_driver_to_host(chanspec);
+
+ isvht80 = chanspec & WL_CHANSPEC_BW_80;
+ WL_INFO(("%s: chanspec(%x:%d)\n", __FUNCTION__, chanspec, isvht80));
+
+ return isvht80;
+}
+#endif /* CUSTOM_SET_CPUCORE || CONFIG_TCPACK_FASTTX */
+
+#ifdef AP_STA_RSDB_FEASIBILITY_CHK
+/* Check if STA connection can be allowed
+ * Reject if request leads to 3 channel concurrency
+ * or if request leads to Multi-Chan VSDB concurrency
+ */
+static bool
+wl_cfg80211_chk_conn_feasibility(struct bcm_cfg80211 *cfg, struct ieee80211_channel *chan)
+{
+ struct net_info *iter, *next;
+ u32 sta_chan = 0;
+ u32 *net_channel = NULL;
+ u32 ap_band, net_band;
+ u32 apcount = 0;
+ bool chan_matched = FALSE, band_matched = FALSE, reject = FALSE;
+
+ if (chan) {
+ sta_chan = ieee80211_frequency_to_channel(chan->center_freq);
+ WL_DBG(("channel (%d), center_req (%d)\n", sta_chan,
+ chan->center_freq));
+ } else {
+ WL_DBG(("No channel info from user space\n"));
+ return reject;
+ }
+
+ for_each_ndev(cfg, iter, next) {
+ if (iter->ndev) {
+ WL_DBG(("Mode (%d)\n", iter->mode));
+ if (iter->mode != WL_MODE_AP) {
+ continue;
+ }
+ apcount++;
+ net_channel = (u32 *)wl_read_prof(cfg, iter->ndev, WL_PROF_CHAN);
+ if (!net_channel) {
+ WL_DBG(("%d Channel not found for a AP\n", __LINE__));
+ continue;
+ }
+ WL_DBG(("Channel (%d)\n", *net_channel));
+ if (*net_channel == sta_chan) {
+ chan_matched = TRUE;
+ } else {
+ net_band = CHSPEC_BAND(wf_channel2chspec(*net_channel,
+ WL_CHANSPEC_BW_20));
+ ap_band = CHSPEC_BAND(wf_channel2chspec(sta_chan,
+ WL_CHANSPEC_BW_20));
+ WL_DBG(("Band (%d)\n", net_band));
+ if (ap_band == net_band) {
+ band_matched = TRUE;
+ }
+ }
+ }
+ }
+
+ switch (apcount) {
+ case 1:
+ /* If there is one AP/AGO connection */
+ if (!chan_matched && band_matched) {
+ reject = TRUE;
+ }
+ break;
+ case 2:
+ /* If there are two AP/AGO connection */
+ if (!chan_matched) {
+ reject = TRUE;
+ }
+ break;
+ default:
+ /* No AP/AGO connection */
+ WL_DBG(("%d No AP/AGO connections formed yet\n", __LINE__));
+ break;
+ }
+
+ return reject;
+}
+#endif /* AP_STA_RSDB_FEASIBILITY_CHK */
+
+static s32
+wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct ieee80211_channel *chan = sme->channel;
+ wl_extjoin_params_t *ext_join_params;
+ struct wl_join_params join_params;
+ size_t join_params_size;
+ s32 err = 0;
+ wpa_ie_fixed_t *wpa_ie;
+ bcm_tlv_t *wpa2_ie;
+ u8* wpaie = 0;
+ u32 wpaie_len = 0;
+ u32 chan_cnt = 0;
+ struct ether_addr bssid;
+ s32 bssidx = -1;
+ int ret;
+ int wait_cnt;
+
+ WL_DBG(("In\n"));
+
+#if defined(SUPPORT_RANDOM_MAC_SCAN)
+ wl_cfg80211_set_random_mac(dev, FALSE);
+#endif /* SUPPORT_RANDOM_MAC_SCAN */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
+ if (sme->channel_hint) {
+ chan = sme->channel_hint;
+ WL_DBG(("channel_hint (%d), channel_hint center_freq (%d)\n",
+ ieee80211_frequency_to_channel(sme->channel_hint->center_freq),
+ sme->channel_hint->center_freq));
+ }
+ if (sme->bssid_hint) {
+ sme->bssid = sme->bssid_hint;
+ WL_DBG(("bssid_hint "MACDBG" \n", MAC2STRDBG(sme->bssid_hint)));
+ }
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
+
+ if (unlikely(!sme->ssid)) {
+ WL_ERR(("Invalid ssid\n"));
+ return -EOPNOTSUPP;
+ }
+
+ if (unlikely(sme->ssid_len > DOT11_MAX_SSID_LEN)) {
+ WL_ERR(("Invalid SSID info: SSID=%s, length=%zd\n",
+ sme->ssid, sme->ssid_len));
+ return -EINVAL;
+ }
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+
+#ifdef AP_STA_RSDB_FEASIBILITY_CHK
+ /* Check if STA connection can be allowed
+ * This is temporary fix till we support
+ * AP/AGO movement to STA request channel
+ */
+ if (wl_cfg80211_chk_conn_feasibility(cfg, chan)) {
+ WL_DBG(("STA connection is not supported\n"));
+ return BCME_ERROR;
+ }
+#endif /* AP_STA_RSDB_FEASIBILITY_CHK */
+
+ /*
+ * Cancel ongoing scan to sync up with sme state machine of cfg80211.
+ */
+#if (defined(BCM4359_CHIP) || !defined(ESCAN_RESULT_PATCH))
+ if (cfg->scan_request) {
+ WL_TRACE_HW4(("Aborting the scan! \n"));
+ wl_cfg80211_scan_abort(cfg);
+ wait_cnt = MAX_SCAN_ABORT_WAIT_CNT;
+ while (wl_get_drv_status(cfg, SCANNING, dev) && wait_cnt) {
+ WL_DBG(("Waiting for SCANNING terminated, wait_cnt: %d\n", wait_cnt));
+ wait_cnt--;
+ OSL_SLEEP(WAIT_SCAN_ABORT_OSL_SLEEP_TIME);
+ }
+ if (wl_get_drv_status(cfg, SCANNING, dev)) {
+ wl_notify_escan_complete(cfg, dev, true, true);
+ }
+ }
+#endif
+#ifdef WL_SCHED_SCAN
+ if (cfg->sched_scan_req) {
+ wl_cfg80211_sched_scan_stop(wiphy, bcmcfg_to_prmry_ndev(cfg));
+ }
+#endif
+#if defined(ESCAN_RESULT_PATCH)
+ if (sme->bssid)
+ memcpy(connect_req_bssid, sme->bssid, ETHER_ADDR_LEN);
+ else
+ bzero(connect_req_bssid, ETHER_ADDR_LEN);
+ bzero(broad_bssid, ETHER_ADDR_LEN);
+#endif
+#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
+ maxrxpktglom = 0;
+#endif
+ bzero(&bssid, sizeof(bssid));
+ if (!wl_get_drv_status(cfg, CONNECTED, dev)&&
+ (ret = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false)) == 0) {
+ if (!ETHER_ISNULLADDR(&bssid)) {
+ scb_val_t scbval;
+ wl_set_drv_status(cfg, DISCONNECTING, dev);
+ scbval.val = DOT11_RC_DISASSOC_LEAVING;
+ memcpy(&scbval.ea, &bssid, ETHER_ADDR_LEN);
+ scbval.val = htod32(scbval.val);
+
+ WL_DBG(("drv status CONNECTED is not set, but connected in FW!" MACDBG "/n",
+ MAC2STRDBG(bssid.octet)));
+ err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
+ sizeof(scb_val_t), true);
+ if (unlikely(err)) {
+ wl_clr_drv_status(cfg, DISCONNECTING, dev);
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+ wait_cnt = 500/10;
+ while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
+ WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n",
+ wait_cnt));
+ wait_cnt--;
+ OSL_SLEEP(10);
+ }
+ } else
+ WL_DBG(("Currently not associated!\n"));
+ } else {
+ /* if status is DISCONNECTING, wait for disconnection terminated max 500 ms */
+ wait_cnt = 200/10;
+ while (wl_get_drv_status(cfg, DISCONNECTING, dev) && wait_cnt) {
+ WL_DBG(("Waiting for disconnection terminated, wait_cnt: %d\n", wait_cnt));
+ wait_cnt--;
+ OSL_SLEEP(10);
+ }
+ if (wl_get_drv_status(cfg, DISCONNECTING, dev)) {
+ WL_ERR(("Force clear DISCONNECTING status!\n"));
+ wl_clr_drv_status(cfg, DISCONNECTING, dev);
+ }
+ }
+
+ /* Clean BSSID */
+ bzero(&bssid, sizeof(bssid));
+ if (!wl_get_drv_status(cfg, DISCONNECTING, dev))
+ wl_update_prof(cfg, dev, NULL, (void *)&bssid, WL_PROF_BSSID);
+
+ if (p2p_is_on(cfg) && (dev != bcmcfg_to_prmry_ndev(cfg))) {
+ /* we only allow to connect using virtual interface in case of P2P */
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n",
+ dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+ wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
+ VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
+ } else if (dev == bcmcfg_to_prmry_ndev(cfg)) {
+ /* find the RSN_IE */
+ if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len,
+ DOT11_MNG_RSN_ID)) != NULL) {
+ WL_DBG((" WPA2 IE is found\n"));
+ }
+ /* find the WPA_IE */
+ if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)sme->ie,
+ sme->ie_len)) != NULL) {
+ WL_DBG((" WPA IE is found\n"));
+ }
+ if (wpa_ie != NULL || wpa2_ie != NULL) {
+ wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie;
+ wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
+ wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
+ err = wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("wpaie set error (%d)\n", err));
+ return err;
+ }
+ } else {
+ err = wldev_iovar_setbuf(dev, "wpaie", NULL, 0,
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("wpaie set error (%d)\n", err));
+ return err;
+ }
+ }
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+ err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
+ VNDR_IE_ASSOCREQ_FLAG, (const u8 *)sme->ie, sme->ie_len);
+ if (unlikely(err)) {
+ return err;
+ }
+ }
+
+ if (chan) {
+ cfg->channel = ieee80211_frequency_to_channel(chan->center_freq);
+ chan_cnt = 1;
+ WL_DBG(("channel (%d), center_req (%d), %d channels\n", cfg->channel,
+ chan->center_freq, chan_cnt));
+ } else {
+ WL_DBG(("No channel info from user space\n"));
+ cfg->channel = 0;
+ }
+
+
+#ifdef BCMWAPI_WPI
+ WL_DBG(("1. enable wapi auth\n"));
+ if (sme->crypto.n_ciphers_pairwise &&
+ (sme->crypto.ciphers_pairwise[0] == WLAN_DHD_CIPHER_SUITE_SMS4)) {
+ WL_DBG(("2. set wapi ie \n"));
+ err = wl_set_set_wapi_ie(dev, sme);
+ if (unlikely(err))
+ return err;
+ } else
+ WL_DBG(("2. Not wapi ie \n"));
+#endif
+ WL_DBG(("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len));
+ WL_DBG(("3. set wpa version \n"));
+ err = wl_set_wpa_version(dev, sme);
+ if (unlikely(err)) {
+ WL_ERR(("Invalid wpa_version\n"));
+ return err;
+ }
+#ifdef BCMWAPI_WPI
+ if (sme->crypto.n_ciphers_pairwise &&
+ (sme->crypto.ciphers_pairwise[0] == WLAN_DHD_CIPHER_SUITE_SMS4))
+ WL_DBG(("4. WAPI Dont Set wl_set_auth_type\n"));
+ else {
+ WL_DBG(("4. wl_set_auth_type\n"));
+#endif
+ err = wl_set_auth_type(dev, sme);
+ if (unlikely(err)) {
+ WL_ERR(("Invalid auth type\n"));
+ return err;
+ }
+#ifdef BCMWAPI_WPI
+ }
+#endif
+
+ err = wl_set_set_cipher(dev, sme);
+ if (unlikely(err)) {
+ WL_ERR(("Invalid ciper\n"));
+ return err;
+ }
+
+ err = wl_set_key_mgmt(dev, sme);
+ if (unlikely(err)) {
+ WL_ERR(("Invalid key mgmt\n"));
+ return err;
+ }
+
+ err = wl_set_set_sharedkey(dev, sme);
+ if (unlikely(err)) {
+ WL_ERR(("Invalid shared key\n"));
+ return err;
+ }
+
+ /*
+ * Join with specific BSSID and cached SSID
+ * If SSID is zero join based on BSSID only
+ */
+ join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
+ chan_cnt * sizeof(chanspec_t);
+ ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL);
+ if (ext_join_params == NULL) {
+ err = -ENOMEM;
+ wl_clr_drv_status(cfg, CONNECTING, dev);
+ goto exit;
+ }
+ ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len);
+ memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len);
+ wl_update_prof(cfg, dev, NULL, &ext_join_params->ssid, WL_PROF_SSID);
+ ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
+ /* increate dwell time to receive probe response or detect Beacon
+ * from target AP at a noisy air only during connect command
+ */
+ ext_join_params->scan.active_time = chan_cnt ? WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS : -1;
+ ext_join_params->scan.passive_time = chan_cnt ? WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS : -1;
+ /* Set up join scan parameters */
+ ext_join_params->scan.scan_type = -1;
+ ext_join_params->scan.nprobes = chan_cnt ?
+ (ext_join_params->scan.active_time/WL_SCAN_JOIN_PROBE_INTERVAL_MS) : -1;
+ ext_join_params->scan.home_time = -1;
+
+ if (sme->bssid)
+ memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN);
+ else
+ memcpy(&ext_join_params->assoc.bssid, &ether_bcast, ETH_ALEN);
+ ext_join_params->assoc.chanspec_num = chan_cnt;
+ if (chan_cnt) {
+ if (cfg->channel) {
+ /*
+ * Use the channel provided by userspace
+ */
+ u16 channel, band, bw, ctl_sb;
+ chanspec_t chspec;
+ channel = cfg->channel;
+ band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G
+ : WL_CHANSPEC_BAND_5G;
+
+ /* Get min_bw set for the interface */
+ bw = wl_cfg80211_ulb_get_min_bw_chspec(dev->ieee80211_ptr, bssidx);
+ if (bw == INVCHANSPEC) {
+ WL_ERR(("Invalid chanspec \n"));
+ kfree(ext_join_params);
+ return BCME_ERROR;
+ }
+
+ ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
+ chspec = (channel | band | bw | ctl_sb);
+ ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
+ ext_join_params->assoc.chanspec_list[0] |= chspec;
+ ext_join_params->assoc.chanspec_list[0] =
+ wl_chspec_host_to_driver(ext_join_params->assoc.chanspec_list[0]);
+ }
+ }
+ ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num);
+ if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
+ WL_INFORM(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
+ ext_join_params->ssid.SSID_len));
+ }
+ wl_set_drv_status(cfg, CONNECTING, dev);
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ kfree(ext_join_params);
+ return BCME_ERROR;
+ }
+ err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size,
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+
+ if (cfg->rcc_enabled) {
+ WL_ERR(("Connecting with" MACDBG " ssid \"%s\", len (%d) with rcc channels \n\n",
+ MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
+ ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len));
+ } else {
+ WL_ERR(("Connecting with" MACDBG " ssid \"%s\", len (%d) channel=%d\n\n",
+ MAC2STRDBG((u8*)(&ext_join_params->assoc.bssid)),
+ ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len, cfg->channel));
+ }
+
+ kfree(ext_join_params);
+ if (err) {
+ wl_clr_drv_status(cfg, CONNECTING, dev);
+ if (err == BCME_UNSUPPORTED) {
+ WL_DBG(("join iovar is not supported\n"));
+ goto set_ssid;
+ } else {
+ WL_ERR(("error (%d)\n", err));
+ goto exit;
+ }
+ } else
+ goto exit;
+
+set_ssid:
+ memset(&join_params, 0, sizeof(join_params));
+ join_params_size = sizeof(join_params.ssid);
+
+ join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len);
+ memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
+ join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
+ wl_update_prof(cfg, dev, NULL, &join_params.ssid, WL_PROF_SSID);
+ if (sme->bssid)
+ memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN);
+ else
+ memcpy(&join_params.params.bssid, &ether_bcast, ETH_ALEN);
+
+ if (wl_ch_to_chanspec(dev, cfg->channel, &join_params, &join_params_size) < 0) {
+ WL_ERR(("Invalid chanspec\n"));
+ return -EINVAL;
+ }
+
+ WL_DBG(("join_param_size %zu\n", join_params_size));
+
+ if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
+ WL_INFORM(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
+ join_params.ssid.SSID_len));
+ }
+ wl_set_drv_status(cfg, CONNECTING, dev);
+ err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true);
+ if (err) {
+ WL_ERR(("error (%d)\n", err));
+ wl_clr_drv_status(cfg, CONNECTING, dev);
+ }
+exit:
+ return err;
+}
+
+static s32
+wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ scb_val_t scbval;
+ bool act = false;
+ s32 err = 0;
+ u8 *curbssid;
+#ifdef CUSTOM_SET_CPUCORE
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+#endif /* CUSTOM_SET_CPUCORE */
+ WL_ERR(("Reason %d\n", reason_code));
+ RETURN_EIO_IF_NOT_UP(cfg);
+ act = *(bool *) wl_read_prof(cfg, dev, WL_PROF_ACT);
+ curbssid = wl_read_prof(cfg, dev, WL_PROF_BSSID);
+#ifdef ESCAN_RESULT_PATCH
+ if (wl_get_drv_status(cfg, CONNECTING, dev) && curbssid &&
+ (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0)) {
+ WL_ERR(("Disconnecting from connecting device: " MACDBG "\n",
+ MAC2STRDBG(curbssid)));
+ act = true;
+ }
+#endif /* ESCAN_RESULT_PATCH */
+
+ if (act) {
+ /*
+ * Cancel ongoing scan to sync up with sme state machine of cfg80211.
+ */
+#if !defined(ESCAN_RESULT_PATCH)
+ /* Let scan aborted by F/W */
+ if (cfg->scan_request) {
+ WL_TRACE_HW4(("Aborting the scan! \n"));
+ wl_notify_escan_complete(cfg, dev, true, true);
+ }
+#endif /* ESCAN_RESULT_PATCH */
+ if (wl_get_drv_status(cfg, CONNECTING, dev) ||
+ wl_get_drv_status(cfg, CONNECTED, dev)) {
+ wl_set_drv_status(cfg, DISCONNECTING, dev);
+ scbval.val = reason_code;
+ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
+ scbval.val = htod32(scbval.val);
+ err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
+ sizeof(scb_val_t), true);
+ if (unlikely(err)) {
+ wl_clr_drv_status(cfg, DISCONNECTING, dev);
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+#if defined(BCM4358_CHIP)
+ WL_ERR(("Wait for complete of disconnecting \n"));
+ OSL_SLEEP(200);
+#endif /* BCM4358_CHIP */
+ }
+ }
+#ifdef CUSTOM_SET_CPUCORE
+ /* set default cpucore */
+ if (dev == bcmcfg_to_prmry_ndev(cfg)) {
+ dhd->chan_isvht80 &= ~DHD_FLAG_STA_MODE;
+ if (!(dhd->chan_isvht80))
+ dhd_set_cpucore(dhd, FALSE);
+ }
+#endif /* CUSTOM_SET_CPUCORE */
+
+ return err;
+}
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+static s32
+wl_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
+ enum nl80211_tx_power_setting type, s32 mbm)
+#else
+static s32
+wl_cfg80211_set_tx_power(struct wiphy *wiphy,
+ enum nl80211_tx_power_setting type, s32 dbm)
+#endif /* WL_CFG80211_P2P_DEV_IF */
+{
+
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ s32 err = 0;
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ s32 dbm = MBM_TO_DBM(mbm);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || \
+ defined(WL_COMPAT_WIRELESS) || defined(WL_SUPPORT_BACKPORTED_KPATCHES)
+ dbm = MBM_TO_DBM(dbm);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+ switch (type) {
+ case NL80211_TX_POWER_AUTOMATIC:
+ break;
+ case NL80211_TX_POWER_LIMITED:
+ if (dbm < 0) {
+ WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n"));
+ return -EINVAL;
+ }
+ break;
+ case NL80211_TX_POWER_FIXED:
+ if (dbm < 0) {
+ WL_ERR(("TX_POWER_FIXED - dbm is negative..\n"));
+ return -EINVAL;
+ }
+ break;
+ }
+
+ err = wl_set_tx_power(ndev, type, dbm);
+ if (unlikely(err)) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+
+ cfg->conf->tx_power = dbm;
+
+ return err;
+}
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy,
+ struct wireless_dev *wdev, s32 *dbm)
+#else
+static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
+#endif /* WL_CFG80211_P2P_DEV_IF */
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ s32 err = 0;
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+ err = wl_get_tx_power(ndev, dbm);
+ if (unlikely(err))
+ WL_ERR(("error (%d)\n", err));
+
+ return err;
+}
+
+static s32
+wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, bool unicast, bool multicast)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ u32 index;
+ s32 wsec;
+ s32 err = 0;
+ s32 bssidx;
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+
+ WL_DBG(("key index (%d)\n", key_idx));
+ RETURN_EIO_IF_NOT_UP(cfg);
+ err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
+ return err;
+ }
+ if (wsec == WEP_ENABLED) {
+ /* Just select a new current key */
+ index = (u32) key_idx;
+ index = htod32(index);
+ err = wldev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index,
+ sizeof(index), true);
+ if (unlikely(err)) {
+ WL_ERR(("error (%d)\n", err));
+ }
+ }
+ return err;
+}
+
+static s32
+wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, const u8 *mac_addr, struct key_params *params)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct wl_wsec_key key;
+ s32 err = 0;
+ s32 bssidx;
+ s32 mode = wl_get_mode_by_netdev(cfg, dev);
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+ memset(&key, 0, sizeof(key));
+ key.index = (u32) key_idx;
+
+ if (!ETHER_ISMULTI(mac_addr))
+ memcpy((char *)&key.ea, (const void *)mac_addr, ETHER_ADDR_LEN);
+ key.len = (u32) params->key_len;
+
+ /* check for key index change */
+ if (key.len == 0) {
+ /* key delete */
+ swap_key_from_BE(&key);
+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("key delete error (%d)\n", err));
+ return err;
+ }
+ } else {
+ if (key.len > sizeof(key.data)) {
+ WL_ERR(("Invalid key length (%d)\n", key.len));
+ return -EINVAL;
+ }
+ WL_DBG(("Setting the key index %d\n", key.index));
+ memcpy(key.data, params->key, key.len);
+
+ if ((mode == WL_MODE_BSS) &&
+ (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
+ u8 keybuf[8];
+ memcpy(keybuf, &key.data[24], sizeof(keybuf));
+ memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
+ memcpy(&key.data[16], keybuf, sizeof(keybuf));
+ }
+
+ /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
+ if (params->seq && params->seq_len == 6) {
+ /* rx iv */
+ u8 *ivptr;
+ ivptr = (u8 *) params->seq;
+ key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
+ (ivptr[3] << 8) | ivptr[2];
+ key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
+ key.iv_initialized = true;
+ }
+
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key.algo = CRYPTO_ALGO_WEP1;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ key.algo = CRYPTO_ALGO_WEP128;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ key.algo = CRYPTO_ALGO_TKIP;
+ WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
+ break;
+#ifdef BCMWAPI_WPI
+ case WLAN_DHD_CIPHER_SUITE_SMS4:
+ key.algo = CRYPTO_ALGO_SMS4;
+ WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
+ break;
+#endif
+ default:
+ WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
+ return -EINVAL;
+ }
+ swap_key_from_BE(&key);
+ /* need to guarantee EAPOL 4/4 send out before set key */
+ dhd_wait_pend8021x(dev);
+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ return err;
+ }
+ }
+ return err;
+}
+
+int
+wl_cfg80211_enable_roam_offload(struct net_device *dev, int enable)
+{
+ int err;
+ wl_eventmsg_buf_t ev_buf;
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+
+ if (dev != bcmcfg_to_prmry_ndev(cfg)) {
+ /* roam offload is only for the primary device */
+ return -1;
+ }
+ err = wldev_iovar_setint(dev, "roam_offload", enable);
+ if (err)
+ return err;
+
+ if (enable) {
+ err = wldev_iovar_setint(dev, "sup_wpa_tmo", IDSUP_4WAY_HANDSHAKE_TIMEOUT);
+ if (err) {
+ WL_INFORM(("Setting 'sup_wpa_tmo' failed, err=%d\n", err));
+ }
+ }
+
+ bzero(&ev_buf, sizeof(wl_eventmsg_buf_t));
+ wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_REQ_IE, !enable);
+ wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ASSOC_RESP_IE, !enable);
+ wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_REASSOC, !enable);
+ wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_JOIN, !enable);
+ wl_cfg80211_add_to_eventbuffer(&ev_buf, WLC_E_ROAM, !enable);
+ err = wl_cfg80211_apply_eventbuffer(dev, cfg, &ev_buf);
+ if (!err) {
+ cfg->roam_offload = enable;
+ }
+ return err;
+}
+
+#if defined(WL_VIRTUAL_APSTA)
+int
+wl_cfg80211_interface_create(struct net_device *dev, char *name)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ bcm_struct_cfgdev *new_cfgdev;
+
+ new_cfgdev = wl_cfg80211_create_iface(cfg->wdev->wiphy,
+ NL80211_IFTYPE_STATION, NULL, name);
+ if (!new_cfgdev) {
+ return BCME_ERROR;
+ }
+ else {
+ WL_DBG(("Iface %s created successfuly\n", name));
+ return BCME_OK;
+ }
+}
+
+int
+wl_cfg80211_interface_delete(struct net_device *dev, char *name)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ struct net_info *iter, *next;
+ int err = BCME_ERROR;
+
+ if (name == NULL) {
+ return BCME_ERROR;
+ }
+
+ for_each_ndev(cfg, iter, next) {
+ if (iter->ndev) {
+ if (strcmp(iter->ndev->name, name) == 0) {
+ err = wl_cfg80211_del_iface(cfg->wdev->wiphy,
+ ndev_to_cfgdev(iter->ndev));
+ break;
+ }
+ }
+ }
+ if (!err) {
+ WL_DBG(("Iface %s deleted successfuly", name));
+ }
+ return err;
+}
+
+#if defined(PKT_FILTER_SUPPORT) && defined(APSTA_BLOCK_ARP_DURING_DHCP)
+void
+wl_cfg80211_block_arp(struct net_device *dev, int enable)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
+
+ if (!dhd_pkt_filter_enable) {
+ WL_INFORM(("Packet filter isn't enabled\n"));
+ return;
+ }
+
+ /* Block/Unblock ARP frames only if STA is connected to
+ * the upstream AP in case of STA+SoftAP Concurrenct mode
+ */
+ if (!wl_get_drv_status(cfg, CONNECTED, dev)) {
+ WL_INFORM(("STA doesn't connected to upstream AP\n"));
+ return;
+ }
+
+ if (enable) {
+ WL_DBG(("Enable ARP Filter\n"));
+ /* Add ARP filter */
+ dhd_packet_filter_add_remove(dhdp, TRUE, DHD_BROADCAST_ARP_FILTER_NUM);
+
+ /* Enable ARP packet filter - blacklist */
+ dhd_master_mode = FALSE;
+ dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
+ TRUE, dhd_master_mode);
+ } else {
+ WL_DBG(("Disable ARP Filter\n"));
+ /* Disable ARP packet filter */
+ dhd_master_mode = TRUE;
+ dhd_pktfilter_offload_enable(dhdp, dhdp->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM],
+ FALSE, dhd_master_mode);
+
+ /* Delete ARP filter */
+ dhd_packet_filter_add_remove(dhdp, FALSE, DHD_BROADCAST_ARP_FILTER_NUM);
+ }
+}
+#endif /* PKT_FILTER_SUPPORT && APSTA_BLOCK_ARP_DURING_DHCP */
+#endif /* defined (WL_VIRTUAL_APSTA) */
+
+static s32
+wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr,
+ struct key_params *params)
+{
+ struct wl_wsec_key key;
+ s32 val = 0;
+ s32 wsec = 0;
+ s32 err = 0;
+ u8 keybuf[8];
+ s32 bssidx = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 mode = wl_get_mode_by_netdev(cfg, dev);
+ WL_DBG(("key index (%d)\n", key_idx));
+ RETURN_EIO_IF_NOT_UP(cfg);
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from dev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+
+ if (mac_addr &&
+ ((params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
+ (params->cipher != WLAN_CIPHER_SUITE_WEP104))) {
+ wl_add_keyext(wiphy, dev, key_idx, mac_addr, params);
+ goto exit;
+ }
+ memset(&key, 0, sizeof(key));
+ /* Clear any buffered wep key */
+ memset(&cfg->wep_key, 0, sizeof(struct wl_wsec_key));
+
+ key.len = (u32) params->key_len;
+ key.index = (u32) key_idx;
+
+ if (unlikely(key.len > sizeof(key.data))) {
+ WL_ERR(("Too long key length (%u)\n", key.len));
+ return -EINVAL;
+ }
+ memcpy(key.data, params->key, key.len);
+
+ key.flags = WL_PRIMARY_KEY;
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key.algo = CRYPTO_ALGO_WEP1;
+ val = WEP_ENABLED;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ key.algo = CRYPTO_ALGO_WEP128;
+ val = WEP_ENABLED;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ key.algo = CRYPTO_ALGO_TKIP;
+ val = TKIP_ENABLED;
+ /* wpa_supplicant switches the third and fourth quarters of the TKIP key */
+ if (mode == WL_MODE_BSS) {
+ bcopy(&key.data[24], keybuf, sizeof(keybuf));
+ bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
+ bcopy(keybuf, &key.data[16], sizeof(keybuf));
+ }
+ WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ val = AES_ENABLED;
+ WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ key.algo = CRYPTO_ALGO_AES_CCM;
+ val = AES_ENABLED;
+ WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
+ break;
+#ifdef BCMWAPI_WPI
+ case WLAN_DHD_CIPHER_SUITE_SMS4:
+ key.algo = CRYPTO_ALGO_SMS4;
+ WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
+ val = SMS4_ENABLED;
+ break;
+#endif /* BCMWAPI_WPI */
+ default:
+ WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
+ return -EINVAL;
+ }
+
+ /* Set the new key/index */
+ if ((mode == WL_MODE_IBSS) && (val & (TKIP_ENABLED | AES_ENABLED))) {
+ WL_ERR(("IBSS KEY setted\n"));
+ wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_NONE);
+ }
+ swap_key_from_BE(&key);
+ if ((params->cipher == WLAN_CIPHER_SUITE_WEP40) ||
+ (params->cipher == WLAN_CIPHER_SUITE_WEP104)) {
+ /*
+ * For AP role, since we are doing a wl down before bringing up AP,
+ * the plumbed keys will be lost. So for AP once we bring up AP, we
+ * need to plumb keys again. So buffer the keys for future use. This
+ * is more like a WAR. If firmware later has the capability to do
+ * interface upgrade without doing a "wl down" and "wl apsta 0", then
+ * this will not be required.
+ */
+ WL_DBG(("Buffering WEP Keys \n"));
+ memcpy(&cfg->wep_key, &key, sizeof(struct wl_wsec_key));
+ }
+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
+ WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ return err;
+ }
+
+exit:
+ err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("get wsec error (%d)\n", err));
+ return err;
+ }
+
+ wsec |= val;
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("set wsec error (%d)\n", err));
+ return err;
+ }
+
+ return err;
+}
+
+static s32
+wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr)
+{
+ struct wl_wsec_key key;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 err = 0;
+ s32 bssidx;
+
+ WL_DBG(("Enter. key_idx: %d\n", key_idx));
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+
+ if ((key_idx >= DOT11_MAX_DEFAULT_KEYS) && (key_idx < DOT11_MAX_DEFAULT_KEYS+2))
+ return -EINVAL;
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+ memset(&key, 0, sizeof(key));
+
+ key.flags = WL_PRIMARY_KEY;
+ key.algo = CRYPTO_ALGO_OFF;
+ key.index = (u32) key_idx;
+
+ /* Set the new key/index */
+ swap_key_from_BE(&key);
+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), cfg->ioctl_buf,
+ WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ if (err == -EINVAL) {
+ if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
+ /* we ignore this key index in this case */
+ WL_DBG(("invalid key index (%d)\n", key_idx));
+ }
+ } else {
+ WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ }
+ return err;
+ }
+ return err;
+}
+
+static s32
+wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
+ u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
+ void (*callback) (void *cookie, struct key_params * params))
+{
+ struct key_params params;
+ struct wl_wsec_key key;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct wl_security *sec;
+ s32 wsec;
+ s32 err = 0;
+ s32 bssidx;
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+ WL_DBG(("key index (%d)\n", key_idx));
+ RETURN_EIO_IF_NOT_UP(cfg);
+ memset(&key, 0, sizeof(key));
+ key.index = key_idx;
+ swap_key_to_BE(&key);
+ memset(&params, 0, sizeof(params));
+ params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len);
+ memcpy((void *)params.key, key.data, params.key_len);
+
+ err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
+ return err;
+ }
+ switch (WSEC_ENABLED(wsec)) {
+ case WEP_ENABLED:
+ sec = wl_read_prof(cfg, dev, WL_PROF_SEC);
+ if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
+ params.cipher = WLAN_CIPHER_SUITE_WEP40;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
+ } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
+ params.cipher = WLAN_CIPHER_SUITE_WEP104;
+ WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
+ }
+ break;
+ case TKIP_ENABLED:
+ params.cipher = WLAN_CIPHER_SUITE_TKIP;
+ WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
+ break;
+ case AES_ENABLED:
+ params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
+ WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
+ break;
+#ifdef BCMWAPI_WPI
+ case SMS4_ENABLED:
+ params.cipher = WLAN_DHD_CIPHER_SUITE_SMS4;
+ WL_DBG(("WLAN_CIPHER_SUITE_SMS4\n"));
+ break;
+#endif
+ default:
+ WL_ERR(("Invalid algo (0x%x)\n", wsec));
+ return -EINVAL;
+ }
+
+ callback(cookie, &params);
+ return err;
+}
+
+static s32
+wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
+ struct net_device *dev, u8 key_idx)
+{
+ WL_INFORM(("Not supported\n"));
+ return -EOPNOTSUPP;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static s32
+wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *mac, struct station_info *sinfo)
+#else
+static s32
+wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_info *sinfo)
+#endif
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ scb_val_t scb_val;
+ s32 rssi;
+ s32 rate;
+ s32 err = 0;
+ sta_info_t *sta;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS)
+ s8 eabuf[ETHER_ADDR_STR_LEN];
+#endif
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+ bool fw_assoc_state = FALSE;
+ u32 dhd_assoc_state = 0;
+ RETURN_EIO_IF_NOT_UP(cfg);
+ if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP) {
+ err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac,
+ ETHER_ADDR_LEN, cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
+ if (err < 0) {
+ WL_ERR(("GET STA INFO failed, %d\n", err));
+ return err;
+ }
+ sinfo->filled = STA_INFO_BIT(INFO_INACTIVE_TIME);
+ sta = (sta_info_t *)cfg->ioctl_buf;
+ sta->len = dtoh16(sta->len);
+ sta->cap = dtoh16(sta->cap);
+ sta->flags = dtoh32(sta->flags);
+ sta->idle = dtoh32(sta->idle);
+ sta->in = dtoh32(sta->in);
+ sinfo->inactive_time = sta->idle * 1000;
+
+ sinfo->filled |= (STA_INFO_BIT(INFO_RX_PACKETS) |
+ STA_INFO_BIT(INFO_RX_DROP_MISC) |
+ STA_INFO_BIT(INFO_TX_PACKETS) |
+ STA_INFO_BIT(INFO_TX_FAILED) |
+ STA_INFO_BIT(INFO_RX_BYTES) |
+ STA_INFO_BIT(INFO_TX_BYTES));
+ sinfo->rx_packets = sta->rx_ucast_pkts;
+ sinfo->rx_dropped_misc = sta->rx_decrypt_failures;
+ sinfo->tx_packets = sta->tx_pkts;
+ sinfo->tx_failed = sta->tx_failures;
+ sinfo->rx_bytes = sta->rx_tot_bytes;
+ sinfo->tx_bytes = sta->tx_tot_bytes;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) || defined(WL_COMPAT_WIRELESS)
+ if (sta->flags & WL_STA_ASSOC) {
+ sinfo->filled |= STA_INFO_BIT(INFO_CONNECTED_TIME);
+ sinfo->connected_time = sta->in;
+ }
+ WL_INFORM(("STA %s : idle time : %d sec, connected time :%d ms\n",
+ bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time,
+ sta->idle * 1000));
+#endif
+ } else if (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_BSS ||
+ wl_get_mode_by_netdev(cfg, dev) == WL_MODE_IBSS) {
+ get_pktcnt_t pktcnt;
+ u8 *curmacp;
+
+ if (cfg->roam_offload) {
+ struct ether_addr bssid;
+ err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+ if (err) {
+ WL_ERR(("Failed to get current BSSID\n"));
+ } else {
+ if (!ETHER_ISNULLADDR(&bssid.octet) &&
+ memcmp(mac, &bssid.octet, ETHER_ADDR_LEN) != 0) {
+ /* roaming is detected */
+ err = wl_cfg80211_delayed_roam(cfg, dev, &bssid);
+ if (err)
+ WL_ERR(("Failed to handle the delayed roam, "
+ "err=%d", err));
+ mac = (u8 *)bssid.octet;
+ }
+ }
+ }
+ dhd_assoc_state = wl_get_drv_status(cfg, CONNECTED, dev);
+ fw_assoc_state = dhd_is_associated(dhd, 0, &err);
+ if (!dhd_assoc_state || !fw_assoc_state) {
+ WL_ERR(("NOT assoc\n"));
+ if (err == -ERESTARTSYS)
+ return err;
+ if (!dhd_assoc_state) {
+ WL_TRACE_HW4(("drv state is not connected \n"));
+ }
+ if (!fw_assoc_state) {
+ WL_TRACE_HW4(("fw state is not associated \n"));
+ }
+ /* Disconnect due to fw is not associated for FW_ASSOC_WATCHDOG_TIME ms.
+ * 'err == 0' of dhd_is_associated() and '!fw_assoc_state'
+ * means that BSSID is null.
+ */
+ if (dhd_assoc_state && !fw_assoc_state && !err) {
+ if (!fw_assoc_watchdog_started) {
+ fw_assoc_watchdog_ms = OSL_SYSUPTIME();
+ fw_assoc_watchdog_started = TRUE;
+ WL_TRACE_HW4(("fw_assoc_watchdog_started \n"));
+ } else {
+ if (OSL_SYSUPTIME() - fw_assoc_watchdog_ms >
+ FW_ASSOC_WATCHDOG_TIME) {
+ fw_assoc_watchdog_started = FALSE;
+ err = -ENODEV;
+ WL_TRACE_HW4(("fw is not associated for %d ms \n",
+ (OSL_SYSUPTIME() - fw_assoc_watchdog_ms)));
+ goto get_station_err;
+ }
+ }
+ }
+ err = -ENODEV;
+ return err;
+ }
+ fw_assoc_watchdog_started = FALSE;
+ curmacp = wl_read_prof(cfg, dev, WL_PROF_BSSID);
+ if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
+ WL_ERR(("Wrong Mac address: "MACDBG" != "MACDBG"\n",
+ MAC2STRDBG(mac), MAC2STRDBG(curmacp)));
+ }
+
+ /* Report the current tx rate */
+ err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
+ if (err) {
+ WL_ERR(("Could not get rate (%d)\n", err));
+ } else {
+#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
+ int rxpktglom;
+#endif
+ rate = dtoh32(rate);
+ sinfo->filled |= STA_INFO_BIT(INFO_TX_BITRATE);
+ sinfo->txrate.legacy = rate * 5;
+ WL_DBG(("Rate %d Mbps\n", (rate / 2)));
+#if defined(USE_DYNAMIC_MAXPKT_RXGLOM)
+ rxpktglom = ((rate/2) > 150) ? 20 : 10;
+
+ if (maxrxpktglom != rxpktglom) {
+ maxrxpktglom = rxpktglom;
+ WL_DBG(("Rate %d Mbps, update bus:maxtxpktglom=%d\n", (rate/2),
+ maxrxpktglom));
+ err = wldev_iovar_setbuf(dev, "bus:maxtxpktglom",
+ (char*)&maxrxpktglom, 4, cfg->ioctl_buf,
+ WLC_IOCTL_MAXLEN, NULL);
+ if (err < 0) {
+ WL_ERR(("set bus:maxtxpktglom failed, %d\n", err));
+ }
+ }
+#endif
+ }
+
+ memset(&scb_val, 0, sizeof(scb_val));
+ scb_val.val = 0;
+ err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val,
+ sizeof(scb_val_t), false);
+ if (err) {
+ WL_ERR(("Could not get rssi (%d)\n", err));
+ goto get_station_err;
+ }
+ rssi = wl_rssi_offset(dtoh32(scb_val.val));
+ sinfo->filled |= STA_INFO_BIT(INFO_SIGNAL);
+ sinfo->signal = rssi;
+ WL_DBG(("RSSI %d dBm\n", rssi));
+ err = wldev_ioctl(dev, WLC_GET_PKTCNTS, &pktcnt,
+ sizeof(pktcnt), false);
+ if (!err) {
+ sinfo->filled |= (STA_INFO_BIT(INFO_RX_PACKETS) |
+ STA_INFO_BIT(INFO_RX_DROP_MISC) |
+ STA_INFO_BIT(INFO_TX_PACKETS) |
+ STA_INFO_BIT(INFO_TX_FAILED));
+ sinfo->rx_packets = pktcnt.rx_good_pkt;
+ sinfo->rx_dropped_misc = pktcnt.rx_bad_pkt;
+ sinfo->tx_packets = pktcnt.tx_good_pkt;
+ sinfo->tx_failed = pktcnt.tx_bad_pkt;
+ }
+get_station_err:
+ if (err && (err != -ERESTARTSYS)) {
+ /* Disconnect due to zero BSSID or error to get RSSI */
+ WL_ERR(("force cfg80211_disconnected: %d\n", err));
+ wl_clr_drv_status(cfg, CONNECTED, dev);
+ CFG80211_DISCONNECTED(dev, 0, NULL, 0, false, GFP_KERNEL);
+ wl_link_down(cfg);
+ }
+ }
+ else {
+ WL_ERR(("Invalid device mode %d\n", wl_get_mode_by_netdev(cfg, dev)));
+ }
+
+ return err;
+}
+
+static s32
+wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ bool enabled, s32 timeout)
+{
+ s32 pm;
+ s32 err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_info *_net_info = wl_get_netinfo_by_netdev(cfg, dev);
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+ WL_DBG(("Enter\n"));
+ if (cfg->p2p_net == dev || _net_info == NULL ||
+ !wl_get_drv_status(cfg, CONNECTED, dev) ||
+ (wl_get_mode_by_netdev(cfg, dev) != WL_MODE_BSS &&
+ wl_get_mode_by_netdev(cfg, dev) != WL_MODE_IBSS)) {
+ return err;
+ }
+ /* Enlarge pm_enable_work */
+ wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_LONG);
+
+ pm = enabled ? PM_FAST : PM_OFF;
+ if (_net_info->pm_block) {
+ WL_ERR(("%s:Do not enable the power save for pm_block %d\n",
+ dev->name, _net_info->pm_block));
+ pm = PM_OFF;
+ }
+ pm = htod32(pm);
+ WL_DBG(("%s:power save %s\n", dev->name, (pm ? "enabled" : "disabled")));
+ err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true);
+ if (unlikely(err)) {
+ if (err == -ENODEV)
+ WL_DBG(("net_device is not ready yet\n"));
+ else
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+ wl_cfg80211_update_power_mode(dev);
+ return err;
+}
+
+void wl_cfg80211_update_power_mode(struct net_device *dev)
+{
+ int err, pm = -1;
+
+ err = wldev_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm), true);
+ if (err)
+ WL_ERR(("%s:error (%d)\n", __FUNCTION__, err));
+ else if (pm != -1 && dev->ieee80211_ptr)
+ dev->ieee80211_ptr->ps = (pm == PM_OFF) ? false : true;
+}
+
+void wl_cfg80211_set_passive_scan(struct net_device *dev, char *command)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+
+ if (strcmp(command, "SCAN-ACTIVE") == 0) {
+ cfg->active_scan = 1;
+ } else if (strcmp(command, "SCAN-PASSIVE") == 0) {
+ cfg->active_scan = 0;
+ } else
+ WL_ERR(("Unknown command \n"));
+}
+
+static __used u32 wl_find_msb(u16 bit16)
+{
+ u32 ret = 0;
+
+ if (bit16 & 0xff00) {
+ ret += 8;
+ bit16 >>= 8;
+ }
+
+ if (bit16 & 0xf0) {
+ ret += 4;
+ bit16 >>= 4;
+ }
+
+ if (bit16 & 0xc) {
+ ret += 2;
+ bit16 >>= 2;
+ }
+
+ if (bit16 & 2)
+ ret += bit16 & 2;
+ else if (bit16)
+ ret += bit16;
+
+ return ret;
+}
+
+static s32 wl_cfg80211_resume(struct wiphy *wiphy)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ s32 err = BCME_OK;
+
+ if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
+ WL_INFORM(("device is not ready\n"));
+ return err;
+ }
+
+ return err;
+}
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
+static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
+#else
+static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
+#endif /* KERNEL_VERSION(2, 6, 39) || WL_COMPAT_WIRELES */
+{
+ s32 err = BCME_OK;
+#ifdef DHD_CLEAR_ON_SUSPEND
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_info *iter, *next;
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ unsigned long flags;
+ if (unlikely(!wl_get_drv_status(cfg, READY, ndev))) {
+ WL_INFORM(("device is not ready : status (%d)\n",
+ (int)cfg->status));
+ return err;
+ }
+ for_each_ndev(cfg, iter, next) {
+ /* p2p discovery iface doesn't have a ndev associated with it (for kernel > 3.8) */
+ if (iter->ndev)
+ wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
+ }
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+ if (cfg->scan_request) {
+ cfg80211_scan_done(cfg->scan_request, true);
+ cfg->scan_request = NULL;
+ }
+ for_each_ndev(cfg, iter, next) {
+ if (iter->ndev) {
+ wl_clr_drv_status(cfg, SCANNING, iter->ndev);
+ wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
+ }
+ }
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+ for_each_ndev(cfg, iter, next) {
+ if (iter->ndev) {
+ if (wl_get_drv_status(cfg, CONNECTING, iter->ndev)) {
+ wl_bss_connect_done(cfg, iter->ndev, NULL, NULL, false);
+ }
+ }
+ }
+#endif /* DHD_CLEAR_ON_SUSPEND */
+
+
+ return err;
+}
+
+static s32
+wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
+ s32 err)
+{
+ int i, j;
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
+
+ if (!pmk_list) {
+ WL_INFORM(("pmk_list is NULL\n"));
+ return -EINVAL;
+ }
+ /* pmk list is supported only for STA interface i.e. primary interface
+ * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
+ */
+ if (primary_dev != dev) {
+ WL_INFORM(("Not supporting Flushing pmklist on virtual"
+ " interfaces than primary interface\n"));
+ return err;
+ }
+
+ WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid));
+ for (i = 0; i < pmk_list->pmkids.npmkid; i++) {
+ WL_DBG(("PMKID[%d]: %pM =\n", i,
+ &pmk_list->pmkids.pmkid[i].BSSID));
+ for (j = 0; j < WPA2_PMKID_LEN; j++) {
+ WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]));
+ }
+ }
+ if (likely(!err)) {
+ err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list,
+ sizeof(*pmk_list), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ }
+
+ return err;
+}
+
+static s32
+wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_pmksa *pmksa)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 err = 0;
+ int i;
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+ for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++)
+ if (!memcmp(pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
+ ETHER_ADDR_LEN))
+ break;
+ if (i < WL_NUM_PMKIDS_MAX) {
+ memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid,
+ ETHER_ADDR_LEN);
+ memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid,
+ WPA2_PMKID_LEN);
+ if (i == cfg->pmk_list->pmkids.npmkid)
+ cfg->pmk_list->pmkids.npmkid++;
+ } else {
+ err = -EINVAL;
+ }
+ WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
+ &cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1].BSSID));
+ for (i = 0; i < WPA2_PMKID_LEN; i++) {
+ WL_DBG(("%02x\n",
+ cfg->pmk_list->pmkids.pmkid[cfg->pmk_list->pmkids.npmkid - 1].
+ PMKID[i]));
+ }
+
+ err = wl_update_pmklist(dev, cfg->pmk_list, err);
+
+ return err;
+}
+
+static s32
+wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_pmksa *pmksa)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+
+ struct _pmkid_list pmkid = {.npmkid = 0};
+ s32 err = 0;
+ int i;
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+ memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN);
+ memcpy(pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN);
+
+ WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
+ &pmkid.pmkid[0].BSSID));
+ for (i = 0; i < WPA2_PMKID_LEN; i++) {
+ WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i]));
+ }
+
+ for (i = 0; i < cfg->pmk_list->pmkids.npmkid; i++)
+ if (!memcmp
+ (pmksa->bssid, &cfg->pmk_list->pmkids.pmkid[i].BSSID,
+ ETHER_ADDR_LEN))
+ break;
+
+ if ((cfg->pmk_list->pmkids.npmkid > 0) &&
+ (i < cfg->pmk_list->pmkids.npmkid)) {
+ memset(&cfg->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t));
+ for (; i < (cfg->pmk_list->pmkids.npmkid - 1); i++) {
+ memcpy(&cfg->pmk_list->pmkids.pmkid[i].BSSID,
+ &cfg->pmk_list->pmkids.pmkid[i + 1].BSSID,
+ ETHER_ADDR_LEN);
+ memcpy(&cfg->pmk_list->pmkids.pmkid[i].PMKID,
+ &cfg->pmk_list->pmkids.pmkid[i + 1].PMKID,
+ WPA2_PMKID_LEN);
+ }
+ cfg->pmk_list->pmkids.npmkid--;
+ } else {
+ err = -EINVAL;
+ }
+
+ err = wl_update_pmklist(dev, cfg->pmk_list, err);
+
+ return err;
+
+}
+
+static s32
+wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 err = 0;
+ RETURN_EIO_IF_NOT_UP(cfg);
+ memset(cfg->pmk_list, 0, sizeof(*cfg->pmk_list));
+ err = wl_update_pmklist(dev, cfg->pmk_list, err);
+ return err;
+
+}
+
+static wl_scan_params_t *
+wl_cfg80211_scan_alloc_params(struct wireless_dev *wdev, int channel,
+ int nprobes, int *out_params_size)
+{
+ wl_scan_params_t *params;
+ int params_size;
+ int num_chans;
+ int bssidx = 0;
+
+ *out_params_size = 0;
+
+ /* Our scan params only need space for 1 channel and 0 ssids */
+ params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16);
+ params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL);
+ if (params == NULL) {
+ WL_ERR(("mem alloc failed (%d bytes)\n", params_size));
+ return params;
+ }
+ memset(params, 0, params_size);
+ params->nprobes = nprobes;
+
+ num_chans = (channel == 0) ? 0 : 1;
+
+ memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
+ params->bss_type = DOT11_BSSTYPE_ANY;
+ params->scan_type = DOT11_SCANTYPE_ACTIVE;
+ params->nprobes = htod32(1);
+ params->active_time = htod32(-1);
+ params->passive_time = htod32(-1);
+ params->home_time = htod32(10);
+ if (channel == -1)
+ params->channel_list[0] = htodchanspec(channel);
+ else
+ params->channel_list[0] = wl_ch_host_to_driver(wdev, bssidx, channel);
+
+ /* Our scan params have 1 channel and 0 ssids */
+ params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
+ (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
+
+ *out_params_size = params_size; /* rtn size to the caller */
+ return params;
+}
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+static s32
+wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
+ struct ieee80211_channel *channel, unsigned int duration, u64 *cookie)
+#else
+static s32
+wl_cfg80211_remain_on_channel(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
+ struct ieee80211_channel * channel,
+ enum nl80211_channel_type channel_type,
+ unsigned int duration, u64 *cookie)
+#endif /* WL_CFG80211_P2P_DEV_IF */
+{
+ s32 target_channel;
+ s32 err = BCME_OK;
+ struct ether_addr primary_mac;
+ struct net_device *ndev = NULL;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ WL_DBG(("Enter, channel: %d, duration ms (%d) SCANNING ?? %s \n",
+ ieee80211_frequency_to_channel(channel->center_freq),
+ duration, (wl_get_drv_status(cfg, SCANNING, ndev)) ? "YES":"NO"));
+
+ if (!cfg->p2p) {
+ WL_ERR(("cfg->p2p is not initialized\n"));
+ err = BCME_ERROR;
+ goto exit;
+ }
+
+#ifdef P2P_LISTEN_OFFLOADING
+ if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
+ WL_ERR(("P2P_FIND: Discovery offload is in progress\n"));
+ return -EAGAIN;
+ }
+#endif /* P2P_LISTEN_OFFLOADING */
+
+#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
+ }
+#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+
+ target_channel = ieee80211_frequency_to_channel(channel->center_freq);
+ memcpy(&cfg->remain_on_chan, channel, sizeof(struct ieee80211_channel));
+#if defined(WL_ENABLE_P2P_IF)
+ cfg->remain_on_chan_type = channel_type;
+#endif /* WL_ENABLE_P2P_IF */
+ *cookie = wl_cfg80211_get_new_roc_id(cfg);
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ if (wl_get_drv_status(cfg, SCANNING, ndev)) {
+ struct timer_list *_timer;
+ WL_DBG(("scan is running. go to fake listen state\n"));
+
+ if (duration > LONG_LISTEN_TIME) {
+ wl_cfg80211_scan_abort(cfg);
+ } else {
+ wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
+
+ if (timer_pending(&cfg->p2p->listen_timer)) {
+ WL_DBG(("cancel current listen timer \n"));
+ del_timer_sync(&cfg->p2p->listen_timer);
+ }
+
+ _timer = &cfg->p2p->listen_timer;
+ wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
+
+ INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration, 0);
+
+ err = BCME_OK;
+ goto exit;
+ }
+ }
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+
+#ifdef WL_CFG80211_SYNC_GON
+ if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
+ /* do not enter listen mode again if we are in listen mode already for next af.
+ * remain on channel completion will be returned by waiting next af completion.
+ */
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
+#else
+ wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+ goto exit;
+ }
+#endif /* WL_CFG80211_SYNC_GON */
+ if (cfg->p2p && !cfg->p2p->on) {
+ /* In case of p2p_listen command, supplicant send remain_on_channel
+ * without turning on P2P
+ */
+ get_primary_mac(cfg, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
+ p2p_on(cfg) = true;
+ }
+
+ if (p2p_is_on(cfg)) {
+ err = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
+ if (unlikely(err)) {
+ goto exit;
+ }
+#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
+#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+ err = wl_cfgp2p_discover_listen(cfg, target_channel, duration);
+
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ if (err == BCME_OK) {
+ wl_set_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
+ } else {
+ /* if failed, firmware may be internal scanning state.
+ * so other scan request shall not abort it
+ */
+ wl_set_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
+ }
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+ /* WAR: set err = ok to prevent cookie mismatch in wpa_supplicant
+ * and expire timer will send a completion to the upper layer
+ */
+ err = BCME_OK;
+ }
+
+exit:
+ if (err == BCME_OK) {
+ WL_INFORM(("Success\n"));
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ cfg80211_ready_on_channel(cfgdev, *cookie, channel,
+ duration, GFP_KERNEL);
+#else
+ cfg80211_ready_on_channel(cfgdev, *cookie, channel,
+ channel_type, duration, GFP_KERNEL);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ } else {
+ WL_ERR(("Fail to Set (err=%d cookie:%llu)\n", err, *cookie));
+ }
+ return err;
+}
+
+static s32
+wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
+ bcm_struct_cfgdev *cfgdev, u64 cookie)
+{
+ s32 err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+
+#ifdef P2PLISTEN_AP_SAMECHN
+ struct net_device *dev;
+#endif /* P2PLISTEN_AP_SAMECHN */
+
+ RETURN_EIO_IF_NOT_UP(cfg);
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ if (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
+ WL_DBG((" enter ) on P2P dedicated discover interface\n"));
+ }
+#else
+ WL_DBG((" enter ) netdev_ifidx: %d \n", cfgdev->ifindex));
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+#ifdef P2PLISTEN_AP_SAMECHN
+ if (cfg && cfg->p2p_resp_apchn_status) {
+ dev = bcmcfg_to_prmry_ndev(cfg);
+ wl_cfg80211_set_p2p_resp_ap_chn(dev, 0);
+ cfg->p2p_resp_apchn_status = false;
+ WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
+ }
+#endif /* P2PLISTEN_AP_SAMECHN */
+
+ if (cfg->last_roc_id == cookie) {
+ wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
+ } else {
+ WL_ERR(("%s : ignore, request cookie(%llu) is not matched. (cur : %llu)\n",
+ __FUNCTION__, cookie, cfg->last_roc_id));
+ }
+
+ return err;
+}
+
+static void
+wl_cfg80211_afx_handler(struct work_struct *work)
+{
+ struct afx_hdl *afx_instance;
+ struct bcm_cfg80211 *cfg = NULL;
+ s32 ret = BCME_OK;
+
+ BCM_SET_CONTAINER_OF(afx_instance, work, struct afx_hdl, work);
+ cfg = NETDEV_GET_CFG80211_PRIV(afx_instance->dev);
+ if (afx_instance != NULL && cfg->afx_hdl->is_active) {
+ if (cfg->afx_hdl->is_listen && cfg->afx_hdl->my_listen_chan) {
+ ret = wl_cfgp2p_discover_listen(cfg, cfg->afx_hdl->my_listen_chan,
+ (100 * (1 + (RANDOM32() % 3)))); /* 100ms ~ 300ms */
+ } else {
+ ret = wl_cfgp2p_act_frm_search(cfg, cfg->afx_hdl->dev,
+ cfg->afx_hdl->bssidx, cfg->afx_hdl->peer_listen_chan,
+ NULL);
+ }
+ if (unlikely(ret != BCME_OK)) {
+ WL_ERR(("ERROR occurred! returned value is (%d)\n", ret));
+ if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL))
+ complete(&cfg->act_frm_scan);
+ }
+ }
+}
+
+static s32
+wl_cfg80211_af_searching_channel(struct bcm_cfg80211 *cfg, struct net_device *dev)
+{
+ u32 max_retry = WL_CHANNEL_SYNC_RETRY;
+ bool is_p2p_gas = false;
+
+ if (dev == NULL)
+ return -1;
+
+ WL_DBG((" enter ) \n"));
+
+ wl_set_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
+ cfg->afx_hdl->is_active = TRUE;
+
+ if (cfg->afx_hdl->pending_tx_act_frm) {
+ wl_action_frame_t *action_frame;
+ action_frame = &(cfg->afx_hdl->pending_tx_act_frm->action_frame);
+ if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len))
+ is_p2p_gas = true;
+ }
+
+ /* Loop to wait until we find a peer's channel or the
+ * pending action frame tx is cancelled.
+ */
+ while ((cfg->afx_hdl->retry < max_retry) &&
+ (cfg->afx_hdl->peer_chan == WL_INVALID)) {
+ cfg->afx_hdl->is_listen = FALSE;
+ wl_set_drv_status(cfg, SCANNING, dev);
+ WL_DBG(("Scheduling the action frame for sending.. retry %d\n",
+ cfg->afx_hdl->retry));
+ /* search peer on peer's listen channel */
+ schedule_work(&cfg->afx_hdl->work);
+ wait_for_completion_timeout(&cfg->act_frm_scan,
+ msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
+
+ if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
+ !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
+ break;
+
+ if (is_p2p_gas)
+ break;
+
+ if (cfg->afx_hdl->my_listen_chan) {
+ WL_DBG(("Scheduling Listen peer in my listen channel = %d\n",
+ cfg->afx_hdl->my_listen_chan));
+ /* listen on my listen channel */
+ cfg->afx_hdl->is_listen = TRUE;
+ schedule_work(&cfg->afx_hdl->work);
+ wait_for_completion_timeout(&cfg->act_frm_scan,
+ msecs_to_jiffies(WL_AF_SEARCH_TIME_MAX));
+ }
+ if ((cfg->afx_hdl->peer_chan != WL_INVALID) ||
+ !(wl_get_drv_status(cfg, FINDING_COMMON_CHANNEL, dev)))
+ break;
+
+ cfg->afx_hdl->retry++;
+
+ WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
+ }
+
+ cfg->afx_hdl->is_active = FALSE;
+
+ wl_clr_drv_status(cfg, SCANNING, dev);
+ wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, dev);
+
+ return (cfg->afx_hdl->peer_chan);
+}
+
+struct p2p_config_af_params {
+ s32 max_tx_retry; /* max tx retry count if tx no ack */
+ /* To make sure to send successfully action frame, we have to turn off mpc
+ * 0: off, 1: on, (-1): do nothing
+ */
+ s32 mpc_onoff;
+#ifdef WL_CFG80211_SYNC_GON
+ bool extra_listen;
+#endif
+ bool search_channel; /* 1: search peer's channel to send af */
+};
+
+static s32
+wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy,
+ wl_action_frame_t *action_frame, wl_af_params_t *af_params,
+ struct p2p_config_af_params *config_af_params)
+{
+ s32 err = BCME_OK;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ wifi_p2p_pub_act_frame_t *act_frm =
+ (wifi_p2p_pub_act_frame_t *) (action_frame->data);
+
+ /* initialize default value */
+#ifdef WL_CFG80211_SYNC_GON
+ config_af_params->extra_listen = true;
+#endif
+ config_af_params->search_channel = false;
+ config_af_params->max_tx_retry = WL_AF_TX_MAX_RETRY;
+ config_af_params->mpc_onoff = -1;
+ cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
+
+ switch (act_frm->subtype) {
+ case P2P_PAF_GON_REQ: {
+ WL_DBG(("P2P: GO_NEG_PHASE status set \n"));
+ wl_set_p2p_status(cfg, GO_NEG_PHASE);
+
+ config_af_params->mpc_onoff = 0;
+ config_af_params->search_channel = true;
+ cfg->next_af_subtype = act_frm->subtype + 1;
+
+ /* increase dwell time to wait for RESP frame */
+ af_params->dwell_time = WL_MED_DWELL_TIME;
+
+ break;
+ }
+ case P2P_PAF_GON_RSP: {
+ cfg->next_af_subtype = act_frm->subtype + 1;
+ /* increase dwell time to wait for CONF frame */
+ af_params->dwell_time = WL_MED_DWELL_TIME + 100;
+ break;
+ }
+ case P2P_PAF_GON_CONF: {
+ /* If we reached till GO Neg confirmation reset the filter */
+ WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
+ wl_clr_p2p_status(cfg, GO_NEG_PHASE);
+
+ /* turn on mpc again if go nego is done */
+ config_af_params->mpc_onoff = 1;
+
+ /* minimize dwell time */
+ af_params->dwell_time = WL_MIN_DWELL_TIME;
+
+#ifdef WL_CFG80211_SYNC_GON
+ config_af_params->extra_listen = false;
+#endif /* WL_CFG80211_SYNC_GON */
+ break;
+ }
+ case P2P_PAF_INVITE_REQ: {
+ config_af_params->search_channel = true;
+ cfg->next_af_subtype = act_frm->subtype + 1;
+
+ /* increase dwell time */
+ af_params->dwell_time = WL_MED_DWELL_TIME;
+ break;
+ }
+ case P2P_PAF_INVITE_RSP:
+ /* minimize dwell time */
+ af_params->dwell_time = WL_MIN_DWELL_TIME;
+#ifdef WL_CFG80211_SYNC_GON
+ config_af_params->extra_listen = false;
+#endif /* WL_CFG80211_SYNC_GON */
+ break;
+ case P2P_PAF_DEVDIS_REQ: {
+ if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
+ action_frame->len)) {
+ config_af_params->search_channel = true;
+ }
+
+ cfg->next_af_subtype = act_frm->subtype + 1;
+ /* maximize dwell time to wait for RESP frame */
+ af_params->dwell_time = WL_LONG_DWELL_TIME;
+ break;
+ }
+ case P2P_PAF_DEVDIS_RSP:
+ /* minimize dwell time */
+ af_params->dwell_time = WL_MIN_DWELL_TIME;
+#ifdef WL_CFG80211_SYNC_GON
+ config_af_params->extra_listen = false;
+#endif /* WL_CFG80211_SYNC_GON */
+ break;
+ case P2P_PAF_PROVDIS_REQ: {
+ if (IS_ACTPUB_WITHOUT_GROUP_ID(&act_frm->elts[0],
+ action_frame->len)) {
+ config_af_params->search_channel = true;
+ }
+
+ config_af_params->mpc_onoff = 0;
+ cfg->next_af_subtype = act_frm->subtype + 1;
+ /* increase dwell time to wait for RESP frame */
+ af_params->dwell_time = WL_MED_DWELL_TIME;
+ break;
+ }
+ case P2P_PAF_PROVDIS_RSP: {
+ cfg->next_af_subtype = P2P_PAF_GON_REQ;
+ af_params->dwell_time = WL_MIN_DWELL_TIME;
+#ifdef WL_CFG80211_SYNC_GON
+ config_af_params->extra_listen = false;
+#endif /* WL_CFG80211_SYNC_GON */
+ break;
+ }
+ default:
+ WL_DBG(("Unknown p2p pub act frame subtype: %d\n",
+ act_frm->subtype));
+ err = BCME_BADARG;
+ }
+ return err;
+}
+
+#ifdef WL11U
+static bool
+wl_cfg80211_check_DFS_channel(struct bcm_cfg80211 *cfg, wl_af_params_t *af_params,
+ void *frame, u16 frame_len)
+{
+ struct wl_scan_results *bss_list;
+ struct wl_bss_info *bi = NULL;
+ bool result = false;
+ s32 i;
+ chanspec_t chanspec;
+
+ /* If DFS channel is 52~148, check to block it or not */
+ if (af_params &&
+ (af_params->channel >= 52 && af_params->channel <= 148)) {
+ if (!wl_cfgp2p_is_p2p_action(frame, frame_len)) {
+ bss_list = cfg->bss_list;
+ bi = next_bss(bss_list, bi);
+ for_each_bss(bss_list, bi, i) {
+ chanspec = wl_chspec_driver_to_host(bi->chanspec);
+ if (CHSPEC_IS5G(chanspec) &&
+ ((bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(chanspec))
+ == af_params->channel)) {
+ result = true; /* do not block the action frame */
+ break;
+ }
+ }
+ }
+ }
+ else {
+ result = true;
+ }
+
+ WL_DBG(("result=%s", result?"true":"false"));
+ return result;
+}
+#endif /* WL11U */
+static bool
+wl_cfg80211_check_dwell_overflow(int32 requested_dwell, ulong dwell_jiffies)
+{
+ if ((requested_dwell & CUSTOM_RETRY_MASK) &&
+ (jiffies_to_msecs(jiffies - dwell_jiffies) >
+ (requested_dwell & ~CUSTOM_RETRY_MASK))) {
+ WL_ERR(("Action frame TX retry time over dwell time!\n"));
+ return true;
+ }
+ return false;
+}
+
+static bool
+wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
+ bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params,
+ wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx)
+{
+#ifdef WL11U
+ struct net_device *ndev = NULL;
+#endif /* WL11U */
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ bool ack = false;
+ u8 category, action;
+ s32 tx_retry;
+ struct p2p_config_af_params config_af_params;
+ struct net_info *netinfo;
+#ifdef VSDB
+ ulong off_chan_started_jiffies = 0;
+#endif
+ ulong dwell_jiffies = 0;
+ bool dwell_overflow = false;
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+
+ int32 requested_dwell = af_params->dwell_time;
+
+ /* Add the default dwell time
+ * Dwell time to stay off-channel to wait for a response action frame
+ * after transmitting an GO Negotiation action frame
+ */
+ af_params->dwell_time = WL_DWELL_TIME;
+
+#ifdef WL11U
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ ndev = dev;
+#else
+ ndev = ndev_to_cfgdev(cfgdev);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+#endif /* WL11U */
+
+ category = action_frame->data[DOT11_ACTION_CAT_OFF];
+ action = action_frame->data[DOT11_ACTION_ACT_OFF];
+
+ /* initialize variables */
+ tx_retry = 0;
+ cfg->next_af_subtype = P2P_PAF_SUBTYPE_INVALID;
+ config_af_params.max_tx_retry = WL_AF_TX_MAX_RETRY;
+ config_af_params.mpc_onoff = -1;
+ config_af_params.search_channel = false;
+#ifdef WL_CFG80211_SYNC_GON
+ config_af_params.extra_listen = false;
+#endif
+
+ /* config parameters */
+ /* Public Action Frame Process - DOT11_ACTION_CAT_PUBLIC */
+ if (category == DOT11_ACTION_CAT_PUBLIC) {
+ if ((action == P2P_PUB_AF_ACTION) &&
+ (action_frame_len >= sizeof(wifi_p2p_pub_act_frame_t))) {
+ /* p2p public action frame process */
+ if (BCME_OK != wl_cfg80211_config_p2p_pub_af_tx(wiphy,
+ action_frame, af_params, &config_af_params)) {
+ WL_DBG(("Unknown subtype.\n"));
+ }
+
+ } else if (action_frame_len >= sizeof(wifi_p2psd_gas_pub_act_frame_t)) {
+ /* service discovery process */
+ if (action == P2PSD_ACTION_ID_GAS_IREQ ||
+ action == P2PSD_ACTION_ID_GAS_CREQ) {
+ /* configure service discovery query frame */
+
+ config_af_params.search_channel = true;
+
+ /* save next af suptype to cancel remained dwell time */
+ cfg->next_af_subtype = action + 1;
+
+ af_params->dwell_time = WL_MED_DWELL_TIME;
+ if (requested_dwell & CUSTOM_RETRY_MASK) {
+ config_af_params.max_tx_retry =
+ (requested_dwell & CUSTOM_RETRY_MASK) >> 24;
+ af_params->dwell_time =
+ (requested_dwell & ~CUSTOM_RETRY_MASK);
+ WL_DBG(("Custom retry(%d) and dwell time(%d) is set.\n",
+ config_af_params.max_tx_retry,
+ af_params->dwell_time));
+ }
+ } else if (action == P2PSD_ACTION_ID_GAS_IRESP ||
+ action == P2PSD_ACTION_ID_GAS_CRESP) {
+ /* configure service discovery response frame */
+ af_params->dwell_time = WL_MIN_DWELL_TIME;
+ } else {
+ WL_DBG(("Unknown action type: %d\n", action));
+ }
+ } else {
+ WL_DBG(("Unknown Frame: category 0x%x, action 0x%x, length %d\n",
+ category, action, action_frame_len));
+ }
+ } else if (category == P2P_AF_CATEGORY) {
+ /* do not configure anything. it will be sent with a default configuration */
+ } else {
+ WL_DBG(("Unknown Frame: category 0x%x, action 0x%x\n",
+ category, action));
+ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
+ wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
+ return false;
+ }
+ }
+
+ /* To make sure to send successfully action frame, we have to turn off mpc */
+ if (config_af_params.mpc_onoff == 0) {
+ wldev_iovar_setint(dev, "mpc", 0);
+ }
+
+ netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx);
+ /* validate channel and p2p ies */
+ if (config_af_params.search_channel && IS_P2P_SOCIAL(af_params->channel) &&
+ netinfo && netinfo->bss.ies.probe_req_ie_len) {
+ config_af_params.search_channel = true;
+ } else {
+ config_af_params.search_channel = false;
+ }
+#ifdef WL11U
+ if (ndev == bcmcfg_to_prmry_ndev(cfg))
+ config_af_params.search_channel = false;
+#endif /* WL11U */
+
+#ifdef VSDB
+ /* if connecting on primary iface, sleep for a while before sending af tx for VSDB */
+ if (wl_get_drv_status(cfg, CONNECTING, bcmcfg_to_prmry_ndev(cfg))) {
+ OSL_SLEEP(50);
+ }
+#endif
+
+ /* if scan is ongoing, abort current scan. */
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
+ }
+
+ /* Abort P2P listen */
+ if (discover_cfgdev(cfgdev, cfg)) {
+ if (cfg->p2p_supported && cfg->p2p) {
+ wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
+ }
+ }
+
+#ifdef WL11U
+ /* handling DFS channel exceptions */
+ if (!wl_cfg80211_check_DFS_channel(cfg, af_params, action_frame->data, action_frame->len)) {
+ return false; /* the action frame was blocked */
+ }
+#endif /* WL11U */
+
+ /* set status and destination address before sending af */
+ if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
+ /* set this status to cancel the remained dwell time in rx process */
+ wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
+ }
+ wl_set_drv_status(cfg, SENDING_ACT_FRM, dev);
+ memcpy(cfg->afx_hdl->tx_dst_addr.octet,
+ af_params->action_frame.da.octet,
+ sizeof(cfg->afx_hdl->tx_dst_addr.octet));
+
+ /* save af_params for rx process */
+ cfg->afx_hdl->pending_tx_act_frm = af_params;
+
+ if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len)) {
+ WL_DBG(("Set GAS action frame config.\n"));
+ config_af_params.search_channel = false;
+ config_af_params.max_tx_retry = 1;
+ }
+
+ /* search peer's channel */
+ if (config_af_params.search_channel) {
+ /* initialize afx_hdl */
+ if ((cfg->afx_hdl->bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ goto exit;
+ }
+ cfg->afx_hdl->dev = dev;
+ cfg->afx_hdl->retry = 0;
+ cfg->afx_hdl->peer_chan = WL_INVALID;
+
+ if (wl_cfg80211_af_searching_channel(cfg, dev) == WL_INVALID) {
+ WL_ERR(("couldn't find peer's channel.\n"));
+ wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len,
+ af_params->channel);
+ goto exit;
+ }
+
+ wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
+ /*
+ * Abort scan even for VSDB scenarios. Scan gets aborted in firmware
+ * but after the check of piggyback algorithm.
+ * To take care of current piggback algo, lets abort the scan here itself.
+ */
+ wl_notify_escan_complete(cfg, dev, true, true);
+ /* Suspend P2P discovery's search-listen to prevent it from
+ * starting a scan or changing the channel.
+ */
+ if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
+ WL_ERR(("Can not disable discovery mode\n"));
+ goto exit;
+ }
+
+ /* update channel */
+ af_params->channel = cfg->afx_hdl->peer_chan;
+ }
+
+#ifdef VSDB
+ off_chan_started_jiffies = jiffies;
+#endif /* VSDB */
+
+ wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len, af_params->channel);
+
+ wl_cfgp2p_need_wait_actfrmae(cfg, action_frame->data, action_frame->len, true);
+
+ dwell_jiffies = jiffies;
+ /* Now send a tx action frame */
+ ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ? false : true;
+ dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
+
+ /* if failed, retry it. tx_retry_max value is configure by .... */
+ while ((ack == false) && (tx_retry++ < config_af_params.max_tx_retry) &&
+ !dwell_overflow) {
+#ifdef VSDB
+ if (af_params->channel) {
+ if (jiffies_to_msecs(jiffies - off_chan_started_jiffies) >
+ OFF_CHAN_TIME_THRESHOLD_MS) {
+ WL_AF_TX_KEEP_PRI_CONNECTION_VSDB(cfg);
+ off_chan_started_jiffies = jiffies;
+ } else
+ OSL_SLEEP(AF_RETRY_DELAY_TIME);
+ }
+#endif /* VSDB */
+ ack = wl_cfgp2p_tx_action_frame(cfg, dev, af_params, bssidx) ?
+ false : true;
+ dwell_overflow = wl_cfg80211_check_dwell_overflow(requested_dwell, dwell_jiffies);
+ }
+
+ if (ack == false) {
+ WL_ERR(("Failed to send Action Frame(retry %d)\n", tx_retry));
+ }
+ WL_DBG(("Complete to send action frame\n"));
+exit:
+ /* Clear SENDING_ACT_FRM after all sending af is done */
+ wl_clr_drv_status(cfg, SENDING_ACT_FRM, dev);
+
+#ifdef WL_CFG80211_SYNC_GON
+ /* WAR: sometimes dongle does not keep the dwell time of 'actframe'.
+ * if we coundn't get the next action response frame and dongle does not keep
+ * the dwell time, go to listen state again to get next action response frame.
+ */
+ if (ack && config_af_params.extra_listen &&
+ wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM) &&
+ cfg->af_sent_channel == cfg->afx_hdl->my_listen_chan) {
+ s32 extar_listen_time;
+
+ extar_listen_time = af_params->dwell_time -
+ jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies);
+
+ if (extar_listen_time > 50) {
+ wl_set_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
+ WL_DBG(("Wait more time! actual af time:%d,"
+ "calculated extar listen:%d\n",
+ af_params->dwell_time, extar_listen_time));
+ if (wl_cfgp2p_discover_listen(cfg, cfg->af_sent_channel,
+ extar_listen_time + 100) == BCME_OK) {
+ wait_for_completion_timeout(&cfg->wait_next_af,
+ msecs_to_jiffies(extar_listen_time + 100 + 300));
+ }
+ wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, dev);
+ }
+ }
+#endif /* WL_CFG80211_SYNC_GON */
+ wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, dev);
+
+ if (cfg->afx_hdl->pending_tx_act_frm)
+ cfg->afx_hdl->pending_tx_act_frm = NULL;
+
+ WL_INFORM(("-- sending Action Frame is %s, listen chan: %d\n",
+ (ack) ? "Succeeded!!":"Failed!!", cfg->afx_hdl->my_listen_chan));
+
+
+ /* if all done, turn mpc on again */
+ if (config_af_params.mpc_onoff == 1) {
+ wldev_iovar_setint(dev, "mpc", 1);
+ }
+
+ return ack;
+}
+
+#define MAX_NUM_OF_ASSOCIATED_DEV 64
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+static s32
+wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
+ struct cfg80211_mgmt_tx_params *params, u64 *cookie)
+#else
+static s32
+wl_cfg80211_mgmt_tx(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
+ struct ieee80211_channel *channel, bool offchan,
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0))
+ enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
+#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) */
+ unsigned int wait, const u8* buf, size_t len,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
+ bool no_cck,
+#endif
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS)
+ bool dont_wait_for_ack,
+#endif
+ u64 *cookie)
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
+{
+ wl_action_frame_t *action_frame;
+ wl_af_params_t *af_params;
+ scb_val_t scb_val;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+ struct ieee80211_channel *channel = params->chan;
+ const u8 *buf = params->buf;
+ size_t len = params->len;
+#endif
+ const struct ieee80211_mgmt *mgmt;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *dev = NULL;
+ s32 err = BCME_OK;
+ s32 bssidx = 0;
+ u32 id;
+ bool ack = false;
+ s8 eabuf[ETHER_ADDR_STR_LEN];
+
+ WL_DBG(("Enter \n"));
+
+ dev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ if (!dev) {
+ WL_ERR(("dev is NULL\n"));
+ return -EINVAL;
+ }
+
+ /* set bsscfg idx for iovar (wlan0: P2PAPI_BSSCFG_PRIMARY, p2p: P2PAPI_BSSCFG_DEVICE) */
+ if (discover_cfgdev(cfgdev, cfg)) {
+ if (!cfg->p2p_supported || !cfg->p2p) {
+ WL_ERR(("P2P doesn't setup completed yet\n"));
+ return -EINVAL;
+ }
+ bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+ }
+ else {
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, cfgdev_to_wdev(cfgdev))) < 0) {
+ WL_ERR(("Find p2p index failed\n"));
+ return BCME_ERROR;
+ }
+ }
+
+ WL_DBG(("TX target bssidx=%d\n", bssidx));
+
+ if (p2p_is_on(cfg)) {
+ /* Suspend P2P discovery search-listen to prevent it from changing the
+ * channel.
+ */
+ if ((err = wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
+ WL_ERR(("Can not disable discovery mode\n"));
+ return -EFAULT;
+ }
+ }
+ *cookie = 0;
+ id = cfg->send_action_id++;
+ if (id == 0)
+ id = cfg->send_action_id++;
+ *cookie = id;
+ mgmt = (const struct ieee80211_mgmt *)buf;
+ if (ieee80211_is_mgmt(mgmt->frame_control)) {
+ if (ieee80211_is_probe_resp(mgmt->frame_control)) {
+ s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
+ s32 ie_len = len - ie_offset;
+ if ((dev == bcmcfg_to_prmry_ndev(cfg)) && cfg->p2p) {
+ bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+ }
+ wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
+ VNDR_IE_PRBRSP_FLAG, (const u8 *)(buf + ie_offset), ie_len);
+ cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
+#if defined(P2P_IE_MISSING_FIX)
+ if (!cfg->p2p_prb_noti) {
+ cfg->p2p_prb_noti = true;
+ WL_DBG(("%s: TX 802_1X Probe Response first time.\n",
+ __FUNCTION__));
+ }
+#endif
+ goto exit;
+ } else if (ieee80211_is_disassoc(mgmt->frame_control) ||
+ ieee80211_is_deauth(mgmt->frame_control)) {
+ char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
+ sizeof(struct ether_addr) + sizeof(uint)] = {0};
+ int num_associated = 0;
+ struct maclist *assoc_maclist = (struct maclist *)mac_buf;
+ if (!bcmp((const uint8 *)BSSID_BROADCAST,
+ (const struct ether_addr *)mgmt->da, ETHER_ADDR_LEN)) {
+ assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
+ err = wldev_ioctl(dev, WLC_GET_ASSOCLIST,
+ assoc_maclist, sizeof(mac_buf), false);
+ if (err < 0)
+ WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
+ else
+ num_associated = assoc_maclist->count;
+ }
+ memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN);
+ scb_val.val = mgmt->u.disassoc.reason_code;
+ err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
+ sizeof(scb_val_t), true);
+ if (err < 0)
+ WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON error %d\n", err));
+ WL_ERR(("Disconnect STA : %s scb_val.val %d\n",
+ bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf),
+ scb_val.val));
+
+ if (num_associated > 0 && ETHER_ISBCAST(mgmt->da))
+ wl_delay(400);
+
+ cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, true, GFP_KERNEL);
+ goto exit;
+
+ } else if (ieee80211_is_action(mgmt->frame_control)) {
+ /* Abort the dwell time of any previous off-channel
+ * action frame that may be still in effect. Sending
+ * off-channel action frames relies on the driver's
+ * scan engine. If a previous off-channel action frame
+ * tx is still in progress (including the dwell time),
+ * then this new action frame will not be sent out.
+ */
+/* Do not abort scan for VSDB. Scan will be aborted in firmware if necessary.
+ * And previous off-channel action frame must be ended before new af tx.
+ */
+#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ wl_notify_escan_complete(cfg, dev, true, true);
+#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+ }
+
+ } else {
+ WL_ERR(("Driver only allows MGMT packet type\n"));
+ goto exit;
+ }
+
+ af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL);
+
+ if (af_params == NULL)
+ {
+ WL_ERR(("unable to allocate frame\n"));
+ return -ENOMEM;
+ }
+
+ action_frame = &af_params->action_frame;
+
+ /* Add the packet Id */
+ action_frame->packetId = *cookie;
+ WL_DBG(("action frame %d\n", action_frame->packetId));
+ /* Add BSSID */
+ memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN);
+ memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN);
+
+ /* Add the length exepted for 802.11 header */
+ action_frame->len = len - DOT11_MGMT_HDR_LEN;
+ WL_DBG(("action_frame->len: %d\n", action_frame->len));
+
+ /* Add the channel */
+ af_params->channel =
+ ieee80211_frequency_to_channel(channel->center_freq);
+ /* Save listen_chan for searching common channel */
+ cfg->afx_hdl->peer_listen_chan = af_params->channel;
+ WL_DBG(("channel from upper layer %d\n", cfg->afx_hdl->peer_listen_chan));
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+ af_params->dwell_time = params->wait;
+#else
+ af_params->dwell_time = wait;
+#endif
+
+ memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
+
+ ack = wl_cfg80211_send_action_frame(wiphy, dev, cfgdev, af_params,
+ action_frame, action_frame->len, bssidx);
+ cfg80211_mgmt_tx_status(cfgdev, *cookie, buf, len, ack, GFP_KERNEL);
+
+ kfree(af_params);
+exit:
+ return err;
+}
+
+
+static void
+wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, bcm_struct_cfgdev *cfgdev,
+ u16 frame_type, bool reg)
+{
+
+ WL_DBG(("frame_type: %x, reg: %d\n", frame_type, reg));
+
+ if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
+ return;
+
+ return;
+}
+
+
+static s32
+wl_cfg80211_change_bss(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct bss_parameters *params)
+{
+ s32 err = 0;
+ s32 ap_isolate = 0;
+
+ if (params->use_cts_prot >= 0) {
+ }
+
+ if (params->use_short_preamble >= 0) {
+ }
+
+ if (params->use_short_slot_time >= 0) {
+ }
+
+ if (params->basic_rates) {
+ }
+
+ if (params->ap_isolate >= 0) {
+ ap_isolate = params->ap_isolate;
+ err = wldev_iovar_setint(dev, "ap_isolate", ap_isolate);
+ if (unlikely(err))
+ {
+ WL_ERR(("set ap_isolate Error (%d)\n", err));
+ }
+ }
+
+ if (params->ht_opmode >= 0) {
+ }
+
+
+ return 0;
+}
+
+static s32
+wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ s32 _chan;
+ chanspec_t chspec = 0;
+ chanspec_t fw_chspec = 0;
+ u32 bw = WL_CHANSPEC_BW_20;
+#ifdef WL11ULB
+ u32 ulb_bw = wl_cfg80211_get_ulb_bw(dev->ieee80211_ptr);
+#endif /* WL11ULB */
+
+ s32 err = BCME_OK;
+ s32 bw_cap = 0;
+ struct {
+ u32 band;
+ u32 bw_cap;
+ } param = {0, 0};
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+#ifdef CUSTOM_SET_CPUCORE
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+#endif /* CUSTOM_SET_CPUCORE */
+ u32 channel_width = 0;
+
+ dev = ndev_to_wlc_ndev(dev, cfg);
+ _chan = ieee80211_frequency_to_channel(chan->center_freq);
+ WL_ERR(("netdev_ifidx(%d), chan_type(%d) target channel(%d) channel_width(%x)\n",
+ dev->ifindex, channel_type, _chan, wl_get_chanwidth_by_netdev(cfg, dev)));
+
+
+#ifdef WL11ULB
+ if (ulb_bw) {
+ WL_DBG(("[ULB] setting AP/GO BW to ulb_bw 0x%x \n", ulb_bw));
+ bw = wl_cfg80211_ulbbw_to_ulbchspec(ulb_bw);
+ goto set_channel;
+ }
+#endif /* WL11ULB */
+ if (chan->band == IEEE80211_BAND_5GHZ) {
+ param.band = WLC_BAND_5G;
+ channel_width = wl_get_chanwidth_by_netdev(cfg, dev);
+ switch (channel_width) {
+ case WL_CHANSPEC_BW_80:
+ case WL_CHANSPEC_BW_40:
+ case WL_CHANSPEC_BW_20:
+ bw = channel_width;
+ /* resetting user specified channel width */
+ wl_set_chanwidth_by_netdev(cfg, dev, 0);
+ break;
+ default:
+ err = wldev_iovar_getbuf(dev, "bw_cap", &param, sizeof(param),
+ cfg->ioctl_buf, WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
+ if (err) {
+ if (err != BCME_UNSUPPORTED) {
+ WL_ERR(("bw_cap failed, %d\n", err));
+ return err;
+ } else {
+ err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
+ if (err) {
+ WL_ERR(("error get mimo_bw_cap (%d)\n", err));
+ }
+ if (bw_cap != WLC_N_BW_20ALL)
+ bw = WL_CHANSPEC_BW_40;
+ }
+ } else {
+ if (WL_BW_CAP_80MHZ(cfg->ioctl_buf[0]))
+ bw = WL_CHANSPEC_BW_80;
+ else if (WL_BW_CAP_40MHZ(cfg->ioctl_buf[0]))
+ bw = WL_CHANSPEC_BW_40;
+ else
+ bw = WL_CHANSPEC_BW_20;
+ }
+ break;
+ }
+
+ } else if (chan->band == IEEE80211_BAND_2GHZ)
+ bw = WL_CHANSPEC_BW_20;
+set_channel:
+ chspec = wf_channel2chspec(_chan, bw);
+ if (wf_chspec_valid(chspec)) {
+ fw_chspec = wl_chspec_host_to_driver(chspec);
+ if (fw_chspec != INVCHANSPEC) {
+ if ((err = wldev_iovar_setint(dev, "chanspec",
+ fw_chspec)) == BCME_BADCHAN) {
+ if (bw == WL_CHANSPEC_BW_80)
+ goto change_bw;
+ err = wldev_ioctl(dev, WLC_SET_CHANNEL,
+ &_chan, sizeof(_chan), true);
+ if (err < 0) {
+ WL_ERR(("WLC_SET_CHANNEL error %d"
+ "chip may not be supporting this channel\n", err));
+ }
+ } else if (err) {
+ WL_ERR(("failed to set chanspec error %d\n", err));
+ }
+ } else {
+ WL_ERR(("failed to convert host chanspec to fw chanspec\n"));
+ err = BCME_ERROR;
+ }
+ } else {
+change_bw:
+ if (bw == WL_CHANSPEC_BW_80)
+ bw = WL_CHANSPEC_BW_40;
+ else if (bw == WL_CHANSPEC_BW_40)
+ bw = WL_CHANSPEC_BW_20;
+ else
+ bw = 0;
+ if (bw)
+ goto set_channel;
+ WL_ERR(("Invalid chanspec 0x%x\n", chspec));
+ err = BCME_ERROR;
+ }
+#ifdef CUSTOM_SET_CPUCORE
+ if (dhd->op_mode == DHD_FLAG_HOSTAP_MODE) {
+ WL_DBG(("SoftAP mode do not need to set cpucore\n"));
+ } else if (chspec & WL_CHANSPEC_BW_80) {
+ /* SoftAp only mode do not need to set cpucore */
+ if ((dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) &&
+ dev != bcmcfg_to_prmry_ndev(cfg)) {
+ /* Soft AP on virtual Iface (AP+STA case) */
+ dhd->chan_isvht80 |= DHD_FLAG_HOSTAP_MODE;
+ dhd_set_cpucore(dhd, TRUE);
+ } else if (is_p2p_group_iface(dev->ieee80211_ptr)) {
+ /* If P2P IF is vht80 */
+ dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE;
+ dhd_set_cpucore(dhd, TRUE);
+ }
+ }
+#endif /* CUSTOM_SET_CPUCORE */
+ if (!err && (wl_get_mode_by_netdev(cfg, dev) == WL_MODE_AP)) {
+ /* Update AP/GO operating channel */
+ cfg->ap_oper_channel = _chan;
+ }
+ return err;
+}
+
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+struct net_device *
+wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg)
+{
+ struct net_info *_net_info, *next;
+ list_for_each_entry_safe(_net_info, next, &cfg->net_list, list) {
+ if (_net_info->ndev &&
+ test_bit(WL_STATUS_REMAINING_ON_CHANNEL, &_net_info->sme_state))
+ return _net_info->ndev;
+ }
+ return NULL;
+}
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
+#ifdef BCMWAPI_WPI
+static s32
+wl_validate_wapisecurity(struct net_device *dev, s32 bssidx)
+{
+ s32 err = BCME_OK;
+
+ /* set auth */
+ err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx);
+ if (err < 0) {
+ WL_ERR(("WAPI auth error %d\n", err));
+ return BCME_ERROR;
+ }
+
+ /* set wsec */
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", SMS4_ENABLED, bssidx);
+ if (err < 0) {
+ WL_ERR(("WAPI wsec error %d\n", err));
+ return BCME_ERROR;
+ }
+
+ /* set upper-layer auth */
+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", WAPI_AUTH_PSK, bssidx);
+ if (err < 0) {
+ WL_ERR(("WAPI wpa_auth error %d\n", err));
+ return BCME_ERROR;
+ }
+ return 0;
+}
+#endif /* BCMWAPI_WPI */
+#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
+
+static s32
+wl_validate_opensecurity(struct net_device *dev, s32 bssidx, bool privacy)
+{
+ s32 err = BCME_OK;
+ u32 wpa_val;
+ s32 wsec = 0;
+
+ /* set auth */
+ err = wldev_iovar_setint_bsscfg(dev, "auth", 0, bssidx);
+ if (err < 0) {
+ WL_ERR(("auth error %d\n", err));
+ return BCME_ERROR;
+ }
+
+ if (privacy) {
+ /* If privacy bit is set in open mode, then WEP would be enabled */
+ wsec = WEP_ENABLED;
+ WL_DBG(("Setting wsec to %d for WEP \n", wsec));
+ }
+
+ /* set wsec */
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
+ if (err < 0) {
+ WL_ERR(("wsec error %d\n", err));
+ return BCME_ERROR;
+ }
+
+ /* set upper-layer auth */
+ if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC)
+ wpa_val = WPA_AUTH_NONE;
+ else
+ wpa_val = WPA_AUTH_DISABLED;
+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_val, bssidx);
+ if (err < 0) {
+ WL_ERR(("wpa_auth error %d\n", err));
+ return BCME_ERROR;
+ }
+
+ return 0;
+}
+
+static s32
+wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
+{
+ s32 len = 0;
+ s32 err = BCME_OK;
+ u16 auth = 0; /* d11 open authentication */
+ u32 wsec;
+ u32 pval = 0;
+ u32 gval = 0;
+ u32 wpa_auth = 0;
+ wpa_suite_mcast_t *mcast;
+ wpa_suite_ucast_t *ucast;
+ wpa_suite_auth_key_mgmt_t *mgmt;
+ wpa_pmkid_list_t *pmkid;
+ int cnt = 0;
+
+ u16 suite_count;
+ u8 rsn_cap[2];
+ u32 wme_bss_disable;
+
+ if (wpa2ie == NULL)
+ goto exit;
+
+ WL_DBG(("Enter \n"));
+ len = wpa2ie->len - WPA2_VERSION_LEN;
+ /* check the mcast cipher */
+ mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
+ switch (mcast->type) {
+ case WPA_CIPHER_NONE:
+ gval = 0;
+ break;
+ case WPA_CIPHER_WEP_40:
+ case WPA_CIPHER_WEP_104:
+ gval = WEP_ENABLED;
+ break;
+ case WPA_CIPHER_TKIP:
+ gval = TKIP_ENABLED;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ gval = AES_ENABLED;
+ break;
+#ifdef BCMWAPI_WPI
+ case WAPI_CIPHER_SMS4:
+ gval = SMS4_ENABLED;
+ break;
+#endif
+ default:
+ WL_ERR(("No Security Info\n"));
+ break;
+ }
+ if ((len -= WPA_SUITE_LEN) <= 0)
+ return BCME_BADLEN;
+
+ /* check the unicast cipher */
+ ucast = (wpa_suite_ucast_t *)&mcast[1];
+ suite_count = ltoh16_ua(&ucast->count);
+ switch (ucast->list[0].type) {
+ case WPA_CIPHER_NONE:
+ pval = 0;
+ break;
+ case WPA_CIPHER_WEP_40:
+ case WPA_CIPHER_WEP_104:
+ pval = WEP_ENABLED;
+ break;
+ case WPA_CIPHER_TKIP:
+ pval = TKIP_ENABLED;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ pval = AES_ENABLED;
+ break;
+#ifdef BCMWAPI_WPI
+ case WAPI_CIPHER_SMS4:
+ pval = SMS4_ENABLED;
+ break;
+#endif
+ default:
+ WL_ERR(("No Security Info\n"));
+ }
+ if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) <= 0)
+ return BCME_BADLEN;
+
+ /* FOR WPS , set SEC_OW_ENABLED */
+ wsec = (pval | gval | SES_OW_ENABLED);
+ /* check the AKM */
+ mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[suite_count];
+ suite_count = cnt = ltoh16_ua(&mgmt->count);
+ while (cnt--) {
+ switch (mgmt->list[cnt].type) {
+ case RSN_AKM_NONE:
+ wpa_auth |= WPA_AUTH_NONE;
+ break;
+ case RSN_AKM_UNSPECIFIED:
+ wpa_auth |= WPA2_AUTH_UNSPECIFIED;
+ break;
+ case RSN_AKM_PSK:
+ wpa_auth |= WPA2_AUTH_PSK;
+ break;
+ default:
+ WL_ERR(("No Key Mgmt Info\n"));
+ }
+ }
+
+ if ((len -= (WPA_IE_SUITE_COUNT_LEN + (WPA_SUITE_LEN * suite_count))) >= RSN_CAP_LEN) {
+ rsn_cap[0] = *(u8 *)&mgmt->list[suite_count];
+ rsn_cap[1] = *((u8 *)&mgmt->list[suite_count] + 1);
+
+ if (rsn_cap[0] & (RSN_CAP_16_REPLAY_CNTRS << RSN_CAP_PTK_REPLAY_CNTR_SHIFT)) {
+ wme_bss_disable = 0;
+ } else {
+ wme_bss_disable = 1;
+ }
+
+
+ /* set wme_bss_disable to sync RSN Capabilities */
+ err = wldev_iovar_setint_bsscfg(dev, "wme_bss_disable", wme_bss_disable, bssidx);
+ if (err < 0) {
+ WL_ERR(("wme_bss_disable error %d\n", err));
+ return BCME_ERROR;
+ }
+ } else {
+ WL_DBG(("There is no RSN Capabilities. remained len %d\n", len));
+ }
+
+ len -= RSN_CAP_LEN;
+ if (len >= WPA2_PMKID_COUNT_LEN) {
+ pmkid = (wpa_pmkid_list_t *)((u8 *)&mgmt->list[suite_count] + RSN_CAP_LEN);
+ cnt = ltoh16_ua(&pmkid->count);
+ if (cnt != 0) {
+ WL_ERR(("AP has non-zero PMKID count. Wrong!\n"));
+ return BCME_ERROR;
+ }
+ /* since PMKID cnt is known to be 0 for AP, */
+ /* so don't bother to send down this info to firmware */
+ }
+
+
+ /* set auth */
+ err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
+ if (err < 0) {
+ WL_ERR(("auth error %d\n", err));
+ return BCME_ERROR;
+ }
+
+ /* set wsec */
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
+ if (err < 0) {
+ WL_ERR(("wsec error %d\n", err));
+ return BCME_ERROR;
+ }
+
+
+ /* set upper-layer auth */
+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
+ if (err < 0) {
+ WL_ERR(("wpa_auth error %d\n", err));
+ return BCME_ERROR;
+ }
+exit:
+ return 0;
+}
+
+static s32
+wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx)
+{
+ wpa_suite_mcast_t *mcast;
+ wpa_suite_ucast_t *ucast;
+ wpa_suite_auth_key_mgmt_t *mgmt;
+ u16 auth = 0; /* d11 open authentication */
+ u16 count;
+ s32 err = BCME_OK;
+ s32 len = 0;
+ u32 i;
+ u32 wsec;
+ u32 pval = 0;
+ u32 gval = 0;
+ u32 wpa_auth = 0;
+ u32 tmp = 0;
+
+ if (wpaie == NULL)
+ goto exit;
+ WL_DBG(("Enter \n"));
+ len = wpaie->length; /* value length */
+ len -= WPA_IE_TAG_FIXED_LEN;
+ /* check for multicast cipher suite */
+ if (len < WPA_SUITE_LEN) {
+ WL_INFORM(("no multicast cipher suite\n"));
+ goto exit;
+ }
+
+ /* pick up multicast cipher */
+ mcast = (wpa_suite_mcast_t *)&wpaie[1];
+ len -= WPA_SUITE_LEN;
+ if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
+ if (IS_WPA_CIPHER(mcast->type)) {
+ tmp = 0;
+ switch (mcast->type) {
+ case WPA_CIPHER_NONE:
+ tmp = 0;
+ break;
+ case WPA_CIPHER_WEP_40:
+ case WPA_CIPHER_WEP_104:
+ tmp = WEP_ENABLED;
+ break;
+ case WPA_CIPHER_TKIP:
+ tmp = TKIP_ENABLED;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ tmp = AES_ENABLED;
+ break;
+ default:
+ WL_ERR(("No Security Info\n"));
+ }
+ gval |= tmp;
+ }
+ }
+ /* Check for unicast suite(s) */
+ if (len < WPA_IE_SUITE_COUNT_LEN) {
+ WL_INFORM(("no unicast suite\n"));
+ goto exit;
+ }
+ /* walk thru unicast cipher list and pick up what we recognize */
+ ucast = (wpa_suite_ucast_t *)&mcast[1];
+ count = ltoh16_ua(&ucast->count);
+ len -= WPA_IE_SUITE_COUNT_LEN;
+ for (i = 0; i < count && len >= WPA_SUITE_LEN;
+ i++, len -= WPA_SUITE_LEN) {
+ if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
+ if (IS_WPA_CIPHER(ucast->list[i].type)) {
+ tmp = 0;
+ switch (ucast->list[i].type) {
+ case WPA_CIPHER_NONE:
+ tmp = 0;
+ break;
+ case WPA_CIPHER_WEP_40:
+ case WPA_CIPHER_WEP_104:
+ tmp = WEP_ENABLED;
+ break;
+ case WPA_CIPHER_TKIP:
+ tmp = TKIP_ENABLED;
+ break;
+ case WPA_CIPHER_AES_CCM:
+ tmp = AES_ENABLED;
+ break;
+ default:
+ WL_ERR(("No Security Info\n"));
+ }
+ pval |= tmp;
+ }
+ }
+ }
+ len -= (count - i) * WPA_SUITE_LEN;
+ /* Check for auth key management suite(s) */
+ if (len < WPA_IE_SUITE_COUNT_LEN) {
+ WL_INFORM((" no auth key mgmt suite\n"));
+ goto exit;
+ }
+ /* walk thru auth management suite list and pick up what we recognize */
+ mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
+ count = ltoh16_ua(&mgmt->count);
+ len -= WPA_IE_SUITE_COUNT_LEN;
+ for (i = 0; i < count && len >= WPA_SUITE_LEN;
+ i++, len -= WPA_SUITE_LEN) {
+ if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
+ if (IS_WPA_AKM(mgmt->list[i].type)) {
+ tmp = 0;
+ switch (mgmt->list[i].type) {
+ case RSN_AKM_NONE:
+ tmp = WPA_AUTH_NONE;
+ break;
+ case RSN_AKM_UNSPECIFIED:
+ tmp = WPA_AUTH_UNSPECIFIED;
+ break;
+ case RSN_AKM_PSK:
+ tmp = WPA_AUTH_PSK;
+ break;
+ default:
+ WL_ERR(("No Key Mgmt Info\n"));
+ }
+ wpa_auth |= tmp;
+ }
+ }
+
+ }
+ /* FOR WPS , set SEC_OW_ENABLED */
+ wsec = (pval | gval | SES_OW_ENABLED);
+ /* set auth */
+ err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
+ if (err < 0) {
+ WL_ERR(("auth error %d\n", err));
+ return BCME_ERROR;
+ }
+ /* set wsec */
+ err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
+ if (err < 0) {
+ WL_ERR(("wsec error %d\n", err));
+ return BCME_ERROR;
+ }
+ /* set upper-layer auth */
+ err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
+ if (err < 0) {
+ WL_ERR(("wpa_auth error %d\n", err));
+ return BCME_ERROR;
+ }
+exit:
+ return 0;
+}
+
+
+static s32
+wl_cfg80211_bcn_validate_sec(
+ struct net_device *dev,
+ struct parsed_ies *ies,
+ u32 dev_role,
+ s32 bssidx,
+ bool privacy)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
+
+ if (!bss) {
+ WL_ERR(("cfgbss is NULL \n"));
+ return BCME_ERROR;
+ }
+
+ if (dev_role == NL80211_IFTYPE_P2P_GO && (ies->wpa2_ie)) {
+ /* For P2P GO, the sec type is WPA2-PSK */
+ WL_DBG(("P2P GO: validating wpa2_ie"));
+ if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0)
+ return BCME_ERROR;
+
+ } else if (dev_role == NL80211_IFTYPE_AP) {
+
+ WL_DBG(("SoftAP: validating security"));
+ /* If wpa2_ie or wpa_ie is present validate it */
+
+ if ((ies->wpa2_ie || ies->wpa_ie) &&
+ ((wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
+ wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0))) {
+ bss->security_mode = false;
+ return BCME_ERROR;
+ }
+
+ bss->security_mode = true;
+ if (bss->rsn_ie) {
+ kfree(bss->rsn_ie);
+ bss->rsn_ie = NULL;
+ }
+ if (bss->wpa_ie) {
+ kfree(bss->wpa_ie);
+ bss->wpa_ie = NULL;
+ }
+ if (bss->wps_ie) {
+ kfree(bss->wps_ie);
+ bss->wps_ie = NULL;
+ }
+ if (ies->wpa_ie != NULL) {
+ /* WPAIE */
+ bss->rsn_ie = NULL;
+ bss->wpa_ie = kmemdup(ies->wpa_ie,
+ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ } else if (ies->wpa2_ie != NULL) {
+ /* RSNIE */
+ bss->wpa_ie = NULL;
+ bss->rsn_ie = kmemdup(ies->wpa2_ie,
+ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ }
+ if (!ies->wpa2_ie && !ies->wpa_ie) {
+ wl_validate_opensecurity(dev, bssidx, privacy);
+ bss->security_mode = false;
+ }
+
+ if (ies->wps_ie) {
+ bss->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
+ }
+ }
+
+ return 0;
+
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
+static s32 wl_cfg80211_bcn_set_params(
+ struct cfg80211_ap_settings *info,
+ struct net_device *dev,
+ u32 dev_role, s32 bssidx)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+#ifdef SUPPORT_HIDDEN_AP
+ struct net_info *_netinfo = wl_get_netinfo_by_netdev(cfg, dev);
+#endif
+ s32 err = BCME_OK;
+
+ WL_DBG(("interval (%d) \ndtim_period (%d) \n",
+ info->beacon_interval, info->dtim_period));
+
+ if (info->beacon_interval) {
+ if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD,
+ &info->beacon_interval, sizeof(s32), true)) < 0) {
+ WL_ERR(("Beacon Interval Set Error, %d\n", err));
+ return err;
+ }
+ }
+
+ if (info->dtim_period) {
+ if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD,
+ &info->dtim_period, sizeof(s32), true)) < 0) {
+ WL_ERR(("DTIM Interval Set Error, %d\n", err));
+ return err;
+ }
+ }
+
+ if ((info->ssid) && (info->ssid_len > 0) &&
+ (info->ssid_len <= DOT11_MAX_SSID_LEN)) {
+ WL_DBG(("SSID (%s) len:%zd \n", info->ssid, info->ssid_len));
+ if (dev_role == NL80211_IFTYPE_AP) {
+ /* Store the hostapd SSID */
+ memset(cfg->hostapd_ssid.SSID, 0x00, DOT11_MAX_SSID_LEN);
+ memcpy(cfg->hostapd_ssid.SSID, info->ssid, info->ssid_len);
+ cfg->hostapd_ssid.SSID_len = info->ssid_len;
+ } else {
+ /* P2P GO */
+ memset(cfg->p2p->ssid.SSID, 0x00, DOT11_MAX_SSID_LEN);
+ memcpy(cfg->p2p->ssid.SSID, info->ssid, info->ssid_len);
+ cfg->p2p->ssid.SSID_len = info->ssid_len;
+ }
+ }
+
+#ifdef SUPPORT_HIDDEN_AP
+ _netinfo->profile.hidden_ssid = info->hidden_ssid;
+#endif
+ if (info->hidden_ssid) {
+ if ((err = wldev_iovar_setint(dev, "closednet", 1)) < 0)
+ WL_ERR(("failed to set hidden : %d\n", err));
+ WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid));
+ }
+ else {
+ if ((err = wldev_iovar_setint(dev, "closednet", 0)) < 0)
+ WL_ERR(("failed to unset hidden : %d\n", err));
+ WL_DBG(("hidden_ssid_enum_val: %d \n", info->hidden_ssid));
+ }
+
+ return err;
+}
+#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
+
+static s32
+wl_cfg80211_parse_ies(u8 *ptr, u32 len, struct parsed_ies *ies)
+{
+ s32 err = BCME_OK;
+
+ memset(ies, 0, sizeof(struct parsed_ies));
+
+ /* find the WPSIE */
+ if ((ies->wps_ie = wl_cfgp2p_find_wpsie(ptr, len)) != NULL) {
+ WL_DBG(("WPSIE in beacon \n"));
+ ies->wps_ie_len = ies->wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
+ } else {
+ WL_ERR(("No WPSIE in beacon \n"));
+ }
+
+ /* find the RSN_IE */
+ if ((ies->wpa2_ie = bcm_parse_tlvs(ptr, len,
+ DOT11_MNG_RSN_ID)) != NULL) {
+ WL_DBG((" WPA2 IE found\n"));
+ ies->wpa2_ie_len = ies->wpa2_ie->len;
+ }
+
+ /* find the WPA_IE */
+ if ((ies->wpa_ie = wl_cfgp2p_find_wpaie(ptr, len)) != NULL) {
+ WL_DBG((" WPA found\n"));
+ ies->wpa_ie_len = ies->wpa_ie->length;
+ }
+
+ return err;
+
+}
+
+#define MAX_AP_LINK_WAIT_TIME 10000
+static s32
+wl_cfg80211_bcn_bringup_ap(
+ struct net_device *dev,
+ struct parsed_ies *ies,
+ u32 dev_role, s32 bssidx)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ struct wl_join_params join_params;
+ struct wiphy *wiphy;
+ bool is_bssup = false;
+ s32 infra = 1;
+ s32 join_params_size = 0;
+ s32 ap = 1;
+ s32 pm;
+ s32 wsec;
+#ifdef SOFTAP_UAPSD_OFF
+ uint32 wme_apsd = 0;
+#endif /* SOFTAP_UAPSD_OFF */
+ s32 err = BCME_OK;
+ s32 is_rsdb_supported = BCME_ERROR;
+ u32 timeout;
+#if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
+#endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
+
+ is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
+ if (is_rsdb_supported < 0)
+ return (-ENODEV);
+
+ WL_DBG(("Enter dev_role:%d bssidx:%d\n", dev_role, bssidx));
+
+ /* Common code for SoftAP and P2P GO */
+ wiphy = bcmcfg_to_wiphy(cfg);
+ if (wl_check_dongle_idle(wiphy) != TRUE) {
+ WL_ERR(("FW is busy to add interface"));
+ return -EINVAL;
+ }
+ wldev_iovar_setint(dev, "mpc", 0);
+
+ wl_clr_drv_status(cfg, AP_CREATED, dev);
+
+ if (dev_role == NL80211_IFTYPE_P2P_GO) {
+ is_bssup = wl_cfgp2p_bss_isup(dev, bssidx);
+ if (!is_bssup && (ies->wpa2_ie != NULL)) {
+
+ err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
+ if (err < 0) {
+ WL_ERR(("SET INFRA error %d\n", err));
+ goto exit;
+ }
+
+ err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &cfg->p2p->ssid,
+ sizeof(cfg->p2p->ssid), cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
+ bssidx, &cfg->ioctl_buf_sync);
+ if (err < 0) {
+ WL_ERR(("GO SSID setting error %d\n", err));
+ goto exit;
+ }
+
+ /* Do abort scan before creating GO */
+ wl_cfg80211_scan_abort(cfg);
+
+ if ((err = wl_cfgp2p_bss(cfg, dev, bssidx, 1)) < 0) {
+ WL_ERR(("GO Bring up error %d\n", err));
+ goto exit;
+ }
+ } else
+ WL_DBG(("Bss is already up\n"));
+ } else if ((dev_role == NL80211_IFTYPE_AP) &&
+ (wl_get_drv_status(cfg, AP_CREATING, dev))) {
+
+ /* Device role SoftAP */
+ WL_DBG(("Creating AP bssidx:%d dev_role:%d\n", bssidx, dev_role));
+
+ /* Clear the status bit after use */
+ wl_clr_drv_status(cfg, AP_CREATING, dev);
+
+ /* AP on primary Interface */
+ if (bssidx == 0) {
+ if (is_rsdb_supported) {
+ if ((err = wl_cfg80211_add_del_bss(cfg, dev, bssidx,
+ NL80211_IFTYPE_AP, 0, NULL)) < 0) {
+ WL_ERR(("wl add_del_bss returned error:%d\n", err));
+ goto exit;
+ }
+ } else if (is_rsdb_supported == 0) {
+ /* AP mode switch not supported. Try setting up AP explicitly */
+ err = wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true);
+ if (err < 0) {
+ WL_ERR(("WLC_DOWN error %d\n", err));
+ goto exit;
+ }
+ err = wldev_iovar_setint(dev, "apsta", 0);
+ if (err < 0) {
+ WL_ERR(("wl apsta 0 error %d\n", err));
+ goto exit;
+ }
+
+ if ((err = wldev_ioctl(dev,
+ WLC_SET_AP, &ap, sizeof(s32), true)) < 0) {
+ WL_ERR(("setting AP mode failed %d \n", err));
+ goto exit;
+ }
+
+ }
+
+ pm = 0;
+ if ((err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true)) != 0) {
+ WL_ERR(("wl PM 0 returned error:%d\n", err));
+ goto exit;
+ }
+
+ err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
+ if (err < 0) {
+ WL_ERR(("SET INFRA error %d\n", err));
+ goto exit;
+ }
+ } else if (wl_get_netinfo_by_bssidx(cfg, bssidx) != NULL) {
+ WL_DBG(("Bringup SoftAP on virtual Interface bssidx:%d \n", bssidx));
+
+ if ((err = wl_cfg80211_add_del_bss(cfg, dev,
+ bssidx, NL80211_IFTYPE_AP, 0, NULL)) < 0) {
+ WL_ERR(("wl bss ap returned error:%d\n", err));
+ goto exit;
+ }
+
+ }
+
+#ifdef SOFTAP_UAPSD_OFF
+ err = wldev_iovar_setbuf_bsscfg(dev, "wme_apsd", &wme_apsd, sizeof(wme_apsd),
+ cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync);
+ if (err < 0) {
+ WL_ERR(("failed to disable uapsd, error=%d\n", err));
+ }
+#endif /* SOFTAP_UAPSD_OFF */
+
+ err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_UP error (%d)\n", err));
+ goto exit;
+ }
+
+
+ err = wldev_iovar_getint(dev, "wsec", (s32 *)&wsec);
+ if (unlikely(err)) {
+ WL_ERR(("Could not get wsec %d\n", err));
+ goto exit;
+ }
+ if ((wsec == WEP_ENABLED) && cfg->wep_key.len) {
+ WL_DBG(("Applying buffered WEP KEY \n"));
+ err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &cfg->wep_key,
+ sizeof(struct wl_wsec_key), cfg->ioctl_buf,
+ WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+ /* clear the key after use */
+ memset(&cfg->wep_key, 0, sizeof(struct wl_wsec_key));
+ if (unlikely(err)) {
+ WL_ERR(("WLC_SET_KEY error (%d)\n", err));
+ goto exit;
+ }
+ }
+
+
+ memset(&join_params, 0, sizeof(join_params));
+ /* join parameters starts with ssid */
+ join_params_size = sizeof(join_params.ssid);
+ join_params.ssid.SSID_len = MIN(cfg->hostapd_ssid.SSID_len,
+ (uint32)DOT11_MAX_SSID_LEN);
+ memcpy(join_params.ssid.SSID, cfg->hostapd_ssid.SSID,
+ join_params.ssid.SSID_len);
+ join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
+
+ /* create softap */
+ if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
+ join_params_size, true)) != 0) {
+ WL_ERR(("SoftAP/GO set ssid failed! \n"));
+ goto exit;
+ } else {
+ WL_DBG((" SoftAP SSID \"%s\" \n", join_params.ssid.SSID));
+ }
+
+ if (bssidx != 0) {
+ /* AP on Virtual Interface */
+ if ((err = wl_cfgp2p_bss(cfg, dev, bssidx, 1)) < 0) {
+ WL_ERR(("GO Bring up error %d\n", err));
+ goto exit;
+ }
+ }
+
+ }
+ /* Wait for Linkup event to mark successful AP/GO bring up */
+ timeout = wait_event_interruptible_timeout(cfg->netif_change_event,
+ wl_get_drv_status(cfg, AP_CREATED, dev), msecs_to_jiffies(MAX_AP_LINK_WAIT_TIME));
+ if (timeout <= 0 || !wl_get_drv_status(cfg, AP_CREATED, dev)) {
+ WL_ERR(("Link up didn't come for AP interface. AP/GO creation failed! \n"));
+#if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
+ if (dhdp->memdump_enabled) {
+ dhdp->memdump_type = DUMP_TYPE_AP_LINKUP_FAILURE;
+ dhd_bus_mem_dump(dhdp);
+ }
+#endif /* DHD_DEBUG && BCMPCIE && DHD_FW_COREDUMP */
+ err = -ENODEV;
+ goto exit;
+ }
+
+exit:
+ if (cfg->wep_key.len) {
+ memset(&cfg->wep_key, 0, sizeof(struct wl_wsec_key));
+ }
+
+
+ return err;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
+s32
+wl_cfg80211_parse_ap_ies(
+ struct net_device *dev,
+ struct cfg80211_beacon_data *info,
+ struct parsed_ies *ies)
+{
+ struct parsed_ies prb_ies;
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+ u8 *vndr = NULL;
+ u32 vndr_ie_len = 0;
+ s32 err = BCME_OK;
+
+ /* Parse Beacon IEs */
+ if (wl_cfg80211_parse_ies((u8 *)info->tail,
+ info->tail_len, ies) < 0) {
+ WL_ERR(("Beacon get IEs failed \n"));
+ err = -EINVAL;
+ goto fail;
+ }
+
+ vndr = (u8 *)info->proberesp_ies;
+ vndr_ie_len = info->proberesp_ies_len;
+
+ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
+ /* SoftAP mode */
+ struct ieee80211_mgmt *mgmt;
+ mgmt = (struct ieee80211_mgmt *)info->probe_resp;
+ if (mgmt != NULL) {
+ vndr = (u8 *)&mgmt->u.probe_resp.variable;
+ vndr_ie_len = info->probe_resp_len -
+ offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+ }
+ }
+
+ /* Parse Probe Response IEs */
+ if (wl_cfg80211_parse_ies(vndr, vndr_ie_len, &prb_ies) < 0) {
+ WL_ERR(("PROBE RESP get IEs failed \n"));
+ err = -EINVAL;
+ }
+
+fail:
+
+ return err;
+}
+
+s32
+wl_cfg80211_set_ies(
+ struct net_device *dev,
+ struct cfg80211_beacon_data *info,
+ s32 bssidx)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+ u8 *vndr = NULL;
+ u32 vndr_ie_len = 0;
+ s32 err = BCME_OK;
+
+ /* Set Beacon IEs to FW */
+ if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
+ VNDR_IE_BEACON_FLAG, (const u8 *)info->tail,
+ info->tail_len)) < 0) {
+ WL_ERR(("Set Beacon IE Failed \n"));
+ } else {
+ WL_DBG(("Applied Vndr IEs for Beacon \n"));
+ }
+
+ vndr = (u8 *)info->proberesp_ies;
+ vndr_ie_len = info->proberesp_ies_len;
+
+ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
+ /* SoftAP mode */
+ struct ieee80211_mgmt *mgmt;
+ mgmt = (struct ieee80211_mgmt *)info->probe_resp;
+ if (mgmt != NULL) {
+ vndr = (u8 *)&mgmt->u.probe_resp.variable;
+ vndr_ie_len = info->probe_resp_len -
+ offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+ }
+ }
+
+ /* Set Probe Response IEs to FW */
+ if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
+ VNDR_IE_PRBRSP_FLAG, vndr, vndr_ie_len)) < 0) {
+ WL_ERR(("Set Probe Resp IE Failed \n"));
+ } else {
+ WL_DBG(("Applied Vndr IEs for Probe Resp \n"));
+ }
+
+ return err;
+}
+#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
+
+static s32 wl_cfg80211_hostapd_sec(
+ struct net_device *dev,
+ struct parsed_ies *ies,
+ s32 bssidx)
+{
+ bool update_bss = 0;
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ wl_cfgbss_t *bss = wl_get_cfgbss_by_wdev(cfg, dev->ieee80211_ptr);
+
+ if (!bss) {
+ WL_ERR(("cfgbss is NULL \n"));
+ return -EINVAL;
+ }
+
+ if (ies->wps_ie) {
+ if (bss->wps_ie &&
+ memcmp(bss->wps_ie, ies->wps_ie, ies->wps_ie_len)) {
+ WL_DBG((" WPS IE is changed\n"));
+ kfree(bss->wps_ie);
+ bss->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
+ } else if (bss->wps_ie == NULL) {
+ WL_DBG((" WPS IE is added\n"));
+ bss->wps_ie = kmemdup(ies->wps_ie, ies->wps_ie_len, GFP_KERNEL);
+ }
+
+ if ((ies->wpa_ie != NULL || ies->wpa2_ie != NULL)) {
+ if (!bss->security_mode) {
+ /* change from open mode to security mode */
+ update_bss = true;
+ if (ies->wpa_ie != NULL) {
+ bss->wpa_ie = kmemdup(ies->wpa_ie,
+ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ } else {
+ bss->rsn_ie = kmemdup(ies->wpa2_ie,
+ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ }
+ } else if (bss->wpa_ie) {
+ /* change from WPA2 mode to WPA mode */
+ if (ies->wpa_ie != NULL) {
+ update_bss = true;
+ kfree(bss->rsn_ie);
+ bss->rsn_ie = NULL;
+ bss->wpa_ie = kmemdup(ies->wpa_ie,
+ ies->wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ } else if (memcmp(bss->rsn_ie,
+ ies->wpa2_ie, ies->wpa2_ie->len
+ + WPA_RSN_IE_TAG_FIXED_LEN)) {
+ update_bss = true;
+ kfree(bss->rsn_ie);
+ bss->rsn_ie = kmemdup(ies->wpa2_ie,
+ ies->wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
+ GFP_KERNEL);
+ bss->wpa_ie = NULL;
+ }
+ }
+ if (update_bss) {
+ bss->security_mode = true;
+ wl_cfgp2p_bss(cfg, dev, bssidx, 0);
+ if (wl_validate_wpa2ie(dev, ies->wpa2_ie, bssidx) < 0 ||
+ wl_validate_wpaie(dev, ies->wpa_ie, bssidx) < 0) {
+ return BCME_ERROR;
+ }
+ wl_cfgp2p_bss(cfg, dev, bssidx, 1);
+ }
+ }
+ } else {
+ WL_ERR(("No WPSIE in beacon \n"));
+ }
+ return 0;
+}
+
+#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
+ 2, 0))
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
+static s32
+wl_cfg80211_del_station(
+ struct wiphy *wiphy, struct net_device *ndev,
+ struct station_del_parameters *params)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static s32
+wl_cfg80211_del_station(
+ struct wiphy *wiphy,
+ struct net_device *ndev,
+ const u8* mac_addr)
+#else
+static s32
+wl_cfg80211_del_station(
+ struct wiphy *wiphy,
+ struct net_device *ndev,
+ u8* mac_addr)
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
+{
+ struct net_device *dev;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ scb_val_t scb_val;
+ s8 eabuf[ETHER_ADDR_STR_LEN];
+ int err;
+ char mac_buf[MAX_NUM_OF_ASSOCIATED_DEV *
+ sizeof(struct ether_addr) + sizeof(uint)] = {0};
+ struct maclist *assoc_maclist = (struct maclist *)mac_buf;
+ int num_associated = 0;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0))
+ const u8 *mac_addr = params->mac;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) */
+
+ WL_DBG(("Entry\n"));
+ if (mac_addr == NULL) {
+ WL_DBG(("mac_addr is NULL ignore it\n"));
+ return 0;
+ }
+
+ dev = ndev_to_wlc_ndev(ndev, cfg);
+
+ if (p2p_is_on(cfg)) {
+ /* Suspend P2P discovery search-listen to prevent it from changing the
+ * channel.
+ */
+ if ((wl_cfgp2p_discover_enable_search(cfg, false)) < 0) {
+ WL_ERR(("Can not disable discovery mode\n"));
+ return -EFAULT;
+ }
+ }
+
+ assoc_maclist->count = MAX_NUM_OF_ASSOCIATED_DEV;
+ err = wldev_ioctl(ndev, WLC_GET_ASSOCLIST,
+ assoc_maclist, sizeof(mac_buf), false);
+ if (err < 0)
+ WL_ERR(("WLC_GET_ASSOCLIST error %d\n", err));
+ else
+ num_associated = assoc_maclist->count;
+
+ memcpy(scb_val.ea.octet, mac_addr, ETHER_ADDR_LEN);
+ scb_val.val = DOT11_RC_DEAUTH_LEAVING;
+ err = wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val,
+ sizeof(scb_val_t), true);
+ if (err < 0)
+ WL_ERR(("WLC_SCB_DEAUTHENTICATE_FOR_REASON err %d\n", err));
+ WL_ERR(("Disconnect STA : %s scb_val.val %d\n",
+ bcm_ether_ntoa((const struct ether_addr *)mac_addr, eabuf),
+ scb_val.val));
+
+ if (num_associated > 0 && ETHER_ISBCAST(mac_addr))
+ wl_delay(400);
+
+ return 0;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static s32
+wl_cfg80211_change_station(
+ struct wiphy *wiphy,
+ struct net_device *dev,
+ const u8 *mac,
+ struct station_parameters *params)
+#else
+static s32
+wl_cfg80211_change_station(
+ struct wiphy *wiphy,
+ struct net_device *dev,
+ u8 *mac,
+ struct station_parameters *params)
+#endif
+{
+ int err;
+#ifdef DHD_LOSSLESS_ROAMING
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+#endif
+
+ WL_DBG(("SCB_AUTHORIZE mac_addr:"MACDBG" sta_flags_mask:0x%x "
+ "sta_flags_set:0x%x iface:%s \n", MAC2STRDBG(mac),
+ params->sta_flags_mask, params->sta_flags_set, dev->name));
+
+ /* Processing only authorize/de-authorize flag for now */
+ if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
+ WL_ERR(("WLC_SCB_AUTHORIZE sta_flags_mask not set \n"));
+ return -ENOTSUPP;
+ }
+
+ if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+ err = wldev_ioctl(dev, WLC_SCB_DEAUTHORIZE, (u8 *)mac, ETH_ALEN, true);
+#else
+ err = wldev_ioctl(dev, WLC_SCB_DEAUTHORIZE, mac, ETH_ALEN, true);
+#endif
+ if (err)
+ WL_ERR(("WLC_SCB_DEAUTHORIZE error (%d)\n", err));
+ return err;
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+ err = wldev_ioctl(dev, WLC_SCB_AUTHORIZE, (u8 *)mac, ETH_ALEN, true);
+#else
+ err = wldev_ioctl(dev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN, true);
+#endif
+ if (err)
+ WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err));
+#ifdef DHD_LOSSLESS_ROAMING
+ wl_del_roam_timeout(cfg);
+#endif
+ return err;
+}
+#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */
+
+static s32
+wl_cfg80211_set_scb_timings(
+ struct bcm_cfg80211 *cfg,
+ struct net_device *dev)
+{
+ int err;
+ u32 ps_pretend;
+ wl_scb_probe_t scb_probe;
+
+ bzero(&scb_probe, sizeof(wl_scb_probe_t));
+ scb_probe.scb_timeout = WL_SCB_TIMEOUT;
+ scb_probe.scb_activity_time = WL_SCB_ACTIVITY_TIME;
+ scb_probe.scb_max_probe = WL_SCB_MAX_PROBE;
+ err = wldev_iovar_setbuf(dev, "scb_probe", (void *)&scb_probe,
+ sizeof(wl_scb_probe_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
+ &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("set 'scb_probe' failed, error = %d\n", err));
+ return err;
+ }
+
+ ps_pretend = MAX(WL_SCB_MAX_PROBE / 2, WL_MIN_PSPRETEND_THRESHOLD);
+ err = wldev_iovar_setint(dev, "pspretend_threshold", ps_pretend);
+ if (unlikely(err)) {
+ if (err == BCME_UNSUPPORTED) {
+ /* Ignore error if fw doesn't support the iovar */
+ WL_DBG(("wl pspretend_threshold %d set error %d\n",
+ ps_pretend, err));
+ } else {
+ WL_ERR(("wl pspretend_threshold %d set error %d\n",
+ ps_pretend, err));
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
+static s32
+wl_cfg80211_start_ap(
+ struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_ap_settings *info)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 err = BCME_OK;
+ struct parsed_ies ies;
+ s32 bssidx = 0;
+ u32 dev_role = 0;
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+#ifdef AP_STA_RSDB_FEASIBILITY_CHK
+ u32 ap_chan = 0;
+ struct net_info *iter, *next;
+#endif /* AP_STA_RSDB_FEASIBILITY_CHK */
+#ifdef SUPPORT_HIDDEN_AP
+ struct net_info *_netinfo = wl_get_netinfo_by_netdev(cfg, dev);
+#endif
+
+#ifdef WL11U
+ bcm_tlv_t *interworking_ie;
+ u32 iw_ie_len = 0;
+ u8 iw_ie[IW_IES_MAX_BUF_LEN];
+#endif
+ WL_DBG(("Enter \n"));
+
+#if defined(SUPPORT_RANDOM_MAC_SCAN)
+ wl_cfg80211_set_random_mac(dev, FALSE);
+#endif /* SUPPORT_RANDOM_MAC_SCAN */
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+#if defined(WL_ENABLE_P2P_IF)
+ if (dev == cfg->p2p_net) {
+ /* Group Add request on p2p0 */
+ WL_DBG(("Start AP req on P2P iface: GO\n"));
+ dev = bcmcfg_to_prmry_ndev(cfg);
+ dev_role = NL80211_IFTYPE_P2P_GO;
+ } else
+#endif /* WL_ENABLE_P2P_IF */
+ if (wl_get_netinfo_by_netdev(cfg, dev) != NULL) {
+ WL_DBG(("Start AP req on iface: %s", dev->name));
+ dev_role = NL80211_IFTYPE_AP;
+ }
+
+ if (p2p_is_on(cfg) && (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO)) {
+ dev_role = NL80211_IFTYPE_P2P_GO;
+ } else if (dev_role == NL80211_IFTYPE_AP) {
+ dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
+ /*
+ * Enabling Softap is causing issues with STA NDO operations
+ * as NDO is not interface specific. So disable NDO while
+ * Softap is enabled
+ */
+ err = dhd_ndo_enable(dhd, FALSE);
+ WL_DBG(("%s: Disabling NDO on Hostapd mode %d\n", __FUNCTION__, err));
+ if (err) {
+ /* Non fatal error. */
+ WL_ERR(("%s: Disabling NDO Failed %d\n", __FUNCTION__, err));
+ } else {
+ cfg->revert_ndo_disable = true;
+ }
+
+#ifdef PKT_FILTER_SUPPORT
+ /* Disable packet filter */
+ if (dhd->early_suspended) {
+ WL_ERR(("Disable pkt_filter\n"));
+ dhd_enable_packet_filter(0, dhd);
+ }
+#endif /* PKT_FILTER_SUPPORT */
+#ifdef ARP_OFFLOAD_SUPPORT
+ /* IF SoftAP is enabled, disable arpoe */
+ if (dhd->op_mode & DHD_FLAG_STA_MODE) {
+ dhd_arp_offload_set(dhd, 0);
+ dhd_arp_offload_enable(dhd, FALSE);
+ }
+#endif /* ARP_OFFLOAD_SUPPORT */
+ if ((dhd->op_mode & DHD_FLAG_STA_MODE) &&
+ wl_cfg80211_is_roam_offload(NETDEV_GET_CFG80211_PRIV(dev))) {
+ WL_ERR(("Cleare roam_offload_bssid_list at STA-SoftAP MODE.\n"));
+ wl_android_set_roam_offload_bssid_list(dev, "0");
+ }
+ } else {
+ /* only AP or GO role need to be handled here. */
+ err = -EINVAL;
+ goto fail;
+ }
+
+ if (!check_dev_role_integrity(cfg, dev_role)) {
+ err = -EINVAL;
+ goto fail;
+ }
+
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && !defined(WL_COMPAT_WIRELESS))
+ if ((err = wl_cfg80211_set_channel(wiphy, dev,
+ dev->ieee80211_ptr->preset_chandef.chan,
+ NL80211_CHAN_HT20) < 0)) {
+ WL_ERR(("Set channel failed \n"));
+ goto fail;
+ }
+#endif /* ((LINUX_VERSION >= VERSION(3, 6, 0) && !WL_COMPAT_WIRELESS) */
+
+ if ((err = wl_cfg80211_bcn_set_params(info, dev,
+ dev_role, bssidx)) < 0) {
+ WL_ERR(("Beacon params set failed \n"));
+ goto fail;
+ }
+
+ /* Parse IEs */
+ if ((err = wl_cfg80211_parse_ap_ies(dev, &info->beacon, &ies)) < 0) {
+ WL_ERR(("Set IEs failed \n"));
+ goto fail;
+ }
+
+
+#ifdef BCMWAPI_WPI
+ if (info->crypto.ciphers_pairwise[0] == WLAN_DHD_CIPHER_SUITE_SMS4) {
+ wl_validate_wapisecurity(dev, bssidx);
+ }
+ else
+#endif
+ {
+ WL_ERR(("%s info->crypto.ciphers_pairwise[0] is not "
+ "WLAN_CIPHER_SUITE_SMS4 \n", __FUNCTION__));
+
+ if ((err = wl_cfg80211_bcn_validate_sec(dev, &ies,
+ dev_role, bssidx, info->privacy)) < 0)
+ {
+ WL_ERR(("Beacon set security failed \n"));
+ goto fail;
+ }
+ }
+
+ if ((err = wl_cfg80211_bcn_bringup_ap(dev, &ies,
+ dev_role, bssidx)) < 0) {
+ WL_ERR(("Beacon bring up AP/GO failed \n"));
+ goto fail;
+ }
+
+ if (bssidx != 0) {
+#ifdef SUPPORT_HIDDEN_AP
+ _netinfo->profile.hidden_ssid = info->hidden_ssid;
+#endif /* SUPPORT_HIDDEN_AP */
+ if ((err = wldev_iovar_setint_bsscfg(dev, "closednet",
+ (info->hidden_ssid ? 1 : 0), bssidx)) < 0) {
+ WL_ERR(("failed to set hidden ssid: %d\n", err));
+ }
+ }
+
+ /* Set GC/STA SCB expiry timings. */
+ if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
+ WL_ERR(("scb setting failed \n"));
+ goto fail;
+ }
+
+ WL_DBG(("** AP/GO Created **\n"));
+
+#ifdef WL_CFG80211_ACL
+ /* Enfoce Admission Control. */
+ if ((err = wl_cfg80211_set_mac_acl(wiphy, dev, info->acl)) < 0) {
+ WL_ERR(("Set ACL failed\n"));
+ }
+#endif /* WL_CFG80211_ACL */
+
+#ifdef WL11U
+ wl_get_iwdata_by_netdev(cfg, dev, iw_ie, &iw_ie_len);
+ /* Add interworking IE from beacon data */
+ if ((interworking_ie = wl_cfg80211_find_interworking_ie(
+ (u8 *)info->beacon.beacon_ies, info->beacon.beacon_ies_len)) != NULL) {
+ err = wl_cfg80211_add_iw_ie(cfg, dev, bssidx,
+ VNDR_IE_CUSTOM_FLAG, interworking_ie->id,
+ interworking_ie->data, interworking_ie->len);
+ if (unlikely(err)) {
+ WL_ERR(("Failed to add interworking IE"));
+ }
+ } else if (iw_ie_len != 0) {
+ /* we have to clear IW IE and disable gratuitous APR */
+ wl_cfg80211_add_iw_ie(cfg, dev, bssidx,
+ VNDR_IE_CUSTOM_FLAG,
+ DOT11_MNG_INTERWORKING_ID,
+ 0, 0);
+
+ (void)wldev_iovar_setint_bsscfg(dev, "grat_arp", 0,
+ bssidx);
+ wl_clear_iwdata_by_netdev(cfg, dev);
+ /* we don't care about error */
+ }
+#endif /* WL11U */
+
+ /* Set IEs to FW */
+ if ((err = wl_cfg80211_set_ies(dev, &info->beacon, bssidx)) < 0)
+ WL_ERR(("Set IEs failed \n"));
+
+ /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
+ if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
+ bool pbc = 0;
+ wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc);
+ if (pbc) {
+ WL_DBG(("set WLC_E_PROBREQ_MSG\n"));
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
+ }
+ }
+
+fail:
+ if (err) {
+ WL_ERR(("ADD/SET beacon failed\n"));
+ wldev_iovar_setint(dev, "mpc", 1);
+ if (dev_role == NL80211_IFTYPE_AP) {
+ dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
+
+#ifdef PKT_FILTER_SUPPORT
+ /* Enable packet filter */
+ if (dhd->early_suspended) {
+ WL_ERR(("Enable pkt_filter\n"));
+ dhd_enable_packet_filter(1, dhd);
+ }
+#endif /* PKT_FILTER_SUPPORT */
+#ifdef ARP_OFFLOAD_SUPPORT
+ /* IF SoftAP is disabled, enable arpoe back for STA mode. */
+ if (dhd->op_mode & DHD_FLAG_STA_MODE) {
+ dhd_arp_offload_set(dhd, dhd_arp_mode);
+ dhd_arp_offload_enable(dhd, TRUE);
+ }
+#endif /* ARP_OFFLOAD_SUPPORT */
+ }
+ }
+#ifdef AP_STA_RSDB_FEASIBILITY_CHK
+ else {
+ WL_DBG(("Store AP channel now\n"));
+ ap_chan = ieee80211_frequency_to_channel(
+ dev->ieee80211_ptr->preset_chandef.chan->center_freq);
+ for_each_ndev(cfg, iter, next) {
+ if (iter->ndev == dev) {
+ WL_DBG(("Set channel (%d)\n", ap_chan));
+ wl_update_prof(cfg, iter->ndev, NULL,
+ (void *)&ap_chan, WL_PROF_CHAN);
+ }
+ }
+ }
+#endif /* AP_STA_RSDB_FEASIBILITY_CHK */
+
+ return err;
+}
+
+static s32
+wl_cfg80211_stop_ap(
+ struct wiphy *wiphy,
+ struct net_device *dev)
+{
+ int err = 0;
+ u32 dev_role = 0;
+ int ap = 0;
+ s32 bssidx = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 is_rsdb_supported = BCME_ERROR;
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+
+ WL_DBG(("Enter \n"));
+
+ is_rsdb_supported = DHD_OPMODE_SUPPORTED(cfg->pub, DHD_FLAG_RSDB_MODE);
+ if (is_rsdb_supported < 0)
+ return (-ENODEV);
+
+ wl_clr_drv_status(cfg, AP_CREATING, dev);
+ wl_clr_drv_status(cfg, AP_CREATED, dev);
+ cfg->ap_oper_channel = 0;
+
+ if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
+ dev_role = NL80211_IFTYPE_AP;
+ WL_DBG(("stopping AP operation\n"));
+ } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
+ dev_role = NL80211_IFTYPE_P2P_GO;
+ WL_DBG(("stopping P2P GO operation\n"));
+#ifdef DHD_BANDSTEER
+ if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
+ /* Disable bandsteer */
+ dhd_bandsteer_module_deinit(bcmcfg_to_prmry_ndev(cfg));
+ }
+#endif /* DHD_BANDSTEER */
+ } else {
+ WL_ERR(("no AP/P2P GO interface is operational.\n"));
+ return -EINVAL;
+ }
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+
+ if (!check_dev_role_integrity(cfg, dev_role)) {
+ WL_ERR(("role integrity check failed \n"));
+ err = -EINVAL;
+ goto exit;
+ }
+
+ if ((err = wl_cfgp2p_bss(cfg, dev, bssidx, 0)) < 0) {
+ WL_ERR(("bss down error %d\n", err));
+ }
+
+ if (dev_role == NL80211_IFTYPE_AP) {
+ if (cfg->revert_ndo_disable == true) {
+ err = dhd_ndo_enable(dhd, TRUE);
+ WL_DBG(("%s: Enabling back NDO on Softap turn off %d\n",
+ __FUNCTION__, err));
+ if (err) {
+ WL_ERR(("%s: Enabling NDO Failed %d\n", __FUNCTION__, err));
+ }
+ cfg->revert_ndo_disable = false;
+ }
+
+#ifdef PKT_FILTER_SUPPORT
+ /* Enable packet filter */
+ if (dhd->early_suspended) {
+ WL_ERR(("Enable pkt_filter\n"));
+ dhd_enable_packet_filter(1, dhd);
+ }
+#endif /* PKT_FILTER_SUPPORT */
+#ifdef ARP_OFFLOAD_SUPPORT
+ /* IF SoftAP is disabled, enable arpoe back for STA mode. */
+ if (dhd->op_mode & DHD_FLAG_STA_MODE) {
+ dhd_arp_offload_set(dhd, dhd_arp_mode);
+ dhd_arp_offload_enable(dhd, TRUE);
+ }
+#endif /* ARP_OFFLOAD_SUPPORT */
+ /*
+ * Bring down the AP interface by changing role to STA.
+ * Don't do a down or "WLC_SET_AP 0" since the shared
+ * interface may be still running
+ */
+ if ((err = wl_cfg80211_add_del_bss(cfg, dev,
+ bssidx, NL80211_IFTYPE_STATION, 0, NULL)) < 0) {
+ if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32),
+ true)) < 0) {
+ WL_ERR(("setting AP mode failed %d \n", err));
+ err = -ENOTSUPP;
+ goto exit;
+ }
+ }
+
+ /* Turn on the MPC */
+ wldev_iovar_setint(dev, "mpc", 1);
+
+ wl_cfg80211_clear_per_bss_ies(cfg, bssidx);
+ } else {
+ WL_DBG(("Stopping P2P GO \n"));
+ DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE((dhd_pub_t *)(cfg->pub),
+ DHD_EVENT_TIMEOUT_MS*3);
+ DHD_OS_WAKE_LOCK_TIMEOUT((dhd_pub_t *)(cfg->pub));
+ }
+
+exit:
+
+ if (dev_role == NL80211_IFTYPE_AP) {
+ /* clear the AP mode */
+ dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
+ }
+ return err;
+}
+
+static s32
+wl_cfg80211_change_beacon(
+ struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_beacon_data *info)
+{
+ s32 err = BCME_OK;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct parsed_ies ies;
+ u32 dev_role = 0;
+ s32 bssidx = 0;
+ bool pbc = 0;
+#ifdef WL11U
+ bcm_tlv_t *interworking_ie;
+ u32 iw_ie_len = 0;
+ u8 iw_ie[IW_IES_MAX_BUF_LEN];
+#endif
+
+ WL_DBG(("Enter \n"));
+
+ if (dev == bcmcfg_to_prmry_ndev(cfg)) {
+ dev_role = NL80211_IFTYPE_AP;
+ }
+#if defined(WL_ENABLE_P2P_IF)
+ else if (dev == cfg->p2p_net) {
+ /* Group Add request on p2p0 */
+ dev = bcmcfg_to_prmry_ndev(cfg);
+ dev_role = NL80211_IFTYPE_P2P_GO;
+ }
+#endif /* WL_ENABLE_P2P_IF */
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+
+ if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
+ dev_role = NL80211_IFTYPE_P2P_GO;
+ }
+
+ if (!check_dev_role_integrity(cfg, dev_role)) {
+ err = -EINVAL;
+ goto fail;
+ }
+
+ if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) {
+ WL_ERR(("P2P already down status!\n"));
+ err = BCME_ERROR;
+ goto fail;
+ }
+
+ /* Parse IEs */
+ if ((err = wl_cfg80211_parse_ap_ies(dev, info, &ies)) < 0) {
+ WL_ERR(("Parse IEs failed \n"));
+ goto fail;
+ }
+#ifdef WL11U
+ wl_get_iwdata_by_netdev(cfg, dev, iw_ie, &iw_ie_len);
+ /* Add interworking IE from beacon data */
+ if ((interworking_ie = wl_cfg80211_find_interworking_ie(
+ (u8 *)info->beacon_ies, info->beacon_ies_len)) != NULL) {
+ err = wl_cfg80211_add_iw_ie(cfg, dev, bssidx,
+ VNDR_IE_CUSTOM_FLAG, interworking_ie->id,
+ interworking_ie->data, interworking_ie->len);
+ if (unlikely(err)) {
+ WL_ERR(("Failed to add interworking IE"));
+ }
+ } else if (iw_ie_len != 0) {
+ /* we have to clear IW IE and disable gratuitous APR */
+ wl_cfg80211_add_iw_ie(cfg, dev, bssidx,
+ VNDR_IE_CUSTOM_FLAG,
+ DOT11_MNG_INTERWORKING_ID,
+ 0, 0);
+
+ /* we don't bother whether grat_arp gets disabled or not */
+ (void)wldev_iovar_setint_bsscfg(dev, "grat_arp", 0,
+ bssidx);
+ wl_clear_iwdata_by_netdev(cfg, dev);
+ } else {
+ WL_DBG(("no update in iw ie\n"));
+ }
+#endif /* WL11U */
+
+
+ /* Set IEs to FW */
+ if ((err = wl_cfg80211_set_ies(dev, info, bssidx)) < 0) {
+ WL_ERR(("Set IEs failed \n"));
+ goto fail;
+ }
+
+ if (dev_role == NL80211_IFTYPE_AP) {
+ if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
+ WL_ERR(("Hostapd update sec failed \n"));
+ err = -EINVAL;
+ goto fail;
+ }
+ /* Enable Probe Req filter, WPS-AP certification 4.2.13 */
+ if ((dev_role == NL80211_IFTYPE_AP) && (ies.wps_ie != NULL)) {
+ wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc);
+ WL_DBG((" WPS AP, wps_ie is exists pbc=%d\n", pbc));
+ if (pbc)
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
+ else
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, false);
+ }
+ }
+
+fail:
+ return err;
+}
+#else
+static s32
+wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
+ struct beacon_parameters *info)
+{
+ s32 err = BCME_OK;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ s32 ie_offset = 0;
+ s32 bssidx = 0;
+ u32 dev_role = NL80211_IFTYPE_AP;
+ struct parsed_ies ies;
+ bcm_tlv_t *ssid_ie;
+ bool pbc = 0;
+ bool privacy;
+ bool is_bss_up = 0;
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+
+ WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
+ info->interval, info->dtim_period, info->head_len, info->tail_len));
+
+ if (dev == bcmcfg_to_prmry_ndev(cfg)) {
+ dev_role = NL80211_IFTYPE_AP;
+ }
+#if defined(WL_ENABLE_P2P_IF)
+ else if (dev == cfg->p2p_net) {
+ /* Group Add request on p2p0 */
+ dev = bcmcfg_to_prmry_ndev(cfg);
+ dev_role = NL80211_IFTYPE_P2P_GO;
+ }
+#endif /* WL_ENABLE_P2P_IF */
+
+ if ((bssidx = wl_get_bssidx_by_wdev(cfg, dev->ieee80211_ptr)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", dev->ieee80211_ptr));
+ return BCME_ERROR;
+ }
+
+ if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
+ dev_role = NL80211_IFTYPE_P2P_GO;
+ } else if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) {
+ dhd->op_mode |= DHD_FLAG_HOSTAP_MODE;
+ }
+
+ if (!check_dev_role_integrity(cfg, dev_role)) {
+ err = -ENODEV;
+ goto fail;
+ }
+
+ if ((dev_role == NL80211_IFTYPE_P2P_GO) && (cfg->p2p_wdev == NULL)) {
+ WL_ERR(("P2P already down status!\n"));
+ err = BCME_ERROR;
+ goto fail;
+ }
+
+ ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
+ /* find the SSID */
+ if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset],
+ info->head_len - ie_offset,
+ DOT11_MNG_SSID_ID)) != NULL) {
+ if (dev_role == NL80211_IFTYPE_AP) {
+ /* Store the hostapd SSID */
+ memset(&cfg->hostapd_ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN);
+ cfg->hostapd_ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
+ memcpy(&cfg->hostapd_ssid.SSID[0], ssid_ie->data,
+ cfg->hostapd_ssid.SSID_len);
+ } else {
+ /* P2P GO */
+ memset(&cfg->p2p->ssid.SSID[0], 0x00, DOT11_MAX_SSID_LEN);
+ cfg->p2p->ssid.SSID_len = MIN(ssid_ie->len, DOT11_MAX_SSID_LEN);
+ memcpy(cfg->p2p->ssid.SSID, ssid_ie->data,
+ cfg->p2p->ssid.SSID_len);
+ }
+ }
+
+ if (wl_cfg80211_parse_ies((u8 *)info->tail,
+ info->tail_len, &ies) < 0) {
+ WL_ERR(("Beacon get IEs failed \n"));
+ err = -EINVAL;
+ goto fail;
+ }
+
+ if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
+ VNDR_IE_BEACON_FLAG, (u8 *)info->tail,
+ info->tail_len)) < 0) {
+ WL_ERR(("Beacon set IEs failed \n"));
+ goto fail;
+ } else {
+ WL_DBG(("Applied Vndr IEs for Beacon \n"));
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+ if ((err = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev), bssidx,
+ VNDR_IE_PRBRSP_FLAG, (u8 *)info->proberesp_ies,
+ info->proberesp_ies_len)) < 0) {
+ WL_ERR(("ProbeRsp set IEs failed \n"));
+ goto fail;
+ } else {
+ WL_DBG(("Applied Vndr IEs for ProbeRsp \n"));
+ }
+#endif
+
+ is_bss_up = wl_cfgp2p_bss_isup(dev, bssidx);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+ privacy = info->privacy;
+#else
+ privacy = 0;
+#endif
+ if (!is_bss_up &&
+ (wl_cfg80211_bcn_validate_sec(dev, &ies, dev_role, bssidx, privacy) < 0))
+ {
+ WL_ERR(("Beacon set security failed \n"));
+ err = -EINVAL;
+ goto fail;
+ }
+
+ /* Set BI and DTIM period */
+ if (info->interval) {
+ if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD,
+ &info->interval, sizeof(s32), true)) < 0) {
+ WL_ERR(("Beacon Interval Set Error, %d\n", err));
+ return err;
+ }
+ }
+ if (info->dtim_period) {
+ if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD,
+ &info->dtim_period, sizeof(s32), true)) < 0) {
+ WL_ERR(("DTIM Interval Set Error, %d\n", err));
+ return err;
+ }
+ }
+
+ /* If bss is already up, skip bring up */
+ if (!is_bss_up &&
+ (err = wl_cfg80211_bcn_bringup_ap(dev, &ies, dev_role, bssidx)) < 0)
+ {
+ WL_ERR(("Beacon bring up AP/GO failed \n"));
+ goto fail;
+ }
+
+ /* Set GC/STA SCB expiry timings. */
+ if ((err = wl_cfg80211_set_scb_timings(cfg, dev))) {
+ WL_ERR(("scb setting failed \n"));
+ goto fail;
+ }
+
+ if (wl_get_drv_status(cfg, AP_CREATED, dev)) {
+ /* Soft AP already running. Update changed params */
+ if (wl_cfg80211_hostapd_sec(dev, &ies, bssidx) < 0) {
+ WL_ERR(("Hostapd update sec failed \n"));
+ err = -EINVAL;
+ goto fail;
+ }
+ }
+
+ /* Enable Probe Req filter */
+ if (((dev_role == NL80211_IFTYPE_P2P_GO) ||
+ (dev_role == NL80211_IFTYPE_AP)) && (ies.wps_ie != NULL)) {
+ wl_validate_wps_ie((char *) ies.wps_ie, ies.wps_ie_len, &pbc);
+ if (pbc)
+ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, true);
+ }
+
+ WL_DBG(("** ADD/SET beacon done **\n"));
+
+fail:
+ if (err) {
+ WL_ERR(("ADD/SET beacon failed\n"));
+ wldev_iovar_setint(dev, "mpc", 1);
+ if (dev_role == NL80211_IFTYPE_AP) {
+ /* clear the AP mode */
+ dhd->op_mode &= ~DHD_FLAG_HOSTAP_MODE;
+ }
+ }
+ return err;
+
+}
+#endif /* LINUX_VERSION < VERSION(3,4,0) || WL_COMPAT_WIRELESS */
+
+#ifdef WL_SCHED_SCAN
+#define PNO_TIME 30
+#define PNO_REPEAT 4
+#define PNO_FREQ_EXPO_MAX 2
+static bool
+is_ssid_in_list(struct cfg80211_ssid *ssid, struct cfg80211_ssid *ssid_list, int count)
+{
+ int i;
+
+ if (!ssid || !ssid_list)
+ return FALSE;
+
+ for (i = 0; i < count; i++) {
+ if (ssid->ssid_len == ssid_list[i].ssid_len) {
+ if (strncmp(ssid->ssid, ssid_list[i].ssid, ssid->ssid_len) == 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static int
+wl_cfg80211_sched_scan_start(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_sched_scan_request *request)
+{
+ ushort pno_time = PNO_TIME;
+ int pno_repeat = PNO_REPEAT;
+ int pno_freq_expo_max = PNO_FREQ_EXPO_MAX;
+ wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT];
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct cfg80211_ssid *ssid = NULL;
+ struct cfg80211_ssid *hidden_ssid_list = NULL;
+ int ssid_cnt = 0;
+ int i;
+ int ret = 0;
+
+ if (!request) {
+ WL_ERR(("Sched scan request was NULL\n"));
+ return -EINVAL;
+ }
+
+ WL_DBG(("Enter \n"));
+ WL_PNO((">>> SCHED SCAN START\n"));
+ WL_PNO(("Enter n_match_sets:%d n_ssids:%d \n",
+ request->n_match_sets, request->n_ssids));
+ WL_PNO(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n",
+ request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max));
+
+
+ if (!request->n_ssids || !request->n_match_sets) {
+ WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids));
+ return -EINVAL;
+ }
+
+ memset(&ssids_local, 0, sizeof(ssids_local));
+
+ if (request->n_ssids > 0) {
+ hidden_ssid_list = request->ssids;
+ }
+
+ for (i = 0; i < request->n_match_sets && ssid_cnt < MAX_PFN_LIST_COUNT; i++) {
+ ssid = &request->match_sets[i].ssid;
+ /* No need to include null ssid */
+ if (ssid->ssid_len) {
+ ssids_local[ssid_cnt].SSID_len = MIN(ssid->ssid_len,
+ (uint32)DOT11_MAX_SSID_LEN);
+ memcpy(ssids_local[ssid_cnt].SSID, ssid->ssid,
+ ssids_local[ssid_cnt].SSID_len);
+ if (is_ssid_in_list(ssid, hidden_ssid_list, request->n_ssids)) {
+ ssids_local[ssid_cnt].hidden = TRUE;
+ WL_PNO((">>> PNO hidden SSID (%s) \n", ssid->ssid));
+ } else {
+ ssids_local[ssid_cnt].hidden = FALSE;
+ WL_PNO((">>> PNO non-hidden SSID (%s) \n", ssid->ssid));
+ }
+ ssid_cnt++;
+ }
+ }
+
+ if (ssid_cnt) {
+ if ((ret = dhd_dev_pno_set_for_ssid(dev, ssids_local, ssid_cnt,
+ pno_time, pno_repeat, pno_freq_expo_max, NULL, 0)) < 0) {
+ WL_ERR(("PNO setup failed!! ret=%d \n", ret));
+ return -EINVAL;
+ }
+ cfg->sched_scan_req = request;
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+
+ WL_DBG(("Enter \n"));
+ WL_PNO((">>> SCHED SCAN STOP\n"));
+
+ if (dhd_dev_pno_stop_for_ssid(dev) < 0)
+ WL_ERR(("PNO Stop for SSID failed"));
+
+ if (cfg->scan_request && cfg->sched_scan_running) {
+ WL_PNO((">>> Sched scan running. Aborting it..\n"));
+ wl_notify_escan_complete(cfg, dev, true, true);
+ }
+
+ cfg->sched_scan_req = NULL;
+ cfg->sched_scan_running = FALSE;
+
+ return 0;
+}
+#endif /* WL_SCHED_SCAN */
+
+#ifdef WL_SUPPORT_ACS
+/*
+ * Currently the dump_obss IOVAR is returning string as output so we need to
+ * parse the output buffer in an unoptimized way. Going forward if we get the
+ * IOVAR output in binary format this method can be optimized
+ */
+static int wl_parse_dump_obss(char *buf, struct wl_dump_survey *survey)
+{
+ int i;
+ char *token;
+ char delim[] = " \n";
+
+ token = strsep(&buf, delim);
+ while (token != NULL) {
+ if (!strcmp(token, "OBSS")) {
+ for (i = 0; i < OBSS_TOKEN_IDX; i++)
+ token = strsep(&buf, delim);
+ survey->obss = simple_strtoul(token, NULL, 10);
+ }
+
+ if (!strcmp(token, "IBSS")) {
+ for (i = 0; i < IBSS_TOKEN_IDX; i++)
+ token = strsep(&buf, delim);
+ survey->ibss = simple_strtoul(token, NULL, 10);
+ }
+
+ if (!strcmp(token, "TXDur")) {
+ for (i = 0; i < TX_TOKEN_IDX; i++)
+ token = strsep(&buf, delim);
+ survey->tx = simple_strtoul(token, NULL, 10);
+ }
+
+ if (!strcmp(token, "Category")) {
+ for (i = 0; i < CTG_TOKEN_IDX; i++)
+ token = strsep(&buf, delim);
+ survey->no_ctg = simple_strtoul(token, NULL, 10);
+ }
+
+ if (!strcmp(token, "Packet")) {
+ for (i = 0; i < PKT_TOKEN_IDX; i++)
+ token = strsep(&buf, delim);
+ survey->no_pckt = simple_strtoul(token, NULL, 10);
+ }
+
+ if (!strcmp(token, "Opp(time):")) {
+ for (i = 0; i < IDLE_TOKEN_IDX; i++)
+ token = strsep(&buf, delim);
+ survey->idle = simple_strtoul(token, NULL, 10);
+ }
+
+ token = strsep(&buf, delim);
+ }
+
+ return 0;
+}
+
+static int wl_dump_obss(struct net_device *ndev, cca_msrmnt_query req,
+ struct wl_dump_survey *survey)
+{
+ cca_stats_n_flags *results;
+ char *buf;
+ int retry, err;
+
+ buf = kzalloc(sizeof(char) * WLC_IOCTL_MAXLEN, GFP_KERNEL);
+ if (unlikely(!buf)) {
+ WL_ERR(("%s: buf alloc failed\n", __func__));
+ return -ENOMEM;
+ }
+
+ retry = IOCTL_RETRY_COUNT;
+ while (retry--) {
+ err = wldev_iovar_getbuf(ndev, "dump_obss", &req, sizeof(req),
+ buf, WLC_IOCTL_MAXLEN, NULL);
+ if (err >= 0) {
+ break;
+ }
+ WL_DBG(("attempt = %d, err = %d, \n",
+ (IOCTL_RETRY_COUNT - retry), err));
+ }
+
+ if (retry <= 0) {
+ WL_ERR(("failure, dump_obss IOVAR failed\n"));
+ err = -EINVAL;
+ goto exit;
+ }
+
+ results = (cca_stats_n_flags *)(buf);
+ wl_parse_dump_obss(results->buf, survey);
+ kfree(buf);
+
+ return 0;
+exit:
+ kfree(buf);
+ return err;
+}
+
+static int wl_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *ndev,
+ int idx, struct survey_info *info)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct wl_dump_survey *survey;
+ struct ieee80211_supported_band *band;
+ struct ieee80211_channel*chan;
+ cca_msrmnt_query req;
+ int val, err, noise, retry;
+
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+ if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
+ return -ENOENT;
+ }
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ if (band && idx >= band->n_channels) {
+ idx -= band->n_channels;
+ band = NULL;
+ }
+
+ if (!band || idx >= band->n_channels) {
+ /* Move to 5G band */
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+ if (idx >= band->n_channels) {
+ return -ENOENT;
+ }
+ }
+
+ chan = &band->channels[idx];
+ /* Setting current channel to the requested channel */
+ if ((err = wl_cfg80211_set_channel(wiphy, ndev, chan,
+ NL80211_CHAN_HT20) < 0)) {
+ WL_ERR(("Set channel failed \n"));
+ }
+
+ if (!idx) {
+ /* Disable mpc */
+ val = 0;
+ err = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val,
+ sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
+ &cfg->ioctl_buf_sync);
+ if (err < 0) {
+ WL_ERR(("set 'mpc' failed, error = %d\n", err));
+ }
+
+ /* Set interface up, explicitly. */
+ val = 1;
+ err = wldev_ioctl(ndev, WLC_UP, (void *)&val, sizeof(val), true);
+ if (err < 0) {
+ WL_ERR(("set interface up failed, error = %d\n", err));
+ }
+ }
+
+ /* Get noise value */
+ retry = IOCTL_RETRY_COUNT;
+ while (retry--) {
+ err = wldev_ioctl(ndev, WLC_GET_PHY_NOISE, &noise,
+ sizeof(noise), false);
+ if (err >= 0) {
+ break;
+ }
+ WL_DBG(("attempt = %d, err = %d, \n",
+ (IOCTL_RETRY_COUNT - retry), err));
+ }
+
+ if (retry <= 0) {
+ WL_ERR(("Get Phy Noise failed, error = %d\n", err));
+ noise = CHAN_NOISE_DUMMY;
+ }
+
+ survey = (struct wl_dump_survey *) kzalloc(sizeof(struct wl_dump_survey),
+ GFP_KERNEL);
+ if (unlikely(!survey)) {
+ WL_ERR(("%s: alloc failed\n", __func__));
+ return -ENOMEM;
+ }
+
+ /* Start Measurement for obss stats on current channel */
+ req.msrmnt_query = 0;
+ req.time_req = ACS_MSRMNT_DELAY;
+ if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
+ goto exit;
+ }
+
+ /*
+ * Wait for the meaurement to complete, adding a buffer value of 10 to take
+ * into consideration any delay in IOVAR completion
+ */
+ msleep(ACS_MSRMNT_DELAY + 10);
+
+ /* Issue IOVAR to collect measurement results */
+ req.msrmnt_query = 1;
+ if ((err = wl_dump_obss(ndev, req, survey)) < 0) {
+ goto exit;
+ }
+
+ info->channel = chan;
+ info->noise = noise;
+ info->channel_time = ACS_MSRMNT_DELAY;
+ info->channel_time_busy = ACS_MSRMNT_DELAY - survey->idle;
+ info->channel_time_rx = survey->obss + survey->ibss + survey->no_ctg +
+ survey->no_pckt;
+ info->channel_time_tx = survey->tx;
+ info->filled = SURVEY_INFO_NOISE_DBM |SURVEY_INFO_CHANNEL_TIME |
+ SURVEY_INFO_CHANNEL_TIME_BUSY | SURVEY_INFO_CHANNEL_TIME_RX |
+ SURVEY_INFO_CHANNEL_TIME_TX;
+ kfree(survey);
+
+ return 0;
+exit:
+ kfree(survey);
+ return err;
+}
+#endif /* WL_SUPPORT_ACS */
+
+static struct cfg80211_ops wl_cfg80211_ops = {
+ .add_virtual_intf = wl_cfg80211_add_virtual_iface,
+ .del_virtual_intf = wl_cfg80211_del_virtual_iface,
+ .change_virtual_intf = wl_cfg80211_change_virtual_iface,
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ .start_p2p_device = wl_cfgp2p_start_p2p_device,
+ .stop_p2p_device = wl_cfgp2p_stop_p2p_device,
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ .scan = wl_cfg80211_scan,
+ .set_wiphy_params = wl_cfg80211_set_wiphy_params,
+ .join_ibss = wl_cfg80211_join_ibss,
+ .leave_ibss = wl_cfg80211_leave_ibss,
+ .get_station = wl_cfg80211_get_station,
+ .set_tx_power = wl_cfg80211_set_tx_power,
+ .get_tx_power = wl_cfg80211_get_tx_power,
+ .add_key = wl_cfg80211_add_key,
+ .del_key = wl_cfg80211_del_key,
+ .get_key = wl_cfg80211_get_key,
+ .set_default_key = wl_cfg80211_config_default_key,
+ .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
+ .set_power_mgmt = wl_cfg80211_set_power_mgmt,
+ .connect = wl_cfg80211_connect,
+ .disconnect = wl_cfg80211_disconnect,
+ .suspend = wl_cfg80211_suspend,
+ .resume = wl_cfg80211_resume,
+ .set_pmksa = wl_cfg80211_set_pmksa,
+ .del_pmksa = wl_cfg80211_del_pmksa,
+ .flush_pmksa = wl_cfg80211_flush_pmksa,
+ .remain_on_channel = wl_cfg80211_remain_on_channel,
+ .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel,
+ .mgmt_tx = wl_cfg80211_mgmt_tx,
+ .mgmt_frame_register = wl_cfg80211_mgmt_frame_register,
+ .change_bss = wl_cfg80211_change_bss,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) || defined(WL_COMPAT_WIRELESS)
+ .set_channel = wl_cfg80211_set_channel,
+#endif /* ((LINUX_VERSION < VERSION(3, 6, 0)) || WL_COMPAT_WIRELESS */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)) && !defined(WL_COMPAT_WIRELESS)
+ .set_beacon = wl_cfg80211_add_set_beacon,
+ .add_beacon = wl_cfg80211_add_set_beacon,
+#else
+ .change_beacon = wl_cfg80211_change_beacon,
+ .start_ap = wl_cfg80211_start_ap,
+ .stop_ap = wl_cfg80211_stop_ap,
+#endif /* LINUX_VERSION < KERNEL_VERSION(3,4,0) && !WL_COMPAT_WIRELESS */
+#ifdef WL_SCHED_SCAN
+ .sched_scan_start = wl_cfg80211_sched_scan_start,
+ .sched_scan_stop = wl_cfg80211_sched_scan_stop,
+#endif /* WL_SCHED_SCAN */
+#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
+ 2, 0))
+ .del_station = wl_cfg80211_del_station,
+ .change_station = wl_cfg80211_change_station,
+ .mgmt_tx_cancel_wait = wl_cfg80211_mgmt_tx_cancel_wait,
+#endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VERSION >= (3,2,0) */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
+ .tdls_mgmt = wl_cfg80211_tdls_mgmt,
+ .tdls_oper = wl_cfg80211_tdls_oper,
+#endif /* LINUX_VERSION > VERSION(3, 2, 0) || WL_COMPAT_WIRELESS */
+#ifdef WL_SUPPORT_ACS
+ .dump_survey = wl_cfg80211_dump_survey,
+#endif /* WL_SUPPORT_ACS */
+#ifdef WL_CFG80211_ACL
+ .set_mac_acl = wl_cfg80211_set_mac_acl,
+#endif /* WL_CFG80211_ACL */
+};
+
+s32 wl_mode_to_nl80211_iftype(s32 mode)
+{
+ s32 err = 0;
+
+ switch (mode) {
+ case WL_MODE_BSS:
+ return NL80211_IFTYPE_STATION;
+ case WL_MODE_IBSS:
+ return NL80211_IFTYPE_ADHOC;
+ case WL_MODE_AP:
+ return NL80211_IFTYPE_AP;
+ default:
+ return NL80211_IFTYPE_UNSPECIFIED;
+ }
+
+ return err;
+}
+
+#ifdef CONFIG_CFG80211_INTERNAL_REGDB
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
+static int
+#else
+static void
+#endif /* kernel version < 3.9.0 */
+wl_cfg80211_reg_notifier(
+ struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
+ int ret = 0;
+ int revinfo = -1;
+
+ if (!request || !cfg) {
+ WL_ERR(("Invalid arg\n"));
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
+ return -EINVAL;
+#else
+ return;
+#endif /* kernel version < 3.9.0 */
+ }
+
+ WL_DBG(("ccode: %c%c Initiator: %d\n",
+ request->alpha2[0], request->alpha2[1], request->initiator));
+
+ /* We support only REGDOM_SET_BY_USER as of now */
+ if ((request->initiator != NL80211_REGDOM_SET_BY_USER) &&
+ (request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
+ WL_ERR(("reg_notifier for intiator:%d not supported : set default\n",
+ request->initiator));
+ /* in case of no supported country by regdb
+ lets driver setup platform default Locale
+ */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
+ return -EINVAL;
+#else
+ return;
+#endif /* kernel version < 3.9.0 */
+ }
+
+ WL_ERR(("Set country code %c%c from %s\n",
+ request->alpha2[0], request->alpha2[1],
+ ((request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) ? " 11d AP" : "User")));
+
+ if ((ret = wldev_set_country(bcmcfg_to_prmry_ndev(cfg), request->alpha2,
+ false, (request->initiator == NL80211_REGDOM_SET_BY_USER ? true : false),
+ revinfo)) < 0) {
+ WL_ERR(("set country Failed :%d\n", ret));
+ }
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0))
+ return ret;
+#else
+ return;
+#endif /* kernel version < 3.9.0 */
+}
+#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
+
+#ifdef CONFIG_PM
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+static const struct wiphy_wowlan_support brcm_wowlan_support = {
+ .flags = WIPHY_WOWLAN_ANY,
+ .n_patterns = WL_WOWLAN_MAX_PATTERNS,
+ .pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN,
+ .pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+ .max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN,
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+};
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+static struct cfg80211_wowlan brcm_wowlan_config = {
+ .disconnect = true,
+ .gtk_rekey_failure = true,
+ .eap_identity_req = true,
+ .four_way_handshake = true,
+};
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
+#endif /* CONFIG_PM */
+
+static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev, void *context)
+{
+ s32 err = 0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
+ dhd_pub_t *dhd = (dhd_pub_t *)context;
+ BCM_REFERENCE(dhd);
+
+ if (!dhd) {
+ WL_ERR(("DHD is NULL!!"));
+ err = -ENODEV;
+ return err;
+ }
+#endif
+
+ wdev->wiphy =
+ wiphy_new(&wl_cfg80211_ops, sizeof(struct bcm_cfg80211));
+ if (unlikely(!wdev->wiphy)) {
+ WL_ERR(("Couldn not allocate wiphy device\n"));
+ err = -ENOMEM;
+ return err;
+ }
+ set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
+ wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
+ /* Report how many SSIDs Driver can support per Scan request */
+ wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
+ wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
+#ifdef WL_SCHED_SCAN
+ wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT;
+ wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT;
+ wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX;
+ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+#endif /* WL_SCHED_SCAN */
+ wdev->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_STATION)
+ | BIT(NL80211_IFTYPE_ADHOC)
+#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF)
+ | BIT(NL80211_IFTYPE_MONITOR)
+#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */
+#if defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF)
+ | BIT(NL80211_IFTYPE_P2P_CLIENT)
+ | BIT(NL80211_IFTYPE_P2P_GO)
+#endif /* WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF */
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ | BIT(NL80211_IFTYPE_P2P_DEVICE)
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ | BIT(NL80211_IFTYPE_AP);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && \
+ (defined(WL_IFACE_COMB_NUM_CHANNELS) || defined(WL_CFG80211_P2P_DEV_IF))
+ WL_DBG(("Setting interface combinations for common mode\n"));
+ wdev->wiphy->iface_combinations = common_iface_combinations;
+ wdev->wiphy->n_iface_combinations =
+ ARRAY_SIZE(common_iface_combinations);
+#endif /* LINUX_VER >= 3.0 && (WL_IFACE_COMB_NUM_CHANNELS || WL_CFG80211_P2P_DEV_IF) */
+
+ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
+
+ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wdev->wiphy->cipher_suites = __wl_cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
+ wdev->wiphy->max_remain_on_channel_duration = 5000;
+ wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes;
+#ifndef WL_POWERSAVE_DISABLED
+ wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
+#else
+ wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+#endif /* !WL_POWERSAVE_DISABLED */
+ wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK |
+ WIPHY_FLAG_4ADDR_AP |
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && !defined(WL_COMPAT_WIRELESS)
+ WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
+#endif
+ WIPHY_FLAG_4ADDR_STATION;
+#if ((defined(ROAM_ENABLE) || defined(BCMFW_ROAM_ENABLE)) && ((LINUX_VERSION_CODE >= \
+ KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)))
+ /*
+ * If FW ROAM flag is advertised, upper layer wouldn't provide
+ * the bssid & freq in the connect command. This will result a
+ * delay in initial connection time due to firmware doing a full
+ * channel scan to figure out the channel & bssid. However kernel
+ * ver >= 3.15, provides bssid_hint & freq_hint and hence kernel
+ * ver >= 3.15 won't have any issue. So if this flags need to be
+ * advertised for kernel < 3.15, suggest to use RCC along with it
+ * to avoid the initial connection delay.
+ */
+ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
+#endif /* (ROAM_ENABLE || BCMFW_ROAM_ENABLE) && (LINUX_VERSION 3.2.0 || WL_COMPAT_WIRELESS) */
+#ifdef UNSET_FW_ROAM_WIPHY_FLAG
+ wdev->wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_FW_ROAM;
+#endif /* UNSET_FW_ROAM_WIPHY_FLAG */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) || defined(WL_COMPAT_WIRELESS)
+ wdev->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+ WIPHY_FLAG_OFFCHAN_TX;
+#endif
+#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
+ 4, 0))
+ /* From 3.4 kernel ownards AP_SME flag can be advertised
+ * to remove the patch from supplicant
+ */
+ wdev->wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
+
+#ifdef WL_CFG80211_ACL
+ /* Configure ACL capabilities. */
+ wdev->wiphy->max_acl_mac_addrs = MAX_NUM_MAC_FILT;
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) || defined(WL_COMPAT_WIRELESS))
+ /* Supplicant distinguish between the SoftAP mode and other
+ * modes (e.g. P2P, WPS, HS2.0) when it builds the probe
+ * response frame from Supplicant MR1 and Kernel 3.4.0 or
+ * later version. To add Vendor specific IE into the
+ * probe response frame in case of SoftAP mode,
+ * AP_PROBE_RESP_OFFLOAD flag is set to wiphy->flags variable.
+ */
+ if (dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) {
+ wdev->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
+ wdev->wiphy->probe_resp_offload = 0;
+ }
+#endif
+#endif /* WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
+ wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
+#endif
+
+#if defined(CONFIG_PM) && defined(WL_CFG80211_P2P_DEV_IF)
+ /*
+ * From linux-3.10 kernel, wowlan packet filter is mandated to avoid the
+ * disconnection of connected network before suspend. So a dummy wowlan
+ * filter is configured for kernels linux-3.8 and above.
+ */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+ wdev->wiphy->wowlan = &brcm_wowlan_support;
+ /* If this is not provided cfg stack will get disconnect
+ * during suspend.
+ */
+ wdev->wiphy->wowlan_config = &brcm_wowlan_config;
+#else
+ wdev->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
+ wdev->wiphy->wowlan.n_patterns = WL_WOWLAN_MAX_PATTERNS;
+ wdev->wiphy->wowlan.pattern_min_len = WL_WOWLAN_MIN_PATTERN_LEN;
+ wdev->wiphy->wowlan.pattern_max_len = WL_WOWLAN_MAX_PATTERN_LEN;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+ wdev->wiphy->wowlan.max_pkt_offset = WL_WOWLAN_MAX_PATTERN_LEN;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
+#endif /* CONFIG_PM && WL_CFG80211_P2P_DEV_IF */
+
+ WL_DBG(("Registering custom regulatory)\n"));
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+ wdev->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
+#else
+ wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+#endif
+ wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom);
+#if defined(WL_VENDOR_EXT_SUPPORT)
+ WL_ERR(("Registering Vendor80211\n"));
+ err = wl_cfgvendor_attach(wdev->wiphy);
+ if (unlikely(err < 0)) {
+ WL_ERR(("Couldn not attach vendor commands (%d)\n", err));
+ }
+#endif /* defined(WL_VENDOR_EXT_SUPPORT) */
+ /* Now we can register wiphy with cfg80211 module */
+ err = wiphy_register(wdev->wiphy);
+ if (unlikely(err < 0)) {
+ WL_ERR(("Couldn not register wiphy device (%d)\n", err));
+ wiphy_free(wdev->wiphy);
+ }
+
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) && (LINUX_VERSION_CODE <= \
+ KERNEL_VERSION(3, 3, 0))) && defined(WL_IFACE_COMB_NUM_CHANNELS)
+ wdev->wiphy->flags &= ~WIPHY_FLAG_ENFORCE_COMBINATIONS;
+#endif
+
+ return err;
+}
+
+static void wl_free_wdev(struct bcm_cfg80211 *cfg)
+{
+ struct wireless_dev *wdev = cfg->wdev;
+ struct wiphy *wiphy = NULL;
+ if (!wdev) {
+ WL_ERR(("wdev is invalid\n"));
+ return;
+ }
+ if (wdev->wiphy) {
+ wiphy = wdev->wiphy;
+
+#if defined(WL_VENDOR_EXT_SUPPORT)
+ wl_cfgvendor_detach(wdev->wiphy);
+#endif /* if defined(WL_VENDOR_EXT_SUPPORT) */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
+ /* Reset wowlan & wowlan_config before Unregister to avoid Kernel Panic */
+ WL_DBG(("wl_free_wdev Clearing wowlan Config \n"));
+ wdev->wiphy->wowlan = NULL;
+ wdev->wiphy->wowlan_config = NULL;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) */
+ wiphy_unregister(wdev->wiphy);
+ wdev->wiphy->dev.parent = NULL;
+ wdev->wiphy = NULL;
+ }
+
+ wl_delete_all_netinfo(cfg);
+ if (wiphy)
+ wiphy_free(wiphy);
+
+ /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "cfg",
+ * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!!
+ */
+}
+
+static s32 wl_inform_bss(struct bcm_cfg80211 *cfg)
+{
+ struct wl_scan_results *bss_list;
+ struct wl_bss_info *bi = NULL; /* must be initialized */
+ s32 err = 0;
+ s32 i;
+
+ bss_list = cfg->bss_list;
+ WL_DBG(("scanned AP count (%d)\n", bss_list->count));
+ bi = next_bss(bss_list, bi);
+ for_each_bss(bss_list, bi, i) {
+ err = wl_inform_single_bss(cfg, bi, false);
+ if (unlikely(err))
+ break;
+ }
+ return err;
+}
+
+static s32 wl_inform_single_bss(struct bcm_cfg80211 *cfg, struct wl_bss_info *bi, bool roam)
+{
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ struct ieee80211_mgmt *mgmt;
+ struct ieee80211_channel *channel;
+ struct ieee80211_supported_band *band;
+ struct wl_cfg80211_bss_info *notif_bss_info;
+ struct wl_scan_req *sr = wl_to_sr(cfg);
+ struct beacon_proberesp *beacon_proberesp;
+ struct cfg80211_bss *cbss = NULL;
+ s32 mgmt_type;
+ s32 signal;
+ u32 freq;
+ s32 err = 0;
+ gfp_t aflags;
+
+ if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) {
+ WL_DBG(("Beacon is larger than buffer. Discarding\n"));
+ return err;
+ }
+ aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
+ notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt)
+ - sizeof(u8) + WL_BSS_INFO_MAX, aflags);
+ if (unlikely(!notif_bss_info)) {
+ WL_ERR(("notif_bss_info alloc failed\n"));
+ return -ENOMEM;
+ }
+ mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf;
+ notif_bss_info->channel =
+ wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
+
+ if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+ if (!band) {
+ WL_ERR(("No valid band"));
+ kfree(notif_bss_info);
+ return -EINVAL;
+ }
+ notif_bss_info->rssi = wl_rssi_offset(dtoh16(bi->RSSI));
+ memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN);
+ mgmt_type = cfg->active_scan ?
+ IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON;
+ if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) {
+ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type);
+ }
+ beacon_proberesp = cfg->active_scan ?
+ (struct beacon_proberesp *)&mgmt->u.probe_resp :
+ (struct beacon_proberesp *)&mgmt->u.beacon;
+ beacon_proberesp->timestamp = 0;
+ beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period);
+ beacon_proberesp->capab_info = cpu_to_le16(bi->capability);
+ wl_rst_ie(cfg);
+ wl_update_hidden_ap_ie(bi, ((u8 *) bi) + bi->ie_offset, &bi->ie_length, roam);
+ wl_mrg_ie(cfg, ((u8 *) bi) + bi->ie_offset, bi->ie_length);
+ wl_cp_ie(cfg, beacon_proberesp->variable, WL_BSS_INFO_MAX -
+ offsetof(struct wl_cfg80211_bss_info, frame_buf));
+ notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt,
+ u.beacon.variable) + wl_get_ielen(cfg);
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
+ freq = ieee80211_channel_to_frequency(notif_bss_info->channel);
+ (void)band->band;
+#else
+ freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band);
+#endif
+ if (freq == 0) {
+ WL_ERR(("Invalid channel, fail to chcnage channel to freq\n"));
+ kfree(notif_bss_info);
+ return -EINVAL;
+ }
+ channel = ieee80211_get_channel(wiphy, freq);
+ if (unlikely(!channel)) {
+ WL_ERR(("ieee80211_get_channel error\n"));
+ kfree(notif_bss_info);
+ return -EINVAL;
+ }
+ WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM"
+ "mgmt_type %d frame_len %d\n", bi->SSID,
+ notif_bss_info->rssi, notif_bss_info->channel,
+ mgmt->u.beacon.capab_info, &bi->BSSID, mgmt_type,
+ notif_bss_info->frame_len));
+
+ signal = notif_bss_info->rssi * 100;
+ if (!mgmt->u.probe_resp.timestamp) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
+ struct timespec ts;
+ get_monotonic_boottime(&ts);
+ mgmt->u.probe_resp.timestamp = ((u64)ts.tv_sec*1000000)
+ + ts.tv_nsec / 1000;
+#else
+ struct timeval tv;
+ do_gettimeofday(&tv);
+ mgmt->u.probe_resp.timestamp = ((u64)tv.tv_sec*1000000)
+ + tv.tv_usec;
+#endif
+ }
+
+
+ cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt,
+ le16_to_cpu(notif_bss_info->frame_len), signal, aflags);
+ if (unlikely(!cbss)) {
+ WL_ERR(("cfg80211_inform_bss_frame error\n"));
+ kfree(notif_bss_info);
+ return -EINVAL;
+ }
+
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0))
+ cfg80211_put_bss(wiphy, cbss);
+#else
+ cfg80211_put_bss(cbss);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) */
+ kfree(notif_bss_info);
+ return err;
+}
+
+static bool wl_is_linkup(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e, struct net_device *ndev)
+{
+ u32 event = ntoh32(e->event_type);
+ u32 status = ntoh32(e->status);
+ u16 flags = ntoh16(e->flags);
+
+ WL_DBG(("event %d, status %d flags %x\n", event, status, flags));
+ if (event == WLC_E_SET_SSID) {
+ if (status == WLC_E_STATUS_SUCCESS) {
+ if (!wl_is_ibssmode(cfg, ndev))
+ return true;
+ }
+ } else if (event == WLC_E_LINK) {
+ if (flags & WLC_EVENT_MSG_LINK)
+ return true;
+ }
+
+ WL_DBG(("wl_is_linkup false\n"));
+ return false;
+}
+
+static bool wl_is_linkdown(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
+{
+ u32 event = ntoh32(e->event_type);
+ u16 flags = ntoh16(e->flags);
+
+ if (event == WLC_E_DEAUTH_IND ||
+ event == WLC_E_DISASSOC_IND ||
+ event == WLC_E_DISASSOC ||
+ event == WLC_E_DEAUTH) {
+#if (WL_DBG_LEVEL > 0)
+ WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event]));
+#endif /* (WL_DBG_LEVEL > 0) */
+ return true;
+ } else if (event == WLC_E_LINK) {
+ if (!(flags & WLC_EVENT_MSG_LINK)) {
+#if (WL_DBG_LEVEL > 0)
+ WL_ERR(("Link down Reason : WLC_E_%s\n", wl_dbg_estr[event]));
+#endif /* (WL_DBG_LEVEL > 0) */
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool wl_is_nonetwork(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
+{
+ u32 event = ntoh32(e->event_type);
+ u32 status = ntoh32(e->status);
+
+ if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS)
+ return true;
+ if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS)
+ return true;
+
+ return false;
+}
+
+/* The mainline kernel >= 3.2.0 has support for indicating new/del station
+ * to AP/P2P GO via events. If this change is backported to kernel for which
+ * this driver is being built, then define WL_CFG80211_STA_EVENT. You
+ * should use this new/del sta event mechanism for BRCM supplicant >= 22.
+ */
+static s32
+wl_notify_connect_status_ap(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data)
+{
+ s32 err = 0;
+ u32 event = ntoh32(e->event_type);
+ u32 reason = ntoh32(e->reason);
+ u32 len = ntoh32(e->datalen);
+ u32 status = ntoh32(e->status);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) \
+ && !defined(WL_COMPAT_WIRELESS)
+ bool isfree = false;
+ u8 *mgmt_frame;
+ u8 bsscfgidx = e->bsscfgidx;
+ s32 freq;
+ s32 channel;
+ u8 *body = NULL;
+ u16 fc = 0;
+
+ struct ieee80211_supported_band *band;
+ struct ether_addr da;
+ struct ether_addr bssid;
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ channel_info_t ci;
+#else
+ struct station_info sinfo;
+#endif /* (LINUX_VERSION < VERSION(3,2,0)) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
+
+ WL_DBG(("event %d status %d reason %d\n", event, ntoh32(e->status), reason));
+ /* if link down, bsscfg is disabled. */
+ if (event == WLC_E_LINK && reason == WLC_E_LINK_BSSCFG_DIS &&
+ wl_get_p2p_status(cfg, IF_DELETING) && (ndev != bcmcfg_to_prmry_ndev(cfg))) {
+ wl_add_remove_eventmsg(ndev, WLC_E_PROBREQ_MSG, false);
+ WL_INFORM(("AP mode link down !! \n"));
+ complete(&cfg->iface_disable);
+ return 0;
+ }
+
+ if ((event == WLC_E_LINK) && (status == WLC_E_STATUS_SUCCESS) &&
+ (reason == WLC_E_REASON_INITIAL_ASSOC) &&
+ (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP)) {
+ if (!wl_get_drv_status(cfg, AP_CREATED, ndev)) {
+ /* AP/GO brought up successfull in firmware */
+ WL_ERR(("** AP/GO Link up event **\n"));
+ wl_set_drv_status(cfg, AP_CREATED, ndev);
+ wake_up_interruptible(&cfg->netif_change_event);
+ return 0;
+ }
+ }
+
+ if (event == WLC_E_DISASSOC_IND || event == WLC_E_DEAUTH_IND || event == WLC_E_DEAUTH) {
+ WL_ERR(("event %s(%d) status %d reason %d\n",
+ bcmevent_get_name(event), event, ntoh32(e->status), reason));
+ }
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !defined(WL_CFG80211_STA_EVENT) \
+ && !defined(WL_COMPAT_WIRELESS)
+ WL_DBG(("Enter \n"));
+ if (!len && (event == WLC_E_DEAUTH)) {
+ len = 2; /* reason code field */
+ data = &reason;
+ }
+ if (len) {
+ body = kzalloc(len, GFP_KERNEL);
+
+ if (body == NULL) {
+ WL_ERR(("wl_notify_connect_status: Failed to allocate body\n"));
+ return WL_INVALID;
+ }
+ }
+ memset(&bssid, 0, ETHER_ADDR_LEN);
+ WL_DBG(("Enter event %d ndev %p\n", event, ndev));
+ if (wl_get_mode_by_netdev(cfg, ndev) == WL_INVALID) {
+ kfree(body);
+ return WL_INVALID;
+ }
+ if (len)
+ memcpy(body, data, len);
+
+ wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
+ NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync);
+ memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN);
+ err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+ switch (event) {
+ case WLC_E_ASSOC_IND:
+ fc = FC_ASSOC_REQ;
+ break;
+ case WLC_E_REASSOC_IND:
+ fc = FC_REASSOC_REQ;
+ break;
+ case WLC_E_DISASSOC_IND:
+ fc = FC_DISASSOC;
+ break;
+ case WLC_E_DEAUTH_IND:
+ fc = FC_DISASSOC;
+ break;
+ case WLC_E_DEAUTH:
+ fc = FC_DISASSOC;
+ break;
+ default:
+ fc = 0;
+ goto exit;
+ }
+ if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) {
+ kfree(body);
+ return err;
+ }
+
+ channel = dtoh32(ci.hw_channel);
+ if (channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+ if (!band) {
+ WL_ERR(("No valid band"));
+ if (body)
+ kfree(body);
+ return -EINVAL;
+ }
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
+ freq = ieee80211_channel_to_frequency(channel);
+ (void)band->band;
+#else
+ freq = ieee80211_channel_to_frequency(channel, band->band);
+#endif
+
+ err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid,
+ &mgmt_frame, &len, body);
+ if (err < 0)
+ goto exit;
+ isfree = true;
+
+ if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
+#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) && (LINUX_VERSION_CODE < \
+ KERNEL_VERSION(3, 18, 0))) || defined(WL_COMPAT_WIRELESS)
+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
+
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len);
+#else
+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
+ } else if (event == WLC_E_DISASSOC_IND) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
+#else
+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
+ } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || defined(WL_COMPAT_WIRELESS)
+ cfg80211_rx_mgmt(ndev, freq, 0, mgmt_frame, len, GFP_ATOMIC);
+#else
+ cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
+#endif /* LINUX_VERSION >= VERSION(3,4,0) || WL_COMPAT_WIRELESS */
+ }
+
+exit:
+ if (isfree)
+ kfree(mgmt_frame);
+ if (body)
+ kfree(body);
+#else /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
+ sinfo.filled = 0;
+ if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) &&
+ reason == DOT11_SC_SUCCESS) {
+ /* Linux ver >= 4.0 assoc_req_ies_len is used instead of
+ * STATION_INFO_ASSOC_REQ_IES flag
+ */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
+ sinfo.filled = STA_INFO_BIT(INFO_ASSOC_REQ_IES);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
+ if (!data) {
+ WL_ERR(("No IEs present in ASSOC/REASSOC_IND"));
+ return -EINVAL;
+ }
+ sinfo.assoc_req_ies = data;
+ sinfo.assoc_req_ies_len = len;
+ cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC);
+ } else if (event == WLC_E_DISASSOC_IND) {
+ cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
+ } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
+ cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC);
+ }
+#endif /* LINUX_VERSION < VERSION(3,2,0) && !WL_CFG80211_STA_EVENT && !WL_COMPAT_WIRELESS */
+ return err;
+}
+
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
+#define MAX_ASSOC_REJECT_ERR_STATUS 5
+int wl_get_connect_failed_status(struct bcm_cfg80211 *cfg, const wl_event_msg_t *e)
+{
+ u32 status = ntoh32(e->status);
+
+ cfg->assoc_reject_status = 0;
+
+ if (status == WLC_E_STATUS_FAIL) {
+ WL_ERR(("auth assoc status event=%d e->status %d e->reason %d \n",
+ ntoh32(cfg->event_auth_assoc.event_type),
+ (int)ntoh32(cfg->event_auth_assoc.status),
+ (int)ntoh32(cfg->event_auth_assoc.reason)));
+
+ switch ((int)ntoh32(cfg->event_auth_assoc.status)) {
+ case WLC_E_STATUS_NO_ACK:
+ cfg->assoc_reject_status = 1;
+ break;
+ case WLC_E_STATUS_FAIL:
+ cfg->assoc_reject_status = 2;
+ break;
+ case WLC_E_STATUS_UNSOLICITED:
+ cfg->assoc_reject_status = 3;
+ break;
+ case WLC_E_STATUS_TIMEOUT:
+ cfg->assoc_reject_status = 4;
+ break;
+ case WLC_E_STATUS_ABORT:
+ cfg->assoc_reject_status = 5;
+ break;
+ default:
+ break;
+ }
+ if (cfg->assoc_reject_status) {
+ if (ntoh32(cfg->event_auth_assoc.event_type) == WLC_E_ASSOC) {
+ cfg->assoc_reject_status += MAX_ASSOC_REJECT_ERR_STATUS;
+ }
+ }
+ }
+
+ WL_ERR(("assoc_reject_status %d \n", cfg->assoc_reject_status));
+
+ return 0;
+}
+
+s32 wl_cfg80211_get_connect_failed_status(struct net_device *dev, char* cmd, int total_len)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ int bytes_written = 0;
+
+ if (cfg == NULL) {
+ return -1;
+ }
+
+ memset(cmd, 0, total_len);
+ bytes_written = snprintf(cmd, 30, "assoc_reject.status %d", cfg->assoc_reject_status);
+
+ WL_ERR(("cmd: %s \n", cmd));
+
+ return bytes_written;
+}
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
+
+static s32
+wl_get_auth_assoc_status(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e)
+{
+ u32 reason = ntoh32(e->reason);
+ u32 event = ntoh32(e->event_type);
+ struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
+ WL_DBG(("event type : %d, reason : %d\n", event, reason));
+
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
+ memcpy(&cfg->event_auth_assoc, e, sizeof(wl_event_msg_t));
+ WL_ERR(("event=%d status %d reason %d \n",
+ ntoh32(cfg->event_auth_assoc.event_type),
+ ntoh32(cfg->event_auth_assoc.status),
+ ntoh32(cfg->event_auth_assoc.reason)));
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
+ if (sec) {
+ switch (event) {
+ case WLC_E_ASSOC:
+ case WLC_E_AUTH:
+ sec->auth_assoc_res_status = reason;
+ default:
+ break;
+ }
+ } else
+ WL_ERR(("sec is NULL\n"));
+ return 0;
+}
+
+static s32
+wl_notify_connect_status_ibss(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data)
+{
+ s32 err = 0;
+ u32 event = ntoh32(e->event_type);
+ u16 flags = ntoh16(e->flags);
+ u32 status = ntoh32(e->status);
+ bool active;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ struct ieee80211_channel *channel = NULL;
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ u32 chanspec, chan;
+ u32 freq, band;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
+
+ if (event == WLC_E_JOIN) {
+ WL_DBG(("joined in IBSS network\n"));
+ }
+ if (event == WLC_E_START) {
+ WL_DBG(("started IBSS network\n"));
+ }
+ if (event == WLC_E_JOIN || event == WLC_E_START ||
+ (event == WLC_E_LINK && (flags == WLC_EVENT_MSG_LINK))) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ err = wldev_iovar_getint(ndev, "chanspec", (s32 *)&chanspec);
+ if (unlikely(err)) {
+ WL_ERR(("Could not get chanspec %d\n", err));
+ return err;
+ }
+ chan = wf_chspec_ctlchan(wl_chspec_driver_to_host(chanspec));
+ band = (chan <= CH_MAX_2G_CHANNEL) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+ freq = ieee80211_channel_to_frequency(chan, band);
+ channel = ieee80211_get_channel(wiphy, freq);
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) */
+ if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
+ /* ROAM or Redundant */
+ u8 *cur_bssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+ if (memcmp(cur_bssid, &e->addr, ETHER_ADDR_LEN) == 0) {
+ WL_DBG(("IBSS connected event from same BSSID("
+ MACDBG "), ignore it\n", MAC2STRDBG(cur_bssid)));
+ return err;
+ }
+ WL_INFORM(("IBSS BSSID is changed from " MACDBG " to " MACDBG "\n",
+ MAC2STRDBG(cur_bssid), MAC2STRDBG((const u8 *)&e->addr)));
+ wl_get_assoc_ies(cfg, ndev);
+ wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
+ wl_update_bss_info(cfg, ndev, false);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
+#else
+ cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
+#endif
+ }
+ else {
+ /* New connection */
+ WL_INFORM(("IBSS connected to " MACDBG "\n",
+ MAC2STRDBG((const u8 *)&e->addr)));
+ wl_link_up(cfg);
+ wl_get_assoc_ies(cfg, ndev);
+ wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
+ wl_update_bss_info(cfg, ndev, false);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
+ cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, channel, GFP_KERNEL);
+#else
+ cfg80211_ibss_joined(ndev, (const s8 *)&e->addr, GFP_KERNEL);
+#endif
+ wl_set_drv_status(cfg, CONNECTED, ndev);
+ active = true;
+ wl_update_prof(cfg, ndev, NULL, (const void *)&active, WL_PROF_ACT);
+ }
+ } else if ((event == WLC_E_LINK && !(flags & WLC_EVENT_MSG_LINK)) ||
+ event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND) {
+ wl_clr_drv_status(cfg, CONNECTED, ndev);
+ wl_link_down(cfg);
+ wl_init_prof(cfg, ndev);
+ }
+ else if (event == WLC_E_SET_SSID && status == WLC_E_STATUS_NO_NETWORKS) {
+ WL_DBG(("no action - join fail (IBSS mode)\n"));
+ }
+ else {
+ WL_DBG(("no action (IBSS mode)\n"));
+}
+ return err;
+}
+
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
+#define WiFiALL_OUI "\x50\x6F\x9A" /* Wi-FiAll OUI */
+#define WiFiALL_OUI_LEN 3
+#define WiFiALL_OUI_TYPE 16
+
+int wl_get_bss_info(struct bcm_cfg80211 *cfg, struct net_device *dev, uint8 *mac)
+{
+ s32 err = 0;
+ struct wl_bss_info *bi;
+ uint8 eabuf[ETHER_ADDR_LEN];
+ u32 rate, channel, freq, supported_rate, nss = 0, mcs_map, mode_80211 = 0;
+ char rate_str[4];
+ u8 *ie = NULL;
+ u32 ie_len;
+ struct wiphy *wiphy;
+ struct cfg80211_bss *bss;
+ bcm_tlv_t *interworking_ie = NULL;
+ bcm_tlv_t *tlv_ie = NULL;
+ bcm_tlv_t *vht_ie = NULL;
+ vndr_ie_t *vndrie;
+ int16 ie_11u_rel_num = -1, ie_mu_mimo_cap = -1;
+ u32 i, remained_len, count = 0;
+ char roam_count_str[4], akm_str[4];
+ s32 val = 0;
+
+ /* get BSS information */
+
+ strncpy(cfg->bss_info, "x x x x x x x x x x x x x", GET_BSS_INFO_LEN);
+
+ *(u32 *) cfg->extra_buf = htod32(WL_EXTRA_BUF_MAX);
+
+ err = wldev_ioctl(dev, WLC_GET_BSS_INFO, cfg->extra_buf, WL_EXTRA_BUF_MAX, false);
+ if (unlikely(err)) {
+ WL_ERR(("Could not get bss info %d\n", err));
+ cfg->roam_count = 0;
+ return -1;
+ }
+
+ if (!mac) {
+ WL_ERR(("mac is null \n"));
+ cfg->roam_count = 0;
+ return -1;
+ }
+
+ memcpy(eabuf, mac, ETHER_ADDR_LEN);
+
+ bi = (struct wl_bss_info *)(cfg->extra_buf + 4);
+ channel = wf_chspec_ctlchan(bi->chanspec);
+
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
+ freq = ieee80211_channel_to_frequency(channel);
+#else
+ if (channel > 14) {
+ freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
+ } else {
+ freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
+ }
+#endif
+
+ err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
+ if (err) {
+ WL_ERR(("Could not get rate (%d)\n", err));
+ snprintf(rate_str, sizeof(rate_str), "x"); // Unknown
+
+ } else {
+ rate = dtoh32(rate);
+ snprintf(rate_str, sizeof(rate_str), "%d", (rate/2));
+ }
+
+ //supported maximum rate
+ supported_rate = (bi->rateset.rates[bi->rateset.count - 1] & 0x7f) / 2;
+
+ if (supported_rate < 12) {
+ mode_80211 = 0; //11b maximum rate is 11Mbps. 11b mode
+ } else {
+ //It's not HT Capable case.
+ if (channel > 14) {
+ mode_80211 = 3; // 11a mode
+ } else {
+ mode_80211 = 1; // 11g mode
+ }
+ }
+
+ if (bi->n_cap) {
+ /* check Rx MCS Map for HT */
+ nss = 0;
+ mode_80211 = 2;
+ 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++;
+ }
+ }
+ }
+
+ if (bi->vht_cap) {
+ nss = 0;
+ mode_80211 = 4;
+ 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++;
+ }
+ }
+ }
+
+ if (nss) {
+ nss = nss - 1;
+ }
+
+ wiphy = bcmcfg_to_wiphy(cfg);
+ bss = cfg80211_get_bss(wiphy, NULL, eabuf,
+ bi->SSID, strlen(bi->SSID), WLAN_CAPABILITY_ESS,
+ WLAN_CAPABILITY_ESS);
+
+ if (!bss) {
+ WL_ERR(("Could not find the AP\n"));
+ } else {
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ ie = (u8 *)bss->ies->data;
+ ie_len = bss->ies->len;
+#else
+ ie = bss->information_elements;
+ ie_len = bss->len_information_elements;
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ }
+
+ if (ie) {
+ ie_mu_mimo_cap = 0;
+ ie_11u_rel_num = 0;
+
+ if (bi->vht_cap) {
+ if ((vht_ie = bcm_parse_tlvs(ie, (u32)ie_len,
+ DOT11_MNG_VHT_CAP_ID)) != NULL) {
+ ie_mu_mimo_cap = (vht_ie->data[2] & 0x08) >> 3;
+ }
+ }
+
+ if ((interworking_ie = bcm_parse_tlvs(ie, (u32)ie_len,
+ DOT11_MNG_INTERWORKING_ID)) != NULL) {
+ if ((tlv_ie = bcm_parse_tlvs(ie, (u32)ie_len, DOT11_MNG_VS_ID)) != NULL) {
+ remained_len = ie_len;
+
+ while (tlv_ie) {
+ if (count > MAX_VNDR_IE_NUMBER)
+ break;
+
+ if (tlv_ie->id == DOT11_MNG_VS_ID) {
+ vndrie = (vndr_ie_t *) tlv_ie;
+
+ if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
+ WL_ERR(("%s: invalid vndr ie."
+ "length is too small %d\n",
+ __FUNCTION__, vndrie->len));
+ break;
+ }
+
+ if (!bcmp(vndrie->oui,
+ (u8*)WiFiALL_OUI, WiFiALL_OUI_LEN) &&
+ (vndrie->data[0] == WiFiALL_OUI_TYPE))
+ {
+ WL_ERR(("Found Wi-FiAll OUI oui.\n"));
+ ie_11u_rel_num = vndrie->data[1];
+ ie_11u_rel_num = (ie_11u_rel_num & 0xf0)>>4;
+ ie_11u_rel_num += 1;
+
+ break;
+ }
+ }
+ count++;
+ tlv_ie = bcm_next_tlv(tlv_ie, &remained_len);
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < bi->SSID_len; i++) {
+ if (bi->SSID[i] == ' ') {
+ bi->SSID[i] = '_';
+ }
+ }
+
+ //0 : None, 1 : OKC, 2 : FT, 3 : CCKM
+ err = wldev_iovar_getint(dev, "wpa_auth", &val);
+ if (unlikely(err)) {
+ WL_ERR(("could not get wpa_auth (%d)\n", err));
+ snprintf(akm_str, sizeof(akm_str), "x"); // Unknown
+ } else {
+ WL_ERR(("wpa_auth val %d \n", val));
+#if defined(BCMEXTCCX)
+ if (val & (WPA_AUTH_CCKM | WPA2_AUTH_CCKM)) {
+ snprintf(akm_str, sizeof(akm_str), "3");
+ } else
+#endif
+ if (val & WPA2_AUTH_FT) {
+ snprintf(akm_str, sizeof(akm_str), "2");
+ } else if (val & (WPA_AUTH_UNSPECIFIED | WPA2_AUTH_UNSPECIFIED)) {
+ snprintf(akm_str, sizeof(akm_str), "1");
+ } else {
+ snprintf(akm_str, sizeof(akm_str), "0");
+ }
+ }
+
+ if (cfg->roam_offload) {
+ snprintf(roam_count_str, sizeof(roam_count_str), "x"); // Unknown
+ } else {
+ snprintf(roam_count_str, sizeof(roam_count_str), "%d", cfg->roam_count);
+ }
+ cfg->roam_count = 0;
+
+ WL_ERR(("BSSID:" MACDBG " SSID %s \n", MAC2STRDBG(eabuf), bi->SSID));
+ WL_ERR(("freq:%d, BW:%s, RSSI:%d dBm, Rate:%d Mbps, 11mode:%d, stream:%d,"
+ "MU-MIMO:%d, Passpoint:%d, SNR:%d, Noise:%d, \n"
+ "akm:%s roam:%s \n",
+ freq, wf_chspec_to_bw_str(bi->chanspec),
+ dtoh32(bi->RSSI), (rate / 2), mode_80211, nss,
+ ie_mu_mimo_cap, ie_11u_rel_num, bi->SNR, bi->phy_noise,
+ akm_str, roam_count_str));
+
+ if (ie) {
+ snprintf(cfg->bss_info, GET_BSS_INFO_LEN,
+ "%02x:%02x:%02x %d %s %d %s %d %d %d %d %d %d %s %s",
+ eabuf[0], eabuf[1], eabuf[2],
+ freq, wf_chspec_to_bw_str(bi->chanspec),
+ dtoh32(bi->RSSI), rate_str, mode_80211, nss,
+ ie_mu_mimo_cap, ie_11u_rel_num,
+ bi->SNR, bi->phy_noise, akm_str, roam_count_str);
+ } else {
+ //ie_mu_mimo_cap and ie_11u_rel_num is unknow.
+ snprintf(cfg->bss_info, GET_BSS_INFO_LEN,
+ "%02x:%02x:%02x %d %s %d %s %d %d x x %d %d %s %s",
+ eabuf[0], eabuf[1], eabuf[2],
+ freq, wf_chspec_to_bw_str(bi->chanspec),
+ dtoh32(bi->RSSI), rate_str, mode_80211, nss,
+ bi->SNR, bi->phy_noise, akm_str, roam_count_str);
+ }
+
+
+ return 0;
+}
+
+s32 wl_cfg80211_get_bss_info(struct net_device *dev, char* cmd, int total_len)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+
+ if (cfg == NULL) {
+ return -1;
+ }
+
+ memset(cmd, 0, total_len);
+ memcpy(cmd, cfg->bss_info, GET_BSS_INFO_LEN);
+
+ WL_ERR(("cmd: %s \n", cmd));
+
+ return GET_BSS_INFO_LEN;
+}
+
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
+
+static s32
+wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ bool act;
+ struct net_device *ndev = NULL;
+ s32 err = 0;
+ u32 event = ntoh32(e->event_type);
+ struct wiphy *wiphy = NULL;
+ struct cfg80211_bss *bss = NULL;
+ struct wlc_ssid *ssid = NULL;
+ u8 *bssid = 0;
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
+ err = wl_notify_connect_status_ap(cfg, ndev, e, data);
+ } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS) {
+ err = wl_notify_connect_status_ibss(cfg, ndev, e, data);
+ } else if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_BSS) {
+ WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n",
+ ntoh32(e->event_type), ntoh32(e->status), ndev));
+ if (event == WLC_E_ASSOC || event == WLC_E_AUTH) {
+ wl_get_auth_assoc_status(cfg, ndev, e);
+ return 0;
+ }
+ DHD_DISABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
+ if (wl_is_linkup(cfg, e, ndev)) {
+ wl_link_up(cfg);
+ act = true;
+ if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
+#ifdef DHD_LOSSLESS_ROAMING
+ bool is_connected = wl_get_drv_status(cfg, CONNECTED, ndev);
+#endif
+
+ WL_ERR(("wl_bss_connect_done succeeded with " MACDBG "\n",
+ MAC2STRDBG((const u8*)(&e->addr))));
+ wl_bss_connect_done(cfg, ndev, e, data, true);
+ WL_DBG(("joined in BSS network \"%s\"\n",
+ ((struct wlc_ssid *)
+ wl_read_prof(cfg, ndev, WL_PROF_SSID))->SSID));
+#ifdef DHD_LOSSLESS_ROAMING
+ if (event == WLC_E_LINK && is_connected &&
+ !cfg->roam_offload) {
+ wl_bss_roaming_done(cfg, ndev, e, data);
+ }
+#endif /* DHD_LOSSLESS_ROAMING */
+
+ }
+ wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
+ wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
+
+ } else if (wl_is_linkdown(cfg, e)) {
+#ifdef DHD_LOSSLESS_ROAMING
+ wl_del_roam_timeout(cfg);
+#endif
+#ifdef P2PLISTEN_AP_SAMECHN
+ if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
+ wl_cfg80211_set_p2p_resp_ap_chn(ndev, 0);
+ cfg->p2p_resp_apchn_status = false;
+ WL_DBG(("p2p_resp_apchn_status Turn OFF \n"));
+ }
+#endif /* P2PLISTEN_AP_SAMECHN */
+ wl_cfg80211_cancel_scan(cfg);
+
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
+ if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
+ wl_get_bss_info(cfg, ndev, (u8*)(&e->addr));
+ }
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
+ /* Explicitly calling unlink to remove BSS in CFG */
+ wiphy = bcmcfg_to_wiphy(cfg);
+ ssid = (struct wlc_ssid *)wl_read_prof(cfg, ndev, WL_PROF_SSID);
+ bssid = (u8 *)wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+ if (ssid && bssid) {
+ bss = cfg80211_get_bss(wiphy, NULL, bssid,
+ ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS,
+ WLAN_CAPABILITY_ESS);
+ if (bss) {
+ cfg80211_unlink_bss(wiphy, bss);
+ }
+ }
+
+ if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
+ scb_val_t scbval;
+ u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+ s32 reason = 0;
+ struct ether_addr bssid_dongle;
+ struct ether_addr bssid_null = {{0, 0, 0, 0, 0, 0}};
+
+ if (event == WLC_E_DEAUTH_IND || event == WLC_E_DISASSOC_IND)
+ reason = ntoh32(e->reason);
+ /* WLAN_REASON_UNSPECIFIED is used for hang up event in Android */
+ reason = (reason == WLAN_REASON_UNSPECIFIED)? 0 : reason;
+
+ WL_ERR(("link down if %s may call cfg80211_disconnected. "
+ "event : %d, reason=%d from " MACDBG "\n",
+ ndev->name, event, ntoh32(e->reason),
+ MAC2STRDBG((const u8*)(&e->addr))));
+
+ /* roam offload does not sync BSSID always, get it from dongle */
+ if (cfg->roam_offload) {
+ if (wldev_ioctl(ndev, WLC_GET_BSSID, &bssid_dongle,
+ sizeof(bssid_dongle), false) == BCME_OK) {
+ /* if not roam case, it would return null bssid */
+ if (memcmp(&bssid_dongle, &bssid_null,
+ ETHER_ADDR_LEN) != 0) {
+ curbssid = (u8 *)&bssid_dongle;
+ }
+ }
+ }
+ if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) != 0) {
+ bool fw_assoc_state = TRUE;
+ dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub;
+ fw_assoc_state = dhd_is_associated(dhd, e->ifidx, &err);
+ if (!fw_assoc_state) {
+ WL_ERR(("Even sends up even different BSSID"
+ " cur: " MACDBG " event: " MACDBG"\n",
+ MAC2STRDBG(curbssid),
+ MAC2STRDBG((const u8*)(&e->addr))));
+ } else {
+ WL_ERR(("BSSID of event is not the connected BSSID"
+ "(ignore it) cur: " MACDBG
+ " event: " MACDBG"\n",
+ MAC2STRDBG(curbssid),
+ MAC2STRDBG((const u8*)(&e->addr))));
+ return 0;
+ }
+ }
+ wl_clr_drv_status(cfg, CONNECTED, ndev);
+ if (! wl_get_drv_status(cfg, DISCONNECTING, ndev)) {
+ /* To make sure disconnect, explictly send dissassoc
+ * for BSSID 00:00:00:00:00:00 issue
+ */
+ scbval.val = WLAN_REASON_DEAUTH_LEAVING;
+
+ memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
+ scbval.val = htod32(scbval.val);
+ err = wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
+ sizeof(scb_val_t), true);
+ if (err < 0) {
+ WL_ERR(("WLC_DISASSOC error %d\n", err));
+ err = 0;
+ }
+ CFG80211_DISCONNECTED(ndev, reason, NULL, 0,
+ false, GFP_KERNEL);
+ wl_link_down(cfg);
+ wl_init_prof(cfg, ndev);
+ }
+ }
+ else if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
+ WL_ERR(("link down, during connecting\n"));
+#ifdef ESCAN_RESULT_PATCH
+ if ((memcmp(connect_req_bssid, broad_bssid, ETHER_ADDR_LEN) == 0) ||
+ (memcmp(&e->addr, broad_bssid, ETHER_ADDR_LEN) == 0) ||
+ (memcmp(&e->addr, connect_req_bssid, ETHER_ADDR_LEN) == 0))
+ /* In case this event comes while associating another AP */
+#endif /* ESCAN_RESULT_PATCH */
+ wl_bss_connect_done(cfg, ndev, e, data, false);
+ }
+ wl_clr_drv_status(cfg, DISCONNECTING, ndev);
+
+ /* if link down, bsscfg is diabled */
+ if (ndev != bcmcfg_to_prmry_ndev(cfg))
+ complete(&cfg->iface_disable);
+
+ } else if (wl_is_nonetwork(cfg, e)) {
+ WL_ERR(("connect failed event=%d e->status %d e->reason %d \n",
+ event, (int)ntoh32(e->status), (int)ntoh32(e->reason)));
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
+ if (event == WLC_E_SET_SSID) {
+ wl_get_connect_failed_status(cfg, e);
+ }
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
+ /* Clean up any pending scan request */
+ wl_cfg80211_cancel_scan(cfg);
+ if (wl_get_drv_status(cfg, CONNECTING, ndev))
+ wl_bss_connect_done(cfg, ndev, e, data, false);
+ } else {
+ WL_DBG(("%s nothing\n", __FUNCTION__));
+ }
+ DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)cfg->pub);
+ }
+ else {
+ WL_ERR(("Invalid ndev status %d\n", wl_get_mode_by_netdev(cfg, ndev)));
+ }
+ return err;
+}
+
+void wl_cfg80211_set_rmc_pid(struct net_device *dev, int pid)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ if (pid > 0)
+ cfg->rmc_event_pid = pid;
+ WL_DBG(("set pid for rmc event : pid=%d\n", pid));
+}
+
+#ifdef WL_RELMCAST
+static s32
+wl_notify_rmc_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ u32 evt = ntoh32(e->event_type);
+ u32 reason = ntoh32(e->reason);
+ int ret = -1;
+
+ switch (reason) {
+ case WLC_E_REASON_RMC_AR_LOST:
+ case WLC_E_REASON_RMC_AR_NO_ACK:
+ if (cfg->rmc_event_pid != 0) {
+ ret = wl_netlink_send_msg(cfg->rmc_event_pid,
+ RMC_EVENT_LEADER_CHECK_FAIL,
+ cfg->rmc_event_seq++, NULL, 0);
+ }
+ break;
+ default:
+ break;
+ }
+ WL_DBG(("rmcevent : evt=%d, pid=%d, ret=%d\n", evt, cfg->rmc_event_pid, ret));
+ return ret;
+}
+#endif /* WL_RELMCAST */
+static s32
+wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ bool act;
+ struct net_device *ndev = NULL;
+ s32 err = 0;
+ u32 event = be32_to_cpu(e->event_type);
+ u32 status = be32_to_cpu(e->status);
+#ifdef DHD_LOSSLESS_ROAMING
+ struct wl_security *sec;
+#endif
+ WL_DBG(("Enter \n"));
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ if ((!cfg->disable_roam_event) && (event == WLC_E_BSSID)) {
+ wl_add_remove_eventmsg(ndev, WLC_E_ROAM, false);
+ cfg->disable_roam_event = TRUE;
+ }
+
+ if ((cfg->disable_roam_event) && (event == WLC_E_ROAM))
+ return err;
+
+ if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status == WLC_E_STATUS_SUCCESS) {
+ if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
+#ifdef DHD_LOSSLESS_ROAMING
+ if (cfg->roam_offload) {
+ wl_bss_roaming_done(cfg, ndev, e, data);
+ wl_del_roam_timeout(cfg);
+ }
+ else {
+ sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
+ /* In order to reduce roaming delay, wl_bss_roaming_done is
+ * early called with WLC_E_LINK event. It is called from
+ * here only if WLC_E_LINK event is blocked for specific
+ * security type.
+ */
+ if (IS_AKM_SUITE_FT(sec)) {
+ wl_bss_roaming_done(cfg, ndev, e, data);
+ }
+ /* Roam timer is deleted mostly from wl_cfg80211_change_station
+ * after roaming is finished successfully. We need to delete
+ * the timer from here only for some security types that aren't
+ * using wl_cfg80211_change_station to authorize SCB
+ */
+ if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) {
+ wl_del_roam_timeout(cfg);
+ }
+ }
+#else
+ wl_bss_roaming_done(cfg, ndev, e, data);
+#endif /* DHD_LOSSLESS_ROAMING */
+ } else {
+ wl_bss_connect_done(cfg, ndev, e, data, true);
+ }
+ act = true;
+ wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT);
+ wl_update_prof(cfg, ndev, NULL, (const void *)&e->addr, WL_PROF_BSSID);
+ }
+#ifdef DHD_LOSSLESS_ROAMING
+ else if ((event == WLC_E_ROAM || event == WLC_E_BSSID) && status != WLC_E_STATUS_SUCCESS) {
+ wl_del_roam_timeout(cfg);
+ }
+#endif
+ return err;
+}
+
+#ifdef QOS_MAP_SET
+/* up range from low to high with up value */
+static bool
+up_table_set(uint8 *up_table, uint8 up, uint8 low, uint8 high)
+{
+ int i;
+
+ if (up > 7 || low > high || low >= UP_TABLE_MAX || high >= UP_TABLE_MAX) {
+ return FALSE;
+ }
+
+ for (i = low; i <= high; i++) {
+ up_table[i] = up;
+ }
+
+ return TRUE;
+}
+
+/* set user priority table */
+static void
+wl_set_up_table(uint8 *up_table, bcm_tlv_t *qos_map_ie)
+{
+ uint8 len;
+
+ if (up_table == NULL || qos_map_ie == NULL) {
+ return;
+ }
+
+ /* 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;
+ }
+ }
+
+ /* update exceptions */
+ for (i = 0; i < except_len; i += 2) {
+ uint8 dscp = except_ptr[i];
+ uint8 up = except_ptr[i+1];
+
+ /* exceptions with invalid dscp/up are ignored */
+ up_table_set(up_table, up, dscp, dscp);
+ }
+ }
+
+ if (wl_dbg_level & WL_DBG_DBG) {
+ prhex("UP table", up_table, UP_TABLE_MAX);
+ }
+}
+
+/* get user priority table */
+uint8 *
+wl_get_up_table(void *cfg80211_priv)
+{
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)cfg80211_priv;
+ return (uint8 *)(cfg->up_table);
+}
+#endif /* QOS_MAP_SET */
+
+#ifdef DHD_LOSSLESS_ROAMING
+static s32
+wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ s32 err = 0;
+ struct wl_security *sec;
+ struct net_device *ndev;
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
+ /* Disable Lossless Roaming for specific AKM suite
+ * Any other AKM suite can be added below if transition time
+ * is delayed because of Lossless Roaming
+ * and it causes any certication failure
+ */
+ if (IS_AKM_SUITE_FT(sec)) {
+ return err;
+ }
+
+ dhdp->dequeue_prec_map = 1 << PRIO_8021D_NC;
+ /* Restore flow control */
+ dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF);
+
+ mod_timer(&cfg->roam_timeout, jiffies + msecs_to_jiffies(WL_ROAM_TIMEOUT_MS));
+
+ return err;
+}
+#endif /* DHD_LOSSLESS_ROAMING */
+
+static s32
+wl_notify_idsup_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ s32 err = 0;
+#if defined(WL_VENDOR_EXT_SUPPORT)
+ u32 idsup_status;
+ u32 reason = ntoh32(e->reason);
+ struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+#endif /* defined(WL_VENDOR_EXT_SUPPORT) */
+
+ if (cfg->roam_offload) {
+#if defined(WL_VENDOR_EXT_SUPPORT)
+ switch (reason) {
+ case WLC_E_SUP_WPA_PSK_TMO:
+ idsup_status = IDSUP_EVENT_4WAY_HANDSHAKE_TIMEOUT;
+ break;
+ case WLC_E_SUP_OTHER:
+ idsup_status = IDSUP_EVENT_SUCCESS;
+ break;
+ default:
+ WL_ERR(("Other type at IDSUP. "
+ "event=%d e->status %d e->reason %d \n",
+ (int)ntoh32(e->event_type), (int)ntoh32(e->status),
+ (int)ntoh32(e->reason)));
+ return err;
+ }
+
+ err = wl_cfgvendor_send_async_event(wiphy, ndev,
+ BRCM_VENDOR_EVENT_IDSUP_STATUS, &idsup_status, sizeof(u32));
+#endif /* defined(WL_VENDOR_EXT_SUPPORT) */
+ }
+ return err;
+}
+
+#ifdef CUSTOM_EVENT_PM_WAKE
+static s32
+wl_check_pmstatus(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ s32 err = 0;
+ struct net_device *ndev = NULL;
+ u8 *pbuf = NULL;
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ pbuf = kzalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
+ if (pbuf == NULL) {
+ WL_ERR(("failed to allocate local pbuf\n"));
+ return -ENOMEM;
+ }
+
+ err = wldev_iovar_getbuf_bsscfg(ndev, "dump",
+ "pm", strlen("pm"), pbuf, WLC_IOCTL_MEDLEN, 0, &cfg->ioctl_buf_sync);
+
+ if (err) {
+ WL_ERR(("dump ioctl err = %d", err));
+ } else {
+ WL_ERR(("PM status : %s\n", pbuf));
+ }
+
+ if (pbuf) {
+ kfree(pbuf);
+ }
+ return err;
+}
+#endif /* CUSTOM_EVENT_PM_WAKE */
+
+#ifdef ENABLE_TEMP_THROTTLING
+static s32
+wl_check_rx_throttle_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ s32 err = 0;
+ u32 status = ntoh32(e->status);
+ u32 reason = ntoh32(e->reason);
+
+ WL_ERR(("RX THROTTLE : status=%d, reason=0x%x\n", status, reason));
+
+ return err;
+}
+#endif /* ENABLE_TEMP_THROTTLING */
+
+static s32 wl_get_assoc_ies(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ wl_assoc_info_t assoc_info;
+ struct wl_connect_info *conn_info = wl_to_conn(cfg);
+ s32 err = 0;
+#ifdef QOS_MAP_SET
+ bcm_tlv_t * qos_map_ie = NULL;
+#endif /* QOS_MAP_SET */
+
+ WL_DBG(("Enter \n"));
+ err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, cfg->extra_buf,
+ WL_ASSOC_INFO_MAX, NULL);
+ if (unlikely(err)) {
+ WL_ERR(("could not get assoc info (%d)\n", err));
+ return err;
+ }
+ memcpy(&assoc_info, cfg->extra_buf, sizeof(wl_assoc_info_t));
+ assoc_info.req_len = htod32(assoc_info.req_len);
+ assoc_info.resp_len = htod32(assoc_info.resp_len);
+ assoc_info.flags = htod32(assoc_info.flags);
+ if (conn_info->req_ie_len) {
+ conn_info->req_ie_len = 0;
+ bzero(conn_info->req_ie, sizeof(conn_info->req_ie));
+ }
+ if (conn_info->resp_ie_len) {
+ conn_info->resp_ie_len = 0;
+ bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
+ }
+ if (assoc_info.req_len) {
+ err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, cfg->extra_buf,
+ WL_ASSOC_INFO_MAX, NULL);
+ if (unlikely(err)) {
+ WL_ERR(("could not get assoc req (%d)\n", err));
+ return err;
+ }
+ conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req);
+ if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
+ conn_info->req_ie_len -= ETHER_ADDR_LEN;
+ }
+ if (conn_info->req_ie_len <= MAX_REQ_LINE)
+ memcpy(conn_info->req_ie, cfg->extra_buf, conn_info->req_ie_len);
+ else {
+ WL_ERR(("IE size %d above max %d size \n",
+ conn_info->req_ie_len, MAX_REQ_LINE));
+ return err;
+ }
+ } else {
+ conn_info->req_ie_len = 0;
+ }
+ if (assoc_info.resp_len) {
+ err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, cfg->extra_buf,
+ WL_ASSOC_INFO_MAX, NULL);
+ if (unlikely(err)) {
+ WL_ERR(("could not get assoc resp (%d)\n", err));
+ return err;
+ }
+ conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp);
+ if (conn_info->resp_ie_len <= MAX_REQ_LINE) {
+ memcpy(conn_info->resp_ie, cfg->extra_buf, conn_info->resp_ie_len);
+ } else {
+ WL_ERR(("IE size %d above max %d size \n",
+ conn_info->resp_ie_len, MAX_REQ_LINE));
+ return err;
+ }
+
+#ifdef QOS_MAP_SET
+ /* find qos map set ie */
+ if ((qos_map_ie = bcm_parse_tlvs(conn_info->resp_ie, conn_info->resp_ie_len,
+ DOT11_MNG_QOS_MAP_ID)) != NULL) {
+ WL_DBG((" QoS map set IE found in assoc response\n"));
+ if (!cfg->up_table) {
+ cfg->up_table = kmalloc(UP_TABLE_MAX, GFP_KERNEL);
+ }
+ wl_set_up_table(cfg->up_table, qos_map_ie);
+ } else {
+ kfree(cfg->up_table);
+ cfg->up_table = NULL;
+ }
+#endif /* QOS_MAP_SET */
+ } else {
+ conn_info->resp_ie_len = 0;
+ }
+ WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len,
+ conn_info->resp_ie_len));
+
+ return err;
+}
+
+static s32 wl_ch_to_chanspec(struct net_device *dev, int ch, struct wl_join_params *join_params,
+ size_t *join_params_size)
+{
+ struct bcm_cfg80211 *cfg;
+ s32 bssidx = -1;
+ chanspec_t chanspec = 0, chspec;
+
+ if (ch != 0) {
+ cfg = (struct bcm_cfg80211 *)wiphy_priv(dev->ieee80211_ptr->wiphy);
+ if (cfg && cfg->rcc_enabled) {
+ } else {
+ join_params->params.chanspec_num = 1;
+ join_params->params.chanspec_list[0] = ch;
+
+ if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
+ chanspec |= WL_CHANSPEC_BAND_2G;
+ else
+ chanspec |= WL_CHANSPEC_BAND_5G;
+
+ /* Get the min_bw set for the interface */
+ chspec = wl_cfg80211_ulb_get_min_bw_chspec(dev->ieee80211_ptr, bssidx);
+ if (chspec == INVCHANSPEC) {
+ WL_ERR(("Invalid chanspec \n"));
+ return -EINVAL;
+ }
+ chanspec |= chspec;
+ chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+
+ *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
+ join_params->params.chanspec_num * sizeof(chanspec_t);
+
+ join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
+ join_params->params.chanspec_list[0] |= chanspec;
+ join_params->params.chanspec_list[0] =
+ wl_chspec_host_to_driver(join_params->params.chanspec_list[0]);
+
+ join_params->params.chanspec_num =
+ htod32(join_params->params.chanspec_num);
+ }
+
+ WL_DBG(("join_params->params.chanspec_list[0]= %X, %d channels\n",
+ join_params->params.chanspec_list[0],
+ join_params->params.chanspec_num));
+ }
+ return 0;
+}
+
+static s32 wl_update_bss_info(struct bcm_cfg80211 *cfg, struct net_device *ndev, bool roam)
+{
+ struct wl_bss_info *bi;
+ struct bcm_tlv *tim;
+ s32 beacon_interval;
+ s32 dtim_period;
+ size_t ie_len;
+ u8 *ie;
+ u8 *curbssid;
+ s32 err = 0;
+ u32 channel;
+
+ curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+
+ mutex_lock(&cfg->usr_sync);
+
+ *(u32 *) cfg->extra_buf = htod32(WL_EXTRA_BUF_MAX);
+ err = wldev_ioctl(ndev, WLC_GET_BSS_INFO,
+ cfg->extra_buf, WL_EXTRA_BUF_MAX, false);
+ if (unlikely(err)) {
+ WL_ERR(("Could not get bss info %d\n", err));
+ goto update_bss_info_out;
+ }
+ bi = (struct wl_bss_info *)(cfg->extra_buf + 4);
+ channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
+ wl_update_prof(cfg, ndev, NULL, &channel, WL_PROF_CHAN);
+
+ if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) {
+ WL_ERR(("Bssid doesn't match\n"));
+ err = -EIO;
+ goto update_bss_info_out;
+ }
+ err = wl_inform_single_bss(cfg, bi, roam);
+ if (unlikely(err))
+ goto update_bss_info_out;
+
+ ie = ((u8 *)bi) + bi->ie_offset;
+ ie_len = bi->ie_length;
+ beacon_interval = cpu_to_le16(bi->beacon_period);
+ tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
+ if (tim) {
+ dtim_period = tim->data[1];
+ } else {
+ /*
+ * active scan was done so we could not get dtim
+ * information out of probe response.
+ * so we speficially query dtim information.
+ */
+ err = wldev_ioctl(ndev, WLC_GET_DTIMPRD,
+ &dtim_period, sizeof(dtim_period), false);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
+ goto update_bss_info_out;
+ }
+ }
+
+ wl_update_prof(cfg, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT);
+ wl_update_prof(cfg, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
+
+update_bss_info_out:
+ if (unlikely(err)) {
+ WL_ERR(("Failed with error %d\n", err));
+ }
+ mutex_unlock(&cfg->usr_sync);
+ return err;
+}
+
+static s32
+wl_bss_roaming_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data)
+{
+ struct wl_connect_info *conn_info = wl_to_conn(cfg);
+ s32 err = 0;
+ u8 *curbssid;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ struct ieee80211_supported_band *band;
+ struct ieee80211_channel *notify_channel = NULL;
+ u32 *channel;
+ u32 freq;
+#endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
+
+
+ if (memcmp(&cfg->last_roamed_addr, &e->addr, ETHER_ADDR_LEN) == 0) {
+ WL_INFORM(("BSSID already updated\n"));
+ return err;
+ }
+
+ /* Skip calling cfg80211_roamed If current bssid and
+ * roamed bssid are same. Also clear timer roam_timeout.
+ */
+ curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+ if (memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0) {
+ WL_ERR(("BSS already present, Skipping roamed event to upper layer\n"));
+#ifdef DHD_LOSSLESS_ROAMING
+ wl_del_roam_timeout(cfg);
+#endif /* DHD_LOSSLESS_ROAMING */
+ return err;
+ }
+
+ wl_get_assoc_ies(cfg, ndev);
+ wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet), WL_PROF_BSSID);
+ curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+ wl_update_bss_info(cfg, ndev, true);
+ wl_update_pmklist(ndev, cfg->pmk_list, err);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
+ /* channel info for cfg80211_roamed introduced in 2.6.39-rc1 */
+ channel = (u32 *)wl_read_prof(cfg, ndev, WL_PROF_CHAN);
+ if (*channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+ freq = ieee80211_channel_to_frequency(*channel, band->band);
+ notify_channel = ieee80211_get_channel(wiphy, freq);
+#endif /* LINUX_VERSION > 2.6.39 || WL_COMPAT_WIRELESS */
+ WL_ERR(("wl_bss_roaming_done succeeded to " MACDBG "\n",
+ MAC2STRDBG((const u8*)(&e->addr))));
+
+ cfg80211_roamed(ndev,
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) || defined(WL_COMPAT_WIRELESS)
+ notify_channel,
+#endif
+ curbssid,
+ conn_info->req_ie, conn_info->req_ie_len,
+ conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
+ WL_DBG(("Report roaming result\n"));
+
+ memcpy(&cfg->last_roamed_addr, (void *)&e->addr, ETHER_ADDR_LEN);
+ wl_set_drv_status(cfg, CONNECTED, ndev);
+
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
+ cfg->roam_count++;
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
+
+ return err;
+}
+
+static s32
+wl_bss_connect_done(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data, bool completed)
+{
+ struct wl_connect_info *conn_info = wl_to_conn(cfg);
+ struct wl_security *sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
+#if defined(CUSTOM_SET_CPUCORE)
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+#endif
+ s32 err = 0;
+ u8 *curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+ if (!sec) {
+ WL_ERR(("sec is NULL\n"));
+ return -ENODEV;
+ }
+ WL_DBG((" enter\n"));
+#ifdef ESCAN_RESULT_PATCH
+ if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
+ if (memcmp(curbssid, connect_req_bssid, ETHER_ADDR_LEN) == 0) {
+ WL_DBG((" Connected event of connected device e=%d s=%d, ignore it\n",
+ ntoh32(e->event_type), ntoh32(e->status)));
+ return err;
+ }
+ }
+ if (memcmp(curbssid, broad_bssid, ETHER_ADDR_LEN) == 0 &&
+ memcmp(broad_bssid, connect_req_bssid, ETHER_ADDR_LEN) != 0) {
+ WL_DBG(("copy bssid\n"));
+ memcpy(curbssid, connect_req_bssid, ETHER_ADDR_LEN);
+ }
+
+#else
+ if (cfg->scan_request) {
+ wl_notify_escan_complete(cfg, ndev, true, true);
+ }
+#endif /* ESCAN_RESULT_PATCH */
+ if (wl_get_drv_status(cfg, CONNECTING, ndev)) {
+ wl_cfg80211_scan_abort(cfg);
+ wl_clr_drv_status(cfg, CONNECTING, ndev);
+ if (completed) {
+ wl_get_assoc_ies(cfg, ndev);
+ wl_update_prof(cfg, ndev, NULL, (const void *)(e->addr.octet),
+ WL_PROF_BSSID);
+ curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+ wl_update_bss_info(cfg, ndev, false);
+ wl_update_pmklist(ndev, cfg->pmk_list, err);
+ wl_set_drv_status(cfg, CONNECTED, ndev);
+ if (ndev != bcmcfg_to_prmry_ndev(cfg)) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
+ init_completion(&cfg->iface_disable);
+#else
+ /* reinitialize completion to clear previous count */
+ INIT_COMPLETION(cfg->iface_disable);
+#endif
+ }
+#ifdef CUSTOM_SET_CPUCORE
+ if (wl_get_chan_isvht80(ndev, dhd)) {
+ if (ndev == bcmcfg_to_prmry_ndev(cfg))
+ dhd->chan_isvht80 |= DHD_FLAG_STA_MODE; /* STA mode */
+ else if (is_p2p_group_iface(ndev->ieee80211_ptr))
+ dhd->chan_isvht80 |= DHD_FLAG_P2P_MODE; /* p2p mode */
+ dhd_set_cpucore(dhd, TRUE);
+ }
+#endif /* CUSTOM_SET_CPUCORE */
+ memset(&cfg->last_roamed_addr, 0, ETHER_ADDR_LEN);
+ }
+ cfg80211_connect_result(ndev,
+ curbssid,
+ conn_info->req_ie,
+ conn_info->req_ie_len,
+ conn_info->resp_ie,
+ conn_info->resp_ie_len,
+ completed ? WLAN_STATUS_SUCCESS :
+ (sec->auth_assoc_res_status) ?
+ sec->auth_assoc_res_status :
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
+ if (completed)
+ WL_INFORM(("Report connect result - connection succeeded\n"));
+ else
+ WL_ERR(("Report connect result - connection failed\n"));
+ }
+#ifdef CONFIG_TCPACK_FASTTX
+ if (wl_get_chan_isvht80(ndev, dhd))
+ wldev_iovar_setint(ndev, "tcpack_fast_tx", 0);
+ else
+ wldev_iovar_setint(ndev, "tcpack_fast_tx", 1);
+#endif /* CONFIG_TCPACK_FASTTX */
+
+ return err;
+}
+
+static s32
+wl_notify_mic_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ struct net_device *ndev = NULL;
+ u16 flags = ntoh16(e->flags);
+ enum nl80211_key_type key_type;
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ mutex_lock(&cfg->usr_sync);
+ if (flags & WLC_EVENT_MSG_GROUP)
+ key_type = NL80211_KEYTYPE_GROUP;
+ else
+ key_type = NL80211_KEYTYPE_PAIRWISE;
+
+ cfg80211_michael_mic_failure(ndev, (const u8 *)&e->addr, key_type, -1,
+ NULL, GFP_KERNEL);
+ mutex_unlock(&cfg->usr_sync);
+
+ return 0;
+}
+
+#ifdef BT_WIFI_HANDOVER
+static s32
+wl_notify_bt_wifi_handover_req(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ struct net_device *ndev = NULL;
+ u32 event = ntoh32(e->event_type);
+ u32 datalen = ntoh32(e->datalen);
+ s32 err;
+
+ WL_ERR(("wl_notify_bt_wifi_handover_req: event_type : %d, datalen : %d\n", event, datalen));
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+ err = wl_genl_send_msg(ndev, event, data, (u16)datalen, 0, 0);
+
+ return err;
+}
+#endif /* BT_WIFI_HANDOVER */
+
+#ifdef PNO_SUPPORT
+static s32
+wl_notify_pfn_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ struct net_device *ndev = NULL;
+
+ WL_ERR((">>> PNO Event\n"));
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+#ifndef WL_SCHED_SCAN
+ mutex_lock(&cfg->usr_sync);
+ /* TODO: Use cfg80211_sched_scan_results(wiphy); */
+ CFG80211_DISCONNECTED(ndev, 0, NULL, 0, false, GFP_KERNEL);
+ mutex_unlock(&cfg->usr_sync);
+#else
+ /* If cfg80211 scheduled scan is supported, report the pno results via sched
+ * scan results
+ */
+ wl_notify_sched_scan_results(cfg, ndev, e, data);
+#endif /* WL_SCHED_SCAN */
+ return 0;
+}
+#endif /* PNO_SUPPORT */
+
+#ifdef GSCAN_SUPPORT
+static s32
+wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ s32 err = 0;
+ u32 event = be32_to_cpu(e->event_type);
+ void *ptr;
+ int send_evt_bytes = 0;
+ int batch_event_result_dummy = 0;
+ struct net_device *ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ u32 len = ntoh32(e->datalen);
+
+ switch (event) {
+ case WLC_E_PFN_SWC:
+ ptr = dhd_dev_swc_scan_event(ndev, data, &send_evt_bytes);
+ if (send_evt_bytes) {
+ wl_cfgvendor_send_async_event(wiphy, ndev,
+ GOOGLE_GSCAN_SIGNIFICANT_EVENT, ptr, send_evt_bytes);
+ kfree(ptr);
+ }
+ break;
+ case WLC_E_PFN_BEST_BATCHING:
+ err = dhd_dev_retrieve_batch_scan(ndev);
+ if (err < 0) {
+ WL_ERR(("Batch retrieval already in progress %d\n", err));
+ } else {
+ wl_cfgvendor_send_async_event(wiphy, ndev,
+ GOOGLE_GSCAN_BATCH_SCAN_EVENT,
+ &batch_event_result_dummy, sizeof(int));
+ }
+ break;
+ case WLC_E_PFN_SCAN_COMPLETE:
+ batch_event_result_dummy = WIFI_SCAN_COMPLETE;
+ wl_cfgvendor_send_async_event(wiphy, ndev,
+ GOOGLE_SCAN_COMPLETE_EVENT,
+ &batch_event_result_dummy, sizeof(int));
+ break;
+ case WLC_E_PFN_BSSID_NET_FOUND:
+ ptr = dhd_dev_hotlist_scan_event(ndev, data, &send_evt_bytes,
+ HOTLIST_FOUND);
+ if (ptr) {
+ wl_cfgvendor_send_hotlist_event(wiphy, ndev,
+ ptr, send_evt_bytes, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT);
+ dhd_dev_gscan_hotlist_cache_cleanup(ndev, HOTLIST_FOUND);
+ }
+ break;
+ case WLC_E_PFN_BSSID_NET_LOST:
+ /* WLC_E_PFN_BSSID_NET_LOST is conflict shared with WLC_E_PFN_SCAN_ALLGONE
+ * We currently do not use WLC_E_PFN_SCAN_ALLGONE, so if we get it, ignore
+ */
+ if (len) {
+ ptr = dhd_dev_hotlist_scan_event(ndev, data, &send_evt_bytes,
+ HOTLIST_LOST);
+ if (ptr) {
+ wl_cfgvendor_send_hotlist_event(wiphy, ndev,
+ ptr, send_evt_bytes, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT);
+ dhd_dev_gscan_hotlist_cache_cleanup(ndev, HOTLIST_LOST);
+ }
+ }
+ break;
+ case WLC_E_PFN_GSCAN_FULL_RESULT:
+ ptr = dhd_dev_process_full_gscan_result(ndev, data, &send_evt_bytes);
+ if (ptr) {
+ wl_cfgvendor_send_async_event(wiphy, ndev,
+ GOOGLE_SCAN_FULL_RESULTS_EVENT, ptr, send_evt_bytes);
+ kfree(ptr);
+ }
+ break;
+ default:
+ WL_ERR(("%s: Unexpected event! - %d\n", __FUNCTION__, event));
+
+ }
+ return err;
+}
+#endif /* GSCAN_SUPPORT */
+
+static s32
+wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ struct channel_info channel_inform;
+ struct wl_scan_results *bss_list;
+ struct net_device *ndev = NULL;
+ u32 len = WL_SCAN_BUF_MAX;
+ s32 err = 0;
+ unsigned long flags;
+
+ WL_DBG(("Enter \n"));
+ if (!wl_get_drv_status(cfg, SCANNING, ndev)) {
+ WL_ERR(("scan is not ready \n"));
+ return err;
+ }
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ mutex_lock(&cfg->usr_sync);
+ wl_clr_drv_status(cfg, SCANNING, ndev);
+ err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform,
+ sizeof(channel_inform), false);
+ if (unlikely(err)) {
+ WL_ERR(("scan busy (%d)\n", err));
+ goto scan_done_out;
+ }
+ channel_inform.scan_channel = dtoh32(channel_inform.scan_channel);
+ if (unlikely(channel_inform.scan_channel)) {
+
+ WL_DBG(("channel_inform.scan_channel (%d)\n",
+ channel_inform.scan_channel));
+ }
+ cfg->bss_list = cfg->scan_results;
+ bss_list = cfg->bss_list;
+ memset(bss_list, 0, len);
+ bss_list->buflen = htod32(len);
+ err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, false);
+ if (unlikely(err) && unlikely(!cfg->scan_suppressed)) {
+ WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err));
+ err = -EINVAL;
+ goto scan_done_out;
+ }
+ bss_list->buflen = dtoh32(bss_list->buflen);
+ bss_list->version = dtoh32(bss_list->version);
+ bss_list->count = dtoh32(bss_list->count);
+
+ err = wl_inform_bss(cfg);
+
+scan_done_out:
+ del_timer_sync(&cfg->scan_timeout);
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+ if (cfg->scan_request) {
+ cfg80211_scan_done(cfg->scan_request, false);
+ cfg->scan_request = NULL;
+ }
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+ WL_DBG(("cfg80211_scan_done\n"));
+ mutex_unlock(&cfg->usr_sync);
+ return err;
+}
+
+static s32
+wl_frame_get_mgmt(u16 fc, const struct ether_addr *da,
+ const struct ether_addr *sa, const struct ether_addr *bssid,
+ u8 **pheader, u32 *body_len, u8 *pbody)
+{
+ struct dot11_management_header *hdr;
+ u32 totlen = 0;
+ s32 err = 0;
+ u8 *offset;
+ u32 prebody_len = *body_len;
+ switch (fc) {
+ case FC_ASSOC_REQ:
+ /* capability , listen interval */
+ totlen = DOT11_ASSOC_REQ_FIXED_LEN;
+ *body_len += DOT11_ASSOC_REQ_FIXED_LEN;
+ break;
+
+ case FC_REASSOC_REQ:
+ /* capability, listen inteval, ap address */
+ totlen = DOT11_REASSOC_REQ_FIXED_LEN;
+ *body_len += DOT11_REASSOC_REQ_FIXED_LEN;
+ break;
+ }
+ totlen += DOT11_MGMT_HDR_LEN + prebody_len;
+ *pheader = kzalloc(totlen, GFP_KERNEL);
+ if (*pheader == NULL) {
+ WL_ERR(("memory alloc failed \n"));
+ return -ENOMEM;
+ }
+ hdr = (struct dot11_management_header *) (*pheader);
+ hdr->fc = htol16(fc);
+ hdr->durid = 0;
+ hdr->seq = 0;
+ offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len);
+ bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN);
+ bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN);
+ bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN);
+ if ((pbody != NULL) && prebody_len)
+ bcopy((const char*)pbody, offset, prebody_len);
+ *body_len = totlen;
+ return err;
+}
+
+
+void
+wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
+ if (timer_pending(&cfg->p2p->listen_timer)) {
+ del_timer_sync(&cfg->p2p->listen_timer);
+ }
+ if (cfg->afx_hdl != NULL) {
+ if (cfg->afx_hdl->dev != NULL) {
+ wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
+ wl_clr_drv_status(cfg, FINDING_COMMON_CHANNEL, cfg->afx_hdl->dev);
+ }
+ cfg->afx_hdl->peer_chan = WL_INVALID;
+ }
+ complete(&cfg->act_frm_scan);
+ WL_DBG(("*** Wake UP ** Working afx searching is cleared\n"));
+ } else if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) {
+ if (!(wl_get_p2p_status(cfg, ACTION_TX_COMPLETED) ||
+ wl_get_p2p_status(cfg, ACTION_TX_NOACK)))
+ wl_set_p2p_status(cfg, ACTION_TX_COMPLETED);
+
+ WL_DBG(("*** Wake UP ** abort actframe iovar\n"));
+ /* if channel is not zero, "actfame" uses off channel scan.
+ * So abort scan for off channel completion.
+ */
+ if (cfg->af_sent_channel)
+ wl_cfg80211_scan_abort(cfg);
+ }
+#ifdef WL_CFG80211_SYNC_GON
+ else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
+ WL_DBG(("*** Wake UP ** abort listen for next af frame\n"));
+ /* So abort scan to cancel listen */
+ wl_cfg80211_scan_abort(cfg);
+ }
+#endif /* WL_CFG80211_SYNC_GON */
+}
+
+#if defined(WLTDLS)
+bool wl_cfg80211_is_tdls_tunneled_frame(void *frame, u32 frame_len)
+{
+ unsigned char *data;
+
+ if (frame == NULL) {
+ WL_ERR(("Invalid frame \n"));
+ return false;
+ }
+
+ if (frame_len < 5) {
+ WL_ERR(("Invalid frame length [%d] \n", frame_len));
+ return false;
+ }
+
+ data = frame;
+
+ if (!memcmp(data, TDLS_TUNNELED_PRB_REQ, 5) ||
+ !memcmp(data, TDLS_TUNNELED_PRB_RESP, 5)) {
+ WL_DBG(("TDLS Vendor Specific Received type\n"));
+ return true;
+ }
+
+ return false;
+}
+#endif /* WLTDLS */
+
+
+int wl_cfg80211_get_ioctl_version(void)
+{
+ return ioctl_version;
+}
+
+static s32
+wl_notify_rx_mgmt_frame(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ struct ieee80211_supported_band *band;
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ struct ether_addr da;
+ struct ether_addr bssid;
+ bool isfree = false;
+ s32 err = 0;
+ s32 freq;
+ struct net_device *ndev = NULL;
+ wifi_p2p_pub_act_frame_t *act_frm = NULL;
+ wifi_p2p_action_frame_t *p2p_act_frm = NULL;
+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL;
+#if defined(WLTDLS) && defined(TDLS_MSG_ONLY_WFD)
+ dhd_pub_t *dhdp;
+#endif /* WLTDLS && TDLS_MSG_ONLY_WFD */
+ wl_event_rx_frame_data_t *rxframe =
+ (wl_event_rx_frame_data_t*)data;
+ u32 event = ntoh32(e->event_type);
+ u8 *mgmt_frame;
+ u8 bsscfgidx = e->bsscfgidx;
+ u32 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t);
+ u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK));
+
+ memset(&bssid, 0, ETHER_ADDR_LEN);
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ if (channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+ if (!band) {
+ WL_ERR(("No valid band"));
+ return -EINVAL;
+ }
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
+ freq = ieee80211_channel_to_frequency(channel);
+ (void)band->band;
+#else
+ freq = ieee80211_channel_to_frequency(channel, band->band);
+#endif
+ if (event == WLC_E_ACTION_FRAME_RX) {
+ wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
+ NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, bsscfgidx, &cfg->ioctl_buf_sync);
+
+ err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
+ if (err < 0)
+ WL_ERR(("WLC_GET_BSSID error %d\n", err));
+ memcpy(da.octet, cfg->ioctl_buf, ETHER_ADDR_LEN);
+ err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid,
+ &mgmt_frame, &mgmt_frame_len,
+ (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
+ if (err < 0) {
+ WL_ERR(("Error in receiving action frame len %d channel %d freq %d\n",
+ mgmt_frame_len, channel, freq));
+ goto exit;
+ }
+ isfree = true;
+ if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
+ act_frm = (wifi_p2p_pub_act_frame_t *)
+ (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+ } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
+ p2p_act_frm = (wifi_p2p_action_frame_t *)
+ (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+ (void) p2p_act_frm;
+ } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN)) {
+
+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)
+ (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
+ if (sd_act_frm && wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
+ if (cfg->next_af_subtype == sd_act_frm->action) {
+ WL_DBG(("We got a right next frame of SD!(%d)\n",
+ sd_act_frm->action));
+ wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
+
+ /* Stop waiting for next AF. */
+ wl_stop_wait_next_action_frame(cfg, ndev);
+ }
+ }
+ (void) sd_act_frm;
+#ifdef WLTDLS
+ } else if ((mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) ||
+ (wl_cfg80211_is_tdls_tunneled_frame(
+ &mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN))) {
+ if (mgmt_frame[DOT11_MGMT_HDR_LEN] == TDLS_AF_CATEGORY) {
+ WL_ERR((" TDLS Action Frame Received type = %d \n",
+ mgmt_frame[DOT11_MGMT_HDR_LEN + 1]));
+ }
+#ifdef TDLS_MSG_ONLY_WFD
+ dhdp = (dhd_pub_t *)(cfg->pub);
+ if (!dhdp->tdls_mode) {
+ WL_DBG((" TDLS Frame filtered \n"));
+ return 0;
+ }
+#else
+ if (mgmt_frame[DOT11_MGMT_HDR_LEN + 1] == TDLS_ACTION_SETUP_RESP) {
+ cfg->tdls_mgmt_frame = mgmt_frame;
+ cfg->tdls_mgmt_frame_len = mgmt_frame_len;
+ cfg->tdls_mgmt_freq = freq;
+ return 0;
+ }
+#endif /* TDLS_MSG_ONLY_WFD */
+#endif /* WLTDLS */
+#ifdef QOS_MAP_SET
+ } else if (mgmt_frame[DOT11_MGMT_HDR_LEN] == DOT11_ACTION_CAT_QOS) {
+ /* update QoS map set table */
+ bcm_tlv_t * qos_map_ie = NULL;
+ if ((qos_map_ie = bcm_parse_tlvs(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN,
+ DOT11_MNG_QOS_MAP_ID)) != NULL) {
+ WL_DBG((" QoS map set IE found in QoS action frame\n"));
+ if (!cfg->up_table) {
+ cfg->up_table = kmalloc(UP_TABLE_MAX, GFP_KERNEL);
+ }
+ wl_set_up_table(cfg->up_table, qos_map_ie);
+ } else {
+ kfree(cfg->up_table);
+ cfg->up_table = NULL;
+ }
+#endif /* QOS_MAP_SET */
+ } else {
+ /*
+ * if we got normal action frame and ndev is p2p0,
+ * we have to change ndev from p2p0 to wlan0
+ */
+
+
+ if (cfg->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
+ u8 action = 0;
+ if (wl_get_public_action(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN, &action) != BCME_OK) {
+ WL_DBG(("Recived action is not public action frame\n"));
+ } else if (cfg->next_af_subtype == action) {
+ WL_DBG(("Recived action is the waiting action(%d)\n",
+ action));
+ wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
+
+ /* Stop waiting for next AF. */
+ wl_stop_wait_next_action_frame(cfg, ndev);
+ }
+ }
+ }
+
+ if (act_frm) {
+
+ if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM)) {
+ if (cfg->next_af_subtype == act_frm->subtype) {
+ WL_DBG(("We got a right next frame!(%d)\n",
+ act_frm->subtype));
+ wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
+
+ if (cfg->next_af_subtype == P2P_PAF_GON_CONF) {
+ OSL_SLEEP(20);
+ }
+
+ /* Stop waiting for next AF. */
+ wl_stop_wait_next_action_frame(cfg, ndev);
+ }
+ }
+ }
+
+ wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN],
+ mgmt_frame_len - DOT11_MGMT_HDR_LEN, channel);
+ /*
+ * After complete GO Negotiation, roll back to mpc mode
+ */
+ if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) ||
+ (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) {
+ wldev_iovar_setint(ndev, "mpc", 1);
+ }
+ if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) {
+ WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
+ wl_clr_p2p_status(cfg, GO_NEG_PHASE);
+ }
+ } else if (event == WLC_E_PROBREQ_MSG) {
+
+ /* Handle probe reqs frame
+ * WPS-AP certification 4.2.13
+ */
+ struct parsed_ies prbreq_ies;
+ u32 prbreq_ie_len = 0;
+ bool pbc = 0;
+
+ WL_DBG((" Event WLC_E_PROBREQ_MSG received\n"));
+ mgmt_frame = (u8 *)(data);
+ mgmt_frame_len = ntoh32(e->datalen);
+
+ prbreq_ie_len = mgmt_frame_len - DOT11_MGMT_HDR_LEN;
+
+ /* Parse prob_req IEs */
+ if (wl_cfg80211_parse_ies(&mgmt_frame[DOT11_MGMT_HDR_LEN],
+ prbreq_ie_len, &prbreq_ies) < 0) {
+ WL_ERR(("Prob req get IEs failed\n"));
+ return 0;
+ }
+ if (prbreq_ies.wps_ie != NULL) {
+ wl_validate_wps_ie((char *)prbreq_ies.wps_ie, prbreq_ies.wps_ie_len, &pbc);
+ WL_DBG((" wps_ie exist pbc = %d\n", pbc));
+ /* if pbc method, send prob_req mgmt frame to upper layer */
+ if (!pbc)
+ return 0;
+ } else
+ return 0;
+ } else {
+ mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
+
+ /* wpa supplicant use probe request event for restarting another GON Req.
+ * but it makes GON Req repetition.
+ * so if src addr of prb req is same as my target device,
+ * do not send probe request event during sending action frame.
+ */
+ if (event == WLC_E_P2P_PROBREQ_MSG) {
+ WL_DBG((" Event %s\n", (event == WLC_E_P2P_PROBREQ_MSG) ?
+ "WLC_E_P2P_PROBREQ_MSG":"WLC_E_PROBREQ_MSG"));
+
+
+ /* Filter any P2P probe reqs arriving during the
+ * GO-NEG Phase
+ */
+ if (cfg->p2p &&
+#if defined(P2P_IE_MISSING_FIX)
+ cfg->p2p_prb_noti &&
+#endif
+ wl_get_p2p_status(cfg, GO_NEG_PHASE)) {
+ WL_DBG(("Filtering P2P probe_req while "
+ "being in GO-Neg state\n"));
+ return 0;
+ }
+ }
+ }
+
+ if (discover_cfgdev(cfgdev, cfg))
+ WL_DBG(("Rx Managment frame For P2P Discovery Interface \n"));
+ else
+ WL_DBG(("Rx Managment frame For Iface (%s) \n", ndev->name));
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+ cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
+#elif(LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
+ cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, 0, GFP_ATOMIC);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
+ defined(WL_COMPAT_WIRELESS)
+ cfg80211_rx_mgmt(cfgdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
+#else
+ cfg80211_rx_mgmt(cfgdev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
+#endif /* LINUX_VERSION >= VERSION(3, 14, 0) */
+
+ WL_DBG(("mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n",
+ mgmt_frame_len, ntoh32(e->datalen), channel, freq));
+exit:
+ if (isfree)
+ kfree(mgmt_frame);
+ return 0;
+}
+
+#ifdef WL_SCHED_SCAN
+/* If target scan is not reliable, set the below define to "1" to do a
+ * full escan
+ */
+#define FULL_ESCAN_ON_PFN_NET_FOUND 0
+static s32
+wl_notify_sched_scan_results(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data)
+{
+ wl_pfn_net_info_t *netinfo, *pnetinfo;
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ int err = 0;
+ struct cfg80211_scan_request *request = NULL;
+ struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT];
+ struct ieee80211_channel *channel = NULL;
+ int channel_req = 0;
+ int band = 0;
+ struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data;
+ int n_pfn_results = pfn_result->count;
+
+ WL_DBG(("Enter\n"));
+
+ if ((e->event_type == WLC_E_PFN_NET_LOST) || !data) {
+ WL_PNO(("Do Nothing %d\n", e->event_type));
+ return 0;
+ }
+ if (pfn_result->version != PFN_SCANRESULT_VERSION) {
+ WL_ERR(("Incorrect version %d, expected %d\n", pfn_result->version,
+ PFN_SCANRESULT_VERSION));
+ return 0;
+ }
+ WL_PNO((">>> PFN NET FOUND event. count:%d \n", n_pfn_results));
+ if (n_pfn_results > 0) {
+ int i;
+
+ if (n_pfn_results > MAX_PFN_LIST_COUNT)
+ n_pfn_results = MAX_PFN_LIST_COUNT;
+ pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t)
+ - sizeof(wl_pfn_net_info_t));
+
+ memset(&ssid, 0x00, sizeof(ssid));
+
+ request = kzalloc(sizeof(*request)
+ + sizeof(*request->channels) * n_pfn_results,
+ GFP_KERNEL);
+ channel = (struct ieee80211_channel *)kzalloc(
+ (sizeof(struct ieee80211_channel) * n_pfn_results),
+ GFP_KERNEL);
+ if (!request || !channel) {
+ WL_ERR(("No memory"));
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ request->wiphy = wiphy;
+
+ for (i = 0; i < n_pfn_results; i++) {
+ netinfo = &pnetinfo[i];
+ if (!netinfo) {
+ WL_ERR(("Invalid netinfo ptr. index:%d", i));
+ err = -EINVAL;
+ goto out_err;
+ }
+ WL_PNO((">>> SSID:%s Channel:%d \n",
+ netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel));
+ /* PFN result doesn't have all the info which are required by the supplicant
+ * (For e.g IEs) Do a target Escan so that sched scan results are reported
+ * via wl_inform_single_bss in the required format. Escan does require the
+ * scan request in the form of cfg80211_scan_request. For timebeing, create
+ * cfg80211_scan_request one out of the received PNO event.
+ */
+ ssid[i].ssid_len = MIN(netinfo->pfnsubnet.SSID_len, DOT11_MAX_SSID_LEN);
+ memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID, ssid[i].ssid_len);
+ request->n_ssids++;
+
+ channel_req = netinfo->pfnsubnet.channel;
+ band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ
+ : NL80211_BAND_5GHZ;
+ channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band);
+ channel[i].band = band;
+ channel[i].flags |= IEEE80211_CHAN_NO_HT40;
+ request->channels[i] = &channel[i];
+ request->n_channels++;
+ }
+
+ /* assign parsed ssid array */
+ if (request->n_ssids)
+ request->ssids = &ssid[0];
+
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ /* Abort any on-going scan */
+ wl_notify_escan_complete(cfg, ndev, true, true);
+ }
+
+ if (wl_get_p2p_status(cfg, DISCOVERY_ON)) {
+ WL_PNO((">>> P2P discovery was ON. Disabling it\n"));
+ err = wl_cfgp2p_discover_enable_search(cfg, false);
+ if (unlikely(err)) {
+ wl_clr_drv_status(cfg, SCANNING, ndev);
+ goto out_err;
+ }
+ p2p_scan(cfg) = false;
+ }
+
+ wl_set_drv_status(cfg, SCANNING, ndev);
+#if FULL_ESCAN_ON_PFN_NET_FOUND
+ WL_PNO((">>> Doing Full ESCAN on PNO event\n"));
+ err = wl_do_escan(cfg, wiphy, ndev, NULL);
+#else
+ WL_PNO((">>> Doing targeted ESCAN on PNO event\n"));
+ err = wl_do_escan(cfg, wiphy, ndev, request);
+#endif
+ if (err) {
+ wl_clr_drv_status(cfg, SCANNING, ndev);
+ goto out_err;
+ }
+ cfg->sched_scan_running = TRUE;
+ }
+ else {
+ WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n"));
+ }
+out_err:
+ if (request)
+ kfree(request);
+ if (channel)
+ kfree(channel);
+ return err;
+}
+#endif /* WL_SCHED_SCAN */
+
+static void wl_init_conf(struct wl_conf *conf)
+{
+ WL_DBG(("Enter \n"));
+ conf->frag_threshold = (u32)-1;
+ conf->rts_threshold = (u32)-1;
+ conf->retry_short = (u32)-1;
+ conf->retry_long = (u32)-1;
+ conf->tx_power = -1;
+}
+
+static void wl_init_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ unsigned long flags;
+ struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
+
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+ memset(profile, 0, sizeof(struct wl_profile));
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+}
+
+static void wl_init_event_handler(struct bcm_cfg80211 *cfg)
+{
+ memset(cfg->evt_handler, 0, sizeof(cfg->evt_handler));
+
+ cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
+ cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_LINK] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status;
+ cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
+ cfg->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame;
+ cfg->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
+ cfg->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
+ cfg->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
+ cfg->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
+ cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
+ cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status;
+ cfg->evt_handler[WLC_E_START] = wl_notify_connect_status;
+#ifdef PNO_SUPPORT
+ cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status;
+#endif /* PNO_SUPPORT */
+#ifdef GSCAN_SUPPORT
+ cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event;
+ cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event;
+ cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event;
+ cfg->evt_handler[WLC_E_PFN_SWC] = wl_notify_gscan_event;
+ cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event;
+ cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event;
+#endif /* GSCAN_SUPPORT */
+#ifdef WLTDLS
+ cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler;
+#endif /* WLTDLS */
+ cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status;
+#ifdef WL_RELMCAST
+ cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status;
+#endif
+#ifdef BT_WIFI_HANDOVER
+ cfg->evt_handler[WLC_E_BT_WIFI_HANDOVER_REQ] = wl_notify_bt_wifi_handover_req;
+#endif
+#ifdef WL_NAN
+ cfg->evt_handler[WLC_E_NAN] = wl_cfgnan_notify_nan_status;
+ cfg->evt_handler[WLC_E_PROXD] = wl_cfgnan_notify_proxd_status;
+#endif /* WL_NAN */
+ cfg->evt_handler[WLC_E_CSA_COMPLETE_IND] = wl_csa_complete_ind;
+#ifdef DHD_LOSSLESS_ROAMING
+ cfg->evt_handler[WLC_E_ROAM_PREP] = wl_notify_roam_prep_status;
+#endif
+ cfg->evt_handler[WLC_E_AP_STARTED] = wl_ap_start_ind;
+#ifdef CUSTOM_EVENT_PM_WAKE
+ cfg->evt_handler[WLC_E_EXCESS_PM_WAKE_EVENT] = wl_check_pmstatus;
+#endif /* CUSTOM_EVENT_PM_WAKE */
+ cfg->evt_handler[WLC_E_PSK_SUP] = wl_notify_idsup_status;
+#ifdef ENABLE_TEMP_THROTTLING
+ cfg->evt_handler[WLC_E_TEMP_THROTTLE] = wl_check_rx_throttle_status;
+#endif /* ENABLE_TEMP_THROTTLING */
+}
+
+#if defined(STATIC_WL_PRIV_STRUCT)
+static void
+wl_init_escan_result_buf(struct bcm_cfg80211 *cfg)
+{
+ cfg->escan_info.escan_buf = DHD_OS_PREALLOC(cfg->pub,
+ DHD_PREALLOC_WIPHY_ESCAN0, ESCAN_BUF_SIZE);
+ bzero(cfg->escan_info.escan_buf, ESCAN_BUF_SIZE);
+}
+
+static void
+wl_deinit_escan_result_buf(struct bcm_cfg80211 *cfg)
+{
+ cfg->escan_info.escan_buf = NULL;
+
+}
+#endif /* STATIC_WL_PRIV_STRUCT */
+
+static s32 wl_init_priv_mem(struct bcm_cfg80211 *cfg)
+{
+ WL_DBG(("Enter \n"));
+
+ cfg->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
+ if (unlikely(!cfg->scan_results)) {
+ WL_ERR(("Scan results alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ cfg->conf = (void *)kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
+ if (unlikely(!cfg->conf)) {
+ WL_ERR(("wl_conf alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ cfg->scan_req_int =
+ (void *)kzalloc(sizeof(*cfg->scan_req_int), GFP_KERNEL);
+ if (unlikely(!cfg->scan_req_int)) {
+ WL_ERR(("Scan req alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ cfg->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
+ if (unlikely(!cfg->ioctl_buf)) {
+ WL_ERR(("Ioctl buf alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ cfg->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
+ if (unlikely(!cfg->escan_ioctl_buf)) {
+ WL_ERR(("Ioctl buf alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ cfg->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
+ if (unlikely(!cfg->extra_buf)) {
+ WL_ERR(("Extra buf alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ cfg->pmk_list = (void *)kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
+ if (unlikely(!cfg->pmk_list)) {
+ WL_ERR(("pmk list alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+#if defined(STATIC_WL_PRIV_STRUCT)
+ cfg->conn_info = (void *)kzalloc(sizeof(*cfg->conn_info), GFP_KERNEL);
+ if (unlikely(!cfg->conn_info)) {
+ WL_ERR(("cfg->conn_info alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ cfg->ie = (void *)kzalloc(sizeof(*cfg->ie), GFP_KERNEL);
+ if (unlikely(!cfg->ie)) {
+ WL_ERR(("cfg->ie alloc failed\n"));
+ goto init_priv_mem_out;
+ }
+ wl_init_escan_result_buf(cfg);
+#endif /* STATIC_WL_PRIV_STRUCT */
+ cfg->afx_hdl = (void *)kzalloc(sizeof(*cfg->afx_hdl), GFP_KERNEL);
+ if (unlikely(!cfg->afx_hdl)) {
+ WL_ERR(("afx hdl alloc failed\n"));
+ goto init_priv_mem_out;
+ } else {
+ init_completion(&cfg->act_frm_scan);
+ init_completion(&cfg->wait_next_af);
+
+ INIT_WORK(&cfg->afx_hdl->work, wl_cfg80211_afx_handler);
+ }
+#ifdef WLTDLS
+ if (cfg->tdls_mgmt_frame) {
+ kfree(cfg->tdls_mgmt_frame);
+ cfg->tdls_mgmt_frame = NULL;
+ }
+#endif /* WLTDLS */
+ return 0;
+
+init_priv_mem_out:
+ wl_deinit_priv_mem(cfg);
+
+ return -ENOMEM;
+}
+
+static void wl_deinit_priv_mem(struct bcm_cfg80211 *cfg)
+{
+ kfree(cfg->scan_results);
+ cfg->scan_results = NULL;
+ kfree(cfg->conf);
+ cfg->conf = NULL;
+ kfree(cfg->scan_req_int);
+ cfg->scan_req_int = NULL;
+ kfree(cfg->ioctl_buf);
+ cfg->ioctl_buf = NULL;
+ kfree(cfg->escan_ioctl_buf);
+ cfg->escan_ioctl_buf = NULL;
+ kfree(cfg->extra_buf);
+ cfg->extra_buf = NULL;
+ kfree(cfg->pmk_list);
+ cfg->pmk_list = NULL;
+#if defined(STATIC_WL_PRIV_STRUCT)
+ kfree(cfg->conn_info);
+ cfg->conn_info = NULL;
+ kfree(cfg->ie);
+ cfg->ie = NULL;
+ wl_deinit_escan_result_buf(cfg);
+#endif /* STATIC_WL_PRIV_STRUCT */
+ if (cfg->afx_hdl) {
+ cancel_work_sync(&cfg->afx_hdl->work);
+ kfree(cfg->afx_hdl);
+ cfg->afx_hdl = NULL;
+ }
+
+}
+
+static s32 wl_create_event_handler(struct bcm_cfg80211 *cfg)
+{
+ int ret = 0;
+ WL_DBG(("Enter \n"));
+
+ if (!cfg->event_workq) {
+ /* Allocate workqueue for event */
+ cfg->event_workq = alloc_workqueue("dhd_eventd", WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
+ if (!cfg->event_workq) {
+ ret = -ENOMEM;
+ } else {
+ INIT_WORK(&cfg->event_work, wl_event_handler);
+ }
+ }
+ return ret;
+}
+
+static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg)
+{
+ if (cfg->event_workq) {
+ cancel_work_sync(&cfg->event_work);
+ destroy_workqueue(cfg->event_workq);
+ cfg->event_workq = NULL;
+ }
+}
+
+void wl_terminate_event_handler(void *cfg80211_priv)
+{
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)cfg80211_priv;
+
+ if (cfg) {
+ wl_destroy_event_handler(cfg);
+ wl_flush_eq(cfg);
+ }
+}
+
+static void wl_scan_timeout(unsigned long data)
+{
+ wl_event_msg_t msg;
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
+ struct wireless_dev *wdev = NULL;
+ struct net_device *ndev = NULL;
+ struct wl_scan_results *bss_list;
+ struct wl_bss_info *bi = NULL;
+ s32 i;
+ u32 channel;
+#if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
+ uint32 prev_memdump_mode = dhdp->memdump_enabled;
+#endif /* DHD_DEBUG && BCMPCIE */
+
+ if (!(cfg->scan_request)) {
+ WL_ERR(("timer expired but no scan request\n"));
+ return;
+ }
+
+ bss_list = wl_escan_get_buf(cfg, FALSE);
+ if (!bss_list) {
+ WL_ERR(("bss_list is null. Didn't receive any partial scan results\n"));
+ } else {
+ WL_ERR(("scanned AP count (%d)\n", bss_list->count));
+
+ bi = next_bss(bss_list, bi);
+ for_each_bss(bss_list, bi, i) {
+ channel = wf_chspec_ctlchan(wl_chspec_driver_to_host(bi->chanspec));
+ WL_ERR(("SSID :%s Channel :%d\n", bi->SSID, channel));
+ }
+ }
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
+ if (cfg->scan_request->dev)
+ wdev = cfg->scan_request->dev->ieee80211_ptr;
+#else
+ wdev = cfg->scan_request->wdev;
+#endif /* LINUX_VERSION < KERNEL_VERSION(3, 6, 0) */
+ if (!wdev) {
+ WL_ERR(("No wireless_dev present\n"));
+ return;
+ }
+ ndev = wdev_to_wlc_ndev(wdev, cfg);
+
+ bzero(&msg, sizeof(wl_event_msg_t));
+ WL_ERR(("timer expired\n"));
+#if defined(DHD_DEBUG) && defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
+ if (dhdp->memdump_enabled) {
+ dhdp->memdump_enabled = DUMP_MEMFILE;
+ dhdp->memdump_type = DUMP_TYPE_SCAN_TIMEOUT;
+ dhd_bus_mem_dump(dhdp);
+ dhdp->memdump_enabled = prev_memdump_mode;
+ }
+#endif /* DHD_DEBUG && BCMPCIE */
+ msg.event_type = hton32(WLC_E_ESCAN_RESULT);
+ msg.status = hton32(WLC_E_STATUS_TIMEOUT);
+ msg.reason = 0xFFFFFFFF;
+ wl_cfg80211_event(ndev, &msg, NULL);
+#ifdef CUSTOMER_HW4_DEBUG
+ if (!wl_scan_timeout_dbg_enabled)
+ wl_scan_timeout_dbg_set();
+#endif /* CUSTOMER_HW4_DEBUG */
+}
+
+#ifdef DHD_LOSSLESS_ROAMING
+static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg)
+{
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
+
+ /* restore prec_map to ALLPRIO */
+ dhdp->dequeue_prec_map = ALLPRIO;
+ if (timer_pending(&cfg->roam_timeout)) {
+ del_timer_sync(&cfg->roam_timeout);
+ }
+
+}
+
+static void wl_roam_timeout(unsigned long data)
+{
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
+ dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
+
+ WL_ERR(("roam timer expired\n"));
+
+ /* restore prec_map to ALLPRIO */
+ dhdp->dequeue_prec_map = ALLPRIO;
+}
+
+#endif /* DHD_LOSSLESS_ROAMING */
+
+static s32
+wl_cfg80211_netdev_notifier_call(struct notifier_block * nb,
+ unsigned long state, void *ptr)
+{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
+ struct net_device *dev = ptr;
+#else
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+#endif /* LINUX_VERSION < VERSION(3, 11, 0) */
+ struct wireless_dev *wdev = ndev_to_wdev(dev);
+ struct bcm_cfg80211 *cfg = NULL;
+
+#ifdef DHD_IFDEBUG
+ WL_ERR(("Enter \n"));
+#endif
+
+ if (!wdev)
+ return NOTIFY_DONE;
+
+ cfg = WDEV_GET_CFG80211_PRIV(wdev);
+ if (!cfg || dev == bcmcfg_to_prmry_ndev(cfg))
+ return NOTIFY_DONE;
+
+ switch (state) {
+ case NETDEV_DOWN:
+ {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
+ int max_wait_timeout = 2;
+ int max_wait_count = 100;
+ int refcnt = 0;
+ unsigned long limit = jiffies + max_wait_timeout * HZ;
+#ifdef DHD_IFDEBUG
+ WL_ERR(("NETDEV_DOWN(+) wdev=%p, cfg=%p, dev=%p\n", wdev, cfg, dev));
+#endif
+ while (work_pending(&wdev->cleanup_work)) {
+ if (refcnt%5 == 0) {
+ WL_ERR(("[NETDEV_DOWN] wait for "
+ "complete of cleanup_work"
+ " (%d th)\n", refcnt));
+ }
+ if (!time_before(jiffies, limit)) {
+ WL_ERR(("[NETDEV_DOWN] cleanup_work"
+ " of CFG80211 is not"
+ " completed in %d sec\n",
+ max_wait_timeout));
+ break;
+ }
+ if (refcnt >= max_wait_count) {
+ WL_ERR(("[NETDEV_DOWN] cleanup_work"
+ " of CFG80211 is not"
+ " completed in %d loop\n",
+ max_wait_count));
+ break;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ (void)schedule_timeout(100);
+ set_current_state(TASK_RUNNING);
+ refcnt++;
+ }
+#ifdef DHD_IFDEBUG
+ WL_ERR(("NETDEV_DOWN(-) wdev=%p, cfg=%p, dev=%p\n", wdev, cfg, dev));
+#endif
+#endif /* LINUX_VERSION < VERSION(3, 14, 0) */
+ break;
+ }
+ case NETDEV_UNREGISTER:
+#ifdef DHD_IFDEBUG
+ WL_ERR(("NETDEV_UNREGISTER(+) wdev=%p, cfg=%p, dev=%p\n", wdev, cfg, dev));
+#endif
+ /* after calling list_del_rcu(&wdev->list) */
+ wl_cfg80211_clear_per_bss_ies(cfg,
+ wl_get_bssidx_by_wdev(cfg, wdev));
+ wl_dealloc_netinfo_by_wdev(cfg, wdev);
+#ifdef DHD_IFDEBUG
+ WL_ERR(("NETDEV_UNREGISTER(-) wdev=%p, cfg=%p, dev=%p\n", wdev, cfg, dev));
+#endif
+ break;
+ case NETDEV_GOING_DOWN:
+ /*
+ * At NETDEV_DOWN state, wdev_cleanup_work work will be called.
+ * In front of door, the function checks whether current scan
+ * is working or not. If the scanning is still working,
+ * wdev_cleanup_work call WARN_ON and make the scan done forcibly.
+ */
+#ifdef DHD_IFDEBUG
+ WL_ERR(("NETDEV_GOING_DOWN wdev=%p, cfg=%p, dev=%p\n", wdev, cfg, dev));
+#endif
+ if (wl_get_drv_status(cfg, SCANNING, dev))
+ wl_notify_escan_complete(cfg, dev, true, true);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block wl_cfg80211_netdev_notifier = {
+ .notifier_call = wl_cfg80211_netdev_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 wl_cfg80211_netdev_notifier_registered = FALSE;
+
+static void wl_cfg80211_cancel_scan(struct bcm_cfg80211 *cfg)
+{
+ struct wireless_dev *wdev = NULL;
+ struct net_device *ndev = NULL;
+
+ if (!cfg->scan_request)
+ return;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
+ if (cfg->scan_request->dev)
+ wdev = cfg->scan_request->dev->ieee80211_ptr;
+#else
+ wdev = cfg->scan_request->wdev;
+#endif /* LINUX_VERSION < KERNEL_VERSION(3, 6, 0) */
+
+ if (!wdev) {
+ WL_ERR(("No wireless_dev present\n"));
+ return;
+ }
+
+ ndev = wdev_to_wlc_ndev(wdev, cfg);
+ wl_notify_escan_complete(cfg, ndev, true, true);
+ WL_ERR(("Scan aborted! \n"));
+}
+
+static void wl_cfg80211_scan_abort(struct bcm_cfg80211 *cfg)
+{
+ wl_scan_params_t *params = NULL;
+ s32 params_size = 0;
+ s32 err = BCME_OK;
+ struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
+ if (!in_atomic()) {
+ /* Our scan params only need space for 1 channel and 0 ssids */
+ params = wl_cfg80211_scan_alloc_params(cfg->wdev, -1, 0, &params_size);
+ if (params == NULL) {
+ WL_ERR(("scan params allocation failed \n"));
+ err = -ENOMEM;
+ } else {
+ /* Do a scan abort to stop the driver's scan engine */
+ err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true);
+ if (err < 0) {
+ WL_ERR(("scan abort failed \n"));
+ }
+ kfree(params);
+ }
+ }
+#ifdef WLTDLS
+ if (cfg->tdls_mgmt_frame) {
+ kfree(cfg->tdls_mgmt_frame);
+ cfg->tdls_mgmt_frame = NULL;
+ }
+#endif /* WLTDLS */
+}
+
+static s32 wl_notify_escan_complete(struct bcm_cfg80211 *cfg,
+ struct net_device *ndev,
+ bool aborted, bool fw_abort)
+{
+ s32 err = BCME_OK;
+ unsigned long flags;
+ struct net_device *dev;
+
+ WL_DBG(("Enter \n"));
+
+ mutex_lock(&cfg->scan_complete);
+
+ if (!ndev) {
+ WL_ERR(("ndev is null\n"));
+ err = BCME_ERROR;
+ goto out;
+ }
+
+ if (cfg->escan_info.ndev != ndev) {
+ WL_ERR(("ndev is different %p %p\n", cfg->escan_info.ndev, ndev));
+ err = BCME_ERROR;
+ goto out;
+ }
+
+ if (cfg->scan_request) {
+ dev = bcmcfg_to_prmry_ndev(cfg);
+#if defined(WL_ENABLE_P2P_IF)
+ if (cfg->scan_request->dev != cfg->p2p_net)
+ dev = cfg->scan_request->dev;
+#elif defined(WL_CFG80211_P2P_DEV_IF)
+ if (cfg->scan_request->wdev->iftype != NL80211_IFTYPE_P2P_DEVICE) {
+#ifdef DHD_IFDEBUG
+ WL_ERR(("%s: dev: %p\n", __FUNCTION__, cfg->scan_request->wdev->netdev));
+#endif
+ dev = cfg->scan_request->wdev->netdev;
+ }
+#endif /* WL_ENABLE_P2P_IF */
+ }
+ else {
+ WL_DBG(("cfg->scan_request is NULL may be internal scan."
+ "doing scan_abort for ndev %p primary %p",
+ ndev, bcmcfg_to_prmry_ndev(cfg)));
+ dev = ndev;
+ }
+ if (fw_abort && !in_atomic())
+ wl_cfg80211_scan_abort(cfg);
+ if (timer_pending(&cfg->scan_timeout))
+ del_timer_sync(&cfg->scan_timeout);
+#if defined(ESCAN_RESULT_PATCH)
+ if (likely(cfg->scan_request)) {
+ cfg->bss_list = wl_escan_get_buf(cfg, aborted);
+ wl_inform_bss(cfg);
+ }
+#endif /* ESCAN_RESULT_PATCH */
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+#ifdef WL_SCHED_SCAN
+ if (cfg->sched_scan_req && !cfg->scan_request) {
+ WL_PNO((">>> REPORTING SCHED SCAN RESULTS \n"));
+ if (!aborted)
+ cfg80211_sched_scan_results(cfg->sched_scan_req->wiphy);
+ cfg->sched_scan_running = FALSE;
+ cfg->sched_scan_req = NULL;
+ }
+#endif /* WL_SCHED_SCAN */
+ if (likely(cfg->scan_request)) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
+ struct cfg80211_scan_info info = {
+ .aborted = aborted
+ };
+ cfg80211_scan_done(cfg->scan_request, &info);
+#else
+ cfg80211_scan_done(cfg->scan_request, aborted);
+#endif
+ cfg->scan_request = NULL;
+ DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
+ DHD_ENABLE_RUNTIME_PM((dhd_pub_t *)(cfg->pub));
+ }
+ if (p2p_is_on(cfg))
+ wl_clr_p2p_status(cfg, SCANNING);
+ wl_clr_drv_status(cfg, SCANNING, dev);
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+
+out:
+ mutex_unlock(&cfg->scan_complete);
+ return err;
+}
+
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+static void
+wl_cfg80211_find_removal_candidate(wl_bss_info_t *bss, removal_element_t *candidate)
+{
+ int idx;
+ for (idx = 0; idx < BUF_OVERFLOW_MGMT_COUNT; idx++) {
+ int len = BUF_OVERFLOW_MGMT_COUNT - idx - 1;
+ if (bss->RSSI < candidate[idx].RSSI) {
+ if (len)
+ memcpy(&candidate[idx + 1], &candidate[idx],
+ sizeof(removal_element_t) * len);
+ candidate[idx].RSSI = bss->RSSI;
+ candidate[idx].length = bss->length;
+ memcpy(&candidate[idx].BSSID, &bss->BSSID, ETHER_ADDR_LEN);
+ return;
+ }
+ }
+}
+
+static void
+wl_cfg80211_remove_lowRSSI_info(wl_scan_results_t *list, removal_element_t *candidate,
+ wl_bss_info_t *bi)
+{
+ int idx1, idx2;
+ int total_delete_len = 0;
+ for (idx1 = 0; idx1 < BUF_OVERFLOW_MGMT_COUNT; idx1++) {
+ int cur_len = WL_SCAN_RESULTS_FIXED_SIZE;
+ wl_bss_info_t *bss = NULL;
+ if (candidate[idx1].RSSI >= bi->RSSI)
+ continue;
+ for (idx2 = 0; idx2 < list->count; idx2++) {
+ bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) :
+ list->bss_info;
+ if (!bcmp(&candidate[idx1].BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
+ candidate[idx1].RSSI == bss->RSSI &&
+ candidate[idx1].length == dtoh32(bss->length)) {
+ u32 delete_len = dtoh32(bss->length);
+ WL_DBG(("delete scan info of " MACDBG " to add new AP\n",
+ MAC2STRDBG(bss->BSSID.octet)));
+ if (idx2 < list->count -1) {
+ memmove((u8 *)bss, (u8 *)bss + delete_len,
+ list->buflen - cur_len - delete_len);
+ }
+ list->buflen -= delete_len;
+ list->count--;
+ total_delete_len += delete_len;
+ /* if delete_len is greater than or equal to result length */
+ if (total_delete_len >= bi->length) {
+ return;
+ }
+ break;
+ }
+ cur_len += dtoh32(bss->length);
+ }
+ }
+}
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
+
+static s32 wl_escan_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ s32 err = BCME_OK;
+ s32 status = ntoh32(e->status);
+ wl_bss_info_t *bi;
+ wl_escan_result_t *escan_result;
+ wl_bss_info_t *bss = NULL;
+ wl_scan_results_t *list;
+ wifi_p2p_ie_t * p2p_ie;
+ struct net_device *ndev = NULL;
+ u32 bi_length;
+ u32 i;
+ u8 *p2p_dev_addr = NULL;
+
+ WL_DBG((" enter event type : %d, status : %d \n",
+ ntoh32(e->event_type), ntoh32(e->status)));
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ mutex_lock(&cfg->usr_sync);
+ /* P2P SCAN is coming from primary interface */
+ if (wl_get_p2p_status(cfg, SCANNING)) {
+ if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM))
+ ndev = cfg->afx_hdl->dev;
+ else
+ ndev = cfg->escan_info.ndev;
+
+ }
+ if (!ndev || (!wl_get_drv_status(cfg, SCANNING, ndev) && !cfg->sched_scan_running)) {
+ WL_ERR(("escan is not ready ndev %p drv_status 0x%x e_type %d e_states %d\n",
+ ndev, wl_get_drv_status(cfg, SCANNING, ndev),
+ ntoh32(e->event_type), ntoh32(e->status)));
+ goto exit;
+ }
+ escan_result = (wl_escan_result_t *)data;
+
+ if (status == WLC_E_STATUS_PARTIAL) {
+ WL_INFORM(("WLC_E_STATUS_PARTIAL \n"));
+ if (!escan_result) {
+ WL_ERR(("Invalid escan result (NULL pointer)\n"));
+ goto exit;
+ }
+ if (dtoh16(escan_result->bss_count) != 1) {
+ WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count));
+ goto exit;
+ }
+ bi = escan_result->bss_info;
+ if (!bi) {
+ WL_ERR(("Invalid escan bss info (NULL pointer)\n"));
+ goto exit;
+ }
+ bi_length = dtoh32(bi->length);
+ if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) {
+ WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length));
+ goto exit;
+ }
+ if (wl_escan_check_sync_id(status, escan_result->sync_id,
+ cfg->escan_info.cur_sync_id) < 0)
+ goto exit;
+
+ if (!(bcmcfg_to_wiphy(cfg)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) {
+ if (dtoh16(bi->capability) & DOT11_CAP_IBSS) {
+ WL_DBG(("Ignoring IBSS result\n"));
+ goto exit;
+ }
+ }
+
+ if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
+ p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length);
+ if (p2p_dev_addr && !memcmp(p2p_dev_addr,
+ cfg->afx_hdl->tx_dst_addr.octet, ETHER_ADDR_LEN)) {
+ s32 channel = wf_chspec_ctlchan(
+ wl_chspec_driver_to_host(bi->chanspec));
+
+ if ((channel > MAXCHANNEL) || (channel <= 0))
+ channel = WL_INVALID;
+ else
+ WL_ERR(("ACTION FRAME SCAN : Peer " MACDBG " found,"
+ " channel : %d\n",
+ MAC2STRDBG(cfg->afx_hdl->tx_dst_addr.octet),
+ channel));
+
+ wl_clr_p2p_status(cfg, SCANNING);
+ cfg->afx_hdl->peer_chan = channel;
+ complete(&cfg->act_frm_scan);
+ goto exit;
+ }
+
+ } else {
+ int cur_len = WL_SCAN_RESULTS_FIXED_SIZE;
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+ removal_element_t candidate[BUF_OVERFLOW_MGMT_COUNT];
+ int remove_lower_rssi = FALSE;
+
+ bzero(candidate, sizeof(removal_element_t)*BUF_OVERFLOW_MGMT_COUNT);
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
+
+ list = wl_escan_get_buf(cfg, FALSE);
+ if (scan_req_match(cfg)) {
+ /* p2p scan && allow only probe response */
+ if ((cfg->p2p->search_state != WL_P2P_DISC_ST_SCAN) &&
+ (bi->flags & WL_BSS_FLAGS_FROM_BEACON))
+ goto exit;
+ if ((p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset,
+ bi->ie_length)) == NULL) {
+ WL_ERR(("Couldn't find P2PIE in probe"
+ " response/beacon\n"));
+ goto exit;
+ }
+ }
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+ if (bi_length > ESCAN_BUF_SIZE - list->buflen)
+ remove_lower_rssi = TRUE;
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
+
+ for (i = 0; i < list->count; i++) {
+ bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
+ : list->bss_info;
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+ WL_TRACE(("%s("MACDBG"), i=%d bss: RSSI %d list->count %d\n",
+ bss->SSID, MAC2STRDBG(bss->BSSID.octet),
+ i, bss->RSSI, list->count));
+
+ if (remove_lower_rssi)
+ wl_cfg80211_find_removal_candidate(bss, candidate);
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
+
+ if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
+ (CHSPEC_BAND(wl_chspec_driver_to_host(bi->chanspec))
+ == CHSPEC_BAND(wl_chspec_driver_to_host(bss->chanspec))) &&
+ bi->SSID_len == bss->SSID_len &&
+ !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) {
+
+ /* do not allow beacon data to update
+ *the data recd from a probe response
+ */
+ if (!(bss->flags & WL_BSS_FLAGS_FROM_BEACON) &&
+ (bi->flags & WL_BSS_FLAGS_FROM_BEACON))
+ goto exit;
+
+ WL_DBG(("%s("MACDBG"), i=%d prev: RSSI %d"
+ " flags 0x%x, new: RSSI %d flags 0x%x\n",
+ bss->SSID, MAC2STRDBG(bi->BSSID.octet), i,
+ bss->RSSI, bss->flags, bi->RSSI, bi->flags));
+
+ if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) ==
+ (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL)) {
+ /* preserve max RSSI if the measurements are
+ * both on-channel or both off-channel
+ */
+ WL_SCAN(("%s("MACDBG"), same onchan"
+ ", RSSI: prev %d new %d\n",
+ bss->SSID, MAC2STRDBG(bi->BSSID.octet),
+ bss->RSSI, bi->RSSI));
+ bi->RSSI = MAX(bss->RSSI, bi->RSSI);
+ } else if ((bss->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) &&
+ (bi->flags & WL_BSS_FLAGS_RSSI_ONCHANNEL) == 0) {
+ /* preserve the on-channel rssi measurement
+ * if the new measurement is off channel
+ */
+ WL_SCAN(("%s("MACDBG"), prev onchan"
+ ", RSSI: prev %d new %d\n",
+ bss->SSID, MAC2STRDBG(bi->BSSID.octet),
+ bss->RSSI, bi->RSSI));
+ bi->RSSI = bss->RSSI;
+ bi->flags |= WL_BSS_FLAGS_RSSI_ONCHANNEL;
+ }
+ if (dtoh32(bss->length) != bi_length) {
+ u32 prev_len = dtoh32(bss->length);
+
+ WL_SCAN(("bss info replacement"
+ " is occured(bcast:%d->probresp%d)\n",
+ bss->ie_length, bi->ie_length));
+ WL_DBG(("%s("MACDBG"), replacement!(%d -> %d)\n",
+ bss->SSID, MAC2STRDBG(bi->BSSID.octet),
+ prev_len, bi_length));
+
+ if (list->buflen - prev_len + bi_length
+ > ESCAN_BUF_SIZE) {
+ WL_ERR(("Buffer is too small: keep the"
+ " previous result of this AP\n"));
+ /* Only update RSSI */
+ bss->RSSI = bi->RSSI;
+ bss->flags |= (bi->flags
+ & WL_BSS_FLAGS_RSSI_ONCHANNEL);
+ goto exit;
+ }
+
+ if (i < list->count - 1) {
+ /* memory copy required by this case only */
+ memmove((u8 *)bss + bi_length,
+ (u8 *)bss + prev_len,
+ list->buflen - cur_len - prev_len);
+ }
+ list->buflen -= prev_len;
+ list->buflen += bi_length;
+ }
+ list->version = dtoh32(bi->version);
+ memcpy((u8 *)bss, (u8 *)bi, bi_length);
+ goto exit;
+ }
+ cur_len += dtoh32(bss->length);
+ }
+ if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+ wl_cfg80211_remove_lowRSSI_info(list, candidate, bi);
+ if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
+ WL_DBG(("RSSI(" MACDBG ") is too low(%d) to add Buffer\n",
+ MAC2STRDBG(bi->BSSID.octet), bi->RSSI));
+ goto exit;
+ }
+#else
+ WL_ERR(("Buffer is too small: ignoring\n"));
+ goto exit;
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
+ }
+
+ memcpy(&(((char *)list)[list->buflen]), bi, bi_length);
+ list->version = dtoh32(bi->version);
+ list->buflen += bi_length;
+ list->count++;
+
+ /*
+ * !Broadcast && number of ssid = 1 && number of channels =1
+ * means specific scan to association
+ */
+ if (wl_cfgp2p_is_p2p_specific_scan(cfg->scan_request)) {
+ WL_ERR(("P2P assoc scan fast aborted.\n"));
+ wl_notify_escan_complete(cfg, cfg->escan_info.ndev, false, true);
+ goto exit;
+ }
+ }
+ }
+ else if (status == WLC_E_STATUS_SUCCESS) {
+ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+ wl_escan_print_sync_id(status, cfg->escan_info.cur_sync_id,
+ escan_result->sync_id);
+
+ if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
+ WL_INFORM(("ACTION FRAME SCAN DONE\n"));
+ wl_clr_p2p_status(cfg, SCANNING);
+ wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
+ if (cfg->afx_hdl->peer_chan == WL_INVALID)
+ complete(&cfg->act_frm_scan);
+ } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
+ WL_INFORM(("ESCAN COMPLETED\n"));
+ cfg->bss_list = wl_escan_get_buf(cfg, FALSE);
+ if (!scan_req_match(cfg)) {
+ WL_TRACE_HW4(("SCAN COMPLETED: scanned AP count=%d\n",
+ cfg->bss_list->count));
+ }
+ wl_inform_bss(cfg);
+ wl_notify_escan_complete(cfg, ndev, false, false);
+ }
+ wl_escan_increment_sync_id(cfg, SCAN_BUF_NEXT);
+#ifdef CUSTOMER_HW4_DEBUG
+ if (wl_scan_timeout_dbg_enabled)
+ wl_scan_timeout_dbg_clear();
+#endif /* CUSTOMER_HW4_DEBUG */
+ } else if ((status == WLC_E_STATUS_ABORT) || (status == WLC_E_STATUS_NEWSCAN) ||
+ (status == WLC_E_STATUS_11HQUIET) || (status == WLC_E_STATUS_CS_ABORT) ||
+ (status == WLC_E_STATUS_NEWASSOC)) {
+ /* Handle all cases of scan abort */
+ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+ wl_escan_print_sync_id(status, escan_result->sync_id,
+ cfg->escan_info.cur_sync_id);
+ WL_DBG(("ESCAN ABORT reason: %d\n", status));
+ if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
+ WL_INFORM(("ACTION FRAME SCAN DONE\n"));
+ wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
+ wl_clr_p2p_status(cfg, SCANNING);
+ if (cfg->afx_hdl->peer_chan == WL_INVALID)
+ complete(&cfg->act_frm_scan);
+ } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
+ WL_INFORM(("ESCAN ABORTED\n"));
+ cfg->bss_list = wl_escan_get_buf(cfg, TRUE);
+ if (!scan_req_match(cfg)) {
+ WL_TRACE_HW4(("scan_req_match=0: scanned AP count=%d\n",
+ cfg->bss_list->count));
+ }
+ wl_inform_bss(cfg);
+ wl_notify_escan_complete(cfg, ndev, true, false);
+ } else {
+ /* If there is no pending host initiated scan, do nothing */
+ WL_DBG(("ESCAN ABORT: No pending scans. Ignoring event.\n"));
+ }
+ wl_escan_increment_sync_id(cfg, SCAN_BUF_CNT);
+ } else if (status == WLC_E_STATUS_TIMEOUT) {
+ WL_ERR(("WLC_E_STATUS_TIMEOUT : scan_request[%p]\n", cfg->scan_request));
+ WL_ERR(("reason[0x%x]\n", e->reason));
+ if (e->reason == 0xFFFFFFFF) {
+ wl_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
+ }
+ } else {
+ WL_ERR(("unexpected Escan Event %d : abort\n", status));
+ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+ wl_escan_print_sync_id(status, escan_result->sync_id,
+ cfg->escan_info.cur_sync_id);
+ if (wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
+ WL_INFORM(("ACTION FRAME SCAN DONE\n"));
+ wl_clr_p2p_status(cfg, SCANNING);
+ wl_clr_drv_status(cfg, SCANNING, cfg->afx_hdl->dev);
+ if (cfg->afx_hdl->peer_chan == WL_INVALID)
+ complete(&cfg->act_frm_scan);
+ } else if ((likely(cfg->scan_request)) || (cfg->sched_scan_running)) {
+ cfg->bss_list = wl_escan_get_buf(cfg, TRUE);
+ if (!scan_req_match(cfg)) {
+ WL_TRACE_HW4(("SCAN ABORTED(UNEXPECTED): "
+ "scanned AP count=%d\n",
+ cfg->bss_list->count));
+ }
+ wl_inform_bss(cfg);
+ wl_notify_escan_complete(cfg, ndev, true, false);
+ }
+ wl_escan_increment_sync_id(cfg, 2);
+ }
+exit:
+ mutex_unlock(&cfg->usr_sync);
+ return err;
+}
+
+static void wl_cfg80211_concurrent_roam(struct bcm_cfg80211 *cfg, int enable)
+{
+ u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
+ bool p2p_connected = wl_cfgp2p_vif_created(cfg);
+ struct net_info *iter, *next;
+
+ if (!cfg->roamoff_on_concurrent)
+ return;
+ if (enable && (p2p_connected||(connected_cnt > 1))) {
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#endif
+ for_each_ndev(cfg, iter, next) {
+ if (iter->ndev && iter->wdev &&
+ iter->wdev->iftype == NL80211_IFTYPE_STATION) {
+ if (wldev_iovar_setint(iter->ndev, "roam_off", TRUE)
+ == BCME_OK) {
+ iter->roam_off = TRUE;
+ }
+ else {
+ WL_ERR(("error to enable roam_off\n"));
+ }
+ }
+ }
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic pop")
+#endif
+ }
+ else if (!enable) {
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#endif
+ for_each_ndev(cfg, iter, next) {
+ if (iter->ndev && iter->wdev &&
+ iter->wdev->iftype == NL80211_IFTYPE_STATION) {
+ if (iter->roam_off != WL_INVALID) {
+ if (wldev_iovar_setint(iter->ndev, "roam_off", FALSE)
+ == BCME_OK) {
+ iter->roam_off = FALSE;
+ }
+ else {
+ WL_ERR(("error to disable roam_off\n"));
+ }
+ }
+ }
+ }
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic pop")
+#endif
+ }
+ return;
+}
+
+static void wl_cfg80211_determine_vsdb_mode(struct bcm_cfg80211 *cfg)
+{
+ struct net_info *iter, *next;
+ u32 ctl_chan = 0;
+ u32 chanspec = 0;
+ u32 pre_ctl_chan = 0;
+ u32 connected_cnt = wl_get_drv_status_all(cfg, CONNECTED);
+ cfg->vsdb_mode = false;
+
+ if (connected_cnt <= 1) {
+ return;
+ }
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#endif
+ for_each_ndev(cfg, iter, next) {
+ /* p2p discovery iface ndev could be null */
+ if (iter->ndev) {
+ chanspec = 0;
+ ctl_chan = 0;
+ if (wl_get_drv_status(cfg, CONNECTED, iter->ndev)) {
+ if (wldev_iovar_getint(iter->ndev, "chanspec",
+ (s32 *)&chanspec) == BCME_OK) {
+ chanspec = wl_chspec_driver_to_host(chanspec);
+ ctl_chan = wf_chspec_ctlchan(chanspec);
+ wl_update_prof(cfg, iter->ndev, NULL,
+ &ctl_chan, WL_PROF_CHAN);
+ }
+ if (!cfg->vsdb_mode) {
+ if (!pre_ctl_chan && ctl_chan)
+ pre_ctl_chan = ctl_chan;
+ else if (pre_ctl_chan && (pre_ctl_chan != ctl_chan)) {
+ cfg->vsdb_mode = true;
+ }
+ }
+ }
+ }
+ }
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic pop")
+#endif
+ WL_ERR(("%s concurrency is enabled\n", cfg->vsdb_mode ? "Multi Channel" : "Same Channel"));
+ return;
+}
+
+#if defined(DISABLE_FRAMEBURST_VSDB) && defined(USE_WFA_CERT_CONF)
+extern int g_frameburst;
+#endif /* DISABLE_FRAMEBURST_VSDB && USE_WFA_CERT_CONF */
+
+static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info,
+ enum wl_status state, bool set)
+{
+ s32 pm = PM_FAST;
+ s32 err = BCME_OK;
+ u32 mode;
+ u32 chan = 0;
+ struct net_device *primary_dev = bcmcfg_to_prmry_ndev(cfg);
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+ if (dhd->busstate == DHD_BUS_DOWN) {
+ WL_ERR(("%s : busstate is DHD_BUS_DOWN!\n", __FUNCTION__));
+ return 0;
+ }
+ WL_DBG(("Enter state %d set %d _net_info->pm_restore %d iface %s\n",
+ state, set, _net_info->pm_restore, _net_info->ndev->name));
+
+ if (state != WL_STATUS_CONNECTED)
+ return 0;
+ mode = wl_get_mode_by_netdev(cfg, _net_info->ndev);
+ if (set) {
+ wl_cfg80211_concurrent_roam(cfg, 1);
+ wl_cfg80211_determine_vsdb_mode(cfg);
+ if (mode == WL_MODE_AP) {
+ if (wl_add_remove_eventmsg(primary_dev, WLC_E_P2P_PROBREQ_MSG, false))
+ WL_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
+ }
+
+ pm = PM_OFF;
+ if ((err = wldev_ioctl(_net_info->ndev, WLC_SET_PM, &pm,
+ sizeof(pm), true)) != 0) {
+ if (err == -ENODEV)
+ WL_DBG(("%s:netdev not ready\n",
+ _net_info->ndev->name));
+ else
+ WL_ERR(("%s:error (%d)\n",
+ _net_info->ndev->name, err));
+
+ wl_cfg80211_update_power_mode(_net_info->ndev);
+ }
+ wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_SHORT);
+#if defined(WLTDLS)
+ if (wl_cfg80211_is_concurrent_mode(cfg)) {
+ err = wldev_iovar_setint(primary_dev, "tdls_enable", 0);
+ }
+#endif /* defined(WLTDLS) */
+
+#ifdef DISABLE_FRAMEBURST_VSDB
+#ifdef USE_WFA_CERT_CONF
+ if (g_frameburst)
+#endif /* USE_WFA_CERT_CONF */
+ {
+ if (wl_cfg80211_is_concurrent_mode(cfg)) {
+ int frameburst = 0;
+ if (wldev_ioctl(primary_dev, WLC_SET_FAKEFRAG, &frameburst,
+ sizeof(frameburst), true) != 0) {
+ WL_DBG(("frameburst set error\n"));
+ }
+ WL_DBG(("Frameburst Disabled\n"));
+ }
+ }
+#endif /* DISABLE_FRAMEBURST_VSDB */
+ } else { /* clear */
+ chan = 0;
+ /* clear chan information when the net device is disconnected */
+ wl_update_prof(cfg, _net_info->ndev, NULL, &chan, WL_PROF_CHAN);
+ wl_cfg80211_determine_vsdb_mode(cfg);
+ if (primary_dev == _net_info->ndev) {
+ pm = PM_FAST;
+ if ((err = wldev_ioctl(_net_info->ndev, WLC_SET_PM, &pm,
+ sizeof(pm), true)) != 0) {
+ if (err == -ENODEV)
+ WL_DBG(("%s:netdev not ready\n",
+ _net_info->ndev->name));
+ else
+ WL_ERR(("%s:error (%d)\n",
+ _net_info->ndev->name, err));
+
+ wl_cfg80211_update_power_mode(_net_info->ndev);
+ }
+ }
+
+ wl_cfg80211_concurrent_roam(cfg, 0);
+#if defined(WLTDLS)
+ if (!wl_cfg80211_is_concurrent_mode(cfg)) {
+ err = wldev_iovar_setint(primary_dev, "tdls_enable", 1);
+ }
+#endif /* defined(WLTDLS) */
+
+#ifdef DISABLE_FRAMEBURST_VSDB
+#ifdef USE_WFA_CERT_CONF
+ if (g_frameburst)
+#endif /* USE_WFA_CERT_CONF */
+ {
+ int frameburst = 1;
+ if (wldev_ioctl(primary_dev, WLC_SET_FAKEFRAG, &frameburst,
+ sizeof(frameburst), true) != 0) {
+ WL_DBG(("frameburst set error\n"));
+ }
+ WL_DBG(("Frameburst Enabled\n"));
+ }
+#endif /* DISABLE_FRAMEBURST_VSDB */
+ }
+ return err;
+}
+static s32 wl_init_scan(struct bcm_cfg80211 *cfg)
+{
+ int err = 0;
+
+ cfg->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler;
+ cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+ wl_escan_init_sync_id(cfg);
+
+ /* Init scan_timeout timer */
+ init_timer(&cfg->scan_timeout);
+ cfg->scan_timeout.data = (unsigned long) cfg;
+ cfg->scan_timeout.function = wl_scan_timeout;
+
+ return err;
+}
+
+#ifdef DHD_LOSSLESS_ROAMING
+static s32 wl_init_roam_timeout(struct bcm_cfg80211 *cfg)
+{
+ int err = 0;
+
+ /* Init roam timer */
+ init_timer(&cfg->roam_timeout);
+ cfg->roam_timeout.data = (unsigned long) cfg;
+ cfg->roam_timeout.function = wl_roam_timeout;
+
+ return err;
+}
+#endif /* DHD_LOSSLESS_ROAMING */
+
+static s32 wl_init_priv(struct bcm_cfg80211 *cfg)
+{
+ struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ s32 err = 0;
+
+ cfg->scan_request = NULL;
+ cfg->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
+ cfg->roam_on = false;
+ cfg->active_scan = true;
+ cfg->rf_blocked = false;
+ cfg->vsdb_mode = false;
+#if defined(BCMSDIO)
+ cfg->wlfc_on = false;
+#endif
+ cfg->roamoff_on_concurrent = true;
+ cfg->disable_roam_event = false;
+ /* register interested state */
+ set_bit(WL_STATUS_CONNECTED, &cfg->interrested_state);
+ spin_lock_init(&cfg->cfgdrv_lock);
+ mutex_init(&cfg->ioctl_buf_sync);
+ init_waitqueue_head(&cfg->netif_change_event);
+ init_completion(&cfg->send_af_done);
+ init_completion(&cfg->iface_disable);
+ wl_init_eq(cfg);
+ err = wl_init_priv_mem(cfg);
+ if (err)
+ return err;
+ if (wl_create_event_handler(cfg))
+ return -ENOMEM;
+ wl_init_event_handler(cfg);
+ mutex_init(&cfg->usr_sync);
+ mutex_init(&cfg->event_sync);
+ mutex_init(&cfg->scan_complete);
+ err = wl_init_scan(cfg);
+ if (err)
+ return err;
+#ifdef DHD_LOSSLESS_ROAMING
+ err = wl_init_roam_timeout(cfg);
+ if (err) {
+ return err;
+ }
+#endif /* DHD_LOSSLESS_ROAMING */
+ wl_init_conf(cfg->conf);
+ wl_init_prof(cfg, ndev);
+ wl_link_down(cfg);
+ DNGL_FUNC(dhd_cfg80211_init, (cfg));
+
+ return err;
+}
+
+static void wl_deinit_priv(struct bcm_cfg80211 *cfg)
+{
+ DNGL_FUNC(dhd_cfg80211_deinit, (cfg));
+ if (cfg->event_workq)
+ wl_destroy_event_handler(cfg);
+ wl_flush_eq(cfg);
+ wl_link_down(cfg);
+ del_timer_sync(&cfg->scan_timeout);
+#ifdef DHD_LOSSLESS_ROAMING
+ del_timer_sync(&cfg->roam_timeout);
+#endif
+ wl_deinit_priv_mem(cfg);
+ if (wl_cfg80211_netdev_notifier_registered) {
+ wl_cfg80211_netdev_notifier_registered = FALSE;
+ unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier);
+ }
+}
+
+#if defined(WL_ENABLE_P2P_IF)
+static s32 wl_cfg80211_attach_p2p(struct bcm_cfg80211 *cfg)
+{
+ WL_TRACE(("Enter \n"));
+
+ if (wl_cfgp2p_register_ndev(cfg) < 0) {
+ WL_ERR(("P2P attach failed. \n"));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static s32 wl_cfg80211_detach_p2p(struct bcm_cfg80211 *cfg)
+{
+ struct wireless_dev *wdev;
+
+ WL_DBG(("Enter \n"));
+ if (!cfg) {
+ WL_ERR(("Invalid Ptr\n"));
+ return -EINVAL;
+ }
+ else {
+ wdev = cfg->p2p_wdev;
+ if (!wdev) {
+ WL_ERR(("Invalid Ptr\n"));
+ return -EINVAL;
+ }
+ }
+
+ wl_cfgp2p_unregister_ndev(cfg);
+
+ cfg->p2p_wdev = NULL;
+ cfg->p2p_net = NULL;
+ WL_DBG(("Freeing 0x%p \n", wdev));
+ kfree(wdev);
+
+ return 0;
+}
+#endif
+
+s32 wl_cfg80211_attach_post(struct net_device *ndev)
+{
+ struct bcm_cfg80211 * cfg = NULL;
+ s32 err = 0;
+ s32 ret = 0;
+ WL_TRACE(("In\n"));
+ if (unlikely(!ndev)) {
+ WL_ERR(("ndev is invaild\n"));
+ return -ENODEV;
+ }
+ cfg = NETDEV_GET_CFG80211_PRIV(ndev);
+ if (unlikely(!cfg)) {
+ WL_ERR(("cfg is invaild\n"));
+ return -EINVAL;
+ }
+ if (!wl_get_drv_status(cfg, READY, ndev)) {
+ if (cfg->wdev) {
+ ret = wl_cfgp2p_supported(cfg, ndev);
+ if (ret > 0) {
+#if !defined(WL_ENABLE_P2P_IF)
+ cfg->wdev->wiphy->interface_modes |=
+ (BIT(NL80211_IFTYPE_P2P_CLIENT)|
+ BIT(NL80211_IFTYPE_P2P_GO));
+#endif /* !WL_ENABLE_P2P_IF */
+ if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
+ goto fail;
+
+#if defined(WL_ENABLE_P2P_IF)
+ if (cfg->p2p_net) {
+ /* Update MAC addr for p2p0 interface here. */
+ memcpy(cfg->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN);
+ cfg->p2p_net->dev_addr[0] |= 0x02;
+ WL_ERR(("%s: p2p_dev_addr="MACDBG "\n",
+ cfg->p2p_net->name,
+ MAC2STRDBG(cfg->p2p_net->dev_addr)));
+ } else {
+ WL_ERR(("p2p_net not yet populated."
+ " Couldn't update the MAC Address for p2p0 \n"));
+ return -ENODEV;
+ }
+#endif /* WL_ENABLE_P2P_IF */
+ cfg->p2p_supported = true;
+ } else if (ret == 0) {
+ if ((err = wl_cfgp2p_init_priv(cfg)) != 0)
+ goto fail;
+ } else {
+ /* SDIO bus timeout */
+ err = -ENODEV;
+ goto fail;
+ }
+ }
+ }
+ wl_set_drv_status(cfg, READY, ndev);
+fail:
+ return err;
+}
+
+void *wl_cfg80211_attach(struct net_device *ndev, void *context)
+{
+ struct wireless_dev *wdev;
+ struct bcm_cfg80211 *cfg = NULL;
+ s32 err = 0;
+ struct device *dev;
+
+ WL_TRACE(("In\n"));
+ if (!ndev) {
+ WL_ERR(("ndev is invaild\n"));
+ return NULL;
+ }
+ WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev()));
+ dev = wl_cfg80211_get_parent_dev();
+
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (unlikely(!wdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ return cfg;
+ }
+ err = wl_setup_wiphy(wdev, dev, context);
+ if (unlikely(err)) {
+ kfree(wdev);
+ return cfg;
+ }
+ wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
+ cfg = (struct bcm_cfg80211 *)wiphy_priv(wdev->wiphy);
+ cfg->wdev = wdev;
+ cfg->pub = context;
+ INIT_LIST_HEAD(&cfg->net_list);
+ spin_lock_init(&cfg->net_list_sync);
+ ndev->ieee80211_ptr = wdev;
+ SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
+ wdev->netdev = ndev;
+ cfg->state_notifier = wl_notifier_change_state;
+ err = wl_alloc_netinfo(cfg, ndev, wdev, WL_MODE_BSS, PM_ENABLE, 0);
+ if (err) {
+ WL_ERR(("Failed to alloc net_info (%d)\n", err));
+ goto cfg80211_attach_out;
+ }
+ err = wl_init_priv(cfg);
+ if (err) {
+ WL_ERR(("Failed to init iwm_priv (%d)\n", err));
+ goto cfg80211_attach_out;
+ }
+
+ err = wl_setup_rfkill(cfg, TRUE);
+ if (err) {
+ WL_ERR(("Failed to setup rfkill %d\n", err));
+ goto cfg80211_attach_out;
+ }
+#ifdef DEBUGFS_CFG80211
+ err = wl_setup_debugfs(cfg);
+ if (err) {
+ WL_ERR(("Failed to setup debugfs %d\n", err));
+ goto cfg80211_attach_out;
+ }
+#endif
+ if (!wl_cfg80211_netdev_notifier_registered) {
+ wl_cfg80211_netdev_notifier_registered = TRUE;
+ err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier);
+ if (err) {
+ wl_cfg80211_netdev_notifier_registered = FALSE;
+ WL_ERR(("Failed to register notifierl %d\n", err));
+ goto cfg80211_attach_out;
+ }
+ }
+#if defined(COEX_DHCP)
+ cfg->btcoex_info = wl_cfg80211_btcoex_init(cfg->wdev->netdev);
+ if (!cfg->btcoex_info)
+ goto cfg80211_attach_out;
+#endif
+#if defined(SUPPORT_RANDOM_MAC_SCAN)
+ cfg->random_mac_enabled = FALSE;
+#endif /* SUPPORT_RANDOM_MAC_SCAN */
+
+#ifdef CONFIG_CFG80211_INTERNAL_REGDB
+ wdev->wiphy->reg_notifier = wl_cfg80211_reg_notifier;
+#endif /* CONFIG_CFG80211_INTERNAL_REGDB */
+
+#if defined(WL_ENABLE_P2P_IF)
+ err = wl_cfg80211_attach_p2p(cfg);
+ if (err)
+ goto cfg80211_attach_out;
+#endif
+
+ INIT_DELAYED_WORK(&cfg->pm_enable_work, wl_cfg80211_work_handler);
+ mutex_init(&cfg->pm_sync);
+
+ return cfg;
+
+cfg80211_attach_out:
+ wl_setup_rfkill(cfg, FALSE);
+ wl_free_wdev(cfg);
+ cfg = NULL;
+ return cfg;
+}
+
+void wl_cfg80211_detach(void *cfg80211_priv)
+{
+ struct bcm_cfg80211 *cfg = NULL;
+
+ cfg = (struct bcm_cfg80211 *) cfg80211_priv;
+
+ WL_TRACE(("In\n"));
+
+ wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
+
+#if defined(COEX_DHCP)
+ wl_cfg80211_btcoex_deinit();
+ cfg->btcoex_info = NULL;
+#endif
+
+ wl_setup_rfkill(cfg, FALSE);
+#ifdef DEBUGFS_CFG80211
+ wl_free_debugfs(cfg);
+#endif
+ if (cfg->p2p_supported) {
+ if (timer_pending(&cfg->p2p->listen_timer))
+ del_timer_sync(&cfg->p2p->listen_timer);
+ wl_cfgp2p_deinit_priv(cfg);
+ }
+
+ if (timer_pending(&cfg->scan_timeout))
+ del_timer_sync(&cfg->scan_timeout);
+#ifdef DHD_LOSSLESS_ROAMING
+ if (timer_pending(&cfg->roam_timeout)) {
+ del_timer_sync(&cfg->roam_timeout);
+ }
+#endif /* DHD_LOSSLESS_ROAMING */
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ if (cfg->p2p_wdev)
+ wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+#if defined(WL_ENABLE_P2P_IF)
+ wl_cfg80211_detach_p2p(cfg);
+#endif
+
+ wl_cfg80211_ibss_vsie_free(cfg);
+ wl_cfg80211_clear_mgmt_vndr_ies(cfg);
+ wl_deinit_priv(cfg);
+ wl_cfg80211_clear_parent_dev();
+ wl_free_wdev(cfg);
+ /* PLEASE do NOT call any function after wl_free_wdev, the driver's private
+ * structure "cfg", which is the private part of wiphy, has been freed in
+ * wl_free_wdev !!!!!!!!!!!
+ */
+}
+
+static void wl_event_handler(struct work_struct *work_data)
+{
+ struct bcm_cfg80211 *cfg = NULL;
+ struct wl_event_q *e;
+ struct wireless_dev *wdev = NULL;
+
+ WL_DBG(("Enter \n"));
+ BCM_SET_CONTAINER_OF(cfg, work_data, struct bcm_cfg80211, event_work);
+ DHD_EVENT_WAKE_LOCK(cfg->pub);
+ while ((e = wl_deq_event(cfg))) {
+ WL_DBG(("event type (%d), ifidx: %d bssidx: %d \n",
+ e->etype, e->emsg.ifidx, e->emsg.bsscfgidx));
+
+ if (e->emsg.ifidx > WL_MAX_IFS) {
+ WL_ERR((" Event ifidx not in range. val:%d \n", e->emsg.ifidx));
+ goto fail;
+ }
+
+ if (!(wdev = wl_get_wdev_by_bssidx(cfg, e->emsg.bsscfgidx))) {
+ /* For WLC_E_IF would be handled by wl_host_event */
+ if (e->etype != WLC_E_IF)
+ WL_ERR(("No wdev corresponding to bssidx: 0x%x found!"
+ " Ignoring event.\n", e->emsg.bsscfgidx));
+ } else if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) {
+ dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub);
+ if (dhd->busstate == DHD_BUS_DOWN) {
+ WL_ERR((": BUS is DOWN.\n"));
+ } else {
+#ifdef DHD_IFDEBUG
+ if (cfg->iface_cnt == 0) {
+ wl_dump_ifinfo(cfg);
+ }
+#endif
+ cfg->evt_handler[e->etype](cfg, wdev_to_cfgdev(wdev),
+ &e->emsg, e->edata);
+ }
+ } else {
+ WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
+ }
+fail:
+ wl_put_event(e);
+ }
+ DHD_EVENT_WAKE_UNLOCK(cfg->pub);
+}
+
+void
+wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
+{
+ u32 event_type = ntoh32(e->event_type);
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(ndev);
+ struct net_info *netinfo;
+
+#if (WL_DBG_LEVEL > 0)
+ s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ?
+ wl_dbg_estr[event_type] : (s8 *) "Unknown";
+ WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr));
+#endif /* (WL_DBG_LEVEL > 0) */
+
+ if ((cfg == NULL) || (cfg->p2p_supported && cfg->p2p == NULL)) {
+ WL_ERR(("Stale event ignored\n"));
+ return;
+ }
+
+ if (cfg->event_workq == NULL) {
+ WL_ERR(("Event handler is not created\n"));
+ return;
+ }
+
+ if (wl_get_p2p_status(cfg, IF_CHANGING) || wl_get_p2p_status(cfg, IF_ADDING)) {
+ WL_ERR(("during IF change, ignore event %d\n", event_type));
+ return;
+ }
+
+#ifdef DHD_IFDEBUG
+ if (event_type != WLC_E_ESCAN_RESULT) {
+ WL_ERR(("Event_type %d , status : %d, reason : %d, bssidx:%d \n",
+ event_type, ntoh32(e->status), ntoh32(e->reason), e->bsscfgidx));
+ }
+#endif
+ netinfo = wl_get_netinfo_by_bssidx(cfg, e->bsscfgidx);
+ if (!netinfo) {
+ /* Since the netinfo entry is not there, the netdev entry is not
+ * created via cfg80211 interface. so the event is not of interest
+ * to the cfg80211 layer.
+ */
+ WL_ERR(("ignore event %d, not interested\n", event_type));
+ return;
+ }
+
+ if (event_type == WLC_E_PFN_NET_FOUND) {
+ WL_DBG((" PNOEVENT: PNO_NET_FOUND\n"));
+ }
+ else if (event_type == WLC_E_PFN_NET_LOST) {
+ WL_DBG((" PNOEVENT: PNO_NET_LOST\n"));
+ }
+
+ if (likely(!wl_enq_event(cfg, ndev, event_type, e, data))) {
+ if (cfg->event_workq) {
+ queue_work(cfg->event_workq, &cfg->event_work);
+ }
+ }
+}
+
+static void wl_init_eq(struct bcm_cfg80211 *cfg)
+{
+ wl_init_eq_lock(cfg);
+ INIT_LIST_HEAD(&cfg->eq_list);
+}
+
+static void wl_flush_eq(struct bcm_cfg80211 *cfg)
+{
+ struct wl_event_q *e;
+ unsigned long flags;
+
+ flags = wl_lock_eq(cfg);
+ while (!list_empty_careful(&cfg->eq_list)) {
+ BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
+ list_del(&e->eq_list);
+ kfree(e);
+ }
+ wl_unlock_eq(cfg, flags);
+}
+
+/*
+* retrieve first queued event from head
+*/
+
+static struct wl_event_q *wl_deq_event(struct bcm_cfg80211 *cfg)
+{
+ struct wl_event_q *e = NULL;
+ unsigned long flags;
+
+ flags = wl_lock_eq(cfg);
+ if (likely(!list_empty(&cfg->eq_list))) {
+ BCM_SET_LIST_FIRST_ENTRY(e, &cfg->eq_list, struct wl_event_q, eq_list);
+ list_del(&e->eq_list);
+ }
+ wl_unlock_eq(cfg, flags);
+
+ return e;
+}
+
+/*
+ * push event to tail of the queue
+ */
+
+static s32
+wl_enq_event(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 event,
+ const wl_event_msg_t *msg, void *data)
+{
+ struct wl_event_q *e;
+ s32 err = 0;
+ uint32 evtq_size;
+ uint32 data_len;
+ unsigned long flags;
+ gfp_t aflags;
+
+ data_len = 0;
+ if (data)
+ data_len = ntoh32(msg->datalen);
+ evtq_size = sizeof(struct wl_event_q) + data_len;
+ aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
+ e = kzalloc(evtq_size, aflags);
+ if (unlikely(!e)) {
+ WL_ERR(("event alloc failed\n"));
+ return -ENOMEM;
+ }
+ e->etype = event;
+ memcpy(&e->emsg, msg, sizeof(wl_event_msg_t));
+ if (data)
+ memcpy(e->edata, data, data_len);
+ flags = wl_lock_eq(cfg);
+ list_add_tail(&e->eq_list, &cfg->eq_list);
+ wl_unlock_eq(cfg, flags);
+
+ return err;
+}
+
+static void wl_put_event(struct wl_event_q *e)
+{
+ kfree(e);
+}
+
+static s32 wl_config_ifmode(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 iftype)
+{
+ s32 infra = 0;
+ s32 err = 0;
+ s32 mode = 0;
+ switch (iftype) {
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_WDS:
+ WL_ERR(("type (%d) : currently we do not support this mode\n",
+ iftype));
+ err = -EINVAL;
+ return err;
+ case NL80211_IFTYPE_ADHOC:
+ mode = WL_MODE_IBSS;
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ mode = WL_MODE_BSS;
+ infra = 1;
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ mode = WL_MODE_AP;
+ infra = 1;
+ break;
+ default:
+ err = -EINVAL;
+ WL_ERR(("invalid type (%d)\n", iftype));
+ return err;
+ }
+ infra = htod32(infra);
+ err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true);
+ if (unlikely(err)) {
+ WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
+ return err;
+ }
+
+ wl_set_mode_by_netdev(cfg, ndev, mode);
+
+ return 0;
+}
+
+void wl_cfg80211_add_to_eventbuffer(struct wl_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 {
+ WL_ERR(("evenbuffer doesn't support > %u events. Update"
+ " the define MAX_EVENT_BUF_NUM \n", MAX_EVENT_BUF_NUM));
+ ASSERT(0);
+ }
+}
+
+s32 wl_cfg80211_apply_eventbuffer(
+ struct net_device *ndev,
+ struct bcm_cfg80211 *cfg,
+ wl_eventmsg_buf_t *ev)
+{
+ char eventmask[WL_EVENTING_MASK_LEN];
+ int i, ret = 0;
+ s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
+
+ if (!ev || (!ev->num))
+ return -EINVAL;
+
+ mutex_lock(&cfg->event_sync);
+
+ /* Read event_msgs mask */
+ bcm_mkiovar("event_msgs", NULL, 0, iovbuf,
+ sizeof(iovbuf));
+ ret = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false);
+ if (unlikely(ret)) {
+ WL_ERR(("Get event_msgs error (%d)\n", ret));
+ goto exit;
+ }
+ memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
+
+ /* 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 */
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
+ sizeof(iovbuf));
+ ret = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+ if (unlikely(ret)) {
+ WL_ERR(("Set event_msgs error (%d)\n", ret));
+ }
+
+exit:
+ mutex_unlock(&cfg->event_sync);
+ return ret;
+}
+
+s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
+{
+ s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
+ s8 eventmask[WL_EVENTING_MASK_LEN];
+ s32 err = 0;
+ struct bcm_cfg80211 *cfg = NULL;
+
+ if (!ndev)
+ return -ENODEV;
+
+ cfg = NETDEV_GET_CFG80211_PRIV(ndev);
+ if (!cfg)
+ return -ENODEV;
+
+ mutex_lock(&cfg->event_sync);
+
+ /* Setup event_msgs */
+ bcm_mkiovar("event_msgs", NULL, 0, iovbuf,
+ sizeof(iovbuf));
+ err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false);
+ if (unlikely(err)) {
+ WL_ERR(("Get event_msgs error (%d)\n", err));
+ goto eventmsg_out;
+ }
+ memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
+ if (add) {
+ setbit(eventmask, event);
+ } else {
+ clrbit(eventmask, event);
+ }
+ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
+ sizeof(iovbuf));
+ err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+ if (unlikely(err)) {
+ WL_ERR(("Set event_msgs error (%d)\n", err));
+ goto eventmsg_out;
+ }
+
+eventmsg_out:
+ mutex_unlock(&cfg->event_sync);
+ return err;
+}
+
+static int wl_construct_reginfo(struct bcm_cfg80211 *cfg, s32 bw_cap)
+{
+ struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
+ struct ieee80211_channel *band_chan_arr = NULL;
+ wl_uint32_list_t *list;
+ u32 i, j, index, n_2g, n_5g, band, channel, array_size;
+ u32 *n_cnt = NULL;
+ chanspec_t c = 0;
+ s32 err = BCME_OK;
+ bool update;
+ bool ht40_allowed;
+ u8 *pbuf = NULL;
+ bool dfs_radar_disabled = FALSE;
+
+#define LOCAL_BUF_LEN 1024
+ pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL);
+
+ if (pbuf == NULL) {
+ WL_ERR(("failed to allocate local buf\n"));
+ return -ENOMEM;
+ }
+ list = (wl_uint32_list_t *)(void *)pbuf;
+ list->count = htod32(WL_NUMCHANSPECS);
+
+
+ err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
+ 0, pbuf, LOCAL_BUF_LEN, 0, &cfg->ioctl_buf_sync);
+ if (err != 0) {
+ WL_ERR(("get chanspecs failed with %d\n", err));
+ kfree(pbuf);
+ return err;
+ }
+#undef LOCAL_BUF_LEN
+
+ list = (wl_uint32_list_t *)(void *)pbuf;
+ band = array_size = n_2g = n_5g = 0;
+ for (i = 0; i < dtoh32(list->count); i++) {
+ index = 0;
+ update = false;
+ ht40_allowed = false;
+ c = (chanspec_t)dtoh32(list->element[i]);
+ c = wl_chspec_driver_to_host(c);
+ channel = wf_chspec_ctlchan(c);
+
+ if (!CHSPEC_IS40(c) && ! CHSPEC_IS20(c)) {
+ WL_DBG(("HT80/160/80p80 center channel : %d\n", channel));
+ continue;
+ }
+ if (CHSPEC_IS2G(c) && (channel >= CH_MIN_2G_CHANNEL) &&
+ (channel <= CH_MAX_2G_CHANNEL)) {
+ band_chan_arr = __wl_2ghz_channels;
+ array_size = ARRAYSIZE(__wl_2ghz_channels);
+ n_cnt = &n_2g;
+ band = IEEE80211_BAND_2GHZ;
+ ht40_allowed = (bw_cap == WLC_N_BW_40ALL)? true : false;
+ } else if (CHSPEC_IS5G(c) && channel >= CH_MIN_5G_CHANNEL) {
+ band_chan_arr = __wl_5ghz_a_channels;
+ array_size = ARRAYSIZE(__wl_5ghz_a_channels);
+ n_cnt = &n_5g;
+ band = IEEE80211_BAND_5GHZ;
+ ht40_allowed = (bw_cap == WLC_N_BW_20ALL)? false : true;
+ } else {
+ WL_ERR(("Invalid channel Sepc. 0x%x.\n", c));
+ continue;
+ }
+ if (!ht40_allowed && CHSPEC_IS40(c))
+ continue;
+ for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
+ if (band_chan_arr[j].hw_value == channel) {
+ update = true;
+ break;
+ }
+ }
+ if (update)
+ index = j;
+ else
+ index = *n_cnt;
+ if (index < array_size) {
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
+ band_chan_arr[index].center_freq =
+ ieee80211_channel_to_frequency(channel);
+#else
+ band_chan_arr[index].center_freq =
+ ieee80211_channel_to_frequency(channel, band);
+#endif
+ band_chan_arr[index].hw_value = channel;
+
+ if (CHSPEC_IS40(c) && ht40_allowed) {
+ /* assuming the order is HT20, HT40 Upper,
+ * HT40 lower from chanspecs
+ */
+ u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40;
+ if (CHSPEC_SB_UPPER(c)) {
+ if (ht40_flag == IEEE80211_CHAN_NO_HT40)
+ band_chan_arr[index].flags &=
+ ~IEEE80211_CHAN_NO_HT40;
+ band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS;
+ } else {
+ /* It should be one of
+ * IEEE80211_CHAN_NO_HT40 or IEEE80211_CHAN_NO_HT40PLUS
+ */
+ band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
+ if (ht40_flag == IEEE80211_CHAN_NO_HT40)
+ band_chan_arr[index].flags |=
+ IEEE80211_CHAN_NO_HT40MINUS;
+ }
+ } else {
+ band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40;
+ if (!dfs_radar_disabled) {
+ if (band == IEEE80211_BAND_2GHZ)
+ channel |= WL_CHANSPEC_BAND_2G;
+ else
+ channel |= WL_CHANSPEC_BAND_5G;
+ channel |= WL_CHANSPEC_BW_20;
+ channel = wl_chspec_host_to_driver(channel);
+ err = wldev_iovar_getint(dev, "per_chan_info", &channel);
+ if (!err) {
+ if (channel & WL_CHAN_RADAR) {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
+ band_chan_arr[index].flags |=
+ (IEEE80211_CHAN_RADAR
+ | IEEE80211_CHAN_NO_IBSS);
+#else
+ band_chan_arr[index].flags |=
+ IEEE80211_CHAN_RADAR;
+#endif
+ }
+
+ if (channel & WL_CHAN_PASSIVE)
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
+ band_chan_arr[index].flags |=
+ IEEE80211_CHAN_PASSIVE_SCAN;
+#else
+ band_chan_arr[index].flags |=
+ IEEE80211_CHAN_NO_IR;
+#endif
+ } else if (err == BCME_UNSUPPORTED) {
+ dfs_radar_disabled = TRUE;
+ WL_ERR(("does not support per_chan_info\n"));
+ }
+ }
+ }
+ if (!update)
+ (*n_cnt)++;
+ }
+
+ }
+ __wl_band_2ghz.n_channels = n_2g;
+ __wl_band_5ghz_a.n_channels = n_5g;
+ kfree(pbuf);
+ return err;
+}
+
+s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify, bool user_sync)
+{
+ struct wiphy *wiphy;
+ struct net_device *dev;
+ u32 bandlist[3];
+ u32 nband = 0;
+ u32 i = 0;
+ s32 err = 0;
+ s32 index = 0;
+ s32 nmode = 0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ u32 j = 0;
+ s32 vhtmode = 0;
+ s32 txstreams = 0;
+ s32 rxstreams = 0;
+ s32 ldpc_cap = 0;
+ s32 stbc_rx = 0;
+ s32 stbc_tx = 0;
+ s32 txbf_bfe_cap = 0;
+ s32 txbf_bfr_cap = 0;
+#endif
+ s32 bw_cap = 0;
+ s32 cur_band = -1;
+ struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS] = {NULL, };
+
+ if (user_sync == true) {
+ mutex_lock(&cfg->usr_sync);
+ }
+ dev = bcmcfg_to_prmry_ndev(cfg);
+
+ memset(bandlist, 0, sizeof(bandlist));
+ err = wldev_ioctl(dev, WLC_GET_BANDLIST, bandlist,
+ sizeof(bandlist), false);
+ if (unlikely(err)) {
+ WL_ERR(("error read bandlist (%d)\n", err));
+ goto end_bands;
+ }
+ err = wldev_ioctl(dev, WLC_GET_BAND, &cur_band,
+ sizeof(s32), false);
+ if (unlikely(err)) {
+ WL_ERR(("error (%d)\n", err));
+ goto end_bands;
+ }
+
+ err = wldev_iovar_getint(dev, "nmode", &nmode);
+ if (unlikely(err)) {
+ WL_ERR(("error reading nmode (%d)\n", err));
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ err = wldev_iovar_getint(dev, "vhtmode", &vhtmode);
+ if (unlikely(err)) {
+ WL_ERR(("error reading vhtmode (%d)\n", err));
+ }
+
+ if (vhtmode) {
+ err = wldev_iovar_getint(dev, "txstreams", &txstreams);
+ if (unlikely(err)) {
+ WL_ERR(("error reading txstreams (%d)\n", err));
+ }
+
+ err = wldev_iovar_getint(dev, "rxstreams", &rxstreams);
+ if (unlikely(err)) {
+ WL_ERR(("error reading rxstreams (%d)\n", err));
+ }
+
+ err = wldev_iovar_getint(dev, "ldpc_cap", &ldpc_cap);
+ if (unlikely(err)) {
+ WL_ERR(("error reading ldpc_cap (%d)\n", err));
+ }
+
+ err = wldev_iovar_getint(dev, "stbc_rx", &stbc_rx);
+ if (unlikely(err)) {
+ WL_ERR(("error reading stbc_rx (%d)\n", err));
+ }
+
+ err = wldev_iovar_getint(dev, "stbc_tx", &stbc_tx);
+ if (unlikely(err)) {
+ WL_ERR(("error reading stbc_tx (%d)\n", err));
+ }
+
+ err = wldev_iovar_getint(dev, "txbf_bfe_cap", &txbf_bfe_cap);
+ if (unlikely(err)) {
+ WL_ERR(("error reading txbf_bfe_cap (%d)\n", err));
+ }
+
+ err = wldev_iovar_getint(dev, "txbf_bfr_cap", &txbf_bfr_cap);
+ if (unlikely(err)) {
+ WL_ERR(("error reading txbf_bfr_cap (%d)\n", err));
+ }
+ }
+#endif
+
+ /* For nmode and vhtmode check bw cap */
+ if (nmode ||
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ vhtmode ||
+#endif
+ 0) {
+ err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
+ if (unlikely(err)) {
+ WL_ERR(("error get mimo_bw_cap (%d)\n", err));
+ }
+ }
+
+ err = wl_construct_reginfo(cfg, bw_cap);
+ if (err) {
+ WL_ERR(("wl_construct_reginfo() fails err=%d\n", err));
+ if (err != BCME_UNSUPPORTED)
+ goto end_bands;
+ err = 0;
+ }
+ wiphy = bcmcfg_to_wiphy(cfg);
+ nband = bandlist[0];
+
+ for (i = 1; i <= nband && i < ARRAYSIZE(bandlist); i++) {
+ index = -1;
+ if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) {
+ bands[IEEE80211_BAND_5GHZ] =
+ &__wl_band_5ghz_a;
+ index = IEEE80211_BAND_5GHZ;
+ if (nmode && (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G))
+ bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
+ /* VHT capabilities. */
+ if (vhtmode) {
+ /* Supported */
+ bands[index]->vht_cap.vht_supported = TRUE;
+
+ for (j = 1; j <= VHT_CAP_MCS_MAP_NSS_MAX; j++) {
+ /* TX stream rates. */
+ if (j <= txstreams) {
+ VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
+ bands[index]->vht_cap.vht_mcs.tx_mcs_map);
+ } else {
+ VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
+ bands[index]->vht_cap.vht_mcs.tx_mcs_map);
+ }
+
+ /* RX stream rates. */
+ if (j <= rxstreams) {
+ VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_0_9,
+ bands[index]->vht_cap.vht_mcs.rx_mcs_map);
+ } else {
+ VHT_MCS_MAP_SET_MCS_PER_SS(j, VHT_CAP_MCS_MAP_NONE,
+ bands[index]->vht_cap.vht_mcs.rx_mcs_map);
+ }
+ }
+
+
+ /* Capabilities */
+ /* 80 MHz is mandatory */
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_SHORT_GI_80;
+
+ if (WL_BW_CAP_160MHZ(bw_cap)) {
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_SHORT_GI_160;
+ }
+
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
+
+ if (ldpc_cap)
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_RXLDPC;
+
+ if (stbc_tx)
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_TXSTBC;
+
+ if (stbc_rx)
+ bands[index]->vht_cap.cap |=
+ (stbc_rx << VHT_CAP_INFO_RX_STBC_SHIFT);
+
+ if (txbf_bfe_cap)
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
+
+ if (txbf_bfr_cap) {
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
+ }
+
+ if (txbf_bfe_cap || txbf_bfr_cap) {
+ bands[index]->vht_cap.cap |=
+ (2 << VHT_CAP_INFO_NUM_BMFMR_ANT_SHIFT);
+ bands[index]->vht_cap.cap |=
+ ((txstreams - 1) <<
+ VHT_CAP_INFO_NUM_SOUNDING_DIM_SHIFT);
+ bands[index]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
+ }
+
+ /* AMPDU length limit, support max 1MB (2 ^ (13 + 7)) */
+ bands[index]->vht_cap.cap |=
+ (7 << VHT_CAP_INFO_AMPDU_MAXLEN_EXP_SHIFT);
+ WL_INFORM(("%s band[%d] vht_enab=%d vht_cap=%08x "
+ "vht_rx_mcs_map=%04x vht_tx_mcs_map=%04x\n",
+ __FUNCTION__, index,
+ bands[index]->vht_cap.vht_supported,
+ bands[index]->vht_cap.cap,
+ bands[index]->vht_cap.vht_mcs.rx_mcs_map,
+ bands[index]->vht_cap.vht_mcs.tx_mcs_map));
+ }
+#endif
+ }
+ else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) {
+ bands[IEEE80211_BAND_2GHZ] =
+ &__wl_band_2ghz;
+ index = IEEE80211_BAND_2GHZ;
+ if (bw_cap == WLC_N_BW_40ALL)
+ bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+ }
+
+ if ((index >= 0) && nmode) {
+ bands[index]->ht_cap.cap |=
+ (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40);
+ bands[index]->ht_cap.ht_supported = TRUE;
+ bands[index]->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ bands[index]->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
+ /* An HT shall support all EQM rates for one spatial stream */
+ bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
+ }
+
+ }
+
+ wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
+ wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
+
+ /* check if any bands populated otherwise makes 2Ghz as default */
+ if (wiphy->bands[IEEE80211_BAND_2GHZ] == NULL &&
+ wiphy->bands[IEEE80211_BAND_5GHZ] == NULL) {
+ /* Setup 2Ghz band as default */
+ wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
+ }
+
+ if (notify)
+ wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
+
+ end_bands:
+ if (user_sync)
+ mutex_unlock(&cfg->usr_sync);
+ return err;
+}
+
+static s32 __wl_cfg80211_up(struct bcm_cfg80211 *cfg)
+{
+ s32 err = 0;
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
+
+ WL_DBG(("In\n"));
+
+ err = dhd_config_dongle(cfg);
+ if (unlikely(err))
+ return err;
+
+ err = wl_config_ifmode(cfg, ndev, wdev->iftype);
+ if (unlikely(err && err != -EINPROGRESS)) {
+ WL_ERR(("wl_config_ifmode failed\n"));
+ if (err == -1) {
+ WL_ERR(("return error %d\n", err));
+ return err;
+ }
+ }
+ err = wl_update_wiphybands(cfg, true, false);
+ if (unlikely(err)) {
+ WL_ERR(("wl_update_wiphybands failed\n"));
+ if (err == -1) {
+ WL_ERR(("return error %d\n", err));
+ return err;
+ }
+ }
+
+ err = wl_create_event_handler(cfg);
+ if (err) {
+ WL_ERR(("wl_create_event_handler failed\n"));
+ return err;
+ }
+ wl_init_event_handler(cfg);
+
+ err = wl_init_scan(cfg);
+ if (err) {
+ WL_ERR(("wl_init_scan failed\n"));
+ return err;
+ }
+#ifdef DHD_LOSSLESS_ROAMING
+ if (timer_pending(&cfg->roam_timeout)) {
+ del_timer_sync(&cfg->roam_timeout);
+ }
+#endif /* DHD_LOSSLESS_ROAMING */
+
+ err = dhd_monitor_init(cfg->pub);
+
+ wl_set_drv_status(cfg, READY, ndev);
+ return err;
+}
+
+static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg)
+{
+ s32 err = 0;
+ unsigned long flags;
+ struct net_info *iter, *next;
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+#if defined(WL_CFG80211) && defined(WL_ENABLE_P2P_IF)
+ struct net_device *p2p_net = cfg->p2p_net;
+#endif
+#ifdef PROP_TXSTATUS_VSDB
+#if defined(BCMSDIO)
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+#endif
+#endif /* PROP_TXSTATUS_VSDB */
+ WL_DBG(("In\n"));
+ /* Delete pm_enable_work */
+ wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
+
+#ifdef WL_NAN
+ wl_cfgnan_stop_handler(ndev, cfg, NULL, 0, NULL);
+#endif /* WL_NAN */
+
+ if (cfg->p2p_supported) {
+ wl_clr_p2p_status(cfg, GO_NEG_PHASE);
+#ifdef PROP_TXSTATUS_VSDB
+#if defined(BCMSDIO)
+ if (wl_cfgp2p_vif_created(cfg)) {
+ bool enabled = false;
+ dhd_wlfc_get_enable(dhd, &enabled);
+ if (enabled && cfg->wlfc_on && dhd->op_mode != DHD_FLAG_HOSTAP_MODE &&
+ dhd->op_mode != DHD_FLAG_IBSS_MODE) {
+ dhd_wlfc_deinit(dhd);
+ cfg->wlfc_on = false;
+ }
+ }
+#endif
+#endif /* PROP_TXSTATUS_VSDB */
+ }
+
+
+ /* If primary BSS is operational (for e.g SoftAP), bring it down */
+ if (wl_cfgp2p_bss_isup(ndev, 0)) {
+ if (wl_cfgp2p_bss(cfg, ndev, 0, 0) < 0)
+ WL_ERR(("BSS down failed \n"));
+ }
+
+ /* Check if cfg80211 interface is already down */
+ if (!wl_get_drv_status(cfg, READY, ndev))
+ return err; /* it is even not ready */
+
+ /* clear all the security setting on primary Interface */
+ wl_cfg80211_clear_security(cfg);
+
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#endif
+ for_each_ndev(cfg, iter, next) {
+ if (iter->ndev) /* p2p discovery iface is null */
+ wl_set_drv_status(cfg, SCAN_ABORTING, iter->ndev);
+ }
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic pop")
+#endif
+
+#ifdef P2P_LISTEN_OFFLOADING
+ wl_cfg80211_p2plo_deinit(cfg);
+#endif /* P2P_LISTEN_OFFLOADING */
+
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+ if (cfg->scan_request) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
+ struct cfg80211_scan_info info = {
+ .aborted = true
+ };
+ cfg80211_scan_done(cfg->scan_request, &info);
+#else
+ cfg80211_scan_done(cfg->scan_request, true);
+#endif
+ cfg->scan_request = NULL;
+ }
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#endif
+ for_each_ndev(cfg, iter, next) {
+ /* p2p discovery iface ndev ptr could be null */
+ if (iter->ndev == NULL)
+ continue;
+ wl_clr_drv_status(cfg, READY, iter->ndev);
+ wl_clr_drv_status(cfg, SCANNING, iter->ndev);
+ wl_clr_drv_status(cfg, SCAN_ABORTING, iter->ndev);
+ wl_clr_drv_status(cfg, CONNECTING, iter->ndev);
+ wl_clr_drv_status(cfg, CONNECTED, iter->ndev);
+ wl_clr_drv_status(cfg, DISCONNECTING, iter->ndev);
+ wl_clr_drv_status(cfg, AP_CREATED, iter->ndev);
+ wl_clr_drv_status(cfg, AP_CREATING, iter->ndev);
+ }
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic pop")
+#endif
+ bcmcfg_to_prmry_ndev(cfg)->ieee80211_ptr->iftype =
+ NL80211_IFTYPE_STATION;
+#if defined(WL_CFG80211) && defined(WL_ENABLE_P2P_IF)
+ if (p2p_net)
+ dev_close(p2p_net);
+#endif
+
+ /* Avoid deadlock from wl_cfg80211_down */
+ mutex_unlock(&cfg->usr_sync);
+ wl_destroy_event_handler(cfg);
+ mutex_lock(&cfg->usr_sync);
+ wl_flush_eq(cfg);
+ wl_link_down(cfg);
+ if (cfg->p2p_supported) {
+ if (timer_pending(&cfg->p2p->listen_timer))
+ del_timer_sync(&cfg->p2p->listen_timer);
+ wl_cfgp2p_down(cfg);
+ }
+
+ if (timer_pending(&cfg->scan_timeout)) {
+ del_timer_sync(&cfg->scan_timeout);
+ }
+
+ DHD_OS_SCAN_WAKE_UNLOCK((dhd_pub_t *)(cfg->pub));
+
+ dhd_monitor_uninit();
+#ifdef WLAIBSS_MCHAN
+ bcm_cfg80211_del_ibss_if(cfg->wdev->wiphy, cfg->ibss_cfgdev);
+#endif /* WLAIBSS_MCHAN */
+
+#if defined(WL_VIRTUAL_APSTA) || defined(DUAL_STA_STATIC_IF)
+ /* Delete all the pending virtual interfaces */
+ for_each_ndev(cfg, iter, next) {
+ if (iter->ndev && (iter->ndev != bcmcfg_to_prmry_ndev(cfg))) {
+ wl_cfg80211_del_iface(cfg->wdev->wiphy, ndev_to_cfgdev(iter->ndev));
+ }
+ }
+#endif /* defined (WL_VIRTUAL_APSTA) || defined (DUAL_STA_STATIC_IF) */
+
+#ifdef WL11U
+ /* Clear interworking element. */
+ wl_clear_iwdata(cfg);
+#endif /* WL11U */
+
+#ifdef CUSTOMER_HW4_DEBUG
+ if (wl_scan_timeout_dbg_enabled)
+ wl_scan_timeout_dbg_clear();
+#endif /* CUSTOMER_HW4_DEBUG */
+
+ cfg->disable_roam_event = false;
+
+ DNGL_FUNC(dhd_cfg80211_down, (cfg));
+
+#ifdef DHD_IFDEBUG
+ /* Printout all netinfo entries */
+ wl_probe_wdev_all(cfg);
+#endif /* DHD_IFDEBUG */
+
+ return err;
+}
+
+s32 wl_cfg80211_up(void *para)
+{
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)para;
+ s32 err = 0;
+ int val = 1;
+ dhd_pub_t *dhd;
+#ifdef DISABLE_PM_BCNRX
+ s32 interr = 0;
+ uint param = 0;
+ s8 iovbuf[WLC_IOCTL_SMLEN];
+#endif /* DISABLE_PM_BCNRX */
+
+ WL_DBG(("In\n"));
+
+ if ((err = wldev_ioctl(bcmcfg_to_prmry_ndev(cfg), WLC_GET_VERSION, &val,
+ sizeof(int), false) < 0)) {
+ WL_ERR(("WLC_GET_VERSION failed, err=%d\n", err));
+ return err;
+ }
+ val = dtoh32(val);
+ if (val != WLC_IOCTL_VERSION && val != 1) {
+ WL_ERR(("Version mismatch, please upgrade. Got %d, expected %d or 1\n",
+ val, WLC_IOCTL_VERSION));
+ return BCME_VERSION;
+ }
+ ioctl_version = val;
+ WL_TRACE(("WLC_GET_VERSION=%d\n", ioctl_version));
+
+ mutex_lock(&cfg->usr_sync);
+ dhd = (dhd_pub_t *)(cfg->pub);
+ if (!(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) {
+ err = wl_cfg80211_attach_post(bcmcfg_to_prmry_ndev(cfg));
+ if (unlikely(err)) {
+ mutex_unlock(&cfg->usr_sync);
+ return err;
+ }
+ }
+ err = __wl_cfg80211_up(cfg);
+ if (unlikely(err))
+ WL_ERR(("__wl_cfg80211_up failed\n"));
+
+
+
+ /* IOVAR configurations with 'up' condition */
+#ifdef DISABLE_PM_BCNRX
+ bcm_mkiovar("pm_bcnrx", (char *)&param, 4, iovbuf, sizeof(iovbuf));
+ interr = wldev_ioctl(bcmcfg_to_prmry_ndev(cfg), WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
+ if (unlikely(interr))
+ WL_ERR(("Set pm_bcnrx returned (%d)\n", interr));
+#endif /* DISABLE_PM_BCNRX */
+
+ mutex_unlock(&cfg->usr_sync);
+
+#ifdef WLAIBSS_MCHAN
+ bcm_cfg80211_add_ibss_if(cfg->wdev->wiphy, IBSS_IF_NAME);
+#endif /* WLAIBSS_MCHAN */
+
+#ifdef DUAL_STA_STATIC_IF
+#ifdef WL_VIRTUAL_APSTA
+#error "Both DUAL STA and DUAL_STA_STATIC_IF can't be enabled together"
+#endif
+ /* Static Interface support is currently supported only for STA only builds (without P2P) */
+ wl_cfg80211_create_iface(cfg->wdev->wiphy, NL80211_IFTYPE_STATION, NULL, "wlan%d");
+#endif /* DUAL_STA_STATIC_IF */
+
+ return err;
+}
+
+/* Private Event to Supplicant with indication that chip hangs */
+int wl_cfg80211_hang(struct net_device *dev, u16 reason)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ dhd_pub_t *dhd;
+#if defined(SOFTAP_SEND_HANGEVT)
+ /* specifc mac address used for hang event */
+ uint8 hang_mac[ETHER_ADDR_LEN] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
+#endif /* SOFTAP_SEND_HANGEVT */
+ if (!cfg) {
+ return BCME_ERROR;
+ }
+
+ dhd = (dhd_pub_t *)(cfg->pub);
+
+#ifdef DHD_USE_EXTENDED_HANG_REASON
+ if (dhd->hang_reason != 0) {
+ reason = dhd->hang_reason;
+ }
+#endif /* DHD_USE_EXTENDED_HANG_REASON */
+
+ WL_ERR(("In : chip crash eventing, reason=0x%x\n", (uint32)(dhd->hang_reason)));
+ wl_add_remove_pm_enable_work(cfg, WL_PM_WORKQ_DEL);
+#if defined(SOFTAP_SEND_HANGEVT)
+ if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
+ cfg80211_del_sta(dev, hang_mac, GFP_ATOMIC);
+ } else
+#endif /* SOFTAP_SEND_HANGEVT */
+ {
+ CFG80211_DISCONNECTED(dev, reason, NULL, 0, false, GFP_KERNEL);
+ }
+ if (cfg != NULL) {
+ wl_link_down(cfg);
+ }
+ return 0;
+}
+
+s32 wl_cfg80211_down(void *para)
+{
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)para;
+ s32 err = 0;
+
+ WL_DBG(("In\n"));
+ mutex_lock(&cfg->usr_sync);
+ err = __wl_cfg80211_down(cfg);
+ mutex_unlock(&cfg->usr_sync);
+
+ return err;
+}
+
+static void *wl_read_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 item)
+{
+ unsigned long flags;
+ void *rptr = NULL;
+ struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
+
+ if (!profile)
+ return NULL;
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+ switch (item) {
+ case WL_PROF_SEC:
+ rptr = &profile->sec;
+ break;
+ case WL_PROF_ACT:
+ rptr = &profile->active;
+ break;
+ case WL_PROF_BSSID:
+ rptr = profile->bssid;
+ break;
+ case WL_PROF_SSID:
+ rptr = &profile->ssid;
+ break;
+ case WL_PROF_CHAN:
+ rptr = &profile->channel;
+ break;
+ }
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+ if (!rptr)
+ WL_ERR(("invalid item (%d)\n", item));
+ return rptr;
+}
+
+static s32
+wl_update_prof(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const wl_event_msg_t *e, const void *data, s32 item)
+{
+ s32 err = 0;
+ const struct wlc_ssid *ssid;
+ unsigned long flags;
+ struct wl_profile *profile = wl_get_profile_by_netdev(cfg, ndev);
+
+ if (!profile)
+ return WL_INVALID;
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+ switch (item) {
+ case WL_PROF_SSID:
+ ssid = (const wlc_ssid_t *) data;
+ memset(profile->ssid.SSID, 0,
+ sizeof(profile->ssid.SSID));
+ profile->ssid.SSID_len = MIN(ssid->SSID_len, DOT11_MAX_SSID_LEN);
+ memcpy(profile->ssid.SSID, ssid->SSID, profile->ssid.SSID_len);
+ break;
+ case WL_PROF_BSSID:
+ if (data)
+ memcpy(profile->bssid, data, ETHER_ADDR_LEN);
+ else
+ memset(profile->bssid, 0, ETHER_ADDR_LEN);
+ break;
+ case WL_PROF_SEC:
+ memcpy(&profile->sec, data, sizeof(profile->sec));
+ break;
+ case WL_PROF_ACT:
+ profile->active = *(const bool *)data;
+ break;
+ case WL_PROF_BEACONINT:
+ profile->beacon_interval = *(const u16 *)data;
+ break;
+ case WL_PROF_DTIMPERIOD:
+ profile->dtim_period = *(const u8 *)data;
+ break;
+ case WL_PROF_CHAN:
+ profile->channel = *(const u32*)data;
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+
+ if (err == -EOPNOTSUPP)
+ WL_ERR(("unsupported item (%d)\n", item));
+
+ return err;
+}
+
+void wl_cfg80211_dbg_level(u32 level)
+{
+ /*
+ * prohibit to change debug level
+ * by insmod parameter.
+ * eventually debug level will be configured
+ * in compile time by using CONFIG_XXX
+ */
+ /* wl_dbg_level = level; */
+}
+
+static bool wl_is_ibssmode(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ return wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_IBSS;
+}
+
+static __used bool wl_is_ibssstarter(struct bcm_cfg80211 *cfg)
+{
+ return cfg->ibss_starter;
+}
+
+static void wl_rst_ie(struct bcm_cfg80211 *cfg)
+{
+ struct wl_ie *ie = wl_to_ie(cfg);
+
+ ie->offset = 0;
+}
+
+static __used s32 wl_add_ie(struct bcm_cfg80211 *cfg, u8 t, u8 l, u8 *v)
+{
+ struct wl_ie *ie = wl_to_ie(cfg);
+ s32 err = 0;
+
+ if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) {
+ WL_ERR(("ei crosses buffer boundary\n"));
+ return -ENOSPC;
+ }
+ ie->buf[ie->offset] = t;
+ ie->buf[ie->offset + 1] = l;
+ memcpy(&ie->buf[ie->offset + 2], v, l);
+ ie->offset += l + 2;
+
+ return err;
+}
+
+static void wl_update_hidden_ap_ie(struct wl_bss_info *bi, const u8 *ie_stream, u32 *ie_size,
+ bool roam)
+{
+ u8 *ssidie;
+ int32 ssid_len = MIN(bi->SSID_len, DOT11_MAX_SSID_LEN);
+ int32 remaining_ie_buf_len, available_buffer_len;
+ /* cfg80211_find_ie defined in kernel returning const u8 */
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#endif
+ ssidie = (u8 *)cfg80211_find_ie(WLAN_EID_SSID, ie_stream, *ie_size);
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic pop")
+#endif
+ /* ERROR out if
+ * 1. No ssid IE is FOUND or
+ * 2. New ssid length is > what was allocated for existing ssid (as
+ * we do not want to overwrite the rest of the IEs) or
+ * 3. If in case of erroneous buffer input where ssid length doesnt match the space
+ * allocated to it.
+ */
+ if (!ssidie) {
+ return;
+ }
+ available_buffer_len = ((int)(*ie_size)) - (ssidie + 2 - ie_stream);
+ remaining_ie_buf_len = available_buffer_len - (int)ssidie[1];
+ if ((ssid_len > ssidie[1]) ||
+ (ssidie[1] > available_buffer_len)) {
+ return;
+ }
+
+
+ if (ssidie[1] != ssid_len) {
+ if (ssidie[1]) {
+ WL_ERR(("%s: Wrong SSID len: %d != %d\n",
+ __FUNCTION__, ssidie[1], bi->SSID_len));
+ }
+ if (roam) {
+ WL_ERR(("Changing the SSID Info.\n"));
+ memmove(ssidie + ssid_len + 2,
+ (ssidie + 2) + ssidie[1],
+ remaining_ie_buf_len);
+ memcpy(ssidie + 2, bi->SSID, ssid_len);
+ *ie_size = *ie_size + ssid_len - ssidie[1];
+ ssidie[1] = ssid_len;
+ }
+ return;
+ }
+ if (*(ssidie + 2) == '\0')
+ memcpy(ssidie + 2, bi->SSID, ssid_len);
+ return;
+}
+
+static s32 wl_mrg_ie(struct bcm_cfg80211 *cfg, u8 *ie_stream, u16 ie_size)
+{
+ struct wl_ie *ie = wl_to_ie(cfg);
+ s32 err = 0;
+
+ if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) {
+ WL_ERR(("ei_stream crosses buffer boundary\n"));
+ return -ENOSPC;
+ }
+ memcpy(&ie->buf[ie->offset], ie_stream, ie_size);
+ ie->offset += ie_size;
+
+ return err;
+}
+
+static s32 wl_cp_ie(struct bcm_cfg80211 *cfg, u8 *dst, u16 dst_size)
+{
+ struct wl_ie *ie = wl_to_ie(cfg);
+ s32 err = 0;
+
+ if (unlikely(ie->offset > dst_size)) {
+ WL_ERR(("dst_size is not enough\n"));
+ return -ENOSPC;
+ }
+ memcpy(dst, &ie->buf[0], ie->offset);
+
+ return err;
+}
+
+static u32 wl_get_ielen(struct bcm_cfg80211 *cfg)
+{
+ struct wl_ie *ie = wl_to_ie(cfg);
+
+ return ie->offset;
+}
+
+static void wl_link_up(struct bcm_cfg80211 *cfg)
+{
+ cfg->link_up = true;
+}
+
+static void wl_link_down(struct bcm_cfg80211 *cfg)
+{
+ struct wl_connect_info *conn_info = wl_to_conn(cfg);
+
+ WL_DBG(("In\n"));
+ cfg->link_up = false;
+ conn_info->req_ie_len = 0;
+ conn_info->resp_ie_len = 0;
+}
+
+static unsigned long wl_lock_eq(struct bcm_cfg80211 *cfg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cfg->eq_lock, flags);
+ return flags;
+}
+
+static void wl_unlock_eq(struct bcm_cfg80211 *cfg, unsigned long flags)
+{
+ spin_unlock_irqrestore(&cfg->eq_lock, flags);
+}
+
+static void wl_init_eq_lock(struct bcm_cfg80211 *cfg)
+{
+ spin_lock_init(&cfg->eq_lock);
+}
+
+static void wl_delay(u32 ms)
+{
+ if (in_atomic() || (ms < jiffies_to_msecs(1))) {
+ OSL_DELAY(ms*1000);
+ } else {
+ OSL_SLEEP(ms);
+ }
+}
+
+s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(net);
+ struct ether_addr primary_mac;
+ if (!cfg->p2p)
+ return -1;
+ if (!p2p_is_on(cfg)) {
+ get_primary_mac(cfg, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
+ } else {
+ memcpy(p2pdev_addr->octet, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE).octet,
+ ETHER_ADDR_LEN);
+ }
+
+ return 0;
+}
+s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(net);
+
+ return wl_cfgp2p_set_p2p_noa(cfg, net, buf, len);
+}
+
+s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(net);
+
+ return wl_cfgp2p_get_p2p_noa(cfg, net, buf, len);
+}
+
+s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(net);
+
+ return wl_cfgp2p_set_p2p_ps(cfg, net, buf, len);
+}
+
+s32 wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(net);
+
+ return wl_cfgp2p_set_p2p_ecsa(cfg, net, buf, len);
+}
+
+s32 wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(net);
+
+ return wl_cfgp2p_increase_p2p_bw(cfg, net, buf, len);
+}
+
+#ifdef P2PLISTEN_AP_SAMECHN
+s32 wl_cfg80211_set_p2p_resp_ap_chn(struct net_device *net, s32 enable)
+{
+ s32 ret = wldev_iovar_setint(net, "p2p_resp_ap_chn", enable);
+
+ if ((ret == 0) && enable) {
+ /* disable PM for p2p responding on infra AP channel */
+ s32 pm = PM_OFF;
+
+ ret = wldev_ioctl(net, WLC_SET_PM, &pm, sizeof(pm), true);
+ }
+
+ return ret;
+}
+#endif /* P2PLISTEN_AP_SAMECHN */
+
+s32 wl_cfg80211_channel_to_freq(u32 channel)
+{
+ int freq = 0;
+
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
+ freq = ieee80211_channel_to_frequency(channel);
+#else
+ {
+ u16 band = 0;
+ if (channel <= CH_MAX_2G_CHANNEL)
+ band = IEEE80211_BAND_2GHZ;
+ else
+ band = IEEE80211_BAND_5GHZ;
+ freq = ieee80211_channel_to_frequency(channel, band);
+ }
+#endif
+ return freq;
+}
+
+
+#ifdef WLTDLS
+static s32
+wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data) {
+
+ struct net_device *ndev = NULL;
+ u32 reason = ntoh32(e->reason);
+ s8 *msg = NULL;
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ switch (reason) {
+ case WLC_E_TDLS_PEER_DISCOVERED :
+ msg = " TDLS PEER DISCOVERD ";
+ break;
+ case WLC_E_TDLS_PEER_CONNECTED :
+#ifdef PCIE_FULL_DONGLE
+ dhd_tdls_update_peer_info(ndev, TRUE, (uint8 *)&e->addr.octet[0]);
+#endif /* PCIE_FULL_DONGLE */
+ if (cfg->tdls_mgmt_frame) {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+ cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
+ cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
+ 0);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
+ cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
+ cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
+ 0, GFP_ATOMIC);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) || \
+ defined(WL_COMPAT_WIRELESS)
+ cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq, 0,
+ cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
+ GFP_ATOMIC);
+#else
+ cfg80211_rx_mgmt(cfgdev, cfg->tdls_mgmt_freq,
+ cfg->tdls_mgmt_frame, cfg->tdls_mgmt_frame_len,
+ GFP_ATOMIC);
+#endif /* LINUX_VERSION >= VERSION(3, 12, 0) */
+ }
+ msg = " TDLS PEER CONNECTED ";
+ break;
+ case WLC_E_TDLS_PEER_DISCONNECTED :
+#ifdef PCIE_FULL_DONGLE
+ dhd_tdls_update_peer_info(ndev, FALSE, (uint8 *)&e->addr.octet[0]);
+#endif /* PCIE_FULL_DONGLE */
+ if (cfg->tdls_mgmt_frame) {
+ kfree(cfg->tdls_mgmt_frame);
+ cfg->tdls_mgmt_frame = NULL;
+ cfg->tdls_mgmt_freq = 0;
+ }
+ msg = "TDLS PEER DISCONNECTED ";
+ break;
+ }
+ if (msg) {
+ WL_ERR(("%s: " MACDBG " on %s ndev\n", msg, MAC2STRDBG((u8*)(&e->addr)),
+ (bcmcfg_to_prmry_ndev(cfg) == ndev) ? "primary" : "secondary"));
+ }
+ return 0;
+
+}
+#endif /* WLTDLS */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 2, 0)) || defined(WL_COMPAT_WIRELESS)
+static s32
+#if (defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)) || (LINUX_VERSION_CODE < \
+ KERNEL_VERSION(3, 16, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
+wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
+ u32 peer_capability, const u8 *data, size_t len)
+#elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) && \
+ (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)))
+wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
+ u32 peer_capability, const u8 *data, size_t len)
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0))
+wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code,
+ u32 peer_capability, bool initiator, const u8 *data, size_t len)
+#else
+wl_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *data,
+ size_t len)
+#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
+{
+ s32 ret = 0;
+#ifdef WLTDLS
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
+ tdls_wfd_ie_iovar_t info;
+ memset(&info, 0, sizeof(tdls_wfd_ie_iovar_t));
+
+#if defined(CONFIG_ARCH_MSM) && defined(TDLS_MGMT_VERSION2)
+ /* Some customer platform back ported this feature from kernel 3.15 to kernel 3.10
+ * and that cuases build error
+ */
+ BCM_REFERENCE(peer_capability);
+#endif /* CONFIG_ARCH_MSM && TDLS_MGMT_VERSION2 */
+
+ switch (action_code) {
+ /* We need to set TDLS Wifi Display IE to firmware
+ * using tdls_wfd_ie iovar
+ */
+ case WLAN_TDLS_SET_PROBE_WFD_IE:
+ WL_ERR(("%s WLAN_TDLS_SET_PROBE_WFD_IE\n", __FUNCTION__));
+ info.mode = TDLS_WFD_PROBE_IE_TX;
+ memcpy(&info.data, data, len);
+ info.length = len;
+ break;
+ case WLAN_TDLS_SET_SETUP_WFD_IE:
+ WL_ERR(("%s WLAN_TDLS_SET_SETUP_WFD_IE\n", __FUNCTION__));
+ info.mode = TDLS_WFD_IE_TX;
+ memcpy(&info.data, data, len);
+ info.length = len;
+ break;
+ case WLAN_TDLS_SET_WFD_ENABLED:
+ WL_ERR(("%s WLAN_TDLS_SET_MODE_WFD_ENABLED\n", __FUNCTION__));
+ dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), true);
+ goto out;
+ case WLAN_TDLS_SET_WFD_DISABLED:
+ WL_ERR(("%s WLAN_TDLS_SET_MODE_WFD_DISABLED\n", __FUNCTION__));
+ dhd_tdls_set_mode((dhd_pub_t *)(cfg->pub), false);
+ goto out;
+ default:
+ WL_ERR(("Unsupported action code : %d\n", action_code));
+ goto out;
+ }
+
+ ret = wldev_iovar_setbuf(dev, "tdls_wfd_ie", &info, sizeof(info),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+
+ if (ret) {
+ WL_ERR(("tdls_wfd_ie error %d\n", ret));
+ }
+out:
+#endif /* WLTDLS */
+ return ret;
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
+static s32
+wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
+ const u8 *peer, enum nl80211_tdls_operation oper)
+#else
+static s32
+wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
+ u8 *peer, enum nl80211_tdls_operation oper)
+#endif
+{
+ s32 ret = 0;
+#ifdef WLTDLS
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)wiphy_priv(wiphy);
+ tdls_iovar_t info;
+ dhd_pub_t *dhdp;
+ bool tdls_auto_mode = false;
+ dhdp = (dhd_pub_t *)(cfg->pub);
+ memset(&info, 0, sizeof(tdls_iovar_t));
+ if (peer) {
+ memcpy(&info.ea, peer, ETHER_ADDR_LEN);
+ } else {
+ return -1;
+ }
+ switch (oper) {
+ case NL80211_TDLS_DISCOVERY_REQ:
+ /* If the discovery request is broadcast then we need to set
+ * info.mode to Tunneled Probe Request
+ */
+ if (memcmp(peer, (const uint8 *)BSSID_BROADCAST, ETHER_ADDR_LEN) == 0) {
+ info.mode = TDLS_MANUAL_EP_WFD_TPQ;
+ WL_ERR(("%s TDLS TUNNELED PRBOBE REQUEST\n", __FUNCTION__));
+ } else {
+ info.mode = TDLS_MANUAL_EP_DISCOVERY;
+ }
+ break;
+ case NL80211_TDLS_SETUP:
+ if (dhdp->tdls_mode == true) {
+ info.mode = TDLS_MANUAL_EP_CREATE;
+ tdls_auto_mode = false;
+ ret = dhd_tdls_enable(dev, false, tdls_auto_mode, NULL);
+ if (ret < 0) {
+ return ret;
+ }
+ } else {
+ tdls_auto_mode = true;
+ }
+ break;
+ case NL80211_TDLS_TEARDOWN:
+ info.mode = TDLS_MANUAL_EP_DELETE;
+ break;
+ default:
+ WL_ERR(("Unsupported operation : %d\n", oper));
+ goto out;
+ }
+ /* turn on TDLS */
+ ret = dhd_tdls_enable(dev, true, tdls_auto_mode, NULL);
+ if (ret < 0) {
+ return ret;
+ }
+ if (info.mode) {
+ ret = wldev_iovar_setbuf(dev, "tdls_endpoint", &info, sizeof(info),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (ret) {
+ WL_ERR(("tdls_endpoint error %d\n", ret));
+ }
+ }
+out:
+#endif /* WLTDLS */
+ return ret;
+}
+#endif /* LINUX_VERSION > VERSION(3,2,0) || WL_COMPAT_WIRELESS */
+
+s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *ndev, char *buf, int len,
+ enum wl_management_type type)
+{
+ struct bcm_cfg80211 *cfg = NULL;
+ s32 ret = 0;
+ struct ether_addr primary_mac;
+ s32 bssidx = 0;
+ s32 pktflag = 0;
+ cfg = NETDEV_GET_CFG80211_PRIV(ndev);
+
+ if (wl_get_drv_status(cfg, AP_CREATING, ndev)) {
+ /* Vendor IEs should be set to FW
+ * after SoftAP interface is brought up
+ */
+ WL_DBG(("Skipping set IE since AP is not up \n"));
+ goto exit;
+ } else if (ndev == bcmcfg_to_prmry_ndev(cfg)) {
+ /* Either stand alone AP case or P2P discovery */
+ if (wl_get_drv_status(cfg, AP_CREATED, ndev)) {
+ /* Stand alone AP case on primary interface */
+ WL_DBG(("Apply IEs for Primary AP Interface \n"));
+ bssidx = 0;
+ } else {
+ /* P2P Discovery case (p2p listen) */
+ if (!cfg->p2p->on) {
+ /* Turn on Discovery interface */
+ get_primary_mac(cfg, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
+ p2p_on(cfg) = true;
+ ret = wl_cfgp2p_enable_discovery(cfg, ndev, NULL, 0);
+ if (unlikely(ret)) {
+ WL_ERR(("Enable discovery failed \n"));
+ goto exit;
+ }
+ }
+ WL_DBG(("Apply IEs for P2P Discovery Iface \n"));
+ ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
+ bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+ }
+ } else {
+ /* Virtual AP/ P2P Group Interface */
+ WL_DBG(("Apply IEs for iface:%s\n", ndev->name));
+ bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
+ }
+
+ if (ndev != NULL) {
+ switch (type) {
+ case WL_BEACON:
+ pktflag = VNDR_IE_BEACON_FLAG;
+ break;
+ case WL_PROBE_RESP:
+ pktflag = VNDR_IE_PRBRSP_FLAG;
+ break;
+ case WL_ASSOC_RESP:
+ pktflag = VNDR_IE_ASSOCRSP_FLAG;
+ break;
+ }
+ if (pktflag) {
+ ret = wl_cfg80211_set_mgmt_vndr_ies(cfg,
+ ndev_to_cfgdev(ndev), bssidx, pktflag, buf, len);
+ }
+ }
+exit:
+ return ret;
+}
+
+#ifdef WL_SUPPORT_AUTO_CHANNEL
+static s32
+wl_cfg80211_set_auto_channel_scan_state(struct net_device *ndev)
+{
+ u32 val = 0;
+ s32 ret = BCME_ERROR;
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(ndev);
+ struct wiphy *wiphy;
+ /* Disable mpc, to avoid automatic interface down. */
+ val = 0;
+
+ wiphy = bcmcfg_to_wiphy(cfg);
+ if (wl_check_dongle_idle(wiphy) != TRUE) {
+ WL_ERR(("FW is busy to add interface"));
+ return ret;
+ }
+ ret = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val,
+ sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
+ &cfg->ioctl_buf_sync);
+ if (ret < 0) {
+ WL_ERR(("set 'mpc' failed, error = %d\n", ret));
+ goto done;
+ }
+
+ /* Set interface up, explicitly. */
+ val = 1;
+
+ ret = wldev_ioctl(ndev, WLC_UP, (void *)&val, sizeof(val), true);
+ if (ret < 0) {
+ WL_ERR(("set interface up failed, error = %d\n", ret));
+ goto done;
+ }
+
+ /* Stop all scan explicitly, till auto channel selection complete. */
+ wl_set_drv_status(cfg, SCANNING, ndev);
+ if (cfg->escan_info.ndev == NULL) {
+ ret = BCME_OK;
+ goto done;
+ }
+ ret = wl_notify_escan_complete(cfg, ndev, true, true);
+ if (ret < 0) {
+ WL_ERR(("set scan abort failed, error = %d\n", ret));
+ goto done;
+ }
+
+done:
+ return ret;
+}
+
+static bool
+wl_cfg80211_valid_channel_p2p(int channel)
+{
+ bool valid = false;
+
+ /* channel 1 to 14 */
+ if ((channel >= 1) && (channel <= 14)) {
+ valid = true;
+ }
+ /* channel 36 to 48 */
+ else if ((channel >= 36) && (channel <= 48)) {
+ valid = true;
+ }
+ /* channel 149 to 161 */
+ else if ((channel >= 149) && (channel <= 161)) {
+ valid = true;
+ }
+ else {
+ valid = false;
+ WL_INFORM(("invalid P2P chanspec, channel = %d\n", channel));
+ }
+
+ return valid;
+}
+
+s32
+wl_cfg80211_get_chanspecs_2g(struct net_device *ndev, void *buf, s32 buflen)
+{
+ s32 ret = BCME_ERROR;
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(ndev);
+ wl_uint32_list_t *list = NULL;
+ chanspec_t chanspec = 0;
+
+ memset(buf, 0, buflen);
+
+ list = (wl_uint32_list_t *)buf;
+ list->count = htod32(WL_NUMCHANSPECS);
+
+ /* Restrict channels to 2.4GHz, 20MHz BW, no SB. */
+ chanspec |= (WL_CHANSPEC_BAND_2G | WL_CHANSPEC_BW_20 |
+ WL_CHANSPEC_CTL_SB_NONE);
+ chanspec = wl_chspec_host_to_driver(chanspec);
+
+ ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
+ sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
+ if (ret < 0) {
+ WL_ERR(("get 'chanspecs' failed, error = %d\n", ret));
+ }
+
+ return ret;
+}
+
+s32
+wl_cfg80211_get_chanspecs_5g(struct net_device *ndev, void *buf, s32 buflen)
+{
+ u32 channel = 0;
+ s32 ret = BCME_ERROR;
+ s32 i = 0;
+ s32 j = 0;
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(ndev);
+ wl_uint32_list_t *list = NULL;
+ chanspec_t chanspec = 0;
+
+ memset(buf, 0, buflen);
+
+ list = (wl_uint32_list_t *)buf;
+ list->count = htod32(WL_NUMCHANSPECS);
+
+ /* Restrict channels to 5GHz, 20MHz BW, no SB. */
+ chanspec |= (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_20 |
+ WL_CHANSPEC_CTL_SB_NONE);
+ chanspec = wl_chspec_host_to_driver(chanspec);
+
+ ret = wldev_iovar_getbuf_bsscfg(ndev, "chanspecs", (void *)&chanspec,
+ sizeof(chanspec), buf, buflen, 0, &cfg->ioctl_buf_sync);
+ if (ret < 0) {
+ WL_ERR(("get 'chanspecs' failed, error = %d\n", ret));
+ goto done;
+ }
+
+ /* Skip DFS and inavlid P2P channel. */
+ for (i = 0, j = 0; i < dtoh32(list->count); i++) {
+ chanspec = (chanspec_t) dtoh32(list->element[i]);
+ channel = CHSPEC_CHANNEL(chanspec);
+
+ ret = wldev_iovar_getint(ndev, "per_chan_info", &channel);
+ if (ret < 0) {
+ WL_ERR(("get 'per_chan_info' failed, error = %d\n", ret));
+ goto done;
+ }
+
+ if (CHANNEL_IS_RADAR(channel) ||
+ !(wl_cfg80211_valid_channel_p2p(CHSPEC_CHANNEL(chanspec)))) {
+ continue;
+ } else {
+ list->element[j] = list->element[i];
+ }
+
+ j++;
+ }
+
+ list->count = j;
+
+done:
+ return ret;
+}
+
+static s32
+wl_cfg80211_get_best_channel(struct net_device *ndev, void *buf, int buflen,
+ int *channel)
+{
+ s32 ret = BCME_ERROR;
+ int chosen = 0;
+ int retry = 0;
+
+ /* Start auto channel selection scan. */
+ ret = wldev_ioctl(ndev, WLC_START_CHANNEL_SEL, buf, buflen, true);
+ if (ret < 0) {
+ WL_ERR(("can't start auto channel scan, error = %d\n", ret));
+ *channel = 0;
+ goto done;
+ }
+
+ /* Wait for auto channel selection, worst case possible delay is 5250ms. */
+ retry = CHAN_SEL_RETRY_COUNT;
+
+ while (retry--) {
+ OSL_SLEEP(CHAN_SEL_IOCTL_DELAY);
+
+ ret = wldev_ioctl(ndev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen),
+ false);
+ if ((ret == 0) && (dtoh32(chosen) != 0)) {
+ *channel = (u16)(chosen & 0x00FF);
+ WL_INFORM(("selected channel = %d\n", *channel));
+ break;
+ }
+ WL_INFORM(("attempt = %d, ret = %d, chosen = %d\n",
+ (CHAN_SEL_RETRY_COUNT - retry), ret, dtoh32(chosen)));
+ }
+
+ if (retry <= 0) {
+ WL_ERR(("failure, auto channel selection timed out\n"));
+ *channel = 0;
+ ret = BCME_ERROR;
+ }
+
+done:
+ return ret;
+}
+
+static s32
+wl_cfg80211_restore_auto_channel_scan_state(struct net_device *ndev)
+{
+ u32 val = 0;
+ s32 ret = BCME_ERROR;
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(ndev);
+
+ /* Clear scan stop driver status. */
+ wl_clr_drv_status(cfg, SCANNING, ndev);
+
+ /* Enable mpc back to 1, irrespective of initial state. */
+ val = 1;
+
+ ret = wldev_iovar_setbuf_bsscfg(ndev, "mpc", (void *)&val,
+ sizeof(val), cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0,
+ &cfg->ioctl_buf_sync);
+ if (ret < 0) {
+ WL_ERR(("set 'mpc' failed, error = %d\n", ret));
+ }
+
+ return ret;
+}
+
+s32
+wl_cfg80211_get_best_channels(struct net_device *dev, char* cmd, int total_len)
+{
+ int channel = 0;
+ s32 ret = BCME_ERROR;
+ u8 *buf = NULL;
+ char *pos = cmd;
+ struct bcm_cfg80211 *cfg = NULL;
+ struct net_device *ndev = NULL;
+
+ memset(cmd, 0, total_len);
+
+ buf = kmalloc(CHANSPEC_BUF_SIZE, GFP_KERNEL);
+ if (buf == NULL) {
+ WL_ERR(("failed to allocate chanspec buffer\n"));
+ return -ENOMEM;
+ }
+
+ /*
+ * Always use primary interface, irrespective of interface on which
+ * command came.
+ */
+ cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ ndev = bcmcfg_to_prmry_ndev(cfg);
+
+ /*
+ * Make sure that FW and driver are in right state to do auto channel
+ * selection scan.
+ */
+ ret = wl_cfg80211_set_auto_channel_scan_state(ndev);
+ if (ret < 0) {
+ WL_ERR(("can't set auto channel scan state, error = %d\n", ret));
+ goto done;
+ }
+
+ /* Best channel selection in 2.4GHz band. */
+ ret = wl_cfg80211_get_chanspecs_2g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
+ if (ret < 0) {
+ WL_ERR(("can't get chanspecs in 2.4GHz, error = %d\n", ret));
+ goto done;
+ }
+
+ ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
+ &channel);
+ if (ret < 0) {
+ WL_ERR(("can't select best channel scan in 2.4GHz, error = %d\n", ret));
+ goto done;
+ }
+
+ if (CHANNEL_IS_2G(channel)) {
+ channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);
+ } else {
+ WL_ERR(("invalid 2.4GHz channel, channel = %d\n", channel));
+ channel = 0;
+ }
+
+ pos += snprintf(pos, total_len, "%04d ", channel);
+
+ /* Best channel selection in 5GHz band. */
+ ret = wl_cfg80211_get_chanspecs_5g(ndev, (void *)buf, CHANSPEC_BUF_SIZE);
+ if (ret < 0) {
+ WL_ERR(("can't get chanspecs in 5GHz, error = %d\n", ret));
+ goto done;
+ }
+
+ ret = wl_cfg80211_get_best_channel(ndev, (void *)buf, CHANSPEC_BUF_SIZE,
+ &channel);
+ if (ret < 0) {
+ WL_ERR(("can't select best channel scan in 5GHz, error = %d\n", ret));
+ goto done;
+ }
+
+ if (CHANNEL_IS_5G(channel)) {
+ channel = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_5GHZ);
+ } else {
+ WL_ERR(("invalid 5GHz channel, channel = %d\n", channel));
+ channel = 0;
+ }
+
+ pos += snprintf(pos, total_len, "%04d ", channel);
+
+ /* Set overall best channel same as 5GHz best channel. */
+ pos += snprintf(pos, total_len, "%04d ", channel);
+
+done:
+ if (NULL != buf) {
+ kfree(buf);
+ }
+
+ /* Restore FW and driver back to normal state. */
+ ret = wl_cfg80211_restore_auto_channel_scan_state(ndev);
+ if (ret < 0) {
+ WL_ERR(("can't restore auto channel scan state, error = %d\n", ret));
+ }
+
+ return (pos - cmd);
+}
+#endif /* WL_SUPPORT_AUTO_CHANNEL */
+
+static const struct rfkill_ops wl_rfkill_ops = {
+ .set_block = wl_rfkill_set
+};
+
+static int wl_rfkill_set(void *data, bool blocked)
+{
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data;
+
+ WL_DBG(("Enter \n"));
+ WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked"));
+
+ if (!cfg)
+ return -EINVAL;
+
+ cfg->rf_blocked = blocked;
+
+ return 0;
+}
+
+static int wl_setup_rfkill(struct bcm_cfg80211 *cfg, bool setup)
+{
+ s32 err = 0;
+
+ WL_DBG(("Enter \n"));
+ if (!cfg)
+ return -EINVAL;
+ if (setup) {
+ cfg->rfkill = rfkill_alloc("brcmfmac-wifi",
+ wl_cfg80211_get_parent_dev(),
+ RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)cfg);
+
+ if (!cfg->rfkill) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ err = rfkill_register(cfg->rfkill);
+
+ if (err)
+ rfkill_destroy(cfg->rfkill);
+ } else {
+ if (!cfg->rfkill) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ rfkill_unregister(cfg->rfkill);
+ rfkill_destroy(cfg->rfkill);
+ }
+
+err_out:
+ return err;
+}
+
+#ifdef DEBUGFS_CFG80211
+/**
+* Format : echo "SCAN:1 DBG:1" > /sys/kernel/debug/dhd/debug_level
+* to turn on SCAN and DBG log.
+* To turn off SCAN partially, echo "SCAN:0" > /sys/kernel/debug/dhd/debug_level
+* To see current setting of debug level,
+* cat /sys/kernel/debug/dhd/debug_level
+*/
+static ssize_t
+wl_debuglevel_write(struct file *file, const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)], sublog[S_SUBLOGLEVEL];
+ char *params, *token, *colon;
+ uint i, tokens, log_on = 0;
+ memset(tbuf, 0, sizeof(tbuf));
+ memset(sublog, 0, sizeof(sublog));
+ if (copy_from_user(&tbuf, userbuf, min_t(size_t, (sizeof(tbuf) - 1), count)))
+ return -EFAULT;
+
+ params = &tbuf[0];
+ colon = strchr(params, '\n');
+ if (colon != NULL)
+ *colon = '\0';
+ while ((token = strsep(&params, " ")) != NULL) {
+ memset(sublog, 0, sizeof(sublog));
+ if (token == NULL || !*token)
+ break;
+ if (*token == '\0')
+ continue;
+ colon = strchr(token, ':');
+ if (colon != NULL) {
+ *colon = ' ';
+ }
+ tokens = sscanf(token, "%s %u", sublog, &log_on);
+ if (colon != NULL)
+ *colon = ':';
+
+ if (tokens == 2) {
+ for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
+ if (!strncmp(sublog, sublogname_map[i].sublogname,
+ strlen(sublogname_map[i].sublogname))) {
+ if (log_on)
+ wl_dbg_level |=
+ (sublogname_map[i].log_level);
+ else
+ wl_dbg_level &=
+ ~(sublogname_map[i].log_level);
+ }
+ }
+ } else
+ WL_ERR(("%s: can't parse '%s' as a "
+ "SUBMODULE:LEVEL (%d tokens)\n",
+ tbuf, token, tokens));
+
+
+ }
+ return count;
+}
+
+static ssize_t
+wl_debuglevel_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char *param;
+ char tbuf[S_SUBLOGLEVEL * ARRAYSIZE(sublogname_map)];
+ uint i;
+ memset(tbuf, 0, sizeof(tbuf));
+ param = &tbuf[0];
+ for (i = 0; i < ARRAYSIZE(sublogname_map); i++) {
+ param += snprintf(param, sizeof(tbuf) - 1, "%s:%d ",
+ sublogname_map[i].sublogname,
+ (wl_dbg_level & sublogname_map[i].log_level) ? 1 : 0);
+ }
+ *param = '\n';
+ return simple_read_from_buffer(user_buf, count, ppos, tbuf, strlen(&tbuf[0]));
+
+}
+static const struct file_operations fops_debuglevel = {
+ .open = NULL,
+ .write = wl_debuglevel_write,
+ .read = wl_debuglevel_read,
+ .owner = THIS_MODULE,
+ .llseek = NULL,
+};
+
+static s32 wl_setup_debugfs(struct bcm_cfg80211 *cfg)
+{
+ s32 err = 0;
+ struct dentry *_dentry;
+ if (!cfg)
+ return -EINVAL;
+ cfg->debugfs = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ if (!cfg->debugfs || IS_ERR(cfg->debugfs)) {
+ if (cfg->debugfs == ERR_PTR(-ENODEV))
+ WL_ERR(("Debugfs is not enabled on this kernel\n"));
+ else
+ WL_ERR(("Can not create debugfs directory\n"));
+ cfg->debugfs = NULL;
+ goto exit;
+
+ }
+ _dentry = debugfs_create_file("debug_level", S_IRUSR | S_IWUSR,
+ cfg->debugfs, cfg, &fops_debuglevel);
+ if (!_dentry || IS_ERR(_dentry)) {
+ WL_ERR(("failed to create debug_level debug file\n"));
+ wl_free_debugfs(cfg);
+ }
+exit:
+ return err;
+}
+static s32 wl_free_debugfs(struct bcm_cfg80211 *cfg)
+{
+ if (!cfg)
+ return -EINVAL;
+ if (cfg->debugfs)
+ debugfs_remove_recursive(cfg->debugfs);
+ cfg->debugfs = NULL;
+ return 0;
+}
+#endif /* DEBUGFS_CFG80211 */
+
+struct device *wl_cfg80211_get_parent_dev(void)
+{
+ return cfg80211_parent_dev;
+}
+
+void wl_cfg80211_set_parent_dev(void *dev)
+{
+ cfg80211_parent_dev = dev;
+}
+
+static void wl_cfg80211_clear_parent_dev(void)
+{
+ cfg80211_parent_dev = NULL;
+}
+
+void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
+{
+ wldev_iovar_getbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg), "cur_etheraddr", NULL,
+ 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
+ memcpy(mac->octet, cfg->ioctl_buf, ETHER_ADDR_LEN);
+}
+static bool check_dev_role_integrity(struct bcm_cfg80211 *cfg, u32 dev_role)
+{
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+ if (((dev_role == NL80211_IFTYPE_AP) &&
+ !(dhd->op_mode & DHD_FLAG_HOSTAP_MODE)) ||
+ ((dev_role == NL80211_IFTYPE_P2P_GO) &&
+ !(dhd->op_mode & DHD_FLAG_P2P_GO_MODE)))
+ {
+ WL_ERR(("device role select failed role:%d op_mode:%d \n", dev_role, dhd->op_mode));
+ return false;
+ }
+ return true;
+}
+
+int wl_cfg80211_do_driver_init(struct net_device *net)
+{
+ struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net);
+
+ if (!cfg || !cfg->wdev)
+ return -EINVAL;
+
+ if (dhd_do_driver_init(cfg->wdev->netdev) < 0)
+ return -1;
+
+ return 0;
+}
+
+void wl_cfg80211_enable_trace(bool set, u32 level)
+{
+ if (set)
+ wl_dbg_level = level & WL_DBG_LEVEL;
+ else
+ wl_dbg_level |= (WL_DBG_LEVEL & level);
+}
+#if defined(WL_SUPPORT_BACKPORTED_KPATCHES) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, \
+ 2, 0))
+static s32
+wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
+ bcm_struct_cfgdev *cfgdev, u64 cookie)
+{
+ /* CFG80211 checks for tx_cancel_wait callback when ATTR_DURATION
+ * is passed with CMD_FRAME. This callback is supposed to cancel
+ * the OFFCHANNEL Wait. Since we are already taking care of that
+ * with the tx_mgmt logic, do nothing here.
+ */
+
+ return 0;
+}
+#endif /* WL_SUPPORT_BACKPORTED_PATCHES || KERNEL >= 3.2.0 */
+
+#ifdef WL11U
+bcm_tlv_t *
+wl_cfg80211_find_interworking_ie(u8 *parse, u32 len)
+{
+ bcm_tlv_t *ie;
+
+ while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_INTERWORKING_ID))) {
+ return (bcm_tlv_t *)ie;
+ }
+ return NULL;
+}
+
+
+static s32
+wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag,
+ uint8 ie_id, uint8 *data, uint8 data_len)
+{
+ s32 err = BCME_OK;
+ s32 buf_len;
+ s32 iecount;
+ ie_setbuf_t *ie_setbuf;
+ u32 iw_ie_len = 0;
+ u8 iw_ie[IW_IES_MAX_BUF_LEN];
+
+ if (ie_id != DOT11_MNG_INTERWORKING_ID)
+ return BCME_UNSUPPORTED;
+
+ /* Validate the pktflag parameter */
+ if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG |
+ VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG |
+ VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG|
+ VNDR_IE_CUSTOM_FLAG))) {
+ WL_ERR(("cfg80211 Add IE: Invalid packet flag 0x%x\n", pktflag));
+ return -1;
+ }
+
+ /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */
+ pktflag = htod32(pktflag);
+
+ if (data_len > IW_IES_MAX_BUF_LEN) {
+ WL_ERR(("IW IE len exceeds max len %d\n", IW_IES_MAX_BUF_LEN));
+ return -EINVAL;
+ }
+
+ buf_len = sizeof(ie_setbuf_t) + data_len - 1;
+ ie_setbuf = (ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL);
+
+ if (!ie_setbuf) {
+ WL_ERR(("Error allocating buffer for IE\n"));
+ return -ENOMEM;
+ }
+
+ wl_get_iwdata_by_netdev(cfg, ndev, iw_ie, &iw_ie_len);
+
+ if (iw_ie_len == data_len && !memcmp(iw_ie, data, data_len)) {
+ WL_ERR(("Previous IW IE is equals to current IE\n"));
+ err = BCME_OK;
+ goto exit;
+ }
+
+ strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1);
+ ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
+
+ /* Buffer contains only 1 IE */
+ iecount = htod32(1);
+ memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int));
+ memcpy((void *)&ie_setbuf->ie_buffer.ie_list[0].pktflag, &pktflag, sizeof(uint32));
+
+ /* Now, add the IE to the buffer */
+ ie_setbuf->ie_buffer.ie_list[0].ie_data.id = ie_id;
+
+ /* if already set with previous values, delete it first */
+ if (iw_ie_len != 0) {
+ WL_DBG(("Different IW_IE was already set. clear first\n"));
+
+ ie_setbuf->ie_buffer.ie_list[0].ie_data.len = 0;
+
+ err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len,
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+
+ if (err != BCME_OK)
+ goto exit;
+ }
+
+ ie_setbuf->ie_buffer.ie_list[0].ie_data.len = data_len;
+ memcpy((uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], data, data_len);
+
+ err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len,
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+
+ if (err == BCME_OK) {
+ wl_set_iwdata_by_netdev(cfg, ndev, data, data_len);
+ err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 1, bssidx);
+ }
+
+exit:
+ if (ie_setbuf)
+ kfree(ie_setbuf);
+ return err;
+}
+#endif /* WL11U */
+
+s32
+wl_cfg80211_dfs_ap_move(struct net_device *ndev, char *data, char *command, int total_len)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(ndev);
+ char ioctl_buf[50];
+ int err = 0;
+ uint32 val = 0;
+ chanspec_t chanspec = 0;
+ int abort;
+ int bytes_written = 0;
+ wl_dfs_ap_move_status_t *status;
+ char chanbuf[CHANSPEC_STR_LEN];
+ const char *dfs_state_str[DFS_SCAN_S_MAX] = {
+ "Radar Free On Channel",
+ "Radar Found On Channel",
+ "Radar Scan In Progress",
+ "Radar Scan Aborted",
+ "RSDB Mode switch in Progress For Scan"
+ };
+ if (ndev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
+ bytes_written = snprintf(command, total_len, "AP is not UP\n");
+ return bytes_written;
+ }
+ if (!*data) {
+ if ((err = wldev_iovar_getbuf(ndev, "dfs_ap_move", NULL, 0,
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
+ WL_ERR(("setting dfs_ap_move failed with err=%d \n", err));
+ return err;
+ }
+ status = (wl_dfs_ap_move_status_t *)cfg->ioctl_buf;
+
+ if (status->version != WL_DFS_AP_MOVE_VERSION) {
+ err = BCME_UNSUPPORTED;
+ WL_ERR(("err=%d version=%d\n", err, status->version));
+ return err;
+ }
+
+ if (status->move_status != (int8) DFS_SCAN_S_IDLE) {
+ chanspec = wl_chspec_driver_to_host(status->chanspec);
+ if (chanspec != 0 && chanspec != INVCHANSPEC) {
+ wf_chspec_ntoa(chanspec, chanbuf);
+ bytes_written = snprintf(command, total_len,
+ "AP Target Chanspec %s (0x%x)\n", chanbuf, chanspec);
+ }
+ bytes_written += snprintf(command + bytes_written, total_len,
+ "%s\n", dfs_state_str[status->move_status]);
+ return bytes_written;
+ } else {
+ bytes_written = snprintf(command, total_len, "dfs AP move in IDLE state\n");
+ return bytes_written;
+ }
+
+ }
+
+ abort = bcm_atoi(data);
+ if (abort == -1) {
+ if ((err = wldev_iovar_setbuf(ndev, "dfs_ap_move", &abort,
+ sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
+ WL_ERR(("seting dfs_ap_move failed with err %d\n", err));
+ return err;
+ }
+ } else {
+ chanspec = wf_chspec_aton(data);
+ if (chanspec != 0) {
+ val = wl_chspec_host_to_driver(chanspec);
+ if (val != INVCHANSPEC) {
+ if ((err = wldev_iovar_setbuf(ndev, "dfs_ap_move", &val,
+ sizeof(int), ioctl_buf, sizeof(ioctl_buf), NULL)) < 0) {
+ WL_ERR(("seting dfs_ap_move failed with err %d\n", err));
+ return err;
+ }
+ WL_DBG((" set dfs_ap_move successfull"));
+ } else {
+ err = BCME_USAGE_ERROR;
+ }
+ }
+ }
+ return err;
+}
+
+s32
+wl_cfg80211_wbtext_config(struct net_device *ndev, char *data, char *command, int total_len)
+{
+ uint i = 0;
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(ndev);
+ wl_roam_prof_band_t *rp;
+ int err = -EINVAL, bytes_written = 0;
+ size_t len = strlen(data);
+ int rp_len = 0;
+ data[len] = '\0';
+ rp = (wl_roam_prof_band_t *) kzalloc(sizeof(*rp)
+ * WL_MAX_ROAM_PROF_BRACKETS, GFP_KERNEL);
+ if (unlikely(!rp)) {
+ WL_ERR(("%s: failed to allocate memory\n", __func__));
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ rp->ver = WL_MAX_ROAM_PROF_VER;
+ if (*data && (!strncmp(data, "b", 1))) {
+ rp->band = WLC_BAND_2G;
+ } else if (*data && (!strncmp(data, "a", 1))) {
+ rp->band = WLC_BAND_5G;
+ } else {
+ err = snprintf(command, total_len, "Missing band\n");
+ goto exit;
+ }
+ data++;
+ rp->len = 0;
+ /* Getting roam profile from fw */
+ if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
+ WL_ERR(("Getting roam_profile failed with err=%d \n", err));
+ goto exit;
+ }
+ memcpy(rp, cfg->ioctl_buf, sizeof(*rp) * WL_MAX_ROAM_PROF_BRACKETS);
+ /* roam_prof version get */
+ if (rp->ver != WL_MAX_ROAM_PROF_VER) {
+ WL_ERR(("bad version (=%d) in return data\n", rp->ver));
+ err = -EINVAL;
+ goto exit;
+ }
+ if ((rp->len % sizeof(wl_roam_prof_t)) != 0) {
+ WL_ERR(("bad length (=%d) in return data\n", rp->len));
+ err = -EINVAL;
+ goto exit;
+ }
+
+ if (!*data) {
+ for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
+ /* printing contents of roam profile data from fw and exits
+ * if code hits any of one of the below condtion. If remaining
+ * length of buffer is less than roam profile size or
+ * if there is no valid entry.
+ */
+ if (((i * sizeof(wl_roam_prof_t)) > rp->len) ||
+ (rp->roam_prof[i].fullscan_period == 0)) {
+ break;
+ }
+ bytes_written += snprintf(command+bytes_written,
+ total_len, "RSSI[%d,%d] CU(trigger:%d%%: duration:%ds)\n",
+ rp->roam_prof[i].roam_trigger, rp->roam_prof[i].rssi_lower,
+ rp->roam_prof[i].channel_usage,
+ rp->roam_prof[i].cu_avg_calc_dur);
+ }
+ err = bytes_written;
+ goto exit;
+ } else {
+ for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
+ /* reading contents of roam profile data from fw and exits
+ * if code hits any of one of the below condtion, If remaining
+ * length of buffer is less than roam profile size or if there
+ * is no valid entry.
+ */
+ if (((i * sizeof(wl_roam_prof_t)) > rp->len) ||
+ (rp->roam_prof[i].fullscan_period == 0)) {
+ break;
+ }
+ }
+ /* Do not set roam_prof from upper layer if fw doesn't have 2 rows */
+ if (i != 2) {
+ WL_ERR(("FW must have 2 rows to fill roam_prof\n"));
+ err = -EINVAL;
+ goto exit;
+ }
+ /* setting roam profile to fw */
+ data++;
+ for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
+ rp->roam_prof[i].roam_trigger = simple_strtol(data, &data, 10);
+ data++;
+ rp->roam_prof[i].rssi_lower = simple_strtol(data, &data, 10);
+ data++;
+ rp->roam_prof[i].channel_usage = simple_strtol(data, &data, 10);
+ data++;
+ rp->roam_prof[i].cu_avg_calc_dur = simple_strtol(data, &data, 10);
+
+ rp_len += sizeof(wl_roam_prof_t);
+ if (*data == '\0') {
+ break;
+ }
+ data++;
+ }
+ if (i != 1) {
+ WL_ERR(("Only two roam_prof rows supported.\n"));
+ err = -EINVAL;
+ goto exit;
+ }
+ rp->len = rp_len;
+ if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
+ sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL)) < 0) {
+ WL_ERR(("seting roam_profile failed with err %d\n", err));
+ }
+ }
+exit:
+ if (rp) {
+ kfree(rp);
+ }
+ return err;
+}
+
+int wl_cfg80211_wbtext_weight_config(struct net_device *ndev, char *data,
+ char *command, int total_len)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(ndev);
+ int bytes_written = 0, err = -EINVAL, argc = 0;
+ char rssi[5], band[5], weight[5];
+ char *endptr = NULL;
+ wnm_bss_select_weight_cfg_t *bwcfg;
+
+ bwcfg = kzalloc(sizeof(*bwcfg), GFP_KERNEL);
+ if (unlikely(!bwcfg)) {
+ WL_ERR(("%s: failed to allocate memory\n", __func__));
+ err = -ENOMEM;
+ goto exit;
+ }
+ bwcfg->version = WNM_BSSLOAD_MONITOR_VERSION;
+ bwcfg->type = 0;
+ bwcfg->weight = 0;
+
+ argc = sscanf(data, "%s %s %s", rssi, band, weight);
+
+ if (!strcasecmp(rssi, "rssi"))
+ bwcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
+ else if (!strcasecmp(rssi, "cu"))
+ bwcfg->type = WNM_BSS_SELECT_TYPE_CU;
+ else {
+ /* Usage DRIVER WBTEXT_WEIGHT_CONFIG <rssi/cu> <band> <weight> */
+ WL_ERR(("%s: Command usage error\n", __func__));
+ goto exit;
+ }
+
+ if (!strcasecmp(band, "a"))
+ bwcfg->band = WLC_BAND_5G;
+ else if (!strcasecmp(band, "b"))
+ bwcfg->band = WLC_BAND_2G;
+ else if (!strcasecmp(band, "all"))
+ bwcfg->band = WLC_BAND_ALL;
+ else {
+ WL_ERR(("%s: Command usage error\n", __func__));
+ goto exit;
+ }
+
+ if (argc == 2) {
+ /* If there is no data after band, getting wnm_bss_select_weight from fw */
+ if (bwcfg->band == WLC_BAND_ALL) {
+ WL_ERR(("band option \"all\" is for set only, not get\n"));
+ goto exit;
+ }
+ if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_weight", bwcfg,
+ sizeof(*bwcfg),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
+ WL_ERR(("Getting wnm_bss_select_weight failed with err=%d \n", err));
+ goto exit;
+ }
+ memcpy(bwcfg, cfg->ioctl_buf, sizeof(*bwcfg));
+ bytes_written = snprintf(command, total_len, "%s %s weight = %d\n",
+ (bwcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU",
+ (bwcfg->band == WLC_BAND_2G) ? "2G" : "5G", bwcfg->weight);
+ err = bytes_written;
+ goto exit;
+ } else {
+ /* if weight is non integer returns command usage error */
+ bwcfg->weight = simple_strtol(weight, &endptr, 0);
+ if (*endptr != '\0') {
+ WL_ERR(("%s: Command usage error", __func__));
+ goto exit;
+ }
+ /* setting weight for iovar wnm_bss_select_weight to fw */
+ if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_weight", bwcfg,
+ sizeof(*bwcfg),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
+ WL_ERR(("Getting wnm_bss_select_weight failed with err=%d\n", err));
+ }
+ }
+exit:
+ if (bwcfg) {
+ kfree(bwcfg);
+ }
+ return err;
+}
+
+/* WBTEXT_TUPLE_MIN_LEN_CHECK :strlen(low)+" "+strlen(high)+" "+strlen(factor) */
+#define WBTEXT_TUPLE_MIN_LEN_CHECK 5
+
+int wl_cfg80211_wbtext_table_config(struct net_device *ndev, char *data,
+ char *command, int total_len)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(ndev);
+ int bytes_written = 0, err = -EINVAL;
+ char rssi[5], band[5];
+ int btcfg_len = 0, i = 0, parsed_len = 0;
+ wnm_bss_select_factor_cfg_t *btcfg;
+ size_t slen = strlen(data);
+ char *start_addr = NULL;
+ data[slen] = '\0';
+
+ btcfg = kzalloc((sizeof(*btcfg) + sizeof(*btcfg) *
+ WL_FACTOR_TABLE_MAX_LIMIT), GFP_KERNEL);
+ if (unlikely(!btcfg)) {
+ WL_ERR(("%s: failed to allocate memory\n", __func__));
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ btcfg->version = WNM_BSS_SELECT_FACTOR_VERSION;
+ btcfg->band = WLC_BAND_AUTO;
+ btcfg->type = 0;
+ btcfg->count = 0;
+
+ sscanf(data, "%s %s", rssi, band);
+
+ if (!strcasecmp(rssi, "rssi")) {
+ btcfg->type = WNM_BSS_SELECT_TYPE_RSSI;
+ }
+ else if (!strcasecmp(rssi, "cu")) {
+ btcfg->type = WNM_BSS_SELECT_TYPE_CU;
+ }
+ else {
+ WL_ERR(("%s: Command usage error\n", __func__));
+ goto exit;
+ }
+
+ if (!strcasecmp(band, "a")) {
+ btcfg->band = WLC_BAND_5G;
+ }
+ else if (!strcasecmp(band, "b")) {
+ btcfg->band = WLC_BAND_2G;
+ }
+ else if (!strcasecmp(band, "all")) {
+ btcfg->band = WLC_BAND_ALL;
+ }
+ else {
+ WL_ERR(("%s: Command usage, Wrong band\n", __func__));
+ goto exit;
+ }
+
+ if ((slen - 1) == (strlen(rssi) + strlen(band))) {
+ /* Getting factor table using iovar 'wnm_bss_select_table' from fw */
+ if ((err = wldev_iovar_getbuf(ndev, "wnm_bss_select_table", btcfg,
+ sizeof(*btcfg),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
+ WL_ERR(("Getting wnm_bss_select_table failed with err=%d \n", err));
+ goto exit;
+ }
+ memcpy(btcfg, cfg->ioctl_buf, sizeof(*btcfg));
+ memcpy(btcfg, cfg->ioctl_buf, (btcfg->count+1) * sizeof(*btcfg));
+
+ bytes_written += snprintf(command + bytes_written, total_len,
+ "No of entries in table: %d\n", btcfg->count);
+ bytes_written += snprintf(command + bytes_written, total_len, "%s factor table\n",
+ (btcfg->type == WNM_BSS_SELECT_TYPE_RSSI) ? "RSSI" : "CU");
+ bytes_written += snprintf(command + bytes_written, total_len,
+ "low\thigh\tfactor\n");
+ for (i = 0; i <= btcfg->count-1; i++) {
+ bytes_written += snprintf(command + bytes_written, total_len,
+ "%d\t%d\t%d\n", btcfg->params[i].low, btcfg->params[i].high,
+ btcfg->params[i].factor);
+ }
+ err = bytes_written;
+ goto exit;
+ } else {
+ memset(btcfg->params, 0, sizeof(*btcfg) * WL_FACTOR_TABLE_MAX_LIMIT);
+ data += (strlen(rssi) + strlen(band) + 2);
+ start_addr = data;
+ slen = slen - (strlen(rssi) + strlen(band) + 2);
+ for (i = 0; i < WL_FACTOR_TABLE_MAX_LIMIT; i++) {
+ if (parsed_len + WBTEXT_TUPLE_MIN_LEN_CHECK <= slen) {
+ btcfg->params[i].low = simple_strtol(data, &data, 10);
+ data++;
+ btcfg->params[i].high = simple_strtol(data, &data, 10);
+ data++;
+ btcfg->params[i].factor = simple_strtol(data, &data, 10);
+ btcfg->count++;
+ if (*data == '\0') {
+ break;
+ }
+ data++;
+ parsed_len = data - start_addr;
+ } else {
+ WL_ERR(("%s:Command usage:less no of args\n", __func__));
+ goto exit;
+ }
+ }
+ btcfg_len = sizeof(*btcfg) + ((btcfg->count) * sizeof(*btcfg));
+ if ((err = wldev_iovar_setbuf(ndev, "wnm_bss_select_table", btcfg, btcfg_len,
+ cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL)) < 0) {
+ WL_ERR(("seting wnm_bss_select_table failed with err %d\n", err));
+ goto exit;
+ }
+ }
+exit:
+ if (btcfg) {
+ kfree(btcfg);
+ }
+ return err;
+}
+
+s32
+wl_cfg80211_wbtext_delta_config(struct net_device *ndev, char *data, char *command, int total_len)
+{
+ uint i = 0;
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(ndev);
+ int err = -EINVAL, bytes_written = 0, argc = 0, val, len = 0;
+ char delta[5], band[5], *endptr = NULL;
+ wl_roam_prof_band_t *rp;
+
+ rp = (wl_roam_prof_band_t *) kzalloc(sizeof(*rp)
+ * WL_MAX_ROAM_PROF_BRACKETS, GFP_KERNEL);
+ if (unlikely(!rp)) {
+ WL_ERR(("%s: failed to allocate memory\n", __func__));
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ argc = sscanf(data, "%s %s", band, delta);
+ if (!strcasecmp(band, "a"))
+ rp->band = WLC_BAND_5G;
+ else if (!strcasecmp(band, "b"))
+ rp->band = WLC_BAND_2G;
+ else {
+ WL_ERR(("%s: Missing band\n", __func__));
+ goto exit;
+ }
+ /* Getting roam profile from fw */
+ if ((err = wldev_iovar_getbuf(ndev, "roam_prof", rp, sizeof(*rp),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync))) {
+ WL_ERR(("Getting roam_profile failed with err=%d \n", err));
+ goto exit;
+ }
+ memcpy(rp, cfg->ioctl_buf, sizeof(wl_roam_prof_band_t));
+ if (rp->ver != WL_MAX_ROAM_PROF_VER) {
+ WL_ERR(("bad version (=%d) in return data\n", rp->ver));
+ err = -EINVAL;
+ goto exit;
+ }
+ if ((rp->len % sizeof(wl_roam_prof_t)) != 0) {
+ WL_ERR(("bad length (=%d) in return data\n", rp->len));
+ err = -EINVAL;
+ goto exit;
+ }
+
+ if (argc == 2) {
+ /* if delta is non integer returns command usage error */
+ val = simple_strtol(delta, &endptr, 0);
+ if (*endptr != '\0') {
+ WL_ERR(("%s: Command usage error", __func__));
+ goto exit;
+ }
+ for (i = 0; i < WL_MAX_ROAM_PROF_BRACKETS; i++) {
+ /*
+ * Checking contents of roam profile data from fw and exits
+ * if code hits below condtion. If remaining length of buffer is
+ * less than roam profile size or if there is no valid entry.
+ */
+ if (((i * sizeof(wl_roam_prof_t)) > rp->len) ||
+ (rp->roam_prof[i].fullscan_period == 0)) {
+ break;
+ }
+ if (rp->roam_prof[i].channel_usage != 0) {
+ rp->roam_prof[i].roam_delta = val;
+ }
+ len += sizeof(wl_roam_prof_t);
+ }
+ }
+ else {
+ if (rp->roam_prof[i].channel_usage != 0) {
+ bytes_written = snprintf(command, total_len,
+ "%s Delta %d\n", (rp->band == WLC_BAND_2G) ? "2G" : "5G",
+ rp->roam_prof[0].roam_delta);
+ }
+ err = bytes_written;
+ goto exit;
+ }
+ rp->len = len;
+ if ((err = wldev_iovar_setbuf(ndev, "roam_prof", rp,
+ sizeof(*rp), cfg->ioctl_buf, WLC_IOCTL_MEDLEN, NULL)) < 0) {
+ WL_ERR(("seting roam_profile failed with err %d\n", err));
+ }
+exit :
+ if (rp) {
+ kfree(rp);
+ }
+ return err;
+}
+
+
+int wl_cfg80211_scan_stop(bcm_struct_cfgdev *cfgdev)
+{
+ struct bcm_cfg80211 *cfg = NULL;
+ struct net_device *ndev = NULL;
+ unsigned long flags;
+ int clear_flag = 0;
+ int ret = 0;
+
+ WL_TRACE(("Enter\n"));
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ cfg = WDEV_GET_CFG80211_PRIV(cfgdev);
+#else
+ cfg = NETDEV_GET_CFG80211_PRIV(cfgdev);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+ if (!cfg)
+ return -EINVAL;
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ spin_lock_irqsave(&cfg->cfgdrv_lock, flags);
+#ifdef WL_CFG80211_P2P_DEV_IF
+ if (cfg->scan_request && cfg->scan_request->wdev == cfgdev) {
+#else
+ if (cfg->scan_request && cfg->scan_request->dev == cfgdev) {
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
+ struct cfg80211_scan_info info = {
+ .aborted = true
+ };
+ cfg80211_scan_done(cfg->scan_request, &info);
+#else
+ cfg80211_scan_done(cfg->scan_request, true);
+#endif
+ cfg->scan_request = NULL;
+ clear_flag = 1;
+ }
+ spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags);
+
+ if (clear_flag)
+ wl_clr_drv_status(cfg, SCANNING, ndev);
+
+ return ret;
+}
+
+bool wl_cfg80211_is_concurrent_mode(struct bcm_cfg80211 *cfg)
+{
+ if ((cfg) && (wl_get_drv_status_all(cfg, CONNECTED) > 1)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void* wl_cfg80211_get_dhdp(struct net_device *net)
+{
+ struct bcm_cfg80211 *cfg = NULL;
+
+ if (!net)
+ return NULL;
+
+ cfg = NETDEV_GET_CFG80211_PRIV(net);
+
+ return cfg->pub;
+}
+
+bool wl_cfg80211_is_p2p_active(struct wireless_dev *wdev)
+{
+ struct bcm_cfg80211 *cfg = WDEV_GET_CFG80211_PRIV(wdev);
+ return (cfg && cfg->p2p);
+}
+
+bool wl_cfg80211_is_roam_offload(struct bcm_cfg80211 *cfg)
+{
+ return (cfg && cfg->roam_offload);
+}
+
+bool wl_cfg80211_is_event_from_connected_bssid(void *cfg80211_priv,
+ const wl_event_msg_t *e, int ifidx)
+{
+ dhd_pub_t *dhd = NULL;
+ struct net_device *ndev = NULL;
+ u8 *curbssid = NULL;
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)cfg80211_priv;
+
+ dhd = (dhd_pub_t *)(cfg->pub);
+
+ if (dhd) {
+ ndev = dhd_idx2net(dhd, ifidx);
+ }
+
+ if (!dhd || !ndev) {
+ return false;
+ }
+
+ curbssid = wl_read_prof(cfg, ndev, WL_PROF_BSSID);
+
+ return memcmp(curbssid, &e->addr, ETHER_ADDR_LEN) == 0;
+}
+
+static void wl_cfg80211_work_handler(struct work_struct * work)
+{
+ struct bcm_cfg80211 *cfg = NULL;
+ struct net_info *iter, *next;
+ s32 err = BCME_OK;
+ s32 pm = PM_FAST;
+ BCM_SET_CONTAINER_OF(cfg, work, struct bcm_cfg80211, pm_enable_work.work);
+ WL_DBG(("Enter \n"));
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#endif
+ for_each_ndev(cfg, iter, next) {
+ /* p2p discovery iface ndev could be null */
+ if (iter->ndev) {
+ if (!wl_get_drv_status(cfg, CONNECTED, iter->ndev) ||
+ (wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_BSS &&
+ wl_get_mode_by_netdev(cfg, iter->ndev) != WL_MODE_IBSS))
+ continue;
+ if (iter->ndev) {
+ if ((err = wldev_ioctl(iter->ndev, WLC_SET_PM,
+ &pm, sizeof(pm), true)) != 0) {
+ if (err == -ENODEV)
+ WL_DBG(("%s:netdev not ready\n",
+ iter->ndev->name));
+ else
+ WL_ERR(("%s:error (%d)\n",
+ iter->ndev->name, err));
+ } else
+ wl_cfg80211_update_power_mode(iter->ndev);
+ }
+ }
+ }
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+ _Pragma("GCC diagnostic pop")
+#endif
+ DHD_PM_WAKE_UNLOCK(cfg->pub);
+}
+
+u8
+wl_get_action_category(void *frame, u32 frame_len)
+{
+ u8 category;
+ u8 *ptr = (u8 *)frame;
+ if (frame == NULL)
+ return DOT11_ACTION_CAT_ERR_MASK;
+ if (frame_len < DOT11_ACTION_HDR_LEN)
+ return DOT11_ACTION_CAT_ERR_MASK;
+ category = ptr[DOT11_ACTION_CAT_OFF];
+ WL_INFORM(("Action Category: %d\n", category));
+ return category;
+}
+
+int
+wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action)
+{
+ u8 *ptr = (u8 *)frame;
+ if (frame == NULL || ret_action == NULL)
+ return BCME_ERROR;
+ if (frame_len < DOT11_ACTION_HDR_LEN)
+ return BCME_ERROR;
+ if (DOT11_ACTION_CAT_PUBLIC != wl_get_action_category(frame, frame_len))
+ return BCME_ERROR;
+ *ret_action = ptr[DOT11_ACTION_ACT_OFF];
+ WL_INFORM(("Public Action : %d\n", *ret_action));
+ return BCME_OK;
+}
+
+
+static int
+wl_cfg80211_delayed_roam(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ const struct ether_addr *bssid)
+{
+ s32 err;
+ wl_event_msg_t e;
+
+ bzero(&e, sizeof(e));
+ e.event_type = cpu_to_be32(WLC_E_BSSID);
+ memcpy(&e.addr, bssid, ETHER_ADDR_LEN);
+ /* trigger the roam event handler */
+ WL_INFORM(("Delayed roam to " MACDBG "\n", MAC2STRDBG((u8*)(bssid))));
+ err = wl_notify_roaming_status(cfg, ndev_to_cfgdev(ndev), &e, NULL);
+
+ return err;
+}
+
+static s32
+wl_cfg80211_parse_vndr_ies(u8 *parse, u32 len,
+ struct parsed_vndr_ies *vndr_ies)
+{
+ s32 err = BCME_OK;
+ vndr_ie_t *vndrie;
+ bcm_tlv_t *ie;
+ struct parsed_vndr_ie_info *parsed_info;
+ u32 count = 0;
+ s32 remained_len;
+
+ remained_len = (s32)len;
+ memset(vndr_ies, 0, sizeof(*vndr_ies));
+
+ WL_INFORM(("---> len %d\n", len));
+ ie = (bcm_tlv_t *) parse;
+ if (!bcm_valid_tlv(ie, remained_len))
+ ie = NULL;
+ while (ie) {
+ if (count >= MAX_VNDR_IE_NUMBER)
+ break;
+ if (ie->id == DOT11_MNG_VS_ID) {
+ vndrie = (vndr_ie_t *) ie;
+ /* len should be bigger than OUI length + one data length at least */
+ if (vndrie->len < (VNDR_IE_MIN_LEN + 1)) {
+ WL_ERR(("%s: invalid vndr ie. length is too small %d\n",
+ __FUNCTION__, vndrie->len));
+ goto end;
+ }
+ /* if wpa or wme ie, do not add ie */
+ if (!bcmp(vndrie->oui, (u8*)WPA_OUI, WPA_OUI_LEN) &&
+ ((vndrie->data[0] == WPA_OUI_TYPE) ||
+ (vndrie->data[0] == WME_OUI_TYPE))) {
+ CFGP2P_DBG(("Found WPA/WME oui. Do not add it\n"));
+ goto end;
+ }
+
+ parsed_info = &vndr_ies->ie_info[count++];
+
+ /* save vndr ie information */
+ parsed_info->ie_ptr = (char *)vndrie;
+ parsed_info->ie_len = (vndrie->len + TLV_HDR_LEN);
+ memcpy(&parsed_info->vndrie, vndrie, sizeof(vndr_ie_t));
+ vndr_ies->count = count;
+
+ WL_DBG(("\t ** OUI %02x %02x %02x, type 0x%02x len:%d\n",
+ parsed_info->vndrie.oui[0], parsed_info->vndrie.oui[1],
+ parsed_info->vndrie.oui[2], parsed_info->vndrie.data[0],
+ parsed_info->ie_len));
+ }
+end:
+ ie = bcm_next_tlv(ie, &remained_len);
+ }
+ return err;
+}
+
+s32
+wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 *cfg, s32 bssidx)
+{
+ s32 index;
+ struct net_info *netinfo;
+ s32 vndrie_flag[] = {VNDR_IE_BEACON_FLAG, VNDR_IE_PRBRSP_FLAG,
+ VNDR_IE_ASSOCRSP_FLAG, VNDR_IE_PRBREQ_FLAG, VNDR_IE_ASSOCREQ_FLAG};
+
+ netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx);
+ if (!netinfo || !netinfo->wdev) {
+ WL_ERR(("netinfo or netinfo->wdev is NULL\n"));
+ return -1;
+ }
+
+ WL_DBG(("clear management vendor IEs for bssidx:%d \n", bssidx));
+ /* Clear the IEs set in the firmware so that host is in sync with firmware */
+ for (index = 0; index < ARRAYSIZE(vndrie_flag); index++) {
+ if (wl_cfg80211_set_mgmt_vndr_ies(cfg, wdev_to_cfgdev(netinfo->wdev),
+ bssidx, vndrie_flag[index], NULL, 0) < 0)
+ WL_ERR(("vndr_ies clear failed. Ignoring.. \n"));
+ }
+
+ return 0;
+}
+
+s32
+wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 *cfg)
+{
+ struct net_info *iter, *next;
+
+ WL_DBG(("clear management vendor IEs \n"));
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#endif
+ for_each_ndev(cfg, iter, next) {
+ wl_cfg80211_clear_per_bss_ies(cfg, iter->bssidx);
+ }
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic pop")
+#endif
+ return 0;
+}
+
+#define WL_VNDR_IE_MAXLEN 2048
+static s8 g_mgmt_ie_buf[WL_VNDR_IE_MAXLEN];
+int
+wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ s32 bssidx, s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
+{
+ struct net_device *ndev = NULL;
+ s32 ret = BCME_OK;
+ u8 *curr_ie_buf = NULL;
+ u8 *mgmt_ie_buf = NULL;
+ u32 mgmt_ie_buf_len = 0;
+ u32 *mgmt_ie_len = 0;
+ u32 del_add_ie_buf_len = 0;
+ u32 total_ie_buf_len = 0;
+ u32 parsed_ie_buf_len = 0;
+ struct parsed_vndr_ies old_vndr_ies;
+ struct parsed_vndr_ies new_vndr_ies;
+ s32 i;
+ u8 *ptr;
+ s32 remained_buf_len;
+ wl_bss_vndr_ies_t *ies = NULL;
+ struct net_info *netinfo;
+
+ WL_DBG(("Enter. pktflag:0x%x bssidx:%x vnd_ie_len:%d \n",
+ pktflag, bssidx, vndr_ie_len));
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ if (bssidx > WL_MAX_IFS) {
+ WL_ERR(("bssidx > supported concurrent Ifaces \n"));
+ return -EINVAL;
+ }
+
+ netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx);
+ if (!netinfo) {
+ WL_ERR(("net_info ptr is NULL \n"));
+ return -EINVAL;
+ }
+
+ /* Clear the global buffer */
+ memset(g_mgmt_ie_buf, 0, sizeof(g_mgmt_ie_buf));
+ curr_ie_buf = g_mgmt_ie_buf;
+ ies = &netinfo->bss.ies;
+
+ switch (pktflag) {
+ case VNDR_IE_PRBRSP_FLAG :
+ mgmt_ie_buf = ies->probe_res_ie;
+ mgmt_ie_len = &ies->probe_res_ie_len;
+ mgmt_ie_buf_len = sizeof(ies->probe_res_ie);
+ break;
+ case VNDR_IE_ASSOCRSP_FLAG :
+ mgmt_ie_buf = ies->assoc_res_ie;
+ mgmt_ie_len = &ies->assoc_res_ie_len;
+ mgmt_ie_buf_len = sizeof(ies->assoc_res_ie);
+ break;
+ case VNDR_IE_BEACON_FLAG :
+ mgmt_ie_buf = ies->beacon_ie;
+ mgmt_ie_len = &ies->beacon_ie_len;
+ mgmt_ie_buf_len = sizeof(ies->beacon_ie);
+ break;
+ case VNDR_IE_PRBREQ_FLAG :
+ mgmt_ie_buf = ies->probe_req_ie;
+ mgmt_ie_len = &ies->probe_req_ie_len;
+ mgmt_ie_buf_len = sizeof(ies->probe_req_ie);
+ break;
+ case VNDR_IE_ASSOCREQ_FLAG :
+ mgmt_ie_buf = ies->assoc_req_ie;
+ mgmt_ie_len = &ies->assoc_req_ie_len;
+ mgmt_ie_buf_len = sizeof(ies->assoc_req_ie);
+ break;
+ default:
+ mgmt_ie_buf = NULL;
+ mgmt_ie_len = NULL;
+ WL_ERR(("not suitable packet type (%d)\n", pktflag));
+ return BCME_ERROR;
+ }
+
+ if (vndr_ie_len > mgmt_ie_buf_len) {
+ WL_ERR(("extra IE size too big\n"));
+ ret = -ENOMEM;
+ } else {
+ /* parse and save new vndr_ie in curr_ie_buff before comparing it */
+ if (vndr_ie && vndr_ie_len && curr_ie_buf) {
+ ptr = curr_ie_buf;
+/* must discard vndr_ie constness, attempt to change vndr_ie arg to non-const
+ * causes cascade of errors in other places, fix involves const casts there
+ */
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#endif
+ if ((ret = wl_cfg80211_parse_vndr_ies((u8 *)vndr_ie,
+ vndr_ie_len, &new_vndr_ies)) < 0) {
+ WL_ERR(("parse vndr ie failed \n"));
+ goto exit;
+ }
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+_Pragma("GCC diagnostic pop")
+#endif
+ for (i = 0; i < new_vndr_ies.count; i++) {
+ struct parsed_vndr_ie_info *vndrie_info =
+ &new_vndr_ies.ie_info[i];
+
+ if ((parsed_ie_buf_len + vndrie_info->ie_len) > WL_VNDR_IE_MAXLEN) {
+ WL_ERR(("IE size is too big (%d > %d)\n",
+ parsed_ie_buf_len, WL_VNDR_IE_MAXLEN));
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ memcpy(ptr + parsed_ie_buf_len, vndrie_info->ie_ptr,
+ vndrie_info->ie_len);
+ parsed_ie_buf_len += vndrie_info->ie_len;
+ }
+ }
+
+ if (mgmt_ie_buf != NULL) {
+ if (parsed_ie_buf_len && (parsed_ie_buf_len == *mgmt_ie_len) &&
+ (memcmp(mgmt_ie_buf, curr_ie_buf, parsed_ie_buf_len) == 0)) {
+ WL_INFORM(("Previous mgmt IE is equals to current IE"));
+ goto exit;
+ }
+
+ /* parse old vndr_ie */
+ if ((ret = wl_cfg80211_parse_vndr_ies(mgmt_ie_buf, *mgmt_ie_len,
+ &old_vndr_ies)) < 0) {
+ WL_ERR(("parse vndr ie failed \n"));
+ goto exit;
+ }
+ /* make a command to delete old ie */
+ for (i = 0; i < old_vndr_ies.count; i++) {
+ struct parsed_vndr_ie_info *vndrie_info =
+ &old_vndr_ies.ie_info[i];
+
+ WL_INFORM(("DELETED ID : %d, Len: %d , OUI:%02x:%02x:%02x\n",
+ vndrie_info->vndrie.id, vndrie_info->vndrie.len,
+ vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1],
+ vndrie_info->vndrie.oui[2]));
+
+ del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
+ pktflag, vndrie_info->vndrie.oui,
+ vndrie_info->vndrie.id,
+ vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
+ vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
+ "del");
+
+ curr_ie_buf += del_add_ie_buf_len;
+ total_ie_buf_len += del_add_ie_buf_len;
+ }
+ }
+
+ *mgmt_ie_len = 0;
+ /* Add if there is any extra IE */
+ if (mgmt_ie_buf && parsed_ie_buf_len) {
+ ptr = mgmt_ie_buf;
+
+ remained_buf_len = mgmt_ie_buf_len;
+
+ /* make a command to add new ie */
+ for (i = 0; i < new_vndr_ies.count; i++) {
+ struct parsed_vndr_ie_info *vndrie_info =
+ &new_vndr_ies.ie_info[i];
+
+ WL_INFORM(("ADDED ID : %d, Len: %d(%d), OUI:%02x:%02x:%02x\n",
+ vndrie_info->vndrie.id, vndrie_info->vndrie.len,
+ vndrie_info->ie_len - 2,
+ vndrie_info->vndrie.oui[0], vndrie_info->vndrie.oui[1],
+ vndrie_info->vndrie.oui[2]));
+
+ del_add_ie_buf_len = wl_cfgp2p_vndr_ie(cfg, curr_ie_buf,
+ pktflag, vndrie_info->vndrie.oui,
+ vndrie_info->vndrie.id,
+ vndrie_info->ie_ptr + VNDR_IE_FIXED_LEN,
+ vndrie_info->ie_len - VNDR_IE_FIXED_LEN,
+ "add");
+
+ /* verify remained buf size before copy data */
+ if (remained_buf_len >= vndrie_info->ie_len) {
+ remained_buf_len -= vndrie_info->ie_len;
+ } else {
+ WL_ERR(("no space in mgmt_ie_buf: pktflag = %d, "
+ "found vndr ies # = %d(cur %d), remained len %d, "
+ "cur mgmt_ie_len %d, new ie len = %d\n",
+ pktflag, new_vndr_ies.count, i, remained_buf_len,
+ *mgmt_ie_len, vndrie_info->ie_len));
+ break;
+ }
+
+ /* save the parsed IE in cfg struct */
+ memcpy(ptr + (*mgmt_ie_len), vndrie_info->ie_ptr,
+ vndrie_info->ie_len);
+ *mgmt_ie_len += vndrie_info->ie_len;
+ curr_ie_buf += del_add_ie_buf_len;
+ total_ie_buf_len += del_add_ie_buf_len;
+ }
+ }
+
+ if (total_ie_buf_len && cfg->ioctl_buf != NULL) {
+ ret = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", g_mgmt_ie_buf,
+ total_ie_buf_len, cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
+ bssidx, &cfg->ioctl_buf_sync);
+ if (ret)
+ WL_ERR(("vndr ie set error : %d\n", ret));
+ }
+ }
+exit:
+
+return ret;
+}
+
+#ifdef WL_CFG80211_ACL
+static int
+wl_cfg80211_set_mac_acl(struct wiphy *wiphy, struct net_device *cfgdev,
+ const struct cfg80211_acl_data *acl)
+{
+ int i;
+ int ret = 0;
+ int macnum = 0;
+ int macmode = MACLIST_MODE_DISABLED;
+ struct maclist *list;
+
+ /* get the MAC filter mode */
+ if (acl && acl->acl_policy == NL80211_ACL_POLICY_DENY_UNLESS_LISTED) {
+ macmode = MACLIST_MODE_ALLOW;
+ } else if (acl && acl->acl_policy == NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED &&
+ acl->n_acl_entries) {
+ macmode = MACLIST_MODE_DENY;
+ }
+
+ /* if acl == NULL, macmode is still disabled.. */
+ if (macmode == MACLIST_MODE_DISABLED) {
+ if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, NULL)) != 0)
+ WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret));
+
+ return ret;
+ }
+
+ macnum = acl->n_acl_entries;
+ if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
+ WL_ERR(("%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) {
+ WL_ERR(("%s : failed to allocate memory\n", __FUNCTION__));
+ return -1;
+ }
+
+ /* prepare the MAC list */
+ list->count = htod32(macnum);
+ for (i = 0; i < macnum; i++) {
+ memcpy(&list->ea[i], &acl->mac_addrs[i], ETHER_ADDR_LEN);
+ }
+ /* set the list */
+ if ((ret = wl_android_set_ap_mac_list(cfgdev, macmode, list)) != 0)
+ WL_ERR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret));
+
+ kfree(list);
+
+ return ret;
+}
+#endif /* WL_CFG80211_ACL */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+int wl_chspec_chandef(chanspec_t chanspec,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
+ struct cfg80211_chan_def *chandef,
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
+ \
+ \
+ \
+ 0)))
+ struct chan_info *chaninfo,
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)) */
+struct wiphy *wiphy)
+
+{
+ uint16 freq = 0;
+ int chan_type = 0;
+ int channel = 0;
+ struct ieee80211_channel *chan;
+
+ if (!chandef) {
+ return -1;
+ }
+ channel = CHSPEC_CHANNEL(chanspec);
+
+ switch (CHSPEC_BW(chanspec)) {
+ case WL_CHANSPEC_BW_20:
+ chan_type = NL80211_CHAN_HT20;
+ break;
+ case WL_CHANSPEC_BW_40:
+ {
+ if (CHSPEC_SB_UPPER(chanspec)) {
+ channel += CH_10MHZ_APART;
+ } else {
+ channel -= CH_10MHZ_APART;
+ }
+ }
+ chan_type = NL80211_CHAN_HT40PLUS;
+ break;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
+ case WL_CHANSPEC_BW_80:
+ case WL_CHANSPEC_BW_8080:
+ {
+ uint16 sb = CHSPEC_CTL_SB(chanspec);
+
+ 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);
+ }
+
+ if (sb == WL_CHANSPEC_CTL_SB_LL || sb == WL_CHANSPEC_CTL_SB_LU)
+ chan_type = NL80211_CHAN_HT40MINUS;
+ else if (sb == WL_CHANSPEC_CTL_SB_UL || sb == WL_CHANSPEC_CTL_SB_UU)
+ chan_type = NL80211_CHAN_HT40PLUS;
+ }
+ break;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
+ default:
+ chan_type = NL80211_CHAN_HT20;
+ break;
+
+ }
+
+ if (CHSPEC_IS5G(chanspec))
+ freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_5GHZ);
+ else
+ freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
+
+ chan = ieee80211_get_channel(wiphy, freq);
+ WL_DBG(("channel:%d freq:%d chan_type: %d chan_ptr:%p \n",
+ channel, freq, chan_type, chan));
+
+ if (unlikely(!chan)) {
+ /* fw and cfg80211 channel lists are not in sync */
+ WL_ERR(("Couldn't find matching channel in wiphy channel list \n"));
+ ASSERT(0);
+ return -EINVAL;
+ }
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
+ cfg80211_chandef_create(chandef, chan, chan_type);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
+ \
+ \
+ \
+ 0)))
+ chaninfo->freq = freq;
+ chaninfo->chan_type = chan_type;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
+ return 0;
+}
+
+void
+wl_cfg80211_ch_switch_notify(struct net_device *dev, uint16 chanspec, struct wiphy *wiphy)
+{
+ u32 freq;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
+ struct cfg80211_chan_def chandef;
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
+ \
+ \
+ \
+ 0)))
+ struct chan_info chaninfo;
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
+
+ if (!wiphy) {
+ WL_ERR(("wiphy is null\n"));
+ return;
+ }
+#ifndef ALLOW_CHSW_EVT
+ /* Channel switch support is only for AP/GO/ADHOC/MESH */
+ if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_STATION ||
+ dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_CLIENT) {
+ WL_ERR(("No channel switch notify support for STA/GC\n"));
+ return;
+ }
+#endif /* !ALLOW_CHSW_EVT */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
+ if (wl_chspec_chandef(chanspec, &chandef, wiphy)) {
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
+ \
+ \
+ \
+ 0)))
+ if (wl_chspec_chandef(chanspec, &chaninfo, wiphy)) {
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
+
+ WL_ERR(("chspec_chandef failed\n"));
+ return;
+ }
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0))
+ freq = chandef.chan ? chandef.chan->center_freq : chandef.center_freq1;
+ cfg80211_ch_switch_notify(dev, &chandef);
+#elif (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 5, 0) && (LINUX_VERSION_CODE <= (3, 7, \
+ \
+ \
+ \
+ 0)))
+ freq = chan_info.freq;
+ cfg80211_ch_switch_notify(dev, chan_info.freq, chan_info.chan_type);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION (3, 8, 0)) */
+
+ WL_ERR(("Channel switch notification for freq: %d chanspec: 0x%x\n", freq, chanspec));
+ return;
+}
+#endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
+
+#ifdef WL11ULB
+s32
+wl_cfg80211_set_ulb_mode(struct net_device *dev, int mode)
+{
+ int ret;
+ int cur_mode;
+
+ ret = wldev_iovar_getint(dev, "ulb_mode", &cur_mode);
+ if (unlikely(ret)) {
+ WL_ERR(("[ULB] ulb_mode get failed. ret:%d \n", ret));
+ return ret;
+ }
+
+ if (cur_mode == mode) {
+ /* If request mode is same as that of the current mode, then
+ * do nothing (Avoid unnecessary wl down and up).
+ */
+ WL_INFORM(("[ULB] No change in ulb_mode. Do nothing.\n"));
+ return 0;
+ }
+
+ /* setting of ulb_mode requires wl to be down */
+ ret = wldev_ioctl(dev, WLC_DOWN, NULL, 0, true);
+ if (unlikely(ret)) {
+ WL_ERR(("[ULB] WLC_DOWN command failed:[%d]\n", ret));
+ return ret;
+ }
+
+ if (mode >= MAX_SUPP_ULB_MODES) {
+ WL_ERR(("[ULB] unsupported ulb_mode :[%d]\n", mode));
+ return -EINVAL;
+ }
+
+ ret = wldev_iovar_setint(dev, "ulb_mode", mode);
+ if (unlikely(ret)) {
+ WL_ERR(("[ULB] ulb_mode set failed. ret:%d \n", ret));
+ return ret;
+ }
+
+ ret = wldev_ioctl(dev, WLC_UP, NULL, 0, true);
+ if (unlikely(ret)) {
+ WL_ERR(("[ULB] WLC_DOWN command failed:[%d]\n", ret));
+ return ret;
+ }
+
+ WL_DBG(("[ULB] ulb_mode set to %d successfully \n", mode));
+
+ return ret;
+}
+
+static s32
+wl_cfg80211_ulbbw_to_ulbchspec(u32 bw)
+{
+ if (bw == ULB_BW_DISABLED) {
+ return WL_CHANSPEC_BW_20;
+ } else if (bw == ULB_BW_10MHZ) {
+ return WL_CHANSPEC_BW_10;
+ } else if (bw == ULB_BW_5MHZ) {
+ return WL_CHANSPEC_BW_5;
+ } else if (bw == ULB_BW_2P5MHZ) {
+ return WL_CHANSPEC_BW_2P5;
+ } else {
+ WL_ERR(("[ULB] unsupported value for ulb_bw \n"));
+ return -EINVAL;
+ }
+}
+
+static chanspec_t
+wl_cfg80211_ulb_get_min_bw_chspec(struct wireless_dev *wdev, s32 bssidx)
+{
+ struct bcm_cfg80211 *cfg = NULL;
+ struct net_info *_netinfo = NULL;
+
+ /*
+ * Return the chspec value corresponding to the
+ * BW setting for a particular interface
+ */
+ if (wdev) {
+ /* if wdev is provided, use it */
+ cfg = WDEV_GET_CFG80211_PRIV(wdev);
+ }
+
+ if (!cfg) {
+ WL_ERR(("[ULB] bcm_cfg80211 is null \n"));
+ return INVCHANSPEC;
+ }
+
+ if (bssidx >= 0) {
+ /* if wdev is not provided, use it */
+ _netinfo = wl_get_netinfo_by_bssidx(cfg, bssidx);
+ } else {
+ _netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
+ }
+
+ if (unlikely(!_netinfo)) {
+ WL_ERR(("[ULB] net_info is null \n"));
+ return INVCHANSPEC;
+ }
+
+ if (_netinfo->ulb_bw) {
+ WL_DBG(("[ULB] wdev_ptr:%p ulb_bw:0x%x \n", _netinfo->wdev, _netinfo->ulb_bw));
+ return wl_cfg80211_ulbbw_to_ulbchspec(_netinfo->ulb_bw);
+ } else {
+ return WL_CHANSPEC_BW_20;
+ }
+}
+
+static s32
+wl_cfg80211_get_ulb_bw(struct wireless_dev *wdev)
+{
+ struct bcm_cfg80211 *cfg = WDEV_GET_CFG80211_PRIV(wdev);
+ struct net_info *_netinfo = wl_get_netinfo_by_wdev(cfg, wdev);
+
+ /*
+ * Return the ulb_bw setting for a
+ * particular interface
+ */
+ if (unlikely(!_netinfo)) {
+ WL_ERR(("[ULB] net_info is null \n"));
+ return -1;
+ }
+
+ return _netinfo->ulb_bw;
+}
+
+s32
+wl_cfg80211_set_ulb_bw(struct net_device *dev,
+ u32 ulb_bw, char *ifname)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ int ret;
+ int mode;
+ struct net_info *_netinfo = NULL, *iter, *next;
+ u32 bssidx;
+
+ if (!ifname)
+ return -EINVAL;
+
+ WL_DBG(("[ULB] Enter. bw_type:%d \n", ulb_bw));
+
+ ret = wldev_iovar_getint(dev, "ulb_mode", &mode);
+ if (unlikely(ret)) {
+ WL_ERR(("[ULB] ulb_mode not supported \n"));
+ return ret;
+ }
+
+ if (mode != ULB_MODE_STD_ALONE_MODE) {
+ WL_ERR(("[ULB] ulb bw modification allowed only in stand-alone mode\n"));
+ return -EINVAL;
+ }
+
+ if (ulb_bw >= MAX_SUPP_ULB_BW) {
+ WL_ERR(("[ULB] unsupported value (%d) for ulb_bw \n", ulb_bw));
+ return -EINVAL;
+ }
+
+#ifdef WL_CFG80211_P2P_DEV_IF
+ if (strcmp(ifname, "p2p-dev-wlan0") == 0) {
+ /* Use wdev corresponding to the dedicated p2p discovery interface */
+ if (likely(cfg->p2p_wdev)) {
+ _netinfo = wl_get_netinfo_by_wdev(cfg, cfg->p2p_wdev);
+ } else {
+ return -ENODEV;
+ }
+ }
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ if (!_netinfo) {
+ for_each_ndev(cfg, iter, next) {
+ if (iter->ndev) {
+ if (strncmp(iter->ndev->name, ifname, strlen(ifname)) == 0) {
+ _netinfo = wl_get_netinfo_by_netdev(cfg, iter->ndev);
+ }
+ }
+ }
+ }
+
+ if (!_netinfo)
+ return -ENODEV;
+ bssidx = _netinfo->bssidx;
+ _netinfo->ulb_bw = ulb_bw;
+
+
+ WL_DBG(("[ULB] Applying ulb_bw:%d for bssidx:%d \n", ulb_bw, bssidx));
+ ret = wldev_iovar_setbuf_bsscfg(dev, "ulb_bw", (void *)&ulb_bw, 4,
+ cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx,
+ &cfg->ioctl_buf_sync);
+ if (unlikely(ret)) {
+ WL_ERR(("[ULB] ulb_bw set failed. ret:%d \n", ret));
+ return ret;
+ }
+
+ return ret;
+}
+#endif /* WL11ULB */
+
+static void
+wl_ap_channel_ind(struct bcm_cfg80211 *cfg,
+ struct net_device *ndev,
+ chanspec_t chanspec)
+{
+ u32 channel = LCHSPEC_CHANNEL(chanspec);
+
+ WL_DBG(("(%s) AP channel:%d chspec:0x%x \n",
+ ndev->name, channel, chanspec));
+ if (cfg->ap_oper_channel && (cfg->ap_oper_channel != channel)) {
+ /*
+ * If cached channel is different from the channel indicated
+ * by the event, notify user space about the channel switch.
+ */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+ wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
+#endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
+ cfg->ap_oper_channel = channel;
+ }
+}
+
+static s32
+wl_ap_start_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+const wl_event_msg_t *e, void *data)
+{
+ struct net_device *ndev = NULL;
+ chanspec_t chanspec;
+
+ WL_DBG(("Enter\n"));
+ if (unlikely(e->status)) {
+ WL_ERR(("status:0x%x \n", e->status));
+ return -1;
+ }
+
+ if (!data) {
+ return -EINVAL;
+ }
+
+ if (likely(cfgdev)) {
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+ chanspec = *((chanspec_t *)data);
+
+ if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
+ /* For AP/GO role */
+ wl_ap_channel_ind(cfg, ndev, chanspec);
+ }
+ }
+
+ return 0;
+}
+
+static s32
+wl_csa_complete_ind(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+const wl_event_msg_t *e, void *data)
+{
+ int error = 0;
+ u32 chanspec = 0;
+ struct net_device *ndev = NULL;
+
+ WL_DBG(("Enter\n"));
+ if (unlikely(e->status)) {
+ WL_ERR(("status:0x%x \n", e->status));
+ return -1;
+ }
+
+ if (likely(cfgdev)) {
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+ error = wldev_iovar_getint(ndev, "chanspec", &chanspec);
+ if (unlikely(error)) {
+ WL_ERR(("Get chanspec error: %d \n", error));
+ return -1;
+ }
+
+ if (wl_get_mode_by_netdev(cfg, ndev) == WL_MODE_AP) {
+ /* For AP/GO role */
+ wl_ap_channel_ind(cfg, ndev, chanspec);
+ } else {
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
+ wl_cfg80211_ch_switch_notify(ndev, chanspec, bcmcfg_to_wiphy(cfg));
+#endif /* LINUX_VERSION_CODE >= (3, 5, 0) */
+ }
+
+ }
+
+ return 0;
+}
+
+#ifdef WL_NAN
+int
+wl_cfg80211_nan_cmd_handler(struct net_device *ndev, char *cmd, int cmd_len)
+{
+ return wl_cfgnan_cmd_handler(ndev, NETDEV_GET_CFG80211_PRIV(ndev), cmd, cmd_len);
+}
+#endif /* WL_NAN */
+
+void wl_cfg80211_clear_security(struct bcm_cfg80211 *cfg)
+{
+ struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
+ int err;
+
+ /* Clear the security settings on the primary Interface */
+ err = wldev_iovar_setint(dev, "wsec", 0);
+ if (unlikely(err)) {
+ WL_ERR(("wsec clear failed \n"));
+ }
+ err = wldev_iovar_setint(dev, "auth", 0);
+ if (unlikely(err)) {
+ WL_ERR(("auth clear failed \n"));
+ }
+ err = wldev_iovar_setint(dev, "wpa_auth", WPA_AUTH_DISABLED);
+ if (unlikely(err)) {
+ WL_ERR(("wpa_auth clear failed \n"));
+ }
+}
+
+#ifdef WL_CFG80211_P2P_DEV_IF
+void wl_cfg80211_del_p2p_wdev(void *cfg80211_priv)
+{
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)cfg80211_priv;
+ struct wireless_dev *wdev = NULL;
+
+ WL_DBG(("Enter \n"));
+ if (!cfg) {
+ WL_ERR(("Invalid Ptr\n"));
+ return;
+ } else {
+ wdev = cfg->p2p_wdev;
+ }
+
+ if (wdev && cfg->down_disc_if) {
+ wl_cfgp2p_del_p2p_disc_if(wdev, cfg);
+ cfg->down_disc_if = FALSE;
+ }
+}
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+#if defined(WL_SUPPORT_AUTO_CHANNEL)
+int
+wl_cfg80211_set_spect(struct net_device *dev, int spect)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ int down = 1;
+ int up = 1;
+ int err = BCME_OK;
+
+ if (!wl_get_drv_status_all(cfg, CONNECTED)) {
+ err = wldev_ioctl(dev, WLC_DOWN, &down, sizeof(down), true);
+ if (err) {
+ WL_ERR(("%s: WLC_DOWN failed: code: %d\n", __func__, err));
+ return err;
+ }
+
+ err = wldev_ioctl(dev, WLC_SET_SPECT_MANAGMENT, &spect, sizeof(spect), true);
+ if (err) {
+ WL_ERR(("%s: error setting spect: code: %d\n", __func__, err));
+ return err;
+ }
+
+ err = wldev_ioctl(dev, WLC_UP, &up, sizeof(up), true);
+ if (err) {
+ WL_ERR(("%s: WLC_UP failed: code: %d\n", __func__, err));
+ return err;
+ }
+ }
+ return err;
+}
+
+int
+wl_cfg80211_get_sta_channel(struct net_device *dev)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ int channel = 0;
+
+ if (wl_get_drv_status(cfg, CONNECTED, ndev)) {
+ channel = cfg->channel;
+ }
+ return channel;
+}
+#endif /* WL_SUPPORT_AUTO_CHANNEL */
+#ifdef P2P_LISTEN_OFFLOADING
+s32
+wl_cfg80211_p2plo_deinit(struct bcm_cfg80211 *cfg)
+{
+ s32 bssidx;
+ int ret = 0;
+ int p2plo_pause = 0;
+ if (!cfg || !cfg->p2p) {
+ WL_ERR(("Wl %p or cfg->p2p %p is null\n",
+ cfg, cfg ? cfg->p2p : 0));
+ return 0;
+ }
+
+ bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+ ret = wldev_iovar_setbuf_bsscfg(bcmcfg_to_prmry_ndev(cfg),
+ "p2po_stop", (void*)&p2plo_pause, sizeof(p2plo_pause),
+ cfg->ioctl_buf, WLC_IOCTL_SMLEN, bssidx, NULL);
+ if (ret < 0) {
+ WL_ERR(("p2po_stop Failed :%d\n", ret));
+ }
+
+ return ret;
+}
+s32
+wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+ wl_p2plo_listen_t p2plo_listen;
+ int ret = -EAGAIN;
+ int channel = 0;
+ int period = 0;
+ int interval = 0;
+ int count = 0;
+
+ if (WL_DRV_STATUS_SENDING_AF_FRM_EXT(cfg)) {
+ WL_ERR(("Sending Action Frames. Try it again.\n"));
+ goto exit;
+ }
+
+ if (wl_get_drv_status_all(cfg, SCANNING)) {
+ WL_ERR(("Scanning already\n"));
+ goto exit;
+ }
+
+ if (wl_get_drv_status(cfg, SCAN_ABORTING, dev)) {
+ WL_ERR(("Scanning being aborted\n"));
+ goto exit;
+ }
+
+ if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
+ WL_ERR(("p2p listen offloading already running\n"));
+ goto exit;
+ }
+
+ /* Just in case if it is not enabled */
+ if ((ret = wl_cfgp2p_enable_discovery(cfg, dev, NULL, 0)) < 0) {
+ WL_ERR(("cfgp2p_enable discovery failed"));
+ goto exit;
+ }
+
+ bzero(&p2plo_listen, sizeof(wl_p2plo_listen_t));
+
+ if (len) {
+ sscanf(buf, " %10d %10d %10d %10d", &channel, &period, &interval, &count);
+ if ((channel == 0) || (period == 0) ||
+ (interval == 0) || (count == 0)) {
+ WL_ERR(("Wrong argument %d/%d/%d/%d \n",
+ channel, period, interval, count));
+ ret = -EAGAIN;
+ goto exit;
+ }
+ p2plo_listen.period = period;
+ p2plo_listen.interval = interval;
+ p2plo_listen.count = count;
+
+ WL_ERR(("channel:%d period:%d, interval:%d count:%d\n",
+ channel, period, interval, count));
+ } else {
+ WL_ERR(("Argument len is wrong.\n"));
+ ret = -EAGAIN;
+ goto exit;
+ }
+
+ if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen_channel", (void*)&channel,
+ sizeof(channel), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
+ bssidx, &cfg->ioctl_buf_sync)) < 0) {
+ WL_ERR(("p2po_listen_channel Failed :%d\n", ret));
+ goto exit;
+ }
+
+ if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_listen", (void*)&p2plo_listen,
+ sizeof(wl_p2plo_listen_t), cfg->ioctl_buf, WLC_IOCTL_SMLEN,
+ bssidx, &cfg->ioctl_buf_sync)) < 0) {
+ WL_ERR(("p2po_listen Failed :%d\n", ret));
+ goto exit;
+ }
+
+ wl_set_p2p_status(cfg, DISC_IN_PROGRESS);
+ cfg->last_roc_id = P2PO_COOKIE;
+exit :
+ return ret;
+}
+s32
+wl_cfg80211_p2plo_listen_stop(struct net_device *dev)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ s32 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+ int ret = -EAGAIN;
+
+ if ((ret = wldev_iovar_setbuf_bsscfg(dev, "p2po_stop", NULL,
+ 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN,
+ bssidx, &cfg->ioctl_buf_sync)) < 0) {
+ WL_ERR(("p2po_stop Failed :%d\n", ret));
+ goto exit;
+ }
+
+exit:
+ return ret;
+}
+#endif /* P2P_LISTEN_OFFLOADING */
+u64
+wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 *cfg)
+{
+ u64 id = 0;
+ id = ++cfg->last_roc_id;
+#ifdef P2P_LISTEN_OFFLOADING
+ if (id == P2PO_COOKIE) {
+ id = ++cfg->last_roc_id;
+ }
+#endif /* P2P_LISTEN_OFFLOADING */
+ if (id == 0)
+ id = ++cfg->last_roc_id;
+ return id;
+}
+
+#if defined(SUPPORT_RANDOM_MAC_SCAN)
+int
+wl_cfg80211_set_random_mac(struct net_device *dev, bool enable)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ int ret;
+
+ if (cfg->random_mac_enabled == enable) {
+ WL_ERR(("Random MAC already %s\n", enable ? "Enabled" : "Disabled"));
+ return BCME_OK;
+ }
+
+ if (enable) {
+ ret = wl_cfg80211_random_mac_enable(dev);
+ } else {
+ ret = wl_cfg80211_random_mac_disable(dev);
+ }
+
+ if (!ret) {
+ cfg->random_mac_enabled = enable;
+ }
+
+ return ret;
+}
+
+int
+wl_cfg80211_random_mac_enable(struct net_device *dev)
+{
+ u8 current_mac[ETH_ALEN] = {0, };
+ s32 err = BCME_ERROR;
+ uint8 buffer[20] = {0, };
+ wl_scanmac_t *sm = NULL;
+ int len = 0;
+ wl_scanmac_enable_t *sm_enable = NULL;
+ wl_scanmac_config_t *sm_config = NULL;
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+
+ if (wl_get_drv_status_all(cfg, CONNECTED) || wl_get_drv_status_all(cfg, CONNECTING) ||
+ wl_get_drv_status_all(cfg, AP_CREATED) || wl_get_drv_status_all(cfg, AP_CREATING)) {
+ WL_ERR(("Fail to Set random mac, current state is wrong\n"));
+ return err;
+ }
+
+ /* Read current mac address */
+ err = wldev_iovar_getbuf_bsscfg(dev, "cur_etheraddr",
+ NULL, 0, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
+
+ if (err != BCME_OK) {
+ WL_ERR(("failed to get current dongle mac address\n"));
+ return err;
+ }
+
+ memcpy(current_mac, cfg->ioctl_buf, ETH_ALEN);
+
+ /* Enable scan mac */
+ sm = (wl_scanmac_t *)buffer;
+ sm_enable = (wl_scanmac_enable_t *)sm->data;
+ sm->len = sizeof(*sm_enable);
+ sm_enable->enable = 1;
+ len = OFFSETOF(wl_scanmac_t, data) + sm->len;
+ sm->subcmd_id = WL_SCANMAC_SUBCMD_ENABLE;
+
+ err = wldev_iovar_setbuf_bsscfg(dev, "scanmac",
+ sm, len, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
+
+ if (err != BCME_OK) {
+ WL_ERR(("failed to enable scanmac, err=%d\n", err));
+ return err;
+ }
+
+ /* Configure scanmac */
+ memset(buffer, 0x0, sizeof(buffer));
+ sm_config = (wl_scanmac_config_t *)sm->data;
+ sm->len = sizeof(*sm_config);
+ sm->subcmd_id = WL_SCANMAC_SUBCMD_CONFIG;
+ sm_config->scan_bitmap = WL_SCANMAC_SCAN_UNASSOC;
+
+ /* Set current mac address */
+ memcpy(&sm_config->mac.octet, current_mac, ETH_ALEN);
+ sm_config->mac.octet[3] = 0x0;
+ sm_config->mac.octet[4] = 0x0;
+ sm_config->mac.octet[5] = 0x0;
+
+ /* Set randomize mac address(last 3bytes) */
+ memset(&sm_config->random_mask.octet, 0x0, ETH_ALEN);
+ sm_config->random_mask.octet[3] = 0xff;
+ sm_config->random_mask.octet[4] = 0xff;
+ sm_config->random_mask.octet[5] = 0xff;
+
+ len = OFFSETOF(wl_scanmac_t, data) + sm->len;
+
+ err = wldev_iovar_setbuf_bsscfg(dev, "scanmac",
+ sm, len, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
+
+ if (err != BCME_OK) {
+ WL_ERR(("failed scanmac configuration\n"));
+
+ /* Disable scan mac for clean-up */
+ wl_cfg80211_random_mac_disable(dev);
+ return err;
+ }
+
+ WL_ERR(("random MAC enable done"));
+ return err;
+}
+
+int
+wl_cfg80211_random_mac_disable(struct net_device *dev)
+{
+ s32 err = BCME_ERROR;
+ uint8 buffer[20] = {0, };
+ wl_scanmac_t *sm = NULL;
+ int len = 0;
+ wl_scanmac_enable_t *sm_enable = NULL;
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+
+ sm = (wl_scanmac_t *)buffer;
+ sm_enable = (wl_scanmac_enable_t *)sm->data;
+ sm->len = sizeof(*sm_enable);
+ sm_enable->enable = 0;
+ len = OFFSETOF(wl_scanmac_t, data) + sm->len;
+
+ sm->subcmd_id = WL_SCANMAC_SUBCMD_ENABLE;
+
+ err = wldev_iovar_setbuf_bsscfg(dev, "scanmac",
+ sm, len, cfg->ioctl_buf, WLC_IOCTL_SMLEN, 0, &cfg->ioctl_buf_sync);
+
+ if (err != BCME_OK) {
+ WL_ERR(("failed to disable scanmac, err=%d\n", err));
+ return err;
+ }
+
+ WL_ERR(("random MAC disable done\n"));
+ return err;
+}
+#endif /* SUPPORT_RANDOM_MAC_SCAN */
+
+int
+wl_cfg80211_iface_count(struct net_device *dev)
+{
+ struct bcm_cfg80211 *cfg = NETDEV_GET_CFG80211_PRIV(dev);
+ struct net_info *iter, *next;
+ int iface_count = 0;
+
+ for_each_ndev(cfg, iter, next) {
+ if (iter->ndev) {
+ iface_count++;
+ }
+ }
+ return iface_count;
+}
+
+#ifdef DHD_LOG_DUMP
+struct bcm_cfg80211*
+wl_get_bcm_cfg80211_ptr(void)
+{
+ /* TODO: dynamically turning-off this feature
+ * for dual-pcie support as g_bcm_cfg80211 dep is removed.
+ * Need to support LOG_DUMP independant of private cfg80211 or dhd_pub.
+ */
+ return NULL;
+}
+#endif /* DHD_LOG_DUMP */
+
+#define CHECK_DONGLE_IDLE_TIME 50
+#define CHECK_DONGLE_IDLE_CNT 100
+int
+wl_check_dongle_idle(struct wiphy *wiphy)
+{
+ int error = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct net_device *primary_ndev;
+ int retry = 0;
+ struct channel_info ci;
+ if (!cfg)
+ return FALSE;
+ /* Use primary I/F for sending cmds down to firmware */
+ primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+
+ while (retry++ < CHECK_DONGLE_IDLE_CNT) {
+ error = wldev_ioctl(primary_ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false);
+ if (error != BCME_OK || ci.scan_channel != 0) {
+ if (error == -ENODEV) {
+ WL_ERR(("Firmware is not ready, return TRUE\n"));
+ return TRUE;
+ }
+ WL_ERR(("Firmware is busy(err:%d scan channel:%d). wait %dms\n",
+ error, ci.scan_channel, CHECK_DONGLE_IDLE_TIME));
+ } else {
+ break;
+ }
+ wl_delay(CHECK_DONGLE_IDLE_TIME);
+ }
+ if (retry >= CHECK_DONGLE_IDLE_CNT) {
+ WL_ERR(("DONGLE is BUSY too long\n"));
+ return FALSE;
+ }
+ WL_DBG(("DONGLE is idle\n"));
+ return TRUE;
+}
diff --git a/drivers/net/wireless/bcmdhd_1363/wl_cfg80211.h b/drivers/net/wireless/bcmdhd_1363/wl_cfg80211.h
new file mode 100644
index 000000000000..c1b3274e17b6
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/wl_cfg80211.h
@@ -0,0 +1,1572 @@
+/*
+ * Linux cfg80211 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wl_cfg80211.h 665052 2017-05-16 13:55:24Z $
+ */
+
+/**
+ * Older Linux versions support the 'iw' interface, more recent ones the 'cfg80211' interface.
+ */
+
+#ifndef _wl_cfg80211_h_
+#define _wl_cfg80211_h_
+
+#include <linux/wireless.h>
+#include <typedefs.h>
+#include <proto/ethernet.h>
+#include <wlioctl.h>
+#include <linux/wireless.h>
+#include <net/cfg80211.h>
+#include <linux/rfkill.h>
+
+#include <wl_cfgp2p.h>
+#include <linux/time.h>
+
+struct wl_conf;
+struct wl_iface;
+struct bcm_cfg80211;
+struct wl_security;
+struct wl_ibss;
+
+
+#define htod32(i) (i)
+#define htod16(i) (i)
+#define dtoh64(i) (i)
+#define dtoh32(i) (i)
+#define dtoh16(i) (i)
+#define htodchanspec(i) (i)
+#define dtohchanspec(i) (i)
+
+#define WL_DBG_NONE 0
+#define WL_DBG_P2P_ACTION (1 << 5)
+#define WL_DBG_TRACE (1 << 4)
+#define WL_DBG_SCAN (1 << 3)
+#define WL_DBG_DBG (1 << 2)
+#define WL_DBG_INFO (1 << 1)
+#define WL_DBG_ERR (1 << 0)
+
+#ifdef DHD_LOG_DUMP
+extern void dhd_log_dump_print(const char *fmt, ...);
+extern char *dhd_log_dump_get_timestamp(void);
+struct bcm_cfg80211 *wl_get_bcm_cfg80211_ptr(void);
+#endif /* DHD_LOG_DUMP */
+
+/* 0 invalidates all debug messages. default is 1 */
+#define WL_DBG_LEVEL 0xFF
+
+#ifdef CUSTOMER_HW4_DEBUG
+#define CFG80211_ERROR_TEXT "CFG80211-INFO2) "
+#else
+#define CFG80211_ERROR_TEXT "CFG80211-ERROR) "
+#endif /* CUSTOMER_HW4_DEBUG */
+
+#if defined(DHD_DEBUG)
+#ifdef DHD_LOG_DUMP
+#define WL_ERR(args) \
+do { \
+ if (wl_dbg_level & WL_DBG_ERR) { \
+ printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \
+ printk args; \
+ dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __func__); \
+ dhd_log_dump_print args; \
+ } \
+} while (0)
+#else
+#define WL_ERR(args) \
+do { \
+ if (wl_dbg_level & WL_DBG_ERR) { \
+ printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \
+ printk args; \
+ } \
+} while (0)
+#endif /* DHD_LOG_DUMP */
+#else /* defined(DHD_DEBUG) */
+#define WL_ERR(args) \
+do { \
+ if ((wl_dbg_level & WL_DBG_ERR) && net_ratelimit()) { \
+ printk(KERN_INFO CFG80211_ERROR_TEXT "%s : ", __func__); \
+ printk args; \
+ } \
+} while (0)
+#endif /* defined(DHD_DEBUG) */
+
+#ifdef WL_INFORM
+#undef WL_INFORM
+#endif
+
+#define WL_INFORM(args) \
+do { \
+ if (wl_dbg_level & WL_DBG_INFO) { \
+ printk(KERN_INFO "CFG80211-INFO) %s : ", __func__); \
+ printk args; \
+ } \
+} while (0)
+
+
+#ifdef WL_SCAN
+#undef WL_SCAN
+#endif
+#define WL_SCAN(args) \
+do { \
+ if (wl_dbg_level & WL_DBG_SCAN) { \
+ printk(KERN_INFO "CFG80211-SCAN) %s :", __func__); \
+ printk args; \
+ } \
+} while (0)
+#ifdef WL_TRACE
+#undef WL_TRACE
+#endif
+#define WL_TRACE(args) \
+do { \
+ if (wl_dbg_level & WL_DBG_TRACE) { \
+ printk(KERN_INFO "CFG80211-TRACE) %s :", __func__); \
+ printk args; \
+ } \
+} while (0)
+#ifdef WL_TRACE_HW4
+#undef WL_TRACE_HW4
+#endif
+#ifdef CUSTOMER_HW4_DEBUG
+#define WL_TRACE_HW4(args) \
+do { \
+ if (wl_dbg_level & WL_DBG_ERR) { \
+ printk(KERN_INFO "CFG80211-TRACE) %s : ", __func__); \
+ printk args; \
+ } \
+} while (0)
+#else
+#define WL_TRACE_HW4 WL_TRACE
+#endif /* CUSTOMER_HW4_DEBUG */
+#if (WL_DBG_LEVEL > 0)
+#define WL_DBG(args) \
+do { \
+ if (wl_dbg_level & WL_DBG_DBG) { \
+ printk(KERN_DEBUG "CFG80211-DEBUG) %s :", __func__); \
+ printk args; \
+ } \
+} while (0)
+#else /* !(WL_DBG_LEVEL > 0) */
+#define WL_DBG(args)
+#endif /* (WL_DBG_LEVEL > 0) */
+#define WL_PNO(x)
+#define WL_SD(x)
+
+
+#define WL_SCAN_RETRY_MAX 3
+#define WL_NUM_PMKIDS_MAX MAXPMKID
+#define WL_SCAN_BUF_MAX (1024 * 8)
+#define WL_TLV_INFO_MAX 1500
+#define WL_SCAN_IE_LEN_MAX 2048
+#define WL_BSS_INFO_MAX 2048
+#define WL_ASSOC_INFO_MAX 512
+#define WL_IOCTL_LEN_MAX 2048
+#define WL_EXTRA_BUF_MAX 2048
+#define WL_SCAN_ERSULTS_LAST (WL_SCAN_RESULTS_NO_MEM+1)
+#define WL_AP_MAX 256
+#define WL_FILE_NAME_MAX 256
+#define WL_DWELL_TIME 200
+#define WL_MED_DWELL_TIME 400
+#define WL_MIN_DWELL_TIME 100
+#define WL_LONG_DWELL_TIME 1000
+#define IFACE_MAX_CNT 4
+#define WL_SCAN_CONNECT_DWELL_TIME_MS 200
+#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20
+#define WL_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320
+#define WL_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400
+#define WL_AF_TX_MAX_RETRY 5
+
+#define WL_AF_SEARCH_TIME_MAX 450
+#define WL_AF_TX_EXTRA_TIME_MAX 200
+
+#define WL_SCAN_TIMER_INTERVAL_MS 10000 /* Scan timeout */
+#define WL_CHANNEL_SYNC_RETRY 5
+#define WL_INVALID -1
+
+#ifdef DHD_LOSSLESS_ROAMING
+#define WL_ROAM_TIMEOUT_MS 1000 /* Roam timeout */
+#endif
+/* Bring down SCB Timeout to 20secs from 60secs default */
+#ifndef WL_SCB_TIMEOUT
+#define WL_SCB_TIMEOUT 20
+#endif
+
+#ifndef WL_SCB_ACTIVITY_TIME
+#define WL_SCB_ACTIVITY_TIME 5
+#endif
+
+#ifndef WL_SCB_MAX_PROBE
+#define WL_SCB_MAX_PROBE 3
+#endif
+
+#ifndef WL_MIN_PSPRETEND_THRESHOLD
+#define WL_MIN_PSPRETEND_THRESHOLD 2
+#endif
+
+/* SCAN_SUPPRESS timer values in ms */
+#define WL_SCAN_SUPPRESS_TIMEOUT 31000 /* default Framwork DHCP timeout is 30 sec */
+#define WL_SCAN_SUPPRESS_RETRY 3000
+
+#define WL_PM_ENABLE_TIMEOUT 10000
+
+/* cfg80211 wowlan definitions */
+#define WL_WOWLAN_MAX_PATTERNS 8
+#define WL_WOWLAN_MIN_PATTERN_LEN 1
+#define WL_WOWLAN_MAX_PATTERN_LEN 255
+#define WL_WOWLAN_PKT_FILTER_ID_FIRST 201
+#define WL_WOWLAN_PKT_FILTER_ID_LAST (WL_WOWLAN_PKT_FILTER_ID_FIRST + \
+ WL_WOWLAN_MAX_PATTERNS - 1)
+
+#ifdef WLTDLS
+#define TDLS_TUNNELED_PRB_REQ "\x7f\x50\x6f\x9a\04"
+#define TDLS_TUNNELED_PRB_RESP "\x7f\x50\x6f\x9a\05"
+#endif /* WLTDLS */
+
+
+/* driver status */
+enum wl_status {
+ WL_STATUS_READY = 0,
+ WL_STATUS_SCANNING,
+ WL_STATUS_SCAN_ABORTING,
+ WL_STATUS_CONNECTING,
+ WL_STATUS_CONNECTED,
+ WL_STATUS_DISCONNECTING,
+ WL_STATUS_AP_CREATING,
+ WL_STATUS_AP_CREATED,
+ /* whole sending action frame procedure:
+ * includes a) 'finding common channel' for public action request frame
+ * and b) 'sending af via 'actframe' iovar'
+ */
+ WL_STATUS_SENDING_ACT_FRM,
+ /* find a peer to go to a common channel before sending public action req frame */
+ WL_STATUS_FINDING_COMMON_CHANNEL,
+ /* waiting for next af to sync time of supplicant.
+ * it includes SENDING_ACT_FRM and WAITING_NEXT_ACT_FRM_LISTEN
+ */
+ WL_STATUS_WAITING_NEXT_ACT_FRM,
+#ifdef WL_CFG80211_SYNC_GON
+ /* go to listen state to wait for next af after SENDING_ACT_FRM */
+ WL_STATUS_WAITING_NEXT_ACT_FRM_LISTEN,
+#endif /* WL_CFG80211_SYNC_GON */
+ /* it will be set when upper layer requests listen and succeed in setting listen mode.
+ * if set, other scan request can abort current listen state
+ */
+ WL_STATUS_REMAINING_ON_CHANNEL,
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ /* it's fake listen state to keep current scan state.
+ * it will be set when upper layer requests listen but scan is running. then just run
+ * a expire timer without actual listen state.
+ * if set, other scan request does not need to abort scan.
+ */
+ WL_STATUS_FAKE_REMAINING_ON_CHANNEL
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+};
+
+/* wi-fi mode */
+enum wl_mode {
+ WL_MODE_BSS,
+ WL_MODE_IBSS,
+ WL_MODE_AP
+};
+
+/* driver profile list */
+enum wl_prof_list {
+ WL_PROF_MODE,
+ WL_PROF_SSID,
+ WL_PROF_SEC,
+ WL_PROF_IBSS,
+ WL_PROF_BAND,
+ WL_PROF_CHAN,
+ WL_PROF_BSSID,
+ WL_PROF_ACT,
+ WL_PROF_BEACONINT,
+ WL_PROF_DTIMPERIOD
+};
+
+/* donlge escan state */
+enum wl_escan_state {
+ WL_ESCAN_STATE_IDLE,
+ WL_ESCAN_STATE_SCANING
+};
+/* fw downloading status */
+enum wl_fw_status {
+ WL_FW_LOADING_DONE,
+ WL_NVRAM_LOADING_DONE
+};
+
+enum wl_management_type {
+ WL_BEACON = 0x1,
+ WL_PROBE_RESP = 0x2,
+ WL_ASSOC_RESP = 0x4
+};
+
+enum wl_pm_workq_act_type {
+ WL_PM_WORKQ_SHORT,
+ WL_PM_WORKQ_LONG,
+ WL_PM_WORKQ_DEL
+};
+
+/* beacon / probe_response */
+struct beacon_proberesp {
+ __le64 timestamp;
+ __le16 beacon_int;
+ __le16 capab_info;
+ u8 variable[0];
+} __attribute__ ((packed));
+
+/* driver configuration */
+struct wl_conf {
+ u32 frag_threshold;
+ u32 rts_threshold;
+ u32 retry_short;
+ u32 retry_long;
+ s32 tx_power;
+ struct ieee80211_channel channel;
+};
+
+typedef s32(*EVENT_HANDLER) (struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+
+/* bss inform structure for cfg80211 interface */
+struct wl_cfg80211_bss_info {
+ u16 band;
+ u16 channel;
+ s16 rssi;
+ u16 frame_len;
+ u8 frame_buf[1];
+};
+
+/* basic structure of scan request */
+struct wl_scan_req {
+ struct wlc_ssid ssid;
+};
+
+/* basic structure of information element */
+struct wl_ie {
+ u16 offset;
+ u8 buf[WL_TLV_INFO_MAX];
+};
+
+/* event queue for cfg80211 main event */
+struct wl_event_q {
+ struct list_head eq_list;
+ u32 etype;
+ wl_event_msg_t emsg;
+ s8 edata[1];
+};
+
+/* security information with currently associated ap */
+struct wl_security {
+ u32 wpa_versions;
+ u32 auth_type;
+ u32 cipher_pairwise;
+ u32 cipher_group;
+ u32 wpa_auth;
+ u32 auth_assoc_res_status;
+};
+
+/* ibss information for currently joined ibss network */
+struct wl_ibss {
+ u8 beacon_interval; /* in millisecond */
+ u8 atim; /* in millisecond */
+ s8 join_only;
+ u8 band;
+ u8 channel;
+};
+
+typedef struct wl_bss_vndr_ies {
+ u8 probe_req_ie[VNDR_IES_BUF_LEN];
+ u8 probe_res_ie[VNDR_IES_MAX_BUF_LEN];
+ u8 assoc_req_ie[VNDR_IES_BUF_LEN];
+ u8 assoc_res_ie[VNDR_IES_BUF_LEN];
+ u8 beacon_ie[VNDR_IES_MAX_BUF_LEN];
+ u32 probe_req_ie_len;
+ u32 probe_res_ie_len;
+ u32 assoc_req_ie_len;
+ u32 assoc_res_ie_len;
+ u32 beacon_ie_len;
+} wl_bss_vndr_ies_t;
+
+typedef struct wl_cfgbss {
+ u8 *wpa_ie;
+ u8 *rsn_ie;
+ u8 *wps_ie;
+ bool security_mode;
+ struct wl_bss_vndr_ies ies; /* Common for STA, P2P GC, GO, AP, P2P Disc Interface */
+} wl_cfgbss_t;
+
+#ifdef WL11U
+/* Max length of Interworking element */
+#define IW_IES_MAX_BUF_LEN 9
+#endif
+
+/* cfg driver profile */
+struct wl_profile {
+ u32 mode;
+ s32 band;
+ u32 channel;
+ struct wlc_ssid ssid;
+ struct wl_security sec;
+ struct wl_ibss ibss;
+ u8 bssid[ETHER_ADDR_LEN];
+ u16 beacon_interval;
+ u8 dtim_period;
+ bool active;
+#ifdef SUPPORT_HIDDEN_AP
+ bool hidden_ssid;
+#endif /* SUPPORT_HIDDEN_AP */
+ u32 channel_width;
+#ifdef WL11U
+ u8 iw_ie[IW_IES_MAX_BUF_LEN];
+ u32 iw_ie_len;
+#endif /* WL11U */
+};
+
+struct net_info {
+ struct net_device *ndev;
+ struct wireless_dev *wdev;
+ struct wl_profile profile;
+ s32 mode;
+ s32 roam_off;
+ unsigned long sme_state;
+ bool pm_restore;
+ bool pm_block;
+ s32 pm;
+ s32 bssidx;
+ wl_cfgbss_t bss;
+ u32 ulb_bw;
+ struct list_head list; /* list of all net_info structure */
+};
+
+/* association inform */
+#define MAX_REQ_LINE 1024
+struct wl_connect_info {
+ u8 req_ie[MAX_REQ_LINE];
+ s32 req_ie_len;
+ u8 resp_ie[MAX_REQ_LINE];
+ s32 resp_ie_len;
+};
+
+/* firmware /nvram downloading controller */
+struct wl_fw_ctrl {
+ const struct firmware *fw_entry;
+ unsigned long status;
+ u32 ptr;
+ s8 fw_name[WL_FILE_NAME_MAX];
+ s8 nvram_name[WL_FILE_NAME_MAX];
+};
+
+/* assoc ie length */
+struct wl_assoc_ielen {
+ u32 req_len;
+ u32 resp_len;
+};
+
+/* wpa2 pmk list */
+struct wl_pmk_list {
+ pmkid_list_t pmkids;
+ pmkid_t foo[MAXPMKID - 1];
+};
+
+#ifdef DHD_MAX_IFS
+#define WL_MAX_IFS DHD_MAX_IFS
+#else
+#define WL_MAX_IFS 16
+#endif
+
+#define ESCAN_BUF_SIZE (64 * 1024)
+
+struct escan_info {
+ u32 escan_state;
+#if defined(STATIC_WL_PRIV_STRUCT)
+#ifndef CONFIG_DHD_USE_STATIC_BUF
+#error STATIC_WL_PRIV_STRUCT should be used with CONFIG_DHD_USE_STATIC_BUF
+#endif /* CONFIG_DHD_USE_STATIC_BUF */
+ u8 *escan_buf;
+#else
+ u8 escan_buf[ESCAN_BUF_SIZE];
+#endif /* STATIC_WL_PRIV_STRUCT */
+ struct wiphy *wiphy;
+ struct net_device *ndev;
+};
+
+#ifdef ESCAN_BUF_OVERFLOW_MGMT
+#define BUF_OVERFLOW_MGMT_COUNT 3
+typedef struct {
+ int RSSI;
+ int length;
+ struct ether_addr BSSID;
+} removal_element_t;
+#endif /* ESCAN_BUF_OVERFLOW_MGMT */
+
+struct afx_hdl {
+ wl_af_params_t *pending_tx_act_frm;
+ struct ether_addr tx_dst_addr;
+ struct net_device *dev;
+ struct work_struct work;
+ s32 bssidx;
+ u32 retry;
+ s32 peer_chan;
+ s32 peer_listen_chan; /* search channel: configured by upper layer */
+ s32 my_listen_chan; /* listen chanel: extract it from prb req or gon req */
+ bool is_listen;
+ bool ack_recv;
+ bool is_active;
+};
+
+struct parsed_ies {
+ wpa_ie_fixed_t *wps_ie;
+ u32 wps_ie_len;
+ wpa_ie_fixed_t *wpa_ie;
+ u32 wpa_ie_len;
+ bcm_tlv_t *wpa2_ie;
+ u32 wpa2_ie_len;
+};
+
+
+#ifdef P2P_LISTEN_OFFLOADING
+typedef struct {
+ uint16 period; /* listen offload period */
+ uint16 interval; /* listen offload interval */
+ uint16 count; /* listen offload count */
+ uint16 pad; /* pad for 32bit align */
+} wl_p2plo_listen_t;
+#endif /* P2P_LISTEN_OFFLOADING */
+
+#define MAX_EVENT_BUF_NUM 16
+typedef struct wl_eventmsg_buf {
+ u16 num;
+ struct {
+ u16 type;
+ bool set;
+ } event [MAX_EVENT_BUF_NUM];
+} wl_eventmsg_buf_t;
+
+typedef struct wl_if_event_info {
+ bool valid;
+ int ifidx;
+ int bssidx;
+ uint8 mac[ETHER_ADDR_LEN];
+ char name[IFNAMSIZ+1];
+} wl_if_event_info;
+
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
+#define GET_BSS_INFO_LEN 90
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
+
+
+/* private data of cfg80211 interface */
+struct bcm_cfg80211 {
+ struct wireless_dev *wdev; /* representing cfg cfg80211 device */
+
+ struct wireless_dev *p2p_wdev; /* representing cfg cfg80211 device for P2P */
+ struct net_device *p2p_net; /* reference to p2p0 interface */
+
+ struct wl_conf *conf;
+ struct cfg80211_scan_request *scan_request; /* scan request object */
+ EVENT_HANDLER evt_handler[WLC_E_LAST];
+ struct list_head eq_list; /* used for event queue */
+ struct list_head net_list; /* used for struct net_info */
+ spinlock_t net_list_sync; /* to protect scan status (and others if needed) */
+ spinlock_t eq_lock; /* for event queue synchronization */
+ spinlock_t cfgdrv_lock; /* to protect scan status (and others if needed) */
+ struct completion act_frm_scan;
+ struct completion iface_disable;
+ struct completion wait_next_af;
+ struct mutex usr_sync; /* maily for up/down synchronization */
+ struct mutex scan_complete; /* serialize scan_complete call */
+ struct wl_scan_results *bss_list;
+ struct wl_scan_results *scan_results;
+
+ /* scan request object for internal purpose */
+ struct wl_scan_req *scan_req_int;
+ /* information element object for internal purpose */
+#if defined(STATIC_WL_PRIV_STRUCT)
+ struct wl_ie *ie;
+#else
+ struct wl_ie ie;
+#endif
+
+ /* association information container */
+#if defined(STATIC_WL_PRIV_STRUCT)
+ struct wl_connect_info *conn_info;
+#else
+ struct wl_connect_info conn_info;
+#endif
+#ifdef DEBUGFS_CFG80211
+ struct dentry *debugfs;
+#endif /* DEBUGFS_CFG80211 */
+ struct wl_pmk_list *pmk_list; /* wpa2 pmk list */
+ tsk_ctl_t event_tsk; /* task of main event handler thread */
+ void *pub;
+ u32 iface_cnt;
+ u32 channel; /* current channel */
+ u32 af_sent_channel; /* channel action frame is sent */
+ /* next af subtype to cancel the remained dwell time in rx process */
+ u8 next_af_subtype;
+#ifdef WL_CFG80211_SYNC_GON
+ ulong af_tx_sent_jiffies;
+#endif /* WL_CFG80211_SYNC_GON */
+ struct escan_info escan_info; /* escan information */
+ bool active_scan; /* current scan mode */
+ bool ibss_starter; /* indicates this sta is ibss starter */
+ bool link_up; /* link/connection up flag */
+
+ /* indicate whether chip to support power save mode */
+ bool pwr_save;
+ bool roam_on; /* on/off switch for self-roaming */
+ bool scan_tried; /* indicates if first scan attempted */
+#if defined(BCMSDIO) || defined(BCMPCIE)
+ bool wlfc_on;
+#endif
+ bool vsdb_mode;
+ bool roamoff_on_concurrent;
+ u8 *ioctl_buf; /* ioctl buffer */
+ struct mutex ioctl_buf_sync;
+ u8 *escan_ioctl_buf;
+ u8 *extra_buf; /* maily to grab assoc information */
+ struct dentry *debugfsdir;
+ struct rfkill *rfkill;
+ bool rf_blocked;
+ struct ieee80211_channel remain_on_chan;
+ enum nl80211_channel_type remain_on_chan_type;
+ u64 send_action_id;
+ u64 last_roc_id;
+ wait_queue_head_t netif_change_event;
+ wl_if_event_info if_event_info;
+ struct completion send_af_done;
+ struct afx_hdl *afx_hdl;
+ struct p2p_info *p2p;
+ bool p2p_supported;
+ void *btcoex_info;
+ struct timer_list scan_timeout; /* Timer for catch scan event timeout */
+#if defined(P2P_IE_MISSING_FIX)
+ bool p2p_prb_noti;
+#endif
+ s32(*state_notifier) (struct bcm_cfg80211 *cfg,
+ struct net_info *_net_info, enum wl_status state, bool set);
+ unsigned long interrested_state;
+ wlc_ssid_t hostapd_ssid;
+ bool sched_scan_running; /* scheduled scan req status */
+#ifdef WL_SCHED_SCAN
+ struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */
+#endif /* WL_SCHED_SCAN */
+ bool scan_suppressed;
+ struct timer_list scan_supp_timer;
+ struct work_struct wlan_work;
+ struct mutex event_sync; /* maily for up/down synchronization */
+ bool disable_roam_event;
+ struct delayed_work pm_enable_work;
+ struct mutex pm_sync; /* mainly for pm work synchronization */
+ struct workqueue_struct *event_workq; /* workqueue for event */
+ struct work_struct event_work; /* work item for event */
+
+ vndr_ie_setbuf_t *ibss_vsie; /* keep the VSIE for IBSS */
+ int ibss_vsie_len;
+ u32 rmc_event_pid;
+ u32 rmc_event_seq;
+#ifdef WLAIBSS_MCHAN
+ struct ether_addr ibss_if_addr;
+ bcm_struct_cfgdev *ibss_cfgdev; /* For AIBSS */
+#endif /* WLAIBSS_MCHAN */
+ bool bss_pending_op; /* indicate where there is a pending IF operation */
+ int roam_offload;
+#ifdef WL_NAN
+ bool nan_enable;
+ bool nan_running;
+#endif /* WL_NAN */
+#ifdef WL_CFG80211_P2P_DEV_IF
+ bool down_disc_if;
+#endif /* WL_CFG80211_P2P_DEV_IF */
+#ifdef P2PLISTEN_AP_SAMECHN
+ bool p2p_resp_apchn_status;
+#endif /* P2PLISTEN_AP_SAMECHN */
+ struct wl_wsec_key wep_key;
+#ifdef WLTDLS
+ u8 *tdls_mgmt_frame;
+ u32 tdls_mgmt_frame_len;
+ s32 tdls_mgmt_freq;
+#endif /* WLTDLS */
+ bool need_wait_afrx;
+#ifdef QOS_MAP_SET
+ uint8 *up_table; /* user priority table, size is UP_TABLE_MAX */
+#endif /* QOS_MAP_SET */
+ struct ether_addr last_roamed_addr;
+#ifdef DHD_LOSSLESS_ROAMING
+ struct timer_list roam_timeout; /* Timer for catch roam timeout */
+#endif
+ bool rcc_enabled; /* flag for Roam channel cache feature */
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
+ char bss_info[GET_BSS_INFO_LEN];
+ wl_event_msg_t event_auth_assoc;
+ u32 assoc_reject_status;
+ u32 roam_count;
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
+ u16 ap_oper_channel;
+ bool revert_ndo_disable;
+#if defined(SUPPORT_RANDOM_MAC_SCAN)
+ bool random_mac_enabled;
+#endif /* SUPPORT_RANDOM_MAC_SCAN */
+#ifdef DHD_BANDSTEER
+ void *dhd_bandsteer_cntx;
+#endif /* DHD_BANDSTEER */
+};
+
+/* dual-pcie chip support */
+#define WDEV_GET_CFG80211_PRIV(wdev) ((struct bcm_cfg80211 *)wiphy_priv((wdev)->wiphy))
+#define NETDEV_GET_CFG80211_PRIV(net) ({ \
+ struct wireless_dev *__wdev = (struct wireless_dev *)net->ieee80211_ptr; \
+ WDEV_GET_CFG80211_PRIV(__wdev); })
+
+#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \
+ 4 && __GNUC_MINOR__ >= 6))
+
+#define BCM_LIST_FOR_EACH_ENTRY_SAFE(pos, next, head, member) \
+_Pragma("GCC diagnostic push") \
+_Pragma("GCC diagnostic ignored \"-Wcast-qual\"") \
+list_for_each_entry_safe((pos), (next), (head), member) \
+_Pragma("GCC diagnostic pop") \
+
+#else
+#define BCM_LIST_FOR_EACH_ENTRY_SAFE(pos, next, head, member) \
+list_for_each_entry_safe((pos), (next), (head), member) \
+
+#endif /* STRICT_GCC_WARNINGS */
+
+static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss)
+{
+ return bss = bss ?
+ (struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info;
+}
+
+static inline void
+wl_probe_wdev_all(struct bcm_cfg80211 *cfg)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+ int idx = 0;
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next,
+ &cfg->net_list, list) {
+ WL_ERR(("%s: net_list[%d] bssidx: %d, "
+ "ndev: %p, wdev: %p \n", __FUNCTION__,
+ idx++, _net_info->bssidx,
+ _net_info->ndev, _net_info->wdev));
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return;
+}
+
+static inline struct net_info *
+wl_get_netinfo_by_bssidx(struct bcm_cfg80211 *cfg, s32 bssidx)
+{
+ struct net_info *_net_info, *next, *info = NULL;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if ((bssidx >= 0) && (_net_info->bssidx == bssidx)) {
+ info = _net_info;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return info;
+}
+
+static inline void
+wl_dealloc_netinfo_by_wdev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+
+#ifdef DHD_IFDEBUG
+ WL_ERR(("dealloc_netinfo enter wdev=%p \n", wdev));
+#endif
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (wdev && (_net_info->wdev == wdev)) {
+ wl_cfgbss_t *bss = &_net_info->bss;
+
+ kfree(bss->wpa_ie);
+ bss->wpa_ie = NULL;
+ kfree(bss->rsn_ie);
+ bss->rsn_ie = NULL;
+ kfree(bss->wps_ie);
+ bss->wps_ie = NULL;
+ list_del(&_net_info->list);
+ cfg->iface_cnt--;
+ kfree(_net_info);
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+#ifdef DHD_IFDEBUG
+ WL_ERR(("dealloc_netinfo exit iface_cnt=%d \n", cfg->iface_cnt));
+#endif
+}
+
+static inline s32
+wl_alloc_netinfo(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ struct wireless_dev * wdev, s32 mode, bool pm_block, u8 bssidx)
+{
+ struct net_info *_net_info;
+ s32 err = 0;
+ unsigned long int flags;
+#ifdef DHD_IFDEBUG
+ WL_ERR(("alloc_netinfo enter bssidx=%d wdev=%p ndev=%p\n", bssidx, wdev, ndev));
+#endif
+ /* Check whether there is any duplicate entry for the
+ * same bssidx *
+ */
+ if ((_net_info = wl_get_netinfo_by_bssidx(cfg, bssidx))) {
+ /* We have a duplicate entry for the same bssidx
+ * already present which shouldn't have been the case.
+ * Attempt recovery.
+ */
+ WL_ERR(("Duplicate entry for bssidx=%d present\n", bssidx));
+ wl_probe_wdev_all(cfg);
+#ifdef DHD_DEBUG
+ ASSERT(0);
+#endif /* DHD_DEBUG */
+ WL_ERR(("Removing the Dup entry for bssidx=%d \n", bssidx));
+ wl_dealloc_netinfo_by_wdev(cfg, _net_info->wdev);
+ }
+ if (cfg->iface_cnt == IFACE_MAX_CNT)
+ return -ENOMEM;
+ _net_info = kzalloc(sizeof(struct net_info), GFP_KERNEL);
+ if (!_net_info)
+ err = -ENOMEM;
+ else {
+ _net_info->mode = mode;
+ _net_info->ndev = ndev;
+ _net_info->wdev = wdev;
+ _net_info->pm_restore = 0;
+ _net_info->pm = 0;
+ _net_info->pm_block = pm_block;
+ _net_info->roam_off = WL_INVALID;
+ _net_info->bssidx = bssidx;
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ cfg->iface_cnt++;
+ list_add(&_net_info->list, &cfg->net_list);
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ }
+#ifdef DHD_IFDEBUG
+ WL_ERR(("alloc_netinfo exit iface_cnt=%d \n", cfg->iface_cnt));
+#endif
+ return err;
+}
+
+static inline void
+wl_delete_all_netinfo(struct bcm_cfg80211 *cfg)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ wl_cfgbss_t *bss = &_net_info->bss;
+
+ kfree(bss->wpa_ie);
+ bss->wpa_ie = NULL;
+ kfree(bss->rsn_ie);
+ bss->rsn_ie = NULL;
+ kfree(bss->wps_ie);
+ bss->wps_ie = NULL;
+ list_del(&_net_info->list);
+ if (_net_info->wdev)
+ kfree(_net_info->wdev);
+ kfree(_net_info);
+ }
+ cfg->iface_cnt = 0;
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+}
+static inline u32
+wl_get_status_all(struct bcm_cfg80211 *cfg, s32 status)
+
+{
+ struct net_info *_net_info, *next;
+ u32 cnt = 0;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (_net_info->ndev &&
+ test_bit(status, &_net_info->sme_state))
+ cnt++;
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return cnt;
+}
+static inline void
+wl_set_status_all(struct bcm_cfg80211 *cfg, s32 status, u32 op)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ switch (op) {
+ case 1:
+ break; /* set all status is not allowed */
+ case 2:
+ /*
+ * Release the spinlock before calling notifier. Else there
+ * will be nested calls
+ */
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ clear_bit(status, &_net_info->sme_state);
+ if (cfg->state_notifier &&
+ test_bit(status, &(cfg->interrested_state)))
+ cfg->state_notifier(cfg, _net_info, status, false);
+ return;
+ case 4:
+ break; /* change all status is not allowed */
+ default:
+ break; /* unknown operation */
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+}
+static inline void
+wl_set_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status,
+ struct net_device *ndev, u32 op)
+{
+
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev)) {
+ switch (op) {
+ case 1:
+ /*
+ * Release the spinlock before calling notifier. Else there
+ * will be nested calls
+ */
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ set_bit(status, &_net_info->sme_state);
+ if (cfg->state_notifier &&
+ test_bit(status, &(cfg->interrested_state)))
+ cfg->state_notifier(cfg, _net_info, status, true);
+ return;
+ case 2:
+ /*
+ * Release the spinlock before calling notifier. Else there
+ * will be nested calls
+ */
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ clear_bit(status, &_net_info->sme_state);
+ if (cfg->state_notifier &&
+ test_bit(status, &(cfg->interrested_state)))
+ cfg->state_notifier(cfg, _net_info, status, false);
+ return;
+ case 4:
+ change_bit(status, &_net_info->sme_state);
+ break;
+ }
+ }
+
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+
+}
+
+static inline wl_cfgbss_t *
+wl_get_cfgbss_by_wdev(struct bcm_cfg80211 *cfg,
+ struct wireless_dev *wdev)
+{
+ struct net_info *_net_info, *next;
+ wl_cfgbss_t *bss = NULL;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (wdev && (_net_info->wdev == wdev)) {
+ bss = &_net_info->bss;
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return bss;
+}
+
+static inline u32
+wl_get_status_by_netdev(struct bcm_cfg80211 *cfg, s32 status,
+ struct net_device *ndev)
+{
+ struct net_info *_net_info, *next;
+ u32 stat = 0;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev)) {
+ stat = test_bit(status, &_net_info->sme_state);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return stat;
+}
+
+static inline s32
+wl_get_mode_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ struct net_info *_net_info, *next;
+ s32 mode = -1;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev)) {
+ mode = _net_info->mode;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return mode;
+}
+
+static inline void
+wl_set_mode_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ s32 mode)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev))
+ _net_info->mode = mode;
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+}
+
+static inline s32
+wl_get_bssidx_by_wdev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev)
+{
+ struct net_info *_net_info, *next;
+ s32 bssidx = -1;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (_net_info->wdev && (_net_info->wdev == wdev)) {
+ bssidx = _net_info->bssidx;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return bssidx;
+}
+
+static inline struct wireless_dev *
+wl_get_wdev_by_bssidx(struct bcm_cfg80211 *cfg, s32 bssidx)
+{
+ struct net_info *_net_info, *next;
+ struct wireless_dev *wdev = NULL;
+ unsigned long int flags;
+
+ if (bssidx < 0)
+ return NULL;
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (_net_info->bssidx == bssidx) {
+ wdev = _net_info->wdev;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return wdev;
+}
+
+static inline struct wl_profile *
+wl_get_profile_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ struct net_info *_net_info, *next;
+ struct wl_profile *prof = NULL;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev)) {
+ prof = &_net_info->profile;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return prof;
+}
+static inline struct net_info *
+wl_get_netinfo_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ struct net_info *_net_info, *next, *info = NULL;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev)) {
+ info = _net_info;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return info;
+}
+
+static inline struct net_info *
+wl_get_netinfo_by_wdev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev)
+{
+ struct net_info *_net_info, *next, *info = NULL;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (wdev && (_net_info->wdev == wdev)) {
+ info = _net_info;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return info;
+}
+
+static inline u32
+wl_get_chanwidth_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+ u32 info = 0;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev)) {
+ info = _net_info->profile.channel_width;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return info;
+}
+
+static inline void
+wl_set_chanwidth_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev, u32 chanwidth)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev))
+ _net_info->profile.channel_width = chanwidth;
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+}
+
+#ifdef WL11U
+static inline void
+wl_get_iwdata_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev, u8 *iw_ie,
+ u32 *iw_ie_len)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev)) {
+ *iw_ie_len = _net_info->profile.iw_ie_len;
+ memcpy(iw_ie, _net_info->profile.iw_ie, _net_info->profile.iw_ie_len);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+}
+
+static inline void
+wl_set_iwdata_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev, u8 *iw_ie, u32 iw_ie_len)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev)) {
+ _net_info->profile.iw_ie_len = iw_ie_len;
+ memcpy(_net_info->profile.iw_ie, iw_ie, _net_info->profile.iw_ie_len);
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+}
+
+static inline void
+wl_clear_iwdata_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next, &cfg->net_list, list) {
+ if (ndev && (_net_info->ndev == ndev)) {
+ _net_info->profile.iw_ie_len = 0;
+ memset(_net_info->profile.iw_ie, 0, IW_IES_MAX_BUF_LEN);
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+}
+
+static inline void
+wl_clear_iwdata(struct bcm_cfg80211 *cfg)
+{
+ struct net_info *_net_info, *next;
+ unsigned long int flags;
+ spin_lock_irqsave(&cfg->net_list_sync, flags);
+ BCM_LIST_FOR_EACH_ENTRY_SAFE(_net_info, next,
+ &cfg->net_list, list) {
+ if (_net_info->profile.iw_ie_len) {
+ _net_info->profile.iw_ie_len = 0;
+ memset(_net_info->profile.iw_ie, 0, IW_IES_MAX_BUF_LEN);
+ }
+ }
+ spin_unlock_irqrestore(&cfg->net_list_sync, flags);
+ return;
+}
+#endif /* WL11U */
+
+#define is_p2p_group_iface(wdev) (((wdev->iftype == NL80211_IFTYPE_P2P_GO) || \
+ (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) ? 1 : 0)
+#define bcmcfg_to_wiphy(cfg) (cfg->wdev->wiphy)
+#define bcmcfg_to_prmry_ndev(cfg) (cfg->wdev->netdev)
+#define bcmcfg_to_prmry_wdev(cfg) (cfg->wdev)
+#define bcmcfg_to_p2p_wdev(cfg) (cfg->p2p_wdev)
+#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr))
+#define ndev_to_wdev(ndev) (ndev->ieee80211_ptr)
+#define wdev_to_ndev(wdev) (wdev->netdev)
+
+#if defined(WL_ENABLE_P2P_IF)
+#define ndev_to_wlc_ndev(ndev, cfg) ((ndev == cfg->p2p_net) ? \
+ bcmcfg_to_prmry_ndev(cfg) : ndev)
+#else
+#define ndev_to_wlc_ndev(ndev, cfg) (ndev)
+#endif /* WL_ENABLE_P2P_IF */
+
+#define wdev_to_wlc_ndev(wdev, cfg) \
+ (wdev_to_ndev(wdev) ? \
+ wdev_to_ndev(wdev) : bcmcfg_to_prmry_ndev(cfg))
+#if defined(WL_CFG80211_P2P_DEV_IF)
+#define cfgdev_to_wlc_ndev(cfgdev, cfg) wdev_to_wlc_ndev(cfgdev, cfg)
+#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) bcmcfg_to_prmry_wdev(cfg)
+#elif defined(WL_ENABLE_P2P_IF)
+#define cfgdev_to_wlc_ndev(cfgdev, cfg) ndev_to_wlc_ndev(cfgdev, cfg)
+#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) bcmcfg_to_prmry_ndev(cfg)
+#else
+#define cfgdev_to_wlc_ndev(cfgdev, cfg) (cfgdev)
+#define bcmcfg_to_prmry_cfgdev(cfgdev, cfg) (cfgdev)
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+#define cfgdev_to_wdev(cfgdev) (cfgdev)
+#define ndev_to_cfgdev(ndev) ndev_to_wdev(ndev)
+#define cfgdev_to_ndev(cfgdev) (cfgdev ? (cfgdev->netdev) : NULL)
+#define wdev_to_cfgdev(cfgdev) (cfgdev)
+#define discover_cfgdev(cfgdev, cfg) (cfgdev->iftype == NL80211_IFTYPE_P2P_DEVICE)
+#else
+#define cfgdev_to_wdev(cfgdev) (cfgdev->ieee80211_ptr)
+#define wdev_to_cfgdev(cfgdev) cfgdev ? (cfgdev->netdev) : NULL
+#define ndev_to_cfgdev(ndev) (ndev)
+#define cfgdev_to_ndev(cfgdev) (cfgdev)
+#define discover_cfgdev(cfgdev, cfg) (cfgdev == cfg->p2p_net)
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+#define scan_req_match(cfg) (((cfg) && (cfg->scan_request) && \
+ (cfg->scan_request->wdev == cfg->p2p_wdev)) ? true : false)
+#elif defined(WL_ENABLE_P2P_IF)
+#define scan_req_match(cfg) (((cfg) && (cfg->scan_request) && \
+ (cfg->scan_request->dev == cfg->p2p_net)) ? true : false)
+#else
+#define scan_req_match(cfg) (((cfg) && p2p_is_on(cfg) && p2p_scan(cfg)) ? \
+ true : false)
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
+#define scan_req_iftype(req) (req->dev->ieee80211_ptr->iftype)
+#else
+#define scan_req_iftype(req) (req->wdev->iftype)
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) */
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
+#define IEEE80211_BAND_2GHZ NL80211_BAND_2GHZ
+#define IEEE80211_BAND_5GHZ NL80211_BAND_5GHZ
+#define IEEE80211_NUM_BANDS NUM_NL80211_BANDS
+#endif
+
+#define wl_to_sr(w) (w->scan_req_int)
+#if defined(STATIC_WL_PRIV_STRUCT)
+#define wl_to_ie(w) (w->ie)
+#define wl_to_conn(w) (w->conn_info)
+#else
+#define wl_to_ie(w) (&w->ie)
+#define wl_to_conn(w) (&w->conn_info)
+#endif
+#define wiphy_from_scan(w) (w->escan_info.wiphy)
+#define wl_get_drv_status_all(cfg, stat) \
+ (wl_get_status_all(cfg, WL_STATUS_ ## stat))
+#define wl_get_drv_status(cfg, stat, ndev) \
+ (wl_get_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev))
+#define wl_set_drv_status(cfg, stat, ndev) \
+ (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 1))
+#define wl_clr_drv_status(cfg, stat, ndev) \
+ (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 2))
+#define wl_clr_drv_status_all(cfg, stat) \
+ (wl_set_status_all(cfg, WL_STATUS_ ## stat, 2))
+#define wl_chg_drv_status(cfg, stat, ndev) \
+ (wl_set_status_by_netdev(cfg, WL_STATUS_ ## stat, ndev, 4))
+
+#define for_each_bss(list, bss, __i) \
+ for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss))
+
+#define for_each_ndev(cfg, iter, next) \
+ list_for_each_entry_safe(iter, next, &cfg->net_list, list)
+
+/* In case of WPS from wpa_supplicant, pairwise siute and group suite is 0.
+ * In addtion to that, wpa_version is WPA_VERSION_1
+ */
+#define is_wps_conn(_sme) \
+ ((wl_cfgp2p_find_wpsie((u8 *)_sme->ie, _sme->ie_len) != NULL) && \
+ (!_sme->crypto.n_ciphers_pairwise) && \
+ (!_sme->crypto.cipher_group))
+
+#define IS_AKM_SUITE_FT(sec) ({BCM_REFERENCE(sec); FALSE;})
+
+#define IS_AKM_SUITE_CCKM(sec) ({BCM_REFERENCE(sec); FALSE;})
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
+#define STA_INFO_BIT(info) (1ul << NL80211_STA_ ## info)
+#define strnicmp(str1, str2, len) strncasecmp((str1), (str2), (len))
+#else
+#define STA_INFO_BIT(info) (STATION_ ## info)
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) */
+
+extern void *wl_cfg80211_attach(struct net_device *ndev, void *context);
+extern s32 wl_cfg80211_attach_post(struct net_device *ndev);
+extern void wl_cfg80211_detach(void *cfg80211_priv);
+
+extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e,
+ void *data);
+void wl_cfg80211_set_parent_dev(void *dev);
+struct device *wl_cfg80211_get_parent_dev(void);
+
+/* clear IEs */
+extern s32 wl_cfg80211_clear_mgmt_vndr_ies(struct bcm_cfg80211 *cfg);
+extern s32 wl_cfg80211_clear_per_bss_ies(struct bcm_cfg80211 *cfg, s32 bssidx);
+
+extern s32 wl_cfg80211_up(void *para);
+extern s32 wl_cfg80211_down(void *para);
+extern s32 wl_cfg80211_notify_ifadd(void *cfg80211_priv, int ifidx, char *name,
+ uint8 *mac, uint8 bssidx);
+extern s32 wl_cfg80211_notify_ifdel(void *cfg80211_priv, int ifidx, char *name,
+ uint8 *mac, uint8 bssidx);
+extern s32 wl_cfg80211_notify_ifchange(void *cfg80211_priv, int ifidx, char *name,
+ uint8 *mac, uint8 bssidx);
+extern struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, char *name,
+ uint8 *mac, uint8 bssidx, char *dngl_name);
+extern int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev);
+extern int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg, int ifidx, struct net_device* ndev);
+extern int wl_cfg80211_scan_stop(bcm_struct_cfgdev *cfgdev);
+extern bool wl_cfg80211_is_concurrent_mode(struct bcm_cfg80211 *cfg);
+extern void *wl_cfg80211_get_dhdp(struct net_device *net);
+extern bool wl_cfg80211_is_p2p_active(struct wireless_dev *wdev);
+extern bool wl_cfg80211_is_roam_offload(struct bcm_cfg80211 *cfg);
+extern bool wl_cfg80211_is_event_from_connected_bssid(void *cfg80211_priv,
+ const wl_event_msg_t *e, int ifidx);
+extern void wl_cfg80211_dbg_level(u32 level);
+extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
+extern s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len);
+extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len);
+extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
+ enum wl_management_type type);
+extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len);
+extern s32 wl_cfg80211_set_p2p_ecsa(struct net_device *net, char* buf, int len);
+extern s32 wl_cfg80211_increase_p2p_bw(struct net_device *net, char* buf, int len);
+#ifdef WL11ULB
+extern s32 wl_cfg80211_set_ulb_mode(struct net_device *dev, int mode);
+extern s32 wl_cfg80211_set_ulb_bw(struct net_device *dev,
+ u32 ulb_bw, char *ifname);
+#endif /* WL11ULB */
+#ifdef P2PLISTEN_AP_SAMECHN
+extern s32 wl_cfg80211_set_p2p_resp_ap_chn(struct net_device *net, s32 enable);
+#endif /* P2PLISTEN_AP_SAMECHN */
+
+/* btcoex functions */
+void* wl_cfg80211_btcoex_init(struct net_device *ndev);
+void wl_cfg80211_btcoex_deinit(void);
+
+#ifdef WL_SUPPORT_AUTO_CHANNEL
+#define CHANSPEC_BUF_SIZE 1024
+#define CHAN_SEL_IOCTL_DELAY 300
+#define CHAN_SEL_RETRY_COUNT 15
+#define CHANNEL_IS_RADAR(channel) (((channel & WL_CHAN_RADAR) || \
+ (channel & WL_CHAN_PASSIVE)) ? true : false)
+#define CHANNEL_IS_2G(channel) (((channel >= 1) && (channel <= 14)) ? \
+ true : false)
+#define CHANNEL_IS_5G(channel) (((channel >= 36) && (channel <= 165)) ? \
+ true : false)
+extern s32 wl_cfg80211_get_best_channels(struct net_device *dev, char* command,
+ int total_len);
+#endif /* WL_SUPPORT_AUTO_CHANNEL */
+extern int wl_cfg80211_ether_atoe(const char *a, struct ether_addr *n);
+extern int wl_cfg80211_hang(struct net_device *dev, u16 reason);
+extern s32 wl_mode_to_nl80211_iftype(s32 mode);
+int wl_cfg80211_do_driver_init(struct net_device *net);
+void wl_cfg80211_enable_trace(bool set, u32 level);
+extern s32 wl_update_wiphybands(struct bcm_cfg80211 *cfg, bool notify, bool user_sync);
+extern s32 wl_cfg80211_if_is_group_owner(void);
+extern chanspec_t wl_chspec_host_to_driver(chanspec_t chanspec);
+extern chanspec_t wl_ch_host_to_driver(struct wireless_dev *wdev, s32 bssidx, u16 channel);
+extern s32 wl_set_tx_power(struct net_device *dev,
+ enum nl80211_tx_power_setting type, s32 dbm);
+extern s32 wl_get_tx_power(struct net_device *dev, s32 *dbm);
+extern s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add);
+extern void wl_stop_wait_next_action_frame(struct bcm_cfg80211 *cfg, struct net_device *ndev);
+extern void wl_cfg80211_add_to_eventbuffer(wl_eventmsg_buf_t *ev, u16 event, bool set);
+extern s32 wl_cfg80211_apply_eventbuffer(struct net_device *ndev,
+ struct bcm_cfg80211 *cfg, wl_eventmsg_buf_t *ev);
+extern void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac);
+extern void wl_cfg80211_update_power_mode(struct net_device *dev);
+extern void wl_cfg80211_set_passive_scan(struct net_device *dev, char *command);
+extern void wl_terminate_event_handler(void *cfg80211_priv);
+#if defined(DHD_ENABLE_BIGDATA_LOGGING)
+extern s32 wl_cfg80211_get_bss_info(struct net_device *dev, char* cmd, int total_len);
+extern s32 wl_cfg80211_get_connect_failed_status(struct net_device *dev, char* cmd, int total_len);
+#endif /* DHD_ENABLE_BIGDATA_LOGGING */
+
+#define SCAN_BUF_CNT 2
+#define SCAN_BUF_NEXT 1
+#define WL_SCANTYPE_LEGACY 0x1
+#define WL_SCANTYPE_P2P 0x2
+#define wl_escan_set_sync_id(a, b) ((a) = htod16(0x1234))
+#define wl_escan_set_type(a, b)
+#define wl_escan_get_buf(a, b) ((wl_scan_results_t *) (a)->escan_info.escan_buf)
+#define wl_escan_check_sync_id(a, b, c) 0
+#define wl_escan_print_sync_id(a, b, c)
+#define wl_escan_increment_sync_id(a, b)
+#define wl_escan_init_sync_id(a)
+extern void wl_cfg80211_ibss_vsie_set_buffer(struct net_device *dev,
+ vndr_ie_setbuf_t *ibss_vsie, int ibss_vsie_len);
+extern s32 wl_cfg80211_ibss_vsie_delete(struct net_device *dev);
+extern void wl_cfg80211_set_rmc_pid(struct net_device *dev, int pid);
+extern int wl_cfg80211_set_mgmt_vndr_ies(struct bcm_cfg80211 *cfg,
+ bcm_struct_cfgdev *cfgdev, s32 bssidx, s32 pktflag,
+ const u8 *vndr_ie, u32 vndr_ie_len);
+
+
+/* Action frame specific functions */
+extern u8 wl_get_action_category(void *frame, u32 frame_len);
+extern int wl_get_public_action(void *frame, u32 frame_len, u8 *ret_action);
+
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+struct net_device *wl_cfg80211_get_remain_on_channel_ndev(struct bcm_cfg80211 *cfg);
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+
+#ifdef WL_SUPPORT_ACS
+#define ACS_MSRMNT_DELAY 1000 /* dump_obss delay in ms */
+#define IOCTL_RETRY_COUNT 5
+#define CHAN_NOISE_DUMMY -80
+#define OBSS_TOKEN_IDX 15
+#define IBSS_TOKEN_IDX 15
+#define TX_TOKEN_IDX 14
+#define CTG_TOKEN_IDX 13
+#define PKT_TOKEN_IDX 15
+#define IDLE_TOKEN_IDX 12
+#endif /* WL_SUPPORT_ACS */
+
+extern int wl_cfg80211_get_ioctl_version(void);
+extern int wl_cfg80211_enable_roam_offload(struct net_device *dev, int enable);
+extern s32 wl_cfg80211_dfs_ap_move(struct net_device *ndev, char *data,
+ char *command, int total_len);
+extern s32 wl_cfg80211_wbtext_config(struct net_device *ndev, char *data,
+ char *command, int total_len);
+extern int wl_cfg80211_wbtext_weight_config(struct net_device *ndev, char *data,
+ char *command, int total_len);
+extern int wl_cfg80211_wbtext_table_config(struct net_device *ndev, char *data,
+ char *command, int total_len);
+extern s32 wl_cfg80211_wbtext_delta_config(struct net_device *ndev, char *data,
+ char *command, int total_len);
+extern s32 wl_cfg80211_get_chanspecs_2g(struct net_device *ndev,
+ void *buf, s32 buflen);
+extern s32 wl_cfg80211_get_chanspecs_5g(struct net_device *ndev,
+ void *buf, s32 buflen);
+#if defined(WL_VIRTUAL_APSTA)
+extern int wl_cfg80211_interface_create(struct net_device *dev, char *name);
+extern int wl_cfg80211_interface_delete(struct net_device *dev, char *name);
+#if defined(PKT_FILTER_SUPPORT) && defined(APSTA_BLOCK_ARP_DURING_DHCP)
+extern void wl_cfg80211_block_arp(struct net_device *dev, int enable);
+#endif /* PKT_FILTER_SUPPORT && APSTA_BLOCK_ARP_DURING_DHCP */
+#endif /* defined (WL_VIRTUAL_APSTA) */
+
+#ifdef WL_NAN
+extern int wl_cfg80211_nan_cmd_handler(struct net_device *ndev, char *cmd,
+ int cmd_len);
+#endif /* WL_NAN */
+
+#ifdef WL_CFG80211_P2P_DEV_IF
+extern void wl_cfg80211_del_p2p_wdev(void *cfg80211_priv);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+#if defined(WL_SUPPORT_AUTO_CHANNEL)
+extern int wl_cfg80211_set_spect(struct net_device *dev, int spect);
+extern int wl_cfg80211_get_sta_channel(struct net_device *dev);
+#endif /* WL_SUPPORT_AUTO_CHANNEL */
+
+#ifdef P2P_LISTEN_OFFLOADING
+extern s32 wl_cfg80211_p2plo_listen_start(struct net_device *dev, u8 *buf, int len);
+extern s32 wl_cfg80211_p2plo_listen_stop(struct net_device *dev);
+#endif /* P2P_LISTEN_OFFLOADING */
+
+#define RETURN_EIO_IF_NOT_UP(wlpriv) \
+do { \
+ struct net_device *checkSysUpNDev = bcmcfg_to_prmry_ndev(wlpriv); \
+ if (unlikely(!wl_get_drv_status(wlpriv, READY, checkSysUpNDev))) { \
+ WL_INFORM(("device is not ready\n")); \
+ return -EIO; \
+ } \
+} while (0)
+
+#ifdef QOS_MAP_SET
+extern uint8 *wl_get_up_table(void *cfg80211_priv);
+#endif /* QOS_MAP_SET */
+
+#define P2PO_COOKIE 65535
+u64 wl_cfg80211_get_new_roc_id(struct bcm_cfg80211 *cfg);
+#if defined(SUPPORT_RANDOM_MAC_SCAN)
+int wl_cfg80211_set_random_mac(struct net_device *dev, bool enable);
+int wl_cfg80211_random_mac_enable(struct net_device *dev);
+int wl_cfg80211_random_mac_disable(struct net_device *dev);
+#endif /* SUPPORT_RANDOM_MAC_SCAN */
+int wl_cfg80211_iface_count(struct net_device *dev);
+int wl_check_dongle_idle(struct wiphy *wiphy);
+#endif /* _wl_cfg80211_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/wl_cfg_btcoex.c b/drivers/net/wireless/bcmdhd_1363/wl_cfg_btcoex.c
new file mode 100644
index 000000000000..93aa29bf4428
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/wl_cfg_btcoex.c
@@ -0,0 +1,564 @@
+/*
+ * 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wl_cfg_btcoex.c 638301 2016-05-17 09:06:40Z $
+ */
+
+#include <net/rtnetlink.h>
+
+#include <bcmutils.h>
+#include <wldev_common.h>
+#include <wl_cfg80211.h>
+#include <dhd_cfg80211.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhdioctl.h>
+#include <wlioctl.h>
+
+#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
+
+struct btcoex_info {
+ struct timer_list timer;
+ u32 timer_ms;
+ u32 timer_on;
+ u32 ts_dhcp_start; /* ms ts ecord time stats */
+ u32 ts_dhcp_ok; /* ms ts ecord time stats */
+ bool dhcp_done; /* flag, indicates that host done with
+ * dhcp before t1/t2 expiration
+ */
+ s32 bt_state;
+ struct work_struct work;
+ struct net_device *dev;
+};
+
+static struct btcoex_info *btcoex_info_loc = NULL;
+
+/* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */
+
+/* use New SCO/eSCO smart YG suppression */
+#define BT_DHCP_eSCO_FIX
+/* this flag boost wifi pkt priority to max, caution: -not fair to sco */
+#define BT_DHCP_USE_FLAGS
+/* T1 start SCO/ESCo priority suppression */
+#define BT_DHCP_OPPR_WIN_TIME 2500
+/* T2 turn off SCO/SCO supperesion is (timeout) */
+#define BT_DHCP_FLAG_FORCE_TIME 5500
+
+enum wl_cfg80211_btcoex_status {
+ BT_DHCP_IDLE,
+ BT_DHCP_START,
+ BT_DHCP_OPPR_WIN,
+ BT_DHCP_FLAG_FORCE_TIMEOUT
+};
+
+/*
+ * get named driver variable to uint register value and return error indication
+ * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, &reg_value)
+ */
+static int
+dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
+ uint reg, int *retval)
+{
+ union {
+ char buf[WLC_IOCTL_SMLEN];
+ int val;
+ } var;
+ int error;
+
+ bcm_mkiovar(name, (char *)(&reg), sizeof(reg),
+ (char *)(&var), sizeof(var.buf));
+ error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false);
+
+ *retval = dtoh32(var.val);
+ return (error);
+}
+
+static int
+dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
+{
+ char ioctlbuf_local[WLC_IOCTL_SMLEN];
+
+ bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local));
+
+ return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true));
+}
+/*
+get named driver variable to uint register value and return error indication
+calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
+*/
+static int
+dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
+{
+ char reg_addr[8];
+
+ memset(reg_addr, 0, sizeof(reg_addr));
+ memcpy((char *)&reg_addr[0], (char *)addr, 4);
+ memcpy((char *)&reg_addr[4], (char *)val, 4);
+
+ return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
+}
+
+static bool btcoex_is_sco_active(struct net_device *dev)
+{
+ int ioc_res = 0;
+ bool res = FALSE;
+ int sco_id_cnt = 0;
+ int param27;
+ int i;
+
+ for (i = 0; i < 12; i++) {
+
+ ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
+
+ WL_TRACE(("sample[%d], btc params: 27:%x\n", i, param27));
+
+ if (ioc_res < 0) {
+ WL_ERR(("ioc read btc params error\n"));
+ break;
+ }
+
+ if ((param27 & 0x6) == 2) { /* count both sco & esco */
+ sco_id_cnt++;
+ }
+
+ if (sco_id_cnt > 2) {
+ WL_TRACE(("sco/esco detected, pkt id_cnt:%d samples:%d\n",
+ sco_id_cnt, i));
+ res = TRUE;
+ break;
+ }
+
+ OSL_SLEEP(5);
+ }
+
+ return res;
+}
+
+#if defined(BT_DHCP_eSCO_FIX)
+/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
+static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
+{
+ static bool saved_status = FALSE;
+
+ char buf_reg50va_dhcp_on[8] =
+ { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
+ char buf_reg51va_dhcp_on[8] =
+ { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ char buf_reg64va_dhcp_on[8] =
+ { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ char buf_reg65va_dhcp_on[8] =
+ { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ char buf_reg71va_dhcp_on[8] =
+ { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
+ uint32 regaddr;
+ static uint32 saved_reg50;
+ static uint32 saved_reg51;
+ static uint32 saved_reg64;
+ static uint32 saved_reg65;
+ static uint32 saved_reg71;
+
+ if (trump_sco) {
+ /* this should reduce eSCO agressive retransmit
+ * w/o breaking it
+ */
+
+ /* 1st save current */
+ WL_TRACE(("Do new SCO/eSCO coex algo {save &"
+ "override}\n"));
+ if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
+ saved_status = TRUE;
+ WL_TRACE(("saved bt_params[50,51,64,65,71]:"
+ "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ saved_reg50, saved_reg51,
+ saved_reg64, saved_reg65, saved_reg71));
+ } else {
+ WL_ERR((":%s: save btc_params failed\n",
+ __FUNCTION__));
+ saved_status = FALSE;
+ return -1;
+ }
+
+ WL_TRACE(("override with [50,51,64,65,71]:"
+ "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ *(u32 *)(buf_reg50va_dhcp_on+4),
+ *(u32 *)(buf_reg51va_dhcp_on+4),
+ *(u32 *)(buf_reg64va_dhcp_on+4),
+ *(u32 *)(buf_reg65va_dhcp_on+4),
+ *(u32 *)(buf_reg71va_dhcp_on+4)));
+
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg50va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg51va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg64va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg65va_dhcp_on[0], 8);
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg71va_dhcp_on[0], 8);
+
+ saved_status = TRUE;
+ } else if (saved_status) {
+ /* restore previously saved bt params */
+ WL_TRACE(("Do new SCO/eSCO coex algo {save &"
+ "override}\n"));
+
+ regaddr = 50;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg50);
+ regaddr = 51;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg51);
+ regaddr = 64;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg64);
+ regaddr = 65;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg65);
+ regaddr = 71;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg71);
+
+ WL_TRACE(("restore bt_params[50,51,64,65,71]:"
+ "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ saved_reg50, saved_reg51, saved_reg64,
+ saved_reg65, saved_reg71));
+
+ saved_status = FALSE;
+ } else {
+ WL_ERR((":%s att to restore not saved BTCOEX params\n",
+ __FUNCTION__));
+ return -1;
+ }
+ return 0;
+}
+#endif /* BT_DHCP_eSCO_FIX */
+
+static void
+wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
+{
+#if defined(BT_DHCP_USE_FLAGS)
+ char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
+ char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
+#endif
+
+
+#if defined(BT_DHCP_eSCO_FIX)
+ /* set = 1, save & turn on 0 - off & restore prev settings */
+ set_btc_esco_params(dev, set);
+#endif
+
+#if defined(BT_DHCP_USE_FLAGS)
+ WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
+ if (set == TRUE)
+ /* Forcing bt_flag7 */
+ dev_wlc_bufvar_set(dev, "btc_flags",
+ (char *)&buf_flag7_dhcp_on[0],
+ sizeof(buf_flag7_dhcp_on));
+ else
+ /* Restoring default bt flag7 */
+ dev_wlc_bufvar_set(dev, "btc_flags",
+ (char *)&buf_flag7_default[0],
+ sizeof(buf_flag7_default));
+#endif
+}
+
+static void wl_cfg80211_bt_timerfunc(ulong data)
+{
+ struct btcoex_info *bt_local = (struct btcoex_info *)data;
+ WL_TRACE(("Enter\n"));
+ bt_local->timer_on = 0;
+ schedule_work(&bt_local->work);
+}
+
+static void wl_cfg80211_bt_handler(struct work_struct *work)
+{
+ struct btcoex_info *btcx_inf;
+
+ btcx_inf = container_of(work, struct btcoex_info, work);
+
+ if (btcx_inf->timer_on) {
+ btcx_inf->timer_on = 0;
+ del_timer_sync(&btcx_inf->timer);
+ }
+
+ switch (btcx_inf->bt_state) {
+ case BT_DHCP_START:
+ /* DHCP started
+ * provide OPPORTUNITY window to get DHCP address
+ */
+ WL_TRACE(("bt_dhcp stm: started \n"));
+
+ btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
+ mod_timer(&btcx_inf->timer,
+ jiffies + msecs_to_jiffies(BT_DHCP_OPPR_WIN_TIME));
+ btcx_inf->timer_on = 1;
+ break;
+
+ case BT_DHCP_OPPR_WIN:
+ if (btcx_inf->dhcp_done) {
+ WL_TRACE(("DHCP Done before T1 expiration\n"));
+ goto btc_coex_idle;
+ }
+
+ /* DHCP is not over yet, start lowering BT priority
+ * enforce btc_params + flags if necessary
+ */
+ WL_TRACE(("DHCP T1:%d expired\n", BT_DHCP_OPPR_WIN_TIME));
+ if (btcx_inf->dev)
+ wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
+ btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
+ mod_timer(&btcx_inf->timer,
+ jiffies + msecs_to_jiffies(BT_DHCP_FLAG_FORCE_TIME));
+ btcx_inf->timer_on = 1;
+ break;
+
+ case BT_DHCP_FLAG_FORCE_TIMEOUT:
+ if (btcx_inf->dhcp_done) {
+ WL_TRACE(("DHCP Done before T2 expiration\n"));
+ } else {
+ /* Noo dhcp during T1+T2, restore BT priority */
+ WL_TRACE(("DHCP wait interval T2:%d msec expired\n",
+ BT_DHCP_FLAG_FORCE_TIME));
+ }
+
+ /* Restoring default bt priority */
+ if (btcx_inf->dev)
+ wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
+btc_coex_idle:
+ btcx_inf->bt_state = BT_DHCP_IDLE;
+ btcx_inf->timer_on = 0;
+ break;
+
+ default:
+ WL_ERR(("error g_status=%d !!!\n", btcx_inf->bt_state));
+ if (btcx_inf->dev)
+ wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
+ btcx_inf->bt_state = BT_DHCP_IDLE;
+ btcx_inf->timer_on = 0;
+ break;
+ }
+
+ net_os_wake_unlock(btcx_inf->dev);
+}
+
+void* wl_cfg80211_btcoex_init(struct net_device *ndev)
+{
+ struct btcoex_info *btco_inf = NULL;
+
+ btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
+ if (!btco_inf)
+ return NULL;
+
+ btco_inf->bt_state = BT_DHCP_IDLE;
+ btco_inf->ts_dhcp_start = 0;
+ btco_inf->ts_dhcp_ok = 0;
+ /* Set up timer for BT */
+ btco_inf->timer_ms = 10;
+ init_timer(&btco_inf->timer);
+ btco_inf->timer.data = (ulong)btco_inf;
+ btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
+
+ btco_inf->dev = ndev;
+
+ INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
+
+ btcoex_info_loc = btco_inf;
+ return btco_inf;
+}
+
+void wl_cfg80211_btcoex_deinit()
+{
+ if (!btcoex_info_loc)
+ return;
+
+ if (btcoex_info_loc->timer_on) {
+ btcoex_info_loc->timer_on = 0;
+ del_timer_sync(&btcoex_info_loc->timer);
+ }
+
+ cancel_work_sync(&btcoex_info_loc->work);
+
+ kfree(btcoex_info_loc);
+}
+
+int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command)
+{
+
+ struct btcoex_info *btco_inf = btcoex_info_loc;
+ char powermode_val = 0;
+ char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
+ char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
+ char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
+
+ uint32 regaddr;
+ static uint32 saved_reg66;
+ static uint32 saved_reg41;
+ static uint32 saved_reg68;
+ static bool saved_status = FALSE;
+
+ char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
+
+ /* Figure out powermode 1 or o command */
+ strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1);
+
+ if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
+ WL_TRACE_HW4(("DHCP session starts\n"));
+
+
+#ifdef PKT_FILTER_SUPPORT
+ dhd->dhcp_in_progress = 1;
+
+#if defined(WL_VIRTUAL_APSTA) && defined(APSTA_BLOCK_ARP_DURING_DHCP)
+ if ((dhd->op_mode & DHD_FLAG_CONCURR_STA_HOSTAP_MODE) ==
+ DHD_FLAG_CONCURR_STA_HOSTAP_MODE) {
+ /* Block ARP frames while DHCP of STA interface is in
+ * progress in case of STA/SoftAP concurrent mode
+ */
+ wl_cfg80211_block_arp(dev, TRUE);
+ } else
+#endif /* WL_VIRTUAL_APSTA && APSTA_BLOCK_ARP_DURING_DHCP */
+ if (dhd->early_suspended) {
+ WL_TRACE_HW4(("DHCP in progressing , disable packet filter!!!\n"));
+ dhd_enable_packet_filter(0, dhd);
+ }
+#endif /* PKT_FILTER_SUPPORT */
+
+ /* Retrieve and saved orig regs value */
+ if ((saved_status == FALSE) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) &&
+ (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) {
+ saved_status = TRUE;
+ WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
+ saved_reg66, saved_reg41, saved_reg68));
+
+ /* Disable PM mode during dhpc session */
+
+ /* Disable PM mode during dhpc session */
+ /* Start BT timer only for SCO connection */
+ if (btcoex_is_sco_active(dev)) {
+ /* btc_params 66 */
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg66va_dhcp_on[0],
+ sizeof(buf_reg66va_dhcp_on));
+ /* btc_params 41 0x33 */
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg41va_dhcp_on[0],
+ sizeof(buf_reg41va_dhcp_on));
+ /* btc_params 68 0x190 */
+ dev_wlc_bufvar_set(dev, "btc_params",
+ (char *)&buf_reg68va_dhcp_on[0],
+ sizeof(buf_reg68va_dhcp_on));
+ saved_status = TRUE;
+
+ btco_inf->bt_state = BT_DHCP_START;
+ btco_inf->timer_on = 1;
+ mod_timer(&btco_inf->timer, btco_inf->timer.expires);
+ WL_TRACE(("enable BT DHCP Timer\n"));
+ }
+ }
+ else if (saved_status == TRUE) {
+ WL_ERR(("was called w/o DHCP OFF. Continue\n"));
+ }
+ }
+ else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
+
+
+
+#ifdef PKT_FILTER_SUPPORT
+ dhd->dhcp_in_progress = 0;
+ WL_TRACE_HW4(("DHCP is complete \n"));
+
+#if defined(WL_VIRTUAL_APSTA) && defined(APSTA_BLOCK_ARP_DURING_DHCP)
+ if ((dhd->op_mode & DHD_FLAG_CONCURR_STA_HOSTAP_MODE) ==
+ DHD_FLAG_CONCURR_STA_HOSTAP_MODE) {
+ /* Unblock ARP frames */
+ wl_cfg80211_block_arp(dev, FALSE);
+ } else
+#endif /* WL_VIRTUAL_APSTA && APSTA_BLOCK_ARP_DURING_DHCP */
+ if (dhd->early_suspended) {
+ /* Enable packet filtering */
+ WL_TRACE_HW4(("DHCP is complete , enable packet filter!!!\n"));
+ dhd_enable_packet_filter(1, dhd);
+ }
+#endif /* PKT_FILTER_SUPPORT */
+
+ /* Restoring PM mode */
+
+ /* Stop any bt timer because DHCP session is done */
+ WL_TRACE(("disable BT DHCP Timer\n"));
+ if (btco_inf->timer_on) {
+ btco_inf->timer_on = 0;
+ del_timer_sync(&btco_inf->timer);
+
+ if (btco_inf->bt_state != BT_DHCP_IDLE) {
+ /* need to restore original btc flags & extra btc params */
+ WL_TRACE(("bt->bt_state:%d\n", btco_inf->bt_state));
+ /* wake up btcoex thread to restore btlags+params */
+ schedule_work(&btco_inf->work);
+ }
+ }
+
+ /* Restoring btc_flag paramter anyway */
+ if (saved_status == TRUE)
+ dev_wlc_bufvar_set(dev, "btc_flags",
+ (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
+
+ /* Restore original values */
+ if (saved_status == TRUE) {
+ regaddr = 66;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg66);
+ regaddr = 41;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg41);
+ regaddr = 68;
+ dev_wlc_intvar_set_reg(dev, "btc_params",
+ (char *)&regaddr, (char *)&saved_reg68);
+
+ WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
+ saved_reg66, saved_reg41, saved_reg68));
+ }
+ saved_status = FALSE;
+
+ }
+ else {
+ WL_ERR(("Unkwown yet power setting, ignored\n"));
+ }
+
+ snprintf(command, 3, "OK");
+
+ return (strlen("OK"));
+}
diff --git a/drivers/net/wireless/bcmdhd_1363/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd_1363/wl_cfgp2p.c
new file mode 100644
index 000000000000..604ca1e9fa92
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/wl_cfgp2p.c
@@ -0,0 +1,2614 @@
+/*
+ * Linux cfgp2p 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wl_cfgp2p.c 653898 2016-08-10 07:50:39Z $
+ *
+ */
+#include <typedefs.h>
+#include <linuxver.h>
+#include <osl.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/if_arp.h>
+#include <asm/uaccess.h>
+
+#include <bcmutils.h>
+#include <bcmendian.h>
+#include <proto/ethernet.h>
+#include <proto/802.11.h>
+#include <net/rtnetlink.h>
+
+#include <wl_cfg80211.h>
+#include <wl_cfgp2p.h>
+#include <wldev_common.h>
+#include <wl_android.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhd_linux.h>
+#include <dhdioctl.h>
+#include <wlioctl.h>
+#include <dhd_cfg80211.h>
+
+static s8 scanparambuf[WLC_IOCTL_SMLEN];
+static bool
+wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
+
+static s32 wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ struct wireless_dev *wdev, bool notify);
+
+#if defined(WL_ENABLE_P2P_IF)
+static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev);
+static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd);
+static int wl_cfgp2p_if_open(struct net_device *net);
+static int wl_cfgp2p_if_stop(struct net_device *net);
+
+static const struct net_device_ops wl_cfgp2p_if_ops = {
+ .ndo_open = wl_cfgp2p_if_open,
+ .ndo_stop = wl_cfgp2p_if_stop,
+ .ndo_do_ioctl = wl_cfgp2p_do_ioctl,
+ .ndo_start_xmit = wl_cfgp2p_start_xmit,
+};
+#endif /* WL_ENABLE_P2P_IF */
+
+
+bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len)
+{
+ wifi_p2p_pub_act_frame_t *pact_frm;
+
+ if (frame == NULL)
+ return false;
+ pact_frm = (wifi_p2p_pub_act_frame_t *)frame;
+ if (frame_len < sizeof(wifi_p2p_pub_act_frame_t) -1)
+ return false;
+
+ if (pact_frm->category == P2P_PUB_AF_CATEGORY &&
+ pact_frm->action == P2P_PUB_AF_ACTION &&
+ pact_frm->oui_type == P2P_VER &&
+ memcmp(pact_frm->oui, P2P_OUI, sizeof(pact_frm->oui)) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len)
+{
+ wifi_p2p_action_frame_t *act_frm;
+
+ if (frame == NULL)
+ return false;
+ act_frm = (wifi_p2p_action_frame_t *)frame;
+ if (frame_len < sizeof(wifi_p2p_action_frame_t) -1)
+ return false;
+
+ if (act_frm->category == P2P_AF_CATEGORY &&
+ act_frm->type == P2P_VER &&
+ memcmp(act_frm->OUI, P2P_OUI, DOT11_OUI_LEN) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+#define GAS_RESP_LEN 2
+#define DOUBLE_TLV_BODY_OFF 4
+#define GAS_RESP_OFFSET 4
+#define GAS_CRESP_OFFSET 5
+
+bool wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len)
+{
+ bcm_tlv_t *ie = (bcm_tlv_t *)data;
+ u8 *frame = NULL;
+ u16 id, flen;
+
+ /* Skipped first ANQP Element, if frame has anqp elemnt */
+ ie = bcm_parse_tlvs(ie, (int)len, DOT11_MNG_ADVERTISEMENT_ID);
+
+ if (ie == NULL)
+ return false;
+
+ frame = (uint8 *)ie + ie->len + TLV_HDR_LEN + GAS_RESP_LEN;
+ id = ((u16) (((frame)[1] << 8) | (frame)[0]));
+ flen = ((u16) (((frame)[3] << 8) | (frame)[2]));
+
+ /* If the contents match the OUI and the type */
+ if (flen >= WFA_OUI_LEN + 1 &&
+ id == P2PSD_GAS_NQP_INFOID &&
+ !bcmp(&frame[DOUBLE_TLV_BODY_OFF], (const uint8*)WFA_OUI, WFA_OUI_LEN) &&
+ subtype == frame[DOUBLE_TLV_BODY_OFF+WFA_OUI_LEN]) {
+ return true;
+ }
+
+ return false;
+}
+
+bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len)
+{
+
+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm;
+
+ if (frame == NULL)
+ return false;
+
+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame;
+ if (frame_len < (sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1))
+ return false;
+ if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)
+ return false;
+
+#ifdef WL11U
+ if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP)
+ return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE,
+ (u8 *)sd_act_frm->query_data + GAS_RESP_OFFSET,
+ frame_len);
+
+ else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP)
+ return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE,
+ (u8 *)sd_act_frm->query_data + GAS_CRESP_OFFSET,
+ frame_len);
+ else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ ||
+ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ)
+ return true;
+ else
+ return false;
+#else
+ if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ ||
+ sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP ||
+ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ ||
+ sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP)
+ return true;
+ else
+ return false;
+#endif /* WL11U */
+}
+
+bool wl_cfgp2p_is_p2p_gas_action(void *frame, u32 frame_len)
+{
+
+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm;
+
+ if (frame == NULL)
+ return false;
+
+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame;
+ if (frame_len < (sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1))
+ return false;
+ if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)
+ return false;
+
+ if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ)
+ return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE,
+ (u8 *)sd_act_frm->query_data,
+ frame_len);
+ else
+ return false;
+}
+
+void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel)
+{
+ wifi_p2p_pub_act_frame_t *pact_frm;
+ wifi_p2p_action_frame_t *act_frm;
+ wifi_p2psd_gas_pub_act_frame_t *sd_act_frm;
+ if (!frame || frame_len <= 2)
+ return;
+
+ if (wl_cfgp2p_is_pub_action(frame, frame_len)) {
+ pact_frm = (wifi_p2p_pub_act_frame_t *)frame;
+ switch (pact_frm->subtype) {
+ case P2P_PAF_GON_REQ:
+ CFGP2P_ACTION(("%s P2P Group Owner Negotiation Req Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_PAF_GON_RSP:
+ CFGP2P_ACTION(("%s P2P Group Owner Negotiation Rsp Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_PAF_GON_CONF:
+ CFGP2P_ACTION(("%s P2P Group Owner Negotiation Confirm Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_PAF_INVITE_REQ:
+ CFGP2P_ACTION(("%s P2P Invitation Request Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_PAF_INVITE_RSP:
+ CFGP2P_ACTION(("%s P2P Invitation Response Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_PAF_DEVDIS_REQ:
+ CFGP2P_ACTION(("%s P2P Device Discoverability Request Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_PAF_DEVDIS_RSP:
+ CFGP2P_ACTION(("%s P2P Device Discoverability Response Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_PAF_PROVDIS_REQ:
+ CFGP2P_ACTION(("%s P2P Provision Discovery Request Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_PAF_PROVDIS_RSP:
+ CFGP2P_ACTION(("%s P2P Provision Discovery Response Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ default:
+ CFGP2P_ACTION(("%s Unknown Public Action Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+
+ }
+
+ } else if (wl_cfgp2p_is_p2p_action(frame, frame_len)) {
+ act_frm = (wifi_p2p_action_frame_t *)frame;
+ switch (act_frm->subtype) {
+ case P2P_AF_NOTICE_OF_ABSENCE:
+ CFGP2P_ACTION(("%s P2P Notice of Absence Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_AF_PRESENCE_REQ:
+ CFGP2P_ACTION(("%s P2P Presence Request Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_AF_PRESENCE_RSP:
+ CFGP2P_ACTION(("%s P2P Presence Response Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ case P2P_AF_GO_DISC_REQ:
+ CFGP2P_ACTION(("%s P2P Discoverability Request Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ break;
+ default:
+ CFGP2P_ACTION(("%s Unknown P2P Action Frame,"
+ " channel=%d\n", (tx)? "TX": "RX", channel));
+ }
+
+ } else if (wl_cfgp2p_is_gas_action(frame, frame_len)) {
+ sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame;
+ switch (sd_act_frm->action) {
+ case P2PSD_ACTION_ID_GAS_IREQ:
+ CFGP2P_ACTION(("%s GAS Initial Request,"
+ " channel=%d\n", (tx)? "TX" : "RX", channel));
+ break;
+ case P2PSD_ACTION_ID_GAS_IRESP:
+ CFGP2P_ACTION(("%s GAS Initial Response,"
+ " channel=%d\n", (tx)? "TX" : "RX", channel));
+ break;
+ case P2PSD_ACTION_ID_GAS_CREQ:
+ CFGP2P_ACTION(("%s GAS Comback Request,"
+ " channel=%d\n", (tx)? "TX" : "RX", channel));
+ break;
+ case P2PSD_ACTION_ID_GAS_CRESP:
+ CFGP2P_ACTION(("%s GAS Comback Response,"
+ " channel=%d\n", (tx)? "TX" : "RX", channel));
+ break;
+ default:
+ CFGP2P_ACTION(("%s Unknown GAS Frame,"
+ " channel=%d\n", (tx)? "TX" : "RX", channel));
+ }
+
+
+ }
+}
+
+/*
+ * Initialize variables related to P2P
+ *
+ */
+s32
+wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg)
+{
+ if (!(cfg->p2p = kzalloc(sizeof(struct p2p_info), GFP_KERNEL))) {
+ CFGP2P_ERR(("struct p2p_info allocation failed\n"));
+ return -ENOMEM;
+ }
+
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY) = bcmcfg_to_prmry_ndev(cfg);
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY) = 0;
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL;
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1) = NULL;
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION1) = -1;
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION2) = NULL;
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION2) = -1;
+ return BCME_OK;
+
+}
+/*
+ * Deinitialize variables related to P2P
+ *
+ */
+void
+wl_cfgp2p_deinit_priv(struct bcm_cfg80211 *cfg)
+{
+ CFGP2P_ERR(("In\n"));
+ if (cfg->p2p) {
+ kfree(cfg->p2p);
+ cfg->p2p = NULL;
+ }
+ cfg->p2p_supported = 0;
+}
+/*
+ * Set P2P functions into firmware
+ */
+s32
+wl_cfgp2p_set_firm_p2p(struct bcm_cfg80211 *cfg)
+{
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ struct ether_addr null_eth_addr = { { 0, 0, 0, 0, 0, 0 } };
+ s32 ret = BCME_OK;
+ s32 val = 0;
+ /* Do we have to check whether APSTA is enabled or not ? */
+ ret = wldev_iovar_getint(ndev, "apsta", &val);
+ if (ret < 0) {
+ CFGP2P_ERR(("get apsta error %d\n", ret));
+ return ret;
+ }
+ if (val == 0) {
+ val = 1;
+ ret = wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true);
+ if (ret < 0) {
+ CFGP2P_ERR(("WLC_DOWN error %d\n", ret));
+ return ret;
+ }
+
+ ret = wldev_iovar_setint(ndev, "apsta", val);
+ if (ret < 0) {
+ /* return error and fail the initialization */
+ CFGP2P_ERR(("wl apsta %d set error. ret: %d\n", val, ret));
+ return ret;
+ }
+
+ ret = wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true);
+ if (ret < 0) {
+ CFGP2P_ERR(("WLC_UP error %d\n", ret));
+ return ret;
+ }
+ }
+
+ /* In case of COB type, firmware has default mac address
+ * After Initializing firmware, we have to set current mac address to
+ * firmware for P2P device address
+ */
+ ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr,
+ sizeof(null_eth_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &cfg->ioctl_buf_sync);
+ if (ret && ret != BCME_UNSUPPORTED) {
+ CFGP2P_ERR(("failed to update device address ret %d\n", ret));
+ }
+ return ret;
+}
+
+int wl_cfg_multip2p_operational(struct bcm_cfg80211 *cfg)
+{
+ if (!cfg->p2p) {
+ CFGP2P_DBG(("p2p not enabled! \n"));
+ return false;
+ }
+
+ if ((wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION1) != -1) &&
+ (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION2) != -1))
+ return true;
+ else
+ return false;
+}
+
+/* Create a new P2P BSS.
+ * Parameters:
+ * @mac : MAC address of the BSS to create
+ * @if_type : interface type: WL_P2P_IF_GO or WL_P2P_IF_CLIENT
+ * @chspec : chspec to use if creating a GO BSS.
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_ifadd(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type,
+ chanspec_t chspec)
+{
+ wl_p2p_if_t ifreq;
+ s32 err;
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+
+ ifreq.type = if_type;
+ ifreq.chspec = chspec;
+ memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
+
+ CFGP2P_DBG(("---cfg p2p_ifadd "MACDBG" %s %u\n",
+ MAC2STRDBG(ifreq.addr.octet),
+ (if_type == WL_P2P_IF_GO) ? "go" : "client",
+ (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
+
+ err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (unlikely(err < 0)) {
+ printk("'cfg p2p_ifadd' error %d\n", err);
+ return err;
+ }
+
+ return err;
+}
+
+/* Disable a P2P BSS.
+ * Parameters:
+ * @mac : MAC address of the BSS to disable
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_ifdisable(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
+{
+ s32 ret;
+ struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg);
+
+ CFGP2P_INFO(("------primary idx %d : cfg p2p_ifdis "MACDBG"\n",
+ netdev->ifindex, MAC2STRDBG(mac->octet)));
+ ret = wldev_iovar_setbuf(netdev, "p2p_ifdis", mac, sizeof(*mac),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (unlikely(ret < 0)) {
+ printk("'cfg p2p_ifdis' error %d\n", ret);
+ }
+ return ret;
+}
+
+/* Delete a P2P BSS.
+ * Parameters:
+ * @mac : MAC address of the BSS to delete
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_ifdel(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
+{
+ s32 ret;
+ struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg);
+
+ CFGP2P_INFO(("------primary idx %d : cfg p2p_ifdel "MACDBG"\n",
+ netdev->ifindex, MAC2STRDBG(mac->octet)));
+ ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (unlikely(ret < 0)) {
+ printk("'cfg p2p_ifdel' error %d\n", ret);
+ }
+ return ret;
+}
+
+/* Change a P2P Role.
+ * Parameters:
+ * @mac : MAC address of the BSS to change a role
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_ifchange(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type,
+ chanspec_t chspec, s32 conn_idx)
+{
+ wl_p2p_if_t ifreq;
+ s32 err;
+
+ struct net_device *netdev = wl_to_p2p_bss_ndev(cfg, conn_idx);
+
+ ifreq.type = if_type;
+ ifreq.chspec = chspec;
+ memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
+
+ CFGP2P_INFO(("---cfg p2p_ifchange "MACDBG" %s %u"
+ " chanspec 0x%04x\n", MAC2STRDBG(ifreq.addr.octet),
+ (if_type == WL_P2P_IF_GO) ? "go" : "client",
+ (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT,
+ ifreq.chspec));
+
+ err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (unlikely(err < 0)) {
+ printk("'cfg p2p_ifupd' error %d\n", err);
+ } else if (if_type == WL_P2P_IF_GO) {
+ cfg->p2p->p2p_go_count++;
+ }
+ return err;
+}
+
+
+/* Get the index of a created P2P BSS.
+ * Parameters:
+ * @mac : MAC address of the created BSS
+ * @index : output: index of created BSS
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_ifidx(struct bcm_cfg80211 *cfg, struct ether_addr *mac, s32 *index)
+{
+ s32 ret;
+ u8 getbuf[64];
+ struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
+
+ CFGP2P_INFO(("---cfg p2p_if "MACDBG"\n", MAC2STRDBG(mac->octet)));
+
+ ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf,
+ sizeof(getbuf), wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY), NULL);
+
+ if (ret == 0) {
+ memcpy(index, getbuf, sizeof(s32));
+ CFGP2P_INFO(("---cfg p2p_if ==> %d\n", *index));
+ }
+
+ return ret;
+}
+
+static s32
+wl_cfgp2p_set_discovery(struct bcm_cfg80211 *cfg, s32 on)
+{
+ s32 ret = BCME_OK;
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+ CFGP2P_DBG(("enter\n"));
+
+ ret = wldev_iovar_setint(ndev, "p2p_disc", on);
+
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR(("p2p_disc %d error %d\n", on, ret));
+ }
+
+ return ret;
+}
+
+/* Set the WL driver's P2P mode.
+ * Parameters :
+ * @mode : is one of WL_P2P_DISC_ST_{SCAN,LISTEN,SEARCH}.
+ * @channel : the channel to listen
+ * @listen_ms : the time (milli seconds) to wait
+ * @bssidx : bss index for BSSCFG
+ * Returns 0 if success
+ */
+
+s32
+wl_cfgp2p_set_p2p_mode(struct bcm_cfg80211 *cfg, u8 mode, u32 channel, u16 listen_ms, int bssidx)
+{
+ wl_p2p_disc_st_t discovery_mode;
+ s32 ret;
+ struct net_device *dev;
+ CFGP2P_DBG(("enter\n"));
+
+ if (unlikely(bssidx == WL_INVALID)) {
+ CFGP2P_ERR((" %d index out of range\n", bssidx));
+ return -1;
+ }
+
+ dev = wl_cfgp2p_find_ndev(cfg, bssidx);
+ if (unlikely(dev == NULL)) {
+ CFGP2P_ERR(("bssidx %d is not assigned\n", bssidx));
+ return BCME_NOTFOUND;
+ }
+
+#ifdef P2PLISTEN_AP_SAMECHN
+ CFGP2P_DBG(("p2p0 listen channel %d AP connection chan %d \n",
+ channel, cfg->channel));
+ if ((mode == WL_P2P_DISC_ST_LISTEN) && (cfg->channel == channel)) {
+ struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
+
+ if (cfg->p2p_resp_apchn_status) {
+ CFGP2P_DBG(("p2p_resp_apchn_status already ON \n"));
+ return BCME_OK;
+ }
+
+ if (wl_get_drv_status(cfg, CONNECTED, primary_ndev)) {
+ ret = wl_cfg80211_set_p2p_resp_ap_chn(primary_ndev, 1);
+ cfg->p2p_resp_apchn_status = true;
+ CFGP2P_DBG(("p2p_resp_apchn_status ON \n"));
+ return ret;
+ }
+ }
+#endif /* P2PLISTEN_AP_SAMECHN */
+
+ /* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */
+ discovery_mode.state = mode;
+ discovery_mode.chspec = wl_ch_host_to_driver(cfg->wdev, bssidx, channel);
+ discovery_mode.dwell = listen_ms;
+ ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode,
+ sizeof(discovery_mode), cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
+ bssidx, &cfg->ioctl_buf_sync);
+
+ return ret;
+}
+
+/* Get the index of the P2P Discovery BSS */
+static s32
+wl_cfgp2p_get_disc_idx(struct bcm_cfg80211 *cfg, s32 *index)
+{
+ s32 ret;
+ struct net_device *dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
+
+ ret = wldev_iovar_getint(dev, "p2p_dev", index);
+ CFGP2P_INFO(("p2p_dev bsscfg_idx=%d ret=%d\n", *index, ret));
+
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR(("'p2p_dev' error %d\n", ret));
+ return ret;
+ }
+ return ret;
+}
+
+int wl_cfgp2p_get_conn_idx(struct bcm_cfg80211 *cfg)
+{
+ int i;
+ s32 connected_cnt;
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+ if (!dhd)
+ return (-ENODEV);
+ for (i = P2PAPI_BSSCFG_CONNECTION1; i < P2PAPI_BSSCFG_MAX; i++) {
+ if (wl_to_p2p_bss_bssidx(cfg, i) == -1) {
+ if (i == P2PAPI_BSSCFG_CONNECTION2) {
+ if (!(dhd->op_mode & DHD_FLAG_MP2P_MODE)) {
+ CFGP2P_ERR(("Multi p2p not supported"));
+ return BCME_ERROR;
+ }
+ if ((connected_cnt = wl_get_drv_status_all(cfg, CONNECTED)) > 1) {
+ CFGP2P_ERR(("Failed to create second p2p interface"
+ "Already one connection exists"));
+ return BCME_ERROR;
+ }
+ }
+ return i;
+ }
+ }
+ return BCME_ERROR;
+}
+
+s32
+wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg)
+{
+
+ s32 bssidx = 0;
+ s32 ret = BCME_OK;
+
+ CFGP2P_DBG(("enter\n"));
+
+ if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) > 0) {
+ CFGP2P_ERR(("do nothing, already initialized\n"));
+ return ret;
+ }
+
+ ret = wl_cfgp2p_set_discovery(cfg, 1);
+ if (ret < 0) {
+ CFGP2P_ERR(("set discover error\n"));
+ return ret;
+ }
+ /* Enable P2P Discovery in the WL Driver */
+ ret = wl_cfgp2p_get_disc_idx(cfg, &bssidx);
+
+ if (ret < 0) {
+ return ret;
+ }
+ /* In case of CFG80211 case, check if p2p_discovery interface has allocated p2p_wdev */
+ if (!cfg->p2p_wdev) {
+ CFGP2P_ERR(("p2p_wdev is NULL.\n"));
+ return BCME_NODEVICE;
+ }
+ /* Make an entry in the netinfo */
+ wl_alloc_netinfo(cfg, NULL, cfg->p2p_wdev, WL_MODE_BSS, 0, bssidx);
+
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) =
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = bssidx;
+
+ /* Set the initial discovery state to SCAN */
+ ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
+
+ if (unlikely(ret != 0)) {
+ CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n"));
+ wl_cfgp2p_set_discovery(cfg, 0);
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL;
+ return 0;
+ }
+ return ret;
+}
+
+/* Deinitialize P2P Discovery
+ * Parameters :
+ * @cfg : wl_private data
+ * Returns 0 if succes
+ */
+static s32
+wl_cfgp2p_deinit_discovery(struct bcm_cfg80211 *cfg)
+{
+ s32 ret = BCME_OK;
+ s32 bssidx;
+
+ CFGP2P_DBG(("enter\n"));
+ bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+ if (bssidx <= 0) {
+ CFGP2P_ERR(("do nothing, not initialized\n"));
+ return -1;
+ }
+
+ /* Clear our saved WPS and P2P IEs for the discovery BSS */
+ wl_cfg80211_clear_per_bss_ies(cfg, bssidx);
+
+ /* Set the discovery state to SCAN */
+ wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
+ bssidx);
+ /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */
+ ret = wl_cfgp2p_set_discovery(cfg, 0);
+
+ /* Remove the p2p disc entry in the netinfo */
+#ifdef DHD_IFDEBUG
+ WL_ERR(("dealloc_net_info by wdev=%p\n", cfg->p2p_wdev));
+#endif
+ wl_dealloc_netinfo_by_wdev(cfg, cfg->p2p_wdev);
+
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = WL_INVALID;
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL;
+
+ return ret;
+
+}
+/* Enable P2P Discovery
+ * Parameters:
+ * @cfg : wl_private data
+ * @ie : probe request ie (WPS IE + P2P IE)
+ * @ie_len : probe request ie length
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev,
+ const u8 *ie, u32 ie_len)
+{
+ s32 ret = BCME_OK;
+ s32 bssidx;
+
+ CFGP2P_DBG(("enter\n"));
+ if (wl_get_p2p_status(cfg, DISCOVERY_ON)) {
+ CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n"));
+ goto set_ie;
+ }
+
+ ret = wl_cfgp2p_init_discovery(cfg);
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR((" init discovery error %d\n", ret));
+ goto exit;
+ }
+
+ wl_set_p2p_status(cfg, DISCOVERY_ON);
+ /* Set wsec to any non-zero value in the discovery bsscfg to ensure our
+ * P2P probe responses have the privacy bit set in the 802.11 WPA IE.
+ * Some peer devices may not initiate WPS with us if this bit is not set.
+ */
+ ret = wldev_iovar_setint_bsscfg(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE),
+ "wsec", AES_ENABLED, wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR((" wsec error %d\n", ret));
+ }
+set_ie:
+ if (ie_len) {
+
+ if (bcmcfg_to_prmry_ndev(cfg) == dev) {
+ bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+ } else if ((bssidx = wl_get_bssidx_by_wdev(cfg, cfg->p2p_wdev)) < 0) {
+ WL_ERR(("Find p2p index from wdev(%p) failed\n", cfg->p2p_wdev));
+ return BCME_ERROR;
+ }
+
+ ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev),
+ bssidx,
+ VNDR_IE_PRBREQ_FLAG, ie, ie_len);
+
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR(("set probreq ie occurs error %d\n", ret));
+ goto exit;
+ }
+ }
+exit:
+ return ret;
+}
+
+/* Disable P2P Discovery
+ * Parameters:
+ * @cfg : wl_private_data
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_disable_discovery(struct bcm_cfg80211 *cfg)
+{
+ s32 ret = BCME_OK;
+ s32 bssidx;
+
+ CFGP2P_DBG((" enter\n"));
+ wl_clr_p2p_status(cfg, DISCOVERY_ON);
+
+#ifdef DHD_IFDEBUG
+ WL_ERR(("%s: (cfg)->p2p->bss[type].bssidx: %d\n",
+ __FUNCTION__, (cfg)->p2p->bss[P2PAPI_BSSCFG_DEVICE].bssidx));
+#endif
+ bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+ if (bssidx <= 0) {
+ CFGP2P_ERR((" do nothing, not initialized\n"));
+ return 0;
+ }
+
+ ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
+ bssidx);
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n"));
+ }
+ /* Do a scan abort to stop the driver's scan engine in case it is still
+ * waiting out an action frame tx dwell time.
+ */
+ wl_clr_p2p_status(cfg, DISCOVERY_ON);
+ ret = wl_cfgp2p_deinit_discovery(cfg);
+
+ return ret;
+}
+
+s32
+wl_cfgp2p_escan(struct bcm_cfg80211 *cfg, struct net_device *dev, u16 active,
+ u32 num_chans, u16 *channels,
+ s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr,
+ p2p_scan_purpose_t p2p_scan_purpose)
+{
+ s32 ret = BCME_OK;
+ s32 memsize;
+ s32 eparams_size;
+ u32 i;
+ s8 *memblk;
+ wl_p2p_scan_t *p2p_params;
+ wl_escan_params_t *eparams;
+ wlc_ssid_t ssid;
+ /* Scan parameters */
+#define P2PAPI_SCAN_NPROBES 1
+#define P2PAPI_SCAN_DWELL_TIME_MS 80
+#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40
+#define P2PAPI_SCAN_HOME_TIME_MS 60
+#define P2PAPI_SCAN_NPROBS_TIME_MS 30
+#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100
+
+ struct net_device *pri_dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
+ /* Allocate scan params which need space for 3 channels and 0 ssids */
+ eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE +
+ OFFSETOF(wl_escan_params_t, params)) +
+ num_chans * sizeof(eparams->params.channel_list[0]);
+
+ memsize = sizeof(wl_p2p_scan_t) + eparams_size;
+ memblk = scanparambuf;
+ if (memsize > sizeof(scanparambuf)) {
+ CFGP2P_ERR((" scanpar buf too small (%u > %zu)\n",
+ memsize, sizeof(scanparambuf)));
+ return -1;
+ }
+ memset(memblk, 0, memsize);
+ memset(cfg->ioctl_buf, 0, WLC_IOCTL_MAXLEN);
+ if (search_state == WL_P2P_DISC_ST_SEARCH) {
+ /*
+ * If we in SEARCH STATE, we don't need to set SSID explictly
+ * because dongle use P2P WILDCARD internally by default
+ */
+ wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx);
+ /* use null ssid */
+ ssid.SSID_len = 0;
+ memset(&ssid.SSID, 0, sizeof(ssid.SSID));
+ } else if (search_state == WL_P2P_DISC_ST_SCAN) {
+ /* SCAN STATE 802.11 SCAN
+ * WFD Supplicant has p2p_find command with (type=progressive, type= full)
+ * So if P2P_find command with type=progressive,
+ * we have to set ssid to P2P WILDCARD because
+ * we just do broadcast scan unless setting SSID
+ */
+ wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx);
+ /* use wild card ssid */
+ ssid.SSID_len = WL_P2P_WILDCARD_SSID_LEN;
+ memset(&ssid.SSID, 0, sizeof(ssid.SSID));
+ memcpy(&ssid.SSID, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN);
+ } else {
+ CFGP2P_ERR((" invalid search state %d\n", search_state));
+ return -1;
+ }
+
+
+ /* Fill in the P2P scan structure at the start of the iovar param block */
+ p2p_params = (wl_p2p_scan_t*) memblk;
+ p2p_params->type = 'E';
+ /* Fill in the Scan structure that follows the P2P scan structure */
+ eparams = (wl_escan_params_t*) (p2p_params + 1);
+ eparams->params.bss_type = DOT11_BSSTYPE_ANY;
+ if (active)
+ eparams->params.scan_type = DOT11_SCANTYPE_ACTIVE;
+ else
+ eparams->params.scan_type = DOT11_SCANTYPE_PASSIVE;
+
+ if (tx_dst_addr == NULL)
+ memcpy(&eparams->params.bssid, &ether_bcast, ETHER_ADDR_LEN);
+ else
+ memcpy(&eparams->params.bssid, tx_dst_addr, ETHER_ADDR_LEN);
+
+ if (ssid.SSID_len)
+ memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t));
+
+ eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS);
+
+ switch (p2p_scan_purpose) {
+ case P2P_SCAN_SOCIAL_CHANNEL:
+ eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS);
+ break;
+ case P2P_SCAN_AFX_PEER_NORMAL:
+ case P2P_SCAN_AFX_PEER_REDUCED:
+ eparams->params.active_time = htod32(P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS);
+ break;
+ case P2P_SCAN_CONNECT_TRY:
+ eparams->params.active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS);
+ break;
+ default :
+ if (wl_get_drv_status_all(cfg, CONNECTED))
+ eparams->params.active_time = -1;
+ else
+ eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS);
+ break;
+ }
+
+ if (p2p_scan_purpose == P2P_SCAN_CONNECT_TRY)
+ eparams->params.nprobes = htod32(eparams->params.active_time /
+ WL_SCAN_JOIN_PROBE_INTERVAL_MS);
+ else
+ eparams->params.nprobes = htod32((eparams->params.active_time /
+ P2PAPI_SCAN_NPROBS_TIME_MS));
+
+
+ if (eparams->params.nprobes <= 0)
+ eparams->params.nprobes = 1;
+ CFGP2P_DBG(("nprobes # %d, active_time %d\n",
+ eparams->params.nprobes, eparams->params.active_time));
+ eparams->params.passive_time = htod32(-1);
+ eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
+ (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
+
+ for (i = 0; i < num_chans; i++) {
+ eparams->params.channel_list[i] = wl_ch_host_to_driver(cfg->wdev,
+ bssidx, channels[i]);
+ }
+ eparams->version = htod32(ESCAN_REQ_VERSION);
+ eparams->action = htod16(action);
+ wl_escan_set_sync_id(eparams->sync_id, cfg);
+ wl_escan_set_type(cfg, WL_SCANTYPE_P2P);
+ CFGP2P_INFO(("SCAN CHANNELS : "));
+
+ for (i = 0; i < num_chans; i++) {
+ if (i == 0) CFGP2P_INFO(("%d", channels[i]));
+ else CFGP2P_INFO((",%d", channels[i]));
+ }
+
+ CFGP2P_INFO(("\n"));
+
+ ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan",
+ memblk, memsize, cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+ WL_SCAN(("P2P_SEARCH sync ID: %d, bssidx: %d\n", eparams->sync_id, bssidx));
+ if (ret == BCME_OK)
+ wl_set_p2p_status(cfg, SCANNING);
+ return ret;
+}
+
+/* search function to reach at common channel to send action frame
+ * Parameters:
+ * @cfg : wl_private data
+ * @ndev : net device for bssidx
+ * @bssidx : bssidx for BSS
+ * Returns 0 if success.
+ */
+s32
+wl_cfgp2p_act_frm_search(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ s32 bssidx, s32 channel, struct ether_addr *tx_dst_addr)
+{
+ s32 ret = 0;
+ u32 chan_cnt = 0;
+ u16 *default_chan_list = NULL;
+ p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_AFX_PEER_NORMAL;
+ if (!p2p_is_on(cfg) || ndev == NULL || bssidx == WL_INVALID)
+ return -EINVAL;
+ WL_TRACE_HW4((" Enter\n"));
+ if (bssidx == wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY))
+ bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+ if (channel)
+ chan_cnt = AF_PEER_SEARCH_CNT;
+ else
+ chan_cnt = SOCIAL_CHAN_CNT;
+
+ if (cfg->afx_hdl->pending_tx_act_frm && cfg->afx_hdl->is_active) {
+ wl_action_frame_t *action_frame;
+ action_frame = &(cfg->afx_hdl->pending_tx_act_frm->action_frame);
+ if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len)) {
+ chan_cnt = 1;
+ p2p_scan_purpose = P2P_SCAN_AFX_PEER_REDUCED;
+ }
+ }
+
+ default_chan_list = kzalloc(chan_cnt * sizeof(*default_chan_list), GFP_KERNEL);
+ if (default_chan_list == NULL) {
+ CFGP2P_ERR(("channel list allocation failed \n"));
+ ret = -ENOMEM;
+ goto exit;
+ }
+ if (channel) {
+ u32 i;
+ /* insert same channel to the chan_list */
+ for (i = 0; i < chan_cnt; i++) {
+ default_chan_list[i] = channel;
+ }
+ } else {
+ default_chan_list[0] = SOCIAL_CHAN_1;
+ default_chan_list[1] = SOCIAL_CHAN_2;
+ default_chan_list[2] = SOCIAL_CHAN_3;
+ }
+ ret = wl_cfgp2p_escan(cfg, ndev, true, chan_cnt,
+ default_chan_list, WL_P2P_DISC_ST_SEARCH,
+ WL_SCAN_ACTION_START, bssidx, NULL, p2p_scan_purpose);
+ kfree(default_chan_list);
+exit:
+ return ret;
+}
+
+/* Check whether pointed-to IE looks like WPA. */
+#define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
+ (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE)
+/* Check whether pointed-to IE looks like WPS. */
+#define wl_cfgp2p_is_wps_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
+ (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE)
+/* Check whether the given IE looks like WFA P2P IE. */
+#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
+ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P)
+/* Check whether the given IE looks like WFA WFDisplay IE. */
+#ifndef WFA_OUI_TYPE_WFD
+#define WFA_OUI_TYPE_WFD 0x0a /* WiFi Display OUI TYPE */
+#endif
+#define wl_cfgp2p_is_wfd_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
+ (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_WFD)
+
+
+/* Is any of the tlvs the expected entry? If
+ * not update the tlvs buffer pointer/length.
+ */
+static bool
+wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type)
+{
+ /* If the contents match the OUI and the type */
+ if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
+ !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
+ type == ie[TLV_BODY_OFF + oui_len]) {
+ return TRUE;
+ }
+
+ if (tlvs == NULL)
+ return FALSE;
+ /* point to the next ie */
+ ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
+ /* calculate the length of the rest of the buffer */
+ *tlvs_len -= (int)(ie - *tlvs);
+ /* update the pointer to the start of the buffer */
+ *tlvs = ie;
+
+ return FALSE;
+}
+
+wpa_ie_fixed_t *
+wl_cfgp2p_find_wpaie(u8 *parse, u32 len)
+{
+ bcm_tlv_t *ie;
+
+ while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) {
+ if (wl_cfgp2p_is_wpa_ie((u8*)ie, &parse, &len)) {
+ return (wpa_ie_fixed_t *)ie;
+ }
+ }
+ return NULL;
+}
+
+wpa_ie_fixed_t *
+wl_cfgp2p_find_wpsie(u8 *parse, u32 len)
+{
+ bcm_tlv_t *ie;
+
+ while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) {
+ if (wl_cfgp2p_is_wps_ie((u8*)ie, &parse, &len)) {
+ return (wpa_ie_fixed_t *)ie;
+ }
+ }
+ return NULL;
+}
+
+wifi_p2p_ie_t *
+wl_cfgp2p_find_p2pie(u8 *parse, u32 len)
+{
+ bcm_tlv_t *ie;
+
+ while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) {
+ if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len)) {
+ return (wifi_p2p_ie_t *)ie;
+ }
+ }
+ return NULL;
+}
+
+wifi_wfd_ie_t *
+wl_cfgp2p_find_wfdie(u8 *parse, u32 len)
+{
+ bcm_tlv_t *ie;
+
+ while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) {
+ if (wl_cfgp2p_is_wfd_ie((uint8*)ie, &parse, &len)) {
+ return (wifi_wfd_ie_t *)ie;
+ }
+ }
+ return NULL;
+}
+u32
+wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag,
+ s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd)
+{
+ vndr_ie_setbuf_t hdr; /* aligned temporary vndr_ie buffer header */
+ s32 iecount;
+ u32 data_offset;
+
+ /* Validate the pktflag parameter */
+ if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG |
+ VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG |
+ VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG))) {
+ CFGP2P_ERR(("p2pwl_vndr_ie: Invalid packet flag 0x%x\n", pktflag));
+ return -1;
+ }
+
+ /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
+ strncpy(hdr.cmd, add_del_cmd, VNDR_IE_CMD_LEN - 1);
+ hdr.cmd[VNDR_IE_CMD_LEN - 1] = '\0';
+
+ /* Set the IE count - the buffer contains only 1 IE */
+ iecount = htod32(1);
+ memcpy((void *)&hdr.vndr_ie_buffer.iecount, &iecount, sizeof(s32));
+
+ /* Copy packet flags that indicate which packets will contain this IE */
+ pktflag = htod32(pktflag);
+ memcpy((void *)&hdr.vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
+ sizeof(u32));
+
+ /* Add the IE ID to the buffer */
+ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id;
+
+ /* Add the IE length to the buffer */
+ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len =
+ (uint8) VNDR_IE_MIN_LEN + datalen;
+
+ /* Add the IE OUI to the buffer */
+ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[0] = oui[0];
+ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[1] = oui[1];
+ hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[2] = oui[2];
+
+ /* Copy the aligned temporary vndr_ie buffer header to the IE buffer */
+ memcpy(iebuf, &hdr, sizeof(hdr) - 1);
+
+ /* Copy the IE data to the IE buffer */
+ data_offset =
+ (u8*)&hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0] -
+ (u8*)&hdr;
+ memcpy(iebuf + data_offset, data, datalen);
+ return data_offset + datalen;
+
+}
+
+struct net_device *
+wl_cfgp2p_find_ndev(struct bcm_cfg80211 *cfg, s32 bssidx)
+{
+ u32 i;
+ struct net_device *ndev = NULL;
+ if (bssidx < 0) {
+ CFGP2P_ERR((" bsscfg idx is invalid\n"));
+ goto exit;
+ }
+
+ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
+ if (bssidx == wl_to_p2p_bss_bssidx(cfg, i)) {
+ ndev = wl_to_p2p_bss_ndev(cfg, i);
+ break;
+ }
+ }
+
+exit:
+ return ndev;
+}
+/*
+ * Search the driver array idx based on bssidx argument
+ * Parameters: Note that this idx is applicable only
+ * for primary and P2P interfaces. The virtual AP/STA is not
+ * covered here.
+ * @cfg : wl_private data
+ * @bssidx : bssidx which indicate bsscfg->idx of firmware.
+ * @type : output arg to store array idx of p2p->bss.
+ * Returns error
+ */
+
+s32
+wl_cfgp2p_find_type(struct bcm_cfg80211 *cfg, s32 bssidx, s32 *type)
+{
+ u32 i;
+ if (bssidx < 0 || type == NULL) {
+ CFGP2P_ERR((" argument is invalid\n"));
+ goto exit;
+ }
+
+ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
+ if (bssidx == wl_to_p2p_bss_bssidx(cfg, i)) {
+ *type = i;
+ return BCME_OK;
+ }
+ }
+
+exit:
+ return BCME_BADARG;
+}
+
+/*
+ * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE
+ */
+s32
+wl_cfgp2p_listen_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ s32 ret = BCME_OK;
+ struct net_device *ndev = NULL;
+
+ if (!cfg || !cfg->p2p || !cfgdev)
+ return BCME_ERROR;
+
+ CFGP2P_DBG((" Enter\n"));
+
+#ifdef DHD_IFDEBUG
+ WL_ERR(("%s: cfg: %p, cfgdev: %p, cfg->wdev: %p, cfg->p2p_wdev: %p\n",
+ __FUNCTION__, cfg, cfgdev, cfg->wdev, cfg->p2p_wdev));
+#endif
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+#ifdef P2P_LISTEN_OFFLOADING
+ if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
+ wl_clr_p2p_status(cfg, DISC_IN_PROGRESS);
+ CFGP2P_ERR(("DISC_IN_PROGRESS cleared\n"));
+ if (ndev && (ndev->ieee80211_ptr != NULL)) {
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ if (cfgdev && ((struct wireless_dev *)cfgdev)->wiphy) {
+ cfg80211_remain_on_channel_expired(cfgdev, cfg->last_roc_id,
+ &cfg->remain_on_chan, GFP_KERNEL);
+ } else {
+ CFGP2P_ERR(("Invalid cfgdev. Dropping the"
+ "remain_on_channel_expired event.\n"));
+ }
+#else
+ cfg80211_remain_on_channel_expired(cfgdev, cfg->last_roc_id,
+ &cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ }
+ }
+#endif /* P2P_LISTEN_OFFLOADING */
+
+ if (wl_get_p2p_status(cfg, LISTEN_EXPIRED) == 0) {
+ wl_set_p2p_status(cfg, LISTEN_EXPIRED);
+ if (timer_pending(&cfg->p2p->listen_timer)) {
+ del_timer_sync(&cfg->p2p->listen_timer);
+ }
+
+ if (cfg->afx_hdl->is_listen == TRUE &&
+ wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
+ WL_DBG(("Listen DONE for action frame\n"));
+ complete(&cfg->act_frm_scan);
+ }
+#ifdef WL_CFG80211_SYNC_GON
+ else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
+ wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, ndev);
+ WL_DBG(("Listen DONE and wake up wait_next_af !!(%d)\n",
+ jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies)));
+
+ if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM))
+ wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
+
+ complete(&cfg->wait_next_af);
+ }
+#endif /* WL_CFG80211_SYNC_GON */
+
+#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ if (wl_get_drv_status_all(cfg, REMAINING_ON_CHANNEL)) {
+#else
+ if (wl_get_drv_status_all(cfg, REMAINING_ON_CHANNEL) ||
+ wl_get_drv_status_all(cfg, FAKE_REMAINING_ON_CHANNEL)) {
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+ WL_DBG(("Listen DONE for remain on channel expired\n"));
+ wl_clr_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ wl_clr_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+ if (ndev && (ndev->ieee80211_ptr != NULL)) {
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ if (cfgdev && ((struct wireless_dev *)cfgdev)->wiphy) {
+ /*
+ * To prevent kernel panic,
+ * if cfgdev->wiphy may be invalid, adding explicit check
+ */
+ cfg80211_remain_on_channel_expired(cfgdev, cfg->last_roc_id,
+ &cfg->remain_on_chan, GFP_KERNEL);
+ } else {
+ CFGP2P_ERR(("Invalid cfgdev. Dropping the"
+ "remain_on_channel_expired event.\n"));
+ }
+#else
+ cfg80211_remain_on_channel_expired(cfgdev, cfg->last_roc_id,
+ &cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ }
+ }
+ if (wl_add_remove_eventmsg(bcmcfg_to_prmry_ndev(cfg),
+ WLC_E_P2P_PROBREQ_MSG, false) != BCME_OK) {
+ CFGP2P_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
+ }
+ } else
+ wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
+
+ return ret;
+
+}
+
+/*
+ * Timer expire callback function for LISTEN
+ * We can't report cfg80211_remain_on_channel_expired from Timer ISR context,
+ * so lets do it from thread context.
+ */
+void
+wl_cfgp2p_listen_expired(unsigned long data)
+{
+ wl_event_msg_t msg;
+ struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *) data;
+ CFGP2P_DBG((" Enter\n"));
+ bzero(&msg, sizeof(wl_event_msg_t));
+ msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE);
+ msg.bsscfgidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
+#if defined(WL_ENABLE_P2P_IF)
+ wl_cfg80211_event(cfg->p2p_net ? cfg->p2p_net :
+ wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE), &msg, NULL);
+#else
+ wl_cfg80211_event(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE), &msg,
+ NULL);
+#endif /* WL_ENABLE_P2P_IF */
+}
+/*
+ * Routine for cancelling the P2P LISTEN
+ */
+static s32
+wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ struct wireless_dev *wdev, bool notify)
+{
+ WL_DBG(("Enter \n"));
+ /* Irrespective of whether timer is running or not, reset
+ * the LISTEN state.
+ */
+ if (timer_pending(&cfg->p2p->listen_timer)) {
+ del_timer_sync(&cfg->p2p->listen_timer);
+ if (notify) {
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ if (wdev)
+ cfg80211_remain_on_channel_expired(wdev, cfg->last_roc_id,
+ &cfg->remain_on_chan, GFP_KERNEL);
+#else
+ if (ndev && ndev->ieee80211_ptr)
+ cfg80211_remain_on_channel_expired(ndev, cfg->last_roc_id,
+ &cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+ }
+ }
+ return 0;
+}
+/*
+ * Do a P2P Listen on the given channel for the given duration.
+ * A listen consists of sitting idle and responding to P2P probe requests
+ * with a P2P probe response.
+ *
+ * This fn assumes dongle p2p device discovery is already enabled.
+ * Parameters :
+ * @cfg : wl_private data
+ * @channel : channel to listen
+ * @duration_ms : the time (milli seconds) to wait
+ */
+s32
+wl_cfgp2p_discover_listen(struct bcm_cfg80211 *cfg, s32 channel, u32 duration_ms)
+{
+#define EXTRA_DELAY_TIME 100
+ s32 ret = BCME_OK;
+ struct timer_list *_timer;
+ s32 extra_delay;
+ struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg);
+
+ CFGP2P_DBG((" Enter Listen Channel : %d, Duration : %d\n", channel, duration_ms));
+ if (unlikely(wl_get_p2p_status(cfg, DISCOVERY_ON) == 0)) {
+
+ CFGP2P_ERR((" Discovery is not set, so we have noting to do\n"));
+
+ ret = BCME_NOTREADY;
+ goto exit;
+ }
+ if (timer_pending(&cfg->p2p->listen_timer)) {
+ CFGP2P_DBG(("previous LISTEN is not completed yet\n"));
+ goto exit;
+
+ }
+#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ else
+ wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
+#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+ if (wl_add_remove_eventmsg(netdev, WLC_E_P2P_PROBREQ_MSG, true) != BCME_OK) {
+ CFGP2P_ERR((" failed to set WLC_E_P2P_PROPREQ_MSG\n"));
+ }
+
+ ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms,
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
+ _timer = &cfg->p2p->listen_timer;
+
+ /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle ,
+ * otherwise we will wait up to duration_ms + 100ms + duration / 10
+ */
+ if (ret == BCME_OK) {
+ extra_delay = EXTRA_DELAY_TIME + (duration_ms / 10);
+ } else {
+ /* if failed to set listen, it doesn't need to wait whole duration. */
+ duration_ms = 100 + duration_ms / 20;
+ extra_delay = 0;
+ }
+
+ INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, extra_delay);
+#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
+ wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
+#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
+
+#undef EXTRA_DELAY_TIME
+exit:
+ return ret;
+}
+
+
+s32
+wl_cfgp2p_discover_enable_search(struct bcm_cfg80211 *cfg, u8 enable)
+{
+ s32 ret = BCME_OK;
+ CFGP2P_DBG((" Enter\n"));
+ if (!wl_get_p2p_status(cfg, DISCOVERY_ON)) {
+
+ CFGP2P_DBG((" do nothing, discovery is off\n"));
+ return ret;
+ }
+ if (wl_get_p2p_status(cfg, SEARCH_ENABLED) == enable) {
+ CFGP2P_DBG(("already : %d\n", enable));
+ return ret;
+ }
+
+ wl_chg_p2p_status(cfg, SEARCH_ENABLED);
+ /* When disabling Search, reset the WL driver's p2p discovery state to
+ * WL_P2P_DISC_ST_SCAN.
+ */
+ if (!enable) {
+ wl_clr_p2p_status(cfg, SCANNING);
+ ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
+ wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
+ }
+
+ return ret;
+}
+
+/*
+ * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE
+ */
+s32
+wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data)
+{
+ s32 ret = BCME_OK;
+ u32 event_type = ntoh32(e->event_type);
+ u32 status = ntoh32(e->status);
+ struct net_device *ndev = NULL;
+ CFGP2P_DBG((" Enter\n"));
+
+ ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
+
+ if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) {
+ if (event_type == WLC_E_ACTION_FRAME_COMPLETE) {
+
+ CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status));
+ if (status == WLC_E_STATUS_SUCCESS) {
+ wl_set_p2p_status(cfg, ACTION_TX_COMPLETED);
+ CFGP2P_DBG(("WLC_E_ACTION_FRAME_COMPLETE : ACK\n"));
+ if (!cfg->need_wait_afrx && cfg->af_sent_channel) {
+ CFGP2P_DBG(("no need to wait next AF.\n"));
+ wl_stop_wait_next_action_frame(cfg, ndev);
+ }
+ }
+ else if (!wl_get_p2p_status(cfg, ACTION_TX_COMPLETED)) {
+ wl_set_p2p_status(cfg, ACTION_TX_NOACK);
+ CFGP2P_INFO(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n"));
+ wl_stop_wait_next_action_frame(cfg, ndev);
+ }
+ } else {
+ CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received,"
+ "status : %d\n", status));
+
+ if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM))
+ complete(&cfg->send_af_done);
+ }
+ }
+ return ret;
+}
+/* Send an action frame immediately without doing channel synchronization.
+ *
+ * This function does not wait for a completion event before returning.
+ * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action
+ * frame is transmitted.
+ * The WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE event will be received when an
+ * 802.11 ack has been received for the sent action frame.
+ */
+s32
+wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev,
+ wl_af_params_t *af_params, s32 bssidx)
+{
+ s32 ret = BCME_OK;
+ s32 evt_ret = BCME_OK;
+ s32 timeout = 0;
+ wl_eventmsg_buf_t buf;
+
+
+ CFGP2P_INFO(("\n"));
+ CFGP2P_INFO(("channel : %u , dwell time : %u\n",
+ af_params->channel, af_params->dwell_time));
+
+ wl_clr_p2p_status(cfg, ACTION_TX_COMPLETED);
+ wl_clr_p2p_status(cfg, ACTION_TX_NOACK);
+
+ bzero(&buf, sizeof(wl_eventmsg_buf_t));
+ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, true);
+ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, true);
+ if ((evt_ret = wl_cfg80211_apply_eventbuffer(bcmcfg_to_prmry_ndev(cfg), cfg, &buf)) < 0)
+ return evt_ret;
+
+ cfg->af_sent_channel = af_params->channel;
+#ifdef WL_CFG80211_SYNC_GON
+ cfg->af_tx_sent_jiffies = jiffies;
+#endif /* WL_CFG80211_SYNC_GON */
+
+ ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
+
+ if (ret < 0) {
+ CFGP2P_ERR((" sending action frame is failed\n"));
+ goto exit;
+ }
+
+ timeout = wait_for_completion_timeout(&cfg->send_af_done,
+ msecs_to_jiffies(af_params->dwell_time + WL_AF_TX_EXTRA_TIME_MAX));
+
+ if (timeout >= 0 && wl_get_p2p_status(cfg, ACTION_TX_COMPLETED)) {
+ CFGP2P_INFO(("tx action frame operation is completed\n"));
+ ret = BCME_OK;
+ } else if (ETHER_ISBCAST(&cfg->afx_hdl->tx_dst_addr)) {
+ CFGP2P_INFO(("bcast tx action frame operation is completed\n"));
+ ret = BCME_OK;
+ } else {
+ ret = BCME_ERROR;
+ CFGP2P_INFO(("tx action frame operation is failed\n"));
+ }
+ /* clear status bit for action tx */
+ wl_clr_p2p_status(cfg, ACTION_TX_COMPLETED);
+ wl_clr_p2p_status(cfg, ACTION_TX_NOACK);
+
+exit:
+ CFGP2P_INFO((" via act frame iovar : status = %d\n", ret));
+
+ bzero(&buf, sizeof(wl_eventmsg_buf_t));
+ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, false);
+ wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, false);
+ if ((evt_ret = wl_cfg80211_apply_eventbuffer(bcmcfg_to_prmry_ndev(cfg), cfg, &buf)) < 0) {
+ WL_ERR(("TX frame events revert back failed \n"));
+ return evt_ret;
+ }
+
+ return ret;
+}
+
+/* Generate our P2P Device Address and P2P Interface Address from our primary
+ * MAC address.
+ */
+void
+wl_cfgp2p_generate_bss_mac(struct bcm_cfg80211 *cfg, struct ether_addr *primary_addr)
+{
+ struct ether_addr *mac_addr = wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE);
+ struct ether_addr *int_addr;
+
+ memcpy(mac_addr, primary_addr, sizeof(struct ether_addr));
+ mac_addr->octet[0] |= 0x02;
+ WL_DBG(("P2P Discovery address:"MACDBG "\n", MAC2STRDBG(mac_addr->octet)));
+
+ int_addr = wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_CONNECTION1);
+ memcpy(int_addr, mac_addr, sizeof(struct ether_addr));
+ int_addr->octet[3] ^= 0x80;
+ WL_DBG(("Primary P2P Interface address:"MACDBG "\n", MAC2STRDBG(int_addr->octet)));
+
+ int_addr = wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_CONNECTION2);
+ memcpy(int_addr, mac_addr, sizeof(struct ether_addr));
+ int_addr->octet[3] ^= 0x90;
+}
+
+/* P2P IF Address change to Virtual Interface MAC Address */
+void
+wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id)
+{
+ wifi_p2p_ie_t *ie = (wifi_p2p_ie_t*) buf;
+ u16 len = ie->len;
+ u8 *subel;
+ u8 subelt_id;
+ u16 subelt_len;
+ CFGP2P_DBG((" Enter\n"));
+
+ /* Point subel to the P2P IE's subelt field.
+ * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
+ */
+ subel = ie->subelts;
+ len -= 4; /* exclude OUI + OUI_TYPE */
+
+ while (len >= 3) {
+ /* attribute id */
+ subelt_id = *subel;
+ subel += 1;
+ len -= 1;
+
+ /* 2-byte little endian */
+ subelt_len = *subel++;
+ subelt_len |= *subel++ << 8;
+
+ len -= 2;
+ len -= subelt_len; /* for the remaining subelt fields */
+
+ if (subelt_id == element_id) {
+ if (subelt_id == P2P_SEID_INTINTADDR) {
+ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
+ CFGP2P_INFO(("Intended P2P Interface Address ATTR FOUND\n"));
+ } else if (subelt_id == P2P_SEID_DEV_ID) {
+ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
+ CFGP2P_INFO(("Device ID ATTR FOUND\n"));
+ } else if (subelt_id == P2P_SEID_DEV_INFO) {
+ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
+ CFGP2P_INFO(("Device INFO ATTR FOUND\n"));
+ } else if (subelt_id == P2P_SEID_GROUP_ID) {
+ memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
+ CFGP2P_INFO(("GROUP ID ATTR FOUND\n"));
+ } return;
+ } else {
+ CFGP2P_DBG(("OTHER id : %d\n", subelt_id));
+ }
+ subel += subelt_len;
+ }
+}
+/*
+ * Check if a BSS is up.
+ * This is a common implementation called by most OSL implementations of
+ * p2posl_bss_isup(). DO NOT call this function directly from the
+ * common code -- call p2posl_bss_isup() instead to allow the OSL to
+ * override the common implementation if necessary.
+ */
+bool
+wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx)
+{
+ s32 result, val;
+ bool isup = false;
+ s8 getbuf[64];
+
+ /* Check if the BSS is up */
+ *(int*)getbuf = -1;
+ result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
+ sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL);
+ if (result != 0) {
+ CFGP2P_ERR(("'cfg bss -C %d' failed: %d\n", bsscfg_idx, result));
+ CFGP2P_ERR(("NOTE: this ioctl error is normal "
+ "when the BSS has not been created yet.\n"));
+ } else {
+ val = *(int*)getbuf;
+ val = dtoh32(val);
+ CFGP2P_INFO(("---cfg bss -C %d ==> %d\n", bsscfg_idx, val));
+ isup = (val ? TRUE : FALSE);
+ }
+ return isup;
+}
+
+
+/* Bring up or down a BSS */
+s32
+wl_cfgp2p_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 is_up)
+{
+ s32 ret = BCME_OK;
+ s32 val = is_up ? 1 : 0;
+
+ struct {
+ s32 cfg;
+ s32 val;
+ } bss_setbuf;
+
+ bss_setbuf.cfg = htod32(bsscfg_idx);
+ bss_setbuf.val = htod32(val);
+ CFGP2P_INFO(("---cfg bss -C %d %s\n", bsscfg_idx, is_up ? "up" : "down"));
+ ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+
+ if (ret != 0) {
+ CFGP2P_ERR(("'bss %d' failed with %d\n", is_up, ret));
+ }
+
+ return ret;
+}
+
+/* Check if 'p2p' is supported in the driver */
+s32
+wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev)
+{
+ s32 ret = BCME_OK;
+ s32 p2p_supported = 0;
+ ret = wldev_iovar_getint(ndev, "p2p",
+ &p2p_supported);
+ if (ret < 0) {
+ if (ret == BCME_UNSUPPORTED) {
+ CFGP2P_INFO(("p2p is unsupported\n"));
+ return 0;
+ } else {
+ CFGP2P_ERR(("cfg p2p error %d\n", ret));
+ return ret;
+ }
+ }
+ if (p2p_supported == 1) {
+ CFGP2P_INFO(("p2p is supported\n"));
+ } else {
+ CFGP2P_INFO(("p2p is unsupported\n"));
+ p2p_supported = 0;
+ }
+ return p2p_supported;
+}
+/* Cleanup P2P resources */
+s32
+wl_cfgp2p_down(struct bcm_cfg80211 *cfg)
+{
+ struct net_device *ndev = NULL;
+ struct wireless_dev *wdev = NULL;
+ s32 i = 0, index = -1;
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+ ndev = bcmcfg_to_prmry_ndev(cfg);
+ wdev = bcmcfg_to_p2p_wdev(cfg);
+#elif defined(WL_ENABLE_P2P_IF)
+ ndev = cfg->p2p_net ? cfg->p2p_net : bcmcfg_to_prmry_ndev(cfg);
+ wdev = ndev_to_wdev(ndev);
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+ wl_cfgp2p_cancel_listen(cfg, ndev, wdev, TRUE);
+ wl_cfgp2p_disable_discovery(cfg);
+
+#if defined(WL_CFG80211_P2P_DEV_IF) && !defined(KEEP_WIFION_OPTION)
+ if (cfg->p2p_wdev) {
+ /* If p2p wdev is left out, clean it up */
+ WL_ERR(("Clean up the p2p discovery IF\n"));
+ wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg);
+ }
+#endif /* WL_CFG80211_P2P_DEV_IF !defined(KEEP_WIFION_OPTION) */
+
+ for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
+ index = wl_to_p2p_bss_bssidx(cfg, i);
+ if (index != WL_INVALID)
+ wl_cfg80211_clear_per_bss_ies(cfg, index);
+ }
+ wl_cfgp2p_deinit_priv(cfg);
+ return 0;
+}
+
+int wl_cfgp2p_vif_created(struct bcm_cfg80211 *cfg)
+{
+ if (cfg->p2p && ((wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION1) != -1) ||
+ (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION2) != -1)))
+ return true;
+ else
+ return false;
+
+}
+
+s32
+wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len)
+{
+ s32 ret = -1;
+ int count, start, duration;
+ wl_p2p_sched_t dongle_noa;
+ s32 bssidx, type;
+ int iovar_len = sizeof(dongle_noa);
+ CFGP2P_DBG((" Enter\n"));
+
+ memset(&dongle_noa, 0, sizeof(dongle_noa));
+
+ if (wl_cfgp2p_vif_created(cfg)) {
+ cfg->p2p->noa.desc[0].start = 0;
+
+ sscanf(buf, "%10d %10d %10d", &count, &start, &duration);
+ CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n",
+ count, start, duration));
+ if (count != -1)
+ cfg->p2p->noa.desc[0].count = count;
+
+ /* supplicant gives interval as start */
+ if (start != -1)
+ cfg->p2p->noa.desc[0].interval = start;
+
+ if (duration != -1)
+ cfg->p2p->noa.desc[0].duration = duration;
+
+ if (cfg->p2p->noa.desc[0].count != 255 && cfg->p2p->noa.desc[0].count != 0) {
+ cfg->p2p->noa.desc[0].start = 200;
+ dongle_noa.type = WL_P2P_SCHED_TYPE_REQ_ABS;
+ dongle_noa.action = WL_P2P_SCHED_ACTION_GOOFF;
+ dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS;
+ }
+ else if (cfg->p2p->noa.desc[0].count == 0) {
+ cfg->p2p->noa.desc[0].start = 0;
+ dongle_noa.type = WL_P2P_SCHED_TYPE_ABS;
+ dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL;
+ dongle_noa.action = WL_P2P_SCHED_ACTION_RESET;
+ }
+ else {
+ /* Continuous NoA interval. */
+ dongle_noa.action = WL_P2P_SCHED_ACTION_DOZE;
+ dongle_noa.type = WL_P2P_SCHED_TYPE_ABS;
+ if ((cfg->p2p->noa.desc[0].interval == 102) ||
+ (cfg->p2p->noa.desc[0].interval == 100)) {
+ cfg->p2p->noa.desc[0].start = 100 -
+ cfg->p2p->noa.desc[0].duration;
+ dongle_noa.option = WL_P2P_SCHED_OPTION_BCNPCT;
+ }
+ else {
+ dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL;
+ }
+ }
+ /* Put the noa descriptor in dongle format for dongle */
+ dongle_noa.desc[0].count = htod32(cfg->p2p->noa.desc[0].count);
+ if (dongle_noa.option == WL_P2P_SCHED_OPTION_BCNPCT) {
+ dongle_noa.desc[0].start = htod32(cfg->p2p->noa.desc[0].start);
+ dongle_noa.desc[0].duration = htod32(cfg->p2p->noa.desc[0].duration);
+ }
+ else {
+ dongle_noa.desc[0].start = htod32(cfg->p2p->noa.desc[0].start*1000);
+ dongle_noa.desc[0].duration = htod32(cfg->p2p->noa.desc[0].duration*1000);
+ }
+ dongle_noa.desc[0].interval = htod32(cfg->p2p->noa.desc[0].interval*1000);
+ bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
+ if (wl_cfgp2p_find_type(cfg, bssidx, &type) != BCME_OK)
+ return BCME_ERROR;
+
+ if (dongle_noa.action == WL_P2P_SCHED_ACTION_RESET) {
+ iovar_len -= sizeof(wl_p2p_sched_desc_t);
+ }
+
+ ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(cfg, type),
+ "p2p_noa", &dongle_noa, iovar_len, cfg->ioctl_buf,
+ WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+
+ if (ret < 0) {
+ CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret));
+ }
+ }
+ else {
+ CFGP2P_ERR(("ERROR: set_noa in non-p2p mode\n"));
+ }
+ return ret;
+}
+s32
+wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int buf_len)
+{
+
+ wifi_p2p_noa_desc_t *noa_desc;
+ int len = 0, i;
+ char _buf[200];
+
+ CFGP2P_DBG((" Enter\n"));
+ buf[0] = '\0';
+ if (wl_cfgp2p_vif_created(cfg)) {
+ if (cfg->p2p->noa.desc[0].count || cfg->p2p->ops.ops) {
+ _buf[0] = 1; /* noa index */
+ _buf[1] = (cfg->p2p->ops.ops ? 0x80: 0) |
+ (cfg->p2p->ops.ctw & 0x7f); /* ops + ctw */
+ len += 2;
+ if (cfg->p2p->noa.desc[0].count) {
+ noa_desc = (wifi_p2p_noa_desc_t*)&_buf[len];
+ noa_desc->cnt_type = cfg->p2p->noa.desc[0].count;
+ noa_desc->duration = cfg->p2p->noa.desc[0].duration;
+ noa_desc->interval = cfg->p2p->noa.desc[0].interval;
+ noa_desc->start = cfg->p2p->noa.desc[0].start;
+ len += sizeof(wifi_p2p_noa_desc_t);
+ }
+ if (buf_len <= len * 2) {
+ CFGP2P_ERR(("ERROR: buf_len %d in not enough for"
+ "returning noa in string format\n", buf_len));
+ return -1;
+ }
+ /* We have to convert the buffer data into ASCII strings */
+ for (i = 0; i < len; i++) {
+ snprintf(buf, 3, "%02x", _buf[i]);
+ buf += 2;
+ }
+ buf[i*2] = '\0';
+ }
+ }
+ else {
+ CFGP2P_ERR(("ERROR: get_noa in non-p2p mode\n"));
+ return -1;
+ }
+ return len * 2;
+}
+s32
+wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len)
+{
+ int ps, ctw;
+ int ret = -1;
+ s32 legacy_ps;
+ s32 conn_idx;
+ s32 bssidx;
+ struct net_device *dev;
+
+ CFGP2P_DBG((" Enter\n"));
+ if (wl_cfgp2p_vif_created(cfg)) {
+ sscanf(buf, "%10d %10d %10d", &legacy_ps, &ps, &ctw);
+ CFGP2P_DBG((" Enter legacy_ps %d ps %d ctw %d\n", legacy_ps, ps, ctw));
+
+ bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
+ if (wl_cfgp2p_find_type(cfg, bssidx, &conn_idx) != BCME_OK)
+ return BCME_ERROR;
+ dev = wl_to_p2p_bss_ndev(cfg, conn_idx);
+ if (ctw != -1) {
+ cfg->p2p->ops.ctw = ctw;
+ ret = 0;
+ }
+ if (ps != -1) {
+ cfg->p2p->ops.ops = ps;
+ ret = wldev_iovar_setbuf(dev,
+ "p2p_ops", &cfg->p2p->ops, sizeof(cfg->p2p->ops),
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (ret < 0) {
+ CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret));
+ }
+ }
+
+ if ((legacy_ps != -1) && ((legacy_ps == PM_MAX) || (legacy_ps == PM_OFF))) {
+ ret = wldev_ioctl(dev,
+ WLC_SET_PM, &legacy_ps, sizeof(legacy_ps), true);
+ if (unlikely(ret))
+ CFGP2P_ERR(("error (%d)\n", ret));
+ wl_cfg80211_update_power_mode(dev);
+ }
+ else
+ CFGP2P_ERR(("ilegal setting\n"));
+ }
+ else {
+ CFGP2P_ERR(("ERROR: set_p2p_ps in non-p2p mode\n"));
+ ret = -1;
+ }
+ return ret;
+}
+
+s32
+wl_cfgp2p_set_p2p_ecsa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len)
+{
+ int ch, bw;
+ s32 conn_idx;
+ s32 bssidx;
+ struct net_device *dev;
+ char smbuf[WLC_IOCTL_SMLEN];
+ wl_chan_switch_t csa_arg;
+ u32 chnsp = 0;
+ int err = 0;
+
+ CFGP2P_DBG((" Enter\n"));
+ if (wl_cfgp2p_vif_created(cfg)) {
+ sscanf(buf, "%10d %10d", &ch, &bw);
+ CFGP2P_DBG(("Enter ch %d bw %d\n", ch, bw));
+
+ bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
+ if (wl_cfgp2p_find_type(cfg, bssidx, &conn_idx) != BCME_OK) {
+ return BCME_ERROR;
+ }
+ dev = wl_to_p2p_bss_ndev(cfg, conn_idx);
+ if (ch <= 0 || bw <= 0) {
+ CFGP2P_ERR(("Negative value not permitted!\n"));
+ return BCME_ERROR;
+ }
+
+ csa_arg.mode = DOT11_CSA_MODE_ADVISORY;
+ csa_arg.count = P2P_ECSA_CNT;
+ csa_arg.reg = 0;
+
+ sprintf(buf, "%d/%d", ch, bw);
+ chnsp = wf_chspec_aton(buf);
+ if (chnsp == 0) {
+ CFGP2P_ERR(("%s:chsp is not correct\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+ chnsp = wl_chspec_host_to_driver(chnsp);
+ csa_arg.chspec = chnsp;
+
+ err = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg),
+ smbuf, sizeof(smbuf), NULL);
+ if (err) {
+ CFGP2P_ERR(("%s:set p2p_ecsa failed:%d\n", __FUNCTION__, err));
+ return BCME_ERROR;
+ }
+ } else {
+ CFGP2P_ERR(("ERROR: set_p2p_ecsa in non-p2p mode\n"));
+ return BCME_ERROR;
+ }
+ return BCME_OK;
+}
+
+s32
+wl_cfgp2p_increase_p2p_bw(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len)
+{
+ int algo;
+ int bw;
+ int ret = BCME_OK;
+
+
+ sscanf(buf, "%3d", &bw);
+ if (bw == 0) {
+ algo = 0;
+ ret = wldev_iovar_setbuf(ndev, "mchan_algo", &algo, sizeof(algo), cfg->ioctl_buf,
+ WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (ret < 0) {
+ CFGP2P_ERR(("fw set mchan_algo failed %d\n", ret));
+ return BCME_ERROR;
+ }
+ } else {
+ algo = 1;
+ ret = wldev_iovar_setbuf(ndev, "mchan_algo", &algo, sizeof(algo), cfg->ioctl_buf,
+ WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (ret < 0) {
+ CFGP2P_ERR(("fw set mchan_algo failed %d\n", ret));
+ return BCME_ERROR;
+ }
+ ret = wldev_iovar_setbuf(ndev, "mchan_bw", &bw, sizeof(algo), cfg->ioctl_buf,
+ WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (ret < 0) {
+ CFGP2P_ERR(("fw set mchan_bw failed %d\n", ret));
+ return BCME_ERROR;
+ }
+ }
+ return BCME_OK;
+}
+
+u8 *
+wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id)
+{
+ wifi_p2p_ie_t *ie = NULL;
+ u16 len = 0;
+ u8 *subel;
+ u8 subelt_id;
+ u16 subelt_len;
+
+ if (!buf) {
+ WL_ERR(("P2P IE not present"));
+ return 0;
+ }
+
+ ie = (wifi_p2p_ie_t*) buf;
+ len = ie->len;
+
+ /* Point subel to the P2P IE's subelt field.
+ * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
+ */
+ subel = ie->subelts;
+ len -= 4; /* exclude OUI + OUI_TYPE */
+
+ while (len >= 3) {
+ /* attribute id */
+ subelt_id = *subel;
+ subel += 1;
+ len -= 1;
+
+ /* 2-byte little endian */
+ subelt_len = *subel++;
+ subelt_len |= *subel++ << 8;
+
+ len -= 2;
+ len -= subelt_len; /* for the remaining subelt fields */
+
+ if (subelt_id == element_id) {
+ /* This will point to start of subelement attrib after
+ * attribute id & len
+ */
+ return subel;
+ }
+
+ /* Go to next subelement */
+ subel += subelt_len;
+ }
+
+ /* Not Found */
+ return NULL;
+}
+
+#define P2P_GROUP_CAPAB_GO_BIT 0x01
+
+u8*
+wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib)
+{
+ bcm_tlv_t *ie;
+ u8* pAttrib;
+
+ CFGP2P_INFO(("Starting parsing parse %p attrib %d remaining len %d ", parse, attrib, len));
+ while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) {
+ if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len) == TRUE) {
+ /* Have the P2p ie. Now check for attribute */
+ if ((pAttrib = wl_cfgp2p_retreive_p2pattrib(parse, attrib)) != NULL) {
+ CFGP2P_INFO(("P2P attribute %d was found at parse %p",
+ attrib, parse));
+ return pAttrib;
+ }
+ else {
+ parse += (ie->len + TLV_HDR_LEN);
+ len -= (ie->len + TLV_HDR_LEN);
+ CFGP2P_INFO(("P2P Attribute %d not found Moving parse"
+ " to %p len to %d", attrib, parse, len));
+ }
+ }
+ else {
+ /* It was not p2p IE. parse will get updated automatically to next TLV */
+ CFGP2P_INFO(("IT was NOT P2P IE parse %p len %d", parse, len));
+ }
+ }
+ CFGP2P_ERR(("P2P attribute %d was NOT found", attrib));
+ return NULL;
+}
+
+u8 *
+wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length)
+{
+ u8 *capability = NULL;
+ bool p2p_go = 0;
+ u8 *ptr = NULL;
+
+ if ((capability = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset,
+ bi->ie_length, P2P_SEID_P2P_INFO)) == NULL) {
+ WL_ERR(("P2P Capability attribute not found"));
+ return NULL;
+ }
+
+ /* Check Group capability for Group Owner bit */
+ p2p_go = capability[1] & P2P_GROUP_CAPAB_GO_BIT;
+ if (!p2p_go) {
+ return bi->BSSID.octet;
+ }
+
+ /* In probe responses, DEVICE INFO attribute will be present */
+ if (!(ptr = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset,
+ bi->ie_length, P2P_SEID_DEV_INFO))) {
+ /* If DEVICE_INFO is not found, this might be a beacon frame.
+ * check for DEVICE_ID in the beacon frame.
+ */
+ ptr = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset,
+ bi->ie_length, P2P_SEID_DEV_ID);
+ }
+
+ if (!ptr)
+ WL_ERR((" Both DEVICE_ID & DEVICE_INFO attribute not present in P2P IE "));
+
+ return ptr;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+static void
+wl_cfgp2p_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
+{
+ snprintf(info->driver, sizeof(info->driver), "p2p");
+ snprintf(info->version, sizeof(info->version), "%lu", (unsigned long)(0));
+}
+
+struct ethtool_ops cfgp2p_ethtool_ops = {
+ .get_drvinfo = wl_cfgp2p_ethtool_get_drvinfo
+};
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
+
+#if defined(WL_ENABLE_P2P_IF)
+s32
+wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg)
+{
+ int ret = 0;
+ struct net_device* net = NULL;
+ struct wireless_dev *wdev = NULL;
+ uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 };
+
+ if (cfg->p2p_net) {
+ CFGP2P_ERR(("p2p_net defined already.\n"));
+ return -EINVAL;
+ }
+
+ /* Allocate etherdev, including space for private structure */
+ if (!(net = alloc_etherdev(sizeof(struct bcm_cfg80211 *)))) {
+ CFGP2P_ERR(("%s: OOM - alloc_etherdev\n", __FUNCTION__));
+ return -ENODEV;
+ }
+
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (unlikely(!wdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ free_netdev(net);
+ return -ENOMEM;
+ }
+
+ strncpy(net->name, "p2p%d", sizeof(net->name) - 1);
+ net->name[IFNAMSIZ - 1] = '\0';
+
+ /* Copy the reference to bcm_cfg80211 */
+ memcpy((void *)netdev_priv(net), &cfg, sizeof(struct bcm_cfg80211 *));
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
+ ASSERT(!net->open);
+ net->do_ioctl = wl_cfgp2p_do_ioctl;
+ net->hard_start_xmit = wl_cfgp2p_start_xmit;
+ net->open = wl_cfgp2p_if_open;
+ net->stop = wl_cfgp2p_if_stop;
+#else
+ ASSERT(!net->netdev_ops);
+ net->netdev_ops = &wl_cfgp2p_if_ops;
+#endif
+
+ /* Register with a dummy MAC addr */
+ memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
+
+ wdev->wiphy = cfg->wdev->wiphy;
+
+ wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
+
+ net->ieee80211_ptr = wdev;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
+ net->ethtool_ops = &cfgp2p_ethtool_ops;
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
+
+ SET_NETDEV_DEV(net, wiphy_dev(wdev->wiphy));
+
+ /* Associate p2p0 network interface with new wdev */
+ wdev->netdev = net;
+
+ ret = register_netdev(net);
+ if (ret) {
+ CFGP2P_ERR((" register_netdevice failed (%d)\n", ret));
+ free_netdev(net);
+ kfree(wdev);
+ return -ENODEV;
+ }
+
+ /* store p2p net ptr for further reference. Note that iflist won't have this
+ * entry as there corresponding firmware interface is a "Hidden" interface.
+ */
+ cfg->p2p_wdev = wdev;
+ cfg->p2p_net = net;
+
+ printk("%s: P2P Interface Registered\n", net->name);
+
+ return ret;
+}
+
+s32
+wl_cfgp2p_unregister_ndev(struct bcm_cfg80211 *cfg)
+{
+
+ if (!cfg || !cfg->p2p_net) {
+ CFGP2P_ERR(("Invalid Ptr\n"));
+ return -EINVAL;
+ }
+
+ unregister_netdev(cfg->p2p_net);
+ free_netdev(cfg->p2p_net);
+
+ return 0;
+}
+static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+
+ if (skb)
+ {
+ CFGP2P_DBG(("(%s) is not used for data operations.Droping the packet.\n",
+ ndev->name));
+ dev_kfree_skb_any(skb);
+ }
+
+ return 0;
+}
+
+static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd)
+{
+ int ret = 0;
+ struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net);
+ struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
+
+ /* There is no ifidx corresponding to p2p0 in our firmware. So we should
+ * not Handle any IOCTL cmds on p2p0 other than ANDROID PRIVATE CMDs.
+ * For Android PRIV CMD handling map it to primary I/F
+ */
+ if (cmd == SIOCDEVPRIVATE+1) {
+ ret = wl_android_priv_cmd(ndev, ifr, cmd);
+
+ } else {
+ CFGP2P_ERR(("%s: IOCTL req 0x%x on p2p0 I/F. Ignoring. \n",
+ __FUNCTION__, cmd));
+ return -1;
+ }
+
+ return ret;
+}
+#endif
+
+#if defined(WL_ENABLE_P2P_IF)
+static int wl_cfgp2p_if_open(struct net_device *net)
+{
+ struct wireless_dev *wdev = net->ieee80211_ptr;
+
+ if (!wdev || !wl_cfg80211_is_p2p_active(wdev))
+ return -EINVAL;
+ WL_TRACE(("Enter\n"));
+#if !defined(WL_IFACE_COMB_NUM_CHANNELS)
+ /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now,
+ * do it here. This will make sure that in concurrent mode, supplicant
+ * is not dependent on a particular order of interface initialization.
+ * i.e you may give wpa_supp -iwlan0 -N -ip2p0 or wpa_supp -ip2p0 -N
+ * -iwlan0.
+ */
+ wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT)
+ | BIT(NL80211_IFTYPE_P2P_GO));
+#endif /* !WL_IFACE_COMB_NUM_CHANNELS */
+ wl_cfg80211_do_driver_init(net);
+
+ return 0;
+}
+
+static int wl_cfgp2p_if_stop(struct net_device *net)
+{
+ struct wireless_dev *wdev = net->ieee80211_ptr;
+
+ if (!wdev)
+ return -EINVAL;
+
+ wl_cfg80211_scan_stop(net);
+
+#if !defined(WL_IFACE_COMB_NUM_CHANNELS)
+ wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes)
+ & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)|
+ BIT(NL80211_IFTYPE_P2P_GO)));
+#endif /* !WL_IFACE_COMB_NUM_CHANNELS */
+ return 0;
+}
+
+bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops)
+{
+ return (if_ops == &wl_cfgp2p_if_ops);
+}
+#endif /* WL_ENABLE_P2P_IF */
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+struct wireless_dev *
+wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg)
+{
+ struct wireless_dev *wdev = NULL;
+ struct ether_addr primary_mac;
+
+ if (!cfg || !cfg->p2p_supported)
+ return ERR_PTR(-EINVAL);
+
+ WL_TRACE(("Enter\n"));
+
+ if (cfg->p2p_wdev) {
+#ifndef EXPLICIT_DISCIF_CLEANUP
+ dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
+#endif /* EXPLICIT_DISCIF_CLEANUP */
+ /*
+ * This is not expected. This can happen due to
+ * supplicant crash/unclean de-initialization which
+ * didn't free the p2p discovery interface. Indicate
+ * driver hang to user space so that the framework
+ * can rei-init the Wi-Fi.
+ */
+ CFGP2P_ERR(("p2p_wdev defined already.\n"));
+ wl_probe_wdev_all(cfg);
+#ifdef EXPLICIT_DISCIF_CLEANUP
+ /*
+ * CUSTOMER_HW4 design doesn't delete the p2p discovery
+ * interface on ifconfig wlan0 down context which comes
+ * without a preceeding NL80211_CMD_DEL_INTERFACE for p2p
+ * discovery. But during supplicant crash the DEL_IFACE
+ * command will not happen and will cause a left over iface
+ * even after ifconfig wlan0 down. So delete the iface
+ * first and then indicate the HANG event
+ */
+ wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg);
+#else
+ dhd->hang_reason = HANG_REASON_P2P_IFACE_DEL_FAILURE;
+ net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
+ return ERR_PTR(-ENODEV);
+#endif /* EXPLICIT_DISCIF_CLEANUP */
+ }
+
+ wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
+ if (unlikely(!wdev)) {
+ WL_ERR(("Could not allocate wireless device\n"));
+ return ERR_PTR(-ENOMEM);
+ }
+
+ memset(&primary_mac, 0, sizeof(primary_mac));
+ get_primary_mac(cfg, &primary_mac);
+ wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
+
+ wdev->wiphy = cfg->wdev->wiphy;
+ wdev->iftype = NL80211_IFTYPE_P2P_DEVICE;
+ memcpy(wdev->address, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE), ETHER_ADDR_LEN);
+
+
+ /* store p2p wdev ptr for further reference. */
+ cfg->p2p_wdev = wdev;
+
+ CFGP2P_ERR(("P2P interface registered\n"));
+#ifdef DHD_IFDEBUG
+ WL_ERR(("%s: wdev: %p, wdev->net: %p\n", __FUNCTION__, wdev, wdev->netdev));
+#endif
+ return wdev;
+}
+
+int
+wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ int ret = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+
+ if (!cfg)
+ return -EINVAL;
+
+ WL_TRACE(("Enter\n"));
+
+ ret = wl_cfgp2p_set_firm_p2p(cfg);
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR(("Set P2P in firmware failed, ret=%d\n", ret));
+ goto exit;
+ }
+
+ ret = wl_cfgp2p_enable_discovery(cfg, bcmcfg_to_prmry_ndev(cfg), NULL, 0);
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR(("P2P enable discovery failed, ret=%d\n", ret));
+ goto exit;
+ }
+
+ p2p_on(cfg) = true;
+#if defined(P2P_IE_MISSING_FIX)
+ cfg->p2p_prb_noti = false;
+#endif
+
+ CFGP2P_DBG(("P2P interface started\n"));
+
+exit:
+ return ret;
+}
+
+void
+wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ int ret = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+
+ if (!cfg)
+ return;
+
+ CFGP2P_DBG(("Enter\n"));
+
+ ret = wl_cfg80211_scan_stop(wdev);
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret));
+ }
+
+ if (!cfg->p2p)
+ return;
+
+ ret = wl_cfgp2p_disable_discovery(cfg);
+ if (unlikely(ret < 0)) {
+ CFGP2P_ERR(("P2P disable discovery failed, ret=%d\n", ret));
+ }
+
+ p2p_on(cfg) = false;
+
+ CFGP2P_DBG(("Exit. P2P interface stopped\n"));
+
+ return;
+}
+
+int
+wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev, struct bcm_cfg80211 *cfg)
+{
+ bool rollback_lock = false;
+
+ if (!wdev)
+ return -EINVAL;
+
+ WL_TRACE(("Enter\n"));
+#ifdef DHD_IFDEBUG
+ WL_ERR(("%s: wdev: %p, wdev->net: %p\n", __FUNCTION__, wdev, wdev->netdev));
+#endif
+
+ if (!rtnl_is_locked()) {
+ rtnl_lock();
+ rollback_lock = true;
+ }
+
+ cfg80211_unregister_wdev(wdev);
+
+ if (rollback_lock)
+ rtnl_unlock();
+
+ synchronize_rcu();
+
+ kfree(wdev);
+
+ if (cfg)
+ cfg->p2p_wdev = NULL;
+
+ CFGP2P_ERR(("P2P interface unregistered\n"));
+
+ return 0;
+}
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+void
+wl_cfgp2p_need_wait_actfrmae(struct bcm_cfg80211 *cfg, void *frame, u32 frame_len, bool tx)
+{
+ wifi_p2p_pub_act_frame_t *pact_frm;
+ int status = 0;
+
+ if (!frame || (frame_len < (sizeof(*pact_frm) + WL_P2P_AF_STATUS_OFFSET - 1))) {
+ return;
+ }
+
+ if (wl_cfgp2p_is_pub_action(frame, frame_len)) {
+ pact_frm = (wifi_p2p_pub_act_frame_t *)frame;
+ if (pact_frm->subtype == P2P_PAF_GON_RSP && tx) {
+ CFGP2P_ACTION(("Check TX P2P Group Owner Negotiation Rsp Frame status\n"));
+ status = pact_frm->elts[WL_P2P_AF_STATUS_OFFSET];
+ if (status) {
+ cfg->need_wait_afrx = false;
+ return;
+ }
+ }
+ }
+
+ cfg->need_wait_afrx = true;
+ return;
+}
+
+int
+wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request)
+{
+ if (request && (request->n_ssids == 1) &&
+ (request->n_channels == 1) &&
+ IS_P2P_SSID(request->ssids[0].ssid, WL_P2P_WILDCARD_SSID_LEN) &&
+ (request->ssids[0].ssid_len > WL_P2P_WILDCARD_SSID_LEN)) {
+ return true;
+ }
+ return false;
+}
diff --git a/drivers/net/wireless/bcmdhd_1363/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd_1363/wl_cfgp2p.h
new file mode 100644
index 000000000000..42b2932374ff
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/wl_cfgp2p.h
@@ -0,0 +1,446 @@
+/*
+ * Linux cfgp2p 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wl_cfgp2p.h 635563 2016-05-04 09:26:53Z $
+ */
+#ifndef _wl_cfgp2p_h_
+#define _wl_cfgp2p_h_
+#include <proto/802.11.h>
+#include <proto/p2p.h>
+
+struct bcm_cfg80211;
+extern u32 wl_dbg_level;
+
+typedef struct wifi_p2p_ie wifi_wfd_ie_t;
+/* Enumeration of the usages of the BSSCFGs used by the P2P Library. Do not
+ * confuse this with a bsscfg index. This value is an index into the
+ * saved_ie[] array of structures which in turn contains a bsscfg index field.
+ */
+typedef enum {
+ P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */
+ P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */
+ P2PAPI_BSSCFG_CONNECTION1, /* maps to driver's P2P connection bsscfg */
+ P2PAPI_BSSCFG_CONNECTION2,
+ P2PAPI_BSSCFG_MAX
+} p2p_bsscfg_type_t;
+
+typedef enum {
+ P2P_SCAN_PURPOSE_MIN,
+ P2P_SCAN_SOCIAL_CHANNEL, /* scan for social channel */
+ P2P_SCAN_AFX_PEER_NORMAL, /* scan for action frame search */
+ P2P_SCAN_AFX_PEER_REDUCED, /* scan for action frame search with short time */
+ P2P_SCAN_DURING_CONNECTED, /* scan during connected status */
+ P2P_SCAN_CONNECT_TRY, /* scan for connecting */
+ P2P_SCAN_NORMAL, /* scan during not-connected status */
+ P2P_SCAN_PURPOSE_MAX
+} p2p_scan_purpose_t;
+
+/* vendor ies max buffer length for probe response or beacon */
+#define VNDR_IES_MAX_BUF_LEN 1400
+/* normal vendor ies buffer length */
+#define VNDR_IES_BUF_LEN 512
+
+struct p2p_bss {
+ s32 bssidx;
+ struct net_device *dev;
+ void *private_data;
+ struct ether_addr mac_addr;
+};
+
+struct p2p_info {
+ bool on; /* p2p on/off switch */
+ bool scan;
+ int16 search_state;
+ s8 vir_ifname[IFNAMSIZ];
+ unsigned long status;
+ struct p2p_bss bss[P2PAPI_BSSCFG_MAX];
+ struct timer_list listen_timer;
+ wl_p2p_sched_t noa;
+ wl_p2p_ops_t ops;
+ wlc_ssid_t ssid;
+ s8 p2p_go_count;
+};
+
+#define MAX_VNDR_IE_NUMBER 10
+
+struct parsed_vndr_ie_info {
+ char *ie_ptr;
+ u32 ie_len; /* total length including id & length field */
+ vndr_ie_t vndrie;
+};
+
+struct parsed_vndr_ies {
+ u32 count;
+ struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER];
+};
+
+/* dongle status */
+enum wl_cfgp2p_status {
+ WLP2P_STATUS_DISCOVERY_ON = 0,
+ WLP2P_STATUS_SEARCH_ENABLED,
+ WLP2P_STATUS_IF_ADDING,
+ WLP2P_STATUS_IF_DELETING,
+ WLP2P_STATUS_IF_CHANGING,
+ WLP2P_STATUS_IF_CHANGED,
+ WLP2P_STATUS_LISTEN_EXPIRED,
+ WLP2P_STATUS_ACTION_TX_COMPLETED,
+ WLP2P_STATUS_ACTION_TX_NOACK,
+ WLP2P_STATUS_SCANNING,
+ WLP2P_STATUS_GO_NEG_PHASE,
+ WLP2P_STATUS_DISC_IN_PROGRESS
+};
+
+
+#define wl_to_p2p_bss_ndev(cfg, type) ((cfg)->p2p->bss[type].dev)
+#define wl_to_p2p_bss_bssidx(cfg, type) ((cfg)->p2p->bss[type].bssidx)
+#define wl_to_p2p_bss_macaddr(cfg, type) &((cfg)->p2p->bss[type].mac_addr)
+#define wl_to_p2p_bss_saved_ie(cfg, type) ((cfg)->p2p->bss[type].saved_ie)
+#define wl_to_p2p_bss_private(cfg, type) ((cfg)->p2p->bss[type].private_data)
+#define wl_to_p2p_bss(cfg, type) ((cfg)->p2p->bss[type])
+#define wl_get_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \
+ test_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status))
+#define wl_set_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \
+ set_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status))
+#define wl_clr_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \
+ clear_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status))
+#define wl_chg_p2p_status(cfg, stat) ((!(cfg)->p2p_supported) ? 0 : \
+ change_bit(WLP2P_STATUS_ ## stat, &(cfg)->p2p->status))
+#define p2p_on(cfg) ((cfg)->p2p->on)
+#define p2p_scan(cfg) ((cfg)->p2p->scan)
+#define p2p_is_on(cfg) ((cfg)->p2p && (cfg)->p2p->on)
+
+/* dword align allocation */
+#define WLC_IOCTL_MAXLEN 8192
+
+#ifdef CUSTOMER_HW4_DEBUG
+#define CFGP2P_ERROR_TEXT "CFGP2P-INFO2) "
+#else
+#define CFGP2P_ERROR_TEXT "CFGP2P-ERROR) "
+#endif /* CUSTOMER_HW4_DEBUG */
+
+#ifdef DHD_LOG_DUMP
+#define CFGP2P_ERR(args) \
+ do { \
+ if (wl_dbg_level & WL_DBG_ERR) { \
+ printk(KERN_INFO CFGP2P_ERROR_TEXT "%s : ", __func__); \
+ printk args; \
+ dhd_log_dump_print("[%s] %s: ", \
+ dhd_log_dump_get_timestamp(), __func__); \
+ dhd_log_dump_print args; \
+ } \
+ } while (0)
+#else
+#define CFGP2P_ERR(args) \
+ do { \
+ if (wl_dbg_level & WL_DBG_ERR) { \
+ printk(KERN_INFO CFGP2P_ERROR_TEXT "%s : ", __func__); \
+ printk args; \
+ } \
+ } while (0)
+#endif /* DHD_LOG_DUMP */
+#define CFGP2P_INFO(args) \
+ do { \
+ if (wl_dbg_level & WL_DBG_INFO) { \
+ printk(KERN_INFO "CFGP2P-INFO) %s : ", __func__); \
+ printk args; \
+ } \
+ } while (0)
+#define CFGP2P_DBG(args) \
+ do { \
+ if (wl_dbg_level & WL_DBG_DBG) { \
+ printk(KERN_DEBUG "CFGP2P-DEBUG) %s :", __func__); \
+ printk args; \
+ } \
+ } while (0)
+
+#define CFGP2P_ACTION(args) \
+ do { \
+ if (wl_dbg_level & WL_DBG_P2P_ACTION) { \
+ printk(KERN_DEBUG "CFGP2P-ACTION) %s :", __func__); \
+ printk args; \
+ } \
+ } while (0)
+#define INIT_TIMER(timer, func, duration, extra_delay) \
+ do { \
+ init_timer(timer); \
+ timer->function = func; \
+ timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \
+ timer->data = (unsigned long) cfg; \
+ add_timer(timer); \
+ } while (0);
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) && !defined(WL_CFG80211_P2P_DEV_IF)
+#define WL_CFG80211_P2P_DEV_IF
+
+#ifdef WL_ENABLE_P2P_IF
+#undef WL_ENABLE_P2P_IF
+#endif
+
+#ifdef WL_SUPPORT_BACKPORTED_KPATCHES
+#undef WL_SUPPORT_BACKPORTED_KPATCHES
+#endif
+#else
+#ifdef WLP2P
+#ifndef WL_ENABLE_P2P_IF
+/* Enable P2P network Interface if P2P support is enabled */
+#define WL_ENABLE_P2P_IF
+#endif /* WL_ENABLE_P2P_IF */
+#endif /* WLP2P */
+#endif /* (LINUX_VERSION >= VERSION(3, 8, 0)) */
+
+#ifndef WL_CFG80211_P2P_DEV_IF
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+#if defined(WL_ENABLE_P2P_IF) && (defined(WL_CFG80211_P2P_DEV_IF) || \
+ (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)))
+#error Disable 'WL_ENABLE_P2P_IF', if 'WL_CFG80211_P2P_DEV_IF' is enabled \
+ or kernel version is 3.8.0 or above
+#endif /* WL_ENABLE_P2P_IF && (WL_CFG80211_P2P_DEV_IF || (LINUX_VERSION >= VERSION(3, 8, 0))) */
+
+#if !defined(WLP2P) && (defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF))
+#error WLP2P not defined
+#endif /* !WLP2P && (WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF) */
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+#define bcm_struct_cfgdev struct wireless_dev
+#else
+#define bcm_struct_cfgdev struct net_device
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+#define P2P_ECSA_CNT 50
+
+extern void
+wl_cfgp2p_listen_expired(unsigned long data);
+extern bool
+wl_cfgp2p_is_pub_action(void *frame, u32 frame_len);
+extern bool
+wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len);
+extern bool
+wl_cfgp2p_is_gas_action(void *frame, u32 frame_len);
+extern bool
+wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len);
+extern bool
+wl_cfgp2p_is_p2p_gas_action(void *frame, u32 frame_len);
+extern void
+wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel);
+extern s32
+wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg);
+extern void
+wl_cfgp2p_deinit_priv(struct bcm_cfg80211 *cfg);
+extern s32
+wl_cfgp2p_set_firm_p2p(struct bcm_cfg80211 *cfg);
+extern s32
+wl_cfgp2p_set_p2p_mode(struct bcm_cfg80211 *cfg, u8 mode,
+ u32 channel, u16 listen_ms, int bssidx);
+extern s32
+wl_cfgp2p_ifadd(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type,
+ chanspec_t chspec);
+extern s32
+wl_cfgp2p_ifdisable(struct bcm_cfg80211 *cfg, struct ether_addr *mac);
+extern s32
+wl_cfgp2p_ifdel(struct bcm_cfg80211 *cfg, struct ether_addr *mac);
+extern s32
+wl_cfgp2p_ifchange(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type,
+ chanspec_t chspec, s32 conn_idx);
+
+extern s32
+wl_cfgp2p_ifidx(struct bcm_cfg80211 *cfg, struct ether_addr *mac, s32 *index);
+
+extern s32
+wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg);
+extern s32
+wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev, const u8 *ie,
+ u32 ie_len);
+extern s32
+wl_cfgp2p_disable_discovery(struct bcm_cfg80211 *cfg);
+extern s32
+wl_cfgp2p_escan(struct bcm_cfg80211 *cfg, struct net_device *dev, u16 active, u32 num_chans,
+ u16 *channels,
+ s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr,
+ p2p_scan_purpose_t p2p_scan_purpose);
+
+extern s32
+wl_cfgp2p_act_frm_search(struct bcm_cfg80211 *cfg, struct net_device *ndev,
+ s32 bssidx, s32 channel, struct ether_addr *tx_dst_addr);
+
+extern wpa_ie_fixed_t *
+wl_cfgp2p_find_wpaie(u8 *parse, u32 len);
+
+extern wpa_ie_fixed_t *
+wl_cfgp2p_find_wpsie(u8 *parse, u32 len);
+
+extern wifi_p2p_ie_t *
+wl_cfgp2p_find_p2pie(u8 *parse, u32 len);
+
+extern wifi_wfd_ie_t *
+wl_cfgp2p_find_wfdie(u8 *parse, u32 len);
+extern s32
+wl_cfgp2p_set_management_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx,
+ s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len);
+extern s32
+wl_cfgp2p_clear_management_ie(struct bcm_cfg80211 *cfg, s32 bssidx);
+
+extern struct net_device *
+wl_cfgp2p_find_ndev(struct bcm_cfg80211 *cfg, s32 bssidx);
+extern s32
+wl_cfgp2p_find_type(struct bcm_cfg80211 *cfg, s32 bssidx, s32 *type);
+
+
+extern s32
+wl_cfgp2p_listen_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+extern s32
+wl_cfgp2p_discover_listen(struct bcm_cfg80211 *cfg, s32 channel, u32 duration_ms);
+
+extern s32
+wl_cfgp2p_discover_enable_search(struct bcm_cfg80211 *cfg, u8 enable);
+
+extern s32
+wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
+ const wl_event_msg_t *e, void *data);
+
+extern s32
+wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev,
+ wl_af_params_t *af_params, s32 bssidx);
+
+extern void
+wl_cfgp2p_generate_bss_mac(struct bcm_cfg80211 *cfg, struct ether_addr *primary_addr);
+
+extern void
+wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id);
+extern bool
+wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx);
+
+extern s32
+wl_cfgp2p_bss(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bsscfg_idx, s32 up);
+
+
+extern s32
+wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev);
+
+extern s32
+wl_cfgp2p_down(struct bcm_cfg80211 *cfg);
+
+extern s32
+wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len);
+
+extern s32
+wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len);
+
+extern s32
+wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len);
+
+extern s32
+wl_cfgp2p_set_p2p_ecsa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len);
+
+extern s32
+wl_cfgp2p_increase_p2p_bw(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len);
+
+extern u8 *
+wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id);
+
+extern u8*
+wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib);
+
+extern u8 *
+wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length);
+
+extern s32
+wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg);
+
+extern s32
+wl_cfgp2p_unregister_ndev(struct bcm_cfg80211 *cfg);
+
+extern bool
+wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops);
+
+extern u32
+wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag,
+ s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd);
+
+extern int wl_cfgp2p_get_conn_idx(struct bcm_cfg80211 *cfg);
+
+extern
+int wl_cfg_multip2p_operational(struct bcm_cfg80211 *cfg);
+
+extern
+int wl_cfgp2p_vif_created(struct bcm_cfg80211 *cfg);
+
+#if defined(WL_CFG80211_P2P_DEV_IF)
+extern struct wireless_dev *
+wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg);
+
+extern int
+wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev);
+
+extern void
+wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev);
+
+extern int
+wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev, struct bcm_cfg80211 *cfg);
+
+#endif /* WL_CFG80211_P2P_DEV_IF */
+
+extern void
+wl_cfgp2p_need_wait_actfrmae(struct bcm_cfg80211 *cfg, void *frame, u32 frame_len, bool tx);
+
+extern int
+wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request);
+
+/* WiFi Direct */
+#define SOCIAL_CHAN_1 1
+#define SOCIAL_CHAN_2 6
+#define SOCIAL_CHAN_3 11
+#define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \
+ (channel == SOCIAL_CHAN_2) || \
+ (channel == SOCIAL_CHAN_3))
+#define SOCIAL_CHAN_CNT 3
+#define AF_PEER_SEARCH_CNT 2
+#define WL_P2P_WILDCARD_SSID "DIRECT-"
+#define WL_P2P_WILDCARD_SSID_LEN 7
+#define WL_P2P_INTERFACE_PREFIX "p2p"
+#define WL_P2P_TEMP_CHAN 11
+#define WL_P2P_AF_STATUS_OFFSET 9
+
+/* If the provision discovery is for JOIN operations,
+ * or the device discoverablity frame is destined to GO
+ * then we need not do an internal scan to find GO.
+ */
+#define IS_ACTPUB_WITHOUT_GROUP_ID(p2p_ie, len) \
+ (wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_GROUP_ID) == NULL)
+
+#define IS_GAS_REQ(frame, len) (wl_cfgp2p_is_gas_action(frame, len) && \
+ ((frame->action == P2PSD_ACTION_ID_GAS_IREQ) || \
+ (frame->action == P2PSD_ACTION_ID_GAS_CREQ)))
+
+#define IS_P2P_PUB_ACT_RSP_SUBTYPE(subtype) ((subtype == P2P_PAF_GON_RSP) || \
+ ((subtype == P2P_PAF_GON_CONF) || \
+ (subtype == P2P_PAF_INVITE_RSP) || \
+ (subtype == P2P_PAF_PROVDIS_RSP)))
+#define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3))
+#define IS_P2P_SSID(ssid, len) (!memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) && \
+ (len == WL_P2P_WILDCARD_SSID_LEN))
+#endif /* _wl_cfgp2p_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd_1363/wl_cfgvendor.c
new file mode 100644
index 000000000000..10231924d276
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/wl_cfgvendor.c
@@ -0,0 +1,1835 @@
+/*
+ * Linux cfg80211 Vendor Extension 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wl_cfgvendor.c 664399 2017-03-24 14:36:24Z $
+ */
+
+/*
+ * New vendor interface additon to nl80211/cfg80211 to allow vendors
+ * to implement proprietary features over the cfg80211 stack.
+*/
+
+#include <typedefs.h>
+#include <linuxver.h>
+#include <osl.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+
+#include <bcmutils.h>
+#include <bcmwifi_channels.h>
+#include <bcmendian.h>
+#include <proto/ethernet.h>
+#include <proto/802.11.h>
+#include <linux/if_arp.h>
+#include <asm/uaccess.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+#include <dhdioctl.h>
+#include <wlioctl.h>
+#include <wlioctl_utils.h>
+#include <dhd_cfg80211.h>
+#ifdef PNO_SUPPORT
+#include <dhd_pno.h>
+#endif /* PNO_SUPPORT */
+#ifdef RTT_SUPPORT
+#include <dhd_rtt.h>
+#endif /* RTT_SUPPORT */
+#include <proto/ethernet.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/ieee80211.h>
+#include <linux/wait.h>
+#include <net/cfg80211.h>
+#include <net/rtnetlink.h>
+
+#include <wlioctl.h>
+#include <wldev_common.h>
+#include <wl_cfg80211.h>
+#include <wl_cfgp2p.h>
+#include <wl_android.h>
+#include <wl_cfgvendor.h>
+
+#ifdef PROP_TXSTATUS
+#include <dhd_wlfc.h>
+#endif
+#include <brcm_nl80211.h>
+
+#if defined(WL_VENDOR_EXT_SUPPORT)
+/*
+ * This API is to be used for asynchronous vendor events. This
+ * shouldn't be used in response to a vendor command from its
+ * do_it handler context (instead wl_cfgvendor_send_cmd_reply should
+ * be used).
+ */
+int wl_cfgvendor_send_async_event(struct wiphy *wiphy,
+ struct net_device *dev, int event_id, const void *data, int len)
+{
+ u16 kflags;
+ struct sk_buff *skb;
+
+ kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
+
+ /* Alloc the SKB for vendor_event */
+#if defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)
+ skb = cfg80211_vendor_event_alloc(wiphy, NULL, len, event_id, kflags);
+#else
+ skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, kflags);
+#endif /* CONFIG_ARCH_MSM && SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC */
+ if (!skb) {
+ WL_ERR(("skb alloc failed"));
+ return -ENOMEM;
+ }
+
+ /* Push the data to the skb */
+ nla_put_nohdr(skb, len, data);
+
+ cfg80211_vendor_event(skb, kflags);
+
+ return 0;
+}
+
+static int
+wl_cfgvendor_send_cmd_reply(struct wiphy *wiphy,
+ struct net_device *dev, const void *data, int len)
+{
+ struct sk_buff *skb;
+
+ /* Alloc the SKB for vendor_event */
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
+ if (unlikely(!skb)) {
+ WL_ERR(("skb alloc failed"));
+ return -ENOMEM;
+ }
+
+ /* Push the data to the skb */
+ nla_put_nohdr(skb, len, data);
+
+ return cfg80211_vendor_cmd_reply(skb);
+}
+
+static int
+wl_cfgvendor_get_feature_set(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ int reply;
+
+ reply = dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg));
+
+ err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
+ &reply, sizeof(int));
+ if (unlikely(err))
+ WL_ERR(("Vendor Command reply failed ret:%d \n", err));
+
+ return err;
+}
+
+static int
+wl_cfgvendor_get_feature_set_matrix(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ struct sk_buff *skb;
+ int *reply;
+ int num, mem_needed, i;
+
+ reply = dhd_dev_get_feature_set_matrix(bcmcfg_to_prmry_ndev(cfg), &num);
+
+ if (!reply) {
+ WL_ERR(("Could not get feature list matrix\n"));
+ err = -EINVAL;
+ return err;
+ }
+ mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * num) +
+ ATTRIBUTE_U32_LEN;
+
+ /* Alloc the SKB for vendor_event */
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
+ if (unlikely(!skb)) {
+ WL_ERR(("skb alloc failed"));
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, num);
+ for (i = 0; i < num; i++) {
+ nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_FEATURE_SET, reply[i]);
+ }
+
+ err = cfg80211_vendor_cmd_reply(skb);
+
+ if (unlikely(err))
+ WL_ERR(("Vendor Command reply failed ret:%d \n", err));
+
+exit:
+ kfree(reply);
+ return err;
+}
+
+static int
+wl_cfgvendor_set_pno_mac_oui(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ int type;
+ uint8 pno_random_mac_oui[DOT11_OUI_LEN];
+
+ type = nla_type(data);
+
+ if (type == ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI) {
+ memcpy(pno_random_mac_oui, nla_data(data), DOT11_OUI_LEN);
+
+ err = dhd_dev_pno_set_mac_oui(bcmcfg_to_prmry_ndev(cfg), pno_random_mac_oui);
+
+ if (unlikely(err))
+ WL_ERR(("Bad OUI, could not set:%d \n", err));
+
+
+ } else {
+ err = -1;
+ }
+
+ return err;
+}
+
+#ifdef CUSTOM_FORCE_NODFS_FLAG
+static int
+wl_cfgvendor_set_nodfs_flag(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ int type;
+ u32 nodfs;
+
+ type = nla_type(data);
+ if (type == ANDR_WIFI_ATTRIBUTE_NODFS_SET) {
+ nodfs = nla_get_u32(data);
+ err = dhd_dev_set_nodfs(bcmcfg_to_prmry_ndev(cfg), nodfs);
+ } else {
+ err = -1;
+ }
+ return err;
+}
+#endif /* CUSTOM_FORCE_NODFS_FLAG */
+
+#ifdef GSCAN_SUPPORT
+int
+wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy,
+ struct net_device *dev, void *data, int len, wl_vendor_event_t event)
+{
+ u16 kflags;
+ const void *ptr;
+ struct sk_buff *skb;
+ int malloc_len, total, iter_cnt_to_send, cnt;
+ gscan_results_cache_t *cache = (gscan_results_cache_t *)data;
+ total = len/sizeof(wifi_gscan_result_t);
+ while (total > 0) {
+ malloc_len = (total * sizeof(wifi_gscan_result_t)) + VENDOR_DATA_OVERHEAD;
+ if (malloc_len > NLMSG_DEFAULT_SIZE) {
+ malloc_len = NLMSG_DEFAULT_SIZE;
+ }
+ iter_cnt_to_send =
+ (malloc_len - VENDOR_DATA_OVERHEAD)/sizeof(wifi_gscan_result_t);
+ total = total - iter_cnt_to_send;
+
+ kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
+
+ /* Alloc the SKB for vendor_event */
+#if defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)
+ skb = cfg80211_vendor_event_alloc(wiphy, NULL, malloc_len, event, kflags);
+#else
+ skb = cfg80211_vendor_event_alloc(wiphy, malloc_len, event, kflags);
+#endif /* CONFIG_ARCH_MSM && SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC */
+ if (!skb) {
+ WL_ERR(("skb alloc failed"));
+ return -ENOMEM;
+ }
+
+ while (cache && iter_cnt_to_send) {
+ ptr = (const void *) &cache->results[cache->tot_consumed];
+
+ if (iter_cnt_to_send < (cache->tot_count - cache->tot_consumed)) {
+ cnt = iter_cnt_to_send;
+ } else {
+ cnt = (cache->tot_count - cache->tot_consumed);
+ }
+
+ iter_cnt_to_send -= cnt;
+ cache->tot_consumed += cnt;
+ /* Push the data to the skb */
+ nla_append(skb, cnt * sizeof(wifi_gscan_result_t), ptr);
+ if (cache->tot_consumed == cache->tot_count) {
+ cache = cache->next;
+ }
+
+ }
+
+ cfg80211_vendor_event(skb, kflags);
+ }
+
+ return 0;
+}
+
+
+static int
+wl_cfgvendor_gscan_get_capabilities(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ dhd_pno_gscan_capabilities_t *reply = NULL;
+ uint32 reply_len = 0;
+
+
+ reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
+ DHD_PNO_GET_CAPABILITIES, NULL, &reply_len);
+ if (!reply) {
+ WL_ERR(("Could not get capabilities\n"));
+ err = -EINVAL;
+ return err;
+ }
+
+ err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
+ reply, reply_len);
+
+ if (unlikely(err)) {
+ WL_ERR(("Vendor Command reply failed ret:%d \n", err));
+ }
+
+ kfree(reply);
+ return err;
+}
+
+static int
+wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0, type, band;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ uint16 *reply = NULL;
+ uint32 reply_len = 0, num_channels, mem_needed;
+ struct sk_buff *skb;
+
+ type = nla_type(data);
+
+ if (type == GSCAN_ATTRIBUTE_BAND) {
+ band = nla_get_u32(data);
+ } else {
+ return -EINVAL;
+ }
+
+ reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
+ DHD_PNO_GET_CHANNEL_LIST, &band, &reply_len);
+
+ if (!reply) {
+ WL_ERR(("Could not get channel list\n"));
+ err = -EINVAL;
+ return err;
+ }
+ num_channels = reply_len/ sizeof(uint32);
+ mem_needed = reply_len + VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
+
+ /* Alloc the SKB for vendor_event */
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
+ if (unlikely(!skb)) {
+ WL_ERR(("skb alloc failed"));
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels);
+ nla_put(skb, GSCAN_ATTRIBUTE_CHANNEL_LIST, reply_len, reply);
+
+ err = cfg80211_vendor_cmd_reply(skb);
+
+ if (unlikely(err)) {
+ WL_ERR(("Vendor Command reply failed ret:%d \n", err));
+ }
+exit:
+ kfree(reply);
+ return err;
+}
+
+static int
+wl_cfgvendor_gscan_get_batch_results(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ gscan_results_cache_t *results, *iter;
+ uint32 reply_len, complete = 0, num_results_iter;
+ int32 mem_needed;
+ wifi_gscan_result_t *ptr;
+ uint16 num_scan_ids, num_results;
+ struct sk_buff *skb;
+ struct nlattr *scan_hdr;
+
+ dhd_dev_wait_batch_results_complete(bcmcfg_to_prmry_ndev(cfg));
+ dhd_dev_pno_lock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
+ results = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
+ DHD_PNO_GET_BATCH_RESULTS, NULL, &reply_len);
+
+ if (!results) {
+ WL_ERR(("No results to send %d\n", err));
+ err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
+ results, 0);
+
+ if (unlikely(err))
+ WL_ERR(("Vendor Command reply failed ret:%d \n", err));
+ dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
+ return err;
+ }
+ num_scan_ids = reply_len & 0xFFFF;
+ num_results = (reply_len & 0xFFFF0000) >> 16;
+ mem_needed = (num_results * sizeof(wifi_gscan_result_t)) +
+ (num_scan_ids * GSCAN_BATCH_RESULT_HDR_LEN) +
+ VENDOR_REPLY_OVERHEAD + SCAN_RESULTS_COMPLETE_FLAG_LEN;
+
+ if (mem_needed > (int32)NLMSG_DEFAULT_SIZE) {
+ mem_needed = (int32)NLMSG_DEFAULT_SIZE;
+ complete = 0;
+ } else {
+ complete = 1;
+ }
+
+ WL_TRACE(("complete %d mem_needed %d max_mem %d\n", complete, mem_needed,
+ (int)NLMSG_DEFAULT_SIZE));
+ /* Alloc the SKB for vendor_event */
+ skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
+ if (unlikely(!skb)) {
+ WL_ERR(("skb alloc failed"));
+ dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
+ return -ENOMEM;
+ }
+ iter = results;
+
+ nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, complete);
+ mem_needed = mem_needed - (SCAN_RESULTS_COMPLETE_FLAG_LEN + VENDOR_REPLY_OVERHEAD);
+ while (iter && ((mem_needed - GSCAN_BATCH_RESULT_HDR_LEN) > 0)) {
+
+ scan_hdr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS);
+ nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_ID, iter->scan_id);
+ nla_put_u8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, iter->flag);
+
+ num_results_iter =
+ (mem_needed - GSCAN_BATCH_RESULT_HDR_LEN)/sizeof(wifi_gscan_result_t);
+
+ if ((iter->tot_count - iter->tot_consumed) < num_results_iter)
+ num_results_iter = iter->tot_count - iter->tot_consumed;
+ nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num_results_iter);
+ if (num_results_iter) {
+ ptr = &iter->results[iter->tot_consumed];
+ iter->tot_consumed += num_results_iter;
+ nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS,
+ num_results_iter * sizeof(wifi_gscan_result_t), ptr);
+ }
+ nla_nest_end(skb, scan_hdr);
+ mem_needed -= GSCAN_BATCH_RESULT_HDR_LEN +
+ (num_results_iter * sizeof(wifi_gscan_result_t));
+ iter = iter->next;
+ }
+
+ dhd_dev_gscan_batch_cache_cleanup(bcmcfg_to_prmry_ndev(cfg));
+ dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
+
+ return cfg80211_vendor_cmd_reply(skb);
+}
+
+static int
+wl_cfgvendor_initiate_gscan(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ int type, tmp = len;
+ int run = 0xFF;
+ int flush = 0;
+ const struct nlattr *iter;
+
+ nla_for_each_attr(iter, data, len, tmp) {
+ type = nla_type(iter);
+ if (type == GSCAN_ATTRIBUTE_ENABLE_FEATURE)
+ run = nla_get_u32(iter);
+ else if (type == GSCAN_ATTRIBUTE_FLUSH_FEATURE)
+ flush = nla_get_u32(iter);
+ }
+
+ if (run != 0xFF) {
+ err = dhd_dev_pno_run_gscan(bcmcfg_to_prmry_ndev(cfg), run, flush);
+
+ if (unlikely(err)) {
+ WL_ERR(("Could not run gscan:%d \n", err));
+ }
+ return err;
+ } else {
+ return -EINVAL;
+ }
+
+
+}
+
+static int
+wl_cfgvendor_enable_full_scan_result(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ int type;
+ bool real_time = FALSE;
+
+ type = nla_type(data);
+
+ if (type == GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS) {
+ real_time = nla_get_u32(data);
+
+ err = dhd_dev_pno_enable_full_scan_result(bcmcfg_to_prmry_ndev(cfg), real_time);
+
+ if (unlikely(err)) {
+ WL_ERR(("Could not run gscan:%d \n", err));
+ }
+
+ } else {
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+#define GSCAN_MAX_CHANNELS_IN_BUCKET 32
+static int
+wl_cfgvendor_set_scan_cfg_bucket(const struct nlattr *prev,
+ gscan_scan_params_t *scan_param, int num)
+{
+ struct dhd_pno_gscan_channel_bucket *ch_bucket;
+ int k = 0, type, err = 0, rem;
+ const struct nlattr *cur, *next;
+
+ nla_for_each_nested(cur, prev, rem) {
+ type = nla_type(cur);
+ ch_bucket = scan_param->channel_bucket;
+ switch (type) {
+ case GSCAN_ATTRIBUTE_BUCKET_ID:
+ break;
+ case GSCAN_ATTRIBUTE_BUCKET_PERIOD:
+ if (nla_len(cur) != sizeof(uint32)) {
+ err = -EINVAL;
+ goto exit;
+ }
+ ch_bucket[num].bucket_freq_multiple = nla_get_u32(cur) / 1000;
+ break;
+ case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS:
+ if (nla_len(cur) != sizeof(uint32)) {
+ err = -EINVAL;
+ goto exit;
+ }
+ ch_bucket[num].num_channels = nla_get_u32(cur);
+ if (ch_bucket[num].num_channels > GSCAN_MAX_CHANNELS_IN_BUCKET) {
+ WL_ERR(("channel range:%d,bucket:%d\n",
+ ch_bucket[num].num_channels, num));
+ err = -EINVAL;
+ goto exit;
+ }
+ break;
+ case GSCAN_ATTRIBUTE_BUCKET_CHANNELS:
+ nla_for_each_nested(next, cur, rem) {
+ if (k >= GSCAN_MAX_CHANNELS_IN_BUCKET)
+ break;
+ if (nla_len(next) != sizeof(uint32)) {
+ err = -EINVAL;
+ goto exit;
+ }
+ ch_bucket[num].chan_list[k] = nla_get_u32(next);
+ k++;
+ }
+ break;
+ case GSCAN_ATTRIBUTE_BUCKETS_BAND:
+ if (nla_len(cur) != sizeof(uint32)) {
+ err = -EINVAL;
+ goto exit;
+ }
+ ch_bucket[num].band = (uint16)nla_get_u32(cur);
+ break;
+ case GSCAN_ATTRIBUTE_REPORT_EVENTS:
+ if (nla_len(cur) != sizeof(uint32)) {
+ err = -EINVAL;
+ goto exit;
+ }
+ ch_bucket[num].report_flag = (uint8)nla_get_u32(cur);
+ break;
+ default:
+ WL_ERR(("unknown attr type:%d\n", type));
+ err = -EINVAL;
+ goto exit;
+ }
+ }
+
+exit:
+ return err;
+}
+
+static int
+wl_cfgvendor_set_scan_cfg(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ gscan_scan_params_t *scan_param;
+ int j = 0;
+ int type, tmp;
+ const struct nlattr *iter;
+
+ scan_param = kzalloc(sizeof(gscan_scan_params_t), GFP_KERNEL);
+ if (!scan_param) {
+ WL_ERR(("Could not set GSCAN scan cfg, mem alloc failure\n"));
+ err = -EINVAL;
+ return err;
+
+ }
+
+ scan_param->scan_fr = PNO_SCAN_MIN_FW_SEC;
+ nla_for_each_attr(iter, data, len, tmp) {
+ type = nla_type(iter);
+
+ if (j >= GSCAN_MAX_CH_BUCKETS) {
+ break;
+ }
+
+ switch (type) {
+ case GSCAN_ATTRIBUTE_BASE_PERIOD:
+ if (nla_len(iter) != sizeof(uint32)) {
+ err = -EINVAL;
+ goto exit;
+ }
+ scan_param->scan_fr = nla_get_u32(iter)/1000;
+ break;
+ case GSCAN_ATTRIBUTE_NUM_BUCKETS:
+ if (nla_len(iter) != sizeof(uint32)) {
+ err = -EINVAL;
+ goto exit;
+ }
+ scan_param->nchannel_buckets = nla_get_u32(iter);
+ if (scan_param->nchannel_buckets >= GSCAN_MAX_CH_BUCKETS) {
+ WL_ERR(("ncha_buck out of range %d\n",
+ scan_param->nchannel_buckets));
+ err = -EINVAL;
+ goto exit;
+ }
+ break;
+ case GSCAN_ATTRIBUTE_CH_BUCKET_1:
+ case GSCAN_ATTRIBUTE_CH_BUCKET_2:
+ case GSCAN_ATTRIBUTE_CH_BUCKET_3:
+ case GSCAN_ATTRIBUTE_CH_BUCKET_4:
+ case GSCAN_ATTRIBUTE_CH_BUCKET_5:
+ case GSCAN_ATTRIBUTE_CH_BUCKET_6:
+ case GSCAN_ATTRIBUTE_CH_BUCKET_7:
+ err = wl_cfgvendor_set_scan_cfg_bucket(iter, scan_param, j);
+ if (err < 0) {
+ WL_ERR(("set_scan_cfg_buck error:%d\n", err));
+ goto exit;
+ }
+ j++;
+ break;
+ default:
+ WL_ERR(("Unknown type %d\n", type));
+ err = -EINVAL;
+ goto exit;
+ }
+ }
+
+ err = dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
+ DHD_PNO_SCAN_CFG_ID, scan_param, FALSE);
+
+ if (err < 0) {
+ WL_ERR(("Could not set GSCAN scan cfg\n"));
+ err = -EINVAL;
+ }
+
+exit:
+ kfree(scan_param);
+ return err;
+
+}
+
+static int
+wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ gscan_hotlist_scan_params_t *hotlist_params;
+ int tmp, tmp1, tmp2, type, j = 0;
+ const struct nlattr *outer, *inner = NULL, *iter;
+ uint8 flush = 0;
+ struct bssid_t *pbssid;
+
+ if (len < sizeof(*hotlist_params) || len >= WLC_IOCTL_MAXLEN) {
+ WL_ERR(("buffer length :%d wrong - bail out.\n", len));
+ return -EINVAL;
+ }
+
+ hotlist_params = kzalloc(sizeof(*hotlist_params)
+ + (sizeof(struct bssid_t) * (PFN_SWC_MAX_NUM_APS - 1)), GFP_KERNEL);
+ if (!hotlist_params) {
+ WL_ERR(("Cannot Malloc memory. \n"));
+ return -ENOMEM;
+ }
+
+ hotlist_params->lost_ap_window = GSCAN_LOST_AP_WINDOW_DEFAULT;
+
+ nla_for_each_attr(iter, data, len, tmp2) {
+ type = nla_type(iter);
+ switch (type) {
+ case GSCAN_ATTRIBUTE_HOTLIST_BSSIDS:
+ pbssid = hotlist_params->bssid;
+ nla_for_each_nested(outer, iter, tmp) {
+ nla_for_each_nested(inner, outer, tmp1) {
+ type = nla_type(inner);
+
+ switch (type) {
+ case GSCAN_ATTRIBUTE_BSSID:
+ if (nla_len(inner) != sizeof(pbssid[j].macaddr)) {
+ WL_ERR(("type:%d length:%d not matching.\n",
+ type, nla_len(inner)));
+ err = -EINVAL;
+ goto exit;
+ }
+ memcpy(&(pbssid[j].macaddr), nla_data(inner),
+ ETHER_ADDR_LEN);
+ break;
+ case GSCAN_ATTRIBUTE_RSSI_LOW:
+ if (nla_len(inner) != sizeof(uint8)) {
+ WL_ERR(("type:%d length:%d not matching.\n",
+ type, nla_len(inner)));
+ err = -EINVAL;
+ goto exit;
+ }
+ pbssid[j].rssi_reporting_threshold =
+ (int8)nla_get_u8(inner);
+ break;
+ case GSCAN_ATTRIBUTE_RSSI_HIGH:
+ if (nla_len(inner) != sizeof(uint8)) {
+ WL_ERR(("type:%d length:%d not matching.\n",
+ type, nla_len(inner)));
+ err = -EINVAL;
+ goto exit;
+ }
+ nla_get_u8(inner);
+ break;
+ default:
+ WL_ERR(("ATTR unknown %d\n", type));
+ err = -EINVAL;
+ goto exit;
+ }
+ }
+
+ if (++j >= PFN_SWC_MAX_NUM_APS) {
+ WL_ERR(("cap hotlist max:%d\n", j));
+ break;
+ }
+ }
+ hotlist_params->nbssid = j;
+ break;
+ case GSCAN_ATTRIBUTE_HOTLIST_FLUSH:
+ if (nla_len(iter) != sizeof(uint8)) {
+ WL_ERR(("type:%d length:%d not matching\n", type, nla_len(inner)));
+ err = -EINVAL;
+ goto exit;
+ }
+ flush = nla_get_u8(iter);
+ break;
+ case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE:
+ if (nla_len(iter) != sizeof(uint32)) {
+ WL_ERR(("type:%d length:%d not matching\n", type, nla_len(inner)));
+ err = -EINVAL;
+ goto exit;
+ }
+ hotlist_params->lost_ap_window = (uint16)nla_get_u32(iter);
+ break;
+ default:
+ WL_ERR(("Unknown type %d\n", type));
+ err = -EINVAL;
+ goto exit;
+ }
+ }
+
+ if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
+ DHD_PNO_GEOFENCE_SCAN_CFG_ID, hotlist_params, flush) < 0) {
+ WL_ERR(("Could not set GSCAN HOTLIST cfg error: %d\n", err));
+ err = -EINVAL;
+ goto exit;
+ }
+exit:
+ kfree(hotlist_params);
+ return err;
+}
+static int
+wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0, tmp, type;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ gscan_batch_params_t batch_param;
+ const struct nlattr *iter;
+
+ batch_param.mscan = batch_param.bestn = 0;
+ batch_param.buffer_threshold = GSCAN_BATCH_NO_THR_SET;
+
+ nla_for_each_attr(iter, data, len, tmp) {
+ type = nla_type(iter);
+
+ switch (type) {
+ case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN:
+ batch_param.bestn = nla_get_u32(iter);
+ break;
+ case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE:
+ batch_param.mscan = nla_get_u32(iter);
+ break;
+ case GSCAN_ATTRIBUTE_REPORT_THRESHOLD:
+ batch_param.buffer_threshold = nla_get_u32(iter);
+ break;
+ default:
+ WL_ERR(("Unknown type %d\n", type));
+ break;
+ }
+ }
+
+ if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
+ DHD_PNO_BATCH_SCAN_CFG_ID,
+ &batch_param, 0) < 0) {
+ WL_ERR(("Could not set batch cfg\n"));
+ err = -EINVAL;
+ return err;
+ }
+
+ return err;
+}
+
+static int
+wl_cfgvendor_significant_change_cfg(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ gscan_swc_params_t *significant_params;
+ int tmp, tmp1, tmp2, type, j = 0;
+ const struct nlattr *outer, *inner, *iter;
+ uint8 flush = 0;
+ wl_pfn_significant_bssid_t *bssid;
+
+ significant_params = (gscan_swc_params_t *) kzalloc(len, GFP_KERNEL);
+ if (!significant_params) {
+ WL_ERR(("Cannot Malloc mem to parse config commands size - %d bytes \n", len));
+ return -ENOMEM;
+ }
+
+ nla_for_each_attr(iter, data, len, tmp2) {
+ type = nla_type(iter);
+
+ switch (type) {
+ case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH:
+ flush = nla_get_u8(iter);
+ break;
+ case GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE:
+ significant_params->rssi_window = nla_get_u16(iter);
+ break;
+ case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE:
+ significant_params->lost_ap_window = nla_get_u16(iter);
+ break;
+ case GSCAN_ATTRIBUTE_MIN_BREACHING:
+ significant_params->swc_threshold = nla_get_u16(iter);
+ break;
+ case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS:
+ bssid = significant_params->bssid_elem_list;
+ nla_for_each_nested(outer, iter, tmp) {
+ nla_for_each_nested(inner, outer, tmp1) {
+ switch (nla_type(inner)) {
+ case GSCAN_ATTRIBUTE_BSSID:
+ memcpy(&(bssid[j].macaddr),
+ nla_data(inner),
+ ETHER_ADDR_LEN);
+ break;
+ case GSCAN_ATTRIBUTE_RSSI_HIGH:
+ bssid[j].rssi_high_threshold
+ = (int8) nla_get_u8(inner);
+ break;
+ case GSCAN_ATTRIBUTE_RSSI_LOW:
+ bssid[j].rssi_low_threshold
+ = (int8) nla_get_u8(inner);
+ break;
+ default:
+ WL_ERR(("ATTR unknown %d\n",
+ type));
+ break;
+ }
+ }
+ j++;
+ }
+ break;
+ default:
+ WL_ERR(("Unknown type %d\n", type));
+ break;
+ }
+ }
+ significant_params->nbssid = j;
+
+ if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
+ DHD_PNO_SIGNIFICANT_SCAN_CFG_ID,
+ significant_params, flush) < 0) {
+ WL_ERR(("Could not set GSCAN significant cfg\n"));
+ err = -EINVAL;
+ goto exit;
+ }
+exit:
+ kfree(significant_params);
+ return err;
+}
+#endif /* GSCAN_SUPPORT */
+
+#ifdef RTT_SUPPORT
+void
+wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data)
+{
+ struct wireless_dev *wdev = (struct wireless_dev *)ctx;
+ struct wiphy *wiphy;
+ struct sk_buff *skb;
+ uint32 tot_len = NLMSG_DEFAULT_SIZE, entry_len = 0;
+ gfp_t kflags;
+ rtt_report_t *rtt_report = NULL;
+ rtt_result_t *rtt_result = NULL;
+ struct list_head *rtt_list;
+ wiphy = wdev->wiphy;
+
+ WL_DBG(("In\n"));
+ /* Push the data to the skb */
+ if (!rtt_data) {
+ WL_ERR(("rtt_data is NULL\n"));
+ goto exit;
+ }
+ rtt_list = (struct list_head *)rtt_data;
+ kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
+ /* Alloc the SKB for vendor_event */
+#if defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)
+ skb = cfg80211_vendor_event_alloc(wiphy, NULL, tot_len, GOOGLE_RTT_COMPLETE_EVENT, kflags);
+#else
+ skb = cfg80211_vendor_event_alloc(wiphy, tot_len, GOOGLE_RTT_COMPLETE_EVENT, kflags);
+#endif /* CONFIG_ARCH_MSM && SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC */
+ if (!skb) {
+ WL_ERR(("skb alloc failed"));
+ goto exit;
+ }
+ /* fill in the rtt results on each entry */
+ list_for_each_entry(rtt_result, rtt_list, list) {
+ entry_len = 0;
+ entry_len = sizeof(rtt_report_t);
+ rtt_report = kzalloc(entry_len, kflags);
+ if (!rtt_report) {
+ WL_ERR(("rtt_report alloc failed"));
+ kfree_skb(skb);
+ goto exit;
+ }
+ rtt_report->addr = rtt_result->peer_mac;
+ rtt_report->num_measurement = 1; /* ONE SHOT */
+ rtt_report->status = rtt_result->err_code;
+ rtt_report->type =
+ (rtt_result->TOF_type == TOF_TYPE_ONE_WAY) ? RTT_ONE_WAY: RTT_TWO_WAY;
+ rtt_report->peer = rtt_result->target_info->peer;
+ rtt_report->channel = rtt_result->target_info->channel;
+ rtt_report->rssi = rtt_result->avg_rssi;
+ /* tx_rate */
+ rtt_report->tx_rate = rtt_result->tx_rate;
+ /* RTT */
+ rtt_report->rtt = rtt_result->meanrtt;
+ rtt_report->rtt_sd = rtt_result->sdrtt/10;
+ /* convert to centi meter */
+ if (rtt_result->distance != 0xffffffff)
+ rtt_report->distance = (rtt_result->distance >> 2) * 25;
+ else /* invalid distance */
+ rtt_report->distance = -1;
+ rtt_report->ts = rtt_result->ts;
+ nla_append(skb, entry_len, rtt_report);
+ kfree(rtt_report);
+ }
+ cfg80211_vendor_event(skb, kflags);
+exit:
+ return;
+}
+
+static int
+wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int len) {
+ int err = 0, rem, rem1, rem2, type;
+ rtt_config_params_t rtt_param;
+ rtt_target_info_t* rtt_target = NULL;
+ const struct nlattr *iter, *iter1, *iter2;
+ int8 eabuf[ETHER_ADDR_STR_LEN];
+ int8 chanbuf[CHANSPEC_STR_LEN];
+ int32 feature_set = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ feature_set = dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg));
+
+ WL_DBG(("In\n"));
+ err = dhd_dev_rtt_register_noti_callback(wdev->netdev, wdev, wl_cfgvendor_rtt_evt);
+ if (err < 0) {
+ WL_ERR(("failed to register rtt_noti_callback\n"));
+ goto exit;
+ }
+ memset(&rtt_param, 0, sizeof(rtt_param));
+ if (len <= 0) {
+ WL_ERR(("Length of the nlattr is not valid len : %d\n", len));
+ err = BCME_ERROR;
+ goto exit;
+ }
+ nla_for_each_attr(iter, data, len, rem) {
+ type = nla_type(iter);
+ switch (type) {
+ case RTT_ATTRIBUTE_TARGET_CNT:
+ rtt_param.rtt_target_cnt = nla_get_u8(iter);
+ if ((rtt_param.rtt_target_cnt <= 0) ||
+ (rtt_param.rtt_target_cnt > RTT_MAX_TARGET_CNT)) {
+ WL_ERR(("target_cnt is not valid : %d\n",
+ rtt_param.rtt_target_cnt));
+ err = BCME_RANGE;
+ goto exit;
+ }
+ break;
+ case RTT_ATTRIBUTE_TARGET_INFO:
+ /* Added this variable for safe check to avoid crash
+ * incase the caller did not respect the order
+ */
+ if (rtt_param.target_info == NULL) {
+ WL_ERR(("rtt_target_info is NULL\n"));
+ err = BCME_NOMEM;
+ goto exit;
+ }
+ rtt_target = rtt_param.target_info;
+ nla_for_each_nested(iter1, iter, rem1) {
+ nla_for_each_nested(iter2, iter1, rem2) {
+ type = nla_type(iter2);
+ switch (type) {
+ case RTT_ATTRIBUTE_TARGET_MAC:
+ memcpy(&rtt_target->addr, nla_data(iter2),
+ ETHER_ADDR_LEN);
+ break;
+ case RTT_ATTRIBUTE_TARGET_TYPE:
+ rtt_target->type = nla_get_u8(iter2);
+ if (!(feature_set & WIFI_FEATURE_D2D_RTT)) {
+ if (rtt_target->type == RTT_TWO_WAY ||
+ rtt_target->type == RTT_INVALID) {
+ WL_ERR(("doesn't support RTT type"
+ " : %d\n",
+ rtt_target->type));
+ err = -EINVAL;
+ goto exit;
+ } else if (rtt_target->type == RTT_AUTO) {
+ rtt_target->type = RTT_ONE_WAY;
+ }
+ } else if (rtt_target->type == RTT_INVALID) {
+ WL_ERR(("doesn't support RTT type"
+ " : %d\n",
+ rtt_target->type));
+ err = -EINVAL;
+ goto exit;
+ }
+ break;
+ case RTT_ATTRIBUTE_TARGET_PEER:
+ rtt_target->peer = nla_get_u8(iter2);
+ if (rtt_target->peer != RTT_PEER_AP) {
+ WL_ERR(("doesn't support peer type : %d\n",
+ rtt_target->peer));
+ err = -EINVAL;
+ goto exit;
+ }
+ break;
+ case RTT_ATTRIBUTE_TARGET_CHAN:
+ memcpy(&rtt_target->channel, nla_data(iter2),
+ sizeof(rtt_target->channel));
+ break;
+ case RTT_ATTRIBUTE_TARGET_MODE:
+ rtt_target->continuous = nla_get_u8(iter2);
+ break;
+ case RTT_ATTRIBUTE_TARGET_INTERVAL:
+ rtt_target->interval = nla_get_u32(iter2);
+ break;
+ case RTT_ATTRIBUTE_TARGET_NUM_MEASUREMENT:
+ rtt_target->measure_cnt = nla_get_u32(iter2);
+ break;
+ case RTT_ATTRIBUTE_TARGET_NUM_PKT:
+ rtt_target->ftm_cnt = nla_get_u32(iter2);
+ break;
+ case RTT_ATTRIBUTE_TARGET_NUM_RETRY:
+ rtt_target->retry_cnt = nla_get_u32(iter2);
+ }
+ }
+ /* convert to chanspec value */
+ rtt_target->chanspec =
+ dhd_rtt_convert_to_chspec(rtt_target->channel);
+ if (rtt_target->chanspec == 0) {
+ WL_ERR(("Channel is not valid \n"));
+ goto exit;
+ }
+ WL_INFORM(("Target addr %s, Channel : %s for RTT \n",
+ bcm_ether_ntoa((const struct ether_addr *)&rtt_target->addr,
+ eabuf),
+ wf_chspec_ntoa(rtt_target->chanspec, chanbuf)));
+ rtt_target++;
+ }
+ break;
+ }
+ }
+ WL_DBG(("leave :target_cnt : %d\n", rtt_param.rtt_target_cnt));
+ if (dhd_dev_rtt_set_cfg(bcmcfg_to_prmry_ndev(cfg), &rtt_param) < 0) {
+ WL_ERR(("Could not set RTT configuration\n"));
+ err = -EINVAL;
+ }
+exit:
+ return err;
+}
+
+static int
+wl_cfgvendor_rtt_cancel_config(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ int err = 0, rem, type, target_cnt = 0;
+ int target_cnt_chk = 0;
+ const struct nlattr *iter;
+ struct ether_addr *mac_list = NULL, *mac_addr = NULL;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+
+ if (len <= 0) {
+ WL_ERR(("Length of nlattr is not valid len : %d\n", len));
+ err = -EINVAL;
+ goto exit;
+ }
+ nla_for_each_attr(iter, data, len, rem) {
+ type = nla_type(iter);
+ switch (type) {
+ case RTT_ATTRIBUTE_TARGET_CNT:
+ if (mac_list != NULL) {
+ WL_ERR(("mac_list is not NULL\n"));
+ err = -EINVAL;
+ goto exit;
+ }
+ target_cnt = nla_get_u8(iter);
+ if ((target_cnt <= 0) && (target_cnt > RTT_MAX_TARGET_CNT)) {
+ /* cancel the current whole RTT process */
+ goto cancel;
+ }
+ mac_list = (struct ether_addr *)kzalloc(target_cnt * ETHER_ADDR_LEN,
+ GFP_KERNEL);
+ if (mac_list == NULL) {
+ WL_ERR(("failed to allocate mem for mac list\n"));
+ err = -EINVAL;
+ goto exit;
+ }
+ mac_addr = &mac_list[0];
+ break;
+ case RTT_ATTRIBUTE_TARGET_MAC:
+ if (mac_addr) {
+ memcpy(mac_addr++, nla_data(iter), ETHER_ADDR_LEN);
+ target_cnt_chk++;
+ if (target_cnt_chk > target_cnt) {
+ WL_ERR(("over target count\n"));
+ err = -EINVAL;
+ goto exit;
+ }
+ break;
+ } else {
+ WL_ERR(("mac_list is NULL\n"));
+ err = -EINVAL;
+ goto exit;
+ }
+ }
+ }
+cancel:
+ if (dhd_dev_rtt_cancel_cfg(bcmcfg_to_prmry_ndev(cfg), mac_list, target_cnt) < 0) {
+ WL_ERR(("Could not cancel RTT configuration\n"));
+ err = -EINVAL;
+ goto exit;
+ }
+
+exit:
+ if (mac_list) {
+ kfree(mac_list);
+ }
+ return err;
+}
+static int
+wl_cfgvendor_rtt_get_capability(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ int err = 0;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ rtt_capabilities_t capability;
+
+ err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
+ if (unlikely(err)) {
+ WL_ERR(("Vendor Command reply failed ret:%d \n", err));
+ goto exit;
+ }
+ err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
+ &capability, sizeof(capability));
+
+ if (unlikely(err)) {
+ WL_ERR(("Vendor Command reply failed ret:%d \n", err));
+ }
+exit:
+ return err;
+}
+
+#endif /* RTT_SUPPORT */
+
+#if defined(KEEP_ALIVE)
+static int wl_cfgvendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ /* max size of IP packet for keep alive */
+ const int MKEEP_ALIVE_IP_PKT_MAX = 256;
+
+ int ret = BCME_OK, rem, type;
+ u8 mkeep_alive_id = 0;
+ u8 *ip_pkt = NULL;
+ u16 ip_pkt_len = 0;
+ u8 src_mac[ETHER_ADDR_LEN];
+ u8 dst_mac[ETHER_ADDR_LEN];
+ u32 period_msec = 0;
+ const struct nlattr *iter;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ dhd_pub_t *dhd_pub = cfg->pub;
+ gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
+ nla_for_each_attr(iter, data, len, rem) {
+ type = nla_type(iter);
+ switch (type) {
+ case MKEEP_ALIVE_ATTRIBUTE_ID:
+ mkeep_alive_id = nla_get_u8(iter);
+ break;
+ case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN:
+ ip_pkt_len = nla_get_u16(iter);
+ if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) {
+ ret = BCME_BADARG;
+ goto exit;
+ }
+ break;
+ case MKEEP_ALIVE_ATTRIBUTE_IP_PKT:
+ if (!ip_pkt_len) {
+ ret = BCME_BADARG;
+ WL_ERR(("ip packet length is 0\n"));
+ goto exit;
+ }
+ ip_pkt = (u8 *)kzalloc(ip_pkt_len, kflags);
+ if (ip_pkt == NULL) {
+ ret = BCME_NOMEM;
+ WL_ERR(("Failed to allocate mem for ip packet\n"));
+ goto exit;
+ }
+ memcpy(ip_pkt, (u8*)nla_data(iter), ip_pkt_len);
+ break;
+ case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR:
+ memcpy(src_mac, nla_data(iter), ETHER_ADDR_LEN);
+ break;
+ case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR:
+ memcpy(dst_mac, nla_data(iter), ETHER_ADDR_LEN);
+ break;
+ case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC:
+ period_msec = nla_get_u32(iter);
+ break;
+ default:
+ WL_ERR(("Unknown type: %d\n", type));
+ ret = BCME_BADARG;
+ goto exit;
+ }
+ }
+
+ if (ip_pkt == NULL) {
+ ret = BCME_BADARG;
+ WL_ERR(("ip packet is NULL\n"));
+ goto exit;
+ }
+
+ ret = dhd_dev_start_mkeep_alive(dhd_pub, mkeep_alive_id, ip_pkt, ip_pkt_len, src_mac,
+ dst_mac, period_msec);
+ if (ret < 0) {
+ WL_ERR(("start_mkeep_alive is failed ret: %d\n", ret));
+ }
+
+exit:
+ if (ip_pkt) {
+ kfree(ip_pkt);
+ }
+
+ return ret;
+}
+
+static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
+ const void *data, int len)
+{
+ int ret = BCME_OK, rem, type;
+ u8 mkeep_alive_id = 0;
+ const struct nlattr *iter;
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ dhd_pub_t *dhd_pub = cfg->pub;
+
+ nla_for_each_attr(iter, data, len, rem) {
+ type = nla_type(iter);
+ switch (type) {
+ case MKEEP_ALIVE_ATTRIBUTE_ID:
+ mkeep_alive_id = nla_get_u8(iter);
+ break;
+ default:
+ WL_ERR(("Unknown type: %d\n", type));
+ ret = BCME_BADARG;
+ break;
+ }
+ }
+
+ ret = dhd_dev_stop_mkeep_alive(dhd_pub, mkeep_alive_id);
+ if (ret < 0) {
+ WL_ERR(("stop_mkeep_alive is failed ret: %d\n", ret));
+ }
+
+ return ret;
+}
+#endif /* defined(KEEP_ALIVE) */
+static int
+wl_cfgvendor_priv_string_handler(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ int ret = 0;
+ int ret_len = 0, payload = 0, msglen;
+ const struct bcm_nlmsg_hdr *nlioc = data;
+ void *buf = NULL, *cur;
+ int maxmsglen = PAGE_SIZE - 0x100;
+ struct sk_buff *reply;
+
+ WL_ERR(("entry: cmd = %d\n", nlioc->cmd));
+
+ len -= sizeof(struct bcm_nlmsg_hdr);
+ ret_len = nlioc->len;
+ if (ret_len > 0 || len > 0) {
+ if (len > DHD_IOCTL_MAXLEN) {
+ WL_ERR(("oversize input buffer %d\n", len));
+ len = DHD_IOCTL_MAXLEN;
+ }
+ if (ret_len > DHD_IOCTL_MAXLEN) {
+ WL_ERR(("oversize return buffer %d\n", ret_len));
+ ret_len = DHD_IOCTL_MAXLEN;
+ }
+ payload = max(ret_len, len) + 1;
+ buf = vzalloc(payload);
+ if (!buf) {
+ return -ENOMEM;
+ }
+ memcpy(buf, (void *)nlioc + nlioc->offset, len);
+ *(char *)(buf + len) = '\0';
+ }
+
+ ret = dhd_cfgvendor_priv_string_handler(cfg, wdev, nlioc, buf);
+ if (ret) {
+ WL_ERR(("dhd_cfgvendor returned error %d", ret));
+ vfree(buf);
+ return ret;
+ }
+ cur = buf;
+ while (ret_len > 0) {
+ msglen = nlioc->len > maxmsglen ? maxmsglen : ret_len;
+ ret_len -= msglen;
+ payload = msglen + sizeof(msglen);
+ reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
+ if (!reply) {
+ WL_ERR(("Failed to allocate reply msg\n"));
+ ret = -ENOMEM;
+ break;
+ }
+
+ if (nla_put(reply, BCM_NLATTR_DATA, msglen, cur) ||
+ nla_put_u16(reply, BCM_NLATTR_LEN, msglen)) {
+ kfree_skb(reply);
+ ret = -ENOBUFS;
+ break;
+ }
+
+ ret = cfg80211_vendor_cmd_reply(reply);
+ if (ret) {
+ WL_ERR(("testmode reply failed:%d\n", ret));
+ break;
+ }
+ cur += msglen;
+ }
+
+ return ret;
+}
+
+static int
+wl_cfgvendor_priv_bcm_handler(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ int err = 0;
+ int data_len = 0;
+
+ WL_INFORM(("%s: Enter \n", __func__));
+
+ bzero(cfg->ioctl_buf, WLC_IOCTL_MAXLEN);
+
+ if (strncmp((char *)data, BRCM_VENDOR_SCMD_CAPA, strlen(BRCM_VENDOR_SCMD_CAPA)) == 0) {
+ err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cap", NULL, 0,
+ cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
+ if (unlikely(err)) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+ data_len = strlen(cfg->ioctl_buf);
+ cfg->ioctl_buf[data_len] = '\0';
+ }
+
+ err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
+ cfg->ioctl_buf, data_len+1);
+ if (unlikely(err))
+ WL_ERR(("Vendor Command reply failed ret:%d \n", err));
+ else
+ WL_INFORM(("Vendor Command reply sent successfully!\n"));
+
+ return err;
+}
+
+#ifdef LINKSTAT_SUPPORT
+#define NUM_RATE 32
+#define NUM_PEER 1
+#define NUM_CHAN 11
+#define HEADER_SIZE sizeof(ver_len)
+static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy,
+ struct wireless_dev *wdev, const void *data, int len)
+{
+ static char iovar_buf[WLC_IOCTL_MAXLEN];
+ struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
+ int err = 0, i;
+ wifi_iface_stat *iface;
+ wifi_radio_stat *radio;
+ wl_wme_cnt_t *wl_wme_cnt;
+ wl_cnt_v_le10_mcst_t *macstat_cnt;
+ wl_cnt_wlc_t *wlc_cnt;
+ scb_val_t scbval;
+ char *output;
+ wifi_rate_stat *p_wifi_rate_stat = NULL;
+ wifi_rate_stat_v2 *p_wifi_rate_stat_v2 = NULL;
+ uint total_len = 0;
+
+
+ WL_INFORM(("%s: Enter \n", __func__));
+ RETURN_EIO_IF_NOT_UP(cfg);
+
+ bzero(&scbval, sizeof(scb_val_t));
+ bzero(cfg->ioctl_buf, WLC_IOCTL_MAXLEN);
+ bzero(iovar_buf, WLC_IOCTL_MAXLEN);
+
+ output = cfg->ioctl_buf;
+
+ err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "radiostat", NULL, 0,
+ iovar_buf, WLC_IOCTL_MAXLEN, NULL);
+ if (err != BCME_OK && err != BCME_UNSUPPORTED) {
+ WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wifi_radio_stat)));
+ return err;
+ }
+ radio = (wifi_radio_stat *)iovar_buf;
+ radio->num_channels = NUM_CHAN;
+ memcpy(output, iovar_buf+HEADER_SIZE, sizeof(wifi_radio_stat)-HEADER_SIZE);
+
+ output += (sizeof(wifi_radio_stat) - HEADER_SIZE) - sizeof(wifi_channel_stat);
+ output += (NUM_CHAN*sizeof(wifi_channel_stat));
+
+ err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "wme_counters", NULL, 0,
+ iovar_buf, WLC_IOCTL_MAXLEN, NULL);
+ if (unlikely(err)) {
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+ wl_wme_cnt = (wl_wme_cnt_t *)iovar_buf;
+ iface = (wifi_iface_stat *)output;
+
+ iface->ac[WIFI_AC_VO].ac = WIFI_AC_VO;
+ iface->ac[WIFI_AC_VO].tx_mpdu = wl_wme_cnt->tx[AC_VO].packets;
+ iface->ac[WIFI_AC_VO].rx_mpdu = wl_wme_cnt->rx[AC_VO].packets;
+ iface->ac[WIFI_AC_VO].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_VO].packets;
+
+ iface->ac[WIFI_AC_VI].ac = WIFI_AC_VI;
+ iface->ac[WIFI_AC_VI].tx_mpdu = wl_wme_cnt->tx[AC_VI].packets;
+ iface->ac[WIFI_AC_VI].rx_mpdu = wl_wme_cnt->rx[AC_VI].packets;
+ iface->ac[WIFI_AC_VI].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_VI].packets;
+
+ iface->ac[WIFI_AC_BE].ac = WIFI_AC_BE;
+ iface->ac[WIFI_AC_BE].tx_mpdu = wl_wme_cnt->tx[AC_BE].packets;
+ iface->ac[WIFI_AC_BE].rx_mpdu = wl_wme_cnt->rx[AC_BE].packets;
+ iface->ac[WIFI_AC_BE].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_BE].packets;
+
+ iface->ac[WIFI_AC_BK].ac = WIFI_AC_BK;
+ iface->ac[WIFI_AC_BK].tx_mpdu = wl_wme_cnt->tx[AC_BK].packets;
+ iface->ac[WIFI_AC_BK].rx_mpdu = wl_wme_cnt->rx[AC_BK].packets;
+ iface->ac[WIFI_AC_BK].mpdu_lost = wl_wme_cnt->tx_failed[WIFI_AC_BK].packets;
+ bzero(iovar_buf, WLC_IOCTL_MAXLEN);
+
+ err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "counters", NULL, 0,
+ iovar_buf, WLC_IOCTL_MAXLEN, NULL);
+ if (unlikely(err)) {
+ WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wl_cnt_wlc_t)));
+ return err;
+ }
+
+ /* Translate traditional (ver <= 10) counters struct to new xtlv type struct */
+ err = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WL_CNTBUF_MAX_SIZE, 0);
+ if (err != BCME_OK) {
+ WL_ERR(("%s wl_cntbuf_to_xtlv_format ERR %d\n", __FUNCTION__, err));
+ return err;
+ }
+
+ if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
+ WL_ERR(("%s wlc_cnt NULL!\n", __FUNCTION__));
+ return BCME_ERROR;
+ }
+
+ iface->ac[WIFI_AC_BE].retries = wlc_cnt->txretry;
+
+ if ((macstat_cnt = bcm_get_data_from_xtlv_buf(((wl_cnt_info_t *)iovar_buf)->data,
+ ((wl_cnt_info_t *)iovar_buf)->datalen,
+ WL_CNT_XTLV_CNTV_LE10_UCODE, NULL,
+ BCM_XTLV_OPTION_ALIGN32)) == NULL) {
+ macstat_cnt = bcm_get_data_from_xtlv_buf(((wl_cnt_info_t *)iovar_buf)->data,
+ ((wl_cnt_info_t *)iovar_buf)->datalen,
+ WL_CNT_XTLV_LT40_UCODE_V1, NULL,
+ BCM_XTLV_OPTION_ALIGN32);
+ }
+
+ if (macstat_cnt == NULL) {
+ printf("wlmTxGetAckedPackets: macstat_cnt NULL!\n");
+ return FALSE;
+ }
+
+ iface->beacon_rx = macstat_cnt->rxbeaconmbss;
+
+ err = wldev_get_rssi(bcmcfg_to_prmry_ndev(cfg), &scbval);
+ if (unlikely(err)) {
+ WL_ERR(("get_rssi error (%d)\n", err));
+ return err;
+ }
+ iface->rssi_mgmt = scbval.val;
+
+ iface->num_peers = NUM_PEER;
+ iface->peer_info->num_rate = NUM_RATE;
+
+ bzero(iovar_buf, WLC_IOCTL_MAXLEN);
+
+ output = (char *) &(iface->peer_info->num_rate);
+ output += sizeof(iface->peer_info->num_rate);
+
+ err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "ratestat", NULL, 0,
+ iovar_buf, WLC_IOCTL_MAXLEN, NULL);
+ if (err != BCME_OK && err != BCME_UNSUPPORTED) {
+ WL_ERR(("error (%d) - size = %zu\n", err, NUM_RATE*sizeof(wifi_rate_stat_v2)));
+ return err;
+ }
+ for (i = 0; i < NUM_RATE; i++) {
+
+ p_wifi_rate_stat_v2 =
+ (wifi_rate_stat_v2 *)(iovar_buf + i*sizeof(wifi_rate_stat_v2));
+
+ /* transform wifi_rate_stat_v2 to wifi_rate_stat */
+ p_wifi_rate_stat = (wifi_rate_stat *)output;
+ p_wifi_rate_stat->rate.preamble = p_wifi_rate_stat_v2->rate.preamble;
+ p_wifi_rate_stat->rate.nss = p_wifi_rate_stat_v2->rate.nss;
+ p_wifi_rate_stat->rate.bw = p_wifi_rate_stat_v2->rate.bw;
+ p_wifi_rate_stat->rate.rateMcsIdx = p_wifi_rate_stat_v2->rate.rateMcsIdx;
+ p_wifi_rate_stat->rate.reserved = p_wifi_rate_stat_v2->rate.reserved;
+ p_wifi_rate_stat->rate.bitrate = p_wifi_rate_stat_v2->rate.bitrate;
+ p_wifi_rate_stat->tx_mpdu = p_wifi_rate_stat_v2->tx_mpdu;
+ p_wifi_rate_stat->rx_mpdu = p_wifi_rate_stat_v2->rx_mpdu;
+ p_wifi_rate_stat->mpdu_lost = p_wifi_rate_stat_v2->mpdu_lost;
+ p_wifi_rate_stat->retries = p_wifi_rate_stat_v2->retries;
+ p_wifi_rate_stat->retries_short = p_wifi_rate_stat_v2->retries_short;
+ p_wifi_rate_stat->retries_long = p_wifi_rate_stat_v2->retries_long;
+
+ output = (char *) &(p_wifi_rate_stat->retries_long);
+ output += sizeof(p_wifi_rate_stat->retries_long);
+ }
+ total_len = sizeof(wifi_radio_stat)-HEADER_SIZE-sizeof(wifi_channel_stat) +
+ NUM_CHAN*sizeof(wifi_channel_stat) +
+ sizeof(wifi_iface_stat)-sizeof(wifi_peer_info) +
+ NUM_PEER*(sizeof(wifi_peer_info)-sizeof(wifi_rate_stat) +
+ NUM_RATE*sizeof(wifi_rate_stat));
+
+ if (total_len > WLC_IOCTL_MAXLEN) {
+ WL_ERR(("Error! total_len:%d is unexpected value\n", total_len));
+ return BCME_BADLEN;
+ }
+
+ err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
+ cfg->ioctl_buf,
+ total_len);
+
+ if (unlikely(err))
+ WL_ERR(("Vendor Command reply failed ret:%d \n", err));
+
+ return err;
+}
+#endif /* LINKSTAT_SUPPORT */
+
+static const struct wiphy_vendor_command wl_vendor_cmds [] = {
+ {
+ {
+ .vendor_id = OUI_BRCM,
+ .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_priv_string_handler
+ },
+ {
+ {
+ .vendor_id = OUI_BRCM,
+ .subcmd = BRCM_VENDOR_SCMD_BCM_STR
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_priv_bcm_handler
+ },
+#ifdef GSCAN_SUPPORT
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_gscan_get_capabilities
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_SET_CONFIG
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_set_scan_cfg
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_set_batch_scan_cfg
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_initiate_gscan
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_enable_full_scan_result
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_SET_HOTLIST
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_hotlist_cfg
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_significant_change_cfg
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_gscan_get_batch_results
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_gscan_get_channel_list
+ },
+#endif /* GSCAN_SUPPORT */
+#ifdef RTT_SUPPORT
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = RTT_SUBCMD_SET_CONFIG
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_rtt_set_config
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = RTT_SUBCMD_CANCEL_CONFIG
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_rtt_cancel_config
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = RTT_SUBCMD_GETCAPABILITY
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_rtt_get_capability
+ },
+#endif /* RTT_SUPPORT */
+#ifdef KEEP_ALIVE
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_start_mkeep_alive
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_stop_mkeep_alive
+ },
+#endif /* KEEP_ALIVE */
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_get_feature_set
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_get_feature_set_matrix
+ },
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = ANDR_WIFI_PNO_RANDOM_MAC_OUI
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_set_pno_mac_oui
+ },
+#ifdef CUSTOM_FORCE_NODFS_FLAG
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = ANDR_WIFI_NODFS_CHANNELS
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_set_nodfs_flag
+
+ },
+#endif /* CUSTOM_FORCE_NODFS_FLAG */
+#ifdef LINKSTAT_SUPPORT
+ {
+ {
+ .vendor_id = OUI_GOOGLE,
+ .subcmd = LSTATS_SUBCMD_GET_INFO
+ },
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
+ .doit = wl_cfgvendor_lstats_get_info
+ },
+#endif /* LINKSTAT_SUPPORT */
+};
+
+static const struct nl80211_vendor_cmd_info wl_vendor_events [] = {
+ { OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC },
+ { OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR },
+#ifdef GSCAN_SUPPORT
+ { OUI_GOOGLE, GOOGLE_GSCAN_SIGNIFICANT_EVENT },
+ { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT },
+ { OUI_GOOGLE, GOOGLE_GSCAN_BATCH_SCAN_EVENT },
+ { OUI_GOOGLE, GOOGLE_SCAN_FULL_RESULTS_EVENT },
+#endif /* GSCAN_SUPPORT */
+#ifdef RTT_SUPPORT
+ { OUI_GOOGLE, GOOGLE_RTT_COMPLETE_EVENT },
+#endif /* RTT_SUPPORT */
+#ifdef GSCAN_SUPPORT
+ { OUI_GOOGLE, GOOGLE_SCAN_COMPLETE_EVENT },
+ { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT },
+#endif /* GSCAN_SUPPORT */
+ { OUI_GOOGLE, GOOGLE_RSSI_MONITOR_EVENT },
+#ifdef KEEP_ALIVE
+ { OUI_GOOGLE, GOOGLE_MKEEP_ALIVE_EVENT },
+#endif
+ { OUI_BRCM, BRCM_VENDOR_EVENT_IDSUP_STATUS }
+};
+
+int wl_cfgvendor_attach(struct wiphy *wiphy)
+{
+
+ WL_INFORM(("Vendor: Register BRCM cfg80211 vendor cmd(0x%x) interface \n",
+ NL80211_CMD_VENDOR));
+
+ wiphy->vendor_commands = wl_vendor_cmds;
+ wiphy->n_vendor_commands = ARRAY_SIZE(wl_vendor_cmds);
+ wiphy->vendor_events = wl_vendor_events;
+ wiphy->n_vendor_events = ARRAY_SIZE(wl_vendor_events);
+
+ return 0;
+}
+
+int wl_cfgvendor_detach(struct wiphy *wiphy)
+{
+ WL_INFORM(("Vendor: Unregister BRCM cfg80211 vendor interface \n"));
+
+ wiphy->vendor_commands = NULL;
+ wiphy->vendor_events = NULL;
+ wiphy->n_vendor_commands = 0;
+ wiphy->n_vendor_events = 0;
+
+ return 0;
+}
+#endif /* defined(WL_VENDOR_EXT_SUPPORT) */
diff --git a/drivers/net/wireless/bcmdhd_1363/wl_cfgvendor.h b/drivers/net/wireless/bcmdhd_1363/wl_cfgvendor.h
new file mode 100644
index 000000000000..414692e23d7a
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/wl_cfgvendor.h
@@ -0,0 +1,286 @@
+/*
+ * Linux cfg80211 Vendor Extension 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wl_cfgvendor.h 630676 2016-04-11 15:20:57Z $
+ */
+
+
+#ifndef _wl_cfgvendor_h_
+#define _wl_cfgvendor_h_
+
+#define OUI_BRCM 0x001018
+#define OUI_GOOGLE 0x001A11
+#define BRCM_VENDOR_SUBCMD_PRIV_STR 1
+#define ATTRIBUTE_U32_LEN (NLA_HDRLEN + 4)
+#define VENDOR_ID_OVERHEAD ATTRIBUTE_U32_LEN
+#define VENDOR_SUBCMD_OVERHEAD ATTRIBUTE_U32_LEN
+#define VENDOR_DATA_OVERHEAD (NLA_HDRLEN)
+
+#define SCAN_RESULTS_COMPLETE_FLAG_LEN ATTRIBUTE_U32_LEN
+#define SCAN_INDEX_HDR_LEN (NLA_HDRLEN)
+#define SCAN_ID_HDR_LEN ATTRIBUTE_U32_LEN
+#define SCAN_FLAGS_HDR_LEN ATTRIBUTE_U32_LEN
+#define GSCAN_NUM_RESULTS_HDR_LEN ATTRIBUTE_U32_LEN
+#define GSCAN_RESULTS_HDR_LEN (NLA_HDRLEN)
+#define GSCAN_BATCH_RESULT_HDR_LEN (SCAN_INDEX_HDR_LEN + SCAN_ID_HDR_LEN + \
+ SCAN_FLAGS_HDR_LEN + \
+ GSCAN_NUM_RESULTS_HDR_LEN + \
+ GSCAN_RESULTS_HDR_LEN)
+
+#define VENDOR_REPLY_OVERHEAD (VENDOR_ID_OVERHEAD + \
+ VENDOR_SUBCMD_OVERHEAD + \
+ VENDOR_DATA_OVERHEAD)
+
+#define GSCAN_ATTR_SET1 10
+#define GSCAN_ATTR_SET2 20
+#define GSCAN_ATTR_SET3 30
+#define GSCAN_ATTR_SET4 40
+#define GSCAN_ATTR_SET5 50
+#define GSCAN_ATTR_SET6 60
+
+typedef enum {
+ /* don't use 0 as a valid subcommand */
+ VENDOR_NL80211_SUBCMD_UNSPECIFIED,
+
+ /* define all vendor startup commands between 0x0 and 0x0FFF */
+ VENDOR_NL80211_SUBCMD_RANGE_START = 0x0001,
+ VENDOR_NL80211_SUBCMD_RANGE_END = 0x0FFF,
+
+ /* define all GScan related commands between 0x1000 and 0x10FF */
+ ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000,
+ ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END = 0x10FF,
+
+ /* define all NearbyDiscovery related commands between 0x1100 and 0x11FF */
+ ANDROID_NL80211_SUBCMD_NBD_RANGE_START = 0x1100,
+ ANDROID_NL80211_SUBCMD_NBD_RANGE_END = 0x11FF,
+
+ /* define all RTT related commands between 0x1100 and 0x11FF */
+ ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100,
+ ANDROID_NL80211_SUBCMD_RTT_RANGE_END = 0x11FF,
+
+ ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200,
+ ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END = 0x12FF,
+
+ ANDROID_NL80211_SUBCMD_TDLS_RANGE_START = 0x1300,
+ ANDROID_NL80211_SUBCMD_TDLS_RANGE_END = 0x13FF,
+ /* This is reserved for future usage */
+
+ /* define all wifi calling related commands between 0x1600 and 0x16FF */
+ ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1600,
+ ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END = 0x16FF
+} ANDROID_VENDOR_SUB_COMMAND;
+enum andr_vendor_subcmd {
+ GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
+ GSCAN_SUBCMD_SET_CONFIG,
+ GSCAN_SUBCMD_SET_SCAN_CONFIG,
+ GSCAN_SUBCMD_ENABLE_GSCAN,
+ GSCAN_SUBCMD_GET_SCAN_RESULTS,
+ GSCAN_SUBCMD_SCAN_RESULTS,
+ GSCAN_SUBCMD_SET_HOTLIST,
+ GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG,
+ GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS,
+ GSCAN_SUBCMD_GET_CHANNEL_LIST,
+ /* ANDR_WIFI_XXX although not related to gscan are defined here */
+ ANDR_WIFI_SUBCMD_GET_FEATURE_SET,
+ ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX,
+ ANDR_WIFI_PNO_RANDOM_MAC_OUI,
+ ANDR_WIFI_NODFS_CHANNELS,
+ RTT_SUBCMD_SET_CONFIG = ANDROID_NL80211_SUBCMD_RTT_RANGE_START,
+ RTT_SUBCMD_CANCEL_CONFIG,
+ RTT_SUBCMD_GETCAPABILITY,
+
+ LSTATS_SUBCMD_GET_INFO = ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START,
+
+ WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START,
+ WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE,
+ /* Add more sub commands here */
+ VENDOR_SUBCMD_MAX
+};
+
+enum gscan_attributes {
+ GSCAN_ATTRIBUTE_NUM_BUCKETS = GSCAN_ATTR_SET1,
+ GSCAN_ATTRIBUTE_BASE_PERIOD,
+ GSCAN_ATTRIBUTE_BUCKETS_BAND,
+ GSCAN_ATTRIBUTE_BUCKET_ID,
+ GSCAN_ATTRIBUTE_BUCKET_PERIOD,
+ GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
+ GSCAN_ATTRIBUTE_BUCKET_CHANNELS,
+ GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN,
+ GSCAN_ATTRIBUTE_REPORT_THRESHOLD,
+ GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE,
+ GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND,
+
+ GSCAN_ATTRIBUTE_ENABLE_FEATURE = GSCAN_ATTR_SET2,
+ GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE,
+ GSCAN_ATTRIBUTE_FLUSH_FEATURE,
+ GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS,
+ GSCAN_ATTRIBUTE_REPORT_EVENTS,
+ /* remaining reserved for additional attributes */
+ GSCAN_ATTRIBUTE_NUM_OF_RESULTS = GSCAN_ATTR_SET3,
+ GSCAN_ATTRIBUTE_FLUSH_RESULTS,
+ GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */
+ GSCAN_ATTRIBUTE_SCAN_ID, /* indicates scan number */
+ GSCAN_ATTRIBUTE_SCAN_FLAGS, /* indicates if scan was aborted */
+ GSCAN_ATTRIBUTE_AP_FLAGS, /* flags on significant change event */
+ GSCAN_ATTRIBUTE_NUM_CHANNELS,
+ GSCAN_ATTRIBUTE_CHANNEL_LIST,
+
+ /* remaining reserved for additional attributes */
+
+ GSCAN_ATTRIBUTE_SSID = GSCAN_ATTR_SET4,
+ GSCAN_ATTRIBUTE_BSSID,
+ GSCAN_ATTRIBUTE_CHANNEL,
+ GSCAN_ATTRIBUTE_RSSI,
+ GSCAN_ATTRIBUTE_TIMESTAMP,
+ GSCAN_ATTRIBUTE_RTT,
+ GSCAN_ATTRIBUTE_RTTSD,
+
+ /* remaining reserved for additional attributes */
+
+ GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = GSCAN_ATTR_SET5,
+ GSCAN_ATTRIBUTE_RSSI_LOW,
+ GSCAN_ATTRIBUTE_RSSI_HIGH,
+ GSCAN_ATTRIBUTE_HOSTLIST_BSSID_ELEM,
+ GSCAN_ATTRIBUTE_HOTLIST_FLUSH,
+
+ /* remaining reserved for additional attributes */
+ GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = GSCAN_ATTR_SET6,
+ GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE,
+ GSCAN_ATTRIBUTE_MIN_BREACHING,
+ GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS,
+ GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH,
+ GSCAN_ATTRIBUTE_MAX
+};
+
+enum gscan_bucket_attributes {
+ GSCAN_ATTRIBUTE_CH_BUCKET_1,
+ GSCAN_ATTRIBUTE_CH_BUCKET_2,
+ GSCAN_ATTRIBUTE_CH_BUCKET_3,
+ GSCAN_ATTRIBUTE_CH_BUCKET_4,
+ GSCAN_ATTRIBUTE_CH_BUCKET_5,
+ GSCAN_ATTRIBUTE_CH_BUCKET_6,
+ GSCAN_ATTRIBUTE_CH_BUCKET_7
+};
+
+enum gscan_ch_attributes {
+ GSCAN_ATTRIBUTE_CH_ID_1,
+ GSCAN_ATTRIBUTE_CH_ID_2,
+ GSCAN_ATTRIBUTE_CH_ID_3,
+ GSCAN_ATTRIBUTE_CH_ID_4,
+ GSCAN_ATTRIBUTE_CH_ID_5,
+ GSCAN_ATTRIBUTE_CH_ID_6,
+ GSCAN_ATTRIBUTE_CH_ID_7
+};
+
+enum rtt_attributes {
+ RTT_ATTRIBUTE_TARGET_CNT,
+ RTT_ATTRIBUTE_TARGET_INFO,
+ RTT_ATTRIBUTE_TARGET_MAC,
+ RTT_ATTRIBUTE_TARGET_TYPE,
+ RTT_ATTRIBUTE_TARGET_PEER,
+ RTT_ATTRIBUTE_TARGET_CHAN,
+ RTT_ATTRIBUTE_TARGET_MODE,
+ RTT_ATTRIBUTE_TARGET_INTERVAL,
+ RTT_ATTRIBUTE_TARGET_NUM_MEASUREMENT,
+ RTT_ATTRIBUTE_TARGET_NUM_PKT,
+ RTT_ATTRIBUTE_TARGET_NUM_RETRY
+};
+
+enum mkeep_alive_attributes {
+ MKEEP_ALIVE_ATTRIBUTE_ID,
+ MKEEP_ALIVE_ATTRIBUTE_IP_PKT,
+ MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN,
+ MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR,
+ MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR,
+ MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC
+};
+
+typedef enum wl_vendor_event {
+ BRCM_VENDOR_EVENT_UNSPEC,
+ BRCM_VENDOR_EVENT_PRIV_STR,
+ GOOGLE_GSCAN_SIGNIFICANT_EVENT,
+ GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT,
+ GOOGLE_GSCAN_BATCH_SCAN_EVENT,
+ GOOGLE_SCAN_FULL_RESULTS_EVENT,
+ GOOGLE_RTT_COMPLETE_EVENT,
+ GOOGLE_SCAN_COMPLETE_EVENT,
+ GOOGLE_GSCAN_GEOFENCE_LOST_EVENT,
+ GOOGLE_RSSI_MONITOR_EVENT,
+ GOOGLE_MKEEP_ALIVE_EVENT,
+ BRCM_VENDOR_EVENT_IDSUP_STATUS
+} wl_vendor_event_t;
+
+enum andr_wifi_attr {
+ ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET,
+ ANDR_WIFI_ATTRIBUTE_FEATURE_SET,
+ ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI,
+ ANDR_WIFI_ATTRIBUTE_NODFS_SET
+};
+
+typedef enum wl_vendor_gscan_attribute {
+ ATTR_START_GSCAN,
+ ATTR_STOP_GSCAN,
+ ATTR_SET_SCAN_BATCH_CFG_ID, /* set batch scan params */
+ ATTR_SET_SCAN_GEOFENCE_CFG_ID, /* set list of bssids to track */
+ ATTR_SET_SCAN_SIGNIFICANT_CFG_ID, /* set list of bssids, rssi threshold etc.. */
+ ATTR_SET_SCAN_CFG_ID, /* set common scan config params here */
+ ATTR_GET_GSCAN_CAPABILITIES_ID,
+ /* Add more sub commands here */
+ ATTR_GSCAN_MAX
+} wl_vendor_gscan_attribute_t;
+
+typedef enum gscan_batch_attribute {
+ ATTR_GSCAN_BATCH_BESTN,
+ ATTR_GSCAN_BATCH_MSCAN,
+ ATTR_GSCAN_BATCH_BUFFER_THRESHOLD
+} gscan_batch_attribute_t;
+
+typedef enum gscan_geofence_attribute {
+ ATTR_GSCAN_NUM_HOTLIST_BSSID,
+ ATTR_GSCAN_HOTLIST_BSSID
+} gscan_geofence_attribute_t;
+
+typedef enum gscan_complete_event {
+ WIFI_SCAN_BUFFER_FULL,
+ WIFI_SCAN_COMPLETE
+} gscan_complete_event_t;
+
+/* Capture the BRCM_VENDOR_SUBCMD_PRIV_STRINGS* here */
+#define BRCM_VENDOR_SCMD_CAPA "cap"
+
+#if defined(WL_VENDOR_EXT_SUPPORT) || defined(CONFIG_BCMDHD_VENDOR_EXT)
+extern int wl_cfgvendor_attach(struct wiphy *wiphy);
+extern int wl_cfgvendor_detach(struct wiphy *wiphy);
+extern int wl_cfgvendor_send_async_event(struct wiphy *wiphy,
+ struct net_device *dev, int event_id, const void *data, int len);
+extern int wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy,
+ struct net_device *dev, void *data, int len, wl_vendor_event_t event);
+#else
+static INLINE int cfgvendor_attach(struct wiphy *wiphy) { return 0; }
+static INLINE int cfgvendor_detach(struct wiphy *wiphy) { return 0; }
+#endif /* defined(WL_VENDOR_EXT_SUPPORT) */
+
+#endif /* _wl_cfgvendor_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/wl_dbg.h b/drivers/net/wireless/bcmdhd_1363/wl_dbg.h
new file mode 100644
index 000000000000..8d0a44045757
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/wl_dbg.h
@@ -0,0 +1,211 @@
+/*
+ * Minimal debug/trace/assert driver definitions for
+ * Broadcom 802.11 Networking 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wl_dbg.h 519338 2014-12-05 21:23:30Z $
+ */
+
+
+#ifndef _wl_dbg_h_
+#define _wl_dbg_h_
+
+/* wl_msg_level is a bit vector with defs in wlioctl.h */
+extern uint32 wl_msg_level;
+extern uint32 wl_msg_level2;
+
+#define WL_TIMESTAMP()
+
+#define WL_PRINT(args) do { WL_TIMESTAMP(); printf args; } while (0)
+
+#if defined(EVENT_LOG_COMPILE) && defined(WLMSG_SRSCAN)
+#define _WL_SRSCAN(fmt, ...) EVENT_LOG(EVENT_LOG_TAG_SRSCAN, fmt, ##__VA_ARGS__)
+#define WL_SRSCAN(args) _WL_SRSCAN args
+#else
+#define WL_SRSCAN(args)
+#endif
+
+#if defined(BCMCONDITIONAL_LOGGING)
+
+/* Ideally this should be some include file that vendors can include to conditionalize logging */
+
+/* DBGONLY() macro to reduce ifdefs in code for statements that are only needed when
+ * BCMDBG is defined.
+ */
+#define DBGONLY(x)
+
+/* To disable a message completely ... until you need it again */
+#define WL_NONE(args)
+#define WL_ERROR(args) do {if (wl_msg_level & WL_ERROR_VAL) WL_PRINT(args);} while (0)
+#define WL_TRACE(args)
+#define WL_PRHDRS_MSG(args)
+#define WL_PRHDRS(i, p, f, t, r, l)
+#define WL_PRPKT(m, b, n)
+#define WL_INFORM(args)
+#define WL_TMP(args)
+#define WL_OID(args)
+#define WL_RATE(args) do {if (wl_msg_level & WL_RATE_VAL) WL_PRINT(args);} while (0)
+#define WL_ASSOC(args) do {if (wl_msg_level & WL_ASSOC_VAL) WL_PRINT(args);} while (0)
+#define WL_PRUSR(m, b, n)
+#define WL_PS(args) do {if (wl_msg_level & WL_PS_VAL) WL_PRINT(args);} while (0)
+
+#define WL_PORT(args)
+#define WL_DUAL(args)
+#define WL_REGULATORY(args) do {if (wl_msg_level & WL_REGULATORY_VAL) WL_PRINT(args);} while (0)
+
+#define WL_MPC(args)
+#define WL_APSTA(args)
+#define WL_APSTA_BCN(args)
+#define WL_APSTA_TX(args)
+#define WL_APSTA_TSF(args)
+#define WL_APSTA_BSSID(args)
+#define WL_BA(args)
+#define WL_MBSS(args)
+#define WL_PROTO(args)
+
+#define WL_CAC(args) do {if (wl_msg_level & WL_CAC_VAL) WL_PRINT(args);} while (0)
+#define WL_AMSDU(args)
+#define WL_AMPDU(args)
+#define WL_FFPLD(args)
+#define WL_MCHAN(args)
+
+#define WL_DFS(args)
+#define WL_WOWL(args)
+#define WL_DPT(args)
+#define WL_ASSOC_OR_DPT(args)
+#define WL_SCAN(args) do {if (wl_msg_level2 & WL_SCAN_VAL) WL_PRINT(args);} while (0)
+#define WL_COEX(args)
+#define WL_RTDC(w, s, i, j)
+#define WL_RTDC2(w, s, i, j)
+#define WL_CHANINT(args)
+#define WL_BTA(args)
+#define WL_P2P(args)
+#define WL_ITFR(args)
+#define WL_TDLS(args)
+#define WL_MCNX(args)
+#define WL_PROT(args)
+#define WL_PSTA(args)
+#define WL_WFDS(m, b, n)
+#define WL_TRF_MGMT(args)
+#define WL_L2FILTER(args)
+#define WL_MQ(args)
+#define WL_TXBF(args)
+#define WL_P2PO(args)
+#define WL_ROAM(args)
+#define WL_WNM(args)
+
+
+#define WL_AMPDU_UPDN(args)
+#define WL_AMPDU_RX(args)
+#define WL_AMPDU_ERR(args)
+#define WL_AMPDU_TX(args)
+#define WL_AMPDU_CTL(args)
+#define WL_AMPDU_HW(args)
+#define WL_AMPDU_HWTXS(args)
+#define WL_AMPDU_HWDBG(args)
+#define WL_AMPDU_STAT(args)
+#define WL_AMPDU_ERR_ON() 0
+#define WL_AMPDU_HW_ON() 0
+#define WL_AMPDU_HWTXS_ON() 0
+
+#define WL_APSTA_UPDN(args)
+#define WL_APSTA_RX(args)
+#define WL_WSEC(args)
+#define WL_WSEC_DUMP(args)
+#define WL_PCIE(args)
+#define WL_TSLOG(w, s, i, j)
+#define WL_FBT(args)
+
+#define WL_ERROR_ON() (wl_msg_level & WL_ERROR_VAL)
+#define WL_TRACE_ON() 0
+#define WL_PRHDRS_ON() 0
+#define WL_PRPKT_ON() 0
+#define WL_INFORM_ON() 0
+#define WL_TMP_ON() 0
+#define WL_OID_ON() 0
+#define WL_RATE_ON() (wl_msg_level & WL_RATE_VAL)
+#define WL_ASSOC_ON() (wl_msg_level & WL_ASSOC_VAL)
+#define WL_PRUSR_ON() 0
+#define WL_PS_ON() (wl_msg_level & WL_PS_VAL)
+#define WL_PORT_ON() 0
+#define WL_WSEC_ON() 0
+#define WL_WSEC_DUMP_ON() 0
+#define WL_MPC_ON() 0
+#define WL_REGULATORY_ON() (wl_msg_level & WL_REGULATORY_VAL)
+#define WL_APSTA_ON() 0
+#define WL_DFS_ON() 0
+#define WL_MBSS_ON() 0
+#define WL_CAC_ON() (wl_msg_level & WL_CAC_VAL)
+#define WL_AMPDU_ON() 0
+#define WL_DPT_ON() 0
+#define WL_WOWL_ON() 0
+#define WL_SCAN_ON() (wl_msg_level2 & WL_SCAN_VAL)
+#define WL_BTA_ON() 0
+#define WL_P2P_ON() 0
+#define WL_ITFR_ON() 0
+#define WL_MCHAN_ON() 0
+#define WL_TDLS_ON() 0
+#define WL_MCNX_ON() 0
+#define WL_PROT_ON() 0
+#define WL_PSTA_ON() 0
+#define WL_TRF_MGMT_ON() 0
+#define WL_LPC_ON() 0
+#define WL_L2FILTER_ON() 0
+#define WL_TXBF_ON() 0
+#define WL_P2PO_ON() 0
+#define WL_TSLOG_ON() 0
+#define WL_WNM_ON() 0
+#define WL_PCIE_ON() 0
+
+#else /* !BCMDBG */
+
+/* DBGONLY() macro to reduce ifdefs in code for statements that are only needed when
+ * BCMDBG is defined.
+ */
+#define DBGONLY(x)
+
+/* To disable a message completely ... until you need it again */
+#define WL_NONE(args)
+
+#define WL_ERROR(args)
+#define WL_TRACE(args)
+#define WL_APSTA_UPDN(args)
+#define WL_APSTA_RX(args)
+#ifdef WLMSG_WSEC
+#define WL_WSEC(args) WL_PRINT(args)
+#define WL_WSEC_DUMP(args) WL_PRINT(args)
+#else
+#define WL_WSEC(args)
+#define WL_WSEC_DUMP(args)
+#endif
+#define WL_PCIE(args) do {if (wl_msg_level2 & WL_PCIE_VAL) WL_PRINT(args);} while (0)
+#define WL_PCIE_ON() (wl_msg_level2 & WL_PCIE_VAL)
+#define WL_PFN(args) do {if (wl_msg_level & WL_PFN_VAL) WL_PRINT(args);} while (0)
+#define WL_PFN_ON() (wl_msg_level & WL_PFN_VAL)
+#endif
+
+extern uint32 wl_msg_level;
+extern uint32 wl_msg_level2;
+#endif /* _wl_dbg_h_ */
diff --git a/drivers/net/wireless/bcmdhd_1363/wl_linux_mon.c b/drivers/net/wireless/bcmdhd_1363/wl_linux_mon.c
new file mode 100644
index 000000000000..755f3d97ec1b
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/wl_linux_mon.c
@@ -0,0 +1,406 @@
+/*
+ * Broadcom Dongle Host Driver (DHD), Linux monitor network 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wl_linux_mon.c 514727 2014-11-12 03:02:48Z $
+ */
+
+#include <osl.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/ieee80211.h>
+#include <linux/rtnetlink.h>
+#include <net/ieee80211_radiotap.h>
+
+#include <wlioctl.h>
+#include <bcmutils.h>
+#include <dhd_dbg.h>
+#include <dngl_stats.h>
+#include <dhd.h>
+
+typedef enum monitor_states
+{
+ MONITOR_STATE_DEINIT = 0x0,
+ MONITOR_STATE_INIT = 0x1,
+ MONITOR_STATE_INTERFACE_ADDED = 0x2,
+ MONITOR_STATE_INTERFACE_DELETED = 0x4
+} monitor_states_t;
+int dhd_add_monitor(char *name, struct net_device **new_ndev);
+extern int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
+int dhd_del_monitor(struct net_device *ndev);
+int dhd_monitor_init(void *dhd_pub);
+int dhd_monitor_uninit(void);
+
+/**
+ * Local declarations and defintions (not exposed)
+ */
+#ifndef DHD_MAX_IFS
+#define DHD_MAX_IFS 16
+#endif
+#define MON_PRINT(format, ...) printk("DHD-MON: %s " format, __func__, ##__VA_ARGS__)
+#define MON_TRACE MON_PRINT
+
+typedef struct monitor_interface {
+ int radiotap_enabled;
+ struct net_device* real_ndev; /* The real interface that the monitor is on */
+ struct net_device* mon_ndev;
+} monitor_interface;
+
+typedef struct dhd_linux_monitor {
+ void *dhd_pub;
+ monitor_states_t monitor_state;
+ monitor_interface mon_if[DHD_MAX_IFS];
+ struct mutex lock; /* lock to protect mon_if */
+} dhd_linux_monitor_t;
+
+static dhd_linux_monitor_t g_monitor;
+
+static struct net_device* lookup_real_netdev(char *name);
+static monitor_interface* ndev_to_monif(struct net_device *ndev);
+static int dhd_mon_if_open(struct net_device *ndev);
+static int dhd_mon_if_stop(struct net_device *ndev);
+static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev);
+static void dhd_mon_if_set_multicast_list(struct net_device *ndev);
+static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr);
+
+static const struct net_device_ops dhd_mon_if_ops = {
+ .ndo_open = dhd_mon_if_open,
+ .ndo_stop = dhd_mon_if_stop,
+ .ndo_start_xmit = dhd_mon_if_subif_start_xmit,
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
+ .ndo_set_rx_mode = dhd_mon_if_set_multicast_list,
+#else
+ .ndo_set_multicast_list = dhd_mon_if_set_multicast_list,
+#endif
+ .ndo_set_mac_address = dhd_mon_if_change_mac,
+};
+
+/**
+ * Local static function defintions
+ */
+
+/* Look up dhd's net device table to find a match (e.g. interface "eth0" is a match for "mon.eth0"
+ * "p2p-eth0-0" is a match for "mon.p2p-eth0-0")
+ */
+static struct net_device* lookup_real_netdev(char *name)
+{
+ struct net_device *ndev_found = NULL;
+
+ int i;
+ int len = 0;
+ int last_name_len = 0;
+ struct net_device *ndev;
+
+ /* We need to find interface "p2p-p2p-0" corresponding to monitor interface "mon-p2p-0",
+ * Once mon iface name reaches IFNAMSIZ, it is reset to p2p0-0 and corresponding mon
+ * iface would be mon-p2p0-0.
+ */
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ ndev = dhd_idx2net(g_monitor.dhd_pub, i);
+
+ /* Skip "p2p" and look for "-p2p0-x" in monitor interface name. If it
+ * it matches, then this netdev is the corresponding real_netdev.
+ */
+ if (ndev && strstr(ndev->name, "p2p-p2p0")) {
+ len = strlen("p2p");
+ } else {
+ /* if p2p- is not present, then the IFNAMSIZ have reached and name
+ * would have got reset. In this casse,look for p2p0-x in mon-p2p0-x
+ */
+ len = 0;
+ }
+ if (ndev && strstr(name, (ndev->name + len))) {
+ if (strlen(ndev->name) > last_name_len) {
+ ndev_found = ndev;
+ last_name_len = strlen(ndev->name);
+ }
+ }
+ }
+
+ return ndev_found;
+}
+
+static monitor_interface* ndev_to_monif(struct net_device *ndev)
+{
+ int i;
+
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ if (g_monitor.mon_if[i].mon_ndev == ndev)
+ return &g_monitor.mon_if[i];
+ }
+
+ return NULL;
+}
+
+static int dhd_mon_if_open(struct net_device *ndev)
+{
+ int ret = 0;
+
+ MON_PRINT("enter\n");
+ return ret;
+}
+
+static int dhd_mon_if_stop(struct net_device *ndev)
+{
+ int ret = 0;
+
+ MON_PRINT("enter\n");
+ return ret;
+}
+
+static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ int ret = 0;
+ int rtap_len;
+ int qos_len = 0;
+ int dot11_hdr_len = 24;
+ int snap_len = 6;
+ unsigned char *pdata;
+ unsigned short frame_ctl;
+ unsigned char src_mac_addr[6];
+ unsigned char dst_mac_addr[6];
+ struct ieee80211_hdr *dot11_hdr;
+ struct ieee80211_radiotap_header *rtap_hdr;
+ monitor_interface* mon_if;
+
+ MON_PRINT("enter\n");
+
+ mon_if = ndev_to_monif(ndev);
+ if (mon_if == NULL || mon_if->real_ndev == NULL) {
+ MON_PRINT(" cannot find matched net dev, skip the packet\n");
+ goto fail;
+ }
+
+ if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
+ goto fail;
+
+ rtap_hdr = (struct ieee80211_radiotap_header *)skb->data;
+ if (unlikely(rtap_hdr->it_version))
+ goto fail;
+
+ rtap_len = ieee80211_get_radiotap_len(skb->data);
+ if (unlikely(skb->len < rtap_len))
+ goto fail;
+
+ MON_PRINT("radiotap len (should be 14): %d\n", rtap_len);
+
+ /* Skip the ratio tap header */
+ skb_pull(skb, rtap_len);
+
+ dot11_hdr = (struct ieee80211_hdr *)skb->data;
+ frame_ctl = le16_to_cpu(dot11_hdr->frame_control);
+ /* Check if the QoS bit is set */
+ if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
+ /* Check if this ia a Wireless Distribution System (WDS) frame
+ * which has 4 MAC addresses
+ */
+ if (dot11_hdr->frame_control & 0x0080)
+ qos_len = 2;
+ if ((dot11_hdr->frame_control & 0x0300) == 0x0300)
+ dot11_hdr_len += 6;
+
+ memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr));
+ memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr));
+
+ /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for
+ * for two MAC addresses
+ */
+ skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2);
+ pdata = (unsigned char*)skb->data;
+ memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr));
+ memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr));
+ PKTSETPRIO(skb, 0);
+
+ MON_PRINT("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
+
+ /* Use the real net device to transmit the packet */
+ ret = dhd_start_xmit(skb, mon_if->real_ndev);
+
+ return ret;
+ }
+fail:
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+static void dhd_mon_if_set_multicast_list(struct net_device *ndev)
+{
+ monitor_interface* mon_if;
+
+ mon_if = ndev_to_monif(ndev);
+ if (mon_if == NULL || mon_if->real_ndev == NULL) {
+ MON_PRINT(" cannot find matched net dev, skip the packet\n");
+ } else {
+ MON_PRINT("enter, if name: %s, matched if name %s\n",
+ ndev->name, mon_if->real_ndev->name);
+ }
+}
+
+static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr)
+{
+ int ret = 0;
+ monitor_interface* mon_if;
+
+ mon_if = ndev_to_monif(ndev);
+ if (mon_if == NULL || mon_if->real_ndev == NULL) {
+ MON_PRINT(" cannot find matched net dev, skip the packet\n");
+ } else {
+ MON_PRINT("enter, if name: %s, matched if name %s\n",
+ ndev->name, mon_if->real_ndev->name);
+ }
+ return ret;
+}
+
+/**
+ * Global function definitions (declared in dhd_linux_mon.h)
+ */
+
+int dhd_add_monitor(char *name, struct net_device **new_ndev)
+{
+ int i;
+ int idx = -1;
+ int ret = 0;
+ struct net_device* ndev = NULL;
+ dhd_linux_monitor_t **dhd_mon;
+
+ mutex_lock(&g_monitor.lock);
+
+ MON_TRACE("enter, if name: %s\n", name);
+ if (!name || !new_ndev) {
+ MON_PRINT("invalid parameters\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * Find a vacancy
+ */
+ for (i = 0; i < DHD_MAX_IFS; i++)
+ if (g_monitor.mon_if[i].mon_ndev == NULL) {
+ idx = i;
+ break;
+ }
+ if (idx == -1) {
+ MON_PRINT("exceeds maximum interfaces\n");
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ndev = alloc_etherdev(sizeof(dhd_linux_monitor_t*));
+ if (!ndev) {
+ MON_PRINT("failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ndev->type = ARPHRD_IEEE80211_RADIOTAP;
+ strncpy(ndev->name, name, IFNAMSIZ);
+ ndev->name[IFNAMSIZ - 1] = 0;
+ ndev->netdev_ops = &dhd_mon_if_ops;
+
+ ret = register_netdevice(ndev);
+ if (ret) {
+ MON_PRINT(" register_netdevice failed (%d)\n", ret);
+ goto out;
+ }
+
+ *new_ndev = ndev;
+ g_monitor.mon_if[idx].radiotap_enabled = TRUE;
+ g_monitor.mon_if[idx].mon_ndev = ndev;
+ g_monitor.mon_if[idx].real_ndev = lookup_real_netdev(name);
+ dhd_mon = (dhd_linux_monitor_t **)netdev_priv(ndev);
+ *dhd_mon = &g_monitor;
+ g_monitor.monitor_state = MONITOR_STATE_INTERFACE_ADDED;
+ MON_PRINT("net device returned: 0x%p\n", ndev);
+ MON_PRINT("found a matched net device, name %s\n", g_monitor.mon_if[idx].real_ndev->name);
+
+out:
+ if (ret && ndev)
+ free_netdev(ndev);
+
+ mutex_unlock(&g_monitor.lock);
+ return ret;
+
+}
+
+int dhd_del_monitor(struct net_device *ndev)
+{
+ int i;
+ if (!ndev)
+ return -EINVAL;
+ mutex_lock(&g_monitor.lock);
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ if (g_monitor.mon_if[i].mon_ndev == ndev ||
+ g_monitor.mon_if[i].real_ndev == ndev) {
+
+ g_monitor.mon_if[i].real_ndev = NULL;
+ unregister_netdevice(g_monitor.mon_if[i].mon_ndev);
+ free_netdev(g_monitor.mon_if[i].mon_ndev);
+ g_monitor.mon_if[i].mon_ndev = NULL;
+ g_monitor.monitor_state = MONITOR_STATE_INTERFACE_DELETED;
+ break;
+ }
+ }
+
+ if (g_monitor.monitor_state != MONITOR_STATE_INTERFACE_DELETED)
+ MON_PRINT("IF not found in monitor array, is this a monitor IF? 0x%p\n", ndev);
+ mutex_unlock(&g_monitor.lock);
+
+ return 0;
+}
+
+int dhd_monitor_init(void *dhd_pub)
+{
+ if (g_monitor.monitor_state == MONITOR_STATE_DEINIT) {
+ g_monitor.dhd_pub = dhd_pub;
+ mutex_init(&g_monitor.lock);
+ g_monitor.monitor_state = MONITOR_STATE_INIT;
+ }
+ return 0;
+}
+
+int dhd_monitor_uninit(void)
+{
+ int i;
+ struct net_device *ndev;
+ mutex_lock(&g_monitor.lock);
+ if (g_monitor.monitor_state != MONITOR_STATE_DEINIT) {
+ for (i = 0; i < DHD_MAX_IFS; i++) {
+ ndev = g_monitor.mon_if[i].mon_ndev;
+ if (ndev) {
+ unregister_netdevice(ndev);
+ free_netdev(ndev);
+ g_monitor.mon_if[i].real_ndev = NULL;
+ g_monitor.mon_if[i].mon_ndev = NULL;
+ }
+ }
+ g_monitor.monitor_state = MONITOR_STATE_DEINIT;
+ }
+ mutex_unlock(&g_monitor.lock);
+ return 0;
+}
diff --git a/drivers/net/wireless/bcmdhd_1363/wl_roam.c b/drivers/net/wireless/bcmdhd_1363/wl_roam.c
new file mode 100644
index 000000000000..f098462e796a
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/wl_roam.c
@@ -0,0 +1,28 @@
+/*
+ * Linux roam 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wl_roam.c 613173 2016-01-18 03:01:57Z $
+ */
diff --git a/drivers/net/wireless/bcmdhd_1363/wldev_common.c b/drivers/net/wireless/bcmdhd_1363/wldev_common.c
new file mode 100644
index 000000000000..d1464f30ff6a
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/wldev_common.c
@@ -0,0 +1,456 @@
+/*
+ * Common function shared by Linux WEXT, cfg80211 and p2p 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wldev_common.c 585478 2015-09-10 13:33:58Z $
+ */
+
+#include <osl.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+
+#include <wldev_common.h>
+#include <bcmutils.h>
+
+#define htod32(i) (i)
+#define htod16(i) (i)
+#define dtoh32(i) (i)
+#define dtoh16(i) (i)
+#define htodchanspec(i) (i)
+#define dtohchanspec(i) (i)
+
+#define WLDEV_ERROR(args) \
+ do { \
+ printk(KERN_ERR "WLDEV-ERROR) "); \
+ printk args; \
+ } while (0)
+
+#define WLDEV_INFO(args) \
+ do { \
+ printk(KERN_INFO "WLDEV-INFO) "); \
+ printk args; \
+ } while (0)
+
+extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd);
+
+s32 wldev_ioctl(
+ struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set)
+{
+ s32 ret = 0;
+ struct wl_ioctl ioc;
+
+
+ memset(&ioc, 0, sizeof(ioc));
+ ioc.cmd = cmd;
+ ioc.buf = arg;
+ ioc.len = len;
+ ioc.set = set;
+
+ ret = dhd_ioctl_entry_local(dev, &ioc, cmd);
+
+ return ret;
+}
+
+/* Format a iovar buffer, not bsscfg indexed. The bsscfg index will be
+ * taken care of in dhd_ioctl_entry. Internal use only, not exposed to
+ * wl_iw, wl_cfg80211 and wl_cfgp2p
+ */
+static s32 wldev_mkiovar(
+ const s8 *iovar_name, s8 *param, s32 paramlen,
+ s8 *iovar_buf, u32 buflen)
+{
+ s32 iolen = 0;
+
+ iolen = bcm_mkiovar(iovar_name, param, paramlen, iovar_buf, buflen);
+ return iolen;
+}
+
+s32 wldev_iovar_getbuf(
+ struct net_device *dev, s8 *iovar_name,
+ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
+{
+ s32 ret = 0;
+ if (buf_sync) {
+ mutex_lock(buf_sync);
+ }
+ wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
+ ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
+ if (buf_sync)
+ mutex_unlock(buf_sync);
+ return ret;
+}
+
+
+s32 wldev_iovar_setbuf(
+ struct net_device *dev, s8 *iovar_name,
+ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync)
+{
+ s32 ret = 0;
+ s32 iovar_len;
+ if (buf_sync) {
+ mutex_lock(buf_sync);
+ }
+ iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
+ if (iovar_len > 0)
+ ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE);
+ else
+ ret = BCME_BUFTOOSHORT;
+
+ if (buf_sync)
+ mutex_unlock(buf_sync);
+ return ret;
+}
+
+s32 wldev_iovar_setint(
+ struct net_device *dev, s8 *iovar, s32 val)
+{
+ s8 iovar_buf[WLC_IOCTL_SMLEN];
+
+ val = htod32(val);
+ memset(iovar_buf, 0, sizeof(iovar_buf));
+ return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf,
+ sizeof(iovar_buf), NULL);
+}
+
+
+s32 wldev_iovar_getint(
+ struct net_device *dev, s8 *iovar, s32 *pval)
+{
+ s8 iovar_buf[WLC_IOCTL_SMLEN];
+ s32 err;
+
+ memset(iovar_buf, 0, sizeof(iovar_buf));
+ err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf,
+ sizeof(iovar_buf), NULL);
+ if (err == 0)
+ {
+ memcpy(pval, iovar_buf, sizeof(*pval));
+ *pval = dtoh32(*pval);
+ }
+ return err;
+}
+
+/** Format a bsscfg indexed iovar buffer. The bsscfg index will be
+ * taken care of in dhd_ioctl_entry. Internal use only, not exposed to
+ * wl_iw, wl_cfg80211 and wl_cfgp2p
+ */
+s32 wldev_mkiovar_bsscfg(
+ const s8 *iovar_name, s8 *param, s32 paramlen,
+ s8 *iovar_buf, s32 buflen, s32 bssidx)
+{
+ const s8 *prefix = "bsscfg:";
+ s8 *p;
+ u32 prefixlen;
+ u32 namelen;
+ u32 iolen;
+
+ if (bssidx == 0) {
+ return wldev_mkiovar(iovar_name, param, paramlen,
+ iovar_buf, buflen);
+ }
+
+ prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */
+ namelen = (u32) strlen(iovar_name) + 1; /* lengh of iovar name + null */
+ iolen = prefixlen + namelen + sizeof(u32) + paramlen;
+
+ if (buflen < 0 || iolen > (u32)buflen)
+ {
+ WLDEV_ERROR(("%s: buffer is too short\n", __FUNCTION__));
+ return BCME_BUFTOOSHORT;
+ }
+
+ p = (s8 *)iovar_buf;
+
+ /* copy prefix, no null */
+ memcpy(p, prefix, prefixlen);
+ p += prefixlen;
+
+ /* copy iovar name including null */
+ memcpy(p, iovar_name, namelen);
+ p += namelen;
+
+ /* bss config index as first param */
+ bssidx = htod32(bssidx);
+ memcpy(p, &bssidx, sizeof(u32));
+ p += sizeof(u32);
+
+ /* parameter buffer follows */
+ if (paramlen)
+ memcpy(p, param, paramlen);
+
+ return iolen;
+
+}
+
+s32 wldev_iovar_getbuf_bsscfg(
+ struct net_device *dev, s8 *iovar_name,
+ void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
+{
+ s32 ret = 0;
+ if (buf_sync) {
+ mutex_lock(buf_sync);
+ }
+
+ wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
+ ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
+ if (buf_sync) {
+ mutex_unlock(buf_sync);
+ }
+ return ret;
+
+}
+
+s32 wldev_iovar_setbuf_bsscfg(
+ struct net_device *dev, s8 *iovar_name,
+ void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync)
+{
+ s32 ret = 0;
+ s32 iovar_len;
+ if (buf_sync) {
+ mutex_lock(buf_sync);
+ }
+ iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
+ if (iovar_len > 0)
+ ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE);
+ else {
+ ret = BCME_BUFTOOSHORT;
+ }
+
+ if (buf_sync) {
+ mutex_unlock(buf_sync);
+ }
+ return ret;
+}
+
+s32 wldev_iovar_setint_bsscfg(
+ struct net_device *dev, s8 *iovar, s32 val, s32 bssidx)
+{
+ s8 iovar_buf[WLC_IOCTL_SMLEN];
+
+ val = htod32(val);
+ memset(iovar_buf, 0, sizeof(iovar_buf));
+ return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf,
+ sizeof(iovar_buf), bssidx, NULL);
+}
+
+
+s32 wldev_iovar_getint_bsscfg(
+ struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx)
+{
+ s8 iovar_buf[WLC_IOCTL_SMLEN];
+ s32 err;
+
+ memset(iovar_buf, 0, sizeof(iovar_buf));
+ err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf,
+ sizeof(iovar_buf), bssidx, NULL);
+ if (err == 0)
+ {
+ memcpy(pval, iovar_buf, sizeof(*pval));
+ *pval = dtoh32(*pval);
+ }
+ return err;
+}
+
+int wldev_get_link_speed(
+ struct net_device *dev, int *plink_speed)
+{
+ int error;
+
+ if (!plink_speed)
+ return -ENOMEM;
+ error = wldev_ioctl(dev, WLC_GET_RATE, plink_speed, sizeof(int), 0);
+ if (unlikely(error))
+ return error;
+
+ /* Convert internal 500Kbps to Kbps */
+ *plink_speed *= 500;
+ return error;
+}
+
+int wldev_get_rssi(
+ struct net_device *dev, scb_val_t *scb_val)
+{
+ int error;
+
+ if (!scb_val)
+ return -ENOMEM;
+
+ error = wldev_ioctl(dev, WLC_GET_RSSI, scb_val, sizeof(scb_val_t), 0);
+ if (unlikely(error))
+ return error;
+
+ return error;
+}
+
+int wldev_get_ssid(
+ struct net_device *dev, wlc_ssid_t *pssid)
+{
+ int error;
+
+ if (!pssid)
+ return -ENOMEM;
+ error = wldev_ioctl(dev, WLC_GET_SSID, pssid, sizeof(wlc_ssid_t), 0);
+ if (unlikely(error))
+ return error;
+ pssid->SSID_len = dtoh32(pssid->SSID_len);
+ return error;
+}
+
+int wldev_get_band(
+ struct net_device *dev, uint *pband)
+{
+ int error;
+
+ error = wldev_ioctl(dev, WLC_GET_BAND, pband, sizeof(uint), 0);
+ return error;
+}
+
+int wldev_set_band(
+ struct net_device *dev, uint band)
+{
+ int error = -1;
+
+ if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) {
+ error = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), true);
+ if (!error)
+ dhd_bus_band_set(dev, band);
+ }
+ return error;
+}
+int wldev_get_datarate(struct net_device *dev, int *datarate)
+{
+ int error = 0;
+
+ error = wldev_ioctl(dev, WLC_GET_RATE, datarate, sizeof(int), false);
+ if (error) {
+ return -1;
+ } else {
+ *datarate = dtoh32(*datarate);
+ }
+
+ return error;
+}
+
+extern chanspec_t
+wl_chspec_driver_to_host(chanspec_t chanspec);
+#define WL_EXTRA_BUF_MAX 2048
+int wldev_get_mode(
+ struct net_device *dev, uint8 *cap)
+{
+ int error = 0;
+ int chanspec = 0;
+ uint16 band = 0;
+ uint16 bandwidth = 0;
+ wl_bss_info_t *bss = NULL;
+ char* buf = kmalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
+ if (!buf)
+ return -1;
+ *(u32*) buf = htod32(WL_EXTRA_BUF_MAX);
+ error = wldev_ioctl(dev, WLC_GET_BSS_INFO, (void*)buf, WL_EXTRA_BUF_MAX, false);
+ if (error) {
+ WLDEV_ERROR(("%s:failed:%d\n", __FUNCTION__, error));
+ return -1;
+ }
+ bss = (struct wl_bss_info *)(buf + 4);
+ chanspec = wl_chspec_driver_to_host(bss->chanspec);
+
+ band = chanspec & WL_CHANSPEC_BAND_MASK;
+ bandwidth = chanspec & WL_CHANSPEC_BW_MASK;
+
+ if (band == WL_CHANSPEC_BAND_2G) {
+ if (bss->n_cap)
+ strcpy(cap, "n");
+ else
+ strcpy(cap, "bg");
+ } else if (band == WL_CHANSPEC_BAND_5G) {
+ if (bandwidth == WL_CHANSPEC_BW_80)
+ strcpy(cap, "ac");
+ else if ((bandwidth == WL_CHANSPEC_BW_40) || (bandwidth == WL_CHANSPEC_BW_20)) {
+ if ((bss->nbss_cap & 0xf00) && (bss->n_cap))
+ strcpy(cap, "n|ac");
+ else if (bss->n_cap)
+ strcpy(cap, "n");
+ else if (bss->vht_cap)
+ strcpy(cap, "ac");
+ else
+ strcpy(cap, "a");
+ } else {
+ WLDEV_ERROR(("%s:Mode get failed\n", __FUNCTION__));
+ return -1;
+ }
+
+ }
+ return error;
+}
+int wldev_set_country(
+ struct net_device *dev, char *country_code, bool notify, bool user_enforced, int revinfo)
+{
+ int error = -1;
+ wl_country_t cspec = {{0}, 0, {0}};
+ scb_val_t scbval;
+ char smbuf[WLC_IOCTL_SMLEN];
+
+ if (!country_code)
+ return error;
+
+ bzero(&scbval, sizeof(scb_val_t));
+ error = wldev_iovar_getbuf(dev, "country", NULL, 0, &cspec, sizeof(cspec), NULL);
+ if (error < 0) {
+ WLDEV_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error));
+ return error;
+ }
+
+ if ((error < 0) ||
+ dhd_force_country_change(dev) ||
+ (strncmp(country_code, cspec.ccode, WLC_CNTRY_BUF_SZ) != 0)) {
+
+ if (user_enforced) {
+ bzero(&scbval, sizeof(scb_val_t));
+ error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true);
+ if (error < 0) {
+ WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n",
+ __FUNCTION__, error));
+ return error;
+ }
+ }
+
+ cspec.rev = revinfo;
+ memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ);
+ memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
+ dhd_get_customized_country_code(dev, (char *)&cspec.country_abbrev, &cspec);
+ error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec),
+ smbuf, sizeof(smbuf), NULL);
+ if (error < 0) {
+ WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n",
+ __FUNCTION__, country_code, cspec.ccode, cspec.rev));
+ return error;
+ }
+ dhd_bus_country_set(dev, &cspec, notify);
+ WLDEV_INFO(("%s: set country for %s as %s rev %d\n",
+ __FUNCTION__, country_code, cspec.ccode, cspec.rev));
+ }
+ return 0;
+}
diff --git a/drivers/net/wireless/bcmdhd_1363/wldev_common.h b/drivers/net/wireless/bcmdhd_1363/wldev_common.h
new file mode 100644
index 000000000000..f080bc44fd67
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd_1363/wldev_common.h
@@ -0,0 +1,124 @@
+/*
+ * Common function shared by Linux WEXT, cfg80211 and p2p 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.
+ *
+ *
+ * <<Broadcom-WL-IPTag/Open:>>
+ *
+ * $Id: wldev_common.h 619484 2016-02-17 02:14:06Z $
+ */
+#ifndef __WLDEV_COMMON_H__
+#define __WLDEV_COMMON_H__
+
+#include <wlioctl.h>
+
+/* wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or
+ * netdev_ops->ndo_do_ioctl in new kernels)
+ * @dev: the net_device handle
+ */
+s32 wldev_ioctl(
+ struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set);
+
+/** Retrieve named IOVARs, this function calls wl_dev_ioctl with
+ * WLC_GET_VAR IOCTL code
+ */
+s32 wldev_iovar_getbuf(
+ struct net_device *dev, s8 *iovar_name,
+ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync);
+
+/** Set named IOVARs, this function calls wl_dev_ioctl with
+ * WLC_SET_VAR IOCTL code
+ */
+s32 wldev_iovar_setbuf(
+ struct net_device *dev, s8 *iovar_name,
+ void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync);
+
+s32 wldev_iovar_setint(
+ struct net_device *dev, s8 *iovar, s32 val);
+
+s32 wldev_iovar_getint(
+ struct net_device *dev, s8 *iovar, s32 *pval);
+
+/** The following function can be implemented if there is a need for bsscfg
+ * indexed IOVARs
+ */
+
+s32 wldev_mkiovar_bsscfg(
+ const s8 *iovar_name, s8 *param, s32 paramlen,
+ s8 *iovar_buf, s32 buflen, s32 bssidx);
+
+/** Retrieve named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with
+ * WLC_GET_VAR IOCTL code
+ */
+s32 wldev_iovar_getbuf_bsscfg(
+ struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen,
+ void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync);
+
+/** Set named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with
+ * WLC_SET_VAR IOCTL code
+ */
+s32 wldev_iovar_setbuf_bsscfg(
+ struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen,
+ void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync);
+
+s32 wldev_iovar_getint_bsscfg(
+ struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx);
+
+s32 wldev_iovar_setint_bsscfg(
+ struct net_device *dev, s8 *iovar, s32 val, s32 bssidx);
+
+extern int dhd_net_set_fw_path(struct net_device *dev, char *fw);
+extern int dhd_net_bus_suspend(struct net_device *dev);
+extern int dhd_net_bus_resume(struct net_device *dev, uint8 stage);
+extern int dhd_net_wifi_platform_set_power(struct net_device *dev, bool on,
+ unsigned long delay_msec);
+extern void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code,
+ wl_country_t *cspec);
+extern void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify);
+extern bool dhd_force_country_change(struct net_device *dev);
+extern void dhd_bus_band_set(struct net_device *dev, uint band);
+extern int wldev_set_country(struct net_device *dev, char *country_code, bool notify,
+ bool user_enforced, int revinfo);
+extern int net_os_wake_lock(struct net_device *dev);
+extern int net_os_wake_unlock(struct net_device *dev);
+extern int net_os_wake_lock_timeout(struct net_device *dev);
+extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val);
+extern int net_os_set_dtim_skip(struct net_device *dev, int val);
+extern int net_os_set_suspend_disable(struct net_device *dev, int val);
+extern int net_os_set_suspend(struct net_device *dev, int val, int force);
+extern int net_os_set_max_dtim_enable(struct net_device *dev, int val);
+extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid,
+ int max, int *bytes_left);
+
+/* Get the link speed from dongle, speed is in kpbs */
+int wldev_get_link_speed(struct net_device *dev, int *plink_speed);
+
+int wldev_get_rssi(struct net_device *dev, scb_val_t *prssi);
+
+int wldev_get_ssid(struct net_device *dev, wlc_ssid_t *pssid);
+
+int wldev_get_band(struct net_device *dev, uint *pband);
+int wldev_get_mode(struct net_device *dev, uint8 *pband);
+int wldev_get_datarate(struct net_device *dev, int *datarate);
+int wldev_set_band(struct net_device *dev, uint band);
+
+#endif /* __WLDEV_COMMON_H__ */
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index fadf151ce830..fc13a10eb901 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -324,9 +324,9 @@ static int nvme_init_iod(struct request *rq, unsigned size,
iod->nents = 0;
iod->length = size;
- if (!(rq->cmd_flags & REQ_DONTPREP)) {
+ if (!(rq->rq_flags & RQF_DONTPREP)) {
rq->retries = 0;
- rq->cmd_flags |= REQ_DONTPREP;
+ rq->rq_flags |= RQF_DONTPREP;
}
return 0;
}
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index ba140eaee5c8..f165be7f65cf 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -15,7 +15,19 @@ if NVMEM
config NVMEM_IMX_OCOTP
tristate "i.MX6 On-Chip OTP Controller support"
- depends on SOC_IMX6 || COMPILE_TEST
+ depends on SOC_IMX6 || ARCH_MXC_ARM64 || COMPILE_TEST
+ depends on HAS_IOMEM
+ help
+ This is a driver for the On-Chip OTP Controller (OCOTP) available on
+ i.MX6 SoCs, providing access to 4 Kbits of one-time programmable
+ eFuses.
+
+ This driver can also be built as a module. If so, the module
+ will be called nvmem-imx-ocotp.
+
+config NVMEM_IMX_SCU_OCOTP
+ tristate "i.MX8QM On-Chip OTP Controller support"
+ depends on ARCH_MXC_ARM64|| COMPILE_TEST
depends on HAS_IOMEM
help
This is a driver for the On-Chip OTP Controller (OCOTP) available on
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 8f942a0cdaec..dc6494bf7e05 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -8,6 +8,8 @@ nvmem_core-y := core.o
# Devices
obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o
nvmem-imx-ocotp-y := imx-ocotp.o
+obj-$(CONFIG_NVMEM_IMX_SCU_OCOTP) += nvmem-imx-scu-ocotp.o
+nvmem-imx-scu-ocotp-y := imx-scu-ocotp.o
obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o
nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o
obj-$(CONFIG_NVMEM_MXS_OCOTP) += nvmem-mxs-ocotp.o
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index 8e7b120696fa..d5c02174149d 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -3,6 +3,8 @@
*
* Copyright (c) 2015 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de>
*
+ * Copyright 2017 NXP
+ *
* Based on the barebox ocotp driver,
* Copyright (c) 2010 Baruch Siach <baruch@tkos.co.il>,
* Orex Computed Radiography
@@ -37,26 +39,40 @@ static int imx_ocotp_read(void *context, unsigned int offset,
{
struct ocotp_priv *priv = context;
unsigned int count;
- u32 *buf = val;
+ u8 *buf, *p;
int i, ret;
- u32 index;
+ u32 index, num_bytes;
index = offset >> 2;
- count = bytes >> 2;
+ num_bytes = round_up((offset % 4) + bytes, 4);
+ count = num_bytes >> 2;
if (count > (priv->nregs - index))
count = priv->nregs - index;
+ p = kzalloc(num_bytes, GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+ buf = p;
+
ret = clk_prepare_enable(priv->clk);
if (ret < 0) {
dev_err(priv->dev, "failed to prepare/enable ocotp clk\n");
+ kfree(p);
return ret;
}
- for (i = index; i < (index + count); i++)
- *buf++ = readl(priv->base + 0x400 + i * 0x10);
+ for (i = index; i < (index + count); i++) {
+ *(u32 *)buf = readl(priv->base + 0x400 + i * 0x10);
+ buf += 4;
+ }
clk_disable_unprepare(priv->clk);
+ index = offset % 4;
+ memcpy(val, &p[index], bytes);
+
+ kfree(p);
+
return 0;
}
@@ -64,7 +80,7 @@ static struct nvmem_config imx_ocotp_nvmem_config = {
.name = "imx-ocotp",
.read_only = true,
.word_size = 4,
- .stride = 4,
+ .stride = 1,
.owner = THIS_MODULE,
.reg_read = imx_ocotp_read,
};
@@ -73,6 +89,7 @@ static const struct of_device_id imx_ocotp_dt_ids[] = {
{ .compatible = "fsl,imx6q-ocotp", (void *)128 },
{ .compatible = "fsl,imx6sl-ocotp", (void *)64 },
{ .compatible = "fsl,imx6sx-ocotp", (void *)128 },
+ { .compatible = "fsl,imx8mq-ocotp", (void *)256 },
{ },
};
MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids);
@@ -100,6 +117,7 @@ static int imx_ocotp_probe(struct platform_device *pdev)
of_id = of_match_device(imx_ocotp_dt_ids, dev);
priv->nregs = (unsigned long)of_id->data;
+ priv->dev = dev;
imx_ocotp_nvmem_config.size = 4 * priv->nregs;
imx_ocotp_nvmem_config.dev = dev;
imx_ocotp_nvmem_config.priv = priv;
diff --git a/drivers/nvmem/imx-scu-ocotp.c b/drivers/nvmem/imx-scu-ocotp.c
new file mode 100644
index 000000000000..ee2d0bdc81fb
--- /dev/null
+++ b/drivers/nvmem/imx-scu-ocotp.c
@@ -0,0 +1,180 @@
+/*
+ * i.MX6 OCOTP fusebox driver
+ *
+ * Copyright (c) 2015 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de>
+ *
+ * Based on the barebox ocotp driver,
+ * Copyright (c) 2010 Baruch Siach <baruch@tkos.co.il>,
+ * Orex Computed Radiography
+ *
+ * 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.
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <soc/imx8/sc/sci.h>
+
+enum ocotp_devtype {
+ IMX8QM,
+ IMX8QXP,
+};
+
+struct ocotp_devtype_data {
+ int devtype;
+ int nregs;
+};
+
+struct ocotp_priv {
+ struct device *dev;
+ struct ocotp_devtype_data *data;
+ sc_ipc_t nvmem_ipc;
+};
+
+static struct ocotp_devtype_data imx8qm_data = {
+ .devtype = IMX8QM,
+ .nregs = 800,
+};
+
+static struct ocotp_devtype_data imx8qxp_data = {
+ .devtype = IMX8QXP,
+ .nregs = 800,
+};
+
+static int imx_scu_ocotp_read(void *context, unsigned int offset,
+ void *val, size_t bytes)
+{
+ struct ocotp_priv *priv = context;
+ sc_err_t sciErr = SC_ERR_NONE;
+ unsigned int count;
+ u32 index;
+ u32 num_bytes;
+ int i;
+ u8 *buf, *p;
+
+ index = offset >> 2;
+ num_bytes = round_up((offset % 4) + bytes, 4);
+ count = num_bytes >> 2;
+
+ if (count > (priv->data->nregs - index))
+ count = priv->data->nregs - index;
+
+ p = kzalloc(num_bytes, GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ buf = p;
+
+ for (i = index; i < (index + count); i++) {
+ if (priv->data->devtype == IMX8QXP) {
+ if ((i > 271) && (i < 544)) {
+ *(u32 *)buf = 0;
+ buf += 4;
+ continue;
+ }
+ }
+
+ sciErr = sc_misc_otp_fuse_read(priv->nvmem_ipc, i, (u32 *)buf);
+ if (sciErr != SC_ERR_NONE) {
+ kfree(p);
+ return -EIO;
+ }
+ buf += 4;
+ }
+
+ index = offset % 4;
+ memcpy(val, &p[index], bytes);
+
+ kfree(p);
+
+ return 0;
+}
+
+static struct nvmem_config imx_scu_ocotp_nvmem_config = {
+ .name = "imx-ocotp",
+ .read_only = true,
+ .word_size = 4,
+ .stride = 1,
+ .owner = THIS_MODULE,
+ .reg_read = imx_scu_ocotp_read,
+};
+
+static const struct of_device_id imx_scu_ocotp_dt_ids[] = {
+ { .compatible = "fsl,imx8qm-ocotp", (void *)&imx8qm_data },
+ { .compatible = "fsl,imx8qxp-ocotp", (void *)&imx8qxp_data },
+ { },
+};
+MODULE_DEVICE_TABLE(of, imx_scu_ocotp_dt_ids);
+
+static int imx_scu_ocotp_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id;
+ struct device *dev = &pdev->dev;
+ struct ocotp_priv *priv;
+ struct nvmem_device *nvmem;
+ uint32_t mu_id;
+ sc_err_t sciErr = SC_ERR_NONE;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_info("pinctrl: Cannot obtain MU ID\n");
+ return -EIO;
+ }
+
+ sciErr = sc_ipc_open(&priv->nvmem_ipc, mu_id);
+
+ if (sciErr != SC_ERR_NONE) {
+ pr_info("pinctrl: Cannot open MU channel to SCU\n");
+ return -EIO;
+ };
+
+ of_id = of_match_device(imx_scu_ocotp_dt_ids, dev);
+ priv->data = (struct ocotp_devtype_data *)of_id->data;
+ priv->dev = dev;
+ imx_scu_ocotp_nvmem_config.size = 4 * priv->data->nregs;
+ imx_scu_ocotp_nvmem_config.dev = dev;
+ imx_scu_ocotp_nvmem_config.priv = priv;
+ nvmem = nvmem_register(&imx_scu_ocotp_nvmem_config);
+ if (IS_ERR(nvmem))
+ return PTR_ERR(nvmem);
+
+ platform_set_drvdata(pdev, nvmem);
+
+ return 0;
+}
+
+static int imx_scu_ocotp_remove(struct platform_device *pdev)
+{
+ struct nvmem_device *nvmem = platform_get_drvdata(pdev);
+
+ return nvmem_unregister(nvmem);
+}
+
+static struct platform_driver imx_scu_ocotp_driver = {
+ .probe = imx_scu_ocotp_probe,
+ .remove = imx_scu_ocotp_remove,
+ .driver = {
+ .name = "imx_scu_ocotp",
+ .of_match_table = imx_scu_ocotp_dt_ids,
+ },
+};
+module_platform_driver(imx_scu_ocotp_driver);
+
+MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
+MODULE_DESCRIPTION("i.MX8QM OCOTP fuse box driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 466b285cef3e..36f6bb39de5b 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -2049,6 +2049,36 @@ static void of_alias_add(struct alias_prop *ap, struct device_node *np,
ap->alias, ap->stem, ap->id, of_node_full_name(np));
}
+/*
+ * of_alias_max_index() - get the maximum index for a given alias stem
+ * @stem: The alias stem for which the maximum index is searched for
+ *
+ * Given an alias stem (the alias without the number) this function
+ * returns the maximum number for which an alias exists.
+ *
+ * Return: The maximum existing alias index or -ENODEV if no alias
+ * exists for this stem.
+ */
+int of_alias_max_index(const char *stem)
+{
+ struct alias_prop *app;
+ int max = -ENODEV;
+
+ mutex_lock(&of_mutex);
+
+ list_for_each_entry(app, &aliases_lookup, link) {
+ if (strcmp(app->stem, stem))
+ continue;
+ if (app->id > max)
+ max = app->id;
+ }
+
+ mutex_unlock(&of_mutex);
+
+ return max;
+}
+EXPORT_SYMBOL_GPL(of_alias_max_index);
+
/**
* of_alias_scan - Scan all properties of the 'aliases' node
*
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 366d8c3c7989..8459c5eb3114 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -31,11 +31,15 @@ static int reserved_mem_count;
#if defined(CONFIG_HAVE_MEMBLOCK)
#include <linux/memblock.h>
-int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
- phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
- phys_addr_t *res_base)
+int __init __weak early_init_dt_alloc_reserved_memory_arch(unsigned long node,
+ phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end,
+ bool nomap, phys_addr_t *res_base)
{
phys_addr_t base;
+ phys_addr_t highmem_start;
+
+ highmem_start = __pa(high_memory - 1) + 1;
+
/*
* We use __memblock_alloc_base() because memblock_alloc_base()
* panic()s on allocation failure.
@@ -53,15 +57,34 @@ int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
return -ENOMEM;
}
+ /*
+ * Sanity check for the cma reserved region:If the reserved region
+ * crosses the low/high memory boundary, try to fix it up and then
+ * fall back to allocate the cma region from the low mememory space.
+ */
+
+ if (IS_ENABLED(CONFIG_CMA)
+ && of_flat_dt_is_compatible(node, "shared-dma-pool")
+ && of_get_flat_dt_prop(node, "reusable", NULL) && !nomap) {
+ if (base < highmem_start && (base + size) > highmem_start) {
+ memblock_free(base, size);
+ base = memblock_alloc_range(size, align, start,
+ highmem_start,
+ MEMBLOCK_NONE);
+ if (!base)
+ return -ENOMEM;
+ }
+ }
+
*res_base = base;
if (nomap)
return memblock_remove(base, size);
return 0;
}
#else
-int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
- phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
- phys_addr_t *res_base)
+int __init __weak early_init_dt_alloc_reserved_memory_arch(unsigned long node,
+ phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end,
+ bool nomap, phys_addr_t *res_base)
{
pr_err("Reserved memory not supported, ignoring region 0x%llx%s\n",
size, nomap ? " (nomap)" : "");
@@ -155,8 +178,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
end = start + dt_mem_next_cell(dt_root_size_cells,
&prop);
- ret = early_init_dt_alloc_reserved_memory_arch(size,
- align, start, end, nomap, &base);
+ ret = early_init_dt_alloc_reserved_memory_arch(node,
+ size, align, start, end, nomap, &base);
if (ret == 0) {
pr_debug("allocated memory for '%s' node: base %pa, size %ld MiB\n",
uname, &base,
@@ -167,8 +190,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
}
} else {
- ret = early_init_dt_alloc_reserved_memory_arch(size, align,
- 0, 0, nomap, &base);
+ ret = early_init_dt_alloc_reserved_memory_arch(node,
+ size, align, 0, 0, nomap, &base);
if (ret == 0)
pr_debug("allocated memory for '%s' node: base %pa, size %ld MiB\n",
uname, &base, (unsigned long)size / SZ_1M);
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index d7e7c0a827c3..e7e7e5632285 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -62,11 +62,33 @@ config PCI_EXYNOS
config PCI_IMX6
bool "Freescale i.MX6 PCIe controller"
- depends on SOC_IMX6Q
+ depends on SOC_IMX6Q || SOC_IMX6SX || SOC_IMX7D || ARCH_MXC_ARM64
depends on PCI_MSI_IRQ_DOMAIN
select PCIEPORTBUS
select PCIE_DW
+config PCI_IMX6_COMPLIANCE_TEST
+ bool "Enable pcie compliance tests on imx6"
+ depends on PCI_IMX6
+ default n
+ help
+ Say Y here if you want do the compliance tests on imx6 pcie rc found
+ on FSL iMX SoCs. The pcie clks wouldn't be turned off, and the link
+ speed wouldn't be limited to gen1 when the Y is set here.
+
+config EP_MODE_IN_EP_RC_SYS
+ bool "PCI Express EP mode in the IMX6 RC/EP interconnection system"
+ depends on PCI_IMX6
+
+config RC_MODE_IN_EP_RC_SYS
+ bool "PCI Express RC mode in the IMX6 RC/EP interconnection system"
+ depends on PCI_IMX6 && EP_MODE_IN_EP_RC_SYS!=y
+
+config PCI_IMX_EP_DRV
+ bool "i.MX6 PCI Express EP skeleton driver"
+ depends on RC_MODE_IN_EP_RC_SYS
+ default y
+
config PCI_TEGRA
bool "NVIDIA Tegra PCIe controller"
depends on ARCH_TEGRA && !ARM64
@@ -99,6 +121,7 @@ config PCI_HOST_GENERIC
depends on (ARM || ARM64) && OF
select PCI_HOST_COMMON
select IRQ_DOMAIN
+ select PCI_DOMAINS
help
Say Y here if you want to support a simple generic PCI host
controller, such as the one emulated by kvmtool.
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 084cb4983645..8d1fbb2d2b50 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -1,9 +1,11 @@
+
obj-$(CONFIG_PCIE_DW) += pcie-designware.o
obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.o
obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
obj-$(CONFIG_PCI_HYPERV) += pci-hyperv.o
+obj-$(CONFIG_PCI_IMX_EP_DRV) += pci-imx6-ep-driver.o
obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o
obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c
index 5c90d7be2184..2967466a8c3b 100644
--- a/drivers/pci/host/pci-host-common.c
+++ b/drivers/pci/host/pci-host-common.c
@@ -163,5 +163,19 @@ int pci_host_common_probe(struct platform_device *pdev,
}
pci_bus_add_devices(bus);
+
+ platform_set_drvdata(pdev, bus);
+ return 0;
+}
+
+int pci_host_common_remove(struct platform_device *pdev)
+{
+ struct pci_bus *bus = platform_get_drvdata(pdev);
+
+ pci_lock_rescan_remove();
+ pci_stop_root_bus(bus);
+ pci_remove_root_bus(bus);
+ pci_unlock_rescan_remove();
+
return 0;
}
diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c
index c05ea9d72f69..326d6726347d 100644
--- a/drivers/pci/host/pci-host-generic.c
+++ b/drivers/pci/host/pci-host-generic.c
@@ -62,5 +62,6 @@ static struct platform_driver gen_pci_driver = {
.of_match_table = gen_pci_of_match,
},
.probe = gen_pci_probe,
+ .remove = pci_host_common_remove,
};
builtin_platform_driver(gen_pci_driver);
diff --git a/drivers/pci/host/pci-imx6-ep-driver.c b/drivers/pci/host/pci-imx6-ep-driver.c
new file mode 100644
index 000000000000..4ea0782a4c60
--- /dev/null
+++ b/drivers/pci/host/pci-imx6-ep-driver.c
@@ -0,0 +1,209 @@
+/*
+ * PCIe endpoint skeleton driver for IMX6 SOCs
+ *
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci-aspm.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#define DRV_DESCRIPTION "i.MX PCIE endpoint device driver"
+#define DRV_VERSION "version 0.1"
+#define DRV_NAME "imx_pcie_ep"
+
+struct imx_pcie_ep_priv {
+ struct pci_dev *pci_dev;
+ void __iomem *hw_base;
+};
+
+/**
+ * imx_pcie_ep_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @id: entry in id_tbl
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int imx_pcie_ep_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int ret = 0, index = 0, found = 0;
+ unsigned int hard_wired = 0, msi_addr = 0, cpu_base;
+ struct resource cfg_res;
+ const char *name = NULL;
+ struct device_node *np = NULL;
+ struct device *dev = &pdev->dev;
+ struct imx_pcie_ep_priv *priv;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(dev, "can't alloc imx pcie priv\n");
+ return -ENOMEM;
+ }
+
+ priv->pci_dev = pdev;
+
+ if (pci_enable_device(pdev)) {
+ ret = -ENODEV;
+ goto out;
+ }
+ pci_set_master(pdev);
+
+ pci_set_drvdata(pdev, priv);
+
+ priv->hw_base = pci_iomap(pdev, 0, 0);
+ if (!priv->hw_base) {
+ ret = -ENODEV;
+ goto err_pci_disable;
+ }
+
+ pr_info("pci_resource_len = 0x%08llx\n",
+ (unsigned long long) pci_resource_len(pdev, 0));
+ pr_info("pci_resource_base = %p\n", priv->hw_base);
+
+ ret = pci_enable_msi(priv->pci_dev);
+ if (ret < 0) {
+ dev_err(dev, "can't enable msi\n");
+ goto err_pci_unmap_mmio;
+ }
+
+ /* Use the first none-hard-wired port as ep */
+ while ((np = of_find_node_by_type(np, "pci"))) {
+ if (of_property_read_u32(np, "hard-wired", &hard_wired)) {
+ hard_wired = 0;
+ break;
+ }
+ }
+ if (of_property_read_u32(np, "cpu-base-addr", &cpu_base))
+ cpu_base = 0;
+
+ while (!of_property_read_string_index(np, "reg-names", index, &name)) {
+ if (strcmp("config", name)) {
+ index++;
+ continue;
+ }
+
+ /* We have a match and @index is where it's at */
+ found = 1;
+ break;
+ }
+
+ if (!found) {
+ dev_err(dev, "can't find config reg space.\n");
+ ret = -EINVAL;
+ goto err_pci_disable_msi;
+ }
+
+ ret = of_address_to_resource(np, index, &cfg_res);
+ if (ret) {
+ dev_err(dev, "can't get cfg_res.\n");
+ ret = -EINVAL;
+ goto err_pci_disable_msi;
+ } else {
+ msi_addr = cfg_res.start + resource_size(&cfg_res);
+ }
+
+ pr_info("pci_msi_addr = 0x%08x, cpu_base 0x%08x\n", msi_addr, cpu_base);
+ pci_bus_write_config_dword(pdev->bus, 0, 0x54, msi_addr);
+ if (cpu_base) {
+ msi_addr = msi_addr & 0xFFFFFFF;
+ msi_addr |= (cpu_base & 0xF0000000);
+ }
+ pci_bus_write_config_dword(pdev->bus->parent, 0, 0x820, msi_addr);
+
+ /* configure rc's msi cap */
+ pci_bus_read_config_dword(pdev->bus->parent, 0, 0x50, &ret);
+ ret |= (PCI_MSI_FLAGS_ENABLE << 16);
+ pci_bus_write_config_dword(pdev->bus->parent, 0, 0x50, ret);
+ pci_bus_write_config_dword(pdev->bus->parent, 0, 0x828, 0x1);
+ pci_bus_write_config_dword(pdev->bus->parent, 0, 0x82C, 0xFFFFFFFE);
+
+ return 0;
+
+err_pci_disable_msi:
+ pci_disable_msi(pdev);
+err_pci_unmap_mmio:
+ pci_iounmap(pdev, priv->hw_base);
+err_pci_disable:
+ pci_disable_device(pdev);
+out:
+ kfree(priv);
+ return ret;
+}
+
+static void imx_pcie_ep_remove(struct pci_dev *pdev)
+{
+ struct imx_pcie_ep_priv *priv = pci_get_drvdata(pdev);
+
+ if (!priv)
+ return;
+ pr_info("***imx pcie ep driver unload***\n");
+}
+
+static struct pci_device_id imx_pcie_ep_ids[] = {
+ {
+ .class = PCI_CLASS_MEMORY_RAM << 8,
+ .class_mask = ~0,
+ .vendor = 0xbeaf,
+ .device = 0xdead,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ { } /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, imx_pcie_ep_ids);
+
+static struct pci_driver imx_pcie_ep_driver = {
+ .name = DRV_NAME,
+ .id_table = imx_pcie_ep_ids,
+ .probe = imx_pcie_ep_probe,
+ .remove = imx_pcie_ep_remove,
+};
+
+static int __init imx_pcie_ep_init(void)
+{
+ int ret;
+ pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
+
+ ret = pci_register_driver(&imx_pcie_ep_driver);
+ if (ret)
+ pr_err("Unable to initialize PCI module\n");
+
+ return ret;
+}
+
+static void __exit imx_pcie_ep_exit(void)
+{
+ pci_unregister_driver(&imx_pcie_ep_driver);
+}
+
+module_exit(imx_pcie_ep_exit);
+module_init(imx_pcie_ep_init);
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("imx_pcie_ep");
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
index c8cefb078218..c3cc315473ce 100644
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -11,49 +11,90 @@
* published by the Free Software Foundation.
*/
+#include <dt-bindings/soc/imx8_hsio.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/mfd/syscon/imx7-iomuxc-gpr.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
+#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/resource.h>
#include <linux/signal.h>
#include <linux/types.h>
#include <linux/interrupt.h>
+#include <linux/busfreq-imx.h>
+#include <linux/regulator/consumer.h>
#include "pcie-designware.h"
-#define to_imx6_pcie(x) container_of(x, struct imx6_pcie, pp)
+#define to_imx_pcie(x) container_of(x, struct imx_pcie, pp)
-enum imx6_pcie_variants {
+enum imx_pcie_variants {
IMX6Q,
IMX6SX,
IMX6QP,
+ IMX7D,
+ IMX8QM,
+ IMX8QXP,
+ IMX8MQ,
+ IMX8MM,
};
-struct imx6_pcie {
+/*
+ * The default value of the reserved ddr memory
+ * used to verify EP/RC memory space access operations.
+ * The layout of the 1G ddr on SD boards
+ * [imx6qdl-sd-ard boards]0x1000_0000 ~ 0x4FFF_FFFF
+ * [imx6sx,imx7d platforms]0x8000_0000 ~ 0xBFFF_FFFF
+ *
+ */
+static u32 ddr_test_region = 0, test_region_size = SZ_2M;
+static bool dma_w_end, dma_r_end, dma_en;
+
+struct imx_pcie {
struct pcie_port pp; /* pp.dbi_base is DT 0th resource */
+ u32 ext_osc;
+ u32 ctrl_id;
+ u32 cpu_base;
+ u32 hard_wired;
+ int clkreq_gpio;
+ int dis_gpio;
+ int power_on_gpio;
int reset_gpio;
bool gpio_active_high;
struct clk *pcie_bus;
- struct clk *pcie_phy;
struct clk *pcie_inbound_axi;
+ struct clk *pcie_phy;
+ struct clk *pcie_per;
struct clk *pcie;
+ struct clk *pcie_ext_src;
struct regmap *iomuxc_gpr;
- enum imx6_pcie_variants variant;
+ enum imx_pcie_variants variant;
+ u32 hsio_cfg;
u32 tx_deemph_gen1;
u32 tx_deemph_gen2_3p5db;
u32 tx_deemph_gen2_6db;
u32 tx_swing_full;
u32 tx_swing_low;
+ u32 dma_unroll_offset;
int link_gen;
+ struct regmap *reg_src;
+ struct regmap *reg_gpc;
+ void __iomem *phy_base;
+ struct regulator *pcie_phy_regulator;
+ struct regulator *pcie_bus_regulator;
+ struct regulator *epdev_on;
};
/* PCIe Root Complex registers (memory-mapped) */
@@ -61,7 +102,6 @@ struct imx6_pcie {
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK 0xf
-
#define PCIE_RC_LCSR 0x80
/* PCIe Port Logic registers (memory-mapped) */
@@ -69,6 +109,11 @@ struct imx6_pcie {
#define PCIE_PL_PFLR (PL_OFFSET + 0x08)
#define PCIE_PL_PFLR_LINK_STATE_MASK (0x3f << 16)
#define PCIE_PL_PFLR_FORCE_LINK (1 << 15)
+#define PCIE_PORT_LINK_CONTROL 0x710
+#define PORT_LINK_MODE_MASK (0x3f << 16)
+#define PORT_LINK_MODE_1_LANES (0x1 << 16)
+#define PORT_LINK_MODE_2_LANES (0x3 << 16)
+
#define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28)
#define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c)
#define PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING (1 << 29)
@@ -86,6 +131,43 @@ struct imx6_pcie {
#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)
+#define PORT_LOGIC_LINK_WIDTH_MASK (0x1f << 8)
+#define PORT_LOGIC_LINK_WIDTH_1_LANES (0x1 << 8)
+#define PORT_LOGIC_LINK_WIDTH_2_LANES (0x2 << 8)
+
+#define PCIE_MISC_CTRL (PL_OFFSET + 0x1BC)
+#define PCIE_MISC_DBI_RO_WR_EN BIT(0)
+
+#define PCIE_ATU_VIEWPORT 0x900
+
+/* DMA registers */
+#define MAX_PCIE_DMA_CHANNELS 8
+#define DMA_UNROLL_CDM_OFFSET (0x7 << 19)
+#define DMA_REG_OFFSET 0x970
+#define DMA_CTRL_VIEWPORT_OFF (DMA_REG_OFFSET + 0x8)
+#define DMA_WRITE_ENGINE_EN_OFF (DMA_REG_OFFSET + 0xC)
+#define DMA_WRITE_ENGINE_EN BIT(0)
+#define DMA_WRITE_DOORBELL (DMA_REG_OFFSET + 0x10)
+#define DMA_READ_ENGINE_EN_OFF (DMA_REG_OFFSET + 0x2C)
+#define DMA_READ_ENGINE_EN BIT(0)
+#define DMA_READ_DOORBELL (DMA_REG_OFFSET + 0x30)
+#define DMA_WRITE_INT_STS (DMA_REG_OFFSET + 0x4C)
+#define DMA_WRITE_INT_MASK (DMA_REG_OFFSET + 0x54)
+#define DMA_WRITE_INT_CLR (DMA_REG_OFFSET + 0x58)
+#define DMA_READ_INT_STS (DMA_REG_OFFSET + 0xA0)
+#define DMA_READ_INT_MASK (DMA_REG_OFFSET + 0xA8)
+#define DMA_READ_INT_CLR (DMA_REG_OFFSET + 0xAC)
+#define DMA_DONE_INT_STS 0xFF
+#define DMA_ABORT_INT_STS (0xFF << 16)
+#define DMA_VIEWPOT_SEL_OFF (DMA_REG_OFFSET + 0xFC)
+#define DMA_CHANNEL_CTRL_1 (DMA_REG_OFFSET + 0x100)
+#define DMA_CHANNEL_CTRL_1_LIE BIT(3)
+#define DMA_CHANNEL_CTRL_2 (DMA_REG_OFFSET + 0x104)
+#define DMA_TRANSFER_SIZE (DMA_REG_OFFSET + 0x108)
+#define DMA_SAR_LOW (DMA_REG_OFFSET + 0x10C)
+#define DMA_SAR_HIGH (DMA_REG_OFFSET + 0x110)
+#define DMA_DAR_LOW (DMA_REG_OFFSET + 0x114)
+#define DMA_DAR_HIGH (DMA_REG_OFFSET + 0x118)
/* PHY registers (not memory-mapped) */
#define PCIE_PHY_RX_ASIC_OUT 0x100D
@@ -95,9 +177,132 @@ struct imx6_pcie {
#define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5)
#define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3)
-static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, int exp_val)
+#define SSP_CR_SUP_DIG_MPLL_OVRD_IN_LO 0x0011
+/* FIELD: RES_ACK_IN_OVRD [15:15]
+ * FIELD: RES_ACK_IN [14:14]
+ * FIELD: RES_REQ_IN_OVRD [13:13]
+ * FIELD: RES_REQ_IN [12:12]
+ * FIELD: RTUNE_REQ_OVRD [11:11]
+ * FIELD: RTUNE_REQ [10:10]
+ * FIELD: MPLL_MULTIPLIER_OVRD [9:9]
+ * FIELD: MPLL_MULTIPLIER [8:2]
+ * FIELD: MPLL_EN_OVRD [1:1]
+ * FIELD: MPLL_EN [0:0]
+ */
+
+#define SSP_CR_SUP_DIG_ATEOVRD 0x0010
+/* FIELD: ateovrd_en [2:2]
+ * FIELD: ref_usb2_en [1:1]
+ * FIELD: ref_clkdiv2 [0:0]
+ */
+
+/* iMX7 PCIe PHY registers */
+#define PCIE_PHY_CMN_REG4 0x14
+#define PCIE_PHY_CMN_REG4_DCC_FB_EN (0x29)
+
+#define PCIE_PHY_CMN_REG24 0x90
+#define PCIE_PHY_CMN_REG24_RX_EQ BIT(6)
+#define PCIE_PHY_CMN_REG24_RX_EQ_SEL BIT(3)
+
+#define PCIE_PHY_CMN_REG26 0x98
+#define PCIE_PHY_CMN_REG26_ATT_MODE 0xBC
+
+#define PCIE_PHY_CMN_REG62 0x188
+#define PCIE_PHY_CMN_REG62_PLL_CLK_OUT 0x08
+#define PCIE_PHY_CMN_REG64 0x190
+#define PCIE_PHY_CMN_REG64_AUX_RX_TX_TERM 0x8C
+#define PCIE_PHY_CMN_REG75 0x1D4
+#define PCIE_PHY_CMN_REG75_PLL_DONE 0x3
+#define PCIE_PHY_TRSV_REG5 0x414
+#define PCIE_PHY_TRSV_REG5_GEN1_DEEMP 0x2D
+#define PCIE_PHY_TRSV_REG6 0x418
+#define PCIE_PHY_TRSV_REG6_GEN2_DEEMP 0xF
+
+/* iMX8 HSIO registers */
+#define IMX8QM_LPCG_PHYX2_OFFSET 0x00000
+#define IMX8QM_LPCG_PHYX1_OFFSET 0x10000
+#define IMX8QM_CSR_PHYX2_OFFSET 0x90000
+#define IMX8QM_CSR_PHYX1_OFFSET 0xA0000
+#define IMX8QM_CSR_PHYX_STTS0_OFFSET 0x4
+#define IMX8QM_CSR_PCIEA_OFFSET 0xB0000
+#define IMX8QM_CSR_PCIEB_OFFSET 0xC0000
+#define IMX8QM_CSR_PCIE_CTRL1_OFFSET 0x4
+#define IMX8QM_CSR_PCIE_CTRL2_OFFSET 0x8
+#define IMX8QM_CSR_PCIE_STTS0_OFFSET 0xC
+#define IMX8QM_CSR_MISC_OFFSET 0xE0000
+
+#define IMX8QM_LPCG_PHY_PCG0 BIT(1)
+#define IMX8QM_LPCG_PHY_PCG1 BIT(5)
+
+#define IMX8QM_CTRL_LTSSM_ENABLE BIT(4)
+#define IMX8QM_CTRL_READY_ENTR_L23 BIT(5)
+#define IMX8QM_CTRL_PM_XMT_TURNOFF BIT(9)
+#define IMX8QM_CTRL_BUTTON_RST_N BIT(21)
+#define IMX8QM_CTRL_PERST_N BIT(22)
+#define IMX8QM_CTRL_POWER_UP_RST_N BIT(23)
+
+#define IMX8QM_CTRL_STTS0_PM_LINKST_IN_L2 BIT(13)
+#define IMX8QM_CTRL_STTS0_PM_REQ_CORE_RST BIT(19)
+#define IMX8QM_STTS0_LANE0_TX_PLL_LOCK BIT(4)
+#define IMX8QM_STTS0_LANE1_TX_PLL_LOCK BIT(12)
+
+#define IMX8QM_PCIE_TYPE_MASK (0xF << 24)
+
+#define IMX8QM_PHYX2_CTRL0_APB_MASK 0x3
+#define IMX8QM_PHY_APB_RSTN_0 BIT(0)
+#define IMX8QM_PHY_APB_RSTN_1 BIT(1)
+
+#define IMX8QM_MISC_IOB_RXENA BIT(0)
+#define IMX8QM_MISC_IOB_TXENA BIT(1)
+#define IMX8QM_CSR_MISC_IOB_A_0_TXOE BIT(2)
+#define IMX8QM_CSR_MISC_IOB_A_0_M1M0_MASK (0x3 << 3)
+#define IMX8QM_CSR_MISC_IOB_A_0_M1M0_2 BIT(4)
+#define IMX8QM_MISC_PHYX1_EPCS_SEL BIT(12)
+#define IMX8QM_MISC_PCIE_AB_SELECT BIT(13)
+
+#define IMX8MQ_PCIE_LINK_CAP_REG_OFFSET 0x7C
+#define IMX8MQ_PCIE_LINK_CAP_L1EL_64US (0x6 << 15)
+#define IMX8MQ_SRC_PCIEPHY_RCR_OFFSET 0x2C
+#define IMX8MQ_SRC_PCIE2PHY_RCR_OFFSET 0x48
+#define IMX8MQ_PCIEPHY_DOMAIN_EN (BIT(31) | (0xF << 24))
+#define IMX8MQ_PCIEPHY_PWR_ON_RST BIT(0)
+#define IMX8MQ_PCIEPHY_G_RST BIT(1)
+#define IMX8MQ_PCIEPHY_BTN BIT(2)
+#define IMX8MQ_PCIEPHY_PERST BIT(3)
+#define IMX8MQ_PCIE_CTRL_APPS_CLK_REQ BIT(4)
+#define IMX8MQ_PCIE_CTRL_APPS_EN BIT(6)
+#define IMX8MQ_PCIE_CTRL_APPS_TURNOFF BIT(11)
+
+#define IMX8MQ_GPC_PGC_CPU_0_1_MAPPING_OFFSET 0xEC
+#define IMX8MQ_GPC_PU_PGC_SW_PUP_REQ_OFFSET 0xF8
+#define IMX8MQ_GPC_PU_PGC_SW_PDN_REQ_OFFSET 0x104
+#define IMX8MQ_GPC_PGC_PCIE_CTRL_OFFSET 0xC40
+#define IMX8MQ_GPC_PGC_PCIE2_CTRL_OFFSET 0xF00
+#define IMX8MQ_GPC_PGC_PCIE_A53_DOMAIN BIT(3)
+#define IMX8MQ_GPC_PU_PGC_PCIE_SW_PWR_REQ BIT(1)
+#define IMX8MQ_GPC_PGC_PCIE2_BIT_OFFSET 12
+#define IMX8MQ_GPC_PCG_PCIE_CTRL_PCR BIT(0)
+#define IMX8MQ_GPR_PCIE_REF_USE_PAD BIT(9)
+#define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN BIT(10)
+#define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE BIT(11)
+#define IMX8MQ_ANA_PLLOUT_REG 0x74
+#define IMX8MQ_ANA_PLLOUT_CKE BIT(4)
+#define IMX8MQ_ANA_PLLOUT_SEL_MASK 0xF
+#define IMX8MQ_ANA_PLLOUT_SEL_SYSPLL1 0xB
+#define IMX8MQ_ANA_PLLOUT_DIV_REG 0x7C
+#define IMX8MQ_ANA_PLLOUT_SYSPLL1_DIV 0x7
+
+#define IMX8MM_GPR_PCIE_REF_CLK_SEL (0x3 << 24)
+#define IMX8MM_GPR_PCIE_REF_CLK_PLL (0x3 << 24)
+#define IMX8MM_GPR_PCIE_REF_CLK_EXT (0x2 << 24)
+#define IMX8MM_GPR_PCIE_AUX_EN BIT(19)
+#define IMX8MM_GPR_PCIE_CMN_RST BIT(18)
+#define IMX8MM_GPR_PCIE_POWER_OFF BIT(17)
+#define IMX8MM_GPR_PCIE_SSC_EN BIT(16)
+
+static int pcie_phy_poll_ack(struct imx_pcie *imx_pcie, int exp_val)
{
- struct pcie_port *pp = &imx6_pcie->pp;
+ struct pcie_port *pp = &imx_pcie->pp;
u32 val;
u32 max_iterations = 10;
u32 wait_counter = 0;
@@ -116,9 +321,9 @@ static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, int exp_val)
return -ETIMEDOUT;
}
-static int pcie_phy_wait_ack(struct imx6_pcie *imx6_pcie, int addr)
+static int pcie_phy_wait_ack(struct imx_pcie *imx_pcie, int addr)
{
- struct pcie_port *pp = &imx6_pcie->pp;
+ struct pcie_port *pp = &imx_pcie->pp;
u32 val;
int ret;
@@ -128,24 +333,24 @@ static int pcie_phy_wait_ack(struct imx6_pcie *imx6_pcie, int addr)
val |= (0x1 << PCIE_PHY_CTRL_CAP_ADR_LOC);
dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, val);
- ret = pcie_phy_poll_ack(imx6_pcie, 1);
+ ret = pcie_phy_poll_ack(imx_pcie, 1);
if (ret)
return ret;
val = addr << PCIE_PHY_CTRL_DATA_LOC;
dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, val);
- return pcie_phy_poll_ack(imx6_pcie, 0);
+ return pcie_phy_poll_ack(imx_pcie, 0);
}
/* Read from the 16-bit PCIe PHY control registers (not memory-mapped) */
-static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data)
+static int pcie_phy_read(struct imx_pcie *imx_pcie, int addr, int *data)
{
- struct pcie_port *pp = &imx6_pcie->pp;
+ struct pcie_port *pp = &imx_pcie->pp;
u32 val, phy_ctl;
int ret;
- ret = pcie_phy_wait_ack(imx6_pcie, addr);
+ ret = pcie_phy_wait_ack(imx_pcie, addr);
if (ret)
return ret;
@@ -153,7 +358,7 @@ static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data)
phy_ctl = 0x1 << PCIE_PHY_CTRL_RD_LOC;
dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, phy_ctl);
- ret = pcie_phy_poll_ack(imx6_pcie, 1);
+ ret = pcie_phy_poll_ack(imx_pcie, 1);
if (ret)
return ret;
@@ -163,18 +368,18 @@ static int pcie_phy_read(struct imx6_pcie *imx6_pcie, int addr, int *data)
/* deassert Read signal */
dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, 0x00);
- return pcie_phy_poll_ack(imx6_pcie, 0);
+ return pcie_phy_poll_ack(imx_pcie, 0);
}
-static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data)
+static int pcie_phy_write(struct imx_pcie *imx_pcie, int addr, int data)
{
- struct pcie_port *pp = &imx6_pcie->pp;
+ struct pcie_port *pp = &imx_pcie->pp;
u32 var;
int ret;
/* write addr */
/* cap addr */
- ret = pcie_phy_wait_ack(imx6_pcie, addr);
+ ret = pcie_phy_wait_ack(imx_pcie, addr);
if (ret)
return ret;
@@ -185,7 +390,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data)
var |= (0x1 << PCIE_PHY_CTRL_CAP_DAT_LOC);
dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, var);
- ret = pcie_phy_poll_ack(imx6_pcie, 1);
+ ret = pcie_phy_poll_ack(imx_pcie, 1);
if (ret)
return ret;
@@ -194,7 +399,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data)
dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, var);
/* wait for ack de-assertion */
- ret = pcie_phy_poll_ack(imx6_pcie, 0);
+ ret = pcie_phy_poll_ack(imx_pcie, 0);
if (ret)
return ret;
@@ -203,7 +408,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data)
dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, var);
/* wait for ack */
- ret = pcie_phy_poll_ack(imx6_pcie, 1);
+ ret = pcie_phy_poll_ack(imx_pcie, 1);
if (ret)
return ret;
@@ -212,7 +417,7 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data)
dw_pcie_writel_rc(pp, PCIE_PHY_CTRL, var);
/* wait for ack de-assertion */
- ret = pcie_phy_poll_ack(imx6_pcie, 0);
+ ret = pcie_phy_poll_ack(imx_pcie, 0);
if (ret)
return ret;
@@ -221,47 +426,53 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, int data)
return 0;
}
-static void imx6_pcie_reset_phy(struct imx6_pcie *imx6_pcie)
+static void imx_pcie_reset_phy(struct imx_pcie *imx_pcie)
{
u32 tmp;
- pcie_phy_read(imx6_pcie, PHY_RX_OVRD_IN_LO, &tmp);
- tmp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN |
- PHY_RX_OVRD_IN_LO_RX_PLL_EN);
- pcie_phy_write(imx6_pcie, PHY_RX_OVRD_IN_LO, tmp);
+ if (imx_pcie->variant == IMX6Q || imx_pcie->variant == IMX6SX
+ || imx_pcie->variant == IMX6QP) {
+ pcie_phy_read(imx_pcie, PHY_RX_OVRD_IN_LO, &tmp);
+ tmp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN |
+ PHY_RX_OVRD_IN_LO_RX_PLL_EN);
+ pcie_phy_write(imx_pcie, PHY_RX_OVRD_IN_LO, tmp);
- usleep_range(2000, 3000);
+ usleep_range(2000, 3000);
- pcie_phy_read(imx6_pcie, PHY_RX_OVRD_IN_LO, &tmp);
- tmp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN |
- PHY_RX_OVRD_IN_LO_RX_PLL_EN);
- pcie_phy_write(imx6_pcie, PHY_RX_OVRD_IN_LO, tmp);
+ pcie_phy_read(imx_pcie, PHY_RX_OVRD_IN_LO, &tmp);
+ tmp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN |
+ PHY_RX_OVRD_IN_LO_RX_PLL_EN);
+ pcie_phy_write(imx_pcie, PHY_RX_OVRD_IN_LO, tmp);
+ }
}
+#ifdef CONFIG_ARM
/* Added for PCI abort handling */
-static int imx6q_pcie_abort_handler(unsigned long addr,
+static int imx_pcie_abort_handler(unsigned long addr,
unsigned int fsr, struct pt_regs *regs)
{
return 0;
}
+#endif
-static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
+static void imx_pcie_assert_core_reset(struct imx_pcie *imx_pcie)
{
- struct pcie_port *pp = &imx6_pcie->pp;
+ struct pcie_port *pp = &imx_pcie->pp;
u32 val, gpr1, gpr12;
+ int i;
- switch (imx6_pcie->variant) {
+ switch (imx_pcie->variant) {
case IMX6SX:
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6SX_GPR12_PCIE_TEST_POWERDOWN,
IMX6SX_GPR12_PCIE_TEST_POWERDOWN);
/* Force PCIe PHY reset */
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5,
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR5,
IMX6SX_GPR5_PCIE_BTNRST_RESET,
IMX6SX_GPR5_PCIE_BTNRST_RESET);
break;
case IMX6QP:
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_SW_RST,
IMX6Q_GPR1_PCIE_SW_RST);
break;
@@ -279,8 +490,8 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
* have a strong indication that the bootloader activated
* the link.
*/
- regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, &gpr1);
- regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, &gpr12);
+ regmap_read(imx_pcie->iomuxc_gpr, IOMUXC_GPR1, &gpr1);
+ regmap_read(imx_pcie->iomuxc_gpr, IOMUXC_GPR12, &gpr12);
if ((gpr1 & IMX6Q_GPR1_PCIE_REF_CLK_EN) &&
(gpr12 & IMX6Q_GPR12_PCIE_CTL_2)) {
@@ -289,39 +500,93 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
val |= PCIE_PL_PFLR_FORCE_LINK;
dw_pcie_writel_rc(pp, PCIE_PL_PFLR, val);
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6Q_GPR12_PCIE_CTL_2, 0 << 10);
}
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_TEST_PD, 1 << 18);
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16);
break;
+ case IMX7D:
+ /* G_RST */
+ regmap_update_bits(imx_pcie->reg_src, 0x2c, BIT(1), BIT(1));
+ /* BTNRST */
+ regmap_update_bits(imx_pcie->reg_src, 0x2c, BIT(2), BIT(2));
+ break;
+ case IMX8QXP:
+ val = IMX8QM_CSR_PCIEB_OFFSET;
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+ IMX8QM_CTRL_BUTTON_RST_N,
+ IMX8QM_CTRL_BUTTON_RST_N);
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+ IMX8QM_CTRL_PERST_N,
+ IMX8QM_CTRL_PERST_N);
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+ IMX8QM_CTRL_POWER_UP_RST_N,
+ IMX8QM_CTRL_POWER_UP_RST_N);
+ break;
+ case IMX8QM:
+ for (i = 0; i <= imx_pcie->ctrl_id; i++) {
+ val = IMX8QM_CSR_PCIEA_OFFSET + i * SZ_64K;
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+ IMX8QM_CTRL_BUTTON_RST_N,
+ IMX8QM_CTRL_BUTTON_RST_N);
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+ IMX8QM_CTRL_PERST_N,
+ IMX8QM_CTRL_PERST_N);
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+ IMX8QM_CTRL_POWER_UP_RST_N,
+ IMX8QM_CTRL_POWER_UP_RST_N);
+ }
+ break;
+ case IMX8MQ:
+ case IMX8MM:
+ if (imx_pcie->ctrl_id == 0)
+ val = IMX8MQ_SRC_PCIEPHY_RCR_OFFSET;
+ else
+ val = IMX8MQ_SRC_PCIE2PHY_RCR_OFFSET;
+ /* Do RSTs */
+ regmap_update_bits(imx_pcie->reg_src, val,
+ IMX8MQ_PCIEPHY_BTN | IMX8MQ_PCIEPHY_DOMAIN_EN,
+ IMX8MQ_PCIEPHY_BTN | IMX8MQ_PCIEPHY_DOMAIN_EN);
+ regmap_update_bits(imx_pcie->reg_src, val,
+ IMX8MQ_PCIEPHY_G_RST |
+ IMX8MQ_PCIEPHY_DOMAIN_EN,
+ IMX8MQ_PCIEPHY_G_RST |
+ IMX8MQ_PCIEPHY_DOMAIN_EN);
}
}
-static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
+static int imx_pcie_enable_ref_clk(struct imx_pcie *imx_pcie)
{
- struct pcie_port *pp = &imx6_pcie->pp;
- struct device *dev = pp->dev;
+ u32 val;
int ret = 0;
+ struct pcie_port *pp = &imx_pcie->pp;
+ struct device *dev = pp->dev;
- switch (imx6_pcie->variant) {
+ switch (imx_pcie->variant) {
case IMX6SX:
- ret = clk_prepare_enable(imx6_pcie->pcie_inbound_axi);
+ ret = clk_prepare_enable(imx_pcie->pcie_inbound_axi);
if (ret) {
dev_err(dev, "unable to enable pcie_axi clock\n");
break;
}
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6SX_GPR12_PCIE_TEST_POWERDOWN, 0);
break;
case IMX6QP: /* FALLTHROUGH */
case IMX6Q:
/* power up core phy and enable ref clock */
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18);
/*
* the async reset input need ref clock to sync internally,
@@ -330,132 +595,809 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
* add one ~10us delay here.
*/
udelay(10);
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
break;
+ case IMX7D:
+ break;
+ case IMX8MQ:
+ case IMX8MM:
+ /*
+ * Set the over ride low and enabled
+ * make sure that REF_CLK is turned on.
+ */
+ if (imx_pcie->ctrl_id == 0)
+ val = IOMUXC_GPR14;
+ else
+ val = IOMUXC_GPR16;
+
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE,
+ 0);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN,
+ IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN);
+
+ break;
+ case IMX8QXP:
+ case IMX8QM:
+ ret = clk_prepare_enable(imx_pcie->pcie_inbound_axi);
+ if (ret) {
+ dev_err(dev, "unable to enable pcie_axi clock\n");
+ break;
+ }
+ ret = clk_prepare_enable(imx_pcie->pcie_per);
+ if (ret) {
+ dev_err(dev, "unable to enable pcie_per clock\n");
+ clk_disable_unprepare(imx_pcie->pcie_inbound_axi);
+ break;
+ }
+
+ break;
}
return ret;
}
-static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
+static int pci_imx_phy_pll_locked(struct imx_pcie *imx_pcie)
{
- struct pcie_port *pp = &imx6_pcie->pp;
+ u32 val, tmp, orig;
+ int i = 0;
+ struct pcie_port *pp = &imx_pcie->pp;
struct device *dev = pp->dev;
- int ret;
- ret = clk_prepare_enable(imx6_pcie->pcie_phy);
+ if (imx_pcie->variant == IMX8MM) {
+ for (i = 0; i < 100; i++) {
+ tmp = readl(imx_pcie->phy_base + PCIE_PHY_CMN_REG75);
+ if (tmp == PCIE_PHY_CMN_REG75_PLL_DONE)
+ break;
+ udelay(10);
+ }
+ } else if (imx_pcie->variant == IMX7D) {
+ for (i = 0; i < 100; i++) {
+ regmap_read(imx_pcie->iomuxc_gpr, IOMUXC_GPR22, &tmp);
+ if (tmp & BIT(31))
+ break;
+ udelay(10);
+ }
+ } else if (imx_pcie->variant == IMX8QXP
+ || imx_pcie->variant == IMX8QM) {
+ for (i = 0; i < 100; i++) {
+ if (imx_pcie->hsio_cfg == PCIEAX2SATA) {
+ regmap_read(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_PHYX2_OFFSET + 0x4,
+ &tmp);
+ orig = IMX8QM_STTS0_LANE0_TX_PLL_LOCK;
+ orig |= IMX8QM_STTS0_LANE1_TX_PLL_LOCK;
+ tmp &= orig;
+ if (tmp == orig) {
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_LPCG_PHYX2_OFFSET,
+ IMX8QM_LPCG_PHY_PCG0
+ | IMX8QM_LPCG_PHY_PCG1,
+ IMX8QM_LPCG_PHY_PCG0
+ | IMX8QM_LPCG_PHY_PCG1);
+ break;
+ }
+ }
+
+ if (imx_pcie->hsio_cfg == PCIEAX1PCIEBX1SATA) {
+ regmap_read(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_PHYX2_OFFSET + 0x4,
+ &tmp);
+ if (imx_pcie->ctrl_id == 0) /* pciea 1 lanes */
+ orig = IMX8QM_STTS0_LANE0_TX_PLL_LOCK;
+ else /* pcieb 1 lanes */
+ orig = IMX8QM_STTS0_LANE1_TX_PLL_LOCK;
+ tmp &= orig;
+ if (tmp == orig) {
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_LPCG_PHYX2_OFFSET,
+ IMX8QM_LPCG_PHY_PCG0
+ | IMX8QM_LPCG_PHY_PCG1,
+ IMX8QM_LPCG_PHY_PCG0
+ | IMX8QM_LPCG_PHY_PCG1);
+ break;
+ }
+ }
+
+ if (imx_pcie->hsio_cfg == PCIEAX2PCIEBX1) {
+ val = IMX8QM_CSR_PHYX2_OFFSET
+ + imx_pcie->ctrl_id * SZ_64K;
+ regmap_read(imx_pcie->iomuxc_gpr,
+ val + IMX8QM_CSR_PHYX_STTS0_OFFSET,
+ &tmp);
+ orig = IMX8QM_STTS0_LANE0_TX_PLL_LOCK;
+ if (imx_pcie->ctrl_id == 0) /* pciea 2 lanes */
+ orig |= IMX8QM_STTS0_LANE1_TX_PLL_LOCK;
+ tmp &= orig;
+ if (tmp == orig) {
+ val = IMX8QM_CSR_PHYX2_OFFSET
+ + imx_pcie->ctrl_id * SZ_64K;
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ val, IMX8QM_LPCG_PHY_PCG0,
+ IMX8QM_LPCG_PHY_PCG0);
+ break;
+ }
+ }
+ udelay(10);
+ }
+ }
+
+ if (i >= 100) {
+ dev_info(dev, "pcie phy pll can't be locked.\n");
+ return -ENODEV;
+ } else {
+ dev_info(dev, "pcie phy pll is locked.\n");
+ return 0;
+ }
+}
+
+static int imx_pcie_deassert_core_reset(struct imx_pcie *imx_pcie)
+{
+ struct pcie_port *pp = &imx_pcie->pp;
+ struct device *dev = pp->dev;
+ int ret, i;
+ u32 val, tmp;
+
+ if (gpio_is_valid(imx_pcie->power_on_gpio))
+ gpio_set_value_cansleep(imx_pcie->power_on_gpio, 1);
+
+ ret = clk_prepare_enable(imx_pcie->pcie);
if (ret) {
- dev_err(dev, "unable to enable pcie_phy clock\n");
- return;
+ dev_err(dev, "unable to enable pcie clock\n");
+ return -ENODEV;
}
- ret = clk_prepare_enable(imx6_pcie->pcie_bus);
+ if (imx_pcie->ext_osc && (imx_pcie->variant == IMX6QP))
+ clk_set_parent(imx_pcie->pcie_bus,
+ imx_pcie->pcie_ext_src);
+ ret = clk_prepare_enable(imx_pcie->pcie_bus);
if (ret) {
- dev_err(dev, "unable to enable pcie_bus clock\n");
+ dev_err(pp->dev, "unable to enable pcie_bus clock\n");
goto err_pcie_bus;
}
- ret = clk_prepare_enable(imx6_pcie->pcie);
+ ret = clk_prepare_enable(imx_pcie->pcie_phy);
if (ret) {
- dev_err(dev, "unable to enable pcie clock\n");
- goto err_pcie;
+ dev_err(dev, "unable to enable pcie_phy clock\n");
+ goto err_pcie_phy;
}
- ret = imx6_pcie_enable_ref_clk(imx6_pcie);
+ ret = imx_pcie_enable_ref_clk(imx_pcie);
if (ret) {
dev_err(dev, "unable to enable pcie ref clock\n");
goto err_ref_clk;
}
/* allow the clocks to stabilize */
- usleep_range(200, 500);
+ udelay(200);
- /* Some boards don't have PCIe reset GPIO. */
- if (gpio_is_valid(imx6_pcie->reset_gpio)) {
- gpio_set_value_cansleep(imx6_pcie->reset_gpio,
- imx6_pcie->gpio_active_high);
- msleep(100);
- gpio_set_value_cansleep(imx6_pcie->reset_gpio,
- !imx6_pcie->gpio_active_high);
- }
-
- switch (imx6_pcie->variant) {
+ switch (imx_pcie->variant) {
case IMX6SX:
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR5,
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR5,
IMX6SX_GPR5_PCIE_BTNRST_RESET, 0);
break;
case IMX6QP:
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ IMX6Q_GPR1_PCIE_SW_RST, 0);
+
+ udelay(200);
+
+ /* Configure the PHY when 100Mhz external OSC is used as input clock */
+ if (!imx_pcie->ext_osc)
+ break;
+
+ mdelay(4);
+ pcie_phy_read(imx_pcie, SSP_CR_SUP_DIG_MPLL_OVRD_IN_LO, &val);
+ /* MPLL_MULTIPLIER [8:2] */
+ val &= ~(0x7F << 2);
+ val |= (0x19 << 2);
+ /* MPLL_MULTIPLIER_OVRD [9:9] */
+ val |= (0x1 << 9);
+ pcie_phy_write(imx_pcie, SSP_CR_SUP_DIG_MPLL_OVRD_IN_LO, val);
+ mdelay(4);
+
+ pcie_phy_read(imx_pcie, SSP_CR_SUP_DIG_ATEOVRD, &val);
+ /* ref_clkdiv2 [0:0] */
+ val &= ~0x1;
+ /* ateovrd_en [2:2] */
+ val |= 0x4;
+ pcie_phy_write(imx_pcie, SSP_CR_SUP_DIG_ATEOVRD, val);
+ mdelay(4);
+
+ break;
+ case IMX6Q:
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_SW_RST, 0);
+ /*
+ * some delay are required by 6qp, after the SW_RST is
+ * cleared, before access the cfg register.
+ */
+ udelay(200);
+ break;
+ case IMX7D:
+ /* wait for more than 10us to release phy g_rst and btnrst */
+ udelay(10);
+ regmap_update_bits(imx_pcie->reg_src, 0x2c, BIT(6), 0);
+ regmap_update_bits(imx_pcie->reg_src, 0x2c, BIT(1), 0);
+
+ /* Add the workaround for ERR010728 */
+ if (unlikely(imx_pcie->phy_base == NULL)) {
+ dev_err(dev, "phy base shouldn't be null.\n");
+ } else {
+ /* De-assert DCC_FB_EN by writing data "0x29". */
+ writel(PCIE_PHY_CMN_REG4_DCC_FB_EN,
+ imx_pcie->phy_base + PCIE_PHY_CMN_REG4);
+ /* Assert RX_EQS and RX_EQS_SEL */
+ writel(PCIE_PHY_CMN_REG24_RX_EQ_SEL
+ | PCIE_PHY_CMN_REG24_RX_EQ,
+ imx_pcie->phy_base + PCIE_PHY_CMN_REG24);
+ /* Assert ATT_MODE by writing data "0xBC". */
+ writel(PCIE_PHY_CMN_REG26_ATT_MODE,
+ imx_pcie->phy_base + PCIE_PHY_CMN_REG26);
+ }
+
+ regmap_update_bits(imx_pcie->reg_src, 0x2c, BIT(2), 0);
+
+ /* wait for phy pll lock firstly. */
+ if (pci_imx_phy_pll_locked(imx_pcie))
+ ret = -ENODEV;
+ break;
+ case IMX8QXP:
+ case IMX8QM:
+ /* bit19 PM_REQ_CORE_RST of pciex#_stts0 should be cleared. */
+ for (i = 0; i < 100; i++) {
+ val = IMX8QM_CSR_PCIEA_OFFSET
+ + imx_pcie->ctrl_id * SZ_64K;
+ regmap_read(imx_pcie->iomuxc_gpr,
+ val + IMX8QM_CSR_PCIE_STTS0_OFFSET,
+ &tmp);
+ if ((tmp & IMX8QM_CTRL_STTS0_PM_REQ_CORE_RST) == 0)
+ break;
+ udelay(10);
+ }
+
+ if ((tmp & IMX8QM_CTRL_STTS0_PM_REQ_CORE_RST) != 0)
+ dev_err(dev, "ERROR PM_REQ_CORE_RST is still set.\n");
+
+ /* wait for phy pll lock firstly. */
+ if (pci_imx_phy_pll_locked(imx_pcie)) {
+ ret = -ENODEV;
+ break;
+ }
- usleep_range(200, 500);
+ /* set up the cpu address offset */
+ if (imx_pcie->cpu_base)
+ pp->cpu_addr_offset = imx_pcie->cpu_base
+ - pp->mem_base;
+ else
+ pp->cpu_addr_offset = 0;
+
+ if (dw_pcie_readl_rc(pp, PCIE_MISC_CTRL) == 0)
+ dw_pcie_writel_rc(pp, PCIE_MISC_CTRL,
+ PCIE_MISC_DBI_RO_WR_EN);
break;
- case IMX6Q: /* Nothing to do */
+ case IMX8MM:
+ case IMX8MQ:
+ /* wait for more than 10us to release phy g_rst and btnrst */
+ udelay(10);
+ if (imx_pcie->ctrl_id == 0)
+ val = IMX8MQ_SRC_PCIEPHY_RCR_OFFSET;
+ else
+ val = IMX8MQ_SRC_PCIE2PHY_RCR_OFFSET;
+ regmap_update_bits(imx_pcie->reg_src, val,
+ IMX8MQ_PCIEPHY_BTN |
+ IMX8MQ_PCIEPHY_DOMAIN_EN,
+ IMX8MQ_PCIEPHY_DOMAIN_EN);
+ regmap_update_bits(imx_pcie->reg_src, val,
+ IMX8MQ_PCIEPHY_G_RST |
+ IMX8MQ_PCIEPHY_DOMAIN_EN,
+ IMX8MQ_PCIEPHY_DOMAIN_EN);
+
+ udelay(100);
+ /* wait for phy pll lock firstly. */
+ if (pci_imx_phy_pll_locked(imx_pcie)) {
+ ret = -ENODEV;
+ break;
+ }
+
+ /*
+ * Configure the CLK_REQ# high, let the L1SS
+ * automatically controlled by HW.
+ */
+ regmap_update_bits(imx_pcie->reg_src, val,
+ IMX8MQ_PCIE_CTRL_APPS_CLK_REQ,
+ IMX8MQ_PCIE_CTRL_APPS_CLK_REQ);
+ regmap_update_bits(imx_pcie->reg_src, val,
+ IMX8MQ_PCIE_CTRL_APPS_EN |
+ IMX8MQ_PCIEPHY_DOMAIN_EN,
+ IMX8MQ_PCIEPHY_DOMAIN_EN);
+
+ if (dw_pcie_readl_rc(pp, PCIE_MISC_CTRL) == 0)
+ dw_pcie_writel_rc(pp, PCIE_MISC_CTRL,
+ PCIE_MISC_DBI_RO_WR_EN);
+ /*
+ * Configure the L1 latency of rc to less than 64us
+ * Otherwise, the L1/L1SUB wouldn't be enable by ASPM.
+ */
+ val = readl(pp->dbi_base + SZ_1M +
+ IMX8MQ_PCIE_LINK_CAP_REG_OFFSET);
+ val &= ~PCI_EXP_LNKCAP_L1EL;
+ val |= IMX8MQ_PCIE_LINK_CAP_L1EL_64US;
+ writel(val, pp->dbi_base + SZ_1M +
+ IMX8MQ_PCIE_LINK_CAP_REG_OFFSET);
break;
}
- return;
+ /* Some boards don't have PCIe reset GPIO. */
+ if (gpio_is_valid(imx_pcie->reset_gpio)) {
+ gpio_set_value_cansleep(imx_pcie->reset_gpio,
+ imx_pcie->gpio_active_high);
+ mdelay(20);
+ gpio_set_value_cansleep(imx_pcie->reset_gpio,
+ !imx_pcie->gpio_active_high);
+ mdelay(20);
+ }
+
+ if (ret == 0)
+ return ret;
err_ref_clk:
- clk_disable_unprepare(imx6_pcie->pcie);
-err_pcie:
- clk_disable_unprepare(imx6_pcie->pcie_bus);
+ clk_disable_unprepare(imx_pcie->pcie_phy);
+err_pcie_phy:
+ clk_disable_unprepare(imx_pcie->pcie_bus);
err_pcie_bus:
- clk_disable_unprepare(imx6_pcie->pcie_phy);
+ clk_disable_unprepare(imx_pcie->pcie);
+ return ret;
+}
+
+static void imx_pcie_phy_pwr_up(struct imx_pcie *imx_pcie)
+{
+ u32 val, offset;
+ unsigned long timeout = jiffies + msecs_to_jiffies(500);
+ struct pcie_port *pp = &imx_pcie->pp;
+ struct device *dev = pp->dev;
+
+ if ((imx_pcie->variant != IMX8MQ) && (imx_pcie->variant != IMX8MM))
+ return;
+ /*
+ * Power up PHY.
+ * pcie phy ref clock select by gpr configuration.
+ * 1? external osc : internal pll
+ */
+
+ if (imx_pcie->ctrl_id == 0)
+ offset = 0;
+ else
+ offset = IMX8MQ_GPC_PGC_PCIE2_BIT_OFFSET;
+
+ regmap_update_bits(imx_pcie->reg_gpc,
+ IMX8MQ_GPC_PGC_CPU_0_1_MAPPING_OFFSET,
+ IMX8MQ_GPC_PGC_PCIE_A53_DOMAIN << offset,
+ IMX8MQ_GPC_PGC_PCIE_A53_DOMAIN << offset);
+ regmap_update_bits(imx_pcie->reg_gpc,
+ IMX8MQ_GPC_PU_PGC_SW_PUP_REQ_OFFSET,
+ IMX8MQ_GPC_PU_PGC_PCIE_SW_PWR_REQ << offset,
+ IMX8MQ_GPC_PU_PGC_PCIE_SW_PWR_REQ << offset);
+
+ regmap_read(imx_pcie->reg_gpc,
+ IMX8MQ_GPC_PU_PGC_SW_PUP_REQ_OFFSET,
+ &val);
+ while (val & (IMX8MQ_GPC_PU_PGC_PCIE_SW_PWR_REQ << offset)) {
+ regmap_read(imx_pcie->reg_gpc,
+ IMX8MQ_GPC_PU_PGC_SW_PUP_REQ_OFFSET,
+ &val);
+ if (time_after(jiffies, timeout)) {
+ dev_err(dev, "CAN NOT PWR UP PCIE%d PHY!\n",
+ imx_pcie->ctrl_id);
+ break;
+ }
+ }
+ udelay(1);
}
-static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
+static void imx_pcie_phy_pwr_dn(struct imx_pcie *imx_pcie)
{
- if (imx6_pcie->variant == IMX6SX)
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ u32 val, offset;
+ unsigned long timeout = jiffies + msecs_to_jiffies(500);
+ struct pcie_port *pp = &imx_pcie->pp;
+ struct device *dev = pp->dev;
+
+ if ((imx_pcie->variant != IMX8MQ) && (imx_pcie->variant != IMX8MM))
+ return;
+ /*
+ * Power up PHY.
+ * pcie phy ref clock select by gpr configuration.
+ * 1? external osc : internal pll
+ */
+
+ if (imx_pcie->ctrl_id == 0) {
+ offset = 0;
+ regmap_update_bits(imx_pcie->reg_gpc,
+ IMX8MQ_GPC_PGC_PCIE_CTRL_OFFSET,
+ IMX8MQ_GPC_PCG_PCIE_CTRL_PCR,
+ IMX8MQ_GPC_PCG_PCIE_CTRL_PCR);
+ } else {
+ offset = IMX8MQ_GPC_PGC_PCIE2_BIT_OFFSET;
+ regmap_update_bits(imx_pcie->reg_gpc,
+ IMX8MQ_GPC_PGC_PCIE2_CTRL_OFFSET,
+ IMX8MQ_GPC_PCG_PCIE_CTRL_PCR,
+ IMX8MQ_GPC_PCG_PCIE_CTRL_PCR);
+ }
+
+ regmap_update_bits(imx_pcie->reg_gpc,
+ IMX8MQ_GPC_PGC_CPU_0_1_MAPPING_OFFSET,
+ IMX8MQ_GPC_PGC_PCIE_A53_DOMAIN << offset,
+ IMX8MQ_GPC_PGC_PCIE_A53_DOMAIN << offset);
+ regmap_update_bits(imx_pcie->reg_gpc,
+ IMX8MQ_GPC_PU_PGC_SW_PDN_REQ_OFFSET,
+ IMX8MQ_GPC_PU_PGC_PCIE_SW_PWR_REQ << offset,
+ IMX8MQ_GPC_PU_PGC_PCIE_SW_PWR_REQ << offset);
+
+ regmap_read(imx_pcie->reg_gpc,
+ IMX8MQ_GPC_PU_PGC_SW_PDN_REQ_OFFSET,
+ &val);
+ while (val & (IMX8MQ_GPC_PU_PGC_PCIE_SW_PWR_REQ << offset)) {
+ regmap_read(imx_pcie->reg_gpc,
+ IMX8MQ_GPC_PU_PGC_SW_PDN_REQ_OFFSET,
+ &val);
+ if (time_after(jiffies, timeout)) {
+ dev_err(dev, "CAN NOT PWR DN PCIE%d PHY!\n",
+ imx_pcie->ctrl_id);
+ break;
+ }
+ }
+ udelay(1);
+}
+
+static void imx_pcie_init_phy(struct imx_pcie *imx_pcie)
+{
+ u32 tmp, val;
+ int ret;
+ struct device_node *np;
+ void __iomem *base;
+
+ if (imx_pcie->variant == IMX8QM
+ || imx_pcie->variant == IMX8QXP) {
+ switch (imx_pcie->hsio_cfg) {
+ case PCIEAX2SATA:
+ /*
+ * bit 0 rx ena 1.
+ * bit12 PHY_X1_EPCS_SEL 1.
+ * bit13 phy_ab_select 0.
+ */
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_PHYX2_OFFSET,
+ IMX8QM_PHYX2_CTRL0_APB_MASK,
+ IMX8QM_PHY_APB_RSTN_0
+ | IMX8QM_PHY_APB_RSTN_1);
+
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_PHYX1_EPCS_SEL,
+ IMX8QM_MISC_PHYX1_EPCS_SEL);
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_PCIE_AB_SELECT,
+ 0);
+ break;
+
+ case PCIEAX1PCIEBX1SATA:
+ tmp = IMX8QM_PHY_APB_RSTN_1;
+ tmp |= IMX8QM_PHY_APB_RSTN_0;
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_PHYX2_OFFSET,
+ IMX8QM_PHYX2_CTRL0_APB_MASK, tmp);
+
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_PHYX1_EPCS_SEL,
+ IMX8QM_MISC_PHYX1_EPCS_SEL);
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_PCIE_AB_SELECT,
+ IMX8QM_MISC_PCIE_AB_SELECT);
+ break;
+
+ case PCIEAX2PCIEBX1:
+ /*
+ * bit 0 rx ena 1.
+ * bit12 PHY_X1_EPCS_SEL 0.
+ * bit13 phy_ab_select 1.
+ */
+ if (imx_pcie->ctrl_id)
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_PHYX1_OFFSET,
+ IMX8QM_PHY_APB_RSTN_0,
+ IMX8QM_PHY_APB_RSTN_0);
+ else
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_PHYX2_OFFSET,
+ IMX8QM_PHYX2_CTRL0_APB_MASK,
+ IMX8QM_PHY_APB_RSTN_0
+ | IMX8QM_PHY_APB_RSTN_1);
+
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_PHYX1_EPCS_SEL,
+ 0);
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_PCIE_AB_SELECT,
+ IMX8QM_MISC_PCIE_AB_SELECT);
+ break;
+ }
+
+ if (imx_pcie->ext_osc) {
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_IOB_RXENA,
+ IMX8QM_MISC_IOB_RXENA);
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_IOB_TXENA,
+ 0);
+ } else {
+ /* Try to used the internal pll as ref clk */
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_IOB_RXENA,
+ 0);
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_MISC_IOB_TXENA,
+ IMX8QM_MISC_IOB_TXENA);
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IMX8QM_CSR_MISC_OFFSET,
+ IMX8QM_CSR_MISC_IOB_A_0_TXOE
+ | IMX8QM_CSR_MISC_IOB_A_0_M1M0_MASK,
+ IMX8QM_CSR_MISC_IOB_A_0_TXOE
+ | IMX8QM_CSR_MISC_IOB_A_0_M1M0_2);
+ }
+ } else if (imx_pcie->variant == IMX8MQ || imx_pcie->variant == IMX8MM) {
+ imx_pcie_phy_pwr_up(imx_pcie);
+
+ if (imx_pcie->ctrl_id == 0)
+ val = IOMUXC_GPR14;
+ else
+ val = IOMUXC_GPR16;
+
+ if (imx_pcie->ext_osc) {
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MQ_GPR_PCIE_REF_USE_PAD,
+ IMX8MQ_GPR_PCIE_REF_USE_PAD);
+ if (imx_pcie->variant == IMX8MM) {
+ dev_info(imx_pcie->pp.dev,
+ "Initialize PHY with EXT REfCLK!.\n");
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MQ_GPR_PCIE_REF_USE_PAD,
+ 0);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MM_GPR_PCIE_REF_CLK_SEL,
+ IMX8MM_GPR_PCIE_REF_CLK_SEL);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MM_GPR_PCIE_AUX_EN,
+ IMX8MM_GPR_PCIE_AUX_EN);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MM_GPR_PCIE_POWER_OFF,
+ 0);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MM_GPR_PCIE_SSC_EN,
+ 0);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MM_GPR_PCIE_REF_CLK_SEL,
+ IMX8MM_GPR_PCIE_REF_CLK_EXT);
+ udelay(100);
+ /* Do the PHY common block reset */
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MM_GPR_PCIE_CMN_RST,
+ IMX8MM_GPR_PCIE_CMN_RST);
+ udelay(200);
+ dev_info(imx_pcie->pp.dev,
+ "PHY Initialization End!.\n");
+ }
+ } else {
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MQ_GPR_PCIE_REF_USE_PAD,
+ 0);
+ if (imx_pcie->variant == IMX8MM) {
+ /* Configure the internal PLL as REF clock */
+ dev_info(imx_pcie->pp.dev,
+ "Initialize PHY with PLL REfCLK!.\n");
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MM_GPR_PCIE_REF_CLK_SEL,
+ IMX8MM_GPR_PCIE_REF_CLK_SEL);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MM_GPR_PCIE_AUX_EN,
+ IMX8MM_GPR_PCIE_AUX_EN);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MM_GPR_PCIE_POWER_OFF,
+ 0);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MM_GPR_PCIE_SSC_EN,
+ 0);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MM_GPR_PCIE_REF_CLK_SEL,
+ IMX8MM_GPR_PCIE_REF_CLK_PLL);
+ udelay(100);
+ /* Configure the PHY */
+ writel(PCIE_PHY_CMN_REG62_PLL_CLK_OUT,
+ imx_pcie->phy_base + PCIE_PHY_CMN_REG62);
+ writel(PCIE_PHY_CMN_REG64_AUX_RX_TX_TERM,
+ imx_pcie->phy_base + PCIE_PHY_CMN_REG64);
+
+ /* Do the PHY common block reset */
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MM_GPR_PCIE_CMN_RST,
+ IMX8MM_GPR_PCIE_CMN_RST);
+ udelay(200);
+ dev_info(imx_pcie->pp.dev,
+ "PHY Initialization End!.\n");
+ } else {
+ np = of_find_compatible_node(NULL, NULL,
+ "fsl,imx8mq-anatop");
+ base = of_iomap(np, 0);
+ WARN_ON(!base);
+
+ val = readl(base + IMX8MQ_ANA_PLLOUT_REG);
+ val &= ~IMX8MQ_ANA_PLLOUT_SEL_MASK;
+ val |= IMX8MQ_ANA_PLLOUT_SEL_SYSPLL1;
+ writel(val, base + IMX8MQ_ANA_PLLOUT_REG);
+ /* SYS_PLL1 is 800M, PCIE REF CLK is 100M */
+ val = readl(base + IMX8MQ_ANA_PLLOUT_DIV_REG);
+ val |= IMX8MQ_ANA_PLLOUT_SYSPLL1_DIV;
+ writel(val, base + IMX8MQ_ANA_PLLOUT_DIV_REG);
+
+ val = readl(base + IMX8MQ_ANA_PLLOUT_REG);
+ val |= IMX8MQ_ANA_PLLOUT_CKE;
+ writel(val, base + IMX8MQ_ANA_PLLOUT_REG);
+ }
+ }
+ /*
+ * In order to pass the compliance tests.
+ * Configure the TRSV regiser of iMX8MM PCIe PHY.
+ */
+ if (imx_pcie->variant == IMX8MM) {
+ writel(PCIE_PHY_TRSV_REG5_GEN1_DEEMP,
+ imx_pcie->phy_base + PCIE_PHY_TRSV_REG5);
+ writel(PCIE_PHY_TRSV_REG6_GEN2_DEEMP,
+ imx_pcie->phy_base + PCIE_PHY_TRSV_REG6);
+ }
+ } else if (imx_pcie->variant == IMX7D) {
+ /* Enable PCIe PHY 1P0D */
+ regulator_set_voltage(imx_pcie->pcie_phy_regulator,
+ 1000000, 1000000);
+ ret = regulator_enable(imx_pcie->pcie_phy_regulator);
+ if (ret)
+ dev_err(imx_pcie->pp.dev,
+ "failed to enable pcie regulator\n");
+
+ /* pcie phy ref clock select; 1? internal pll : external osc */
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ BIT(5), 0);
+ } else if (imx_pcie->variant == IMX6SX) {
+ /* Force PCIe PHY reset */
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR5,
+ IMX6SX_GPR5_PCIE_BTNRST_RESET,
+ IMX6SX_GPR5_PCIE_BTNRST_RESET);
+
+ regulator_set_voltage(imx_pcie->pcie_phy_regulator,
+ 1100000, 1100000);
+ ret = regulator_enable(imx_pcie->pcie_phy_regulator);
+ if (ret)
+ dev_err(imx_pcie->pp.dev,
+ "failed to enable pcie regulator.\n");
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6SX_GPR12_PCIE_RX_EQ_MASK,
IMX6SX_GPR12_PCIE_RX_EQ_2);
+ }
+
+ if (imx_pcie->pcie_bus_regulator != NULL) {
+ ret = regulator_enable(imx_pcie->pcie_bus_regulator);
+ if (ret)
+ dev_err(imx_pcie->pp.dev, "failed to enable pcie regulator.\n");
+ }
+
+ if ((imx_pcie->variant == IMX6Q) || (imx_pcie->variant == IMX6QP)
+ || (imx_pcie->variant == IMX6SX)) {
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6Q_GPR12_PCIE_CTL_2, 0 << 10);
+
+ /* configure constant input signal to the pcie ctrl and phy */
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6Q_GPR12_LOS_LEVEL, IMX6Q_GPR12_LOS_LEVEL_9);
+
+
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR8,
+ IMX6Q_GPR8_TX_DEEMPH_GEN1,
+ imx_pcie->tx_deemph_gen1 << 0);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR8,
+ IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB,
+ imx_pcie->tx_deemph_gen2_3p5db << 6);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR8,
+ IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB,
+ imx_pcie->tx_deemph_gen2_6db << 12);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR8,
+ IMX6Q_GPR8_TX_SWING_FULL,
+ imx_pcie->tx_swing_full << 18);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR8,
+ IMX6Q_GPR8_TX_SWING_LOW,
+ imx_pcie->tx_swing_low << 25);
+ }
+
+ /* configure the device type */
+ if (IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)) {
+ if (imx_pcie->variant == IMX8QM
+ || imx_pcie->variant == IMX8QXP) {
+ val = IMX8QM_CSR_PCIEA_OFFSET
+ + imx_pcie->ctrl_id * SZ_64K;
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ val, IMX8QM_PCIE_TYPE_MASK,
+ PCI_EXP_TYPE_ENDPOINT << 24);
+ } else {
+ if (unlikely(imx_pcie->ctrl_id))
+ /* iMX8MQ second PCIE */
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IOMUXC_GPR12,
+ IMX6Q_GPR12_DEVICE_TYPE >> 4,
+ PCI_EXP_TYPE_ENDPOINT << 8);
+ else
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IOMUXC_GPR12,
+ IMX6Q_GPR12_DEVICE_TYPE,
+ PCI_EXP_TYPE_ENDPOINT << 12);
+ }
+ } else {
+ if (imx_pcie->variant == IMX8QM
+ || imx_pcie->variant == IMX8QXP) {
+ val = IMX8QM_CSR_PCIEA_OFFSET
+ + imx_pcie->ctrl_id * SZ_64K;
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ val, IMX8QM_PCIE_TYPE_MASK,
+ PCI_EXP_TYPE_ROOT_PORT << 24);
+ } else {
+ if (unlikely(imx_pcie->ctrl_id))
+ /* iMX8MQ second PCIE */
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IOMUXC_GPR12,
+ IMX6Q_GPR12_DEVICE_TYPE >> 4,
+ PCI_EXP_TYPE_ROOT_PORT << 8);
+ else
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ IOMUXC_GPR12,
+ IMX6Q_GPR12_DEVICE_TYPE,
+ PCI_EXP_TYPE_ROOT_PORT << 12);
+ }
+ }
+}
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
- IMX6Q_GPR12_PCIE_CTL_2, 0 << 10);
-
- /* configure constant input signal to the pcie ctrl and phy */
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
- IMX6Q_GPR12_DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT << 12);
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
- IMX6Q_GPR12_LOS_LEVEL, 9 << 4);
-
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
- IMX6Q_GPR8_TX_DEEMPH_GEN1,
- imx6_pcie->tx_deemph_gen1 << 0);
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
- IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB,
- imx6_pcie->tx_deemph_gen2_3p5db << 6);
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
- IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB,
- imx6_pcie->tx_deemph_gen2_6db << 12);
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
- IMX6Q_GPR8_TX_SWING_FULL,
- imx6_pcie->tx_swing_full << 18);
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
- IMX6Q_GPR8_TX_SWING_LOW,
- imx6_pcie->tx_swing_low << 25);
-}
-
-static int imx6_pcie_wait_for_link(struct imx6_pcie *imx6_pcie)
-{
- struct pcie_port *pp = &imx6_pcie->pp;
+static int imx_pcie_wait_for_link(struct imx_pcie *imx_pcie)
+{
+ int count = 20000;
+ struct pcie_port *pp = &imx_pcie->pp;
struct device *dev = pp->dev;
/* check if the link is up or not */
- if (!dw_pcie_wait_for_link(pp))
- return 0;
- dev_dbg(dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
- dw_pcie_readl_rc(pp, PCIE_PHY_DEBUG_R0),
- dw_pcie_readl_rc(pp, PCIE_PHY_DEBUG_R1));
- return -ETIMEDOUT;
+ while (!dw_pcie_link_up(pp)) {
+ udelay(10);
+ if (--count)
+ continue;
+
+ dev_err(pp->dev, "phy link never came up\n");
+ dev_dbg(dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
+ dw_pcie_readl_rc(pp, PCIE_PHY_DEBUG_R0),
+ dw_pcie_readl_rc(pp, PCIE_PHY_DEBUG_R1));
+ return -ETIMEDOUT;
+ }
+
+ return 0;
}
-static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie)
+static int imx_pcie_wait_for_speed_change(struct imx_pcie *imx_pcie)
{
- struct pcie_port *pp = &imx6_pcie->pp;
+ struct pcie_port *pp = &imx_pcie->pp;
struct device *dev = pp->dev;
u32 tmp;
unsigned int retries;
@@ -465,24 +1407,115 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie)
/* Test if the speed change finished. */
if (!(tmp & PORT_LOGIC_SPEED_CHANGE))
return 0;
- usleep_range(100, 1000);
+ udelay(100);
}
dev_err(dev, "Speed change timeout\n");
return -EINVAL;
}
-static irqreturn_t imx6_pcie_msi_handler(int irq, void *arg)
+static irqreturn_t imx_pcie_msi_handler(int irq, void *arg)
{
- struct imx6_pcie *imx6_pcie = arg;
- struct pcie_port *pp = &imx6_pcie->pp;
+ struct imx_pcie *imx_pcie = arg;
+ struct pcie_port *pp = &imx_pcie->pp;
return dw_handle_msi_irq(pp);
}
-static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
+static void pci_imx_clk_disable(struct device *dev)
+{
+ u32 val;
+ struct imx_pcie *imx_pcie = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(imx_pcie->pcie);
+ clk_disable_unprepare(imx_pcie->pcie_phy);
+ clk_disable_unprepare(imx_pcie->pcie_bus);
+ switch (imx_pcie->variant) {
+ case IMX6Q:
+ break;
+ case IMX6SX:
+ clk_disable_unprepare(imx_pcie->pcie_inbound_axi);
+ break;
+ case IMX6QP:
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ IMX6Q_GPR1_PCIE_REF_CLK_EN, 0);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ IMX6Q_GPR1_PCIE_TEST_PD,
+ IMX6Q_GPR1_PCIE_TEST_PD);
+ break;
+ case IMX7D:
+ /* turn off external osc input */
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ BIT(5), BIT(5));
+ break;
+ /*
+ * Disable the over ride.
+ * Configure the CLK_REQ# high, let the L1SS automatically
+ * controlled by HW when link is up.
+ * Otherwise, turn off the REF_CLK to save power consumption.
+ */
+ case IMX8MQ:
+ case IMX8MM:
+ if (imx_pcie->ctrl_id == 0)
+ val = IOMUXC_GPR14;
+ else
+ val = IOMUXC_GPR16;
+
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN,
+ 0);
+ break;
+ case IMX8QXP:
+ case IMX8QM:
+ clk_disable_unprepare(imx_pcie->pcie_per);
+ clk_disable_unprepare(imx_pcie->pcie_inbound_axi);
+ break;
+ }
+}
+
+static void pci_imx_ltssm_enable(struct device *dev)
+{
+ u32 val;
+ struct imx_pcie *imx_pcie = dev_get_drvdata(dev);
+
+ switch (imx_pcie->variant) {
+ case IMX6Q:
+ case IMX6SX:
+ case IMX6QP:
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6Q_GPR12_PCIE_CTL_2,
+ IMX6Q_GPR12_PCIE_CTL_2);
+ break;
+ case IMX7D:
+ case IMX8MQ:
+ case IMX8MM:
+ if (imx_pcie->ctrl_id == 0)
+ val = IMX8MQ_SRC_PCIEPHY_RCR_OFFSET;
+ else
+ val = IMX8MQ_SRC_PCIE2PHY_RCR_OFFSET;
+ regmap_update_bits(imx_pcie->reg_src, val,
+ IMX8MQ_PCIE_CTRL_APPS_EN |
+ IMX8MQ_PCIEPHY_DOMAIN_EN,
+ IMX8MQ_PCIE_CTRL_APPS_EN |
+ IMX8MQ_PCIEPHY_DOMAIN_EN);
+ break;
+ case IMX8QXP:
+ case IMX8QM:
+ /* Bit4 of the CTRL2 */
+ val = IMX8QM_CSR_PCIEA_OFFSET
+ + imx_pcie->ctrl_id * SZ_64K;
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+ IMX8QM_CTRL_LTSSM_ENABLE,
+ IMX8QM_CTRL_LTSSM_ENABLE);
+ break;
+ }
+
+}
+
+static int imx_pcie_establish_link(struct imx_pcie *imx_pcie)
{
- struct pcie_port *pp = &imx6_pcie->pp;
+ struct pcie_port *pp = &imx_pcie->pp;
struct device *dev = pp->dev;
u32 tmp;
int ret;
@@ -492,29 +1525,31 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
* started in Gen2 mode, there is a possibility the devices on the
* bus will not be detected at all. This happens with PCIe switches.
*/
- tmp = dw_pcie_readl_rc(pp, PCIE_RC_LCR);
- tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
- tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1;
- dw_pcie_writel_rc(pp, PCIE_RC_LCR, tmp);
+ if (!IS_ENABLED(CONFIG_PCI_IMX6_COMPLIANCE_TEST)) {
+ tmp = dw_pcie_readl_rc(pp, PCIE_RC_LCR);
+ tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
+ tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1;
+ dw_pcie_writel_rc(pp, PCIE_RC_LCR, tmp);
+ }
/* Start LTSSM. */
- regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
- IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
+ pci_imx_ltssm_enable(dev);
- ret = imx6_pcie_wait_for_link(imx6_pcie);
+ ret = imx_pcie_wait_for_link(imx_pcie);
if (ret) {
dev_info(dev, "Link never came up\n");
goto err_reset_phy;
}
- if (imx6_pcie->link_gen == 2) {
+ if (imx_pcie->link_gen >= 2) {
/* Allow Gen2 mode after the link is up. */
tmp = dw_pcie_readl_rc(pp, PCIE_RC_LCR);
tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
- tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2;
+ tmp |= imx_pcie->link_gen;
dw_pcie_writel_rc(pp, PCIE_RC_LCR, tmp);
} else {
dev_info(dev, "Link: Gen2 disabled\n");
+ goto out;
}
/*
@@ -525,19 +1560,19 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
tmp |= PORT_LOGIC_SPEED_CHANGE;
dw_pcie_writel_rc(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp);
- ret = imx6_pcie_wait_for_speed_change(imx6_pcie);
+ ret = imx_pcie_wait_for_speed_change(imx_pcie);
if (ret) {
- dev_err(dev, "Failed to bring link up!\n");
- goto err_reset_phy;
+ dev_info(dev, "Roll back to GEN1 link!\n");
}
/* Make sure link training is finished as well! */
- ret = imx6_pcie_wait_for_link(imx6_pcie);
+ ret = imx_pcie_wait_for_link(imx_pcie);
if (ret) {
dev_err(dev, "Failed to bring link up!\n");
goto err_reset_phy;
}
+out:
tmp = dw_pcie_readl_rc(pp, PCIE_RC_LCSR);
dev_info(dev, "Link up, Gen%i\n", (tmp >> 16) & 0xf);
return 0;
@@ -546,39 +1581,84 @@ err_reset_phy:
dev_dbg(dev, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n",
dw_pcie_readl_rc(pp, PCIE_PHY_DEBUG_R0),
dw_pcie_readl_rc(pp, PCIE_PHY_DEBUG_R1));
- imx6_pcie_reset_phy(imx6_pcie);
+ imx_pcie_reset_phy(imx_pcie);
+
+ if (!IS_ENABLED(CONFIG_PCI_IMX6_COMPLIANCE_TEST)) {
+ pci_imx_clk_disable(dev);
+ pm_runtime_put_sync(pp->dev);
+ imx_pcie_phy_pwr_dn(imx_pcie);
+ if (imx_pcie->pcie_phy_regulator != NULL)
+ regulator_disable(imx_pcie->pcie_phy_regulator);
+ if (imx_pcie->pcie_bus_regulator != NULL)
+ regulator_disable(imx_pcie->pcie_bus_regulator);
+ }
+
return ret;
}
-static void imx6_pcie_host_init(struct pcie_port *pp)
+static int imx_pcie_host_init(struct pcie_port *pp)
{
- struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
+ u32 val;
+ int ret;
+ struct imx_pcie *imx_pcie = to_imx_pcie(pp);
- imx6_pcie_assert_core_reset(imx6_pcie);
- imx6_pcie_init_phy(imx6_pcie);
- imx6_pcie_deassert_core_reset(imx6_pcie);
- dw_pcie_setup_rc(pp);
- imx6_pcie_establish_link(imx6_pcie);
+ /* enable disp_mix power domain */
+ pm_runtime_get_sync(pp->dev);
- if (IS_ENABLED(CONFIG_PCI_MSI))
- dw_pcie_msi_init(pp);
+ imx_pcie_assert_core_reset(imx_pcie);
+ imx_pcie_init_phy(imx_pcie);
+ ret = imx_pcie_deassert_core_reset(imx_pcie);
+ if (ret < 0)
+ return ret;
+
+ if (!IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)) {
+ dw_pcie_setup_rc(pp);
+ ret = imx_pcie_establish_link(imx_pcie);
+ if (ret < 0)
+ return ret;
+ /*
+ * Disable the over ride after link up.
+ * Let the the CLK_REQ# controlled by HW L1SS
+ * automatically.
+ */
+ switch (imx_pcie->variant) {
+ case IMX8MQ:
+ case IMX8MM:
+ if (imx_pcie->ctrl_id == 0)
+ val = IOMUXC_GPR14;
+ else
+ val = IOMUXC_GPR16;
+
+ regmap_update_bits(imx_pcie->iomuxc_gpr, val,
+ IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN,
+ 0);
+ break;
+ default:
+ break;
+ }
+
+ if (IS_ENABLED(CONFIG_PCI_MSI))
+ dw_pcie_msi_init(pp);
+ }
+
+ return 0;
}
-static int imx6_pcie_link_up(struct pcie_port *pp)
+static int imx_pcie_link_up(struct pcie_port *pp)
{
return dw_pcie_readl_rc(pp, PCIE_PHY_DEBUG_R1) &
PCIE_PHY_DEBUG_R1_XMLH_LINK_UP;
}
-static struct pcie_host_ops imx6_pcie_host_ops = {
- .link_up = imx6_pcie_link_up,
- .host_init = imx6_pcie_host_init,
+static struct pcie_host_ops imx_pcie_host_ops = {
+ .link_up = imx_pcie_link_up,
+ .host_init = imx_pcie_host_init,
};
-static int __init imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
+static int imx6_add_pcie_port(struct imx_pcie *imx_pcie,
struct platform_device *pdev)
{
- struct pcie_port *pp = &imx6_pcie->pp;
+ struct pcie_port *pp = &imx_pcie->pp;
struct device *dev = pp->dev;
int ret;
@@ -590,9 +1670,9 @@ static int __init imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
}
ret = devm_request_irq(dev, pp->msi_irq,
- imx6_pcie_msi_handler,
+ imx_pcie_msi_handler,
IRQF_SHARED | IRQF_NO_THREAD,
- "mx6-pcie-msi", imx6_pcie);
+ "mx6-pcie-msi", imx_pcie);
if (ret) {
dev_err(dev, "failed to request MSI irq\n");
return ret;
@@ -600,7 +1680,7 @@ static int __init imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
}
pp->root_bus_nr = -1;
- pp->ops = &imx6_pcie_host_ops;
+ pp->ops = &imx_pcie_host_ops;
ret = dw_pcie_host_init(pp);
if (ret) {
@@ -611,41 +1691,666 @@ static int __init imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
return 0;
}
-static int __init imx6_pcie_probe(struct platform_device *pdev)
+static ssize_t imx_pcie_bar0_addr_info(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct imx_pcie *imx_pcie = dev_get_drvdata(dev);
+ struct pcie_port *pp = &imx_pcie->pp;
+
+ return sprintf(buf, "imx-pcie-bar0-addr-info start 0x%08x\n",
+ readl(pp->dbi_base + PCI_BASE_ADDRESS_0));
+}
+
+static ssize_t imx_pcie_bar0_addr_start(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ u32 bar_start;
+ struct imx_pcie *imx_pcie = dev_get_drvdata(dev);
+ struct pcie_port *pp = &imx_pcie->pp;
+
+ sscanf(buf, "%x\n", &bar_start);
+ writel(bar_start, pp->dbi_base + PCI_BASE_ADDRESS_0);
+
+ return count;
+}
+
+static void imx_pcie_regions_setup(struct device *dev)
+{
+ struct imx_pcie *imx_pcie = dev_get_drvdata(dev);
+ struct pcie_port *pp = &imx_pcie->pp;
+
+ switch (imx_pcie->variant) {
+ case IMX8QM:
+ case IMX8QXP:
+ case IMX8MQ:
+ case IMX8MM:
+ /*
+ * RPMSG reserved 4Mbytes, but only used up to 2Mbytes.
+ * The left 2Mbytes can be used here.
+ */
+ if (ddr_test_region == 0)
+ dev_err(pp->dev, "invalid ddr test region.\n");
+ break;
+ case IMX6SX:
+ case IMX7D:
+ ddr_test_region = 0xb0000000;
+ break;
+
+ case IMX6Q:
+ case IMX6QP:
+ ddr_test_region = 0x40000000;
+ break;
+ }
+ dev_info(pp->dev, "ddr_test_region is 0x%08x.\n", ddr_test_region);
+
+ dw_pcie_prog_outbound_atu(pp, 2, 0, pp->mem_base,
+ ddr_test_region, test_region_size);
+}
+
+static ssize_t imx_pcie_memw_info(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ return sprintf(buf, "imx-pcie-rc-memw-info start 0x%08x, size 0x%08x\n",
+ ddr_test_region, test_region_size);
+}
+
+static ssize_t
+imx_pcie_memw_start(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ u32 memw_start;
+ struct imx_pcie *imx_pcie = dev_get_drvdata(dev);
+
+ sscanf(buf, "%x\n", &memw_start);
+
+ if (imx_pcie->variant == IMX7D || imx_pcie->variant == IMX6SX) {
+ if (memw_start < 0x80000000 || memw_start > 0xb0000000) {
+ dev_err(dev, "Invalid memory start addr.\n");
+ dev_info(dev, "e.x: echo 0xb0000000 > /sys/...");
+ return -1;
+ }
+ } else {
+ if (memw_start < 0x10000000 || memw_start > 0x40000000) {
+ dev_err(dev, "Invalid imx6q sd memory start addr.\n");
+ dev_info(dev, "e.x: echo 0x30000000 > /sys/...");
+ return -1;
+ }
+ }
+
+ if (ddr_test_region != memw_start) {
+ ddr_test_region = memw_start;
+ imx_pcie_regions_setup(dev);
+ }
+
+ return count;
+}
+
+static ssize_t
+imx_pcie_memw_size(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ u32 memw_size;
+
+ sscanf(buf, "%x\n", &memw_size);
+
+ if ((memw_size > (SZ_16M - SZ_1M)) || (memw_size < SZ_64K)) {
+ dev_err(dev, "Invalid, should be [SZ_64K,SZ_16M - SZ_1MB].\n");
+ dev_info(dev, "For example: echo 0x200000 > /sys/...");
+ return -1;
+ }
+
+ if (test_region_size != memw_size) {
+ test_region_size = memw_size;
+ imx_pcie_regions_setup(dev);
+ }
+
+ return count;
+}
+
+static ssize_t imx_pcie_bus_freq(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int ret;
+ u32 bus_freq;
+
+ ret = sscanf(buf, "%x\n", &bus_freq);
+ if (ret != 1)
+ return -EINVAL;
+ if (bus_freq) {
+ dev_info(dev, "pcie request bus freq high.\n");
+ request_bus_freq(BUS_FREQ_HIGH);
+ } else {
+ dev_info(dev, "pcie release bus freq high.\n");
+ release_bus_freq(BUS_FREQ_HIGH);
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(memw_info, S_IRUGO, imx_pcie_memw_info, NULL);
+static DEVICE_ATTR(memw_start_set, S_IWUSR, NULL, imx_pcie_memw_start);
+static DEVICE_ATTR(memw_size_set, S_IWUSR, NULL, imx_pcie_memw_size);
+static DEVICE_ATTR(ep_bar0_addr, S_IWUSR | S_IRUGO, imx_pcie_bar0_addr_info,
+ imx_pcie_bar0_addr_start);
+static DEVICE_ATTR(bus_freq, 0200, NULL, imx_pcie_bus_freq);
+
+static struct attribute *imx_pcie_ep_attrs[] = {
+ /*
+ * The start address, and the limitation (64KB ~ (16MB - 1MB))
+ * of the ddr mem window reserved by RC, and used for EP to access.
+ * BTW, these attrs are only configured at EP side.
+ */
+ &dev_attr_memw_info.attr,
+ &dev_attr_memw_start_set.attr,
+ &dev_attr_memw_size_set.attr,
+ &dev_attr_ep_bar0_addr.attr,
+ NULL
+};
+
+static struct attribute *imx_pcie_rc_attrs[] = {
+ &dev_attr_bus_freq.attr,
+ NULL
+};
+
+static struct attribute_group imx_pcie_attrgroup = {
+ .attrs = imx_pcie_ep_attrs,
+};
+
+static void imx_pcie_setup_ep(struct pcie_port *pp)
+{
+ int ret;
+ u32 val;
+ struct device_node *np = pp->dev->of_node;
+
+ ret = of_property_read_u32(np, "num-lanes", &pp->lanes);
+ if (ret)
+ pp->lanes = 0;
+
+ /* set the number of lanes */
+ val = dw_pcie_readl_rc(pp, PCIE_PORT_LINK_CONTROL);
+ val &= ~PORT_LINK_MODE_MASK;
+ switch (pp->lanes) {
+ case 1:
+ val |= PORT_LINK_MODE_1_LANES;
+ break;
+ case 2:
+ val |= PORT_LINK_MODE_2_LANES;
+ break;
+ default:
+ dev_err(pp->dev, "num-lanes %u: invalid value\n", pp->lanes);
+ return;
+ }
+ dw_pcie_writel_rc(pp, PCIE_PORT_LINK_CONTROL, val);
+
+ /* set link width speed control register */
+ val = dw_pcie_readl_rc(pp, PCIE_LINK_WIDTH_SPEED_CONTROL);
+ val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
+ switch (pp->lanes) {
+ case 1:
+ val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
+ break;
+ case 2:
+ val |= PORT_LOGIC_LINK_WIDTH_2_LANES;
+ break;
+ }
+ dw_pcie_writel_rc(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
+
+ /* get iATU unroll support */
+ val = dw_pcie_readl_rc(pp, PCIE_ATU_VIEWPORT);
+ if (val == 0xffffffff)
+ pp->iatu_unroll_enabled = 1;
+ dev_info(pp->dev, "iATU unroll: %s\n",
+ pp->iatu_unroll_enabled ? "enabled" : "disabled");
+
+ /* CMD reg:I/O space, MEM space, and Bus Master Enable */
+ writel(readl(pp->dbi_base + PCI_COMMAND)
+ | PCI_COMMAND_IO
+ | PCI_COMMAND_MEMORY
+ | PCI_COMMAND_MASTER,
+ pp->dbi_base + PCI_COMMAND);
+
+ /*
+ * configure the class_rev(emaluate one memory ram ep device),
+ * bar0 and bar1 of ep
+ */
+ writel(0xdeadbeaf, pp->dbi_base + PCI_VENDOR_ID);
+ writel((readl(pp->dbi_base + PCI_CLASS_REVISION) & 0xFFFF)
+ | (PCI_CLASS_MEMORY_RAM << 16),
+ pp->dbi_base + PCI_CLASS_REVISION);
+ writel(0xdeadbeaf, pp->dbi_base
+ + PCI_SUBSYSTEM_VENDOR_ID);
+
+ /* 32bit none-prefetchable 8M bytes memory on bar0 */
+ writel(0x0, pp->dbi_base + PCI_BASE_ADDRESS_0);
+ writel(SZ_8M - 1, pp->dbi_base + (1 << 12)
+ + PCI_BASE_ADDRESS_0);
+
+ /* None used bar1 */
+ writel(0x0, pp->dbi_base + PCI_BASE_ADDRESS_1);
+ writel(0, pp->dbi_base + (1 << 12) + PCI_BASE_ADDRESS_1);
+
+ /* 4K bytes IO on bar2 */
+ writel(0x1, pp->dbi_base + PCI_BASE_ADDRESS_2);
+ writel(SZ_4K - 1, pp->dbi_base + (1 << 12) +
+ PCI_BASE_ADDRESS_2);
+
+ /*
+ * 32bit prefetchable 1M bytes memory on bar3
+ * FIXME BAR MASK3 is not changable, the size
+ * is fixed to 256 bytes.
+ */
+ writel(0x8, pp->dbi_base + PCI_BASE_ADDRESS_3);
+ writel(SZ_1M - 1, pp->dbi_base + (1 << 12)
+ + PCI_BASE_ADDRESS_3);
+
+ /*
+ * 64bit prefetchable 1M bytes memory on bar4-5.
+ * FIXME BAR4,5 are not enabled yet
+ */
+ writel(0xc, pp->dbi_base + PCI_BASE_ADDRESS_4);
+ writel(SZ_1M - 1, pp->dbi_base + (1 << 12)
+ + PCI_BASE_ADDRESS_4);
+ writel(0, pp->dbi_base + (1 << 12) + PCI_BASE_ADDRESS_5);
+}
+
+#ifdef CONFIG_PM_SLEEP
+/* PM_TURN_OFF */
+static void pci_imx_pm_turn_off(struct imx_pcie *imx_pcie)
+{
+ int i;
+ u32 dst, val;
+ struct pcie_port *pp = &imx_pcie->pp;
+ struct device *dev = pp->dev;
+
+ /* PM_TURN_OFF */
+ switch (imx_pcie->variant) {
+ case IMX6SX:
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6SX_GPR12_PCIE_PM_TURN_OFF,
+ IMX6SX_GPR12_PCIE_PM_TURN_OFF);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6SX_GPR12_PCIE_PM_TURN_OFF, 0);
+ break;
+ case IMX6QP:
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6Q_GPR12_PCIE_PM_TURN_OFF,
+ IMX6Q_GPR12_PCIE_PM_TURN_OFF);
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6Q_GPR12_PCIE_PM_TURN_OFF, 0);
+ break;
+ case IMX7D:
+ case IMX8MQ:
+ case IMX8MM:
+ if (imx_pcie->ctrl_id == 0)
+ dst = IMX8MQ_SRC_PCIEPHY_RCR_OFFSET;
+ else
+ dst = IMX8MQ_SRC_PCIE2PHY_RCR_OFFSET;
+ regmap_update_bits(imx_pcie->reg_src, dst,
+ IMX8MQ_PCIE_CTRL_APPS_TURNOFF |
+ IMX8MQ_PCIEPHY_DOMAIN_EN,
+ IMX8MQ_PCIE_CTRL_APPS_TURNOFF |
+ IMX8MQ_PCIEPHY_DOMAIN_EN);
+ regmap_update_bits(imx_pcie->reg_src, dst,
+ IMX8MQ_PCIE_CTRL_APPS_TURNOFF |
+ IMX8MQ_PCIEPHY_DOMAIN_EN,
+ IMX8MQ_PCIEPHY_DOMAIN_EN);
+ break;
+ case IMX8QXP:
+ case IMX8QM:
+ dst = IMX8QM_CSR_PCIEA_OFFSET + imx_pcie->ctrl_id * SZ_64K;
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ dst + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+ IMX8QM_CTRL_PM_XMT_TURNOFF,
+ IMX8QM_CTRL_PM_XMT_TURNOFF);
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ dst + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+ IMX8QM_CTRL_PM_XMT_TURNOFF,
+ 0);
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ dst + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+ IMX8QM_CTRL_READY_ENTR_L23,
+ IMX8QM_CTRL_READY_ENTR_L23);
+ /* check the L2 is entered or not. */
+ for (i = 0; i < 10000; i++) {
+ regmap_read(imx_pcie->iomuxc_gpr,
+ dst + IMX8QM_CSR_PCIE_STTS0_OFFSET,
+ &val);
+ if (val & IMX8QM_CTRL_STTS0_PM_LINKST_IN_L2)
+ break;
+ udelay(10);
+ }
+ if ((val & IMX8QM_CTRL_STTS0_PM_LINKST_IN_L2) == 0)
+ dev_err(dev, "PCIE%d can't enter into L2.\n",
+ imx_pcie->ctrl_id);
+ break;
+ case IMX6Q:
+ dev_info(dev, "Info: don't support pm_turn_off yet.\n");
+ return;
+ }
+
+ udelay(1000);
+ if (gpio_is_valid(imx_pcie->reset_gpio))
+ gpio_set_value_cansleep(imx_pcie->reset_gpio, 0);
+}
+
+static int pci_imx_suspend_noirq(struct device *dev)
+{
+ struct imx_pcie *imx_pcie = dev_get_drvdata(dev);
+ struct pcie_port *pp = &imx_pcie->pp;
+
+ if (IS_ENABLED(CONFIG_PCI_MSI))
+ dw_pcie_msi_cfg_store(pp);
+
+ pci_imx_pm_turn_off(imx_pcie);
+
+ if (unlikely(imx_pcie->variant == IMX6Q)) {
+ /*
+ * L2 can exit by 'reset' or Inband beacon (from remote EP)
+ * toggling phy_powerdown has same effect as 'inband beacon'
+ * So, toggle bit18 of GPR1, used as a workaround of errata
+ * "PCIe PCIe does not support L2 Power Down"
+ */
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ IMX6Q_GPR1_PCIE_TEST_PD,
+ IMX6Q_GPR1_PCIE_TEST_PD);
+ } else {
+ pci_imx_clk_disable(dev);
+
+ imx_pcie_phy_pwr_dn(imx_pcie);
+ /* Power down PCIe PHY. */
+ if (imx_pcie->pcie_phy_regulator != NULL)
+ regulator_disable(imx_pcie->pcie_phy_regulator);
+ if (imx_pcie->pcie_bus_regulator != NULL)
+ regulator_disable(imx_pcie->pcie_bus_regulator);
+ }
+
+ return 0;
+}
+
+static void pci_imx_ltssm_disable(struct device *dev)
+{
+ u32 val;
+ struct imx_pcie *imx_pcie = dev_get_drvdata(dev);
+
+ switch (imx_pcie->variant) {
+ case IMX6Q:
+ case IMX6SX:
+ case IMX6QP:
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR12,
+ IMX6Q_GPR12_PCIE_CTL_2, 0);
+ break;
+ case IMX7D:
+ case IMX8MQ:
+ case IMX8MM:
+ if (imx_pcie->ctrl_id == 0)
+ val = IMX8MQ_SRC_PCIEPHY_RCR_OFFSET;
+ else
+ val = IMX8MQ_SRC_PCIE2PHY_RCR_OFFSET;
+ regmap_update_bits(imx_pcie->reg_src, val,
+ IMX8MQ_PCIE_CTRL_APPS_EN |
+ IMX8MQ_PCIEPHY_DOMAIN_EN,
+ IMX8MQ_PCIEPHY_DOMAIN_EN);
+ break;
+ case IMX8QXP:
+ case IMX8QM:
+ /* Bit4 of the CTRL2 */
+ val = IMX8QM_CSR_PCIEA_OFFSET
+ + imx_pcie->ctrl_id * SZ_64K;
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+ IMX8QM_CTRL_LTSSM_ENABLE, 0);
+ regmap_update_bits(imx_pcie->iomuxc_gpr,
+ val + IMX8QM_CSR_PCIE_CTRL2_OFFSET,
+ IMX8QM_CTRL_READY_ENTR_L23, 0);
+ break;
+ }
+}
+
+static int pci_imx_resume_noirq(struct device *dev)
+{
+ int ret = 0;
+ struct imx_pcie *imx_pcie = dev_get_drvdata(dev);
+ struct pcie_port *pp = &imx_pcie->pp;
+
+ if (unlikely(imx_pcie->variant == IMX6Q)) {
+ /*
+ * L2 can exit by 'reset' or Inband beacon (from remote EP)
+ * toggling phy_powerdown has same effect as 'inband beacon'
+ * So, toggle bit18 of GPR1, used as a workaround of errata
+ * "PCIe PCIe does not support L2 Power Down"
+ */
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR1,
+ IMX6Q_GPR1_PCIE_TEST_PD, 0);
+ } else {
+ pci_imx_ltssm_disable(dev);
+ imx_pcie_assert_core_reset(imx_pcie);
+ imx_pcie_init_phy(imx_pcie);
+ ret = imx_pcie_deassert_core_reset(imx_pcie);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * controller maybe turn off, re-configure again
+ */
+ dw_pcie_setup_rc(pp);
+
+ if (IS_ENABLED(CONFIG_PCI_MSI))
+ dw_pcie_msi_cfg_restore(pp);
+ pci_imx_ltssm_enable(dev);
+
+ ret = imx_pcie_wait_for_link(imx_pcie);
+ if (ret < 0)
+ dev_info(dev, "pcie link is down after resume.\n");
+ }
+
+ return ret;
+}
+
+static const struct dev_pm_ops pci_imx_pm_ops = {
+ .suspend_noirq = pci_imx_suspend_noirq,
+ .resume_noirq = pci_imx_resume_noirq,
+ .freeze_noirq = pci_imx_suspend_noirq,
+ .thaw_noirq = pci_imx_resume_noirq,
+ .poweroff_noirq = pci_imx_suspend_noirq,
+ .restore_noirq = pci_imx_resume_noirq,
+};
+#endif
+
+static irqreturn_t imx_pcie_dma_isr(int irq, void *param)
+{
+ u32 irqs, offset;
+ struct pcie_port *pp = (struct pcie_port *)param;
+ struct imx_pcie *imx_pcie = to_imx_pcie(pp);
+
+ offset = imx_pcie->dma_unroll_offset;
+
+ /* check write isr */
+ irqs = readl(pp->dbi_base + offset + DMA_WRITE_INT_STS);
+ if (irqs & DMA_DONE_INT_STS) {
+ /* write 1 clear */
+ writel(irqs & DMA_DONE_INT_STS,
+ pp->dbi_base + offset + DMA_WRITE_INT_CLR);
+ dma_w_end = 1;
+ } else if (irqs & DMA_ABORT_INT_STS) {
+ pr_info("imx pcie dma write error 0x%0x.\n", irqs);
+ }
+ /* check read isr */
+ irqs = readl(pp->dbi_base + offset + DMA_READ_INT_STS);
+ if (irqs & DMA_DONE_INT_STS) {
+ /* write 1 clear */
+ writel(irqs & DMA_DONE_INT_STS,
+ pp->dbi_base + offset + DMA_READ_INT_CLR);
+ dma_r_end = 1;
+ } else if (irqs & DMA_ABORT_INT_STS) {
+ pr_info("imx pcie dma read error 0x%0x.", irqs);
+ }
+ return IRQ_HANDLED;
+}
+
+/**
+ * imx_pcie_local_dma_start - Start one local iMX PCIE DMA.
+ * @pp: the port start the dma transmission.
+ * @dir: direction of the dma, 1 read, 0 write;
+ * @chl: the channel num of the iMX PCIE DMA(0 - 7).
+ * @src: source DMA address.
+ * @dst: destination DMA address.
+ * @len: transfer length.
+ */
+static int imx_pcie_local_dma_start(struct pcie_port *pp, bool dir,
+ unsigned int chl, dma_addr_t src, dma_addr_t dst,
+ unsigned int len)
+{
+ u32 offset, doorbell, unroll_cal;
+ struct imx_pcie *imx_pcie = to_imx_pcie(pp);
+
+ if (pp == NULL)
+ return -EINVAL;
+ if (chl > MAX_PCIE_DMA_CHANNELS)
+ return -EINVAL;
+
+ offset = imx_pcie->dma_unroll_offset;
+ /* enable dma engine, dir 1:read. 0:write. */
+ if (dir)
+ writel(DMA_READ_ENGINE_EN,
+ pp->dbi_base + offset
+ + DMA_READ_ENGINE_EN_OFF);
+ else
+ writel(DMA_WRITE_ENGINE_EN,
+ pp->dbi_base + offset
+ + DMA_WRITE_ENGINE_EN_OFF);
+ writel(0x0, pp->dbi_base + offset + DMA_WRITE_INT_MASK);
+ writel(0x0, pp->dbi_base + offset + DMA_READ_INT_MASK);
+ /* ch dir and ch num */
+ if (offset == 0) {
+ writel((dir << 31) | chl, pp->dbi_base + DMA_VIEWPOT_SEL_OFF);
+ writel(DMA_CHANNEL_CTRL_1_LIE,
+ pp->dbi_base + DMA_CHANNEL_CTRL_1);
+ writel(0x0, pp->dbi_base + DMA_CHANNEL_CTRL_2);
+ writel(len, pp->dbi_base + DMA_TRANSFER_SIZE);
+ writel((u32)src, pp->dbi_base + DMA_SAR_LOW);
+ writel(0x0, pp->dbi_base + DMA_SAR_HIGH);
+ writel((u32)dst, pp->dbi_base + DMA_DAR_LOW);
+ writel(0x0, pp->dbi_base + DMA_DAR_HIGH);
+ } else {
+ unroll_cal = DMA_UNROLL_CDM_OFFSET
+ + 0x200 * (chl + 1) + 0x100 * dir;
+ writel(DMA_CHANNEL_CTRL_1_LIE, pp->dbi_base + unroll_cal);
+ writel(0x0, pp->dbi_base + unroll_cal + 0x4);
+ writel(len, pp->dbi_base + unroll_cal + 0x8);
+ writel((u32)src, pp->dbi_base + unroll_cal + 0xc);
+ writel(0x0, pp->dbi_base + unroll_cal + 0x10);
+ writel((u32)dst, pp->dbi_base + unroll_cal + 0x14);
+ writel(0x0, pp->dbi_base + unroll_cal + 0x18);
+ }
+
+ doorbell = dir ? DMA_READ_DOORBELL : DMA_WRITE_DOORBELL;
+ writel(chl, pp->dbi_base + offset + doorbell);
+
+ return 0;
+}
+
+static int imx_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct imx6_pcie *imx6_pcie;
+ struct imx_pcie *imx_pcie;
struct pcie_port *pp;
- struct resource *dbi_base;
- struct device_node *node = dev->of_node;
+ struct resource *res, reserved_res;
+ struct device_node *reserved_node, *node = dev->of_node;
int ret;
- imx6_pcie = devm_kzalloc(dev, sizeof(*imx6_pcie), GFP_KERNEL);
- if (!imx6_pcie)
+ imx_pcie = devm_kzalloc(dev, sizeof(*imx_pcie), GFP_KERNEL);
+ if (!imx_pcie)
return -ENOMEM;
- pp = &imx6_pcie->pp;
+ pp = &imx_pcie->pp;
pp->dev = dev;
- imx6_pcie->variant =
- (enum imx6_pcie_variants)of_device_get_match_data(dev);
+ imx_pcie->variant =
+ (enum imx_pcie_variants)of_device_get_match_data(dev);
- /* Added for PCI abort handling */
- hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0,
- "imprecise external abort");
+ if (of_property_read_u32(node, "hsio-cfg", &imx_pcie->hsio_cfg))
+ imx_pcie->hsio_cfg = 0;
+
+ if (of_property_read_u32(node, "ctrl-id", &imx_pcie->ctrl_id))
+ imx_pcie->ctrl_id = 0;
+
+ if (of_property_read_u32(node, "cpu-base-addr", &imx_pcie->cpu_base))
+ imx_pcie->cpu_base = 0;
+ if (of_property_read_u32(node, "hard-wired", &imx_pcie->hard_wired))
+ imx_pcie->hard_wired = 0;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
+ if (res)
+ imx_pcie->phy_base = devm_ioremap_resource(dev, res);
+ else
+ imx_pcie->phy_base = NULL;
- dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- pp->dbi_base = devm_ioremap_resource(dev, dbi_base);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+ if (res)
+ pp->dbi_base = devm_ioremap_resource(dev, res);
+ else
+ dev_err(dev, "missing *dbi* reg space\n");
if (IS_ERR(pp->dbi_base))
return PTR_ERR(pp->dbi_base);
+ reserved_node = of_parse_phandle(node, "reserved-region", 0);
+ if (!reserved_node) {
+ dev_info(dev, "no reserved region node.\n");
+ } else {
+ if (of_address_to_resource(reserved_node, 0, &reserved_res)) {
+ dev_err(dev, "failed to get reserved region address\n");
+ of_node_put(reserved_node);
+ return -EINVAL;
+ }
+ ddr_test_region = reserved_res.start + SZ_2M;
+ of_node_put(reserved_node);
+ }
+
/* Fetch GPIOs */
- imx6_pcie->reset_gpio = of_get_named_gpio(node, "reset-gpio", 0);
- imx6_pcie->gpio_active_high = of_property_read_bool(node,
+ imx_pcie->clkreq_gpio = of_get_named_gpio(node, "clkreq-gpio", 0);
+ if (gpio_is_valid(imx_pcie->clkreq_gpio)) {
+ ret = devm_gpio_request_one(&pdev->dev, imx_pcie->clkreq_gpio,
+ GPIOF_OUT_INIT_LOW, "PCIe CLKREQ");
+ if (ret) {
+ dev_err(&pdev->dev, "unable to get clkreq gpio\n");
+ return ret;
+ }
+ } else if (imx_pcie->clkreq_gpio == -EPROBE_DEFER) {
+ return imx_pcie->clkreq_gpio;
+ }
+
+ imx_pcie->dis_gpio = of_get_named_gpio(node, "disable-gpio", 0);
+ if (gpio_is_valid(imx_pcie->dis_gpio)) {
+ ret = devm_gpio_request_one(&pdev->dev, imx_pcie->dis_gpio,
+ GPIOF_OUT_INIT_HIGH, "PCIe DIS");
+ if (ret) {
+ dev_err(&pdev->dev, "unable to get disable gpio\n");
+ return ret;
+ }
+ } else if (imx_pcie->dis_gpio == -EPROBE_DEFER) {
+ return imx_pcie->dis_gpio;
+ }
+
+ imx_pcie->power_on_gpio = of_get_named_gpio(node, "power-on-gpio", 0);
+ if (gpio_is_valid(imx_pcie->power_on_gpio)) {
+ ret = devm_gpio_request_one(&pdev->dev,
+ imx_pcie->power_on_gpio,
+ GPIOF_OUT_INIT_LOW,
+ "PCIe power enable");
+ if (ret) {
+ dev_err(&pdev->dev, "unable to get power-on gpio\n");
+ return ret;
+ }
+ } else if (imx_pcie->power_on_gpio == -EPROBE_DEFER) {
+ return imx_pcie->power_on_gpio;
+ }
+
+ imx_pcie->reset_gpio = of_get_named_gpio(node, "reset-gpio", 0);
+ imx_pcie->gpio_active_high = of_property_read_bool(node,
"reset-gpio-active-high");
- if (gpio_is_valid(imx6_pcie->reset_gpio)) {
- ret = devm_gpio_request_one(dev, imx6_pcie->reset_gpio,
- imx6_pcie->gpio_active_high ?
+ if (gpio_is_valid(imx_pcie->reset_gpio)) {
+ ret = devm_gpio_request_one(dev, imx_pcie->reset_gpio,
+ imx_pcie->gpio_active_high ?
GPIOF_OUT_INIT_HIGH :
GPIOF_OUT_INIT_LOW,
"PCIe reset");
@@ -653,105 +2358,456 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
dev_err(dev, "unable to get reset gpio\n");
return ret;
}
+ } else if (imx_pcie->reset_gpio == -EPROBE_DEFER) {
+ return imx_pcie->reset_gpio;
+ }
+
+ imx_pcie->epdev_on = devm_regulator_get(&pdev->dev, "epdev_on");
+ if (IS_ERR(imx_pcie->epdev_on)) {
+ if (PTR_ERR(imx_pcie->epdev_on) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ dev_info(dev, "no ep regulator found\n");
+ imx_pcie->epdev_on = NULL;
+ } else {
+ ret = regulator_enable(imx_pcie->epdev_on);
+ if (ret)
+ dev_err(dev, "failed to enable the epdev_on regulator\n");
}
/* Fetch clocks */
- imx6_pcie->pcie_phy = devm_clk_get(dev, "pcie_phy");
- if (IS_ERR(imx6_pcie->pcie_phy)) {
+ imx_pcie->pcie_phy = devm_clk_get(dev, "pcie_phy");
+ if (IS_ERR(imx_pcie->pcie_phy)) {
dev_err(dev, "pcie_phy clock source missing or invalid\n");
- return PTR_ERR(imx6_pcie->pcie_phy);
+ return PTR_ERR(imx_pcie->pcie_phy);
}
- imx6_pcie->pcie_bus = devm_clk_get(dev, "pcie_bus");
- if (IS_ERR(imx6_pcie->pcie_bus)) {
+ imx_pcie->pcie_bus = devm_clk_get(dev, "pcie_bus");
+ if (IS_ERR(imx_pcie->pcie_bus)) {
dev_err(dev, "pcie_bus clock source missing or invalid\n");
- return PTR_ERR(imx6_pcie->pcie_bus);
+ return PTR_ERR(imx_pcie->pcie_bus);
+ }
+
+ if (of_property_read_u32(node, "ext_osc", &imx_pcie->ext_osc) < 0)
+ imx_pcie->ext_osc = 0;
+
+ if (imx_pcie->ext_osc && (imx_pcie->variant == IMX6QP)) {
+ /* Change the pcie_bus clock to pcie external OSC */
+ imx_pcie->pcie_bus = devm_clk_get(&pdev->dev, "pcie_ext");
+ if (IS_ERR(imx_pcie->pcie_bus)) {
+ dev_err(&pdev->dev,
+ "pcie_bus clock source missing or invalid\n");
+ return PTR_ERR(imx_pcie->pcie_bus);
+ }
+
+ imx_pcie->pcie_ext_src = devm_clk_get(&pdev->dev,
+ "pcie_ext_src");
+ if (IS_ERR(imx_pcie->pcie_ext_src)) {
+ dev_err(&pdev->dev,
+ "pcie_ext_src clk src missing or invalid\n");
+ return PTR_ERR(imx_pcie->pcie_ext_src);
+ }
}
- imx6_pcie->pcie = devm_clk_get(dev, "pcie");
- if (IS_ERR(imx6_pcie->pcie)) {
+ imx_pcie->pcie = devm_clk_get(dev, "pcie");
+ if (IS_ERR(imx_pcie->pcie)) {
dev_err(dev, "pcie clock source missing or invalid\n");
- return PTR_ERR(imx6_pcie->pcie);
+ return PTR_ERR(imx_pcie->pcie);
}
- if (imx6_pcie->variant == IMX6SX) {
- imx6_pcie->pcie_inbound_axi = devm_clk_get(dev,
- "pcie_inbound_axi");
- if (IS_ERR(imx6_pcie->pcie_inbound_axi)) {
- dev_err(dev,
- "pcie_incbound_axi clock missing or invalid\n");
- return PTR_ERR(imx6_pcie->pcie_inbound_axi);
- }
+ if (imx_pcie->variant == IMX6QP) {
+ imx_pcie->pcie_bus_regulator = devm_regulator_get(pp->dev,
+ "pcie-bus");
+ if (PTR_ERR(imx_pcie->pcie_bus_regulator) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ if (IS_ERR(imx_pcie->pcie_bus_regulator))
+ imx_pcie->pcie_bus_regulator = NULL;
+ } else {
+ imx_pcie->pcie_bus_regulator = NULL;
}
/* Grab GPR config register range */
- imx6_pcie->iomuxc_gpr =
+ if (imx_pcie->variant == IMX7D) {
+ imx_pcie->iomuxc_gpr =
+ syscon_regmap_lookup_by_compatible
+ ("fsl,imx7d-iomuxc-gpr");
+ imx_pcie->reg_src =
+ syscon_regmap_lookup_by_compatible("fsl,imx7d-src");
+ if (IS_ERR(imx_pcie->reg_src)) {
+ dev_err(&pdev->dev,
+ "imx7d pcie phy src missing or invalid\n");
+ return PTR_ERR(imx_pcie->reg_src);
+ }
+ imx_pcie->pcie_phy_regulator = devm_regulator_get(pp->dev,
+ "pcie-phy");
+ } else if (imx_pcie->variant == IMX8MQ || imx_pcie->variant == IMX8MM) {
+ imx_pcie->iomuxc_gpr =
+ syscon_regmap_lookup_by_compatible
+ ("fsl,imx7d-iomuxc-gpr");
+ imx_pcie->reg_src =
+ syscon_regmap_lookup_by_compatible("fsl,imx8mq-src");
+ if (IS_ERR(imx_pcie->reg_src)) {
+ dev_err(&pdev->dev,
+ "imx8mq pcie phy src missing or invalid\n");
+ return PTR_ERR(imx_pcie->reg_src);
+ }
+ imx_pcie->reg_gpc =
+ syscon_regmap_lookup_by_compatible("fsl,imx8mq-gpc");
+ if (IS_ERR(imx_pcie->reg_gpc)) {
+ dev_err(&pdev->dev,
+ "imx8mq pcie phy src missing or invalid\n");
+ return PTR_ERR(imx_pcie->reg_gpc);
+ }
+ } else if (imx_pcie->variant == IMX6SX) {
+ imx_pcie->pcie_inbound_axi = devm_clk_get(&pdev->dev,
+ "pcie_inbound_axi");
+ if (IS_ERR(imx_pcie->pcie_inbound_axi)) {
+ dev_err(&pdev->dev,
+ "pcie clock source missing or invalid\n");
+ return PTR_ERR(imx_pcie->pcie_inbound_axi);
+ }
+
+ imx_pcie->pcie_phy_regulator = devm_regulator_get(pp->dev,
+ "pcie-phy");
+
+ imx_pcie->iomuxc_gpr =
+ syscon_regmap_lookup_by_compatible
+ ("fsl,imx6sx-iomuxc-gpr");
+ } else if (imx_pcie->variant == IMX8QM
+ || imx_pcie->variant == IMX8QXP) {
+ imx_pcie->pcie_per = devm_clk_get(dev, "pcie_per");
+ if (IS_ERR(imx_pcie->pcie_per)) {
+ dev_err(dev, "pcie_per clock source missing or invalid\n");
+ return PTR_ERR(imx_pcie->pcie_per);
+ }
+
+ imx_pcie->iomuxc_gpr =
+ syscon_regmap_lookup_by_phandle(node, "hsio");
+ imx_pcie->pcie_inbound_axi = devm_clk_get(&pdev->dev,
+ "pcie_inbound_axi");
+ if (IS_ERR(imx_pcie->pcie_inbound_axi)) {
+ dev_err(&pdev->dev,
+ "pcie clock source missing or invalid\n");
+ return PTR_ERR(imx_pcie->pcie_inbound_axi);
+ }
+ } else {
+ imx_pcie->iomuxc_gpr =
syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
- if (IS_ERR(imx6_pcie->iomuxc_gpr)) {
+ }
+
+ if (IS_ERR(imx_pcie->iomuxc_gpr)) {
dev_err(dev, "unable to find iomuxc registers\n");
- return PTR_ERR(imx6_pcie->iomuxc_gpr);
+ return PTR_ERR(imx_pcie->iomuxc_gpr);
}
/* Grab PCIe PHY Tx Settings */
if (of_property_read_u32(node, "fsl,tx-deemph-gen1",
- &imx6_pcie->tx_deemph_gen1))
- imx6_pcie->tx_deemph_gen1 = 0;
+ &imx_pcie->tx_deemph_gen1))
+ imx_pcie->tx_deemph_gen1 = 20;
if (of_property_read_u32(node, "fsl,tx-deemph-gen2-3p5db",
- &imx6_pcie->tx_deemph_gen2_3p5db))
- imx6_pcie->tx_deemph_gen2_3p5db = 0;
+ &imx_pcie->tx_deemph_gen2_3p5db))
+ imx_pcie->tx_deemph_gen2_3p5db = 20;
if (of_property_read_u32(node, "fsl,tx-deemph-gen2-6db",
- &imx6_pcie->tx_deemph_gen2_6db))
- imx6_pcie->tx_deemph_gen2_6db = 20;
+ &imx_pcie->tx_deemph_gen2_6db))
+ imx_pcie->tx_deemph_gen2_6db = 20;
if (of_property_read_u32(node, "fsl,tx-swing-full",
- &imx6_pcie->tx_swing_full))
- imx6_pcie->tx_swing_full = 127;
+ &imx_pcie->tx_swing_full))
+ imx_pcie->tx_swing_full = 115;
if (of_property_read_u32(node, "fsl,tx-swing-low",
- &imx6_pcie->tx_swing_low))
- imx6_pcie->tx_swing_low = 127;
+ &imx_pcie->tx_swing_low))
+ imx_pcie->tx_swing_low = 115;
/* Limit link speed */
ret = of_property_read_u32(node, "fsl,max-link-speed",
- &imx6_pcie->link_gen);
+ &imx_pcie->link_gen);
if (ret)
- imx6_pcie->link_gen = 1;
+ imx_pcie->link_gen = 1;
+
+ platform_set_drvdata(pdev, imx_pcie);
+
+ if (IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)
+ && (imx_pcie->hard_wired == 0)) {
+ int i = 0, irq;
+ void *test_reg1, *test_reg2;
+ dma_addr_t test_reg1_dma, test_reg2_dma;
+ void __iomem *pcie_arb_base_addr;
+ struct timeval tv1s, tv1e, tv2s, tv2e;
+ u32 val, tv_count1, tv_count2;
+ struct device_node *np = pp->dev->of_node;
+ LIST_HEAD(res);
+ struct resource_entry *win, *tmp;
+ unsigned long timeout = jiffies + msecs_to_jiffies(300000);
+
+ /* add attributes for device */
+ ret = sysfs_create_group(&pdev->dev.kobj, &imx_pcie_attrgroup);
+ if (ret)
+ return -EINVAL;
+
+ ret = of_pci_get_host_bridge_resources(np, 0, 0xff, &res,
+ &pp->io_base);
+ if (ret)
+ return ret;
- ret = imx6_add_pcie_port(imx6_pcie, pdev);
- if (ret < 0)
- return ret;
+ ret = devm_request_pci_bus_resources(&pdev->dev, &res);
+ if (ret) {
+ dev_err(pp->dev, "missing ranges property\n");
+ pci_free_resource_list(&res);
+ return ret;
+ }
+
+ /* Get the I/O and memory ranges from DT */
+ resource_list_for_each_entry_safe(win, tmp, &res) {
+ switch (resource_type(win->res)) {
+ case IORESOURCE_MEM:
+ pp->mem = win->res;
+ pp->mem->name = "MEM";
+ pp->mem_size = resource_size(pp->mem);
+ pp->mem_bus_addr = pp->mem->start - win->offset;
+ break;
+ }
+ }
- platform_set_drvdata(pdev, imx6_pcie);
+ pp->mem_base = pp->mem->start;
+ pp->ops = &imx_pcie_host_ops;
+ dev_info(dev, " try to initialize pcie ep.\n");
+ ret = imx_pcie_host_init(pp);
+ if (ret) {
+ dev_info(dev, " fail to initialize pcie ep.\n");
+ return ret;
+ }
+
+ imx_pcie_setup_ep(pp);
+ platform_set_drvdata(pdev, imx_pcie);
+ imx_pcie_regions_setup(dev);
+
+ /*
+ * iMX6SX PCIe has the stand-alone power domain.
+ * refer to the initialization for iMX6SX PCIe,
+ * release the PCIe PHY reset here,
+ * before LTSSM enable is set
+ * .
+ */
+ if (imx_pcie->variant == IMX6SX)
+ regmap_update_bits(imx_pcie->iomuxc_gpr, IOMUXC_GPR5,
+ BIT(19), 0 << 19);
+
+ /* assert LTSSM enable */
+ pci_imx_ltssm_enable(dev);
+
+ dev_info(dev, "PCIe EP: waiting for link up...\n");
+ /* link is indicated by the bit4 of DB_R1 register */
+ do {
+ usleep_range(10, 20);
+ if (time_after(jiffies, timeout)) {
+ dev_info(dev, "PCIe EP: link down.\n");
+ return 0;
+ }
+ } while ((readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) & 0x10) == 0);
+
+ /* self io test */
+ /* Check the DMA INT exist or not */
+ irq = of_irq_get(node, 1);
+ if (irq > 0)
+ dma_en = 1;
+ else
+ dma_en = 0;
+ if (dma_en) {
+ /* configure the DMA INT ISR */
+ ret = request_irq(irq, imx_pcie_dma_isr,
+ IRQF_SHARED, "imx-pcie-dma", pp);
+ if (ret) {
+ pr_err("register interrupt %d failed, rc %d\n",
+ irq, ret);
+ dma_en = 0;
+ }
+ test_reg1 = dma_alloc_coherent(dev, test_region_size,
+ &test_reg1_dma, GFP_KERNEL);
+ test_reg2 = dma_alloc_coherent(dev, test_region_size,
+ &test_reg2_dma, GFP_KERNEL);
+ if (!(test_reg1 && test_reg2))
+ dma_en = 0; /* Roll back to PIO. */
+ dma_r_end = dma_w_end = 0;
+
+ val = readl(pp->dbi_base + DMA_CTRL_VIEWPORT_OFF);
+ if (val == 0xffffffff)
+ imx_pcie->dma_unroll_offset =
+ DMA_UNROLL_CDM_OFFSET - DMA_REG_OFFSET;
+ else
+ imx_pcie->dma_unroll_offset = 0;
+ }
+
+ if (unlikely(dma_en == 0)) {
+ test_reg1 = devm_kzalloc(&pdev->dev,
+ test_region_size, GFP_KERNEL);
+ if (!test_reg1) {
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ test_reg2 = devm_kzalloc(&pdev->dev,
+ test_region_size, GFP_KERNEL);
+ if (!test_reg2) {
+ ret = -ENOMEM;
+ return ret;
+ }
+ }
+
+ pcie_arb_base_addr = ioremap_nocache(pp->mem_base,
+ test_region_size);
+ if (!pcie_arb_base_addr) {
+ dev_err(dev, "ioremap error in ep io test\n");
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ for (i = 0; i < test_region_size; i = i + 4) {
+ writel(0xE6600D00 + i, test_reg1 + i);
+ writel(0xDEADBEAF, test_reg2 + i);
+ }
+
+ /* PCIe EP start the data transfer after link up */
+ dev_info(dev, "pcie ep: Starting data transfer...\n");
+ do_gettimeofday(&tv1s);
+
+ /* EP write the test region to remote RC's DDR memory */
+ if (dma_en) {
+ imx_pcie_local_dma_start(pp, 0, 0, test_reg1_dma,
+ pp->mem_base + pp->cpu_addr_offset,
+ test_region_size);
+ timeout = jiffies + msecs_to_jiffies(300);
+ do {
+ udelay(1);
+ if (time_after(jiffies, timeout)) {
+ dev_info(dev, "dma write no end ...\n");
+ break;
+ }
+ } while (!dma_w_end);
+ } else {
+ memcpy((unsigned int *)pcie_arb_base_addr,
+ (unsigned int *)test_reg1,
+ test_region_size);
+ }
+
+ do_gettimeofday(&tv1e);
+
+ do_gettimeofday(&tv2s);
+ /* EP read the test region back from remote RC's DDR memory */
+ if (dma_en) {
+ imx_pcie_local_dma_start(pp, 1, 0,
+ pp->mem_base + pp->cpu_addr_offset,
+ test_reg2_dma, test_region_size);
+ timeout = jiffies + msecs_to_jiffies(300);
+ do {
+ udelay(1);
+ if (time_after(jiffies, timeout)) {
+ dev_info(dev, "dma read no end\n");
+ break;
+ }
+ } while (!dma_r_end);
+ } else {
+ memcpy((unsigned int *)test_reg2,
+ (unsigned int *)pcie_arb_base_addr,
+ test_region_size);
+ }
+
+ do_gettimeofday(&tv2e);
+ if (memcmp(test_reg2, test_reg1, test_region_size) == 0) {
+ tv_count1 = (tv1e.tv_sec - tv1s.tv_sec)
+ * USEC_PER_SEC
+ + tv1e.tv_usec - tv1s.tv_usec;
+ tv_count2 = (tv2e.tv_sec - tv2s.tv_sec)
+ * USEC_PER_SEC
+ + tv2e.tv_usec - tv2s.tv_usec;
+
+ dev_info(dev, "pcie ep: Data %s transfer is successful."
+ " tv_count1 %dus,"
+ " tv_count2 %dus.\n",
+ dma_en ? "DMA" : "PIO",
+ tv_count1, tv_count2);
+ dev_info(dev, "pcie ep: Data write speed:%ldMB/s.\n",
+ ((test_region_size/1024)
+ * MSEC_PER_SEC)
+ /(tv_count1));
+ dev_info(dev, "pcie ep: Data read speed:%ldMB/s.\n",
+ ((test_region_size/1024)
+ * MSEC_PER_SEC)
+ /(tv_count2));
+ } else {
+ dev_info(dev, "pcie ep: Data transfer is failed.\n");
+ } /* end of self io test. */
+ } else {
+ /* add attributes for bus freq */
+ imx_pcie_attrgroup.attrs = imx_pcie_rc_attrs;
+ ret = sysfs_create_group(&pdev->dev.kobj, &imx_pcie_attrgroup);
+ if (ret)
+ return -EINVAL;
+
+ ret = imx6_add_pcie_port(imx_pcie, pdev);
+ if (ret < 0) {
+ if (IS_ENABLED(CONFIG_PCI_IMX6_COMPLIANCE_TEST)) {
+ /* The PCIE clocks wouldn't be turned off */
+ dev_info(dev, "To do the compliance tests.\n");
+ ret = 0;
+ } else {
+ dev_err(dev, "unable to add pcie port.\n");
+ }
+ return ret;
+ }
+ if (IS_ENABLED(CONFIG_RC_MODE_IN_EP_RC_SYS)
+ && (imx_pcie->hard_wired == 0))
+ imx_pcie_regions_setup(&pdev->dev);
+ }
return 0;
}
-static void imx6_pcie_shutdown(struct platform_device *pdev)
+static void imx_pcie_shutdown(struct platform_device *pdev)
{
- struct imx6_pcie *imx6_pcie = platform_get_drvdata(pdev);
+ struct imx_pcie *imx_pcie = platform_get_drvdata(pdev);
/* bring down link, so bootloader gets clean state in case of reboot */
- imx6_pcie_assert_core_reset(imx6_pcie);
+ if (imx_pcie->variant == IMX6Q)
+ imx_pcie_assert_core_reset(imx_pcie);
}
-static const struct of_device_id imx6_pcie_of_match[] = {
+static const struct of_device_id imx_pcie_of_match[] = {
{ .compatible = "fsl,imx6q-pcie", .data = (void *)IMX6Q, },
{ .compatible = "fsl,imx6sx-pcie", .data = (void *)IMX6SX, },
{ .compatible = "fsl,imx6qp-pcie", .data = (void *)IMX6QP, },
+ { .compatible = "fsl,imx7d-pcie", .data = (void *)IMX7D, },
+ { .compatible = "fsl,imx8qm-pcie", .data = (void *)IMX8QM, },
+ { .compatible = "fsl,imx8qxp-pcie", .data = (void *)IMX8QXP, },
+ { .compatible = "fsl,imx8mq-pcie", .data = (void *)IMX8MQ, },
+ { .compatible = "fsl,imx8mm-pcie", .data = (void *)IMX8MM, },
{},
};
-static struct platform_driver imx6_pcie_driver = {
+static struct platform_driver imx_pcie_driver = {
.driver = {
- .name = "imx6q-pcie",
- .of_match_table = imx6_pcie_of_match,
+ .name = "imx-pcie",
+ .of_match_table = imx_pcie_of_match,
+ .pm = &pci_imx_pm_ops,
},
- .shutdown = imx6_pcie_shutdown,
+ .probe = imx_pcie_probe,
+ .shutdown = imx_pcie_shutdown,
};
-static int __init imx6_pcie_init(void)
+static int __init imx_pcie_init(void)
{
- return platform_driver_probe(&imx6_pcie_driver, imx6_pcie_probe);
+#ifdef CONFIG_ARM
+ /*
+ * Since probe() can be deferred we need to make sure that
+ * hook_fault_code is not called after __init memory is freed
+ * by kernel and since imx_pcie_abort_handler() is a no-op,
+ * we can install the handler here without risking it
+ * accessing some uninitialized driver state.
+ */
+ hook_fault_code(16 + 6, imx_pcie_abort_handler, SIGBUS, 0,
+ "imprecise external abort");
+#endif
+
+ return platform_driver_register(&imx_pcie_driver);
}
-device_initcall(imx6_pcie_init);
+device_initcall(imx_pcie_init);
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index b3a87159e457..b27d85b36f56 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -190,11 +190,14 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
return dw_pcie_cfg_write(pp->dbi_base + where, size, val);
}
-static void dw_pcie_prog_outbound_atu(struct pcie_port *pp, int index,
+void dw_pcie_prog_outbound_atu(struct pcie_port *pp, int index,
int type, u64 cpu_addr, u64 pci_addr, u32 size)
{
u32 retries, val;
+ if (cpu_addr >= pp->mem_base)
+ cpu_addr = cpu_addr + pp->cpu_addr_offset;
+
if (pp->iatu_unroll_enabled) {
dw_pcie_writel_unroll(pp, index, PCIE_ATU_UNR_LOWER_BASE,
lower_32_bits(cpu_addr));
@@ -241,7 +244,7 @@ static void dw_pcie_prog_outbound_atu(struct pcie_port *pp, int index,
if (val == PCIE_ATU_ENABLE)
return;
- usleep_range(LINK_WAIT_IATU_MIN, LINK_WAIT_IATU_MAX);
+ mdelay(LINK_WAIT_IATU_MAX/1000);
}
dev_err(pp->dev, "iATU is not being enabled\n");
}
@@ -284,16 +287,36 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
void dw_pcie_msi_init(struct pcie_port *pp)
{
- u64 msi_target;
-
- pp->msi_data = __get_free_pages(GFP_KERNEL, 0);
- msi_target = virt_to_phys((void *)pp->msi_data);
+ dma_addr_t msi_addr;
+ dma_alloc_coherent(pp->dev, 64, &msi_addr, GFP_KERNEL);
+ pp->msi_target = (u64)msi_addr;
/* program the msi_data */
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
- (u32)(msi_target & 0xffffffff));
+ (u32)(pp->msi_target & 0xffffffff));
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4,
- (u32)(msi_target >> 32 & 0xffffffff));
+ (u32)(pp->msi_target >> 32 & 0xffffffff));
+}
+
+void dw_pcie_msi_cfg_store(struct pcie_port *pp)
+{
+ int i;
+
+ for (i = 0; i < MAX_MSI_CTRLS; i++)
+ dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + i * 12, 4,
+ &pp->msi_enable[i]);
+}
+
+void dw_pcie_msi_cfg_restore(struct pcie_port *pp)
+{
+ int i;
+
+ for (i = 0; i < MAX_MSI_CTRLS; i++) {
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4, pp->msi_target);
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4, 0);
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + i * 12, 4,
+ pp->msi_enable[i]);
+ }
}
static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
@@ -382,15 +405,12 @@ no_valid_irq:
static void dw_msi_setup_msg(struct pcie_port *pp, unsigned int irq, u32 pos)
{
struct msi_msg msg;
- u64 msi_target;
if (pp->ops->get_msi_addr)
- msi_target = pp->ops->get_msi_addr(pp);
- else
- msi_target = virt_to_phys((void *)pp->msi_data);
+ pp->msi_target = pp->ops->get_msi_addr(pp);
- msg.address_lo = (u32)(msi_target & 0xffffffff);
- msg.address_hi = (u32)(msi_target >> 32 & 0xffffffff);
+ msg.address_lo = (u32)(pp->msi_target & 0xffffffff);
+ msg.address_hi = (u32)(pp->msi_target >> 32 & 0xffffffff);
if (pp->ops->get_msi_data)
msg.data = pp->ops->get_msi_data(pp, pos);
@@ -406,9 +426,6 @@ static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
int irq, pos;
struct pcie_port *pp = pdev->bus->sysdata;
- if (desc->msi_attrib.is_msix)
- return -EINVAL;
-
irq = assign_irq(1, desc, &pos);
if (irq < 0)
return irq;
@@ -426,9 +443,20 @@ static int dw_msi_setup_irqs(struct msi_controller *chip, struct pci_dev *pdev,
struct msi_desc *desc;
struct pcie_port *pp = pdev->bus->sysdata;
- /* MSI-X interrupts are not supported */
- if (type == PCI_CAP_ID_MSIX)
- return -EINVAL;
+ if (type == PCI_CAP_ID_MSIX) {
+ if ((MAX_MSI_IRQS - bitmap_weight(pp->msi_irq_in_use,
+ MAX_MSI_IRQS)) < nvec)
+ return -ENOSPC;
+
+ for_each_pci_msi_entry(desc, pdev) {
+ int ret = dw_msi_setup_irq(chip, pdev, desc);
+
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+ }
WARN_ON(!list_is_singular(&pdev->dev.msi_list));
desc = list_entry(pdev->dev.msi_list.next, struct msi_desc, list);
@@ -637,8 +665,11 @@ int dw_pcie_host_init(struct pcie_port *pp)
}
}
- if (pp->ops->host_init)
- pp->ops->host_init(pp);
+ if (pp->ops->host_init) {
+ ret = pp->ops->host_init(pp);
+ if (ret < 0)
+ return ret;
+ }
pp->root_bus_nr = pp->busn->start;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
@@ -882,9 +913,11 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
dev_dbg(pp->dev, "iATU unroll: %s\n",
pp->iatu_unroll_enabled ? "enabled" : "disabled");
- dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
- PCIE_ATU_TYPE_MEM, pp->mem_base,
- pp->mem_bus_addr, pp->mem_size);
+ if (!IS_ENABLED(CONFIG_EP_MODE_IN_EP_RC_SYS)
+ && !IS_ENABLED(CONFIG_RC_MODE_IN_EP_RC_SYS))
+ dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_MEM, pp->mem_base,
+ pp->mem_bus_addr, pp->mem_size);
if (pp->num_viewport > 2)
dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX2,
PCIE_ATU_TYPE_IO, pp->io_base,
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index a567ea288ee2..101fc5fee2ed 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -38,6 +38,7 @@ struct pcie_port {
u64 mem_base;
phys_addr_t mem_bus_addr;
u32 mem_size;
+ int cpu_addr_offset;
struct resource *cfg;
struct resource *io;
struct resource *mem;
@@ -48,8 +49,9 @@ struct pcie_port {
struct pcie_host_ops *ops;
int msi_irq;
struct irq_domain *irq_domain;
- unsigned long msi_data;
+ u64 msi_target;
u8 iatu_unroll_enabled;
+ unsigned int msi_enable[MAX_MSI_CTRLS];
DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
};
@@ -63,7 +65,7 @@ struct pcie_host_ops {
int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
unsigned int devfn, int where, int size, u32 val);
int (*link_up)(struct pcie_port *pp);
- void (*host_init)(struct pcie_port *pp);
+ int (*host_init)(struct pcie_port *pp);
void (*msi_set_irq)(struct pcie_port *pp, int irq);
void (*msi_clear_irq)(struct pcie_port *pp, int irq);
phys_addr_t (*get_msi_addr)(struct pcie_port *pp);
@@ -79,8 +81,12 @@ int dw_pcie_cfg_write(void __iomem *addr, int size, u32 val);
irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
void dw_pcie_msi_init(struct pcie_port *pp);
int dw_pcie_wait_for_link(struct pcie_port *pp);
+void dw_pcie_msi_cfg_store(struct pcie_port *pp);
+void dw_pcie_msi_cfg_restore(struct pcie_port *pp);
int dw_pcie_link_up(struct pcie_port *pp);
void dw_pcie_setup_rc(struct pcie_port *pp);
int dw_pcie_host_init(struct pcie_port *pp);
+void dw_pcie_prog_outbound_atu(struct pcie_port *pp, int index,
+ int type, u64 cpu_addr, u64 pci_addr, u32 size);
#endif /* _PCIE_DESIGNWARE_H */
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 6b3c5c4cbb37..605922e01c45 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -5241,15 +5241,14 @@ static void pci_no_domains(void)
#endif
}
-#ifdef CONFIG_PCI_DOMAINS
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
static atomic_t __domain_nr = ATOMIC_INIT(-1);
-int pci_get_new_domain_nr(void)
+static int pci_get_new_domain_nr(void)
{
return atomic_inc_return(&__domain_nr);
}
-#ifdef CONFIG_PCI_DOMAINS_GENERIC
static int of_pci_bus_find_domain_nr(struct device *parent)
{
static int use_dt_domains = -1;
@@ -5303,7 +5302,6 @@ int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
acpi_pci_bus_find_domain_nr(bus);
}
#endif
-#endif
/**
* pci_ext_cfg_avail - can we access extended PCI config space?
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 7ce77635e5ad..ac53edbc9613 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -71,6 +71,14 @@ config PCIEASPM_POWERSAVE
Enable PCI Express ASPM L0s and L1 where possible, even if the
BIOS did not.
+config PCIEASPM_POWER_SUPERSAVE
+ bool "Power Supersave"
+ depends on PCIEASPM
+ help
+ Same as PCIEASPM_POWERSAVE, except it also enables L1 substates where
+ possible. This would result in higher power savings while staying in L1
+ where the components support it.
+
config PCIEASPM_PERFORMANCE
bool "Performance"
depends on PCIEASPM
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 6643a7bc381c..80b417e697da 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -30,8 +30,29 @@
#define ASPM_STATE_L0S_UP (1) /* Upstream direction L0s state */
#define ASPM_STATE_L0S_DW (2) /* Downstream direction L0s state */
#define ASPM_STATE_L1 (4) /* L1 state */
+#define ASPM_STATE_L1_1 (8) /* ASPM L1.1 state */
+#define ASPM_STATE_L1_2 (0x10) /* ASPM L1.2 state */
+#define ASPM_STATE_L1_1_PCIPM (0x20) /* PCI PM L1.1 state */
+#define ASPM_STATE_L1_2_PCIPM (0x40) /* PCI PM L1.2 state */
+#define ASPM_STATE_L1_SS_PCIPM (ASPM_STATE_L1_1_PCIPM | ASPM_STATE_L1_2_PCIPM)
+#define ASPM_STATE_L1_2_MASK (ASPM_STATE_L1_2 | ASPM_STATE_L1_2_PCIPM)
+#define ASPM_STATE_L1SS (ASPM_STATE_L1_1 | ASPM_STATE_L1_1_PCIPM |\
+ ASPM_STATE_L1_2_MASK)
#define ASPM_STATE_L0S (ASPM_STATE_L0S_UP | ASPM_STATE_L0S_DW)
-#define ASPM_STATE_ALL (ASPM_STATE_L0S | ASPM_STATE_L1)
+#define ASPM_STATE_ALL (ASPM_STATE_L0S | ASPM_STATE_L1 | \
+ ASPM_STATE_L1SS)
+
+/*
+ * When L1 substates are enabled, the LTR L1.2 threshold is a timing parameter
+ * that decides whether L1.1 or L1.2 is entered (Refer PCIe spec for details).
+ * Not sure is there is a way to "calculate" this on the fly, but maybe we
+ * could turn it into a parameter in future. This value has been taken from
+ * the following files from Intel's coreboot (which is the only code I found
+ * to have used this):
+ * https://www.coreboot.org/pipermail/coreboot-gerrit/2015-March/021134.html
+ * https://review.coreboot.org/#/c/8832/
+ */
+#define LTR_L1_2_THRESHOLD_BITS ((1 << 21) | (1 << 23) | (1 << 30))
struct aspm_latency {
u32 l0s; /* L0s latency (nsec) */
@@ -40,6 +61,7 @@ struct aspm_latency {
struct pcie_link_state {
struct pci_dev *pdev; /* Upstream component of the Link */
+ struct pci_dev *downstream; /* Downstream component, function 0 */
struct pcie_link_state *root; /* pointer to the root port link */
struct pcie_link_state *parent; /* pointer to the parent Link state */
struct list_head sibling; /* node in link_list */
@@ -47,11 +69,11 @@ struct pcie_link_state {
struct list_head link; /* node in parent's children list */
/* ASPM state */
- u32 aspm_support:3; /* Supported ASPM state */
- u32 aspm_enabled:3; /* Enabled ASPM state */
- u32 aspm_capable:3; /* Capable ASPM state with latency */
- u32 aspm_default:3; /* Default ASPM state by BIOS */
- u32 aspm_disable:3; /* Disabled ASPM state */
+ u32 aspm_support:7; /* Supported ASPM state */
+ u32 aspm_enabled:7; /* Enabled ASPM state */
+ u32 aspm_capable:7; /* Capable ASPM state with latency */
+ u32 aspm_default:7; /* Default ASPM state by BIOS */
+ u32 aspm_disable:7; /* Disabled ASPM state */
/* Clock PM state */
u32 clkpm_capable:1; /* Clock PM capable? */
@@ -66,6 +88,14 @@ struct pcie_link_state {
* has one slot under it, so at most there are 8 functions.
*/
struct aspm_latency acceptable[8];
+
+ /* L1 PM Substate info */
+ struct {
+ u32 up_cap_ptr; /* L1SS cap ptr in upstream dev */
+ u32 dw_cap_ptr; /* L1SS cap ptr in downstream dev */
+ u32 ctl1; /* value to be programmed in ctl1 */
+ u32 ctl2; /* value to be programmed in ctl2 */
+ } l1ss;
};
static int aspm_disabled, aspm_force;
@@ -76,11 +106,14 @@ static LIST_HEAD(link_list);
#define POLICY_DEFAULT 0 /* BIOS default setting */
#define POLICY_PERFORMANCE 1 /* high performance */
#define POLICY_POWERSAVE 2 /* high power saving */
+#define POLICY_POWER_SUPERSAVE 3 /* possibly even more power saving */
#ifdef CONFIG_PCIEASPM_PERFORMANCE
static int aspm_policy = POLICY_PERFORMANCE;
#elif defined CONFIG_PCIEASPM_POWERSAVE
static int aspm_policy = POLICY_POWERSAVE;
+#elif defined CONFIG_PCIEASPM_POWER_SUPERSAVE
+static int aspm_policy = POLICY_POWER_SUPERSAVE;
#else
static int aspm_policy;
#endif
@@ -88,7 +121,8 @@ static int aspm_policy;
static const char *policy_str[] = {
[POLICY_DEFAULT] = "default",
[POLICY_PERFORMANCE] = "performance",
- [POLICY_POWERSAVE] = "powersave"
+ [POLICY_POWERSAVE] = "powersave",
+ [POLICY_POWER_SUPERSAVE] = "powersupersave"
};
#define LINK_RETRAIN_TIMEOUT HZ
@@ -101,6 +135,9 @@ static int policy_to_aspm_state(struct pcie_link_state *link)
return 0;
case POLICY_POWERSAVE:
/* Enable ASPM L0s/L1 */
+ return (ASPM_STATE_L0S | ASPM_STATE_L1);
+ case POLICY_POWER_SUPERSAVE:
+ /* Enable Everything */
return ASPM_STATE_ALL;
case POLICY_DEFAULT:
return link->aspm_default;
@@ -115,7 +152,8 @@ static int policy_to_clkpm_state(struct pcie_link_state *link)
/* Disable ASPM and Clock PM */
return 0;
case POLICY_POWERSAVE:
- /* Disable Clock PM */
+ case POLICY_POWER_SUPERSAVE:
+ /* Enable Clock PM */
return 1;
case POLICY_DEFAULT:
return link->clkpm_default;
@@ -278,11 +316,33 @@ static u32 calc_l1_acceptable(u32 encoding)
return (1000 << encoding);
}
+/* Convert L1SS T_pwr encoding to usec */
+static u32 calc_l1ss_pwron(struct pci_dev *pdev, u32 scale, u32 val)
+{
+ switch (scale) {
+ case 0:
+ return val * 2;
+ case 1:
+ return val * 10;
+ case 2:
+ return val * 100;
+ }
+ dev_err(&pdev->dev, "%s: Invalid T_PwrOn scale: %u\n",
+ __func__, scale);
+ return 0;
+}
+
struct aspm_register_info {
u32 support:2;
u32 enabled:2;
u32 latency_encoding_l0s;
u32 latency_encoding_l1;
+
+ /* L1 substates */
+ u32 l1ss_cap_ptr;
+ u32 l1ss_cap;
+ u32 l1ss_ctl1;
+ u32 l1ss_ctl2;
};
static void pcie_get_aspm_reg(struct pci_dev *pdev,
@@ -297,6 +357,22 @@ static void pcie_get_aspm_reg(struct pci_dev *pdev,
info->latency_encoding_l1 = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15;
pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &reg16);
info->enabled = reg16 & PCI_EXP_LNKCTL_ASPMC;
+
+ /* Read L1 PM substate capabilities */
+ info->l1ss_cap = info->l1ss_ctl1 = info->l1ss_ctl2 = 0;
+ info->l1ss_cap_ptr = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
+ if (!info->l1ss_cap_ptr)
+ return;
+ pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CAP,
+ &info->l1ss_cap);
+ if (!(info->l1ss_cap & PCI_L1SS_CAP_L1_PM_SS)) {
+ info->l1ss_cap = 0;
+ return;
+ }
+ pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CTL1,
+ &info->l1ss_ctl1);
+ pci_read_config_dword(pdev, info->l1ss_cap_ptr + PCI_L1SS_CTL2,
+ &info->l1ss_ctl2);
}
static void pcie_aspm_check_latency(struct pci_dev *endpoint)
@@ -327,6 +403,14 @@ static void pcie_aspm_check_latency(struct pci_dev *endpoint)
* Check L1 latency.
* Every switch on the path to root complex need 1
* more microsecond for L1. Spec doesn't mention L0s.
+ *
+ * The exit latencies for L1 substates are not advertised
+ * by a device. Since the spec also doesn't mention a way
+ * to determine max latencies introduced by enabling L1
+ * substates on the components, it is not clear how to do
+ * a L1 substate exit latency check. We assume that the
+ * L1 exit latencies advertised by a device include L1
+ * substate latencies (and hence do not do any check).
*/
latency = max_t(u32, link->latency_up.l1, link->latency_dw.l1);
if ((link->aspm_capable & ASPM_STATE_L1) &&
@@ -338,6 +422,60 @@ static void pcie_aspm_check_latency(struct pci_dev *endpoint)
}
}
+/*
+ * The L1 PM substate capability is only implemented in function 0 in a
+ * multi function device.
+ */
+static struct pci_dev *pci_function_0(struct pci_bus *linkbus)
+{
+ struct pci_dev *child;
+
+ list_for_each_entry(child, &linkbus->devices, bus_list)
+ if (PCI_FUNC(child->devfn) == 0)
+ return child;
+ return NULL;
+}
+
+/* Calculate L1.2 PM substate timing parameters */
+static void aspm_calc_l1ss_info(struct pcie_link_state *link,
+ struct aspm_register_info *upreg,
+ struct aspm_register_info *dwreg)
+{
+ u32 val1, val2, scale1, scale2;
+
+ link->l1ss.up_cap_ptr = upreg->l1ss_cap_ptr;
+ link->l1ss.dw_cap_ptr = dwreg->l1ss_cap_ptr;
+ link->l1ss.ctl1 = link->l1ss.ctl2 = 0;
+
+ if (!(link->aspm_support & ASPM_STATE_L1_2_MASK))
+ return;
+
+ /* Choose the greater of the two T_cmn_mode_rstr_time */
+ val1 = (upreg->l1ss_cap >> 8) & 0xFF;
+ val2 = (upreg->l1ss_cap >> 8) & 0xFF;
+ if (val1 > val2)
+ link->l1ss.ctl1 |= val1 << 8;
+ else
+ link->l1ss.ctl1 |= val2 << 8;
+ /*
+ * We currently use LTR L1.2 threshold to be fixed constant picked from
+ * Intel's coreboot.
+ */
+ link->l1ss.ctl1 |= LTR_L1_2_THRESHOLD_BITS;
+
+ /* Choose the greater of the two T_pwr_on */
+ val1 = (upreg->l1ss_cap >> 19) & 0x1F;
+ scale1 = (upreg->l1ss_cap >> 16) & 0x03;
+ val2 = (dwreg->l1ss_cap >> 19) & 0x1F;
+ scale2 = (dwreg->l1ss_cap >> 16) & 0x03;
+
+ if (calc_l1ss_pwron(link->pdev, scale1, val1) >
+ calc_l1ss_pwron(link->downstream, scale2, val2))
+ link->l1ss.ctl2 |= scale1 | (val1 << 3);
+ else
+ link->l1ss.ctl2 |= scale2 | (val2 << 3);
+}
+
static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
{
struct pci_dev *child, *parent = link->pdev;
@@ -351,12 +489,27 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
return;
}
+ /* Get upstream/downstream components' register state */
+ pcie_get_aspm_reg(parent, &upreg);
+ child = pci_function_0(linkbus);
+ pcie_get_aspm_reg(child, &dwreg);
+ link->downstream = child;
+
+ /*
+ * If ASPM not supported, don't mess with the clocks and link,
+ * bail out now.
+ */
+ if (!(upreg.support & dwreg.support))
+ return;
+
/* Configure common clock before checking latencies */
pcie_aspm_configure_common_clock(link);
- /* Get upstream/downstream components' register state */
+ /*
+ * Re-read upstream/downstream components' register state
+ * after clock configuration
+ */
pcie_get_aspm_reg(parent, &upreg);
- child = list_entry(linkbus->devices.next, struct pci_dev, bus_list);
pcie_get_aspm_reg(child, &dwreg);
/*
@@ -383,6 +536,28 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
link->latency_up.l1 = calc_l1_latency(upreg.latency_encoding_l1);
link->latency_dw.l1 = calc_l1_latency(dwreg.latency_encoding_l1);
+ /* Setup L1 substate */
+ if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_ASPM_L1_1)
+ link->aspm_support |= ASPM_STATE_L1_1;
+ if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_ASPM_L1_2)
+ link->aspm_support |= ASPM_STATE_L1_2;
+ if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_1)
+ link->aspm_support |= ASPM_STATE_L1_1_PCIPM;
+ if (upreg.l1ss_cap & dwreg.l1ss_cap & PCI_L1SS_CAP_PCIPM_L1_2)
+ link->aspm_support |= ASPM_STATE_L1_2_PCIPM;
+
+ if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_1)
+ link->aspm_enabled |= ASPM_STATE_L1_1;
+ if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_2)
+ link->aspm_enabled |= ASPM_STATE_L1_2;
+ if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_1)
+ link->aspm_enabled |= ASPM_STATE_L1_1_PCIPM;
+ if (upreg.l1ss_ctl1 & dwreg.l1ss_ctl1 & PCI_L1SS_CTL1_PCIPM_L1_2)
+ link->aspm_enabled |= ASPM_STATE_L1_2_PCIPM;
+
+ if (link->aspm_support & ASPM_STATE_L1SS)
+ aspm_calc_l1ss_info(link, &upreg, &dwreg);
+
/* Save default state */
link->aspm_default = link->aspm_enabled;
@@ -421,6 +596,92 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
}
}
+static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos,
+ u32 clear, u32 set)
+{
+ u32 val;
+
+ pci_read_config_dword(pdev, pos, &val);
+ val &= ~clear;
+ val |= set;
+ pci_write_config_dword(pdev, pos, val);
+}
+
+/* Configure the ASPM L1 substates */
+static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
+{
+ u32 val, enable_req;
+ struct pci_dev *child = link->downstream, *parent = link->pdev;
+ u32 up_cap_ptr = link->l1ss.up_cap_ptr;
+ u32 dw_cap_ptr = link->l1ss.dw_cap_ptr;
+
+ enable_req = (link->aspm_enabled ^ state) & state;
+
+ /*
+ * Here are the rules specified in the PCIe spec for enabling L1SS:
+ * - When enabling L1.x, enable bit at parent first, then at child
+ * - When disabling L1.x, disable bit at child first, then at parent
+ * - When enabling ASPM L1.x, need to disable L1
+ * (at child followed by parent).
+ * - The ASPM/PCIPM L1.2 must be disabled while programming timing
+ * parameters
+ *
+ * To keep it simple, disable all L1SS bits first, and later enable
+ * what is needed.
+ */
+
+ /* Disable all L1 substates */
+ pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
+ PCI_L1SS_CTL1_L1SS_MASK, 0);
+ pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
+ PCI_L1SS_CTL1_L1SS_MASK, 0);
+ /*
+ * If needed, disable L1, and it gets enabled later
+ * in pcie_config_aspm_link().
+ */
+ if (enable_req & (ASPM_STATE_L1_1 | ASPM_STATE_L1_2)) {
+ pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_ASPM_L1, 0);
+ pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_ASPM_L1, 0);
+ }
+
+ if (enable_req & ASPM_STATE_L1_2_MASK) {
+
+ /* Program T_pwr_on in both ports */
+ pci_write_config_dword(parent, up_cap_ptr + PCI_L1SS_CTL2,
+ link->l1ss.ctl2);
+ pci_write_config_dword(child, dw_cap_ptr + PCI_L1SS_CTL2,
+ link->l1ss.ctl2);
+
+ /* Program T_cmn_mode in parent */
+ pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
+ 0xFF00, link->l1ss.ctl1);
+
+ /* Program LTR L1.2 threshold in both ports */
+ pci_clear_and_set_dword(parent, dw_cap_ptr + PCI_L1SS_CTL1,
+ 0xE3FF0000, link->l1ss.ctl1);
+ pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
+ 0xE3FF0000, link->l1ss.ctl1);
+ }
+
+ val = 0;
+ if (state & ASPM_STATE_L1_1)
+ val |= PCI_L1SS_CTL1_ASPM_L1_1;
+ if (state & ASPM_STATE_L1_2)
+ val |= PCI_L1SS_CTL1_ASPM_L1_2;
+ if (state & ASPM_STATE_L1_1_PCIPM)
+ val |= PCI_L1SS_CTL1_PCIPM_L1_1;
+ if (state & ASPM_STATE_L1_2_PCIPM)
+ val |= PCI_L1SS_CTL1_PCIPM_L1_2;
+
+ /* Enable what we need to enable */
+ pci_clear_and_set_dword(parent, up_cap_ptr + PCI_L1SS_CTL1,
+ PCI_L1SS_CAP_L1_PM_SS, val);
+ pci_clear_and_set_dword(child, dw_cap_ptr + PCI_L1SS_CTL1,
+ PCI_L1SS_CAP_L1_PM_SS, val);
+}
+
static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val)
{
pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL,
@@ -430,11 +691,23 @@ static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val)
static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
{
u32 upstream = 0, dwstream = 0;
- struct pci_dev *child, *parent = link->pdev;
+ struct pci_dev *child = link->downstream, *parent = link->pdev;
struct pci_bus *linkbus = parent->subordinate;
- /* Nothing to do if the link is already in the requested state */
+ /* Enable only the states that were not explicitly disabled */
state &= (link->aspm_capable & ~link->aspm_disable);
+
+ /* Can't enable any substates if L1 is not enabled */
+ if (!(state & ASPM_STATE_L1))
+ state &= ~ASPM_STATE_L1SS;
+
+ /* Spec says both ports must be in D0 before enabling PCI PM substates*/
+ if (parent->current_state != PCI_D0 || child->current_state != PCI_D0) {
+ state &= ~ASPM_STATE_L1_SS_PCIPM;
+ state |= (link->aspm_enabled & ASPM_STATE_L1_SS_PCIPM);
+ }
+
+ /* Nothing to do if the link is already in the requested state */
if (link->aspm_enabled == state)
return;
/* Convert ASPM state to upstream/downstream ASPM register state */
@@ -446,6 +719,10 @@ static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
upstream |= PCI_EXP_LNKCTL_ASPM_L1;
dwstream |= PCI_EXP_LNKCTL_ASPM_L1;
}
+
+ if (link->aspm_capable & ASPM_STATE_L1SS)
+ pcie_config_aspm_l1ss(link, state);
+
/*
* Spec 2.0 suggests all functions should be configured the
* same setting for ASPM. Enabling ASPM L1 should be done in
@@ -609,7 +886,8 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
* the BIOS's expectation, we'll do so once pci_enable_device() is
* called.
*/
- if (aspm_policy != POLICY_POWERSAVE) {
+ if (aspm_policy != POLICY_POWERSAVE &&
+ aspm_policy != POLICY_POWER_SUPERSAVE) {
pcie_config_aspm_path(link);
pcie_set_clkpm(link, policy_to_clkpm_state(link));
}
@@ -709,7 +987,8 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
if (aspm_disabled || !link)
return;
- if (aspm_policy != POLICY_POWERSAVE)
+ if (aspm_policy != POLICY_POWERSAVE &&
+ aspm_policy != POLICY_POWER_SUPERSAVE)
return;
down_read(&pci_bus_sem);
@@ -897,8 +1176,8 @@ static ssize_t clk_ctl_store(struct device *dev,
return n;
}
-static DEVICE_ATTR(link_state, 0644, link_state_show, link_state_store);
-static DEVICE_ATTR(clk_ctl, 0644, clk_ctl_show, clk_ctl_store);
+static DEVICE_ATTR_RW(link_state);
+static DEVICE_ATTR_RW(clk_ctl);
static char power_group[] = "power";
void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev)
diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index 4d5c5f9f0dbd..c6ab4a4d36ba 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -12,6 +12,9 @@ config ARM_PMU
Say y if you want to use CPU performance monitors on ARM-based
systems.
+config IMX8_DDR_PERF
+ tristate "Freescale i.MX8 DDR perf monitor"
+
config XGENE_PMU
depends on PERF_EVENTS && ARCH_XGENE
bool "APM X-Gene SoC PMU"
diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
index b116e982810b..2f8260d912fb 100644
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_ARM_PMU) += arm_pmu.o
+obj-$(CONFIG_IMX8_DDR_PERF) += ddr-perf.o
obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o
diff --git a/drivers/perf/ddr-perf.c b/drivers/perf/ddr-perf.c
new file mode 100644
index 000000000000..73fe52ee8b95
--- /dev/null
+++ b/drivers/perf/ddr-perf.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright 2017 NXP
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/perf_event.h>
+#include <linux/slab.h>
+
+
+#define COUNTER_CNTL 0x0
+#define COUNTER_READ 0x20
+
+#define COUNTER_DPCR1 0x30
+
+#define CNTL_OVER 0x1
+#define CNTL_CLEAR 0x2
+#define CNTL_EN 0x4
+#define CNTL_EN_MASK 0xFFFFFFFB
+#define CNTL_CLEAR_MASK 0xFFFFFFFD
+#define CNTL_OVER_MASK 0xFFFFFFFE
+
+#define CNTL_CSV_SHIFT 24
+#define CNTL_CSV_MASK (0xFF << CNTL_CSV_SHIFT)
+
+#define EVENT_CYCLES_ID 0
+#define EVENT_CYCLES_COUNTER 0
+#define NUM_COUNTER 4
+#define MAX_EVENT 3
+
+#define to_ddr_pmu(p) container_of(p, struct ddr_pmu, pmu)
+
+#define DDR_PERF_DEV_NAME "ddr_perf"
+
+static DEFINE_IDA(ddr_ida);
+
+PMU_EVENT_ATTR_STRING(cycles, ddr_perf_cycles, "event=0x00");
+PMU_EVENT_ATTR_STRING(selfresh, ddr_perf_selfresh, "event=0x01");
+PMU_EVENT_ATTR_STRING(read-access, ddr_perf_read_accesses, "event=0x04");
+PMU_EVENT_ATTR_STRING(write-access, ddr_perf_write_accesses, "event=0x05");
+PMU_EVENT_ATTR_STRING(read-queue-depth, ddr_perf_read_queue_depth,
+ "event=0x08");
+PMU_EVENT_ATTR_STRING(write-queue-depth, ddr_perf_write_queue_depth,
+ "event=0x09");
+PMU_EVENT_ATTR_STRING(lp-read-credit-cnt, ddr_perf_lp_read_credit_cnt,
+ "event=0x10");
+PMU_EVENT_ATTR_STRING(hp-read-credit-cnt, ddr_perf_hp_read_credit_cnt,
+ "event=0x11");
+PMU_EVENT_ATTR_STRING(write-credit-cnt, ddr_perf_write_credit_cnt,
+ "event=0x12");
+PMU_EVENT_ATTR_STRING(read-command, ddr_perf_read_command, "event=0x20");
+PMU_EVENT_ATTR_STRING(write-command, ddr_perf_write_command, "event=0x21");
+PMU_EVENT_ATTR_STRING(read-modify-write-command,
+ ddr_perf_read_modify_write_command, "event=0x22");
+PMU_EVENT_ATTR_STRING(hp-read, ddr_perf_hp_read, "event=0x23");
+PMU_EVENT_ATTR_STRING(hp-req-nodcredit, ddr_perf_hp_req_nocredit, "event=0x24");
+PMU_EVENT_ATTR_STRING(hp-xact-credit, ddr_perf_hp_xact_credit, "event=0x25");
+PMU_EVENT_ATTR_STRING(lp-req-nocredit, ddr_perf_lp_req_nocredit, "event=0x26");
+PMU_EVENT_ATTR_STRING(lp-xact-credit, ddr_perf_lp_xact_credit, "event=0x27");
+PMU_EVENT_ATTR_STRING(wr-xact-credit, ddr_perf_wr_xact_credit, "event=0x29");
+PMU_EVENT_ATTR_STRING(read-cycles, ddr_perf_read_cycles, "event=0x2a");
+PMU_EVENT_ATTR_STRING(write-cycles, ddr_perf_write_cycles, "event=0x2b");
+PMU_EVENT_ATTR_STRING(read-write-transition, ddr_perf_read_write_transition,
+ "event=0x30");
+PMU_EVENT_ATTR_STRING(precharge, ddr_perf_precharge, "event=0x31");
+PMU_EVENT_ATTR_STRING(activate, ddr_perf_activate, "event=0x32");
+PMU_EVENT_ATTR_STRING(load-mode, ddr_perf_load_mode, "event=0x33");
+PMU_EVENT_ATTR_STRING(mwr, ddr_perf_mwr, "event=0x34");
+PMU_EVENT_ATTR_STRING(read, ddr_perf_read, "event=0x35");
+PMU_EVENT_ATTR_STRING(read-activate, ddr_perf_read_activate, "event=0x36");
+PMU_EVENT_ATTR_STRING(refresh, ddr_perf_refresh, "event=0x37");
+PMU_EVENT_ATTR_STRING(write, ddr_perf_write, "event=0x38");
+PMU_EVENT_ATTR_STRING(raw-hazard, ddr_perf_raw_hazard, "event=0x39");
+
+PMU_EVENT_ATTR_STRING(axid-read, ddr_perf_axid_read, "event=0x41");
+PMU_EVENT_ATTR_STRING(axid-write, ddr_perf_axid_write, "event=0x42");
+
+#define DDR_CAP_AXI_ID 0x1
+
+struct fsl_ddr_devtype_data {
+ unsigned int flags;
+};
+
+static const struct fsl_ddr_devtype_data imx8_data;
+static const struct fsl_ddr_devtype_data imx8m_data = {
+ .flags = DDR_CAP_AXI_ID,
+};
+
+static const struct of_device_id imx_ddr_pmu_dt_ids[] = {
+ { .compatible = "fsl,imx8-ddr-pmu", .data = (void*)&imx8_data},
+ { .compatible = "fsl,imx8m-ddr-pmu", .data = (void*)&imx8m_data},
+ { /* sentinel */ }
+};
+
+struct ddr_pmu {
+ struct pmu pmu;
+ void __iomem *base;
+ cpumask_t cpu;
+ struct hlist_node node;
+ struct device *dev;
+ struct perf_event *active_events[NUM_COUNTER];
+ int total_events;
+ bool cycles_active;
+ struct fsl_ddr_devtype_data *devtype;
+};
+
+static ssize_t ddr_perf_cpumask_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ddr_pmu *pmu = dev_get_drvdata(dev);
+
+ return cpumap_print_to_pagebuf(true, buf, &pmu->cpu);
+}
+
+static struct device_attribute ddr_perf_cpumask_attr =
+ __ATTR(cpumask, 0444, ddr_perf_cpumask_show, NULL);
+
+static struct attribute *ddr_perf_cpumask_attrs[] = {
+ &ddr_perf_cpumask_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ddr_perf_cpumask_attr_group = {
+ .attrs = ddr_perf_cpumask_attrs,
+};
+
+static struct attribute *ddr_perf_events_attrs[] = {
+ &ddr_perf_cycles.attr.attr,
+ &ddr_perf_selfresh.attr.attr,
+ &ddr_perf_read_accesses.attr.attr,
+ &ddr_perf_write_accesses.attr.attr,
+ &ddr_perf_read_queue_depth.attr.attr,
+ &ddr_perf_write_queue_depth.attr.attr,
+ &ddr_perf_lp_read_credit_cnt.attr.attr,
+ &ddr_perf_hp_read_credit_cnt.attr.attr,
+ &ddr_perf_write_credit_cnt.attr.attr,
+ &ddr_perf_read_command.attr.attr,
+ &ddr_perf_write_command.attr.attr,
+ &ddr_perf_read_modify_write_command.attr.attr,
+ &ddr_perf_hp_read.attr.attr,
+ &ddr_perf_hp_req_nocredit.attr.attr,
+ &ddr_perf_hp_xact_credit.attr.attr,
+ &ddr_perf_lp_req_nocredit.attr.attr,
+ &ddr_perf_lp_xact_credit.attr.attr,
+ &ddr_perf_wr_xact_credit.attr.attr,
+ &ddr_perf_read_cycles.attr.attr,
+ &ddr_perf_write_cycles.attr.attr,
+ &ddr_perf_read_write_transition.attr.attr,
+ &ddr_perf_precharge.attr.attr,
+ &ddr_perf_activate.attr.attr,
+ &ddr_perf_load_mode.attr.attr,
+ &ddr_perf_mwr.attr.attr,
+ &ddr_perf_read.attr.attr,
+ &ddr_perf_read_activate.attr.attr,
+ &ddr_perf_refresh.attr.attr,
+ &ddr_perf_write.attr.attr,
+ &ddr_perf_raw_hazard.attr.attr,
+ &ddr_perf_axid_read.attr.attr,
+ &ddr_perf_axid_write.attr.attr,
+ NULL,
+};
+
+static struct attribute_group ddr_perf_events_attr_group = {
+ .name = "events",
+ .attrs = ddr_perf_events_attrs,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-63");
+PMU_FORMAT_ATTR(axi_id, "config1:0-63");
+
+static struct attribute *ddr_perf_format_attrs[] = {
+ &format_attr_event.attr,
+ &format_attr_axi_id.attr,
+ NULL,
+};
+
+static struct attribute_group ddr_perf_format_attr_group = {
+ .name = "format",
+ .attrs = ddr_perf_format_attrs,
+};
+
+static const struct attribute_group *attr_groups[] = {
+ &ddr_perf_events_attr_group,
+ &ddr_perf_format_attr_group,
+ &ddr_perf_cpumask_attr_group,
+ NULL,
+};
+
+static u32 ddr_perf_alloc_counter(struct ddr_pmu *pmu, int event)
+{
+ int i;
+
+ /* Always map cycle event to counter 0 */
+ if (event == EVENT_CYCLES_ID)
+ return EVENT_CYCLES_COUNTER;
+
+ for (i = 1; i < NUM_COUNTER; i++)
+ if (pmu->active_events[i] == NULL)
+ return i;
+
+ return -ENOENT;
+}
+
+static u32 ddr_perf_free_counter(struct ddr_pmu *pmu, int counter)
+{
+ if (counter < 0 || counter >= NUM_COUNTER)
+ return -ENOENT;
+
+ pmu->active_events[counter] = NULL;
+
+ return 0;
+}
+
+static u32 ddr_perf_read_counter(struct ddr_pmu *pmu, int counter)
+{
+ return readl(pmu->base + COUNTER_READ + counter * 4);
+}
+
+static int ddr_perf_event_init(struct perf_event *event)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+ return -EOPNOTSUPP;
+
+ if (event->cpu < 0) {
+ dev_warn(pmu->dev, "Can't provide per-task data!\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (event->attr.exclude_user ||
+ event->attr.exclude_kernel ||
+ event->attr.exclude_hv ||
+ event->attr.exclude_idle ||
+ event->attr.exclude_host ||
+ event->attr.exclude_guest ||
+ event->attr.sample_period)
+ return -EINVAL;
+
+ event->cpu = cpumask_first(&pmu->cpu);
+ hwc->idx = -1;
+
+ return 0;
+}
+
+
+static void ddr_perf_event_update(struct perf_event *event)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ u64 delta, prev_raw_count, new_raw_count;
+ int counter = hwc->idx;
+
+ do {
+ prev_raw_count = local64_read(&hwc->prev_count);
+ new_raw_count = ddr_perf_read_counter(pmu, counter);
+ } while (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+ new_raw_count) != prev_raw_count);
+
+ delta = (new_raw_count - prev_raw_count) & 0xFFFFFFFF;
+
+ local64_add(delta, &event->count);
+}
+
+static void ddr_perf_event_enable(struct ddr_pmu *pmu, int config,
+ int counter, bool enable)
+{
+ u8 reg = counter * 4 + COUNTER_CNTL;
+ int val;
+
+ if (enable) {
+ /* Clear counter, then enable it. */
+ writel(0, pmu->base + reg);
+ val = CNTL_EN | CNTL_CLEAR;
+ val |= (config << CNTL_CSV_SHIFT) & CNTL_CSV_MASK;
+ } else {
+ /* Disable counter */
+ val = readl(pmu->base + reg) & CNTL_EN_MASK;
+ }
+
+ writel(val, pmu->base + reg);
+
+ if (config == EVENT_CYCLES_ID)
+ pmu->cycles_active = enable;
+}
+
+static void ddr_perf_event_start(struct perf_event *event, int flags)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ int counter = hwc->idx;
+
+ if (pmu->devtype->flags & DDR_CAP_AXI_ID) {
+ if (event->attr.config == 0x41 ||
+ event->attr.config == 0x42) {
+ int val = event->attr.config1;
+ writel(val, pmu->base + COUNTER_DPCR1);
+ }
+ }
+
+ local64_set(&hwc->prev_count, 0);
+
+ ddr_perf_event_enable(pmu, event->attr.config, counter, true);
+ /*
+ * If the cycles counter wasn't explicitly selected,
+ * we will enable it now.
+ */
+ if (counter > 0 && !pmu->cycles_active)
+ ddr_perf_event_enable(pmu, EVENT_CYCLES_ID,
+ EVENT_CYCLES_COUNTER, true);
+}
+
+static int ddr_perf_event_add(struct perf_event *event, int flags)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ int counter;
+ int cfg = event->attr.config;
+
+ counter = ddr_perf_alloc_counter(pmu, cfg);
+ if (counter < 0) {
+ dev_warn(pmu->dev, "There are not enough counters\n");
+ return -EOPNOTSUPP;
+ }
+
+ pmu->active_events[counter] = event;
+ pmu->total_events++;
+ hwc->idx = counter;
+
+ if (flags & PERF_EF_START)
+ ddr_perf_event_start(event, flags);
+
+ local64_set(&hwc->prev_count, ddr_perf_read_counter(pmu, counter));
+
+ return 0;
+}
+
+static void ddr_perf_event_stop(struct perf_event *event, int flags)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ int counter = hwc->idx;
+
+ ddr_perf_event_enable(pmu, event->attr.config, counter, false);
+ ddr_perf_event_update(event);
+}
+
+static void ddr_perf_event_del(struct perf_event *event, int flags)
+{
+ struct ddr_pmu *pmu = to_ddr_pmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ int counter = hwc->idx;
+
+ ddr_perf_event_stop(event, PERF_EF_UPDATE);
+
+ ddr_perf_free_counter(pmu, counter);
+ pmu->total_events--;
+ hwc->idx = -1;
+
+ /* If all events have stopped, stop the cycles counter as well */
+ if ((pmu->total_events == 0) && pmu->cycles_active)
+ ddr_perf_event_enable(pmu, EVENT_CYCLES_ID,
+ EVENT_CYCLES_COUNTER, false);
+}
+
+static int ddr_perf_init(struct ddr_pmu *pmu, void __iomem *base,
+ struct device *dev)
+{
+ *pmu = (struct ddr_pmu) {
+ .pmu = (struct pmu) {
+ .task_ctx_nr = perf_invalid_context,
+ .attr_groups = attr_groups,
+ .event_init = ddr_perf_event_init,
+ .add = ddr_perf_event_add,
+ .del = ddr_perf_event_del,
+ .start = ddr_perf_event_start,
+ .stop = ddr_perf_event_stop,
+ .read = ddr_perf_event_update,
+ },
+ .base = base,
+ .dev = dev,
+ };
+
+ return ida_simple_get(&ddr_ida, 0, 0, GFP_KERNEL);
+}
+
+static irqreturn_t ddr_perf_irq_handler(int irq, void *p)
+{
+ int i;
+ u8 reg;
+ int val;
+ int counter;
+ struct ddr_pmu *pmu = (struct ddr_pmu *) p;
+ struct perf_event *event;
+
+ /*
+ * The cycles counter has overflowed. Update all of the local counter
+ * values, then reset the cycles counter, so the others can continue
+ * counting.
+ */
+ for (i = 0; i <= pmu->total_events; i++) {
+ if (pmu->active_events[i] != NULL) {
+ event = pmu->active_events[i];
+ counter = event->hw.idx;
+ reg = counter * 4 + COUNTER_CNTL;
+ val = readl(pmu->base + reg);
+ ddr_perf_event_update(event);
+ if (val & CNTL_OVER) {
+ /* Clear counter, then re-enable it. */
+ ddr_perf_event_enable(pmu, event->attr.config,
+ counter, true);
+ /* Update event again to reset prev_count */
+ ddr_perf_event_update(event);
+ }
+ }
+ }
+
+ /*
+ * Reset the cycles counter regardless if it was explicitly
+ * enabled or not.
+ */
+ ddr_perf_event_enable(pmu, EVENT_CYCLES_ID,
+ EVENT_CYCLES_COUNTER, true);
+
+ return IRQ_HANDLED;
+}
+
+static int ddr_perf_probe(struct platform_device *pdev)
+{
+ struct ddr_pmu *pmu;
+ struct device_node *np;
+ void __iomem *base;
+ struct resource *iomem;
+ char *name;
+ int num;
+ int ret;
+ u32 irq;
+ const struct of_device_id *of_id =
+ of_match_device(imx_ddr_pmu_dt_ids, &pdev->dev);
+
+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, iomem);
+ if (IS_ERR(base)) {
+ ret = PTR_ERR(base);
+ return ret;
+ }
+
+ np = pdev->dev.of_node;
+
+ pmu = kzalloc(sizeof(*pmu), GFP_KERNEL);
+ if (!pmu)
+ return -ENOMEM;
+
+ num = ddr_perf_init(pmu, base, &pdev->dev);
+ name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "ddr%d", num);
+
+ pmu->devtype = (struct fsl_ddr_devtype_data *)of_id->data;
+
+ cpumask_set_cpu(smp_processor_id(), &pmu->cpu);
+ ret = perf_pmu_register(&(pmu->pmu), name, -1);
+ if (ret)
+ goto ddr_perf_err;
+
+ /* Request irq */
+ irq = of_irq_get(np, 0);
+ if (irq < 0) {
+ pr_err("Failed to get irq: %d", irq);
+ goto ddr_perf_err;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq,
+ ddr_perf_irq_handler, NULL,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ DDR_PERF_DEV_NAME,
+ pmu);
+ if (ret < 0) {
+ pr_err("Request irq failed: %d", ret);
+ goto ddr_perf_irq_err;
+ }
+
+ return 0;
+
+ddr_perf_irq_err:
+ perf_pmu_unregister(&(pmu->pmu));
+ddr_perf_err:
+ pr_warn("i.MX8 DDR Perf PMU failed (%d), disabled\n", ret);
+ kfree(pmu);
+ return ret;
+}
+
+
+static int ddr_perf_remove(struct platform_device *pdev)
+{
+ struct ddr_pmu *pmu = platform_get_drvdata(pdev);
+
+ perf_pmu_unregister(&pmu->pmu);
+ kfree(pmu);
+
+ return 0;
+}
+
+static struct platform_driver imx_ddr_pmu_driver = {
+ .driver = {
+ .name = "imx-ddr-pmu",
+ .of_match_table = imx_ddr_pmu_dt_ids,
+ },
+ .probe = ddr_perf_probe,
+ .remove = ddr_perf_remove,
+};
+
+static int __init imx_ddr_pmu_init(void)
+{
+ return platform_driver_register(&imx_ddr_pmu_driver);
+}
+
+module_init(imx_ddr_pmu_init);
+
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 7dc726d7fbde..0121a4b17589 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -490,4 +490,29 @@ config PHY_NS2_PCIE
help
Enable this to support the Broadcom Northstar2 PCIe PHY.
If unsure, say N.
+
+config PHY_MIXEL_LVDS
+ bool
+ depends on OF
+ select GENERIC_PHY
+ default ARCH_FSL_IMX8QM
+
+config PHY_MIXEL_LVDS_COMBO
+ bool
+ depends on OF
+ select GENERIC_PHY
+ default ARCH_FSL_IMX8QXP
+
+config PHY_FSL_IMX8MQ_USB
+ bool
+ depends on OF
+ select GENERIC_PHY
+ default ARCH_FSL_IMX8MQ
+
+config PHY_MIXEL_MIPI_DSI
+ bool
+ depends on OF
+ select GENERIC_PHY
+ default ARCH_FSL_IMX8QM || ARCH_FSL_IMX8QXP
+
endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index a534cf5be07d..969565f7382b 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -60,3 +60,7 @@ obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
+obj-$(CONFIG_PHY_MIXEL_LVDS) += phy-mixel-lvds.o
+obj-$(CONFIG_PHY_MIXEL_LVDS_COMBO) += phy-mixel-lvds-combo.o
+obj-$(CONFIG_PHY_FSL_IMX8MQ_USB) += phy-fsl-imx8mq-usb.o
+obj-$(CONFIG_PHY_MIXEL_MIPI_DSI) += phy-mixel-mipi-dsi.o
diff --git a/drivers/phy/phy-fsl-imx8mq-usb.c b/drivers/phy/phy-fsl-imx8mq-usb.c
new file mode 100644
index 000000000000..113bc5b192e1
--- /dev/null
+++ b/drivers/phy/phy-fsl-imx8mq-usb.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2017 NXP.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+#include <linux/io.h>
+
+#define PHY_CTRL0 0x0
+#define PHY_CTRL0_REF_SSP_EN BIT(2)
+
+#define PHY_CTRL1 0x4
+#define PHY_CTRL1_RESET BIT(0)
+#define PHY_CTRL1_COMMONONN BIT(1)
+#define PHY_CTRL1_ATERESET BIT(3)
+#define PHY_CTRL1_VDATSRCENB0 BIT(19)
+#define PHY_CTRL1_VDATDETENB0 BIT(20)
+
+#define PHY_CTRL2 0x8
+#define PHY_CTRL2_TXENABLEN0 BIT(8)
+
+struct imx8mq_usb_phy {
+ struct phy *phy;
+ struct clk *clk;
+ void __iomem *base;
+};
+
+static int imx8mq_phy_start(struct phy *_phy)
+{
+ struct imx8mq_usb_phy *phy = phy_get_drvdata(_phy);
+
+ return clk_prepare_enable(phy->clk);
+}
+
+static int imx8mq_phy_exit(struct phy *_phy)
+{
+ struct imx8mq_usb_phy *phy = phy_get_drvdata(_phy);
+
+ clk_disable_unprepare(phy->clk);
+
+ return 0;
+}
+
+static struct phy_ops imx8mq_usb_phy_ops = {
+ .init = imx8mq_phy_start,
+ .exit = imx8mq_phy_exit,
+ .owner = THIS_MODULE,
+};
+
+static void imx8mq_usb_phy_init(struct imx8mq_usb_phy *phy)
+{
+ u32 value;
+
+ value = readl(phy->base + PHY_CTRL1);
+ value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0 |
+ PHY_CTRL1_COMMONONN);
+ value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET;
+ writel(value, phy->base + PHY_CTRL1);
+
+ value = readl(phy->base + PHY_CTRL0);
+ value |= PHY_CTRL0_REF_SSP_EN;
+ writel(value, phy->base + PHY_CTRL0);
+
+ value = readl(phy->base + PHY_CTRL2);
+ value |= PHY_CTRL2_TXENABLEN0;
+ writel(value, phy->base + PHY_CTRL2);
+
+ value = readl(phy->base + PHY_CTRL1);
+ value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
+ writel(value, phy->base + PHY_CTRL1);
+}
+
+static int imx8mq_usb_phy_probe(struct platform_device *pdev)
+{
+ struct phy_provider *phy_provider;
+ struct device *dev = &pdev->dev;
+ struct imx8mq_usb_phy *imx_phy;
+ struct resource *res;
+
+ imx_phy = devm_kzalloc(dev, sizeof(*imx_phy), GFP_KERNEL);
+ if (!imx_phy)
+ return -ENOMEM;
+
+ imx_phy->clk = devm_clk_get(dev, "usb_phy_root_clk");
+ if (IS_ERR(imx_phy->clk)) {
+ dev_err(dev, "failed to get imx8mq usb phy clock\n");
+ return PTR_ERR(imx_phy->clk);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ imx_phy->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(imx_phy->base))
+ return PTR_ERR(imx_phy->base);
+
+ imx_phy->phy = devm_phy_create(dev, NULL, &imx8mq_usb_phy_ops);
+ if (IS_ERR(imx_phy->phy))
+ return PTR_ERR(imx_phy->phy);
+
+ phy_set_drvdata(imx_phy->phy, imx_phy);
+
+ imx8mq_usb_phy_init(imx_phy);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id imx8mq_usb_phy_of_match[] = {
+ {.compatible = "fsl,imx8mq-usb-phy",},
+ { },
+};
+MODULE_DEVICE_TABLE(of, imx8mq_usb_phy_of_match);
+
+static struct platform_driver imx8mq_usb_phy_driver = {
+ .probe = imx8mq_usb_phy_probe,
+ .driver = {
+ .name = "imx8mq-usb-phy",
+ .of_match_table = imx8mq_usb_phy_of_match,
+ }
+};
+module_platform_driver(imx8mq_usb_phy_driver);
+
+MODULE_DESCRIPTION("FSL IMX8MQ USB PHY driver");
+MODULE_ALIAS("platform:imx8mq-usb-phy");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/phy-mixel-lvds-combo.c b/drivers/phy/phy-mixel-lvds-combo.c
new file mode 100644
index 000000000000..3b888b110e0d
--- /dev/null
+++ b/drivers/phy/phy-mixel-lvds-combo.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mixel-lvds-combo.h>
+#include <linux/platform_device.h>
+
+/* Control and Status Registers(CSR) */
+#define PHY_CTRL 0x00
+#define CCM(n) (((n) & 0x7) << 5)
+#define CCM_MASK 0xe0
+#define CA(n) (((n) & 0x7) << 2)
+#define CA_MASK 0x1c
+#define RFB BIT(1)
+#define LVDS_EN BIT(0)
+
+#define SS 0x20
+#define CH_HSYNC_M(id) BIT(0 + ((id) * 2))
+#define CH_VSYNC_M(id) BIT(1 + ((id) * 2))
+#define CH_PHSYNC(id) BIT(0 + ((id) * 2))
+#define CH_PVSYNC(id) BIT(1 + ((id) * 2))
+
+#define ULPS 0x30
+#define ULPS_MASK 0x1f
+#define LANE(n) BIT(n)
+
+#define DPI 0x40
+#define COLOR_CODE_MASK 0x7
+#define BIT16_CFG1 0x0
+#define BIT16_CFG2 0x1
+#define BIT16_CFG3 0x2
+#define BIT18_CFG1 0x3
+#define BIT18_CFG2 0x4
+#define BIT24 0x5
+
+/* controller registers */
+#define PD_TX 0x300
+#define PD_PLL 0x31c
+
+struct mixel_lvds_phy {
+ struct device *dev;
+ void __iomem *csr_base;
+ void __iomem *ctrl_base;
+ struct mutex lock;
+ struct phy *phy;
+ struct clk *phy_clk;
+};
+
+static inline u32 phy_csr_read(struct phy *phy, unsigned int reg)
+{
+ struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy);
+
+ return readl(lvds_phy->csr_base + reg);
+}
+
+static inline void phy_csr_write(struct phy *phy, u32 value, unsigned int reg)
+{
+ struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy);
+
+ writel(value, lvds_phy->csr_base + reg);
+}
+
+static inline u32 phy_ctrl_read(struct phy *phy, unsigned int reg)
+{
+ struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy);
+
+ return readl(lvds_phy->ctrl_base + reg);
+}
+
+static inline void phy_ctrl_write(struct phy *phy, u32 value, unsigned int reg)
+{
+ struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy);
+
+ writel(value, lvds_phy->ctrl_base + reg);
+}
+
+void mixel_phy_combo_lvds_set_phy_speed(struct phy *phy,
+ unsigned long phy_clk_rate)
+{
+ struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy);
+
+ /*
+ * To workaround setting clock rate failure issue
+ * when the system resumes back from PM sleep mode,
+ * we need to get the clock rate before setting it's
+ * rate, otherwise, setting the clock rate will fail.
+ */
+ clk_get_rate(lvds_phy->phy_clk);
+ clk_set_rate(lvds_phy->phy_clk, phy_clk_rate);
+}
+EXPORT_SYMBOL_GPL(mixel_phy_combo_lvds_set_phy_speed);
+
+void mixel_phy_combo_lvds_set_hsync_pol(struct phy *phy, bool active_high)
+{
+ struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy);
+ u32 val;
+
+ clk_prepare_enable(lvds_phy->phy_clk);
+ mutex_lock(&lvds_phy->lock);
+ val = phy_csr_read(phy, SS);
+ val &= ~(CH_HSYNC_M(0) | CH_HSYNC_M(1));
+ if (active_high)
+ val |= (CH_PHSYNC(0) | CH_PHSYNC(1));
+ phy_csr_write(phy, val, SS);
+ mutex_unlock(&lvds_phy->lock);
+ clk_disable_unprepare(lvds_phy->phy_clk);
+}
+EXPORT_SYMBOL_GPL(mixel_phy_combo_lvds_set_hsync_pol);
+
+void mixel_phy_combo_lvds_set_vsync_pol(struct phy *phy, bool active_high)
+{
+ struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy);
+ u32 val;
+
+ clk_prepare_enable(lvds_phy->phy_clk);
+ mutex_lock(&lvds_phy->lock);
+ val = phy_csr_read(phy, SS);
+ val &= ~(CH_VSYNC_M(0) | CH_VSYNC_M(1));
+ if (active_high)
+ val |= (CH_PVSYNC(0) | CH_PVSYNC(1));
+ phy_csr_write(phy, val, SS);
+ mutex_unlock(&lvds_phy->lock);
+ clk_disable_unprepare(lvds_phy->phy_clk);
+}
+EXPORT_SYMBOL_GPL(mixel_phy_combo_lvds_set_vsync_pol);
+
+static int mixel_lvds_combo_phy_init(struct phy *phy)
+{
+ struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy);
+ u32 val;
+
+ clk_prepare_enable(lvds_phy->phy_clk);
+ mutex_lock(&lvds_phy->lock);
+ val = phy_csr_read(phy, PHY_CTRL);
+ val &= ~(CCM_MASK | CA_MASK);
+ val |= (CCM(0x5) | CA(0x4) | RFB);
+ phy_csr_write(phy, val, PHY_CTRL);
+
+ val = phy_csr_read(phy, DPI);
+ val &= ~COLOR_CODE_MASK;
+ val |= BIT24;
+ phy_csr_write(phy, val, DPI);
+ mutex_unlock(&lvds_phy->lock);
+ clk_disable_unprepare(lvds_phy->phy_clk);
+
+ return 0;
+}
+
+static int mixel_lvds_combo_phy_power_on(struct phy *phy)
+{
+ struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy);
+ u32 val;
+
+ clk_prepare_enable(lvds_phy->phy_clk);
+ mutex_lock(&lvds_phy->lock);
+ phy_ctrl_write(phy, 0, PD_PLL);
+ phy_ctrl_write(phy, 0, PD_TX);
+
+ val = phy_csr_read(phy, ULPS);
+ val &= ~ULPS_MASK;
+ phy_csr_write(phy, val, ULPS);
+
+ val = phy_csr_read(phy, PHY_CTRL);
+ val |= LVDS_EN;
+ phy_csr_write(phy, val, PHY_CTRL);
+ mutex_unlock(&lvds_phy->lock);
+
+ usleep_range(500, 1000);
+
+ return 0;
+}
+
+static int mixel_lvds_combo_phy_power_off(struct phy *phy)
+{
+ struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy);
+ u32 val;
+
+ mutex_lock(&lvds_phy->lock);
+ val = phy_csr_read(phy, PHY_CTRL);
+ val &= ~LVDS_EN;
+ phy_csr_write(phy, val, PHY_CTRL);
+
+ val = phy_csr_read(phy, ULPS);
+ val |= ULPS_MASK;
+ phy_csr_write(phy, val, ULPS);
+
+ phy_ctrl_write(phy, 1, PD_TX);
+ phy_ctrl_write(phy, 1, PD_PLL);
+ mutex_unlock(&lvds_phy->lock);
+ clk_disable_unprepare(lvds_phy->phy_clk);
+
+ return 0;
+}
+
+static const struct phy_ops mixel_lvds_combo_phy_ops = {
+ .init = mixel_lvds_combo_phy_init,
+ .power_on = mixel_lvds_combo_phy_power_on,
+ .power_off = mixel_lvds_combo_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static int mixel_lvds_combo_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct phy_provider *phy_provider;
+ struct mixel_lvds_phy *lvds_phy;
+
+ lvds_phy = devm_kzalloc(dev, sizeof(*lvds_phy), GFP_KERNEL);
+ if (!lvds_phy)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ lvds_phy->csr_base = devm_ioremap(dev, res->start, SZ_256);
+ if (!lvds_phy->csr_base)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res)
+ return -ENODEV;
+
+ lvds_phy->ctrl_base = devm_ioremap(dev, res->start, SZ_4K);
+ if (!lvds_phy->ctrl_base)
+ return -ENOMEM;
+
+ lvds_phy->phy_clk = devm_clk_get(dev, "phy");
+ if (IS_ERR(lvds_phy->phy_clk)) {
+ dev_err(dev, "cannot get phy clock\n");
+ return PTR_ERR(lvds_phy->phy_clk);
+ }
+
+ lvds_phy->dev = dev;
+ mutex_init(&lvds_phy->lock);
+
+ lvds_phy->phy = devm_phy_create(dev, NULL, &mixel_lvds_combo_phy_ops);
+ if (IS_ERR(lvds_phy->phy)) {
+ dev_err(dev, "failed to create phy\n");
+ return PTR_ERR(lvds_phy->phy);
+ }
+
+ phy_set_drvdata(lvds_phy->phy, lvds_phy);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id mixel_lvds_combo_phy_of_match[] = {
+ { .compatible = "mixel,lvds-combo-phy" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mixel_lvds_combo_phy_of_match);
+
+static struct platform_driver mixel_lvds_combo_phy_driver = {
+ .probe = mixel_lvds_combo_phy_probe,
+ .driver = {
+ .name = "mixel-lvds-combo-phy",
+ .of_match_table = mixel_lvds_combo_phy_of_match,
+ }
+};
+module_platform_driver(mixel_lvds_combo_phy_driver);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("Mixel LVDS combo PHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-mixel-lvds.c b/drivers/phy/phy-mixel-lvds.c
new file mode 100644
index 000000000000..31188884f331
--- /dev/null
+++ b/drivers/phy/phy-mixel-lvds.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mixel-lvds.h>
+#include <linux/platform_device.h>
+
+#define SET 0x4
+#define CLR 0x8
+#define TOG 0xc
+
+#define PHY_CTRL 0x0
+#define M(n) (((n) & 0x3) << 17)
+#define M_MASK 0x60000
+#define CCM(n) (((n) & 0x7) << 14)
+#define CCM_MASK 0x1c000
+#define CA(n) (((n) & 0x7) << 11)
+#define CA_MASK 0x3800
+#define TST(n) (((n) & 0x3f) << 5)
+#define TST_MASK 0x7e0
+#define CH_EN(id) BIT(3 + (id))
+#define NB BIT(2)
+#define RFB BIT(1)
+#define PD BIT(0)
+
+#define PHY_STATUS 0x10
+#define LOCK BIT(0)
+
+#define PHY_SS_CTRL 0x20
+#define CH_HSYNC_M(id) BIT(0 + ((id) * 2))
+#define CH_VSYNC_M(id) BIT(1 + ((id) * 2))
+#define CH_PHSYNC(id) BIT(0 + ((id) * 2))
+#define CH_PVSYNC(id) BIT(1 + ((id) * 2))
+
+struct mixel_lvds_phy {
+ struct phy *phy;
+ unsigned int id;
+};
+
+struct mixel_lvds_phy_priv {
+ struct device *dev;
+ void __iomem *base;
+ struct mutex lock;
+ struct clk *phy_clk;
+ struct mixel_lvds_phy *phys[2];
+};
+
+static inline u32 phy_read(struct phy *phy, unsigned int reg)
+{
+ struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent);
+
+ return readl(priv->base + reg);
+}
+
+static inline void phy_write(struct phy *phy, u32 value, unsigned int reg)
+{
+ struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent);
+
+ writel(value, priv->base + reg);
+}
+
+void mixel_phy_lvds_set_phy_speed(struct phy *phy, unsigned long phy_clk_rate)
+{
+ struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent);
+ u32 val;
+
+ /* assuming NB is zero - 7bits per channel */
+ clk_prepare_enable(priv->phy_clk);
+ mutex_lock(&priv->lock);
+ val = phy_read(phy, PHY_CTRL);
+ val &= ~M_MASK;
+ if (phy_clk_rate < 44000000)
+ val |= M(0x2);
+ else if (phy_clk_rate < 90000000)
+ val |= M(0x1);
+ else
+ val |= M(0x0);
+ phy_write(phy, val, PHY_CTRL);
+ mutex_unlock(&priv->lock);
+ clk_disable_unprepare(priv->phy_clk);
+
+ /*
+ * To workaround setting clock rate failure issue
+ * when the system resumes back from PM sleep mode,
+ * we need to get the clock rate before setting it's
+ * rate, otherwise, setting the clock rate will fail.
+ */
+ clk_get_rate(priv->phy_clk);
+ clk_set_rate(priv->phy_clk, phy_clk_rate);
+}
+EXPORT_SYMBOL_GPL(mixel_phy_lvds_set_phy_speed);
+
+void mixel_phy_lvds_set_hsync_pol(struct phy *phy, bool active_high)
+{
+ struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent);
+ struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy);
+ unsigned int id = lvds_phy->id;
+ u32 val;
+
+ clk_prepare_enable(priv->phy_clk);
+ mutex_lock(&priv->lock);
+ val = phy_read(phy, PHY_SS_CTRL);
+ val &= ~CH_HSYNC_M(id);
+ if (active_high)
+ val |= CH_PHSYNC(id);
+ phy_write(phy, val, PHY_SS_CTRL);
+ mutex_unlock(&priv->lock);
+ clk_disable_unprepare(priv->phy_clk);
+}
+EXPORT_SYMBOL_GPL(mixel_phy_lvds_set_hsync_pol);
+
+void mixel_phy_lvds_set_vsync_pol(struct phy *phy, bool active_high)
+{
+ struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent);
+ struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy);
+ unsigned int id = lvds_phy->id;
+ u32 val;
+
+ clk_prepare_enable(priv->phy_clk);
+ mutex_lock(&priv->lock);
+ val = phy_read(phy, PHY_SS_CTRL);
+ val &= ~CH_VSYNC_M(id);
+ if (active_high)
+ val |= CH_PVSYNC(id);
+ phy_write(phy, val, PHY_SS_CTRL);
+ mutex_unlock(&priv->lock);
+ clk_disable_unprepare(priv->phy_clk);
+}
+EXPORT_SYMBOL_GPL(mixel_phy_lvds_set_vsync_pol);
+
+static int mixel_lvds_phy_init(struct phy *phy)
+{
+ struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent);
+ u32 val;
+
+ clk_prepare_enable(priv->phy_clk);
+ mutex_lock(&priv->lock);
+ val = phy_read(phy, PHY_CTRL);
+ val &= ~(M_MASK | CCM_MASK | CA_MASK | TST_MASK | NB | PD);
+ val |= (M(0x0) | CCM(0x5) | CA(0x4) | TST(0x25) | RFB);
+ phy_write(phy, val, PHY_CTRL);
+ mutex_unlock(&priv->lock);
+ clk_disable_unprepare(priv->phy_clk);
+
+ return 0;
+}
+
+static int mixel_lvds_phy_power_on(struct phy *phy)
+{
+ struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent);
+ struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy);
+ unsigned int id = lvds_phy->id;
+
+ clk_prepare_enable(priv->phy_clk);
+
+ mutex_lock(&priv->lock);
+ phy_write(phy, CH_EN(id), PHY_CTRL + SET);
+ mutex_unlock(&priv->lock);
+
+ usleep_range(500, 1000);
+
+ return 0;
+}
+
+static int mixel_lvds_phy_power_off(struct phy *phy)
+{
+ struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent);
+ struct mixel_lvds_phy *lvds_phy = phy_get_drvdata(phy);
+ unsigned int id = lvds_phy->id;
+
+ mutex_lock(&priv->lock);
+ phy_write(phy, CH_EN(id), PHY_CTRL + CLR);
+ mutex_unlock(&priv->lock);
+
+ clk_disable_unprepare(priv->phy_clk);
+
+ return 0;
+}
+
+static const struct phy_ops mixel_lvds_phy_ops = {
+ .init = mixel_lvds_phy_init,
+ .power_on = mixel_lvds_phy_power_on,
+ .power_off = mixel_lvds_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static int mixel_lvds_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *child;
+ struct resource *res;
+ struct phy_provider *phy_provider;
+ struct mixel_lvds_phy_priv *priv;
+ struct mixel_lvds_phy *lvds_phy;
+ struct phy *phy;
+ u32 phy_id;
+ int ret;
+
+ if (!np)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base = devm_ioremap(dev, res->start, SZ_256);
+ if (!priv->base)
+ return -ENOMEM;
+
+ priv->dev = dev;
+
+ priv->phy_clk = devm_clk_get(dev, "phy");
+ if (IS_ERR(priv->phy_clk)) {
+ dev_err(dev, "cannot get phy clock\n");
+ return PTR_ERR(priv->phy_clk);
+ }
+
+ mutex_init(&priv->lock);
+ dev_set_drvdata(dev, priv);
+
+ for_each_available_child_of_node(np, child) {
+ if (of_property_read_u32(child, "reg", &phy_id)) {
+ dev_err(dev, "missing reg property in node %s\n",
+ child->name);
+ ret = -EINVAL;
+ goto put_child;
+ }
+
+ if (phy_id >= ARRAY_SIZE(priv->phys)) {
+ dev_err(dev, "invalid reg in node %s\n", child->name);
+ ret = -EINVAL;
+ goto put_child;
+ }
+
+ if (priv->phys[phy_id]) {
+ dev_err(dev, "duplicated phy id: %u\n", phy_id);
+ ret = -EINVAL;
+ goto put_child;
+ }
+
+ lvds_phy = devm_kzalloc(dev, sizeof(*lvds_phy), GFP_KERNEL);
+ if (!lvds_phy) {
+ ret = -ENOMEM;
+ goto put_child;
+ }
+
+ phy = devm_phy_create(dev, child, &mixel_lvds_phy_ops);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "failed to create phy\n");
+ ret = PTR_ERR(phy);
+ goto put_child;
+ }
+
+ lvds_phy->phy = phy;
+ lvds_phy->id = phy_id;
+ priv->phys[phy_id] = lvds_phy;
+
+ phy_set_drvdata(phy, lvds_phy);
+ }
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+
+put_child:
+ of_node_put(child);
+ return ret;
+}
+
+static const struct of_device_id mixel_lvds_phy_of_match[] = {
+ { .compatible = "mixel,lvds-phy" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mixel_lvds_phy_of_match);
+
+static struct platform_driver mixel_lvds_phy_driver = {
+ .probe = mixel_lvds_phy_probe,
+ .driver = {
+ .name = "mixel-lvds-phy",
+ .of_match_table = mixel_lvds_phy_of_match,
+ }
+};
+module_platform_driver(mixel_lvds_phy_driver);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("Mixel LVDS PHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-mixel-mipi-dsi.c b/drivers/phy/phy-mixel-mipi-dsi.c
new file mode 100644
index 000000000000..2966d4bf03e0
--- /dev/null
+++ b/drivers/phy/phy-mixel-mipi-dsi.c
@@ -0,0 +1,538 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy-mixel-mipi-dsi.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <soc/imx8/sc/sci.h>
+
+#define DPHY_PD_DPHY 0x00
+#define DPHY_M_PRG_HS_PREPARE 0x04
+#define DPHY_MC_PRG_HS_PREPARE 0x08
+#define DPHY_M_PRG_HS_ZERO 0x0c
+#define DPHY_MC_PRG_HS_ZERO 0x10
+#define DPHY_M_PRG_HS_TRAIL 0x14
+#define DPHY_MC_PRG_HS_TRAIL 0x18
+#define DPHY_PD_PLL 0x1c
+#define DPHY_TST 0x20
+#define DPHY_CN 0x24
+#define DPHY_CM 0x28
+#define DPHY_CO 0x2c
+#define DPHY_LOCK 0x30
+#define DPHY_LOCK_BYP 0x34
+
+#define MBPS(x) ((x) * 1000000)
+
+#define DATA_RATE_MAX_SPEED MBPS(1500)
+#define DATA_RATE_MIN_SPEED MBPS(80)
+
+#define CN_BUF 0xcb7a89c0
+#define CO_BUF 0x63
+#define CM(x) ( \
+ ((x) < 32)?0xe0|((x)-16) : \
+ ((x) < 64)?0xc0|((x)-32) : \
+ ((x) < 128)?0x80|((x)-64) : \
+ ((x) - 128))
+#define CN(x) (((x) == 1)?0x1f : (((CN_BUF)>>((x)-1))&0x1f))
+#define CO(x) ((CO_BUF)>>(8-(x))&0x3)
+
+/* PHY power on is LOW_ENABLE */
+#define PWR_ON 0
+#define PWR_OFF 1
+
+struct pll_divider {
+ u32 cm;
+ u32 cn;
+ u32 co;
+};
+
+struct devtype {
+ bool have_sc;
+ u8 reg_tx_rcal;
+ u8 reg_auto_pd_en;
+ u8 reg_rxlprp;
+ u8 reg_rxcdrp;
+ u8 reg_rxhs_settle;
+ u8 reg_bypass_pll;
+};
+
+struct mixel_mipi_phy_priv {
+ struct device *dev;
+ void __iomem *base;
+ const struct devtype *plat_data;
+ sc_rsrc_t mipi_id;
+ struct pll_divider divider;
+ struct mutex lock;
+ unsigned long data_rate;
+};
+
+
+static inline u32 phy_read(struct phy *phy, unsigned int reg)
+{
+ struct mixel_mipi_phy_priv *priv = phy_get_drvdata(phy);
+
+ return readl(priv->base + reg);
+}
+
+static inline void phy_write(struct phy *phy, u32 value, unsigned int reg)
+{
+ struct mixel_mipi_phy_priv *priv = phy_get_drvdata(phy);
+
+ writel(value, priv->base + reg);
+}
+
+/*
+ * mixel_phy_mipi_set_phy_speed:
+ * Input params:
+ * bit_clk: PHY PLL needed output clock
+ * ref_clk: reference input clock for the PHY PLL
+ *
+ * Returns:
+ * 0: if the bit_clk can be achieved for the given ref_clk
+ * -EINVAL: otherwise
+ */
+int mixel_phy_mipi_set_phy_speed(struct phy *phy,
+ unsigned long bit_clk,
+ unsigned long ref_clk,
+ bool best_match)
+{
+ struct mixel_mipi_phy_priv *priv = dev_get_drvdata(phy->dev.parent);
+ u32 div_rate;
+ u32 numerator = 0;
+ u32 denominator = 1;
+
+ if (bit_clk > DATA_RATE_MAX_SPEED || bit_clk < DATA_RATE_MIN_SPEED)
+ return -EINVAL;
+
+ /* simulated fixed point with 3 decimals */
+ div_rate = (bit_clk * 1000) / ref_clk;
+
+ while (denominator <= 256) {
+ if (div_rate % 1000 == 0)
+ numerator = div_rate / 1000;
+ if (numerator > 15)
+ break;
+ denominator = denominator << 1;
+ div_rate = div_rate << 1;
+ }
+
+ /* CM ranges between 16 and 255 */
+ /* CN ranges between 1 and 32 */
+ /* CO is power of 2: 1, 2, 4, 8 */
+ if (best_match && numerator < 16)
+ numerator = div_rate / 1000;
+
+ if (best_match && numerator > 255) {
+ while (numerator > 255 && denominator > 1) {
+ numerator = DIV_ROUND_UP(numerator, 2);
+ denominator = denominator >> 1;
+ }
+ }
+
+ if (numerator < 16 || numerator > 255)
+ return -EINVAL;
+
+ if (best_match)
+ numerator = DIV_ROUND_UP(numerator, denominator) * denominator;
+
+ priv->divider.cn = 1;
+ if (denominator > 8) {
+ priv->divider.cn = denominator >> 3;
+ denominator = 8;
+ }
+ priv->divider.co = denominator;
+ priv->divider.cm = numerator;
+
+ priv->data_rate = bit_clk;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mixel_phy_mipi_set_phy_speed);
+
+static int mixel_mipi_phy_enable(struct phy *phy, u32 reset)
+{
+ struct mixel_mipi_phy_priv *priv = phy_get_drvdata(phy);
+ sc_err_t sci_err = 0;
+ sc_ipc_t ipc_handle = 0;
+ u32 mu_id;
+
+ sci_err = sc_ipc_getMuID(&mu_id);
+ if (sci_err != SC_ERR_NONE) {
+ dev_err(&phy->dev, "Failed to get MU ID (%d)\n", sci_err);
+ return -ENODEV;
+ }
+ sci_err = sc_ipc_open(&ipc_handle, mu_id);
+ if (sci_err != SC_ERR_NONE) {
+ dev_err(&phy->dev, "Failed to open IPC (%d)\n", sci_err);
+ return -ENODEV;
+ }
+
+ sci_err = sc_misc_set_control(ipc_handle,
+ priv->mipi_id,
+ SC_C_PHY_RESET,
+ reset);
+ if (sci_err != SC_ERR_NONE) {
+ dev_err(&phy->dev, "Failed to reset DPHY (%d)\n", sci_err);
+ sc_ipc_close(ipc_handle);
+ return -ENODEV;
+ }
+
+ sc_ipc_close(ipc_handle);
+
+ return 0;
+}
+
+/*
+ * We tried our best here to use the values as specified in
+ * Reference Manual, but we got unstable results. So, these values
+ * are hacked from their original explanation as found in RM.
+ */
+static void mixel_phy_set_prg_regs(struct phy *phy)
+{
+ struct mixel_mipi_phy_priv *priv = phy_get_drvdata(phy);
+ unsigned int hs_reg;
+
+ /* MC_PRG_HS_PREPARE = 1.0 * Ttxescape if DPHY_MC_PRG_HS_PREPARE = 0
+ *
+ * MC_PRG_HS_PREPARE = 1.5 * Ttxescape if DPHY_MC_PRG_HS_PREPARE = 1
+ *
+ * Assume Ftxescape is 18-20 MHz with DPHY_MC_PRG_HS_PREPARE = 0,
+ * this gives 55-50 ns.
+ * The specification is 38 to 95 ns.
+ */
+ phy_write(phy, 0x00, DPHY_MC_PRG_HS_PREPARE);
+
+ /* PRG_HS_PREPARE
+ * for PRG_HS_PREPARE = 00, THS-PREPARE = 1 * TxClkEsc Period
+ * PRG_HS_PREPARE = 01, THS-PREPARE = 1.5 * TxClkEsc Period
+ * PRG_HS_PREPARE = 10, THS-PREPARE = 2 * TxClkEsc Period
+ * PRG_HS_PREPARE = 11, THS-PREPARE = 2.5 * TxClkEsc Period
+ *
+ * The specification for THS-PREPARE is
+ * Min (40ns + 4*UI)
+ * Max 85ns +6*UI
+ */
+ if (priv->data_rate <= MBPS(61))
+ phy_write(phy, 0x03, DPHY_M_PRG_HS_PREPARE);
+ else if (priv->data_rate <= MBPS(90))
+ phy_write(phy, 0x02, DPHY_M_PRG_HS_PREPARE);
+ else if (priv->data_rate <= MBPS(500))
+ phy_write(phy, 0x01, DPHY_M_PRG_HS_PREPARE);
+ else
+ phy_write(phy, 0x00, DPHY_M_PRG_HS_PREPARE);
+
+ /* MC_PRG_HS_ZERO
+ *
+ * T-CLK-ZERO = ( MC_PRG_HS_ZERO + 3) * (TxByteClkHS Period)
+ *
+ * The minimum specification for THS-PREPARE is 262 ns.
+ *
+ */
+ hs_reg =
+ /* simplified equation y = .034x - 2.5
+ *
+ * This a linear interpolation of the values from the
+ * PHY user guide
+ */
+ (34 * (priv->data_rate/1000000) - 2500) / 1000;
+
+ if (hs_reg < 1)
+ hs_reg = 1;
+ phy_write(phy, hs_reg, DPHY_MC_PRG_HS_ZERO);
+
+ /* M_PRG_HS_ZERO
+ *
+ * TT-HS-ZERO =(M_PRG_HS_ZERO + 6) * (TxByteClkHS Period)
+ *
+ * The minimum specification for THS-ZERO 105ns + 6*UI.
+ *
+ */
+ hs_reg =
+ /* simplified equation y = .0144x - 4.75
+ *
+ * This a linear interpolation of the values from the
+ * PHY user guide
+ */
+
+ (144 * (priv->data_rate/1000000) - 47500) / 10000;
+
+ if (hs_reg < 1)
+ hs_reg = 1;
+ phy_write(phy, hs_reg, DPHY_M_PRG_HS_ZERO);
+
+ /* MC_PRG_HS_TRAIL and M_PRG_HS_TRAIL
+ *
+ * THS-TRAIL =(PRG_HS_TRAIL) * (TxByteClkHS Period)
+ *
+ * The specification for THS-TRAIL is
+ * Min (60ns + 4*UI)
+ * Typical (82.5ns + 8*UI)
+ * Max (105ns + 12*UI)
+ *
+ */
+
+ hs_reg =
+ /* simplified equation y = .0103x + 1
+ *
+ * This a linear interpolation of the values from the
+ * PHY user guide
+ */
+ (103 * (priv->data_rate/1000000) + 10000) / 10000;
+
+ if (hs_reg > 15)
+ hs_reg = 15;
+ if (hs_reg < 1)
+ hs_reg = 1;
+
+ phy_write(phy, hs_reg, DPHY_MC_PRG_HS_TRAIL);
+ phy_write(phy, hs_reg, DPHY_M_PRG_HS_TRAIL);
+
+ /* M_PRG_RXHS_SETTLE */
+ if (priv->plat_data->reg_rxhs_settle == 0xFF)
+ return;
+ if (priv->data_rate < MBPS(80))
+ phy_write(phy, 0x0d, priv->plat_data->reg_rxhs_settle);
+ else if (priv->data_rate < MBPS(90))
+ phy_write(phy, 0x0c, priv->plat_data->reg_rxhs_settle);
+ else if (priv->data_rate < MBPS(125))
+ phy_write(phy, 0x0b, priv->plat_data->reg_rxhs_settle);
+ else if (priv->data_rate < MBPS(150))
+ phy_write(phy, 0x0a, priv->plat_data->reg_rxhs_settle);
+ else if (priv->data_rate < MBPS(225))
+ phy_write(phy, 0x09, priv->plat_data->reg_rxhs_settle);
+ else if (priv->data_rate < MBPS(500))
+ phy_write(phy, 0x08, priv->plat_data->reg_rxhs_settle);
+ else
+ phy_write(phy, 0x07, priv->plat_data->reg_rxhs_settle);
+
+}
+
+static int mixel_mipi_phy_init(struct phy *phy)
+{
+ struct mixel_mipi_phy_priv *priv = dev_get_drvdata(phy->dev.parent);
+
+ mutex_lock(&priv->lock);
+
+ phy_write(phy, PWR_OFF, DPHY_PD_PLL);
+ phy_write(phy, PWR_OFF, DPHY_PD_DPHY);
+
+ mixel_phy_set_prg_regs(phy);
+
+ phy_write(phy, 0x00, DPHY_LOCK_BYP);
+ if (priv->plat_data->reg_tx_rcal != 0xFF)
+ phy_write(phy, 0x01, priv->plat_data->reg_tx_rcal);
+ if (priv->plat_data->reg_auto_pd_en != 0xFF)
+ phy_write(phy, 0x00, priv->plat_data->reg_auto_pd_en);
+ if (priv->plat_data->reg_rxlprp != 0xFF)
+ phy_write(phy, 0x02, priv->plat_data->reg_rxlprp);
+ if (priv->plat_data->reg_rxcdrp != 0xFF)
+ phy_write(phy, 0x02, priv->plat_data->reg_rxcdrp);
+ phy_write(phy, 0x25, DPHY_TST);
+
+ /* VCO = REF_CLK * CM / CN * CO */
+ if (priv->divider.cm < 16 || priv->divider.cm > 255 ||
+ priv->divider.cn < 1 || priv->divider.cn > 32 ||
+ priv->divider.co < 1 || priv->divider.co > 8) {
+ dev_err(&phy->dev, "Invalid CM/CN/CO values! (%u/%u/%u)\n",
+ priv->divider.cm, priv->divider.cn, priv->divider.co);
+ mutex_unlock(&priv->lock);
+ return -EINVAL;
+ }
+ dev_dbg(&phy->dev, "Using CM:%u CN:%u CO:%u\n",
+ priv->divider.cm, priv->divider.cn, priv->divider.co);
+ phy_write(phy, CM(priv->divider.cm), DPHY_CM);
+ phy_write(phy, CN(priv->divider.cn), DPHY_CN);
+ phy_write(phy, CO(priv->divider.co), DPHY_CO);
+
+ mutex_unlock(&priv->lock);
+
+ return 0;
+}
+
+static int mixel_mipi_phy_exit(struct phy *phy)
+{
+ phy_write(phy, 0, DPHY_CM);
+ phy_write(phy, 0, DPHY_CN);
+ phy_write(phy, 0, DPHY_CO);
+
+ return 0;
+}
+
+static int mixel_mipi_phy_power_on(struct phy *phy)
+{
+ struct mixel_mipi_phy_priv *priv = phy_get_drvdata(phy);
+ u32 lock, timeout;
+ int ret = 0;
+
+ mutex_lock(&priv->lock);
+
+ phy_write(phy, PWR_ON, DPHY_PD_PLL);
+
+ timeout = 100;
+ while (!(lock = phy_read(phy, DPHY_LOCK))) {
+ udelay(10);
+ if (--timeout == 0) {
+ dev_err(&phy->dev, "Could not get DPHY lock!\n");
+ phy_write(phy, PWR_OFF, DPHY_PD_PLL);
+ mutex_unlock(&priv->lock);
+ return -EINVAL;
+ }
+ }
+ dev_dbg(&phy->dev, "DPHY lock acquired after %d tries\n",
+ (100 - timeout));
+
+ phy_write(phy, PWR_ON, DPHY_PD_DPHY);
+
+ if (priv->plat_data->have_sc)
+ ret = mixel_mipi_phy_enable(phy, 1);
+
+ mutex_unlock(&priv->lock);
+
+ return ret;
+}
+
+static int mixel_mipi_phy_power_off(struct phy *phy)
+{
+ struct mixel_mipi_phy_priv *priv = phy_get_drvdata(phy);
+ int ret = 0;
+
+ mutex_lock(&priv->lock);
+
+ phy_write(phy, PWR_OFF, DPHY_PD_PLL);
+ phy_write(phy, PWR_OFF, DPHY_PD_DPHY);
+
+ if (priv->plat_data->have_sc)
+ ret = mixel_mipi_phy_enable(phy, 0);
+
+ mutex_unlock(&priv->lock);
+
+ return ret;
+}
+
+static const struct phy_ops mixel_mipi_phy_ops = {
+ .init = mixel_mipi_phy_init,
+ .exit = mixel_mipi_phy_exit,
+ .power_on = mixel_mipi_phy_power_on,
+ .power_off = mixel_mipi_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static struct devtype imx8qm_dev = {
+ .have_sc = true,
+ .reg_tx_rcal = 0xFF,
+ .reg_auto_pd_en = 0x38,
+ .reg_rxlprp = 0x3c,
+ .reg_rxcdrp = 0x40,
+ .reg_rxhs_settle = 0x44,
+ .reg_bypass_pll = 0xFF,
+};
+static struct devtype imx8qxp_dev = {
+ .have_sc = true,
+ .reg_tx_rcal = 0xFF,
+ .reg_auto_pd_en = 0x38,
+ .reg_rxlprp = 0x3c,
+ .reg_rxcdrp = 0x40,
+ .reg_rxhs_settle = 0x44,
+ .reg_bypass_pll = 0xFF,
+};
+static struct devtype imx8mq_dev = {
+ .have_sc = false,
+ .reg_tx_rcal = 0x38,
+ .reg_auto_pd_en = 0x3c,
+ .reg_rxlprp = 0x40,
+ .reg_rxcdrp = 0x44,
+ .reg_rxhs_settle = 0x48,
+ .reg_bypass_pll = 0x4c,
+};
+
+static const struct of_device_id mixel_mipi_phy_of_match[] = {
+ { .compatible = "mixel,imx8qm-mipi-dsi-phy", .data = &imx8qm_dev },
+ { .compatible = "mixel,imx8qxp-mipi-dsi-phy", .data = &imx8qxp_dev },
+ { .compatible = "mixel,imx8mq-mipi-dsi-phy", .data = &imx8mq_dev },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mixel_mipi_phy_of_match);
+
+static int mixel_mipi_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ const struct of_device_id *of_id =
+ of_match_device(mixel_mipi_phy_of_match, dev);
+ struct phy_provider *phy_provider;
+ struct mixel_mipi_phy_priv *priv;
+ struct resource *res;
+ struct phy *phy;
+ int phy_id = 0;
+
+ if (!np)
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ priv->base = devm_ioremap(dev, res->start, SZ_256);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->plat_data = of_id->data;
+
+ phy_id = of_alias_get_id(np, "dsi_phy");
+ if (phy_id < 0) {
+ dev_err(dev, "No dsi_phy alias found!");
+ return phy_id;
+ }
+
+ priv->mipi_id = phy_id?SC_R_MIPI_1:SC_R_MIPI_0;
+
+ priv->dev = dev;
+
+ mutex_init(&priv->lock);
+ dev_set_drvdata(dev, priv);
+
+ phy = devm_phy_create(dev, np, &mixel_mipi_phy_ops);
+ if (IS_ERR(phy)) {
+ dev_err(dev, "Failed to create phy\n");
+ return PTR_ERR(phy);
+ }
+ phy_set_drvdata(phy, priv);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static struct platform_driver mixel_mipi_phy_driver = {
+ .probe = mixel_mipi_phy_probe,
+ .driver = {
+ .name = "mixel-mipi-dsi-phy",
+ .of_match_table = mixel_mipi_phy_of_match,
+ }
+};
+module_platform_driver(mixel_mipi_phy_driver);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("Mixel MIPI-DSI PHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
index 54dad89fc9bf..1f890267cb72 100644
--- a/drivers/pinctrl/devicetree.c
+++ b/drivers/pinctrl/devicetree.c
@@ -18,6 +18,7 @@
#include <linux/device.h>
#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/slab.h>
@@ -166,6 +167,43 @@ static int dt_remember_dummy_state(struct pinctrl *p, const char *statename)
return dt_remember_or_free_map(p, statename, NULL, map, 1);
}
+static int dt_gpio_assert_pinctrl(struct pinctrl *p)
+{
+ struct device_node *np = p->dev->of_node;
+ enum of_gpio_flags flags;
+ int gpio;
+ int index = 0;
+ int ret;
+
+ if (!of_find_property(np, "pinctrl-assert-gpios", NULL))
+ return 0; /* Missing the property, so nothing to be done */
+
+ for (;; index++) {
+ gpio = of_get_named_gpio_flags(np, "pinctrl-assert-gpios",
+ index, &flags);
+ if (gpio < 0)
+ break; /* End of the phandle list */
+
+ if (!gpio_is_valid(gpio))
+ return -EINVAL;
+
+ ret = devm_gpio_request_one(p->dev, gpio, GPIOF_OUT_INIT_LOW,
+ NULL);
+ if (ret < 0)
+ return ret;
+
+ if (flags & OF_GPIO_ACTIVE_LOW)
+ continue;
+
+ if (gpio_cansleep(gpio))
+ gpio_set_value_cansleep(gpio, 1);
+ else
+ gpio_set_value(gpio, 1);
+ }
+
+ return 0;
+}
+
int pinctrl_dt_to_map(struct pinctrl *p)
{
struct device_node *np = p->dev->of_node;
@@ -186,6 +224,12 @@ int pinctrl_dt_to_map(struct pinctrl *p)
return 0;
}
+ ret = dt_gpio_assert_pinctrl(p);
+ if (ret) {
+ dev_dbg(p->dev, "failed to assert pinctrl setting: %d\n", ret);
+ return ret;
+ }
+
/* We may store pointers to property names within the node */
of_node_get(np);
diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
index fc8cbf611723..6333d33b1e14 100644
--- a/drivers/pinctrl/freescale/Kconfig
+++ b/drivers/pinctrl/freescale/Kconfig
@@ -4,6 +4,12 @@ config PINCTRL_IMX
select PINCONF
select REGMAP
+config PINCTRL_IMX_SCU
+ bool
+
+config PINCTRL_IMX_MEMMAP
+ bool
+
config PINCTRL_IMX1_CORE
bool
select PINMUX
@@ -36,6 +42,7 @@ config PINCTRL_IMX25
depends on OF
depends on SOC_IMX25
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx25 pinctrl driver
@@ -43,6 +50,7 @@ config PINCTRL_IMX35
bool "IMX35 pinctrl driver"
depends on SOC_IMX35
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx35 pinctrl driver
@@ -50,6 +58,7 @@ config PINCTRL_IMX50
bool "IMX50 pinctrl driver"
depends on SOC_IMX50
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx50 pinctrl driver
@@ -57,6 +66,7 @@ config PINCTRL_IMX51
bool "IMX51 pinctrl driver"
depends on SOC_IMX51
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx51 pinctrl driver
@@ -64,6 +74,7 @@ config PINCTRL_IMX53
bool "IMX53 pinctrl driver"
depends on SOC_IMX53
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx53 pinctrl driver
@@ -71,6 +82,7 @@ config PINCTRL_IMX6Q
bool "IMX6Q/DL pinctrl driver"
depends on SOC_IMX6Q
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx6q/dl pinctrl driver
@@ -78,6 +90,7 @@ config PINCTRL_IMX6SL
bool "IMX6SL pinctrl driver"
depends on SOC_IMX6SL
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx6sl pinctrl driver
@@ -85,6 +98,7 @@ config PINCTRL_IMX6SX
bool "IMX6SX pinctrl driver"
depends on SOC_IMX6SX
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx6sx pinctrl driver
@@ -92,20 +106,71 @@ config PINCTRL_IMX6UL
bool "IMX6UL pinctrl driver"
depends on SOC_IMX6UL
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx6ul pinctrl driver
+config PINCTRL_IMX6SLL
+ bool "IMX6SLL pinctrl driver"
+ depends on SOC_IMX6SLL
+ select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
+ help
+ Say Y here to enable the imx6sll pinctrl driver
+
config PINCTRL_IMX7D
bool "IMX7D pinctrl driver"
depends on SOC_IMX7D
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the imx7d pinctrl driver
+config PINCTRL_IMX7ULP
+ bool "IMX7ULP pinctrl driver"
+ depends on SOC_IMX7ULP
+ select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
+ help
+ Say Y here to enable the imx7ulp pinctrl driver
+
+config PINCTRL_IMX8QM
+ bool "IMX8QM pinctrl driver"
+ depends on ARCH_FSL_IMX8QM
+ select PINCTRL_IMX
+ select PINCTRL_IMX_SCU
+ help
+ Say Y here to enable the imx8qm pinctrl driver
+
+config PINCTRL_IMX8QXP
+ bool "IMX8QXP pinctrl driver"
+ depends on ARCH_FSL_IMX8QXP
+ select PINCTRL_IMX
+ select PINCTRL_IMX_SCU
+ help
+ Say Y here to enable the imx8qxp pinctrl driver
+
+config PINCTRL_IMX8MQ
+ bool "IMX8MQ pinctrl driver"
+ depends on ARCH_FSL_IMX8MQ
+ select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
+ help
+ Say Y here to enable the imx8mq pinctrl driver
+
+config PINCTRL_IMX8MM
+ bool "IMX8MM pinctrl driver"
+ depends on ARCH_FSL_IMX8MM
+ select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
+ help
+ Say Y here to enable the imx8mm pinctrl driver
+
config PINCTRL_VF610
bool "Freescale Vybrid VF610 pinctrl driver"
depends on SOC_VF610
select PINCTRL_IMX
+ select PINCTRL_IMX_MEMMAP
help
Say Y here to enable the Freescale Vybrid VF610 pinctrl driver
diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile
index d44c9e253f21..0b547020a853 100644
--- a/drivers/pinctrl/freescale/Makefile
+++ b/drivers/pinctrl/freescale/Makefile
@@ -1,5 +1,7 @@
# Freescale pin control drivers
obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o
+obj-$(CONFIG_PINCTRL_IMX_MEMMAP)+= pinctrl-memmap.o
+obj-$(CONFIG_PINCTRL_IMX_SCU) += pinctrl-scu.o
obj-$(CONFIG_PINCTRL_IMX1_CORE) += pinctrl-imx1-core.o
obj-$(CONFIG_PINCTRL_IMX1) += pinctrl-imx1.o
obj-$(CONFIG_PINCTRL_IMX21) += pinctrl-imx21.o
@@ -13,7 +15,13 @@ obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6dl.o
obj-$(CONFIG_PINCTRL_IMX6SL) += pinctrl-imx6sl.o
obj-$(CONFIG_PINCTRL_IMX6SX) += pinctrl-imx6sx.o
obj-$(CONFIG_PINCTRL_IMX6UL) += pinctrl-imx6ul.o
+obj-$(CONFIG_PINCTRL_IMX6SLL) += pinctrl-imx6sll.o
obj-$(CONFIG_PINCTRL_IMX7D) += pinctrl-imx7d.o
+obj-$(CONFIG_PINCTRL_IMX7ULP) += pinctrl-imx7ulp.o
+obj-$(CONFIG_PINCTRL_IMX8QM) += pinctrl-imx8qm.o
+obj-$(CONFIG_PINCTRL_IMX8QXP) += pinctrl-imx8qxp.o
+obj-$(CONFIG_PINCTRL_IMX8MQ) += pinctrl-imx8mq.o
+obj-$(CONFIG_PINCTRL_IMX8MM) += pinctrl-imx8mm.o
obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o
obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o
obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o
diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c
index 5ef7e875b50e..41574d9a432f 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx.c
@@ -31,19 +31,6 @@
/* The bits in CONFIG cell defined in binding doc*/
#define IMX_NO_PAD_CTL 0x80000000 /* no pin config need */
-#define IMX_PAD_SION 0x40000000 /* set SION */
-
-/**
- * @dev: a pointer back to containing device
- * @base: the offset to the controller in virtual memory
- */
-struct imx_pinctrl {
- struct device *dev;
- struct pinctrl_dev *pctl;
- void __iomem *base;
- void __iomem *input_sel_base;
- const struct imx_pinctrl_soc_info *info;
-};
static inline const struct imx_pin_group *imx_pinctrl_find_group_by_name(
const struct imx_pinctrl_soc_info *info,
@@ -124,9 +111,14 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
return -EINVAL;
}
- for (i = 0; i < grp->npins; i++) {
- if (!(grp->pins[i].config & IMX_NO_PAD_CTL))
- map_num++;
+ if (info->flags & IMX8_USE_SCU) {
+ map_num += grp->npins;
+ } else {
+ for (i = 0; i < grp->npins; i++) {
+ if (!(grp->pins[i].pin_conf.pin_memmap.config &
+ IMX_NO_PAD_CTL))
+ map_num++;
+ }
}
new_map = kmalloc(sizeof(struct pinctrl_map) * map_num, GFP_KERNEL);
@@ -150,11 +142,20 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
/* create config map */
new_map++;
for (i = j = 0; i < grp->npins; i++) {
- if (!(grp->pins[i].config & IMX_NO_PAD_CTL)) {
+ if (info->flags & IMX8_USE_SCU) {
new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
new_map[j].data.configs.group_or_pin =
pin_get_name(pctldev, grp->pins[i].pin);
- new_map[j].data.configs.configs = &grp->pins[i].config;
+ new_map[j].data.configs.configs =
+ (unsigned long *)&grp->pins[i].pin_conf.pin_scu.mux;
+ new_map[j].data.configs.num_configs = 2;
+ j++;
+ } else if (!(grp->pins[i].pin_conf.pin_memmap.config & IMX_NO_PAD_CTL)) {
+ new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
+ new_map[j].data.configs.group_or_pin =
+ pin_get_name(pctldev, grp->pins[i].pin);
+ new_map[j].data.configs.configs =
+ &grp->pins[i].pin_conf.pin_memmap.config;
new_map[j].data.configs.num_configs = 1;
j++;
}
@@ -187,9 +188,8 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
{
struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
const struct imx_pinctrl_soc_info *info = ipctl->info;
- const struct imx_pin_reg *pin_reg;
- unsigned int npins, pin_id;
- int i;
+ unsigned int npins;
+ int i, err;
struct imx_pin_group *grp;
/*
@@ -203,70 +203,12 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
info->functions[selector].name, grp->name);
for (i = 0; i < npins; i++) {
- struct imx_pin *pin = &grp->pins[i];
- pin_id = pin->pin;
- pin_reg = &info->pin_regs[pin_id];
-
- if (pin_reg->mux_reg == -1) {
- dev_dbg(ipctl->dev, "Pin(%s) does not support mux function\n",
- info->pins[pin_id].name);
- continue;
- }
-
- if (info->flags & SHARE_MUX_CONF_REG) {
- u32 reg;
- reg = readl(ipctl->base + pin_reg->mux_reg);
- reg &= ~(0x7 << 20);
- reg |= (pin->mux_mode << 20);
- writel(reg, ipctl->base + pin_reg->mux_reg);
- } else {
- writel(pin->mux_mode, ipctl->base + pin_reg->mux_reg);
- }
- dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
- pin_reg->mux_reg, pin->mux_mode);
-
- /*
- * If the select input value begins with 0xff, it's a quirky
- * select input and the value should be interpreted as below.
- * 31 23 15 7 0
- * | 0xff | shift | width | select |
- * It's used to work around the problem that the select
- * input for some pin is not implemented in the select
- * input register but in some general purpose register.
- * We encode the select input value, width and shift of
- * the bit field into input_val cell of pin function ID
- * in device tree, and then decode them here for setting
- * up the select input bits in general purpose register.
- */
- if (pin->input_val >> 24 == 0xff) {
- u32 val = pin->input_val;
- u8 select = val & 0xff;
- u8 width = (val >> 8) & 0xff;
- u8 shift = (val >> 16) & 0xff;
- u32 mask = ((1 << width) - 1) << shift;
- /*
- * The input_reg[i] here is actually some IOMUXC general
- * purpose register, not regular select input register.
- */
- val = readl(ipctl->base + pin->input_reg);
- val &= ~mask;
- val |= select << shift;
- writel(val, ipctl->base + pin->input_reg);
- } else if (pin->input_reg) {
- /*
- * Regular select input register can never be at offset
- * 0, and we only print register value for regular case.
- */
- if (ipctl->input_sel_base)
- writel(pin->input_val, ipctl->input_sel_base +
- pin->input_reg);
- else
- writel(pin->input_val, ipctl->base +
- pin->input_reg);
- dev_dbg(ipctl->dev,
- "==>select_input: offset 0x%x val 0x%x\n",
- pin->input_reg, pin->input_val);
- }
+ if (info->flags & IMX8_USE_SCU)
+ err = imx_pmx_set_one_pin_scu(ipctl, &grp->pins[i]);
+ else
+ err = imx_pmx_set_one_pin_mem(ipctl, &grp->pins[i]);
+ if (err)
+ return err;
}
return 0;
@@ -302,98 +244,15 @@ static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
return 0;
}
-static int imx_pmx_gpio_request_enable(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range, unsigned offset)
-{
- struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
- const struct imx_pinctrl_soc_info *info = ipctl->info;
- const struct imx_pin_reg *pin_reg;
- struct imx_pin_group *grp;
- struct imx_pin *imx_pin;
- unsigned int pin, group;
- u32 reg;
-
- /* Currently implementation only for shared mux/conf register */
- if (!(info->flags & SHARE_MUX_CONF_REG))
- return 0;
-
- pin_reg = &info->pin_regs[offset];
- if (pin_reg->mux_reg == -1)
- return -EINVAL;
-
- /* Find the pinctrl config with GPIO mux mode for the requested pin */
- for (group = 0; group < info->ngroups; group++) {
- grp = &info->groups[group];
- for (pin = 0; pin < grp->npins; pin++) {
- imx_pin = &grp->pins[pin];
- if (imx_pin->pin == offset && !imx_pin->mux_mode)
- goto mux_pin;
- }
- }
-
- return -EINVAL;
-
-mux_pin:
- reg = readl(ipctl->base + pin_reg->mux_reg);
- reg &= ~(0x7 << 20);
- reg |= imx_pin->config;
- writel(reg, ipctl->base + pin_reg->mux_reg);
-
- return 0;
-}
-
-static void imx_pmx_gpio_disable_free(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range, unsigned offset)
-{
- struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
- const struct imx_pinctrl_soc_info *info = ipctl->info;
- const struct imx_pin_reg *pin_reg;
- u32 reg;
-
- /*
- * Only Vybrid has the input/output buffer enable flags (IBE/OBE)
- * They are part of the shared mux/conf register.
- */
- if (!(info->flags & SHARE_MUX_CONF_REG))
- return;
-
- pin_reg = &info->pin_regs[offset];
- if (pin_reg->mux_reg == -1)
- return;
-
- /* Clear IBE/OBE/PUE to disable the pin (Hi-Z) */
- reg = readl(ipctl->base + pin_reg->mux_reg);
- reg &= ~0x7;
- writel(reg, ipctl->base + pin_reg->mux_reg);
-}
-
static int imx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range, unsigned offset, bool input)
{
struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
const struct imx_pinctrl_soc_info *info = ipctl->info;
- const struct imx_pin_reg *pin_reg;
- u32 reg;
-
- /*
- * Only Vybrid has the input/output buffer enable flags (IBE/OBE)
- * They are part of the shared mux/conf register.
- */
- if (!(info->flags & SHARE_MUX_CONF_REG))
- return 0;
-
- pin_reg = &info->pin_regs[offset];
- if (pin_reg->mux_reg == -1)
- return -EINVAL;
-
- /* IBE always enabled allows us to read the value "on the wire" */
- reg = readl(ipctl->base + pin_reg->mux_reg);
- if (input)
- reg &= ~0x2;
- else
- reg |= 0x2;
- writel(reg, ipctl->base + pin_reg->mux_reg);
+ if (!(info->flags & IMX8_USE_SCU))
+ return imx_pmx_backend_gpio_set_direction_mem(pctldev,
+ range, offset, input);
return 0;
}
@@ -402,8 +261,6 @@ static const struct pinmux_ops imx_pmx_ops = {
.get_function_name = imx_pmx_get_func_name,
.get_function_groups = imx_pmx_get_groups,
.set_mux = imx_pmx_set,
- .gpio_request_enable = imx_pmx_gpio_request_enable,
- .gpio_disable_free = imx_pmx_gpio_disable_free,
.gpio_set_direction = imx_pmx_gpio_set_direction,
};
@@ -412,20 +269,11 @@ static int imx_pinconf_get(struct pinctrl_dev *pctldev,
{
struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
const struct imx_pinctrl_soc_info *info = ipctl->info;
- const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
-
- if (pin_reg->conf_reg == -1) {
- dev_err(info->dev, "Pin(%s) does not support config function\n",
- info->pins[pin_id].name);
- return -EINVAL;
- }
-
- *config = readl(ipctl->base + pin_reg->conf_reg);
- if (info->flags & SHARE_MUX_CONF_REG)
- *config &= 0xffff;
-
- return 0;
+ if (info->flags & IMX8_USE_SCU)
+ return imx_pinconf_backend_get_scu(pctldev, pin_id, config);
+ else
+ return imx_pinconf_backend_get_mem(pctldev, pin_id, config);
}
static int imx_pinconf_set(struct pinctrl_dev *pctldev,
@@ -434,33 +282,11 @@ static int imx_pinconf_set(struct pinctrl_dev *pctldev,
{
struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
const struct imx_pinctrl_soc_info *info = ipctl->info;
- const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
- int i;
-
- if (pin_reg->conf_reg == -1) {
- dev_err(info->dev, "Pin(%s) does not support config function\n",
- info->pins[pin_id].name);
- return -EINVAL;
- }
-
- dev_dbg(ipctl->dev, "pinconf set pin %s\n",
- info->pins[pin_id].name);
-
- for (i = 0; i < num_configs; i++) {
- if (info->flags & SHARE_MUX_CONF_REG) {
- u32 reg;
- reg = readl(ipctl->base + pin_reg->conf_reg);
- reg &= ~0xffff;
- reg |= configs[i];
- writel(reg, ipctl->base + pin_reg->conf_reg);
- } else {
- writel(configs[i], ipctl->base + pin_reg->conf_reg);
- }
- dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n",
- pin_reg->conf_reg, configs[i]);
- } /* for each config */
- return 0;
+ if (info->flags & IMX8_USE_SCU)
+ return imx_pinconf_backend_set_scu(pctldev, pin_id, configs, num_configs);
+ else
+ return imx_pinconf_backend_set_mem(pctldev, pin_id, configs, num_configs);
}
static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
@@ -468,15 +294,19 @@ static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
{
struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
const struct imx_pinctrl_soc_info *info = ipctl->info;
- const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
unsigned long config;
+ int ret;
- if (!pin_reg || pin_reg->conf_reg == -1) {
+ if (info->flags & IMX8_USE_SCU)
+ ret = imx_pinconf_backend_get_scu(pctldev, pin_id, &config);
+ else
+ ret = imx_pinconf_backend_get_mem(pctldev, pin_id, &config);
+
+ if (ret) {
seq_printf(s, "N/A");
return;
}
- config = readl(ipctl->base + pin_reg->conf_reg);
seq_printf(s, "0x%lx", config);
}
@@ -516,6 +346,7 @@ static const struct pinconf_ops imx_pinconf_ops = {
* Each pin represented in fsl,pins consists of 5 u32 PIN_FUNC_ID and
* 1 u32 CONFIG, so 24 types in total for each pin.
*/
+#define FSL_IMX8_PIN_SIZE 12
#define FSL_PIN_SIZE 24
#define SHARE_FSL_PIN_SIZE 20
@@ -525,13 +356,14 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
u32 index)
{
int size, pin_size;
- const __be32 *list;
+ const __be32 *list, **list_p;
int i;
- u32 config;
dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
- if (info->flags & SHARE_MUX_CONF_REG)
+ if (info->flags & IMX8_USE_SCU)
+ pin_size = FSL_IMX8_PIN_SIZE;
+ else if (info->flags & SHARE_MUX_CONF_REG)
pin_size = SHARE_FSL_PIN_SIZE;
else
pin_size = FSL_PIN_SIZE;
@@ -548,6 +380,8 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
return -EINVAL;
}
+ list_p = &list;
+
/* we do not check return since it's safe node passed down */
if (!size || size % pin_size) {
dev_err(info->dev, "Invalid fsl,pins property in node %s\n", np->full_name);
@@ -563,41 +397,12 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
return -ENOMEM;
for (i = 0; i < grp->npins; i++) {
- u32 mux_reg = be32_to_cpu(*list++);
- u32 conf_reg;
- unsigned int pin_id;
- struct imx_pin_reg *pin_reg;
- struct imx_pin *pin = &grp->pins[i];
-
- if (!(info->flags & ZERO_OFFSET_VALID) && !mux_reg)
- mux_reg = -1;
-
- if (info->flags & SHARE_MUX_CONF_REG) {
- conf_reg = mux_reg;
- } else {
- conf_reg = be32_to_cpu(*list++);
- if (!conf_reg)
- conf_reg = -1;
- }
-
- pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4;
- pin_reg = &info->pin_regs[pin_id];
- pin->pin = pin_id;
- grp->pin_ids[i] = pin_id;
- pin_reg->mux_reg = mux_reg;
- pin_reg->conf_reg = conf_reg;
- pin->input_reg = be32_to_cpu(*list++);
- pin->mux_mode = be32_to_cpu(*list++);
- pin->input_val = be32_to_cpu(*list++);
-
- /* SION bit is in mux register */
- config = be32_to_cpu(*list++);
- if (config & IMX_PAD_SION)
- pin->mux_mode |= IOMUXC_CONFIG_SION;
- pin->config = config & ~IMX_PAD_SION;
-
- dev_dbg(info->dev, "%s: 0x%x 0x%08lx", info->pins[pin_id].name,
- pin->mux_mode, pin->config);
+ if (info->flags & IMX8_USE_SCU)
+ imx_pinctrl_parse_pin_scu(info, &grp->pin_ids[i],
+ &grp->pins[i], list_p);
+ else
+ imx_pinctrl_parse_pin_mem(info, &grp->pin_ids[i],
+ &grp->pins[i], list_p);
}
return 0;
@@ -739,34 +544,36 @@ int imx_pinctrl_probe(struct platform_device *pdev,
if (!ipctl)
return -ENOMEM;
- info->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*info->pin_regs) *
- info->npins, GFP_KERNEL);
- if (!info->pin_regs)
- return -ENOMEM;
-
- for (i = 0; i < info->npins; i++) {
- info->pin_regs[i].mux_reg = -1;
- info->pin_regs[i].conf_reg = -1;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ipctl->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ipctl->base))
- return PTR_ERR(ipctl->base);
+ if (!(info->flags & IMX8_USE_SCU)) {
+ info->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*info->pin_regs) *
+ info->npins, GFP_KERNEL);
+ if (!info->pin_regs)
+ return -ENOMEM;
- if (of_property_read_bool(dev_np, "fsl,input-sel")) {
- np = of_parse_phandle(dev_np, "fsl,input-sel", 0);
- if (!np) {
- dev_err(&pdev->dev, "iomuxc fsl,input-sel property not found\n");
- return -EINVAL;
+ for (i = 0; i < info->npins; i++) {
+ info->pin_regs[i].mux_reg = -1;
+ info->pin_regs[i].conf_reg = -1;
}
- ipctl->input_sel_base = of_iomap(np, 0);
- of_node_put(np);
- if (!ipctl->input_sel_base) {
- dev_err(&pdev->dev,
- "iomuxc input select base address not found\n");
- return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ipctl->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ipctl->base))
+ return PTR_ERR(ipctl->base);
+
+ if (of_property_read_bool(dev_np, "fsl,input-sel")) {
+ np = of_parse_phandle(dev_np, "fsl,input-sel", 0);
+ if (!np) {
+ dev_err(&pdev->dev, "iomuxc fsl,input-sel property not found\n");
+ return -EINVAL;
+ }
+
+ ipctl->input_sel_base = of_iomap(np, 0);
+ of_node_put(np);
+ if (!ipctl->input_sel_base) {
+ dev_err(&pdev->dev,
+ "iomuxc input select base address not found\n");
+ return -ENOMEM;
+ }
}
}
@@ -803,3 +610,23 @@ int imx_pinctrl_probe(struct platform_device *pdev,
return 0;
}
+
+int imx_pinctrl_suspend(struct device *dev)
+{
+ struct imx_pinctrl *ipctl = dev_get_drvdata(dev);
+
+ if (!ipctl)
+ return -EINVAL;
+
+ return pinctrl_force_sleep(ipctl->pctl);
+}
+
+int imx_pinctrl_resume(struct device *dev)
+{
+ struct imx_pinctrl *ipctl = dev_get_drvdata(dev);
+
+ if (!ipctl)
+ return -EINVAL;
+
+ return pinctrl_force_default(ipctl->pctl);
+}
diff --git a/drivers/pinctrl/freescale/pinctrl-imx.h b/drivers/pinctrl/freescale/pinctrl-imx.h
index 8af8aa2897ab..80af4f65e92f 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx.h
+++ b/drivers/pinctrl/freescale/pinctrl-imx.h
@@ -3,6 +3,7 @@
*
* Copyright (C) 2012 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Linaro Ltd.
+ * Copyright 2017 NXP
*
* Author: Dong Aisheng <dong.aisheng@linaro.org>
*
@@ -26,14 +27,26 @@ struct platform_device;
* @input_val: the select input value for this pin.
* @configs: the config for this pin.
*/
-struct imx_pin {
- unsigned int pin;
+struct imx_pin_memmap {
unsigned int mux_mode;
u16 input_reg;
unsigned int input_val;
unsigned long config;
};
+struct imx_pin_scu {
+ unsigned long mux;
+ unsigned long config;
+};
+
+struct imx_pin {
+ unsigned int pin;
+ union {
+ struct imx_pin_memmap pin_memmap;
+ struct imx_pin_scu pin_scu;
+ } pin_conf;
+};
+
/**
* struct imx_pin_group - describes an IMX pin group
* @name: the name of this specific pin group
@@ -83,10 +96,34 @@ struct imx_pinctrl_soc_info {
unsigned int nfunctions;
unsigned int flags;
const char *gpr_compatible;
+
+ /* MUX_MODE shift and mask in case SHARE_MUX_CONF_REG */
+ unsigned int mux_mask;
+ u8 mux_shift;
+ u32 ibe_bit;
+ u32 obe_bit;
+};
+
+/**
+ * @dev: a pointer back to containing device
+ * @base: the offset to the controller in virtual memory
+ */
+struct imx_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+ void __iomem *base;
+ void __iomem *input_sel_base;
+ const struct imx_pinctrl_soc_info *info;
};
#define SHARE_MUX_CONF_REG 0x1
#define ZERO_OFFSET_VALID 0x2
+#define IMX8_ENABLE_MUX_CONFIG (1 << 29)
+#define IMX8_ENABLE_PAD_CONFIG (1 << 30)
+#define IMX8_USE_SCU (1 << 31)
+
+#define BM_IMX8_GP_ENABLE (1 << 30)
+#define BM_IMX8_IFMUX_ENABLE (1 << 31)
#define NO_MUX 0x0
#define NO_PAD 0x0
@@ -99,4 +136,73 @@ struct imx_pinctrl_soc_info {
int imx_pinctrl_probe(struct platform_device *pdev,
struct imx_pinctrl_soc_info *info);
+int imx_pinctrl_suspend(struct device *dev);
+int imx_pinctrl_resume(struct device *dev);
+
+#ifdef CONFIG_PINCTRL_IMX_MEMMAP
+int imx_pmx_set_one_pin_mem(struct imx_pinctrl *ipctl, struct imx_pin *pin);
+int imx_pmx_backend_gpio_set_direction_mem(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned offset, bool input);
+int imx_pinconf_backend_get_mem(struct pinctrl_dev *pctldev, unsigned pin_id,
+ unsigned long *config);
+int imx_pinconf_backend_set_mem(struct pinctrl_dev *pctldev, unsigned pin_id,
+ unsigned long *configs, unsigned num_configs);
+int imx_pinctrl_parse_pin_mem(struct imx_pinctrl_soc_info *info,
+ unsigned int *pin_id, struct imx_pin *pin, const __be32 **list_p);
+#else
+static inline int imx_pmx_set_one_pin_mem(struct imx_pinctrl *ipctl, struct imx_pin *pin)
+{
+ return 0;
+}
+static inline int imx_pmx_backend_gpio_set_direction_mem(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned offset, bool input)
+{
+ return 0;
+}
+static inline int imx_pinconf_backend_get_mem(struct pinctrl_dev *pctldev, unsigned pin_id,
+ unsigned long *config)
+{
+ return 0;
+}
+static inline int imx_pinconf_backend_set_mem(struct pinctrl_dev *pctldev, unsigned pin_id,
+ unsigned long *configs, unsigned num_configs)
+{
+ return 0;
+}
+static inline int imx_pinctrl_parse_pin_mem(struct imx_pinctrl_soc_info *info,
+ unsigned int *pin_id, struct imx_pin *pin, const __be32 **list_p)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PINCTRL_IMX_SCU
+int imx_pmx_set_one_pin_scu(struct imx_pinctrl *ipctl, struct imx_pin *pin);
+int imx_pinconf_backend_get_scu(struct pinctrl_dev *pctldev, unsigned pin_id,
+ unsigned long *config);
+int imx_pinconf_backend_set_scu(struct pinctrl_dev *pctldev, unsigned pin_id,
+ unsigned long *configs, unsigned num_configs);
+int imx_pinctrl_parse_pin_scu(struct imx_pinctrl_soc_info *info,
+ unsigned int *pin_id, struct imx_pin *pin, const __be32 **list_p);
+#else
+static inline int imx_pmx_set_one_pin_scu(struct imx_pinctrl *ipctl, struct imx_pin *pin)
+{
+ return 0;
+}
+static inline int imx_pinconf_backend_get_scu(struct pinctrl_dev *pctldev, unsigned pin_id,
+ unsigned long *config)
+{
+ return 0;
+}
+static inline int imx_pinconf_backend_set_scu(struct pinctrl_dev *pctldev, unsigned pin_id,
+ unsigned long *configs, unsigned num_configs)
+{
+ return 0;
+}
+static inline int imx_pinctrl_parse_pin_scu(struct imx_pinctrl_soc_info *info,
+ unsigned int *pin_id, struct imx_pin *pin, const __be32 **list_p)
+{
+ return 0;
+}
+#endif
#endif /* __DRIVERS_PINCTRL_IMX_H */
diff --git a/drivers/pinctrl/freescale/pinctrl-imx6sll.c b/drivers/pinctrl/freescale/pinctrl-imx6sll.c
new file mode 100644
index 000000000000..371fb143e039
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-imx6sll.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-imx.h"
+
+enum imx6sll_pads {
+ MX6SLL_PAD_RESERVE0 = 0,
+ MX6SLL_PAD_RESERVE1 = 1,
+ MX6SLL_PAD_RESERVE2 = 2,
+ MX6SLL_PAD_RESERVE3 = 3,
+ MX6SLL_PAD_RESERVE4 = 4,
+ MX6SLL_PAD_WDOG_B = 5,
+ MX6SLL_PAD_REF_CLK_24M = 6,
+ MX6SLL_PAD_REF_CLK_32K = 7,
+ MX6SLL_PAD_PWM1 = 8,
+ MX6SLL_PAD_KEY_COL0 = 9,
+ MX6SLL_PAD_KEY_ROW0 = 10,
+ MX6SLL_PAD_KEY_COL1 = 11,
+ MX6SLL_PAD_KEY_ROW1 = 12,
+ MX6SLL_PAD_KEY_COL2 = 13,
+ MX6SLL_PAD_KEY_ROW2 = 14,
+ MX6SLL_PAD_KEY_COL3 = 15,
+ MX6SLL_PAD_KEY_ROW3 = 16,
+ MX6SLL_PAD_KEY_COL4 = 17,
+ MX6SLL_PAD_KEY_ROW4 = 18,
+ MX6SLL_PAD_KEY_COL5 = 19,
+ MX6SLL_PAD_KEY_ROW5 = 20,
+ MX6SLL_PAD_KEY_COL6 = 21,
+ MX6SLL_PAD_KEY_ROW6 = 22,
+ MX6SLL_PAD_KEY_COL7 = 23,
+ MX6SLL_PAD_KEY_ROW7 = 24,
+ MX6SLL_PAD_EPDC_DATA00 = 25,
+ MX6SLL_PAD_EPDC_DATA01 = 26,
+ MX6SLL_PAD_EPDC_DATA02 = 27,
+ MX6SLL_PAD_EPDC_DATA03 = 28,
+ MX6SLL_PAD_EPDC_DATA04 = 29,
+ MX6SLL_PAD_EPDC_DATA05 = 30,
+ MX6SLL_PAD_EPDC_DATA06 = 31,
+ MX6SLL_PAD_EPDC_DATA07 = 32,
+ MX6SLL_PAD_EPDC_DATA08 = 33,
+ MX6SLL_PAD_EPDC_DATA09 = 34,
+ MX6SLL_PAD_EPDC_DATA10 = 35,
+ MX6SLL_PAD_EPDC_DATA11 = 36,
+ MX6SLL_PAD_EPDC_DATA12 = 37,
+ MX6SLL_PAD_EPDC_DATA13 = 38,
+ MX6SLL_PAD_EPDC_DATA14 = 39,
+ MX6SLL_PAD_EPDC_DATA15 = 40,
+ MX6SLL_PAD_EPDC_SDCLK = 41,
+ MX6SLL_PAD_EPDC_SDLE = 42,
+ MX6SLL_PAD_EPDC_SDOE = 43,
+ MX6SLL_PAD_EPDC_SDSHR = 44,
+ MX6SLL_PAD_EPDC_SDCE0 = 45,
+ MX6SLL_PAD_EPDC_SDCE1 = 46,
+ MX6SLL_PAD_EPDC_SDCE2 = 47,
+ MX6SLL_PAD_EPDC_SDCE3 = 48,
+ MX6SLL_PAD_EPDC_GDCLK = 49,
+ MX6SLL_PAD_EPDC_GDOE = 50,
+ MX6SLL_PAD_EPDC_GDRL = 51,
+ MX6SLL_PAD_EPDC_GDSP = 52,
+ MX6SLL_PAD_EPDC_VCOM0 = 53,
+ MX6SLL_PAD_EPDC_VCOM1 = 54,
+ MX6SLL_PAD_EPDC_BDR0 = 55,
+ MX6SLL_PAD_EPDC_BDR1 = 56,
+ MX6SLL_PAD_EPDC_PWR_CTRL0 = 57,
+ MX6SLL_PAD_EPDC_PWR_CTRL1 = 58,
+ MX6SLL_PAD_EPDC_PWR_CTRL2 = 59,
+ MX6SLL_PAD_EPDC_PWR_CTRL3 = 60,
+ MX6SLL_PAD_EPDC_PWR_COM = 61,
+ MX6SLL_PAD_EPDC_PWR_INT = 62,
+ MX6SLL_PAD_EPDC_PWR_STAT = 63,
+ MX6SLL_PAD_EPDC_PWR_WAKE = 64,
+ MX6SLL_PAD_LCD_CLK = 65,
+ MX6SLL_PAD_LCD_ENABLE = 66,
+ MX6SLL_PAD_LCD_HSYNC = 67,
+ MX6SLL_PAD_LCD_VSYNC = 68,
+ MX6SLL_PAD_LCD_RESET = 69,
+ MX6SLL_PAD_LCD_DATA00 = 70,
+ MX6SLL_PAD_LCD_DATA01 = 71,
+ MX6SLL_PAD_LCD_DATA02 = 72,
+ MX6SLL_PAD_LCD_DATA03 = 73,
+ MX6SLL_PAD_LCD_DATA04 = 74,
+ MX6SLL_PAD_LCD_DATA05 = 75,
+ MX6SLL_PAD_LCD_DATA06 = 76,
+ MX6SLL_PAD_LCD_DATA07 = 77,
+ MX6SLL_PAD_LCD_DATA08 = 78,
+ MX6SLL_PAD_LCD_DATA09 = 79,
+ MX6SLL_PAD_LCD_DATA10 = 80,
+ MX6SLL_PAD_LCD_DATA11 = 81,
+ MX6SLL_PAD_LCD_DATA12 = 82,
+ MX6SLL_PAD_LCD_DATA13 = 83,
+ MX6SLL_PAD_LCD_DATA14 = 84,
+ MX6SLL_PAD_LCD_DATA15 = 85,
+ MX6SLL_PAD_LCD_DATA16 = 86,
+ MX6SLL_PAD_LCD_DATA17 = 87,
+ MX6SLL_PAD_LCD_DATA18 = 88,
+ MX6SLL_PAD_LCD_DATA19 = 89,
+ MX6SLL_PAD_LCD_DATA20 = 90,
+ MX6SLL_PAD_LCD_DATA21 = 91,
+ MX6SLL_PAD_LCD_DATA22 = 92,
+ MX6SLL_PAD_LCD_DATA23 = 93,
+ MX6SLL_PAD_AUD_RXFS = 94,
+ MX6SLL_PAD_AUD_RXC = 95,
+ MX6SLL_PAD_AUD_RXD = 96,
+ MX6SLL_PAD_AUD_TXC = 97,
+ MX6SLL_PAD_AUD_TXFS = 98,
+ MX6SLL_PAD_AUD_TXD = 99,
+ MX6SLL_PAD_AUD_MCLK = 100,
+ MX6SLL_PAD_UART1_RXD = 101,
+ MX6SLL_PAD_UART1_TXD = 102,
+ MX6SLL_PAD_I2C1_SCL = 103,
+ MX6SLL_PAD_I2C1_SDA = 104,
+ MX6SLL_PAD_I2C2_SCL = 105,
+ MX6SLL_PAD_I2C2_SDA = 106,
+ MX6SLL_PAD_ECSPI1_SCLK = 107,
+ MX6SLL_PAD_ECSPI1_MOSI = 108,
+ MX6SLL_PAD_ECSPI1_MISO = 109,
+ MX6SLL_PAD_ECSPI1_SS0 = 110,
+ MX6SLL_PAD_ECSPI2_SCLK = 111,
+ MX6SLL_PAD_ECSPI2_MOSI = 112,
+ MX6SLL_PAD_ECSPI2_MISO = 113,
+ MX6SLL_PAD_ECSPI2_SS0 = 114,
+ MX6SLL_PAD_SD1_CLK = 115,
+ MX6SLL_PAD_SD1_CMD = 116,
+ MX6SLL_PAD_SD1_DATA0 = 117,
+ MX6SLL_PAD_SD1_DATA1 = 118,
+ MX6SLL_PAD_SD1_DATA2 = 119,
+ MX6SLL_PAD_SD1_DATA3 = 120,
+ MX6SLL_PAD_SD1_DATA4 = 121,
+ MX6SLL_PAD_SD1_DATA5 = 122,
+ MX6SLL_PAD_SD1_DATA6 = 123,
+ MX6SLL_PAD_SD1_DATA7 = 124,
+ MX6SLL_PAD_SD2_RESET = 125,
+ MX6SLL_PAD_SD2_CLK = 126,
+ MX6SLL_PAD_SD2_CMD = 127,
+ MX6SLL_PAD_SD2_DATA0 = 128,
+ MX6SLL_PAD_SD2_DATA1 = 129,
+ MX6SLL_PAD_SD2_DATA2 = 130,
+ MX6SLL_PAD_SD2_DATA3 = 131,
+ MX6SLL_PAD_SD2_DATA4 = 132,
+ MX6SLL_PAD_SD2_DATA5 = 133,
+ MX6SLL_PAD_SD2_DATA6 = 134,
+ MX6SLL_PAD_SD2_DATA7 = 135,
+ MX6SLL_PAD_SD3_CLK = 136,
+ MX6SLL_PAD_SD3_CMD = 137,
+ MX6SLL_PAD_SD3_DATA0 = 138,
+ MX6SLL_PAD_SD3_DATA1 = 139,
+ MX6SLL_PAD_SD3_DATA2 = 140,
+ MX6SLL_PAD_SD3_DATA3 = 141,
+ MX6SLL_PAD_GPIO4_IO20 = 142,
+ MX6SLL_PAD_GPIO4_IO21 = 143,
+ MX6SLL_PAD_GPIO4_IO19 = 144,
+ MX6SLL_PAD_GPIO4_IO25 = 145,
+ MX6SLL_PAD_GPIO4_IO18 = 146,
+ MX6SLL_PAD_GPIO4_IO24 = 147,
+ MX6SLL_PAD_GPIO4_IO23 = 148,
+ MX6SLL_PAD_GPIO4_IO17 = 149,
+ MX6SLL_PAD_GPIO4_IO22 = 150,
+ MX6SLL_PAD_GPIO4_IO16 = 151,
+ MX6SLL_PAD_GPIO4_IO26 = 152,
+};
+
+enum imx6sll_lpsr_pads {
+ MX6SLL_PAD_SNVS_TAMPER = 0,
+ MX6SLL_PAD_SNVS_PMIC_ON_REQ = 1,
+ MX6SLL_PAD_SNVS_PMIC_STBY_REQ = 2,
+ MX6SLL_PAD_SNVS_BOOT_MODE0 = 3,
+ MX6SLL_PAD_SNVS_BOOT_MODE1 = 4,
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc imx6sll_pinctrl_pads[] = {
+ IMX_PINCTRL_PIN(MX6SLL_PAD_RESERVE0),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_RESERVE1),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_RESERVE2),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_RESERVE3),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_RESERVE4),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_WDOG_B),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_REF_CLK_24M),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_REF_CLK_32K),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_PWM1),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_KEY_COL0),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_KEY_ROW0),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_KEY_COL1),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_KEY_ROW1),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_KEY_COL2),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_KEY_ROW2),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_KEY_COL3),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_KEY_ROW3),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_KEY_COL4),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_KEY_ROW4),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_KEY_COL5),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_KEY_ROW5),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_KEY_COL6),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_KEY_ROW6),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_KEY_COL7),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_KEY_ROW7),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_DATA00),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_DATA01),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_DATA02),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_DATA03),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_DATA04),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_DATA05),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_DATA06),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_DATA07),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_DATA08),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_DATA09),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_DATA10),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_DATA11),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_DATA12),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_DATA13),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_DATA14),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_DATA15),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_SDCLK),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_SDLE),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_SDOE),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_SDSHR),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_SDCE0),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_SDCE1),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_SDCE2),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_SDCE3),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_GDCLK),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_GDOE),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_GDRL),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_GDSP),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_VCOM0),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_VCOM1),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_BDR0),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_BDR1),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_PWR_CTRL0),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_PWR_CTRL1),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_PWR_CTRL2),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_PWR_CTRL3),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_PWR_COM),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_PWR_INT),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_PWR_STAT),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_EPDC_PWR_WAKE),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_CLK),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_ENABLE),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_HSYNC),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_VSYNC),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_RESET),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA00),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA01),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA02),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA03),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA04),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA05),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA06),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA07),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA08),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA09),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA10),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA11),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA12),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA13),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA14),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA15),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA16),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA17),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA18),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA19),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA20),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA21),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA22),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_LCD_DATA23),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_AUD_RXFS),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_AUD_RXC),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_AUD_RXD),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_AUD_TXC),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_AUD_TXFS),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_AUD_TXD),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_AUD_MCLK),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_UART1_RXD),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_UART1_TXD),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_I2C1_SCL),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_I2C1_SDA),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_I2C2_SCL),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_I2C2_SDA),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_ECSPI1_SCLK),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_ECSPI1_MOSI),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_ECSPI1_MISO),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_ECSPI1_SS0),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_ECSPI2_SCLK),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_ECSPI2_MOSI),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_ECSPI2_MISO),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_ECSPI2_SS0),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD1_CLK),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD1_CMD),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD1_DATA0),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD1_DATA1),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD1_DATA2),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD1_DATA3),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD1_DATA4),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD1_DATA5),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD1_DATA6),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD1_DATA7),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD2_RESET),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD2_CLK),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD2_CMD),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD2_DATA0),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD2_DATA1),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD2_DATA2),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD2_DATA3),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD2_DATA4),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD2_DATA5),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD2_DATA6),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD2_DATA7),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD3_CLK),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD3_CMD),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD3_DATA0),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD3_DATA1),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD3_DATA2),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_SD3_DATA3),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_GPIO4_IO20),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_GPIO4_IO21),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_GPIO4_IO19),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_GPIO4_IO25),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_GPIO4_IO18),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_GPIO4_IO24),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_GPIO4_IO23),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_GPIO4_IO17),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_GPIO4_IO22),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_GPIO4_IO16),
+ IMX_PINCTRL_PIN(MX6SLL_PAD_GPIO4_IO26),
+};
+
+static struct imx_pinctrl_soc_info imx6sll_pinctrl_info = {
+ .pins = imx6sll_pinctrl_pads,
+ .npins = ARRAY_SIZE(imx6sll_pinctrl_pads),
+};
+
+static struct of_device_id imx6sll_pinctrl_of_match[] = {
+ { .compatible = "fsl,imx6sll-iomuxc", .data = &imx6sll_pinctrl_info, },
+ { /* sentinel */ }
+};
+
+static int imx6sll_pinctrl_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct imx_pinctrl_soc_info *pinctrl_info;
+
+ match = of_match_device(imx6sll_pinctrl_of_match, &pdev->dev);
+
+ if (!match)
+ return -ENODEV;
+
+ pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;
+
+ return imx_pinctrl_probe(pdev, pinctrl_info);
+}
+
+static struct platform_driver imx6sll_pinctrl_driver = {
+ .driver = {
+ .name = "imx6sll-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(imx6sll_pinctrl_of_match),
+ },
+ .probe = imx6sll_pinctrl_probe,
+};
+
+static int __init imx6sll_pinctrl_init(void)
+{
+ return platform_driver_register(&imx6sll_pinctrl_driver);
+}
+arch_initcall(imx6sll_pinctrl_init);
+
+static void __exit imx6sll_pinctrl_exit(void)
+{
+ platform_driver_unregister(&imx6sll_pinctrl_driver);
+}
+module_exit(imx6sll_pinctrl_exit);
+
+MODULE_AUTHOR("Bai Ping <ping.bai@nxp.com>");
+MODULE_DESCRIPTION("Freescale imx6sll pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/freescale/pinctrl-imx6ul.c b/drivers/pinctrl/freescale/pinctrl-imx6ul.c
index 1aeb840aae1d..cbad1c69226d 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx6ul.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx6ul.c
@@ -150,6 +150,21 @@ enum imx6ul_pads {
MX6UL_PAD_CSI_DATA07 = 128,
};
+enum imx6ull_lpsr_pads {
+ MX6ULL_PAD_BOOT_MODE0 = 0,
+ MX6ULL_PAD_BOOT_MODE1 = 1,
+ MX6ULL_PAD_SNVS_TAMPER0 = 2,
+ MX6ULL_PAD_SNVS_TAMPER1 = 3,
+ MX6ULL_PAD_SNVS_TAMPER2 = 4,
+ MX6ULL_PAD_SNVS_TAMPER3 = 5,
+ MX6ULL_PAD_SNVS_TAMPER4 = 6,
+ MX6ULL_PAD_SNVS_TAMPER5 = 7,
+ MX6ULL_PAD_SNVS_TAMPER6 = 8,
+ MX6ULL_PAD_SNVS_TAMPER7 = 9,
+ MX6ULL_PAD_SNVS_TAMPER8 = 10,
+ MX6ULL_PAD_SNVS_TAMPER9 = 11,
+};
+
/* Pad names for the pinmux subsystem */
static const struct pinctrl_pin_desc imx6ul_pinctrl_pads[] = {
IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE0),
@@ -283,20 +298,53 @@ static const struct pinctrl_pin_desc imx6ul_pinctrl_pads[] = {
IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA07),
};
+/* pad for i.MX6ULL lpsr pinmux */
+static struct pinctrl_pin_desc imx6ull_snvs_pinctrl_pads[] = {
+ IMX_PINCTRL_PIN(MX6ULL_PAD_BOOT_MODE0),
+ IMX_PINCTRL_PIN(MX6ULL_PAD_BOOT_MODE1),
+ IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER0),
+ IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER1),
+ IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER2),
+ IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER3),
+ IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER4),
+ IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER5),
+ IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER6),
+ IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER7),
+ IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER8),
+ IMX_PINCTRL_PIN(MX6ULL_PAD_SNVS_TAMPER9),
+};
+
static struct imx_pinctrl_soc_info imx6ul_pinctrl_info = {
.pins = imx6ul_pinctrl_pads,
.npins = ARRAY_SIZE(imx6ul_pinctrl_pads),
.gpr_compatible = "fsl,imx6ul-iomuxc-gpr",
};
+static struct imx_pinctrl_soc_info imx6ull_snvs_pinctrl_info = {
+ .pins = imx6ull_snvs_pinctrl_pads,
+ .npins = ARRAY_SIZE(imx6ull_snvs_pinctrl_pads),
+ .flags = ZERO_OFFSET_VALID,
+};
+
static struct of_device_id imx6ul_pinctrl_of_match[] = {
- { .compatible = "fsl,imx6ul-iomuxc", },
+ { .compatible = "fsl,imx6ul-iomuxc", .data = &imx6ul_pinctrl_info, },
+ { .compatible = "fsl,imx6ull-iomuxc-snvs", .data = &imx6ull_snvs_pinctrl_info, },
{ /* sentinel */ }
};
static int imx6ul_pinctrl_probe(struct platform_device *pdev)
{
- return imx_pinctrl_probe(pdev, &imx6ul_pinctrl_info);
+ const struct of_device_id *match;
+ struct imx_pinctrl_soc_info *pinctrl_info;
+
+ match = of_match_device(imx6ul_pinctrl_of_match, &pdev->dev);
+
+ if (!match)
+ return -ENODEV;
+
+ pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;
+
+ return imx_pinctrl_probe(pdev, pinctrl_info);
}
static struct platform_driver imx6ul_pinctrl_driver = {
diff --git a/drivers/pinctrl/freescale/pinctrl-imx7d.c b/drivers/pinctrl/freescale/pinctrl-imx7d.c
index a465a66c3ef4..9f6d8ba7ce61 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx7d.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx7d.c
@@ -391,10 +391,27 @@ static int imx7d_pinctrl_probe(struct platform_device *pdev)
return imx_pinctrl_probe(pdev, pinctrl_info);
}
+static int imx7d_pinctrl_suspend(struct device *dev)
+{
+
+ return imx_pinctrl_suspend(dev);
+}
+
+static int imx7d_pinctrl_resume(struct device *dev)
+{
+
+ return imx_pinctrl_resume(dev);
+}
+
+static const struct dev_pm_ops imx7d_pinctrl_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(imx7d_pinctrl_suspend, imx7d_pinctrl_resume)
+};
+
static struct platform_driver imx7d_pinctrl_driver = {
.driver = {
.name = "imx7d-pinctrl",
.of_match_table = of_match_ptr(imx7d_pinctrl_of_match),
+ .pm = &imx7d_pinctrl_pm_ops,
},
.probe = imx7d_pinctrl_probe,
};
diff --git a/drivers/pinctrl/freescale/pinctrl-imx7ulp.c b/drivers/pinctrl/freescale/pinctrl-imx7ulp.c
new file mode 100644
index 000000000000..454bf2a4ffbf
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-imx7ulp.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-imx.h"
+
+enum imx7ulp_pads {
+ ULP1_PAD_PTA0 = 0,
+ ULP1_PAD_PTA1,
+ ULP1_PAD_PTA2,
+ ULP1_PAD_PTA3,
+ ULP1_PAD_PTA4,
+ ULP1_PAD_PTA5,
+ ULP1_PAD_PTA6,
+ ULP1_PAD_PTA7,
+ ULP1_PAD_PTA8,
+ ULP1_PAD_PTA9,
+ ULP1_PAD_PTA10,
+ ULP1_PAD_PTA11,
+ ULP1_PAD_PTA12,
+ ULP1_PAD_PTA13,
+ ULP1_PAD_PTA14,
+ ULP1_PAD_PTA15,
+ ULP1_PAD_PTA16,
+ ULP1_PAD_PTA17,
+ ULP1_PAD_PTA18,
+ ULP1_PAD_PTA19,
+ ULP1_PAD_PTA20,
+ ULP1_PAD_PTA21,
+ ULP1_PAD_PTA22,
+ ULP1_PAD_PTA23,
+ ULP1_PAD_PTA24,
+ ULP1_PAD_PTA25,
+ ULP1_PAD_PTA26,
+ ULP1_PAD_PTA27,
+ ULP1_PAD_PTA28,
+ ULP1_PAD_PTA29,
+ ULP1_PAD_PTA30,
+ ULP1_PAD_PTA31,
+ ULP1_PAD_PTB0,
+ ULP1_PAD_PTB1,
+ ULP1_PAD_PTB2,
+ ULP1_PAD_PTB3,
+ ULP1_PAD_PTB4,
+ ULP1_PAD_PTB5,
+ ULP1_PAD_PTB6,
+ ULP1_PAD_PTB7,
+ ULP1_PAD_PTB8,
+ ULP1_PAD_PTB9,
+ ULP1_PAD_PTB10,
+ ULP1_PAD_PTB11,
+ ULP1_PAD_PTB12,
+ ULP1_PAD_PTB13,
+ ULP1_PAD_PTB14,
+ ULP1_PAD_PTB15,
+ ULP1_PAD_PTB16,
+ ULP1_PAD_PTB17,
+ ULP1_PAD_PTB18,
+ ULP1_PAD_PTB19 = 51,
+ ULP1_PAD_PTC0 = 0,
+ ULP1_PAD_PTC1,
+ ULP1_PAD_PTC2,
+ ULP1_PAD_PTC3,
+ ULP1_PAD_PTC4,
+ ULP1_PAD_PTC5,
+ ULP1_PAD_PTC6,
+ ULP1_PAD_PTC7,
+ ULP1_PAD_PTC8,
+ ULP1_PAD_PTC9,
+ ULP1_PAD_PTC10,
+ ULP1_PAD_PTC11,
+ ULP1_PAD_PTC12,
+ ULP1_PAD_PTC13,
+ ULP1_PAD_PTC14,
+ ULP1_PAD_PTC15,
+ ULP1_PAD_PTC16,
+ ULP1_PAD_PTC17,
+ ULP1_PAD_PTC18,
+ ULP1_PAD_PTC19,
+ ULP1_PAD_RESERVE0,
+ ULP1_PAD_RESERVE1,
+ ULP1_PAD_RESERVE2,
+ ULP1_PAD_RESERVE3,
+ ULP1_PAD_RESERVE4,
+ ULP1_PAD_RESERVE5,
+ ULP1_PAD_RESERVE6,
+ ULP1_PAD_RESERVE7,
+ ULP1_PAD_RESERVE8,
+ ULP1_PAD_RESERVE9,
+ ULP1_PAD_RESERVE10,
+ ULP1_PAD_RESERVE11,
+ ULP1_PAD_PTD0,
+ ULP1_PAD_PTD1,
+ ULP1_PAD_PTD2,
+ ULP1_PAD_PTD3,
+ ULP1_PAD_PTD4,
+ ULP1_PAD_PTD5,
+ ULP1_PAD_PTD6,
+ ULP1_PAD_PTD7,
+ ULP1_PAD_PTD8,
+ ULP1_PAD_PTD9,
+ ULP1_PAD_PTD10,
+ ULP1_PAD_PTD11,
+ ULP1_PAD_RESERVE12,
+ ULP1_PAD_RESERVE13,
+ ULP1_PAD_RESERVE14,
+ ULP1_PAD_RESERVE15,
+ ULP1_PAD_RESERVE16,
+ ULP1_PAD_RESERVE17,
+ ULP1_PAD_RESERVE18,
+ ULP1_PAD_RESERVE19,
+ ULP1_PAD_RESERVE20,
+ ULP1_PAD_RESERVE21,
+ ULP1_PAD_RESERVE22,
+ ULP1_PAD_RESERVE23,
+ ULP1_PAD_RESERVE24,
+ ULP1_PAD_RESERVE25,
+ ULP1_PAD_RESERVE26,
+ ULP1_PAD_RESERVE27,
+ ULP1_PAD_RESERVE28,
+ ULP1_PAD_RESERVE29,
+ ULP1_PAD_RESERVE30,
+ ULP1_PAD_RESERVE31,
+ ULP1_PAD_PTE0,
+ ULP1_PAD_PTE1,
+ ULP1_PAD_PTE2,
+ ULP1_PAD_PTE3,
+ ULP1_PAD_PTE4,
+ ULP1_PAD_PTE5,
+ ULP1_PAD_PTE6,
+ ULP1_PAD_PTE7,
+ ULP1_PAD_PTE8,
+ ULP1_PAD_PTE9,
+ ULP1_PAD_PTE10,
+ ULP1_PAD_PTE11,
+ ULP1_PAD_PTE12,
+ ULP1_PAD_PTE13,
+ ULP1_PAD_PTE14,
+ ULP1_PAD_PTE15,
+ ULP1_PAD_RESERVE32,
+ ULP1_PAD_RESERVE33,
+ ULP1_PAD_RESERVE34,
+ ULP1_PAD_RESERVE35,
+ ULP1_PAD_RESERVE36,
+ ULP1_PAD_RESERVE37,
+ ULP1_PAD_RESERVE38,
+ ULP1_PAD_RESERVE39,
+ ULP1_PAD_RESERVE40,
+ ULP1_PAD_RESERVE41,
+ ULP1_PAD_RESERVE42,
+ ULP1_PAD_RESERVE43,
+ ULP1_PAD_RESERVE44,
+ ULP1_PAD_RESERVE45,
+ ULP1_PAD_RESERVE46,
+ ULP1_PAD_RESERVE47,
+ ULP1_PAD_PTF0,
+ ULP1_PAD_PTF1,
+ ULP1_PAD_PTF2,
+ ULP1_PAD_PTF3,
+ ULP1_PAD_PTF4,
+ ULP1_PAD_PTF5,
+ ULP1_PAD_PTF6,
+ ULP1_PAD_PTF7,
+ ULP1_PAD_PTF8,
+ ULP1_PAD_PTF9,
+ ULP1_PAD_PTF10,
+ ULP1_PAD_PTF11,
+ ULP1_PAD_PTF12,
+ ULP1_PAD_PTF13,
+ ULP1_PAD_PTF14,
+ ULP1_PAD_PTF15,
+ ULP1_PAD_PTF16,
+ ULP1_PAD_PTF17,
+ ULP1_PAD_PTF18,
+ ULP1_PAD_PTF19,
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc imx7ulp_pinctrl_pads_0[] = {
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA0),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA1),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA2),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA3),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA4),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA5),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA6),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA7),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA8),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA9),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA10),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA11),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA12),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA13),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA14),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA15),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA16),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA17),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA18),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA19),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA20),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA21),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA22),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA23),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA24),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA25),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA26),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA27),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA28),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA29),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA30),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTA31),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB0),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB1),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB2),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB3),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB4),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB5),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB6),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB7),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB8),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB9),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB10),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB11),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB12),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB13),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB14),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB15),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB16),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB17),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB18),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTB19),
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc imx7ulp_pinctrl_pads_1[] = {
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC0),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC1),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC2),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC3),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC4),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC5),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC6),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC7),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC8),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC9),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC10),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC11),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC12),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC13),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC14),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC15),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC16),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC17),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC18),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTC19),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE0),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE1),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE2),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE3),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE4),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE5),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE6),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE7),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE8),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE9),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE10),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE11),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTD0),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTD1),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTD2),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTD3),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTD4),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTD5),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTD6),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTD7),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTD8),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTD9),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTD10),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTD11),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE12),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE13),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE14),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE15),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE16),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE17),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE18),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE19),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE20),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE21),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE22),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE23),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE24),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE25),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE26),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE27),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE28),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE29),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE30),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE31),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTE0),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTE1),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTE2),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTE3),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTE4),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTE5),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTE6),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTE7),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTE8),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTE9),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTE10),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTE11),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTE12),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTE13),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTE14),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTE15),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE32),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE33),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE34),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE35),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE36),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE37),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE38),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE39),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE40),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE41),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE42),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE43),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE44),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE45),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE46),
+ IMX_PINCTRL_PIN(ULP1_PAD_RESERVE47),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF0),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF1),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF2),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF3),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF4),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF5),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF6),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF7),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF8),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF9),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF10),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF11),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF12),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF13),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF14),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF15),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF16),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF17),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF18),
+ IMX_PINCTRL_PIN(ULP1_PAD_PTF19),
+};
+
+#define BM_MUX_MODE 0xf00
+#define BP_MUX_MODE 8
+
+static struct imx_pinctrl_soc_info imx7ulp_pinctrl_info_0 = {
+ .pins = imx7ulp_pinctrl_pads_0,
+ .npins = ARRAY_SIZE(imx7ulp_pinctrl_pads_0),
+ .flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG,
+ .mux_mask = BM_MUX_MODE,
+ .mux_shift = BP_MUX_MODE,
+ .ibe_bit = BIT(16),
+ .obe_bit = BIT(17),
+};
+
+static struct imx_pinctrl_soc_info imx7ulp_pinctrl_info_1 = {
+ .pins = imx7ulp_pinctrl_pads_1,
+ .npins = ARRAY_SIZE(imx7ulp_pinctrl_pads_1),
+ .flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG,
+ .mux_mask = BM_MUX_MODE,
+ .mux_shift = BP_MUX_MODE,
+ .ibe_bit = BIT(16),
+ .obe_bit = BIT(17),
+};
+
+static struct of_device_id imx7ulp_pinctrl_of_match[] = {
+ { .compatible = "fsl,imx7ulp-iomuxc-0", .data = &imx7ulp_pinctrl_info_0 },
+ { .compatible = "fsl,imx7ulp-iomuxc-1", .data = &imx7ulp_pinctrl_info_1,},
+ { /* sentinel */ }
+};
+
+static int imx7ulp_pinctrl_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct imx_pinctrl_soc_info *pinctrl_info;
+
+ match = of_match_device(imx7ulp_pinctrl_of_match, &pdev->dev);
+
+ if (!match)
+ return -ENODEV;
+
+ pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;
+
+ return imx_pinctrl_probe(pdev, pinctrl_info);
+}
+
+static int __maybe_unused imx7ulp_pinctrl_suspend(struct device *dev)
+{
+ return imx_pinctrl_suspend(dev);
+}
+
+static int __maybe_unused imx7ulp_pinctrl_resume(struct device *dev)
+{
+ return imx_pinctrl_resume(dev);
+}
+
+static const struct dev_pm_ops imx7ulp_pinctrl_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(imx7ulp_pinctrl_suspend,
+ imx7ulp_pinctrl_resume)
+};
+
+static struct platform_driver imx7ulp_pinctrl_driver = {
+ .driver = {
+ .name = "imx7ulp-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(imx7ulp_pinctrl_of_match),
+ .pm = &imx7ulp_pinctrl_pm_ops,
+ },
+ .probe = imx7ulp_pinctrl_probe,
+};
+
+static int __init imx7ulp_pinctrl_init(void)
+{
+ return platform_driver_register(&imx7ulp_pinctrl_driver);
+}
+arch_initcall(imx7ulp_pinctrl_init);
+
+static void __exit imx7ulp_pinctrl_exit(void)
+{
+ platform_driver_unregister(&imx7ulp_pinctrl_driver);
+}
+module_exit(imx7ulp_pinctrl_exit);
+
+MODULE_AUTHOR("Fugang Duan <fugang.duan@nxp.com>");
+MODULE_DESCRIPTION("Freescale imx7ulp pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/freescale/pinctrl-imx8mm.c b/drivers/pinctrl/freescale/pinctrl-imx8mm.c
new file mode 100644
index 000000000000..b88d5b9f5717
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-imx8mm.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-imx.h"
+
+enum imx8mm_pads {
+ MX8MM_PAD_RESERVE0 = 0,
+ MX8MM_PAD_RESERVE1 = 1,
+ MX8MM_PAD_RESERVE2 = 2,
+ MX8MM_PAD_RESERVE3 = 3,
+ MX8MM_PAD_RESERVE4 = 4,
+ MX8MM_PAD_RESERVE5 = 5,
+ MX8MM_PAD_RESERVE6 = 6,
+ MX8MM_PAD_RESERVE7 = 7,
+ MX8MM_PAD_RESERVE8 = 8,
+ MX8MM_PAD_RESERVE9 = 9,
+ MX8MM_IOMUXC_GPIO1_IO00 = 10,
+ MX8MM_IOMUXC_GPIO1_IO01 = 11,
+ MX8MM_IOMUXC_GPIO1_IO02 = 12,
+ MX8MM_IOMUXC_GPIO1_IO03 = 13,
+ MX8MM_IOMUXC_GPIO1_IO04 = 14,
+ MX8MM_IOMUXC_GPIO1_IO05 = 15,
+ MX8MM_IOMUXC_GPIO1_IO06 = 16,
+ MX8MM_IOMUXC_GPIO1_IO07 = 17,
+ MX8MM_IOMUXC_GPIO1_IO08 = 18,
+ MX8MM_IOMUXC_GPIO1_IO09 = 19,
+ MX8MM_IOMUXC_GPIO1_IO10 = 20,
+ MX8MM_IOMUXC_GPIO1_IO11 = 21,
+ MX8MM_IOMUXC_GPIO1_IO12 = 22,
+ MX8MM_IOMUXC_GPIO1_IO13 = 23,
+ MX8MM_IOMUXC_GPIO1_IO14 = 24,
+ MX8MM_IOMUXC_GPIO1_IO15 = 25,
+ MX8MM_IOMUXC_ENET_MDC = 26,
+ MX8MM_IOMUXC_ENET_MDIO = 27,
+ MX8MM_IOMUXC_ENET_TD3 = 28,
+ MX8MM_IOMUXC_ENET_TD2 = 29,
+ MX8MM_IOMUXC_ENET_TD1 = 30,
+ MX8MM_IOMUXC_ENET_TD0 = 31,
+ MX8MM_IOMUXC_ENET_TX_CTL = 32,
+ MX8MM_IOMUXC_ENET_TXC = 33,
+ MX8MM_IOMUXC_ENET_RX_CTL = 34,
+ MX8MM_IOMUXC_ENET_RXC = 35,
+ MX8MM_IOMUXC_ENET_RD0 = 36,
+ MX8MM_IOMUXC_ENET_RD1 = 37,
+ MX8MM_IOMUXC_ENET_RD2 = 38,
+ MX8MM_IOMUXC_ENET_RD3 = 39,
+ MX8MM_IOMUXC_SD1_CLK = 40,
+ MX8MM_IOMUXC_SD1_CMD = 41,
+ MX8MM_IOMUXC_SD1_DATA0 = 42,
+ MX8MM_IOMUXC_SD1_DATA1 = 43,
+ MX8MM_IOMUXC_SD1_DATA2 = 44,
+ MX8MM_IOMUXC_SD1_DATA3 = 45,
+ MX8MM_IOMUXC_SD1_DATA4 = 46,
+ MX8MM_IOMUXC_SD1_DATA5 = 47,
+ MX8MM_IOMUXC_SD1_DATA6 = 48,
+ MX8MM_IOMUXC_SD1_DATA7 = 49,
+ MX8MM_IOMUXC_SD1_RESET_B = 50,
+ MX8MM_IOMUXC_SD1_STROBE = 51,
+ MX8MM_IOMUXC_SD2_CD_B = 52,
+ MX8MM_IOMUXC_SD2_CLK = 53,
+ MX8MM_IOMUXC_SD2_CMD = 54,
+ MX8MM_IOMUXC_SD2_DATA0 = 55,
+ MX8MM_IOMUXC_SD2_DATA1 = 56,
+ MX8MM_IOMUXC_SD2_DATA2 = 57,
+ MX8MM_IOMUXC_SD2_DATA3 = 58,
+ MX8MM_IOMUXC_SD2_RESET_B = 59,
+ MX8MM_IOMUXC_SD2_WP = 60,
+ MX8MM_IOMUXC_NAND_ALE = 61,
+ MX8MM_IOMUXC_NAND_CE0 = 62,
+ MX8MM_IOMUXC_NAND_CE1 = 63,
+ MX8MM_IOMUXC_NAND_CE2 = 64,
+ MX8MM_IOMUXC_NAND_CE3 = 65,
+ MX8MM_IOMUXC_NAND_CLE = 66,
+ MX8MM_IOMUXC_NAND_DATA00 = 67,
+ MX8MM_IOMUXC_NAND_DATA01 = 68,
+ MX8MM_IOMUXC_NAND_DATA02 = 69,
+ MX8MM_IOMUXC_NAND_DATA03 = 70,
+ MX8MM_IOMUXC_NAND_DATA04 = 71,
+ MX8MM_IOMUXC_NAND_DATA05 = 72,
+ MX8MM_IOMUXC_NAND_DATA06 = 73,
+ MX8MM_IOMUXC_NAND_DATA07 = 74,
+ MX8MM_IOMUXC_NAND_DQS = 75,
+ MX8MM_IOMUXC_NAND_RE_B = 76,
+ MX8MM_IOMUXC_NAND_READY_B = 77,
+ MX8MM_IOMUXC_NAND_WE_B = 78,
+ MX8MM_IOMUXC_NAND_WP_B = 79,
+ MX8MM_IOMUXC_SAI5_RXFS = 80,
+ MX8MM_IOMUXC_SAI5_RXC = 81,
+ MX8MM_IOMUXC_SAI5_RXD0 = 82,
+ MX8MM_IOMUXC_SAI5_RXD1 = 83,
+ MX8MM_IOMUXC_SAI5_RXD2 = 84,
+ MX8MM_IOMUXC_SAI5_RXD3 = 85,
+ MX8MM_IOMUXC_SAI5_MCLK = 86,
+ MX8MM_IOMUXC_SAI1_RXFS = 87,
+ MX8MM_IOMUXC_SAI1_RXC = 88,
+ MX8MM_IOMUXC_SAI1_RXD0 = 89,
+ MX8MM_IOMUXC_SAI1_RXD1 = 90,
+ MX8MM_IOMUXC_SAI1_RXD2 = 91,
+ MX8MM_IOMUXC_SAI1_RXD3 = 92,
+ MX8MM_IOMUXC_SAI1_RXD4 = 93,
+ MX8MM_IOMUXC_SAI1_RXD5 = 94,
+ MX8MM_IOMUXC_SAI1_RXD6 = 95,
+ MX8MM_IOMUXC_SAI1_RXD7 = 96,
+ MX8MM_IOMUXC_SAI1_TXFS = 97,
+ MX8MM_IOMUXC_SAI1_TXC = 98,
+ MX8MM_IOMUXC_SAI1_TXD0 = 99,
+ MX8MM_IOMUXC_SAI1_TXD1 = 100,
+ MX8MM_IOMUXC_SAI1_TXD2 = 101,
+ MX8MM_IOMUXC_SAI1_TXD3 = 102,
+ MX8MM_IOMUXC_SAI1_TXD4 = 103,
+ MX8MM_IOMUXC_SAI1_TXD5 = 104,
+ MX8MM_IOMUXC_SAI1_TXD6 = 105,
+ MX8MM_IOMUXC_SAI1_TXD7 = 106,
+ MX8MM_IOMUXC_SAI1_MCLK = 107,
+ MX8MM_IOMUXC_SAI2_RXFS = 108,
+ MX8MM_IOMUXC_SAI2_RXC = 109,
+ MX8MM_IOMUXC_SAI2_RXD0 = 110,
+ MX8MM_IOMUXC_SAI2_TXFS = 111,
+ MX8MM_IOMUXC_SAI2_TXC = 112,
+ MX8MM_IOMUXC_SAI2_TXD0 = 113,
+ MX8MM_IOMUXC_SAI2_MCLK = 114,
+ MX8MM_IOMUXC_SAI3_RXFS = 115,
+ MX8MM_IOMUXC_SAI3_RXC = 116,
+ MX8MM_IOMUXC_SAI3_RXD = 117,
+ MX8MM_IOMUXC_SAI3_TXFS = 118,
+ MX8MM_IOMUXC_SAI3_TXC = 119,
+ MX8MM_IOMUXC_SAI3_TXD = 120,
+ MX8MM_IOMUXC_SAI3_MCLK = 121,
+ MX8MM_IOMUXC_SPDIF_TX = 122,
+ MX8MM_IOMUXC_SPDIF_RX = 123,
+ MX8MM_IOMUXC_SPDIF_EXT_CLK = 124,
+ MX8MM_IOMUXC_ECSPI1_SCLK = 125,
+ MX8MM_IOMUXC_ECSPI1_MOSI = 126,
+ MX8MM_IOMUXC_ECSPI1_MISO = 127,
+ MX8MM_IOMUXC_ECSPI1_SS0 = 128,
+ MX8MM_IOMUXC_ECSPI2_SCLK = 129,
+ MX8MM_IOMUXC_ECSPI2_MOSI = 130,
+ MX8MM_IOMUXC_ECSPI2_MISO = 131,
+ MX8MM_IOMUXC_ECSPI2_SS0 = 132,
+ MX8MM_IOMUXC_I2C1_SCL = 133,
+ MX8MM_IOMUXC_I2C1_SDA = 134,
+ MX8MM_IOMUXC_I2C2_SCL = 135,
+ MX8MM_IOMUXC_I2C2_SDA = 136,
+ MX8MM_IOMUXC_I2C3_SCL = 137,
+ MX8MM_IOMUXC_I2C3_SDA = 138,
+ MX8MM_IOMUXC_I2C4_SCL = 139,
+ MX8MM_IOMUXC_I2C4_SDA = 140,
+ MX8MM_IOMUXC_UART1_RXD = 141,
+ MX8MM_IOMUXC_UART1_TXD = 142,
+ MX8MM_IOMUXC_UART2_RXD = 143,
+ MX8MM_IOMUXC_UART2_TXD = 144,
+ MX8MM_IOMUXC_UART3_RXD = 145,
+ MX8MM_IOMUXC_UART3_TXD = 146,
+ MX8MM_IOMUXC_UART4_RXD = 147,
+ MX8MM_IOMUXC_UART4_TXD = 148,
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc imx8mm_pinctrl_pads[] = {
+ IMX_PINCTRL_PIN(MX8MM_PAD_RESERVE0),
+ IMX_PINCTRL_PIN(MX8MM_PAD_RESERVE1),
+ IMX_PINCTRL_PIN(MX8MM_PAD_RESERVE2),
+ IMX_PINCTRL_PIN(MX8MM_PAD_RESERVE3),
+ IMX_PINCTRL_PIN(MX8MM_PAD_RESERVE4),
+ IMX_PINCTRL_PIN(MX8MM_PAD_RESERVE5),
+ IMX_PINCTRL_PIN(MX8MM_PAD_RESERVE6),
+ IMX_PINCTRL_PIN(MX8MM_PAD_RESERVE7),
+ IMX_PINCTRL_PIN(MX8MM_PAD_RESERVE8),
+ IMX_PINCTRL_PIN(MX8MM_PAD_RESERVE9),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO00),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO01),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO02),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO03),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO04),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO05),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO06),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO07),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO08),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO09),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO10),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO11),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO12),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO13),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO14),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_GPIO1_IO15),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ENET_MDC),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ENET_MDIO),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ENET_TD3),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ENET_TD2),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ENET_TD1),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ENET_TD0),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ENET_TX_CTL),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ENET_TXC),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ENET_RX_CTL),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ENET_RXC),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ENET_RD0),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ENET_RD1),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ENET_RD2),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ENET_RD3),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD1_CLK),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD1_CMD),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD1_DATA0),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD1_DATA1),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD1_DATA2),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD1_DATA3),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD1_DATA4),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD1_DATA5),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD1_DATA6),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD1_DATA7),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD1_RESET_B),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD1_STROBE),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD2_CD_B),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD2_CLK),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD2_CMD),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD2_DATA0),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD2_DATA1),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD2_DATA2),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD2_DATA3),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD2_RESET_B),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SD2_WP),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_ALE),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_CE0),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_CE1),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_CE2),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_CE3),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_CLE),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_DATA00),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_DATA01),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_DATA02),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_DATA03),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_DATA04),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_DATA05),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_DATA06),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_DATA07),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_DQS),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_RE_B),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_READY_B),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_WE_B),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_NAND_WP_B),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI5_RXFS),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI5_RXC),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI5_RXD0),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI5_RXD1),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI5_RXD2),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI5_RXD3),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI5_MCLK),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_RXFS),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_RXC),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_RXD0),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_RXD1),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_RXD2),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_RXD3),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_RXD4),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_RXD5),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_RXD6),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_RXD7),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_TXFS),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_TXC),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_TXD0),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_TXD1),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_TXD2),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_TXD3),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_TXD4),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_TXD5),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_TXD6),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_TXD7),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI1_MCLK),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI2_RXFS),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI2_RXC),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI2_RXD0),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI2_TXFS),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI2_TXC),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI2_TXD0),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI2_MCLK),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI3_RXFS),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI3_RXC),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI3_RXD),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI3_TXFS),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI3_TXC),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI3_TXD),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SAI3_MCLK),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SPDIF_TX),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SPDIF_RX),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_SPDIF_EXT_CLK),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ECSPI1_SCLK),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ECSPI1_MOSI),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ECSPI1_MISO),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ECSPI1_SS0),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ECSPI2_SCLK),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ECSPI2_MOSI),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ECSPI2_MISO),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_ECSPI2_SS0),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_I2C1_SCL),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_I2C1_SDA),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_I2C2_SCL),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_I2C2_SDA),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_I2C3_SCL),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_I2C3_SDA),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_I2C4_SCL),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_I2C4_SDA),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_UART1_RXD),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_UART1_TXD),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_UART2_RXD),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_UART2_TXD),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_UART3_RXD),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_UART3_TXD),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_UART4_RXD),
+ IMX_PINCTRL_PIN(MX8MM_IOMUXC_UART4_TXD),
+};
+
+static struct imx_pinctrl_soc_info imx8mm_pinctrl_info = {
+ .pins = imx8mm_pinctrl_pads,
+ .npins = ARRAY_SIZE(imx8mm_pinctrl_pads),
+ .gpr_compatible = "fsl,imx8mm-iomuxc-gpr",
+};
+
+static struct of_device_id imx8mm_pinctrl_of_match[] = {
+ { .compatible = "fsl,imx8mm-iomuxc", .data = &imx8mm_pinctrl_info, },
+ { /* sentinel */ }
+};
+
+static int imx8mm_pinctrl_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct imx_pinctrl_soc_info *pinctrl_info;
+
+ match = of_match_device(imx8mm_pinctrl_of_match, &pdev->dev);
+
+ if (!match)
+ return -ENODEV;
+
+ pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;
+
+ return imx_pinctrl_probe(pdev, pinctrl_info);
+}
+
+static int imx8mm_pinctrl_suspend(struct device *dev)
+{
+
+ return imx_pinctrl_suspend(dev);
+}
+
+static int imx8mm_pinctrl_resume(struct device *dev)
+{
+
+ return imx_pinctrl_resume(dev);
+}
+
+static const struct dev_pm_ops imx8mm_pinctrl_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(imx8mm_pinctrl_suspend, imx8mm_pinctrl_resume)
+};
+
+static struct platform_driver imx8mm_pinctrl_driver = {
+ .driver = {
+ .name = "imx8mm-pinctrl",
+ .of_match_table = of_match_ptr(imx8mm_pinctrl_of_match),
+ .pm = &imx8mm_pinctrl_pm_ops,
+ },
+ .probe = imx8mm_pinctrl_probe,
+};
+
+static int __init imx8mm_pinctrl_init(void)
+{
+ return platform_driver_register(&imx8mm_pinctrl_driver);
+}
+arch_initcall(imx8mm_pinctrl_init);
diff --git a/drivers/pinctrl/freescale/pinctrl-imx8mq.c b/drivers/pinctrl/freescale/pinctrl-imx8mq.c
new file mode 100644
index 000000000000..06585061cfa8
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-imx8mq.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-imx.h"
+
+enum imx8mq_pads {
+ MX8MQ_PAD_RESERVE0 = 0,
+ MX8MQ_PAD_RESERVE1 = 1,
+ MX8MQ_PAD_RESERVE2 = 2,
+ MX8MQ_PAD_RESERVE3 = 3,
+ MX8MQ_PAD_RESERVE4 = 4,
+ MX8MQ_IOMUXC_PMIC_STBY_REQ_CCMSRCGPCMIX = 5,
+ MX8MQ_IOMUXC_PMIC_ON_REQ_SNVSMIX = 6,
+ MX8MQ_IOMUXC_ONOFF_SNVSMIX = 7,
+ MX8MQ_IOMUXC_POR_B_SNVSMIX = 8,
+ MX8MQ_IOMUXC_RTC_RESET_B_SNVSMIX = 9,
+ MX8MQ_IOMUXC_GPIO1_IO00 = 10,
+ MX8MQ_IOMUXC_GPIO1_IO01 = 11,
+ MX8MQ_IOMUXC_GPIO1_IO02 = 12,
+ MX8MQ_IOMUXC_GPIO1_IO03 = 13,
+ MX8MQ_IOMUXC_GPIO1_IO04 = 14,
+ MX8MQ_IOMUXC_GPIO1_IO05 = 15,
+ MX8MQ_IOMUXC_GPIO1_IO06 = 16,
+ MX8MQ_IOMUXC_GPIO1_IO07 = 17,
+ MX8MQ_IOMUXC_GPIO1_IO08 = 18,
+ MX8MQ_IOMUXC_GPIO1_IO09 = 19,
+ MX8MQ_IOMUXC_GPIO1_IO10 = 20,
+ MX8MQ_IOMUXC_GPIO1_IO11 = 21,
+ MX8MQ_IOMUXC_GPIO1_IO12 = 22,
+ MX8MQ_IOMUXC_GPIO1_IO13 = 23,
+ MX8MQ_IOMUXC_GPIO1_IO14 = 24,
+ MX8MQ_IOMUXC_GPIO1_IO15 = 25,
+ MX8MQ_IOMUXC_ENET_MDC = 26,
+ MX8MQ_IOMUXC_ENET_MDIO = 27,
+ MX8MQ_IOMUXC_ENET_TD3 = 28,
+ MX8MQ_IOMUXC_ENET_TD2 = 29,
+ MX8MQ_IOMUXC_ENET_TD1 = 30,
+ MX8MQ_IOMUXC_ENET_TD0 = 31,
+ MX8MQ_IOMUXC_ENET_TX_CTL = 32,
+ MX8MQ_IOMUXC_ENET_TXC = 33,
+ MX8MQ_IOMUXC_ENET_RX_CTL = 34,
+ MX8MQ_IOMUXC_ENET_RXC = 35,
+ MX8MQ_IOMUXC_ENET_RD0 = 36,
+ MX8MQ_IOMUXC_ENET_RD1 = 37,
+ MX8MQ_IOMUXC_ENET_RD2 = 38,
+ MX8MQ_IOMUXC_ENET_RD3 = 39,
+ MX8MQ_IOMUXC_SD1_CLK = 40,
+ MX8MQ_IOMUXC_SD1_CMD = 41,
+ MX8MQ_IOMUXC_SD1_DATA0 = 42,
+ MX8MQ_IOMUXC_SD1_DATA1 = 43,
+ MX8MQ_IOMUXC_SD1_DATA2 = 44,
+ MX8MQ_IOMUXC_SD1_DATA3 = 45,
+ MX8MQ_IOMUXC_SD1_DATA4 = 46,
+ MX8MQ_IOMUXC_SD1_DATA5 = 47,
+ MX8MQ_IOMUXC_SD1_DATA6 = 48,
+ MX8MQ_IOMUXC_SD1_DATA7 = 49,
+ MX8MQ_IOMUXC_SD1_RESET_B = 50,
+ MX8MQ_IOMUXC_SD1_STROBE = 51,
+ MX8MQ_IOMUXC_SD2_CD_B = 52,
+ MX8MQ_IOMUXC_SD2_CLK = 53,
+ MX8MQ_IOMUXC_SD2_CMD = 54,
+ MX8MQ_IOMUXC_SD2_DATA0 = 55,
+ MX8MQ_IOMUXC_SD2_DATA1 = 56,
+ MX8MQ_IOMUXC_SD2_DATA2 = 57,
+ MX8MQ_IOMUXC_SD2_DATA3 = 58,
+ MX8MQ_IOMUXC_SD2_RESET_B = 59,
+ MX8MQ_IOMUXC_SD2_WP = 60,
+ MX8MQ_IOMUXC_NAND_ALE = 61,
+ MX8MQ_IOMUXC_NAND_CE0_B = 62,
+ MX8MQ_IOMUXC_NAND_CE1_B = 63,
+ MX8MQ_IOMUXC_NAND_CE2_B = 64,
+ MX8MQ_IOMUXC_NAND_CE3_B = 65,
+ MX8MQ_IOMUXC_NAND_CLE = 66,
+ MX8MQ_IOMUXC_NAND_DATA00 = 67,
+ MX8MQ_IOMUXC_NAND_DATA01 = 68,
+ MX8MQ_IOMUXC_NAND_DATA02 = 69,
+ MX8MQ_IOMUXC_NAND_DATA03 = 70,
+ MX8MQ_IOMUXC_NAND_DATA04 = 71,
+ MX8MQ_IOMUXC_NAND_DATA05 = 72,
+ MX8MQ_IOMUXC_NAND_DATA06 = 73,
+ MX8MQ_IOMUXC_NAND_DATA07 = 74,
+ MX8MQ_IOMUXC_NAND_DQS = 75,
+ MX8MQ_IOMUXC_NAND_RE_B = 76,
+ MX8MQ_IOMUXC_NAND_READY_B = 77,
+ MX8MQ_IOMUXC_NAND_WE_B = 78,
+ MX8MQ_IOMUXC_NAND_WP_B = 79,
+ MX8MQ_IOMUXC_SAI5_RXFS = 80,
+ MX8MQ_IOMUXC_SAI5_RXC = 81,
+ MX8MQ_IOMUXC_SAI5_RXD0 = 82,
+ MX8MQ_IOMUXC_SAI5_RXD1 = 83,
+ MX8MQ_IOMUXC_SAI5_RXD2 = 84,
+ MX8MQ_IOMUXC_SAI5_RXD3 = 85,
+ MX8MQ_IOMUXC_SAI5_MCLK = 86,
+ MX8MQ_IOMUXC_SAI1_RXFS = 87,
+ MX8MQ_IOMUXC_SAI1_RXC = 88,
+ MX8MQ_IOMUXC_SAI1_RXD0 = 89,
+ MX8MQ_IOMUXC_SAI1_RXD1 = 90,
+ MX8MQ_IOMUXC_SAI1_RXD2 = 91,
+ MX8MQ_IOMUXC_SAI1_RXD3 = 92,
+ MX8MQ_IOMUXC_SAI1_RXD4 = 93,
+ MX8MQ_IOMUXC_SAI1_RXD5 = 94,
+ MX8MQ_IOMUXC_SAI1_RXD6 = 95,
+ MX8MQ_IOMUXC_SAI1_RXD7 = 96,
+ MX8MQ_IOMUXC_SAI1_TXFS = 97,
+ MX8MQ_IOMUXC_SAI1_TXC = 98,
+ MX8MQ_IOMUXC_SAI1_TXD0 = 99,
+ MX8MQ_IOMUXC_SAI1_TXD1 = 100,
+ MX8MQ_IOMUXC_SAI1_TXD2 = 101,
+ MX8MQ_IOMUXC_SAI1_TXD3 = 102,
+ MX8MQ_IOMUXC_SAI1_TXD4 = 103,
+ MX8MQ_IOMUXC_SAI1_TXD5 = 104,
+ MX8MQ_IOMUXC_SAI1_TXD6 = 105,
+ MX8MQ_IOMUXC_SAI1_TXD7 = 106,
+ MX8MQ_IOMUXC_SAI1_MCLK = 107,
+ MX8MQ_IOMUXC_SAI2_RXFS = 108,
+ MX8MQ_IOMUXC_SAI2_RXC = 109,
+ MX8MQ_IOMUXC_SAI2_RXD0 = 110,
+ MX8MQ_IOMUXC_SAI2_TXFS = 111,
+ MX8MQ_IOMUXC_SAI2_TXC = 112,
+ MX8MQ_IOMUXC_SAI2_TXD0 = 113,
+ MX8MQ_IOMUXC_SAI2_MCLK = 114,
+ MX8MQ_IOMUXC_SAI3_RXFS = 115,
+ MX8MQ_IOMUXC_SAI3_RXC = 116,
+ MX8MQ_IOMUXC_SAI3_RXD = 117,
+ MX8MQ_IOMUXC_SAI3_TXFS = 118,
+ MX8MQ_IOMUXC_SAI3_TXC = 119,
+ MX8MQ_IOMUXC_SAI3_TXD = 120,
+ MX8MQ_IOMUXC_SAI3_MCLK = 121,
+ MX8MQ_IOMUXC_SPDIF_TX = 122,
+ MX8MQ_IOMUXC_SPDIF_RX = 123,
+ MX8MQ_IOMUXC_SPDIF_EXT_CLK = 124,
+ MX8MQ_IOMUXC_ECSPI1_SCLK = 125,
+ MX8MQ_IOMUXC_ECSPI1_MOSI = 126,
+ MX8MQ_IOMUXC_ECSPI1_MISO = 127,
+ MX8MQ_IOMUXC_ECSPI1_SS0 = 128,
+ MX8MQ_IOMUXC_ECSPI2_SCLK = 129,
+ MX8MQ_IOMUXC_ECSPI2_MOSI = 130,
+ MX8MQ_IOMUXC_ECSPI2_MISO = 131,
+ MX8MQ_IOMUXC_ECSPI2_SS0 = 132,
+ MX8MQ_IOMUXC_I2C1_SCL = 133,
+ MX8MQ_IOMUXC_I2C1_SDA = 134,
+ MX8MQ_IOMUXC_I2C2_SCL = 135,
+ MX8MQ_IOMUXC_I2C2_SDA = 136,
+ MX8MQ_IOMUXC_I2C3_SCL = 137,
+ MX8MQ_IOMUXC_I2C3_SDA = 138,
+ MX8MQ_IOMUXC_I2C4_SCL = 139,
+ MX8MQ_IOMUXC_I2C4_SDA = 140,
+ MX8MQ_IOMUXC_UART1_RXD = 141,
+ MX8MQ_IOMUXC_UART1_TXD = 142,
+ MX8MQ_IOMUXC_UART2_RXD = 143,
+ MX8MQ_IOMUXC_UART2_TXD = 144,
+ MX8MQ_IOMUXC_UART3_RXD = 145,
+ MX8MQ_IOMUXC_UART3_TXD = 146,
+ MX8MQ_IOMUXC_UART4_RXD = 147,
+ MX8MQ_IOMUXC_UART4_TXD = 148,
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc imx8mq_pinctrl_pads[] = {
+ IMX_PINCTRL_PIN(MX8MQ_PAD_RESERVE0),
+ IMX_PINCTRL_PIN(MX8MQ_PAD_RESERVE1),
+ IMX_PINCTRL_PIN(MX8MQ_PAD_RESERVE2),
+ IMX_PINCTRL_PIN(MX8MQ_PAD_RESERVE3),
+ IMX_PINCTRL_PIN(MX8MQ_PAD_RESERVE4),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_PMIC_STBY_REQ_CCMSRCGPCMIX),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_PMIC_ON_REQ_SNVSMIX),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ONOFF_SNVSMIX),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_POR_B_SNVSMIX),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_RTC_RESET_B_SNVSMIX),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_GPIO1_IO00),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_GPIO1_IO01),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_GPIO1_IO02),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_GPIO1_IO03),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_GPIO1_IO04),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_GPIO1_IO05),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_GPIO1_IO06),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_GPIO1_IO07),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_GPIO1_IO08),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_GPIO1_IO09),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_GPIO1_IO10),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_GPIO1_IO11),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_GPIO1_IO12),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_GPIO1_IO13),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_GPIO1_IO14),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_GPIO1_IO15),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ENET_MDC),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ENET_MDIO),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ENET_TD3),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ENET_TD2),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ENET_TD1),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ENET_TD0),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ENET_TX_CTL),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ENET_TXC),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ENET_RX_CTL),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ENET_RXC),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ENET_RD0),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ENET_RD1),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ENET_RD2),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ENET_RD3),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD1_CLK),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD1_CMD),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD1_DATA0),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD1_DATA1),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD1_DATA2),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD1_DATA3),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD1_DATA4),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD1_DATA5),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD1_DATA6),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD1_DATA7),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD1_RESET_B),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD1_STROBE),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD2_CD_B),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD2_CLK),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD2_CMD),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD2_DATA0),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD2_DATA1),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD2_DATA2),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD2_DATA3),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD2_RESET_B),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SD2_WP),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_ALE),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_CE0_B),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_CE1_B),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_CE2_B),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_CE3_B),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_CLE),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_DATA00),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_DATA01),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_DATA02),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_DATA03),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_DATA04),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_DATA05),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_DATA06),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_DATA07),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_DQS),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_RE_B),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_READY_B),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_WE_B),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_NAND_WP_B),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI5_RXFS),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI5_RXC),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI5_RXD0),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI5_RXD1),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI5_RXD2),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI5_RXD3),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI5_MCLK),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_RXFS),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_RXC),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_RXD0),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_RXD1),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_RXD2),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_RXD3),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_RXD4),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_RXD5),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_RXD6),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_RXD7),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_TXFS),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_TXC),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_TXD0),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_TXD1),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_TXD2),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_TXD3),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_TXD4),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_TXD5),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_TXD6),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_TXD7),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI1_MCLK),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI2_RXFS),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI2_RXC),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI2_RXD0),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI2_TXFS),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI2_TXC),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI2_TXD0),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI2_MCLK),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI3_RXFS),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI3_RXC),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI3_RXD),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI3_TXFS),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI3_TXC),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI3_TXD),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SAI3_MCLK),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SPDIF_TX),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SPDIF_RX),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_SPDIF_EXT_CLK),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ECSPI1_SCLK),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ECSPI1_MOSI),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ECSPI1_MISO),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ECSPI1_SS0),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ECSPI2_SCLK),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ECSPI2_MOSI),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ECSPI2_MISO),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_ECSPI2_SS0),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_I2C1_SCL),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_I2C1_SDA),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_I2C2_SCL),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_I2C2_SDA),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_I2C3_SCL),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_I2C3_SDA),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_I2C4_SCL),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_I2C4_SDA),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_UART1_RXD),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_UART1_TXD),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_UART2_RXD),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_UART2_TXD),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_UART3_RXD),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_UART3_TXD),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_UART4_RXD),
+ IMX_PINCTRL_PIN(MX8MQ_IOMUXC_UART4_TXD),
+};
+
+static struct imx_pinctrl_soc_info imx8mq_pinctrl_info = {
+ .pins = imx8mq_pinctrl_pads,
+ .npins = ARRAY_SIZE(imx8mq_pinctrl_pads),
+ .gpr_compatible = "fsl,imx8mq-iomuxc-gpr",
+};
+
+static struct of_device_id imx8mq_pinctrl_of_match[] = {
+ { .compatible = "fsl,imx8mq-iomuxc", .data = &imx8mq_pinctrl_info, },
+ { /* sentinel */ }
+};
+
+static int imx8mq_pinctrl_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct imx_pinctrl_soc_info *pinctrl_info;
+
+ match = of_match_device(imx8mq_pinctrl_of_match, &pdev->dev);
+
+ if (!match)
+ return -ENODEV;
+
+ pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;
+
+ return imx_pinctrl_probe(pdev, pinctrl_info);
+}
+
+static int imx8mq_pinctrl_suspend(struct device *dev)
+{
+
+ return imx_pinctrl_suspend(dev);
+}
+
+static int imx8mq_pinctrl_resume(struct device *dev)
+{
+
+ return imx_pinctrl_resume(dev);
+}
+
+static const struct dev_pm_ops imx8mq_pinctrl_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(imx8mq_pinctrl_suspend, imx8mq_pinctrl_resume)
+};
+
+static struct platform_driver imx8mq_pinctrl_driver = {
+ .driver = {
+ .name = "imx8mq-pinctrl",
+ .of_match_table = of_match_ptr(imx8mq_pinctrl_of_match),
+ .pm = &imx8mq_pinctrl_pm_ops,
+ },
+ .probe = imx8mq_pinctrl_probe,
+};
+
+static int __init imx8mq_pinctrl_init(void)
+{
+ return platform_driver_register(&imx8mq_pinctrl_driver);
+}
+arch_initcall(imx8mq_pinctrl_init);
diff --git a/drivers/pinctrl/freescale/pinctrl-imx8qm.c b/drivers/pinctrl/freescale/pinctrl-imx8qm.c
new file mode 100644
index 000000000000..665c0b4429ef
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-imx8qm.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <dt-bindings/pinctrl/pads-imx8qm.h>
+#include <soc/imx8/sc/sci.h>
+
+#include "pinctrl-imx.h"
+
+extern sc_ipc_t pinctrl_ipcHandle;
+
+static const struct pinctrl_pin_desc imx8qm_pinctrl_pads[] = {
+ IMX_PINCTRL_PIN(SC_P_SIM0_CLK),
+ IMX_PINCTRL_PIN(SC_P_SIM0_RST),
+ IMX_PINCTRL_PIN(SC_P_SIM0_IO),
+ IMX_PINCTRL_PIN(SC_P_SIM0_PD),
+ IMX_PINCTRL_PIN(SC_P_SIM0_POWER_EN),
+ IMX_PINCTRL_PIN(SC_P_SIM0_GPIO0_00),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_SIM),
+ IMX_PINCTRL_PIN(SC_P_M40_I2C0_SCL),
+ IMX_PINCTRL_PIN(SC_P_M40_I2C0_SDA),
+ IMX_PINCTRL_PIN(SC_P_M40_GPIO0_00),
+ IMX_PINCTRL_PIN(SC_P_M40_GPIO0_01),
+ IMX_PINCTRL_PIN(SC_P_M41_I2C0_SCL),
+ IMX_PINCTRL_PIN(SC_P_M41_I2C0_SDA),
+ IMX_PINCTRL_PIN(SC_P_M41_GPIO0_00),
+ IMX_PINCTRL_PIN(SC_P_M41_GPIO0_01),
+ IMX_PINCTRL_PIN(SC_P_GPT0_CLK),
+ IMX_PINCTRL_PIN(SC_P_GPT0_CAPTURE),
+ IMX_PINCTRL_PIN(SC_P_GPT0_COMPARE),
+ IMX_PINCTRL_PIN(SC_P_GPT1_CLK),
+ IMX_PINCTRL_PIN(SC_P_GPT1_CAPTURE),
+ IMX_PINCTRL_PIN(SC_P_GPT1_COMPARE),
+ IMX_PINCTRL_PIN(SC_P_UART0_RX),
+ IMX_PINCTRL_PIN(SC_P_UART0_TX),
+ IMX_PINCTRL_PIN(SC_P_UART0_RTS_B),
+ IMX_PINCTRL_PIN(SC_P_UART0_CTS_B),
+ IMX_PINCTRL_PIN(SC_P_UART1_TX),
+ IMX_PINCTRL_PIN(SC_P_UART1_RX),
+ IMX_PINCTRL_PIN(SC_P_UART1_RTS_B),
+ IMX_PINCTRL_PIN(SC_P_UART1_CTS_B),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOLH),
+ IMX_PINCTRL_PIN(SC_P_SCU_PMIC_MEMC_ON),
+ IMX_PINCTRL_PIN(SC_P_SCU_WDOG_OUT),
+ IMX_PINCTRL_PIN(SC_P_PMIC_I2C_SDA),
+ IMX_PINCTRL_PIN(SC_P_PMIC_I2C_SCL),
+ IMX_PINCTRL_PIN(SC_P_PMIC_EARLY_WARNING),
+ IMX_PINCTRL_PIN(SC_P_PMIC_INT_B),
+ IMX_PINCTRL_PIN(SC_P_SCU_GPIO0_00),
+ IMX_PINCTRL_PIN(SC_P_SCU_GPIO0_01),
+ IMX_PINCTRL_PIN(SC_P_SCU_GPIO0_02),
+ IMX_PINCTRL_PIN(SC_P_SCU_GPIO0_03),
+ IMX_PINCTRL_PIN(SC_P_SCU_GPIO0_04),
+ IMX_PINCTRL_PIN(SC_P_SCU_GPIO0_05),
+ IMX_PINCTRL_PIN(SC_P_SCU_GPIO0_06),
+ IMX_PINCTRL_PIN(SC_P_SCU_GPIO0_07),
+ IMX_PINCTRL_PIN(SC_P_SCU_BOOT_MODE0),
+ IMX_PINCTRL_PIN(SC_P_SCU_BOOT_MODE1),
+ IMX_PINCTRL_PIN(SC_P_SCU_BOOT_MODE2),
+ IMX_PINCTRL_PIN(SC_P_SCU_BOOT_MODE3),
+ IMX_PINCTRL_PIN(SC_P_SCU_BOOT_MODE4),
+ IMX_PINCTRL_PIN(SC_P_SCU_BOOT_MODE5),
+ IMX_PINCTRL_PIN(SC_P_LVDS0_GPIO00),
+ IMX_PINCTRL_PIN(SC_P_LVDS0_GPIO01),
+ IMX_PINCTRL_PIN(SC_P_LVDS0_I2C0_SCL),
+ IMX_PINCTRL_PIN(SC_P_LVDS0_I2C0_SDA),
+ IMX_PINCTRL_PIN(SC_P_LVDS0_I2C1_SCL),
+ IMX_PINCTRL_PIN(SC_P_LVDS0_I2C1_SDA),
+ IMX_PINCTRL_PIN(SC_P_LVDS1_GPIO00),
+ IMX_PINCTRL_PIN(SC_P_LVDS1_GPIO01),
+ IMX_PINCTRL_PIN(SC_P_LVDS1_I2C0_SCL),
+ IMX_PINCTRL_PIN(SC_P_LVDS1_I2C0_SDA),
+ IMX_PINCTRL_PIN(SC_P_LVDS1_I2C1_SCL),
+ IMX_PINCTRL_PIN(SC_P_LVDS1_I2C1_SDA),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_LVDSGPIO),
+ IMX_PINCTRL_PIN(SC_P_MIPI_DSI0_I2C0_SCL),
+ IMX_PINCTRL_PIN(SC_P_MIPI_DSI0_I2C0_SDA),
+ IMX_PINCTRL_PIN(SC_P_MIPI_DSI0_GPIO0_00),
+ IMX_PINCTRL_PIN(SC_P_MIPI_DSI0_GPIO0_01),
+ IMX_PINCTRL_PIN(SC_P_MIPI_DSI1_I2C0_SCL),
+ IMX_PINCTRL_PIN(SC_P_MIPI_DSI1_I2C0_SDA),
+ IMX_PINCTRL_PIN(SC_P_MIPI_DSI1_GPIO0_00),
+ IMX_PINCTRL_PIN(SC_P_MIPI_DSI1_GPIO0_01),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_MIPIDSIGPIO),
+ IMX_PINCTRL_PIN(SC_P_MIPI_CSI0_MCLK_OUT),
+ IMX_PINCTRL_PIN(SC_P_MIPI_CSI0_I2C0_SCL),
+ IMX_PINCTRL_PIN(SC_P_MIPI_CSI0_I2C0_SDA),
+ IMX_PINCTRL_PIN(SC_P_MIPI_CSI0_GPIO0_00),
+ IMX_PINCTRL_PIN(SC_P_MIPI_CSI0_GPIO0_01),
+ IMX_PINCTRL_PIN(SC_P_MIPI_CSI1_MCLK_OUT),
+ IMX_PINCTRL_PIN(SC_P_MIPI_CSI1_GPIO0_00),
+ IMX_PINCTRL_PIN(SC_P_MIPI_CSI1_GPIO0_01),
+ IMX_PINCTRL_PIN(SC_P_MIPI_CSI1_I2C0_SCL),
+ IMX_PINCTRL_PIN(SC_P_MIPI_CSI1_I2C0_SDA),
+ IMX_PINCTRL_PIN(SC_P_HDMI_TX0_TS_SCL),
+ IMX_PINCTRL_PIN(SC_P_HDMI_TX0_TS_SDA),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_3V3_HDMIGPIO),
+ IMX_PINCTRL_PIN(SC_P_ESAI1_FSR),
+ IMX_PINCTRL_PIN(SC_P_ESAI1_FST),
+ IMX_PINCTRL_PIN(SC_P_ESAI1_SCKR),
+ IMX_PINCTRL_PIN(SC_P_ESAI1_SCKT),
+ IMX_PINCTRL_PIN(SC_P_ESAI1_TX0),
+ IMX_PINCTRL_PIN(SC_P_ESAI1_TX1),
+ IMX_PINCTRL_PIN(SC_P_ESAI1_TX2_RX3),
+ IMX_PINCTRL_PIN(SC_P_ESAI1_TX3_RX2),
+ IMX_PINCTRL_PIN(SC_P_ESAI1_TX4_RX1),
+ IMX_PINCTRL_PIN(SC_P_ESAI1_TX5_RX0),
+ IMX_PINCTRL_PIN(SC_P_SPDIF0_RX),
+ IMX_PINCTRL_PIN(SC_P_SPDIF0_TX),
+ IMX_PINCTRL_PIN(SC_P_SPDIF0_EXT_CLK),
+ IMX_PINCTRL_PIN(SC_P_SPI3_SCK),
+ IMX_PINCTRL_PIN(SC_P_SPI3_SDO),
+ IMX_PINCTRL_PIN(SC_P_SPI3_SDI),
+ IMX_PINCTRL_PIN(SC_P_SPI3_CS0),
+ IMX_PINCTRL_PIN(SC_P_SPI3_CS1),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHB),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_FSR),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_FST),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_SCKR),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_SCKT),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_TX0),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_TX1),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_TX2_RX3),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_TX3_RX2),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_TX4_RX1),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_TX5_RX0),
+ IMX_PINCTRL_PIN(SC_P_MCLK_IN0),
+ IMX_PINCTRL_PIN(SC_P_MCLK_OUT0),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHC),
+ IMX_PINCTRL_PIN(SC_P_SPI0_SCK),
+ IMX_PINCTRL_PIN(SC_P_SPI0_SDO),
+ IMX_PINCTRL_PIN(SC_P_SPI0_SDI),
+ IMX_PINCTRL_PIN(SC_P_SPI0_CS0),
+ IMX_PINCTRL_PIN(SC_P_SPI0_CS1),
+ IMX_PINCTRL_PIN(SC_P_SPI2_SCK),
+ IMX_PINCTRL_PIN(SC_P_SPI2_SDO),
+ IMX_PINCTRL_PIN(SC_P_SPI2_SDI),
+ IMX_PINCTRL_PIN(SC_P_SPI2_CS0),
+ IMX_PINCTRL_PIN(SC_P_SPI2_CS1),
+ IMX_PINCTRL_PIN(SC_P_SAI1_RXC),
+ IMX_PINCTRL_PIN(SC_P_SAI1_RXD),
+ IMX_PINCTRL_PIN(SC_P_SAI1_RXFS),
+ IMX_PINCTRL_PIN(SC_P_SAI1_TXC),
+ IMX_PINCTRL_PIN(SC_P_SAI1_TXD),
+ IMX_PINCTRL_PIN(SC_P_SAI1_TXFS),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHT),
+ IMX_PINCTRL_PIN(SC_P_ADC_IN7),
+ IMX_PINCTRL_PIN(SC_P_ADC_IN6),
+ IMX_PINCTRL_PIN(SC_P_ADC_IN5),
+ IMX_PINCTRL_PIN(SC_P_ADC_IN4),
+ IMX_PINCTRL_PIN(SC_P_ADC_IN3),
+ IMX_PINCTRL_PIN(SC_P_ADC_IN2),
+ IMX_PINCTRL_PIN(SC_P_ADC_IN1),
+ IMX_PINCTRL_PIN(SC_P_ADC_IN0),
+ IMX_PINCTRL_PIN(SC_P_MLB_SIG),
+ IMX_PINCTRL_PIN(SC_P_MLB_CLK),
+ IMX_PINCTRL_PIN(SC_P_MLB_DATA),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOLHT),
+ IMX_PINCTRL_PIN(SC_P_FLEXCAN0_RX),
+ IMX_PINCTRL_PIN(SC_P_FLEXCAN0_TX),
+ IMX_PINCTRL_PIN(SC_P_FLEXCAN1_RX),
+ IMX_PINCTRL_PIN(SC_P_FLEXCAN1_TX),
+ IMX_PINCTRL_PIN(SC_P_FLEXCAN2_RX),
+ IMX_PINCTRL_PIN(SC_P_FLEXCAN2_TX),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOTHR),
+ IMX_PINCTRL_PIN(SC_P_USB_SS3_TC0),
+ IMX_PINCTRL_PIN(SC_P_USB_SS3_TC1),
+ IMX_PINCTRL_PIN(SC_P_USB_SS3_TC2),
+ IMX_PINCTRL_PIN(SC_P_USB_SS3_TC3),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_3V3_USB3IO),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_RESET_B),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_VSELECT),
+ IMX_PINCTRL_PIN(SC_P_USDHC2_RESET_B),
+ IMX_PINCTRL_PIN(SC_P_USDHC2_VSELECT),
+ IMX_PINCTRL_PIN(SC_P_USDHC2_WP),
+ IMX_PINCTRL_PIN(SC_P_USDHC2_CD_B),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_VSELSEP),
+ IMX_PINCTRL_PIN(SC_P_ENET0_MDIO),
+ IMX_PINCTRL_PIN(SC_P_ENET0_MDC),
+ IMX_PINCTRL_PIN(SC_P_ENET0_REFCLK_125M_25M),
+ IMX_PINCTRL_PIN(SC_P_ENET1_REFCLK_125M_25M),
+ IMX_PINCTRL_PIN(SC_P_ENET1_MDIO),
+ IMX_PINCTRL_PIN(SC_P_ENET1_MDC),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOCT),
+ IMX_PINCTRL_PIN(SC_P_QSPI1A_SS0_B),
+ IMX_PINCTRL_PIN(SC_P_QSPI1A_SS1_B),
+ IMX_PINCTRL_PIN(SC_P_QSPI1A_SCLK),
+ IMX_PINCTRL_PIN(SC_P_QSPI1A_DQS),
+ IMX_PINCTRL_PIN(SC_P_QSPI1A_DATA3),
+ IMX_PINCTRL_PIN(SC_P_QSPI1A_DATA2),
+ IMX_PINCTRL_PIN(SC_P_QSPI1A_DATA1),
+ IMX_PINCTRL_PIN(SC_P_QSPI1A_DATA0),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_QSPI1),
+ IMX_PINCTRL_PIN(SC_P_QSPI0A_DATA0),
+ IMX_PINCTRL_PIN(SC_P_QSPI0A_DATA1),
+ IMX_PINCTRL_PIN(SC_P_QSPI0A_DATA2),
+ IMX_PINCTRL_PIN(SC_P_QSPI0A_DATA3),
+ IMX_PINCTRL_PIN(SC_P_QSPI0A_DQS),
+ IMX_PINCTRL_PIN(SC_P_QSPI0A_SS0_B),
+ IMX_PINCTRL_PIN(SC_P_QSPI0A_SS1_B),
+ IMX_PINCTRL_PIN(SC_P_QSPI0A_SCLK),
+ IMX_PINCTRL_PIN(SC_P_QSPI0B_SCLK),
+ IMX_PINCTRL_PIN(SC_P_QSPI0B_DATA0),
+ IMX_PINCTRL_PIN(SC_P_QSPI0B_DATA1),
+ IMX_PINCTRL_PIN(SC_P_QSPI0B_DATA2),
+ IMX_PINCTRL_PIN(SC_P_QSPI0B_DATA3),
+ IMX_PINCTRL_PIN(SC_P_QSPI0B_DQS),
+ IMX_PINCTRL_PIN(SC_P_QSPI0B_SS0_B),
+ IMX_PINCTRL_PIN(SC_P_QSPI0B_SS1_B),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_QSPI0),
+ IMX_PINCTRL_PIN(SC_P_PCIE_CTRL0_CLKREQ_B),
+ IMX_PINCTRL_PIN(SC_P_PCIE_CTRL0_WAKE_B),
+ IMX_PINCTRL_PIN(SC_P_PCIE_CTRL0_PERST_B),
+ IMX_PINCTRL_PIN(SC_P_PCIE_CTRL1_CLKREQ_B),
+ IMX_PINCTRL_PIN(SC_P_PCIE_CTRL1_WAKE_B),
+ IMX_PINCTRL_PIN(SC_P_PCIE_CTRL1_PERST_B),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_PCIESEP),
+ IMX_PINCTRL_PIN(SC_P_USB_HSIC0_DATA),
+ IMX_PINCTRL_PIN(SC_P_USB_HSIC0_STROBE),
+ IMX_PINCTRL_PIN(SC_P_CALIBRATION_0_HSIC),
+ IMX_PINCTRL_PIN(SC_P_CALIBRATION_1_HSIC),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_CLK),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_CMD),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_DATA0),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_DATA1),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_DATA2),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_DATA3),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_DATA4),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_DATA5),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_DATA6),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_DATA7),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_STROBE),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_RESET_B),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_SD1FIX),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_CLK),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_CMD),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_DATA0),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_DATA1),
+ IMX_PINCTRL_PIN(SC_P_CTL_NAND_RE_P_N),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_DATA2),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_DATA3),
+ IMX_PINCTRL_PIN(SC_P_CTL_NAND_DQS_P_N),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_DATA4),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_DATA5),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_DATA6),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_DATA7),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_STROBE),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_VSEL2),
+ IMX_PINCTRL_PIN(SC_P_USDHC2_CLK),
+ IMX_PINCTRL_PIN(SC_P_USDHC2_CMD),
+ IMX_PINCTRL_PIN(SC_P_USDHC2_DATA0),
+ IMX_PINCTRL_PIN(SC_P_USDHC2_DATA1),
+ IMX_PINCTRL_PIN(SC_P_USDHC2_DATA2),
+ IMX_PINCTRL_PIN(SC_P_USDHC2_DATA3),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_VSEL3),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_TXC),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_TX_CTL),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_TXD0),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_TXD1),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_TXD2),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_TXD3),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_RXC),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_RX_CTL),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_RXD0),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_RXD1),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_RXD2),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_RXD3),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_ENET_ENETB),
+ IMX_PINCTRL_PIN(SC_P_ENET1_RGMII_TXC),
+ IMX_PINCTRL_PIN(SC_P_ENET1_RGMII_TX_CTL),
+ IMX_PINCTRL_PIN(SC_P_ENET1_RGMII_TXD0),
+ IMX_PINCTRL_PIN(SC_P_ENET1_RGMII_TXD1),
+ IMX_PINCTRL_PIN(SC_P_ENET1_RGMII_TXD2),
+ IMX_PINCTRL_PIN(SC_P_ENET1_RGMII_TXD3),
+ IMX_PINCTRL_PIN(SC_P_ENET1_RGMII_RXC),
+ IMX_PINCTRL_PIN(SC_P_ENET1_RGMII_RX_CTL),
+ IMX_PINCTRL_PIN(SC_P_ENET1_RGMII_RXD0),
+ IMX_PINCTRL_PIN(SC_P_ENET1_RGMII_RXD1),
+ IMX_PINCTRL_PIN(SC_P_ENET1_RGMII_RXD2),
+ IMX_PINCTRL_PIN(SC_P_ENET1_RGMII_RXD3),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_ENET_ENETA),
+};
+
+static struct imx_pinctrl_soc_info imx8qm_pinctrl_info = {
+ .pins = imx8qm_pinctrl_pads,
+ .npins = ARRAY_SIZE(imx8qm_pinctrl_pads),
+ .flags = IMX8_USE_SCU | SHARE_MUX_CONF_REG
+ | IMX8_ENABLE_MUX_CONFIG | IMX8_ENABLE_PAD_CONFIG,
+};
+
+static struct of_device_id imx8qm_pinctrl_of_match[] = {
+ { .compatible = "fsl,imx8qm-iomuxc", },
+ { /* sentinel */ }
+};
+
+static int imx8qm_pinctrl_probe(struct platform_device *pdev)
+{
+ uint32_t mu_id;
+ sc_err_t sciErr = SC_ERR_NONE;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_info("pinctrl: Cannot obtain MU ID\n");
+ return sciErr;
+ }
+
+ sciErr = sc_ipc_open(&pinctrl_ipcHandle, mu_id);
+
+ if (sciErr != SC_ERR_NONE) {
+ pr_info("pinctrl: Cannot open MU channel to SCU\n");
+ return sciErr;
+ };
+
+ return imx_pinctrl_probe(pdev, &imx8qm_pinctrl_info);
+}
+
+static struct platform_driver imx8qm_pinctrl_driver = {
+ .driver = {
+ .name = "imx8qm-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(imx8qm_pinctrl_of_match),
+ },
+ .probe = imx8qm_pinctrl_probe,
+};
+
+static int __init imx8qm_pinctrl_init(void)
+{
+ return platform_driver_register(&imx8qm_pinctrl_driver);
+}
+arch_initcall(imx8qm_pinctrl_init);
+
+static void __exit imx8qm_pinctrl_exit(void)
+{
+ platform_driver_unregister(&imx8qm_pinctrl_driver);
+}
+module_exit(imx8qm_pinctrl_exit);
+
+MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
+MODULE_DESCRIPTION("Freescale imx8qm pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/freescale/pinctrl-imx8qxp.c b/drivers/pinctrl/freescale/pinctrl-imx8qxp.c
new file mode 100644
index 000000000000..120c282771bf
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-imx8qxp.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <dt-bindings/pinctrl/pads-imx8qxp.h>
+#include <soc/imx8/sc/sci.h>
+
+#include "pinctrl-imx.h"
+
+extern sc_ipc_t pinctrl_ipcHandle;
+
+static const struct pinctrl_pin_desc imx8qxp_pinctrl_pads[] = {
+ IMX_PINCTRL_PIN(SC_P_PCIE_CTRL0_PERST_B),
+ IMX_PINCTRL_PIN(SC_P_PCIE_CTRL0_CLKREQ_B),
+ IMX_PINCTRL_PIN(SC_P_PCIE_CTRL0_WAKE_B),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_PCIESEP),
+ IMX_PINCTRL_PIN(SC_P_USB_SS3_TC0),
+ IMX_PINCTRL_PIN(SC_P_USB_SS3_TC1),
+ IMX_PINCTRL_PIN(SC_P_USB_SS3_TC2),
+ IMX_PINCTRL_PIN(SC_P_USB_SS3_TC3),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_3V3_USB3IO),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_CLK),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_CMD),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_DATA0),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_DATA1),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_DATA2),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_DATA3),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_SD1FIX0),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_DATA4),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_DATA5),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_DATA6),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_DATA7),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_STROBE),
+ IMX_PINCTRL_PIN(SC_P_EMMC0_RESET_B),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_SD1FIX1),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_RESET_B),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_VSELECT),
+ IMX_PINCTRL_PIN(SC_P_CTL_NAND_RE_P_N),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_WP),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_CD_B),
+ IMX_PINCTRL_PIN(SC_P_CTL_NAND_DQS_P_N),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_VSELSEP),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_CLK),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_CMD),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_DATA0),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_DATA1),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_DATA2),
+ IMX_PINCTRL_PIN(SC_P_USDHC1_DATA3),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_VSEL3),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_TXC),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_TX_CTL),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_TXD0),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_TXD1),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_TXD2),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_TXD3),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_ENET_ENETB0),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_RXC),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_RX_CTL),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_RXD0),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_RXD1),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_RXD2),
+ IMX_PINCTRL_PIN(SC_P_ENET0_RGMII_RXD3),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_ENET_ENETB1),
+ IMX_PINCTRL_PIN(SC_P_ENET0_REFCLK_125M_25M),
+ IMX_PINCTRL_PIN(SC_P_ENET0_MDIO),
+ IMX_PINCTRL_PIN(SC_P_ENET0_MDC),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOCT),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_FSR),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_FST),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_SCKR),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_SCKT),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_TX0),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_TX1),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_TX2_RX3),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_TX3_RX2),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_TX4_RX1),
+ IMX_PINCTRL_PIN(SC_P_ESAI0_TX5_RX0),
+ IMX_PINCTRL_PIN(SC_P_SPDIF0_RX),
+ IMX_PINCTRL_PIN(SC_P_SPDIF0_TX),
+ IMX_PINCTRL_PIN(SC_P_SPDIF0_EXT_CLK),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHB),
+ IMX_PINCTRL_PIN(SC_P_SPI3_SCK),
+ IMX_PINCTRL_PIN(SC_P_SPI3_SDO),
+ IMX_PINCTRL_PIN(SC_P_SPI3_SDI),
+ IMX_PINCTRL_PIN(SC_P_SPI3_CS0),
+ IMX_PINCTRL_PIN(SC_P_SPI3_CS1),
+ IMX_PINCTRL_PIN(SC_P_MCLK_IN1),
+ IMX_PINCTRL_PIN(SC_P_MCLK_IN0),
+ IMX_PINCTRL_PIN(SC_P_MCLK_OUT0),
+ IMX_PINCTRL_PIN(SC_P_UART1_TX),
+ IMX_PINCTRL_PIN(SC_P_UART1_RX),
+ IMX_PINCTRL_PIN(SC_P_UART1_RTS_B),
+ IMX_PINCTRL_PIN(SC_P_UART1_CTS_B),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHK),
+ IMX_PINCTRL_PIN(SC_P_SAI0_TXD),
+ IMX_PINCTRL_PIN(SC_P_SAI0_TXC),
+ IMX_PINCTRL_PIN(SC_P_SAI0_RXD),
+ IMX_PINCTRL_PIN(SC_P_SAI0_TXFS),
+ IMX_PINCTRL_PIN(SC_P_SAI1_RXD),
+ IMX_PINCTRL_PIN(SC_P_SAI1_RXC),
+ IMX_PINCTRL_PIN(SC_P_SAI1_RXFS),
+ IMX_PINCTRL_PIN(SC_P_SPI2_CS0),
+ IMX_PINCTRL_PIN(SC_P_SPI2_SDO),
+ IMX_PINCTRL_PIN(SC_P_SPI2_SDI),
+ IMX_PINCTRL_PIN(SC_P_SPI2_SCK),
+ IMX_PINCTRL_PIN(SC_P_SPI0_SCK),
+ IMX_PINCTRL_PIN(SC_P_SPI0_SDI),
+ IMX_PINCTRL_PIN(SC_P_SPI0_SDO),
+ IMX_PINCTRL_PIN(SC_P_SPI0_CS1),
+ IMX_PINCTRL_PIN(SC_P_SPI0_CS0),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHT),
+ IMX_PINCTRL_PIN(SC_P_ADC_IN1),
+ IMX_PINCTRL_PIN(SC_P_ADC_IN0),
+ IMX_PINCTRL_PIN(SC_P_ADC_IN3),
+ IMX_PINCTRL_PIN(SC_P_ADC_IN2),
+ IMX_PINCTRL_PIN(SC_P_ADC_IN5),
+ IMX_PINCTRL_PIN(SC_P_ADC_IN4),
+ IMX_PINCTRL_PIN(SC_P_FLEXCAN0_RX),
+ IMX_PINCTRL_PIN(SC_P_FLEXCAN0_TX),
+ IMX_PINCTRL_PIN(SC_P_FLEXCAN1_RX),
+ IMX_PINCTRL_PIN(SC_P_FLEXCAN1_TX),
+ IMX_PINCTRL_PIN(SC_P_FLEXCAN2_RX),
+ IMX_PINCTRL_PIN(SC_P_FLEXCAN2_TX),
+ IMX_PINCTRL_PIN(SC_P_UART0_RX),
+ IMX_PINCTRL_PIN(SC_P_UART0_TX),
+ IMX_PINCTRL_PIN(SC_P_UART2_TX),
+ IMX_PINCTRL_PIN(SC_P_UART2_RX),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOLH),
+ IMX_PINCTRL_PIN(SC_P_MIPI_DSI0_I2C0_SCL),
+ IMX_PINCTRL_PIN(SC_P_MIPI_DSI0_I2C0_SDA),
+ IMX_PINCTRL_PIN(SC_P_MIPI_DSI0_GPIO0_00),
+ IMX_PINCTRL_PIN(SC_P_MIPI_DSI0_GPIO0_01),
+ IMX_PINCTRL_PIN(SC_P_MIPI_DSI1_I2C0_SCL),
+ IMX_PINCTRL_PIN(SC_P_MIPI_DSI1_I2C0_SDA),
+ IMX_PINCTRL_PIN(SC_P_MIPI_DSI1_GPIO0_00),
+ IMX_PINCTRL_PIN(SC_P_MIPI_DSI1_GPIO0_01),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_MIPIDSIGPIO),
+ IMX_PINCTRL_PIN(SC_P_JTAG_TRST_B),
+ IMX_PINCTRL_PIN(SC_P_PMIC_I2C_SCL),
+ IMX_PINCTRL_PIN(SC_P_PMIC_I2C_SDA),
+ IMX_PINCTRL_PIN(SC_P_PMIC_INT_B),
+ IMX_PINCTRL_PIN(SC_P_SCU_GPIO0_00),
+ IMX_PINCTRL_PIN(SC_P_SCU_GPIO0_01),
+ IMX_PINCTRL_PIN(SC_P_SCU_PMIC_STANDBY),
+ IMX_PINCTRL_PIN(SC_P_SCU_BOOT_MODE0),
+ IMX_PINCTRL_PIN(SC_P_SCU_BOOT_MODE1),
+ IMX_PINCTRL_PIN(SC_P_SCU_BOOT_MODE2),
+ IMX_PINCTRL_PIN(SC_P_SCU_BOOT_MODE3),
+ IMX_PINCTRL_PIN(SC_P_CSI_D00),
+ IMX_PINCTRL_PIN(SC_P_CSI_D01),
+ IMX_PINCTRL_PIN(SC_P_CSI_D02),
+ IMX_PINCTRL_PIN(SC_P_CSI_D03),
+ IMX_PINCTRL_PIN(SC_P_CSI_D04),
+ IMX_PINCTRL_PIN(SC_P_CSI_D05),
+ IMX_PINCTRL_PIN(SC_P_CSI_D06),
+ IMX_PINCTRL_PIN(SC_P_CSI_D07),
+ IMX_PINCTRL_PIN(SC_P_CSI_HSYNC),
+ IMX_PINCTRL_PIN(SC_P_CSI_VSYNC),
+ IMX_PINCTRL_PIN(SC_P_CSI_PCLK),
+ IMX_PINCTRL_PIN(SC_P_CSI_MCLK),
+ IMX_PINCTRL_PIN(SC_P_CSI_EN),
+ IMX_PINCTRL_PIN(SC_P_CSI_RESET),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHD),
+ IMX_PINCTRL_PIN(SC_P_MIPI_CSI0_MCLK_OUT),
+ IMX_PINCTRL_PIN(SC_P_MIPI_CSI0_I2C0_SCL),
+ IMX_PINCTRL_PIN(SC_P_MIPI_CSI0_I2C0_SDA),
+ IMX_PINCTRL_PIN(SC_P_MIPI_CSI0_GPIO0_01),
+ IMX_PINCTRL_PIN(SC_P_MIPI_CSI0_GPIO0_00),
+ IMX_PINCTRL_PIN(SC_P_QSPI0A_DATA0),
+ IMX_PINCTRL_PIN(SC_P_QSPI0A_DATA1),
+ IMX_PINCTRL_PIN(SC_P_QSPI0A_DATA2),
+ IMX_PINCTRL_PIN(SC_P_QSPI0A_DATA3),
+ IMX_PINCTRL_PIN(SC_P_QSPI0A_DQS),
+ IMX_PINCTRL_PIN(SC_P_QSPI0A_SS0_B),
+ IMX_PINCTRL_PIN(SC_P_QSPI0A_SS1_B),
+ IMX_PINCTRL_PIN(SC_P_QSPI0A_SCLK),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_QSPI0A),
+ IMX_PINCTRL_PIN(SC_P_QSPI0B_SCLK),
+ IMX_PINCTRL_PIN(SC_P_QSPI0B_DATA0),
+ IMX_PINCTRL_PIN(SC_P_QSPI0B_DATA1),
+ IMX_PINCTRL_PIN(SC_P_QSPI0B_DATA2),
+ IMX_PINCTRL_PIN(SC_P_QSPI0B_DATA3),
+ IMX_PINCTRL_PIN(SC_P_QSPI0B_DQS),
+ IMX_PINCTRL_PIN(SC_P_QSPI0B_SS0_B),
+ IMX_PINCTRL_PIN(SC_P_QSPI0B_SS1_B),
+ IMX_PINCTRL_PIN(SC_P_COMP_CTL_GPIO_1V8_3V3_QSPI0B),
+};
+
+static struct imx_pinctrl_soc_info imx8qxp_pinctrl_info = {
+ .pins = imx8qxp_pinctrl_pads,
+ .npins = ARRAY_SIZE(imx8qxp_pinctrl_pads),
+ .flags = IMX8_USE_SCU | SHARE_MUX_CONF_REG
+ | IMX8_ENABLE_MUX_CONFIG | IMX8_ENABLE_PAD_CONFIG,
+};
+
+static struct of_device_id imx8qxp_pinctrl_of_match[] = {
+ { .compatible = "fsl,imx8qxp-iomuxc", },
+ { /* sentinel */ }
+};
+
+static int imx8qxp_pinctrl_probe(struct platform_device *pdev)
+{
+ uint32_t mu_id;
+ sc_err_t sciErr = SC_ERR_NONE;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_info("pinctrl: Cannot obtain MU ID\n");
+ return sciErr;
+ }
+
+ sciErr = sc_ipc_open(&pinctrl_ipcHandle, mu_id);
+
+ if (sciErr != SC_ERR_NONE) {
+ pr_info("pinctrl: Cannot open MU channel to SCU\n");
+ return sciErr;
+ };
+
+ return imx_pinctrl_probe(pdev, &imx8qxp_pinctrl_info);
+}
+
+static struct platform_driver imx8qxp_pinctrl_driver = {
+ .driver = {
+ .name = "imx8qxp-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(imx8qxp_pinctrl_of_match),
+ },
+ .probe = imx8qxp_pinctrl_probe,
+};
+
+static int __init imx8qxp_pinctrl_init(void)
+{
+ return platform_driver_register(&imx8qxp_pinctrl_driver);
+}
+arch_initcall(imx8qxp_pinctrl_init);
+
+static void __exit imx8qxp_pinctrl_exit(void)
+{
+ platform_driver_unregister(&imx8qxp_pinctrl_driver);
+}
+module_exit(imx8qxp_pinctrl_exit);
+
+MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
+MODULE_DESCRIPTION("Freescale imx8qxp pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/freescale/pinctrl-memmap.c b/drivers/pinctrl/freescale/pinctrl-memmap.c
new file mode 100644
index 000000000000..0492429ca822
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-memmap.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/slab.h>
+
+#include "../core.h"
+#include "pinctrl-imx.h"
+
+#define IMX_PAD_SION 0x40000000 /* set SION */
+
+int imx_pmx_set_one_pin_mem(struct imx_pinctrl *ipctl, struct imx_pin *pin)
+{
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+ unsigned int pin_id = pin->pin;
+ struct imx_pin_reg *pin_reg;
+ struct imx_pin_memmap *pin_memmap;
+ pin_reg = &info->pin_regs[pin_id];
+ pin_memmap = &pin->pin_conf.pin_memmap;
+
+ if (pin_reg->mux_reg == -1) {
+ dev_err(ipctl->dev, "Pin(%s) does not support mux function\n",
+ info->pins[pin_id].name);
+ return 0;
+ }
+
+ if (info->flags & SHARE_MUX_CONF_REG) {
+ u32 reg;
+ reg = readl(ipctl->base + pin_reg->mux_reg);
+ reg &= ~info->mux_mask;
+ reg |= (pin_memmap->mux_mode << info->mux_shift);
+ writel(reg, ipctl->base + pin_reg->mux_reg);
+ dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
+ pin_reg->mux_reg, reg);
+ } else {
+ writel(pin_memmap->mux_mode, ipctl->base + pin_reg->mux_reg);
+ dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
+ pin_reg->mux_reg, pin_memmap->mux_mode);
+ }
+
+ /*
+ * If the select input value begins with 0xff, it's a quirky
+ * select input and the value should be interpreted as below.
+ * 31 23 15 7 0
+ * | 0xff | shift | width | select |
+ * It's used to work around the problem that the select
+ * input for some pin is not implemented in the select
+ * input register but in some general purpose register.
+ * We encode the select input value, width and shift of
+ * the bit field into input_val cell of pin function ID
+ * in device tree, and then decode them here for setting
+ * up the select input bits in general purpose register.
+ */
+ if (pin_memmap->input_val >> 24 == 0xff) {
+ u32 val = pin_memmap->input_val;
+ u8 select = val & 0xff;
+ u8 width = (val >> 8) & 0xff;
+ u8 shift = (val >> 16) & 0xff;
+ u32 mask = ((1 << width) - 1) << shift;
+ /*
+ * The input_reg[i] here is actually some IOMUXC general
+ * purpose register, not regular select input register.
+ */
+ val = readl(ipctl->base + pin_memmap->input_reg);
+ val &= ~mask;
+ val |= select << shift;
+ writel(val, ipctl->base + pin_memmap->input_reg);
+ } else if (pin_memmap->input_reg) {
+ /*
+ * Regular select input register can never be at offset
+ * 0, and we only print register value for regular case.
+ */
+ if (ipctl->input_sel_base)
+ writel(pin_memmap->input_val, ipctl->input_sel_base +
+ pin_memmap->input_reg);
+ else
+ writel(pin_memmap->input_val, ipctl->base +
+ pin_memmap->input_reg);
+ dev_dbg(ipctl->dev,
+ "==>select_input: offset 0x%x val 0x%x\n",
+ pin_memmap->input_reg, pin_memmap->input_val);
+ }
+
+ return 0;
+}
+
+int imx_pmx_backend_gpio_set_direction_mem(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned offset, bool input)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+ const struct imx_pin_reg *pin_reg;
+ u32 reg;
+
+ /*
+ * Only Vybrid and iMX ULP has the input/output buffer enable flags
+ * (IBE/OBE) They are part of the shared mux/conf register.
+ */
+ if (!(info->flags & SHARE_MUX_CONF_REG))
+ return 0;
+
+ pin_reg = &info->pin_regs[offset];
+ if (pin_reg->mux_reg == -1)
+ return -EINVAL;
+
+ reg = readl(ipctl->base + pin_reg->mux_reg);
+ if (input)
+ reg = (reg & ~info->obe_bit) | info->ibe_bit;
+ else
+ reg = (reg & ~info->ibe_bit) | info->obe_bit;
+ writel(reg, ipctl->base + pin_reg->mux_reg);
+
+ return 0;
+}
+
+int imx_pinconf_backend_get_mem(struct pinctrl_dev *pctldev,
+ unsigned pin_id, unsigned long *config)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+ const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
+
+ if (pin_reg->conf_reg == -1) {
+ dev_err(info->dev, "Pin(%s) does not support config function\n",
+ info->pins[pin_id].name);
+ return -EINVAL;
+ }
+
+ *config = readl(ipctl->base + pin_reg->conf_reg);
+
+ if (info->flags & SHARE_MUX_CONF_REG)
+ *config &= ~info->mux_mask;
+
+ return 0;
+}
+
+int imx_pinconf_backend_set_mem(struct pinctrl_dev *pctldev,
+ unsigned pin_id, unsigned long *configs,
+ unsigned num_configs)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+ const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
+ int i;
+
+ if (pin_reg->conf_reg == -1) {
+ dev_err(info->dev, "Pin(%s) does not support config function\n",
+ info->pins[pin_id].name);
+ return -EINVAL;
+ }
+
+ dev_dbg(ipctl->dev, "pinconf set pin %s\n",
+ info->pins[pin_id].name);
+
+ for (i = 0; i < num_configs; i++) {
+ if (info->flags & SHARE_MUX_CONF_REG) {
+ u32 reg;
+ reg = readl(ipctl->base + pin_reg->conf_reg);
+ reg &= info->mux_mask;
+ reg |= configs[i];
+ writel(reg, ipctl->base + pin_reg->conf_reg);
+ dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
+ pin_reg->conf_reg, reg);
+ } else {
+ writel(configs[i], ipctl->base + pin_reg->conf_reg);
+ dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n",
+ pin_reg->conf_reg, configs[i]);
+ }
+ } /* for each config */
+
+ return 0;
+}
+
+int imx_pinctrl_parse_pin_mem(struct imx_pinctrl_soc_info *info,
+ unsigned int *grp_pin_id, struct imx_pin *pin,
+ const __be32 **list_p)
+{
+ struct imx_pin_memmap *pin_memmap = &pin->pin_conf.pin_memmap;
+ u32 mux_reg = be32_to_cpu(*((*list_p)++));
+ u32 conf_reg;
+ u32 config;
+ unsigned int pin_id;
+ struct imx_pin_reg *pin_reg;
+
+ if (info->flags & SHARE_MUX_CONF_REG) {
+ conf_reg = mux_reg;
+ } else {
+ conf_reg = be32_to_cpu(*((*list_p)++));
+ if (!conf_reg)
+ conf_reg = -1;
+ }
+
+ pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4;
+ pin_reg = &info->pin_regs[pin_id];
+ pin->pin = pin_id;
+ *grp_pin_id = pin_id;
+ pin_reg->mux_reg = mux_reg;
+ pin_reg->conf_reg = conf_reg;
+ pin_memmap->input_reg = be32_to_cpu(*((*list_p)++));
+ pin_memmap->mux_mode = be32_to_cpu(*((*list_p)++));
+ pin_memmap->input_val = be32_to_cpu((*(*list_p)++));
+
+ /* SION bit is in mux register */
+ config = be32_to_cpu(*((*list_p)++));
+ if (config & IMX_PAD_SION)
+ pin_memmap->mux_mode |= IOMUXC_CONFIG_SION;
+ pin_memmap->config = config & ~IMX_PAD_SION;
+
+ dev_dbg(info->dev, "%s: 0x%x 0x%08lx", info->pins[pin_id].name,
+ pin_memmap->mux_mode, pin_memmap->config);
+
+ return 0;
+}
diff --git a/drivers/pinctrl/freescale/pinctrl-scu.c b/drivers/pinctrl/freescale/pinctrl-scu.c
new file mode 100644
index 000000000000..79e987c6577c
--- /dev/null
+++ b/drivers/pinctrl/freescale/pinctrl-scu.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/slab.h>
+#include <soc/imx8/sc/sci.h>
+
+#include "../core.h"
+#include "pinctrl-imx.h"
+
+sc_ipc_t pinctrl_ipcHandle;
+
+int imx_pmx_set_one_pin_scu(struct imx_pinctrl *ipctl, struct imx_pin *pin)
+{
+ return 0;
+}
+
+int imx_pinconf_backend_get_scu(struct pinctrl_dev *pctldev, unsigned pin_id,
+ unsigned long *config)
+{
+ sc_err_t err = SC_ERR_NONE;
+ sc_ipc_t ipc = pinctrl_ipcHandle;
+
+ if (ipc == -1) {
+ printk("IPC handle not initialized!\n");
+ return -EIO;
+ }
+
+ err = sc_pad_get(ipc, pin_id, (unsigned int *)config);
+
+ if (err != SC_ERR_NONE)
+ return -EIO;
+
+ return 0;
+}
+
+int imx_pinconf_backend_set_scu(struct pinctrl_dev *pctldev, unsigned pin_id,
+ unsigned long *configs, unsigned num_configs)
+{
+ sc_err_t err = SC_ERR_NONE;
+ sc_ipc_t ipc = pinctrl_ipcHandle;
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+ /*
+ * Mux should be done in pmx set, but we do not have a good api
+ * to handle that in scfw, so config it in pad conf func
+ */
+ unsigned int mux = configs[0];
+ unsigned int val = configs[1];
+
+ if (ipc == -1) {
+ printk("IPC handle not initialized!\n");
+ return -EIO;
+ }
+
+ if (info->flags & IMX8_ENABLE_MUX_CONFIG)
+ val |= BM_IMX8_IFMUX_ENABLE;
+
+ if (info->flags & IMX8_ENABLE_PAD_CONFIG)
+ val |= BM_IMX8_GP_ENABLE;
+
+ if (info->flags & SHARE_MUX_CONF_REG) {
+ val |= (mux << 27) & (0x7 << 27);
+ err = sc_pad_set(ipc, pin_id, val);
+ }
+
+ if (err != SC_ERR_NONE)
+ return -EIO;
+
+ return 0;
+}
+
+int imx_pinctrl_parse_pin_scu(struct imx_pinctrl_soc_info *info,
+ unsigned int *pin_id, struct imx_pin *pin,
+ const __be32 **list_p)
+{
+ struct imx_pin_scu *pin_scu = &pin->pin_conf.pin_scu;
+
+ pin->pin = be32_to_cpu(*((*list_p)++));
+ *pin_id = pin->pin;
+ pin_scu->mux = be32_to_cpu(*((*list_p)++));
+ pin_scu->config = be32_to_cpu(*((*list_p)++));
+
+ dev_dbg(info->dev, "%s: 0x%lx 0x%lx",
+ info->pins[pin->pin].name, pin_scu->mux, pin_scu->config);
+
+ return 0;
+}
diff --git a/drivers/pinctrl/freescale/pinctrl-vf610.c b/drivers/pinctrl/freescale/pinctrl-vf610.c
index 2b1e198e3092..c0823f9a838e 100644
--- a/drivers/pinctrl/freescale/pinctrl-vf610.c
+++ b/drivers/pinctrl/freescale/pinctrl-vf610.c
@@ -299,6 +299,10 @@ static struct imx_pinctrl_soc_info vf610_pinctrl_info = {
.pins = vf610_pinctrl_pads,
.npins = ARRAY_SIZE(vf610_pinctrl_pads),
.flags = SHARE_MUX_CONF_REG | ZERO_OFFSET_VALID,
+ .mux_mask = 0x700000,
+ .mux_shift = 20,
+ .ibe_bit = BIT(0),
+ .obe_bit = BIT(1),
};
static const struct of_device_id vf610_pinctrl_of_match[] = {
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 76806a0be820..e7407876da8b 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -281,6 +281,12 @@ config CHARGER_PCF50633
help
Say Y to include support for NXP PCF50633 Main Battery Charger.
+config CHARGER_PF1550
+ tristate "Freescale PF1550 battery charger driver"
+ depends on MFD_PF1550
+ help
+ Say Y to enable support for the Freescale PF1550 battery charger.
+
config BATTERY_JZ4740
tristate "Ingenic JZ4740 battery"
depends on MACH_JZ4740
@@ -511,4 +517,12 @@ config AXP20X_POWER
This driver provides support for the power supply features of
AXP20x PMIC.
+config SABRESD_MAX8903
+ tristate "Sabresd Board Battery DC-DC Charger for USB and Adapter Power"
+ depends on TOUCHSCREEN_MAX11801
+ help
+ Say Y to enable support for the MAX8903 DC-DC charger and sysfs on
+ sabresd board.The driver supports controlling charger and battery
+ based on the status of charger connections with interrupt handlers.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 36c599d9a495..110df86baebb 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -46,11 +46,13 @@ obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o
obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
+obj-$(CONFIG_CHARGER_PF1550) += pf1550_charger.o
obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o
obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o pm2301_charger.o
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
+obj-$(CONFIG_SABRESD_MAX8903) += sabresd_battery.o
obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
obj-$(CONFIG_CHARGER_LP8727) += lp8727_charger.o
diff --git a/drivers/power/supply/pf1550_charger.c b/drivers/power/supply/pf1550_charger.c
new file mode 100644
index 000000000000..d14ef2b29ffd
--- /dev/null
+++ b/drivers/power/supply/pf1550_charger.c
@@ -0,0 +1,656 @@
+/*
+ * pf1550_charger.c - regulator driver for the PF1550
+ *
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Robin Gong <yibin.gong@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/mfd/pf1550.h>
+
+#define PF1550_CHARGER_NAME "pf1550-charger"
+#define PF1550_DEFAULT_CONSTANT_VOLT 4200000
+#define PF1550_DEFAULT_MIN_SYSTEM_VOLT 3500000
+#define PF1550_DEFAULT_THERMAL_TEMP 75
+
+static const char *pf1550_charger_model = "PF1550";
+static const char *pf1550_charger_manufacturer = "Freescale";
+
+struct pf1550_charger {
+ struct device *dev;
+ struct pf1550_dev *pf1550;
+ struct power_supply *charger;
+ struct power_supply_desc psy_desc;
+ int irq;
+ struct delayed_work irq_work;
+ struct mutex mutex;
+
+ u32 constant_volt;
+ u32 min_system_volt;
+ u32 thermal_regulation_temp;
+};
+
+static struct pf1550_irq_info pf1550_charger_irqs[] = {
+ { PF1550_CHARG_IRQ_BAT2SOCI, "BAT2SOC" },
+ { PF1550_CHARG_IRQ_BATI, "BAT" },
+ { PF1550_CHARG_IRQ_CHGI, "CHG" },
+ { PF1550_CHARG_IRQ_VBUSI, "VBUS" },
+ { PF1550_CHARG_IRQ_THMI, "THM" },
+};
+
+static int pf1550_get_charger_state(struct regmap *regmap, int *val)
+{
+ int ret;
+ unsigned int data;
+
+ ret = regmap_read(regmap, PF1550_CHARG_REG_CHG_SNS, &data);
+ if (ret < 0)
+ return ret;
+
+ data &= PF1550_CHG_SNS_MASK;
+
+ switch (data) {
+ case PF1550_CHG_PRECHARGE:
+ case PF1550_CHG_CONSTANT_CURRENT:
+ case PF1550_CHG_CONSTANT_VOL:
+ case PF1550_CHG_EOC:
+ *val = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ case PF1550_CHG_DONE:
+ *val = POWER_SUPPLY_STATUS_FULL;
+ break;
+ case PF1550_CHG_TIMER_FAULT:
+ case PF1550_CHG_SUSPEND:
+ *val = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case PF1550_CHG_OFF_INV:
+ case PF1550_CHG_OFF_TEMP:
+ case PF1550_CHG_LINEAR_ONLY:
+ *val = POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+ default:
+ *val = POWER_SUPPLY_STATUS_UNKNOWN;
+ }
+
+ return 0;
+}
+
+static int pf1550_get_charge_type(struct regmap *regmap, int *val)
+{
+ int ret;
+ unsigned int data;
+
+ ret = regmap_read(regmap, PF1550_CHARG_REG_CHG_SNS, &data);
+ if (ret < 0)
+ return ret;
+
+ data &= PF1550_CHG_SNS_MASK;
+
+ switch (data) {
+ case PF1550_CHG_SNS_MASK:
+ *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ break;
+ case PF1550_CHG_CONSTANT_CURRENT:
+ case PF1550_CHG_CONSTANT_VOL:
+ case PF1550_CHG_EOC:
+ *val = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ break;
+ case PF1550_CHG_DONE:
+ case PF1550_CHG_TIMER_FAULT:
+ case PF1550_CHG_SUSPEND:
+ case PF1550_CHG_OFF_INV:
+ case PF1550_CHG_BAT_OVER:
+ case PF1550_CHG_OFF_TEMP:
+ case PF1550_CHG_LINEAR_ONLY:
+ *val = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ break;
+ default:
+ *val = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+ }
+
+ return 0;
+}
+
+/*
+ * Supported health statuses:
+ * - POWER_SUPPLY_HEALTH_DEAD
+ * - POWER_SUPPLY_HEALTH_GOOD
+ * - POWER_SUPPLY_HEALTH_OVERVOLTAGE
+ * - POWER_SUPPLY_HEALTH_UNKNOWN
+ */
+static int pf1550_get_battery_health(struct regmap *regmap, int *val)
+{
+ int ret;
+ unsigned int data;
+
+ ret = regmap_read(regmap, PF1550_CHARG_REG_BATT_SNS, &data);
+ if (ret < 0)
+ return ret;
+
+ data &= PF1550_BAT_SNS_MASK;
+
+ switch (data) {
+ case PF1550_BAT_NO_DETECT:
+ *val = POWER_SUPPLY_HEALTH_DEAD;
+ break;
+ case PF1550_BAT_NO_VBUS:
+ case PF1550_BAT_LOW_THAN_PRECHARG:
+ case PF1550_BAT_CHARG_FAIL:
+ case PF1550_BAT_HIGH_THAN_PRECHARG:
+ *val = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ case PF1550_BAT_OVER_VOL:
+ *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ break;
+ default:
+ *val = POWER_SUPPLY_HEALTH_UNKNOWN;
+ break;
+ }
+
+ return 0;
+}
+
+static int pf1550_get_present(struct regmap *regmap, int *val)
+{
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(regmap, PF1550_CHARG_REG_BATT_SNS, &data);
+ if (ret < 0)
+ return ret;
+
+ data &= PF1550_BAT_SNS_MASK;
+ *val = (data == PF1550_BAT_NO_DETECT) ? 0 : 1;
+
+ return 0;
+}
+
+static int pf1550_get_online(struct regmap *regmap, int *val)
+{
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(regmap, PF1550_CHARG_REG_VBUS_SNS, &data);
+ if (ret < 0)
+ return ret;
+
+ *val = (data & PF1550_VBUS_VALID) ? 1 : 0;
+
+ return 0;
+}
+
+static void pf1550_chg_bat_isr(struct pf1550_charger *chg)
+{
+ unsigned int data;
+
+ if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_BATT_SNS, &data)) {
+ dev_err(chg->dev, "Read BATT_SNS error.\n");
+ return;
+ }
+
+ switch (data & PF1550_BAT_SNS_MASK) {
+ case PF1550_BAT_NO_VBUS:
+ dev_dbg(chg->dev, "No valid VBUS input.\n");
+ break;
+ case PF1550_BAT_LOW_THAN_PRECHARG:
+ dev_dbg(chg->dev, "VBAT < VPRECHG.LB.\n");
+ break;
+ case PF1550_BAT_CHARG_FAIL:
+ dev_dbg(chg->dev, "Battery charging failed.\n");
+ break;
+ case PF1550_BAT_HIGH_THAN_PRECHARG:
+ dev_dbg(chg->dev, "VBAT > VPRECHG.LB.\n");
+ break;
+ case PF1550_BAT_OVER_VOL:
+ dev_dbg(chg->dev, "VBAT > VBATOV.\n");
+ break;
+ case PF1550_BAT_NO_DETECT:
+ dev_dbg(chg->dev, "Battery not detected.\n");
+ break;
+ default:
+ dev_err(chg->dev, "Unknown value read:%x\n",
+ data & PF1550_CHG_SNS_MASK);
+ }
+}
+
+static void pf1550_chg_chg_isr(struct pf1550_charger *chg)
+{
+ unsigned int data;
+
+ if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_SNS, &data)) {
+ dev_err(chg->dev, "Read CHG_SNS error.\n");
+ return;
+ }
+
+ switch (data & PF1550_CHG_SNS_MASK) {
+ case PF1550_CHG_PRECHARGE:
+ dev_dbg(chg->dev, "In pre-charger mode.\n");
+ break;
+ case PF1550_CHG_CONSTANT_CURRENT:
+ dev_dbg(chg->dev, "In fast-charge constant current mode.\n");
+ break;
+ case PF1550_CHG_CONSTANT_VOL:
+ dev_dbg(chg->dev, "In fast-charge constant voltage mode.\n");
+ break;
+ case PF1550_CHG_EOC:
+ dev_dbg(chg->dev, "In EOC mode.\n");
+ break;
+ case PF1550_CHG_DONE:
+ dev_dbg(chg->dev, "In DONE mode.\n");
+ break;
+ case PF1550_CHG_TIMER_FAULT:
+ dev_info(chg->dev, "In timer fault mode.\n");
+ break;
+ case PF1550_CHG_SUSPEND:
+ dev_info(chg->dev, "In thermistor suspend mode.\n");
+ break;
+ case PF1550_CHG_OFF_INV:
+ dev_info(chg->dev, "Input invalid, charger off.\n");
+ break;
+ case PF1550_CHG_BAT_OVER:
+ dev_info(chg->dev, "Battery over-voltage.\n");
+ break;
+ case PF1550_CHG_OFF_TEMP:
+ dev_info(chg->dev, "Temp high, charger off.\n");
+ break;
+ case PF1550_CHG_LINEAR_ONLY:
+ dev_dbg(chg->dev, "In Linear mode, not charging.\n");
+ break;
+ default:
+ dev_err(chg->dev, "Unknown value read:%x\n",
+ data & PF1550_CHG_SNS_MASK);
+ }
+}
+
+static void pf1550_chg_vbus_isr(struct pf1550_charger *chg)
+{
+ enum power_supply_type old_type;
+ unsigned int data;
+
+ if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_VBUS_SNS, &data)) {
+ dev_err(chg->dev, "Read VBUS_SNS error.\n");
+ return;
+ }
+
+ old_type = chg->psy_desc.type;
+
+ if (data & PF1550_VBUS_UVLO) {
+ chg->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY;
+ dev_dbg(chg->dev, "VBUS deattached.\n");
+ }
+ if (data & PF1550_VBUS_IN2SYS)
+ dev_dbg(chg->dev, "VBUS_IN2SYS_SNS.\n");
+ if (data & PF1550_VBUS_OVLO)
+ dev_dbg(chg->dev, "VBUS_OVLO_SNS.\n");
+ if (data & PF1550_VBUS_VALID) {
+ chg->psy_desc.type = POWER_SUPPLY_TYPE_MAINS;
+ dev_dbg(chg->dev, "VBUS attached.\n");
+ }
+
+ if (old_type != chg->psy_desc.type)
+ power_supply_changed(chg->charger);
+}
+
+static irqreturn_t pf1550_charger_irq_handler(int irq, void *data)
+{
+ struct pf1550_charger *chg = data;
+
+ chg->irq = irq;
+ schedule_delayed_work(&chg->irq_work, msecs_to_jiffies(10));
+
+ return IRQ_HANDLED;
+}
+
+static void pf1550_charger_irq_work(struct work_struct *work)
+{
+ struct pf1550_charger *chg = container_of(to_delayed_work(work),
+ struct pf1550_charger,
+ irq_work);
+ int i, irq_type = -1;
+ unsigned int status;
+
+ if (!chg->charger)
+ return;
+
+ mutex_lock(&chg->mutex);
+
+ for (i = 0; i < ARRAY_SIZE(pf1550_charger_irqs); i++)
+ if (chg->irq == pf1550_charger_irqs[i].virq)
+ irq_type = pf1550_charger_irqs[i].irq;
+
+ switch (irq_type) {
+ case PF1550_CHARG_IRQ_BAT2SOCI:
+ dev_info(chg->dev, "BAT to SYS Overcurrent interrupt.\n");
+ break;
+ case PF1550_CHARG_IRQ_BATI:
+ pf1550_chg_bat_isr(chg);
+ break;
+ case PF1550_CHARG_IRQ_CHGI:
+ pf1550_chg_chg_isr(chg);
+ break;
+ case PF1550_CHARG_IRQ_VBUSI:
+ pf1550_chg_vbus_isr(chg);
+ break;
+ case PF1550_CHARG_IRQ_THMI:
+ dev_info(chg->dev, "Thermal interrupt.\n");
+ break;
+ default:
+ dev_err(chg->dev, "unknown interrupt occurred.\n");
+ }
+
+ if (regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_INT, &status))
+ dev_err(chg->dev, "Read CHG_INT error.\n");
+ if (regmap_write(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_INT, status))
+ dev_err(chg->dev, "clear CHG_INT error.\n");
+
+ mutex_unlock(&chg->mutex);
+}
+
+static enum power_supply_property pf1550_charger_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static int pf1550_charger_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct pf1550_charger *chg = power_supply_get_drvdata(psy);
+ struct regmap *regmap = chg->pf1550->regmap;
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ ret = pf1550_get_charger_state(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ ret = pf1550_get_charge_type(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ ret = pf1550_get_battery_health(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ ret = pf1550_get_present(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ ret = pf1550_get_online(regmap, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = pf1550_charger_model;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = pf1550_charger_manufacturer;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int pf1550_set_constant_volt(struct pf1550_charger *chg,
+ unsigned int uvolt)
+{
+ unsigned int data;
+
+ if (uvolt >= 3500000 && uvolt <= 4440000)
+ data = 8 + (uvolt - 3500000) / 20000;
+ else {
+ dev_err(chg->dev, "Wrong value for constant voltage\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(chg->dev, "Charging constant voltage: %u (0x%x)\n", uvolt,
+ data);
+
+ return regmap_update_bits(chg->pf1550->regmap,
+ PF1550_CHARG_REG_BATT_REG,
+ PF1550_CHARG_REG_BATT_REG_CHGCV_MASK, data);
+}
+
+static int pf1550_set_min_system_volt(struct pf1550_charger *chg,
+ unsigned int uvolt)
+{
+ unsigned int data;
+
+ switch (uvolt) {
+ case 3500000:
+ data = 0x0;
+ break;
+ case 3700000:
+ data = 0x1;
+ break;
+ case 4300000:
+ data = 0x2;
+ break;
+ default:
+ dev_err(chg->dev, "Wrong value for minimum system voltage\n");
+ return -EINVAL;
+ }
+
+ data <<= PF1550_CHARG_REG_BATT_REG_VMINSYS_SHIFT;
+
+ dev_dbg(chg->dev, "Minimum system regulation voltage: %u (0x%x)\n",
+ uvolt, data);
+
+ return regmap_update_bits(chg->pf1550->regmap,
+ PF1550_CHARG_REG_BATT_REG,
+ PF1550_CHARG_REG_BATT_REG_VMINSYS_MASK, data);
+}
+
+static int pf1550_set_thermal_regulation_temp(struct pf1550_charger *chg,
+ unsigned int cels)
+{
+ unsigned int data;
+
+ switch (cels) {
+ case 60:
+ data = 0x0;
+ break;
+ case 75:
+ data = 0x1;
+ break;
+ case 90:
+ data = 0x2;
+ break;
+ case 105:
+ data = 0x3;
+ break;
+ default:
+ dev_err(chg->dev, "Wrong value for thermal temperature\n");
+ return -EINVAL;
+ }
+
+ data <<= PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_SHIFT;
+
+ dev_dbg(chg->dev, "Thermal regulation loop temperature: %u (0x%x)\n",
+ cels, data);
+
+ return regmap_update_bits(chg->pf1550->regmap,
+ PF1550_CHARG_REG_THM_REG_CNFG,
+ PF1550_CHARG_REG_THM_REG_CNFG_REGTEMP_MASK, data);
+}
+
+/*
+ * Sets charger registers to proper and safe default values.
+ */
+static int pf1550_reg_init(struct pf1550_charger *chg)
+{
+ int ret;
+ unsigned int data;
+
+ /* Unmask charger interrupt, mask DPMI and reserved bit */
+ ret = regmap_write(chg->pf1550->regmap, PF1550_CHARG_REG_CHG_INT_MASK,
+ 0x51);
+ if (ret) {
+ dev_err(chg->dev, "Error unmask charger interrupt: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_read(chg->pf1550->regmap, PF1550_CHARG_REG_VBUS_SNS,
+ &data);
+ if (ret) {
+ dev_err(chg->dev, "Read charg vbus_sns error: %d\n", ret);
+ return ret;
+ }
+
+ if (data & PF1550_VBUS_VALID)
+ chg->psy_desc.type = POWER_SUPPLY_TYPE_MAINS;
+
+ ret = pf1550_set_constant_volt(chg, chg->constant_volt);
+ if (ret)
+ return ret;
+
+ ret = pf1550_set_min_system_volt(chg, chg->min_system_volt);
+ if (ret)
+ return ret;
+
+ ret = pf1550_set_thermal_regulation_temp(chg,
+ chg->thermal_regulation_temp);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int pf1550_dt_init(struct device *dev, struct pf1550_charger *chg)
+{
+ struct device_node *np = dev->of_node;
+
+ if (!np) {
+ dev_err(dev, "no charger OF node\n");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32(np, "fsl,constant-microvolt",
+ &chg->constant_volt))
+ chg->constant_volt = PF1550_DEFAULT_CONSTANT_VOLT;
+
+ if (of_property_read_u32(np, "fsl,min-system-microvolt",
+ &chg->min_system_volt))
+ chg->min_system_volt = PF1550_DEFAULT_MIN_SYSTEM_VOLT;
+
+ if (of_property_read_u32(np, "fsl,thermal-regulation",
+ &chg->thermal_regulation_temp))
+ chg->thermal_regulation_temp = PF1550_DEFAULT_THERMAL_TEMP;
+
+ return 0;
+}
+
+static int pf1550_charger_probe(struct platform_device *pdev)
+{
+ struct pf1550_charger *chg;
+ struct power_supply_config psy_cfg = {};
+ struct pf1550_dev *pf1550 = dev_get_drvdata(pdev->dev.parent);
+ int i, ret;
+
+ chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL);
+ if (!chg)
+ return -ENOMEM;
+
+ chg->dev = &pdev->dev;
+ chg->pf1550 = pf1550;
+
+ platform_set_drvdata(pdev, chg);
+
+ ret = pf1550_dt_init(&pdev->dev, chg);
+ if (ret)
+ return ret;
+
+ mutex_init(&chg->mutex);
+
+ INIT_DELAYED_WORK(&chg->irq_work, pf1550_charger_irq_work);
+
+ for (i = 0; i < ARRAY_SIZE(pf1550_charger_irqs); i++) {
+ struct pf1550_irq_info *charger_irq =
+ &pf1550_charger_irqs[i];
+ unsigned int virq = 0;
+
+ virq = regmap_irq_get_virq(pf1550->irq_data_charger,
+ charger_irq->irq);
+ if (!virq)
+ return -EINVAL;
+
+ charger_irq->virq = virq;
+
+ ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
+ pf1550_charger_irq_handler,
+ IRQF_NO_SUSPEND,
+ charger_irq->name, chg);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed: irq request (IRQ: %d, error :%d)\n",
+ charger_irq->irq, ret);
+ return ret;
+ }
+ }
+
+ psy_cfg.drv_data = chg;
+
+ chg->psy_desc.name = PF1550_CHARGER_NAME;
+ chg->psy_desc.type = POWER_SUPPLY_TYPE_BATTERY;
+ chg->psy_desc.get_property = pf1550_charger_get_property;
+ chg->psy_desc.properties = pf1550_charger_props;
+ chg->psy_desc.num_properties = ARRAY_SIZE(pf1550_charger_props);
+
+ chg->charger = power_supply_register(&pdev->dev, &chg->psy_desc,
+ &psy_cfg);
+ if (IS_ERR(chg->charger)) {
+ dev_err(&pdev->dev, "failed: power supply register\n");
+ ret = PTR_ERR(chg->charger);
+ return ret;
+ }
+
+ ret = pf1550_reg_init(chg);
+
+ return ret;
+}
+
+static int pf1550_charger_remove(struct platform_device *pdev)
+{
+ struct pf1550_charger *chg = platform_get_drvdata(pdev);
+
+ cancel_delayed_work_sync(&chg->irq_work);
+ power_supply_unregister(chg->charger);
+
+ return 0;
+}
+
+static const struct platform_device_id pf1550_charger_id[] = {
+ { "pf1550-charger", 0, },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, pf1550_charger_id);
+
+static struct platform_driver pf1550_charger_driver = {
+ .driver = {
+ .name = "pf1550-charger",
+ },
+ .probe = pf1550_charger_probe,
+ .remove = pf1550_charger_remove,
+ .id_table = pf1550_charger_id,
+};
+module_platform_driver(pf1550_charger_driver);
+
+MODULE_AUTHOR("Robin Gong <yibin.gong@freescale.com>");
+MODULE_DESCRIPTION("PF1550 charger driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/supply/sabresd_battery.c b/drivers/power/supply/sabresd_battery.c
new file mode 100644
index 000000000000..5f479f83525a
--- /dev/null
+++ b/drivers/power/supply/sabresd_battery.c
@@ -0,0 +1,1014 @@
+/*
+ * sabresd_battery.c - Maxim 8903 USB/Adapter Charger Driver
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc.
+ * Based on max8903_charger.c
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <linux/power/sabresd_battery.h>
+#include <linux/slab.h>
+
+#define BATTERY_UPDATE_INTERVAL 5 /*seconds*/
+#define LOW_VOLT_THRESHOLD 2800000
+#define HIGH_VOLT_THRESHOLD 4200000
+#define ADC_SAMPLE_COUNT 6
+
+struct max8903_data {
+ struct max8903_pdata *pdata;
+ struct device *dev;
+ struct power_supply *psy;
+ struct power_supply *usb;
+ struct power_supply *bat;
+ struct power_supply *detect_usb;
+ bool fault;
+ bool usb_in;
+ bool ta_in;
+ bool chg_state;
+ struct delayed_work work;
+ unsigned int interval;
+ unsigned short thermal_raw;
+ int voltage_uV;
+ int current_uA;
+ int battery_status;
+ int charger_online;
+ int charger_voltage_uV;
+ int real_capacity;
+ int percent;
+ int old_percent;
+ int usb_charger_online;
+ int first_delay_count;
+};
+
+typedef struct {
+ u32 voltage;
+ u32 percent;
+} battery_capacity , *pbattery_capacity;
+
+static int offset_discharger;
+static int offset_charger;
+static int offset_usb_charger;
+
+static battery_capacity chargingTable[] = {
+ {4050, 99},
+ {4040, 98},
+ {4020, 97},
+ {4010, 96},
+ {3990, 95},
+ {3980, 94},
+ {3970, 93},
+ {3960, 92},
+ {3950, 91},
+ {3940, 90},
+ {3930, 85},
+ {3920, 81},
+ {3910, 77},
+ {3900, 73},
+ {3890, 70},
+ {3860, 65},
+ {3830, 60},
+ {3780, 55},
+ {3760, 50},
+ {3740, 45},
+ {3720, 40},
+ {3700, 35},
+ {3680, 30},
+ {3660, 25},
+ {3640, 20},
+ {3620, 17},
+ {3600, 14},
+ {3580, 13},
+ {3560, 12},
+ {3540, 11},
+ {3520, 10},
+ {3500, 9},
+ {3480, 8},
+ {3460, 7},
+ {3440, 6},
+ {3430, 5},
+ {3420, 4},
+ {3020, 0},
+};
+
+static battery_capacity dischargingTable[] = {
+ {4050, 100},
+ {4035, 99},
+ {4020, 98},
+ {4010, 97},
+ {4000, 96},
+ {3990, 96},
+ {3980, 95},
+ {3970, 92},
+ {3960, 91},
+ {3950, 90},
+ {3940, 88},
+ {3930, 86},
+ {3920, 84},
+ {3910, 82},
+ {3900, 80},
+ {3890, 74},
+ {3860, 69},
+ {3830, 64},
+ {3780, 59},
+ {3760, 54},
+ {3740, 49},
+ {3720, 44},
+ {3700, 39},
+ {3680, 34},
+ {3660, 29},
+ {3640, 24},
+ {3620, 19},
+ {3600, 14},
+ {3580, 13},
+ {3560, 12},
+ {3540, 11},
+ {3520, 10},
+ {3500, 9},
+ {3480, 8},
+ {3460, 7},
+ {3440, 6},
+ {3430, 5},
+ {3420, 4},
+ {3020, 0},
+};
+
+u32 calibrate_battery_capability_percent(struct max8903_data *data)
+{
+ u8 i;
+ pbattery_capacity pTable;
+ u32 tableSize;
+
+ if (data->battery_status == POWER_SUPPLY_STATUS_DISCHARGING) {
+ pTable = dischargingTable;
+ tableSize = sizeof(dischargingTable)/
+ sizeof(dischargingTable[0]);
+ } else {
+ pTable = chargingTable;
+ tableSize = sizeof(chargingTable)/
+ sizeof(chargingTable[0]);
+ }
+ for (i = 0; i < tableSize; i++) {
+ if (data->voltage_uV >= pTable[i].voltage)
+ return pTable[i].percent;
+ }
+
+ return 0;
+}
+
+static enum power_supply_property max8903_charger_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static enum power_supply_property max8903_battery_props[] = {
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+};
+
+extern int max11801_read_adc(void);
+
+static void max8903_charger_update_status(struct max8903_data *data)
+{
+ if (data->ta_in) {
+ data->charger_online = 1;
+ } else if (data->usb_in) {
+ data->usb_charger_online = 1;
+ } else {
+ data->charger_online = 0;
+ data->usb_charger_online = 0;
+ }
+
+ if (!data->charger_online && !data->usb_charger_online) {
+ data->battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
+ } else if (gpio_get_value(data->pdata->chg) == 0) {
+ data->battery_status = POWER_SUPPLY_STATUS_CHARGING;
+ } else if ((data->ta_in || data->usb_in) &&
+ gpio_get_value(data->pdata->chg) > 0) {
+ if (!data->pdata->feature_flag) {
+ if (data->percent >= 99)
+ data->battery_status = POWER_SUPPLY_STATUS_FULL;
+ else
+ data->battery_status =
+ POWER_SUPPLY_STATUS_NOT_CHARGING;
+ } else {
+ data->battery_status = POWER_SUPPLY_STATUS_FULL;
+ }
+ }
+}
+
+u32 calibration_voltage(struct max8903_data *data)
+{
+ u32 voltage_data = 0;
+ int adc_val = 0;
+ int i;
+ int offset;
+
+ if (!data->charger_online && !data->usb_charger_online)
+ offset = offset_discharger;
+ else if (data->usb_charger_online)
+ offset = offset_usb_charger;
+ else if (data->charger_online)
+ offset = offset_charger;
+
+ /* simple average */
+ for (i = 0; i < ADC_SAMPLE_COUNT; i++) {
+ adc_val = max11801_read_adc();
+ /* Check if touch driver is probed */
+ if (max11801_read_adc() < 0)
+ break;
+ voltage_data += adc_val - offset;
+ }
+ voltage_data = voltage_data / ADC_SAMPLE_COUNT;
+ dev_dbg(data->dev, "volt: %d\n", voltage_data);
+
+ return voltage_data;
+}
+
+static void max8903_battery_update_status(struct max8903_data *data)
+{
+ if (!data->pdata->feature_flag) {
+ data->voltage_uV = calibration_voltage(data);
+ data->percent = calibrate_battery_capability_percent(data);
+ if (data->percent != data->old_percent) {
+ data->old_percent = data->percent;
+ power_supply_changed(data->bat);
+ }
+ /*
+ * because boot time gap between led framwork and charger
+ * framwork,when system boots with charger attatched,
+ * charger led framwork loses the first charger online event,
+ * add once extra power_supply_changed can fix this issure
+ */
+ if (data->first_delay_count < 200) {
+ data->first_delay_count = data->first_delay_count + 1;
+ power_supply_changed(data->bat);
+ }
+ }
+}
+
+static int max8903_battery_get_property(struct power_supply *bat,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct max8903_data *di = power_supply_get_drvdata(bat);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+ if (gpio_get_value(di->pdata->chg) == 0) {
+ di->battery_status = POWER_SUPPLY_STATUS_CHARGING;
+ } else if ((di->ta_in || di->usb_in) &&
+ gpio_get_value(di->pdata->chg) > 0) {
+ if (!di->pdata->feature_flag) {
+ if (di->percent >= 99)
+ di->battery_status =
+ POWER_SUPPLY_STATUS_FULL;
+ else
+ di->battery_status =
+ POWER_SUPPLY_STATUS_NOT_CHARGING;
+ } else {
+ di->battery_status = POWER_SUPPLY_STATUS_FULL;
+ }
+ }
+ val->intval = di->battery_status;
+ return 0;
+ default:
+ break;
+ }
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = di->voltage_uV;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ val->intval = 0;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+ val->intval = HIGH_VOLT_THRESHOLD;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+ val->intval = LOW_VOLT_THRESHOLD;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = 1;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = di->percent < 0 ? 0 :
+ (di->percent > 100 ? 100 : di->percent);
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ if (di->fault)
+ val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+ if (di->battery_status == POWER_SUPPLY_STATUS_FULL)
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+ else if (di->percent <= 15)
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+ else
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int max8903_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct max8903_data *data = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = 0;
+ if (data->ta_in)
+ val->intval = 1;
+ data->charger_online = val->intval;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int max8903_get_usb_property(struct power_supply *usb,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct max8903_data *data = power_supply_get_drvdata(usb);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = 0;
+ if (data->usb_in)
+ val->intval = 1;
+ data->usb_charger_online = val->intval;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static irqreturn_t max8903_dcin(int irq, void *_data)
+{
+ struct max8903_data *data = _data;
+ struct max8903_pdata *pdata = data->pdata;
+ bool ta_in = false;
+
+ if (pdata->dok)
+ ta_in = gpio_get_value(pdata->dok) ? false : true;
+
+ if (ta_in == data->ta_in)
+ return IRQ_HANDLED;
+
+ data->ta_in = ta_in;
+ dev_info(data->dev, "TA(DC-IN) Charger %s.\n", ta_in ?
+ "Connected" : "Disconnected");
+ max8903_charger_update_status(data);
+ power_supply_changed(data->psy);
+ power_supply_changed(data->bat);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t max8903_usbin(int irq, void *_data)
+{
+ struct max8903_data *data = _data;
+ struct max8903_pdata *pdata = data->pdata;
+ bool usb_in = false;
+
+ if (pdata->uok)
+ usb_in = gpio_get_value(pdata->uok) ? false : true;
+ if (usb_in == data->usb_in)
+ return IRQ_HANDLED;
+ data->usb_in = usb_in;
+ dev_info(data->dev, "USB Charger %s.\n", usb_in ?
+ "Connected" : "Disconnected");
+ max8903_charger_update_status(data);
+ power_supply_changed(data->bat);
+ power_supply_changed(data->usb);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t max8903_fault(int irq, void *_data)
+{
+ struct max8903_data *data = _data;
+ struct max8903_pdata *pdata = data->pdata;
+ bool fault;
+
+ fault = gpio_get_value(pdata->flt) ? false : true;
+
+ if (fault == data->fault)
+ return IRQ_HANDLED;
+ data->fault = fault;
+
+ if (fault)
+ dev_err(data->dev, "Charger suffers a fault and stops.\n");
+ else
+ dev_err(data->dev, "Charger recovered from a fault.\n");
+ max8903_charger_update_status(data);
+ power_supply_changed(data->psy);
+ power_supply_changed(data->bat);
+ power_supply_changed(data->usb);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t max8903_chg(int irq, void *_data)
+{
+ struct max8903_data *data = _data;
+ struct max8903_pdata *pdata = data->pdata;
+ int chg_state;
+
+ chg_state = gpio_get_value(pdata->chg) ? false : true;
+
+ if (chg_state == data->chg_state)
+ return IRQ_HANDLED;
+ data->chg_state = chg_state;
+ max8903_charger_update_status(data);
+ power_supply_changed(data->psy);
+ power_supply_changed(data->bat);
+ power_supply_changed(data->usb);
+
+ return IRQ_HANDLED;
+}
+
+static void max8903_battery_work(struct work_struct *work)
+{
+ struct max8903_data *data;
+
+ data = container_of(work, struct max8903_data, work.work);
+ data->interval = HZ * BATTERY_UPDATE_INTERVAL;
+
+ max8903_charger_update_status(data);
+ max8903_battery_update_status(data);
+ dev_dbg(data->dev, "battery voltage: %4d mV\n", data->voltage_uV);
+ dev_dbg(data->dev, "charger online status: %d\n",
+ data->charger_online);
+ dev_dbg(data->dev, "battery status : %d\n" , data->battery_status);
+ dev_dbg(data->dev, "battery capacity percent: %3d\n", data->percent);
+ dev_dbg(data->dev, "data->usb_in: %x , data->ta_in: %x\n",
+ data->usb_in, data->ta_in);
+ /* reschedule for the next time */
+ schedule_delayed_work(&data->work, data->interval);
+}
+
+static ssize_t max8903_voltage_offset_discharger_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "read offset_discharger:%04d\n",
+ offset_discharger);
+}
+
+static ssize_t max8903_voltage_offset_discharger_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ int ret;
+ unsigned long data;
+
+ ret = kstrtoul(buf, 10, &data);
+ offset_discharger = (int)data;
+ pr_info("read offset_discharger:%04d\n", offset_discharger);
+
+ return count;
+}
+
+static ssize_t max8903_voltage_offset_charger_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "read offset_charger:%04d\n",
+ offset_charger);
+}
+
+static ssize_t max8903_voltage_offset_charger_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ int ret;
+ unsigned long data;
+
+ ret = kstrtoul(buf, 10, &data);
+ offset_charger = (int)data;
+ pr_info("read offset_charger:%04d\n", offset_charger);
+ return count;
+}
+
+static ssize_t max8903_voltage_offset_usb_charger_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "read offset_usb_charger:%04d\n",
+ offset_usb_charger);
+}
+
+static ssize_t max8903_voltage_offset_usb_charger_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ int ret;
+ unsigned long data;
+
+ ret = kstrtoul(buf, 10, &data);
+ offset_usb_charger = (int)data;
+ pr_info("read offset_charger:%04d\n", offset_usb_charger);
+
+ return count;
+}
+
+static struct device_attribute max8903_discharger_dev_attr = {
+ .attr = {
+ .name = "max8903_ctl_offset_discharger",
+ .mode = S_IRUSR | S_IWUSR,
+ },
+ .show = max8903_voltage_offset_discharger_show,
+ .store = max8903_voltage_offset_discharger_store,
+};
+
+static struct device_attribute max8903_charger_dev_attr = {
+ .attr = {
+ .name = "max8903_ctl_offset_charger",
+ .mode = S_IRUSR | S_IWUSR,
+ },
+ .show = max8903_voltage_offset_charger_show,
+ .store = max8903_voltage_offset_charger_store,
+};
+
+static struct device_attribute max8903_usb_charger_dev_attr = {
+ .attr = {
+ .name = "max8903_ctl_offset_usb_charger",
+ .mode = S_IRUSR | S_IWUSR,
+ },
+ .show = max8903_voltage_offset_usb_charger_show,
+ .store = max8903_voltage_offset_usb_charger_store,
+};
+
+#if defined(CONFIG_OF)
+static const struct of_device_id max8903_dt_ids[] = {
+ { .compatible = "fsl,max8903-charger", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, max8903_dt_ids);
+
+static struct max8903_pdata *max8903_of_populate_pdata(
+ struct device *dev)
+{
+ struct device_node *of_node = dev->of_node;
+ struct max8903_pdata *pdata = dev->platform_data;
+
+ if (!of_node || pdata)
+ return pdata;
+
+ pdata = devm_kzalloc(dev, sizeof(struct max8903_pdata),
+ GFP_KERNEL);
+ if (!pdata)
+ return pdata;
+
+ if (of_get_property(of_node, "fsl,dcm_always_high", NULL))
+ pdata->dcm_always_high = true;
+ if (of_get_property(of_node, "fsl,dc_valid", NULL))
+ pdata->dc_valid = true;
+ if (of_get_property(of_node, "fsl,usb_valid", NULL))
+ pdata->usb_valid = true;
+ if (of_get_property(of_node, "fsl,adc_disable", NULL))
+ pdata->feature_flag = true;
+
+ if (pdata->dc_valid) {
+ pdata->dok = of_get_named_gpio(of_node, "dok_input", 0);
+ if (!gpio_is_valid(pdata->dok)) {
+ dev_err(dev, "pin pdata->dok: invalid gpio %d\n", pdata->dok);
+ return NULL;
+ }
+ }
+ if (pdata->usb_valid) {
+ pdata->uok = of_get_named_gpio(of_node, "uok_input", 0);
+ if (!gpio_is_valid(pdata->uok)) {
+ dev_err(dev, "pin pdata->uok: invalid gpio %d\n", pdata->uok);
+ return NULL;
+ }
+ }
+ pdata->chg = of_get_named_gpio(of_node, "chg_input", 0);
+ if (!gpio_is_valid(pdata->chg)) {
+ dev_err(dev, "pin pdata->chg: invalid gpio %d\n", pdata->chg);
+ return NULL;
+ }
+ pdata->flt = of_get_named_gpio(of_node, "flt_input", 0);
+ if (!gpio_is_valid(pdata->flt)) {
+ dev_err(dev, "pin pdata->flt: invalid gpio %d\n", pdata->flt);
+ return NULL;
+ }
+
+ /* no need check offset without adc converter */
+ if (!pdata->feature_flag) {
+ if (of_property_read_u32(of_node, "offset-charger",
+ &offset_charger))
+ dev_err(dev, "Not setting offset-charger in dts!\n");
+
+ if (of_property_read_u32(of_node, "offset-discharger",
+ &offset_discharger))
+ dev_err(dev, "Not setting offset-discharger in dts!\n");
+
+ if (of_property_read_u32(of_node, "offset-usb-charger",
+ &offset_usb_charger))
+ dev_err(dev, "Not setting offset-usb-charger in dts!\n");
+ }
+
+ return pdata;
+}
+#endif
+
+static const struct power_supply_desc max8903_ac_desc = {
+ .name = "max8903-ac",
+ .type = POWER_SUPPLY_TYPE_MAINS,
+ .get_property = max8903_get_property,
+ .properties = max8903_charger_props,
+ .num_properties = ARRAY_SIZE(max8903_charger_props),
+};
+
+static const struct power_supply_desc max8903_usb_desc = {
+ .name = "max8903-usb",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .get_property = max8903_get_usb_property,
+ .properties = max8903_charger_props,
+ .num_properties = ARRAY_SIZE(max8903_charger_props),
+};
+
+static const struct power_supply_desc max8903_bat_desc = {
+ .name = "max8903-charger",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .properties = max8903_battery_props,
+ .num_properties = ARRAY_SIZE(max8903_battery_props),
+ .get_property = max8903_battery_get_property,
+ .use_for_apm = 1,
+};
+
+static int max8903_probe(struct platform_device *pdev)
+{
+ struct max8903_data *data;
+ struct device *dev = &pdev->dev;
+ struct max8903_pdata *pdata = pdev->dev.platform_data;
+ int ret = 0;
+ int gpio = 0;
+ int ta_in = 0;
+ int usb_in = 0;
+ struct power_supply_config psy_cfg = {};
+
+ data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ pdata = max8903_of_populate_pdata(&pdev->dev);
+ if (!pdata)
+ return -EINVAL;
+ }
+
+ data->first_delay_count = 0;
+ data->pdata = pdata;
+ data->dev = dev;
+ data->usb_in = 0;
+ data->ta_in = 0;
+ platform_set_drvdata(pdev, data);
+
+ if (pdata->dc_valid == false && pdata->usb_valid == false) {
+ dev_err(dev, "No valid power sources.\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ if (pdata->dc_valid) {
+ if (pdata->dok && pdata->dcm_always_high) {
+ gpio = pdata->dok;
+ ret = gpio_request_one(gpio, GPIOF_IN, "max8903-DOK");
+ if (ret) {
+ dev_err(dev, "request max8903-DOK error!!\n");
+ goto err;
+ }
+ ta_in = gpio_get_value(gpio) ? 0 : 1;
+ } else {
+ dev_err(dev, "When DC is wired, DOK and DCM should be"
+ " wired as well or set dcm always high!\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ if (pdata->usb_valid) {
+ if (pdata->uok) {
+ gpio = pdata->uok;
+ ret = gpio_request_one(gpio, GPIOF_IN, "max8903-UOK");
+ if (ret) {
+ dev_err(dev, "request max8903-UOK error!!\n");
+ goto err;
+ }
+ usb_in = gpio_get_value(gpio) ? 0 : 1;
+ } else {
+ dev_err(dev, "When USB is wired, UOK should be wired"
+ " as well.\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ if (pdata->chg) {
+ ret = gpio_request_one(pdata->chg, GPIOF_IN, "max8903-CHG");
+ if (ret) {
+ dev_err(dev, "request max8903-CHG error!!\n");
+ goto err;
+ }
+ }
+
+ if (pdata->flt) {
+ ret = gpio_request_one(pdata->flt, GPIOF_IN, "max8903-FLT");
+ if (ret) {
+ dev_err(dev, "request max8903-FLT error!!\n");
+ goto err;
+ }
+ }
+
+ data->fault = false;
+ data->ta_in = ta_in;
+ data->usb_in = usb_in;
+
+ psy_cfg.of_node = dev->of_node;
+ psy_cfg.drv_data = data;
+
+ data->psy = power_supply_register(dev, &max8903_ac_desc, &psy_cfg);
+ if (IS_ERR(data->psy)) {
+ dev_err(dev, "failed: power supply register.\n");
+ goto err;
+ }
+
+ data->usb = power_supply_register(dev, &max8903_usb_desc, &psy_cfg);
+ if (IS_ERR(data->usb)) {
+ dev_err(dev, "failed: power supply register.\n");
+ goto err_psy;
+ }
+
+ data->bat = power_supply_register(dev, &max8903_bat_desc, &psy_cfg);
+ if (IS_ERR(data->bat)) {
+ dev_err(data->dev, "failed to register battery\n");
+ goto err_usb;
+ }
+
+ INIT_DELAYED_WORK(&data->work, max8903_battery_work);
+ schedule_delayed_work(&data->work, data->interval);
+
+ if (pdata->dc_valid) {
+ ret = request_threaded_irq(gpio_to_irq(pdata->dok), NULL,
+ max8903_dcin, IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT, "MAX8903 DC IN",
+ data);
+ if (ret) {
+ dev_err(dev, "Cannot request irq %d for DC (%d)\n",
+ gpio_to_irq(pdata->dok), ret);
+ goto err_dc_irq;
+ }
+ }
+
+ if (pdata->usb_valid) {
+ ret = request_threaded_irq(gpio_to_irq(pdata->uok), NULL,
+ max8903_usbin, IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT, "MAX8903 USB IN",
+ data);
+ if (ret) {
+ dev_err(dev, "Cannot request irq %d for USB (%d)\n",
+ gpio_to_irq(pdata->uok), ret);
+ goto err_usb_irq;
+ }
+ }
+
+ if (pdata->flt) {
+ ret = request_threaded_irq(gpio_to_irq(pdata->flt), NULL,
+ max8903_fault, IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT, "MAX8903 Fault",
+ data);
+ if (ret) {
+ dev_err(dev, "Cannot request irq %d for Fault (%d)\n",
+ gpio_to_irq(pdata->flt), ret);
+ goto err_flt_irq;
+ }
+ }
+
+ if (pdata->chg) {
+ ret = request_threaded_irq(gpio_to_irq(pdata->chg), NULL,
+ max8903_chg, IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT, "MAX8903 Status",
+ data);
+ if (ret) {
+ dev_err(dev, "Cannot request irq %d for Status (%d)\n",
+ gpio_to_irq(pdata->flt), ret);
+ goto err_chg_irq;
+ }
+ }
+
+ ret = device_create_file(&pdev->dev, &max8903_discharger_dev_attr);
+ if (ret)
+ dev_err(&pdev->dev, "create device file failed!\n");
+ ret = device_create_file(&pdev->dev, &max8903_charger_dev_attr);
+ if (ret)
+ dev_err(&pdev->dev, "create device file failed!\n");
+ ret = device_create_file(&pdev->dev, &max8903_usb_charger_dev_attr);
+ if (ret)
+ dev_err(&pdev->dev, "create device file failed!\n");
+
+ device_set_wakeup_capable(&pdev->dev, true);
+
+ max8903_charger_update_status(data);
+ max8903_battery_update_status(data);
+
+ return 0;
+err_chg_irq:
+ if (pdata->chg)
+ free_irq(gpio_to_irq(pdata->chg), data);
+err_flt_irq:
+ if (pdata->flt)
+ free_irq(gpio_to_irq(pdata->flt), data);
+err_usb_irq:
+ if (pdata->usb_valid)
+ free_irq(gpio_to_irq(pdata->uok), data);
+err_dc_irq:
+ if (pdata->dc_valid)
+ free_irq(gpio_to_irq(pdata->dok), data);
+ cancel_delayed_work(&data->work);
+ power_supply_unregister(data->bat);
+err_usb:
+ power_supply_unregister(data->usb);
+err_psy:
+ power_supply_unregister(data->psy);
+err:
+ if (pdata->uok)
+ gpio_free(pdata->uok);
+ if (pdata->dok)
+ gpio_free(pdata->dok);
+ if (pdata->flt)
+ gpio_free(pdata->flt);
+ if (pdata->chg)
+ gpio_free(pdata->chg);
+ return ret;
+}
+
+static int max8903_remove(struct platform_device *pdev)
+{
+ struct max8903_data *data = platform_get_drvdata(pdev);
+ if (data) {
+ struct max8903_pdata *pdata = data->pdata;
+
+ cancel_delayed_work_sync(&data->work);
+ power_supply_unregister(data->psy);
+ power_supply_unregister(data->usb);
+ power_supply_unregister(data->bat);
+
+ if (pdata->flt) {
+ free_irq(gpio_to_irq(pdata->flt), data);
+ gpio_free(pdata->flt);
+ }
+ if (pdata->usb_valid && pdata->uok) {
+ free_irq(gpio_to_irq(pdata->uok), data);
+ gpio_free(pdata->uok);
+ }
+ if (pdata->dc_valid) {
+ if (pdata->dok) {
+ free_irq(gpio_to_irq(pdata->dok), data);
+ gpio_free(pdata->dok);
+ } else if (pdata->chg) {
+ free_irq(gpio_to_irq(pdata->chg), data);
+ gpio_free(pdata->chg);
+ }
+ }
+
+ device_remove_file(&pdev->dev, &max8903_discharger_dev_attr);
+ device_remove_file(&pdev->dev, &max8903_charger_dev_attr);
+ device_remove_file(&pdev->dev, &max8903_usb_charger_dev_attr);
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+ }
+
+ return 0;
+}
+
+static int max8903_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct max8903_data *data = platform_get_drvdata(pdev);
+ int irq;
+ if (data) {
+ struct max8903_pdata *pdata = data->pdata;
+ if (pdata) {
+ if (pdata->dc_valid && device_may_wakeup(&pdev->dev)) {
+ irq = gpio_to_irq(pdata->dok);
+ enable_irq_wake(irq);
+ }
+
+ if (pdata->usb_valid && device_may_wakeup(&pdev->dev)) {
+ irq = gpio_to_irq(pdata->uok);
+ enable_irq_wake(irq);
+ }
+ cancel_delayed_work(&data->work);
+ }
+ }
+ return 0;
+}
+
+static int max8903_resume(struct platform_device *pdev)
+{
+ struct max8903_data *data = platform_get_drvdata(pdev);
+ bool ta_in = false;
+ bool usb_in = false;
+ int irq;
+
+ if (data) {
+ struct max8903_pdata *pdata = data->pdata;
+
+ if (pdata) {
+ if (pdata->dok)
+ ta_in = gpio_get_value(pdata->dok) ? false : true;
+ if (pdata->uok)
+ usb_in = gpio_get_value(pdata->uok) ? false : true;
+
+ if (ta_in != data->ta_in) {
+ data->ta_in = ta_in;
+ dev_info(data->dev, "TA(DC-IN) Charger %s.\n", ta_in ?
+ "Connected" : "Disconnected");
+ max8903_charger_update_status(data);
+ power_supply_changed(data->psy);
+ }
+
+ if (usb_in != data->usb_in) {
+ data->usb_in = usb_in;
+ dev_info(data->dev, "USB Charger %s.\n", usb_in ?
+ "Connected" : "Disconnected");
+ max8903_charger_update_status(data);
+ power_supply_changed(data->usb);
+ }
+
+ if (pdata->dc_valid && device_may_wakeup(&pdev->dev)) {
+ irq = gpio_to_irq(pdata->dok);
+ disable_irq_wake(irq);
+ }
+ if (pdata->usb_valid && device_may_wakeup(&pdev->dev)) {
+ irq = gpio_to_irq(pdata->uok);
+ disable_irq_wake(irq);
+ }
+
+ schedule_delayed_work(&data->work,
+ BATTERY_UPDATE_INTERVAL);
+ }
+ }
+
+ return 0;
+}
+
+static struct platform_driver max8903_driver = {
+ .probe = max8903_probe,
+ .remove = max8903_remove,
+ .suspend = max8903_suspend,
+ .resume = max8903_resume,
+ .driver = {
+ .name = "max8903-charger",
+ .owner = THIS_MODULE,
+ .of_match_table = max8903_dt_ids,
+ },
+};
+module_platform_driver(max8903_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Sabresd Battery Driver");
+MODULE_ALIAS("sabresd_battery");
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index bf0128899c09..ffb60a4db314 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -190,13 +190,22 @@ config PWM_IMG
config PWM_IMX
tristate "i.MX PWM support"
- depends on ARCH_MXC
+ depends on ARCH_MXC || ARCH_MXC_ARM64
help
Generic PWM framework driver for i.MX.
To compile this driver as a module, choose M here: the module
will be called pwm-imx.
+config PWM_TPM
+ tristate "i.MX TPM PWM support"
+ depends on ARCH_MXC
+ help
+ Generic PWM framework driver for i.MX TPM.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-tpm.
+
config PWM_JZ4740
tristate "Ingenic JZ4740 PWM support"
depends on MACH_JZ4740
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 1194c54efcc2..e13e3b19ce36 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o
obj-$(CONFIG_PWM_IMG) += pwm-img.o
obj-$(CONFIG_PWM_IMX) += pwm-imx.o
+obj-$(CONFIG_PWM_TPM) += pwm-tpm.o
obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o
obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o
obj-$(CONFIG_PWM_LPC18XX_SCT) += pwm-lpc18xx-sct.o
diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c
index fad968eb75f6..7a800b02be94 100644
--- a/drivers/pwm/pwm-fsl-ftm.c
+++ b/drivers/pwm/pwm-fsl-ftm.c
@@ -86,7 +86,9 @@ struct fsl_pwm_chip {
struct regmap *regmap;
int period_ns;
+ bool has_pwmen;
+ struct clk *ipg_clk;
struct clk *clk[FSL_PWM_CLK_MAX];
};
@@ -95,18 +97,39 @@ static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip)
return container_of(chip, struct fsl_pwm_chip, chip);
}
+static inline int fsl_pwm_mode_enable(struct fsl_pwm_chip *fpc)
+{
+ if (!fpc)
+ return -ENODEV;
+
+ if (fpc->ipg_clk)
+ clk_prepare_enable(fpc->ipg_clk);
+
+ return clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]);
+}
+
+static inline void fsl_pwm_mode_disable(struct fsl_pwm_chip *fpc)
+{
+ if (!fpc)
+ return;
+
+ clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
+ if (fpc->ipg_clk)
+ clk_disable_unprepare(fpc->ipg_clk);
+}
+
static int fsl_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
- return clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]);
+ return fsl_pwm_mode_enable(fpc);
}
static void fsl_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
- clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
+ fsl_pwm_mode_disable(fpc);
}
static int fsl_pwm_calculate_default_ps(struct fsl_pwm_chip *fpc,
@@ -323,6 +346,9 @@ static int fsl_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
mutex_lock(&fpc->lock);
regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm), 0);
+ if (fpc->has_pwmen)
+ regmap_update_bits(fpc->regmap, FTM_SC,
+ BIT(pwm->hwpwm + 16), BIT(pwm->hwpwm + 16));
ret = fsl_counter_clock_enable(fpc);
mutex_unlock(&fpc->lock);
@@ -336,6 +362,10 @@ static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
u32 val;
mutex_lock(&fpc->lock);
+
+ if (fpc->has_pwmen)
+ regmap_update_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16), 0);
+
regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm),
BIT(pwm->hwpwm));
@@ -363,7 +393,7 @@ static int fsl_pwm_init(struct fsl_pwm_chip *fpc)
{
int ret;
- ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]);
+ ret = fsl_pwm_mode_enable(fpc);
if (ret)
return ret;
@@ -371,7 +401,7 @@ static int fsl_pwm_init(struct fsl_pwm_chip *fpc)
regmap_write(fpc->regmap, FTM_OUTINIT, 0x00);
regmap_write(fpc->regmap, FTM_OUTMASK, 0xFF);
- clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
+ fsl_pwm_mode_disable(fpc);
return 0;
}
@@ -422,7 +452,12 @@ static int fsl_pwm_probe(struct platform_device *pdev)
return PTR_ERR(fpc->regmap);
}
+ fpc->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
+ if (IS_ERR(fpc->ipg_clk))
+ fpc->ipg_clk = 0;
+
fpc->clk[FSL_PWM_CLK_SYS] = devm_clk_get(&pdev->dev, "ftm_sys");
+
if (IS_ERR(fpc->clk[FSL_PWM_CLK_SYS])) {
dev_err(&pdev->dev, "failed to get \"ftm_sys\" clock\n");
return PTR_ERR(fpc->clk[FSL_PWM_CLK_SYS]);
@@ -447,6 +482,8 @@ static int fsl_pwm_probe(struct platform_device *pdev)
fpc->chip.base = -1;
fpc->chip.npwm = 8;
fpc->chip.can_sleep = true;
+ fpc->has_pwmen = of_property_read_bool(pdev->dev.of_node,
+ "ftm-has-pwmen-bits");
ret = pwmchip_add(&fpc->chip);
if (ret < 0) {
@@ -481,7 +518,7 @@ static int fsl_pwm_suspend(struct device *dev)
if (!test_bit(PWMF_REQUESTED, &pwm->flags))
continue;
- clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
+ fsl_pwm_mode_disable(fpc);
if (!pwm_is_enabled(pwm))
continue;
@@ -504,7 +541,7 @@ static int fsl_pwm_resume(struct device *dev)
if (!test_bit(PWMF_REQUESTED, &pwm->flags))
continue;
- clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]);
+ fsl_pwm_mode_enable(fpc);
if (!pwm_is_enabled(pwm))
continue;
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index d600fd5cd4ba..2c2818c4b96e 100644
--- a/drivers/pwm/pwm-imx.c
+++ b/drivers/pwm/pwm-imx.c
@@ -50,6 +50,7 @@
struct imx_chip {
struct clk *clk_per;
struct clk *clk_ipg;
+ struct clk *clk_32k;
void __iomem *mmio_base;
@@ -206,14 +207,29 @@ static int imx_pwm_config(struct pwm_chip *chip,
struct imx_chip *imx = to_imx_chip(chip);
int ret;
+ if (imx->clk_32k) {
+ ret = clk_prepare_enable(imx->clk_32k);
+ if (ret)
+ goto err1;
+ }
+
+ ret = clk_prepare_enable(imx->clk_per);
+ if (ret)
+ goto err2;
+
ret = clk_prepare_enable(imx->clk_ipg);
if (ret)
- return ret;
+ goto err3;
ret = imx->config(chip, pwm, duty_ns, period_ns);
clk_disable_unprepare(imx->clk_ipg);
-
+err3:
+ clk_disable_unprepare(imx->clk_per);
+err2:
+ if (imx->clk_32k)
+ clk_disable_unprepare(imx->clk_32k);
+err1:
return ret;
}
@@ -222,13 +238,30 @@ static int imx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
struct imx_chip *imx = to_imx_chip(chip);
int ret;
+ if (imx->clk_32k) {
+ ret = clk_prepare_enable(imx->clk_32k);
+ if (ret)
+ goto err1;
+ }
+
ret = clk_prepare_enable(imx->clk_per);
if (ret)
- return ret;
+ goto err2;
+
+ ret = clk_prepare_enable(imx->clk_ipg);
+ if (ret)
+ goto err3;
imx->set_enable(chip, true);
return 0;
+err3:
+ clk_disable_unprepare(imx->clk_per);
+err2:
+ if (imx->clk_32k)
+ clk_disable_unprepare(imx->clk_32k);
+err1:
+ return ret;
}
static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
@@ -237,7 +270,10 @@ static void imx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
imx->set_enable(chip, false);
+ clk_disable_unprepare(imx->clk_ipg);
clk_disable_unprepare(imx->clk_per);
+ if (imx->clk_32k)
+ clk_disable_unprepare(imx->clk_32k);
}
static struct pwm_ops imx_pwm_ops = {
@@ -300,6 +336,10 @@ static int imx_pwm_probe(struct platform_device *pdev)
return PTR_ERR(imx->clk_ipg);
}
+ imx->clk_32k = devm_clk_get(&pdev->dev, "32k");
+ if (IS_ERR(imx->clk_32k))
+ imx->clk_32k = NULL;
+
imx->chip.ops = &imx_pwm_ops;
imx->chip.dev = &pdev->dev;
imx->chip.base = -1;
diff --git a/drivers/pwm/pwm-tpm.c b/drivers/pwm/pwm-tpm.c
new file mode 100644
index 000000000000..63312877785a
--- /dev/null
+++ b/drivers/pwm/pwm-tpm.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2017-2018 NXP.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+#define TPM_GLOBAL 0x8
+#define TPM_SC 0x10
+#define TPM_CNT 0x14
+#define TPM_MOD 0x18
+#define TPM_C0SC 0x20
+#define TPM_C0V 0x24
+
+#define SC_CMOD 3
+#define SC_CPWMS BIT(5)
+#define MSnB BIT(5)
+#define MSnA BIT(4)
+#define ELSnB BIT(3)
+#define ELSnA BIT(2)
+
+#define PERIOD_PERIOD_MAX 0x10000
+#define PERIOD_DIV_MAX 8
+
+struct tpm_pwm_chip {
+ struct pwm_chip chip;
+ struct clk *clk;
+ void __iomem *base;
+};
+
+static const unsigned int prediv[8] = {
+ 1, 2, 4, 8, 16, 32, 64, 128
+};
+
+#define to_tpm_pwm_chip(_chip) container_of(_chip, struct tpm_pwm_chip, chip)
+
+static int tpm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ int duty_ns, int period_ns)
+{
+ struct tpm_pwm_chip *tpm = to_tpm_pwm_chip(chip);
+ int ret, val, div = 0;
+ unsigned int period_cycles, duty_cycles;
+ unsigned long rate;
+ u64 c;
+
+ rate = clk_get_rate(tpm->clk);
+ /* calculate the period_cycles and duty_cycles */
+ while (1) {
+ c = rate / prediv[div];
+ c = c * period_ns;
+ do_div(c, 1000000000);
+ if (c < PERIOD_PERIOD_MAX)
+ break;
+ div++;
+ if (div >= 8)
+ return -EINVAL;
+ }
+
+ /* enable the clock before writing the register */
+ if (!pwm_is_enabled(pwm)) {
+ ret = clk_prepare_enable(tpm->clk);
+ if (ret)
+ return ret;
+ }
+
+ /* set the pre-scale */
+ val = readl(tpm->base + TPM_SC);
+ val &= ~0x7;
+ val |= div;
+ writel(val, tpm->base + TPM_SC);
+
+ period_cycles = c;
+ c *= duty_ns;
+ do_div(c, period_ns);
+ duty_cycles = c;
+
+ writel(period_cycles & 0xffff, tpm->base + TPM_MOD);
+ writel(duty_cycles & 0xffff, tpm->base + TPM_C0V + pwm->hwpwm * 0x8);
+
+ /* if pwm is not enabled, disable clk after setting */
+ if (!pwm_is_enabled(pwm))
+ clk_disable_unprepare(tpm->clk);
+
+ return 0;
+}
+
+static int tpm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct tpm_pwm_chip *tpm = to_tpm_pwm_chip(chip);
+ int val;
+
+ clk_prepare_enable(tpm->clk);
+ /*
+ * To enable a tpm channel, CPWMS = 0, MSnB:MSnA = 0x0,
+ * for TPM normal polarity ELSnB:ELSnA = 2b'10,
+ * inverse ELSnB:ELSnA = 2b'01
+ */
+ val = readl(tpm->base + TPM_C0SC + pwm->hwpwm * 0x8);
+
+ val &= ~(MSnB | MSnA | ELSnB | ELSnA);
+ val |= MSnB;
+ val |= pwm->state.polarity ? ELSnA : ELSnB;
+
+ writel(val, tpm->base + TPM_C0SC + pwm->hwpwm * 0x8);
+
+ /* start the counter */
+ val = readl(tpm->base + TPM_SC);
+ val |= 0x1 << SC_CMOD;
+ writel(val, tpm->base + TPM_SC);
+
+ return 0;
+}
+
+static void tpm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct tpm_pwm_chip *tpm = to_tpm_pwm_chip(chip);
+
+ clk_disable_unprepare(tpm->clk);
+}
+
+static int tpm_pwm_set_polarity(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ enum pwm_polarity polarity)
+{
+ struct tpm_pwm_chip *tpm = to_tpm_pwm_chip(chip);
+ int ret, val;
+
+ /* enable the clock before writing the register */
+ if (!pwm_is_enabled(pwm)) {
+ ret = clk_prepare_enable(tpm->clk);
+ if (ret)
+ return ret;
+ }
+
+ val = readl(tpm->base + TPM_C0SC + pwm->hwpwm * 0x8);
+ val &= ~(ELSnB | ELSnA);
+ val |= pwm->state.polarity ? ELSnA : ELSnB;
+ writel(val, tpm->base + TPM_C0SC + pwm->hwpwm * 0x8);
+
+ if (!pwm_is_enabled(pwm))
+ clk_disable_unprepare(tpm->clk);
+
+ return 0;
+}
+
+static const struct pwm_ops tpm_pwm_ops = {
+ .config = tpm_pwm_config,
+ .enable = tpm_pwm_enable,
+ .disable = tpm_pwm_disable,
+ .set_polarity = tpm_pwm_set_polarity,
+ .owner = THIS_MODULE,
+};
+
+static int tpm_pwm_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct tpm_pwm_chip *tpm;
+ struct resource *res;
+ int ret;
+
+ tpm = devm_kzalloc(&pdev->dev, sizeof(*tpm), GFP_KERNEL);
+ if (!tpm)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ tpm->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(tpm->base))
+ return PTR_ERR(tpm->base);
+
+ tpm->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(tpm->clk))
+ return PTR_ERR(tpm->clk);
+
+ tpm->chip.dev = &pdev->dev;
+ tpm->chip.ops = &tpm_pwm_ops;
+ tpm->chip.base = -1;
+ tpm->chip.can_sleep = true;
+ /*
+ * init the number of pwm in the pwm chip. if no "fsl,pwm-number"
+ * found, init the npwm to 2, as tpm module has at least two pwm channel
+ */
+ ret = of_property_read_u32(np, "nxp,pwm-number", &tpm->chip.npwm);
+ if (ret < 0) {
+ dev_info(&pdev->dev, "default two pwm channel");
+ tpm->chip.npwm = 2;
+ }
+
+ ret = pwmchip_add(&tpm->chip);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to add pwm chip %d\n", ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, tpm);
+
+ return 0;
+}
+
+static int tpm_pwm_remove(struct platform_device *pdev)
+{
+ struct tpm_pwm_chip *tpm = platform_get_drvdata(pdev);
+
+ return pwmchip_remove(&tpm->chip);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tpm_pwm_suspend(struct device *dev)
+{
+ pinctrl_pm_select_sleep_state(dev);
+
+ return 0;
+}
+
+static int tpm_pwm_resume(struct device *dev)
+{
+ pinctrl_pm_select_default_state(dev);
+
+ return 0;
+};
+#endif
+
+static SIMPLE_DEV_PM_OPS(tpm_pwm_pm, tpm_pwm_suspend, tpm_pwm_resume);
+
+static const struct of_device_id tpm_pwm_dt_ids[] = {
+ { .compatible = "nxp,tpm-pwm", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, tpm_pwm_dt_ids);
+
+static struct platform_driver tpm_pwm_driver = {
+ .driver = {
+ .name = "tpm-pwm",
+ .of_match_table = tpm_pwm_dt_ids,
+ .pm = &tpm_pwm_pm,
+ },
+ .probe = tpm_pwm_probe,
+ .remove = tpm_pwm_remove,
+};
+module_platform_driver(tpm_pwm_driver);
+
+MODULE_ALIAS("platform:tpm-pwm");
+MODULE_AUTHOR("Jacky Bai <ping.bai@nxp.com>");
+MODULE_DESCRIPTION("NXP TPM PWM Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 936f7ccc9736..85b1e1197148 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -377,6 +377,10 @@ config REGULATOR_MAX1586
regulator via I2C bus. The provided regulator is suitable
for PXA27x chips to control VCC_CORE and VCC_USIM voltages.
+config REGULATOR_MAX17135
+ tristate "Maxim MAX17135 Regulator Support"
+ depends on MFD_MAX17135
+
config REGULATOR_MAX77620
tristate "Maxim 77620/MAX20024 voltage regulator"
depends on MFD_MAX77620
@@ -590,6 +594,21 @@ config REGULATOR_PV88090
Say y here to support the voltage regulators and convertors
on PV88090
+config REGULATOR_PF1550
+ tristate "Freescale PF1550 regulator"
+ depends on MFD_PF1550
+ help
+ This driver controls a PF1550 regulator via I2C bus.
+ The regulators include three switch and three ldo.
+
+config REGULATOR_PF1550_RPMSG
+ tristate "Freescale PF1550 rpmsg regulator driver"
+ depends on RPMSG
+ help
+ This driver controls a PF1550 regulator which connected in M4
+ side via RPMSG.The regulators include three switch and three
+ ldo.
+
config REGULATOR_PWM
tristate "PWM voltage regulator"
depends on PWM
@@ -878,5 +897,11 @@ config REGULATOR_WM8994
This driver provides support for the voltage regulators on the
WM8994 CODEC.
+config REGULATOR_BD71837
+ tristate "RoHM BD71837 Power Regulator"
+ depends on MFD_BD71837
+ help
+ This driver supports BD71837 voltage regulator chips.
+
endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 2142a5d3fc08..ab88964d3afc 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_REGULATOR_LTC3589) += ltc3589.o
obj-$(CONFIG_REGULATOR_LTC3676) += ltc3676.o
obj-$(CONFIG_REGULATOR_MAX14577) += max14577-regulator.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
+obj-$(CONFIG_REGULATOR_MAX17135) += max17135-regulator.o
obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o
obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
@@ -72,6 +73,8 @@ obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
+obj-$(CONFIG_REGULATOR_PF1550) += pf1550.o
+obj-$(CONFIG_REGULATOR_PF1550_RPMSG) += pf1550-regulator-rpmsg.o
obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
obj-$(CONFIG_REGULATOR_PV88060) += pv88060-regulator.o
obj-$(CONFIG_REGULATOR_PV88080) += pv88080-regulator.o
@@ -112,6 +115,7 @@ obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
+obj-$(CONFIG_REGULATOR_BD71837) += bd71837-regulator.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index c5e272ea4372..21f72f1c1100 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -38,6 +38,8 @@
#define LDO_POWER_GATE 0x00
#define LDO_FET_FULL_ON 0x1f
+#define LDO_MIN_DROPOUT_UV 125000
+
struct anatop_regulator {
const char *name;
u32 control_reg;
@@ -54,8 +56,12 @@ struct anatop_regulator {
struct regulator_init_data *initdata;
bool bypass;
int sel;
+ u32 enable_bit;
};
+static struct anatop_regulator *vddpu;
+static struct anatop_regulator *vddsoc;
+
static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,
unsigned int old_sel,
unsigned int new_sel)
@@ -82,21 +88,32 @@ static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg,
return ret;
}
-static int anatop_regmap_enable(struct regulator_dev *reg)
+static int anatop_core_regmap_enable(struct regulator_dev *reg)
{
struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
int sel;
+ /*
+ * The vddpu has to stay at the same voltage level as vddsoc
+ * whenever it's about to be enabled.
+ */
+ if (anatop_reg == vddpu && vddsoc) {
+ anatop_reg->sel = vddsoc->sel;
+ anatop_reg->bypass = vddsoc->bypass;
+ if (anatop_reg->bypass)
+ anatop_reg->rdesc.min_dropout_uV = 0;
+ }
+
sel = anatop_reg->bypass ? LDO_FET_FULL_ON : anatop_reg->sel;
return regulator_set_voltage_sel_regmap(reg, sel);
}
-static int anatop_regmap_disable(struct regulator_dev *reg)
+static int anatop_core_regmap_disable(struct regulator_dev *reg)
{
return regulator_set_voltage_sel_regmap(reg, LDO_POWER_GATE);
}
-static int anatop_regmap_is_enabled(struct regulator_dev *reg)
+static int anatop_core_regmap_is_enabled(struct regulator_dev *reg)
{
return regulator_get_voltage_sel_regmap(reg) != LDO_POWER_GATE;
}
@@ -107,7 +124,7 @@ static int anatop_regmap_core_set_voltage_sel(struct regulator_dev *reg,
struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
int ret;
- if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg)) {
+ if (anatop_reg->bypass || !anatop_core_regmap_is_enabled(reg)) {
anatop_reg->sel = selector;
return 0;
}
@@ -122,7 +139,7 @@ static int anatop_regmap_core_get_voltage_sel(struct regulator_dev *reg)
{
struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
- if (anatop_reg->bypass || !anatop_regmap_is_enabled(reg))
+ if (anatop_reg->bypass || !anatop_core_regmap_is_enabled(reg))
return anatop_reg->sel;
return regulator_get_voltage_sel_regmap(reg);
@@ -153,11 +170,52 @@ static int anatop_regmap_set_bypass(struct regulator_dev *reg, bool enable)
sel = enable ? LDO_FET_FULL_ON : anatop_reg->sel;
anatop_reg->bypass = enable;
+ if (anatop_reg->bypass)
+ anatop_reg->rdesc.min_dropout_uV = 0;
+ else
+ anatop_reg->rdesc.min_dropout_uV = LDO_MIN_DROPOUT_UV;
return regulator_set_voltage_sel_regmap(reg, sel);
}
+static int anatop_regmap_enable(struct regulator_dev *reg)
+{
+ u32 val;
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+
+ regmap_read(anatop_reg->anatop, anatop_reg->control_reg, &val);
+ val |= (1 << anatop_reg->enable_bit);
+ regmap_write(anatop_reg->anatop, anatop_reg->control_reg, val);
+
+ return 0;
+}
+
+static int anatop_regmap_disable(struct regulator_dev *reg)
+{
+ u32 val;
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+
+ regmap_read(anatop_reg->anatop, anatop_reg->control_reg, &val);
+ val &= ~(1 << anatop_reg->enable_bit);
+ regmap_write(anatop_reg->anatop, anatop_reg->control_reg, val);
+
+ return 0;
+}
+
+static int anatop_regmap_is_enabled(struct regulator_dev *reg)
+{
+ u32 val;
+ struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
+
+ regmap_read(anatop_reg->anatop, anatop_reg->control_reg, &val);
+
+ return !!(val & (1 << anatop_reg->enable_bit));
+}
+
static struct regulator_ops anatop_rops = {
+ .enable = anatop_regmap_enable,
+ .disable = anatop_regmap_disable,
+ .is_enabled = anatop_regmap_is_enabled,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
@@ -165,9 +223,9 @@ static struct regulator_ops anatop_rops = {
};
static struct regulator_ops anatop_core_rops = {
- .enable = anatop_regmap_enable,
- .disable = anatop_regmap_disable,
- .is_enabled = anatop_regmap_is_enabled,
+ .enable = anatop_core_regmap_enable,
+ .disable = anatop_core_regmap_disable,
+ .is_enabled = anatop_core_regmap_is_enabled,
.set_voltage_sel = anatop_regmap_core_set_voltage_sel,
.set_voltage_time_sel = anatop_regmap_set_voltage_time_sel,
.get_voltage_sel = anatop_regmap_core_get_voltage_sel,
@@ -194,6 +252,12 @@ static int anatop_regulator_probe(struct platform_device *pdev)
if (!sreg)
return -ENOMEM;
sreg->name = of_get_property(np, "regulator-name", NULL);
+
+ if (!sreg->name) {
+ dev_err(dev, "no regulator-name set\n");
+ return -EINVAL;
+ }
+
rdesc = &sreg->rdesc;
rdesc->name = sreg->name;
rdesc->type = REGULATOR_VOLTAGE;
@@ -203,6 +267,11 @@ static int anatop_regulator_probe(struct platform_device *pdev)
initdata->supply_regulator = "vin";
sreg->initdata = initdata;
+ if (strcmp(sreg->name, "vddpu") == 0)
+ vddpu = sreg;
+ else if (strcmp(sreg->name, "vddsoc") == 0)
+ vddsoc = sreg;
+
anatop_np = of_get_parent(np);
if (!anatop_np)
return -ENODEV;
@@ -256,6 +325,9 @@ static int anatop_regulator_probe(struct platform_device *pdev)
of_property_read_u32(np, "anatop-delay-bit-shift",
&sreg->delay_bit_shift);
+ /* Only 3p0, 2p5, and 1p1 has enable bit */
+ of_property_read_u32(np, "anatop-enable-bit", &sreg->enable_bit);
+
rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage) / 25000 + 1
+ sreg->min_bit_val;
rdesc->min_uV = sreg->min_voltage;
@@ -264,7 +336,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
rdesc->vsel_reg = sreg->control_reg;
rdesc->vsel_mask = ((1 << sreg->vol_bit_width) - 1) <<
sreg->vol_bit_shift;
- rdesc->min_dropout_uV = 125000;
+ rdesc->min_dropout_uV = LDO_MIN_DROPOUT_UV;
config.dev = &pdev->dev;
config.init_data = initdata;
@@ -286,6 +358,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
if (sreg->sel == LDO_FET_FULL_ON) {
sreg->sel = 0;
sreg->bypass = true;
+ rdesc->min_dropout_uV = 0;
}
/*
@@ -297,8 +370,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
sreg->sel = 22;
/* set the default voltage of the pcie phy to be 1.100v */
- if (!sreg->sel && rdesc->name &&
- !strcmp(rdesc->name, "vddpcie"))
+ if (!sreg->sel && !strcmp(sreg->name, "vddpcie-phy"))
sreg->sel = 0x10;
if (!sreg->bypass && !sreg->sel) {
@@ -312,9 +384,10 @@ static int anatop_regulator_probe(struct platform_device *pdev)
/* register regulator */
rdev = devm_regulator_register(dev, rdesc, &config);
if (IS_ERR(rdev)) {
- dev_err(dev, "failed to register %s\n",
- rdesc->name);
- return PTR_ERR(rdev);
+ ret = PTR_ERR(rdev);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to register %s\n", rdesc->name);
+ return ret;
}
platform_set_drvdata(pdev, rdev);
diff --git a/drivers/regulator/bd71837-regulator.c b/drivers/regulator/bd71837-regulator.c
new file mode 100644
index 000000000000..05ceb6a0af03
--- /dev/null
+++ b/drivers/regulator/bd71837-regulator.c
@@ -0,0 +1,1053 @@
+/*
+ * @file bd71837-regulator.c ROHM BD71837MWV regulator driver
+ *
+ * @author: cpham2403@gmail.com
+ * Copyright 2017.
+ *
+ *
+ * This program is free software; 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
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/mfd/bd71837.h>
+#include <linux/regulator/of_regulator.h>
+
+#define BD71837_DVS_BUCK_NUM 4 /* Buck 1/2/3/4 support DVS */
+#define BD71837_DVS_RUN_IDLE_SUSP 3
+#define BD71837_DVS_RUN_IDLE 2
+#define BD71837_DVS_RUN 1
+
+struct bd71837_buck_dvs {
+ u32 voltage[BD71837_DVS_RUN_IDLE_SUSP];
+};
+
+/** @brief bd71837 regulator type */
+struct bd71837_pmic {
+ struct regulator_desc descs[BD71837_REGULATOR_CNT]; /**< regulator description to system */
+ struct bd71837 *mfd; /**< parent device */
+ struct device *dev; /**< regulator kernel device */
+ struct regulator_dev *rdev[BD71837_REGULATOR_CNT]; /**< regulator device of system */
+ struct bd71837_buck_dvs buck_dvs[BD71837_DVS_BUCK_NUM]; /**< buck1/2 dvs */
+ int reg_index;
+};
+
+/*
+ * BUCK1/2/3/4
+ * BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting
+ * 00: 10.00mV/usec 10mV 1uS
+ * 01: 5.00mV/usec 10mV 2uS
+ * 10: 2.50mV/usec 10mV 4uS
+ * 11: 1.25mV/usec 10mV 8uS
+ */
+static int bd71837_buck1234_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+ struct bd71837_pmic *pmic = rdev_get_drvdata(rdev);
+ struct bd71837 *mfd = pmic->mfd;
+ int id = rdev->desc->id;
+ unsigned int ramp_value = BUCK1_RAMPRATE_10P00MV;
+
+ dev_dbg(pmic->dev, "Buck[%d] Set Ramp = %d\n", id + 1, ramp_delay);
+ switch (ramp_delay) {
+ case 1 ... 1250:
+ ramp_value = BUCK1_RAMPRATE_1P25MV;
+ break;
+ case 1251 ... 2500:
+ ramp_value = BUCK1_RAMPRATE_2P50MV;
+ break;
+ case 2501 ... 5000:
+ ramp_value = BUCK1_RAMPRATE_5P00MV;
+ break;
+ case 5001 ... 10000:
+ ramp_value = BUCK1_RAMPRATE_10P00MV;
+ break;
+ default:
+ ramp_value = BUCK1_RAMPRATE_10P00MV;
+ dev_err(pmic->dev, "%s: ramp_delay: %d not supported, setting 10000mV//us\n",
+ rdev->desc->name, ramp_delay);
+ }
+
+ return regmap_update_bits(mfd->regmap, BD71837_REG_BUCK1_CTRL + id,
+ BUCK1_RAMPRATE_MASK, ramp_value << 6);
+}
+
+static struct regulator_ops bd71837_ldo_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops bd71837_fixed_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+static struct regulator_ops bd71837_buck_regulator_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_ops bd71837_buck1234_regulator_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_ramp_delay = bd71837_buck1234_set_ramp_delay,
+};
+
+/*
+ * BUCK1/2/3/4
+ * 0.70 to 1.30V (10mV step)
+ */
+static const struct regulator_linear_range bd71837_buck1234_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(700000, 0x00, 0x3C, 10000),
+ REGULATOR_LINEAR_RANGE(1300000, 0x3D, 0x3F, 0),
+};
+
+/*
+ * BUCK5
+ * 0.9V to 1.35V ()
+ */
+static const struct regulator_linear_range bd71837_buck5_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(700000, 0x00, 0x03, 100000),
+ REGULATOR_LINEAR_RANGE(1050000, 0x04, 0x05, 50000),
+ REGULATOR_LINEAR_RANGE(1200000, 0x06, 0x07, 150000),
+};
+
+/*
+ * BUCK6
+ * 3.0V to 3.3V (step 100mV)
+ */
+static const struct regulator_linear_range bd71837_buck6_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
+};
+
+/*
+ * BUCK7
+ * 1.605V to 1.995V ()
+ * 000 = 1.605V
+ * 001 = 1.695V
+ * 010 = 1.755V
+ * 011 = 1.8V (Initial)
+ * 100 = 1.845V
+ * 101 = 1.905V
+ * 110 = 1.95V
+ * 111 = 1.995V
+ */
+static const struct regulator_linear_range bd71837_buck7_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1605000, 0x00, 0x01, 90000),
+ REGULATOR_LINEAR_RANGE(1755000, 0x02, 0x03, 45000),
+ REGULATOR_LINEAR_RANGE(1845000, 0x04, 0x05, 60000),
+ REGULATOR_LINEAR_RANGE(1950000, 0x06, 0x07, 45000),
+};
+
+/*
+ * BUCK8
+ * 0.8V to 1.40V (step 10mV)
+ */
+static const struct regulator_linear_range bd71837_buck8_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(800000, 0x00, 0x3C, 10000),
+ REGULATOR_LINEAR_RANGE(1400000, 0x3D, 0x3F, 0),
+};
+
+/*
+ * LDO1
+ * 3.0 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo1_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(3000000, 0x00, 0x03, 100000),
+};
+
+/*
+ * LDO3
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo3_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+/*
+ * LDO4
+ * 0.9 to 1.8V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo4_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
+ REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0),
+};
+
+/*
+ * LDO5
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo5_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+/*
+ * LDO6
+ * 0.9 to 1.8V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo6_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(900000, 0x00, 0x09, 100000),
+ REGULATOR_LINEAR_RANGE(1800000, 0x0A, 0x0F, 0),
+};
+
+/*
+ * LDO7
+ * 1.8 to 3.3V (100mV step)
+ */
+static const struct regulator_linear_range bd71837_ldo7_voltage_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0x00, 0x0F, 100000),
+};
+
+static const struct regulator_desc bd71837_regulators[] = {
+ {
+ .name = "BUCK1",
+ .id = BD71837_BUCK1,
+ .ops = &bd71837_buck1234_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK1_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck1234_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
+ .vsel_reg = BD71837_REG_BUCK1_VOLT_RUN,
+ .vsel_mask = BUCK1_RUN_MASK,
+ .enable_reg = BD71837_REG_BUCK1_CTRL,
+ .enable_mask = BUCK1_SEL|BUCK1_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "BUCK2",
+ .id = BD71837_BUCK2,
+ .ops = &bd71837_buck1234_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK2_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck1234_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
+ .vsel_reg = BD71837_REG_BUCK2_VOLT_RUN,
+ .vsel_mask = BUCK2_RUN_MASK,
+ .enable_reg = BD71837_REG_BUCK2_CTRL,
+ .enable_mask = BUCK2_SEL|BUCK2_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "BUCK3",
+ .id = BD71837_BUCK3,
+ .ops = &bd71837_buck1234_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK3_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck1234_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
+ .vsel_reg = BD71837_REG_BUCK3_VOLT_RUN,
+ .vsel_mask = BUCK3_RUN_MASK,
+ .enable_reg = BD71837_REG_BUCK3_CTRL,
+ .enable_mask = BUCK3_SEL|BUCK3_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "BUCK4",
+ .id = BD71837_BUCK4,
+ .ops = &bd71837_buck1234_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK4_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck1234_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_buck1234_voltage_ranges),
+ .vsel_reg = BD71837_REG_BUCK4_VOLT_RUN,
+ .vsel_mask = BUCK4_RUN_MASK,
+ .enable_reg = BD71837_REG_BUCK4_CTRL,
+ .enable_mask = BUCK4_SEL|BUCK4_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "BUCK5",
+ .id = BD71837_BUCK5,
+ .ops = &bd71837_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK5_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck5_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_buck5_voltage_ranges),
+ .vsel_reg = BD71837_REG_BUCK5_VOLT,
+ .vsel_mask = BUCK5_MASK,
+ .enable_reg = BD71837_REG_BUCK5_CTRL,
+ .enable_mask = BUCK5_SEL|BUCK5_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "BUCK6",
+ .id = BD71837_BUCK6,
+ .ops = &bd71837_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK6_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck6_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_buck6_voltage_ranges),
+ .vsel_reg = BD71837_REG_BUCK6_VOLT,
+ .vsel_mask = BUCK6_MASK,
+ .enable_reg = BD71837_REG_BUCK6_CTRL,
+ .enable_mask = BUCK6_SEL|BUCK6_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "BUCK7",
+ .id = BD71837_BUCK7,
+ .ops = &bd71837_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK7_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck7_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_buck7_voltage_ranges),
+ .vsel_reg = BD71837_REG_BUCK7_VOLT,
+ .vsel_mask = BUCK7_MASK,
+ .enable_reg = BD71837_REG_BUCK7_CTRL,
+ .enable_mask = BUCK7_SEL|BUCK7_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "BUCK8",
+ .id = BD71837_BUCK8,
+ .ops = &bd71837_buck_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_BUCK8_VOLTAGE_NUM,
+ .linear_ranges = bd71837_buck8_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_buck8_voltage_ranges),
+ .vsel_reg = BD71837_REG_BUCK8_VOLT,
+ .vsel_mask = BUCK8_MASK,
+ .enable_reg = BD71837_REG_BUCK8_CTRL,
+ .enable_mask = BUCK8_SEL|BUCK8_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO1",
+ .id = BD71837_LDO1,
+ .ops = &bd71837_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO1_VOLTAGE_NUM,
+ .linear_ranges = bd71837_ldo1_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_ldo1_voltage_ranges),
+ .vsel_reg = BD71837_REG_LDO1_VOLT,
+ .vsel_mask = LDO1_MASK,
+ .enable_reg = BD71837_REG_LDO1_VOLT,
+ .enable_mask = LDO1_EN,
+ .owner = THIS_MODULE,
+ },
+ /*
+ * LDO2 0.9V
+ * Fixed voltage
+ */
+ {
+ .name = "LDO2",
+ .id = BD71837_LDO2,
+ .ops = &bd71837_fixed_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO2_VOLTAGE_NUM,
+ .min_uV = 900000,
+ .enable_reg = BD71837_REG_LDO2_VOLT,
+ .enable_mask = LDO2_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO3",
+ .id = BD71837_LDO3,
+ .ops = &bd71837_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO3_VOLTAGE_NUM,
+ .linear_ranges = bd71837_ldo3_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_ldo3_voltage_ranges),
+ .vsel_reg = BD71837_REG_LDO3_VOLT,
+ .vsel_mask = LDO3_MASK,
+ .enable_reg = BD71837_REG_LDO3_VOLT,
+ .enable_mask = LDO3_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO4",
+ .id = BD71837_LDO4,
+ .ops = &bd71837_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO4_VOLTAGE_NUM,
+ .linear_ranges = bd71837_ldo4_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_ldo4_voltage_ranges),
+ .vsel_reg = BD71837_REG_LDO4_VOLT,
+ .vsel_mask = LDO4_MASK,
+ .enable_reg = BD71837_REG_LDO4_VOLT,
+ .enable_mask = LDO4_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO5",
+ .id = BD71837_LDO5,
+ .ops = &bd71837_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO5_VOLTAGE_NUM,
+ .linear_ranges = bd71837_ldo5_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_ldo5_voltage_ranges),
+ .vsel_reg = BD71837_REG_LDO5_VOLT,
+ .vsel_mask = LDO5_MASK,
+ .enable_reg = BD71837_REG_LDO5_VOLT,
+ .enable_mask = LDO5_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO6",
+ .id = BD71837_LDO6,
+ .ops = &bd71837_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO6_VOLTAGE_NUM,
+ .linear_ranges = bd71837_ldo6_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_ldo6_voltage_ranges),
+ .vsel_reg = BD71837_REG_LDO6_VOLT,
+ .vsel_mask = LDO6_MASK,
+ .enable_reg = BD71837_REG_LDO6_VOLT,
+ .enable_mask = LDO6_EN,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO7",
+ .id = BD71837_LDO7,
+ .ops = &bd71837_ldo_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = BD71837_LDO7_VOLTAGE_NUM,
+ .linear_ranges = bd71837_ldo7_voltage_ranges,
+ .n_linear_ranges = ARRAY_SIZE(bd71837_ldo7_voltage_ranges),
+ .vsel_reg = BD71837_REG_LDO7_VOLT,
+ .vsel_mask = LDO7_MASK,
+ .enable_reg = BD71837_REG_LDO7_VOLT,
+ .enable_mask = LDO7_EN,
+ .owner = THIS_MODULE,
+ },
+};
+
+#ifdef CONFIG_OF
+
+static struct of_regulator_match bd71837_matches[] = {
+ { .name = "buck1", },
+ { .name = "buck2", },
+ { .name = "buck3", },
+ { .name = "buck4", },
+ { .name = "buck5", },
+ { .name = "buck6", },
+ { .name = "buck7", },
+ { .name = "buck8", },
+ { .name = "ldo1", },
+ { .name = "ldo2", },
+ { .name = "ldo3", },
+ { .name = "ldo4", },
+ { .name = "ldo5", },
+ { .name = "ldo6", },
+ { .name = "ldo7", },
+};
+
+/**@brief parse bd71837 regulator device tree
+ * @param pdev platform device of bd71837 regulator
+ * @param bd71837_reg_matches return regualtor matches
+ * @retval 0 parse success
+ * @retval NULL parse fail
+ */
+static int bd71837_parse_dt_reg_data(
+ struct platform_device *pdev,
+ struct of_regulator_match **reg_matches)
+{
+ // struct bd71837 *bd71837 = dev_get_drvdata(pdev->dev.parent);
+ struct device_node *np, *regulators;
+ struct of_regulator_match *matches;
+ int ret, count;
+
+ np = of_node_get(pdev->dev.parent->of_node);
+ regulators = of_find_node_by_name(np, "regulators");
+ if (!regulators) {
+ dev_err(&pdev->dev, "regulator node not found\n");
+ return -EINVAL;
+ }
+
+ count = ARRAY_SIZE(bd71837_matches);
+ matches = bd71837_matches;
+
+ ret = of_regulator_match(&pdev->dev, regulators, matches, count);
+ of_node_put(regulators);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
+ ret);
+ return ret;
+ }
+
+ *reg_matches = matches;
+
+ return 0;
+}
+#else
+static inline int bd71837_parse_dt_reg_data(
+ struct platform_device *pdev,
+ struct of_regulator_match **reg_matches)
+{
+ *reg_matches = NULL;
+ return 0;
+}
+#endif
+
+/** @brief retrive out32k output value */
+static ssize_t show_value(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct bd71837_pmic *pmic = dev_get_drvdata(dev);
+ int o;
+
+ o = bd71837_reg_read(pmic->mfd, BD71837_REG_OUT32K);
+ o = (o & OUT32K_EN) != 0;
+
+ return sprintf(buf, "%d\n", o);
+}
+
+/** @brief set o output value */
+static ssize_t set_value(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bd71837_pmic *pmic = dev_get_drvdata(dev);
+ int o, r;
+
+ if (sscanf(buf, "%d", &o) < 1) {
+ return -EINVAL;
+ }
+
+ if (o != 0) {
+ o = OUT32K_EN;
+ }
+ r = bd71837_update_bits(pmic->mfd, BD71837_REG_OUT32K, OUT32K_EN, o);
+ if (r < 0) {
+ return r;
+ }
+ return count;
+}
+
+/** @brief list all supported values */
+static ssize_t available_values(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "0 1 \n");
+}
+
+/** @brief directly set raw value to chip register, format: 'register value' */
+static ssize_t bd71837_sysfs_set_registers(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct bd71837_pmic *pmic = dev_get_drvdata(dev);
+ ssize_t ret = 0;
+ unsigned int reg;
+ unsigned int val;
+
+ ret = sscanf(buf, "%x %x", &reg, &val);
+ if (ret < 1) {
+ pmic->reg_index = -1;
+ dev_err(pmic->dev, "registers set: <reg> <value>\n");
+ return count;
+ }
+
+ if (ret == 1 && reg < BD71837_MAX_REGISTER) {
+ pmic->reg_index = reg;
+ dev_info(pmic->dev, "registers set: reg=0x%x\n", reg);
+ return count;
+ }
+
+ if (reg > BD71837_MAX_REGISTER) {
+ dev_err(pmic->dev, "reg=%d out of Max=%d\n", reg, BD71837_MAX_REGISTER);
+ return -EINVAL;
+ }
+ dev_info(pmic->dev, "registers set: reg=0x%x, val=0x%x\n", reg, val);
+ ret = bd71837_reg_write(pmic->mfd, reg, val);
+ if (ret < 0)
+ return ret;
+ return count;
+}
+
+/** @brief print value of chip register, format: 'register=value' */
+static ssize_t bd71837_sysfs_print_reg(struct bd71837_pmic *pmic,
+ u8 reg,
+ char *buf)
+{
+ int ret = bd71837_reg_read(pmic->mfd, reg);
+ if (ret < 0)
+ return sprintf(buf, "%#.2x=error %d\n", reg, ret);
+ return sprintf(buf, "[0x%.2X] = %.2X\n", reg, ret);
+}
+
+/** @brief show all raw values of chip register, format per line: 'register=value' */
+static ssize_t bd71837_sysfs_show_registers(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bd71837_pmic *pmic = dev_get_drvdata(dev);
+ ssize_t ret = 0;
+ int i;
+
+ dev_info(pmic->dev, "register: index[0x%x]\n", pmic->reg_index);
+ if (pmic->reg_index >= 0) {
+ ret += bd71837_sysfs_print_reg(pmic, pmic->reg_index, buf + ret);
+ } else {
+ for (i = 0; i < BD71837_MAX_REGISTER; i++) {
+ ret += bd71837_sysfs_print_reg(pmic, i, buf + ret);
+ }
+ }
+ return ret;
+}
+
+static DEVICE_ATTR(out32k_value, S_IWUSR | S_IRUGO, show_value, set_value);
+static DEVICE_ATTR(available_value, S_IWUSR | S_IRUGO, available_values, NULL);
+static DEVICE_ATTR(registers, S_IWUSR | S_IRUGO,
+ bd71837_sysfs_show_registers, bd71837_sysfs_set_registers);
+
+/** @brief device sysfs attribute table, about o */
+static struct attribute *clk_attributes[] = {
+ &dev_attr_out32k_value.attr,
+ &dev_attr_available_value.attr,
+ &dev_attr_registers.attr,
+ NULL
+};
+
+static const struct attribute_group clk_attr_group = {
+ .attrs = clk_attributes,
+};
+
+/*----------------------------------------------------------------------*/
+#ifdef CONFIG_OF
+/** @brief buck1/2 dvs enable/voltage from device tree
+ * @param pdev platfrom device pointer
+ * @param buck_dvs pointer
+ * @return void
+ */
+static void of_bd71837_buck_dvs(struct platform_device *pdev, struct bd71837_buck_dvs *buck_dvs)
+{
+ struct device_node *pmic_np;
+
+ pmic_np = of_node_get(pdev->dev.parent->of_node);
+ if (!pmic_np) {
+ dev_err(&pdev->dev, "could not find pmic sub-node\n");
+ return;
+ }
+
+ if (of_get_property(pmic_np, "bd71837,pmic-buck1-uses-i2c-dvs", NULL)) {
+ if (of_property_read_u32_array(pmic_np,
+ "bd71837,pmic-buck1-dvs-voltage",
+ &buck_dvs[0].voltage[0], BD71837_DVS_RUN_IDLE_SUSP)) {
+ dev_err(&pdev->dev, "buck1 voltages not specified\n");
+ }
+ }
+
+ if (of_get_property(pmic_np, "bd71837,pmic-buck2-uses-i2c-dvs", NULL)) {
+ if (of_property_read_u32_array(pmic_np,
+ "bd71837,pmic-buck2-dvs-voltage",
+ &buck_dvs[1].voltage[0], BD71837_DVS_RUN_IDLE)) {
+ dev_err(&pdev->dev, "buck2 voltages not specified\n");
+ }
+ }
+
+ if (of_get_property(pmic_np, "bd71837,pmic-buck3-uses-i2c-dvs", NULL)) {
+ if (of_property_read_u32_array(pmic_np,
+ "bd71837,pmic-buck3-dvs-voltage",
+ &buck_dvs[2].voltage[0], BD71837_DVS_RUN)) {
+ dev_err(&pdev->dev, "buck3 voltages not specified\n");
+ }
+ }
+ if (of_get_property(pmic_np, "bd71837,pmic-buck4-uses-i2c-dvs", NULL)) {
+ if (of_property_read_u32_array(pmic_np,
+ "bd71837,pmic-buck4-dvs-voltage",
+ &buck_dvs[3].voltage[0], BD71837_DVS_RUN)) {
+ dev_err(&pdev->dev, "buck4 voltages not specified\n");
+ }
+ }
+}
+#else
+static void of_bd71837_buck_dvs(struct platform_device *pdev, struct bd71837_buck_dvs *buck_dvs)
+{
+ buck_dvs[0].voltage[0] = BUCK1_RUN_DEFAULT;
+ buck_dvs[0].voltage[1] = BUCK1_IDLE_DEFAULT;
+ buck_dvs[0].voltage[2] = BUCK1_SUSP_DEFAULT;
+ buck_dvs[1].voltage[0] = BUCK2_RUN_DEFAULT;
+ buck_dvs[1].voltage[1] = BUCK2_IDLE_DEFAULT;
+ buck_dvs[1].voltage[2] = 0; /* Not supported */
+ buck_dvs[2].voltage[0] = BUCK3_RUN_DEFAULT;
+ buck_dvs[2].voltage[1] = 0; /* Not supported */
+ buck_dvs[2].voltage[2] = 0; /* Not supported */
+ buck_dvs[3].voltage[0] = BUCK4_RUN_DEFAULT;
+ buck_dvs[3].voltage[1] = 0; /* Not supported */
+ buck_dvs[3].voltage[2] = 0; /* Not supported */
+}
+#endif
+
+static int bd71837_buck1234_dvs_init(struct bd71837_pmic *pmic)
+{
+ struct bd71837 *bd71837 = pmic->mfd;
+ struct bd71837_buck_dvs *buck_dvs = &pmic->buck_dvs[0];
+ int i, ret, val, selector = 0;
+ u8 reg_run, reg_idle, reg_susp;
+ u8 reg_run_msk, reg_idle_msk, reg_susp_msk;
+
+ for (i = 0; i < BD71837_DVS_BUCK_NUM; i++, buck_dvs++) {
+ switch (i) {
+ case 0:
+ default:
+ reg_run = BD71837_REG_BUCK1_VOLT_RUN;
+ reg_run_msk = BUCK1_RUN_MASK;
+ reg_idle = BD71837_REG_BUCK1_VOLT_IDLE;
+ reg_idle_msk = BUCK1_IDLE_MASK;
+ reg_susp = BD71837_REG_BUCK1_VOLT_SUSP;
+ reg_susp_msk = BUCK1_SUSP_MASK;
+ break;
+ case 1:
+ reg_run = BD71837_REG_BUCK2_VOLT_RUN;
+ reg_run_msk = BUCK2_RUN_MASK;
+ reg_idle = BD71837_REG_BUCK2_VOLT_IDLE;
+ reg_idle_msk = BUCK2_IDLE_MASK;
+ reg_susp = 0;
+ break;
+ case 2:
+ reg_run = BD71837_REG_BUCK3_VOLT_RUN;
+ reg_run_msk = BUCK3_RUN_MASK;
+ reg_idle = 0;
+ reg_susp = 0;
+ break;
+ case 3:
+ reg_run = BD71837_REG_BUCK4_VOLT_RUN;
+ reg_run_msk = BUCK4_RUN_MASK;
+ reg_idle = 0;
+ reg_susp = 0;
+ break;
+ }
+
+ dev_dbg(pmic->dev, "Buck%d: DVS Run-Idle-Susp[%d - %d - %d].\n", i+1, buck_dvs->voltage[0], buck_dvs->voltage[1], buck_dvs->voltage[2]);
+ if (reg_run > 0) {
+ selector = regulator_map_voltage_iterate(pmic->rdev[i], buck_dvs->voltage[0], buck_dvs->voltage[0]);
+ if (selector < 0) {
+ dev_dbg(pmic->dev, "%s(): not found selector for Run voltage [%d]\n", __func__, buck_dvs->voltage[0]);
+ } else {
+ val = (selector & reg_run_msk);
+ ret = bd71837_reg_write(bd71837, reg_run, val);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ if (reg_idle > 0) {
+ selector = regulator_map_voltage_iterate(pmic->rdev[i], buck_dvs->voltage[1], buck_dvs->voltage[1]);
+ if (selector < 0) {
+ dev_dbg(pmic->dev, "%s(): not found selector for Idle voltage [%d]\n", __func__, buck_dvs->voltage[1]);
+ } else {
+ val = (selector & reg_idle_msk);
+ ret = bd71837_reg_write(bd71837, reg_idle, val);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ if (reg_susp > 0) {
+ selector = regulator_map_voltage_iterate(pmic->rdev[i], buck_dvs->voltage[2], buck_dvs->voltage[2]);
+ if (selector < 0) {
+ dev_dbg(pmic->dev, "%s(): not found selector for Susp voltage [%d]\n", __func__, buck_dvs->voltage[2]);
+ } else {
+ val = (selector & reg_susp_msk);
+ ret = bd71837_reg_write(bd71837, reg_susp, val);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ }
+ return 0;
+}
+
+/**@brief bd71837 pmic interrupt
+ * @param irq system irq
+ * @param pwrsys bd71837 power device of system
+ * @retval IRQ_HANDLED success
+ * @retval IRQ_NONE error
+ */
+static irqreturn_t bd71837_pmic_interrupt(int irq, void *pwrsys)
+{
+ struct device *dev = pwrsys;
+ struct bd71837 *mfd = dev_get_drvdata(dev->parent);
+ // struct bd71837_power *pwr = dev_get_drvdata(dev);
+ int reg;
+
+ bd71837_debug(BD71837_DBG0, "bd71837_pmic_interrupt() in.\n");
+
+ reg = bd71837_reg_read(mfd, BD71837_REG_IRQ);
+ if (reg < 0)
+ return IRQ_NONE;
+
+ if (reg & IRQ_SWRST) {
+ bd71837_debug(BD71837_DBG0, "IRQ_SWRST\n");
+ }
+ if (reg & IRQ_PWRON_S) {
+ bd71837_debug(BD71837_DBG0, "IRQ_PWRON_S\n");
+ }
+ if (reg & IRQ_PWRON_L) {
+ bd71837_debug(BD71837_DBG0, "IRQ_PWRON_L\n");
+ }
+ if (reg & IRQ_PWRON) {
+ bd71837_debug(BD71837_DBG0, "IRQ_PWRON\n");
+ }
+ if (reg & IRQ_WDOG) {
+ bd71837_debug(BD71837_DBG0, "IRQ_WDOG\n");
+ }
+ if (reg & IRQ_ON_REQ) {
+ bd71837_debug(BD71837_DBG0, "IRQ_ON_REQ\n");
+ }
+ if (reg & IRQ_STBY_REQ) {
+ bd71837_debug(BD71837_DBG0, "IRQ_STBY_REQ\n");
+ }
+
+ reg = bd71837_reg_write(mfd, BD71837_REG_IRQ, reg);
+ if (reg < 0)
+ return IRQ_NONE;
+
+ return IRQ_HANDLED;
+}
+
+/**@brief probe bd71837 regulator device
+ @param pdev bd71837 regulator platform device
+ @retval 0 success
+ @retval negative fail
+*/
+static int bd71837_probe(struct platform_device *pdev)
+{
+ struct bd71837_pmic *pmic;
+ struct bd71837_board *pdata;
+ struct regulator_config config = {};
+ struct bd71837 *bd71837 = dev_get_drvdata(pdev->dev.parent);
+ struct of_regulator_match *matches = NULL;
+ int i = 0, err, irq = 0, ret = 0;
+
+ pmic = kzalloc(sizeof(*pmic), GFP_KERNEL);
+ if (!pmic) {
+ dev_err(&pdev->dev, "Memory allocation failed for pmic\n");
+ return -ENOMEM;
+ }
+
+ memcpy(pmic->descs, bd71837_regulators, sizeof(pmic->descs));
+
+ pmic->dev = &pdev->dev;
+ pmic->mfd = bd71837;
+ platform_set_drvdata(pdev, pmic);
+ pdata = dev_get_platdata(bd71837->dev);
+
+ if (!pdata && bd71837->dev->of_node) {
+ bd71837_parse_dt_reg_data(pdev, &matches);
+ if (matches == NULL) {
+ dev_err(&pdev->dev, "Platform data not found\n");
+ return -EINVAL;
+ }
+ }
+
+ /* Get buck dvs parameters */
+ of_bd71837_buck_dvs(pdev, &pmic->buck_dvs[0]);
+
+ /* Register LOCK release */
+ err = bd71837_reg_write(bd71837, BD71837_REG_REGLOCK, 0x0);
+ if (err != 0) {
+ dev_err(&pdev->dev, "Failed to write LOCK register(%d)\n", err);
+ goto err;
+ }
+
+ for (i = 0; i < BD71837_REGULATOR_CNT; i++) {
+ struct regulator_init_data *init_data;
+ struct regulator_desc *desc;
+ struct regulator_dev *rdev;
+
+ desc = &pmic->descs[i];
+ desc->name = bd71837_matches[i].name;
+
+ if (pdata) {
+ init_data = pdata->init_data[i];
+ } else {
+ init_data = matches[i].init_data;
+ }
+
+ config.dev = pmic->dev;
+ config.init_data = init_data;
+ config.driver_data = pmic;
+ config.regmap = bd71837->regmap;
+ config.of_node = matches[i].of_node;
+ dev_info(config.dev, "regulator register name '%s'\n", desc->name);
+
+ rdev = regulator_register(desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(bd71837->dev,
+ "failed to register %s regulator\n",
+ desc->name);
+ err = PTR_ERR(rdev);
+ goto err;
+ }
+ pmic->rdev[i] = rdev;
+ }
+
+ /* Init sysfs registers */
+ pmic->reg_index = -1;
+
+ err = sysfs_create_group(&pdev->dev.kobj, &clk_attr_group);
+ if (err != 0) {
+ dev_err(&pdev->dev, "Failed to create attribute group: %d\n", err);
+ goto err;
+ }
+
+ /* Init Buck1/2/3/4 dvs */
+ err = bd71837_buck1234_dvs_init(pmic);
+ if (err != 0) {
+ dev_err(&pdev->dev, "Failed to buck12 dvs: %d\n", err);
+ goto err;
+ }
+
+ /* Add Interrupt */
+ irq = platform_get_irq(pdev, 0); // get irq number
+ if (irq <= 0) {
+ dev_warn(&pdev->dev, "platform irq error # %d\n", irq);
+ return -ENXIO;
+ }
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ bd71837_pmic_interrupt, IRQF_TRIGGER_LOW | IRQF_EARLY_RESUME,
+ dev_name(&pdev->dev), &pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "IRQ %d is not free.\n", irq);
+ }
+
+ /* Un-mask IRQ Interrupt */
+ ret = bd71837_reg_write(bd71837, BD71837_REG_MIRQ, 0);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Write Un-mask 'BD71837_REG_MIRQ': failed!\n");
+ ret = -EIO;
+ goto err;
+ }
+
+ return 0;
+
+err:
+ while (--i >= 0)
+ regulator_unregister(pmic->rdev[i]);
+
+ kfree(pmic);
+ return err;
+}
+
+/**@brief remove bd71837 regulator device
+ @param pdev bd71837 regulator platform device
+ @return 0
+*/
+static int __exit bd71837_remove(struct platform_device *pdev)
+{
+ struct bd71837_pmic *pmic = platform_get_drvdata(pdev);
+ int i;
+
+ sysfs_remove_group(&pdev->dev.kobj, &clk_attr_group);
+
+ for (i = 0; i < BD71837_REGULATOR_CNT; i++)
+ regulator_unregister(pmic->rdev[i]);
+
+ kfree(pmic);
+ return 0;
+}
+
+static struct platform_driver bd71837_driver = {
+ .driver = {
+ .name = "bd71837-pmic",
+ .owner = THIS_MODULE,
+ },
+ .probe = bd71837_probe,
+ .remove = bd71837_remove,
+};
+
+/**@brief module initialize function */
+static int __init bd71837_init(void)
+{
+ return platform_driver_register(&bd71837_driver);
+}
+subsys_initcall(bd71837_init);
+
+/**@brief module deinitialize function */
+static void __exit bd71837_cleanup(void)
+{
+ platform_driver_unregister(&bd71837_driver);
+}
+module_exit(bd71837_cleanup);
+
+MODULE_AUTHOR("Cong Pham <cpham2403@gmail.com>");
+MODULE_DESCRIPTION("BD71837 voltage regulator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bd71837-pmic");
+
+/*-------------------------------------------------------*/
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+
+#define PROCFS_NAME "bd71837"
+#define BD71837_REV "BD71837 Driver: Rev002\n"
+
+#define BD71837_BUF_SIZE 1024
+static char procfs_buffer[BD71837_BUF_SIZE];
+/**
+ * This function is called then the /proc file is read
+ *
+ */
+static int onetime;
+static ssize_t bd71837_proc_read (struct file *file, char __user *buffer, size_t count, loff_t *data)
+{
+ int ret = 0, error = 0;
+ if (onetime == 0) {
+ onetime = 1;
+ memset(procfs_buffer, 0, BD71837_BUF_SIZE);
+ sprintf(procfs_buffer, "%s", BD71837_REV);
+ ret = strlen(procfs_buffer);
+ error = copy_to_user(buffer, procfs_buffer, strlen(procfs_buffer));
+ } else {
+ //Clear for next time
+ onetime = 0;
+ }
+ return (error != 0) ? 0 : ret;
+}
+
+static ssize_t bd71837_proc_write (struct file *file, const char __user *buffer, size_t count, loff_t *data)
+{
+ sscanf(buffer, "0x%x", &bd71837_debug_mask);
+ printk("bd71837: bd71837_debug_mask=0x%08x\n", bd71837_debug_mask);
+ return count;
+}
+
+static const struct file_operations bd71837_proc_fops = {
+ .owner = THIS_MODULE,
+ .read = bd71837_proc_read,
+ .write = bd71837_proc_write,
+};
+
+/**
+ *This function is called when the module is loaded
+ *
+ */
+int bd71837_revision_init(void)
+{
+ struct proc_dir_entry *bd71837_proc_entry;
+
+ /* create the /proc/bd71837 */
+ bd71837_proc_entry = proc_create(PROCFS_NAME, 0644, NULL, &bd71837_proc_fops);
+ if (bd71837_proc_entry == NULL) {
+ printk("Error: Could not initialize /proc/%s\n", PROCFS_NAME);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+module_init(bd71837_revision_init);
+/*-------------------------------------------------------*/
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 178fcda12cec..8a9221c9246c 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2075,6 +2075,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
{
int ret, delay;
+ _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_DO_ENABLE, NULL);
/* Query before enabling in case configuration dependent. */
ret = _regulator_get_enable_time(rdev);
if (ret >= 0) {
@@ -2134,6 +2135,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
_regulator_enable_delay(delay);
trace_regulator_enable_complete(rdev_get_name(rdev));
+ _notifier_call_chain(rdev, REGULATOR_EVENT_AFT_DO_ENABLE, NULL);
return 0;
}
@@ -2213,6 +2215,7 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
{
int ret;
+ _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_DO_DISABLE, NULL);
trace_regulator_disable(rdev_get_name(rdev));
if (rdev->ena_pin) {
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 988a7472c2ab..136a9a3c7e30 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -30,6 +30,7 @@
#include <linux/of_gpio.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
+#include <linux/pinctrl/consumer.h>
struct fixed_voltage_data {
struct regulator_desc desc;
@@ -83,6 +84,7 @@ of_get_fixed_voltage_config(struct device *dev,
return ERR_PTR(config->gpio);
of_property_read_u32(np, "startup-delay-us", &config->startup_delay);
+ of_property_read_u32(np, "off-on-delay", &config->off_on_delay);
config->enable_high = of_property_read_bool(np, "enable-active-high");
config->gpio_is_open_drain = of_property_read_bool(np,
@@ -133,6 +135,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
drvdata->desc.ops = &fixed_voltage_ops;
drvdata->desc.enable_time = config->startup_delay;
+ drvdata->desc.off_on_delay = config->off_on_delay;
if (config->input_supply) {
drvdata->desc.supply_name = devm_kstrdup(&pdev->dev,
@@ -199,11 +202,32 @@ static const struct of_device_id fixed_of_match[] = {
MODULE_DEVICE_TABLE(of, fixed_of_match);
#endif
+#ifdef CONFIG_PM_SLEEP
+static int reg_fixed_voltage_suspend(struct device *dev)
+{
+ pinctrl_pm_select_sleep_state(dev);
+
+ return 0;
+}
+static int reg_fixed_voltage_resume(struct device *dev)
+{
+ pinctrl_pm_select_default_state(dev);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops reg_fixed_voltage_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(reg_fixed_voltage_suspend,
+ reg_fixed_voltage_resume)
+};
+
static struct platform_driver regulator_fixed_voltage_driver = {
.probe = reg_fixed_voltage_probe,
.driver = {
.name = "reg-fixed-voltage",
.of_match_table = of_match_ptr(fixed_of_match),
+ .pm = &reg_fixed_voltage_pm_ops,
},
};
diff --git a/drivers/regulator/max17135-regulator.c b/drivers/regulator/max17135-regulator.c
new file mode 100644
index 000000000000..90a2665c3d64
--- /dev/null
+++ b/drivers/regulator/max17135-regulator.c
@@ -0,0 +1,858 @@
+/*
+ * Copyright (C) 2010-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mfd/max17135.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+/*
+ * Regulator definitions
+ * *_MIN_uV - minimum microvolt for regulator
+ * *_MAX_uV - maximum microvolt for regulator
+ * *_STEP_uV - microvolts between regulator output levels
+ * *_MIN_VAL - minimum register field value for regulator
+ * *_MAX_VAL - maximum register field value for regulator
+ */
+#define MAX17135_HVINP_MIN_uV 5000000
+#define MAX17135_HVINP_MAX_uV 20000000
+#define MAX17135_HVINP_STEP_uV 1000000
+#define MAX17135_HVINP_MIN_VAL 0
+#define MAX17135_HVINP_MAX_VAL 12
+
+#define MAX17135_HVINN_MIN_uV 5000000
+#define MAX17135_HVINN_MAX_uV 20000000
+#define MAX17135_HVINN_STEP_uV 1000000
+#define MAX17135_HVINN_MIN_VAL 0
+#define MAX17135_HVINN_MAX_VAL 1
+
+#define MAX17135_GVDD_MIN_uV 5000000
+#define MAX17135_GVDD_MAX_uV 20000000
+#define MAX17135_GVDD_STEP_uV 1000000
+#define MAX17135_GVDD_MIN_VAL 0
+#define MAX17135_GVDD_MAX_VAL 1
+
+#define MAX17135_GVEE_MIN_uV 5000000
+#define MAX17135_GVEE_MAX_uV 20000000
+#define MAX17135_GVEE_STEP_uV 1000000
+#define MAX17135_GVEE_MIN_VAL 0
+#define MAX17135_GVEE_MAX_VAL 1
+
+#define MAX17135_VCOM_MIN_VAL 0
+#define MAX17135_VCOM_MAX_VAL 255
+
+#define MAX17135_VNEG_MIN_uV 5000000
+#define MAX17135_VNEG_MAX_uV 20000000
+#define MAX17135_VNEG_STEP_uV 1000000
+#define MAX17135_VNEG_MIN_VAL 0
+#define MAX17135_VNEG_MAX_VAL 1
+
+#define MAX17135_VPOS_MIN_uV 5000000
+#define MAX17135_VPOS_MAX_uV 20000000
+#define MAX17135_VPOS_STEP_uV 1000000
+#define MAX17135_VPOS_MIN_VAL 0
+#define MAX17135_VPOS_MAX_VAL 1
+
+struct max17135_vcom_programming_data {
+ int vcom_min_uV;
+ int vcom_max_uV;
+ int vcom_step_uV;
+};
+
+struct max17135_data {
+ int num_regulators;
+ struct max17135 *max17135;
+ struct regulator_dev **rdev;
+};
+
+static long unsigned int max17135_pass_num = { 1 };
+static int max17135_vcom = { -1250000 };
+
+struct max17135_vcom_programming_data vcom_data[2] = {
+ {
+ -4325000,
+ -500000,
+ 15000,
+ },
+ {
+ -3050000,
+ -500000,
+ 10000,
+ },
+};
+
+static int max17135_is_power_good(struct max17135 *max17135);
+
+/*
+ * Regulator operations
+ */
+static int max17135_hvinp_set_voltage(struct regulator_dev *reg,
+ int minuV, int uV, unsigned *selector)
+{
+ unsigned int reg_val;
+ unsigned int fld_val;
+
+ if ((uV >= MAX17135_HVINP_MIN_uV) &&
+ (uV <= MAX17135_HVINP_MAX_uV))
+ fld_val = (uV - MAX17135_HVINP_MIN_uV) /
+ MAX17135_HVINP_STEP_uV;
+ else
+ return -EINVAL;
+
+ max17135_reg_read(REG_MAX17135_HVINP, &reg_val);
+
+ reg_val &= ~BITFMASK(HVINP);
+ reg_val |= BITFVAL(HVINP, fld_val); /* shift to correct bit */
+
+ return max17135_reg_write(REG_MAX17135_HVINP, reg_val);
+}
+
+static int max17135_hvinp_get_voltage(struct regulator_dev *reg)
+{
+ unsigned int reg_val;
+ unsigned int fld_val;
+ int volt;
+
+ max17135_reg_read(REG_MAX17135_HVINP, &reg_val);
+
+ fld_val = (reg_val & BITFMASK(HVINP)) >> HVINP_LSH;
+
+ if ((fld_val >= MAX17135_HVINP_MIN_VAL) &&
+ (fld_val <= MAX17135_HVINP_MAX_VAL)) {
+ volt = (fld_val * MAX17135_HVINP_STEP_uV) +
+ MAX17135_HVINP_MIN_uV;
+ } else {
+ printk(KERN_ERR "MAX17135: HVINP voltage is out of range\n");
+ volt = 0;
+ }
+ return volt;
+}
+
+static int max17135_hvinp_enable(struct regulator_dev *reg)
+{
+ return 0;
+}
+
+static int max17135_hvinp_disable(struct regulator_dev *reg)
+{
+ return 0;
+}
+
+/* Convert uV to the VCOM register bitfield setting */
+static inline int vcom_uV_to_rs(int uV, int pass_num)
+{
+ return (vcom_data[pass_num].vcom_max_uV - uV)
+ / vcom_data[pass_num].vcom_step_uV;
+}
+
+/* Convert the VCOM register bitfield setting to uV */
+static inline int vcom_rs_to_uV(int rs, int pass_num)
+{
+ return vcom_data[pass_num].vcom_max_uV
+ - (vcom_data[pass_num].vcom_step_uV * rs);
+}
+
+/*
+ * This function should only be called with positive voltage values because
+ * negative ones are considered errors by the regulator core implementation.
+ *
+ * The given positive value if the absolute value of the desired negative one.
+ */
+static int max17135_vcom_set_voltage(struct regulator_dev *reg,
+ int minuV, int uV, unsigned *selector)
+{
+ struct max17135 *max17135 = rdev_get_drvdata(reg);
+ unsigned int reg_val;
+ int vcom_read;
+
+ /* Transform uV for our negative land values */
+ uV = -uV;
+
+ if ((uV < vcom_data[max17135->pass_num-1].vcom_min_uV)
+ || (uV > vcom_data[max17135->pass_num-1].vcom_max_uV))
+ return -EINVAL;
+
+ max17135_reg_read(REG_MAX17135_DVR, &reg_val);
+
+ /*
+ * Only program VCOM if it is not set to the desired value.
+ * Programming VCOM excessively degrades ability to keep
+ * DVR register value persistent.
+ */
+ vcom_read = vcom_rs_to_uV(reg_val, max17135->pass_num-1);
+ if (vcom_read != max17135->vcom_uV) {
+ reg_val &= ~BITFMASK(DVR);
+ reg_val |= BITFVAL(DVR, vcom_uV_to_rs(uV,
+ max17135->pass_num-1));
+ max17135_reg_write(REG_MAX17135_DVR, reg_val);
+
+ reg_val = BITFVAL(CTRL_DVR, true); /* shift to correct bit */
+ return max17135_reg_write(REG_MAX17135_PRGM_CTRL, reg_val);
+ }
+
+ return 0;
+}
+
+/*
+ * This function should only return positive voltage values because negative
+ * ones are considered errors by the regulator core implementation.
+ */
+static int max17135_vcom_get_voltage(struct regulator_dev *reg)
+{
+ struct max17135 *max17135 = rdev_get_drvdata(reg);
+ unsigned int reg_val;
+ int uV;
+
+ max17135_reg_read(REG_MAX17135_DVR, &reg_val);
+ uV = vcom_rs_to_uV(BITFEXT(reg_val, DVR), max17135->pass_num-1);
+
+ /* Transform uV to positive value */
+ uV = -uV;
+
+ return uV;
+}
+
+static int max17135_vcom_enable(struct regulator_dev *reg)
+{
+ struct max17135 *max17135 = rdev_get_drvdata(reg);
+ int uV;
+
+ /*
+ * Check to see if we need to set the VCOM voltage.
+ * Should only be done one time. And, we can
+ * only change vcom voltage if we have been enabled.
+ */
+ if (!max17135->vcom_setup && max17135_is_power_good(max17135)) {
+ uV = (-1) * max17135->vcom_uV;
+
+ max17135_vcom_set_voltage(reg, uV, uV, NULL);
+ max17135->vcom_setup = true;
+ }
+
+ /* enable VCOM regulator output */
+ if (max17135->pass_num == 1)
+ gpio_set_value(max17135->gpio_pmic_vcom_ctrl, 1);
+ else {
+ unsigned int reg_val;
+
+ max17135_reg_read(REG_MAX17135_ENABLE, &reg_val);
+ reg_val &= ~BITFMASK(VCOM_ENABLE);
+ reg_val |= BITFVAL(VCOM_ENABLE, 1); /* shift to correct bit */
+ max17135_reg_write(REG_MAX17135_ENABLE, reg_val);
+ }
+
+ return 0;
+}
+
+static int max17135_vcom_disable(struct regulator_dev *reg)
+{
+ struct max17135 *max17135 = rdev_get_drvdata(reg);
+
+ if (max17135->pass_num == 1)
+ gpio_set_value(max17135->gpio_pmic_vcom_ctrl, 0);
+ else {
+ unsigned int reg_val;
+
+ max17135_reg_read(REG_MAX17135_ENABLE, &reg_val);
+ reg_val &= ~BITFMASK(VCOM_ENABLE);
+ max17135_reg_write(REG_MAX17135_ENABLE, reg_val);
+ }
+
+ return 0;
+}
+
+static int max17135_vcom_is_enabled(struct regulator_dev *reg)
+{
+ struct max17135 *max17135 = rdev_get_drvdata(reg);
+
+ /* read VCOM regulator enable setting */
+ if (max17135->pass_num == 1) {
+ int gpio = gpio_get_value(max17135->gpio_pmic_vcom_ctrl);
+ if (gpio == 0)
+ return 0;
+ else
+ return 1;
+ } else {
+ unsigned int reg_val;
+
+ max17135_reg_read(REG_MAX17135_ENABLE, &reg_val);
+ reg_val &= BITFMASK(VCOM_ENABLE);
+ if (reg_val != 0)
+ return 1;
+ else
+ return 0;
+ }
+}
+
+static int max17135_is_power_good(struct max17135 *max17135)
+{
+ unsigned int reg_val;
+ unsigned int fld_val;
+
+ max17135_reg_read(REG_MAX17135_FAULT, &reg_val);
+ fld_val = (reg_val & BITFMASK(FAULT_POK)) >> FAULT_POK_LSH;
+
+ /* Check the POK bit */
+ return fld_val;
+}
+
+static int max17135_wait_power_good(struct max17135 *max17135)
+{
+ int i;
+
+ for (i = 0; i < max17135->max_wait * 3; i++) {
+ if (max17135_is_power_good(max17135))
+ return 0;
+
+ msleep(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int max17135_display_enable(struct regulator_dev *reg)
+{
+ struct max17135 *max17135 = rdev_get_drvdata(reg);
+
+ /* The Pass 1 parts cannot turn on the PMIC via I2C. */
+ if (max17135->pass_num == 1)
+ gpio_set_value(max17135->gpio_pmic_wakeup, 1);
+ else {
+ unsigned int reg_val;
+
+ max17135_reg_read(REG_MAX17135_ENABLE, &reg_val);
+ reg_val &= ~BITFMASK(ENABLE);
+ reg_val |= BITFVAL(ENABLE, 1);
+ max17135_reg_write(REG_MAX17135_ENABLE, reg_val);
+ }
+
+ return max17135_wait_power_good(max17135);
+}
+
+static int max17135_display_disable(struct regulator_dev *reg)
+{
+ struct max17135 *max17135 = rdev_get_drvdata(reg);
+
+ if (max17135->pass_num == 1)
+ gpio_set_value(max17135->gpio_pmic_wakeup, 0);
+ else {
+ unsigned int reg_val;
+
+ max17135_reg_read(REG_MAX17135_ENABLE, &reg_val);
+ reg_val &= ~BITFMASK(ENABLE);
+ max17135_reg_write(REG_MAX17135_ENABLE, reg_val);
+ }
+
+ msleep(max17135->max_wait);
+
+ return 0;
+}
+
+static int max17135_display_is_enabled(struct regulator_dev *reg)
+{
+ struct max17135 *max17135 = rdev_get_drvdata(reg);
+ int gpio = gpio_get_value(max17135->gpio_pmic_wakeup);
+
+ if (gpio == 0)
+ return 0;
+ else
+ return 1;
+}
+
+static int max17135_v3p3_enable(struct regulator_dev *reg)
+{
+ struct max17135 *max17135 = rdev_get_drvdata(reg);
+
+ gpio_set_value(max17135->gpio_pmic_v3p3, 1);
+ return 0;
+}
+
+static int max17135_v3p3_disable(struct regulator_dev *reg)
+{
+ struct max17135 *max17135 = rdev_get_drvdata(reg);
+
+ gpio_set_value(max17135->gpio_pmic_v3p3, 0);
+ return 0;
+}
+
+static int max17135_v3p3_is_enabled(struct regulator_dev *reg)
+{
+ struct max17135 *max17135 = rdev_get_drvdata(reg);
+ int gpio = gpio_get_value(max17135->gpio_pmic_v3p3);
+
+ if (gpio == 0)
+ return 0;
+ else
+ return 1;
+}
+
+/*
+ * Regulator operations
+ */
+
+static struct regulator_ops max17135_display_ops = {
+ .enable = max17135_display_enable,
+ .disable = max17135_display_disable,
+ .is_enabled = max17135_display_is_enabled,
+};
+
+static struct regulator_ops max17135_gvdd_ops = {
+};
+
+static struct regulator_ops max17135_gvee_ops = {
+};
+
+static struct regulator_ops max17135_hvinn_ops = {
+};
+
+static struct regulator_ops max17135_hvinp_ops = {
+ .enable = max17135_hvinp_enable,
+ .disable = max17135_hvinp_disable,
+ .get_voltage = max17135_hvinp_get_voltage,
+ .set_voltage = max17135_hvinp_set_voltage,
+};
+
+static struct regulator_ops max17135_vcom_ops = {
+ .enable = max17135_vcom_enable,
+ .disable = max17135_vcom_disable,
+ .get_voltage = max17135_vcom_get_voltage,
+ .set_voltage = max17135_vcom_set_voltage,
+ .is_enabled = max17135_vcom_is_enabled,
+};
+
+static struct regulator_ops max17135_vneg_ops = {
+};
+
+static struct regulator_ops max17135_vpos_ops = {
+};
+
+static struct regulator_ops max17135_v3p3_ops = {
+ .enable = max17135_v3p3_enable,
+ .disable = max17135_v3p3_disable,
+ .is_enabled = max17135_v3p3_is_enabled,
+};
+
+
+/*
+ * Regulator descriptors
+ */
+static struct regulator_desc max17135_reg[MAX17135_NUM_REGULATORS] = {
+{
+ .name = "DISPLAY",
+ .id = MAX17135_DISPLAY,
+ .ops = &max17135_display_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+},
+{
+ .name = "GVDD",
+ .id = MAX17135_GVDD,
+ .ops = &max17135_gvdd_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+},
+{
+ .name = "GVEE",
+ .id = MAX17135_GVEE,
+ .ops = &max17135_gvee_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+},
+{
+ .name = "HVINN",
+ .id = MAX17135_HVINN,
+ .ops = &max17135_hvinn_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+},
+{
+ .name = "HVINP",
+ .id = MAX17135_HVINP,
+ .ops = &max17135_hvinp_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+},
+{
+ .name = "VCOM",
+ .id = MAX17135_VCOM,
+ .ops = &max17135_vcom_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+},
+{
+ .name = "VNEG",
+ .id = MAX17135_VNEG,
+ .ops = &max17135_vneg_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+},
+{
+ .name = "VPOS",
+ .id = MAX17135_VPOS,
+ .ops = &max17135_vpos_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+},
+{
+ .name = "V3P3",
+ .id = MAX17135_V3P3,
+ .ops = &max17135_v3p3_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+},
+};
+
+static void max17135_setup_timings(struct max17135 *max17135)
+{
+ unsigned int reg_val;
+
+ int timing1, timing2, timing3, timing4,
+ timing5, timing6, timing7, timing8;
+
+ max17135_reg_read(REG_MAX17135_TIMING1, &timing1);
+ max17135_reg_read(REG_MAX17135_TIMING2, &timing2);
+ max17135_reg_read(REG_MAX17135_TIMING3, &timing3);
+ max17135_reg_read(REG_MAX17135_TIMING4, &timing4);
+ max17135_reg_read(REG_MAX17135_TIMING5, &timing5);
+ max17135_reg_read(REG_MAX17135_TIMING6, &timing6);
+ max17135_reg_read(REG_MAX17135_TIMING7, &timing7);
+ max17135_reg_read(REG_MAX17135_TIMING8, &timing8);
+
+ if ((timing1 != max17135->gvee_pwrup) ||
+ (timing2 != max17135->vneg_pwrup) ||
+ (timing3 != max17135->vpos_pwrup) ||
+ (timing4 != max17135->gvdd_pwrup) ||
+ (timing5 != max17135->gvdd_pwrdn) ||
+ (timing6 != max17135->vpos_pwrdn) ||
+ (timing7 != max17135->vneg_pwrdn) ||
+ (timing8 != max17135->gvee_pwrdn)) {
+ max17135_reg_write(REG_MAX17135_TIMING1, max17135->gvee_pwrup);
+ max17135_reg_write(REG_MAX17135_TIMING2, max17135->vneg_pwrup);
+ max17135_reg_write(REG_MAX17135_TIMING3, max17135->vpos_pwrup);
+ max17135_reg_write(REG_MAX17135_TIMING4, max17135->gvdd_pwrup);
+ max17135_reg_write(REG_MAX17135_TIMING5, max17135->gvdd_pwrdn);
+ max17135_reg_write(REG_MAX17135_TIMING6, max17135->vpos_pwrdn);
+ max17135_reg_write(REG_MAX17135_TIMING7, max17135->vneg_pwrdn);
+ max17135_reg_write(REG_MAX17135_TIMING8, max17135->gvee_pwrdn);
+
+ reg_val = BITFVAL(CTRL_TIMING, true); /* shift to correct bit */
+ max17135_reg_write(REG_MAX17135_PRGM_CTRL, reg_val);
+ }
+}
+
+#define CHECK_PROPERTY_ERROR_KFREE(prop) \
+do { \
+ int ret = of_property_read_u32(max17135->dev->of_node, \
+ #prop, &max17135->prop); \
+ if (ret < 0) { \
+ return ret; \
+ } \
+} while (0);
+
+#ifdef CONFIG_OF
+static int max17135_pmic_dt_parse_pdata(struct platform_device *pdev,
+ struct max17135_platform_data *pdata)
+{
+ struct max17135 *max17135 = dev_get_drvdata(pdev->dev.parent);
+ struct device_node *pmic_np, *regulators_np, *reg_np;
+ struct max17135_regulator_data *rdata;
+ int i, ret;
+
+ pmic_np = of_node_get(max17135->dev->of_node);
+ if (!pmic_np) {
+ dev_err(&pdev->dev, "could not find pmic sub-node\n");
+ return -ENODEV;
+ }
+
+ regulators_np = of_find_node_by_name(pmic_np, "regulators");
+ if (!regulators_np) {
+ dev_err(&pdev->dev, "could not find regulators sub-node\n");
+ return -EINVAL;
+ }
+
+ pdata->num_regulators = of_get_child_count(regulators_np);
+ dev_dbg(&pdev->dev, "num_regulators %d\n", pdata->num_regulators);
+
+ rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
+ pdata->num_regulators, GFP_KERNEL);
+ if (!rdata) {
+ of_node_put(regulators_np);
+ dev_err(&pdev->dev, "could not allocate memory for"
+ "regulator data\n");
+ return -ENOMEM;
+ }
+
+ pdata->regulators = rdata;
+ for_each_child_of_node(regulators_np, reg_np) {
+ for (i = 0; i < ARRAY_SIZE(max17135_reg); i++)
+ if (!of_node_cmp(reg_np->name, max17135_reg[i].name))
+ break;
+
+ if (i == ARRAY_SIZE(max17135_reg)) {
+ dev_warn(&pdev->dev, "don't know how to configure"
+ "regulator %s\n", reg_np->name);
+ continue;
+ }
+
+ rdata->id = i;
+ rdata->initdata = of_get_regulator_init_data(&pdev->dev,
+ reg_np,
+ &max17135_reg[i]);
+ rdata->reg_node = reg_np;
+ rdata++;
+ }
+ of_node_put(regulators_np);
+
+ CHECK_PROPERTY_ERROR_KFREE(vneg_pwrup);
+ CHECK_PROPERTY_ERROR_KFREE(gvee_pwrup);
+ CHECK_PROPERTY_ERROR_KFREE(vpos_pwrup);
+ CHECK_PROPERTY_ERROR_KFREE(gvdd_pwrup);
+ CHECK_PROPERTY_ERROR_KFREE(gvdd_pwrdn);
+ CHECK_PROPERTY_ERROR_KFREE(vpos_pwrdn);
+ CHECK_PROPERTY_ERROR_KFREE(gvee_pwrdn);
+ CHECK_PROPERTY_ERROR_KFREE(vneg_pwrdn);
+
+ dev_dbg(&pdev->dev, "vneg_pwrup %d, vneg_pwrdn %d, vpos_pwrup %d,"
+ "vpos_pwrdn %d, gvdd_pwrup %d, gvdd_pwrdn %d, gvee_pwrup %d,"
+ "gvee_pwrdn %d\n", max17135->vneg_pwrup, max17135->vneg_pwrdn,
+ max17135->vpos_pwrup, max17135->vpos_pwrdn,
+ max17135->gvdd_pwrup, max17135->gvdd_pwrdn,
+ max17135->gvee_pwrup, max17135->gvee_pwrdn);
+
+ max17135->max_wait = max17135->vpos_pwrup + max17135->vneg_pwrup +
+ max17135->gvdd_pwrup + max17135->gvee_pwrup;
+
+ max17135->gpio_pmic_wakeup = of_get_named_gpio(pmic_np,
+ "gpio_pmic_wakeup", 0);
+ if (!gpio_is_valid(max17135->gpio_pmic_wakeup)) {
+ dev_err(&pdev->dev, "no epdc pmic wakeup pin available\n");
+ goto err;
+ }
+ ret = devm_gpio_request_one(&pdev->dev, max17135->gpio_pmic_wakeup,
+ GPIOF_OUT_INIT_LOW, "epdc-pmic-wake");
+ if (ret < 0)
+ goto err;
+
+ max17135->gpio_pmic_vcom_ctrl = of_get_named_gpio(pmic_np,
+ "gpio_pmic_vcom_ctrl", 0);
+ if (!gpio_is_valid(max17135->gpio_pmic_vcom_ctrl)) {
+ dev_err(&pdev->dev, "no epdc pmic vcom_ctrl pin available\n");
+ goto err;
+ }
+ ret = devm_gpio_request_one(&pdev->dev, max17135->gpio_pmic_vcom_ctrl,
+ GPIOF_OUT_INIT_LOW, "epdc-vcom");
+ if (ret < 0)
+ goto err;
+
+ max17135->gpio_pmic_v3p3 = of_get_named_gpio(pmic_np,
+ "gpio_pmic_v3p3", 0);
+ if (!gpio_is_valid(max17135->gpio_pmic_v3p3)) {
+ dev_err(&pdev->dev, "no epdc pmic v3p3 pin available\n");
+ goto err;
+ }
+ ret = devm_gpio_request_one(&pdev->dev, max17135->gpio_pmic_v3p3,
+ GPIOF_OUT_INIT_LOW, "epdc-v3p3");
+ if (ret < 0)
+ goto err;
+
+ max17135->gpio_pmic_intr = of_get_named_gpio(pmic_np,
+ "gpio_pmic_intr", 0);
+ if (!gpio_is_valid(max17135->gpio_pmic_intr)) {
+ dev_err(&pdev->dev, "no epdc pmic intr pin available\n");
+ goto err;
+ }
+ ret = devm_gpio_request_one(&pdev->dev, max17135->gpio_pmic_intr,
+ GPIOF_IN, "epdc-pmic-int");
+ if (ret < 0)
+ goto err;
+
+ max17135->gpio_pmic_pwrgood = of_get_named_gpio(pmic_np,
+ "gpio_pmic_pwrgood", 0);
+ if (!gpio_is_valid(max17135->gpio_pmic_pwrgood)) {
+ dev_err(&pdev->dev, "no epdc pmic pwrgood pin available\n");
+ goto err;
+ }
+ ret = devm_gpio_request_one(&pdev->dev, max17135->gpio_pmic_pwrgood,
+ GPIOF_IN, "epdc-pwrstat");
+ if (ret < 0)
+ goto err;
+
+err:
+ return 0;
+
+}
+#else
+static int max17135_pmic_dt_parse_pdata(struct platform_device *pdev,
+ struct max17135 *max17135)
+{
+ return 0;
+}
+#endif /* !CONFIG_OF */
+
+/*
+ * Regulator init/probing/exit functions
+ */
+static int max17135_regulator_probe(struct platform_device *pdev)
+{
+ struct max17135 *max17135 = dev_get_drvdata(pdev->dev.parent);
+ struct max17135_platform_data *pdata = max17135->pdata;
+ struct max17135_data *priv;
+ struct regulator_dev **rdev;
+ struct regulator_config config = { };
+ int size, i, ret = 0;
+
+ if (max17135->dev->of_node) {
+ ret = max17135_pmic_dt_parse_pdata(pdev, pdata);
+ if (ret)
+ return ret;
+ }
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct max17135_data),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ size = sizeof(struct regulator_dev *) * pdata->num_regulators;
+ priv->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ if (!priv->rdev)
+ return -ENOMEM;
+
+ rdev = priv->rdev;
+ priv->num_regulators = pdata->num_regulators;
+ platform_set_drvdata(pdev, priv);
+
+ max17135->vcom_setup = false;
+ max17135->pass_num = max17135_pass_num;
+ max17135->vcom_uV = max17135_vcom;
+
+ for (i = 0; i < pdata->num_regulators; i++) {
+ int id = pdata->regulators[i].id;
+
+ config.dev = max17135->dev;
+ config.init_data = pdata->regulators[i].initdata;
+ config.driver_data = max17135;
+ config.of_node = pdata->regulators[i].reg_node;
+
+ rdev[i] = regulator_register(&max17135_reg[id], &config);
+ if (IS_ERR(rdev[i])) {
+ ret = PTR_ERR(rdev[i]);
+ dev_err(&pdev->dev, "regulator init failed for %d\n",
+ id);
+ rdev[i] = NULL;
+ goto err;
+ }
+ }
+
+ /*
+ * Set up PMIC timing values.
+ * Should only be done one time! Timing values may only be
+ * changed a limited number of times according to spec.
+ */
+ max17135_setup_timings(max17135);
+
+ return 0;
+err:
+ while (--i >= 0)
+ regulator_unregister(rdev[i]);
+ return ret;
+}
+
+static int max17135_regulator_remove(struct platform_device *pdev)
+{
+ struct max17135_data *priv = platform_get_drvdata(pdev);
+ struct regulator_dev **rdev = priv->rdev;
+ int i;
+
+ for (i = 0; i < priv->num_regulators; i++)
+ regulator_unregister(rdev[i]);
+ return 0;
+}
+
+static const struct platform_device_id max17135_pmic_id[] = {
+ { "max17135-pmic", 0},
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, max17135_pmic_id);
+
+static struct platform_driver max17135_regulator_driver = {
+ .probe = max17135_regulator_probe,
+ .remove = max17135_regulator_remove,
+ .id_table = max17135_pmic_id,
+ .driver = {
+ .name = "max17135-pmic",
+ },
+};
+
+static int __init max17135_regulator_init(void)
+{
+ return platform_driver_register(&max17135_regulator_driver);
+}
+subsys_initcall_sync(max17135_regulator_init);
+
+static void __exit max17135_regulator_exit(void)
+{
+ platform_driver_unregister(&max17135_regulator_driver);
+}
+module_exit(max17135_regulator_exit);
+
+/*
+ * Parse user specified options (`max17135:')
+ * example:
+ * max17135:pass=2,vcom=-1250000
+ */
+static int __init max17135_setup(char *options)
+{
+ int ret;
+ char *opt;
+ while ((opt = strsep(&options, ",")) != NULL) {
+ if (!*opt)
+ continue;
+ if (!strncmp(opt, "pass=", 5)) {
+ ret = kstrtoul(opt + 5, 0, &max17135_pass_num);
+ if (ret < 0)
+ return ret;
+ }
+ if (!strncmp(opt, "vcom=", 5)) {
+ int offs = 5;
+ if (opt[5] == '-')
+ offs = 6;
+ ret = kstrtoul(opt + offs, 0,
+ (long *)&max17135_vcom);
+ if (ret < 0)
+ return ret;
+ max17135_vcom = -max17135_vcom;
+ }
+ }
+
+ return 1;
+}
+
+__setup("max17135:", max17135_setup);
+
+/* Module information */
+MODULE_DESCRIPTION("MAX17135 regulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/pf1550-regulator-rpmsg.c b/drivers/regulator/pf1550-regulator-rpmsg.c
new file mode 100644
index 000000000000..11a893373390
--- /dev/null
+++ b/drivers/regulator/pf1550-regulator-rpmsg.c
@@ -0,0 +1,512 @@
+/*
+ * pf1550.c - regulator driver for the PF1550
+ *
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright (C) 2017 NXP.
+ * Robin Gong <yibin.gong@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/imx_rpmsg.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/machine.h>
+#include <linux/rpmsg.h>
+#include <linux/uaccess.h>
+#include <linux/virtio.h>
+
+#define PF1550_DBGFS
+#define PF1550_MAX_REGULATOR 7
+#define RPMSG_TIMEOUT 1000
+
+enum pf1550_regs {
+ PF1550_SW1,
+ PF1550_SW2,
+ PF1550_SW3,
+ PF1550_VREFDDR,
+ PF1550_LDO1,
+ PF1550_LDO2,
+ PF1550_LDO3,
+};
+
+enum pf1550_rpmsg_cmd {
+ PF1550_ENABLE,
+ PF1550_DISABLE,
+ PF1550_IS_ENABLED,
+ PF1550_SET_VOL,
+ PF1550_GET_VOL,
+ PF1550_GET_REG,
+ PF1550_SET_REG,
+};
+
+enum pf1550_resp {
+ PF1550_SUCCESS,
+ PF1550_FAILED,
+ PF1550_UNSURPPORT,
+};
+
+enum pf1550_status {
+ PF1550_DISABLED,
+ PF1550_ENABLED,
+};
+
+struct pf1550_regulator_info {
+ struct rpmsg_device *rpdev;
+ struct device *dev;
+ struct pf1550_regulator_rpmsg *msg;
+ struct completion cmd_complete;
+ struct pm_qos_request pm_qos_req;
+ struct mutex lock;
+ struct regulator_desc *regulators;
+};
+
+static struct pf1550_regulator_info pf1550_info;
+
+struct pf1550_regulator_rpmsg {
+ /* common head */
+ struct imx_rpmsg_head header;
+ /* pmic structure */
+ union {
+ u8 regulator;
+ u8 reg;
+ };
+ u8 response;
+ u8 status;
+ union {
+ u32 voltage; /* uV */
+ u32 val;
+ };
+} __attribute__ ((packed));
+
+static int pf1550_send_message(struct pf1550_regulator_rpmsg *msg,
+ struct pf1550_regulator_info *info)
+{
+ int err;
+
+ if (!info->rpdev) {
+ dev_dbg(info->dev,
+ "rpmsg channel not ready, m4 image ready?\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&info->lock);
+ pm_qos_add_request(&info->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, 0);
+
+ msg->header.cate = IMX_RPMSG_PMIC;
+ msg->header.major = IMX_RMPSG_MAJOR;
+ msg->header.minor = IMX_RMPSG_MINOR;
+ msg->header.type = 0;
+
+ /* wait response from rpmsg */
+ reinit_completion(&info->cmd_complete);
+
+ err = rpmsg_send(info->rpdev->ept, (void *)msg,
+ sizeof(struct pf1550_regulator_rpmsg));
+ if (err) {
+ dev_err(&info->rpdev->dev, "rpmsg_send failed: %d\n", err);
+ goto err_out;
+ }
+ err = wait_for_completion_timeout(&info->cmd_complete,
+ msecs_to_jiffies(RPMSG_TIMEOUT));
+ if (!err) {
+ dev_err(&info->rpdev->dev, "rpmsg_send timeout!\n");
+ err = -ETIMEDOUT;
+ goto err_out;
+ }
+
+ err = 0;
+
+err_out:
+ pm_qos_remove_request(&info->pm_qos_req);
+ mutex_unlock(&info->lock);
+
+ dev_dbg(&info->rpdev->dev, "cmd:%d, reg:%d, resp:%d.\n",
+ msg->header.cmd, msg->regulator, msg->response);
+
+ return err;
+}
+
+static int pf1550_enable(struct regulator_dev *reg)
+{
+ struct pf1550_regulator_info *info = rdev_get_drvdata(reg);
+ struct pf1550_regulator_rpmsg msg;
+
+ msg.header.cmd = PF1550_ENABLE;
+ msg.regulator = reg->desc->id;
+
+ return pf1550_send_message(&msg, info);
+}
+
+static int pf1550_disable(struct regulator_dev *reg)
+{
+ struct pf1550_regulator_info *info = rdev_get_drvdata(reg);
+ struct pf1550_regulator_rpmsg msg;
+
+ msg.header.cmd = PF1550_DISABLE;
+ msg.regulator = reg->desc->id;
+
+ return pf1550_send_message(&msg, info);
+}
+
+static int pf1550_is_enabled(struct regulator_dev *reg)
+{
+ struct pf1550_regulator_info *info = rdev_get_drvdata(reg);
+ struct pf1550_regulator_rpmsg msg;
+ int err;
+
+ msg.header.cmd = PF1550_IS_ENABLED;
+ msg.regulator = reg->desc->id;
+
+ err = pf1550_send_message(&msg, info);
+ if (err)
+ return err;
+ /* Here SUCCESS means ENABLED */
+ if (info->msg->status == PF1550_ENABLED)
+ return 1;
+ else
+ return 0;
+}
+
+static int pf1550_set_voltage(struct regulator_dev *reg,
+ int minuV, int uV, unsigned *selector)
+{
+ struct pf1550_regulator_info *info = rdev_get_drvdata(reg);
+ struct pf1550_regulator_rpmsg msg;
+ int err;
+
+ msg.header.cmd = PF1550_SET_VOL;
+ msg.regulator = reg->desc->id;
+ msg.voltage = minuV;
+
+ err = pf1550_send_message(&msg, info);
+ if (err)
+ return err;
+
+ if (info->msg->response == PF1550_UNSURPPORT) {
+ dev_err(info->dev, "Voltages not allowed to set to %d!\n", uV);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int pf1550_get_voltage(struct regulator_dev *reg)
+{
+ struct pf1550_regulator_info *info = rdev_get_drvdata(reg);
+ struct pf1550_regulator_rpmsg msg;
+ int err;
+
+ msg.header.cmd = PF1550_GET_VOL;
+ msg.regulator = reg->desc->id;
+ msg.voltage = 0;
+
+ err = pf1550_send_message(&msg, info);
+ if (err)
+ return err;
+
+ return info->msg->voltage;
+}
+
+/* return the fix voltage */
+static int pf1550_get_fix_voltage(struct regulator_dev *dev)
+{
+ return dev->desc->fixed_uV;
+}
+
+static struct regulator_ops pf1550_sw_ops = {
+ .set_voltage = pf1550_set_voltage,
+ .get_voltage = pf1550_get_voltage,
+};
+
+static struct regulator_ops pf1550_ldo_ops = {
+ .enable = pf1550_enable,
+ .disable = pf1550_disable,
+ .is_enabled = pf1550_is_enabled,
+ .set_voltage = pf1550_set_voltage,
+ .get_voltage = pf1550_get_voltage,
+};
+
+static struct regulator_ops pf1550_fixed_ops = {
+ .enable = pf1550_enable,
+ .disable = pf1550_disable,
+ .get_voltage = pf1550_get_fix_voltage,
+ .is_enabled = pf1550_is_enabled,
+};
+
+static struct regulator_desc pf1550_regulators[PF1550_MAX_REGULATOR] = {
+{
+ .name = "SW1",
+ .of_match = of_match_ptr("SW1"),
+ .id = PF1550_SW1,
+ .ops = &pf1550_sw_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+},
+{
+ .name = "SW2",
+ .of_match = of_match_ptr("SW2"),
+ .id = PF1550_SW2,
+ .ops = &pf1550_sw_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+},
+{
+ .name = "SW3",
+ .of_match = of_match_ptr("SW3"),
+ .id = PF1550_SW3,
+ .ops = &pf1550_sw_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+},
+{
+ .name = "VREFDDR",
+ .of_match = of_match_ptr("VREFDDR"),
+ .id = PF1550_VREFDDR,
+ .ops = &pf1550_fixed_ops,
+ .type = REGULATOR_VOLTAGE,
+ .fixed_uV = 1200000,
+ .owner = THIS_MODULE,
+},
+{
+ .name = "LDO1",
+ .of_match = of_match_ptr("LDO1"),
+ .id = PF1550_LDO1,
+ .ops = &pf1550_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+},
+{
+ .name = "LDO2",
+ .of_match = of_match_ptr("LDO2"),
+ .id = PF1550_LDO2,
+ .ops = &pf1550_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+},
+{
+ .name = "LDO3",
+ .of_match = of_match_ptr("LDO3"),
+ .id = PF1550_LDO3,
+ .ops = &pf1550_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+},
+};
+
+
+static int rpmsg_regulator_cb(struct rpmsg_device *rpdev, void *data, int len,
+ void *priv, u32 src)
+{
+ struct pf1550_regulator_rpmsg *msg = (struct pf1550_regulator_rpmsg *)data;
+
+
+ dev_dbg(&rpdev->dev, "get from%d: cmd:%d, reg:%d, resp:%d.\n",
+ src, msg->header.cmd, msg->regulator, msg->response);
+
+ pf1550_info.msg = msg;
+
+ complete(&pf1550_info.cmd_complete);
+
+ return 0;
+}
+
+static int rpmsg_regulator_probe(struct rpmsg_device *rpdev)
+{
+ pf1550_info.rpdev = rpdev;
+
+ init_completion(&pf1550_info.cmd_complete);
+ mutex_init(&pf1550_info.lock);
+
+ dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
+ rpdev->src, rpdev->dst);
+ return 0;
+}
+
+static void rpmsg_regulator_remove(struct rpmsg_device *rpdev)
+{
+ dev_info(&rpdev->dev, "rpmsg regulator driver is removed\n");
+}
+
+static struct rpmsg_device_id rpmsg_regulator_id_table[] = {
+ { .name = "rpmsg-regulator-channel" },
+ { },
+};
+
+static struct rpmsg_driver rpmsg_regulator_driver = {
+ .drv.name = "regulator_rpmsg",
+ .drv.owner = THIS_MODULE,
+ .id_table = rpmsg_regulator_id_table,
+ .probe = rpmsg_regulator_probe,
+ .callback = rpmsg_regulator_cb,
+ .remove = rpmsg_regulator_remove,
+};
+
+#ifdef PF1550_DBGFS
+#define MAX_REGS 0xff
+
+/*
+ * Alligned the below two functions as the same as regmap_map_read_file
+ * and regmap_map_write_file in regmap-debugfs.c
+ */
+static ssize_t pf1550_registers_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pf1550_regulator_info *info = platform_get_drvdata(pdev);
+ struct pf1550_regulator_rpmsg msg;
+ int err;
+ size_t bufpos = 0, count = MAX_REGS * 7;
+
+ for (i = 0; i < MAX_REGS; i++) {
+ snprintf(buf + bufpos, count - bufpos, "%.*x: ", 2, i);
+ bufpos += 4;
+
+ msg.header.cmd = PF1550_GET_REG;
+ msg.reg = i;
+ msg.val = 0;
+
+ err = pf1550_send_message(&msg, info);
+ if (err)
+ return err;
+
+ if (info->msg->response != PF1550_SUCCESS) {
+ dev_err(info->dev, "Get register failed %x, resp=%x!\n",
+ i, info->msg->response);
+ return -EINVAL;
+ }
+
+ snprintf(buf + bufpos, count - bufpos, "%.*x\n", 2,
+ info->msg->val);
+ bufpos += 2;
+
+ buf[bufpos++] = '\n';
+ }
+
+ return bufpos;
+}
+
+static ssize_t pf1550_register_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pf1550_regulator_info *info = platform_get_drvdata(pdev);
+ struct pf1550_regulator_rpmsg msg;
+ char *start = (char *)buf;
+ unsigned long reg, value;
+ int err;
+
+ while (*start == ' ')
+ start++;
+ reg = simple_strtoul(start, &start, 16);
+
+ while (*start == ' ')
+ start++;
+ if (kstrtoul(start, 16, &value))
+ return -EINVAL;
+
+ msg.header.cmd = PF1550_SET_REG;
+ msg.reg = reg;
+ msg.val = value;
+
+ err = pf1550_send_message(&msg, info);
+ if (err)
+ return err;
+
+ if (info->msg->response != PF1550_SUCCESS) {
+ dev_err(info->dev, "set register failed %lx!\n", reg);
+ return -EINVAL;
+ }
+
+ return size;
+}
+
+static DEVICE_ATTR(regs, 0644, pf1550_registers_show, pf1550_register_store);
+#endif
+
+static int pf1550_regulator_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int i;
+ struct regulator_config config = { };
+
+ if (!np)
+ return -ENODEV;
+
+ config.dev = &pdev->dev;
+ config.driver_data = &pf1550_info;
+ pf1550_info.dev = &pdev->dev;
+ pf1550_info.regulators = pf1550_regulators;
+
+ for (i = 0; i < ARRAY_SIZE(pf1550_regulators); i++) {
+ struct regulator_dev *rdev;
+ struct regulator_desc *desc;
+
+ desc = &pf1550_info.regulators[i];
+ rdev = devm_regulator_register(&pdev->dev, desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev,
+ "Failed to initialize regulator-%d\n", i);
+ return PTR_ERR(rdev);
+ }
+ }
+
+#ifdef PF1550_DBGFS
+ i = sysfs_create_file(&config.dev->kobj, &dev_attr_regs.attr);
+ if (i) {
+ dev_err(&pdev->dev, "Failed to create pf1550 debug sysfs.\n");
+ return i;
+ }
+#endif
+
+ platform_set_drvdata(pdev, &pf1550_info);
+
+ return 0;
+}
+
+static const struct of_device_id pf1550_regulator_id[] = {
+ {"fsl,pf1550-rpmsg",},
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, pf1550_regulator_id);
+
+static struct platform_driver pf1550_regulator_driver = {
+ .driver = {
+ .name = "pf1550-rpmsg",
+ .owner = THIS_MODULE,
+ .of_match_table = pf1550_regulator_id,
+ },
+ .probe = pf1550_regulator_probe,
+};
+
+static int __init pf1550_rpmsg_init(void)
+{
+ return register_rpmsg_driver(&rpmsg_regulator_driver);
+}
+
+module_platform_driver(pf1550_regulator_driver);
+module_init(pf1550_rpmsg_init);
+
+MODULE_DESCRIPTION("Freescale PF1550 regulator rpmsg driver");
+MODULE_AUTHOR("Robin Gong <yibin.gong@freescale.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/pf1550.c b/drivers/regulator/pf1550.c
new file mode 100644
index 000000000000..f6837052859b
--- /dev/null
+++ b/drivers/regulator/pf1550.c
@@ -0,0 +1,390 @@
+/*
+ * pf1550.c - regulator driver for the PF1550
+ *
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Robin Gong <yibin.gong@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * This driver is based on pfuze100-regulator.c
+ */
+
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/mfd/pf1550.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/machine.h>
+#include <linux/platform_device.h>
+
+#define PF1550_MAX_REGULATOR 7
+
+struct pf1550_desc {
+ struct regulator_desc desc;
+ unsigned char stby_reg;
+ unsigned char stby_mask;
+};
+
+struct pf1550_regulator_info {
+ struct device *dev;
+ struct pf1550_dev *pf1550;
+ struct pf1550_desc regulator_descs[PF1550_MAX_REGULATOR];
+ int irq;
+};
+
+static struct pf1550_irq_info pf1550_regulator_irqs[] = {
+ { PF1550_PMIC_IRQ_SW1_LS, "sw1-lowside" },
+ { PF1550_PMIC_IRQ_SW2_LS, "sw2-lowside" },
+ { PF1550_PMIC_IRQ_SW3_LS, "sw3-lowside" },
+
+ { PF1550_PMIC_IRQ_SW1_HS, "sw1-highside" },
+ { PF1550_PMIC_IRQ_SW2_HS, "sw2-highside" },
+ { PF1550_PMIC_IRQ_SW3_HS, "sw3-highside" },
+
+ { PF1550_PMIC_IRQ_LDO1_FAULT, "ldo1-fault" },
+ { PF1550_PMIC_IRQ_LDO2_FAULT, "ldo2-fault" },
+ { PF1550_PMIC_IRQ_LDO3_FAULT, "ldo3-fault" },
+
+ { PF1550_PMIC_IRQ_TEMP_110, "temp-110" },
+ { PF1550_PMIC_IRQ_TEMP_125, "temp-125" },
+};
+
+static const int pf1550_sw12_volts[] = {
+ 1100000, 1200000, 1350000, 1500000, 1800000, 2500000, 3000000, 3300000,
+};
+
+static const int pf1550_ldo13_volts[] = {
+ 750000, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000,
+ 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
+ 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000,
+ 2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000,
+};
+
+static int pf1550_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+ int id = rdev_get_id(rdev);
+ unsigned int ramp_bits;
+ int ret;
+
+ if (id < PF1550_VREFDDR) {
+ ramp_delay = 6250 / ramp_delay;
+ ramp_bits = ramp_delay >> 1;
+ ret = regmap_update_bits(rdev->regmap,
+ rdev->desc->vsel_reg + 4,
+ 0x10, ramp_bits << 4);
+ if (ret < 0)
+ dev_err(&rdev->dev, "ramp failed, err %d\n", ret);
+ } else
+ ret = -EACCES;
+
+ return ret;
+}
+
+static struct regulator_ops pf1550_sw1_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_ramp_delay = pf1550_set_ramp_delay,
+};
+
+static struct regulator_ops pf1550_sw2_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_ramp_delay = pf1550_set_ramp_delay,
+};
+
+static struct regulator_ops pf1550_ldo1_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops pf1550_ldo2_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops pf1550_fixed_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+#define PF_VREF(_chip, _name, voltage) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(#_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = 1, \
+ .ops = &pf1550_fixed_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (voltage), \
+ .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .enable_mask = 0x1, \
+ }, \
+ .stby_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .stby_mask = 0x2, \
+}
+
+#define PF_SW1(_chip, _name, mask, voltages) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(#_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = ARRAY_SIZE(voltages), \
+ .ops = &pf1550_sw1_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .volt_table = voltages, \
+ .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \
+ .vsel_mask = (mask), \
+ }, \
+ .stby_reg = _chip ## _PMIC_REG_ ## _name ## _STBY_VOLT, \
+ .stby_mask = (mask), \
+}
+
+#define PF_SW3(_chip, _name, min, max, mask, step) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(#_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &pf1550_sw2_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \
+ .vsel_mask = (mask), \
+ }, \
+ .stby_reg = _chip ## _PMIC_REG_ ## _name ## _STBY_VOLT, \
+ .stby_mask = (mask), \
+}
+
+#define PF_LDO1(_chip, _name, mask, voltages) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(#_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = ARRAY_SIZE(voltages), \
+ .ops = &pf1550_ldo1_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .volt_table = voltages, \
+ .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \
+ .vsel_mask = (mask), \
+ .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .enable_mask = 0x1, \
+ }, \
+ .stby_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .stby_mask = 0x2, \
+}
+
+#define PF_LDO2(_chip, _name, mask, min, max, step) { \
+ .desc = { \
+ .name = #_name, \
+ .of_match = of_match_ptr(#_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &pf1550_ldo2_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .vsel_reg = _chip ## _PMIC_REG_ ## _name ## _VOLT, \
+ .vsel_mask = (mask), \
+ .enable_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .enable_mask = 0x1, \
+ }, \
+ .stby_reg = _chip ## _PMIC_REG_ ## _name ## _CTRL, \
+ .stby_mask = 0x2, \
+}
+
+static struct pf1550_desc pf1550_regulators[] = {
+ PF_SW3(PF1550, SW1, 600000, 1387500, 0x3f, 12500),
+ PF_SW3(PF1550, SW2, 600000, 1387500, 0x3f, 12500),
+ PF_SW3(PF1550, SW3, 1800000, 3300000, 0xf, 100000),
+ PF_VREF(PF1550, VREFDDR, 1200000),
+ PF_LDO1(PF1550, LDO1, 0x1f, pf1550_ldo13_volts),
+ PF_LDO2(PF1550, LDO2, 0xf, 1800000, 3300000, 100000),
+ PF_LDO1(PF1550, LDO3, 0x1f, pf1550_ldo13_volts),
+};
+
+static irqreturn_t pf1550_regulator_irq_handler(int irq, void *data)
+{
+ struct pf1550_regulator_info *info = data;
+ int i, irq_type = -1;
+
+ info->irq = irq;
+
+ for (i = 0; i < ARRAY_SIZE(pf1550_regulator_irqs); i++)
+ if (info->irq == pf1550_regulator_irqs[i].virq)
+ irq_type = pf1550_regulator_irqs[i].irq;
+
+ switch (irq_type) {
+ case PF1550_PMIC_IRQ_SW1_LS:
+ case PF1550_PMIC_IRQ_SW2_LS:
+ case PF1550_PMIC_IRQ_SW3_LS:
+ dev_info(info->dev, "lowside interrupt trigged! irq_type=%d\n",
+ irq_type);
+ break;
+ case PF1550_PMIC_IRQ_SW1_HS:
+ case PF1550_PMIC_IRQ_SW2_HS:
+ case PF1550_PMIC_IRQ_SW3_HS:
+ dev_info(info->dev, "highside interrupt triggered! irq_type=%d\n",
+ irq_type);
+ break;
+ case PF1550_PMIC_IRQ_LDO1_FAULT:
+ case PF1550_PMIC_IRQ_LDO2_FAULT:
+ case PF1550_PMIC_IRQ_LDO3_FAULT:
+ dev_info(info->dev, "ldo fault triggered! irq_type=%d\n",
+ irq_type);
+ break;
+ case PF1550_PMIC_IRQ_TEMP_110:
+ case PF1550_PMIC_IRQ_TEMP_125:
+ dev_info(info->dev, "thermal exception triggered! irq_type=%d\n",
+ irq_type);
+ break;
+ default:
+ dev_err(info->dev, "regulator interrupt: irq %d occurred\n",
+ irq_type);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int pf1550_regulator_probe(struct platform_device *pdev)
+{
+ struct pf1550_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+ struct device_node *np = pdev->dev.of_node;
+ struct pf1550_regulator_info *info;
+ int i, ret = 0;
+ struct regulator_config config = { };
+
+ if (!np)
+ return -ENODEV;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(struct pf1550_regulator_info),
+ GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ config.dev = iodev->dev;
+ config.regmap = iodev->regmap;
+ info->dev = &pdev->dev;
+ info->pf1550 = iodev;
+
+ memcpy(info->regulator_descs, pf1550_regulators,
+ sizeof(info->regulator_descs));
+
+ for (i = 0; i < ARRAY_SIZE(pf1550_regulators); i++) {
+ struct regulator_dev *rdev;
+ struct regulator_desc *desc;
+ unsigned int val;
+
+ desc = &info->regulator_descs[i].desc;
+
+ if (desc->id == PF1550_SW2) {
+ pf1550_read_otp(info->pf1550, 0x1f, &val);
+ /* OTP_SW2_DVS_ENB == 1? */
+ if ((val & 0x8)) {
+ desc->volt_table = pf1550_sw12_volts;
+ desc->n_voltages = ARRAY_SIZE(pf1550_sw12_volts);
+ desc->ops = &pf1550_sw1_ops;
+ }
+ }
+
+ rdev = devm_regulator_register(&pdev->dev, desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev,
+ "Failed to initialize regulator-%d\n", i);
+ return PTR_ERR(rdev);
+ }
+ }
+
+ platform_set_drvdata(pdev, info);
+
+ for (i = 0; i < ARRAY_SIZE(pf1550_regulator_irqs); i++) {
+ struct pf1550_irq_info *regulator_irq =
+ &pf1550_regulator_irqs[i];
+ unsigned int virq = 0;
+
+ virq = regmap_irq_get_virq(iodev->irq_data_regulator,
+ regulator_irq->irq);
+
+ if (!virq)
+ return -EINVAL;
+ regulator_irq->virq = virq;
+
+ ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
+ pf1550_regulator_irq_handler,
+ IRQF_NO_SUSPEND,
+ regulator_irq->name, info);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed: irq request (IRQ: %d, error :%d)\n",
+ regulator_irq->irq, ret);
+ return ret;
+ }
+ }
+
+ /* unmask all exception interrupts for regulators */
+ regmap_write(info->pf1550->regmap, PF1550_PMIC_REG_SW_INT_MASK0, 0);
+ regmap_write(info->pf1550->regmap, PF1550_PMIC_REG_SW_INT_MASK1, 0);
+ regmap_write(info->pf1550->regmap, PF1550_PMIC_REG_LDO_INT_MASK0, 0);
+ regmap_write(info->pf1550->regmap, PF1550_PMIC_REG_TEMP_INT_MASK0, 0);
+
+ return 0;
+}
+
+static const struct platform_device_id pf1550_regulator_id[] = {
+ {"pf1550-regulator", PF1550},
+ {},
+};
+
+MODULE_DEVICE_TABLE(platform, pf1550_regulator_id);
+
+static struct platform_driver pf1550_regulator_driver = {
+ .driver = {
+ .name = "pf1550-regulator",
+ },
+ .probe = pf1550_regulator_probe,
+ .id_table = pf1550_regulator_id,
+};
+
+module_platform_driver(pf1550_regulator_driver);
+
+MODULE_DESCRIPTION("Freescale PF1550 regulator driver");
+MODULE_AUTHOR("Robin Gong <yibin.gong@freescale.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
index 86b348740fcd..92bf0c952583 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2017 NXP
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,6 +36,15 @@
#define PFUZE100_STANDBY_OFFSET 1
#define PFUZE100_MODE_OFFSET 3
#define PFUZE100_CONF_OFFSET 4
+/*
+ * below regs will lost after exit from LPSR mode(PFUZE3000), need to be saved
+ * and restored:
+ * 0x20~0x40: 33
+ * 0x66~0x71: 12
+ * 0x7f: 1
+ * total 46 registers.
+ */
+#define PFUZE100_REG_SAVED_NUM (33 + 12 + 1)
#define PFUZE100_DEVICEID 0x0
#define PFUZE100_REVID 0x3
@@ -68,6 +78,8 @@ struct pfuze_chip {
int chip_id;
struct regmap *regmap;
struct device *dev;
+ bool need_restore;
+ unsigned int reg_save_array[PFUZE100_REG_SAVED_NUM];
struct pfuze_regulator regulator_descs[PFUZE100_MAX_REGULATOR];
struct regulator_dev *regulators[PFUZE100_MAX_REGULATOR];
struct pfuze_regulator *pfuze_regulators;
@@ -81,6 +93,13 @@ static const int pfuze100_vsnvs[] = {
1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000,
};
+static const int pfuze3000_sw1a[] = {
+ 700000, 725000, 750000, 775000, 800000, 825000, 850000, 875000,
+ 900000, 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000,
+ 1100000, 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000,
+ 1300000, 1325000, 1350000, 1375000, 1400000, 1425000, 1800000, 3300000,
+};
+
static const int pfuze3000_sw2lo[] = {
1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000,
};
@@ -143,6 +162,9 @@ static struct regulator_ops pfuze100_fixed_regulator_ops = {
};
static struct regulator_ops pfuze100_sw_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -189,6 +211,11 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
.uV_step = (step), \
.vsel_reg = (base) + PFUZE100_VOL_OFFSET, \
.vsel_mask = 0x3f, \
+ .enable_reg = (base) + PFUZE100_MODE_OFFSET, \
+ .enable_val = 0xc, \
+ .disable_val = 0x0, \
+ .enable_mask = 0xf, \
+ .enable_time = 500, \
}, \
.stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \
.stby_mask = 0x3f, \
@@ -321,7 +348,7 @@ static struct pfuze_regulator pfuze200_regulators[] = {
};
static struct pfuze_regulator pfuze3000_regulators[] = {
- PFUZE100_SW_REG(PFUZE3000, SW1A, PFUZE100_SW1ABVOL, 700000, 1475000, 25000),
+ PFUZE100_SWB_REG(PFUZE3000, SW1A, PFUZE100_SW1ABVOL, 0x1f, pfuze3000_sw1a),
PFUZE100_SW_REG(PFUZE3000, SW1B, PFUZE100_SW1CVOL, 700000, 1475000, 25000),
PFUZE100_SWB_REG(PFUZE3000, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo),
PFUZE3000_SW3_REG(PFUZE3000, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000),
@@ -636,14 +663,95 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
}
}
+
+ if (of_get_property(client->dev.of_node, "fsl,lpsr-mode", NULL))
+ pfuze_chip->need_restore = true;
+
+ return 0;
+}
+
+static int pfuze_reg_save_restore(struct pfuze_chip *pfuze_chip, int start,
+ int end, int index, bool save)
+{
+ int i, ret;
+
+ for (i = 0; i < end - start + 1; i++) {
+ if (save)
+ ret = regmap_read(pfuze_chip->regmap, start + i,
+ &pfuze_chip->reg_save_array[index + i]);
+ else
+ ret = regmap_write(pfuze_chip->regmap, start + i,
+ pfuze_chip->reg_save_array[index + i]);
+
+ if (ret)
+ return ret;
+ }
+
+ return index + i;
+}
+
+static int pfuze_suspend(struct device *dev)
+{
+ struct pfuze_chip *pfuze_chip = i2c_get_clientdata(to_i2c_client(dev));
+ int index = 0;
+
+ if (pfuze_chip->need_restore) {
+ /* 0x20~0x40 */
+ index = pfuze_reg_save_restore(pfuze_chip, 0x20, 0x40, index, true);
+ if (index < 0)
+ goto err_ret;
+ /* 0x66~0x71 */
+ index = pfuze_reg_save_restore(pfuze_chip, 0x66, 0x71, ++index, true);
+ if (index < 0)
+ goto err_ret;
+ /* 0x7f */
+ index = pfuze_reg_save_restore(pfuze_chip, 0x7f, 0x7f, ++index, true);
+ if (index < 0)
+ goto err_ret;
+ }
+
return 0;
+
+err_ret:
+ return index;
}
+static int pfuze_resume(struct device *dev)
+{
+ struct pfuze_chip *pfuze_chip = i2c_get_clientdata(to_i2c_client(dev));
+ int index = 0;
+
+ if (pfuze_chip->need_restore) {
+ /* 0x20~0x40 */
+ index = pfuze_reg_save_restore(pfuze_chip, 0x20, 0x40, index, false);
+ if (index < 0)
+ goto err_ret;
+ /* 0x66~0x71 */
+ index = pfuze_reg_save_restore(pfuze_chip, 0x66, 0x71, ++index, false);
+ if (index < 0)
+ goto err_ret;
+ /* 0x7f */
+ index = pfuze_reg_save_restore(pfuze_chip, 0x7f, 0x7f, ++index, false);
+ if (index < 0)
+ goto err_ret;
+ }
+
+ return 0;
+
+err_ret:
+ return index;
+}
+
+static const struct dev_pm_ops pfuze_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pfuze_suspend, pfuze_resume)
+};
+
static struct i2c_driver pfuze_driver = {
.id_table = pfuze_device_id,
.driver = {
.name = "pfuze100-regulator",
.of_match_table = pfuze_dt_ids,
+ .pm = &pfuze_pm_ops,
},
.probe = pfuze100_regulator_probe,
};
diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c
index 765acc11c9c8..9d6c07976fa5 100644
--- a/drivers/regulator/userspace-consumer.c
+++ b/drivers/regulator/userspace-consumer.c
@@ -22,6 +22,8 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/userspace-consumer.h>
+#include <linux/of.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/slab.h>
struct userspace_consumer_data {
@@ -105,6 +107,39 @@ static const struct attribute_group attr_group = {
.attrs = attributes,
};
+#if defined(CONFIG_OF)
+static struct regulator_userspace_consumer_data*
+ of_get_uc_config(struct device *dev, struct device_node *np)
+{
+ struct regulator_userspace_consumer_data *ucd;
+ int r;
+
+ ucd = devm_kzalloc(dev, sizeof(struct regulator_userspace_consumer_data)
+ + sizeof(struct regulator_bulk_data),
+ GFP_KERNEL);
+ if (ucd == NULL)
+ return NULL;
+
+ r = of_property_read_string(np, "uc-name", &ucd->name);
+ if (r) {
+ goto err;
+ }
+
+ ucd->num_supplies = 1;
+ ucd->supplies = (struct regulator_bulk_data *)&ucd[1];
+
+ r = of_property_read_string(np, "suck-supply", &ucd->supplies->supply);
+ if (r) {
+ goto err;
+ }
+ return ucd;
+
+err:
+ devm_kfree(dev, ucd);
+ return NULL;
+}
+#endif
+
static int regulator_userspace_consumer_probe(struct platform_device *pdev)
{
struct regulator_userspace_consumer_data *pdata;
@@ -112,6 +147,11 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev)
int ret;
pdata = dev_get_platdata(&pdev->dev);
+#if defined(CONFIG_OF)
+ if (!pdata && pdev->dev.of_node) {
+ pdata = of_get_uc_config(&pdev->dev, pdev->dev.of_node);
+ }
+#endif
if (!pdata)
return -EINVAL;
@@ -151,6 +191,8 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev)
drvdata->enabled = pdata->init_on;
platform_set_drvdata(pdev, drvdata);
+ dev_info(&pdev->dev, "attached: %s\n", drvdata->name);
+
return 0;
err_enable:
@@ -171,11 +213,22 @@ static int regulator_userspace_consumer_remove(struct platform_device *pdev)
return 0;
}
+#if defined(CONFIG_OF)
+static const struct of_device_id uc_of_match[] = {
+ { .compatible = "userspace_consumer", },
+ {},
+};
+#endif
+
static struct platform_driver regulator_userspace_consumer_driver = {
.probe = regulator_userspace_consumer_probe,
.remove = regulator_userspace_consumer_remove,
.driver = {
.name = "reg-userspace-consumer",
+ .owner = THIS_MODULE,
+#if defined(CONFIG_OF)
+ .of_match_table = of_match_ptr(uc_of_match),
+#endif
},
};
diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c
index a6f1c7a9914f..115b9b350f76 100644
--- a/drivers/regulator/virtual.c
+++ b/drivers/regulator/virtual.c
@@ -15,8 +15,11 @@
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/of.h>
+
struct virtual_consumer_data {
struct mutex lock;
@@ -285,9 +288,22 @@ static const struct attribute_group regulator_virtual_attr_group = {
.attrs = regulator_virtual_attributes,
};
+static const char *of_get_virt_regulator_config(struct device *dev, struct device_node *np)
+{
+ const char *reg_id;
+ int r;
+
+ r = of_property_read_string(np, "virtual-supply", &reg_id);
+ if (r) {
+ return NULL;
+ }
+ return reg_id;
+}
+
static int regulator_virtual_probe(struct platform_device *pdev)
{
char *reg_id = dev_get_platdata(&pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
struct virtual_consumer_data *drvdata;
int ret;
@@ -296,6 +312,15 @@ static int regulator_virtual_probe(struct platform_device *pdev)
if (drvdata == NULL)
return -ENOMEM;
+ if (np) {
+ reg_id = (char *)of_get_virt_regulator_config(&pdev->dev, np);
+ }
+
+ if (reg_id == NULL) {
+ dev_err(&pdev->dev, "Fail to get reg_id");
+ return -EINVAL;
+ }
+
mutex_init(&drvdata->lock);
drvdata->regulator = devm_regulator_get(&pdev->dev, reg_id);
@@ -318,6 +343,8 @@ static int regulator_virtual_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, drvdata);
+ dev_info(&pdev->dev, "attached: %s\n", reg_id);
+
return 0;
}
@@ -330,14 +357,25 @@ static int regulator_virtual_remove(struct platform_device *pdev)
if (drvdata->enabled)
regulator_disable(drvdata->regulator);
+ platform_set_drvdata(pdev, NULL);
+
return 0;
}
+#if defined(CONFIG_OF)
+static const struct of_device_id regulator_virtual_of_match[] = {
+ { .compatible = "regulator-virtual", },
+ {},
+};
+#endif
+
static struct platform_driver regulator_virtual_consumer_driver = {
.probe = regulator_virtual_probe,
.remove = regulator_virtual_remove,
.driver = {
.name = "reg-virt-consumer",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(regulator_virtual_of_match),
},
};
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 06d9fa2f3bc0..155746d32a65 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -27,6 +27,14 @@ config RESET_BERLIN
help
This enables the reset controller driver for Marvell Berlin SoCs.
+config RESET_GPIO
+ tristate "GPIO reset controller support"
+ default y
+ depends on GPIOLIB && OF
+ help
+ This driver provides support for reset lines that are controlled
+ directly by GPIOs.
+
config RESET_LPC18XX
bool "LPC18xx/43xx Reset Driver" if COMPILE_TEST
default ARCH_LPC18XX
@@ -95,4 +103,5 @@ config RESET_ZYNQ
source "drivers/reset/sti/Kconfig"
source "drivers/reset/hisilicon/Kconfig"
+
endif
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index bbe7026617fc..391cad3c91ce 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -3,6 +3,7 @@ obj-y += hisilicon/
obj-$(CONFIG_ARCH_STI) += sti/
obj-$(CONFIG_RESET_ATH79) += reset-ath79.o
obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o
+obj-$(CONFIG_RESET_GPIO) += gpio-reset.o
obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
obj-$(CONFIG_RESET_MESON) += reset-meson.o
obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
diff --git a/drivers/reset/gpio-reset.c b/drivers/reset/gpio-reset.c
new file mode 100644
index 000000000000..9dc768aa6f33
--- /dev/null
+++ b/drivers/reset/gpio-reset.c
@@ -0,0 +1,196 @@
+/*
+ * GPIO Reset Controller driver
+ *
+ * Copyright 2013 Philipp Zabel, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+
+struct gpio_reset_data {
+ struct reset_controller_dev rcdev;
+ unsigned int gpio;
+ bool active_low;
+ s32 delay_us;
+ s32 post_delay_ms;
+};
+
+static void gpio_reset_set(struct reset_controller_dev *rcdev, int asserted)
+{
+ struct gpio_reset_data *drvdata = container_of(rcdev,
+ struct gpio_reset_data, rcdev);
+ int value = asserted;
+
+ if (drvdata->active_low)
+ value = !value;
+
+ gpio_set_value_cansleep(drvdata->gpio, value);
+}
+
+static int gpio_reset(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ struct gpio_reset_data *drvdata = container_of(rcdev,
+ struct gpio_reset_data, rcdev);
+
+ if (drvdata->delay_us < 0)
+ return -ENOSYS;
+
+ gpio_reset_set(rcdev, 1);
+ udelay(drvdata->delay_us);
+ gpio_reset_set(rcdev, 0);
+
+ if (drvdata->post_delay_ms < 0)
+ return 0;
+
+ msleep(drvdata->post_delay_ms);
+ return 0;
+}
+
+static int gpio_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ gpio_reset_set(rcdev, 1);
+
+ return 0;
+}
+
+static int gpio_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ gpio_reset_set(rcdev, 0);
+
+ return 0;
+}
+
+static struct reset_control_ops gpio_reset_ops = {
+ .reset = gpio_reset,
+ .assert = gpio_reset_assert,
+ .deassert = gpio_reset_deassert,
+};
+
+static int of_gpio_reset_xlate(struct reset_controller_dev *rcdev,
+ const struct of_phandle_args *reset_spec)
+{
+ if (WARN_ON(reset_spec->args_count != 0))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int gpio_reset_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct gpio_reset_data *drvdata;
+ enum of_gpio_flags flags;
+ unsigned long gpio_flags;
+ bool initially_in_reset;
+ int ret;
+
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+ if (drvdata == NULL)
+ return -ENOMEM;
+
+ if (of_gpio_named_count(np, "reset-gpios") != 1) {
+ dev_err(&pdev->dev,
+ "reset-gpios property missing, or not a single gpio\n");
+ return -EINVAL;
+ }
+
+ drvdata->gpio = of_get_named_gpio_flags(np, "reset-gpios", 0, &flags);
+ if (drvdata->gpio == -EPROBE_DEFER) {
+ return drvdata->gpio;
+ } else if (!gpio_is_valid(drvdata->gpio)) {
+ dev_err(&pdev->dev, "invalid reset gpio: %d\n", drvdata->gpio);
+ return drvdata->gpio;
+ }
+
+ drvdata->active_low = flags & OF_GPIO_ACTIVE_LOW;
+
+ ret = of_property_read_u32(np, "reset-delay-us", &drvdata->delay_us);
+ if (ret < 0)
+ drvdata->delay_us = -1;
+ else if (drvdata->delay_us < 0)
+ dev_warn(&pdev->dev, "reset delay too high\n");
+
+ /* It is optional.
+ * Some devices need some milliseconds to wait after reset.
+ */
+ ret = of_property_read_u32(np, "reset-post-delay-ms", &drvdata->post_delay_ms);
+ if (ret < 0)
+ drvdata->post_delay_ms = -1;
+
+ initially_in_reset = of_property_read_bool(np, "initially-in-reset");
+ if (drvdata->active_low ^ initially_in_reset)
+ gpio_flags = GPIOF_OUT_INIT_HIGH;
+ else
+ gpio_flags = GPIOF_OUT_INIT_LOW;
+
+ ret = devm_gpio_request_one(&pdev->dev, drvdata->gpio, gpio_flags, NULL);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request gpio %d: %d\n",
+ drvdata->gpio, ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, drvdata);
+
+ drvdata->rcdev.of_node = np;
+ drvdata->rcdev.owner = THIS_MODULE;
+ drvdata->rcdev.nr_resets = 1;
+ drvdata->rcdev.ops = &gpio_reset_ops;
+ drvdata->rcdev.of_xlate = of_gpio_reset_xlate;
+ reset_controller_register(&drvdata->rcdev);
+
+ return 0;
+}
+
+static int gpio_reset_remove(struct platform_device *pdev)
+{
+ struct gpio_reset_data *drvdata = platform_get_drvdata(pdev);
+
+ reset_controller_unregister(&drvdata->rcdev);
+
+ return 0;
+}
+
+static struct of_device_id gpio_reset_dt_ids[] = {
+ { .compatible = "gpio-reset" },
+ { }
+};
+
+static struct platform_driver gpio_reset_driver = {
+ .probe = gpio_reset_probe,
+ .remove = gpio_reset_remove,
+ .driver = {
+ .name = "gpio-reset",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(gpio_reset_dt_ids),
+ },
+};
+
+static int __init gpio_reset_init(void)
+{
+ return platform_driver_register(&gpio_reset_driver);
+}
+arch_initcall(gpio_reset_init);
+
+static void __exit gpio_reset_exit(void)
+{
+ platform_driver_unregister(&gpio_reset_driver);
+}
+module_exit(gpio_reset_exit);
+
+MODULE_AUTHOR("Philipp Zabel <p.zabel@pengutronix.de>");
+MODULE_DESCRIPTION("gpio reset controller");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-reset");
+MODULE_DEVICE_TABLE(of, gpio_reset_dt_ids);
diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
index de31c5f14dd9..af1c66f138cf 100644
--- a/drivers/rpmsg/Kconfig
+++ b/drivers/rpmsg/Kconfig
@@ -4,6 +4,14 @@ menu "Rpmsg drivers"
config RPMSG
tristate
+config RPMSG_CHAR
+ tristate "RPMSG device interface"
+ depends on RPMSG
+ help
+ Say Y here to export rpmsg endpoints as device files, usually found
+ in /dev. They make it possible for user-space programs to send and
+ receive rpmsg packets.
+
config RPMSG_QCOM_SMD
tristate "Qualcomm Shared Memory Driver (SMD)"
depends on QCOM_SMEM
@@ -20,4 +28,19 @@ config RPMSG_VIRTIO
select VIRTIO
select VIRTUALIZATION
+config HAVE_IMX_RPMSG
+ bool "IMX RPMSG driver on the AMP SOCs"
+ select RPMSG
+ select RPMSG_VIRTIO
+
+config IMX_RPMSG_PINGPONG
+ tristate "IMX RPMSG pingpong driver -- loadable modules only"
+ default m
+ depends on RPMSG && m
+
+config IMX_RPMSG_TTY
+ tristate "IMX RPMSG tty driver -- loadable modules only"
+ default m
+ depends on RPMSG && m
+
endmenu
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
index ae9c9132cf76..1548f5c55815 100644
--- a/drivers/rpmsg/Makefile
+++ b/drivers/rpmsg/Makefile
@@ -1,3 +1,7 @@
obj-$(CONFIG_RPMSG) += rpmsg_core.o
+obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o
obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o
obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o
+obj-$(CONFIG_HAVE_IMX_RPMSG) += imx_rpmsg.o
+obj-$(CONFIG_IMX_RPMSG_PINGPONG) += imx_rpmsg_pingpong.o
+obj-$(CONFIG_IMX_RPMSG_TTY) += imx_rpmsg_tty.o
diff --git a/drivers/rpmsg/imx_rpmsg.c b/drivers/rpmsg/imx_rpmsg.c
new file mode 100644
index 000000000000..d4ee27085fe1
--- /dev/null
+++ b/drivers/rpmsg/imx_rpmsg.c
@@ -0,0 +1,613 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * derived from the omap-rpmsg implementation.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/rpmsg.h>
+#include <linux/slab.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_ring.h>
+#include <linux/imx_rpmsg.h>
+#include <linux/mx8_mu.h>
+
+enum imx_rpmsg_variants {
+ IMX6SX,
+ IMX7D,
+ IMX7ULP,
+ IMX8QXP,
+ IMX8QM,
+};
+
+struct imx_virdev {
+ struct virtio_device vdev;
+ unsigned int vring[2];
+ struct virtqueue *vq[2];
+ int base_vq_id;
+ int num_of_vqs;
+ struct notifier_block nb;
+};
+
+struct imx_rpmsg_vproc {
+ char *rproc_name;
+ struct mutex lock;
+ struct clk *mu_clk;
+ enum imx_rpmsg_variants variant;
+ int vdev_nums;
+#define MAX_VDEV_NUMS 8
+ struct imx_virdev ivdev[MAX_VDEV_NUMS];
+ void __iomem *mu_base;
+ struct delayed_work rpmsg_work;
+ struct blocking_notifier_head notifier;
+#define MAX_NUM 10 /* enlarge it if overflow happen */
+ u32 m4_message[MAX_NUM];
+ u32 in_idx;
+ u32 out_idx;
+ u32 core_id;
+ spinlock_t mu_lock;
+};
+
+/*
+ * For now, allocate 256 buffers of 512 bytes for each side. each buffer
+ * will then have 16B for the msg header and 496B for the payload.
+ * This will require a total space of 256KB for the buffers themselves, and
+ * 3 pages for every vring (the size of the vring depends on the number of
+ * buffers it supports).
+ */
+#define RPMSG_NUM_BUFS (512)
+#define RPMSG_BUF_SIZE (512)
+#define RPMSG_BUFS_SPACE (RPMSG_NUM_BUFS * RPMSG_BUF_SIZE)
+
+/*
+ * The alignment between the consumer and producer parts of the vring.
+ * Note: this is part of the "wire" protocol. If you change this, you need
+ * to update your BIOS image as well
+ */
+#define RPMSG_VRING_ALIGN (4096)
+
+/* With 256 buffers, our vring will occupy 3 pages */
+#define RPMSG_RING_SIZE ((DIV_ROUND_UP(vring_size(RPMSG_NUM_BUFS / 2, \
+ RPMSG_VRING_ALIGN), PAGE_SIZE)) * PAGE_SIZE)
+
+#define to_imx_virdev(vd) container_of(vd, struct imx_virdev, vdev)
+#define to_imx_rpdev(vd, id) container_of(vd, struct imx_rpmsg_vproc, ivdev[id])
+
+struct imx_rpmsg_vq_info {
+ __u16 num; /* number of entries in the virtio_ring */
+ __u16 vq_id; /* a globaly unique index of this virtqueue */
+ void *addr; /* address where we mapped the virtio ring */
+ struct imx_rpmsg_vproc *rpdev;
+};
+
+static u64 imx_rpmsg_get_features(struct virtio_device *vdev)
+{
+ /* VIRTIO_RPMSG_F_NS has been made private */
+ return 1 << 0;
+}
+
+static int imx_rpmsg_finalize_features(struct virtio_device *vdev)
+{
+ /* Give virtio_ring a chance to accept features */
+ vring_transport_features(vdev);
+ return 0;
+}
+
+/* kick the remote processor, and let it know which virtqueue to poke at */
+static bool imx_rpmsg_notify(struct virtqueue *vq)
+{
+ unsigned int mu_rpmsg = 0;
+ struct imx_rpmsg_vq_info *rpvq = vq->priv;
+
+ mu_rpmsg = rpvq->vq_id << 16;
+ mutex_lock(&rpvq->rpdev->lock);
+ /* send the index of the triggered virtqueue as the mu payload */
+ MU_SendMessage(rpvq->rpdev->mu_base, 1, mu_rpmsg);
+ mutex_unlock(&rpvq->rpdev->lock);
+
+ return true;
+}
+
+static int imx_mu_rpmsg_callback(struct notifier_block *this,
+ unsigned long index, void *data)
+{
+ u32 mu_msg = (phys_addr_t) data;
+ struct imx_virdev *virdev;
+
+ virdev = container_of(this, struct imx_virdev, nb);
+
+ pr_debug("%s mu_msg: 0x%x\n", __func__, mu_msg);
+ /* ignore vq indices which are clearly not for us */
+ mu_msg = mu_msg >> 16;
+ if (mu_msg < virdev->base_vq_id || mu_msg > virdev->base_vq_id + 1) {
+ pr_debug("mu_msg: 0x%x is invalid\n", mu_msg);
+ return NOTIFY_DONE;
+ }
+
+ mu_msg -= virdev->base_vq_id;
+
+ /*
+ * Currently both PENDING_MSG and explicit-virtqueue-index
+ * messaging are supported.
+ * Whatever approach is taken, at this point 'mu_msg' contains
+ * the index of the vring which was just triggered.
+ */
+ if (mu_msg < virdev->num_of_vqs)
+ vring_interrupt(mu_msg, virdev->vq[mu_msg]);
+
+ return NOTIFY_DONE;
+}
+
+static int imx_mu_rpmsg_register_nb(struct imx_rpmsg_vproc *rpdev,
+ struct notifier_block *nb)
+{
+ if ((rpdev == NULL) || (nb == NULL))
+ return -EINVAL;
+
+ blocking_notifier_chain_register(&(rpdev->notifier), nb);
+
+ return 0;
+}
+
+static int imx_mu_rpmsg_unregister_nb(struct imx_rpmsg_vproc *rpdev,
+ struct notifier_block *nb)
+{
+ if ((rpdev == NULL) || (nb == NULL))
+ return -EINVAL;
+
+ blocking_notifier_chain_unregister(&(rpdev->notifier), nb);
+
+ return 0;
+}
+
+static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
+ unsigned int index,
+ void (*callback)(struct virtqueue *vq),
+ const char *name)
+{
+ struct imx_virdev *virdev = to_imx_virdev(vdev);
+ struct imx_rpmsg_vproc *rpdev = to_imx_rpdev(virdev,
+ virdev->base_vq_id / 2);
+ struct imx_rpmsg_vq_info *rpvq;
+ struct virtqueue *vq;
+ int err;
+
+ rpvq = kmalloc(sizeof(*rpvq), GFP_KERNEL);
+ if (!rpvq)
+ return ERR_PTR(-ENOMEM);
+
+ /* ioremap'ing normal memory, so we cast away sparse's complaints */
+ rpvq->addr = (__force void *) ioremap_nocache(virdev->vring[index],
+ RPMSG_RING_SIZE);
+ if (!rpvq->addr) {
+ err = -ENOMEM;
+ goto free_rpvq;
+ }
+
+ memset_io(rpvq->addr, 0, RPMSG_RING_SIZE);
+
+ pr_debug("vring%d: phys 0x%x, virt 0x%p\n", index, virdev->vring[index],
+ rpvq->addr);
+
+ vq = vring_new_virtqueue(index, RPMSG_NUM_BUFS / 2, RPMSG_VRING_ALIGN,
+ vdev, true, rpvq->addr, imx_rpmsg_notify, callback,
+ name);
+ if (!vq) {
+ pr_err("vring_new_virtqueue failed\n");
+ err = -ENOMEM;
+ goto unmap_vring;
+ }
+
+ virdev->vq[index] = vq;
+ vq->priv = rpvq;
+ /* system-wide unique id for this virtqueue */
+ rpvq->vq_id = virdev->base_vq_id + index;
+ rpvq->rpdev = rpdev;
+ mutex_init(&rpdev->lock);
+
+ return vq;
+
+unmap_vring:
+ /* iounmap normal memory, so make sparse happy */
+ iounmap((__force void __iomem *) rpvq->addr);
+free_rpvq:
+ kfree(rpvq);
+ return ERR_PTR(err);
+}
+
+static void imx_rpmsg_del_vqs(struct virtio_device *vdev)
+{
+ struct virtqueue *vq, *n;
+ struct imx_virdev *virdev = to_imx_virdev(vdev);
+ struct imx_rpmsg_vproc *rpdev = to_imx_rpdev(virdev,
+ virdev->base_vq_id / 2);
+
+ list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
+ struct imx_rpmsg_vq_info *rpvq = vq->priv;
+
+ iounmap(rpvq->addr);
+ vring_del_virtqueue(vq);
+ kfree(rpvq);
+ }
+
+ if (&virdev->nb)
+ imx_mu_rpmsg_unregister_nb(rpdev, &virdev->nb);
+}
+
+static int imx_rpmsg_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
+ struct virtqueue *vqs[],
+ vq_callback_t *callbacks[],
+ const char * const names[])
+{
+ struct imx_virdev *virdev = to_imx_virdev(vdev);
+ struct imx_rpmsg_vproc *rpdev = to_imx_rpdev(virdev,
+ virdev->base_vq_id / 2);
+ int i, err;
+
+ /* we maintain two virtqueues per remote processor (for RX and TX) */
+ if (nvqs != 2)
+ return -EINVAL;
+
+ for (i = 0; i < nvqs; ++i) {
+ vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]);
+ if (IS_ERR(vqs[i])) {
+ err = PTR_ERR(vqs[i]);
+ goto error;
+ }
+ }
+
+ virdev->num_of_vqs = nvqs;
+
+ virdev->nb.notifier_call = imx_mu_rpmsg_callback;
+ imx_mu_rpmsg_register_nb(rpdev, &virdev->nb);
+
+ return 0;
+
+error:
+ imx_rpmsg_del_vqs(vdev);
+ return err;
+}
+
+static void imx_rpmsg_reset(struct virtio_device *vdev)
+{
+ dev_dbg(&vdev->dev, "reset !\n");
+}
+
+static u8 imx_rpmsg_get_status(struct virtio_device *vdev)
+{
+ return 0;
+}
+
+static void imx_rpmsg_set_status(struct virtio_device *vdev, u8 status)
+{
+ dev_dbg(&vdev->dev, "%s new status: %d\n", __func__, status);
+}
+
+static void imx_rpmsg_vproc_release(struct device *dev)
+{
+ /* this handler is provided so driver core doesn't yell at us */
+}
+
+static struct virtio_config_ops imx_rpmsg_config_ops = {
+ .get_features = imx_rpmsg_get_features,
+ .finalize_features = imx_rpmsg_finalize_features,
+ .find_vqs = imx_rpmsg_find_vqs,
+ .del_vqs = imx_rpmsg_del_vqs,
+ .reset = imx_rpmsg_reset,
+ .set_status = imx_rpmsg_set_status,
+ .get_status = imx_rpmsg_get_status,
+};
+
+static struct imx_rpmsg_vproc imx_rpmsg_vprocs[] = {
+ {
+ .rproc_name = "m4",
+ },
+ {
+ .rproc_name = "m4",
+ },
+};
+
+static const struct of_device_id imx_rpmsg_dt_ids[] = {
+ { .compatible = "fsl,imx6sx-rpmsg", .data = (void *)IMX6SX, },
+ { .compatible = "fsl,imx7d-rpmsg", .data = (void *)IMX7D, },
+ { .compatible = "fsl,imx7ulp-rpmsg", .data = (void *)IMX7ULP, },
+ { .compatible = "fsl,imx8qxp-rpmsg", .data = (void *)IMX8QXP, },
+ { .compatible = "fsl,imx8qm-rpmsg", .data = (void *)IMX8QM, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_rpmsg_dt_ids);
+
+static int set_vring_phy_buf(struct platform_device *pdev,
+ struct imx_rpmsg_vproc *rpdev, int vdev_nums)
+{
+ struct resource *res;
+ resource_size_t size;
+ unsigned int start, end;
+ int i, ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res) {
+ size = resource_size(res);
+ start = res->start;
+ end = res->start + size;
+ for (i = 0; i < vdev_nums; i++) {
+ rpdev->ivdev[i].vring[0] = start;
+ rpdev->ivdev[i].vring[1] = start +
+ 0x8000;
+ start += 0x10000;
+ if (start > end) {
+ pr_err("Too small memory size %x!\n",
+ (u32)size);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ } else {
+ return -ENOMEM;
+ }
+
+ return ret;
+}
+
+static void rpmsg_work_handler(struct work_struct *work)
+{
+ u32 message;
+ unsigned long flags;
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct imx_rpmsg_vproc *rpdev = container_of(dwork,
+ struct imx_rpmsg_vproc, rpmsg_work);
+
+ spin_lock_irqsave(&rpdev->mu_lock, flags);
+ /* handle all incoming mu message */
+ while (rpdev->in_idx != rpdev->out_idx) {
+ message = rpdev->m4_message[rpdev->out_idx % MAX_NUM];
+ spin_unlock_irqrestore(&rpdev->mu_lock, flags);
+
+ blocking_notifier_call_chain(&(rpdev->notifier), 4,
+ (void *)(phys_addr_t)message);
+
+ spin_lock_irqsave(&rpdev->mu_lock, flags);
+ rpdev->m4_message[rpdev->out_idx % MAX_NUM] = 0;
+ rpdev->out_idx++;
+ }
+ spin_unlock_irqrestore(&rpdev->mu_lock, flags);
+}
+
+static irqreturn_t imx_mu_rpmsg_isr(int irq, void *param)
+{
+ u32 irqs, message;
+ unsigned long flags;
+ struct imx_rpmsg_vproc *rpdev = (struct imx_rpmsg_vproc *)param;
+
+ irqs = MU_ReadStatus(rpdev->mu_base);
+
+ /* RPMSG */
+ if (irqs & (1 << 26)) {
+ spin_lock_irqsave(&rpdev->mu_lock, flags);
+ /* get message from receive buffer */
+ MU_ReceiveMsg(rpdev->mu_base, 1, &message);
+ rpdev->m4_message[rpdev->in_idx % MAX_NUM] = message;
+ rpdev->in_idx++;
+ /*
+ * Too many mu message not be handled in timely, can enlarge
+ * MAX_NUM
+ */
+ if (rpdev->in_idx == rpdev->out_idx) {
+ spin_unlock_irqrestore(&rpdev->mu_lock, flags);
+ pr_err("MU overflow!\n");
+ return IRQ_HANDLED;
+ }
+ spin_unlock_irqrestore(&rpdev->mu_lock, flags);
+
+ schedule_delayed_work(&(rpdev->rpmsg_work), 0);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int imx_rpmsg_mu_init(struct imx_rpmsg_vproc *rpdev)
+{
+ int ret = 0;
+
+ /*
+ * bit26 is used by rpmsg channels.
+ * bit0 of MX7ULP_MU_CR used to let m4 to know MU is ready now
+ */
+ MU_Init(rpdev->mu_base);
+ if (rpdev->variant == IMX7ULP) {
+ MU_EnableRxFullInt(rpdev->mu_base, 1);
+ ret = MU_SetFn(rpdev->mu_base, 1);
+ } else {
+ MU_EnableRxFullInt(rpdev->mu_base, 1);
+ }
+
+ return ret;
+}
+static int imx_rpmsg_probe(struct platform_device *pdev)
+{
+ int core_id, j, ret = 0;
+ u32 irq;
+ struct device_node *np_mu;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = pdev->dev.of_node;
+ struct imx_rpmsg_vproc *rpdev;
+
+ if (of_property_read_u32(np, "multi-core-id", &core_id))
+ core_id = 0;
+ rpdev = &imx_rpmsg_vprocs[core_id];
+ rpdev->core_id = core_id;
+ rpdev->variant = (enum imx_rpmsg_variants)of_device_get_match_data(dev);
+
+ /* Initialize the mu unit used by rpmsg */
+ if (rpdev->core_id == 1)
+ np_mu = of_find_compatible_node(NULL, NULL,
+ "fsl,imx-mu-rpmsg1");
+ else
+ np_mu = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-mu");
+ if (!np_mu) {
+ pr_info("Cannot find MU-RPMSG entry in device tree\n");
+ return -EINVAL;
+ }
+ rpdev->mu_base = of_iomap(np_mu, 0);
+ WARN_ON(!rpdev->mu_base);
+
+ spin_lock_init(&rpdev->mu_lock);
+
+ if (rpdev->variant == IMX7ULP)
+ irq = of_irq_get(np_mu, 1);
+ else
+ irq = of_irq_get(np_mu, 0);
+
+ ret = request_irq(irq, imx_mu_rpmsg_isr,
+ IRQF_EARLY_RESUME | IRQF_SHARED,
+ "imx-mu-rpmsg", rpdev);
+ if (ret) {
+ pr_err("%s: register interrupt %d failed, rc %d\n",
+ __func__, irq, ret);
+ return ret;
+ }
+
+ if (rpdev->variant == IMX7D || rpdev->variant == IMX8QXP
+ || rpdev->variant == IMX8QM) {
+ rpdev->mu_clk = of_clk_get(np_mu, 0);
+ if (IS_ERR(rpdev->mu_clk)) {
+ pr_err("mu clock source missing or invalid\n");
+ return PTR_ERR(rpdev->mu_clk);
+ }
+ ret = clk_prepare_enable(rpdev->mu_clk);
+ if (ret) {
+ pr_err("unable to enable mu clock\n");
+ return ret;
+ }
+ } else {
+ rpdev->mu_clk = NULL;
+ }
+
+ ret = imx_rpmsg_mu_init(rpdev);
+ if (ret) {
+ pr_err("unable to initialize mu module.\n");
+ return ret;
+ }
+ INIT_DELAYED_WORK(&(rpdev->rpmsg_work), rpmsg_work_handler);
+ BLOCKING_INIT_NOTIFIER_HEAD(&(rpdev->notifier));
+
+ pr_info("MU is ready for cross core communication!\n");
+
+ ret = of_property_read_u32(np, "vdev-nums", &rpdev->vdev_nums);
+ if (ret)
+ rpdev->vdev_nums = 1;
+ if (rpdev->vdev_nums > MAX_VDEV_NUMS) {
+ pr_err("vdev-nums exceed the max %d\n", MAX_VDEV_NUMS);
+ return -EINVAL;
+ }
+
+ if (!strcmp(rpdev->rproc_name, "m4")) {
+ ret = set_vring_phy_buf(pdev, rpdev,
+ rpdev->vdev_nums);
+ if (ret) {
+ pr_err("No vring buffer.\n");
+ return -ENOMEM;
+ }
+ } else {
+ pr_err("No remote m4 processor.\n");
+ return -ENODEV;
+ }
+
+ for (j = 0; j < rpdev->vdev_nums; j++) {
+ pr_debug("%s rpdev%d vdev%d: vring0 0x%x, vring1 0x%x\n",
+ __func__, rpdev->core_id, rpdev->vdev_nums,
+ rpdev->ivdev[j].vring[0],
+ rpdev->ivdev[j].vring[1]);
+ rpdev->ivdev[j].vdev.id.device = VIRTIO_ID_RPMSG;
+ rpdev->ivdev[j].vdev.config = &imx_rpmsg_config_ops;
+ rpdev->ivdev[j].vdev.dev.parent = &pdev->dev;
+ rpdev->ivdev[j].vdev.dev.release = imx_rpmsg_vproc_release;
+ rpdev->ivdev[j].base_vq_id = j * 2;
+
+ ret = register_virtio_device(&rpdev->ivdev[j].vdev);
+ if (ret) {
+ pr_err("%s failed to register rpdev: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ }
+ platform_set_drvdata(pdev, rpdev);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int imx_rpmsg_suspend(struct device *dev)
+{
+ struct imx_rpmsg_vproc *rpdev = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(rpdev->mu_clk);
+
+ return 0;
+}
+
+static int imx_rpmsg_resume(struct device *dev)
+{
+ struct imx_rpmsg_vproc *rpdev = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(rpdev->mu_clk);
+ if (ret) {
+ pr_err("unable to enable mu clock\n");
+ return ret;
+ }
+
+ return imx_rpmsg_mu_init(rpdev);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(imx_rpmsg_pm_ops, imx_rpmsg_suspend, imx_rpmsg_resume);
+
+static struct platform_driver imx_rpmsg_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "imx-rpmsg",
+ .of_match_table = imx_rpmsg_dt_ids,
+ .pm = &imx_rpmsg_pm_ops,
+ },
+ .probe = imx_rpmsg_probe,
+};
+
+static int __init imx_rpmsg_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&imx_rpmsg_driver);
+ if (ret)
+ pr_err("Unable to initialize rpmsg driver\n");
+ else
+ pr_info("imx rpmsg driver is registered.\n");
+
+ return ret;
+}
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("iMX remote processor messaging virtio device");
+MODULE_LICENSE("GPL v2");
+subsys_initcall(imx_rpmsg_init);
diff --git a/drivers/rpmsg/imx_rpmsg_pingpong.c b/drivers/rpmsg/imx_rpmsg_pingpong.c
new file mode 100644
index 000000000000..3aa545fcfe14
--- /dev/null
+++ b/drivers/rpmsg/imx_rpmsg_pingpong.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ *
+ * derived from the omap-rpmsg implementation.
+ * Remote processor messaging transport - pingpong driver
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/virtio.h>
+#include <linux/rpmsg.h>
+
+#define MSG "hello world!"
+static unsigned int rpmsg_pingpong;
+
+static int rpmsg_pingpong_cb(struct rpmsg_device *rpdev, void *data, int len,
+ void *priv, u32 src)
+{
+ int err;
+
+ /* reply */
+ rpmsg_pingpong = *(unsigned int *)data;
+ pr_info("get %d (src: 0x%x)\n", rpmsg_pingpong, src);
+
+ /* pingpongs should not live forever */
+ if (rpmsg_pingpong > 100) {
+ dev_info(&rpdev->dev, "goodbye!\n");
+ return 0;
+ }
+ rpmsg_pingpong++;
+ err = rpmsg_sendto(rpdev->ept, (void *)(&rpmsg_pingpong), 4, src);
+
+ if (err)
+ dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", err);
+
+ return err;
+}
+
+static int rpmsg_pingpong_probe(struct rpmsg_device *rpdev)
+{
+ int err;
+
+ dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
+ rpdev->src, rpdev->dst);
+
+ /*
+ * send a message to our remote processor, and tell remote
+ * processor about this channel
+ */
+ err = rpmsg_send(rpdev->ept, MSG, strlen(MSG));
+ if (err) {
+ dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", err);
+ return err;
+ }
+
+ rpmsg_pingpong = 0;
+ err = rpmsg_sendto(rpdev->ept, (void *)(&rpmsg_pingpong), 4, rpdev->dst);
+ if (err) {
+ dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static void rpmsg_pingpong_remove(struct rpmsg_device *rpdev)
+{
+ dev_info(&rpdev->dev, "rpmsg pingpong driver is removed\n");
+}
+
+static struct rpmsg_device_id rpmsg_driver_pingpong_id_table[] = {
+ { .name = "rpmsg-openamp-demo-channel" },
+ { .name = "rpmsg-openamp-demo-channel-1" },
+ { },
+};
+MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_pingpong_id_table);
+
+static struct rpmsg_driver rpmsg_pingpong_driver = {
+ .drv.name = KBUILD_MODNAME,
+ .drv.owner = THIS_MODULE,
+ .id_table = rpmsg_driver_pingpong_id_table,
+ .probe = rpmsg_pingpong_probe,
+ .callback = rpmsg_pingpong_cb,
+ .remove = rpmsg_pingpong_remove,
+};
+
+static int __init init(void)
+{
+ return register_rpmsg_driver(&rpmsg_pingpong_driver);
+}
+
+static void __exit fini(void)
+{
+ unregister_rpmsg_driver(&rpmsg_pingpong_driver);
+}
+module_init(init);
+module_exit(fini);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("iMX virtio remote processor messaging pingpong driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rpmsg/imx_rpmsg_tty.c b/drivers/rpmsg/imx_rpmsg_tty.c
new file mode 100644
index 000000000000..db200e03af3a
--- /dev/null
+++ b/drivers/rpmsg/imx_rpmsg_tty.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright (C) 2017 NXP
+ *
+ * derived from the omap-rpmsg implementation.
+ * Remote processor messaging transport - tty driver
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rpmsg.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/virtio.h>
+
+/* this needs to be less then (RPMSG_BUF_SIZE - sizeof(struct rpmsg_hdr)) */
+#define RPMSG_MAX_SIZE 256
+#define MSG "hello world!"
+
+/*
+ * struct rpmsgtty_port - Wrapper struct for imx rpmsg tty port.
+ * @port: TTY port data
+ */
+struct rpmsgtty_port {
+ struct tty_port port;
+ spinlock_t rx_lock;
+ struct rpmsg_device *rpdev;
+ struct tty_driver *rpmsgtty_driver;
+};
+
+static int rpmsg_tty_cb(struct rpmsg_device *rpdev, void *data, int len,
+ void *priv, u32 src)
+{
+ int space;
+ unsigned char *cbuf;
+ struct rpmsgtty_port *cport = dev_get_drvdata(&rpdev->dev);
+
+ /* flush the recv-ed none-zero data to tty node */
+ if (len == 0)
+ return 0;
+
+ dev_dbg(&rpdev->dev, "msg(<- src 0x%x) len %d\n", src, len);
+
+ print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
+ data, len, true);
+
+ spin_lock_bh(&cport->rx_lock);
+ space = tty_prepare_flip_string(&cport->port, &cbuf, len);
+ if (space <= 0) {
+ dev_err(&rpdev->dev, "No memory for tty_prepare_flip_string\n");
+ spin_unlock_bh(&cport->rx_lock);
+ return -ENOMEM;
+ }
+
+ memcpy(cbuf, data, len);
+ tty_flip_buffer_push(&cport->port);
+ spin_unlock_bh(&cport->rx_lock);
+
+ return 0;
+}
+
+static struct tty_port_operations rpmsgtty_port_ops = { };
+
+static int rpmsgtty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ struct rpmsgtty_port *cport = driver->driver_state;
+
+ return tty_port_install(&cport->port, driver, tty);
+}
+
+static int rpmsgtty_open(struct tty_struct *tty, struct file *filp)
+{
+ return tty_port_open(tty->port, tty, filp);
+}
+
+static void rpmsgtty_close(struct tty_struct *tty, struct file *filp)
+{
+ return tty_port_close(tty->port, tty, filp);
+}
+
+static int rpmsgtty_write(struct tty_struct *tty, const unsigned char *buf,
+ int total)
+{
+ int count, ret = 0;
+ const unsigned char *tbuf;
+ struct rpmsgtty_port *rptty_port = container_of(tty->port,
+ struct rpmsgtty_port, port);
+ struct rpmsg_device *rpdev = rptty_port->rpdev;
+
+ if (NULL == buf) {
+ pr_err("buf shouldn't be null.\n");
+ return -ENOMEM;
+ }
+
+ count = total;
+ tbuf = buf;
+ do {
+ /* send a message to our remote processor */
+ ret = rpmsg_send(rpdev->ept, (void *)tbuf,
+ count > RPMSG_MAX_SIZE ? RPMSG_MAX_SIZE : count);
+ if (ret) {
+ dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
+ return ret;
+ }
+
+ if (count > RPMSG_MAX_SIZE) {
+ count -= RPMSG_MAX_SIZE;
+ tbuf += RPMSG_MAX_SIZE;
+ } else {
+ count = 0;
+ }
+ } while (count > 0);
+
+ return total;
+}
+
+static int rpmsgtty_write_room(struct tty_struct *tty)
+{
+ /* report the space in the rpmsg buffer */
+ return RPMSG_MAX_SIZE;
+}
+
+static const struct tty_operations imxrpmsgtty_ops = {
+ .install = rpmsgtty_install,
+ .open = rpmsgtty_open,
+ .close = rpmsgtty_close,
+ .write = rpmsgtty_write,
+ .write_room = rpmsgtty_write_room,
+};
+
+static int rpmsg_tty_probe(struct rpmsg_device *rpdev)
+{
+ int ret;
+ char name[80];
+ struct rpmsgtty_port *cport;
+ struct tty_driver *rpmsgtty_driver;
+
+ dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
+ rpdev->src, rpdev->dst);
+
+ cport = devm_kzalloc(&rpdev->dev, sizeof(*cport), GFP_KERNEL);
+ if (!cport)
+ return -ENOMEM;
+
+ rpmsgtty_driver = tty_alloc_driver(1, TTY_DRIVER_UNNUMBERED_NODE);
+ if (IS_ERR(rpmsgtty_driver)) {
+ kfree(cport);
+ return PTR_ERR(rpmsgtty_driver);
+ }
+
+ rpmsgtty_driver->driver_name = "rpmsg_tty";
+ sprintf(name, "ttyRPMSG%d", rpdev->dst);
+ rpmsgtty_driver->name = name;
+ rpmsgtty_driver->major = UNNAMED_MAJOR;
+ rpmsgtty_driver->minor_start = 0;
+ rpmsgtty_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+ rpmsgtty_driver->init_termios = tty_std_termios;
+
+ tty_set_operations(rpmsgtty_driver, &imxrpmsgtty_ops);
+
+ tty_port_init(&cport->port);
+ cport->port.ops = &rpmsgtty_port_ops;
+ spin_lock_init(&cport->rx_lock);
+ cport->port.low_latency = cport->port.flags | ASYNC_LOW_LATENCY;
+ cport->rpdev = rpdev;
+ dev_set_drvdata(&rpdev->dev, cport);
+ rpmsgtty_driver->driver_state = cport;
+ cport->rpmsgtty_driver = rpmsgtty_driver;
+
+ ret = tty_register_driver(cport->rpmsgtty_driver);
+ if (ret < 0) {
+ pr_err("Couldn't install rpmsg tty driver: ret %d\n", ret);
+ goto error1;
+ } else {
+ pr_info("Install rpmsg tty driver!\n");
+ }
+
+ /*
+ * send a message to our remote processor, and tell remote
+ * processor about this channel
+ */
+ ret = rpmsg_send(rpdev->ept, MSG, strlen(MSG));
+ if (ret) {
+ dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ tty_unregister_driver(cport->rpmsgtty_driver);
+error1:
+ put_tty_driver(cport->rpmsgtty_driver);
+ tty_port_destroy(&cport->port);
+ cport->rpmsgtty_driver = NULL;
+ kfree(cport);
+
+ return ret;
+}
+
+static void rpmsg_tty_remove(struct rpmsg_device *rpdev)
+{
+ struct rpmsgtty_port *cport = dev_get_drvdata(&rpdev->dev);
+
+ dev_info(&rpdev->dev, "rpmsg tty driver is removed\n");
+
+ tty_unregister_driver(cport->rpmsgtty_driver);
+ put_tty_driver(cport->rpmsgtty_driver);
+ tty_port_destroy(&cport->port);
+ cport->rpmsgtty_driver = NULL;
+}
+
+static struct rpmsg_device_id rpmsg_driver_tty_id_table[] = {
+ { .name = "rpmsg-virtual-tty-channel-1" },
+ { .name = "rpmsg-virtual-tty-channel" },
+ { .name = "rpmsg-openamp-demo-channel" },
+ { },
+};
+MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_tty_id_table);
+
+static struct rpmsg_driver rpmsg_tty_driver = {
+ .drv.name = KBUILD_MODNAME,
+ .drv.owner = THIS_MODULE,
+ .id_table = rpmsg_driver_tty_id_table,
+ .probe = rpmsg_tty_probe,
+ .callback = rpmsg_tty_cb,
+ .remove = rpmsg_tty_remove,
+};
+
+static int __init init(void)
+{
+ return register_rpmsg_driver(&rpmsg_tty_driver);
+}
+
+static void __exit fini(void)
+{
+ unregister_rpmsg_driver(&rpmsg_tty_driver);
+}
+module_init(init);
+module_exit(fini);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("iMX virtio remote processor messaging tty driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rpmsg/rpmsg_char.c b/drivers/rpmsg/rpmsg_char.c
new file mode 100644
index 000000000000..0b5d0d342ab0
--- /dev/null
+++ b/drivers/rpmsg/rpmsg_char.c
@@ -0,0 +1,584 @@
+/*
+ * Copyright (c) 2016, Linaro Ltd.
+ * Copyright (c) 2012, Michal Simek <monstr@monstr.eu>
+ * Copyright (c) 2012, PetaLogix
+ * Copyright (c) 2011, Texas Instruments, Inc.
+ * Copyright (c) 2011, Google, Inc.
+ *
+ * Based on rpmsg performance statistics driver by Michal Simek, which in turn
+ * was based on TI & Google OMX rpmsg 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 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/rpmsg.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <uapi/linux/rpmsg.h>
+
+#include "rpmsg_internal.h"
+
+#define RPMSG_DEV_MAX (MINORMASK + 1)
+
+static dev_t rpmsg_major;
+static struct class *rpmsg_class;
+
+static DEFINE_IDA(rpmsg_ctrl_ida);
+static DEFINE_IDA(rpmsg_ept_ida);
+static DEFINE_IDA(rpmsg_minor_ida);
+
+#define dev_to_eptdev(dev) container_of(dev, struct rpmsg_eptdev, dev)
+#define cdev_to_eptdev(i_cdev) container_of(i_cdev, struct rpmsg_eptdev, cdev)
+
+#define dev_to_ctrldev(dev) container_of(dev, struct rpmsg_ctrldev, dev)
+#define cdev_to_ctrldev(i_cdev) container_of(i_cdev, struct rpmsg_ctrldev, cdev)
+
+/**
+ * struct rpmsg_ctrldev - control device for instantiating endpoint devices
+ * @rpdev: underlaying rpmsg device
+ * @cdev: cdev for the ctrl device
+ * @dev: device for the ctrl device
+ */
+struct rpmsg_ctrldev {
+ struct rpmsg_device *rpdev;
+ struct cdev cdev;
+ struct device dev;
+};
+
+/**
+ * struct rpmsg_eptdev - endpoint device context
+ * @dev: endpoint device
+ * @cdev: cdev for the endpoint device
+ * @rpdev: underlaying rpmsg device
+ * @chinfo: info used to open the endpoint
+ * @ept_lock: synchronization of @ept modifications
+ * @ept: rpmsg endpoint reference, when open
+ * @queue_lock: synchronization of @queue operations
+ * @queue: incoming message queue
+ * @readq: wait object for incoming queue
+ */
+struct rpmsg_eptdev {
+ struct device dev;
+ struct cdev cdev;
+
+ struct rpmsg_device *rpdev;
+ struct rpmsg_channel_info chinfo;
+
+ struct mutex ept_lock;
+ struct rpmsg_endpoint *ept;
+
+ spinlock_t queue_lock;
+ struct sk_buff_head queue;
+ wait_queue_head_t readq;
+};
+
+static int rpmsg_eptdev_destroy(struct device *dev, void *data)
+{
+ struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev);
+
+ mutex_lock(&eptdev->ept_lock);
+ if (eptdev->ept) {
+ rpmsg_destroy_ept(eptdev->ept);
+ eptdev->ept = NULL;
+ }
+ mutex_unlock(&eptdev->ept_lock);
+
+ /* wake up any blocked readers */
+ wake_up_interruptible(&eptdev->readq);
+
+ device_del(&eptdev->dev);
+ put_device(&eptdev->dev);
+
+ return 0;
+}
+
+static int rpmsg_ept_cb(struct rpmsg_device *rpdev, void *buf, int len,
+ void *priv, u32 addr)
+{
+ struct rpmsg_eptdev *eptdev = priv;
+ struct sk_buff *skb;
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ memcpy(skb_put(skb, len), buf, len);
+
+ spin_lock(&eptdev->queue_lock);
+ skb_queue_tail(&eptdev->queue, skb);
+ spin_unlock(&eptdev->queue_lock);
+
+ /* wake up any blocking processes, waiting for new data */
+ wake_up_interruptible(&eptdev->readq);
+
+ return 0;
+}
+
+static int rpmsg_eptdev_open(struct inode *inode, struct file *filp)
+{
+ struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev);
+ struct rpmsg_endpoint *ept;
+ struct rpmsg_device *rpdev = eptdev->rpdev;
+ struct device *dev = &eptdev->dev;
+
+ get_device(dev);
+
+ ept = rpmsg_create_ept(rpdev, rpmsg_ept_cb, eptdev, eptdev->chinfo);
+ if (!ept) {
+ dev_err(dev, "failed to open %s\n", eptdev->chinfo.name);
+ put_device(dev);
+ return -EINVAL;
+ }
+
+ eptdev->ept = ept;
+ filp->private_data = eptdev;
+
+ return 0;
+}
+
+static int rpmsg_eptdev_release(struct inode *inode, struct file *filp)
+{
+ struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev);
+ struct device *dev = &eptdev->dev;
+ struct sk_buff *skb;
+
+ /* Close the endpoint, if it's not already destroyed by the parent */
+ mutex_lock(&eptdev->ept_lock);
+ if (eptdev->ept) {
+ rpmsg_destroy_ept(eptdev->ept);
+ eptdev->ept = NULL;
+ }
+ mutex_unlock(&eptdev->ept_lock);
+
+ /* Discard all SKBs */
+ while (!skb_queue_empty(&eptdev->queue)) {
+ skb = skb_dequeue(&eptdev->queue);
+ kfree_skb(skb);
+ }
+
+ put_device(dev);
+
+ return 0;
+}
+
+static ssize_t rpmsg_eptdev_read(struct file *filp, char __user *buf,
+ size_t len, loff_t *f_pos)
+{
+ struct rpmsg_eptdev *eptdev = filp->private_data;
+ unsigned long flags;
+ struct sk_buff *skb;
+ int use;
+
+ if (!eptdev->ept)
+ return -EPIPE;
+
+ spin_lock_irqsave(&eptdev->queue_lock, flags);
+
+ /* Wait for data in the queue */
+ if (skb_queue_empty(&eptdev->queue)) {
+ spin_unlock_irqrestore(&eptdev->queue_lock, flags);
+
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ /* Wait until we get data or the endpoint goes away */
+ if (wait_event_interruptible(eptdev->readq,
+ !skb_queue_empty(&eptdev->queue) ||
+ !eptdev->ept))
+ return -ERESTARTSYS;
+
+ /* We lost the endpoint while waiting */
+ if (!eptdev->ept)
+ return -EPIPE;
+
+ spin_lock_irqsave(&eptdev->queue_lock, flags);
+ }
+
+ skb = skb_dequeue(&eptdev->queue);
+ spin_unlock_irqrestore(&eptdev->queue_lock, flags);
+ if (!skb)
+ return -EFAULT;
+
+ use = min_t(size_t, len, skb->len);
+ if (copy_to_user(buf, skb->data, use))
+ use = -EFAULT;
+
+ kfree_skb(skb);
+
+ return use;
+}
+
+static ssize_t rpmsg_eptdev_write(struct file *filp, const char __user *buf,
+ size_t len, loff_t *f_pos)
+{
+ struct rpmsg_eptdev *eptdev = filp->private_data;
+ void *kbuf;
+ int ret;
+
+ kbuf = memdup_user(buf, len);
+ if (IS_ERR(kbuf))
+ return PTR_ERR(kbuf);
+
+ if (mutex_lock_interruptible(&eptdev->ept_lock)) {
+ ret = -ERESTARTSYS;
+ goto free_kbuf;
+ }
+
+ if (!eptdev->ept) {
+ ret = -EPIPE;
+ goto unlock_eptdev;
+ }
+
+ if (filp->f_flags & O_NONBLOCK)
+ ret = rpmsg_trysend(eptdev->ept, kbuf, len);
+ else
+ ret = rpmsg_send(eptdev->ept, kbuf, len);
+
+unlock_eptdev:
+ mutex_unlock(&eptdev->ept_lock);
+
+free_kbuf:
+ kfree(kbuf);
+ return ret < 0 ? ret : len;
+}
+
+static unsigned int rpmsg_eptdev_poll(struct file *filp, poll_table *wait)
+{
+ struct rpmsg_eptdev *eptdev = filp->private_data;
+ unsigned int mask = 0;
+
+ if (!eptdev->ept)
+ return POLLERR;
+
+ poll_wait(filp, &eptdev->readq, wait);
+
+ if (!skb_queue_empty(&eptdev->queue))
+ mask |= POLLIN | POLLRDNORM;
+
+ mask |= rpmsg_poll(eptdev->ept, filp, wait);
+
+ return mask;
+}
+
+static long rpmsg_eptdev_ioctl(struct file *fp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct rpmsg_eptdev *eptdev = fp->private_data;
+
+ if (cmd != RPMSG_DESTROY_EPT_IOCTL)
+ return -EINVAL;
+
+ return rpmsg_eptdev_destroy(&eptdev->dev, NULL);
+}
+
+static const struct file_operations rpmsg_eptdev_fops = {
+ .owner = THIS_MODULE,
+ .open = rpmsg_eptdev_open,
+ .release = rpmsg_eptdev_release,
+ .read = rpmsg_eptdev_read,
+ .write = rpmsg_eptdev_write,
+ .poll = rpmsg_eptdev_poll,
+ .unlocked_ioctl = rpmsg_eptdev_ioctl,
+};
+
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct rpmsg_eptdev *eptdev = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", eptdev->chinfo.name);
+}
+static DEVICE_ATTR_RO(name);
+
+static ssize_t src_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct rpmsg_eptdev *eptdev = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", eptdev->chinfo.src);
+}
+static DEVICE_ATTR_RO(src);
+
+static ssize_t dst_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct rpmsg_eptdev *eptdev = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", eptdev->chinfo.dst);
+}
+static DEVICE_ATTR_RO(dst);
+
+static struct attribute *rpmsg_eptdev_attrs[] = {
+ &dev_attr_name.attr,
+ &dev_attr_src.attr,
+ &dev_attr_dst.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(rpmsg_eptdev);
+
+static void rpmsg_eptdev_release_device(struct device *dev)
+{
+ struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev);
+
+ ida_simple_remove(&rpmsg_ept_ida, dev->id);
+ ida_simple_remove(&rpmsg_minor_ida, MINOR(eptdev->dev.devt));
+ cdev_del(&eptdev->cdev);
+ kfree(eptdev);
+}
+
+static int rpmsg_eptdev_create(struct rpmsg_ctrldev *ctrldev,
+ struct rpmsg_channel_info chinfo)
+{
+ struct rpmsg_device *rpdev = ctrldev->rpdev;
+ struct rpmsg_eptdev *eptdev;
+ struct device *dev;
+ int ret;
+
+ eptdev = kzalloc(sizeof(*eptdev), GFP_KERNEL);
+ if (!eptdev)
+ return -ENOMEM;
+
+ dev = &eptdev->dev;
+ eptdev->rpdev = rpdev;
+ eptdev->chinfo = chinfo;
+
+ mutex_init(&eptdev->ept_lock);
+ spin_lock_init(&eptdev->queue_lock);
+ skb_queue_head_init(&eptdev->queue);
+ init_waitqueue_head(&eptdev->readq);
+
+ device_initialize(dev);
+ dev->class = rpmsg_class;
+ dev->parent = &ctrldev->dev;
+ dev->groups = rpmsg_eptdev_groups;
+ dev_set_drvdata(dev, eptdev);
+
+ cdev_init(&eptdev->cdev, &rpmsg_eptdev_fops);
+ eptdev->cdev.owner = THIS_MODULE;
+
+ ret = ida_simple_get(&rpmsg_minor_ida, 0, RPMSG_DEV_MAX, GFP_KERNEL);
+ if (ret < 0)
+ goto free_eptdev;
+ dev->devt = MKDEV(MAJOR(rpmsg_major), ret);
+
+ ret = ida_simple_get(&rpmsg_ept_ida, 0, 0, GFP_KERNEL);
+ if (ret < 0)
+ goto free_minor_ida;
+ dev->id = ret;
+ dev_set_name(dev, "rpmsg%d", ret);
+
+ ret = cdev_add(&eptdev->cdev, dev->devt, 1);
+ if (ret)
+ goto free_ept_ida;
+
+ /* We can now rely on the release function for cleanup */
+ dev->release = rpmsg_eptdev_release_device;
+
+ ret = device_add(dev);
+ if (ret) {
+ dev_err(dev, "device_add failed: %d\n", ret);
+ put_device(dev);
+ }
+
+ return ret;
+
+free_ept_ida:
+ ida_simple_remove(&rpmsg_ept_ida, dev->id);
+free_minor_ida:
+ ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
+free_eptdev:
+ put_device(dev);
+ kfree(eptdev);
+
+ return ret;
+}
+
+static int rpmsg_ctrldev_open(struct inode *inode, struct file *filp)
+{
+ struct rpmsg_ctrldev *ctrldev = cdev_to_ctrldev(inode->i_cdev);
+
+ get_device(&ctrldev->dev);
+ filp->private_data = ctrldev;
+
+ return 0;
+}
+
+static int rpmsg_ctrldev_release(struct inode *inode, struct file *filp)
+{
+ struct rpmsg_ctrldev *ctrldev = cdev_to_ctrldev(inode->i_cdev);
+
+ put_device(&ctrldev->dev);
+
+ return 0;
+}
+
+static long rpmsg_ctrldev_ioctl(struct file *fp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct rpmsg_ctrldev *ctrldev = fp->private_data;
+ void __user *argp = (void __user *)arg;
+ struct rpmsg_endpoint_info eptinfo;
+ struct rpmsg_channel_info chinfo;
+
+ if (cmd != RPMSG_CREATE_EPT_IOCTL)
+ return -EINVAL;
+
+ if (copy_from_user(&eptinfo, argp, sizeof(eptinfo)))
+ return -EFAULT;
+
+ memcpy(chinfo.name, eptinfo.name, RPMSG_NAME_SIZE);
+ chinfo.name[RPMSG_NAME_SIZE-1] = '\0';
+ chinfo.src = eptinfo.src;
+ chinfo.dst = eptinfo.dst;
+
+ return rpmsg_eptdev_create(ctrldev, chinfo);
+};
+
+static const struct file_operations rpmsg_ctrldev_fops = {
+ .owner = THIS_MODULE,
+ .open = rpmsg_ctrldev_open,
+ .release = rpmsg_ctrldev_release,
+ .unlocked_ioctl = rpmsg_ctrldev_ioctl,
+};
+
+static void rpmsg_ctrldev_release_device(struct device *dev)
+{
+ struct rpmsg_ctrldev *ctrldev = dev_to_ctrldev(dev);
+
+ ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
+ ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
+ cdev_del(&ctrldev->cdev);
+ kfree(ctrldev);
+}
+
+static int rpmsg_chrdev_probe(struct rpmsg_device *rpdev)
+{
+ struct rpmsg_ctrldev *ctrldev;
+ struct device *dev;
+ int ret;
+
+ ctrldev = kzalloc(sizeof(*ctrldev), GFP_KERNEL);
+ if (!ctrldev)
+ return -ENOMEM;
+
+ ctrldev->rpdev = rpdev;
+
+ dev = &ctrldev->dev;
+ device_initialize(dev);
+ dev->parent = &rpdev->dev;
+ dev->class = rpmsg_class;
+
+ cdev_init(&ctrldev->cdev, &rpmsg_ctrldev_fops);
+ ctrldev->cdev.owner = THIS_MODULE;
+
+ ret = ida_simple_get(&rpmsg_minor_ida, 0, RPMSG_DEV_MAX, GFP_KERNEL);
+ if (ret < 0)
+ goto free_ctrldev;
+ dev->devt = MKDEV(MAJOR(rpmsg_major), ret);
+
+ ret = ida_simple_get(&rpmsg_ctrl_ida, 0, 0, GFP_KERNEL);
+ if (ret < 0)
+ goto free_minor_ida;
+ dev->id = ret;
+ dev_set_name(&ctrldev->dev, "rpmsg_ctrl%d", ret);
+
+ ret = cdev_add(&ctrldev->cdev, dev->devt, 1);
+ if (ret)
+ goto free_ctrl_ida;
+
+ /* We can now rely on the release function for cleanup */
+ dev->release = rpmsg_ctrldev_release_device;
+
+ ret = device_add(dev);
+ if (ret) {
+ dev_err(&rpdev->dev, "device_add failed: %d\n", ret);
+ put_device(dev);
+ }
+
+ dev_set_drvdata(&rpdev->dev, ctrldev);
+
+ return ret;
+
+free_ctrl_ida:
+ ida_simple_remove(&rpmsg_ctrl_ida, dev->id);
+free_minor_ida:
+ ida_simple_remove(&rpmsg_minor_ida, MINOR(dev->devt));
+free_ctrldev:
+ put_device(dev);
+ kfree(ctrldev);
+
+ return ret;
+}
+
+static void rpmsg_chrdev_remove(struct rpmsg_device *rpdev)
+{
+ struct rpmsg_ctrldev *ctrldev = dev_get_drvdata(&rpdev->dev);
+ int ret;
+
+ /* Destroy all endpoints */
+ ret = device_for_each_child(&ctrldev->dev, NULL, rpmsg_eptdev_destroy);
+ if (ret)
+ dev_warn(&rpdev->dev, "failed to nuke endpoints: %d\n", ret);
+
+ device_del(&ctrldev->dev);
+ put_device(&ctrldev->dev);
+}
+
+static struct rpmsg_driver rpmsg_chrdev_driver = {
+ .probe = rpmsg_chrdev_probe,
+ .remove = rpmsg_chrdev_remove,
+ .drv = {
+ .name = "rpmsg_chrdev",
+ },
+};
+
+static int rpmsg_char_init(void)
+{
+ int ret;
+
+ ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg");
+ if (ret < 0) {
+ pr_err("rpmsg: failed to allocate char dev region\n");
+ return ret;
+ }
+
+ rpmsg_class = class_create(THIS_MODULE, "rpmsg");
+ if (IS_ERR(rpmsg_class)) {
+ pr_err("failed to create rpmsg class\n");
+ unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
+ return PTR_ERR(rpmsg_class);
+ }
+
+ ret = register_rpmsg_driver(&rpmsg_chrdev_driver);
+ if (ret < 0) {
+ pr_err("rpmsgchr: failed to register rpmsg driver\n");
+ class_destroy(rpmsg_class);
+ unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
+ }
+
+ return ret;
+}
+postcore_initcall(rpmsg_char_init);
+
+static void rpmsg_chrdev_exit(void)
+{
+ unregister_rpmsg_driver(&rpmsg_chrdev_driver);
+ class_destroy(rpmsg_class);
+ unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
+}
+module_exit(rpmsg_chrdev_exit);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
index e0a629eaceab..028190080eb3 100644
--- a/drivers/rpmsg/rpmsg_core.c
+++ b/drivers/rpmsg/rpmsg_core.c
@@ -315,6 +315,9 @@ static int rpmsg_dev_match(struct device *dev, struct device_driver *drv)
const struct rpmsg_device_id *ids = rpdrv->id_table;
unsigned int i;
+ if (rpdev->driver_override)
+ return !strcmp(rpdev->driver_override, drv->name);
+
if (ids)
for (i = 0; ids[i].name[0]; i++)
if (rpmsg_id_match(rpdev, &ids[i]))
diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h
index 8075a20f919b..a34e519ea3dc 100644
--- a/drivers/rpmsg/rpmsg_internal.h
+++ b/drivers/rpmsg/rpmsg_internal.h
@@ -79,4 +79,19 @@ int rpmsg_unregister_device(struct device *parent,
struct device *rpmsg_find_device(struct device *parent,
struct rpmsg_channel_info *chinfo);
+/**
+ * rpmsg_chrdev_register_device() - register chrdev device based on rpdev
+ * @rpdev: prepared rpdev to be used for creating endpoints
+ *
+ * This function wraps rpmsg_register_device() preparing the rpdev for use as
+ * basis for the rpmsg chrdev.
+ */
+static inline int rpmsg_chrdev_register_device(struct rpmsg_device *rpdev)
+{
+ strcpy(rpdev->id.name, "rpmsg_chrdev");
+ rpdev->driver_override = "rpmsg_chrdev";
+
+ return rpmsg_register_device(rpdev);
+}
+
#endif
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 3090b0d3072f..15a8fa77c9fc 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -495,6 +495,27 @@ static void rpmsg_downref_sleepers(struct virtproc_info *vrp)
mutex_unlock(&vrp->tx_lock);
}
+static int sg_init_one_full(struct scatterlist *sg, const void *buf,
+ unsigned int buflen)
+{
+ const bool vmalloced_buf = is_vmalloc_addr(buf);
+ struct page *vm_page;
+
+ /* get page for high memory */
+ if (vmalloced_buf) {
+ vm_page = vmalloc_to_page(buf);
+ if (!vm_page)
+ return -ENOMEM;
+
+ sg_init_table(sg, 1);
+ sg_set_page(sg, vm_page, RPMSG_BUF_SIZE,
+ offset_in_page(buf));
+ } else
+ sg_init_one(sg, buf, buflen);
+
+ return 0;
+}
+
/**
* rpmsg_send_offchannel_raw() - send a message across to the remote processor
* @rpdev: the rpmsg channel
@@ -604,7 +625,11 @@ static int rpmsg_send_offchannel_raw(struct rpmsg_device *rpdev,
msg, sizeof(*msg) + msg->len, true);
#endif
- sg_init_one(&sg, msg, sizeof(*msg) + len);
+ err = sg_init_one_full(&sg, msg, sizeof(*msg) + len);
+ if (err) {
+ dev_err(dev, "virtqueue_add_outbuf sg_init failed: %d\n", err);
+ return err;
+ }
mutex_lock(&vrp->tx_lock);
@@ -729,7 +754,11 @@ static int rpmsg_recv_single(struct virtproc_info *vrp, struct device *dev,
dev_warn(dev, "msg received with no recipient\n");
/* publish the real size of the buffer */
- sg_init_one(&sg, msg, RPMSG_BUF_SIZE);
+ err = sg_init_one_full(&sg, msg, RPMSG_BUF_SIZE);
+ if (err) {
+ dev_err(dev, "rpmsg_recv_done sg_init failed: %d\n", err);
+ return err;
+ }
/* add the buffer back to the remote processor's virtqueue */
err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, msg, GFP_KERNEL);
@@ -911,7 +940,11 @@ static int rpmsg_probe(struct virtio_device *vdev)
struct scatterlist sg;
void *cpu_addr = vrp->rbufs + i * RPMSG_BUF_SIZE;
- sg_init_one(&sg, cpu_addr, RPMSG_BUF_SIZE);
+ err = sg_init_one_full(&sg, cpu_addr, RPMSG_BUF_SIZE);
+ if (err) {
+ dev_err(&vdev->dev, "rpmsg_probe sg_init failed.\n");
+ return err;
+ }
err = virtqueue_add_inbuf(vrp->rvq, &sg, 1, cpu_addr,
GFP_KERNEL);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 0723c97ebea3..6c107828ad77 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1647,6 +1647,20 @@ config RTC_DRV_SNVS
This driver can also be built as a module, if so, the module
will be called "rtc-snvs".
+config RTC_DRV_IMX_SC
+ tristate "NXP SC RTC support"
+ depends on OF
+ help
+ If you say yes here you get support for the NXP SC
+ RTC module.
+
+config RTC_DRV_IMX_RPMSG
+ tristate "NXP RPMSG RTC support"
+ depends on OF
+ help
+ If you say yes here you get support for the NXP RPMSG
+ RTC module.
+
config RTC_DRV_SIRFSOC
tristate "SiRFSOC RTC"
depends on ARCH_SIRF
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 1ac694a330c8..78a5e2536f4b 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -141,6 +141,8 @@ obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o
obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
+obj-$(CONFIG_RTC_DRV_IMX_SC) += rtc-imx-sc.o
+obj-$(CONFIG_RTC_DRV_IMX_RPMSG) += rtc-imx-rpmsg.o
obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o
obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
diff --git a/drivers/rtc/rtc-imx-rpmsg.c b/drivers/rtc/rtc-imx-rpmsg.c
new file mode 100644
index 000000000000..82140af645ec
--- /dev/null
+++ b/drivers/rtc/rtc-imx-rpmsg.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/imx_rpmsg.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+#include <linux/rpmsg.h>
+#include <linux/rtc.h>
+
+#define RPMSG_TIMEOUT 1000
+
+#define RTC_RPMSG_SEND 0x0
+#define RTC_RPMSG_RECEIVE 0x1
+#define RTC_RPMSG_NOTIFY 0x2
+
+enum rtc_rpmsg_cmd {
+ RTC_RPMSG_SET_TIME,
+ RTC_RPMSG_GET_TIME,
+ RTC_RPMSG_SET_ALARM,
+ RTC_RPMSG_GET_ALARM,
+ RTC_RPMSG_ENABLE_ALARM,
+};
+
+struct rtc_rpmsg_data {
+ struct imx_rpmsg_head header;
+ u8 reserved0;
+ union {
+ u8 reserved1;
+ u8 ret;
+ };
+ union {
+ u32 reserved2;
+ u32 sec;
+ };
+ union {
+ u8 enable;
+ u8 reserved3;
+ };
+ union {
+ u8 pending;
+ u8 reserved4;
+ };
+} __attribute__ ((packed));
+
+struct rtc_rpmsg_info {
+ struct rpmsg_device *rpdev;
+ struct device *dev;
+ struct rtc_rpmsg_data *msg;
+ struct pm_qos_request pm_qos_req;
+ struct completion cmd_complete;
+ struct mutex lock;
+};
+
+static struct rtc_rpmsg_info rtc_rpmsg;
+
+struct imx_rpmsg_rtc_data {
+ struct rtc_device *rtc;
+ spinlock_t lock;
+};
+
+struct imx_rpmsg_rtc_data *data;
+
+static int rtc_send_message(struct rtc_rpmsg_data *msg,
+ struct rtc_rpmsg_info *info, bool ack)
+{
+ int err;
+
+ if (!info->rpdev) {
+ dev_dbg(info->dev,
+ "rpmsg channel not ready, m4 image ready?\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&info->lock);
+ pm_qos_add_request(&info->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, 0);
+
+ reinit_completion(&info->cmd_complete);
+
+ err = rpmsg_send(info->rpdev->ept, (void *)msg,
+ sizeof(struct rtc_rpmsg_data));
+
+ if (err) {
+ dev_err(&info->rpdev->dev, "rpmsg_send failed: %d\n", err);
+ goto err_out;
+ }
+
+ if (ack) {
+ err = wait_for_completion_timeout(&info->cmd_complete,
+ msecs_to_jiffies(RPMSG_TIMEOUT));
+ if (!err) {
+ dev_err(&info->rpdev->dev, "rpmsg_send timeout!\n");
+ err = -ETIMEDOUT;
+ goto err_out;
+ }
+
+ if (info->msg->ret != 0) {
+ dev_err(&info->rpdev->dev, "rpmsg not ack %d!\n",
+ info->msg->ret);
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ err = 0;
+ }
+
+err_out:
+ pm_qos_remove_request(&info->pm_qos_req);
+ mutex_unlock(&info->lock);
+
+ return err;
+}
+
+static int imx_rpmsg_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rtc_rpmsg_data msg;
+ int ret;
+
+ msg.header.cate = IMX_RPMSG_RTC;
+ msg.header.major = IMX_RMPSG_MAJOR;
+ msg.header.minor = IMX_RMPSG_MINOR;
+ msg.header.type = RTC_RPMSG_SEND;
+ msg.header.cmd = RTC_RPMSG_GET_TIME;
+
+ ret = rtc_send_message(&msg, &rtc_rpmsg, true);
+ if (ret)
+ return ret;
+
+ rtc_time_to_tm(rtc_rpmsg.msg->sec, tm);
+
+ return 0;
+}
+
+static int imx_rpmsg_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rtc_rpmsg_data msg;
+ unsigned long time;
+ int ret;
+
+ rtc_tm_to_time(tm, &time);
+
+ msg.header.cate = IMX_RPMSG_RTC;
+ msg.header.major = IMX_RMPSG_MAJOR;
+ msg.header.minor = IMX_RMPSG_MINOR;
+ msg.header.type = RTC_RPMSG_SEND;
+ msg.header.cmd = RTC_RPMSG_SET_TIME;
+ msg.sec = time;
+
+ ret = rtc_send_message(&msg, &rtc_rpmsg, true);
+ if (ret)
+ return ret;
+
+ return rtc_rpmsg.msg->ret;
+}
+
+static int imx_rpmsg_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct rtc_rpmsg_data msg;
+ int ret;
+
+ msg.header.cate = IMX_RPMSG_RTC;
+ msg.header.major = IMX_RMPSG_MAJOR;
+ msg.header.minor = IMX_RMPSG_MINOR;
+ msg.header.type = RTC_RPMSG_SEND;
+ msg.header.cmd = RTC_RPMSG_GET_ALARM;
+
+ ret = rtc_send_message(&msg, &rtc_rpmsg, true);
+ if (ret)
+ return ret;
+
+ rtc_time_to_tm(rtc_rpmsg.msg->sec, &alrm->time);
+ alrm->pending = rtc_rpmsg.msg->pending;
+
+ return rtc_rpmsg.msg->ret;
+}
+
+static int imx_rpmsg_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enable)
+{
+ struct rtc_rpmsg_data msg;
+ int ret;
+
+ msg.header.cate = IMX_RPMSG_RTC;
+ msg.header.major = IMX_RMPSG_MAJOR;
+ msg.header.minor = IMX_RMPSG_MINOR;
+ msg.header.type = RTC_RPMSG_SEND;
+ msg.header.cmd = RTC_RPMSG_ENABLE_ALARM;
+ msg.enable = enable;
+
+ ret = rtc_send_message(&msg, &rtc_rpmsg, true);
+ if (ret)
+ return ret;
+
+ return rtc_rpmsg.msg->ret;
+}
+
+static int imx_rpmsg_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct rtc_rpmsg_data msg;
+ unsigned long time;
+ int ret;
+
+ rtc_tm_to_time(&alrm->time, &time);
+
+ msg.header.cate = IMX_RPMSG_RTC;
+ msg.header.major = IMX_RMPSG_MAJOR;
+ msg.header.minor = IMX_RMPSG_MINOR;
+ msg.header.type = RTC_RPMSG_SEND;
+ msg.header.cmd = RTC_RPMSG_SET_ALARM;
+ msg.sec = time;
+ msg.enable = alrm->enabled;
+
+ ret = rtc_send_message(&msg, &rtc_rpmsg, true);
+ if (ret)
+ return ret;
+
+ return rtc_rpmsg.msg->ret;
+}
+
+static int imx_rpmsg_rtc_alarm_irq_update(void)
+{
+ rtc_update_irq(data->rtc, 1, RTC_IRQF);
+
+ return 0;
+}
+
+static const struct rtc_class_ops imx_rpmsg_rtc_ops = {
+ .read_time = imx_rpmsg_rtc_read_time,
+ .set_time = imx_rpmsg_rtc_set_time,
+ .read_alarm = imx_rpmsg_rtc_read_alarm,
+ .set_alarm = imx_rpmsg_rtc_set_alarm,
+ .alarm_irq_enable = imx_rpmsg_rtc_alarm_irq_enable,
+};
+
+static struct rpmsg_device_id rtc_rpmsg_id_table[] = {
+ { .name = "rpmsg-rtc-channel" },
+ { },
+};
+
+static int rtc_rpmsg_probe(struct rpmsg_device *rpdev)
+{
+ int ret = 0;
+
+ dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
+ rpdev->src, rpdev->dst);
+
+ rtc_rpmsg.rpdev = rpdev;
+ mutex_init(&rtc_rpmsg.lock);
+
+ init_completion(&rtc_rpmsg.cmd_complete);
+
+ return ret;
+}
+
+static int rtc_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
+ void *priv, u32 src)
+{
+ struct rtc_rpmsg_data *msg = (struct rtc_rpmsg_data *)data;
+
+ if (msg->header.type == RTC_RPMSG_RECEIVE) {
+ rtc_rpmsg.msg = msg;
+ complete(&rtc_rpmsg.cmd_complete);
+ return 0;
+ } else if (msg->header.type == RTC_RPMSG_NOTIFY) {
+ rtc_rpmsg.msg = msg;
+ imx_rpmsg_rtc_alarm_irq_update();
+ } else
+ dev_err(&rtc_rpmsg.rpdev->dev, "wrong command type!\n");
+
+ return 0;
+}
+
+static void rtc_rpmsg_remove(struct rpmsg_device *rpdev)
+{
+ dev_info(&rpdev->dev, "rtc rpmsg driver is removed\n");
+}
+
+static struct rpmsg_driver rtc_rpmsg_driver = {
+ .drv.name = "rtc_rpmsg",
+ .drv.owner = THIS_MODULE,
+ .id_table = rtc_rpmsg_id_table,
+ .probe = rtc_rpmsg_probe,
+ .callback = rtc_rpmsg_cb,
+ .remove = rtc_rpmsg_remove,
+};
+
+static int imx_rpmsg_rtc_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, data);
+ device_init_wakeup(&pdev->dev, true);
+
+ data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &imx_rpmsg_rtc_ops, THIS_MODULE);
+ if (IS_ERR(data->rtc)) {
+ ret = PTR_ERR(data->rtc);
+ dev_err(&pdev->dev, "failed to register rtc: %d\n", ret);
+ goto error_rtc_device_register;
+ }
+
+ platform_set_drvdata(pdev, &rtc_rpmsg);
+ ret = register_rpmsg_driver(&rtc_rpmsg_driver);
+ if (ret)
+ dev_err(&pdev->dev, "failed to register rpmsg for rtc: %d\n",
+ ret);
+
+error_rtc_device_register:
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int imx_rpmsg_rtc_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int imx_rpmsg_rtc_suspend_noirq(struct device *dev)
+{
+ return 0;
+}
+
+static int imx_rpmsg_rtc_resume(struct device *dev)
+{
+ return 0;
+}
+
+static int imx_rpmsg_rtc_resume_noirq(struct device *dev)
+{
+ return 0;
+}
+
+static const struct dev_pm_ops imx_rpmsg_rtc_pm_ops = {
+ .suspend = imx_rpmsg_rtc_suspend,
+ .suspend_noirq = imx_rpmsg_rtc_suspend_noirq,
+ .resume = imx_rpmsg_rtc_resume,
+ .resume_noirq = imx_rpmsg_rtc_resume_noirq,
+};
+
+#define IMX_RPMSG_RTC_PM_OPS (&imx_rpmsg_rtc_pm_ops)
+
+#else
+
+#define IMX8_RPMSG_RTC_PM_OPS NULL
+
+#endif
+
+static const struct of_device_id imx_rpmsg_rtc_dt_ids[] = {
+ { .compatible = "fsl,imx-rpmsg-rtc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_rpmsg_rtc_dt_ids);
+
+static struct platform_driver imx_rpmsg_rtc_driver = {
+ .driver = {
+ .name = "imx_rpmsg_rtc",
+ .pm = IMX_RPMSG_RTC_PM_OPS,
+ .of_match_table = imx_rpmsg_rtc_dt_ids,
+ },
+ .probe = imx_rpmsg_rtc_probe,
+};
+module_platform_driver(imx_rpmsg_rtc_driver);
+
+MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
+MODULE_DESCRIPTION("NXP i.MX RPMSG RTC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-imx-sc.c b/drivers/rtc/rtc-imx-sc.c
new file mode 100644
index 000000000000..909d7c2a7005
--- /dev/null
+++ b/drivers/rtc/rtc-imx-sc.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <soc/imx/fsl_sip.h>
+#include <soc/imx8/sc/sci.h>
+#include <soc/imx8/sc/svc/irq/api.h>
+
+sc_ipc_t timer_ipcHandle;
+
+struct imx_sc_rtc_data {
+ struct rtc_device *rtc;
+ spinlock_t lock;
+};
+
+struct imx_sc_rtc_data *data;
+
+static int imx_sc_rtc_alarm_sc_notify(struct notifier_block *nb,
+ unsigned long event, void *group)
+{
+ u32 events = 0;
+
+ /* ignore non-rtc irq */
+ if (!((event & SC_IRQ_RTC) &&
+ (*(sc_irq_group_t *)group == SC_IRQ_GROUP_RTC)))
+ return 0;
+
+ rtc_update_irq(data->rtc, 1, events);
+
+ return 0;
+}
+
+static struct notifier_block imx_sc_rtc_alarm_sc_notifier = {
+ .notifier_call = imx_sc_rtc_alarm_sc_notify,
+};
+
+static int imx_sc_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ u32 time = 0;
+ sc_err_t sciErr = SC_ERR_NONE;
+
+ if (!timer_ipcHandle)
+ return -ENODEV;
+
+ sciErr = sc_timer_get_rtc_sec1970(timer_ipcHandle, &time);
+ if (sciErr) {
+ dev_err_once(dev, "failed to read time: %d\n", sciErr);
+ return -EINVAL;
+ }
+
+ rtc_time_to_tm(time, tm);
+
+ return 0;
+}
+
+static int imx_sc_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct arm_smccc_res res;
+
+ /* pack 2 time parameters into 1 register, 16 bits for each */
+ arm_smccc_smc(FSL_SIP_SRTC, FSL_SIP_SRTC_SET_TIME,
+ ((tm->tm_year + 1900) << 16) | (tm->tm_mon + 1),
+ (tm->tm_mday << 16) | tm->tm_hour,
+ (tm->tm_min << 16) | tm->tm_sec,
+ 0, 0, 0, &res);
+
+ return res.a0;
+}
+
+static int imx_sc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ return 0;
+}
+
+static int imx_sc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+ return 0;
+}
+
+static int imx_sc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ sc_err_t sciErr = SC_ERR_NONE;
+ struct rtc_time *alrm_tm = &alrm->time;
+
+ if (!timer_ipcHandle)
+ return -ENODEV;
+
+ sciErr = sc_timer_set_rtc_alarm(timer_ipcHandle,
+ alrm_tm->tm_year + 1900,
+ alrm_tm->tm_mon + 1,
+ alrm_tm->tm_mday,
+ alrm_tm->tm_hour,
+ alrm_tm->tm_min,
+ alrm_tm->tm_sec);
+
+ return 0;
+}
+
+static const struct rtc_class_ops imx_sc_rtc_ops = {
+ .read_time = imx_sc_rtc_read_time,
+ .set_time = imx_sc_rtc_set_time,
+ .read_alarm = imx_sc_rtc_read_alarm,
+ .set_alarm = imx_sc_rtc_set_alarm,
+ .alarm_irq_enable = imx_sc_rtc_alarm_irq_enable,
+};
+
+static int imx_sc_rtc_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ uint32_t mu_id;
+ sc_err_t sciErr;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, data);
+
+ device_init_wakeup(&pdev->dev, true);
+ data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &imx_sc_rtc_ops, THIS_MODULE);
+ if (IS_ERR(data->rtc)) {
+ ret = PTR_ERR(data->rtc);
+ dev_err(&pdev->dev, "failed to register rtc: %d\n", ret);
+ goto error_rtc_device_register;
+ }
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ dev_err(&pdev->dev, "can not obtain mu id: %d\n", sciErr);
+ return sciErr;
+ }
+
+ sciErr = sc_ipc_open(&timer_ipcHandle, mu_id);
+
+ if (sciErr != SC_ERR_NONE) {
+ dev_err(&pdev->dev, "can not open mu channel to scu: %d\n", sciErr);
+ return sciErr;
+ };
+
+ register_scu_notifier(&imx_sc_rtc_alarm_sc_notifier);
+
+error_rtc_device_register:
+
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int imx_sc_rtc_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int imx_sc_rtc_suspend_noirq(struct device *dev)
+{
+ return 0;
+}
+
+static int imx_sc_rtc_resume(struct device *dev)
+{
+ return 0;
+}
+
+static int imx_sc_rtc_resume_noirq(struct device *dev)
+{
+ return 0;
+}
+
+static const struct dev_pm_ops imx_sc_rtc_pm_ops = {
+ .suspend = imx_sc_rtc_suspend,
+ .suspend_noirq = imx_sc_rtc_suspend_noirq,
+ .resume = imx_sc_rtc_resume,
+ .resume_noirq = imx_sc_rtc_resume_noirq,
+};
+
+#define IMX_SC_RTC_PM_OPS (&imx_sc_rtc_pm_ops)
+
+#else
+
+#define IMX8_SC_RTC_PM_OPS NULL
+
+#endif
+
+static const struct of_device_id imx_sc_dt_ids[] = {
+ { .compatible = "fsl,imx-sc-rtc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_sc_dt_ids);
+
+static struct platform_driver imx_sc_rtc_driver = {
+ .driver = {
+ .name = "imx_sc_rtc",
+ .pm = IMX_SC_RTC_PM_OPS,
+ .of_match_table = imx_sc_dt_ids,
+ },
+ .probe = imx_sc_rtc_probe,
+};
+module_platform_driver(imx_sc_rtc_driver);
+
+MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
+MODULE_DESCRIPTION("NXP i.MX SC RTC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c
index 3e8fd33c2576..536d71c4c6f8 100644
--- a/drivers/rtc/rtc-snvs.c
+++ b/drivers/rtc/rtc-snvs.c
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2011-2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2011-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
@@ -18,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
@@ -64,7 +66,12 @@ static u32 rtc_read_lp_counter(struct snvs_rtc_data *data)
read2 <<= 32;
regmap_read(data->regmap, data->offset + SNVS_LPSRTCLR, &val);
read2 |= val;
- } while (read1 != read2);
+ /*
+ * when CPU/BUS are running at low speed, there is chance that
+ * we never get same value during two consecutive read, so here
+ * we only compare the second value.
+ */
+ } while ((read1 >> CNTR_TO_SECS_SH) != (read2 >> CNTR_TO_SECS_SH));
/* Convert 47-bit counter to 32-bit raw second count */
return (u32) (read1 >> CNTR_TO_SECS_SH);
@@ -141,6 +148,8 @@ static int snvs_rtc_set_time(struct device *dev, struct rtc_time *tm)
if (ret)
return ret;
+ udelay(50);
+
/* Write 32-bit time to 47-bit timer, leaving 15 LSBs blank */
regmap_write(data->regmap, data->offset + SNVS_LPSRTCLR, time << CNTR_TO_SECS_SH);
regmap_write(data->regmap, data->offset + SNVS_LPSRTCMR, time >> (32 - CNTR_TO_SECS_SH));
@@ -187,6 +196,7 @@ static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
rtc_tm_to_time(alrm_tm, &time);
regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_LPTA_EN, 0);
+ rtc_write_sync_lp(data);
regmap_write(data->regmap, data->offset + SNVS_LPTAR, time);
/* Clear alarm interrupt status bit */
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index d3145799b92f..7645949024d7 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -154,7 +154,8 @@ static int submit_rtpg(struct scsi_device *sdev, unsigned char *buff,
return scsi_execute_req_flags(sdev, cdb, DMA_FROM_DEVICE,
buff, bufflen, sshdr,
ALUA_FAILOVER_TIMEOUT * HZ,
- ALUA_FAILOVER_RETRIES, NULL, req_flags);
+ ALUA_FAILOVER_RETRIES, NULL,
+ req_flags, 0);
}
/*
@@ -187,7 +188,8 @@ static int submit_stpg(struct scsi_device *sdev, int group_id,
return scsi_execute_req_flags(sdev, cdb, DMA_TO_DEVICE,
stpg_data, stpg_len,
sshdr, ALUA_FAILOVER_TIMEOUT * HZ,
- ALUA_FAILOVER_RETRIES, NULL, req_flags);
+ ALUA_FAILOVER_RETRIES, NULL,
+ req_flags, 0);
}
static struct alua_port_group *alua_find_get_pg(char *id_str, size_t id_size,
@@ -1076,7 +1078,7 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req)
state != SCSI_ACCESS_STATE_ACTIVE &&
state != SCSI_ACCESS_STATE_LBA) {
ret = BLKPREP_KILL;
- req->cmd_flags |= REQ_QUIET;
+ req->rq_flags |= RQF_QUIET;
}
return ret;
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index d5f6fbfa17bf..4d4f2461288f 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -452,7 +452,7 @@ static int clariion_prep_fn(struct scsi_device *sdev, struct request *req)
if (h->lun_state != CLARIION_LUN_OWNED) {
ret = BLKPREP_KILL;
- req->cmd_flags |= REQ_QUIET;
+ req->rq_flags |= RQF_QUIET;
}
return ret;
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index 9406d5f4a3d3..308e87195dc1 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -266,7 +266,7 @@ static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
if (h->path_state != HP_SW_PATH_ACTIVE) {
ret = BLKPREP_KILL;
- req->cmd_flags |= REQ_QUIET;
+ req->rq_flags |= RQF_QUIET;
}
return ret;
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 06fbd0b0c68a..00d9c326158e 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -724,7 +724,7 @@ static int rdac_prep_fn(struct scsi_device *sdev, struct request *req)
if (h->state != RDAC_STATE_ACTIVE) {
ret = BLKPREP_KILL;
- req->cmd_flags |= REQ_QUIET;
+ req->rq_flags |= RQF_QUIET;
}
return ret;
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 2f2a9910e30e..ef99f62831fb 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -1595,7 +1595,7 @@ static int _init_blk_request(struct osd_request *or,
}
or->request = req;
- req->cmd_flags |= REQ_QUIET;
+ req->rq_flags |= RQF_QUIET;
req->timeout = or->timeout;
req->retries = or->retries;
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 5033223f6287..a2960f5d98ec 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -368,7 +368,7 @@ static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd,
return DRIVER_ERROR << 24;
blk_rq_set_block_pc(req);
- req->cmd_flags |= REQ_QUIET;
+ req->rq_flags |= RQF_QUIET;
SRpnt->bio = NULL;
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 106a6adbd6f1..b542e494c9f4 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -59,6 +59,12 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd);
static int scsi_try_to_abort_cmd(struct scsi_host_template *,
struct scsi_cmnd *);
+#ifdef CONFIG_AHCI_IMX
+extern void *sg_io_buffer_hack;
+#else
+#define sg_io_buffer_hack NULL
+#endif
+
/* called with shost->host_lock held */
void scsi_eh_wakeup(struct Scsi_Host *shost)
{
@@ -67,6 +73,11 @@ void scsi_eh_wakeup(struct Scsi_Host *shost)
wake_up_process(shost->ehandler);
SCSI_LOG_ERROR_RECOVERY(5, shost_printk(KERN_INFO, shost,
"Waking error handler thread\n"));
+ } else if ((shost->host_failed > 0) || (sg_io_buffer_hack != NULL)) {
+ trace_scsi_eh_wakeup(shost);
+ wake_up_process(shost->ehandler);
+ SCSI_LOG_ERROR_RECOVERY(5, shost_printk(KERN_INFO, shost,
+ "Waking error handler thread\n"));
}
}
@@ -1988,7 +1999,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
req->cmd_len = COMMAND_SIZE(req->cmd[0]);
- req->cmd_flags |= REQ_QUIET;
+ req->rq_flags |= RQF_QUIET;
req->timeout = 10 * HZ;
req->retries = 5;
@@ -2190,8 +2201,15 @@ int scsi_error_handler(void *data)
if (kthread_should_stop())
break;
+ /*
+ * Do not go to sleep, when there is host_failed when the
+ * one-PRD per command workaroud is tiggered.
+ * Because that ata/scsi subsystem maybe hang, when CD_ROM
+ * and HDD are accessed simultaneously.
+ */
if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) ||
- shost->host_failed != atomic_read(&shost->host_busy)) {
+ ((shost->host_failed != atomic_read(&shost->host_busy)) &&
+ (sg_io_buffer_hack == NULL) && (shost->host_failed > 0))) {
SCSI_LOG_ERROR_RECOVERY(1,
shost_printk(KERN_INFO, shost,
"scsi_eh_%d: sleeping\n",
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index c7b770075caa..da8624509c9f 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -163,26 +163,11 @@ void scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
{
__scsi_queue_insert(cmd, reason, 1);
}
-/**
- * scsi_execute - insert request and wait for the result
- * @sdev: scsi device
- * @cmd: scsi command
- * @data_direction: data direction
- * @buffer: data buffer
- * @bufflen: len of buffer
- * @sense: optional sense buffer
- * @timeout: request timeout in seconds
- * @retries: number of times to retry request
- * @flags: or into request flags;
- * @resid: optional residual length
- *
- * returns the req->errors value which is the scsi_cmnd result
- * field.
- */
-int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
+
+static int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
int data_direction, void *buffer, unsigned bufflen,
unsigned char *sense, int timeout, int retries, u64 flags,
- int *resid)
+ req_flags_t rq_flags, int *resid)
{
struct request *req;
int write = (data_direction == DMA_TO_DEVICE);
@@ -203,7 +188,8 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
req->sense_len = 0;
req->retries = retries;
req->timeout = timeout;
- req->cmd_flags |= flags | REQ_QUIET | REQ_PREEMPT;
+ req->cmd_flags |= flags;
+ req->rq_flags |= rq_flags | RQF_QUIET | RQF_PREEMPT;
/*
* head injection *required* here otherwise quiesce won't work
@@ -227,12 +213,37 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
return ret;
}
+
+/**
+ * scsi_execute - insert request and wait for the result
+ * @sdev: scsi device
+ * @cmd: scsi command
+ * @data_direction: data direction
+ * @buffer: data buffer
+ * @bufflen: len of buffer
+ * @sense: optional sense buffer
+ * @timeout: request timeout in seconds
+ * @retries: number of times to retry request
+ * @flags: or into request flags;
+ * @resid: optional residual length
+ *
+ * returns the req->errors value which is the scsi_cmnd result
+ * field.
+ */
+int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
+ int data_direction, void *buffer, unsigned bufflen,
+ unsigned char *sense, int timeout, int retries, u64 flags,
+ int *resid)
+{
+ return __scsi_execute(sdev, cmd, data_direction, buffer, bufflen, sense,
+ timeout, retries, flags, 0, resid);
+}
EXPORT_SYMBOL(scsi_execute);
int scsi_execute_req_flags(struct scsi_device *sdev, const unsigned char *cmd,
int data_direction, void *buffer, unsigned bufflen,
struct scsi_sense_hdr *sshdr, int timeout, int retries,
- int *resid, u64 flags)
+ int *resid, u64 flags, req_flags_t rq_flags)
{
char *sense = NULL;
int result;
@@ -242,8 +253,8 @@ int scsi_execute_req_flags(struct scsi_device *sdev, const unsigned char *cmd,
if (!sense)
return DRIVER_ERROR << 24;
}
- result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen,
- sense, timeout, retries, flags, resid);
+ result = __scsi_execute(sdev, cmd, data_direction, buffer, bufflen,
+ sense, timeout, retries, flags, rq_flags, resid);
if (sshdr)
scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, sshdr);
@@ -813,7 +824,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
*/
if ((sshdr.asc == 0x0) && (sshdr.ascq == 0x1d))
;
- else if (!(req->cmd_flags & REQ_QUIET))
+ else if (!(req->rq_flags & RQF_QUIET))
scsi_print_sense(cmd);
result = 0;
/* BLOCK_PC may have set error */
@@ -943,7 +954,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
switch (action) {
case ACTION_FAIL:
/* Give up and fail the remainder of the request */
- if (!(req->cmd_flags & REQ_QUIET)) {
+ if (!(req->rq_flags & RQF_QUIET)) {
static DEFINE_RATELIMIT_STATE(_rs,
DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST);
@@ -972,7 +983,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
* A new command will be prepared and issued.
*/
if (q->mq_ops) {
- cmd->request->cmd_flags &= ~REQ_DONTPREP;
+ cmd->request->rq_flags &= ~RQF_DONTPREP;
scsi_mq_uninit_cmd(cmd);
scsi_mq_requeue_cmd(cmd);
} else {
@@ -1235,7 +1246,7 @@ scsi_prep_state_check(struct scsi_device *sdev, struct request *req)
/*
* If the devices is blocked we defer normal commands.
*/
- if (!(req->cmd_flags & REQ_PREEMPT))
+ if (!(req->rq_flags & RQF_PREEMPT))
ret = BLKPREP_DEFER;
break;
default:
@@ -1244,7 +1255,7 @@ scsi_prep_state_check(struct scsi_device *sdev, struct request *req)
* special commands. In particular any user initiated
* command is not allowed.
*/
- if (!(req->cmd_flags & REQ_PREEMPT))
+ if (!(req->rq_flags & RQF_PREEMPT))
ret = BLKPREP_KILL;
break;
}
@@ -1280,7 +1291,7 @@ scsi_prep_return(struct request_queue *q, struct request *req, int ret)
blk_delay_queue(q, SCSI_QUEUE_DELAY);
break;
default:
- req->cmd_flags |= REQ_DONTPREP;
+ req->rq_flags |= RQF_DONTPREP;
}
return ret;
@@ -1737,7 +1748,7 @@ static void scsi_request_fn(struct request_queue *q)
* we add the dev to the starved list so it eventually gets
* a run when a tag is freed.
*/
- if (blk_queue_tagged(q) && !(req->cmd_flags & REQ_QUEUED)) {
+ if (blk_queue_tagged(q) && !(req->rq_flags & RQF_QUEUED)) {
spin_lock_irq(shost->host_lock);
if (list_empty(&sdev->starved_entry))
list_add_tail(&sdev->starved_entry,
@@ -1904,11 +1915,11 @@ static int scsi_queue_rq(struct blk_mq_hw_ctx *hctx,
goto out_dec_target_busy;
- if (!(req->cmd_flags & REQ_DONTPREP)) {
+ if (!(req->rq_flags & RQF_DONTPREP)) {
ret = prep_to_mq(scsi_mq_prep_fn(req));
if (ret)
goto out_dec_host_busy;
- req->cmd_flags |= REQ_DONTPREP;
+ req->rq_flags |= RQF_DONTPREP;
} else {
blk_mq_start_request(req);
}
@@ -1953,7 +1964,7 @@ out:
* we hit an error, as we will never see this command
* again.
*/
- if (req->cmd_flags & REQ_DONTPREP)
+ if (req->rq_flags & RQF_DONTPREP)
scsi_mq_uninit_cmd(cmd);
break;
default:
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index f8b6bf56c48e..b1b1952a4c2a 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1021,8 +1021,7 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt)
} else if (rq_data_dir(rq) == READ) {
SCpnt->cmnd[0] = READ_6;
} else {
- scmd_printk(KERN_ERR, SCpnt, "Unknown command %llu,%llx\n",
- req_op(rq), (unsigned long long) rq->cmd_flags);
+ scmd_printk(KERN_ERR, SCpnt, "Unknown command %d\n", req_op(rq));
goto out;
}
@@ -1503,7 +1502,7 @@ static int sd_sync_cache(struct scsi_disk *sdkp)
*/
res = scsi_execute_req_flags(sdp, cmd, DMA_NONE, NULL, 0,
&sshdr, timeout, SD_MAX_RETRIES,
- NULL, REQ_PM);
+ NULL, 0, RQF_PM);
if (res == 0)
break;
}
@@ -1848,7 +1847,7 @@ static int sd_done(struct scsi_cmnd *SCpnt)
good_bytes = 0;
req->__data_len = blk_rq_bytes(req);
- req->cmd_flags |= REQ_QUIET;
+ req->rq_flags |= RQF_QUIET;
}
}
}
@@ -3238,7 +3237,7 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, int start)
return -ENODEV;
res = scsi_execute_req_flags(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
- SD_TIMEOUT, SD_MAX_RETRIES, NULL, REQ_PM);
+ SD_TIMEOUT, SD_MAX_RETRIES, NULL, 0, RQF_PM);
if (res) {
sd_print_result(sdkp, "Start/Stop Unit failed", res);
if (driver_byte(res) & DRIVER_SENSE)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 618422ea3a41..605887d5ee57 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -546,7 +546,7 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
return DRIVER_ERROR << 24;
blk_rq_set_block_pc(req);
- req->cmd_flags |= REQ_QUIET;
+ req->rq_flags |= RQF_QUIET;
mdata->null_mapped = 1;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f857086ce2fa..398e2af1a9d9 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5867,7 +5867,7 @@ ufshcd_send_request_sense(struct ufs_hba *hba, struct scsi_device *sdp)
ret = scsi_execute_req_flags(sdp, cmd, DMA_FROM_DEVICE, buffer,
SCSI_SENSE_BUFFERSIZE, NULL,
- msecs_to_jiffies(1000), 3, NULL, REQ_PM);
+ msecs_to_jiffies(1000), 3, NULL, 0, RQF_PM);
if (ret)
pr_err("%s: failed with err %d\n", __func__, ret);
@@ -5929,11 +5929,11 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
/*
* Current function would be generally called from the power management
- * callbacks hence set the REQ_PM flag so that it doesn't resume the
+ * callbacks hence set the RQF_PM flag so that it doesn't resume the
* already suspended childs.
*/
ret = scsi_execute_req_flags(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
- START_STOP_TIMEOUT, 0, NULL, REQ_PM);
+ START_STOP_TIMEOUT, 0, NULL, 0, RQF_PM);
if (ret) {
sdev_printk(KERN_WARNING, sdp,
"START_STOP failed for power mode: %d, result %x\n",
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index e6e90e80519a..ecd861969e8f 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -3,6 +3,7 @@ menu "SOC (System On Chip) specific Drivers"
source "drivers/soc/bcm/Kconfig"
source "drivers/soc/fsl/qbman/Kconfig"
source "drivers/soc/fsl/qe/Kconfig"
+source "drivers/soc/imx/Kconfig"
source "drivers/soc/mediatek/Kconfig"
source "drivers/soc/qcom/Kconfig"
source "drivers/soc/rockchip/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 50c23d0bd457..489df4d77687 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_SOC_TI) += ti/
obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_PLAT_VERSATILE) += versatile/
+obj-y += imx/
diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig
new file mode 100644
index 000000000000..c34998507218
--- /dev/null
+++ b/drivers/soc/imx/Kconfig
@@ -0,0 +1,50 @@
+#
+# IMX Soc drivers
+#
+menu "NXP IMX SoC drivers"
+
+menuconfig ARCH_MXC_ARM64
+ bool "NXP i.MX family"
+ depends on ARM64
+ help
+ Support for NXP MXC/iMX-based ARM64 family of processors
+
+if ARCH_MXC_ARM64
+
+config ARCH_FSL_IMX8QM
+ bool "i.MX8QM"
+ select HAVE_IMX_MU
+ select HAVE_IMX_RPMSG
+ select HAVE_IMX8_SOC
+
+config ARCH_FSL_IMX8QXP
+ bool "i.MX8QXP"
+ select HAVE_IMX_MU
+ select HAVE_IMX_RPMSG
+ select HAVE_IMX8_SOC
+
+config ARCH_FSL_IMX8MQ
+ bool "i.MX8MQ"
+ select HAVE_IMX_MU
+ select HAVE_IMX_RPMSG
+ select HAVE_IMX8_SOC
+
+config ARCH_FSL_IMX8MM
+ bool "i.MX8MM"
+ select HAVE_IMX_MU
+ select HAVE_IMX_RPMSG
+ select HAVE_IMX8_SOC
+
+endif
+
+config HAVE_IMX_MU
+ bool
+
+config HAVE_IMX8_SOC
+ bool
+
+config HAVE_IMX_RPMSG
+ select RPMSG_VIRTIO
+ select RPMSG
+ bool
+endmenu
diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile
new file mode 100644
index 000000000000..0eebc25dcfb9
--- /dev/null
+++ b/drivers/soc/imx/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_HAVE_IMX_MU) += mu/
+obj-$(CONFIG_ARCH_FSL_IMX8QM) += sc/
+obj-$(CONFIG_ARCH_FSL_IMX8QM) += pm-domains.o
+obj-$(CONFIG_ARCH_FSL_IMX8MQ) += busfreq-imx8mq.o gpc-psci.o
+obj-$(CONFIG_ARCH_FSL_IMX8MM) += gpc-psci.o
+obj-$(CONFIG_HAVE_IMX8_SOC) += soc-imx8.o
diff --git a/drivers/soc/imx/busfreq-imx8mq.c b/drivers/soc/imx/busfreq-imx8mq.c
new file mode 100644
index 000000000000..a8c3488d0b4c
--- /dev/null
+++ b/drivers/soc/imx/busfreq-imx8mq.c
@@ -0,0 +1,661 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/busfreq-imx.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/cpumask.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/proc_fs.h>
+#include <linux/reboot.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/suspend.h>
+#include <soc/imx/fsl_sip.h>
+
+#define HIGH_FREQ_3200MTS 0x0
+#define AUDIO_FREQ_400MTS 0x1
+#define LOW_BUS_FREQ_100MTS 0x2
+#define LOW_BUS_FREQ_667MTS 0x1
+#define WAIT_BUS_FREQ_DONE 0xf
+
+static struct device *busfreq_dev;
+static int low_bus_freq_mode;
+static int audio_bus_freq_mode;
+static int high_bus_freq_mode;
+static int bus_freq_scaling_initialized;
+static int bus_freq_scaling_is_active;
+static int high_bus_count, audio_bus_count, low_bus_count;
+static int cur_bus_freq_mode;
+static int busfreq_suspended;
+static bool cancel_reduce_bus_freq;
+
+static struct clk *dram_pll_clk;
+static struct clk *sys1_pll_800m;
+static struct clk *sys1_pll_400m;
+static struct clk *sys1_pll_100m;
+static struct clk *sys1_pll_40m;
+static struct clk *dram_alt_src;
+static struct clk *dram_alt_root;
+static struct clk *dram_core_clk;
+static struct clk *dram_apb_src;
+static struct clk *dram_apb_pre_div;
+static struct clk *noc_div;
+static struct clk *main_axi_src;
+static struct clk *ahb_div;
+static struct clk *osc_25m;
+static struct clk *sys2_pll_333m;
+
+static struct delayed_work low_bus_freq_handler;
+static struct delayed_work bus_freq_daemon;
+
+DEFINE_MUTEX(bus_freq_mutex);
+
+static irqreturn_t wait_in_wfe_irq(int irq, void *dev_id)
+{
+ struct arm_smccc_res res;
+ /* call smc trap to ATF */
+ arm_smccc_smc(FSL_SIP_DDR_DVFS, WAIT_BUS_FREQ_DONE, 0,
+ 0, 0, 0, 0, 0, &res);
+
+ return IRQ_HANDLED;
+}
+
+static void update_bus_freq(int target_freq)
+{
+ struct arm_smccc_res res;
+ u32 online_cpus = 0;
+ int cpu = 0;
+
+ local_irq_disable();
+
+ for_each_online_cpu(cpu) {
+ online_cpus |= (1 << (cpu * 8));
+ }
+ /* change the ddr freqency */
+ arm_smccc_smc(FSL_SIP_DDR_DVFS, target_freq, online_cpus,
+ 0, 0, 0, 0, 0, &res);
+
+ local_irq_enable();
+}
+
+static void reduce_bus_freq(void)
+{
+ high_bus_freq_mode = 0;
+
+ /*
+ * below piece of code has some redundant part, keep
+ * it at present, we may need update the audio freq
+ * in the future if needed.
+ */
+ if (audio_bus_count) {
+ if (cur_bus_freq_mode == BUS_FREQ_HIGH) {
+
+ if (of_machine_is_compatible("fsl,imx8mq")) {
+ update_bus_freq(LOW_BUS_FREQ_667MTS);
+
+ /*
+ * the dram_apb and dram_core clk rate is changed
+ * in ATF side, below two lines of code is just used
+ * to upate the clock tree info in kernel side.
+ */
+ clk_set_rate(dram_apb_pre_div, 160000000);
+ clk_get_rate(dram_pll_clk);
+ /* reduce the NOC & bus clock */
+ clk_set_rate(noc_div, clk_get_rate(noc_div) / 8);
+ } else {
+ /* prepare the necessary clk before frequency change */
+ clk_prepare_enable(sys1_pll_40m);
+ clk_prepare_enable(dram_alt_root);
+ clk_prepare_enable(sys1_pll_100m);
+
+ update_bus_freq(LOW_BUS_FREQ_100MTS);
+
+ /* correct the clock tree info */
+ clk_set_parent(dram_alt_src, sys1_pll_100m);
+ clk_set_parent(dram_core_clk, dram_alt_root);
+ clk_set_parent(dram_apb_src, sys1_pll_40m);
+ clk_set_rate(dram_apb_pre_div, 20000000);
+ clk_disable_unprepare(sys1_pll_100m);
+ clk_disable_unprepare(sys1_pll_40m);
+ clk_disable_unprepare(dram_alt_root);
+
+ /* change the NOC rate */
+ clk_set_rate(noc_div, clk_get_rate(noc_div) / 5);
+ }
+
+ clk_set_rate(ahb_div, clk_get_rate(ahb_div) / 6);
+ clk_set_parent(main_axi_src, osc_25m);
+ }
+
+ low_bus_freq_mode = 0;
+ audio_bus_freq_mode = 1;
+ cur_bus_freq_mode = BUS_FREQ_AUDIO;
+ } else {
+ if (cur_bus_freq_mode == BUS_FREQ_HIGH) {
+
+ if (of_machine_is_compatible("fsl,imx8mq")) {
+ update_bus_freq(LOW_BUS_FREQ_667MTS);
+
+ clk_set_rate(dram_apb_pre_div, 160000000);
+ clk_get_rate(dram_pll_clk);
+ /* reduce the NOC & bus clock */
+ clk_set_rate(noc_div, clk_get_rate(noc_div) / 8);
+ } else {
+ /* prepare the necessary clk before frequency change */
+ clk_prepare_enable(sys1_pll_40m);
+ clk_prepare_enable(dram_alt_root);
+ clk_prepare_enable(sys1_pll_100m);
+
+ update_bus_freq(LOW_BUS_FREQ_100MTS);
+
+ /* correct the clock tree info */
+ clk_set_parent(dram_alt_src, sys1_pll_100m);
+ clk_set_parent(dram_core_clk, dram_alt_root);
+ clk_set_parent(dram_apb_src, sys1_pll_40m);
+ clk_set_rate(dram_apb_pre_div, 20000000);
+ clk_disable_unprepare(sys1_pll_100m);
+ clk_disable_unprepare(sys1_pll_40m);
+ clk_disable_unprepare(dram_alt_root);
+
+ /* change the NOC clock rate */
+ clk_set_rate(noc_div, clk_get_rate(noc_div) / 5);
+ }
+
+ clk_set_rate(ahb_div, clk_get_rate(ahb_div) / 6);
+ clk_set_parent(main_axi_src, osc_25m);
+ }
+
+ low_bus_freq_mode = 1;
+ audio_bus_freq_mode = 0;
+ cur_bus_freq_mode = BUS_FREQ_LOW;
+ }
+
+ if (audio_bus_freq_mode)
+ printk(KERN_DEBUG "ddrc freq set to audio bus mode\n");
+ if (low_bus_freq_mode)
+ printk(KERN_DEBUG "ddrc freq set to low bus mode\n");
+}
+
+static void reduce_bus_freq_handler(struct work_struct *work)
+{
+ mutex_lock(&bus_freq_mutex);
+
+ if (!cancel_reduce_bus_freq)
+ reduce_bus_freq();
+
+ mutex_unlock(&bus_freq_mutex);
+}
+
+static int set_low_bus_freq(void)
+{
+ if (busfreq_suspended)
+ return 0;
+
+ if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active)
+ return 0;
+
+ cancel_reduce_bus_freq = false;
+
+ /*
+ * check to see if we need to got from low bus
+ * freq mode to audio bus freq mode.
+ * If so, the change needs to be done immediately.
+ */
+ if (audio_bus_count && low_bus_freq_mode)
+ reduce_bus_freq();
+ else
+ schedule_delayed_work(&low_bus_freq_handler,
+ usecs_to_jiffies(1000000));
+
+ return 0;
+}
+
+static inline void cancel_low_bus_freq_handler(void)
+{
+ cancel_delayed_work(&low_bus_freq_handler);
+ cancel_reduce_bus_freq = true;
+}
+
+static int set_high_bus_freq(int high_bus_freq)
+{
+ if (bus_freq_scaling_initialized || bus_freq_scaling_is_active)
+ cancel_low_bus_freq_handler();
+
+ if (busfreq_suspended)
+ return 0;
+
+ if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active)
+ return 0;
+
+ if (high_bus_freq_mode)
+ return 0;
+
+ if (of_machine_is_compatible("fsl,imx8mq")) {
+ /* switch the DDR freqeuncy */
+ update_bus_freq(HIGH_FREQ_3200MTS);
+
+ clk_set_rate(dram_apb_pre_div, 200000000);
+ clk_get_rate(dram_pll_clk);
+ clk_set_rate(noc_div, 800000000);
+ } else {
+ /* enable the clks needed in frequency */
+ clk_prepare_enable(sys1_pll_800m);
+ clk_prepare_enable(dram_pll_clk);
+
+ /* switch the DDR freqeuncy */
+ update_bus_freq(HIGH_FREQ_3200MTS);
+
+ /* correct the clock tree info */
+ clk_set_parent(dram_apb_src, sys1_pll_800m);
+ clk_set_rate(dram_apb_pre_div, 160000000);
+ clk_set_parent(dram_core_clk, dram_pll_clk);
+ clk_disable_unprepare(sys1_pll_800m);
+ clk_disable_unprepare(dram_pll_clk);
+ clk_set_rate(noc_div, 750000000);
+ }
+
+ clk_set_rate(ahb_div, 133333333);
+ clk_set_parent(main_axi_src, sys2_pll_333m);
+
+ high_bus_freq_mode = 1;
+ audio_bus_freq_mode = 0;
+ low_bus_freq_mode = 0;
+ cur_bus_freq_mode = BUS_FREQ_HIGH;
+
+ if (high_bus_freq_mode)
+ printk(KERN_DEBUG "ddrc freq set to high bus mode\n");
+
+ return 0;
+}
+
+void request_bus_freq(enum bus_freq_mode mode)
+{
+ mutex_lock(&bus_freq_mutex);
+
+ if (mode == BUS_FREQ_HIGH)
+ high_bus_count++;
+ else if (mode == BUS_FREQ_AUDIO)
+ audio_bus_count++;
+ else if (mode == BUS_FREQ_LOW)
+ low_bus_count++;
+
+ if (busfreq_suspended || !bus_freq_scaling_initialized ||
+ !bus_freq_scaling_is_active) {
+ mutex_unlock(&bus_freq_mutex);
+ return;
+ }
+
+ cancel_low_bus_freq_handler();
+
+ if ((mode == BUS_FREQ_HIGH) && (!high_bus_freq_mode)) {
+ set_high_bus_freq(1);
+ mutex_unlock(&bus_freq_mutex);
+ return;
+ }
+
+ if ((mode == BUS_FREQ_AUDIO) && (!high_bus_freq_mode) &&
+ (!audio_bus_freq_mode)) {
+ set_low_bus_freq();
+ mutex_unlock(&bus_freq_mutex);
+ return;
+ }
+
+ mutex_unlock(&bus_freq_mutex);
+}
+EXPORT_SYMBOL(request_bus_freq);
+
+void release_bus_freq(enum bus_freq_mode mode)
+{
+ mutex_lock(&bus_freq_mutex);
+ if (mode == BUS_FREQ_HIGH) {
+ if (high_bus_count == 0) {
+ dev_err(busfreq_dev, "high bus count mismatch!\n");
+ dump_stack();
+ mutex_unlock(&bus_freq_mutex);
+ return;
+ }
+ high_bus_count--;
+ } else if (mode == BUS_FREQ_AUDIO) {
+ if (audio_bus_count == 0) {
+ dev_err(busfreq_dev, "audio bus count mismatch!\n");
+ dump_stack();
+ mutex_unlock(&bus_freq_mutex);
+ return;
+ }
+ audio_bus_count--;
+ } else if (mode == BUS_FREQ_LOW) {
+ if (low_bus_count == 0) {
+ dev_err(busfreq_dev, "low bus count mismatch!\n");
+ dump_stack();
+ mutex_unlock(&bus_freq_mutex);
+ return;
+ }
+ low_bus_count--;
+ }
+
+ if (busfreq_suspended || !bus_freq_scaling_initialized ||
+ !bus_freq_scaling_is_active) {
+ mutex_unlock(&bus_freq_mutex);
+ return;
+ }
+
+ if ((!audio_bus_freq_mode) && (high_bus_count == 0) &&
+ (audio_bus_count != 0)) {
+ set_low_bus_freq();
+ mutex_unlock(&bus_freq_mutex);
+ return;
+ }
+
+ if ((!low_bus_freq_mode) && (high_bus_count == 0) &&
+ (audio_bus_count == 0)) {
+ set_low_bus_freq();
+ mutex_unlock(&bus_freq_mutex);
+ return;
+ }
+
+ mutex_unlock(&bus_freq_mutex);
+}
+EXPORT_SYMBOL(release_bus_freq);
+
+int get_bus_freq_mode(void)
+{
+ return cur_bus_freq_mode;
+}
+EXPORT_SYMBOL(get_bus_freq_mode);
+
+static void bus_freq_daemon_handler(struct work_struct *work)
+{
+ mutex_lock(&bus_freq_mutex);
+ if ((!low_bus_freq_mode) && (high_bus_count == 0) &&
+ (audio_bus_count == 0))
+ set_low_bus_freq();
+ mutex_unlock(&bus_freq_mutex);
+}
+
+static ssize_t bus_freq_scaling_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (bus_freq_scaling_is_active)
+ return sprintf(buf, "Bus frequency scaling is enabled\n");
+ else
+ return sprintf(buf, "Bus frequency scaling is disabled\n");
+}
+
+static ssize_t bus_freq_scaling_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ if (strncmp(buf, "1", 1) == 0) {
+ bus_freq_scaling_is_active = 1;
+ set_high_bus_freq(1);
+ /*
+ * We set bus freq to higher at the beginning,
+ * so we use this daemon thread to make sure system
+ * can enter low bus mode if there is no high bus request pending
+ */
+ schedule_delayed_work(&bus_freq_daemon,
+ usecs_to_jiffies(5000000));
+ } else if (strncmp(buf, "0", 1) == 0) {
+ if (bus_freq_scaling_is_active)
+ set_high_bus_freq(1);
+ bus_freq_scaling_is_active = 0;
+ }
+ return size;
+}
+
+static int bus_freq_pm_notify(struct notifier_block *nb, unsigned long event,
+ void *dummy)
+{
+ mutex_lock(&bus_freq_mutex);
+
+ if (event == PM_SUSPEND_PREPARE) {
+ high_bus_count++;
+ set_high_bus_freq(1);
+ busfreq_suspended = 1;
+ } else if (event == PM_POST_SUSPEND) {
+ busfreq_suspended = 0;
+ high_bus_count--;
+ schedule_delayed_work(&bus_freq_daemon,
+ usecs_to_jiffies(5000000));
+ }
+
+ mutex_unlock(&bus_freq_mutex);
+
+ return NOTIFY_OK;
+}
+
+static int busfreq_reboot_notifier_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ /* System is rebooting. Set the system into high_bus_freq_mode. */
+ request_bus_freq(BUS_FREQ_HIGH);
+
+ return 0;
+}
+
+static struct notifier_block imx_bus_freq_pm_notifier = {
+ .notifier_call = bus_freq_pm_notify,
+};
+
+static struct notifier_block imx_busfreq_reboot_notifier = {
+ .notifier_call = busfreq_reboot_notifier_event,
+};
+
+static DEVICE_ATTR(enable, 0644, bus_freq_scaling_enable_show,
+ bus_freq_scaling_enable_store);
+
+static int init_busfreq_irq(struct platform_device *busfreq_pdev)
+{
+ struct device *dev = &busfreq_pdev->dev;
+ u32 cpu;
+ int err;
+
+ for_each_online_cpu(cpu) {
+ int irq;
+ /*
+ * set up a reserved interrupt to get all
+ * the active cores into a WFE state before
+ * changing the DDR frequency.
+ */
+ irq = platform_get_irq(busfreq_pdev, cpu);
+ err = request_irq(irq, wait_in_wfe_irq,
+ IRQF_PERCPU, "ddrc", NULL);
+ if (err) {
+ dev_err(dev, "Busfreq request irq failed %d, err = %d\n",
+ irq, err);
+ return err;
+ }
+ err = irq_set_affinity(irq, cpumask_of(cpu));
+ if (err) {
+ dev_err(dev, "busfreq can't set irq affinity irq = %d\n", irq);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int imx8mq_init_busfreq_clk(struct platform_device *pdev)
+{
+ dram_pll_clk = devm_clk_get(&pdev->dev, "dram_pll");
+ sys1_pll_800m = devm_clk_get(&pdev->dev, "sys1_pll_800m");
+ sys1_pll_400m = devm_clk_get(&pdev->dev, "sys1_pll_400m");
+ sys1_pll_100m = devm_clk_get(&pdev->dev, "sys1_pll_100m");
+ sys1_pll_40m = devm_clk_get(&pdev->dev, "sys1_pll_40m");
+ dram_alt_src = devm_clk_get(&pdev->dev, "dram_alt_src");
+ dram_alt_root = devm_clk_get(&pdev->dev, "dram_alt_root");
+ dram_core_clk = devm_clk_get(&pdev->dev, "dram_core");
+ dram_apb_src = devm_clk_get(&pdev->dev, "dram_apb_src");
+ dram_apb_pre_div = devm_clk_get(&pdev->dev, "dram_apb_pre_div");
+ noc_div = devm_clk_get(&pdev->dev, "noc_div");
+ ahb_div = devm_clk_get(&pdev->dev, "ahb_div");
+ main_axi_src = devm_clk_get(&pdev->dev, "main_axi_src");
+ osc_25m = devm_clk_get(&pdev->dev, "osc_25m");
+ sys2_pll_333m = devm_clk_get(&pdev->dev, "sys2_pll_333m");
+
+ if (IS_ERR(dram_pll_clk) || IS_ERR(sys1_pll_400m) || IS_ERR(sys1_pll_100m) ||
+ IS_ERR(sys1_pll_40m) || IS_ERR(dram_alt_src) || IS_ERR(dram_alt_root) ||
+ IS_ERR(dram_core_clk) || IS_ERR(dram_apb_src) || IS_ERR(dram_apb_pre_div)
+ || IS_ERR(noc_div) || IS_ERR(main_axi_src) || IS_ERR(ahb_div)
+ || IS_ERR(osc_25m) || IS_ERR(sys2_pll_333m)) {
+ dev_err(&pdev->dev, "failed to get busfreq clk\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int imx8mm_init_busfreq_clk(struct platform_device *pdev)
+{
+ dram_pll_clk = devm_clk_get(&pdev->dev, "dram_pll");
+ dram_alt_src = devm_clk_get(&pdev->dev, "dram_alt_src");
+ dram_alt_root = devm_clk_get(&pdev->dev, "dram_alt_root");
+ dram_core_clk = devm_clk_get(&pdev->dev, "dram_core");
+ dram_apb_src = devm_clk_get(&pdev->dev, "dram_apb_src");
+ dram_apb_pre_div = devm_clk_get(&pdev->dev, "dram_apb_pre_div");
+ sys1_pll_800m = devm_clk_get(&pdev->dev, "sys_pll1_800m");
+ sys1_pll_100m = devm_clk_get(&pdev->dev, "sys_pll1_100m");
+ sys1_pll_40m = devm_clk_get(&pdev->dev, "sys_pll1_40m");
+ noc_div = devm_clk_get(&pdev->dev, "noc_div");
+ ahb_div = devm_clk_get(&pdev->dev, "ahb_div");
+ main_axi_src = devm_clk_get(&pdev->dev, "main_axi_src");
+ osc_25m = devm_clk_get(&pdev->dev, "osc_24m");
+ sys2_pll_333m = devm_clk_get(&pdev->dev, "sys_pll2_333m");
+
+ if (IS_ERR(dram_pll_clk) || IS_ERR(dram_alt_src) || IS_ERR(dram_alt_root) ||
+ IS_ERR(dram_core_clk) || IS_ERR(dram_apb_src) || IS_ERR(dram_apb_pre_div) ||
+ IS_ERR(sys1_pll_800m) || IS_ERR(sys1_pll_100m) || IS_ERR(sys1_pll_40m) ||
+ IS_ERR(osc_25m) || IS_ERR(noc_div) || IS_ERR(main_axi_src) || IS_ERR(ahb_div) ||
+ IS_ERR(sys2_pll_333m)) {
+ dev_err(&pdev->dev, "failed to get busfreq clk\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*!
+ * This is the probe routine for the bus frequency driver.
+ *
+ * @param pdev The platform device structure
+ *
+ * @return The function returns 0 on success
+ *
+ */
+static int busfreq_probe(struct platform_device *pdev)
+{
+ int err;
+
+ busfreq_dev = &pdev->dev;
+
+ /* get the clock for DDRC */
+ if (of_machine_is_compatible("fsl,imx8mq"))
+ err = imx8mq_init_busfreq_clk(pdev);
+ else
+ err = imx8mm_init_busfreq_clk(pdev);
+
+ if (err) {
+ dev_err(busfreq_dev, "init clk failed\n");
+ return err;
+ }
+
+ /* init the irq used for ddr frequency change */
+ err = init_busfreq_irq(pdev);
+ if (err) {
+ dev_err(busfreq_dev, "init busfreq irq failed!\n");
+ return err;
+ }
+
+ /* create the sysfs file */
+ err = sysfs_create_file(&busfreq_dev->kobj, &dev_attr_enable.attr);
+ if (err) {
+ dev_err(busfreq_dev,
+ "Unable to register sysdev entry for BUSFREQ");
+ return err;
+ }
+
+ high_bus_freq_mode = 1;
+ low_bus_freq_mode = 0;
+ audio_bus_freq_mode = 0;
+ cur_bus_freq_mode = BUS_FREQ_HIGH;
+
+ bus_freq_scaling_is_active = 1;
+ bus_freq_scaling_initialized = 1;
+
+ INIT_DELAYED_WORK(&low_bus_freq_handler, reduce_bus_freq_handler);
+ INIT_DELAYED_WORK(&bus_freq_daemon, bus_freq_daemon_handler);
+ register_pm_notifier(&imx_bus_freq_pm_notifier);
+ register_reboot_notifier(&imx_busfreq_reboot_notifier);
+
+ /* enter low bus mode if no high speed device enabled */
+ schedule_delayed_work(&bus_freq_daemon, msecs_to_jiffies(10000));
+
+ return 0;
+}
+
+static const struct of_device_id imx_busfreq_ids[] = {
+ { .compatible = "fsl,imx_busfreq", },
+ { /*sentinel */}
+};
+
+static struct platform_driver busfreq_driver = {
+ .driver = {
+ .name = "imx_busfreq",
+ .owner = THIS_MODULE,
+ .of_match_table = imx_busfreq_ids,
+ },
+ .probe = busfreq_probe,
+};
+
+/*!
+ * Initialise the busfreq_driver.
+ *
+ * @return The function always returns 0.
+ */
+static int __init busfreq_init(void)
+{
+ if (platform_driver_register(&busfreq_driver) != 0)
+ return -ENODEV;
+
+ printk(KERN_INFO "Bus freq driver module loaded\n");
+
+ return 0;
+}
+
+static void __exit busfreq_cleanup(void)
+{
+ sysfs_remove_file(&busfreq_dev->kobj, &dev_attr_enable.attr);
+
+ /* Unregister the device structure */
+ platform_driver_unregister(&busfreq_driver);
+ bus_freq_scaling_initialized = 0;
+}
+
+module_init(busfreq_init);
+module_exit(busfreq_cleanup);
+
+MODULE_AUTHOR("NXP Semiconductor, Inc.");
+MODULE_DESCRIPTION("Busfreq driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/soc/imx/gpc-psci.c b/drivers/soc/imx/gpc-psci.c
new file mode 100644
index 000000000000..92d334d612ea
--- /dev/null
+++ b/drivers/soc/imx/gpc-psci.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/clk.h>
+#include <linux/cpumask.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_domain.h>
+#include <soc/imx/fsl_sip.h>
+
+#define GPC_MAX_IRQS (4 * 32)
+
+struct imx_gpc_pm_domain {
+ const char name[30];
+ struct device *dev;
+ struct generic_pm_domain pd;
+ u32 gpc_domain_id;
+ struct clk **clks;
+ unsigned int num_clks;
+ struct regulator *reg;
+};
+
+enum imx_gpc_pm_domain_state {
+ GPC_PD_STATE_OFF,
+ GPC_PD_STATE_ON,
+};
+
+#define to_imx_gpc_pm_domain(_genpd) container_of(_genpd, struct imx_gpc_pm_domain, pd)
+
+static DEFINE_SPINLOCK(gpc_psci_lock);
+static DEFINE_MUTEX(gpc_pd_mutex);
+
+static void imx_gpc_psci_irq_unmask(struct irq_data *d)
+{
+ struct arm_smccc_res res;
+
+ spin_lock(&gpc_psci_lock);
+ arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_UNMASK, d->hwirq,
+ 0, 0, 0, 0, 0, &res);
+ spin_unlock(&gpc_psci_lock);
+
+ irq_chip_unmask_parent(d);
+}
+
+static void imx_gpc_psci_irq_mask(struct irq_data *d)
+{
+ struct arm_smccc_res res;
+
+ spin_lock(&gpc_psci_lock);
+ arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_MASK, d->hwirq,
+ 0, 0, 0, 0, 0, &res);
+ spin_unlock(&gpc_psci_lock);
+
+ irq_chip_mask_parent(d);
+}
+static int imx_gpc_psci_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+ struct arm_smccc_res res;
+
+ spin_lock(&gpc_psci_lock);
+ arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_SET_WAKE, d->hwirq,
+ on, 0, 0, 0, 0, &res);
+ spin_unlock(&gpc_psci_lock);
+
+ return 0;
+}
+
+static int imx_gpc_psci_irq_set_affinity(struct irq_data *d,
+ const struct cpumask *dest, bool force)
+{
+ /* parse the cpu of irq affinity */
+ struct arm_smccc_res res;
+ unsigned int cpu = cpumask_any_and(dest, cpu_online_mask);
+
+ irq_chip_set_affinity_parent(d, dest, force);
+
+ spin_lock(&gpc_psci_lock);
+ arm_smccc_smc(FSL_SIP_GPC, 0x4, d->hwirq,
+ cpu, 0, 0, 0, 0, &res);
+ spin_unlock(&gpc_psci_lock);
+
+ return 0;
+}
+
+static struct irq_chip imx_gpc_psci_chip = {
+ .name = "GPC-PSCI",
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_mask = imx_gpc_psci_irq_mask,
+ .irq_unmask = imx_gpc_psci_irq_unmask,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
+ .irq_set_wake = imx_gpc_psci_irq_set_wake,
+ .irq_set_affinity = imx_gpc_psci_irq_set_affinity,
+};
+
+static int imx_gpc_psci_domain_translate(struct irq_domain *d,
+ struct irq_fwspec *fwspec,
+ unsigned long *hwirq,
+ unsigned int *type)
+{
+ if (is_of_node(fwspec->fwnode)) {
+ if (fwspec->param_count != 3)
+ return -EINVAL;
+
+ /* No PPI should point to this domain */
+ if (fwspec->param[0] != 0)
+ return -EINVAL;
+
+ *hwirq = fwspec->param[1];
+ *type = fwspec->param[2];
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int imx_gpc_psci_domain_alloc(struct irq_domain *domain,
+ unsigned int irq,
+ unsigned int nr_irqs, void *data)
+{
+ struct irq_fwspec *fwspec = data;
+ struct irq_fwspec parent_fwspec;
+ irq_hw_number_t hwirq;
+ int i;
+
+ if (fwspec->param_count != 3)
+ return -EINVAL; /* Not GIC compliant */
+ if (fwspec->param[0] != 0)
+ return -EINVAL; /* No PPI should point to this domain */
+
+ hwirq = fwspec->param[1];
+ if (hwirq >= GPC_MAX_IRQS)
+ return -EINVAL; /* Can't deal with this */
+
+ for (i = 0; i < nr_irqs; i++)
+ irq_domain_set_hwirq_and_chip(domain, irq + i, hwirq + i,
+ &imx_gpc_psci_chip, NULL);
+
+ parent_fwspec = *fwspec;
+ parent_fwspec.fwnode = domain->parent->fwnode;
+
+ return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs,
+ &parent_fwspec);
+}
+
+static struct irq_domain_ops imx_gpc_psci_domain_ops = {
+ .translate = imx_gpc_psci_domain_translate,
+ .alloc = imx_gpc_psci_domain_alloc,
+ .free = irq_domain_free_irqs_common,
+};
+
+static int __init imx_gpc_psci_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct irq_domain *parent_domain, *domain;
+
+ if (!parent) {
+ pr_err("%s: no parent, giving up\n", node->full_name);
+ return -ENODEV;
+ }
+
+ parent_domain = irq_find_host(parent);
+ if (!parent_domain) {
+ pr_err("%s: unable to obtain parent domain\n", node->full_name);
+ return -ENXIO;
+ }
+
+ domain = irq_domain_add_hierarchy(parent_domain, 0, GPC_MAX_IRQS,
+ node, &imx_gpc_psci_domain_ops,
+ NULL);
+ if (!domain)
+ return -ENOMEM;
+
+ return 0;
+}
+IRQCHIP_DECLARE(imx_gpc_psci, "fsl,imx8mq-gpc", imx_gpc_psci_init);
+
+static int imx_gpc_pd_power_on(struct generic_pm_domain *domain)
+{
+ struct imx_gpc_pm_domain *pd = to_imx_gpc_pm_domain(domain);
+ struct arm_smccc_res res;
+ int index, ret = 0;
+
+ /* power on the external supply */
+ if (pd->reg) {
+ ret = regulator_enable(pd->reg);
+ if (ret) {
+ dev_warn(pd->dev, "failed to power up the reg%d\n", ret);
+ return ret;
+ }
+ }
+
+ /* enable the necessary clks needed by the power domain */
+ if (pd->num_clks) {
+ for (index = 0; index < pd->num_clks; index++)
+ clk_prepare_enable(pd->clks[index]);
+ }
+
+ mutex_lock(&gpc_pd_mutex);
+ arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_PM_DOMAIN, pd->gpc_domain_id,
+ GPC_PD_STATE_ON, 0, 0, 0, 0, &res);
+ mutex_unlock(&gpc_pd_mutex);
+
+ return 0;
+}
+
+static int imx_gpc_pd_power_off(struct generic_pm_domain *domain)
+{
+ struct imx_gpc_pm_domain *pd = to_imx_gpc_pm_domain(domain);
+ struct arm_smccc_res res;
+ int index, ret = 0;
+
+ mutex_lock(&gpc_pd_mutex);
+ arm_smccc_smc(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_PM_DOMAIN, pd->gpc_domain_id,
+ GPC_PD_STATE_OFF, 0, 0, 0, 0, &res);
+ mutex_unlock(&gpc_pd_mutex);
+
+ /* power off the external supply */
+ if (pd->reg) {
+ ret = regulator_disable(pd->reg);
+ if (ret) {
+ dev_warn(pd->dev, "failed to power off the reg%d\n", ret);
+ return ret;
+ }
+ }
+
+ /* disable the necessary clks when power domain on finished */
+ if (pd->num_clks) {
+ for (index = 0; index < pd->num_clks; index++)
+ clk_disable_unprepare(pd->clks[index]);
+ }
+
+ return ret;
+};
+
+static int imx8m_pd_clk_init(struct device_node *np,
+ struct imx_gpc_pm_domain *domain)
+{
+ struct property *pp;
+ struct clk **clks;
+ int index;
+
+ pp = of_find_property(np, "clocks", NULL);
+ if (pp)
+ domain->num_clks = pp->length / 8;
+ else
+ domain->num_clks = 0;
+
+ if (domain->num_clks) {
+ clks = kcalloc(domain->num_clks, sizeof(*clks), GFP_KERNEL);
+ if (!clks) {
+ domain->num_clks = 0;
+ domain->clks = NULL;
+ return -ENOMEM;
+ }
+
+ domain->clks = clks;
+ }
+
+ for (index = 0; index < domain->num_clks; index++) {
+ clks[index] = of_clk_get(np, index);
+ if (IS_ERR(clks[index])) {
+ for (index = 0; index < domain->num_clks; index++) {
+ if (!IS_ERR(clks[index]))
+ clk_put(clks[index]);
+ }
+
+ domain->num_clks = 0;
+ domain->clks = NULL;
+ kfree(clks);
+ pr_warn("imx8m domain clock init failed\n");
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+}
+
+static int imx8m_add_subdomain(struct device_node *parent,
+ struct generic_pm_domain *parent_pd)
+{
+ struct device_node *child_node;
+ struct imx_gpc_pm_domain *child_domain;
+ int ret = 0;
+
+ /* add each of the child domain of parent */
+ for_each_child_of_node(parent, child_node) {
+ if (!of_device_is_available(child_node))
+ continue;
+
+ child_domain = kzalloc(sizeof(*child_domain), GFP_KERNEL);
+ if (!child_domain)
+ return -ENOMEM;
+
+ ret = of_property_read_string(child_node, "domain-name",
+ &child_domain->pd.name);
+ if (ret)
+ goto exit;
+
+ ret = of_property_read_u32(child_node, "domain-id",
+ &child_domain->gpc_domain_id);
+ if (ret)
+ goto exit;
+
+ child_domain->pd.power_off = imx_gpc_pd_power_off;
+ child_domain->pd.power_on = imx_gpc_pd_power_on;
+ /* no reg for subdomains */
+ child_domain->reg = NULL;
+
+ imx8m_pd_clk_init(child_node, child_domain);
+
+ /* power domains as off at boot */
+ pm_genpd_init(&child_domain->pd, NULL, true);
+
+ /* add subdomain of parent power domain */
+ pm_genpd_add_subdomain(parent_pd, &child_domain->pd);
+
+ ret = of_genpd_add_provider_simple(child_node,
+ &child_domain->pd);
+ if (ret)
+ pr_err("failed to add subdomain\n");
+ }
+
+ return 0;
+exit:
+ kfree(child_domain);
+ return ret;
+};
+
+static int imx_gpc_pm_domain_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct imx_gpc_pm_domain *imx_pm_domain;
+ int ret = 0;
+
+ if (!np) {
+ dev_err(dev, "power domain device tree node not found\n");
+ return -ENODEV;
+ }
+
+ imx_pm_domain = devm_kzalloc(dev, sizeof(*imx_pm_domain), GFP_KERNEL);
+ if (!imx_pm_domain)
+ return -ENOMEM;
+ imx_pm_domain->dev = dev;
+
+ ret = of_property_read_string(np, "domain-name", &imx_pm_domain->pd.name);
+ if (ret) {
+ dev_err(dev, "get domain name failed\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(np, "domain-id", &imx_pm_domain->gpc_domain_id);
+ if (ret) {
+ dev_err(dev, "get domain id failed\n");
+ return -EINVAL;
+ }
+
+ imx_pm_domain->reg = devm_regulator_get_optional(dev, "power");
+ if (IS_ERR(imx_pm_domain->reg)) {
+ if (PTR_ERR(imx_pm_domain->reg) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ imx_pm_domain->reg = NULL;
+ }
+
+ imx8m_pd_clk_init(np, imx_pm_domain);
+
+ imx_pm_domain->pd.power_off = imx_gpc_pd_power_off;
+ imx_pm_domain->pd.power_on = imx_gpc_pd_power_on;
+ /* all power domains as off at boot */
+ pm_genpd_init(&imx_pm_domain->pd, NULL, true);
+
+ ret = of_genpd_add_provider_simple(np,
+ &imx_pm_domain->pd);
+
+ /* add subdomain */
+ ret = imx8m_add_subdomain(np, &imx_pm_domain->pd);
+ if (ret)
+ dev_warn(dev, "please check the child power domain init\n");
+
+ return 0;
+}
+
+static const struct of_device_id imx_gpc_pm_domain_ids[] = {
+ {.compatible = "fsl,imx8mq-pm-domain"},
+ {.compatible = "fsl,imx8mm-pm-domain"},
+ {},
+};
+
+static struct platform_driver imx_gpc_pm_domain_driver = {
+ .driver = {
+ .name = "imx8m_gpc_pm_domain",
+ .owner = THIS_MODULE,
+ .of_match_table = imx_gpc_pm_domain_ids,
+ },
+ .probe = imx_gpc_pm_domain_probe,
+};
+
+module_platform_driver(imx_gpc_pm_domain_driver);
+
+MODULE_AUTHOR("NXP");
+MODULE_DESCRIPTION("NXP i.MX8M GPC power domain driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/imx/mu/Makefile b/drivers/soc/imx/mu/Makefile
new file mode 100644
index 000000000000..922308c3f90f
--- /dev/null
+++ b/drivers/soc/imx/mu/Makefile
@@ -0,0 +1 @@
+obj-y += mx8_mu.o
diff --git a/drivers/soc/imx/mu/mx8_mu.c b/drivers/soc/imx/mu/mx8_mu.c
new file mode 100644
index 000000000000..30c7fd888cb4
--- /dev/null
+++ b/drivers/soc/imx/mu/mx8_mu.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mx8_mu.h>
+#include <linux/of.h>
+
+static int version;
+
+/*!
+ * This function sets the Flag n of the MU.
+ */
+int32_t MU_SetFn(void __iomem *base, uint32_t Fn)
+{
+ uint32_t reg, offset;
+
+ reg = Fn & (~MU_CR_Fn_MASK1);
+ if (reg > 0)
+ return -EINVAL;
+
+ offset = unlikely(version == MU_VER_ID_V10)
+ ? MU_V10_ACR_OFFSET1 : MU_ACR_OFFSET1;
+
+ reg = readl_relaxed(base + offset);
+ /* Clear ABFn. */
+ reg &= ~MU_CR_Fn_MASK1;
+ reg |= Fn;
+ writel_relaxed(reg, base + offset);
+
+ return 0;
+}
+
+/*!
+ * This function reads the status from status register.
+ */
+uint32_t MU_ReadStatus(void __iomem *base)
+{
+ uint32_t reg, offset;
+
+ offset = unlikely(version == MU_VER_ID_V10)
+ ? MU_V10_ASR_OFFSET1 : MU_ASR_OFFSET1;
+
+ reg = readl_relaxed(base + offset);
+
+ return reg;
+}
+
+/*!
+ * This function enables specific RX full interrupt.
+ */
+void MU_EnableRxFullInt(void __iomem *base, uint32_t index)
+{
+ uint32_t reg, offset;
+
+ offset = unlikely(version == MU_VER_ID_V10)
+ ? MU_V10_ACR_OFFSET1 : MU_ACR_OFFSET1;
+
+ reg = readl_relaxed(base + offset);
+ reg &= ~(MU_CR_GIRn_MASK1 | MU_CR_NMI_MASK1);
+ reg |= MU_CR_RIE0_MASK1 >> index;
+ writel_relaxed(reg, base + offset);
+}
+
+/*!
+ * This function enables specific general purpose interrupt.
+ */
+void MU_EnableGeneralInt(void __iomem *base, uint32_t index)
+{
+ uint32_t reg, offset;
+
+ offset = unlikely(version == MU_VER_ID_V10)
+ ? MU_V10_ACR_OFFSET1 : MU_ACR_OFFSET1;
+
+ reg = readl_relaxed(base + offset);
+ reg &= ~(MU_CR_GIRn_MASK1 | MU_CR_NMI_MASK1);
+ reg |= MU_CR_GIE0_MASK1 >> index;
+ writel_relaxed(reg, base + offset);
+}
+
+/*
+ * Wait and send message to the other core.
+ */
+void MU_SendMessage(void __iomem *base, uint32_t regIndex, uint32_t msg)
+{
+ uint32_t mask = MU_SR_TE0_MASK1 >> regIndex;
+
+ if (unlikely(version == MU_VER_ID_V10)) {
+ /* Wait TX register to be empty. */
+ while (!(readl_relaxed(base + MU_V10_ASR_OFFSET1) & mask))
+ ;
+ writel_relaxed(msg, base + MU_V10_ATR0_OFFSET1
+ + (regIndex * 4));
+ } else {
+ /* Wait TX register to be empty. */
+ while (!(readl_relaxed(base + MU_ASR_OFFSET1) & mask))
+ ;
+ writel_relaxed(msg, base + MU_ATR0_OFFSET1 + (regIndex * 4));
+ }
+}
+
+
+/*
+ * Wait to receive message from the other core.
+ */
+void MU_ReceiveMsg(void __iomem *base, uint32_t regIndex, uint32_t *msg)
+{
+ uint32_t mask = MU_SR_RF0_MASK1 >> regIndex;
+
+ if (unlikely(version == MU_VER_ID_V10)) {
+ /* Wait RX register to be full. */
+ while (!(readl_relaxed(base + MU_V10_ASR_OFFSET1) & mask))
+ ;
+ *msg = readl_relaxed(base + MU_V10_ARR0_OFFSET1
+ + (regIndex * 4));
+ } else {
+ /* Wait RX register to be full. */
+ while (!(readl_relaxed(base + MU_ASR_OFFSET1) & mask))
+ ;
+ *msg = readl_relaxed(base + MU_ARR0_OFFSET1 + (regIndex * 4));
+ }
+}
+
+
+
+void MU_Init(void __iomem *base)
+{
+ uint32_t reg, offset;
+
+ version = readl_relaxed(base) >> 16;
+
+ offset = unlikely(version == MU_VER_ID_V10)
+ ? MU_V10_ACR_OFFSET1 : MU_ACR_OFFSET1;
+
+ reg = readl_relaxed(base + offset);
+ /* Clear GIEn, TIEn, GIRn and ABFn. */
+ reg &= ~(MU_CR_GIEn_MASK1 | MU_CR_TIEn_MASK1
+ | MU_CR_GIRn_MASK1 | MU_CR_NMI_MASK1 | MU_CR_Fn_MASK1);
+
+ /*
+ * i.MX6SX and i.MX7D have multi-core power management which need
+ * to use RIE interrupts.
+ */
+ if (!(of_machine_is_compatible("fsl,imx6sx") ||
+ of_machine_is_compatible("fsl,imx7d")))
+ reg &= ~MU_CR_RIEn_MASK1;
+
+ writel_relaxed(reg, base + offset);
+}
+
+/**@}*/
+
diff --git a/drivers/soc/imx/pm-domain-imx8.h b/drivers/soc/imx/pm-domain-imx8.h
new file mode 100644
index 000000000000..58b5328e47e5
--- /dev/null
+++ b/drivers/soc/imx/pm-domain-imx8.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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 PM_DOMAIN_IMX8_H
+#define PM_DOMAIN_IMX8_H
+
+#include <linux/clk.h>
+#include <linux/pm_domain.h>
+#include <soc/imx8/sc/sci.h>
+
+#define DEFAULT_DEV_LATENCY_NS 250000
+
+struct platform_device;
+
+struct imx8_pm_rsrc_clks {
+ struct clk *clk;
+ struct clk *parent;
+ u32 rate;
+ struct list_head node;
+};
+
+struct imx8_pm_domain {
+ const char *name;
+ struct generic_pm_domain pd;
+ struct dev_power_governor *gov;
+ int (*suspend)(void);
+ void (*resume)(void);
+ sc_rsrc_t rsrc_id;
+ bool runtime_idle_active;
+ struct list_head clks;
+
+ /* indicate the possible clk state lost */
+ bool clk_state_saved;
+ bool clk_state_may_lost;
+};
+
+static inline
+struct imx8_pm_domain *to_imx8_pd(struct generic_pm_domain *d)
+{
+ return container_of(d, struct imx8_pm_domain, pd);
+}
+
+struct pm_domain_device {
+ const char *domain_name;
+ struct platform_device *pdev;
+};
+
+#endif /* PM_DOMAIN_IMX8_H */
diff --git a/drivers/soc/imx/pm-domains.c b/drivers/soc/imx/pm-domains.c
new file mode 100644
index 000000000000..50f5d1574704
--- /dev/null
+++ b/drivers/soc/imx/pm-domains.c
@@ -0,0 +1,638 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_clock.h>
+#include <linux/slab.h>
+#include <linux/syscore_ops.h>
+
+#include <soc/imx/fsl_sip.h>
+#include <soc/imx8/sc/sci.h>
+
+#include "pm-domain-imx8.h"
+
+static sc_ipc_t pm_ipc_handle;
+static sc_rsrc_t early_power_on_rsrc[] = {
+ SC_R_LAST, SC_R_LAST, SC_R_LAST, SC_R_LAST, SC_R_LAST,
+ SC_R_LAST, SC_R_LAST, SC_R_LAST, SC_R_LAST, SC_R_LAST,
+};
+static sc_rsrc_t rsrc_debug_console;
+
+#define IMX8_WU_MAX_IRQS (((SC_R_LAST + 31) / 32 ) * 32 )
+static sc_rsrc_t irq2rsrc[IMX8_WU_MAX_IRQS];
+static sc_rsrc_t wakeup_rsrc_id[IMX8_WU_MAX_IRQS / 32];
+static DEFINE_SPINLOCK(imx8_wu_lock);
+static DEFINE_MUTEX(rsrc_pm_list_lock);
+
+enum imx_pd_state {
+ PD_LP,
+ PD_OFF,
+};
+
+struct clk_stat {
+ struct clk *clk;
+ struct clk *parent;
+ unsigned long rate;
+};
+
+static int imx8_pd_power(struct generic_pm_domain *domain, bool power_on)
+{
+ struct imx8_pm_domain *pd;
+ sc_err_t sci_err = SC_ERR_NONE;
+
+ pd = container_of(domain, struct imx8_pm_domain, pd);
+
+ if (pd->rsrc_id == SC_R_LAST)
+ return 0;
+
+ /* keep uart console power on for no_console_suspend */
+ if (pd->rsrc_id == rsrc_debug_console &&
+ !console_suspend_enabled && !power_on)
+ return 0;
+
+ /* keep resource power on if it is a wakeup source */
+ if (!power_on && ((1 << pd->rsrc_id % 32) &
+ wakeup_rsrc_id[pd->rsrc_id / 32]))
+ return 0;
+
+ sci_err = sc_pm_set_resource_power_mode(pm_ipc_handle, pd->rsrc_id,
+ (power_on) ? SC_PM_PW_MODE_ON :
+ pd->pd.state_idx ? SC_PM_PW_MODE_OFF : SC_PM_PW_MODE_LP);
+ if (sci_err)
+ pr_err("Failed power operation on resource %d\n", pd->rsrc_id);
+
+ return 0;
+}
+
+static int imx8_pd_power_on(struct generic_pm_domain *domain)
+{
+ struct imx8_pm_domain *pd;
+ struct imx8_pm_rsrc_clks *imx8_rsrc_clk;
+ int ret = 0;
+
+ pd = container_of(domain, struct imx8_pm_domain, pd);
+
+ ret = imx8_pd_power(domain, true);
+
+ if (!list_empty(&pd->clks) && (pd->pd.state_idx == PD_OFF)) {
+
+ if (pd->clk_state_saved) {
+ /*
+ * The SS is powered on restore the clock rates that
+ * may be lost.
+ */
+ list_for_each_entry(imx8_rsrc_clk, &pd->clks, node) {
+
+ if (imx8_rsrc_clk->parent)
+ clk_set_parent(imx8_rsrc_clk->clk,
+ imx8_rsrc_clk->parent);
+
+ if (imx8_rsrc_clk->rate) {
+ /*
+ * Need to read the clock so that rate in
+ * Linux is reset.
+ */
+ clk_get_rate(imx8_rsrc_clk->clk);
+ /* Restore the clock rate. */
+ clk_set_rate(imx8_rsrc_clk->clk,
+ imx8_rsrc_clk->rate);
+ }
+ }
+ } else if (pd->clk_state_may_lost) {
+ struct clk_stat *clk_stats;
+ int count = 0;
+ int i = 0;
+ /*
+ * The SS is powered down before without saving clk rates,
+ * try to restore the lost clock rates if any
+ *
+ * As a parent clk rate restore will cause the clk recalc
+ * to all possible child clks which may result in child clk
+ * previous state lost due to power domain lost before, we
+ * have to first walk through all child clks to retrieve the
+ * state via clk_hw_get_rate which bypassed the clk recalc,
+ * then we can restore them one by one.
+ */
+ list_for_each_entry(imx8_rsrc_clk, &pd->clks, node)
+ count++;
+
+ clk_stats = kzalloc(count * sizeof(*clk_stats), GFP_KERNEL);
+ if (!clk_stats) {
+ pr_warn("%s: failed to alloc mem for clk state recovery\n", pd->name);
+ return -ENOMEM;
+ }
+
+ list_for_each_entry(imx8_rsrc_clk, &pd->clks, node) {
+ clk_stats[i].clk = imx8_rsrc_clk->clk;
+ clk_stats[i].parent = clk_get_parent(imx8_rsrc_clk->clk);
+ clk_stats[i].rate = clk_hw_get_rate(__clk_get_hw(imx8_rsrc_clk->clk));
+ i++;
+ }
+
+ for (i = 0; i < count; i++) {
+ /* restore parent first */
+ if (clk_stats[i].parent)
+ clk_set_parent(clk_stats[i].clk, clk_stats[i].parent);
+
+ if (clk_stats[i].rate) {
+ /* invalid cached rate first by get rate once */
+ clk_get_rate(clk_stats[i].clk);
+ /* restore the lost rate */
+ clk_set_rate(clk_stats[i].clk, clk_stats[i].rate);
+ }
+ }
+
+ kfree(clk_stats);
+ }
+ }
+
+ return ret;
+}
+
+static int imx8_pd_power_off(struct generic_pm_domain *domain)
+{
+ struct imx8_pm_domain *pd;
+ struct imx8_pm_rsrc_clks *imx8_rsrc_clk;
+
+ pd = container_of(domain, struct imx8_pm_domain, pd);
+
+ if (!list_empty(&pd->clks) && (pd->pd.state_idx == PD_OFF)) {
+ /*
+ * The SS is going to be powered off, store the clock rates
+ * that may be lost.
+ */
+ list_for_each_entry(imx8_rsrc_clk, &pd->clks, node) {
+ imx8_rsrc_clk->parent = clk_get_parent(imx8_rsrc_clk->clk);
+ imx8_rsrc_clk->rate = clk_hw_get_rate(__clk_get_hw(imx8_rsrc_clk->clk));
+ }
+ pd->clk_state_saved = true;
+ pd->clk_state_may_lost = false;
+ } else if (pd->pd.state_idx == PD_OFF) {
+ pd->clk_state_saved = false;
+ pd->clk_state_may_lost = true;
+ } else {
+ pd->clk_state_saved = false;
+ pd->clk_state_may_lost = false;
+ }
+ return imx8_pd_power(domain, false);
+}
+
+static int imx8_attach_dev(struct generic_pm_domain *genpd, struct device *dev)
+{
+ struct imx8_pm_domain *pd;
+ struct device_node *node = dev->of_node;
+ struct of_phandle_args clkspec;
+ int rc, index, num_clks;
+
+ pd = container_of(genpd, struct imx8_pm_domain, pd);
+
+ num_clks = of_count_phandle_with_args(node, "assigned-clocks",
+ "#clock-cells");
+ if (num_clks == -EINVAL)
+ pr_err("%s: Invalid value of assigned-clocks property at %s\n",
+ pd->name, node->full_name);
+
+ for (index = 0; index < num_clks; index++) {
+ struct imx8_pm_rsrc_clks *imx8_rsrc_clk;
+
+ rc = of_parse_phandle_with_args(node, "assigned-clocks",
+ "#clock-cells", index, &clkspec);
+ if (rc < 0) {
+ /* skip empty (null) phandles */
+ if (rc == -ENOENT)
+ continue;
+ else
+ return rc;
+ }
+ if (clkspec.np == node)
+ return 0;
+
+ imx8_rsrc_clk = devm_kzalloc(dev, sizeof(*imx8_rsrc_clk),
+ GFP_KERNEL);
+ if (!imx8_rsrc_clk)
+ return -ENOMEM;
+
+ imx8_rsrc_clk->clk = of_clk_get_from_provider(&clkspec);
+ if (!IS_ERR(imx8_rsrc_clk->clk))
+ list_add_tail(&imx8_rsrc_clk->node, &pd->clks);
+ }
+ return 0;
+}
+
+static void imx8_detach_dev(struct generic_pm_domain *genpd, struct device *dev)
+{
+ struct imx8_pm_domain *pd;
+ struct imx8_pm_rsrc_clks *imx8_rsrc_clk, *tmp;
+
+ pd = container_of(genpd, struct imx8_pm_domain, pd);
+
+ /* Free all the clock entry nodes. */
+ if (list_empty(&pd->clks))
+ return;
+
+ list_for_each_entry_safe(imx8_rsrc_clk, tmp, &pd->clks, node) {
+ list_del(&imx8_rsrc_clk->node);
+ devm_kfree(dev, imx8_rsrc_clk);
+ }
+}
+
+static int imx8_pm_domains_suspend(void)
+{
+ struct arm_smccc_res res;
+ unsigned int i;
+
+ for (i = 0; i < IMX8_WU_MAX_IRQS / 32; i++) {
+ if (wakeup_rsrc_id[i] != 0) {
+ arm_smccc_smc(FSL_SIP_WAKEUP_SRC,
+ FSL_SIP_WAKEUP_SRC_IRQSTEER, 0,
+ 0, 0, 0, 0, 0, &res);
+ return 0;
+ }
+ }
+
+ arm_smccc_smc(FSL_SIP_WAKEUP_SRC,
+ FSL_SIP_WAKEUP_SRC_SCU, 0,
+ 0, 0, 0, 0, 0, &res);
+
+ return 0;
+}
+
+static void imx8_pm_domains_resume(void)
+{
+ sc_err_t sci_err = SC_ERR_NONE;
+ int i;
+
+ for (i = 0; i < (sizeof(early_power_on_rsrc) /
+ sizeof(sc_rsrc_t)); i++) {
+ if (early_power_on_rsrc[i] != SC_R_LAST) {
+ sci_err = sc_pm_set_resource_power_mode(pm_ipc_handle,
+ early_power_on_rsrc[i], SC_PM_PW_MODE_ON);
+ if (sci_err != SC_ERR_NONE)
+ pr_err("fail to power on resource %d\n",
+ early_power_on_rsrc[i]);
+ }
+ }
+}
+
+struct syscore_ops imx8_pm_domains_syscore_ops = {
+ .suspend = imx8_pm_domains_suspend,
+ .resume = imx8_pm_domains_resume,
+};
+
+static void imx8_pd_setup(struct imx8_pm_domain *pd)
+{
+ pd->pd.power_off = imx8_pd_power_off;
+ pd->pd.power_on = imx8_pd_power_on;
+ pd->pd.attach_dev = imx8_attach_dev;
+ pd->pd.detach_dev = imx8_detach_dev;
+
+ pd->pd.states[0].power_off_latency_ns = 25000;
+ pd->pd.states[0].power_on_latency_ns = 25000;
+ pd->pd.states[1].power_off_latency_ns = 2500000;
+ pd->pd.states[1].power_on_latency_ns = 2500000;
+
+ pd->pd.state_count = 2;
+}
+
+static int __init imx8_add_pm_domains(struct device_node *parent,
+ struct generic_pm_domain *genpd_parent)
+{
+ struct device_node *np;
+ static int index;
+
+ for_each_child_of_node(parent, np) {
+ struct imx8_pm_domain *imx8_pd;
+ sc_rsrc_t rsrc_id;
+ u32 wakeup_irq;
+
+ if (!of_device_is_available(np))
+ continue;
+
+ imx8_pd = kzalloc(sizeof(*imx8_pd), GFP_KERNEL);
+ if (!imx8_pd)
+ return -ENOMEM;
+
+ if (!of_property_read_string(np, "name", &imx8_pd->pd.name))
+ imx8_pd->name = imx8_pd->pd.name;
+
+ if (!of_property_read_u32(np, "reg", &rsrc_id))
+ imx8_pd->rsrc_id = rsrc_id;
+
+ if (imx8_pd->rsrc_id != SC_R_LAST) {
+ imx8_pd_setup(imx8_pd);
+
+ if (of_property_read_bool(np, "early_power_on")
+ && index < (sizeof(early_power_on_rsrc) /
+ sizeof(sc_rsrc_t))) {
+ early_power_on_rsrc[index++] = imx8_pd->rsrc_id;
+ }
+ if (of_property_read_bool(np, "debug_console"))
+ rsrc_debug_console = imx8_pd->rsrc_id;
+ if (!of_property_read_u32(np, "wakeup-irq",
+ &wakeup_irq))
+ irq2rsrc[wakeup_irq] = imx8_pd->rsrc_id;
+ }
+ INIT_LIST_HEAD(&imx8_pd->clks);
+ pm_genpd_init(&imx8_pd->pd, NULL, true);
+
+ if (genpd_parent)
+ pm_genpd_add_subdomain(genpd_parent, &imx8_pd->pd);
+
+ of_genpd_add_provider_simple(np, &imx8_pd->pd);
+
+ imx8_add_pm_domains(np, &imx8_pd->pd);
+ }
+ return 0;
+}
+
+static int __init imx8_init_pm_domains(void)
+{
+ struct device_node *np;
+ sc_err_t sci_err;
+ sc_rsrc_t rsrc_id;
+ uint32_t mu_id;
+
+ /* skip pm domains for non-SCFW system */
+ if (!of_find_compatible_node(NULL, NULL, "nxp,imx8-pd"))
+ return 0;
+
+ pr_info("***** imx8_init_pm_domains *****\n");
+
+ for_each_compatible_node(np, NULL, "nxp,imx8-pd") {
+ struct imx8_pm_domain *imx8_pd;
+
+ if (!of_device_is_available(np))
+ continue;
+
+ imx8_pd = kzalloc(sizeof(struct imx8_pm_domain), GFP_KERNEL);
+ if (!imx8_pd) {
+ pr_err("%s: failed to allocate memory for domain\n",
+ __func__);
+ return -ENOMEM;
+ }
+ if (!of_property_read_string(np, "name", &imx8_pd->pd.name))
+ imx8_pd->name = imx8_pd->pd.name;
+
+ if (!of_property_read_u32(np, "reg", &rsrc_id))
+ imx8_pd->rsrc_id = rsrc_id;
+
+ if (imx8_pd->rsrc_id != SC_R_LAST)
+ imx8_pd_setup(imx8_pd);
+
+ INIT_LIST_HEAD(&imx8_pd->clks);
+
+ pm_genpd_init(&imx8_pd->pd, NULL, true);
+ of_genpd_add_provider_simple(np, &imx8_pd->pd);
+ imx8_add_pm_domains(np, &imx8_pd->pd);
+ }
+
+ sci_err = sc_ipc_getMuID(&mu_id);
+ if (sci_err != SC_ERR_NONE) {
+ pr_info("Cannot obtain MU ID\n");
+ return sci_err;
+ }
+
+ sci_err = sc_ipc_open(&pm_ipc_handle, mu_id);
+ register_syscore_ops(&imx8_pm_domains_syscore_ops);
+
+ return 0;
+}
+
+early_initcall(imx8_init_pm_domains);
+
+static int imx8_wu_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+ unsigned int idx = irq2rsrc[d->hwirq] / 32;
+ u32 mask = 1 << irq2rsrc[d->hwirq] % 32;
+
+ spin_lock(&imx8_wu_lock);
+ wakeup_rsrc_id[idx] = on ? wakeup_rsrc_id[idx] | mask :
+ wakeup_rsrc_id[idx] & ~mask;
+ spin_unlock(&imx8_wu_lock);
+
+ return 0;
+}
+
+static struct irq_chip imx8_wu_chip = {
+ .name = "IMX8-WU",
+ .irq_eoi = irq_chip_eoi_parent,
+ .irq_mask = irq_chip_mask_parent,
+ .irq_unmask = irq_chip_unmask_parent,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
+ .irq_set_wake = imx8_wu_irq_set_wake,
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+};
+
+static int imx8_wu_domain_translate(struct irq_domain *d,
+ struct irq_fwspec *fwspec,
+ unsigned long *hwirq,
+ unsigned int *type)
+{
+ if (is_of_node(fwspec->fwnode)) {
+ if (fwspec->param_count != 3)
+ return -EINVAL;
+ /* No PPI should point to this domain */
+ if (fwspec->param[0] != 0)
+ return -EINVAL;
+ *hwirq = fwspec->param[1];
+ *type = fwspec->param[2];
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int imx8_wu_domain_alloc(struct irq_domain *domain,
+ unsigned int irq,
+ unsigned int nr_irqs, void *data)
+{
+ struct irq_fwspec *fwspec = data;
+ struct irq_fwspec parent_fwspec;
+ irq_hw_number_t hwirq;
+ int i;
+
+ if (fwspec->param_count != 3)
+ return -EINVAL; /* Not GIC compliant */
+ if (fwspec->param[0] != 0)
+ return -EINVAL; /* No PPI should point to this domain */
+
+ hwirq = fwspec->param[1];
+ if (hwirq >= IMX8_WU_MAX_IRQS)
+ return -EINVAL; /* Can't deal with this */
+
+ for (i = 0; i < nr_irqs; i++)
+ irq_domain_set_hwirq_and_chip(domain, irq + i, hwirq + i,
+ &imx8_wu_chip, NULL);
+
+ parent_fwspec = *fwspec;
+ parent_fwspec.fwnode = domain->parent->fwnode;
+
+ return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs,
+ &parent_fwspec);
+}
+
+static const struct irq_domain_ops imx8_wu_domain_ops = {
+ .translate = imx8_wu_domain_translate,
+ .alloc = imx8_wu_domain_alloc,
+ .free = irq_domain_free_irqs_common,
+};
+
+static int __init imx8_wu_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct irq_domain *parent_domain, *domain;
+
+ if (!parent) {
+ pr_err("%s: no parent, giving up\n", node->full_name);
+ return -ENODEV;
+ }
+
+ parent_domain = irq_find_host(parent);
+ if (!parent_domain) {
+ pr_err("%s: unable to obtain parent domain\n", node->full_name);
+ return -ENXIO;
+ }
+
+ domain = irq_domain_add_hierarchy(parent_domain, 0, IMX8_WU_MAX_IRQS,
+ node, &imx8_wu_domain_ops,
+ NULL);
+ if (!domain)
+ return -ENOMEM;
+
+ return 0;
+}
+IRQCHIP_DECLARE(imx8_wakeup_unit, "fsl,imx8-wu", imx8_wu_init);
+
+/*** debugfs support ***/
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/kobject.h>
+
+#define SC_PM_PW_MODE_FAIL (SC_PM_PW_MODE_ON + 1)
+static struct dentry *imx8_rsrc_pm_debugfs_dir;
+
+static int imx8_rsrc_pm_summary_one(struct seq_file *s,
+ sc_rsrc_t rsrc_id)
+{
+ static const char * const status_lookup[] = {
+ [SC_PM_PW_MODE_OFF] = "OFF",
+ [SC_PM_PW_MODE_STBY] = "STBY",
+ [SC_PM_PW_MODE_LP] = "LP",
+ [SC_PM_PW_MODE_ON] = "ON",
+ [SC_PM_PW_MODE_FAIL] = "FAIL",
+ };
+ sc_err_t sci_err = SC_ERR_NONE;
+ sc_pm_power_mode_t mode;
+ char state[16];
+
+ sci_err = sc_pm_get_resource_power_mode(pm_ipc_handle, rsrc_id, &mode);
+ if (sci_err) {
+ pr_debug("failed to get power mode on resource %d, ret %d\n",
+ rsrc_id, sci_err);
+ mode = SC_PM_PW_MODE_FAIL;
+ }
+
+ if (WARN_ON(mode >= ARRAY_SIZE(status_lookup)))
+ return 0;
+
+ snprintf(state, sizeof(state), "%s", status_lookup[mode]);
+ seq_printf(s, "%-30d %-15s ", rsrc_id, state);
+ seq_puts(s, "\n");
+
+ return 0;
+}
+
+static int imx8_rsrc_pm_summary_show(struct seq_file *s, void *data)
+{
+ int ret = 0;
+ int i;
+
+ seq_puts(s, "resource_id power_mode\n");
+ seq_puts(s, "---------------------------------------------\n");
+
+ ret = mutex_lock_interruptible(&rsrc_pm_list_lock);
+ if (ret)
+ return -ERESTARTSYS;
+
+ for (i = 0; i < SC_R_LAST; i++) {
+ ret = imx8_rsrc_pm_summary_one(s, i);
+ if (ret)
+ break;
+ }
+ mutex_unlock(&rsrc_pm_list_lock);
+
+ return ret;
+}
+
+static int imx8_rsrc_pm_summary_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, imx8_rsrc_pm_summary_show, NULL);
+}
+
+static const struct file_operations imx8_rsrc_pm_summary_fops = {
+ .open = imx8_rsrc_pm_summary_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init imx8_pm_debug_init(void)
+{
+ struct dentry *d;
+
+ /* skip for non-SCFW system */
+ if (!of_find_compatible_node(NULL, NULL, "nxp,imx8-pd"))
+ return 0;
+
+ imx8_rsrc_pm_debugfs_dir = debugfs_create_dir("imx_rsrc_pm", NULL);
+
+ if (!imx8_rsrc_pm_debugfs_dir)
+ return -ENOMEM;
+
+ d = debugfs_create_file("imx_rsrc_pm_summary", 0444,
+ imx8_rsrc_pm_debugfs_dir, NULL,
+ &imx8_rsrc_pm_summary_fops);
+ if (!d)
+ return -ENOMEM;
+
+ return 0;
+}
+late_initcall(imx8_pm_debug_init);
+
+static void __exit imx8_rsrc_pm_debug_exit(void)
+{
+ debugfs_remove_recursive(imx8_rsrc_pm_debugfs_dir);
+}
+__exitcall(imx8_rsrc_pm_debug_exit);
+#endif /* CONFIG_DEBUG_FS */
diff --git a/drivers/soc/imx/sc/Makefile b/drivers/soc/imx/sc/Makefile
new file mode 100644
index 000000000000..851c687ce7b3
--- /dev/null
+++ b/drivers/soc/imx/sc/Makefile
@@ -0,0 +1,8 @@
+obj-y += main/ipc.o
+obj-y += svc/misc/rpc_clnt.o
+obj-y += svc/pad/rpc_clnt.o
+obj-y += svc/pm/rpc_clnt.o
+obj-y += svc/rm/rpc_clnt.o
+obj-y += svc/timer/rpc_clnt.o
+obj-y += svc/irq/rpc_clnt.o
+
diff --git a/drivers/soc/imx/sc/main/ipc.c b/drivers/soc/imx/sc/main/ipc.c
new file mode 100644
index 000000000000..65af00b41536
--- /dev/null
+++ b/drivers/soc/imx/sc/main/ipc.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/* Includes */
+#include <linux/arm-smccc.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_fdt.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mx8_mu.h>
+#include <linux/syscore_ops.h>
+
+#include <soc/imx/fsl_hvc.h>
+#include <soc/imx8/sc/svc/irq/api.h>
+#include <soc/imx8/sc/ipc.h>
+#include <soc/imx8/sc/sci.h>
+
+#include "rpc.h"
+
+/* Local Defines */
+#define MU_SIZE 0x10000
+
+/* Local Types */
+unsigned int scu_mu_id;
+static void __iomem *mu_base_virtaddr;
+static struct delayed_work scu_mu_work;
+static sc_ipc_t mu_ipcHandle;
+
+/* Local functions */
+
+/* Local variables */
+static uint32_t gIPCport;
+static bool scu_mu_init;
+
+DEFINE_MUTEX(scu_mu_mutex);
+
+static BLOCKING_NOTIFIER_HEAD(SCU_notifier_chain);
+
+EXPORT_SYMBOL(sc_pm_set_resource_power_mode);
+EXPORT_SYMBOL(sc_pm_get_resource_power_mode);
+EXPORT_SYMBOL(sc_pm_cpu_start);
+EXPORT_SYMBOL(sc_misc_set_control);
+EXPORT_SYMBOL(sc_pm_clock_enable);
+EXPORT_SYMBOL(sc_pm_set_clock_rate);
+/*--------------------------------------------------------------------------*/
+/* RPC command/response */
+/*--------------------------------------------------------------------------*/
+void sc_call_rpc(sc_ipc_t handle, sc_rpc_msg_t *msg, bool no_resp)
+{
+ struct arm_smccc_res res;
+
+ if (in_interrupt()) {
+ pr_warn("Cannot make SC IPC calls from an interrupt context\n");
+ dump_stack();
+ return;
+ }
+ mutex_lock(&scu_mu_mutex);
+
+ if (xen_initial_domain()) {
+ arm_smccc_hvc(FSL_HVC_SC, (uint64_t)msg, no_resp, 0, 0, 0, 0,
+ 0, &res);
+ if (res.a0)
+ printk("Error FSL_HVC_SC %ld\n", res.a0);
+ } else {
+ sc_ipc_write(handle, msg);
+ if (!no_resp)
+ sc_ipc_read(handle, msg);
+ }
+
+ mutex_unlock(&scu_mu_mutex);
+}
+EXPORT_SYMBOL(sc_call_rpc);
+
+/*--------------------------------------------------------------------------*/
+/* Get MU base address for specified IPC channel */
+/*--------------------------------------------------------------------------*/
+static uint32_t *sc_ipc_get_mu_base(uint32_t id)
+{
+ uint32_t *base;
+
+ /* Check parameters */
+ if (id >= SC_NUM_IPC)
+ base = NULL;
+ else
+ base = (uint32_t *) (mu_base_virtaddr + (id * MU_SIZE));
+
+ return base;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Get the MU ID used by Linux */
+/*--------------------------------------------------------------------------*/
+int sc_ipc_getMuID(uint32_t *mu_id)
+{
+ if (scu_mu_init) {
+ *mu_id = scu_mu_id;
+ return SC_ERR_NONE;
+ }
+ return SC_ERR_UNAVAILABLE;
+}
+
+EXPORT_SYMBOL(sc_ipc_getMuID);
+
+/*--------------------------------------------------------------------------*/
+/* Open an IPC channel */
+/*--------------------------------------------------------------------------*/
+sc_err_t sc_ipc_requestInt(sc_ipc_t *handle, uint32_t id)
+{
+ return SC_ERR_NONE;
+}
+
+/*--------------------------------------------------------------------------*/
+/* Open an IPC channel */
+/*--------------------------------------------------------------------------*/
+sc_err_t sc_ipc_open(sc_ipc_t *handle, uint32_t id)
+{
+ uint32_t *base;
+
+ mutex_lock(&scu_mu_mutex);
+
+ if (!scu_mu_init) {
+ mutex_unlock(&scu_mu_mutex);
+ return SC_ERR_UNAVAILABLE;
+ }
+ /* Get MU base associated with IPC channel */
+ base = sc_ipc_get_mu_base(id);
+
+ if (base == NULL) {
+ mutex_unlock(&scu_mu_mutex);
+ return SC_ERR_IPC;
+ }
+
+ *handle = (sc_ipc_t) task_pid_vnr(current);
+
+ mutex_unlock(&scu_mu_mutex);
+
+ return SC_ERR_NONE;
+}
+EXPORT_SYMBOL(sc_ipc_open);
+/*--------------------------------------------------------------------------*/
+/* Close an IPC channel */
+/*--------------------------------------------------------------------------*/
+void sc_ipc_close(sc_ipc_t handle)
+{
+ uint32_t *base;
+
+ mutex_lock(&scu_mu_mutex);
+
+ if (!scu_mu_init) {
+ mutex_unlock(&scu_mu_mutex);
+ return;
+ }
+
+ /* Get MU base associated with IPC channel */
+ base = sc_ipc_get_mu_base(gIPCport);
+
+ /* TBD ***** What needs to be done here? */
+ mutex_unlock(&scu_mu_mutex);
+}
+EXPORT_SYMBOL(sc_ipc_close);
+
+/*!
+ * This function reads a message from an IPC channel.
+ *
+ * @param[in] ipc id of channel read from
+ * @param[out] data pointer to message buffer to read
+ *
+ * This function will block if no message is available to be read.
+ */
+void sc_ipc_read(sc_ipc_t handle, void *data)
+{
+ uint32_t *base;
+ uint8_t count = 0;
+ sc_rpc_msg_t *msg = (sc_rpc_msg_t *) data;
+
+ /* Get MU base associated with IPC channel */
+ base = sc_ipc_get_mu_base(gIPCport);
+
+ if ((base == NULL) || (msg == NULL))
+ return;
+
+ /* Read first word */
+ MU_ReceiveMsg(base, 0, (uint32_t *) msg);
+ count++;
+
+ /* Check size */
+ if (msg->size > SC_RPC_MAX_MSG) {
+ *((uint32_t *) msg) = 0;
+ return;
+ }
+
+ /* Read remaining words */
+ while (count < msg->size) {
+ MU_ReceiveMsg(base, count % MU_RR_COUNT,
+ &(msg->DATA.u32[count - 1]));
+ count++;
+ }
+}
+
+/*!
+ * This function writes a message to an IPC channel.
+ *
+ * @param[in] ipc id of channel to write to
+ * @param[in] data pointer to message buffer to write
+ *
+ * This function will block if the outgoing buffer is full.
+ */
+void sc_ipc_write(sc_ipc_t handle, void *data)
+{
+ uint32_t *base;
+ uint8_t count = 0;
+ sc_rpc_msg_t *msg = (sc_rpc_msg_t *) data;
+
+ /* Get MU base associated with IPC channel */
+ base = sc_ipc_get_mu_base(gIPCport);
+
+ if ((base == NULL) || (msg == NULL))
+ return;
+
+ /* Check size */
+ if (msg->size > SC_RPC_MAX_MSG)
+ return;
+
+ /* Write first word */
+ MU_SendMessage(base, 0, *((uint32_t *) msg));
+ count++;
+
+ /* Write remaining words */
+ while (count < msg->size) {
+ MU_SendMessage(base, count % MU_TR_COUNT, msg->DATA.u32[count - 1]);
+ count++;
+ }
+}
+
+int register_scu_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&SCU_notifier_chain, nb);
+}
+
+EXPORT_SYMBOL(register_scu_notifier);
+
+int unregister_scu_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&SCU_notifier_chain, nb);
+}
+
+EXPORT_SYMBOL(unregister_scu_notifier);
+
+static int SCU_notifier_call_chain(unsigned long status, sc_irq_group_t *group)
+{
+ return blocking_notifier_call_chain(&SCU_notifier_chain, status,
+ (void *)group);
+}
+
+static void scu_mu_work_handler(struct work_struct *work)
+{
+ uint32_t irq_status;
+ sc_err_t sciErr;
+ sc_irq_group_t i;
+
+ /* Walk all groups interrupt callback, callback will judge if it's
+ * the right group for itself, return directly if not.
+ */
+ for (i = 0; i < SC_IRQ_NUM_GROUP; i++) {
+ sciErr = sc_irq_status(mu_ipcHandle, SC_R_MU_1A, i,
+ &irq_status);
+ /* no irq? */
+ if (!irq_status)
+ continue;
+
+ SCU_notifier_call_chain(irq_status, &i);
+ }
+}
+
+static irqreturn_t imx8_scu_mu_isr(int irq, void *param)
+{
+ u32 irqs;
+
+ irqs = (readl_relaxed(mu_base_virtaddr + 0x20) & (0xf << 28));
+ if (irqs) {
+ /* Clear the General Interrupt */
+ writel_relaxed(irqs, mu_base_virtaddr + 0x20);
+ /* Setup a bottom-half to handle the irq work. */
+ schedule_delayed_work(&scu_mu_work, 0);
+ }
+ return IRQ_HANDLED;
+}
+
+static void imx8_mu_resume(void)
+{
+ int i;
+
+ MU_Init(mu_base_virtaddr);
+ for (i = 0; i < MU_RR_COUNT; i++)
+ MU_EnableGeneralInt(mu_base_virtaddr, i);
+}
+
+struct syscore_ops imx8_mu_syscore_ops = {
+ .resume = imx8_mu_resume,
+};
+
+/*Initialization of the MU code. */
+int __init imx8_mu_init(void)
+{
+ struct device_node *np;
+ int irq;
+ int err;
+ sc_err_t sciErr;
+
+ /*
+ * Get the address of MU to be used for communication with the SCU
+ */
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx8-mu");
+ if (!np) {
+ pr_info("Cannot find MU entry in device tree\n");
+ return 0;
+ }
+ mu_base_virtaddr = of_iomap(np, 0);
+ WARN_ON(!mu_base_virtaddr);
+
+ err = of_property_read_u32_index(np, "fsl,scu_ap_mu_id", 0, &scu_mu_id);
+ if (err)
+ pr_info("imx8_mu_init: Cannot get mu_id err = %d\n", err);
+
+ irq = of_irq_get(np, 0);
+
+ if (irq <= 0) {
+ /* SCU works just fine without irq */
+ pr_warn("imx8_mu_init: no irq: %d\n", irq);
+ } else {
+ err = request_irq(irq, imx8_scu_mu_isr,
+ IRQF_EARLY_RESUME, "imx8_mu_isr", NULL);
+ if (err) {
+ pr_err("imx8_mu_init: request_irq %d failed: %d\n",
+ irq, err);
+ return err;
+ }
+
+ err = irq_set_irq_wake(irq, 1);
+ if (err)
+ pr_err("imx8mu_init: set_irq_wake failed: %d\n", err);
+ }
+
+ if (!scu_mu_init) {
+ uint32_t i;
+
+ INIT_DELAYED_WORK(&scu_mu_work, scu_mu_work_handler);
+
+ /* Init MU */
+ MU_Init(mu_base_virtaddr);
+
+#if 1
+ /* Enable all RX interrupts */
+ for (i = 0; i < MU_RR_COUNT; i++)
+ MU_EnableGeneralInt(mu_base_virtaddr, i);
+#endif
+ gIPCport = scu_mu_id;
+ scu_mu_init = true;
+ }
+
+ sciErr = sc_ipc_open(&mu_ipcHandle, scu_mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ pr_info("Cannot open MU channel to SCU\n");
+ return sciErr;
+ };
+
+ /* Request for the high temp interrupt. */
+ sciErr = sc_irq_enable(mu_ipcHandle, SC_R_MU_1A, SC_IRQ_GROUP_TEMP,
+ SC_IRQ_TEMP_PMIC0_HIGH, true);
+
+ if (sciErr)
+ pr_info("Cannot request PMIC0_TEMP interrupt\n");
+
+ /* Request for the high temp interrupt. */
+ sciErr = sc_irq_enable(mu_ipcHandle, SC_R_MU_1A, SC_IRQ_GROUP_TEMP,
+ SC_IRQ_TEMP_PMIC1_HIGH, true);
+
+ if (sciErr)
+ pr_info("Cannot request PMIC1_TEMP interrupt\n");
+
+ /* Request for the rtc alarm interrupt. */
+ sciErr = sc_irq_enable(mu_ipcHandle, SC_R_MU_1A, SC_IRQ_GROUP_RTC,
+ SC_IRQ_RTC, true);
+
+ if (sciErr)
+ pr_info("Cannot request ALARM_RTC interrupt\n");
+
+ /* Request for the ON/OFF interrupt. */
+ sciErr = sc_irq_enable(mu_ipcHandle, SC_R_MU_1A, SC_IRQ_GROUP_WAKE,
+ SC_IRQ_BUTTON, true);
+
+ if (sciErr)
+ pr_info("Cannot request ON/OFF interrupt\n");
+
+ /* Request for the watchdog interrupt. */
+ sciErr = sc_irq_enable(mu_ipcHandle, SC_R_MU_1A, SC_IRQ_GROUP_WDOG,
+ SC_IRQ_WDOG, true);
+
+ if (sciErr)
+ pr_info("Cannot request WDOG interrupt\n");
+
+ sciErr = sc_irq_enable(mu_ipcHandle, SC_R_MU_1A, SC_IRQ_GROUP_WAKE,
+ SC_IRQ_PAD, true);
+ if (sciErr)
+ pr_info("Cannot request PAD interrupt\n");
+
+ register_syscore_ops(&imx8_mu_syscore_ops);
+
+ pr_info("*****Initialized MU\n");
+ return scu_mu_id;
+}
+
+early_initcall(imx8_mu_init);
diff --git a/drivers/soc/imx/sc/main/rpc.h b/drivers/soc/imx/sc/main/rpc.h
new file mode 100644
index 000000000000..85cff2315f65
--- /dev/null
+++ b/drivers/soc/imx/sc/main/rpc.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*!
+ * Header file for the RPC implementation.
+ */
+
+#ifndef _SC_RPC_H
+#define _SC_RPC_H
+
+/* Includes */
+
+#include <soc/imx8/sc/types.h>
+#include <soc/imx8/sc/ipc.h>
+
+/* Defines */
+
+#define SC_RPC_VERSION 1
+
+#define SC_RPC_MAX_MSG 8
+
+#define RPC_VER(MSG) ((MSG)->version)
+#define RPC_SIZE(MSG) ((MSG)->size)
+#define RPC_SVC(MSG) ((MSG)->svc)
+#define RPC_FUNC(MSG) ((MSG)->func)
+#define RPC_R8(MSG) ((MSG)->func)
+#define RPC_I32(MSG, IDX) ((MSG)->DATA.i32[(IDX) / 4])
+#define RPC_I16(MSG, IDX) ((MSG)->DATA.i16[(IDX) / 2])
+#define RPC_I8(MSG, IDX) ((MSG)->DATA.i8[(IDX)])
+#define RPC_U32(MSG, IDX) ((MSG)->DATA.u32[(IDX) / 4])
+#define RPC_U16(MSG, IDX) ((MSG)->DATA.u16[(IDX) / 2])
+#define RPC_U8(MSG, IDX) ((MSG)->DATA.u8[(IDX)])
+
+/* Types */
+
+typedef enum sc_rpc_svc_e {
+ SC_RPC_SVC_UNKNOWN = 0,
+ SC_RPC_SVC_RETURN = 1,
+ SC_RPC_SVC_PM = 2,
+ SC_RPC_SVC_RM = 3,
+ SC_RPC_SVC_TIMER = 5,
+ SC_RPC_SVC_PAD = 6,
+ SC_RPC_SVC_MISC = 7,
+ SC_RPC_SVC_IRQ = 8,
+ SC_RPC_SVC_ABORT = 9
+} sc_rpc_svc_t;
+
+typedef struct sc_rpc_msg_s {
+ uint8_t version;
+ uint8_t size;
+ uint8_t svc;
+ uint8_t func;
+ union {
+ int32_t i32[(SC_RPC_MAX_MSG - 1)];
+ int16_t i16[(SC_RPC_MAX_MSG - 1) * 2];
+ int8_t i8[(SC_RPC_MAX_MSG - 1) * 4];
+ uint32_t u32[(SC_RPC_MAX_MSG - 1)];
+ uint16_t u16[(SC_RPC_MAX_MSG - 1) * 2];
+ uint8_t u8[(SC_RPC_MAX_MSG - 1) * 4];
+ } DATA;
+} sc_rpc_msg_t;
+
+typedef enum sc_rpc_async_state_e {
+ SC_RPC_ASYNC_STATE_RD_START = 0,
+ SC_RPC_ASYNC_STATE_RD_ACTIVE = 1,
+ SC_RPC_ASYNC_STATE_RD_DONE = 2,
+ SC_RPC_ASYNC_STATE_WR_START = 3,
+ SC_RPC_ASYNC_STATE_WR_ACTIVE = 4,
+ SC_RPC_ASYNC_STATE_WR_DONE = 5,
+} sc_rpc_async_state_t;
+
+typedef struct sc_rpc_async_msg_s {
+ sc_rpc_async_state_t state;
+ uint8_t wordIdx;
+ sc_rpc_msg_t msg;
+ uint32_t timeStamp;
+} sc_rpc_async_msg_t;
+
+/* Functions */
+
+/*!
+ * This is an internal function to send an RPC message over an IPC
+ * channel. It is called by client-side SCFW API function shims.
+ *
+ * @param[in] ipc IPC handle
+ * @param[in,out] msg handle to a message
+ * @param[in] no_resp response flag
+ *
+ * If \a no_resp is false then this function waits for a response
+ * and returns the result in \a msg.
+ */
+void sc_call_rpc(sc_ipc_t ipc, sc_rpc_msg_t *msg, bool no_resp);
+
+/*!
+ * This is an internal function to dispath an RPC call that has
+ * arrived via IPC over an MU. It is called by server-side SCFW.
+ *
+ * @param[in] mu MU message arrived on
+ * @param[in,out] msg handle to a message
+ *
+ * The function result is returned in \a msg.
+ */
+void sc_rpc_dispatch(sc_rsrc_t mu, sc_rpc_msg_t *msg);
+
+/*!
+ * This function translates an RPC message and forwards on to the
+ * normal RPC API. It is used only by hypervisors.
+ *
+ * @param[in] ipc IPC handle
+ * @param[in,out] msg handle to a message
+ *
+ * This function decodes a message, calls macros to translate the
+ * resources, pads, addresses, partitions, memory regions, etc. and
+ * then forwards on to the hypervisors SCFW API.Return results are
+ * translated back abd placed back into the message to be returned
+ * to the original API.
+ */
+void sc_rpc_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg);
+
+#endif /* _SC_RPC_H */
diff --git a/drivers/soc/imx/sc/svc/irq/rpc.h b/drivers/soc/imx/sc/svc/irq/rpc.h
new file mode 100644
index 000000000000..93ce7c3b87a3
--- /dev/null
+++ b/drivers/soc/imx/sc/svc/irq/rpc.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*!
+ * Header file for the IRQ RPC implementation.
+ *
+ * @addtogroup IRQ_SVC
+ * @{
+ */
+
+#ifndef _SC_IRQ_RPC_H
+#define _SC_IRQ_RPC_H
+
+/* Includes */
+
+/* Defines */
+
+/* Types */
+
+/*!
+ * This type is used to indicate RPC IRQ function calls.
+ */
+typedef enum irq_func_e {
+ IRQ_FUNC_UNKNOWN = 0, /* Unknown function */
+ IRQ_FUNC_ENABLE = 1, /* Index for irq_enable() RPC call */
+ IRQ_FUNC_STATUS = 2, /* Index for irq_status() RPC call */
+} irq_func_t;
+
+/* Functions */
+
+/*!
+ * This function dispatches an incoming IRQ RPC request.
+ *
+ * @param[in] caller_pt caller partition
+ * @param[in] msg pointer to RPC message
+ */
+void irq_dispatch(sc_rm_pt_t caller_pt, sc_rpc_msg_t *msg);
+
+/*!
+ * This function translates and dispatches an IRQ RPC request.
+ *
+ * @param[in] ipc IPC handle
+ * @param[in] msg pointer to RPC message
+ */
+void irq_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg);
+
+#endif /* _SC_IRQ_RPC_H */
+
+/**@}*/
diff --git a/drivers/soc/imx/sc/svc/irq/rpc_clnt.c b/drivers/soc/imx/sc/svc/irq/rpc_clnt.c
new file mode 100644
index 000000000000..779be383aea3
--- /dev/null
+++ b/drivers/soc/imx/sc/svc/irq/rpc_clnt.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*!
+ * File containing client-side RPC functions for the IRQ service. These
+ * functions are ported to clients that communicate to the SC.
+ *
+ * @addtogroup IRQ_SVC
+ * @{
+ */
+
+/* Includes */
+
+#include <soc/imx8/sc/types.h>
+#include <soc/imx8/sc/svc/rm/api.h>
+#include <soc/imx8/sc/svc/irq/api.h>
+#include "../../main/rpc.h"
+#include "rpc.h"
+
+/* Local Defines */
+
+/* Local Types */
+
+/* Local Functions */
+
+sc_err_t sc_irq_enable(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_irq_group_t group, uint32_t mask, bool enable)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_IRQ;
+ RPC_FUNC(&msg) = (uint8_t)IRQ_FUNC_ENABLE;
+ RPC_U32(&msg, 0) = mask;
+ RPC_U16(&msg, 4) = resource;
+ RPC_U8(&msg, 6) = group;
+ RPC_U8(&msg, 7) = (uint8_t)enable;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_irq_status(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_irq_group_t group, uint32_t *status)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_IRQ;
+ RPC_FUNC(&msg) = (uint8_t)IRQ_FUNC_STATUS;
+ RPC_U16(&msg, 0) = resource;
+ RPC_U8(&msg, 2) = group;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (status != NULL) {
+ *status = RPC_U32(&msg, 0);
+ }
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+/**@}*/
diff --git a/drivers/soc/imx/sc/svc/misc/rpc.h b/drivers/soc/imx/sc/svc/misc/rpc.h
new file mode 100644
index 000000000000..087b6b9f6dea
--- /dev/null
+++ b/drivers/soc/imx/sc/svc/misc/rpc.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*!
+ * Header file for the MISC RPC implementation.
+ *
+ * @addtogroup MISC_SVC
+ * @{
+ */
+
+#ifndef _SC_MISC_RPC_H
+#define _SC_MISC_RPC_H
+
+/* Includes */
+
+/* Defines */
+
+/* Types */
+
+/*!
+ * This type is used to indicate RPC MISC function calls.
+ */
+typedef enum misc_func_e {
+ MISC_FUNC_UNKNOWN = 0, /* Unknown function */
+ MISC_FUNC_SET_CONTROL = 1, /* Index for misc_set_control() RPC call */
+ MISC_FUNC_GET_CONTROL = 2, /* Index for misc_get_control() RPC call */
+ MISC_FUNC_SET_MAX_DMA_GROUP = 4, /* Index for misc_set_max_dma_group() RPC call */
+ MISC_FUNC_SET_DMA_GROUP = 5, /* Index for misc_set_dma_group() RPC call */
+ MISC_FUNC_SECO_IMAGE_LOAD = 8, /* Index for misc_seco_image_load() RPC call */
+ MISC_FUNC_SECO_AUTHENTICATE = 9, /* Index for misc_seco_authenticate() RPC call */
+ MISC_FUNC_DEBUG_OUT = 10, /* Index for misc_debug_out() RPC call */
+ MISC_FUNC_WAVEFORM_CAPTURE = 6, /* Index for misc_waveform_capture() RPC call */
+ MISC_FUNC_BUILD_INFO = 15, /* Index for misc_build_info() RPC call */
+ MISC_FUNC_UNIQUE_ID = 19, /* Index for misc_unique_id() RPC call */
+ MISC_FUNC_SET_ARI = 3, /* Index for misc_set_ari() RPC call */
+ MISC_FUNC_BOOT_STATUS = 7, /* Index for misc_boot_status() RPC call */
+ MISC_FUNC_BOOT_DONE = 14, /* Index for misc_boot_done() RPC call */
+ MISC_FUNC_OTP_FUSE_READ = 11, /* Index for misc_otp_fuse_read() RPC call */
+ MISC_FUNC_OTP_FUSE_WRITE = 17, /* Index for misc_otp_fuse_write() RPC call */
+ MISC_FUNC_SET_TEMP = 12, /* Index for misc_set_temp() RPC call */
+ MISC_FUNC_GET_TEMP = 13, /* Index for misc_get_temp() RPC call */
+ MISC_FUNC_GET_BOOT_DEV = 16, /* Index for misc_get_boot_dev() RPC call */
+ MISC_FUNC_GET_BUTTON_STATUS = 18, /* Index for misc_get_button_status() RPC call */
+} misc_func_t;
+
+/* Functions */
+
+/*!
+ * This function dispatches an incoming MISC RPC request.
+ *
+ * @param[in] caller_pt caller partition
+ * @param[in] msg pointer to RPC message
+ */
+void misc_dispatch(sc_rm_pt_t caller_pt, sc_rpc_msg_t *msg);
+
+/*!
+ * This function translates and dispatches an MISC RPC request.
+ *
+ * @param[in] ipc IPC handle
+ * @param[in] msg pointer to RPC message
+ */
+void misc_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg);
+
+#endif /* _SC_MISC_RPC_H */
+
+/**@}*/
diff --git a/drivers/soc/imx/sc/svc/misc/rpc_clnt.c b/drivers/soc/imx/sc/svc/misc/rpc_clnt.c
new file mode 100644
index 000000000000..e1f588c52b5c
--- /dev/null
+++ b/drivers/soc/imx/sc/svc/misc/rpc_clnt.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*!
+ * File containing client-side RPC functions for the MISC service. These
+ * functions are ported to clients that communicate to the SC.
+ *
+ * @addtogroup MISC_SVC
+ * @{
+ */
+
+/* Includes */
+
+#include <soc/imx8/sc/types.h>
+#include <soc/imx8/sc/svc/rm/api.h>
+#include <soc/imx8/sc/svc/misc/api.h>
+#include "../../main/rpc.h"
+#include "rpc.h"
+
+/* Local Defines */
+
+/* Local Types */
+
+/* Local Functions */
+
+sc_err_t sc_misc_set_control(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_ctrl_t ctrl, uint32_t val)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SET_CONTROL;
+ RPC_U32(&msg, 0) = ctrl;
+ RPC_U32(&msg, 4) = val;
+ RPC_U16(&msg, 8) = resource;
+ RPC_SIZE(&msg) = 4;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_get_control(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_ctrl_t ctrl, uint32_t *val)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_GET_CONTROL;
+ RPC_U32(&msg, 0) = ctrl;
+ RPC_U16(&msg, 4) = resource;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (val != NULL) {
+ *val = RPC_U32(&msg, 0);
+ }
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_set_max_dma_group(sc_ipc_t ipc, sc_rm_pt_t pt,
+ sc_misc_dma_group_t max)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SET_MAX_DMA_GROUP;
+ RPC_U8(&msg, 0) = pt;
+ RPC_U8(&msg, 1) = max;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_set_dma_group(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_misc_dma_group_t group)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SET_DMA_GROUP;
+ RPC_U16(&msg, 0) = resource;
+ RPC_U8(&msg, 2) = group;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_seco_image_load(sc_ipc_t ipc, uint32_t addr_src,
+ uint32_t addr_dst, uint32_t len, bool fw)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_IMAGE_LOAD;
+ RPC_U32(&msg, 0) = addr_src;
+ RPC_U32(&msg, 4) = addr_dst;
+ RPC_U32(&msg, 8) = len;
+ RPC_U8(&msg, 12) = (uint8_t)fw;
+ RPC_SIZE(&msg) = 5;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_seco_authenticate(sc_ipc_t ipc,
+ sc_misc_seco_auth_cmd_t cmd,
+ uint32_t addr_meta)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_AUTHENTICATE;
+ RPC_U32(&msg, 0) = addr_meta;
+ RPC_U8(&msg, 4) = cmd;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+void sc_misc_debug_out(sc_ipc_t ipc, uint8_t ch)
+{
+ sc_rpc_msg_t msg;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_DEBUG_OUT;
+ RPC_U8(&msg, 0) = ch;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ return;
+}
+
+sc_err_t sc_misc_waveform_capture(sc_ipc_t ipc, bool enable)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_WAVEFORM_CAPTURE;
+ RPC_U8(&msg, 0) = (uint8_t)enable;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+void sc_misc_build_info(sc_ipc_t ipc, uint32_t *build, uint32_t *commit)
+{
+ sc_rpc_msg_t msg;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_BUILD_INFO;
+ RPC_SIZE(&msg) = 1;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (build != NULL) {
+ *build = RPC_U32(&msg, 0);
+ }
+
+ if (commit != NULL) {
+ *commit = RPC_U32(&msg, 4);
+ }
+
+ return;
+}
+
+void sc_misc_unique_id(sc_ipc_t ipc, uint32_t *id_l, uint32_t *id_h)
+{
+ sc_rpc_msg_t msg;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_UNIQUE_ID;
+ RPC_SIZE(&msg) = 1;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (id_l != NULL) {
+ *id_l = RPC_U32(&msg, 0);
+ }
+
+ if (id_h != NULL) {
+ *id_h = RPC_U32(&msg, 4);
+ }
+
+ return;
+}
+
+sc_err_t sc_misc_set_ari(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_rsrc_t resource_mst, uint16_t ari, bool enable)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SET_ARI;
+ RPC_U16(&msg, 0) = resource;
+ RPC_U16(&msg, 2) = resource_mst;
+ RPC_U16(&msg, 4) = ari;
+ RPC_U8(&msg, 6) = (uint8_t)enable;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+void sc_misc_boot_status(sc_ipc_t ipc, sc_misc_boot_status_t status)
+{
+ sc_rpc_msg_t msg;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_BOOT_STATUS;
+ RPC_U8(&msg, 0) = status;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, true);
+
+ return;
+}
+
+sc_err_t sc_misc_boot_done(sc_ipc_t ipc, sc_rsrc_t cpu)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_BOOT_DONE;
+ RPC_U16(&msg, 0) = cpu;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_otp_fuse_read(sc_ipc_t ipc, uint32_t word, uint32_t *val)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_OTP_FUSE_READ;
+ RPC_U32(&msg, 0) = word;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (val != NULL) {
+ *val = RPC_U32(&msg, 0);
+ }
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_otp_fuse_write(sc_ipc_t ipc, uint32_t word, uint32_t val)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_OTP_FUSE_WRITE;
+ RPC_U32(&msg, 0) = word;
+ RPC_U32(&msg, 4) = val;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_set_temp(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_misc_temp_t temp, int16_t celsius, int8_t tenths)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SET_TEMP;
+ RPC_U16(&msg, 0) = resource;
+ RPC_I16(&msg, 2) = celsius;
+ RPC_U8(&msg, 4) = temp;
+ RPC_I8(&msg, 5) = tenths;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_misc_get_temp(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_misc_temp_t temp, int16_t * celsius,
+ int8_t * tenths)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_GET_TEMP;
+ RPC_U16(&msg, 0) = resource;
+ RPC_U8(&msg, 2) = temp;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (celsius != NULL) {
+ *celsius = RPC_I16(&msg, 0);
+ }
+
+ result = RPC_R8(&msg);
+ if (tenths != NULL) {
+ *tenths = RPC_I8(&msg, 2);
+ }
+
+ return (sc_err_t)result;
+}
+
+void sc_misc_get_boot_dev(sc_ipc_t ipc, sc_rsrc_t *dev)
+{
+ sc_rpc_msg_t msg;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_GET_BOOT_DEV;
+ RPC_SIZE(&msg) = 1;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (dev != NULL) {
+ *dev = RPC_U16(&msg, 0);
+ }
+
+ return;
+}
+
+void sc_misc_get_button_status(sc_ipc_t ipc, bool *status)
+{
+ sc_rpc_msg_t msg;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_GET_BUTTON_STATUS;
+ RPC_SIZE(&msg) = 1;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (status != NULL) {
+ *status = RPC_U8(&msg, 0);
+ }
+
+ return;
+}
+
+/**@}*/
diff --git a/drivers/soc/imx/sc/svc/pad/rpc.h b/drivers/soc/imx/sc/svc/pad/rpc.h
new file mode 100644
index 000000000000..ee8fe3b42af2
--- /dev/null
+++ b/drivers/soc/imx/sc/svc/pad/rpc.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*!
+ * Header file for the PAD RPC implementation.
+ *
+ * @addtogroup PAD_SVC
+ * @{
+ */
+
+#ifndef _SC_PAD_RPC_H
+#define _SC_PAD_RPC_H
+
+/* Includes */
+
+/* Defines */
+
+/* Types */
+
+/*!
+ * This type is used to indicate RPC PAD function calls.
+ */
+typedef enum pad_func_e {
+ PAD_FUNC_UNKNOWN = 0, /* Unknown function */
+ PAD_FUNC_SET_MUX = 1, /* Index for pad_set_mux() RPC call */
+ PAD_FUNC_GET_MUX = 6, /* Index for pad_get_mux() RPC call */
+ PAD_FUNC_SET_GP = 2, /* Index for pad_set_gp() RPC call */
+ PAD_FUNC_GET_GP = 7, /* Index for pad_get_gp() RPC call */
+ PAD_FUNC_SET_WAKEUP = 4, /* Index for pad_set_wakeup() RPC call */
+ PAD_FUNC_GET_WAKEUP = 9, /* Index for pad_get_wakeup() RPC call */
+ PAD_FUNC_SET_ALL = 5, /* Index for pad_set_all() RPC call */
+ PAD_FUNC_GET_ALL = 10, /* Index for pad_get_all() RPC call */
+ PAD_FUNC_SET = 15, /* Index for pad_set() RPC call */
+ PAD_FUNC_GET = 16, /* Index for pad_get() RPC call */
+ PAD_FUNC_SET_GP_28FDSOI = 11, /* Index for pad_set_gp_28fdsoi() RPC call */
+ PAD_FUNC_GET_GP_28FDSOI = 12, /* Index for pad_get_gp_28fdsoi() RPC call */
+ PAD_FUNC_SET_GP_28FDSOI_HSIC = 3, /* Index for pad_set_gp_28fdsoi_hsic() RPC call */
+ PAD_FUNC_GET_GP_28FDSOI_HSIC = 8, /* Index for pad_get_gp_28fdsoi_hsic() RPC call */
+ PAD_FUNC_SET_GP_28FDSOI_COMP = 13, /* Index for pad_set_gp_28fdsoi_comp() RPC call */
+ PAD_FUNC_GET_GP_28FDSOI_COMP = 14, /* Index for pad_get_gp_28fdsoi_comp() RPC call */
+} pad_func_t;
+
+/* Functions */
+
+/*!
+ * This function dispatches an incoming PAD RPC request.
+ *
+ * @param[in] caller_pt caller partition
+ * @param[in] msg pointer to RPC message
+ */
+void pad_dispatch(sc_rm_pt_t caller_pt, sc_rpc_msg_t *msg);
+
+/*!
+ * This function translates and dispatches an PAD RPC request.
+ *
+ * @param[in] ipc IPC handle
+ * @param[in] msg pointer to RPC message
+ */
+void pad_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg);
+
+#endif /* _SC_PAD_RPC_H */
+
+/**@}*/
diff --git a/drivers/soc/imx/sc/svc/pad/rpc_clnt.c b/drivers/soc/imx/sc/svc/pad/rpc_clnt.c
new file mode 100644
index 000000000000..90fb3904ca7b
--- /dev/null
+++ b/drivers/soc/imx/sc/svc/pad/rpc_clnt.c
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*!
+ * File containing client-side RPC functions for the PAD service. These
+ * functions are ported to clients that communicate to the SC.
+ *
+ * @addtogroup PAD_SVC
+ * @{
+ */
+
+/* Includes */
+
+#include <soc/imx8/sc/types.h>
+#include <soc/imx8/sc/svc/rm/api.h>
+#include <soc/imx8/sc/svc/pad/api.h>
+#include "../../main/rpc.h"
+#include "rpc.h"
+
+/* Local Defines */
+
+/* Local Types */
+
+/* Local Functions */
+
+sc_err_t sc_pad_set_mux(sc_ipc_t ipc, sc_pad_t pad,
+ uint8_t mux, sc_pad_config_t config, sc_pad_iso_t iso)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+ RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_MUX;
+ RPC_U16(&msg, 0) = pad;
+ RPC_U8(&msg, 2) = mux;
+ RPC_U8(&msg, 3) = config;
+ RPC_U8(&msg, 4) = iso;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_get_mux(sc_ipc_t ipc, sc_pad_t pad,
+ uint8_t *mux, sc_pad_config_t *config,
+ sc_pad_iso_t *iso)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+ RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_MUX;
+ RPC_U16(&msg, 0) = pad;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ if (mux != NULL) {
+ *mux = RPC_U8(&msg, 0);
+ }
+
+ if (config != NULL) {
+ *config = RPC_U8(&msg, 1);
+ }
+
+ if (iso != NULL) {
+ *iso = RPC_U8(&msg, 2);
+ }
+
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_set_gp(sc_ipc_t ipc, sc_pad_t pad, uint32_t ctrl)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+ RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_GP;
+ RPC_U32(&msg, 0) = ctrl;
+ RPC_U16(&msg, 4) = pad;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_get_gp(sc_ipc_t ipc, sc_pad_t pad, uint32_t *ctrl)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+ RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_GP;
+ RPC_U16(&msg, 0) = pad;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (ctrl != NULL) {
+ *ctrl = RPC_U32(&msg, 0);
+ }
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_set_wakeup(sc_ipc_t ipc, sc_pad_t pad, sc_pad_wakeup_t wakeup)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+ RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_WAKEUP;
+ RPC_U16(&msg, 0) = pad;
+ RPC_U8(&msg, 2) = wakeup;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_get_wakeup(sc_ipc_t ipc, sc_pad_t pad, sc_pad_wakeup_t *wakeup)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+ RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_WAKEUP;
+ RPC_U16(&msg, 0) = pad;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ if (wakeup != NULL) {
+ *wakeup = RPC_U8(&msg, 0);
+ }
+
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_set_all(sc_ipc_t ipc, sc_pad_t pad, uint8_t mux,
+ sc_pad_config_t config, sc_pad_iso_t iso, uint32_t ctrl,
+ sc_pad_wakeup_t wakeup)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+ RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_ALL;
+ RPC_U32(&msg, 0) = ctrl;
+ RPC_U16(&msg, 4) = pad;
+ RPC_U8(&msg, 6) = mux;
+ RPC_U8(&msg, 7) = config;
+ RPC_U8(&msg, 8) = iso;
+ RPC_U8(&msg, 9) = wakeup;
+ RPC_SIZE(&msg) = 4;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_get_all(sc_ipc_t ipc, sc_pad_t pad, uint8_t *mux,
+ sc_pad_config_t *config, sc_pad_iso_t *iso,
+ uint32_t *ctrl, sc_pad_wakeup_t *wakeup)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+ RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_ALL;
+ RPC_U16(&msg, 0) = pad;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (ctrl != NULL) {
+ *ctrl = RPC_U32(&msg, 0);
+ }
+
+ result = RPC_R8(&msg);
+ if (mux != NULL) {
+ *mux = RPC_U8(&msg, 4);
+ }
+
+ if (config != NULL) {
+ *config = RPC_U8(&msg, 5);
+ }
+
+ if (iso != NULL) {
+ *iso = RPC_U8(&msg, 6);
+ }
+
+ if (wakeup != NULL) {
+ *wakeup = RPC_U8(&msg, 7);
+ }
+
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_set(sc_ipc_t ipc, sc_pad_t pad, uint32_t val)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+ RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET;
+ RPC_U32(&msg, 0) = val;
+ RPC_U16(&msg, 4) = pad;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_get(sc_ipc_t ipc, sc_pad_t pad, uint32_t *val)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+ RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET;
+ RPC_U16(&msg, 0) = pad;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (val != NULL) {
+ *val = RPC_U32(&msg, 0);
+ }
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_set_gp_28fdsoi(sc_ipc_t ipc, sc_pad_t pad,
+ sc_pad_28fdsoi_dse_t dse, sc_pad_28fdsoi_ps_t ps)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+ RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_GP_28FDSOI;
+ RPC_U16(&msg, 0) = pad;
+ RPC_U8(&msg, 2) = dse;
+ RPC_U8(&msg, 3) = ps;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_get_gp_28fdsoi(sc_ipc_t ipc, sc_pad_t pad,
+ sc_pad_28fdsoi_dse_t *dse,
+ sc_pad_28fdsoi_ps_t *ps)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+ RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_GP_28FDSOI;
+ RPC_U16(&msg, 0) = pad;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ if (dse != NULL) {
+ *dse = RPC_U8(&msg, 0);
+ }
+
+ if (ps != NULL) {
+ *ps = RPC_U8(&msg, 1);
+ }
+
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_set_gp_28fdsoi_hsic(sc_ipc_t ipc, sc_pad_t pad,
+ sc_pad_28fdsoi_dse_t dse, bool hys,
+ sc_pad_28fdsoi_pus_t pus, bool pke,
+ bool pue)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+ RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_GP_28FDSOI_HSIC;
+ RPC_U16(&msg, 0) = pad;
+ RPC_U8(&msg, 2) = dse;
+ RPC_U8(&msg, 3) = pus;
+ RPC_U8(&msg, 4) = (uint8_t)hys;
+ RPC_U8(&msg, 5) = (uint8_t)pke;
+ RPC_U8(&msg, 6) = (uint8_t)pue;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_get_gp_28fdsoi_hsic(sc_ipc_t ipc, sc_pad_t pad,
+ sc_pad_28fdsoi_dse_t *dse, bool *hys,
+ sc_pad_28fdsoi_pus_t *pus, bool *pke,
+ bool *pue)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+ RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_GP_28FDSOI_HSIC;
+ RPC_U16(&msg, 0) = pad;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ if (dse != NULL) {
+ *dse = RPC_U8(&msg, 0);
+ }
+
+ if (pus != NULL) {
+ *pus = RPC_U8(&msg, 1);
+ }
+
+ if (hys != NULL) {
+ *hys = RPC_U8(&msg, 2);
+ }
+
+ if (pke != NULL) {
+ *pke = RPC_U8(&msg, 3);
+ }
+
+ if (pue != NULL) {
+ *pue = RPC_U8(&msg, 4);
+ }
+
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_set_gp_28fdsoi_comp(sc_ipc_t ipc, sc_pad_t pad,
+ uint8_t compen, bool fastfrz,
+ uint8_t rasrcp, uint8_t rasrcn,
+ bool nasrc_sel, bool psw_ovr)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+ RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_GP_28FDSOI_COMP;
+ RPC_U16(&msg, 0) = pad;
+ RPC_U8(&msg, 2) = compen;
+ RPC_U8(&msg, 3) = rasrcp;
+ RPC_U8(&msg, 4) = rasrcn;
+ RPC_U8(&msg, 5) = (uint8_t)fastfrz;
+ RPC_U8(&msg, 6) = (uint8_t)nasrc_sel;
+ RPC_U8(&msg, 7) = (uint8_t)psw_ovr;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pad_get_gp_28fdsoi_comp(sc_ipc_t ipc, sc_pad_t pad,
+ uint8_t *compen, bool *fastfrz,
+ uint8_t *rasrcp, uint8_t *rasrcn,
+ bool *nasrc_sel, bool *compok,
+ uint8_t *nasrc, bool *psw_ovr)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD;
+ RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_GP_28FDSOI_COMP;
+ RPC_U16(&msg, 0) = pad;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ if (compen != NULL) {
+ *compen = RPC_U8(&msg, 0);
+ }
+
+ if (rasrcp != NULL) {
+ *rasrcp = RPC_U8(&msg, 1);
+ }
+
+ if (rasrcn != NULL) {
+ *rasrcn = RPC_U8(&msg, 2);
+ }
+
+ if (nasrc != NULL) {
+ *nasrc = RPC_U8(&msg, 3);
+ }
+
+ if (fastfrz != NULL) {
+ *fastfrz = RPC_U8(&msg, 4);
+ }
+
+ if (nasrc_sel != NULL) {
+ *nasrc_sel = RPC_U8(&msg, 5);
+ }
+
+ if (compok != NULL) {
+ *compok = RPC_U8(&msg, 6);
+ }
+
+ if (psw_ovr != NULL) {
+ *psw_ovr = RPC_U8(&msg, 7);
+ }
+
+ return (sc_err_t)result;
+}
+
+/**@}*/
diff --git a/drivers/soc/imx/sc/svc/pm/rpc.h b/drivers/soc/imx/sc/svc/pm/rpc.h
new file mode 100644
index 000000000000..e83db74d20bd
--- /dev/null
+++ b/drivers/soc/imx/sc/svc/pm/rpc.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*!
+ * Header file for the PM RPC implementation.
+ *
+ * @addtogroup PM_SVC
+ * @{
+ */
+
+#ifndef _SC_PM_RPC_H
+#define _SC_PM_RPC_H
+
+/* Includes */
+
+/* Defines */
+
+/* Types */
+
+/*!
+ * This type is used to indicate RPC PM function calls.
+ */
+typedef enum pm_func_e {
+ PM_FUNC_UNKNOWN = 0, /* Unknown function */
+ PM_FUNC_SET_SYS_POWER_MODE = 19, /* Index for pm_set_sys_power_mode() RPC call */
+ PM_FUNC_SET_PARTITION_POWER_MODE = 1, /* Index for pm_set_partition_power_mode() RPC call */
+ PM_FUNC_GET_SYS_POWER_MODE = 2, /* Index for pm_get_sys_power_mode() RPC call */
+ PM_FUNC_SET_RESOURCE_POWER_MODE = 3, /* Index for pm_set_resource_power_mode() RPC call */
+ PM_FUNC_GET_RESOURCE_POWER_MODE = 4, /* Index for pm_get_resource_power_mode() RPC call */
+ PM_FUNC_REQ_LOW_POWER_MODE = 16, /* Index for pm_req_low_power_mode() RPC call */
+ PM_FUNC_SET_CPU_RESUME_ADDR = 17, /* Index for pm_set_cpu_resume_addr() RPC call */
+ PM_FUNC_REQ_SYS_IF_POWER_MODE = 18, /* Index for pm_req_sys_if_power_mode() RPC call */
+ PM_FUNC_SET_CLOCK_RATE = 5, /* Index for pm_set_clock_rate() RPC call */
+ PM_FUNC_GET_CLOCK_RATE = 6, /* Index for pm_get_clock_rate() RPC call */
+ PM_FUNC_CLOCK_ENABLE = 7, /* Index for pm_clock_enable() RPC call */
+ PM_FUNC_SET_CLOCK_PARENT = 14, /* Index for pm_set_clock_parent() RPC call */
+ PM_FUNC_GET_CLOCK_PARENT = 15, /* Index for pm_get_clock_parent() RPC call */
+ PM_FUNC_RESET = 13, /* Index for pm_reset() RPC call */
+ PM_FUNC_RESET_REASON = 10, /* Index for pm_reset_reason() RPC call */
+ PM_FUNC_BOOT = 8, /* Index for pm_boot() RPC call */
+ PM_FUNC_REBOOT = 9, /* Index for pm_reboot() RPC call */
+ PM_FUNC_REBOOT_PARTITION = 12, /* Index for pm_reboot_partition() RPC call */
+ PM_FUNC_CPU_START = 11, /* Index for pm_cpu_start() RPC call */
+} pm_func_t;
+
+/* Functions */
+
+/*!
+ * This function dispatches an incoming PM RPC request.
+ *
+ * @param[in] caller_pt caller partition
+ * @param[in] msg pointer to RPC message
+ */
+void pm_dispatch(sc_rm_pt_t caller_pt, sc_rpc_msg_t *msg);
+
+/*!
+ * This function translates and dispatches an PM RPC request.
+ *
+ * @param[in] ipc IPC handle
+ * @param[in] msg pointer to RPC message
+ */
+void pm_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg);
+
+#endif /* _SC_PM_RPC_H */
+
+/**@}*/
diff --git a/drivers/soc/imx/sc/svc/pm/rpc_clnt.c b/drivers/soc/imx/sc/svc/pm/rpc_clnt.c
new file mode 100644
index 000000000000..b4b651e91ad5
--- /dev/null
+++ b/drivers/soc/imx/sc/svc/pm/rpc_clnt.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*!
+ * File containing client-side RPC functions for the PM service. These
+ * functions are ported to clients that communicate to the SC.
+ *
+ * @addtogroup PM_SVC
+ * @{
+ */
+
+/* Includes */
+
+#include <soc/imx8/sc/types.h>
+#include <soc/imx8/sc/svc/rm/api.h>
+#include <soc/imx8/sc/svc/pm/api.h>
+#include "../../main/rpc.h"
+#include "rpc.h"
+
+/* Local Defines */
+
+/* Local Types */
+
+/* Local Functions */
+
+sc_err_t sc_pm_set_sys_power_mode(sc_ipc_t ipc, sc_pm_power_mode_t mode)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_SYS_POWER_MODE;
+ RPC_U8(&msg, 0) = mode;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_set_partition_power_mode(sc_ipc_t ipc, sc_rm_pt_t pt,
+ sc_pm_power_mode_t mode)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_PARTITION_POWER_MODE;
+ RPC_U8(&msg, 0) = pt;
+ RPC_U8(&msg, 1) = mode;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_get_sys_power_mode(sc_ipc_t ipc, sc_rm_pt_t pt,
+ sc_pm_power_mode_t *mode)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_GET_SYS_POWER_MODE;
+ RPC_U8(&msg, 0) = pt;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ if (mode != NULL) {
+ *mode = RPC_U8(&msg, 0);
+ }
+
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_set_resource_power_mode(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_pm_power_mode_t mode)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_RESOURCE_POWER_MODE;
+ RPC_U16(&msg, 0) = resource;
+ RPC_U8(&msg, 2) = mode;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_get_resource_power_mode(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_pm_power_mode_t *mode)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_GET_RESOURCE_POWER_MODE;
+ RPC_U16(&msg, 0) = resource;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ if (mode != NULL) {
+ *mode = RPC_U8(&msg, 0);
+ }
+
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_req_low_power_mode(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_pm_power_mode_t mode)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_REQ_LOW_POWER_MODE;
+ RPC_U16(&msg, 0) = resource;
+ RPC_U8(&msg, 2) = mode;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_set_cpu_resume_addr(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_faddr_t address)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_CPU_RESUME_ADDR;
+ RPC_U32(&msg, 0) = (uint32_t)(address >> 32u);
+ RPC_U32(&msg, 4) = (uint32_t)address;
+ RPC_U16(&msg, 8) = resource;
+ RPC_SIZE(&msg) = 4;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_req_sys_if_power_mode(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_pm_sys_if_t sys_if,
+ sc_pm_power_mode_t hpm,
+ sc_pm_power_mode_t lpm)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_REQ_SYS_IF_POWER_MODE;
+ RPC_U16(&msg, 0) = resource;
+ RPC_U8(&msg, 2) = sys_if;
+ RPC_U8(&msg, 3) = hpm;
+ RPC_U8(&msg, 4) = lpm;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_set_clock_rate(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_pm_clk_t clk, sc_pm_clock_rate_t *rate)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_CLOCK_RATE;
+ RPC_U32(&msg, 0) = *rate;
+ RPC_U16(&msg, 4) = resource;
+ RPC_U8(&msg, 6) = clk;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ *rate = RPC_U32(&msg, 0);
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_get_clock_rate(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_pm_clk_t clk, sc_pm_clock_rate_t *rate)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_GET_CLOCK_RATE;
+ RPC_U16(&msg, 0) = resource;
+ RPC_U8(&msg, 2) = clk;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (rate != NULL) {
+ *rate = RPC_U32(&msg, 0);
+ }
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_clock_enable(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_pm_clk_t clk, bool enable, bool autog)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_CLOCK_ENABLE;
+ RPC_U16(&msg, 0) = resource;
+ RPC_U8(&msg, 2) = clk;
+ RPC_U8(&msg, 3) = (uint8_t)enable;
+ RPC_U8(&msg, 4) = (uint8_t)autog;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_set_clock_parent(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_pm_clk_t clk, sc_pm_clk_parent_t parent)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_CLOCK_PARENT;
+ RPC_U16(&msg, 0) = resource;
+ RPC_U8(&msg, 2) = clk;
+ RPC_U8(&msg, 3) = parent;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_get_clock_parent(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_pm_clk_t clk, sc_pm_clk_parent_t * parent)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_GET_CLOCK_PARENT;
+ RPC_U16(&msg, 0) = resource;
+ RPC_U8(&msg, 2) = clk;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ if (parent != NULL) {
+ *parent = RPC_U8(&msg, 0);
+ }
+
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_reset(sc_ipc_t ipc, sc_pm_reset_type_t type)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_RESET;
+ RPC_U8(&msg, 0) = type;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_reset_reason(sc_ipc_t ipc, sc_pm_reset_reason_t *reason)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_RESET_REASON;
+ RPC_SIZE(&msg) = 1;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ if (reason != NULL) {
+ *reason = RPC_U8(&msg, 0);
+ }
+
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_boot(sc_ipc_t ipc, sc_rm_pt_t pt,
+ sc_rsrc_t resource_cpu, sc_faddr_t boot_addr,
+ sc_rsrc_t resource_mu, sc_rsrc_t resource_dev)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_BOOT;
+ RPC_U32(&msg, 0) = (uint32_t)(boot_addr >> 32u);
+ RPC_U32(&msg, 4) = (uint32_t)boot_addr;
+ RPC_U16(&msg, 8) = resource_cpu;
+ RPC_U16(&msg, 10) = resource_mu;
+ RPC_U16(&msg, 12) = resource_dev;
+ RPC_U8(&msg, 14) = pt;
+ RPC_SIZE(&msg) = 5;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+void sc_pm_reboot(sc_ipc_t ipc, sc_pm_reset_type_t type)
+{
+ sc_rpc_msg_t msg;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_REBOOT;
+ RPC_U8(&msg, 0) = type;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, true);
+
+ return;
+}
+
+sc_err_t sc_pm_reboot_partition(sc_ipc_t ipc, sc_rm_pt_t pt,
+ sc_pm_reset_type_t type)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_REBOOT_PARTITION;
+ RPC_U8(&msg, 0) = pt;
+ RPC_U8(&msg, 1) = type;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_pm_cpu_start(sc_ipc_t ipc, sc_rsrc_t resource, bool enable,
+ sc_faddr_t address)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM;
+ RPC_FUNC(&msg) = (uint8_t)PM_FUNC_CPU_START;
+ RPC_U32(&msg, 0) = (uint32_t)(address >> 32u);
+ RPC_U32(&msg, 4) = (uint32_t)address;
+ RPC_U16(&msg, 8) = resource;
+ RPC_U8(&msg, 10) = (uint8_t)enable;
+ RPC_SIZE(&msg) = 4;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+/**@}*/
diff --git a/drivers/soc/imx/sc/svc/rm/rpc.h b/drivers/soc/imx/sc/svc/rm/rpc.h
new file mode 100644
index 000000000000..457b01860ae5
--- /dev/null
+++ b/drivers/soc/imx/sc/svc/rm/rpc.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*!
+ * Header file for the RM RPC implementation.
+ *
+ * @addtogroup RM_SVC
+ * @{
+ */
+
+#ifndef _SC_RM_RPC_H
+#define _SC_RM_RPC_H
+
+/* Includes */
+
+/* Defines */
+
+/* Types */
+
+/*!
+ * This type is used to indicate RPC RM function calls.
+ */
+typedef enum rm_func_e {
+ RM_FUNC_UNKNOWN = 0, /* Unknown function */
+ RM_FUNC_PARTITION_ALLOC = 1, /* Index for rm_partition_alloc() RPC call */
+ RM_FUNC_SET_CONFIDENTIAL = 31, /* Index for rm_set_confidential() RPC call */
+ RM_FUNC_PARTITION_FREE = 2, /* Index for rm_partition_free() RPC call */
+ RM_FUNC_GET_DID = 26, /* Index for rm_get_did() RPC call */
+ RM_FUNC_PARTITION_STATIC = 3, /* Index for rm_partition_static() RPC call */
+ RM_FUNC_PARTITION_LOCK = 4, /* Index for rm_partition_lock() RPC call */
+ RM_FUNC_GET_PARTITION = 5, /* Index for rm_get_partition() RPC call */
+ RM_FUNC_SET_PARENT = 6, /* Index for rm_set_parent() RPC call */
+ RM_FUNC_MOVE_ALL = 7, /* Index for rm_move_all() RPC call */
+ RM_FUNC_ASSIGN_RESOURCE = 8, /* Index for rm_assign_resource() RPC call */
+ RM_FUNC_SET_RESOURCE_MOVABLE = 9, /* Index for rm_set_resource_movable() RPC call */
+ RM_FUNC_SET_SUBSYS_RSRC_MOVABLE = 28, /* Index for rm_set_subsys_rsrc_movable() RPC call */
+ RM_FUNC_SET_MASTER_ATTRIBUTES = 10, /* Index for rm_set_master_attributes() RPC call */
+ RM_FUNC_SET_MASTER_SID = 11, /* Index for rm_set_master_sid() RPC call */
+ RM_FUNC_SET_PERIPHERAL_PERMISSIONS = 12, /* Index for rm_set_peripheral_permissions() RPC call */
+ RM_FUNC_IS_RESOURCE_OWNED = 13, /* Index for rm_is_resource_owned() RPC call */
+ RM_FUNC_IS_RESOURCE_MASTER = 14, /* Index for rm_is_resource_master() RPC call */
+ RM_FUNC_IS_RESOURCE_PERIPHERAL = 15, /* Index for rm_is_resource_peripheral() RPC call */
+ RM_FUNC_GET_RESOURCE_INFO = 16, /* Index for rm_get_resource_info() RPC call */
+ RM_FUNC_MEMREG_ALLOC = 17, /* Index for rm_memreg_alloc() RPC call */
+ RM_FUNC_MEMREG_SPLIT = 29, /* Index for rm_memreg_split() RPC call */
+ RM_FUNC_MEMREG_FREE = 18, /* Index for rm_memreg_free() RPC call */
+ RM_FUNC_FIND_MEMREG = 30, /* Index for rm_find_memreg() RPC call */
+ RM_FUNC_ASSIGN_MEMREG = 19, /* Index for rm_assign_memreg() RPC call */
+ RM_FUNC_SET_MEMREG_PERMISSIONS = 20, /* Index for rm_set_memreg_permissions() RPC call */
+ RM_FUNC_IS_MEMREG_OWNED = 21, /* Index for rm_is_memreg_owned() RPC call */
+ RM_FUNC_GET_MEMREG_INFO = 22, /* Index for rm_get_memreg_info() RPC call */
+ RM_FUNC_ASSIGN_PAD = 23, /* Index for rm_assign_pad() RPC call */
+ RM_FUNC_SET_PAD_MOVABLE = 24, /* Index for rm_set_pad_movable() RPC call */
+ RM_FUNC_IS_PAD_OWNED = 25, /* Index for rm_is_pad_owned() RPC call */
+ RM_FUNC_DUMP = 27, /* Index for rm_dump() RPC call */
+} rm_func_t;
+
+/* Functions */
+
+/*!
+ * This function dispatches an incoming RM RPC request.
+ *
+ * @param[in] caller_pt caller partition
+ * @param[in] msg pointer to RPC message
+ */
+void rm_dispatch(sc_rm_pt_t caller_pt, sc_rpc_msg_t *msg);
+
+/*!
+ * This function translates and dispatches an RM RPC request.
+ *
+ * @param[in] ipc IPC handle
+ * @param[in] msg pointer to RPC message
+ */
+void rm_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg);
+
+#endif /* _SC_RM_RPC_H */
+
+/**@}*/
diff --git a/drivers/soc/imx/sc/svc/rm/rpc_clnt.c b/drivers/soc/imx/sc/svc/rm/rpc_clnt.c
new file mode 100644
index 000000000000..a9bb6ba42c15
--- /dev/null
+++ b/drivers/soc/imx/sc/svc/rm/rpc_clnt.c
@@ -0,0 +1,637 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*!
+ * File containing client-side RPC functions for the RM service. These
+ * functions are ported to clients that communicate to the SC.
+ *
+ * @addtogroup RM_SVC
+ * @{
+ */
+
+/* Includes */
+
+#include <soc/imx8/sc/types.h>
+#include <soc/imx8/sc/svc/rm/api.h>
+#include "../../main/rpc.h"
+#include "rpc.h"
+
+/* Local Defines */
+
+/* Local Types */
+
+/* Local Functions */
+
+sc_err_t sc_rm_partition_alloc(sc_ipc_t ipc, sc_rm_pt_t *pt, bool secure,
+ bool isolated, bool restricted, bool grant,
+ bool coherent)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_PARTITION_ALLOC;
+ RPC_U8(&msg, 0) = (uint8_t)secure;
+ RPC_U8(&msg, 1) = (uint8_t)isolated;
+ RPC_U8(&msg, 2) = (uint8_t)restricted;
+ RPC_U8(&msg, 3) = (uint8_t)grant;
+ RPC_U8(&msg, 4) = (uint8_t)coherent;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ if (pt != NULL) {
+ *pt = RPC_U8(&msg, 0);
+ }
+
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_confidential(sc_ipc_t ipc, sc_rm_pt_t pt, bool retro)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_CONFIDENTIAL;
+ RPC_U8(&msg, 0) = pt;
+ RPC_U8(&msg, 1) = (uint8_t)retro;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_partition_free(sc_ipc_t ipc, sc_rm_pt_t pt)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_PARTITION_FREE;
+ RPC_U8(&msg, 0) = pt;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_rm_did_t sc_rm_get_did(sc_ipc_t ipc)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_GET_DID;
+ RPC_SIZE(&msg) = 1;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_rm_did_t) result;
+}
+
+sc_err_t sc_rm_partition_static(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rm_did_t did)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_PARTITION_STATIC;
+ RPC_U8(&msg, 0) = pt;
+ RPC_U8(&msg, 1) = did;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_partition_lock(sc_ipc_t ipc, sc_rm_pt_t pt)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_PARTITION_LOCK;
+ RPC_U8(&msg, 0) = pt;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_get_partition(sc_ipc_t ipc, sc_rm_pt_t *pt)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_GET_PARTITION;
+ RPC_SIZE(&msg) = 1;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ if (pt != NULL) {
+ *pt = RPC_U8(&msg, 0);
+ }
+
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_parent(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rm_pt_t pt_parent)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_PARENT;
+ RPC_U8(&msg, 0) = pt;
+ RPC_U8(&msg, 1) = pt_parent;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_move_all(sc_ipc_t ipc, sc_rm_pt_t pt_src, sc_rm_pt_t pt_dst,
+ bool move_rsrc, bool move_pads)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_MOVE_ALL;
+ RPC_U8(&msg, 0) = pt_src;
+ RPC_U8(&msg, 1) = pt_dst;
+ RPC_U8(&msg, 2) = (uint8_t)move_rsrc;
+ RPC_U8(&msg, 3) = (uint8_t)move_pads;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_assign_resource(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rsrc_t resource)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_ASSIGN_RESOURCE;
+ RPC_U16(&msg, 0) = resource;
+ RPC_U8(&msg, 2) = pt;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_resource_movable(sc_ipc_t ipc, sc_rsrc_t resource_fst,
+ sc_rsrc_t resource_lst, bool movable)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_RESOURCE_MOVABLE;
+ RPC_U16(&msg, 0) = resource_fst;
+ RPC_U16(&msg, 2) = resource_lst;
+ RPC_U8(&msg, 4) = (uint8_t)movable;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_subsys_rsrc_movable(sc_ipc_t ipc, sc_rsrc_t resource,
+ bool movable)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_SUBSYS_RSRC_MOVABLE;
+ RPC_U16(&msg, 0) = resource;
+ RPC_U8(&msg, 2) = (uint8_t)movable;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_master_attributes(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_rm_spa_t sa, sc_rm_spa_t pa,
+ bool smmu_bypass)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_MASTER_ATTRIBUTES;
+ RPC_U16(&msg, 0) = resource;
+ RPC_U8(&msg, 2) = sa;
+ RPC_U8(&msg, 3) = pa;
+ RPC_U8(&msg, 4) = (uint8_t)smmu_bypass;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_master_sid(sc_ipc_t ipc, sc_rsrc_t resource, sc_rm_sid_t sid)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_MASTER_SID;
+ RPC_U16(&msg, 0) = resource;
+ RPC_U16(&msg, 2) = sid;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_peripheral_permissions(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_rm_pt_t pt, sc_rm_perm_t perm)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_PERIPHERAL_PERMISSIONS;
+ RPC_U16(&msg, 0) = resource;
+ RPC_U8(&msg, 2) = pt;
+ RPC_U8(&msg, 3) = perm;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+bool sc_rm_is_resource_owned(sc_ipc_t ipc, sc_rsrc_t resource)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_IS_RESOURCE_OWNED;
+ RPC_U16(&msg, 0) = resource;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (bool)result;
+}
+
+bool sc_rm_is_resource_master(sc_ipc_t ipc, sc_rsrc_t resource)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_IS_RESOURCE_MASTER;
+ RPC_U16(&msg, 0) = resource;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (bool)result;
+}
+
+bool sc_rm_is_resource_peripheral(sc_ipc_t ipc, sc_rsrc_t resource)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_IS_RESOURCE_PERIPHERAL;
+ RPC_U16(&msg, 0) = resource;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (bool)result;
+}
+
+sc_err_t sc_rm_get_resource_info(sc_ipc_t ipc, sc_rsrc_t resource,
+ sc_rm_sid_t *sid)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_GET_RESOURCE_INFO;
+ RPC_U16(&msg, 0) = resource;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (sid != NULL) {
+ *sid = RPC_U16(&msg, 0);
+ }
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_memreg_alloc(sc_ipc_t ipc, sc_rm_mr_t *mr,
+ sc_faddr_t addr_start, sc_faddr_t addr_end)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_MEMREG_ALLOC;
+ RPC_U32(&msg, 0) = (uint32_t)(addr_start >> 32u);
+ RPC_U32(&msg, 4) = (uint32_t)addr_start;
+ RPC_U32(&msg, 8) = (uint32_t)(addr_end >> 32u);
+ RPC_U32(&msg, 12) = (uint32_t)addr_end;
+ RPC_SIZE(&msg) = 5;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ if (mr != NULL) {
+ *mr = RPC_U8(&msg, 0);
+ }
+
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_memreg_split(sc_ipc_t ipc, sc_rm_mr_t mr,
+ sc_rm_mr_t *mr_ret, sc_faddr_t addr_start,
+ sc_faddr_t addr_end)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_MEMREG_SPLIT;
+ RPC_U32(&msg, 0) = (uint32_t)(addr_start >> 32u);
+ RPC_U32(&msg, 4) = (uint32_t)addr_start;
+ RPC_U32(&msg, 8) = (uint32_t)(addr_end >> 32u);
+ RPC_U32(&msg, 12) = (uint32_t)addr_end;
+ RPC_U8(&msg, 16) = mr;
+ RPC_SIZE(&msg) = 6;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ if (mr_ret != NULL) {
+ *mr_ret = RPC_U8(&msg, 0);
+ }
+
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_memreg_free(sc_ipc_t ipc, sc_rm_mr_t mr)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_MEMREG_FREE;
+ RPC_U8(&msg, 0) = mr;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_find_memreg(sc_ipc_t ipc, sc_rm_mr_t *mr,
+ sc_faddr_t addr_start, sc_faddr_t addr_end)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_FIND_MEMREG;
+ RPC_U32(&msg, 0) = (uint32_t)(addr_start >> 32u);
+ RPC_U32(&msg, 4) = (uint32_t)addr_start;
+ RPC_U32(&msg, 8) = (uint32_t)(addr_end >> 32u);
+ RPC_U32(&msg, 12) = (uint32_t)addr_end;
+ RPC_SIZE(&msg) = 5;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ if (mr != NULL) {
+ *mr = RPC_U8(&msg, 0);
+ }
+
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_assign_memreg(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rm_mr_t mr)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_ASSIGN_MEMREG;
+ RPC_U8(&msg, 0) = pt;
+ RPC_U8(&msg, 1) = mr;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_memreg_permissions(sc_ipc_t ipc, sc_rm_mr_t mr,
+ sc_rm_pt_t pt, sc_rm_perm_t perm)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_MEMREG_PERMISSIONS;
+ RPC_U8(&msg, 0) = mr;
+ RPC_U8(&msg, 1) = pt;
+ RPC_U8(&msg, 2) = perm;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+bool sc_rm_is_memreg_owned(sc_ipc_t ipc, sc_rm_mr_t mr)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_IS_MEMREG_OWNED;
+ RPC_U8(&msg, 0) = mr;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (bool)result;
+}
+
+sc_err_t sc_rm_get_memreg_info(sc_ipc_t ipc, sc_rm_mr_t mr,
+ sc_faddr_t *addr_start, sc_faddr_t *addr_end)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_GET_MEMREG_INFO;
+ RPC_U8(&msg, 0) = mr;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (addr_start != NULL) {
+ *addr_start =
+ ((uint64_t) RPC_U32(&msg, 0) << 32u) | RPC_U32(&msg, 4);
+ }
+
+ if (addr_end != NULL) {
+ *addr_end =
+ ((uint64_t) RPC_U32(&msg, 8) << 32u) | RPC_U32(&msg, 12);
+ }
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_assign_pad(sc_ipc_t ipc, sc_rm_pt_t pt, sc_pad_t pad)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_ASSIGN_PAD;
+ RPC_U16(&msg, 0) = pad;
+ RPC_U8(&msg, 2) = pt;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_rm_set_pad_movable(sc_ipc_t ipc, sc_pad_t pad_fst,
+ sc_pad_t pad_lst, bool movable)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_PAD_MOVABLE;
+ RPC_U16(&msg, 0) = pad_fst;
+ RPC_U16(&msg, 2) = pad_lst;
+ RPC_U8(&msg, 4) = (uint8_t)movable;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+bool sc_rm_is_pad_owned(sc_ipc_t ipc, sc_pad_t pad)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_IS_PAD_OWNED;
+ RPC_U8(&msg, 0) = pad;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (bool)result;
+}
+
+void sc_rm_dump(sc_ipc_t ipc)
+{
+ sc_rpc_msg_t msg;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM;
+ RPC_FUNC(&msg) = (uint8_t)RM_FUNC_DUMP;
+ RPC_SIZE(&msg) = 1;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ return;
+}
+
+/**@}*/
diff --git a/drivers/soc/imx/sc/svc/timer/rpc.h b/drivers/soc/imx/sc/svc/timer/rpc.h
new file mode 100644
index 000000000000..42413a049ea4
--- /dev/null
+++ b/drivers/soc/imx/sc/svc/timer/rpc.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*!
+ * Header file for the TIMER RPC implementation.
+ *
+ * @addtogroup TIMER_SVC
+ * @{
+ */
+
+#ifndef _SC_TIMER_RPC_H
+#define _SC_TIMER_RPC_H
+
+/* Includes */
+
+/* Defines */
+
+/* Types */
+
+/*!
+ * This type is used to indicate RPC TIMER function calls.
+ */
+typedef enum timer_func_e {
+ TIMER_FUNC_UNKNOWN = 0, /* Unknown function */
+ TIMER_FUNC_SET_WDOG_TIMEOUT = 1, /* Index for timer_set_wdog_timeout() RPC call */
+ TIMER_FUNC_SET_WDOG_PRE_TIMEOUT = 12, /* Index for timer_set_wdog_pre_timeout() RPC call */
+ TIMER_FUNC_START_WDOG = 2, /* Index for timer_start_wdog() RPC call */
+ TIMER_FUNC_STOP_WDOG = 3, /* Index for timer_stop_wdog() RPC call */
+ TIMER_FUNC_PING_WDOG = 4, /* Index for timer_ping_wdog() RPC call */
+ TIMER_FUNC_GET_WDOG_STATUS = 5, /* Index for timer_get_wdog_status() RPC call */
+ TIMER_FUNC_PT_GET_WDOG_STATUS = 13, /* Index for timer_pt_get_wdog_status() RPC call */
+ TIMER_FUNC_SET_WDOG_ACTION = 10, /* Index for timer_set_wdog_action() RPC call */
+ TIMER_FUNC_SET_RTC_TIME = 6, /* Index for timer_set_rtc_time() RPC call */
+ TIMER_FUNC_GET_RTC_TIME = 7, /* Index for timer_get_rtc_time() RPC call */
+ TIMER_FUNC_GET_RTC_SEC1970 = 9, /* Index for timer_get_rtc_sec1970() RPC call */
+ TIMER_FUNC_SET_RTC_ALARM = 8, /* Index for timer_set_rtc_alarm() RPC call */
+ TIMER_FUNC_SET_RTC_CALB = 11, /* Index for timer_set_rtc_calb() RPC call */
+} timer_func_t;
+
+/* Functions */
+
+/*!
+ * This function dispatches an incoming TIMER RPC request.
+ *
+ * @param[in] caller_pt caller partition
+ * @param[in] msg pointer to RPC message
+ */
+void timer_dispatch(sc_rm_pt_t caller_pt, sc_rpc_msg_t *msg);
+
+/*!
+ * This function translates and dispatches an TIMER RPC request.
+ *
+ * @param[in] ipc IPC handle
+ * @param[in] msg pointer to RPC message
+ */
+void timer_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg);
+
+#endif /* _SC_TIMER_RPC_H */
+
+/**@}*/
diff --git a/drivers/soc/imx/sc/svc/timer/rpc_clnt.c b/drivers/soc/imx/sc/svc/timer/rpc_clnt.c
new file mode 100644
index 000000000000..badb79e44c41
--- /dev/null
+++ b/drivers/soc/imx/sc/svc/timer/rpc_clnt.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*!
+ * File containing client-side RPC functions for the TIMER service. These
+ * functions are ported to clients that communicate to the SC.
+ *
+ * @addtogroup TIMER_SVC
+ * @{
+ */
+
+/* Includes */
+
+#include <soc/imx8/sc/types.h>
+#include <soc/imx8/sc/svc/rm/api.h>
+#include <soc/imx8/sc/svc/timer/api.h>
+#include "../../main/rpc.h"
+#include "rpc.h"
+
+/* Local Defines */
+
+/* Local Types */
+
+/* Local Functions */
+
+sc_err_t sc_timer_set_wdog_timeout(sc_ipc_t ipc, sc_timer_wdog_time_t timeout)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+ RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_WDOG_TIMEOUT;
+ RPC_U32(&msg, 0) = timeout;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_set_wdog_pre_timeout(sc_ipc_t ipc,
+ sc_timer_wdog_time_t pre_timeout)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+ RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_WDOG_PRE_TIMEOUT;
+ RPC_U32(&msg, 0) = pre_timeout;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_start_wdog(sc_ipc_t ipc, bool lock)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+ RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_START_WDOG;
+ RPC_U8(&msg, 0) = (uint8_t)lock;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_stop_wdog(sc_ipc_t ipc)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+ RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_STOP_WDOG;
+ RPC_SIZE(&msg) = 1;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_ping_wdog(sc_ipc_t ipc)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+ RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_PING_WDOG;
+ RPC_SIZE(&msg) = 1;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_get_wdog_status(sc_ipc_t ipc,
+ sc_timer_wdog_time_t *timeout,
+ sc_timer_wdog_time_t *max_timeout,
+ sc_timer_wdog_time_t *remaining_time)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+ RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_GET_WDOG_STATUS;
+ RPC_SIZE(&msg) = 1;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (timeout != NULL) {
+ *timeout = RPC_U32(&msg, 0);
+ }
+
+ if (max_timeout != NULL) {
+ *max_timeout = RPC_U32(&msg, 4);
+ }
+
+ if (remaining_time != NULL) {
+ *remaining_time = RPC_U32(&msg, 8);
+ }
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_pt_get_wdog_status(sc_ipc_t ipc, sc_rm_pt_t pt, bool *enb,
+ sc_timer_wdog_time_t *timeout,
+ sc_timer_wdog_time_t *remaining_time)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+ RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_PT_GET_WDOG_STATUS;
+ RPC_U8(&msg, 0) = pt;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (timeout != NULL) {
+ *timeout = RPC_U32(&msg, 0);
+ }
+
+ if (remaining_time != NULL) {
+ *remaining_time = RPC_U32(&msg, 4);
+ }
+
+ result = RPC_R8(&msg);
+ if (enb != NULL) {
+ *enb = RPC_U8(&msg, 8);
+ }
+
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_set_wdog_action(sc_ipc_t ipc,
+ sc_rm_pt_t pt, sc_timer_wdog_action_t action)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+ RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_WDOG_ACTION;
+ RPC_U8(&msg, 0) = pt;
+ RPC_U8(&msg, 1) = action;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_set_rtc_time(sc_ipc_t ipc, uint16_t year, uint8_t mon,
+ uint8_t day, uint8_t hour, uint8_t min,
+ uint8_t sec)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+ RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_RTC_TIME;
+ RPC_U16(&msg, 0) = year;
+ RPC_U8(&msg, 2) = mon;
+ RPC_U8(&msg, 3) = day;
+ RPC_U8(&msg, 4) = hour;
+ RPC_U8(&msg, 5) = min;
+ RPC_U8(&msg, 6) = sec;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_get_rtc_time(sc_ipc_t ipc, uint16_t *year, uint8_t *mon,
+ uint8_t *day, uint8_t *hour, uint8_t *min,
+ uint8_t *sec)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+ RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_GET_RTC_TIME;
+ RPC_SIZE(&msg) = 1;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (year != NULL) {
+ *year = RPC_U16(&msg, 0);
+ }
+
+ result = RPC_R8(&msg);
+ if (mon != NULL) {
+ *mon = RPC_U8(&msg, 2);
+ }
+
+ if (day != NULL) {
+ *day = RPC_U8(&msg, 3);
+ }
+
+ if (hour != NULL) {
+ *hour = RPC_U8(&msg, 4);
+ }
+
+ if (min != NULL) {
+ *min = RPC_U8(&msg, 5);
+ }
+
+ if (sec != NULL) {
+ *sec = RPC_U8(&msg, 6);
+ }
+
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_get_rtc_sec1970(sc_ipc_t ipc, uint32_t *sec)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+ RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_GET_RTC_SEC1970;
+ RPC_SIZE(&msg) = 1;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ if (sec != NULL) {
+ *sec = RPC_U32(&msg, 0);
+ }
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_set_rtc_alarm(sc_ipc_t ipc, uint16_t year, uint8_t mon,
+ uint8_t day, uint8_t hour, uint8_t min,
+ uint8_t sec)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+ RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_RTC_ALARM;
+ RPC_U16(&msg, 0) = year;
+ RPC_U8(&msg, 2) = mon;
+ RPC_U8(&msg, 3) = day;
+ RPC_U8(&msg, 4) = hour;
+ RPC_U8(&msg, 5) = min;
+ RPC_U8(&msg, 6) = sec;
+ RPC_SIZE(&msg) = 3;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+sc_err_t sc_timer_set_rtc_calb(sc_ipc_t ipc, int8_t count)
+{
+ sc_rpc_msg_t msg;
+ uint8_t result;
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER;
+ RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_RTC_CALB;
+ RPC_I8(&msg, 0) = count;
+ RPC_SIZE(&msg) = 2;
+
+ sc_call_rpc(ipc, &msg, false);
+
+ result = RPC_R8(&msg);
+ return (sc_err_t)result;
+}
+
+/**@}*/
diff --git a/drivers/soc/imx/soc-imx8.c b/drivers/soc/imx/soc-imx8.c
new file mode 100644
index 000000000000..0fc298e9c700
--- /dev/null
+++ b/drivers/soc/imx/soc-imx8.c
@@ -0,0 +1,457 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/cpu.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/pm_opp.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+#include <soc/imx8/sc/sci.h>
+#include <soc/imx8/soc.h>
+#include <soc/imx/revision.h>
+#include <soc/imx/src.h>
+#include <soc/imx/fsl_sip.h>
+
+struct imx8_soc_data {
+ char *name;
+ u32 (*soc_revision)(void);
+};
+
+static u32 imx8_soc_id;
+static u32 imx8_soc_rev = IMX_CHIP_REVISION_UNKNOWN;
+static u64 imx8_soc_uid;
+
+static const struct imx8_soc_data *soc_data;
+
+static inline void imx8_set_soc_revision(u32 rev)
+{
+ imx8_soc_rev = rev;
+}
+
+unsigned int imx8_get_soc_revision(void)
+{
+ return imx8_soc_rev;
+}
+
+static inline void imx8_set_soc_id(u32 id)
+{
+ imx8_soc_id = id;
+}
+
+inline bool cpu_is_imx8qm(void)
+{
+ return imx8_soc_id == IMX_SOC_IMX8QM;
+}
+
+inline bool cpu_is_imx8qxp(void)
+{
+ return imx8_soc_id == IMX_SOC_IMX8QXP;
+}
+
+inline bool cpu_is_imx8mq(void)
+{
+ return imx8_soc_id == IMX_SOC_IMX8MQ;
+}
+
+static u32 imx_init_revision_from_atf(void)
+{
+ struct arm_smccc_res res;
+ u32 digprog;
+ u32 id, rev;
+
+ arm_smccc_smc(FSL_SIP_GET_SOC_INFO, 0, 0,
+ 0, 0, 0, 0, 0, &res);
+ digprog = res.a0;
+
+ /*
+ * Bit [23:16] is the silicon ID
+ * Bit[7:4] is the base layer revision,
+ * Bit[3:0] is the metal layer revision
+ * e.g. 0x10 stands for Tapeout 1.0
+ */
+
+ rev = digprog & 0xff;
+ id = digprog >> 16 & 0xff;
+
+ imx8_set_soc_id(id);
+ imx8_set_soc_revision(rev);
+
+ return rev;
+}
+
+static u32 imx_init_revision_from_scu(void)
+{
+ uint32_t mu_id;
+ sc_err_t sc_err = SC_ERR_NONE;
+ sc_ipc_t ipc_handle;
+ u32 id, rev;
+ u32 uid_l = 0, uid_h = 0;
+
+ sc_err = sc_ipc_getMuID(&mu_id);
+ if (sc_err != SC_ERR_NONE) {
+ WARN(1, "%s: Cannot obtain MU ID\n", __func__);
+
+ return IMX_CHIP_REVISION_UNKNOWN;
+ }
+
+ sc_err = sc_ipc_open(&ipc_handle, mu_id);
+ if (sc_err != SC_ERR_NONE) {
+ WARN(1, "%s: Cannot open MU channel\n", __func__);
+
+ return IMX_CHIP_REVISION_UNKNOWN;
+ };
+
+ sc_err = sc_misc_get_control(ipc_handle, SC_R_SYSTEM, SC_C_ID, &id);
+ if (sc_err != SC_ERR_NONE) {
+ WARN(1, "%s: Cannot get control\n", __func__);
+
+ return IMX_CHIP_REVISION_UNKNOWN;
+ };
+
+ rev = (id >> 5) & 0xf;
+ rev = (((rev >> 2) + 1) << 4) | (rev & 0x3);
+ id &= 0x1f;
+
+ imx8_set_soc_id(id);
+ imx8_set_soc_revision(rev);
+
+ sc_misc_unique_id(ipc_handle, &uid_l, &uid_h);
+
+ imx8_soc_uid = uid_h;
+ imx8_soc_uid <<= 32;
+ imx8_soc_uid |= uid_l;
+
+ return rev;
+}
+
+bool TKT340553_SW_WORKAROUND;
+
+static u32 imx8qm_soc_revision(void)
+{
+ u32 rev = imx_init_revision_from_scu();
+
+ if (rev == IMX_CHIP_REVISION_1_0 || rev == IMX_CHIP_REVISION_1_1)
+ TKT340553_SW_WORKAROUND = true;
+
+ return rev;
+}
+
+static u32 imx8qxp_soc_revision(void)
+{
+ return imx_init_revision_from_scu();
+}
+
+#define OCOTP_UID_LOW 0x410
+#define OCOTP_UID_HIGH 0x420
+
+static u64 imx8mq_soc_get_soc_uid(void)
+{
+ struct device_node *np;
+ void __iomem *base;
+
+ u64 val = 0;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp");
+ if (!np) {
+ pr_warn("failed to find ocotp node\n");
+ return val;
+ }
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_warn("failed to map ocotp\n");
+ goto put_node;
+ }
+
+ val = readl_relaxed(base + OCOTP_UID_HIGH);
+ val <<= 32;
+ val |= readl_relaxed(base + OCOTP_UID_LOW);
+
+ iounmap(base);
+
+put_node:
+ of_node_put(np);
+ return val;
+}
+
+static u32 imx8mq_soc_revision(void)
+{
+ imx8_soc_uid = imx8mq_soc_get_soc_uid();
+ return imx_init_revision_from_atf();
+}
+
+static u32 imx8mm_soc_revision(void)
+{
+ imx8_soc_uid = imx8mq_soc_get_soc_uid();
+ return imx_init_revision_from_atf();
+}
+
+static struct imx8_soc_data imx8qm_soc_data = {
+ .name = "i.MX8QM",
+ .soc_revision = imx8qm_soc_revision,
+};
+
+static struct imx8_soc_data imx8qxp_soc_data = {
+ .name = "i.MX8QXP",
+ .soc_revision = imx8qxp_soc_revision,
+};
+
+static struct imx8_soc_data imx8mq_soc_data = {
+ .name = "i.MX8MQ",
+ .soc_revision = imx8mq_soc_revision,
+};
+
+static struct imx8_soc_data imx8mm_soc_data = {
+ .name = "i.MX8MM",
+ .soc_revision = imx8mm_soc_revision,
+};
+
+static const struct of_device_id imx8_soc_match[] = {
+ { .compatible = "fsl,imx8qm", .data = &imx8qm_soc_data, },
+ { .compatible = "fsl,imx8qxp", .data = &imx8qxp_soc_data, },
+ { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, },
+ { .compatible = "fsl,imx8mm", .data = &imx8mm_soc_data, },
+ /* Fixme: this is a hack for big/little xen guest, b0 no need this */
+ { .compatible = "xen,xenvm", .data = &imx8qm_soc_data, },
+ { }
+};
+
+static int __init imx8_revision_init(void)
+{
+ struct device_node *root;
+ const struct of_device_id *id;
+ const char *machine;
+ u32 rev = IMX_CHIP_REVISION_UNKNOWN;
+ int ret;
+
+ root = of_find_node_by_path("/");
+ ret = of_property_read_string(root, "model", &machine);
+ if (ret)
+ return -ENODEV;
+
+ id = of_match_node(imx8_soc_match, root);
+ if (!id)
+ return -ENODEV;
+
+ of_node_put(root);
+
+ soc_data = id->data;
+ if (soc_data && soc_data->soc_revision)
+ rev = soc_data->soc_revision();
+
+ if (rev == IMX_CHIP_REVISION_UNKNOWN)
+ pr_info("CPU identified as %s, unknown revision\n",
+ soc_data->name);
+ else
+ pr_info("CPU identified as %s, silicon rev %d.%d\n",
+ soc_data->name, (rev >> 4) & 0xf, rev & 0xf);
+
+ return 0;
+}
+early_initcall(imx8_revision_init);
+
+static ssize_t imx8_get_soc_uid(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%016llX\n", imx8_soc_uid);
+}
+
+static struct device_attribute imx8_uid =
+ __ATTR(soc_uid, S_IRUGO, imx8_get_soc_uid, NULL);
+
+static void __init imx8mq_noc_init(void)
+{
+ struct arm_smccc_res res;
+
+ pr_info("Config NOC for VPU and CPU\n");
+
+ arm_smccc_smc(FSL_SIP_NOC, FSL_SIP_NOC_PRIORITY, NOC_CPU_PRIORITY,
+ 0x80000300, 0, 0, 0, 0, &res);
+ if (res.a0)
+ pr_err("Config NOC for CPU fail!\n");
+
+ arm_smccc_smc(FSL_SIP_NOC, FSL_SIP_NOC_PRIORITY, NOC_VPU_PRIORITY,
+ 0x80000300, 0, 0, 0, 0, &res);
+ if (res.a0)
+ pr_err("Config NOC for VPU fail!\n");
+}
+
+static int __init imx8_soc_init(void)
+{
+ struct soc_device_attribute *soc_dev_attr;
+ struct soc_device *soc_dev;
+ u32 soc_rev;
+
+ soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+ if (!soc_dev_attr)
+ return -ENODEV;
+
+ soc_dev_attr->family = "Freescale i.MX";
+
+ if (soc_data)
+ soc_dev_attr->soc_id = soc_data->name;
+
+ soc_rev = imx8_get_soc_revision();
+ soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",
+ (soc_rev >> 4) & 0xf,
+ soc_rev & 0xf);
+ if (!soc_dev_attr->revision)
+ goto free_soc;
+
+ of_property_read_string(of_root, "model", &soc_dev_attr->machine);
+
+ soc_dev = soc_device_register(soc_dev_attr);
+ if (IS_ERR(soc_dev))
+ goto free_rev;
+
+ device_create_file(soc_device_to_device(soc_dev), &imx8_uid);
+
+ if (of_machine_is_compatible("fsl,imx8mq"))
+ imx8mq_noc_init();
+
+ return 0;
+
+free_rev:
+ kfree(soc_dev_attr->revision);
+free_soc:
+ kfree(soc_dev_attr);
+ return -ENODEV;
+}
+device_initcall(imx8_soc_init);
+
+#define OCOTP_CFG3 0x440
+#define OCOTP_CFG3_MKT_SEGMENT_SHIFT 6
+#define OCOTP_CFG3_CONSUMER 0
+#define OCOTP_CFG3_EXT_CONSUMER 1
+#define OCOTP_CFG3_INDUSTRIAL 2
+#define OCOTP_CFG3_AUTO 3
+
+static void __init imx8mq_opp_check_speed_grading(struct device *cpu_dev)
+{
+ struct device_node *np;
+ void __iomem *base;
+ u32 val;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp");
+ if (!np) {
+ pr_warn("failed to find ocotp node\n");
+ return;
+ }
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_warn("failed to map ocotp\n");
+ goto put_node;
+ }
+ val = readl_relaxed(base + OCOTP_CFG3);
+ val >>= OCOTP_CFG3_MKT_SEGMENT_SHIFT;
+ val &= 0x3;
+
+ switch (val) {
+ case OCOTP_CFG3_CONSUMER:
+ if (dev_pm_opp_disable(cpu_dev, 800000000))
+ pr_warn("failed to disable 800MHz OPP!\n");
+ if (dev_pm_opp_disable(cpu_dev, 1300000000))
+ pr_warn("failed to disable 1.3GHz OPP!\n");
+ break;
+ case OCOTP_CFG3_INDUSTRIAL:
+ if (dev_pm_opp_disable(cpu_dev, 1000000000))
+ pr_warn("failed to disable 1GHz OPP!\n");
+ if (dev_pm_opp_disable(cpu_dev, 1500000000))
+ pr_warn("failed to disable 1.5GHz OPP!\n");
+ break;
+ default:
+ /* consumer part for default */
+ if (dev_pm_opp_disable(cpu_dev, 800000000))
+ pr_warn("failed to disable 800MHz OPP!\n");
+ if (dev_pm_opp_disable(cpu_dev, 1300000000))
+ pr_warn("failed to disable 1.3GHz OPP!\n");
+ break;
+ }
+
+ iounmap(base);
+
+put_node:
+ of_node_put(np);
+}
+
+static void __init imx8mq_opp_init(void)
+{
+ struct device_node *np;
+ struct device *cpu_dev = get_cpu_device(0);
+
+ if (!cpu_dev) {
+ pr_warn("failed to get cpu0 device\n");
+ return;
+ }
+ np = of_node_get(cpu_dev->of_node);
+ if (!np) {
+ pr_warn("failed to find cpu0 node\n");
+ return;
+ }
+
+ if (dev_pm_opp_of_add_table(cpu_dev)) {
+ pr_warn("failed to init OPP table\n");
+ goto put_node;
+ }
+
+ if (of_machine_is_compatible("fsl,imx8mq"))
+ imx8mq_opp_check_speed_grading(cpu_dev);
+
+put_node:
+ of_node_put(np);
+}
+
+static int __init imx8_register_cpufreq(void)
+{
+ if (of_machine_is_compatible("fsl,imx8mq") ||
+ of_machine_is_compatible("fsl,imx8mm")) {
+ imx8mq_opp_init();
+ platform_device_register_simple("imx8mq-cpufreq", -1, NULL, 0);
+ } else {
+ platform_device_register_simple("imx8-cpufreq", -1, NULL, 0);
+ }
+
+ return 0;
+}
+late_initcall(imx8_register_cpufreq);
+
+/* To indicate M4 enabled or not on i.MX8MQ */
+static bool m4_is_enabled;
+bool imx_src_is_m4_enabled(void)
+{
+ return m4_is_enabled;
+}
+
+int check_m4_enabled(void)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(FSL_SIP_SRC, FSL_SIP_SRC_M4_STARTED, 0,
+ 0, 0, 0, 0, 0, &res);
+ m4_is_enabled = !!res.a0;
+
+ if (m4_is_enabled)
+ printk("M4 is started\n");
+
+ return 0;
+}
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index b7995474148c..afb563df6e5a 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -289,7 +289,7 @@ config SPI_IMG_SPFI
config SPI_IMX
tristate "Freescale i.MX SPI controllers"
- depends on ARCH_MXC || COMPILE_TEST
+ depends on ARCH_MXC || ARCH_MXC_ARM64 || COMPILE_TEST
select SPI_BITBANG
help
This enables using the Freescale i.MX SPI controllers in master
@@ -379,6 +379,13 @@ config SPI_FSL_ESPI
From MPC8536, 85xx platform uses the controller, and all P10xx,
P20xx, P30xx,P40xx, P50xx uses this controller.
+config SPI_FSL_LPSPI
+ tristate "Freescale i.MX LPSPI controller"
+ depends on ARCH_MXC || ARCH_MXC_ARM64 || COMPILE_TEST
+ select SPI_BITBANG
+ help
+ This enables Freescale i.MX LPSPI controllers in master mode.
+
config SPI_MESON_SPIFC
tristate "Amlogic Meson SPIFC controller"
depends on ARCH_MESON || COMPILE_TEST
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index aa939d955521..aaeb91e8e6ad 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_SPI_FSL_DSPI) += spi-fsl-dspi.o
obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o
obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o
obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o
+obj-$(CONFIG_SPI_FSL_LPSPI) += spi-fsl-lpspi.o
obj-$(CONFIG_SPI_GPIO) += spi-gpio.o
obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o
obj-$(CONFIG_SPI_IMX) += spi-imx.o
diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
new file mode 100644
index 000000000000..6f2566ecac25
--- /dev/null
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -0,0 +1,624 @@
+/*
+ * Freescale i.MX7ULP LPSPI driver
+ *
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#define DEBUG
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/spi-imx.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/types.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pm_runtime.h>
+
+#define DRIVER_NAME "fsl_lpspi"
+
+#define FSL_LPSPI_RPM_TIMEOUT 50 /* 50ms */
+
+/* i.MX7ULP LPSPI registers */
+#define IMX7ULP_VERID 0x0
+#define IMX7ULP_PARAM 0x4
+#define IMX7ULP_CR 0x10
+#define IMX7ULP_SR 0x14
+#define IMX7ULP_IER 0x18
+#define IMX7ULP_DER 0x1c
+#define IMX7ULP_CFGR0 0x20
+#define IMX7ULP_CFGR1 0x24
+#define IMX7ULP_DMR0 0x30
+#define IMX7ULP_DMR1 0x34
+#define IMX7ULP_CCR 0x40
+#define IMX7ULP_FCR 0x58
+#define IMX7ULP_FSR 0x5c
+#define IMX7ULP_TCR 0x60
+#define IMX7ULP_TDR 0x64
+#define IMX7ULP_RSR 0x70
+#define IMX7ULP_RDR 0x74
+
+/* General control register field define */
+#define CR_RRF (1 << 9)
+#define CR_RTF (1 << 8)
+#define CR_RST (1 << 1)
+#define CR_MEN (1 << 0)
+#define SR_TCF (1 << 10)
+#define SR_RDF (1 << 1)
+#define SR_TDF (1 << 0)
+#define IER_TCIE (1 << 10)
+#define IER_RDIE (1 << 1)
+#define IER_TDIE (1 << 0)
+#define CFGR1_PCSCFG (1 << 27) /* PCS[3:2] disabled */
+#define CFGR1_PCSPOL (1 << 8) /* PCS active high */
+#define CFGR1_NOSTALL (1 << 3) /* NO STALL */
+#define CFGR1_SAMPLE (1 << 1) /* SAMPLE POINT*/
+#define CFGR1_MASTER (1 << 0) /* MASTER MODE */
+#define RSR_RXEMPTY (1 << 1)
+#define TCR_CPOL (1 << 31)
+#define TCR_CPHA (1 << 30)
+#define TCR_CONT (1 << 21)
+#define TCR_CONTC (1 << 20)
+#define TCR_RXMSK (1 << 19)
+#define TCR_TXMSK (1 << 18)
+
+static int clkdivs[] = {1, 2, 4, 8, 16, 32, 64, 128};
+
+struct lpspi_config {
+ u8 bpw;
+ u8 chip_select;
+ u8 prescale;
+ u16 mode;
+ u32 speed_hz;
+};
+
+struct fsl_lpspi_data {
+ struct spi_bitbang bitbang;
+ struct device *dev;
+
+ struct completion xfer_done;
+ void __iomem *base;
+ struct clk *clk_per;
+ struct clk *clk_ipg;
+
+ void *rx_buf;
+ const void *tx_buf;
+ void (*tx)(struct fsl_lpspi_data *);
+ void (*rx)(struct fsl_lpspi_data *);
+ struct lpspi_config config;
+
+ u8 txfifosize;
+ u8 rxfifosize;
+ unsigned remain;
+
+ int chipselect[0];
+};
+
+static const struct of_device_id fsl_lpspi_dt_ids[] = {
+ { .compatible = "fsl,imx7ulp-spi", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_lpspi_dt_ids);
+
+#define LPSPI_BUF_RX(type) \
+static void fsl_lpspi_buf_rx_##type(struct fsl_lpspi_data *fsl_lpspi) \
+{ \
+ unsigned int val = readl(fsl_lpspi->base + IMX7ULP_RDR); \
+ \
+ if (fsl_lpspi->rx_buf) { \
+ *(type *)fsl_lpspi->rx_buf = val; \
+ fsl_lpspi->rx_buf += sizeof(type); \
+ } \
+}
+
+#define LPSPI_BUF_TX(type) \
+static void fsl_lpspi_buf_tx_##type(struct fsl_lpspi_data *fsl_lpspi) \
+{ \
+ type val = 0; \
+ \
+ if (fsl_lpspi->tx_buf) { \
+ val = *(type *)fsl_lpspi->tx_buf; \
+ fsl_lpspi->tx_buf += sizeof(type); \
+ } \
+ \
+ fsl_lpspi->remain -= sizeof(type); \
+ writel(val, fsl_lpspi->base + IMX7ULP_TDR); \
+}
+
+LPSPI_BUF_RX(u8)
+LPSPI_BUF_TX(u8)
+LPSPI_BUF_RX(u16)
+LPSPI_BUF_TX(u16)
+LPSPI_BUF_RX(u32)
+LPSPI_BUF_TX(u32)
+
+static void fsl_lpspi_intctrl(
+ struct fsl_lpspi_data *fsl_lpspi, unsigned int enable)
+{
+ writel(enable, fsl_lpspi->base + IMX7ULP_IER);
+}
+
+static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi)
+{
+ u8 txfifo_cnt;
+ u32 temp;
+
+ txfifo_cnt = readl(fsl_lpspi->base + IMX7ULP_FSR) & 0xff;
+
+ while (txfifo_cnt < fsl_lpspi->txfifosize) {
+ if (!fsl_lpspi->remain)
+ break;
+ fsl_lpspi->tx(fsl_lpspi);
+ txfifo_cnt++;
+ }
+
+ if (txfifo_cnt < fsl_lpspi->txfifosize) {
+ temp = readl(fsl_lpspi->base + IMX7ULP_TCR);
+ temp &= ~TCR_CONTC;
+ writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
+
+ fsl_lpspi_intctrl(fsl_lpspi, IER_TCIE);
+ } else
+ fsl_lpspi_intctrl(fsl_lpspi, IER_TDIE);
+}
+
+static void fsl_lpspi_read_rx_fifo(struct fsl_lpspi_data *fsl_lpspi)
+{
+ while (!(readl(fsl_lpspi->base + IMX7ULP_RSR) & RSR_RXEMPTY))
+ fsl_lpspi->rx(fsl_lpspi);
+}
+
+static void fsl_lpspi_set_cmd(struct fsl_lpspi_data *fsl_lpspi)
+{
+ u32 temp = 0;
+
+ temp |= TCR_CONT;
+ temp |= fsl_lpspi->config.bpw - 1;
+ temp |= fsl_lpspi->config.prescale << 27;
+ temp |= (fsl_lpspi->config.mode & 0x3) << 30;
+ temp |= (fsl_lpspi->config.chip_select & 0x3) << 24;
+
+ writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
+
+ dev_dbg(fsl_lpspi->dev, "TCR=0x%x\n", temp);
+}
+
+static void fsl_lpspi_set_watermark(struct fsl_lpspi_data *fsl_lpspi)
+{
+ u32 temp;
+ u8 txwatermark, rxwatermark;
+
+ temp = readl(fsl_lpspi->base + IMX7ULP_PARAM);
+
+ fsl_lpspi->txfifosize = 1 << (temp & 0x0f);
+ fsl_lpspi->rxfifosize = 1 << ((temp >> 8) & 0x0f);
+
+ rxwatermark = fsl_lpspi->txfifosize >> 1;
+ txwatermark = fsl_lpspi->rxfifosize >> 1;
+ temp = txwatermark | rxwatermark << 16;
+
+ writel(temp, fsl_lpspi->base + IMX7ULP_FCR);
+
+ dev_dbg(fsl_lpspi->dev, "FCR=0x%x\n", temp);
+}
+
+static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
+{
+ u8 prescale;
+ unsigned int perclk_rate, scldiv;
+ struct lpspi_config config = fsl_lpspi->config;
+
+ perclk_rate = clk_get_rate(fsl_lpspi->clk_per);
+
+ for (prescale = 0; prescale < 8; prescale++) {
+ scldiv = perclk_rate / (clkdivs[prescale] * config.speed_hz) - 2;
+ if (scldiv < 256) {
+ fsl_lpspi->config.prescale = prescale;
+ break;
+ }
+ }
+
+ if (prescale == 8 && scldiv >= 256)
+ return -EINVAL;
+
+ writel(scldiv | (scldiv << 8), fsl_lpspi->base + IMX7ULP_CCR);
+
+ dev_dbg(fsl_lpspi->dev, "perclk=%d, speed=%d, prescale =%d, scldiv=%d\n",
+ perclk_rate, config.speed_hz, prescale, scldiv);
+
+ return 0;
+}
+
+static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
+{
+ int ret;
+ u32 temp;
+
+ temp = CR_RST;
+ writel(temp, fsl_lpspi->base + IMX7ULP_CR);
+ writel(0, fsl_lpspi->base + IMX7ULP_CR);
+
+ ret = fsl_lpspi_set_bitrate(fsl_lpspi);
+ if (ret)
+ return ret;
+
+ fsl_lpspi_set_watermark(fsl_lpspi);
+
+ temp = CFGR1_PCSCFG | CFGR1_MASTER
+ | CFGR1_SAMPLE | CFGR1_NOSTALL;
+
+ /* chip select polarity */
+ if (fsl_lpspi->config.mode & SPI_CS_HIGH)
+ temp |= CFGR1_PCSPOL;
+
+ writel(temp, fsl_lpspi->base + IMX7ULP_CFGR1);
+
+ temp = readl(fsl_lpspi->base + IMX7ULP_CR);
+ temp |= CR_RRF | CR_RTF | CR_MEN;
+ writel(temp, fsl_lpspi->base + IMX7ULP_CR);
+
+ return 0;
+}
+
+static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id)
+{
+ u32 temp;
+ struct fsl_lpspi_data *fsl_lpspi = dev_id;
+
+ fsl_lpspi_intctrl(fsl_lpspi, 0);
+ temp = readl(fsl_lpspi->base + IMX7ULP_SR);
+
+ fsl_lpspi_read_rx_fifo(fsl_lpspi);
+
+ if ((temp & SR_TDF) && !(temp & SR_TCF)) {
+ fsl_lpspi_write_tx_fifo(fsl_lpspi);
+ return IRQ_HANDLED;
+ }
+
+ if (temp & SR_TCF) {
+ complete(&fsl_lpspi->xfer_done);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static void fsl_lpspi_chipselect(struct spi_device *spi, int is_active)
+{
+ struct fsl_lpspi_data *fsl_lpspi = spi_master_get_devdata(spi->master);
+ int gpio = fsl_lpspi->chipselect[spi->chip_select];
+ int active = is_active != BITBANG_CS_INACTIVE;
+ int dev_is_lowactive = !(spi->mode & SPI_CS_HIGH);
+
+ if (!gpio_is_valid(gpio))
+ return;
+
+ gpio_set_value(gpio, dev_is_lowactive ^ active);
+}
+
+static int fsl_lpspi_setupxfer(struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct fsl_lpspi_data *fsl_lpspi = spi_master_get_devdata(spi->master);
+
+ fsl_lpspi->config.mode = spi->mode;
+ fsl_lpspi->config.bpw = t ? t->bits_per_word : spi->bits_per_word;
+ fsl_lpspi->config.speed_hz = t ? t->speed_hz : spi->max_speed_hz;
+ fsl_lpspi->config.chip_select = spi->chip_select;
+
+ if (!fsl_lpspi->config.speed_hz)
+ fsl_lpspi->config.speed_hz = spi->max_speed_hz;
+ if (!fsl_lpspi->config.bpw)
+ fsl_lpspi->config.bpw = spi->bits_per_word;
+
+ /* Initialize the functions for transfer */
+ if (fsl_lpspi->config.bpw <= 8) {
+ fsl_lpspi->rx = fsl_lpspi_buf_rx_u8;
+ fsl_lpspi->tx = fsl_lpspi_buf_tx_u8;
+ } else if (fsl_lpspi->config.bpw <= 16) {
+ fsl_lpspi->rx = fsl_lpspi_buf_rx_u16;
+ fsl_lpspi->tx = fsl_lpspi_buf_tx_u16;
+ } else {
+ fsl_lpspi->rx = fsl_lpspi_buf_rx_u32;
+ fsl_lpspi->tx = fsl_lpspi_buf_tx_u32;
+ }
+
+ fsl_lpspi_config(fsl_lpspi);
+
+ return 0;
+}
+
+static int fsl_lpspi_transfer(struct spi_device *spi,
+ struct spi_transfer *transfer)
+{
+ struct fsl_lpspi_data *fsl_lpspi = spi_master_get_devdata(spi->master);
+
+ fsl_lpspi->tx_buf = transfer->tx_buf;
+ fsl_lpspi->rx_buf = transfer->rx_buf;
+ fsl_lpspi->remain = transfer->len;
+
+ reinit_completion(&fsl_lpspi->xfer_done);
+ fsl_lpspi_set_cmd(fsl_lpspi);
+ fsl_lpspi_write_tx_fifo(fsl_lpspi);
+ wait_for_completion(&fsl_lpspi->xfer_done);
+
+ return transfer->len;
+}
+
+/* The following funs are decided by spi framework */
+
+static int fsl_lpspi_setup(struct spi_device *spi)
+{
+ struct fsl_lpspi_data *fsl_lpspi = spi_master_get_devdata(spi->master);
+ int gpio = fsl_lpspi->chipselect[spi->chip_select];
+
+ dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__,
+ spi->mode, spi->bits_per_word, spi->max_speed_hz);
+
+ if (gpio_is_valid(gpio))
+ gpio_direction_output(gpio,
+ spi->mode & SPI_CS_HIGH ? 0 : 1);
+
+ fsl_lpspi_chipselect(spi, BITBANG_CS_INACTIVE);
+
+ return 0;
+}
+
+static void fsl_lpspi_cleanup(struct spi_device *spi)
+{
+}
+
+static int
+fsl_lpspi_prepare_message(struct spi_master *master, struct spi_message *msg)
+{
+ struct fsl_lpspi_data *fsl_lpspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = pm_runtime_get_sync(fsl_lpspi->dev);
+ if (ret < 0) {
+ dev_err(fsl_lpspi->dev, "failed to enable clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+fsl_lpspi_unprepare_message(struct spi_master *master, struct spi_message *msg)
+{
+ struct fsl_lpspi_data *fsl_lpspi = spi_master_get_devdata(master);
+
+ pm_runtime_mark_last_busy(fsl_lpspi->dev);
+ pm_runtime_put_autosuspend(fsl_lpspi->dev);
+
+ return 0;
+}
+
+int fsl_lpspi_runtime_resume(struct device *dev)
+{
+ struct fsl_lpspi_data *fsl_lpspi = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(fsl_lpspi->clk_per);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(fsl_lpspi->clk_ipg);
+ if (ret) {
+ clk_disable_unprepare(fsl_lpspi->clk_per);
+ return ret;
+ }
+
+ return 0;
+}
+
+int fsl_lpspi_runtime_suspend(struct device *dev)
+{
+ struct fsl_lpspi_data *fsl_lpspi = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(fsl_lpspi->clk_per);
+ clk_disable_unprepare(fsl_lpspi->clk_ipg);
+
+ return 0;
+}
+
+static int fsl_lpspi_init_rpm(struct fsl_lpspi_data *fsl_lpspi)
+{
+ struct device *dev = fsl_lpspi->dev;
+
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, FSL_LPSPI_RPM_TIMEOUT);
+ pm_runtime_use_autosuspend(dev);
+
+ return 0;
+}
+
+static int fsl_lpspi_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct spi_master *master;
+ struct fsl_lpspi_data *fsl_lpspi;
+ struct spi_imx_master *lpspi_platform_info =
+ dev_get_platdata(&pdev->dev);
+ struct resource *res;
+ int i, ret, irq;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_lpspi_data));
+ if (!master)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, master);
+
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
+ master->bus_num = pdev->id;
+
+ fsl_lpspi = spi_master_get_devdata(master);
+ fsl_lpspi->bitbang.master = master;
+ fsl_lpspi->dev = &pdev->dev;
+ dev_set_drvdata(&pdev->dev, fsl_lpspi);
+
+ for (i = 0; i < master->num_chipselect; i++) {
+ int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
+
+ if (!gpio_is_valid(cs_gpio) && lpspi_platform_info)
+ cs_gpio = lpspi_platform_info->chipselect[i];
+
+ fsl_lpspi->chipselect[i] = cs_gpio;
+ if (!gpio_is_valid(cs_gpio))
+ continue;
+
+ ret = devm_gpio_request(&pdev->dev, fsl_lpspi->chipselect[i],
+ DRIVER_NAME);
+ if (ret) {
+ dev_err(&pdev->dev, "can't get cs gpios\n");
+ goto out_master_put;
+ }
+ }
+
+ fsl_lpspi->bitbang.chipselect = fsl_lpspi_chipselect;
+ fsl_lpspi->bitbang.master->setup = fsl_lpspi_setup;
+ fsl_lpspi->bitbang.master->cleanup = fsl_lpspi_cleanup;
+ fsl_lpspi->bitbang.setup_transfer = fsl_lpspi_setupxfer;
+ fsl_lpspi->bitbang.txrx_bufs = fsl_lpspi_transfer;
+ fsl_lpspi->bitbang.master->prepare_message = fsl_lpspi_prepare_message;
+ fsl_lpspi->bitbang.master->unprepare_message = fsl_lpspi_unprepare_message;
+ fsl_lpspi->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ fsl_lpspi->bitbang.master->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX;
+
+ init_completion(&fsl_lpspi->xfer_done);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ fsl_lpspi->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(fsl_lpspi->base)) {
+ ret = PTR_ERR(fsl_lpspi->base);
+ goto out_master_put;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = irq;
+ goto out_master_put;
+ }
+
+ fsl_lpspi->clk_per = devm_clk_get(&pdev->dev, "per");
+ if (IS_ERR(fsl_lpspi->clk_per)) {
+ ret = PTR_ERR(fsl_lpspi->clk_per);
+ goto out_master_put;
+ }
+
+ fsl_lpspi->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
+ if (IS_ERR(fsl_lpspi->clk_ipg)) {
+ ret = PTR_ERR(fsl_lpspi->clk_ipg);
+ goto out_master_put;
+ }
+
+ /* enable the clock */
+ ret = fsl_lpspi_init_rpm(fsl_lpspi);
+ if (ret)
+ goto out_master_put;
+
+ ret = devm_request_irq(&pdev->dev, irq, fsl_lpspi_isr, 0,
+ dev_name(&pdev->dev), fsl_lpspi);
+ if (ret) {
+ dev_err(&pdev->dev, "can't get irq%d: %d\n", irq, ret);
+ goto out_master_put;
+ }
+
+ master->dev.of_node = pdev->dev.of_node;
+ ret = spi_bitbang_start(&fsl_lpspi->bitbang);
+ if (ret) {
+ dev_err(&pdev->dev, "bitbang start failed with %d\n", ret);
+ goto out_master_put;
+ }
+
+ dev_info(fsl_lpspi->dev, "lpspi probed\n");
+
+ return ret;
+
+out_master_put:
+ spi_master_put(master);
+
+ return ret;
+}
+
+static int fsl_lpspi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct fsl_lpspi_data *fsl_lpspi = spi_master_get_devdata(master);
+
+ spi_bitbang_stop(&fsl_lpspi->bitbang);
+ pm_runtime_disable(fsl_lpspi->dev);
+
+ spi_master_put(master);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fsl_lpspi_suspend(struct device *dev)
+{
+ int ret;
+
+ pinctrl_pm_select_sleep_state(dev);
+ ret = pm_runtime_force_suspend(dev);
+ return ret;
+}
+
+static int fsl_lpspi_resume(struct device *dev)
+{
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret) {
+ dev_err(dev, "Error in resume: %d\n", ret);
+ return ret;
+ }
+
+ pinctrl_pm_select_default_state(dev);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops fsl_lpspi_pm_ops = {
+ SET_RUNTIME_PM_OPS(fsl_lpspi_runtime_suspend, fsl_lpspi_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(fsl_lpspi_suspend, fsl_lpspi_resume)
+};
+
+static struct platform_driver fsl_lpspi_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = fsl_lpspi_dt_ids,
+ .pm = &fsl_lpspi_pm_ops,
+ },
+ .probe = fsl_lpspi_probe,
+ .remove = fsl_lpspi_remove,
+};
+module_platform_driver(fsl_lpspi_driver);
+
+MODULE_DESCRIPTION("SPI Master Controller driver");
+MODULE_AUTHOR("Gao Pan <pandy.gao@nxp.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index a6e34f05d44d..91764a44c6f7 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -68,6 +68,7 @@ enum spi_imx_devtype {
IMX31_CSPI,
IMX35_CSPI, /* CSPI on all i.mx except above */
IMX51_ECSPI, /* ECSPI on i.mx51 and later */
+ IMX6UL_ECSPI,
};
struct spi_imx_data;
@@ -124,7 +125,8 @@ static inline int is_imx35_cspi(struct spi_imx_data *d)
static inline int is_imx51_ecspi(struct spi_imx_data *d)
{
- return d->devtype_data->devtype == IMX51_ECSPI;
+ return d->devtype_data->devtype == IMX51_ECSPI ||
+ d->devtype_data->devtype == IMX6UL_ECSPI;
}
static inline unsigned spi_imx_get_fifosize(struct spi_imx_data *d)
@@ -326,10 +328,17 @@ static void mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int enable)
static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
{
- u32 reg;
-
- reg = readl(spi_imx->base + MX51_ECSPI_CTRL);
- reg |= MX51_ECSPI_CTRL_XCH;
+ u32 reg = readl(spi_imx->base + MX51_ECSPI_CTRL);
+ /*
+ * To workaround ERR008517, SDMA script need use XCH instead of SMC
+ * just like PIO mode and it fix on i.mx6ul
+ */
+ if (!spi_imx->usedma)
+ reg |= MX51_ECSPI_CTRL_XCH;
+ else if (spi_imx->devtype_data->devtype == IMX6UL_ECSPI)
+ reg |= MX51_ECSPI_CTRL_SMC;
+ else
+ reg &= ~MX51_ECSPI_CTRL_SMC;
writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
}
@@ -340,6 +349,7 @@ static int mx51_ecspi_config(struct spi_device *spi,
u32 ctrl = MX51_ECSPI_CTRL_ENABLE;
u32 clk = config->speed_hz, delay, reg;
u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
+ int tx_wml = 0;
/*
* The hardware seems to have a race condition when changing modes. The
@@ -414,9 +424,11 @@ static int mx51_ecspi_config(struct spi_device *spi,
* Configure the DMA register: setup the watermark
* and enable DMA request.
*/
+ if (spi_imx->devtype_data->devtype == IMX6UL_ECSPI)
+ tx_wml = spi_imx->wml / 2;
writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml) |
- MX51_ECSPI_DMA_TX_WML(spi_imx->wml) |
+ MX51_ECSPI_DMA_TX_WML(tx_wml) |
MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) |
MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN |
MX51_ECSPI_DMA_RXTDEN, spi_imx->base + MX51_ECSPI_DMA);
@@ -723,7 +735,16 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
.devtype = IMX51_ECSPI,
};
-static const struct platform_device_id spi_imx_devtype[] = {
+static struct spi_imx_devtype_data imx6ul_ecspi_devtype_data = {
+ .intctrl = mx51_ecspi_intctrl,
+ .config = mx51_ecspi_config,
+ .trigger = mx51_ecspi_trigger,
+ .rx_available = mx51_ecspi_rx_available,
+ .reset = mx51_ecspi_reset,
+ .devtype = IMX6UL_ECSPI,
+};
+
+static struct platform_device_id spi_imx_devtype[] = {
{
.name = "imx1-cspi",
.driver_data = (kernel_ulong_t) &imx1_cspi_devtype_data,
@@ -743,6 +764,9 @@ static const struct platform_device_id spi_imx_devtype[] = {
.name = "imx51-ecspi",
.driver_data = (kernel_ulong_t) &imx51_ecspi_devtype_data,
}, {
+ .name = "imx6ul-ecspi",
+ .driver_data = (kernel_ulong_t) &imx6ul_ecspi_devtype_data,
+ }, {
/* sentinel */
}
};
@@ -754,6 +778,7 @@ static const struct of_device_id spi_imx_dt_ids[] = {
{ .compatible = "fsl,imx31-cspi", .data = &imx31_cspi_devtype_data, },
{ .compatible = "fsl,imx35-cspi", .data = &imx35_cspi_devtype_data, },
{ .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, },
+ { .compatible = "fsl,imx6ul-ecspi", .data = &imx6ul_ecspi_devtype_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, spi_imx_dt_ids);
@@ -839,7 +864,7 @@ static int spi_imx_dma_configure(struct spi_master *master,
tx.direction = DMA_MEM_TO_DEV;
tx.dst_addr = spi_imx->base_phys + MXC_CSPITXDATA;
tx.dst_addr_width = buswidth;
- tx.dst_maxburst = spi_imx->wml;
+ tx.dst_maxburst = spi_imx->wml / 2;
ret = dmaengine_slave_config(master->dma_tx, &tx);
if (ret) {
dev_err(spi_imx->dev, "TX dma configuration failed with %d\n", ret);
@@ -925,10 +950,6 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
{
int ret;
- /* use pio mode for i.mx6dl chip TKT238285 */
- if (of_machine_is_compatible("fsl,imx6dl"))
- return 0;
-
spi_imx->wml = spi_imx_get_fifosize(spi_imx) / 2;
/* Prepare for TX DMA: */
@@ -1033,6 +1054,8 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
+ spi_imx->devtype_data->trigger(spi_imx);
+
/* Wait SDMA to finish the data transfer.*/
timeout = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
transfer_timeout);
@@ -1121,13 +1144,13 @@ spi_imx_prepare_message(struct spi_master *master, struct spi_message *msg)
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
int ret;
- ret = clk_enable(spi_imx->clk_per);
+ ret = clk_prepare_enable(spi_imx->clk_per);
if (ret)
return ret;
- ret = clk_enable(spi_imx->clk_ipg);
+ ret = clk_prepare_enable(spi_imx->clk_ipg);
if (ret) {
- clk_disable(spi_imx->clk_per);
+ clk_disable_unprepare(spi_imx->clk_per);
return ret;
}
@@ -1139,8 +1162,8 @@ spi_imx_unprepare_message(struct spi_master *master, struct spi_message *msg)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
- clk_disable(spi_imx->clk_ipg);
- clk_disable(spi_imx->clk_per);
+ clk_disable_unprepare(spi_imx->clk_ipg);
+ clk_disable_unprepare(spi_imx->clk_per);
return 0;
}
@@ -1154,13 +1177,21 @@ static int spi_imx_probe(struct platform_device *pdev)
struct spi_master *master;
struct spi_imx_data *spi_imx;
struct resource *res;
- int i, ret, irq;
+ int i, ret, irq, num_cs;
if (!np && !mxc_platform_info) {
dev_err(&pdev->dev, "can't get the platform data\n");
return -EINVAL;
}
+ ret = of_property_read_u32(np, "fsl,spi-num-chipselects", &num_cs);
+ if (ret < 0) {
+ if (mxc_platform_info)
+ num_cs = mxc_platform_info->num_chipselect;
+ else
+ return ret;
+ }
+
master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data));
if (!master)
return -ENOMEM;
@@ -1169,6 +1200,7 @@ static int spi_imx_probe(struct platform_device *pdev)
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
master->bus_num = np ? -1 : pdev->id;
+ master->num_chipselect = num_cs;
spi_imx = spi_master_get_devdata(master);
spi_imx->bitbang.master = master;
@@ -1177,16 +1209,32 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->devtype_data = of_id ? of_id->data :
(struct spi_imx_devtype_data *)pdev->id_entry->driver_data;
- if (mxc_platform_info) {
- master->num_chipselect = mxc_platform_info->num_chipselect;
- master->cs_gpios = devm_kzalloc(&master->dev,
+ master->cs_gpios = devm_kzalloc(&master->dev,
sizeof(int) * master->num_chipselect, GFP_KERNEL);
- if (!master->cs_gpios)
- return -ENOMEM;
- for (i = 0; i < master->num_chipselect; i++)
- master->cs_gpios[i] = mxc_platform_info->chipselect[i];
- }
+ if (!master->cs_gpios) {
+ dev_err(&pdev->dev, "No CS GPIOs available\n");
+ ret = -EINVAL;
+ goto out_master_put;
+ }
+
+ for (i = 0; i < master->num_chipselect; i++) {
+ int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
+ if (!gpio_is_valid(cs_gpio) && mxc_platform_info)
+ cs_gpio = mxc_platform_info->chipselect[i];
+
+ master->cs_gpios[i] = cs_gpio;
+ if (!gpio_is_valid(cs_gpio))
+ continue;
+
+ ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i],
+ DRIVER_NAME);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't get CS GPIO %i\n",
+ master->cs_gpios[i]);
+ goto out_master_put;
+ }
+ }
spi_imx->bitbang.chipselect = spi_imx_chipselect;
spi_imx->bitbang.setup_transfer = spi_imx_setupxfer;
@@ -1268,29 +1316,10 @@ static int spi_imx_probe(struct platform_device *pdev)
goto out_clk_put;
}
- if (!master->cs_gpios) {
- dev_err(&pdev->dev, "No CS GPIOs available\n");
- ret = -EINVAL;
- goto out_clk_put;
- }
-
- for (i = 0; i < master->num_chipselect; i++) {
- if (!gpio_is_valid(master->cs_gpios[i]))
- continue;
-
- ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i],
- DRIVER_NAME);
- if (ret) {
- dev_err(&pdev->dev, "Can't get CS GPIO %i\n",
- master->cs_gpios[i]);
- goto out_clk_put;
- }
- }
-
dev_info(&pdev->dev, "probed\n");
- clk_disable(spi_imx->clk_ipg);
- clk_disable(spi_imx->clk_per);
+ clk_disable_unprepare(spi_imx->clk_ipg);
+ clk_disable_unprepare(spi_imx->clk_per);
return ret;
out_clk_put:
@@ -1330,11 +1359,31 @@ static int spi_imx_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int spi_imx_suspend(struct device *dev)
+{
+ pinctrl_pm_select_sleep_state(dev);
+ return 0;
+}
+
+static int spi_imx_resume(struct device *dev)
+{
+ pinctrl_pm_select_default_state(dev);
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(imx_spi_pm, spi_imx_suspend, spi_imx_resume);
+#define IMX_SPI_PM (&imx_spi_pm)
+#else
+#define IMX_SPI_PM NULL
+#endif
+
static struct platform_driver spi_imx_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = spi_imx_dt_ids,
- },
+ .pm = IMX_SPI_PM,
+ },
.id_table = spi_imx_devtype,
.probe = spi_imx_probe,
.remove = spi_imx_remove,
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index c2e85e23d538..2ebcd1851ab0 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -722,6 +722,7 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
int desc_len;
int sgs;
struct page *vm_page;
+ struct scatterlist *sg;
void *sg_buf;
size_t min;
int i, ret;
@@ -740,6 +741,7 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
if (ret != 0)
return ret;
+ sg = &sgt->sgl[0];
for (i = 0; i < sgs; i++) {
if (vmalloced_buf || kmap_buf) {
@@ -759,16 +761,17 @@ static int spi_map_buf(struct spi_master *master, struct device *dev,
sg_free_table(sgt);
return -ENOMEM;
}
- sg_set_page(&sgt->sgl[i], vm_page,
+ sg_set_page(sg, vm_page,
min, offset_in_page(buf));
} else {
min = min_t(size_t, len, desc_len);
sg_buf = buf;
- sg_set_buf(&sgt->sgl[i], sg_buf, min);
+ sg_set_buf(sg, sg_buf, min);
}
buf += min;
len -= min;
+ sg = sg_next(sg);
}
ret = dma_map_sg(dev, sgt->sgl, sgt->nents, dir);
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 58a7b3504b82..d250ce5b82af 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -106,4 +106,6 @@ source "drivers/staging/greybus/Kconfig"
source "drivers/staging/vc04_services/Kconfig"
+source "drivers/staging/typec/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 2fa9745db614..758980875124 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -2,6 +2,7 @@
obj-y += media/
obj-$(CONFIG_SLICOSS) += slicoss/
+obj-y += typec/
obj-$(CONFIG_PRISM2_USB) += wlan-ng/
obj-$(CONFIG_COMEDI) += comedi/
obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/
@@ -22,7 +23,7 @@ obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_USB_EMXX) += emxx_udc/
obj-$(CONFIG_SPEAKUP) += speakup/
obj-$(CONFIG_MFD_NVEC) += nvec/
-obj-$(CONFIG_ANDROID) += android/
+obj-y += android/
obj-$(CONFIG_STAGING_BOARD) += board/
obj-$(CONFIG_LTE_GDM724X) += gdm724x/
obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index 6c00d6f765c6..6b2b942ebfc3 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -24,8 +24,8 @@ config ANDROID_LOW_MEMORY_KILLER
scripts (/init.rc), and it defines priority values with minimum free memory size
for each priority.
-source "drivers/staging/android/ion/Kconfig"
-
endif # if ANDROID
+source "drivers/staging/android/ion/Kconfig"
+
endmenu
diff --git a/drivers/staging/android/ion/Kconfig b/drivers/staging/android/ion/Kconfig
index c8fb4134c55d..21d3bcaa10d3 100644
--- a/drivers/staging/android/ion/Kconfig
+++ b/drivers/staging/android/ion/Kconfig
@@ -42,6 +42,14 @@ config ION_HISI
source "drivers/staging/android/ion/hisilicon/Kconfig"
+config ION_MXC
+ tristate "Ion for imx platform"
+ depends on ION
+ select VIDEOBUF2_DMA_CONTIG
+ select ION_OF
+ help
+ Choose this option if you wish to use ion on imx platform.
+
config ION_OF
bool "Devicetree support for Ion"
depends on ION && OF_ADDRESS
@@ -52,3 +60,37 @@ config ION_OF
extensions
If using Ion and devicetree, you should say Y here
+
+config ION_UNMAPPED_HEAP
+ bool "unmapped heap support in ION"
+ depends on ION && (ARM || ARM64)
+ default y
+ help
+ ION unmapped heap is not available on some architectures.
+ If unmapped heap is supported, the default configuration enables
+ it. You should say N here only if you really do not want unmapped
+ heap support in the ION driver.
+
+config ION_DUMMY_UNMAPPED_HEAP
+ bool "ION dummy driver define an ION unmapped heap"
+ depends on ION_DUMMY && ION_UNMAPPED_HEAP
+ help
+ Dummy ION driver will create a unmapped heap from physical
+ location provided through CONFIG_ION_DUMMY_UNMAPPED_BASE and
+ CONFIG_ION_DUMMY_UNMAPPED_SIZE.
+
+config ION_DUMMY_UNMAPPED_BASE
+ hex "Physical base address of the ION unmapped heap"
+ depends on ION_DUMMY_UNMAPPED_HEAP
+ default 0
+ help
+ Allows one the statically define an unmapped heap from the
+ ION dummy driver to exercice unamped heaps buffer managment.
+
+config ION_DUMMY_UNMAPPED_SIZE
+ hex "Physical byte size of the ION unmapped heap"
+ depends on ION_DUMMY_UNMAPPED_HEAP
+ default 0
+ help
+ Allows one the statically define an unmapped heap from the
+ ION dummy driver to exercice unamped heaps buffer managment.
diff --git a/drivers/staging/android/ion/Makefile b/drivers/staging/android/ion/Makefile
index 5d630a088381..6653353e86d8 100644
--- a/drivers/staging/android/ion/Makefile
+++ b/drivers/staging/android/ion/Makefile
@@ -1,6 +1,9 @@
obj-$(CONFIG_ION) += ion.o ion-ioctl.o ion_heap.o \
ion_page_pool.o ion_system_heap.o \
ion_carveout_heap.o ion_chunk_heap.o ion_cma_heap.o
+
+obj-$(CONFIG_ION_UNMAPPED_HEAP) += ion_unmapped_heap.o
+
obj-$(CONFIG_ION_TEST) += ion_test.o
ifdef CONFIG_COMPAT
obj-$(CONFIG_ION) += compat_ion.o
@@ -9,5 +12,5 @@ endif
obj-$(CONFIG_ION_DUMMY) += ion_dummy_driver.o
obj-$(CONFIG_ION_TEGRA) += tegra/
obj-$(CONFIG_ION_HISI) += hisilicon/
+obj-$(CONFIG_ION_MXC) += mxc/
obj-$(CONFIG_ION_OF) += ion_of.o
-
diff --git a/drivers/staging/android/ion/devicetree.txt b/drivers/staging/android/ion/devicetree.txt
index 168715271f06..ca73ff88dc7d 100644
--- a/drivers/staging/android/ion/devicetree.txt
+++ b/drivers/staging/android/ion/devicetree.txt
@@ -25,6 +25,7 @@ for the specific instance of the heap. Current heap types
-- linux,ion-heap-chunk
-- linux,ion-heap-dma
-- linux,ion-heap-custom
+-- linux,ion-heap-unmapped
Optional properties
- memory-region: A phandle to a memory region. Required for DMA heap type
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 806e9b30b9dc..2be0f3d02357 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -3,6 +3,7 @@
* drivers/staging/android/ion/ion.c
*
* Copyright (C) 2011 Google, Inc.
+ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -363,6 +364,33 @@ struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client,
return ERR_PTR(-EINVAL);
}
+/* for used in mxc_ion.c */
+int ion_handle_put_wrap(struct ion_handle *handle)
+{
+ return ion_handle_put(handle);
+}
+
+struct ion_handle *ion_handle_get_by_id_wrap(struct ion_client *client,
+ int id)
+{
+ // copy previous ion_handle_get_by_id as used by mxc...
+ struct ion_handle *handle;
+
+ mutex_lock(&client->lock);
+ handle = ion_handle_get_by_id_nolock(client, id);
+ mutex_unlock(&client->lock);
+
+ return handle;
+}
+
+struct device *ion_device_get_by_client(struct ion_client *client)
+{
+ if (client)
+ return client->dev->dev.this_device;
+ else
+ return NULL;
+}
+
static bool ion_handle_validate(struct ion_client *client,
struct ion_handle *handle)
{
@@ -1015,6 +1043,21 @@ static int ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf,
return 0;
}
+static void *ion_dma_buf_vmap(struct dma_buf *dmabuf)
+{
+ struct ion_buffer *buffer = dmabuf->priv;
+
+ if (ion_dma_buf_begin_cpu_access(dmabuf, DMA_NONE) != 0)
+ return NULL;
+
+ return buffer->vaddr;
+}
+
+static void ion_dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
+{
+ ion_dma_buf_end_cpu_access(dmabuf, DMA_NONE);
+}
+
static struct dma_buf_ops dma_buf_ops = {
.map_dma_buf = ion_map_dma_buf,
.unmap_dma_buf = ion_unmap_dma_buf,
@@ -1026,6 +1069,8 @@ static struct dma_buf_ops dma_buf_ops = {
.kunmap_atomic = ion_dma_buf_kunmap,
.kmap = ion_dma_buf_kmap,
.kunmap = ion_dma_buf_kunmap,
+ .vmap = ion_dma_buf_vmap,
+ .vunmap = ion_dma_buf_vunmap,
};
static struct dma_buf *__ion_share_dma_buf(struct ion_client *client,
@@ -1222,6 +1267,7 @@ int ion_query_heaps(struct ion_client *client, struct ion_heap_query *query)
}
query->cnt = cnt;
+ ret = 0;
out:
up_read(&dev->lock);
return ret;
diff --git a/drivers/staging/android/ion/ion_dummy_driver.c b/drivers/staging/android/ion/ion_dummy_driver.c
index b23f2c76c753..504c379ab036 100644
--- a/drivers/staging/android/ion/ion_dummy_driver.c
+++ b/drivers/staging/android/ion/ion_dummy_driver.c
@@ -56,6 +56,16 @@ static struct ion_platform_heap dummy_heaps[] = {
.align = SZ_16K,
.priv = (void *)(SZ_16K),
},
+#if defined(CONFIG_ION_DUMMY_UNMAPPED_HEAP) && CONFIG_ION_DUMMY_UNMAPPED_SIZE
+ {
+ .id = ION_HEAP_TYPE_UNMAPPED,
+ .type = ION_HEAP_TYPE_UNMAPPED,
+ .name = "unmapped",
+ .base = CONFIG_ION_DUMMY_UNMAPPED_BASE,
+ .size = CONFIG_ION_DUMMY_UNMAPPED_SIZE,
+ .align = SZ_4K,
+ },
+#endif
};
static struct ion_platform_data dummy_ion_pdata = {
diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c
index c2a7cb95725b..2fcdf5fd29a2 100644
--- a/drivers/staging/android/ion/ion_heap.c
+++ b/drivers/staging/android/ion/ion_heap.c
@@ -335,6 +335,11 @@ struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
case ION_HEAP_TYPE_DMA:
heap = ion_cma_heap_create(heap_data);
break;
+#ifdef CONFIG_ION_UNMAPPED_HEAP
+ case ION_HEAP_TYPE_UNMAPPED:
+ heap = ion_unmapped_heap_create(heap_data);
+ break;
+#endif
default:
pr_err("%s: Invalid heap type %d\n", __func__,
heap_data->type);
@@ -375,6 +380,11 @@ void ion_heap_destroy(struct ion_heap *heap)
case ION_HEAP_TYPE_DMA:
ion_cma_heap_destroy(heap);
break;
+#ifdef CONFIG_ION_UNMAPPED_HEAP
+ case ION_HEAP_TYPE_UNMAPPED:
+ ion_unmapped_heap_destroy(heap);
+ break;
+#endif
default:
pr_err("%s: Invalid heap type %d\n", __func__,
heap->type);
diff --git a/drivers/staging/android/ion/ion_of.c b/drivers/staging/android/ion/ion_of.c
index 46b2bb99bfd6..a20668077082 100644
--- a/drivers/staging/android/ion/ion_of.c
+++ b/drivers/staging/android/ion/ion_of.c
@@ -60,6 +60,7 @@ static int ion_setup_heap_common(struct platform_device *parent,
switch (heap->type) {
case ION_HEAP_TYPE_CARVEOUT:
case ION_HEAP_TYPE_CHUNK:
+ case ION_HEAP_TYPE_UNMAPPED:
if (heap->base && heap->size)
return 0;
diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h
index 760e41885448..70ac322967a3 100644
--- a/drivers/staging/android/ion/ion_priv.h
+++ b/drivers/staging/android/ion/ion_priv.h
@@ -2,6 +2,7 @@
* drivers/staging/android/ion/ion_priv.h
*
* Copyright (C) 2011 Google, Inc.
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -387,6 +388,11 @@ void ion_chunk_heap_destroy(struct ion_heap *);
struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *);
void ion_cma_heap_destroy(struct ion_heap *);
+#ifdef CONFIG_ION_UNMAPPED_HEAP
+struct ion_heap *ion_unmapped_heap_create(struct ion_platform_heap *pheap);
+void ion_unmapped_heap_destroy(struct ion_heap *heap);
+#endif
+
/**
* functions for creating and destroying a heap pool -- allows you
* to keep a pool of pre allocated memory to use from your heap. Keeping
@@ -470,4 +476,9 @@ int ion_query_heaps(struct ion_client *client, struct ion_heap_query *query);
int ion_share_dma_buf_fd_nolock(struct ion_client *client,
struct ion_handle *handle);
+int ion_handle_put_wrap(struct ion_handle *handle);
+struct ion_handle *ion_handle_get_by_id_wrap(struct ion_client *client,
+ int id);
+struct device *ion_device_get_by_client(struct ion_client *client);
+
#endif /* _ION_PRIV_H */
diff --git a/drivers/staging/android/ion/ion_unmapped_heap.c b/drivers/staging/android/ion/ion_unmapped_heap.c
new file mode 100644
index 000000000000..21f6c13571d1
--- /dev/null
+++ b/drivers/staging/android/ion/ion_unmapped_heap.c
@@ -0,0 +1,236 @@
+/*
+ * drivers/staging/android/ion/ion_unmapped_heap.c
+ *
+ * Copyright (C) 2016-2017 Linaro, Inc.
+ * Copyright (C) Allwinner 2014
+ * Author: <sunny@allwinnertech.com> for Allwinner.
+ *
+ * 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.
+ */
+
+/*
+ * ION heap type for handling physical memory heap not mapped
+ * in the linux-based OS.
+ *
+ * "unmapped heap" buffers are default not mapped but buffer owner
+ * can explicitly request mapping for some specific purpose.
+ *
+ * Based on Allwinner work (allocation thru gen_pool) and
+ * HiSilicon work (create ION heaps from DT nodes,
+ * Author: Chen Feng <puck.chen@hisilicon.com>).
+ */
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/genalloc.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+
+#include "ion.h"
+#include "ion_priv.h"
+
+struct ion_unmapped_heap {
+ struct ion_heap heap;
+ struct gen_pool *pool;
+ ion_phys_addr_t base;
+ size_t size;
+};
+
+struct unmapped_buffer_priv {
+ ion_phys_addr_t base;
+};
+
+static ion_phys_addr_t get_buffer_base(struct unmapped_buffer_priv *priv)
+{
+ return priv->base;
+}
+
+static struct device *heap2dev(struct ion_heap *heap)
+{
+ return heap->dev->dev.this_device;
+}
+
+static ion_phys_addr_t ion_unmapped_allocate(struct ion_heap *heap,
+ unsigned long size,
+ unsigned long align,
+ ion_phys_addr_t *addr)
+{
+ struct ion_unmapped_heap *umh =
+ container_of(heap, struct ion_unmapped_heap, heap);
+ unsigned long offset = gen_pool_alloc(umh->pool, size);
+
+ if (!offset) {
+ dev_err(heap2dev(heap),
+ "%s(%d) err: alloc 0x%08x bytes failed\n",
+ __func__, __LINE__, (u32)size);
+ return false;
+ }
+
+ *addr = offset;
+ return true;
+}
+
+static void ion_unmapped_free(struct ion_heap *heap, ion_phys_addr_t addr,
+ unsigned long size)
+{
+ struct ion_unmapped_heap *umh =
+ container_of(heap, struct ion_unmapped_heap, heap);
+
+ gen_pool_free(umh->pool, addr, size);
+}
+
+static struct sg_table *ion_unmapped_heap_map_dma(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ struct sg_table *table;
+ int ret;
+
+ table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+ if (!table)
+ return ERR_PTR(-ENOMEM);
+ ret = sg_alloc_table(table, 1, GFP_KERNEL);
+ if (ret) {
+ kfree(table);
+ return ERR_PTR(ret);
+ }
+ sg_set_page(table->sgl,
+ phys_to_page(get_buffer_base(buffer->priv_virt)),
+ buffer->size, 0);
+
+ return table;
+}
+
+void ion_unmapped_heap_unmap_dma(struct ion_heap *heap,
+ struct ion_buffer *buffer)
+{
+ sg_free_table(buffer->sg_table);
+ kfree(buffer->sg_table);
+}
+
+
+static int ion_unmapped_heap_allocate(struct ion_heap *heap,
+ struct ion_buffer *buffer,
+ unsigned long size, unsigned long align,
+ unsigned long flags)
+{
+ struct unmapped_buffer_priv *priv;
+ ion_phys_addr_t base;
+ int rc = -EINVAL;
+
+ if (!ion_unmapped_allocate(heap, size, align, &base))
+ return -ENOMEM;
+
+ priv = devm_kzalloc(heap2dev(heap), sizeof(*priv), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(priv)) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ priv->base = base;
+ buffer->size = roundup(size, PAGE_SIZE);
+ buffer->priv_virt = priv;
+
+ buffer->sg_table = ion_unmapped_heap_map_dma(heap, buffer);
+ if (!buffer->sg_table) {
+ rc = -ENOMEM;
+ goto err;
+ }
+ sg_dma_address(buffer->sg_table->sgl) = priv->base;
+ sg_dma_len(buffer->sg_table->sgl) = size;
+ return 0;
+err:
+ ion_unmapped_free(heap, base, size);
+ devm_kfree(heap2dev(heap), priv);
+ buffer->priv_virt = NULL;
+ return rc;
+}
+
+static void ion_unmapped_heap_free(struct ion_buffer *buffer)
+{
+ struct ion_heap *heap = buffer->heap;
+
+
+ ion_unmapped_heap_unmap_dma(heap, buffer);
+ ion_unmapped_free(heap, get_buffer_base(buffer->priv_virt),
+ buffer->size);
+ devm_kfree(heap2dev(heap), buffer->priv_virt);
+ buffer->priv_virt = NULL;
+}
+
+static int ion_unmapped_heap_map_user(struct ion_heap *heap,
+ struct ion_buffer *buffer,
+ struct vm_area_struct *vma)
+{
+ ion_phys_addr_t pa = get_buffer_base(buffer->priv_virt);
+
+ /*
+ * when user call ION_IOC_ALLOC not with ION_FLAG_CACHED, ion_mmap will
+ * change vma->vm_page_prot to pgprot_writecombine itself, so we do not
+ * need change to pgprot_writecombine here manually.
+ */
+ return remap_pfn_range(vma, vma->vm_start,
+ __phys_to_pfn(pa) + vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+}
+
+static struct ion_heap_ops unmapped_heap_ops = {
+ .allocate = ion_unmapped_heap_allocate,
+ .free = ion_unmapped_heap_free,
+ .map_user = ion_unmapped_heap_map_user,
+ .map_kernel = ion_heap_map_kernel,
+ .unmap_kernel = ion_heap_unmap_kernel,
+};
+
+struct ion_heap *ion_unmapped_heap_create(struct ion_platform_heap *pheap)
+{
+ struct ion_unmapped_heap *umh;
+
+ if (pheap->type != ION_HEAP_TYPE_UNMAPPED)
+ return NULL;
+
+ umh = kzalloc(sizeof(struct ion_unmapped_heap), GFP_KERNEL);
+ if (!umh)
+ return ERR_PTR(-ENOMEM);
+
+ umh->pool = gen_pool_create(PAGE_SHIFT, -1);
+ if (!umh->pool) {
+ kfree(umh);
+ return ERR_PTR(-ENOMEM);
+ }
+ umh->base = pheap->base;
+ umh->size = pheap->size;
+
+ gen_pool_add(umh->pool, umh->base, pheap->size, -1);
+ umh->heap.ops = &unmapped_heap_ops;
+ umh->heap.type = ION_HEAP_TYPE_UNMAPPED;
+
+ return &umh->heap;
+}
+EXPORT_SYMBOL(ion_unmapped_heap_create);
+
+void ion_unmapped_heap_destroy(struct ion_heap *heap)
+{
+ struct ion_unmapped_heap *umh =
+ container_of(heap, struct ion_unmapped_heap, heap);
+
+ gen_pool_destroy(umh->pool);
+ kfree(umh);
+ umh = NULL;
+}
+EXPORT_SYMBOL(ion_unmapped_heap_destroy);
diff --git a/drivers/staging/android/ion/mxc/Makefile b/drivers/staging/android/ion/mxc/Makefile
new file mode 100644
index 000000000000..df308e51837a
--- /dev/null
+++ b/drivers/staging/android/ion/mxc/Makefile
@@ -0,0 +1,2 @@
+ccflags-y += -I../
+obj-y += mxc_ion.o
diff --git a/drivers/staging/android/ion/mxc/mxc_ion.c b/drivers/staging/android/ion/mxc/mxc_ion.c
new file mode 100644
index 000000000000..b86c1f8c213c
--- /dev/null
+++ b/drivers/staging/android/ion/mxc/mxc_ion.c
@@ -0,0 +1,532 @@
+/*
+ * drivers/gpu/mxc/mxc_ion.c
+ *
+ * Copyright (C) 2011 Google, Inc.
+ * Copyright (C) 2012-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/uaccess.h>
+#include <media/videobuf2-dma-contig.h>
+#include <linux/dma-buf.h>
+
+#include "../ion_priv.h"
+#include "../ion_of.h"
+
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+#endif
+static struct ion_device *idev;
+static int num_heaps = 1;
+static struct ion_heap **heaps;
+static int cacheable;
+
+static struct ion_of_heap mxc_heaps[] = {
+ PLATFORM_HEAP("fsl,user-heap", 0, ION_HEAP_TYPE_DMA, "user"),
+ PLATFORM_HEAP("fsl,display-heap", 1, ION_HEAP_TYPE_UNMAPPED, "display"),
+ PLATFORM_HEAP("fsl,vpu-heap", 2, ION_HEAP_TYPE_UNMAPPED, "vpu"),
+ {}
+};
+
+static int rmem_imx_device_init(struct reserved_mem *rmem, struct device *dev)
+{
+ dev_set_drvdata(dev, rmem);
+ return 0;
+}
+
+static const struct reserved_mem_ops rmem_dma_ops = {
+ .device_init = rmem_imx_device_init,
+};
+
+static int __init rmem_imx_ion_setup(struct reserved_mem *rmem)
+{
+ rmem->ops = &rmem_dma_ops;
+ pr_info("Reserved memory: created ION memory pool at %pa, size %ld MiB\n",
+ &rmem->base, (unsigned long)rmem->size / SZ_1M);
+ return 0;
+}
+
+RESERVEDMEM_OF_DECLARE(cma, "imx-ion-pool", rmem_imx_ion_setup);
+
+/* Note: original code could be adapted so we just call ion_parse_dt() */
+struct ion_platform_data *mxc_ion_parse_of(struct platform_device *pdev)
+{
+ struct ion_platform_data *pdata = 0;
+ const struct device_node *node = pdev->dev.of_node;
+ int ret = 0;
+ unsigned int val = 0;
+ struct ion_platform_heap *heaps = NULL;
+ struct ion_platform_heap *user_heap;
+
+ pdata = ion_parse_dt(pdev, mxc_heaps);
+ if (IS_ERR(pdata)) {
+ if (PTR_ERR(pdata) != -EINVAL)
+ return pdata;
+
+ /* Even if DT has no heap, we still want the user one */
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return ERR_PTR(-ENOMEM);
+ } else {
+ /* Get rmem info into heap */
+ int i;
+
+ for (i = 0; i < pdata->nr; i++) {
+ struct ion_platform_heap *heap = &pdata->heaps[i];
+ struct reserved_mem *rmem = dev_get_drvdata(heap->priv);
+
+ heap->base = rmem->base;
+ heap->size = rmem->size;
+ }
+ }
+
+ /* Add user heap for legacy + copy device tree ones */
+ heaps = devm_kzalloc(&pdev->dev,
+ sizeof(struct ion_platform_heap) * (pdata->nr + 1),
+ GFP_KERNEL);
+ if (!heaps) {
+ ion_destroy_platform_data(pdata);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ if (pdata->heaps) {
+ memcpy(heaps, pdata->heaps,
+ sizeof(struct ion_platform_heap) * pdata->nr);
+ devm_kfree(&pdev->dev, pdata->heaps);
+ }
+
+ pdata->heaps = heaps;
+
+ /* Add the VPU heap */
+ user_heap = &heaps[pdata->nr];
+ user_heap->type = ION_HEAP_TYPE_DMA;
+ user_heap->priv = &pdev->dev;
+ user_heap->name = "mxc_ion";
+ pdata->nr++;
+
+ ret = of_property_read_u32(node, "fsl,heap-cacheable", &val);
+ if (!ret)
+ cacheable = 1;
+
+ val = 0;
+ ret = of_property_read_u32(node, "fsl,heap-id", &val);
+ if (!ret)
+ user_heap->id = val;
+ else
+ user_heap->id = 0;
+
+ return pdata;
+}
+
+static long
+mxc_custom_ioctl(struct ion_client *client, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case ION_IOC_PHYS:
+ {
+#ifdef CONFIG_ARCH_MXC_ARM64
+ /* Don't use ION_IOC_PHYS on ARM64,
+ * use ION_IOC_PHYS_DMA
+ */
+ return -EFAULT;
+#else
+ struct ion_handle *handle;
+ struct ion_phys_data data;
+ struct device *dev;
+ void *vaddr;
+
+ if (copy_from_user(&data, (void __user *)arg,
+ sizeof(struct ion_phys_data)))
+ return -EFAULT;
+ handle = ion_handle_get_by_id_wrap(client, data.handle);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ vaddr = ion_map_kernel(client, handle);
+ ion_handle_put_wrap(handle);
+
+ if (IS_ERR(vaddr))
+ return PTR_ERR(vaddr);
+
+ dev = ion_device_get_by_client(client);
+ data.phys = virt_to_dma(dev, vaddr);
+
+ if (copy_to_user((void __user *)arg, &data,
+ sizeof(struct ion_phys_data)))
+ return -EFAULT;
+ return 0;
+#endif
+ }
+ case ION_IOC_PHYS_DMA:
+ {
+ int ret = 0;
+ struct device *dev = NULL;
+ struct dma_buf *dmabuf = NULL;
+ unsigned long phys = 0;
+ size_t len = 0;
+ struct ion_phys_dma_data data;
+ const struct vb2_mem_ops *mem_ops =
+ &vb2_dma_contig_memops;
+ dma_addr_t *addr;
+ void *mem_priv;
+
+ if (copy_from_user(&data, (void __user *)arg,
+ sizeof(struct ion_phys_dma_data)))
+ return -EFAULT;
+
+ /* Get physical address from dmafd */
+ dmabuf = dma_buf_get(data.dmafd);
+ if (!dmabuf)
+ return -1;
+
+ dev = ion_device_get_by_client(client);
+
+ mem_priv = mem_ops->attach_dmabuf(dev,
+ dmabuf, dmabuf->size,
+ DMA_BIDIRECTIONAL);
+ if (IS_ERR(mem_priv))
+ goto err1;
+ ret = mem_ops->map_dmabuf(mem_priv);
+ if (ret)
+ goto err0;
+
+ addr = mem_ops->cookie(mem_priv);
+ phys = *addr;
+ len = dmabuf->size;
+
+ data.phys = phys;
+ data.size = len;
+ if (copy_to_user((void __user *)arg, &data,
+ sizeof(struct ion_phys_dma_data))) {
+ ret = -EFAULT;
+ }
+
+ /* unmap and detach */
+ mem_ops->unmap_dmabuf(mem_priv);
+err0:
+ mem_ops->detach_dmabuf(mem_priv);
+err1:
+ dma_buf_put(dmabuf);
+
+ if (ret < 0)
+ return ret;
+ return 0;
+ }
+ case ION_IOC_PHYS_VIRT:
+ {
+ struct device *dev = NULL;
+ struct ion_phys_virt_data data;
+ const struct vb2_mem_ops *mem_ops =
+ &vb2_dma_contig_memops;
+ dma_addr_t *addr;
+ void *mem_priv;
+
+ if (copy_from_user(&data, (void __user *)arg,
+ sizeof(struct ion_phys_virt_data)))
+ return -EFAULT;
+
+ /* Get physical address from virtual address */
+ if (!data.virt)
+ return -1;
+
+ dev = ion_device_get_by_client(client);
+
+ mem_priv = mem_ops->get_userptr(dev,
+ data.virt, data.size,
+ DMA_BIDIRECTIONAL);
+ if (IS_ERR(mem_priv))
+ return -1;
+
+ addr = mem_ops->cookie(mem_priv);
+ data.phys = *addr;
+ mem_ops->put_userptr(mem_priv);
+
+ if (copy_to_user((void __user *)arg, &data,
+ sizeof(struct ion_phys_virt_data)))
+ return -EFAULT;
+ return 0;
+ }
+ default:
+ return -ENOTTY;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_COMPAT
+struct ion_phys_data32 {
+ __s32 handle; //ion_user_handle_t
+ compat_long_t phys;
+};
+
+struct ion_phys_dma_data32 {
+ compat_long_t phys;
+ __u32 size;
+ __u32 dmafd;
+};
+
+struct ion_phys_virt_data32 {
+ compat_long_t virt;
+ compat_long_t phys;
+ __u32 size;
+};
+
+#define ION_IOC_PHYS32 _IOWR(ION_IOC_MAGIC, _IOC_NR(ION_IOC_PHYS), struct ion_phys_data32)
+#define ION_IOC_PHYS_DMA32 _IOWR(ION_IOC_MAGIC, _IOC_NR(ION_IOC_PHYS_DMA), struct ion_phys_dma_data32)
+#define ION_IOC_PHYS_VIRT32 _IOWR(ION_IOC_MAGIC, _IOC_NR(ION_IOC_PHYS_VIRT), struct ion_phys_virt_data32)
+
+static int get_ion_phys_data32(struct ion_phys_data *kp,
+ struct ion_phys_data32 __user *up)
+{
+ void __user *up_pln;
+ compat_long_t p;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(struct ion_phys_data32)) ||
+ get_user(kp->handle, &up->handle) || get_user(p, &up->phys))
+ return -EFAULT;
+ up_pln = compat_ptr(p);
+ put_user((unsigned long)up_pln, &kp->phys);
+ return 0;
+}
+
+static int put_ion_phys_data32(struct ion_phys_data *kp,
+ struct ion_phys_data32 __user *up)
+{
+ u32 tmp = (u32)((unsigned long)kp->phys);
+
+ if (!access_ok(VERIFY_WRITE, up, sizeof(struct ion_phys_data32)) ||
+ put_user((s32)kp->handle, &up->handle) || put_user(tmp, &up->phys))
+ return -EFAULT;
+ return 0;
+}
+
+static int get_ion_phys_dma_data32(struct ion_phys_dma_data *kp,
+ struct ion_phys_dma_data32 __user *up)
+{
+ void __user *up_pln;
+ compat_long_t p;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(struct ion_phys_dma_data32)) ||
+ get_user(kp->size, &up->size) ||
+ get_user(kp->dmafd, &up->dmafd) || get_user(p, &up->phys))
+ return -EFAULT;
+ up_pln = compat_ptr(p);
+ put_user((unsigned long)up_pln, &kp->phys);
+ return 0;
+}
+
+static int put_ion_phys_dma_data32(struct ion_phys_dma_data *kp,
+ struct ion_phys_dma_data32 __user *up)
+{
+ u32 tmp = (u32)((unsigned long)kp->phys);
+
+ if (!access_ok(VERIFY_WRITE, up, sizeof(struct ion_phys_dma_data32)) ||
+ put_user((s32)kp->size, &up->size) ||
+ put_user((s32)kp->dmafd, &up->dmafd) || put_user(tmp, &up->phys))
+ return -EFAULT;
+ return 0;
+}
+
+static int get_ion_phys_virt_data32(struct ion_phys_virt_data *kp,
+ struct ion_phys_virt_data32 __user *up)
+{
+ void __user *up_pln;
+ void __user *up_pln2;
+ compat_long_t p;
+ compat_long_t p2;
+
+ if (!access_ok(VERIFY_READ, up, sizeof(struct ion_phys_virt_data32)) ||
+ get_user(kp->size, &up->size) ||
+ get_user(p, &up->phys) || get_user(p2, &up->virt))
+ return -EFAULT;
+ up_pln = compat_ptr(p);
+ up_pln2 = compat_ptr(p2);
+ put_user((unsigned long)up_pln, &kp->phys);
+ put_user((unsigned long)up_pln2, &kp->virt);
+ return 0;
+}
+
+static int put_ion_phys_virt_data32(struct ion_phys_virt_data *kp,
+ struct ion_phys_virt_data32 __user *up)
+{
+ u32 tmp = (u32)((unsigned long)kp->phys);
+ u32 tmp2 = (u32)((unsigned long)kp->virt);
+
+ if (!access_ok(VERIFY_WRITE, up, sizeof(struct ion_phys_virt_data32)) ||
+ put_user((u32)kp->size, &up->size) ||
+ put_user(tmp, &up->phys) || put_user(tmp2, &up->virt))
+ return -EFAULT;
+ return 0;
+}
+
+static long
+mxc_custom_compat_ioctl(struct ion_client *client, unsigned int cmd,
+ unsigned long arg)
+{
+#define MXC_CUSTOM_IOCTL32(r, cli, c, arg) {\
+ mm_segment_t old_fs = get_fs();\
+ set_fs(KERNEL_DS);\
+ r = mxc_custom_ioctl(cli, c, arg);\
+ set_fs(old_fs);\
+}
+
+ union {
+ struct ion_phys_data kdata;
+ struct ion_phys_dma_data kdmadata;
+ struct ion_phys_virt_data kvirtdata;
+ } karg;
+
+ void __user *up = compat_ptr(arg);
+ long err = 0;
+
+ switch (cmd) {
+ case ION_IOC_PHYS32:
+ err = get_ion_phys_data32(&karg.kdata, up);
+ if (err)
+ return err;
+ MXC_CUSTOM_IOCTL32(err, client, ION_IOC_PHYS,
+ (unsigned long)&karg);
+ err = put_ion_phys_data32(&karg.kdata, up);
+ break;
+ case ION_IOC_PHYS_DMA32:
+ err = get_ion_phys_dma_data32(&karg.kdmadata, up);
+ if (err)
+ return err;
+ MXC_CUSTOM_IOCTL32(err, client, ION_IOC_PHYS_DMA,
+ (unsigned long)&karg);
+ err = put_ion_phys_dma_data32(&karg.kdmadata, up);
+ break;
+ case ION_IOC_PHYS_VIRT32:
+ err = get_ion_phys_virt_data32(&karg.kvirtdata, up);
+ if (err)
+ return err;
+ MXC_CUSTOM_IOCTL32(err, client, ION_IOC_PHYS_VIRT,
+ (unsigned long)&karg);
+ err = put_ion_phys_virt_data32(&karg.kvirtdata, up);
+ break;
+ default:
+ err = mxc_custom_ioctl(client, cmd, (unsigned long)arg);
+ break;
+ }
+
+ return err;
+}
+#endif //CONFIG_COMPAT
+
+int mxc_ion_probe(struct platform_device *pdev)
+{
+ struct ion_platform_data *pdata = NULL;
+ int err;
+ int i;
+
+ if (pdev->dev.of_node)
+ pdata = mxc_ion_parse_of(pdev);
+ else
+ pdata = pdev->dev.platform_data;
+
+ if (IS_ERR_OR_NULL(pdata))
+ return PTR_ERR(pdata);
+
+ num_heaps = pdata->nr;
+
+ heaps = devm_kzalloc(&pdev->dev, sizeof(struct ion_heap *) * pdata->nr,
+ GFP_KERNEL);
+
+#ifdef CONFIG_COMPAT
+ idev = ion_device_create(mxc_custom_compat_ioctl);
+#else
+ idev = ion_device_create(mxc_custom_ioctl);
+#endif
+ if (IS_ERR_OR_NULL(idev)) {
+ err = PTR_ERR(idev);
+ goto err;
+ }
+
+ of_dma_configure(idev->dev.this_device, pdev->dev.of_node);
+
+ /* create the heaps as specified in the board file */
+ for (i = 0; i < pdata->nr; i++) {
+ heaps[i] = ion_heap_create(&pdata->heaps[i]);
+ if (IS_ERR_OR_NULL(heaps[i])) {
+ err = PTR_ERR(heaps[i]);
+ heaps[i] = NULL;
+ goto err;
+ }
+ ion_device_add_heap(idev, heaps[i]);
+ }
+ platform_set_drvdata(pdev, idev);
+ return 0;
+err:
+ for (i = 0; i < pdata->nr; i++)
+ if (heaps[i])
+ ion_heap_destroy(heaps[i]);
+
+ devm_kfree(&pdev->dev, heaps);
+ if (pdev->dev.of_node)
+ ion_destroy_platform_data(pdata);
+
+ return err;
+}
+
+int mxc_ion_remove(struct platform_device *pdev)
+{
+ struct ion_device *idev = platform_get_drvdata(pdev);
+ int i;
+
+ ion_device_destroy(idev);
+ for (i = 0; i < num_heaps; i++)
+ ion_heap_destroy(heaps[i]);
+
+ devm_kfree(&pdev->dev, heaps);
+ return 0;
+}
+
+static struct of_device_id ion_match_table[] = {
+ {.compatible = "fsl,mxc-ion"},
+ {},
+};
+
+static struct platform_driver ion_driver = {
+ .probe = mxc_ion_probe,
+ .remove = mxc_ion_remove,
+ .driver = {
+ .name = "ion-mxc",
+ .of_match_table = ion_match_table,
+ },
+};
+
+static int __init ion_init(void)
+{
+ return platform_driver_register(&ion_driver);
+}
+
+static void __exit ion_exit(void)
+{
+ platform_driver_unregister(&ion_driver);
+}
+
+module_init(ion_init);
+module_exit(ion_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC ion allocator driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("fb");
diff --git a/drivers/staging/android/uapi/ion.h b/drivers/staging/android/uapi/ion.h
index 14cd8738ecfc..61ea81472365 100644
--- a/drivers/staging/android/uapi/ion.h
+++ b/drivers/staging/android/uapi/ion.h
@@ -2,6 +2,7 @@
* drivers/staging/android/uapi/ion.h
*
* Copyright (C) 2011 Google, Inc.
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -30,6 +31,8 @@ typedef int ion_user_handle_t;
* carveout heap, allocations are physically
* contiguous
* @ION_HEAP_TYPE_DMA: memory allocated via DMA API
+ * @ION_HEAP_TYPE_UNMAPPED: memory not intended to be mapped into the
+ * linux address space unless for debug cases
* @ION_NUM_HEAPS: helper for iterating over heaps, a bit mask
* is used to identify the heaps, so only 32
* total heap types are supported
@@ -40,12 +43,14 @@ enum ion_heap_type {
ION_HEAP_TYPE_CARVEOUT,
ION_HEAP_TYPE_CHUNK,
ION_HEAP_TYPE_DMA,
+ ION_HEAP_TYPE_UNMAPPED,
ION_HEAP_TYPE_CUSTOM, /*
* must be last so device specific heaps always
* are at the end of this enum
*/
};
+#define ION_CMA_HEAP_ID 0
#define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8)
/**
@@ -158,6 +163,23 @@ struct ion_heap_query {
__u32 reserved2;
};
+struct ion_phys_data {
+ ion_user_handle_t handle;
+ unsigned long phys;
+};
+
+struct ion_phys_dma_data {
+ unsigned long phys;
+ size_t size;
+ int dmafd;
+};
+
+struct ion_phys_virt_data {
+ unsigned long virt;
+ unsigned long phys;
+ size_t size;
+};
+
#define ION_IOC_MAGIC 'I'
/**
@@ -233,4 +255,10 @@ struct ion_heap_query {
#define ION_IOC_HEAP_QUERY _IOWR(ION_IOC_MAGIC, 8, \
struct ion_heap_query)
+#define ION_IOC_PHYS _IOWR(ION_IOC_MAGIC, 8, struct ion_phys_data)
+
+#define ION_IOC_PHYS_DMA _IOWR(ION_IOC_MAGIC, 9, struct ion_phys_dma_data)
+
+#define ION_IOC_PHYS_VIRT _IOWR(ION_IOC_MAGIC, 10, struct ion_phys_virt_data)
+
#endif /* _UAPI_LINUX_ION_H */
diff --git a/drivers/staging/android/uapi/secure_ion.h b/drivers/staging/android/uapi/secure_ion.h
new file mode 100644
index 000000000000..e1078977a8bb
--- /dev/null
+++ b/drivers/staging/android/uapi/secure_ion.h
@@ -0,0 +1,25 @@
+/*
+ * drivers/staging/android/uapi/secure_ion.h
+ *
+ * Copyright (C) 2011 Google, Inc.
+ * Copyright (C) 2012-2017 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP.
+ *
+ * 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_SECURE_ION_H
+#define _LINUX_SECURE_ION_H
+
+#define DWL_ION_ENCODED_BUFFER_VPU_HEAP 4
+#define DWL_ION_DECODED_BUFFER_DCSS_HEAP 2
+
+#endif
diff --git a/drivers/staging/typec/Kconfig b/drivers/staging/typec/Kconfig
new file mode 100644
index 000000000000..c4e8019839f2
--- /dev/null
+++ b/drivers/staging/typec/Kconfig
@@ -0,0 +1,22 @@
+menu "USB Power Delivery and Type-C drivers"
+
+config TYPEC_TCPM
+ tristate "USB Type-C Port Controller Manager"
+ depends on USB
+ select TYPEC
+ help
+ The Type-C Port Controller Manager provides a USB PD and USB Type-C
+ state machine for use with Type-C Port Controllers.
+
+if TYPEC_TCPM
+
+config TYPEC_TCPCI
+ tristate "Type-C Port Controller Interface driver"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Type-C Port Controller driver for TCPCI-compliant controller.
+
+endif
+
+endmenu
diff --git a/drivers/staging/typec/Makefile b/drivers/staging/typec/Makefile
new file mode 100644
index 000000000000..144f7ae60a7b
--- /dev/null
+++ b/drivers/staging/typec/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_TYPEC_TCPM) += tcpm.o
+obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o
diff --git a/drivers/staging/typec/TODO b/drivers/staging/typec/TODO
new file mode 100644
index 000000000000..bc1f97a2d1bf
--- /dev/null
+++ b/drivers/staging/typec/TODO
@@ -0,0 +1,15 @@
+tcpm:
+- Add documentation (at the very least for the API to low level drivers)
+- Split PD code into separate file
+- Check if it makes sense to use tracepoints instead of debugfs for debug logs
+- Implement Alternate Mode handling
+- Address "#if 0" code if not addressed with the above
+- Validate all comments marked with "XXX"; either address or remove comments
+- Add support for USB PD 3.0. While not mandatory, at least fast role swap
+ as well as authentication support would be very desirable.
+
+tcpci:
+- Test with real hardware
+
+Please send patches to Guenter Roeck <linux@roeck-us.net> and copy
+Heikki Krogerus <heikki.krogerus@linux.intel.com>.
diff --git a/drivers/staging/typec/pd.h b/drivers/staging/typec/pd.h
new file mode 100644
index 000000000000..7fdc1294dbb3
--- /dev/null
+++ b/drivers/staging/typec/pd.h
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2015-2017 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_USB_PD_H
+#define __LINUX_USB_PD_H
+
+#include <linux/types.h>
+#include <linux/usb/typec.h>
+
+/* USB PD Messages */
+enum pd_ctrl_msg_type {
+ /* 0 Reserved */
+ PD_CTRL_GOOD_CRC = 1,
+ PD_CTRL_GOTO_MIN = 2,
+ PD_CTRL_ACCEPT = 3,
+ PD_CTRL_REJECT = 4,
+ PD_CTRL_PING = 5,
+ PD_CTRL_PS_RDY = 6,
+ PD_CTRL_GET_SOURCE_CAP = 7,
+ PD_CTRL_GET_SINK_CAP = 8,
+ PD_CTRL_DR_SWAP = 9,
+ PD_CTRL_PR_SWAP = 10,
+ PD_CTRL_VCONN_SWAP = 11,
+ PD_CTRL_WAIT = 12,
+ PD_CTRL_SOFT_RESET = 13,
+ /* 14-15 Reserved */
+};
+
+enum pd_data_msg_type {
+ /* 0 Reserved */
+ PD_DATA_SOURCE_CAP = 1,
+ PD_DATA_REQUEST = 2,
+ PD_DATA_BIST = 3,
+ PD_DATA_SINK_CAP = 4,
+ /* 5-14 Reserved */
+ PD_DATA_VENDOR_DEF = 15,
+};
+
+#define PD_REV10 0x0
+#define PD_REV20 0x1
+
+#define PD_HEADER_CNT_SHIFT 12
+#define PD_HEADER_CNT_MASK 0x7
+#define PD_HEADER_ID_SHIFT 9
+#define PD_HEADER_ID_MASK 0x7
+#define PD_HEADER_PWR_ROLE BIT(8)
+#define PD_HEADER_REV_SHIFT 6
+#define PD_HEADER_REV_MASK 0x3
+#define PD_HEADER_DATA_ROLE BIT(5)
+#define PD_HEADER_TYPE_SHIFT 0
+#define PD_HEADER_TYPE_MASK 0xf
+
+#define PD_HEADER(type, pwr, data, id, cnt) \
+ ((((type) & PD_HEADER_TYPE_MASK) << PD_HEADER_TYPE_SHIFT) | \
+ ((pwr) == TYPEC_SOURCE ? PD_HEADER_PWR_ROLE : 0) | \
+ ((data) == TYPEC_HOST ? PD_HEADER_DATA_ROLE : 0) | \
+ (PD_REV20 << PD_HEADER_REV_SHIFT) | \
+ (((id) & PD_HEADER_ID_MASK) << PD_HEADER_ID_SHIFT) | \
+ (((cnt) & PD_HEADER_CNT_MASK) << PD_HEADER_CNT_SHIFT))
+
+#define PD_HEADER_LE(type, pwr, data, id, cnt) \
+ cpu_to_le16(PD_HEADER((type), (pwr), (data), (id), (cnt)))
+
+static inline unsigned int pd_header_cnt(u16 header)
+{
+ return (header >> PD_HEADER_CNT_SHIFT) & PD_HEADER_CNT_MASK;
+}
+
+static inline unsigned int pd_header_cnt_le(__le16 header)
+{
+ return pd_header_cnt(le16_to_cpu(header));
+}
+
+static inline unsigned int pd_header_type(u16 header)
+{
+ return (header >> PD_HEADER_TYPE_SHIFT) & PD_HEADER_TYPE_MASK;
+}
+
+static inline unsigned int pd_header_type_le(__le16 header)
+{
+ return pd_header_type(le16_to_cpu(header));
+}
+
+#define PD_MAX_PAYLOAD 7
+
+struct pd_message {
+ __le16 header;
+ __le32 payload[PD_MAX_PAYLOAD];
+} __packed;
+
+/* PDO: Power Data Object */
+#define PDO_MAX_OBJECTS 7
+
+enum pd_pdo_type {
+ PDO_TYPE_FIXED = 0,
+ PDO_TYPE_BATT = 1,
+ PDO_TYPE_VAR = 2,
+};
+
+#define PDO_TYPE_SHIFT 30
+#define PDO_TYPE_MASK 0x3
+
+#define PDO_TYPE(t) ((t) << PDO_TYPE_SHIFT)
+
+#define PDO_VOLT_MASK 0x3ff
+#define PDO_CURR_MASK 0x3ff
+#define PDO_PWR_MASK 0x3ff
+
+#define PDO_FIXED_DUAL_ROLE BIT(29) /* Power role swap supported */
+#define PDO_FIXED_SUSPEND BIT(28) /* USB Suspend supported (Source) */
+#define PDO_FIXED_HIGHER_CAP BIT(28) /* Requires more than vSafe5V (Sink) */
+#define PDO_FIXED_EXTPOWER BIT(27) /* Externally powered */
+#define PDO_FIXED_USB_COMM BIT(26) /* USB communications capable */
+#define PDO_FIXED_DATA_SWAP BIT(25) /* Data role swap supported */
+#define PDO_FIXED_VOLT_SHIFT 10 /* 50mV units */
+#define PDO_FIXED_CURR_SHIFT 0 /* 10mA units */
+
+#define PDO_FIXED_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_FIXED_VOLT_SHIFT)
+#define PDO_FIXED_CURR(ma) ((((ma) / 10) & PDO_CURR_MASK) << PDO_FIXED_CURR_SHIFT)
+
+#define PDO_FIXED(mv, ma, flags) \
+ (PDO_TYPE(PDO_TYPE_FIXED) | (flags) | \
+ PDO_FIXED_VOLT(mv) | PDO_FIXED_CURR(ma))
+
+#define PDO_BATT_MAX_VOLT_SHIFT 20 /* 50mV units */
+#define PDO_BATT_MIN_VOLT_SHIFT 10 /* 50mV units */
+#define PDO_BATT_MAX_PWR_SHIFT 0 /* 250mW units */
+
+#define PDO_BATT_MIN_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_BATT_MIN_VOLT_SHIFT)
+#define PDO_BATT_MAX_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_BATT_MAX_VOLT_SHIFT)
+#define PDO_BATT_MAX_POWER(mw) ((((mw) / 250) & PDO_PWR_MASK) << PDO_BATT_MAX_PWR_SHIFT)
+
+#define PDO_BATT(min_mv, max_mv, max_mw) \
+ (PDO_TYPE(PDO_TYPE_BATT) | PDO_BATT_MIN_VOLT(min_mv) | \
+ PDO_BATT_MAX_VOLT(max_mv) | PDO_BATT_MAX_POWER(max_mw))
+
+#define PDO_VAR_MAX_VOLT_SHIFT 20 /* 50mV units */
+#define PDO_VAR_MIN_VOLT_SHIFT 10 /* 50mV units */
+#define PDO_VAR_MAX_CURR_SHIFT 0 /* 10mA units */
+
+#define PDO_VAR_MIN_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_VAR_MIN_VOLT_SHIFT)
+#define PDO_VAR_MAX_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_VAR_MAX_VOLT_SHIFT)
+#define PDO_VAR_MAX_CURR(ma) ((((ma) / 10) & PDO_CURR_MASK) << PDO_VAR_MAX_CURR_SHIFT)
+
+#define PDO_VAR(min_mv, max_mv, max_ma) \
+ (PDO_TYPE(PDO_TYPE_VAR) | PDO_VAR_MIN_VOLT(min_mv) | \
+ PDO_VAR_MAX_VOLT(max_mv) | PDO_VAR_MAX_CURR(max_ma))
+
+static inline enum pd_pdo_type pdo_type(u32 pdo)
+{
+ return (pdo >> PDO_TYPE_SHIFT) & PDO_TYPE_MASK;
+}
+
+static inline unsigned int pdo_fixed_voltage(u32 pdo)
+{
+ return ((pdo >> PDO_FIXED_VOLT_SHIFT) & PDO_VOLT_MASK) * 50;
+}
+
+static inline unsigned int pdo_min_voltage(u32 pdo)
+{
+ return ((pdo >> PDO_VAR_MIN_VOLT_SHIFT) & PDO_VOLT_MASK) * 50;
+}
+
+static inline unsigned int pdo_max_voltage(u32 pdo)
+{
+ return ((pdo >> PDO_VAR_MAX_VOLT_SHIFT) & PDO_VOLT_MASK) * 50;
+}
+
+static inline unsigned int pdo_max_current(u32 pdo)
+{
+ return ((pdo >> PDO_VAR_MAX_CURR_SHIFT) & PDO_CURR_MASK) * 10;
+}
+
+static inline unsigned int pdo_max_power(u32 pdo)
+{
+ return ((pdo >> PDO_BATT_MAX_PWR_SHIFT) & PDO_PWR_MASK) * 250;
+}
+
+/* RDO: Request Data Object */
+#define RDO_OBJ_POS_SHIFT 28
+#define RDO_OBJ_POS_MASK 0x7
+#define RDO_GIVE_BACK BIT(27) /* Supports reduced operating current */
+#define RDO_CAP_MISMATCH BIT(26) /* Not satisfied by source caps */
+#define RDO_USB_COMM BIT(25) /* USB communications capable */
+#define RDO_NO_SUSPEND BIT(24) /* USB Suspend not supported */
+
+#define RDO_PWR_MASK 0x3ff
+#define RDO_CURR_MASK 0x3ff
+
+#define RDO_FIXED_OP_CURR_SHIFT 10
+#define RDO_FIXED_MAX_CURR_SHIFT 0
+
+#define RDO_OBJ(idx) (((idx) & RDO_OBJ_POS_MASK) << RDO_OBJ_POS_SHIFT)
+
+#define PDO_FIXED_OP_CURR(ma) ((((ma) / 10) & RDO_CURR_MASK) << RDO_FIXED_OP_CURR_SHIFT)
+#define PDO_FIXED_MAX_CURR(ma) ((((ma) / 10) & RDO_CURR_MASK) << RDO_FIXED_MAX_CURR_SHIFT)
+
+#define RDO_FIXED(idx, op_ma, max_ma, flags) \
+ (RDO_OBJ(idx) | (flags) | \
+ PDO_FIXED_OP_CURR(op_ma) | PDO_FIXED_MAX_CURR(max_ma))
+
+#define RDO_BATT_OP_PWR_SHIFT 10 /* 250mW units */
+#define RDO_BATT_MAX_PWR_SHIFT 0 /* 250mW units */
+
+#define RDO_BATT_OP_PWR(mw) ((((mw) / 250) & RDO_PWR_MASK) << RDO_BATT_OP_PWR_SHIFT)
+#define RDO_BATT_MAX_PWR(mw) ((((mw) / 250) & RDO_PWR_MASK) << RDO_BATT_MAX_PWR_SHIFT)
+
+#define RDO_BATT(idx, op_mw, max_mw, flags) \
+ (RDO_OBJ(idx) | (flags) | \
+ RDO_BATT_OP_PWR(op_mw) | RDO_BATT_MAX_PWR(max_mw))
+
+static inline unsigned int rdo_index(u32 rdo)
+{
+ return (rdo >> RDO_OBJ_POS_SHIFT) & RDO_OBJ_POS_MASK;
+}
+
+static inline unsigned int rdo_op_current(u32 rdo)
+{
+ return ((rdo >> RDO_FIXED_OP_CURR_SHIFT) & RDO_CURR_MASK) * 10;
+}
+
+static inline unsigned int rdo_max_current(u32 rdo)
+{
+ return ((rdo >> RDO_FIXED_MAX_CURR_SHIFT) &
+ RDO_CURR_MASK) * 10;
+}
+
+static inline unsigned int rdo_op_power(u32 rdo)
+{
+ return ((rdo >> RDO_BATT_OP_PWR_SHIFT) & RDO_PWR_MASK) * 250;
+}
+
+static inline unsigned int rdo_max_power(u32 rdo)
+{
+ return ((rdo >> RDO_BATT_MAX_PWR_SHIFT) & RDO_PWR_MASK) * 250;
+}
+
+/* USB PD timers and counters */
+#define PD_T_NO_RESPONSE 5000 /* 4.5 - 5.5 seconds */
+#define PD_T_DB_DETECT 10000 /* 10 - 15 seconds */
+#define PD_T_SEND_SOURCE_CAP 150 /* 100 - 200 ms */
+#define PD_T_SENDER_RESPONSE 25 /* 24 - 30 ms, relaxed */
+#define PD_T_SOURCE_ACTIVITY 45
+#define PD_T_SINK_ACTIVITY 135
+#define PD_T_SINK_WAIT_CAP 400
+#define PD_T_PS_TRANSITION 500
+#define PD_T_SRC_TRANSITION 35
+#define PD_T_DRP_SNK 40
+#define PD_T_DRP_SRC 30
+#define PD_T_PS_SOURCE_OFF 790
+#define PD_T_PS_SOURCE_ON 400
+#define PD_T_PS_HARD_RESET 30
+#define PD_T_SRC_RECOVER 760
+#define PD_T_SRC_RECOVER_MAX 1000
+#define PD_T_SRC_TURN_ON 275
+#define PD_T_SAFE_0V 650
+#define PD_T_VCONN_SOURCE_ON 100
+#define PD_T_SINK_REQUEST 100 /* 100 ms minimum */
+#define PD_T_ERROR_RECOVERY 100 /* minimum 25 is insufficient */
+
+#define PD_T_DRP_TRY 100 /* 75 - 150 ms */
+#define PD_T_DRP_TRYWAIT 600 /* 400 - 800 ms */
+
+#define PD_T_CC_DEBOUNCE 110 /* 100 - 200 ms */
+#define PD_T_PD_DEBOUNCE 10 /* 10 - 20 ms */
+
+#define PD_N_CAPS_COUNT (PD_T_NO_RESPONSE / PD_T_SEND_SOURCE_CAP)
+#define PD_N_HARD_RESET_COUNT 2
+
+#endif /* __LINUX_USB_PD_H */
diff --git a/drivers/staging/typec/pd_bdo.h b/drivers/staging/typec/pd_bdo.h
new file mode 100644
index 000000000000..90b94d9fea5d
--- /dev/null
+++ b/drivers/staging/typec/pd_bdo.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015-2017 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_USB_PD_BDO_H
+#define __LINUX_USB_PD_BDO_H
+
+/* BDO : BIST Data Object */
+#define BDO_MODE_RECV (0 << 28)
+#define BDO_MODE_TRANSMIT (1 << 28)
+#define BDO_MODE_COUNTERS (2 << 28)
+#define BDO_MODE_CARRIER0 (3 << 28)
+#define BDO_MODE_CARRIER1 (4 << 28)
+#define BDO_MODE_CARRIER2 (5 << 28)
+#define BDO_MODE_CARRIER3 (6 << 28)
+#define BDO_MODE_EYE (7 << 28)
+#define BDO_MODE_TESTDATA (8 << 28)
+
+#define BDO_MODE_MASK(mode) ((mode) & 0xf0000000)
+
+#endif
diff --git a/drivers/staging/typec/pd_vdo.h b/drivers/staging/typec/pd_vdo.h
new file mode 100644
index 000000000000..dba172e0e0d1
--- /dev/null
+++ b/drivers/staging/typec/pd_vdo.h
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2015-2017 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_USB_PD_VDO_H
+#define __LINUX_USB_PD_VDO_H
+
+#include "pd.h"
+
+/*
+ * VDO : Vendor Defined Message Object
+ * VDM object is minimum of VDM header + 6 additional data objects.
+ */
+
+/*
+ * VDM header
+ * ----------
+ * <31:16> :: SVID
+ * <15> :: VDM type ( 1b == structured, 0b == unstructured )
+ * <14:13> :: Structured VDM version (can only be 00 == 1.0 currently)
+ * <12:11> :: reserved
+ * <10:8> :: object position (1-7 valid ... used for enter/exit mode only)
+ * <7:6> :: command type (SVDM only?)
+ * <5> :: reserved (SVDM), command type (UVDM)
+ * <4:0> :: command
+ */
+#define VDO_MAX_SIZE 7
+#define VDO(vid, type, custom) \
+ (((vid) << 16) | \
+ ((type) << 15) | \
+ ((custom) & 0x7FFF))
+
+#define VDO_SVDM_TYPE (1 << 15)
+#define VDO_SVDM_VERS(x) ((x) << 13)
+#define VDO_OPOS(x) ((x) << 8)
+#define VDO_CMDT(x) ((x) << 6)
+#define VDO_OPOS_MASK VDO_OPOS(0x7)
+#define VDO_CMDT_MASK VDO_CMDT(0x3)
+
+#define CMDT_INIT 0
+#define CMDT_RSP_ACK 1
+#define CMDT_RSP_NAK 2
+#define CMDT_RSP_BUSY 3
+
+/* reserved for SVDM ... for Google UVDM */
+#define VDO_SRC_INITIATOR (0 << 5)
+#define VDO_SRC_RESPONDER (1 << 5)
+
+#define CMD_DISCOVER_IDENT 1
+#define CMD_DISCOVER_SVID 2
+#define CMD_DISCOVER_MODES 3
+#define CMD_ENTER_MODE 4
+#define CMD_EXIT_MODE 5
+#define CMD_ATTENTION 6
+
+#define VDO_CMD_VENDOR(x) (((10 + (x)) & 0x1f))
+
+/* ChromeOS specific commands */
+#define VDO_CMD_VERSION VDO_CMD_VENDOR(0)
+#define VDO_CMD_SEND_INFO VDO_CMD_VENDOR(1)
+#define VDO_CMD_READ_INFO VDO_CMD_VENDOR(2)
+#define VDO_CMD_REBOOT VDO_CMD_VENDOR(5)
+#define VDO_CMD_FLASH_ERASE VDO_CMD_VENDOR(6)
+#define VDO_CMD_FLASH_WRITE VDO_CMD_VENDOR(7)
+#define VDO_CMD_ERASE_SIG VDO_CMD_VENDOR(8)
+#define VDO_CMD_PING_ENABLE VDO_CMD_VENDOR(10)
+#define VDO_CMD_CURRENT VDO_CMD_VENDOR(11)
+#define VDO_CMD_FLIP VDO_CMD_VENDOR(12)
+#define VDO_CMD_GET_LOG VDO_CMD_VENDOR(13)
+#define VDO_CMD_CCD_EN VDO_CMD_VENDOR(14)
+
+#define PD_VDO_VID(vdo) ((vdo) >> 16)
+#define PD_VDO_SVDM(vdo) (((vdo) >> 15) & 1)
+#define PD_VDO_OPOS(vdo) (((vdo) >> 8) & 0x7)
+#define PD_VDO_CMD(vdo) ((vdo) & 0x1f)
+#define PD_VDO_CMDT(vdo) (((vdo) >> 6) & 0x3)
+
+/*
+ * SVDM Identity request -> response
+ *
+ * Request is simply properly formatted SVDM header
+ *
+ * Response is 4 data objects:
+ * [0] :: SVDM header
+ * [1] :: Identitiy header
+ * [2] :: Cert Stat VDO
+ * [3] :: (Product | Cable) VDO
+ * [4] :: AMA VDO
+ *
+ */
+#define VDO_INDEX_HDR 0
+#define VDO_INDEX_IDH 1
+#define VDO_INDEX_CSTAT 2
+#define VDO_INDEX_CABLE 3
+#define VDO_INDEX_PRODUCT 3
+#define VDO_INDEX_AMA 4
+
+/*
+ * SVDM Identity Header
+ * --------------------
+ * <31> :: data capable as a USB host
+ * <30> :: data capable as a USB device
+ * <29:27> :: product type
+ * <26> :: modal operation supported (1b == yes)
+ * <25:16> :: Reserved, Shall be set to zero
+ * <15:0> :: USB-IF assigned VID for this cable vendor
+ */
+#define IDH_PTYPE_UNDEF 0
+#define IDH_PTYPE_HUB 1
+#define IDH_PTYPE_PERIPH 2
+#define IDH_PTYPE_PCABLE 3
+#define IDH_PTYPE_ACABLE 4
+#define IDH_PTYPE_AMA 5
+
+#define VDO_IDH(usbh, usbd, ptype, is_modal, vid) \
+ ((usbh) << 31 | (usbd) << 30 | ((ptype) & 0x7) << 27 \
+ | (is_modal) << 26 | ((vid) & 0xffff))
+
+#define PD_IDH_PTYPE(vdo) (((vdo) >> 27) & 0x7)
+#define PD_IDH_VID(vdo) ((vdo) & 0xffff)
+#define PD_IDH_MODAL_SUPP(vdo) ((vdo) & (1 << 26))
+
+/*
+ * Cert Stat VDO
+ * -------------
+ * <31:0> : USB-IF assigned XID for this cable
+ */
+#define PD_CSTAT_XID(vdo) (vdo)
+
+/*
+ * Product VDO
+ * -----------
+ * <31:16> : USB Product ID
+ * <15:0> : USB bcdDevice
+ */
+#define VDO_PRODUCT(pid, bcd) (((pid) & 0xffff) << 16 | ((bcd) & 0xffff))
+#define PD_PRODUCT_PID(vdo) (((vdo) >> 16) & 0xffff)
+
+/*
+ * Cable VDO
+ * ---------
+ * <31:28> :: Cable HW version
+ * <27:24> :: Cable FW version
+ * <23:20> :: Reserved, Shall be set to zero
+ * <19:18> :: type-C to Type-A/B/C (00b == A, 01 == B, 10 == C)
+ * <17> :: Type-C to Plug/Receptacle (0b == plug, 1b == receptacle)
+ * <16:13> :: cable latency (0001 == <10ns(~1m length))
+ * <12:11> :: cable termination type (11b == both ends active VCONN req)
+ * <10> :: SSTX1 Directionality support (0b == fixed, 1b == cfgable)
+ * <9> :: SSTX2 Directionality support
+ * <8> :: SSRX1 Directionality support
+ * <7> :: SSRX2 Directionality support
+ * <6:5> :: Vbus current handling capability
+ * <4> :: Vbus through cable (0b == no, 1b == yes)
+ * <3> :: SOP" controller present? (0b == no, 1b == yes)
+ * <2:0> :: USB SS Signaling support
+ */
+#define CABLE_ATYPE 0
+#define CABLE_BTYPE 1
+#define CABLE_CTYPE 2
+#define CABLE_PLUG 0
+#define CABLE_RECEPTACLE 1
+#define CABLE_CURR_1A5 0
+#define CABLE_CURR_3A 1
+#define CABLE_CURR_5A 2
+#define CABLE_USBSS_U2_ONLY 0
+#define CABLE_USBSS_U31_GEN1 1
+#define CABLE_USBSS_U31_GEN2 2
+#define VDO_CABLE(hw, fw, cbl, gdr, lat, term, tx1d, tx2d, rx1d, rx2d, cur,\
+ vps, sopp, usbss) \
+ (((hw) & 0x7) << 28 | ((fw) & 0x7) << 24 | ((cbl) & 0x3) << 18 \
+ | (gdr) << 17 | ((lat) & 0x7) << 13 | ((term) & 0x3) << 11 \
+ | (tx1d) << 10 | (tx2d) << 9 | (rx1d) << 8 | (rx2d) << 7 \
+ | ((cur) & 0x3) << 5 | (vps) << 4 | (sopp) << 3 \
+ | ((usbss) & 0x7))
+
+/*
+ * AMA VDO
+ * ---------
+ * <31:28> :: Cable HW version
+ * <27:24> :: Cable FW version
+ * <23:12> :: Reserved, Shall be set to zero
+ * <11> :: SSTX1 Directionality support (0b == fixed, 1b == cfgable)
+ * <10> :: SSTX2 Directionality support
+ * <9> :: SSRX1 Directionality support
+ * <8> :: SSRX2 Directionality support
+ * <7:5> :: Vconn power
+ * <4> :: Vconn power required
+ * <3> :: Vbus power required
+ * <2:0> :: USB SS Signaling support
+ */
+#define VDO_AMA(hw, fw, tx1d, tx2d, rx1d, rx2d, vcpwr, vcr, vbr, usbss) \
+ (((hw) & 0x7) << 28 | ((fw) & 0x7) << 24 \
+ | (tx1d) << 11 | (tx2d) << 10 | (rx1d) << 9 | (rx2d) << 8 \
+ | ((vcpwr) & 0x7) << 5 | (vcr) << 4 | (vbr) << 3 \
+ | ((usbss) & 0x7))
+
+#define PD_VDO_AMA_VCONN_REQ(vdo) (((vdo) >> 4) & 1)
+#define PD_VDO_AMA_VBUS_REQ(vdo) (((vdo) >> 3) & 1)
+
+#define AMA_VCONN_PWR_1W 0
+#define AMA_VCONN_PWR_1W5 1
+#define AMA_VCONN_PWR_2W 2
+#define AMA_VCONN_PWR_3W 3
+#define AMA_VCONN_PWR_4W 4
+#define AMA_VCONN_PWR_5W 5
+#define AMA_VCONN_PWR_6W 6
+#define AMA_USBSS_U2_ONLY 0
+#define AMA_USBSS_U31_GEN1 1
+#define AMA_USBSS_U31_GEN2 2
+#define AMA_USBSS_BBONLY 3
+
+/*
+ * SVDM Discover SVIDs request -> response
+ *
+ * Request is properly formatted VDM Header with discover SVIDs command.
+ * Response is a set of SVIDs of all all supported SVIDs with all zero's to
+ * mark the end of SVIDs. If more than 12 SVIDs are supported command SHOULD be
+ * repeated.
+ */
+#define VDO_SVID(svid0, svid1) (((svid0) & 0xffff) << 16 | ((svid1) & 0xffff))
+#define PD_VDO_SVID_SVID0(vdo) ((vdo) >> 16)
+#define PD_VDO_SVID_SVID1(vdo) ((vdo) & 0xffff)
+
+/* USB-IF SIDs */
+#define USB_SID_PD 0xff00 /* power delivery */
+#define USB_SID_DISPLAYPORT 0xff01
+#define USB_SID_MHL 0xff02 /* Mobile High-Definition Link */
+
+/* VDM command timeouts (in ms) */
+
+#define PD_T_VDM_UNSTRUCTURED 500
+#define PD_T_VDM_BUSY 100
+#define PD_T_VDM_WAIT_MODE_E 100
+#define PD_T_VDM_SNDR_RSP 30
+#define PD_T_VDM_E_MODE 25
+#define PD_T_VDM_RCVR_RSP 15
+
+#endif /* __LINUX_USB_PD_VDO_H */
diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c
new file mode 100644
index 000000000000..7a4a9a89743d
--- /dev/null
+++ b/drivers/staging/typec/tcpci.c
@@ -0,0 +1,935 @@
+/*
+ * Copyright 2015-2017 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * USB Type-C Port Controller Interface.
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/usb/typec.h>
+#include <linux/of_gpio.h>
+#include <linux/extcon.h>
+
+#include "pd.h"
+#include "tcpci.h"
+#include "tcpm.h"
+
+#define PD_RETRY_COUNT 3
+
+struct tcpci {
+ struct device *dev;
+ struct i2c_client *client;
+ struct extcon_dev *edev;
+
+ struct tcpm_port *port;
+
+ struct regmap *regmap;
+
+ bool controls_vbus;
+ bool drive_vbus;
+ bool sink_disable;
+ struct gpio_desc *ss_sel_gpio;
+
+ struct tcpc_dev tcpc;
+ unsigned int irq_mask;
+};
+
+static const unsigned int tcpci_extcon_cable[] = {
+ EXTCON_USB_HOST,
+ EXTCON_USB,
+ EXTCON_NONE,
+};
+
+static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
+{
+ return container_of(tcpc, struct tcpci, tcpc);
+}
+
+static int tcpci_read16(struct tcpci *tcpci, unsigned int reg,
+ unsigned int *val)
+{
+ return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16));
+}
+
+static int tcpci_write16(struct tcpci *tcpci, unsigned int reg, u16 val)
+{
+ return regmap_raw_write(tcpci->regmap, reg, &val, sizeof(u16));
+}
+
+static int tcpci_vbus_force_discharge(struct tcpc_dev *tcpc, bool enable)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ unsigned int reg;
+ int ret;
+
+ if (enable)
+ regmap_write(tcpci->regmap,
+ TCPC_VBUS_VOLTAGE_ALARM_LO_CFG, 0x1c);
+ else
+ regmap_write(tcpci->regmap,
+ TCPC_VBUS_VOLTAGE_ALARM_LO_CFG, 0);
+
+ regmap_read(tcpci->regmap, TCPC_POWER_CTRL, &reg);
+ if (enable)
+ reg |= TCPC_POWER_CTRL_FORCEDISCH;
+ else
+ reg &= ~TCPC_POWER_CTRL_FORCEDISCH;
+ ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL, reg);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ unsigned int reg;
+ int ret;
+
+ switch (cc) {
+ case TYPEC_CC_RA:
+ reg = (TCPC_ROLE_CTRL_CC_RA << TCPC_ROLE_CTRL_CC1_SHIFT) |
+ (TCPC_ROLE_CTRL_CC_RA << TCPC_ROLE_CTRL_CC2_SHIFT);
+ break;
+ case TYPEC_CC_RD:
+ reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) |
+ (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT);
+ break;
+ case TYPEC_CC_RP_DEF:
+ reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) |
+ (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) |
+ (TCPC_ROLE_CTRL_RP_VAL_DEF <<
+ TCPC_ROLE_CTRL_RP_VAL_SHIFT);
+ break;
+ case TYPEC_CC_RP_1_5:
+ reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) |
+ (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) |
+ (TCPC_ROLE_CTRL_RP_VAL_1_5 <<
+ TCPC_ROLE_CTRL_RP_VAL_SHIFT);
+ break;
+ case TYPEC_CC_RP_3_0:
+ reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) |
+ (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) |
+ (TCPC_ROLE_CTRL_RP_VAL_3_0 <<
+ TCPC_ROLE_CTRL_RP_VAL_SHIFT);
+ break;
+ case TYPEC_CC_OPEN:
+ default:
+ reg = (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC1_SHIFT) |
+ (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC2_SHIFT);
+ break;
+ }
+
+ ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
+ enum typec_cc_status cc, int attach)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ unsigned int reg = 0;
+
+ /* Only set DRP bit for auto toggle when unattached */
+ if (attach) {
+ switch (cc) {
+ case TYPEC_CC_RP_DEF:
+ if (attach >> TYPEC_POLARITY_CC2)
+ reg |= TCPC_ROLE_CTRL_CC_RP <<
+ TCPC_ROLE_CTRL_CC2_SHIFT;
+ else if (attach >> TYPEC_POLARITY_CC1)
+ reg |= TCPC_ROLE_CTRL_CC_RP <<
+ TCPC_ROLE_CTRL_CC1_SHIFT;
+
+ reg |= (TCPC_ROLE_CTRL_RP_VAL_DEF <<
+ TCPC_ROLE_CTRL_RP_VAL_SHIFT);
+ break;
+ case TYPEC_CC_RP_1_5:
+ if (attach >> TYPEC_POLARITY_CC2)
+ reg |= TCPC_ROLE_CTRL_CC_RP <<
+ TCPC_ROLE_CTRL_CC2_SHIFT;
+ else if (attach >> TYPEC_POLARITY_CC1)
+ reg |= TCPC_ROLE_CTRL_CC_RP <<
+ TCPC_ROLE_CTRL_CC1_SHIFT;
+
+ reg |= (TCPC_ROLE_CTRL_RP_VAL_1_5 <<
+ TCPC_ROLE_CTRL_RP_VAL_SHIFT);
+ break;
+ case TYPEC_CC_RP_3_0:
+ if (attach >> TYPEC_POLARITY_CC2)
+ reg |= TCPC_ROLE_CTRL_CC_RP <<
+ TCPC_ROLE_CTRL_CC2_SHIFT;
+ else if (attach >> TYPEC_POLARITY_CC1)
+ reg |= TCPC_ROLE_CTRL_CC_RP <<
+ TCPC_ROLE_CTRL_CC1_SHIFT;
+
+ reg |= (TCPC_ROLE_CTRL_RP_VAL_3_0 <<
+ TCPC_ROLE_CTRL_RP_VAL_SHIFT);
+ break;
+ case TYPEC_CC_RD:
+ if (attach >> TYPEC_POLARITY_CC2)
+ reg |= TCPC_ROLE_CTRL_CC_RD <<
+ TCPC_ROLE_CTRL_CC2_SHIFT;
+ else if (attach >> TYPEC_POLARITY_CC1)
+ reg |= TCPC_ROLE_CTRL_CC_RD <<
+ TCPC_ROLE_CTRL_CC1_SHIFT;
+ break;
+ default:
+ break;
+ }
+
+ /* keep the un-touched cc line to be open */
+ if (attach >> TYPEC_POLARITY_CC2)
+ reg |= TCPC_ROLE_CTRL_CC_OPEN <<
+ TCPC_ROLE_CTRL_CC1_SHIFT;
+ else if (attach >> TYPEC_POLARITY_CC1)
+ reg |= TCPC_ROLE_CTRL_CC_OPEN <<
+ TCPC_ROLE_CTRL_CC2_SHIFT;
+ } else { /* Not attached */
+ if (cc == TYPEC_CC_RD)
+ reg = TCPC_ROLE_CTRL_DRP | 0xa; /* Rd */
+ else
+ reg = TCPC_ROLE_CTRL_DRP | 0x5; /* Rp */
+ }
+
+ regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
+
+ if (!attach)
+ regmap_write(tcpci->regmap, TCPC_COMMAND,
+ TCPC_CMD_LOOK4CONNECTION);
+ return 0;
+}
+
+static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
+{
+ switch (cc) {
+ case 0x1:
+ return sink ? TYPEC_CC_RP_DEF : TYPEC_CC_RA;
+ case 0x2:
+ return sink ? TYPEC_CC_RP_1_5 : TYPEC_CC_RD;
+ case 0x3:
+ if (sink)
+ return TYPEC_CC_RP_3_0;
+ case 0x0:
+ default:
+ return TYPEC_CC_OPEN;
+ }
+}
+
+static int tcpci_get_cc(struct tcpc_dev *tcpc,
+ enum typec_cc_status *cc1, enum typec_cc_status *cc2)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(tcpci->regmap, TCPC_CC_STATUS, &reg);
+ if (ret < 0)
+ return ret;
+
+ *cc1 = tcpci_to_typec_cc((reg >> TCPC_CC_STATUS_CC1_SHIFT) &
+ TCPC_CC_STATUS_CC1_MASK,
+ reg & TCPC_CC_STATUS_TERM);
+ *cc2 = tcpci_to_typec_cc((reg >> TCPC_CC_STATUS_CC2_SHIFT) &
+ TCPC_CC_STATUS_CC2_MASK,
+ reg & TCPC_CC_STATUS_TERM);
+
+ return 0;
+}
+
+static int tcpci_set_polarity(struct tcpc_dev *tcpc,
+ enum typec_cc_polarity polarity)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ int ret;
+
+ ret = regmap_write(tcpci->regmap, TCPC_TCPC_CTRL,
+ (polarity == TYPEC_POLARITY_CC2) ?
+ TCPC_TCPC_CTRL_ORIENTATION : 0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int tcpci_set_ss_mux(struct tcpc_dev *tcpc,
+ enum typec_cc_polarity polarity)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+
+ if (!tcpci->ss_sel_gpio)
+ return 0;
+
+ if (polarity == TYPEC_POLARITY_CC1)
+ gpiod_set_value_cansleep(tcpci->ss_sel_gpio, 1);
+ else
+ gpiod_set_value_cansleep(tcpci->ss_sel_gpio, 0);
+
+ return 0;
+}
+
+static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ int ret;
+
+ ret = regmap_update_bits(tcpci->regmap, TCPC_POWER_CTRL,
+ TCPC_POWER_CTRL_VCONN_ENABLE,
+ enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
+ return ret;
+}
+
+static int tcpci_set_roles(struct tcpc_dev *tcpc, bool attached,
+ enum typec_role role, enum typec_data_role data)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ unsigned int reg;
+ int ret;
+
+ reg = PD_REV20 << TCPC_MSG_HDR_INFO_REV_SHIFT;
+ if (role == TYPEC_SOURCE)
+ reg |= TCPC_MSG_HDR_INFO_PWR_ROLE;
+ if (data == TYPEC_HOST)
+ reg |= TCPC_MSG_HDR_INFO_DATA_ROLE;
+ ret = regmap_write(tcpci->regmap, TCPC_MSG_HDR_INFO, reg);
+ if (ret < 0)
+ return ret;
+
+ if (data == TYPEC_HOST)
+ extcon_set_state_sync(tcpci->edev, EXTCON_USB_HOST, true);
+ else
+ extcon_set_state_sync(tcpci->edev, EXTCON_USB_HOST, false);
+
+ return 0;
+}
+
+static int tcpci_set_pd_rx(struct tcpc_dev *tcpc, bool enable)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ unsigned int reg = 0;
+ int ret;
+
+ if (enable)
+ reg = TCPC_RX_DETECT_SOP | TCPC_RX_DETECT_HARD_RESET;
+ ret = regmap_write(tcpci->regmap, TCPC_RX_DETECT, reg);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int tcpci_get_vbus(struct tcpc_dev *tcpc)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(tcpci->regmap, TCPC_POWER_STATUS, &reg);
+ if (ret < 0)
+ return ret;
+
+ ret = !!(reg & TCPC_POWER_STATUS_VBUS_PRES);
+
+ /*
+ * If the vbus is not from itself for source, we
+ * assume the vbus is from the port partner, this
+ * is to work around the case of connect to legacy
+ * Host like PC via a fixed Rp pull up cable, so
+ * we notify the possible EXTCON_USB connection.
+ */
+ if (!tcpci->drive_vbus)
+ extcon_set_state_sync(tcpci->edev, EXTCON_USB, ret);
+
+ return ret;
+}
+
+static unsigned int tcpci_get_vbus_vol(struct tcpc_dev *tcpc)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ unsigned int reg, ret = 0;
+
+ ret = regmap_read(tcpci->regmap, TCPC_VBUS_VOLTAGE, &reg);
+
+ /* Convert it to be the vol number(mv) */
+ ret = ((reg & TCPC_VBUS_VOL_MASK) <<
+ ((reg & TCPC_VBUS_VOL_SCALE_FACTOR_MASK) >>
+ TCPC_VBUS_VOL_SCALE_FACTOR_SHIFT)) * TCPC_VBUS_VOL_MV_UNIT;
+
+ return ret;
+}
+
+static int tcpci_set_vbus(struct tcpc_dev *tcpc, bool source, bool sink)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ int ret;
+
+ /* Only disable source if it was enabled */
+ if (!source && tcpci->drive_vbus) {
+ ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
+ TCPC_CMD_DISABLE_SRC_VBUS);
+ if (ret < 0)
+ return ret;
+
+ tcpci->drive_vbus = false;
+ }
+
+ if (!sink) {
+ ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
+ TCPC_CMD_DISABLE_SINK_VBUS);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Enable force discharge */
+ if (!source && !sink)
+ tcpci_vbus_force_discharge(tcpc, true);
+
+ if (source) {
+ ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
+ TCPC_CMD_SRC_VBUS_DEFAULT);
+ if (ret < 0)
+ return ret;
+ tcpci->drive_vbus = true;
+ }
+
+ if (sink && !tcpci->sink_disable) {
+ ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
+ TCPC_CMD_SINK_VBUS);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tcpci_pd_transmit(struct tcpc_dev *tcpc,
+ enum tcpm_transmit_type type,
+ const struct pd_message *msg)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ unsigned int reg, cnt, header;
+ int ret;
+
+ cnt = msg ? pd_header_cnt(msg->header) * 4 : 0;
+ ret = regmap_write(tcpci->regmap, TCPC_TX_BYTE_CNT, cnt + 2);
+ if (ret < 0)
+ return ret;
+
+ header = msg ? msg->header : 0;
+ ret = tcpci_write16(tcpci, TCPC_TX_HDR, header);
+ if (ret < 0)
+ return ret;
+
+ if (cnt > 0) {
+ ret = regmap_raw_write(tcpci->regmap, TCPC_TX_DATA,
+ &msg->payload, cnt);
+ if (ret < 0)
+ return ret;
+ }
+
+ reg = (PD_RETRY_COUNT << TCPC_TRANSMIT_RETRY_SHIFT) |
+ (type << TCPC_TRANSMIT_TYPE_SHIFT);
+ ret = regmap_write(tcpci->regmap, TCPC_TRANSMIT, reg);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int tcpci_vbus_detect(struct tcpc_dev *tcpc, bool enable)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ int ret;
+
+ if (enable) {
+ ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
+ TCPC_CMD_ENABLE_VBUS_DETECT);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
+ TCPC_CMD_DISABLE_VBUS_DETECT);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void tcpci_bist_mode(struct tcpc_dev *tcpc, bool enable)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+
+ regmap_update_bits(tcpci->regmap, TCPC_TCPC_CTRL,
+ TCPC_TCPC_CTRL_BIST_MODE,
+ enable ? TCPC_TCPC_CTRL_BIST_MODE : 0);
+}
+
+static int tcpci_init(struct tcpc_dev *tcpc)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ unsigned long timeout = jiffies + msecs_to_jiffies(2000); /* XXX */
+ unsigned int reg;
+ int ret;
+
+ while (time_before_eq(jiffies, timeout)) {
+ ret = regmap_read(tcpci->regmap, TCPC_POWER_STATUS, &reg);
+ if (ret < 0)
+ return ret;
+ if (!(reg & TCPC_POWER_STATUS_UNINIT))
+ break;
+ usleep_range(10000, 20000);
+ }
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+
+ /* Clear all events */
+ ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
+ if (ret < 0)
+ return ret;
+
+ /* Clear fault condition */
+ regmap_write(tcpci->regmap, TCPC_FAULT_STATUS, 0x80);
+
+ if (tcpci->controls_vbus)
+ reg = TCPC_POWER_STATUS_VBUS_PRES;
+ else
+ reg = 0;
+ ret = regmap_write(tcpci->regmap, TCPC_POWER_STATUS_MASK, reg);
+ if (ret < 0)
+ return ret;
+
+ /* Enable Voltage Alarms Power status reporting */
+ regmap_read(tcpci->regmap, TCPC_POWER_CTRL, &reg);
+ reg &= ~TCPC_POWER_CTRL_DIS_VOL_ALARM;
+ ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL, reg);
+
+ reg = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_FAILED |
+ TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_RX_STATUS |
+ TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_CC_STATUS |
+ TCPC_ALERT_RX_BUF_OVF | TCPC_ALERT_FAULT |
+ TCPC_ALERT_V_ALARM_LO;
+ if (tcpci->controls_vbus)
+ reg |= TCPC_ALERT_POWER_STATUS;
+ tcpci->irq_mask = reg;
+
+ return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);
+}
+
+static irqreturn_t tcpci_irq(int irq, void *dev_id)
+{
+ struct tcpci *tcpci = dev_id;
+ unsigned int status, reg;
+
+ tcpci_read16(tcpci, TCPC_ALERT, &status);
+
+ /*
+ * Clear alert status for enabled irq except RX_STATUS, which shouldn't
+ * be cleared until we have successfully retrieved message.
+ */
+ if ((status & ~TCPC_ALERT_RX_STATUS) & tcpci->irq_mask)
+ tcpci_write16(tcpci, TCPC_ALERT,
+ status & ~TCPC_ALERT_RX_STATUS);
+
+ if (status & TCPC_ALERT_CC_STATUS)
+ tcpm_cc_change(tcpci->port);
+
+ if (status & TCPC_ALERT_POWER_STATUS) {
+ /* Read power status to clear the event */
+ regmap_read(tcpci->regmap, TCPC_POWER_STATUS, &reg);
+
+ regmap_read(tcpci->regmap, TCPC_POWER_STATUS_MASK, &reg);
+
+ /*
+ * If power status mask has been reset, then the TCPC
+ * has reset.
+ */
+ if (reg == 0xff)
+ tcpm_tcpc_reset(tcpci->port);
+ else
+ tcpm_vbus_change(tcpci->port);
+ }
+
+ if (status & TCPC_ALERT_V_ALARM_LO)
+ tcpm_vbus_low_alarm(tcpci->port);
+
+ if (status & TCPC_ALERT_RX_STATUS) {
+ struct pd_message msg;
+ unsigned int cnt;
+
+ regmap_read(tcpci->regmap, TCPC_RX_BYTE_CNT, &cnt);
+
+ tcpci_read16(tcpci, TCPC_RX_HDR, &reg);
+ msg.header = reg;
+
+ /*
+ * TCPC_RX_BYTE_CNT is the number of bytes in the
+ * RX_BUFFER_DATA_OBJECTS plus three (for the RX_BUF_FRAME_TYPE
+ * and RX_BUF_HEADER).
+ */
+ cnt -= 3;
+ if (WARN_ON(cnt > sizeof(msg.payload)))
+ cnt = sizeof(msg.payload);
+
+ if (cnt > 0)
+ regmap_raw_read(tcpci->regmap, TCPC_RX_DATA,
+ &msg.payload, cnt);
+
+ /* Read complete, clear RX status alert bit */
+ tcpci_write16(tcpci, TCPC_ALERT, TCPC_ALERT_RX_STATUS);
+
+ tcpm_pd_receive(tcpci->port, &msg);
+ }
+
+ if (status & TCPC_ALERT_RX_BUF_OVF)
+ tcpci_write16(tcpci, TCPC_ALERT,
+ TCPC_ALERT_RX_BUF_OVF | TCPC_ALERT_RX_STATUS);
+
+ /* Clear the fault status anyway */
+ if (status & TCPC_ALERT_FAULT) {
+ regmap_read(tcpci->regmap, TCPC_FAULT_STATUS, &reg);
+ regmap_write(tcpci->regmap, TCPC_FAULT_STATUS,
+ reg | TCPC_FAULT_STATUS_CLEAR);
+ }
+
+ if (status & TCPC_ALERT_RX_HARD_RST)
+ tcpm_pd_hard_reset(tcpci->port);
+
+ if (status & TCPC_ALERT_TX_SUCCESS)
+ tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_SUCCESS);
+ else if (status & TCPC_ALERT_TX_DISCARDED)
+ tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_DISCARDED);
+ else if (status & TCPC_ALERT_TX_FAILED)
+ tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_FAILED);
+
+ return IRQ_HANDLED;
+}
+
+static const struct regmap_config tcpci_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = 0x7F, /* 0x80 .. 0xFF are vendor defined */
+};
+
+const struct tcpc_config tcpci_tcpc_config = {
+ .type = TYPEC_PORT_DFP,
+ .default_role = TYPEC_SINK,
+};
+
+/* Populate struct tcpc_config from ACPI/device-tree */
+static int tcpci_parse_config(struct tcpci *tcpci)
+{
+ struct tcpc_config *tcfg;
+ int ret = -EINVAL;
+
+ tcpci->controls_vbus = true; /* XXX */
+
+ /* Alloc tcpc_config struct */
+ tcpci->tcpc.config = devm_kzalloc(tcpci->dev, sizeof(*tcfg),
+ GFP_KERNEL);
+ if (!tcpci->tcpc.config)
+ return -ENOMEM;
+
+ tcfg = tcpci->tcpc.config;
+
+ /* Get the port-type */
+ tcfg->type = typec_get_port_type(tcpci->dev);
+ if (tcfg->type == TYPEC_PORT_TYPE_UNKNOWN) {
+ dev_err(tcpci->dev, "typec port type is NOT correct!\n");
+ return -EINVAL;
+ }
+
+ if (tcfg->type == TYPEC_PORT_UFP)
+ goto sink;
+
+ /* Check source pdo array size */
+ tcfg->nr_src_pdo = device_property_read_u32_array(tcpci->dev,
+ "src-pdos", NULL, 0);
+ if (tcfg->nr_src_pdo <= 0) {
+ dev_err(tcpci->dev, "typec source pdo is missing!\n");
+ return -EINVAL;
+ }
+
+ /* Alloc src_pdo based on the array size */
+ tcfg->src_pdo = devm_kzalloc(tcpci->dev,
+ sizeof(*tcfg->src_pdo) * tcfg->nr_src_pdo, GFP_KERNEL);
+ if (!tcfg->src_pdo)
+ return -ENOMEM;
+
+ /* Read out source pdo array */
+ ret = device_property_read_u32_array(tcpci->dev, "src-pdos",
+ tcfg->src_pdo, tcfg->nr_src_pdo);
+ if (ret) {
+ dev_err(tcpci->dev, "Failed to read src pdo!\n");
+ return -EINVAL;
+ }
+
+ if (tcfg->type == TYPEC_PORT_DFP)
+ return 0;
+
+ /* Get the default-role */
+ tcfg->default_role = typec_get_power_role(tcpci->dev);
+ if (tcfg->default_role == TYPEC_ROLE_UNKNOWN) {
+ dev_err(tcpci->dev, "typec power role is NOT correct!\n");
+ return -EINVAL;
+ }
+
+ /*
+ * In case DRP only for data role, power role is source only
+ * we can use this property to disable power sink.
+ */
+ if (device_property_read_bool(tcpci->dev, "sink-disable")) {
+ tcpci->sink_disable = true;
+
+ /* Provide a sink PDO to setup a PD session */
+ tcfg->nr_snk_pdo = 1;
+ tcfg->snk_pdo = devm_kzalloc(tcpci->dev,
+ sizeof(*tcfg->snk_pdo), GFP_KERNEL);
+ if (!tcfg->snk_pdo)
+ return -ENOMEM;
+
+ /*
+ * Sink PDO setting:
+ * - Voltage in 50mV units: 5V
+ * - Operational Current in 10mA units: 100mA
+ */
+ *tcfg->snk_pdo = PDO_FIXED(5000,
+ 100,
+ PDO_FIXED_DUAL_ROLE |
+ PDO_FIXED_EXTPOWER |
+ PDO_FIXED_USB_COMM |
+ PDO_FIXED_DATA_SWAP);
+ tcfg->max_snk_mv = 5000;
+ tcfg->max_snk_ma = 2000;
+ tcfg->max_snk_mw = 10000;
+ tcfg->operating_snk_mw = 500;
+
+ return 0;
+ }
+
+sink:
+ /* Check the num of snk pdo */
+ tcfg->nr_snk_pdo = device_property_read_u32_array(tcpci->dev,
+ "snk-pdos", NULL, 0);
+ if (tcfg->nr_snk_pdo <= 0) {
+ dev_err(tcpci->dev, "typec sink pdo is missing!\n");
+ return -EINVAL;
+ }
+
+ /* alloc snk_pdo based on the array size */
+ tcfg->snk_pdo = devm_kzalloc(tcpci->dev,
+ sizeof(*tcfg->snk_pdo) * tcfg->nr_snk_pdo, GFP_KERNEL);
+ if (!tcfg->snk_pdo)
+ return -ENOMEM;
+
+ /* Read out sink pdo array */
+ ret = device_property_read_u32_array(tcpci->dev, "snk-pdos",
+ tcfg->snk_pdo, tcfg->nr_snk_pdo);
+ if (ret) {
+ dev_err(tcpci->dev, "Failed to read snk pdo!\n");
+ return -EINVAL;
+ }
+
+ /* Get the max-snk-mv max-snk-ma op-snk-mw */
+ if (device_property_read_u32(tcpci->dev, "max-snk-mv",
+ &tcfg->max_snk_mv) ||
+ device_property_read_u32(tcpci->dev, "max-snk-ma",
+ &tcfg->max_snk_ma) ||
+ device_property_read_u32(tcpci->dev, "max-snk-mw",
+ &tcfg->max_snk_mw) ||
+ device_property_read_u32(tcpci->dev, "op-snk-mw",
+ &tcfg->operating_snk_mw)) {
+ ret = -EINVAL;
+ goto snk_setting_wrong;
+ }
+
+ return 0;
+
+snk_setting_wrong:
+ if (tcfg->type == TYPEC_PORT_DRP ||
+ tcfg->type == TYPEC_PORT_UFP)
+ dev_err(tcpci->dev, "Failed to read snk setting!\n");
+
+ return ret;
+}
+
+static int tcpci_ss_mux_control_init(struct tcpci *tcpci)
+{
+ struct device *dev = tcpci->dev;
+ struct gpio_desc *gpiod_reset;
+
+ gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(gpiod_reset)) {
+ dev_err(dev, "Failed to request reset gpio.");
+ return PTR_ERR(gpiod_reset);
+ }
+
+ if (gpiod_reset)
+ usleep_range(700, 1000);
+
+ tcpci->ss_sel_gpio = devm_gpiod_get_optional(dev, "ss-sel",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(tcpci->ss_sel_gpio)) {
+ dev_err(dev, "Failed to request super speed mux sel gpio.");
+ return PTR_ERR(tcpci->ss_sel_gpio);
+ }
+
+ return 0;
+}
+
+static int tcpci_probe(struct i2c_client *client,
+ const struct i2c_device_id *i2c_id)
+{
+ struct tcpci *tcpci;
+ int err;
+
+ tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL);
+ if (!tcpci)
+ return -ENOMEM;
+
+ tcpci->client = client;
+ tcpci->dev = &client->dev;
+ i2c_set_clientdata(client, tcpci);
+ tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
+ if (IS_ERR(tcpci->regmap))
+ return PTR_ERR(tcpci->regmap);
+
+ tcpci->tcpc.init = tcpci_init;
+ tcpci->tcpc.get_vbus = tcpci_get_vbus;
+ tcpci->tcpc.set_vbus = tcpci_set_vbus;
+ tcpci->tcpc.set_cc = tcpci_set_cc;
+ tcpci->tcpc.get_cc = tcpci_get_cc;
+ tcpci->tcpc.set_polarity = tcpci_set_polarity;
+ tcpci->tcpc.set_vconn = tcpci_set_vconn;
+ tcpci->tcpc.start_drp_toggling = tcpci_start_drp_toggling;
+ tcpci->tcpc.vbus_detect = tcpci_vbus_detect;
+ tcpci->tcpc.vbus_discharge = tcpci_vbus_force_discharge;
+ tcpci->tcpc.get_vbus_vol = tcpci_get_vbus_vol;
+ tcpci->tcpc.bist_mode = tcpci_bist_mode;
+ tcpci->tcpc.ss_mux_sel = tcpci_set_ss_mux;
+
+ tcpci->tcpc.set_pd_rx = tcpci_set_pd_rx;
+ tcpci->tcpc.set_roles = tcpci_set_roles;
+ tcpci->tcpc.pd_transmit = tcpci_pd_transmit;
+
+ /* Allocate extcon device */
+ tcpci->edev = devm_extcon_dev_allocate(&client->dev,
+ tcpci_extcon_cable);
+ if (IS_ERR(tcpci->edev)) {
+ dev_err(&client->dev, "failed to allocate extcon dev.\n");
+ return -ENOMEM;
+ }
+
+ err = devm_extcon_dev_register(&client->dev, tcpci->edev);
+ if (err) {
+ dev_err(&client->dev, "failed to register extcon dev.\n");
+ return err;
+ }
+
+ err = tcpci_parse_config(tcpci);
+ if (err < 0)
+ return err;
+
+ tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
+ if (IS_ERR(tcpci->port))
+ return PTR_ERR(tcpci->port);
+
+ err = tcpci_ss_mux_control_init(tcpci);
+ if (err)
+ goto err1;
+
+ err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL,
+ tcpci_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ dev_name(tcpci->dev), tcpci);
+ if (err < 0)
+ goto err1;
+
+ device_set_wakeup_capable(tcpci->dev, true);
+
+ return 0;
+err1:
+ tcpm_unregister_port(tcpci->port);
+ return err;
+}
+
+static int tcpci_remove(struct i2c_client *client)
+{
+ struct tcpci *tcpci = i2c_get_clientdata(client);
+
+ tcpm_unregister_port(tcpci->port);
+
+ return 0;
+}
+
+static int tcpci_suspend(struct device *dev)
+{
+ struct tcpci *tcpci = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(tcpci->client->irq);
+
+ return 0;
+}
+
+static int tcpci_resume(struct device *dev)
+{
+ struct tcpci *tcpci = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(tcpci->client->irq);
+
+ return 0;
+}
+
+static const struct dev_pm_ops tcpci_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(tcpci_suspend, tcpci_resume)
+};
+
+static const struct i2c_device_id tcpci_id[] = {
+ { "tcpci", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tcpci_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id tcpci_of_match[] = {
+ { .compatible = "usb,tcpci", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tcpci_of_match);
+#endif
+
+static struct i2c_driver tcpci_i2c_driver = {
+ .driver = {
+ .name = "tcpci",
+ .pm = &tcpci_pm_ops,
+ .of_match_table = of_match_ptr(tcpci_of_match),
+ },
+ .probe = tcpci_probe,
+ .remove = tcpci_remove,
+ .id_table = tcpci_id,
+};
+module_i2c_driver(tcpci_i2c_driver);
+
+MODULE_DESCRIPTION("USB Type-C Port Controller Interface driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/typec/tcpci.h b/drivers/staging/typec/tcpci.h
new file mode 100644
index 000000000000..8b261a456917
--- /dev/null
+++ b/drivers/staging/typec/tcpci.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2015-2017 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * USB Type-C Port Controller Interface.
+ */
+
+#ifndef __LINUX_USB_TCPCI_H
+#define __LINUX_USB_TCPCI_H
+
+#define TCPC_VENDOR_ID 0x0
+#define TCPC_PRODUCT_ID 0x2
+#define TCPC_BCD_DEV 0x4
+#define TCPC_TC_REV 0x6
+#define TCPC_PD_REV 0x8
+#define TCPC_PD_INT_REV 0xa
+
+#define TCPC_ALERT 0x10
+#define TCPC_ALERT_VBUS_DISCNCT BIT(11)
+#define TCPC_ALERT_RX_BUF_OVF BIT(10)
+#define TCPC_ALERT_FAULT BIT(9)
+#define TCPC_ALERT_V_ALARM_LO BIT(8)
+#define TCPC_ALERT_V_ALARM_HI BIT(7)
+#define TCPC_ALERT_TX_SUCCESS BIT(6)
+#define TCPC_ALERT_TX_DISCARDED BIT(5)
+#define TCPC_ALERT_TX_FAILED BIT(4)
+#define TCPC_ALERT_RX_HARD_RST BIT(3)
+#define TCPC_ALERT_RX_STATUS BIT(2)
+#define TCPC_ALERT_POWER_STATUS BIT(1)
+#define TCPC_ALERT_CC_STATUS BIT(0)
+
+#define TCPC_ALERT_MASK 0x12
+#define TCPC_POWER_STATUS_MASK 0x14
+#define TCPC_FAULT_STATUS_MASK 0x15
+#define TCPC_FAULT_STATUS_CLEAR BIT(7)
+#define TCPC_CONFIG_STD_OUTPUT 0x18
+
+#define TCPC_TCPC_CTRL 0x19
+#define TCPC_TCPC_CTRL_BIST_MODE BIT(1)
+#define TCPC_TCPC_CTRL_ORIENTATION BIT(0)
+
+#define TCPC_ROLE_CTRL 0x1a
+#define TCPC_ROLE_CTRL_DRP BIT(6)
+#define TCPC_ROLE_CTRL_RP_VAL_SHIFT 4
+#define TCPC_ROLE_CTRL_RP_VAL_MASK 0x3
+#define TCPC_ROLE_CTRL_RP_VAL_DEF 0x0
+#define TCPC_ROLE_CTRL_RP_VAL_1_5 0x1
+#define TCPC_ROLE_CTRL_RP_VAL_3_0 0x2
+#define TCPC_ROLE_CTRL_CC2_SHIFT 2
+#define TCPC_ROLE_CTRL_CC2_MASK 0x3
+#define TCPC_ROLE_CTRL_CC1_SHIFT 0
+#define TCPC_ROLE_CTRL_CC1_MASK 0x3
+#define TCPC_ROLE_CTRL_CC_RA 0x0
+#define TCPC_ROLE_CTRL_CC_RP 0x1
+#define TCPC_ROLE_CTRL_CC_RD 0x2
+#define TCPC_ROLE_CTRL_CC_OPEN 0x3
+
+#define TCPC_FAULT_CTRL 0x1b
+
+#define TCPC_POWER_CTRL 0x1c
+#define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0)
+#define TCPC_POWER_CTRL_FORCEDISCH BIT(2)
+#define TCPC_POWER_CTRL_DIS_VOL_ALARM BIT(5)
+
+#define TCPC_CC_STATUS 0x1d
+#define TCPC_CC_STATUS_TERM BIT(4)
+#define TCPC_CC_STATUS_CC2_SHIFT 2
+#define TCPC_CC_STATUS_CC2_MASK 0x3
+#define TCPC_CC_STATUS_CC1_SHIFT 0
+#define TCPC_CC_STATUS_CC1_MASK 0x3
+
+#define TCPC_POWER_STATUS 0x1e
+#define TCPC_POWER_STATUS_UNINIT BIT(6)
+#define TCPC_POWER_STATUS_VBUS_DET BIT(3)
+#define TCPC_POWER_STATUS_VBUS_PRES BIT(2)
+
+#define TCPC_FAULT_STATUS 0x1f
+
+#define TCPC_COMMAND 0x23
+#define TCPC_CMD_WAKE_I2C 0x11
+#define TCPC_CMD_DISABLE_VBUS_DETECT 0x22
+#define TCPC_CMD_ENABLE_VBUS_DETECT 0x33
+#define TCPC_CMD_DISABLE_SINK_VBUS 0x44
+#define TCPC_CMD_SINK_VBUS 0x55
+#define TCPC_CMD_DISABLE_SRC_VBUS 0x66
+#define TCPC_CMD_SRC_VBUS_DEFAULT 0x77
+#define TCPC_CMD_SRC_VBUS_HIGH 0x88
+#define TCPC_CMD_LOOK4CONNECTION 0x99
+#define TCPC_CMD_RXONEMORE 0xAA
+#define TCPC_CMD_I2C_IDLE 0xFF
+
+#define TCPC_DEV_CAP_1 0x24
+#define TCPC_DEV_CAP_2 0x26
+#define TCPC_STD_INPUT_CAP 0x28
+#define TCPC_STD_OUTPUT_CAP 0x29
+
+#define TCPC_MSG_HDR_INFO 0x2e
+#define TCPC_MSG_HDR_INFO_DATA_ROLE BIT(3)
+#define TCPC_MSG_HDR_INFO_PWR_ROLE BIT(0)
+#define TCPC_MSG_HDR_INFO_REV_SHIFT 1
+#define TCPC_MSG_HDR_INFO_REV_MASK 0x3
+
+#define TCPC_RX_DETECT 0x2f
+#define TCPC_RX_DETECT_HARD_RESET BIT(5)
+#define TCPC_RX_DETECT_SOP BIT(0)
+
+#define TCPC_RX_BYTE_CNT 0x30
+#define TCPC_RX_BUF_FRAME_TYPE 0x31
+#define TCPC_RX_HDR 0x32
+#define TCPC_RX_DATA 0x34 /* through 0x4f */
+
+#define TCPC_TRANSMIT 0x50
+#define TCPC_TRANSMIT_RETRY_SHIFT 4
+#define TCPC_TRANSMIT_RETRY_MASK 0x3
+#define TCPC_TRANSMIT_TYPE_SHIFT 0
+#define TCPC_TRANSMIT_TYPE_MASK 0x7
+
+#define TCPC_TX_BYTE_CNT 0x51
+#define TCPC_TX_HDR 0x52
+#define TCPC_TX_DATA 0x54 /* through 0x6f */
+
+#define TCPC_VBUS_VOLTAGE 0x70
+#define TCPC_VBUS_VOL_MASK 0x3ff
+#define TCPC_VBUS_VOL_SCALE_FACTOR_MASK 0xc00
+#define TCPC_VBUS_VOL_SCALE_FACTOR_SHIFT 10
+#define TCPC_VBUS_VOL_MV_UNIT 25
+
+#define TCPC_VBUS_SINK_DISCONNECT_THRESH 0x72
+#define TCPC_VBUS_STOP_DISCHARGE_THRESH 0x74
+#define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG 0x76
+#define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG 0x78
+
+#endif /* __LINUX_USB_TCPCI_H */
diff --git a/drivers/staging/typec/tcpm.c b/drivers/staging/typec/tcpm.c
new file mode 100644
index 000000000000..7e167bdaf7da
--- /dev/null
+++ b/drivers/staging/typec/tcpm.c
@@ -0,0 +1,3637 @@
+/*
+ * Copyright 2015-2017 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * USB Power Delivery protocol stack.
+ */
+
+#include <linux/completion.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/usb/typec.h>
+#include <linux/workqueue.h>
+#include <linux/busfreq-imx.h>
+#include <linux/pm_qos.h>
+
+#include "pd.h"
+#include "pd_vdo.h"
+#include "pd_bdo.h"
+#include "tcpm.h"
+
+#define FOREACH_STATE(S) \
+ S(INVALID_STATE), \
+ S(DRP_TOGGLING), \
+ S(SRC_UNATTACHED), \
+ S(SRC_ATTACH_WAIT), \
+ S(SRC_ATTACHED), \
+ S(SRC_STARTUP), \
+ S(SRC_SEND_CAPABILITIES), \
+ S(SRC_NEGOTIATE_CAPABILITIES), \
+ S(SRC_TRANSITION_SUPPLY), \
+ S(SRC_READY), \
+ S(SRC_WAIT_NEW_CAPABILITIES), \
+ \
+ S(SNK_UNATTACHED), \
+ S(SNK_ATTACH_WAIT), \
+ S(SNK_DEBOUNCED), \
+ S(SNK_ATTACHED), \
+ S(SNK_STARTUP), \
+ S(SNK_DISCOVERY), \
+ S(SNK_DISCOVERY_DEBOUNCE), \
+ S(SNK_DISCOVERY_DEBOUNCE_DONE), \
+ S(SNK_WAIT_CAPABILITIES), \
+ S(SNK_NEGOTIATE_CAPABILITIES), \
+ S(SNK_TRANSITION_SINK), \
+ S(SNK_TRANSITION_SINK_VBUS), \
+ S(SNK_READY), \
+ \
+ S(ACC_UNATTACHED), \
+ S(DEBUG_ACC_ATTACHED), \
+ S(AUDIO_ACC_ATTACHED), \
+ S(AUDIO_ACC_DEBOUNCE), \
+ \
+ S(HARD_RESET_SEND), \
+ S(HARD_RESET_START), \
+ S(SRC_HARD_RESET_VBUS_OFF), \
+ S(SRC_HARD_RESET_VBUS_ON), \
+ S(SNK_HARD_RESET_SINK_OFF), \
+ S(SNK_HARD_RESET_WAIT_VBUS), \
+ S(SNK_HARD_RESET_SINK_ON), \
+ \
+ S(SOFT_RESET), \
+ S(SOFT_RESET_SEND), \
+ \
+ S(DR_SWAP_ACCEPT), \
+ S(DR_SWAP_SEND), \
+ S(DR_SWAP_SEND_TIMEOUT), \
+ S(DR_SWAP_CANCEL), \
+ S(DR_SWAP_CHANGE_DR), \
+ \
+ S(PR_SWAP_ACCEPT), \
+ S(PR_SWAP_SEND), \
+ S(PR_SWAP_SEND_TIMEOUT), \
+ S(PR_SWAP_CANCEL), \
+ S(PR_SWAP_START), \
+ S(PR_SWAP_SRC_SNK_TRANSITION_OFF), \
+ S(PR_SWAP_SRC_SNK_SOURCE_OFF), \
+ S(PR_SWAP_SRC_SNK_SINK_ON), \
+ S(PR_SWAP_SNK_SRC_ASSERT_RP), \
+ S(PR_SWAP_SNK_SRC_SINK_OFF), \
+ S(PR_SWAP_SNK_SRC_SOURCE_ON), \
+ \
+ S(VCONN_SWAP_ACCEPT), \
+ S(VCONN_SWAP_SEND), \
+ S(VCONN_SWAP_SEND_TIMEOUT), \
+ S(VCONN_SWAP_CANCEL), \
+ S(VCONN_SWAP_START), \
+ S(VCONN_SWAP_WAIT_FOR_VCONN), \
+ S(VCONN_SWAP_TURN_ON_VCONN), \
+ S(VCONN_SWAP_TURN_OFF_VCONN), \
+ \
+ S(SNK_TRY), \
+ S(SNK_TRY_WAIT), \
+ S(SRC_TRYWAIT), \
+ S(SRC_TRYWAIT_UNATTACHED), \
+ \
+ S(SRC_TRY), \
+ S(SRC_TRY_DEBOUNCE), \
+ S(SNK_TRYWAIT), \
+ S(SNK_TRYWAIT_DEBOUNCE), \
+ S(SNK_TRYWAIT_VBUS), \
+ S(BIST_RX), \
+ \
+ S(ERROR_RECOVERY), \
+ S(ERROR_RECOVERY_WAIT_OFF)
+
+#define GENERATE_ENUM(e) e
+#define GENERATE_STRING(s) #s
+
+enum tcpm_state {
+ FOREACH_STATE(GENERATE_ENUM)
+};
+
+static const char * const tcpm_states[] = {
+ FOREACH_STATE(GENERATE_STRING)
+};
+
+enum vdm_states {
+ VDM_STATE_ERR_BUSY = -3,
+ VDM_STATE_ERR_SEND = -2,
+ VDM_STATE_ERR_TMOUT = -1,
+ VDM_STATE_DONE = 0,
+ /* Anything >0 represents an active state */
+ VDM_STATE_READY = 1,
+ VDM_STATE_BUSY = 2,
+ VDM_STATE_WAIT_RSP_BUSY = 3,
+};
+
+enum pd_msg_request {
+ PD_MSG_NONE = 0,
+ PD_MSG_CTRL_REJECT,
+ PD_MSG_CTRL_WAIT,
+ PD_MSG_DATA_SINK_CAP,
+ PD_MSG_DATA_SOURCE_CAP,
+};
+
+/* Events from low level driver */
+
+#define TCPM_CC_EVENT BIT(0)
+#define TCPM_VBUS_EVENT BIT(1)
+#define TCPM_RESET_EVENT BIT(2)
+#define TCPM_VBUS_LOW_ALARM BIT(3)
+
+#define LOG_BUFFER_ENTRIES 1024
+#define LOG_BUFFER_ENTRY_SIZE 128
+
+/* Alternate mode support */
+
+#define SVID_DISCOVERY_MAX 16
+
+struct pd_mode_data {
+ int svid_index; /* current SVID index */
+ int nsvids;
+ u16 svids[SVID_DISCOVERY_MAX];
+ int altmodes; /* number of alternate modes */
+ struct typec_altmode_desc altmode_desc[SVID_DISCOVERY_MAX];
+};
+
+struct tcpm_port {
+ struct device *dev;
+
+ struct mutex lock; /* tcpm state machine lock */
+ struct workqueue_struct *wq;
+
+ struct typec_capability typec_caps;
+ struct typec_port *typec_port;
+
+ struct tcpc_dev *tcpc;
+
+ enum typec_role vconn_role;
+ enum typec_role pwr_role;
+ enum typec_data_role data_role;
+ enum typec_pwr_opmode pwr_opmode;
+
+ struct usb_pd_identity partner_ident;
+ struct typec_partner_desc partner_desc;
+ struct typec_partner *partner;
+
+ enum typec_cc_status cc_req;
+
+ enum typec_cc_status cc1;
+ enum typec_cc_status cc2;
+ enum typec_cc_polarity polarity;
+
+ bool attached;
+ bool connected;
+ bool vbus_present;
+ bool vbus_never_low;
+ bool vbus_source;
+ bool vbus_charge;
+
+ bool send_discover;
+ bool op_vsafe5v;
+
+ int try_role;
+ int try_snk_count;
+ int try_src_count;
+
+ enum pd_msg_request queued_message;
+
+ enum tcpm_state enter_state;
+ enum tcpm_state prev_state;
+ enum tcpm_state state;
+ enum tcpm_state delayed_state;
+ unsigned long delayed_runtime;
+ unsigned long delay_ms;
+
+ spinlock_t pd_event_lock;
+ u32 pd_events;
+
+ struct work_struct event_work;
+ struct delayed_work state_machine;
+ struct delayed_work vdm_state_machine;
+ bool state_machine_running;
+
+ struct completion tx_complete;
+ enum tcpm_transmit_status tx_status;
+
+ struct mutex swap_lock; /* swap command lock */
+ bool swap_pending;
+ struct completion swap_complete;
+ int swap_status;
+
+ unsigned int message_id;
+ unsigned int caps_count;
+ unsigned int hard_reset_count;
+ bool pd_capable;
+ bool explicit_contract;
+
+ /* Partner capabilities/requests */
+ u32 sink_request;
+ u32 source_caps[PDO_MAX_OBJECTS];
+ unsigned int nr_source_caps;
+ u32 sink_caps[PDO_MAX_OBJECTS];
+ unsigned int nr_sink_caps;
+
+ /* Local capabilities */
+ u32 src_pdo[PDO_MAX_OBJECTS];
+ unsigned int nr_src_pdo;
+ u32 snk_pdo[PDO_MAX_OBJECTS];
+ unsigned int nr_snk_pdo;
+
+ unsigned int max_snk_mv;
+ unsigned int max_snk_ma;
+ unsigned int max_snk_mw;
+ unsigned int operating_snk_mw;
+
+ /* Requested current / voltage */
+ u32 current_limit;
+ u32 supply_voltage;
+
+ u32 bist_request;
+
+ /* PD state for Vendor Defined Messages */
+ enum vdm_states vdm_state;
+ u32 vdm_retries;
+ /* next Vendor Defined Message to send */
+ u32 vdo_data[VDO_MAX_SIZE];
+ u8 vdo_count;
+ /* VDO to retry if UFP responder replied busy */
+ u32 vdo_retry;
+
+ /* Alternate mode data */
+
+ struct pd_mode_data mode_data;
+ struct typec_altmode *partner_altmode[SVID_DISCOVERY_MAX];
+ struct typec_altmode *port_altmode[SVID_DISCOVERY_MAX];
+
+ /* Send response timer */
+ struct hrtimer snd_res_timer;
+ struct pm_qos_request pm_qos_req;
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dentry;
+ struct mutex logbuffer_lock; /* log buffer access lock */
+ int logbuffer_head;
+ int logbuffer_tail;
+ u8 *logbuffer[LOG_BUFFER_ENTRIES];
+#endif
+};
+
+struct pd_rx_event {
+ struct work_struct work;
+ struct tcpm_port *port;
+ struct pd_message msg;
+};
+
+#define tcpm_cc_is_sink(cc) \
+ ((cc) == TYPEC_CC_RP_DEF || (cc) == TYPEC_CC_RP_1_5 || \
+ (cc) == TYPEC_CC_RP_3_0)
+
+#define tcpm_port_is_sink(port) \
+ ((tcpm_cc_is_sink((port)->cc1) && !tcpm_cc_is_sink((port)->cc2)) || \
+ (tcpm_cc_is_sink((port)->cc2) && !tcpm_cc_is_sink((port)->cc1)))
+
+#define tcpm_cc_is_source(cc) ((cc) == TYPEC_CC_RD)
+#define tcpm_cc_is_audio(cc) ((cc) == TYPEC_CC_RA)
+#define tcpm_cc_is_open(cc) ((cc) == TYPEC_CC_OPEN)
+
+#define tcpm_port_is_source(port) \
+ ((tcpm_cc_is_source((port)->cc1) && \
+ !tcpm_cc_is_source((port)->cc2)) || \
+ (tcpm_cc_is_source((port)->cc2) && \
+ !tcpm_cc_is_source((port)->cc1)))
+
+#define tcpm_port_is_debug(port) \
+ (tcpm_cc_is_source((port)->cc1) && tcpm_cc_is_source((port)->cc2))
+
+#define tcpm_port_is_audio(port) \
+ (tcpm_cc_is_audio((port)->cc1) && tcpm_cc_is_audio((port)->cc2))
+
+#define tcpm_port_is_audio_detached(port) \
+ ((tcpm_cc_is_audio((port)->cc1) && tcpm_cc_is_open((port)->cc2)) || \
+ (tcpm_cc_is_audio((port)->cc2) && tcpm_cc_is_open((port)->cc1)))
+
+#define tcpm_try_snk(port) \
+ ((port)->try_snk_count == 0 && (port)->try_role == TYPEC_SINK)
+
+#define tcpm_try_src(port) \
+ ((port)->try_src_count == 0 && (port)->try_role == TYPEC_SOURCE)
+
+static enum tcpm_state tcpm_default_state(struct tcpm_port *port)
+{
+ if (port->typec_caps.type == TYPEC_PORT_DRP) {
+ if (port->try_role == TYPEC_SINK)
+ return SNK_UNATTACHED;
+ else if (port->try_role == TYPEC_SOURCE)
+ return SRC_UNATTACHED;
+ else if (port->tcpc->config->default_role == TYPEC_SINK)
+ return SNK_UNATTACHED;
+ /* Fall through to return SRC_UNATTACHED */
+ } else if (port->typec_caps.type == TYPEC_PORT_UFP) {
+ return SNK_UNATTACHED;
+ }
+ return SRC_UNATTACHED;
+}
+
+static inline
+struct tcpm_port *typec_cap_to_tcpm(const struct typec_capability *cap)
+{
+ return container_of(cap, struct tcpm_port, typec_caps);
+}
+
+static bool tcpm_port_is_disconnected(struct tcpm_port *port)
+{
+ return (!port->attached && port->cc1 == TYPEC_CC_OPEN &&
+ port->cc2 == TYPEC_CC_OPEN) ||
+ (port->attached && ((port->polarity == TYPEC_POLARITY_CC1 &&
+ port->cc1 == TYPEC_CC_OPEN) ||
+ (port->polarity == TYPEC_POLARITY_CC2 &&
+ port->cc2 == TYPEC_CC_OPEN)));
+}
+
+/*
+ * Logging
+ */
+
+#ifdef CONFIG_DEBUG_FS
+
+static bool tcpm_log_full(struct tcpm_port *port)
+{
+ return port->logbuffer_tail ==
+ (port->logbuffer_head + 1) % LOG_BUFFER_ENTRIES;
+}
+
+static void _tcpm_log(struct tcpm_port *port, const char *fmt, va_list args)
+{
+ char tmpbuffer[LOG_BUFFER_ENTRY_SIZE];
+ u64 ts_nsec = local_clock();
+ unsigned long rem_nsec;
+
+ if (!port->logbuffer[port->logbuffer_head]) {
+ port->logbuffer[port->logbuffer_head] =
+ kzalloc(LOG_BUFFER_ENTRY_SIZE, GFP_KERNEL);
+ if (!port->logbuffer[port->logbuffer_head])
+ return;
+ }
+
+ vsnprintf(tmpbuffer, sizeof(tmpbuffer), fmt, args);
+
+ mutex_lock(&port->logbuffer_lock);
+
+ if (tcpm_log_full(port)) {
+ port->logbuffer_head = max(port->logbuffer_head - 1, 0);
+ strcpy(tmpbuffer, "overflow");
+ }
+
+ if (port->logbuffer_head < 0 ||
+ port->logbuffer_head >= LOG_BUFFER_ENTRIES) {
+ dev_warn(port->dev,
+ "Bad log buffer index %d\n", port->logbuffer_head);
+ goto abort;
+ }
+
+ if (!port->logbuffer[port->logbuffer_head]) {
+ dev_warn(port->dev,
+ "Log buffer index %d is NULL\n", port->logbuffer_head);
+ goto abort;
+ }
+
+ rem_nsec = do_div(ts_nsec, 1000000000);
+ scnprintf(port->logbuffer[port->logbuffer_head],
+ LOG_BUFFER_ENTRY_SIZE, "[%5lu.%06lu] %s",
+ (unsigned long)ts_nsec, rem_nsec / 1000,
+ tmpbuffer);
+ port->logbuffer_head = (port->logbuffer_head + 1) % LOG_BUFFER_ENTRIES;
+
+abort:
+ mutex_unlock(&port->logbuffer_lock);
+}
+
+static void tcpm_log(struct tcpm_port *port, const char *fmt, ...)
+{
+ va_list args;
+
+ /* Do not log while disconnected and unattached */
+ if (tcpm_port_is_disconnected(port) &&
+ (port->state == SRC_UNATTACHED || port->state == SNK_UNATTACHED ||
+ port->state == DRP_TOGGLING))
+ return;
+
+ va_start(args, fmt);
+ _tcpm_log(port, fmt, args);
+ va_end(args);
+}
+
+static void tcpm_log_force(struct tcpm_port *port, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ _tcpm_log(port, fmt, args);
+ va_end(args);
+}
+
+static void tcpm_log_source_caps(struct tcpm_port *port)
+{
+ int i;
+
+ for (i = 0; i < port->nr_source_caps; i++) {
+ u32 pdo = port->source_caps[i];
+ enum pd_pdo_type type = pdo_type(pdo);
+ char msg[64];
+
+ switch (type) {
+ case PDO_TYPE_FIXED:
+ scnprintf(msg, sizeof(msg),
+ "%u mV, %u mA [%s%s%s%s%s%s]",
+ pdo_fixed_voltage(pdo),
+ pdo_max_current(pdo),
+ (pdo & PDO_FIXED_DUAL_ROLE) ?
+ "R" : "",
+ (pdo & PDO_FIXED_SUSPEND) ?
+ "S" : "",
+ (pdo & PDO_FIXED_HIGHER_CAP) ?
+ "H" : "",
+ (pdo & PDO_FIXED_USB_COMM) ?
+ "U" : "",
+ (pdo & PDO_FIXED_DATA_SWAP) ?
+ "D" : "",
+ (pdo & PDO_FIXED_EXTPOWER) ?
+ "E" : "");
+ break;
+ case PDO_TYPE_VAR:
+ scnprintf(msg, sizeof(msg),
+ "%u-%u mV, %u mA",
+ pdo_min_voltage(pdo),
+ pdo_max_voltage(pdo),
+ pdo_max_current(pdo));
+ break;
+ case PDO_TYPE_BATT:
+ scnprintf(msg, sizeof(msg),
+ "%u-%u mV, %u mW",
+ pdo_min_voltage(pdo),
+ pdo_max_voltage(pdo),
+ pdo_max_power(pdo));
+ break;
+ default:
+ strcpy(msg, "undefined");
+ break;
+ }
+ tcpm_log(port, " PDO %d: type %d, %s",
+ i, type, msg);
+ }
+}
+
+static int tcpm_seq_show(struct seq_file *s, void *v)
+{
+ struct tcpm_port *port = (struct tcpm_port *)s->private;
+ int tail;
+
+ mutex_lock(&port->logbuffer_lock);
+ tail = port->logbuffer_tail;
+ while (tail != port->logbuffer_head) {
+ seq_printf(s, "%s\n", port->logbuffer[tail]);
+ tail = (tail + 1) % LOG_BUFFER_ENTRIES;
+ }
+ if (!seq_has_overflowed(s))
+ port->logbuffer_tail = tail;
+ mutex_unlock(&port->logbuffer_lock);
+
+ return 0;
+}
+
+static int tcpm_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, tcpm_seq_show, inode->i_private);
+}
+
+static const struct file_operations tcpm_debug_operations = {
+ .open = tcpm_debug_open,
+ .llseek = seq_lseek,
+ .read = seq_read,
+ .release = single_release,
+};
+
+static struct dentry *rootdir;
+
+static int tcpm_debugfs_init(struct tcpm_port *port)
+{
+ mutex_init(&port->logbuffer_lock);
+ /* /sys/kernel/debug/tcpm/usbcX */
+ if (!rootdir) {
+ rootdir = debugfs_create_dir("tcpm", NULL);
+ if (!rootdir)
+ return -ENOMEM;
+ }
+
+ port->dentry = debugfs_create_file(dev_name(port->dev),
+ S_IFREG | 0444, rootdir,
+ port, &tcpm_debug_operations);
+
+ return 0;
+}
+
+static void tcpm_debugfs_exit(struct tcpm_port *port)
+{
+ debugfs_remove(port->dentry);
+}
+
+#else
+
+static void tcpm_log(const struct tcpm_port *port, const char *fmt, ...) { }
+static void tcpm_log_force(struct tcpm_port *port, const char *fmt, ...) { }
+static void tcpm_log_source_caps(struct tcpm_port *port) { }
+static int tcpm_debugfs_init(const struct tcpm_port *port) { return 0; }
+static void tcpm_debugfs_exit(const struct tcpm_port *port) { }
+
+#endif
+
+static int tcpm_pd_transmit(struct tcpm_port *port,
+ enum tcpm_transmit_type type,
+ const struct pd_message *msg)
+{
+ unsigned long timeout;
+ int ret;
+
+ if (msg)
+ tcpm_log(port, "PD TX, header: %#x", le16_to_cpu(msg->header));
+ else
+ tcpm_log(port, "PD TX, type: %#x", type);
+
+ reinit_completion(&port->tx_complete);
+ ret = port->tcpc->pd_transmit(port->tcpc, type, msg);
+ if (ret < 0)
+ return ret;
+
+ mutex_unlock(&port->lock);
+ timeout = wait_for_completion_timeout(&port->tx_complete,
+ msecs_to_jiffies(PD_T_TCPC_TX_TIMEOUT));
+ mutex_lock(&port->lock);
+ if (!timeout)
+ return -ETIMEDOUT;
+
+ switch (port->tx_status) {
+ case TCPC_TX_SUCCESS:
+ port->message_id = (port->message_id + 1) & PD_HEADER_ID_MASK;
+ return 0;
+ case TCPC_TX_DISCARDED:
+ return -EAGAIN;
+ case TCPC_TX_FAILED:
+ default:
+ return -EIO;
+ }
+}
+
+void tcpm_pd_transmit_complete(struct tcpm_port *port,
+ enum tcpm_transmit_status status)
+{
+ tcpm_log(port, "PD TX complete, status: %u", status);
+ port->tx_status = status;
+ complete(&port->tx_complete);
+}
+EXPORT_SYMBOL_GPL(tcpm_pd_transmit_complete);
+
+static int tcpm_mux_set(struct tcpm_port *port, enum tcpc_mux_mode mode,
+ enum tcpc_usb_switch config)
+{
+ int ret = 0;
+
+ tcpm_log(port, "Requesting mux mode %d, config %d, polarity %d",
+ mode, config, port->polarity);
+
+ if (port->tcpc->mux)
+ ret = port->tcpc->mux->set(port->tcpc->mux, mode, config,
+ port->polarity);
+
+ return ret;
+}
+
+static int tcpm_set_polarity(struct tcpm_port *port,
+ enum typec_cc_polarity polarity)
+{
+ int ret;
+
+ tcpm_log(port, "polarity %d", polarity);
+
+ ret = port->tcpc->set_polarity(port->tcpc, polarity);
+ if (ret < 0)
+ return ret;
+
+ port->polarity = polarity;
+
+ return 0;
+}
+
+static int tcpm_set_vconn(struct tcpm_port *port, bool enable)
+{
+ int ret;
+
+ tcpm_log(port, "vconn:=%d", enable);
+
+ ret = port->tcpc->set_vconn(port->tcpc, enable);
+ if (!ret) {
+ port->vconn_role = enable ? TYPEC_SOURCE : TYPEC_SINK;
+ typec_set_vconn_role(port->typec_port, port->vconn_role);
+ }
+
+ return ret;
+}
+
+static u32 tcpm_get_current_limit(struct tcpm_port *port)
+{
+ enum typec_cc_status cc;
+ u32 limit;
+
+ cc = port->polarity ? port->cc2 : port->cc1;
+ switch (cc) {
+ case TYPEC_CC_RP_1_5:
+ limit = 1500;
+ break;
+ case TYPEC_CC_RP_3_0:
+ limit = 3000;
+ break;
+ case TYPEC_CC_RP_DEF:
+ default:
+ limit = 0;
+ break;
+ }
+
+ return limit;
+}
+
+static int tcpm_set_current_limit(struct tcpm_port *port, u32 max_ma, u32 mv)
+{
+ int ret = -EOPNOTSUPP;
+
+ tcpm_log(port, "Setting voltage/current limit %u mV %u mA", mv, max_ma);
+
+ if (port->tcpc->set_current_limit)
+ ret = port->tcpc->set_current_limit(port->tcpc, max_ma, mv);
+
+ return ret;
+}
+
+/*
+ * Determine RP value to set based on maximum current supported
+ * by a port if configured as source.
+ * Returns CC value to report to link partner.
+ */
+static enum typec_cc_status tcpm_rp_cc(struct tcpm_port *port)
+{
+ const u32 *src_pdo = port->src_pdo;
+ int nr_pdo = port->nr_src_pdo;
+ int i;
+
+ /*
+ * Search for first entry with matching voltage.
+ * It should report the maximum supported current.
+ */
+ for (i = 0; i < nr_pdo; i++) {
+ const u32 pdo = src_pdo[i];
+
+ if (pdo_type(pdo) == PDO_TYPE_FIXED &&
+ pdo_fixed_voltage(pdo) == 5000) {
+ unsigned int curr = pdo_max_current(pdo);
+
+ if (curr >= 3000)
+ return TYPEC_CC_RP_3_0;
+ else if (curr >= 1500)
+ return TYPEC_CC_RP_1_5;
+ return TYPEC_CC_RP_DEF;
+ }
+ }
+
+ return TYPEC_CC_RP_DEF;
+}
+
+static int tcpm_set_attached_state(struct tcpm_port *port, bool attached)
+{
+ return port->tcpc->set_roles(port->tcpc, attached, port->pwr_role,
+ port->data_role);
+}
+
+static int tcpm_set_roles(struct tcpm_port *port, bool attached,
+ enum typec_role role, enum typec_data_role data)
+{
+ int ret;
+
+ if (data == TYPEC_HOST)
+ ret = tcpm_mux_set(port, TYPEC_MUX_USB,
+ TCPC_USB_SWITCH_CONNECT);
+ else
+ ret = tcpm_mux_set(port, TYPEC_MUX_NONE,
+ TCPC_USB_SWITCH_DISCONNECT);
+ if (ret < 0)
+ return ret;
+
+ ret = port->tcpc->set_roles(port->tcpc, attached, role, data);
+ if (ret < 0)
+ return ret;
+
+ port->pwr_role = role;
+ port->data_role = data;
+ typec_set_data_role(port->typec_port, data);
+ typec_set_pwr_role(port->typec_port, role);
+
+ return 0;
+}
+
+static int tcpm_set_pwr_role(struct tcpm_port *port, enum typec_role role)
+{
+ int ret;
+
+ ret = port->tcpc->set_roles(port->tcpc, true, role,
+ port->data_role);
+ if (ret < 0)
+ return ret;
+
+ port->pwr_role = role;
+ typec_set_pwr_role(port->typec_port, role);
+
+ return 0;
+}
+
+static int tcpm_pd_send_source_caps(struct tcpm_port *port)
+{
+ struct pd_message msg;
+ int i;
+
+ memset(&msg, 0, sizeof(msg));
+ if (!port->nr_src_pdo) {
+ /* No source capabilities defined, sink only */
+ msg.header = PD_HEADER_LE(PD_CTRL_REJECT,
+ port->pwr_role,
+ port->data_role,
+ port->message_id, 0);
+ } else {
+ msg.header = PD_HEADER_LE(PD_DATA_SOURCE_CAP,
+ port->pwr_role,
+ port->data_role,
+ port->message_id,
+ port->nr_src_pdo);
+ }
+ for (i = 0; i < port->nr_src_pdo; i++)
+ msg.payload[i] = cpu_to_le32(port->src_pdo[i]);
+
+ return tcpm_pd_transmit(port, TCPC_TX_SOP, &msg);
+}
+
+static int tcpm_pd_send_sink_caps(struct tcpm_port *port)
+{
+ struct pd_message msg;
+ int i;
+
+ memset(&msg, 0, sizeof(msg));
+ if (!port->nr_snk_pdo) {
+ /* No sink capabilities defined, source only */
+ msg.header = PD_HEADER_LE(PD_CTRL_REJECT,
+ port->pwr_role,
+ port->data_role,
+ port->message_id, 0);
+ } else {
+ msg.header = PD_HEADER_LE(PD_DATA_SINK_CAP,
+ port->pwr_role,
+ port->data_role,
+ port->message_id,
+ port->nr_snk_pdo);
+ }
+ for (i = 0; i < port->nr_snk_pdo; i++)
+ msg.payload[i] = cpu_to_le32(port->snk_pdo[i]);
+
+ return tcpm_pd_transmit(port, TCPC_TX_SOP, &msg);
+}
+
+static void tcpm_qos_handling(struct tcpm_port *port)
+{
+ enum tcpm_state idle_state;
+
+ if (port->typec_caps.type == TYPEC_PORT_UFP)
+ idle_state = SNK_UNATTACHED;
+ else if (port->typec_caps.type == TYPEC_PORT_DFP)
+ idle_state = SNK_UNATTACHED;
+ else if (port->typec_caps.type == TYPEC_PORT_DRP)
+ idle_state = DRP_TOGGLING;
+ else
+ return;
+
+ if ((port->prev_state == SNK_READY || port->prev_state == SRC_READY ||
+ port->prev_state == idle_state)) {
+ /* Hold high bus before leave those states */
+ request_bus_freq(BUS_FREQ_HIGH);
+ pm_qos_add_request(&port->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, 0);
+ } else if ((port->state == SNK_READY || port->state == SRC_READY ||
+ port->state == idle_state)) {
+ /* Release high bus after enter those states */
+ pm_qos_remove_request(&port->pm_qos_req);
+ release_bus_freq(BUS_FREQ_HIGH);
+ }
+}
+
+static void tcpm_set_state(struct tcpm_port *port, enum tcpm_state state,
+ unsigned int delay_ms)
+{
+ if (delay_ms) {
+ tcpm_log(port, "pending state change %s -> %s @ %u ms",
+ tcpm_states[port->state], tcpm_states[state],
+ delay_ms);
+ port->delayed_state = state;
+ mod_delayed_work(port->wq, &port->state_machine,
+ msecs_to_jiffies(delay_ms));
+ port->delayed_runtime = jiffies + msecs_to_jiffies(delay_ms);
+ port->delay_ms = delay_ms;
+ } else {
+ tcpm_log(port, "state change %s -> %s",
+ tcpm_states[port->state], tcpm_states[state]);
+ port->delayed_state = INVALID_STATE;
+ port->prev_state = port->state;
+ port->state = state;
+ tcpm_qos_handling(port);
+ /*
+ * Don't re-queue the state machine work item if we're currently
+ * in the state machine and we're immediately changing states.
+ * tcpm_state_machine_work() will continue running the state
+ * machine.
+ */
+ if (!port->state_machine_running)
+ mod_delayed_work(port->wq, &port->state_machine, 0);
+ }
+}
+
+static void tcpm_set_state_cond(struct tcpm_port *port, enum tcpm_state state,
+ unsigned int delay_ms)
+{
+ if (port->enter_state == port->state)
+ tcpm_set_state(port, state, delay_ms);
+ else
+ tcpm_log(port,
+ "skipped %sstate change %s -> %s [%u ms], context state %s",
+ delay_ms ? "delayed " : "",
+ tcpm_states[port->state], tcpm_states[state],
+ delay_ms, tcpm_states[port->enter_state]);
+}
+
+static void tcpm_queue_message(struct tcpm_port *port,
+ enum pd_msg_request message)
+{
+ port->queued_message = message;
+ mod_delayed_work(port->wq, &port->state_machine, 0);
+}
+
+/*
+ * VDM/VDO handling functions
+ */
+static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header,
+ const u32 *data, int cnt)
+{
+ port->vdo_count = cnt + 1;
+ port->vdo_data[0] = header;
+ memcpy(&port->vdo_data[1], data, sizeof(u32) * cnt);
+ /* Set ready, vdm state machine will actually send */
+ port->vdm_retries = 0;
+ port->vdm_state = VDM_STATE_READY;
+}
+
+static void svdm_consume_identity(struct tcpm_port *port, const __le32 *payload,
+ int cnt)
+{
+ u32 vdo = le32_to_cpu(payload[VDO_INDEX_IDH]);
+ u32 product = le32_to_cpu(payload[VDO_INDEX_PRODUCT]);
+
+ memset(&port->mode_data, 0, sizeof(port->mode_data));
+
+#if 0 /* Not really a match */
+ switch (PD_IDH_PTYPE(vdo)) {
+ case IDH_PTYPE_UNDEF:
+ port->partner.type = TYPEC_PARTNER_NONE; /* no longer exists */
+ break;
+ case IDH_PTYPE_HUB:
+ break;
+ case IDH_PTYPE_PERIPH:
+ break;
+ case IDH_PTYPE_PCABLE:
+ break;
+ case IDH_PTYPE_ACABLE:
+ break;
+ case IDH_PTYPE_AMA:
+ port->partner.type = TYPEC_PARTNER_ALTMODE;
+ break;
+ default:
+ break;
+ }
+#endif
+
+ port->partner_ident.id_header = vdo;
+ port->partner_ident.cert_stat = le32_to_cpu(payload[VDO_INDEX_CSTAT]);
+ port->partner_ident.product = product;
+
+ typec_partner_set_identity(port->partner);
+
+ tcpm_log(port, "Identity: %04x:%04x.%04x",
+ PD_IDH_VID(vdo),
+ PD_PRODUCT_PID(product), product & 0xffff);
+}
+
+static bool svdm_consume_svids(struct tcpm_port *port, const __le32 *payload,
+ int cnt)
+{
+ struct pd_mode_data *pmdata = &port->mode_data;
+ int i;
+
+ for (i = 1; i < cnt; i++) {
+ u32 p = le32_to_cpu(payload[i]);
+ u16 svid;
+
+ svid = (p >> 16) & 0xffff;
+ if (!svid)
+ return false;
+
+ if (pmdata->nsvids >= SVID_DISCOVERY_MAX)
+ goto abort;
+
+ pmdata->svids[pmdata->nsvids++] = svid;
+ tcpm_log(port, "SVID %d: 0x%x", pmdata->nsvids, svid);
+
+ svid = p & 0xffff;
+ if (!svid)
+ return false;
+
+ if (pmdata->nsvids >= SVID_DISCOVERY_MAX)
+ goto abort;
+
+ pmdata->svids[pmdata->nsvids++] = svid;
+ tcpm_log(port, "SVID %d: 0x%x", pmdata->nsvids, svid);
+ }
+ return true;
+abort:
+ tcpm_log(port, "SVID_DISCOVERY_MAX(%d) too low!", SVID_DISCOVERY_MAX);
+ return false;
+}
+
+static void svdm_consume_modes(struct tcpm_port *port, const __le32 *payload,
+ int cnt)
+{
+ struct pd_mode_data *pmdata = &port->mode_data;
+ struct typec_altmode_desc *paltmode;
+ struct typec_mode_desc *pmode;
+ int i;
+
+ if (pmdata->altmodes >= ARRAY_SIZE(port->partner_altmode)) {
+ /* Already logged in svdm_consume_svids() */
+ return;
+ }
+
+ paltmode = &pmdata->altmode_desc[pmdata->altmodes];
+ memset(paltmode, 0, sizeof(*paltmode));
+
+ paltmode->svid = pmdata->svids[pmdata->svid_index];
+
+ tcpm_log(port, " Alternate mode %d: SVID 0x%04x",
+ pmdata->altmodes, paltmode->svid);
+
+ for (i = 1; i < cnt && paltmode->n_modes < ALTMODE_MAX_MODES; i++) {
+ pmode = &paltmode->modes[paltmode->n_modes];
+ memset(pmode, 0, sizeof(*pmode));
+ pmode->vdo = le32_to_cpu(payload[i]);
+ pmode->index = i - 1;
+ paltmode->n_modes++;
+ tcpm_log(port, " VDO %d: 0x%08x",
+ pmode->index, pmode->vdo);
+ }
+ port->partner_altmode[pmdata->altmodes] =
+ typec_partner_register_altmode(port->partner, paltmode);
+ if (port->partner_altmode[pmdata->altmodes] == NULL) {
+ tcpm_log(port,
+ "Failed to register alternate modes for SVID 0x%04x",
+ paltmode->svid);
+ return;
+ }
+ pmdata->altmodes++;
+}
+
+#define supports_modal(port) PD_IDH_MODAL_SUPP((port)->partner_ident.id_header)
+
+static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt,
+ u32 *response)
+{
+ u32 p0 = le32_to_cpu(payload[0]);
+ int cmd_type = PD_VDO_CMDT(p0);
+ int cmd = PD_VDO_CMD(p0);
+ struct pd_mode_data *modep;
+ int rlen = 0;
+ u16 svid;
+
+ tcpm_log(port, "Rx VDM cmd 0x%x type %d cmd %d len %d",
+ p0, cmd_type, cmd, cnt);
+
+ modep = &port->mode_data;
+
+ switch (cmd_type) {
+ case CMDT_INIT:
+ switch (cmd) {
+ case CMD_DISCOVER_IDENT:
+ break;
+ case CMD_DISCOVER_SVID:
+ break;
+ case CMD_DISCOVER_MODES:
+ break;
+ case CMD_ENTER_MODE:
+ break;
+ case CMD_EXIT_MODE:
+ break;
+ case CMD_ATTENTION:
+ break;
+ default:
+ break;
+ }
+ if (rlen >= 1) {
+ response[0] = p0 | VDO_CMDT(CMDT_RSP_ACK);
+ } else if (rlen == 0) {
+ response[0] = p0 | VDO_CMDT(CMDT_RSP_NAK);
+ rlen = 1;
+ } else {
+ response[0] = p0 | VDO_CMDT(CMDT_RSP_BUSY);
+ rlen = 1;
+ }
+ break;
+ case CMDT_RSP_ACK:
+ /* silently drop message if we are not connected */
+ if (!port->partner)
+ break;
+
+ switch (cmd) {
+ case CMD_DISCOVER_IDENT:
+ /* 6.4.4.3.1 */
+ svdm_consume_identity(port, payload, cnt);
+ response[0] = VDO(USB_SID_PD, 1, CMD_DISCOVER_SVID);
+ rlen = 1;
+ break;
+ case CMD_DISCOVER_SVID:
+ /* 6.4.4.3.2 */
+ if (svdm_consume_svids(port, payload, cnt)) {
+ response[0] = VDO(USB_SID_PD, 1,
+ CMD_DISCOVER_SVID);
+ rlen = 1;
+ } else if (modep->nsvids && supports_modal(port)) {
+ response[0] = VDO(modep->svids[0], 1,
+ CMD_DISCOVER_MODES);
+ rlen = 1;
+ }
+ break;
+ case CMD_DISCOVER_MODES:
+ /* 6.4.4.3.3 */
+ svdm_consume_modes(port, payload, cnt);
+ modep->svid_index++;
+ if (modep->svid_index < modep->nsvids) {
+ svid = modep->svids[modep->svid_index];
+ response[0] = VDO(svid, 1, CMD_DISCOVER_MODES);
+ rlen = 1;
+ } else {
+#if 0
+ response[0] = pd_dfp_enter_mode(port, 0, 0);
+ if (response[0])
+ rlen = 1;
+#endif
+ }
+ break;
+ case CMD_ENTER_MODE:
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return rlen;
+}
+
+static void tcpm_handle_vdm_request(struct tcpm_port *port,
+ const __le32 *payload, int cnt)
+{
+ int rlen = 0;
+ u32 response[8] = { };
+ u32 p0 = le32_to_cpu(payload[0]);
+
+ if (port->vdm_state == VDM_STATE_BUSY) {
+ /* If UFP responded busy retry after timeout */
+ if (PD_VDO_CMDT(p0) == CMDT_RSP_BUSY) {
+ port->vdm_state = VDM_STATE_WAIT_RSP_BUSY;
+ port->vdo_retry = (p0 & ~VDO_CMDT_MASK) |
+ CMDT_INIT;
+ mod_delayed_work(port->wq, &port->vdm_state_machine,
+ msecs_to_jiffies(PD_T_VDM_BUSY));
+ return;
+ }
+ port->vdm_state = VDM_STATE_DONE;
+ }
+
+ if (PD_VDO_SVDM(p0))
+ rlen = tcpm_pd_svdm(port, payload, cnt, response);
+#if 0
+ else
+ rlen = tcpm_pd_custom_vdm(port, cnt, payload, response);
+#endif
+
+ if (rlen > 0) {
+ tcpm_queue_vdm(port, response[0], &response[1], rlen - 1);
+ mod_delayed_work(port->wq, &port->vdm_state_machine, 0);
+ }
+}
+
+static void tcpm_send_vdm(struct tcpm_port *port, u32 vid, int cmd,
+ const u32 *data, int count)
+{
+ u32 header;
+
+ if (WARN_ON(count > VDO_MAX_SIZE - 1))
+ count = VDO_MAX_SIZE - 1;
+
+ /* set VDM header with VID & CMD */
+ header = VDO(vid, ((vid & USB_SID_PD) == USB_SID_PD) ?
+ 1 : (PD_VDO_CMD(cmd) <= CMD_ATTENTION), cmd);
+ tcpm_queue_vdm(port, header, data, count);
+
+ mod_delayed_work(port->wq, &port->vdm_state_machine, 0);
+}
+
+static unsigned int vdm_ready_timeout(u32 vdm_hdr)
+{
+ unsigned int timeout;
+ int cmd = PD_VDO_CMD(vdm_hdr);
+
+ /* its not a structured VDM command */
+ if (!PD_VDO_SVDM(vdm_hdr))
+ return PD_T_VDM_UNSTRUCTURED;
+
+ switch (PD_VDO_CMDT(vdm_hdr)) {
+ case CMDT_INIT:
+ if (cmd == CMD_ENTER_MODE || cmd == CMD_EXIT_MODE)
+ timeout = PD_T_VDM_WAIT_MODE_E;
+ else
+ timeout = PD_T_VDM_SNDR_RSP;
+ break;
+ default:
+ if (cmd == CMD_ENTER_MODE || cmd == CMD_EXIT_MODE)
+ timeout = PD_T_VDM_E_MODE;
+ else
+ timeout = PD_T_VDM_RCVR_RSP;
+ break;
+ }
+ return timeout;
+}
+
+static void vdm_run_state_machine(struct tcpm_port *port)
+{
+ struct pd_message msg;
+ int i, res;
+
+ switch (port->vdm_state) {
+ case VDM_STATE_READY:
+ /* Only transmit VDM if attached */
+ if (!port->attached) {
+ port->vdm_state = VDM_STATE_ERR_BUSY;
+ break;
+ }
+
+ /*
+ * if there's traffic or we're not in PDO ready state don't send
+ * a VDM.
+ */
+ if (port->state != SRC_READY && port->state != SNK_READY)
+ break;
+
+ /* Prepare and send VDM */
+ memset(&msg, 0, sizeof(msg));
+ msg.header = PD_HEADER_LE(PD_DATA_VENDOR_DEF,
+ port->pwr_role,
+ port->data_role,
+ port->message_id, port->vdo_count);
+ for (i = 0; i < port->vdo_count; i++)
+ msg.payload[i] = cpu_to_le32(port->vdo_data[i]);
+ res = tcpm_pd_transmit(port, TCPC_TX_SOP, &msg);
+ if (res < 0) {
+ port->vdm_state = VDM_STATE_ERR_SEND;
+ } else {
+ unsigned long timeout;
+
+ port->vdm_retries = 0;
+ port->vdm_state = VDM_STATE_BUSY;
+ timeout = vdm_ready_timeout(port->vdo_data[0]);
+ mod_delayed_work(port->wq, &port->vdm_state_machine,
+ timeout);
+ }
+ break;
+ case VDM_STATE_WAIT_RSP_BUSY:
+ port->vdo_data[0] = port->vdo_retry;
+ port->vdo_count = 1;
+ port->vdm_state = VDM_STATE_READY;
+ break;
+ case VDM_STATE_BUSY:
+ port->vdm_state = VDM_STATE_ERR_TMOUT;
+ break;
+ case VDM_STATE_ERR_SEND:
+ /*
+ * A partner which does not support USB PD will not reply,
+ * so this is not a fatal error. At the same time, some
+ * devices may not return GoodCRC under some circumstances,
+ * so we need to retry.
+ */
+ if (port->vdm_retries < 3) {
+ tcpm_log(port, "VDM Tx error, retry");
+ port->vdm_retries++;
+ port->vdm_state = VDM_STATE_READY;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void vdm_state_machine_work(struct work_struct *work)
+{
+ struct tcpm_port *port = container_of(work, struct tcpm_port,
+ vdm_state_machine.work);
+ enum vdm_states prev_state;
+
+ mutex_lock(&port->lock);
+
+ /*
+ * Continue running as long as the port is not busy and there was
+ * a state change.
+ */
+ do {
+ prev_state = port->vdm_state;
+ vdm_run_state_machine(port);
+ } while (port->vdm_state != prev_state &&
+ port->vdm_state != VDM_STATE_BUSY);
+
+ mutex_unlock(&port->lock);
+}
+
+/*
+ * PD (data, control) command handling functions
+ */
+static void tcpm_pd_data_request(struct tcpm_port *port,
+ const struct pd_message *msg)
+{
+ enum pd_data_msg_type type = pd_header_type_le(msg->header);
+ unsigned int cnt = pd_header_cnt_le(msg->header);
+ unsigned int i;
+
+ switch (type) {
+ case PD_DATA_SOURCE_CAP:
+ if (port->pwr_role != TYPEC_SINK)
+ break;
+
+ for (i = 0; i < cnt; i++)
+ port->source_caps[i] = le32_to_cpu(msg->payload[i]);
+
+ port->nr_source_caps = cnt;
+
+ tcpm_log_source_caps(port);
+
+ /*
+ * This message may be received even if VBUS is not
+ * present. This is quite unexpected; see USB PD
+ * specification, sections 8.3.3.6.3.1 and 8.3.3.6.3.2.
+ * However, at the same time, we must be ready to
+ * receive this message and respond to it 15ms after
+ * receiving PS_RDY during power swap operations, no matter
+ * if VBUS is available or not (USB PD specification,
+ * section 6.5.9.2).
+ * So we need to accept the message either way,
+ * but be prepared to keep waiting for VBUS after it was
+ * handled.
+ */
+ tcpm_set_state(port, SNK_NEGOTIATE_CAPABILITIES, 0);
+ break;
+ case PD_DATA_REQUEST:
+ if (port->pwr_role != TYPEC_SOURCE ||
+ cnt != 1) {
+ tcpm_queue_message(port, PD_MSG_CTRL_REJECT);
+ break;
+ }
+ port->sink_request = le32_to_cpu(msg->payload[0]);
+ hrtimer_cancel(&port->snd_res_timer);
+ tcpm_set_state(port, SRC_NEGOTIATE_CAPABILITIES, 0);
+ break;
+ case PD_DATA_SINK_CAP:
+ /* We don't do anything with this at the moment... */
+ for (i = 0; i < cnt; i++)
+ port->sink_caps[i] = le32_to_cpu(msg->payload[i]);
+ port->nr_sink_caps = cnt;
+ break;
+ case PD_DATA_VENDOR_DEF:
+ tcpm_handle_vdm_request(port, msg->payload, cnt);
+ break;
+ case PD_DATA_BIST:
+ if (port->state == SRC_READY || port->state == SNK_READY) {
+ port->bist_request = le32_to_cpu(msg->payload[0]);
+ tcpm_set_state(port, BIST_RX, 0);
+ }
+ break;
+ default:
+ tcpm_log(port, "Unhandled data message type %#x", type);
+ break;
+ }
+}
+
+static void tcpm_pd_ctrl_request(struct tcpm_port *port,
+ const struct pd_message *msg)
+{
+ enum pd_ctrl_msg_type type = pd_header_type_le(msg->header);
+ enum tcpm_state next_state;
+
+ switch (type) {
+ case PD_CTRL_GOOD_CRC:
+ case PD_CTRL_PING:
+ break;
+ case PD_CTRL_GET_SOURCE_CAP:
+ switch (port->state) {
+ case SRC_READY:
+ case SNK_READY:
+ tcpm_queue_message(port, PD_MSG_DATA_SOURCE_CAP);
+ break;
+ default:
+ tcpm_queue_message(port, PD_MSG_CTRL_REJECT);
+ break;
+ }
+ break;
+ case PD_CTRL_GET_SINK_CAP:
+ switch (port->state) {
+ case SRC_READY:
+ case SNK_READY:
+ tcpm_queue_message(port, PD_MSG_DATA_SINK_CAP);
+ break;
+ default:
+ hrtimer_cancel(&port->snd_res_timer);
+ tcpm_set_state(port, SOFT_RESET_SEND, 0);
+ break;
+ }
+ break;
+ case PD_CTRL_GOTO_MIN:
+ break;
+ case PD_CTRL_PS_RDY:
+ switch (port->state) {
+ case SNK_TRANSITION_SINK:
+ if (port->vbus_present) {
+ tcpm_set_current_limit(port,
+ port->current_limit,
+ port->supply_voltage);
+ tcpm_set_state(port, SNK_READY, 0);
+ } else {
+ /*
+ * Seen after power swap. Keep waiting for VBUS
+ * in a transitional state.
+ */
+ tcpm_set_state(port,
+ SNK_TRANSITION_SINK_VBUS, 0);
+ }
+ break;
+ case PR_SWAP_SRC_SNK_SOURCE_OFF:
+ tcpm_set_state(port, PR_SWAP_SRC_SNK_SINK_ON, 0);
+ break;
+ case PR_SWAP_SNK_SRC_SINK_OFF:
+ tcpm_set_state(port, PR_SWAP_SNK_SRC_ASSERT_RP, 0);
+ break;
+ case VCONN_SWAP_WAIT_FOR_VCONN:
+ tcpm_set_state(port, VCONN_SWAP_TURN_OFF_VCONN, 0);
+ break;
+ default:
+ break;
+ }
+ break;
+ case PD_CTRL_REJECT:
+ case PD_CTRL_WAIT:
+ switch (port->state) {
+ case SNK_NEGOTIATE_CAPABILITIES:
+ hrtimer_cancel(&port->snd_res_timer);
+ /* USB PD specification, Figure 8-43 */
+ if (port->explicit_contract)
+ next_state = SNK_READY;
+ else
+ next_state = SNK_WAIT_CAPABILITIES;
+ tcpm_set_state(port, next_state, 0);
+ break;
+ case DR_SWAP_SEND:
+ port->swap_status = (type == PD_CTRL_WAIT ?
+ -EAGAIN : -EOPNOTSUPP);
+ tcpm_set_state(port, DR_SWAP_CANCEL, 0);
+ break;
+ case PR_SWAP_SEND:
+ port->swap_status = (type == PD_CTRL_WAIT ?
+ -EAGAIN : -EOPNOTSUPP);
+ tcpm_set_state(port, PR_SWAP_CANCEL, 0);
+ break;
+ case VCONN_SWAP_SEND:
+ port->swap_status = (type == PD_CTRL_WAIT ?
+ -EAGAIN : -EOPNOTSUPP);
+ tcpm_set_state(port, VCONN_SWAP_CANCEL, 0);
+ break;
+ default:
+ break;
+ }
+ break;
+ case PD_CTRL_ACCEPT:
+ switch (port->state) {
+ case SNK_NEGOTIATE_CAPABILITIES:
+ hrtimer_cancel(&port->snd_res_timer);
+ tcpm_set_state(port, SNK_TRANSITION_SINK, 0);
+ break;
+ case SOFT_RESET_SEND:
+ /*
+ * After reset data sent, the msg id is updated
+ * by pd_transmit(0+1), now the other end gives
+ * an accept so we can go on with msg id 1.
+ */
+ if (port->pwr_role == TYPEC_SOURCE) {
+ next_state = SRC_SEND_CAPABILITIES;
+ } else {
+ port->message_id = 0;
+ next_state = SNK_WAIT_CAPABILITIES;
+ }
+ tcpm_set_state(port, next_state, 0);
+ break;
+ case DR_SWAP_SEND:
+ tcpm_set_state(port, DR_SWAP_CHANGE_DR, 0);
+ break;
+ case PR_SWAP_SEND:
+ tcpm_set_state(port, PR_SWAP_START, 0);
+ break;
+ case VCONN_SWAP_SEND:
+ tcpm_set_state(port, VCONN_SWAP_START, 0);
+ break;
+ default:
+ break;
+ }
+ break;
+ case PD_CTRL_SOFT_RESET:
+ tcpm_set_state(port, SOFT_RESET, 0);
+ break;
+ case PD_CTRL_DR_SWAP:
+ if (port->typec_caps.type != TYPEC_PORT_DRP) {
+ tcpm_queue_message(port, PD_MSG_CTRL_REJECT);
+ break;
+ }
+ /*
+ * XXX
+ * 6.3.9: If an alternate mode is active, a request to swap
+ * alternate modes shall trigger a port reset.
+ */
+ switch (port->state) {
+ case SRC_READY:
+ case SNK_READY:
+ tcpm_set_state(port, DR_SWAP_ACCEPT, 0);
+ break;
+ default:
+ tcpm_queue_message(port, PD_MSG_CTRL_WAIT);
+ break;
+ }
+ break;
+ case PD_CTRL_PR_SWAP:
+ if (port->typec_caps.type != TYPEC_PORT_DRP) {
+ tcpm_queue_message(port, PD_MSG_CTRL_REJECT);
+ break;
+ }
+ switch (port->state) {
+ case SRC_READY:
+ case SNK_READY:
+ tcpm_set_state(port, PR_SWAP_ACCEPT, 0);
+ break;
+ default:
+ tcpm_queue_message(port, PD_MSG_CTRL_WAIT);
+ break;
+ }
+ break;
+ case PD_CTRL_VCONN_SWAP:
+ switch (port->state) {
+ case SRC_READY:
+ case SNK_READY:
+ tcpm_set_state(port, VCONN_SWAP_ACCEPT, 0);
+ break;
+ default:
+ tcpm_queue_message(port, PD_MSG_CTRL_WAIT);
+ break;
+ }
+ break;
+ default:
+ tcpm_log(port, "Unhandled ctrl message type %#x", type);
+ break;
+ }
+}
+
+static void tcpm_pd_rx_handler(struct work_struct *work)
+{
+ struct pd_rx_event *event = container_of(work,
+ struct pd_rx_event, work);
+ const struct pd_message *msg = &event->msg;
+ unsigned int cnt = pd_header_cnt_le(msg->header);
+ struct tcpm_port *port = event->port;
+
+ mutex_lock(&port->lock);
+
+ tcpm_log(port, "PD RX, header: %#x [%d]", le16_to_cpu(msg->header),
+ port->attached);
+
+ if (port->attached) {
+ /*
+ * If both ends believe to be DFP/host, we have a data role
+ * mismatch.
+ */
+ if (!!(le16_to_cpu(msg->header) & PD_HEADER_DATA_ROLE) ==
+ (port->data_role == TYPEC_HOST)) {
+ tcpm_log(port,
+ "Data role mismatch, initiating error recovery");
+ tcpm_set_state(port, ERROR_RECOVERY, 0);
+ } else {
+ if (cnt)
+ tcpm_pd_data_request(port, msg);
+ else
+ tcpm_pd_ctrl_request(port, msg);
+ }
+ }
+
+ mutex_unlock(&port->lock);
+ kfree(event);
+}
+
+void tcpm_pd_receive(struct tcpm_port *port, const struct pd_message *msg)
+{
+ struct pd_rx_event *event;
+
+ event = kzalloc(sizeof(*event), GFP_ATOMIC);
+ if (!event)
+ return;
+
+ INIT_WORK(&event->work, tcpm_pd_rx_handler);
+ event->port = port;
+ memcpy(&event->msg, msg, sizeof(*msg));
+ queue_work(port->wq, &event->work);
+}
+EXPORT_SYMBOL_GPL(tcpm_pd_receive);
+
+static int tcpm_pd_send_control(struct tcpm_port *port,
+ enum pd_ctrl_msg_type type)
+{
+ struct pd_message msg;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.header = PD_HEADER_LE(type, port->pwr_role,
+ port->data_role,
+ port->message_id, 0);
+
+ return tcpm_pd_transmit(port, TCPC_TX_SOP, &msg);
+}
+
+/*
+ * Send queued message without affecting state.
+ * Return true if state machine should go back to sleep,
+ * false otherwise.
+ */
+static bool tcpm_send_queued_message(struct tcpm_port *port)
+{
+ enum pd_msg_request queued_message;
+ int ret = 0;
+
+ do {
+ queued_message = port->queued_message;
+ port->queued_message = PD_MSG_NONE;
+
+ switch (queued_message) {
+ case PD_MSG_CTRL_WAIT:
+ ret = tcpm_pd_send_control(port, PD_CTRL_WAIT);
+ break;
+ case PD_MSG_CTRL_REJECT:
+ ret = tcpm_pd_send_control(port, PD_CTRL_REJECT);
+ break;
+ case PD_MSG_DATA_SINK_CAP:
+ ret = tcpm_pd_send_sink_caps(port);
+ break;
+ case PD_MSG_DATA_SOURCE_CAP:
+ ret = tcpm_pd_send_source_caps(port);
+ break;
+ default:
+ break;
+ }
+ } while (port->queued_message != PD_MSG_NONE);
+
+ if (ret) {
+ tcpm_set_state(port, SOFT_RESET_SEND, 0);
+ tcpm_log(port, "TCPM sending message failure!");
+ return false;
+ }
+
+ if (port->delayed_state != INVALID_STATE) {
+ if (time_is_after_jiffies(port->delayed_runtime)) {
+ mod_delayed_work(port->wq, &port->state_machine,
+ port->delayed_runtime - jiffies);
+ return true;
+ }
+ port->delayed_state = INVALID_STATE;
+ }
+ return false;
+}
+
+static int tcpm_pd_check_request(struct tcpm_port *port)
+{
+ u32 pdo, rdo = port->sink_request;
+ unsigned int max, op, pdo_max, index;
+ enum pd_pdo_type type;
+
+ index = rdo_index(rdo);
+ if (!index || index > port->nr_src_pdo)
+ return -EINVAL;
+
+ pdo = port->src_pdo[index - 1];
+ type = pdo_type(pdo);
+ switch (type) {
+ case PDO_TYPE_FIXED:
+ case PDO_TYPE_VAR:
+ max = rdo_max_current(rdo);
+ op = rdo_op_current(rdo);
+ pdo_max = pdo_max_current(pdo);
+
+ if (op > pdo_max)
+ return -EINVAL;
+ if (max > pdo_max && !(rdo & RDO_CAP_MISMATCH))
+ return -EINVAL;
+
+ if (type == PDO_TYPE_FIXED)
+ tcpm_log(port,
+ "Requested %u mV, %u mA for %u / %u mA",
+ pdo_fixed_voltage(pdo), pdo_max, op, max);
+ else
+ tcpm_log(port,
+ "Requested %u -> %u mV, %u mA for %u / %u mA",
+ pdo_min_voltage(pdo), pdo_max_voltage(pdo),
+ pdo_max, op, max);
+ break;
+ case PDO_TYPE_BATT:
+ max = rdo_max_power(rdo);
+ op = rdo_op_power(rdo);
+ pdo_max = pdo_max_power(pdo);
+
+ if (op > pdo_max)
+ return -EINVAL;
+ if (max > pdo_max && !(rdo & RDO_CAP_MISMATCH))
+ return -EINVAL;
+ tcpm_log(port,
+ "Requested %u -> %u mV, %u mW for %u / %u mW",
+ pdo_min_voltage(pdo), pdo_max_voltage(pdo),
+ pdo_max, op, max);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ port->op_vsafe5v = index == 1;
+
+ return 0;
+}
+
+static int tcpm_pd_select_pdo(struct tcpm_port *port)
+{
+ unsigned int i, max_mw = 0, max_mv = 0;
+ int ret = -EINVAL;
+
+ /*
+ * Select the source PDO providing the most power while staying within
+ * the board's voltage limits. Prefer PDO providing exp
+ */
+ for (i = 0; i < port->nr_source_caps; i++) {
+ u32 pdo = port->source_caps[i];
+ enum pd_pdo_type type = pdo_type(pdo);
+ unsigned int mv, ma, mw;
+
+ if (type == PDO_TYPE_FIXED)
+ mv = pdo_fixed_voltage(pdo);
+ else
+ mv = pdo_min_voltage(pdo);
+
+ if (type == PDO_TYPE_BATT) {
+ mw = pdo_max_power(pdo);
+ } else {
+ ma = min(pdo_max_current(pdo),
+ port->max_snk_ma);
+ mw = ma * mv / 1000;
+ }
+
+ /* Perfer higher voltages if available */
+ if ((mw > max_mw || (mw == max_mw && mv > max_mv)) &&
+ mv <= port->max_snk_mv) {
+ ret = i;
+ max_mw = mw;
+ max_mv = mv;
+ }
+ }
+
+ return ret;
+}
+
+static int tcpm_pd_build_request(struct tcpm_port *port, u32 *rdo)
+{
+ unsigned int mv, ma, mw, flags;
+ unsigned int max_ma, max_mw;
+ enum pd_pdo_type type;
+ int index;
+ u32 pdo;
+
+ index = tcpm_pd_select_pdo(port);
+ if (index < 0)
+ return -EINVAL;
+ pdo = port->source_caps[index];
+ type = pdo_type(pdo);
+
+ if (type == PDO_TYPE_FIXED)
+ mv = pdo_fixed_voltage(pdo);
+ else
+ mv = pdo_min_voltage(pdo);
+
+ /* Select maximum available current within the board's power limit */
+ if (type == PDO_TYPE_BATT) {
+ mw = pdo_max_power(pdo);
+ ma = 1000 * min(mw, port->max_snk_mw) / mv;
+ } else {
+ ma = min(pdo_max_current(pdo),
+ 1000 * port->max_snk_mw / mv);
+ }
+ ma = min(ma, port->max_snk_ma);
+
+ /* XXX: Any other flags need to be set? */
+ flags = 0;
+
+ /* Set mismatch bit if offered power is less than operating power */
+ mw = ma * mv / 1000;
+ max_ma = ma;
+ max_mw = mw;
+ if (mw < port->operating_snk_mw) {
+ flags |= RDO_CAP_MISMATCH;
+ max_mw = port->operating_snk_mw;
+ max_ma = max_mw * 1000 / mv;
+ }
+
+ tcpm_log(port, "cc=%d cc1=%d cc2=%d vbus=%d vconn=%s polarity=%d",
+ port->cc_req, port->cc1, port->cc2, port->vbus_source,
+ port->vconn_role == TYPEC_SOURCE ? "source" : "sink",
+ port->polarity);
+
+ if (type == PDO_TYPE_BATT) {
+ *rdo = RDO_BATT(index + 1, mw, max_mw, flags);
+
+ tcpm_log(port, "Requesting PDO %d: %u mV, %u mW%s",
+ index, mv, mw,
+ flags & RDO_CAP_MISMATCH ? " [mismatch]" : "");
+ } else {
+ *rdo = RDO_FIXED(index + 1, ma, max_ma, flags);
+
+ tcpm_log(port, "Requesting PDO %d: %u mV, %u mA%s",
+ index, mv, ma,
+ flags & RDO_CAP_MISMATCH ? " [mismatch]" : "");
+ }
+
+ port->current_limit = ma;
+ port->supply_voltage = mv;
+
+ return 0;
+}
+
+static int tcpm_pd_send_request(struct tcpm_port *port)
+{
+ struct pd_message msg;
+ int ret;
+ u32 rdo;
+
+ ret = tcpm_pd_build_request(port, &rdo);
+ if (ret < 0)
+ return ret;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.header = PD_HEADER_LE(PD_DATA_REQUEST,
+ port->pwr_role,
+ port->data_role,
+ port->message_id, 1);
+ msg.payload[0] = cpu_to_le32(rdo);
+
+ return tcpm_pd_transmit(port, TCPC_TX_SOP, &msg);
+}
+
+static int tcpm_set_vbus(struct tcpm_port *port, bool enable)
+{
+ int ret;
+
+ if (enable && port->vbus_charge)
+ return -EINVAL;
+
+ tcpm_log(port, "vbus:=%d charge=%d", enable, port->vbus_charge);
+
+ ret = port->tcpc->set_vbus(port->tcpc, enable, port->vbus_charge);
+ if (ret < 0)
+ return ret;
+
+ port->vbus_source = enable;
+ return 0;
+}
+
+static int tcpm_set_charge(struct tcpm_port *port, bool charge)
+{
+ int ret;
+
+ if (charge && port->vbus_source)
+ return -EINVAL;
+
+ if (charge != port->vbus_charge) {
+ tcpm_log(port, "vbus=%d charge:=%d", port->vbus_source, charge);
+ ret = port->tcpc->set_vbus(port->tcpc, port->vbus_source,
+ charge);
+ if (ret < 0)
+ return ret;
+ }
+ port->vbus_charge = charge;
+ return 0;
+}
+
+static bool tcpm_start_drp_toggling(struct tcpm_port *port)
+{
+ int ret = 0;
+
+ tcpm_log(port, "Start DRP toggling");
+
+ /* First toggle Rp if current state is SNK_UNATTACHED */
+ if (port->tcpc->start_drp_toggling &&
+ port->typec_caps.type == TYPEC_PORT_DRP) {
+ if (port->state == SRC_UNATTACHED)
+ ret = port->tcpc->start_drp_toggling(port->tcpc,
+ tcpm_rp_cc(port), 0);
+ else if (port->state == SNK_UNATTACHED)
+ ret = port->tcpc->start_drp_toggling(port->tcpc,
+ TYPEC_CC_RD, 0);
+ else if (port->state == SRC_ATTACHED)
+ ret = port->tcpc->start_drp_toggling(port->tcpc,
+ tcpm_rp_cc(port), 0x1 << port->polarity);
+ else if (port->state == SNK_ATTACHED)
+ ret = port->tcpc->start_drp_toggling(port->tcpc,
+ TYPEC_CC_RD, 0x1 << port->polarity);
+ if (!ret)
+ return true;
+ }
+
+ return false;
+}
+
+static bool tcpm_vbus_is_low(struct tcpm_port *port)
+{
+ if (port->tcpc->get_vbus_vol &&
+ port->tcpc->get_vbus_vol(port->tcpc) > TCPM_VBUS_PRESENT_LEVEL)
+ return false;
+ else
+ return true;
+}
+
+static void tcpm_set_cc(struct tcpm_port *port, enum typec_cc_status cc)
+{
+ tcpm_log(port, "cc:=%d", cc);
+ port->cc_req = cc;
+ port->tcpc->set_cc(port->tcpc, cc);
+}
+
+static int tcpm_init_vbus(struct tcpm_port *port)
+{
+ int ret;
+
+ ret = port->tcpc->set_vbus(port->tcpc, false, false);
+ port->vbus_source = false;
+ port->vbus_charge = false;
+ return ret;
+}
+
+static int tcpm_init_vconn(struct tcpm_port *port)
+{
+ int ret;
+
+ ret = port->tcpc->set_vconn(port->tcpc, false);
+ port->vconn_role = TYPEC_SINK;
+ return ret;
+}
+
+static void tcpm_typec_connect(struct tcpm_port *port)
+{
+ if (!port->connected) {
+ /* Make sure we don't report stale identity information */
+ memset(&port->partner_ident, 0, sizeof(port->partner_ident));
+ port->partner_desc.usb_pd = port->pd_capable;
+ if (tcpm_port_is_debug(port))
+ port->partner_desc.accessory = TYPEC_ACCESSORY_DEBUG;
+ else if (tcpm_port_is_audio(port))
+ port->partner_desc.accessory = TYPEC_ACCESSORY_AUDIO;
+ else
+ port->partner_desc.accessory = TYPEC_ACCESSORY_NONE;
+ port->partner = typec_register_partner(port->typec_port,
+ &port->partner_desc);
+ port->connected = true;
+ }
+}
+
+static void tcpm_bist_handle(struct tcpm_port *port, bool enable)
+{
+ /* Enable or disable BIST test mode */
+ if (port->tcpc && port->tcpc->bist_mode)
+ port->tcpc->bist_mode(port->tcpc, enable);
+}
+
+static int tcpm_src_attach(struct tcpm_port *port)
+{
+ enum typec_cc_polarity polarity =
+ port->cc2 == TYPEC_CC_RD ? TYPEC_POLARITY_CC2
+ : TYPEC_POLARITY_CC1;
+ int ret;
+
+ if (port->attached)
+ return 0;
+
+ ret = tcpm_set_polarity(port, polarity);
+ if (ret < 0)
+ return ret;
+
+ if (port->tcpc->ss_mux_sel)
+ port->tcpc->ss_mux_sel(port->tcpc, polarity);
+
+ tcpm_start_drp_toggling(port);
+
+ ret = tcpm_set_roles(port, true, TYPEC_SOURCE, TYPEC_HOST);
+ if (ret < 0)
+ return ret;
+
+ ret = port->tcpc->set_pd_rx(port->tcpc, true);
+ if (ret < 0)
+ goto out_disable_mux;
+
+ /*
+ * USB Type-C specification, version 1.2,
+ * chapter 4.5.2.2.8.1 (Attached.SRC Requirements)
+ * Enable VCONN only if the non-RD port is set to RA.
+ */
+ if ((polarity == TYPEC_POLARITY_CC1 && port->cc2 == TYPEC_CC_RA) ||
+ (polarity == TYPEC_POLARITY_CC2 && port->cc1 == TYPEC_CC_RA)) {
+ ret = tcpm_set_vconn(port, true);
+ if (ret < 0)
+ goto out_disable_pd;
+ }
+
+ ret = tcpm_set_vbus(port, true);
+ if (ret < 0)
+ goto out_disable_vconn;
+
+ port->pd_capable = false;
+
+ port->partner = NULL;
+
+ port->attached = true;
+ port->send_discover = true;
+
+ return 0;
+
+out_disable_vconn:
+ tcpm_set_vconn(port, false);
+out_disable_pd:
+ port->tcpc->set_pd_rx(port->tcpc, false);
+out_disable_mux:
+ tcpm_mux_set(port, TYPEC_MUX_NONE, TCPC_USB_SWITCH_DISCONNECT);
+ return ret;
+}
+
+static void tcpm_typec_disconnect(struct tcpm_port *port)
+{
+ if (port->connected) {
+ typec_unregister_partner(port->partner);
+ port->partner = NULL;
+ port->connected = false;
+ }
+}
+
+static void tcpm_unregister_altmodes(struct tcpm_port *port)
+{
+ struct pd_mode_data *modep = &port->mode_data;
+ int i;
+
+ for (i = 0; i < modep->altmodes; i++) {
+ typec_unregister_altmode(port->partner_altmode[i]);
+ port->partner_altmode[i] = NULL;
+ }
+
+ memset(modep, 0, sizeof(*modep));
+}
+
+static void tcpm_reset_port(struct tcpm_port *port)
+{
+ tcpm_unregister_altmodes(port);
+ tcpm_typec_disconnect(port);
+ port->attached = false;
+ port->pd_capable = false;
+
+ tcpm_bist_handle(port, false);
+ port->tcpc->set_pd_rx(port->tcpc, false);
+ /* Don't disable charging if boot from dead battery */
+ if (!port->vbus_never_low)
+ tcpm_init_vbus(port);
+ tcpm_init_vconn(port);
+ tcpm_set_current_limit(port, 0, 0);
+ tcpm_set_polarity(port, TYPEC_POLARITY_CC1);
+ tcpm_set_attached_state(port, false);
+ port->try_src_count = 0;
+ port->try_snk_count = 0;
+}
+
+static void tcpm_detach(struct tcpm_port *port)
+{
+ if (!port->attached)
+ return;
+
+ if (tcpm_port_is_disconnected(port))
+ port->hard_reset_count = 0;
+
+ tcpm_reset_port(port);
+}
+
+static void tcpm_src_detach(struct tcpm_port *port)
+{
+ port->data_role = TYPEC_DEVICE;
+ tcpm_detach(port);
+}
+
+static int tcpm_snk_attach(struct tcpm_port *port)
+{
+ enum typec_cc_polarity polarity = port->cc2 != TYPEC_CC_OPEN ?
+ TYPEC_POLARITY_CC2 : TYPEC_POLARITY_CC1;
+ int ret;
+
+ if (port->attached)
+ return 0;
+
+ ret = tcpm_set_polarity(port, polarity);
+ if (ret < 0)
+ return ret;
+
+ if (port->tcpc->ss_mux_sel)
+ port->tcpc->ss_mux_sel(port->tcpc, polarity);
+
+ tcpm_start_drp_toggling(port);
+
+ ret = tcpm_set_roles(port, true, TYPEC_SINK, TYPEC_DEVICE);
+ if (ret < 0)
+ return ret;
+
+ port->pd_capable = false;
+
+ port->partner = NULL;
+
+ port->attached = true;
+ port->send_discover = true;
+
+ return 0;
+}
+
+static void tcpm_snk_detach(struct tcpm_port *port)
+{
+ tcpm_detach(port);
+
+ /* XXX: (Dis)connect SuperSpeed mux? */
+}
+
+static int tcpm_acc_attach(struct tcpm_port *port)
+{
+ int ret;
+
+ if (port->attached)
+ return 0;
+
+ ret = tcpm_set_roles(port, true, TYPEC_SOURCE, TYPEC_HOST);
+ if (ret < 0)
+ return ret;
+
+ port->partner = NULL;
+
+ tcpm_typec_connect(port);
+
+ port->attached = true;
+
+ return 0;
+}
+
+static void tcpm_acc_detach(struct tcpm_port *port)
+{
+ tcpm_detach(port);
+}
+
+static void tcpm_vbus_det(struct tcpm_port *port, bool enable)
+{
+ if (port->tcpc && port->tcpc->vbus_detect)
+ port->tcpc->vbus_detect(port->tcpc, true);
+}
+
+static inline enum tcpm_state hard_reset_state(struct tcpm_port *port)
+{
+ if (port->hard_reset_count < PD_N_HARD_RESET_COUNT)
+ return HARD_RESET_SEND;
+ if (port->pd_capable)
+ return ERROR_RECOVERY;
+ if (port->pwr_role == TYPEC_SOURCE)
+ return SRC_UNATTACHED;
+ if (port->state == SNK_WAIT_CAPABILITIES)
+ return SNK_READY;
+ return SNK_UNATTACHED;
+}
+
+static inline enum tcpm_state ready_state(struct tcpm_port *port)
+{
+ if (port->pwr_role == TYPEC_SOURCE)
+ return SRC_READY;
+ else
+ return SNK_READY;
+}
+
+static inline enum tcpm_state unattached_state(struct tcpm_port *port)
+{
+ if (port->pwr_role == TYPEC_SOURCE)
+ return SRC_UNATTACHED;
+ else
+ return SNK_UNATTACHED;
+}
+
+static void tcpm_check_send_discover(struct tcpm_port *port)
+{
+ if (port->data_role == TYPEC_HOST && port->send_discover &&
+ port->pd_capable) {
+ tcpm_send_vdm(port, USB_SID_PD, CMD_DISCOVER_IDENT, NULL, 0);
+ port->send_discover = false;
+ }
+}
+
+static void tcpm_swap_complete(struct tcpm_port *port, int result)
+{
+ if (port->swap_pending) {
+ port->swap_status = result;
+ port->swap_pending = false;
+ complete(&port->swap_complete);
+ }
+}
+
+static enum hrtimer_restart tcpm_sender_res_handle(struct hrtimer *data)
+{
+ struct tcpm_port *port = container_of(data, struct tcpm_port,
+ snd_res_timer);
+
+ tcpm_log_force(port, "Sender response timeout!");
+ tcpm_set_state(port, HARD_RESET_SEND, 0);
+ return HRTIMER_NORESTART;
+}
+
+static void run_state_machine(struct tcpm_port *port)
+{
+ int ret;
+
+ port->enter_state = port->state;
+ switch (port->state) {
+ case DRP_TOGGLING:
+ break;
+ /* SRC states */
+ case SRC_UNATTACHED:
+ tcpm_swap_complete(port, -ENOTCONN);
+ tcpm_src_detach(port);
+ if (tcpm_start_drp_toggling(port)) {
+ tcpm_set_state(port, DRP_TOGGLING, 0);
+ break;
+ }
+ tcpm_set_cc(port, tcpm_rp_cc(port));
+ if (port->typec_caps.type == TYPEC_PORT_DRP)
+ tcpm_set_state(port, SNK_UNATTACHED, PD_T_DRP_SNK);
+ break;
+ case SRC_ATTACH_WAIT:
+ if (tcpm_port_is_debug(port))
+ tcpm_set_state(port, DEBUG_ACC_ATTACHED,
+ PD_T_CC_DEBOUNCE);
+ else if (tcpm_port_is_audio(port))
+ tcpm_set_state(port, AUDIO_ACC_ATTACHED,
+ PD_T_CC_DEBOUNCE);
+ else if (tcpm_port_is_source(port))
+ tcpm_set_state(port,
+ tcpm_try_snk(port) ? SNK_TRY
+ : SRC_ATTACHED,
+ PD_T_CC_DEBOUNCE);
+ break;
+
+ case SNK_TRY:
+ port->try_snk_count++;
+ /*
+ * Requirements:
+ * - Do not drive vconn or vbus
+ * - Terminate CC pins (both) to Rd
+ * Action:
+ * - Wait for tDRPTry (PD_T_DRP_TRY).
+ * Until then, ignore any state changes.
+ */
+ tcpm_set_cc(port, TYPEC_CC_RD);
+ tcpm_set_state(port, SNK_TRY_WAIT, PD_T_DRP_TRY);
+ break;
+ case SNK_TRY_WAIT:
+ if (port->vbus_present && tcpm_port_is_sink(port)) {
+ tcpm_set_state(port, SNK_ATTACHED, 0);
+ break;
+ }
+ if (!tcpm_port_is_sink(port)) {
+ tcpm_set_state(port, SRC_TRYWAIT,
+ PD_T_PD_DEBOUNCE);
+ break;
+ }
+ /* No vbus, cc state is sink or open */
+ tcpm_set_state(port, SRC_TRYWAIT_UNATTACHED, PD_T_DRP_TRYWAIT);
+ break;
+ case SRC_TRYWAIT:
+ tcpm_set_cc(port, tcpm_rp_cc(port));
+ if (!port->vbus_present && tcpm_port_is_source(port))
+ tcpm_set_state(port, SRC_ATTACHED, PD_T_CC_DEBOUNCE);
+ else
+ tcpm_set_state(port, SRC_TRYWAIT_UNATTACHED,
+ PD_T_DRP_TRY);
+ break;
+ case SRC_TRYWAIT_UNATTACHED:
+ tcpm_set_state(port, SNK_UNATTACHED, 0);
+ break;
+
+ case SRC_ATTACHED:
+ if (tcpm_vbus_is_low(port)) {
+ ret = tcpm_src_attach(port);
+ tcpm_set_state(port, SRC_UNATTACHED,
+ ret < 0 ? 0 : PD_T_PS_SOURCE_ON);
+ } else {
+ tcpm_log(port, "Sink shouldn't provide vbus!");
+ tcpm_set_state(port, SRC_UNATTACHED, 10);
+ }
+ break;
+ case SRC_STARTUP:
+ typec_set_pwr_opmode(port->typec_port, TYPEC_PWR_MODE_USB);
+ port->pwr_opmode = TYPEC_PWR_MODE_USB;
+ port->caps_count = 0;
+ port->message_id = 0;
+ port->explicit_contract = false;
+ tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
+ break;
+ case SRC_SEND_CAPABILITIES:
+ port->caps_count++;
+ if (port->caps_count > PD_N_CAPS_COUNT) {
+ tcpm_set_state(port, SRC_READY, 0);
+ break;
+ }
+ ret = tcpm_pd_send_source_caps(port);
+ if (ret < 0) {
+ tcpm_set_state(port, SRC_SEND_CAPABILITIES,
+ PD_T_SEND_SOURCE_CAP);
+ } else {
+ port->hard_reset_count = 0;
+ port->caps_count = 0;
+ port->pd_capable = true;
+ hrtimer_start(&port->snd_res_timer,
+ ms_to_ktime(PD_T_SENDER_RESPONSE),
+ HRTIMER_MODE_REL);
+ }
+ break;
+ case SRC_NEGOTIATE_CAPABILITIES:
+ ret = tcpm_pd_check_request(port);
+ if (ret < 0) {
+ tcpm_pd_send_control(port, PD_CTRL_REJECT);
+ if (!port->explicit_contract) {
+ tcpm_set_state(port,
+ SRC_WAIT_NEW_CAPABILITIES, 0);
+ } else {
+ tcpm_set_state(port, SRC_READY, 0);
+ }
+ } else {
+ tcpm_pd_send_control(port, PD_CTRL_ACCEPT);
+ tcpm_set_state(port, SRC_TRANSITION_SUPPLY,
+ PD_T_SRC_TRANSITION);
+ }
+ break;
+ case SRC_TRANSITION_SUPPLY:
+ /* XXX: regulator_set_voltage(vbus, ...) */
+ tcpm_pd_send_control(port, PD_CTRL_PS_RDY);
+ port->explicit_contract = true;
+ typec_set_pwr_opmode(port->typec_port, TYPEC_PWR_MODE_PD);
+ port->pwr_opmode = TYPEC_PWR_MODE_PD;
+ tcpm_set_state_cond(port, SRC_READY, 0);
+ break;
+ case SRC_READY:
+#if 1
+ port->hard_reset_count = 0;
+#endif
+ port->try_src_count = 0;
+
+ tcpm_typec_connect(port);
+
+ tcpm_check_send_discover(port);
+ /*
+ * 6.3.5
+ * Sending ping messages is not necessary if
+ * - the source operates at vSafe5V
+ * or
+ * - The system is not operating in PD mode
+ * or
+ * - Both partners are connected using a Type-C connector
+ *
+ * There is no actual need to send PD messages since the local
+ * port type-c and the spec does not clearly say whether PD is
+ * possible when type-c is connected to Type-A/B
+ */
+ break;
+ case SRC_WAIT_NEW_CAPABILITIES:
+ /* Nothing to do... */
+ break;
+
+ /* SNK states */
+ case SNK_UNATTACHED:
+ tcpm_swap_complete(port, -ENOTCONN);
+ tcpm_snk_detach(port);
+ if (tcpm_start_drp_toggling(port)) {
+ tcpm_set_state(port, DRP_TOGGLING, 0);
+ break;
+ }
+ tcpm_set_cc(port, TYPEC_CC_RD);
+ if (port->typec_caps.type == TYPEC_PORT_DRP)
+ tcpm_set_state(port, SRC_UNATTACHED, PD_T_DRP_SRC);
+ break;
+ case SNK_ATTACH_WAIT:
+ if ((port->cc1 == TYPEC_CC_OPEN &&
+ port->cc2 != TYPEC_CC_OPEN) ||
+ (port->cc1 != TYPEC_CC_OPEN &&
+ port->cc2 == TYPEC_CC_OPEN)) {
+ tcpm_set_state(port, SNK_DEBOUNCED,
+ PD_T_CC_DEBOUNCE);
+ tcpm_vbus_det(port, true);
+ } else if (tcpm_port_is_disconnected(port))
+ tcpm_set_state(port, SNK_UNATTACHED,
+ PD_T_PD_DEBOUNCE);
+ break;
+ case SNK_DEBOUNCED:
+ if (tcpm_port_is_disconnected(port))
+ tcpm_set_state(port, SNK_UNATTACHED,
+ PD_T_PD_DEBOUNCE);
+ else if (port->vbus_present)
+ tcpm_set_state(port,
+ tcpm_try_src(port) ? SRC_TRY
+ : SNK_ATTACHED,
+ 0);
+ else
+ /* Wait for VBUS, but not forever */
+ tcpm_set_state(port, SNK_UNATTACHED, PD_T_PS_SOURCE_ON);
+ break;
+
+ case SRC_TRY:
+ port->try_src_count++;
+ tcpm_set_cc(port, tcpm_rp_cc(port));
+ tcpm_set_state(port, SNK_TRYWAIT, PD_T_DRP_TRY);
+ break;
+ case SRC_TRY_DEBOUNCE:
+ tcpm_set_state(port, SRC_ATTACHED, PD_T_PD_DEBOUNCE);
+ break;
+ case SNK_TRYWAIT:
+ tcpm_set_cc(port, TYPEC_CC_RD);
+ tcpm_set_state(port, SNK_TRYWAIT_DEBOUNCE, PD_T_CC_DEBOUNCE);
+ break;
+ case SNK_TRYWAIT_DEBOUNCE:
+ if (port->vbus_present) {
+ tcpm_set_state(port, SNK_ATTACHED, 0);
+ break;
+ }
+ if (tcpm_port_is_disconnected(port)) {
+ tcpm_set_state(port, SNK_UNATTACHED,
+ PD_T_PD_DEBOUNCE);
+ break;
+ }
+ if (tcpm_port_is_source(port))
+ tcpm_set_state(port, SRC_ATTACHED, 0);
+ /* XXX Are we supposed to stay in this state ? */
+ break;
+ case SNK_TRYWAIT_VBUS:
+ tcpm_set_state(port, SNK_ATTACHED, PD_T_CC_DEBOUNCE);
+ break;
+
+ case SNK_ATTACHED:
+ ret = tcpm_snk_attach(port);
+ if (ret < 0)
+ tcpm_set_state(port, SNK_UNATTACHED, 0);
+ else
+ tcpm_set_state(port, SNK_STARTUP, 0);
+ break;
+ case SNK_STARTUP:
+ /* XXX: callback into infrastructure */
+ typec_set_pwr_opmode(port->typec_port, TYPEC_PWR_MODE_USB);
+ port->pwr_opmode = TYPEC_PWR_MODE_USB;
+ port->message_id = 0;
+ port->explicit_contract = false;
+ tcpm_set_state(port, SNK_DISCOVERY, 0);
+ break;
+ case SNK_DISCOVERY:
+ if (port->vbus_present) {
+ tcpm_set_current_limit(port,
+ tcpm_get_current_limit(port),
+ 5000);
+ tcpm_set_charge(port, true);
+ tcpm_set_state(port, SNK_WAIT_CAPABILITIES, 0);
+ break;
+ }
+ /*
+ * For DRP, timeouts differ. Also, handling is supposed to be
+ * different and much more complex (dead battery detection;
+ * see USB power delivery specification, section 8.3.3.6.1.5.1).
+ */
+ tcpm_set_state(port, hard_reset_state(port),
+ port->typec_caps.type == TYPEC_PORT_DRP ?
+ PD_T_DB_DETECT : PD_T_NO_RESPONSE);
+ break;
+ case SNK_DISCOVERY_DEBOUNCE:
+ tcpm_set_state(port, SNK_DISCOVERY_DEBOUNCE_DONE,
+ PD_T_CC_DEBOUNCE);
+ break;
+ case SNK_DISCOVERY_DEBOUNCE_DONE:
+ if (!tcpm_port_is_disconnected(port) &&
+ tcpm_port_is_sink(port) &&
+ time_is_after_jiffies(port->delayed_runtime)) {
+ tcpm_set_state(port, SNK_DISCOVERY,
+ port->delayed_runtime - jiffies);
+ break;
+ }
+ tcpm_set_state(port, unattached_state(port), 0);
+ break;
+ case SNK_WAIT_CAPABILITIES:
+ ret = port->tcpc->set_pd_rx(port->tcpc, true);
+ if (ret < 0) {
+ tcpm_set_state(port, SNK_READY, 0);
+ break;
+ }
+ /*
+ * If VBUS has never been low, and we time out waiting
+ * for source cap, try a soft reset first, in case we
+ * were already in a stable contract before this boot.
+ * Do this only once.
+ */
+ if (port->vbus_never_low) {
+ port->vbus_never_low = false;
+ tcpm_set_state(port, SOFT_RESET_SEND,
+ PD_T_SINK_WAIT_CAP);
+ } else {
+ tcpm_set_state(port, hard_reset_state(port),
+ PD_T_SINK_WAIT_CAP);
+ }
+ break;
+ case SNK_NEGOTIATE_CAPABILITIES:
+ port->pd_capable = true;
+ port->hard_reset_count = 0;
+ ret = tcpm_pd_send_request(port);
+ if (ret < 0) {
+ /* Let the Source send capabilities again. */
+ tcpm_set_state(port, SNK_WAIT_CAPABILITIES, 0);
+ } else {
+ hrtimer_start(&port->snd_res_timer,
+ ms_to_ktime(PD_T_SENDER_RESPONSE),
+ HRTIMER_MODE_REL);
+ }
+ break;
+ case SNK_TRANSITION_SINK:
+ case SNK_TRANSITION_SINK_VBUS:
+ tcpm_set_state(port, hard_reset_state(port),
+ PD_T_PS_TRANSITION);
+ break;
+ case SNK_READY:
+ port->try_snk_count = 0;
+ port->explicit_contract = true;
+ typec_set_pwr_opmode(port->typec_port, TYPEC_PWR_MODE_PD);
+ port->pwr_opmode = TYPEC_PWR_MODE_PD;
+
+ tcpm_typec_connect(port);
+
+ tcpm_check_send_discover(port);
+ break;
+
+ /* Accessory states */
+ case ACC_UNATTACHED:
+ tcpm_acc_detach(port);
+ tcpm_set_state(port, SRC_UNATTACHED, 0);
+ break;
+ case DEBUG_ACC_ATTACHED:
+ case AUDIO_ACC_ATTACHED:
+ ret = tcpm_acc_attach(port);
+ if (ret < 0)
+ tcpm_set_state(port, ACC_UNATTACHED, 0);
+ break;
+ case AUDIO_ACC_DEBOUNCE:
+ tcpm_set_state(port, ACC_UNATTACHED, PD_T_CC_DEBOUNCE);
+ break;
+
+ /* Hard_Reset states */
+ case HARD_RESET_SEND:
+ tcpm_pd_transmit(port, TCPC_TX_HARD_RESET, NULL);
+ tcpm_set_state(port, HARD_RESET_START, 0);
+ break;
+ case HARD_RESET_START:
+ port->hard_reset_count++;
+ port->tcpc->set_pd_rx(port->tcpc, false);
+ tcpm_unregister_altmodes(port);
+ port->send_discover = true;
+ if (port->pwr_role == TYPEC_SOURCE)
+ tcpm_set_state(port, SRC_HARD_RESET_VBUS_OFF,
+ PD_T_PS_HARD_RESET);
+ else
+ tcpm_set_state(port, SNK_HARD_RESET_SINK_OFF, 0);
+ break;
+ case SRC_HARD_RESET_VBUS_OFF:
+ tcpm_set_vconn(port, true);
+ tcpm_set_vbus(port, false);
+ tcpm_set_roles(port, false, TYPEC_SOURCE, TYPEC_HOST);
+ tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER);
+ break;
+ case SRC_HARD_RESET_VBUS_ON:
+ tcpm_set_vbus(port, true);
+ port->tcpc->set_pd_rx(port->tcpc, true);
+ tcpm_set_attached_state(port, true);
+ tcpm_set_state(port, SRC_UNATTACHED, PD_T_PS_SOURCE_ON);
+ break;
+ case SNK_HARD_RESET_SINK_OFF:
+ tcpm_set_vconn(port, false);
+ tcpm_set_charge(port, false);
+ tcpm_set_roles(port, false, TYPEC_SINK, TYPEC_DEVICE);
+ /*
+ * VBUS may or may not toggle, depending on the adapter.
+ * If it doesn't toggle, transition to SNK_HARD_RESET_SINK_ON
+ * directly after timeout.
+ */
+ tcpm_set_state(port, SNK_HARD_RESET_SINK_ON, PD_T_SAFE_0V);
+ break;
+ case SNK_HARD_RESET_WAIT_VBUS:
+ /* Assume we're disconnected if VBUS doesn't come back. */
+ tcpm_set_state(port, SNK_UNATTACHED,
+ PD_T_SRC_RECOVER_MAX + PD_T_SRC_TURN_ON);
+ break;
+ case SNK_HARD_RESET_SINK_ON:
+ /* Note: There is no guarantee that VBUS is on in this state */
+ /*
+ * XXX:
+ * The specification suggests that dual mode ports in sink
+ * mode should transition to state PE_SRC_Transition_to_default.
+ * See USB power delivery specification chapter 8.3.3.6.1.3.
+ * This would mean to to
+ * - turn off VCONN, reset power supply
+ * - request hardware reset
+ * - turn on VCONN
+ * - Transition to state PE_Src_Startup
+ * SNK only ports shall transition to state Snk_Startup
+ * (see chapter 8.3.3.3.8).
+ * Similar, dual-mode ports in source mode should transition
+ * to PE_SNK_Transition_to_default.
+ */
+ tcpm_set_attached_state(port, true);
+ if (tcpm_port_is_disconnected(port))
+ tcpm_set_state(port, unattached_state(port), 0);
+ else
+ tcpm_set_state(port, SNK_STARTUP, 0);
+ break;
+
+ /* Soft_Reset states */
+ case SOFT_RESET:
+ port->message_id = 0;
+ tcpm_pd_send_control(port, PD_CTRL_ACCEPT);
+ if (port->pwr_role == TYPEC_SOURCE)
+ tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
+ else
+ tcpm_set_state(port, SNK_WAIT_CAPABILITIES, 0);
+ break;
+ case SOFT_RESET_SEND:
+ port->message_id = 0;
+ if (tcpm_pd_send_control(port, PD_CTRL_SOFT_RESET))
+ tcpm_set_state_cond(port, hard_reset_state(port), 0);
+ else
+ tcpm_set_state_cond(port, hard_reset_state(port),
+ PD_T_SENDER_RESPONSE);
+ break;
+
+ /* DR_Swap states */
+ case DR_SWAP_SEND:
+ tcpm_pd_send_control(port, PD_CTRL_DR_SWAP);
+ tcpm_set_state_cond(port, DR_SWAP_SEND_TIMEOUT,
+ PD_T_SENDER_RESPONSE);
+ break;
+ case DR_SWAP_ACCEPT:
+ tcpm_pd_send_control(port, PD_CTRL_ACCEPT);
+ tcpm_set_state_cond(port, DR_SWAP_CHANGE_DR, 0);
+ break;
+ case DR_SWAP_SEND_TIMEOUT:
+ tcpm_swap_complete(port, -ETIMEDOUT);
+ tcpm_set_state(port, ready_state(port), 0);
+ break;
+ case DR_SWAP_CHANGE_DR:
+ if (port->data_role == TYPEC_HOST) {
+ tcpm_unregister_altmodes(port);
+ tcpm_set_roles(port, true, port->pwr_role,
+ TYPEC_DEVICE);
+ } else {
+ tcpm_set_roles(port, true, port->pwr_role,
+ TYPEC_HOST);
+ port->send_discover = true;
+ }
+ tcpm_swap_complete(port, 0);
+ tcpm_set_state(port, ready_state(port), 0);
+ break;
+
+ /* PR_Swap states */
+ case PR_SWAP_ACCEPT:
+ tcpm_pd_send_control(port, PD_CTRL_ACCEPT);
+ tcpm_set_state(port, PR_SWAP_START, 0);
+ break;
+ case PR_SWAP_SEND:
+ tcpm_pd_send_control(port, PD_CTRL_PR_SWAP);
+ tcpm_set_state_cond(port, PR_SWAP_SEND_TIMEOUT,
+ PD_T_SENDER_RESPONSE);
+ break;
+ case PR_SWAP_SEND_TIMEOUT:
+ tcpm_swap_complete(port, -ETIMEDOUT);
+ tcpm_set_state(port, ready_state(port), 0);
+ break;
+ case PR_SWAP_START:
+ if (port->pwr_role == TYPEC_SOURCE)
+ tcpm_set_state(port, PR_SWAP_SRC_SNK_TRANSITION_OFF,
+ PD_T_SRC_TRANSITION);
+ else
+ tcpm_set_state(port, PR_SWAP_SNK_SRC_SINK_OFF, 0);
+ break;
+ case PR_SWAP_SRC_SNK_TRANSITION_OFF:
+ tcpm_set_vbus(port, false);
+ port->explicit_contract = false;
+ tcpm_set_state(port, PR_SWAP_SRC_SNK_SOURCE_OFF,
+ PD_T_PS_SOURCE_OFF);
+ break;
+ case PR_SWAP_SRC_SNK_SOURCE_OFF:
+ tcpm_set_cc(port, TYPEC_CC_RD);
+ tcpm_set_pwr_role(port, TYPEC_SINK);
+ if (tcpm_pd_send_control(port, PD_CTRL_PS_RDY)) {
+ tcpm_set_state(port, ERROR_RECOVERY, 0);
+ break;
+ }
+ tcpm_set_state_cond(port, ERROR_RECOVERY, PD_T_PS_SOURCE_ON);
+ break;
+ case PR_SWAP_SRC_SNK_SINK_ON:
+ tcpm_swap_complete(port, 0);
+ tcpm_set_state(port, SNK_STARTUP, 0);
+ break;
+ case PR_SWAP_SNK_SRC_SINK_OFF:
+ tcpm_set_charge(port, false);
+ tcpm_set_state(port, hard_reset_state(port),
+ PD_T_PS_SOURCE_OFF);
+ break;
+ case PR_SWAP_SNK_SRC_ASSERT_RP:
+ tcpm_set_cc(port, tcpm_rp_cc(port));
+ tcpm_set_vbus(port, true);
+ break;
+ case PR_SWAP_SNK_SRC_SOURCE_ON:
+ tcpm_set_pwr_role(port, TYPEC_SOURCE);
+ tcpm_pd_send_control(port, PD_CTRL_PS_RDY);
+ tcpm_swap_complete(port, 0);
+ tcpm_set_state(port, SRC_STARTUP, 25);
+ break;
+
+ case VCONN_SWAP_ACCEPT:
+ tcpm_pd_send_control(port, PD_CTRL_ACCEPT);
+ tcpm_set_state(port, VCONN_SWAP_START, 0);
+ break;
+ case VCONN_SWAP_SEND:
+ tcpm_pd_send_control(port, PD_CTRL_VCONN_SWAP);
+ tcpm_set_state(port, VCONN_SWAP_SEND_TIMEOUT,
+ PD_T_SENDER_RESPONSE);
+ break;
+ case VCONN_SWAP_SEND_TIMEOUT:
+ tcpm_swap_complete(port, -ETIMEDOUT);
+ tcpm_set_state(port, ready_state(port), 0);
+ break;
+ case VCONN_SWAP_START:
+ if (port->vconn_role == TYPEC_SOURCE)
+ tcpm_set_state(port, VCONN_SWAP_WAIT_FOR_VCONN, 0);
+ else
+ tcpm_set_state(port, VCONN_SWAP_TURN_ON_VCONN, 0);
+ break;
+ case VCONN_SWAP_WAIT_FOR_VCONN:
+ tcpm_set_state(port, hard_reset_state(port),
+ PD_T_VCONN_SOURCE_ON);
+ break;
+ case VCONN_SWAP_TURN_ON_VCONN:
+ tcpm_set_vconn(port, true);
+ tcpm_pd_send_control(port, PD_CTRL_PS_RDY);
+ tcpm_swap_complete(port, 0);
+ tcpm_set_state(port, ready_state(port), 0);
+ break;
+ case VCONN_SWAP_TURN_OFF_VCONN:
+ tcpm_set_vconn(port, false);
+ tcpm_swap_complete(port, 0);
+ tcpm_set_state(port, ready_state(port), 0);
+ break;
+
+ case DR_SWAP_CANCEL:
+ case PR_SWAP_CANCEL:
+ case VCONN_SWAP_CANCEL:
+ tcpm_swap_complete(port, port->swap_status);
+ if (port->pwr_role == TYPEC_SOURCE)
+ tcpm_set_state(port, SRC_READY, 0);
+ else
+ tcpm_set_state(port, SNK_READY, 0);
+ break;
+
+ case BIST_RX:
+ tcpm_bist_handle(port, true);
+ switch (BDO_MODE_MASK(port->bist_request)) {
+ case BDO_MODE_CARRIER2:
+ tcpm_pd_transmit(port, TCPC_TX_BIST_MODE_2, NULL);
+ break;
+ default:
+ break;
+ }
+ break;
+ case ERROR_RECOVERY:
+ tcpm_swap_complete(port, -EPROTO);
+ tcpm_reset_port(port);
+
+ tcpm_set_cc(port, TYPEC_CC_OPEN);
+ tcpm_set_state(port, ERROR_RECOVERY_WAIT_OFF,
+ PD_T_ERROR_RECOVERY);
+ break;
+ case ERROR_RECOVERY_WAIT_OFF:
+ tcpm_set_state(port,
+ tcpm_default_state(port),
+ port->vbus_present ? PD_T_PS_SOURCE_OFF : 0);
+ break;
+ default:
+ WARN(1, "Unexpected port state %d\n", port->state);
+ break;
+ }
+}
+
+static void tcpm_state_machine_work(struct work_struct *work)
+{
+ struct tcpm_port *port = container_of(work, struct tcpm_port,
+ state_machine.work);
+ enum tcpm_state prev_state;
+
+ mutex_lock(&port->lock);
+ port->state_machine_running = true;
+
+ if (port->queued_message && tcpm_send_queued_message(port))
+ goto done;
+
+ /* If we were queued due to a delayed state change, update it now */
+ if (port->delayed_state) {
+ tcpm_log(port, "state change %s -> %s [delayed %ld ms]",
+ tcpm_states[port->state],
+ tcpm_states[port->delayed_state], port->delay_ms);
+ port->prev_state = port->state;
+ port->state = port->delayed_state;
+ port->delayed_state = INVALID_STATE;
+ tcpm_qos_handling(port);
+ }
+
+ /*
+ * Continue running as long as we have (non-delayed) state changes
+ * to make.
+ */
+ do {
+ prev_state = port->state;
+ run_state_machine(port);
+ if (port->queued_message)
+ tcpm_send_queued_message(port);
+ } while (port->state != prev_state && !port->delayed_state);
+done:
+ port->state_machine_running = false;
+ mutex_unlock(&port->lock);
+}
+
+static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,
+ enum typec_cc_status cc2)
+{
+ enum typec_cc_status old_cc1, old_cc2;
+ enum tcpm_state new_state;
+
+ old_cc1 = port->cc1;
+ old_cc2 = port->cc2;
+ port->cc1 = cc1;
+ port->cc2 = cc2;
+
+ tcpm_log_force(port,
+ "CC1: %u -> %u, CC2: %u -> %u [state %s, polarity %d, %s]",
+ old_cc1, cc1, old_cc2, cc2, tcpm_states[port->state],
+ port->polarity,
+ tcpm_port_is_disconnected(port) ? "disconnected"
+ : "connected");
+
+ switch (port->state) {
+ case DRP_TOGGLING:
+ if (tcpm_port_is_debug(port) || tcpm_port_is_audio(port) ||
+ tcpm_port_is_source(port))
+ tcpm_set_state(port, SRC_ATTACH_WAIT, 0);
+ else if (tcpm_port_is_sink(port))
+ tcpm_set_state(port, SNK_ATTACH_WAIT, 0);
+ break;
+ case SRC_UNATTACHED:
+ case ACC_UNATTACHED:
+ if (tcpm_port_is_debug(port) || tcpm_port_is_audio(port) ||
+ tcpm_port_is_source(port))
+ tcpm_set_state(port, SRC_ATTACH_WAIT, 0);
+ break;
+ case SRC_ATTACH_WAIT:
+ if (tcpm_port_is_disconnected(port) ||
+ tcpm_port_is_audio_detached(port))
+ tcpm_set_state(port, SRC_UNATTACHED, 0);
+ else if (cc1 != old_cc1 || cc2 != old_cc2)
+ tcpm_set_state(port, SRC_ATTACH_WAIT, 0);
+ break;
+ case SRC_ATTACHED:
+ if (tcpm_port_is_disconnected(port))
+ tcpm_set_state(port, SRC_UNATTACHED, 0);
+ break;
+
+ case SNK_UNATTACHED:
+ if (tcpm_port_is_sink(port))
+ tcpm_set_state(port, SNK_ATTACH_WAIT, 0);
+ break;
+ case SNK_ATTACH_WAIT:
+ if ((port->cc1 == TYPEC_CC_OPEN &&
+ port->cc2 != TYPEC_CC_OPEN) ||
+ (port->cc1 != TYPEC_CC_OPEN &&
+ port->cc2 == TYPEC_CC_OPEN))
+ new_state = SNK_DEBOUNCED;
+ else if (tcpm_port_is_disconnected(port))
+ new_state = SNK_UNATTACHED;
+ else
+ break;
+ if (new_state != port->delayed_state)
+ tcpm_set_state(port, SNK_ATTACH_WAIT, 0);
+ break;
+ case SNK_DEBOUNCED:
+ if (tcpm_port_is_disconnected(port))
+ new_state = SNK_UNATTACHED;
+ else if (port->vbus_present)
+ new_state = tcpm_try_src(port) ? SRC_TRY : SNK_ATTACHED;
+ else if (cc1 > TYPEC_CC_RP_DEF || cc2 > TYPEC_CC_RP_DEF)
+ /* CC changes on pull-up value */
+ new_state = SNK_ATTACH_WAIT;
+ else
+ new_state = SNK_UNATTACHED;
+ if (new_state != port->delayed_state)
+ tcpm_set_state(port, SNK_DEBOUNCED, 0);
+ break;
+ case SNK_READY:
+ if (tcpm_port_is_disconnected(port))
+ tcpm_set_state(port, unattached_state(port), 0);
+ else if (!port->pd_capable &&
+ (cc1 != old_cc1 || cc2 != old_cc2))
+ tcpm_set_current_limit(port,
+ tcpm_get_current_limit(port),
+ 5000);
+ break;
+
+ case AUDIO_ACC_ATTACHED:
+ if (cc1 == TYPEC_CC_OPEN || cc2 == TYPEC_CC_OPEN)
+ tcpm_set_state(port, AUDIO_ACC_DEBOUNCE, 0);
+ break;
+ case AUDIO_ACC_DEBOUNCE:
+ if (tcpm_port_is_audio(port))
+ tcpm_set_state(port, AUDIO_ACC_ATTACHED, 0);
+ break;
+
+ case DEBUG_ACC_ATTACHED:
+ if (cc1 == TYPEC_CC_OPEN || cc2 == TYPEC_CC_OPEN)
+ tcpm_set_state(port, ACC_UNATTACHED, 0);
+ break;
+
+ case SNK_TRY:
+ /* Do nothing, waiting for timeout */
+ break;
+
+ case SNK_DISCOVERY:
+ /* CC line is unstable, wait for debounce */
+ if (tcpm_port_is_disconnected(port))
+ tcpm_set_state(port, SNK_DISCOVERY_DEBOUNCE, 0);
+ break;
+ case SNK_DISCOVERY_DEBOUNCE:
+ break;
+
+ case SRC_TRYWAIT:
+ /* Hand over to state machine if needed */
+ if (!port->vbus_present && tcpm_port_is_source(port))
+ tcpm_set_state(port, SRC_ATTACHED, 0);
+ else if (port->delayed_state != SRC_TRYWAIT_UNATTACHED)
+ tcpm_set_state(port, SRC_TRYWAIT, 0);
+ break;
+ case SNK_TRY_WAIT:
+ if (port->vbus_present && tcpm_port_is_sink(port)) {
+ tcpm_set_state(port, SNK_ATTACHED, 0);
+ break;
+ }
+ if (!tcpm_port_is_sink(port))
+ new_state = SRC_TRYWAIT;
+ else
+ new_state = SRC_TRYWAIT_UNATTACHED;
+
+ if (new_state != port->delayed_state)
+ tcpm_set_state(port, SNK_TRY_WAIT, 0);
+ break;
+
+ case SRC_TRY:
+ if (tcpm_port_is_source(port))
+ tcpm_set_state(port, SRC_TRY_DEBOUNCE, 0);
+ break;
+ case SRC_TRY_DEBOUNCE:
+ tcpm_set_state(port, SRC_TRY, 0);
+ break;
+ case SNK_TRYWAIT_DEBOUNCE:
+ if (port->vbus_present) {
+ tcpm_set_state(port, SNK_ATTACHED, 0);
+ break;
+ }
+ if (tcpm_port_is_source(port)) {
+ tcpm_set_state(port, SRC_ATTACHED, 0);
+ break;
+ }
+ if (tcpm_port_is_disconnected(port) &&
+ port->delayed_state != SNK_UNATTACHED)
+ tcpm_set_state(port, SNK_TRYWAIT_DEBOUNCE, 0);
+ break;
+
+ case PR_SWAP_SNK_SRC_SINK_OFF:
+ case PR_SWAP_SNK_SRC_ASSERT_RP:
+ case PR_SWAP_SRC_SNK_TRANSITION_OFF:
+ case PR_SWAP_SRC_SNK_SOURCE_OFF:
+ case ERROR_RECOVERY:
+ /*
+ * CC state change is expected here; we just turned off power.
+ * Ignore it.
+ */
+ break;
+ default:
+ if (tcpm_port_is_disconnected(port))
+ tcpm_set_state(port, unattached_state(port), 0);
+ break;
+ }
+}
+
+static void _tcpm_pd_vbus_on(struct tcpm_port *port)
+{
+ enum tcpm_state new_state;
+
+ tcpm_log_force(port, "VBUS on");
+ port->vbus_present = true;
+ switch (port->state) {
+ case SNK_TRANSITION_SINK_VBUS:
+ tcpm_set_state(port, SNK_READY, 0);
+ break;
+ case SNK_DISCOVERY:
+ tcpm_set_state(port, SNK_DISCOVERY, 0);
+ break;
+
+ case SNK_DEBOUNCED:
+ tcpm_set_state(port, tcpm_try_src(port) ? SRC_TRY
+ : SNK_ATTACHED,
+ 0);
+ break;
+ case SNK_HARD_RESET_WAIT_VBUS:
+ tcpm_set_state(port, SNK_HARD_RESET_SINK_ON, 0);
+ break;
+ case SRC_ATTACHED:
+ tcpm_set_state(port, SRC_STARTUP, 0);
+ break;
+ case SRC_HARD_RESET_VBUS_ON:
+ tcpm_set_state(port, SRC_STARTUP, 0);
+ break;
+
+ case SNK_TRY:
+ /* Do nothing, waiting for timeout */
+ break;
+ case SRC_TRYWAIT:
+ /* Hand over to state machine if needed */
+ if (port->delayed_state != SRC_TRYWAIT_UNATTACHED)
+ tcpm_set_state(port, SRC_TRYWAIT, 0);
+ break;
+ case SNK_TRY_WAIT:
+ if (tcpm_port_is_sink(port)) {
+ tcpm_set_state(port, SNK_ATTACHED, 0);
+ break;
+ }
+ if (!tcpm_port_is_sink(port))
+ new_state = SRC_TRYWAIT;
+ else
+ new_state = SRC_TRYWAIT_UNATTACHED;
+
+ if (new_state != port->delayed_state)
+ tcpm_set_state(port, SNK_TRY_WAIT, 0);
+ break;
+ case SNK_TRYWAIT:
+ tcpm_set_state(port, SNK_TRYWAIT_VBUS, 0);
+ break;
+ case PR_SWAP_SNK_SRC_ASSERT_RP:
+ /* If vbus is reached, start source on to send PS_RDY */
+ tcpm_set_state(port, PR_SWAP_SNK_SRC_SOURCE_ON, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+static void _tcpm_pd_vbus_off(struct tcpm_port *port)
+{
+ enum tcpm_state new_state;
+
+ tcpm_log_force(port, "VBUS off");
+ port->vbus_present = false;
+ port->vbus_never_low = false;
+ switch (port->state) {
+ case SNK_HARD_RESET_SINK_OFF:
+ tcpm_set_state(port, SNK_HARD_RESET_WAIT_VBUS, 0);
+ break;
+ case SRC_HARD_RESET_VBUS_OFF:
+ tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, 0);
+ break;
+ case HARD_RESET_SEND:
+ break;
+
+ case SNK_TRY:
+ /* Do nothing, waiting for timeout */
+ break;
+ case SRC_TRYWAIT:
+ /* Hand over to state machine if needed */
+ if (tcpm_port_is_source(port))
+ new_state = SRC_ATTACHED;
+ else
+ new_state = SRC_TRYWAIT_UNATTACHED;
+ if (new_state != port->delayed_state)
+ tcpm_set_state(port, SRC_TRYWAIT, 0);
+ break;
+ case SNK_TRY_WAIT:
+ if (!tcpm_port_is_sink(port))
+ new_state = SRC_TRYWAIT;
+ else
+ new_state = SRC_TRYWAIT_UNATTACHED;
+
+ if (new_state != port->delayed_state)
+ tcpm_set_state(port, SNK_TRY_WAIT, 0);
+ break;
+ case SNK_TRYWAIT_VBUS:
+ tcpm_set_state(port, SNK_TRYWAIT, 0);
+ break;
+
+ case SNK_ATTACH_WAIT:
+ tcpm_set_state(port, SNK_UNATTACHED, 0);
+ break;
+
+ case SNK_NEGOTIATE_CAPABILITIES:
+ break;
+
+ case PR_SWAP_SRC_SNK_TRANSITION_OFF:
+ /*
+ * At this moment, vbus may only fall to be below 4v,
+ * we need wait tPSSourceOff and let vbus discharge
+ * finished.
+ */
+ if (!port->tcpc->vbus_discharge)
+ tcpm_set_state(port, PR_SWAP_SRC_SNK_SOURCE_OFF, 0);
+ break;
+
+ case PR_SWAP_SNK_SRC_SINK_OFF:
+ /* Do nothing, expected */
+ break;
+
+ case ERROR_RECOVERY_WAIT_OFF:
+ tcpm_set_state(port,
+ port->pwr_role == TYPEC_SOURCE ?
+ SRC_UNATTACHED : SNK_UNATTACHED,
+ 0);
+ break;
+
+ default:
+ if (port->pwr_role == TYPEC_SINK &&
+ port->attached)
+ tcpm_set_state(port, SNK_UNATTACHED, 0);
+ break;
+ }
+}
+
+static void _tcpm_pd_hard_reset(struct tcpm_port *port)
+{
+ tcpm_log_force(port, "Received hard reset");
+ /*
+ * If we keep receiving hard reset requests, executing the hard reset
+ * must have failed. Revert to error recovery if that happens.
+ */
+ tcpm_set_state(port,
+ port->hard_reset_count < PD_N_HARD_RESET_COUNT ?
+ HARD_RESET_START : ERROR_RECOVERY,
+ 0);
+}
+
+static void _tcpm_vbus_discharge(struct tcpm_port *port, bool on)
+{
+ tcpm_log_force(port, "%s force discharge", on ? "Enable":"Disable");
+
+ /*
+ * By vbus discharge and low alarm, now we can disable
+ * vbus discharge.
+ */
+ if (port->tcpc && port->tcpc->vbus_discharge)
+ port->tcpc->vbus_discharge(port->tcpc, false);
+
+ /* We can transit to PR_SWAP_SRC_SNK_SOURCE_OFF safely */
+ if (port->state == PR_SWAP_SRC_SNK_TRANSITION_OFF)
+ tcpm_set_state(port, PR_SWAP_SRC_SNK_SOURCE_OFF, 0);
+}
+
+static void tcpm_pd_event_handler(struct work_struct *work)
+{
+ struct tcpm_port *port = container_of(work, struct tcpm_port,
+ event_work);
+ u32 events;
+
+ mutex_lock(&port->lock);
+
+ spin_lock(&port->pd_event_lock);
+ while (port->pd_events) {
+ events = port->pd_events;
+ port->pd_events = 0;
+ spin_unlock(&port->pd_event_lock);
+ if (events & TCPM_RESET_EVENT)
+ _tcpm_pd_hard_reset(port);
+ if (events & TCPM_VBUS_EVENT) {
+ bool vbus;
+
+ vbus = port->tcpc->get_vbus(port->tcpc);
+ if (vbus)
+ _tcpm_pd_vbus_on(port);
+ else
+ _tcpm_pd_vbus_off(port);
+ }
+
+ if (events & TCPM_VBUS_LOW_ALARM)
+ _tcpm_vbus_discharge(port, false);
+
+ if (events & TCPM_CC_EVENT) {
+ enum typec_cc_status cc1, cc2;
+
+ if (port->tcpc->get_cc(port->tcpc, &cc1, &cc2) == 0)
+ _tcpm_cc_change(port, cc1, cc2);
+ }
+ spin_lock(&port->pd_event_lock);
+ }
+ spin_unlock(&port->pd_event_lock);
+ mutex_unlock(&port->lock);
+}
+
+void tcpm_cc_change(struct tcpm_port *port)
+{
+ spin_lock(&port->pd_event_lock);
+ port->pd_events |= TCPM_CC_EVENT;
+ spin_unlock(&port->pd_event_lock);
+ queue_work(port->wq, &port->event_work);
+}
+EXPORT_SYMBOL_GPL(tcpm_cc_change);
+
+void tcpm_vbus_change(struct tcpm_port *port)
+{
+ spin_lock(&port->pd_event_lock);
+ port->pd_events |= TCPM_VBUS_EVENT;
+ spin_unlock(&port->pd_event_lock);
+ queue_work(port->wq, &port->event_work);
+}
+EXPORT_SYMBOL_GPL(tcpm_vbus_change);
+
+void tcpm_vbus_low_alarm(struct tcpm_port *port)
+{
+ spin_lock(&port->pd_event_lock);
+ port->pd_events |= TCPM_VBUS_LOW_ALARM;
+ spin_unlock(&port->pd_event_lock);
+ queue_work(port->wq, &port->event_work);
+}
+EXPORT_SYMBOL_GPL(tcpm_vbus_low_alarm);
+
+void tcpm_pd_hard_reset(struct tcpm_port *port)
+{
+ spin_lock(&port->pd_event_lock);
+ port->pd_events = TCPM_RESET_EVENT;
+ spin_unlock(&port->pd_event_lock);
+ queue_work(port->wq, &port->event_work);
+}
+EXPORT_SYMBOL_GPL(tcpm_pd_hard_reset);
+
+static int tcpm_dr_set(const struct typec_capability *cap,
+ enum typec_data_role data)
+{
+ struct tcpm_port *port = typec_cap_to_tcpm(cap);
+ int ret;
+
+ mutex_lock(&port->swap_lock);
+ mutex_lock(&port->lock);
+
+ if (port->typec_caps.type != TYPEC_PORT_DRP || !port->pd_capable) {
+ ret = -EINVAL;
+ goto port_unlock;
+ }
+ if (port->state != SRC_READY && port->state != SNK_READY) {
+ ret = -EAGAIN;
+ goto port_unlock;
+ }
+
+ if (port->data_role == data) {
+ ret = 0;
+ goto port_unlock;
+ }
+
+ /*
+ * XXX
+ * 6.3.9: If an alternate mode is active, a request to swap
+ * alternate modes shall trigger a port reset.
+ * Reject data role swap request in this case.
+ */
+
+ port->swap_status = 0;
+ port->swap_pending = true;
+ reinit_completion(&port->swap_complete);
+ tcpm_set_state(port, DR_SWAP_SEND, 0);
+ mutex_unlock(&port->lock);
+
+ wait_for_completion(&port->swap_complete);
+
+ ret = port->swap_status;
+ goto swap_unlock;
+
+port_unlock:
+ mutex_unlock(&port->lock);
+swap_unlock:
+ mutex_unlock(&port->swap_lock);
+ return ret;
+}
+
+static int tcpm_pr_set(const struct typec_capability *cap,
+ enum typec_role role)
+{
+ struct tcpm_port *port = typec_cap_to_tcpm(cap);
+ int ret;
+
+ mutex_lock(&port->swap_lock);
+ mutex_lock(&port->lock);
+
+ if (port->typec_caps.type != TYPEC_PORT_DRP) {
+ ret = -EINVAL;
+ goto port_unlock;
+ }
+ if (port->state != SRC_READY && port->state != SNK_READY) {
+ ret = -EAGAIN;
+ goto port_unlock;
+ }
+
+ if (role == port->pwr_role) {
+ ret = 0;
+ goto port_unlock;
+ }
+
+ if (!port->pd_capable) {
+ /*
+ * If the partner is not PD capable, reset the port to
+ * trigger a role change. This can only work if a preferred
+ * role is configured, and if it matches the requested role.
+ */
+ if (port->try_role == TYPEC_NO_PREFERRED_ROLE ||
+ port->try_role == port->pwr_role) {
+ ret = -EINVAL;
+ goto port_unlock;
+ }
+ tcpm_set_state(port, HARD_RESET_SEND, 0);
+ ret = 0;
+ goto port_unlock;
+ }
+
+ port->swap_status = 0;
+ port->swap_pending = true;
+ reinit_completion(&port->swap_complete);
+ tcpm_set_state(port, PR_SWAP_SEND, 0);
+ mutex_unlock(&port->lock);
+
+ wait_for_completion(&port->swap_complete);
+
+ ret = port->swap_status;
+ goto swap_unlock;
+
+port_unlock:
+ mutex_unlock(&port->lock);
+swap_unlock:
+ mutex_unlock(&port->swap_lock);
+ return ret;
+}
+
+static int tcpm_vconn_set(const struct typec_capability *cap,
+ enum typec_role role)
+{
+ struct tcpm_port *port = typec_cap_to_tcpm(cap);
+ int ret;
+
+ mutex_lock(&port->swap_lock);
+ mutex_lock(&port->lock);
+
+ if (port->state != SRC_READY && port->state != SNK_READY) {
+ ret = -EAGAIN;
+ goto port_unlock;
+ }
+
+ if (role == port->vconn_role) {
+ ret = 0;
+ goto port_unlock;
+ }
+
+ port->swap_status = 0;
+ port->swap_pending = true;
+ reinit_completion(&port->swap_complete);
+ tcpm_set_state(port, VCONN_SWAP_SEND, 0);
+ mutex_unlock(&port->lock);
+
+ wait_for_completion(&port->swap_complete);
+
+ ret = port->swap_status;
+ goto swap_unlock;
+
+port_unlock:
+ mutex_unlock(&port->lock);
+swap_unlock:
+ mutex_unlock(&port->swap_lock);
+ return ret;
+}
+
+static int tcpm_try_role(const struct typec_capability *cap, int role)
+{
+ struct tcpm_port *port = typec_cap_to_tcpm(cap);
+ struct tcpc_dev *tcpc = port->tcpc;
+ int ret = 0;
+
+ mutex_lock(&port->lock);
+ if (tcpc->try_role)
+ ret = tcpc->try_role(tcpc, role);
+ if (!ret && !tcpc->config->try_role_hw)
+ port->try_role = role;
+ port->try_src_count = 0;
+ port->try_snk_count = 0;
+ mutex_unlock(&port->lock);
+
+ return ret;
+}
+
+static void tcpm_init(struct tcpm_port *port)
+{
+ enum typec_cc_status cc1, cc2;
+
+ /*
+ * Possibly the vbus was enabled locally which is wrong, we can
+ * firstly disable power sink then start tcpm state transition
+ * to fix it, this is different from dead battery case which can
+ * detect RP on cc , in case of dead battery boot, we don't disable
+ * vbus sink for charging.
+ */
+ if (port->tcpc->get_cc(port->tcpc, &cc1, &cc2))
+ return;
+
+ port->vbus_present = port->tcpc->get_vbus(port->tcpc);
+ if ((cc1 >= TYPEC_CC_RP_DEF || cc2 >= TYPEC_CC_RP_DEF) &&
+ port->vbus_present)
+ port->vbus_never_low = true;
+
+ tcpm_reset_port(port);
+
+ tcpm_set_state(port, tcpm_default_state(port), 0);
+
+ _tcpm_cc_change(port, cc1, cc2);
+
+ /*
+ * Some adapters need a clean slate at startup, and won't recover
+ * otherwise. So do not try to be fancy and force a clean disconnect.
+ */
+ /*tcpm_set_state(port, ERROR_RECOVERY, 0);*/
+
+ port->tcpc->init(port->tcpc);
+}
+
+void tcpm_tcpc_reset(struct tcpm_port *port)
+{
+ mutex_lock(&port->lock);
+ /* XXX: Maintain PD connection if possible? */
+ tcpm_init(port);
+ mutex_unlock(&port->lock);
+}
+EXPORT_SYMBOL_GPL(tcpm_tcpc_reset);
+
+static int tcpm_copy_pdos(u32 *dest_pdo, const u32 *src_pdo,
+ unsigned int nr_pdo)
+{
+ unsigned int i;
+
+ if (nr_pdo > PDO_MAX_OBJECTS)
+ nr_pdo = PDO_MAX_OBJECTS;
+
+ for (i = 0; i < nr_pdo; i++)
+ dest_pdo[i] = src_pdo[i];
+
+ return nr_pdo;
+}
+
+void tcpm_update_source_capabilities(struct tcpm_port *port, const u32 *pdo,
+ unsigned int nr_pdo)
+{
+ mutex_lock(&port->lock);
+ port->nr_src_pdo = tcpm_copy_pdos(port->src_pdo, pdo, nr_pdo);
+ switch (port->state) {
+ case SRC_UNATTACHED:
+ case SRC_ATTACH_WAIT:
+ case SRC_TRYWAIT:
+ tcpm_set_cc(port, tcpm_rp_cc(port));
+ break;
+ case SRC_SEND_CAPABILITIES:
+ case SRC_NEGOTIATE_CAPABILITIES:
+ case SRC_READY:
+ case SRC_WAIT_NEW_CAPABILITIES:
+ tcpm_set_cc(port, tcpm_rp_cc(port));
+ tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&port->lock);
+}
+EXPORT_SYMBOL_GPL(tcpm_update_source_capabilities);
+
+void tcpm_update_sink_capabilities(struct tcpm_port *port, const u32 *pdo,
+ unsigned int nr_pdo,
+ unsigned int max_snk_mv,
+ unsigned int max_snk_ma,
+ unsigned int max_snk_mw,
+ unsigned int operating_snk_mw)
+{
+ mutex_lock(&port->lock);
+ port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, pdo, nr_pdo);
+ port->max_snk_mv = max_snk_mv;
+ port->max_snk_ma = max_snk_ma;
+ port->max_snk_mw = max_snk_mw;
+ port->operating_snk_mw = operating_snk_mw;
+
+ switch (port->state) {
+ case SNK_NEGOTIATE_CAPABILITIES:
+ case SNK_READY:
+ case SNK_TRANSITION_SINK:
+ case SNK_TRANSITION_SINK_VBUS:
+ tcpm_set_state(port, SNK_NEGOTIATE_CAPABILITIES, 0);
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&port->lock);
+}
+EXPORT_SYMBOL_GPL(tcpm_update_sink_capabilities);
+
+struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
+{
+ struct tcpm_port *port;
+ int i, err;
+
+ if (!dev || !tcpc || !tcpc->config ||
+ !tcpc->get_vbus || !tcpc->set_cc || !tcpc->get_cc ||
+ !tcpc->set_polarity || !tcpc->set_vconn || !tcpc->set_vbus ||
+ !tcpc->set_pd_rx || !tcpc->set_roles || !tcpc->pd_transmit)
+ return ERR_PTR(-EINVAL);
+
+ port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return ERR_PTR(-ENOMEM);
+
+ port->dev = dev;
+ port->tcpc = tcpc;
+
+ mutex_init(&port->lock);
+ mutex_init(&port->swap_lock);
+
+ port->wq = create_singlethread_workqueue(dev_name(dev));
+ if (!port->wq)
+ return ERR_PTR(-ENOMEM);
+ INIT_DELAYED_WORK(&port->state_machine, tcpm_state_machine_work);
+ INIT_DELAYED_WORK(&port->vdm_state_machine, vdm_state_machine_work);
+ INIT_WORK(&port->event_work, tcpm_pd_event_handler);
+
+ spin_lock_init(&port->pd_event_lock);
+
+ init_completion(&port->tx_complete);
+ init_completion(&port->swap_complete);
+
+ port->nr_src_pdo = tcpm_copy_pdos(port->src_pdo, tcpc->config->src_pdo,
+ tcpc->config->nr_src_pdo);
+ port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, tcpc->config->snk_pdo,
+ tcpc->config->nr_snk_pdo);
+
+ port->max_snk_mv = tcpc->config->max_snk_mv;
+ port->max_snk_ma = tcpc->config->max_snk_ma;
+ port->max_snk_mw = tcpc->config->max_snk_mw;
+ port->operating_snk_mw = tcpc->config->operating_snk_mw;
+ if (!tcpc->config->try_role_hw)
+ port->try_role = tcpc->config->default_role;
+ else
+ port->try_role = TYPEC_NO_PREFERRED_ROLE;
+
+ port->typec_caps.prefer_role = tcpc->config->default_role;
+ port->typec_caps.type = tcpc->config->type;
+ port->typec_caps.revision = 0x0120; /* Type-C spec release 1.2 */
+ port->typec_caps.pd_revision = 0x0200; /* USB-PD spec release 2.0 */
+ port->typec_caps.dr_set = tcpm_dr_set;
+ port->typec_caps.pr_set = tcpm_pr_set;
+ port->typec_caps.vconn_set = tcpm_vconn_set;
+ port->typec_caps.try_role = tcpm_try_role;
+
+ port->partner_desc.identity = &port->partner_ident;
+
+ /*
+ * TODO:
+ * - alt_modes, set_alt_mode
+ * - {debug,audio}_accessory
+ */
+
+ port->typec_port = typec_register_port(port->dev, &port->typec_caps);
+ if (!port->typec_port) {
+ err = -ENOMEM;
+ goto out_destroy_wq;
+ }
+
+ if (tcpc->config->alt_modes) {
+ struct typec_altmode_desc *paltmode = tcpc->config->alt_modes;
+
+ i = 0;
+ while (paltmode->svid && i < ARRAY_SIZE(port->port_altmode)) {
+ port->port_altmode[i] =
+ typec_port_register_altmode(port->typec_port,
+ paltmode);
+ if (!port->port_altmode[i]) {
+ tcpm_log(port,
+ "%s: failed to register port alternate mode 0x%x",
+ dev_name(dev), paltmode->svid);
+ break;
+ }
+ i++;
+ paltmode++;
+ }
+ }
+
+ hrtimer_init(&port->snd_res_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ port->snd_res_timer.function = tcpm_sender_res_handle;
+
+ tcpm_debugfs_init(port);
+ mutex_lock(&port->lock);
+ request_bus_freq(BUS_FREQ_HIGH);
+ pm_qos_add_request(&port->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, 0);
+
+ tcpm_init(port);
+ mutex_unlock(&port->lock);
+
+ tcpm_log(port, "%s: registered", dev_name(dev));
+ return port;
+
+out_destroy_wq:
+ destroy_workqueue(port->wq);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(tcpm_register_port);
+
+void tcpm_unregister_port(struct tcpm_port *port)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(port->port_altmode); i++)
+ typec_unregister_altmode(port->port_altmode[i]);
+ typec_unregister_port(port->typec_port);
+ tcpm_debugfs_exit(port);
+ destroy_workqueue(port->wq);
+}
+EXPORT_SYMBOL_GPL(tcpm_unregister_port);
+
+MODULE_AUTHOR("Guenter Roeck <groeck@chromium.org>");
+MODULE_DESCRIPTION("USB Type-C Port Manager");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/typec/tcpm.h b/drivers/staging/typec/tcpm.h
new file mode 100644
index 000000000000..59b939933692
--- /dev/null
+++ b/drivers/staging/typec/tcpm.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2015-2017 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_USB_TCPM_H
+#define __LINUX_USB_TCPM_H
+
+#include <linux/bitops.h>
+#include <linux/usb/typec.h>
+#include "pd.h"
+
+/* VBUS off level should be lower than it */
+#define TCPM_VBUS_PRESENT_LEVEL 600
+
+enum typec_cc_status {
+ TYPEC_CC_OPEN,
+ TYPEC_CC_RA,
+ TYPEC_CC_RD,
+ TYPEC_CC_RP_DEF,
+ TYPEC_CC_RP_1_5,
+ TYPEC_CC_RP_3_0,
+};
+
+enum typec_cc_polarity {
+ TYPEC_POLARITY_CC1,
+ TYPEC_POLARITY_CC2,
+};
+
+/* Time to wait for TCPC to complete transmit */
+#define PD_T_TCPC_TX_TIMEOUT 100
+
+enum tcpm_transmit_status {
+ TCPC_TX_SUCCESS = 0,
+ TCPC_TX_DISCARDED = 1,
+ TCPC_TX_FAILED = 2,
+};
+
+enum tcpm_transmit_type {
+ TCPC_TX_SOP = 0,
+ TCPC_TX_SOP_PRIME = 1,
+ TCPC_TX_SOP_PRIME_PRIME = 2,
+ TCPC_TX_SOP_DEBUG_PRIME = 3,
+ TCPC_TX_SOP_DEBUG_PRIME_PRIME = 4,
+ TCPC_TX_HARD_RESET = 5,
+ TCPC_TX_CABLE_RESET = 6,
+ TCPC_TX_BIST_MODE_2 = 7
+};
+
+struct tcpc_config {
+ u32 *src_pdo;
+ unsigned int nr_src_pdo;
+
+ u32 *snk_pdo;
+ unsigned int nr_snk_pdo;
+
+ unsigned int max_snk_mv;
+ unsigned int max_snk_ma;
+ unsigned int max_snk_mw;
+ unsigned int operating_snk_mw;
+
+ enum typec_port_type type;
+ enum typec_role default_role;
+ bool try_role_hw; /* try.{src,snk} implemented in hardware */
+
+ struct typec_altmode_desc *alt_modes;
+};
+
+enum tcpc_usb_switch {
+ TCPC_USB_SWITCH_CONNECT,
+ TCPC_USB_SWITCH_DISCONNECT,
+ TCPC_USB_SWITCH_RESTORE, /* TODO FIXME */
+};
+
+/* Mux state attributes */
+#define TCPC_MUX_USB_ENABLED BIT(0) /* USB enabled */
+#define TCPC_MUX_DP_ENABLED BIT(1) /* DP enabled */
+#define TCPC_MUX_POLARITY_INVERTED BIT(2) /* Polarity inverted */
+
+/* Mux modes, decoded to attributes */
+enum tcpc_mux_mode {
+ TYPEC_MUX_NONE = 0, /* Open switch */
+ TYPEC_MUX_USB = TCPC_MUX_USB_ENABLED, /* USB only */
+ TYPEC_MUX_DP = TCPC_MUX_DP_ENABLED, /* DP only */
+ TYPEC_MUX_DOCK = TCPC_MUX_USB_ENABLED | /* Both USB and DP */
+ TCPC_MUX_DP_ENABLED,
+};
+
+struct tcpc_mux_dev {
+ int (*set)(struct tcpc_mux_dev *dev, enum tcpc_mux_mode mux_mode,
+ enum tcpc_usb_switch usb_config,
+ enum typec_cc_polarity polarity);
+ bool dfp_only;
+ void *priv_data;
+};
+
+struct tcpc_dev {
+ struct tcpc_config *config;
+
+ int (*init)(struct tcpc_dev *dev);
+ int (*get_vbus)(struct tcpc_dev *dev);
+ /* Optional, get the vbus voltage(mv) */
+ unsigned int (*get_vbus_vol)(struct tcpc_dev *dev);
+ int (*set_cc)(struct tcpc_dev *dev, enum typec_cc_status cc);
+ int (*get_cc)(struct tcpc_dev *dev, enum typec_cc_status *cc1,
+ enum typec_cc_status *cc2);
+ int (*set_polarity)(struct tcpc_dev *dev,
+ enum typec_cc_polarity polarity);
+ int (*set_vconn)(struct tcpc_dev *dev, bool on);
+ int (*set_vbus)(struct tcpc_dev *dev, bool on, bool charge);
+ int (*set_current_limit)(struct tcpc_dev *dev, u32 max_ma, u32 mv);
+ int (*set_pd_rx)(struct tcpc_dev *dev, bool on);
+ int (*set_roles)(struct tcpc_dev *dev, bool attached,
+ enum typec_role role, enum typec_data_role data);
+ int (*start_drp_toggling)(struct tcpc_dev *dev,
+ enum typec_cc_status cc, int attach);
+ int (*try_role)(struct tcpc_dev *dev, int role);
+ int (*pd_transmit)(struct tcpc_dev *dev, enum tcpm_transmit_type type,
+ const struct pd_message *msg);
+ int (*vbus_detect)(struct tcpc_dev *dev, bool enable);
+ int (*vbus_discharge)(struct tcpc_dev *tcpc, bool enable);
+ void (*bist_mode)(struct tcpc_dev *tcpc, bool enable);
+ int (*ss_mux_sel)(struct tcpc_dev *dev,
+ enum typec_cc_polarity polarity);
+
+ struct tcpc_mux_dev *mux;
+};
+
+struct tcpm_port;
+
+struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc);
+void tcpm_unregister_port(struct tcpm_port *port);
+
+void tcpm_update_source_capabilities(struct tcpm_port *port, const u32 *pdo,
+ unsigned int nr_pdo);
+void tcpm_update_sink_capabilities(struct tcpm_port *port, const u32 *pdo,
+ unsigned int nr_pdo,
+ unsigned int max_snk_mv,
+ unsigned int max_snk_ma,
+ unsigned int max_snk_mw,
+ unsigned int operating_snk_mw);
+
+void tcpm_vbus_change(struct tcpm_port *port);
+void tcpm_cc_change(struct tcpm_port *port);
+void tcpm_pd_receive(struct tcpm_port *port,
+ const struct pd_message *msg);
+void tcpm_pd_transmit_complete(struct tcpm_port *port,
+ enum tcpm_transmit_status status);
+void tcpm_pd_hard_reset(struct tcpm_port *port);
+void tcpm_tcpc_reset(struct tcpm_port *port);
+void tcpm_vbus_low_alarm(struct tcpm_port *port);
+
+#endif /* __LINUX_USB_TCPM_H */
diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig
new file mode 100644
index 000000000000..a6df12d88f90
--- /dev/null
+++ b/drivers/tee/Kconfig
@@ -0,0 +1,19 @@
+# Generic Trusted Execution Environment Configuration
+config TEE
+ tristate "Trusted Execution Environment support"
+ depends on HAVE_ARM_SMCCC || COMPILE_TEST
+ select DMA_SHARED_BUFFER
+ select GENERIC_ALLOCATOR
+ help
+ This implements a generic interface towards a Trusted Execution
+ Environment (TEE).
+
+if TEE
+
+menu "TEE drivers"
+
+source "drivers/tee/optee/Kconfig"
+
+endmenu
+
+endif
diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile
new file mode 100644
index 000000000000..7a4e4a1ac39c
--- /dev/null
+++ b/drivers/tee/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_TEE) += tee.o
+tee-objs += tee_core.o
+tee-objs += tee_shm.o
+tee-objs += tee_shm_pool.o
+obj-$(CONFIG_OPTEE) += optee/
diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig
new file mode 100644
index 000000000000..0126de898036
--- /dev/null
+++ b/drivers/tee/optee/Kconfig
@@ -0,0 +1,7 @@
+# OP-TEE Trusted Execution Environment Configuration
+config OPTEE
+ tristate "OP-TEE"
+ depends on HAVE_ARM_SMCCC
+ help
+ This implements the OP-TEE Trusted Execution Environment (TEE)
+ driver.
diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile
new file mode 100644
index 000000000000..92fe5789bcce
--- /dev/null
+++ b/drivers/tee/optee/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_OPTEE) += optee.o
+optee-objs += core.o
+optee-objs += call.o
+optee-objs += rpc.o
+optee-objs += supp.o
diff --git a/drivers/tee/optee/call.c b/drivers/tee/optee/call.c
new file mode 100644
index 000000000000..f7b7b404c990
--- /dev/null
+++ b/drivers/tee/optee/call.c
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/arm-smccc.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include "optee_private.h"
+#include "optee_smc.h"
+
+struct optee_call_waiter {
+ struct list_head list_node;
+ struct completion c;
+};
+
+static void optee_cq_wait_init(struct optee_call_queue *cq,
+ struct optee_call_waiter *w)
+{
+ /*
+ * We're preparing to make a call to secure world. In case we can't
+ * allocate a thread in secure world we'll end up waiting in
+ * optee_cq_wait_for_completion().
+ *
+ * Normally if there's no contention in secure world the call will
+ * complete and we can cleanup directly with optee_cq_wait_final().
+ */
+ mutex_lock(&cq->mutex);
+
+ /*
+ * We add ourselves to the queue, but we don't wait. This
+ * guarantees that we don't lose a completion if secure world
+ * returns busy and another thread just exited and try to complete
+ * someone.
+ */
+ init_completion(&w->c);
+ list_add_tail(&w->list_node, &cq->waiters);
+
+ mutex_unlock(&cq->mutex);
+}
+
+static void optee_cq_wait_for_completion(struct optee_call_queue *cq,
+ struct optee_call_waiter *w)
+{
+ wait_for_completion(&w->c);
+
+ mutex_lock(&cq->mutex);
+
+ /* Move to end of list to get out of the way for other waiters */
+ list_del(&w->list_node);
+ reinit_completion(&w->c);
+ list_add_tail(&w->list_node, &cq->waiters);
+
+ mutex_unlock(&cq->mutex);
+}
+
+static void optee_cq_complete_one(struct optee_call_queue *cq)
+{
+ struct optee_call_waiter *w;
+
+ list_for_each_entry(w, &cq->waiters, list_node) {
+ if (!completion_done(&w->c)) {
+ complete(&w->c);
+ break;
+ }
+ }
+}
+
+static void optee_cq_wait_final(struct optee_call_queue *cq,
+ struct optee_call_waiter *w)
+{
+ /*
+ * We're done with the call to secure world. The thread in secure
+ * world that was used for this call is now available for some
+ * other task to use.
+ */
+ mutex_lock(&cq->mutex);
+
+ /* Get out of the list */
+ list_del(&w->list_node);
+
+ /* Wake up one eventual waiting task */
+ optee_cq_complete_one(cq);
+
+ /*
+ * If we're completed we've got a completion from another task that
+ * was just done with its call to secure world. Since yet another
+ * thread now is available in secure world wake up another eventual
+ * waiting task.
+ */
+ if (completion_done(&w->c))
+ optee_cq_complete_one(cq);
+
+ mutex_unlock(&cq->mutex);
+}
+
+/* Requires the filpstate mutex to be held */
+static struct optee_session *find_session(struct optee_context_data *ctxdata,
+ u32 session_id)
+{
+ struct optee_session *sess;
+
+ list_for_each_entry(sess, &ctxdata->sess_list, list_node)
+ if (sess->session_id == session_id)
+ return sess;
+
+ return NULL;
+}
+
+/**
+ * optee_do_call_with_arg() - Do an SMC to OP-TEE in secure world
+ * @ctx: calling context
+ * @parg: physical address of message to pass to secure world
+ *
+ * Does and SMC to OP-TEE in secure world and handles eventual resulting
+ * Remote Procedure Calls (RPC) from OP-TEE.
+ *
+ * Returns return code from secure world, 0 is OK
+ */
+u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg)
+{
+ struct optee *optee = tee_get_drvdata(ctx->teedev);
+ struct optee_call_waiter w;
+ struct optee_rpc_param param = { };
+ u32 ret;
+
+ param.a0 = OPTEE_SMC_CALL_WITH_ARG;
+ reg_pair_from_64(&param.a1, &param.a2, parg);
+ /* Initialize waiter */
+ optee_cq_wait_init(&optee->call_queue, &w);
+ while (true) {
+ struct arm_smccc_res res;
+
+ optee->invoke_fn(param.a0, param.a1, param.a2, param.a3,
+ param.a4, param.a5, param.a6, param.a7,
+ &res);
+
+ if (res.a0 == OPTEE_SMC_RETURN_ETHREAD_LIMIT) {
+ /*
+ * Out of threads in secure world, wait for a thread
+ * become available.
+ */
+ optee_cq_wait_for_completion(&optee->call_queue, &w);
+ } else if (OPTEE_SMC_RETURN_IS_RPC(res.a0)) {
+ param.a0 = res.a0;
+ param.a1 = res.a1;
+ param.a2 = res.a2;
+ param.a3 = res.a3;
+ optee_handle_rpc(ctx, &param);
+ } else {
+ ret = res.a0;
+ break;
+ }
+ }
+
+ /*
+ * We're done with our thread in secure world, if there's any
+ * thread waiters wake up one.
+ */
+ optee_cq_wait_final(&optee->call_queue, &w);
+
+ return ret;
+}
+
+static struct tee_shm *get_msg_arg(struct tee_context *ctx, size_t num_params,
+ struct optee_msg_arg **msg_arg,
+ phys_addr_t *msg_parg)
+{
+ int rc;
+ struct tee_shm *shm;
+ struct optee_msg_arg *ma;
+
+ shm = tee_shm_alloc(ctx, OPTEE_MSG_GET_ARG_SIZE(num_params),
+ TEE_SHM_MAPPED);
+ if (IS_ERR(shm))
+ return shm;
+
+ ma = tee_shm_get_va(shm, 0);
+ if (IS_ERR(ma)) {
+ rc = PTR_ERR(ma);
+ goto out;
+ }
+
+ rc = tee_shm_get_pa(shm, 0, msg_parg);
+ if (rc)
+ goto out;
+
+ memset(ma, 0, OPTEE_MSG_GET_ARG_SIZE(num_params));
+ ma->num_params = num_params;
+ *msg_arg = ma;
+out:
+ if (rc) {
+ tee_shm_free(shm);
+ return ERR_PTR(rc);
+ }
+
+ return shm;
+}
+
+int optee_open_session(struct tee_context *ctx,
+ struct tee_ioctl_open_session_arg *arg,
+ struct tee_param *param)
+{
+ struct optee_context_data *ctxdata = ctx->data;
+ int rc;
+ struct tee_shm *shm;
+ struct optee_msg_arg *msg_arg;
+ phys_addr_t msg_parg;
+ struct optee_session *sess = NULL;
+
+ /* +2 for the meta parameters added below */
+ shm = get_msg_arg(ctx, arg->num_params + 2, &msg_arg, &msg_parg);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+ msg_arg->cmd = OPTEE_MSG_CMD_OPEN_SESSION;
+ msg_arg->cancel_id = arg->cancel_id;
+
+ /*
+ * Initialize and add the meta parameters needed when opening a
+ * session.
+ */
+ msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT |
+ OPTEE_MSG_ATTR_META;
+ msg_arg->params[1].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT |
+ OPTEE_MSG_ATTR_META;
+ memcpy(&msg_arg->params[0].u.value, arg->uuid, sizeof(arg->uuid));
+ memcpy(&msg_arg->params[1].u.value, arg->uuid, sizeof(arg->clnt_uuid));
+ msg_arg->params[1].u.value.c = arg->clnt_login;
+
+ rc = optee_to_msg_param(msg_arg->params + 2, arg->num_params, param);
+ if (rc)
+ goto out;
+
+ sess = kzalloc(sizeof(*sess), GFP_KERNEL);
+ if (!sess) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ if (optee_do_call_with_arg(ctx, msg_parg)) {
+ msg_arg->ret = TEEC_ERROR_COMMUNICATION;
+ msg_arg->ret_origin = TEEC_ORIGIN_COMMS;
+ }
+
+ if (msg_arg->ret == TEEC_SUCCESS) {
+ /* A new session has been created, add it to the list. */
+ sess->session_id = msg_arg->session;
+ mutex_lock(&ctxdata->mutex);
+ list_add(&sess->list_node, &ctxdata->sess_list);
+ mutex_unlock(&ctxdata->mutex);
+ } else {
+ kfree(sess);
+ }
+
+ if (optee_from_msg_param(param, arg->num_params, msg_arg->params + 2)) {
+ arg->ret = TEEC_ERROR_COMMUNICATION;
+ arg->ret_origin = TEEC_ORIGIN_COMMS;
+ /* Close session again to avoid leakage */
+ optee_close_session(ctx, msg_arg->session);
+ } else {
+ arg->session = msg_arg->session;
+ arg->ret = msg_arg->ret;
+ arg->ret_origin = msg_arg->ret_origin;
+ }
+out:
+ tee_shm_free(shm);
+
+ return rc;
+}
+
+int optee_close_session(struct tee_context *ctx, u32 session)
+{
+ struct optee_context_data *ctxdata = ctx->data;
+ struct tee_shm *shm;
+ struct optee_msg_arg *msg_arg;
+ phys_addr_t msg_parg;
+ struct optee_session *sess;
+
+ /* Check that the session is valid and remove it from the list */
+ mutex_lock(&ctxdata->mutex);
+ sess = find_session(ctxdata, session);
+ if (sess)
+ list_del(&sess->list_node);
+ mutex_unlock(&ctxdata->mutex);
+ if (!sess)
+ return -EINVAL;
+ kfree(sess);
+
+ shm = get_msg_arg(ctx, 0, &msg_arg, &msg_parg);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+ msg_arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION;
+ msg_arg->session = session;
+ optee_do_call_with_arg(ctx, msg_parg);
+
+ tee_shm_free(shm);
+ return 0;
+}
+
+int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
+ struct tee_param *param)
+{
+ struct optee_context_data *ctxdata = ctx->data;
+ struct tee_shm *shm;
+ struct optee_msg_arg *msg_arg;
+ phys_addr_t msg_parg;
+ struct optee_session *sess;
+ int rc;
+
+ /* Check that the session is valid */
+ mutex_lock(&ctxdata->mutex);
+ sess = find_session(ctxdata, arg->session);
+ mutex_unlock(&ctxdata->mutex);
+ if (!sess)
+ return -EINVAL;
+
+ shm = get_msg_arg(ctx, arg->num_params, &msg_arg, &msg_parg);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+ msg_arg->cmd = OPTEE_MSG_CMD_INVOKE_COMMAND;
+ msg_arg->func = arg->func;
+ msg_arg->session = arg->session;
+ msg_arg->cancel_id = arg->cancel_id;
+
+ rc = optee_to_msg_param(msg_arg->params, arg->num_params, param);
+ if (rc)
+ goto out;
+
+ if (optee_do_call_with_arg(ctx, msg_parg)) {
+ msg_arg->ret = TEEC_ERROR_COMMUNICATION;
+ msg_arg->ret_origin = TEEC_ORIGIN_COMMS;
+ }
+
+ if (optee_from_msg_param(param, arg->num_params, msg_arg->params)) {
+ msg_arg->ret = TEEC_ERROR_COMMUNICATION;
+ msg_arg->ret_origin = TEEC_ORIGIN_COMMS;
+ }
+
+ arg->ret = msg_arg->ret;
+ arg->ret_origin = msg_arg->ret_origin;
+out:
+ tee_shm_free(shm);
+ return rc;
+}
+
+int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session)
+{
+ struct optee_context_data *ctxdata = ctx->data;
+ struct tee_shm *shm;
+ struct optee_msg_arg *msg_arg;
+ phys_addr_t msg_parg;
+ struct optee_session *sess;
+
+ /* Check that the session is valid */
+ mutex_lock(&ctxdata->mutex);
+ sess = find_session(ctxdata, session);
+ mutex_unlock(&ctxdata->mutex);
+ if (!sess)
+ return -EINVAL;
+
+ shm = get_msg_arg(ctx, 0, &msg_arg, &msg_parg);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+ msg_arg->cmd = OPTEE_MSG_CMD_CANCEL;
+ msg_arg->session = session;
+ msg_arg->cancel_id = cancel_id;
+ optee_do_call_with_arg(ctx, msg_parg);
+
+ tee_shm_free(shm);
+ return 0;
+}
+
+/**
+ * optee_enable_shm_cache() - Enables caching of some shared memory allocation
+ * in OP-TEE
+ * @optee: main service struct
+ */
+void optee_enable_shm_cache(struct optee *optee)
+{
+ struct optee_call_waiter w;
+
+ /* We need to retry until secure world isn't busy. */
+ optee_cq_wait_init(&optee->call_queue, &w);
+ while (true) {
+ struct arm_smccc_res res;
+
+ optee->invoke_fn(OPTEE_SMC_ENABLE_SHM_CACHE, 0, 0, 0, 0, 0, 0,
+ 0, &res);
+ if (res.a0 == OPTEE_SMC_RETURN_OK)
+ break;
+ optee_cq_wait_for_completion(&optee->call_queue, &w);
+ }
+ optee_cq_wait_final(&optee->call_queue, &w);
+}
+
+/**
+ * optee_disable_shm_cache() - Disables caching of some shared memory allocation
+ * in OP-TEE
+ * @optee: main service struct
+ */
+void optee_disable_shm_cache(struct optee *optee)
+{
+ struct optee_call_waiter w;
+
+ /* We need to retry until secure world isn't busy. */
+ optee_cq_wait_init(&optee->call_queue, &w);
+ while (true) {
+ union {
+ struct arm_smccc_res smccc;
+ struct optee_smc_disable_shm_cache_result result;
+ } res;
+
+ optee->invoke_fn(OPTEE_SMC_DISABLE_SHM_CACHE, 0, 0, 0, 0, 0, 0,
+ 0, &res.smccc);
+ if (res.result.status == OPTEE_SMC_RETURN_ENOTAVAIL)
+ break; /* All shm's freed */
+ if (res.result.status == OPTEE_SMC_RETURN_OK) {
+ struct tee_shm *shm;
+
+ shm = reg_pair_to_ptr(res.result.shm_upper32,
+ res.result.shm_lower32);
+ tee_shm_free(shm);
+ } else {
+ optee_cq_wait_for_completion(&optee->call_queue, &w);
+ }
+ }
+ optee_cq_wait_final(&optee->call_queue, &w);
+}
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
new file mode 100644
index 000000000000..d0dd09219795
--- /dev/null
+++ b/drivers/tee/optee/core.c
@@ -0,0 +1,619 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/arm-smccc.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tee_drv.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include "optee_private.h"
+#include "optee_smc.h"
+
+#define DRIVER_NAME "optee"
+
+#define OPTEE_SHM_NUM_PRIV_PAGES 1
+
+/**
+ * optee_from_msg_param() - convert from OPTEE_MSG parameters to
+ * struct tee_param
+ * @params: subsystem internal parameter representation
+ * @num_params: number of elements in the parameter arrays
+ * @msg_params: OPTEE_MSG parameters
+ * Returns 0 on success or <0 on failure
+ */
+int optee_from_msg_param(struct tee_param *params, size_t num_params,
+ const struct optee_msg_param *msg_params)
+{
+ int rc;
+ size_t n;
+ struct tee_shm *shm;
+ phys_addr_t pa;
+
+ for (n = 0; n < num_params; n++) {
+ struct tee_param *p = params + n;
+ const struct optee_msg_param *mp = msg_params + n;
+ u32 attr = mp->attr & OPTEE_MSG_ATTR_TYPE_MASK;
+
+ switch (attr) {
+ case OPTEE_MSG_ATTR_TYPE_NONE:
+ p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
+ memset(&p->u, 0, sizeof(p->u));
+ break;
+ case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT:
+ case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT:
+ case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT:
+ p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT +
+ attr - OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
+ p->u.value.a = mp->u.value.a;
+ p->u.value.b = mp->u.value.b;
+ p->u.value.c = mp->u.value.c;
+ break;
+ case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT:
+ case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
+ case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
+ p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
+ attr - OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
+ p->u.memref.size = mp->u.tmem.size;
+ shm = (struct tee_shm *)(unsigned long)
+ mp->u.tmem.shm_ref;
+ if (!shm) {
+ p->u.memref.shm_offs = 0;
+ p->u.memref.shm = NULL;
+ break;
+ }
+ rc = tee_shm_get_pa(shm, 0, &pa);
+ if (rc)
+ return rc;
+ p->u.memref.shm_offs = mp->u.tmem.buf_ptr - pa;
+ p->u.memref.shm = shm;
+
+ /* Check that the memref is covered by the shm object */
+ if (p->u.memref.size) {
+ size_t o = p->u.memref.shm_offs +
+ p->u.memref.size - 1;
+
+ rc = tee_shm_get_pa(shm, o, NULL);
+ if (rc)
+ return rc;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/**
+ * optee_to_msg_param() - convert from struct tee_params to OPTEE_MSG parameters
+ * @msg_params: OPTEE_MSG parameters
+ * @num_params: number of elements in the parameter arrays
+ * @params: subsystem itnernal parameter representation
+ * Returns 0 on success or <0 on failure
+ */
+int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params,
+ const struct tee_param *params)
+{
+ int rc;
+ size_t n;
+ phys_addr_t pa;
+
+ for (n = 0; n < num_params; n++) {
+ const struct tee_param *p = params + n;
+ struct optee_msg_param *mp = msg_params + n;
+
+ switch (p->attr) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_NONE:
+ mp->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
+ memset(&mp->u, 0, sizeof(mp->u));
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+ mp->attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT + p->attr -
+ TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
+ mp->u.value.a = p->u.value.a;
+ mp->u.value.b = p->u.value.b;
+ mp->u.value.c = p->u.value.c;
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ mp->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT +
+ p->attr -
+ TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
+ mp->u.tmem.shm_ref = (unsigned long)p->u.memref.shm;
+ mp->u.tmem.size = p->u.memref.size;
+ if (!p->u.memref.shm) {
+ mp->u.tmem.buf_ptr = 0;
+ break;
+ }
+ rc = tee_shm_get_pa(p->u.memref.shm,
+ p->u.memref.shm_offs, &pa);
+ if (rc)
+ return rc;
+ mp->u.tmem.buf_ptr = pa;
+ mp->attr |= OPTEE_MSG_ATTR_CACHE_PREDEFINED <<
+ OPTEE_MSG_ATTR_CACHE_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static void optee_get_version(struct tee_device *teedev,
+ struct tee_ioctl_version_data *vers)
+{
+ struct tee_ioctl_version_data v = {
+ .impl_id = TEE_IMPL_ID_OPTEE,
+ .impl_caps = TEE_OPTEE_CAP_TZ,
+ .gen_caps = TEE_GEN_CAP_GP,
+ };
+ *vers = v;
+}
+
+static int optee_open(struct tee_context *ctx)
+{
+ struct optee_context_data *ctxdata;
+ struct tee_device *teedev = ctx->teedev;
+ struct optee *optee = tee_get_drvdata(teedev);
+
+ ctxdata = kzalloc(sizeof(*ctxdata), GFP_KERNEL);
+ if (!ctxdata)
+ return -ENOMEM;
+
+ if (teedev == optee->supp_teedev) {
+ bool busy = true;
+
+ mutex_lock(&optee->supp.mutex);
+ if (!optee->supp.ctx) {
+ busy = false;
+ optee->supp.ctx = ctx;
+ }
+ mutex_unlock(&optee->supp.mutex);
+ if (busy) {
+ kfree(ctxdata);
+ return -EBUSY;
+ }
+ }
+
+ mutex_init(&ctxdata->mutex);
+ INIT_LIST_HEAD(&ctxdata->sess_list);
+
+ ctx->data = ctxdata;
+ return 0;
+}
+
+static void optee_release(struct tee_context *ctx)
+{
+ struct optee_context_data *ctxdata = ctx->data;
+ struct tee_device *teedev = ctx->teedev;
+ struct optee *optee = tee_get_drvdata(teedev);
+ struct tee_shm *shm;
+ struct optee_msg_arg *arg = NULL;
+ phys_addr_t parg;
+ struct optee_session *sess;
+ struct optee_session *sess_tmp;
+
+ if (!ctxdata)
+ return;
+
+ shm = tee_shm_alloc(ctx, sizeof(struct optee_msg_arg), TEE_SHM_MAPPED);
+ if (!IS_ERR(shm)) {
+ arg = tee_shm_get_va(shm, 0);
+ /*
+ * If va2pa fails for some reason, we can't call into
+ * secure world, only free the memory. Secure OS will leak
+ * sessions and finally refuse more sessions, but we will
+ * at least let normal world reclaim its memory.
+ */
+ if (!IS_ERR(arg))
+ if (tee_shm_va2pa(shm, arg, &parg))
+ arg = NULL; /* prevent usage of parg below */
+ }
+
+ list_for_each_entry_safe(sess, sess_tmp, &ctxdata->sess_list,
+ list_node) {
+ list_del(&sess->list_node);
+ if (!IS_ERR_OR_NULL(arg)) {
+ memset(arg, 0, sizeof(*arg));
+ arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION;
+ arg->session = sess->session_id;
+ optee_do_call_with_arg(ctx, parg);
+ }
+ kfree(sess);
+ }
+ kfree(ctxdata);
+
+ if (!IS_ERR(shm))
+ tee_shm_free(shm);
+
+ ctx->data = NULL;
+
+ if (teedev == optee->supp_teedev)
+ optee_supp_release(&optee->supp);
+}
+
+static const struct tee_driver_ops optee_ops = {
+ .get_version = optee_get_version,
+ .open = optee_open,
+ .release = optee_release,
+ .open_session = optee_open_session,
+ .close_session = optee_close_session,
+ .invoke_func = optee_invoke_func,
+ .cancel_req = optee_cancel_req,
+};
+
+static const struct tee_desc optee_desc = {
+ .name = DRIVER_NAME "-clnt",
+ .ops = &optee_ops,
+ .owner = THIS_MODULE,
+};
+
+static const struct tee_driver_ops optee_supp_ops = {
+ .get_version = optee_get_version,
+ .open = optee_open,
+ .release = optee_release,
+ .supp_recv = optee_supp_recv,
+ .supp_send = optee_supp_send,
+};
+
+static const struct tee_desc optee_supp_desc = {
+ .name = DRIVER_NAME "-supp",
+ .ops = &optee_supp_ops,
+ .owner = THIS_MODULE,
+ .flags = TEE_DESC_PRIVILEGED,
+};
+
+static bool optee_msg_api_uid_is_optee_api(optee_invoke_fn *invoke_fn)
+{
+ struct arm_smccc_res res;
+
+ invoke_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &res);
+
+ if (res.a0 == OPTEE_MSG_UID_0 && res.a1 == OPTEE_MSG_UID_1 &&
+ res.a2 == OPTEE_MSG_UID_2 && res.a3 == OPTEE_MSG_UID_3)
+ return true;
+ return false;
+}
+
+static bool optee_msg_api_revision_is_compatible(optee_invoke_fn *invoke_fn)
+{
+ union {
+ struct arm_smccc_res smccc;
+ struct optee_smc_calls_revision_result result;
+ } res;
+
+ invoke_fn(OPTEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
+
+ if (res.result.major == OPTEE_MSG_REVISION_MAJOR &&
+ (int)res.result.minor >= OPTEE_MSG_REVISION_MINOR)
+ return true;
+ return false;
+}
+
+static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn,
+ u32 *sec_caps)
+{
+ union {
+ struct arm_smccc_res smccc;
+ struct optee_smc_exchange_capabilities_result result;
+ } res;
+ u32 a1 = 0;
+
+ /*
+ * TODO This isn't enough to tell if it's UP system (from kernel
+ * point of view) or not, is_smp() returns the the information
+ * needed, but can't be called directly from here.
+ */
+ if (!IS_ENABLED(CONFIG_SMP) || nr_cpu_ids == 1)
+ a1 |= OPTEE_SMC_NSEC_CAP_UNIPROCESSOR;
+
+ invoke_fn(OPTEE_SMC_EXCHANGE_CAPABILITIES, a1, 0, 0, 0, 0, 0, 0,
+ &res.smccc);
+
+ if (res.result.status != OPTEE_SMC_RETURN_OK)
+ return false;
+
+ *sec_caps = res.result.capabilities;
+ return true;
+}
+
+static struct tee_shm_pool *
+optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm)
+{
+ union {
+ struct arm_smccc_res smccc;
+ struct optee_smc_get_shm_config_result result;
+ } res;
+ struct tee_shm_pool *pool;
+ unsigned long vaddr;
+ phys_addr_t paddr;
+ size_t size;
+ phys_addr_t begin;
+ phys_addr_t end;
+ void *va;
+ struct tee_shm_pool_mem_info priv_info;
+ struct tee_shm_pool_mem_info dmabuf_info;
+
+ invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
+ if (res.result.status != OPTEE_SMC_RETURN_OK) {
+ pr_info("shm service not available\n");
+ return ERR_PTR(-ENOENT);
+ }
+
+ if (res.result.settings != OPTEE_SMC_SHM_CACHED) {
+ pr_err("only normal cached shared memory supported\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ begin = roundup(res.result.start, PAGE_SIZE);
+ end = rounddown(res.result.start + res.result.size, PAGE_SIZE);
+ paddr = begin;
+ size = end - begin;
+
+ if (size < 2 * OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE) {
+ pr_err("too small shared memory area\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ va = memremap(paddr, size, MEMREMAP_WB);
+ if (!va) {
+ pr_err("shared memory ioremap failed\n");
+ return ERR_PTR(-EINVAL);
+ }
+ vaddr = (unsigned long)va;
+
+ priv_info.vaddr = vaddr;
+ priv_info.paddr = paddr;
+ priv_info.size = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
+ dmabuf_info.vaddr = vaddr + OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
+ dmabuf_info.paddr = paddr + OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
+ dmabuf_info.size = size - OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
+
+ pool = tee_shm_pool_alloc_res_mem(&priv_info, &dmabuf_info);
+ if (IS_ERR(pool)) {
+ memunmap(va);
+ goto out;
+ }
+
+ *memremaped_shm = va;
+out:
+ return pool;
+}
+
+/* Simple wrapper functions to be able to use a function pointer */
+static void optee_smccc_smc(unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3,
+ unsigned long a4, unsigned long a5,
+ unsigned long a6, unsigned long a7,
+ struct arm_smccc_res *res)
+{
+ arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res);
+}
+
+static void optee_smccc_hvc(unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3,
+ unsigned long a4, unsigned long a5,
+ unsigned long a6, unsigned long a7,
+ struct arm_smccc_res *res)
+{
+ arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res);
+}
+
+static optee_invoke_fn *get_invoke_func(struct device_node *np)
+{
+ const char *method;
+
+ pr_info("probing for conduit method from DT.\n");
+
+ if (of_property_read_string(np, "method", &method)) {
+ pr_warn("missing \"method\" property\n");
+ return ERR_PTR(-ENXIO);
+ }
+
+ if (!strcmp("hvc", method))
+ return optee_smccc_hvc;
+ else if (!strcmp("smc", method))
+ return optee_smccc_smc;
+
+ pr_warn("invalid \"method\" property: %s\n", method);
+ return ERR_PTR(-EINVAL);
+}
+
+static struct optee *optee_probe(struct device_node *np)
+{
+ optee_invoke_fn *invoke_fn;
+ struct tee_shm_pool *pool;
+ struct optee *optee = NULL;
+ void *memremaped_shm = NULL;
+ struct tee_device *teedev;
+ u32 sec_caps;
+ int rc;
+
+ invoke_fn = get_invoke_func(np);
+ if (IS_ERR(invoke_fn))
+ return (void *)invoke_fn;
+
+ if (!optee_msg_api_uid_is_optee_api(invoke_fn)) {
+ pr_warn("api uid mismatch\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
+ pr_warn("api revision mismatch\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!optee_msg_exchange_capabilities(invoke_fn, &sec_caps)) {
+ pr_warn("capabilities mismatch\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ /*
+ * We have no other option for shared memory, if secure world
+ * doesn't have any reserved memory we can use we can't continue.
+ */
+ if (!(sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM))
+ return ERR_PTR(-EINVAL);
+
+ pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm);
+ if (IS_ERR(pool))
+ return (void *)pool;
+
+ optee = kzalloc(sizeof(*optee), GFP_KERNEL);
+ if (!optee) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ optee->invoke_fn = invoke_fn;
+
+ teedev = tee_device_alloc(&optee_desc, NULL, pool, optee);
+ if (IS_ERR(teedev)) {
+ rc = PTR_ERR(teedev);
+ goto err;
+ }
+ optee->teedev = teedev;
+
+ teedev = tee_device_alloc(&optee_supp_desc, NULL, pool, optee);
+ if (IS_ERR(teedev)) {
+ rc = PTR_ERR(teedev);
+ goto err;
+ }
+ optee->supp_teedev = teedev;
+
+ rc = tee_device_register(optee->teedev);
+ if (rc)
+ goto err;
+
+ rc = tee_device_register(optee->supp_teedev);
+ if (rc)
+ goto err;
+
+ mutex_init(&optee->call_queue.mutex);
+ INIT_LIST_HEAD(&optee->call_queue.waiters);
+ optee_wait_queue_init(&optee->wait_queue);
+ optee_supp_init(&optee->supp);
+ optee->memremaped_shm = memremaped_shm;
+ optee->pool = pool;
+
+ optee_enable_shm_cache(optee);
+
+ pr_info("initialized driver\n");
+ return optee;
+err:
+ if (optee) {
+ /*
+ * tee_device_unregister() is safe to call even if the
+ * devices hasn't been registered with
+ * tee_device_register() yet.
+ */
+ tee_device_unregister(optee->supp_teedev);
+ tee_device_unregister(optee->teedev);
+ kfree(optee);
+ }
+ if (pool)
+ tee_shm_pool_free(pool);
+ if (memremaped_shm)
+ memunmap(memremaped_shm);
+ return ERR_PTR(rc);
+}
+
+static void optee_remove(struct optee *optee)
+{
+ /*
+ * Ask OP-TEE to free all cached shared memory objects to decrease
+ * reference counters and also avoid wild pointers in secure world
+ * into the old shared memory range.
+ */
+ optee_disable_shm_cache(optee);
+
+ /*
+ * The two devices has to be unregistered before we can free the
+ * other resources.
+ */
+ tee_device_unregister(optee->supp_teedev);
+ tee_device_unregister(optee->teedev);
+
+ tee_shm_pool_free(optee->pool);
+ if (optee->memremaped_shm)
+ memunmap(optee->memremaped_shm);
+ optee_wait_queue_exit(&optee->wait_queue);
+ optee_supp_uninit(&optee->supp);
+ mutex_destroy(&optee->call_queue.mutex);
+
+ kfree(optee);
+}
+
+static const struct of_device_id optee_match[] = {
+ { .compatible = "linaro,optee-tz" },
+ {},
+};
+
+static struct optee *optee_svc;
+
+static int __init optee_driver_init(void)
+{
+ struct device_node *fw_np;
+ struct device_node *np;
+ struct optee *optee;
+
+ /* Node is supposed to be below /firmware */
+ fw_np = of_find_node_by_name(NULL, "firmware");
+ if (!fw_np)
+ return -ENODEV;
+
+ np = of_find_matching_node(fw_np, optee_match);
+ if (!np)
+ return -ENODEV;
+
+ optee = optee_probe(np);
+ of_node_put(np);
+
+ if (IS_ERR(optee))
+ return PTR_ERR(optee);
+
+ optee_svc = optee;
+
+ return 0;
+}
+module_init(optee_driver_init);
+
+static void __exit optee_driver_exit(void)
+{
+ struct optee *optee = optee_svc;
+
+ optee_svc = NULL;
+ if (optee)
+ optee_remove(optee);
+}
+module_exit(optee_driver_exit);
+
+MODULE_AUTHOR("Linaro");
+MODULE_DESCRIPTION("OP-TEE driver");
+MODULE_SUPPORTED_DEVICE("");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h
new file mode 100644
index 000000000000..dd7a06ee0462
--- /dev/null
+++ b/drivers/tee/optee/optee_msg.h
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ * 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.
+ *
+ * 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.
+ *
+ * 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 HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _OPTEE_MSG_H
+#define _OPTEE_MSG_H
+
+#include <linux/bitops.h>
+#include <linux/types.h>
+
+/*
+ * This file defines the OP-TEE message protocol used to communicate
+ * with an instance of OP-TEE running in secure world.
+ *
+ * This file is divided into three sections.
+ * 1. Formatting of messages.
+ * 2. Requests from normal world
+ * 3. Requests from secure world, Remote Procedure Call (RPC), handled by
+ * tee-supplicant.
+ */
+
+/*****************************************************************************
+ * Part 1 - formatting of messages
+ *****************************************************************************/
+
+#define OPTEE_MSG_ATTR_TYPE_NONE 0x0
+#define OPTEE_MSG_ATTR_TYPE_VALUE_INPUT 0x1
+#define OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT 0x2
+#define OPTEE_MSG_ATTR_TYPE_VALUE_INOUT 0x3
+#define OPTEE_MSG_ATTR_TYPE_RMEM_INPUT 0x5
+#define OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT 0x6
+#define OPTEE_MSG_ATTR_TYPE_RMEM_INOUT 0x7
+#define OPTEE_MSG_ATTR_TYPE_TMEM_INPUT 0x9
+#define OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT 0xa
+#define OPTEE_MSG_ATTR_TYPE_TMEM_INOUT 0xb
+
+#define OPTEE_MSG_ATTR_TYPE_MASK GENMASK(7, 0)
+
+/*
+ * Meta parameter to be absorbed by the Secure OS and not passed
+ * to the Trusted Application.
+ *
+ * Currently only used with OPTEE_MSG_CMD_OPEN_SESSION.
+ */
+#define OPTEE_MSG_ATTR_META BIT(8)
+
+/*
+ * The temporary shared memory object is not physically contigous and this
+ * temp memref is followed by another fragment until the last temp memref
+ * that doesn't have this bit set.
+ */
+#define OPTEE_MSG_ATTR_FRAGMENT BIT(9)
+
+/*
+ * Memory attributes for caching passed with temp memrefs. The actual value
+ * used is defined outside the message protocol with the exception of
+ * OPTEE_MSG_ATTR_CACHE_PREDEFINED which means the attributes already
+ * defined for the memory range should be used. If optee_smc.h is used as
+ * bearer of this protocol OPTEE_SMC_SHM_* is used for values.
+ */
+#define OPTEE_MSG_ATTR_CACHE_SHIFT 16
+#define OPTEE_MSG_ATTR_CACHE_MASK GENMASK(2, 0)
+#define OPTEE_MSG_ATTR_CACHE_PREDEFINED 0
+
+/*
+ * Same values as TEE_LOGIN_* from TEE Internal API
+ */
+#define OPTEE_MSG_LOGIN_PUBLIC 0x00000000
+#define OPTEE_MSG_LOGIN_USER 0x00000001
+#define OPTEE_MSG_LOGIN_GROUP 0x00000002
+#define OPTEE_MSG_LOGIN_APPLICATION 0x00000004
+#define OPTEE_MSG_LOGIN_APPLICATION_USER 0x00000005
+#define OPTEE_MSG_LOGIN_APPLICATION_GROUP 0x00000006
+
+/**
+ * struct optee_msg_param_tmem - temporary memory reference parameter
+ * @buf_ptr: Address of the buffer
+ * @size: Size of the buffer
+ * @shm_ref: Temporary shared memory reference, pointer to a struct tee_shm
+ *
+ * Secure and normal world communicates pointers as physical address
+ * instead of the virtual address. This is because secure and normal world
+ * have completely independent memory mapping. Normal world can even have a
+ * hypervisor which need to translate the guest physical address (AKA IPA
+ * in ARM documentation) to a real physical address before passing the
+ * structure to secure world.
+ */
+struct optee_msg_param_tmem {
+ u64 buf_ptr;
+ u64 size;
+ u64 shm_ref;
+};
+
+/**
+ * struct optee_msg_param_rmem - registered memory reference parameter
+ * @offs: Offset into shared memory reference
+ * @size: Size of the buffer
+ * @shm_ref: Shared memory reference, pointer to a struct tee_shm
+ */
+struct optee_msg_param_rmem {
+ u64 offs;
+ u64 size;
+ u64 shm_ref;
+};
+
+/**
+ * struct optee_msg_param_value - opaque value parameter
+ *
+ * Value parameters are passed unchecked between normal and secure world.
+ */
+struct optee_msg_param_value {
+ u64 a;
+ u64 b;
+ u64 c;
+};
+
+/**
+ * struct optee_msg_param - parameter used together with struct optee_msg_arg
+ * @attr: attributes
+ * @tmem: parameter by temporary memory reference
+ * @rmem: parameter by registered memory reference
+ * @value: parameter by opaque value
+ *
+ * @attr & OPTEE_MSG_ATTR_TYPE_MASK indicates if tmem, rmem or value is used in
+ * the union. OPTEE_MSG_ATTR_TYPE_VALUE_* indicates value,
+ * OPTEE_MSG_ATTR_TYPE_TMEM_* indicates tmem and
+ * OPTEE_MSG_ATTR_TYPE_RMEM_* indicates rmem.
+ * OPTEE_MSG_ATTR_TYPE_NONE indicates that none of the members are used.
+ */
+struct optee_msg_param {
+ u64 attr;
+ union {
+ struct optee_msg_param_tmem tmem;
+ struct optee_msg_param_rmem rmem;
+ struct optee_msg_param_value value;
+ } u;
+};
+
+/**
+ * struct optee_msg_arg - call argument
+ * @cmd: Command, one of OPTEE_MSG_CMD_* or OPTEE_MSG_RPC_CMD_*
+ * @func: Trusted Application function, specific to the Trusted Application,
+ * used if cmd == OPTEE_MSG_CMD_INVOKE_COMMAND
+ * @session: In parameter for all OPTEE_MSG_CMD_* except
+ * OPTEE_MSG_CMD_OPEN_SESSION where it's an output parameter instead
+ * @cancel_id: Cancellation id, a unique value to identify this request
+ * @ret: return value
+ * @ret_origin: origin of the return value
+ * @num_params: number of parameters supplied to the OS Command
+ * @params: the parameters supplied to the OS Command
+ *
+ * All normal calls to Trusted OS uses this struct. If cmd requires further
+ * information than what these field holds it can be passed as a parameter
+ * tagged as meta (setting the OPTEE_MSG_ATTR_META bit in corresponding
+ * attrs field). All parameters tagged as meta has to come first.
+ *
+ * Temp memref parameters can be fragmented if supported by the Trusted OS
+ * (when optee_smc.h is bearer of this protocol this is indicated with
+ * OPTEE_SMC_SEC_CAP_UNREGISTERED_SHM). If a logical memref parameter is
+ * fragmented then has all but the last fragment the
+ * OPTEE_MSG_ATTR_FRAGMENT bit set in attrs. Even if a memref is fragmented
+ * it will still be presented as a single logical memref to the Trusted
+ * Application.
+ */
+struct optee_msg_arg {
+ u32 cmd;
+ u32 func;
+ u32 session;
+ u32 cancel_id;
+ u32 pad;
+ u32 ret;
+ u32 ret_origin;
+ u32 num_params;
+
+ /* num_params tells the actual number of element in params */
+ struct optee_msg_param params[0];
+};
+
+/**
+ * OPTEE_MSG_GET_ARG_SIZE - return size of struct optee_msg_arg
+ *
+ * @num_params: Number of parameters embedded in the struct optee_msg_arg
+ *
+ * Returns the size of the struct optee_msg_arg together with the number
+ * of embedded parameters.
+ */
+#define OPTEE_MSG_GET_ARG_SIZE(num_params) \
+ (sizeof(struct optee_msg_arg) + \
+ sizeof(struct optee_msg_param) * (num_params))
+
+/*****************************************************************************
+ * Part 2 - requests from normal world
+ *****************************************************************************/
+
+/*
+ * Return the following UID if using API specified in this file without
+ * further extensions:
+ * 384fb3e0-e7f8-11e3-af63-0002a5d5c51b.
+ * Represented in 4 32-bit words in OPTEE_MSG_UID_0, OPTEE_MSG_UID_1,
+ * OPTEE_MSG_UID_2, OPTEE_MSG_UID_3.
+ */
+#define OPTEE_MSG_UID_0 0x384fb3e0
+#define OPTEE_MSG_UID_1 0xe7f811e3
+#define OPTEE_MSG_UID_2 0xaf630002
+#define OPTEE_MSG_UID_3 0xa5d5c51b
+#define OPTEE_MSG_FUNCID_CALLS_UID 0xFF01
+
+/*
+ * Returns 2.0 if using API specified in this file without further
+ * extensions. Represented in 2 32-bit words in OPTEE_MSG_REVISION_MAJOR
+ * and OPTEE_MSG_REVISION_MINOR
+ */
+#define OPTEE_MSG_REVISION_MAJOR 2
+#define OPTEE_MSG_REVISION_MINOR 0
+#define OPTEE_MSG_FUNCID_CALLS_REVISION 0xFF03
+
+/*
+ * Get UUID of Trusted OS.
+ *
+ * Used by non-secure world to figure out which Trusted OS is installed.
+ * Note that returned UUID is the UUID of the Trusted OS, not of the API.
+ *
+ * Returns UUID in 4 32-bit words in the same way as
+ * OPTEE_MSG_FUNCID_CALLS_UID described above.
+ */
+#define OPTEE_MSG_OS_OPTEE_UUID_0 0x486178e0
+#define OPTEE_MSG_OS_OPTEE_UUID_1 0xe7f811e3
+#define OPTEE_MSG_OS_OPTEE_UUID_2 0xbc5e0002
+#define OPTEE_MSG_OS_OPTEE_UUID_3 0xa5d5c51b
+#define OPTEE_MSG_FUNCID_GET_OS_UUID 0x0000
+
+/*
+ * Get revision of Trusted OS.
+ *
+ * Used by non-secure world to figure out which version of the Trusted OS
+ * is installed. Note that the returned revision is the revision of the
+ * Trusted OS, not of the API.
+ *
+ * Returns revision in 2 32-bit words in the same way as
+ * OPTEE_MSG_CALLS_REVISION described above.
+ */
+#define OPTEE_MSG_FUNCID_GET_OS_REVISION 0x0001
+
+/*
+ * Do a secure call with struct optee_msg_arg as argument
+ * The OPTEE_MSG_CMD_* below defines what goes in struct optee_msg_arg::cmd
+ *
+ * OPTEE_MSG_CMD_OPEN_SESSION opens a session to a Trusted Application.
+ * The first two parameters are tagged as meta, holding two value
+ * parameters to pass the following information:
+ * param[0].u.value.a-b uuid of Trusted Application
+ * param[1].u.value.a-b uuid of Client
+ * param[1].u.value.c Login class of client OPTEE_MSG_LOGIN_*
+ *
+ * OPTEE_MSG_CMD_INVOKE_COMMAND invokes a command a previously opened
+ * session to a Trusted Application. struct optee_msg_arg::func is Trusted
+ * Application function, specific to the Trusted Application.
+ *
+ * OPTEE_MSG_CMD_CLOSE_SESSION closes a previously opened session to
+ * Trusted Application.
+ *
+ * OPTEE_MSG_CMD_CANCEL cancels a currently invoked command.
+ *
+ * OPTEE_MSG_CMD_REGISTER_SHM registers a shared memory reference. The
+ * information is passed as:
+ * [in] param[0].attr OPTEE_MSG_ATTR_TYPE_TMEM_INPUT
+ * [| OPTEE_MSG_ATTR_FRAGMENT]
+ * [in] param[0].u.tmem.buf_ptr physical address (of first fragment)
+ * [in] param[0].u.tmem.size size (of first fragment)
+ * [in] param[0].u.tmem.shm_ref holds shared memory reference
+ * ...
+ * The shared memory can optionally be fragmented, temp memrefs can follow
+ * each other with all but the last with the OPTEE_MSG_ATTR_FRAGMENT bit set.
+ *
+ * OPTEE_MSG_CMD_UNREGISTER_SHM unregisteres a previously registered shared
+ * memory reference. The information is passed as:
+ * [in] param[0].attr OPTEE_MSG_ATTR_TYPE_RMEM_INPUT
+ * [in] param[0].u.rmem.shm_ref holds shared memory reference
+ * [in] param[0].u.rmem.offs 0
+ * [in] param[0].u.rmem.size 0
+ */
+#define OPTEE_MSG_CMD_OPEN_SESSION 0
+#define OPTEE_MSG_CMD_INVOKE_COMMAND 1
+#define OPTEE_MSG_CMD_CLOSE_SESSION 2
+#define OPTEE_MSG_CMD_CANCEL 3
+#define OPTEE_MSG_CMD_REGISTER_SHM 4
+#define OPTEE_MSG_CMD_UNREGISTER_SHM 5
+#define OPTEE_MSG_FUNCID_CALL_WITH_ARG 0x0004
+
+/*****************************************************************************
+ * Part 3 - Requests from secure world, RPC
+ *****************************************************************************/
+
+/*
+ * All RPC is done with a struct optee_msg_arg as bearer of information,
+ * struct optee_msg_arg::arg holds values defined by OPTEE_MSG_RPC_CMD_* below
+ *
+ * RPC communication with tee-supplicant is reversed compared to normal
+ * client communication desribed above. The supplicant receives requests
+ * and sends responses.
+ */
+
+/*
+ * Load a TA into memory, defined in tee-supplicant
+ */
+#define OPTEE_MSG_RPC_CMD_LOAD_TA 0
+
+/*
+ * Reserved
+ */
+#define OPTEE_MSG_RPC_CMD_RPMB 1
+
+/*
+ * File system access, defined in tee-supplicant
+ */
+#define OPTEE_MSG_RPC_CMD_FS 2
+
+/*
+ * Get time
+ *
+ * Returns number of seconds and nano seconds since the Epoch,
+ * 1970-01-01 00:00:00 +0000 (UTC).
+ *
+ * [out] param[0].u.value.a Number of seconds
+ * [out] param[0].u.value.b Number of nano seconds.
+ */
+#define OPTEE_MSG_RPC_CMD_GET_TIME 3
+
+/*
+ * Wait queue primitive, helper for secure world to implement a wait queue.
+ *
+ * If secure world need to wait for a secure world mutex it issues a sleep
+ * request instead of spinning in secure world. Conversely is a wakeup
+ * request issued when a secure world mutex with a thread waiting thread is
+ * unlocked.
+ *
+ * Waiting on a key
+ * [in] param[0].u.value.a OPTEE_MSG_RPC_WAIT_QUEUE_SLEEP
+ * [in] param[0].u.value.b wait key
+ *
+ * Waking up a key
+ * [in] param[0].u.value.a OPTEE_MSG_RPC_WAIT_QUEUE_WAKEUP
+ * [in] param[0].u.value.b wakeup key
+ */
+#define OPTEE_MSG_RPC_CMD_WAIT_QUEUE 4
+#define OPTEE_MSG_RPC_WAIT_QUEUE_SLEEP 0
+#define OPTEE_MSG_RPC_WAIT_QUEUE_WAKEUP 1
+
+/*
+ * Suspend execution
+ *
+ * [in] param[0].value .a number of milliseconds to suspend
+ */
+#define OPTEE_MSG_RPC_CMD_SUSPEND 5
+
+/*
+ * Allocate a piece of shared memory
+ *
+ * Shared memory can optionally be fragmented, to support that additional
+ * spare param entries are allocated to make room for eventual fragments.
+ * The spare param entries has .attr = OPTEE_MSG_ATTR_TYPE_NONE when
+ * unused. All returned temp memrefs except the last should have the
+ * OPTEE_MSG_ATTR_FRAGMENT bit set in the attr field.
+ *
+ * [in] param[0].u.value.a type of memory one of
+ * OPTEE_MSG_RPC_SHM_TYPE_* below
+ * [in] param[0].u.value.b requested size
+ * [in] param[0].u.value.c required alignment
+ *
+ * [out] param[0].u.tmem.buf_ptr physical address (of first fragment)
+ * [out] param[0].u.tmem.size size (of first fragment)
+ * [out] param[0].u.tmem.shm_ref shared memory reference
+ * ...
+ * [out] param[n].u.tmem.buf_ptr physical address
+ * [out] param[n].u.tmem.size size
+ * [out] param[n].u.tmem.shm_ref shared memory reference (same value
+ * as in param[n-1].u.tmem.shm_ref)
+ */
+#define OPTEE_MSG_RPC_CMD_SHM_ALLOC 6
+/* Memory that can be shared with a non-secure user space application */
+#define OPTEE_MSG_RPC_SHM_TYPE_APPL 0
+/* Memory only shared with non-secure kernel */
+#define OPTEE_MSG_RPC_SHM_TYPE_KERNEL 1
+
+/*
+ * Free shared memory previously allocated with OPTEE_MSG_RPC_CMD_SHM_ALLOC
+ *
+ * [in] param[0].u.value.a type of memory one of
+ * OPTEE_MSG_RPC_SHM_TYPE_* above
+ * [in] param[0].u.value.b value of shared memory reference
+ * returned in param[0].u.tmem.shm_ref
+ * above
+ */
+#define OPTEE_MSG_RPC_CMD_SHM_FREE 7
+
+#endif /* _OPTEE_MSG_H */
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
new file mode 100644
index 000000000000..3e7da187acbe
--- /dev/null
+++ b/drivers/tee/optee/optee_private.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * 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 OPTEE_PRIVATE_H
+#define OPTEE_PRIVATE_H
+
+#include <linux/arm-smccc.h>
+#include <linux/semaphore.h>
+#include <linux/tee_drv.h>
+#include <linux/types.h>
+#include "optee_msg.h"
+
+#define OPTEE_MAX_ARG_SIZE 1024
+
+/* Some Global Platform error codes used in this driver */
+#define TEEC_SUCCESS 0x00000000
+#define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006
+#define TEEC_ERROR_COMMUNICATION 0xFFFF000E
+#define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C
+
+#define TEEC_ORIGIN_COMMS 0x00000002
+
+typedef void (optee_invoke_fn)(unsigned long, unsigned long, unsigned long,
+ unsigned long, unsigned long, unsigned long,
+ unsigned long, unsigned long,
+ struct arm_smccc_res *);
+
+struct optee_call_queue {
+ /* Serializes access to this struct */
+ struct mutex mutex;
+ struct list_head waiters;
+};
+
+struct optee_wait_queue {
+ /* Serializes access to this struct */
+ struct mutex mu;
+ struct list_head db;
+};
+
+/**
+ * struct optee_supp - supplicant synchronization struct
+ * @ctx the context of current connected supplicant.
+ * if !NULL the supplicant device is available for use,
+ * else busy
+ * @mutex: held while accessing content of this struct
+ * @req_id: current request id if supplicant is doing synchronous
+ * communication, else -1
+ * @reqs: queued request not yet retrieved by supplicant
+ * @idr: IDR holding all requests currently being processed
+ * by supplicant
+ * @reqs_c: completion used by supplicant when waiting for a
+ * request to be queued.
+ */
+struct optee_supp {
+ /* Serializes access to this struct */
+ struct mutex mutex;
+ struct tee_context *ctx;
+
+ int req_id;
+ struct list_head reqs;
+ struct idr idr;
+ struct completion reqs_c;
+};
+
+/**
+ * struct optee - main service struct
+ * @supp_teedev: supplicant device
+ * @teedev: client device
+ * @invoke_fn: function to issue smc or hvc
+ * @call_queue: queue of threads waiting to call @invoke_fn
+ * @wait_queue: queue of threads from secure world waiting for a
+ * secure world sync object
+ * @supp: supplicant synchronization struct for RPC to supplicant
+ * @pool: shared memory pool
+ * @memremaped_shm virtual address of memory in shared memory pool
+ */
+struct optee {
+ struct tee_device *supp_teedev;
+ struct tee_device *teedev;
+ optee_invoke_fn *invoke_fn;
+ struct optee_call_queue call_queue;
+ struct optee_wait_queue wait_queue;
+ struct optee_supp supp;
+ struct tee_shm_pool *pool;
+ void *memremaped_shm;
+};
+
+struct optee_session {
+ struct list_head list_node;
+ u32 session_id;
+};
+
+struct optee_context_data {
+ /* Serializes access to this struct */
+ struct mutex mutex;
+ struct list_head sess_list;
+};
+
+struct optee_rpc_param {
+ u32 a0;
+ u32 a1;
+ u32 a2;
+ u32 a3;
+ u32 a4;
+ u32 a5;
+ u32 a6;
+ u32 a7;
+};
+
+void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param);
+
+void optee_wait_queue_init(struct optee_wait_queue *wq);
+void optee_wait_queue_exit(struct optee_wait_queue *wq);
+
+u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
+ struct tee_param *param);
+
+int optee_supp_read(struct tee_context *ctx, void __user *buf, size_t len);
+int optee_supp_write(struct tee_context *ctx, void __user *buf, size_t len);
+void optee_supp_init(struct optee_supp *supp);
+void optee_supp_uninit(struct optee_supp *supp);
+void optee_supp_release(struct optee_supp *supp);
+
+int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
+ struct tee_param *param);
+int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
+ struct tee_param *param);
+
+u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg);
+int optee_open_session(struct tee_context *ctx,
+ struct tee_ioctl_open_session_arg *arg,
+ struct tee_param *param);
+int optee_close_session(struct tee_context *ctx, u32 session);
+int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg,
+ struct tee_param *param);
+int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session);
+
+void optee_enable_shm_cache(struct optee *optee);
+void optee_disable_shm_cache(struct optee *optee);
+
+int optee_from_msg_param(struct tee_param *params, size_t num_params,
+ const struct optee_msg_param *msg_params);
+int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params,
+ const struct tee_param *params);
+
+/*
+ * Small helpers
+ */
+
+static inline void *reg_pair_to_ptr(u32 reg0, u32 reg1)
+{
+ return (void *)(unsigned long)(((u64)reg0 << 32) | reg1);
+}
+
+static inline void reg_pair_from_64(u32 *reg0, u32 *reg1, u64 val)
+{
+ *reg0 = val >> 32;
+ *reg1 = val;
+}
+
+#endif /*OPTEE_PRIVATE_H*/
diff --git a/drivers/tee/optee/optee_smc.h b/drivers/tee/optee/optee_smc.h
new file mode 100644
index 000000000000..069c8e1429de
--- /dev/null
+++ b/drivers/tee/optee/optee_smc.h
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ * 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.
+ *
+ * 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.
+ *
+ * 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 HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef OPTEE_SMC_H
+#define OPTEE_SMC_H
+
+#include <linux/arm-smccc.h>
+#include <linux/bitops.h>
+
+#define OPTEE_SMC_STD_CALL_VAL(func_num) \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_32, \
+ ARM_SMCCC_OWNER_TRUSTED_OS, (func_num))
+#define OPTEE_SMC_FAST_CALL_VAL(func_num) \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \
+ ARM_SMCCC_OWNER_TRUSTED_OS, (func_num))
+
+/*
+ * Function specified by SMC Calling convention.
+ */
+#define OPTEE_SMC_FUNCID_CALLS_COUNT 0xFF00
+#define OPTEE_SMC_CALLS_COUNT \
+ ARM_SMCCC_CALL_VAL(OPTEE_SMC_FAST_CALL, SMCCC_SMC_32, \
+ SMCCC_OWNER_TRUSTED_OS_END, \
+ OPTEE_SMC_FUNCID_CALLS_COUNT)
+
+/*
+ * Normal cached memory (write-back), shareable for SMP systems and not
+ * shareable for UP systems.
+ */
+#define OPTEE_SMC_SHM_CACHED 1
+
+/*
+ * a0..a7 is used as register names in the descriptions below, on arm32
+ * that translates to r0..r7 and on arm64 to w0..w7. In both cases it's
+ * 32-bit registers.
+ */
+
+/*
+ * Function specified by SMC Calling convention
+ *
+ * Return one of the following UIDs if using API specified in this file
+ * without further extentions:
+ * 65cb6b93-af0c-4617-8ed6-644a8d1140f8
+ * see also OPTEE_SMC_UID_* in optee_msg.h
+ */
+#define OPTEE_SMC_FUNCID_CALLS_UID OPTEE_MSG_FUNCID_CALLS_UID
+#define OPTEE_SMC_CALLS_UID \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \
+ ARM_SMCCC_OWNER_TRUSTED_OS_END, \
+ OPTEE_SMC_FUNCID_CALLS_UID)
+
+/*
+ * Function specified by SMC Calling convention
+ *
+ * Returns 2.0 if using API specified in this file without further extentions.
+ * see also OPTEE_MSG_REVISION_* in optee_msg.h
+ */
+#define OPTEE_SMC_FUNCID_CALLS_REVISION OPTEE_MSG_FUNCID_CALLS_REVISION
+#define OPTEE_SMC_CALLS_REVISION \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_32, \
+ ARM_SMCCC_OWNER_TRUSTED_OS_END, \
+ OPTEE_SMC_FUNCID_CALLS_REVISION)
+
+struct optee_smc_calls_revision_result {
+ unsigned long major;
+ unsigned long minor;
+ unsigned long reserved0;
+ unsigned long reserved1;
+};
+
+/*
+ * Get UUID of Trusted OS.
+ *
+ * Used by non-secure world to figure out which Trusted OS is installed.
+ * Note that returned UUID is the UUID of the Trusted OS, not of the API.
+ *
+ * Returns UUID in a0-4 in the same way as OPTEE_SMC_CALLS_UID
+ * described above.
+ */
+#define OPTEE_SMC_FUNCID_GET_OS_UUID OPTEE_MSG_FUNCID_GET_OS_UUID
+#define OPTEE_SMC_CALL_GET_OS_UUID \
+ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_OS_UUID)
+
+/*
+ * Get revision of Trusted OS.
+ *
+ * Used by non-secure world to figure out which version of the Trusted OS
+ * is installed. Note that the returned revision is the revision of the
+ * Trusted OS, not of the API.
+ *
+ * Returns revision in a0-1 in the same way as OPTEE_SMC_CALLS_REVISION
+ * described above.
+ */
+#define OPTEE_SMC_FUNCID_GET_OS_REVISION OPTEE_MSG_FUNCID_GET_OS_REVISION
+#define OPTEE_SMC_CALL_GET_OS_REVISION \
+ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_OS_REVISION)
+
+/*
+ * Call with struct optee_msg_arg as argument
+ *
+ * Call register usage:
+ * a0 SMC Function ID, OPTEE_SMC*CALL_WITH_ARG
+ * a1 Upper 32bit of a 64bit physical pointer to a struct optee_msg_arg
+ * a2 Lower 32bit of a 64bit physical pointer to a struct optee_msg_arg
+ * a3 Cache settings, not used if physical pointer is in a predefined shared
+ * memory area else per OPTEE_SMC_SHM_*
+ * a4-6 Not used
+ * a7 Hypervisor Client ID register
+ *
+ * Normal return register usage:
+ * a0 Return value, OPTEE_SMC_RETURN_*
+ * a1-3 Not used
+ * a4-7 Preserved
+ *
+ * OPTEE_SMC_RETURN_ETHREAD_LIMIT return register usage:
+ * a0 Return value, OPTEE_SMC_RETURN_ETHREAD_LIMIT
+ * a1-3 Preserved
+ * a4-7 Preserved
+ *
+ * RPC return register usage:
+ * a0 Return value, OPTEE_SMC_RETURN_IS_RPC(val)
+ * a1-2 RPC parameters
+ * a3-7 Resume information, must be preserved
+ *
+ * Possible return values:
+ * OPTEE_SMC_RETURN_UNKNOWN_FUNCTION Trusted OS does not recognize this
+ * function.
+ * OPTEE_SMC_RETURN_OK Call completed, result updated in
+ * the previously supplied struct
+ * optee_msg_arg.
+ * OPTEE_SMC_RETURN_ETHREAD_LIMIT Number of Trusted OS threads exceeded,
+ * try again later.
+ * OPTEE_SMC_RETURN_EBADADDR Bad physcial pointer to struct
+ * optee_msg_arg.
+ * OPTEE_SMC_RETURN_EBADCMD Bad/unknown cmd in struct optee_msg_arg
+ * OPTEE_SMC_RETURN_IS_RPC() Call suspended by RPC call to normal
+ * world.
+ */
+#define OPTEE_SMC_FUNCID_CALL_WITH_ARG OPTEE_MSG_FUNCID_CALL_WITH_ARG
+#define OPTEE_SMC_CALL_WITH_ARG \
+ OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_CALL_WITH_ARG)
+
+/*
+ * Get Shared Memory Config
+ *
+ * Returns the Secure/Non-secure shared memory config.
+ *
+ * Call register usage:
+ * a0 SMC Function ID, OPTEE_SMC_GET_SHM_CONFIG
+ * a1-6 Not used
+ * a7 Hypervisor Client ID register
+ *
+ * Have config return register usage:
+ * a0 OPTEE_SMC_RETURN_OK
+ * a1 Physical address of start of SHM
+ * a2 Size of of SHM
+ * a3 Cache settings of memory, as defined by the
+ * OPTEE_SMC_SHM_* values above
+ * a4-7 Preserved
+ *
+ * Not available register usage:
+ * a0 OPTEE_SMC_RETURN_ENOTAVAIL
+ * a1-3 Not used
+ * a4-7 Preserved
+ */
+#define OPTEE_SMC_FUNCID_GET_SHM_CONFIG 7
+#define OPTEE_SMC_GET_SHM_CONFIG \
+ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_SHM_CONFIG)
+
+struct optee_smc_get_shm_config_result {
+ unsigned long status;
+ unsigned long start;
+ unsigned long size;
+ unsigned long settings;
+};
+
+/*
+ * Exchanges capabilities between normal world and secure world
+ *
+ * Call register usage:
+ * a0 SMC Function ID, OPTEE_SMC_EXCHANGE_CAPABILITIES
+ * a1 bitfield of normal world capabilities OPTEE_SMC_NSEC_CAP_*
+ * a2-6 Not used
+ * a7 Hypervisor Client ID register
+ *
+ * Normal return register usage:
+ * a0 OPTEE_SMC_RETURN_OK
+ * a1 bitfield of secure world capabilities OPTEE_SMC_SEC_CAP_*
+ * a2-7 Preserved
+ *
+ * Error return register usage:
+ * a0 OPTEE_SMC_RETURN_ENOTAVAIL, can't use the capabilities from normal world
+ * a1 bitfield of secure world capabilities OPTEE_SMC_SEC_CAP_*
+ * a2-7 Preserved
+ */
+/* Normal world works as a uniprocessor system */
+#define OPTEE_SMC_NSEC_CAP_UNIPROCESSOR BIT(0)
+/* Secure world has reserved shared memory for normal world to use */
+#define OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM BIT(0)
+/* Secure world can communicate via previously unregistered shared memory */
+#define OPTEE_SMC_SEC_CAP_UNREGISTERED_SHM BIT(1)
+#define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9
+#define OPTEE_SMC_EXCHANGE_CAPABILITIES \
+ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES)
+
+struct optee_smc_exchange_capabilities_result {
+ unsigned long status;
+ unsigned long capabilities;
+ unsigned long reserved0;
+ unsigned long reserved1;
+};
+
+/*
+ * Disable and empties cache of shared memory objects
+ *
+ * Secure world can cache frequently used shared memory objects, for
+ * example objects used as RPC arguments. When secure world is idle this
+ * function returns one shared memory reference to free. To disable the
+ * cache and free all cached objects this function has to be called until
+ * it returns OPTEE_SMC_RETURN_ENOTAVAIL.
+ *
+ * Call register usage:
+ * a0 SMC Function ID, OPTEE_SMC_DISABLE_SHM_CACHE
+ * a1-6 Not used
+ * a7 Hypervisor Client ID register
+ *
+ * Normal return register usage:
+ * a0 OPTEE_SMC_RETURN_OK
+ * a1 Upper 32bit of a 64bit Shared memory cookie
+ * a2 Lower 32bit of a 64bit Shared memory cookie
+ * a3-7 Preserved
+ *
+ * Cache empty return register usage:
+ * a0 OPTEE_SMC_RETURN_ENOTAVAIL
+ * a1-7 Preserved
+ *
+ * Not idle return register usage:
+ * a0 OPTEE_SMC_RETURN_EBUSY
+ * a1-7 Preserved
+ */
+#define OPTEE_SMC_FUNCID_DISABLE_SHM_CACHE 10
+#define OPTEE_SMC_DISABLE_SHM_CACHE \
+ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_DISABLE_SHM_CACHE)
+
+struct optee_smc_disable_shm_cache_result {
+ unsigned long status;
+ unsigned long shm_upper32;
+ unsigned long shm_lower32;
+ unsigned long reserved0;
+};
+
+/*
+ * Enable cache of shared memory objects
+ *
+ * Secure world can cache frequently used shared memory objects, for
+ * example objects used as RPC arguments. When secure world is idle this
+ * function returns OPTEE_SMC_RETURN_OK and the cache is enabled. If
+ * secure world isn't idle OPTEE_SMC_RETURN_EBUSY is returned.
+ *
+ * Call register usage:
+ * a0 SMC Function ID, OPTEE_SMC_ENABLE_SHM_CACHE
+ * a1-6 Not used
+ * a7 Hypervisor Client ID register
+ *
+ * Normal return register usage:
+ * a0 OPTEE_SMC_RETURN_OK
+ * a1-7 Preserved
+ *
+ * Not idle return register usage:
+ * a0 OPTEE_SMC_RETURN_EBUSY
+ * a1-7 Preserved
+ */
+#define OPTEE_SMC_FUNCID_ENABLE_SHM_CACHE 11
+#define OPTEE_SMC_ENABLE_SHM_CACHE \
+ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_ENABLE_SHM_CACHE)
+
+/*
+ * Resume from RPC (for example after processing a foreign interrupt)
+ *
+ * Call register usage:
+ * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC
+ * a1-3 Value of a1-3 when OPTEE_SMC_CALL_WITH_ARG returned
+ * OPTEE_SMC_RETURN_RPC in a0
+ *
+ * Return register usage is the same as for OPTEE_SMC_*CALL_WITH_ARG above.
+ *
+ * Possible return values
+ * OPTEE_SMC_RETURN_UNKNOWN_FUNCTION Trusted OS does not recognize this
+ * function.
+ * OPTEE_SMC_RETURN_OK Original call completed, result
+ * updated in the previously supplied.
+ * struct optee_msg_arg
+ * OPTEE_SMC_RETURN_RPC Call suspended by RPC call to normal
+ * world.
+ * OPTEE_SMC_RETURN_ERESUME Resume failed, the opaque resume
+ * information was corrupt.
+ */
+#define OPTEE_SMC_FUNCID_RETURN_FROM_RPC 3
+#define OPTEE_SMC_CALL_RETURN_FROM_RPC \
+ OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_RETURN_FROM_RPC)
+
+#define OPTEE_SMC_RETURN_RPC_PREFIX_MASK 0xFFFF0000
+#define OPTEE_SMC_RETURN_RPC_PREFIX 0xFFFF0000
+#define OPTEE_SMC_RETURN_RPC_FUNC_MASK 0x0000FFFF
+
+#define OPTEE_SMC_RETURN_GET_RPC_FUNC(ret) \
+ ((ret) & OPTEE_SMC_RETURN_RPC_FUNC_MASK)
+
+#define OPTEE_SMC_RPC_VAL(func) ((func) | OPTEE_SMC_RETURN_RPC_PREFIX)
+
+/*
+ * Allocate memory for RPC parameter passing. The memory is used to hold a
+ * struct optee_msg_arg.
+ *
+ * "Call" register usage:
+ * a0 This value, OPTEE_SMC_RETURN_RPC_ALLOC
+ * a1 Size in bytes of required argument memory
+ * a2 Not used
+ * a3 Resume information, must be preserved
+ * a4-5 Not used
+ * a6-7 Resume information, must be preserved
+ *
+ * "Return" register usage:
+ * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC.
+ * a1 Upper 32bits of 64bit physical pointer to allocated
+ * memory, (a1 == 0 && a2 == 0) if size was 0 or if memory can't
+ * be allocated.
+ * a2 Lower 32bits of 64bit physical pointer to allocated
+ * memory, (a1 == 0 && a2 == 0) if size was 0 or if memory can't
+ * be allocated
+ * a3 Preserved
+ * a4 Upper 32bits of 64bit Shared memory cookie used when freeing
+ * the memory or doing an RPC
+ * a5 Lower 32bits of 64bit Shared memory cookie used when freeing
+ * the memory or doing an RPC
+ * a6-7 Preserved
+ */
+#define OPTEE_SMC_RPC_FUNC_ALLOC 0
+#define OPTEE_SMC_RETURN_RPC_ALLOC \
+ OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_ALLOC)
+
+/*
+ * Free memory previously allocated by OPTEE_SMC_RETURN_RPC_ALLOC
+ *
+ * "Call" register usage:
+ * a0 This value, OPTEE_SMC_RETURN_RPC_FREE
+ * a1 Upper 32bits of 64bit shared memory cookie belonging to this
+ * argument memory
+ * a2 Lower 32bits of 64bit shared memory cookie belonging to this
+ * argument memory
+ * a3-7 Resume information, must be preserved
+ *
+ * "Return" register usage:
+ * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC.
+ * a1-2 Not used
+ * a3-7 Preserved
+ */
+#define OPTEE_SMC_RPC_FUNC_FREE 2
+#define OPTEE_SMC_RETURN_RPC_FREE \
+ OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_FREE)
+
+/*
+ * Deliver foreign interrupt to normal world.
+ *
+ * "Call" register usage:
+ * a0 OPTEE_SMC_RETURN_RPC_FOREIGN_INTR
+ * a1-7 Resume information, must be preserved
+ *
+ * "Return" register usage:
+ * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC.
+ * a1-7 Preserved
+ */
+#define OPTEE_SMC_RPC_FUNC_FOREIGN_INTR 4
+#define OPTEE_SMC_RETURN_RPC_FOREIGN_INTR \
+ OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_FOREIGN_INTR)
+
+/*
+ * Do an RPC request. The supplied struct optee_msg_arg tells which
+ * request to do and the parameters for the request. The following fields
+ * are used (the rest are unused):
+ * - cmd the Request ID
+ * - ret return value of the request, filled in by normal world
+ * - num_params number of parameters for the request
+ * - params the parameters
+ * - param_attrs attributes of the parameters
+ *
+ * "Call" register usage:
+ * a0 OPTEE_SMC_RETURN_RPC_CMD
+ * a1 Upper 32bit of a 64bit Shared memory cookie holding a
+ * struct optee_msg_arg, must be preserved, only the data should
+ * be updated
+ * a2 Lower 32bit of a 64bit Shared memory cookie holding a
+ * struct optee_msg_arg, must be preserved, only the data should
+ * be updated
+ * a3-7 Resume information, must be preserved
+ *
+ * "Return" register usage:
+ * a0 SMC Function ID, OPTEE_SMC_CALL_RETURN_FROM_RPC.
+ * a1-2 Not used
+ * a3-7 Preserved
+ */
+#define OPTEE_SMC_RPC_FUNC_CMD 5
+#define OPTEE_SMC_RETURN_RPC_CMD \
+ OPTEE_SMC_RPC_VAL(OPTEE_SMC_RPC_FUNC_CMD)
+
+/* Returned in a0 */
+#define OPTEE_SMC_RETURN_UNKNOWN_FUNCTION 0xFFFFFFFF
+
+/* Returned in a0 only from Trusted OS functions */
+#define OPTEE_SMC_RETURN_OK 0x0
+#define OPTEE_SMC_RETURN_ETHREAD_LIMIT 0x1
+#define OPTEE_SMC_RETURN_EBUSY 0x2
+#define OPTEE_SMC_RETURN_ERESUME 0x3
+#define OPTEE_SMC_RETURN_EBADADDR 0x4
+#define OPTEE_SMC_RETURN_EBADCMD 0x5
+#define OPTEE_SMC_RETURN_ENOMEM 0x6
+#define OPTEE_SMC_RETURN_ENOTAVAIL 0x7
+#define OPTEE_SMC_RETURN_IS_RPC(ret) __optee_smc_return_is_rpc((ret))
+
+static inline bool __optee_smc_return_is_rpc(u32 ret)
+{
+ return ret != OPTEE_SMC_RETURN_UNKNOWN_FUNCTION &&
+ (ret & OPTEE_SMC_RETURN_RPC_PREFIX_MASK) ==
+ OPTEE_SMC_RETURN_RPC_PREFIX;
+}
+
+#endif /* OPTEE_SMC_H */
diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c
new file mode 100644
index 000000000000..c6df4317ca9f
--- /dev/null
+++ b/drivers/tee/optee/rpc.c
@@ -0,0 +1,393 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include "optee_private.h"
+#include "optee_smc.h"
+
+struct wq_entry {
+ struct list_head link;
+ struct completion c;
+ u32 key;
+};
+
+void optee_wait_queue_init(struct optee_wait_queue *priv)
+{
+ mutex_init(&priv->mu);
+ INIT_LIST_HEAD(&priv->db);
+}
+
+void optee_wait_queue_exit(struct optee_wait_queue *priv)
+{
+ mutex_destroy(&priv->mu);
+}
+
+static void handle_rpc_func_cmd_get_time(struct optee_msg_arg *arg)
+{
+ struct timespec64 ts;
+
+ if (arg->num_params != 1)
+ goto bad;
+ if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) !=
+ OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT)
+ goto bad;
+
+ getnstimeofday64(&ts);
+ arg->params[0].u.value.a = ts.tv_sec;
+ arg->params[0].u.value.b = ts.tv_nsec;
+
+ arg->ret = TEEC_SUCCESS;
+ return;
+bad:
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+}
+
+static struct wq_entry *wq_entry_get(struct optee_wait_queue *wq, u32 key)
+{
+ struct wq_entry *w;
+
+ mutex_lock(&wq->mu);
+
+ list_for_each_entry(w, &wq->db, link)
+ if (w->key == key)
+ goto out;
+
+ w = kmalloc(sizeof(*w), GFP_KERNEL);
+ if (w) {
+ init_completion(&w->c);
+ w->key = key;
+ list_add_tail(&w->link, &wq->db);
+ }
+out:
+ mutex_unlock(&wq->mu);
+ return w;
+}
+
+static void wq_sleep(struct optee_wait_queue *wq, u32 key)
+{
+ struct wq_entry *w = wq_entry_get(wq, key);
+
+ if (w) {
+ wait_for_completion(&w->c);
+ mutex_lock(&wq->mu);
+ list_del(&w->link);
+ mutex_unlock(&wq->mu);
+ kfree(w);
+ }
+}
+
+static void wq_wakeup(struct optee_wait_queue *wq, u32 key)
+{
+ struct wq_entry *w = wq_entry_get(wq, key);
+
+ if (w)
+ complete(&w->c);
+}
+
+static void handle_rpc_func_cmd_wq(struct optee *optee,
+ struct optee_msg_arg *arg)
+{
+ if (arg->num_params != 1)
+ goto bad;
+
+ if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) !=
+ OPTEE_MSG_ATTR_TYPE_VALUE_INPUT)
+ goto bad;
+
+ switch (arg->params[0].u.value.a) {
+ case OPTEE_MSG_RPC_WAIT_QUEUE_SLEEP:
+ wq_sleep(&optee->wait_queue, arg->params[0].u.value.b);
+ break;
+ case OPTEE_MSG_RPC_WAIT_QUEUE_WAKEUP:
+ wq_wakeup(&optee->wait_queue, arg->params[0].u.value.b);
+ break;
+ default:
+ goto bad;
+ }
+
+ arg->ret = TEEC_SUCCESS;
+ return;
+bad:
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+}
+
+static void handle_rpc_func_cmd_wait(struct optee_msg_arg *arg)
+{
+ u32 msec_to_wait;
+
+ if (arg->num_params != 1)
+ goto bad;
+
+ if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) !=
+ OPTEE_MSG_ATTR_TYPE_VALUE_INPUT)
+ goto bad;
+
+ msec_to_wait = arg->params[0].u.value.a;
+
+ /* Go to interruptible sleep */
+ msleep_interruptible(msec_to_wait);
+
+ arg->ret = TEEC_SUCCESS;
+ return;
+bad:
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+}
+
+static void handle_rpc_supp_cmd(struct tee_context *ctx,
+ struct optee_msg_arg *arg)
+{
+ struct tee_param *params;
+
+ arg->ret_origin = TEEC_ORIGIN_COMMS;
+
+ params = kmalloc_array(arg->num_params, sizeof(struct tee_param),
+ GFP_KERNEL);
+ if (!params) {
+ arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
+ return;
+ }
+
+ if (optee_from_msg_param(params, arg->num_params, arg->params)) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ goto out;
+ }
+
+ arg->ret = optee_supp_thrd_req(ctx, arg->cmd, arg->num_params, params);
+
+ if (optee_to_msg_param(arg->params, arg->num_params, params))
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+out:
+ kfree(params);
+}
+
+static struct tee_shm *cmd_alloc_suppl(struct tee_context *ctx, size_t sz)
+{
+ u32 ret;
+ struct tee_param param;
+ struct optee *optee = tee_get_drvdata(ctx->teedev);
+ struct tee_shm *shm;
+
+ param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;
+ param.u.value.a = OPTEE_MSG_RPC_SHM_TYPE_APPL;
+ param.u.value.b = sz;
+ param.u.value.c = 0;
+
+ ret = optee_supp_thrd_req(ctx, OPTEE_MSG_RPC_CMD_SHM_ALLOC, 1, &param);
+ if (ret)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_lock(&optee->supp.mutex);
+ /* Increases count as secure world doesn't have a reference */
+ shm = tee_shm_get_from_id(optee->supp.ctx, param.u.value.c);
+ mutex_unlock(&optee->supp.mutex);
+ return shm;
+}
+
+static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
+ struct optee_msg_arg *arg)
+{
+ phys_addr_t pa;
+ struct tee_shm *shm;
+ size_t sz;
+ size_t n;
+
+ arg->ret_origin = TEEC_ORIGIN_COMMS;
+
+ if (!arg->num_params ||
+ arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ return;
+ }
+
+ for (n = 1; n < arg->num_params; n++) {
+ if (arg->params[n].attr != OPTEE_MSG_ATTR_TYPE_NONE) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ return;
+ }
+ }
+
+ sz = arg->params[0].u.value.b;
+ switch (arg->params[0].u.value.a) {
+ case OPTEE_MSG_RPC_SHM_TYPE_APPL:
+ shm = cmd_alloc_suppl(ctx, sz);
+ break;
+ case OPTEE_MSG_RPC_SHM_TYPE_KERNEL:
+ shm = tee_shm_alloc(ctx, sz, TEE_SHM_MAPPED);
+ break;
+ default:
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ return;
+ }
+
+ if (IS_ERR(shm)) {
+ arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
+ return;
+ }
+
+ if (tee_shm_get_pa(shm, 0, &pa)) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ goto bad;
+ }
+
+ arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
+ arg->params[0].u.tmem.buf_ptr = pa;
+ arg->params[0].u.tmem.size = sz;
+ arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
+ arg->ret = TEEC_SUCCESS;
+ return;
+bad:
+ tee_shm_free(shm);
+}
+
+static void cmd_free_suppl(struct tee_context *ctx, struct tee_shm *shm)
+{
+ struct tee_param param;
+
+ param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT;
+ param.u.value.a = OPTEE_MSG_RPC_SHM_TYPE_APPL;
+ param.u.value.b = tee_shm_get_id(shm);
+ param.u.value.c = 0;
+
+ /*
+ * Match the tee_shm_get_from_id() in cmd_alloc_suppl() as secure
+ * world has released its reference.
+ *
+ * It's better to do this before sending the request to supplicant
+ * as we'd like to let the process doing the initial allocation to
+ * do release the last reference too in order to avoid stacking
+ * many pending fput() on the client process. This could otherwise
+ * happen if secure world does many allocate and free in a single
+ * invoke.
+ */
+ tee_shm_put(shm);
+
+ optee_supp_thrd_req(ctx, OPTEE_MSG_RPC_CMD_SHM_FREE, 1, &param);
+}
+
+static void handle_rpc_func_cmd_shm_free(struct tee_context *ctx,
+ struct optee_msg_arg *arg)
+{
+ struct tee_shm *shm;
+
+ arg->ret_origin = TEEC_ORIGIN_COMMS;
+
+ if (arg->num_params != 1 ||
+ arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) {
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ return;
+ }
+
+ shm = (struct tee_shm *)(unsigned long)arg->params[0].u.value.b;
+ switch (arg->params[0].u.value.a) {
+ case OPTEE_MSG_RPC_SHM_TYPE_APPL:
+ cmd_free_suppl(ctx, shm);
+ break;
+ case OPTEE_MSG_RPC_SHM_TYPE_KERNEL:
+ tee_shm_free(shm);
+ break;
+ default:
+ arg->ret = TEEC_ERROR_BAD_PARAMETERS;
+ }
+ arg->ret = TEEC_SUCCESS;
+}
+
+static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
+ struct tee_shm *shm)
+{
+ struct optee_msg_arg *arg;
+
+ arg = tee_shm_get_va(shm, 0);
+ if (IS_ERR(arg)) {
+ pr_err("%s: tee_shm_get_va %p failed\n", __func__, shm);
+ return;
+ }
+
+ switch (arg->cmd) {
+ case OPTEE_MSG_RPC_CMD_GET_TIME:
+ handle_rpc_func_cmd_get_time(arg);
+ break;
+ case OPTEE_MSG_RPC_CMD_WAIT_QUEUE:
+ handle_rpc_func_cmd_wq(optee, arg);
+ break;
+ case OPTEE_MSG_RPC_CMD_SUSPEND:
+ handle_rpc_func_cmd_wait(arg);
+ break;
+ case OPTEE_MSG_RPC_CMD_SHM_ALLOC:
+ handle_rpc_func_cmd_shm_alloc(ctx, arg);
+ break;
+ case OPTEE_MSG_RPC_CMD_SHM_FREE:
+ handle_rpc_func_cmd_shm_free(ctx, arg);
+ break;
+ default:
+ handle_rpc_supp_cmd(ctx, arg);
+ }
+}
+
+/**
+ * optee_handle_rpc() - handle RPC from secure world
+ * @ctx: context doing the RPC
+ * @param: value of registers for the RPC
+ *
+ * Result of RPC is written back into @param.
+ */
+void optee_handle_rpc(struct tee_context *ctx, struct optee_rpc_param *param)
+{
+ struct tee_device *teedev = ctx->teedev;
+ struct optee *optee = tee_get_drvdata(teedev);
+ struct tee_shm *shm;
+ phys_addr_t pa;
+
+ switch (OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0)) {
+ case OPTEE_SMC_RPC_FUNC_ALLOC:
+ shm = tee_shm_alloc(ctx, param->a1, TEE_SHM_MAPPED);
+ if (!IS_ERR(shm) && !tee_shm_get_pa(shm, 0, &pa)) {
+ reg_pair_from_64(&param->a1, &param->a2, pa);
+ reg_pair_from_64(&param->a4, &param->a5,
+ (unsigned long)shm);
+ } else {
+ param->a1 = 0;
+ param->a2 = 0;
+ param->a4 = 0;
+ param->a5 = 0;
+ }
+ break;
+ case OPTEE_SMC_RPC_FUNC_FREE:
+ shm = reg_pair_to_ptr(param->a1, param->a2);
+ tee_shm_free(shm);
+ break;
+ case OPTEE_SMC_RPC_FUNC_FOREIGN_INTR:
+ /*
+ * A foreign interrupt was raised while secure world was
+ * executing, since they are handled in Linux a dummy RPC is
+ * performed to let Linux take the interrupt through the normal
+ * vector.
+ */
+ break;
+ case OPTEE_SMC_RPC_FUNC_CMD:
+ shm = reg_pair_to_ptr(param->a1, param->a2);
+ handle_rpc_func_cmd(ctx, optee, shm);
+ break;
+ default:
+ pr_warn("Unknown RPC func 0x%x\n",
+ (u32)OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0));
+ break;
+ }
+
+ param->a0 = OPTEE_SMC_CALL_RETURN_FROM_RPC;
+}
diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c
new file mode 100644
index 000000000000..df35fc01fd3e
--- /dev/null
+++ b/drivers/tee/optee/supp.c
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include "optee_private.h"
+
+struct optee_supp_req {
+ struct list_head link;
+
+ bool busy;
+ u32 func;
+ u32 ret;
+ size_t num_params;
+ struct tee_param *param;
+
+ struct completion c;
+};
+
+void optee_supp_init(struct optee_supp *supp)
+{
+ memset(supp, 0, sizeof(*supp));
+ mutex_init(&supp->mutex);
+ init_completion(&supp->reqs_c);
+ idr_init(&supp->idr);
+ INIT_LIST_HEAD(&supp->reqs);
+ supp->req_id = -1;
+}
+
+void optee_supp_uninit(struct optee_supp *supp)
+{
+ mutex_destroy(&supp->mutex);
+ idr_destroy(&supp->idr);
+}
+
+void optee_supp_release(struct optee_supp *supp)
+{
+ int id;
+ struct optee_supp_req *req;
+ struct optee_supp_req *req_tmp;
+
+ mutex_lock(&supp->mutex);
+
+ /* Abort all request retrieved by supplicant */
+ idr_for_each_entry(&supp->idr, req, id) {
+ req->busy = false;
+ idr_remove(&supp->idr, id);
+ req->ret = TEEC_ERROR_COMMUNICATION;
+ complete(&req->c);
+ }
+
+ /* Abort all queued requests */
+ list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) {
+ list_del(&req->link);
+ req->ret = TEEC_ERROR_COMMUNICATION;
+ complete(&req->c);
+ }
+
+ supp->ctx = NULL;
+ supp->req_id = -1;
+
+ mutex_unlock(&supp->mutex);
+}
+
+/**
+ * optee_supp_thrd_req() - request service from supplicant
+ * @ctx: context doing the request
+ * @func: function requested
+ * @num_params: number of elements in @param array
+ * @param: parameters for function
+ *
+ * Returns result of operation to be passed to secure world
+ */
+u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
+ struct tee_param *param)
+
+{
+ struct optee *optee = tee_get_drvdata(ctx->teedev);
+ struct optee_supp *supp = &optee->supp;
+ struct optee_supp_req *req = kzalloc(sizeof(*req), GFP_KERNEL);
+ bool interruptable;
+ u32 ret;
+
+ if (!req)
+ return TEEC_ERROR_OUT_OF_MEMORY;
+
+ init_completion(&req->c);
+ req->func = func;
+ req->num_params = num_params;
+ req->param = param;
+
+ /* Insert the request in the request list */
+ mutex_lock(&supp->mutex);
+ list_add_tail(&req->link, &supp->reqs);
+ mutex_unlock(&supp->mutex);
+
+ /* Tell an eventual waiter there's a new request */
+ complete(&supp->reqs_c);
+
+ /*
+ * Wait for supplicant to process and return result, once we've
+ * returned from wait_for_completion(&req->c) successfully we have
+ * exclusive access again.
+ */
+ while (wait_for_completion_interruptible(&req->c)) {
+ mutex_lock(&supp->mutex);
+ interruptable = !supp->ctx;
+ if (interruptable) {
+ /*
+ * There's no supplicant available and since the
+ * supp->mutex currently is held none can
+ * become available until the mutex released
+ * again.
+ *
+ * Interrupting an RPC to supplicant is only
+ * allowed as a way of slightly improving the user
+ * experience in case the supplicant hasn't been
+ * started yet. During normal operation the supplicant
+ * will serve all requests in a timely manner and
+ * interrupting then wouldn't make sense.
+ */
+ interruptable = !req->busy;
+ if (!req->busy)
+ list_del(&req->link);
+ }
+ mutex_unlock(&supp->mutex);
+
+ if (interruptable) {
+ req->ret = TEEC_ERROR_COMMUNICATION;
+ break;
+ }
+ }
+
+ ret = req->ret;
+ kfree(req);
+
+ return ret;
+}
+
+static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp,
+ int num_params, int *id)
+{
+ struct optee_supp_req *req;
+
+ if (supp->req_id != -1) {
+ /*
+ * Supplicant should not mix synchronous and asnynchronous
+ * requests.
+ */
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (list_empty(&supp->reqs))
+ return NULL;
+
+ req = list_first_entry(&supp->reqs, struct optee_supp_req, link);
+
+ if (num_params < req->num_params) {
+ /* Not enough room for parameters */
+ return ERR_PTR(-EINVAL);
+ }
+
+ *id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL);
+ if (*id < 0)
+ return ERR_PTR(-ENOMEM);
+
+ list_del(&req->link);
+ req->busy = true;
+
+ return req;
+}
+
+static int supp_check_recv_params(size_t num_params, struct tee_param *params,
+ size_t *num_meta)
+{
+ size_t n;
+
+ if (!num_params)
+ return -EINVAL;
+
+ /*
+ * If there's memrefs we need to decrease those as they where
+ * increased earlier and we'll even refuse to accept any below.
+ */
+ for (n = 0; n < num_params; n++)
+ if (tee_param_is_memref(params + n) && params[n].u.memref.shm)
+ tee_shm_put(params[n].u.memref.shm);
+
+ /*
+ * We only expect parameters as TEE_IOCTL_PARAM_ATTR_TYPE_NONE with
+ * or without the TEE_IOCTL_PARAM_ATTR_META bit set.
+ */
+ for (n = 0; n < num_params; n++)
+ if (params[n].attr &&
+ params[n].attr != TEE_IOCTL_PARAM_ATTR_META)
+ return -EINVAL;
+
+ /* At most we'll need one meta parameter so no need to check for more */
+ if (params->attr == TEE_IOCTL_PARAM_ATTR_META)
+ *num_meta = 1;
+ else
+ *num_meta = 0;
+
+ return 0;
+}
+
+/**
+ * optee_supp_recv() - receive request for supplicant
+ * @ctx: context receiving the request
+ * @func: requested function in supplicant
+ * @num_params: number of elements allocated in @param, updated with number
+ * used elements
+ * @param: space for parameters for @func
+ *
+ * Returns 0 on success or <0 on failure
+ */
+int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
+ struct tee_param *param)
+{
+ struct tee_device *teedev = ctx->teedev;
+ struct optee *optee = tee_get_drvdata(teedev);
+ struct optee_supp *supp = &optee->supp;
+ struct optee_supp_req *req = NULL;
+ int id;
+ size_t num_meta;
+ int rc;
+
+ rc = supp_check_recv_params(*num_params, param, &num_meta);
+ if (rc)
+ return rc;
+
+ while (true) {
+ mutex_lock(&supp->mutex);
+ req = supp_pop_entry(supp, *num_params - num_meta, &id);
+ mutex_unlock(&supp->mutex);
+
+ if (req) {
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+ break;
+ }
+
+ /*
+ * If we didn't get a request we'll block in
+ * wait_for_completion() to avoid needless spinning.
+ *
+ * This is where supplicant will be hanging most of
+ * the time, let's make this interruptable so we
+ * can easily restart supplicant if needed.
+ */
+ if (wait_for_completion_interruptible(&supp->reqs_c))
+ return -ERESTARTSYS;
+ }
+
+ if (num_meta) {
+ /*
+ * tee-supplicant support meta parameters -> requsts can be
+ * processed asynchronously.
+ */
+ param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
+ TEE_IOCTL_PARAM_ATTR_META;
+ param->u.value.a = id;
+ param->u.value.b = 0;
+ param->u.value.c = 0;
+ } else {
+ mutex_lock(&supp->mutex);
+ supp->req_id = id;
+ mutex_unlock(&supp->mutex);
+ }
+
+ *func = req->func;
+ *num_params = req->num_params + num_meta;
+ memcpy(param + num_meta, req->param,
+ sizeof(struct tee_param) * req->num_params);
+
+ return 0;
+}
+
+static struct optee_supp_req *supp_pop_req(struct optee_supp *supp,
+ size_t num_params,
+ struct tee_param *param,
+ size_t *num_meta)
+{
+ struct optee_supp_req *req;
+ int id;
+ size_t nm;
+ const u32 attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
+ TEE_IOCTL_PARAM_ATTR_META;
+
+ if (!num_params)
+ return ERR_PTR(-EINVAL);
+
+ if (supp->req_id == -1) {
+ if (param->attr != attr)
+ return ERR_PTR(-EINVAL);
+ id = param->u.value.a;
+ nm = 1;
+ } else {
+ id = supp->req_id;
+ nm = 0;
+ }
+
+ req = idr_find(&supp->idr, id);
+ if (!req)
+ return ERR_PTR(-ENOENT);
+
+ if ((num_params - nm) != req->num_params)
+ return ERR_PTR(-EINVAL);
+
+ req->busy = false;
+ idr_remove(&supp->idr, id);
+ supp->req_id = -1;
+ *num_meta = nm;
+
+ return req;
+}
+
+/**
+ * optee_supp_send() - send result of request from supplicant
+ * @ctx: context sending result
+ * @ret: return value of request
+ * @num_params: number of parameters returned
+ * @param: returned parameters
+ *
+ * Returns 0 on success or <0 on failure.
+ */
+int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
+ struct tee_param *param)
+{
+ struct tee_device *teedev = ctx->teedev;
+ struct optee *optee = tee_get_drvdata(teedev);
+ struct optee_supp *supp = &optee->supp;
+ struct optee_supp_req *req;
+ size_t n;
+ size_t num_meta;
+
+ mutex_lock(&supp->mutex);
+ req = supp_pop_req(supp, num_params, param, &num_meta);
+ mutex_unlock(&supp->mutex);
+
+ if (IS_ERR(req)) {
+ /* Something is wrong, let supplicant restart. */
+ return PTR_ERR(req);
+ }
+
+ /* Update out and in/out parameters */
+ for (n = 0; n < req->num_params; n++) {
+ struct tee_param *p = req->param + n;
+
+ switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+ p->u.value.a = param[n + num_meta].u.value.a;
+ p->u.value.b = param[n + num_meta].u.value.b;
+ p->u.value.c = param[n + num_meta].u.value.c;
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ p->u.memref.size = param[n + num_meta].u.memref.size;
+ break;
+ default:
+ break;
+ }
+ }
+ req->ret = ret;
+
+ /* Let the requesting thread continue */
+ complete(&req->c);
+
+ return 0;
+}
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
new file mode 100644
index 000000000000..17bd0fc0c66e
--- /dev/null
+++ b/drivers/tee/tee_core.c
@@ -0,0 +1,1031 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include <linux/uaccess.h>
+#include "tee_private.h"
+
+#define TEE_NUM_DEVICES 32
+
+#define TEE_IOCTL_PARAM_SIZE(x) (sizeof(struct tee_param) * (x))
+
+/*
+ * Unprivileged devices in the lower half range and privileged devices in
+ * the upper half range.
+ */
+static DECLARE_BITMAP(dev_mask, TEE_NUM_DEVICES);
+static DEFINE_SPINLOCK(driver_lock);
+
+static struct class *tee_class;
+static dev_t tee_devt;
+
+static struct tee_context *teedev_open(struct tee_device *teedev)
+{
+ int rc;
+ struct tee_context *ctx;
+
+ if (!tee_device_get(teedev))
+ return ERR_PTR(-EINVAL);
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ ctx->teedev = teedev;
+ INIT_LIST_HEAD(&ctx->list_shm);
+ rc = teedev->desc->ops->open(ctx);
+ if (rc)
+ goto err;
+
+ return ctx;
+err:
+ kfree(ctx);
+ tee_device_put(teedev);
+ return ERR_PTR(rc);
+
+}
+
+static void teedev_close_context(struct tee_context *ctx)
+{
+ struct tee_shm *shm;
+
+ ctx->teedev->desc->ops->release(ctx);
+ mutex_lock(&ctx->teedev->mutex);
+ list_for_each_entry(shm, &ctx->list_shm, link)
+ shm->ctx = NULL;
+ mutex_unlock(&ctx->teedev->mutex);
+ tee_device_put(ctx->teedev);
+ kfree(ctx);
+}
+
+static int tee_open(struct inode *inode, struct file *filp)
+{
+ struct tee_context *ctx;
+
+ ctx = teedev_open(container_of(inode->i_cdev, struct tee_device, cdev));
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ filp->private_data = ctx;
+ return 0;
+}
+
+static int tee_release(struct inode *inode, struct file *filp)
+{
+ teedev_close_context(filp->private_data);
+ return 0;
+}
+
+static int tee_ioctl_version(struct tee_context *ctx,
+ struct tee_ioctl_version_data __user *uvers)
+{
+ struct tee_ioctl_version_data vers;
+
+ ctx->teedev->desc->ops->get_version(ctx->teedev, &vers);
+
+ if (ctx->teedev->desc->flags & TEE_DESC_PRIVILEGED)
+ vers.gen_caps |= TEE_GEN_CAP_PRIVILEGED;
+
+ if (copy_to_user(uvers, &vers, sizeof(vers)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int tee_ioctl_shm_alloc(struct tee_context *ctx,
+ struct tee_ioctl_shm_alloc_data __user *udata)
+{
+ long ret;
+ struct tee_ioctl_shm_alloc_data data;
+ struct tee_shm *shm;
+
+ if (copy_from_user(&data, udata, sizeof(data)))
+ return -EFAULT;
+
+ /* Currently no input flags are supported */
+ if (data.flags)
+ return -EINVAL;
+
+ data.id = -1;
+
+ shm = tee_shm_alloc(ctx, data.size, TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+ data.id = shm->id;
+ data.flags = shm->flags;
+ data.size = shm->size;
+
+ if (copy_to_user(udata, &data, sizeof(data)))
+ ret = -EFAULT;
+ else
+ ret = tee_shm_get_fd(shm);
+
+ /*
+ * When user space closes the file descriptor the shared memory
+ * should be freed or if tee_shm_get_fd() failed then it will
+ * be freed immediately.
+ */
+ tee_shm_put(shm);
+ return ret;
+}
+
+static int tee_ioctl_shm_register_fd(struct tee_context *ctx,
+ struct tee_ioctl_shm_register_fd_data __user *udata)
+{
+ struct tee_ioctl_shm_register_fd_data data;
+ struct tee_shm *shm;
+ long ret;
+
+ if (copy_from_user(&data, udata, sizeof(data)))
+ return -EFAULT;
+
+ /* Currently no input flags are supported */
+ if (data.flags)
+ return -EINVAL;
+
+ shm = tee_shm_register_fd(ctx, data.fd);
+ if (IS_ERR_OR_NULL(shm))
+ return -EINVAL;
+
+ data.id = shm->id;
+ data.flags = shm->flags;
+ data.size = shm->size;
+
+ if (copy_to_user(udata, &data, sizeof(data)))
+ ret = -EFAULT;
+ else
+ ret = tee_shm_get_fd(shm);
+
+ /*
+ * When user space closes the file descriptor the shared memory
+ * should be freed or if tee_shm_get_fd() failed then it will
+ * be freed immediately.
+ */
+ tee_shm_put(shm);
+ return ret;
+}
+
+static int params_from_user(struct tee_context *ctx, struct tee_param *params,
+ size_t num_params,
+ struct tee_ioctl_param __user *uparams)
+{
+ size_t n;
+
+ for (n = 0; n < num_params; n++) {
+ struct tee_shm *shm;
+ struct tee_ioctl_param ip;
+
+ if (copy_from_user(&ip, uparams + n, sizeof(ip)))
+ return -EFAULT;
+
+ /* All unused attribute bits has to be zero */
+ if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_MASK)
+ return -EINVAL;
+
+ params[n].attr = ip.attr;
+ switch (ip.attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_NONE:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+ params[n].u.value.a = ip.a;
+ params[n].u.value.b = ip.b;
+ params[n].u.value.c = ip.c;
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ /*
+ * If we fail to get a pointer to a shared memory
+ * object (and increase the ref count) from an
+ * identifier we return an error. All pointers that
+ * has been added in params have an increased ref
+ * count. It's the callers responibility to do
+ * tee_shm_put() on all resolved pointers.
+ */
+ shm = tee_shm_get_from_id(ctx, ip.c);
+ if (IS_ERR(shm))
+ return PTR_ERR(shm);
+
+ params[n].u.memref.shm_offs = ip.a;
+ params[n].u.memref.size = ip.b;
+ params[n].u.memref.shm = shm;
+ break;
+ default:
+ /* Unknown attribute */
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int params_to_user(struct tee_ioctl_param __user *uparams,
+ size_t num_params, struct tee_param *params)
+{
+ size_t n;
+
+ for (n = 0; n < num_params; n++) {
+ struct tee_ioctl_param __user *up = uparams + n;
+ struct tee_param *p = params + n;
+
+ switch (p->attr) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+ if (put_user(p->u.value.a, &up->a) ||
+ put_user(p->u.value.b, &up->b) ||
+ put_user(p->u.value.c, &up->c))
+ return -EFAULT;
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ if (put_user((u64)p->u.memref.size, &up->b))
+ return -EFAULT;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+static int tee_ioctl_open_session(struct tee_context *ctx,
+ struct tee_ioctl_buf_data __user *ubuf)
+{
+ int rc;
+ size_t n;
+ struct tee_ioctl_buf_data buf;
+ struct tee_ioctl_open_session_arg __user *uarg;
+ struct tee_ioctl_open_session_arg arg;
+ struct tee_ioctl_param __user *uparams = NULL;
+ struct tee_param *params = NULL;
+ bool have_session = false;
+
+ if (!ctx->teedev->desc->ops->open_session)
+ return -EINVAL;
+
+ if (copy_from_user(&buf, ubuf, sizeof(buf)))
+ return -EFAULT;
+
+ if (buf.buf_len > TEE_MAX_ARG_SIZE ||
+ buf.buf_len < sizeof(struct tee_ioctl_open_session_arg))
+ return -EINVAL;
+
+ uarg = u64_to_user_ptr(buf.buf_ptr);
+ if (copy_from_user(&arg, uarg, sizeof(arg)))
+ return -EFAULT;
+
+ if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len)
+ return -EINVAL;
+
+ if (arg.num_params) {
+ params = kcalloc(arg.num_params, sizeof(struct tee_param),
+ GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+ uparams = uarg->params;
+ rc = params_from_user(ctx, params, arg.num_params, uparams);
+ if (rc)
+ goto out;
+ }
+
+ rc = ctx->teedev->desc->ops->open_session(ctx, &arg, params);
+ if (rc)
+ goto out;
+ have_session = true;
+
+ if (put_user(arg.session, &uarg->session) ||
+ put_user(arg.ret, &uarg->ret) ||
+ put_user(arg.ret_origin, &uarg->ret_origin)) {
+ rc = -EFAULT;
+ goto out;
+ }
+ rc = params_to_user(uparams, arg.num_params, params);
+out:
+ /*
+ * If we've succeeded to open the session but failed to communicate
+ * it back to user space, close the session again to avoid leakage.
+ */
+ if (rc && have_session && ctx->teedev->desc->ops->close_session)
+ ctx->teedev->desc->ops->close_session(ctx, arg.session);
+
+ if (params) {
+ /* Decrease ref count for all valid shared memory pointers */
+ for (n = 0; n < arg.num_params; n++)
+ if (tee_param_is_memref(params + n) &&
+ params[n].u.memref.shm)
+ tee_shm_put(params[n].u.memref.shm);
+ kfree(params);
+ }
+
+ return rc;
+}
+
+static int tee_ioctl_invoke(struct tee_context *ctx,
+ struct tee_ioctl_buf_data __user *ubuf)
+{
+ int rc;
+ size_t n;
+ struct tee_ioctl_buf_data buf;
+ struct tee_ioctl_invoke_arg __user *uarg;
+ struct tee_ioctl_invoke_arg arg;
+ struct tee_ioctl_param __user *uparams = NULL;
+ struct tee_param *params = NULL;
+
+ if (!ctx->teedev->desc->ops->invoke_func)
+ return -EINVAL;
+
+ if (copy_from_user(&buf, ubuf, sizeof(buf)))
+ return -EFAULT;
+
+ if (buf.buf_len > TEE_MAX_ARG_SIZE ||
+ buf.buf_len < sizeof(struct tee_ioctl_invoke_arg))
+ return -EINVAL;
+
+ uarg = u64_to_user_ptr(buf.buf_ptr);
+ if (copy_from_user(&arg, uarg, sizeof(arg)))
+ return -EFAULT;
+
+ if (sizeof(arg) + TEE_IOCTL_PARAM_SIZE(arg.num_params) != buf.buf_len)
+ return -EINVAL;
+
+ if (arg.num_params) {
+ params = kcalloc(arg.num_params, sizeof(struct tee_param),
+ GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+ uparams = uarg->params;
+ rc = params_from_user(ctx, params, arg.num_params, uparams);
+ if (rc)
+ goto out;
+ }
+
+ rc = ctx->teedev->desc->ops->invoke_func(ctx, &arg, params);
+ if (rc)
+ goto out;
+
+ if (put_user(arg.ret, &uarg->ret) ||
+ put_user(arg.ret_origin, &uarg->ret_origin)) {
+ rc = -EFAULT;
+ goto out;
+ }
+ rc = params_to_user(uparams, arg.num_params, params);
+out:
+ if (params) {
+ /* Decrease ref count for all valid shared memory pointers */
+ for (n = 0; n < arg.num_params; n++)
+ if (tee_param_is_memref(params + n) &&
+ params[n].u.memref.shm)
+ tee_shm_put(params[n].u.memref.shm);
+ kfree(params);
+ }
+ return rc;
+}
+
+static int tee_ioctl_cancel(struct tee_context *ctx,
+ struct tee_ioctl_cancel_arg __user *uarg)
+{
+ struct tee_ioctl_cancel_arg arg;
+
+ if (!ctx->teedev->desc->ops->cancel_req)
+ return -EINVAL;
+
+ if (copy_from_user(&arg, uarg, sizeof(arg)))
+ return -EFAULT;
+
+ return ctx->teedev->desc->ops->cancel_req(ctx, arg.cancel_id,
+ arg.session);
+}
+
+static int
+tee_ioctl_close_session(struct tee_context *ctx,
+ struct tee_ioctl_close_session_arg __user *uarg)
+{
+ struct tee_ioctl_close_session_arg arg;
+
+ if (!ctx->teedev->desc->ops->close_session)
+ return -EINVAL;
+
+ if (copy_from_user(&arg, uarg, sizeof(arg)))
+ return -EFAULT;
+
+ return ctx->teedev->desc->ops->close_session(ctx, arg.session);
+}
+
+static int params_to_supp(struct tee_context *ctx,
+ struct tee_ioctl_param __user *uparams,
+ size_t num_params, struct tee_param *params)
+{
+ size_t n;
+
+ for (n = 0; n < num_params; n++) {
+ struct tee_ioctl_param ip;
+ struct tee_param *p = params + n;
+
+ ip.attr = p->attr;
+ switch (p->attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+ ip.a = p->u.value.a;
+ ip.b = p->u.value.b;
+ ip.c = p->u.value.c;
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ ip.b = p->u.memref.size;
+ if (!p->u.memref.shm) {
+ ip.a = 0;
+ ip.c = (u64)-1; /* invalid shm id */
+ break;
+ }
+ ip.a = p->u.memref.shm_offs;
+ ip.c = p->u.memref.shm->id;
+ break;
+ default:
+ ip.a = 0;
+ ip.b = 0;
+ ip.c = 0;
+ break;
+ }
+
+ if (copy_to_user(uparams + n, &ip, sizeof(ip)))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int tee_ioctl_supp_recv(struct tee_context *ctx,
+ struct tee_ioctl_buf_data __user *ubuf)
+{
+ int rc;
+ struct tee_ioctl_buf_data buf;
+ struct tee_iocl_supp_recv_arg __user *uarg;
+ struct tee_param *params;
+ u32 num_params;
+ u32 func;
+
+ if (!ctx->teedev->desc->ops->supp_recv)
+ return -EINVAL;
+
+ if (copy_from_user(&buf, ubuf, sizeof(buf)))
+ return -EFAULT;
+
+ if (buf.buf_len > TEE_MAX_ARG_SIZE ||
+ buf.buf_len < sizeof(struct tee_iocl_supp_recv_arg))
+ return -EINVAL;
+
+ uarg = u64_to_user_ptr(buf.buf_ptr);
+ if (get_user(num_params, &uarg->num_params))
+ return -EFAULT;
+
+ if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) != buf.buf_len)
+ return -EINVAL;
+
+ params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ rc = params_from_user(ctx, params, num_params, uarg->params);
+ if (rc)
+ goto out;
+
+ rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params);
+ if (rc)
+ goto out;
+
+ if (put_user(func, &uarg->func) ||
+ put_user(num_params, &uarg->num_params)) {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ rc = params_to_supp(ctx, uarg->params, num_params, params);
+out:
+ kfree(params);
+ return rc;
+}
+
+static int params_from_supp(struct tee_param *params, size_t num_params,
+ struct tee_ioctl_param __user *uparams)
+{
+ size_t n;
+
+ for (n = 0; n < num_params; n++) {
+ struct tee_param *p = params + n;
+ struct tee_ioctl_param ip;
+
+ if (copy_from_user(&ip, uparams + n, sizeof(ip)))
+ return -EFAULT;
+
+ /* All unused attribute bits has to be zero */
+ if (ip.attr & ~TEE_IOCTL_PARAM_ATTR_MASK)
+ return -EINVAL;
+
+ p->attr = ip.attr;
+ switch (ip.attr & TEE_IOCTL_PARAM_ATTR_TYPE_MASK) {
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
+ /* Only out and in/out values can be updated */
+ p->u.value.a = ip.a;
+ p->u.value.b = ip.b;
+ p->u.value.c = ip.c;
+ break;
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
+ case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
+ /*
+ * Only the size of the memref can be updated.
+ * Since we don't have access to the original
+ * parameters here, only store the supplied size.
+ * The driver will copy the updated size into the
+ * original parameters.
+ */
+ p->u.memref.shm = NULL;
+ p->u.memref.shm_offs = 0;
+ p->u.memref.size = ip.b;
+ break;
+ default:
+ memset(&p->u, 0, sizeof(p->u));
+ break;
+ }
+ }
+ return 0;
+}
+
+static int tee_ioctl_supp_send(struct tee_context *ctx,
+ struct tee_ioctl_buf_data __user *ubuf)
+{
+ long rc;
+ struct tee_ioctl_buf_data buf;
+ struct tee_iocl_supp_send_arg __user *uarg;
+ struct tee_param *params;
+ u32 num_params;
+ u32 ret;
+
+ /* Not valid for this driver */
+ if (!ctx->teedev->desc->ops->supp_send)
+ return -EINVAL;
+
+ if (copy_from_user(&buf, ubuf, sizeof(buf)))
+ return -EFAULT;
+
+ if (buf.buf_len > TEE_MAX_ARG_SIZE ||
+ buf.buf_len < sizeof(struct tee_iocl_supp_send_arg))
+ return -EINVAL;
+
+ uarg = u64_to_user_ptr(buf.buf_ptr);
+ if (get_user(ret, &uarg->ret) ||
+ get_user(num_params, &uarg->num_params))
+ return -EFAULT;
+
+ if (sizeof(*uarg) + TEE_IOCTL_PARAM_SIZE(num_params) > buf.buf_len)
+ return -EINVAL;
+
+ params = kcalloc(num_params, sizeof(struct tee_param), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
+
+ rc = params_from_supp(params, num_params, uarg->params);
+ if (rc)
+ goto out;
+
+ rc = ctx->teedev->desc->ops->supp_send(ctx, ret, num_params, params);
+out:
+ kfree(params);
+ return rc;
+}
+
+static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ struct tee_context *ctx = filp->private_data;
+ void __user *uarg = (void __user *)arg;
+
+ switch (cmd) {
+ case TEE_IOC_VERSION:
+ return tee_ioctl_version(ctx, uarg);
+ case TEE_IOC_SHM_ALLOC:
+ return tee_ioctl_shm_alloc(ctx, uarg);
+ case TEE_IOC_SHM_REGISTER_FD:
+ return tee_ioctl_shm_register_fd(ctx, uarg);
+ case TEE_IOC_OPEN_SESSION:
+ return tee_ioctl_open_session(ctx, uarg);
+ case TEE_IOC_INVOKE:
+ return tee_ioctl_invoke(ctx, uarg);
+ case TEE_IOC_CANCEL:
+ return tee_ioctl_cancel(ctx, uarg);
+ case TEE_IOC_CLOSE_SESSION:
+ return tee_ioctl_close_session(ctx, uarg);
+ case TEE_IOC_SUPPL_RECV:
+ return tee_ioctl_supp_recv(ctx, uarg);
+ case TEE_IOC_SUPPL_SEND:
+ return tee_ioctl_supp_send(ctx, uarg);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct file_operations tee_fops = {
+ .owner = THIS_MODULE,
+ .open = tee_open,
+ .release = tee_release,
+ .unlocked_ioctl = tee_ioctl,
+ .compat_ioctl = tee_ioctl,
+};
+
+static void tee_release_device(struct device *dev)
+{
+ struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+
+ spin_lock(&driver_lock);
+ clear_bit(teedev->id, dev_mask);
+ spin_unlock(&driver_lock);
+ mutex_destroy(&teedev->mutex);
+ idr_destroy(&teedev->idr);
+ kfree(teedev);
+}
+
+/**
+ * tee_device_alloc() - Allocate a new struct tee_device instance
+ * @teedesc: Descriptor for this driver
+ * @dev: Parent device for this device
+ * @pool: Shared memory pool, NULL if not used
+ * @driver_data: Private driver data for this device
+ *
+ * Allocates a new struct tee_device instance. The device is
+ * removed by tee_device_unregister().
+ *
+ * @returns a pointer to a 'struct tee_device' or an ERR_PTR on failure
+ */
+struct tee_device *tee_device_alloc(const struct tee_desc *teedesc,
+ struct device *dev,
+ struct tee_shm_pool *pool,
+ void *driver_data)
+{
+ struct tee_device *teedev;
+ void *ret;
+ int rc;
+ int offs = 0;
+
+ if (!teedesc || !teedesc->name || !teedesc->ops ||
+ !teedesc->ops->get_version || !teedesc->ops->open ||
+ !teedesc->ops->release || !pool)
+ return ERR_PTR(-EINVAL);
+
+ teedev = kzalloc(sizeof(*teedev), GFP_KERNEL);
+ if (!teedev) {
+ ret = ERR_PTR(-ENOMEM);
+ goto err;
+ }
+
+ if (teedesc->flags & TEE_DESC_PRIVILEGED)
+ offs = TEE_NUM_DEVICES / 2;
+
+ spin_lock(&driver_lock);
+ teedev->id = find_next_zero_bit(dev_mask, TEE_NUM_DEVICES, offs);
+ if (teedev->id < TEE_NUM_DEVICES)
+ set_bit(teedev->id, dev_mask);
+ spin_unlock(&driver_lock);
+
+ if (teedev->id >= TEE_NUM_DEVICES) {
+ ret = ERR_PTR(-ENOMEM);
+ goto err;
+ }
+
+ snprintf(teedev->name, sizeof(teedev->name), "tee%s%d",
+ teedesc->flags & TEE_DESC_PRIVILEGED ? "priv" : "",
+ teedev->id - offs);
+
+ teedev->dev.class = tee_class;
+ teedev->dev.release = tee_release_device;
+ teedev->dev.parent = dev;
+
+ teedev->dev.devt = MKDEV(MAJOR(tee_devt), teedev->id);
+
+ rc = dev_set_name(&teedev->dev, "%s", teedev->name);
+ if (rc) {
+ ret = ERR_PTR(rc);
+ goto err_devt;
+ }
+
+ cdev_init(&teedev->cdev, &tee_fops);
+ teedev->cdev.owner = teedesc->owner;
+ teedev->cdev.kobj.parent = &teedev->dev.kobj;
+
+ dev_set_drvdata(&teedev->dev, driver_data);
+ device_initialize(&teedev->dev);
+
+ /* 1 as tee_device_unregister() does one final tee_device_put() */
+ teedev->num_users = 1;
+ init_completion(&teedev->c_no_users);
+ mutex_init(&teedev->mutex);
+ idr_init(&teedev->idr);
+
+ teedev->desc = teedesc;
+ teedev->pool = pool;
+
+ return teedev;
+err_devt:
+ unregister_chrdev_region(teedev->dev.devt, 1);
+err:
+ pr_err("could not register %s driver\n",
+ teedesc->flags & TEE_DESC_PRIVILEGED ? "privileged" : "client");
+ if (teedev && teedev->id < TEE_NUM_DEVICES) {
+ spin_lock(&driver_lock);
+ clear_bit(teedev->id, dev_mask);
+ spin_unlock(&driver_lock);
+ }
+ kfree(teedev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tee_device_alloc);
+
+static ssize_t implementation_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+ struct tee_ioctl_version_data vers;
+
+ teedev->desc->ops->get_version(teedev, &vers);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", vers.impl_id);
+}
+static DEVICE_ATTR_RO(implementation_id);
+
+static struct attribute *tee_dev_attrs[] = {
+ &dev_attr_implementation_id.attr,
+ NULL
+};
+
+static const struct attribute_group tee_dev_group = {
+ .attrs = tee_dev_attrs,
+};
+
+/**
+ * tee_device_register() - Registers a TEE device
+ * @teedev: Device to register
+ *
+ * tee_device_unregister() need to be called to remove the @teedev if
+ * this function fails.
+ *
+ * @returns < 0 on failure
+ */
+int tee_device_register(struct tee_device *teedev)
+{
+ int rc;
+
+ if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) {
+ dev_err(&teedev->dev, "attempt to register twice\n");
+ return -EINVAL;
+ }
+
+ rc = cdev_add(&teedev->cdev, teedev->dev.devt, 1);
+ if (rc) {
+ dev_err(&teedev->dev,
+ "unable to cdev_add() %s, major %d, minor %d, err=%d\n",
+ teedev->name, MAJOR(teedev->dev.devt),
+ MINOR(teedev->dev.devt), rc);
+ return rc;
+ }
+
+ rc = device_add(&teedev->dev);
+ if (rc) {
+ dev_err(&teedev->dev,
+ "unable to device_add() %s, major %d, minor %d, err=%d\n",
+ teedev->name, MAJOR(teedev->dev.devt),
+ MINOR(teedev->dev.devt), rc);
+ goto err_device_add;
+ }
+
+ rc = sysfs_create_group(&teedev->dev.kobj, &tee_dev_group);
+ if (rc) {
+ dev_err(&teedev->dev,
+ "failed to create sysfs attributes, err=%d\n", rc);
+ goto err_sysfs_create_group;
+ }
+
+ teedev->flags |= TEE_DEVICE_FLAG_REGISTERED;
+ return 0;
+
+err_sysfs_create_group:
+ device_del(&teedev->dev);
+err_device_add:
+ cdev_del(&teedev->cdev);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(tee_device_register);
+
+void tee_device_put(struct tee_device *teedev)
+{
+ mutex_lock(&teedev->mutex);
+ /* Shouldn't put in this state */
+ if (!WARN_ON(!teedev->desc)) {
+ teedev->num_users--;
+ if (!teedev->num_users) {
+ teedev->desc = NULL;
+ complete(&teedev->c_no_users);
+ }
+ }
+ mutex_unlock(&teedev->mutex);
+}
+
+bool tee_device_get(struct tee_device *teedev)
+{
+ mutex_lock(&teedev->mutex);
+ if (!teedev->desc) {
+ mutex_unlock(&teedev->mutex);
+ return false;
+ }
+ teedev->num_users++;
+ mutex_unlock(&teedev->mutex);
+ return true;
+}
+
+/**
+ * tee_device_unregister() - Removes a TEE device
+ * @teedev: Device to unregister
+ *
+ * This function should be called to remove the @teedev even if
+ * tee_device_register() hasn't been called yet. Does nothing if
+ * @teedev is NULL.
+ */
+void tee_device_unregister(struct tee_device *teedev)
+{
+ if (!teedev)
+ return;
+
+ if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) {
+ sysfs_remove_group(&teedev->dev.kobj, &tee_dev_group);
+ cdev_del(&teedev->cdev);
+ device_del(&teedev->dev);
+ }
+
+ tee_device_put(teedev);
+ wait_for_completion(&teedev->c_no_users);
+
+ /*
+ * No need to take a mutex any longer now since teedev->desc was
+ * set to NULL before teedev->c_no_users was completed.
+ */
+
+ teedev->pool = NULL;
+
+ put_device(&teedev->dev);
+}
+EXPORT_SYMBOL_GPL(tee_device_unregister);
+
+/**
+ * tee_get_drvdata() - Return driver_data pointer
+ * @teedev: Device containing the driver_data pointer
+ * @returns the driver_data pointer supplied to tee_register().
+ */
+void *tee_get_drvdata(struct tee_device *teedev)
+{
+ return dev_get_drvdata(&teedev->dev);
+}
+EXPORT_SYMBOL_GPL(tee_get_drvdata);
+
+struct match_dev_data {
+ struct tee_ioctl_version_data *vers;
+ const void *data;
+ int (*match)(struct tee_ioctl_version_data *, const void *);
+};
+
+static int match_dev(struct device *dev, const void *data)
+{
+ const struct match_dev_data *match_data = data;
+ struct tee_device *teedev = container_of(dev, struct tee_device, dev);
+
+ teedev->desc->ops->get_version(teedev, match_data->vers);
+ return match_data->match(match_data->vers, match_data->data);
+}
+
+struct tee_context *tee_client_open_context(struct tee_context *start,
+ int (*match)(struct tee_ioctl_version_data *,
+ const void *),
+ const void *data, struct tee_ioctl_version_data *vers)
+{
+ struct device *dev = NULL;
+ struct device *put_dev = NULL;
+ struct tee_context *ctx = NULL;
+ struct tee_ioctl_version_data v;
+ struct match_dev_data match_data = { vers ? vers : &v, data, match };
+
+ if (start)
+ dev = &start->teedev->dev;
+
+ do {
+ dev = class_find_device(tee_class, dev, &match_data, match_dev);
+ if (!dev) {
+ ctx = ERR_PTR(-ENOENT);
+ break;
+ }
+
+ put_device(put_dev);
+ put_dev = dev;
+
+ ctx = teedev_open(container_of(dev, struct tee_device, dev));
+ } while (IS_ERR(ctx) && PTR_ERR(ctx) != -ENOMEM);
+
+ put_device(put_dev);
+ return ctx;
+}
+EXPORT_SYMBOL_GPL(tee_client_open_context);
+
+void tee_client_close_context(struct tee_context *ctx)
+{
+ teedev_close_context(ctx);
+}
+
+EXPORT_SYMBOL_GPL(tee_client_close_context);
+
+void tee_client_get_version(struct tee_context *ctx,
+ struct tee_ioctl_version_data *vers)
+{
+ ctx->teedev->desc->ops->get_version(ctx->teedev, vers);
+}
+EXPORT_SYMBOL_GPL(tee_client_get_version);
+
+
+int tee_client_open_session(struct tee_context *ctx,
+ struct tee_ioctl_open_session_arg *arg,
+ struct tee_param *param)
+{
+ if (!ctx->teedev->desc->ops->open_session)
+ return -EINVAL;
+ return ctx->teedev->desc->ops->open_session(ctx, arg, param);
+}
+EXPORT_SYMBOL_GPL(tee_client_open_session);
+
+int tee_client_close_session(struct tee_context *ctx, u32 session)
+{
+ if (!ctx->teedev->desc->ops->close_session)
+ return -EINVAL;
+ return ctx->teedev->desc->ops->close_session(ctx, session);
+}
+EXPORT_SYMBOL_GPL(tee_client_close_session);
+
+int tee_client_invoke_func(struct tee_context *ctx,
+ struct tee_ioctl_invoke_arg *arg,
+ struct tee_param *param)
+{
+ if (!ctx->teedev->desc->ops->invoke_func)
+ return -EINVAL;
+ return ctx->teedev->desc->ops->invoke_func(ctx, arg, param);
+}
+EXPORT_SYMBOL_GPL(tee_client_invoke_func);
+
+static int __init tee_init(void)
+{
+ int rc;
+
+ tee_class = class_create(THIS_MODULE, "tee");
+ if (IS_ERR(tee_class)) {
+ pr_err("couldn't create class\n");
+ return PTR_ERR(tee_class);
+ }
+
+ rc = alloc_chrdev_region(&tee_devt, 0, TEE_NUM_DEVICES, "tee");
+ if (rc) {
+ pr_err("failed to allocate char dev region\n");
+ class_destroy(tee_class);
+ tee_class = NULL;
+ }
+
+ return rc;
+}
+
+static void __exit tee_exit(void)
+{
+ class_destroy(tee_class);
+ tee_class = NULL;
+ unregister_chrdev_region(tee_devt, TEE_NUM_DEVICES);
+}
+
+subsys_initcall(tee_init);
+module_exit(tee_exit);
+
+MODULE_AUTHOR("Linaro");
+MODULE_DESCRIPTION("TEE Driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tee/tee_private.h b/drivers/tee/tee_private.h
new file mode 100644
index 000000000000..21cb6be8bce9
--- /dev/null
+++ b/drivers/tee/tee_private.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ *
+ * 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 TEE_PRIVATE_H
+#define TEE_PRIVATE_H
+
+#include <linux/cdev.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/kref.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+struct tee_device;
+
+/**
+ * struct tee_shm - shared memory object
+ * @teedev: device used to allocate the object
+ * @ctx: context using the object, if NULL the context is gone
+ * @link link element
+ * @paddr: physical address of the shared memory
+ * @kaddr: virtual address of the shared memory
+ * @size: size of shared memory
+ * @dmabuf: dmabuf used to for exporting to user space
+ * @flags: defined by TEE_SHM_* in tee_drv.h
+ * @id: unique id of a shared memory object on this device
+ */
+struct tee_shm {
+ struct tee_device *teedev;
+ struct tee_context *ctx;
+ struct list_head link;
+ phys_addr_t paddr;
+ void *kaddr;
+ size_t size;
+ struct dma_buf *dmabuf;
+ u32 flags;
+ int id;
+};
+
+struct tee_shm_pool_mgr;
+
+/**
+ * struct tee_shm_pool_mgr_ops - shared memory pool manager operations
+ * @alloc: called when allocating shared memory
+ * @free: called when freeing shared memory
+ */
+struct tee_shm_pool_mgr_ops {
+ int (*alloc)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm,
+ size_t size);
+ void (*free)(struct tee_shm_pool_mgr *poolmgr, struct tee_shm *shm);
+};
+
+/**
+ * struct tee_shm_pool_mgr - shared memory manager
+ * @ops: operations
+ * @private_data: private data for the shared memory manager
+ */
+struct tee_shm_pool_mgr {
+ const struct tee_shm_pool_mgr_ops *ops;
+ void *private_data;
+};
+
+/**
+ * struct tee_shm_pool - shared memory pool
+ * @private_mgr: pool manager for shared memory only between kernel
+ * and secure world
+ * @dma_buf_mgr: pool manager for shared memory exported to user space
+ * @destroy: called when destroying the pool
+ * @private_data: private data for the pool
+ */
+struct tee_shm_pool {
+ struct tee_shm_pool_mgr private_mgr;
+ struct tee_shm_pool_mgr dma_buf_mgr;
+ void (*destroy)(struct tee_shm_pool *pool);
+ void *private_data;
+};
+
+#define TEE_DEVICE_FLAG_REGISTERED 0x1
+#define TEE_MAX_DEV_NAME_LEN 32
+
+/**
+ * struct tee_device - TEE Device representation
+ * @name: name of device
+ * @desc: description of device
+ * @id: unique id of device
+ * @flags: represented by TEE_DEVICE_FLAG_REGISTERED above
+ * @dev: embedded basic device structure
+ * @cdev: embedded cdev
+ * @num_users: number of active users of this device
+ * @c_no_user: completion used when unregistering the device
+ * @mutex: mutex protecting @num_users and @idr
+ * @idr: register of shared memory object allocated on this device
+ * @pool: shared memory pool
+ */
+struct tee_device {
+ char name[TEE_MAX_DEV_NAME_LEN];
+ const struct tee_desc *desc;
+ int id;
+ unsigned int flags;
+
+ struct device dev;
+ struct cdev cdev;
+
+ size_t num_users;
+ struct completion c_no_users;
+ struct mutex mutex; /* protects num_users and idr */
+
+ struct idr idr;
+ struct tee_shm_pool *pool;
+};
+
+int tee_shm_init(void);
+
+int tee_shm_get_fd(struct tee_shm *shm);
+
+bool tee_device_get(struct tee_device *teedev);
+void tee_device_put(struct tee_device *teedev);
+
+#endif /*TEE_PRIVATE_H*/
diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
new file mode 100644
index 000000000000..c5b561a12bb9
--- /dev/null
+++ b/drivers/tee/tee_shm.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 2015-2016, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/device.h>
+#include <linux/dma-buf.h>
+#include <linux/fdtable.h>
+#include <linux/idr.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include "tee_private.h"
+
+/* extra references appended to shm object for registered shared memory */
+struct tee_shm_dmabuf_ref {
+ struct tee_shm shm;
+ struct dma_buf *dmabuf;
+ struct dma_buf_attachment *attach;
+ struct sg_table *sgt;
+};
+
+static void tee_shm_release(struct tee_shm *shm)
+{
+ struct tee_device *teedev = shm->teedev;
+
+ mutex_lock(&teedev->mutex);
+ idr_remove(&teedev->idr, shm->id);
+ if (shm->ctx)
+ list_del(&shm->link);
+ mutex_unlock(&teedev->mutex);
+
+ if (shm->flags & TEE_SHM_EXT_DMA_BUF) {
+ struct tee_shm_dmabuf_ref *ref;
+
+ ref = container_of(shm, struct tee_shm_dmabuf_ref, shm);
+ dma_buf_unmap_attachment(ref->attach, ref->sgt,
+ DMA_BIDIRECTIONAL);
+ dma_buf_detach(shm->dmabuf, ref->attach);
+ dma_buf_put(ref->dmabuf);
+ } else {
+ struct tee_shm_pool_mgr *poolm;
+
+ if (shm->flags & TEE_SHM_DMA_BUF)
+ poolm = &teedev->pool->dma_buf_mgr;
+ else
+ poolm = &teedev->pool->private_mgr;
+
+ poolm->ops->free(poolm, shm);
+ }
+
+ kfree(shm);
+ tee_device_put(teedev);
+}
+
+static struct sg_table *tee_shm_op_map_dma_buf(struct dma_buf_attachment
+ *attach, enum dma_data_direction dir)
+{
+ return NULL;
+}
+
+static void tee_shm_op_unmap_dma_buf(struct dma_buf_attachment *attach,
+ struct sg_table *table,
+ enum dma_data_direction dir)
+{
+}
+
+static void tee_shm_op_release(struct dma_buf *dmabuf)
+{
+ struct tee_shm *shm = dmabuf->priv;
+
+ tee_shm_release(shm);
+}
+
+static void *tee_shm_op_kmap_atomic(struct dma_buf *dmabuf, unsigned long pgnum)
+{
+ return NULL;
+}
+
+static void *tee_shm_op_kmap(struct dma_buf *dmabuf, unsigned long pgnum)
+{
+ return NULL;
+}
+
+static int tee_shm_op_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
+{
+ struct tee_shm *shm = dmabuf->priv;
+ size_t size = vma->vm_end - vma->vm_start;
+
+ return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT,
+ size, vma->vm_page_prot);
+}
+
+static const struct dma_buf_ops tee_shm_dma_buf_ops = {
+ .map_dma_buf = tee_shm_op_map_dma_buf,
+ .unmap_dma_buf = tee_shm_op_unmap_dma_buf,
+ .release = tee_shm_op_release,
+ .kmap_atomic = tee_shm_op_kmap_atomic,
+ .kmap = tee_shm_op_kmap,
+ .mmap = tee_shm_op_mmap,
+};
+
+/**
+ * tee_shm_alloc() - Allocate shared memory
+ * @ctx: Context that allocates the shared memory
+ * @size: Requested size of shared memory
+ * @flags: Flags setting properties for the requested shared memory.
+ *
+ * Memory allocated as global shared memory is automatically freed when the
+ * TEE file pointer is closed. The @flags field uses the bits defined by
+ * TEE_SHM_* in <linux/tee_drv.h>. TEE_SHM_MAPPED must currently always be
+ * set. If TEE_SHM_DMA_BUF global shared memory will be allocated and
+ * associated with a dma-buf handle, else driver private memory.
+ */
+struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags)
+{
+ struct tee_device *teedev = ctx->teedev;
+ struct tee_shm_pool_mgr *poolm = NULL;
+ struct tee_shm *shm;
+ void *ret;
+ int rc;
+
+ if (!(flags & TEE_SHM_MAPPED)) {
+ dev_err(teedev->dev.parent,
+ "only mapped allocations supported\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if ((flags & ~(TEE_SHM_MAPPED | TEE_SHM_DMA_BUF))) {
+ dev_err(teedev->dev.parent, "invalid shm flags 0x%x", flags);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!tee_device_get(teedev))
+ return ERR_PTR(-EINVAL);
+
+ if (!teedev->pool) {
+ /* teedev has been detached from driver */
+ ret = ERR_PTR(-EINVAL);
+ goto err_dev_put;
+ }
+
+ shm = kzalloc(sizeof(*shm), GFP_KERNEL);
+ if (!shm) {
+ ret = ERR_PTR(-ENOMEM);
+ goto err_dev_put;
+ }
+
+ shm->flags = flags;
+ shm->teedev = teedev;
+ shm->ctx = ctx;
+ if (flags & TEE_SHM_DMA_BUF)
+ poolm = &teedev->pool->dma_buf_mgr;
+ else
+ poolm = &teedev->pool->private_mgr;
+
+ rc = poolm->ops->alloc(poolm, shm, size);
+ if (rc) {
+ ret = ERR_PTR(rc);
+ goto err_kfree;
+ }
+
+ mutex_lock(&teedev->mutex);
+ shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL);
+ mutex_unlock(&teedev->mutex);
+ if (shm->id < 0) {
+ ret = ERR_PTR(shm->id);
+ goto err_pool_free;
+ }
+
+ if (flags & TEE_SHM_DMA_BUF) {
+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+
+ exp_info.ops = &tee_shm_dma_buf_ops;
+ exp_info.size = shm->size;
+ exp_info.flags = O_RDWR;
+ exp_info.priv = shm;
+
+ shm->dmabuf = dma_buf_export(&exp_info);
+ if (IS_ERR(shm->dmabuf)) {
+ ret = ERR_CAST(shm->dmabuf);
+ goto err_rem;
+ }
+ }
+ mutex_lock(&teedev->mutex);
+ list_add_tail(&shm->link, &ctx->list_shm);
+ mutex_unlock(&teedev->mutex);
+
+ return shm;
+err_rem:
+ mutex_lock(&teedev->mutex);
+ idr_remove(&teedev->idr, shm->id);
+ mutex_unlock(&teedev->mutex);
+err_pool_free:
+ poolm->ops->free(poolm, shm);
+err_kfree:
+ kfree(shm);
+err_dev_put:
+ tee_device_put(teedev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tee_shm_alloc);
+
+struct tee_shm *tee_shm_register_fd(struct tee_context *ctx, int fd)
+{
+ struct tee_shm_dmabuf_ref *ref;
+ void *rc;
+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+
+ if (!tee_device_get(ctx->teedev))
+ return ERR_PTR(-EINVAL);
+
+ ref = kzalloc(sizeof(*ref), GFP_KERNEL);
+ if (!ref) {
+ rc = ERR_PTR(-ENOMEM);
+ goto err;
+ }
+
+ ref->shm.ctx = ctx;
+ ref->shm.teedev = ctx->teedev;
+ ref->shm.id = -1;
+
+ ref->dmabuf = dma_buf_get(fd);
+ if (!ref->dmabuf) {
+ rc = ERR_PTR(-EINVAL);
+ goto err;
+ }
+
+ ref->attach = dma_buf_attach(ref->dmabuf, &ref->shm.teedev->dev);
+ if (IS_ERR_OR_NULL(ref->attach)) {
+ rc = ERR_PTR(-EINVAL);
+ goto err;
+ }
+
+ ref->sgt = dma_buf_map_attachment(ref->attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR_OR_NULL(ref->sgt)) {
+ rc = ERR_PTR(-EINVAL);
+ goto err;
+ }
+
+ if (sg_nents(ref->sgt->sgl) != 1) {
+ rc = ERR_PTR(-EINVAL);
+ goto err;
+ }
+
+ ref->shm.paddr = sg_dma_address(ref->sgt->sgl);
+ ref->shm.size = sg_dma_len(ref->sgt->sgl);
+ ref->shm.flags = TEE_SHM_DMA_BUF | TEE_SHM_EXT_DMA_BUF;
+
+ mutex_lock(&ref->shm.teedev->mutex);
+ ref->shm.id = idr_alloc(&ref->shm.teedev->idr, &ref->shm,
+ 1, 0, GFP_KERNEL);
+ mutex_unlock(&ref->shm.teedev->mutex);
+ if (ref->shm.id < 0) {
+ rc = ERR_PTR(ref->shm.id);
+ goto err;
+ }
+
+ /* export a dmabuf to later get a userland ref */
+ exp_info.ops = &tee_shm_dma_buf_ops;
+ exp_info.size = ref->shm.size;
+ exp_info.flags = O_RDWR;
+ exp_info.priv = &ref->shm;
+
+ ref->shm.dmabuf = dma_buf_export(&exp_info);
+ if (IS_ERR(ref->shm.dmabuf)) {
+ rc = ERR_PTR(-EINVAL);
+ goto err;
+ }
+
+ mutex_lock(&ref->shm.teedev->mutex);
+ list_add_tail(&ref->shm.link, &ctx->list_shm);
+ mutex_unlock(&ref->shm.teedev->mutex);
+
+ return &ref->shm;
+
+err:
+ if (ref) {
+ if (ref->shm.id >= 0) {
+ mutex_lock(&ctx->teedev->mutex);
+ idr_remove(&ctx->teedev->idr, ref->shm.id);
+ mutex_unlock(&ctx->teedev->mutex);
+ }
+ if (ref->sgt)
+ dma_buf_unmap_attachment(ref->attach, ref->sgt,
+ DMA_BIDIRECTIONAL);
+ if (ref->attach)
+ dma_buf_detach(ref->dmabuf, ref->attach);
+ if (ref->dmabuf)
+ dma_buf_put(ref->dmabuf);
+ }
+ kfree(ref);
+ tee_device_put(ctx->teedev);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(tee_shm_register_fd);
+
+/**
+ * tee_shm_get_fd() - Increase reference count and return file descriptor
+ * @shm: Shared memory handle
+ * @returns user space file descriptor to shared memory
+ */
+int tee_shm_get_fd(struct tee_shm *shm)
+{
+ int fd;
+
+ if (!(shm->flags & TEE_SHM_DMA_BUF))
+ return -EINVAL;
+
+ fd = dma_buf_fd(shm->dmabuf, O_CLOEXEC);
+ if (fd >= 0)
+ get_dma_buf(shm->dmabuf);
+ return fd;
+}
+
+/**
+ * tee_shm_free() - Free shared memory
+ * @shm: Handle to shared memory to free
+ */
+void tee_shm_free(struct tee_shm *shm)
+{
+ /*
+ * dma_buf_put() decreases the dmabuf reference counter and will
+ * call tee_shm_release() when the last reference is gone.
+ *
+ * In the case of driver private memory we call tee_shm_release
+ * directly instead as it doesn't have a reference counter.
+ */
+ if (shm->flags & TEE_SHM_DMA_BUF)
+ dma_buf_put(shm->dmabuf);
+ else
+ tee_shm_release(shm);
+}
+EXPORT_SYMBOL_GPL(tee_shm_free);
+
+/**
+ * tee_shm_va2pa() - Get physical address of a virtual address
+ * @shm: Shared memory handle
+ * @va: Virtual address to tranlsate
+ * @pa: Returned physical address
+ * @returns 0 on success and < 0 on failure
+ */
+int tee_shm_va2pa(struct tee_shm *shm, void *va, phys_addr_t *pa)
+{
+ if (!(shm->flags & TEE_SHM_MAPPED))
+ return -EINVAL;
+ /* Check that we're in the range of the shm */
+ if ((char *)va < (char *)shm->kaddr)
+ return -EINVAL;
+ if ((char *)va >= ((char *)shm->kaddr + shm->size))
+ return -EINVAL;
+
+ return tee_shm_get_pa(
+ shm, (unsigned long)va - (unsigned long)shm->kaddr, pa);
+}
+EXPORT_SYMBOL_GPL(tee_shm_va2pa);
+
+/**
+ * tee_shm_pa2va() - Get virtual address of a physical address
+ * @shm: Shared memory handle
+ * @pa: Physical address to tranlsate
+ * @va: Returned virtual address
+ * @returns 0 on success and < 0 on failure
+ */
+int tee_shm_pa2va(struct tee_shm *shm, phys_addr_t pa, void **va)
+{
+ if (!(shm->flags & TEE_SHM_MAPPED))
+ return -EINVAL;
+ /* Check that we're in the range of the shm */
+ if (pa < shm->paddr)
+ return -EINVAL;
+ if (pa >= (shm->paddr + shm->size))
+ return -EINVAL;
+
+ if (va) {
+ void *v = tee_shm_get_va(shm, pa - shm->paddr);
+
+ if (IS_ERR(v))
+ return PTR_ERR(v);
+ *va = v;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tee_shm_pa2va);
+
+/**
+ * tee_shm_get_va() - Get virtual address of a shared memory plus an offset
+ * @shm: Shared memory handle
+ * @offs: Offset from start of this shared memory
+ * @returns virtual address of the shared memory + offs if offs is within
+ * the bounds of this shared memory, else an ERR_PTR
+ */
+void *tee_shm_get_va(struct tee_shm *shm, size_t offs)
+{
+ if (!(shm->flags & TEE_SHM_MAPPED))
+ return ERR_PTR(-EINVAL);
+ if (offs >= shm->size)
+ return ERR_PTR(-EINVAL);
+ return (char *)shm->kaddr + offs;
+}
+EXPORT_SYMBOL_GPL(tee_shm_get_va);
+
+/**
+ * tee_shm_get_pa() - Get physical address of a shared memory plus an offset
+ * @shm: Shared memory handle
+ * @offs: Offset from start of this shared memory
+ * @pa: Physical address to return
+ * @returns 0 if offs is within the bounds of this shared memory, else an
+ * error code.
+ */
+int tee_shm_get_pa(struct tee_shm *shm, size_t offs, phys_addr_t *pa)
+{
+ if (offs >= shm->size)
+ return -EINVAL;
+ if (pa)
+ *pa = shm->paddr + offs;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tee_shm_get_pa);
+
+/**
+ * tee_shm_get_from_id() - Find shared memory object and increase reference
+ * count
+ * @ctx: Context owning the shared memory
+ * @id: Id of shared memory object
+ * @returns a pointer to 'struct tee_shm' on success or an ERR_PTR on failure
+ */
+struct tee_shm *tee_shm_get_from_id(struct tee_context *ctx, int id)
+{
+ struct tee_device *teedev;
+ struct tee_shm *shm;
+
+ if (!ctx)
+ return ERR_PTR(-EINVAL);
+
+ teedev = ctx->teedev;
+ mutex_lock(&teedev->mutex);
+ shm = idr_find(&teedev->idr, id);
+ if (!shm || shm->ctx != ctx)
+ shm = ERR_PTR(-EINVAL);
+ else if (shm->flags & TEE_SHM_DMA_BUF)
+ get_dma_buf(shm->dmabuf);
+ mutex_unlock(&teedev->mutex);
+ return shm;
+}
+EXPORT_SYMBOL_GPL(tee_shm_get_from_id);
+
+/**
+ * tee_shm_get_id() - Get id of a shared memory object
+ * @shm: Shared memory handle
+ * @returns id
+ */
+int tee_shm_get_id(struct tee_shm *shm)
+{
+ return shm->id;
+}
+EXPORT_SYMBOL_GPL(tee_shm_get_id);
+
+/**
+ * tee_shm_put() - Decrease reference count on a shared memory handle
+ * @shm: Shared memory handle
+ */
+void tee_shm_put(struct tee_shm *shm)
+{
+ if (shm->flags & TEE_SHM_DMA_BUF)
+ dma_buf_put(shm->dmabuf);
+}
+EXPORT_SYMBOL_GPL(tee_shm_put);
diff --git a/drivers/tee/tee_shm_pool.c b/drivers/tee/tee_shm_pool.c
new file mode 100644
index 000000000000..fb4f8522a526
--- /dev/null
+++ b/drivers/tee/tee_shm_pool.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/device.h>
+#include <linux/dma-buf.h>
+#include <linux/genalloc.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include "tee_private.h"
+
+static int pool_op_gen_alloc(struct tee_shm_pool_mgr *poolm,
+ struct tee_shm *shm, size_t size)
+{
+ unsigned long va;
+ struct gen_pool *genpool = poolm->private_data;
+ size_t s = roundup(size, 1 << genpool->min_alloc_order);
+
+ va = gen_pool_alloc(genpool, s);
+ if (!va)
+ return -ENOMEM;
+
+ memset((void *)va, 0, s);
+ shm->kaddr = (void *)va;
+ shm->paddr = gen_pool_virt_to_phys(genpool, va);
+ shm->size = s;
+ return 0;
+}
+
+static void pool_op_gen_free(struct tee_shm_pool_mgr *poolm,
+ struct tee_shm *shm)
+{
+ gen_pool_free(poolm->private_data, (unsigned long)shm->kaddr,
+ shm->size);
+ shm->kaddr = NULL;
+}
+
+static const struct tee_shm_pool_mgr_ops pool_ops_generic = {
+ .alloc = pool_op_gen_alloc,
+ .free = pool_op_gen_free,
+};
+
+static void pool_res_mem_destroy(struct tee_shm_pool *pool)
+{
+ gen_pool_destroy(pool->private_mgr.private_data);
+ gen_pool_destroy(pool->dma_buf_mgr.private_data);
+}
+
+static int pool_res_mem_mgr_init(struct tee_shm_pool_mgr *mgr,
+ struct tee_shm_pool_mem_info *info,
+ int min_alloc_order)
+{
+ size_t page_mask = PAGE_SIZE - 1;
+ struct gen_pool *genpool = NULL;
+ int rc;
+
+ /*
+ * Start and end must be page aligned
+ */
+ if ((info->vaddr & page_mask) || (info->paddr & page_mask) ||
+ (info->size & page_mask))
+ return -EINVAL;
+
+ genpool = gen_pool_create(min_alloc_order, -1);
+ if (!genpool)
+ return -ENOMEM;
+
+ gen_pool_set_algo(genpool, gen_pool_best_fit, NULL);
+ rc = gen_pool_add_virt(genpool, info->vaddr, info->paddr, info->size,
+ -1);
+ if (rc) {
+ gen_pool_destroy(genpool);
+ return rc;
+ }
+
+ mgr->private_data = genpool;
+ mgr->ops = &pool_ops_generic;
+ return 0;
+}
+
+/**
+ * tee_shm_pool_alloc_res_mem() - Create a shared memory pool from reserved
+ * memory range
+ * @priv_info: Information for driver private shared memory pool
+ * @dmabuf_info: Information for dma-buf shared memory pool
+ *
+ * Start and end of pools will must be page aligned.
+ *
+ * Allocation with the flag TEE_SHM_DMA_BUF set will use the range supplied
+ * in @dmabuf, others will use the range provided by @priv.
+ *
+ * @returns pointer to a 'struct tee_shm_pool' or an ERR_PTR on failure.
+ */
+struct tee_shm_pool *
+tee_shm_pool_alloc_res_mem(struct tee_shm_pool_mem_info *priv_info,
+ struct tee_shm_pool_mem_info *dmabuf_info)
+{
+ struct tee_shm_pool *pool = NULL;
+ int ret;
+
+ pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+ if (!pool) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /*
+ * Create the pool for driver private shared memory
+ */
+ ret = pool_res_mem_mgr_init(&pool->private_mgr, priv_info,
+ 3 /* 8 byte aligned */);
+ if (ret)
+ goto err;
+
+ /*
+ * Create the pool for dma_buf shared memory
+ */
+ ret = pool_res_mem_mgr_init(&pool->dma_buf_mgr, dmabuf_info,
+ PAGE_SHIFT);
+ if (ret)
+ goto err;
+
+ pool->destroy = pool_res_mem_destroy;
+ return pool;
+err:
+ if (ret == -ENOMEM)
+ pr_err("%s: can't allocate memory for res_mem shared memory pool\n", __func__);
+ if (pool && pool->private_mgr.private_data)
+ gen_pool_destroy(pool->private_mgr.private_data);
+ kfree(pool);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem);
+
+/**
+ * tee_shm_pool_free() - Free a shared memory pool
+ * @pool: The shared memory pool to free
+ *
+ * There must be no remaining shared memory allocated from this pool when
+ * this function is called.
+ */
+void tee_shm_pool_free(struct tee_shm_pool *pool)
+{
+ pool->destroy(pool);
+ kfree(pool);
+}
+EXPORT_SYMBOL_GPL(tee_shm_pool_free);
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 6356295672cb..7fdd4dd80db4 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -195,6 +195,35 @@ config IMX_THERMAL
cpufreq is used as the cooling device to throttle CPUs when the
passive trip is crossed.
+config IMX8M_THERMAL
+ tristate "i.MX8M Thermal Monitoring Unit"
+ depends on THERMAL_OF
+ depends on HAS_IOMEM
+ help
+ Support for Thermal Monitoring Unit (TMU) found on i.MX8M platforms.
+ It supports one critical trip point and one passive trip point. The
+ cpufreq is used as the cooling device to throttle CPUs when the
+ passive trip is crossed.
+
+config IMX8MM_THERMAL
+ tristate "i.MX8MM Thermal Monitor Unit"
+ depends on THERMAL_OF
+ depends on HAS_IOMEM
+ help
+ Support for Thermal Monitor Unit (TMU) found on i.MX8MM platforms.
+ It supports one critical trip point and one passive trip point. The
+ cpufreq is used as the cooling device to throttle CPUs when the
+ passive trip is crossed.
+
+config IMX_SC_THERMAL
+ tristate "thermal sensor driver for NXP i.MX8 SoCs"
+ depends on THERMAL_OF && ARCH_MXC_ARM64
+ help
+ Support for Temperature Monitor (TEMPMON) found on NXP i.MX SOCs
+ with system controller.
+ cpufreq is used as the cooling device to throttle CPUs when the
+ passive trip is crossed.
+
config MAX77620_THERMAL
tristate "Temperature sensor driver for Maxim MAX77620 PMIC"
depends on MFD_MAX77620
@@ -215,6 +244,13 @@ config QORIQ_THERMAL
cpufreq is used as the cooling device to throttle CPUs when the
passive trip is crossed.
+config DEVICE_THERMAL
+ tristate "generic device cooling support"
+ help
+ Support for device cooling.
+ It supports notification of crossing passive trip for devices,
+ devices need to do their own actions to cool down the SOC.
+
config SPEAR_THERMAL
tristate "SPEAr thermal sensor driver"
depends on PLAT_SPEAR || COMPILE_TEST
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index c92eb22a41ff..70455fd46cb0 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -37,8 +37,12 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o
obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o
obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
+obj-$(CONFIG_IMX8M_THERMAL) += qoriq_thermal.o
+obj-$(CONFIG_IMX8MM_THERMAL) += imx8mm_thermal.o
+obj-$(CONFIG_IMX_SC_THERMAL) += imx_sc_thermal.o
obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o
obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o
+obj-$(CONFIG_DEVICE_THERMAL) += device_cooling.o
obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
diff --git a/drivers/thermal/device_cooling.c b/drivers/thermal/device_cooling.c
new file mode 100644
index 000000000000..844b074a2532
--- /dev/null
+++ b/drivers/thermal/device_cooling.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/thermal.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+struct devfreq_cooling_device {
+ int id;
+ struct thermal_cooling_device *cool_dev;
+ unsigned int devfreq_state;
+};
+
+static DEFINE_IDR(devfreq_idr);
+static DEFINE_MUTEX(devfreq_cooling_lock);
+
+#define MAX_STATE 1
+
+static BLOCKING_NOTIFIER_HEAD(devfreq_cooling_chain_head);
+
+int register_devfreq_cooling_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(
+ &devfreq_cooling_chain_head, nb);
+}
+EXPORT_SYMBOL_GPL(register_devfreq_cooling_notifier);
+
+int unregister_devfreq_cooling_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(
+ &devfreq_cooling_chain_head, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_devfreq_cooling_notifier);
+
+static int devfreq_cooling_notifier_call_chain(unsigned long val)
+{
+ return (blocking_notifier_call_chain(
+ &devfreq_cooling_chain_head, val, NULL)
+ == NOTIFY_BAD) ? -EINVAL : 0;
+}
+
+static int devfreq_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ struct devfreq_cooling_device *devfreq_device = cdev->devdata;
+ int ret;
+
+ ret = devfreq_cooling_notifier_call_chain(state);
+ if (ret)
+ return -EINVAL;
+ devfreq_device->devfreq_state = state;
+
+ return 0;
+}
+
+static int devfreq_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ *state = MAX_STATE;
+
+ return 0;
+}
+
+static int devfreq_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct devfreq_cooling_device *devfreq_device = cdev->devdata;
+
+ *state = devfreq_device->devfreq_state;
+
+ return 0;
+}
+
+static struct thermal_cooling_device_ops const devfreq_cooling_ops = {
+ .get_max_state = devfreq_get_max_state,
+ .get_cur_state = devfreq_get_cur_state,
+ .set_cur_state = devfreq_set_cur_state,
+};
+
+static int get_idr(struct idr *idr, int *id)
+{
+ int ret;
+
+ mutex_lock(&devfreq_cooling_lock);
+ ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
+ mutex_unlock(&devfreq_cooling_lock);
+ if (unlikely(ret < 0))
+ return ret;
+ *id = ret;
+
+ return 0;
+}
+
+static void release_idr(struct idr *idr, int id)
+{
+ mutex_lock(&devfreq_cooling_lock);
+ idr_remove(idr, id);
+ mutex_unlock(&devfreq_cooling_lock);
+}
+
+struct thermal_cooling_device *devfreq_cooling_register(void)
+{
+ struct thermal_cooling_device *cool_dev;
+ struct devfreq_cooling_device *devfreq_dev = NULL;
+ char dev_name[THERMAL_NAME_LENGTH];
+ int ret = 0;
+
+ devfreq_dev = kzalloc(sizeof(struct devfreq_cooling_device),
+ GFP_KERNEL);
+ if (!devfreq_dev)
+ return ERR_PTR(-ENOMEM);
+
+ ret = get_idr(&devfreq_idr, &devfreq_dev->id);
+ if (ret) {
+ kfree(devfreq_dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d",
+ devfreq_dev->id);
+
+ cool_dev = thermal_cooling_device_register(dev_name, devfreq_dev,
+ &devfreq_cooling_ops);
+ if (!cool_dev) {
+ release_idr(&devfreq_idr, devfreq_dev->id);
+ kfree(devfreq_dev);
+ return ERR_PTR(-EINVAL);
+ }
+ devfreq_dev->cool_dev = cool_dev;
+ devfreq_dev->devfreq_state = 0;
+
+ return cool_dev;
+}
+EXPORT_SYMBOL_GPL(devfreq_cooling_register);
+
+void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
+{
+ struct devfreq_cooling_device *devfreq_dev = cdev->devdata;
+
+ thermal_cooling_device_unregister(devfreq_dev->cool_dev);
+ release_idr(&devfreq_idr, devfreq_dev->id);
+ kfree(devfreq_dev);
+}
+EXPORT_SYMBOL_GPL(devfreq_cooling_unregister);
diff --git a/drivers/thermal/imx8mm_thermal.c b/drivers/thermal/imx8mm_thermal.c
new file mode 100644
index 000000000000..e6026f13c12f
--- /dev/null
+++ b/drivers/thermal/imx8mm_thermal.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2018 NXP.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device_cooling.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+
+#include "thermal_core.h"
+
+#define TER 0x0 /* TMU enable */
+#define TSR 0x4 /* TMU status */
+#define TIER 0x8 /* TMU interrupt enable */
+#define TIDR 0xc /* TMU interrupt detect */
+#define TMHTITR 0x10 /* TMU high immediate threshold */
+#define TMHTATR 0x14 /* TMU high average threshold */
+#define TMHTCATR 0x18 /* TMU high average critical threshold */
+#define TSCR 0x1c /* TMU sensor val(raw, no calibration) */
+#define TRITSR 0x20 /* TMU immediate temp */
+#define TRATSR 0x24 /* TMU average temp */
+
+#define TER_EN BIT(31)
+#define TRITSR_VALID BIT(31)
+#define TEMP_VAL_MASK 0xff
+
+#define IMX_TEMP_PASSIVE_COOL_DELTA 10000
+
+struct imx8mm_tmu {
+ struct thermal_zone_device *tzd;
+ struct thermal_cooling_device *cdev;
+ struct clk *clk;
+ void __iomem *tmu_base;
+ bool enabled;
+ int temp_passive;
+ int temp_critical;
+};
+
+/* The driver support 1 passive trip point and 1 critical trip point */
+enum imx_thermal_trip {
+ IMX_TRIP_PASSIVE,
+ IMX_TRIP_CRITICAL,
+ IMX_TRIP_NUM,
+};
+
+static int tmu_get_temp(void *data, int *temp)
+{
+ struct imx8mm_tmu *tmu = data;
+ u32 val;
+
+ /* the temp sensor need about 1ms to finish the measurement */
+ msleep(1);
+
+ /* read the calibrated temp value */
+ val = readl_relaxed(tmu->tmu_base + TRITSR);
+
+ if (!(val & TRITSR_VALID))
+ return -EAGAIN;
+
+ *temp = (val & TEMP_VAL_MASK) * 1000;
+
+ return 0;
+}
+
+static int tmu_get_trend(void *p, int trip, enum thermal_trend *trend)
+{
+ int trip_temp;
+ struct imx8mm_tmu *tmu = p;
+
+ if (!tmu->tzd)
+ return 0;
+
+ trip_temp = (trip == IMX_TRIP_PASSIVE) ? tmu->temp_passive : tmu->temp_critical;
+
+ if (tmu->tzd->temperature >= (trip_temp - IMX_TEMP_PASSIVE_COOL_DELTA))
+ *trend = THERMAL_TREND_RAISE_FULL;
+ else
+ *trend = THERMAL_TREND_DROP_FULL;
+
+ return 0;
+}
+
+static int tmu_set_trip_temp(void *p, int trip, int temp)
+{
+ struct imx8mm_tmu *tmu = p;
+
+ if (trip == IMX_TRIP_CRITICAL)
+ tmu->temp_critical = temp;
+
+ if (trip == IMX_TRIP_PASSIVE)
+ tmu->temp_passive = temp;
+
+ return 0;
+}
+
+static struct thermal_zone_of_device_ops tmu_tz_ops = {
+ .get_temp = tmu_get_temp,
+ .get_trend = tmu_get_trend,
+ .set_trip_temp = tmu_set_trip_temp,
+};
+
+static const struct of_device_id imx8mm_tmu_table[] = {
+ { .compatible = "fsl,imx8mm-tmu", },
+ { },
+};
+
+static int imx8mm_tmu_probe(struct platform_device *pdev)
+{
+ int ret;
+ u32 val;
+ struct imx8mm_tmu *tmu;
+ const struct thermal_trip *trips;
+ struct device_node *np = pdev->dev.of_node;
+
+ if (!np) {
+ dev_err(&pdev->dev, "device node NOT found\n");
+ return -ENODEV;
+ }
+
+ tmu = devm_kzalloc(&pdev->dev, sizeof(*tmu), GFP_KERNEL);
+ if (!tmu)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, tmu);
+
+ tmu->tmu_base = of_iomap(np, 0);
+ if (!tmu->tmu_base) {
+ dev_err(&pdev->dev, "Failed to map the memory\n");
+ return -ENODEV;
+ }
+
+ tmu->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(tmu->clk)) {
+ ret = PTR_ERR(tmu->clk);
+ dev_err(&pdev->dev, "Failed to get the tmu clk\n");
+ goto err;
+ }
+
+ /* register the thermal zone sensor */
+ tmu->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, tmu, &tmu_tz_ops);
+
+ if (IS_ERR(tmu->tzd)) {
+ ret = PTR_ERR(tmu->tzd);
+ dev_err(&pdev->dev, "Failed to register thermal zone sensor %d\n", ret);
+ goto err;
+ }
+
+ tmu->cdev = devfreq_cooling_register();
+ if (IS_ERR(tmu->cdev)) {
+ ret = PTR_ERR(tmu->cdev);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "failed to register devfreq cooling device %d\n", ret);
+ goto err;
+ }
+
+ ret = thermal_zone_bind_cooling_device(tmu->tzd,
+ IMX_TRIP_PASSIVE,
+ tmu->cdev,
+ THERMAL_NO_LIMIT,
+ THERMAL_NO_LIMIT,
+ THERMAL_WEIGHT_DEFAULT);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "binding zone %s with cdev %s failed:%d\n",
+ tmu->tzd->type, tmu->cdev->type, ret);
+ devfreq_cooling_unregister(tmu->cdev);
+ goto err;
+ }
+
+ trips = of_thermal_get_trip_points(tmu->tzd);
+
+ /* get the thermal trip temp */
+ tmu->temp_passive = trips[0].temperature;
+ tmu->temp_critical = trips[1].temperature;
+
+ /* enable the tmu clock */
+ ret = clk_prepare_enable(tmu->clk);
+ if (ret) {
+ dev_warn(&pdev->dev, "tmu clock enable failed:%d\n", ret);
+ thermal_zone_unbind_cooling_device(tmu->tzd, IMX_TRIP_PASSIVE, tmu->cdev);
+ devfreq_cooling_unregister(tmu->cdev);
+ goto err;
+ }
+
+ /* enable the monitor */
+ val = readl_relaxed(tmu->tmu_base + TER);
+ val |= TER_EN;
+ writel_relaxed(val, tmu->tmu_base + TER);
+
+ return 0;
+err:
+ iounmap(tmu->tmu_base);
+ return ret;
+}
+
+static int imx8mm_tmu_remove(struct platform_device *pdev)
+{
+ u32 val;
+ struct imx8mm_tmu *tmu = platform_get_drvdata(pdev);
+
+ thermal_zone_unbind_cooling_device(tmu->tzd, IMX_TRIP_PASSIVE, tmu->cdev);
+ devfreq_cooling_unregister(tmu->cdev);
+
+ /* disable TMU */
+ val = readl_relaxed(tmu->tmu_base + TER);
+ val &= ~TER_EN;
+ writel_relaxed(val, tmu->tmu_base + TER);
+
+ /* disable TMU clk */
+ clk_disable_unprepare(tmu->clk);
+
+ iounmap(tmu->tmu_base);
+
+ return 0;
+}
+
+static struct platform_driver imx8mm_tmu = {
+ .driver = {
+ .name = "i.mx8mm_thermal",
+ .of_match_table = imx8mm_tmu_table,
+ },
+ .probe = imx8mm_tmu_probe,
+ .remove = imx8mm_tmu_remove,
+};
+module_platform_driver(imx8mm_tmu);
+
+MODULE_AUTHOR("Jacky Bai <ping.bai@nxp.com>");
+MODULE_DESCRIPTION("i.MX8MM Thermal Monitor Unit driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/imx_sc_thermal.c b/drivers/thermal/imx_sc_thermal.c
new file mode 100644
index 000000000000..8c5049020cd8
--- /dev/null
+++ b/drivers/thermal/imx_sc_thermal.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2017-2018 NXP.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/device_cooling.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/thermal.h>
+#include <soc/imx8/sc/sci.h>
+
+#include "thermal_core.h"
+
+#define IMX_SC_TEMP_PASSIVE_COOL_DELTA 10000
+
+struct imx_sc_sensor {
+ struct thermal_zone_device *tzd;
+ struct thermal_cooling_device *cdev;
+ sc_rsrc_t hw_id;
+ int temp_passive;
+ int temp_critical;
+};
+
+struct imx_sc_tsens_device {
+ u32 sensor_num;
+ struct imx_sc_sensor sensor[0];
+};
+
+/* The driver support 1 passive trip point and 1 critical trip point */
+enum imx_thermal_trip {
+ IMX_TRIP_PASSIVE,
+ IMX_TRIP_CRITICAL,
+ IMX_TRIP_NUM,
+};
+
+static const sc_rsrc_t imx8qm_sensor_hw_id[] = {
+ SC_R_A53, SC_R_A72, SC_R_GPU_0_PID0, SC_R_GPU_1_PID0,
+ SC_R_DRC_0, SC_R_PMIC_0, SC_R_PMIC_1, SC_R_PMIC_2,
+};
+
+static const sc_rsrc_t imx8qxp_sensor_hw_id[] = {
+ SC_R_SYSTEM, SC_R_DRC_0, SC_R_PMIC_0,
+ SC_R_PMIC_1, SC_R_PMIC_2,
+};
+
+const int *sensor_hw_id;
+sc_ipc_t tsens_ipcHandle;
+
+static int imx_sc_tsens_get_temp(void *data, int *temp)
+{
+ struct imx_sc_sensor *sensor = data;
+ sc_err_t sciErr;
+ int16_t celsius;
+ int8_t tenths;
+
+ sciErr = sc_misc_get_temp(tsens_ipcHandle, sensor->hw_id,
+ SC_C_TEMP, &celsius, &tenths);
+ /*
+ * if the SS power domain is down, read temp will fail, so
+ * we can return the temp of CPU domain instead.
+ */
+ if (sciErr != SC_ERR_NONE) {
+ sciErr = sc_misc_get_temp(tsens_ipcHandle,
+ sensor_hw_id[topology_physical_package_id(smp_processor_id())],
+ SC_C_TEMP, &celsius, &tenths);
+ if (sciErr != SC_ERR_NONE) {
+ pr_err("read temp sensor:%d failed\n", sensor->hw_id);
+ return -EINVAL;
+ }
+ }
+ *temp = celsius * 1000 + tenths * 100;
+
+ return 0;
+}
+
+static int imx_sc_tsens_get_trend(void *p, int trip, enum thermal_trend *trend)
+{
+ int trip_temp;
+ struct imx_sc_sensor *sensor = p;
+
+ if (!sensor->tzd)
+ return 0;
+
+ trip_temp = (trip == IMX_TRIP_PASSIVE) ? sensor->temp_passive :
+ sensor->temp_critical;
+
+ if (sensor->tzd->temperature >=
+ (trip_temp - IMX_SC_TEMP_PASSIVE_COOL_DELTA))
+ *trend = THERMAL_TREND_RAISE_FULL;
+ else
+ *trend = THERMAL_TREND_DROP_FULL;
+
+ return 0;
+}
+
+static int imx_sc_set_trip_temp(void *p, int trip,
+ int temp)
+{
+ struct imx_sc_sensor *sensor = p;
+
+ if (trip == IMX_TRIP_CRITICAL)
+ sensor->temp_critical = temp;
+
+ if (trip == IMX_TRIP_PASSIVE)
+ sensor->temp_passive = temp;
+
+ return 0;
+}
+
+static const struct thermal_zone_of_device_ops imx_sc_tsens_ops = {
+ .get_temp = imx_sc_tsens_get_temp,
+ .get_trend = imx_sc_tsens_get_trend,
+ .set_trip_temp = imx_sc_set_trip_temp,
+};
+
+static const struct of_device_id imx_sc_tsens_table[] = {
+ { .compatible = "nxp,imx8qm-sc-tsens", .data = &imx8qm_sensor_hw_id, },
+ { .compatible = "nxp,imx8qxp-sc-tsens", .data = &imx8qxp_sensor_hw_id, },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, imx_sc_tsens_table);
+
+static int imx_sc_tsens_probe(struct platform_device *pdev)
+{
+ struct device_node *tz_np, *child_tz_np = NULL;
+ struct device_node *np = pdev->dev.of_node;
+ struct imx_sc_tsens_device *tsens_dev;
+ struct imx_sc_sensor *sensor;
+ const struct thermal_trip *trip;
+ struct thermal_zone_device *tzd;
+ sc_err_t sciErr;
+ uint32_t mu_id;
+ u32 tsens_num;
+ int ret, sensor_id;
+
+ sciErr = sc_ipc_getMuID(&mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ dev_err(&pdev->dev, "Can not get the mu id: %d\n", sciErr);
+ return -ENODEV;
+ };
+
+ sciErr = sc_ipc_open(&tsens_ipcHandle, mu_id);
+ if (sciErr != SC_ERR_NONE) {
+ dev_err(&pdev->dev, "open mu channel failed: %d\n", sciErr);
+ return -EINVAL;
+ };
+ sensor_hw_id = of_device_get_match_data(&pdev->dev);
+
+ /* get the temp sensor number from device node */
+ of_property_read_u32(np, "tsens-num", &tsens_num);
+ if (!tsens_num) {
+ dev_err(&pdev->dev, "no temp sensor number provided!\n");
+ return -EINVAL;
+ }
+
+ tsens_dev = devm_kzalloc(&pdev->dev, sizeof(*tsens_dev) +
+ tsens_num * sizeof(*sensor), GFP_KERNEL);
+ if (!tsens_dev)
+ return -ENOMEM;
+
+ tsens_dev->sensor_num = tsens_num;
+
+ tz_np = of_find_node_by_name(NULL, "thermal-zones");
+ if (!tz_np)
+ return -ENODEV;
+
+ for (sensor_id = 0; sensor_id < tsens_num; sensor_id++) {
+ child_tz_np = of_get_next_child(tz_np, child_tz_np);
+ if (!of_device_is_available(child_tz_np))
+ continue;
+
+ sensor = &tsens_dev->sensor[sensor_id];
+ sensor->hw_id = sensor_hw_id[sensor_id];
+ tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, sensor_id, sensor,
+ &imx_sc_tsens_ops);
+ if (IS_ERR(tzd)) {
+ dev_err(&pdev->dev, "failed to register temp sensor: %d\n", sensor_id);
+ ret = -EINVAL;
+ goto failed;
+ }
+ sensor->tzd = tzd;
+ trip = of_thermal_get_trip_points(sensor->tzd);
+ sensor->temp_passive = trip[0].temperature;
+ sensor->temp_critical = trip[1].temperature;
+
+ sensor->cdev = devfreq_cooling_register();
+ if (IS_ERR(sensor->cdev)) {
+ dev_err(&pdev->dev,
+ "failed to register devfreq cooling device: %d\n",
+ ret);
+ goto failed;
+ }
+
+ ret = thermal_zone_bind_cooling_device(sensor->tzd,
+ IMX_TRIP_PASSIVE,
+ sensor->cdev,
+ THERMAL_NO_LIMIT,
+ THERMAL_NO_LIMIT,
+ THERMAL_WEIGHT_DEFAULT);
+ if (ret) {
+ dev_err(&sensor->tzd->device,
+ "binding zone %s with cdev %s failed:%d\n",
+ sensor->tzd->type, sensor->cdev->type, ret);
+ devfreq_cooling_unregister(sensor->cdev);
+ goto failed;
+ }
+ }
+
+ return 0;
+failed:
+ return ret;
+}
+
+static int imx_sc_tsens_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver imx_sc_tsens_driver = {
+ .probe = imx_sc_tsens_probe,
+ .remove = imx_sc_tsens_remove,
+ .driver = {
+ .name = "imx-sc-thermal",
+ .of_match_table = imx_sc_tsens_table,
+ },
+};
+
+module_platform_driver(imx_sc_tsens_driver);
+
+MODULE_AUTHOR("Jacky Bai<ping.bai@nxp.com");
+MODULE_DESCRIPTION("Thermal driver for NXP i.MX SoCs with system controller");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index b7cb49afa056..de4fc8791c6c 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -1,16 +1,18 @@
/*
- * Copyright 2013 Freescale Semiconductor, Inc.
+ * Copyright 2013-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
-
+#include <linux/busfreq-imx.h>
#include <linux/clk.h>
#include <linux/cpu_cooling.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/device_cooling.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -37,17 +39,20 @@
#define MISC1_IRQ_TEMPLOW (1 << 28)
#define MISC1_IRQ_TEMPPANIC (1 << 27)
-#define TEMPSENSE0 0x0180
-#define TEMPSENSE0_ALARM_VALUE_SHIFT 20
-#define TEMPSENSE0_ALARM_VALUE_MASK (0xfff << TEMPSENSE0_ALARM_VALUE_SHIFT)
-#define TEMPSENSE0_TEMP_CNT_SHIFT 8
-#define TEMPSENSE0_TEMP_CNT_MASK (0xfff << TEMPSENSE0_TEMP_CNT_SHIFT)
-#define TEMPSENSE0_FINISHED (1 << 2)
-#define TEMPSENSE0_MEASURE_TEMP (1 << 1)
-#define TEMPSENSE0_POWER_DOWN (1 << 0)
-
-#define TEMPSENSE1 0x0190
-#define TEMPSENSE1_MEASURE_FREQ 0xffff
+/* i.MX6 specific */
+#define IMX6_TEMPSENSE0 0X180
+#define IMX6_TEMPSENSE0_ALARM_VALUE_SHIFT 20
+#define IMX6_TEMPSENSE0_ALARM_VALUE_MASK (0xfff << 20)
+#define IMX6_TEMPSENSE0_TEMP_CNT_SHIFT 8
+#define IMX6_TEMPSENSE0_TEMP_CNT_MASK (0xfff << 8)
+#define IMX6_TEMPSENSE0_FINISHED (1 << 2)
+#define IMX6_TEMPSENSE0_MEASURE_TEMP (1 << 1)
+#define IMX6_TEMPSENSE0_POWER_DOWN (1 << 0)
+
+#define IMX6_TEMPSENSE1 0X190
+#define IMX6_TEMPSENSE1_MEASURE_FREQ 0xffff
+#define IMX6_TEMPSENSE1_MEASURE_FREQ_SHIFT 0
+
/* Below TEMPSENSE2 is only for TEMPMON_IMX6SX */
#define TEMPSENSE2 0x0290
#define TEMPSENSE2_LOW_VALUE_SHIFT 0
@@ -58,6 +63,29 @@
#define OCOTP_MEM0 0x0480
#define OCOTP_ANA1 0x04e0
+/* i.MX7D specific */
+#define IMX7_ANADIG_DIGPROG 0x800
+#define IMX7_TEMPSENSE0 0X300
+#define IMX7_TEMPSENSE0_PANIC_ALARM_SHIFT 18
+#define IMX7_TEMPSENSE0_PANIC_ALARM_MASK (0x1ff << 18)
+#define IMX7_TEMPSENSE0_HIGH_ALARM_SHIFT 9
+#define IMX7_TEMPSENSE0_HIGH_ALARM_MASK (0x1ff << 9)
+#define IMX7_TEMPSENSE0_LOW_ALARM_SHIFT 0
+#define IMX7_TEMPSENSE0_LOW_ALARM_MASK 0x1ff
+
+#define IMX7_TEMPSENSE1 0X310
+#define IMX7_TEMPSENSE1_MEASURE_FREQ_SHIFT 16
+#define IMX7_TEMPSENSE1_MEASURE_FREQ_MASK (0xffff << 16)
+#define IMX7_TEMPSENSE1_FINISHED (1 << 11)
+#define IMX7_TEMPSENSE1_MEASURE_TEMP (1 << 10)
+#define IMX7_TEMPSENSE1_POWER_DOWN (1 << 9)
+#define IMX7_TEMPSENSE1_TEMP_VALUE_SHIFT 0
+#define IMX7_TEMPSENSE1_TEMP_VALUE_MASK 0x1ff
+
+#define IMX6_OCOTP_ANA1 0x04e0
+#define IMX7_OCOTP_ANA1 0x04f0
+#define IMX7_OCOTP_TESTER3 0x0440
+
/* The driver supports 1 passive trip point and 1 critical trip point */
enum imx_thermal_trip {
IMX_TRIP_PASSIVE,
@@ -65,31 +93,133 @@ enum imx_thermal_trip {
IMX_TRIP_NUM,
};
+#define IMX_TEMP_PASSIVE_COOL_DELTA 10000
+
#define IMX_POLLING_DELAY 2000 /* millisecond */
#define IMX_PASSIVE_DELAY 1000
#define FACTOR0 10000000
-#define FACTOR1 15976
-#define FACTOR2 4297157
+#define FACTOR1 15423
+#define FACTOR2 4148468
+#define OFFSET 3580661
#define TEMPMON_IMX6Q 1
#define TEMPMON_IMX6SX 2
+#define TEMPMON_IMX7 3
+
+/* the register offsets and bitfields may change across
+ * i.MX SOCs, use below struct as a description of the
+ * register.
+ */
struct thermal_soc_data {
+ u32 sensor_ctrl; /* tempmon sensor basic control */
+ u32 power_down_mask;
+ u32 measure_temp_mask;
+
+ u32 measure_freq_ctrl;
+ u32 measure_freq_mask;
+ u32 measure_freq_shift;
+
+ u32 temp_data;
+ u32 temp_value_mask;
+ u32 temp_value_shift;
+ u32 temp_valid_mask;
+
+ u32 panic_alarm_ctrl;
+ u32 panic_alarm_mask;
+ u32 panic_alarm_shift;
+
+ u32 high_alarm_ctrl;
+ u32 high_alarm_mask;
+ u32 high_alarm_shift;
+
+ u32 low_alarm_ctrl;
+ u32 low_alarm_mask;
+ u32 low_alarm_shift;
+
u32 version;
};
static struct thermal_soc_data thermal_imx6q_data = {
.version = TEMPMON_IMX6Q,
+
+ .sensor_ctrl = IMX6_TEMPSENSE0,
+ .power_down_mask = IMX6_TEMPSENSE0_POWER_DOWN,
+ .measure_temp_mask = IMX6_TEMPSENSE0_MEASURE_TEMP,
+
+ .measure_freq_ctrl = IMX6_TEMPSENSE1,
+ .measure_freq_shift = IMX6_TEMPSENSE1_MEASURE_FREQ_SHIFT,
+ .measure_freq_mask = IMX6_TEMPSENSE1_MEASURE_FREQ,
+
+ .temp_data = IMX6_TEMPSENSE0,
+ .temp_value_mask = IMX6_TEMPSENSE0_TEMP_CNT_MASK,
+ .temp_value_shift = IMX6_TEMPSENSE0_TEMP_CNT_SHIFT,
+ .temp_valid_mask = IMX6_TEMPSENSE0_FINISHED,
+
+ .high_alarm_ctrl = IMX6_TEMPSENSE0,
+ .high_alarm_mask = IMX6_TEMPSENSE0_ALARM_VALUE_MASK,
+ .high_alarm_shift = IMX6_TEMPSENSE0_ALARM_VALUE_SHIFT,
};
static struct thermal_soc_data thermal_imx6sx_data = {
.version = TEMPMON_IMX6SX,
+
+ .sensor_ctrl = IMX6_TEMPSENSE0,
+ .power_down_mask = IMX6_TEMPSENSE0_POWER_DOWN,
+ .measure_temp_mask = IMX6_TEMPSENSE0_MEASURE_TEMP,
+
+ .measure_freq_ctrl = IMX6_TEMPSENSE1,
+ .measure_freq_shift = IMX6_TEMPSENSE1_MEASURE_FREQ_SHIFT,
+ .measure_freq_mask = IMX6_TEMPSENSE1_MEASURE_FREQ,
+
+ .temp_data = IMX6_TEMPSENSE0,
+ .temp_value_mask = IMX6_TEMPSENSE0_TEMP_CNT_MASK,
+ .temp_value_shift = IMX6_TEMPSENSE0_TEMP_CNT_SHIFT,
+ .temp_valid_mask = IMX6_TEMPSENSE0_FINISHED,
+
+ .high_alarm_ctrl = IMX6_TEMPSENSE0,
+ .high_alarm_mask = IMX6_TEMPSENSE0_ALARM_VALUE_MASK,
+ .high_alarm_shift = IMX6_TEMPSENSE0_ALARM_VALUE_SHIFT,
+
+ .panic_alarm_ctrl = TEMPSENSE2,
+ .panic_alarm_mask = TEMPSENSE2_PANIC_VALUE_MASK,
+ .panic_alarm_shift = TEMPSENSE2_PANIC_VALUE_SHIFT,
+};
+
+static struct thermal_soc_data thermal_imx7d_data = {
+ .version = TEMPMON_IMX7,
+
+ .sensor_ctrl = IMX7_TEMPSENSE1,
+ .power_down_mask = IMX7_TEMPSENSE1_POWER_DOWN,
+ .measure_temp_mask = IMX7_TEMPSENSE1_MEASURE_TEMP,
+
+ .measure_freq_ctrl = IMX7_TEMPSENSE1,
+ .measure_freq_shift = IMX7_TEMPSENSE1_MEASURE_FREQ_SHIFT,
+ .measure_freq_mask = IMX7_TEMPSENSE1_MEASURE_FREQ_MASK,
+
+ .temp_data = IMX7_TEMPSENSE1,
+ .temp_value_mask = IMX7_TEMPSENSE1_TEMP_VALUE_MASK,
+ .temp_value_shift = IMX7_TEMPSENSE1_TEMP_VALUE_SHIFT,
+ .temp_valid_mask = IMX7_TEMPSENSE1_FINISHED,
+
+ .panic_alarm_ctrl = IMX7_TEMPSENSE1,
+ .panic_alarm_mask = IMX7_TEMPSENSE0_PANIC_ALARM_MASK,
+ .panic_alarm_shift = IMX7_TEMPSENSE0_PANIC_ALARM_SHIFT,
+
+ .high_alarm_ctrl = IMX7_TEMPSENSE0,
+ .high_alarm_mask = IMX7_TEMPSENSE0_HIGH_ALARM_MASK,
+ .high_alarm_shift = IMX7_TEMPSENSE0_HIGH_ALARM_SHIFT,
+
+ .low_alarm_ctrl = IMX7_TEMPSENSE0,
+ .low_alarm_mask = IMX7_TEMPSENSE0_LOW_ALARM_MASK,
+ .low_alarm_shift = IMX7_TEMPSENSE0_LOW_ALARM_SHIFT,
+
};
struct imx_thermal_data {
struct thermal_zone_device *tz;
- struct thermal_cooling_device *cdev;
+ struct thermal_cooling_device *cdev[2];
enum thermal_device_mode mode;
struct regmap *tempmon;
u32 c1, c2; /* See formula in imx_get_sensor_data() */
@@ -101,55 +231,78 @@ struct imx_thermal_data {
bool irq_enabled;
int irq;
struct clk *thermal_clk;
+ struct mutex mutex;
const struct thermal_soc_data *socdata;
const char *temp_grade;
};
+static struct imx_thermal_data *imx_thermal_data;
+static int skip_finish_check;
+static u32 imx7_lpsr_save[2];
+
static void imx_set_panic_temp(struct imx_thermal_data *data,
int panic_temp)
{
+ const struct thermal_soc_data *soc_data = data->socdata;
struct regmap *map = data->tempmon;
int critical_value;
- critical_value = (data->c2 - panic_temp) / data->c1;
- regmap_write(map, TEMPSENSE2 + REG_CLR, TEMPSENSE2_PANIC_VALUE_MASK);
- regmap_write(map, TEMPSENSE2 + REG_SET, critical_value <<
- TEMPSENSE2_PANIC_VALUE_SHIFT);
+ if (data->socdata->version == TEMPMON_IMX7)
+ critical_value = panic_temp / 1000 + data->c1 - 25;
+ else
+ critical_value = (data->c2 - panic_temp) / data->c1;
+
+ regmap_write(map, soc_data->panic_alarm_ctrl + REG_CLR,
+ soc_data->panic_alarm_mask);
+ regmap_write(map, soc_data->panic_alarm_ctrl + REG_SET,
+ critical_value << soc_data->panic_alarm_shift);
}
static void imx_set_alarm_temp(struct imx_thermal_data *data,
int alarm_temp)
{
+ const struct thermal_soc_data *soc_data = data->socdata;
struct regmap *map = data->tempmon;
int alarm_value;
data->alarm_temp = alarm_temp;
- alarm_value = (data->c2 - alarm_temp) / data->c1;
- regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_ALARM_VALUE_MASK);
- regmap_write(map, TEMPSENSE0 + REG_SET, alarm_value <<
- TEMPSENSE0_ALARM_VALUE_SHIFT);
+
+ if (data->socdata->version == TEMPMON_IMX7)
+ alarm_value = alarm_temp / 1000 + data->c1 - 25;
+ else
+ alarm_value = (data->c2 - alarm_temp) / data->c1;
+
+ regmap_write(map, soc_data->high_alarm_ctrl + REG_CLR,
+ soc_data->high_alarm_mask);
+ regmap_write(map, soc_data->high_alarm_ctrl + REG_SET,
+ alarm_value << soc_data->high_alarm_shift);
}
static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
{
struct imx_thermal_data *data = tz->devdata;
+ const struct thermal_soc_data *soc_data = data->socdata;
struct regmap *map = data->tempmon;
unsigned int n_meas;
bool wait;
u32 val;
+ mutex_lock(&data->mutex);
if (data->mode == THERMAL_DEVICE_ENABLED) {
/* Check if a measurement is currently in progress */
- regmap_read(map, TEMPSENSE0, &val);
- wait = !(val & TEMPSENSE0_FINISHED);
+ regmap_read(map, soc_data->temp_data, &val);
+ wait = !(val & soc_data->temp_valid_mask);
} else {
/*
* Every time we measure the temperature, we will power on the
* temperature sensor, enable measurements, take a reading,
* disable measurements, power off the temperature sensor.
*/
- regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
- regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
+ clk_prepare_enable(data->thermal_clk);
+ regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
+ soc_data->power_down_mask);
+ regmap_write(map, soc_data->sensor_ctrl + REG_SET,
+ soc_data->measure_temp_mask);
wait = true;
}
@@ -158,25 +311,41 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
* According to the temp sensor designers, it may require up to ~17us
* to complete a measurement.
*/
- if (wait)
- usleep_range(20, 50);
-
- regmap_read(map, TEMPSENSE0, &val);
+ if (wait) {
+ /*
+ * On i.MX7 TO1.0, the finish bit can only keep 1us after
+ * the measured data available. It is hard for software to
+ * polling this bit. So wait for 20ms to make sure the
+ * measured data is valid.
+ */
+ if (data->socdata->version == TEMPMON_IMX7 && skip_finish_check)
+ msleep(20);
+ else
+ usleep_range(20, 50);
+ regmap_read(map, soc_data->temp_data, &val);
+ }
if (data->mode != THERMAL_DEVICE_ENABLED) {
- regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
- regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
+ regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
+ soc_data->measure_temp_mask);
+ regmap_write(map, soc_data->sensor_ctrl + REG_SET,
+ soc_data->power_down_mask);
+ clk_disable_unprepare(data->thermal_clk);
}
- if ((val & TEMPSENSE0_FINISHED) == 0) {
+ if (!skip_finish_check && ((val & soc_data->temp_valid_mask) == 0)) {
dev_dbg(&tz->device, "temp measurement never finished\n");
+ mutex_unlock(&data->mutex);
return -EAGAIN;
}
- n_meas = (val & TEMPSENSE0_TEMP_CNT_MASK) >> TEMPSENSE0_TEMP_CNT_SHIFT;
-
+ n_meas = (val & soc_data->temp_value_mask) >> soc_data->temp_value_shift;
/* See imx_get_sensor_data() for formula derivation */
*temp = data->c2 - n_meas * data->c1;
+ if (data->socdata->version == TEMPMON_IMX7)
+ *temp = (n_meas - data->c1 + 25) * 1000;
+ else
+ *temp = data->c2 - n_meas * data->c1;
/* Update alarm value to next higher trip point for TEMPMON_IMX6Q */
if (data->socdata->version == TEMPMON_IMX6Q) {
@@ -201,6 +370,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
data->irq_enabled = true;
enable_irq(data->irq);
}
+ mutex_unlock(&data->mutex);
return 0;
}
@@ -219,22 +389,26 @@ static int imx_set_mode(struct thermal_zone_device *tz,
enum thermal_device_mode mode)
{
struct imx_thermal_data *data = tz->devdata;
+ const struct thermal_soc_data *soc_data = data->socdata;
struct regmap *map = data->tempmon;
if (mode == THERMAL_DEVICE_ENABLED) {
tz->polling_delay = IMX_POLLING_DELAY;
tz->passive_delay = IMX_PASSIVE_DELAY;
- regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
- regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
-
+ regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
+ soc_data->power_down_mask);
+ regmap_write(map, soc_data->sensor_ctrl + REG_SET,
+ soc_data->measure_temp_mask);
if (!data->irq_enabled) {
data->irq_enabled = true;
enable_irq(data->irq);
}
} else {
- regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
- regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
+ regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
+ soc_data->measure_temp_mask);
+ regmap_write(map, soc_data->sensor_ctrl + REG_SET,
+ soc_data->power_down_mask);
tz->polling_delay = 0;
tz->passive_delay = 0;
@@ -282,17 +456,18 @@ static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip,
{
struct imx_thermal_data *data = tz->devdata;
- /* do not allow changing critical threshold */
- if (trip == IMX_TRIP_CRITICAL)
- return -EPERM;
-
- /* do not allow passive to be set higher than critical */
- if (temp < 0 || temp > data->temp_critical)
- return -EINVAL;
-
- data->temp_passive = temp;
+ if (trip == IMX_TRIP_CRITICAL) {
+ data->temp_critical = temp;
+ if (data->socdata->version == TEMPMON_IMX6SX)
+ imx_set_panic_temp(data, temp);
+ }
- imx_set_alarm_temp(data, temp);
+ if (trip == IMX_TRIP_PASSIVE) {
+ if (temp > (data->temp_max - (1000 * 10)))
+ return -EINVAL;
+ data->temp_passive = temp;
+ imx_set_alarm_temp(data, temp);
+ }
return 0;
}
@@ -332,6 +507,23 @@ static int imx_unbind(struct thermal_zone_device *tz,
return 0;
}
+static int imx_get_trend(struct thermal_zone_device *tz,
+ int trip, enum thermal_trend *trend)
+{
+ int ret;
+ int trip_temp;
+
+ ret = imx_get_trip_temp(tz, trip, &trip_temp);
+ if (ret < 0)
+ return ret;
+
+ if (tz->temperature >= (trip_temp - IMX_TEMP_PASSIVE_COOL_DELTA))
+ *trend = THERMAL_TREND_RAISE_FULL;
+ else
+ *trend = THERMAL_TREND_DROP_FULL;
+
+ return 0;
+}
static struct thermal_zone_device_ops imx_tz_ops = {
.bind = imx_bind,
.unbind = imx_unbind,
@@ -342,69 +534,102 @@ static struct thermal_zone_device_ops imx_tz_ops = {
.get_trip_temp = imx_get_trip_temp,
.get_crit_temp = imx_get_crit_temp,
.set_trip_temp = imx_set_trip_temp,
+ .get_trend = imx_get_trend,
};
-static int imx_get_sensor_data(struct platform_device *pdev)
+static inline void imx6_calibrate_data(struct imx_thermal_data *data, u32 val)
{
- struct imx_thermal_data *data = platform_get_drvdata(pdev);
- struct regmap *map;
- int t1, n1;
- int ret;
- u32 val;
+ int t1, t2, n1, n2;
u64 temp64;
-
- map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
- "fsl,tempmon-data");
- if (IS_ERR(map)) {
- ret = PTR_ERR(map);
- dev_err(&pdev->dev, "failed to get sensor regmap: %d\n", ret);
- return ret;
- }
-
- ret = regmap_read(map, OCOTP_ANA1, &val);
- if (ret) {
- dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
- return ret;
- }
-
- if (val == 0 || val == ~0) {
- dev_err(&pdev->dev, "invalid sensor calibration data\n");
- return -EINVAL;
- }
-
/*
* Sensor data layout:
* [31:20] - sensor value @ 25C
+ * [19:8] - sensor value of hot
+ * [7:0] - hot temperature value
* Use universal formula now and only need sensor value @ 25C
* slope = 0.4297157 - (0.0015976 * 25C fuse)
*/
n1 = val >> 20;
+ n2 = (val & 0xfff00) >> 8;
+ t2 = val & 0xff;
t1 = 25; /* t1 always 25C */
/*
* Derived from linear interpolation:
* slope = 0.4297157 - (0.0015976 * 25C fuse)
* slope = (FACTOR2 - FACTOR1 * n1) / FACTOR0
+ * offset = OFFSET / 1000000
* (Nmeas - n1) / (Tmeas - t1) = slope
* We want to reduce this down to the minimum computation necessary
* for each temperature read. Also, we want Tmeas in millicelsius
* and we don't want to lose precision from integer division. So...
- * Tmeas = (Nmeas - n1) / slope + t1
- * milli_Tmeas = 1000 * (Nmeas - n1) / slope + 1000 * t1
- * milli_Tmeas = -1000 * (n1 - Nmeas) / slope + 1000 * t1
+ * Tmeas = (Nmeas - n1) / slope + t1 + offset
+ * milli_Tmeas = 1000 * (Nmeas - n1) / slope + 1000 * t1 + OFFSET / 1000
+ * milli_Tmeas = -1000 * (n1 - Nmeas) / slope + 1000 * t1 + OFFSET /1000
* Let constant c1 = (-1000 / slope)
- * milli_Tmeas = (n1 - Nmeas) * c1 + 1000 * t1
- * Let constant c2 = n1 *c1 + 1000 * t1
+ * milli_Tmeas = (n1 - Nmeas) * c1 + 1000 * t1 + OFFSET / 1000
+ * Let constant c2 = n1 *c1 + 1000 * t1 + OFFSET / 1000
* milli_Tmeas = c2 - Nmeas * c1
*/
temp64 = FACTOR0;
temp64 *= 1000;
do_div(temp64, FACTOR1 * n1 - FACTOR2);
data->c1 = temp64;
- data->c2 = n1 * data->c1 + 1000 * t1;
+ temp64 = OFFSET;
+ do_div(temp64, 1000);
+ data->c2 = n1 * data->c1 + 1000 * t1 + temp64;
+}
+
+/*
+ * On i.MX7, we only use the calibration data at 25C to get the temp,
+ * Tmeas = ( Nmeas - n1) + 25; n1 is the fuse value for 25C.
+ */
+static inline void imx7_calibrate_data(struct imx_thermal_data *data, u32 val)
+{
+ data->c1 = (val >> 9) & 0x1ff;
+}
+
+static int imx_get_sensor_data(struct platform_device *pdev)
+{
+ struct imx_thermal_data *data = platform_get_drvdata(pdev);
+ struct regmap *map;
+ int ret;
+ u32 val;
+
+ map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "fsl,tempmon-data");
+ if (IS_ERR(map)) {
+ ret = PTR_ERR(map);
+ dev_err(&pdev->dev, "failed to get sensor regmap: %d\n", ret);
+ return ret;
+ }
+
+ if (data->socdata->version == TEMPMON_IMX7)
+ ret = regmap_read(map, IMX7_OCOTP_ANA1, &val);
+ else
+ ret = regmap_read(map, IMX6_OCOTP_ANA1, &val);
+
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
+ return ret;
+ }
+
+ if (val == 0 || val == ~0) {
+ dev_err(&pdev->dev, "invalid sensor calibration data\n");
+ return -EINVAL;
+ }
+
+ if (data->socdata->version == TEMPMON_IMX7)
+ imx7_calibrate_data(data, val);
+ else
+ imx6_calibrate_data(data, val);
/* use OTP for thermal grade */
- ret = regmap_read(map, OCOTP_MEM0, &val);
+ if (data->socdata->version == TEMPMON_IMX7)
+ ret = regmap_read(map, IMX7_OCOTP_TESTER3, &val);
+ else
+ ret = regmap_read(map, OCOTP_MEM0, &val);
+
if (ret) {
dev_err(&pdev->dev, "failed to read temp grade: %d\n", ret);
return ret;
@@ -465,20 +690,68 @@ static irqreturn_t imx_thermal_alarm_irq_thread(int irq, void *dev)
static const struct of_device_id of_imx_thermal_match[] = {
{ .compatible = "fsl,imx6q-tempmon", .data = &thermal_imx6q_data, },
{ .compatible = "fsl,imx6sx-tempmon", .data = &thermal_imx6sx_data, },
+ { .compatible = "fsl,imx7d-tempmon", .data = &thermal_imx7d_data, },
{ /* end */ }
};
MODULE_DEVICE_TABLE(of, of_imx_thermal_match);
+static int thermal_notifier_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ const struct thermal_soc_data *soc_data = imx_thermal_data->socdata;
+ struct regmap *map = imx_thermal_data->tempmon;
+
+ mutex_lock(&imx_thermal_data->mutex);
+
+ switch (event) {
+ /*
+ * In low_bus_freq_mode, the thermal sensor auto measurement
+ * can be disabled to low the power consumption.
+ */
+ case LOW_BUSFREQ_ENTER:
+ regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
+ soc_data->measure_temp_mask);
+ regmap_write(map, soc_data->sensor_ctrl + REG_SET,
+ soc_data->power_down_mask);
+ imx_thermal_data->mode = THERMAL_DEVICE_DISABLED;
+ disable_irq(imx_thermal_data->irq);
+ clk_disable_unprepare(imx_thermal_data->thermal_clk);
+ break;
+
+ /* Enabled thermal auto measurement when exiting low_bus_freq_mode */
+ case LOW_BUSFREQ_EXIT:
+ clk_prepare_enable(imx_thermal_data->thermal_clk);
+ regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
+ soc_data->power_down_mask);
+ regmap_write(map, soc_data->sensor_ctrl + REG_SET,
+ soc_data->measure_temp_mask);
+ imx_thermal_data->mode = THERMAL_DEVICE_ENABLED;
+ enable_irq(imx_thermal_data->irq);
+ break;
+
+ default:
+ break;
+ }
+ mutex_unlock(&imx_thermal_data->mutex);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block thermal_notifier = {
+ .notifier_call = thermal_notifier_event,
+};
+
static int imx_thermal_probe(struct platform_device *pdev)
{
struct imx_thermal_data *data;
struct regmap *map;
int measure_freq;
- int ret;
+ int ret, revision;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
+ imx_thermal_data = data;
map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "fsl,tempmon");
if (IS_ERR(map)) {
@@ -514,16 +787,29 @@ static int imx_thermal_probe(struct platform_device *pdev)
return ret;
}
+ /*
+ * for i.MX7D TO1.0, finish bit is not available, check the
+ * SOC revision to skip checking the finish bit status.
+ */
+ regmap_read(map, IMX7_ANADIG_DIGPROG, &revision);
+ if ((revision & 0xff) == 0x10)
+ skip_finish_check = 1;
+
/* Make sure sensor is in known good state for measurements */
- regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
- regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
- regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ);
- regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF);
- regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
-
- data->cdev = cpufreq_cooling_register(cpu_present_mask);
- if (IS_ERR(data->cdev)) {
- ret = PTR_ERR(data->cdev);
+ regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
+ data->socdata->power_down_mask);
+ regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
+ data->socdata->measure_temp_mask);
+ regmap_write(map, data->socdata->measure_freq_ctrl + REG_CLR,
+ data->socdata->measure_freq_mask);
+ if (data->socdata->version != TEMPMON_IMX7)
+ regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF);
+ regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
+ data->socdata->power_down_mask);
+
+ data->cdev[0] = cpufreq_cooling_register(cpu_present_mask);
+ if (IS_ERR(data->cdev[0])) {
+ ret = PTR_ERR(data->cdev[0]);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"failed to register cpufreq cooling device: %d\n",
@@ -531,13 +817,25 @@ static int imx_thermal_probe(struct platform_device *pdev)
return ret;
}
+ data->cdev[1] = devfreq_cooling_register();
+ if (IS_ERR(data->cdev[1])) {
+ ret = PTR_ERR(data->cdev[1]);
+ if (ret != -EPROBE_DEFER) {
+ dev_err(&pdev->dev,
+ "failed to register cpufreq cooling device: %d\n",
+ ret);
+ cpufreq_cooling_unregister(data->cdev[0]);
+ }
+ return ret;
+ }
+
data->thermal_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(data->thermal_clk)) {
ret = PTR_ERR(data->thermal_clk);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"failed to get thermal clk: %d\n", ret);
- cpufreq_cooling_unregister(data->cdev);
+ cpufreq_cooling_unregister(data->cdev[0]);
return ret;
}
@@ -551,13 +849,15 @@ static int imx_thermal_probe(struct platform_device *pdev)
ret = clk_prepare_enable(data->thermal_clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret);
- cpufreq_cooling_unregister(data->cdev);
+ cpufreq_cooling_unregister(data->cdev[0]);
+ devfreq_cooling_unregister(data->cdev[1]);
return ret;
}
+ mutex_init(&data->mutex);
data->tz = thermal_zone_device_register("imx_thermal_zone",
IMX_TRIP_NUM,
- BIT(IMX_TRIP_PASSIVE), data,
+ (1 << IMX_TRIP_NUM) - 1, data,
&imx_tz_ops, NULL,
IMX_PASSIVE_DELAY,
IMX_POLLING_DELAY);
@@ -566,7 +866,8 @@ static int imx_thermal_probe(struct platform_device *pdev)
dev_err(&pdev->dev,
"failed to register thermal zone device %d\n", ret);
clk_disable_unprepare(data->thermal_clk);
- cpufreq_cooling_unregister(data->cdev);
+ cpufreq_cooling_unregister(data->cdev[0]);
+ devfreq_cooling_unregister(data->cdev[1]);
return ret;
}
@@ -576,16 +877,20 @@ static int imx_thermal_probe(struct platform_device *pdev)
data->temp_passive / 1000);
/* Enable measurements at ~ 10 Hz */
- regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ);
+ regmap_write(map, data->socdata->measure_freq_ctrl + REG_CLR,
+ data->socdata->measure_freq_mask);
measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */
- regmap_write(map, TEMPSENSE1 + REG_SET, measure_freq);
+ regmap_write(map, data->socdata->measure_freq_ctrl + REG_SET,
+ measure_freq << data->socdata->measure_freq_shift);
imx_set_alarm_temp(data, data->temp_passive);
if (data->socdata->version == TEMPMON_IMX6SX)
imx_set_panic_temp(data, data->temp_critical);
- regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
- regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
+ regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
+ data->socdata->power_down_mask);
+ regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
+ data->socdata->measure_temp_mask);
data->irq_enabled = true;
data->mode = THERMAL_DEVICE_ENABLED;
@@ -597,10 +902,15 @@ static int imx_thermal_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
clk_disable_unprepare(data->thermal_clk);
thermal_zone_device_unregister(data->tz);
- cpufreq_cooling_unregister(data->cdev);
+ cpufreq_cooling_unregister(data->cdev[0]);
+ devfreq_cooling_unregister(data->cdev[1]);
return ret;
}
+ /* register the busfreq notifier called in low bus freq */
+ if (data->socdata->version != TEMPMON_IMX7)
+ register_busfreq_notifier(&thermal_notifier);
+
return 0;
}
@@ -610,12 +920,18 @@ static int imx_thermal_remove(struct platform_device *pdev)
struct regmap *map = data->tempmon;
/* Disable measurements */
- regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
+ regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
+ data->socdata->power_down_mask);
if (!IS_ERR(data->thermal_clk))
clk_disable_unprepare(data->thermal_clk);
+ /* unregister the busfreq notifier called in low bus freq */
+ if (data->socdata->version != TEMPMON_IMX7)
+ unregister_busfreq_notifier(&thermal_notifier);
+
thermal_zone_device_unregister(data->tz);
- cpufreq_cooling_unregister(data->cdev);
+ cpufreq_cooling_unregister(data->cdev[0]);
+ devfreq_cooling_unregister(data->cdev[1]);
return 0;
}
@@ -632,8 +948,20 @@ static int imx_thermal_suspend(struct device *dev)
* temperature will be read as the thermal sensor is powered
* down.
*/
- regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
- regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
+ regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
+ data->socdata->measure_temp_mask);
+ regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
+ data->socdata->power_down_mask);
+
+ /*
+ * Save the temp sensor registers of i.MX7D as the tempmon
+ * will lost power in LPSR mode
+ */
+ if (data->socdata->version == TEMPMON_IMX7) {
+ regmap_read(map, data->socdata->sensor_ctrl, &imx7_lpsr_save[0]);
+ regmap_read(map, data->socdata->high_alarm_ctrl, &imx7_lpsr_save[1]);
+ }
+
data->mode = THERMAL_DEVICE_DISABLED;
clk_disable_unprepare(data->thermal_clk);
@@ -646,9 +974,21 @@ static int imx_thermal_resume(struct device *dev)
struct regmap *map = data->tempmon;
clk_prepare_enable(data->thermal_clk);
+
+ /*
+ * restore the temp sensor registers of i.MX7D as the tempmon
+ * will lost power in LPSR mode
+ */
+ if (data->socdata->version == TEMPMON_IMX7) {
+ regmap_write(map, data->socdata->sensor_ctrl, imx7_lpsr_save[0]);
+ regmap_write(map, data->socdata->high_alarm_ctrl, imx7_lpsr_save[1]);
+ }
+
/* Enabled thermal sensor after resume */
- regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
- regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
+ regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
+ data->socdata->power_down_mask);
+ regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
+ data->socdata->measure_temp_mask);
data->mode = THERMAL_DEVICE_ENABLED;
return 0;
diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c
index 644ba526d9ea..42abb043a1ec 100644
--- a/drivers/thermal/qoriq_thermal.c
+++ b/drivers/thermal/qoriq_thermal.c
@@ -1,5 +1,6 @@
/*
* Copyright 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -14,6 +15,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/device_cooling.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
@@ -24,6 +26,8 @@
#define SITES_MAX 16
+#define TMU_TEMP_PASSIVE_COOL_DELTA 10000
+
/*
* QorIQ TMU Registers
*/
@@ -74,9 +78,18 @@ struct qoriq_tmu_regs {
*/
struct qoriq_tmu_data {
struct thermal_zone_device *tz;
+ struct thermal_cooling_device *cdev;
struct qoriq_tmu_regs __iomem *regs;
int sensor_id;
bool little_endian;
+ int temp_passive;
+ int temp_critical;
+};
+
+enum tmu_trip {
+ TMU_TRIP_PASSIVE,
+ TMU_TRIP_CRITICAL,
+ TMU_TRIP_NUM,
};
static void tmu_write(struct qoriq_tmu_data *p, u32 val, void __iomem *addr)
@@ -188,8 +201,45 @@ static void qoriq_tmu_init_device(struct qoriq_tmu_data *data)
tmu_write(data, TMR_DISABLE, &data->regs->tmr);
}
+static int tmu_get_trend(void *p,
+ int trip, enum thermal_trend *trend)
+{
+ int trip_temp;
+ struct qoriq_tmu_data *data = p;
+
+ if (!data->tz)
+ return 0;
+
+ trip_temp = (trip == TMU_TRIP_PASSIVE) ? data->temp_passive :
+ data->temp_critical;
+
+ if (data->tz->temperature >=
+ (trip_temp - TMU_TEMP_PASSIVE_COOL_DELTA))
+ *trend = THERMAL_TREND_RAISE_FULL;
+ else
+ *trend = THERMAL_TREND_DROP_FULL;
+
+ return 0;
+}
+
+static int tmu_set_trip_temp(void *p, int trip,
+ int temp)
+{
+ struct qoriq_tmu_data *data = p;
+
+ if (trip == TMU_TRIP_CRITICAL)
+ data->temp_critical = temp;
+
+ if (trip == TMU_TRIP_PASSIVE)
+ data->temp_passive = temp;
+
+ return 0;
+}
+
static struct thermal_zone_of_device_ops tmu_tz_ops = {
.get_temp = tmu_get_temp,
+ .get_trend = tmu_get_trend,
+ .set_trip_temp = tmu_set_trip_temp,
};
static int qoriq_tmu_probe(struct platform_device *pdev)
@@ -243,7 +293,33 @@ static int qoriq_tmu_probe(struct platform_device *pdev)
goto err_tmu;
}
+ data->cdev = devfreq_cooling_register();
+ if (IS_ERR(data->cdev)) {
+ ret = PTR_ERR(data->cdev);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "failed to register devfreq cooling device: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = thermal_zone_bind_cooling_device(data->tz,
+ TMU_TRIP_PASSIVE,
+ data->cdev,
+ THERMAL_NO_LIMIT,
+ THERMAL_NO_LIMIT,
+ THERMAL_WEIGHT_DEFAULT);
+ if (ret) {
+ dev_err(&data->tz->device,
+ "binding zone %s with cdev %s failed:%d\n",
+ data->tz->type, data->cdev->type, ret);
+ devfreq_cooling_unregister(data->cdev);
+ return ret;
+ }
+
trip = of_thermal_get_trip_points(data->tz);
+ data->temp_passive = trip[0].temperature;
+ data->temp_critical = trip[1].temperature;
/* Enable monitoring */
site |= 0x1 << (15 - data->sensor_id);
@@ -264,6 +340,7 @@ static int qoriq_tmu_remove(struct platform_device *pdev)
{
struct qoriq_tmu_data *data = platform_get_drvdata(pdev);
+ devfreq_cooling_unregister(data->cdev);
thermal_zone_of_sensor_unregister(&pdev->dev, data->tz);
/* Disable monitoring */
@@ -308,6 +385,7 @@ static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops,
static const struct of_device_id qoriq_tmu_match[] = {
{ .compatible = "fsl,qoriq-tmu", },
+ { .compatible = "fsl,imx8mq-tmu",},
{},
};
MODULE_DEVICE_TABLE(of, qoriq_tmu_match);
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 25c1d7bc0100..0980f8146d02 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -574,7 +574,7 @@ config BFIN_UART3_CTSRTS
config SERIAL_IMX
tristate "IMX serial port support"
depends on HAS_DMA
- depends on ARCH_MXC || COMPILE_TEST
+ depends on ARCH_MXC || ARCH_MXC_ARM64 || COMPILE_TEST
select SERIAL_CORE
select RATIONAL
select SERIAL_MCTRL_GPIO if GPIOLIB
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 937f5e10f165..7bd511c96192 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -2,6 +2,7 @@
* Freescale lpuart serial port driver
*
* Copyright 2012-2014 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,6 +16,7 @@
#include <linux/clk.h>
#include <linux/console.h>
+#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/dmapool.h>
@@ -24,6 +26,8 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_dma.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
#include <linux/tty_flip.h>
@@ -118,20 +122,21 @@
#define UARTSFIFO_RXUF 0x01
/* 32-bit register defination */
-#define UARTBAUD 0x00
-#define UARTSTAT 0x04
-#define UARTCTRL 0x08
-#define UARTDATA 0x0C
-#define UARTMATCH 0x10
-#define UARTMODIR 0x14
-#define UARTFIFO 0x18
-#define UARTWATER 0x1c
+#define UARTBAUD 0x10
+#define UARTSTAT 0x14
+#define UARTCTRL 0x18
+#define UARTDATA 0x1C
+#define UARTMATCH 0x20
+#define UARTMODIR 0x24
+#define UARTFIFO 0x28
+#define UARTWATER 0x2c
#define UARTBAUD_MAEN1 0x80000000
#define UARTBAUD_MAEN2 0x40000000
#define UARTBAUD_M10 0x20000000
#define UARTBAUD_TDMAE 0x00800000
#define UARTBAUD_RDMAE 0x00200000
+#define UARTBAUD_RIDMAE 0x00100000
#define UARTBAUD_MATCFG 0x00400000
#define UARTBAUD_BOTHEDGE 0x00020000
#define UARTBAUD_RESYNCDIS 0x00010000
@@ -140,6 +145,8 @@
#define UARTBAUD_SBNS 0x00002000
#define UARTBAUD_SBR 0x00000000
#define UARTBAUD_SBR_MASK 0x1fff
+#define UARTBAUD_OSR_MASK 0x1f
+#define UARTBAUD_OSR_SHIFT 24
#define UARTSTAT_LBKDIF 0x80000000
#define UARTSTAT_RXEDGIF 0x40000000
@@ -178,7 +185,7 @@
#define UARTCTRL_SBK 0x00010000
#define UARTCTRL_MA1IE 0x00008000
#define UARTCTRL_MA2IE 0x00004000
-#define UARTCTRL_IDLECFG 0x00000100
+#define UARTCTRL_IDLECFG_OFF 0x8
#define UARTCTRL_LOOPS 0x00000080
#define UARTCTRL_DOZEEN 0x00000040
#define UARTCTRL_RSRC 0x00000020
@@ -193,9 +200,12 @@
#define UARTDATA_FRETSC 0x00002000
#define UARTDATA_RXEMPT 0x00001000
#define UARTDATA_IDLINE 0x00000800
+#define UARTDATA_INVALID 0x0000F000
#define UARTDATA_MASK 0x3ff
#define UARTMODIR_IREN 0x00020000
+#define UARTMODIR_RTSWATER_S 0x8
+#define UARTMODIR_RTSWATER_M 0x0000ff00
#define UARTMODIR_TXCTSSRC 0x00000020
#define UARTMODIR_TXCTSC 0x00000010
#define UARTMODIR_RXRTSE 0x00000008
@@ -209,6 +219,8 @@
#define UARTFIFO_RXUF 0x00010000
#define UARTFIFO_TXFLUSH 0x00008000
#define UARTFIFO_RXFLUSH 0x00004000
+#define UARTFIFO_RXIDEN_MASK 0x7
+#define UARTFIFO_RXIDEN_OFF 10
#define UARTFIFO_TXOFE 0x00000200
#define UARTFIFO_RXUFE 0x00000100
#define UARTFIFO_TXFE 0x00000080
@@ -224,8 +236,10 @@
#define UARTWATER_TXWATER_OFF 0
#define UARTWATER_RXWATER_OFF 16
-/* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */
-#define DMA_RX_TIMEOUT (10)
+#define UARTFIFO_RXIDEN_RDRF 0x3
+#define UARTCTRL_IDLECFG 0x7
+#define FSL_UART_RX_DMA_BUFFER_SIZE 128
+#define UART_AUTOSUSPEND_TIMEOUT 3000
#define DRIVER_NAME "fsl-lpuart"
#define DEV_NAME "ttyLP"
@@ -233,27 +247,35 @@
struct lpuart_port {
struct uart_port port;
- struct clk *clk;
+ struct clk *ipg_clk;
+ struct clk *per_clk;
unsigned int txfifo_size;
unsigned int rxfifo_size;
+ unsigned int txfifo_watermark;
+ unsigned int rxfifo_watermark;
+ unsigned int rts_watermark;
bool lpuart32;
+ bool dma_eeop;
bool lpuart_dma_tx_use;
bool lpuart_dma_rx_use;
+ bool dma_rx_chan_active;
struct dma_chan *dma_tx_chan;
struct dma_chan *dma_rx_chan;
struct dma_async_tx_descriptor *dma_tx_desc;
struct dma_async_tx_descriptor *dma_rx_desc;
+ dma_addr_t dma_rx_buf_bus;
dma_cookie_t dma_tx_cookie;
dma_cookie_t dma_rx_cookie;
+ unsigned char *dma_rx_buf_virt;
unsigned int dma_tx_bytes;
unsigned int dma_rx_bytes;
+ size_t rxdma_len;
bool dma_tx_in_progress;
+ bool dma_rx_in_progress;
unsigned int dma_rx_timeout;
struct timer_list lpuart_timer;
struct scatterlist rx_sgl, tx_sgl[2];
- struct circ_buf rx_ring;
- int rx_dma_rng_buf_len;
unsigned int dma_tx_nents;
wait_queue_head_t dma_wait;
};
@@ -265,21 +287,29 @@ static const struct of_device_id lpuart_dt_ids[] = {
{
.compatible = "fsl,ls1021a-lpuart",
},
+ {
+ .compatible = "fsl,imx7ulp-lpuart",
+ },
+ {
+ .compatible = "fsl,imx8qm-lpuart",
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
/* Forward declare this for the dma callbacks*/
+static int lpuart_dma_rx(struct lpuart_port *sport);
static void lpuart_dma_tx_complete(void *arg);
+static inline void lpuart_prepare_rx(struct lpuart_port *sport);
static u32 lpuart32_read(void __iomem *addr)
{
- return ioread32be(addr);
+ return readl(addr);
}
static void lpuart32_write(u32 val, void __iomem *addr)
{
- iowrite32be(val, addr);
+ writel(val, addr);
}
static void lpuart_stop_tx(struct uart_port *port)
@@ -316,19 +346,46 @@ static void lpuart32_stop_rx(struct uart_port *port)
lpuart32_write(temp & ~UARTCTRL_RE, port->membase + UARTCTRL);
}
+static void lpuart_recal_min_trans_size(struct lpuart_port *sport)
+{
+ struct circ_buf *xmit = &sport->port.state->xmit;
+ u32 txcount, rxcount;
+
+ sport->dma_tx_bytes = uart_circ_chars_pending(xmit);
+
+ /* lpuart32 and loopback mode re-calculate the trans size */
+ if (!sport->lpuart32 || !(sport->port.mctrl & TIOCM_LOOP))
+ return;
+
+ txcount = lpuart32_read(sport->port.membase + UARTWATER);
+ txcount = txcount >> UARTWATER_TXCNT_OFF;
+ txcount &= UARTWATER_COUNT_MASK;
+ rxcount = lpuart32_read(sport->port.membase + UARTWATER);
+ rxcount = rxcount >> UARTWATER_RXCNT_OFF;
+ txcount = min_t(unsigned int, sport->txfifo_size - txcount,
+ sport->rxfifo_size - rxcount);
+ sport->dma_tx_bytes = min_t(unsigned int, txcount, sport->dma_tx_bytes);
+}
+
static void lpuart_dma_tx(struct lpuart_port *sport)
{
struct circ_buf *xmit = &sport->port.state->xmit;
struct scatterlist *sgl = sport->tx_sgl;
struct device *dev = sport->port.dev;
+ u32 toend_cnt;
int ret;
if (sport->dma_tx_in_progress)
return;
- sport->dma_tx_bytes = uart_circ_chars_pending(xmit);
+ lpuart_recal_min_trans_size(sport);
+ if (!sport->dma_tx_bytes)
+ return;
+
+ toend_cnt = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
- if (xmit->tail < xmit->head || xmit->head == 0) {
+ if (xmit->tail < xmit->head || xmit->head == 0 ||
+ (sport->port.mctrl & TIOCM_LOOP && sport->dma_tx_bytes <= toend_cnt)) {
sport->dma_tx_nents = 1;
sg_init_one(sgl, xmit->buf + xmit->tail, sport->dma_tx_bytes);
} else {
@@ -336,7 +393,8 @@ static void lpuart_dma_tx(struct lpuart_port *sport)
sg_init_table(sgl, 2);
sg_set_buf(sgl, xmit->buf + xmit->tail,
UART_XMIT_SIZE - xmit->tail);
- sg_set_buf(sgl + 1, xmit->buf, xmit->head);
+ sg_set_buf(sgl + 1, xmit->buf, sport->dma_tx_bytes -
+ (UART_XMIT_SIZE - xmit->tail));
}
ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
@@ -346,8 +404,8 @@ static void lpuart_dma_tx(struct lpuart_port *sport)
}
sport->dma_tx_desc = dmaengine_prep_slave_sg(sport->dma_tx_chan, sgl,
- sport->dma_tx_nents,
- DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
+ ret, DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT);
if (!sport->dma_tx_desc) {
dma_unmap_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
dev_err(dev, "Cannot prepare TX slave DMA!\n");
@@ -369,6 +427,10 @@ static void lpuart_dma_tx_complete(void *arg)
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
+ if (!sport->dma_tx_in_progress) {
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+ return;
+ }
dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
@@ -376,18 +438,16 @@ static void lpuart_dma_tx_complete(void *arg)
sport->port.icount.tx += sport->dma_tx_bytes;
sport->dma_tx_in_progress = false;
- spin_unlock_irqrestore(&sport->port.lock, flags);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port);
if (waitqueue_active(&sport->dma_wait)) {
wake_up(&sport->dma_wait);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
return;
}
- spin_lock_irqsave(&sport->port.lock, flags);
-
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port))
lpuart_dma_tx(sport);
@@ -401,15 +461,18 @@ static int lpuart_dma_tx_request(struct uart_port *port)
struct dma_slave_config dma_tx_sconfig = {};
int ret;
- dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR;
+ if (sport->lpuart32)
+ dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDATA;
+ else
+ dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR;
dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma_tx_sconfig.dst_maxburst = 1;
dma_tx_sconfig.direction = DMA_MEM_TO_DEV;
ret = dmaengine_slave_config(sport->dma_tx_chan, &dma_tx_sconfig);
- if (ret) {
+ if (ret < 0) {
dev_err(sport->port.dev,
- "DMA slave config failed, err = %d\n", ret);
+ "Dma slave config failed, err = %d\n", ret);
return ret;
}
@@ -419,6 +482,7 @@ static int lpuart_dma_tx_request(struct uart_port *port)
static void lpuart_flush_buffer(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+ u32 val;
if (sport->lpuart_dma_tx_use) {
if (sport->dma_tx_in_progress) {
@@ -428,6 +492,16 @@ static void lpuart_flush_buffer(struct uart_port *port)
}
dmaengine_terminate_all(sport->dma_tx_chan);
}
+
+ if (sport->lpuart32) {
+ val = lpuart32_read(sport->port.membase + UARTFIFO);
+ val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
+ lpuart32_write(val, sport->port.membase + UARTFIFO);
+ } else {
+ val = readb(sport->port.membase + UARTPFIFO);
+ val |= UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH;
+ writeb(val, sport->port.membase + UARTCFIFO);
+ }
}
static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
@@ -479,13 +553,13 @@ static void lpuart_start_tx(struct uart_port *port)
struct circ_buf *xmit = &sport->port.state->xmit;
unsigned char temp;
- temp = readb(port->membase + UARTCR2);
- writeb(temp | UARTCR2_TIE, port->membase + UARTCR2);
-
if (sport->lpuart_dma_tx_use) {
if (!uart_circ_empty(xmit) && !uart_tx_stopped(port))
lpuart_dma_tx(sport);
} else {
+ temp = readb(port->membase + UARTCR2);
+ writeb(temp | UARTCR2_TIE, port->membase + UARTCR2);
+
if (readb(port->membase + UARTSR1) & UARTSR1_TDRE)
lpuart_transmit_buffer(sport);
}
@@ -494,13 +568,33 @@ static void lpuart_start_tx(struct uart_port *port)
static void lpuart32_start_tx(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+ struct circ_buf *xmit = &sport->port.state->xmit;
unsigned long temp;
- temp = lpuart32_read(port->membase + UARTCTRL);
- lpuart32_write(temp | UARTCTRL_TIE, port->membase + UARTCTRL);
+ if (sport->lpuart_dma_tx_use) {
+ if (!uart_circ_empty(xmit) && !uart_tx_stopped(port))
+ lpuart_dma_tx(sport);
+ } else {
+ temp = lpuart32_read(port->membase + UARTCTRL);
+ lpuart32_write(temp | UARTCTRL_TIE, port->membase + UARTCTRL);
+ if (lpuart32_read(sport->port.membase + UARTSTAT) &
+ UARTSTAT_TDRE)
+ lpuart32_transmit_buffer(sport);
+ }
+}
- if (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TDRE)
- lpuart32_transmit_buffer(sport);
+static void
+lpuart_uart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
+{
+ switch (state) {
+ case UART_PM_STATE_OFF:
+ pm_runtime_mark_last_busy(port->dev);
+ pm_runtime_put_autosuspend(port->dev);
+ break;
+ default:
+ pm_runtime_get_sync(port->dev);
+ break;
+ }
}
/* return TIOCSER_TEMT when transmitter is not busy */
@@ -522,8 +616,18 @@ static unsigned int lpuart_tx_empty(struct uart_port *port)
static unsigned int lpuart32_tx_empty(struct uart_port *port)
{
- return (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TC) ?
- TIOCSER_TEMT : 0;
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ unsigned int sr1 = lpuart32_read(port->membase + UARTSTAT);
+ unsigned int sfifo = lpuart32_read(sport->port.membase + UARTFIFO);
+
+ if (sport->dma_tx_in_progress)
+ return 0;
+
+ if (sr1 & UARTSTAT_TC && sfifo & UARTFIFO_TXEMPT)
+ return TIOCSER_TEMT;
+
+ return 0;
}
static irqreturn_t lpuart_txint(int irq, void *dev_id)
@@ -638,13 +742,19 @@ static irqreturn_t lpuart32_rxint(int irq, void *dev_id)
while (!(lpuart32_read(sport->port.membase + UARTFIFO) & UARTFIFO_RXEMPT)) {
flg = TTY_NORMAL;
sport->port.icount.rx++;
+
/*
* to clear the FE, OR, NF, FE, PE flags,
* read STAT then read DATA reg
*/
sr = lpuart32_read(sport->port.membase + UARTSTAT);
rx = lpuart32_read(sport->port.membase + UARTDATA);
- rx &= 0x3ff;
+
+ if ((sr & UARTSTAT_FE) && (rx & UARTDATA_FRETSC) &&
+ !(rx & UARTDATA_MASK)) {
+ if (uart_handle_break(&sport->port))
+ continue;
+ }
if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
continue;
@@ -677,8 +787,13 @@ static irqreturn_t lpuart32_rxint(int irq, void *dev_id)
#ifdef SUPPORT_SYSRQ
sport->port.sysrq = 0;
#endif
+ continue;
}
+ if (rx & UARTDATA_INVALID)
+ continue;
+
+ rx &= UARTDATA_MASK;
tty_insert_flip_char(port, rx, flg);
}
@@ -692,14 +807,19 @@ out:
static irqreturn_t lpuart_int(int irq, void *dev_id)
{
struct lpuart_port *sport = dev_id;
- unsigned char sts;
+ unsigned char sts, crdma;
sts = readb(sport->port.membase + UARTSR1);
+ crdma = readb(sport->port.membase + UARTCR5);
- if (sts & UARTSR1_RDRF)
- lpuart_rxint(irq, dev_id);
+ if (sts & UARTSR1_RDRF && !(crdma & UARTCR5_RDMAS)) {
+ if (sport->lpuart_dma_rx_use)
+ lpuart_prepare_rx(sport);
+ else
+ lpuart_rxint(irq, dev_id);
+ }
- if (sts & UARTSR1_TDRE)
+ if (sts & UARTSR1_TDRE && !sport->lpuart_dma_tx_use)
lpuart_txint(irq, dev_id);
return IRQ_HANDLED;
@@ -708,195 +828,164 @@ static irqreturn_t lpuart_int(int irq, void *dev_id)
static irqreturn_t lpuart32_int(int irq, void *dev_id)
{
struct lpuart_port *sport = dev_id;
- unsigned long sts, rxcount;
+ unsigned long sts, rxcount, crdma;
sts = lpuart32_read(sport->port.membase + UARTSTAT);
rxcount = lpuart32_read(sport->port.membase + UARTWATER);
rxcount = rxcount >> UARTWATER_RXCNT_OFF;
+ crdma = lpuart32_read(sport->port.membase + UARTBAUD);
+
+ if (!sts)
+ return IRQ_NONE;
+
+ if (!(crdma & UARTBAUD_RDMAE) && rxcount > 0) {
+ if (!sport->lpuart_dma_rx_use ||
+ (sts & (UARTSTAT_PE | UARTSTAT_NF | UARTSTAT_FE)))
+ lpuart32_rxint(irq, dev_id);
+ else if (sport->lpuart_dma_rx_use && sport->dma_rx_chan_active)
+ lpuart_prepare_rx(sport);
+ } else if (!(crdma & UARTBAUD_RDMAE) && (sts & UARTSTAT_IDLE) &&
+ !(sport->lpuart_dma_rx_use && sport->dma_eeop &&
+ rxcount > 0)) {
+ lpuart32_write(UARTSTAT_IDLE, sport->port.membase + UARTSTAT);
+ }
- if (sts & UARTSTAT_RDRF || rxcount > 0)
- lpuart32_rxint(irq, dev_id);
-
- if ((sts & UARTSTAT_TDRE) &&
- !(lpuart32_read(sport->port.membase + UARTBAUD) & UARTBAUD_TDMAE))
+ if (sts & UARTSTAT_TDRE && !sport->lpuart_dma_tx_use)
lpuart_txint(irq, dev_id);
+ sts &= ~UARTSTAT_IDLE;
lpuart32_write(sts, sport->port.membase + UARTSTAT);
return IRQ_HANDLED;
}
-static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
+static void lpuart_copy_rx_to_tty(struct lpuart_port *sport,
+ struct tty_port *tty, int count)
{
- struct tty_port *port = &sport->port.state->port;
- struct dma_tx_state state;
- enum dma_status dmastat;
- struct circ_buf *ring = &sport->rx_ring;
- unsigned long flags;
- int count = 0;
- unsigned char sr;
-
- sr = readb(sport->port.membase + UARTSR1);
+ int copied;
- if (sr & (UARTSR1_PE | UARTSR1_FE)) {
- /* Read DR to clear the error flags */
- readb(sport->port.membase + UARTDR);
-
- if (sr & UARTSR1_PE)
- sport->port.icount.parity++;
- else if (sr & UARTSR1_FE)
- sport->port.icount.frame++;
- }
-
- async_tx_ack(sport->dma_rx_desc);
+ sport->port.icount.rx += count;
- spin_lock_irqsave(&sport->port.lock, flags);
-
- dmastat = dmaengine_tx_status(sport->dma_rx_chan,
- sport->dma_rx_cookie,
- &state);
-
- if (dmastat == DMA_ERROR) {
- dev_err(sport->port.dev, "Rx DMA transfer failed!\n");
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ if (!tty) {
+ dev_err(sport->port.dev, "No tty port\n");
return;
}
- /* CPU claims ownership of RX DMA buffer */
- dma_sync_sg_for_cpu(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
+ dma_sync_single_for_cpu(sport->port.dev, sport->dma_rx_buf_bus,
+ sport->rxdma_len, DMA_FROM_DEVICE);
+ copied = tty_insert_flip_string(tty,
+ ((unsigned char *)(sport->dma_rx_buf_virt)), count);
- /*
- * ring->head points to the end of data already written by the DMA.
- * ring->tail points to the beginning of data to be read by the
- * framework.
- * The current transfer size should not be larger than the dma buffer
- * length.
- */
- ring->head = sport->rx_sgl.length - state.residue;
- BUG_ON(ring->head > sport->rx_sgl.length);
- /*
- * At this point ring->head may point to the first byte right after the
- * last byte of the dma buffer:
- * 0 <= ring->head <= sport->rx_sgl.length
- *
- * However ring->tail must always points inside the dma buffer:
- * 0 <= ring->tail <= sport->rx_sgl.length - 1
- *
- * Since we use a ring buffer, we have to handle the case
- * where head is lower than tail. In such a case, we first read from
- * tail to the end of the buffer then reset tail.
- */
- if (ring->head < ring->tail) {
- count = sport->rx_sgl.length - ring->tail;
+ if (copied != count)
+ sport->port.icount.buf_overrun += count - copied;
+ sport->port.icount.rx += copied;
+}
- tty_insert_flip_string(port, ring->buf + ring->tail, count);
- ring->tail = 0;
- sport->port.icount.rx += count;
- }
+static void lpuart_dma_stop(struct lpuart_port *sport, bool enable_pio)
+{
+ unsigned int temp;
+ unsigned int crdma;
- /* Finally we read data from tail to head */
- if (ring->tail < ring->head) {
- count = ring->head - ring->tail;
- tty_insert_flip_string(port, ring->buf + ring->tail, count);
- /* Wrap ring->head if needed */
- if (ring->head >= sport->rx_sgl.length)
- ring->head = 0;
- ring->tail = ring->head;
- sport->port.icount.rx += count;
+ if (sport->lpuart32) {
+ lpuart32_write(UARTSTAT_IDLE, sport->port.membase + UARTSTAT);
+ crdma = lpuart32_read(sport->port.membase + UARTBAUD);
+ lpuart32_write(crdma & ~(UARTBAUD_RDMAE | UARTBAUD_RIDMAE),
+ sport->port.membase + UARTBAUD);
+ if (enable_pio) {
+ temp = lpuart32_read(sport->port.membase + UARTCTRL);
+ temp |= (UARTCTRL_RIE | UARTCTRL_ILIE);
+ lpuart32_write(temp, sport->port.membase + UARTCTRL);
+ }
+ } else {
+ temp = readb(sport->port.membase + UARTCR5);
+ writeb(temp & ~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
}
+}
- dma_sync_sg_for_device(sport->port.dev, &sport->rx_sgl, 1,
- DMA_FROM_DEVICE);
+static void lpuart_dma_rx_complete(void *arg)
+{
+ struct lpuart_port *sport = arg;
+ struct tty_port *port = &sport->port.state->port;
+ unsigned long flags;
+ struct dma_tx_state state;
+ int count, rxcount;
+
+ if (!sport->dma_eeop)
+ mod_timer(&sport->lpuart_timer,
+ jiffies + sport->dma_rx_timeout);
+ spin_lock_irqsave(&sport->port.lock, flags);
+ sport->dma_rx_in_progress = false;
+ dmaengine_tx_status(sport->dma_rx_chan, sport->dma_rx_cookie, &state);
+ count = sport->rxdma_len - state.residue;
spin_unlock_irqrestore(&sport->port.lock, flags);
+ lpuart_copy_rx_to_tty(sport, port, count);
tty_flip_buffer_push(port);
- mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout);
-}
-static void lpuart_dma_rx_complete(void *arg)
-{
- struct lpuart_port *sport = arg;
+ spin_lock_irqsave(&sport->port.lock, flags);
- lpuart_copy_rx_to_tty(sport);
-}
+ /* For end of packet, clear the idle flag to avoid to trigger
+ * the next transfer. Only i.MX8x lpuart support EEOP.
+ */
+ if (sport->dma_eeop && sport->lpuart32) {
+ rxcount = lpuart32_read(sport->port.membase + UARTWATER);
+ rxcount = rxcount >> UARTWATER_RXCNT_OFF;
+ if (!rxcount)
+ lpuart32_write(UARTSTAT_IDLE,
+ sport->port.membase + UARTSTAT);
+ }
-static void lpuart_timer_func(unsigned long data)
-{
- struct lpuart_port *sport = (struct lpuart_port *)data;
+ if (!sport->dma_eeop && count < sport->rxfifo_watermark)
+ lpuart_dma_stop(sport, true);
+ else
+ lpuart_dma_rx(sport);
- lpuart_copy_rx_to_tty(sport);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
-static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
+static void lpuart_timer_func(unsigned long data)
{
- struct dma_slave_config dma_rx_sconfig = {};
- struct circ_buf *ring = &sport->rx_ring;
- int ret, nent;
- int bits, baud;
- struct tty_struct *tty = tty_port_tty_get(&sport->port.state->port);
- struct ktermios *termios = &tty->termios;
-
- baud = tty_get_baud_rate(tty);
-
- bits = (termios->c_cflag & CSIZE) == CS7 ? 9 : 10;
- if (termios->c_cflag & PARENB)
- bits++;
+ struct lpuart_port *sport = (struct lpuart_port *)data;
+ struct tty_port *port = &sport->port.state->port;
+ struct dma_tx_state state;
+ unsigned long flags;
+ int count;
- /*
- * Calculate length of one DMA buffer size to keep latency below
- * 10ms at any baud rate.
- */
- sport->rx_dma_rng_buf_len = (DMA_RX_TIMEOUT * baud / bits / 1000) * 2;
- sport->rx_dma_rng_buf_len = (1 << (fls(sport->rx_dma_rng_buf_len) - 1));
- if (sport->rx_dma_rng_buf_len < 16)
- sport->rx_dma_rng_buf_len = 16;
-
- ring->buf = kmalloc(sport->rx_dma_rng_buf_len, GFP_ATOMIC);
- if (!ring->buf) {
- dev_err(sport->port.dev, "Ring buf alloc failed\n");
- return -ENOMEM;
- }
+ del_timer(&sport->lpuart_timer);
+ dmaengine_pause(sport->dma_rx_chan);
+ dmaengine_tx_status(sport->dma_rx_chan, sport->dma_rx_cookie, &state);
+ dmaengine_terminate_all(sport->dma_rx_chan);
+ count = sport->rxdma_len - state.residue;
- sg_init_one(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len);
- sg_set_buf(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len);
- nent = dma_map_sg(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
+ spin_lock_irqsave(&sport->port.lock, flags);
- if (!nent) {
- dev_err(sport->port.dev, "DMA Rx mapping error\n");
- return -EINVAL;
- }
+ sport->dma_rx_in_progress = false;
+ lpuart_copy_rx_to_tty(sport, port, count);
+ tty_flip_buffer_push(port);
+ lpuart_dma_stop(sport, true);
- dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR;
- dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- dma_rx_sconfig.src_maxburst = 1;
- dma_rx_sconfig.direction = DMA_DEV_TO_MEM;
- ret = dmaengine_slave_config(sport->dma_rx_chan, &dma_rx_sconfig);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
- if (ret < 0) {
- dev_err(sport->port.dev,
- "DMA Rx slave config failed, err = %d\n", ret);
- return ret;
- }
+static int lpuart_dma_rx(struct lpuart_port *sport)
+{
+ dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus,
+ sport->rxdma_len, DMA_FROM_DEVICE);
+ sport->dma_rx_desc = dmaengine_prep_slave_single(sport->dma_rx_chan,
+ sport->dma_rx_buf_bus, sport->rxdma_len,
+ DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
- sport->dma_rx_desc = dmaengine_prep_dma_cyclic(sport->dma_rx_chan,
- sg_dma_address(&sport->rx_sgl),
- sport->rx_sgl.length,
- sport->rx_sgl.length / 2,
- DMA_DEV_TO_MEM,
- DMA_PREP_INTERRUPT);
if (!sport->dma_rx_desc) {
- dev_err(sport->port.dev, "Cannot prepare cyclic DMA\n");
- return -EFAULT;
+ dev_err(sport->port.dev, "Not able to get desc for rx\n");
+ return -EIO;
}
sport->dma_rx_desc->callback = lpuart_dma_rx_complete;
sport->dma_rx_desc->callback_param = sport;
+ sport->dma_rx_in_progress = true;
sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc);
dma_async_issue_pending(sport->dma_rx_chan);
- writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_RDMAS,
- sport->port.membase + UARTCR5);
-
return 0;
}
@@ -905,15 +994,44 @@ static void lpuart_dma_rx_free(struct uart_port *port)
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
- if (sport->dma_rx_chan)
- dmaengine_terminate_all(sport->dma_rx_chan);
+ sport->dma_rx_chan_active = false;
+ dma_unmap_single(sport->port.dev, sport->dma_rx_buf_bus,
+ sport->rxdma_len, DMA_FROM_DEVICE);
- dma_unmap_sg(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
- kfree(sport->rx_ring.buf);
- sport->rx_ring.tail = 0;
- sport->rx_ring.head = 0;
- sport->dma_rx_desc = NULL;
- sport->dma_rx_cookie = -EINVAL;
+ devm_kfree(sport->port.dev, sport->dma_rx_buf_virt);
+ sport->dma_rx_buf_bus = 0;
+ sport->dma_rx_buf_virt = NULL;
+}
+
+static inline void lpuart_prepare_rx(struct lpuart_port *sport)
+{
+ unsigned long flags;
+ unsigned int temp;
+ unsigned int crdma;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
+ if (!sport->dma_eeop) {
+ sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
+ add_timer(&sport->lpuart_timer);
+ }
+
+ lpuart_dma_rx(sport);
+ if (sport->lpuart32) {
+ temp = lpuart32_read(sport->port.membase + UARTCTRL);
+ temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE);
+ lpuart32_write(temp, sport->port.membase + UARTCTRL);
+ crdma = lpuart32_read(sport->port.membase + UARTBAUD);
+ if (sport->dma_eeop)
+ crdma |= UARTBAUD_RIDMAE;
+ lpuart32_write(crdma | UARTBAUD_RDMAE,
+ sport->port.membase + UARTBAUD);
+ } else {
+ temp = readb(sport->port.membase + UARTCR5);
+ writeb(temp | UARTCR5_RDMAS, sport->port.membase + UARTCR5);
+ }
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
static int lpuart_config_rs485(struct uart_port *port,
@@ -989,11 +1107,15 @@ static unsigned int lpuart32_get_mctrl(struct uart_port *port)
if (reg & UARTMODIR_RXRTSE)
temp |= TIOCM_RTS;
+ if (lpuart32_read(port->membase + UARTCTRL) & UARTCTRL_LOOPS)
+ temp |= TIOCM_LOOP;
+
return temp;
}
static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
+ /* No flow control for user handle */
unsigned char temp;
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
@@ -1017,16 +1139,13 @@ static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
unsigned long temp;
- temp = lpuart32_read(port->membase + UARTMODIR) &
- ~(UARTMODIR_RXRTSE | UARTMODIR_TXCTSE);
-
- if (mctrl & TIOCM_RTS)
- temp |= UARTMODIR_RXRTSE;
-
- if (mctrl & TIOCM_CTS)
- temp |= UARTMODIR_TXCTSE;
+ temp = lpuart32_read(port->membase + UARTCTRL);
+ if (mctrl & TIOCM_LOOP)
+ temp |= UARTCTRL_LOOPS;
+ else
+ temp &= ~UARTCTRL_LOOPS;
- lpuart32_write(temp, port->membase + UARTMODIR);
+ lpuart32_write(temp, port->membase + UARTCTRL);
}
static void lpuart_break_ctl(struct uart_port *port, int break_state)
@@ -1089,6 +1208,7 @@ static void lpuart32_setup_watermark(struct lpuart_port *sport)
{
unsigned long val, ctrl;
unsigned long ctrl_saved;
+ unsigned long rxiden_cnt = UARTFIFO_RXIDEN_RDRF;
ctrl = lpuart32_read(sport->port.membase + UARTCTRL);
ctrl_saved = ctrl;
@@ -1100,28 +1220,82 @@ static void lpuart32_setup_watermark(struct lpuart_port *sport)
val = lpuart32_read(sport->port.membase + UARTFIFO);
val |= UARTFIFO_TXFE | UARTFIFO_RXFE;
val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
+ val &= ~(UARTFIFO_RXIDEN_MASK << UARTFIFO_RXIDEN_OFF);
+ if (sport->dma_eeop)
+ rxiden_cnt = 0;
+ val |= ((rxiden_cnt & UARTFIFO_RXIDEN_MASK) <<
+ UARTFIFO_RXIDEN_OFF);
lpuart32_write(val, sport->port.membase + UARTFIFO);
/* set the watermark */
- val = (0x1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF);
+ if (uart_console(&sport->port)) {
+ val = (0x1 << UARTWATER_RXWATER_OFF) |
+ (0x0 << UARTWATER_TXWATER_OFF);
+ } else {
+ val = lpuart32_read(sport->port.membase + UARTMODIR);
+ val = sport->rts_watermark << UARTMODIR_RTSWATER_S;
+ lpuart32_write(val, sport->port.membase + UARTMODIR);
+ val = (sport->rxfifo_watermark << UARTWATER_RXWATER_OFF) |
+ (sport->txfifo_watermark << UARTWATER_TXWATER_OFF);
+ }
lpuart32_write(val, sport->port.membase + UARTWATER);
/* Restore cr2 */
lpuart32_write(ctrl_saved, sport->port.membase + UARTCTRL);
}
-static void rx_dma_timer_init(struct lpuart_port *sport)
+static int lpuart_dma_rx_request(struct uart_port *port)
{
- setup_timer(&sport->lpuart_timer, lpuart_timer_func,
- (unsigned long)sport);
- sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
- add_timer(&sport->lpuart_timer);
+ struct lpuart_port *sport = container_of(port,
+ struct lpuart_port, port);
+ struct dma_slave_config dma_rx_sconfig;
+ dma_addr_t dma_bus;
+ unsigned char *dma_buf;
+ int ret;
+
+ dma_buf = devm_kzalloc(sport->port.dev,
+ sport->rxdma_len, GFP_KERNEL);
+
+ if (!dma_buf) {
+ dev_err(sport->port.dev, "Dma rx alloc failed\n");
+ return -ENOMEM;
+ }
+
+ dma_bus = dma_map_single(sport->port.dev, dma_buf,
+ sport->rxdma_len, DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(sport->port.dev, dma_bus)) {
+ dev_err(sport->port.dev, "dma_map_single rx failed\n");
+ return -ENOMEM;
+ }
+
+ if (sport->lpuart32)
+ dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDATA;
+ else
+ dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR;
+
+ dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_rx_sconfig.src_maxburst = 1;
+ dma_rx_sconfig.direction = DMA_DEV_TO_MEM;
+ ret = dmaengine_slave_config(sport->dma_rx_chan, &dma_rx_sconfig);
+
+ if (ret < 0) {
+ dev_err(sport->port.dev,
+ "Dma slave config failed, err = %d\n", ret);
+ return ret;
+ }
+
+ sport->dma_rx_buf_virt = dma_buf;
+ sport->dma_rx_buf_bus = dma_bus;
+ sport->dma_rx_in_progress = false;
+ sport->dma_rx_chan_active = true;
+
+ return 0;
}
static int lpuart_startup(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- int ret;
unsigned long flags;
unsigned char temp;
@@ -1135,74 +1309,95 @@ static int lpuart_startup(struct uart_port *port)
sport->rxfifo_size = 0x1 << (((temp >> UARTPFIFO_RXSIZE_OFF) &
UARTPFIFO_FIFOSIZE_MASK) + 1);
+ sport->rxdma_len = FSL_UART_RX_DMA_BUFFER_SIZE;
- ret = devm_request_irq(port->dev, port->irq, lpuart_int, 0,
- DRIVER_NAME, sport);
- if (ret)
- return ret;
-
- spin_lock_irqsave(&sport->port.lock, flags);
-
- lpuart_setup_watermark(sport);
-
- temp = readb(sport->port.membase + UARTCR2);
- temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE);
- writeb(temp, sport->port.membase + UARTCR2);
-
- if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) {
- /* set Rx DMA timeout */
- sport->dma_rx_timeout = msecs_to_jiffies(DMA_RX_TIMEOUT);
- if (!sport->dma_rx_timeout)
- sport->dma_rx_timeout = 1;
-
+ if (sport->dma_rx_chan && !lpuart_dma_rx_request(port)) {
sport->lpuart_dma_rx_use = true;
- rx_dma_timer_init(sport);
- } else {
+ setup_timer(&sport->lpuart_timer, lpuart_timer_func,
+ (unsigned long)sport);
+ } else
sport->lpuart_dma_rx_use = false;
- }
+
if (sport->dma_tx_chan && !lpuart_dma_tx_request(port)) {
init_waitqueue_head(&sport->dma_wait);
sport->lpuart_dma_tx_use = true;
temp = readb(port->membase + UARTCR5);
+ temp &= ~UARTCR5_RDMAS;
writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5);
- } else {
+ } else
sport->lpuart_dma_tx_use = false;
- }
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ spin_lock_irqsave(&sport->port.lock, flags);
+ lpuart_setup_watermark(sport);
+
+ temp = readb(sport->port.membase + UARTCR2);
+ temp |= (UARTCR2_RIE | UARTCR2_RE | UARTCR2_TE);
+ writeb(temp, sport->port.membase + UARTCR2);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
return 0;
}
static int lpuart32_startup(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+ struct tty_port *tty_port = &sport->port.state->port;
int ret;
unsigned long flags;
unsigned long temp;
+ /* some modem may need reset */
+ if (!tty_port_suspended(tty_port)) {
+ ret = device_reset(sport->port.dev);
+ if (ret && ret != -ENOENT)
+ return ret;
+ }
+
/* determine FIFO size */
temp = lpuart32_read(sport->port.membase + UARTFIFO);
sport->txfifo_size = 0x1 << (((temp >> UARTFIFO_TXSIZE_OFF) &
- UARTFIFO_FIFOSIZE_MASK) - 1);
+ UARTFIFO_FIFOSIZE_MASK) + 1);
+
+ sport->port.fifosize = sport->txfifo_size;
sport->rxfifo_size = 0x1 << (((temp >> UARTFIFO_RXSIZE_OFF) &
- UARTFIFO_FIFOSIZE_MASK) - 1);
+ UARTFIFO_FIFOSIZE_MASK) + 1);
- ret = devm_request_irq(port->dev, port->irq, lpuart32_int, 0,
- DRIVER_NAME, sport);
- if (ret)
- return ret;
+ sport->txfifo_watermark = sport->txfifo_size >> 1;
+ sport->rxfifo_watermark = 1;
+ sport->rts_watermark = sport->rxfifo_size >> 1;
+ sport->rxdma_len = FSL_UART_RX_DMA_BUFFER_SIZE;
+
+ if (sport->dma_rx_chan && !lpuart_dma_rx_request(port)) {
+ sport->lpuart_dma_rx_use = true;
+ if (!sport->dma_eeop)
+ setup_timer(&sport->lpuart_timer,
+ lpuart_timer_func,
+ (unsigned long)sport);
+ } else
+ sport->lpuart_dma_rx_use = false;
+
+
+ if (sport->dma_tx_chan && !lpuart_dma_tx_request(port)) {
+ init_waitqueue_head(&sport->dma_wait);
+ sport->lpuart_dma_tx_use = true;
+ temp = lpuart32_read(sport->port.membase + UARTBAUD);
+ temp |= UARTBAUD_TDMAE;
+ lpuart32_write(temp, sport->port.membase + UARTBAUD);
+ } else
+ sport->lpuart_dma_tx_use = false;
spin_lock_irqsave(&sport->port.lock, flags);
lpuart32_setup_watermark(sport);
temp = lpuart32_read(sport->port.membase + UARTCTRL);
- temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE | UARTCTRL_TE);
+ temp |= (UARTCTRL_RIE | UARTCTRL_RE | UARTCTRL_TE);
temp |= UARTCTRL_ILIE;
+ temp |= UARTCTRL_IDLECFG << UARTCTRL_IDLECFG_OFF;
lpuart32_write(temp, sport->port.membase + UARTCTRL);
spin_unlock_irqrestore(&sport->port.lock, flags);
@@ -1214,6 +1409,7 @@ static void lpuart_shutdown(struct uart_port *port)
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
unsigned char temp;
unsigned long flags;
+ int ret;
spin_lock_irqsave(&port->lock, flags);
@@ -1225,21 +1421,20 @@ static void lpuart_shutdown(struct uart_port *port)
spin_unlock_irqrestore(&port->lock, flags);
- devm_free_irq(port->dev, port->irq, sport);
-
if (sport->lpuart_dma_rx_use) {
+ sport->dma_rx_in_progress = false;
+ dmaengine_terminate_all(sport->dma_rx_chan);
del_timer_sync(&sport->lpuart_timer);
lpuart_dma_rx_free(&sport->port);
}
if (sport->lpuart_dma_tx_use) {
- if (wait_event_interruptible(sport->dma_wait,
- !sport->dma_tx_in_progress) != false) {
+ ret = wait_event_interruptible_timeout(sport->dma_wait,
+ !sport->dma_tx_in_progress, msecs_to_jiffies(1));
+ if (ret <= 0) {
sport->dma_tx_in_progress = false;
dmaengine_terminate_all(sport->dma_tx_chan);
}
-
- lpuart_stop_tx(port);
}
}
@@ -1248,18 +1443,45 @@ static void lpuart32_shutdown(struct uart_port *port)
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
unsigned long temp;
unsigned long flags;
+ int ret;
spin_lock_irqsave(&port->lock, flags);
+ /* clear statue */
+ temp = lpuart32_read(sport->port.membase + UARTSTAT);
+ lpuart32_write(temp, sport->port.membase + UARTSTAT);
+
+ /* disable Rx/Tx DMA */
+ temp = lpuart32_read(sport->port.membase + UARTBAUD);
+ temp &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE | UARTBAUD_RIDMAE);
+ lpuart32_write(temp, sport->port.membase + UARTBAUD);
+
/* disable Rx/Tx and interrupts */
temp = lpuart32_read(port->membase + UARTCTRL);
- temp &= ~(UARTCTRL_TE | UARTCTRL_RE |
- UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE);
+ temp &= ~(UARTCTRL_TE | UARTCTRL_RE | UARTCTRL_TIE |
+ UARTCTRL_TCIE | UARTCTRL_RIE | UARTCTRL_ILIE |
+ UARTCTRL_LOOPS);
lpuart32_write(temp, port->membase + UARTCTRL);
+ lpuart32_write(0, sport->port.membase + UARTMODIR);
spin_unlock_irqrestore(&port->lock, flags);
- devm_free_irq(port->dev, port->irq, sport);
+ if (sport->lpuart_dma_rx_use) {
+ sport->dma_rx_in_progress = false;
+ dmaengine_terminate_all(sport->dma_rx_chan);
+ if (!sport->dma_eeop)
+ del_timer_sync(&sport->lpuart_timer);
+ lpuart_dma_rx_free(&sport->port);
+ }
+
+ if (sport->lpuart_dma_tx_use) {
+ ret = wait_event_interruptible_timeout(sport->dma_wait,
+ !sport->dma_tx_in_progress, msecs_to_jiffies(1));
+ if (ret <= 0) {
+ sport->dma_tx_in_progress = false;
+ dmaengine_terminate_all(sport->dma_tx_chan);
+ }
+ }
}
static void
@@ -1373,6 +1595,17 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
/* update the per-port timeout */
uart_update_timeout(port, termios->c_cflag, baud);
+ if (sport->lpuart_dma_rx_use) {
+ /* Calculate delay for 1.5 DMA buffers */
+ sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) *
+ sport->rxdma_len * 3 /
+ sport->rxfifo_size / 2;
+ dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n",
+ sport->dma_rx_timeout * 1000 / HZ, sport->port.timeout);
+ if (sport->dma_rx_timeout < msecs_to_jiffies(20))
+ sport->dma_rx_timeout = msecs_to_jiffies(20);
+ }
+
/* wait transmit engin complete */
while (!(readb(sport->port.membase + UARTSR1) & UARTSR1_TC))
barrier();
@@ -1397,25 +1630,74 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
/* restore control register */
writeb(old_cr2, sport->port.membase + UARTCR2);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static void
+lpuart32_serial_setbrg(struct lpuart_port *sport, unsigned int baudrate)
+{
+ u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp;
+ u32 clk = sport->port.uartclk;
+
/*
- * If new baud rate is set, we will also need to update the Ring buffer
- * length according to the selected baud rate and restart Rx DMA path.
+ * The idea is to use the best OSR (over-sampling rate) possible.
+ * Note, OSR is typically hard-set to 16 in other LPUART instantiations.
+ * Loop to find the best OSR value possible, one that generates minimum
+ * baud_diff iterate through the rest of the supported values of OSR.
+ *
+ * Calculation Formula:
+ * Baud Rate = baud clock / ((OSR+1) × SBR)
*/
- if (old) {
- if (sport->lpuart_dma_rx_use) {
- del_timer_sync(&sport->lpuart_timer);
- lpuart_dma_rx_free(&sport->port);
+ baud_diff = baudrate;
+ osr = 0;
+ sbr = 0;
+
+ for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) {
+ /* calculate the temporary sbr value */
+ tmp_sbr = (clk / (baudrate * tmp_osr));
+ if (tmp_sbr == 0)
+ tmp_sbr = 1;
+
+ /*
+ * calculate the baud rate difference based on the temporary
+ * osr and sbr values
+ */
+ tmp_diff = clk / (tmp_osr * tmp_sbr) - baudrate;
+
+ /* select best values between sbr and sbr+1 */
+ tmp = clk / (tmp_osr * (tmp_sbr + 1));
+ if (tmp_diff > (baudrate - tmp)) {
+ tmp_diff = baudrate - tmp;
+ tmp_sbr++;
}
- if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) {
- sport->lpuart_dma_rx_use = true;
- rx_dma_timer_init(sport);
- } else {
- sport->lpuart_dma_rx_use = false;
+ if (tmp_diff <= baud_diff) {
+ baud_diff = tmp_diff;
+ osr = tmp_osr;
+ sbr = tmp_sbr;
+
+ if (!baud_diff)
+ break;
}
}
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ /* handle buadrate outside acceptable rate */
+ if (baud_diff > ((baudrate / 100) * 3))
+ dev_warn(sport->port.dev,
+ "unacceptable baud rate difference of more than 3%%\n");
+
+ tmp = lpuart32_read(sport->port.membase + UARTBAUD);
+
+ if ((osr > 3) && (osr < 8))
+ tmp |= UARTBAUD_BOTHEDGE;
+
+ tmp &= ~(UARTBAUD_OSR_MASK << UARTBAUD_OSR_SHIFT);
+ tmp |= (((osr-1) & UARTBAUD_OSR_MASK) << UARTBAUD_OSR_SHIFT);
+
+ tmp &= ~UARTBAUD_SBR_MASK;
+ tmp |= sbr & UARTBAUD_SBR_MASK;
+
+ lpuart32_write(tmp, sport->port.membase + UARTBAUD);
}
static void
@@ -1427,7 +1709,6 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned long ctrl, old_ctrl, bd, modem;
unsigned int baud;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
- unsigned int sbr;
ctrl = old_ctrl = lpuart32_read(sport->port.membase + UARTCTRL);
bd = lpuart32_read(sport->port.membase + UARTBAUD);
@@ -1467,7 +1748,9 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
}
if (termios->c_cflag & CSTOPB)
- termios->c_cflag &= ~CSTOPB;
+ bd |= UARTBAUD_SBNS;
+ else
+ bd &= ~UARTBAUD_SBNS;
/* parity must be enabled when CS7 to match 8-bits format */
if ((termios->c_cflag & CSIZE) == CS7)
@@ -1489,7 +1772,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
}
/* ask the core to calculate the divisor */
- baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
+ baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 4);
spin_lock_irqsave(&sport->port.lock, flags);
@@ -1516,7 +1799,19 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
/* update the per-port timeout */
uart_update_timeout(port, termios->c_cflag, baud);
- /* wait transmit engin complete */
+ if (sport->lpuart_dma_rx_use && !sport->dma_eeop) {
+ /* Calculate delay for 1.5 DMA buffers */
+ sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) *
+ sport->rxdma_len * 3 /
+ sport->rxfifo_size / 2;
+ dev_dbg(port->dev, "DMA Rx t-out %ums, tty t-out %u jiffies\n",
+ sport->dma_rx_timeout * 1000 / HZ, sport->port.timeout);
+ if (sport->dma_rx_timeout < msecs_to_jiffies(20))
+ sport->dma_rx_timeout = msecs_to_jiffies(20);
+ }
+
+ /* wait transmit engin complete, there disable flow control */
+ lpuart32_write(0, sport->port.membase + UARTMODIR);
while (!(lpuart32_read(sport->port.membase + UARTSTAT) & UARTSTAT_TC))
barrier();
@@ -1524,17 +1819,15 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
lpuart32_write(old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE),
sport->port.membase + UARTCTRL);
- sbr = sport->port.uartclk / (16 * baud);
- bd &= ~UARTBAUD_SBR_MASK;
- bd |= sbr & UARTBAUD_SBR_MASK;
- bd |= UARTBAUD_BOTHEDGE;
- bd &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE);
lpuart32_write(bd, sport->port.membase + UARTBAUD);
+ lpuart32_serial_setbrg(sport, baud);
lpuart32_write(modem, sport->port.membase + UARTMODIR);
lpuart32_write(ctrl, sport->port.membase + UARTCTRL);
- /* restore control register */
spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ /* wait baud rate stable */
+ usleep_range(1000, 2000);
}
static const char *lpuart_type(struct uart_port *port)
@@ -1588,6 +1881,7 @@ static const struct uart_ops lpuart_pops = {
.break_ctl = lpuart_break_ctl,
.startup = lpuart_startup,
.shutdown = lpuart_shutdown,
+ .pm = lpuart_uart_pm,
.set_termios = lpuart_set_termios,
.type = lpuart_type,
.request_port = lpuart_request_port,
@@ -1607,6 +1901,7 @@ static const struct uart_ops lpuart32_pops = {
.break_ctl = lpuart32_break_ctl,
.startup = lpuart32_startup,
.shutdown = lpuart32_shutdown,
+ .pm = lpuart_uart_pm,
.set_termios = lpuart32_set_termios,
.type = lpuart_type,
.request_port = lpuart_request_port,
@@ -1719,7 +2014,10 @@ lpuart_console_get_options(struct lpuart_port *sport, int *baud,
brfa = readb(sport->port.membase + UARTCR4);
brfa &= UARTCR4_BRFA_MASK;
- uartclk = clk_get_rate(sport->clk);
+ if (sport->per_clk)
+ uartclk = clk_get_rate(sport->per_clk);
+ else
+ uartclk = clk_get_rate(sport->ipg_clk);
/*
* baud = mod_clk/(16*(sbr[13]+(brfa)/32)
*/
@@ -1735,7 +2033,7 @@ lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
int *parity, int *bits)
{
unsigned long cr, bd;
- unsigned int sbr, uartclk, baud_raw;
+ unsigned int sbr, osr, uartclk, baud_raw;
cr = lpuart32_read(sport->port.membase + UARTCTRL);
cr &= UARTCTRL_TE | UARTCTRL_RE;
@@ -1762,12 +2060,13 @@ lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
bd = lpuart32_read(sport->port.membase + UARTBAUD);
bd &= UARTBAUD_SBR_MASK;
sbr = bd;
- uartclk = clk_get_rate(sport->clk);
- /*
- * baud = mod_clk/(16*(sbr[13]+(brfa)/32)
- */
- baud_raw = uartclk / (16 * sbr);
+ osr = (bd >> UARTBAUD_OSR_SHIFT) & UARTBAUD_OSR_MASK;
+ if (sport->per_clk)
+ uartclk = clk_get_rate(sport->per_clk);
+ else
+ uartclk = clk_get_rate(sport->ipg_clk);
+ baud_raw = uartclk / ((osr + 1) * sbr);
if (*baud != baud_raw)
printk(KERN_INFO "Serial: Console lpuart rounded baud rate"
"from %d to %d\n", baud_raw, *baud);
@@ -1830,21 +2129,24 @@ static struct console lpuart32_console = {
.data = &lpuart_reg,
};
-static void lpuart_early_write(struct console *con, const char *s, unsigned n)
+static void
+lpuart_early_write(struct console *con, const char *s, unsigned int n)
{
struct earlycon_device *dev = con->data;
uart_console_write(&dev->port, s, n, lpuart_console_putchar);
}
-static void lpuart32_early_write(struct console *con, const char *s, unsigned n)
+static void
+lpuart32_early_write(struct console *con, const char *s, unsigned int n)
{
struct earlycon_device *dev = con->data;
uart_console_write(&dev->port, s, n, lpuart32_console_putchar);
}
-static int __init lpuart_early_console_setup(struct earlycon_device *device,
+static int __init
+lpuart_early_console_setup(struct earlycon_device *device,
const char *opt)
{
if (!device->port.membase)
@@ -1854,8 +2156,8 @@ static int __init lpuart_early_console_setup(struct earlycon_device *device,
return 0;
}
-static int __init lpuart32_early_console_setup(struct earlycon_device *device,
- const char *opt)
+static int __init
+lpuart32_early_console_setup(struct earlycon_device *device, const char *opt)
{
if (!device->port.membase)
return -ENODEV;
@@ -1864,8 +2166,12 @@ static int __init lpuart32_early_console_setup(struct earlycon_device *device,
return 0;
}
-OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup);
-OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup);
+OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart",
+ lpuart_early_console_setup);
+OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart",
+ lpuart32_early_console_setup);
+OF_EARLYCON_DECLARE(lpuart32, "fsl,imx7ulp-lpuart",
+ lpuart32_early_console_setup);
EARLYCON_DECLARE(lpuart, lpuart_early_console_setup);
EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup);
@@ -1895,8 +2201,6 @@ static int lpuart_probe(struct platform_device *pdev)
if (!sport)
return -ENOMEM;
- pdev->dev.coherent_dma_mask = 0;
-
ret = of_alias_get_id(np, "serial");
if (ret < 0) {
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
@@ -1907,7 +2211,10 @@ static int lpuart_probe(struct platform_device *pdev)
return -EINVAL;
}
sport->port.line = ret;
- sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart");
+ sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart") |
+ of_device_is_compatible(np, "fsl,imx7ulp-lpuart") |
+ of_device_is_compatible(np, "fsl,imx8qm-lpuart");
+ sport->dma_eeop = of_device_is_compatible(np, "fsl,imx8qm-lpuart");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sport->port.membase = devm_ioremap_resource(&pdev->dev, res);
@@ -1931,55 +2238,86 @@ static int lpuart_probe(struct platform_device *pdev)
sport->port.ops = &lpuart_pops;
sport->port.flags = UPF_BOOT_AUTOCONF;
- sport->port.rs485_config = lpuart_config_rs485;
+ if (!sport->lpuart32)
+ sport->port.rs485_config = lpuart_config_rs485;
- sport->clk = devm_clk_get(&pdev->dev, "ipg");
- if (IS_ERR(sport->clk)) {
- ret = PTR_ERR(sport->clk);
- dev_err(&pdev->dev, "failed to get uart clk: %d\n", ret);
+ sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
+ if (IS_ERR(sport->ipg_clk)) {
+ ret = PTR_ERR(sport->ipg_clk);
+ dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret);
return ret;
}
+ sport->per_clk = devm_clk_get(&pdev->dev, "per");
+ if (IS_ERR(sport->per_clk))
+ sport->per_clk = NULL;
- ret = clk_prepare_enable(sport->clk);
+ ret = clk_prepare_enable(sport->ipg_clk);
if (ret) {
+ dev_err(&pdev->dev, "failed to enable uart ipg clk: %d\n", ret);
+ return ret;
+ }
+ ret = clk_prepare_enable(sport->per_clk);
+ if (ret) {
+ clk_disable_unprepare(sport->ipg_clk);
dev_err(&pdev->dev, "failed to enable uart clk: %d\n", ret);
return ret;
}
-
- sport->port.uartclk = clk_get_rate(sport->clk);
+ if (sport->per_clk)
+ sport->port.uartclk = clk_get_rate(sport->per_clk);
+ else
+ sport->port.uartclk = clk_get_rate(sport->ipg_clk);
lpuart_ports[sport->port.line] = sport;
platform_set_drvdata(pdev, &sport->port);
- if (sport->lpuart32)
+ if (sport->lpuart32) {
lpuart_reg.cons = LPUART32_CONSOLE;
- else
+ ret = devm_request_irq(&pdev->dev, sport->port.irq, lpuart32_int, 0,
+ DRIVER_NAME, sport);
+ } else {
lpuart_reg.cons = LPUART_CONSOLE;
+ ret = devm_request_irq(&pdev->dev, sport->port.irq, lpuart_int, 0,
+ DRIVER_NAME, sport);
+ }
+
+ if (ret)
+ goto failed_irq_request;
+
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
ret = uart_add_one_port(&lpuart_reg, &sport->port);
- if (ret) {
- clk_disable_unprepare(sport->clk);
- return ret;
- }
+ if (ret)
+ goto failed_attach_port;
sport->dma_tx_chan = dma_request_slave_channel(sport->port.dev, "tx");
if (!sport->dma_tx_chan)
- dev_info(sport->port.dev, "DMA tx channel request failed, "
- "operating without tx DMA\n");
+ dev_info(sport->port.dev, "NO DMA tx channel, run at cpu mode\n");
sport->dma_rx_chan = dma_request_slave_channel(sport->port.dev, "rx");
if (!sport->dma_rx_chan)
- dev_info(sport->port.dev, "DMA rx channel request failed, "
- "operating without rx DMA\n");
+ dev_info(sport->port.dev, "NO DMA rx channel, run at cpu mode\n");
- if (of_property_read_bool(np, "linux,rs485-enabled-at-boot-time")) {
+ if (!sport->lpuart32 &&
+ of_property_read_bool(np, "linux,rs485-enabled-at-boot-time")) {
sport->port.rs485.flags |= SER_RS485_ENABLED;
sport->port.rs485.flags |= SER_RS485_RTS_ON_SEND;
writeb(UARTMODEM_TXRTSE, sport->port.membase + UARTMODEM);
}
return 0;
+
+failed_attach_port:
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+failed_irq_request:
+ clk_disable_unprepare(sport->per_clk);
+ clk_disable_unprepare(sport->ipg_clk);
+ return ret;
}
static int lpuart_remove(struct platform_device *pdev)
@@ -1988,114 +2326,371 @@ static int lpuart_remove(struct platform_device *pdev)
uart_remove_one_port(&lpuart_reg, &sport->port);
- clk_disable_unprepare(sport->clk);
-
if (sport->dma_tx_chan)
dma_release_channel(sport->dma_tx_chan);
if (sport->dma_rx_chan)
dma_release_channel(sport->dma_rx_chan);
+ clk_disable_unprepare(sport->per_clk);
+ clk_disable_unprepare(sport->ipg_clk);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
-static int lpuart_suspend(struct device *dev)
+static int lpuart_runtime_suspend(struct device *dev)
{
- struct lpuart_port *sport = dev_get_drvdata(dev);
- unsigned long temp;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct lpuart_port *sport = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(sport->per_clk);
+ clk_disable_unprepare(sport->ipg_clk);
+
+ return 0;
+};
+
+static int lpuart_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct lpuart_port *sport = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = clk_prepare_enable(sport->ipg_clk);
+ if (ret)
+ return ret;
+ ret = clk_prepare_enable(sport->per_clk);
+ if (ret) {
+ clk_disable_unprepare(sport->ipg_clk);
+ return ret;
+ }
+
+ return 0;
+};
+
+static void serial_lpuart_enable_wakeup(struct lpuart_port *sport, bool on)
+{
+ unsigned int val;
if (sport->lpuart32) {
- /* disable Rx/Tx and interrupts */
- temp = lpuart32_read(sport->port.membase + UARTCTRL);
- temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
- lpuart32_write(temp, sport->port.membase + UARTCTRL);
+ val = lpuart32_read(sport->port.membase + UARTCTRL);
+ if (on)
+ val |= (UARTCTRL_RIE | UARTCTRL_ILIE);
+ else
+ val &= ~(UARTCTRL_RIE | UARTCTRL_ILIE);
+ lpuart32_write(val, sport->port.membase + UARTCTRL);
} else {
- /* disable Rx/Tx and interrupts */
- temp = readb(sport->port.membase + UARTCR2);
- temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE);
- writeb(temp, sport->port.membase + UARTCR2);
+ val = readb(sport->port.membase + UARTCR2);
+ if (on)
+ val |= UARTCR2_RIE;
+ else
+ val &= ~UARTCR2_RIE;
+ writeb(val, sport->port.membase + UARTCR2);
+ }
+}
+
+static bool lpuart_uport_is_active(struct lpuart_port *sport)
+{
+ struct tty_port *port = &sport->port.state->port;
+ struct tty_struct *tty;
+ struct device *tty_dev;
+ int may_wake = 0;
+
+ tty = tty_port_tty_get(port);
+ if (tty) {
+ tty_dev = tty->dev;
+ may_wake = device_may_wakeup(tty_dev);
+ tty_kref_put(tty);
+ }
+
+ if ((tty_port_initialized(port) && may_wake) ||
+ (!console_suspend_enabled && uart_console(&sport->port)))
+ return true;
+
+ return false;
+}
+
+static int lpuart_suspend_noirq(struct device *dev)
+{
+ struct lpuart_port *sport = dev_get_drvdata(dev);
+
+ if (lpuart_uport_is_active(sport))
+ serial_lpuart_enable_wakeup(sport, !!sport->port.irq_wake);
+
+ pinctrl_pm_select_sleep_state(dev);
+
+ return 0;
+}
+
+static int lpuart_resume_noirq(struct device *dev)
+{
+ struct lpuart_port *sport = dev_get_drvdata(dev);
+ unsigned int val;
+
+ pinctrl_pm_select_default_state(dev);
+
+ if (lpuart_uport_is_active(sport)) {
+ serial_lpuart_enable_wakeup(sport, false);
+
+ /* clear the wakeup flags */
+ if (sport->lpuart32) {
+ val = lpuart32_read(sport->port.membase + UARTSTAT);
+ lpuart32_write(val, sport->port.membase + UARTSTAT);
+ }
}
+ return 0;
+}
+
+static int lpuart_suspend(struct device *dev)
+{
+ struct lpuart_port *sport = dev_get_drvdata(dev);
+ unsigned long temp;
+ unsigned long flags;
+
uart_suspend_port(&lpuart_reg, &sport->port);
- if (sport->lpuart_dma_rx_use) {
- /*
- * EDMA driver during suspend will forcefully release any
- * non-idle DMA channels. If port wakeup is enabled or if port
- * is console port or 'no_console_suspend' is set the Rx DMA
- * cannot resume as as expected, hence gracefully release the
- * Rx DMA path before suspend and start Rx DMA path on resume.
- */
- if (sport->port.irq_wake) {
- del_timer_sync(&sport->lpuart_timer);
+ if (lpuart_uport_is_active(sport)) {
+ spin_lock_irqsave(&sport->port.lock, flags);
+ if (sport->lpuart32) {
+ temp = lpuart32_read(sport->port.membase + UARTCTRL);
+ temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
+ lpuart32_write(temp, sport->port.membase + UARTCTRL);
+ } else {
+ temp = readb(sport->port.membase + UARTCR2);
+ temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE);
+ writeb(temp, sport->port.membase + UARTCR2);
+ }
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ if (sport->lpuart_dma_rx_use) {
+ spin_lock_irqsave(&sport->port.lock, flags);
+ lpuart_dma_stop(sport, false);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ dmaengine_terminate_all(sport->dma_rx_chan);
+ if (!sport->dma_eeop)
+ del_timer_sync(&sport->lpuart_timer);
lpuart_dma_rx_free(&sport->port);
}
- /* Disable Rx DMA to use UART port as wakeup source */
- writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_RDMAS,
- sport->port.membase + UARTCR5);
- }
+ if (sport->lpuart_dma_tx_use) {
+ spin_lock_irqsave(&sport->port.lock, flags);
+ if (sport->lpuart32) {
+ temp = lpuart32_read(sport->port.membase + UARTBAUD);
+ temp &= ~UARTBAUD_TDMAE;
+ lpuart32_write(temp, sport->port.membase + UARTBAUD);
+ } else {
+ temp = readb(sport->port.membase + UARTCR5);
+ temp &= ~UARTCR5_TDMAS;
+ writeb(temp, sport->port.membase + UARTCR5);
+ }
+ spin_unlock_irqrestore(&sport->port.lock, flags);
- if (sport->lpuart_dma_tx_use) {
- sport->dma_tx_in_progress = false;
- dmaengine_terminate_all(sport->dma_tx_chan);
+ sport->dma_tx_in_progress = false;
+ dmaengine_terminate_all(sport->dma_tx_chan);
+ }
+ } else if (pm_runtime_active(sport->port.dev)) {
+ clk_disable_unprepare(sport->per_clk);
+ clk_disable_unprepare(sport->ipg_clk);
+ pm_runtime_disable(sport->port.dev);
+ pm_runtime_set_suspended(sport->port.dev);
}
- if (sport->port.suspended && !sport->port.irq_wake)
- clk_disable_unprepare(sport->clk);
-
return 0;
}
-static int lpuart_resume(struct device *dev)
+static void lpuart_console_fixup(struct lpuart_port *sport)
+{
+ struct tty_port *port = &sport->port.state->port;
+ struct uart_port *uport = &sport->port;
+ struct device_node *np = sport->port.dev->of_node;
+ struct ktermios termios;
+
+ if (!sport->lpuart32 || !np)
+ return;
+
+ /* i.MX7ULP enter VLLS mode that lpuart module power off and registers
+ * all lost no matter the port is wakeup source.
+ * For console port, console baud rate setting lost and print messy
+ * log when enable the console port as wakeup source. To avoid the
+ * issue happen, user should not enable uart port as wakeup source
+ * in VLLS mode, or restore console setting here.
+ */
+ if (of_device_is_compatible(np, "fsl,imx7ulp-lpuart") &&
+ lpuart_uport_is_active(sport) && console_suspend_enabled &&
+ uart_console(&sport->port)) {
+
+ mutex_lock(&port->mutex);
+ memset(&termios, 0, sizeof(struct ktermios));
+ termios.c_cflag = uport->cons->cflag;
+ if (port->tty && termios.c_cflag == 0)
+ termios = port->tty->termios;
+ uport->ops->set_termios(uport, &termios, NULL);
+ mutex_unlock(&port->mutex);
+ }
+}
+
+static inline void lpuart32_resume_init(struct lpuart_port *sport)
{
- struct lpuart_port *sport = dev_get_drvdata(dev);
unsigned long temp;
+ unsigned long flags;
- if (sport->port.suspended && !sport->port.irq_wake)
- clk_prepare_enable(sport->clk);
+ spin_lock_irqsave(&sport->port.lock, flags);
+ lpuart32_setup_watermark(sport);
- if (sport->lpuart32) {
- lpuart32_setup_watermark(sport);
+ temp = lpuart32_read(sport->port.membase + UARTCTRL);
+ temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE |
+ UARTCTRL_TE | UARTCTRL_ILIE);
+
+ if (sport->dma_rx_chan)
+ temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE);
+
+ if (sport->dma_tx_chan)
+ temp &= ~(UARTCTRL_TIE | UARTCTRL_TE);
+
+ lpuart32_write(temp, sport->port.membase + UARTCTRL);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ if (sport->lpuart_dma_rx_use) {
+ if (!lpuart_dma_rx_request(&sport->port)) {
+ sport->lpuart_dma_rx_use = true;
+ if (!sport->dma_eeop)
+ setup_timer(&sport->lpuart_timer,
+ lpuart_timer_func,
+ (unsigned long)sport);
+ } else {
+ sport->lpuart_dma_rx_use = false;
+ }
+
+ spin_lock_irqsave(&sport->port.lock, flags);
temp = lpuart32_read(sport->port.membase + UARTCTRL);
- temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE |
- UARTCTRL_TE | UARTCTRL_ILIE);
+ temp |= (UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE);
+ temp |= UARTCTRL_IDLECFG << UARTCTRL_IDLECFG_OFF;
lpuart32_write(temp, sport->port.membase + UARTCTRL);
- } else {
- lpuart_setup_watermark(sport);
- temp = readb(sport->port.membase + UARTCR2);
- temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE);
- writeb(temp, sport->port.membase + UARTCR2);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+ }
+
+ if (sport->lpuart_dma_tx_use) {
+ if (!lpuart_dma_tx_request(&sport->port)) {
+ init_waitqueue_head(&sport->dma_wait);
+ spin_lock_irqsave(&sport->port.lock, flags);
+ temp = lpuart32_read(sport->port.membase + UARTBAUD);
+ temp |= UARTBAUD_TDMAE;
+ lpuart32_write(temp, sport->port.membase + UARTBAUD);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+ } else {
+ sport->lpuart_dma_tx_use = false;
+ }
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ temp = lpuart32_read(sport->port.membase + UARTCTRL);
+ temp |= UARTCTRL_TE;
+ lpuart32_write(temp, sport->port.membase + UARTCTRL);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
+}
+
+static inline void lpuart_resume_init(struct lpuart_port *sport)
+{
+ unsigned char temp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ lpuart_setup_watermark(sport);
+ temp = readb(sport->port.membase + UARTCR2);
+ temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE);
+
+ if (sport->dma_rx_chan)
+ temp &= ~(UARTCR2_RIE | UARTCR2_RE);
+
+ if (sport->dma_tx_chan)
+ temp &= ~(UARTCR2_TIE | UARTCR2_TE);
+
+ writeb(temp, sport->port.membase + UARTCR2);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
if (sport->lpuart_dma_rx_use) {
- if (sport->port.irq_wake) {
- if (!lpuart_start_rx_dma(sport)) {
- sport->lpuart_dma_rx_use = true;
- rx_dma_timer_init(sport);
- } else {
- sport->lpuart_dma_rx_use = false;
- }
+ if (!lpuart_dma_rx_request(&sport->port)) {
+ sport->lpuart_dma_rx_use = true;
+ setup_timer(&sport->lpuart_timer,
+ lpuart_timer_func,
+ (unsigned long)sport);
+ } else {
+ sport->lpuart_dma_rx_use = false;
}
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ temp = readb(sport->port.membase + UARTCR2);
+ temp |= (UARTCR2_RIE | UARTCR2_RE);
+ writeb(temp, sport->port.membase + UARTCR2);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
- if (sport->dma_tx_chan && !lpuart_dma_tx_request(&sport->port)) {
+ if (sport->lpuart_dma_tx_use) {
+ if (!lpuart_dma_tx_request(&sport->port)) {
init_waitqueue_head(&sport->dma_wait);
- sport->lpuart_dma_tx_use = true;
- writeb(readb(sport->port.membase + UARTCR5) |
- UARTCR5_TDMAS, sport->port.membase + UARTCR5);
- } else {
- sport->lpuart_dma_tx_use = false;
+ spin_lock_irqsave(&sport->port.lock, flags);
+ temp = readb(sport->port.membase + UARTCR5);
+ temp |= UARTCR5_TDMAS;
+ writeb(temp, sport->port.membase + UARTCR5);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+ } else {
+ sport->lpuart_dma_tx_use = false;
+ }
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ temp = readb(sport->port.membase + UARTCR2);
+ temp |= UARTCR2_TE;
+ writeb(temp, sport->port.membase + UARTCR2);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
+}
+
+static int lpuart_resume(struct device *dev)
+{
+ struct lpuart_port *sport = dev_get_drvdata(dev);
+ int ret;
+ if (lpuart_uport_is_active(sport)) {
+ if (sport->lpuart32)
+ lpuart32_resume_init(sport);
+ else
+ lpuart_resume_init(sport);
+ } else if (pm_runtime_active(sport->port.dev)) {
+ ret = clk_prepare_enable(sport->ipg_clk);
+ if (ret)
+ return ret;
+ ret = clk_prepare_enable(sport->per_clk);
+ if (ret) {
+ clk_disable_unprepare(sport->ipg_clk);
+ return ret;
+ }
+ pm_runtime_set_active(sport->port.dev);
+ pm_runtime_enable(sport->port.dev);
+ }
+
+ lpuart_console_fixup(sport);
uart_resume_port(&lpuart_reg, &sport->port);
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(lpuart_pm_ops, lpuart_suspend, lpuart_resume);
+static const struct dev_pm_ops lpuart_pm_ops = {
+ SET_RUNTIME_PM_OPS(lpuart_runtime_suspend,
+ lpuart_runtime_resume, NULL)
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(lpuart_suspend_noirq,
+ lpuart_resume_noirq)
+ SET_SYSTEM_SLEEP_PM_OPS(lpuart_suspend, lpuart_resume)
+};
+#define SERIAL_LPUART_PM_OPS (&lpuart_pm_ops)
+
+#else /* !CONFIG_PM_SLEEP */
+
+#define SERIAL_LPUART_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
static struct platform_driver lpuart_driver = {
.probe = lpuart_probe,
@@ -2103,7 +2698,7 @@ static struct platform_driver lpuart_driver = {
.driver = {
.name = "fsl-lpuart",
.of_match_table = lpuart_dt_ids,
- .pm = &lpuart_pm_ops,
+ .pm = SERIAL_LPUART_PM_OPS,
},
};
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index b24edf634985..b6e390e56f28 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -34,6 +34,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/rational.h>
+#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -41,6 +42,7 @@
#include <linux/dma-mapping.h>
#include <asm/irq.h>
+#include <linux/busfreq-imx.h>
#include <linux/platform_data/serial-imx.h>
#include <linux/platform_data/dma-imx.h>
@@ -185,6 +187,8 @@
#define DRIVER_NAME "IMX-uart"
#define UART_NR 8
+#define IMX_RXBD_NUM 20
+#define IMX_MODULE_MAX_CLK_RATE 80000000
/* i.MX21 type uart runs on all i.mx except i.MX1 and i.MX6q */
enum imx_uart_type {
@@ -200,6 +204,24 @@ struct imx_uart_data {
enum imx_uart_type devtype;
};
+struct imx_dma_bufinfo {
+ bool filled;
+ unsigned int rx_bytes;
+};
+
+struct imx_dma_rxbuf {
+ unsigned int periods;
+ unsigned int period_len;
+ unsigned int buf_len;
+
+ void *buf;
+ dma_addr_t dmaaddr;
+ unsigned int cur_idx;
+ unsigned int last_completed_idx;
+ dma_cookie_t cookie;
+ struct imx_dma_bufinfo buf_info[IMX_RXBD_NUM];
+};
+
struct imx_port {
struct uart_port port;
struct timer_list timer;
@@ -221,16 +243,16 @@ struct imx_port {
unsigned int dma_is_rxing:1;
unsigned int dma_is_txing:1;
struct dma_chan *dma_chan_rx, *dma_chan_tx;
- struct scatterlist rx_sgl, tx_sgl[2];
- void *rx_buf;
- struct circ_buf rx_ring;
- unsigned int rx_periods;
- dma_cookie_t rx_cookie;
+ struct scatterlist tx_sgl[2];
+ struct imx_dma_rxbuf rx_buf;
unsigned int tx_bytes;
unsigned int dma_tx_nents;
+ struct work_struct tsk_dma_tx;
wait_queue_head_t dma_wait;
unsigned int saved_reg[10];
bool context_saved;
+#define DMA_TX_IS_WORKING 1
+ unsigned long flags;
};
struct imx_port_ucrs {
@@ -405,12 +427,14 @@ static void imx_stop_rx(struct uart_port *port)
}
}
- temp = readl(sport->port.membase + UCR2);
- writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2);
-
- /* disable the `Receiver Ready Interrrupt` */
+ /* disable the Receiver Ready and overrun Interrrupt */
temp = readl(sport->port.membase + UCR1);
writel(temp & ~UCR1_RRDYEN, sport->port.membase + UCR1);
+ temp = readl(sport->port.membase + UCR4);
+ writel(temp & ~UCR4_OREN, sport->port.membase + UCR4);
+
+ temp = readl(sport->port.membase + UCR2);
+ writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2);
}
/*
@@ -425,7 +449,6 @@ static void imx_enable_ms(struct uart_port *port)
mctrl_gpio_enable_ms(sport->gpios);
}
-static void imx_dma_tx(struct imx_port *sport);
static inline void imx_transmit_buffer(struct imx_port *sport)
{
struct circ_buf *xmit = &sport->port.state->xmit;
@@ -456,7 +479,7 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
writel(temp, sport->port.membase + UCR1);
} else {
writel(temp, sport->port.membase + UCR1);
- imx_dma_tx(sport);
+ schedule_work(&sport->tsk_dma_tx);
}
}
@@ -482,95 +505,99 @@ static void dma_tx_callback(void *data)
struct scatterlist *sgl = &sport->tx_sgl[0];
struct circ_buf *xmit = &sport->port.state->xmit;
unsigned long flags;
- unsigned long temp;
+ /* update the stat */
spin_lock_irqsave(&sport->port.lock, flags);
+ /* user call .flush() before the code slice coming */
+ if (!sport->dma_is_txing) {
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+ return;
+ }
+ sport->dma_is_txing = 0;
- dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
-
- temp = readl(sport->port.membase + UCR1);
- temp &= ~UCR1_TDMAEN;
- writel(temp, sport->port.membase + UCR1);
-
- /* update the stat */
xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1);
sport->port.icount.tx += sport->tx_bytes;
+ spin_unlock_irqrestore(&sport->port.lock, flags);
- dev_dbg(sport->port.dev, "we finish the TX DMA.\n");
+ dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
- sport->dma_is_txing = 0;
+ dev_dbg(sport->port.dev, "we finish the TX DMA.\n");
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ clear_bit(DMA_TX_IS_WORKING, &sport->flags);
+ smp_mb__after_atomic();
+ uart_write_wakeup(&sport->port);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(&sport->port);
+ if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port))
+ schedule_work(&sport->tsk_dma_tx);
if (waitqueue_active(&sport->dma_wait)) {
wake_up(&sport->dma_wait);
dev_dbg(sport->port.dev, "exit in %s.\n", __func__);
return;
}
-
- spin_lock_irqsave(&sport->port.lock, flags);
- if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port))
- imx_dma_tx(sport);
- spin_unlock_irqrestore(&sport->port.lock, flags);
}
-static void imx_dma_tx(struct imx_port *sport)
+static void dma_tx_work(struct work_struct *w)
{
+ struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_tx);
struct circ_buf *xmit = &sport->port.state->xmit;
struct scatterlist *sgl = sport->tx_sgl;
struct dma_async_tx_descriptor *desc;
struct dma_chan *chan = sport->dma_chan_tx;
struct device *dev = sport->port.dev;
+ unsigned long flags;
unsigned long temp;
int ret;
- if (sport->dma_is_txing)
+ if (test_and_set_bit(DMA_TX_IS_WORKING, &sport->flags))
return;
+ spin_lock_irqsave(&sport->port.lock, flags);
sport->tx_bytes = uart_circ_chars_pending(xmit);
- if (xmit->tail < xmit->head) {
- sport->dma_tx_nents = 1;
- sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
- } else {
- sport->dma_tx_nents = 2;
- sg_init_table(sgl, 2);
- sg_set_buf(sgl, xmit->buf + xmit->tail,
- UART_XMIT_SIZE - xmit->tail);
- sg_set_buf(sgl + 1, xmit->buf, xmit->head);
- }
-
- ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
- if (ret == 0) {
- dev_err(dev, "DMA mapping error for TX.\n");
- return;
- }
- desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents,
- DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
- if (!desc) {
- dma_unmap_sg(dev, sgl, sport->dma_tx_nents,
- DMA_TO_DEVICE);
- dev_err(dev, "We cannot prepare for the TX slave dma!\n");
- return;
- }
- desc->callback = dma_tx_callback;
- desc->callback_param = sport;
+ if (sport->tx_bytes > 0) {
+ if (xmit->tail > xmit->head && xmit->head > 0) {
+ sport->dma_tx_nents = 2;
+ sg_init_table(sgl, 2);
+ sg_set_buf(sgl, xmit->buf + xmit->tail,
+ UART_XMIT_SIZE - xmit->tail);
+ sg_set_buf(sgl + 1, xmit->buf, xmit->head);
+ } else {
+ sport->dma_tx_nents = 1;
+ sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
+ }
+ spin_unlock_irqrestore(&sport->port.lock, flags);
- dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n",
- uart_circ_chars_pending(xmit));
+ ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
+ if (ret == 0) {
+ dev_err(dev, "DMA mapping error for TX.\n");
+ goto err_out;
+ }
+ desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents,
+ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
+ if (!desc) {
+ dev_err(dev, "We cannot prepare for the TX slave dma!\n");
+ goto err_out;
+ }
+ desc->callback = dma_tx_callback;
+ desc->callback_param = sport;
- temp = readl(sport->port.membase + UCR1);
- temp |= UCR1_TDMAEN;
- writel(temp, sport->port.membase + UCR1);
+ dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n",
+ uart_circ_chars_pending(xmit));
+ /* fire it */
+ sport->dma_is_txing = 1;
+ dmaengine_submit(desc);
+ dma_async_issue_pending(chan);
- /* fire it */
- sport->dma_is_txing = 1;
- dmaengine_submit(desc);
- dma_async_issue_pending(chan);
- return;
+ temp = readl(sport->port.membase + UCR1);
+ temp |= UCR1_TDMAEN;
+ writel(temp, sport->port.membase + UCR1);
+ return;
+ }
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+err_out:
+ clear_bit(DMA_TX_IS_WORKING, &sport->flags);
+ smp_mb__after_atomic();
}
/*
@@ -615,7 +642,7 @@ static void imx_start_tx(struct uart_port *port)
if (!uart_circ_empty(&port->state->xmit) &&
!uart_tx_stopped(port))
- imx_dma_tx(sport);
+ schedule_work(&sport->tsk_dma_tx);
return;
}
}
@@ -718,56 +745,22 @@ out:
return IRQ_HANDLED;
}
-static void clear_rx_errors(struct imx_port *sport);
-static int start_rx_dma(struct imx_port *sport);
-/*
- * If the RXFIFO is filled with some data, and then we
- * arise a DMA operation to receive them.
- */
-static void imx_dma_rxint(struct imx_port *sport)
-{
- unsigned long temp;
- unsigned long flags;
-
- spin_lock_irqsave(&sport->port.lock, flags);
-
- temp = readl(sport->port.membase + USR2);
- if ((temp & USR2_RDR) && !sport->dma_is_rxing) {
- sport->dma_is_rxing = 1;
-
- /* disable the receiver ready and aging timer interrupts */
- temp = readl(sport->port.membase + UCR1);
- temp &= ~(UCR1_RRDYEN);
- writel(temp, sport->port.membase + UCR1);
-
- temp = readl(sport->port.membase + UCR2);
- temp &= ~(UCR2_ATEN);
- writel(temp, sport->port.membase + UCR2);
-
- /* disable the rx errors interrupts */
- temp = readl(sport->port.membase + UCR4);
- temp &= ~UCR4_OREN;
- writel(temp, sport->port.membase + UCR4);
-
- /* tell the DMA to receive the data. */
- start_rx_dma(sport);
- }
-
- spin_unlock_irqrestore(&sport->port.lock, flags);
-}
-
/*
* We have a modem side uart, so the meanings of RTS and CTS are inverted.
*/
static unsigned int imx_get_hwmctrl(struct imx_port *sport)
{
- unsigned int tmp = TIOCM_DSR;
- unsigned usr1 = readl(sport->port.membase + USR1);
- unsigned usr2 = readl(sport->port.membase + USR2);
+ unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
+ unsigned int usr1 = readl(sport->port.membase + USR1);
+ unsigned int usr2 = readl(sport->port.membase + USR2);
+ unsigned int ucr2 = readl(sport->port.membase + UCR2);
if (usr1 & USR1_RTSS)
tmp |= TIOCM_CTS;
+ if (ucr2 & UCR2_CTS)
+ tmp |= TIOCM_RTS;
+
/* in DCE mode DCDIN is always 0 */
if (!(usr2 & USR2_DCDIN))
tmp |= TIOCM_CAR;
@@ -776,6 +769,9 @@ static unsigned int imx_get_hwmctrl(struct imx_port *sport)
if (!(readl(sport->port.membase + USR2) & USR2_RIIN))
tmp |= TIOCM_RI;
+ if (readl(sport->port.membase + uts_reg(sport)) & UTS_LOOP)
+ tmp |= TIOCM_LOOP;
+
return tmp;
}
@@ -811,26 +807,22 @@ static irqreturn_t imx_int(int irq, void *dev_id)
struct imx_port *sport = dev_id;
unsigned int sts;
unsigned int sts2;
- irqreturn_t ret = IRQ_NONE;
sts = readl(sport->port.membase + USR1);
sts2 = readl(sport->port.membase + USR2);
- if (sts & (USR1_RRDY | USR1_AGTIM)) {
- if (sport->dma_is_enabled)
- imx_dma_rxint(sport);
- else
- imx_rxint(irq, dev_id);
- ret = IRQ_HANDLED;
+ if ((sts & USR1_RRDY || sts & USR1_AGTIM) &&
+ !sport->dma_is_enabled) {
+ if (sts & USR1_AGTIM)
+ writel(USR1_AGTIM, sport->port.membase + USR1);
+ imx_rxint(irq, dev_id);
}
if ((sts & USR1_TRDY &&
readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) ||
(sts2 & USR2_TXDC &&
- readl(sport->port.membase + UCR4) & UCR4_TCEN)) {
+ readl(sport->port.membase + UCR4) & UCR4_TCEN))
imx_txint(irq, dev_id);
- ret = IRQ_HANDLED;
- }
if (sts & USR1_DTRD) {
unsigned long flags;
@@ -841,27 +833,20 @@ static irqreturn_t imx_int(int irq, void *dev_id)
spin_lock_irqsave(&sport->port.lock, flags);
imx_mctrl_check(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
-
- ret = IRQ_HANDLED;
}
- if (sts & USR1_RTSD) {
+ if (sts & USR1_RTSD)
imx_rtsint(irq, dev_id);
- ret = IRQ_HANDLED;
- }
- if (sts & USR1_AWAKE) {
+ if (sts & USR1_AWAKE)
writel(USR1_AWAKE, sport->port.membase + USR1);
- ret = IRQ_HANDLED;
- }
if (sts2 & USR2_ORE) {
sport->port.icount.overrun++;
writel(USR2_ORE, sport->port.membase + USR2);
- ret = IRQ_HANDLED;
}
- return ret;
+ return IRQ_HANDLED;
}
/*
@@ -881,6 +866,9 @@ static unsigned int imx_tx_empty(struct uart_port *port)
return ret;
}
+/*
+ * We have a modem side uart, so the meanings of RTS and CTS are inverted.
+ */
static unsigned int imx_get_mctrl(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
@@ -937,6 +925,97 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
spin_unlock_irqrestore(&sport->port.lock, flags);
}
+#define TXTL 2 /* reset default */
+#define RXTL 1 /* For console port */
+#define RXTL_UART 16 /* For uart */
+
+static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
+{
+ unsigned int val;
+ unsigned int rx_fifo_trig;
+
+ if (uart_console(&sport->port))
+ rx_fifo_trig = RXTL;
+ else
+ rx_fifo_trig = RXTL_UART;
+
+ /* set receiver / transmitter trigger level */
+ val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
+ val |= TXTL << UFCR_TXTL_SHF | rx_fifo_trig;
+ writel(val, sport->port.membase + UFCR);
+ return 0;
+}
+
+#define RX_BUF_SIZE (PAGE_SIZE)
+static void dma_rx_push_data(struct imx_port *sport, struct tty_struct *tty,
+ unsigned int start, unsigned int end)
+{
+ unsigned int i;
+ struct tty_port *port = &sport->port.state->port;
+
+ for (i = start; i < end; i++) {
+ if (sport->rx_buf.buf_info[i].filled) {
+ tty_insert_flip_string(port, sport->rx_buf.buf + (i
+ * RX_BUF_SIZE), sport->rx_buf.buf_info[i].rx_bytes);
+ tty_flip_buffer_push(port);
+ sport->rx_buf.buf_info[i].filled = false;
+ sport->rx_buf.last_completed_idx++;
+ sport->rx_buf.last_completed_idx %= IMX_RXBD_NUM;
+ sport->port.icount.rx += sport->rx_buf.buf_info[i].rx_bytes;
+ }
+ }
+}
+
+static void dma_rx_work(struct imx_port *sport)
+{
+ struct tty_struct *tty = sport->port.state->port.tty;
+ unsigned int cur_idx = sport->rx_buf.cur_idx;
+
+ if (sport->rx_buf.last_completed_idx < cur_idx) {
+ dma_rx_push_data(sport, tty, sport->rx_buf.last_completed_idx + 1, cur_idx);
+ } else if (sport->rx_buf.last_completed_idx == (IMX_RXBD_NUM - 1)) {
+ dma_rx_push_data(sport, tty, 0, cur_idx);
+ } else {
+ dma_rx_push_data(sport, tty, sport->rx_buf.last_completed_idx + 1,
+ IMX_RXBD_NUM);
+ dma_rx_push_data(sport, tty, 0, cur_idx);
+ }
+}
+
+static void imx_rx_dma_done(struct imx_port *sport)
+{
+ sport->dma_is_rxing = 0;
+
+ /* Is the shutdown waiting for us? */
+ if (waitqueue_active(&sport->dma_wait))
+ wake_up(&sport->dma_wait);
+}
+
+static void clear_rx_errors(struct imx_port *sport)
+{
+ unsigned int status_usr1, status_usr2;
+
+ status_usr1 = readl(sport->port.membase + USR1);
+ status_usr2 = readl(sport->port.membase + USR2);
+
+ if (status_usr2 & USR2_BRCD) {
+ sport->port.icount.brk++;
+ writel(USR2_BRCD, sport->port.membase + USR2);
+ } else if (status_usr1 & USR1_FRAMERR) {
+ sport->port.icount.frame++;
+ writel(USR1_FRAMERR, sport->port.membase + USR1);
+ } else if (status_usr1 & USR1_PARITYERR) {
+ sport->port.icount.parity++;
+ writel(USR1_PARITYERR, sport->port.membase + USR1);
+ }
+
+ if (status_usr2 & USR2_ORE) {
+ sport->port.icount.overrun++;
+ writel(USR2_ORE, sport->port.membase + USR2);
+ }
+
+}
+
/*
* This is our per-port timeout handler, for checking the
* modem status signals.
@@ -955,188 +1034,103 @@ static void imx_timeout(unsigned long data)
}
}
-#define RX_BUF_SIZE (PAGE_SIZE)
-
/*
- * There are two kinds of RX DMA interrupts(such as in the MX6Q):
+ * There are three kinds of RX DMA interrupts(such as in the MX6Q):
* [1] the RX DMA buffer is full.
- * [2] the aging timer expires
+ * [2] the Aging timer expires(wait for 8 bytes long)
+ * [3] the Idle Condition Detect(enabled the UCR4_IDDMAEN).
*
- * Condition [2] is triggered when a character has been sitting in the FIFO
- * for at least 8 byte durations.
+ * The [2] is trigger when a character was been sitting in the FIFO
+ * meanwhile [3] can wait for 32 bytes long when the RX line is
+ * on IDLE state and RxFIFO is empty.
*/
static void dma_rx_callback(void *data)
{
struct imx_port *sport = data;
struct dma_chan *chan = sport->dma_chan_rx;
- struct scatterlist *sgl = &sport->rx_sgl;
- struct tty_port *port = &sport->port.state->port;
+ struct tty_struct *tty = sport->port.state->port.tty;
struct dma_tx_state state;
- struct circ_buf *rx_ring = &sport->rx_ring;
enum dma_status status;
- unsigned int w_bytes = 0;
- unsigned int r_bytes;
- unsigned int bd_size;
+ unsigned int count;
- status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state);
+ /* If we have finish the reading. we will not accept any more data. */
+ if (tty->closing) {
+ imx_rx_dma_done(sport);
+ return;
+ }
+ status = dmaengine_tx_status(chan, sport->rx_buf.cookie, &state);
if (status == DMA_ERROR) {
dev_err(sport->port.dev, "DMA transaction error.\n");
clear_rx_errors(sport);
return;
}
- if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) {
-
- /*
- * The state-residue variable represents the empty space
- * relative to the entire buffer. Taking this in consideration
- * the head is always calculated base on the buffer total
- * length - DMA transaction residue. The UART script from the
- * SDMA firmware will jump to the next buffer descriptor,
- * once a DMA transaction if finalized (IMX53 RM - A.4.1.2.4).
- * Taking this in consideration the tail is always at the
- * beginning of the buffer descriptor that contains the head.
- */
-
- /* Calculate the head */
- rx_ring->head = sg_dma_len(sgl) - state.residue;
-
- /* Calculate the tail. */
- bd_size = sg_dma_len(sgl) / sport->rx_periods;
- rx_ring->tail = ((rx_ring->head-1) / bd_size) * bd_size;
-
- if (rx_ring->head <= sg_dma_len(sgl) &&
- rx_ring->head > rx_ring->tail) {
+ count = RX_BUF_SIZE - state.residue;
+ sport->rx_buf.buf_info[sport->rx_buf.cur_idx].filled = true;
+ sport->rx_buf.buf_info[sport->rx_buf.cur_idx].rx_bytes = count;
+ sport->rx_buf.cur_idx++;
+ sport->rx_buf.cur_idx %= IMX_RXBD_NUM;
+ dev_dbg(sport->port.dev, "We get %d bytes.\n", count);
- /* Move data from tail to head */
- r_bytes = rx_ring->head - rx_ring->tail;
+ if (sport->rx_buf.cur_idx == sport->rx_buf.last_completed_idx)
+ dev_err(sport->port.dev, "overwrite!\n");
- /* CPU claims ownership of RX DMA buffer */
- dma_sync_sg_for_cpu(sport->port.dev, sgl, 1,
- DMA_FROM_DEVICE);
-
- w_bytes = tty_insert_flip_string(port,
- sport->rx_buf + rx_ring->tail, r_bytes);
-
- /* UART retrieves ownership of RX DMA buffer */
- dma_sync_sg_for_device(sport->port.dev, sgl, 1,
- DMA_FROM_DEVICE);
-
- if (w_bytes != r_bytes)
- sport->port.icount.buf_overrun++;
-
- sport->port.icount.rx += w_bytes;
- } else {
- WARN_ON(rx_ring->head > sg_dma_len(sgl));
- WARN_ON(rx_ring->head <= rx_ring->tail);
- }
- }
-
- if (w_bytes) {
- tty_flip_buffer_push(port);
- dev_dbg(sport->port.dev, "We get %d bytes.\n", w_bytes);
- }
+ if (count)
+ dma_rx_work(sport);
}
-/* RX DMA buffer periods */
-#define RX_DMA_PERIODS 4
-
static int start_rx_dma(struct imx_port *sport)
{
- struct scatterlist *sgl = &sport->rx_sgl;
struct dma_chan *chan = sport->dma_chan_rx;
- struct device *dev = sport->port.dev;
struct dma_async_tx_descriptor *desc;
- int ret;
-
- sport->rx_ring.head = 0;
- sport->rx_ring.tail = 0;
- sport->rx_periods = RX_DMA_PERIODS;
- sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE);
- ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE);
- if (ret == 0) {
- dev_err(dev, "DMA mapping error for RX.\n");
- return -EINVAL;
- }
-
- desc = dmaengine_prep_dma_cyclic(chan, sg_dma_address(sgl),
- sg_dma_len(sgl), sg_dma_len(sgl) / sport->rx_periods,
+ sport->rx_buf.periods = IMX_RXBD_NUM;
+ sport->rx_buf.period_len = RX_BUF_SIZE;
+ sport->rx_buf.buf_len = IMX_RXBD_NUM * RX_BUF_SIZE;
+ sport->rx_buf.cur_idx = 0;
+ sport->rx_buf.last_completed_idx = -1;
+ desc = dmaengine_prep_dma_cyclic(chan, sport->rx_buf.dmaaddr,
+ sport->rx_buf.buf_len, sport->rx_buf.period_len,
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
-
if (!desc) {
- dma_unmap_sg(dev, sgl, 1, DMA_FROM_DEVICE);
- dev_err(dev, "We cannot prepare for the RX slave dma!\n");
+ dev_err(sport->port.dev, "Prepare for the RX slave dma failed!\n");
return -EINVAL;
}
+
desc->callback = dma_rx_callback;
desc->callback_param = sport;
- dev_dbg(dev, "RX: prepare for the DMA.\n");
- sport->rx_cookie = dmaengine_submit(desc);
+ dev_dbg(sport->port.dev, "RX: prepare for the DMA.\n");
+ sport->rx_buf.cookie = dmaengine_submit(desc);
dma_async_issue_pending(chan);
- return 0;
-}
-
-static void clear_rx_errors(struct imx_port *sport)
-{
- unsigned int status_usr1, status_usr2;
-
- status_usr1 = readl(sport->port.membase + USR1);
- status_usr2 = readl(sport->port.membase + USR2);
-
- if (status_usr2 & USR2_BRCD) {
- sport->port.icount.brk++;
- writel(USR2_BRCD, sport->port.membase + USR2);
- } else if (status_usr1 & USR1_FRAMERR) {
- sport->port.icount.frame++;
- writel(USR1_FRAMERR, sport->port.membase + USR1);
- } else if (status_usr1 & USR1_PARITYERR) {
- sport->port.icount.parity++;
- writel(USR1_PARITYERR, sport->port.membase + USR1);
- }
-
- if (status_usr2 & USR2_ORE) {
- sport->port.icount.overrun++;
- writel(USR2_ORE, sport->port.membase + USR2);
- }
-
-}
-
-#define TXTL_DEFAULT 2 /* reset default */
-#define RXTL_DEFAULT 1 /* reset default */
-#define TXTL_DMA 8 /* DMA burst setting */
-#define RXTL_DMA 9 /* DMA burst setting */
-static void imx_setup_ufcr(struct imx_port *sport,
- unsigned char txwl, unsigned char rxwl)
-{
- unsigned int val;
-
- /* set receiver / transmitter trigger level */
- val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
- val |= txwl << UFCR_TXTL_SHF | rxwl;
- writel(val, sport->port.membase + UFCR);
+ sport->dma_is_rxing = 1;
+ return 0;
}
static void imx_uart_dma_exit(struct imx_port *sport)
{
if (sport->dma_chan_rx) {
- dmaengine_terminate_sync(sport->dma_chan_rx);
dma_release_channel(sport->dma_chan_rx);
sport->dma_chan_rx = NULL;
- sport->rx_cookie = -EINVAL;
- kfree(sport->rx_buf);
- sport->rx_buf = NULL;
+
+ if (sport->rx_buf.buf) {
+ dma_free_coherent(sport->port.dev, IMX_RXBD_NUM * RX_BUF_SIZE,
+ (void *)sport->rx_buf.buf,
+ sport->rx_buf.dmaaddr);
+ sport->rx_buf.buf = NULL;
+ }
}
if (sport->dma_chan_tx) {
- dmaengine_terminate_sync(sport->dma_chan_tx);
dma_release_channel(sport->dma_chan_tx);
sport->dma_chan_tx = NULL;
}
+ if (sport->dma_is_inited)
+ release_bus_freq(BUS_FREQ_HIGH);
+
sport->dma_is_inited = 0;
}
@@ -1144,7 +1138,7 @@ static int imx_uart_dma_init(struct imx_port *sport)
{
struct dma_slave_config slave_config = {};
struct device *dev = sport->port.dev;
- int ret;
+ int ret, i;
/* Prepare for RX : */
sport->dma_chan_rx = dma_request_slave_channel(dev, "rx");
@@ -1157,20 +1151,25 @@ static int imx_uart_dma_init(struct imx_port *sport)
slave_config.direction = DMA_DEV_TO_MEM;
slave_config.src_addr = sport->port.mapbase + URXD0;
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- /* one byte less than the watermark level to enable the aging timer */
- slave_config.src_maxburst = RXTL_DMA - 1;
+ slave_config.src_maxburst = RXTL_UART;
ret = dmaengine_slave_config(sport->dma_chan_rx, &slave_config);
if (ret) {
dev_err(dev, "error in RX dma configuration.\n");
goto err;
}
- sport->rx_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
- if (!sport->rx_buf) {
+ sport->rx_buf.buf = dma_alloc_coherent(sport->port.dev, IMX_RXBD_NUM * RX_BUF_SIZE,
+ &sport->rx_buf.dmaaddr, GFP_KERNEL);
+ if (!sport->rx_buf.buf) {
+ dev_err(dev, "cannot alloc DMA buffer.\n");
ret = -ENOMEM;
goto err;
}
- sport->rx_ring.buf = sport->rx_buf;
+
+ for (i = 0; i < IMX_RXBD_NUM; i++) {
+ sport->rx_buf.buf_info[i].rx_bytes = 0;
+ sport->rx_buf.buf_info[i].filled = false;
+ }
/* Prepare for TX : */
sport->dma_chan_tx = dma_request_slave_channel(dev, "tx");
@@ -1183,7 +1182,7 @@ static int imx_uart_dma_init(struct imx_port *sport)
slave_config.direction = DMA_MEM_TO_DEV;
slave_config.dst_addr = sport->port.mapbase + URTX0;
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- slave_config.dst_maxburst = TXTL_DMA;
+ slave_config.dst_maxburst = TXTL;
ret = dmaengine_slave_config(sport->dma_chan_tx, &slave_config);
if (ret) {
dev_err(dev, "error in TX dma configuration.");
@@ -1191,6 +1190,7 @@ static int imx_uart_dma_init(struct imx_port *sport)
}
sport->dma_is_inited = 1;
+ request_bus_freq(BUS_FREQ_HIGH);
return 0;
err:
@@ -1203,17 +1203,19 @@ static void imx_enable_dma(struct imx_port *sport)
unsigned long temp;
init_waitqueue_head(&sport->dma_wait);
+ sport->flags = 0;
/* set UCR1 */
temp = readl(sport->port.membase + UCR1);
- temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN;
+ temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN |
+ /* wait for 32 idle frames for IDDMA interrupt */
+ UCR1_ICD_REG(3);
writel(temp, sport->port.membase + UCR1);
- temp = readl(sport->port.membase + UCR2);
- temp |= UCR2_ATEN;
- writel(temp, sport->port.membase + UCR2);
-
- imx_setup_ufcr(sport, TXTL_DMA, RXTL_DMA);
+ /* set UCR4 */
+ temp = readl(sport->port.membase + UCR4);
+ temp |= UCR4_IDDMAEN;
+ writel(temp, sport->port.membase + UCR4);
sport->dma_is_enabled = 1;
}
@@ -1229,10 +1231,13 @@ static void imx_disable_dma(struct imx_port *sport)
/* clear UCR2 */
temp = readl(sport->port.membase + UCR2);
- temp &= ~(UCR2_CTSC | UCR2_CTS | UCR2_ATEN);
+ temp &= ~(UCR2_CTSC | UCR2_CTS);
writel(temp, sport->port.membase + UCR2);
- imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ /* clear UCR4 */
+ temp = readl(sport->port.membase + UCR4);
+ temp &= ~UCR4_IDDMAEN;
+ writel(temp, sport->port.membase + UCR4);
sport->dma_is_enabled = 0;
}
@@ -1243,9 +1248,17 @@ static void imx_disable_dma(struct imx_port *sport)
static int imx_startup(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
+ struct tty_port *tty_port = &sport->port.state->port;
int retval, i;
unsigned long flags, temp;
+ /* some modem may need reset */
+ if (!tty_port_suspended(tty_port)) {
+ retval = device_reset(sport->port.dev);
+ if (retval && retval != -ENOENT)
+ return retval;
+ }
+
retval = clk_prepare_enable(sport->clk_per);
if (retval)
return retval;
@@ -1255,7 +1268,7 @@ static int imx_startup(struct uart_port *port)
return retval;
}
- imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_setup_ufcr(sport, 0);
/* disable the DREN bit (Data Ready interrupt enable) before
* requesting IRQs
@@ -1268,11 +1281,6 @@ static int imx_startup(struct uart_port *port)
writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
- /* Can we enable the DMA support? */
- if (!uart_console(port) && !sport->dma_is_inited)
- imx_uart_dma_init(sport);
-
- spin_lock_irqsave(&sport->port.lock, flags);
/* Reset fifo's and state machines */
i = 100;
@@ -1283,18 +1291,28 @@ static int imx_startup(struct uart_port *port)
while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
udelay(1);
+ /* Can we enable the DMA support? */
+ if (is_imx6q_uart(sport) && !uart_console(port)
+ && !sport->dma_is_inited)
+ imx_uart_dma_init(sport);
+
+ if (sport->dma_is_inited)
+ INIT_WORK(&sport->tsk_dma_tx, dma_tx_work);
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
/*
* Finally, clear and enable interrupts
*/
- writel(USR1_RTSD | USR1_DTRD, sport->port.membase + USR1);
+ writel(USR1_RTSD, sport->port.membase + USR1);
writel(USR2_ORE, sport->port.membase + USR2);
- if (sport->dma_is_inited && !sport->dma_is_enabled)
- imx_enable_dma(sport);
-
temp = readl(sport->port.membase + UCR1);
- temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
-
+ if (!sport->dma_is_inited)
+ temp |= UCR1_RRDYEN;
+ if (sport->have_rtscts)
+ temp |= UCR1_RTSDEN;
+ temp |= UCR1_UARTEN;
writel(temp, sport->port.membase + UCR1);
temp = readl(sport->port.membase + UCR4);
@@ -1341,10 +1359,20 @@ static void imx_shutdown(struct uart_port *port)
unsigned long flags;
if (sport->dma_is_enabled) {
- sport->dma_is_rxing = 0;
- sport->dma_is_txing = 0;
- dmaengine_terminate_sync(sport->dma_chan_tx);
- dmaengine_terminate_sync(sport->dma_chan_rx);
+ int ret;
+
+ /* We have to wait for the DMA to finish. */
+ ret = wait_event_interruptible_timeout(sport->dma_wait,
+ !sport->dma_is_rxing && !sport->dma_is_txing,
+ msecs_to_jiffies(1));
+ if (ret <= 0) {
+ sport->dma_is_rxing = 0;
+ sport->dma_is_txing = 0;
+ dmaengine_terminate_all(sport->dma_chan_tx);
+ dmaengine_terminate_all(sport->dma_chan_rx);
+ }
+
+ cancel_work_sync(&sport->tsk_dma_tx);
spin_lock_irqsave(&sport->port.lock, flags);
imx_stop_tx(port);
@@ -1400,7 +1428,9 @@ static void imx_flush_buffer(struct uart_port *port)
temp = readl(sport->port.membase + UCR1);
temp &= ~UCR1_TDMAEN;
writel(temp, sport->port.membase + UCR1);
- sport->dma_is_txing = false;
+ sport->dma_is_txing = 0;
+ clear_bit(DMA_TX_IS_WORKING, &sport->flags);
+ smp_mb__after_atomic();
}
/*
@@ -1433,10 +1463,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
{
struct imx_port *sport = (struct imx_port *)port;
unsigned long flags;
- unsigned long ucr2, old_ucr1, old_ucr2;
- unsigned int baud, quot;
+ unsigned long ucr2, old_ucr1, old_txrxen, baud, quot;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
- unsigned long div, ufcr;
+ unsigned int div, ufcr;
unsigned long num, denom;
uint64_t tdiv64;
@@ -1484,7 +1513,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
imx_port_rts_active(sport, &ucr2);
}
-
if (termios->c_cflag & CSTOPB)
ucr2 |= UCR2_STPB;
if (termios->c_cflag & PARENB) {
@@ -1544,10 +1572,10 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
barrier();
/* then, disable everything */
- old_ucr2 = readl(sport->port.membase + UCR2);
- writel(old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN),
+ old_txrxen = readl(sport->port.membase + UCR2);
+ writel(old_txrxen & ~(UCR2_TXEN | UCR2_RXEN),
sport->port.membase + UCR2);
- old_ucr2 &= (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN);
+ old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
/* custom-baudrate handling */
div = sport->port.uartclk / (baud * 16);
@@ -1586,11 +1614,21 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
writel(old_ucr1, sport->port.membase + UCR1);
/* set the parity, stop bits and data size */
- writel(ucr2 | old_ucr2, sport->port.membase + UCR2);
+ writel(ucr2 | old_txrxen, sport->port.membase + UCR2);
if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
imx_enable_ms(&sport->port);
+ if (sport->dma_is_inited && !sport->dma_is_enabled) {
+ imx_enable_dma(sport);
+ start_rx_dma(sport);
+ }
+
+ if (!sport->dma_is_enabled) {
+ ucr2 = readl(sport->port.membase + UCR2);
+ writel(ucr2 | UCR2_ATEN, sport->port.membase + UCR2);
+ }
+
spin_unlock_irqrestore(&sport->port.lock, flags);
}
@@ -1656,7 +1694,7 @@ static int imx_poll_init(struct uart_port *port)
if (retval)
clk_disable_unprepare(sport->clk_ipg);
- imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_setup_ufcr(sport, 0);
spin_lock_irqsave(&sport->port.lock, flags);
@@ -1931,7 +1969,7 @@ imx_console_setup(struct console *co, char *options)
else
imx_console_get_options(sport, &baud, &parity, &bits);
- imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_setup_ufcr(sport, 0);
retval = uart_set_options(&sport->port, co, baud, parity, bits, flow);
@@ -2130,6 +2168,14 @@ static int serial_imx_probe(struct platform_device *pdev)
}
sport->port.uartclk = clk_get_rate(sport->clk_per);
+ if (sport->port.uartclk > IMX_MODULE_MAX_CLK_RATE) {
+ ret = clk_set_rate(sport->clk_per, IMX_MODULE_MAX_CLK_RATE);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "clk_set_rate() failed\n");
+ return ret;
+ }
+ }
+ sport->port.uartclk = clk_get_rate(sport->clk_per);
/* For register access, we only need to enable the ipg clock. */
ret = clk_prepare_enable(sport->clk_ipg);
@@ -2222,9 +2268,12 @@ static int serial_imx_remove(struct platform_device *pdev)
static void serial_imx_restore_context(struct imx_port *sport)
{
+ unsigned long flags = 0;
+
if (!sport->context_saved)
return;
+ spin_lock_irqsave(&sport->port.lock, flags);
writel(sport->saved_reg[4], sport->port.membase + UFCR);
writel(sport->saved_reg[5], sport->port.membase + UESC);
writel(sport->saved_reg[6], sport->port.membase + UTIM);
@@ -2236,11 +2285,15 @@ static void serial_imx_restore_context(struct imx_port *sport)
writel(sport->saved_reg[2], sport->port.membase + UCR3);
writel(sport->saved_reg[3], sport->port.membase + UCR4);
sport->context_saved = false;
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
static void serial_imx_save_context(struct imx_port *sport)
{
+ unsigned long flags = 0;
+
/* Save necessary regs */
+ spin_lock_irqsave(&sport->port.lock, flags);
sport->saved_reg[0] = readl(sport->port.membase + UCR1);
sport->saved_reg[1] = readl(sport->port.membase + UCR2);
sport->saved_reg[2] = readl(sport->port.membase + UCR3);
@@ -2252,12 +2305,20 @@ static void serial_imx_save_context(struct imx_port *sport)
sport->saved_reg[8] = readl(sport->port.membase + UBMR);
sport->saved_reg[9] = readl(sport->port.membase + IMX21_UTS);
sport->context_saved = true;
+
+ if (uart_console(&sport->port) && sport->port.sysrq)
+ sport->saved_reg[0] |= UCR1_RRDYEN;
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
static void serial_imx_enable_wakeup(struct imx_port *sport, bool on)
{
unsigned int val;
+ val = readl(sport->port.membase + USR1);
+ if (val & (USR1_AWAKE | USR1_RTSD))
+ writel(USR1_AWAKE | USR1_RTSD, sport->port.membase + USR1);
+
val = readl(sport->port.membase + UCR3);
if (on)
val |= UCR3_AWAKEN;
@@ -2285,10 +2346,15 @@ static int imx_serial_port_suspend_noirq(struct device *dev)
if (ret)
return ret;
+ /* enable wakeup from i.MX UART */
+ serial_imx_enable_wakeup(sport, true);
+
serial_imx_save_context(sport);
clk_disable(sport->clk_ipg);
+ pinctrl_pm_select_sleep_state(dev);
+
return 0;
}
@@ -2298,12 +2364,17 @@ static int imx_serial_port_resume_noirq(struct device *dev)
struct imx_port *sport = platform_get_drvdata(pdev);
int ret;
+ pinctrl_pm_select_default_state(dev);
+
ret = clk_enable(sport->clk_ipg);
if (ret)
return ret;
serial_imx_restore_context(sport);
+ /* disable wakeup from i.MX UART */
+ serial_imx_enable_wakeup(sport, false);
+
clk_disable(sport->clk_ipg);
return 0;
@@ -2314,9 +2385,6 @@ static int imx_serial_port_suspend(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
- /* enable wakeup from i.MX UART */
- serial_imx_enable_wakeup(sport, true);
-
uart_suspend_port(&imx_reg, &sport->port);
/* Needed to enable clock in suspend_noirq */
@@ -2328,9 +2396,6 @@ static int imx_serial_port_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct imx_port *sport = platform_get_drvdata(pdev);
- /* disable wakeup from i.MX UART */
- serial_imx_enable_wakeup(sport, false);
-
uart_resume_port(&imx_reg, &sport->port);
clk_unprepare(sport->clk_ipg);
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 0103f777b97a..c055561e84aa 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -113,6 +113,8 @@ source "drivers/usb/chipidea/Kconfig"
source "drivers/usb/isp1760/Kconfig"
+source "drivers/usb/cdns3/Kconfig"
+
comment "USB port drivers"
if USB
@@ -158,6 +160,8 @@ source "drivers/usb/phy/Kconfig"
source "drivers/usb/gadget/Kconfig"
+source "drivers/usb/typec/Kconfig"
+
config USB_LED_TRIG
bool "USB LED Triggers"
depends on LEDS_CLASS && LEDS_TRIGGERS
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index dca78565eb55..cbdfe47f011c 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_USB_SUPPORT) += phy/
obj-$(CONFIG_USB_DWC3) += dwc3/
obj-$(CONFIG_USB_DWC2) += dwc2/
obj-$(CONFIG_USB_ISP1760) += isp1760/
+obj-$(CONFIG_USB_CDNS3) += cdns3/
obj-$(CONFIG_USB_MON) += mon/
@@ -61,3 +62,5 @@ obj-$(CONFIG_USB_GADGET) += gadget/
obj-$(CONFIG_USB_COMMON) += common/
obj-$(CONFIG_USBIP_CORE) += usbip/
+
+obj-$(CONFIG_TYPEC) += typec/
diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig
new file mode 100644
index 000000000000..165afdb99d15
--- /dev/null
+++ b/drivers/usb/cdns3/Kconfig
@@ -0,0 +1,26 @@
+config USB_CDNS3
+ tristate "Cadence USB3 Dual-Role Controller"
+ depends on ((USB_XHCI_HCD && USB_GADGET) || (USB_XHCI_HCD && !USB_GADGET) || (!USB_XHCI_HCD && USB_GADGET)) && HAS_DMA
+ select EXTCON
+ help
+ Say Y here if your system has a cadence USB3 dual-role controller.
+ It supports: dual-role switch Host-only, and Peripheral-only.
+
+ When compiled dynamically, the module will be called cdns3.ko.
+
+if USB_CDNS3
+
+config USB_CDNS3_GADGET
+ bool "Cadence USB3 device controller"
+ depends on USB_GADGET
+ help
+ Say Y here to enable device controller functionality of the
+ cadence usb3 driver.
+
+config USB_CDNS3_HOST
+ bool "Cadence USB3 host controller"
+ depends on USB_XHCI_HCD
+ help
+ Say Y here to enable host controller functionality of the
+ cadence usb3 driver.
+endif
diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile
new file mode 100644
index 000000000000..7328cb9fcc89
--- /dev/null
+++ b/drivers/usb/cdns3/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_USB_CDNS3) += cdns3.o
+
+cdns3-y := core.o
+cdns3-$(CONFIG_USB_CDNS3_GADGET) += gadget.o
+cdns3-$(CONFIG_USB_CDNS3_HOST) += host.o
diff --git a/drivers/usb/cdns3/cdns3-nxp-reg-def.h b/drivers/usb/cdns3/cdns3-nxp-reg-def.h
new file mode 100644
index 000000000000..886632265e98
--- /dev/null
+++ b/drivers/usb/cdns3/cdns3-nxp-reg-def.h
@@ -0,0 +1,172 @@
+/**
+ * cdns3-nxp-reg-def.h - nxp wrap layer register definition
+ *
+ * Copyright 2017 NXP
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __DRIVERS_USB_CDNS3_NXP_H
+#define __DRIVERS_USB_CDNS3_NXP_H
+
+#define USB3_CORE_CTRL1 0x00
+#define USB3_CORE_CTRL2 0x04
+#define USB3_INT_REG 0x08
+#define USB3_CORE_STATUS 0x0c
+#define XHCI_DEBUG_LINK_ST 0x10
+#define XHCI_DEBUG_BUS 0x14
+#define USB3_SSPHY_CTRL1 0x40
+#define USB3_SSPHY_CTRL2 0x44
+#define USB3_SSPHY_STATUS 0x4c
+#define USB2_PHY_CTRL1 0x50
+#define USB2_PHY_CTRL2 0x54
+#define USB2_PHY_STATUS 0x5c
+
+/* Register bits definition */
+
+/* USB3_CORE_CTRL1 */
+#define SW_RESET_MASK (0x3f << 26)
+#define PWR_SW_RESET (1 << 31)
+#define APB_SW_RESET (1 << 30)
+#define AXI_SW_RESET (1 << 29)
+#define RW_SW_RESET (1 << 28)
+#define PHY_SW_RESET (1 << 27)
+#define PHYAHB_SW_RESET (1 << 26)
+#define ALL_SW_RESET (PWR_SW_RESET | APB_SW_RESET | AXI_SW_RESET | \
+ RW_SW_RESET | PHY_SW_RESET | PHYAHB_SW_RESET)
+#define OC_DISABLE (1 << 9)
+#define MDCTRL_CLK_SEL (1 << 7)
+#define MODE_STRAP_MASK (0x7)
+#define DEV_MODE (1 << 2)
+#define HOST_MODE (1 << 1)
+#define OTG_MODE (1 << 0)
+
+/* USB3_INT_REG */
+#define CLK_125_REQ (1 << 29)
+#define LPM_CLK_REQ (1 << 28)
+#define DEVU3_WAEKUP_EN (1 << 14)
+#define OTG_WAKEUP_EN (1 << 12)
+#define DEV_INT_EN (3 << 8) /* DEV INT b9:8 */
+#define HOST_INT1_EN (1 << 0) /* HOST INT b7:0 */
+
+/* USB3_CORE_STATUS */
+#define MDCTRL_CLK_STATUS (1 << 15)
+#define DEV_POWER_ON_READY (1 << 13)
+#define HOST_POWER_ON_READY (1 << 12)
+
+/* USB3_SSPHY_STATUS */
+#define PHY_REFCLK_REQ (1 << 0)
+
+
+/* PHY register definition */
+#define PHY_PMA_CMN_CTRL1 (0xC800 * 4)
+#define TB_ADDR_CMN_DIAG_HSCLK_SEL (0x01e0 * 4)
+#define TB_ADDR_CMN_PLL0_VCOCAL_INIT_TMR (0x0084 * 4)
+#define TB_ADDR_CMN_PLL0_VCOCAL_ITER_TMR (0x0085 * 4)
+#define TB_ADDR_CMN_PLL0_INTDIV (0x0094 * 4)
+#define TB_ADDR_CMN_PLL0_FRACDIV (0x0095 * 4)
+#define TB_ADDR_CMN_PLL0_HIGH_THR (0x0096 * 4)
+#define TB_ADDR_CMN_PLL0_SS_CTRL1 (0x0098 * 4)
+#define TB_ADDR_CMN_PLL0_SS_CTRL2 (0x0099 * 4)
+#define TB_ADDR_CMN_PLL0_DSM_DIAG (0x0097 * 4)
+#define TB_ADDR_CMN_DIAG_PLL0_OVRD (0x01c2 * 4)
+#define TB_ADDR_CMN_DIAG_PLL0_FBH_OVRD (0x01c0 * 4)
+#define TB_ADDR_CMN_DIAG_PLL0_FBL_OVRD (0x01c1 * 4)
+#define TB_ADDR_CMN_DIAG_PLL0_V2I_TUNE (0x01C5 * 4)
+#define TB_ADDR_CMN_DIAG_PLL0_CP_TUNE (0x01C6 * 4)
+#define TB_ADDR_CMN_DIAG_PLL0_LF_PROG (0x01C7 * 4)
+#define TB_ADDR_CMN_DIAG_PLL0_TEST_MODE (0x01c4 * 4)
+#define TB_ADDR_CMN_PSM_CLK_CTRL (0x0061 * 4)
+#define TB_ADDR_XCVR_DIAG_RX_LANE_CAL_RST_TMR (0x40ea * 4)
+#define TB_ADDR_XCVR_PSM_RCTRL (0x4001 * 4)
+#define TB_ADDR_TX_PSC_A0 (0x4100 * 4)
+#define TB_ADDR_TX_PSC_A1 (0x4101 * 4)
+#define TB_ADDR_TX_PSC_A2 (0x4102 * 4)
+#define TB_ADDR_TX_PSC_A3 (0x4103 * 4)
+#define TB_ADDR_TX_DIAG_ECTRL_OVRD (0x41f5 * 4)
+#define TB_ADDR_TX_PSC_CAL (0x4106 * 4)
+#define TB_ADDR_TX_PSC_RDY (0x4107 * 4)
+#define TB_ADDR_RX_PSC_A0 (0x8000 * 4)
+#define TB_ADDR_RX_PSC_A1 (0x8001 * 4)
+#define TB_ADDR_RX_PSC_A2 (0x8002 * 4)
+#define TB_ADDR_RX_PSC_A3 (0x8003 * 4)
+#define TB_ADDR_RX_PSC_CAL (0x8006 * 4)
+#define TB_ADDR_RX_PSC_RDY (0x8007 * 4)
+#define TB_ADDR_TX_TXCC_MGNLS_MULT_000 (0x4058 * 4)
+#define TB_ADDR_TX_DIAG_BGREF_PREDRV_DELAY (0x41e7 * 4)
+#define TB_ADDR_RX_SLC_CU_ITER_TMR (0x80e3 * 4)
+#define TB_ADDR_RX_SIGDET_HL_FILT_TMR (0x8090 * 4)
+#define TB_ADDR_RX_SAMP_DAC_CTRL (0x8058 * 4)
+#define TB_ADDR_RX_DIAG_SIGDET_TUNE (0x81dc * 4)
+#define TB_ADDR_RX_DIAG_LFPSDET_TUNE2 (0x81df * 4)
+#define TB_ADDR_RX_DIAG_BS_TM (0x81f5 * 4)
+#define TB_ADDR_RX_DIAG_DFE_CTRL1 (0x81d3 * 4)
+#define TB_ADDR_RX_DIAG_ILL_IQE_TRIM4 (0x81c7 * 4)
+#define TB_ADDR_RX_DIAG_ILL_E_TRIM0 (0x81c2 * 4)
+#define TB_ADDR_RX_DIAG_ILL_IQ_TRIM0 (0x81c1 * 4)
+#define TB_ADDR_RX_DIAG_ILL_IQE_TRIM6 (0x81c9 * 4)
+#define TB_ADDR_RX_DIAG_RXFE_TM3 (0x81f8 * 4)
+#define TB_ADDR_RX_DIAG_RXFE_TM4 (0x81f9 * 4)
+#define TB_ADDR_RX_DIAG_LFPSDET_TUNE (0x81dd * 4)
+#define TB_ADDR_RX_DIAG_DFE_CTRL3 (0x81d5 * 4)
+#define TB_ADDR_RX_DIAG_SC2C_DELAY (0x81e1 * 4)
+#define TB_ADDR_RX_REE_VGA_GAIN_NODFE (0x81bf * 4)
+#define TB_ADDR_XCVR_PSM_CAL_TMR (0x4002 * 4)
+#define TB_ADDR_XCVR_PSM_A0BYP_TMR (0x4004 * 4)
+#define TB_ADDR_XCVR_PSM_A0IN_TMR (0x4003 * 4)
+#define TB_ADDR_XCVR_PSM_A1IN_TMR (0x4005 * 4)
+#define TB_ADDR_XCVR_PSM_A2IN_TMR (0x4006 * 4)
+#define TB_ADDR_XCVR_PSM_A3IN_TMR (0x4007 * 4)
+#define TB_ADDR_XCVR_PSM_A4IN_TMR (0x4008 * 4)
+#define TB_ADDR_XCVR_PSM_A5IN_TMR (0x4009 * 4)
+#define TB_ADDR_XCVR_PSM_A0OUT_TMR (0x400a * 4)
+#define TB_ADDR_XCVR_PSM_A1OUT_TMR (0x400b * 4)
+#define TB_ADDR_XCVR_PSM_A2OUT_TMR (0x400c * 4)
+#define TB_ADDR_XCVR_PSM_A3OUT_TMR (0x400d * 4)
+#define TB_ADDR_XCVR_PSM_A4OUT_TMR (0x400e * 4)
+#define TB_ADDR_XCVR_PSM_A5OUT_TMR (0x400f * 4)
+#define TB_ADDR_TX_RCVDET_EN_TMR (0x4122 * 4)
+#define TB_ADDR_TX_RCVDET_ST_TMR (0x4123 * 4)
+#define TB_ADDR_XCVR_DIAG_LANE_FCM_EN_MGN_TMR (0x40f2 * 4)
+#define TB_ADDR_TX_RCVDETSC_CTRL (0x4124 * 4)
+
+/* Register bits definition */
+
+/* TB_ADDR_TX_RCVDETSC_CTRL */
+#define RXDET_IN_P3_32KHZ (1 << 0)
+
+/* OTG registers definition */
+#define OTGSTS 0x4
+#define OTGREFCLK 0xc
+
+/* Register bits definition */
+/* OTGSTS */
+#define OTG_NRDY (1 << 11)
+/* OTGREFCLK */
+#define OTG_STB_CLK_SWITCH_EN (1 << 31)
+
+/* xHCI registers definition */
+#define XECP_PORT_CAP_REG 0x8000
+#define XECP_PM_PMCSR 0x8018
+#define XECP_AUX_CTRL_REG1 0x8120
+
+/* Register bits definition */
+/* XECP_PORT_CAP_REG */
+#define LPM_2_STB_SWITCH_EN (1 << 25)
+
+/* XECP_AUX_CTRL_REG1 */
+#define CFG_RXDET_P3_EN (1 << 15)
+
+/* XECP_PM_PMCSR */
+#define PS_D0 (1 << 0)
+#endif /* __DRIVERS_USB_CDNS3_NXP_H */
diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c
new file mode 100644
index 000000000000..df68728f1de3
--- /dev/null
+++ b/drivers/usb/cdns3/core.c
@@ -0,0 +1,1014 @@
+/**
+ * core.c - Cadence USB3 DRD Controller Core file
+ *
+ * Copyright 2017 NXP
+ *
+ * Authors: Peter Chen <peter.chen@nxp.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/usb/of.h>
+#include <linux/usb/phy.h>
+#include <linux/extcon.h>
+#include <linux/pm_runtime.h>
+
+#include "cdns3-nxp-reg-def.h"
+#include "core.h"
+#include "host-export.h"
+#include "gadget-export.h"
+
+static void cdns3_usb_phy_init(void __iomem *regs)
+{
+ u32 value;
+
+ pr_debug("begin of %s\n", __func__);
+
+ writel(0x0830, regs + PHY_PMA_CMN_CTRL1);
+ writel(0x10, regs + TB_ADDR_CMN_DIAG_HSCLK_SEL);
+ writel(0x00F0, regs + TB_ADDR_CMN_PLL0_VCOCAL_INIT_TMR);
+ writel(0x0018, regs + TB_ADDR_CMN_PLL0_VCOCAL_ITER_TMR);
+ writel(0x00D0, regs + TB_ADDR_CMN_PLL0_INTDIV);
+ writel(0x4aaa, regs + TB_ADDR_CMN_PLL0_FRACDIV);
+ writel(0x0034, regs + TB_ADDR_CMN_PLL0_HIGH_THR);
+ writel(0x1ee, regs + TB_ADDR_CMN_PLL0_SS_CTRL1);
+ writel(0x7F03, regs + TB_ADDR_CMN_PLL0_SS_CTRL2);
+ writel(0x0020, regs + TB_ADDR_CMN_PLL0_DSM_DIAG);
+ writel(0x0000, regs + TB_ADDR_CMN_DIAG_PLL0_OVRD);
+ writel(0x0000, regs + TB_ADDR_CMN_DIAG_PLL0_FBH_OVRD);
+ writel(0x0000, regs + TB_ADDR_CMN_DIAG_PLL0_FBL_OVRD);
+ writel(0x0007, regs + TB_ADDR_CMN_DIAG_PLL0_V2I_TUNE);
+ writel(0x0027, regs + TB_ADDR_CMN_DIAG_PLL0_CP_TUNE);
+ writel(0x0008, regs + TB_ADDR_CMN_DIAG_PLL0_LF_PROG);
+ writel(0x0022, regs + TB_ADDR_CMN_DIAG_PLL0_TEST_MODE);
+ writel(0x000a, regs + TB_ADDR_CMN_PSM_CLK_CTRL);
+ writel(0x139, regs + TB_ADDR_XCVR_DIAG_RX_LANE_CAL_RST_TMR);
+ writel(0xbefc, regs + TB_ADDR_XCVR_PSM_RCTRL);
+
+ writel(0x7799, regs + TB_ADDR_TX_PSC_A0);
+ writel(0x7798, regs + TB_ADDR_TX_PSC_A1);
+ writel(0x509b, regs + TB_ADDR_TX_PSC_A2);
+ writel(0x3, regs + TB_ADDR_TX_DIAG_ECTRL_OVRD);
+ writel(0x509b, regs + TB_ADDR_TX_PSC_A3);
+ writel(0x2090, regs + TB_ADDR_TX_PSC_CAL);
+ writel(0x2090, regs + TB_ADDR_TX_PSC_RDY);
+
+ writel(0xA6FD, regs + TB_ADDR_RX_PSC_A0);
+ writel(0xA6FD, regs + TB_ADDR_RX_PSC_A1);
+ writel(0xA410, regs + TB_ADDR_RX_PSC_A2);
+ writel(0x2410, regs + TB_ADDR_RX_PSC_A3);
+
+ writel(0x23FF, regs + TB_ADDR_RX_PSC_CAL);
+ writel(0x2010, regs + TB_ADDR_RX_PSC_RDY);
+
+ writel(0x0020, regs + TB_ADDR_TX_TXCC_MGNLS_MULT_000);
+ writel(0x00ff, regs + TB_ADDR_TX_DIAG_BGREF_PREDRV_DELAY);
+ writel(0x0002, regs + TB_ADDR_RX_SLC_CU_ITER_TMR);
+ writel(0x0013, regs + TB_ADDR_RX_SIGDET_HL_FILT_TMR);
+ writel(0x0000, regs + TB_ADDR_RX_SAMP_DAC_CTRL);
+ writel(0x1004, regs + TB_ADDR_RX_DIAG_SIGDET_TUNE);
+ writel(0x4041, regs + TB_ADDR_RX_DIAG_LFPSDET_TUNE2);
+ writel(0x0480, regs + TB_ADDR_RX_DIAG_BS_TM);
+ writel(0x8006, regs + TB_ADDR_RX_DIAG_DFE_CTRL1);
+ writel(0x003f, regs + TB_ADDR_RX_DIAG_ILL_IQE_TRIM4);
+ writel(0x543f, regs + TB_ADDR_RX_DIAG_ILL_E_TRIM0);
+ writel(0x543f, regs + TB_ADDR_RX_DIAG_ILL_IQ_TRIM0);
+ writel(0x0000, regs + TB_ADDR_RX_DIAG_ILL_IQE_TRIM6);
+ writel(0x8000, regs + TB_ADDR_RX_DIAG_RXFE_TM3);
+ writel(0x0003, regs + TB_ADDR_RX_DIAG_RXFE_TM4);
+ writel(0x2408, regs + TB_ADDR_RX_DIAG_LFPSDET_TUNE);
+ writel(0x05ca, regs + TB_ADDR_RX_DIAG_DFE_CTRL3);
+ writel(0x0258, regs + TB_ADDR_RX_DIAG_SC2C_DELAY);
+ writel(0x1fff, regs + TB_ADDR_RX_REE_VGA_GAIN_NODFE);
+
+ writel(0x02c6, regs + TB_ADDR_XCVR_PSM_CAL_TMR);
+ writel(0x0002, regs + TB_ADDR_XCVR_PSM_A0BYP_TMR);
+ writel(0x02c6, regs + TB_ADDR_XCVR_PSM_A0IN_TMR);
+ writel(0x0010, regs + TB_ADDR_XCVR_PSM_A1IN_TMR);
+ writel(0x0010, regs + TB_ADDR_XCVR_PSM_A2IN_TMR);
+ writel(0x0010, regs + TB_ADDR_XCVR_PSM_A3IN_TMR);
+ writel(0x0010, regs + TB_ADDR_XCVR_PSM_A4IN_TMR);
+ writel(0x0010, regs + TB_ADDR_XCVR_PSM_A5IN_TMR);
+
+ writel(0x0002, regs + TB_ADDR_XCVR_PSM_A0OUT_TMR);
+ writel(0x0002, regs + TB_ADDR_XCVR_PSM_A1OUT_TMR);
+ writel(0x0002, regs + TB_ADDR_XCVR_PSM_A2OUT_TMR);
+ writel(0x0002, regs + TB_ADDR_XCVR_PSM_A3OUT_TMR);
+ writel(0x0002, regs + TB_ADDR_XCVR_PSM_A4OUT_TMR);
+ writel(0x0002, regs + TB_ADDR_XCVR_PSM_A5OUT_TMR);
+
+ /* Change rx detect parameter */
+ writel(0x960, regs + TB_ADDR_TX_RCVDET_EN_TMR);
+ writel(0x01e0, regs + TB_ADDR_TX_RCVDET_ST_TMR);
+ writel(0x0090, regs + TB_ADDR_XCVR_DIAG_LANE_FCM_EN_MGN_TMR);
+
+ /* RXDET_IN_P3_32KHZ, Receiver detect slow clock enable */
+ value = readl(regs + TB_ADDR_TX_RCVDETSC_CTRL);
+ value |= RXDET_IN_P3_32KHZ;
+ writel(value, regs + TB_ADDR_TX_RCVDETSC_CTRL);
+
+ udelay(10);
+
+ pr_debug("end of %s\n", __func__);
+}
+
+static void cdns_set_role(struct cdns3 *cdns, enum cdns3_roles role)
+{
+ u32 value;
+ int timeout_us = 100000;
+
+ if (role == CDNS3_ROLE_END)
+ return;
+
+ /* Wait clk value */
+ value = readl(cdns->none_core_regs + USB3_SSPHY_STATUS);
+ writel(value, cdns->none_core_regs + USB3_SSPHY_STATUS);
+ udelay(1);
+ value = readl(cdns->none_core_regs + USB3_SSPHY_STATUS);
+ while ((value & 0xf0000000) != 0xf0000000 && timeout_us-- > 0) {
+ value = readl(cdns->none_core_regs + USB3_SSPHY_STATUS);
+ dev_dbg(cdns->dev, "clkvld:0x%x\n", value);
+ udelay(1);
+ }
+
+ if (timeout_us <= 0)
+ dev_err(cdns->dev, "wait clkvld timeout\n");
+
+ /* Set all Reset bits */
+ value = readl(cdns->none_core_regs + USB3_CORE_CTRL1);
+ value |= ALL_SW_RESET;
+ writel(value, cdns->none_core_regs + USB3_CORE_CTRL1);
+ udelay(1);
+
+ if (role == CDNS3_ROLE_HOST) {
+ value = readl(cdns->none_core_regs + USB3_CORE_CTRL1);
+ value = (value & ~MODE_STRAP_MASK) | HOST_MODE | OC_DISABLE;
+ writel(value, cdns->none_core_regs + USB3_CORE_CTRL1);
+ value &= ~PHYAHB_SW_RESET;
+ writel(value, cdns->none_core_regs + USB3_CORE_CTRL1);
+ mdelay(1);
+ cdns3_usb_phy_init(cdns->phy_regs);
+ /* Force B Session Valid as 1 */
+ writel(0x0060, cdns->phy_regs + 0x380a4);
+ mdelay(1);
+
+ value = readl(cdns->none_core_regs + USB3_INT_REG);
+ value |= HOST_INT1_EN;
+ writel(value, cdns->none_core_regs + USB3_INT_REG);
+
+ value = readl(cdns->none_core_regs + USB3_CORE_CTRL1);
+ value &= ~ALL_SW_RESET;
+ writel(value, cdns->none_core_regs + USB3_CORE_CTRL1);
+
+ dev_dbg(cdns->dev, "wait xhci_power_on_ready\n");
+
+ value = readl(cdns->none_core_regs + USB3_CORE_STATUS);
+ timeout_us = 100000;
+ while (!(value & HOST_POWER_ON_READY) && timeout_us-- > 0) {
+ value = readl(cdns->none_core_regs + USB3_CORE_STATUS);
+ udelay(1);
+ }
+
+ if (timeout_us <= 0)
+ dev_err(cdns->dev, "wait xhci_power_on_ready timeout\n");
+
+ mdelay(1);
+
+ dev_dbg(cdns->dev, "switch to host role successfully\n");
+ } else { /* gadget mode */
+ value = readl(cdns->none_core_regs + USB3_CORE_CTRL1);
+ value = (value & ~MODE_STRAP_MASK) | DEV_MODE;
+ writel(value, cdns->none_core_regs + USB3_CORE_CTRL1);
+ value &= ~PHYAHB_SW_RESET;
+ writel(value, cdns->none_core_regs + USB3_CORE_CTRL1);
+
+ cdns3_usb_phy_init(cdns->phy_regs);
+ /* Force B Session Valid as 1 */
+ writel(0x0060, cdns->phy_regs + 0x380a4);
+ value = readl(cdns->none_core_regs + USB3_INT_REG);
+ value |= DEV_INT_EN;
+ writel(value, cdns->none_core_regs + USB3_INT_REG);
+
+ value = readl(cdns->none_core_regs + USB3_CORE_CTRL1);
+ value &= ~ALL_SW_RESET;
+ writel(value, cdns->none_core_regs + USB3_CORE_CTRL1);
+
+ dev_dbg(cdns->dev, "wait gadget_power_on_ready\n");
+
+ value = readl(cdns->none_core_regs + USB3_CORE_STATUS);
+ timeout_us = 100000;
+ while (!(value & DEV_POWER_ON_READY) && timeout_us-- > 0) {
+ value = readl(cdns->none_core_regs + USB3_CORE_STATUS);
+ udelay(1);
+ }
+
+ if (timeout_us <= 0)
+ dev_err(cdns->dev,
+ "wait gadget_power_on_ready timeout\n");
+
+ mdelay(1);
+
+ dev_dbg(cdns->dev, "switch to gadget role successfully\n");
+ }
+}
+
+static enum cdns3_roles cdns3_get_role(struct cdns3 *cdns)
+{
+ if (cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET]) {
+ if (extcon_get_state(cdns->extcon, EXTCON_USB_HOST))
+ return CDNS3_ROLE_HOST;
+ else if (extcon_get_state(cdns->extcon, EXTCON_USB))
+ return CDNS3_ROLE_GADGET;
+ else
+ return CDNS3_ROLE_END;
+ } else {
+ return cdns->roles[CDNS3_ROLE_HOST]
+ ? CDNS3_ROLE_HOST
+ : CDNS3_ROLE_GADGET;
+ }
+}
+
+/**
+ * cdns3_core_init_role - initialize role of operation
+ * @cdns: Pointer to cdns3 structure
+ *
+ * Returns 0 on success otherwise negative errno
+ */
+static int cdns3_core_init_role(struct cdns3 *cdns)
+{
+ struct device *dev = cdns->dev;
+ enum usb_dr_mode dr_mode = usb_get_dr_mode(dev);
+
+ cdns->role = CDNS3_ROLE_END;
+ if (dr_mode == USB_DR_MODE_UNKNOWN)
+ dr_mode = USB_DR_MODE_OTG;
+
+ if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) {
+ if (cdns3_host_init(cdns))
+ dev_info(dev, "doesn't support host\n");
+ }
+
+ if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) {
+ if (cdns3_gadget_init(cdns))
+ dev_info(dev, "doesn't support gadget\n");
+ }
+
+ if (!cdns->roles[CDNS3_ROLE_HOST] && !cdns->roles[CDNS3_ROLE_GADGET]) {
+ dev_err(dev, "no supported roles\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/**
+ * cdns3_irq - interrupt handler for cdns3 core device
+ *
+ * @irq: irq number for cdns3 core device
+ * @data: structure of cdns3
+ *
+ * Returns IRQ_HANDLED or IRQ_NONE
+ */
+static irqreturn_t cdns3_irq(int irq, void *data)
+{
+ struct cdns3 *cdns = data;
+ irqreturn_t ret = IRQ_NONE;
+
+ if (cdns->in_lpm) {
+ disable_irq_nosync(cdns->irq);
+ cdns->wakeup_int = true;
+ pm_runtime_get(cdns->dev);
+ return IRQ_HANDLED;
+ }
+
+ /* Handle device/host interrupt */
+ if (cdns->role != CDNS3_ROLE_END)
+ ret = cdns3_role(cdns)->irq(cdns);
+
+ return ret;
+}
+
+static int cdns3_get_clks(struct device *dev)
+{
+ struct cdns3 *cdns = dev_get_drvdata(dev);
+ int ret = 0;
+
+ cdns->cdns3_clks[0] = devm_clk_get(dev, "usb3_lpm_clk");
+ if (IS_ERR(cdns->cdns3_clks[0])) {
+ ret = PTR_ERR(cdns->cdns3_clks[0]);
+ dev_err(dev, "Failed to get usb3_lpm_clk, err=%d\n", ret);
+ return ret;
+ }
+
+ cdns->cdns3_clks[1] = devm_clk_get(dev, "usb3_bus_clk");
+ if (IS_ERR(cdns->cdns3_clks[1])) {
+ ret = PTR_ERR(cdns->cdns3_clks[1]);
+ dev_err(dev, "Failed to get usb3_bus_clk, err=%d\n", ret);
+ return ret;
+ }
+
+ cdns->cdns3_clks[2] = devm_clk_get(dev, "usb3_aclk");
+ if (IS_ERR(cdns->cdns3_clks[2])) {
+ ret = PTR_ERR(cdns->cdns3_clks[2]);
+ dev_err(dev, "Failed to get usb3_aclk, err=%d\n", ret);
+ return ret;
+ }
+
+ cdns->cdns3_clks[3] = devm_clk_get(dev, "usb3_ipg_clk");
+ if (IS_ERR(cdns->cdns3_clks[3])) {
+ ret = PTR_ERR(cdns->cdns3_clks[3]);
+ dev_err(dev, "Failed to get usb3_ipg_clk, err=%d\n", ret);
+ return ret;
+ }
+
+ cdns->cdns3_clks[4] = devm_clk_get(dev, "usb3_core_pclk");
+ if (IS_ERR(cdns->cdns3_clks[4])) {
+ ret = PTR_ERR(cdns->cdns3_clks[4]);
+ dev_err(dev, "Failed to get usb3_core_pclk, err=%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cdns3_prepare_enable_clks(struct device *dev)
+{
+ struct cdns3 *cdns = dev_get_drvdata(dev);
+ int i, j, ret = 0;
+
+ for (i = 0; i < CDNS3_NUM_OF_CLKS; i++) {
+ ret = clk_prepare_enable(cdns->cdns3_clks[i]);
+ if (ret) {
+ dev_err(dev,
+ "Failed to prepare/enable cdns3 clk, err=%d\n",
+ ret);
+ goto err;
+ }
+ }
+
+ return ret;
+err:
+ for (j = i; j > 0; j--)
+ clk_disable_unprepare(cdns->cdns3_clks[j - 1]);
+
+ return ret;
+}
+
+static void cdns3_disable_unprepare_clks(struct device *dev)
+{
+ struct cdns3 *cdns = dev_get_drvdata(dev);
+ int i;
+
+ for (i = CDNS3_NUM_OF_CLKS - 1; i >= 0; i--)
+ clk_disable_unprepare(cdns->cdns3_clks[i]);
+}
+
+static void cdns3_remove_roles(struct cdns3 *cdns)
+{
+ cdns3_gadget_remove(cdns);
+ cdns3_host_remove(cdns);
+}
+
+static int cdns3_do_role_switch(struct cdns3 *cdns, enum cdns3_roles role)
+{
+ int ret = 0;
+ enum cdns3_roles current_role;
+
+ dev_dbg(cdns->dev, "current role is %d, switch to %d\n",
+ cdns->role, role);
+
+ if (cdns->role == role)
+ return 0;
+
+ pm_runtime_get_sync(cdns->dev);
+ current_role = cdns->role;
+ cdns3_role_stop(cdns);
+ if (role == CDNS3_ROLE_END) {
+ /* Force B Session Valid as 0 */
+ writel(0x0040, cdns->phy_regs + 0x380a4);
+ pm_runtime_put_sync(cdns->dev);
+ return 0;
+ }
+
+ cdns_set_role(cdns, role);
+ ret = cdns3_role_start(cdns, role);
+ if (ret) {
+ /* Back to current role */
+ dev_err(cdns->dev, "set %d has failed, back to %d\n",
+ role, current_role);
+ cdns_set_role(cdns, current_role);
+ ret = cdns3_role_start(cdns, current_role);
+ }
+
+ pm_runtime_put_sync(cdns->dev);
+ return ret;
+}
+
+/**
+ * cdns3_role_switch - work queue handler for role switch
+ *
+ * @work: work queue item structure
+ *
+ * Handles below events:
+ * - Role switch for dual-role devices
+ * - CDNS3_ROLE_GADGET <--> CDNS3_ROLE_END for peripheral-only devices
+ */
+static void cdns3_role_switch(struct work_struct *work)
+{
+ struct cdns3 *cdns = container_of(work, struct cdns3,
+ role_switch_wq);
+ bool device, host;
+
+ host = extcon_get_state(cdns->extcon, EXTCON_USB_HOST);
+ device = extcon_get_state(cdns->extcon, EXTCON_USB);
+
+ if (host) {
+ if (cdns->roles[CDNS3_ROLE_HOST])
+ cdns3_do_role_switch(cdns, CDNS3_ROLE_HOST);
+ return;
+ }
+
+ if (device)
+ cdns3_do_role_switch(cdns, CDNS3_ROLE_GADGET);
+ else
+ cdns3_do_role_switch(cdns, CDNS3_ROLE_END);
+}
+
+static int cdns3_extcon_notifier(struct notifier_block *nb, unsigned long event,
+ void *ptr)
+{
+ struct cdns3 *cdns = container_of(nb, struct cdns3, extcon_nb);
+
+ queue_work(system_freezable_wq, &cdns->role_switch_wq);
+
+ return NOTIFY_DONE;
+}
+
+static int cdns3_register_extcon(struct cdns3 *cdns)
+{
+ struct extcon_dev *extcon;
+ struct device *dev = cdns->dev;
+ int ret;
+
+ if (of_property_read_bool(dev->of_node, "extcon")) {
+ extcon = extcon_get_edev_by_phandle(dev, 0);
+ if (IS_ERR(extcon))
+ return PTR_ERR(extcon);
+
+ ret = devm_extcon_register_notifier(dev, extcon,
+ EXTCON_USB_HOST, &cdns->extcon_nb);
+ if (ret < 0) {
+ dev_err(dev, "register Host Connector failed\n");
+ return ret;
+ }
+
+ ret = devm_extcon_register_notifier(dev, extcon,
+ EXTCON_USB, &cdns->extcon_nb);
+ if (ret < 0) {
+ dev_err(dev, "register Device Connector failed\n");
+ return ret;
+ }
+
+ cdns->extcon = extcon;
+ cdns->extcon_nb.notifier_call = cdns3_extcon_notifier;
+ }
+
+ return 0;
+}
+
+/**
+ * cdns3_probe - probe for cdns3 core device
+ * @pdev: Pointer to cdns3 core platform device
+ *
+ * Returns 0 on success otherwise negative errno
+ */
+static int cdns3_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct cdns3 *cdns;
+ void __iomem *regs;
+ int ret;
+
+ cdns = devm_kzalloc(dev, sizeof(*cdns), GFP_KERNEL);
+ if (!cdns)
+ return -ENOMEM;
+
+ cdns->dev = dev;
+ platform_set_drvdata(pdev, cdns);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(dev, "missing IRQ\n");
+ return -ENODEV;
+ }
+ cdns->irq = res->start;
+
+ /*
+ * Request memory region
+ * region-0: nxp wrap registers
+ * region-1: xHCI
+ * region-2: Peripheral
+ * region-3: PHY registers
+ * region-4: OTG registers
+ */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+ cdns->none_core_regs = regs;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+ cdns->xhci_regs = regs;
+ cdns->xhci_res = res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+ cdns->dev_regs = regs;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+ cdns->phy_regs = regs;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+ cdns->otg_regs = regs;
+
+ mutex_init(&cdns->mutex);
+ ret = cdns3_get_clks(dev);
+ if (ret)
+ return ret;
+
+ ret = cdns3_prepare_enable_clks(dev);
+ if (ret)
+ return ret;
+
+ cdns->usbphy = devm_usb_get_phy_by_phandle(dev, "cdns3,usbphy", 0);
+ if (IS_ERR(cdns->usbphy)) {
+ ret = PTR_ERR(cdns->usbphy);
+ if (ret == -ENODEV)
+ ret = -EINVAL;
+ goto err1;
+ }
+
+ ret = usb_phy_init(cdns->usbphy);
+ if (ret)
+ goto err1;
+
+ ret = cdns3_core_init_role(cdns);
+ if (ret)
+ goto err2;
+
+ if (cdns->roles[CDNS3_ROLE_GADGET]) {
+ INIT_WORK(&cdns->role_switch_wq, cdns3_role_switch);
+ ret = cdns3_register_extcon(cdns);
+ if (ret)
+ goto err3;
+ }
+
+ cdns->role = cdns3_get_role(cdns);
+ dev_dbg(dev, "the init role is %d\n", cdns->role);
+ cdns_set_role(cdns, cdns->role);
+ ret = cdns3_role_start(cdns, cdns->role);
+ if (ret) {
+ dev_err(dev, "can't start %s role\n",
+ cdns3_role(cdns)->name);
+ goto err3;
+ }
+
+ ret = devm_request_irq(dev, cdns->irq, cdns3_irq, IRQF_SHARED,
+ dev_name(dev), cdns);
+ if (ret)
+ goto err4;
+
+ device_set_wakeup_capable(dev, true);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ /*
+ * The controller needs less time between bus and controller suspend,
+ * and we also needs a small delay to avoid frequently entering low
+ * power mode.
+ */
+ pm_runtime_set_autosuspend_delay(dev, 20);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_use_autosuspend(dev);
+ dev_dbg(dev, "Cadence USB3 core: probe succeed\n");
+
+ return 0;
+
+err4:
+ cdns3_role_stop(cdns);
+err3:
+ cdns3_remove_roles(cdns);
+err2:
+ usb_phy_shutdown(cdns->usbphy);
+err1:
+ cdns3_disable_unprepare_clks(dev);
+ return ret;
+}
+
+/**
+ * cdns3_remove - unbind our drd driver and clean up
+ * @pdev: Pointer to Linux platform device
+ *
+ * Returns 0 on success otherwise negative errno
+ */
+static int cdns3_remove(struct platform_device *pdev)
+{
+ struct cdns3 *cdns = platform_get_drvdata(pdev);
+
+ pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+ cdns3_remove_roles(cdns);
+ usb_phy_shutdown(cdns->usbphy);
+ cdns3_disable_unprepare_clks(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id of_cdns3_match[] = {
+ { .compatible = "Cadence,usb3" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, of_cdns3_match);
+#endif
+
+#ifdef CONFIG_PM
+static inline bool controller_power_is_lost(struct cdns3 *cdns)
+{
+ u32 value;
+
+ value = readl(cdns->none_core_regs + USB3_CORE_CTRL1);
+ if ((value & SW_RESET_MASK) == ALL_SW_RESET)
+ return true;
+ else
+ return false;
+}
+
+static void cdns3_set_wakeup(void *none_core_regs, bool enable)
+{
+ u32 value;
+
+ if (enable) {
+ /* Enable wakeup and phy_refclk_req */
+ value = readl(none_core_regs + USB3_INT_REG);
+ value |= OTG_WAKEUP_EN | DEVU3_WAEKUP_EN;
+ writel(value, none_core_regs + USB3_INT_REG);
+ } else {
+ /* disable wakeup and phy_refclk_req */
+ value = readl(none_core_regs + USB3_INT_REG);
+ value &= ~(OTG_WAKEUP_EN | DEVU3_WAEKUP_EN);
+ writel(value, none_core_regs + USB3_INT_REG);
+ }
+}
+
+static void cdns3_enter_suspend(struct cdns3 *cdns, bool suspend, bool wakeup)
+{
+ void __iomem *otg_regs = cdns->otg_regs;
+ void __iomem *xhci_regs = cdns->xhci_regs;
+ void __iomem *none_core_regs = cdns->none_core_regs;
+ u32 value;
+ int timeout_us = 100000;
+
+ if (cdns->role != CDNS3_ROLE_HOST)
+ return;
+
+ disable_irq(cdns->irq);
+ if (suspend) {
+ value = readl(otg_regs + OTGREFCLK);
+ value |= OTG_STB_CLK_SWITCH_EN;
+ writel(value, otg_regs + OTGREFCLK);
+
+ value = readl(xhci_regs + XECP_PORT_CAP_REG);
+ value |= LPM_2_STB_SWITCH_EN;
+ writel(value, xhci_regs + XECP_PORT_CAP_REG);
+ if (cdns3_role(cdns)->suspend)
+ cdns3_role(cdns)->suspend(cdns, wakeup);
+
+ /*
+ * SW should ensure LPM_2_STB_SWITCH_EN and RXDET_IN_P3_32KHZ
+ * are aligned before setting CFG_RXDET_P3_EN
+ */
+ value = readl(xhci_regs + XECP_AUX_CTRL_REG1);
+ value |= CFG_RXDET_P3_EN;
+ writel(value, xhci_regs + XECP_AUX_CTRL_REG1);
+ /* SW request low power when all usb ports allow to it ??? */
+ value = readl(xhci_regs + XECP_PM_PMCSR);
+ value |= PS_D0;
+ writel(value, xhci_regs + XECP_PM_PMCSR);
+
+ /* mdctrl_clk_sel */
+ value = readl(none_core_regs + USB3_CORE_CTRL1);
+ value |= MDCTRL_CLK_SEL;
+ writel(value, none_core_regs + USB3_CORE_CTRL1);
+
+ /* wait for mdctrl_clk_status */
+ value = readl(none_core_regs + USB3_CORE_STATUS);
+ while (!(value & MDCTRL_CLK_STATUS) && timeout_us-- > 0) {
+ value = readl(none_core_regs + USB3_CORE_STATUS);
+ udelay(1);
+ }
+
+ if (timeout_us <= 0)
+ dev_err(cdns->dev, "wait mdctrl_clk_status timeout\n");
+
+ dev_dbg(cdns->dev, "mdctrl_clk_status is set\n");
+
+ /* wait lpm_clk_req to be 0 */
+ value = readl(none_core_regs + USB3_INT_REG);
+ timeout_us = 100000;
+ while ((value & LPM_CLK_REQ) && timeout_us-- > 0) {
+ value = readl(none_core_regs + USB3_INT_REG);
+ udelay(1);
+ }
+
+ if (timeout_us <= 0)
+ dev_err(cdns->dev, "wait lpm_clk_req timeout\n");
+
+ dev_dbg(cdns->dev, "lpm_clk_req cleared\n");
+
+ /* wait phy_refclk_req to be 0 */
+ value = readl(none_core_regs + USB3_SSPHY_STATUS);
+ timeout_us = 100000;
+ while ((value & PHY_REFCLK_REQ) && timeout_us-- > 0) {
+ value = readl(none_core_regs + USB3_SSPHY_STATUS);
+ udelay(1);
+ }
+
+ if (timeout_us <= 0)
+ dev_err(cdns->dev, "wait phy_refclk_req timeout\n");
+
+ dev_dbg(cdns->dev, "phy_refclk_req cleared\n");
+
+ cdns3_set_wakeup(none_core_regs, true);
+ } else {
+ value = readl(none_core_regs + USB3_INT_REG);
+ /* wait CLK_125_REQ to be 1 */
+ value = readl(none_core_regs + USB3_INT_REG);
+ while (!(value & CLK_125_REQ) && timeout_us-- > 0) {
+ value = readl(none_core_regs + USB3_INT_REG);
+ udelay(1);
+ }
+
+ cdns3_set_wakeup(none_core_regs, false);
+
+ /* SW request D0 */
+ value = readl(xhci_regs + XECP_PM_PMCSR);
+ value &= ~PS_D0;
+ writel(value, xhci_regs + XECP_PM_PMCSR);
+
+ /* clr CFG_RXDET_P3_EN */
+ value = readl(xhci_regs + XECP_AUX_CTRL_REG1);
+ value &= ~CFG_RXDET_P3_EN;
+ writel(value, xhci_regs + XECP_AUX_CTRL_REG1);
+
+ /* clear mdctrl_clk_sel */
+ value = readl(none_core_regs + USB3_CORE_CTRL1);
+ value &= ~MDCTRL_CLK_SEL;
+ writel(value, none_core_regs + USB3_CORE_CTRL1);
+
+ /* wait for mdctrl_clk_status is cleared */
+ value = readl(none_core_regs + USB3_CORE_STATUS);
+ timeout_us = 100000;
+ while ((value & MDCTRL_CLK_STATUS) && timeout_us-- > 0) {
+ value = readl(none_core_regs + USB3_CORE_STATUS);
+ udelay(1);
+ }
+
+ if (timeout_us <= 0)
+ dev_err(cdns->dev, "wait mdctrl_clk_status timeout\n");
+
+ dev_dbg(cdns->dev, "mdctrl_clk_status cleared\n");
+
+ /* Wait until OTG_NRDY is 0 */
+ value = readl(otg_regs + OTGSTS);
+ timeout_us = 100000;
+ while ((value & OTG_NRDY) && timeout_us-- > 0) {
+ value = readl(otg_regs + OTGSTS);
+ udelay(1);
+ }
+
+ if (timeout_us <= 0)
+ dev_err(cdns->dev, "wait OTG ready timeout\n");
+
+ value = readl(none_core_regs + USB3_CORE_STATUS);
+ timeout_us = 100000;
+ while (!(value & HOST_POWER_ON_READY) && timeout_us-- > 0) {
+ value = readl(none_core_regs + USB3_CORE_STATUS);
+ udelay(1);
+ }
+
+ if (timeout_us <= 0)
+ dev_err(cdns->dev, "wait xhci_power_on_ready timeout\n");
+ }
+ enable_irq(cdns->irq);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int cdns3_suspend(struct device *dev)
+{
+ struct cdns3 *cdns = dev_get_drvdata(dev);
+ bool wakeup = device_may_wakeup(dev);
+ u32 value;
+
+ dev_dbg(dev, "at %s\n", __func__);
+
+ if (pm_runtime_status_suspended(dev))
+ pm_runtime_resume(dev);
+
+ if (cdns->role == CDNS3_ROLE_HOST)
+ cdns3_enter_suspend(cdns, true, wakeup);
+ else if (cdns->role == CDNS3_ROLE_GADGET) {
+ /* When at device mode, always set controller at reset mode */
+ value = readl(cdns->none_core_regs + USB3_CORE_CTRL1);
+ value |= ALL_SW_RESET;
+ writel(value, cdns->none_core_regs + USB3_CORE_CTRL1);
+ }
+
+ if (wakeup)
+ enable_irq_wake(cdns->irq);
+
+ usb_phy_set_suspend(cdns->usbphy, 1);
+ cdns3_disable_unprepare_clks(dev);
+ cdns->in_lpm = true;
+
+ return 0;
+}
+
+static int cdns3_resume(struct device *dev)
+{
+ struct cdns3 *cdns = dev_get_drvdata(dev);
+ int ret;
+ bool power_lost;
+
+ dev_dbg(dev, "at %s\n", __func__);
+ if (!cdns->in_lpm) {
+ WARN_ON(1);
+ return 0;
+ }
+
+ ret = cdns3_prepare_enable_clks(dev);
+ if (ret)
+ return ret;
+
+ usb_phy_set_suspend(cdns->usbphy, 0);
+ cdns->in_lpm = false;
+ if (device_may_wakeup(dev))
+ disable_irq_wake(cdns->irq);
+ power_lost = controller_power_is_lost(cdns);
+ if (power_lost) {
+ dev_dbg(dev, "power is lost, the role is %d\n", cdns->role);
+ cdns_set_role(cdns, cdns->role);
+ if ((cdns->role != CDNS3_ROLE_END)
+ && cdns3_role(cdns)->resume) {
+ /* Force B Session Valid as 1 */
+ writel(0x0060, cdns->phy_regs + 0x380a4);
+ cdns3_role(cdns)->resume(cdns, true);
+ }
+ } else {
+ cdns3_enter_suspend(cdns, false, false);
+ if (cdns->wakeup_int) {
+ cdns->wakeup_int = false;
+ pm_runtime_mark_last_busy(cdns->dev);
+ pm_runtime_put_autosuspend(cdns->dev);
+ enable_irq(cdns->irq);
+ }
+
+ if ((cdns->role != CDNS3_ROLE_END) && cdns3_role(cdns)->resume)
+ cdns3_role(cdns)->resume(cdns, false);
+ }
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ if (cdns->role == CDNS3_ROLE_HOST) {
+ /*
+ * There is no PM APIs for cdns->host_dev, we can only do
+ * it at its parent PM APIs
+ */
+ pm_runtime_disable(cdns->host_dev);
+ pm_runtime_set_active(cdns->host_dev);
+ pm_runtime_enable(cdns->host_dev);
+ }
+
+ dev_dbg(dev, "at end of %s\n", __func__);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+static int cdns3_runtime_suspend(struct device *dev)
+{
+ struct cdns3 *cdns = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "at the begin of %s\n", __func__);
+ if (cdns->in_lpm) {
+ WARN_ON(1);
+ return 0;
+ }
+
+ cdns3_enter_suspend(cdns, true, true);
+ usb_phy_set_suspend(cdns->usbphy, 1);
+ cdns3_disable_unprepare_clks(dev);
+ cdns->in_lpm = true;
+
+ dev_dbg(dev, "at the end of %s\n", __func__);
+
+ return 0;
+}
+
+static int cdns3_runtime_resume(struct device *dev)
+{
+ struct cdns3 *cdns = dev_get_drvdata(dev);
+ int ret;
+
+ if (!cdns->in_lpm) {
+ WARN_ON(1);
+ return 0;
+ }
+
+ ret = cdns3_prepare_enable_clks(dev);
+ if (ret)
+ return ret;
+
+ usb_phy_set_suspend(cdns->usbphy, 0);
+ cdns3_enter_suspend(cdns, false, false);
+ cdns->in_lpm = 0;
+
+ if (cdns->role == CDNS3_ROLE_HOST) {
+ if (cdns->wakeup_int) {
+ cdns->wakeup_int = false;
+ pm_runtime_mark_last_busy(cdns->dev);
+ pm_runtime_put_autosuspend(cdns->dev);
+ enable_irq(cdns->irq);
+ }
+
+ if ((cdns->role != CDNS3_ROLE_END) && cdns3_role(cdns)->resume)
+ cdns3_role(cdns)->resume(cdns, false);
+ }
+
+ dev_dbg(dev, "at %s\n", __func__);
+ return 0;
+}
+#endif /* CONFIG_PM */
+static const struct dev_pm_ops cdns3_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(cdns3_suspend, cdns3_resume)
+ SET_RUNTIME_PM_OPS(cdns3_runtime_suspend, cdns3_runtime_resume, NULL)
+};
+
+static struct platform_driver cdns3_driver = {
+ .probe = cdns3_probe,
+ .remove = cdns3_remove,
+ .driver = {
+ .name = "cdns-usb3",
+ .of_match_table = of_match_ptr(of_cdns3_match),
+ .pm = &cdns3_pm_ops,
+ },
+};
+
+static int __init cdns3_driver_platform_register(void)
+{
+ cdns3_host_driver_init();
+ return platform_driver_register(&cdns3_driver);
+}
+module_init(cdns3_driver_platform_register);
+
+static void __exit cdns3_driver_platform_unregister(void)
+{
+ platform_driver_unregister(&cdns3_driver);
+}
+module_exit(cdns3_driver_platform_unregister);
+
+MODULE_ALIAS("platform:cdns3");
+MODULE_AUTHOR("Peter Chen <peter.chen@nxp.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Cadence USB3 DRD Controller Driver");
diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h
new file mode 100644
index 000000000000..738dbfa836cf
--- /dev/null
+++ b/drivers/usb/cdns3/core.h
@@ -0,0 +1,131 @@
+/**
+ * core.h - Cadence USB3 DRD Controller Core header file
+ *
+ * Copyright 2017 NXP
+ *
+ * Authors: Peter Chen <peter.chen@nxp.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __DRIVERS_USB_CDNS3_CORE_H
+#define __DRIVERS_USB_CDNS3_CORE_H
+
+struct cdns3;
+enum cdns3_roles {
+ CDNS3_ROLE_HOST = 0,
+ CDNS3_ROLE_GADGET,
+ CDNS3_ROLE_END,
+};
+
+/**
+ * struct cdns3_role_driver - host/gadget role driver
+ * @start: start this role
+ * @stop: stop this role
+ * @suspend: suspend callback for this role
+ * @resume: resume callback for this role
+ * @irq: irq handler for this role
+ * @name: role name string (host/gadget)
+ */
+struct cdns3_role_driver {
+ int (*start)(struct cdns3 *);
+ void (*stop)(struct cdns3 *);
+ int (*suspend)(struct cdns3 *, bool do_wakeup);
+ int (*resume)(struct cdns3 *, bool hibernated);
+ irqreturn_t (*irq)(struct cdns3 *);
+ const char *name;
+};
+
+#define CDNS3_NUM_OF_CLKS 5
+/**
+ * struct cdns3 - Representation of Cadence USB3 DRD controller.
+ * @dev: pointer to Cadence device struct
+ * @xhci_regs: pointer to base of xhci registers
+ * @xhci_res: the resource for xhci
+ * @dev_regs: pointer to base of dev registers
+ * @none_core_regs: pointer to base of nxp wrapper registers
+ * @phy_regs: pointer to base of phy registers
+ * @otg_regs: pointer to base of otg registers
+ * @irq: irq number for controller
+ * @roles: array of supported roles for this controller
+ * @role: current role
+ * @host_dev: the child host device pointer for cdns3 core
+ * @gadget_dev: the child gadget device pointer for cdns3 core
+ * @usbphy: usbphy for this controller
+ * @cdns3_clks: Clock pointer array for cdns3 core
+ * @extcon: Type-C extern connector
+ * @extcon_nb: notifier block for Type-C extern connector
+ * @role_switch_wq: work queue item for role switch
+ * @in_lpm: the controller in low power mode
+ * @wakeup_int: the wakeup interrupt
+ * @mutex: the mutex for concurrent code at driver
+ */
+struct cdns3 {
+ struct device *dev;
+ void __iomem *xhci_regs;
+ struct resource *xhci_res;
+ struct usbss_dev_register_block_type __iomem *dev_regs;
+ void __iomem *none_core_regs;
+ void __iomem *phy_regs;
+ void __iomem *otg_regs;
+ int irq;
+ struct cdns3_role_driver *roles[CDNS3_ROLE_END];
+ enum cdns3_roles role;
+ struct device *host_dev;
+ struct device *gadget_dev;
+ struct usb_phy *usbphy;
+ struct clk *cdns3_clks[CDNS3_NUM_OF_CLKS];
+ struct extcon_dev *extcon;
+ struct notifier_block extcon_nb;
+ struct work_struct role_switch_wq;
+ bool in_lpm;
+ bool wakeup_int;
+ struct mutex mutex;
+};
+
+static inline struct cdns3_role_driver *cdns3_role(struct cdns3 *cdns)
+{
+ WARN_ON(cdns->role >= CDNS3_ROLE_END || !cdns->roles[cdns->role]);
+ return cdns->roles[cdns->role];
+}
+
+static inline int cdns3_role_start(struct cdns3 *cdns, enum cdns3_roles role)
+{
+ int ret;
+ if (role >= CDNS3_ROLE_END)
+ return 0;
+
+ if (!cdns->roles[role])
+ return -ENXIO;
+
+ mutex_lock(&cdns->mutex);
+ cdns->role = role;
+ ret = cdns->roles[role]->start(cdns);
+ mutex_unlock(&cdns->mutex);
+ return ret;
+}
+
+static inline void cdns3_role_stop(struct cdns3 *cdns)
+{
+ enum cdns3_roles role = cdns->role;
+
+ if (role == CDNS3_ROLE_END)
+ return;
+
+ mutex_lock(&cdns->mutex);
+ cdns->roles[role]->stop(cdns);
+ cdns->role = CDNS3_ROLE_END;
+ mutex_unlock(&cdns->mutex);
+}
+
+#endif /* __DRIVERS_USB_CDNS3_CORE_H */
diff --git a/drivers/usb/cdns3/dev-regs-macro.h b/drivers/usb/cdns3/dev-regs-macro.h
new file mode 100644
index 000000000000..5b307623afec
--- /dev/null
+++ b/drivers/usb/cdns3/dev-regs-macro.h
@@ -0,0 +1,894 @@
+/**
+ * dev-regs-macro.h - Cadence USB3 Device register definition
+ *
+ * Copyright (C) 2016 Cadence Design Systems - http://www.cadence.com
+ * Copyright 2017 NXP
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __REG_USBSS_DEV_ADDR_MAP_MACRO_H__
+#define __REG_USBSS_DEV_ADDR_MAP_MACRO_H__
+
+
+/* macros for BlueprintGlobalNameSpace::USB_CONF */
+#ifndef __USB_CONF_MACRO__
+#define __USB_CONF_MACRO__
+
+/* macros for field CFGRST */
+#define USB_CONF__CFGRST__MASK 0x00000001U
+#define USB_CONF__CFGSET__MASK 0x00000002U
+#define USB_CONF__USB3DIS__MASK 0x00000008U
+#define USB_CONF__DEVEN__MASK 0x00004000U
+#define USB_CONF__DEVDS__MASK 0x00008000U
+#define USB_CONF__L1EN__MASK 0x00010000U
+#define USB_CONF__L1DS__MASK 0x00020000U
+#define USB_CONF__CLK2OFFDS__MASK 0x00080000U
+#define USB_CONF__U1EN__MASK 0x01000000U
+#define USB_CONF__U1DS__MASK 0x02000000U
+#define USB_CONF__U2EN__MASK 0x04000000U
+#define USB_CONF__U2DS__MASK 0x08000000U
+#endif /* __USB_CONF_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_conf */
+#ifndef __USB_STS_MACRO__
+#define __USB_STS_MACRO__
+
+/* macros for field CFGSTS */
+#define USB_STS__CFGSTS__MASK 0x00000001U
+#define USB_STS__USBSPEED__READ(src) (((uint32_t)(src) & 0x00000070U) >> 4)
+
+/* macros for field ENDIAN_MIRROR */
+#define USB_STS__LPMST__READ(src) (((uint32_t)(src) & 0x000c0000U) >> 18)
+
+/* macros for field USB2CONS */
+#define USB_STS__U1ENS__MASK 0x01000000U
+#define USB_STS__U2ENS__MASK 0x02000000U
+#define USB_STS__LST__READ(src) (((uint32_t)(src) & 0x3c000000U) >> 26)
+
+/* macros for field DMAOFF */
+#endif /* __USB_STS_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_sts */
+#ifndef __USB_CMD_MACRO__
+#define __USB_CMD_MACRO__
+
+/* macros for field SET_ADDR */
+#define USB_CMD__SET_ADDR__MASK 0x00000001U
+#define USB_CMD__STMODE 0x00000200U
+#define USB_CMD__TMODE_SEL(x) (x << 10)
+#define USB_CMD__FADDR__WRITE(src) (((uint32_t)(src) << 1) & 0x000000feU)
+#endif /* __USB_CMD_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cmd */
+#ifndef __USB_ITPN_MACRO__
+#define __USB_ITPN_MACRO__
+
+/* macros for field ITPN */
+#endif /* __USB_ITPN_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_iptn */
+#ifndef __USB_LPM_MACRO__
+#define __USB_LPM_MACRO__
+
+/* macros for field HIRD */
+#endif /* __USB_LPM_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_lpm */
+#ifndef __USB_IEN_MACRO__
+#define __USB_IEN_MACRO__
+
+/* macros for field CONIEN */
+#define USB_IEN__CONIEN__MASK 0x00000001U
+#define USB_IEN__DISIEN__MASK 0x00000002U
+#define USB_IEN__UWRESIEN__MASK 0x00000004U
+#define USB_IEN__UHRESIEN__MASK 0x00000008U
+#define USB_IEN__U3EXTIEN__MASK 0x00000020U
+#define USB_IEN__CON2IEN__MASK 0x00010000U
+#define USB_IEN__U2RESIEN__MASK 0x00040000U
+#define USB_IEN__L2ENTIEN__MASK 0x00100000U
+#define USB_IEN__L2EXTIEN__MASK 0x00200000U
+#endif /* __USB_IEN_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_ien */
+#ifndef __USB_ISTS_MACRO__
+#define __USB_ISTS_MACRO__
+
+/* macros for field CONI */
+#define USB_ISTS__CONI__SHIFT 0
+#define USB_ISTS__DISI__SHIFT 1
+#define USB_ISTS__UWRESI__SHIFT 2
+#define USB_ISTS__UHRESI__SHIFT 3
+#define USB_ISTS__U3EXTI__SHIFT 5
+#define USB_ISTS__CON2I__SHIFT 16
+#define USB_ISTS__DIS2I__SHIFT 17
+#define USB_ISTS__DIS2I__MASK 0x00020000U
+#define USB_ISTS__U2RESI__SHIFT 18
+#define USB_ISTS__L2ENTI__SHIFT 20
+#define USB_ISTS__L2EXTI__SHIFT 21
+#endif /* __USB_ISTS_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_ists */
+#ifndef __EP_SEL_MACRO__
+#define __EP_SEL_MACRO__
+
+/* macros for field EPNO */
+#endif /* __EP_SEL_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_sel */
+#ifndef __EP_TRADDR_MACRO__
+#define __EP_TRADDR_MACRO__
+
+/* macros for field TRADDR */
+#define EP_TRADDR__TRADDR__WRITE(src) ((uint32_t)(src) & 0xffffffffU)
+#endif /* __EP_TRADDR_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_traddr */
+#ifndef __EP_CFG_MACRO__
+#define __EP_CFG_MACRO__
+
+/* macros for field ENABLE */
+#define EP_CFG__ENABLE__MASK 0x00000001U
+#define EP_CFG__EPTYPE__WRITE(src) (((uint32_t)(src) << 1) & 0x00000006U)
+#define EP_CFG__MAXBURST__WRITE(src) (((uint32_t)(src) << 8) & 0x00000f00U)
+#define EP_CFG__MAXPKTSIZE__WRITE(src) (((uint32_t)(src) << 16) & 0x07ff0000U)
+#define EP_CFG__BUFFERING__WRITE(src) (((uint32_t)(src) << 27) & 0xf8000000U)
+#endif /* __EP_CFG_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_cfg */
+#ifndef __EP_CMD_MACRO__
+#define __EP_CMD_MACRO__
+
+/* macros for field EPRST */
+#define EP_CMD__EPRST__MASK 0x00000001U
+#define EP_CMD__SSTALL__MASK 0x00000002U
+#define EP_CMD__CSTALL__MASK 0x00000004U
+#define EP_CMD__ERDY__MASK 0x00000008U
+#define EP_CMD__REQ_CMPL__MASK 0x00000020U
+#define EP_CMD__DRDY__MASK 0x00000040U
+#define EP_CMD__DFLUSH__MASK 0x00000080U
+#endif /* __EP_CMD_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_cmd */
+#ifndef __EP_STS_MACRO__
+#define __EP_STS_MACRO__
+
+/* macros for field SETUP */
+#define EP_STS__SETUP__MASK 0x00000001U
+#define EP_STS__STALL__MASK 0x00000002U
+#define EP_STS__IOC__MASK 0x00000004U
+#define EP_STS__ISP__MASK 0x00000008U
+#define EP_STS__DESCMIS__MASK 0x00000010U
+#define EP_STS__TRBERR__MASK 0x00000080U
+#define EP_STS__NRDY__MASK 0x00000100U
+#define EP_STS__DBUSY__MASK 0x00000200U
+#define EP_STS__OUTSMM__MASK 0x00004000U
+#define EP_STS__ISOERR__MASK 0x00008000U
+#endif /* __EP_STS_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_sts */
+#ifndef __EP_STS_SID_MACRO__
+#define __EP_STS_SID_MACRO__
+
+/* macros for field SID */
+#endif /* __EP_STS_SID_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_sts_sid */
+#ifndef __EP_STS_EN_MACRO__
+#define __EP_STS_EN_MACRO__
+
+/* macros for field SETUPEN */
+#define EP_STS_EN__SETUPEN__MASK 0x00000001U
+#define EP_STS_EN__DESCMISEN__MASK 0x00000010U
+#define EP_STS_EN__TRBERREN__MASK 0x00000080U
+#endif /* __EP_STS_EN_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_sts_en */
+#ifndef __DRBL_MACRO__
+#define __DRBL_MACRO__
+
+/* macros for field DRBL0O */
+#endif /* __DRBL_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.drbl */
+#ifndef __EP_IEN_MACRO__
+#define __EP_IEN_MACRO__
+
+/* macros for field EOUTEN0 */
+#define EP_IEN__EOUTEN0__MASK 0x00000001U
+#define EP_IEN__EINEN0__MASK 0x00010000U
+#endif /* __EP_IEN_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_ien */
+#ifndef __EP_ISTS_MACRO__
+#define __EP_ISTS_MACRO__
+
+/* macros for field EOUT0 */
+#define EP_ISTS__EOUT0__MASK 0x00000001U
+#define EP_ISTS__EIN0__MASK 0x00010000U
+#endif /* __EP_ISTS_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.ep_ists */
+#ifndef __USB_PWR_MACRO__
+#define __USB_PWR_MACRO__
+
+/* macros for field PSO_EN */
+#endif /* __USB_PWR_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_pwr */
+#ifndef __USB_CONF2_MACRO__
+#define __USB_CONF2_MACRO__
+
+/* macros for field AHB_RETRY_EN */
+#endif /* __USB_CONF2_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_conf2 */
+#ifndef __USB_CAP1_MACRO__
+#define __USB_CAP1_MACRO__
+
+/* macros for field SFR_TYPE */
+#endif /* __USB_CAP1_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cap1 */
+#ifndef __USB_CAP2_MACRO__
+#define __USB_CAP2_MACRO__
+
+/* macros for field ACTUAL_MEM_SIZE */
+#endif /* __USB_CAP2_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cap2 */
+#ifndef __USB_CAP3_MACRO__
+#define __USB_CAP3_MACRO__
+
+/* macros for field EPOUT_N */
+#endif /* __USB_CAP3_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cap3 */
+#ifndef __USB_CAP4_MACRO__
+#define __USB_CAP4_MACRO__
+
+/* macros for field EPOUTI_N */
+#endif /* __USB_CAP4_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cap4 */
+#ifndef __USB_CAP5_MACRO__
+#define __USB_CAP5_MACRO__
+
+/* macros for field EPOUTI_N */
+#endif /* __USB_CAP5_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cap5 */
+#ifndef __USB_CAP6_MACRO__
+#define __USB_CAP6_MACRO__
+
+/* macros for field VERSION */
+#endif /* __USB_CAP6_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cap6 */
+#ifndef __USB_CPKT1_MACRO__
+#define __USB_CPKT1_MACRO__
+
+/* macros for field CPKT1 */
+#endif /* __USB_CPKT1_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cpkt1 */
+#ifndef __USB_CPKT2_MACRO__
+#define __USB_CPKT2_MACRO__
+
+/* macros for field CPKT2 */
+#endif /* __USB_CPKT2_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cpkt2 */
+#ifndef __USB_CPKT3_MACRO__
+#define __USB_CPKT3_MACRO__
+
+/* macros for field CPKT3 */
+#endif /* __USB_CPKT3_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.usb_cpkt3 */
+#ifndef __CFG_REG1_MACRO__
+#define __CFG_REG1_MACRO__
+
+/* macros for field DEBOUNCER_CNT */
+#endif /* __CFG_REG1_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg1 */
+#ifndef __DBG_LINK1_MACRO__
+#define __DBG_LINK1_MACRO__
+
+/* macros for field LFPS_MIN_DET_U1_EXIT */
+#define DBG_LINK1__LFPS_MIN_GEN_U1_EXIT__WRITE(src) \
+ (((uint32_t)(src)\
+ << 8) & 0x0000ff00U)
+#define DBG_LINK1__LFPS_MIN_GEN_U1_EXIT_SET__MASK 0x02000000U
+#endif /* __DBG_LINK1_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.dbg_link1 */
+#ifndef __DBG_LINK2_MACRO__
+#define __DBG_LINK2_MACRO__
+
+/* macros for field RXEQTR_AVAL */
+#endif /* __DBG_LINK2_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.dbg_link2 */
+#ifndef __CFG_REG4_MACRO__
+#define __CFG_REG4_MACRO__
+
+/* macros for field RXDETECT_QUIET_TIMEOUT */
+#endif /* __CFG_REG4_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg4 */
+#ifndef __CFG_REG5_MACRO__
+#define __CFG_REG5_MACRO__
+
+/* macros for field U3_HDSK_FAIL_TIMEOUT */
+#endif /* __CFG_REG5_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg5 */
+#ifndef __CFG_REG6_MACRO__
+#define __CFG_REG6_MACRO__
+
+/* macros for field SSINACTIVE_QUIET_TIMEOUT */
+#endif /* __CFG_REG6_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg6 */
+#ifndef __CFG_REG7_MACRO__
+#define __CFG_REG7_MACRO__
+
+/* macros for field POLLING_LFPS_TIMEOUT */
+#endif /* __CFG_REG7_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg7 */
+#ifndef __CFG_REG8_MACRO__
+#define __CFG_REG8_MACRO__
+
+/* macros for field POLLING_ACTIVE_TIMEOUT */
+#endif /* __CFG_REG8_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg8 */
+#ifndef __CFG_REG9_MACRO__
+#define __CFG_REG9_MACRO__
+
+/* macros for field POLLING_IDLE_TIMEOUT */
+#endif /* __CFG_REG9_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg9 */
+#ifndef __CFG_REG10_MACRO__
+#define __CFG_REG10_MACRO__
+
+/* macros for field POLLING_CONF_TIMEOUT */
+#endif /* __CFG_REG10_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg10 */
+#ifndef __CFG_REG11_MACRO__
+#define __CFG_REG11_MACRO__
+
+/* macros for field RECOVERY_ACTIVE_TIMEOUT */
+#endif /* __CFG_REG11_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg11 */
+#ifndef __CFG_REG12_MACRO__
+#define __CFG_REG12_MACRO__
+
+/* macros for field RECOVERY_CONF_TIMEOUT */
+#endif /* __CFG_REG12_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg12 */
+#ifndef __CFG_REG13_MACRO__
+#define __CFG_REG13_MACRO__
+
+/* macros for field RECOVERY_IDLE_TIMEOUT */
+#endif /* __CFG_REG13_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg13 */
+#ifndef __CFG_REG14_MACRO__
+#define __CFG_REG14_MACRO__
+
+/* macros for field HOTRESET_ACTIVE_TIMEOUT */
+#endif /* __CFG_REG14_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg14 */
+#ifndef __CFG_REG15_MACRO__
+#define __CFG_REG15_MACRO__
+
+/* macros for field HOTRESET_EXIT_TIMEOUT */
+#endif /* __CFG_REG15_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg15 */
+#ifndef __CFG_REG16_MACRO__
+#define __CFG_REG16_MACRO__
+
+/* macros for field LFPS_PING_REPEAT */
+#endif /* __CFG_REG16_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg16 */
+#ifndef __CFG_REG17_MACRO__
+#define __CFG_REG17_MACRO__
+
+/* macros for field PENDING_HP_TIMEOUT */
+#endif /* __CFG_REG17_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg17 */
+#ifndef __CFG_REG18_MACRO__
+#define __CFG_REG18_MACRO__
+
+/* macros for field CREDIT_HP_TIMEOUT */
+#endif /* __CFG_REG18_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg18 */
+#ifndef __CFG_REG19_MACRO__
+#define __CFG_REG19_MACRO__
+
+/* macros for field LUP_TIMEOUT */
+#endif /* __CFG_REG19_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg19 */
+#ifndef __CFG_REG20_MACRO__
+#define __CFG_REG20_MACRO__
+
+/* macros for field LDN_TIMEOUT */
+#endif /* __CFG_REG20_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg20 */
+#ifndef __CFG_REG21_MACRO__
+#define __CFG_REG21_MACRO__
+
+/* macros for field PM_LC_TIMEOUT */
+#endif /* __CFG_REG21_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg21 */
+#ifndef __CFG_REG22_MACRO__
+#define __CFG_REG22_MACRO__
+
+/* macros for field PM_ENTRY_TIMEOUT */
+#endif /* __CFG_REG22_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg22 */
+#ifndef __CFG_REG23_MACRO__
+#define __CFG_REG23_MACRO__
+
+/* macros for field UX_EXIT_TIMEOUT */
+#endif /* __CFG_REG23_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg23 */
+#ifndef __CFG_REG24_MACRO__
+#define __CFG_REG24_MACRO__
+
+/* macros for field LFPS_DET_RESET_MIN */
+#endif /* __CFG_REG24_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg24 */
+#ifndef __CFG_REG25_MACRO__
+#define __CFG_REG25_MACRO__
+
+/* macros for field LFPS_DET_RESET_MAX */
+#endif /* __CFG_REG25_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg25 */
+#ifndef __CFG_REG26_MACRO__
+#define __CFG_REG26_MACRO__
+
+/* macros for field LFPS_DET_POLLING_MIN */
+#endif /* __CFG_REG26_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg26 */
+#ifndef __CFG_REG27_MACRO__
+#define __CFG_REG27_MACRO__
+
+/* macros for field LFPS_DET_POLLING_MAX */
+#endif /* __CFG_REG27_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg27 */
+#ifndef __CFG_REG28_MACRO__
+#define __CFG_REG28_MACRO__
+
+/* macros for field LFPS_DET_PING_MIN */
+#endif /* __CFG_REG28_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg28 */
+#ifndef __CFG_REG29_MACRO__
+#define __CFG_REG29_MACRO__
+
+/* macros for field LFPS_DET_PING_MAX */
+#endif /* __CFG_REG29_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg29 */
+#ifndef __CFG_REG30_MACRO__
+#define __CFG_REG30_MACRO__
+
+/* macros for field LFPS_DET_U1EXIT_MIN */
+#endif /* __CFG_REG30_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg30 */
+#ifndef __CFG_REG31_MACRO__
+#define __CFG_REG31_MACRO__
+
+/* macros for field LFPS_DET_U1EXIT_MAX */
+#endif /* __CFG_REG31_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg31 */
+#ifndef __CFG_REG32_MACRO__
+#define __CFG_REG32_MACRO__
+
+/* macros for field LFPS_DET_U2EXIT_MIN */
+#endif /* __CFG_REG32_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg32 */
+#ifndef __CFG_REG33_MACRO__
+#define __CFG_REG33_MACRO__
+
+/* macros for field LFPS_DET_U2EXIT_MAX */
+#endif /* __CFG_REG33_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg33 */
+#ifndef __CFG_REG34_MACRO__
+#define __CFG_REG34_MACRO__
+
+/* macros for field LFPS_DET_U3EXIT_MIN */
+#endif /* __CFG_REG34_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg34 */
+#ifndef __CFG_REG35_MACRO__
+#define __CFG_REG35_MACRO__
+
+/* macros for field LFPS_DET_U3EXIT_MAX */
+#endif /* __CFG_REG35_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg35 */
+#ifndef __CFG_REG36_MACRO__
+#define __CFG_REG36_MACRO__
+
+/* macros for field LFPS_GEN_PING */
+#endif /* __CFG_REG36_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg36 */
+#ifndef __CFG_REG37_MACRO__
+#define __CFG_REG37_MACRO__
+
+/* macros for field LFPS_GEN_POLLING */
+#endif /* __CFG_REG37_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg37 */
+#ifndef __CFG_REG38_MACRO__
+#define __CFG_REG38_MACRO__
+
+/* macros for field LFPS_GEN_U1EXIT */
+#endif /* __CFG_REG38_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg38 */
+#ifndef __CFG_REG39_MACRO__
+#define __CFG_REG39_MACRO__
+
+/* macros for field LFPS_GEN_U3EXIT */
+#endif /* __CFG_REG39_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg39 */
+#ifndef __CFG_REG40_MACRO__
+#define __CFG_REG40_MACRO__
+
+/* macros for field LFPS_MIN_GEN_U1EXIT */
+#endif /* __CFG_REG40_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg40 */
+#ifndef __CFG_REG41_MACRO__
+#define __CFG_REG41_MACRO__
+
+/* macros for field LFPS_MIN_GEN_U2EXIT */
+#endif /* __CFG_REG41_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg41 */
+#ifndef __CFG_REG42_MACRO__
+#define __CFG_REG42_MACRO__
+
+/* macros for field LFPS_POLLING_REPEAT */
+#endif /* __CFG_REG42_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg42 */
+#ifndef __CFG_REG43_MACRO__
+#define __CFG_REG43_MACRO__
+
+/* macros for field LFPS_POLLING_MAX_TREPEAT */
+#endif /* __CFG_REG43_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg43 */
+#ifndef __CFG_REG44_MACRO__
+#define __CFG_REG44_MACRO__
+
+/* macros for field LFPS_POLLING_MIN_TREPEAT */
+#endif /* __CFG_REG44_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg44 */
+#ifndef __CFG_REG45_MACRO__
+#define __CFG_REG45_MACRO__
+
+/* macros for field ITP_WAKEUP_TIMEOUT */
+#endif /* __CFG_REG45_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg45 */
+#ifndef __CFG_REG46_MACRO__
+#define __CFG_REG46_MACRO__
+
+/* macros for field TSEQ_QUANTITY */
+#endif /* __CFG_REG46_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg46 */
+#ifndef __CFG_REG47_MACRO__
+#define __CFG_REG47_MACRO__
+
+/* macros for field ERDY_TIMEOUT_CNT */
+#endif /* __CFG_REG47_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg47 */
+#ifndef __CFG_REG48_MACRO__
+#define __CFG_REG48_MACRO__
+
+/* macros for field TWTRSTFS_J_CNT */
+#endif /* __CFG_REG48_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg48 */
+#ifndef __CFG_REG49_MACRO__
+#define __CFG_REG49_MACRO__
+
+/* macros for field TUCH_CNT */
+#endif /* __CFG_REG49_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg49 */
+#ifndef __CFG_REG50_MACRO__
+#define __CFG_REG50_MACRO__
+
+/* macros for field TWAITCHK_CNT */
+#endif /* __CFG_REG50_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg50 */
+#ifndef __CFG_REG51_MACRO__
+#define __CFG_REG51_MACRO__
+
+/* macros for field TWTFS_CNT */
+#endif /* __CFG_REG51_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg51 */
+#ifndef __CFG_REG52_MACRO__
+#define __CFG_REG52_MACRO__
+
+/* macros for field TWTREV_CNT */
+#endif /* __CFG_REG52_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg52 */
+#ifndef __CFG_REG53_MACRO__
+#define __CFG_REG53_MACRO__
+
+/* macros for field TWTRSTHS_CNT */
+#endif /* __CFG_REG53_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg53 */
+#ifndef __CFG_REG54_MACRO__
+#define __CFG_REG54_MACRO__
+
+/* macros for field TWTRSM_CNT */
+#endif /* __CFG_REG54_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg54 */
+#ifndef __CFG_REG55_MACRO__
+#define __CFG_REG55_MACRO__
+
+/* macros for field TDRSMUP_CNT */
+#endif /* __CFG_REG55_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg55 */
+#ifndef __CFG_REG56_MACRO__
+#define __CFG_REG56_MACRO__
+
+/* macros for field TOUTHS_CNT */
+#endif /* __CFG_REG56_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg56 */
+#ifndef __CFG_REG57_MACRO__
+#define __CFG_REG57_MACRO__
+
+/* macros for field LFPS_DEB_WIDTH */
+#endif /* __CFG_REG57_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg57 */
+#ifndef __CFG_REG58_MACRO__
+#define __CFG_REG58_MACRO__
+
+/* macros for field LFPS_GEN_U2EXIT */
+#endif /* __CFG_REG58_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg58 */
+#ifndef __CFG_REG59_MACRO__
+#define __CFG_REG59_MACRO__
+
+/* macros for field LFPS_MIN_GEN_U3EXIT */
+#endif /* __CFG_REG59_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg59 */
+#ifndef __CFG_REG60_MACRO__
+#define __CFG_REG60_MACRO__
+
+/* macros for field PORT_CONFIG_TIMEOUT */
+#endif /* __CFG_REG60_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg60 */
+#ifndef __CFG_REG61_MACRO__
+#define __CFG_REG61_MACRO__
+
+/* macros for field LFPS_POL_LFPS_TO_RXEQ */
+#endif /* __CFG_REG61_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg61 */
+#ifndef __CFG_REG62_MACRO__
+#define __CFG_REG62_MACRO__
+
+/* macros for field PHY_TX_LATENCY */
+#endif /* __CFG_REG62_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg62 */
+#ifndef __CFG_REG63_MACRO__
+#define __CFG_REG63_MACRO__
+
+/* macros for field U2_INACTIVITY_TMOUT */
+#endif /* __CFG_REG63_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg63 */
+#ifndef __CFG_REG64_MACRO__
+#define __CFG_REG64_MACRO__
+
+/* macros for field TFILTSE0 */
+#endif /* __CFG_REG64_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg64 */
+#ifndef __CFG_REG65_MACRO__
+#define __CFG_REG65_MACRO__
+
+/* macros for field TFILT */
+#endif /* __CFG_REG65_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg65 */
+#ifndef __CFG_REG66_MACRO__
+#define __CFG_REG66_MACRO__
+
+/* macros for field TWTRSTFS_SE0 */
+#endif /* __CFG_REG66_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.cfg_reg66 */
+#ifndef __DMA_AXI_CTRL_MACRO__
+#define __DMA_AXI_CTRL_MACRO__
+
+/* macros for field MAWPROT */
+#endif /* __DMA_AXI_CTRL_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.dma_axi_ctrl */
+#ifndef __DMA_AXI_ID_MACRO__
+#define __DMA_AXI_ID_MACRO__
+
+/* macros for field MAW_ID */
+#endif /* __DMA_AXI_ID_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.dma_axi_id */
+#ifndef __DMA_AXI_CAP_MACRO__
+#define __DMA_AXI_CAP_MACRO__
+
+/* macros for field RESERVED0 */
+#endif /* __DMA_AXI_CAP_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.dma_axi_cap */
+#ifndef __DMA_AXI_CTRL0_MACRO__
+#define __DMA_AXI_CTRL0_MACRO__
+
+/* macros for field B_MAX */
+#endif /* __DMA_AXI_CTRL0_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.dma_axi_ctrl0 */
+#ifndef __DMA_AXI_CTRL1_MACRO__
+#define __DMA_AXI_CTRL1_MACRO__
+
+/* macros for field ROT */
+#endif /* __DMA_AXI_CTRL1_MACRO__ */
+
+
+/* macros for usbss_dev_register_block.dma_axi_ctrl1 */
+#endif /* __REG_USBSS_DEV_ADDR_MAP_MACRO_H__ */
diff --git a/drivers/usb/cdns3/dev-regs-map.h b/drivers/usb/cdns3/dev-regs-map.h
new file mode 100644
index 000000000000..ef9cfe2ff342
--- /dev/null
+++ b/drivers/usb/cdns3/dev-regs-map.h
@@ -0,0 +1,126 @@
+/**
+ * dev-regs-map.h - Cadence USB3 Device register map definition
+ *
+ * Copyright (C) 2016 Cadence Design Systems - http://www.cadence.com
+ * Copyright 2017 NXP
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+
+#ifndef __REG_USBSS_DEV_ADDR_MAP_H__
+#define __REG_USBSS_DEV_ADDR_MAP_H__
+
+#include "dev-regs-macro.h"
+
+struct usbss_dev_register_block_type {
+ uint32_t usb_conf; /* 0x0 - 0x4 */
+ uint32_t usb_sts; /* 0x4 - 0x8 */
+ uint32_t usb_cmd; /* 0x8 - 0xc */
+ uint32_t usb_iptn; /* 0xc - 0x10 */
+ uint32_t usb_lpm; /* 0x10 - 0x14 */
+ uint32_t usb_ien; /* 0x14 - 0x18 */
+ uint32_t usb_ists; /* 0x18 - 0x1c */
+ uint32_t ep_sel; /* 0x1c - 0x20 */
+ uint32_t ep_traddr; /* 0x20 - 0x24 */
+ uint32_t ep_cfg; /* 0x24 - 0x28 */
+ uint32_t ep_cmd; /* 0x28 - 0x2c */
+ uint32_t ep_sts; /* 0x2c - 0x30 */
+ uint32_t ep_sts_sid; /* 0x30 - 0x34 */
+ uint32_t ep_sts_en; /* 0x34 - 0x38 */
+ uint32_t drbl; /* 0x38 - 0x3c */
+ uint32_t ep_ien; /* 0x3c - 0x40 */
+ uint32_t ep_ists; /* 0x40 - 0x44 */
+ uint32_t usb_pwr; /* 0x44 - 0x48 */
+ uint32_t usb_conf2; /* 0x48 - 0x4c */
+ uint32_t usb_cap1; /* 0x4c - 0x50 */
+ uint32_t usb_cap2; /* 0x50 - 0x54 */
+ uint32_t usb_cap3; /* 0x54 - 0x58 */
+ uint32_t usb_cap4; /* 0x58 - 0x5c */
+ uint32_t usb_cap5; /* 0x5c - 0x60 */
+ uint32_t PAD2_73; /* 0x60 - 0x64 */
+ uint32_t usb_cpkt1; /* 0x64 - 0x68 */
+ uint32_t usb_cpkt2; /* 0x68 - 0x6c */
+ uint32_t usb_cpkt3; /* 0x6c - 0x70 */
+ char pad__0[0x90]; /* 0x70 - 0x100 */
+ uint32_t PAD2_78; /* 0x100 - 0x104 */
+ uint32_t dbg_link1; /* 0x104 - 0x108 */
+ uint32_t PAD2_80; /* 0x108 - 0x10c */
+ uint32_t PAD2_81; /* 0x10c - 0x110 */
+ uint32_t PAD2_82; /* 0x110 - 0x114 */
+ uint32_t PAD2_83; /* 0x114 - 0x118 */
+ uint32_t PAD2_84; /* 0x118 - 0x11c */
+ uint32_t PAD2_85; /* 0x11c - 0x120 */
+ uint32_t PAD2_86; /* 0x120 - 0x124 */
+ uint32_t PAD2_87; /* 0x124 - 0x128 */
+ uint32_t PAD2_88; /* 0x128 - 0x12c */
+ uint32_t PAD2_89; /* 0x12c - 0x130 */
+ uint32_t PAD2_90; /* 0x130 - 0x134 */
+ uint32_t PAD2_91; /* 0x134 - 0x138 */
+ uint32_t PAD2_92; /* 0x138 - 0x13c */
+ uint32_t PAD2_93; /* 0x13c - 0x140 */
+ uint32_t PAD2_94; /* 0x140 - 0x144 */
+ uint32_t PAD2_95; /* 0x144 - 0x148 */
+ uint32_t PAD2_96; /* 0x148 - 0x14c */
+ uint32_t PAD2_97; /* 0x14c - 0x150 */
+ uint32_t PAD2_98; /* 0x150 - 0x154 */
+ uint32_t PAD2_99; /* 0x154 - 0x158 */
+ uint32_t PAD2_100; /* 0x158 - 0x15c */
+ uint32_t PAD2_101; /* 0x15c - 0x160 */
+ uint32_t PAD2_102; /* 0x160 - 0x164 */
+ uint32_t PAD2_103; /* 0x164 - 0x168 */
+ uint32_t PAD2_104; /* 0x168 - 0x16c */
+ uint32_t PAD2_105; /* 0x16c - 0x170 */
+ uint32_t PAD2_106; /* 0x170 - 0x174 */
+ uint32_t PAD2_107; /* 0x174 - 0x178 */
+ uint32_t PAD2_108; /* 0x178 - 0x17c */
+ uint32_t PAD2_109; /* 0x17c - 0x180 */
+ uint32_t PAD2_110; /* 0x180 - 0x184 */
+ uint32_t PAD2_111; /* 0x184 - 0x188 */
+ uint32_t PAD2_112; /* 0x188 - 0x18c */
+ char pad__1[0x20]; /* 0x18c - 0x1ac */
+ uint32_t PAD2_114; /* 0x1ac - 0x1b0 */
+ uint32_t PAD2_115; /* 0x1b0 - 0x1b4 */
+ uint32_t PAD2_116; /* 0x1b4 - 0x1b8 */
+ uint32_t PAD2_117; /* 0x1b8 - 0x1bc */
+ uint32_t PAD2_118; /* 0x1bc - 0x1c0 */
+ uint32_t PAD2_119; /* 0x1c0 - 0x1c4 */
+ uint32_t PAD2_120; /* 0x1c4 - 0x1c8 */
+ uint32_t PAD2_121; /* 0x1c8 - 0x1cc */
+ uint32_t PAD2_122; /* 0x1cc - 0x1d0 */
+ uint32_t PAD2_123; /* 0x1d0 - 0x1d4 */
+ uint32_t PAD2_124; /* 0x1d4 - 0x1d8 */
+ uint32_t PAD2_125; /* 0x1d8 - 0x1dc */
+ uint32_t PAD2_126; /* 0x1dc - 0x1e0 */
+ uint32_t PAD2_127; /* 0x1e0 - 0x1e4 */
+ uint32_t PAD2_128; /* 0x1e4 - 0x1e8 */
+ uint32_t PAD2_129; /* 0x1e8 - 0x1ec */
+ uint32_t PAD2_130; /* 0x1ec - 0x1f0 */
+ uint32_t PAD2_131; /* 0x1f0 - 0x1f4 */
+ uint32_t PAD2_132; /* 0x1f4 - 0x1f8 */
+ uint32_t PAD2_133; /* 0x1f8 - 0x1fc */
+ uint32_t PAD2_134; /* 0x1fc - 0x200 */
+ uint32_t PAD2_135; /* 0x200 - 0x204 */
+ uint32_t PAD2_136; /* 0x204 - 0x208 */
+ uint32_t PAD2_137; /* 0x208 - 0x20c */
+ uint32_t PAD2_138; /* 0x20c - 0x210 */
+ uint32_t PAD2_139; /* 0x210 - 0x214 */
+ uint32_t PAD2_140; /* 0x214 - 0x218 */
+ uint32_t PAD2_141; /* 0x218 - 0x21c */
+ uint32_t PAD2_142; /* 0x21c - 0x220 */
+ uint32_t PAD2_143; /* 0x220 - 0x224 */
+ uint32_t PAD2_144; /* 0x224 - 0x228 */
+ char pad__2[0xd8]; /* 0x228 - 0x300 */
+ uint32_t dma_axi_ctrl; /* 0x300 - 0x304 */
+ uint32_t PAD2_147; /* 0x304 - 0x308 */
+ uint32_t PAD2_148; /* 0x308 - 0x30c */
+ uint32_t PAD2_149; /* 0x30c - 0x310 */
+ uint32_t PAD2_150; /* 0x310 - 0x314 */
+};
+
+#endif /* __REG_USBSS_DEV_ADDR_MAP_H__ */
diff --git a/drivers/usb/cdns3/gadget-export.h b/drivers/usb/cdns3/gadget-export.h
new file mode 100644
index 000000000000..e085ed38ea05
--- /dev/null
+++ b/drivers/usb/cdns3/gadget-export.h
@@ -0,0 +1,36 @@
+/*
+ * gadget-export.h - Gadget Export APIs
+ *
+ * Copyright 2017 NXP
+ * Authors: Peter Chen <peter.chen@nxp.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __CDNS3_GADGET_EXPORT_H
+#define __CDNS3_GADGET_EXPORT_H
+
+#ifdef CONFIG_USB_CDNS3_GADGET
+
+int cdns3_gadget_init(struct cdns3 *cdns);
+void cdns3_gadget_remove(struct cdns3 *cdns);
+#else
+
+static inline int cdns3_gadget_init(struct cdns3 *cdns)
+{
+ return -ENXIO;
+}
+
+static inline void cdns3_gadget_remove(struct cdns3 *cdns)
+{
+
+}
+
+#endif
+
+#endif /* __CDNS3_GADGET_EXPORT_H */
diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c
new file mode 100644
index 000000000000..b3d81aabe9c3
--- /dev/null
+++ b/drivers/usb/cdns3/gadget.c
@@ -0,0 +1,2526 @@
+/**
+ * gadget.c - Cadence USB3 Device Core file
+ *
+ * Copyright (C) 2016 Cadence Design Systems - http://www.cadence.com
+ * Copyright 2017 NXP
+ *
+ * Authors: Pawel Jez <pjez@cadence.com>,
+ * Konrad Kociolek <konrad@cadence.com>
+ * Peter Chen <peter.chen@nxp.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/composite.h>
+#include <linux/of_platform.h>
+#include <linux/usb/gadget.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/byteorder/generic.h>
+#include <linux/ctype.h>
+
+#include "core.h"
+#include "gadget-export.h"
+#include "gadget.h"
+#include "io.h"
+
+/*-------------------------------------------------------------------------*/
+/* Function declarations */
+
+static void select_ep(struct usb_ss_dev *usb_ss, u32 ep);
+static int usb_ss_allocate_trb_pool(struct usb_ss_endpoint *usb_ss_ep);
+static void cdns_ep_stall_flush(struct usb_ss_endpoint *usb_ss_ep);
+static void cdns_ep0_config(struct usb_ss_dev *usb_ss);
+static void cdns_gadget_unconfig(struct usb_ss_dev *usb_ss);
+static void cdns_ep0_run_transfer(struct usb_ss_dev *usb_ss,
+ dma_addr_t dma_addr, unsigned int length, int erdy);
+static int cdns_ep_run_transfer(struct usb_ss_endpoint *usb_ss_ep);
+static int cdns_get_setup_ret(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req);
+static int cdns_req_ep0_set_address(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req);
+static int cdns_req_ep0_get_status(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req);
+static int cdns_req_ep0_handle_feature(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req, int set);
+static int cdns_req_ep0_set_sel(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req);
+static int cdns_req_ep0_set_isoch_delay(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req);
+static int cdns_req_ep0_set_configuration(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req);
+static int cdns_ep0_standard_request(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req);
+static void cdns_ep0_setup_phase(struct usb_ss_dev *usb_ss);
+static int cdns_check_ep_interrupt_proceed(struct usb_ss_endpoint *usb_ss_ep);
+static void cdns_check_ep0_interrupt_proceed(struct usb_ss_dev *usb_ss,
+ int dir);
+static void cdns_check_usb_interrupt_proceed(struct usb_ss_dev *usb_ss,
+ u32 usb_ists);
+static int usb_ss_gadget_ep0_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc);
+static int usb_ss_gadget_ep0_disable(struct usb_ep *ep);
+static int usb_ss_gadget_ep0_set_halt(struct usb_ep *ep, int value);
+static int usb_ss_gadget_ep0_queue(struct usb_ep *ep,
+ struct usb_request *request, gfp_t gfp_flags);
+static int usb_ss_gadget_ep_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc);
+static int usb_ss_gadget_ep_disable(struct usb_ep *ep);
+static struct usb_request *usb_ss_gadget_ep_alloc_request(struct usb_ep *ep,
+ gfp_t gfp_flags);
+static void usb_ss_gadget_ep_free_request(struct usb_ep *ep,
+ struct usb_request *request);
+static int usb_ss_gadget_ep_queue(struct usb_ep *ep,
+ struct usb_request *request, gfp_t gfp_flags);
+static int usb_ss_gadget_ep_dequeue(struct usb_ep *ep,
+ struct usb_request *request);
+static int usb_ss_gadget_ep_set_halt(struct usb_ep *ep, int value);
+static int usb_ss_gadget_ep_set_wedge(struct usb_ep *ep);
+static int usb_ss_gadget_get_frame(struct usb_gadget *gadget);
+static int usb_ss_gadget_wakeup(struct usb_gadget *gadget);
+static int usb_ss_gadget_set_selfpowered(struct usb_gadget *gadget,
+ int is_selfpowered);
+static int usb_ss_gadget_pullup(struct usb_gadget *gadget, int is_on);
+static int usb_ss_gadget_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int usb_ss_gadget_udc_stop(struct usb_gadget *gadget);
+static int usb_ss_init_ep(struct usb_ss_dev *usb_ss);
+static int usb_ss_init_ep0(struct usb_ss_dev *usb_ss);
+static void __cdns3_gadget_start(struct usb_ss_dev *usb_ss);
+static void cdns_prepare_setup_packet(struct usb_ss_dev *usb_ss);
+static void cdns_ep_config(struct usb_ss_endpoint *usb_ss_ep);
+static void cdns_enable_l1(struct usb_ss_dev *usb_ss, int enable);
+static void __pending_setup_status_handler(struct usb_ss_dev *usb_ss);
+
+static struct usb_endpoint_descriptor cdns3_gadget_ep0_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+};
+
+static u32 gadget_readl(struct usb_ss_dev *usb_ss, uint32_t __iomem *reg)
+{
+ return cdns_readl(reg);
+}
+
+static void gadget_writel(struct usb_ss_dev *usb_ss,
+ uint32_t __iomem *reg, u32 value)
+{
+ cdns_writel(reg, value);
+}
+
+/**
+ * next_request - returns next request from list
+ * @list: list containing requests
+ *
+ * Returns request or NULL if no requests in list
+ */
+static struct usb_request *next_request(struct list_head *list)
+{
+ if (list_empty(list))
+ return NULL;
+ return list_first_entry(list, struct usb_request, list);
+}
+
+/**
+ * wait_reg_bit - Read reg and compare until equal to specific value
+ * @reg: the register address to read
+ * @value: the value to compare
+ * @wait_value: 0 or 1
+ * @timeout_ms: timeout value in milliseconds, must be larger than 1
+ *
+ * Returns -ETIMEDOUT if timeout occurs
+ */
+static int wait_reg_bit(struct usb_ss_dev *usb_ss, u32 __iomem *reg,
+ u32 value, int wait_value, int timeout_ms)
+{
+ u32 temp;
+
+ WARN_ON(timeout_ms <= 0);
+ timeout_ms *= 100;
+ temp = cdns_readl(reg);
+ while (timeout_ms-- > 0) {
+ if (!!(temp & value) == wait_value)
+ return 0;
+ temp = cdns_readl(reg);
+ udelay(10);
+ }
+
+ dev_err(&usb_ss->dev, "wait register timeout %s\n", __func__);
+ return -ETIMEDOUT;
+}
+
+static int wait_reg_bit_set(struct usb_ss_dev *usb_ss, u32 __iomem *reg,
+ u32 value, int timeout_ms)
+{
+ return wait_reg_bit(usb_ss, reg, value, 1, timeout_ms);
+}
+
+static int wait_reg_bit_clear(struct usb_ss_dev *usb_ss, u32 __iomem *reg,
+ u32 value, int timeout_ms)
+{
+ return wait_reg_bit(usb_ss, reg, value, 0, timeout_ms);
+}
+
+/**
+ * select_ep - selects endpoint
+ * @usb_ss: extended gadget object
+ * @ep: endpoint address
+ */
+static void select_ep(struct usb_ss_dev *usb_ss, u32 ep)
+{
+ if (!usb_ss || !usb_ss->regs) {
+ dev_err(&usb_ss->dev, "Failed to select endpoint!\n");
+ return;
+ }
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_sel, ep);
+}
+
+/**
+ * usb_ss_allocate_trb_pool - Allocates TRB's pool for selected endpoint
+ * @usb_ss_ep: extended endpoint object
+ *
+ * Function will return 0 on success or -ENOMEM on allocation error
+ */
+static int usb_ss_allocate_trb_pool(struct usb_ss_endpoint *usb_ss_ep)
+{
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+
+ if (!usb_ss_ep->trb_pool) {
+ usb_ss_ep->trb_pool = dma_zalloc_coherent(usb_ss->sysdev,
+ sizeof(struct usb_ss_trb) * USB_SS_TRBS_NUM,
+ &usb_ss_ep->trb_pool_dma, GFP_DMA);
+ if (!usb_ss_ep->trb_pool)
+ return -ENOMEM;
+ }
+
+ if (!usb_ss_ep->cpu_addr) {
+ usb_ss_ep->cpu_addr = dma_alloc_coherent(usb_ss->sysdev,
+ CDNS3_UNALIGNED_BUF_SIZE,
+ &usb_ss_ep->dma_addr, GFP_DMA);
+ if (!usb_ss_ep->cpu_addr)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * cdns_data_flush - do flush data at onchip buffer
+ * @usb_ss_ep: extended endpoint object
+ *
+ * Endpoint must be selected before call to this function
+ *
+ * Returns zero on success or negative value on failure
+ */
+static int cdns_data_flush(struct usb_ss_endpoint *usb_ss_ep)
+{
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__DFLUSH__MASK);
+ /* wait for DFLUSH cleared */
+ return wait_reg_bit_clear(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__DFLUSH__MASK, 100);
+}
+
+/**
+ * cdns_ep_stall_flush - Stalls and flushes selected endpoint
+ * @usb_ss_ep: extended endpoint object
+ *
+ * Endpoint must be selected before call to this function
+ */
+static void cdns_ep_stall_flush(struct usb_ss_endpoint *usb_ss_ep)
+{
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__DFLUSH__MASK | EP_CMD__ERDY__MASK |
+ EP_CMD__SSTALL__MASK);
+
+ /* wait for DFLUSH cleared */
+ wait_reg_bit_clear(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__DFLUSH__MASK, 100);
+ usb_ss_ep->stalled_flag = 1;
+}
+
+/**
+ * cdns_ep0_config - Configures default endpoint
+ * @usb_ss: extended gadget object
+ *
+ * Functions sets parameters: maximal packet size and enables interrupts
+ */
+static void cdns_ep0_config(struct usb_ss_dev *usb_ss)
+{
+ u32 reg, max_packet_size = 0;
+
+ switch (usb_ss->gadget.speed) {
+ case USB_SPEED_UNKNOWN:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_0;
+ usb_ss->gadget.ep0->maxpacket = ENDPOINT_MAX_PACKET_SIZE_0;
+ cdns3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(0);
+ break;
+
+ case USB_SPEED_LOW:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_8;
+ usb_ss->gadget.ep0->maxpacket = ENDPOINT_MAX_PACKET_SIZE_8;
+ cdns3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8);
+ break;
+
+ case USB_SPEED_FULL:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_64;
+ usb_ss->gadget.ep0->maxpacket = ENDPOINT_MAX_PACKET_SIZE_64;
+ cdns3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+ break;
+
+ case USB_SPEED_HIGH:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_64;
+ usb_ss->gadget.ep0->maxpacket = ENDPOINT_MAX_PACKET_SIZE_64;
+ cdns3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+ break;
+
+ case USB_SPEED_WIRELESS:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_64;
+ usb_ss->gadget.ep0->maxpacket = ENDPOINT_MAX_PACKET_SIZE_64;
+ cdns3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+ break;
+
+ case USB_SPEED_SUPER:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_512;
+ usb_ss->gadget.ep0->maxpacket = ENDPOINT_MAX_PACKET_SIZE_512;
+ cdns3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+ break;
+
+ case USB_SPEED_SUPER_PLUS:
+ dev_warn(&usb_ss->dev, "USB 3.1 is not supported\n");
+ usb_ss->gadget.ep0->maxpacket = ENDPOINT_MAX_PACKET_SIZE_512;
+ cdns3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_512;
+ break;
+ }
+
+ /* init ep out */
+ select_ep(usb_ss, USB_DIR_OUT);
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cfg,
+ EP_CFG__ENABLE__MASK |
+ EP_CFG__MAXPKTSIZE__WRITE(max_packet_size));
+ gadget_writel(usb_ss, &usb_ss->regs->ep_sts_en,
+ EP_STS_EN__SETUPEN__MASK |
+ EP_STS_EN__DESCMISEN__MASK |
+ EP_STS_EN__TRBERREN__MASK);
+
+ /* init ep in */
+ select_ep(usb_ss, USB_DIR_IN);
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cfg,
+ EP_CFG__ENABLE__MASK |
+ EP_CFG__MAXPKTSIZE__WRITE(max_packet_size));
+ gadget_writel(usb_ss, &usb_ss->regs->ep_sts_en,
+ EP_STS_EN__SETUPEN__MASK |
+ EP_STS_EN__TRBERREN__MASK);
+
+ reg = gadget_readl(usb_ss, &usb_ss->regs->usb_conf);
+ reg |= USB_CONF__U1DS__MASK | USB_CONF__U2DS__MASK;
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf, reg);
+
+ cdns_prepare_setup_packet(usb_ss);
+}
+
+/**
+ * cdns_gadget_unconfig - Unconfigures device controller
+ * @usb_ss: extended gadget object
+ */
+static void cdns_gadget_unconfig(struct usb_ss_dev *usb_ss)
+{
+ /* RESET CONFIGURATION */
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__CFGRST__MASK);
+
+ cdns_enable_l1(usb_ss, 0);
+ usb_ss->hw_configured_flag = 0;
+ usb_ss->onchip_mem_allocated_size = 0;
+ usb_ss->out_mem_is_allocated = 0;
+}
+
+/**
+ * cdns_ep0_run_transfer - Do transfer on default endpoint hardware
+ * @usb_ss: extended gadget object
+ * @dma_addr: physical address where data is/will be stored
+ * @length: data length
+ * @erdy: set it to 1 when ERDY packet should be sent -
+ * exit from flow control state
+ */
+static void cdns_ep0_run_transfer(struct usb_ss_dev *usb_ss,
+ dma_addr_t dma_addr, unsigned int length, int erdy)
+{
+ usb_ss->trb_ep0[0] = TRB_SET_DATA_BUFFER_POINTER(dma_addr);
+ usb_ss->trb_ep0[1] = TRB_SET_TRANSFER_LENGTH((u32)length);
+ usb_ss->trb_ep0[2] = TRB_SET_CYCLE_BIT |
+ TRB_SET_INT_ON_COMPLETION | TRB_TYPE_NORMAL;
+
+ dev_dbg(&usb_ss->dev, "DRBL(%02X)\n",
+ usb_ss->ep0_data_dir ? USB_DIR_IN : USB_DIR_OUT);
+
+ select_ep(usb_ss, usb_ss->ep0_data_dir
+ ? USB_DIR_IN : USB_DIR_OUT);
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_traddr,
+ EP_TRADDR__TRADDR__WRITE(usb_ss->trb_ep0_dma));
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__DRDY__MASK); /* drbl */
+
+ if (erdy)
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__ERDY__MASK);
+}
+
+/**
+ * cdns_ep_run_transfer - Do transfer on no-default endpoint hardware
+ * @usb_ss_ep: extended endpoint object
+ *
+ * Returns zero on success or negative value on failure
+ */
+static int cdns_ep_run_transfer(struct usb_ss_endpoint *usb_ss_ep)
+{
+ dma_addr_t trb_dma;
+ struct usb_request *request = next_request(&usb_ss_ep->request_list);
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+ int sg_iter = 0;
+ struct usb_ss_trb *trb;
+
+ if (request == NULL)
+ return -EINVAL;
+
+ if (request->num_sgs > USB_SS_TRBS_NUM)
+ return -EINVAL;
+
+ dev_dbg(&usb_ss->dev, "DRBL(%02X)\n",
+ usb_ss_ep->endpoint.desc->bEndpointAddress);
+
+ usb_ss_ep->hw_pending_flag = 1;
+ trb_dma = request->dma;
+
+ /* must allocate buffer aligned to 8 */
+ if ((request->dma % ADDR_MODULO_8)) {
+ if (request->length <= CDNS3_UNALIGNED_BUF_SIZE) {
+ memcpy(usb_ss_ep->cpu_addr, request->buf,
+ request->length);
+ trb_dma = usb_ss_ep->dma_addr;
+ } else {
+ return -ENOMEM;
+ }
+ }
+
+ trb = usb_ss_ep->trb_pool;
+
+ do {
+ /* fill TRB */
+ trb->offset0 = TRB_SET_DATA_BUFFER_POINTER(request->num_sgs == 0
+ ? trb_dma : request->sg[sg_iter].dma_address);
+
+ trb->offset4 = TRB_SET_BURST_LENGTH(16) |
+ TRB_SET_TRANSFER_LENGTH(request->num_sgs == 0 ?
+ request->length : request->sg[sg_iter].length);
+
+ trb->offset8 = TRB_SET_CYCLE_BIT
+ | TRB_SET_INT_ON_COMPLETION
+ | TRB_SET_INT_ON_SHORT_PACKET
+ | TRB_TYPE_NORMAL;
+
+ ++sg_iter;
+ ++trb;
+
+ } while (sg_iter < request->num_sgs);
+
+ /* arm transfer on selected endpoint */
+ select_ep(usb_ss_ep->usb_ss,
+ usb_ss_ep->endpoint.desc->bEndpointAddress);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_traddr,
+ EP_TRADDR__TRADDR__WRITE(usb_ss_ep->trb_pool_dma));
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__DRDY__MASK); /* DRDY */
+ return 0;
+}
+
+/**
+ * cdns_get_setup_ret - Returns status of handling setup packet
+ * Setup is handled by gadget driver
+ * @usb_ss: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns zero on success or negative value on failure
+ */
+static int cdns_get_setup_ret(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req)
+{
+ int ret;
+
+ spin_unlock(&usb_ss->lock);
+ usb_ss->setup_pending = 1;
+ ret = usb_ss->gadget_driver->setup(&usb_ss->gadget, ctrl_req);
+ usb_ss->setup_pending = 0;
+ spin_lock(&usb_ss->lock);
+ return ret;
+}
+
+static void cdns_prepare_setup_packet(struct usb_ss_dev *usb_ss)
+{
+ usb_ss->ep0_data_dir = 0;
+ cdns_ep0_run_transfer(usb_ss, usb_ss->setup_dma, 8, 0);
+}
+
+/**
+ * cdns_req_ep0_set_address - Handling of SET_ADDRESS standard USB request
+ * @usb_ss: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns_req_ep0_set_address(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req)
+{
+ enum usb_device_state device_state = usb_ss->gadget.state;
+ u32 reg;
+ u32 addr;
+
+ addr = le16_to_cpu(ctrl_req->wValue);
+
+ if (addr > DEVICE_ADDRESS_MAX) {
+ dev_err(&usb_ss->dev,
+ "Device address (%d) cannot be greater than %d\n",
+ addr, DEVICE_ADDRESS_MAX);
+ return -EINVAL;
+ }
+
+ if (device_state == USB_STATE_CONFIGURED) {
+ dev_err(&usb_ss->dev, "USB device already configured\n");
+ return -EINVAL;
+ }
+
+ reg = gadget_readl(usb_ss, &usb_ss->regs->usb_cmd);
+
+ gadget_writel(usb_ss, &usb_ss->regs->usb_cmd, reg
+ | USB_CMD__FADDR__WRITE(addr)
+ | USB_CMD__SET_ADDR__MASK);
+
+ usb_gadget_set_state(&usb_ss->gadget,
+ (addr ? USB_STATE_ADDRESS : USB_STATE_DEFAULT));
+
+ cdns_prepare_setup_packet(usb_ss);
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__ERDY__MASK | EP_CMD__REQ_CMPL__MASK);
+ return 0;
+}
+
+/**
+ * cdns_req_ep0_get_status - Handling of GET_STATUS standard USB request
+ * @usb_ss: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns_req_ep0_get_status(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req)
+{
+ u16 usb_status = 0;
+ unsigned int length = 2;
+ u32 recip = ctrl_req->bRequestType & USB_RECIP_MASK;
+ u32 reg;
+
+ switch (recip) {
+
+ case USB_RECIP_DEVICE:
+ /* handling otg features */
+ if (ctrl_req->wIndex == OTG_STS_SELECTOR) {
+ length = 1;
+ usb_status = usb_ss->gadget.host_request_flag;
+ } else {
+
+ reg = gadget_readl(usb_ss, &usb_ss->regs->usb_sts);
+
+ if (reg & USB_STS__U1ENS__MASK)
+ usb_status |= 1uL << USB_DEV_STAT_U1_ENABLED;
+
+ if (reg & USB_STS__U2ENS__MASK)
+ usb_status |= 1uL << USB_DEV_STAT_U2_ENABLED;
+
+ if (usb_ss->wake_up_flag)
+ usb_status |= 1uL << USB_DEVICE_REMOTE_WAKEUP;
+
+ /* self powered */
+ usb_status |= usb_ss->gadget.is_selfpowered;
+ }
+ break;
+
+ case USB_RECIP_INTERFACE:
+ return cdns_get_setup_ret(usb_ss, ctrl_req);
+
+ case USB_RECIP_ENDPOINT:
+ /* check if endpoint is stalled */
+ select_ep(usb_ss, ctrl_req->wIndex);
+ if (gadget_readl(usb_ss, &usb_ss->regs->ep_sts)
+ & EP_STS__STALL__MASK)
+ usb_status = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ *(u16 *)usb_ss->setup = cpu_to_le16(usb_status);
+
+ usb_ss->actual_ep0_request = NULL;
+ cdns_ep0_run_transfer(usb_ss, usb_ss->setup_dma, length, 1);
+ return 0;
+}
+
+/**
+ * cdns_req_ep0_handle_feature -
+ * Handling of GET/SET_FEATURE standard USB request
+ *
+ * @usb_ss: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ * @set: must be set to 1 for SET_FEATURE request
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns_req_ep0_handle_feature(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req, int set)
+{
+ u32 recip = ctrl_req->bRequestType & USB_RECIP_MASK;
+ struct usb_ss_endpoint *usb_ss_ep;
+ u32 reg;
+ u8 tmode = 0;
+ int ret = 0;
+
+ switch (recip) {
+ case USB_RECIP_DEVICE:
+ switch (ctrl_req->wValue) {
+ case USB_DEVICE_U1_ENABLE:
+ if (usb_ss->gadget.state != USB_STATE_CONFIGURED)
+ return -EINVAL;
+ if (usb_ss->gadget.speed != USB_SPEED_SUPER)
+ return -EINVAL;
+
+ reg = gadget_readl(usb_ss, &usb_ss->regs->usb_conf);
+ if (set)
+ /* set U1EN */
+ reg |= USB_CONF__U1EN__MASK;
+ else
+ /* set U1 disable */
+ reg |= USB_CONF__U1DS__MASK;
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf, reg);
+ break;
+ case USB_DEVICE_U2_ENABLE:
+ if (usb_ss->gadget.state != USB_STATE_CONFIGURED)
+ return -EINVAL;
+ if (usb_ss->gadget.speed != USB_SPEED_SUPER)
+ return -EINVAL;
+
+ reg = gadget_readl(usb_ss, &usb_ss->regs->usb_conf);
+ if (set)
+ /* set U2EN */
+ reg |= USB_CONF__U2EN__MASK;
+ else
+ /* set U2 disable */
+ reg |= USB_CONF__U2DS__MASK;
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf, reg);
+ break;
+ case USB_DEVICE_A_ALT_HNP_SUPPORT:
+ break;
+ case USB_DEVICE_A_HNP_SUPPORT:
+ break;
+ case USB_DEVICE_B_HNP_ENABLE:
+ if (!usb_ss->gadget.b_hnp_enable && set)
+ usb_ss->gadget.b_hnp_enable = 1;
+ break;
+ case USB_DEVICE_REMOTE_WAKEUP:
+ usb_ss->wake_up_flag = !!set;
+ break;
+ case USB_DEVICE_TEST_MODE:
+ if (usb_ss->gadget.state != USB_STATE_CONFIGURED)
+ return -EINVAL;
+ if (usb_ss->gadget.speed != USB_SPEED_HIGH &&
+ usb_ss->gadget.speed != USB_SPEED_FULL)
+ return -EINVAL;
+ if (ctrl_req->wLength != 0 ||
+ ctrl_req->bRequestType & USB_DIR_IN) {
+ dev_err(&usb_ss->dev, "req is error\n");
+ return -EINVAL;
+ }
+ tmode = le16_to_cpu(ctrl_req->wIndex) >> 8;
+ switch (tmode) {
+ case TEST_J:
+ case TEST_K:
+ case TEST_SE0_NAK:
+ case TEST_PACKET:
+ reg = gadget_readl(usb_ss,
+ &usb_ss->regs->usb_cmd);
+ tmode -= 1;
+ reg |= USB_CMD__STMODE |
+ USB_CMD__TMODE_SEL(tmode);
+ gadget_writel(usb_ss, &usb_ss->regs->usb_cmd,
+ reg);
+ dev_info(&usb_ss->dev,
+ "set test mode, val=0x%x", reg);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+ break;
+ case USB_RECIP_INTERFACE:
+ return cdns_get_setup_ret(usb_ss, ctrl_req);
+ case USB_RECIP_ENDPOINT:
+ select_ep(usb_ss, ctrl_req->wIndex);
+ if (set) {
+ /* set stall */
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__SSTALL__MASK);
+
+ /* handle non zero endpoint software endpoint */
+ if (ctrl_req->wIndex & 0x7F) {
+ usb_ss_ep = usb_ss->eps[CAST_EP_ADDR_TO_INDEX(
+ ctrl_req->wIndex)];
+ usb_ss_ep->stalled_flag = 1;
+ }
+ } else {
+ struct usb_request *request;
+
+ if (ctrl_req->wIndex & 0x7F) {
+ if (usb_ss->eps[CAST_EP_ADDR_TO_INDEX(
+ ctrl_req->wIndex)]->wedge_flag)
+ goto jmp_wedge;
+ }
+
+ /* clear stall */
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__CSTALL__MASK | EP_CMD__EPRST__MASK);
+ /* wait for EPRST cleared */
+ ret = wait_reg_bit_clear(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__EPRST__MASK, 100);
+
+ /* handle non zero endpoint software endpoint */
+ if (ctrl_req->wIndex & 0x7F) {
+ usb_ss_ep = usb_ss->eps[CAST_EP_ADDR_TO_INDEX(
+ ctrl_req->wIndex)];
+ usb_ss_ep->stalled_flag = 0;
+
+ request = next_request(
+ &usb_ss_ep->request_list);
+ if (request)
+ cdns_ep_run_transfer(usb_ss_ep);
+ }
+ }
+jmp_wedge:
+ select_ep(usb_ss, 0x00);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__ERDY__MASK | EP_CMD__REQ_CMPL__MASK);
+ return ret;
+}
+
+/**
+ * cdns_req_ep0_set_sel - Handling of SET_SEL standard USB request
+ * @usb_ss: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns_req_ep0_set_sel(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req)
+{
+ if (usb_ss->gadget.state < USB_STATE_ADDRESS)
+ return -EINVAL;
+
+ if (ctrl_req->wLength != 6) {
+ dev_err(&usb_ss->dev, "Set SEL should be 6 bytes, got %d\n",
+ ctrl_req->wLength);
+ return -EINVAL;
+ }
+
+ usb_ss->ep0_data_dir = 0;
+ usb_ss->actual_ep0_request = NULL;
+ cdns_ep0_run_transfer(usb_ss, usb_ss->setup_dma, 6, 1);
+ return 0;
+}
+
+/**
+ * cdns_req_ep0_set_isoch_delay -
+ * Handling of GET_ISOCH_DELAY standard USB request
+ * @usb_ss: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns_req_ep0_set_isoch_delay(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req)
+{
+ if (ctrl_req->wIndex || ctrl_req->wLength)
+ return -EINVAL;
+
+ usb_ss->isoch_delay = ctrl_req->wValue;
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__ERDY__MASK | EP_CMD__REQ_CMPL__MASK);
+ return 0;
+}
+
+static void cdns_enable_l1(struct usb_ss_dev *usb_ss, int enable)
+{
+ if (enable)
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__L1EN__MASK);
+ else
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__L1DS__MASK);
+}
+
+/**
+ * cdns_req_ep0_set_configuration - Handling of SET_CONFIG standard USB request
+ * @usb_ss: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, 0x7FFF on deferred status stage, error code on error
+ */
+static int cdns_req_ep0_set_configuration(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req)
+{
+ enum usb_device_state device_state = usb_ss->gadget.state;
+ u32 config = le16_to_cpu(ctrl_req->wValue);
+ struct usb_ep *ep;
+ struct usb_ss_endpoint *usb_ss_ep, *temp_ss_ep;
+ int i, result = 0;
+
+ switch (device_state) {
+ case USB_STATE_ADDRESS:
+ /* Configure non-control EPs */
+ list_for_each_entry_safe(usb_ss_ep, temp_ss_ep,
+ &usb_ss->ep_match_list, ep_match_pending_list)
+ cdns_ep_config(usb_ss_ep);
+
+ result = cdns_get_setup_ret(usb_ss, ctrl_req);
+
+ if (result != 0)
+ return result;
+
+ if (config) {
+ if (!usb_ss->hw_configured_flag) {
+ /* SET CONFIGURATION */
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__CFGSET__MASK);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__ERDY__MASK |
+ EP_CMD__REQ_CMPL__MASK);
+ /* wait until configuration set */
+ result = wait_reg_bit_set(usb_ss,
+ &usb_ss->regs->usb_sts,
+ USB_STS__CFGSTS__MASK, 100);
+ usb_ss->hw_configured_flag = 1;
+ cdns_enable_l1(usb_ss, 1);
+
+ list_for_each_entry(ep,
+ &usb_ss->gadget.ep_list,
+ ep_list) {
+ if (ep->enabled)
+ cdns_ep_run_transfer(
+ to_usb_ss_ep(ep));
+ }
+ }
+ } else {
+ cdns_gadget_unconfig(usb_ss);
+ for (i = 0; i < usb_ss->ep_nums; i++)
+ usb_ss->eps[i]->endpoint.enabled = 0;
+ usb_gadget_set_state(&usb_ss->gadget,
+ USB_STATE_ADDRESS);
+ }
+ break;
+ case USB_STATE_CONFIGURED:
+ result = cdns_get_setup_ret(usb_ss, ctrl_req);
+ if (!config && !result) {
+ cdns_gadget_unconfig(usb_ss);
+ for (i = 0; i < usb_ss->ep_nums; i++)
+ usb_ss->eps[i]->endpoint.enabled = 0;
+ usb_gadget_set_state(&usb_ss->gadget,
+ USB_STATE_ADDRESS);
+ }
+ break;
+ default:
+ result = -EINVAL;
+ }
+
+ return result;
+}
+
+/**
+ * cdns_ep0_standard_request - Handling standard USB requests
+ * @usb_ss: extended gadget object
+ * @ctrl_req: pointer to received setup packet
+ *
+ * Returns 0 if success, error code on error
+ */
+static int cdns_ep0_standard_request(struct usb_ss_dev *usb_ss,
+ struct usb_ctrlrequest *ctrl_req)
+{
+ switch (ctrl_req->bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ return cdns_req_ep0_set_address(usb_ss, ctrl_req);
+ case USB_REQ_SET_CONFIGURATION:
+ return cdns_req_ep0_set_configuration(usb_ss, ctrl_req);
+ case USB_REQ_GET_STATUS:
+ return cdns_req_ep0_get_status(usb_ss, ctrl_req);
+ case USB_REQ_CLEAR_FEATURE:
+ return cdns_req_ep0_handle_feature(usb_ss, ctrl_req, 0);
+ case USB_REQ_SET_FEATURE:
+ return cdns_req_ep0_handle_feature(usb_ss, ctrl_req, 1);
+ case USB_REQ_SET_SEL:
+ return cdns_req_ep0_set_sel(usb_ss, ctrl_req);
+ case USB_REQ_SET_ISOCH_DELAY:
+ return cdns_req_ep0_set_isoch_delay(usb_ss, ctrl_req);
+ default:
+ return cdns_get_setup_ret(usb_ss, ctrl_req);
+ }
+}
+
+/**
+ * cdns_ep0_setup_phase - Handling setup USB requests
+ * @usb_ss: extended gadget object
+ */
+static void cdns_ep0_setup_phase(struct usb_ss_dev *usb_ss)
+{
+ int result;
+ struct usb_ctrlrequest *ctrl_req =
+ (struct usb_ctrlrequest *)usb_ss->setup;
+
+ if ((ctrl_req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
+ result = cdns_ep0_standard_request(usb_ss, ctrl_req);
+ else
+ result = cdns_get_setup_ret(usb_ss, ctrl_req);
+
+ if (result != 0 && result != USB_GADGET_DELAYED_STATUS) {
+ dev_dbg(&usb_ss->dev, "STALL(00) %d\n", result);
+ /* set_stall on ep0 */
+ select_ep(usb_ss, 0x00);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__SSTALL__MASK);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__ERDY__MASK | EP_CMD__REQ_CMPL__MASK);
+ }
+}
+
+/**
+ * cdns_check_ep_interrupt_proceed - Processes interrupt related to endpoint
+ * @usb_ss_ep: extended endpoint object
+ *
+ * Returns 0
+ */
+static int cdns_check_ep_interrupt_proceed(struct usb_ss_endpoint *usb_ss_ep)
+{
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+ struct usb_request *request;
+ u32 ep_sts_reg;
+
+ select_ep(usb_ss, usb_ss_ep->endpoint.address);
+ ep_sts_reg = gadget_readl(usb_ss, &usb_ss->regs->ep_sts);
+
+ dev_dbg(&usb_ss->dev, "EP_STS: %08X\n", ep_sts_reg);
+
+ if (ep_sts_reg & EP_STS__TRBERR__MASK) {
+ gadget_writel(usb_ss,
+ &usb_ss->regs->ep_sts, EP_STS__TRBERR__MASK);
+
+ dev_dbg(&usb_ss->dev, "TRBERR(%02X)\n",
+ usb_ss_ep->endpoint.desc->bEndpointAddress);
+ }
+
+ if (ep_sts_reg & EP_STS__ISOERR__MASK) {
+ gadget_writel(usb_ss,
+ &usb_ss->regs->ep_sts, EP_STS__ISOERR__MASK);
+ dev_dbg(&usb_ss->dev, "ISOERR(%02X)\n",
+ usb_ss_ep->endpoint.desc->bEndpointAddress);
+ }
+
+ if (ep_sts_reg & EP_STS__OUTSMM__MASK) {
+ gadget_writel(usb_ss, &usb_ss->regs->ep_sts,
+ EP_STS__OUTSMM__MASK);
+ dev_dbg(&usb_ss->dev, "OUTSMM(%02X)\n",
+ usb_ss_ep->endpoint.desc->bEndpointAddress);
+ }
+
+ if (ep_sts_reg & EP_STS__NRDY__MASK) {
+ gadget_writel(usb_ss,
+ &usb_ss->regs->ep_sts, EP_STS__NRDY__MASK);
+ dev_dbg(&usb_ss->dev, "NRDY(%02X)\n",
+ usb_ss_ep->endpoint.desc->bEndpointAddress);
+ }
+
+ if ((ep_sts_reg & EP_STS__IOC__MASK)
+ || (ep_sts_reg & EP_STS__ISP__MASK)) {
+ gadget_writel(usb_ss, &usb_ss->regs->ep_sts,
+ EP_STS__IOC__MASK | EP_STS__ISP__MASK);
+
+ /* get just completed request */
+ request = next_request(&usb_ss_ep->request_list);
+ if (!request)
+ return 0;
+
+ if ((request->dma % ADDR_MODULO_8) &&
+ (usb_ss_ep->dir == USB_DIR_OUT))
+ memcpy(request->buf, usb_ss_ep->cpu_addr,
+ request->length);
+
+ usb_gadget_unmap_request_by_dev(usb_ss->sysdev, request,
+ usb_ss_ep->endpoint.desc->bEndpointAddress
+ & ENDPOINT_DIR_MASK);
+
+ request->status = 0;
+ request->actual =
+ le32_to_cpu(((u32 *) usb_ss_ep->trb_pool)[1])
+ & ACTUAL_TRANSFERRED_BYTES_MASK;
+
+ dev_dbg(&usb_ss->dev, "IOC(%02X) %d\n",
+ usb_ss_ep->endpoint.desc->bEndpointAddress,
+ request->actual);
+
+ list_del(&request->list);
+
+ usb_ss_ep->hw_pending_flag = 0;
+ if (request->complete) {
+ spin_unlock(&usb_ss->lock);
+ usb_gadget_giveback_request(&usb_ss_ep->endpoint,
+ request);
+ spin_lock(&usb_ss->lock);
+ }
+
+ if (request->buf == usb_ss->zlp_buf)
+ kfree(request);
+
+ /* handle deferred STALL */
+ if (usb_ss_ep->stalled_flag) {
+ cdns_ep_stall_flush(usb_ss_ep);
+ return 0;
+ }
+
+ /* exit if hardware transfer already started */
+ if (usb_ss_ep->hw_pending_flag)
+ return 0;
+
+ /* if any request queued run it! */
+ if (!list_empty(&usb_ss_ep->request_list))
+ cdns_ep_run_transfer(usb_ss_ep);
+ }
+
+ if (ep_sts_reg & EP_STS__DESCMIS__MASK) {
+ gadget_writel(usb_ss,
+ &usb_ss->regs->ep_sts, EP_STS__DESCMIS__MASK);
+ dev_dbg(&usb_ss->dev, "DESCMIS(%02X)\n",
+ usb_ss_ep->endpoint.desc->bEndpointAddress);
+ }
+
+ return 0;
+}
+
+/**
+ * cdns_check_ep0_interrupt_proceed - Processes interrupt related to endpoint 0
+ * @usb_ss: extended gadget object
+ * @dir: 1 for IN direction, 0 for OUT direction
+ */
+static void cdns_check_ep0_interrupt_proceed(struct usb_ss_dev *usb_ss, int dir)
+{
+ u32 ep_sts_reg;
+ int i;
+
+ select_ep(usb_ss, 0 | (dir ? USB_DIR_IN : USB_DIR_OUT));
+ ep_sts_reg = gadget_readl(usb_ss, &usb_ss->regs->ep_sts);
+
+ dev_dbg(&usb_ss->dev, "EP_STS: %08X\n", ep_sts_reg);
+
+ __pending_setup_status_handler(usb_ss);
+
+ if ((ep_sts_reg & EP_STS__SETUP__MASK) && (dir == 0)) {
+ dev_dbg(&usb_ss->dev, "SETUP(%02X)\n", 0x00);
+
+ gadget_writel(usb_ss, &usb_ss->regs->ep_sts,
+ EP_STS__SETUP__MASK |
+ EP_STS__IOC__MASK | EP_STS__ISP__MASK);
+
+ dev_dbg(&usb_ss->dev, "SETUP: ");
+ for (i = 0; i < 8; i++)
+ dev_dbg(&usb_ss->dev, "%02X ", usb_ss->setup[i]);
+ dev_dbg(&usb_ss->dev, "\nSTATE: %d\n", usb_ss->gadget.state);
+ usb_ss->ep0_data_dir = usb_ss->setup[0] & USB_DIR_IN;
+ cdns_ep0_setup_phase(usb_ss);
+ ep_sts_reg &= ~(EP_STS__SETUP__MASK |
+ EP_STS__IOC__MASK |
+ EP_STS__ISP__MASK);
+ }
+
+ if (ep_sts_reg & EP_STS__TRBERR__MASK) {
+ gadget_writel(usb_ss,
+ &usb_ss->regs->ep_sts, EP_STS__TRBERR__MASK);
+ dev_dbg(&usb_ss->dev, "TRBERR(%02X)\n",
+ dir ? USB_DIR_IN : USB_DIR_OUT);
+ }
+
+ if (ep_sts_reg & EP_STS__DESCMIS__MASK) {
+ gadget_writel(usb_ss,
+ &usb_ss->regs->ep_sts, EP_STS__DESCMIS__MASK);
+
+ dev_dbg(&usb_ss->dev, "DESCMIS(%02X)\n",
+ dir ? USB_DIR_IN : USB_DIR_OUT);
+
+ if (dir == 0 && !usb_ss->setup_pending) {
+ usb_ss->ep0_data_dir = 0;
+ cdns_ep0_run_transfer(usb_ss,
+ usb_ss->setup_dma, 8, 0);
+ }
+ }
+
+ if ((ep_sts_reg & EP_STS__IOC__MASK)
+ || (ep_sts_reg & EP_STS__ISP__MASK)) {
+ gadget_writel(usb_ss,
+ &usb_ss->regs->ep_sts, EP_STS__IOC__MASK);
+ if (usb_ss->actual_ep0_request) {
+ usb_gadget_unmap_request_by_dev(usb_ss->sysdev,
+ usb_ss->actual_ep0_request,
+ usb_ss->ep0_data_dir);
+
+ usb_ss->actual_ep0_request->actual =
+ le32_to_cpu((usb_ss->trb_ep0)[1])
+ & ACTUAL_TRANSFERRED_BYTES_MASK;
+
+ dev_dbg(&usb_ss->dev, "IOC(%02X) %d\n",
+ dir ? USB_DIR_IN : USB_DIR_OUT,
+ usb_ss->actual_ep0_request->actual);
+ list_del_init(&usb_ss->actual_ep0_request->list);
+ }
+
+ if (usb_ss->actual_ep0_request
+ && usb_ss->actual_ep0_request->complete) {
+ spin_unlock(&usb_ss->lock);
+ usb_ss->actual_ep0_request->complete(usb_ss->gadget.ep0,
+ usb_ss->actual_ep0_request);
+ spin_lock(&usb_ss->lock);
+ }
+ cdns_prepare_setup_packet(usb_ss);
+ gadget_writel(usb_ss,
+ &usb_ss->regs->ep_cmd, EP_CMD__REQ_CMPL__MASK);
+ }
+}
+
+/**
+ * cdns_check_usb_interrupt_proceed - Processes interrupt related to device
+ * @usb_ss: extended gadget object
+ * @usb_ists: bitmap representation of device's reported interrupts
+ * (usb_ists register value)
+ */
+static void cdns_check_usb_interrupt_proceed(struct usb_ss_dev *usb_ss,
+ u32 usb_ists)
+{
+ int interrupt_bit = ffs(usb_ists) - 1;
+ int speed;
+ u32 val;
+
+ dev_dbg(&usb_ss->dev, "USB interrupt detected\n");
+
+ switch (interrupt_bit) {
+ case USB_ISTS__CON2I__SHIFT:
+ /* FS/HS Connection detected */
+ dev_dbg(&usb_ss->dev,
+ "[Interrupt] FS/HS Connection detected\n");
+ val = gadget_readl(usb_ss, &usb_ss->regs->usb_sts);
+ speed = USB_STS__USBSPEED__READ(val);
+ if (speed == USB_SPEED_WIRELESS)
+ speed = USB_SPEED_SUPER;
+ dev_dbg(&usb_ss->dev, "Speed value: %s (%d), usbsts:0x%x\n",
+ usb_speed_string(speed), speed, val);
+ usb_ss->gadget.speed = speed;
+ usb_ss->is_connected = 1;
+ usb_gadget_set_state(&usb_ss->gadget, USB_STATE_POWERED);
+ cdns_ep0_config(usb_ss);
+ break;
+ case USB_ISTS__CONI__SHIFT:
+ /* SS Connection detected */
+ dev_dbg(&usb_ss->dev, "[Interrupt] SS Connection detected\n");
+ val = gadget_readl(usb_ss, &usb_ss->regs->usb_sts);
+ speed = USB_STS__USBSPEED__READ(val);
+ if (speed == USB_SPEED_WIRELESS)
+ speed = USB_SPEED_SUPER;
+ dev_dbg(&usb_ss->dev, "Speed value: %s (%d), usbsts:0x%x\n",
+ usb_speed_string(speed), speed, val);
+ usb_ss->gadget.speed = speed;
+ usb_ss->is_connected = 1;
+ usb_gadget_set_state(&usb_ss->gadget, USB_STATE_POWERED);
+ cdns_ep0_config(usb_ss);
+ break;
+ case USB_ISTS__DIS2I__SHIFT:
+ case USB_ISTS__DISI__SHIFT:
+ /* SS Disconnection detected */
+ val = gadget_readl(usb_ss, &usb_ss->regs->usb_sts);
+ dev_dbg(&usb_ss->dev,
+ "[Interrupt] Disconnection detected: usbsts:0x%x\n",
+ val);
+ if (usb_ss->gadget_driver
+ && usb_ss->gadget_driver->disconnect) {
+
+ spin_unlock(&usb_ss->lock);
+ usb_ss->gadget_driver->disconnect(&usb_ss->gadget);
+ spin_lock(&usb_ss->lock);
+ }
+ usb_ss->gadget.speed = USB_SPEED_UNKNOWN;
+ usb_gadget_set_state(&usb_ss->gadget, USB_STATE_NOTATTACHED);
+ usb_ss->is_connected = 0;
+ cdns_gadget_unconfig(usb_ss);
+ break;
+ case USB_ISTS__L2ENTI__SHIFT:
+ dev_dbg(&usb_ss->dev,
+ "[Interrupt] Device suspended\n");
+ break;
+ case USB_ISTS__L2EXTI__SHIFT:
+ dev_dbg(&usb_ss->dev, "[Interrupt] L2 exit detected\n");
+ /*
+ * Exit from standby mode
+ * on L2 exit (Suspend in HS/FS or SS)
+ */
+ break;
+ case USB_ISTS__U3EXTI__SHIFT:
+ /*
+ * Exit from standby mode
+ * on U3 exit (Suspend in HS/FS or SS)
+ */
+ dev_dbg(&usb_ss->dev, "[Interrupt] U3 exit detected\n");
+ break;
+
+ /* resets cases */
+ case USB_ISTS__UWRESI__SHIFT:
+ case USB_ISTS__UHRESI__SHIFT:
+ case USB_ISTS__U2RESI__SHIFT:
+ dev_dbg(&usb_ss->dev, "[Interrupt] Reset detected\n");
+ speed = USB_STS__USBSPEED__READ(
+ gadget_readl(usb_ss, &usb_ss->regs->usb_sts));
+ if (speed == USB_SPEED_WIRELESS)
+ speed = USB_SPEED_SUPER;
+ usb_gadget_set_state(&usb_ss->gadget, USB_STATE_DEFAULT);
+ usb_ss->gadget.speed = speed;
+ cdns_gadget_unconfig(usb_ss);
+ cdns_ep0_config(usb_ss);
+ break;
+ default:
+ break;
+ }
+
+ /* Clear interrupt bit */
+ gadget_writel(usb_ss, &usb_ss->regs->usb_ists, (1uL << interrupt_bit));
+}
+
+/**
+ * cdns_irq_handler - irq line interrupt handler
+ * @cdns: cdns3 instance
+ *
+ * Returns IRQ_HANDLED when interrupt raised by USBSS_DEV,
+ * IRQ_NONE when interrupt raised by other device connected
+ * to the irq line
+ */
+static irqreturn_t cdns_irq_handler_thread(struct cdns3 *cdns)
+{
+ struct usb_ss_dev *usb_ss =
+ container_of(cdns->gadget_dev, struct usb_ss_dev, dev);
+ u32 reg;
+ enum irqreturn ret = IRQ_NONE;
+ unsigned long flags;
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+
+ /* check USB device interrupt */
+ reg = gadget_readl(usb_ss, &usb_ss->regs->usb_ists);
+ if (reg) {
+ dev_dbg(&usb_ss->dev, "usb_ists: %08X\n", reg);
+ cdns_check_usb_interrupt_proceed(usb_ss, reg);
+ ret = IRQ_HANDLED;
+ }
+
+ /* check endpoint interrupt */
+ reg = gadget_readl(usb_ss, &usb_ss->regs->ep_ists);
+ if (reg != 0) {
+ dev_dbg(&usb_ss->dev, "ep_ists: %08X\n", reg);
+ } else {
+ if (gadget_readl(usb_ss, &usb_ss->regs->usb_sts) &
+ USB_STS__CFGSTS__MASK)
+ ret = IRQ_HANDLED;
+ goto irqend;
+ }
+
+ /* handle default endpoint OUT */
+ if (reg & EP_ISTS__EOUT0__MASK) {
+ cdns_check_ep0_interrupt_proceed(usb_ss, 0);
+ ret = IRQ_HANDLED;
+ }
+
+ /* handle default endpoint IN */
+ if (reg & EP_ISTS__EIN0__MASK) {
+ cdns_check_ep0_interrupt_proceed(usb_ss, 1);
+ ret = IRQ_HANDLED;
+ }
+
+ /* check if interrupt from non default endpoint, if no exit */
+ reg &= ~(EP_ISTS__EOUT0__MASK | EP_ISTS__EIN0__MASK);
+ if (!reg)
+ goto irqend;
+
+ do {
+ unsigned int bit_pos = ffs(reg);
+ u32 bit_mask = 1 << (bit_pos - 1);
+
+ dev_dbg(&usb_ss->dev, "Interrupt on index: %d bitmask %08X\n",
+ CAST_EP_REG_POS_TO_INDEX(bit_pos), bit_mask);
+ cdns_check_ep_interrupt_proceed(
+ usb_ss->eps[CAST_EP_REG_POS_TO_INDEX(bit_pos)]);
+ reg &= ~bit_mask;
+ ret = IRQ_HANDLED;
+ } while (reg);
+
+irqend:
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return ret;
+}
+
+/**
+ * usb_ss_gadget_ep0_enable
+ * Function shouldn't be called by gadget driver,
+ * endpoint 0 is allways active
+ */
+static int usb_ss_gadget_ep0_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ return -EINVAL;
+}
+
+/**
+ * usb_ss_gadget_ep0_disable
+ * Function shouldn't be called by gadget driver,
+ * endpoint 0 is allways active
+ */
+static int usb_ss_gadget_ep0_disable(struct usb_ep *ep)
+{
+ return -EINVAL;
+}
+
+/**
+ * usb_ss_gadget_ep0_set_halt
+ * @ep: pointer to endpoint zero object
+ * @value: 1 for set stall, 0 for clear stall
+ *
+ * Returns 0
+ */
+static int usb_ss_gadget_ep0_set_halt(struct usb_ep *ep, int value)
+{
+ /* TODO */
+ return 0;
+}
+
+static void __pending_setup_status_handler(struct usb_ss_dev *usb_ss)
+{
+ struct usb_request *request = usb_ss->pending_status_request;
+
+ if (usb_ss->status_completion_no_call && request && request->complete) {
+ request->complete(usb_ss->gadget.ep0, request);
+ usb_ss->status_completion_no_call = 0;
+ }
+}
+
+static void pending_setup_status_handler(struct work_struct *work)
+{
+ struct usb_ss_dev *usb_ss = container_of(work, struct usb_ss_dev,
+ pending_status_wq);
+ unsigned long flags;
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ __pending_setup_status_handler(usb_ss);
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+}
+
+/**
+ * usb_ss_gadget_ep0_queue Transfer data on endpoint zero
+ * @ep: pointer to endpoint zero object
+ * @request: pointer to request object
+ * @gfp_flags: gfp flags
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_gadget_ep0_queue(struct usb_ep *ep,
+ struct usb_request *request, gfp_t gfp_flags)
+{
+ int ret = 0;
+ unsigned long flags;
+ int erdy_sent = 0;
+ /* get extended endpoint */
+ struct usb_ss_endpoint *usb_ss_ep =
+ to_usb_ss_ep(ep);
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+
+ dev_dbg(&usb_ss->dev, "QUEUE(%02X) %d\n",
+ usb_ss->ep0_data_dir ? USB_DIR_IN : USB_DIR_OUT,
+ request->length);
+
+ /* send STATUS stage */
+ if (request->length == 0 && request->zero == 0) {
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ select_ep(usb_ss, 0x00);
+ if (!usb_ss->hw_configured_flag) {
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__CFGSET__MASK); /* SET CONFIGURATION */
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__ERDY__MASK | EP_CMD__REQ_CMPL__MASK);
+ /* wait until configuration set */
+ ret = wait_reg_bit_set(usb_ss, &usb_ss->regs->usb_sts,
+ USB_STS__CFGSTS__MASK, 100);
+ erdy_sent = 1;
+ usb_ss->hw_configured_flag = 1;
+ cdns_enable_l1(usb_ss, 1);
+
+ list_for_each_entry(ep,
+ &usb_ss->gadget.ep_list,
+ ep_list) {
+
+ if (ep->enabled)
+ cdns_ep_run_transfer(
+ to_usb_ss_ep(ep));
+ }
+ }
+ if (!erdy_sent)
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__ERDY__MASK | EP_CMD__REQ_CMPL__MASK);
+
+ cdns_prepare_setup_packet(usb_ss);
+ request->actual = 0;
+ usb_ss->status_completion_no_call = true;
+ usb_ss->pending_status_request = request;
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ /*
+ * Since there is no completion interrupt for status stage,
+ * it needs to call ->completion in software after
+ * ep0_queue is back.
+ */
+ queue_work(system_freezable_wq, &usb_ss->pending_status_wq);
+ return 0;
+ }
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ if (!list_empty(&usb_ss_ep->request_list)) {
+ dev_err(&usb_ss->dev,
+ "can't handle multiple requests for ep0\n");
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return -EOPNOTSUPP;
+ }
+
+ ret = usb_gadget_map_request_by_dev(usb_ss->sysdev, request,
+ usb_ss->ep0_data_dir);
+ if (ret) {
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ dev_err(&usb_ss->dev, "failed to map request\n");
+ return -EINVAL;
+ }
+
+ usb_ss->actual_ep0_request = request;
+ cdns_ep0_run_transfer(usb_ss, request->dma, request->length, 1);
+ list_add_tail(&request->list, &usb_ss_ep->request_list);
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return ret;
+}
+/**
+ * ep_onchip_buffer_alloc - Try to allocate onchip buf for EP
+ *
+ * The real allocation will occur during write to EP_CFG register,
+ * this function is used to check if the 'size' allocation is allowed.
+ *
+ * @usb_ss: extended gadget object
+ * @size: the size (KB) for EP would like to allocate
+ * @is_in: the direction for EP
+ *
+ * Return 0 if the later allocation is allowed or negative value on failure
+ */
+
+static int ep_onchip_buffer_alloc(struct usb_ss_dev *usb_ss,
+ int size, int is_in)
+{
+ if (is_in) {
+ usb_ss->onchip_mem_allocated_size += size;
+ } else if (!usb_ss->out_mem_is_allocated) {
+ /* ALL OUT EPs are shared the same chunk onchip memory */
+ usb_ss->onchip_mem_allocated_size += size;
+ usb_ss->out_mem_is_allocated = 1;
+ }
+
+ if (usb_ss->onchip_mem_allocated_size > CDNS3_ONCHIP_BUF_SIZE) {
+ usb_ss->onchip_mem_allocated_size -= size;
+ return -EPERM;
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * cdns_ep_config Configure hardware endpoint
+ * @usb_ss_ep: extended endpoint object
+ */
+static void cdns_ep_config(struct usb_ss_endpoint *usb_ss_ep)
+{
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+ u32 ep_cfg = 0;
+ u32 max_packet_size = 0;
+ u32 bEndpointAddress = usb_ss_ep->num | usb_ss_ep->dir;
+ u32 interrupt_mask = 0;
+ int is_in = !!usb_ss_ep->dir;
+ bool is_iso_ep = (usb_ss_ep->type == USB_ENDPOINT_XFER_ISOC);
+ int default_buf_size = CDNS3_EP_BUF_SIZE;
+
+ dev_dbg(&usb_ss->dev, "%s: %s addr=0x%x\n", __func__,
+ usb_ss_ep->name, bEndpointAddress);
+
+ if (is_iso_ep) {
+ ep_cfg = EP_CFG__EPTYPE__WRITE(USB_ENDPOINT_XFER_ISOC);
+ interrupt_mask = INTERRUPT_MASK;
+ } else {
+ ep_cfg = EP_CFG__EPTYPE__WRITE(USB_ENDPOINT_XFER_BULK);
+ }
+
+ switch (usb_ss->gadget.speed) {
+ case USB_SPEED_UNKNOWN:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_0;
+ break;
+ case USB_SPEED_LOW:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_8;
+ break;
+ case USB_SPEED_FULL:
+ max_packet_size = (is_iso_ep ?
+ ENDPOINT_MAX_PACKET_SIZE_1023 :
+ ENDPOINT_MAX_PACKET_SIZE_64);
+ break;
+ case USB_SPEED_HIGH:
+ max_packet_size = (is_iso_ep ?
+ ENDPOINT_MAX_PACKET_SIZE_1024 :
+ ENDPOINT_MAX_PACKET_SIZE_512);
+ break;
+ case USB_SPEED_WIRELESS:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_512;
+ break;
+ case USB_SPEED_SUPER:
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_1024;
+ break;
+ case USB_SPEED_SUPER_PLUS:
+ dev_warn(&usb_ss->dev, "USB 3.1 is not supported\n");
+ max_packet_size = ENDPOINT_MAX_PACKET_SIZE_1024;
+ break;
+ }
+
+ if (ep_onchip_buffer_alloc(usb_ss, default_buf_size, is_in)) {
+ dev_err(&usb_ss->dev, "onchip mem is full, ep is invalid\n");
+ return;
+ }
+
+ ep_cfg |= EP_CFG__MAXPKTSIZE__WRITE(max_packet_size) |
+ EP_CFG__BUFFERING__WRITE(default_buf_size - 1) |
+ EP_CFG__MAXBURST__WRITE(usb_ss_ep->endpoint.maxburst);
+
+ select_ep(usb_ss, bEndpointAddress);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cfg, ep_cfg);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_sts_en,
+ EP_STS_EN__TRBERREN__MASK | interrupt_mask);
+
+ /* enable interrupt for selected endpoint */
+ ep_cfg = gadget_readl(usb_ss, &usb_ss->regs->ep_ien);
+ ep_cfg |= CAST_EP_ADDR_TO_BIT_POS(bEndpointAddress);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_ien, ep_cfg);
+}
+
+/**
+ * usb_ss_gadget_ep_enable Enable endpoint
+ * @ep: endpoint object
+ * @desc: endpoint descriptor
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_gadget_ep_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct usb_ss_endpoint *usb_ss_ep;
+ struct usb_ss_dev *usb_ss;
+ unsigned long flags;
+ int ret;
+ u32 ep_cfg;
+
+ usb_ss_ep = to_usb_ss_ep(ep);
+ usb_ss = usb_ss_ep->usb_ss;
+
+ if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
+ dev_err(&usb_ss->dev, "usb-ss: invalid parameters\n");
+ return -EINVAL;
+ }
+
+ if (!desc->wMaxPacketSize) {
+ dev_err(&usb_ss->dev, "usb-ss: missing wMaxPacketSize\n");
+ return -EINVAL;
+ }
+
+ ret = usb_ss_allocate_trb_pool(usb_ss_ep);
+ if (ret)
+ return ret;
+
+ dev_dbg(&usb_ss->dev, "Enabling endpoint: %s, addr=0x%x\n",
+ ep->name, desc->bEndpointAddress);
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ select_ep(usb_ss, desc->bEndpointAddress);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__EPRST__MASK);
+ ret = wait_reg_bit_clear(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__EPRST__MASK, 100);
+ ep_cfg = gadget_readl(usb_ss, &usb_ss->regs->ep_cfg);
+ ep_cfg |= EP_CFG__ENABLE__MASK;
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cfg, ep_cfg);
+
+ ep->enabled = 1;
+ ep->desc = desc;
+ usb_ss_ep->hw_pending_flag = 0;
+ usb_ss_ep->stalled_flag = 0;
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return 0;
+}
+
+/* Find correct direction for HW endpoint according to description */
+static int ep_dir_is_correct(struct usb_endpoint_descriptor *desc,
+ struct usb_ss_endpoint *usb_ss_ep)
+{
+ return (usb_ss_ep->endpoint.caps.dir_in &&
+ !!(desc->bEndpointAddress & USB_DIR_IN))
+ || (usb_ss_ep->endpoint.caps.dir_out
+ && ((desc->bEndpointAddress & 0x80) == USB_DIR_OUT));
+}
+
+static struct usb_ss_endpoint *find_available_ss_ep(
+ struct usb_ss_dev *usb_ss,
+ struct usb_endpoint_descriptor *desc)
+{
+ struct usb_ep *ep;
+ struct usb_ss_endpoint *usb_ss_ep;
+
+ list_for_each_entry(ep, &usb_ss->gadget.ep_list, ep_list) {
+ unsigned long num;
+ int ret;
+ /* ep name pattern likes epXin or epXout */
+ char c[2] = {ep->name[2], '\0'};
+
+ ret = kstrtoul(c, 10, &num);
+ if (ret)
+ return ERR_PTR(ret);
+
+ usb_ss_ep = to_usb_ss_ep(ep);
+ if (ep_dir_is_correct(desc, usb_ss_ep)) {
+ if (!usb_ss_ep->used) {
+ usb_ss_ep->num = num;
+ usb_ss_ep->used = true;
+ return usb_ss_ep;
+ }
+ }
+ }
+ return ERR_PTR(-ENOENT);
+}
+
+static struct usb_ep *usb_ss_gadget_match_ep(struct usb_gadget *gadget,
+ struct usb_endpoint_descriptor *desc,
+ struct usb_ss_ep_comp_descriptor *comp_desc)
+{
+ struct usb_ss_dev *usb_ss = gadget_to_usb_ss(gadget);
+ struct usb_ss_endpoint *usb_ss_ep;
+ unsigned long flags;
+
+ usb_ss_ep = find_available_ss_ep(usb_ss, desc);
+ if (IS_ERR(usb_ss_ep)) {
+ dev_err(&usb_ss->dev, "no available ep\n");
+ return NULL;
+ }
+
+ dev_dbg(&usb_ss->dev, "match endpoint: %s\n", usb_ss_ep->name);
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ usb_ss_ep->endpoint.desc = desc;
+ usb_ss_ep->dir = usb_endpoint_dir_in(desc) ? USB_DIR_IN : USB_DIR_OUT;
+ usb_ss_ep->type = usb_endpoint_type(desc);
+
+ list_add_tail(&usb_ss_ep->ep_match_pending_list,
+ &usb_ss->ep_match_list);
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return &usb_ss_ep->endpoint;
+}
+
+static void usb_ss_free_trb_pool(struct usb_ss_endpoint *usb_ss_ep)
+{
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+
+ if (usb_ss_ep->trb_pool) {
+ dma_free_coherent(usb_ss->sysdev,
+ sizeof(struct usb_ss_trb) * USB_SS_TRBS_NUM,
+ usb_ss_ep->trb_pool, usb_ss_ep->trb_pool_dma);
+ usb_ss_ep->trb_pool = NULL;
+ }
+
+ if (usb_ss_ep->cpu_addr) {
+ dma_free_coherent(usb_ss->sysdev, CDNS3_UNALIGNED_BUF_SIZE,
+ usb_ss_ep->cpu_addr, usb_ss_ep->dma_addr);
+ usb_ss_ep->cpu_addr = NULL;
+ }
+}
+
+/**
+ * usb_ss_gadget_ep_disable Disable endpoint
+ * @ep: endpoint object
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_gadget_ep_disable(struct usb_ep *ep)
+{
+ struct usb_ss_endpoint *usb_ss_ep;
+ struct usb_ss_dev *usb_ss;
+ unsigned long flags;
+ int ret = 0;
+ struct usb_request *request;
+ u32 ep_cfg;
+
+ if (!ep) {
+ pr_debug("usb-ss: invalid parameters\n");
+ return -EINVAL;
+ }
+
+ usb_ss_ep = to_usb_ss_ep(ep);
+ usb_ss = usb_ss_ep->usb_ss;
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ if (!usb_ss->start_gadget) {
+ dev_dbg(&usb_ss->dev,
+ "Disabling endpoint at disconnection: %s\n", ep->name);
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return 0;
+ }
+
+ dev_dbg(&usb_ss->dev,
+ "Disabling endpoint: %s\n", ep->name);
+
+ select_ep(usb_ss, ep->desc->bEndpointAddress);
+ ret = cdns_data_flush(usb_ss_ep);
+ while (!list_empty(&usb_ss_ep->request_list)) {
+
+ request = next_request(&usb_ss_ep->request_list);
+ usb_gadget_unmap_request_by_dev(usb_ss->sysdev, request,
+ ep->desc->bEndpointAddress & USB_DIR_IN);
+ request->status = -ESHUTDOWN;
+ list_del(&request->list);
+ spin_unlock(&usb_ss->lock);
+ usb_gadget_giveback_request(ep, request);
+ spin_lock(&usb_ss->lock);
+ }
+
+ ep_cfg = gadget_readl(usb_ss, &usb_ss->regs->ep_cfg);
+ ep_cfg &= ~EP_CFG__ENABLE__MASK;
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cfg, ep_cfg);
+ ep->desc = NULL;
+ ep->enabled = 0;
+
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+
+ return ret;
+}
+
+/**
+ * usb_ss_gadget_ep_alloc_request Allocates request
+ * @ep: endpoint object associated with request
+ * @gfp_flags: gfp flags
+ *
+ * Returns allocated request address, NULL on allocation error
+ */
+static struct usb_request *usb_ss_gadget_ep_alloc_request(struct usb_ep *ep,
+ gfp_t gfp_flags)
+{
+ struct usb_request *request;
+
+ request = kzalloc(sizeof(struct usb_request), gfp_flags);
+ if (!request)
+ return NULL;
+
+ return request;
+}
+
+/**
+ * usb_ss_gadget_ep_free_request Free memory occupied by request
+ * @ep: endpoint object associated with request
+ * @request: request to free memory
+ */
+static void usb_ss_gadget_ep_free_request(struct usb_ep *ep,
+ struct usb_request *request)
+{
+ kfree(request);
+}
+
+/**
+ * usb_ss_gadget_ep_queue Transfer data on endpoint
+ * @ep: endpoint object
+ * @request: request object
+ * @gfp_flags: gfp flags
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int __usb_ss_gadget_ep_queue(struct usb_ep *ep,
+ struct usb_request *request, gfp_t gfp_flags)
+{
+ struct usb_ss_endpoint *usb_ss_ep =
+ to_usb_ss_ep(ep);
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+ int ret = 0;
+ int empty_list = 0;
+
+ request->actual = 0;
+ request->status = -EINPROGRESS;
+
+ dev_dbg(&usb_ss->dev,
+ "Queuing endpoint: %s\n", usb_ss_ep->name);
+
+ dev_dbg(&usb_ss->dev, "QUEUE(%02X) %d\n",
+ ep->desc->bEndpointAddress, request->length);
+
+ ret = usb_gadget_map_request_by_dev(usb_ss->sysdev, request,
+ ep->desc->bEndpointAddress & USB_DIR_IN);
+
+ if (ret)
+ return ret;
+
+ empty_list = list_empty(&usb_ss_ep->request_list);
+ list_add_tail(&request->list, &usb_ss_ep->request_list);
+
+ if (!usb_ss->hw_configured_flag)
+ return 0;
+
+ if (empty_list) {
+ if (!usb_ss_ep->stalled_flag)
+ ret = cdns_ep_run_transfer(usb_ss_ep);
+ }
+
+ return ret;
+}
+
+static int usb_ss_gadget_ep_queue(struct usb_ep *ep,
+ struct usb_request *request, gfp_t gfp_flags)
+{
+ struct usb_ss_endpoint *usb_ss_ep = to_usb_ss_ep(ep);
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+ struct usb_request *zlp_request;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+
+ ret = __usb_ss_gadget_ep_queue(ep, request, gfp_flags);
+ if (ret == 0 && request->zero && request->length &&
+ (request->length % ep->maxpacket == 0)) {
+ zlp_request = usb_ss_gadget_ep_alloc_request(ep, GFP_ATOMIC);
+ zlp_request->length = 0;
+ zlp_request->buf = usb_ss->zlp_buf;
+
+ dev_dbg(&usb_ss->dev, "Queuing ZLP for endpoint: %s\n",
+ usb_ss_ep->name);
+ ret = __usb_ss_gadget_ep_queue(ep, zlp_request, gfp_flags);
+ }
+
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return ret;
+}
+
+/**
+ * usb_ss_gadget_ep_dequeue Remove request from transfer queue
+ * @ep: endpoint object associated with request
+ * @request: request object
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_gadget_ep_dequeue(struct usb_ep *ep,
+ struct usb_request *request)
+{
+ struct usb_ss_endpoint *usb_ss_ep =
+ to_usb_ss_ep(ep);
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+ unsigned long flags;
+ struct usb_request *req, *req_temp;
+ int ret = 0;
+
+ if (ep == NULL || request == NULL || ep->desc == NULL)
+ return -EINVAL;
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ dev_dbg(&usb_ss->dev, "DEQUEUE(%02X) %d\n",
+ ep->address, request->length);
+
+ select_ep(usb_ss, ep->desc->bEndpointAddress);
+ if (usb_ss->start_gadget)
+ ret = cdns_data_flush(usb_ss_ep);
+
+ list_for_each_entry_safe(req, req_temp,
+ &usb_ss_ep->request_list, list) {
+ if (request == req) {
+ request->status = -ECONNRESET;
+ usb_gadget_unmap_request_by_dev(usb_ss->sysdev, request,
+ ep->address & USB_DIR_IN);
+ list_del_init(&request->list);
+ if (request->complete) {
+ spin_unlock(&usb_ss->lock);
+ usb_gadget_giveback_request
+ (&usb_ss_ep->endpoint, request);
+ spin_lock(&usb_ss->lock);
+ }
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return ret;
+}
+
+/**
+ * usb_ss_gadget_ep_set_halt Sets/clears stall on selected endpoint
+ * @ep: endpoint object to set/clear stall on
+ * @value: 1 for set stall, 0 for clear stall
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_gadget_ep_set_halt(struct usb_ep *ep, int value)
+{
+ struct usb_ss_endpoint *usb_ss_ep =
+ to_usb_ss_ep(ep);
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+ unsigned long flags;
+ int ret = 0;
+
+ /* return error when endpoint disabled */
+ if (!ep->enabled)
+ return -EPERM;
+
+ /* if actual transfer is pending defer setting stall on this endpoint */
+ if (usb_ss_ep->hw_pending_flag && value) {
+ usb_ss_ep->stalled_flag = 1;
+ return 0;
+ }
+
+ dev_dbg(&usb_ss->dev, "HALT(%02X) %d\n", ep->address, value);
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+
+ select_ep(usb_ss, ep->desc->bEndpointAddress);
+ if (value) {
+ cdns_ep_stall_flush(usb_ss_ep);
+ } else {
+ /*
+ * TODO:
+ * epp->wedgeFlag = 0;
+ */
+ usb_ss_ep->wedge_flag = 0;
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__CSTALL__MASK | EP_CMD__EPRST__MASK);
+ /* wait for EPRST cleared */
+ ret = wait_reg_bit_clear(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__EPRST__MASK, 100);
+ usb_ss_ep->stalled_flag = 0;
+ }
+ usb_ss_ep->hw_pending_flag = 0;
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+
+ return ret;
+}
+
+/**
+ * usb_ss_gadget_ep_set_wedge Set wedge on selected endpoint
+ * @ep: endpoint object
+ *
+ * Returns 0
+ */
+static int usb_ss_gadget_ep_set_wedge(struct usb_ep *ep)
+{
+ struct usb_ss_endpoint *usb_ss_ep = to_usb_ss_ep(ep);
+ struct usb_ss_dev *usb_ss = usb_ss_ep->usb_ss;
+
+ dev_dbg(&usb_ss->dev, "WEDGE(%02X)\n", ep->address);
+ usb_ss_gadget_ep_set_halt(ep, 1);
+ usb_ss_ep->wedge_flag = 1;
+ return 0;
+}
+
+static const struct usb_ep_ops usb_ss_gadget_ep0_ops = {
+ .enable = usb_ss_gadget_ep0_enable,
+ .disable = usb_ss_gadget_ep0_disable,
+ .alloc_request = usb_ss_gadget_ep_alloc_request,
+ .free_request = usb_ss_gadget_ep_free_request,
+ .queue = usb_ss_gadget_ep0_queue,
+ .dequeue = usb_ss_gadget_ep_dequeue,
+ .set_halt = usb_ss_gadget_ep0_set_halt,
+ .set_wedge = usb_ss_gadget_ep_set_wedge,
+};
+
+static const struct usb_ep_ops usb_ss_gadget_ep_ops = {
+ .enable = usb_ss_gadget_ep_enable,
+ .disable = usb_ss_gadget_ep_disable,
+ .alloc_request = usb_ss_gadget_ep_alloc_request,
+ .free_request = usb_ss_gadget_ep_free_request,
+ .queue = usb_ss_gadget_ep_queue,
+ .dequeue = usb_ss_gadget_ep_dequeue,
+ .set_halt = usb_ss_gadget_ep_set_halt,
+ .set_wedge = usb_ss_gadget_ep_set_wedge,
+};
+
+/**
+ * usb_ss_gadget_get_frame Returns number of actual ITP frame
+ * @gadget: gadget object
+ *
+ * Returns number of actual ITP frame
+ */
+static int usb_ss_gadget_get_frame(struct usb_gadget *gadget)
+{
+ struct usb_ss_dev *usb_ss = gadget_to_usb_ss(gadget);
+
+ dev_dbg(&usb_ss->dev, "usb_ss_gadget_get_frame\n");
+ return gadget_readl(usb_ss, &usb_ss->regs->usb_iptn);
+}
+
+static int usb_ss_gadget_wakeup(struct usb_gadget *gadget)
+{
+ struct usb_ss_dev *usb_ss = gadget_to_usb_ss(gadget);
+
+ dev_dbg(&usb_ss->dev, "usb_ss_gadget_wakeup\n");
+ return 0;
+}
+
+static int usb_ss_gadget_set_selfpowered(struct usb_gadget *gadget,
+ int is_selfpowered)
+{
+ struct usb_ss_dev *usb_ss = gadget_to_usb_ss(gadget);
+ unsigned long flags;
+
+ dev_dbg(&usb_ss->dev, "usb_ss_gadget_set_selfpowered: %d\n",
+ is_selfpowered);
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ gadget->is_selfpowered = !!is_selfpowered;
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return 0;
+}
+
+static int usb_ss_gadget_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct usb_ss_dev *usb_ss = gadget_to_usb_ss(gadget);
+
+ if (!usb_ss->start_gadget)
+ return 0;
+
+ dev_dbg(&usb_ss->dev, "usb_ss_gadget_pullup: %d\n", is_on);
+
+ if (is_on)
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__DEVEN__MASK);
+ else
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__DEVDS__MASK);
+
+ return 0;
+}
+
+/**
+ * usb_ss_gadget_udc_start Gadget start
+ * @gadget: gadget object
+ * @driver: driver which operates on this gadget
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_gadget_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ struct usb_ss_dev *usb_ss = gadget_to_usb_ss(gadget);
+ unsigned long flags;
+
+ if (usb_ss->gadget_driver) {
+ dev_err(&usb_ss->dev, "%s is already bound to %s\n",
+ usb_ss->gadget.name,
+ usb_ss->gadget_driver->driver.name);
+ return -EBUSY;
+ }
+
+ dev_dbg(&usb_ss->dev, "%s begins\n", __func__);
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ usb_ss->gadget_driver = driver;
+ if (!usb_ss->start_gadget) {
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return 0;
+ }
+
+ __cdns3_gadget_start(usb_ss);
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ dev_dbg(&usb_ss->dev, "%s ends\n", __func__);
+ return 0;
+}
+
+/**
+ * usb_ss_gadget_udc_stop Stops gadget
+ * @gadget: gadget object
+ *
+ * Returns 0
+ */
+static int usb_ss_gadget_udc_stop(struct usb_gadget *gadget)
+{
+ struct usb_ss_dev *usb_ss = gadget_to_usb_ss(gadget);
+ struct usb_ep *ep;
+ struct usb_ss_endpoint *usb_ss_ep, *temp_ss_ep;
+ int i;
+ u32 bEndpointAddress;
+ int ret = 0;
+
+ usb_ss->gadget_driver = NULL;
+ list_for_each_entry_safe(usb_ss_ep, temp_ss_ep,
+ &usb_ss->ep_match_list, ep_match_pending_list) {
+ list_del(&usb_ss_ep->ep_match_pending_list);
+ usb_ss_ep->used = false;
+ }
+
+ usb_ss->onchip_mem_allocated_size = 0;
+ usb_ss->out_mem_is_allocated = 0;
+ usb_ss->gadget.speed = USB_SPEED_UNKNOWN;
+ for (i = 0; i < usb_ss->ep_nums ; i++)
+ usb_ss_free_trb_pool(usb_ss->eps[i]);
+
+ if (!usb_ss->start_gadget)
+ return 0;
+
+ list_for_each_entry(ep, &usb_ss->gadget.ep_list, ep_list) {
+ usb_ss_ep = to_usb_ss_ep(ep);
+ bEndpointAddress = usb_ss_ep->num | usb_ss_ep->dir;
+ select_ep(usb_ss, bEndpointAddress);
+ gadget_writel(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__EPRST__MASK);
+ ret = wait_reg_bit_clear(usb_ss, &usb_ss->regs->ep_cmd,
+ EP_CMD__EPRST__MASK, 100);
+ }
+
+ /* disable interrupt for device */
+ gadget_writel(usb_ss, &usb_ss->regs->usb_ien, 0);
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf, USB_CONF__DEVDS__MASK);
+
+ return ret;
+}
+
+static const struct usb_gadget_ops usb_ss_gadget_ops = {
+ .get_frame = usb_ss_gadget_get_frame,
+ .wakeup = usb_ss_gadget_wakeup,
+ .set_selfpowered = usb_ss_gadget_set_selfpowered,
+ .pullup = usb_ss_gadget_pullup,
+ .udc_start = usb_ss_gadget_udc_start,
+ .udc_stop = usb_ss_gadget_udc_stop,
+ .match_ep = usb_ss_gadget_match_ep,
+};
+
+/**
+ * usb_ss_init_ep Initializes software endpoints of gadget
+ * @usb_ss: extended gadget object
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_init_ep(struct usb_ss_dev *usb_ss)
+{
+ struct usb_ss_endpoint *usb_ss_ep;
+ u32 ep_enabled_reg, iso_ep_reg, bulk_ep_reg;
+ int i;
+ int ep_reg_pos, ep_dir, ep_number;
+ int found_endpoints = 0;
+
+ /* Read it from USB_CAP3 to USB_CAP5 */
+ ep_enabled_reg = 0x00ff00ff;
+ iso_ep_reg = 0x00fe00fe;
+ bulk_ep_reg = 0x00fe00fe;
+
+ dev_dbg(&usb_ss->dev, "Initializing non-zero endpoints\n");
+
+ for (i = 0; i < USB_SS_ENDPOINTS_MAX_COUNT; i++) {
+ ep_number = (i / 2) + 1;
+ ep_dir = i % 2;
+ ep_reg_pos = (16 * ep_dir) + ep_number;
+
+ if (!(ep_enabled_reg & (1uL << ep_reg_pos)))
+ continue;
+
+ /* create empty endpoint object */
+ usb_ss_ep = devm_kzalloc(&usb_ss->dev, sizeof(*usb_ss_ep),
+ GFP_KERNEL);
+ if (!usb_ss_ep)
+ return -ENOMEM;
+
+ /* set parent of endpoint object */
+ usb_ss_ep->usb_ss = usb_ss;
+
+ /* set index of endpoint in endpoints container */
+ usb_ss->eps[found_endpoints++] = usb_ss_ep;
+
+ /* set name of endpoint */
+ snprintf(usb_ss_ep->name, sizeof(usb_ss_ep->name), "ep%d%s",
+ ep_number, !!ep_dir ? "in" : "out");
+ usb_ss_ep->endpoint.name = usb_ss_ep->name;
+ dev_dbg(&usb_ss->dev, "Initializing endpoint: %s\n",
+ usb_ss_ep->name);
+
+ usb_ep_set_maxpacket_limit(&usb_ss_ep->endpoint,
+ ENDPOINT_MAX_PACKET_LIMIT);
+ usb_ss_ep->endpoint.max_streams = ENDPOINT_MAX_STREAMS;
+ usb_ss_ep->endpoint.ops = &usb_ss_gadget_ep_ops;
+ if (ep_dir)
+ usb_ss_ep->endpoint.caps.dir_in = 1;
+ else
+ usb_ss_ep->endpoint.caps.dir_out = 1;
+
+ /* check endpoint type */
+ if (iso_ep_reg & (1uL << ep_reg_pos))
+ usb_ss_ep->endpoint.caps.type_iso = 1;
+
+ if (bulk_ep_reg & (1uL << ep_reg_pos)) {
+ usb_ss_ep->endpoint.caps.type_bulk = 1;
+ usb_ss_ep->endpoint.caps.type_int = 1;
+ usb_ss_ep->endpoint.maxburst = CDNS3_EP_BUF_SIZE - 1;
+ }
+
+ list_add_tail(&usb_ss_ep->endpoint.ep_list,
+ &usb_ss->gadget.ep_list);
+ INIT_LIST_HEAD(&usb_ss_ep->request_list);
+ INIT_LIST_HEAD(&usb_ss_ep->ep_match_pending_list);
+ }
+
+ usb_ss->ep_nums = found_endpoints;
+ return 0;
+}
+
+/**
+ * usb_ss_init_ep0 Initializes software endpoint 0 of gadget
+ * @usb_ss: extended gadget object
+ *
+ * Returns 0 on success, error code elsewhere
+ */
+static int usb_ss_init_ep0(struct usb_ss_dev *usb_ss)
+{
+ struct usb_ss_endpoint *ep0;
+
+ dev_dbg(&usb_ss->dev, "Initializing EP0\n");
+ ep0 = devm_kzalloc(&usb_ss->dev, sizeof(struct usb_ss_endpoint),
+ GFP_KERNEL);
+
+ if (!ep0)
+ return -ENOMEM;
+
+ /* fill CDNS fields */
+ ep0->usb_ss = usb_ss;
+ sprintf(ep0->name, "ep0");
+
+ /* fill linux fields */
+ ep0->endpoint.ops = &usb_ss_gadget_ep0_ops;
+ ep0->endpoint.maxburst = 1;
+ usb_ep_set_maxpacket_limit(&ep0->endpoint, ENDPOINT0_MAX_PACKET_LIMIT);
+ ep0->endpoint.address = 0;
+ ep0->endpoint.enabled = 1;
+ ep0->endpoint.caps.type_control = 1;
+ ep0->endpoint.caps.dir_in = 1;
+ ep0->endpoint.caps.dir_out = 1;
+ ep0->endpoint.name = ep0->name;
+ ep0->endpoint.desc = &cdns3_gadget_ep0_desc;
+ usb_ss->gadget.ep0 = &ep0->endpoint;
+ INIT_LIST_HEAD(&ep0->request_list);
+
+ return 0;
+}
+
+static void cdns3_gadget_release(struct device *dev)
+{
+ struct usb_ss_dev *usb_ss = container_of(dev, struct usb_ss_dev, dev);
+
+ dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
+ kfree(usb_ss);
+}
+
+static int __cdns3_gadget_init(struct cdns3 *cdns)
+{
+ struct usb_ss_dev *usb_ss;
+ int ret;
+ struct device *dev;
+
+ usb_ss = kzalloc(sizeof(*usb_ss), GFP_KERNEL);
+ if (!usb_ss)
+ return -ENOMEM;
+
+ dev = &usb_ss->dev;
+ dev->release = cdns3_gadget_release;
+ dev->parent = cdns->dev;
+ dev_set_name(dev, "gadget-cdns3");
+ cdns->gadget_dev = dev;
+ usb_ss->sysdev = cdns->dev;
+ ret = device_register(dev);
+ if (ret)
+ goto err1;
+
+ usb_ss->regs = cdns->dev_regs;
+
+ /* fill gadget fields */
+ usb_ss->gadget.ops = &usb_ss_gadget_ops;
+ usb_ss->gadget.max_speed = USB_SPEED_SUPER;
+ usb_ss->gadget.speed = USB_SPEED_UNKNOWN;
+ usb_ss->gadget.name = "usb-ss-gadget";
+ usb_ss->gadget.sg_supported = 1;
+ usb_ss->is_connected = 0;
+ spin_lock_init(&usb_ss->lock);
+ INIT_WORK(&usb_ss->pending_status_wq, pending_setup_status_handler);
+
+ usb_ss->in_standby_mode = 1;
+
+ /* initialize endpoint container */
+ INIT_LIST_HEAD(&usb_ss->gadget.ep_list);
+ INIT_LIST_HEAD(&usb_ss->ep_match_list);
+ ret = usb_ss_init_ep0(usb_ss);
+ if (ret) {
+ dev_err(dev, "Failed to create endpoint 0\n");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ ret = usb_ss_init_ep(usb_ss);
+ if (ret) {
+ dev_err(dev, "Failed to create non zero endpoints\n");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ /* allocate memory for default endpoint TRB */
+ usb_ss->trb_ep0 = (u32 *)dma_alloc_coherent(usb_ss->sysdev, 20,
+ &usb_ss->trb_ep0_dma, GFP_DMA);
+ if (!usb_ss->trb_ep0) {
+ dev_err(dev, "Failed to allocate memory for ep0 TRB\n");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ /* allocate memory for setup packet buffer */
+ usb_ss->setup = (u8 *)dma_alloc_coherent(usb_ss->sysdev, 8,
+ &usb_ss->setup_dma,
+ GFP_DMA);
+ if (!usb_ss->setup) {
+ dev_err(dev, "Failed to allocate memory for SETUP buffer\n");
+ ret = -ENOMEM;
+ goto err3;
+ }
+
+ /* add USB gadget device */
+ ret = usb_add_gadget_udc(&usb_ss->dev, &usb_ss->gadget);
+ if (ret < 0) {
+ dev_err(dev, "Failed to register USB device controller\n");
+ goto err4;
+ }
+
+ usb_ss->zlp_buf = kzalloc(ENDPOINT_ZLP_BUF_SIZE, GFP_KERNEL);
+ if (!usb_ss->zlp_buf) {
+ ret = -ENOMEM;
+ goto err4;
+ }
+
+ return 0;
+err4:
+ dma_free_coherent(usb_ss->sysdev, 8, usb_ss->setup,
+ usb_ss->setup_dma);
+err3:
+ dma_free_coherent(usb_ss->sysdev, 20, usb_ss->trb_ep0,
+ usb_ss->trb_ep0_dma);
+err2:
+ device_del(dev);
+err1:
+ put_device(dev);
+ cdns->gadget_dev = NULL;
+ return ret;
+}
+
+/**
+ * cdns3_gadget_remove: parent must call this to remove UDC
+ *
+ * cdns: cdns3 instance
+ *
+ */
+void cdns3_gadget_remove(struct cdns3 *cdns)
+{
+ struct usb_ss_dev *usb_ss;
+
+ if (!cdns->roles[CDNS3_ROLE_GADGET])
+ return;
+
+ usb_ss = container_of(cdns->gadget_dev, struct usb_ss_dev, dev);
+ usb_del_gadget_udc(&usb_ss->gadget);
+ dma_free_coherent(usb_ss->sysdev, 8, usb_ss->setup, usb_ss->setup_dma);
+ dma_free_coherent(usb_ss->sysdev, 20, usb_ss->trb_ep0,
+ usb_ss->trb_ep0_dma);
+ device_unregister(cdns->gadget_dev);
+ cdns->gadget_dev = NULL;
+ kfree(usb_ss->zlp_buf);
+}
+
+static void __cdns3_gadget_start(struct usb_ss_dev *usb_ss)
+{
+
+ /* configure endpoint 0 hardware */
+ cdns_ep0_config(usb_ss);
+
+ /* enable interrupts for endpoint 0 (in and out) */
+ gadget_writel(usb_ss, &usb_ss->regs->ep_ien,
+ EP_IEN__EOUTEN0__MASK | EP_IEN__EINEN0__MASK);
+
+ /* enable interrupt for device */
+ gadget_writel(usb_ss, &usb_ss->regs->usb_ien,
+ USB_IEN__U2RESIEN__MASK
+ | USB_ISTS__DIS2I__MASK
+ | USB_IEN__CON2IEN__MASK
+ | USB_IEN__UHRESIEN__MASK
+ | USB_IEN__UWRESIEN__MASK
+ | USB_IEN__DISIEN__MASK
+ | USB_IEN__CONIEN__MASK
+ | USB_IEN__U3EXTIEN__MASK
+ | USB_IEN__L2ENTIEN__MASK
+ | USB_IEN__L2EXTIEN__MASK);
+
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__CLK2OFFDS__MASK
+ /* | USB_CONF__USB3DIS__MASK */
+ | USB_CONF__L1DS__MASK);
+
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf,
+ USB_CONF__U1DS__MASK
+ | USB_CONF__U2DS__MASK
+ );
+
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf, USB_CONF__DEVEN__MASK);
+
+ gadget_writel(usb_ss, &usb_ss->regs->dbg_link1,
+ DBG_LINK1__LFPS_MIN_GEN_U1_EXIT_SET__MASK |
+ DBG_LINK1__LFPS_MIN_GEN_U1_EXIT__WRITE(0x3C));
+}
+
+static int cdns3_gadget_start(struct cdns3 *cdns)
+{
+ struct usb_ss_dev *usb_ss = container_of(cdns->gadget_dev,
+ struct usb_ss_dev, dev);
+ unsigned long flags;
+
+ dev_dbg(&usb_ss->dev, "%s begins\n", __func__);
+
+ pm_runtime_get_sync(cdns->dev);
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ usb_ss->start_gadget = 1;
+ if (!usb_ss->gadget_driver) {
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return 0;
+ }
+
+ __cdns3_gadget_start(usb_ss);
+ usb_ss->in_standby_mode = 0;
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ dev_dbg(&usb_ss->dev, "%s ends\n", __func__);
+ return 0;
+}
+
+static void __cdns3_gadget_stop(struct cdns3 *cdns)
+{
+ struct usb_ss_dev *usb_ss;
+ unsigned long flags;
+
+ usb_ss = container_of(cdns->gadget_dev, struct usb_ss_dev, dev);
+ if (usb_ss->gadget_driver)
+ usb_ss->gadget_driver->disconnect(&usb_ss->gadget);
+ usb_gadget_disconnect(&usb_ss->gadget);
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ usb_ss->gadget.speed = USB_SPEED_UNKNOWN;
+ /* disable interrupt for device */
+ gadget_writel(usb_ss, &usb_ss->regs->usb_ien, 0);
+ gadget_writel(usb_ss, &usb_ss->regs->usb_conf, USB_CONF__DEVDS__MASK);
+ usb_ss->start_gadget = 0;
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+}
+
+static void cdns3_gadget_stop(struct cdns3 *cdns)
+{
+ if (cdns->role == CDNS3_ROLE_GADGET)
+ __cdns3_gadget_stop(cdns);
+ pm_runtime_mark_last_busy(cdns->dev);
+ pm_runtime_put_autosuspend(cdns->dev);
+}
+
+static int cdns3_gadget_suspend(struct cdns3 *cdns, bool do_wakeup)
+{
+ __cdns3_gadget_stop(cdns);
+ return 0;
+}
+
+static int cdns3_gadget_resume(struct cdns3 *cdns, bool hibernated)
+{
+ struct usb_ss_dev *usb_ss = container_of(cdns->gadget_dev,
+ struct usb_ss_dev, dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&usb_ss->lock, flags);
+ usb_ss->start_gadget = 1;
+ if (!usb_ss->gadget_driver) {
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return 0;
+ }
+
+ __cdns3_gadget_start(usb_ss);
+ usb_ss->in_standby_mode = 0;
+ spin_unlock_irqrestore(&usb_ss->lock, flags);
+ return 0;
+}
+
+/**
+ * cdns3_gadget_init - initialize device structure
+ *
+ * cdns: cdns3 instance
+ *
+ * This function initializes the gadget.
+ */
+int cdns3_gadget_init(struct cdns3 *cdns)
+{
+ struct cdns3_role_driver *rdrv;
+
+ rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL);
+ if (!rdrv)
+ return -ENOMEM;
+
+ rdrv->start = cdns3_gadget_start;
+ rdrv->stop = cdns3_gadget_stop;
+ rdrv->suspend = cdns3_gadget_suspend;
+ rdrv->resume = cdns3_gadget_resume;
+ rdrv->irq = cdns_irq_handler_thread;
+ rdrv->name = "gadget";
+ cdns->roles[CDNS3_ROLE_GADGET] = rdrv;
+ return __cdns3_gadget_init(cdns);
+}
diff --git a/drivers/usb/cdns3/gadget.h b/drivers/usb/cdns3/gadget.h
new file mode 100644
index 000000000000..f0a576d8a4ea
--- /dev/null
+++ b/drivers/usb/cdns3/gadget.h
@@ -0,0 +1,225 @@
+/**
+ * gadget.h - Cadence USB3 device Controller Core file
+ *
+ * Copyright (C) 2016 Cadence Design Systems - http://www.cadence.com
+ * Copyright 2017 NXP
+ *
+ * Authors: Pawel Jez <pjez@cadence.com>,
+ * Konrad Kociolek <konrad@cadence.com>,
+ * Peter Chen <peter.chen@nxp.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __DRIVERS_CDNS3_GADGET
+#define __DRIVERS_CDNS3_GADGET
+
+#include "dev-regs-map.h"
+
+#if IS_ENABLED(CONFIG_USB_CDNS_MISC)
+#include "cdns_misc.h"
+#endif
+
+#define gadget_to_usb_ss(g) \
+ (container_of(g, struct usb_ss_dev, gadget))
+
+#define to_usb_ss_ep(ep) \
+ (container_of(ep, struct usb_ss_endpoint, endpoint))
+
+#define ep_to_usb_ss_ep(ep) \
+ (container_of(ep, struct usb_ss_endpoint, endpoint))
+
+/*-------------------------------------------------------------------------*/
+/* TRB macros */
+
+/* Common TRB fields */
+#define TRB_SET_CYCLE_BIT 1uL
+#define TRB_SET_CHAIN_BIT 0x10
+
+/* offset 0 */
+#define TRB_DATA_BUFFER_POINTER_MASK 0xFFFFFFFF
+#define TRB_SET_DATA_BUFFER_POINTER(p) (p & TRB_DATA_BUFFER_POINTER_MASK)
+
+/* offset 4 */
+#define TRB_TRANSFER_LENGTH_MASK 0x1FFFF
+#define TRB_SET_TRANSFER_LENGTH(l) (l & TRB_TRANSFER_LENGTH_MASK)
+
+#define TRB_BURST_LENGTH_MASK 0xFF
+#define TRB_SET_BURST_LENGTH(l) ((l & TRB_BURST_LENGTH_MASK) << 24)
+
+/* offset 8 */
+#define TRB_SET_INT_ON_SHORT_PACKET 0x04
+#define TRB_SET_FIFO_MODE 0x08
+#define TRB_SET_INT_ON_COMPLETION 0x20
+
+#define TRB_TYPE_NORMAL 0x400
+
+#define TRB_STREAM_ID_MASK 0xFFFF
+#define TRB_SET_STREAM_ID(sid) ((sid & TRB_STREAM_ID_MASK) << 16)
+
+/*-------------------------------------------------------------------------*/
+/* Driver numeric constants */
+
+
+#define DEVICE_ADDRESS_MAX 127
+
+/* Endpoint init values */
+#define ENDPOINT_MAX_PACKET_LIMIT 1024
+#define ENDPOINT_MAX_STREAMS 15
+
+#define ENDPOINT0_MAX_PACKET_LIMIT 512
+
+/* All endpoints except EP0 */
+#define USB_SS_ENDPOINTS_MAX_COUNT 30
+
+#define USB_SS_TRBS_NUM 32
+
+/* Standby mode */
+#define STB_CLK_SWITCH_DONE_MASK 0x200
+#define STB_CLK_SWITCH_EN_MASK 0x100
+#define STB_CLK_SWITCH_EN_SHIFT 8
+
+#define ENDPOINT_MAX_PACKET_SIZE_0 0
+#define ENDPOINT_MAX_PACKET_SIZE_8 8
+#define ENDPOINT_MAX_PACKET_SIZE_64 64
+#define ENDPOINT_MAX_PACKET_SIZE_512 512
+#define ENDPOINT_MAX_PACKET_SIZE_1023 1023
+#define ENDPOINT_MAX_PACKET_SIZE_1024 1024
+
+#define SS_LINK_STATE_U3 3
+#define FSHS_LPM_STATE_L2 2
+
+#define ADDR_MODULO_8 8
+
+#define INTERRUPT_MASK 0xFFFFFFFF
+
+#define ACTUAL_TRANSFERRED_BYTES_MASK 0x1FFFF
+
+#define ENDPOINT_DIR_MASK 0x80
+
+#define ENDPOINT_ZLP_BUF_SIZE 1024
+/*-------------------------------------------------------------------------*/
+
+/**
+ * IS_REG_REQUIRING_ACTIVE_REF_CLOCK - Macro checks if desired
+ * register requires active clock, it involves such registers as:
+ * EP_CFG, EP_TR_ADDR, EP_CMD, EP_SEL, USB_CONF
+ * @usb_ss: extended gadget object
+ * @reg: register address
+ */
+#define IS_REG_REQUIRING_ACTIVE_REF_CLOCK(usb_ss, reg) (!reg || \
+ (reg >= &usb_ss->regs->ep_sel && reg <= &usb_ss->regs->ep_cmd))
+
+/**
+ * CAST_EP_REG_POS_TO_INDEX - Macro converts bit position of ep_ists register to
+ * index of endpoint object in usb_ss_dev.eps[] container
+ * @i: bit position of endpoint for which endpoint object is required
+ *
+ * Remember that endpoint container doesn't contain default endpoint
+ */
+#define CAST_EP_REG_POS_TO_INDEX(i) (((i) / 16) + ((((i) % 16) - 2) * 2))
+
+/**
+ * CAST_EP_ADDR_TO_INDEX - Macro converts endpoint address to
+ * index of endpoint object in usb_ss_dev.eps[] container
+ * @ep_addr: endpoint address for which endpoint object is required
+ *
+ * Remember that endpoint container doesn't contain default endpoint
+ */
+#define CAST_EP_ADDR_TO_INDEX(ep_addr) \
+ (((ep_addr & 0x7F) - 1) + ((ep_addr & 0x80) ? 1 : 0))
+
+/**
+ * CAST_EP_ADDR_TO_BIT_POS - Macro converts endpoint address to
+ * bit position in ep_ists register
+ * @ep_addr: endpoint address for which bit position is required
+ *
+ * Remember that endpoint container doesn't contain default endpoint
+ */
+#define CAST_EP_ADDR_TO_BIT_POS(ep_addr) \
+ (((uint32_t)1 << (ep_addr & 0x7F)) << ((ep_addr & 0x80) ? 16 : 0))
+
+
+#define CAST_INDEX_TO_EP_ADDR(index) \
+ ((index / 2 + 1) | ((index % 2) ? 0x80 : 0x00))
+
+/* 18KB is the total size, and 2KB is used for EP0 and configuration */
+#define CDNS3_ONCHIP_BUF_SIZE 16 /* KB */
+#define CDNS3_EP_BUF_SIZE 2 /* KB */
+#define CDNS3_UNALIGNED_BUF_SIZE 16384 /* Bytes */
+/*-------------------------------------------------------------------------*/
+/* Used structs */
+
+struct usb_ss_trb {
+ u32 offset0;
+ u32 offset4;
+ u32 offset8;
+};
+
+struct usb_ss_dev;
+
+struct usb_ss_endpoint {
+ struct usb_ep endpoint;
+ struct list_head request_list;
+ struct list_head ep_match_pending_list;
+
+ struct usb_ss_trb *trb_pool;
+ dma_addr_t trb_pool_dma;
+
+ struct usb_ss_dev *usb_ss;
+ char name[20];
+ int hw_pending_flag;
+ int stalled_flag;
+ int wedge_flag;
+ void *cpu_addr;
+ dma_addr_t dma_addr;
+ u8 dir;
+ u8 num;
+ u8 type;
+ bool used;
+};
+
+struct usb_ss_dev {
+ struct device dev;
+ struct usbss_dev_register_block_type __iomem *regs;
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *gadget_driver;
+
+ dma_addr_t setup_dma;
+ dma_addr_t trb_ep0_dma;
+ u32 *trb_ep0;
+ u8 *setup;
+ void *zlp_buf;
+
+ struct usb_ss_endpoint *eps[USB_SS_ENDPOINTS_MAX_COUNT];
+ int ep_nums;
+ struct usb_request *actual_ep0_request;
+ int ep0_data_dir;
+ int hw_configured_flag;
+ int wake_up_flag;
+ u16 isoch_delay;
+ spinlock_t lock;
+
+ unsigned is_connected:1;
+ unsigned in_standby_mode:1;
+ unsigned status_completion_no_call:1;
+
+ u32 usb_ien;
+ u32 ep_ien;
+ int setup_pending;
+ struct device *sysdev;
+ bool start_gadget; /* The device mode is enabled */
+ struct list_head ep_match_list;
+ int onchip_mem_allocated_size; /* KB */
+ /* Memory is allocated for OUT */
+ int out_mem_is_allocated:1;
+ struct work_struct pending_status_wq;
+ struct usb_request *pending_status_request;
+};
+
+#endif /* __DRIVERS_CDNS3_GADGET */
diff --git a/drivers/usb/cdns3/host-export.h b/drivers/usb/cdns3/host-export.h
new file mode 100644
index 000000000000..a981d5cf3658
--- /dev/null
+++ b/drivers/usb/cdns3/host-export.h
@@ -0,0 +1,43 @@
+/*
+ * host-export.h - Host Export APIs
+ *
+ * Copyright 2017 NXP
+ * Authors: Peter Chen <peter.chen@nxp.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __DRIVERS_USB_CDNS3_HOST_H
+#define __DRIVERS_USB_CDNS3_HOST_H
+
+#ifdef CONFIG_USB_CDNS3_HOST
+
+int cdns3_host_init(struct cdns3 *cdns);
+void cdns3_host_remove(struct cdns3 *cdns);
+void cdns3_host_driver_init(void);
+
+#else
+
+static inline int cdns3_host_init(struct cdns3 *cdns)
+{
+ return -ENXIO;
+}
+
+static inline void cdns3_host_remove(struct cdns3 *cdns)
+{
+
+}
+
+static inline void cdns3_host_driver_init(void)
+{
+
+}
+
+#endif /* CONFIG_USB_CDNS3_HOST */
+
+#endif /* __DRIVERS_USB_CDNS3_HOST_H */
diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c
new file mode 100644
index 000000000000..4ed97339a724
--- /dev/null
+++ b/drivers/usb/cdns3/host.c
@@ -0,0 +1,259 @@
+/*
+ * host.c - Cadence USB3 host controller driver
+ *
+ * Copyright 2017 NXP
+ * Authors: Peter Chen <peter.chen@nxp.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/of.h>
+
+#include "../host/xhci.h"
+
+#include "core.h"
+#include "host-export.h"
+
+static struct hc_driver __read_mostly xhci_cdns3_hc_driver;
+
+static void xhci_cdns3_quirks(struct device *dev, struct xhci_hcd *xhci)
+{
+ /*
+ * As of now platform drivers don't provide MSI support so we ensure
+ * here that the generic code does not try to make a pci_dev from our
+ * dev struct in order to setup MSI
+ */
+ xhci->quirks |= (XHCI_PLAT | XHCI_CDNS_HOST);
+}
+
+static int xhci_cdns3_setup(struct usb_hcd *hcd)
+{
+ int ret;
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ u32 command;
+
+ ret = xhci_gen_setup(hcd, xhci_cdns3_quirks);
+ if (ret)
+ return ret;
+ /* set usbcmd.EU3S */
+ command = readl(&xhci->op_regs->command);
+ command |= CMD_PM_INDEX;
+ writel(command, &xhci->op_regs->command);
+
+ return 0;
+}
+
+static const struct xhci_driver_overrides xhci_cdns3_overrides __initconst = {
+ .extra_priv_size = sizeof(struct xhci_hcd),
+ .reset = xhci_cdns3_setup,
+};
+
+struct cdns3_host {
+ struct device dev;
+ struct usb_hcd *hcd;
+};
+
+static irqreturn_t cdns3_host_irq(struct cdns3 *cdns)
+{
+ struct device *dev = cdns->host_dev;
+ struct usb_hcd *hcd;
+
+ if (dev)
+ hcd = dev_get_drvdata(dev);
+ else
+ return IRQ_NONE;
+
+ if (hcd)
+ return usb_hcd_irq(cdns->irq, hcd);
+ else
+ return IRQ_NONE;
+}
+
+static void cdns3_host_release(struct device *dev)
+{
+ struct cdns3_host *host = container_of(dev, struct cdns3_host, dev);
+
+ dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
+ kfree(host);
+}
+
+static int cdns3_host_start(struct cdns3 *cdns)
+{
+ struct cdns3_host *host;
+ struct device *dev;
+ struct device *sysdev;
+ struct xhci_hcd *xhci;
+ int ret;
+
+ host = kzalloc(sizeof(*host), GFP_KERNEL);
+ if (!host)
+ return -ENOMEM;
+
+ dev = &host->dev;
+ dev->release = cdns3_host_release;
+ dev->parent = cdns->dev;
+ dev_set_name(dev, "xhci-cdns3");
+ cdns->host_dev = dev;
+ ret = device_register(dev);
+ if (ret)
+ goto err1;
+
+ sysdev = cdns->dev;
+ /* Try to set 64-bit DMA first */
+ if (WARN_ON(!sysdev->dma_mask))
+ /* Platform did not initialize dma_mask */
+ ret = dma_coerce_mask_and_coherent(sysdev,
+ DMA_BIT_MASK(64));
+ else
+ ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
+
+ /* If setting 64-bit DMA mask fails, fall back to 32-bit DMA mask */
+ if (ret) {
+ ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+ }
+ pm_runtime_set_active(dev);
+ pm_runtime_no_callbacks(dev);
+ pm_runtime_enable(dev);
+
+ host->hcd = __usb_create_hcd(&xhci_cdns3_hc_driver, sysdev, dev,
+ dev_name(dev), NULL);
+ if (!host->hcd) {
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ host->hcd->regs = cdns->xhci_regs;
+ host->hcd->rsrc_start = cdns->xhci_res->start;
+ host->hcd->rsrc_len = resource_size(cdns->xhci_res);
+
+ device_wakeup_enable(host->hcd->self.controller);
+
+ xhci = hcd_to_xhci(host->hcd);
+
+ xhci->quirks = XHCI_SKIP_ACCESS_RESERVED_REG;
+ xhci->main_hcd = host->hcd;
+ xhci->shared_hcd = __usb_create_hcd(&xhci_cdns3_hc_driver, sysdev, dev,
+ dev_name(dev), host->hcd);
+ if (!xhci->shared_hcd) {
+ ret = -ENOMEM;
+ goto err3;
+ }
+ host->hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node);
+ xhci->shared_hcd->tpl_support = host->hcd->tpl_support;
+
+ ret = usb_add_hcd(host->hcd, 0, IRQF_SHARED);
+ if (ret)
+ goto err4;
+
+ ret = usb_add_hcd(xhci->shared_hcd, 0, IRQF_SHARED);
+ if (ret)
+ goto err5;
+
+ device_set_wakeup_capable(dev, true);
+ dev_dbg(dev, "%s ends\n", __func__);
+
+ return 0;
+
+err5:
+ usb_remove_hcd(host->hcd);
+err4:
+ usb_put_hcd(xhci->shared_hcd);
+err3:
+ usb_put_hcd(host->hcd);
+err2:
+ device_del(dev);
+err1:
+ put_device(dev);
+ cdns->host_dev = NULL;
+ return ret;
+}
+
+static void cdns3_host_stop(struct cdns3 *cdns)
+{
+ struct device *dev = cdns->host_dev;
+ struct usb_hcd *hcd;
+ struct xhci_hcd *xhci;
+
+ if (dev) {
+ hcd = dev_get_drvdata(dev);
+ xhci = hcd_to_xhci(hcd);
+ usb_remove_hcd(xhci->shared_hcd);
+ usb_remove_hcd(hcd);
+ synchronize_irq(cdns->irq);
+ usb_put_hcd(xhci->shared_hcd);
+ usb_put_hcd(hcd);
+ cdns->host_dev = NULL;
+ pm_runtime_set_suspended(dev);
+ pm_runtime_disable(dev);
+ device_del(dev);
+ put_device(dev);
+ }
+}
+
+static int cdns3_host_suspend(struct cdns3 *cdns, bool do_wakeup)
+{
+ struct device *dev = cdns->host_dev;
+ struct xhci_hcd *xhci;
+
+ if (!dev)
+ return 0;
+
+ xhci = hcd_to_xhci(dev_get_drvdata(dev));
+ return xhci_suspend(xhci, do_wakeup);
+}
+
+static int cdns3_host_resume(struct cdns3 *cdns, bool hibernated)
+{
+ struct device *dev = cdns->host_dev;
+ struct xhci_hcd *xhci;
+
+ if (!dev)
+ return 0;
+
+ xhci = hcd_to_xhci(dev_get_drvdata(dev));
+ return xhci_resume(xhci, hibernated);
+}
+
+int cdns3_host_init(struct cdns3 *cdns)
+{
+ struct cdns3_role_driver *rdrv;
+
+ rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL);
+ if (!rdrv)
+ return -ENOMEM;
+
+ rdrv->start = cdns3_host_start;
+ rdrv->stop = cdns3_host_stop;
+ rdrv->irq = cdns3_host_irq;
+ rdrv->suspend = cdns3_host_suspend;
+ rdrv->resume = cdns3_host_resume;
+ rdrv->name = "host";
+ cdns->roles[CDNS3_ROLE_HOST] = rdrv;
+
+ return 0;
+}
+
+void cdns3_host_remove(struct cdns3 *cdns)
+{
+ cdns3_host_stop(cdns);
+}
+
+void __init cdns3_host_driver_init(void)
+{
+ xhci_init_driver(&xhci_cdns3_hc_driver, &xhci_cdns3_overrides);
+}
diff --git a/drivers/usb/cdns3/io.h b/drivers/usb/cdns3/io.h
new file mode 100644
index 000000000000..c16edbf54b8b
--- /dev/null
+++ b/drivers/usb/cdns3/io.h
@@ -0,0 +1,35 @@
+/**
+ * io.h - Cadence USB3 IO Header
+ *
+ * Copyright (C) 2016 Cadence Design Systems - https://www.cadence.com/
+ *
+ * Authors: Rafal Ozieblo <rafalo@cadence.com>,
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __DRIVERS_USB_CDNS_IO_H
+#define __DRIVERS_USB_CDNS_IO_H
+
+#include <linux/io.h>
+
+static inline u32 cdns_readl(uint32_t __iomem *reg)
+{
+ u32 value = 0;
+
+ value = readl(reg);
+ return value;
+}
+
+static inline void cdns_writel(uint32_t __iomem *reg, u32 value)
+{
+ writel(value, reg);
+}
+
+
+#endif /* __DRIVERS_USB_CDNS_IO_H */
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 05bc4d631cb9..33c99e2fc8fe 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -125,12 +125,16 @@ enum ci_revision {
* @start: start this role
* @stop: stop this role
* @irq: irq handler for this role
+ * @suspend: system suspend handler for this role
+ * @resume: system resume handler for this role
* @name: role name string (host/gadget)
*/
struct ci_role_driver {
int (*start)(struct ci_hdrc *);
void (*stop)(struct ci_hdrc *);
irqreturn_t (*irq)(struct ci_hdrc *);
+ void (*suspend)(struct ci_hdrc *);
+ void (*resume)(struct ci_hdrc *, bool power_lost);
const char *name;
};
@@ -174,6 +178,7 @@ struct hw_bank {
* @td_pool: allocation pool for transfer descriptors
* @gadget: device side representation for peripheral controller
* @driver: gadget driver
+ * @resume_state: save the state of gadget suspend from
* @hw_ep_max: total number of endpoints supported by hardware
* @ci_hw_ep: array of endpoints
* @ep0_dir: ep0 direction
@@ -193,12 +198,14 @@ struct hw_bank {
* @debugfs: root dentry for this controller in debugfs
* @id_event: indicates there is an id event, and handled at ci_otg_work
* @b_sess_valid_event: indicates there is a vbus event, and handled
+ * @vbus_glitch_check_event: check if vbus change is a glitch
* at ci_otg_work
* @imx28_write_fix: Freescale imx28 needs swp instruction for writing
* @supports_runtime_pm: if runtime pm is supported
* @in_lpm: if the core in low power mode
* @wakeup_int: if wakeup interrupt occur
* @rev: The revision number for controller
+ * @mutex: protect code from concorrent running
*/
struct ci_hdrc {
struct device *dev;
@@ -222,6 +229,7 @@ struct ci_hdrc {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
+ enum usb_device_state resume_state;
unsigned hw_ep_max;
struct ci_hw_ep ci_hw_ep[ENDPT_MAX];
u32 ep0_dir;
@@ -243,11 +251,25 @@ struct ci_hdrc {
struct dentry *debugfs;
bool id_event;
bool b_sess_valid_event;
+ bool vbus_glitch_check_event;
bool imx28_write_fix;
bool supports_runtime_pm;
bool in_lpm;
bool wakeup_int;
enum ci_revision rev;
+ /* register save area for suspend&resume */
+ u32 pm_command;
+ u32 pm_status;
+ u32 pm_intr_enable;
+ u32 pm_frame_index;
+ u32 pm_segment;
+ u32 pm_frame_list;
+ u32 pm_async_next;
+ u32 pm_configured_flag;
+ u32 pm_portsc;
+ u32 pm_usbmode;
+ struct work_struct power_lost_work;
+ struct mutex mutex;
};
static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci)
@@ -267,9 +289,21 @@ static inline int ci_role_start(struct ci_hdrc *ci, enum ci_role role)
return -ENXIO;
ret = ci->roles[role]->start(ci);
- if (!ret)
- ci->role = role;
- return ret;
+ if (ret)
+ return ret;
+
+ ci->role = role;
+
+ if (ci->usb_phy) {
+ if (role == CI_ROLE_HOST)
+ usb_phy_set_mode(ci->usb_phy,
+ USB_MODE_HOST);
+ else
+ usb_phy_set_mode(ci->usb_phy,
+ USB_MODE_DEVICE);
+ }
+
+ return 0;
}
static inline void ci_role_stop(struct ci_hdrc *ci)
@@ -282,6 +316,9 @@ static inline void ci_role_stop(struct ci_hdrc *ci)
ci->role = CI_ROLE_END;
ci->roles[role]->stop(ci);
+
+ if (ci->usb_phy)
+ usb_phy_set_mode(ci->usb_phy, USB_MODE_NONE);
}
/**
@@ -429,6 +466,7 @@ int hw_port_test_set(struct ci_hdrc *ci, u8 mode);
u8 hw_port_test_get(struct ci_hdrc *ci);
void ci_platform_configure(struct ci_hdrc *ci);
+int hw_controller_reset(struct ci_hdrc *ci);
int dbg_create_files(struct ci_hdrc *ci);
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 099179457f60..53f48cc2eeb5 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -1,5 +1,6 @@
/*
- * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
* Copyright (C) 2012 Marek Vasut <marex@denx.de>
* on behalf of DENX Software Engineering GmbH
*
@@ -19,6 +20,13 @@
#include <linux/dma-mapping.h>
#include <linux/usb/chipidea.h>
#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regulator/consumer.h>
+#include <linux/busfreq-imx.h>
+#include <linux/pm_qos.h>
+#include <linux/usb/of.h>
#include "ci.h"
#include "ci_hdrc_imx.h"
@@ -40,25 +48,29 @@ static const struct ci_hdrc_imx_platform_flag imx27_usb_data = {
static const struct ci_hdrc_imx_platform_flag imx28_usb_data = {
.flags = CI_HDRC_IMX28_WRITE_FIX |
CI_HDRC_TURN_VBUS_EARLY_ON |
- CI_HDRC_DISABLE_STREAMING,
+ CI_HDRC_DISABLE_STREAMING |
+ CI_HDRC_IMX_EHCI_QUIRK,
};
static const struct ci_hdrc_imx_platform_flag imx6q_usb_data = {
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
CI_HDRC_TURN_VBUS_EARLY_ON |
- CI_HDRC_DISABLE_STREAMING,
+ CI_HDRC_DISABLE_STREAMING |
+ CI_HDRC_IMX_EHCI_QUIRK,
};
static const struct ci_hdrc_imx_platform_flag imx6sl_usb_data = {
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
CI_HDRC_TURN_VBUS_EARLY_ON |
- CI_HDRC_DISABLE_HOST_STREAMING,
+ CI_HDRC_DISABLE_HOST_STREAMING |
+ CI_HDRC_IMX_EHCI_QUIRK,
};
static const struct ci_hdrc_imx_platform_flag imx6sx_usb_data = {
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
CI_HDRC_TURN_VBUS_EARLY_ON |
- CI_HDRC_DISABLE_HOST_STREAMING,
+ CI_HDRC_DISABLE_HOST_STREAMING |
+ CI_HDRC_IMX_EHCI_QUIRK,
};
static const struct ci_hdrc_imx_platform_flag imx6ul_usb_data = {
@@ -70,6 +82,16 @@ static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = {
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM,
};
+static const struct ci_hdrc_imx_platform_flag imx7ulp_usb_data = {
+ .flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
+ CI_HDRC_IMX_EHCI_QUIRK |
+ CI_HDRC_PMQOS,
+};
+
+static const struct ci_hdrc_imx_platform_flag imx8qm_usb_data = {
+ .flags = CI_HDRC_SUPPORTS_RUNTIME_PM,
+};
+
static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
{ .compatible = "fsl,imx23-usb", .data = &imx23_usb_data},
{ .compatible = "fsl,imx28-usb", .data = &imx28_usb_data},
@@ -79,6 +101,8 @@ static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
{ .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data},
{ .compatible = "fsl,imx6ul-usb", .data = &imx6ul_usb_data},
{ .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data},
+ { .compatible = "fsl,imx7ulp-usb", .data = &imx7ulp_usb_data},
+ { .compatible = "fsl,imx8qm-usb", .data = &imx8qm_usb_data},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
@@ -90,12 +114,30 @@ struct ci_hdrc_imx_data {
struct imx_usbmisc_data *usbmisc_data;
bool supports_runtime_pm;
bool in_lpm;
+ bool imx_usb_charger_detection;
+ struct usb_charger charger;
+ struct regmap *anatop;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pinctrl_hsic_active;
+ struct regulator *hsic_pad_regulator;
+ const struct ci_hdrc_imx_platform_flag *data;
/* SoC before i.mx6 (except imx23/imx28) needs three clks */
bool need_three_clks;
struct clk *clk_ipg;
struct clk *clk_ahb;
struct clk *clk_per;
/* --------------------------------- */
+ struct pm_qos_request pm_qos_req;
+};
+
+static char *imx_usb_charger_supplied_to[] = {
+ "imx_usb_charger",
+};
+
+static enum power_supply_property imx_usb_charger_power_props[] = {
+ POWER_SUPPLY_PROP_PRESENT, /* Charger detected */
+ POWER_SUPPLY_PROP_ONLINE, /* VBUS online */
+ POWER_SUPPLY_PROP_CURRENT_MAX, /* Maximum current in mA */
};
/* Common functions shared by usbmisc drivers */
@@ -143,9 +185,32 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
if (of_find_property(np, "over-current-active-high", NULL))
data->oc_polarity = 1;
+ if (of_find_property(np, "power-polarity-active-high", NULL))
+ data->pwr_polarity = 1;
+
if (of_find_property(np, "external-vbus-divider", NULL))
data->evdo = 1;
+ if (of_find_property(np, "osc-clkgate-delay", NULL)) {
+ ret = of_property_read_u32(np, "osc-clkgate-delay",
+ &data->osc_clkgate_delay);
+ if (ret) {
+ dev_err(dev,
+ "failed to get osc-clkgate-delay value\n");
+ return ERR_PTR(ret);
+ }
+ /*
+ * 0 <= osc_clkgate_delay <=7
+ * - 0x0 (default) is 0.5ms,
+ * - 0x1-0x7: 1-7ms
+ */
+ if (data->osc_clkgate_delay > 7) {
+ dev_err(dev,
+ "value of osc-clkgate-delay is incorrect\n");
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
return data;
}
@@ -247,41 +312,212 @@ static void imx_disable_unprepare_clks(struct device *dev)
}
}
+static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned event)
+{
+ struct device *dev = ci->dev->parent;
+ struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
+ int ret = 0;
+
+ switch (event) {
+ case CI_HDRC_CONTROLLER_VBUS_EVENT:
+ if (data->usbmisc_data && ci->vbus_active) {
+ if (data->imx_usb_charger_detection) {
+ ret = imx_usbmisc_charger_detection(
+ data->usbmisc_data, true);
+ if (!ret && data->charger.psy_desc.type !=
+ POWER_SUPPLY_TYPE_USB)
+ ret = CI_HDRC_NOTIFY_RET_DEFER_EVENT;
+ }
+ } else if (data->usbmisc_data && !ci->vbus_active) {
+ if (data->imx_usb_charger_detection)
+ ret = imx_usbmisc_charger_detection(
+ data->usbmisc_data, false);
+ }
+ break;
+ case CI_HDRC_CONTROLLER_CHARGER_POST_EVENT:
+ if (!data->imx_usb_charger_detection)
+ return ret;
+ imx_usbmisc_charger_secondary_detection(data->usbmisc_data);
+ break;
+ case CI_HDRC_IMX_HSIC_ACTIVE_EVENT:
+ if (!IS_ERR(data->pinctrl) &&
+ !IS_ERR(data->pinctrl_hsic_active)) {
+ ret = pinctrl_select_state(data->pinctrl,
+ data->pinctrl_hsic_active);
+ if (ret)
+ dev_err(dev,
+ "hsic_active select failed, err=%d\n",
+ ret);
+ return ret;
+ }
+ break;
+ case CI_HDRC_IMX_HSIC_SUSPEND_EVENT:
+ if (data->usbmisc_data) {
+ ret = imx_usbmisc_hsic_set_connect(data->usbmisc_data);
+ if (ret)
+ dev_err(dev,
+ "hsic_set_connect failed, err=%d\n",
+ ret);
+ return ret;
+ }
+ break;
+ case CI_HDRC_IMX_TERM_SELECT_OVERRIDE_FS:
+ if (data->usbmisc_data)
+ return imx_usbmisc_term_select_override(
+ data->usbmisc_data, true, 1);
+ break;
+ case CI_HDRC_IMX_TERM_SELECT_OVERRIDE_OFF:
+ if (data->usbmisc_data)
+ return imx_usbmisc_term_select_override(
+ data->usbmisc_data, false, 0);
+ break;
+ default:
+ dev_dbg(dev, "unknown event\n");
+ }
+
+ return ret;
+}
+
+static int imx_usb_charger_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct usb_charger *charger =
+ container_of(psy->desc, struct usb_charger, psy_desc);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = charger->present;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = charger->online;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = charger->max_current;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * imx_usb_register_charger - register a USB charger
+ * @charger: the charger to be initialized
+ * @name: name for the power supply
+
+ * Registers a power supply for the charger. The USB Controller
+ * driver will call this after filling struct usb_charger.
+ */
+static int imx_usb_register_charger(struct usb_charger *charger,
+ const char *name)
+{
+ struct power_supply_desc *desc = &charger->psy_desc;
+
+ if (!charger->dev)
+ return -EINVAL;
+
+ if (name)
+ desc->name = name;
+ else
+ desc->name = "imx_usb_charger";
+
+ charger->bc = BATTERY_CHARGING_SPEC_1_2;
+ mutex_init(&charger->lock);
+
+ desc->type = POWER_SUPPLY_TYPE_MAINS;
+ desc->properties = imx_usb_charger_power_props;
+ desc->num_properties = ARRAY_SIZE(imx_usb_charger_power_props);
+ desc->get_property = imx_usb_charger_get_property;
+
+ charger->psy = devm_power_supply_register(charger->dev,
+ &charger->psy_desc, NULL);
+ if (IS_ERR(charger->psy))
+ return PTR_ERR(charger->psy);
+
+ charger->psy->supplied_to = imx_usb_charger_supplied_to;
+ charger->psy->num_supplicants = sizeof(imx_usb_charger_supplied_to)
+ / sizeof(char *);
+
+ return 0;
+}
+
static int ci_hdrc_imx_probe(struct platform_device *pdev)
{
struct ci_hdrc_imx_data *data;
struct ci_hdrc_platform_data pdata = {
.name = dev_name(&pdev->dev),
.capoffset = DEF_CAPOFFSET,
+ .notify_event = ci_hdrc_imx_notify_event,
};
int ret;
const struct of_device_id *of_id;
const struct ci_hdrc_imx_platform_flag *imx_platform_flag;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct pinctrl_state *pinctrl_hsic_idle;
- of_id = of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev);
+ of_id = of_match_device(ci_hdrc_imx_dt_ids, dev);
if (!of_id)
return -ENODEV;
imx_platform_flag = of_id->data;
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
platform_set_drvdata(pdev, data);
- data->usbmisc_data = usbmisc_get_init_data(&pdev->dev);
+
+ data->data = imx_platform_flag;
+ pdata.flags |= imx_platform_flag->flags;
+ data->usbmisc_data = usbmisc_get_init_data(dev);
if (IS_ERR(data->usbmisc_data))
return PTR_ERR(data->usbmisc_data);
- ret = imx_get_clks(&pdev->dev);
+ data->pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(data->pinctrl)) {
+ dev_dbg(dev, "pinctrl get failed, err=%ld\n",
+ PTR_ERR(data->pinctrl));
+ } else {
+ pinctrl_hsic_idle = pinctrl_lookup_state(data->pinctrl, "idle");
+ if (IS_ERR(pinctrl_hsic_idle)) {
+ dev_dbg(dev,
+ "pinctrl_hsic_idle lookup failed, err=%ld\n",
+ PTR_ERR(pinctrl_hsic_idle));
+ } else {
+ ret = pinctrl_select_state(data->pinctrl,
+ pinctrl_hsic_idle);
+ if (ret) {
+ dev_err(dev,
+ "hsic_idle select failed, err=%d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ data->pinctrl_hsic_active = pinctrl_lookup_state(data->pinctrl,
+ "active");
+ if (IS_ERR(data->pinctrl_hsic_active))
+ dev_dbg(dev,
+ "pinctrl_hsic_active lookup failed, err=%ld\n",
+ PTR_ERR(data->pinctrl_hsic_active));
+ }
+
+ ret = imx_get_clks(dev);
if (ret)
return ret;
- ret = imx_prepare_enable_clks(&pdev->dev);
+ request_bus_freq(BUS_FREQ_HIGH);
+ if (pdata.flags & CI_HDRC_PMQOS)
+ pm_qos_add_request(&data->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, 0);
+
+ ret = imx_prepare_enable_clks(dev);
if (ret)
- return ret;
+ goto err_bus_freq;
- data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0);
+ data->phy = devm_usb_get_phy_by_phandle(dev, "fsl,usbphy", 0);
if (IS_ERR(data->phy)) {
ret = PTR_ERR(data->phy);
/* Return -EINVAL if no usbphy is available */
@@ -291,46 +527,119 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
}
pdata.usb_phy = data->phy;
- pdata.flags |= imx_platform_flag->flags;
if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM)
data->supports_runtime_pm = true;
+ if (of_find_property(np, "ci-disable-lpm", NULL)) {
+ data->supports_runtime_pm = false;
+ pdata.flags &= ~CI_HDRC_SUPPORTS_RUNTIME_PM;
+ }
+
+ if (of_usb_get_phy_mode(dev->of_node) == USBPHY_INTERFACE_MODE_HSIC) {
+ pdata.flags |= CI_HDRC_IMX_IS_HSIC;
+ data->usbmisc_data->hsic = 1;
+ data->hsic_pad_regulator = devm_regulator_get(dev, "pad");
+ if (PTR_ERR(data->hsic_pad_regulator) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto err_clk;
+ } else if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) {
+ /* no pad regualator is needed */
+ data->hsic_pad_regulator = NULL;
+ } else if (IS_ERR(data->hsic_pad_regulator)) {
+ dev_err(dev, "Get hsic pad regulator error: %ld\n",
+ PTR_ERR(data->hsic_pad_regulator));
+ ret = PTR_ERR(data->hsic_pad_regulator);
+ goto err_clk;
+ }
+
+ if (data->hsic_pad_regulator) {
+ ret = regulator_enable(data->hsic_pad_regulator);
+ if (ret) {
+ dev_err(dev,
+ "Fail to enable hsic pad regulator\n");
+ goto err_clk;
+ }
+ }
+ }
+
+ if (of_find_property(np, "fsl,anatop", NULL) && data->usbmisc_data) {
+ data->anatop = syscon_regmap_lookup_by_phandle(np,
+ "fsl,anatop");
+ if (IS_ERR(data->anatop)) {
+ dev_dbg(dev, "failed to find regmap for anatop\n");
+ ret = PTR_ERR(data->anatop);
+ goto disable_hsic_regulator;
+ }
+ data->usbmisc_data->anatop = data->anatop;
+ }
+
+ if (of_find_property(np, "imx-usb-charger-detection", NULL) &&
+ data->usbmisc_data) {
+ data->imx_usb_charger_detection = true;
+ data->charger.dev = dev;
+ data->usbmisc_data->charger = &data->charger;
+ ret = imx_usb_register_charger(&data->charger,
+ "imx_usb_charger");
+ if (ret && ret != -ENODEV)
+ goto disable_hsic_regulator;
+ if (!ret)
+ dev_dbg(dev, "USB Charger is created\n");
+ }
+
ret = imx_usbmisc_init(data->usbmisc_data);
if (ret) {
- dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret);
- goto err_clk;
+ dev_err(dev, "usbmisc init failed, ret=%d\n", ret);
+ goto disable_hsic_regulator;
}
- data->ci_pdev = ci_hdrc_add_device(&pdev->dev,
+ data->ci_pdev = ci_hdrc_add_device(dev,
pdev->resource, pdev->num_resources,
&pdata);
if (IS_ERR(data->ci_pdev)) {
ret = PTR_ERR(data->ci_pdev);
if (ret != -EPROBE_DEFER)
- dev_err(&pdev->dev,
+ dev_err(dev,
"ci_hdrc_add_device failed, err=%d\n", ret);
- goto err_clk;
+ goto disable_hsic_regulator;
}
ret = imx_usbmisc_init_post(data->usbmisc_data);
if (ret) {
- dev_err(&pdev->dev, "usbmisc post failed, ret=%d\n", ret);
+ dev_err(dev, "usbmisc post failed, ret=%d\n", ret);
goto disable_device;
}
+ ret = imx_usbmisc_set_wakeup(data->usbmisc_data, false);
+ if (ret) {
+ dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
+ goto disable_device;
+ }
+
+ /* usbmisc needs to know dr mode to choose wakeup setting */
+ if (data->usbmisc_data)
+ data->usbmisc_data->available_role =
+ ci_hdrc_query_available_role(data->ci_pdev);
+
if (data->supports_runtime_pm) {
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
}
- device_set_wakeup_capable(&pdev->dev, true);
+ device_set_wakeup_capable(dev, true);
return 0;
disable_device:
ci_hdrc_remove_device(data->ci_pdev);
+disable_hsic_regulator:
+ if (data->hsic_pad_regulator)
+ ret = regulator_disable(data->hsic_pad_regulator);
err_clk:
imx_disable_unprepare_clks(&pdev->dev);
+err_bus_freq:
+ if (pdata.flags & CI_HDRC_PMQOS)
+ pm_qos_remove_request(&data->pm_qos_req);
+ release_bus_freq(BUS_FREQ_HIGH);
return ret;
}
@@ -345,6 +654,11 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
}
ci_hdrc_remove_device(data->ci_pdev);
imx_disable_unprepare_clks(&pdev->dev);
+ if (data->data->flags & CI_HDRC_PMQOS)
+ pm_qos_remove_request(&data->pm_qos_req);
+ release_bus_freq(BUS_FREQ_HIGH);
+ if (data->hsic_pad_regulator)
+ regulator_disable(data->hsic_pad_regulator);
return 0;
}
@@ -358,10 +672,23 @@ static void ci_hdrc_imx_shutdown(struct platform_device *pdev)
static int imx_controller_suspend(struct device *dev)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
+ int ret;
dev_dbg(dev, "at %s\n", __func__);
+ if (data->usbmisc_data) {
+ ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, false);
+ if (ret) {
+ dev_err(dev,
+ "usbmisc hsic_set_clk failed, ret=%d\n", ret);
+ return ret;
+ }
+ }
+
imx_disable_unprepare_clks(dev);
+ if (data->data->flags & CI_HDRC_PMQOS)
+ pm_qos_remove_request(&data->pm_qos_req);
+ release_bus_freq(BUS_FREQ_HIGH);
data->in_lpm = true;
return 0;
@@ -374,27 +701,51 @@ static int imx_controller_resume(struct device *dev)
dev_dbg(dev, "at %s\n", __func__);
- if (!data->in_lpm) {
- WARN_ON(1);
+ if (!data->in_lpm)
return 0;
- }
+ request_bus_freq(BUS_FREQ_HIGH);
+ if (data->data->flags & CI_HDRC_PMQOS)
+ pm_qos_add_request(&data->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, 0);
ret = imx_prepare_enable_clks(dev);
if (ret)
- return ret;
+ goto err_bus_freq;
data->in_lpm = false;
+ ret = imx_usbmisc_power_lost_check(data->usbmisc_data);
+ /* re-init if resume from power lost */
+ if (ret > 0) {
+ ret = imx_usbmisc_init(data->usbmisc_data);
+ if (ret) {
+ dev_err(dev, "usbmisc init failed, ret=%d\n", ret);
+ goto clk_disable;
+ }
+ }
+
ret = imx_usbmisc_set_wakeup(data->usbmisc_data, false);
if (ret) {
dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
goto clk_disable;
}
+ ret = imx_usbmisc_hsic_set_clk(data->usbmisc_data, true);
+ if (ret) {
+ dev_err(dev, "usbmisc hsic_set_clk failed, ret=%d\n", ret);
+ goto hsic_set_clk_fail;
+ }
+
return 0;
+hsic_set_clk_fail:
+ imx_usbmisc_set_wakeup(data->usbmisc_data, true);
clk_disable:
imx_disable_unprepare_clks(dev);
+err_bus_freq:
+ if (data->data->flags & CI_HDRC_PMQOS)
+ pm_qos_remove_request(&data->pm_qos_req);
+ release_bus_freq(BUS_FREQ_HIGH);
return ret;
}
@@ -442,10 +793,8 @@ static int ci_hdrc_imx_runtime_suspend(struct device *dev)
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
int ret;
- if (data->in_lpm) {
- WARN_ON(1);
+ if (data->in_lpm)
return 0;
- }
ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
if (ret) {
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h
index 409aa5ca8dda..8d86a9dbdfe0 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.h
+++ b/drivers/usb/chipidea/ci_hdrc_imx.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012-2015 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
@@ -11,18 +11,61 @@
#ifndef __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H
#define __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H
+#include <linux/usb/otg.h>
+#include <linux/power_supply.h>
+
+enum battery_charging_spec {
+ BATTERY_CHARGING_SPEC_NONE = 0,
+ BATTERY_CHARGING_SPEC_UNKNOWN,
+ BATTERY_CHARGING_SPEC_1_0,
+ BATTERY_CHARGING_SPEC_1_1,
+ BATTERY_CHARGING_SPEC_1_2,
+};
+
+struct usb_charger {
+ /* USB controller */
+ struct device *dev;
+ struct power_supply *psy;
+ struct power_supply_desc psy_desc;
+ struct mutex lock;
+
+ /* Compliant with Battery Charging Specification version (if any) */
+ enum battery_charging_spec bc;
+
+ /* properties */
+ unsigned present:1;
+ unsigned online:1;
+ unsigned max_current;
+};
struct imx_usbmisc_data {
struct device *dev;
int index;
+ struct regmap *anatop;
+ struct usb_charger *charger;
unsigned int disable_oc:1; /* over current detect disabled */
unsigned int oc_polarity:1; /* over current polarity if oc enabled */
+ unsigned int pwr_polarity:1; /* polarity of enable vbus from pmic */
unsigned int evdo:1; /* set external vbus divider option */
+ unsigned int hsic:1; /* HSIC controlller */
+ /*
+ * Specifies the delay between powering up the xtal 24MHz clock
+ * and release the clock to the digital logic inside the analog block
+ */
+ unsigned int osc_clkgate_delay;
+ enum usb_dr_mode available_role;
};
int imx_usbmisc_init(struct imx_usbmisc_data *);
int imx_usbmisc_init_post(struct imx_usbmisc_data *);
int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *, bool);
+int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect);
+int imx_usbmisc_charger_secondary_detection(struct imx_usbmisc_data *data);
+int imx_usbmisc_power_lost_check(struct imx_usbmisc_data *);
+int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *);
+int imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *, bool);
+int imx_usbmisc_term_select_override(struct imx_usbmisc_data *data,
+ bool enable, int val);
#endif /* __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H */
diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c
index 37591a4b1346..6d5cf973dba6 100644
--- a/drivers/usb/chipidea/ci_hdrc_msm.c
+++ b/drivers/usb/chipidea/ci_hdrc_msm.c
@@ -17,7 +17,7 @@
#define MSM_USB_BASE (ci->hw_bank.abs)
-static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
+static int ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
{
struct device *dev = ci->gadget.dev.parent;
@@ -40,6 +40,8 @@ static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
dev_dbg(dev, "unknown ci_hdrc event\n");
break;
}
+
+ return 0;
}
static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = {
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 64c6af2c8559..a9b3795a150b 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -461,7 +461,7 @@ void ci_platform_configure(struct ci_hdrc *ci)
*
* This function returns an error code
*/
-static int hw_controller_reset(struct ci_hdrc *ci)
+int hw_controller_reset(struct ci_hdrc *ci)
{
int count = 0;
@@ -555,7 +555,7 @@ static irqreturn_t ci_irq(int irq, void *data)
* and disconnection events.
*/
if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
- ci->b_sess_valid_event = true;
+ ci->vbus_glitch_check_event = true;
/* Clear BSV irq */
hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS);
ci_otg_queue_work(ci);
@@ -569,35 +569,14 @@ static irqreturn_t ci_irq(int irq, void *data)
return ret;
}
-static int ci_vbus_notifier(struct notifier_block *nb, unsigned long event,
- void *ptr)
+static int ci_cable_notifier(struct notifier_block *nb, unsigned long event,
+ void *ptr)
{
- struct ci_hdrc_cable *vbus = container_of(nb, struct ci_hdrc_cable, nb);
- struct ci_hdrc *ci = vbus->ci;
+ struct ci_hdrc_cable *cbl = container_of(nb, struct ci_hdrc_cable, nb);
+ struct ci_hdrc *ci = cbl->ci;
- if (event)
- vbus->state = true;
- else
- vbus->state = false;
-
- vbus->changed = true;
-
- ci_irq(ci->irq, ci);
- return NOTIFY_DONE;
-}
-
-static int ci_id_notifier(struct notifier_block *nb, unsigned long event,
- void *ptr)
-{
- struct ci_hdrc_cable *id = container_of(nb, struct ci_hdrc_cable, nb);
- struct ci_hdrc *ci = id->ci;
-
- if (event)
- id->state = false;
- else
- id->state = true;
-
- id->changed = true;
+ cbl->connected = event;
+ cbl->changed = true;
ci_irq(ci->irq, ci);
return NOTIFY_DONE;
@@ -706,27 +685,27 @@ static int ci_get_platdata(struct device *dev,
}
cable = &platdata->vbus_extcon;
- cable->nb.notifier_call = ci_vbus_notifier;
+ cable->nb.notifier_call = ci_cable_notifier;
cable->edev = ext_vbus;
if (!IS_ERR(ext_vbus)) {
- ret = extcon_get_cable_state_(cable->edev, EXTCON_USB);
+ ret = extcon_get_state(cable->edev, EXTCON_USB);
if (ret)
- cable->state = true;
+ cable->connected = true;
else
- cable->state = false;
+ cable->connected = false;
}
cable = &platdata->id_extcon;
- cable->nb.notifier_call = ci_id_notifier;
+ cable->nb.notifier_call = ci_cable_notifier;
cable->edev = ext_id;
if (!IS_ERR(ext_id)) {
- ret = extcon_get_cable_state_(cable->edev, EXTCON_USB_HOST);
+ ret = extcon_get_state(cable->edev, EXTCON_USB_HOST);
if (ret)
- cable->state = false;
+ cable->connected = true;
else
- cable->state = true;
+ cable->connected = false;
}
return 0;
}
@@ -738,9 +717,9 @@ static int ci_extcon_register(struct ci_hdrc *ci)
id = &ci->platdata->id_extcon;
id->ci = ci;
- if (!IS_ERR(id->edev)) {
- ret = extcon_register_notifier(id->edev, EXTCON_USB_HOST,
- &id->nb);
+ if (!IS_ERR_OR_NULL(id->edev)) {
+ ret = devm_extcon_register_notifier(ci->dev, id->edev,
+ EXTCON_USB_HOST, &id->nb);
if (ret < 0) {
dev_err(ci->dev, "register ID failed\n");
return ret;
@@ -749,12 +728,10 @@ static int ci_extcon_register(struct ci_hdrc *ci)
vbus = &ci->platdata->vbus_extcon;
vbus->ci = ci;
- if (!IS_ERR(vbus->edev)) {
- ret = extcon_register_notifier(vbus->edev, EXTCON_USB,
- &vbus->nb);
+ if (!IS_ERR_OR_NULL(vbus->edev)) {
+ ret = devm_extcon_register_notifier(ci->dev, vbus->edev,
+ EXTCON_USB, &vbus->nb);
if (ret < 0) {
- extcon_unregister_notifier(id->edev, EXTCON_USB_HOST,
- &id->nb);
dev_err(ci->dev, "register VBUS failed\n");
return ret;
}
@@ -763,20 +740,6 @@ static int ci_extcon_register(struct ci_hdrc *ci)
return 0;
}
-static void ci_extcon_unregister(struct ci_hdrc *ci)
-{
- struct ci_hdrc_cable *cable;
-
- cable = &ci->platdata->id_extcon;
- if (!IS_ERR(cable->edev))
- extcon_unregister_notifier(cable->edev, EXTCON_USB_HOST,
- &cable->nb);
-
- cable = &ci->platdata->vbus_extcon;
- if (!IS_ERR(cable->edev))
- extcon_unregister_notifier(cable->edev, EXTCON_USB, &cable->nb);
-}
-
static DEFINE_IDA(ci_ida);
struct platform_device *ci_hdrc_add_device(struct device *dev,
@@ -801,9 +764,6 @@ struct platform_device *ci_hdrc_add_device(struct device *dev,
}
pdev->dev.parent = dev;
- pdev->dev.dma_mask = dev->dma_mask;
- pdev->dev.dma_parms = dev->dma_parms;
- dma_set_coherent_mask(&pdev->dev, dev->coherent_dma_mask);
ret = platform_device_add_resources(pdev, res, nres);
if (ret)
@@ -835,12 +795,39 @@ void ci_hdrc_remove_device(struct platform_device *pdev)
}
EXPORT_SYMBOL_GPL(ci_hdrc_remove_device);
+/**
+ * ci_hdrc_query_available_role: get runtime available operation mode
+ *
+ * The glue layer can get current operation mode (host/peripheral/otg)
+ * This function should be called after ci core device has created.
+ *
+ * @pdev: the platform device of ci core.
+ *
+ * Return USB_DR_MODE_XXX.
+ */
+enum usb_dr_mode ci_hdrc_query_available_role(struct platform_device *pdev)
+{
+ struct ci_hdrc *ci = platform_get_drvdata(pdev);
+
+ if (!ci)
+ return USB_DR_MODE_UNKNOWN;
+ if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET])
+ return USB_DR_MODE_OTG;
+ else if (ci->roles[CI_ROLE_HOST])
+ return USB_DR_MODE_HOST;
+ else if (ci->roles[CI_ROLE_GADGET])
+ return USB_DR_MODE_PERIPHERAL;
+ else
+ return USB_DR_MODE_UNKNOWN;
+}
+EXPORT_SYMBOL_GPL(ci_hdrc_query_available_role);
+
static inline void ci_role_destroy(struct ci_hdrc *ci)
{
- ci_hdrc_gadget_destroy(ci);
- ci_hdrc_host_destroy(ci);
if (ci->is_otg && ci->roles[CI_ROLE_GADGET])
ci_hdrc_otg_destroy(ci);
+ ci_hdrc_gadget_destroy(ci);
+ ci_hdrc_host_destroy(ci);
}
static void ci_get_otg_capable(struct ci_hdrc *ci)
@@ -859,6 +846,104 @@ static void ci_get_otg_capable(struct ci_hdrc *ci)
}
}
+static enum ci_role ci_get_role(struct ci_hdrc *ci)
+{
+ if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
+ if (ci->is_otg) {
+ hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);
+ return ci_otg_role(ci);
+ } else {
+ /*
+ * If the controller is not OTG capable, but support
+ * role switch, the defalt role is gadget, and the
+ * user can switch it through debugfs.
+ */
+ return CI_ROLE_GADGET;
+ }
+ } else {
+ return ci->roles[CI_ROLE_HOST]
+ ? CI_ROLE_HOST
+ : CI_ROLE_GADGET;
+ }
+}
+
+static void ci_start_new_role(struct ci_hdrc *ci)
+{
+ enum ci_role role = ci_get_role(ci);
+
+ if (ci->role != role) {
+ ci_handle_id_switch(ci);
+ } else if (role == CI_ROLE_GADGET) {
+ if (ci->vbus_active)
+ usb_gadget_vbus_disconnect(&ci->gadget);
+ ci_handle_vbus_connected(ci);
+ }
+}
+
+static void ci_power_lost_work(struct work_struct *work)
+{
+ struct ci_hdrc *ci = container_of(work, struct ci_hdrc,
+ power_lost_work);
+
+ pm_runtime_get_sync(ci->dev);
+ if (!ci_otg_is_fsm_mode(ci))
+ ci_start_new_role(ci);
+ else
+ ci_hdrc_otg_fsm_restart(ci);
+ pm_runtime_put_sync(ci->dev);
+ enable_irq(ci->irq);
+}
+
+static ssize_t ci_role_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci_hdrc *ci = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", ci_role(ci)->name);
+}
+
+static ssize_t ci_role_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t n)
+{
+ struct ci_hdrc *ci = dev_get_drvdata(dev);
+ enum ci_role role;
+ int ret;
+
+ if (!(ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET])) {
+ dev_warn(dev, "Current configuration is not dual-role, quit\n");
+ return -EPERM;
+ }
+
+ for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
+ if (!strncmp(buf, ci->roles[role]->name,
+ strlen(ci->roles[role]->name)))
+ break;
+
+ if (role == CI_ROLE_END || role == ci->role)
+ return -EINVAL;
+
+ pm_runtime_get_sync(dev);
+ disable_irq(ci->irq);
+ ci_role_stop(ci);
+ ret = ci_role_start(ci, role);
+ if (!ret && ci->role == CI_ROLE_GADGET)
+ ci_handle_vbus_change(ci);
+ enable_irq(ci->irq);
+ pm_runtime_put_sync(dev);
+
+ return (ret == 0) ? n : ret;
+}
+static DEVICE_ATTR(role, 0644, ci_role_show, ci_role_store);
+
+static struct attribute *ci_attrs[] = {
+ &dev_attr_role.attr,
+ NULL,
+};
+
+static struct attribute_group ci_attr_group = {
+ .attrs = ci_attrs,
+};
+
static int ci_hdrc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -971,30 +1056,12 @@ static int ci_hdrc_probe(struct platform_device *pdev)
}
}
- if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
- if (ci->is_otg) {
- ci->role = ci_otg_role(ci);
- /* Enable ID change irq */
- hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);
- } else {
- /*
- * If the controller is not OTG capable, but support
- * role switch, the defalt role is gadget, and the
- * user can switch it through debugfs.
- */
- ci->role = CI_ROLE_GADGET;
- }
- } else {
- ci->role = ci->roles[CI_ROLE_HOST]
- ? CI_ROLE_HOST
- : CI_ROLE_GADGET;
- }
+ ci->role = ci_get_role(ci);
+ /* only update vbus status for peripheral */
+ if (ci->role == CI_ROLE_GADGET)
+ ci_handle_vbus_connected(ci);
if (!ci_otg_is_fsm_mode(ci)) {
- /* only update vbus status for peripheral */
- if (ci->role == CI_ROLE_GADGET)
- ci_handle_vbus_change(ci);
-
ret = ci_role_start(ci, ci->role);
if (ret) {
dev_err(dev, "can't start %s role\n",
@@ -1026,11 +1093,22 @@ static int ci_hdrc_probe(struct platform_device *pdev)
device_set_wakeup_capable(&pdev->dev, true);
+ /* Init workqueue for controller power lost handling */
+ INIT_WORK(&ci->power_lost_work, ci_power_lost_work);
+ mutex_init(&ci->mutex);
+
ret = dbg_create_files(ci);
- if (!ret)
- return 0;
+ if (ret)
+ goto stop;
+
+ ret = sysfs_create_group(&dev->kobj, &ci_attr_group);
+ if (ret)
+ goto remove_debug;
- ci_extcon_unregister(ci);
+ return 0;
+
+remove_debug:
+ dbg_remove_files(ci);
stop:
if (ci->is_otg && ci->roles[CI_ROLE_GADGET])
ci_hdrc_otg_destroy(ci);
@@ -1055,7 +1133,7 @@ static int ci_hdrc_remove(struct platform_device *pdev)
}
dbg_remove_files(ci);
- ci_extcon_unregister(ci);
+ sysfs_remove_group(&ci->dev->kobj, &ci_attr_group);
ci_role_destroy(ci);
ci_hdrc_enter_lpm(ci, true);
ci_usb_phy_exit(ci);
@@ -1081,13 +1159,10 @@ static void ci_otg_fsm_wakeup_by_srp(struct ci_hdrc *ci)
{
if ((ci->fsm.otg->state == OTG_STATE_A_IDLE) &&
(ci->fsm.a_bus_drop == 1) && (ci->fsm.a_bus_req == 0)) {
- if (!hw_read_otgsc(ci, OTGSC_ID)) {
- ci->fsm.a_srp_det = 1;
- ci->fsm.a_bus_drop = 0;
- } else {
+ if (!hw_read_otgsc(ci, OTGSC_ID))
+ otg_add_timer(&ci->fsm, A_DP_END);
+ else
ci->fsm.id = 1;
- }
- ci_otg_queue_work(ci);
}
}
@@ -1103,16 +1178,37 @@ static void ci_controller_suspend(struct ci_hdrc *ci)
enable_irq(ci->irq);
}
+/*
+ * Handle the wakeup interrupt triggered by extcon connector
+ * We need to call ci_irq again for extcon since the first
+ * interrupt (wakeup int) only let the controller be out of
+ * low power mode, but not handle any interrupts.
+ */
+static void ci_extcon_wakeup_int(struct ci_hdrc *ci)
+{
+ struct ci_hdrc_cable *cable_id, *cable_vbus;
+ u32 otgsc = hw_read_otgsc(ci, ~0);
+
+ cable_id = &ci->platdata->id_extcon;
+ cable_vbus = &ci->platdata->vbus_extcon;
+
+ if (!IS_ERR(cable_id->edev) && ci->is_otg &&
+ (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS))
+ ci_irq(ci->irq, ci);
+
+ if (!IS_ERR(cable_vbus->edev) && ci->is_otg &&
+ (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS))
+ ci_irq(ci->irq, ci);
+}
+
static int ci_controller_resume(struct device *dev)
{
struct ci_hdrc *ci = dev_get_drvdata(dev);
dev_dbg(dev, "at %s\n", __func__);
- if (!ci->in_lpm) {
- WARN_ON(1);
+ if (!ci->in_lpm)
return 0;
- }
ci_hdrc_enter_lpm(ci, false);
if (ci->usb_phy) {
@@ -1129,6 +1225,7 @@ static int ci_controller_resume(struct device *dev)
enable_irq(ci->irq);
if (ci_otg_is_fsm_mode(ci))
ci_otg_fsm_wakeup_by_srp(ci);
+ ci_extcon_wakeup_int(ci);
}
return 0;
@@ -1155,6 +1252,10 @@ static int ci_suspend(struct device *dev)
return 0;
}
+ /* Extra routine per role before system suspend */
+ if (ci->role != CI_ROLE_END && ci_role(ci)->suspend)
+ ci_role(ci)->suspend(ci);
+
if (device_may_wakeup(dev)) {
if (ci_otg_is_fsm_mode(ci))
ci_otg_fsm_suspend_for_srp(ci);
@@ -1171,8 +1272,18 @@ static int ci_suspend(struct device *dev)
static int ci_resume(struct device *dev)
{
struct ci_hdrc *ci = dev_get_drvdata(dev);
+ bool power_lost = false;
+ u32 sample_reg_val;
int ret;
+ /* Check if controller resume from power lost */
+ sample_reg_val = hw_read(ci, OP_ENDPTLISTADDR, ~0);
+ if (sample_reg_val == 0)
+ power_lost = true;
+ else if (sample_reg_val == 0xFFFFFFFF)
+ /* Restore value 0 if it was set for power lost check */
+ hw_write(ci, OP_ENDPTLISTADDR, ~0, 0);
+
if (device_may_wakeup(dev))
disable_irq_wake(ci->irq);
@@ -1180,6 +1291,21 @@ static int ci_resume(struct device *dev)
if (ret)
return ret;
+ if (power_lost) {
+ /* shutdown and re-init for phy */
+ ci_usb_phy_exit(ci);
+ ci_usb_phy_init(ci);
+ }
+
+ /* Extra routine per role after system resume */
+ if (ci->role != CI_ROLE_END && ci_role(ci)->resume)
+ ci_role(ci)->resume(ci, power_lost);
+
+ if (power_lost) {
+ disable_irq_nosync(ci->irq);
+ schedule_work(&ci->power_lost_work);
+ }
+
if (ci->supports_runtime_pm) {
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
@@ -1196,10 +1322,8 @@ static int ci_runtime_suspend(struct device *dev)
dev_dbg(dev, "at %s\n", __func__);
- if (ci->in_lpm) {
- WARN_ON(1);
+ if (ci->in_lpm)
return 0;
- }
if (ci_otg_is_fsm_mode(ci))
ci_otg_fsm_suspend_for_srp(ci);
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index 111b0e0b8698..4b687bb8db0c 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -25,6 +25,7 @@
#include <linux/usb/hcd.h>
#include <linux/usb/chipidea.h>
#include <linux/regulator/consumer.h>
+#include <linux/imx_gpc.h>
#include "../host/ehci.h"
@@ -34,11 +35,29 @@
static struct hc_driver __read_mostly ci_ehci_hc_driver;
static int (*orig_bus_suspend)(struct usb_hcd *hcd);
+static int (*orig_bus_resume)(struct usb_hcd *hcd);
+static int (*orig_hub_control)(struct usb_hcd *hcd,
+ u16 typeReq, u16 wValue, u16 wIndex,
+ char *buf, u16 wLength);
struct ehci_ci_priv {
struct regulator *reg_vbus;
};
+/* This function is used to override WKCN, WKDN, and WKOC */
+static void ci_ehci_override_wakeup_flag(struct ehci_hcd *ehci,
+ u32 __iomem *reg, u32 flags, bool set)
+{
+ u32 val = ehci_readl(ehci, reg);
+
+ if (set)
+ val |= flags;
+ else
+ val &= ~flags;
+
+ ehci_writel(ehci, val, reg);
+}
+
static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
@@ -101,9 +120,164 @@ static const struct ehci_driver_overrides ehci_ci_overrides = {
.reset = ehci_ci_reset,
};
+static int ci_imx_ehci_bus_resume(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int port;
+
+ int ret = orig_bus_resume(hcd);
+
+ if (ret)
+ return ret;
+
+ port = HCS_N_PORTS(ehci->hcs_params);
+ while (port--) {
+ u32 __iomem *reg = &ehci->regs->port_status[port];
+ u32 portsc = ehci_readl(ehci, reg);
+ /*
+ * Notify PHY after resume signal has finished, it is
+ * for global suspend case.
+ */
+ if (hcd->usb_phy
+ && test_bit(port, &ehci->bus_suspended)
+ && (portsc & PORT_CONNECT)
+ && (ehci_port_speed(ehci, portsc) ==
+ USB_PORT_STAT_HIGH_SPEED))
+ /* notify the USB PHY */
+ usb_phy_notify_resume(hcd->usb_phy, USB_SPEED_HIGH);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_USB_OTG
+
+static int ci_start_port_reset(struct usb_hcd *hcd, unsigned port)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ u32 __iomem *reg;
+ u32 status;
+
+ if (!port)
+ return -EINVAL;
+ port--;
+ /* start port reset before HNP protocol time out */
+ reg = &ehci->regs->port_status[port];
+ status = ehci_readl(ehci, reg);
+ if (!(status & PORT_CONNECT))
+ return -ENODEV;
+
+ /* khubd will finish the reset later */
+ if (ehci_is_TDI(ehci))
+ ehci_writel(ehci, status | (PORT_RESET & ~PORT_RWC_BITS), reg);
+ else
+ ehci_writel(ehci, status | PORT_RESET, reg);
+
+ return 0;
+}
+
+#else
+
+#define ci_start_port_reset NULL
+
+#endif
+
+/* The below code is based on tegra ehci driver */
+static int ci_imx_ehci_hub_control(
+ struct usb_hcd *hcd,
+ u16 typeReq,
+ u16 wValue,
+ u16 wIndex,
+ char *buf,
+ u16 wLength
+)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ u32 __iomem *status_reg;
+ u32 temp;
+ unsigned long flags;
+ int retval = 0;
+ struct device *dev = hcd->self.controller;
+ struct ci_hdrc *ci = dev_get_drvdata(dev);
+
+ status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1];
+
+ spin_lock_irqsave(&ehci->lock, flags);
+
+ if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
+ temp = ehci_readl(ehci, status_reg);
+ if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) {
+ retval = -EPIPE;
+ goto done;
+ }
+
+ temp &= ~(PORT_RWC_BITS | PORT_WKCONN_E);
+ temp |= PORT_WKDISC_E | PORT_WKOC_E;
+ ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
+
+ /*
+ * If a transaction is in progress, there may be a delay in
+ * suspending the port. Poll until the port is suspended.
+ */
+ if (ehci_handshake(ehci, status_reg, PORT_SUSPEND,
+ PORT_SUSPEND, 5000))
+ ehci_err(ehci, "timeout waiting for SUSPEND\n");
+
+ if (ci->platdata->flags & CI_HDRC_IMX_IS_HSIC) {
+ if (ci->platdata->notify_event)
+ ci->platdata->notify_event
+ (ci, CI_HDRC_IMX_HSIC_SUSPEND_EVENT);
+ ci_ehci_override_wakeup_flag(ehci, status_reg,
+ PORT_WKDISC_E | PORT_WKCONN_E, false);
+ }
+
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ if (ehci_port_speed(ehci, temp) ==
+ USB_PORT_STAT_HIGH_SPEED && hcd->usb_phy) {
+ /* notify the USB PHY */
+ usb_phy_notify_suspend(hcd->usb_phy, USB_SPEED_HIGH);
+ }
+ spin_lock_irqsave(&ehci->lock, flags);
+
+ set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports);
+ goto done;
+ }
+
+ /*
+ * After resume has finished, it needs do some post resume
+ * operation for some SoCs.
+ */
+ else if (typeReq == ClearPortFeature &&
+ wValue == USB_PORT_FEAT_C_SUSPEND) {
+
+ /* Make sure the resume has finished, it should be finished */
+ if (ehci_handshake(ehci, status_reg, PORT_RESUME, 0, 25000))
+ ehci_err(ehci, "timeout waiting for resume\n");
+
+ temp = ehci_readl(ehci, status_reg);
+
+ if (ehci_port_speed(ehci, temp) ==
+ USB_PORT_STAT_HIGH_SPEED && hcd->usb_phy) {
+ /* notify the USB PHY */
+ usb_phy_notify_resume(hcd->usb_phy, USB_SPEED_HIGH);
+ }
+ }
+
+ spin_unlock_irqrestore(&ehci->lock, flags);
+
+ /* Handle the hub control events here */
+ return orig_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
+done:
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ return retval;
+}
+
static irqreturn_t host_irq(struct ci_hdrc *ci)
{
- return usb_hcd_irq(ci->irq, ci->hcd);
+ if (ci->hcd)
+ return usb_hcd_irq(ci->irq, ci->hcd);
+ else
+ return IRQ_NONE;
}
static int host_start(struct ci_hdrc *ci)
@@ -116,7 +290,8 @@ static int host_start(struct ci_hdrc *ci)
if (usb_disabled())
return -ENODEV;
- hcd = usb_create_hcd(&ci_ehci_hc_driver, ci->dev, dev_name(ci->dev));
+ hcd = __usb_create_hcd(&ci_ehci_hc_driver, ci->dev->parent,
+ ci->dev, dev_name(ci->dev), NULL);
if (!hcd)
return -ENOMEM;
@@ -156,6 +331,13 @@ static int host_start(struct ci_hdrc *ci)
}
}
+ if (ci_otg_is_fsm_mode(ci)) {
+ if (ci->fsm.id && ci->fsm.otg->state <= OTG_STATE_B_HOST)
+ hcd->self.is_b_host = 1;
+ else
+ hcd->self.is_b_host = 0;
+ }
+
ret = usb_add_hcd(hcd, 0, 0);
if (ret) {
goto disable_reg;
@@ -165,11 +347,17 @@ static int host_start(struct ci_hdrc *ci)
ci->hcd = hcd;
if (ci_otg_is_fsm_mode(ci)) {
+ hcd->self.otg_fsm = &ci->fsm;
otg->host = &hcd->self;
hcd->self.otg_port = 1;
}
}
+ if (ci->platdata->notify_event &&
+ (ci->platdata->flags & CI_HDRC_IMX_IS_HSIC))
+ ci->platdata->notify_event
+ (ci, CI_HDRC_IMX_HSIC_ACTIVE_EVENT);
+
return ret;
disable_reg:
@@ -194,16 +382,123 @@ static void host_stop(struct ci_hdrc *ci)
if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci) &&
(ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON))
regulator_disable(ci->platdata->reg_vbus);
+ if (hcd->self.is_b_host)
+ hcd->self.is_b_host = 0;
}
ci->hcd = NULL;
ci->otg.host = NULL;
}
+bool ci_hdrc_host_has_device(struct ci_hdrc *ci)
+{
+ struct usb_device *roothub;
+ int i;
+
+ if ((ci->role == CI_ROLE_HOST) && ci->hcd) {
+ roothub = ci->hcd->self.root_hub;
+ for (i = 0; i < roothub->maxchild; ++i) {
+ if (usb_hub_find_child(roothub, (i + 1)))
+ return true;
+ }
+ }
+ return false;
+}
+
+static void ci_hdrc_host_save_for_power_lost(struct ci_hdrc *ci)
+{
+ struct ehci_hcd *ehci;
+
+ if (!ci->hcd)
+ return;
+
+ ehci = hcd_to_ehci(ci->hcd);
+ /* save EHCI registers */
+ ci->pm_usbmode = ehci_readl(ehci, &ehci->regs->usbmode);
+ ci->pm_command = ehci_readl(ehci, &ehci->regs->command);
+ ci->pm_command &= ~CMD_RUN;
+ ci->pm_status = ehci_readl(ehci, &ehci->regs->status);
+ ci->pm_intr_enable = ehci_readl(ehci, &ehci->regs->intr_enable);
+ ci->pm_frame_index = ehci_readl(ehci, &ehci->regs->frame_index);
+ ci->pm_segment = ehci_readl(ehci, &ehci->regs->segment);
+ ci->pm_frame_list = ehci_readl(ehci, &ehci->regs->frame_list);
+ ci->pm_async_next = ehci_readl(ehci, &ehci->regs->async_next);
+ ci->pm_configured_flag =
+ ehci_readl(ehci, &ehci->regs->configured_flag);
+ ci->pm_portsc = ehci_readl(ehci, &ehci->regs->port_status[0]);
+}
+
+static void ci_hdrc_host_restore_from_power_lost(struct ci_hdrc *ci)
+{
+ struct ehci_hcd *ehci;
+ unsigned long flags;
+ u32 tmp;
+ int step_ms;
+ /*
+ * If the vbus is off during system suspend, most of devices will pull
+ * DP up within 200ms when they see vbus, set 1000ms for safety.
+ */
+ int timeout_ms = 1000;
+
+ if (!ci->hcd)
+ return;
+
+ hw_controller_reset(ci);
+
+ ehci = hcd_to_ehci(ci->hcd);
+ spin_lock_irqsave(&ehci->lock, flags);
+ /* Restore EHCI registers */
+ ehci_writel(ehci, ci->pm_usbmode, &ehci->regs->usbmode);
+ ehci_writel(ehci, ci->pm_portsc, &ehci->regs->port_status[0]);
+ ehci_writel(ehci, ci->pm_command, &ehci->regs->command);
+ ehci_writel(ehci, ci->pm_intr_enable, &ehci->regs->intr_enable);
+ ehci_writel(ehci, ci->pm_frame_index, &ehci->regs->frame_index);
+ ehci_writel(ehci, ci->pm_segment, &ehci->regs->segment);
+ ehci_writel(ehci, ci->pm_frame_list, &ehci->regs->frame_list);
+ ehci_writel(ehci, ci->pm_async_next, &ehci->regs->async_next);
+ ehci_writel(ehci, ci->pm_configured_flag,
+ &ehci->regs->configured_flag);
+ /* Restore the PHY's connect notifier setting */
+ if (ci->pm_portsc & PORTSC_HSP)
+ usb_phy_notify_connect(ci->usb_phy, USB_SPEED_HIGH);
+
+ tmp = ehci_readl(ehci, &ehci->regs->command);
+ tmp |= CMD_RUN;
+ ehci_writel(ehci, tmp, &ehci->regs->command);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+
+ if (!(ci->pm_portsc & PORTSC_CCS))
+ return;
+
+ for (step_ms = 0; step_ms < timeout_ms; step_ms += 25) {
+ if (ehci_readl(ehci, &ehci->regs->port_status[0]) & PORTSC_CCS)
+ break;
+ msleep(25);
+ }
+}
+
+static void ci_hdrc_host_suspend(struct ci_hdrc *ci)
+{
+ if (ci_hdrc_host_has_device(ci))
+ imx_gpc_mf_request_on(ci->irq, 1);
+
+ ci_hdrc_host_save_for_power_lost(ci);
+}
+
+static void ci_hdrc_host_resume(struct ci_hdrc *ci, bool power_lost)
+{
+ imx_gpc_mf_request_on(ci->irq, 0);
+
+ if (power_lost)
+ ci_hdrc_host_restore_from_power_lost(ci);
+}
void ci_hdrc_host_destroy(struct ci_hdrc *ci)
{
- if (ci->role == CI_ROLE_HOST && ci->hcd)
+ if (ci->role == CI_ROLE_HOST && ci->hcd) {
+ disable_irq_nosync(ci->irq);
host_stop(ci);
+ enable_irq(ci->irq);
+ }
}
static int ci_ehci_bus_suspend(struct usb_hcd *hcd)
@@ -211,6 +506,8 @@ static int ci_ehci_bus_suspend(struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int port;
u32 tmp;
+ struct device *dev = hcd->self.controller;
+ struct ci_hdrc *ci = dev_get_drvdata(dev);
int ret = orig_bus_suspend(hcd);
@@ -240,6 +537,30 @@ static int ci_ehci_bus_suspend(struct usb_hcd *hcd)
* It needs a short delay between set RS bit and PHCD.
*/
usleep_range(150, 200);
+
+ /*
+ * If a transaction is in progress, there may be
+ * a delay in suspending the port. Poll until the
+ * port is suspended.
+ */
+ if (test_bit(port, &ehci->bus_suspended) &&
+ ehci_handshake(ehci, reg, PORT_SUSPEND,
+ PORT_SUSPEND, 5000))
+ ehci_err(ehci, "timeout waiting for SUSPEND\n");
+
+ if (ci->platdata->flags & CI_HDRC_IMX_IS_HSIC)
+ ci_ehci_override_wakeup_flag(ehci, reg,
+ PORT_WKDISC_E | PORT_WKCONN_E, false);
+
+ if (hcd->usb_phy && test_bit(port, &ehci->bus_suspended)
+ && (ehci_port_speed(ehci, portsc) ==
+ USB_PORT_STAT_HIGH_SPEED))
+ /*
+ * notify the USB PHY, it is for global
+ * suspend case.
+ */
+ usb_phy_notify_suspend(hcd->usb_phy,
+ USB_SPEED_HIGH);
break;
}
}
@@ -261,6 +582,8 @@ int ci_hdrc_host_init(struct ci_hdrc *ci)
rdrv->start = host_start;
rdrv->stop = host_stop;
rdrv->irq = host_irq;
+ rdrv->suspend = ci_hdrc_host_suspend;
+ rdrv->resume = ci_hdrc_host_resume;
rdrv->name = "host";
ci->roles[CI_ROLE_HOST] = rdrv;
@@ -271,5 +594,11 @@ void ci_hdrc_host_driver_init(void)
{
ehci_init_driver(&ci_ehci_hc_driver, &ehci_ci_overrides);
orig_bus_suspend = ci_ehci_hc_driver.bus_suspend;
+ orig_bus_resume = ci_ehci_hc_driver.bus_resume;
+ orig_hub_control = ci_ehci_hc_driver.hub_control;
+
ci_ehci_hc_driver.bus_suspend = ci_ehci_bus_suspend;
+ ci_ehci_hc_driver.bus_resume = ci_imx_ehci_bus_resume;
+ ci_ehci_hc_driver.hub_control = ci_imx_ehci_hub_control;
+ ci_ehci_hc_driver.start_port_reset = ci_start_port_reset;
}
diff --git a/drivers/usb/chipidea/host.h b/drivers/usb/chipidea/host.h
index 0f12f131bdd3..4dfb59a05a1a 100644
--- a/drivers/usb/chipidea/host.h
+++ b/drivers/usb/chipidea/host.h
@@ -6,6 +6,7 @@
int ci_hdrc_host_init(struct ci_hdrc *ci);
void ci_hdrc_host_destroy(struct ci_hdrc *ci);
void ci_hdrc_host_driver_init(void);
+bool ci_hdrc_host_has_device(struct ci_hdrc *ci);
#else
@@ -19,11 +20,16 @@ static inline void ci_hdrc_host_destroy(struct ci_hdrc *ci)
}
-static void ci_hdrc_host_driver_init(void)
+static inline void ci_hdrc_host_driver_init(void)
{
}
+static inline bool ci_hdrc_host_has_device(struct ci_hdrc *ci)
+{
+ return false;
+}
+
#endif
#endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
index f36a1ac3bfbd..9a17e04f4bfc 100644
--- a/drivers/usb/chipidea/otg.c
+++ b/drivers/usb/chipidea/otg.c
@@ -1,7 +1,8 @@
/*
* otg.c - ChipIdea USB IP core OTG driver
*
- * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ * Copyright (C) 2013-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
*
* Author: Peter Chen
*
@@ -23,6 +24,7 @@
#include "bits.h"
#include "otg.h"
#include "otg_fsm.h"
+#include "host.h"
/**
* hw_read_otgsc returns otgsc register bits value.
@@ -44,7 +46,7 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask)
else
val &= ~OTGSC_BSVIS;
- if (cable->state)
+ if (cable->connected)
val |= OTGSC_BSV;
else
val &= ~OTGSC_BSV;
@@ -62,10 +64,10 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask)
else
val &= ~OTGSC_IDIS;
- if (cable->state)
- val |= OTGSC_ID;
+ if (cable->connected)
+ val &= ~OTGSC_ID; /* host */
else
- val &= ~OTGSC_ID;
+ val |= OTGSC_ID; /* device */
if (cable->enabled)
val |= OTGSC_IDIE;
@@ -129,6 +131,46 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci)
return role;
}
+/*
+ * Handling vbus glitch
+ * We only need to consider glitch for without usb connection,
+ * With usb connection, we consider it as real disconnection.
+ *
+ * If the vbus can't be kept above B session valid for timeout value,
+ * we think it is a vbus glitch, otherwise it's a valid vbus.
+ */
+#define CI_VBUS_CONNECT_TIMEOUT_MS 300
+static int ci_is_vbus_glitch(struct ci_hdrc *ci)
+{
+ int i;
+
+ for (i = 0; i < CI_VBUS_CONNECT_TIMEOUT_MS/20; i++) {
+ if (hw_read_otgsc(ci, OTGSC_AVV)) {
+ return 0;
+ } else if (!hw_read_otgsc(ci, OTGSC_BSV)) {
+ dev_warn(ci->dev, "there is a vbus glitch\n");
+ return 1;
+ }
+ msleep(20);
+ }
+
+ return 0;
+}
+
+void ci_handle_vbus_connected(struct ci_hdrc *ci)
+{
+ /*
+ * TODO: if the platform does not supply 5v to udc, or use other way
+ * to supply 5v, it needs to use other conditions to call
+ * usb_gadget_vbus_connect.
+ */
+ if (!ci->is_otg)
+ return;
+
+ if (hw_read_otgsc(ci, OTGSC_BSV) && !ci_is_vbus_glitch(ci))
+ usb_gadget_vbus_connect(&ci->gadget);
+}
+
void ci_handle_vbus_change(struct ci_hdrc *ci)
{
if (!ci->is_otg)
@@ -165,10 +207,12 @@ static int hw_wait_vbus_lower_bsv(struct ci_hdrc *ci)
return 0;
}
-static void ci_handle_id_switch(struct ci_hdrc *ci)
+void ci_handle_id_switch(struct ci_hdrc *ci)
{
- enum ci_role role = ci_otg_role(ci);
+ enum ci_role role;
+ mutex_lock(&ci->mutex);
+ role = ci_otg_role(ci);
if (role != ci->role) {
dev_dbg(ci->dev, "switching from %s to %s\n",
ci_role(ci)->name, ci->roles[role]->name);
@@ -191,7 +235,34 @@ static void ci_handle_id_switch(struct ci_hdrc *ci)
if (role == CI_ROLE_GADGET)
ci_handle_vbus_change(ci);
}
+ mutex_unlock(&ci->mutex);
+}
+
+static void ci_handle_vbus_glitch(struct ci_hdrc *ci)
+{
+ bool valid_vbus_change = false;
+
+ if (hw_read_otgsc(ci, OTGSC_BSV)) {
+ if (!ci_is_vbus_glitch(ci)) {
+ if (ci_otg_is_fsm_mode(ci)) {
+ ci->fsm.b_sess_vld = 1;
+ ci->fsm.b_ssend_srp = 0;
+ otg_del_timer(&ci->fsm, B_SSEND_SRP);
+ otg_del_timer(&ci->fsm, B_SRP_FAIL);
+ }
+ valid_vbus_change = true;
+ }
+ } else {
+ if (ci->vbus_active && !ci_otg_is_fsm_mode(ci))
+ valid_vbus_change = true;
+ }
+
+ if (valid_vbus_change) {
+ ci->b_sess_valid_event = true;
+ ci_otg_queue_work(ci);
+ }
}
+
/**
* ci_otg_work - perform otg (vbus/id) event handle
* @work: work struct
@@ -200,6 +271,15 @@ static void ci_otg_work(struct work_struct *work)
{
struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work);
+ if (ci->vbus_glitch_check_event) {
+ ci->vbus_glitch_check_event = false;
+ pm_runtime_get_sync(ci->dev);
+ ci_handle_vbus_glitch(ci);
+ pm_runtime_put_sync(ci->dev);
+ enable_irq(ci->irq);
+ return;
+ }
+
if (ci_otg_is_fsm_mode(ci) && !ci_otg_fsm_work(ci)) {
enable_irq(ci->irq);
return;
@@ -245,13 +325,14 @@ int ci_hdrc_otg_init(struct ci_hdrc *ci)
*/
void ci_hdrc_otg_destroy(struct ci_hdrc *ci)
{
+ /* Disable all OTG irq and clear status */
+ hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS,
+ OTGSC_INT_STATUS_BITS);
if (ci->wq) {
flush_workqueue(ci->wq);
destroy_workqueue(ci->wq);
+ ci->wq = NULL;
}
- /* Disable all OTG irq and clear status */
- hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS,
- OTGSC_INT_STATUS_BITS);
if (ci_otg_is_fsm_mode(ci))
ci_hdrc_otg_fsm_remove(ci);
}
diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h
index 9ecb598e48f0..95fa6c2b675a 100644
--- a/drivers/usb/chipidea/otg.h
+++ b/drivers/usb/chipidea/otg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2014 Freescale Semiconductor, Inc.
+ * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
*
* Author: Peter Chen
*
@@ -17,10 +17,17 @@ int ci_hdrc_otg_init(struct ci_hdrc *ci);
void ci_hdrc_otg_destroy(struct ci_hdrc *ci);
enum ci_role ci_otg_role(struct ci_hdrc *ci);
void ci_handle_vbus_change(struct ci_hdrc *ci);
+void ci_handle_id_switch(struct ci_hdrc *ci);
+void ci_handle_vbus_connected(struct ci_hdrc *ci);
static inline void ci_otg_queue_work(struct ci_hdrc *ci)
{
- disable_irq_nosync(ci->irq);
- queue_work(ci->wq, &ci->work);
+ if (ci->wq) {
+ disable_irq_nosync(ci->irq);
+ if (!queue_work(ci->wq, &ci->work))
+ enable_irq(ci->irq);
+ } else {
+ WARN_ON(!ci->wq);
+ }
}
#endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index de8e22ec3902..05ff5f155e96 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -1,7 +1,7 @@
/*
* otg_fsm.c - ChipIdea USB IP core OTG FSM driver
*
- * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
*
* Author: Jun Li
*
@@ -28,7 +28,10 @@
#include "ci.h"
#include "bits.h"
#include "otg.h"
+#include "udc.h"
#include "otg_fsm.h"
+#include "udc.h"
+#include "host.h"
/* Add for otg: interact with user space app */
static ssize_t
@@ -215,6 +218,11 @@ static unsigned otg_timer_ms[] = {
0,
TB_DATA_PLS,
TB_SSEND_SRP,
+ TA_DP_END,
+ TA_TST_MAINT,
+ TB_SRP_REQD,
+ TB_TST_SUSP,
+ 0,
};
/*
@@ -300,6 +308,7 @@ static int a_wait_vfall_tmout(struct ci_hdrc *ci)
static int a_wait_bcon_tmout(struct ci_hdrc *ci)
{
ci->fsm.a_wait_bcon_tmout = 1;
+ dev_warn(ci->dev, "Device No Response\n");
return 0;
}
@@ -312,6 +321,7 @@ static int a_aidl_bdis_tmout(struct ci_hdrc *ci)
static int b_ase0_brst_tmout(struct ci_hdrc *ci)
{
ci->fsm.b_ase0_brst_tmout = 1;
+ dev_warn(ci->dev, "Device No Response\n");
return 0;
}
@@ -336,6 +346,7 @@ static int b_se0_srp_tmout(struct ci_hdrc *ci)
static int b_srp_fail_tmout(struct ci_hdrc *ci)
{
ci->fsm.b_srp_done = 1;
+ dev_warn(ci->dev, "Device No Response\n");
return 1;
}
@@ -360,6 +371,57 @@ static int b_ssend_srp_tmout(struct ci_hdrc *ci)
return 1;
}
+static int a_dp_end_tmout(struct ci_hdrc *ci)
+{
+ ci->fsm.a_bus_drop = 0;
+ ci->fsm.a_srp_det = 1;
+ return 0;
+}
+
+static int a_tst_maint_tmout(struct ci_hdrc *ci)
+{
+ ci->fsm.tst_maint = 0;
+ if (ci->fsm.otg_vbus_off) {
+ ci->fsm.otg_vbus_off = 0;
+ dev_dbg(ci->dev,
+ "test device does not disconnect, end the session!\n");
+ }
+
+ /* End the session */
+ ci->fsm.a_bus_req = 0;
+ ci->fsm.a_bus_drop = 1;
+ return 0;
+}
+
+/*
+ * otg_srp_reqd feature
+ * After A(PET) turn off vbus, B(UUT) should start this timer to do SRP
+ * when the timer expires.
+ */
+static int b_srp_reqd_tmout(struct ci_hdrc *ci)
+{
+ ci->fsm.otg_srp_reqd = 0;
+ if (ci->fsm.otg->state == OTG_STATE_B_IDLE) {
+ ci->fsm.b_bus_req = 1;
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * otg_hnp_reqd feature
+ * After B(UUT) switch to host, B should hand host role back
+ * to A(PET) within TB_TST_SUSP after setting configuration.
+ */
+static int b_tst_susp_tmout(struct ci_hdrc *ci)
+{
+ if (ci->fsm.otg->state == OTG_STATE_B_HOST) {
+ ci->fsm.b_bus_req = 0;
+ return 0;
+ }
+ return 1;
+}
+
/*
* Keep this list in the same order as timers indexed
* by enum otg_fsm_timer in include/linux/usb/otg-fsm.h
@@ -377,6 +439,11 @@ static int (*otg_timer_handlers[])(struct ci_hdrc *) = {
NULL, /* A_WAIT_ENUM */
b_data_pls_tmout, /* B_DATA_PLS */
b_ssend_srp_tmout, /* B_SSEND_SRP */
+ a_dp_end_tmout, /* A_DP_END */
+ a_tst_maint_tmout, /* A_TST_MAINT */
+ b_srp_reqd_tmout, /* B_SRP_REQD */
+ b_tst_susp_tmout, /* B_TST_SUSP */
+ NULL, /* HNP_POLLING */
};
/*
@@ -463,6 +530,9 @@ static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on)
struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm);
if (on) {
+ ci->platdata->notify_event(ci,
+ CI_HDRC_IMX_TERM_SELECT_OVERRIDE_OFF);
+
/* Enable power power */
hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP,
PORTSC_PP);
@@ -486,6 +556,7 @@ static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on)
fsm->a_bus_drop = 1;
fsm->a_bus_req = 0;
+ fsm->b_conn = 0;
}
}
@@ -562,11 +633,16 @@ static int ci_otg_start_host(struct otg_fsm *fsm, int on)
static int ci_otg_start_gadget(struct otg_fsm *fsm, int on)
{
struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm);
+ unsigned long flags;
+ int gadget_ready = 0;
- if (on)
- usb_gadget_vbus_connect(&ci->gadget);
- else
- usb_gadget_vbus_disconnect(&ci->gadget);
+ spin_lock_irqsave(&ci->lock, flags);
+ ci->vbus_active = on;
+ if (ci->driver)
+ gadget_ready = 1;
+ spin_unlock_irqrestore(&ci->lock, flags);
+ if (gadget_ready)
+ ci_hdrc_gadget_connect(&ci->gadget, on);
return 0;
}
@@ -584,13 +660,26 @@ static struct otg_fsm_ops ci_otg_ops = {
int ci_otg_fsm_work(struct ci_hdrc *ci)
{
- /*
- * Don't do fsm transition for B device
- * when there is no gadget class driver
- */
- if (ci->fsm.id && !(ci->driver) &&
- ci->fsm.otg->state < OTG_STATE_A_IDLE)
- return 0;
+ if (ci->fsm.id && ci->fsm.otg->state < OTG_STATE_A_IDLE) {
+ unsigned long flags;
+
+ /* Charger detection */
+ spin_lock_irqsave(&ci->lock, flags);
+ if (ci->b_sess_valid_event) {
+ ci->b_sess_valid_event = false;
+ ci->vbus_active = ci->fsm.b_sess_vld;
+ spin_unlock_irqrestore(&ci->lock, flags);
+ ci_usb_charger_connect(ci, ci->fsm.b_sess_vld);
+ spin_lock_irqsave(&ci->lock, flags);
+ }
+ spin_unlock_irqrestore(&ci->lock, flags);
+ /*
+ * Don't do fsm transition for B device if gadget
+ * driver is not binded.
+ */
+ if (!ci->driver)
+ return 0;
+ }
pm_runtime_get_sync(ci->dev);
if (otg_statemachine(&ci->fsm)) {
@@ -612,10 +701,14 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
PORTSC_PP, 0);
hw_write_otgsc(ci, OTGSC_DPIS, OTGSC_DPIS);
hw_write_otgsc(ci, OTGSC_DPIE, OTGSC_DPIE);
+ /* FS termination override if needed */
+ ci->platdata->notify_event(ci,
+ CI_HDRC_IMX_TERM_SELECT_OVERRIDE_FS);
}
if (ci->id_event)
ci->id_event = false;
} else if (ci->fsm.otg->state == OTG_STATE_B_IDLE) {
+ ci->fsm.b_sess_vld = hw_read_otgsc(ci, OTGSC_BSV);
if (ci->fsm.b_sess_vld) {
ci->fsm.power_up = 0;
/*
@@ -624,7 +717,8 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
*/
ci_otg_queue_work(ci);
}
- } else if (ci->fsm.otg->state == OTG_STATE_A_HOST) {
+ } else if (ci->fsm.otg->state == OTG_STATE_A_HOST ||
+ ci->fsm.otg->state == OTG_STATE_A_WAIT_VFALL) {
pm_runtime_mark_last_busy(ci->dev);
pm_runtime_put_autosuspend(ci->dev);
return 0;
@@ -678,25 +772,16 @@ static void ci_otg_fsm_event(struct ci_hdrc *ci)
}
break;
case OTG_STATE_A_PERIPHERAL:
- if (intr_sts & USBi_SLI) {
- fsm->b_bus_suspend = 1;
+ if (intr_sts & USBi_SLI)
/*
* Init a timer to know how long this suspend
* will continue, if time out, indicates B no longer
* wants to be host role
*/
ci_otg_add_timer(ci, A_BIDL_ADIS);
- }
- if (intr_sts & USBi_URI)
+ if (intr_sts & (USBi_URI | USBi_PCI))
ci_otg_del_timer(ci, A_BIDL_ADIS);
-
- if (intr_sts & USBi_PCI) {
- if (fsm->b_bus_suspend == 1) {
- ci_otg_del_timer(ci, A_BIDL_ADIS);
- fsm->b_bus_suspend = 0;
- }
- }
break;
case OTG_STATE_A_SUSPEND:
if ((intr_sts & USBi_PCI) && !port_conn) {
@@ -713,6 +798,15 @@ static void ci_otg_fsm_event(struct ci_hdrc *ci)
case OTG_STATE_A_HOST:
if ((intr_sts & USBi_PCI) && !port_conn) {
fsm->b_conn = 0;
+ if (fsm->tst_maint) {
+ ci_otg_del_timer(ci, A_TST_MAINT);
+ if (fsm->otg_vbus_off) {
+ fsm->a_bus_req = 0;
+ fsm->a_bus_drop = 1;
+ fsm->otg_vbus_off = 0;
+ }
+ fsm->tst_maint = 0;
+ }
ci_otg_queue_work(ci);
}
break;
@@ -746,26 +840,36 @@ irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci)
if (otg_int_src) {
if (otg_int_src & OTGSC_DPIS) {
hw_write_otgsc(ci, OTGSC_DPIS, OTGSC_DPIS);
- fsm->a_srp_det = 1;
- fsm->a_bus_drop = 0;
+ ci->platdata->notify_event(ci,
+ CI_HDRC_IMX_TERM_SELECT_OVERRIDE_OFF);
+ ci_otg_add_timer(ci, A_DP_END);
} else if (otg_int_src & OTGSC_IDIS) {
hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS);
if (fsm->id == 0) {
fsm->a_bus_drop = 0;
fsm->a_bus_req = 1;
ci->id_event = true;
+ } else {
+ /*
+ * Disable term select override and data pulse
+ * for B device.
+ */
+ ci->platdata->notify_event(ci,
+ CI_HDRC_IMX_TERM_SELECT_OVERRIDE_OFF);
}
} else if (otg_int_src & OTGSC_BSVIS) {
hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS);
- if (otgsc & OTGSC_BSV) {
- fsm->b_sess_vld = 1;
- ci_otg_del_timer(ci, B_SSEND_SRP);
- ci_otg_del_timer(ci, B_SRP_FAIL);
- fsm->b_ssend_srp = 0;
- } else {
+ if (!(otgsc & OTGSC_BSV) && fsm->b_sess_vld) {
+ ci->b_sess_valid_event = true;
fsm->b_sess_vld = 0;
if (fsm->id)
ci_otg_add_timer(ci, B_SSEND_SRP);
+ if (fsm->b_bus_req)
+ fsm->b_bus_req = 0;
+ if (fsm->otg_srp_reqd)
+ ci_otg_add_timer(ci, B_SRP_REQD);
+ } else {
+ ci->vbus_glitch_check_event = true;
}
} else if (otg_int_src & OTGSC_AVVIS) {
hw_write_otgsc(ci, OTGSC_AVVIS, OTGSC_AVVIS);
@@ -802,6 +906,7 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
ci->otg.gadget = &ci->gadget;
ci->fsm.otg = &ci->otg;
ci->fsm.power_up = 1;
+ ci->fsm.hnp_polling = 1;
ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0;
ci->fsm.otg->state = OTG_STATE_UNDEFINED;
ci->fsm.ops = &ci_otg_ops;
@@ -844,5 +949,56 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci)
{
+ enum otg_fsm_timer i;
+
+ mutex_lock(&ci->fsm.lock);
+ ci->fsm.otg->state = OTG_STATE_UNDEFINED;
+ mutex_unlock(&ci->fsm.lock);
+
+ for (i = 0; i < NUM_OTG_FSM_TIMERS; i++)
+ otg_del_timer(&ci->fsm, i);
+
+ ci->enabled_otg_timer_bits = 0;
+
+ /* Turn off vbus if vbus is on */
+ if (ci->fsm.drv_vbus)
+ otg_drv_vbus(&ci->fsm, 0);
+
sysfs_remove_group(&ci->dev->kobj, &inputs_attr_group);
}
+
+/* Restart OTG fsm if resume from power lost */
+void ci_hdrc_otg_fsm_restart(struct ci_hdrc *ci)
+{
+ struct otg_fsm *fsm = &ci->fsm;
+ int id_status = fsm->id;
+
+ /* Update fsm if power lost in peripheral state */
+ if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) {
+ fsm->b_sess_vld = 0;
+ otg_statemachine(fsm);
+ }
+
+ hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);
+ hw_write_otgsc(ci, OTGSC_AVVIE, OTGSC_AVVIE);
+
+ /* Update fsm variables for restart */
+ fsm->id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0;
+ if (fsm->id) {
+ fsm->b_ssend_srp =
+ hw_read_otgsc(ci, OTGSC_BSV) ? 0 : 1;
+ fsm->b_sess_vld =
+ hw_read_otgsc(ci, OTGSC_BSV) ? 1 : 0;
+ } else if (fsm->id != id_status) {
+ /* ID changes to be 0 */
+ fsm->a_bus_drop = 0;
+ fsm->a_bus_req = 1;
+ ci->id_event = true;
+ }
+
+ if (ci_hdrc_host_has_device(ci) &&
+ !hw_read(ci, OP_PORTSC, PORTSC_CCS))
+ fsm->b_conn = 0;
+
+ ci_otg_fsm_work(ci);
+}
diff --git a/drivers/usb/chipidea/otg_fsm.h b/drivers/usb/chipidea/otg_fsm.h
index 6366fe398ba6..ff77d2e1bb64 100644
--- a/drivers/usb/chipidea/otg_fsm.h
+++ b/drivers/usb/chipidea/otg_fsm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
*
* Author: Jun Li
*
@@ -25,7 +25,7 @@
* ->DC Electrical Timing
*/
/* Wait for VBUS Fall */
-#define TA_WAIT_VFALL (1000) /* a_wait_vfall: section 7.1.7
+#define TA_WAIT_VFALL (500) /* a_wait_vfall: section 7.1.7
* a_wait_vfall_tmr: section: 7.4.5.2
*/
/* Wait for B-Connect */
@@ -38,9 +38,13 @@
* TA_AIDL_BDIS: section 5.5, Table 5-1
*/
/* B-Idle to A-Disconnect */
-#define TA_BIDL_ADIS (500) /* TA_BIDL_ADIS: section 5.2.1
- * 500ms is used for B switch to host
- * for safe
+#define TA_BIDL_ADIS (160) /* TA_BIDL_ADIS: section 5.2.1
+ * 155ms ~ 200 ms
+ */
+
+#define TA_DP_END (200)
+#define TA_TST_MAINT (9900) /* OTG test device session maintain
+ * timer, 9.9s~10.1s
*/
/*
@@ -63,6 +67,14 @@
#define TB_SSEND_SRP (1500) /* minimum 1.5 sec, section:5.1.2 */
#define TB_AIDL_BDIS (20) /* 4ms ~ 150ms, section 5.2.1 */
+#define TB_SRP_REQD (2000) /* For otg_srp_reqd to start data
+ * pulse after A(PET) turn off v-bus
+ */
+
+#define TB_TST_SUSP (20) /* B-dev hand host role back to A-dev
+ * via suspend bus after set config.
+ * max: 100ms
+ */
#if IS_ENABLED(CONFIG_USB_OTG_FSM)
@@ -71,6 +83,7 @@ int ci_otg_fsm_work(struct ci_hdrc *ci);
irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci);
void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci);
void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci);
+void ci_hdrc_otg_fsm_restart(struct ci_hdrc *ci);
#else
@@ -99,6 +112,11 @@ static inline void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci)
}
+static inline void ci_hdrc_otg_fsm_restart(struct ci_hdrc *ci)
+{
+
+}
+
#endif
#endif /* __DRIVERS_USB_CHIPIDEA_OTG_FSM_H */
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 6a15b7250e9c..cf24527d24eb 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -423,7 +423,8 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
hwreq->req.status = -EALREADY;
- ret = usb_gadget_map_request(&ci->gadget, &hwreq->req, hwep->dir);
+ ret = usb_gadget_map_request_by_dev(ci->dev->parent,
+ &hwreq->req, hwep->dir);
if (ret)
return ret;
@@ -603,7 +604,8 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
list_del_init(&node->td);
}
- usb_gadget_unmap_request(&hwep->ci->gadget, &hwreq->req, hwep->dir);
+ usb_gadget_unmap_request_by_dev(hwep->ci->dev->parent,
+ &hwreq->req, hwep->dir);
hwreq->req.actual += actual;
@@ -709,12 +711,6 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)
struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
unsigned long flags;
- spin_lock_irqsave(&ci->lock, flags);
- ci->gadget.speed = USB_SPEED_UNKNOWN;
- ci->remote_wakeup = 0;
- ci->suspended = 0;
- spin_unlock_irqrestore(&ci->lock, flags);
-
/* flush all endpoints */
gadget_for_each_ep(ep, gadget) {
usb_ep_fifo_flush(ep);
@@ -732,6 +728,12 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)
ci->status = NULL;
}
+ spin_lock_irqsave(&ci->lock, flags);
+ ci->gadget.speed = USB_SPEED_UNKNOWN;
+ ci->remote_wakeup = 0;
+ ci->suspended = 0;
+ spin_unlock_irqrestore(&ci->lock, flags);
+
return 0;
}
@@ -750,6 +752,11 @@ __acquires(ci->lock)
{
int retval;
+ if (ci_otg_is_fsm_mode(ci)) {
+ ci->fsm.otg_srp_reqd = 0;
+ ci->fsm.otg_hnp_reqd = 0;
+ }
+
spin_unlock(&ci->lock);
if (ci->gadget.speed != USB_SPEED_UNKNOWN)
usb_gadget_udc_reset(&ci->gadget, ci->driver);
@@ -873,7 +880,10 @@ __acquires(hwep->lock)
return -ENOMEM;
req->complete = isr_get_status_complete;
- req->length = 2;
+ if (setup->wIndex == OTG_STS_SELECTOR)
+ req->length = 1;
+ else
+ req->length = 2;
req->buf = kzalloc(req->length, gfp_flags);
if (req->buf == NULL) {
retval = -ENOMEM;
@@ -881,8 +891,16 @@ __acquires(hwep->lock)
}
if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
- *(u16 *)req->buf = (ci->remote_wakeup << 1) |
- ci->gadget.is_selfpowered;
+ if ((setup->wIndex == OTG_STS_SELECTOR) &&
+ ci_otg_is_fsm_mode(ci)) {
+ if (ci->gadget.host_request_flag)
+ *(u8 *)req->buf = HOST_REQUEST_FLAG;
+ else
+ *(u8 *)req->buf = 0;
+ } else {
+ *(u16 *)req->buf = (ci->remote_wakeup << 1) |
+ ci->gadget.is_selfpowered;
+ }
} else if ((setup->bRequestType & USB_RECIP_MASK) \
== USB_RECIP_ENDPOINT) {
dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
@@ -1007,6 +1025,28 @@ static int otg_a_alt_hnp_support(struct ci_hdrc *ci)
return isr_setup_status_phase(ci);
}
+static int otg_srp_reqd(struct ci_hdrc *ci)
+{
+ if (ci_otg_is_fsm_mode(ci)) {
+ ci->fsm.otg_srp_reqd = 1;
+ return isr_setup_status_phase(ci);
+ } else {
+ return -ENOTSUPP;
+ }
+}
+
+static int otg_hnp_reqd(struct ci_hdrc *ci)
+{
+ if (ci_otg_is_fsm_mode(ci)) {
+ ci->fsm.otg_hnp_reqd = 1;
+ ci->fsm.b_bus_req = 1;
+ ci->gadget.host_request_flag = 1;
+ return isr_setup_status_phase(ci);
+ } else {
+ return -ENOTSUPP;
+ }
+}
+
/**
* isr_setup_packet_handler: setup packet handler
* @ci: UDC descriptor
@@ -1077,8 +1117,9 @@ __acquires(ci->lock)
type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
type != (USB_DIR_IN|USB_RECIP_INTERFACE))
goto delegate;
- if (le16_to_cpu(req.wLength) != 2 ||
- le16_to_cpu(req.wValue) != 0)
+ if ((le16_to_cpu(req.wLength) != 2 &&
+ le16_to_cpu(req.wLength) != 1) ||
+ le16_to_cpu(req.wValue) != 0)
break;
err = isr_get_status_response(ci, &req);
break;
@@ -1129,6 +1170,12 @@ __acquires(ci->lock)
err = isr_setup_status_phase(
ci);
break;
+ case TEST_OTG_SRP_REQD:
+ err = otg_srp_reqd(ci);
+ break;
+ case TEST_OTG_HNP_REQD:
+ err = otg_hnp_reqd(ci);
+ break;
default:
break;
}
@@ -1306,6 +1353,10 @@ static int ep_disable(struct usb_ep *ep)
return -EBUSY;
spin_lock_irqsave(hwep->lock, flags);
+ if (hwep->ci->gadget.speed == USB_SPEED_UNKNOWN) {
+ spin_unlock_irqrestore(hwep->lock, flags);
+ return 0;
+ }
/* only internal SW should disable ctrl endpts */
@@ -1395,6 +1446,10 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
return -EINVAL;
spin_lock_irqsave(hwep->lock, flags);
+ if (hwep->ci->gadget.speed == USB_SPEED_UNKNOWN) {
+ spin_unlock_irqrestore(hwep->lock, flags);
+ return 0;
+ }
retval = _ep_queue(ep, req, gfp_flags);
spin_unlock_irqrestore(hwep->lock, flags);
return retval;
@@ -1418,8 +1473,8 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
return -EINVAL;
spin_lock_irqsave(hwep->lock, flags);
-
- hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
+ if (hwep->ci->gadget.speed != USB_SPEED_UNKNOWN)
+ hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
dma_pool_free(hwep->td_pool, node->ptr, node->dma);
@@ -1490,6 +1545,10 @@ static void ep_fifo_flush(struct usb_ep *ep)
}
spin_lock_irqsave(hwep->lock, flags);
+ if (hwep->ci->gadget.speed == USB_SPEED_UNKNOWN) {
+ spin_unlock_irqrestore(hwep->lock, flags);
+ return;
+ }
hw_ep_flush(hwep->ci, hwep->num, hwep->dir);
@@ -1527,27 +1586,19 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
gadget_ready = 1;
spin_unlock_irqrestore(&ci->lock, flags);
- if (gadget_ready) {
- if (is_active) {
- pm_runtime_get_sync(&_gadget->dev);
- hw_device_reset(ci);
- hw_device_state(ci, ci->ep0out->qh.dma);
- usb_gadget_set_state(_gadget, USB_STATE_POWERED);
- usb_udc_vbus_handler(_gadget, true);
- } else {
- usb_udc_vbus_handler(_gadget, false);
- if (ci->driver)
- ci->driver->disconnect(&ci->gadget);
- hw_device_state(ci, 0);
- if (ci->platdata->notify_event)
- ci->platdata->notify_event(ci,
- CI_HDRC_CONTROLLER_STOPPED_EVENT);
- _gadget_stop_activity(&ci->gadget);
- pm_runtime_put_sync(&_gadget->dev);
- usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED);
- }
+ /* Charger Detection */
+ ci_usb_charger_connect(ci, is_active);
+
+ if (ci->usb_phy) {
+ if (is_active)
+ usb_phy_set_event(ci->usb_phy, USB_EVENT_VBUS);
+ else
+ usb_phy_set_event(ci->usb_phy, USB_EVENT_NONE);
}
+ if (gadget_ready)
+ ci_hdrc_gadget_connect(_gadget, is_active);
+
return 0;
}
@@ -1558,6 +1609,10 @@ static int ci_udc_wakeup(struct usb_gadget *_gadget)
int ret = 0;
spin_lock_irqsave(&ci->lock, flags);
+ if (ci->gadget.speed == USB_SPEED_UNKNOWN) {
+ spin_unlock_irqrestore(&ci->lock, flags);
+ return 0;
+ }
if (!ci->remote_wakeup) {
ret = -EOPNOTSUPP;
goto out;
@@ -1725,7 +1780,6 @@ static int ci_udc_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
{
struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
- unsigned long flags;
int retval = -ENOMEM;
if (driver->disconnect == NULL)
@@ -1745,25 +1799,14 @@ static int ci_udc_start(struct usb_gadget *gadget,
ci->driver = driver;
/* Start otg fsm for B-device */
- if (ci_otg_is_fsm_mode(ci) && ci->fsm.id) {
- ci_hdrc_otg_fsm_start(ci);
+ if (ci_otg_is_fsm_mode(ci)) {
+ if (ci->fsm.id)
+ ci_hdrc_otg_fsm_start(ci);
return retval;
}
- pm_runtime_get_sync(&ci->gadget.dev);
- if (ci->vbus_active) {
- spin_lock_irqsave(&ci->lock, flags);
- hw_device_reset(ci);
- } else {
- usb_udc_vbus_handler(&ci->gadget, false);
- pm_runtime_put_sync(&ci->gadget.dev);
- return retval;
- }
-
- retval = hw_device_state(ci, ci->ep0out->qh.dma);
- spin_unlock_irqrestore(&ci->lock, flags);
- if (retval)
- pm_runtime_put_sync(&ci->gadget.dev);
+ if (ci->vbus_active)
+ ci_hdrc_gadget_connect(&ci->gadget, 1);
return retval;
}
@@ -1848,27 +1891,35 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci)
if (USBi_PCI & intr) {
ci->gadget.speed = hw_port_is_high_speed(ci) ?
USB_SPEED_HIGH : USB_SPEED_FULL;
- if (ci->suspended && ci->driver->resume) {
- spin_unlock(&ci->lock);
- ci->driver->resume(&ci->gadget);
- spin_lock(&ci->lock);
+ if (ci->usb_phy)
+ usb_phy_set_event(ci->usb_phy,
+ USB_EVENT_ENUMERATED);
+ if (ci->suspended) {
+ if (ci->driver->resume) {
+ spin_unlock(&ci->lock);
+ ci->driver->resume(&ci->gadget);
+ spin_lock(&ci->lock);
+ }
ci->suspended = 0;
+ usb_gadget_set_state(&ci->gadget,
+ ci->resume_state);
}
}
if (USBi_UI & intr)
isr_tr_complete_handler(ci);
- if (USBi_SLI & intr) {
+ if ((USBi_SLI & intr) && !(ci->suspended)) {
+ ci->suspended = 1;
+ ci->resume_state = ci->gadget.state;
if (ci->gadget.speed != USB_SPEED_UNKNOWN &&
ci->driver->suspend) {
- ci->suspended = 1;
spin_unlock(&ci->lock);
ci->driver->suspend(&ci->gadget);
- usb_gadget_set_state(&ci->gadget,
- USB_STATE_SUSPENDED);
spin_lock(&ci->lock);
}
+ usb_gadget_set_state(&ci->gadget,
+ USB_STATE_SUSPENDED);
}
retval = IRQ_HANDLED;
} else {
@@ -1902,13 +1953,13 @@ static int udc_start(struct ci_hdrc *ci)
INIT_LIST_HEAD(&ci->gadget.ep_list);
/* alloc resources */
- ci->qh_pool = dma_pool_create("ci_hw_qh", dev,
+ ci->qh_pool = dma_pool_create("ci_hw_qh", dev->parent,
sizeof(struct ci_hw_qh),
64, CI_HDRC_PAGE_SIZE);
if (ci->qh_pool == NULL)
return -ENOMEM;
- ci->td_pool = dma_pool_create("ci_hw_td", dev,
+ ci->td_pool = dma_pool_create("ci_hw_td", dev->parent,
sizeof(struct ci_hw_td),
64, CI_HDRC_PAGE_SIZE);
if (ci->td_pool == NULL) {
@@ -1958,10 +2009,74 @@ void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
dma_pool_destroy(ci->qh_pool);
}
+int ci_usb_charger_connect(struct ci_hdrc *ci, int is_active)
+{
+ int ret = 0;
+
+ if (is_active)
+ pm_runtime_get_sync(ci->dev);
+
+ if (ci->platdata->notify_event) {
+ if (is_active)
+ hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
+
+ ret = ci->platdata->notify_event(ci,
+ CI_HDRC_CONTROLLER_VBUS_EVENT);
+ if (ret == CI_HDRC_NOTIFY_RET_DEFER_EVENT) {
+ hw_device_reset(ci);
+ /* Pull up dp */
+ hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
+ ci->platdata->notify_event(ci,
+ CI_HDRC_CONTROLLER_CHARGER_POST_EVENT);
+ /* Pull down dp */
+ hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
+ }
+ }
+
+ if (!is_active)
+ pm_runtime_put_sync(ci->dev);
+
+ return ret;
+}
+
+/**
+ * ci_hdrc_gadget_connect: caller make sure gadget driver is binded
+ */
+void ci_hdrc_gadget_connect(struct usb_gadget *gadget, int is_active)
+{
+ struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
+
+ if (is_active) {
+ pm_runtime_get_sync(&gadget->dev);
+ hw_device_reset(ci);
+ hw_device_state(ci, ci->ep0out->qh.dma);
+ usb_gadget_set_state(gadget, USB_STATE_POWERED);
+ usb_udc_vbus_handler(gadget, true);
+ } else {
+ usb_udc_vbus_handler(gadget, false);
+ if (ci->driver)
+ ci->driver->disconnect(gadget);
+ hw_device_state(ci, 0);
+ if (ci->platdata->notify_event)
+ ci->platdata->notify_event(ci,
+ CI_HDRC_CONTROLLER_STOPPED_EVENT);
+ _gadget_stop_activity(gadget);
+ pm_runtime_put_sync(&gadget->dev);
+ usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
+ }
+}
+
static int udc_id_switch_for_device(struct ci_hdrc *ci)
{
- if (ci->is_otg)
- /* Clear and enable BSV irq */
+ if (!ci->is_otg)
+ return 0;
+
+ /*
+ * Clear and enable BSV irq for A-device switch to B-device
+ * (in otg fsm mode, means A_IDLE->B_DILE) due to ID change.
+ */
+ if (!ci_otg_is_fsm_mode(ci) ||
+ ci->fsm.otg->state == OTG_STATE_A_IDLE)
hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE,
OTGSC_BSVIS | OTGSC_BSVIE);
@@ -1970,12 +2085,57 @@ static int udc_id_switch_for_device(struct ci_hdrc *ci)
static void udc_id_switch_for_host(struct ci_hdrc *ci)
{
+ if (!ci->is_otg)
+ return;
+
/*
- * host doesn't care B_SESSION_VALID event
- * so clear and disbale BSV irq
+ * Clear and disbale BSV irq for B-device switch to A-device
+ * (in otg fsm mode, means B_IDLE->A_IDLE) due to ID change.
*/
- if (ci->is_otg)
+ if (!ci_otg_is_fsm_mode(ci) ||
+ ci->fsm.otg->state == OTG_STATE_B_IDLE ||
+ ci->fsm.otg->state == OTG_STATE_UNDEFINED)
hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS);
+
+ ci->vbus_active = 0;
+}
+
+static void udc_suspend_for_power_lost(struct ci_hdrc *ci)
+{
+ /*
+ * Set OP_ENDPTLISTADDR to be non-zero for
+ * checking if controller resume from power lost
+ * in non-host mode.
+ */
+ if (hw_read(ci, OP_ENDPTLISTADDR, ~0) == 0)
+ hw_write(ci, OP_ENDPTLISTADDR, ~0, ~0);
+}
+
+/* Power lost with device mode */
+static void udc_resume_from_power_lost(struct ci_hdrc *ci)
+{
+ if (ci->is_otg)
+ hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE,
+ OTGSC_BSVIS | OTGSC_BSVIE);
+}
+
+static void udc_suspend(struct ci_hdrc *ci)
+{
+ udc_suspend_for_power_lost(ci);
+
+ if (ci->driver && ci->vbus_active &&
+ (ci->gadget.state != USB_STATE_SUSPENDED))
+ usb_gadget_disconnect(&ci->gadget);
+}
+
+static void udc_resume(struct ci_hdrc *ci, bool power_lost)
+{
+ if (power_lost) {
+ udc_resume_from_power_lost(ci);
+ } else {
+ if (ci->driver && ci->vbus_active)
+ usb_gadget_connect(&ci->gadget);
+ }
}
/**
@@ -1999,6 +2159,8 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci)
rdrv->start = udc_id_switch_for_device;
rdrv->stop = udc_id_switch_for_host;
rdrv->irq = udc_irq;
+ rdrv->suspend = udc_suspend;
+ rdrv->resume = udc_resume;
rdrv->name = "gadget";
ret = udc_start(ci);
diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h
index e66df0020bd4..7c3af66aa8f4 100644
--- a/drivers/usb/chipidea/udc.h
+++ b/drivers/usb/chipidea/udc.h
@@ -85,6 +85,8 @@ struct ci_hw_req {
int ci_hdrc_gadget_init(struct ci_hdrc *ci);
void ci_hdrc_gadget_destroy(struct ci_hdrc *ci);
+int ci_usb_charger_connect(struct ci_hdrc *ci, int is_active);
+void ci_hdrc_gadget_connect(struct usb_gadget *gadget, int is_active);
#else
@@ -98,6 +100,17 @@ static inline void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
}
+static inline int ci_usb_charger_connect(struct ci_hdrc *ci, int is_active)
+{
+ return 0;
+}
+
+static inline void ci_hdrc_gadget_connect(struct usb_gadget *gadget,
+ int is_active)
+{
+
+}
+
#endif
#endif /* __DRIVERS_USB_CHIPIDEA_UDC_H */
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index 20d02a5e418d..b7d21b052c19 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -1,5 +1,6 @@
/*
- * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
@@ -14,6 +15,8 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include "ci_hdrc_imx.h"
@@ -57,11 +60,24 @@
#define MX6_BM_NON_BURST_SETTING BIT(1)
#define MX6_BM_OVER_CUR_DIS BIT(7)
#define MX6_BM_OVER_CUR_POLARITY BIT(8)
+#define MX6_BM_PRW_POLARITY BIT(9)
#define MX6_BM_WAKEUP_ENABLE BIT(10)
+#define MX6_BM_UTMI_ON_CLOCK BIT(13)
#define MX6_BM_ID_WAKEUP BIT(16)
#define MX6_BM_VBUS_WAKEUP BIT(17)
#define MX6SX_BM_DPDM_WAKEUP_EN BIT(29)
#define MX6_BM_WAKEUP_INTR BIT(31)
+
+#define MX6_USB_HSIC_CTRL_OFFSET 0x10
+/* Send resume signal without 480Mhz PHY clock */
+#define MX6SX_BM_HSIC_AUTO_RESUME BIT(23)
+/* set before portsc.suspendM = 1 */
+#define MX6_BM_HSIC_DEV_CONN BIT(21)
+/* HSIC enable */
+#define MX6_BM_HSIC_EN BIT(12)
+/* Force HSIC module 480M clock on, even when in Host is in suspend mode */
+#define MX6_BM_HSIC_CLK_ON BIT(11)
+
#define MX6_USB_OTG1_PHY_CTRL 0x18
/* For imx6dql, it is host-only controller, for later imx6, it is otg's */
#define MX6_USB_OTG2_PHY_CTRL 0x1c
@@ -74,12 +90,50 @@
#define VF610_OVER_CUR_DIS BIT(7)
#define MX7D_USBNC_USB_CTRL2 0x4
+#define MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN BIT(8)
+#define MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK (BIT(7) | BIT(6))
+#define MX7D_USBNC_USB_CTRL2_OPMODE(v) (v << 6)
+#define MX7D_USBNC_USB_CTRL2_OPMODE_NON_DRIVING MX7D_USBNC_USB_CTRL2_OPMODE(1)
+#define MX7D_USBNC_HSIC_AUTO_RESUME BIT(2)
+
#define MX7D_USB_VBUS_WAKEUP_SOURCE_MASK 0x3
#define MX7D_USB_VBUS_WAKEUP_SOURCE(v) (v << 0)
#define MX7D_USB_VBUS_WAKEUP_SOURCE_VBUS MX7D_USB_VBUS_WAKEUP_SOURCE(0)
#define MX7D_USB_VBUS_WAKEUP_SOURCE_AVALID MX7D_USB_VBUS_WAKEUP_SOURCE(1)
#define MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID MX7D_USB_VBUS_WAKEUP_SOURCE(2)
#define MX7D_USB_VBUS_WAKEUP_SOURCE_SESS_END MX7D_USB_VBUS_WAKEUP_SOURCE(3)
+#define MX7D_USB_TERMSEL_OVERRIDE BIT(4)
+#define MX7D_USB_TERMSEL_OVERRIDE_EN BIT(5)
+
+#define MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB BIT(3)
+#define MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 BIT(2)
+#define MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0 BIT(1)
+#define MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL BIT(0)
+#define MX7D_USB_OTG_PHY_CFG2 0x34
+
+#define MX7D_USB_OTG_PHY_STATUS 0x3c
+#define MX7D_USB_OTG_PHY_STATUS_CHRGDET BIT(29)
+#define MX7D_USB_OTG_PHY_STATUS_VBUS_VLD BIT(3)
+#define MX7D_USB_OTG_PHY_STATUS_LINE_STATE1 BIT(1)
+#define MX7D_USB_OTG_PHY_STATUS_LINE_STATE0 BIT(0)
+
+#define ANADIG_ANA_MISC0 0x150
+#define ANADIG_ANA_MISC0_SET 0x154
+#define ANADIG_ANA_MISC0_CLK_DELAY(x) ((x >> 26) & 0x7)
+
+#define ANADIG_USB1_CHRG_DETECT_SET 0x1b4
+#define ANADIG_USB1_CHRG_DETECT_CLR 0x1b8
+#define ANADIG_USB1_CHRG_DETECT_EN_B BIT(20)
+#define ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B BIT(19)
+#define ANADIG_USB1_CHRG_DETECT_CHK_CONTACT BIT(18)
+
+#define ANADIG_USB1_VBUS_DET_STAT 0x1c0
+#define ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID BIT(3)
+
+#define ANADIG_USB1_CHRG_DET_STAT 0x1d0
+#define ANADIG_USB1_CHRG_DET_STAT_DM_STATE BIT(2)
+#define ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED BIT(1)
+#define ANADIG_USB1_CHRG_DET_STAT_PLUG_CONTACT BIT(0)
struct usbmisc_ops {
/* It's called once when probe a usb device */
@@ -88,6 +142,19 @@ struct usbmisc_ops {
int (*post)(struct imx_usbmisc_data *data);
/* It's called when we need to enable/disable usb wakeup */
int (*set_wakeup)(struct imx_usbmisc_data *data, bool enabled);
+ /* usb charger contact and primary detection */
+ int (*charger_primary_detection)(struct imx_usbmisc_data *data);
+ /* usb charger secondary detection */
+ int (*charger_secondary_detection)(struct imx_usbmisc_data *data);
+ /* It's called when system resume from usb power lost */
+ int (*power_lost_check)(struct imx_usbmisc_data *data);
+ /* It's called before setting portsc.suspendM */
+ int (*hsic_set_connect)(struct imx_usbmisc_data *data);
+ /* It's called during suspend/resume */
+ int (*hsic_set_clk)(struct imx_usbmisc_data *data, bool enabled);
+ /* override UTMI termination select */
+ int (*term_select_override)(struct imx_usbmisc_data *data,
+ bool enable, int val);
};
struct imx_usbmisc {
@@ -96,6 +163,8 @@ struct imx_usbmisc {
const struct usbmisc_ops *ops;
};
+static struct regulator *vbus_wakeup_reg;
+
static int usbmisc_imx25_init(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
@@ -227,15 +296,86 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
return 0;
}
+static int usbmisc_imx6_hsic_set_connect(struct imx_usbmisc_data *data)
+{
+ unsigned long flags;
+ u32 val, offset;
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
+ int ret = 0;
+
+ spin_lock_irqsave(&usbmisc->lock, flags);
+ if (data->index == 2 || data->index == 3) {
+ offset = (data->index - 2) * 4;
+ } else if (data->index == 0) {
+ /*
+ * For controllers later than imx7d (imx7d is included),
+ * each controller has its own non core register region.
+ * And the controllers before than imx7d, the 1st controller
+ * is not HSIC controller.
+ */
+ offset = 0;
+ } else {
+ dev_err(data->dev, "index is error for usbmisc\n");
+ offset = 0;
+ ret = -EINVAL;
+ }
+
+ val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset);
+ if (!(val & MX6_BM_HSIC_DEV_CONN))
+ writel(val | MX6_BM_HSIC_DEV_CONN,
+ usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+
+ return ret;
+}
+
+static int usbmisc_imx6_hsic_set_clk(struct imx_usbmisc_data *data, bool on)
+{
+ unsigned long flags;
+ u32 val, offset;
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
+ int ret = 0;
+
+ spin_lock_irqsave(&usbmisc->lock, flags);
+ if (data->index == 2 || data->index == 3) {
+ offset = (data->index - 2) * 4;
+ } else if (data->index == 0) {
+ offset = 0;
+ } else {
+ dev_err(data->dev, "index is error for usbmisc\n");
+ offset = 0;
+ ret = -EINVAL;
+ }
+
+ val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset);
+ val |= MX6_BM_HSIC_EN | MX6_BM_HSIC_CLK_ON;
+ if (on)
+ val |= MX6_BM_HSIC_CLK_ON;
+ else
+ val &= ~MX6_BM_HSIC_CLK_ON;
+ writel(val, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET + offset);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+
+ return 0;
+}
+
+static u32 imx6q_finalize_wakeup_setting(struct imx_usbmisc_data *data)
+{
+ if (data->available_role == USB_DR_MODE_PERIPHERAL)
+ return MX6_BM_VBUS_WAKEUP;
+ else if (data->available_role == USB_DR_MODE_OTG)
+ return MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP;
+
+ return 0;
+}
+
static int usbmisc_imx6q_set_wakeup
(struct imx_usbmisc_data *data, bool enabled)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
unsigned long flags;
- u32 val;
- u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE |
- MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP);
int ret = 0;
+ u32 val, wakeup_setting = MX6_BM_WAKEUP_ENABLE;
if (data->index > 3)
return -EINVAL;
@@ -243,15 +383,20 @@ static int usbmisc_imx6q_set_wakeup
spin_lock_irqsave(&usbmisc->lock, flags);
val = readl(usbmisc->base + data->index * 4);
if (enabled) {
- val |= wakeup_setting;
- writel(val, usbmisc->base + data->index * 4);
+ wakeup_setting |= imx6q_finalize_wakeup_setting(data);
+ writel(val | wakeup_setting, usbmisc->base + data->index * 4);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+ if (vbus_wakeup_reg)
+ ret = regulator_enable(vbus_wakeup_reg);
} else {
if (val & MX6_BM_WAKEUP_INTR)
pr_debug("wakeup int at ci_hdrc.%d\n", data->index);
- val &= ~wakeup_setting;
- writel(val, usbmisc->base + data->index * 4);
+ wakeup_setting |= MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP;
+ writel(val & ~wakeup_setting, usbmisc->base + data->index * 4);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+ if (vbus_wakeup_reg && regulator_is_enabled(vbus_wakeup_reg))
+ regulator_disable(vbus_wakeup_reg);
}
- spin_unlock_irqrestore(&usbmisc->lock, flags);
return ret;
}
@@ -260,7 +405,7 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
{
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
unsigned long flags;
- u32 reg;
+ u32 reg, val;
if (data->index > 3)
return -EINVAL;
@@ -281,6 +426,27 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
writel(reg | MX6_BM_NON_BURST_SETTING,
usbmisc->base + data->index * 4);
+ /* For HSIC controller */
+ if (data->index == 2 || data->index == 3) {
+ val = readl(usbmisc->base + data->index * 4);
+ writel(val | MX6_BM_UTMI_ON_CLOCK,
+ usbmisc->base + data->index * 4);
+ val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET
+ + (data->index - 2) * 4);
+ val |= MX6_BM_HSIC_EN | MX6_BM_HSIC_CLK_ON;
+ writel(val, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET
+ + (data->index - 2) * 4);
+
+ /*
+ * Need to add delay to wait 24M OSC to be stable,
+ * It is board specific.
+ */
+ regmap_read(data->anatop, ANADIG_ANA_MISC0, &val);
+ /* 0 <= data->osc_clkgate_delay <= 7 */
+ if (data->osc_clkgate_delay > ANADIG_ANA_MISC0_CLK_DELAY(val))
+ regmap_write(data->anatop, ANADIG_ANA_MISC0_SET,
+ (data->osc_clkgate_delay) << 26);
+ }
spin_unlock_irqrestore(&usbmisc->lock, flags);
usbmisc_imx6q_set_wakeup(data, false);
@@ -297,9 +463,9 @@ static int usbmisc_imx6sx_init(struct imx_usbmisc_data *data)
usbmisc_imx6q_init(data);
+ spin_lock_irqsave(&usbmisc->lock, flags);
if (data->index == 0 || data->index == 1) {
reg = usbmisc->base + MX6_USB_OTG1_PHY_CTRL + data->index * 4;
- spin_lock_irqsave(&usbmisc->lock, flags);
/* Set vbus wakeup source as bvalid */
val = readl(reg);
writel(val | MX6SX_USB_VBUS_WAKEUP_SOURCE_BVALID, reg);
@@ -310,9 +476,18 @@ static int usbmisc_imx6sx_init(struct imx_usbmisc_data *data)
val = readl(usbmisc->base + data->index * 4);
writel(val & ~MX6SX_BM_DPDM_WAKEUP_EN,
usbmisc->base + data->index * 4);
- spin_unlock_irqrestore(&usbmisc->lock, flags);
}
+ /* For HSIC controller */
+ if (data->index == 2) {
+ val = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET
+ + (data->index - 2) * 4);
+ val |= MX6SX_BM_HSIC_AUTO_RESUME;
+ writel(val, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET
+ + (data->index - 2) * 4);
+ }
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+
return 0;
}
@@ -342,16 +517,17 @@ static int usbmisc_imx7d_set_wakeup
struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
unsigned long flags;
u32 val;
- u32 wakeup_setting = (MX6_BM_WAKEUP_ENABLE |
- MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP);
+ u32 wakeup_setting = MX6_BM_WAKEUP_ENABLE;
spin_lock_irqsave(&usbmisc->lock, flags);
val = readl(usbmisc->base);
if (enabled) {
+ wakeup_setting |= imx6q_finalize_wakeup_setting(data);
writel(val | wakeup_setting, usbmisc->base);
} else {
if (val & MX6_BM_WAKEUP_INTR)
dev_dbg(data->dev, "wakeup int\n");
+ wakeup_setting |= MX6_BM_VBUS_WAKEUP | MX6_BM_ID_WAKEUP;
writel(val & ~wakeup_setting, usbmisc->base);
}
spin_unlock_irqrestore(&usbmisc->lock, flags);
@@ -376,12 +552,33 @@ static int usbmisc_imx7d_init(struct imx_usbmisc_data *data)
/* High active */
reg &= ~(MX6_BM_OVER_CUR_DIS | MX6_BM_OVER_CUR_POLARITY);
}
+
+ if (data->pwr_polarity)
+ reg |= MX6_BM_PRW_POLARITY;
+
writel(reg, usbmisc->base);
+ /* SoC non-burst setting */
+ reg = readl(usbmisc->base);
+ writel(reg | MX6_BM_NON_BURST_SETTING, usbmisc->base);
+
reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
reg &= ~MX7D_USB_VBUS_WAKEUP_SOURCE_MASK;
writel(reg | MX7D_USB_VBUS_WAKEUP_SOURCE_BVALID,
usbmisc->base + MX7D_USBNC_USB_CTRL2);
+
+ if (data->hsic) {
+ reg = readl(usbmisc->base);
+ writel(reg | MX6_BM_UTMI_ON_CLOCK, usbmisc->base);
+
+ reg = readl(usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET);
+ reg |= MX6_BM_HSIC_EN | MX6_BM_HSIC_CLK_ON;
+ writel(reg, usbmisc->base + MX6_USB_HSIC_CTRL_OFFSET);
+
+ reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
+ writel(reg | MX7D_USBNC_HSIC_AUTO_RESUME,
+ usbmisc->base + MX7D_USBNC_USB_CTRL2);
+ }
spin_unlock_irqrestore(&usbmisc->lock, flags);
usbmisc_imx7d_set_wakeup(data, false);
@@ -389,6 +586,371 @@ static int usbmisc_imx7d_init(struct imx_usbmisc_data *data)
return 0;
}
+static int usbmisc_imx7d_power_lost_check(struct imx_usbmisc_data *data)
+{
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&usbmisc->lock, flags);
+ val = readl(usbmisc->base);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+ /*
+ * Here use a power on reset value to judge
+ * if the controller experienced a power lost
+ */
+ if (val == 0x30001000)
+ return 1;
+ else
+ return 0;
+}
+
+
+/***************************************************************************/
+/* imx usb charger detecton */
+/***************************************************************************/
+static void usb_charger_is_present(struct usb_charger *charger, bool present)
+{
+ if (present)
+ charger->present = 1;
+ else
+ charger->present = 0;
+
+ power_supply_changed(charger->psy);
+ sysfs_notify(&charger->psy->dev.kobj, NULL, "present");
+}
+
+static void imx6_disable_charger_detector(struct imx_usbmisc_data *data)
+{
+ struct regmap *regmap = data->anatop;
+
+ regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_SET,
+ ANADIG_USB1_CHRG_DETECT_EN_B |
+ ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
+}
+
+static int imx6_charger_data_contact_detect(struct imx_usbmisc_data *data)
+{
+ struct regmap *regmap = data->anatop;
+ struct usb_charger *charger = data->charger;
+ u32 val;
+ int i, data_pin_contact_count = 0;
+
+ /* check if vbus is valid */
+ regmap_read(regmap, ANADIG_USB1_VBUS_DET_STAT, &val);
+ if (!(val & ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID)) {
+ dev_err(charger->dev, "vbus is error\n");
+ return -EINVAL;
+ }
+
+ /* Enable charger detector */
+ regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_CLR,
+ ANADIG_USB1_CHRG_DETECT_EN_B);
+ /*
+ * - Do not check whether a charger is connected to the USB port
+ * - Check whether the USB plug has been in contact with each other
+ */
+ regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_SET,
+ ANADIG_USB1_CHRG_DETECT_CHK_CONTACT |
+ ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
+
+ /* Check if plug is connected */
+ for (i = 0; i < 100; i = i + 1) {
+ regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val);
+ if (val & ANADIG_USB1_CHRG_DET_STAT_PLUG_CONTACT) {
+ data_pin_contact_count++;
+ if (data_pin_contact_count > 5)
+ /* Data pin makes contact */
+ break;
+ else
+ usleep_range(5000, 10000);
+ } else {
+ data_pin_contact_count = 0;
+ usleep_range(5000, 6000);
+ }
+ }
+
+ if (i == 100) {
+ dev_err(charger->dev,
+ "VBUS is coming from a dedicated power supply.\n");
+ imx6_disable_charger_detector(data);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int imx6_charger_primary_detection(struct imx_usbmisc_data *data)
+{
+ struct regmap *regmap = data->anatop;
+ struct usb_charger *charger = data->charger;
+ u32 val;
+ int ret;
+
+ ret = imx6_charger_data_contact_detect(data);
+ if (ret)
+ return ret;
+
+ /*
+ * - Do check whether a charger is connected to the USB port
+ * - Do not Check whether the USB plug has been in contact with
+ * each other
+ */
+ regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_CLR,
+ ANADIG_USB1_CHRG_DETECT_CHK_CONTACT |
+ ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
+
+ msleep(100);
+
+ /* Check if it is a charger */
+ regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val);
+ if (!(val & ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED)) {
+ dev_dbg(charger->dev, "It is a stardard downstream port\n");
+ charger->psy_desc.type = POWER_SUPPLY_TYPE_USB;
+ charger->max_current = 500;
+ }
+
+ imx6_disable_charger_detector(data);
+ return 0;
+}
+
+/*
+ * It must be called after dp is pulled up (from USB controller driver),
+ * That is used to differentiate DCP and CDP
+ */
+int imx6_charger_secondary_detection(struct imx_usbmisc_data *data)
+{
+ struct regmap *regmap = data->anatop;
+ struct usb_charger *charger = data->charger;
+ int val;
+
+ msleep(80);
+
+ mutex_lock(&charger->lock);
+ regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val);
+ if (val & ANADIG_USB1_CHRG_DET_STAT_DM_STATE) {
+ dev_dbg(charger->dev, "It is a dedicate charging port\n");
+ charger->psy_desc.type = POWER_SUPPLY_TYPE_USB_DCP;
+ charger->max_current = 1500;
+ } else {
+ dev_dbg(charger->dev, "It is a charging downstream port\n");
+ charger->psy_desc.type = POWER_SUPPLY_TYPE_USB_CDP;
+ charger->max_current = 900;
+ }
+
+ usb_charger_is_present(charger, true);
+ mutex_unlock(&charger->lock);
+
+ return 0;
+}
+
+static int usbmisc_imx6sx_power_lost_check(struct imx_usbmisc_data *data)
+{
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&usbmisc->lock, flags);
+ val = readl(usbmisc->base + data->index * 4);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+ /*
+ * Here use a power on reset value to judge
+ * if the controller experienced a power lost
+ */
+ if (val == 0x30001000)
+ return 1;
+ else
+ return 0;
+}
+
+static void imx7_disable_charger_detector(struct imx_usbmisc_data *data)
+{
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&usbmisc->lock, flags);
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
+ val &= ~(MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB |
+ MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 |
+ MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0 |
+ MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL);
+ writel(val, usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
+
+ /* Set OPMODE to be 2'b00 and disable its override */
+ val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
+ val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK;
+ writel(val, usbmisc->base + MX7D_USBNC_USB_CTRL2);
+
+ val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
+ writel(val & ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN,
+ usbmisc->base + MX7D_USBNC_USB_CTRL2);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+}
+
+static int imx7d_charger_data_contact_detect(struct imx_usbmisc_data *data)
+{
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
+ struct usb_charger *charger = data->charger;
+ unsigned long flags;
+ u32 val;
+ int i, data_pin_contact_count = 0;
+
+ spin_lock_irqsave(&usbmisc->lock, flags);
+
+ /* check if vbus is valid */
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS);
+ if (!(val & MX7D_USB_OTG_PHY_STATUS_VBUS_VLD)) {
+ dev_err(charger->dev, "vbus is error\n");
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+ return -EINVAL;
+ }
+
+ /*
+ * - Do not check whether a charger is connected to the USB port
+ * - Check whether the USB plug has been in contact with each other
+ */
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
+ writel(val | MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB,
+ usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
+
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+
+ /* Check if plug is connected */
+ for (i = 0; i < 100; i = i + 1) {
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS);
+ if (!(val & MX7D_USB_OTG_PHY_STATUS_LINE_STATE0)) {
+ if (data_pin_contact_count++ > 5)
+ /* Data pin makes contact */
+ break;
+ else
+ usleep_range(5000, 10000);
+ } else {
+ data_pin_contact_count = 0;
+ usleep_range(5000, 6000);
+ }
+ }
+
+ if (i == 100) {
+ dev_err(charger->dev,
+ "VBUS is coming from a dedicated power supply.\n");
+ imx7_disable_charger_detector(data);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int imx7d_charger_primary_detection(struct imx_usbmisc_data *data)
+{
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
+ struct usb_charger *charger = data->charger;
+ unsigned long flags;
+ u32 val;
+ int ret;
+
+ ret = imx7d_charger_data_contact_detect(data);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&usbmisc->lock, flags);
+ /* Set OPMODE to be non-driving mode */
+ val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
+ val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK;
+ val |= MX7D_USBNC_USB_CTRL2_OPMODE_NON_DRIVING;
+ writel(val, usbmisc->base + MX7D_USBNC_USB_CTRL2);
+
+ val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
+ writel(val | MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN,
+ usbmisc->base + MX7D_USBNC_USB_CTRL2);
+
+ /*
+ * - Do check whether a charger is connected to the USB port
+ * - Do not Check whether the USB plug has been in contact with
+ * each other
+ */
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
+ writel(val | MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 |
+ MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0,
+ usbmisc->base + MX7D_USB_OTG_PHY_CFG2);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+
+ usleep_range(1000, 2000);
+
+ /* Check if it is a charger */
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS);
+ if (!(val & MX7D_USB_OTG_PHY_STATUS_CHRGDET)) {
+ dev_dbg(charger->dev, "It is a stardard downstream port\n");
+ charger->psy_desc.type = POWER_SUPPLY_TYPE_USB;
+ charger->max_current = 500;
+ }
+
+ imx7_disable_charger_detector(data);
+
+ return 0;
+}
+
+/*
+ * It must be called after dp is pulled up (from USB controller driver),
+ * That is used to differentiate DCP and CDP
+ */
+int imx7d_charger_secondary_detection(struct imx_usbmisc_data *data)
+{
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
+ struct usb_charger *charger = data->charger;
+ int val;
+
+ msleep(80);
+
+ mutex_lock(&charger->lock);
+ val = readl(usbmisc->base + MX7D_USB_OTG_PHY_STATUS);
+ if (val & MX7D_USB_OTG_PHY_STATUS_LINE_STATE1) {
+ dev_dbg(charger->dev, "It is a dedicate charging port\n");
+ charger->psy_desc.type = POWER_SUPPLY_TYPE_USB_DCP;
+ charger->max_current = 1500;
+ } else {
+ dev_dbg(charger->dev, "It is a charging downstream port\n");
+ charger->psy_desc.type = POWER_SUPPLY_TYPE_USB_CDP;
+ charger->max_current = 900;
+ }
+
+ usb_charger_is_present(charger, true);
+ mutex_unlock(&charger->lock);
+
+ return 0;
+}
+
+static int usbmisc_term_select_override(struct imx_usbmisc_data *data,
+ bool enable, int val)
+{
+ struct imx_usbmisc *usbmisc = dev_get_drvdata(data->dev);
+ unsigned long flags;
+ u32 reg;
+
+ spin_lock_irqsave(&usbmisc->lock, flags);
+
+ reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
+ if (enable) {
+ if (val)
+ writel(reg | MX7D_USB_TERMSEL_OVERRIDE,
+ usbmisc->base + MX7D_USBNC_USB_CTRL2);
+ else
+ writel(reg & ~MX7D_USB_TERMSEL_OVERRIDE,
+ usbmisc->base + MX7D_USBNC_USB_CTRL2);
+
+ reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
+ writel(reg | MX7D_USB_TERMSEL_OVERRIDE_EN,
+ usbmisc->base + MX7D_USBNC_USB_CTRL2);
+ } else {
+ writel(reg & ~MX7D_USB_TERMSEL_OVERRIDE_EN,
+ usbmisc->base + MX7D_USBNC_USB_CTRL2);
+ }
+
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+
+ return 0;
+}
+
static const struct usbmisc_ops imx25_usbmisc_ops = {
.init = usbmisc_imx25_init,
.post = usbmisc_imx25_post,
@@ -405,6 +967,10 @@ static const struct usbmisc_ops imx53_usbmisc_ops = {
static const struct usbmisc_ops imx6q_usbmisc_ops = {
.set_wakeup = usbmisc_imx6q_set_wakeup,
.init = usbmisc_imx6q_init,
+ .charger_primary_detection = imx6_charger_primary_detection,
+ .charger_secondary_detection = imx6_charger_secondary_detection,
+ .hsic_set_connect = usbmisc_imx6_hsic_set_connect,
+ .hsic_set_clk = usbmisc_imx6_hsic_set_clk,
};
static const struct usbmisc_ops vf610_usbmisc_ops = {
@@ -414,11 +980,30 @@ static const struct usbmisc_ops vf610_usbmisc_ops = {
static const struct usbmisc_ops imx6sx_usbmisc_ops = {
.set_wakeup = usbmisc_imx6q_set_wakeup,
.init = usbmisc_imx6sx_init,
+ .charger_primary_detection = imx6_charger_primary_detection,
+ .charger_secondary_detection = imx6_charger_secondary_detection,
+ .power_lost_check = usbmisc_imx6sx_power_lost_check,
+ .hsic_set_connect = usbmisc_imx6_hsic_set_connect,
+ .hsic_set_clk = usbmisc_imx6_hsic_set_clk,
};
static const struct usbmisc_ops imx7d_usbmisc_ops = {
.init = usbmisc_imx7d_init,
.set_wakeup = usbmisc_imx7d_set_wakeup,
+ .power_lost_check = usbmisc_imx7d_power_lost_check,
+ .charger_primary_detection = imx7d_charger_primary_detection,
+ .charger_secondary_detection = imx7d_charger_secondary_detection,
+ .term_select_override = usbmisc_term_select_override,
+ .hsic_set_connect = usbmisc_imx6_hsic_set_connect,
+ .hsic_set_clk = usbmisc_imx6_hsic_set_clk,
+};
+
+static const struct usbmisc_ops imx7ulp_usbmisc_ops = {
+ .init = usbmisc_imx7d_init,
+ .set_wakeup = usbmisc_imx7d_set_wakeup,
+ .power_lost_check = usbmisc_imx7d_power_lost_check,
+ .hsic_set_connect = usbmisc_imx6_hsic_set_connect,
+ .hsic_set_clk = usbmisc_imx6_hsic_set_clk,
};
int imx_usbmisc_init(struct imx_usbmisc_data *data)
@@ -463,6 +1048,115 @@ int imx_usbmisc_set_wakeup(struct imx_usbmisc_data *data, bool enabled)
}
EXPORT_SYMBOL_GPL(imx_usbmisc_set_wakeup);
+int imx_usbmisc_charger_detection(struct imx_usbmisc_data *data, bool connect)
+{
+ struct imx_usbmisc *usbmisc;
+ struct usb_charger *charger;
+ int ret = 0;
+
+ if (!data)
+ return -EINVAL;
+
+ charger = data->charger;
+ usbmisc = dev_get_drvdata(data->dev);
+ if (!usbmisc->ops->charger_primary_detection)
+ return -ENOTSUPP;
+
+ mutex_lock(&charger->lock);
+ if (connect) {
+ charger->online = 1;
+ ret = usbmisc->ops->charger_primary_detection(data);
+ if (ret) {
+ dev_err(charger->dev,
+ "Error occurs during detection: %d\n",
+ ret);
+ } else {
+ if (charger->psy_desc.type == POWER_SUPPLY_TYPE_USB)
+ usb_charger_is_present(charger, true);
+ }
+ } else {
+ charger->online = 0;
+ charger->max_current = 0;
+ charger->psy_desc.type = POWER_SUPPLY_TYPE_MAINS;
+
+ usb_charger_is_present(charger, false);
+ }
+ mutex_unlock(&charger->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(imx_usbmisc_charger_detection);
+
+int imx_usbmisc_charger_secondary_detection(struct imx_usbmisc_data *data)
+{
+ struct imx_usbmisc *usbmisc;
+
+ if (!data)
+ return 0;
+
+ usbmisc = dev_get_drvdata(data->dev);
+ if (!usbmisc->ops->charger_secondary_detection)
+ return 0;
+ return usbmisc->ops->charger_secondary_detection(data);
+}
+EXPORT_SYMBOL_GPL(imx_usbmisc_charger_secondary_detection);
+
+int imx_usbmisc_power_lost_check(struct imx_usbmisc_data *data)
+{
+ struct imx_usbmisc *usbmisc;
+
+ if (!data)
+ return 0;
+
+ usbmisc = dev_get_drvdata(data->dev);
+ if (!usbmisc->ops->power_lost_check)
+ return 0;
+ return usbmisc->ops->power_lost_check(data);
+}
+EXPORT_SYMBOL_GPL(imx_usbmisc_power_lost_check);
+
+int imx_usbmisc_hsic_set_connect(struct imx_usbmisc_data *data)
+{
+ struct imx_usbmisc *usbmisc;
+
+ if (!data)
+ return 0;
+
+ usbmisc = dev_get_drvdata(data->dev);
+ if (!usbmisc->ops->hsic_set_connect || !data->hsic)
+ return 0;
+ return usbmisc->ops->hsic_set_connect(data);
+}
+EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_connect);
+
+int imx_usbmisc_hsic_set_clk(struct imx_usbmisc_data *data, bool on)
+{
+ struct imx_usbmisc *usbmisc;
+
+ if (!data)
+ return 0;
+
+ usbmisc = dev_get_drvdata(data->dev);
+ if (!usbmisc->ops->hsic_set_clk || !data->hsic)
+ return 0;
+ return usbmisc->ops->hsic_set_clk(data, on);
+}
+EXPORT_SYMBOL_GPL(imx_usbmisc_hsic_set_clk);
+
+int imx_usbmisc_term_select_override(struct imx_usbmisc_data *data,
+ bool enable, int val)
+{
+ struct imx_usbmisc *usbmisc;
+
+ if (!data)
+ return 0;
+
+ usbmisc = dev_get_drvdata(data->dev);
+ if (!usbmisc->ops->term_select_override)
+ return 0;
+ return usbmisc->ops->term_select_override(data, enable, val);
+}
+EXPORT_SYMBOL_GPL(imx_usbmisc_term_select_override);
+
static const struct of_device_id usbmisc_imx_dt_ids[] = {
{
.compatible = "fsl,imx25-usbmisc",
@@ -504,6 +1198,10 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {
.compatible = "fsl,imx7d-usbmisc",
.data = &imx7d_usbmisc_ops,
},
+ {
+ .compatible = "fsl,imx7ulp-usbmisc",
+ .data = &imx7ulp_usbmisc_ops,
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
@@ -532,6 +1230,18 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
data->ops = (const struct usbmisc_ops *)of_id->data;
platform_set_drvdata(pdev, data);
+ vbus_wakeup_reg = devm_regulator_get(&pdev->dev, "vbus-wakeup");
+ if (PTR_ERR(vbus_wakeup_reg) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ else if (PTR_ERR(vbus_wakeup_reg) == -ENODEV)
+ /* no vbus regualator is needed */
+ vbus_wakeup_reg = NULL;
+ else if (IS_ERR(vbus_wakeup_reg)) {
+ dev_err(&pdev->dev, "Getting regulator error: %ld\n",
+ PTR_ERR(vbus_wakeup_reg));
+ return PTR_ERR(vbus_wakeup_reg);
+ }
+
return 0;
}
diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index 2f537bbdda09..23009e3d8ca9 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -68,6 +68,7 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
switch (old_state) {
case OTG_STATE_B_IDLE:
otg_del_timer(fsm, B_SE0_SRP);
+ otg_del_timer(fsm, B_SRP_FAIL);
fsm->b_se0_srp = 0;
fsm->adp_sns = 0;
fsm->adp_prb = 0;
@@ -85,6 +86,11 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
fsm->b_ase0_brst_tmout = 0;
break;
case OTG_STATE_B_HOST:
+ if (fsm->otg_hnp_reqd) {
+ fsm->otg_hnp_reqd = 0;
+ fsm->b_bus_req = 0;
+ }
+ fsm->a_conn = 0;
break;
case OTG_STATE_A_IDLE:
fsm->adp_prb = 0;
@@ -131,8 +137,10 @@ static void otg_hnp_polling_work(struct work_struct *work)
enum usb_otg_state state = fsm->otg->state;
u8 flag;
int retval;
+ struct usb_otg_descriptor *desc = NULL;
- if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST)
+ if ((state != OTG_STATE_A_HOST || !fsm->b_hnp_enable) &&
+ state != OTG_STATE_B_HOST)
return;
udev = usb_hub_find_child(fsm->otg->host->root_hub, 1);
@@ -142,6 +150,31 @@ static void otg_hnp_polling_work(struct work_struct *work)
return;
}
+ if (udev->state != USB_STATE_CONFIGURED) {
+ dev_dbg(&udev->dev, "the B dev is not resumed!\n");
+ schedule_delayed_work(&fsm->hnp_polling_work,
+ msecs_to_jiffies(T_HOST_REQ_POLL));
+ return;
+ }
+
+ /*
+ * Legacy otg test device does not support HNP polling,
+ * start HNP directly for legacy otg test device.
+ */
+ if (fsm->tst_maint &&
+ (__usb_get_extra_descriptor(udev->rawdescriptors[0],
+ le16_to_cpu(udev->config[0].desc.wTotalLength),
+ USB_DT_OTG, (void **) &desc) == 0)) {
+ /* shorter bLength of OTG 1.3 or earlier */
+ if (desc->bLength < 5) {
+ fsm->a_bus_req = 0;
+ fsm->tst_maint = 0;
+ otg_del_timer(fsm, A_TST_MAINT);
+ *fsm->host_req_flag = HOST_REQUEST_FLAG;
+ return;
+ }
+ }
+
*fsm->host_req_flag = 0;
/* Get host request flag from connected USB device */
retval = usb_control_msg(udev,
@@ -183,6 +216,11 @@ static void otg_hnp_polling_work(struct work_struct *work)
fsm->otg->host->b_hnp_enable = 1;
}
fsm->a_bus_req = 0;
+ if (fsm->tst_maint) {
+ fsm->tst_maint = 0;
+ fsm->otg_vbus_off = 0;
+ otg_del_timer(fsm, A_TST_MAINT);
+ }
} else if (state == OTG_STATE_B_HOST) {
fsm->b_bus_req = 0;
}
@@ -224,6 +262,10 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
otg_start_adp_sns(fsm);
otg_set_protocol(fsm, PROTO_UNDEF);
otg_add_timer(fsm, B_SE0_SRP);
+ if (fsm->otg_hnp_reqd) {
+ fsm->otg_hnp_reqd = 0;
+ fsm->b_bus_req = 0;
+ }
break;
case OTG_STATE_B_SRP_INIT:
otg_start_pulse(fsm);
@@ -236,6 +278,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
otg_loc_sof(fsm, 0);
otg_set_protocol(fsm, PROTO_GADGET);
otg_loc_conn(fsm, 1);
+ fsm->b_bus_req = 0;
break;
case OTG_STATE_B_WAIT_ACON:
otg_chrg_vbus(fsm, 0);
@@ -250,8 +293,6 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
otg_loc_conn(fsm, 0);
otg_loc_sof(fsm, 1);
otg_set_protocol(fsm, PROTO_HOST);
- usb_bus_start_enum(fsm->otg->host,
- fsm->otg->host->otg_port);
otg_start_hnp_polling(fsm);
break;
case OTG_STATE_A_IDLE:
@@ -406,8 +447,7 @@ int otg_statemachine(struct otg_fsm *fsm)
case OTG_STATE_A_HOST:
if (fsm->id || fsm->a_bus_drop)
otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);
- else if ((!fsm->a_bus_req || fsm->a_suspend_req_inf) &&
- fsm->otg->host->b_hnp_enable)
+ else if (!fsm->a_bus_req || fsm->a_suspend_req_inf)
otg_set_state(fsm, OTG_STATE_A_SUSPEND);
else if (!fsm->b_conn)
otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
@@ -415,9 +455,9 @@ int otg_statemachine(struct otg_fsm *fsm)
otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
break;
case OTG_STATE_A_SUSPEND:
- if (!fsm->b_conn && fsm->otg->host->b_hnp_enable)
+ if (!fsm->b_conn && fsm->a_set_b_hnp_en)
otg_set_state(fsm, OTG_STATE_A_PERIPHERAL);
- else if (!fsm->b_conn && !fsm->otg->host->b_hnp_enable)
+ else if (!fsm->b_conn && !fsm->a_set_b_hnp_en)
otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
else if (fsm->a_bus_req || fsm->b_bus_resume)
otg_set_state(fsm, OTG_STATE_A_HOST);
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index 98e39f91723a..a6cd44a711cf 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -63,7 +63,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
int i, size;
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
- (!hcd->self.controller->dma_mask &&
+ (!is_device_dma_capable(hcd->self.sysdev) &&
!(hcd->driver->flags & HCD_LOCAL_MEM)))
return 0;
@@ -72,7 +72,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
if (!size)
continue;
snprintf(name, sizeof(name), "buffer-%d", size);
- hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
+ hcd->pool[i] = dma_pool_create(name, hcd->self.sysdev,
size, size, 0);
if (!hcd->pool[i]) {
hcd_buffer_destroy(hcd);
@@ -127,7 +127,7 @@ void *hcd_buffer_alloc(
/* some USB hosts just use PIO */
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
- (!bus->controller->dma_mask &&
+ (!is_device_dma_capable(bus->sysdev) &&
!(hcd->driver->flags & HCD_LOCAL_MEM))) {
*dma = ~(dma_addr_t) 0;
return kmalloc(size, mem_flags);
@@ -137,7 +137,7 @@ void *hcd_buffer_alloc(
if (size <= pool_max[i])
return dma_pool_alloc(hcd->pool[i], mem_flags, dma);
}
- return dma_alloc_coherent(hcd->self.controller, size, dma, mem_flags);
+ return dma_alloc_coherent(hcd->self.sysdev, size, dma, mem_flags);
}
void hcd_buffer_free(
@@ -154,7 +154,7 @@ void hcd_buffer_free(
return;
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
- (!bus->controller->dma_mask &&
+ (!is_device_dma_capable(bus->sysdev) &&
!(hcd->driver->flags & HCD_LOCAL_MEM))) {
kfree(addr);
return;
@@ -166,5 +166,5 @@ void hcd_buffer_free(
return;
}
}
- dma_free_coherent(hcd->self.controller, size, addr, dma);
+ dma_free_coherent(hcd->self.sysdev, size, addr, dma);
}
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index bdb0d7a08ff9..0f7ef2b2e0a6 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1076,6 +1076,7 @@ static void usb_deregister_bus (struct usb_bus *bus)
static int register_root_hub(struct usb_hcd *hcd)
{
struct device *parent_dev = hcd->self.controller;
+ struct device *sysdev = hcd->self.sysdev;
struct usb_device *usb_dev = hcd->self.root_hub;
const int devnum = 1;
int retval;
@@ -1122,7 +1123,7 @@ static int register_root_hub(struct usb_hcd *hcd)
/* Did the HC die before the root hub was registered? */
if (HCD_DEAD(hcd))
usb_hc_died (hcd); /* This time clean up */
- usb_dev->dev.of_node = parent_dev->of_node;
+ usb_dev->dev.of_node = sysdev->of_node;
}
mutex_unlock(&usb_bus_idr_lock);
@@ -1435,7 +1436,7 @@ void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
if (IS_ENABLED(CONFIG_HAS_DMA) &&
(urb->transfer_flags & URB_SETUP_MAP_SINGLE))
- dma_unmap_single(hcd->self.controller,
+ dma_unmap_single(hcd->self.sysdev,
urb->setup_dma,
sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
@@ -1468,19 +1469,19 @@ void usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
if (IS_ENABLED(CONFIG_HAS_DMA) &&
(urb->transfer_flags & URB_DMA_MAP_SG))
- dma_unmap_sg(hcd->self.controller,
+ dma_unmap_sg(hcd->self.sysdev,
urb->sg,
urb->num_sgs,
dir);
else if (IS_ENABLED(CONFIG_HAS_DMA) &&
(urb->transfer_flags & URB_DMA_MAP_PAGE))
- dma_unmap_page(hcd->self.controller,
+ dma_unmap_page(hcd->self.sysdev,
urb->transfer_dma,
urb->transfer_buffer_length,
dir);
else if (IS_ENABLED(CONFIG_HAS_DMA) &&
(urb->transfer_flags & URB_DMA_MAP_SINGLE))
- dma_unmap_single(hcd->self.controller,
+ dma_unmap_single(hcd->self.sysdev,
urb->transfer_dma,
urb->transfer_buffer_length,
dir);
@@ -1523,11 +1524,11 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
return ret;
if (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
urb->setup_dma = dma_map_single(
- hcd->self.controller,
+ hcd->self.sysdev,
urb->setup_packet,
sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
- if (dma_mapping_error(hcd->self.controller,
+ if (dma_mapping_error(hcd->self.sysdev,
urb->setup_dma))
return -EAGAIN;
urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
@@ -1558,7 +1559,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
}
n = dma_map_sg(
- hcd->self.controller,
+ hcd->self.sysdev,
urb->sg,
urb->num_sgs,
dir);
@@ -1573,12 +1574,12 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
} else if (urb->sg) {
struct scatterlist *sg = urb->sg;
urb->transfer_dma = dma_map_page(
- hcd->self.controller,
+ hcd->self.sysdev,
sg_page(sg),
sg->offset,
urb->transfer_buffer_length,
dir);
- if (dma_mapping_error(hcd->self.controller,
+ if (dma_mapping_error(hcd->self.sysdev,
urb->transfer_dma))
ret = -EAGAIN;
else
@@ -1588,11 +1589,11 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
ret = -EAGAIN;
} else {
urb->transfer_dma = dma_map_single(
- hcd->self.controller,
+ hcd->self.sysdev,
urb->transfer_buffer,
urb->transfer_buffer_length,
dir);
- if (dma_mapping_error(hcd->self.controller,
+ if (dma_mapping_error(hcd->self.sysdev,
urb->transfer_dma))
ret = -EAGAIN;
else
@@ -2232,6 +2233,140 @@ int usb_hcd_get_frame_number (struct usb_device *udev)
}
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_HCD_TEST_MODE
+
+static void usb_ehset_completion(struct urb *urb)
+{
+ struct completion *done = urb->context;
+
+ complete(done);
+}
+/*
+ * Allocate and initialize a control URB. This request will be used by the
+ * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages
+ * of the GetDescriptor request are sent 15 seconds after the SETUP stage.
+ * Return NULL if failed.
+ */
+static struct urb *request_single_step_set_feature_urb(
+ struct usb_device *udev,
+ void *dr,
+ void *buf,
+ struct completion *done
+) {
+ struct urb *urb;
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ struct usb_host_endpoint *ep;
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return NULL;
+
+ urb->pipe = usb_rcvctrlpipe(udev, 0);
+ ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out)
+ [usb_pipeendpoint(urb->pipe)];
+ if (!ep) {
+ usb_free_urb(urb);
+ return NULL;
+ }
+
+ urb->ep = ep;
+ urb->dev = udev;
+ urb->setup_packet = (void *)dr;
+ urb->transfer_buffer = buf;
+ urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
+ urb->complete = usb_ehset_completion;
+ urb->status = -EINPROGRESS;
+ urb->actual_length = 0;
+ urb->transfer_flags = URB_DIR_IN;
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+ urb->setup_dma = dma_map_single(
+ hcd->self.sysdev,
+ urb->setup_packet,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ urb->transfer_dma = dma_map_single(
+ hcd->self.sysdev,
+ urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ DMA_FROM_DEVICE);
+ urb->context = done;
+ return urb;
+}
+
+int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
+{
+ int retval = -ENOMEM;
+ struct usb_ctrlrequest *dr;
+ struct urb *urb;
+ struct usb_device *udev;
+ struct usb_device_descriptor *buf;
+ DECLARE_COMPLETION_ONSTACK(done);
+
+ /* Obtain udev of the rhub's child port */
+ udev = usb_hub_find_child(hcd->self.root_hub, port);
+ if (!udev) {
+ dev_err(hcd->self.controller, "No device attached to the RootHub\n");
+ return -ENODEV;
+ }
+ buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!dr) {
+ kfree(buf);
+ return -ENOMEM;
+ }
+
+ /* Fill Setup packet for GetDescriptor */
+ dr->bRequestType = USB_DIR_IN;
+ dr->bRequest = USB_REQ_GET_DESCRIPTOR;
+ dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
+ dr->wIndex = 0;
+ dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
+ urb = request_single_step_set_feature_urb(udev, dr, buf, &done);
+ if (!urb)
+ goto cleanup;
+
+ /* Submit just the SETUP stage */
+ retval = hcd->driver->submit_single_step_set_feature(hcd, urb, 1);
+ if (retval)
+ goto out1;
+ if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
+ usb_kill_urb(urb);
+ retval = -ETIMEDOUT;
+ dev_err(hcd->self.controller,
+ "%s SETUP stage timed out on ep0\n", __func__);
+ goto out1;
+ }
+ msleep(15 * 1000);
+
+ /* Complete remaining DATA and STATUS stages using the same URB */
+ urb->status = -EINPROGRESS;
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+ retval = hcd->driver->submit_single_step_set_feature(hcd, urb, 0);
+ if (!retval && !wait_for_completion_timeout(&done,
+ msecs_to_jiffies(2000))) {
+ usb_kill_urb(urb);
+ retval = -ETIMEDOUT;
+ dev_err(hcd->self.controller,
+ "%s IN stage timed out on ep0\n", __func__);
+ }
+out1:
+ usb_free_urb(urb);
+cleanup:
+ kfree(dr);
+ kfree(buf);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(ehset_single_step_set_feature);
+#endif /* CONFIG_USB_HCD_TEST_MODE */
+
+/*-------------------------------------------------------------------------*/
#ifdef CONFIG_PM
@@ -2501,24 +2636,8 @@ static void init_giveback_urb_bh(struct giveback_urb_bh *bh)
tasklet_init(&bh->bh, usb_giveback_urb_bh, (unsigned long)bh);
}
-/**
- * usb_create_shared_hcd - create and initialize an HCD structure
- * @driver: HC driver that will use this hcd
- * @dev: device for this HC, stored in hcd->self.controller
- * @bus_name: value to store in hcd->self.bus_name
- * @primary_hcd: a pointer to the usb_hcd structure that is sharing the
- * PCI device. Only allocate certain resources for the primary HCD
- * Context: !in_interrupt()
- *
- * Allocate a struct usb_hcd, with extra space at the end for the
- * HC driver's private data. Initialize the generic members of the
- * hcd structure.
- *
- * Return: On success, a pointer to the created and initialized HCD structure.
- * On failure (e.g. if memory is unavailable), %NULL.
- */
-struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
- struct device *dev, const char *bus_name,
+struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver,
+ struct device *sysdev, struct device *dev, const char *bus_name,
struct usb_hcd *primary_hcd)
{
struct usb_hcd *hcd;
@@ -2560,8 +2679,9 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
usb_bus_init(&hcd->self);
hcd->self.controller = dev;
+ hcd->self.sysdev = sysdev;
hcd->self.bus_name = bus_name;
- hcd->self.uses_dma = (dev->dma_mask != NULL);
+ hcd->self.uses_dma = (sysdev->dma_mask != NULL);
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;
@@ -2576,6 +2696,30 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
"USB Host Controller";
return hcd;
}
+EXPORT_SYMBOL_GPL(__usb_create_hcd);
+
+/**
+ * usb_create_shared_hcd - create and initialize an HCD structure
+ * @driver: HC driver that will use this hcd
+ * @dev: device for this HC, stored in hcd->self.controller
+ * @bus_name: value to store in hcd->self.bus_name
+ * @primary_hcd: a pointer to the usb_hcd structure that is sharing the
+ * PCI device. Only allocate certain resources for the primary HCD
+ * Context: !in_interrupt()
+ *
+ * Allocate a struct usb_hcd, with extra space at the end for the
+ * HC driver's private data. Initialize the generic members of the
+ * hcd structure.
+ *
+ * Return: On success, a pointer to the created and initialized HCD structure.
+ * On failure (e.g. if memory is unavailable), %NULL.
+ */
+struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
+ struct device *dev, const char *bus_name,
+ struct usb_hcd *primary_hcd)
+{
+ return __usb_create_hcd(driver, dev, dev, bus_name, primary_hcd);
+}
EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
/**
@@ -2595,7 +2739,7 @@ EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
struct device *dev, const char *bus_name)
{
- return usb_create_shared_hcd(driver, dev, bus_name, NULL);
+ return __usb_create_hcd(driver, dev, dev, bus_name, NULL);
}
EXPORT_SYMBOL_GPL(usb_create_hcd);
@@ -2722,7 +2866,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
struct usb_device *rhdev;
if (IS_ENABLED(CONFIG_USB_PHY) && !hcd->usb_phy) {
- struct usb_phy *phy = usb_get_phy_dev(hcd->self.controller, 0);
+ struct usb_phy *phy = usb_get_phy_dev(hcd->self.sysdev, 0);
if (IS_ERR(phy)) {
retval = PTR_ERR(phy);
@@ -2740,7 +2884,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
}
if (IS_ENABLED(CONFIG_GENERIC_PHY) && !hcd->phy) {
- struct phy *phy = phy_get(hcd->self.controller, "usb");
+ struct phy *phy = phy_get(hcd->self.sysdev, "usb");
if (IS_ERR(phy)) {
retval = PTR_ERR(phy);
@@ -2788,7 +2932,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
*/
retval = hcd_buffer_create(hcd);
if (retval != 0) {
- dev_dbg(hcd->self.controller, "pool alloc failed\n");
+ dev_dbg(hcd->self.sysdev, "pool alloc failed\n");
goto err_create_buf;
}
@@ -2798,7 +2942,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
rhdev = usb_alloc_dev(NULL, &hcd->self, 0);
if (rhdev == NULL) {
- dev_err(hcd->self.controller, "unable to allocate root hub\n");
+ dev_err(hcd->self.sysdev, "unable to allocate root hub\n");
retval = -ENOMEM;
goto err_allocate_root_hub;
}
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 7aee55244b4a..6436ca2f5d3e 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -21,6 +21,7 @@
#include <linux/usbdevice_fs.h>
#include <linux/usb/hcd.h>
#include <linux/usb/otg.h>
+#include <linux/usb/otg-fsm.h>
#include <linux/usb/quirks.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
@@ -1113,6 +1114,10 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
need_debounce_delay = true;
usb_clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_CONNECTION);
+#ifdef CONFIG_USB_OTG
+ if (hdev->bus->is_b_host)
+ usb_bus_start_enum(hdev->bus, port1);
+#endif
}
if (portchange & USB_PORT_STAT_C_ENABLE) {
need_debounce_delay = true;
@@ -2207,9 +2212,9 @@ static inline void announce_device(struct usb_device *udev) { }
*/
static int usb_enumerate_device_otg(struct usb_device *udev)
{
+#ifdef CONFIG_USB_OTG
int err = 0;
-#ifdef CONFIG_USB_OTG
/*
* OTG-aware devices on OTG-capable root hubs may be able to use SRP,
* to wake us after we've powered off VBUS; and HNP, switching roles
@@ -2250,6 +2255,12 @@ static int usb_enumerate_device_otg(struct usb_device *udev)
err);
bus->b_hnp_enable = 0;
}
+
+ if (bus->otg_fsm) {
+ bus->otg_fsm->b_hnp_enable = 1;
+ if (bus->b_hnp_enable)
+ bus->otg_fsm->a_set_b_hnp_en = 1;
+ }
} else if (desc->bLength == sizeof
(struct usb_otg_descriptor)) {
/* Set a_alt_hnp_support for legacy otg device */
@@ -2266,7 +2277,7 @@ static int usb_enumerate_device_otg(struct usb_device *udev)
}
}
#endif
- return err;
+ return 0;
}
@@ -2288,6 +2299,7 @@ static int usb_enumerate_device(struct usb_device *udev)
{
int err;
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ struct otg_fsm *fsm = udev->bus->otg_fsm;
if (udev->config == NULL) {
err = usb_get_configuration(udev);
@@ -2319,8 +2331,10 @@ static int usb_enumerate_device(struct usb_device *udev)
err = usb_port_suspend(udev, PMSG_AUTO_SUSPEND);
if (err < 0)
dev_dbg(&udev->dev, "HNP fail, %d\n", err);
+ return -ENOTSUPP;
+ } else if (!fsm || !fsm->b_hnp_enable || !fsm->hnp_polling) {
+ return -ENOTSUPP;
}
- return -ENOTSUPP;
}
usb_detect_interface_quirks(udev);
@@ -4364,6 +4378,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
enum usb_device_speed oldspeed = udev->speed;
const char *speed;
int devnum = udev->devnum;
+ const char *driver_name;
/* root hub ports have a slightly longer reset period
* (from USB 2.0 spec, section 7.1.7.5)
@@ -4431,11 +4446,23 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
else
speed = usb_speed_string(udev->speed);
+ /*
+ * The controller driver may be NULL if the controller device
+ * is the middle device between platform device and roothub.
+ * This middle device may not need a device driver due to
+ * all hardware control can be at platform device driver, this
+ * platform device is usually a dual-role USB controller device.
+ */
+ if (udev->bus->controller->driver)
+ driver_name = udev->bus->controller->driver->name;
+ else
+ driver_name = udev->bus->sysdev->driver->name;
+
if (udev->speed < USB_SPEED_SUPER)
dev_info(&udev->dev,
"%s %s USB device number %d using %s\n",
(udev->config) ? "reset" : "new", speed,
- devnum, udev->bus->controller->driver->name);
+ devnum, driver_name);
/* Set up TT records, if needed */
if (hdev->tt) {
@@ -4537,7 +4564,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
}
if (r) {
if (r != -ENODEV)
- dev_err(&udev->dev, "device descriptor read/64, error %d\n",
+ dev_err(&udev->dev,
+ "device no response, device descriptor read/64, error %d\n",
r);
retval = -EMSGSIZE;
continue;
@@ -4569,7 +4597,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
"%s SuperSpeed%s USB device number %d using %s\n",
(udev->config) ? "reset" : "new",
(udev->speed == USB_SPEED_SUPER_PLUS) ? "Plus" : "",
- devnum, udev->bus->controller->driver->name);
+ devnum, driver_name);
}
/* cope with hardware quirkiness:
diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
index 085049d37d7a..68b4f7e80b47 100644
--- a/drivers/usb/core/otg_whitelist.h
+++ b/drivers/usb/core/otg_whitelist.h
@@ -17,35 +17,64 @@
*/
static struct usb_device_id whitelist_table[] = {
-
-/* hubs are optional in OTG, but very handy ... */
-{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
-{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), },
-
-#ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */
-/* FIXME actually, printers are NOT supposed to use device classes;
- * they're supposed to use interface classes...
- */
-{ USB_DEVICE_INFO(7, 1, 1) },
-{ USB_DEVICE_INFO(7, 1, 2) },
-{ USB_DEVICE_INFO(7, 1, 3) },
+/* Add FSL i.mx whitelist, the default list is for USB Compliance Test */
+#if defined(CONFIG_USB_EHSET_TEST_FIXTURE) \
+ || defined(CONFIG_USB_EHSET_TEST_FIXTURE_MODULE)
+#define TEST_SE0_NAK_PID 0x0101
+#define TEST_J_PID 0x0102
+#define TEST_K_PID 0x0103
+#define TEST_PACKET_PID 0x0104
+#define TEST_HS_HOST_PORT_SUSPEND_RESUME 0x0106
+#define TEST_SINGLE_STEP_GET_DEV_DESC 0x0107
+#define TEST_SINGLE_STEP_SET_FEATURE 0x0108
+#define TEST_OTG_TEST_DEVICE_SUPPORT 0x0200
+{ USB_DEVICE(0x1a0a, TEST_SE0_NAK_PID) },
+{ USB_DEVICE(0x1a0a, TEST_J_PID) },
+{ USB_DEVICE(0x1a0a, TEST_K_PID) },
+{ USB_DEVICE(0x1a0a, TEST_PACKET_PID) },
+{ USB_DEVICE(0x1a0a, TEST_HS_HOST_PORT_SUSPEND_RESUME) },
+{ USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_GET_DEV_DESC) },
+{ USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_SET_FEATURE) },
+{ USB_DEVICE(0x1a0a, TEST_OTG_TEST_DEVICE_SUPPORT) },
#endif
-#ifdef CONFIG_USB_NET_CDCETHER
-/* Linux-USB CDC Ethernet gadget */
-{ USB_DEVICE(0x0525, 0xa4a1), },
-/* Linux-USB CDC Ethernet + RNDIS gadget */
-{ USB_DEVICE(0x0525, 0xa4a2), },
-#endif
+#define USB_INTERFACE_CLASS_INFO(cl) \
+ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, \
+ .bInterfaceClass = (cl)
-#if IS_ENABLED(CONFIG_USB_TEST)
-/* gadget zero, for testing */
-{ USB_DEVICE(0x0525, 0xa4a0), },
+{USB_INTERFACE_CLASS_INFO(USB_CLASS_HUB) },
+#if defined(CONFIG_USB_STORAGE) || defined(CONFIG_USB_STORAGE_MODULE)
+{USB_INTERFACE_CLASS_INFO(USB_CLASS_MASS_STORAGE) },
+#endif
+#if defined(CONFIG_USB_HID) || defined(CONFIG_USB_HID_MODULE)
+{USB_INTERFACE_CLASS_INFO(USB_CLASS_HID) },
#endif
{ } /* Terminating entry */
};
+static bool match_int_class(struct usb_device_id *id, struct usb_device *udev)
+{
+ struct usb_host_config *c;
+ int num_configs, i;
+
+ /* Copy the code from generic.c */
+ c = udev->config;
+ num_configs = udev->descriptor.bNumConfigurations;
+ for (i = 0; i < num_configs; (i++, c++)) {
+ struct usb_interface_descriptor *desc = NULL;
+
+ /* It's possible that a config has no interfaces! */
+ if (c->desc.bNumInterfaces > 0)
+ desc = &c->intf_cache[0]->altsetting->desc;
+
+ if (desc && (desc->bInterfaceClass == id->bInterfaceClass))
+ return true;
+ }
+
+ return false;
+}
+
static int is_targeted(struct usb_device *dev)
{
struct usb_device_id *id = whitelist_table;
@@ -60,6 +89,19 @@ static int is_targeted(struct usb_device *dev)
le16_to_cpu(dev->descriptor.idProduct) == 0x0200))
return 1;
+ /* Unknown Device Not Supporting HNP */
+ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
+ le16_to_cpu(dev->descriptor.idProduct) == 0x0201)) {
+ dev_warn(&dev->dev, "Unsupported Device\n");
+ return 0;
+ }
+ /* Unknown Device Supporting HNP */
+ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
+ le16_to_cpu(dev->descriptor.idProduct) == 0x0202)) {
+ dev_warn(&dev->dev, "Device no Responding\n");
+ return 0;
+ }
+
/* NOTE: can't use usb_match_id() since interface caches
* aren't set up yet. this is cut/paste from that code.
*/
@@ -94,6 +136,10 @@ static int is_targeted(struct usb_device *dev)
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
continue;
+ if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
+ (!match_int_class(id, dev)))
+ continue;
+
return 1;
}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index eaf1c3b06f02..e1ab778e774a 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -452,9 +452,9 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
* Note: calling dma_set_mask() on a USB device would set the
* mask for the entire HCD, so don't do that.
*/
- dev->dev.dma_mask = bus->controller->dma_mask;
- dev->dev.dma_pfn_offset = bus->controller->dma_pfn_offset;
- set_dev_node(&dev->dev, dev_to_node(bus->controller));
+ dev->dev.dma_mask = bus->sysdev->dma_mask;
+ dev->dev.dma_pfn_offset = bus->sysdev->dma_pfn_offset;
+ set_dev_node(&dev->dev, dev_to_node(bus->sysdev));
dev->state = USB_STATE_ATTACHED;
dev->lpm_disable_count = 1;
atomic_set(&dev->urbnum, 0);
@@ -802,7 +802,7 @@ struct urb *usb_buffer_map(struct urb *urb)
if (!urb
|| !urb->dev
|| !(bus = urb->dev->bus)
- || !(controller = bus->controller))
+ || !(controller = bus->sysdev))
return NULL;
if (controller->dma_mask) {
@@ -840,7 +840,7 @@ void usb_buffer_dmasync(struct urb *urb)
|| !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|| !urb->dev
|| !(bus = urb->dev->bus)
- || !(controller = bus->controller))
+ || !(controller = bus->sysdev))
return;
if (controller->dma_mask) {
@@ -874,7 +874,7 @@ void usb_buffer_unmap(struct urb *urb)
|| !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|| !urb->dev
|| !(bus = urb->dev->bus)
- || !(controller = bus->controller))
+ || !(controller = bus->sysdev))
return;
if (controller->dma_mask) {
@@ -924,7 +924,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
if (!dev
|| !(bus = dev->bus)
- || !(controller = bus->controller)
+ || !(controller = bus->sysdev)
|| !controller->dma_mask)
return -EINVAL;
@@ -960,7 +960,7 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
if (!dev
|| !(bus = dev->bus)
- || !(controller = bus->controller)
+ || !(controller = bus->sysdev)
|| !controller->dma_mask)
return;
@@ -988,7 +988,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
if (!dev
|| !(bus = dev->bus)
- || !(controller = bus->controller)
+ || !(controller = bus->sysdev)
|| !controller->dma_mask)
return;
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index b97cde76914d..3a0481b93118 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -41,6 +41,7 @@ config USB_DWC3_GADGET
config USB_DWC3_DUAL_ROLE
bool "Dual Role mode"
depends on ((USB=y || USB=USB_DWC3) && (USB_GADGET=y || USB_GADGET=USB_DWC3))
+ depends on (EXTCON=y || EXTCON=USB_DWC3)
help
This is the default mode of working of DWC3 controller where
both host and gadget features are enabled.
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 22420e17d68b..e2a3b265b066 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -13,6 +13,10 @@ ifneq ($(filter y,$(CONFIG_USB_DWC3_GADGET) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
dwc3-y += gadget.o ep0.o
endif
+ifneq ($(CONFIG_USB_DWC3_DUAL_ROLE),)
+ dwc3-y += drd.o
+endif
+
ifneq ($(CONFIG_USB_DWC3_ULPI),)
dwc3-y += ulpi.o
endif
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 53b26e978d90..f4f2a1337dd4 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -100,7 +100,10 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
return 0;
}
-void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
+static void dwc3_event_buffers_cleanup(struct dwc3 *dwc);
+static int dwc3_event_buffers_setup(struct dwc3 *dwc);
+
+static void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
{
u32 reg;
@@ -110,6 +113,93 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
}
+static void __dwc3_set_mode(struct work_struct *work)
+{
+ struct dwc3 *dwc = work_to_dwc(work);
+ unsigned long flags;
+ int ret;
+
+ if (!dwc->desired_dr_role)
+ return;
+
+ if (dwc->desired_dr_role == dwc->current_dr_role)
+ return;
+
+ if (dwc->dr_mode != USB_DR_MODE_OTG)
+ return;
+
+ switch (dwc->current_dr_role) {
+ case DWC3_GCTL_PRTCAP_HOST:
+ dwc3_host_exit(dwc);
+ break;
+ case DWC3_GCTL_PRTCAP_DEVICE:
+ dwc3_gadget_exit(dwc);
+ dwc3_event_buffers_cleanup(dwc);
+ break;
+ default:
+ break;
+ }
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ dwc3_set_prtcap(dwc, dwc->desired_dr_role);
+
+ dwc->current_dr_role = dwc->desired_dr_role;
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ switch (dwc->desired_dr_role) {
+ case DWC3_GCTL_PRTCAP_HOST:
+ ret = dwc3_host_init(dwc);
+ if (ret)
+ dev_err(dwc->dev, "failed to initialize host\n");
+ break;
+ case DWC3_GCTL_PRTCAP_DEVICE:
+ dwc3_event_buffers_setup(dwc);
+ ret = dwc3_gadget_init(dwc);
+ if (ret)
+ dev_err(dwc->dev, "failed to initialize peripheral\n");
+ break;
+ default:
+ break;
+ }
+}
+
+void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc->desired_dr_role = mode;
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ queue_work(system_freezable_wq, &dwc->drd_work);
+}
+
+static int dwc3_set_suspend_clk(struct dwc3 *dwc)
+{
+ u32 reg, scale;
+
+ /*
+ * DWC3_GCTL.PWRDNSCALE: The USB3 suspend_clk input replaces
+ * pipe3_rx_pclk as a clock source to a small part of the USB3
+ * core that operates when the SS PHY is in its lowest power
+ * (P3) state, and therefore does not provide a clock.
+ * The Power Down Scale field specifies how many suspend_clk
+ * periods fit into a 16 kHz clock period. When performing the
+ * division, round up the remainder.
+ */
+ if (!device_property_read_u32(dwc->dev, "snps,power-down-scale",
+ &scale)) {
+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+ reg &= ~(DWC3_GCTL_PWRDNSCALE_MASK);
+ reg |= DWC3_GCTL_PWRDNSCALE(scale);
+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ }
+
+ return 0;
+}
+
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
{
struct dwc3 *dwc = dep->dwc;
@@ -663,6 +753,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (ret)
goto err0;
+ /* Set suspend_clk */
+ dwc3_set_suspend_clk(dwc);
+
ret = dwc3_phy_setup(dwc);
if (ret)
goto err0;
@@ -760,21 +853,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
goto err4;
}
- switch (dwc->dr_mode) {
- case USB_DR_MODE_PERIPHERAL:
- dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
- break;
- case USB_DR_MODE_HOST:
- dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
- break;
- case USB_DR_MODE_OTG:
- dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
- break;
- default:
- dev_warn(dwc->dev, "Unsupported mode %d\n", dwc->dr_mode);
- break;
- }
-
/*
* ENDXFER polling is available on version 3.10a and later of
* the DWC_usb3 controller. It is NOT available in the
@@ -882,6 +960,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
+ dwc->current_dr_role = DWC3_GCTL_PRTCAP_DEVICE;
+ dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret) {
if (ret != -EPROBE_DEFER)
@@ -890,6 +970,8 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
}
break;
case USB_DR_MODE_HOST:
+ dwc->current_dr_role = DWC3_GCTL_PRTCAP_HOST;
+ dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
ret = dwc3_host_init(dwc);
if (ret) {
if (ret != -EPROBE_DEFER)
@@ -898,17 +980,11 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
}
break;
case USB_DR_MODE_OTG:
- ret = dwc3_host_init(dwc);
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "failed to initialize host\n");
- return ret;
- }
-
- ret = dwc3_gadget_init(dwc);
+ INIT_WORK(&dwc->drd_work, __dwc3_set_mode);
+ ret = dwc3_drd_init(dwc);
if (ret) {
if (ret != -EPROBE_DEFER)
- dev_err(dev, "failed to initialize gadget\n");
+ dev_err(dev, "failed to initialize dual-role\n");
return ret;
}
break;
@@ -930,8 +1006,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
dwc3_host_exit(dwc);
break;
case USB_DR_MODE_OTG:
- dwc3_host_exit(dwc);
- dwc3_gadget_exit(dwc);
+ dwc3_drd_exit(dwc);
break;
default:
/* do nothing */
@@ -1061,6 +1136,19 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->hird_threshold = hird_threshold
| (dwc->is_utmi_l1_suspend << 4);
+ if (dwc->dr_mode == USB_DR_MODE_OTG) {
+ dwc->otg_caps.otg_rev = 0x0300;
+ dwc->otg_caps.hnp_support = true;
+ dwc->otg_caps.srp_support = true;
+ dwc->otg_caps.adp_support = true;
+
+ /* Update otg capabilities by DT properties */
+ ret = of_usb_update_otg_caps(dev->of_node,
+ &dwc->otg_caps);
+ if (ret)
+ goto err0;
+ }
+
platform_set_drvdata(pdev, dwc);
dwc3_cache_hwparams(dwc);
@@ -1205,21 +1293,19 @@ static int dwc3_suspend_common(struct dwc3 *dwc)
{
unsigned long flags;
- switch (dwc->dr_mode) {
- case USB_DR_MODE_PERIPHERAL:
- case USB_DR_MODE_OTG:
+ switch (dwc->current_dr_role) {
+ case DWC3_GCTL_PRTCAP_DEVICE:
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_suspend(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
+ dwc3_core_exit(dwc);
break;
- case USB_DR_MODE_HOST:
+ case DWC3_GCTL_PRTCAP_HOST:
default:
/* do nothing */
break;
}
- dwc3_core_exit(dwc);
-
return 0;
}
@@ -1228,18 +1314,17 @@ static int dwc3_resume_common(struct dwc3 *dwc)
unsigned long flags;
int ret;
- ret = dwc3_core_init(dwc);
- if (ret)
- return ret;
+ switch (dwc->current_dr_role) {
+ case DWC3_GCTL_PRTCAP_DEVICE:
+ ret = dwc3_core_init(dwc);
+ if (ret)
+ return ret;
- switch (dwc->dr_mode) {
- case USB_DR_MODE_PERIPHERAL:
- case USB_DR_MODE_OTG:
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_resume(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
- /* FALLTHROUGH */
- case USB_DR_MODE_HOST:
+ break;
+ case DWC3_GCTL_PRTCAP_HOST:
default:
/* do nothing */
break;
@@ -1250,7 +1335,7 @@ static int dwc3_resume_common(struct dwc3 *dwc)
static int dwc3_runtime_checks(struct dwc3 *dwc)
{
- switch (dwc->dr_mode) {
+ switch (dwc->current_dr_role) {
case USB_DR_MODE_PERIPHERAL:
case USB_DR_MODE_OTG:
if (dwc->connected)
@@ -1293,12 +1378,11 @@ static int dwc3_runtime_resume(struct device *dev)
if (ret)
return ret;
- switch (dwc->dr_mode) {
- case USB_DR_MODE_PERIPHERAL:
- case USB_DR_MODE_OTG:
+ switch (dwc->current_dr_role) {
+ case DWC3_GCTL_PRTCAP_DEVICE:
dwc3_gadget_process_pending_events(dwc);
break;
- case USB_DR_MODE_HOST:
+ case DWC3_GCTL_PRTCAP_HOST:
default:
/* do nothing */
break;
@@ -1314,13 +1398,12 @@ static int dwc3_runtime_idle(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
- switch (dwc->dr_mode) {
- case USB_DR_MODE_PERIPHERAL:
- case USB_DR_MODE_OTG:
+ switch (dwc->current_dr_role) {
+ case DWC3_GCTL_PRTCAP_DEVICE:
if (dwc3_runtime_checks(dwc))
return -EBUSY;
break;
- case USB_DR_MODE_HOST:
+ case DWC3_GCTL_PRTCAP_HOST:
default:
/* do nothing */
break;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index affb3d757310..c621a0fbc9a7 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -26,6 +26,7 @@
#include <linux/dma-mapping.h>
#include <linux/mm.h>
#include <linux/debugfs.h>
+#include <linux/wait.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -176,6 +177,7 @@
/* Global Configuration Register */
#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19)
+#define DWC3_GCTL_PWRDNSCALE_MASK DWC3_GCTL_PWRDNSCALE(0x1fff)
#define DWC3_GCTL_U2RSTECN (1 << 16)
#define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6)
#define DWC3_GCTL_CLK_BUS (0)
@@ -451,6 +453,8 @@
#define DWC3_DEPCMD_SETTRANSFRESOURCE (0x02 << 0)
#define DWC3_DEPCMD_SETEPCONFIG (0x01 << 0)
+#define DWC3_DEPCMD_CMD(x) ((x) & 0xf)
+
/* The EP number goes 0..31 so ep0 is always out and ep1 is always in */
#define DWC3_DALEPENA_EP(n) (1 << n)
@@ -500,6 +504,7 @@ struct dwc3_event_buffer {
* @endpoint: usb endpoint
* @pending_list: list of pending requests for this endpoint
* @started_list: list of started requests on this endpoint
+ * @wait_end_transfer: wait_queue_head_t for waiting on End Transfer complete
* @lock: spinlock for endpoint request queue traversal
* @regs: pointer to first endpoint register
* @trb_pool: array of transaction buffers
@@ -525,6 +530,8 @@ struct dwc3_ep {
struct list_head pending_list;
struct list_head started_list;
+ wait_queue_head_t wait_end_transfer;
+
spinlock_t lock;
void __iomem *regs;
@@ -541,6 +548,8 @@ struct dwc3_ep {
#define DWC3_EP_BUSY (1 << 4)
#define DWC3_EP_PENDING_REQUEST (1 << 5)
#define DWC3_EP_MISSED_ISOC (1 << 6)
+#define DWC3_EP_END_TRANSFER_PENDING (1 << 7)
+#define DWC3_EP_TRANSFER_STARTED (1 << 8)
/* This last one is specific to EP0 */
#define DWC3_EP0_DIR_IN (1 << 31)
@@ -740,6 +749,7 @@ struct dwc3_scratchpad_array {
/**
* struct dwc3 - representation of our controller
* @ctrl_req: usb control request which is used for ep0
+ * @drd_work - workqueue used for role swapping
* @ep0_trb: trb which is used for the ctrl_req
* @ep0_bounce: bounce buffer for ep0
* @zlp_buf: used when request->zero is set
@@ -764,6 +774,10 @@ struct dwc3_scratchpad_array {
* @maximum_speed: maximum speed requested (mainly for testing purposes)
* @revision: revision register contents
* @dr_mode: requested mode of operation
+ * @current_dr_role: current role of operation when in dual-role mode
+ * @desired_dr_role: desired role of operation when in dual-role mode
+ * @edev: extcon handle
+ * @edev_nb: extcon notifier
* @hsphy_mode: UTMI phy mode, one of following:
* - USBPHY_INTERFACE_MODE_UTMI
* - USBPHY_INTERFACE_MODE_UTMIW
@@ -834,9 +848,11 @@ struct dwc3_scratchpad_array {
* 1 - -3.5dB de-emphasis
* 2 - No de-emphasis
* 3 - Reserved
+ * @otg_caps: the OTG capabilities from hardware point
*/
struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
+ struct work_struct drd_work;
struct dwc3_trb *ep0_trb;
void *ep0_bounce;
void *zlp_buf;
@@ -874,6 +890,10 @@ struct dwc3 {
size_t regs_size;
enum usb_dr_mode dr_mode;
+ u32 current_dr_role;
+ u32 desired_dr_role;
+ struct extcon_dev *edev;
+ struct notifier_block edev_nb;
enum usb_phy_interface hsphy_mode;
u32 fladj;
@@ -979,9 +999,10 @@ struct dwc3 {
unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2;
+ struct usb_otg_caps otg_caps;
};
-/* -------------------------------------------------------------------------- */
+#define work_to_dwc(w) (container_of((w), struct dwc3, drd_work))
/* -------------------------------------------------------------------------- */
@@ -1046,6 +1067,9 @@ struct dwc3_event_depevt {
#define DEPEVT_TRANSFER_BUS_EXPIRY 2
u32 parameters:16;
+
+/* For Command Complete Events */
+#define DEPEVT_PARAMETER_CMD(n) (((n) & (0xf << 8)) >> 8)
} __packed;
/**
@@ -1180,6 +1204,16 @@ static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
{ return 0; }
#endif
+#if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
+int dwc3_drd_init(struct dwc3 *dwc);
+void dwc3_drd_exit(struct dwc3 *dwc);
+#else
+static inline int dwc3_drd_init(struct dwc3 *dwc)
+{ return 0; }
+static inline void dwc3_drd_exit(struct dwc3 *dwc)
+{ }
+#endif
+
/* power management interface */
#if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
int dwc3_gadget_suspend(struct dwc3 *dwc);
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index 31926dda43c9..ef7dccb55c47 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -319,7 +319,6 @@ static ssize_t dwc3_mode_write(struct file *file,
{
struct seq_file *s = file->private_data;
struct dwc3 *dwc = s->private;
- unsigned long flags;
u32 mode = 0;
char buf[32];
@@ -327,19 +326,16 @@ static ssize_t dwc3_mode_write(struct file *file,
return -EFAULT;
if (!strncmp(buf, "host", 4))
- mode |= DWC3_GCTL_PRTCAP_HOST;
+ mode = DWC3_GCTL_PRTCAP_HOST;
if (!strncmp(buf, "device", 6))
- mode |= DWC3_GCTL_PRTCAP_DEVICE;
+ mode = DWC3_GCTL_PRTCAP_DEVICE;
if (!strncmp(buf, "otg", 3))
- mode |= DWC3_GCTL_PRTCAP_OTG;
+ mode = DWC3_GCTL_PRTCAP_OTG;
+
+ dwc3_set_mode(dwc, mode);
- if (mode) {
- spin_lock_irqsave(&dwc->lock, flags);
- dwc3_set_mode(dwc, mode);
- spin_unlock_irqrestore(&dwc->lock, flags);
- }
return count;
}
diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c
new file mode 100644
index 000000000000..2765c51c7ef5
--- /dev/null
+++ b/drivers/usb/dwc3/drd.c
@@ -0,0 +1,85 @@
+/**
+ * drd.c - DesignWare USB3 DRD Controller Dual-role support
+ *
+ * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Roger Quadros <rogerq@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/extcon.h>
+
+#include "debug.h"
+#include "core.h"
+#include "gadget.h"
+
+static void dwc3_drd_update(struct dwc3 *dwc)
+{
+ int id;
+
+ id = extcon_get_state(dwc->edev, EXTCON_USB_HOST);
+ if (id < 0)
+ id = 0;
+
+ dwc3_set_mode(dwc, id ?
+ DWC3_GCTL_PRTCAP_HOST :
+ DWC3_GCTL_PRTCAP_DEVICE);
+}
+
+static int dwc3_drd_notifier(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb);
+
+ dwc3_set_mode(dwc, event ?
+ DWC3_GCTL_PRTCAP_HOST :
+ DWC3_GCTL_PRTCAP_DEVICE);
+
+ return NOTIFY_DONE;
+}
+
+int dwc3_drd_init(struct dwc3 *dwc)
+{
+ int ret;
+
+ if (dwc->dev->of_node) {
+ if (of_property_read_bool(dwc->dev->of_node, "extcon"))
+ dwc->edev = extcon_get_edev_by_phandle(dwc->dev, 0);
+
+ if (IS_ERR(dwc->edev))
+ return PTR_ERR(dwc->edev);
+
+ dwc->edev_nb.notifier_call = dwc3_drd_notifier;
+ ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
+ &dwc->edev_nb);
+ if (ret < 0) {
+ dev_err(dwc->dev, "couldn't register cable notifier\n");
+ return ret;
+ }
+ }
+
+ dwc3_drd_update(dwc);
+
+ return 0;
+}
+
+void dwc3_drd_exit(struct dwc3 *dwc)
+{
+ extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
+ &dwc->edev_nb);
+
+ dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+ flush_work(&dwc->drd_work);
+ dwc3_gadget_exit(dwc);
+}
diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c
index 58526932d2b6..29433c80be10 100644
--- a/drivers/usb/dwc3/dwc3-of-simple.c
+++ b/drivers/usb/dwc3/dwc3-of-simple.c
@@ -180,6 +180,7 @@ static const struct of_device_id of_dwc3_simple_match[] = {
{ .compatible = "rockchip,rk3399-dwc3" },
{ .compatible = "xlnx,zynqmp-dwc3" },
{ .compatible = "cavium,octeon-7130-usb-uctl" },
+ { .compatible = "fsl, imx8mq-dwc3" },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_dwc3_simple_match);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 26efe8c7535f..31a07649d99f 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -26,6 +26,7 @@
#include <linux/io.h>
#include <linux/list.h>
#include <linux/dma-mapping.h>
+#include <linux/busfreq-imx.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -247,7 +248,11 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
struct dwc3_gadget_ep_cmd_params *params)
{
struct dwc3 *dwc = dep->dwc;
- u32 timeout = 1000;
+ /*
+ * FIXME need check why 500 times check
+ * is not enough.
+ */
+ u32 timeout = 20000;
u32 reg;
int cmd_status = 0;
@@ -271,7 +276,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
}
}
- if (cmd == DWC3_DEPCMD_STARTTRANSFER) {
+ if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) {
int needs_wakeup;
needs_wakeup = (dwc->link_state == DWC3_LINK_STATE_U1 ||
@@ -331,6 +336,20 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
trace_dwc3_gadget_ep_cmd(dep, cmd, params, cmd_status);
+ if (ret == 0) {
+ switch (DWC3_DEPCMD_CMD(cmd)) {
+ case DWC3_DEPCMD_STARTTRANSFER:
+ dep->flags |= DWC3_EP_TRANSFER_STARTED;
+ break;
+ case DWC3_DEPCMD_ENDTRANSFER:
+ dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
+ break;
+ default:
+ /* nothing */
+ break;
+ }
+ }
+
if (unlikely(susphy)) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
@@ -584,11 +603,14 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
dep->comp_desc = comp_desc;
dep->type = usb_endpoint_type(desc);
dep->flags |= DWC3_EP_ENABLED;
+ dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING;
reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
reg |= DWC3_DALEPENA_EP(dep->number);
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
+ init_waitqueue_head(&dep->wait_end_transfer);
+
if (usb_endpoint_xfer_control(desc))
return 0;
@@ -661,7 +683,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
dep->endpoint.desc = NULL;
dep->comp_desc = NULL;
dep->type = 0;
- dep->flags = 0;
+ dep->flags &= DWC3_EP_END_TRANSFER_PENDING;
return 0;
}
@@ -1060,6 +1082,14 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
return 0;
}
+static int __dwc3_gadget_get_frame(struct dwc3 *dwc)
+{
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+ return DWC3_DSTS_SOFFN(reg);
+}
+
static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
struct dwc3_ep *dep, u32 cur_uf)
{
@@ -1137,12 +1167,27 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
* errors which will force us issue EndTransfer command.
*/
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
- if ((dep->flags & DWC3_EP_PENDING_REQUEST) &&
- list_empty(&dep->started_list)) {
- dwc3_stop_active_transfer(dwc, dep->number, true);
- dep->flags = DWC3_EP_ENABLED;
+ if ((dep->flags & DWC3_EP_PENDING_REQUEST)) {
+ if (dep->flags & DWC3_EP_TRANSFER_STARTED) {
+ dwc3_stop_active_transfer(dwc, dep->number, true);
+ dep->flags = DWC3_EP_ENABLED;
+ } else {
+ u32 cur_uf;
+
+ cur_uf = __dwc3_gadget_get_frame(dwc);
+ __dwc3_gadget_start_isoc(dwc, dep, cur_uf);
+ }
+ return 0;
}
- return 0;
+
+ if ((dep->flags & DWC3_EP_BUSY) &&
+ !(dep->flags & DWC3_EP_MISSED_ISOC)) {
+ WARN_ON_ONCE(!dep->resource_index);
+ ret = __dwc3_gadget_kick_transfer(dep,
+ dep->resource_index);
+ }
+
+ goto out;
}
if (!dwc3_calc_trbs_left(dep))
@@ -1153,6 +1198,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
dwc3_trace(trace_dwc3_gadget,
"%s: failed to kick transfers",
dep->name);
+out:
if (ret == -EBUSY)
ret = 0;
@@ -1243,6 +1289,52 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
if (r == req) {
/* wait until it is processed */
dwc3_stop_active_transfer(dwc, dep->number, true);
+
+ /*
+ * If request was already started, this means we had to
+ * stop the transfer. With that we also need to ignore
+ * all TRBs used by the request, however TRBs can only
+ * be modified after completion of END_TRANSFER
+ * command. So what we do here is that we wait for
+ * END_TRANSFER completion and only after that, we jump
+ * over TRBs by clearing HWO and incrementing dequeue
+ * pointer.
+ *
+ * Note that we have 2 possible types of transfers here:
+ *
+ * i) Linear buffer request
+ * ii) SG-list based request
+ *
+ * SG-list based requests will have r->num_pending_sgs
+ * set to a valid number (> 0). Linear requests,
+ * normally use a single TRB.
+ *
+ * All of these cases need to be taken into
+ * consideration so we don't mess up our TRB ring
+ * pointers.
+ */
+ wait_event_lock_irq(dep->wait_end_transfer,
+ !(dep->flags & DWC3_EP_END_TRANSFER_PENDING),
+ dwc->lock);
+
+ if (!r->trb)
+ goto out1;
+
+ if (r->num_pending_sgs) {
+ struct dwc3_trb *trb;
+ int i = 0;
+
+ for (i = 0; i < r->num_pending_sgs; i++) {
+ trb = r->trb + i;
+ trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
+ dwc3_ep_inc_deq(dep);
+ }
+ } else {
+ struct dwc3_trb *trb = r->trb;
+
+ trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
+ dwc3_ep_inc_deq(dep);
+ }
goto out1;
}
dev_err(dwc->dev, "request %pK was not queued to %s\n",
@@ -1253,6 +1345,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
out1:
/* giveback the request */
+ dep->queued_requests--;
dwc3_gadget_giveback(dep, req, -ECONNRESET);
out0:
@@ -1280,9 +1373,6 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
unsigned transfer_in_flight;
unsigned started;
- if (dep->flags & DWC3_EP_STALL)
- return 0;
-
if (dep->number > 1)
trb = dwc3_ep_prev_trb(dep, dep->trb_enqueue);
else
@@ -1307,8 +1397,6 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
else
dep->flags |= DWC3_EP_STALL;
} else {
- if (!(dep->flags & DWC3_EP_STALL))
- return 0;
ret = dwc3_send_clear_stall_ep_cmd(dep);
if (ret)
@@ -1391,10 +1479,8 @@ static const struct usb_ep_ops dwc3_gadget_ep_ops = {
static int dwc3_gadget_get_frame(struct usb_gadget *g)
{
struct dwc3 *dwc = gadget_to_dwc(g);
- u32 reg;
- reg = dwc3_readl(dwc->regs, DWC3_DSTS);
- return DWC3_DSTS_SOFFN(reg);
+ return __dwc3_gadget_get_frame(dwc);
}
static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
@@ -1768,9 +1854,6 @@ err0:
static void __dwc3_gadget_stop(struct dwc3 *dwc)
{
- if (pm_runtime_suspended(dwc->dev))
- return;
-
dwc3_gadget_disable_irq(dwc);
__dwc3_gadget_ep_disable(dwc->eps[0]);
__dwc3_gadget_ep_disable(dwc->eps[1]);
@@ -1780,9 +1863,30 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
+ int epnum;
spin_lock_irqsave(&dwc->lock, flags);
+
+ if (pm_runtime_suspended(dwc->dev))
+ goto out;
+
__dwc3_gadget_stop(dwc);
+
+ for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+ struct dwc3_ep *dep = dwc->eps[epnum];
+
+ if (!dep)
+ continue;
+
+ if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
+ continue;
+
+ wait_event_lock_irq(dep->wait_end_transfer,
+ !(dep->flags & DWC3_EP_END_TRANSFER_PENDING),
+ dwc->lock);
+ }
+
+out:
dwc->gadget_driver = NULL;
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -2156,10 +2260,12 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
{
struct dwc3_ep *dep;
u8 epnum = event->endpoint_number;
+ u8 cmd;
dep = dwc->eps[epnum];
- if (!(dep->flags & DWC3_EP_ENABLED))
+ if (!(dep->flags & DWC3_EP_ENABLED) &&
+ !(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
return;
if (epnum == 0 || epnum == 1) {
@@ -2227,11 +2333,15 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
"unable to find suitable stream");
}
break;
- case DWC3_DEPEVT_RXTXFIFOEVT:
- dwc3_trace(trace_dwc3_gadget, "%s FIFO Overrun", dep->name);
- break;
case DWC3_DEPEVT_EPCMDCMPLT:
- dwc3_trace(trace_dwc3_gadget, "Endpoint Command Complete");
+ cmd = DEPEVT_PARAMETER_CMD(event->parameters);
+
+ if (cmd == DWC3_DEPCMD_ENDTRANSFER) {
+ dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING;
+ wake_up(&dep->wait_end_transfer);
+ }
+ break;
+ case DWC3_DEPEVT_RXTXFIFOEVT:
break;
}
}
@@ -2284,7 +2394,8 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
dep = dwc->eps[epnum];
- if (!dep->resource_index)
+ if ((dep->flags & DWC3_EP_END_TRANSFER_PENDING) ||
+ !dep->resource_index)
return;
/*
@@ -2328,8 +2439,10 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
dep->resource_index = 0;
dep->flags &= ~DWC3_EP_BUSY;
- if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A)
+ if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) {
+ dep->flags |= DWC3_EP_END_TRANSFER_PENDING;
udelay(100);
+ }
}
static void dwc3_stop_active_transfers(struct dwc3 *dwc)
@@ -2389,14 +2502,20 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
dwc->setup_packet_pending = false;
usb_gadget_set_state(&dwc->gadget, USB_STATE_NOTATTACHED);
- dwc->connected = false;
+ if (dwc->connected) {
+ release_bus_freq(BUS_FREQ_HIGH);
+ dwc->connected = false;
+ }
}
static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
{
u32 reg;
- dwc->connected = true;
+ if (!dwc->connected) {
+ request_bus_freq(BUS_FREQ_HIGH);
+ dwc->connected = true;
+ }
/*
* WORKAROUND: DWC3 revisions <1.88a have an issue which
@@ -3000,7 +3119,10 @@ int dwc3_gadget_init(struct dwc3 *dwc)
dwc->gadget.speed = USB_SPEED_UNKNOWN;
dwc->gadget.sg_supported = true;
dwc->gadget.name = "dwc3-gadget";
- dwc->gadget.is_otg = dwc->dr_mode == USB_DR_MODE_OTG;
+ dwc->gadget.is_otg = (dwc->dr_mode == USB_DR_MODE_OTG) &&
+ (dwc->otg_caps.hnp_support ||
+ dwc->otg_caps.srp_support ||
+ dwc->otg_caps.adp_support);
/*
* FIXME We might be setting max_speed to <SUPER, however versions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index f3ee80ece682..9f4b89b3d37d 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -337,6 +337,12 @@ config USB_CONFIGFS_MASS_STORAGE
device (in much the same way as the "loop" device driver),
specified as a module parameter or sysfs option.
+config FSL_UTP
+ bool "UTP over Storage Gadget"
+ depends on USB_CONFIGFS_MASS_STORAGE
+ help
+ Freescale's extension to MSC protocol
+
config USB_CONFIGFS_F_LB_SS
bool "Loopback and sourcesink function (for testing)"
depends on USB_CONFIGFS
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index d2fc237cd87a..e23150fb50e6 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -329,8 +329,15 @@ struct fsg_dev {
struct usb_ep *bulk_in;
struct usb_ep *bulk_out;
+#ifdef CONFIG_FSL_UTP
+ void *utp;
+#endif
};
+#ifdef CONFIG_FSL_UTP
+#include "fsl_updater.h"
+#endif
+
static inline int __fsg_is_set(struct fsg_common *common,
const char *func, unsigned line)
{
@@ -1148,6 +1155,15 @@ static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
}
#endif
+#ifdef CONFIG_FSL_UTP
+ if (is_utp_device(common->fsg) &&
+ utp_get_sense(common->fsg) == 0) {
+ /* got the sense from the UTP */
+ sd = UTP_CTX(common->fsg)->sd;
+ sdinfo = UTP_CTX(common->fsg)->sdinfo;
+ valid = 0;
+ } else
+#endif
if (!curlun) { /* Unsupported LUNs are okay */
common->bad_lun_okay = 1;
sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
@@ -1169,6 +1185,10 @@ static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
buf[7] = 18 - 8; /* Additional sense length */
buf[12] = ASC(sd);
buf[13] = ASCQ(sd);
+#ifdef CONFIG_FSL_UTP
+ if (is_utp_device(common->fsg))
+ put_unaligned_be32(UTP_CTX(common->fsg)->sdinfo_h, &buf[8]);
+#endif
return 18;
}
@@ -1662,7 +1682,20 @@ static int send_status(struct fsg_common *common)
sd = SS_INVALID_COMMAND;
} else if (sd != SS_NO_SENSE) {
DBG(common, "sending command-failure status\n");
- status = US_BULK_STAT_FAIL;
+#ifdef CONFIG_FSL_UTP
+ /*
+ * mfgtool host frequently reset bus during transfer
+ * - the response in csw to request sense will be 1
+ * due to UTP change some storage information
+ * - host will reset the bus if response to request sense is 1
+ * - change the response to 0 if CONFIG_FSL_UTP is defined
+ */
+ if (is_utp_device(common->fsg))
+ status = US_BULK_STAT_OK;
+ else
+#endif
+ status = US_BULK_STAT_FAIL;
+
VDBG(common, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
" info x%x\n",
SK(sd), ASC(sd), ASCQ(sd), sdinfo);
@@ -1853,6 +1886,14 @@ static int do_scsi_command(struct fsg_common *common)
common->phase_error = 0;
common->short_packet_received = 0;
+#ifdef CONFIG_FSL_UTP
+ if (is_utp_device(common->fsg))
+ reply = utp_handle_message(common->fsg, common->cmnd, reply);
+
+ if (reply != -EINVAL)
+ return reply;
+#endif
+
down_read(&common->filesem); /* We're using the backing file */
switch (common->cmnd[0]) {
@@ -2522,7 +2563,12 @@ static int fsg_main_thread(void *common_)
* pointers. That way we can pass a kernel pointer to a routine
* that expects a __user pointer and it will work okay.
*/
+#ifdef CONFIG_FSL_UTP
+ if (!is_utp_device(common->fsg))
+ set_fs(get_ds());
+#else
set_fs(get_ds());
+#endif
/* The main loop */
while (common->state != FSG_STATE_TERMINATED) {
@@ -2988,6 +3034,10 @@ static void fsg_common_release(struct kref *ref)
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_FSL_UTP
+#include "fsl_updater.c"
+#endif
+
static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
{
struct fsg_dev *fsg = fsg_from_func(f);
@@ -3039,6 +3089,11 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
fsg_intf_desc.bInterfaceNumber = i;
fsg->interface_number = i;
+#ifdef CONFIG_FSL_UTP
+ if (is_utp_device(fsg))
+ utp_init(fsg);
+#endif
+
/* Find all the endpoints we will use */
ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
if (!ep)
@@ -3102,6 +3157,12 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
}
usb_free_all_descriptors(&fsg->function);
+
+#ifdef CONFIG_FSL_UTP
+ if (is_utp_device(common->fsg))
+ utp_exit(fsg);
+#endif
+
}
static inline struct fsg_lun_opts *to_fsg_lun_opts(struct config_item *item)
diff --git a/drivers/usb/gadget/function/fsl_updater.c b/drivers/usb/gadget/function/fsl_updater.c
new file mode 100644
index 000000000000..59ec7479bd71
--- /dev/null
+++ b/drivers/usb/gadget/function/fsl_updater.c
@@ -0,0 +1,647 @@
+/*
+ * Freescale UUT driver
+ *
+ * Copyright 2008-2016 Freescale Semiconductor, Inc.
+ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved.
+ * Copyright 2017 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+static bool is_utp_device(struct fsg_dev *fsg)
+{
+ struct usb_device_descriptor *pdesc;
+
+ if (!fsg || !fsg->common || !fsg->common->cdev)
+ return false;
+
+ pdesc = &fsg->common->cdev->desc;
+ if (pdesc->idVendor == UTP_IDVENDOR &&
+ pdesc->idProduct == UTP_IDPRODUCT)
+ return true;
+
+ return false;
+}
+
+static u64 get_be64(u8 *buf)
+{
+ return ((u64)get_unaligned_be32(buf) << 32) |
+ get_unaligned_be32(buf + 4);
+}
+
+static DEFINE_IDA(utp_ida);
+
+static int utp_init(struct fsg_dev *fsg)
+{
+ struct utp_context *utp;
+ int index;
+
+ utp = vzalloc(sizeof(struct utp_context));
+ if (!utp)
+ return -EIO;
+
+ init_waitqueue_head(&utp->wq);
+ init_waitqueue_head(&utp->list_full_wq);
+
+ INIT_LIST_HEAD(&utp->read);
+ INIT_LIST_HEAD(&utp->write);
+ mutex_init(&utp->lock);
+
+ /* the max message is 64KB */
+ utp->buffer = vmalloc(0x10000);
+ if (!utp->buffer) {
+ vfree(utp);
+ return -EIO;
+ }
+
+ utp->utp_version = 0x1ull;
+ fsg->utp = utp;
+ utp->utp_dev.minor = MISC_DYNAMIC_MINOR;
+ utp->utp_dev.fops = &utp_fops;
+
+ index = ida_simple_get(&utp_ida, 0, 0, GFP_KERNEL);
+ if (index == 0)
+ snprintf(utp->utp_name, 8, "utp");
+ else
+ snprintf(utp->utp_name, 8, "utp%d", index);
+
+ utp->utp_dev.name = utp->utp_name;
+ return misc_register(&utp->utp_dev);
+}
+
+static void utp_exit(struct fsg_dev *fsg)
+{
+ struct utp_context *utp;
+ utp = UTP_CTX(fsg);
+
+ misc_deregister(&utp->utp_dev);
+
+ vfree(utp->buffer);
+ vfree(utp);
+}
+
+static struct utp_user_data *utp_user_data_alloc(size_t size)
+{
+ struct utp_user_data *uud;
+
+ uud = vmalloc(size + sizeof(*uud));
+ if (!uud)
+ return uud;
+ memset(uud, 0, size + sizeof(*uud));
+ uud->data.size = size + sizeof(uud->data);
+ INIT_LIST_HEAD(&uud->link);
+ return uud;
+}
+
+static void utp_user_data_free(struct utp_context *utp, struct utp_user_data *uud)
+{
+ mutex_lock(&utp->lock);
+ list_del(&uud->link);
+ mutex_unlock(&utp->lock);
+ vfree(uud);
+}
+
+/* Get the number of element for list */
+static u32 count_list(struct utp_context *utp, struct list_head *l)
+{
+ u32 count = 0;
+ struct list_head *tmp;
+
+ mutex_lock(&utp->lock);
+ list_for_each(tmp, l) {
+ count++;
+ }
+ mutex_unlock(&utp->lock);
+
+ return count;
+}
+
+/* The routine will not go on if utp_context.queue is empty */
+#define WAIT_ACTIVITY(utp, queue) \
+ wait_event_interruptible(utp->wq, !list_empty(&utp->queue))
+
+/* Called by userspace program (uuc) */
+static ssize_t utp_file_read(struct file *file,
+ char __user *buf,
+ size_t size,
+ loff_t *off)
+{
+ struct utp_user_data *uud;
+ size_t size_to_put;
+ int free = 0;
+
+ struct miscdevice *misc = (struct miscdevice *)file->private_data;
+ struct utp_context *utp = container_of(misc, struct utp_context, utp_dev);
+
+ WAIT_ACTIVITY(utp, read);
+
+ mutex_lock(&utp->lock);
+ uud = list_first_entry(&utp->read, struct utp_user_data, link);
+ mutex_unlock(&utp->lock);
+ size_to_put = uud->data.size;
+
+ if (size >= size_to_put)
+ free = !0;
+ if (copy_to_user(buf, &uud->data, size_to_put)) {
+ printk(KERN_INFO "[ %s ] copy error\n", __func__);
+ return -EACCES;
+ }
+ if (free)
+ utp_user_data_free(utp, uud);
+ else {
+ pr_info("sizeof = %zd, size = %zd\n",
+ sizeof(uud->data),
+ uud->data.size);
+
+ pr_err("Will not free utp_user_data, because buffer size = %zd need to put %zd\n",
+ size, size_to_put);
+ }
+
+ /*
+ * The user program has already finished data process,
+ * go on getting data from the host
+ */
+ wake_up(&utp->list_full_wq);
+
+ return size_to_put;
+}
+
+static ssize_t utp_file_write(struct file *file, const char __user *buf,
+ size_t size, loff_t *off)
+{
+ struct utp_user_data *uud;
+
+ struct miscdevice *misc = (struct miscdevice *)file->private_data;
+ struct utp_context *utp = container_of(misc, struct utp_context, utp_dev);
+
+ if (size < sizeof(uud->data))
+ return -EINVAL;
+ uud = utp_user_data_alloc(size);
+ if (uud == NULL)
+ return -ENOMEM;
+ if (copy_from_user(&uud->data, buf, size)) {
+ printk(KERN_INFO "[ %s ] copy error!\n", __func__);
+ vfree(uud);
+ return -EACCES;
+ }
+ mutex_lock(&utp->lock);
+ list_add_tail(&uud->link, &utp->write);
+ /* Go on EXEC routine process */
+ wake_up(&utp->wq);
+ mutex_unlock(&utp->lock);
+ return size;
+}
+
+/*
+ * uuc should change to use soc bus infrastructure to soc information
+ * /sys/devices/soc0/soc_id
+ * this function can be removed.
+ */
+static long
+utp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int cpu_id = 0;
+
+ switch (cmd) {
+ case UTP_GET_CPU_ID:
+ return put_user(cpu_id, (int __user *)arg);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+/* Will be called when the host wants to get the sense data */
+static int utp_get_sense(struct fsg_dev *fsg)
+{
+ if (UTP_CTX(fsg)->processed == 0)
+ return -1;
+
+ UTP_CTX(fsg)->processed = 0;
+ return 0;
+}
+
+static int utp_do_read(struct fsg_dev *fsg, void *data, size_t size)
+{
+ struct fsg_buffhd *bh;
+ int rc;
+ u32 amount_left;
+ unsigned int amount;
+
+ /* Get the starting Logical Block Address and check that it's
+ * not too big */
+
+ amount_left = size;
+ if (unlikely(amount_left == 0))
+ return -EIO; /* No default reply*/
+
+ pr_debug("%s: sending %zd\n", __func__, size);
+ for (;;) {
+ /* Figure out how much we need to read:
+ * Try to read the remaining amount.
+ * But don't read more than the buffer size.
+ * And don't try to read past the end of the file.
+ * Finally, if we're not at a page boundary, don't read past
+ * the next page.
+ * If this means reading 0 then we were asked to read past
+ * the end of file. */
+ amount = min((unsigned int) amount_left, FSG_BUFLEN);
+
+ /* Wait for the next buffer to become available */
+ bh = fsg->common->next_buffhd_to_fill;
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(fsg->common, true);
+ if (rc)
+ return rc;
+ }
+
+ /* If we were asked to read past the end of file,
+ * end with an empty buffer. */
+ if (amount == 0) {
+ bh->inreq->length = 0;
+ bh->state = BUF_STATE_FULL;
+ break;
+ }
+
+ /* Perform the read */
+ pr_info("Copied to %p, %d bytes started from %zd\n",
+ bh->buf, amount, size - amount_left);
+ /* from upt buffer to file_storeage buffer */
+ memcpy(bh->buf, data + size - amount_left, amount);
+ amount_left -= amount;
+ fsg->common->residue -= amount;
+
+ bh->inreq->length = amount;
+ bh->state = BUF_STATE_FULL;
+
+ /* Send this buffer and go read some more */
+ bh->inreq->zero = 0;
+
+ /* USB Physical transfer: Data from device to host */
+ start_transfer(fsg, fsg->bulk_in, bh->inreq,
+ &bh->inreq_busy, &bh->state);
+
+ fsg->common->next_buffhd_to_fill = bh->next;
+
+ if (amount_left <= 0)
+ break;
+ }
+
+ return size - amount_left;
+}
+
+static int utp_do_write(struct fsg_dev *fsg, void *data, size_t size)
+{
+ struct fsg_buffhd *bh;
+ int get_some_more;
+ u32 amount_left_to_req, amount_left_to_write;
+ unsigned int amount;
+ int rc;
+ loff_t offset;
+
+ /* Carry out the file writes */
+ get_some_more = 1;
+ amount_left_to_req = amount_left_to_write = size;
+
+ if (unlikely(amount_left_to_write == 0))
+ return -EIO;
+
+ offset = 0;
+ while (amount_left_to_write > 0) {
+
+ /* Queue a request for more data from the host */
+ bh = fsg->common->next_buffhd_to_fill;
+ if (bh->state == BUF_STATE_EMPTY && get_some_more) {
+
+ /* Figure out how much we want to get:
+ * Try to get the remaining amount.
+ * But don't get more than the buffer size.
+ * And don't try to go past the end of the file.
+ * If we're not at a page boundary,
+ * don't go past the next page.
+ * If this means getting 0, then we were asked
+ * to write past the end of file.
+ * Finally, round down to a block boundary. */
+ amount = min(amount_left_to_req, FSG_BUFLEN);
+
+ if (amount == 0) {
+ get_some_more = 0;
+ /* cry now */
+ continue;
+ }
+
+ /* Get the next buffer */
+ amount_left_to_req -= amount;
+ if (amount_left_to_req == 0)
+ get_some_more = 0;
+
+ /* amount is always divisible by 512, hence by
+ * the bulk-out maxpacket size */
+ set_bulk_out_req_length(fsg->common, bh, amount);
+ bh->outreq->short_not_ok = 1;
+ start_transfer(fsg, fsg->bulk_out, bh->outreq,
+ &bh->outreq_busy, &bh->state);
+ fsg->common->next_buffhd_to_fill = bh->next;
+ continue;
+ }
+
+ /* Write the received data to the backing file */
+ bh = fsg->common->next_buffhd_to_drain;
+ if (bh->state == BUF_STATE_EMPTY && !get_some_more)
+ break; /* We stopped early */
+ if (bh->state == BUF_STATE_FULL) {
+ smp_rmb();
+ fsg->common->next_buffhd_to_drain = bh->next;
+ bh->state = BUF_STATE_EMPTY;
+
+ /* Did something go wrong with the transfer? */
+ if (bh->outreq->status != 0)
+ /* cry again, COMMUNICATION_FAILURE */
+ break;
+
+ amount = bh->outreq->actual;
+
+ /* Perform the write */
+ memcpy(data + offset, bh->buf, amount);
+
+ offset += amount;
+ if (signal_pending(current))
+ return -EINTR; /* Interrupted!*/
+ amount_left_to_write -= amount;
+ fsg->common->residue -= amount;
+
+ /* Did the host decide to stop early? */
+ if (bh->outreq->actual != bh->outreq->length) {
+ fsg->common->short_packet_received = 1;
+ break;
+ }
+ continue;
+ }
+
+ /* Wait for something to happen */
+ rc = sleep_thread(fsg->common, true);
+ if (rc)
+ return rc;
+ }
+
+ return -EIO;
+}
+
+static inline void utp_set_sense(struct fsg_dev *fsg, u16 code, u64 reply)
+{
+ UTP_CTX(fsg)->processed = true;
+ UTP_CTX(fsg)->sdinfo = reply & 0xFFFFFFFF;
+ UTP_CTX(fsg)->sdinfo_h = (reply >> 32) & 0xFFFFFFFF;
+ UTP_CTX(fsg)->sd = (UTP_SENSE_KEY << 16) | code;
+}
+
+static void utp_poll(struct fsg_dev *fsg)
+{
+ struct utp_context *ctx = UTP_CTX(fsg);
+ struct utp_user_data *uud = NULL;
+
+ mutex_lock(&ctx->lock);
+ if (!list_empty(&ctx->write))
+ uud = list_first_entry(&ctx->write, struct utp_user_data, link);
+ mutex_unlock(&ctx->lock);
+
+ if (uud) {
+ if (uud->data.flags & UTP_FLAG_STATUS) {
+ printk(KERN_WARNING "%s: exit with status %d\n",
+ __func__, uud->data.status);
+ UTP_SS_EXIT(fsg, uud->data.status);
+ } else if (uud->data.flags & UTP_FLAG_REPORT_BUSY) {
+ UTP_SS_BUSY(fsg, --ctx->counter);
+ } else {
+ printk("%s: pass returned.\n", __func__);
+ UTP_SS_PASS(fsg);
+ }
+ utp_user_data_free(ctx, uud);
+ } else {
+ if (ctx->cur_state & UTP_FLAG_DATA) {
+ if (count_list(ctx, &ctx->read) < 7) {
+ pr_debug("%s: pass returned in POLL stage. \n", __func__);
+ UTP_SS_PASS(fsg);
+ ctx->cur_state = 0;
+ return;
+ }
+ }
+ UTP_SS_BUSY(fsg, --ctx->counter);
+ }
+}
+
+static int utp_exec(struct fsg_dev *fsg,
+ char *command,
+ int cmdsize,
+ unsigned long long payload)
+{
+ struct utp_user_data *uud = NULL, *uud2r;
+ struct utp_context *ctx = UTP_CTX(fsg);
+
+ ctx->counter = 0xFFFF;
+ uud2r = utp_user_data_alloc(cmdsize + 1);
+ if (!uud2r)
+ return -ENOMEM;
+ uud2r->data.flags = UTP_FLAG_COMMAND;
+ uud2r->data.payload = payload;
+ strncpy(uud2r->data.command, command, cmdsize);
+
+ mutex_lock(&ctx->lock);
+ list_add_tail(&uud2r->link, &ctx->read);
+ mutex_unlock(&ctx->lock);
+ /* wake up the read routine */
+ wake_up(&ctx->wq);
+
+ if (command[0] == '!') /* there will be no response */
+ return 0;
+
+ /*
+ * the user program (uuc) will return utp_message
+ * and add list to write list
+ */
+ WAIT_ACTIVITY(ctx, write);
+
+ mutex_lock(&ctx->lock);
+ if (!list_empty(&ctx->write)) {
+ uud = list_first_entry(&ctx->write, struct utp_user_data, link);
+#ifdef DEBUG
+ pr_info("UUD:\n\tFlags = %02X\n", uud->data.flags);
+ if (uud->data.flags & UTP_FLAG_DATA) {
+ pr_info("\tbufsize = %d\n", uud->data.bufsize);
+ print_hex_dump(KERN_DEBUG, "\t", DUMP_PREFIX_NONE,
+ 16, 2, uud->data.data, uud->data.bufsize, true);
+ }
+ if (uud->data.flags & UTP_FLAG_REPORT_BUSY)
+ pr_info("\tBUSY\n");
+#endif
+ } else {
+ pr_err("UTP write list is empty.\n");
+ mutex_unlock(&ctx->lock);
+ return 0;
+ }
+ mutex_unlock(&ctx->lock);
+
+ if (uud->data.flags & UTP_FLAG_DATA) {
+ memcpy(ctx->buffer, uud->data.data, uud->data.bufsize);
+ UTP_SS_SIZE(fsg, uud->data.bufsize);
+ } else if (uud->data.flags & UTP_FLAG_REPORT_BUSY) {
+ UTP_SS_BUSY(fsg, ctx->counter);
+ } else if (uud->data.flags & UTP_FLAG_STATUS) {
+ printk(KERN_WARNING "%s: exit with status %d\n", __func__,
+ uud->data.status);
+ UTP_SS_EXIT(fsg, uud->data.status);
+ } else {
+ pr_debug("%s: pass returned in EXEC stage. \n", __func__);
+ UTP_SS_PASS(fsg);
+ }
+ utp_user_data_free(ctx, uud);
+ return 0;
+}
+
+static int utp_send_status(struct fsg_dev *fsg)
+{
+ struct fsg_buffhd *bh;
+ u8 status = US_BULK_STAT_OK;
+ struct bulk_cs_wrap *csw;
+ int rc;
+
+ /* Wait for the next buffer to become available */
+ bh = fsg->common->next_buffhd_to_fill;
+ while (bh->state != BUF_STATE_EMPTY) {
+ rc = sleep_thread(fsg->common, true);
+ if (rc)
+ return rc;
+ }
+
+ if (fsg->common->phase_error) {
+ DBG(fsg, "sending phase-error status\n");
+ status = US_BULK_STAT_PHASE;
+
+ } else if ((UTP_CTX(fsg)->sd & 0xFFFF) != UTP_REPLY_PASS) {
+ status = US_BULK_STAT_FAIL;
+ }
+
+ csw = bh->buf;
+
+ /* Store and send the Bulk-only CSW */
+ csw->Signature = __constant_cpu_to_le32(US_BULK_CS_SIGN);
+ csw->Tag = fsg->common->tag;
+ csw->Residue = cpu_to_le32(fsg->common->residue);
+ csw->Status = status;
+
+ bh->inreq->length = US_BULK_CS_WRAP_LEN;
+ bh->inreq->zero = 0;
+ start_transfer(fsg, fsg->bulk_in, bh->inreq,
+ &bh->inreq_busy, &bh->state);
+ fsg->common->next_buffhd_to_fill = bh->next;
+ return 0;
+}
+
+static int utp_handle_message(struct fsg_dev *fsg,
+ char *cdb_data,
+ int default_reply)
+{
+ struct utp_msg *m = (struct utp_msg *)cdb_data;
+ void *data = NULL;
+ int r;
+ struct utp_user_data *uud2r;
+ unsigned long long param;
+ unsigned long tag;
+
+ if (m->f0 != 0xF0)
+ return default_reply;
+
+ tag = get_unaligned_be32((void *)&m->utp_msg_tag);
+ param = get_be64((void *)&m->param);
+ pr_debug("Type 0x%x, tag 0x%08lx, param %llx\n",
+ m->utp_msg_type, tag, param);
+
+ switch ((enum utp_msg_type)m->utp_msg_type) {
+
+ case UTP_POLL:
+ if (get_be64((void *)&m->param) == 1) {
+ pr_debug("%s: version request\n", __func__);
+ UTP_SS_EXIT(fsg, UTP_CTX(fsg)->utp_version);
+ break;
+ }
+ utp_poll(fsg);
+ break;
+ case UTP_EXEC:
+ pr_debug("%s: EXEC\n", __func__);
+ data = vmalloc(fsg->common->data_size);
+ memset(data, 0, fsg->common->data_size);
+ /* copy data from usb buffer to utp buffer */
+ utp_do_write(fsg, data, fsg->common->data_size);
+ utp_exec(fsg, data, fsg->common->data_size, param);
+ vfree(data);
+ break;
+ case UTP_GET: /* data from device to host */
+ pr_debug("%s: GET, %d bytes\n", __func__,
+ fsg->common->data_size);
+ r = utp_do_read(fsg, UTP_CTX(fsg)->buffer,
+ fsg->common->data_size);
+ UTP_SS_PASS(fsg);
+ break;
+ case UTP_PUT:
+ UTP_CTX(fsg)->cur_state = UTP_FLAG_DATA;
+ pr_debug("%s: PUT, Received %d bytes\n", __func__, fsg->common->data_size);/* data from host to device */
+ uud2r = utp_user_data_alloc(fsg->common->data_size);
+ if (!uud2r)
+ return -ENOMEM;
+ uud2r->data.bufsize = fsg->common->data_size;
+ uud2r->data.flags = UTP_FLAG_DATA;
+ utp_do_write(fsg, uud2r->data.data, fsg->common->data_size);
+ /* don't know what will be written */
+ mutex_lock(&UTP_CTX(fsg)->lock);
+ list_add_tail(&uud2r->link, &UTP_CTX(fsg)->read);
+ mutex_unlock(&UTP_CTX(fsg)->lock);
+ wake_up(&UTP_CTX(fsg)->wq);
+ /*
+ * Return PASS or FAIL according to uuc's status
+ * Please open it if need to check uuc's status
+ * and use another version uuc
+ */
+#if 0
+ struct utp_user_data *uud = NULL;
+ struct utp_context *ctx;
+ WAIT_ACTIVITY(write);
+ ctx = UTP_CTX(fsg);
+ mutex_lock(&ctx->lock);
+
+ if (!list_empty(&ctx->write))
+ uud = list_first_entry(&ctx->write,
+ struct utp_user_data, link);
+
+ mutex_unlock(&ctx->lock);
+ if (uud) {
+ if (uud->data.flags & UTP_FLAG_STATUS) {
+ printk(KERN_WARNING "%s: exit with status %d\n",
+ __func__, uud->data.status);
+ UTP_SS_EXIT(fsg, uud->data.status);
+ } else {
+ pr_debug("%s: pass\n", __func__);
+ UTP_SS_PASS(fsg);
+ }
+ utp_user_data_free(uud);
+ } else{
+ UTP_SS_PASS(fsg);
+ }
+#endif
+ if (count_list(UTP_CTX(fsg), &UTP_CTX(fsg)->read) < 7) {
+ UTP_CTX(fsg)->cur_state = 0;
+ UTP_SS_PASS(fsg);
+ } else
+ UTP_SS_BUSY(fsg, UTP_CTX(fsg)->counter);
+
+ break;
+ }
+
+ utp_send_status(fsg);
+ return -1;
+}
diff --git a/drivers/usb/gadget/function/fsl_updater.h b/drivers/usb/gadget/function/fsl_updater.h
new file mode 100644
index 000000000000..044beb0e2114
--- /dev/null
+++ b/drivers/usb/gadget/function/fsl_updater.h
@@ -0,0 +1,152 @@
+/*
+ * Freescale UUT driver
+ *
+ * Copyright 2008-2016 Freescale Semiconductor, Inc.
+ * Copyright 2008-2009 Embedded Alley Solutions, Inc All Rights Reserved.
+ * Copyright 2017 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __FSL_UPDATER_H
+#define __FSL_UPDATER_H
+
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+#include <linux/ioctl.h>
+/* #include <mach/hardware.h> */
+struct utp_context;
+
+static int utp_init(struct fsg_dev *fsg);
+static void utp_exit(struct fsg_dev *fsg);
+static ssize_t utp_file_read(struct file *file,
+ char __user *buf,
+ size_t size,
+ loff_t *off);
+
+static ssize_t utp_file_write(struct file *file,
+ const char __user *buf,
+ size_t size,
+ loff_t *off);
+
+static bool is_utp_device(struct fsg_dev *fsg);
+static long utp_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg);
+static struct utp_user_data *utp_user_data_alloc(size_t size);
+static void utp_user_data_free(struct utp_context *utp, struct utp_user_data *uud);
+static int utp_get_sense(struct fsg_dev *fsg);
+static int utp_do_read(struct fsg_dev *fsg, void *data, size_t size);
+static int utp_do_write(struct fsg_dev *fsg, void *data, size_t size);
+static inline void utp_set_sense(struct fsg_dev *fsg, u16 code, u64 reply);
+static int utp_handle_message(struct fsg_dev *fsg,
+ char *cdb_data,
+ int default_reply);
+
+#define UTP_REPLY_PASS 0
+#define UTP_REPLY_EXIT 0x8001
+#define UTP_REPLY_BUSY 0x8002
+#define UTP_REPLY_SIZE 0x8003
+#define UTP_SENSE_KEY 9
+
+#define UTP_MINOR 222
+/* MISC_DYNAMIC_MINOR would be better, but... */
+
+#define UTP_IDVENDOR 0x066F
+#define UTP_IDPRODUCT 0x37FF
+
+#define UTP_COMMAND_SIZE 80
+
+#define UTP_SS_EXIT(fsg, r) utp_set_sense(fsg, UTP_REPLY_EXIT, (u64)r)
+#define UTP_SS_PASS(fsg) utp_set_sense(fsg, UTP_REPLY_PASS, 0)
+#define UTP_SS_BUSY(fsg, r) utp_set_sense(fsg, UTP_REPLY_BUSY, (u64)r)
+#define UTP_SS_SIZE(fsg, r) utp_set_sense(fsg, UTP_REPLY_SIZE, (u64)r)
+
+#define UTP_IOCTL_BASE 'U'
+#define UTP_GET_CPU_ID _IOR(UTP_IOCTL_BASE, 0, int)
+/* the structure of utp message which is mapped to 16-byte SCSI CBW's CDB */
+#pragma pack(1)
+struct utp_msg {
+ u8 f0;
+ u8 utp_msg_type;
+ u32 utp_msg_tag;
+ union {
+ struct {
+ u32 param_lsb;
+ u32 param_msb;
+ };
+ u64 param;
+ };
+};
+
+enum utp_msg_type {
+ UTP_POLL = 0,
+ UTP_EXEC,
+ UTP_GET,
+ UTP_PUT,
+};
+
+struct utp_context {
+ wait_queue_head_t wq;
+ wait_queue_head_t list_full_wq;
+ struct mutex lock;
+ struct list_head read;
+ struct list_head write;
+ u32 sd, sdinfo, sdinfo_h; /* sense data */
+ int processed;
+ u8 *buffer;
+ u32 counter;
+ u64 utp_version;
+ u32 cur_state;
+ struct miscdevice utp_dev;
+ char utp_name[8];
+};
+
+static const struct file_operations utp_fops = {
+ .open = nonseekable_open,
+ .read = utp_file_read,
+ .write = utp_file_write,
+ /* .ioctl = utp_ioctl, */
+ .unlocked_ioctl = utp_ioctl,
+};
+
+#define UTP_FLAG_COMMAND 0x00000001
+#define UTP_FLAG_DATA 0x00000002
+#define UTP_FLAG_STATUS 0x00000004
+#define UTP_FLAG_REPORT_BUSY 0x10000000
+struct utp_message {
+ u32 flags;
+ size_t size;
+ union {
+ struct {
+ u64 payload;
+ char command[1];
+ };
+ struct {
+ size_t bufsize;
+ u8 data[1];
+ };
+ u32 status;
+ };
+};
+
+struct utp_user_data {
+ struct list_head link;
+ struct utp_message data;
+};
+#pragma pack()
+
+static inline struct utp_context *UTP_CTX(struct fsg_dev *fsg)
+{
+ return (struct utp_context *)fsg->utp;
+}
+
+#endif /* __FSL_UPDATER_H */
+
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 139f6cce30b1..53abf7e7875b 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -1274,6 +1274,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
flush_work(&gadget->work);
device_unregister(&udc->dev);
device_unregister(&gadget->dev);
+ memset(&gadget->dev, 0x00, sizeof(gadget->dev));
}
EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 063064801ceb..f75423664003 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -93,7 +93,7 @@ module_param (log2_irq_thresh, int, S_IRUGO);
MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
/* initial park setting: slower than hw default */
-static unsigned park = 0;
+static unsigned park = 3;
module_param (park, uint, S_IRUGO);
MODULE_PARM_DESC (park, "park setting; 1-3 back-to-back async packets");
@@ -1244,6 +1244,10 @@ static const struct hc_driver ehci_hc_driver = {
* device support
*/
.free_dev = ehci_remove_device,
+#ifdef CONFIG_USB_HCD_TEST_MODE
+ /* EH SINGLE_STEP_SET_FEATURE test support */
+ .submit_single_step_set_feature = ehci_submit_single_step_set_feature,
+#endif
};
void ehci_init_driver(struct hc_driver *drv,
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 74f62d68f013..9de412272dea 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -722,145 +722,6 @@ ehci_hub_descriptor (
}
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_USB_HCD_TEST_MODE
-
-#define EHSET_TEST_SINGLE_STEP_SET_FEATURE 0x06
-
-static void usb_ehset_completion(struct urb *urb)
-{
- struct completion *done = urb->context;
-
- complete(done);
-}
-static int submit_single_step_set_feature(
- struct usb_hcd *hcd,
- struct urb *urb,
- int is_setup
-);
-
-/*
- * Allocate and initialize a control URB. This request will be used by the
- * EHSET SINGLE_STEP_SET_FEATURE test in which the DATA and STATUS stages
- * of the GetDescriptor request are sent 15 seconds after the SETUP stage.
- * Return NULL if failed.
- */
-static struct urb *request_single_step_set_feature_urb(
- struct usb_device *udev,
- void *dr,
- void *buf,
- struct completion *done
-) {
- struct urb *urb;
- struct usb_hcd *hcd = bus_to_hcd(udev->bus);
- struct usb_host_endpoint *ep;
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb)
- return NULL;
-
- urb->pipe = usb_rcvctrlpipe(udev, 0);
- ep = (usb_pipein(urb->pipe) ? udev->ep_in : udev->ep_out)
- [usb_pipeendpoint(urb->pipe)];
- if (!ep) {
- usb_free_urb(urb);
- return NULL;
- }
-
- urb->ep = ep;
- urb->dev = udev;
- urb->setup_packet = (void *)dr;
- urb->transfer_buffer = buf;
- urb->transfer_buffer_length = USB_DT_DEVICE_SIZE;
- urb->complete = usb_ehset_completion;
- urb->status = -EINPROGRESS;
- urb->actual_length = 0;
- urb->transfer_flags = URB_DIR_IN;
- usb_get_urb(urb);
- atomic_inc(&urb->use_count);
- atomic_inc(&urb->dev->urbnum);
- urb->setup_dma = dma_map_single(
- hcd->self.controller,
- urb->setup_packet,
- sizeof(struct usb_ctrlrequest),
- DMA_TO_DEVICE);
- urb->transfer_dma = dma_map_single(
- hcd->self.controller,
- urb->transfer_buffer,
- urb->transfer_buffer_length,
- DMA_FROM_DEVICE);
- urb->context = done;
- return urb;
-}
-
-static int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
-{
- int retval = -ENOMEM;
- struct usb_ctrlrequest *dr;
- struct urb *urb;
- struct usb_device *udev;
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- struct usb_device_descriptor *buf;
- DECLARE_COMPLETION_ONSTACK(done);
-
- /* Obtain udev of the rhub's child port */
- udev = usb_hub_find_child(hcd->self.root_hub, port);
- if (!udev) {
- ehci_err(ehci, "No device attached to the RootHub\n");
- return -ENODEV;
- }
- buf = kmalloc(USB_DT_DEVICE_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
- if (!dr) {
- kfree(buf);
- return -ENOMEM;
- }
-
- /* Fill Setup packet for GetDescriptor */
- dr->bRequestType = USB_DIR_IN;
- dr->bRequest = USB_REQ_GET_DESCRIPTOR;
- dr->wValue = cpu_to_le16(USB_DT_DEVICE << 8);
- dr->wIndex = 0;
- dr->wLength = cpu_to_le16(USB_DT_DEVICE_SIZE);
- urb = request_single_step_set_feature_urb(udev, dr, buf, &done);
- if (!urb)
- goto cleanup;
-
- /* Submit just the SETUP stage */
- retval = submit_single_step_set_feature(hcd, urb, 1);
- if (retval)
- goto out1;
- if (!wait_for_completion_timeout(&done, msecs_to_jiffies(2000))) {
- usb_kill_urb(urb);
- retval = -ETIMEDOUT;
- ehci_err(ehci, "%s SETUP stage timed out on ep0\n", __func__);
- goto out1;
- }
- msleep(15 * 1000);
-
- /* Complete remaining DATA and STATUS stages using the same URB */
- urb->status = -EINPROGRESS;
- usb_get_urb(urb);
- atomic_inc(&urb->use_count);
- atomic_inc(&urb->dev->urbnum);
- retval = submit_single_step_set_feature(hcd, urb, 0);
- if (!retval && !wait_for_completion_timeout(&done,
- msecs_to_jiffies(2000))) {
- usb_kill_urb(urb);
- retval = -ETIMEDOUT;
- ehci_err(ehci, "%s IN stage timed out on ep0\n", __func__);
- }
-out1:
- usb_free_urb(urb);
-cleanup:
- kfree(dr);
- kfree(buf);
- return retval;
-}
-#endif /* CONFIG_USB_HCD_TEST_MODE */
-/*-------------------------------------------------------------------------*/
int ehci_hub_control(
struct usb_hcd *hcd,
@@ -935,7 +796,7 @@ int ehci_hub_control(
break;
#ifdef CONFIG_USB_OTG
if ((hcd->self.otg_port == (wIndex + 1))
- && hcd->self.b_hnp_enable) {
+ && hcd->self.b_hnp_enable && !hcd->self.otg_fsm) {
otg_start_hnp(hcd->usb_phy->otg);
break;
}
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index 4de43011df23..9b7e63977215 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -138,7 +138,7 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci)
ehci->sitd_pool = NULL;
if (ehci->periodic)
- dma_free_coherent (ehci_to_hcd(ehci)->self.controller,
+ dma_free_coherent(ehci_to_hcd(ehci)->self.sysdev,
ehci->periodic_size * sizeof (u32),
ehci->periodic, ehci->periodic_dma);
ehci->periodic = NULL;
@@ -155,7 +155,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
/* QTDs for control/bulk/intr transfers */
ehci->qtd_pool = dma_pool_create ("ehci_qtd",
- ehci_to_hcd(ehci)->self.controller,
+ ehci_to_hcd(ehci)->self.sysdev,
sizeof (struct ehci_qtd),
32 /* byte alignment (for hw parts) */,
4096 /* can't cross 4K */);
@@ -165,7 +165,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
/* QHs for control/bulk/intr transfers */
ehci->qh_pool = dma_pool_create ("ehci_qh",
- ehci_to_hcd(ehci)->self.controller,
+ ehci_to_hcd(ehci)->self.sysdev,
sizeof(struct ehci_qh_hw),
32 /* byte alignment (for hw parts) */,
4096 /* can't cross 4K */);
@@ -179,7 +179,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
/* ITD for high speed ISO transfers */
ehci->itd_pool = dma_pool_create ("ehci_itd",
- ehci_to_hcd(ehci)->self.controller,
+ ehci_to_hcd(ehci)->self.sysdev,
sizeof (struct ehci_itd),
32 /* byte alignment (for hw parts) */,
4096 /* can't cross 4K */);
@@ -189,7 +189,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
/* SITD for full/low speed split ISO transfers */
ehci->sitd_pool = dma_pool_create ("ehci_sitd",
- ehci_to_hcd(ehci)->self.controller,
+ ehci_to_hcd(ehci)->self.sysdev,
sizeof (struct ehci_sitd),
32 /* byte alignment (for hw parts) */,
4096 /* can't cross 4K */);
@@ -199,7 +199,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
/* Hardware periodic table */
ehci->periodic = (__le32 *)
- dma_alloc_coherent (ehci_to_hcd(ehci)->self.controller,
+ dma_alloc_coherent(ehci_to_hcd(ehci)->self.sysdev,
ehci->periodic_size * sizeof(__le32),
&ehci->periodic_dma, flags);
if (ehci->periodic == NULL) {
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index eca3710d8fc4..27b53f4386bd 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -1169,7 +1169,7 @@ submit_async (
* performed; TRUE - SETUP and FALSE - IN+STATUS
* Returns 0 if success
*/
-static int submit_single_step_set_feature(
+static int ehci_submit_single_step_set_feature(
struct usb_hcd *hcd,
struct urb *urb,
int is_setup
@@ -1203,10 +1203,10 @@ static int submit_single_step_set_feature(
* 15 secs after the setup
*/
if (is_setup) {
- /* SETUP pid */
+ /* SETUP pid, and interrupt after SETUP completion */
qtd_fill(ehci, qtd, urb->setup_dma,
sizeof(struct usb_ctrlrequest),
- token | (2 /* "setup" */ << 8), 8);
+ QTD_IOC | token | (2 /* "setup" */ << 8), 8);
submit_async(ehci, urb, &qtd_list, GFP_ATOMIC);
return 0; /*Return now; we shall come back after 15 seconds*/
@@ -1243,12 +1243,8 @@ static int submit_single_step_set_feature(
qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma);
list_add_tail(&qtd->qtd_list, head);
- /* dont fill any data in such packets */
- qtd_fill(ehci, qtd, 0, 0, token, 0);
-
- /* by default, enable interrupt on urb completion */
- if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT)))
- qtd->hw_token |= cpu_to_hc32(ehci, QTD_IOC);
+ /* Interrupt after STATUS completion */
+ qtd_fill(ehci, qtd, 0, 0, token | QTD_IOC, 0);
submit_async(ehci, urb, &qtd_list, GFP_KERNEL);
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
index 3425154baf8b..faecbfbeb874 100644
--- a/drivers/usb/host/xhci-dbg.c
+++ b/drivers/usb/host/xhci-dbg.c
@@ -240,6 +240,9 @@ void xhci_print_run_regs(struct xhci_hcd *xhci)
xhci_dbg(xhci, " %p: Microframe index = 0x%x\n",
&xhci->run_regs->microframe_index,
(unsigned int) temp);
+ if (xhci->quirks & XHCI_SKIP_ACCESS_RESERVED_REG)
+ return;
+
for (i = 0; i < 7; ++i) {
temp = readl(&xhci->run_regs->rsvd[i]);
if (temp != XHCI_INIT_VALUE)
@@ -253,7 +256,8 @@ void xhci_print_registers(struct xhci_hcd *xhci)
{
xhci_print_cap_regs(xhci);
xhci_print_op_regs(xhci);
- xhci_print_ports(xhci);
+ if (!(xhci->quirks & XHCI_SKIP_ACCESS_RESERVED_REG))
+ xhci_print_ports(xhci);
}
void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb)
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 0722f75f1d6a..638fe817c85f 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -558,6 +558,121 @@ static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
return max_ports;
}
+static __le32 __iomem *xhci_get_port_io_addr(struct usb_hcd *hcd, int index)
+{
+ __le32 __iomem **port_array;
+
+ xhci_get_ports(hcd, &port_array);
+ return port_array[index];
+}
+
+/*
+ * xhci_set_port_power() must be called with xhci->lock held.
+ * It will release and re-aquire the lock while calling ACPI
+ * method.
+ */
+static void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd,
+ u16 index, bool on, unsigned long *flags)
+{
+ __le32 __iomem *addr;
+ u32 temp;
+
+ addr = xhci_get_port_io_addr(hcd, index);
+ temp = readl(addr);
+ temp = xhci_port_state_to_neutral(temp);
+ if (on) {
+ /* Power on */
+ writel(temp | PORT_POWER, addr);
+ temp = readl(addr);
+ xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n",
+ index, temp);
+ } else {
+ /* Power off */
+ writel(temp & ~PORT_POWER, addr);
+ }
+
+ spin_unlock_irqrestore(&xhci->lock, *flags);
+ temp = usb_acpi_power_manageable(hcd->self.root_hub,
+ index);
+ if (temp)
+ usb_acpi_set_power_state(hcd->self.root_hub,
+ index, on);
+ spin_lock_irqsave(&xhci->lock, *flags);
+}
+
+static void xhci_port_set_test_mode(struct xhci_hcd *xhci,
+ u16 test_mode, u16 wIndex)
+{
+ u32 temp;
+ __le32 __iomem *addr;
+
+ /* xhci only supports test mode for usb2 ports, i.e. xhci->main_hcd */
+ addr = xhci_get_port_io_addr(xhci->main_hcd, wIndex);
+ temp = readl(addr + PORTPMSC);
+ temp |= test_mode << PORT_TEST_MODE_SHIFT;
+ writel(temp, addr + PORTPMSC);
+ xhci->test_mode = test_mode;
+ if (test_mode == TEST_FORCE_EN)
+ xhci_start(xhci);
+}
+
+static int xhci_enter_test_mode(struct xhci_hcd *xhci,
+ u16 test_mode, u16 wIndex, unsigned long *flags)
+{
+ int i, retval;
+
+ /* Disable all Device Slots */
+ xhci_dbg(xhci, "Disable all slots\n");
+ spin_unlock_irqrestore(&xhci->lock, *flags);
+ for (i = 1; i <= HCS_MAX_SLOTS(xhci->hcs_params1); i++) {
+ retval = xhci_disable_slot(xhci, NULL, i);
+ if (retval)
+ xhci_err(xhci, "Failed to disable slot %d, %d. Enter test mode anyway\n",
+ i, retval);
+ }
+ spin_lock_irqsave(&xhci->lock, *flags);
+ /* Put all ports to the Disable state by clear PP */
+ xhci_dbg(xhci, "Disable all port (PP = 0)\n");
+ /* Power off USB3 ports*/
+ for (i = 0; i < xhci->num_usb3_ports; i++)
+ xhci_set_port_power(xhci, xhci->shared_hcd, i, false, flags);
+ /* Power off USB2 ports*/
+ for (i = 0; i < xhci->num_usb2_ports; i++)
+ xhci_set_port_power(xhci, xhci->main_hcd, i, false, flags);
+ /* Stop the controller */
+ xhci_dbg(xhci, "Stop controller\n");
+ retval = xhci_halt(xhci);
+ if (retval)
+ return retval;
+ /* Disable runtime PM for test mode */
+ pm_runtime_forbid(xhci_to_hcd(xhci)->self.controller);
+ /* Set PORTPMSC.PTC field to enter selected test mode */
+ /* Port is selected by wIndex. port_id = wIndex + 1 */
+ xhci_dbg(xhci, "Enter Test Mode: %d, Port_id=%d\n",
+ test_mode, wIndex + 1);
+ xhci_port_set_test_mode(xhci, test_mode, wIndex);
+ return retval;
+}
+
+static int xhci_exit_test_mode(struct xhci_hcd *xhci)
+{
+ int retval;
+
+ if (!xhci->test_mode) {
+ xhci_err(xhci, "Not in test mode, do nothing.\n");
+ return 0;
+ }
+ if (xhci->test_mode == TEST_FORCE_EN &&
+ !(xhci->xhc_state & XHCI_STATE_HALTED)) {
+ retval = xhci_halt(xhci);
+ if (retval)
+ return retval;
+ }
+ pm_runtime_allow(xhci_to_hcd(xhci)->self.controller);
+ xhci->test_mode = 0;
+ return xhci_reset(xhci);
+}
+
void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
int port_id, u32 link_state)
{
@@ -916,6 +1031,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 link_state = 0;
u16 wake_mask = 0;
u16 timeout = 0;
+ u16 test_mode = 0;
max_ports = xhci_get_ports(hcd, &port_array);
bus_state = &xhci->bus_state[hcd_index(hcd)];
@@ -989,6 +1105,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
link_state = (wIndex & 0xff00) >> 3;
if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK)
wake_mask = wIndex & 0xff00;
+ if (wValue == USB_PORT_FEAT_TEST)
+ test_mode = (wIndex & 0xff00) >> 8;
/* The MSB of wIndex is the U1/U2 timeout */
timeout = (wIndex & 0xff00) >> 8;
wIndex &= 0xff;
@@ -1114,18 +1232,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
* However, hub_wq will ignore the roothub events until
* the roothub is registered.
*/
- writel(temp | PORT_POWER, port_array[wIndex]);
-
- temp = readl(port_array[wIndex]);
- xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp);
-
- spin_unlock_irqrestore(&xhci->lock, flags);
- temp = usb_acpi_power_manageable(hcd->self.root_hub,
- wIndex);
- if (temp)
- usb_acpi_set_power_state(hcd->self.root_hub,
- wIndex, true);
- spin_lock_irqsave(&xhci->lock, flags);
+ xhci_set_port_power(xhci, hcd, wIndex, true, &flags);
break;
case USB_PORT_FEAT_RESET:
temp = (temp | PORT_RESET);
@@ -1164,6 +1271,24 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp |= PORT_U2_TIMEOUT(timeout);
writel(temp, port_array[wIndex] + PORTPMSC);
break;
+ case USB_PORT_FEAT_TEST:
+ /* 4.19.6 Port Test Modes (USB2 Test Mode) */
+ if (hcd->speed != HCD_USB2)
+ goto error;
+#ifdef CONFIG_USB_HCD_TEST_MODE
+ if (test_mode == EHSET_TEST_SINGLE_STEP_SET_FEATURE) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ retval = ehset_single_step_set_feature(hcd,
+ wIndex + 1);
+ spin_lock_irqsave(&xhci->lock, flags);
+ break;
+ }
+#endif
+ if (test_mode > TEST_FORCE_EN || test_mode < TEST_J)
+ goto error;
+ retval = xhci_enter_test_mode(xhci, test_mode, wIndex,
+ &flags);
+ break;
default:
goto error;
}
@@ -1229,15 +1354,10 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
port_array[wIndex], temp);
break;
case USB_PORT_FEAT_POWER:
- writel(temp & ~PORT_POWER, port_array[wIndex]);
-
- spin_unlock_irqrestore(&xhci->lock, flags);
- temp = usb_acpi_power_manageable(hcd->self.root_hub,
- wIndex);
- if (temp)
- usb_acpi_set_power_state(hcd->self.root_hub,
- wIndex, false);
- spin_lock_irqsave(&xhci->lock, flags);
+ xhci_set_port_power(xhci, hcd, wIndex, false, &flags);
+ break;
+ case USB_PORT_FEAT_TEST:
+ retval = xhci_exit_test_mode(xhci);
break;
default:
goto error;
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 7199e400fbac..436e787d95b4 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -586,7 +586,7 @@ static void xhci_free_stream_ctx(struct xhci_hcd *xhci,
unsigned int num_stream_ctxs,
struct xhci_stream_ctx *stream_ctx, dma_addr_t dma)
{
- struct device *dev = xhci_to_hcd(xhci)->self.controller;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs;
if (size > MEDIUM_STREAM_ARRAY_SIZE)
@@ -614,7 +614,7 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci,
unsigned int num_stream_ctxs, dma_addr_t *dma,
gfp_t mem_flags)
{
- struct device *dev = xhci_to_hcd(xhci)->self.controller;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs;
if (size > MEDIUM_STREAM_ARRAY_SIZE)
@@ -1706,7 +1706,7 @@ void xhci_slot_copy(struct xhci_hcd *xhci,
static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
{
int i;
- struct device *dev = xhci_to_hcd(xhci)->self.controller;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
int num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2);
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
@@ -1729,36 +1729,27 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
if (!xhci->scratchpad->sp_buffers)
goto fail_sp3;
- xhci->scratchpad->sp_dma_buffers =
- kzalloc(sizeof(dma_addr_t) * num_sp, flags);
-
- if (!xhci->scratchpad->sp_dma_buffers)
- goto fail_sp4;
-
xhci->dcbaa->dev_context_ptrs[0] = cpu_to_le64(xhci->scratchpad->sp_dma);
for (i = 0; i < num_sp; i++) {
dma_addr_t dma;
void *buf = dma_zalloc_coherent(dev, xhci->page_size, &dma,
flags);
if (!buf)
- goto fail_sp5;
+ goto fail_sp4;
xhci->scratchpad->sp_array[i] = dma;
xhci->scratchpad->sp_buffers[i] = buf;
- xhci->scratchpad->sp_dma_buffers[i] = dma;
}
return 0;
- fail_sp5:
+ fail_sp4:
for (i = i - 1; i >= 0; i--) {
dma_free_coherent(dev, xhci->page_size,
xhci->scratchpad->sp_buffers[i],
- xhci->scratchpad->sp_dma_buffers[i]);
+ xhci->scratchpad->sp_array[i]);
}
- kfree(xhci->scratchpad->sp_dma_buffers);
- fail_sp4:
kfree(xhci->scratchpad->sp_buffers);
fail_sp3:
@@ -1778,7 +1769,7 @@ static void scratchpad_free(struct xhci_hcd *xhci)
{
int num_sp;
int i;
- struct device *dev = xhci_to_hcd(xhci)->self.controller;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
if (!xhci->scratchpad)
return;
@@ -1788,9 +1779,8 @@ static void scratchpad_free(struct xhci_hcd *xhci)
for (i = 0; i < num_sp; i++) {
dma_free_coherent(dev, xhci->page_size,
xhci->scratchpad->sp_buffers[i],
- xhci->scratchpad->sp_dma_buffers[i]);
+ xhci->scratchpad->sp_array[i]);
}
- kfree(xhci->scratchpad->sp_dma_buffers);
kfree(xhci->scratchpad->sp_buffers);
dma_free_coherent(dev, num_sp * sizeof(u64),
xhci->scratchpad->sp_array,
@@ -1854,7 +1844,7 @@ void xhci_free_command(struct xhci_hcd *xhci,
void xhci_mem_cleanup(struct xhci_hcd *xhci)
{
- struct device *dev = xhci_to_hcd(xhci)->self.controller;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
int size;
int i, j, num_ports;
@@ -2399,7 +2389,7 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
{
dma_addr_t dma;
- struct device *dev = xhci_to_hcd(xhci)->self.controller;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
unsigned int val, val2;
u64 val_64;
struct xhci_segment *seg;
@@ -2445,7 +2435,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
writel(val, &xhci->op_regs->config_reg);
/*
- * Section 5.4.8 - doorbell array must be
+ * xHCI section 5.4.6 - doorbell array must be
* "physically contiguous and 64-byte (cache line) aligned".
*/
xhci->dcbaa = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), &dma,
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index ca8b0b1ae37d..248cdaa62397 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -14,11 +14,14 @@
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
+#include <linux/pci.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/usb/phy.h>
#include <linux/slab.h>
#include <linux/acpi.h>
+#include <linux/busfreq-imx.h>
+#include <linux/usb/of.h>
#include "xhci.h"
#include "xhci-plat.h"
@@ -139,6 +142,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
const struct hc_driver *driver;
+ struct device *sysdev;
struct xhci_hcd *xhci;
struct resource *res;
struct usb_hcd *hcd;
@@ -155,24 +159,47 @@ static int xhci_plat_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
+ /*
+ * sysdev must point to a device that is known to the system firmware
+ * or PCI hardware. We handle these three cases here:
+ * 1. xhci_plat comes from firmware
+ * 2. xhci_plat is child of a device from firmware (dwc3-plat)
+ * 3. xhci_plat is grandchild of a pci device (dwc3-pci)
+ */
+ sysdev = &pdev->dev;
+ if (sysdev->parent && !sysdev->of_node && sysdev->parent->of_node)
+ sysdev = sysdev->parent;
+#ifdef CONFIG_PCI
+ else if (sysdev->parent && sysdev->parent->parent &&
+ sysdev->parent->parent->bus == &pci_bus_type)
+ sysdev = sysdev->parent->parent;
+#endif
+
/* Try to set 64-bit DMA first */
- if (WARN_ON(!pdev->dev.dma_mask))
+ if (WARN_ON(!sysdev->dma_mask))
/* Platform did not initialize dma_mask */
- ret = dma_coerce_mask_and_coherent(&pdev->dev,
+ ret = dma_coerce_mask_and_coherent(sysdev,
DMA_BIT_MASK(64));
else
- ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
/* If seting 64-bit DMA mask fails, fall back to 32-bit DMA mask */
if (ret) {
- ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(32));
if (ret)
return ret;
}
- hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
- if (!hcd)
- return -ENOMEM;
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_noresume(&pdev->dev);
+
+ hcd = __usb_create_hcd(driver, sysdev, &pdev->dev,
+ dev_name(&pdev->dev), NULL);
+ if (!hcd) {
+ ret = -ENOMEM;
+ goto disable_runtime;
+ }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
@@ -213,20 +240,23 @@ static int xhci_plat_probe(struct platform_device *pdev)
xhci->clk = clk;
xhci->main_hcd = hcd;
- xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev,
+ xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev,
dev_name(&pdev->dev), hcd);
if (!xhci->shared_hcd) {
ret = -ENOMEM;
goto disable_clk;
}
- if (device_property_read_bool(&pdev->dev, "usb3-lpm-capable"))
+ if (device_property_read_bool(sysdev, "usb3-lpm-capable"))
xhci->quirks |= XHCI_LPM_SUPPORT;
+ if (device_property_read_bool(sysdev, "usb3-resume-missing-cas"))
+ xhci->quirks |= XHCI_MISSING_CAS;
+
if (device_property_read_bool(&pdev->dev, "quirk-broken-port-ped"))
xhci->quirks |= XHCI_BROKEN_PORT_PED;
- hcd->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0);
+ hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, "usb-phy", 0);
if (IS_ERR(hcd->usb_phy)) {
ret = PTR_ERR(hcd->usb_phy);
if (ret == -EPROBE_DEFER)
@@ -238,6 +268,10 @@ static int xhci_plat_probe(struct platform_device *pdev)
goto put_usb3_hcd;
}
+ request_bus_freq(BUS_FREQ_HIGH);
+ hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node);
+ xhci->shared_hcd->tpl_support = hcd->tpl_support;
+
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret)
goto disable_usb_phy;
@@ -249,6 +283,9 @@ static int xhci_plat_probe(struct platform_device *pdev)
if (ret)
goto dealloc_usb2_hcd;
+ device_enable_async_suspend(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+
return 0;
@@ -257,6 +294,7 @@ dealloc_usb2_hcd:
disable_usb_phy:
usb_phy_shutdown(hcd->usb_phy);
+ release_bus_freq(BUS_FREQ_HIGH);
put_usb3_hcd:
usb_put_hcd(xhci->shared_hcd);
@@ -268,6 +306,10 @@ disable_clk:
put_hcd:
usb_put_hcd(hcd);
+disable_runtime:
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
return ret;
}
@@ -289,6 +331,12 @@ static int xhci_plat_remove(struct platform_device *dev)
clk_disable_unprepare(clk);
usb_put_hcd(hcd);
+ if (!pm_runtime_suspended(&dev->dev))
+ release_bus_freq(BUS_FREQ_HIGH);
+
+ pm_runtime_set_suspended(&dev->dev);
+ pm_runtime_disable(&dev->dev);
+
return 0;
}
@@ -316,14 +364,29 @@ static int xhci_plat_resume(struct device *dev)
return xhci_resume(xhci, 0);
}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+static int xhci_plat_runtime_suspend(struct device *dev)
+{
+ release_bus_freq(BUS_FREQ_HIGH);
+ return 0;
+}
+
+static int xhci_plat_runtime_resume(struct device *dev)
+{
+ request_bus_freq(BUS_FREQ_HIGH);
+ return 0;
+}
+#endif /* CONFIG_PM */
static const struct dev_pm_ops xhci_plat_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(xhci_plat_suspend, xhci_plat_resume)
+
+ SET_RUNTIME_PM_OPS(xhci_plat_runtime_suspend,
+ xhci_plat_runtime_resume,
+ NULL)
};
-#define DEV_PM_OPS (&xhci_plat_pm_ops)
-#else
-#define DEV_PM_OPS NULL
-#endif /* CONFIG_PM */
static const struct acpi_device_id usb_xhci_acpi_match[] = {
/* XHCI-compliant USB Controller */
@@ -337,7 +400,7 @@ static struct platform_driver usb_xhci_driver = {
.remove = xhci_plat_remove,
.driver = {
.name = "xhci-hcd",
- .pm = DEV_PM_OPS,
+ .pm = &xhci_plat_pm_ops,
.of_match_table = of_match_ptr(usb_xhci_of_match),
.acpi_match_table = ACPI_PTR(usb_xhci_acpi_match),
},
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 89a14d5f6ad8..806816401f59 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1968,9 +1968,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
switch (trb_comp_code) {
case COMP_SUCCESS:
if (event_trb == ep_ring->dequeue) {
- xhci_warn(xhci, "WARN: Success on ctrl setup TRB "
- "without IOC set??\n");
- *status = -ESHUTDOWN;
+ *status = 0;
} else if (event_trb != td->last_trb) {
xhci_warn(xhci, "WARN: Success on ctrl data TRB "
"without IOC set??\n");
@@ -2770,12 +2768,9 @@ hw_died:
*/
status |= STS_EINT;
writel(status, &xhci->op_regs->status);
- /* FIXME when MSI-X is supported and there are multiple vectors */
- /* Clear the MSI-X event interrupt status */
- if (hcd->irq) {
+ if (!hcd->msi_enabled) {
u32 irq_pending;
- /* Acknowledge the PCI interrupt */
irq_pending = readl(&xhci->ir_set->irq_pending);
irq_pending |= IMAN_IP;
writel(irq_pending, &xhci->ir_set->irq_pending);
@@ -3488,6 +3483,135 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
return 0;
}
+#ifdef CONFIG_USB_HCD_TEST_MODE
+/*
+ * This function prepare TRBs and submits them for the
+ * SINGLE_STEP_SET_FEATURE Test.
+ * This is done in two parts: first SETUP req for GetDesc is sent then
+ * 15 seconds later, the IN stage for GetDesc starts to req data from dev
+ *
+ * is_setup : argument decides which of the two stage needs to be
+ * performed; TRUE - SETUP and FALSE - IN+STATUS
+ * Returns 0 if success
+ */
+int xhci_submit_single_step_set_feature(struct usb_hcd *hcd,
+ struct urb *urb, int is_setup)
+{
+ int slot_id;
+ unsigned int ep_index;
+ struct xhci_ring *ep_ring;
+ int ret;
+ struct usb_ctrlrequest *setup;
+ struct xhci_generic_trb *start_trb;
+ int start_cycle;
+ u32 field, length_field, remainder;
+ struct urb_priv *urb_priv;
+ struct xhci_td *td;
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ /* urb_priv will be free after transcation has completed */
+ urb_priv = kzalloc(sizeof(struct urb_priv) +
+ sizeof(struct xhci_td *), GFP_KERNEL);
+ if (!urb_priv)
+ return -ENOMEM;
+
+ td = kzalloc(sizeof(struct xhci_td), GFP_KERNEL);
+ if (!td) {
+ kfree(urb_priv);
+ return -ENOMEM;
+ }
+
+ urb_priv->td[0] = td;
+ urb_priv->length = 1;
+ urb_priv->td_cnt = 0;
+ urb->hcpriv = urb_priv;
+
+ ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
+ if (!ep_ring) {
+ ret = -EINVAL;
+ goto free_priv;
+ }
+
+ slot_id = urb->dev->slot_id;
+ ep_index = xhci_get_endpoint_index(&urb->ep->desc);
+
+ setup = (struct usb_ctrlrequest *) urb->setup_packet;
+ if (is_setup) {
+ ret = prepare_transfer(xhci, xhci->devs[slot_id],
+ ep_index, urb->stream_id,
+ 1, urb, 0, GFP_KERNEL);
+ if (ret < 0)
+ goto free_priv;
+
+ start_trb = &ep_ring->enqueue->generic;
+ start_cycle = ep_ring->cycle_state;
+ /* Save the DMA address of the last TRB in the TD */
+ td->last_trb = ep_ring->enqueue;
+ field = TRB_IOC | TRB_IDT | TRB_TYPE(TRB_SETUP) | start_cycle;
+ /* xHCI 1.0/1.1 6.4.1.2.1: Transfer Type field */
+ if ((xhci->hci_version >= 0x100) ||
+ (xhci->quirks & XHCI_MTK_HOST))
+ field |= TRB_TX_TYPE(TRB_DATA_IN);
+
+ queue_trb(xhci, ep_ring, false,
+ setup->bRequestType | setup->bRequest << 8 |
+ le16_to_cpu(setup->wValue) << 16,
+ le16_to_cpu(setup->wIndex) |
+ le16_to_cpu(setup->wLength) << 16,
+ TRB_LEN(8) | TRB_INTR_TARGET(0),
+ /* Immediate data in pointer */
+ field);
+ giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
+ start_cycle, start_trb);
+ return 0;
+ }
+
+ ret = prepare_transfer(xhci, xhci->devs[slot_id],
+ ep_index, urb->stream_id,
+ 2, urb, 0, GFP_KERNEL);
+ if (ret < 0)
+ goto free_priv;
+
+ start_trb = &ep_ring->enqueue->generic;
+ start_cycle = ep_ring->cycle_state;
+ field = TRB_ISP | TRB_TYPE(TRB_DATA);
+
+ remainder = xhci_td_remainder(xhci, 0,
+ urb->transfer_buffer_length,
+ urb->transfer_buffer_length,
+ urb, 1);
+
+ length_field = TRB_LEN(urb->transfer_buffer_length) |
+ TRB_TD_SIZE(remainder) |
+ TRB_INTR_TARGET(0);
+
+ if (urb->transfer_buffer_length > 0) {
+ field |= TRB_DIR_IN;
+ queue_trb(xhci, ep_ring, true,
+ lower_32_bits(urb->transfer_dma),
+ upper_32_bits(urb->transfer_dma),
+ length_field,
+ field | ep_ring->cycle_state);
+ }
+
+ td->last_trb = ep_ring->enqueue;
+ field = TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state;
+ queue_trb(xhci, ep_ring, false,
+ 0,
+ 0,
+ TRB_INTR_TARGET(0),
+ field);
+
+ giveback_first_trb(xhci, slot_id, ep_index, 0,
+ start_cycle, start_trb);
+
+ return 0;
+free_priv:
+ xhci_urb_free_priv(urb_priv);
+ return ret;
+}
+#endif /* CONFIG_USB_HCD_TEST_MODE */
+
/*
* The transfer burst count field of the isochronous TRB defines the number of
* bursts that are required to move all packets in this TD. Only SuperSpeed
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index e9f5f9c32b49..dbf7bd4582e1 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -125,7 +125,7 @@ int xhci_halt(struct xhci_hcd *xhci)
/*
* Set the run bit and wait for the host to be running.
*/
-static int xhci_start(struct xhci_hcd *xhci)
+int xhci_start(struct xhci_hcd *xhci)
{
u32 temp;
int ret;
@@ -184,7 +184,7 @@ int xhci_reset(struct xhci_hcd *xhci)
* Without this delay, the subsequent HC register access,
* may result in a system hang very rarely.
*/
- if (xhci->quirks & XHCI_INTEL_HOST)
+ if (xhci->quirks & (XHCI_INTEL_HOST | XHCI_CDNS_HOST))
udelay(1000);
ret = xhci_handshake(&xhci->op_regs->command,
@@ -234,6 +234,9 @@ static int xhci_free_msi(struct xhci_hcd *xhci)
static int xhci_setup_msi(struct xhci_hcd *xhci)
{
int ret;
+ /*
+ * TODO:Check with MSI Soc for sysdev
+ */
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
ret = pci_enable_msi(pdev);
@@ -260,7 +263,7 @@ static int xhci_setup_msi(struct xhci_hcd *xhci)
*/
static void xhci_free_irq(struct xhci_hcd *xhci)
{
- struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+ struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.sysdev);
int ret;
/* return if using legacy interrupt */
@@ -395,9 +398,10 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)
/* fall back to msi*/
ret = xhci_setup_msi(xhci);
- if (!ret)
- /* hcd->irq is 0, we have MSI */
+ if (!ret) {
+ hcd->msi_enabled = 1;
return 0;
+ }
if (!pdev->irq) {
xhci_err(xhci, "No msi-x/msi found and no IRQ in BIOS\n");
@@ -746,7 +750,7 @@ void xhci_shutdown(struct usb_hcd *hcd)
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
if (xhci->quirks & XHCI_SPURIOUS_REBOOT)
- usb_disable_xhci_ports(to_pci_dev(hcd->self.controller));
+ usb_disable_xhci_ports(to_pci_dev(hcd->self.sysdev));
spin_lock_irq(&xhci->lock);
xhci_halt(xhci);
@@ -763,7 +767,7 @@ void xhci_shutdown(struct usb_hcd *hcd)
/* Yet another workaround for spurious wakeups at shutdown with HSW */
if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
- pci_set_power_state(to_pci_dev(hcd->self.controller), PCI_D3hot);
+ pci_set_power_state(to_pci_dev(hcd->self.sysdev), PCI_D3hot);
}
#ifdef CONFIG_PM
@@ -3619,8 +3623,6 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct xhci_virt_device *virt_dev;
- unsigned long flags;
- u32 state;
int i, ret;
struct xhci_command *command;
@@ -3655,6 +3657,29 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
del_timer_sync(&virt_dev->eps[i].stop_cmd_timer);
}
+ xhci_disable_slot(xhci, command, udev->slot_id);
+ /*
+ * Event command completion handler will free any data structures
+ * associated with the slot. XXX Can free sleep?
+ */
+}
+
+int xhci_disable_slot(struct xhci_hcd *xhci, struct xhci_command *command,
+ u32 slot_id)
+{
+ unsigned long flags;
+ u32 state;
+ int ret = 0;
+ struct xhci_virt_device *virt_dev;
+
+ virt_dev = xhci->devs[slot_id];
+ if (!virt_dev)
+ return -EINVAL;
+ if (!command)
+ command = xhci_alloc_command(xhci, false, false, GFP_KERNEL);
+ if (!command)
+ return -ENOMEM;
+
spin_lock_irqsave(&xhci->lock, flags);
virt_dev->udev = NULL;
@@ -3663,25 +3688,22 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
state = readl(&xhci->op_regs->status);
if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||
(xhci->xhc_state & XHCI_STATE_HALTED)) {
- xhci_free_virt_device(xhci, udev->slot_id);
+ xhci_free_virt_device(xhci, slot_id);
spin_unlock_irqrestore(&xhci->lock, flags);
kfree(command);
- return;
+ return ret;
}
- if (xhci_queue_slot_control(xhci, command, TRB_DISABLE_SLOT,
- udev->slot_id)) {
+ ret = xhci_queue_slot_control(xhci, command, TRB_DISABLE_SLOT,
+ slot_id);
+ if (ret) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
- return;
+ return ret;
}
xhci_ring_cmd_db(xhci);
spin_unlock_irqrestore(&xhci->lock, flags);
-
- /*
- * Event command completion handler will free any data structures
- * associated with the slot. XXX Can free sleep?
- */
+ return ret;
}
/*
@@ -3789,14 +3811,10 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
disable_slot:
/* Disable slot, if we can do it without mem alloc */
- spin_lock_irqsave(&xhci->lock, flags);
+ kfree(command->completion);
command->completion = NULL;
command->status = 0;
- if (!xhci_queue_slot_control(xhci, command, TRB_DISABLE_SLOT,
- udev->slot_id))
- xhci_ring_cmd_db(xhci);
- spin_unlock_irqrestore(&xhci->lock, flags);
- return 0;
+ return xhci_disable_slot(xhci, command, udev->slot_id);
}
/*
@@ -4869,7 +4887,11 @@ int xhci_get_frame(struct usb_hcd *hcd)
int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
{
struct xhci_hcd *xhci;
- struct device *dev = hcd->self.controller;
+ /*
+ * TODO: Check with DWC3 clients for sysdev according to
+ * quirks
+ */
+ struct device *dev = hcd->self.sysdev;
int retval;
/* Accept arbitrarily long scatter-gather lists */
@@ -5050,6 +5072,7 @@ static const struct hc_driver xhci_hc_driver = {
.enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout,
.disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout,
.find_raw_port_number = xhci_find_raw_port_number,
+ .submit_single_step_set_feature = xhci_submit_single_step_set_feature,
};
void xhci_init_driver(struct hc_driver *drv,
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index b9181281aa9e..a6dd4d97a179 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -429,6 +429,7 @@ struct xhci_op_regs {
#define PORT_L1DS_MASK (0xff << 8)
#define PORT_L1DS(p) (((p) & 0xff) << 8)
#define PORT_HLE (1 << 16)
+#define PORT_TEST_MODE_SHIFT 28
/* USB3 Protocol PORTLI Port Link Information */
#define PORT_RX_LANES(p) (((p) >> 16) & 0xf)
@@ -1444,7 +1445,6 @@ struct xhci_scratchpad {
u64 *sp_array;
dma_addr_t sp_dma;
void **sp_buffers;
- dma_addr_t *sp_dma_buffers;
};
struct urb_priv {
@@ -1666,6 +1666,8 @@ struct xhci_hcd {
#define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26)
/* Reserved. It was XHCI_U2_DISABLE_WAKE */
#define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28)
+#define XHCI_SKIP_ACCESS_RESERVED_REG (1 << 29)
+#define XHCI_CDNS_HOST (1 << 30)
unsigned int num_active_eps;
unsigned int limit_active_eps;
@@ -1691,6 +1693,7 @@ struct xhci_hcd {
/* Compliance Mode Recovery Data */
struct timer_list comp_mode_recovery_timer;
u32 port_status_u0;
+ u16 test_mode;
/* Compliance Mode Timer Triggered every 2 seconds */
#define COMP_MODE_RCVRY_MSECS 2000
@@ -1858,6 +1861,7 @@ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec);
void xhci_quiesce(struct xhci_hcd *xhci);
int xhci_halt(struct xhci_hcd *xhci);
+int xhci_start(struct xhci_hcd *xhci);
int xhci_reset(struct xhci_hcd *xhci);
int xhci_init(struct usb_hcd *hcd);
int xhci_run(struct usb_hcd *hcd);
@@ -1866,6 +1870,8 @@ void xhci_shutdown(struct usb_hcd *hcd);
int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks);
void xhci_init_driver(struct hc_driver *drv,
const struct xhci_driver_overrides *over);
+int xhci_disable_slot(struct xhci_hcd *xhci,
+ struct xhci_command *command, u32 slot_id);
#ifdef CONFIG_PM
int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup);
@@ -1971,6 +1977,16 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
char *buf, u16 wLength);
int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);
+#ifdef CONFIG_USB_HCD_TEST_MODE
+int xhci_submit_single_step_set_feature(struct usb_hcd *hcd,
+ struct urb *urb, int is_setup);
+#else
+static inline int xhci_submit_single_step_set_feature(struct usb_hcd *hcd,
+ struct urb *urb, int is_setup)
+{
+ return 0;
+}
+#endif
#ifdef CONFIG_PM
int xhci_bus_suspend(struct usb_hcd *hcd);
diff --git a/drivers/usb/misc/ehset.c b/drivers/usb/misc/ehset.c
index c31b4a33e6bb..f54473cd25b3 100644
--- a/drivers/usb/misc/ehset.c
+++ b/drivers/usb/misc/ehset.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/usb/ch11.h>
+#include <linux/usb/otg-fsm.h>
#define TEST_SE0_NAK_PID 0x0101
#define TEST_J_PID 0x0102
@@ -25,6 +26,7 @@
#define TEST_HS_HOST_PORT_SUSPEND_RESUME 0x0106
#define TEST_SINGLE_STEP_GET_DEV_DESC 0x0107
#define TEST_SINGLE_STEP_SET_FEATURE 0x0108
+#define TEST_OTG_TEST_DEVICE_SUPPORT 0x0200
static int ehset_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -35,6 +37,7 @@ static int ehset_probe(struct usb_interface *intf,
struct usb_device_descriptor *buf;
u8 portnum = dev->portnum;
u16 test_pid = le16_to_cpu(dev->descriptor.idProduct);
+ struct otg_fsm *fsm = dev->bus->otg_fsm;
switch (test_pid) {
case TEST_SE0_NAK_PID:
@@ -115,6 +118,27 @@ static int ehset_probe(struct usb_interface *intf,
NULL, 0, 60 * 1000);
break;
+ case TEST_OTG_TEST_DEVICE_SUPPORT:
+ if (!fsm)
+ return ret;
+
+ /* B host enumerate test device */
+ if (dev->bus->is_b_host) {
+ otg_add_timer(fsm, B_TST_SUSP);
+ ret = 0;
+ break;
+ }
+
+ mutex_lock(&fsm->lock);
+ fsm->tst_maint = 1;
+ if (le16_to_cpu(dev->descriptor.bcdDevice) & 0x1)
+ fsm->otg_vbus_off = 1;
+ else
+ fsm->otg_vbus_off = 0;
+ mutex_unlock(&fsm->lock);
+ otg_add_timer(fsm, A_TST_MAINT);
+ ret = 0;
+ break;
default:
dev_err(&intf->dev, "%s: unsupported PID: 0x%x\n",
__func__, test_pid);
@@ -135,6 +159,7 @@ static const struct usb_device_id ehset_id_table[] = {
{ USB_DEVICE(0x1a0a, TEST_HS_HOST_PORT_SUSPEND_RESUME) },
{ USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_GET_DEV_DESC) },
{ USB_DEVICE(0x1a0a, TEST_SINGLE_STEP_SET_FEATURE) },
+ { USB_DEVICE(0x1a0a, TEST_OTG_TEST_DEVICE_SUPPORT) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, ehset_id_table);
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 125cea1c3c8d..2c60f0cab568 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -187,7 +187,7 @@ config USB_MV_OTG
config USB_MXS_PHY
tristate "Freescale MXS USB PHY support"
- depends on ARCH_MXC || ARCH_MXS
+ depends on ARCH_MXC || ARCH_MXS || ARCH_MXC_ARM64
select STMP_DEVICE
select USB_PHY
help
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index 8311ba2968cd..cdc6f862dcdb 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -59,6 +59,16 @@ EXPORT_SYMBOL_GPL(usb_phy_generic_unregister);
static int nop_set_suspend(struct usb_phy *x, int suspend)
{
+ struct usb_phy_generic *nop = dev_get_drvdata(x->dev);
+
+ if (IS_ERR(nop->clk))
+ return 0;
+
+ if (suspend)
+ clk_disable_unprepare(nop->clk);
+ else
+ clk_prepare_enable(nop->clk);
+
return 0;
}
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index 0e2f1a36d315..92b94341b1b4 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -1,5 +1,6 @@
/*
- * Copyright 2012-2014 Freescale Semiconductor, Inc.
+ * Copyright 2012-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
* Copyright (C) 2012 Marek Vasut <marex@denx.de>
* on behalf of DENX Software Engineering GmbH
*
@@ -23,9 +24,11 @@
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
+#include <linux/regulator/consumer.h>
#define DRIVER_NAME "mxs_phy"
+/* Register Macro */
#define HW_USBPHY_PWD 0x00
#define HW_USBPHY_TX 0x10
#define HW_USBPHY_CTRL 0x30
@@ -43,6 +46,11 @@
#define GM_USBPHY_TX_TXCAL45DN(x) (((x) & 0xf) << 8)
#define GM_USBPHY_TX_D_CAL(x) (((x) & 0xf) << 0)
+/* imx7ulp */
+#define HW_USBPHY_PLL_SIC 0xa4
+#define HW_USBPHY_PLL_SIC_SET 0xa4
+#define HW_USBPHY_PLL_SIC_CLR 0xa8
+
#define BM_USBPHY_CTRL_SFTRST BIT(31)
#define BM_USBPHY_CTRL_CLKGATE BIT(30)
#define BM_USBPHY_CTRL_OTG_ID_VALUE BIT(27)
@@ -61,8 +69,20 @@
#define BM_USBPHY_IP_FIX (BIT(17) | BIT(18))
#define BM_USBPHY_DEBUG_CLKGATE BIT(30)
+/* imx7ulp */
+#define BM_USBPHY_PLL_LOCK BIT(31)
+#define BM_USBPHY_PLL_REG_ENABLE BIT(21)
+#define BM_USBPHY_PLL_BYPASS BIT(16)
+#define BM_USBPHY_PLL_POWER BIT(12)
+#define BM_USBPHY_PLL_EN_USB_CLKS BIT(6)
/* Anatop Registers */
+#define ANADIG_PLL_USB2 0x20
+#define ANADIG_PLL_USB2_SET 0x24
+#define ANADIG_PLL_USB2_CLR 0x28
+#define ANADIG_REG_1P1_SET 0x114
+#define ANADIG_REG_1P1_CLR 0x118
+
#define ANADIG_ANA_MISC0 0x150
#define ANADIG_ANA_MISC0_SET 0x154
#define ANADIG_ANA_MISC0_CLR 0x158
@@ -94,6 +114,11 @@
#define BM_ANADIG_USB2_MISC_RX_VPIN_FS BIT(29)
#define BM_ANADIG_USB2_MISC_RX_VMIN_FS BIT(28)
+#define BM_ANADIG_REG_1P1_ENABLE_WEAK_LINREG BIT(18)
+#define BM_ANADIG_REG_1P1_TRACK_VDD_SOC_CAP BIT(19)
+
+#define BM_ANADIG_PLL_USB2_HOLD_RING_OFF BIT(11)
+
#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
/* Do disconnection between PHY and controller without vbus */
@@ -126,6 +151,16 @@
#define MXS_PHY_TX_D_CAL_MIN 79
#define MXS_PHY_TX_D_CAL_MAX 119
+/*
+ * At some versions, the PHY2's clock is controlled by hardware directly,
+ * eg, according to PHY's suspend status. In these PHYs, we only need to
+ * open the clock at the initialization and close it at its shutdown routine.
+ * It will be benefit for remote wakeup case which needs to send resume
+ * signal as soon as possible, and in this case, the resume signal can be sent
+ * out without software interfere.
+ */
+#define MXS_PHY_HARDWARE_CONTROL_PHY2_CLK BIT(4)
+
struct mxs_phy_data {
unsigned int flags;
};
@@ -137,12 +172,14 @@ static const struct mxs_phy_data imx23_phy_data = {
static const struct mxs_phy_data imx6q_phy_data = {
.flags = MXS_PHY_SENDING_SOF_TOO_FAST |
MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
- MXS_PHY_NEED_IP_FIX,
+ MXS_PHY_NEED_IP_FIX |
+ MXS_PHY_HARDWARE_CONTROL_PHY2_CLK,
};
static const struct mxs_phy_data imx6sl_phy_data = {
.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
- MXS_PHY_NEED_IP_FIX,
+ MXS_PHY_NEED_IP_FIX |
+ MXS_PHY_HARDWARE_CONTROL_PHY2_CLK,
};
static const struct mxs_phy_data vf610_phy_data = {
@@ -151,14 +188,21 @@ static const struct mxs_phy_data vf610_phy_data = {
};
static const struct mxs_phy_data imx6sx_phy_data = {
- .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
+ .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
+ MXS_PHY_HARDWARE_CONTROL_PHY2_CLK,
};
static const struct mxs_phy_data imx6ul_phy_data = {
- .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
+ .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
+ MXS_PHY_HARDWARE_CONTROL_PHY2_CLK,
+};
+
+static const struct mxs_phy_data imx7ulp_phy_data = {
};
static const struct of_device_id mxs_phy_dt_ids[] = {
+ { .compatible = "fsl,imx7ulp-usbphy", .data = &imx7ulp_phy_data, },
+ { .compatible = "fsl,imx6ul-usbphy", .data = &imx6sx_phy_data, },
{ .compatible = "fsl,imx6sx-usbphy", .data = &imx6sx_phy_data, },
{ .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, },
{ .compatible = "fsl,imx6q-usbphy", .data = &imx6q_phy_data, },
@@ -177,6 +221,9 @@ struct mxs_phy {
int port_id;
u32 tx_reg_set;
u32 tx_reg_mask;
+ struct regulator *phy_3p0;
+ bool hardware_control_phy2_clk;
+ enum usb_current_mode mode;
};
static inline bool is_imx6q_phy(struct mxs_phy *mxs_phy)
@@ -189,6 +236,16 @@ static inline bool is_imx6sl_phy(struct mxs_phy *mxs_phy)
return mxs_phy->data == &imx6sl_phy_data;
}
+static inline bool is_imx6ul_phy(struct mxs_phy *mxs_phy)
+{
+ return mxs_phy->data == &imx6ul_phy_data;
+}
+
+static inline bool is_imx7ulp_phy(struct mxs_phy *mxs_phy)
+{
+ return mxs_phy->data == &imx7ulp_phy_data;
+}
+
/*
* PHY needs some 32K cycles to switch from 32K clock to
* bus (such as AHB/AXI, etc) clock.
@@ -212,14 +269,69 @@ static void mxs_phy_tx_init(struct mxs_phy *mxs_phy)
}
}
+static int wait_for_pll_lock(const void __iomem *base)
+{
+ int loop_count = 100;
+
+ /* Wait for PLL to lock */
+ do {
+ if (readl(base + HW_USBPHY_PLL_SIC) & BM_USBPHY_PLL_LOCK)
+ break;
+ usleep_range(100, 150);
+ } while (loop_count-- > 0);
+
+ return readl(base + HW_USBPHY_PLL_SIC) & BM_USBPHY_PLL_LOCK
+ ? 0 : -ETIMEDOUT;
+}
+
+static int mxs_phy_pll_enable(void __iomem *base, bool enable)
+{
+ int ret = 0;
+
+ if (enable) {
+ writel(BM_USBPHY_PLL_REG_ENABLE, base + HW_USBPHY_PLL_SIC_SET);
+ writel(BM_USBPHY_PLL_BYPASS, base + HW_USBPHY_PLL_SIC_CLR);
+ writel(BM_USBPHY_PLL_POWER, base + HW_USBPHY_PLL_SIC_SET);
+ ret = wait_for_pll_lock(base);
+ if (ret)
+ return ret;
+ writel(BM_USBPHY_PLL_EN_USB_CLKS, base +
+ HW_USBPHY_PLL_SIC_SET);
+ } else {
+ writel(BM_USBPHY_PLL_EN_USB_CLKS, base +
+ HW_USBPHY_PLL_SIC_CLR);
+ writel(BM_USBPHY_PLL_POWER, base + HW_USBPHY_PLL_SIC_CLR);
+ writel(BM_USBPHY_PLL_BYPASS, base + HW_USBPHY_PLL_SIC_SET);
+ writel(BM_USBPHY_PLL_REG_ENABLE, base + HW_USBPHY_PLL_SIC_CLR);
+ }
+
+ return ret;
+}
+
static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
{
int ret;
void __iomem *base = mxs_phy->phy.io_priv;
+ if (is_imx7ulp_phy(mxs_phy)) {
+ ret = mxs_phy_pll_enable(base, true);
+ if (ret)
+ return ret;
+ }
+
ret = stmp_reset_block(base + HW_USBPHY_CTRL);
if (ret)
- return ret;
+ goto disable_pll;
+
+ if (mxs_phy->phy_3p0) {
+ ret = regulator_enable(mxs_phy->phy_3p0);
+ if (ret) {
+ dev_err(mxs_phy->phy.dev,
+ "Failed to enable 3p0 regulator, ret=%d\n",
+ ret);
+ goto disable_pll;
+ }
+ }
/* Power up the PHY */
writel(0, base + HW_USBPHY_PWD);
@@ -244,6 +356,11 @@ static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
mxs_phy_tx_init(mxs_phy);
return 0;
+
+disable_pll:
+ if (is_imx7ulp_phy(mxs_phy))
+ mxs_phy_pll_enable(base, false);
+ return ret;
}
/* Return true if the vbus is there */
@@ -301,21 +418,10 @@ static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect)
usleep_range(500, 1000);
}
-static bool mxs_phy_is_otg_host(struct mxs_phy *mxs_phy)
-{
- void __iomem *base = mxs_phy->phy.io_priv;
- u32 phyctrl = readl(base + HW_USBPHY_CTRL);
-
- if (IS_ENABLED(CONFIG_USB_OTG) &&
- !(phyctrl & BM_USBPHY_CTRL_OTG_ID_VALUE))
- return true;
-
- return false;
-}
-
static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
{
bool vbus_is_on = false;
+ enum usb_phy_events last_event = mxs_phy->phy.last_event;
/* If the SoCs don't need to disconnect line without vbus, quit */
if (!(mxs_phy->data->flags & MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS))
@@ -327,7 +433,8 @@ static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
- if (on && !vbus_is_on && !mxs_phy_is_otg_host(mxs_phy))
+ if (on && ((!vbus_is_on && mxs_phy->mode != USB_MODE_HOST) ||
+ (last_event == USB_EVENT_VBUS)))
__mxs_phy_disconnect_line(mxs_phy, true);
else
__mxs_phy_disconnect_line(mxs_phy, false);
@@ -365,6 +472,9 @@ static void mxs_phy_shutdown(struct usb_phy *phy)
writel(BM_USBPHY_CTRL_CLKGATE,
phy->io_priv + HW_USBPHY_CTRL_SET);
+ if (mxs_phy->phy_3p0)
+ regulator_disable(mxs_phy->phy_3p0);
+
clk_disable_unprepare(mxs_phy->clk);
}
@@ -418,14 +528,49 @@ static int mxs_phy_suspend(struct usb_phy *x, int suspend)
} else {
writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
}
+
+ /*
+ * USB2 PLL use ring VCO, when the PLL power up, the ring
+ * VCO’s supply also ramp up. There is a possibility that
+ * the ring VCO start oscillation at multi nodes in this
+ * phase, especially for VCO which has many stages, then
+ * the multiwave will be kept until PLL power down. the bit
+ * hold_ring_off can force the VCO in one determined state
+ * to avoid the multiwave issue when VCO supply start ramp
+ * up.
+ */
+ if (mxs_phy->port_id == 1 && mxs_phy->regmap_anatop)
+ regmap_write(mxs_phy->regmap_anatop,
+ ANADIG_PLL_USB2_SET,
+ BM_ANADIG_PLL_USB2_HOLD_RING_OFF);
+
writel(BM_USBPHY_CTRL_CLKGATE,
x->io_priv + HW_USBPHY_CTRL_SET);
- clk_disable_unprepare(mxs_phy->clk);
+ if (!(mxs_phy->port_id == 1 &&
+ mxs_phy->hardware_control_phy2_clk))
+ clk_disable_unprepare(mxs_phy->clk);
} else {
mxs_phy_clock_switch_delay();
- ret = clk_prepare_enable(mxs_phy->clk);
- if (ret)
- return ret;
+ if (!(mxs_phy->port_id == 1 &&
+ mxs_phy->hardware_control_phy2_clk)) {
+ ret = clk_prepare_enable(mxs_phy->clk);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Per IC design's requirement, hold_ring_off bit can be
+ * cleared 25us after PLL power up and 25us before any USB
+ * TX/RX.
+ */
+ if (mxs_phy->port_id == 1 && mxs_phy->regmap_anatop) {
+ udelay(25);
+ regmap_write(mxs_phy->regmap_anatop,
+ ANADIG_PLL_USB2_CLR,
+ BM_ANADIG_PLL_USB2_HOLD_RING_OFF);
+ udelay(25);
+ }
+
writel(BM_USBPHY_CTRL_CLKGATE,
x->io_priv + HW_USBPHY_CTRL_CLR);
writel(0, x->io_priv + HW_USBPHY_PWD);
@@ -479,6 +624,61 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy,
return 0;
}
+static int mxs_phy_on_suspend(struct usb_phy *phy,
+ enum usb_device_speed speed)
+{
+ struct mxs_phy *mxs_phy = to_mxs_phy(phy);
+
+ dev_dbg(phy->dev, "%s device has suspended\n",
+ (speed == USB_SPEED_HIGH) ? "HS" : "FS/LS");
+
+ /* delay 4ms to wait bus entering idle */
+ usleep_range(4000, 5000);
+
+ if (mxs_phy->data->flags & MXS_PHY_ABNORMAL_IN_SUSPEND) {
+ writel_relaxed(0xffffffff, phy->io_priv + HW_USBPHY_PWD);
+ writel_relaxed(0, phy->io_priv + HW_USBPHY_PWD);
+ }
+
+ if (speed == USB_SPEED_HIGH)
+ writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ phy->io_priv + HW_USBPHY_CTRL_CLR);
+
+ return 0;
+}
+
+/*
+ * The resume signal must be finished here.
+ */
+static int mxs_phy_on_resume(struct usb_phy *phy,
+ enum usb_device_speed speed)
+{
+ dev_dbg(phy->dev, "%s device has resumed\n",
+ (speed == USB_SPEED_HIGH) ? "HS" : "FS/LS");
+
+ if (speed == USB_SPEED_HIGH) {
+ /* Make sure the device has switched to High-Speed mode */
+ udelay(500);
+ writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ phy->io_priv + HW_USBPHY_CTRL_SET);
+ }
+
+ return 0;
+}
+
+/*
+ * Set the usb current role for phy.
+ */
+static int mxs_phy_set_mode(struct usb_phy *phy,
+ enum usb_current_mode mode)
+{
+ struct mxs_phy *mxs_phy = to_mxs_phy(phy);
+
+ mxs_phy->mode = mode;
+
+ return 0;
+}
+
static int mxs_phy_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -556,6 +756,8 @@ static int mxs_phy_probe(struct platform_device *pdev)
if (ret < 0)
dev_dbg(&pdev->dev, "failed to get alias id, errno %d\n", ret);
mxs_phy->port_id = ret;
+ mxs_phy->clk = clk;
+ mxs_phy->data = of_id->data;
mxs_phy->phy.io_priv = base;
mxs_phy->phy.dev = &pdev->dev;
@@ -567,9 +769,28 @@ static int mxs_phy_probe(struct platform_device *pdev)
mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect;
mxs_phy->phy.type = USB_PHY_TYPE_USB2;
mxs_phy->phy.set_wakeup = mxs_phy_set_wakeup;
+ mxs_phy->phy.set_mode = mxs_phy_set_mode;
+ if (mxs_phy->data->flags & MXS_PHY_SENDING_SOF_TOO_FAST) {
+ mxs_phy->phy.notify_suspend = mxs_phy_on_suspend;
+ mxs_phy->phy.notify_resume = mxs_phy_on_resume;
+ }
- mxs_phy->clk = clk;
- mxs_phy->data = of_id->data;
+ mxs_phy->phy_3p0 = devm_regulator_get(&pdev->dev, "phy-3p0");
+ if (PTR_ERR(mxs_phy->phy_3p0) == -EPROBE_DEFER) {
+ return -EPROBE_DEFER;
+ } else if (PTR_ERR(mxs_phy->phy_3p0) == -ENODEV) {
+ /* not exist */
+ mxs_phy->phy_3p0 = NULL;
+ } else if (IS_ERR(mxs_phy->phy_3p0)) {
+ dev_err(&pdev->dev, "Getting regulator error: %ld\n",
+ PTR_ERR(mxs_phy->phy_3p0));
+ return PTR_ERR(mxs_phy->phy_3p0);
+ }
+ if (mxs_phy->phy_3p0)
+ regulator_set_voltage(mxs_phy->phy_3p0, 3200000, 3200000);
+
+ if (mxs_phy->data->flags & MXS_PHY_HARDWARE_CONTROL_PHY2_CLK)
+ mxs_phy->hardware_control_phy2_clk = true;
platform_set_drvdata(pdev, mxs_phy);
@@ -590,18 +811,30 @@ static int mxs_phy_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static void mxs_phy_enable_ldo_in_suspend(struct mxs_phy *mxs_phy, bool on)
{
- unsigned int reg = on ? ANADIG_ANA_MISC0_SET : ANADIG_ANA_MISC0_CLR;
+ unsigned int reg;
+ u32 value;
/* If the SoCs don't have anatop, quit */
if (!mxs_phy->regmap_anatop)
return;
- if (is_imx6q_phy(mxs_phy))
+ if (is_imx6q_phy(mxs_phy)) {
+ reg = on ? ANADIG_ANA_MISC0_SET : ANADIG_ANA_MISC0_CLR;
regmap_write(mxs_phy->regmap_anatop, reg,
BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG);
- else if (is_imx6sl_phy(mxs_phy))
+ } else if (is_imx6sl_phy(mxs_phy)) {
+ reg = on ? ANADIG_ANA_MISC0_SET : ANADIG_ANA_MISC0_CLR;
regmap_write(mxs_phy->regmap_anatop,
reg, BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL);
+ } else if (is_imx6ul_phy(mxs_phy)) {
+ reg = on ? ANADIG_REG_1P1_SET : ANADIG_REG_1P1_CLR;
+ value = BM_ANADIG_REG_1P1_ENABLE_WEAK_LINREG |
+ BM_ANADIG_REG_1P1_TRACK_VDD_SOC_CAP;
+ if (mxs_phy_get_vbus_status(mxs_phy) && on)
+ regmap_write(mxs_phy->regmap_anatop, reg, value);
+ else if (!on)
+ regmap_write(mxs_phy->regmap_anatop, reg, value);
+ }
}
static int mxs_phy_system_suspend(struct device *dev)
diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig
new file mode 100644
index 000000000000..17792f9114c6
--- /dev/null
+++ b/drivers/usb/typec/Kconfig
@@ -0,0 +1,7 @@
+
+menu "USB Power Delivery and Type-C drivers"
+
+config TYPEC
+ tristate
+
+endmenu
diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile
new file mode 100644
index 000000000000..1012a8bed6d5
--- /dev/null
+++ b/drivers/usb/typec/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_TYPEC) += typec.o
diff --git a/drivers/usb/typec/typec.c b/drivers/usb/typec/typec.c
new file mode 100644
index 000000000000..25b745173f7c
--- /dev/null
+++ b/drivers/usb/typec/typec.c
@@ -0,0 +1,1310 @@
+/*
+ * USB Type-C Connector Class
+ *
+ * Copyright (C) 2017, Intel Corporation
+ * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/usb/typec.h>
+
+struct typec_mode {
+ int index;
+ u32 vdo;
+ char *desc;
+ enum typec_port_type roles;
+
+ struct typec_altmode *alt_mode;
+
+ unsigned int active:1;
+
+ char group_name[6];
+ struct attribute_group group;
+ struct attribute *attrs[5];
+ struct device_attribute vdo_attr;
+ struct device_attribute desc_attr;
+ struct device_attribute active_attr;
+ struct device_attribute roles_attr;
+};
+
+struct typec_altmode {
+ struct device dev;
+ u16 svid;
+ int n_modes;
+ struct typec_mode modes[ALTMODE_MAX_MODES];
+ const struct attribute_group *mode_groups[ALTMODE_MAX_MODES];
+};
+
+struct typec_plug {
+ struct device dev;
+ enum typec_plug_index index;
+};
+
+struct typec_cable {
+ struct device dev;
+ enum typec_plug_type type;
+ struct usb_pd_identity *identity;
+ unsigned int active:1;
+};
+
+struct typec_partner {
+ struct device dev;
+ unsigned int usb_pd:1;
+ struct usb_pd_identity *identity;
+ enum typec_accessory accessory;
+};
+
+struct typec_port {
+ unsigned int id;
+ struct device dev;
+
+ int prefer_role;
+ enum typec_data_role data_role;
+ enum typec_role pwr_role;
+ enum typec_role vconn_role;
+ enum typec_pwr_opmode pwr_opmode;
+
+ const struct typec_capability *cap;
+};
+
+#define to_typec_port(_dev_) container_of(_dev_, struct typec_port, dev)
+#define to_typec_plug(_dev_) container_of(_dev_, struct typec_plug, dev)
+#define to_typec_cable(_dev_) container_of(_dev_, struct typec_cable, dev)
+#define to_typec_partner(_dev_) container_of(_dev_, struct typec_partner, dev)
+#define to_altmode(_dev_) container_of(_dev_, struct typec_altmode, dev)
+
+static const struct device_type typec_partner_dev_type;
+static const struct device_type typec_cable_dev_type;
+static const struct device_type typec_plug_dev_type;
+static const struct device_type typec_port_dev_type;
+
+#define is_typec_partner(_dev_) (_dev_->type == &typec_partner_dev_type)
+#define is_typec_cable(_dev_) (_dev_->type == &typec_cable_dev_type)
+#define is_typec_plug(_dev_) (_dev_->type == &typec_plug_dev_type)
+#define is_typec_port(_dev_) (_dev_->type == &typec_port_dev_type)
+
+static DEFINE_IDA(typec_index_ida);
+static struct class *typec_class;
+
+/* Common attributes */
+
+static const char * const typec_accessory_modes[] = {
+ [TYPEC_ACCESSORY_NONE] = "none",
+ [TYPEC_ACCESSORY_AUDIO] = "analog_audio",
+ [TYPEC_ACCESSORY_DEBUG] = "debug",
+};
+
+static const char *const typec_port_types[] = {
+ [TYPEC_PORT_DFP] = "dfp",
+ [TYPEC_PORT_UFP] = "ufp",
+ [TYPEC_PORT_DRP] = "drp",
+};
+
+static struct usb_pd_identity *get_pd_identity(struct device *dev)
+{
+ if (is_typec_partner(dev)) {
+ struct typec_partner *partner = to_typec_partner(dev);
+
+ return partner->identity;
+ } else if (is_typec_cable(dev)) {
+ struct typec_cable *cable = to_typec_cable(dev);
+
+ return cable->identity;
+ }
+ return NULL;
+}
+
+static ssize_t id_header_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_pd_identity *id = get_pd_identity(dev);
+
+ return sprintf(buf, "0x%08x\n", id->id_header);
+}
+static DEVICE_ATTR_RO(id_header);
+
+static ssize_t cert_stat_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_pd_identity *id = get_pd_identity(dev);
+
+ return sprintf(buf, "0x%08x\n", id->cert_stat);
+}
+static DEVICE_ATTR_RO(cert_stat);
+
+static ssize_t product_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_pd_identity *id = get_pd_identity(dev);
+
+ return sprintf(buf, "0x%08x\n", id->product);
+}
+static DEVICE_ATTR_RO(product);
+
+static struct attribute *usb_pd_id_attrs[] = {
+ &dev_attr_id_header.attr,
+ &dev_attr_cert_stat.attr,
+ &dev_attr_product.attr,
+ NULL
+};
+
+static const struct attribute_group usb_pd_id_group = {
+ .name = "identity",
+ .attrs = usb_pd_id_attrs,
+};
+
+static const struct attribute_group *usb_pd_id_groups[] = {
+ &usb_pd_id_group,
+ NULL,
+};
+
+static void typec_report_identity(struct device *dev)
+{
+ sysfs_notify(&dev->kobj, "identity", "id_header");
+ sysfs_notify(&dev->kobj, "identity", "cert_stat");
+ sysfs_notify(&dev->kobj, "identity", "product");
+}
+
+/* ------------------------------------------------------------------------- */
+/* Alternate Modes */
+
+/**
+ * typec_altmode_update_active - Report Enter/Exit mode
+ * @alt: Handle to the alternate mode
+ * @mode: Mode index
+ * @active: True when the mode has been entered
+ *
+ * If a partner or cable plug executes Enter/Exit Mode command successfully, the
+ * drivers use this routine to report the updated state of the mode.
+ */
+void typec_altmode_update_active(struct typec_altmode *alt, int mode,
+ bool active)
+{
+ struct typec_mode *m = &alt->modes[mode];
+ char dir[6];
+
+ if (m->active == active)
+ return;
+
+ m->active = active;
+ snprintf(dir, sizeof(dir), "mode%d", mode);
+ sysfs_notify(&alt->dev.kobj, dir, "active");
+ kobject_uevent(&alt->dev.kobj, KOBJ_CHANGE);
+}
+EXPORT_SYMBOL_GPL(typec_altmode_update_active);
+
+/**
+ * typec_altmode2port - Alternate Mode to USB Type-C port
+ * @alt: The Alternate Mode
+ *
+ * Returns handle to the port that a cable plug or partner with @alt is
+ * connected to.
+ */
+struct typec_port *typec_altmode2port(struct typec_altmode *alt)
+{
+ if (is_typec_plug(alt->dev.parent))
+ return to_typec_port(alt->dev.parent->parent->parent);
+ if (is_typec_partner(alt->dev.parent))
+ return to_typec_port(alt->dev.parent->parent);
+ if (is_typec_port(alt->dev.parent))
+ return to_typec_port(alt->dev.parent);
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(typec_altmode2port);
+
+static ssize_t
+typec_altmode_vdo_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct typec_mode *mode = container_of(attr, struct typec_mode,
+ vdo_attr);
+
+ return sprintf(buf, "0x%08x\n", mode->vdo);
+}
+
+static ssize_t
+typec_altmode_desc_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct typec_mode *mode = container_of(attr, struct typec_mode,
+ desc_attr);
+
+ return sprintf(buf, "%s\n", mode->desc ? mode->desc : "");
+}
+
+static ssize_t
+typec_altmode_active_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct typec_mode *mode = container_of(attr, struct typec_mode,
+ active_attr);
+
+ return sprintf(buf, "%s\n", mode->active ? "yes" : "no");
+}
+
+static ssize_t
+typec_altmode_active_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct typec_mode *mode = container_of(attr, struct typec_mode,
+ active_attr);
+ struct typec_port *port = typec_altmode2port(mode->alt_mode);
+ bool activate;
+ int ret;
+
+ if (!port->cap->activate_mode)
+ return -EOPNOTSUPP;
+
+ ret = kstrtobool(buf, &activate);
+ if (ret)
+ return ret;
+
+ ret = port->cap->activate_mode(port->cap, mode->index, activate);
+ if (ret)
+ return ret;
+
+ return size;
+}
+
+static ssize_t
+typec_altmode_roles_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct typec_mode *mode = container_of(attr, struct typec_mode,
+ roles_attr);
+ ssize_t ret;
+
+ switch (mode->roles) {
+ case TYPEC_PORT_DFP:
+ ret = sprintf(buf, "source\n");
+ break;
+ case TYPEC_PORT_UFP:
+ ret = sprintf(buf, "sink\n");
+ break;
+ case TYPEC_PORT_DRP:
+ default:
+ ret = sprintf(buf, "source sink\n");
+ break;
+ }
+ return ret;
+}
+
+static void typec_init_modes(struct typec_altmode *alt,
+ struct typec_mode_desc *desc, bool is_port)
+{
+ int i;
+
+ for (i = 0; i < alt->n_modes; i++, desc++) {
+ struct typec_mode *mode = &alt->modes[i];
+
+ /* Not considering the human readable description critical */
+ mode->desc = kstrdup(desc->desc, GFP_KERNEL);
+ if (desc->desc && !mode->desc)
+ dev_err(&alt->dev, "failed to copy mode%d desc\n", i);
+
+ mode->alt_mode = alt;
+ mode->vdo = desc->vdo;
+ mode->roles = desc->roles;
+ mode->index = desc->index;
+ sprintf(mode->group_name, "mode%d", desc->index);
+
+ sysfs_attr_init(&mode->vdo_attr.attr);
+ mode->vdo_attr.attr.name = "vdo";
+ mode->vdo_attr.attr.mode = 0444;
+ mode->vdo_attr.show = typec_altmode_vdo_show;
+
+ sysfs_attr_init(&mode->desc_attr.attr);
+ mode->desc_attr.attr.name = "description";
+ mode->desc_attr.attr.mode = 0444;
+ mode->desc_attr.show = typec_altmode_desc_show;
+
+ sysfs_attr_init(&mode->active_attr.attr);
+ mode->active_attr.attr.name = "active";
+ mode->active_attr.attr.mode = 0644;
+ mode->active_attr.show = typec_altmode_active_show;
+ mode->active_attr.store = typec_altmode_active_store;
+
+ mode->attrs[0] = &mode->vdo_attr.attr;
+ mode->attrs[1] = &mode->desc_attr.attr;
+ mode->attrs[2] = &mode->active_attr.attr;
+
+ /* With ports, list the roles that the mode is supported with */
+ if (is_port) {
+ sysfs_attr_init(&mode->roles_attr.attr);
+ mode->roles_attr.attr.name = "supported_roles";
+ mode->roles_attr.attr.mode = 0444;
+ mode->roles_attr.show = typec_altmode_roles_show;
+
+ mode->attrs[3] = &mode->roles_attr.attr;
+ }
+
+ mode->group.attrs = mode->attrs;
+ mode->group.name = mode->group_name;
+
+ alt->mode_groups[i] = &mode->group;
+ }
+}
+
+static ssize_t svid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct typec_altmode *alt = to_altmode(dev);
+
+ return sprintf(buf, "%04x\n", alt->svid);
+}
+static DEVICE_ATTR_RO(svid);
+
+static struct attribute *typec_altmode_attrs[] = {
+ &dev_attr_svid.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(typec_altmode);
+
+static void typec_altmode_release(struct device *dev)
+{
+ struct typec_altmode *alt = to_altmode(dev);
+ int i;
+
+ for (i = 0; i < alt->n_modes; i++)
+ kfree(alt->modes[i].desc);
+ kfree(alt);
+}
+
+static const struct device_type typec_altmode_dev_type = {
+ .name = "typec_alternate_mode",
+ .groups = typec_altmode_groups,
+ .release = typec_altmode_release,
+};
+
+static struct typec_altmode *
+typec_register_altmode(struct device *parent, struct typec_altmode_desc *desc)
+{
+ struct typec_altmode *alt;
+ int ret;
+
+ alt = kzalloc(sizeof(*alt), GFP_KERNEL);
+ if (!alt)
+ return NULL;
+
+ alt->svid = desc->svid;
+ alt->n_modes = desc->n_modes;
+ typec_init_modes(alt, desc->modes, is_typec_port(parent));
+
+ alt->dev.parent = parent;
+ alt->dev.groups = alt->mode_groups;
+ alt->dev.type = &typec_altmode_dev_type;
+ dev_set_name(&alt->dev, "svid-%04x", alt->svid);
+
+ ret = device_register(&alt->dev);
+ if (ret) {
+ dev_err(parent, "failed to register alternate mode (%d)\n",
+ ret);
+ put_device(&alt->dev);
+ return NULL;
+ }
+
+ return alt;
+}
+
+/**
+ * typec_unregister_altmode - Unregister Alternate Mode
+ * @alt: The alternate mode to be unregistered
+ *
+ * Unregister device created with typec_partner_register_altmode(),
+ * typec_plug_register_altmode() or typec_port_register_altmode().
+ */
+void typec_unregister_altmode(struct typec_altmode *alt)
+{
+ if (alt)
+ device_unregister(&alt->dev);
+}
+EXPORT_SYMBOL_GPL(typec_unregister_altmode);
+
+/* ------------------------------------------------------------------------- */
+/* Type-C Partners */
+
+static ssize_t accessory_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct typec_partner *p = to_typec_partner(dev);
+
+ return sprintf(buf, "%s\n", typec_accessory_modes[p->accessory]);
+}
+static DEVICE_ATTR_RO(accessory_mode);
+
+static ssize_t supports_usb_power_delivery_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct typec_partner *p = to_typec_partner(dev);
+
+ return sprintf(buf, "%s\n", p->usb_pd ? "yes" : "no");
+}
+static DEVICE_ATTR_RO(supports_usb_power_delivery);
+
+static struct attribute *typec_partner_attrs[] = {
+ &dev_attr_accessory_mode.attr,
+ &dev_attr_supports_usb_power_delivery.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(typec_partner);
+
+static void typec_partner_release(struct device *dev)
+{
+ struct typec_partner *partner = to_typec_partner(dev);
+
+ kfree(partner);
+}
+
+static const struct device_type typec_partner_dev_type = {
+ .name = "typec_partner",
+ .groups = typec_partner_groups,
+ .release = typec_partner_release,
+};
+
+/**
+ * typec_partner_set_identity - Report result from Discover Identity command
+ * @partner: The partner updated identity values
+ *
+ * This routine is used to report that the result of Discover Identity USB power
+ * delivery command has become available.
+ */
+int typec_partner_set_identity(struct typec_partner *partner)
+{
+ if (!partner->identity)
+ return -EINVAL;
+
+ typec_report_identity(&partner->dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(typec_partner_set_identity);
+
+/**
+ * typec_partner_register_altmode - Register USB Type-C Partner Alternate Mode
+ * @partner: USB Type-C Partner that supports the alternate mode
+ * @desc: Description of the alternate mode
+ *
+ * This routine is used to register each alternate mode individually that
+ * @partner has listed in response to Discover SVIDs command. The modes for a
+ * SVID listed in response to Discover Modes command need to be listed in an
+ * array in @desc.
+ *
+ * Returns handle to the alternate mode on success or NULL on failure.
+ */
+struct typec_altmode *
+typec_partner_register_altmode(struct typec_partner *partner,
+ struct typec_altmode_desc *desc)
+{
+ return typec_register_altmode(&partner->dev, desc);
+}
+EXPORT_SYMBOL_GPL(typec_partner_register_altmode);
+
+/**
+ * typec_register_partner - Register a USB Type-C Partner
+ * @port: The USB Type-C Port the partner is connected to
+ * @desc: Description of the partner
+ *
+ * Registers a device for USB Type-C Partner described in @desc.
+ *
+ * Returns handle to the partner on success or NULL on failure.
+ */
+struct typec_partner *typec_register_partner(struct typec_port *port,
+ struct typec_partner_desc *desc)
+{
+ struct typec_partner *partner;
+ int ret;
+
+ partner = kzalloc(sizeof(*partner), GFP_KERNEL);
+ if (!partner)
+ return NULL;
+
+ partner->usb_pd = desc->usb_pd;
+ partner->accessory = desc->accessory;
+
+ if (desc->identity) {
+ /*
+ * Creating directory for the identity only if the driver is
+ * able to provide data to it.
+ */
+ partner->dev.groups = usb_pd_id_groups;
+ partner->identity = desc->identity;
+ }
+
+ partner->dev.class = typec_class;
+ partner->dev.parent = &port->dev;
+ partner->dev.type = &typec_partner_dev_type;
+ dev_set_name(&partner->dev, "%s-partner", dev_name(&port->dev));
+
+ ret = device_register(&partner->dev);
+ if (ret) {
+ dev_err(&port->dev, "failed to register partner (%d)\n", ret);
+ put_device(&partner->dev);
+ return NULL;
+ }
+
+ return partner;
+}
+EXPORT_SYMBOL_GPL(typec_register_partner);
+
+/**
+ * typec_unregister_partner - Unregister a USB Type-C Partner
+ * @partner: The partner to be unregistered
+ *
+ * Unregister device created with typec_register_partner().
+ */
+void typec_unregister_partner(struct typec_partner *partner)
+{
+ if (partner)
+ device_unregister(&partner->dev);
+}
+EXPORT_SYMBOL_GPL(typec_unregister_partner);
+
+/* ------------------------------------------------------------------------- */
+/* Type-C Cable Plugs */
+
+static void typec_plug_release(struct device *dev)
+{
+ struct typec_plug *plug = to_typec_plug(dev);
+
+ kfree(plug);
+}
+
+static const struct device_type typec_plug_dev_type = {
+ .name = "typec_plug",
+ .release = typec_plug_release,
+};
+
+/**
+ * typec_plug_register_altmode - Register USB Type-C Cable Plug Alternate Mode
+ * @plug: USB Type-C Cable Plug that supports the alternate mode
+ * @desc: Description of the alternate mode
+ *
+ * This routine is used to register each alternate mode individually that @plug
+ * has listed in response to Discover SVIDs command. The modes for a SVID that
+ * the plug lists in response to Discover Modes command need to be listed in an
+ * array in @desc.
+ *
+ * Returns handle to the alternate mode on success or NULL on failure.
+ */
+struct typec_altmode *
+typec_plug_register_altmode(struct typec_plug *plug,
+ struct typec_altmode_desc *desc)
+{
+ return typec_register_altmode(&plug->dev, desc);
+}
+EXPORT_SYMBOL_GPL(typec_plug_register_altmode);
+
+/**
+ * typec_register_plug - Register a USB Type-C Cable Plug
+ * @cable: USB Type-C Cable with the plug
+ * @desc: Description of the cable plug
+ *
+ * Registers a device for USB Type-C Cable Plug described in @desc. A USB Type-C
+ * Cable Plug represents a plug with electronics in it that can response to USB
+ * Power Delivery SOP Prime or SOP Double Prime packages.
+ *
+ * Returns handle to the cable plug on success or NULL on failure.
+ */
+struct typec_plug *typec_register_plug(struct typec_cable *cable,
+ struct typec_plug_desc *desc)
+{
+ struct typec_plug *plug;
+ char name[8];
+ int ret;
+
+ plug = kzalloc(sizeof(*plug), GFP_KERNEL);
+ if (!plug)
+ return NULL;
+
+ sprintf(name, "plug%d", desc->index);
+
+ plug->index = desc->index;
+ plug->dev.class = typec_class;
+ plug->dev.parent = &cable->dev;
+ plug->dev.type = &typec_plug_dev_type;
+ dev_set_name(&plug->dev, "%s-%s", dev_name(cable->dev.parent), name);
+
+ ret = device_register(&plug->dev);
+ if (ret) {
+ dev_err(&cable->dev, "failed to register plug (%d)\n", ret);
+ put_device(&plug->dev);
+ return NULL;
+ }
+
+ return plug;
+}
+EXPORT_SYMBOL_GPL(typec_register_plug);
+
+/**
+ * typec_unregister_plug - Unregister a USB Type-C Cable Plug
+ * @plug: The cable plug to be unregistered
+ *
+ * Unregister device created with typec_register_plug().
+ */
+void typec_unregister_plug(struct typec_plug *plug)
+{
+ if (plug)
+ device_unregister(&plug->dev);
+}
+EXPORT_SYMBOL_GPL(typec_unregister_plug);
+
+/* Type-C Cables */
+
+static ssize_t
+type_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct typec_cable *cable = to_typec_cable(dev);
+
+ return sprintf(buf, "%s\n", cable->active ? "active" : "passive");
+}
+static DEVICE_ATTR_RO(type);
+
+static const char * const typec_plug_types[] = {
+ [USB_PLUG_NONE] = "unknown",
+ [USB_PLUG_TYPE_A] = "type-a",
+ [USB_PLUG_TYPE_B] = "type-b",
+ [USB_PLUG_TYPE_C] = "type-c",
+ [USB_PLUG_CAPTIVE] = "captive",
+};
+
+static ssize_t plug_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct typec_cable *cable = to_typec_cable(dev);
+
+ return sprintf(buf, "%s\n", typec_plug_types[cable->type]);
+}
+static DEVICE_ATTR_RO(plug_type);
+
+static struct attribute *typec_cable_attrs[] = {
+ &dev_attr_type.attr,
+ &dev_attr_plug_type.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(typec_cable);
+
+static void typec_cable_release(struct device *dev)
+{
+ struct typec_cable *cable = to_typec_cable(dev);
+
+ kfree(cable);
+}
+
+static const struct device_type typec_cable_dev_type = {
+ .name = "typec_cable",
+ .groups = typec_cable_groups,
+ .release = typec_cable_release,
+};
+
+/**
+ * typec_cable_set_identity - Report result from Discover Identity command
+ * @cable: The cable updated identity values
+ *
+ * This routine is used to report that the result of Discover Identity USB power
+ * delivery command has become available.
+ */
+int typec_cable_set_identity(struct typec_cable *cable)
+{
+ if (!cable->identity)
+ return -EINVAL;
+
+ typec_report_identity(&cable->dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(typec_cable_set_identity);
+
+/**
+ * typec_register_cable - Register a USB Type-C Cable
+ * @port: The USB Type-C Port the cable is connected to
+ * @desc: Description of the cable
+ *
+ * Registers a device for USB Type-C Cable described in @desc. The cable will be
+ * parent for the optional cable plug devises.
+ *
+ * Returns handle to the cable on success or NULL on failure.
+ */
+struct typec_cable *typec_register_cable(struct typec_port *port,
+ struct typec_cable_desc *desc)
+{
+ struct typec_cable *cable;
+ int ret;
+
+ cable = kzalloc(sizeof(*cable), GFP_KERNEL);
+ if (!cable)
+ return NULL;
+
+ cable->type = desc->type;
+ cable->active = desc->active;
+
+ if (desc->identity) {
+ /*
+ * Creating directory for the identity only if the driver is
+ * able to provide data to it.
+ */
+ cable->dev.groups = usb_pd_id_groups;
+ cable->identity = desc->identity;
+ }
+
+ cable->dev.class = typec_class;
+ cable->dev.parent = &port->dev;
+ cable->dev.type = &typec_cable_dev_type;
+ dev_set_name(&cable->dev, "%s-cable", dev_name(&port->dev));
+
+ ret = device_register(&cable->dev);
+ if (ret) {
+ dev_err(&port->dev, "failed to register cable (%d)\n", ret);
+ put_device(&cable->dev);
+ return NULL;
+ }
+
+ return cable;
+}
+EXPORT_SYMBOL_GPL(typec_register_cable);
+
+/**
+ * typec_unregister_cable - Unregister a USB Type-C Cable
+ * @cable: The cable to be unregistered
+ *
+ * Unregister device created with typec_register_cable().
+ */
+void typec_unregister_cable(struct typec_cable *cable)
+{
+ if (cable)
+ device_unregister(&cable->dev);
+}
+EXPORT_SYMBOL_GPL(typec_unregister_cable);
+
+/* ------------------------------------------------------------------------- */
+/* USB Type-C ports */
+
+static const char * const typec_roles[] = {
+ [TYPEC_SINK] = "sink",
+ [TYPEC_SOURCE] = "source",
+};
+
+static const char * const typec_data_roles[] = {
+ [TYPEC_DEVICE] = "device",
+ [TYPEC_HOST] = "host",
+};
+
+static ssize_t
+preferred_role_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct typec_port *port = to_typec_port(dev);
+ int role;
+ int ret;
+
+ if (port->cap->type != TYPEC_PORT_DRP) {
+ dev_dbg(dev, "Preferred role only supported with DRP ports\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (!port->cap->try_role) {
+ dev_dbg(dev, "Setting preferred role not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ role = sysfs_match_string(typec_roles, buf);
+ if (role < 0) {
+ if (sysfs_streq(buf, "none"))
+ role = TYPEC_NO_PREFERRED_ROLE;
+ else
+ return -EINVAL;
+ }
+
+ ret = port->cap->try_role(port->cap, role);
+ if (ret)
+ return ret;
+
+ port->prefer_role = role;
+ return size;
+}
+
+static ssize_t
+preferred_role_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct typec_port *port = to_typec_port(dev);
+
+ if (port->cap->type != TYPEC_PORT_DRP)
+ return 0;
+
+ if (port->prefer_role < 0)
+ return 0;
+
+ return sprintf(buf, "%s\n", typec_roles[port->prefer_role]);
+}
+static DEVICE_ATTR_RW(preferred_role);
+
+static ssize_t data_role_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct typec_port *port = to_typec_port(dev);
+ int ret;
+
+ if (port->cap->type != TYPEC_PORT_DRP) {
+ dev_dbg(dev, "data role swap only supported with DRP ports\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (!port->cap->dr_set) {
+ dev_dbg(dev, "data role swapping not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ ret = sysfs_match_string(typec_data_roles, buf);
+ if (ret < 0)
+ return ret;
+
+ ret = port->cap->dr_set(port->cap, ret);
+ if (ret)
+ return ret;
+
+ return size;
+}
+
+static ssize_t data_role_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct typec_port *port = to_typec_port(dev);
+
+ if (port->cap->type == TYPEC_PORT_DRP)
+ return sprintf(buf, "%s\n", port->data_role == TYPEC_HOST ?
+ "[host] device" : "host [device]");
+
+ return sprintf(buf, "[%s]\n", typec_data_roles[port->data_role]);
+}
+static DEVICE_ATTR_RW(data_role);
+
+static ssize_t power_role_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct typec_port *port = to_typec_port(dev);
+ int ret = size;
+
+ if (!port->cap->pd_revision) {
+ dev_dbg(dev, "USB Power Delivery not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (!port->cap->pr_set) {
+ dev_dbg(dev, "power role swapping not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (port->pwr_opmode != TYPEC_PWR_MODE_PD) {
+ dev_dbg(dev, "partner unable to swap power role\n");
+ return -EIO;
+ }
+
+ ret = sysfs_match_string(typec_roles, buf);
+ if (ret < 0)
+ return ret;
+
+ ret = port->cap->pr_set(port->cap, ret);
+ if (ret)
+ return ret;
+
+ return size;
+}
+
+static ssize_t power_role_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct typec_port *port = to_typec_port(dev);
+
+ if (port->cap->type == TYPEC_PORT_DRP)
+ return sprintf(buf, "%s\n", port->pwr_role == TYPEC_SOURCE ?
+ "[source] sink" : "source [sink]");
+
+ return sprintf(buf, "[%s]\n", typec_roles[port->pwr_role]);
+}
+static DEVICE_ATTR_RW(power_role);
+
+static const char * const typec_pwr_opmodes[] = {
+ [TYPEC_PWR_MODE_USB] = "default",
+ [TYPEC_PWR_MODE_1_5A] = "1.5A",
+ [TYPEC_PWR_MODE_3_0A] = "3.0A",
+ [TYPEC_PWR_MODE_PD] = "usb_power_delivery",
+};
+
+static ssize_t power_operation_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct typec_port *port = to_typec_port(dev);
+
+ return sprintf(buf, "%s\n", typec_pwr_opmodes[port->pwr_opmode]);
+}
+static DEVICE_ATTR_RO(power_operation_mode);
+
+static ssize_t vconn_source_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct typec_port *port = to_typec_port(dev);
+ bool source;
+ int ret;
+
+ if (!port->cap->pd_revision) {
+ dev_dbg(dev, "VCONN swap depends on USB Power Delivery\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (!port->cap->vconn_set) {
+ dev_dbg(dev, "VCONN swapping not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ ret = kstrtobool(buf, &source);
+ if (ret)
+ return ret;
+
+ ret = port->cap->vconn_set(port->cap, (enum typec_role)source);
+ if (ret)
+ return ret;
+
+ return size;
+}
+
+static ssize_t vconn_source_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct typec_port *port = to_typec_port(dev);
+
+ return sprintf(buf, "%s\n",
+ port->vconn_role == TYPEC_SOURCE ? "yes" : "no");
+}
+static DEVICE_ATTR_RW(vconn_source);
+
+static ssize_t supported_accessory_modes_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct typec_port *port = to_typec_port(dev);
+ ssize_t ret = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(port->cap->accessory); i++) {
+ if (port->cap->accessory[i])
+ ret += sprintf(buf + ret, "%s ",
+ typec_accessory_modes[port->cap->accessory[i]]);
+ }
+
+ if (!ret)
+ return sprintf(buf, "none\n");
+
+ buf[ret - 1] = '\n';
+
+ return ret;
+}
+static DEVICE_ATTR_RO(supported_accessory_modes);
+
+static ssize_t usb_typec_revision_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct typec_port *port = to_typec_port(dev);
+ u16 rev = port->cap->revision;
+
+ return sprintf(buf, "%d.%d\n", (rev >> 8) & 0xff, (rev >> 4) & 0xf);
+}
+static DEVICE_ATTR_RO(usb_typec_revision);
+
+static ssize_t usb_power_delivery_revision_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct typec_port *p = to_typec_port(dev);
+
+ return sprintf(buf, "%d\n", (p->cap->pd_revision >> 8) & 0xff);
+}
+static DEVICE_ATTR_RO(usb_power_delivery_revision);
+
+static struct attribute *typec_attrs[] = {
+ &dev_attr_data_role.attr,
+ &dev_attr_power_operation_mode.attr,
+ &dev_attr_power_role.attr,
+ &dev_attr_preferred_role.attr,
+ &dev_attr_supported_accessory_modes.attr,
+ &dev_attr_usb_power_delivery_revision.attr,
+ &dev_attr_usb_typec_revision.attr,
+ &dev_attr_vconn_source.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(typec);
+
+static int typec_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ int ret;
+
+ ret = add_uevent_var(env, "TYPEC_PORT=%s", dev_name(dev));
+ if (ret)
+ dev_err(dev, "failed to add uevent TYPEC_PORT\n");
+
+ return ret;
+}
+
+static void typec_release(struct device *dev)
+{
+ struct typec_port *port = to_typec_port(dev);
+
+ ida_simple_remove(&typec_index_ida, port->id);
+ kfree(port);
+}
+
+static const struct device_type typec_port_dev_type = {
+ .name = "typec_port",
+ .groups = typec_groups,
+ .uevent = typec_uevent,
+ .release = typec_release,
+};
+
+static enum typec_port_type typec_get_port_type_from_string(const char *str)
+{
+ int ret;
+
+ ret = match_string(typec_port_types, ARRAY_SIZE(typec_port_types), str);
+ return (ret < 0) ? TYPEC_PORT_TYPE_UNKNOWN : ret;
+}
+
+enum typec_port_type typec_get_port_type(struct device *dev)
+{
+ const char *port_type;
+ int err;
+
+ err = device_property_read_string(dev, "port-type", &port_type);
+ if (err < 0)
+ return TYPEC_PORT_TYPE_UNKNOWN;
+
+ return typec_get_port_type_from_string(port_type);
+}
+EXPORT_SYMBOL_GPL(typec_get_port_type);
+
+static enum typec_role typec_get_power_role_from_string(const char *str)
+{
+ int ret;
+
+ ret = match_string(typec_roles, ARRAY_SIZE(typec_roles), str);
+ return (ret < 0) ? TYPEC_ROLE_UNKNOWN : ret;
+}
+
+enum typec_role typec_get_power_role(struct device *dev)
+{
+ const char *power_role;
+ int err;
+
+ err = device_property_read_string(dev, "default-role", &power_role);
+ if (err < 0)
+ return TYPEC_ROLE_UNKNOWN;
+
+ return typec_get_power_role_from_string(power_role);
+}
+EXPORT_SYMBOL_GPL(typec_get_power_role);
+/* --------------------------------------- */
+/* Driver callbacks to report role updates */
+
+/**
+ * typec_set_data_role - Report data role change
+ * @port: The USB Type-C Port where the role was changed
+ * @role: The new data role
+ *
+ * This routine is used by the port drivers to report data role changes.
+ */
+void typec_set_data_role(struct typec_port *port, enum typec_data_role role)
+{
+ if (port->data_role == role)
+ return;
+
+ port->data_role = role;
+ sysfs_notify(&port->dev.kobj, NULL, "data_role");
+ kobject_uevent(&port->dev.kobj, KOBJ_CHANGE);
+}
+EXPORT_SYMBOL_GPL(typec_set_data_role);
+
+/**
+ * typec_set_pwr_role - Report power role change
+ * @port: The USB Type-C Port where the role was changed
+ * @role: The new data role
+ *
+ * This routine is used by the port drivers to report power role changes.
+ */
+void typec_set_pwr_role(struct typec_port *port, enum typec_role role)
+{
+ if (port->pwr_role == role)
+ return;
+
+ port->pwr_role = role;
+ sysfs_notify(&port->dev.kobj, NULL, "power_role");
+ kobject_uevent(&port->dev.kobj, KOBJ_CHANGE);
+}
+EXPORT_SYMBOL_GPL(typec_set_pwr_role);
+
+/**
+ * typec_set_pwr_role - Report VCONN source change
+ * @port: The USB Type-C Port which VCONN role changed
+ * @role: Source when @port is sourcing VCONN, or Sink when it's not
+ *
+ * This routine is used by the port drivers to report if the VCONN source is
+ * changes.
+ */
+void typec_set_vconn_role(struct typec_port *port, enum typec_role role)
+{
+ if (port->vconn_role == role)
+ return;
+
+ port->vconn_role = role;
+ sysfs_notify(&port->dev.kobj, NULL, "vconn_source");
+ kobject_uevent(&port->dev.kobj, KOBJ_CHANGE);
+}
+EXPORT_SYMBOL_GPL(typec_set_vconn_role);
+
+/**
+ * typec_set_pwr_opmode - Report changed power operation mode
+ * @port: The USB Type-C Port where the mode was changed
+ * @opmode: New power operation mode
+ *
+ * This routine is used by the port drivers to report changed power operation
+ * mode in @port. The modes are USB (default), 1.5A, 3.0A as defined in USB
+ * Type-C specification, and "USB Power Delivery" when the power levels are
+ * negotiated with methods defined in USB Power Delivery specification.
+ */
+void typec_set_pwr_opmode(struct typec_port *port,
+ enum typec_pwr_opmode opmode)
+{
+ if (port->pwr_opmode == opmode)
+ return;
+
+ port->pwr_opmode = opmode;
+ sysfs_notify(&port->dev.kobj, NULL, "power_operation_mode");
+ kobject_uevent(&port->dev.kobj, KOBJ_CHANGE);
+}
+EXPORT_SYMBOL_GPL(typec_set_pwr_opmode);
+
+/* --------------------------------------- */
+
+/**
+ * typec_port_register_altmode - Register USB Type-C Port Alternate Mode
+ * @port: USB Type-C Port that supports the alternate mode
+ * @desc: Description of the alternate mode
+ *
+ * This routine is used to register an alternate mode that @port is capable of
+ * supporting.
+ *
+ * Returns handle to the alternate mode on success or NULL on failure.
+ */
+struct typec_altmode *
+typec_port_register_altmode(struct typec_port *port,
+ struct typec_altmode_desc *desc)
+{
+ return typec_register_altmode(&port->dev, desc);
+}
+EXPORT_SYMBOL_GPL(typec_port_register_altmode);
+
+/**
+ * typec_register_port - Register a USB Type-C Port
+ * @parent: Parent device
+ * @cap: Description of the port
+ *
+ * Registers a device for USB Type-C Port described in @cap.
+ *
+ * Returns handle to the port on success or NULL on failure.
+ */
+struct typec_port *typec_register_port(struct device *parent,
+ const struct typec_capability *cap)
+{
+ struct typec_port *port;
+ int role;
+ int ret;
+ int id;
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return NULL;
+
+ id = ida_simple_get(&typec_index_ida, 0, 0, GFP_KERNEL);
+ if (id < 0) {
+ kfree(port);
+ return NULL;
+ }
+
+ if (cap->type == TYPEC_PORT_DFP)
+ role = TYPEC_SOURCE;
+ else if (cap->type == TYPEC_PORT_UFP)
+ role = TYPEC_SINK;
+ else
+ role = cap->prefer_role;
+
+ if (role == TYPEC_SOURCE) {
+ port->data_role = TYPEC_HOST;
+ port->pwr_role = TYPEC_SOURCE;
+ port->vconn_role = TYPEC_SOURCE;
+ } else {
+ port->data_role = TYPEC_DEVICE;
+ port->pwr_role = TYPEC_SINK;
+ port->vconn_role = TYPEC_SINK;
+ }
+
+ port->id = id;
+ port->cap = cap;
+ port->prefer_role = cap->prefer_role;
+
+ port->dev.class = typec_class;
+ port->dev.parent = parent;
+ port->dev.fwnode = cap->fwnode;
+ port->dev.type = &typec_port_dev_type;
+ dev_set_name(&port->dev, "port%d", id);
+
+ ret = device_register(&port->dev);
+ if (ret) {
+ dev_err(parent, "failed to register port (%d)\n", ret);
+ put_device(&port->dev);
+ return NULL;
+ }
+
+ return port;
+}
+EXPORT_SYMBOL_GPL(typec_register_port);
+
+/**
+ * typec_unregister_port - Unregister a USB Type-C Port
+ * @port: The port to be unregistered
+ *
+ * Unregister device created with typec_register_port().
+ */
+void typec_unregister_port(struct typec_port *port)
+{
+ if (port)
+ device_unregister(&port->dev);
+}
+EXPORT_SYMBOL_GPL(typec_unregister_port);
+
+static int __init typec_init(void)
+{
+ typec_class = class_create(THIS_MODULE, "typec");
+ return PTR_ERR_OR_ZERO(typec_class);
+}
+subsys_initcall(typec_init);
+
+static void __exit typec_exit(void)
+{
+ class_destroy(typec_class);
+ ida_destroy(&typec_index_ida);
+}
+module_exit(typec_exit);
+
+MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("USB Type-C Connector Class");
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 3c20af999893..21e9baf714ea 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -16,7 +16,7 @@ source "drivers/char/agp/Kconfig"
source "drivers/gpu/vga/Kconfig"
source "drivers/gpu/host1x/Kconfig"
-source "drivers/gpu/ipu-v3/Kconfig"
+source "drivers/gpu/imx/Kconfig"
source "drivers/gpu/drm/Kconfig"
diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c
index 18134416b154..e3f08fe4ce75 100644
--- a/drivers/video/backlight/gpio_backlight.c
+++ b/drivers/video/backlight/gpio_backlight.c
@@ -154,10 +154,26 @@ static struct of_device_id gpio_backlight_of_match[] = {
MODULE_DEVICE_TABLE(of, gpio_backlight_of_match);
#endif
+static int gpio_backlight_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int gpio_backlight_resume(struct device *dev)
+{
+ return 0;
+}
+
+static const struct dev_pm_ops mipi_dsi_pm_ops = {
+ .suspend = gpio_backlight_suspend,
+ .resume = gpio_backlight_resume,
+};
+
static struct platform_driver gpio_backlight_driver = {
.driver = {
.name = "gpio-backlight",
.of_match_table = of_match_ptr(gpio_backlight_of_match),
+ .pm = &mipi_dsi_pm_ops,
},
.probe = gpio_backlight_probe,
};
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index d95ae092f154..7582e2829bb5 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -41,6 +41,7 @@ struct pwm_bl_data {
int brightness);
int (*check_fb)(struct device *, struct fb_info *);
void (*exit)(struct device *);
+ char fb_id[16];
};
static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness)
@@ -133,6 +134,17 @@ static const struct backlight_ops pwm_backlight_ops = {
};
#ifdef CONFIG_OF
+static int pwm_backlight_check_fb_name(struct device *dev, struct fb_info *info)
+{
+ struct backlight_device *bl = dev_get_drvdata(dev);
+ struct pwm_bl_data *pb = bl_get_data(bl);
+
+ if (strcmp(info->fix.id, pb->fb_id) == 0)
+ return true;
+
+ return false;
+}
+
static int pwm_backlight_parse_dt(struct device *dev,
struct platform_pwm_backlight_data *data)
{
@@ -141,6 +153,7 @@ static int pwm_backlight_parse_dt(struct device *dev,
int length;
u32 value;
int ret;
+ const char *names;
if (!node)
return -ENODEV;
@@ -177,6 +190,11 @@ static int pwm_backlight_parse_dt(struct device *dev,
data->max_brightness--;
}
+ if (!of_property_read_string(node, "fb-names", &names)){
+ strcpy(data->fb_id, names);
+ data->check_fb = &pwm_backlight_check_fb_name;
+ }
+
data->enable_gpio = -EINVAL;
return 0;
}
@@ -246,6 +264,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->exit = data->exit;
pb->dev = &pdev->dev;
pb->enabled = false;
+ strcpy(pb->fb_id, data->fb_id);
pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
GPIOD_ASIS);
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 4db10d7990c9..478b577ccab2 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -3215,6 +3215,8 @@ static void fbcon_new_modelist(struct fb_info *info)
if (!fb_display[i].mode)
continue;
vc = vc_cons[i].d;
+ if (!vc)
+ continue;
display_to_var(&var, &fb_display[i]);
mode = fb_find_nearest_mode(fb_display[i].mode,
&info->modelist);
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 5d3b0db5ce0a..3aeb4b5f5163 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -38,6 +38,23 @@ menuconfig FB
(e.g. an accelerated X server) and that are not frame buffer
device-aware may cause unexpected results. If unsure, say N.
+config FB_IMX64
+ bool "Enable framebuffer support for 64 bit platforms"
+ depends on FB && ARM64
+ default n
+ ---help---
+ Add framebuffer device support for 64 bit platforms. This is needed
+ only if you specifically need FBDEV support on your 64bit platform,
+ since it will soon become deprecated.
+
+config FB_IMX64_DEBUG
+ bool "Enable debug messages and operations for 64bit framebuffer devices"
+ depends on FB_IMX64
+ default n
+ ---help---
+ Select this option if you need to debug 64bit platforms specific
+ operations.
+
config FIRMWARE_EDID
bool "Enable firmware EDID"
depends on FB
@@ -2400,7 +2417,9 @@ config FB_JZ4740
config FB_MXS
tristate "MXS LCD framebuffer support"
- depends on FB && (ARCH_MXS || ARCH_MXC)
+ depends on (FB && (ARCH_MXS || ARCH_MXC)) || \
+ (FB_IMX64 && (ARCH_FSL_IMX8QM || ARCH_FSL_IMX8QXP || ARCH_FSL_IMX8MQ))
+ select FB_MXC_DISP_FRAMEWORK
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -2449,6 +2468,11 @@ source "drivers/video/fbdev/omap/Kconfig"
source "drivers/video/fbdev/omap2/Kconfig"
source "drivers/video/fbdev/mmp/Kconfig"
+if ARCH_MXC || \
+ (FB_IMX64 && (ARCH_FSL_IMX8QM || ARCH_FSL_IMX8QXP || ARCH_FSL_IMX8MQ))
+source "drivers/video/fbdev/mxc/Kconfig"
+endif
+
config FB_SH_MOBILE_MERAM
tristate "SuperH Mobile MERAM read ahead support"
depends on (SUPERH || ARCH_SHMOBILE)
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
index ee8c81405a7f..098f3b5d1066 100644
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_FB_KYRO) += kyro/
obj-$(CONFIG_FB_SAVAGE) += savage/
obj-$(CONFIG_FB_GEODE) += geode/
obj-$(CONFIG_FB_MBX) += mbx/
+obj-$(CONFIG_FB_MXC) += mxc/
obj-$(CONFIG_FB_NEOMAGIC) += neofb.o
obj-$(CONFIG_FB_3DFX) += tdfxfb.o
obj-$(CONFIG_FB_CONTROL) += controlfb.o
diff --git a/drivers/video/fbdev/mxc/Kconfig b/drivers/video/fbdev/mxc/Kconfig
new file mode 100644
index 000000000000..c475723fc1e6
--- /dev/null
+++ b/drivers/video/fbdev/mxc/Kconfig
@@ -0,0 +1,136 @@
+config FB_MXC
+ tristate "MXC Framebuffer support"
+ depends on FB
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select FB_MODE_HELPERS
+ default y
+ help
+ This is a framebuffer device for the MXC LCD Controller.
+ See <http://www.linux-fbdev.org/> for information on framebuffer
+ devices.
+
+ If you plan to use the LCD display with your MXC system, say
+ Y here.
+
+config FB_MXC_DISP_FRAMEWORK
+ tristate "Display driver framework"
+ help
+ This is a framework that helps with registration and data handling
+ between fb drivers and display drivers.
+
+ It is selected by drivers which use this framework as linkage code
+ between display controllers and panels.
+
+config FB_MXC_SYNC_PANEL
+ depends on FB_MXC && !FB_IMX64
+ depends on MXC_IPU_V3
+ select FB_MXC_DISP_FRAMEWORK
+ tristate "Synchronous Panel Framebuffer"
+
+config FB_MXC_OVERLAY
+ depends on FB_MXC
+ tristate "Overlay Framebuffer"
+ default n
+ help
+ Enhanced LCD controller of MXC has overlay function.
+
+config FB_MXC_MIPI_DSI
+ tristate "MXC MIPI_DSI"
+ depends on FB_MXC_SYNC_PANEL
+ depends on MXC_IPU_V3
+
+config FB_MXC_MIPI_DSI_SAMSUNG
+ tristate "MXC MIPI_DSI_SAMSUNG"
+ depends on FB_MXC_SYNC_PANEL
+ depends on FB_MXS
+
+config FB_MXC_MIPI_DSI_NORTHWEST
+ tristate "MXC MIPI_DSI_NORTHWEST"
+ depends on FB_MXC_DISP_FRAMEWORK || FB_MXC_SYNC_PANEL
+ depends on FB_MXS
+
+config FB_MXC_TRULY_WVGA_SYNC_PANEL
+ tristate "TRULY WVGA Panel"
+ depends on FB_MXC_DISP_FRAMEWORK || FB_MXC_SYNC_PANEL
+ depends on FB_MXC_MIPI_DSI || FB_MXC_MIPI_DSI_SAMSUNG || FB_MXC_MIPI_DSI_NORTHWEST
+
+config FB_MXC_TRULY_PANEL_TFT3P5079E
+ tristate "TRULY Panel TFT3P5079E"
+ depends on FB_MXC_DISP_FRAMEWORK || FB_MXC_SYNC_PANEL
+ depends on FB_MXC_MIPI_DSI_SAMSUNG
+
+config FB_MXC_TRULY_PANEL_TFT3P5581E
+ tristate "TRULY Panel TFT3P5581E"
+ depends on FB_MXC_DISP_FRAMEWORK || FB_MXC_SYNC_PANEL
+ depends on FB_MXC_MIPI_DSI_SAMSUNG || FB_MXC_MIPI_DSI_NORTHWEST
+
+config FB_MXC_LDB
+ tristate "MXC LDB"
+ depends on FB_MXC_SYNC_PANEL
+ depends on MXC_IPU_V3 || FB_MXS
+ select VIDEOMODE_HELPERS
+
+config FB_MXC_HDMI
+ depends on FB_MXC_SYNC_PANEL
+ depends on MXC_IPU_V3
+ depends on I2C
+ tristate "MXC HDMI driver support"
+ select MFD_MXC_HDMI
+ help
+ Driver for the on-chip MXC HDMI controller.
+
+config FB_MXC_EDID
+ depends on FB_MXC && I2C
+ tristate "MXC EDID support"
+ default y
+
+config FB_MXS_SII902X
+ tristate "Si Image SII9022 DVI/HDMI Interface Chip"
+ depends on FB_MXS && I2C
+
+config FB_MXC_DCIC
+ tristate "MXC DCIC"
+ depends on FB_MXC_SYNC_PANEL
+ depends on MXC_IPU_V3 || FB_MXS
+ select VIDEOMODE_HELPERS
+
+config FB_MXC_ADV7535
+ tristate "ADI ADV7535 support"
+ depends on I2C
+ depends on FB_MXC_MIPI_DSI || FB_MXC_MIPI_DSI_NORTHWEST
+ help
+ Driver support for the ADV7535 DSI-to-HDMI module
+
+config HANNSTAR_CABC
+ tristate "Hannstar CABC function"
+ help
+ Say yes here to support switching on/off Hannstar CABC
+ function. This function turns backlight density of a
+ display panel automatically according to the content
+ shown on the panel.
+
+config FB_MXC_EINK_PANEL
+ depends on FB_MXC
+ depends on DMA_ENGINE
+ select FB_DEFERRED_IO
+ tristate "E-Ink Panel Framebuffer"
+
+config FB_MXC_EINK_V2_PANEL
+ depends on FB_MXC
+ depends on DMA_ENGINE
+ select FB_DEFERRED_IO
+ tristate "E-Ink Panel Framebuffer based on EPDC V2"
+
+config FB_MXC_EINK_AUTO_UPDATE_MODE
+ bool "E-Ink Auto-update Mode Support"
+ depends on FB_MXC_EINK_PANEL
+
+config FB_DCSS
+ tristate "DCSS multi-layer framebuffer support"
+ depends on FB_MXC && ARCH_FSL_IMX8MQ
+ default y
+ help
+ Framebuffer support the DCSS controller in imx8mq platform.
+ DCSS support 3 layer compsition.
diff --git a/drivers/video/fbdev/mxc/Makefile b/drivers/video/fbdev/mxc/Makefile
new file mode 100644
index 000000000000..38da682930a6
--- /dev/null
+++ b/drivers/video/fbdev/mxc/Makefile
@@ -0,0 +1,18 @@
+obj-$(CONFIG_FB_MXC_MIPI_DSI) += mipi_dsi.o
+obj-$(CONFIG_FB_MXC_MIPI_DSI_SAMSUNG) += mipi_dsi_samsung.o
+obj-$(CONFIG_FB_MXC_MIPI_DSI_NORTHWEST) += mipi_dsi_northwest.o
+obj-$(CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL) += mxcfb_hx8369_wvga.o
+obj-$(CONFIG_FB_MXC_TRULY_PANEL_TFT3P5079E) += mxcfb_otm8018b_wvga.o
+obj-$(CONFIG_FB_MXC_TRULY_PANEL_TFT3P5581E) += mxcfb_hx8363_wvga.o
+obj-$(CONFIG_FB_MXC_LDB) += ldb.o
+obj-$(CONFIG_FB_MXC_HDMI) += mxc_hdmi.o
+obj-$(CONFIG_FB_MXC_EDID) += mxc_edid.o
+obj-$(CONFIG_FB_MXC_ADV7535) += adv7535.o
+obj-$(CONFIG_FB_MXC_DISP_FRAMEWORK) += mxc_dispdrv.o
+obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxc_lcdif.o mxc_ipuv3_fb.o
+obj-$(CONFIG_FB_MXC_EINK_PANEL) += mxc_epdc_fb.o
+obj-$(CONFIG_FB_MXC_EINK_V2_PANEL) += mxc_epdc_v2_fb.o
+obj-$(CONFIG_FB_MXS_SII902X) += mxsfb_sii902x.o
+obj-$(CONFIG_FB_MXC_DCIC) += mxc_dcic.o
+obj-$(CONFIG_HANNSTAR_CABC) += hannstar_cabc.o
+obj-$(CONFIG_FB_DCSS) += imx_dcss.o
diff --git a/drivers/video/fbdev/mxc/adv7535.c b/drivers/video/fbdev/mxc/adv7535.c
new file mode 100644
index 000000000000..f47378fd9a03
--- /dev/null
+++ b/drivers/video/fbdev/mxc/adv7535.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
+#include <video/mxc_edid.h>
+
+#include "mipi_dsi.h"
+
+/* main registers addr*/
+#define ADV7535_CHIP_REVISION 0x0
+#define ADV7535_DSI_CEC_ADDR 0xE1
+
+#define TEST_PATTERN_ENABLE 0
+
+struct adv7535_info {
+ int rev;
+ struct device *dev;
+ struct i2c_client *i2c_main;
+ struct i2c_client *i2c_dsi_cec;
+ struct fb_videomode *fb_vmode;
+ unsigned int bpp;
+};
+
+static int adv7535_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+static int adv7535_remove(struct i2c_client *client);
+static int adv7535_detect(struct i2c_client *client,
+ struct i2c_board_info *info);
+
+static const struct i2c_device_id adv7535_id[] = {
+ {"adv7535", 0},
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, adv7535_id);
+
+static const struct of_device_id adv7535_dt_ids[] = {
+ { .compatible = "adi,adv7535", .data = NULL, },
+ { /* sentinel */ }
+};
+
+static struct i2c_driver adv7535_i2c_driver = {
+ .driver = {
+ .name = "adv7535",
+ .owner = THIS_MODULE,
+ .of_match_table = adv7535_dt_ids,
+ },
+ .probe = adv7535_probe,
+ .remove = adv7535_remove,
+ .id_table = adv7535_id,
+ .detect = adv7535_detect,
+};
+
+#define adv7535_write_reg(reg, val) { \
+ int err; \
+ \
+ err = i2c_smbus_write_byte_data(client, reg, val); \
+ if (err < 0) { \
+ dev_err(&client->dev, \
+ "%s:write reg error:reg=%2x, val=%2x\n",\
+ __func__, reg, val); \
+ return err; \
+ } \
+} \
+
+static int adv7535_detect(struct i2c_client *client,
+ struct i2c_board_info *info)
+{
+ s8 ret;
+ u8 chip_rev;
+ struct i2c_adapter *adapter = client->adapter;
+
+ /* check i2c functionality */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C |
+ I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ /* i2c detection */
+ ret = i2c_smbus_read_byte_data(client,
+ ADV7535_CHIP_REVISION);
+ if (ret < 0) {
+ dev_err(&adapter->dev, "ADV7535 not found\n");
+ return -ENODEV;
+ }
+
+ chip_rev = ret;
+ if (chip_rev != 0x14) {
+ dev_info(&adapter->dev, "Unsupported chip id: 0x%2x\n",
+ chip_rev);
+ return -ENODEV;
+ }
+
+ dev_info(&adapter->dev, "chip_rev = 0x%x\n", ret);
+ return 0;
+}
+
+static int adv7535_setup_cfg(struct adv7535_info *info)
+{
+ struct i2c_client *client = NULL;
+
+ client = info->i2c_main;
+ adv7535_write_reg(0xd6, 0x48); /* HPD Override */
+ adv7535_write_reg(0x41, 0x10); /* Power Up */
+
+ adv7535_write_reg(0x16, 0x20); /* Fixed Init */
+ adv7535_write_reg(0x9A, 0xE0);
+ adv7535_write_reg(0xBA, 0x70);
+ adv7535_write_reg(0xDE, 0x82);
+ adv7535_write_reg(0xE4, 0x40);
+ adv7535_write_reg(0xE5, 0x80);
+
+ client = info->i2c_dsi_cec;
+ adv7535_write_reg(0x15, 0xD0);
+ adv7535_write_reg(0x17, 0xD0);
+ adv7535_write_reg(0x24, 0x20);
+ adv7535_write_reg(0x57, 0x11);
+
+ return 0;
+}
+
+static int adv7535_vmode_cfg(struct adv7535_info *info)
+{
+ struct i2c_client *client = NULL;
+ struct fb_videomode *fb_vmode = info->fb_vmode;
+ u32 line_length, frame_height;
+ u8 low, high;
+
+ line_length = fb_vmode->xres + fb_vmode->left_margin +
+ fb_vmode->right_margin + fb_vmode->hsync_len;
+ frame_height = fb_vmode->yres + fb_vmode->upper_margin +
+ fb_vmode->lower_margin + fb_vmode->vsync_len;
+
+ client = info->i2c_dsi_cec;
+#ifdef CONFIG_FB_IMX64
+ adv7535_write_reg(0x1C, 0x40); /* 4 Data Lanes */
+#else
+ adv7535_write_reg(0x1C, 0x20); /* 2 Data Lanes */
+#endif
+
+#if TEST_PATTERN_ENABLE
+ adv7535_write_reg(0x55, 0x80);
+ adv7535_write_reg(0x16, 0x1C);
+#else
+ adv7535_write_reg(0x16, 0x00); /* Pixel Clock */
+#endif
+ adv7535_write_reg(0x27, 0xCB); /* INT_TIMING_GEN */
+
+ /* video mode settings */
+ low = (line_length << 4);
+ high = (line_length >> 4);
+ adv7535_write_reg(0x28, high); /* Total Line Length */
+ adv7535_write_reg(0x29, low);
+
+ low = (fb_vmode->hsync_len << 4);
+ high = (fb_vmode->hsync_len >> 4);
+ adv7535_write_reg(0x2A, high); /* Hsync Active Width */
+ adv7535_write_reg(0x2B, low);
+
+ low = (fb_vmode->right_margin << 4);
+ high = (fb_vmode->right_margin >> 4);
+ adv7535_write_reg(0x2C, high); /* Horizontal FP Width */
+ adv7535_write_reg(0x2D, low);
+
+ low = (fb_vmode->left_margin << 4);
+ high = (fb_vmode->left_margin >> 4);
+ adv7535_write_reg(0x2E, high); /* Horizontal BP Width */
+ adv7535_write_reg(0x2F, low);
+
+ low = (frame_height << 4);
+ high = (frame_height >> 4);
+ adv7535_write_reg(0x30, high); /* Total Frame Height */
+ adv7535_write_reg(0x31, low);
+
+ low = (fb_vmode->vsync_len << 4);
+ high = (fb_vmode->vsync_len >> 4);
+ adv7535_write_reg(0x32, high); /* Vsync Active Height */
+ adv7535_write_reg(0x33, low);
+
+ low = (fb_vmode->lower_margin << 4);
+ high = (fb_vmode->lower_margin >> 4);
+ adv7535_write_reg(0x34, high); /* Vertical FP Height */
+ adv7535_write_reg(0x35, low);
+
+ low = (fb_vmode->upper_margin << 4);
+ high = (fb_vmode->upper_margin >> 4);
+ adv7535_write_reg(0x36, high); /* Vertical BP Height */
+ adv7535_write_reg(0x37, low);
+
+ /* Reset Internal Timing Generator */
+ adv7535_write_reg(0x27, 0xCB);
+ adv7535_write_reg(0x27, 0x8B);
+ adv7535_write_reg(0x27, 0xCB);
+
+ client = info->i2c_main;
+ adv7535_write_reg(0xAF, 0x16); /* HDMI Output */
+ adv7535_write_reg(0x55, 0x10); /* AVI Info-frame */
+#ifdef CONFIG_FB_IMX64
+ adv7535_write_reg(0x56, 0x28); /* 16:9 */
+#else
+ adv7535_write_reg(0x56, 0x18);
+#endif
+ adv7535_write_reg(0x40, 0x80); /* GCP Enable */
+ adv7535_write_reg(0x4C, 0x04); /* 24bpp */
+ adv7535_write_reg(0x49, 0x00);
+
+#ifdef CONFIG_FB_IMX64
+ /* low refresh rate */
+ if (fb_vmode->refresh < 50)
+ adv7535_write_reg(0x4A, 0x8C);
+#else
+ adv7535_write_reg(0x17, 0x60); /* VS & HS Low Polarity, DE disabled */
+#endif
+
+ /*TODO Audio Setup */
+
+ client = info->i2c_dsi_cec;
+ adv7535_write_reg(0xBE, 0x3D); /* CEC Power Mode */
+
+ adv7535_write_reg(0x03, 0x89);
+
+ return 0;
+}
+
+static int adv7535_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ u32 vmode_index;
+ int ret = 0, addr;
+ struct adv7535_info *info;
+ struct device *dev = &client->dev;
+ struct device_node *endpoint = NULL;
+
+ pr_info("adv7535 probing phase\n");
+ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+
+ if (!info)
+ return -ENOMEM;
+
+ info->dev = &client->dev;
+ info->i2c_main = client;
+ i2c_set_clientdata(client, info);
+
+ dev_info(dev, "main addr = 0x%x\n", info->i2c_main->addr);
+ /* get dsi source endpoint */
+ endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+ if (!endpoint) {
+ dev_err(dev, "DSI source endpoint not exsit\n");
+ ret = -ENODEV;
+ goto err1;
+ }
+
+ info->fb_vmode = devm_kzalloc(dev, sizeof(struct fb_videomode),
+ GFP_KERNEL);
+ if (!info->fb_vmode) {
+ return -ENOMEM;
+ goto err1;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "video-mode", &vmode_index);
+ if (ret < 0) {
+ dev_err(dev, "failed to get required video mode\n");
+ goto err2;
+ }
+ if (vmode_index >= ARRAY_SIZE(mxc_cea_mode))
+ goto err2;
+
+ memcpy(info->fb_vmode, &mxc_cea_mode[vmode_index],
+ sizeof(struct fb_videomode));
+
+ ret = of_property_read_u32(dev->of_node, "bpp", &info->bpp);
+ if (ret < 0) {
+ dev_err(dev, "failed to get bpp\n");
+ goto err2;
+ }
+
+ if ((ret = adv7535_detect(client, NULL)))
+ goto err2;
+
+ addr = i2c_smbus_read_byte_data(client,
+ ADV7535_DSI_CEC_ADDR);
+ if (addr < 0) {
+ dev_err(dev, "Cannot get dsi_cec addr\n");
+ ret = addr;
+ goto err2;
+ }
+
+ dev_info(dev, "dsi cec addr = 0x%x\n", addr);
+ info->i2c_dsi_cec = i2c_new_dummy(client->adapter, addr >> 1);
+ if (!info->i2c_dsi_cec) {
+ dev_err(dev, "Failed to allocate I2C device for dsi_cec\n");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ i2c_set_clientdata(info->i2c_dsi_cec, info);
+
+ /*TODO interrupts */
+
+ if ((ret = adv7535_setup_cfg(info)))
+ goto err3;
+
+ if ((ret = adv7535_vmode_cfg(info)))
+ goto err3;
+
+#ifndef CONFIG_FB_IMX64
+ pm_runtime_enable(info->dev);
+#endif
+
+ dev_info(dev, "adv7535 probe finished\n");
+
+ return 0;
+err3:
+ i2c_unregister_device(info->i2c_dsi_cec);
+err2:
+ devm_kfree(dev, info->fb_vmode);
+err1:
+ devm_kfree(dev, info);
+
+ return ret;
+}
+
+static int adv7535_remove(struct i2c_client *client)
+{
+ struct adv7535_info *info;
+
+ info = i2c_get_clientdata(client);
+ i2c_set_clientdata(client, NULL);
+
+#ifndef CONFIG_FB_IMX64
+ pm_runtime_disable(info->dev);
+#endif
+
+ i2c_unregister_device(info->i2c_dsi_cec);
+
+ kfree(info->fb_vmode);
+ kfree(info);
+
+ return 0;
+}
+
+static __init int adv7535_init(void)
+{
+ u8 err = 0;
+
+
+ err = i2c_add_driver(&adv7535_i2c_driver);
+ if (err != 0)
+ pr_err("%s: i2c driver register failed, error = %d\n",
+ __func__, err);
+
+ pr_debug("%s (ret=%d)\n", __func__, err);
+ return err;
+}
+
+static void __exit adv7535_exit(void)
+{
+ i2c_del_driver(&adv7535_i2c_driver);
+}
+
+module_init(adv7535_init);
+module_exit(adv7535_exit);
+
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_DESCRIPTION("ADV7535 video encoder driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/mxc/crtc.h b/drivers/video/fbdev/mxc/crtc.h
new file mode 100644
index 000000000000..8bd1c1b95bd1
--- /dev/null
+++ b/drivers/video/fbdev/mxc/crtc.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __CRTC__
+#define __CRTC__
+
+enum crtc {
+ CRTC_IPU_DI0,
+ CRTC_IPU_DI1,
+ CRTC_IPU1_DI0,
+ CRTC_IPU1_DI1,
+ CRTC_IPU2_DI0,
+ CRTC_IPU2_DI1,
+ CRTC_LCDIF,
+ CRTC_LCDIF1,
+ CRTC_LCDIF2,
+ CRTC_MAX,
+};
+
+struct ipu_di_crtc_map {
+ enum crtc crtc;
+ int ipu_id;
+ int ipu_di;
+};
+
+static const struct ipu_di_crtc_map ipu_di_crtc_maps[] = {
+ {CRTC_IPU1_DI0, 0 , 0}, {CRTC_IPU1_DI1, 0 , 1},
+ {CRTC_IPU2_DI0, 1 , 0}, {CRTC_IPU2_DI1, 1 , 1},
+};
+
+static inline int ipu_di_to_crtc(struct device *dev, int ipu_id,
+ int ipu_di, enum crtc *crtc)
+{
+ int i = 0;
+
+ for (; i < ARRAY_SIZE(ipu_di_crtc_maps); i++)
+ if (ipu_di_crtc_maps[i].ipu_id == ipu_id &&
+ ipu_di_crtc_maps[i].ipu_di == ipu_di) {
+ *crtc = ipu_di_crtc_maps[i].crtc;
+ return 0;
+ }
+
+ dev_err(dev, "failed to get valid ipu di crtc "
+ "ipu_id %d, ipu_di %d\n", ipu_id, ipu_di);
+ return -EINVAL;
+}
+
+#endif
diff --git a/drivers/video/fbdev/mxc/epdc_regs.h b/drivers/video/fbdev/mxc/epdc_regs.h
new file mode 100644
index 000000000000..d4e6e525b7b9
--- /dev/null
+++ b/drivers/video/fbdev/mxc/epdc_regs.h
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __EPDC_REGS_INCLUDED__
+#define __EPDC_REGS_INCLUDED__
+
+extern void __iomem *epdc_base;
+
+/*************************************
+ * Register addresses
+ **************************************/
+
+#define EPDC_CTRL (epdc_base + 0x000)
+#define EPDC_CTRL_SET (epdc_base + 0x004)
+#define EPDC_CTRL_CLEAR (epdc_base + 0x008)
+#define EPDC_CTRL_TOGGLE (epdc_base + 0x00C)
+#define EPDC_WVADDR (epdc_base + 0x020)
+#define EPDC_WB_ADDR (epdc_base + 0x030)
+#define EPDC_RES (epdc_base + 0x040)
+#define EPDC_FORMAT (epdc_base + 0x050)
+#define EPDC_FORMAT_SET (epdc_base + 0x054)
+#define EPDC_FORMAT_CLEAR (epdc_base + 0x058)
+#define EPDC_FORMAT_TOGGLE (epdc_base + 0x05C)
+#define EPDC_FIFOCTRL (epdc_base + 0x0A0)
+#define EPDC_FIFOCTRL_SET (epdc_base + 0x0A4)
+#define EPDC_FIFOCTRL_CLEAR (epdc_base + 0x0A8)
+#define EPDC_FIFOCTRL_TOGGLE (epdc_base + 0x0AC)
+#define EPDC_UPD_ADDR (epdc_base + 0x100)
+#define EPDC_UPD_STRIDE (epdc_base + 0x110)
+#define EPDC_UPD_CORD (epdc_base + 0x120)
+#define EPDC_UPD_SIZE (epdc_base + 0x140)
+#define EPDC_UPD_CTRL (epdc_base + 0x160)
+#define EPDC_UPD_FIXED (epdc_base + 0x180)
+#define EPDC_TEMP (epdc_base + 0x1A0)
+#define EPDC_AUTOWV_LUT (epdc_base + 0x1C0)
+#define EPDC_TCE_CTRL (epdc_base + 0x200)
+#define EPDC_TCE_SDCFG (epdc_base + 0x220)
+#define EPDC_TCE_GDCFG (epdc_base + 0x240)
+#define EPDC_TCE_HSCAN1 (epdc_base + 0x260)
+#define EPDC_TCE_HSCAN2 (epdc_base + 0x280)
+#define EPDC_TCE_VSCAN (epdc_base + 0x2A0)
+#define EPDC_TCE_OE (epdc_base + 0x2C0)
+#define EPDC_TCE_POLARITY (epdc_base + 0x2E0)
+#define EPDC_TCE_TIMING1 (epdc_base + 0x300)
+#define EPDC_TCE_TIMING2 (epdc_base + 0x310)
+#define EPDC_TCE_TIMING3 (epdc_base + 0x320)
+#define EPDC_PIGEON_CTRL0 (epdc_base + 0x380)
+#define EPDC_PIGEON_CTRL1 (epdc_base + 0x390)
+#define EPDC_IRQ_MASK1 (epdc_base + 0x3C0)
+#define EPDC_IRQ_MASK1_SET (epdc_base + 0x3C4)
+#define EPDC_IRQ_MASK1_CLEAR (epdc_base + 0x3C8)
+#define EPDC_IRQ_MASK1_TOGGLE (epdc_base + 0x3CC)
+#define EPDC_IRQ_MASK2 (epdc_base + 0x3D0)
+#define EPDC_IRQ_MASK2_SET (epdc_base + 0x3D4)
+#define EPDC_IRQ_MASK2_CLEAR (epdc_base + 0x3D8)
+#define EPDC_IRQ_MASK2_TOGGLE (epdc_base + 0x3DC)
+#define EPDC_IRQ1 (epdc_base + 0x3E0)
+#define EPDC_IRQ1_SET (epdc_base + 0x3E4)
+#define EPDC_IRQ1_CLEAR (epdc_base + 0x3E8)
+#define EPDC_IRQ1_TOGGLE (epdc_base + 0x3EC)
+#define EPDC_IRQ2 (epdc_base + 0x3F0)
+#define EPDC_IRQ2_SET (epdc_base + 0x3F4)
+#define EPDC_IRQ2_CLEAR (epdc_base + 0x3F8)
+#define EPDC_IRQ2_TOGGLE (epdc_base + 0x3FC)
+#define EPDC_IRQ_MASK (epdc_base + 0x400)
+#define EPDC_IRQ_MASK_SET (epdc_base + 0x404)
+#define EPDC_IRQ_MASK_CLEAR (epdc_base + 0x408)
+#define EPDC_IRQ_MASK_TOGGLE (epdc_base + 0x40C)
+#define EPDC_IRQ (epdc_base + 0x420)
+#define EPDC_IRQ_SET (epdc_base + 0x424)
+#define EPDC_IRQ_CLEAR (epdc_base + 0x428)
+#define EPDC_IRQ_TOGGLE (epdc_base + 0x42C)
+#define EPDC_STATUS_LUTS (epdc_base + 0x440)
+#define EPDC_STATUS_LUTS_SET (epdc_base + 0x444)
+#define EPDC_STATUS_LUTS_CLEAR (epdc_base + 0x448)
+#define EPDC_STATUS_LUTS_TOGGLE (epdc_base + 0x44C)
+#define EPDC_STATUS_LUTS2 (epdc_base + 0x450)
+#define EPDC_STATUS_LUTS2_SET (epdc_base + 0x454)
+#define EPDC_STATUS_LUTS2_CLEAR (epdc_base + 0x458)
+#define EPDC_STATUS_LUTS2_TOGGLE (epdc_base + 0x45C)
+#define EPDC_STATUS_NEXTLUT (epdc_base + 0x460)
+#define EPDC_STATUS_COL (epdc_base + 0x480)
+#define EPDC_STATUS_COL2 (epdc_base + 0x490)
+#define EPDC_STATUS (epdc_base + 0x4A0)
+#define EPDC_STATUS_SET (epdc_base + 0x4A4)
+#define EPDC_STATUS_CLEAR (epdc_base + 0x4A8)
+#define EPDC_STATUS_TOGGLE (epdc_base + 0x4AC)
+#define EPDC_UPD_COL_CORD (epdc_base + 0x4C0)
+#define EPDC_UPD_COL_SIZE (epdc_base + 0x4E0)
+#define EPDC_DEBUG (epdc_base + 0x500)
+#define EPDC_DEBUG_LUT (epdc_base + 0x530)
+#define EPDC_HIST1_PARAM (epdc_base + 0x600)
+#define EPDC_HIST2_PARAM (epdc_base + 0x610)
+#define EPDC_HIST4_PARAM (epdc_base + 0x620)
+#define EPDC_HIST8_PARAM0 (epdc_base + 0x630)
+#define EPDC_HIST8_PARAM1 (epdc_base + 0x640)
+#define EPDC_HIST16_PARAM0 (epdc_base + 0x650)
+#define EPDC_HIST16_PARAM1 (epdc_base + 0x660)
+#define EPDC_HIST16_PARAM2 (epdc_base + 0x670)
+#define EPDC_HIST16_PARAM3 (epdc_base + 0x680)
+#define EPDC_GPIO (epdc_base + 0x700)
+#define EPDC_VERSION (epdc_base + 0x7F0)
+#define EPDC_PIGEON_0_0 (epdc_base + 0x800)
+#define EPDC_PIGEON_0_1 (epdc_base + 0x810)
+#define EPDC_PIGEON_0_2 (epdc_base + 0x820)
+#define EPDC_PIGEON_1_0 (epdc_base + 0x840)
+#define EPDC_PIGEON_1_1 (epdc_base + 0x850)
+#define EPDC_PIGEON_1_2 (epdc_base + 0x860)
+#define EPDC_PIGEON_2_0 (epdc_base + 0x880)
+#define EPDC_PIGEON_2_1 (epdc_base + 0x890)
+#define EPDC_PIGEON_2_2 (epdc_base + 0x8A0)
+#define EPDC_PIGEON_3_0 (epdc_base + 0x8C0)
+#define EPDC_PIGEON_3_1 (epdc_base + 0x8D0)
+#define EPDC_PIGEON_3_2 (epdc_base + 0x8E0)
+#define EPDC_PIGEON_4_0 (epdc_base + 0x900)
+#define EPDC_PIGEON_4_1 (epdc_base + 0x910)
+#define EPDC_PIGEON_4_2 (epdc_base + 0x920)
+#define EPDC_PIGEON_5_0 (epdc_base + 0x940)
+#define EPDC_PIGEON_5_1 (epdc_base + 0x950)
+#define EPDC_PIGEON_5_2 (epdc_base + 0x960)
+#define EPDC_PIGEON_6_0 (epdc_base + 0x980)
+#define EPDC_PIGEON_6_1 (epdc_base + 0x990)
+#define EPDC_PIGEON_6_2 (epdc_base + 0x9A0)
+#define EPDC_PIGEON_7_0 (epdc_base + 0x9C0)
+#define EPDC_PIGEON_7_1 (epdc_base + 0x9D0)
+#define EPDC_PIGEON_7_2 (epdc_base + 0x9E0)
+#define EPDC_PIGEON_8_0 (epdc_base + 0xA00)
+#define EPDC_PIGEON_8_1 (epdc_base + 0xA10)
+#define EPDC_PIGEON_8_2 (epdc_base + 0xA20)
+#define EPDC_PIGEON_9_0 (epdc_base + 0xA40)
+#define EPDC_PIGEON_9_1 (epdc_base + 0xA50)
+#define EPDC_PIGEON_9_2 (epdc_base + 0xA60)
+#define EPDC_PIGEON_10_0 (epdc_base + 0xA80)
+#define EPDC_PIGEON_10_1 (epdc_base + 0xA90)
+#define EPDC_PIGEON_10_2 (epdc_base + 0xAA0)
+#define EPDC_PIGEON_11_0 (epdc_base + 0xAC0)
+#define EPDC_PIGEON_11_1 (epdc_base + 0xAD0)
+#define EPDC_PIGEON_11_2 (epdc_base + 0xAE0)
+#define EPDC_PIGEON_12_0 (epdc_base + 0xB00)
+#define EPDC_PIGEON_12_1 (epdc_base + 0xB10)
+#define EPDC_PIGEON_12_2 (epdc_base + 0xB20)
+#define EPDC_PIGEON_13_0 (epdc_base + 0xB40)
+#define EPDC_PIGEON_13_1 (epdc_base + 0xB50)
+#define EPDC_PIGEON_13_2 (epdc_base + 0xB60)
+#define EPDC_PIGEON_14_0 (epdc_base + 0xB80)
+#define EPDC_PIGEON_14_1 (epdc_base + 0xB90)
+#define EPDC_PIGEON_14_2 (epdc_base + 0xBA0)
+#define EPDC_PIGEON_15_0 (epdc_base + 0xBC0)
+#define EPDC_PIGEON_15_1 (epdc_base + 0xBD0)
+#define EPDC_PIGEON_15_2 (epdc_base + 0xBE0)
+#define EPDC_WB_ADDR_TCE (epdc_base + 0xC10)
+
+/*
+ * Register field definitions
+ */
+
+enum {
+/* EPDC_CTRL field values */
+ EPDC_CTRL_SFTRST = 0x80000000,
+ EPDC_CTRL_CLKGATE = 0x40000000,
+ EPDC_CTRL_SRAM_POWERDOWN = 0x100,
+ EPDC_CTRL_UPD_DATA_SWIZZLE_MASK = 0xC0,
+ EPDC_CTRL_UPD_DATA_SWIZZLE_NO_SWAP = 0,
+ EPDC_CTRL_UPD_DATA_SWIZZLE_ALL_BYTES_SWAP = 0x40,
+ EPDC_CTRL_UPD_DATA_SWIZZLE_HWD_SWAP = 0x80,
+ EPDC_CTRL_UPD_DATA_SWIZZLE_HWD_BYTE_SWAP = 0xC0,
+ EPDC_CTRL_LUT_DATA_SWIZZLE_MASK = 0x30,
+ EPDC_CTRL_LUT_DATA_SWIZZLE_NO_SWAP = 0,
+ EPDC_CTRL_LUT_DATA_SWIZZLE_ALL_BYTES_SWAP = 0x10,
+ EPDC_CTRL_LUT_DATA_SWIZZLE_HWD_SWAP = 0x20,
+ EPDC_CTRL_LUT_DATA_SWIZZLE_HWD_BYTE_SWAP = 0x30,
+ EPDC_CTRL_BURST_LEN_8_8 = 0x1,
+ EPDC_CTRL_BURST_LEN_8_16 = 0,
+
+/* EPDC_RES field values */
+ EPDC_RES_VERTICAL_MASK = 0x1FFF0000,
+ EPDC_RES_VERTICAL_OFFSET = 16,
+ EPDC_RES_HORIZONTAL_MASK = 0x1FFF,
+ EPDC_RES_HORIZONTAL_OFFSET = 0,
+
+/* EPDC_FORMAT field values */
+ EPDC_FORMAT_BUF_PIXEL_SCALE_ROUND = 0x1000000,
+ EPDC_FORMAT_DEFAULT_TFT_PIXEL_MASK = 0xFF0000,
+ EPDC_FORMAT_DEFAULT_TFT_PIXEL_OFFSET = 16,
+ EPDC_FORMAT_BUF_PIXEL_FORMAT_MASK = 0x700,
+ EPDC_FORMAT_BUF_PIXEL_FORMAT_P2N = 0x200,
+ EPDC_FORMAT_BUF_PIXEL_FORMAT_P3N = 0x300,
+ EPDC_FORMAT_BUF_PIXEL_FORMAT_P4N = 0x400,
+ EPDC_FORMAT_BUF_PIXEL_FORMAT_P5N = 0x500,
+ EPDC_FORMAT_TFT_PIXEL_FORMAT_2BIT = 0x0,
+ EPDC_FORMAT_TFT_PIXEL_FORMAT_2BIT_VCOM = 0x1,
+ EPDC_FORMAT_TFT_PIXEL_FORMAT_4BIT = 0x2,
+ EPDC_FORMAT_TFT_PIXEL_FORMAT_4BIT_VCOM = 0x3,
+
+/* EPDC_FIFOCTRL field values */
+ EPDC_FIFOCTRL_ENABLE_PRIORITY = 0x80000000,
+ EPDC_FIFOCTRL_FIFO_INIT_LEVEL_MASK = 0xFF0000,
+ EPDC_FIFOCTRL_FIFO_INIT_LEVEL_OFFSET = 16,
+ EPDC_FIFOCTRL_FIFO_H_LEVEL_MASK = 0xFF00,
+ EPDC_FIFOCTRL_FIFO_H_LEVEL_OFFSET = 8,
+ EPDC_FIFOCTRL_FIFO_L_LEVEL_MASK = 0xFF,
+ EPDC_FIFOCTRL_FIFO_L_LEVEL_OFFSET = 0,
+
+/* EPDC_UPD_CORD field values */
+ EPDC_UPD_CORD_YCORD_MASK = 0x1FFF0000,
+ EPDC_UPD_CORD_YCORD_OFFSET = 16,
+ EPDC_UPD_CORD_XCORD_MASK = 0x1FFF,
+ EPDC_UPD_CORD_XCORD_OFFSET = 0,
+
+/* EPDC_UPD_SIZE field values */
+ EPDC_UPD_SIZE_HEIGHT_MASK = 0x1FFF0000,
+ EPDC_UPD_SIZE_HEIGHT_OFFSET = 16,
+ EPDC_UPD_SIZE_WIDTH_MASK = 0x1FFF,
+ EPDC_UPD_SIZE_WIDTH_OFFSET = 0,
+
+/* EPDC_UPD_CTRL field values */
+ EPDC_UPD_CTRL_USE_FIXED = 0x80000000,
+ EPDC_UPD_CTRL_LUT_SEL_MASK = 0x3F0000,
+ EPDC_UPD_CTRL_LUT_SEL_OFFSET = 16,
+ EPDC_UPD_CTRL_WAVEFORM_MODE_MASK = 0xFF00,
+ EPDC_UPD_CTRL_WAVEFORM_MODE_OFFSET = 8,
+ EPDC_UPD_CTRL_AUTOWV_PAUSE = 0x8,
+ EPDC_UPD_CTRL_AUTOWV = 0x4,
+ EPDC_UPD_CTRL_DRY_RUN = 0x2,
+ EPDC_UPD_CTRL_UPDATE_MODE_FULL = 0x1,
+
+/* EPDC_UPD_FIXED field values */
+ EPDC_UPD_FIXED_FIXNP_EN = 0x80000000,
+ EPDC_UPD_FIXED_FIXCP_EN = 0x40000000,
+ EPDC_UPD_FIXED_FIXNP_MASK = 0xFF00,
+ EPDC_UPD_FIXED_FIXNP_OFFSET = 8,
+ EPDC_UPD_FIXED_FIXCP_MASK = 0xFF,
+ EPDC_UPD_FIXED_FIXCP_OFFSET = 0,
+
+/* EPDC_AUTOWV_LUT field values */
+ EPDC_AUTOWV_LUT_DATA_MASK = 0xFF0000,
+ EPDC_AUTOWV_LUT_DATA_OFFSET = 16,
+ EPDC_AUTOWV_LUT_ADDR_MASK = 0xFF,
+ EPDC_AUTOWV_LUT_ADDR_OFFSET = 0,
+
+/* EPDC_TCE_CTRL field values */
+ EPDC_TCE_CTRL_VSCAN_HOLDOFF_MASK = 0x1FF0000,
+ EPDC_TCE_CTRL_VSCAN_HOLDOFF_OFFSET = 16,
+ EPDC_TCE_CTRL_VCOM_VAL_MASK = 0xC00,
+ EPDC_TCE_CTRL_VCOM_VAL_OFFSET = 10,
+ EPDC_TCE_CTRL_VCOM_MODE_AUTO = 0x200,
+ EPDC_TCE_CTRL_VCOM_MODE_MANUAL = 0x000,
+ EPDC_TCE_CTRL_DDR_MODE_ENABLE = 0x100,
+ EPDC_TCE_CTRL_LVDS_MODE_CE_ENABLE = 0x80,
+ EPDC_TCE_CTRL_LVDS_MODE_ENABLE = 0x40,
+ EPDC_TCE_CTRL_SCAN_DIR_1_UP = 0x20,
+ EPDC_TCE_CTRL_SCAN_DIR_0_UP = 0x10,
+ EPDC_TCE_CTRL_DUAL_SCAN_ENABLE = 0x8,
+ EPDC_TCE_CTRL_SDDO_WIDTH_16BIT = 0x4,
+ EPDC_TCE_CTRL_PIXELS_PER_SDCLK_2 = 1,
+ EPDC_TCE_CTRL_PIXELS_PER_SDCLK_4 = 2,
+ EPDC_TCE_CTRL_PIXELS_PER_SDCLK_8 = 3,
+
+/* EPDC_TCE_SDCFG field values */
+ EPDC_TCE_SDCFG_SDCLK_HOLD = 0x200000,
+ EPDC_TCE_SDCFG_SDSHR = 0x100000,
+ EPDC_TCE_SDCFG_NUM_CE_MASK = 0xF0000,
+ EPDC_TCE_SDCFG_NUM_CE_OFFSET = 16,
+ EPDC_TCE_SDCFG_SDDO_REFORMAT_STANDARD = 0,
+ EPDC_TCE_SDCFG_SDDO_REFORMAT_FLIP_PIXELS = 0x4000,
+ EPDC_TCE_SDCFG_SDDO_INVERT_ENABLE = 0x2000,
+ EPDC_TCE_SDCFG_PIXELS_PER_CE_MASK = 0x1FFF,
+ EPDC_TCE_SDCFG_PIXELS_PER_CE_OFFSET = 0,
+
+/* EPDC_TCE_GDCFG field values */
+ EPDC_TCE_SDCFG_GDRL = 0x10,
+ EPDC_TCE_SDCFG_GDOE_MODE_DELAYED_GDCLK = 0x2,
+ EPDC_TCE_SDCFG_GDSP_MODE_FRAME_SYNC = 0x1,
+ EPDC_TCE_SDCFG_GDSP_MODE_ONE_LINE = 0x0,
+
+/* EPDC_TCE_HSCAN1 field values */
+ EPDC_TCE_HSCAN1_LINE_SYNC_WIDTH_MASK = 0xFFF0000,
+ EPDC_TCE_HSCAN1_LINE_SYNC_WIDTH_OFFSET = 16,
+ EPDC_TCE_HSCAN1_LINE_SYNC_MASK = 0xFFF,
+ EPDC_TCE_HSCAN1_LINE_SYNC_OFFSET = 0,
+
+/* EPDC_TCE_HSCAN2 field values */
+ EPDC_TCE_HSCAN2_LINE_END_MASK = 0xFFF0000,
+ EPDC_TCE_HSCAN2_LINE_END_OFFSET = 16,
+ EPDC_TCE_HSCAN2_LINE_BEGIN_MASK = 0xFFF,
+ EPDC_TCE_HSCAN2_LINE_BEGIN_OFFSET = 0,
+
+/* EPDC_TCE_VSCAN field values */
+ EPDC_TCE_VSCAN_FRAME_END_MASK = 0xFF0000,
+ EPDC_TCE_VSCAN_FRAME_END_OFFSET = 16,
+ EPDC_TCE_VSCAN_FRAME_BEGIN_MASK = 0xFF00,
+ EPDC_TCE_VSCAN_FRAME_BEGIN_OFFSET = 8,
+ EPDC_TCE_VSCAN_FRAME_SYNC_MASK = 0xFF,
+ EPDC_TCE_VSCAN_FRAME_SYNC_OFFSET = 0,
+
+/* EPDC_TCE_OE field values */
+ EPDC_TCE_OE_SDOED_WIDTH_MASK = 0xFF000000,
+ EPDC_TCE_OE_SDOED_WIDTH_OFFSET = 24,
+ EPDC_TCE_OE_SDOED_DLY_MASK = 0xFF0000,
+ EPDC_TCE_OE_SDOED_DLY_OFFSET = 16,
+ EPDC_TCE_OE_SDOEZ_WIDTH_MASK = 0xFF00,
+ EPDC_TCE_OE_SDOEZ_WIDTH_OFFSET = 8,
+ EPDC_TCE_OE_SDOEZ_DLY_MASK = 0xFF,
+ EPDC_TCE_OE_SDOEZ_DLY_OFFSET = 0,
+
+/* EPDC_TCE_POLARITY field values */
+ EPDC_TCE_POLARITY_GDSP_POL_ACTIVE_HIGH = 0x10,
+ EPDC_TCE_POLARITY_GDOE_POL_ACTIVE_HIGH = 0x8,
+ EPDC_TCE_POLARITY_SDOE_POL_ACTIVE_HIGH = 0x4,
+ EPDC_TCE_POLARITY_SDLE_POL_ACTIVE_HIGH = 0x2,
+ EPDC_TCE_POLARITY_SDCE_POL_ACTIVE_HIGH = 0x1,
+
+/* EPDC_TCE_TIMING1 field values */
+ EPDC_TCE_TIMING1_SDLE_SHIFT_NONE = 0x00,
+ EPDC_TCE_TIMING1_SDLE_SHIFT_1 = 0x10,
+ EPDC_TCE_TIMING1_SDLE_SHIFT_2 = 0x20,
+ EPDC_TCE_TIMING1_SDLE_SHIFT_3 = 0x30,
+ EPDC_TCE_TIMING1_SDCLK_INVERT = 0x8,
+ EPDC_TCE_TIMING1_SDCLK_SHIFT_NONE = 0,
+ EPDC_TCE_TIMING1_SDCLK_SHIFT_1CYCLE = 1,
+ EPDC_TCE_TIMING1_SDCLK_SHIFT_2CYCLES = 2,
+ EPDC_TCE_TIMING1_SDCLK_SHIFT_3CYCLES = 3,
+
+/* EPDC_TCE_TIMING2 field values */
+ EPDC_TCE_TIMING2_GDCLK_HP_MASK = 0xFFFF0000,
+ EPDC_TCE_TIMING2_GDCLK_HP_OFFSET = 16,
+ EPDC_TCE_TIMING2_GDSP_OFFSET_MASK = 0xFFFF,
+ EPDC_TCE_TIMING2_GDSP_OFFSET_OFFSET = 0,
+
+/* EPDC_TCE_TIMING3 field values */
+ EPDC_TCE_TIMING3_GDOE_OFFSET_MASK = 0xFFFF0000,
+ EPDC_TCE_TIMING3_GDOE_OFFSET_OFFSET = 16,
+ EPDC_TCE_TIMING3_GDCLK_OFFSET_MASK = 0xFFFF,
+ EPDC_TCE_TIMING3_GDCLK_OFFSET_OFFSET = 0,
+
+/* EPDC_IRQ_MASK/EPDC_IRQ field values */
+ EPDC_IRQ_WB_CMPLT_IRQ = 0x10000,
+ EPDC_IRQ_LUT_COL_IRQ = 0x20000,
+ EPDC_IRQ_TCE_UNDERRUN_IRQ = 0x40000,
+ EPDC_IRQ_FRAME_END_IRQ = 0x80000,
+ EPDC_IRQ_BUS_ERROR_IRQ = 0x100000,
+ EPDC_IRQ_TCE_IDLE_IRQ = 0x200000,
+ EPDC_IRQ_UPD_DONE_IRQ = 0x400000,
+ EPDC_IRQ_PWR_IRQ = 0x800000,
+
+/* EPDC_STATUS_NEXTLUT field values */
+ EPDC_STATUS_NEXTLUT_NEXT_LUT_VALID = 0x100,
+ EPDC_STATUS_NEXTLUT_NEXT_LUT_MASK = 0x3F,
+ EPDC_STATUS_NEXTLUT_NEXT_LUT_OFFSET = 0,
+
+/* EPDC_STATUS field values */
+ EPDC_STATUS_HISTOGRAM_CP_MASK = 0x1F0000,
+ EPDC_STATUS_HISTOGRAM_CP_OFFSET = 16,
+ EPDC_STATUS_HISTOGRAM_NP_MASK = 0x1F00,
+ EPDC_STATUS_HISTOGRAM_NP_OFFSET = 8,
+ EPDC_STATUS_UPD_VOID = 0x8,
+ EPDC_STATUS_LUTS_UNDERRUN = 0x4,
+ EPDC_STATUS_LUTS_BUSY = 0x2,
+ EPDC_STATUS_WB_BUSY = 0x1,
+
+/* EPDC_UPD_COL_CORD field values */
+ EPDC_UPD_COL_CORD_YCORD_MASK = 0x1FFF0000,
+ EPDC_UPD_COL_CORD_YCORD_OFFSET = 16,
+ EPDC_UPD_COL_CORD_XCORD_MASK = 0x1FFF,
+ EPDC_UPD_COL_CORD_XCORD_OFFSET = 0,
+
+/* EPDC_UPD_COL_SIZE field values */
+ EPDC_UPD_COL_SIZE_HEIGHT_MASK = 0x1FFF0000,
+ EPDC_UPD_COL_SIZE_HEIGHT_OFFSET = 16,
+ EPDC_UPD_COL_SIZE_WIDTH_MASK = 0x1FFF,
+ EPDC_UPD_COL_SIZE_WIDTH_OFFSET = 0,
+
+/* EPDC_DEBUG field values */
+ EPDC_DEBUG_UNDERRUN_RECOVER = 0x2,
+ EPDC_DEBUG_COLLISION_OFF = 0x1,
+
+/* EPDC_HISTx_PARAM field values */
+ EPDC_HIST_PARAM_VALUE0_MASK = 0x1F,
+ EPDC_HIST_PARAM_VALUE0_OFFSET = 0,
+ EPDC_HIST_PARAM_VALUE1_MASK = 0x1F00,
+ EPDC_HIST_PARAM_VALUE1_OFFSET = 8,
+ EPDC_HIST_PARAM_VALUE2_MASK = 0x1F0000,
+ EPDC_HIST_PARAM_VALUE2_OFFSET = 16,
+ EPDC_HIST_PARAM_VALUE3_MASK = 0x1F000000,
+ EPDC_HIST_PARAM_VALUE3_OFFSET = 24,
+ EPDC_HIST_PARAM_VALUE4_MASK = 0x1F,
+ EPDC_HIST_PARAM_VALUE4_OFFSET = 0,
+ EPDC_HIST_PARAM_VALUE5_MASK = 0x1F00,
+ EPDC_HIST_PARAM_VALUE5_OFFSET = 8,
+ EPDC_HIST_PARAM_VALUE6_MASK = 0x1F0000,
+ EPDC_HIST_PARAM_VALUE6_OFFSET = 16,
+ EPDC_HIST_PARAM_VALUE7_MASK = 0x1F000000,
+ EPDC_HIST_PARAM_VALUE7_OFFSET = 24,
+ EPDC_HIST_PARAM_VALUE8_MASK = 0x1F,
+ EPDC_HIST_PARAM_VALUE8_OFFSET = 0,
+ EPDC_HIST_PARAM_VALUE9_MASK = 0x1F00,
+ EPDC_HIST_PARAM_VALUE9_OFFSET = 8,
+ EPDC_HIST_PARAM_VALUE10_MASK = 0x1F0000,
+ EPDC_HIST_PARAM_VALUE10_OFFSET = 16,
+ EPDC_HIST_PARAM_VALUE11_MASK = 0x1F000000,
+ EPDC_HIST_PARAM_VALUE11_OFFSET = 24,
+ EPDC_HIST_PARAM_VALUE12_MASK = 0x1F,
+ EPDC_HIST_PARAM_VALUE12_OFFSET = 0,
+ EPDC_HIST_PARAM_VALUE13_MASK = 0x1F00,
+ EPDC_HIST_PARAM_VALUE13_OFFSET = 8,
+ EPDC_HIST_PARAM_VALUE14_MASK = 0x1F0000,
+ EPDC_HIST_PARAM_VALUE14_OFFSET = 16,
+ EPDC_HIST_PARAM_VALUE15_MASK = 0x1F000000,
+ EPDC_HIST_PARAM_VALUE15_OFFSET = 24,
+
+/* EPDC_GPIO field values */
+ EPDC_GPIO_PWRCOM = 0x40,
+ EPDC_GPIO_PWRCTRL_MASK = 0x3C,
+ EPDC_GPIO_PWRCTRL_OFFSET = 2,
+ EPDC_GPIO_BDR_MASK = 0x3,
+ EPDC_GPIO_BDR_OFFSET = 0,
+
+/* EPDC_VERSION field values */
+ EPDC_VERSION_MAJOR_MASK = 0xFF000000,
+ EPDC_VERSION_MAJOR_OFFSET = 24,
+ EPDC_VERSION_MINOR_MASK = 0xFF0000,
+ EPDC_VERSION_MINOR_OFFSET = 16,
+ EPDC_VERSION_STEP_MASK = 0xFFFF,
+ EPDC_VERSION_STEP_OFFSET = 0,
+};
+
+#endif /* __EPDC_REGS_INCLUDED__ */
diff --git a/drivers/video/fbdev/mxc/epdc_v2_regs.h b/drivers/video/fbdev/mxc/epdc_v2_regs.h
new file mode 100644
index 000000000000..052df13151fc
--- /dev/null
+++ b/drivers/video/fbdev/mxc/epdc_v2_regs.h
@@ -0,0 +1,533 @@
+/*
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __EPDC_REGS_INCLUDED__
+#define __EPDC_REGS_INCLUDED__
+
+extern void __iomem *epdc_v2_base;
+
+/*************************************
+ * Register addresses
+ **************************************/
+
+#define EPDC_CTRL (epdc_v2_base + 0x000)
+#define EPDC_CTRL_SET (epdc_v2_base + 0x004)
+#define EPDC_CTRL_CLEAR (epdc_v2_base + 0x008)
+#define EPDC_CTRL_TOGGLE (epdc_v2_base + 0x00C)
+#define EPDC_WVADDR (epdc_v2_base + 0x020)
+#define EPDC_WB_ADDR (epdc_v2_base + 0x030)
+#define EPDC_RES (epdc_v2_base + 0x040)
+#define EPDC_FORMAT (epdc_v2_base + 0x050)
+#define EPDC_FORMAT_SET (epdc_v2_base + 0x054)
+#define EPDC_FORMAT_CLEAR (epdc_v2_base + 0x058)
+#define EPDC_FORMAT_TOGGLE (epdc_v2_base + 0x05C)
+#define EPDC_WB_FIELD0 (epdc_v2_base + 0x060)
+#define EPDC_WB_FIELD0_SET (epdc_v2_base + 0x064)
+#define EPDC_WB_FIELD0_CLEAR (epdc_v2_base + 0x068)
+#define EPDC_WB_FIELD0_TOGGLE (epdc_v2_base + 0x06C)
+#define EPDC_WB_FIELD1 (epdc_v2_base + 0x070)
+#define EPDC_WB_FIELD1_SET (epdc_v2_base + 0x074)
+#define EPDC_WB_FIELD1_CLEAR (epdc_v2_base + 0x078)
+#define EPDC_WB_FIELD1_TOGGLE (epdc_v2_base + 0x07C)
+#define EPDC_WB_FIELD2 (epdc_v2_base + 0x080)
+#define EPDC_WB_FIELD2_SET (epdc_v2_base + 0x084)
+#define EPDC_WB_FIELD2_CLEAR (epdc_v2_base + 0x088)
+#define EPDC_WB_FIELD2_TOGGLE (epdc_v2_base + 0x08C)
+#define EPDC_WB_FIELD3 (epdc_v2_base + 0x090)
+#define EPDC_WB_FIELD3_SET (epdc_v2_base + 0x094)
+#define EPDC_WB_FIELD3_CLEAR (epdc_v2_base + 0x098)
+#define EPDC_WB_FIELD3_TOGGLE (epdc_v2_base + 0x09C)
+#define EPDC_FIFOCTRL (epdc_v2_base + 0x0A0)
+#define EPDC_FIFOCTRL_SET (epdc_v2_base + 0x0A4)
+#define EPDC_FIFOCTRL_CLEAR (epdc_v2_base + 0x0A8)
+#define EPDC_FIFOCTRL_TOGGLE (epdc_v2_base + 0x0AC)
+#define EPDC_UPD_ADDR (epdc_v2_base + 0x100)
+#define EPDC_UPD_STRIDE (epdc_v2_base + 0x110)
+#define EPDC_UPD_CORD (epdc_v2_base + 0x120)
+#define EPDC_UPD_SIZE (epdc_v2_base + 0x140)
+#define EPDC_UPD_CTRL (epdc_v2_base + 0x160)
+#define EPDC_UPD_FIXED (epdc_v2_base + 0x180)
+#define EPDC_TEMP (epdc_v2_base + 0x1A0)
+#define EPDC_AUTOWV_LUT (epdc_v2_base + 0x1C0)
+#define EPDC_LUT_STANDBY1 (epdc_v2_base + 0x1E0)
+#define EPDC_LUT_STANDBY1_SET (epdc_v2_base + 0x1E4)
+#define EPDC_LUT_STANDBY1_CLEAR (epdc_v2_base + 0x1E8)
+#define EPDC_LUT_STANDBY1_TOGGLE (epdc_v2_base + 0x1EC)
+#define EPDC_LUT_STANDBY2 (epdc_v2_base + 0x1F0)
+#define EPDC_LUT_STANDBY2_SET (epdc_v2_base + 0x1F4)
+#define EPDC_LUT_STANDBY2_CLEAR (epdc_v2_base + 0x1F8)
+#define EPDC_LUT_STANDBY2_TOGGLE (epdc_v2_base + 0x1FC)
+#define EPDC_TCE_CTRL (epdc_v2_base + 0x200)
+#define EPDC_TCE_SDCFG (epdc_v2_base + 0x220)
+#define EPDC_TCE_GDCFG (epdc_v2_base + 0x240)
+#define EPDC_TCE_HSCAN1 (epdc_v2_base + 0x260)
+#define EPDC_TCE_HSCAN2 (epdc_v2_base + 0x280)
+#define EPDC_TCE_VSCAN (epdc_v2_base + 0x2A0)
+#define EPDC_TCE_OE (epdc_v2_base + 0x2C0)
+#define EPDC_TCE_POLARITY (epdc_v2_base + 0x2E0)
+#define EPDC_TCE_TIMING1 (epdc_v2_base + 0x300)
+#define EPDC_TCE_TIMING2 (epdc_v2_base + 0x310)
+#define EPDC_TCE_TIMING3 (epdc_v2_base + 0x320)
+#define EPDC_PIGEON_CTRL0 (epdc_v2_base + 0x380)
+#define EPDC_PIGEON_CTRL1 (epdc_v2_base + 0x390)
+#define EPDC_IRQ_MASK1 (epdc_v2_base + 0x3C0)
+#define EPDC_IRQ_MASK1_SET (epdc_v2_base + 0x3C4)
+#define EPDC_IRQ_MASK1_CLEAR (epdc_v2_base + 0x3C8)
+#define EPDC_IRQ_MASK1_TOGGLE (epdc_v2_base + 0x3CC)
+#define EPDC_IRQ_MASK2 (epdc_v2_base + 0x3D0)
+#define EPDC_IRQ_MASK2_SET (epdc_v2_base + 0x3D4)
+#define EPDC_IRQ_MASK2_CLEAR (epdc_v2_base + 0x3D8)
+#define EPDC_IRQ_MASK2_TOGGLE (epdc_v2_base + 0x3DC)
+#define EPDC_IRQ1 (epdc_v2_base + 0x3E0)
+#define EPDC_IRQ1_SET (epdc_v2_base + 0x3E4)
+#define EPDC_IRQ1_CLEAR (epdc_v2_base + 0x3E8)
+#define EPDC_IRQ1_TOGGLE (epdc_v2_base + 0x3EC)
+#define EPDC_IRQ2 (epdc_v2_base + 0x3F0)
+#define EPDC_IRQ2_SET (epdc_v2_base + 0x3F4)
+#define EPDC_IRQ2_CLEAR (epdc_v2_base + 0x3F8)
+#define EPDC_IRQ2_TOGGLE (epdc_v2_base + 0x3FC)
+#define EPDC_IRQ_MASK (epdc_v2_base + 0x400)
+#define EPDC_IRQ_MASK_SET (epdc_v2_base + 0x404)
+#define EPDC_IRQ_MASK_CLEAR (epdc_v2_base + 0x408)
+#define EPDC_IRQ_MASK_TOGGLE (epdc_v2_base + 0x40C)
+#define EPDC_IRQ (epdc_v2_base + 0x420)
+#define EPDC_IRQ_SET (epdc_v2_base + 0x424)
+#define EPDC_IRQ_CLEAR (epdc_v2_base + 0x428)
+#define EPDC_IRQ_TOGGLE (epdc_v2_base + 0x42C)
+#define EPDC_STATUS_LUTS (epdc_v2_base + 0x440)
+#define EPDC_STATUS_LUTS_SET (epdc_v2_base + 0x444)
+#define EPDC_STATUS_LUTS_CLEAR (epdc_v2_base + 0x448)
+#define EPDC_STATUS_LUTS_TOGGLE (epdc_v2_base + 0x44C)
+#define EPDC_STATUS_LUTS2 (epdc_v2_base + 0x450)
+#define EPDC_STATUS_LUTS2_SET (epdc_v2_base + 0x454)
+#define EPDC_STATUS_LUTS2_CLEAR (epdc_v2_base + 0x458)
+#define EPDC_STATUS_LUTS2_TOGGLE (epdc_v2_base + 0x45C)
+#define EPDC_STATUS_NEXTLUT (epdc_v2_base + 0x460)
+#define EPDC_STATUS_COL (epdc_v2_base + 0x480)
+#define EPDC_STATUS_COL2 (epdc_v2_base + 0x490)
+#define EPDC_STATUS (epdc_v2_base + 0x4A0)
+#define EPDC_STATUS_SET (epdc_v2_base + 0x4A4)
+#define EPDC_STATUS_CLEAR (epdc_v2_base + 0x4A8)
+#define EPDC_STATUS_TOGGLE (epdc_v2_base + 0x4AC)
+#define EPDC_UPD_COL_CORD (epdc_v2_base + 0x4C0)
+#define EPDC_UPD_COL_SIZE (epdc_v2_base + 0x4E0)
+#define EPDC_DEBUG (epdc_v2_base + 0x500)
+#define EPDC_DEBUG_LUT (epdc_v2_base + 0x530)
+#define EPDC_HIST1_PARAM (epdc_v2_base + 0x600)
+#define EPDC_HIST2_PARAM (epdc_v2_base + 0x610)
+#define EPDC_HIST4_PARAM (epdc_v2_base + 0x620)
+#define EPDC_HIST8_PARAM0 (epdc_v2_base + 0x630)
+#define EPDC_HIST8_PARAM1 (epdc_v2_base + 0x640)
+#define EPDC_HIST16_PARAM0 (epdc_v2_base + 0x650)
+#define EPDC_HIST16_PARAM1 (epdc_v2_base + 0x660)
+#define EPDC_HIST16_PARAM2 (epdc_v2_base + 0x670)
+#define EPDC_HIST16_PARAM3 (epdc_v2_base + 0x680)
+#define EPDC_GPIO (epdc_v2_base + 0x700)
+#define EPDC_VERSION (epdc_v2_base + 0x7F0)
+#define EPDC_PIGEON_0_0 (epdc_v2_base + 0x800)
+#define EPDC_PIGEON_0_1 (epdc_v2_base + 0x810)
+#define EPDC_PIGEON_0_2 (epdc_v2_base + 0x820)
+#define EPDC_PIGEON_1_0 (epdc_v2_base + 0x840)
+#define EPDC_PIGEON_1_1 (epdc_v2_base + 0x850)
+#define EPDC_PIGEON_1_2 (epdc_v2_base + 0x860)
+#define EPDC_PIGEON_2_0 (epdc_v2_base + 0x880)
+#define EPDC_PIGEON_2_1 (epdc_v2_base + 0x890)
+#define EPDC_PIGEON_2_2 (epdc_v2_base + 0x8A0)
+#define EPDC_PIGEON_3_0 (epdc_v2_base + 0x8C0)
+#define EPDC_PIGEON_3_1 (epdc_v2_base + 0x8D0)
+#define EPDC_PIGEON_3_2 (epdc_v2_base + 0x8E0)
+#define EPDC_PIGEON_4_0 (epdc_v2_base + 0x900)
+#define EPDC_PIGEON_4_1 (epdc_v2_base + 0x910)
+#define EPDC_PIGEON_4_2 (epdc_v2_base + 0x920)
+#define EPDC_PIGEON_5_0 (epdc_v2_base + 0x940)
+#define EPDC_PIGEON_5_1 (epdc_v2_base + 0x950)
+#define EPDC_PIGEON_5_2 (epdc_v2_base + 0x960)
+#define EPDC_PIGEON_6_0 (epdc_v2_base + 0x980)
+#define EPDC_PIGEON_6_1 (epdc_v2_base + 0x990)
+#define EPDC_PIGEON_6_2 (epdc_v2_base + 0x9A0)
+#define EPDC_PIGEON_7_0 (epdc_v2_base + 0x9C0)
+#define EPDC_PIGEON_7_1 (epdc_v2_base + 0x9D0)
+#define EPDC_PIGEON_7_2 (epdc_v2_base + 0x9E0)
+#define EPDC_PIGEON_8_0 (epdc_v2_base + 0xA00)
+#define EPDC_PIGEON_8_1 (epdc_v2_base + 0xA10)
+#define EPDC_PIGEON_8_2 (epdc_v2_base + 0xA20)
+#define EPDC_PIGEON_9_0 (epdc_v2_base + 0xA40)
+#define EPDC_PIGEON_9_1 (epdc_v2_base + 0xA50)
+#define EPDC_PIGEON_9_2 (epdc_v2_base + 0xA60)
+#define EPDC_PIGEON_10_0 (epdc_v2_base + 0xA80)
+#define EPDC_PIGEON_10_1 (epdc_v2_base + 0xA90)
+#define EPDC_PIGEON_10_2 (epdc_v2_base + 0xAA0)
+#define EPDC_PIGEON_11_0 (epdc_v2_base + 0xAC0)
+#define EPDC_PIGEON_11_1 (epdc_v2_base + 0xAD0)
+#define EPDC_PIGEON_11_2 (epdc_v2_base + 0xAE0)
+#define EPDC_PIGEON_12_0 (epdc_v2_base + 0xB00)
+#define EPDC_PIGEON_12_1 (epdc_v2_base + 0xB10)
+#define EPDC_PIGEON_12_2 (epdc_v2_base + 0xB20)
+#define EPDC_PIGEON_13_0 (epdc_v2_base + 0xB40)
+#define EPDC_PIGEON_13_1 (epdc_v2_base + 0xB50)
+#define EPDC_PIGEON_13_2 (epdc_v2_base + 0xB60)
+#define EPDC_PIGEON_14_0 (epdc_v2_base + 0xB80)
+#define EPDC_PIGEON_14_1 (epdc_v2_base + 0xB90)
+#define EPDC_PIGEON_14_2 (epdc_v2_base + 0xBA0)
+#define EPDC_PIGEON_15_0 (epdc_v2_base + 0xBC0)
+#define EPDC_PIGEON_15_1 (epdc_v2_base + 0xBD0)
+#define EPDC_PIGEON_15_2 (epdc_v2_base + 0xBE0)
+#define EPDC_PIGEON_16_0 (epdc_v2_base + 0xC00)
+#define EPDC_PIGEON_16_1 (epdc_v2_base + 0xC10)
+#define EPDC_PIGEON_16_2 (epdc_v2_base + 0xC20)
+#define EPDC_WB_ADDR_TCE (epdc_v2_base + 0x010)
+
+/*
+ * Register field definitions
+ */
+
+enum {
+/* EPDC_CTRL field values */
+ EPDC_CTRL_SFTRST = 0x80000000,
+ EPDC_CTRL_CLKGATE = 0x40000000,
+ EPDC_CTRL_SRAM_POWERDOWN = 0x100,
+ EPDC_CTRL_UPD_DATA_SWIZZLE_MASK = 0xC0,
+ EPDC_CTRL_UPD_DATA_SWIZZLE_NO_SWAP = 0,
+ EPDC_CTRL_UPD_DATA_SWIZZLE_ALL_BYTES_SWAP = 0x40,
+ EPDC_CTRL_UPD_DATA_SWIZZLE_HWD_SWAP = 0x80,
+ EPDC_CTRL_UPD_DATA_SWIZZLE_HWD_BYTE_SWAP = 0xC0,
+ EPDC_CTRL_LUT_DATA_SWIZZLE_MASK = 0x30,
+ EPDC_CTRL_LUT_DATA_SWIZZLE_NO_SWAP = 0,
+ EPDC_CTRL_LUT_DATA_SWIZZLE_ALL_BYTES_SWAP = 0x10,
+ EPDC_CTRL_LUT_DATA_SWIZZLE_HWD_SWAP = 0x20,
+ EPDC_CTRL_LUT_DATA_SWIZZLE_HWD_BYTE_SWAP = 0x30,
+ EPDC_CTRL_BURST_LEN_8_8 = 0x1,
+ EPDC_CTRL_BURST_LEN_8_16 = 0,
+
+/* EPDC_RES field values */
+ EPDC_RES_VERTICAL_MASK = 0x1FFF0000,
+ EPDC_RES_VERTICAL_OFFSET = 16,
+ EPDC_RES_HORIZONTAL_MASK = 0x1FFF,
+ EPDC_RES_HORIZONTAL_OFFSET = 0,
+
+/* EPDC_FORMAT field values */
+ EPDC_FORMAT_BUF_PIXEL_SCALE_ROUND = 0x1000000,
+ EPDC_FORMAT_DEFAULT_TFT_PIXEL_MASK = 0xFF0000,
+ EPDC_FORMAT_DEFAULT_TFT_PIXEL_OFFSET = 16,
+ EPDC_FORMAT_WB_ADDR_NO_COPY = 0x4000,
+ EPDC_FORMAT_WB_TYPE_MASK = 0x3000,
+ EPDC_FORMAT_WB_TYPE_OFFSET = 12,
+ EPDC_FORMAT_WB_TYPE_WB_INTERNAL = 0x0,
+ EPDC_FORMAT_WB_TYPE_WB_WAVEFORM = 0x1000,
+ EPDC_FORMAT_WB_TYPE_WB_EXTERNAL16 = 0x2000,
+ EPDC_FORMAT_WB_TYPE_WB_EXTERNAL32 = 0x3000,
+ EPDC_FORMAT_WB_COMPRESS = 0x800,
+ EPDC_FORMAT_BUF_PIXEL_FORMAT_MASK = 0x700,
+ EPDC_FORMAT_BUF_PIXEL_FORMAT_P2N = 0x200,
+ EPDC_FORMAT_BUF_PIXEL_FORMAT_P3N = 0x300,
+ EPDC_FORMAT_BUF_PIXEL_FORMAT_P4N = 0x400,
+ EPDC_FORMAT_BUF_PIXEL_FORMAT_P5N = 0x500,
+ EPDC_FORMAT_TFT_PIXEL_FORMAT_2BIT = 0x0,
+ EPDC_FORMAT_TFT_PIXEL_FORMAT_2BIT_VCOM = 0x1,
+ EPDC_FORMAT_TFT_PIXEL_FORMAT_4BIT = 0x2,
+ EPDC_FORMAT_TFT_PIXEL_FORMAT_4BIT_VCOM = 0x3,
+
+/* EPDC_WB_FIELD field values */
+ EPDC_WB_FIELD_FIXED_MASK = 0xFF000000,
+ EPDC_WB_FIELD_FIXED_OFFSET = 24,
+ EPDC_WB_FIELD_USE_FIXED_MASK = 0x30000,
+ EPDC_WB_FIELD_USE_FIXED_OFFSET = 16,
+ EPDC_WB_FIELD_USE_FIXED_NO_FIXED = 0x0,
+ EPDC_WB_FIELD_USE_FIXED_USE_FIXED = 0x1,
+ EPDC_WB_FIELD_USE_FIXED_NE_FIXED = 0x2,
+ EPDC_WB_FIELD_USE_FIXED_EQ_FIXED = 0x3,
+ EPDC_WB_FIELD_USAGE_MASK = 0xE000,
+ EPDC_WB_FIELD_USAGE_OFFSET = 13,
+ EPDC_WB_FIELD_USAGE_NOT_USED = 0x0,
+ EPDC_WB_FIELD_USAGE_PARTIAL = 0x3,
+ EPDC_WB_FIELD_USAGE_LUT = 0x4,
+ EPDC_WB_FIELD_USAGE_CP = 0x5,
+ EPDC_WB_FIELD_USAGE_NP = 0x6,
+ EPDC_WB_FIELD_USAGE_PTS = 0x7,
+ EPDC_WB_FIELD_FROM_MASK = 0x1F00,
+ EPDC_WB_FIELD_FROM_OFFSET = 8,
+ EPDC_WB_FIELD_TO_MASK = 0xF0,
+ EPDC_WB_FIELD_TO_OFFSET = 4,
+ EPDC_WB_FIELD_LEN_MASK = 0xF,
+ EPDC_WB_FIELD_LEN_OFFSET = 0,
+
+/* EPDC_FIFOCTRL field values */
+ EPDC_FIFOCTRL_ENABLE_PRIORITY = 0x80000000,
+ EPDC_FIFOCTRL_FIFO_INIT_LEVEL_MASK = 0xFF0000,
+ EPDC_FIFOCTRL_FIFO_INIT_LEVEL_OFFSET = 16,
+ EPDC_FIFOCTRL_FIFO_H_LEVEL_MASK = 0xFF00,
+ EPDC_FIFOCTRL_FIFO_H_LEVEL_OFFSET = 8,
+ EPDC_FIFOCTRL_FIFO_L_LEVEL_MASK = 0xFF,
+ EPDC_FIFOCTRL_FIFO_L_LEVEL_OFFSET = 0,
+
+/* EPDC_UPD_CORD field values */
+ EPDC_UPD_CORD_YCORD_MASK = 0x1FFF0000,
+ EPDC_UPD_CORD_YCORD_OFFSET = 16,
+ EPDC_UPD_CORD_XCORD_MASK = 0x1FFF,
+ EPDC_UPD_CORD_XCORD_OFFSET = 0,
+
+/* EPDC_UPD_SIZE field values */
+ EPDC_UPD_SIZE_HEIGHT_MASK = 0x1FFF0000,
+ EPDC_UPD_SIZE_HEIGHT_OFFSET = 16,
+ EPDC_UPD_SIZE_WIDTH_MASK = 0x1FFF,
+ EPDC_UPD_SIZE_WIDTH_OFFSET = 0,
+
+/* EPDC_UPD_CTRL field values */
+ EPDC_UPD_CTRL_USE_FIXED = 0x80000000,
+ EPDC_UPD_CTRL_LUT_SEL_MASK = 0x3F0000,
+ EPDC_UPD_CTRL_LUT_SEL_OFFSET = 16,
+ EPDC_UPD_CTRL_WAVEFORM_MODE_MASK = 0xFF00,
+ EPDC_UPD_CTRL_WAVEFORM_MODE_OFFSET = 8,
+ EPDC_UPD_CTRL_NO_LUT_CANCEL = 0x10,
+ EPDC_UPD_CTRL_AUTOWV_PAUSE = 0x8,
+ EPDC_UPD_CTRL_AUTOWV = 0x4,
+ EPDC_UPD_CTRL_DRY_RUN = 0x2,
+ EPDC_UPD_CTRL_UPDATE_MODE_FULL = 0x1,
+
+/* EPDC_UPD_FIXED field values */
+ EPDC_UPD_FIXED_FIXNP_EN = 0x80000000,
+ EPDC_UPD_FIXED_FIXCP_EN = 0x40000000,
+ EPDC_UPD_FIXED_FIXNP_MASK = 0xFF00,
+ EPDC_UPD_FIXED_FIXNP_OFFSET = 8,
+ EPDC_UPD_FIXED_FIXCP_MASK = 0xFF,
+ EPDC_UPD_FIXED_FIXCP_OFFSET = 0,
+
+/* EPDC_AUTOWV_LUT field values */
+ EPDC_AUTOWV_LUT_DATA_MASK = 0xFF0000,
+ EPDC_AUTOWV_LUT_DATA_OFFSET = 16,
+ EPDC_AUTOWV_LUT_ADDR_MASK = 0x7,
+ EPDC_AUTOWV_LUT_ADDR_OFFSET = 0,
+
+/* EPDC_TCE_CTRL field values */
+ EPDC_TCE_CTRL_VSCAN_HOLDOFF_MASK = 0x1FF0000,
+ EPDC_TCE_CTRL_VSCAN_HOLDOFF_OFFSET = 16,
+ EPDC_TCE_CTRL_VCOM_VAL_MASK = 0xC00,
+ EPDC_TCE_CTRL_VCOM_VAL_OFFSET = 10,
+ EPDC_TCE_CTRL_VCOM_MODE_AUTO = 0x200,
+ EPDC_TCE_CTRL_VCOM_MODE_MANUAL = 0x000,
+ EPDC_TCE_CTRL_DDR_MODE_ENABLE = 0x100,
+ EPDC_TCE_CTRL_LVDS_MODE_CE_ENABLE = 0x80,
+ EPDC_TCE_CTRL_LVDS_MODE_ENABLE = 0x40,
+ EPDC_TCE_CTRL_SCAN_DIR_1_UP = 0x20,
+ EPDC_TCE_CTRL_SCAN_DIR_0_UP = 0x10,
+ EPDC_TCE_CTRL_DUAL_SCAN_ENABLE = 0x8,
+ EPDC_TCE_CTRL_SDDO_WIDTH_16BIT = 0x4,
+ EPDC_TCE_CTRL_PIXELS_PER_SDCLK_2 = 1,
+ EPDC_TCE_CTRL_PIXELS_PER_SDCLK_4 = 2,
+ EPDC_TCE_CTRL_PIXELS_PER_SDCLK_8 = 3,
+
+/* EPDC_TCE_SDCFG field values */
+ EPDC_TCE_SDCFG_SDCLK_HOLD = 0x200000,
+ EPDC_TCE_SDCFG_SDSHR = 0x100000,
+ EPDC_TCE_SDCFG_NUM_CE_MASK = 0xF0000,
+ EPDC_TCE_SDCFG_NUM_CE_OFFSET = 16,
+ EPDC_TCE_SDCFG_SDDO_REFORMAT_STANDARD = 0,
+ EPDC_TCE_SDCFG_SDDO_REFORMAT_FLIP_PIXELS = 0x4000,
+ EPDC_TCE_SDCFG_SDDO_INVERT_ENABLE = 0x2000,
+ EPDC_TCE_SDCFG_PIXELS_PER_CE_MASK = 0x1FFF,
+ EPDC_TCE_SDCFG_PIXELS_PER_CE_OFFSET = 0,
+
+/* EPDC_TCE_GDCFG field values */
+ EPDC_TCE_SDCFG_GDRL = 0x10,
+ EPDC_TCE_SDCFG_GDOE_MODE_DELAYED_GDCLK = 0x2,
+ EPDC_TCE_SDCFG_GDSP_MODE_FRAME_SYNC = 0x1,
+ EPDC_TCE_SDCFG_GDSP_MODE_ONE_LINE = 0x0,
+
+/* EPDC_TCE_HSCAN1 field values */
+ EPDC_TCE_HSCAN1_LINE_SYNC_WIDTH_MASK = 0xFFF0000,
+ EPDC_TCE_HSCAN1_LINE_SYNC_WIDTH_OFFSET = 16,
+ EPDC_TCE_HSCAN1_LINE_SYNC_MASK = 0xFFF,
+ EPDC_TCE_HSCAN1_LINE_SYNC_OFFSET = 0,
+
+/* EPDC_TCE_HSCAN2 field values */
+ EPDC_TCE_HSCAN2_LINE_END_MASK = 0xFFF0000,
+ EPDC_TCE_HSCAN2_LINE_END_OFFSET = 16,
+ EPDC_TCE_HSCAN2_LINE_BEGIN_MASK = 0xFFF,
+ EPDC_TCE_HSCAN2_LINE_BEGIN_OFFSET = 0,
+
+/* EPDC_TCE_VSCAN field values */
+ EPDC_TCE_VSCAN_FRAME_END_MASK = 0xFF0000,
+ EPDC_TCE_VSCAN_FRAME_END_OFFSET = 16,
+ EPDC_TCE_VSCAN_FRAME_BEGIN_MASK = 0xFF00,
+ EPDC_TCE_VSCAN_FRAME_BEGIN_OFFSET = 8,
+ EPDC_TCE_VSCAN_FRAME_SYNC_MASK = 0xFF,
+ EPDC_TCE_VSCAN_FRAME_SYNC_OFFSET = 0,
+
+/* EPDC_TCE_OE field values */
+ EPDC_TCE_OE_SDOED_WIDTH_MASK = 0xFF000000,
+ EPDC_TCE_OE_SDOED_WIDTH_OFFSET = 24,
+ EPDC_TCE_OE_SDOED_DLY_MASK = 0xFF0000,
+ EPDC_TCE_OE_SDOED_DLY_OFFSET = 16,
+ EPDC_TCE_OE_SDOEZ_WIDTH_MASK = 0xFF00,
+ EPDC_TCE_OE_SDOEZ_WIDTH_OFFSET = 8,
+ EPDC_TCE_OE_SDOEZ_DLY_MASK = 0xFF,
+ EPDC_TCE_OE_SDOEZ_DLY_OFFSET = 0,
+
+/* EPDC_TCE_POLARITY field values */
+ EPDC_TCE_POLARITY_GDSP_POL_ACTIVE_HIGH = 0x10,
+ EPDC_TCE_POLARITY_GDOE_POL_ACTIVE_HIGH = 0x8,
+ EPDC_TCE_POLARITY_SDOE_POL_ACTIVE_HIGH = 0x4,
+ EPDC_TCE_POLARITY_SDLE_POL_ACTIVE_HIGH = 0x2,
+ EPDC_TCE_POLARITY_SDCE_POL_ACTIVE_HIGH = 0x1,
+
+/* EPDC_TCE_TIMING1 field values */
+ EPDC_TCE_TIMING1_SDLE_SHIFT_NONE = 0x00,
+ EPDC_TCE_TIMING1_SDLE_SHIFT_1 = 0x10,
+ EPDC_TCE_TIMING1_SDLE_SHIFT_2 = 0x20,
+ EPDC_TCE_TIMING1_SDLE_SHIFT_3 = 0x30,
+ EPDC_TCE_TIMING1_SDCLK_INVERT = 0x8,
+ EPDC_TCE_TIMING1_SDCLK_SHIFT_NONE = 0,
+ EPDC_TCE_TIMING1_SDCLK_SHIFT_1CYCLE = 1,
+ EPDC_TCE_TIMING1_SDCLK_SHIFT_2CYCLES = 2,
+ EPDC_TCE_TIMING1_SDCLK_SHIFT_3CYCLES = 3,
+
+/* EPDC_TCE_TIMING2 field values */
+ EPDC_TCE_TIMING2_GDCLK_HP_MASK = 0xFFFF0000,
+ EPDC_TCE_TIMING2_GDCLK_HP_OFFSET = 16,
+ EPDC_TCE_TIMING2_GDSP_OFFSET_MASK = 0xFFFF,
+ EPDC_TCE_TIMING2_GDSP_OFFSET_OFFSET = 0,
+
+/* EPDC_TCE_TIMING3 field values */
+ EPDC_TCE_TIMING3_GDOE_OFFSET_MASK = 0xFFFF0000,
+ EPDC_TCE_TIMING3_GDOE_OFFSET_OFFSET = 16,
+ EPDC_TCE_TIMING3_GDCLK_OFFSET_MASK = 0xFFFF,
+ EPDC_TCE_TIMING3_GDCLK_OFFSET_OFFSET = 0,
+
+/* EPDC EPDC_PIGEON_CTRL0 field values */
+ EPDC_PIGEON_CTRL0_LD_PERIOD_MASK = 0xFFF0000,
+ EPDC_PIGEON_CTRL0_LD_PERIOD_OFFSET = 16,
+ EPDC_PIGEON_CTRL0_FD_PERIOD_MASK = 0xFFF,
+ EPDC_PIGEON_CTRL0_FD_PERIOD_OFFSET = 0,
+
+/* EPDC EPDC_PIGEON_CTRL1 field values */
+ EPDC_PIGEON_CTRL1_LD_PERIOD_MASK = 0xFFF0000,
+ EPDC_PIGEON_CTRL1_LD_PERIOD_OFFSET = 16,
+ EPDC_PIGEON_CTRL1_FD_PERIOD_MASK = 0xFFF,
+ EPDC_PIGEON_CTRL1_FD_PERIOD_OFFSET = 0,
+
+/* EPDC_IRQ_MASK/EPDC_IRQ field values */
+ EPDC_IRQ_WB_CMPLT_IRQ = 0x10000,
+ EPDC_IRQ_LUT_COL_IRQ = 0x20000,
+ EPDC_IRQ_TCE_UNDERRUN_IRQ = 0x40000,
+ EPDC_IRQ_FRAME_END_IRQ = 0x80000,
+ EPDC_IRQ_BUS_ERROR_IRQ = 0x100000,
+ EPDC_IRQ_TCE_IDLE_IRQ = 0x200000,
+ EPDC_IRQ_UPD_DONE_IRQ = 0x400000,
+ EPDC_IRQ_PWR_IRQ = 0x800000,
+
+/* EPDC_STATUS_NEXTLUT field values */
+ EPDC_STATUS_NEXTLUT_NEXT_LUT_VALID = 0x100,
+ EPDC_STATUS_NEXTLUT_NEXT_LUT_MASK = 0x3F,
+ EPDC_STATUS_NEXTLUT_NEXT_LUT_OFFSET = 0,
+
+/* EPDC_STATUS field values */
+ EPDC_STATUS_HISTOGRAM_CP_MASK = 0x1F0000,
+ EPDC_STATUS_HISTOGRAM_CP_OFFSET = 16,
+ EPDC_STATUS_HISTOGRAM_NP_MASK = 0x1F00,
+ EPDC_STATUS_HISTOGRAM_NP_OFFSET = 8,
+ EPDC_STATUS_UPD_VOID = 0x8,
+ EPDC_STATUS_LUTS_UNDERRUN = 0x4,
+ EPDC_STATUS_LUTS_BUSY = 0x2,
+ EPDC_STATUS_WB_BUSY = 0x1,
+
+/* EPDC_UPD_COL_CORD field values */
+ EPDC_UPD_COL_CORD_YCORD_MASK = 0x1FFF0000,
+ EPDC_UPD_COL_CORD_YCORD_OFFSET = 16,
+ EPDC_UPD_COL_CORD_XCORD_MASK = 0x1FFF,
+ EPDC_UPD_COL_CORD_XCORD_OFFSET = 0,
+
+/* EPDC_UPD_COL_SIZE field values */
+ EPDC_UPD_COL_SIZE_HEIGHT_MASK = 0x1FFF0000,
+ EPDC_UPD_COL_SIZE_HEIGHT_OFFSET = 16,
+ EPDC_UPD_COL_SIZE_WIDTH_MASK = 0x1FFF,
+ EPDC_UPD_COL_SIZE_WIDTH_OFFSET = 0,
+
+/* EPDC_DEBUG field values */
+ EPDC_DEBUG_DEBUG_LUT_SEL_MASK = 0x3F00000,
+ EPDC_DEBUG_DEBUG_LUT_SEL_OFFSET = 24,
+ EPDC_DEBUG_UBW_BURST_LEN_MASK = 0xF000,
+ EPDC_DEBUG_UBW_BURST_LEN_OFFSET = 12,
+ EPDC_DEBUG_UBR_BURST_LEN_MASK = 0xF00,
+ EPDC_DEBUG_UBR_BURST_LEN = 8,
+ EPDC_DEBUG_UPD_BURST_LEN_MASK = 0xF0,
+ EPDC_DEBUG_UPD_BURST_LEN_OFFSET = 4,
+ EPDC_DEBUG_UPDATE_SAME = 0x4,
+ EPDC_DEBUG_UNDERRUN_RECOVER = 0x2,
+ EPDC_DEBUG_COLLISION_OFF = 0x1,
+
+/* EPDC_DEBUG_LUT field values */
+ EPDC_DEBUG_LUT_LUTADDR_MASK = 0x3FF0000,
+ EPDC_DEBUG_LUT_LUTADDR_OFFSET = 16,
+ EPDC_DEBUG_LUT_FRAME_MASK = 0x7FE0,
+ EPDC_DEBUG_LUT_FRAME_OFFSET = 5,
+ EPDC_DEBUG_LUT_STATEMACHINE_MASK = 0x1F,
+ EPDC_DEBUG_LUT_STATEMACHINE_OFFSET = 0,
+
+/* EPDC_HISTx_PARAM field values */
+ EPDC_HIST_PARAM_VALUE0_MASK = 0x1F,
+ EPDC_HIST_PARAM_VALUE0_OFFSET = 0,
+ EPDC_HIST_PARAM_VALUE1_MASK = 0x1F00,
+ EPDC_HIST_PARAM_VALUE1_OFFSET = 8,
+ EPDC_HIST_PARAM_VALUE2_MASK = 0x1F0000,
+ EPDC_HIST_PARAM_VALUE2_OFFSET = 16,
+ EPDC_HIST_PARAM_VALUE3_MASK = 0x1F000000,
+ EPDC_HIST_PARAM_VALUE3_OFFSET = 24,
+ EPDC_HIST_PARAM_VALUE4_MASK = 0x1F,
+ EPDC_HIST_PARAM_VALUE4_OFFSET = 0,
+ EPDC_HIST_PARAM_VALUE5_MASK = 0x1F00,
+ EPDC_HIST_PARAM_VALUE5_OFFSET = 8,
+ EPDC_HIST_PARAM_VALUE6_MASK = 0x1F0000,
+ EPDC_HIST_PARAM_VALUE6_OFFSET = 16,
+ EPDC_HIST_PARAM_VALUE7_MASK = 0x1F000000,
+ EPDC_HIST_PARAM_VALUE7_OFFSET = 24,
+ EPDC_HIST_PARAM_VALUE8_MASK = 0x1F,
+ EPDC_HIST_PARAM_VALUE8_OFFSET = 0,
+ EPDC_HIST_PARAM_VALUE9_MASK = 0x1F00,
+ EPDC_HIST_PARAM_VALUE9_OFFSET = 8,
+ EPDC_HIST_PARAM_VALUE10_MASK = 0x1F0000,
+ EPDC_HIST_PARAM_VALUE10_OFFSET = 16,
+ EPDC_HIST_PARAM_VALUE11_MASK = 0x1F000000,
+ EPDC_HIST_PARAM_VALUE11_OFFSET = 24,
+ EPDC_HIST_PARAM_VALUE12_MASK = 0x1F,
+ EPDC_HIST_PARAM_VALUE12_OFFSET = 0,
+ EPDC_HIST_PARAM_VALUE13_MASK = 0x1F00,
+ EPDC_HIST_PARAM_VALUE13_OFFSET = 8,
+ EPDC_HIST_PARAM_VALUE14_MASK = 0x1F0000,
+ EPDC_HIST_PARAM_VALUE14_OFFSET = 16,
+ EPDC_HIST_PARAM_VALUE15_MASK = 0x1F000000,
+ EPDC_HIST_PARAM_VALUE15_OFFSET = 24,
+
+/* EPDC_GPIO field values */
+ EPDC_GPIO_PWRSTAT = 0x100,
+ EPDC_GPIO_PWRWAKE = 0x80,
+ EPDC_GPIO_PWRCOM = 0x40,
+ EPDC_GPIO_PWRCTRL_MASK = 0x3C,
+ EPDC_GPIO_PWRCTRL_OFFSET = 2,
+ EPDC_GPIO_BDR_MASK = 0x3,
+ EPDC_GPIO_BDR_OFFSET = 0,
+
+/* EPDC_VERSION field values */
+ EPDC_VERSION_MAJOR_MASK = 0xFF000000,
+ EPDC_VERSION_MAJOR_OFFSET = 24,
+ EPDC_VERSION_MINOR_MASK = 0xFF0000,
+ EPDC_VERSION_MINOR_OFFSET = 16,
+ EPDC_VERSION_STEP_MASK = 0xFFFF,
+ EPDC_VERSION_STEP_OFFSET = 0,
+};
+
+#endif /* __EPDC_REGS_INCLUDED__ */
diff --git a/drivers/video/fbdev/mxc/hannstar_cabc.c b/drivers/video/fbdev/mxc/hannstar_cabc.c
new file mode 100644
index 000000000000..14528c8c6511
--- /dev/null
+++ b/drivers/video/fbdev/mxc/hannstar_cabc.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+
+#define DRIVER_NAME "hannstar-cabc"
+
+static const struct of_device_id cabc_dt_ids[] = {
+ { .compatible = "hannstar,cabc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, cabc_dt_ids);
+
+static int cabc_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node, *pp;
+ int cabc_gpio, ret = 0;
+ bool cabc_enable;
+ unsigned long gpio_flag;
+ enum of_gpio_flags flags;
+
+ for_each_child_of_node(np, pp) {
+ if (!of_find_property(pp, "gpios", NULL)) {
+ dev_warn(&pdev->dev, "Found interface without "
+ "gpios\n");
+ continue;
+ }
+
+ cabc_gpio = of_get_gpio_flags(pp, 0, &flags);
+ if (!gpio_is_valid(cabc_gpio)) {
+ ret = cabc_gpio;
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "Failed to get gpio flags, "
+ "error: %d\n", ret);
+ return ret;
+ }
+
+ cabc_enable = of_property_read_bool(pp, "cabc-enable");
+
+ if (flags & OF_GPIO_ACTIVE_LOW)
+ gpio_flag = cabc_enable ?
+ GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH;
+ else
+ gpio_flag = cabc_enable ?
+ GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+
+ devm_gpio_request_one(&pdev->dev, cabc_gpio,
+ gpio_flag, "hannstar-cabc");
+ }
+
+ return ret;
+}
+
+static struct platform_driver cabc_driver = {
+ .probe = cabc_probe,
+ .driver = {
+ .of_match_table = cabc_dt_ids,
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+module_platform_driver(cabc_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Hannstar CABC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/video/fbdev/mxc/imx_dcss.c b/drivers/video/fbdev/mxc/imx_dcss.c
new file mode 100644
index 000000000000..b065956335f3
--- /dev/null
+++ b/drivers/video/fbdev/mxc/imx_dcss.c
@@ -0,0 +1,3585 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/cache.h>
+#include <asm/cacheflush.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/irqdesc.h>
+#include <linux/fb.h>
+#include <linux/freezer.h>
+#include <linux/kfifo.h>
+#include <linux/kthread.h>
+#include <linux/log2.h>
+#include <linux/regulator/consumer.h>
+#include <linux/scatterlist.h>
+#include <linux/videodev2.h>
+#include <video/mxc_edid.h>
+#include <linux/workqueue.h>
+
+#include "mxc_dispdrv.h"
+#include "imx_dcss_table.h"
+
+/* sub engines address start offset */
+#define HDR_CHAN1_START 0x00000
+#define HDR_CHAN2_START 0x04000
+#define HDR_CHAN3_START 0x08000
+#define HDR_OUT_START 0x0C000
+#define DOLBY_VISION_START 0x10000
+#define DOLBY_GRAPHIC_START 0x11000
+#define DOLBY_OUTPUT_START 0x12000
+#define DEC400D_CHAN1_START 0x15000
+#define DTRC_CHAN2_START 0x16000
+#define DTRC_CHAN3_START 0x17000
+#define DPR_CHAN1_START 0x18000
+#define DPR_CHAN2_START 0x19000
+#define DPR_CHAN3_START 0x1A000
+#define SUBSAM_START 0x1B000
+#define SCALER_CHAN1_START 0x1C000
+#define SCALER_CHAN2_START 0x1C400
+#define SCALER_CHAN3_START 0x1C800
+#define DTG_START 0x20000
+#define WR_SCL_START 0x21000
+#define RD_SRC_START 0x22000
+#define CTX_LD_START 0x23000
+#define LUT_LD_START 0x24000
+#define IRQ_STEER_START 0x2D000
+#define LPCG_START 0x2E000
+#define BLK_CTRL_START 0x2F000
+
+#define DCSS_MODE_SCALE_EN (1 << 0)
+#define DCSS_MODE_CSC_EN (1 << 1)
+#define DCSS_MODE_RESOLVE_EN (1 << 2)
+#define DCSS_MODE_DECOMPRESS_EN (1 << 3)
+#define DCSS_MODE_HDR10_EN (1 << 4)
+#define DCSS_MODE_DOLBY_EN (1 << 5)
+
+/* define several clocks rate */
+#define DISP_AXI_RATE 800000000
+#define DISP_APB_RATE 133000000
+#define DISP_RTRAM_RATE 400000000
+#define DISP_PIXEL_RATE 100000000
+
+#define TILE_TYPE_LINEAR 0x0
+#define TILE_TYPE_GPU_STANDARD 0x1
+#define TILE_TYPE_GPU_SUPER 0x2
+#define TILE_TYPE_VPU_2PYUV420 0x3
+#define TILE_TYPE_VPU_2PVP9 0x4
+
+#define PIXEL_STORE_NONCOMPRESS 0x1
+#define PIXEL_STORE_COMPRESS 0x2
+
+#define CSC_MODE_BYPASS 0x0
+#define CSC_MODE_YUV2RGB 0x1
+#define CSC_MODE_RGB2YUV 0x2
+
+#define HSYNC_ACTIVE_HIGH 0x1
+#define VSYNC_ACTIVE_HIGH 0x1
+#define DE_ACTIVE_HIGH 0x1
+
+/* pixel format macros */
+#define PIX_FMT_A8R8G8B8 0x1
+#define PIX_FMT_A2R10G10B10 0x2
+#define PIX_FMT_1PYUV422 0x3
+#define PIX_FMT_2PYUV420_8 0x4
+#define PIX_FMT_2PYUV420_10 0x5
+#define PIX_FMT_2PVP9_8 0x6
+#define PIX_FMT_2PVP9_10 0x7
+#define PIX_FMT_AYUV444 0x8
+
+/* more formats fourcc define */
+#define V4L2_PIX_FMT_A2R10G10B10 v4l2_fourcc('B', 'A', '3', '0') /* 32 ARGB-2-10-10-10 */
+
+#define MAX_WIDTH 4096
+#define MAX_HEIGHT 4096
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define TRANSP 3
+
+#define CTXLD_TYPE_DB 0x1
+#define CTXLD_TYPE_SB 0x2
+
+#define DCSS_REGS_SIZE 0x30000
+#define DCSS_CFIFO_SIZE 0x100000 /* power of 2 */
+#define DCSS_IRQS_NUM 32
+
+/* define registers offset */
+#define CTXLD_CTRL_STATUS 0x0
+#define CTXLD_CTRL_STATUS_SET 0x4
+#define CTXLD_CTRL_STATUS_CLR 0x8
+#define CTXLD_CTRL_STATUS_TOG 0xC
+
+#define CTXLD_DB_BASE_ADDR 0x10
+#define CTXLD_DB_COUNT 0x14
+#define CTXLD_SB_BASE_ADDR 0x18
+#define CTXLD_SB_COUNT 0x1C
+
+#define TC_LINE1_INT 0x50
+#define TC_INTERRUPT_STATUS 0x5C
+#define TC_INTERRUPT_CONTROL 0x60
+#define TC_INTERRUPT_MASK 0x68
+
+/* define dcss state */
+#define DCSS_STATE_RESET 0x0
+#define DCSS_STATE_RUNNING 0x1
+#define DCSS_STATE_STOP 0x2
+
+/* io memory blocks number */
+#define IORESOURCE_MEM_NUM 0x2
+
+#define USE_CTXLD 0x1
+
+#define NAME_LEN 32
+
+/* TODO: DCSS IRQs indexes, more added later */
+#define IRQ_DPR_CH1 3
+#define IRQ_DPR_CH2 4
+#define IRQ_DPR_CH3 5
+#define IRQ_CTX_LD 6
+#define IRQ_TC_LINE1 8
+#define IRQ_DEC400D_CH1 15
+#define IRQ_DTRC_CH2 16
+#define IRQ_DTRC_CH3 17
+
+/* ctxld irqs status */
+#define RD_ERR (1 << 16)
+#define DB_COMP (1 << 17)
+#define SB_HP_COMP (1 << 18)
+#define SB_LP_COMP (1 << 19)
+#define AHB_ERR (1 << 22)
+
+/* ctxld irqs mask */
+#define RD_ERR_EN (1 << 2)
+#define DB_COMP_EN (1 << 3)
+#define SB_HP_COMP_EN (1 << 4)
+#define SB_LP_COMP_EN (1 << 5)
+#define AHB_ERR_EN (1 << 8)
+
+/* channels */
+#define DCSS_CHAN_MAIN 0
+#define DCSS_CHAN_SECONDARY 1
+#define DCSS_CHAN_THIRD 2
+/* all channels are disabled */
+#define DCSS_CHAN_NULL 3
+
+/**
+ * kfifo_to_end_len - returns the size from 'out' to buffer end
+ * this is a kfifo extend interface as required
+ */
+#define kfifo_to_end_len(fifo) ( \
+{ \
+ unsigned int ptr; \
+ \
+ if (!(fifo)->kfifo.in) \
+ ptr = 0; \
+ else \
+ ptr = ((((fifo)->kfifo.in - 1) & (fifo)->kfifo.mask) + 1); \
+ \
+ kfifo_size(fifo) - ptr; \
+} \
+)
+
+/* TODO: */
+struct coordinate {
+ uint32_t x;
+ uint32_t y;
+};
+
+struct rectangle {
+ uint32_t ulc_x;
+ uint32_t ulc_y;
+ uint32_t lrc_x;
+ uint32_t lrc_y;
+};
+
+struct pix_fmt_info {
+ uint32_t fourcc;
+ uint32_t bpp;
+ bool is_yuv;
+};
+
+struct dcss_pixmap {
+ uint32_t channel_id;
+ uint32_t width;
+ uint32_t height;
+ uint32_t bits_per_pixel;
+ uint32_t pitch;
+ struct rectangle crop; /* active area */
+ uint32_t format;
+ uint32_t tile_type; /* see TILE_TYPE_* macros */
+ uint32_t pixel_store; /* see PIXEL_STORE_* macros */
+ uint32_t flags;
+ dma_addr_t paddr;
+};
+
+/* Display state format in DRAM used by CTX_LD */
+struct ctxld_unit {
+ uint32_t reg_value;
+ uint32_t reg_offset;
+};
+
+/* ctxld buffer */
+struct cbuffer{
+ void *sb_addr;
+ void *db_addr;
+ uint32_t sb_len; /* buffer length in elements */
+ uint32_t db_len;
+ uint32_t sb_data_len; /* data length in elements */
+ uint32_t db_data_len;
+ uint32_t esize; /* size per element */
+};
+
+struct vsync_info {
+ wait_queue_head_t vwait;
+ unsigned long vcount;
+};
+
+struct ctxld_commit {
+ struct list_head list;
+ struct kref refcount;
+ struct work_struct work;
+ void *data;
+ uint32_t sb_data_len;
+ uint32_t sb_hp_data_len;
+ uint32_t db_data_len;
+ uint32_t sb_trig_pos;
+ uint32_t db_trig_pos;
+};
+
+struct ctxld_fifo {
+ uint32_t size;
+ void *vaddr;
+ dma_addr_t dma_handle;
+ struct list_head ctxld_list; /* manage context loader */
+ DECLARE_KFIFO_PTR(fifo, struct ctxld_unit);
+ struct scatterlist sgl[1];
+ uint32_t sgl_num;
+ struct workqueue_struct *ctxld_wq;
+ /* synchronization in two points:
+ * a. simutanous fifo commits
+ * b. queue waiting for cfifo flush
+ */
+ wait_queue_head_t cqueue;
+ struct completion complete;
+};
+
+/* channel info: 3 channels in DCSS */
+struct dcss_channel_info {
+ uint32_t channel_id;
+ uint32_t channel_en; /* channel 1 enable by default */
+ struct platform_device *pdev;
+ struct fb_info *fb_info;
+ struct dcss_pixmap input;
+ struct rectangle ch_pos; /* display position in dtg for one channel */
+ struct cbuffer cb;
+ uint32_t hdr10_in_addr;
+ uint32_t decomp_addr;
+ uint32_t dpr_addr;
+ uint32_t scaler_addr;
+ int blank; /* see FB_BLANK_* macros */
+ uint32_t csc_mode; /* see CSC_MODE_* macros */
+ bool dpr_scaler_en; /* record dpr and scaler enabled or not */
+ unsigned long update_stamp; /* default is ~0x0UL */
+
+ void *dev_data; /* pointer to dcss_info */
+};
+
+struct dcss_channels {
+ struct dcss_channel_info chan_info[3];
+ uint32_t hdr10_out_addr;
+ uint32_t subsam_addr;
+ uint32_t dtg_addr;
+ uint32_t wrscl_addr;
+ uint32_t rdsrc_addr;
+ uint32_t ctxld_addr;
+ uint32_t lutld_addr;
+ uint32_t hdmi_phy_addr;
+ uint32_t irq_steer_addr;
+ uint32_t lpcg_addr;
+ uint32_t blk_ctrl_addr;
+};
+
+/* display info: output to monitor */
+struct dcss_info {
+ struct platform_device *pdev;
+ void __iomem *base;
+ void __iomem *blkctl_base;
+ spinlock_t llock; /* list lock: for ctxld_list */
+ int irqs[DCSS_IRQS_NUM];
+ uint32_t irqs_num;
+ uint32_t dcss_state; /* see DCSS_STATE_* macros */
+ struct clk *clk_axi;
+ struct clk *clk_apb;
+ struct clk *clk_rtram;
+ struct clk *clk_dtrc;
+ struct clk *clk_pix;
+ struct regulator *power;
+ struct ctxld_fifo cfifo;
+ struct task_struct *handler;
+ struct dcss_pixmap *output;
+ struct dcss_channels chans; /* maximum 3 channels
+ * TODO: better change to layer
+ */
+ const struct fb_videomode *dft_disp_mode; /* Default display mode */
+ uint32_t tile_type; /* see TILE_TYPE_* macros */
+ uint32_t pixel_store; /* see PIXEL_STORE_* macros */
+ uint32_t csc_mode; /* see CSC_MODE_* macros */
+ uint32_t mode_flags; /* see DCSS_MODE_* macros */
+ uint32_t sync_flags; /* see FB_SYNC_* macros */
+ uint32_t hsync_pol;
+ uint32_t vsync_pol;
+ uint32_t de_pol;
+ char disp_dev[NAME_LEN];
+ struct mxc_dispdrv_handle *dispdrv;
+ struct vsync_info vinfo;
+
+ atomic_t flush;
+};
+
+const struct fb_videomode imx_cea_mode[100] = {
+ /* #1: 640x480p@59.94/60Hz 4:3 */
+ [1] = {
+ NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #2: 720x480p@59.94/60Hz 4:3 */
+ [2] = {
+ NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #3: 720x480p@59.94/60Hz 16:9 */
+ [3] = {
+ NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #4: 1280x720p@59.94/60Hz 16:9 */
+ [4] = {
+ NULL, 60, 1280, 720, 13468, 220, 110, 20, 5, 40, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0
+ },
+ /* #5: 1920x1080i@59.94/60Hz 16:9 */
+ [5] = {
+ NULL, 60, 1920, 1080, 13763, 148, 88, 15, 2, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_INTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #6: 720(1440)x480iH@59.94/60Hz 4:3 */
+ [6] = {
+ NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0,
+ FB_VMODE_INTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #7: 720(1440)x480iH@59.94/60Hz 16:9 */
+ [7] = {
+ NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0,
+ FB_VMODE_INTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #8: 720(1440)x240pH@59.94/60Hz 4:3 */
+ [8] = {
+ NULL, 60, 1440, 240, 37108, 114, 38, 15, 4, 124, 3, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #9: 720(1440)x240pH@59.94/60Hz 16:9 */
+ [9] = {
+ NULL, 60, 1440, 240, 37108, 114, 38, 15, 4, 124, 3, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #14: 1440x480p@59.94/60Hz 4:3 */
+ [14] = {
+ NULL, 60, 1440, 480, 18500, 120, 32, 30, 9, 124, 6, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #15: 1440x480p@59.94/60Hz 16:9 */
+ [15] = {
+ NULL, 60, 1440, 480, 18500, 120, 32, 30, 9, 124, 6, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #16: 1920x1080p@60Hz 16:9 */
+ [16] = {
+ NULL, 60, 1920, 1080, 6734, 148, 88, 36, 4, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #17: 720x576pH@50Hz 4:3 */
+ [17] = {
+ NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #18: 720x576pH@50Hz 16:9 */
+ [18] = {
+ NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #19: 1280x720p@50Hz */
+ [19] = {
+ NULL, 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #20: 1920x1080i@50Hz */
+ [20] = {
+ NULL, 50, 1920, 1080, 13480, 148, 528, 15, 5, 528, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_INTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #23: 720(1440)x288pH@50Hz 4:3 */
+ [23] = {
+ NULL, 50, 1440, 288, 37037, 138, 24, 19, 2, 126, 3, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #24: 720(1440)x288pH@50Hz 16:9 */
+ [24] = {
+ NULL, 50, 1440, 288, 37037, 138, 24, 19, 2, 126, 3, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #29: 720(1440)x576pH@50Hz 4:3 */
+ [29] = {
+ NULL, 50, 1440, 576, 18518, 136, 24, 39, 5, 128, 5, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #30: 720(1440)x576pH@50Hz 16:9 */
+ [30] = {
+ NULL, 50, 1440, 576, 18518, 136, 24, 39, 5, 128, 5, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #31: 1920x1080p@50Hz */
+ [31] = {
+ NULL, 50, 1920, 1080, 6734, 148, 528, 36, 4, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #32: 1920x1080p@23.98/24Hz */
+ [32] = {
+ NULL, 24, 1920, 1080, 13468, 148, 638, 36, 4, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #33: 1920x1080p@25Hz */
+ [33] = {
+ NULL, 25, 1920, 1080, 13468, 148, 528, 36, 4, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #34: 1920x1080p@30Hz */
+ [34] = {
+ NULL, 30, 1920, 1080, 13468, 148, 88, 36, 4, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #41: 1280x720p@100Hz 16:9 */
+ [41] = {
+ NULL, 100, 1280, 720, 6734, 220, 440, 20, 5, 40, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0
+ },
+ /* #47: 1280x720p@119.88/120Hz 16:9 */
+ [47] = {
+ NULL, 120, 1280, 720, 6734, 220, 110, 20, 5, 40, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0
+ },
+ /* #95: 3840x2160p@30Hz 16:9 */
+ [95] = {
+ NULL, 30, 3840, 2160, 3367, 296, 176, 72, 8, 88, 10,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0
+ },
+ /* #97: 3840x2160p@60Hz 16:9 */
+ [97] = {
+ NULL, 30, 3840, 2160, 1684, 296, 176, 72, 8, 88, 10,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0
+ },
+};
+
+static const struct of_device_id dcss_dt_ids[] ={
+ { .compatible = "fsl,imx8mq-dcss", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, dcss_dt_ids);
+
+static void dcss_free_fbmem(struct fb_info *fbi);
+static int dcss_open(struct fb_info *fbi, int user);
+static int dcss_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *fbi);
+static int dcss_set_par(struct fb_info *fbi);
+static int dcss_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp, struct fb_info *info);
+static int dcss_blank(int blank, struct fb_info *fbi);
+static int dcss_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *fbi);
+static int dcss_ioctl(struct fb_info *fbi, unsigned int cmd,
+ unsigned long arg);
+static int vcount_compare(unsigned long vcount,
+ struct vsync_info *vinfo);
+static int dcss_wait_for_vsync(unsigned long crtc,
+ struct dcss_info *info);
+static void flush_cfifo(struct ctxld_fifo *cfifo,
+ struct work_struct *work);
+
+static struct fb_ops dcss_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = dcss_open,
+ .fb_check_var = dcss_check_var,
+ .fb_set_par = dcss_set_par,
+ .fb_setcolreg = dcss_setcolreg,
+ .fb_blank = dcss_blank,
+ .fb_pan_display = dcss_pan_display,
+ .fb_ioctl = dcss_ioctl,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+/* TODO: more added later */
+static const struct pix_fmt_info formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_ARGB32,
+ .bpp = 32,
+ .is_yuv = false,
+ }, {
+ .fourcc = V4L2_PIX_FMT_A2R10G10B10,
+ .bpp = 32,
+ .is_yuv = false,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .bpp = 16,
+ .is_yuv = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .bpp = 16,
+ .is_yuv = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .bpp = 16,
+ .is_yuv = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .bpp = 16,
+ .is_yuv = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YUV32,
+ .bpp = 32,
+ .is_yuv = true,
+ }, {
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .bpp = 8,
+ .is_yuv = true,
+ },
+};
+
+static const struct fb_bitfield def_a8r8g8b8[] = {
+ [RED] = {
+ .offset = 16,
+ .length = 8,
+ .msb_right = 0,
+ },
+ [GREEN] = {
+ .offset = 8,
+ .length = 8,
+ .msb_right = 0,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 8,
+ .msb_right = 0,
+ },
+ [TRANSP] = {
+ .offset = 24,
+ .length = 8,
+ .msb_right = 0,
+ }
+};
+
+static const struct fb_bitfield def_a2r10g10b10[] = {
+ [RED] = {
+ .offset = 20,
+ .length = 10,
+ },
+ [GREEN] = {
+ .offset = 10,
+ .length = 10,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 10,
+ },
+ [TRANSP] = {
+ .offset = 30,
+ .length = 2,
+ }
+};
+
+static const struct pix_fmt_info *get_fmt_info(uint32_t fourcc)
+{
+ uint32_t i;
+
+ for (i = 0; i < ARRAY_SIZE(formats); i++) {
+ if (formats[i].fourcc == fourcc)
+ return &formats[i];
+ }
+
+ return NULL;
+}
+
+static int fmt_is_yuv(uint32_t fourcc)
+{
+ switch (fourcc) {
+ case V4L2_PIX_FMT_ARGB32:
+ case V4L2_PIX_FMT_A2R10G10B10:
+ return 0;
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ case V4L2_PIX_FMT_YUV32:
+ return 1;
+ case V4L2_PIX_FMT_NV12:
+ return 2;
+ default:
+ return -EINVAL;
+ }
+}
+
+/* TODO: writel ? */
+#define fill_unit(uint, offset, value) { \
+ unit->reg_value = value; \
+ unit->reg_offset = offset; \
+}
+
+static void fill_sb(struct cbuffer *cb,
+ uint32_t offset,
+ uint32_t value)
+{
+ struct ctxld_unit *unit = NULL;
+
+ BUG_ON(!cb);
+
+ if (unlikely(cb->sb_data_len == cb->sb_len)) {
+ /* sb is full */
+ BUG_ON(1);
+ }
+
+ unit = (struct ctxld_unit *)(cb->sb_addr + cb->sb_data_len * cb->esize);
+
+ fill_unit(unit, offset, value);
+ cb->sb_data_len++;
+}
+
+static void __maybe_unused fill_db(struct cbuffer *cb,
+ uint32_t offset,
+ uint32_t value)
+{
+ struct ctxld_unit *unit = NULL;
+
+ BUG_ON(!cb);
+
+ if (unlikely(cb->db_data_len == cb->db_len)) {
+ /* db is full */
+ BUG_ON(1);
+ }
+
+ unit = (struct ctxld_unit *)(cb->db_addr + cb->db_data_len * cb->esize);
+
+ fill_unit(unit, offset, value);
+ cb->db_data_len++;
+}
+
+static void ctxld_fifo_info_print(struct ctxld_fifo *cfifo)
+{
+ pr_debug("%s: print kfifo info: **********\n", __func__);
+ pr_debug("in = 0x%x, out = 0x%x, mask = 0x%x\n",
+ cfifo->fifo.kfifo.in,
+ cfifo->fifo.kfifo.out,
+ cfifo->fifo.kfifo.mask);
+}
+
+static int ctxld_fifo_alloc(struct device *dev,
+ struct ctxld_fifo *cfifo,
+ uint32_t fifo_size)
+{
+ if (!cfifo || fifo_size < 2)
+ return -EINVAL;
+
+ fifo_size = roundup_pow_of_two(fifo_size);
+ cfifo->vaddr = dma_alloc_coherent(dev, fifo_size,
+ &cfifo->dma_handle,
+ GFP_DMA | GFP_KERNEL);
+ if (!cfifo->vaddr) {
+ dev_err(dev, "allocate ctxld fifo failed\n");
+ return -ENOMEM;
+ }
+
+ cfifo->size = fifo_size;
+ kfifo_init(&cfifo->fifo, cfifo->vaddr, fifo_size);
+
+ /* TODO: sgl num can be changed if required */
+ cfifo->sgl_num = 1;
+
+ INIT_LIST_HEAD(&cfifo->ctxld_list);
+ init_waitqueue_head(&cfifo->cqueue);
+ init_completion(&cfifo->complete);
+
+ return 0;
+}
+
+static void ctxld_fifo_free(struct device *dev,
+ struct ctxld_fifo *cfifo)
+{
+ if (!cfifo)
+ return;
+
+ /* TODO: wait fifo flush empty */
+
+ kfifo_reset(&cfifo->fifo);
+
+ dma_free_coherent(dev, cfifo->size,
+ cfifo->vaddr,
+ cfifo->dma_handle);
+
+ cfifo->size = 0;
+ cfifo->vaddr = NULL;
+ cfifo->dma_handle = 0;
+
+ memset(cfifo->sgl, 0x0, sizeof(*cfifo->sgl));
+ cfifo->sgl_num = 0;
+}
+
+static int dcss_clks_get(struct dcss_info *info)
+{
+ int ret = 0;
+ struct platform_device *pdev = info->pdev;
+
+ info->clk_axi = devm_clk_get(&pdev->dev, "axi");
+ if (IS_ERR(info->clk_axi)) {
+ ret = PTR_ERR(info->clk_axi);
+ goto out;
+ }
+
+ info->clk_apb = devm_clk_get(&pdev->dev, "apb");
+ if (IS_ERR(info->clk_apb)) {
+ ret = PTR_ERR(info->clk_apb);
+ goto put_axi;
+ }
+
+ info->clk_rtram = devm_clk_get(&pdev->dev, "rtram");
+ if (IS_ERR(info->clk_rtram)) {
+ ret = PTR_ERR(info->clk_rtram);
+ goto put_apb;
+ }
+
+ info->clk_dtrc = devm_clk_get(&pdev->dev, "dtrc");
+ if (IS_ERR(info->clk_dtrc)) {
+ ret = PTR_ERR(info->clk_dtrc);
+ goto put_rtram;
+ }
+
+ info->clk_pix = devm_clk_get(&pdev->dev, "pix");
+ if (IS_ERR(info->clk_pix)) {
+ ret = PTR_ERR(info->clk_pix);
+ goto put_dtrc;
+ }
+
+ goto out;
+
+put_dtrc:
+ devm_clk_put(&pdev->dev, info->clk_dtrc);
+put_rtram:
+ devm_clk_put(&pdev->dev, info->clk_rtram);
+put_apb:
+ devm_clk_put(&pdev->dev, info->clk_apb);
+put_axi:
+ devm_clk_put(&pdev->dev, info->clk_axi);
+out:
+ return ret;
+}
+
+#if 0
+static void dcss_clks_put(struct dcss_info *info)
+{
+ struct platform_device *pdev = info->pdev;
+
+ devm_clk_put(&pdev->dev, info->clk_axi);
+ devm_clk_put(&pdev->dev, info->clk_apb);
+ devm_clk_put(&pdev->dev, info->clk_rtram);
+ devm_clk_put(&pdev->dev, info->clk_dtrc);
+ devm_clk_put(&pdev->dev, info->clk_pix);
+}
+#endif
+
+static void fb_var_to_pixmap(struct dcss_pixmap *pixmap,
+ struct fb_var_screeninfo *var)
+{
+ BUG_ON(!pixmap || !var);
+
+ pixmap->width = var->xres;
+ pixmap->height = var->yres;
+ pixmap->bits_per_pixel = var->bits_per_pixel;
+ pixmap->pitch = var->width * (var->bits_per_pixel >> 3);
+ pixmap->crop.ulc_x = 0;
+ pixmap->crop.ulc_y = 0;
+ pixmap->crop.lrc_x = var->xres;
+ pixmap->crop.lrc_y = var->yres;
+ pixmap->format = var->grayscale;
+
+ /* TODO possible passed through 'reserved' ? */
+ pixmap->tile_type = TILE_TYPE_LINEAR;
+ pixmap->pixel_store = PIXEL_STORE_NONCOMPRESS;
+}
+
+static int fill_one_chan_info(uint32_t chan_id,
+ struct dcss_channel_info *info)
+{
+ void *dsb; /* mem to store ctxld units */
+ struct cbuffer *cb;
+ struct platform_device *pdev;
+
+ BUG_ON(!info || IS_ERR(info));
+ pdev = info->pdev;
+
+ if (chan_id > 2) {
+ dev_err(&pdev->dev, "incorrect channel number: %d\n", chan_id);
+ return -EINVAL;
+ }
+
+ info->channel_id = chan_id;
+ info->channel_en = (chan_id == 0) ? 1 : 0;
+ info->blank = FB_BLANK_NORMAL;
+ info->update_stamp = ~0x0UL;
+
+ switch (chan_id) {
+ case 0:
+ info->hdr10_in_addr = HDR_CHAN1_START;
+ info->decomp_addr = DEC400D_CHAN1_START;
+ info->dpr_addr = DPR_CHAN1_START;
+ info->scaler_addr = SCALER_CHAN1_START;
+ break;
+ case 1:
+ info->hdr10_in_addr = HDR_CHAN2_START;
+ info->decomp_addr = DTRC_CHAN2_START;
+ info->dpr_addr = DPR_CHAN2_START;
+ info->scaler_addr = SCALER_CHAN2_START;
+ break;
+ case 2:
+ info->hdr10_in_addr = HDR_CHAN3_START;
+ info->decomp_addr = DTRC_CHAN3_START;
+ info->dpr_addr = DPR_CHAN3_START;
+ info->scaler_addr = SCALER_CHAN3_START;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* dsb is used to hold double & single buffer units */
+ dsb = devm_kzalloc(&pdev->dev, DCSS_REGS_SIZE << 1, GFP_KERNEL);
+ if (!dsb)
+ return -ENOMEM;
+
+ /* init cbuffer struct */
+ cb = &info->cb;
+ cb->esize = sizeof(struct ctxld_unit);
+
+ cb->sb_addr = dsb;
+ cb->sb_len = DCSS_REGS_SIZE / cb->esize;
+ cb->sb_data_len = 0x0;
+
+ cb->db_addr = dsb + DCSS_REGS_SIZE;
+ cb->db_len = DCSS_REGS_SIZE / cb->esize;
+ cb->db_data_len = 0x0;
+
+ return 0;
+}
+
+/* allocate fb info for one channel */
+static int alloc_one_fbinfo(struct dcss_channel_info *cinfo)
+{
+ struct platform_device *pdev;
+
+ BUG_ON(!cinfo || IS_ERR(cinfo));
+
+ pdev = cinfo->pdev;
+ if (!pdev)
+ return -ENODEV;
+
+ cinfo->fb_info = framebuffer_alloc(0, &pdev->dev);
+ if (!cinfo->fb_info) {
+ dev_err(&pdev->dev, "failed to alloc fb info for channel %d\n",
+ cinfo->channel_id);
+ return -ENOMEM;
+ }
+
+ cinfo->fb_info->par = cinfo;
+ INIT_LIST_HEAD(&cinfo->fb_info->modelist);
+
+ return 0;
+}
+
+static struct fb_info *get_one_fbinfo(uint32_t ch_id,
+ struct dcss_channels *chans)
+{
+ struct dcss_channel_info *cinfo;
+
+ if (ch_id > 2)
+ return NULL;
+
+ cinfo = &chans->chan_info[ch_id];
+
+ return cinfo->fb_info;
+}
+
+static int init_chan_pixmap(struct dcss_channel_info *cinfo)
+{
+ struct dcss_pixmap *pixmap;
+ struct fb_info *fbi;
+ struct fb_var_screeninfo *var;
+
+ BUG_ON(!cinfo || IS_ERR(cinfo));
+
+ pixmap = &cinfo->input;
+ fbi = cinfo->fb_info;
+ var = &fbi->var;
+
+ fb_var_to_pixmap(pixmap, var);
+
+ return 0;
+}
+
+static int init_ch_pos(struct dcss_channel_info *cinfo)
+{
+ struct rectangle *pos;
+ struct fb_info *fbi;
+ struct fb_var_screeninfo *var;
+
+ /* TODO: init ch_pos with var temporarily */
+ pos = &cinfo->ch_pos;
+ fbi = cinfo->fb_info;
+ var = &fbi->var;
+
+ pos->ulc_x = var->left_margin + var->hsync_len - 1;
+ pos->ulc_y = var->upper_margin + var->lower_margin +
+ var->vsync_len - 1;
+ pos->lrc_x = var->xres + var->left_margin +
+ var->hsync_len - 1;
+ pos->lrc_y = var->yres + var->upper_margin +
+ var->lower_margin + var->vsync_len - 1;
+
+ return 0;
+}
+
+static int dcss_init_chans(struct dcss_info *info)
+{
+ struct dcss_channels *dcss_chans = &info->chans;
+
+ /* init sharable info between chans */
+ dcss_chans->hdr10_out_addr = HDR_OUT_START;
+ dcss_chans->subsam_addr = SUBSAM_START;
+ dcss_chans->dtg_addr = DTG_START;
+ dcss_chans->wrscl_addr = WR_SCL_START;
+ dcss_chans->rdsrc_addr = RD_SRC_START;
+ dcss_chans->ctxld_addr = CTX_LD_START;
+ dcss_chans->lutld_addr = LUT_LD_START;
+ dcss_chans->hdmi_phy_addr = 0;
+ dcss_chans->irq_steer_addr = IRQ_STEER_START;
+ dcss_chans->lpcg_addr = LPCG_START;
+ dcss_chans->blk_ctrl_addr = BLK_CTRL_START;
+
+ return 0;
+}
+
+static int dcss_init_fbinfo(struct fb_info *fbi)
+{
+ int ret;
+ uint32_t luma_size;
+ struct dcss_channel_info *cinfo = fbi->par;
+ struct dcss_info *info = cinfo->dev_data;
+ struct fb_fix_screeninfo *fix = &fbi->fix;
+ struct fb_var_screeninfo *var = &fbi->var;
+ struct fb_modelist *modelist;
+
+ fbi->fbops = &dcss_ops;
+
+ /* init fix screeninfo */
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->ypanstep = 1;
+ fix->ywrapstep = 1;
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ fix->accel = FB_ACCEL_NONE;
+
+ ret = fb_add_videomode(info->dft_disp_mode, &fbi->modelist);
+ if (ret)
+ return ret;
+
+ /* init var screeninfo */
+ modelist = list_first_entry(&fbi->modelist,
+ struct fb_modelist, list);
+ fb_videomode_to_var(var, &modelist->mode);
+ var->nonstd = 0;
+ var->activate = FB_ACTIVATE_NOW;
+ var->vmode = FB_VMODE_NONINTERLACED;
+ /* default format */
+ if (cinfo->channel_id == DCSS_CHAN_MAIN)
+ /* main channel is for graphic */
+ var->grayscale = V4L2_PIX_FMT_ARGB32;
+ else
+ /* other channels are for video */
+ var->grayscale = V4L2_PIX_FMT_NV12;
+
+ /* Allocate memory buffer: Maybe need alignment */
+ fix->smem_len = (fix->line_length * var->yres_virtual > SZ_32M) ?
+ fix->line_length * var->yres_virtual : SZ_32M;
+ fbi->screen_base = dma_alloc_writecombine(fbi->device, fix->smem_len,
+ (dma_addr_t *)&fix->smem_start,
+ GFP_DMA | GFP_KERNEL);
+ if (!fbi->screen_base) {
+ dev_err(fbi->device, "Unable to alloc fb memory\n");
+ fix->smem_len = 0;
+ fix->smem_start = 0;
+ return -ENOMEM;
+ }
+ dev_dbg(fbi->device, "%s: smem_start = 0x%lx, screen_base = 0x%p\n",
+ __func__, fix->smem_start, fbi->screen_base);
+
+ fbi->screen_size = fix->smem_len;
+
+ fbi->pseudo_palette = devm_kzalloc(fbi->device,
+ sizeof(u32) * 16, GFP_KERNEL);
+ if (!fbi->pseudo_palette) {
+ dev_err(fbi->device, "alloc pseudo_palette failed\n");
+ dcss_free_fbmem(fbi);
+ return -ENOMEM;
+ }
+
+ /* clear screen content to black */
+ switch (var->grayscale) {
+ case V4L2_PIX_FMT_ARGB32:
+ memset((void*)fbi->screen_base, 0x0, fix->smem_len);
+ break;
+ case V4L2_PIX_FMT_NV12:
+ /* set luma: 0x0 */
+ luma_size = var->xres * var->yres;
+ memset((void*)fbi->screen_base, 0x0, luma_size);
+ /* set chroma: 0x80 */
+ memset((void*)fbi->screen_base + luma_size, 0x80, luma_size);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (dcss_check_var(var, fbi)) {
+ devm_kfree(fbi->device, fbi->pseudo_palette);
+ dcss_free_fbmem(fbi);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void dcss_free_fbmem(struct fb_info *fbi)
+{
+ struct fb_fix_screeninfo *fix = &fbi->fix;
+
+ dma_free_writecombine(fbi->device, fix->smem_len,
+ fbi->screen_base,
+ (dma_addr_t)fix->smem_start);
+
+ fbi->screen_base = NULL;
+ fix->smem_start = 0;
+ fix->smem_len = 0;
+}
+
+static int dcss_clks_enable(struct dcss_info *info)
+{
+ int ret = 0;
+ struct platform_device *pdev = info->pdev;
+
+ /* TODO: Add return value check */
+ ret = clk_prepare_enable(info->clk_axi);
+ if (ret) {
+ dev_err(&pdev->dev, "enable axi clock failed\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(info->clk_apb);
+ if (ret) {
+ dev_err(&pdev->dev, "enable apb clock failed\n");
+ goto disable_axi;
+ }
+
+ ret = clk_prepare_enable(info->clk_rtram);
+ if (ret) {
+ dev_err(&pdev->dev, "enable rtram clock failed\n");
+ goto disable_apb;
+ }
+
+ ret = clk_prepare_enable(info->clk_dtrc);
+ if (ret) {
+ dev_err(&pdev->dev, "enable dtrc clock failed\n");
+ goto disable_rtram;
+ }
+
+ ret = clk_prepare_enable(info->clk_pix);
+ if (ret) {
+ dev_err(&pdev->dev, "enable pix clock failed\n");
+ goto disable_dtrc;
+ }
+
+ goto out;
+
+disable_dtrc:
+ clk_disable_unprepare(info->clk_dtrc);
+disable_rtram:
+ clk_disable_unprepare(info->clk_rtram);
+disable_apb:
+ clk_disable_unprepare(info->clk_apb);
+disable_axi:
+ clk_disable_unprepare(info->clk_axi);
+out:
+ return ret;
+}
+
+#if 0
+static void dcss_clks_disable(struct dcss_info *info)
+{
+ clk_disable_unprepare(info->clk_axi);
+ clk_disable_unprepare(info->clk_apb);
+ clk_disable_unprepare(info->clk_rtram);
+ clk_disable_unprepare(info->clk_dtrc);
+ clk_disable_unprepare(info->clk_pix);
+}
+#endif
+
+static int dcss_clks_rate_set(struct dcss_info *info)
+{
+ int ret;
+ uint32_t pix_clk_rate;
+ struct platform_device *pdev = info->pdev;
+
+ /* TODO: axi, abp, rtrm clock rate are set by uboot already */
+ ret = clk_set_rate(info->clk_axi, DISP_AXI_RATE);
+ if (ret) {
+ dev_err(&pdev->dev, "set axi clock rate failed\n");
+ return ret;
+ }
+
+ ret = clk_set_rate(info->clk_apb, DISP_APB_RATE);
+ if (ret) {
+ dev_err(&pdev->dev, "set apb clock rate failed\n");
+ return ret;
+ }
+
+ ret = clk_set_rate(info->clk_rtram, DISP_RTRAM_RATE);
+ if (ret) {
+ dev_err(&pdev->dev, "set rtram clock rate failed\n");
+ return ret;
+ }
+
+ pix_clk_rate = PICOS2KHZ(info->dft_disp_mode->pixclock) * 1000U;
+ dev_dbg(&pdev->dev, "%s: pix clock rate = %u\n", __func__, pix_clk_rate);
+
+ ret = clk_set_rate(info->clk_pix, pix_clk_rate);
+ if (ret) {
+ dev_err(&pdev->dev, "set pixel clock rate failed, ret = %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dcss_dec400d_config(struct dcss_info *info,
+ bool decompress, bool resolve)
+{
+ struct dcss_channel_info *chan_info;
+ struct cbuffer *cb;
+
+ if (resolve == true)
+ return -EINVAL;
+
+ /* dec400d always in channel 1 */
+ chan_info = &info->chans.chan_info[0];
+ cb = &chan_info->cb;
+
+ if (decompress == true) {
+ /* TODO: configure decompress */
+ ;
+ } else {
+ /* TODO: configure bypass */
+ ;
+ }
+
+ return 0;
+}
+
+static int dcss_dtrc_config(uint32_t dtrc_ch,
+ struct dcss_info *info,
+ bool decompress,
+ bool resolve)
+{
+ struct platform_device *pdev = info->pdev;
+ struct dcss_channel_info *chan_info;
+ struct cbuffer *cb;
+
+ if (dtrc_ch != 1 && dtrc_ch != 2) {
+ dev_err(&pdev->dev, "invalid dtrc channel number\n");
+ return -EINVAL;
+ }
+
+ chan_info = &info->chans.chan_info[dtrc_ch];
+ cb = &chan_info->cb;
+
+ if (!decompress && !resolve) {
+#if USE_CTXLD
+ /* Bypass DTRC */
+ fill_sb(cb, chan_info->decomp_addr + 0xc8, 0x2);
+#else
+ writel(0x2, info->base + chan_info->decomp_addr + 0xc8);
+#endif
+ } else {
+ /* TODO: decompress & resolve config */
+ ;
+ }
+
+ return 0;
+}
+
+static int dcss_decomp_config(uint32_t decomp_ch, struct dcss_info *info)
+{
+ bool need_decomp, need_resolve;
+ struct platform_device *pdev = info->pdev;
+ struct dcss_channel_info *chan_info;
+ struct dcss_pixmap *input;
+
+ if (decomp_ch > 2) {
+ dev_err(&pdev->dev, "invalid decompression channel number\n");
+ return -EINVAL;
+ }
+
+ chan_info = &info->chans.chan_info[decomp_ch];
+ input = &chan_info->input;
+
+ switch (input->pixel_store) {
+ case PIXEL_STORE_NONCOMPRESS:
+ need_decomp = false;
+ break;
+ case PIXEL_STORE_COMPRESS:
+ need_decomp = true;
+ break;
+ default:
+ dev_err(&pdev->dev, "invalid pixel store type\n");
+ return -EINVAL;
+ }
+
+ switch (input->tile_type) {
+ case TILE_TYPE_LINEAR:
+ case TILE_TYPE_GPU_STANDARD:
+ case TILE_TYPE_GPU_SUPER:
+ need_resolve = false;
+ break;
+ case TILE_TYPE_VPU_2PYUV420:
+ case TILE_TYPE_VPU_2PVP9:
+ need_resolve = true;
+ break;
+ default:
+ dev_err(&pdev->dev, "invalid buffer tile type\n");
+ return -EINVAL;
+ }
+
+ switch (decomp_ch) {
+ case 0: /* DEC400D */
+ dcss_dec400d_config(info, need_decomp, need_resolve);
+ break;
+ case 1: /* DTRC1 */
+ case 2: /* DTRC2 */
+ dcss_dtrc_config(decomp_ch, info,
+ need_decomp, need_resolve);
+ break;
+ default:
+ dev_err(&pdev->dev, "invalid ch num = %d\n", decomp_ch);
+ break;
+ }
+
+ return 0;
+}
+
+/* for both luma and chroma
+ */
+static int dpr_pix_x_calc(u32 pix_size,
+ u32 width,
+ u32 tile_type)
+{
+ unsigned int num_pix_x_in_64byte;
+ unsigned int pix_x_div_64byte_mod;
+ unsigned int pix_x_offset;
+
+ if (pix_size > 2)
+ return -EINVAL;
+
+ /* 1st calculation step */
+ switch (tile_type) {
+ case TILE_TYPE_LINEAR:
+ /* Divisable by 64 bytes */
+ num_pix_x_in_64byte = 64 / (1 << pix_size);
+ break;
+ /* 4x4 tile or super tile */
+ case TILE_TYPE_GPU_STANDARD:
+ case TILE_TYPE_GPU_SUPER:
+ BUG_ON(!pix_size);
+ num_pix_x_in_64byte = 64 / (4 * (1 << pix_size));
+ break;
+ /* 8bpp YUV420 8x8 tile */
+ case TILE_TYPE_VPU_2PYUV420:
+ BUG_ON(pix_size);
+ num_pix_x_in_64byte = 64 / (8 * (1 << pix_size));
+ break;
+ /* 8bpp or 10bpp VP9 4x4 tile */
+ case TILE_TYPE_VPU_2PVP9:
+ BUG_ON(pix_size == 2);
+ num_pix_x_in_64byte = 64 / (4 * (1 << pix_size));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* 2nd calculation step */
+ pix_x_div_64byte_mod = width % num_pix_x_in_64byte;
+ pix_x_offset = !pix_x_div_64byte_mod ? 0 :
+ (num_pix_x_in_64byte - pix_x_div_64byte_mod);
+
+ return width + pix_x_offset;
+}
+
+/* Divisable by 4 or 8 */
+static int dpr_pix_y_calc(u32 rtr_lines,
+ u32 height,
+ u32 tile_type)
+{
+ unsigned int num_rows_buf;
+ unsigned int pix_y_mod = 0;
+ unsigned int pix_y_offset = 0;
+
+ if (rtr_lines != 0 && rtr_lines != 1)
+ return -EINVAL;
+
+ switch (tile_type) {
+ case TILE_TYPE_LINEAR:
+ num_rows_buf = rtr_lines ? 4 : 8;
+ break;
+ /* 4x4 tile or super tile */
+ case TILE_TYPE_GPU_STANDARD:
+ case TILE_TYPE_GPU_SUPER:
+ num_rows_buf = 4;
+ break;
+ /* 8bpp YUV420 8x8 tile */
+ case TILE_TYPE_VPU_2PYUV420:
+ num_rows_buf = 8;
+ break;
+ /* 8bpp or 10bpp VP9 4x4 tile */
+ case TILE_TYPE_VPU_2PVP9:
+ num_rows_buf = 4;
+ break;
+ default:
+ return -EINVAL;
+ }
+ pix_y_mod = height % num_rows_buf;
+ pix_y_offset = !pix_y_mod ? 0 : (num_rows_buf - pix_y_mod);
+
+ return height + pix_y_offset;
+}
+
+static int dcss_dpr_config(uint32_t dpr_ch, struct dcss_info *info)
+{
+ uint32_t pitch, pix_size;
+ uint32_t num_pix_x, num_pix_y;
+ bool need_resolve = false;
+ struct platform_device *pdev = info->pdev;
+ struct dcss_channels *chans = &info->chans;
+ struct dcss_channel_info *chan_info;
+ struct fb_info *fbi;
+ struct fb_fix_screeninfo *fix;
+ struct fb_var_screeninfo *var;
+ struct dcss_pixmap *input;
+ struct cbuffer *cb;
+
+ if (dpr_ch > 2) {
+ dev_err(&pdev->dev, "invalid dpr channel number\n");
+ return -EINVAL;
+ }
+
+ chan_info = &chans->chan_info[dpr_ch];
+ fbi = chan_info->fb_info;
+ fix = &fbi->fix;
+ var = &fbi->var;
+ input = &chan_info->input;
+
+ if (dpr_ch == 0) {
+ switch (input->tile_type) {
+ case TILE_TYPE_LINEAR:
+ need_resolve = false;
+ break;
+ case TILE_TYPE_GPU_STANDARD:
+ case TILE_TYPE_GPU_SUPER:
+ need_resolve = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ /* For channel 2,3, 'Tile Resolve' will be done by DTRC */
+
+#if !USE_CTXLD
+ writel(fix->smem_start, info->base + chan_info->dpr_addr + 0xc0);
+ writel(0x2, info->base + chan_info->dpr_addr + 0x90);
+ writel(var->xres, info->base + chan_info->dpr_addr + 0xa0);
+ writel(var->yres, info->base + chan_info->dpr_addr + 0xb0);
+
+ /* TODO: second plane config for YUV2P formats */
+ writel(fix->smem_start + var->xres * var->yres,
+ info->base + chan_info->dpr_addr + 0x110);
+ writel(var->xres, info->base + chan_info->dpr_addr + 0xf0);
+ writel(var->yres, info->base + chan_info->dpr_addr + 0x100);
+
+ /* TODO: calculate pitch for different formats */
+ pitch = (var->xres * (var->bits_per_pixel >> 3)) << 16;
+ writel(pitch, info->base + chan_info->dpr_addr + 0x70);
+
+ if (!need_resolve) {
+ /* Bypass resolve */
+ writel(0xe4203, info->base + chan_info->dpr_addr + 0x50);
+ } else {
+ /* configure resolve */
+ ;
+ }
+
+ writel(0x38, info->base + chan_info->dpr_addr + 0x200);
+ writel(0x4, info->base + chan_info->dpr_addr + 0x0);
+
+ /* Trigger DPR on */
+ writel(0x4, info->base + chan_info->dpr_addr + 0x0);
+ writel(0x5, info->base + chan_info->dpr_addr + 0x0);
+#else
+ cb = &chan_info->cb;
+
+ fill_sb(cb, chan_info->dpr_addr + 0xc0, fix->smem_start);
+ fill_sb(cb, chan_info->dpr_addr + 0x90, 0x2);
+
+ pix_size = ilog2(input->bits_per_pixel >> 3);
+
+ num_pix_x = dpr_pix_x_calc(pix_size, input->width, input->tile_type);
+ BUG_ON(num_pix_x < 0);
+ fill_sb(cb, chan_info->dpr_addr + 0xa0, num_pix_x);
+
+ switch (fmt_is_yuv(input->format)) {
+ case 0: /* RGB */
+ num_pix_y = dpr_pix_y_calc(1, input->height, input->tile_type);
+ BUG_ON(num_pix_y < 0);
+ fill_sb(cb, chan_info->dpr_addr + 0xb0, num_pix_y);
+
+ if (!need_resolve)
+ /* Bypass resolve */
+ fill_sb(cb, chan_info->dpr_addr + 0x50, 0xe4203);
+ else {
+ /* TODO: configure resolve */
+ ;
+ }
+ pitch = var->xres * (var->bits_per_pixel >> 3);
+ break;
+ case 1: /* TODO: YUV 1P */
+ return -EINVAL;
+ case 2: /* YUV 2P */
+ /* Two planes YUV format */
+ num_pix_y = dpr_pix_y_calc(0, input->height, input->tile_type);
+ BUG_ON(num_pix_y < 0);
+ fill_sb(cb, chan_info->dpr_addr + 0xb0, num_pix_y);
+
+ fill_sb(cb, chan_info->dpr_addr + 0x50, 0xc1);
+ fill_sb(cb, chan_info->dpr_addr + 0xe0, 0x2);
+
+ /* TODO: VPU always has 16bytes alignment in width */
+ pitch = ALIGN(var->xres * (var->bits_per_pixel >> 3), 16);
+ fill_sb(cb, chan_info->dpr_addr + 0x110,
+ fix->smem_start + pitch * var->yres);
+ fill_sb(cb, chan_info->dpr_addr + 0xf0, num_pix_x);
+
+ /* TODO: Require alignment handling:
+ * value must be evenly divisible by
+ * the number of rows programmed in
+ * MODE_CTRL0: RTR_4LINE_BUF_EN.
+ * UV height is 1/2 height of Luma.
+ */
+ num_pix_y = dpr_pix_y_calc(0, input->height >> 1, input->tile_type);
+ BUG_ON(num_pix_y < 0);
+ fill_sb(cb, chan_info->dpr_addr + 0x100, num_pix_y);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* TODO: calculate pitch for different formats */
+ /* config pitch */
+ fill_sb(cb, chan_info->dpr_addr + 0x70, pitch << 16);
+
+ fill_sb(cb, chan_info->dpr_addr + 0x200, 0x38);
+
+ /* Trigger DPR on */
+ fill_sb(cb, chan_info->dpr_addr + 0x0, 0x5);
+#endif
+
+ return 0;
+}
+
+static int dcss_scaler_config(uint32_t scaler_ch, struct dcss_info *info)
+{
+ struct platform_device *pdev = info->pdev;
+ struct dcss_channels *chans = &info->chans;
+ struct dcss_channel_info *chan_info;
+ struct fb_info *fbi;
+ struct fb_var_screeninfo *var;
+ struct dcss_pixmap *input;
+ struct cbuffer *cb;
+ int scale_v_luma_inc, scale_h_luma_inc;
+ uint32_t align_width, align_height;
+ const struct fb_videomode *dmode = info->dft_disp_mode;
+
+ if (scaler_ch > 2) {
+ dev_err(&pdev->dev, "invalid scaler channel number\n");
+ return -EINVAL;
+ }
+
+ chan_info = &chans->chan_info[scaler_ch];
+ fbi = chan_info->fb_info;
+ var = &fbi->var;
+ input = &chan_info->input;
+#if !USE_CTXLD
+ writel(0x0, info->base + chan_info->scaler_addr + 0x8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xc);
+ writel(0x2, info->base + chan_info->scaler_addr + 0x10); /* src format */
+ writel(0x2, info->base + chan_info->scaler_addr + 0x14); /* dst format */
+
+ writel((var->xres - 1) | (var->yres - 1) << 16,
+ info->base + chan_info->scaler_addr + 0x18); /* src resolution */
+ writel((var->xres - 1) | (var->yres - 1) << 16,
+ info->base + chan_info->scaler_addr + 0x1c);
+ writel((var->xres - 1) | (var->yres - 1) << 16,
+ info->base + chan_info->scaler_addr + 0x20); /* dst resolution */
+ writel((var->xres - 1) | (var->yres - 1) << 16,
+ info->base + chan_info->scaler_addr + 0x24);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x28);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x2c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x30);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x34);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x38);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x3c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x40);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x44);
+
+ /* scale ratio: ###.#_####_####_#### */
+ writel(0x0, info->base + chan_info->scaler_addr + 0x48);
+ writel(0x2000, info->base + chan_info->scaler_addr + 0x4c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x50);
+ writel(0x2000, info->base + chan_info->scaler_addr + 0x54);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x58);
+ writel(0x2000, info->base + chan_info->scaler_addr + 0x5c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x60);
+ writel(0x2000, info->base + chan_info->scaler_addr + 0x64);
+
+ writel(0x0, info->base + chan_info->scaler_addr + 0x80);
+
+ writel(0x40000, info->base + chan_info->scaler_addr + 0xc0);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x100);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x84);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xc4);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x104);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x88);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xc8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x108);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x8c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xcc);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x10c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x90);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xd0);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x110);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x94);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xd4);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x114);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x98);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xd8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x118);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x9c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xdc);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x11c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xa0);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xe0);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x120);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xa4);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xe4);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x124);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xa8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xe8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x128);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xac);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xec);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x12c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xb0);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xf0);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x130);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xb4);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xf4);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x134);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xb8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xf8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x138);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xbc);
+ writel(0x0, info->base + chan_info->scaler_addr + 0xfc);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x13c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x140);
+
+ writel(0x40000, info->base + chan_info->scaler_addr + 0x180);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1c0);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x144);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x184);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1c4);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x148);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x188);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1c8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x14c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x18c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1cc);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x150);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x190);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1d0);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x154);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x194);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1d4);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x158);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x198);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1d8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x15c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x19c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1dc);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x160);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1a0);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1e0);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x164);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1a4);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1e4);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x168);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1a8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1e8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x16c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1ac);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1ec);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x170);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1b0);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1f0);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x174);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1b4);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1f4);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x178);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1b8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1f8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x17c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1bc);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x1fc);
+
+ writel(0x0, info->base + chan_info->scaler_addr + 0x300);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x340);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x380);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x304);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x344);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x384);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x308);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x348);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x388);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x30c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x34c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x38c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x310);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x350);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x390);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x314);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x354);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x394);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x318);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x358);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x398);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x31c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x35c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x39c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x320);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x360);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x3a0);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x324);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x364);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x3a4);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x328);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x368);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x3a8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x32c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x36c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x3ac);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x330);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x370);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x3b0);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x334);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x374);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x3b4);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x338);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x378);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x3b8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x33c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x37c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x3bc);
+
+ writel(0x0, info->base + chan_info->scaler_addr + 0x200);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x240);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x280);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x204);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x244);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x284);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x208);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x248);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x288);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x20c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x24c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x28c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x210);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x250);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x290);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x214);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x254);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x294);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x218);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x258);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x298);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x21c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x25c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x29c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x220);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x260);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x2a0);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x224);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x264);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x2a4);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x228);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x268);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x2a8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x22c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x26c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x2ac);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x230);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x270);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x2b0);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x234);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x274);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x2b4);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x238);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x278);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x2b8);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x23c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x27c);
+ writel(0x0, info->base + chan_info->scaler_addr + 0x2bc);
+
+ /* Trigger Scaler on */
+ writel(0x11, info->base + chan_info->scaler_addr + 0x0);
+#else
+ cb = &chan_info->cb;
+
+ switch (fmt_is_yuv(input->format)) {
+ case 0: /* ARGB8888 */
+ fill_sb(cb, chan_info->scaler_addr + 0x8, 0x0);
+ /* Scaler Input Format */
+ fill_sb(cb, chan_info->scaler_addr + 0x10, 0x2);
+ break;
+ case 1: /* TODO: YUV422 or YUV444 */
+ break;
+ case 2: /* YUV420 */
+ fill_sb(cb, chan_info->scaler_addr + 0x8, 0x3);
+ /* Scaler Input Format */
+ fill_sb(cb, chan_info->scaler_addr + 0x10, 0x0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Chroma and Luma bit depth */
+ fill_sb(cb, chan_info->scaler_addr + 0xc, 0x0);
+
+ /* Scaler Output Format
+ * TODO: set dst fmt always to RGB888/YUV444
+ */
+ fill_sb(cb, chan_info->scaler_addr + 0x14, 0x2);
+
+ /* Scaler Input Luma Resolution
+ * Alighment Workaround for YUV420:
+ * 'width' divisable by 16, 'height' divisable by 8.
+ */
+
+ if (fmt_is_yuv(input->format) == 2) {
+ align_width = round_down(input->width, 16);
+ align_height = round_down(input->height, 8);
+ } else {
+ align_width = input->width;
+ align_height = input->height;
+ }
+
+ fill_sb(cb, chan_info->scaler_addr + 0x18,
+ (align_height - 1) << 16 | (align_width - 1));
+
+ /* Scaler Input Chroma Resolution */
+ switch (fmt_is_yuv(input->format)) {
+ case 0: /* ARGB8888 */
+ fill_sb(cb, chan_info->scaler_addr + 0x1c,
+ (align_height - 1) << 16 | (align_width - 1));
+ break;
+ case 1: /* TODO: YUV422 or YUV444 */
+ break;
+ case 2: /* YUV420 */
+ fill_sb(cb, chan_info->scaler_addr + 0x1c,
+ ((align_height >> 1) - 1) << 16 |
+ ((align_width >> 1) - 1));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Scaler Output Luma Resolution
+ * TODO: It should be scaled result value.
+ */
+ fill_sb(cb, chan_info->scaler_addr + 0x20,
+ (dmode->yres - 1) << 16 | (dmode->xres - 1));
+
+ /* Scaler Output Chroma Resolution
+ * TODO: It should be scaled result value.
+ */
+ fill_sb(cb, chan_info->scaler_addr + 0x24,
+ (dmode->yres - 1) << 16 | (dmode->xres - 1));
+
+ fill_sb(cb, chan_info->scaler_addr + 0x28, 0x0);
+ fill_sb(cb, chan_info->scaler_addr + 0x2c, 0x0);
+ fill_sb(cb, chan_info->scaler_addr + 0x30, 0x0);
+ fill_sb(cb, chan_info->scaler_addr + 0x34, 0x0);
+ fill_sb(cb, chan_info->scaler_addr + 0x38, 0x0);
+ fill_sb(cb, chan_info->scaler_addr + 0x3c, 0x0);
+ fill_sb(cb, chan_info->scaler_addr + 0x40, 0x0);
+ fill_sb(cb, chan_info->scaler_addr + 0x44, 0x0);
+
+ /* scale ratio: ###.#_####_####_#### */
+ /* vertical ratio */
+ scale_v_luma_inc = ((align_height << 13) + (dmode->yres >> 1)) / dmode->yres;
+ /* horizontal ratio */
+ scale_h_luma_inc = ((align_width << 13) + (dmode->xres >> 1)) / dmode->xres;
+
+ fill_sb(cb, chan_info->scaler_addr + 0x48, 0x0);
+ fill_sb(cb, chan_info->scaler_addr + 0x4c, scale_v_luma_inc);
+ fill_sb(cb, chan_info->scaler_addr + 0x50, 0x0);
+ fill_sb(cb, chan_info->scaler_addr + 0x54, scale_h_luma_inc);
+
+ switch (fmt_is_yuv(input->format)) {
+ case 0: /* ARGB8888 */
+ /* Scale Vertical Chroma Start */
+ fill_sb(cb, chan_info->scaler_addr + 0x58, 0x0);
+
+ /* Scale Vertical Chroma Increment */
+ fill_sb(cb, chan_info->scaler_addr + 0x5c, scale_v_luma_inc);
+
+ /* Scale Horizontal Chroma Increment */
+ fill_sb(cb, chan_info->scaler_addr + 0x64, scale_h_luma_inc);
+ break;
+ case 1: /* TODO: YUV422 or YUV444 */
+ break;
+ case 2: /* YUV420 */
+ /* Scale Vertical Chroma Start */
+ fill_sb(cb, chan_info->scaler_addr + 0x58, 0x01fff800);
+
+ /* Scale Vertical Chroma Increment */
+ fill_sb(cb, chan_info->scaler_addr + 0x5c, scale_v_luma_inc >> 1);
+
+ /* Scale Horizontal Chroma Increment */
+ fill_sb(cb, chan_info->scaler_addr + 0x64, scale_h_luma_inc >> 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Scale Horizontal Chroma Start */
+ fill_sb(cb, chan_info->scaler_addr + 0x60, 0x0);
+
+ /* Trigger SCALER on */
+ fill_sb(cb, chan_info->scaler_addr + 0x0, 0x11);
+#endif
+ return 0;
+}
+
+static int dcss_dtg_start(struct dcss_info *info)
+{
+ uint32_t dtg_lrc_x, dtg_lrc_y;
+ uint32_t dis_ulc_x, dis_ulc_y;
+ uint32_t dis_lrc_x, dis_lrc_y;
+ struct dcss_channels *chans = &info->chans;
+ struct dcss_channel_info *chan_info;
+ const struct fb_videomode *dmode;
+ struct cbuffer *cb;
+
+ chan_info = &chans->chan_info[0];
+ dmode = info->dft_disp_mode;
+ cb = &chan_info->cb;
+
+ /* Display Timing Config */
+ dtg_lrc_x = dmode->xres + dmode->left_margin +
+ dmode->right_margin + dmode->hsync_len - 1;
+ dtg_lrc_y = dmode->yres + dmode->upper_margin +
+ dmode->lower_margin + dmode->vsync_len - 1;
+ writel(dtg_lrc_y << 16 | dtg_lrc_x, info->base + chans->dtg_addr + 0x4);
+
+ /* global output timing */
+ dis_ulc_x = dmode->left_margin + dmode->hsync_len - 1;
+ dis_ulc_y = dmode->upper_margin + dmode->lower_margin +
+ dmode->vsync_len - 1;
+ writel(dis_ulc_y << 16 | dis_ulc_x, info->base + chans->dtg_addr + 0x8);
+
+ dis_lrc_x = dmode->xres + dmode->left_margin +
+ dmode->hsync_len - 1;
+ dis_lrc_y = dmode->yres + dmode->upper_margin +
+ dmode->lower_margin + dmode->vsync_len - 1;
+ writel(dis_lrc_y << 16 | dis_lrc_x, info->base + chans->dtg_addr + 0xc);
+
+ /* config db and sb loading position of ctxld */
+ writel(0xb000a, info->base + chans->dtg_addr + 0x28);
+
+ /* config background color for graph layer: black */
+ writel(0x0, info->base + chans->dtg_addr + 0x2c);
+
+ /* config background color for video layer: black */
+ writel(0x00080200, info->base + chans->dtg_addr + 0x30);
+
+ /* Trigger DTG on */
+ writel(0xff00518e, info->base + chans->dtg_addr + 0x0);
+
+ info->dcss_state = DCSS_STATE_RUNNING;
+
+ return 0;
+}
+
+static void dtg_channel_timing_config(int blank,
+ struct dcss_channel_info *cinfo)
+{
+ struct cbuffer *cb;
+ uint32_t ch_ulc_reg, ch_lrc_reg;
+ struct fb_info *fbi = cinfo->fb_info;
+ struct rectangle *pos = &cinfo->ch_pos;
+ struct platform_device *pdev = cinfo->pdev;
+ struct dcss_info *info = cinfo->dev_data;
+ struct dcss_channels *chans = &info->chans;
+
+ switch (fbi->node) {
+ case 0:
+ ch_ulc_reg = 0x10;
+ ch_lrc_reg = 0x14;
+ break;
+ case 1:
+ ch_ulc_reg = 0x18;
+ ch_lrc_reg = 0x1c;
+ break;
+ case 2:
+ ch_ulc_reg = 0x20;
+ ch_lrc_reg = 0x24;
+ break;
+ default:
+ dev_err(&pdev->dev, "%s: invalid channel number %d\n",
+ __func__, fbi->node);
+ return;
+ }
+
+ cb = &cinfo->cb;
+
+ switch (blank) {
+ case FB_BLANK_UNBLANK:
+ /* set display window for one channel */
+ fill_sb(cb, chans->dtg_addr + ch_ulc_reg,
+ pos->ulc_y << 16 | pos->ulc_x);
+ fill_sb(cb, chans->dtg_addr + ch_lrc_reg,
+ pos->lrc_y << 16 | pos->lrc_x);
+ break;
+ case FB_BLANK_NORMAL:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_POWERDOWN:
+ fill_sb(cb, chans->dtg_addr + ch_ulc_reg, 0x0);
+ fill_sb(cb, chans->dtg_addr + ch_lrc_reg, 0x0);
+ break;
+ default:
+ return;
+ }
+}
+
+static void dtg_global_timing_config(struct dcss_info *info)
+{
+ struct cbuffer *cb;
+ uint32_t dtg_lrc_x, dtg_lrc_y;
+ uint32_t dis_ulc_x, dis_ulc_y;
+ uint32_t dis_lrc_x, dis_lrc_y;
+ struct dcss_channels *chans = &info->chans;
+ struct dcss_channel_info *cmain;
+ const struct fb_videomode *dmode = info->dft_disp_mode;
+
+ /* only main channel can change dtg timings */
+ cmain = &chans->chan_info[DCSS_CHAN_MAIN];
+ cb = &cmain->cb;
+
+ /* Display Timing config */
+ dtg_lrc_x = dmode->xres + dmode->left_margin +
+ dmode->right_margin + dmode->hsync_len - 1;
+ dtg_lrc_y = dmode->yres + dmode->upper_margin +
+ dmode->lower_margin + dmode->vsync_len - 1;
+ fill_sb(cb, chans->dtg_addr + 0x4, dtg_lrc_y << 16 | dtg_lrc_x);
+
+ /* Active Region Timing config*/
+ dis_ulc_x = dmode->left_margin + dmode->hsync_len - 1;
+ dis_ulc_y = dmode->upper_margin + dmode->lower_margin +
+ dmode->vsync_len - 1;
+ fill_sb(cb, chans->dtg_addr + 0x8, dis_ulc_y << 16 | dis_ulc_x);
+
+ dis_lrc_x = dmode->xres + dmode->left_margin +
+ dmode->hsync_len - 1;
+ dis_lrc_y = dmode->yres + dmode->upper_margin +
+ dmode->lower_margin + dmode->vsync_len - 1;
+ fill_sb(cb, chans->dtg_addr + 0xc, dis_lrc_y << 16 | dis_lrc_x);
+}
+
+static int dcss_dtg_config(uint32_t ch_id, struct dcss_info *info)
+{
+ struct platform_device *pdev = info->pdev;
+ struct dcss_channels *chans = &info->chans;
+ struct dcss_channel_info *cinfo;
+
+ if (ch_id > 2) {
+ dev_err(&pdev->dev, "invalid channel id\n");
+ return -EINVAL;
+ }
+
+ cinfo = &chans->chan_info[ch_id];
+
+ if (ch_id == DCSS_CHAN_MAIN)
+ dtg_global_timing_config(info);
+
+ /* TODO: Channel Timing Config */
+ dtg_channel_timing_config(FB_BLANK_UNBLANK, cinfo);
+
+ return 0;
+}
+
+static int dcss_subsam_config(struct dcss_info *info)
+{
+ uint32_t hsync_pol, vsync_pol, de_pol;
+ uint32_t disp_lrc_x, disp_lrc_y;
+ uint32_t hsync_start, hsync_end;
+ uint32_t vsync_start, vsync_end;
+ uint32_t de_ulc_x, de_ulc_y;
+ uint32_t de_lrc_x, de_lrc_y;
+ struct dcss_channels *chans = &info->chans;
+ struct dcss_channel_info *chan_info;
+ struct cbuffer *cb;
+ const struct fb_videomode *dmode;
+
+ /* using channel 0 by default */
+ chan_info = &chans->chan_info[0];
+ cb = &chan_info->cb;
+ dmode = info->dft_disp_mode;
+
+ /* TODO: for 1080p only */
+ hsync_pol = 1;
+ vsync_pol = 1;
+ de_pol = 1;
+
+#if USE_CTXLD
+ /* 3 tap fir filters coefficients */
+ fill_sb(cb, chans->subsam_addr + 0x70, 0x41614161);
+ fill_sb(cb, chans->subsam_addr + 0x80, 0x03ff0000);
+ fill_sb(cb, chans->subsam_addr + 0x90, 0x03ff0000);
+#else
+ writel(0x41614161, info->base + chans->subsam_addr + 0x70);
+ writel(0x03ff0000, info->base + chans->subsam_addr + 0x80);
+ writel(0x03ff0000, info->base + chans->subsam_addr + 0x90);
+#endif
+
+ /* Timing Config */
+ disp_lrc_x = dmode->xres + dmode->left_margin +
+ dmode->right_margin + dmode->hsync_len - 1;
+ disp_lrc_y = dmode->yres + dmode->upper_margin +
+ dmode->lower_margin + dmode->vsync_len - 1;
+#if USE_CTXLD
+ fill_sb(cb, chans->subsam_addr + 0x10,
+ disp_lrc_y << 16 | disp_lrc_x);
+#else
+ writel(disp_lrc_y << 16 | disp_lrc_x,
+ info->base + chans->subsam_addr + 0x10);
+#endif
+
+ /* horizontal sync will be asserted when
+ * horizontal count == START
+ */
+ hsync_start = dmode->xres + dmode->left_margin +
+ dmode->right_margin + dmode->hsync_len - 1;
+ hsync_end = dmode->hsync_len - 1;
+#if USE_CTXLD
+ fill_sb(cb, chans->subsam_addr + 0x20,
+ (hsync_pol << 31) | hsync_end << 16 | hsync_start);
+#else
+ writel((hsync_pol << 31) | hsync_end << 16 | hsync_start,
+ info->base + chans->subsam_addr + 0x20);
+#endif
+
+ vsync_start = dmode->lower_margin - 1;
+ vsync_end = dmode->lower_margin + dmode->vsync_len - 1;
+#if USE_CTXLD
+ fill_sb(cb, chans->subsam_addr + 0x30,
+ (vsync_pol << 31) | vsync_end << 16 | vsync_start);
+#else
+ writel((vsync_pol << 31) | vsync_end << 16 | vsync_start,
+ info->base + chans->subsam_addr + 0x30);
+#endif
+
+ de_ulc_x = dmode->left_margin + dmode->hsync_len - 1;
+ de_ulc_y = dmode->upper_margin + dmode->lower_margin +
+ dmode->vsync_len;
+#if USE_CTXLD
+ fill_sb(cb, chans->subsam_addr + 0x40,
+ (de_pol << 31) | de_ulc_y << 16 | de_ulc_x);
+#else
+ writel((de_pol << 31) | de_ulc_y << 16 | de_ulc_x,
+ info->base + chans->subsam_addr + 0x40);
+#endif
+
+ de_lrc_x = dmode->xres + dmode->left_margin +
+ dmode->hsync_len - 1;
+ de_lrc_y = dmode->yres + dmode->upper_margin +
+ dmode->lower_margin + dmode->vsync_len - 1;
+#if USE_CTXLD
+ fill_sb(cb, chans->subsam_addr + 0x50,
+ de_lrc_y << 16 | de_lrc_x);
+
+ /* Trigger Subsam on */
+ fill_sb(cb, chans->subsam_addr + 0x0, 0x1);
+#else
+ writel(de_lrc_y << 16 | de_lrc_x,
+ info->base + chans->subsam_addr + 0x50);
+ writel(0x1, info->base + chans->subsam_addr + 0x0);
+#endif
+
+ return 0;
+}
+
+static void ctxld_irq_unmask(uint32_t irq_en, struct dcss_info *info)
+{
+ struct dcss_channels *chans = &info->chans;
+
+ writel(irq_en, info->base + chans->ctxld_addr + CTXLD_CTRL_STATUS_SET);
+}
+
+static void __maybe_unused dtg_irq_mask(unsigned long hwirq,
+ struct dcss_info *info)
+{
+ unsigned long irq_mask = 0;
+ struct dcss_channels *chans = &info->chans;
+
+ irq_mask = readl(info->base + chans->dtg_addr + TC_INTERRUPT_MASK);
+ writel(~(1 << (hwirq - 8)) & irq_mask,
+ info->base + chans->dtg_addr + TC_INTERRUPT_MASK);
+}
+
+static void dtg_irq_unmask(unsigned long hwirq,
+ struct dcss_info *info)
+{
+ unsigned long irq_mask = 0;
+ struct dcss_channels *chans = &info->chans;
+
+ irq_mask = readl(info->base + chans->dtg_addr + TC_INTERRUPT_MASK);
+
+ writel(1 << (hwirq - 8) | irq_mask,
+ info->base + chans->dtg_addr + TC_INTERRUPT_MASK);
+}
+
+static void dtg_irq_clear(unsigned long hwirq,
+ struct dcss_info *info)
+{
+ unsigned long irq_status = 0;
+ struct dcss_channels *chans = &info->chans;
+
+ irq_status = readl(info->base + chans->dtg_addr + TC_INTERRUPT_STATUS);
+ BUG_ON(!(irq_status & 1 << (hwirq - 8)));
+
+ /* write 1 to clear irq */
+ writel(1 << (hwirq - 8),
+ info->base + chans->dtg_addr + TC_INTERRUPT_CONTROL);
+}
+
+static void dcss_ctxld_config(struct work_struct *work)
+{
+ int ret;
+ uint32_t dsb_len, nsgl, esize, offset;
+ struct dcss_info *info;
+ struct platform_device *pdev;
+ struct dcss_channels *chans;
+ struct ctxld_commit *cc;
+ struct ctxld_fifo *cfifo;
+
+ cc = container_of(work, struct ctxld_commit, work);
+ info = (struct dcss_info *)cc->data;
+ pdev = info->pdev;
+ chans = &info->chans;
+ cfifo = &info->cfifo;
+ dsb_len = cc->sb_data_len + cc->db_data_len;
+ esize = kfifo_esize(&cfifo->fifo);
+
+ /* NOOP cc */
+ if (!cc->sb_data_len && !cc->db_data_len)
+ goto free_cc;
+
+ sg_init_table(cfifo->sgl, cfifo->sgl_num);
+ nsgl = kfifo_dma_out_prepare(&cfifo->fifo, cfifo->sgl,
+ cfifo->sgl_num, dsb_len);
+ BUG_ON(!nsgl);
+
+ if (nsgl == 1) {
+ if (cfifo->sgl[0].length != dsb_len * esize)
+ BUG_ON(1);
+ }
+
+ offset = cfifo->fifo.kfifo.out & cfifo->fifo.kfifo.mask;
+
+ /* configure sb buffer */
+ if (cc->sb_data_len) {
+ /* cfifo first store sb and than store db */
+ writel(cfifo->dma_handle + offset * esize,
+ info->base + chans->ctxld_addr + CTXLD_SB_BASE_ADDR);
+ writel(cc->sb_hp_data_len |
+ ((cc->sb_data_len - cc->sb_hp_data_len) << 16),
+ info->base + chans->ctxld_addr + CTXLD_SB_COUNT);
+ }
+
+ /* configure db buffer */
+ if (cc->db_data_len) {
+ writel(cfifo->dma_handle + (offset + cc->sb_data_len) * esize,
+ info->base + chans->ctxld_addr + CTXLD_DB_BASE_ADDR);
+ writel(cc->db_data_len,
+ info->base + chans->ctxld_addr + CTXLD_DB_COUNT);
+ }
+
+ /* enable ctx_ld */
+ writel(0x1, info->base + chans->ctxld_addr + CTXLD_CTRL_STATUS_SET);
+
+ /* wait finish */
+ reinit_completion(&cfifo->complete);
+ ret = wait_for_completion_timeout(&cfifo->complete, HZ);
+ if (!ret) /* timeout */
+ dev_err(&pdev->dev, "wait ctxld finish timeout\n");
+
+ ctxld_fifo_info_print(cfifo);
+ kfifo_dma_out_finish(&cfifo->fifo,
+ (cc->sb_data_len + cc->db_data_len) * esize);
+ ctxld_fifo_info_print(cfifo);
+
+free_cc:
+ kfree(cc);
+
+ dev_dbg(&pdev->dev, "finish ctxld config\n");
+}
+
+static void copy_data_to_cfifo(struct ctxld_fifo *cfifo,
+ struct cbuffer *cb,
+ struct ctxld_commit *cc)
+{
+ struct ctxld_unit *unit;
+ uint32_t count;
+
+ unit = (struct ctxld_unit *)cb->sb_addr;
+
+ if (cb->sb_data_len) {
+ count = kfifo_in(&cfifo->fifo, cb->sb_addr, cb->sb_data_len);
+ if (count != cb->sb_data_len) {
+ /* TODO: this case should be completely ignored */
+ pr_err("write sb data mismatch\n");
+ count = kfifo_out(&cfifo->fifo, cb->sb_addr, count);
+ WARN_ON(1);
+ }
+ cc->sb_hp_data_len += count;
+ cc->sb_data_len += count;
+ }
+
+ if (cb->db_data_len) {
+ count = kfifo_in(&cfifo->fifo, cb->db_addr, cb->db_data_len);
+ if (count != cb->db_data_len) {
+ /* TODO: this case should be completely ignored */
+ pr_err("write db data mismatch\n");
+ count = kfifo_out(&cfifo->fifo, cb->db_addr, count);
+ WARN_ON(1);
+ }
+ cc->db_data_len += count;
+ }
+}
+
+static struct ctxld_commit *alloc_cc(struct dcss_info *info)
+{
+ struct ctxld_commit *cc;
+
+ cc = kzalloc(sizeof(*cc), GFP_KERNEL);
+ if (!cc)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&cc->list);
+ INIT_WORK(&cc->work, dcss_ctxld_config);
+ kref_init(&cc->refcount);
+ cc->data = info;
+
+ return cc;
+}
+
+static struct ctxld_commit *obtain_cc(int ch_id, struct dcss_info *info)
+{
+ int ret;
+ unsigned long irqflags;
+ struct dcss_channel_info *cinfo;
+ struct ctxld_commit *cc = NULL;
+ struct platform_device *pdev = info->pdev;
+ struct dcss_channels *chans = &info->chans;
+ struct ctxld_fifo *cfifo = &info->cfifo;
+ struct vsync_info *vinfo = &info->vinfo;
+
+ cinfo = &chans->chan_info[ch_id];
+
+ /* wait for next frame window */
+ ret = wait_event_interruptible_timeout(vinfo->vwait,
+ vcount_compare(cinfo->update_stamp, vinfo),
+ HZ);
+ if (!ret) {
+ dev_err(&pdev->dev, "wait next frame timeout\n");
+ return ERR_PTR(-EBUSY);
+ }
+
+ spin_lock_irqsave(&vinfo->vwait.lock, irqflags);
+
+ cinfo->update_stamp = vinfo->vcount;
+ if (!list_empty(&cfifo->ctxld_list)) {
+ cc = list_first_entry(&cfifo->ctxld_list,
+ struct ctxld_commit,
+ list);
+ kref_get(&cc->refcount);
+ }
+
+ spin_unlock_irqrestore(&vinfo->vwait.lock, irqflags);
+
+ if (!cc) {
+ cc = alloc_cc(info);
+ if (IS_ERR(cc))
+ return cc;
+
+ spin_lock_irqsave(&vinfo->vwait.lock, irqflags);
+
+ if (list_empty(&cfifo->ctxld_list))
+ list_add_tail(&cfifo->ctxld_list, &cc->list);
+ else {
+ kfree(cc);
+ cc = list_first_entry(&cfifo->ctxld_list,
+ struct ctxld_commit,
+ list);
+ }
+ kref_get(&cc->refcount);
+
+ spin_unlock_irqrestore(&vinfo->vwait.lock, irqflags);
+ }
+
+ return cc;
+}
+
+static void release_cc(struct kref *kref)
+{
+ unsigned long irqflags;
+ struct ctxld_commit *cc;
+ struct dcss_info *info;
+ struct vsync_info *vinfo;
+ struct ctxld_fifo *cfifo;
+
+ cc = container_of(kref, struct ctxld_commit, refcount);
+ info = (struct dcss_info *)cc->data;
+ vinfo = &info->vinfo;
+ cfifo = &info->cfifo;
+
+ spin_lock_irqsave(&vinfo->vwait.lock, irqflags);
+
+ list_del(&cc->list);
+ flush_cfifo(cfifo, &cc->work);
+
+ spin_unlock_irqrestore(&vinfo->vwait.lock, irqflags);
+}
+
+/**
+ * Only be called when 'vwait.lock' is hold
+ */
+static void release_cc_locked(struct kref *kref)
+{
+ struct ctxld_commit *cc;
+ struct dcss_info *info;
+ struct ctxld_fifo *cfifo;
+
+ cc = container_of(kref, struct ctxld_commit, refcount);
+ info = (struct dcss_info *)cc->data;
+ cfifo = &info->cfifo;
+
+ list_del(&cc->list);
+ flush_cfifo(cfifo, &cc->work);
+}
+
+static void flush_cfifo(struct ctxld_fifo *cfifo,
+ struct work_struct *work)
+{
+ int ret;
+
+ ret = queue_work(cfifo->ctxld_wq, work);
+
+ WARN(!ret, "work has already been queued\n");
+}
+
+static int defer_flush_cfifo(struct ctxld_fifo *cfifo)
+{
+ int i;
+ struct dcss_info *info;
+ struct dcss_channels *chans;
+ struct dcss_channel_info *cinfo;
+
+ info = container_of(cfifo, struct dcss_info, cfifo);
+ chans = &info->chans;
+
+ for (i = 0; i < 3; i++) {
+ cinfo = &chans->chan_info[i];
+ cinfo->update_stamp = info->vinfo.vcount;
+ }
+
+ return 0;
+}
+
+static int finish_cfifo(struct ctxld_fifo *cfifo)
+{
+ int ret;
+ struct dcss_info *info;
+
+ info = container_of(cfifo, struct dcss_info, cfifo);
+
+ ret = dcss_wait_for_vsync(0, info);
+ if (ret)
+ return ret;
+
+ flush_workqueue(cfifo->ctxld_wq);
+
+ return 0;
+}
+
+static int commit_cfifo(uint32_t channel,
+ struct dcss_info *info,
+ struct ctxld_commit *cc)
+{
+ uint32_t commit_size;
+ struct dcss_channels *chans;
+ struct dcss_channel_info *chan_info;
+ struct ctxld_fifo *cfifo;
+ struct cbuffer *cb;
+
+ cfifo = &info->cfifo;
+ chans = &info->chans;
+ chan_info = &chans->chan_info[channel];
+ cb = &chan_info->cb;
+ commit_size = cb->sb_data_len + cb->db_data_len;
+
+ spin_lock(&cfifo->cqueue.lock);
+
+ if (unlikely(atomic_read(&info->flush) == 1)) {
+ /* cancel this commit and restart it later */
+ kref_put(&cc->refcount, release_cc);
+
+ wait_event_interruptible_exclusive_locked(cfifo->cqueue,
+ atomic_read(&info->flush));
+
+ spin_unlock(&cfifo->cqueue.lock);
+ return -ERESTARTSYS;
+ } else {
+ if (unlikely(waitqueue_active(&cfifo->cqueue)))
+ wake_up_locked(&cfifo->cqueue);
+ }
+
+ if (unlikely(commit_size > kfifo_to_end_len(&cfifo->fifo))) {
+ atomic_set(&info->flush, 1);
+ spin_unlock(&cfifo->cqueue.lock);
+
+ /* cancel this commit and restart it later */
+ kref_put(&cc->refcount, release_cc);
+
+ /* Wait fifo flush empty to avoid fifo wrap */
+ finish_cfifo(cfifo);
+
+ spin_lock(&cfifo->cqueue.lock);
+
+ atomic_set(&info->flush, 0);
+ kfifo_reset(&cfifo->fifo);
+ if (waitqueue_active(&cfifo->cqueue))
+ wake_up_locked(&cfifo->cqueue);
+
+ spin_unlock(&cfifo->cqueue.lock);
+
+ return -ERESTART;
+ }
+
+ copy_data_to_cfifo(cfifo, cb, cc);
+
+ ctxld_fifo_info_print(cfifo);
+
+ /* empty sb and db buffer */
+ cb->db_data_len = 0;
+ cb->sb_data_len = 0;
+
+ spin_unlock(&cfifo->cqueue.lock);
+
+ return 0;
+}
+
+static int dcss_open(struct fb_info *fbi, int user)
+{
+ int fb_node = fbi->node;
+ struct dcss_channel_info *cinfo = fbi->par;
+ struct dcss_info *info = cinfo->dev_data;
+ struct dcss_channels *chans = &info->chans;
+ struct dcss_channel_info *chan_info;
+ struct cbuffer *cb;
+
+ if (fb_node < 0 || fb_node > 2)
+ BUG_ON(1);
+
+ chan_info = &chans->chan_info[fb_node];
+ cb = &chan_info->cb;
+
+ if (fb_node == 0)
+ return 0;
+
+ return 0;
+}
+
+static int dcss_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *fbi)
+{
+ uint32_t fb_size;
+ uint32_t scale_ratio_mode_x, scale_ratio_mode_y;
+ uint32_t scale_ratio_x, scale_ratio_y;
+ struct dcss_channel_info *cinfo = fbi->par;
+ struct dcss_info *info = cinfo->dev_data;
+ struct platform_device *pdev = info->pdev;
+ const struct fb_bitfield *rgb = NULL;
+ const struct pix_fmt_info *format = NULL;
+ struct fb_fix_screeninfo *fix = &fbi->fix;
+ const struct fb_videomode *dmode = info->dft_disp_mode;
+
+ if (var->xres > MAX_WIDTH || var->yres > MAX_HEIGHT) {
+ dev_err(&pdev->dev, "unsupport display resolution\n");
+ return -EINVAL;
+ }
+
+ if (var->xres_virtual > var->xres) {
+ dev_err(&pdev->dev, "stride not supported\n");
+ return -EINVAL;
+ }
+
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+
+ switch (var->grayscale) {
+ case 0: /* TODO: color */
+ case 1: /* grayscale */
+ return -EINVAL;
+ default: /* fourcc */
+ format = get_fmt_info(var->grayscale);
+ if (!format) {
+ dev_err(&pdev->dev, "unsupport pixel format\n");
+ return -EINVAL;
+ }
+ var->bits_per_pixel = format->bpp;
+ }
+
+ /* Add alignment check for scaler */
+ switch (fmt_is_yuv(var->grayscale)) {
+ case 0: /* ARGB8888 */
+ case 2: /* YUV420 */
+ if (ALIGN(var->xres, 4) != var->xres ||
+ ALIGN(var->yres, 4) != var->yres) {
+ dev_err(&pdev->dev, "width or height is not aligned\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Add scale ratio check:
+ * Maximum scale down ratio is 1/7;
+ * Maximum scale up ratio is 8;
+ */
+ if (dmode->xres > var->xres) {
+ /* upscaling */
+ scale_ratio_mode_x = dmode->xres % var->xres;
+ scale_ratio_mode_y = dmode->yres % var->yres;
+ scale_ratio_x = (dmode->xres - scale_ratio_mode_x) / var->xres;
+ scale_ratio_y = (dmode->yres - scale_ratio_mode_y) / var->yres;
+ if (scale_ratio_x >= 8) {
+ if ((scale_ratio_x == 8 && scale_ratio_mode_x > 0) ||
+ (scale_ratio_x > 8)) {
+ dev_err(&pdev->dev, "unsupport scaling ration for width\n");
+ return -EINVAL;
+ }
+ }
+
+ if (scale_ratio_y >= 8) {
+ if ((scale_ratio_y == 8 && scale_ratio_mode_y > 0) ||
+ (scale_ratio_y > 8)) {
+ dev_err(&pdev->dev, "unsupport scaling ration for height\n");
+ return -EINVAL;
+ }
+ }
+ } else {
+ /* downscaling */
+ scale_ratio_mode_x = var->xres % dmode->xres;
+ scale_ratio_mode_y = var->yres % dmode->yres;
+ scale_ratio_x = (var->xres - scale_ratio_mode_x) / dmode->xres;
+ scale_ratio_y = (var->yres - scale_ratio_mode_y) / dmode->yres;
+ if (scale_ratio_x >= 7) {
+ if ((scale_ratio_x == 7 && scale_ratio_mode_x > 0) ||
+ (scale_ratio_x > 7)) {
+ dev_err(&pdev->dev, "unsupport scaling ration for width\n");
+ return -EINVAL;
+ }
+ }
+
+ if (scale_ratio_y >= 7) {
+ if ((scale_ratio_y == 7 && scale_ratio_mode_y > 0) ||
+ (scale_ratio_y > 7)) {
+ dev_err(&pdev->dev, "unsupport scaling ration for height\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ fix->line_length = var->xres * (var->bits_per_pixel >> 3);
+ fb_size = var->yres_virtual * fix->line_length;
+
+ if (fb_size > fix->smem_len) {
+ dev_err(&pdev->dev, "exceeds fb size limit!\n");
+ return -ENOMEM;
+ }
+
+ if (format && !format->is_yuv) {
+ switch (format->fourcc) {
+ case V4L2_PIX_FMT_ARGB32:
+ rgb = def_a8r8g8b8;
+ break;
+ case V4L2_PIX_FMT_A2R10G10B10:
+ rgb = def_a2r10g10b10;
+ break;
+ default:
+ dev_err(&pdev->dev, "unsupport pixel format\n");
+ return -EINVAL;
+ }
+
+ var->red = rgb[RED];
+ var->green = rgb[GREEN];
+ var->blue = rgb[BLUE];
+ var->transp = rgb[TRANSP];
+ } else {
+ /* TODO: YUV format */
+ ;
+ }
+
+ return 0;
+}
+
+static int config_channel_pipe(struct dcss_channel_info *cinfo)
+{
+ int ret = 0;
+ int fb_node;
+ struct fb_info *fbi = cinfo->fb_info;
+ struct dcss_info *info = cinfo->dev_data;
+ struct platform_device *pdev = info->pdev;
+
+ fb_node = fbi->node;
+
+ dev_dbg(&cinfo->pdev->dev, "begin config pipe %d\n", fb_node);
+
+ /* configure all the sub modules on one channel:
+ * 1. DEC400D/DTRC
+ * 2. DPR
+ * 3. SCALER
+ * 4. HDR10_INPUT
+ */
+ ret = dcss_decomp_config(fb_node, info);
+ if (ret) {
+ dev_err(&pdev->dev, "decomp config failed\n");
+ goto out;
+ }
+
+ ret = dcss_dpr_config(fb_node, info);
+ if (ret) {
+ dev_err(&pdev->dev, "dpr config failed\n");
+ goto out;
+ }
+
+ ret = dcss_scaler_config(fb_node, info);
+ if (ret) {
+ dev_err(&pdev->dev, "scaler config failed\n");
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static int dcss_set_par(struct fb_info *fbi)
+{
+ int ret = 0;
+ int fb_node = fbi->node;
+ struct dcss_channel_info *cinfo = fbi->par;
+ struct dcss_info *info = cinfo->dev_data;
+ struct cbuffer *cb = &cinfo->cb;
+ struct ctxld_commit *cc;
+
+ if (fb_node < 0 || fb_node > 2)
+ BUG_ON(1);
+
+ /* TODO: add save/recovery when config failed */
+ fb_var_to_pixmap(&cinfo->input, &fbi->var);
+
+ ret = config_channel_pipe(cinfo);
+ if (ret)
+ goto fail;
+
+ ret = dcss_dtg_config(fb_node, info);
+ if (ret)
+ goto fail;
+
+#if USE_CTXLD
+restart:
+ cc = obtain_cc(fb_node, info);
+ if (IS_ERR(cc)) {
+ ret = PTR_ERR(cc);
+ goto fail;
+ }
+
+ ret = commit_cfifo(fb_node, info, cc);
+ if (ret == -ERESTART)
+ goto restart;
+
+ kref_put(&cc->refcount, release_cc);
+#endif
+
+ goto out;
+
+fail:
+ /* drop any ctxld_uint already
+ * been written to sb or db
+ */
+ cb->sb_data_len = 0;
+ cb->db_data_len = 0;
+out:
+ return ret;
+}
+
+static int dcss_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp, struct fb_info *info)
+{
+ return 0;
+}
+
+static int dcss_channel_blank(int blank,
+ struct dcss_channel_info *cinfo)
+{
+ uint32_t dtg_ctrl;
+ struct dcss_info *info = cinfo->dev_data;
+ struct dcss_channels *chans = &info->chans;
+ struct cbuffer *cb = &cinfo->cb;
+
+ dtg_ctrl = readl(info->base + chans->dtg_addr + 0x0);
+
+ switch (blank) {
+ case FB_BLANK_UNBLANK:
+ /* set global alpha */
+ if (cinfo->channel_id == DCSS_CHAN_MAIN)
+ dtg_ctrl |= (0xff << 24);
+ else
+ dtg_ctrl &= ~(0xff << 24);
+ break;
+ case FB_BLANK_NORMAL:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_POWERDOWN:
+ /* clear global alpha */
+ if (cinfo->channel_id == DCSS_CHAN_MAIN)
+ dtg_ctrl &= ~(0xff << 24);
+ else
+ dtg_ctrl |= (0xff << 24);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ fill_sb(cb, chans->dtg_addr + 0x0, dtg_ctrl);
+
+ return 0;
+}
+
+static int dcss_blank(int blank, struct fb_info *fbi)
+{
+ int ret = 0;
+ int fb_node = fbi->node;
+ struct dcss_channel_info *cinfo = fbi->par;
+ struct dcss_info *info = cinfo->dev_data;
+ struct cbuffer *cb;
+ struct ctxld_commit *cc;
+
+ cb = &cinfo->cb;
+
+ dtg_channel_timing_config(blank, cinfo);
+ dcss_channel_blank(blank, cinfo);
+
+#if USE_CTXLD
+restart:
+ cc = obtain_cc(fb_node, info);
+ if (IS_ERR(cc)) {
+ ret = PTR_ERR(cc);
+ goto fail;
+ }
+
+ ret = commit_cfifo(fb_node, info, cc);
+ if (ret == -ERESTART)
+ goto restart;
+
+ kref_put(&cc->refcount, release_cc);
+#endif
+
+ cinfo->blank = blank;
+
+ goto out;
+
+fail:
+ /* drop any ctxld_uint already
+ * been written to sb or db
+ */
+ cb->sb_data_len = 0;
+ cb->db_data_len = 0;
+
+out:
+ return ret;
+}
+
+static int dcss_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *fbi)
+{
+ int ret = 0;
+ int fb_node = fbi->node;
+ uint32_t offset, pitch, luma_addr, chroma_addr = 0;
+ struct dcss_channel_info *cinfo = fbi->par;
+ struct dcss_info *info = cinfo->dev_data;
+ struct platform_device *pdev = info->pdev;
+ struct cbuffer *cb = &cinfo->cb;
+ struct dcss_pixmap *input = &cinfo->input;
+ struct ctxld_commit *cc;
+
+ /* TODO: change framebuffer memory start address */
+ luma_addr = var->reserved[0] ? var->reserved[0] :
+ fbi->fix.smem_start;
+
+ /* change display offset in framebuffer */
+ if (var->xoffset > 0) {
+ dev_dbg(&pdev->dev, "x panning not supported\n");
+ return -EINVAL;
+ }
+
+ if ((var->yoffset + var->yres > var->yres_virtual)) {
+ dev_err(&pdev->dev, "y panning exceeds\n");
+ return -EINVAL;
+ }
+
+ offset = fbi->fix.line_length * var->yoffset;
+
+ fill_sb(cb, cinfo->dpr_addr + 0xc0, luma_addr + offset);
+
+ /* Two planes YUV format */
+ if (fmt_is_yuv(input->format) == 2) {
+ pitch = ALIGN(var->xres * (var->bits_per_pixel >> 3), 16);
+ chroma_addr = luma_addr + pitch * var->yres;
+ fill_sb(cb,
+ cinfo->dpr_addr + 0x110,
+ chroma_addr + (offset >> 1));
+ }
+
+#if USE_CTXLD
+restart:
+ cc = obtain_cc(fb_node, info);
+ if (IS_ERR(cc)) {
+ ret = PTR_ERR(cc);
+ goto fail;
+ }
+
+ ret = commit_cfifo(fb_node, info, cc);
+ if (ret == -ERESTART)
+ goto restart;
+
+ kref_put(&cc->refcount, release_cc);
+#endif
+
+ goto out;
+
+fail:
+ /* drop any ctxld_uint already
+ * been written to sb or db
+ */
+ cb->sb_data_len = 0;
+ cb->db_data_len = 0;
+
+out:
+ return ret;
+}
+
+static int vcount_compare(unsigned long vcount,
+ struct vsync_info *vinfo)
+{
+ int ret = 0;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&vinfo->vwait.lock, irqflags);
+
+ ret = (vcount != vinfo->vcount) ? 1 : 0;
+
+ spin_unlock_irqrestore(&vinfo->vwait.lock, irqflags);
+
+ return ret;
+}
+
+static int dcss_wait_for_vsync(unsigned long crtc,
+ struct dcss_info *info)
+{
+ int ret = 0;
+ unsigned long irqflags, vcount;
+ struct platform_device *pdev = info->pdev;
+
+ spin_lock_irqsave(&info->vinfo.vwait.lock, irqflags);
+ vcount = info->vinfo.vcount;
+ spin_unlock_irqrestore(&info->vinfo.vwait.lock, irqflags);
+
+ ret = wait_event_interruptible_timeout(info->vinfo.vwait,
+ vcount_compare(vcount, &info->vinfo),
+ HZ);
+ if (!ret) {
+ dev_err(&pdev->dev, "wait vsync active timeout\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int dcss_ioctl(struct fb_info *fbi, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = 0;
+ unsigned long crtc;
+ void __user *argp = (void __user *)arg;
+ struct dcss_channel_info *cinfo = fbi->par;
+ struct dcss_info *info = cinfo->dev_data;
+ struct platform_device *pdev = cinfo->pdev;
+
+ switch (cmd) {
+ case FBIO_WAITFORVSYNC:
+ if (copy_from_user(&crtc, argp, sizeof(unsigned long)))
+ return -EFAULT;
+
+ ret = dcss_wait_for_vsync(crtc, info);
+ break;
+ default:
+ dev_err(&pdev->dev, "invalid ioctl command: 0x%x\n", cmd);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static void ctxld_irq_clear(struct dcss_info *info)
+{
+ uint32_t irq_status;
+ struct dcss_channels *chans = &info->chans;
+ struct platform_device *pdev = info->pdev;
+
+ irq_status = readl(info->base + chans->ctxld_addr + CTXLD_CTRL_STATUS);
+ dev_dbg(&pdev->dev, "ctxld irq_status before = 0x%x\n", irq_status);
+
+ if (irq_status & RD_ERR)
+ writel(RD_ERR, info->base + chans->ctxld_addr + CTXLD_CTRL_STATUS_CLR);
+
+ if (irq_status & DB_COMP)
+ writel(DB_COMP, info->base + chans->ctxld_addr + CTXLD_CTRL_STATUS_CLR);
+
+ if (irq_status & SB_HP_COMP)
+ writel(SB_HP_COMP,
+ info->base + chans->ctxld_addr + CTXLD_CTRL_STATUS_CLR);
+
+ if (irq_status & SB_LP_COMP)
+ writel(SB_LP_COMP,
+ info->base + chans->ctxld_addr + CTXLD_CTRL_STATUS_CLR);
+
+ if (irq_status & AHB_ERR)
+ writel(AHB_ERR,
+ info->base + chans->ctxld_addr + CTXLD_CTRL_STATUS_CLR);
+
+ irq_status = readl(info->base + chans->ctxld_addr + CTXLD_CTRL_STATUS);
+}
+
+static irqreturn_t dcss_irq_handler(int irq, void *dev_id)
+{
+ int ret;
+ struct irq_desc *desc;
+ uint32_t irq_status;
+ unsigned long irqflags;
+ struct dcss_info *info = (struct dcss_info *)dev_id;
+ struct dcss_channels *chans = &info->chans;
+ struct dcss_channel_info *chan;
+ struct ctxld_fifo *cfifo;
+ struct ctxld_commit *cc;
+
+ cfifo = &info->cfifo;
+ desc = irq_to_desc(irq);
+
+ switch (desc->irq_data.hwirq) {
+ case IRQ_DPR_CH1:
+ chan = &chans->chan_info[0];
+ irq_status = readl(info->base + chan->dpr_addr + 0x40);
+ writel(irq_status, info->base + chan->dpr_addr + 0x40);
+ break;
+ case IRQ_DPR_CH2:
+ break;
+ case IRQ_DPR_CH3:
+ break;
+ case IRQ_CTX_LD:
+ ctxld_irq_clear(info);
+ complete(&cfifo->complete);
+ break;
+ case IRQ_TC_LINE1:
+ dtg_irq_clear(IRQ_TC_LINE1, info);
+
+ spin_lock_irqsave(&info->vinfo.vwait.lock, irqflags);
+
+ /* unblock new commits */
+ info->vinfo.vcount++;
+
+ if (!list_empty(&cfifo->ctxld_list)) {
+ cc = list_first_entry(&cfifo->ctxld_list,
+ struct ctxld_commit,
+ list);
+
+ ret = kref_put(&cc->refcount, release_cc_locked);
+
+ /* 'cc' can not be released */
+ if (!ret)
+ defer_flush_cfifo(cfifo);
+ }
+
+ spin_unlock_irqrestore(&info->vinfo.vwait.lock, irqflags);
+
+ wake_up_all(&info->vinfo.vwait);
+ break;
+ case IRQ_DEC400D_CH1:
+ case IRQ_DTRC_CH2:
+ case IRQ_DTRC_CH3:
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int dcss_interrupts_init(struct dcss_info *info)
+{
+ int i, ret = 0;
+ struct irq_desc *desc;
+ struct dcss_channels *chans = &info->chans;
+ struct platform_device *pdev = info->pdev;
+
+ for (i = 0; i < DCSS_IRQS_NUM; i++) {
+ info->irqs[i] = platform_get_irq(pdev, i);
+ if (info->irqs[i] < 0)
+ break;
+
+ desc = irq_to_desc(info->irqs[i]);
+ switch (desc->irq_data.hwirq) {
+ case 6: /* CTX_LD */
+ ctxld_irq_unmask(SB_HP_COMP_EN, info);
+ break;
+ case 8: /* dtg_programmable_1: for vsync */
+ /* TODO: (0, 0) or (last, last)? */
+ writel(0x0, info->base + chans->dtg_addr + TC_LINE1_INT);
+ dtg_irq_unmask(IRQ_TC_LINE1, info);
+ break;
+ default: /* TODO: add support later */
+ continue;
+ }
+
+ ret = devm_request_irq(&pdev->dev, info->irqs[i],
+ dcss_irq_handler, 0,
+ dev_name(&pdev->dev), info);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq (%d) failed with error %d\n",
+ info->irqs[i], ret);
+ return ret;
+ }
+ }
+
+ if (i == 0)
+ return -ENXIO;
+
+ info->irqs_num = i + 1;
+
+ return 0;
+}
+
+static void __iomem *dev_iomem_init(struct platform_device *pdev,
+ unsigned int res_idx)
+{
+ struct resource *res;
+
+ if (res_idx > IORESOURCE_MEM_NUM)
+ return NULL;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, res_idx);
+ if (!res)
+ return ERR_PTR(-ENODEV);
+
+ return devm_ioremap_resource(&pdev->dev, res);
+}
+
+static int dcss_dispdrv_init(struct platform_device *pdev,
+ struct fb_info *fbi)
+{
+ struct dcss_channel_info *cinfo = fbi->par;
+ struct dcss_info *info = cinfo->dev_data;
+ struct mxc_dispdrv_setting setting;
+ char disp_dev[NAME_LEN];
+
+ memset(&setting, 0x0, sizeof(setting));
+ setting.fbi = fbi;
+ memcpy(disp_dev, info->disp_dev, strlen(info->disp_dev));
+ disp_dev[strlen(info->disp_dev)] = '\0';
+
+ info->dispdrv = mxc_dispdrv_gethandle(disp_dev, &setting);
+ if (IS_ERR(info->dispdrv)) {
+ dev_info(&pdev->dev, "no encoder driver exists\n");
+ return -EPROBE_DEFER;
+ }
+
+ dev_info(&pdev->dev, "%s encoder registered success\n", disp_dev);
+
+ return 0;
+}
+
+static int dcss_register_one_ch(uint32_t ch_id,
+ struct dcss_info *info)
+{
+ int ret = 0;
+ struct dcss_channels *chans;
+ struct dcss_channel_info *cinfo;
+
+ BUG_ON(ch_id > 2);
+
+ chans = &info->chans;
+ cinfo = &chans->chan_info[ch_id];
+
+ cinfo->pdev = info->pdev;
+ cinfo->dev_data = (void *)info;
+
+ ret = fill_one_chan_info(ch_id, cinfo);
+ if (ret) {
+ dev_err(&info->pdev->dev, "register channel %d failed\n", ch_id);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int dcss_register_one_fb(struct dcss_channel_info *cinfo)
+{
+ int ret = 0;
+ struct fb_info *fbi;
+
+ ret = alloc_one_fbinfo(cinfo);
+ if (ret) {
+ dev_err(&cinfo->pdev->dev,
+ "register fb %d failed\n", cinfo->channel_id);
+ goto out;
+ }
+
+ fbi = cinfo->fb_info;
+ ret = dcss_init_fbinfo(fbi);
+ if (ret)
+ goto out;
+
+ init_chan_pixmap(cinfo);
+ init_ch_pos(cinfo);
+
+ if (cinfo->channel_id == 0) {
+ ret = dcss_dispdrv_init(cinfo->pdev, fbi);
+ if (ret == -EPROBE_DEFER) {
+ dev_info(&cinfo->pdev->dev,
+ "Defer fb probe for encoder unready\n");
+ goto out;
+ }
+ }
+
+ ret = register_framebuffer(fbi);
+ if (ret) {
+ dev_err(&cinfo->pdev->dev, "failed to register fb%d\n",
+ cinfo->channel_id);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static int read_dcss_properties(struct dcss_info *info)
+{
+ int ret = 0;
+ uint32_t disp_mode;
+ const char *disp_dev;
+ struct platform_device *pdev = info->pdev;
+ struct device_node *np = pdev->dev.of_node;
+
+ /* read disp-mode */
+ ret = of_property_read_u32(np, "disp-mode", &disp_mode);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "invalid disp-mode provided in dtb\n");
+ return -EINVAL;
+ }
+
+ info->dft_disp_mode = &imx_cea_mode[disp_mode];
+ if (!info->dft_disp_mode->xres)
+ return -EINVAL;
+
+ /* read disp-dev */
+ ret = of_property_read_string(np, "disp-dev", &disp_dev);
+ if (!ret) {
+ memcpy(info->disp_dev, disp_dev, strlen(disp_dev));
+ dev_info(&pdev->dev, "%s: disp_dev = %s\n", __func__,
+ info->disp_dev);
+ }
+
+ return 0;
+}
+
+static int dcss_info_init(struct dcss_info *info)
+{
+ int ret = 0;
+ struct platform_device *pdev = info->pdev;
+
+ spin_lock_init(&info->llock);
+
+ info->dcss_state = DCSS_STATE_RESET;
+
+ ret = read_dcss_properties(info);
+ if (ret)
+ return -ENODEV;
+
+ ret = dcss_init_chans(info);
+
+ info->base = dev_iomem_init(pdev, 0);
+ if (IS_ERR(info->base)) {
+ ret = PTR_ERR(info->base);
+ goto out;
+ }
+
+ info->blkctl_base = dev_iomem_init(pdev, 1);
+ if (IS_ERR(info->blkctl_base)) {
+ ret = PTR_ERR(info->blkctl_base);
+ goto out;
+ }
+
+ ret = dcss_clks_get(info);
+ if (ret)
+ goto out;
+
+ ret = dcss_clks_rate_set(info);
+ if (ret)
+ goto out;
+
+ ret = dcss_clks_enable(info);
+ if (ret)
+ goto out;
+
+ /* alloc ctxld fifo */
+ ret = ctxld_fifo_alloc(&pdev->dev, &info->cfifo, DCSS_CFIFO_SIZE);
+ if (ret) {
+ dev_err(&pdev->dev, "ctxld fifo alloc failed\n");
+ goto out;
+ }
+
+ info->cfifo.ctxld_wq = alloc_ordered_workqueue("ctxld-wq", WQ_FREEZABLE);
+ if (!info->cfifo.ctxld_wq) {
+ dev_err(&pdev->dev, "allocate ctxld wq failed\n");
+ ret = -EINVAL;
+ goto free_cfifo;
+ }
+
+ platform_set_drvdata(pdev, info);
+ init_waitqueue_head(&info->vinfo.vwait);
+ info->vinfo.vcount = 0;
+
+ goto out;
+
+free_cfifo:
+ ctxld_fifo_free(&pdev->dev, &info->cfifo);
+out:
+ return ret;
+}
+
+static int dcss_enable_encoder(struct dcss_info *info)
+{
+ int ret = 0;
+ struct fb_info *main_fbinfo;
+ struct platform_device *pdev;
+
+ if (!info->dispdrv)
+ goto out;
+
+ pdev = info->pdev;
+ main_fbinfo = get_one_fbinfo(0, &info->chans);
+
+ if (info->dispdrv->drv->setup) {
+ ret = info->dispdrv->drv->setup(info->dispdrv, main_fbinfo);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "setup encoder failed: %d\n", ret);
+ goto out;
+ }
+ }
+
+ if (info->dispdrv->drv->enable) {
+ ret = info->dispdrv->drv->enable(info->dispdrv, main_fbinfo);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "enable encoder failed: %d\n", ret);
+ goto out;
+ }
+ }
+
+out:
+ return ret;
+}
+
+static void dcss_fix_data_config(struct dcss_info *info)
+{
+ int i, esize;
+
+ esize = sizeof(struct data_unit);
+
+ /* SCALER COEFFS config */
+ for (i = 0; i < sizeof(scaler_coeffs_ch0) / esize; i++)
+ writel(scaler_coeffs_ch0[i].data,
+ info->base + scaler_coeffs_ch0[i].addr);
+
+ for (i = 0; i < sizeof(scaler_coeffs_ch1) / esize; i++)
+ writel(scaler_coeffs_ch1[i].data,
+ info->base + scaler_coeffs_ch1[i].addr);
+
+ /* HDR10 PIPE1 config */
+ for (i = 0; i < sizeof(hdr10_pipe1_lut_a0) / esize; i++)
+ writel(hdr10_pipe1_lut_a0[i].data,
+ info->base + hdr10_pipe1_lut_a0[i].addr);
+
+ for (i = 0; i < sizeof(hdr10_pipe1_lut_a1) / esize; i++)
+ writel(hdr10_pipe1_lut_a1[i].data,
+ info->base + hdr10_pipe1_lut_a1[i].addr);
+
+ for (i = 0; i < sizeof(hdr10_pipe1_lut_a2) / esize; i++)
+ writel(hdr10_pipe1_lut_a2[i].data,
+ info->base + hdr10_pipe1_lut_a2[i].addr);
+
+ for (i = 0; i < sizeof(hdr10_pipe1_csca) / esize; i++)
+ writel(hdr10_pipe1_csca[i].data,
+ info->base + hdr10_pipe1_csca[i].addr);
+
+ for (i = 0; i < sizeof(hdr10_pipe1_cscb) / esize; i++)
+ writel(hdr10_pipe1_cscb[i].data,
+ info->base + hdr10_pipe1_cscb[i].addr);
+
+ /* HDR10 PIPE2 config */
+ for (i = 0; i < sizeof(hdr10_pipe2_lut_a0) / esize; i++)
+ writel(hdr10_pipe2_lut_a0[i].data,
+ info->base + hdr10_pipe2_lut_a0[i].addr);
+
+ for (i = 0; i < sizeof(hdr10_pipe2_lut_a1) / esize; i++)
+ writel(hdr10_pipe2_lut_a1[i].data,
+ info->base + hdr10_pipe2_lut_a1[i].addr);
+
+ for (i = 0; i < sizeof(hdr10_pipe2_lut_a2) / esize; i++)
+ writel(hdr10_pipe2_lut_a2[i].data,
+ info->base + hdr10_pipe2_lut_a2[i].addr);
+
+ for (i = 0; i < sizeof(hdr10_pipe2_csca) / esize; i++)
+ writel(hdr10_pipe2_csca[i].data,
+ info->base + hdr10_pipe2_csca[i].addr);
+
+ for (i = 0; i < sizeof(hdr10_pipe2_cscb) / esize; i++)
+ writel(hdr10_pipe2_cscb[i].data,
+ info->base + hdr10_pipe2_cscb[i].addr);
+
+ /* HDR10 OPIPE config */
+ for (i = 0; i < sizeof(hdr10_opipe_a0) / esize; i++)
+ writel(hdr10_opipe_a0[i].data,
+ info->base + hdr10_opipe_a0[i].addr);
+
+ for (i = 0; i < sizeof(hdr10_opipe_a1) / esize; i++)
+ writel(hdr10_opipe_a1[i].data,
+ info->base + hdr10_opipe_a1[i].addr);
+
+ for (i = 0; i < sizeof(hdr10_opipe_a2) / esize; i++)
+ writel(hdr10_opipe_a2[i].data,
+ info->base + hdr10_opipe_a2[i].addr);
+
+ for (i = 0; i < sizeof(hdr10_opipe_csco) / esize; i++)
+ writel(hdr10_opipe_csco[i].data,
+ info->base + hdr10_opipe_csco[i].addr);
+}
+
+static int dcss_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct dcss_info *info;
+ struct fb_info *m_fbinfo;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(struct dcss_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->pdev = pdev;
+
+ ret = dcss_info_init(info);
+ if (ret)
+ goto kfree_info;
+
+ /* TODO: reset DCSS to make it clean */
+
+ /* Clocks select: before dcss de-resets */
+ if (!strcmp(info->disp_dev, "hdmi_disp"))
+ /* HDMI */
+ writel(0x0, info->blkctl_base + 0x10);
+ else
+ /* MIPI DSI */
+ writel(0x101, info->blkctl_base + 0x10);
+
+ /* Pull DCSS out of resets */
+ writel(0xffffffff, info->blkctl_base + 0x0);
+
+ /* TODO: config fixed data for DCSS */
+ dcss_fix_data_config(info);
+
+ dcss_interrupts_init(info);
+
+ ret = dcss_dtg_start(info);
+ if (ret)
+ goto kfree_info;
+
+ /* register channel 0: graphic */
+ ret = dcss_register_one_ch(0, info);
+ if (ret)
+ goto kfree_info;
+
+ /* register fb 0 */
+ ret = dcss_register_one_fb(&info->chans.chan_info[0]);
+ if (ret)
+ goto unregister_ch0;
+
+ /* enable encoder if exists */
+ dcss_enable_encoder(info);
+
+ ret = dcss_subsam_config(info);
+ if (ret)
+ goto unregister_fb0;
+
+ /* register channel 1: video */
+ ret = dcss_register_one_ch(1, info);
+ if (ret)
+ goto unregister_fb0;
+
+ /* register fb 1 */
+ ret = dcss_register_one_fb(&info->chans.chan_info[1]);
+ if (ret)
+ goto unregister_ch1;
+
+ /* unblank fb0 */
+ m_fbinfo = get_one_fbinfo(0, &info->chans);
+ dcss_blank(FB_BLANK_UNBLANK, m_fbinfo);
+
+ /* init fb1 */
+ dcss_set_par(get_one_fbinfo(1, &info->chans));
+
+ goto out;
+
+unregister_ch1:
+ /* TODO: add later */
+ ;
+unregister_fb0:
+ framebuffer_release(get_one_fbinfo(0, &info->chans));
+unregister_ch0:
+ /* TODO: add later */
+ ;
+kfree_info:
+ devm_kfree(&pdev->dev, info);
+out:
+ return ret;
+}
+
+static int dcss_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static void dcss_shutdown(struct platform_device *pdev)
+{
+}
+
+static struct platform_driver dcss_driver = {
+ .probe = dcss_probe,
+ .remove = dcss_remove,
+ .shutdown = dcss_shutdown,
+ .driver = {
+ .name = "dcss_fb",
+ .of_match_table = dcss_dt_ids,
+ },
+};
+
+module_platform_driver(dcss_driver);
+
+MODULE_DESCRIPTION("NXP DCSS framebuffer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/mxc/imx_dcss_table.h b/drivers/video/fbdev/mxc/imx_dcss_table.h
new file mode 100644
index 000000000000..6046a7a73251
--- /dev/null
+++ b/drivers/video/fbdev/mxc/imx_dcss_table.h
@@ -0,0 +1,9761 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; 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
+ *
+ */
+
+/* data unit structure for coeffs */
+struct data_unit {
+ uint32_t addr;
+ uint32_t data;
+};
+
+struct data_unit scaler_coeffs_ch0[] = {
+ { 0x0001c300, 0x00000000 },
+ { 0x0001c304, 0x00000000 },
+ { 0x0001c308, 0x00000000 },
+ { 0x0001c30c, 0x00000000 },
+ { 0x0001c310, 0x00000000 },
+ { 0x0001c314, 0x00000000 },
+ { 0x0001c318, 0x00000000 },
+ { 0x0001c31c, 0x00000000 },
+ { 0x0001c320, 0x00000000 },
+ { 0x0001c324, 0x00000000 },
+ { 0x0001c328, 0x00000000 },
+ { 0x0001c32c, 0x00000000 },
+ { 0x0001c330, 0x00000000 },
+ { 0x0001c334, 0x00000000 },
+ { 0x0001c338, 0x00000000 },
+ { 0x0001c33c, 0x00000000 },
+ { 0x0001c340, 0x00040000 },
+ { 0x0001c344, 0x00040000 },
+ { 0x0001c348, 0x00040000 },
+ { 0x0001c34c, 0x00040000 },
+ { 0x0001c350, 0x00040000 },
+ { 0x0001c354, 0x00040000 },
+ { 0x0001c358, 0x00040000 },
+ { 0x0001c35c, 0x00040000 },
+ { 0x0001c360, 0x00040000 },
+ { 0x0001c364, 0x00040000 },
+ { 0x0001c368, 0x00040000 },
+ { 0x0001c36c, 0x00040000 },
+ { 0x0001c370, 0x00040000 },
+ { 0x0001c374, 0x00040000 },
+ { 0x0001c378, 0x00040000 },
+ { 0x0001c37c, 0x00040000 },
+ { 0x0001c380, 0x00000000 },
+ { 0x0001c384, 0x00000000 },
+ { 0x0001c388, 0x00000000 },
+ { 0x0001c38c, 0x00000000 },
+ { 0x0001c390, 0x00000000 },
+ { 0x0001c394, 0x00000000 },
+ { 0x0001c398, 0x00000000 },
+ { 0x0001c39c, 0x00000000 },
+ { 0x0001c3a0, 0x00000000 },
+ { 0x0001c3a4, 0x00000000 },
+ { 0x0001c3a8, 0x00000000 },
+ { 0x0001c3ac, 0x00000000 },
+ { 0x0001c3b0, 0x00000000 },
+ { 0x0001c3b4, 0x00000000 },
+ { 0x0001c3b8, 0x00000000 },
+ { 0x0001c3bc, 0x00000000 },
+
+ { 0x0001c140, 0x00000000 },
+ { 0x0001c144, 0x00000000 },
+ { 0x0001c148, 0x00000000 },
+ { 0x0001c14c, 0x00000000 },
+ { 0x0001c150, 0x00000000 },
+ { 0x0001c154, 0x00000000 },
+ { 0x0001c158, 0x00000000 },
+ { 0x0001c15c, 0x00000000 },
+ { 0x0001c160, 0x00000000 },
+ { 0x0001c164, 0x00000000 },
+ { 0x0001c168, 0x00000000 },
+ { 0x0001c16c, 0x00000000 },
+ { 0x0001c170, 0x00000000 },
+ { 0x0001c174, 0x00000000 },
+ { 0x0001c178, 0x00000000 },
+ { 0x0001c17c, 0x00000000 },
+ { 0x0001c180, 0x00040000 },
+ { 0x0001c184, 0x00040000 },
+ { 0x0001c188, 0x00040000 },
+ { 0x0001c18c, 0x00040000 },
+ { 0x0001c190, 0x00040000 },
+ { 0x0001c194, 0x00040000 },
+ { 0x0001c198, 0x00040000 },
+ { 0x0001c19c, 0x00040000 },
+ { 0x0001c1a0, 0x00040000 },
+ { 0x0001c1a4, 0x00040000 },
+ { 0x0001c1a8, 0x00040000 },
+ { 0x0001c1ac, 0x00040000 },
+ { 0x0001c1b0, 0x00040000 },
+ { 0x0001c1b4, 0x00040000 },
+ { 0x0001c1b8, 0x00040000 },
+ { 0x0001c1bc, 0x00040000 },
+ { 0x0001c1c0, 0x00000000 },
+ { 0x0001c1c4, 0x00000000 },
+ { 0x0001c1c8, 0x00000000 },
+ { 0x0001c1cc, 0x00000000 },
+ { 0x0001c1d0, 0x00000000 },
+ { 0x0001c1d4, 0x00000000 },
+ { 0x0001c1d8, 0x00000000 },
+ { 0x0001c1dc, 0x00000000 },
+ { 0x0001c1e0, 0x00000000 },
+ { 0x0001c1e4, 0x00000000 },
+ { 0x0001c1e8, 0x00000000 },
+ { 0x0001c1ec, 0x00000000 },
+ { 0x0001c1f0, 0x00000000 },
+ { 0x0001c1f4, 0x00000000 },
+ { 0x0001c1f8, 0x00000000 },
+ { 0x0001c1fc, 0x00000000 },
+
+ { 0x0001c200, 0x00000000 },
+ { 0x0001c204, 0x00000000 },
+ { 0x0001c208, 0x00000000 },
+ { 0x0001c20c, 0x00000000 },
+ { 0x0001c210, 0x00000000 },
+ { 0x0001c214, 0x00000000 },
+ { 0x0001c218, 0x00000000 },
+ { 0x0001c21c, 0x00000000 },
+ { 0x0001c220, 0x00000000 },
+ { 0x0001c224, 0x00000000 },
+ { 0x0001c228, 0x00000000 },
+ { 0x0001c22c, 0x00000000 },
+ { 0x0001c230, 0x00000000 },
+ { 0x0001c234, 0x00000000 },
+ { 0x0001c238, 0x00000000 },
+ { 0x0001c23c, 0x00000000 },
+ { 0x0001c240, 0x00040000 },
+ { 0x0001c244, 0x00040000 },
+ { 0x0001c248, 0x00040000 },
+ { 0x0001c24c, 0x00040000 },
+ { 0x0001c250, 0x00040000 },
+ { 0x0001c254, 0x00040000 },
+ { 0x0001c258, 0x00040000 },
+ { 0x0001c25c, 0x00040000 },
+ { 0x0001c260, 0x00040000 },
+ { 0x0001c264, 0x00040000 },
+ { 0x0001c268, 0x00040000 },
+ { 0x0001c26c, 0x00040000 },
+ { 0x0001c270, 0x00040000 },
+ { 0x0001c274, 0x00040000 },
+ { 0x0001c278, 0x00040000 },
+ { 0x0001c27c, 0x00040000 },
+ { 0x0001c280, 0x00000000 },
+ { 0x0001c284, 0x00000000 },
+ { 0x0001c288, 0x00000000 },
+ { 0x0001c28c, 0x00000000 },
+ { 0x0001c290, 0x00000000 },
+ { 0x0001c294, 0x00000000 },
+ { 0x0001c298, 0x00000000 },
+ { 0x0001c29c, 0x00000000 },
+ { 0x0001c2a0, 0x00000000 },
+ { 0x0001c2a4, 0x00000000 },
+ { 0x0001c2a8, 0x00000000 },
+ { 0x0001c2ac, 0x00000000 },
+ { 0x0001c2b0, 0x00000000 },
+ { 0x0001c2b4, 0x00000000 },
+ { 0x0001c2b8, 0x00000000 },
+ { 0x0001c2bc, 0x00000000 },
+
+ { 0x0001c080, 0x00000000 },
+ { 0x0001c084, 0x00000000 },
+ { 0x0001c088, 0x00000000 },
+ { 0x0001c08c, 0x00000000 },
+ { 0x0001c090, 0x00000000 },
+ { 0x0001c094, 0x00000000 },
+ { 0x0001c098, 0x00000000 },
+ { 0x0001c09c, 0x00000000 },
+ { 0x0001c0a0, 0x00000000 },
+ { 0x0001c0a4, 0x00000000 },
+ { 0x0001c0a8, 0x00000000 },
+ { 0x0001c0ac, 0x00000000 },
+ { 0x0001c0b0, 0x00000000 },
+ { 0x0001c0b4, 0x00000000 },
+ { 0x0001c0b8, 0x00000000 },
+ { 0x0001c0bc, 0x00000000 },
+ { 0x0001c0c0, 0x00040000 },
+ { 0x0001c0c4, 0x00040000 },
+ { 0x0001c0c8, 0x00040000 },
+ { 0x0001c0cc, 0x00040000 },
+ { 0x0001c0d0, 0x00040000 },
+ { 0x0001c0d4, 0x00040000 },
+ { 0x0001c0d8, 0x00040000 },
+ { 0x0001c0dc, 0x00040000 },
+ { 0x0001c0e0, 0x00040000 },
+ { 0x0001c0e4, 0x00040000 },
+ { 0x0001c0e8, 0x00040000 },
+ { 0x0001c0ec, 0x00040000 },
+ { 0x0001c0f0, 0x00040000 },
+ { 0x0001c0f4, 0x00040000 },
+ { 0x0001c0f8, 0x00040000 },
+ { 0x0001c0fc, 0x00040000 },
+ { 0x0001c100, 0x00000000 },
+ { 0x0001c104, 0x00000000 },
+ { 0x0001c108, 0x00000000 },
+ { 0x0001c10c, 0x00000000 },
+ { 0x0001c110, 0x00000000 },
+ { 0x0001c114, 0x00000000 },
+ { 0x0001c118, 0x00000000 },
+ { 0x0001c11c, 0x00000000 },
+ { 0x0001c120, 0x00000000 },
+ { 0x0001c124, 0x00000000 },
+ { 0x0001c128, 0x00000000 },
+ { 0x0001c12c, 0x00000000 },
+ { 0x0001c130, 0x00000000 },
+ { 0x0001c134, 0x00000000 },
+ { 0x0001c138, 0x00000000 },
+ { 0x0001c13c, 0x00000000 },
+};
+
+struct data_unit scaler_coeffs_ch1[] = {
+ { 0x0001c700, 0x00000000 },
+ { 0x0001c704, 0x00000000 },
+ { 0x0001c708, 0x00000000 },
+ { 0x0001c70c, 0x00000000 },
+ { 0x0001c710, 0x00000000 },
+ { 0x0001c714, 0x00000000 },
+ { 0x0001c718, 0x00000000 },
+ { 0x0001c71c, 0x00000000 },
+ { 0x0001c720, 0x00000000 },
+ { 0x0001c724, 0x00000061 },
+ { 0x0001c728, 0x00000041 },
+ { 0x0001c72c, 0x00000031 },
+ { 0x0001c730, 0x00000021 },
+ { 0x0001c734, 0x00000010 },
+ { 0x0001c738, 0x00000010 },
+ { 0x0001c73c, 0x00000000 },
+ { 0x0001c740, 0x06d32506 },
+ { 0x0001c744, 0x05432008 },
+ { 0x0001c748, 0x0403100a },
+ { 0x0001c74c, 0x0302f50d },
+ { 0x0001c750, 0x0242d110 },
+ { 0x0001c754, 0x01a2a413 },
+ { 0x0001c758, 0x01326f17 },
+ { 0x0001c75c, 0x00d2351b },
+ { 0x0001c760, 0x0091f71f },
+ { 0x0001c764, 0x0b823500 },
+ { 0x0001c768, 0x07a26f01 },
+ { 0x0001c76c, 0x03f2a401 },
+ { 0x0001c770, 0x0092d102 },
+ { 0x0001c774, 0x0d92f503 },
+ { 0x0001c778, 0x0af31004 },
+ { 0x0001c77c, 0x08b32005 },
+ { 0x0001c780, 0x0d000000 },
+ { 0x0001c784, 0x0b000000 },
+ { 0x0001c788, 0x0f001000 },
+ { 0x0001c78c, 0x09001000 },
+ { 0x0001c790, 0x09002000 },
+ { 0x0001c794, 0x0f003000 },
+ { 0x0001c798, 0x0a004000 },
+ { 0x0001c79c, 0x08006000 },
+ { 0x0001c7a0, 0x07009000 },
+ { 0x0001c7a4, 0x0d000000 },
+ { 0x0001c7a8, 0x03000000 },
+ { 0x0001c7ac, 0x0a000000 },
+ { 0x0001c7b0, 0x04000000 },
+ { 0x0001c7b4, 0x00000000 },
+ { 0x0001c7b8, 0x00000000 },
+ { 0x0001c7bc, 0x04000000 },
+
+ { 0x0001c540, 0x00000000 },
+ { 0x0001c544, 0x00000000 },
+ { 0x0001c548, 0x00000000 },
+ { 0x0001c54c, 0x00000000 },
+ { 0x0001c550, 0x00000000 },
+ { 0x0001c554, 0x00000000 },
+ { 0x0001c558, 0x00000000 },
+ { 0x0001c55c, 0x00000000 },
+ { 0x0001c560, 0x00000000 },
+ { 0x0001c564, 0x00000061 },
+ { 0x0001c568, 0x00000041 },
+ { 0x0001c56c, 0x00000031 },
+ { 0x0001c570, 0x00000021 },
+ { 0x0001c574, 0x00000010 },
+ { 0x0001c578, 0x00000010 },
+ { 0x0001c57c, 0x00000000 },
+ { 0x0001c580, 0x06d32506 },
+ { 0x0001c584, 0x05432008 },
+ { 0x0001c588, 0x0403100a },
+ { 0x0001c58c, 0x0302f50d },
+ { 0x0001c590, 0x0242d110 },
+ { 0x0001c594, 0x01a2a413 },
+ { 0x0001c598, 0x01326f17 },
+ { 0x0001c59c, 0x00d2351b },
+ { 0x0001c5a0, 0x0091f71f },
+ { 0x0001c5a4, 0x0b823500 },
+ { 0x0001c5a8, 0x07a26f01 },
+ { 0x0001c5ac, 0x03f2a401 },
+ { 0x0001c5b0, 0x0092d102 },
+ { 0x0001c5b4, 0x0d92f503 },
+ { 0x0001c5b8, 0x0af31004 },
+ { 0x0001c5bc, 0x08b32005 },
+ { 0x0001c5c0, 0x0d000000 },
+ { 0x0001c5c4, 0x0b000000 },
+ { 0x0001c5c8, 0x0f001000 },
+ { 0x0001c5cc, 0x09001000 },
+ { 0x0001c5d0, 0x09002000 },
+ { 0x0001c5d4, 0x0f003000 },
+ { 0x0001c5d8, 0x0a004000 },
+ { 0x0001c5dc, 0x08006000 },
+ { 0x0001c5e0, 0x07009000 },
+ { 0x0001c5e4, 0x0d000000 },
+ { 0x0001c5e8, 0x03000000 },
+ { 0x0001c5ec, 0x0a000000 },
+ { 0x0001c5f0, 0x04000000 },
+ { 0x0001c5f4, 0x00000000 },
+ { 0x0001c5f8, 0x00000000 },
+ { 0x0001c5fc, 0x04000000 },
+ { 0x0001c600, 0x00000000 },
+ { 0x0001c604, 0x00000000 },
+ { 0x0001c608, 0x00000000 },
+ { 0x0001c60c, 0x00000000 },
+ { 0x0001c610, 0x00000000 },
+ { 0x0001c614, 0x00000000 },
+ { 0x0001c618, 0x00000000 },
+ { 0x0001c61c, 0x00000000 },
+ { 0x0001c620, 0x00000000 },
+ { 0x0001c624, 0x00000061 },
+ { 0x0001c628, 0x00000041 },
+ { 0x0001c62c, 0x00000031 },
+ { 0x0001c630, 0x00000021 },
+ { 0x0001c634, 0x00000010 },
+ { 0x0001c638, 0x00000010 },
+ { 0x0001c63c, 0x00000000 },
+ { 0x0001c640, 0x06d32806 },
+ { 0x0001c644, 0x05532208 },
+ { 0x0001c648, 0x0413120a },
+ { 0x0001c64c, 0x0312f80d },
+ { 0x0001c650, 0x0242d310 },
+ { 0x0001c654, 0x01a2a614 },
+ { 0x0001c658, 0x01327117 },
+ { 0x0001c65c, 0x00d2361b },
+ { 0x0001c660, 0x0091f81f },
+ { 0x0001c664, 0x0b923600 },
+ { 0x0001c668, 0x07b27101 },
+ { 0x0001c66c, 0x0402a601 },
+ { 0x0001c670, 0x00a2d302 },
+ { 0x0001c674, 0x0da2f803 },
+ { 0x0001c678, 0x0af31204 },
+ { 0x0001c67c, 0x08b32205 },
+ { 0x0001c680, 0x0d000000 },
+ { 0x0001c684, 0x0b000000 },
+ { 0x0001c688, 0x0f001000 },
+ { 0x0001c68c, 0x0a001000 },
+ { 0x0001c690, 0x0a002000 },
+ { 0x0001c694, 0x00003000 },
+ { 0x0001c698, 0x0b004000 },
+ { 0x0001c69c, 0x09006000 },
+ { 0x0001c6a0, 0x08009000 },
+ { 0x0001c6a4, 0x0d000000 },
+ { 0x0001c6a8, 0x03000000 },
+ { 0x0001c6ac, 0x0a000000 },
+ { 0x0001c6b0, 0x04000000 },
+ { 0x0001c6b4, 0x01000000 },
+ { 0x0001c6b8, 0x01000000 },
+ { 0x0001c6bc, 0x05000000 },
+
+ { 0x0001c480, 0x00000000 },
+ { 0x0001c484, 0x00000000 },
+ { 0x0001c488, 0x00000000 },
+ { 0x0001c48c, 0x00000000 },
+ { 0x0001c490, 0x00000000 },
+ { 0x0001c494, 0x00000000 },
+ { 0x0001c498, 0x00000000 },
+ { 0x0001c49c, 0x00000000 },
+ { 0x0001c4a0, 0x00000000 },
+ { 0x0001c4a4, 0x00000061 },
+ { 0x0001c4a8, 0x00000041 },
+ { 0x0001c4ac, 0x00000031 },
+ { 0x0001c4b0, 0x00000021 },
+ { 0x0001c4b4, 0x00000010 },
+ { 0x0001c4b8, 0x00000010 },
+ { 0x0001c4bc, 0x00000000 },
+ { 0x0001c4c0, 0x06d32806 },
+ { 0x0001c4c4, 0x05532208 },
+ { 0x0001c4c8, 0x0413120a },
+ { 0x0001c4cc, 0x0312f80d },
+ { 0x0001c4d0, 0x0242d310 },
+ { 0x0001c4d4, 0x01a2a614 },
+ { 0x0001c4d8, 0x01327117 },
+ { 0x0001c4dc, 0x00d2361b },
+ { 0x0001c4e0, 0x0091f81f },
+ { 0x0001c4e4, 0x0b923600 },
+ { 0x0001c4e8, 0x07b27101 },
+ { 0x0001c4ec, 0x0402a601 },
+ { 0x0001c4f0, 0x00a2d302 },
+ { 0x0001c4f4, 0x0da2f803 },
+ { 0x0001c4f8, 0x0af31204 },
+ { 0x0001c4fc, 0x08b32205 },
+ { 0x0001c500, 0x0d000000 },
+ { 0x0001c504, 0x0b000000 },
+ { 0x0001c508, 0x0f001000 },
+ { 0x0001c50c, 0x0a001000 },
+ { 0x0001c510, 0x0a002000 },
+ { 0x0001c514, 0x00003000 },
+ { 0x0001c518, 0x0b004000 },
+ { 0x0001c51c, 0x09006000 },
+ { 0x0001c520, 0x08009000 },
+ { 0x0001c524, 0x0d000000 },
+ { 0x0001c528, 0x03000000 },
+ { 0x0001c52c, 0x0a000000 },
+ { 0x0001c530, 0x04000000 },
+ { 0x0001c534, 0x01000000 },
+ { 0x0001c538, 0x01000000 },
+ { 0x0001c53c, 0x05000000 },
+ { 0x0001c40c, 0x00000000 },
+ { 0x0001c424, 0x0437077f },
+ { 0x0001c414, 0x00000002 },
+ { 0x0001c420, 0x0437077f },
+ { 0x0001c464, 0x00001000 },
+ { 0x0001c460, 0x00000000 },
+ { 0x0001c454, 0x00002000 },
+ { 0x0001c450, 0x00000000 },
+ { 0x0001c444, 0x00000000 },
+ { 0x0001c438, 0x00000000 },
+ { 0x0001c43c, 0x00000000 },
+ { 0x0001c440, 0x00000000 },
+ { 0x0001c41c, 0x021b03bf },
+ { 0x0001c410, 0x00000000 },
+ { 0x0001c408, 0x00000003 },
+ { 0x0001c434, 0x00000000 },
+ { 0x0001c428, 0x00000000 },
+ { 0x0001c42c, 0x00000000 },
+ { 0x0001c430, 0x00000000 },
+ { 0x0001c418, 0x0437077f },
+ { 0x0001c45c, 0x00001000 },
+ { 0x0001c458, 0xfffff800 },
+ { 0x0001c44c, 0x00002000 },
+ { 0x0001c448, 0x00000000 },
+};
+
+struct data_unit hdr10_pipe1_lut_a0[] = {
+ { 0x00000000, 0x00000000 },
+ { 0x00000004, 0x00000003 },
+ { 0x00000008, 0x00000007 },
+ { 0x0000000c, 0x0000000a },
+ { 0x00000010, 0x0000000e },
+ { 0x00000014, 0x00000011 },
+ { 0x00000018, 0x00000015 },
+ { 0x0000001c, 0x00000018 },
+ { 0x00000020, 0x0000001c },
+ { 0x00000024, 0x00000020 },
+ { 0x00000028, 0x00000023 },
+ { 0x0000002c, 0x00000027 },
+ { 0x00000030, 0x0000002a },
+ { 0x00000034, 0x0000002e },
+ { 0x00000038, 0x00000031 },
+ { 0x0000003c, 0x00000035 },
+ { 0x00000040, 0x00000038 },
+ { 0x00000044, 0x0000003c },
+ { 0x00000048, 0x00000040 },
+ { 0x0000004c, 0x00000043 },
+ { 0x00000050, 0x00000047 },
+ { 0x00000054, 0x0000004a },
+ { 0x00000058, 0x0000004e },
+ { 0x0000005c, 0x00000051 },
+ { 0x00000060, 0x00000055 },
+ { 0x00000064, 0x00000058 },
+ { 0x00000068, 0x0000005c },
+ { 0x0000006c, 0x00000060 },
+ { 0x00000070, 0x00000063 },
+ { 0x00000074, 0x00000067 },
+ { 0x00000078, 0x0000006a },
+ { 0x0000007c, 0x0000006e },
+ { 0x00000080, 0x00000071 },
+ { 0x00000084, 0x00000075 },
+ { 0x00000088, 0x00000078 },
+ { 0x0000008c, 0x0000007c },
+ { 0x00000090, 0x00000080 },
+ { 0x00000094, 0x00000083 },
+ { 0x00000098, 0x00000087 },
+ { 0x0000009c, 0x0000008a },
+ { 0x000000a0, 0x0000008e },
+ { 0x000000a4, 0x00000091 },
+ { 0x000000a8, 0x00000095 },
+ { 0x000000ac, 0x00000099 },
+ { 0x000000b0, 0x0000009c },
+ { 0x000000b4, 0x000000a0 },
+ { 0x000000b8, 0x000000a3 },
+ { 0x000000bc, 0x000000a7 },
+ { 0x000000c0, 0x000000aa },
+ { 0x000000c4, 0x000000ae },
+ { 0x000000c8, 0x000000b1 },
+ { 0x000000cc, 0x000000b5 },
+ { 0x000000d0, 0x000000b9 },
+ { 0x000000d4, 0x000000bc },
+ { 0x000000d8, 0x000000c0 },
+ { 0x000000dc, 0x000000c3 },
+ { 0x000000e0, 0x000000c7 },
+ { 0x000000e4, 0x000000ca },
+ { 0x000000e8, 0x000000ce },
+ { 0x000000ec, 0x000000d1 },
+ { 0x000000f0, 0x000000d5 },
+ { 0x000000f4, 0x000000d9 },
+ { 0x000000f8, 0x000000dc },
+ { 0x000000fc, 0x000000e0 },
+ { 0x00000100, 0x000000e3 },
+ { 0x00000104, 0x000000e7 },
+ { 0x00000108, 0x000000ea },
+ { 0x0000010c, 0x000000ee },
+ { 0x00000110, 0x000000f1 },
+ { 0x00000114, 0x000000f5 },
+ { 0x00000118, 0x000000f9 },
+ { 0x0000011c, 0x000000fc },
+ { 0x00000120, 0x00000100 },
+ { 0x00000124, 0x00000103 },
+ { 0x00000128, 0x00000107 },
+ { 0x0000012c, 0x0000010a },
+ { 0x00000130, 0x0000010e },
+ { 0x00000134, 0x00000112 },
+ { 0x00000138, 0x00000115 },
+ { 0x0000013c, 0x00000119 },
+ { 0x00000140, 0x0000011c },
+ { 0x00000144, 0x00000120 },
+ { 0x00000148, 0x00000123 },
+ { 0x0000014c, 0x00000126 },
+ { 0x00000150, 0x0000012a },
+ { 0x00000154, 0x0000012d },
+ { 0x00000158, 0x00000131 },
+ { 0x0000015c, 0x00000134 },
+ { 0x00000160, 0x00000138 },
+ { 0x00000164, 0x0000013c },
+ { 0x00000168, 0x0000013f },
+ { 0x0000016c, 0x00000143 },
+ { 0x00000170, 0x00000147 },
+ { 0x00000174, 0x0000014b },
+ { 0x00000178, 0x0000014e },
+ { 0x0000017c, 0x00000152 },
+ { 0x00000180, 0x00000156 },
+ { 0x00000184, 0x0000015a },
+ { 0x00000188, 0x0000015e },
+ { 0x0000018c, 0x00000162 },
+ { 0x00000190, 0x00000166 },
+ { 0x00000194, 0x0000016a },
+ { 0x00000198, 0x0000016e },
+ { 0x0000019c, 0x00000172 },
+ { 0x000001a0, 0x00000176 },
+ { 0x000001a4, 0x0000017a },
+ { 0x000001a8, 0x0000017e },
+ { 0x000001ac, 0x00000182 },
+ { 0x000001b0, 0x00000186 },
+ { 0x000001b4, 0x0000018a },
+ { 0x000001b8, 0x0000018f },
+ { 0x000001bc, 0x00000193 },
+ { 0x000001c0, 0x00000197 },
+ { 0x000001c4, 0x0000019b },
+ { 0x000001c8, 0x000001a0 },
+ { 0x000001cc, 0x000001a4 },
+ { 0x000001d0, 0x000001a8 },
+ { 0x000001d4, 0x000001ad },
+ { 0x000001d8, 0x000001b1 },
+ { 0x000001dc, 0x000001b5 },
+ { 0x000001e0, 0x000001ba },
+ { 0x000001e4, 0x000001be },
+ { 0x000001e8, 0x000001c3 },
+ { 0x000001ec, 0x000001c7 },
+ { 0x000001f0, 0x000001cc },
+ { 0x000001f4, 0x000001d0 },
+ { 0x000001f8, 0x000001d5 },
+ { 0x000001fc, 0x000001d9 },
+ { 0x00000200, 0x000001de },
+ { 0x00000204, 0x000001e3 },
+ { 0x00000208, 0x000001e7 },
+ { 0x0000020c, 0x000001ec },
+ { 0x00000210, 0x000001f1 },
+ { 0x00000214, 0x000001f6 },
+ { 0x00000218, 0x000001fa },
+ { 0x0000021c, 0x000001ff },
+ { 0x00000220, 0x00000204 },
+ { 0x00000224, 0x00000209 },
+ { 0x00000228, 0x0000020e },
+ { 0x0000022c, 0x00000213 },
+ { 0x00000230, 0x00000217 },
+ { 0x00000234, 0x0000021c },
+ { 0x00000238, 0x00000221 },
+ { 0x0000023c, 0x00000226 },
+ { 0x00000240, 0x0000022b },
+ { 0x00000244, 0x00000230 },
+ { 0x00000248, 0x00000236 },
+ { 0x0000024c, 0x0000023b },
+ { 0x00000250, 0x00000240 },
+ { 0x00000254, 0x00000245 },
+ { 0x00000258, 0x0000024a },
+ { 0x0000025c, 0x0000024f },
+ { 0x00000260, 0x00000255 },
+ { 0x00000264, 0x0000025a },
+ { 0x00000268, 0x0000025f },
+ { 0x0000026c, 0x00000264 },
+ { 0x00000270, 0x0000026a },
+ { 0x00000274, 0x0000026f },
+ { 0x00000278, 0x00000274 },
+ { 0x0000027c, 0x0000027a },
+ { 0x00000280, 0x0000027f },
+ { 0x00000284, 0x00000285 },
+ { 0x00000288, 0x0000028a },
+ { 0x0000028c, 0x00000290 },
+ { 0x00000290, 0x00000295 },
+ { 0x00000294, 0x0000029b },
+ { 0x00000298, 0x000002a0 },
+ { 0x0000029c, 0x000002a6 },
+ { 0x000002a0, 0x000002ac },
+ { 0x000002a4, 0x000002b1 },
+ { 0x000002a8, 0x000002b7 },
+ { 0x000002ac, 0x000002bd },
+ { 0x000002b0, 0x000002c2 },
+ { 0x000002b4, 0x000002c8 },
+ { 0x000002b8, 0x000002ce },
+ { 0x000002bc, 0x000002d4 },
+ { 0x000002c0, 0x000002da },
+ { 0x000002c4, 0x000002df },
+ { 0x000002c8, 0x000002e5 },
+ { 0x000002cc, 0x000002eb },
+ { 0x000002d0, 0x000002f1 },
+ { 0x000002d4, 0x000002f7 },
+ { 0x000002d8, 0x000002fd },
+ { 0x000002dc, 0x00000303 },
+ { 0x000002e0, 0x00000309 },
+ { 0x000002e4, 0x0000030f },
+ { 0x000002e8, 0x00000315 },
+ { 0x000002ec, 0x0000031c },
+ { 0x000002f0, 0x00000322 },
+ { 0x000002f4, 0x00000328 },
+ { 0x000002f8, 0x0000032e },
+ { 0x000002fc, 0x00000334 },
+ { 0x00000300, 0x0000033b },
+ { 0x00000304, 0x00000341 },
+ { 0x00000308, 0x00000347 },
+ { 0x0000030c, 0x0000034d },
+ { 0x00000310, 0x00000354 },
+ { 0x00000314, 0x0000035a },
+ { 0x00000318, 0x00000361 },
+ { 0x0000031c, 0x00000367 },
+ { 0x00000320, 0x0000036d },
+ { 0x00000324, 0x00000374 },
+ { 0x00000328, 0x0000037a },
+ { 0x0000032c, 0x00000381 },
+ { 0x00000330, 0x00000388 },
+ { 0x00000334, 0x0000038e },
+ { 0x00000338, 0x00000395 },
+ { 0x0000033c, 0x0000039b },
+ { 0x00000340, 0x000003a2 },
+ { 0x00000344, 0x000003a9 },
+ { 0x00000348, 0x000003b0 },
+ { 0x0000034c, 0x000003b6 },
+ { 0x00000350, 0x000003bd },
+ { 0x00000354, 0x000003c4 },
+ { 0x00000358, 0x000003cb },
+ { 0x0000035c, 0x000003d2 },
+ { 0x00000360, 0x000003d8 },
+ { 0x00000364, 0x000003df },
+ { 0x00000368, 0x000003e6 },
+ { 0x0000036c, 0x000003ed },
+ { 0x00000370, 0x000003f4 },
+ { 0x00000374, 0x000003fb },
+ { 0x00000378, 0x00000402 },
+ { 0x0000037c, 0x00000409 },
+ { 0x00000380, 0x00000411 },
+ { 0x00000384, 0x00000418 },
+ { 0x00000388, 0x0000041f },
+ { 0x0000038c, 0x00000426 },
+ { 0x00000390, 0x0000042d },
+ { 0x00000394, 0x00000434 },
+ { 0x00000398, 0x0000043c },
+ { 0x0000039c, 0x00000443 },
+ { 0x000003a0, 0x0000044a },
+ { 0x000003a4, 0x00000452 },
+ { 0x000003a8, 0x00000459 },
+ { 0x000003ac, 0x00000460 },
+ { 0x000003b0, 0x00000468 },
+ { 0x000003b4, 0x0000046f },
+ { 0x000003b8, 0x00000477 },
+ { 0x000003bc, 0x0000047e },
+ { 0x000003c0, 0x00000486 },
+ { 0x000003c4, 0x0000048d },
+ { 0x000003c8, 0x00000495 },
+ { 0x000003cc, 0x0000049c },
+ { 0x000003d0, 0x000004a4 },
+ { 0x000003d4, 0x000004ac },
+ { 0x000003d8, 0x000004b3 },
+ { 0x000003dc, 0x000004bb },
+ { 0x000003e0, 0x000004c3 },
+ { 0x000003e4, 0x000004cb },
+ { 0x000003e8, 0x000004d3 },
+ { 0x000003ec, 0x000004da },
+ { 0x000003f0, 0x000004e2 },
+ { 0x000003f4, 0x000004ea },
+ { 0x000003f8, 0x000004f2 },
+ { 0x000003fc, 0x000004fa },
+ { 0x00000400, 0x00000502 },
+ { 0x00000404, 0x0000050a },
+ { 0x00000408, 0x00000512 },
+ { 0x0000040c, 0x0000051a },
+ { 0x00000410, 0x00000522 },
+ { 0x00000414, 0x0000052a },
+ { 0x00000418, 0x00000532 },
+ { 0x0000041c, 0x0000053a },
+ { 0x00000420, 0x00000543 },
+ { 0x00000424, 0x0000054b },
+ { 0x00000428, 0x00000553 },
+ { 0x0000042c, 0x0000055b },
+ { 0x00000430, 0x00000564 },
+ { 0x00000434, 0x0000056c },
+ { 0x00000438, 0x00000574 },
+ { 0x0000043c, 0x0000057d },
+ { 0x00000440, 0x00000585 },
+ { 0x00000444, 0x0000058d },
+ { 0x00000448, 0x00000596 },
+ { 0x0000044c, 0x0000059e },
+ { 0x00000450, 0x000005a7 },
+ { 0x00000454, 0x000005af },
+ { 0x00000458, 0x000005b8 },
+ { 0x0000045c, 0x000005c1 },
+ { 0x00000460, 0x000005c9 },
+ { 0x00000464, 0x000005d2 },
+ { 0x00000468, 0x000005db },
+ { 0x0000046c, 0x000005e3 },
+ { 0x00000470, 0x000005ec },
+ { 0x00000474, 0x000005f5 },
+ { 0x00000478, 0x000005fe },
+ { 0x0000047c, 0x00000606 },
+ { 0x00000480, 0x0000060f },
+ { 0x00000484, 0x00000618 },
+ { 0x00000488, 0x00000621 },
+ { 0x0000048c, 0x0000062a },
+ { 0x00000490, 0x00000633 },
+ { 0x00000494, 0x0000063c },
+ { 0x00000498, 0x00000645 },
+ { 0x0000049c, 0x0000064e },
+ { 0x000004a0, 0x00000657 },
+ { 0x000004a4, 0x00000660 },
+ { 0x000004a8, 0x00000669 },
+ { 0x000004ac, 0x00000672 },
+ { 0x000004b0, 0x0000067b },
+ { 0x000004b4, 0x00000685 },
+ { 0x000004b8, 0x0000068e },
+ { 0x000004bc, 0x00000697 },
+ { 0x000004c0, 0x000006a0 },
+ { 0x000004c4, 0x000006aa },
+ { 0x000004c8, 0x000006b3 },
+ { 0x000004cc, 0x000006bd },
+ { 0x000004d0, 0x000006c6 },
+ { 0x000004d4, 0x000006cf },
+ { 0x000004d8, 0x000006d9 },
+ { 0x000004dc, 0x000006e2 },
+ { 0x000004e0, 0x000006ec },
+ { 0x000004e4, 0x000006f5 },
+ { 0x000004e8, 0x000006ff },
+ { 0x000004ec, 0x00000709 },
+ { 0x000004f0, 0x00000712 },
+ { 0x000004f4, 0x0000071c },
+ { 0x000004f8, 0x00000726 },
+ { 0x000004fc, 0x0000072f },
+ { 0x00000500, 0x00000739 },
+ { 0x00000504, 0x00000743 },
+ { 0x00000508, 0x0000074d },
+ { 0x0000050c, 0x00000756 },
+ { 0x00000510, 0x00000760 },
+ { 0x00000514, 0x0000076a },
+ { 0x00000518, 0x00000774 },
+ { 0x0000051c, 0x0000077e },
+ { 0x00000520, 0x00000788 },
+ { 0x00000524, 0x00000792 },
+ { 0x00000528, 0x0000079c },
+ { 0x0000052c, 0x000007a6 },
+ { 0x00000530, 0x000007b0 },
+ { 0x00000534, 0x000007ba },
+ { 0x00000538, 0x000007c4 },
+ { 0x0000053c, 0x000007cf },
+ { 0x00000540, 0x000007d9 },
+ { 0x00000544, 0x000007e3 },
+ { 0x00000548, 0x000007ed },
+ { 0x0000054c, 0x000007f7 },
+ { 0x00000550, 0x00000802 },
+ { 0x00000554, 0x0000080c },
+ { 0x00000558, 0x00000816 },
+ { 0x0000055c, 0x00000821 },
+ { 0x00000560, 0x0000082b },
+ { 0x00000564, 0x00000836 },
+ { 0x00000568, 0x00000840 },
+ { 0x0000056c, 0x0000084b },
+ { 0x00000570, 0x00000855 },
+ { 0x00000574, 0x00000860 },
+ { 0x00000578, 0x0000086a },
+ { 0x0000057c, 0x00000875 },
+ { 0x00000580, 0x00000880 },
+ { 0x00000584, 0x0000088a },
+ { 0x00000588, 0x00000895 },
+ { 0x0000058c, 0x000008a0 },
+ { 0x00000590, 0x000008ab },
+ { 0x00000594, 0x000008b5 },
+ { 0x00000598, 0x000008c0 },
+ { 0x0000059c, 0x000008cb },
+ { 0x000005a0, 0x000008d6 },
+ { 0x000005a4, 0x000008e1 },
+ { 0x000005a8, 0x000008ec },
+ { 0x000005ac, 0x000008f7 },
+ { 0x000005b0, 0x00000902 },
+ { 0x000005b4, 0x0000090d },
+ { 0x000005b8, 0x00000918 },
+ { 0x000005bc, 0x00000923 },
+ { 0x000005c0, 0x0000092e },
+ { 0x000005c4, 0x00000939 },
+ { 0x000005c8, 0x00000944 },
+ { 0x000005cc, 0x00000950 },
+ { 0x000005d0, 0x0000095b },
+ { 0x000005d4, 0x00000966 },
+ { 0x000005d8, 0x00000971 },
+ { 0x000005dc, 0x0000097d },
+ { 0x000005e0, 0x00000988 },
+ { 0x000005e4, 0x00000993 },
+ { 0x000005e8, 0x0000099f },
+ { 0x000005ec, 0x000009aa },
+ { 0x000005f0, 0x000009b6 },
+ { 0x000005f4, 0x000009c1 },
+ { 0x000005f8, 0x000009cd },
+ { 0x000005fc, 0x000009d8 },
+ { 0x00000600, 0x000009e4 },
+ { 0x00000604, 0x000009f0 },
+ { 0x00000608, 0x000009fb },
+ { 0x0000060c, 0x00000a07 },
+ { 0x00000610, 0x00000a13 },
+ { 0x00000614, 0x00000a1e },
+ { 0x00000618, 0x00000a2a },
+ { 0x0000061c, 0x00000a36 },
+ { 0x00000620, 0x00000a42 },
+ { 0x00000624, 0x00000a4e },
+ { 0x00000628, 0x00000a59 },
+ { 0x0000062c, 0x00000a65 },
+ { 0x00000630, 0x00000a71 },
+ { 0x00000634, 0x00000a7d },
+ { 0x00000638, 0x00000a89 },
+ { 0x0000063c, 0x00000a95 },
+ { 0x00000640, 0x00000aa1 },
+ { 0x00000644, 0x00000aad },
+ { 0x00000648, 0x00000ab9 },
+ { 0x0000064c, 0x00000ac6 },
+ { 0x00000650, 0x00000ad2 },
+ { 0x00000654, 0x00000ade },
+ { 0x00000658, 0x00000aea },
+ { 0x0000065c, 0x00000af6 },
+ { 0x00000660, 0x00000b03 },
+ { 0x00000664, 0x00000b0f },
+ { 0x00000668, 0x00000b1b },
+ { 0x0000066c, 0x00000b28 },
+ { 0x00000670, 0x00000b34 },
+ { 0x00000674, 0x00000b41 },
+ { 0x00000678, 0x00000b4d },
+ { 0x0000067c, 0x00000b5a },
+ { 0x00000680, 0x00000b66 },
+ { 0x00000684, 0x00000b73 },
+ { 0x00000688, 0x00000b7f },
+ { 0x0000068c, 0x00000b8c },
+ { 0x00000690, 0x00000b98 },
+ { 0x00000694, 0x00000ba5 },
+ { 0x00000698, 0x00000bb2 },
+ { 0x0000069c, 0x00000bbf },
+ { 0x000006a0, 0x00000bcb },
+ { 0x000006a4, 0x00000bd8 },
+ { 0x000006a8, 0x00000be5 },
+ { 0x000006ac, 0x00000bf2 },
+ { 0x000006b0, 0x00000bff },
+ { 0x000006b4, 0x00000c0c },
+ { 0x000006b8, 0x00000c19 },
+ { 0x000006bc, 0x00000c25 },
+ { 0x000006c0, 0x00000c32 },
+ { 0x000006c4, 0x00000c40 },
+ { 0x000006c8, 0x00000c4d },
+ { 0x000006cc, 0x00000c5a },
+ { 0x000006d0, 0x00000c67 },
+ { 0x000006d4, 0x00000c74 },
+ { 0x000006d8, 0x00000c81 },
+ { 0x000006dc, 0x00000c8e },
+ { 0x000006e0, 0x00000c9c },
+ { 0x000006e4, 0x00000ca9 },
+ { 0x000006e8, 0x00000cb6 },
+ { 0x000006ec, 0x00000cc3 },
+ { 0x000006f0, 0x00000cd1 },
+ { 0x000006f4, 0x00000cde },
+ { 0x000006f8, 0x00000cec },
+ { 0x000006fc, 0x00000cf9 },
+ { 0x00000700, 0x00000d07 },
+ { 0x00000704, 0x00000d14 },
+ { 0x00000708, 0x00000d22 },
+ { 0x0000070c, 0x00000d2f },
+ { 0x00000710, 0x00000d3d },
+ { 0x00000714, 0x00000d4a },
+ { 0x00000718, 0x00000d58 },
+ { 0x0000071c, 0x00000d66 },
+ { 0x00000720, 0x00000d73 },
+ { 0x00000724, 0x00000d81 },
+ { 0x00000728, 0x00000d8f },
+ { 0x0000072c, 0x00000d9d },
+ { 0x00000730, 0x00000dab },
+ { 0x00000734, 0x00000db8 },
+ { 0x00000738, 0x00000dc6 },
+ { 0x0000073c, 0x00000dd4 },
+ { 0x00000740, 0x00000de2 },
+ { 0x00000744, 0x00000df0 },
+ { 0x00000748, 0x00000dfe },
+ { 0x0000074c, 0x00000e0c },
+ { 0x00000750, 0x00000e1a },
+ { 0x00000754, 0x00000e29 },
+ { 0x00000758, 0x00000e37 },
+ { 0x0000075c, 0x00000e45 },
+ { 0x00000760, 0x00000e53 },
+ { 0x00000764, 0x00000e61 },
+ { 0x00000768, 0x00000e70 },
+ { 0x0000076c, 0x00000e7e },
+ { 0x00000770, 0x00000e8c },
+ { 0x00000774, 0x00000e9a },
+ { 0x00000778, 0x00000ea9 },
+ { 0x0000077c, 0x00000eb7 },
+ { 0x00000780, 0x00000ec6 },
+ { 0x00000784, 0x00000ed4 },
+ { 0x00000788, 0x00000ee3 },
+ { 0x0000078c, 0x00000ef1 },
+ { 0x00000790, 0x00000f00 },
+ { 0x00000794, 0x00000f0e },
+ { 0x00000798, 0x00000f1d },
+ { 0x0000079c, 0x00000f2c },
+ { 0x000007a0, 0x00000f3a },
+ { 0x000007a4, 0x00000f49 },
+ { 0x000007a8, 0x00000f58 },
+ { 0x000007ac, 0x00000f67 },
+ { 0x000007b0, 0x00000f75 },
+ { 0x000007b4, 0x00000f84 },
+ { 0x000007b8, 0x00000f93 },
+ { 0x000007bc, 0x00000fa2 },
+ { 0x000007c0, 0x00000fb1 },
+ { 0x000007c4, 0x00000fc0 },
+ { 0x000007c8, 0x00000fcf },
+ { 0x000007cc, 0x00000fde },
+ { 0x000007d0, 0x00000fed },
+ { 0x000007d4, 0x00000ffc },
+ { 0x000007d8, 0x0000100b },
+ { 0x000007dc, 0x0000101a },
+ { 0x000007e0, 0x0000102a },
+ { 0x000007e4, 0x00001039 },
+ { 0x000007e8, 0x00001048 },
+ { 0x000007ec, 0x00001057 },
+ { 0x000007f0, 0x00001067 },
+ { 0x000007f4, 0x00001076 },
+ { 0x000007f8, 0x00001085 },
+ { 0x000007fc, 0x00001095 },
+ { 0x00000800, 0x000010a4 },
+ { 0x00000804, 0x000010b4 },
+ { 0x00000808, 0x000010c3 },
+ { 0x0000080c, 0x000010d3 },
+ { 0x00000810, 0x000010e2 },
+ { 0x00000814, 0x000010f2 },
+ { 0x00000818, 0x00001101 },
+ { 0x0000081c, 0x00001111 },
+ { 0x00000820, 0x00001121 },
+ { 0x00000824, 0x00001130 },
+ { 0x00000828, 0x00001140 },
+ { 0x0000082c, 0x00001150 },
+ { 0x00000830, 0x00001160 },
+ { 0x00000834, 0x0000116f },
+ { 0x00000838, 0x0000117f },
+ { 0x0000083c, 0x0000118f },
+ { 0x00000840, 0x0000119f },
+ { 0x00000844, 0x000011af },
+ { 0x00000848, 0x000011bf },
+ { 0x0000084c, 0x000011cf },
+ { 0x00000850, 0x000011df },
+ { 0x00000854, 0x000011ef },
+ { 0x00000858, 0x000011ff },
+ { 0x0000085c, 0x0000120f },
+ { 0x00000860, 0x0000121f },
+ { 0x00000864, 0x00001230 },
+ { 0x00000868, 0x00001240 },
+ { 0x0000086c, 0x00001250 },
+ { 0x00000870, 0x00001260 },
+ { 0x00000874, 0x00001271 },
+ { 0x00000878, 0x00001281 },
+ { 0x0000087c, 0x00001291 },
+ { 0x00000880, 0x000012a2 },
+ { 0x00000884, 0x000012b2 },
+ { 0x00000888, 0x000012c3 },
+ { 0x0000088c, 0x000012d3 },
+ { 0x00000890, 0x000012e4 },
+ { 0x00000894, 0x000012f4 },
+ { 0x00000898, 0x00001305 },
+ { 0x0000089c, 0x00001316 },
+ { 0x000008a0, 0x00001326 },
+ { 0x000008a4, 0x00001337 },
+ { 0x000008a8, 0x00001348 },
+ { 0x000008ac, 0x00001359 },
+ { 0x000008b0, 0x00001369 },
+ { 0x000008b4, 0x0000137a },
+ { 0x000008b8, 0x0000138b },
+ { 0x000008bc, 0x0000139c },
+ { 0x000008c0, 0x000013ad },
+ { 0x000008c4, 0x000013be },
+ { 0x000008c8, 0x000013cf },
+ { 0x000008cc, 0x000013e0 },
+ { 0x000008d0, 0x000013f1 },
+ { 0x000008d4, 0x00001402 },
+ { 0x000008d8, 0x00001413 },
+ { 0x000008dc, 0x00001424 },
+ { 0x000008e0, 0x00001435 },
+ { 0x000008e4, 0x00001446 },
+ { 0x000008e8, 0x00001458 },
+ { 0x000008ec, 0x00001469 },
+ { 0x000008f0, 0x0000147a },
+ { 0x000008f4, 0x0000148b },
+ { 0x000008f8, 0x0000149d },
+ { 0x000008fc, 0x000014ae },
+ { 0x00000900, 0x000014c0 },
+ { 0x00000904, 0x000014d1 },
+ { 0x00000908, 0x000014e3 },
+ { 0x0000090c, 0x000014f4 },
+ { 0x00000910, 0x00001506 },
+ { 0x00000914, 0x00001517 },
+ { 0x00000918, 0x00001529 },
+ { 0x0000091c, 0x0000153a },
+ { 0x00000920, 0x0000154c },
+ { 0x00000924, 0x0000155e },
+ { 0x00000928, 0x0000156f },
+ { 0x0000092c, 0x00001581 },
+ { 0x00000930, 0x00001593 },
+ { 0x00000934, 0x000015a5 },
+ { 0x00000938, 0x000015b7 },
+ { 0x0000093c, 0x000015c9 },
+ { 0x00000940, 0x000015db },
+ { 0x00000944, 0x000015ec },
+ { 0x00000948, 0x000015fe },
+ { 0x0000094c, 0x00001610 },
+ { 0x00000950, 0x00001623 },
+ { 0x00000954, 0x00001635 },
+ { 0x00000958, 0x00001647 },
+ { 0x0000095c, 0x00001659 },
+ { 0x00000960, 0x0000166b },
+ { 0x00000964, 0x0000167d },
+ { 0x00000968, 0x0000168f },
+ { 0x0000096c, 0x000016a2 },
+ { 0x00000970, 0x000016b4 },
+ { 0x00000974, 0x000016c6 },
+ { 0x00000978, 0x000016d9 },
+ { 0x0000097c, 0x000016eb },
+ { 0x00000980, 0x000016fe },
+ { 0x00000984, 0x00001710 },
+ { 0x00000988, 0x00001722 },
+ { 0x0000098c, 0x00001735 },
+ { 0x00000990, 0x00001748 },
+ { 0x00000994, 0x0000175a },
+ { 0x00000998, 0x0000176d },
+ { 0x0000099c, 0x0000177f },
+ { 0x000009a0, 0x00001792 },
+ { 0x000009a4, 0x000017a5 },
+ { 0x000009a8, 0x000017b8 },
+ { 0x000009ac, 0x000017ca },
+ { 0x000009b0, 0x000017dd },
+ { 0x000009b4, 0x000017f0 },
+ { 0x000009b8, 0x00001803 },
+ { 0x000009bc, 0x00001816 },
+ { 0x000009c0, 0x00001829 },
+ { 0x000009c4, 0x0000183c },
+ { 0x000009c8, 0x0000184f },
+ { 0x000009cc, 0x00001862 },
+ { 0x000009d0, 0x00001875 },
+ { 0x000009d4, 0x00001888 },
+ { 0x000009d8, 0x0000189b },
+ { 0x000009dc, 0x000018ae },
+ { 0x000009e0, 0x000018c1 },
+ { 0x000009e4, 0x000018d5 },
+ { 0x000009e8, 0x000018e8 },
+ { 0x000009ec, 0x000018fb },
+ { 0x000009f0, 0x0000190e },
+ { 0x000009f4, 0x00001922 },
+ { 0x000009f8, 0x00001935 },
+ { 0x000009fc, 0x00001949 },
+ { 0x00000a00, 0x0000195c },
+ { 0x00000a04, 0x0000196f },
+ { 0x00000a08, 0x00001983 },
+ { 0x00000a0c, 0x00001996 },
+ { 0x00000a10, 0x000019aa },
+ { 0x00000a14, 0x000019be },
+ { 0x00000a18, 0x000019d1 },
+ { 0x00000a1c, 0x000019e5 },
+ { 0x00000a20, 0x000019f9 },
+ { 0x00000a24, 0x00001a0c },
+ { 0x00000a28, 0x00001a20 },
+ { 0x00000a2c, 0x00001a34 },
+ { 0x00000a30, 0x00001a48 },
+ { 0x00000a34, 0x00001a5c },
+ { 0x00000a38, 0x00001a70 },
+ { 0x00000a3c, 0x00001a84 },
+ { 0x00000a40, 0x00001a97 },
+ { 0x00000a44, 0x00001aab },
+ { 0x00000a48, 0x00001ac0 },
+ { 0x00000a4c, 0x00001ad4 },
+ { 0x00000a50, 0x00001ae8 },
+ { 0x00000a54, 0x00001afc },
+ { 0x00000a58, 0x00001b10 },
+ { 0x00000a5c, 0x00001b24 },
+ { 0x00000a60, 0x00001b38 },
+ { 0x00000a64, 0x00001b4d },
+ { 0x00000a68, 0x00001b61 },
+ { 0x00000a6c, 0x00001b75 },
+ { 0x00000a70, 0x00001b8a },
+ { 0x00000a74, 0x00001b9e },
+ { 0x00000a78, 0x00001bb2 },
+ { 0x00000a7c, 0x00001bc7 },
+ { 0x00000a80, 0x00001bdb },
+ { 0x00000a84, 0x00001bf0 },
+ { 0x00000a88, 0x00001c04 },
+ { 0x00000a8c, 0x00001c19 },
+ { 0x00000a90, 0x00001c2e },
+ { 0x00000a94, 0x00001c42 },
+ { 0x00000a98, 0x00001c57 },
+ { 0x00000a9c, 0x00001c6c },
+ { 0x00000aa0, 0x00001c80 },
+ { 0x00000aa4, 0x00001c95 },
+ { 0x00000aa8, 0x00001caa },
+ { 0x00000aac, 0x00001cbf },
+ { 0x00000ab0, 0x00001cd4 },
+ { 0x00000ab4, 0x00001ce8 },
+ { 0x00000ab8, 0x00001cfd },
+ { 0x00000abc, 0x00001d12 },
+ { 0x00000ac0, 0x00001d27 },
+ { 0x00000ac4, 0x00001d3c },
+ { 0x00000ac8, 0x00001d51 },
+ { 0x00000acc, 0x00001d67 },
+ { 0x00000ad0, 0x00001d7c },
+ { 0x00000ad4, 0x00001d91 },
+ { 0x00000ad8, 0x00001da6 },
+ { 0x00000adc, 0x00001dbb },
+ { 0x00000ae0, 0x00001dd1 },
+ { 0x00000ae4, 0x00001de6 },
+ { 0x00000ae8, 0x00001dfb },
+ { 0x00000aec, 0x00001e10 },
+ { 0x00000af0, 0x00001e26 },
+ { 0x00000af4, 0x00001e3b },
+ { 0x00000af8, 0x00001e51 },
+ { 0x00000afc, 0x00001e66 },
+ { 0x00000b00, 0x00001e7c },
+ { 0x00000b04, 0x00001e91 },
+ { 0x00000b08, 0x00001ea7 },
+ { 0x00000b0c, 0x00001ebd },
+ { 0x00000b10, 0x00001ed2 },
+ { 0x00000b14, 0x00001ee8 },
+ { 0x00000b18, 0x00001efe },
+ { 0x00000b1c, 0x00001f13 },
+ { 0x00000b20, 0x00001f29 },
+ { 0x00000b24, 0x00001f3f },
+ { 0x00000b28, 0x00001f55 },
+ { 0x00000b2c, 0x00001f6b },
+ { 0x00000b30, 0x00001f81 },
+ { 0x00000b34, 0x00001f96 },
+ { 0x00000b38, 0x00001fac },
+ { 0x00000b3c, 0x00001fc2 },
+ { 0x00000b40, 0x00001fd9 },
+ { 0x00000b44, 0x00001fef },
+ { 0x00000b48, 0x00002005 },
+ { 0x00000b4c, 0x0000201b },
+ { 0x00000b50, 0x00002031 },
+ { 0x00000b54, 0x00002047 },
+ { 0x00000b58, 0x0000205d },
+ { 0x00000b5c, 0x00002074 },
+ { 0x00000b60, 0x0000208a },
+ { 0x00000b64, 0x000020a0 },
+ { 0x00000b68, 0x000020b7 },
+ { 0x00000b6c, 0x000020cd },
+ { 0x00000b70, 0x000020e4 },
+ { 0x00000b74, 0x000020fa },
+ { 0x00000b78, 0x00002111 },
+ { 0x00000b7c, 0x00002127 },
+ { 0x00000b80, 0x0000213e },
+ { 0x00000b84, 0x00002154 },
+ { 0x00000b88, 0x0000216b },
+ { 0x00000b8c, 0x00002182 },
+ { 0x00000b90, 0x00002198 },
+ { 0x00000b94, 0x000021af },
+ { 0x00000b98, 0x000021c6 },
+ { 0x00000b9c, 0x000021dd },
+ { 0x00000ba0, 0x000021f3 },
+ { 0x00000ba4, 0x0000220a },
+ { 0x00000ba8, 0x00002221 },
+ { 0x00000bac, 0x00002238 },
+ { 0x00000bb0, 0x0000224f },
+ { 0x00000bb4, 0x00002266 },
+ { 0x00000bb8, 0x0000227d },
+ { 0x00000bbc, 0x00002294 },
+ { 0x00000bc0, 0x000022ab },
+ { 0x00000bc4, 0x000022c2 },
+ { 0x00000bc8, 0x000022da },
+ { 0x00000bcc, 0x000022f1 },
+ { 0x00000bd0, 0x00002308 },
+ { 0x00000bd4, 0x0000231f },
+ { 0x00000bd8, 0x00002337 },
+ { 0x00000bdc, 0x0000234e },
+ { 0x00000be0, 0x00002365 },
+ { 0x00000be4, 0x0000237d },
+ { 0x00000be8, 0x00002394 },
+ { 0x00000bec, 0x000023ac },
+ { 0x00000bf0, 0x000023c3 },
+ { 0x00000bf4, 0x000023db },
+ { 0x00000bf8, 0x000023f2 },
+ { 0x00000bfc, 0x0000240a },
+ { 0x00000c00, 0x00002421 },
+ { 0x00000c04, 0x00002439 },
+ { 0x00000c08, 0x00002451 },
+ { 0x00000c0c, 0x00002469 },
+ { 0x00000c10, 0x00002480 },
+ { 0x00000c14, 0x00002498 },
+ { 0x00000c18, 0x000024b0 },
+ { 0x00000c1c, 0x000024c8 },
+ { 0x00000c20, 0x000024e0 },
+ { 0x00000c24, 0x000024f8 },
+ { 0x00000c28, 0x00002510 },
+ { 0x00000c2c, 0x00002528 },
+ { 0x00000c30, 0x00002540 },
+ { 0x00000c34, 0x00002558 },
+ { 0x00000c38, 0x00002570 },
+ { 0x00000c3c, 0x00002588 },
+ { 0x00000c40, 0x000025a0 },
+ { 0x00000c44, 0x000025b8 },
+ { 0x00000c48, 0x000025d0 },
+ { 0x00000c4c, 0x000025e9 },
+ { 0x00000c50, 0x00002601 },
+ { 0x00000c54, 0x00002619 },
+ { 0x00000c58, 0x00002632 },
+ { 0x00000c5c, 0x0000264a },
+ { 0x00000c60, 0x00002663 },
+ { 0x00000c64, 0x0000267b },
+ { 0x00000c68, 0x00002693 },
+ { 0x00000c6c, 0x000026ac },
+ { 0x00000c70, 0x000026c5 },
+ { 0x00000c74, 0x000026dd },
+ { 0x00000c78, 0x000026f6 },
+ { 0x00000c7c, 0x0000270e },
+ { 0x00000c80, 0x00002727 },
+ { 0x00000c84, 0x00002740 },
+ { 0x00000c88, 0x00002759 },
+ { 0x00000c8c, 0x00002771 },
+ { 0x00000c90, 0x0000278a },
+ { 0x00000c94, 0x000027a3 },
+ { 0x00000c98, 0x000027bc },
+ { 0x00000c9c, 0x000027d5 },
+ { 0x00000ca0, 0x000027ee },
+ { 0x00000ca4, 0x00002807 },
+ { 0x00000ca8, 0x00002820 },
+ { 0x00000cac, 0x00002839 },
+ { 0x00000cb0, 0x00002852 },
+ { 0x00000cb4, 0x0000286b },
+ { 0x00000cb8, 0x00002884 },
+ { 0x00000cbc, 0x0000289e },
+ { 0x00000cc0, 0x000028b7 },
+ { 0x00000cc4, 0x000028d0 },
+ { 0x00000cc8, 0x000028e9 },
+ { 0x00000ccc, 0x00002903 },
+ { 0x00000cd0, 0x0000291c },
+ { 0x00000cd4, 0x00002936 },
+ { 0x00000cd8, 0x0000294f },
+ { 0x00000cdc, 0x00002968 },
+ { 0x00000ce0, 0x00002982 },
+ { 0x00000ce4, 0x0000299c },
+ { 0x00000ce8, 0x000029b5 },
+ { 0x00000cec, 0x000029cf },
+ { 0x00000cf0, 0x000029e8 },
+ { 0x00000cf4, 0x00002a02 },
+ { 0x00000cf8, 0x00002a1c },
+ { 0x00000cfc, 0x00002a35 },
+ { 0x00000d00, 0x00002a4f },
+ { 0x00000d04, 0x00002a69 },
+ { 0x00000d08, 0x00002a83 },
+ { 0x00000d0c, 0x00002a9d },
+ { 0x00000d10, 0x00002ab7 },
+ { 0x00000d14, 0x00002ad1 },
+ { 0x00000d18, 0x00002aeb },
+ { 0x00000d1c, 0x00002b05 },
+ { 0x00000d20, 0x00002b1f },
+ { 0x00000d24, 0x00002b39 },
+ { 0x00000d28, 0x00002b53 },
+ { 0x00000d2c, 0x00002b6d },
+ { 0x00000d30, 0x00002b87 },
+ { 0x00000d34, 0x00002ba1 },
+ { 0x00000d38, 0x00002bbc },
+ { 0x00000d3c, 0x00002bd6 },
+ { 0x00000d40, 0x00002bf0 },
+ { 0x00000d44, 0x00002c0b },
+ { 0x00000d48, 0x00002c25 },
+ { 0x00000d4c, 0x00002c3f },
+ { 0x00000d50, 0x00002c5a },
+ { 0x00000d54, 0x00002c74 },
+ { 0x00000d58, 0x00002c8f },
+ { 0x00000d5c, 0x00002ca9 },
+ { 0x00000d60, 0x00002cc4 },
+ { 0x00000d64, 0x00002cdf },
+ { 0x00000d68, 0x00002cf9 },
+ { 0x00000d6c, 0x00002d14 },
+ { 0x00000d70, 0x00002d2f },
+ { 0x00000d74, 0x00002d49 },
+ { 0x00000d78, 0x00002d64 },
+ { 0x00000d7c, 0x00002d7f },
+ { 0x00000d80, 0x00002d9a },
+ { 0x00000d84, 0x00002db5 },
+ { 0x00000d88, 0x00002dd0 },
+ { 0x00000d8c, 0x00002deb },
+ { 0x00000d90, 0x00002e06 },
+ { 0x00000d94, 0x00002e21 },
+ { 0x00000d98, 0x00002e3c },
+ { 0x00000d9c, 0x00002e57 },
+ { 0x00000da0, 0x00002e72 },
+ { 0x00000da4, 0x00002e8d },
+ { 0x00000da8, 0x00002ea8 },
+ { 0x00000dac, 0x00002ec4 },
+ { 0x00000db0, 0x00002edf },
+ { 0x00000db4, 0x00002efa },
+ { 0x00000db8, 0x00002f16 },
+ { 0x00000dbc, 0x00002f31 },
+ { 0x00000dc0, 0x00002f4c },
+ { 0x00000dc4, 0x00002f68 },
+ { 0x00000dc8, 0x00002f83 },
+ { 0x00000dcc, 0x00002f9f },
+ { 0x00000dd0, 0x00002fba },
+ { 0x00000dd4, 0x00002fd6 },
+ { 0x00000dd8, 0x00002ff1 },
+ { 0x00000ddc, 0x0000300d },
+ { 0x00000de0, 0x00003029 },
+ { 0x00000de4, 0x00003044 },
+ { 0x00000de8, 0x00003060 },
+ { 0x00000dec, 0x0000307c },
+ { 0x00000df0, 0x00003098 },
+ { 0x00000df4, 0x000030b4 },
+ { 0x00000df8, 0x000030d0 },
+ { 0x00000dfc, 0x000030eb },
+ { 0x00000e00, 0x00003107 },
+ { 0x00000e04, 0x00003123 },
+ { 0x00000e08, 0x0000313f },
+ { 0x00000e0c, 0x0000315b },
+ { 0x00000e10, 0x00003178 },
+ { 0x00000e14, 0x00003194 },
+ { 0x00000e18, 0x000031b0 },
+ { 0x00000e1c, 0x000031cc },
+ { 0x00000e20, 0x000031e8 },
+ { 0x00000e24, 0x00003205 },
+ { 0x00000e28, 0x00003221 },
+ { 0x00000e2c, 0x0000323d },
+ { 0x00000e30, 0x0000325a },
+ { 0x00000e34, 0x00003276 },
+ { 0x00000e38, 0x00003292 },
+ { 0x00000e3c, 0x000032af },
+ { 0x00000e40, 0x000032cb },
+ { 0x00000e44, 0x000032e8 },
+ { 0x00000e48, 0x00003304 },
+ { 0x00000e4c, 0x00003321 },
+ { 0x00000e50, 0x0000333e },
+ { 0x00000e54, 0x0000335a },
+ { 0x00000e58, 0x00003377 },
+ { 0x00000e5c, 0x00003394 },
+ { 0x00000e60, 0x000033b1 },
+ { 0x00000e64, 0x000033cd },
+ { 0x00000e68, 0x000033ea },
+ { 0x00000e6c, 0x00003407 },
+ { 0x00000e70, 0x00003424 },
+ { 0x00000e74, 0x00003441 },
+ { 0x00000e78, 0x0000345e },
+ { 0x00000e7c, 0x0000347b },
+ { 0x00000e80, 0x00003498 },
+ { 0x00000e84, 0x000034b5 },
+ { 0x00000e88, 0x000034d2 },
+ { 0x00000e8c, 0x000034ef },
+ { 0x00000e90, 0x0000350d },
+ { 0x00000e94, 0x0000352a },
+ { 0x00000e98, 0x00003547 },
+ { 0x00000e9c, 0x00003564 },
+ { 0x00000ea0, 0x00003582 },
+ { 0x00000ea4, 0x0000359f },
+ { 0x00000ea8, 0x000035bc },
+ { 0x00000eac, 0x000035da },
+ { 0x00000eb0, 0x000035f7 },
+ { 0x00000eb4, 0x00003615 },
+ { 0x00000eb8, 0x00003632 },
+ { 0x00000ebc, 0x00003650 },
+ { 0x00000ec0, 0x0000366e },
+ { 0x00000ec4, 0x0000368b },
+ { 0x00000ec8, 0x000036a9 },
+ { 0x00000ecc, 0x000036c7 },
+ { 0x00000ed0, 0x000036e4 },
+ { 0x00000ed4, 0x00003702 },
+ { 0x00000ed8, 0x00003720 },
+ { 0x00000edc, 0x0000373e },
+ { 0x00000ee0, 0x0000375c },
+ { 0x00000ee4, 0x0000377a },
+ { 0x00000ee8, 0x00003798 },
+ { 0x00000eec, 0x000037b6 },
+ { 0x00000ef0, 0x000037d4 },
+ { 0x00000ef4, 0x000037f2 },
+ { 0x00000ef8, 0x00003810 },
+ { 0x00000efc, 0x0000382e },
+ { 0x00000f00, 0x0000384c },
+ { 0x00000f04, 0x0000386a },
+ { 0x00000f08, 0x00003888 },
+ { 0x00000f0c, 0x000038a7 },
+ { 0x00000f10, 0x000038c5 },
+ { 0x00000f14, 0x000038e3 },
+ { 0x00000f18, 0x00003902 },
+ { 0x00000f1c, 0x00003920 },
+ { 0x00000f20, 0x0000393f },
+ { 0x00000f24, 0x0000395d },
+ { 0x00000f28, 0x0000397c },
+ { 0x00000f2c, 0x0000399a },
+ { 0x00000f30, 0x000039b9 },
+ { 0x00000f34, 0x000039d7 },
+ { 0x00000f38, 0x000039f6 },
+ { 0x00000f3c, 0x00003a15 },
+ { 0x00000f40, 0x00003a33 },
+ { 0x00000f44, 0x00003a52 },
+ { 0x00000f48, 0x00003a71 },
+ { 0x00000f4c, 0x00003a90 },
+ { 0x00000f50, 0x00003aaf },
+ { 0x00000f54, 0x00003acd },
+ { 0x00000f58, 0x00003aec },
+ { 0x00000f5c, 0x00003b0b },
+ { 0x00000f60, 0x00003b2a },
+ { 0x00000f64, 0x00003b49 },
+ { 0x00000f68, 0x00003b68 },
+ { 0x00000f6c, 0x00003b87 },
+ { 0x00000f70, 0x00003ba7 },
+ { 0x00000f74, 0x00003bc6 },
+ { 0x00000f78, 0x00003be5 },
+ { 0x00000f7c, 0x00003c04 },
+ { 0x00000f80, 0x00003c24 },
+ { 0x00000f84, 0x00003c43 },
+ { 0x00000f88, 0x00003c62 },
+ { 0x00000f8c, 0x00003c82 },
+ { 0x00000f90, 0x00003ca1 },
+ { 0x00000f94, 0x00003cc0 },
+ { 0x00000f98, 0x00003ce0 },
+ { 0x00000f9c, 0x00003cff },
+ { 0x00000fa0, 0x00003d1f },
+ { 0x00000fa4, 0x00003d3f },
+ { 0x00000fa8, 0x00003d5e },
+ { 0x00000fac, 0x00003d7e },
+ { 0x00000fb0, 0x00003d9e },
+ { 0x00000fb4, 0x00003dbd },
+ { 0x00000fb8, 0x00003ddd },
+ { 0x00000fbc, 0x00003dfd },
+ { 0x00000fc0, 0x00003e1d },
+ { 0x00000fc4, 0x00003e3d },
+ { 0x00000fc8, 0x00003e5d },
+ { 0x00000fcc, 0x00003e7c },
+ { 0x00000fd0, 0x00003e9c },
+ { 0x00000fd4, 0x00003ebc },
+ { 0x00000fd8, 0x00003edc },
+ { 0x00000fdc, 0x00003efd },
+ { 0x00000fe0, 0x00003f1d },
+ { 0x00000fe4, 0x00003f3d },
+ { 0x00000fe8, 0x00003f5d },
+ { 0x00000fec, 0x00003f7d },
+ { 0x00000ff0, 0x00003f9e },
+ { 0x00000ff4, 0x00003fbe },
+ { 0x00000ff8, 0x00003fde },
+ { 0x00000ffc, 0x00003fff },
+};
+
+struct data_unit hdr10_pipe1_lut_a1[] = {
+ { 0x00001000, 0x00000000 },
+ { 0x00001004, 0x00000003 },
+ { 0x00001008, 0x00000007 },
+ { 0x0000100c, 0x0000000a },
+ { 0x00001010, 0x0000000e },
+ { 0x00001014, 0x00000011 },
+ { 0x00001018, 0x00000015 },
+ { 0x0000101c, 0x00000018 },
+ { 0x00001020, 0x0000001c },
+ { 0x00001024, 0x00000020 },
+ { 0x00001028, 0x00000023 },
+ { 0x0000102c, 0x00000027 },
+ { 0x00001030, 0x0000002a },
+ { 0x00001034, 0x0000002e },
+ { 0x00001038, 0x00000031 },
+ { 0x0000103c, 0x00000035 },
+ { 0x00001040, 0x00000038 },
+ { 0x00001044, 0x0000003c },
+ { 0x00001048, 0x00000040 },
+ { 0x0000104c, 0x00000043 },
+ { 0x00001050, 0x00000047 },
+ { 0x00001054, 0x0000004a },
+ { 0x00001058, 0x0000004e },
+ { 0x0000105c, 0x00000051 },
+ { 0x00001060, 0x00000055 },
+ { 0x00001064, 0x00000058 },
+ { 0x00001068, 0x0000005c },
+ { 0x0000106c, 0x00000060 },
+ { 0x00001070, 0x00000063 },
+ { 0x00001074, 0x00000067 },
+ { 0x00001078, 0x0000006a },
+ { 0x0000107c, 0x0000006e },
+ { 0x00001080, 0x00000071 },
+ { 0x00001084, 0x00000075 },
+ { 0x00001088, 0x00000078 },
+ { 0x0000108c, 0x0000007c },
+ { 0x00001090, 0x00000080 },
+ { 0x00001094, 0x00000083 },
+ { 0x00001098, 0x00000087 },
+ { 0x0000109c, 0x0000008a },
+ { 0x000010a0, 0x0000008e },
+ { 0x000010a4, 0x00000091 },
+ { 0x000010a8, 0x00000095 },
+ { 0x000010ac, 0x00000099 },
+ { 0x000010b0, 0x0000009c },
+ { 0x000010b4, 0x000000a0 },
+ { 0x000010b8, 0x000000a3 },
+ { 0x000010bc, 0x000000a7 },
+ { 0x000010c0, 0x000000aa },
+ { 0x000010c4, 0x000000ae },
+ { 0x000010c8, 0x000000b1 },
+ { 0x000010cc, 0x000000b5 },
+ { 0x000010d0, 0x000000b9 },
+ { 0x000010d4, 0x000000bc },
+ { 0x000010d8, 0x000000c0 },
+ { 0x000010dc, 0x000000c3 },
+ { 0x000010e0, 0x000000c7 },
+ { 0x000010e4, 0x000000ca },
+ { 0x000010e8, 0x000000ce },
+ { 0x000010ec, 0x000000d1 },
+ { 0x000010f0, 0x000000d5 },
+ { 0x000010f4, 0x000000d9 },
+ { 0x000010f8, 0x000000dc },
+ { 0x000010fc, 0x000000e0 },
+ { 0x00001100, 0x000000e3 },
+ { 0x00001104, 0x000000e7 },
+ { 0x00001108, 0x000000ea },
+ { 0x0000110c, 0x000000ee },
+ { 0x00001110, 0x000000f1 },
+ { 0x00001114, 0x000000f5 },
+ { 0x00001118, 0x000000f9 },
+ { 0x0000111c, 0x000000fc },
+ { 0x00001120, 0x00000100 },
+ { 0x00001124, 0x00000103 },
+ { 0x00001128, 0x00000107 },
+ { 0x0000112c, 0x0000010a },
+ { 0x00001130, 0x0000010e },
+ { 0x00001134, 0x00000112 },
+ { 0x00001138, 0x00000115 },
+ { 0x0000113c, 0x00000119 },
+ { 0x00001140, 0x0000011c },
+ { 0x00001144, 0x00000120 },
+ { 0x00001148, 0x00000123 },
+ { 0x0000114c, 0x00000126 },
+ { 0x00001150, 0x0000012a },
+ { 0x00001154, 0x0000012d },
+ { 0x00001158, 0x00000131 },
+ { 0x0000115c, 0x00000134 },
+ { 0x00001160, 0x00000138 },
+ { 0x00001164, 0x0000013c },
+ { 0x00001168, 0x0000013f },
+ { 0x0000116c, 0x00000143 },
+ { 0x00001170, 0x00000147 },
+ { 0x00001174, 0x0000014b },
+ { 0x00001178, 0x0000014e },
+ { 0x0000117c, 0x00000152 },
+ { 0x00001180, 0x00000156 },
+ { 0x00001184, 0x0000015a },
+ { 0x00001188, 0x0000015e },
+ { 0x0000118c, 0x00000162 },
+ { 0x00001190, 0x00000166 },
+ { 0x00001194, 0x0000016a },
+ { 0x00001198, 0x0000016e },
+ { 0x0000119c, 0x00000172 },
+ { 0x000011a0, 0x00000176 },
+ { 0x000011a4, 0x0000017a },
+ { 0x000011a8, 0x0000017e },
+ { 0x000011ac, 0x00000182 },
+ { 0x000011b0, 0x00000186 },
+ { 0x000011b4, 0x0000018a },
+ { 0x000011b8, 0x0000018f },
+ { 0x000011bc, 0x00000193 },
+ { 0x000011c0, 0x00000197 },
+ { 0x000011c4, 0x0000019b },
+ { 0x000011c8, 0x000001a0 },
+ { 0x000011cc, 0x000001a4 },
+ { 0x000011d0, 0x000001a8 },
+ { 0x000011d4, 0x000001ad },
+ { 0x000011d8, 0x000001b1 },
+ { 0x000011dc, 0x000001b5 },
+ { 0x000011e0, 0x000001ba },
+ { 0x000011e4, 0x000001be },
+ { 0x000011e8, 0x000001c3 },
+ { 0x000011ec, 0x000001c7 },
+ { 0x000011f0, 0x000001cc },
+ { 0x000011f4, 0x000001d0 },
+ { 0x000011f8, 0x000001d5 },
+ { 0x000011fc, 0x000001d9 },
+ { 0x00001200, 0x000001de },
+ { 0x00001204, 0x000001e3 },
+ { 0x00001208, 0x000001e7 },
+ { 0x0000120c, 0x000001ec },
+ { 0x00001210, 0x000001f1 },
+ { 0x00001214, 0x000001f6 },
+ { 0x00001218, 0x000001fa },
+ { 0x0000121c, 0x000001ff },
+ { 0x00001220, 0x00000204 },
+ { 0x00001224, 0x00000209 },
+ { 0x00001228, 0x0000020e },
+ { 0x0000122c, 0x00000213 },
+ { 0x00001230, 0x00000217 },
+ { 0x00001234, 0x0000021c },
+ { 0x00001238, 0x00000221 },
+ { 0x0000123c, 0x00000226 },
+ { 0x00001240, 0x0000022b },
+ { 0x00001244, 0x00000230 },
+ { 0x00001248, 0x00000236 },
+ { 0x0000124c, 0x0000023b },
+ { 0x00001250, 0x00000240 },
+ { 0x00001254, 0x00000245 },
+ { 0x00001258, 0x0000024a },
+ { 0x0000125c, 0x0000024f },
+ { 0x00001260, 0x00000255 },
+ { 0x00001264, 0x0000025a },
+ { 0x00001268, 0x0000025f },
+ { 0x0000126c, 0x00000264 },
+ { 0x00001270, 0x0000026a },
+ { 0x00001274, 0x0000026f },
+ { 0x00001278, 0x00000274 },
+ { 0x0000127c, 0x0000027a },
+ { 0x00001280, 0x0000027f },
+ { 0x00001284, 0x00000285 },
+ { 0x00001288, 0x0000028a },
+ { 0x0000128c, 0x00000290 },
+ { 0x00001290, 0x00000295 },
+ { 0x00001294, 0x0000029b },
+ { 0x00001298, 0x000002a0 },
+ { 0x0000129c, 0x000002a6 },
+ { 0x000012a0, 0x000002ac },
+ { 0x000012a4, 0x000002b1 },
+ { 0x000012a8, 0x000002b7 },
+ { 0x000012ac, 0x000002bd },
+ { 0x000012b0, 0x000002c2 },
+ { 0x000012b4, 0x000002c8 },
+ { 0x000012b8, 0x000002ce },
+ { 0x000012bc, 0x000002d4 },
+ { 0x000012c0, 0x000002da },
+ { 0x000012c4, 0x000002df },
+ { 0x000012c8, 0x000002e5 },
+ { 0x000012cc, 0x000002eb },
+ { 0x000012d0, 0x000002f1 },
+ { 0x000012d4, 0x000002f7 },
+ { 0x000012d8, 0x000002fd },
+ { 0x000012dc, 0x00000303 },
+ { 0x000012e0, 0x00000309 },
+ { 0x000012e4, 0x0000030f },
+ { 0x000012e8, 0x00000315 },
+ { 0x000012ec, 0x0000031c },
+ { 0x000012f0, 0x00000322 },
+ { 0x000012f4, 0x00000328 },
+ { 0x000012f8, 0x0000032e },
+ { 0x000012fc, 0x00000334 },
+ { 0x00001300, 0x0000033b },
+ { 0x00001304, 0x00000341 },
+ { 0x00001308, 0x00000347 },
+ { 0x0000130c, 0x0000034d },
+ { 0x00001310, 0x00000354 },
+ { 0x00001314, 0x0000035a },
+ { 0x00001318, 0x00000361 },
+ { 0x0000131c, 0x00000367 },
+ { 0x00001320, 0x0000036d },
+ { 0x00001324, 0x00000374 },
+ { 0x00001328, 0x0000037a },
+ { 0x0000132c, 0x00000381 },
+ { 0x00001330, 0x00000388 },
+ { 0x00001334, 0x0000038e },
+ { 0x00001338, 0x00000395 },
+ { 0x0000133c, 0x0000039b },
+ { 0x00001340, 0x000003a2 },
+ { 0x00001344, 0x000003a9 },
+ { 0x00001348, 0x000003b0 },
+ { 0x0000134c, 0x000003b6 },
+ { 0x00001350, 0x000003bd },
+ { 0x00001354, 0x000003c4 },
+ { 0x00001358, 0x000003cb },
+ { 0x0000135c, 0x000003d2 },
+ { 0x00001360, 0x000003d8 },
+ { 0x00001364, 0x000003df },
+ { 0x00001368, 0x000003e6 },
+ { 0x0000136c, 0x000003ed },
+ { 0x00001370, 0x000003f4 },
+ { 0x00001374, 0x000003fb },
+ { 0x00001378, 0x00000402 },
+ { 0x0000137c, 0x00000409 },
+ { 0x00001380, 0x00000411 },
+ { 0x00001384, 0x00000418 },
+ { 0x00001388, 0x0000041f },
+ { 0x0000138c, 0x00000426 },
+ { 0x00001390, 0x0000042d },
+ { 0x00001394, 0x00000434 },
+ { 0x00001398, 0x0000043c },
+ { 0x0000139c, 0x00000443 },
+ { 0x000013a0, 0x0000044a },
+ { 0x000013a4, 0x00000452 },
+ { 0x000013a8, 0x00000459 },
+ { 0x000013ac, 0x00000460 },
+ { 0x000013b0, 0x00000468 },
+ { 0x000013b4, 0x0000046f },
+ { 0x000013b8, 0x00000477 },
+ { 0x000013bc, 0x0000047e },
+ { 0x000013c0, 0x00000486 },
+ { 0x000013c4, 0x0000048d },
+ { 0x000013c8, 0x00000495 },
+ { 0x000013cc, 0x0000049c },
+ { 0x000013d0, 0x000004a4 },
+ { 0x000013d4, 0x000004ac },
+ { 0x000013d8, 0x000004b3 },
+ { 0x000013dc, 0x000004bb },
+ { 0x000013e0, 0x000004c3 },
+ { 0x000013e4, 0x000004cb },
+ { 0x000013e8, 0x000004d3 },
+ { 0x000013ec, 0x000004da },
+ { 0x000013f0, 0x000004e2 },
+ { 0x000013f4, 0x000004ea },
+ { 0x000013f8, 0x000004f2 },
+ { 0x000013fc, 0x000004fa },
+ { 0x00001400, 0x00000502 },
+ { 0x00001404, 0x0000050a },
+ { 0x00001408, 0x00000512 },
+ { 0x0000140c, 0x0000051a },
+ { 0x00001410, 0x00000522 },
+ { 0x00001414, 0x0000052a },
+ { 0x00001418, 0x00000532 },
+ { 0x0000141c, 0x0000053a },
+ { 0x00001420, 0x00000543 },
+ { 0x00001424, 0x0000054b },
+ { 0x00001428, 0x00000553 },
+ { 0x0000142c, 0x0000055b },
+ { 0x00001430, 0x00000564 },
+ { 0x00001434, 0x0000056c },
+ { 0x00001438, 0x00000574 },
+ { 0x0000143c, 0x0000057d },
+ { 0x00001440, 0x00000585 },
+ { 0x00001444, 0x0000058d },
+ { 0x00001448, 0x00000596 },
+ { 0x0000144c, 0x0000059e },
+ { 0x00001450, 0x000005a7 },
+ { 0x00001454, 0x000005af },
+ { 0x00001458, 0x000005b8 },
+ { 0x0000145c, 0x000005c1 },
+ { 0x00001460, 0x000005c9 },
+ { 0x00001464, 0x000005d2 },
+ { 0x00001468, 0x000005db },
+ { 0x0000146c, 0x000005e3 },
+ { 0x00001470, 0x000005ec },
+ { 0x00001474, 0x000005f5 },
+ { 0x00001478, 0x000005fe },
+ { 0x0000147c, 0x00000606 },
+ { 0x00001480, 0x0000060f },
+ { 0x00001484, 0x00000618 },
+ { 0x00001488, 0x00000621 },
+ { 0x0000148c, 0x0000062a },
+ { 0x00001490, 0x00000633 },
+ { 0x00001494, 0x0000063c },
+ { 0x00001498, 0x00000645 },
+ { 0x0000149c, 0x0000064e },
+ { 0x000014a0, 0x00000657 },
+ { 0x000014a4, 0x00000660 },
+ { 0x000014a8, 0x00000669 },
+ { 0x000014ac, 0x00000672 },
+ { 0x000014b0, 0x0000067b },
+ { 0x000014b4, 0x00000685 },
+ { 0x000014b8, 0x0000068e },
+ { 0x000014bc, 0x00000697 },
+ { 0x000014c0, 0x000006a0 },
+ { 0x000014c4, 0x000006aa },
+ { 0x000014c8, 0x000006b3 },
+ { 0x000014cc, 0x000006bd },
+ { 0x000014d0, 0x000006c6 },
+ { 0x000014d4, 0x000006cf },
+ { 0x000014d8, 0x000006d9 },
+ { 0x000014dc, 0x000006e2 },
+ { 0x000014e0, 0x000006ec },
+ { 0x000014e4, 0x000006f5 },
+ { 0x000014e8, 0x000006ff },
+ { 0x000014ec, 0x00000709 },
+ { 0x000014f0, 0x00000712 },
+ { 0x000014f4, 0x0000071c },
+ { 0x000014f8, 0x00000726 },
+ { 0x000014fc, 0x0000072f },
+ { 0x00001500, 0x00000739 },
+ { 0x00001504, 0x00000743 },
+ { 0x00001508, 0x0000074d },
+ { 0x0000150c, 0x00000756 },
+ { 0x00001510, 0x00000760 },
+ { 0x00001514, 0x0000076a },
+ { 0x00001518, 0x00000774 },
+ { 0x0000151c, 0x0000077e },
+ { 0x00001520, 0x00000788 },
+ { 0x00001524, 0x00000792 },
+ { 0x00001528, 0x0000079c },
+ { 0x0000152c, 0x000007a6 },
+ { 0x00001530, 0x000007b0 },
+ { 0x00001534, 0x000007ba },
+ { 0x00001538, 0x000007c4 },
+ { 0x0000153c, 0x000007cf },
+ { 0x00001540, 0x000007d9 },
+ { 0x00001544, 0x000007e3 },
+ { 0x00001548, 0x000007ed },
+ { 0x0000154c, 0x000007f7 },
+ { 0x00001550, 0x00000802 },
+ { 0x00001554, 0x0000080c },
+ { 0x00001558, 0x00000816 },
+ { 0x0000155c, 0x00000821 },
+ { 0x00001560, 0x0000082b },
+ { 0x00001564, 0x00000836 },
+ { 0x00001568, 0x00000840 },
+ { 0x0000156c, 0x0000084b },
+ { 0x00001570, 0x00000855 },
+ { 0x00001574, 0x00000860 },
+ { 0x00001578, 0x0000086a },
+ { 0x0000157c, 0x00000875 },
+ { 0x00001580, 0x00000880 },
+ { 0x00001584, 0x0000088a },
+ { 0x00001588, 0x00000895 },
+ { 0x0000158c, 0x000008a0 },
+ { 0x00001590, 0x000008ab },
+ { 0x00001594, 0x000008b5 },
+ { 0x00001598, 0x000008c0 },
+ { 0x0000159c, 0x000008cb },
+ { 0x000015a0, 0x000008d6 },
+ { 0x000015a4, 0x000008e1 },
+ { 0x000015a8, 0x000008ec },
+ { 0x000015ac, 0x000008f7 },
+ { 0x000015b0, 0x00000902 },
+ { 0x000015b4, 0x0000090d },
+ { 0x000015b8, 0x00000918 },
+ { 0x000015bc, 0x00000923 },
+ { 0x000015c0, 0x0000092e },
+ { 0x000015c4, 0x00000939 },
+ { 0x000015c8, 0x00000944 },
+ { 0x000015cc, 0x00000950 },
+ { 0x000015d0, 0x0000095b },
+ { 0x000015d4, 0x00000966 },
+ { 0x000015d8, 0x00000971 },
+ { 0x000015dc, 0x0000097d },
+ { 0x000015e0, 0x00000988 },
+ { 0x000015e4, 0x00000993 },
+ { 0x000015e8, 0x0000099f },
+ { 0x000015ec, 0x000009aa },
+ { 0x000015f0, 0x000009b6 },
+ { 0x000015f4, 0x000009c1 },
+ { 0x000015f8, 0x000009cd },
+ { 0x000015fc, 0x000009d8 },
+ { 0x00001600, 0x000009e4 },
+ { 0x00001604, 0x000009f0 },
+ { 0x00001608, 0x000009fb },
+ { 0x0000160c, 0x00000a07 },
+ { 0x00001610, 0x00000a13 },
+ { 0x00001614, 0x00000a1e },
+ { 0x00001618, 0x00000a2a },
+ { 0x0000161c, 0x00000a36 },
+ { 0x00001620, 0x00000a42 },
+ { 0x00001624, 0x00000a4e },
+ { 0x00001628, 0x00000a59 },
+ { 0x0000162c, 0x00000a65 },
+ { 0x00001630, 0x00000a71 },
+ { 0x00001634, 0x00000a7d },
+ { 0x00001638, 0x00000a89 },
+ { 0x0000163c, 0x00000a95 },
+ { 0x00001640, 0x00000aa1 },
+ { 0x00001644, 0x00000aad },
+ { 0x00001648, 0x00000ab9 },
+ { 0x0000164c, 0x00000ac6 },
+ { 0x00001650, 0x00000ad2 },
+ { 0x00001654, 0x00000ade },
+ { 0x00001658, 0x00000aea },
+ { 0x0000165c, 0x00000af6 },
+ { 0x00001660, 0x00000b03 },
+ { 0x00001664, 0x00000b0f },
+ { 0x00001668, 0x00000b1b },
+ { 0x0000166c, 0x00000b28 },
+ { 0x00001670, 0x00000b34 },
+ { 0x00001674, 0x00000b41 },
+ { 0x00001678, 0x00000b4d },
+ { 0x0000167c, 0x00000b5a },
+ { 0x00001680, 0x00000b66 },
+ { 0x00001684, 0x00000b73 },
+ { 0x00001688, 0x00000b7f },
+ { 0x0000168c, 0x00000b8c },
+ { 0x00001690, 0x00000b98 },
+ { 0x00001694, 0x00000ba5 },
+ { 0x00001698, 0x00000bb2 },
+ { 0x0000169c, 0x00000bbf },
+ { 0x000016a0, 0x00000bcb },
+ { 0x000016a4, 0x00000bd8 },
+ { 0x000016a8, 0x00000be5 },
+ { 0x000016ac, 0x00000bf2 },
+ { 0x000016b0, 0x00000bff },
+ { 0x000016b4, 0x00000c0c },
+ { 0x000016b8, 0x00000c19 },
+ { 0x000016bc, 0x00000c25 },
+ { 0x000016c0, 0x00000c32 },
+ { 0x000016c4, 0x00000c40 },
+ { 0x000016c8, 0x00000c4d },
+ { 0x000016cc, 0x00000c5a },
+ { 0x000016d0, 0x00000c67 },
+ { 0x000016d4, 0x00000c74 },
+ { 0x000016d8, 0x00000c81 },
+ { 0x000016dc, 0x00000c8e },
+ { 0x000016e0, 0x00000c9c },
+ { 0x000016e4, 0x00000ca9 },
+ { 0x000016e8, 0x00000cb6 },
+ { 0x000016ec, 0x00000cc3 },
+ { 0x000016f0, 0x00000cd1 },
+ { 0x000016f4, 0x00000cde },
+ { 0x000016f8, 0x00000cec },
+ { 0x000016fc, 0x00000cf9 },
+ { 0x00001700, 0x00000d07 },
+ { 0x00001704, 0x00000d14 },
+ { 0x00001708, 0x00000d22 },
+ { 0x0000170c, 0x00000d2f },
+ { 0x00001710, 0x00000d3d },
+ { 0x00001714, 0x00000d4a },
+ { 0x00001718, 0x00000d58 },
+ { 0x0000171c, 0x00000d66 },
+ { 0x00001720, 0x00000d73 },
+ { 0x00001724, 0x00000d81 },
+ { 0x00001728, 0x00000d8f },
+ { 0x0000172c, 0x00000d9d },
+ { 0x00001730, 0x00000dab },
+ { 0x00001734, 0x00000db8 },
+ { 0x00001738, 0x00000dc6 },
+ { 0x0000173c, 0x00000dd4 },
+ { 0x00001740, 0x00000de2 },
+ { 0x00001744, 0x00000df0 },
+ { 0x00001748, 0x00000dfe },
+ { 0x0000174c, 0x00000e0c },
+ { 0x00001750, 0x00000e1a },
+ { 0x00001754, 0x00000e29 },
+ { 0x00001758, 0x00000e37 },
+ { 0x0000175c, 0x00000e45 },
+ { 0x00001760, 0x00000e53 },
+ { 0x00001764, 0x00000e61 },
+ { 0x00001768, 0x00000e70 },
+ { 0x0000176c, 0x00000e7e },
+ { 0x00001770, 0x00000e8c },
+ { 0x00001774, 0x00000e9a },
+ { 0x00001778, 0x00000ea9 },
+ { 0x0000177c, 0x00000eb7 },
+ { 0x00001780, 0x00000ec6 },
+ { 0x00001784, 0x00000ed4 },
+ { 0x00001788, 0x00000ee3 },
+ { 0x0000178c, 0x00000ef1 },
+ { 0x00001790, 0x00000f00 },
+ { 0x00001794, 0x00000f0e },
+ { 0x00001798, 0x00000f1d },
+ { 0x0000179c, 0x00000f2c },
+ { 0x000017a0, 0x00000f3a },
+ { 0x000017a4, 0x00000f49 },
+ { 0x000017a8, 0x00000f58 },
+ { 0x000017ac, 0x00000f67 },
+ { 0x000017b0, 0x00000f75 },
+ { 0x000017b4, 0x00000f84 },
+ { 0x000017b8, 0x00000f93 },
+ { 0x000017bc, 0x00000fa2 },
+ { 0x000017c0, 0x00000fb1 },
+ { 0x000017c4, 0x00000fc0 },
+ { 0x000017c8, 0x00000fcf },
+ { 0x000017cc, 0x00000fde },
+ { 0x000017d0, 0x00000fed },
+ { 0x000017d4, 0x00000ffc },
+ { 0x000017d8, 0x0000100b },
+ { 0x000017dc, 0x0000101a },
+ { 0x000017e0, 0x0000102a },
+ { 0x000017e4, 0x00001039 },
+ { 0x000017e8, 0x00001048 },
+ { 0x000017ec, 0x00001057 },
+ { 0x000017f0, 0x00001067 },
+ { 0x000017f4, 0x00001076 },
+ { 0x000017f8, 0x00001085 },
+ { 0x000017fc, 0x00001095 },
+ { 0x00001800, 0x000010a4 },
+ { 0x00001804, 0x000010b4 },
+ { 0x00001808, 0x000010c3 },
+ { 0x0000180c, 0x000010d3 },
+ { 0x00001810, 0x000010e2 },
+ { 0x00001814, 0x000010f2 },
+ { 0x00001818, 0x00001101 },
+ { 0x0000181c, 0x00001111 },
+ { 0x00001820, 0x00001121 },
+ { 0x00001824, 0x00001130 },
+ { 0x00001828, 0x00001140 },
+ { 0x0000182c, 0x00001150 },
+ { 0x00001830, 0x00001160 },
+ { 0x00001834, 0x0000116f },
+ { 0x00001838, 0x0000117f },
+ { 0x0000183c, 0x0000118f },
+ { 0x00001840, 0x0000119f },
+ { 0x00001844, 0x000011af },
+ { 0x00001848, 0x000011bf },
+ { 0x0000184c, 0x000011cf },
+ { 0x00001850, 0x000011df },
+ { 0x00001854, 0x000011ef },
+ { 0x00001858, 0x000011ff },
+ { 0x0000185c, 0x0000120f },
+ { 0x00001860, 0x0000121f },
+ { 0x00001864, 0x00001230 },
+ { 0x00001868, 0x00001240 },
+ { 0x0000186c, 0x00001250 },
+ { 0x00001870, 0x00001260 },
+ { 0x00001874, 0x00001271 },
+ { 0x00001878, 0x00001281 },
+ { 0x0000187c, 0x00001291 },
+ { 0x00001880, 0x000012a2 },
+ { 0x00001884, 0x000012b2 },
+ { 0x00001888, 0x000012c3 },
+ { 0x0000188c, 0x000012d3 },
+ { 0x00001890, 0x000012e4 },
+ { 0x00001894, 0x000012f4 },
+ { 0x00001898, 0x00001305 },
+ { 0x0000189c, 0x00001316 },
+ { 0x000018a0, 0x00001326 },
+ { 0x000018a4, 0x00001337 },
+ { 0x000018a8, 0x00001348 },
+ { 0x000018ac, 0x00001359 },
+ { 0x000018b0, 0x00001369 },
+ { 0x000018b4, 0x0000137a },
+ { 0x000018b8, 0x0000138b },
+ { 0x000018bc, 0x0000139c },
+ { 0x000018c0, 0x000013ad },
+ { 0x000018c4, 0x000013be },
+ { 0x000018c8, 0x000013cf },
+ { 0x000018cc, 0x000013e0 },
+ { 0x000018d0, 0x000013f1 },
+ { 0x000018d4, 0x00001402 },
+ { 0x000018d8, 0x00001413 },
+ { 0x000018dc, 0x00001424 },
+ { 0x000018e0, 0x00001435 },
+ { 0x000018e4, 0x00001446 },
+ { 0x000018e8, 0x00001458 },
+ { 0x000018ec, 0x00001469 },
+ { 0x000018f0, 0x0000147a },
+ { 0x000018f4, 0x0000148b },
+ { 0x000018f8, 0x0000149d },
+ { 0x000018fc, 0x000014ae },
+ { 0x00001900, 0x000014c0 },
+ { 0x00001904, 0x000014d1 },
+ { 0x00001908, 0x000014e3 },
+ { 0x0000190c, 0x000014f4 },
+ { 0x00001910, 0x00001506 },
+ { 0x00001914, 0x00001517 },
+ { 0x00001918, 0x00001529 },
+ { 0x0000191c, 0x0000153a },
+ { 0x00001920, 0x0000154c },
+ { 0x00001924, 0x0000155e },
+ { 0x00001928, 0x0000156f },
+ { 0x0000192c, 0x00001581 },
+ { 0x00001930, 0x00001593 },
+ { 0x00001934, 0x000015a5 },
+ { 0x00001938, 0x000015b7 },
+ { 0x0000193c, 0x000015c9 },
+ { 0x00001940, 0x000015db },
+ { 0x00001944, 0x000015ec },
+ { 0x00001948, 0x000015fe },
+ { 0x0000194c, 0x00001610 },
+ { 0x00001950, 0x00001623 },
+ { 0x00001954, 0x00001635 },
+ { 0x00001958, 0x00001647 },
+ { 0x0000195c, 0x00001659 },
+ { 0x00001960, 0x0000166b },
+ { 0x00001964, 0x0000167d },
+ { 0x00001968, 0x0000168f },
+ { 0x0000196c, 0x000016a2 },
+ { 0x00001970, 0x000016b4 },
+ { 0x00001974, 0x000016c6 },
+ { 0x00001978, 0x000016d9 },
+ { 0x0000197c, 0x000016eb },
+ { 0x00001980, 0x000016fe },
+ { 0x00001984, 0x00001710 },
+ { 0x00001988, 0x00001722 },
+ { 0x0000198c, 0x00001735 },
+ { 0x00001990, 0x00001748 },
+ { 0x00001994, 0x0000175a },
+ { 0x00001998, 0x0000176d },
+ { 0x0000199c, 0x0000177f },
+ { 0x000019a0, 0x00001792 },
+ { 0x000019a4, 0x000017a5 },
+ { 0x000019a8, 0x000017b8 },
+ { 0x000019ac, 0x000017ca },
+ { 0x000019b0, 0x000017dd },
+ { 0x000019b4, 0x000017f0 },
+ { 0x000019b8, 0x00001803 },
+ { 0x000019bc, 0x00001816 },
+ { 0x000019c0, 0x00001829 },
+ { 0x000019c4, 0x0000183c },
+ { 0x000019c8, 0x0000184f },
+ { 0x000019cc, 0x00001862 },
+ { 0x000019d0, 0x00001875 },
+ { 0x000019d4, 0x00001888 },
+ { 0x000019d8, 0x0000189b },
+ { 0x000019dc, 0x000018ae },
+ { 0x000019e0, 0x000018c1 },
+ { 0x000019e4, 0x000018d5 },
+ { 0x000019e8, 0x000018e8 },
+ { 0x000019ec, 0x000018fb },
+ { 0x000019f0, 0x0000190e },
+ { 0x000019f4, 0x00001922 },
+ { 0x000019f8, 0x00001935 },
+ { 0x000019fc, 0x00001949 },
+ { 0x00001a00, 0x0000195c },
+ { 0x00001a04, 0x0000196f },
+ { 0x00001a08, 0x00001983 },
+ { 0x00001a0c, 0x00001996 },
+ { 0x00001a10, 0x000019aa },
+ { 0x00001a14, 0x000019be },
+ { 0x00001a18, 0x000019d1 },
+ { 0x00001a1c, 0x000019e5 },
+ { 0x00001a20, 0x000019f9 },
+ { 0x00001a24, 0x00001a0c },
+ { 0x00001a28, 0x00001a20 },
+ { 0x00001a2c, 0x00001a34 },
+ { 0x00001a30, 0x00001a48 },
+ { 0x00001a34, 0x00001a5c },
+ { 0x00001a38, 0x00001a70 },
+ { 0x00001a3c, 0x00001a84 },
+ { 0x00001a40, 0x00001a97 },
+ { 0x00001a44, 0x00001aab },
+ { 0x00001a48, 0x00001ac0 },
+ { 0x00001a4c, 0x00001ad4 },
+ { 0x00001a50, 0x00001ae8 },
+ { 0x00001a54, 0x00001afc },
+ { 0x00001a58, 0x00001b10 },
+ { 0x00001a5c, 0x00001b24 },
+ { 0x00001a60, 0x00001b38 },
+ { 0x00001a64, 0x00001b4d },
+ { 0x00001a68, 0x00001b61 },
+ { 0x00001a6c, 0x00001b75 },
+ { 0x00001a70, 0x00001b8a },
+ { 0x00001a74, 0x00001b9e },
+ { 0x00001a78, 0x00001bb2 },
+ { 0x00001a7c, 0x00001bc7 },
+ { 0x00001a80, 0x00001bdb },
+ { 0x00001a84, 0x00001bf0 },
+ { 0x00001a88, 0x00001c04 },
+ { 0x00001a8c, 0x00001c19 },
+ { 0x00001a90, 0x00001c2e },
+ { 0x00001a94, 0x00001c42 },
+ { 0x00001a98, 0x00001c57 },
+ { 0x00001a9c, 0x00001c6c },
+ { 0x00001aa0, 0x00001c80 },
+ { 0x00001aa4, 0x00001c95 },
+ { 0x00001aa8, 0x00001caa },
+ { 0x00001aac, 0x00001cbf },
+ { 0x00001ab0, 0x00001cd4 },
+ { 0x00001ab4, 0x00001ce8 },
+ { 0x00001ab8, 0x00001cfd },
+ { 0x00001abc, 0x00001d12 },
+ { 0x00001ac0, 0x00001d27 },
+ { 0x00001ac4, 0x00001d3c },
+ { 0x00001ac8, 0x00001d51 },
+ { 0x00001acc, 0x00001d67 },
+ { 0x00001ad0, 0x00001d7c },
+ { 0x00001ad4, 0x00001d91 },
+ { 0x00001ad8, 0x00001da6 },
+ { 0x00001adc, 0x00001dbb },
+ { 0x00001ae0, 0x00001dd1 },
+ { 0x00001ae4, 0x00001de6 },
+ { 0x00001ae8, 0x00001dfb },
+ { 0x00001aec, 0x00001e10 },
+ { 0x00001af0, 0x00001e26 },
+ { 0x00001af4, 0x00001e3b },
+ { 0x00001af8, 0x00001e51 },
+ { 0x00001afc, 0x00001e66 },
+ { 0x00001b00, 0x00001e7c },
+ { 0x00001b04, 0x00001e91 },
+ { 0x00001b08, 0x00001ea7 },
+ { 0x00001b0c, 0x00001ebd },
+ { 0x00001b10, 0x00001ed2 },
+ { 0x00001b14, 0x00001ee8 },
+ { 0x00001b18, 0x00001efe },
+ { 0x00001b1c, 0x00001f13 },
+ { 0x00001b20, 0x00001f29 },
+ { 0x00001b24, 0x00001f3f },
+ { 0x00001b28, 0x00001f55 },
+ { 0x00001b2c, 0x00001f6b },
+ { 0x00001b30, 0x00001f81 },
+ { 0x00001b34, 0x00001f96 },
+ { 0x00001b38, 0x00001fac },
+ { 0x00001b3c, 0x00001fc2 },
+ { 0x00001b40, 0x00001fd9 },
+ { 0x00001b44, 0x00001fef },
+ { 0x00001b48, 0x00002005 },
+ { 0x00001b4c, 0x0000201b },
+ { 0x00001b50, 0x00002031 },
+ { 0x00001b54, 0x00002047 },
+ { 0x00001b58, 0x0000205d },
+ { 0x00001b5c, 0x00002074 },
+ { 0x00001b60, 0x0000208a },
+ { 0x00001b64, 0x000020a0 },
+ { 0x00001b68, 0x000020b7 },
+ { 0x00001b6c, 0x000020cd },
+ { 0x00001b70, 0x000020e4 },
+ { 0x00001b74, 0x000020fa },
+ { 0x00001b78, 0x00002111 },
+ { 0x00001b7c, 0x00002127 },
+ { 0x00001b80, 0x0000213e },
+ { 0x00001b84, 0x00002154 },
+ { 0x00001b88, 0x0000216b },
+ { 0x00001b8c, 0x00002182 },
+ { 0x00001b90, 0x00002198 },
+ { 0x00001b94, 0x000021af },
+ { 0x00001b98, 0x000021c6 },
+ { 0x00001b9c, 0x000021dd },
+ { 0x00001ba0, 0x000021f3 },
+ { 0x00001ba4, 0x0000220a },
+ { 0x00001ba8, 0x00002221 },
+ { 0x00001bac, 0x00002238 },
+ { 0x00001bb0, 0x0000224f },
+ { 0x00001bb4, 0x00002266 },
+ { 0x00001bb8, 0x0000227d },
+ { 0x00001bbc, 0x00002294 },
+ { 0x00001bc0, 0x000022ab },
+ { 0x00001bc4, 0x000022c2 },
+ { 0x00001bc8, 0x000022da },
+ { 0x00001bcc, 0x000022f1 },
+ { 0x00001bd0, 0x00002308 },
+ { 0x00001bd4, 0x0000231f },
+ { 0x00001bd8, 0x00002337 },
+ { 0x00001bdc, 0x0000234e },
+ { 0x00001be0, 0x00002365 },
+ { 0x00001be4, 0x0000237d },
+ { 0x00001be8, 0x00002394 },
+ { 0x00001bec, 0x000023ac },
+ { 0x00001bf0, 0x000023c3 },
+ { 0x00001bf4, 0x000023db },
+ { 0x00001bf8, 0x000023f2 },
+ { 0x00001bfc, 0x0000240a },
+ { 0x00001c00, 0x00002421 },
+ { 0x00001c04, 0x00002439 },
+ { 0x00001c08, 0x00002451 },
+ { 0x00001c0c, 0x00002469 },
+ { 0x00001c10, 0x00002480 },
+ { 0x00001c14, 0x00002498 },
+ { 0x00001c18, 0x000024b0 },
+ { 0x00001c1c, 0x000024c8 },
+ { 0x00001c20, 0x000024e0 },
+ { 0x00001c24, 0x000024f8 },
+ { 0x00001c28, 0x00002510 },
+ { 0x00001c2c, 0x00002528 },
+ { 0x00001c30, 0x00002540 },
+ { 0x00001c34, 0x00002558 },
+ { 0x00001c38, 0x00002570 },
+ { 0x00001c3c, 0x00002588 },
+ { 0x00001c40, 0x000025a0 },
+ { 0x00001c44, 0x000025b8 },
+ { 0x00001c48, 0x000025d0 },
+ { 0x00001c4c, 0x000025e9 },
+ { 0x00001c50, 0x00002601 },
+ { 0x00001c54, 0x00002619 },
+ { 0x00001c58, 0x00002632 },
+ { 0x00001c5c, 0x0000264a },
+ { 0x00001c60, 0x00002663 },
+ { 0x00001c64, 0x0000267b },
+ { 0x00001c68, 0x00002693 },
+ { 0x00001c6c, 0x000026ac },
+ { 0x00001c70, 0x000026c5 },
+ { 0x00001c74, 0x000026dd },
+ { 0x00001c78, 0x000026f6 },
+ { 0x00001c7c, 0x0000270e },
+ { 0x00001c80, 0x00002727 },
+ { 0x00001c84, 0x00002740 },
+ { 0x00001c88, 0x00002759 },
+ { 0x00001c8c, 0x00002771 },
+ { 0x00001c90, 0x0000278a },
+ { 0x00001c94, 0x000027a3 },
+ { 0x00001c98, 0x000027bc },
+ { 0x00001c9c, 0x000027d5 },
+ { 0x00001ca0, 0x000027ee },
+ { 0x00001ca4, 0x00002807 },
+ { 0x00001ca8, 0x00002820 },
+ { 0x00001cac, 0x00002839 },
+ { 0x00001cb0, 0x00002852 },
+ { 0x00001cb4, 0x0000286b },
+ { 0x00001cb8, 0x00002884 },
+ { 0x00001cbc, 0x0000289e },
+ { 0x00001cc0, 0x000028b7 },
+ { 0x00001cc4, 0x000028d0 },
+ { 0x00001cc8, 0x000028e9 },
+ { 0x00001ccc, 0x00002903 },
+ { 0x00001cd0, 0x0000291c },
+ { 0x00001cd4, 0x00002936 },
+ { 0x00001cd8, 0x0000294f },
+ { 0x00001cdc, 0x00002968 },
+ { 0x00001ce0, 0x00002982 },
+ { 0x00001ce4, 0x0000299c },
+ { 0x00001ce8, 0x000029b5 },
+ { 0x00001cec, 0x000029cf },
+ { 0x00001cf0, 0x000029e8 },
+ { 0x00001cf4, 0x00002a02 },
+ { 0x00001cf8, 0x00002a1c },
+ { 0x00001cfc, 0x00002a35 },
+ { 0x00001d00, 0x00002a4f },
+ { 0x00001d04, 0x00002a69 },
+ { 0x00001d08, 0x00002a83 },
+ { 0x00001d0c, 0x00002a9d },
+ { 0x00001d10, 0x00002ab7 },
+ { 0x00001d14, 0x00002ad1 },
+ { 0x00001d18, 0x00002aeb },
+ { 0x00001d1c, 0x00002b05 },
+ { 0x00001d20, 0x00002b1f },
+ { 0x00001d24, 0x00002b39 },
+ { 0x00001d28, 0x00002b53 },
+ { 0x00001d2c, 0x00002b6d },
+ { 0x00001d30, 0x00002b87 },
+ { 0x00001d34, 0x00002ba1 },
+ { 0x00001d38, 0x00002bbc },
+ { 0x00001d3c, 0x00002bd6 },
+ { 0x00001d40, 0x00002bf0 },
+ { 0x00001d44, 0x00002c0b },
+ { 0x00001d48, 0x00002c25 },
+ { 0x00001d4c, 0x00002c3f },
+ { 0x00001d50, 0x00002c5a },
+ { 0x00001d54, 0x00002c74 },
+ { 0x00001d58, 0x00002c8f },
+ { 0x00001d5c, 0x00002ca9 },
+ { 0x00001d60, 0x00002cc4 },
+ { 0x00001d64, 0x00002cdf },
+ { 0x00001d68, 0x00002cf9 },
+ { 0x00001d6c, 0x00002d14 },
+ { 0x00001d70, 0x00002d2f },
+ { 0x00001d74, 0x00002d49 },
+ { 0x00001d78, 0x00002d64 },
+ { 0x00001d7c, 0x00002d7f },
+ { 0x00001d80, 0x00002d9a },
+ { 0x00001d84, 0x00002db5 },
+ { 0x00001d88, 0x00002dd0 },
+ { 0x00001d8c, 0x00002deb },
+ { 0x00001d90, 0x00002e06 },
+ { 0x00001d94, 0x00002e21 },
+ { 0x00001d98, 0x00002e3c },
+ { 0x00001d9c, 0x00002e57 },
+ { 0x00001da0, 0x00002e72 },
+ { 0x00001da4, 0x00002e8d },
+ { 0x00001da8, 0x00002ea8 },
+ { 0x00001dac, 0x00002ec4 },
+ { 0x00001db0, 0x00002edf },
+ { 0x00001db4, 0x00002efa },
+ { 0x00001db8, 0x00002f16 },
+ { 0x00001dbc, 0x00002f31 },
+ { 0x00001dc0, 0x00002f4c },
+ { 0x00001dc4, 0x00002f68 },
+ { 0x00001dc8, 0x00002f83 },
+ { 0x00001dcc, 0x00002f9f },
+ { 0x00001dd0, 0x00002fba },
+ { 0x00001dd4, 0x00002fd6 },
+ { 0x00001dd8, 0x00002ff1 },
+ { 0x00001ddc, 0x0000300d },
+ { 0x00001de0, 0x00003029 },
+ { 0x00001de4, 0x00003044 },
+ { 0x00001de8, 0x00003060 },
+ { 0x00001dec, 0x0000307c },
+ { 0x00001df0, 0x00003098 },
+ { 0x00001df4, 0x000030b4 },
+ { 0x00001df8, 0x000030d0 },
+ { 0x00001dfc, 0x000030eb },
+ { 0x00001e00, 0x00003107 },
+ { 0x00001e04, 0x00003123 },
+ { 0x00001e08, 0x0000313f },
+ { 0x00001e0c, 0x0000315b },
+ { 0x00001e10, 0x00003178 },
+ { 0x00001e14, 0x00003194 },
+ { 0x00001e18, 0x000031b0 },
+ { 0x00001e1c, 0x000031cc },
+ { 0x00001e20, 0x000031e8 },
+ { 0x00001e24, 0x00003205 },
+ { 0x00001e28, 0x00003221 },
+ { 0x00001e2c, 0x0000323d },
+ { 0x00001e30, 0x0000325a },
+ { 0x00001e34, 0x00003276 },
+ { 0x00001e38, 0x00003292 },
+ { 0x00001e3c, 0x000032af },
+ { 0x00001e40, 0x000032cb },
+ { 0x00001e44, 0x000032e8 },
+ { 0x00001e48, 0x00003304 },
+ { 0x00001e4c, 0x00003321 },
+ { 0x00001e50, 0x0000333e },
+ { 0x00001e54, 0x0000335a },
+ { 0x00001e58, 0x00003377 },
+ { 0x00001e5c, 0x00003394 },
+ { 0x00001e60, 0x000033b1 },
+ { 0x00001e64, 0x000033cd },
+ { 0x00001e68, 0x000033ea },
+ { 0x00001e6c, 0x00003407 },
+ { 0x00001e70, 0x00003424 },
+ { 0x00001e74, 0x00003441 },
+ { 0x00001e78, 0x0000345e },
+ { 0x00001e7c, 0x0000347b },
+ { 0x00001e80, 0x00003498 },
+ { 0x00001e84, 0x000034b5 },
+ { 0x00001e88, 0x000034d2 },
+ { 0x00001e8c, 0x000034ef },
+ { 0x00001e90, 0x0000350d },
+ { 0x00001e94, 0x0000352a },
+ { 0x00001e98, 0x00003547 },
+ { 0x00001e9c, 0x00003564 },
+ { 0x00001ea0, 0x00003582 },
+ { 0x00001ea4, 0x0000359f },
+ { 0x00001ea8, 0x000035bc },
+ { 0x00001eac, 0x000035da },
+ { 0x00001eb0, 0x000035f7 },
+ { 0x00001eb4, 0x00003615 },
+ { 0x00001eb8, 0x00003632 },
+ { 0x00001ebc, 0x00003650 },
+ { 0x00001ec0, 0x0000366e },
+ { 0x00001ec4, 0x0000368b },
+ { 0x00001ec8, 0x000036a9 },
+ { 0x00001ecc, 0x000036c7 },
+ { 0x00001ed0, 0x000036e4 },
+ { 0x00001ed4, 0x00003702 },
+ { 0x00001ed8, 0x00003720 },
+ { 0x00001edc, 0x0000373e },
+ { 0x00001ee0, 0x0000375c },
+ { 0x00001ee4, 0x0000377a },
+ { 0x00001ee8, 0x00003798 },
+ { 0x00001eec, 0x000037b6 },
+ { 0x00001ef0, 0x000037d4 },
+ { 0x00001ef4, 0x000037f2 },
+ { 0x00001ef8, 0x00003810 },
+ { 0x00001efc, 0x0000382e },
+ { 0x00001f00, 0x0000384c },
+ { 0x00001f04, 0x0000386a },
+ { 0x00001f08, 0x00003888 },
+ { 0x00001f0c, 0x000038a7 },
+ { 0x00001f10, 0x000038c5 },
+ { 0x00001f14, 0x000038e3 },
+ { 0x00001f18, 0x00003902 },
+ { 0x00001f1c, 0x00003920 },
+ { 0x00001f20, 0x0000393f },
+ { 0x00001f24, 0x0000395d },
+ { 0x00001f28, 0x0000397c },
+ { 0x00001f2c, 0x0000399a },
+ { 0x00001f30, 0x000039b9 },
+ { 0x00001f34, 0x000039d7 },
+ { 0x00001f38, 0x000039f6 },
+ { 0x00001f3c, 0x00003a15 },
+ { 0x00001f40, 0x00003a33 },
+ { 0x00001f44, 0x00003a52 },
+ { 0x00001f48, 0x00003a71 },
+ { 0x00001f4c, 0x00003a90 },
+ { 0x00001f50, 0x00003aaf },
+ { 0x00001f54, 0x00003acd },
+ { 0x00001f58, 0x00003aec },
+ { 0x00001f5c, 0x00003b0b },
+ { 0x00001f60, 0x00003b2a },
+ { 0x00001f64, 0x00003b49 },
+ { 0x00001f68, 0x00003b68 },
+ { 0x00001f6c, 0x00003b87 },
+ { 0x00001f70, 0x00003ba7 },
+ { 0x00001f74, 0x00003bc6 },
+ { 0x00001f78, 0x00003be5 },
+ { 0x00001f7c, 0x00003c04 },
+ { 0x00001f80, 0x00003c24 },
+ { 0x00001f84, 0x00003c43 },
+ { 0x00001f88, 0x00003c62 },
+ { 0x00001f8c, 0x00003c82 },
+ { 0x00001f90, 0x00003ca1 },
+ { 0x00001f94, 0x00003cc0 },
+ { 0x00001f98, 0x00003ce0 },
+ { 0x00001f9c, 0x00003cff },
+ { 0x00001fa0, 0x00003d1f },
+ { 0x00001fa4, 0x00003d3f },
+ { 0x00001fa8, 0x00003d5e },
+ { 0x00001fac, 0x00003d7e },
+ { 0x00001fb0, 0x00003d9e },
+ { 0x00001fb4, 0x00003dbd },
+ { 0x00001fb8, 0x00003ddd },
+ { 0x00001fbc, 0x00003dfd },
+ { 0x00001fc0, 0x00003e1d },
+ { 0x00001fc4, 0x00003e3d },
+ { 0x00001fc8, 0x00003e5d },
+ { 0x00001fcc, 0x00003e7c },
+ { 0x00001fd0, 0x00003e9c },
+ { 0x00001fd4, 0x00003ebc },
+ { 0x00001fd8, 0x00003edc },
+ { 0x00001fdc, 0x00003efd },
+ { 0x00001fe0, 0x00003f1d },
+ { 0x00001fe4, 0x00003f3d },
+ { 0x00001fe8, 0x00003f5d },
+ { 0x00001fec, 0x00003f7d },
+ { 0x00001ff0, 0x00003f9e },
+ { 0x00001ff4, 0x00003fbe },
+ { 0x00001ff8, 0x00003fde },
+ { 0x00001ffc, 0x00003fff },
+};
+
+struct data_unit hdr10_pipe1_lut_a2[] = {
+ { 0x00002000, 0x00000000 },
+ { 0x00002004, 0x00000003 },
+ { 0x00002008, 0x00000007 },
+ { 0x0000200c, 0x0000000a },
+ { 0x00002010, 0x0000000e },
+ { 0x00002014, 0x00000011 },
+ { 0x00002018, 0x00000015 },
+ { 0x0000201c, 0x00000018 },
+ { 0x00002020, 0x0000001c },
+ { 0x00002024, 0x00000020 },
+ { 0x00002028, 0x00000023 },
+ { 0x0000202c, 0x00000027 },
+ { 0x00002030, 0x0000002a },
+ { 0x00002034, 0x0000002e },
+ { 0x00002038, 0x00000031 },
+ { 0x0000203c, 0x00000035 },
+ { 0x00002040, 0x00000038 },
+ { 0x00002044, 0x0000003c },
+ { 0x00002048, 0x00000040 },
+ { 0x0000204c, 0x00000043 },
+ { 0x00002050, 0x00000047 },
+ { 0x00002054, 0x0000004a },
+ { 0x00002058, 0x0000004e },
+ { 0x0000205c, 0x00000051 },
+ { 0x00002060, 0x00000055 },
+ { 0x00002064, 0x00000058 },
+ { 0x00002068, 0x0000005c },
+ { 0x0000206c, 0x00000060 },
+ { 0x00002070, 0x00000063 },
+ { 0x00002074, 0x00000067 },
+ { 0x00002078, 0x0000006a },
+ { 0x0000207c, 0x0000006e },
+ { 0x00002080, 0x00000071 },
+ { 0x00002084, 0x00000075 },
+ { 0x00002088, 0x00000078 },
+ { 0x0000208c, 0x0000007c },
+ { 0x00002090, 0x00000080 },
+ { 0x00002094, 0x00000083 },
+ { 0x00002098, 0x00000087 },
+ { 0x0000209c, 0x0000008a },
+ { 0x000020a0, 0x0000008e },
+ { 0x000020a4, 0x00000091 },
+ { 0x000020a8, 0x00000095 },
+ { 0x000020ac, 0x00000099 },
+ { 0x000020b0, 0x0000009c },
+ { 0x000020b4, 0x000000a0 },
+ { 0x000020b8, 0x000000a3 },
+ { 0x000020bc, 0x000000a7 },
+ { 0x000020c0, 0x000000aa },
+ { 0x000020c4, 0x000000ae },
+ { 0x000020c8, 0x000000b1 },
+ { 0x000020cc, 0x000000b5 },
+ { 0x000020d0, 0x000000b9 },
+ { 0x000020d4, 0x000000bc },
+ { 0x000020d8, 0x000000c0 },
+ { 0x000020dc, 0x000000c3 },
+ { 0x000020e0, 0x000000c7 },
+ { 0x000020e4, 0x000000ca },
+ { 0x000020e8, 0x000000ce },
+ { 0x000020ec, 0x000000d1 },
+ { 0x000020f0, 0x000000d5 },
+ { 0x000020f4, 0x000000d9 },
+ { 0x000020f8, 0x000000dc },
+ { 0x000020fc, 0x000000e0 },
+ { 0x00002100, 0x000000e3 },
+ { 0x00002104, 0x000000e7 },
+ { 0x00002108, 0x000000ea },
+ { 0x0000210c, 0x000000ee },
+ { 0x00002110, 0x000000f1 },
+ { 0x00002114, 0x000000f5 },
+ { 0x00002118, 0x000000f9 },
+ { 0x0000211c, 0x000000fc },
+ { 0x00002120, 0x00000100 },
+ { 0x00002124, 0x00000103 },
+ { 0x00002128, 0x00000107 },
+ { 0x0000212c, 0x0000010a },
+ { 0x00002130, 0x0000010e },
+ { 0x00002134, 0x00000112 },
+ { 0x00002138, 0x00000115 },
+ { 0x0000213c, 0x00000119 },
+ { 0x00002140, 0x0000011c },
+ { 0x00002144, 0x00000120 },
+ { 0x00002148, 0x00000123 },
+ { 0x0000214c, 0x00000126 },
+ { 0x00002150, 0x0000012a },
+ { 0x00002154, 0x0000012d },
+ { 0x00002158, 0x00000131 },
+ { 0x0000215c, 0x00000134 },
+ { 0x00002160, 0x00000138 },
+ { 0x00002164, 0x0000013c },
+ { 0x00002168, 0x0000013f },
+ { 0x0000216c, 0x00000143 },
+ { 0x00002170, 0x00000147 },
+ { 0x00002174, 0x0000014b },
+ { 0x00002178, 0x0000014e },
+ { 0x0000217c, 0x00000152 },
+ { 0x00002180, 0x00000156 },
+ { 0x00002184, 0x0000015a },
+ { 0x00002188, 0x0000015e },
+ { 0x0000218c, 0x00000162 },
+ { 0x00002190, 0x00000166 },
+ { 0x00002194, 0x0000016a },
+ { 0x00002198, 0x0000016e },
+ { 0x0000219c, 0x00000172 },
+ { 0x000021a0, 0x00000176 },
+ { 0x000021a4, 0x0000017a },
+ { 0x000021a8, 0x0000017e },
+ { 0x000021ac, 0x00000182 },
+ { 0x000021b0, 0x00000186 },
+ { 0x000021b4, 0x0000018a },
+ { 0x000021b8, 0x0000018f },
+ { 0x000021bc, 0x00000193 },
+ { 0x000021c0, 0x00000197 },
+ { 0x000021c4, 0x0000019b },
+ { 0x000021c8, 0x000001a0 },
+ { 0x000021cc, 0x000001a4 },
+ { 0x000021d0, 0x000001a8 },
+ { 0x000021d4, 0x000001ad },
+ { 0x000021d8, 0x000001b1 },
+ { 0x000021dc, 0x000001b5 },
+ { 0x000021e0, 0x000001ba },
+ { 0x000021e4, 0x000001be },
+ { 0x000021e8, 0x000001c3 },
+ { 0x000021ec, 0x000001c7 },
+ { 0x000021f0, 0x000001cc },
+ { 0x000021f4, 0x000001d0 },
+ { 0x000021f8, 0x000001d5 },
+ { 0x000021fc, 0x000001d9 },
+ { 0x00002200, 0x000001de },
+ { 0x00002204, 0x000001e3 },
+ { 0x00002208, 0x000001e7 },
+ { 0x0000220c, 0x000001ec },
+ { 0x00002210, 0x000001f1 },
+ { 0x00002214, 0x000001f6 },
+ { 0x00002218, 0x000001fa },
+ { 0x0000221c, 0x000001ff },
+ { 0x00002220, 0x00000204 },
+ { 0x00002224, 0x00000209 },
+ { 0x00002228, 0x0000020e },
+ { 0x0000222c, 0x00000213 },
+ { 0x00002230, 0x00000217 },
+ { 0x00002234, 0x0000021c },
+ { 0x00002238, 0x00000221 },
+ { 0x0000223c, 0x00000226 },
+ { 0x00002240, 0x0000022b },
+ { 0x00002244, 0x00000230 },
+ { 0x00002248, 0x00000236 },
+ { 0x0000224c, 0x0000023b },
+ { 0x00002250, 0x00000240 },
+ { 0x00002254, 0x00000245 },
+ { 0x00002258, 0x0000024a },
+ { 0x0000225c, 0x0000024f },
+ { 0x00002260, 0x00000255 },
+ { 0x00002264, 0x0000025a },
+ { 0x00002268, 0x0000025f },
+ { 0x0000226c, 0x00000264 },
+ { 0x00002270, 0x0000026a },
+ { 0x00002274, 0x0000026f },
+ { 0x00002278, 0x00000274 },
+ { 0x0000227c, 0x0000027a },
+ { 0x00002280, 0x0000027f },
+ { 0x00002284, 0x00000285 },
+ { 0x00002288, 0x0000028a },
+ { 0x0000228c, 0x00000290 },
+ { 0x00002290, 0x00000295 },
+ { 0x00002294, 0x0000029b },
+ { 0x00002298, 0x000002a0 },
+ { 0x0000229c, 0x000002a6 },
+ { 0x000022a0, 0x000002ac },
+ { 0x000022a4, 0x000002b1 },
+ { 0x000022a8, 0x000002b7 },
+ { 0x000022ac, 0x000002bd },
+ { 0x000022b0, 0x000002c2 },
+ { 0x000022b4, 0x000002c8 },
+ { 0x000022b8, 0x000002ce },
+ { 0x000022bc, 0x000002d4 },
+ { 0x000022c0, 0x000002da },
+ { 0x000022c4, 0x000002df },
+ { 0x000022c8, 0x000002e5 },
+ { 0x000022cc, 0x000002eb },
+ { 0x000022d0, 0x000002f1 },
+ { 0x000022d4, 0x000002f7 },
+ { 0x000022d8, 0x000002fd },
+ { 0x000022dc, 0x00000303 },
+ { 0x000022e0, 0x00000309 },
+ { 0x000022e4, 0x0000030f },
+ { 0x000022e8, 0x00000315 },
+ { 0x000022ec, 0x0000031c },
+ { 0x000022f0, 0x00000322 },
+ { 0x000022f4, 0x00000328 },
+ { 0x000022f8, 0x0000032e },
+ { 0x000022fc, 0x00000334 },
+ { 0x00002300, 0x0000033b },
+ { 0x00002304, 0x00000341 },
+ { 0x00002308, 0x00000347 },
+ { 0x0000230c, 0x0000034d },
+ { 0x00002310, 0x00000354 },
+ { 0x00002314, 0x0000035a },
+ { 0x00002318, 0x00000361 },
+ { 0x0000231c, 0x00000367 },
+ { 0x00002320, 0x0000036d },
+ { 0x00002324, 0x00000374 },
+ { 0x00002328, 0x0000037a },
+ { 0x0000232c, 0x00000381 },
+ { 0x00002330, 0x00000388 },
+ { 0x00002334, 0x0000038e },
+ { 0x00002338, 0x00000395 },
+ { 0x0000233c, 0x0000039b },
+ { 0x00002340, 0x000003a2 },
+ { 0x00002344, 0x000003a9 },
+ { 0x00002348, 0x000003b0 },
+ { 0x0000234c, 0x000003b6 },
+ { 0x00002350, 0x000003bd },
+ { 0x00002354, 0x000003c4 },
+ { 0x00002358, 0x000003cb },
+ { 0x0000235c, 0x000003d2 },
+ { 0x00002360, 0x000003d8 },
+ { 0x00002364, 0x000003df },
+ { 0x00002368, 0x000003e6 },
+ { 0x0000236c, 0x000003ed },
+ { 0x00002370, 0x000003f4 },
+ { 0x00002374, 0x000003fb },
+ { 0x00002378, 0x00000402 },
+ { 0x0000237c, 0x00000409 },
+ { 0x00002380, 0x00000411 },
+ { 0x00002384, 0x00000418 },
+ { 0x00002388, 0x0000041f },
+ { 0x0000238c, 0x00000426 },
+ { 0x00002390, 0x0000042d },
+ { 0x00002394, 0x00000434 },
+ { 0x00002398, 0x0000043c },
+ { 0x0000239c, 0x00000443 },
+ { 0x000023a0, 0x0000044a },
+ { 0x000023a4, 0x00000452 },
+ { 0x000023a8, 0x00000459 },
+ { 0x000023ac, 0x00000460 },
+ { 0x000023b0, 0x00000468 },
+ { 0x000023b4, 0x0000046f },
+ { 0x000023b8, 0x00000477 },
+ { 0x000023bc, 0x0000047e },
+ { 0x000023c0, 0x00000486 },
+ { 0x000023c4, 0x0000048d },
+ { 0x000023c8, 0x00000495 },
+ { 0x000023cc, 0x0000049c },
+ { 0x000023d0, 0x000004a4 },
+ { 0x000023d4, 0x000004ac },
+ { 0x000023d8, 0x000004b3 },
+ { 0x000023dc, 0x000004bb },
+ { 0x000023e0, 0x000004c3 },
+ { 0x000023e4, 0x000004cb },
+ { 0x000023e8, 0x000004d3 },
+ { 0x000023ec, 0x000004da },
+ { 0x000023f0, 0x000004e2 },
+ { 0x000023f4, 0x000004ea },
+ { 0x000023f8, 0x000004f2 },
+ { 0x000023fc, 0x000004fa },
+ { 0x00002400, 0x00000502 },
+ { 0x00002404, 0x0000050a },
+ { 0x00002408, 0x00000512 },
+ { 0x0000240c, 0x0000051a },
+ { 0x00002410, 0x00000522 },
+ { 0x00002414, 0x0000052a },
+ { 0x00002418, 0x00000532 },
+ { 0x0000241c, 0x0000053a },
+ { 0x00002420, 0x00000543 },
+ { 0x00002424, 0x0000054b },
+ { 0x00002428, 0x00000553 },
+ { 0x0000242c, 0x0000055b },
+ { 0x00002430, 0x00000564 },
+ { 0x00002434, 0x0000056c },
+ { 0x00002438, 0x00000574 },
+ { 0x0000243c, 0x0000057d },
+ { 0x00002440, 0x00000585 },
+ { 0x00002444, 0x0000058d },
+ { 0x00002448, 0x00000596 },
+ { 0x0000244c, 0x0000059e },
+ { 0x00002450, 0x000005a7 },
+ { 0x00002454, 0x000005af },
+ { 0x00002458, 0x000005b8 },
+ { 0x0000245c, 0x000005c1 },
+ { 0x00002460, 0x000005c9 },
+ { 0x00002464, 0x000005d2 },
+ { 0x00002468, 0x000005db },
+ { 0x0000246c, 0x000005e3 },
+ { 0x00002470, 0x000005ec },
+ { 0x00002474, 0x000005f5 },
+ { 0x00002478, 0x000005fe },
+ { 0x0000247c, 0x00000606 },
+ { 0x00002480, 0x0000060f },
+ { 0x00002484, 0x00000618 },
+ { 0x00002488, 0x00000621 },
+ { 0x0000248c, 0x0000062a },
+ { 0x00002490, 0x00000633 },
+ { 0x00002494, 0x0000063c },
+ { 0x00002498, 0x00000645 },
+ { 0x0000249c, 0x0000064e },
+ { 0x000024a0, 0x00000657 },
+ { 0x000024a4, 0x00000660 },
+ { 0x000024a8, 0x00000669 },
+ { 0x000024ac, 0x00000672 },
+ { 0x000024b0, 0x0000067b },
+ { 0x000024b4, 0x00000685 },
+ { 0x000024b8, 0x0000068e },
+ { 0x000024bc, 0x00000697 },
+ { 0x000024c0, 0x000006a0 },
+ { 0x000024c4, 0x000006aa },
+ { 0x000024c8, 0x000006b3 },
+ { 0x000024cc, 0x000006bd },
+ { 0x000024d0, 0x000006c6 },
+ { 0x000024d4, 0x000006cf },
+ { 0x000024d8, 0x000006d9 },
+ { 0x000024dc, 0x000006e2 },
+ { 0x000024e0, 0x000006ec },
+ { 0x000024e4, 0x000006f5 },
+ { 0x000024e8, 0x000006ff },
+ { 0x000024ec, 0x00000709 },
+ { 0x000024f0, 0x00000712 },
+ { 0x000024f4, 0x0000071c },
+ { 0x000024f8, 0x00000726 },
+ { 0x000024fc, 0x0000072f },
+ { 0x00002500, 0x00000739 },
+ { 0x00002504, 0x00000743 },
+ { 0x00002508, 0x0000074d },
+ { 0x0000250c, 0x00000756 },
+ { 0x00002510, 0x00000760 },
+ { 0x00002514, 0x0000076a },
+ { 0x00002518, 0x00000774 },
+ { 0x0000251c, 0x0000077e },
+ { 0x00002520, 0x00000788 },
+ { 0x00002524, 0x00000792 },
+ { 0x00002528, 0x0000079c },
+ { 0x0000252c, 0x000007a6 },
+ { 0x00002530, 0x000007b0 },
+ { 0x00002534, 0x000007ba },
+ { 0x00002538, 0x000007c4 },
+ { 0x0000253c, 0x000007cf },
+ { 0x00002540, 0x000007d9 },
+ { 0x00002544, 0x000007e3 },
+ { 0x00002548, 0x000007ed },
+ { 0x0000254c, 0x000007f7 },
+ { 0x00002550, 0x00000802 },
+ { 0x00002554, 0x0000080c },
+ { 0x00002558, 0x00000816 },
+ { 0x0000255c, 0x00000821 },
+ { 0x00002560, 0x0000082b },
+ { 0x00002564, 0x00000836 },
+ { 0x00002568, 0x00000840 },
+ { 0x0000256c, 0x0000084b },
+ { 0x00002570, 0x00000855 },
+ { 0x00002574, 0x00000860 },
+ { 0x00002578, 0x0000086a },
+ { 0x0000257c, 0x00000875 },
+ { 0x00002580, 0x00000880 },
+ { 0x00002584, 0x0000088a },
+ { 0x00002588, 0x00000895 },
+ { 0x0000258c, 0x000008a0 },
+ { 0x00002590, 0x000008ab },
+ { 0x00002594, 0x000008b5 },
+ { 0x00002598, 0x000008c0 },
+ { 0x0000259c, 0x000008cb },
+ { 0x000025a0, 0x000008d6 },
+ { 0x000025a4, 0x000008e1 },
+ { 0x000025a8, 0x000008ec },
+ { 0x000025ac, 0x000008f7 },
+ { 0x000025b0, 0x00000902 },
+ { 0x000025b4, 0x0000090d },
+ { 0x000025b8, 0x00000918 },
+ { 0x000025bc, 0x00000923 },
+ { 0x000025c0, 0x0000092e },
+ { 0x000025c4, 0x00000939 },
+ { 0x000025c8, 0x00000944 },
+ { 0x000025cc, 0x00000950 },
+ { 0x000025d0, 0x0000095b },
+ { 0x000025d4, 0x00000966 },
+ { 0x000025d8, 0x00000971 },
+ { 0x000025dc, 0x0000097d },
+ { 0x000025e0, 0x00000988 },
+ { 0x000025e4, 0x00000993 },
+ { 0x000025e8, 0x0000099f },
+ { 0x000025ec, 0x000009aa },
+ { 0x000025f0, 0x000009b6 },
+ { 0x000025f4, 0x000009c1 },
+ { 0x000025f8, 0x000009cd },
+ { 0x000025fc, 0x000009d8 },
+ { 0x00002600, 0x000009e4 },
+ { 0x00002604, 0x000009f0 },
+ { 0x00002608, 0x000009fb },
+ { 0x0000260c, 0x00000a07 },
+ { 0x00002610, 0x00000a13 },
+ { 0x00002614, 0x00000a1e },
+ { 0x00002618, 0x00000a2a },
+ { 0x0000261c, 0x00000a36 },
+ { 0x00002620, 0x00000a42 },
+ { 0x00002624, 0x00000a4e },
+ { 0x00002628, 0x00000a59 },
+ { 0x0000262c, 0x00000a65 },
+ { 0x00002630, 0x00000a71 },
+ { 0x00002634, 0x00000a7d },
+ { 0x00002638, 0x00000a89 },
+ { 0x0000263c, 0x00000a95 },
+ { 0x00002640, 0x00000aa1 },
+ { 0x00002644, 0x00000aad },
+ { 0x00002648, 0x00000ab9 },
+ { 0x0000264c, 0x00000ac6 },
+ { 0x00002650, 0x00000ad2 },
+ { 0x00002654, 0x00000ade },
+ { 0x00002658, 0x00000aea },
+ { 0x0000265c, 0x00000af6 },
+ { 0x00002660, 0x00000b03 },
+ { 0x00002664, 0x00000b0f },
+ { 0x00002668, 0x00000b1b },
+ { 0x0000266c, 0x00000b28 },
+ { 0x00002670, 0x00000b34 },
+ { 0x00002674, 0x00000b41 },
+ { 0x00002678, 0x00000b4d },
+ { 0x0000267c, 0x00000b5a },
+ { 0x00002680, 0x00000b66 },
+ { 0x00002684, 0x00000b73 },
+ { 0x00002688, 0x00000b7f },
+ { 0x0000268c, 0x00000b8c },
+ { 0x00002690, 0x00000b98 },
+ { 0x00002694, 0x00000ba5 },
+ { 0x00002698, 0x00000bb2 },
+ { 0x0000269c, 0x00000bbf },
+ { 0x000026a0, 0x00000bcb },
+ { 0x000026a4, 0x00000bd8 },
+ { 0x000026a8, 0x00000be5 },
+ { 0x000026ac, 0x00000bf2 },
+ { 0x000026b0, 0x00000bff },
+ { 0x000026b4, 0x00000c0c },
+ { 0x000026b8, 0x00000c19 },
+ { 0x000026bc, 0x00000c25 },
+ { 0x000026c0, 0x00000c32 },
+ { 0x000026c4, 0x00000c40 },
+ { 0x000026c8, 0x00000c4d },
+ { 0x000026cc, 0x00000c5a },
+ { 0x000026d0, 0x00000c67 },
+ { 0x000026d4, 0x00000c74 },
+ { 0x000026d8, 0x00000c81 },
+ { 0x000026dc, 0x00000c8e },
+ { 0x000026e0, 0x00000c9c },
+ { 0x000026e4, 0x00000ca9 },
+ { 0x000026e8, 0x00000cb6 },
+ { 0x000026ec, 0x00000cc3 },
+ { 0x000026f0, 0x00000cd1 },
+ { 0x000026f4, 0x00000cde },
+ { 0x000026f8, 0x00000cec },
+ { 0x000026fc, 0x00000cf9 },
+ { 0x00002700, 0x00000d07 },
+ { 0x00002704, 0x00000d14 },
+ { 0x00002708, 0x00000d22 },
+ { 0x0000270c, 0x00000d2f },
+ { 0x00002710, 0x00000d3d },
+ { 0x00002714, 0x00000d4a },
+ { 0x00002718, 0x00000d58 },
+ { 0x0000271c, 0x00000d66 },
+ { 0x00002720, 0x00000d73 },
+ { 0x00002724, 0x00000d81 },
+ { 0x00002728, 0x00000d8f },
+ { 0x0000272c, 0x00000d9d },
+ { 0x00002730, 0x00000dab },
+ { 0x00002734, 0x00000db8 },
+ { 0x00002738, 0x00000dc6 },
+ { 0x0000273c, 0x00000dd4 },
+ { 0x00002740, 0x00000de2 },
+ { 0x00002744, 0x00000df0 },
+ { 0x00002748, 0x00000dfe },
+ { 0x0000274c, 0x00000e0c },
+ { 0x00002750, 0x00000e1a },
+ { 0x00002754, 0x00000e29 },
+ { 0x00002758, 0x00000e37 },
+ { 0x0000275c, 0x00000e45 },
+ { 0x00002760, 0x00000e53 },
+ { 0x00002764, 0x00000e61 },
+ { 0x00002768, 0x00000e70 },
+ { 0x0000276c, 0x00000e7e },
+ { 0x00002770, 0x00000e8c },
+ { 0x00002774, 0x00000e9a },
+ { 0x00002778, 0x00000ea9 },
+ { 0x0000277c, 0x00000eb7 },
+ { 0x00002780, 0x00000ec6 },
+ { 0x00002784, 0x00000ed4 },
+ { 0x00002788, 0x00000ee3 },
+ { 0x0000278c, 0x00000ef1 },
+ { 0x00002790, 0x00000f00 },
+ { 0x00002794, 0x00000f0e },
+ { 0x00002798, 0x00000f1d },
+ { 0x0000279c, 0x00000f2c },
+ { 0x000027a0, 0x00000f3a },
+ { 0x000027a4, 0x00000f49 },
+ { 0x000027a8, 0x00000f58 },
+ { 0x000027ac, 0x00000f67 },
+ { 0x000027b0, 0x00000f75 },
+ { 0x000027b4, 0x00000f84 },
+ { 0x000027b8, 0x00000f93 },
+ { 0x000027bc, 0x00000fa2 },
+ { 0x000027c0, 0x00000fb1 },
+ { 0x000027c4, 0x00000fc0 },
+ { 0x000027c8, 0x00000fcf },
+ { 0x000027cc, 0x00000fde },
+ { 0x000027d0, 0x00000fed },
+ { 0x000027d4, 0x00000ffc },
+ { 0x000027d8, 0x0000100b },
+ { 0x000027dc, 0x0000101a },
+ { 0x000027e0, 0x0000102a },
+ { 0x000027e4, 0x00001039 },
+ { 0x000027e8, 0x00001048 },
+ { 0x000027ec, 0x00001057 },
+ { 0x000027f0, 0x00001067 },
+ { 0x000027f4, 0x00001076 },
+ { 0x000027f8, 0x00001085 },
+ { 0x000027fc, 0x00001095 },
+ { 0x00002800, 0x000010a4 },
+ { 0x00002804, 0x000010b4 },
+ { 0x00002808, 0x000010c3 },
+ { 0x0000280c, 0x000010d3 },
+ { 0x00002810, 0x000010e2 },
+ { 0x00002814, 0x000010f2 },
+ { 0x00002818, 0x00001101 },
+ { 0x0000281c, 0x00001111 },
+ { 0x00002820, 0x00001121 },
+ { 0x00002824, 0x00001130 },
+ { 0x00002828, 0x00001140 },
+ { 0x0000282c, 0x00001150 },
+ { 0x00002830, 0x00001160 },
+ { 0x00002834, 0x0000116f },
+ { 0x00002838, 0x0000117f },
+ { 0x0000283c, 0x0000118f },
+ { 0x00002840, 0x0000119f },
+ { 0x00002844, 0x000011af },
+ { 0x00002848, 0x000011bf },
+ { 0x0000284c, 0x000011cf },
+ { 0x00002850, 0x000011df },
+ { 0x00002854, 0x000011ef },
+ { 0x00002858, 0x000011ff },
+ { 0x0000285c, 0x0000120f },
+ { 0x00002860, 0x0000121f },
+ { 0x00002864, 0x00001230 },
+ { 0x00002868, 0x00001240 },
+ { 0x0000286c, 0x00001250 },
+ { 0x00002870, 0x00001260 },
+ { 0x00002874, 0x00001271 },
+ { 0x00002878, 0x00001281 },
+ { 0x0000287c, 0x00001291 },
+ { 0x00002880, 0x000012a2 },
+ { 0x00002884, 0x000012b2 },
+ { 0x00002888, 0x000012c3 },
+ { 0x0000288c, 0x000012d3 },
+ { 0x00002890, 0x000012e4 },
+ { 0x00002894, 0x000012f4 },
+ { 0x00002898, 0x00001305 },
+ { 0x0000289c, 0x00001316 },
+ { 0x000028a0, 0x00001326 },
+ { 0x000028a4, 0x00001337 },
+ { 0x000028a8, 0x00001348 },
+ { 0x000028ac, 0x00001359 },
+ { 0x000028b0, 0x00001369 },
+ { 0x000028b4, 0x0000137a },
+ { 0x000028b8, 0x0000138b },
+ { 0x000028bc, 0x0000139c },
+ { 0x000028c0, 0x000013ad },
+ { 0x000028c4, 0x000013be },
+ { 0x000028c8, 0x000013cf },
+ { 0x000028cc, 0x000013e0 },
+ { 0x000028d0, 0x000013f1 },
+ { 0x000028d4, 0x00001402 },
+ { 0x000028d8, 0x00001413 },
+ { 0x000028dc, 0x00001424 },
+ { 0x000028e0, 0x00001435 },
+ { 0x000028e4, 0x00001446 },
+ { 0x000028e8, 0x00001458 },
+ { 0x000028ec, 0x00001469 },
+ { 0x000028f0, 0x0000147a },
+ { 0x000028f4, 0x0000148b },
+ { 0x000028f8, 0x0000149d },
+ { 0x000028fc, 0x000014ae },
+ { 0x00002900, 0x000014c0 },
+ { 0x00002904, 0x000014d1 },
+ { 0x00002908, 0x000014e3 },
+ { 0x0000290c, 0x000014f4 },
+ { 0x00002910, 0x00001506 },
+ { 0x00002914, 0x00001517 },
+ { 0x00002918, 0x00001529 },
+ { 0x0000291c, 0x0000153a },
+ { 0x00002920, 0x0000154c },
+ { 0x00002924, 0x0000155e },
+ { 0x00002928, 0x0000156f },
+ { 0x0000292c, 0x00001581 },
+ { 0x00002930, 0x00001593 },
+ { 0x00002934, 0x000015a5 },
+ { 0x00002938, 0x000015b7 },
+ { 0x0000293c, 0x000015c9 },
+ { 0x00002940, 0x000015db },
+ { 0x00002944, 0x000015ec },
+ { 0x00002948, 0x000015fe },
+ { 0x0000294c, 0x00001610 },
+ { 0x00002950, 0x00001623 },
+ { 0x00002954, 0x00001635 },
+ { 0x00002958, 0x00001647 },
+ { 0x0000295c, 0x00001659 },
+ { 0x00002960, 0x0000166b },
+ { 0x00002964, 0x0000167d },
+ { 0x00002968, 0x0000168f },
+ { 0x0000296c, 0x000016a2 },
+ { 0x00002970, 0x000016b4 },
+ { 0x00002974, 0x000016c6 },
+ { 0x00002978, 0x000016d9 },
+ { 0x0000297c, 0x000016eb },
+ { 0x00002980, 0x000016fe },
+ { 0x00002984, 0x00001710 },
+ { 0x00002988, 0x00001722 },
+ { 0x0000298c, 0x00001735 },
+ { 0x00002990, 0x00001748 },
+ { 0x00002994, 0x0000175a },
+ { 0x00002998, 0x0000176d },
+ { 0x0000299c, 0x0000177f },
+ { 0x000029a0, 0x00001792 },
+ { 0x000029a4, 0x000017a5 },
+ { 0x000029a8, 0x000017b8 },
+ { 0x000029ac, 0x000017ca },
+ { 0x000029b0, 0x000017dd },
+ { 0x000029b4, 0x000017f0 },
+ { 0x000029b8, 0x00001803 },
+ { 0x000029bc, 0x00001816 },
+ { 0x000029c0, 0x00001829 },
+ { 0x000029c4, 0x0000183c },
+ { 0x000029c8, 0x0000184f },
+ { 0x000029cc, 0x00001862 },
+ { 0x000029d0, 0x00001875 },
+ { 0x000029d4, 0x00001888 },
+ { 0x000029d8, 0x0000189b },
+ { 0x000029dc, 0x000018ae },
+ { 0x000029e0, 0x000018c1 },
+ { 0x000029e4, 0x000018d5 },
+ { 0x000029e8, 0x000018e8 },
+ { 0x000029ec, 0x000018fb },
+ { 0x000029f0, 0x0000190e },
+ { 0x000029f4, 0x00001922 },
+ { 0x000029f8, 0x00001935 },
+ { 0x000029fc, 0x00001949 },
+ { 0x00002a00, 0x0000195c },
+ { 0x00002a04, 0x0000196f },
+ { 0x00002a08, 0x00001983 },
+ { 0x00002a0c, 0x00001996 },
+ { 0x00002a10, 0x000019aa },
+ { 0x00002a14, 0x000019be },
+ { 0x00002a18, 0x000019d1 },
+ { 0x00002a1c, 0x000019e5 },
+ { 0x00002a20, 0x000019f9 },
+ { 0x00002a24, 0x00001a0c },
+ { 0x00002a28, 0x00001a20 },
+ { 0x00002a2c, 0x00001a34 },
+ { 0x00002a30, 0x00001a48 },
+ { 0x00002a34, 0x00001a5c },
+ { 0x00002a38, 0x00001a70 },
+ { 0x00002a3c, 0x00001a84 },
+ { 0x00002a40, 0x00001a97 },
+ { 0x00002a44, 0x00001aab },
+ { 0x00002a48, 0x00001ac0 },
+ { 0x00002a4c, 0x00001ad4 },
+ { 0x00002a50, 0x00001ae8 },
+ { 0x00002a54, 0x00001afc },
+ { 0x00002a58, 0x00001b10 },
+ { 0x00002a5c, 0x00001b24 },
+ { 0x00002a60, 0x00001b38 },
+ { 0x00002a64, 0x00001b4d },
+ { 0x00002a68, 0x00001b61 },
+ { 0x00002a6c, 0x00001b75 },
+ { 0x00002a70, 0x00001b8a },
+ { 0x00002a74, 0x00001b9e },
+ { 0x00002a78, 0x00001bb2 },
+ { 0x00002a7c, 0x00001bc7 },
+ { 0x00002a80, 0x00001bdb },
+ { 0x00002a84, 0x00001bf0 },
+ { 0x00002a88, 0x00001c04 },
+ { 0x00002a8c, 0x00001c19 },
+ { 0x00002a90, 0x00001c2e },
+ { 0x00002a94, 0x00001c42 },
+ { 0x00002a98, 0x00001c57 },
+ { 0x00002a9c, 0x00001c6c },
+ { 0x00002aa0, 0x00001c80 },
+ { 0x00002aa4, 0x00001c95 },
+ { 0x00002aa8, 0x00001caa },
+ { 0x00002aac, 0x00001cbf },
+ { 0x00002ab0, 0x00001cd4 },
+ { 0x00002ab4, 0x00001ce8 },
+ { 0x00002ab8, 0x00001cfd },
+ { 0x00002abc, 0x00001d12 },
+ { 0x00002ac0, 0x00001d27 },
+ { 0x00002ac4, 0x00001d3c },
+ { 0x00002ac8, 0x00001d51 },
+ { 0x00002acc, 0x00001d67 },
+ { 0x00002ad0, 0x00001d7c },
+ { 0x00002ad4, 0x00001d91 },
+ { 0x00002ad8, 0x00001da6 },
+ { 0x00002adc, 0x00001dbb },
+ { 0x00002ae0, 0x00001dd1 },
+ { 0x00002ae4, 0x00001de6 },
+ { 0x00002ae8, 0x00001dfb },
+ { 0x00002aec, 0x00001e10 },
+ { 0x00002af0, 0x00001e26 },
+ { 0x00002af4, 0x00001e3b },
+ { 0x00002af8, 0x00001e51 },
+ { 0x00002afc, 0x00001e66 },
+ { 0x00002b00, 0x00001e7c },
+ { 0x00002b04, 0x00001e91 },
+ { 0x00002b08, 0x00001ea7 },
+ { 0x00002b0c, 0x00001ebd },
+ { 0x00002b10, 0x00001ed2 },
+ { 0x00002b14, 0x00001ee8 },
+ { 0x00002b18, 0x00001efe },
+ { 0x00002b1c, 0x00001f13 },
+ { 0x00002b20, 0x00001f29 },
+ { 0x00002b24, 0x00001f3f },
+ { 0x00002b28, 0x00001f55 },
+ { 0x00002b2c, 0x00001f6b },
+ { 0x00002b30, 0x00001f81 },
+ { 0x00002b34, 0x00001f96 },
+ { 0x00002b38, 0x00001fac },
+ { 0x00002b3c, 0x00001fc2 },
+ { 0x00002b40, 0x00001fd9 },
+ { 0x00002b44, 0x00001fef },
+ { 0x00002b48, 0x00002005 },
+ { 0x00002b4c, 0x0000201b },
+ { 0x00002b50, 0x00002031 },
+ { 0x00002b54, 0x00002047 },
+ { 0x00002b58, 0x0000205d },
+ { 0x00002b5c, 0x00002074 },
+ { 0x00002b60, 0x0000208a },
+ { 0x00002b64, 0x000020a0 },
+ { 0x00002b68, 0x000020b7 },
+ { 0x00002b6c, 0x000020cd },
+ { 0x00002b70, 0x000020e4 },
+ { 0x00002b74, 0x000020fa },
+ { 0x00002b78, 0x00002111 },
+ { 0x00002b7c, 0x00002127 },
+ { 0x00002b80, 0x0000213e },
+ { 0x00002b84, 0x00002154 },
+ { 0x00002b88, 0x0000216b },
+ { 0x00002b8c, 0x00002182 },
+ { 0x00002b90, 0x00002198 },
+ { 0x00002b94, 0x000021af },
+ { 0x00002b98, 0x000021c6 },
+ { 0x00002b9c, 0x000021dd },
+ { 0x00002ba0, 0x000021f3 },
+ { 0x00002ba4, 0x0000220a },
+ { 0x00002ba8, 0x00002221 },
+ { 0x00002bac, 0x00002238 },
+ { 0x00002bb0, 0x0000224f },
+ { 0x00002bb4, 0x00002266 },
+ { 0x00002bb8, 0x0000227d },
+ { 0x00002bbc, 0x00002294 },
+ { 0x00002bc0, 0x000022ab },
+ { 0x00002bc4, 0x000022c2 },
+ { 0x00002bc8, 0x000022da },
+ { 0x00002bcc, 0x000022f1 },
+ { 0x00002bd0, 0x00002308 },
+ { 0x00002bd4, 0x0000231f },
+ { 0x00002bd8, 0x00002337 },
+ { 0x00002bdc, 0x0000234e },
+ { 0x00002be0, 0x00002365 },
+ { 0x00002be4, 0x0000237d },
+ { 0x00002be8, 0x00002394 },
+ { 0x00002bec, 0x000023ac },
+ { 0x00002bf0, 0x000023c3 },
+ { 0x00002bf4, 0x000023db },
+ { 0x00002bf8, 0x000023f2 },
+ { 0x00002bfc, 0x0000240a },
+ { 0x00002c00, 0x00002421 },
+ { 0x00002c04, 0x00002439 },
+ { 0x00002c08, 0x00002451 },
+ { 0x00002c0c, 0x00002469 },
+ { 0x00002c10, 0x00002480 },
+ { 0x00002c14, 0x00002498 },
+ { 0x00002c18, 0x000024b0 },
+ { 0x00002c1c, 0x000024c8 },
+ { 0x00002c20, 0x000024e0 },
+ { 0x00002c24, 0x000024f8 },
+ { 0x00002c28, 0x00002510 },
+ { 0x00002c2c, 0x00002528 },
+ { 0x00002c30, 0x00002540 },
+ { 0x00002c34, 0x00002558 },
+ { 0x00002c38, 0x00002570 },
+ { 0x00002c3c, 0x00002588 },
+ { 0x00002c40, 0x000025a0 },
+ { 0x00002c44, 0x000025b8 },
+ { 0x00002c48, 0x000025d0 },
+ { 0x00002c4c, 0x000025e9 },
+ { 0x00002c50, 0x00002601 },
+ { 0x00002c54, 0x00002619 },
+ { 0x00002c58, 0x00002632 },
+ { 0x00002c5c, 0x0000264a },
+ { 0x00002c60, 0x00002663 },
+ { 0x00002c64, 0x0000267b },
+ { 0x00002c68, 0x00002693 },
+ { 0x00002c6c, 0x000026ac },
+ { 0x00002c70, 0x000026c5 },
+ { 0x00002c74, 0x000026dd },
+ { 0x00002c78, 0x000026f6 },
+ { 0x00002c7c, 0x0000270e },
+ { 0x00002c80, 0x00002727 },
+ { 0x00002c84, 0x00002740 },
+ { 0x00002c88, 0x00002759 },
+ { 0x00002c8c, 0x00002771 },
+ { 0x00002c90, 0x0000278a },
+ { 0x00002c94, 0x000027a3 },
+ { 0x00002c98, 0x000027bc },
+ { 0x00002c9c, 0x000027d5 },
+ { 0x00002ca0, 0x000027ee },
+ { 0x00002ca4, 0x00002807 },
+ { 0x00002ca8, 0x00002820 },
+ { 0x00002cac, 0x00002839 },
+ { 0x00002cb0, 0x00002852 },
+ { 0x00002cb4, 0x0000286b },
+ { 0x00002cb8, 0x00002884 },
+ { 0x00002cbc, 0x0000289e },
+ { 0x00002cc0, 0x000028b7 },
+ { 0x00002cc4, 0x000028d0 },
+ { 0x00002cc8, 0x000028e9 },
+ { 0x00002ccc, 0x00002903 },
+ { 0x00002cd0, 0x0000291c },
+ { 0x00002cd4, 0x00002936 },
+ { 0x00002cd8, 0x0000294f },
+ { 0x00002cdc, 0x00002968 },
+ { 0x00002ce0, 0x00002982 },
+ { 0x00002ce4, 0x0000299c },
+ { 0x00002ce8, 0x000029b5 },
+ { 0x00002cec, 0x000029cf },
+ { 0x00002cf0, 0x000029e8 },
+ { 0x00002cf4, 0x00002a02 },
+ { 0x00002cf8, 0x00002a1c },
+ { 0x00002cfc, 0x00002a35 },
+ { 0x00002d00, 0x00002a4f },
+ { 0x00002d04, 0x00002a69 },
+ { 0x00002d08, 0x00002a83 },
+ { 0x00002d0c, 0x00002a9d },
+ { 0x00002d10, 0x00002ab7 },
+ { 0x00002d14, 0x00002ad1 },
+ { 0x00002d18, 0x00002aeb },
+ { 0x00002d1c, 0x00002b05 },
+ { 0x00002d20, 0x00002b1f },
+ { 0x00002d24, 0x00002b39 },
+ { 0x00002d28, 0x00002b53 },
+ { 0x00002d2c, 0x00002b6d },
+ { 0x00002d30, 0x00002b87 },
+ { 0x00002d34, 0x00002ba1 },
+ { 0x00002d38, 0x00002bbc },
+ { 0x00002d3c, 0x00002bd6 },
+ { 0x00002d40, 0x00002bf0 },
+ { 0x00002d44, 0x00002c0b },
+ { 0x00002d48, 0x00002c25 },
+ { 0x00002d4c, 0x00002c3f },
+ { 0x00002d50, 0x00002c5a },
+ { 0x00002d54, 0x00002c74 },
+ { 0x00002d58, 0x00002c8f },
+ { 0x00002d5c, 0x00002ca9 },
+ { 0x00002d60, 0x00002cc4 },
+ { 0x00002d64, 0x00002cdf },
+ { 0x00002d68, 0x00002cf9 },
+ { 0x00002d6c, 0x00002d14 },
+ { 0x00002d70, 0x00002d2f },
+ { 0x00002d74, 0x00002d49 },
+ { 0x00002d78, 0x00002d64 },
+ { 0x00002d7c, 0x00002d7f },
+ { 0x00002d80, 0x00002d9a },
+ { 0x00002d84, 0x00002db5 },
+ { 0x00002d88, 0x00002dd0 },
+ { 0x00002d8c, 0x00002deb },
+ { 0x00002d90, 0x00002e06 },
+ { 0x00002d94, 0x00002e21 },
+ { 0x00002d98, 0x00002e3c },
+ { 0x00002d9c, 0x00002e57 },
+ { 0x00002da0, 0x00002e72 },
+ { 0x00002da4, 0x00002e8d },
+ { 0x00002da8, 0x00002ea8 },
+ { 0x00002dac, 0x00002ec4 },
+ { 0x00002db0, 0x00002edf },
+ { 0x00002db4, 0x00002efa },
+ { 0x00002db8, 0x00002f16 },
+ { 0x00002dbc, 0x00002f31 },
+ { 0x00002dc0, 0x00002f4c },
+ { 0x00002dc4, 0x00002f68 },
+ { 0x00002dc8, 0x00002f83 },
+ { 0x00002dcc, 0x00002f9f },
+ { 0x00002dd0, 0x00002fba },
+ { 0x00002dd4, 0x00002fd6 },
+ { 0x00002dd8, 0x00002ff1 },
+ { 0x00002ddc, 0x0000300d },
+ { 0x00002de0, 0x00003029 },
+ { 0x00002de4, 0x00003044 },
+ { 0x00002de8, 0x00003060 },
+ { 0x00002dec, 0x0000307c },
+ { 0x00002df0, 0x00003098 },
+ { 0x00002df4, 0x000030b4 },
+ { 0x00002df8, 0x000030d0 },
+ { 0x00002dfc, 0x000030eb },
+ { 0x00002e00, 0x00003107 },
+ { 0x00002e04, 0x00003123 },
+ { 0x00002e08, 0x0000313f },
+ { 0x00002e0c, 0x0000315b },
+ { 0x00002e10, 0x00003178 },
+ { 0x00002e14, 0x00003194 },
+ { 0x00002e18, 0x000031b0 },
+ { 0x00002e1c, 0x000031cc },
+ { 0x00002e20, 0x000031e8 },
+ { 0x00002e24, 0x00003205 },
+ { 0x00002e28, 0x00003221 },
+ { 0x00002e2c, 0x0000323d },
+ { 0x00002e30, 0x0000325a },
+ { 0x00002e34, 0x00003276 },
+ { 0x00002e38, 0x00003292 },
+ { 0x00002e3c, 0x000032af },
+ { 0x00002e40, 0x000032cb },
+ { 0x00002e44, 0x000032e8 },
+ { 0x00002e48, 0x00003304 },
+ { 0x00002e4c, 0x00003321 },
+ { 0x00002e50, 0x0000333e },
+ { 0x00002e54, 0x0000335a },
+ { 0x00002e58, 0x00003377 },
+ { 0x00002e5c, 0x00003394 },
+ { 0x00002e60, 0x000033b1 },
+ { 0x00002e64, 0x000033cd },
+ { 0x00002e68, 0x000033ea },
+ { 0x00002e6c, 0x00003407 },
+ { 0x00002e70, 0x00003424 },
+ { 0x00002e74, 0x00003441 },
+ { 0x00002e78, 0x0000345e },
+ { 0x00002e7c, 0x0000347b },
+ { 0x00002e80, 0x00003498 },
+ { 0x00002e84, 0x000034b5 },
+ { 0x00002e88, 0x000034d2 },
+ { 0x00002e8c, 0x000034ef },
+ { 0x00002e90, 0x0000350d },
+ { 0x00002e94, 0x0000352a },
+ { 0x00002e98, 0x00003547 },
+ { 0x00002e9c, 0x00003564 },
+ { 0x00002ea0, 0x00003582 },
+ { 0x00002ea4, 0x0000359f },
+ { 0x00002ea8, 0x000035bc },
+ { 0x00002eac, 0x000035da },
+ { 0x00002eb0, 0x000035f7 },
+ { 0x00002eb4, 0x00003615 },
+ { 0x00002eb8, 0x00003632 },
+ { 0x00002ebc, 0x00003650 },
+ { 0x00002ec0, 0x0000366e },
+ { 0x00002ec4, 0x0000368b },
+ { 0x00002ec8, 0x000036a9 },
+ { 0x00002ecc, 0x000036c7 },
+ { 0x00002ed0, 0x000036e4 },
+ { 0x00002ed4, 0x00003702 },
+ { 0x00002ed8, 0x00003720 },
+ { 0x00002edc, 0x0000373e },
+ { 0x00002ee0, 0x0000375c },
+ { 0x00002ee4, 0x0000377a },
+ { 0x00002ee8, 0x00003798 },
+ { 0x00002eec, 0x000037b6 },
+ { 0x00002ef0, 0x000037d4 },
+ { 0x00002ef4, 0x000037f2 },
+ { 0x00002ef8, 0x00003810 },
+ { 0x00002efc, 0x0000382e },
+ { 0x00002f00, 0x0000384c },
+ { 0x00002f04, 0x0000386a },
+ { 0x00002f08, 0x00003888 },
+ { 0x00002f0c, 0x000038a7 },
+ { 0x00002f10, 0x000038c5 },
+ { 0x00002f14, 0x000038e3 },
+ { 0x00002f18, 0x00003902 },
+ { 0x00002f1c, 0x00003920 },
+ { 0x00002f20, 0x0000393f },
+ { 0x00002f24, 0x0000395d },
+ { 0x00002f28, 0x0000397c },
+ { 0x00002f2c, 0x0000399a },
+ { 0x00002f30, 0x000039b9 },
+ { 0x00002f34, 0x000039d7 },
+ { 0x00002f38, 0x000039f6 },
+ { 0x00002f3c, 0x00003a15 },
+ { 0x00002f40, 0x00003a33 },
+ { 0x00002f44, 0x00003a52 },
+ { 0x00002f48, 0x00003a71 },
+ { 0x00002f4c, 0x00003a90 },
+ { 0x00002f50, 0x00003aaf },
+ { 0x00002f54, 0x00003acd },
+ { 0x00002f58, 0x00003aec },
+ { 0x00002f5c, 0x00003b0b },
+ { 0x00002f60, 0x00003b2a },
+ { 0x00002f64, 0x00003b49 },
+ { 0x00002f68, 0x00003b68 },
+ { 0x00002f6c, 0x00003b87 },
+ { 0x00002f70, 0x00003ba7 },
+ { 0x00002f74, 0x00003bc6 },
+ { 0x00002f78, 0x00003be5 },
+ { 0x00002f7c, 0x00003c04 },
+ { 0x00002f80, 0x00003c24 },
+ { 0x00002f84, 0x00003c43 },
+ { 0x00002f88, 0x00003c62 },
+ { 0x00002f8c, 0x00003c82 },
+ { 0x00002f90, 0x00003ca1 },
+ { 0x00002f94, 0x00003cc0 },
+ { 0x00002f98, 0x00003ce0 },
+ { 0x00002f9c, 0x00003cff },
+ { 0x00002fa0, 0x00003d1f },
+ { 0x00002fa4, 0x00003d3f },
+ { 0x00002fa8, 0x00003d5e },
+ { 0x00002fac, 0x00003d7e },
+ { 0x00002fb0, 0x00003d9e },
+ { 0x00002fb4, 0x00003dbd },
+ { 0x00002fb8, 0x00003ddd },
+ { 0x00002fbc, 0x00003dfd },
+ { 0x00002fc0, 0x00003e1d },
+ { 0x00002fc4, 0x00003e3d },
+ { 0x00002fc8, 0x00003e5d },
+ { 0x00002fcc, 0x00003e7c },
+ { 0x00002fd0, 0x00003e9c },
+ { 0x00002fd4, 0x00003ebc },
+ { 0x00002fd8, 0x00003edc },
+ { 0x00002fdc, 0x00003efd },
+ { 0x00002fe0, 0x00003f1d },
+ { 0x00002fe4, 0x00003f3d },
+ { 0x00002fe8, 0x00003f5d },
+ { 0x00002fec, 0x00003f7d },
+ { 0x00002ff0, 0x00003f9e },
+ { 0x00002ff4, 0x00003fbe },
+ { 0x00002ff8, 0x00003fde },
+ { 0x00002ffc, 0x00003fff },
+};
+
+struct data_unit hdr10_pipe1_csca[] = {
+ { 0x00003004, 0x00004000 },
+ { 0x00003014, 0x00004000 },
+ { 0x00003024, 0x00004000 },
+ { 0x00003040, 0x000003ff },
+ { 0x00003044, 0x000003ff },
+ { 0x00003048, 0x000003ff },
+ { 0x0000304c, 0x0000000e },
+ { 0x00003068, 0x000003ff },
+ { 0x0000306c, 0x000003ff },
+ { 0x00003070, 0x000003ff },
+ { 0x00003080, 0x00000003 },
+ { 0x00003000, 0x00000003 },
+};
+
+struct data_unit hdr10_pipe1_cscb[] = {
+ { 0x00003804, 0x00007fe2 },
+ { 0x00003814, 0x00007fe2 },
+ { 0x00003824, 0x00007fe2 },
+ { 0x00003840, 0x00003fff },
+ { 0x00003844, 0x00003fff },
+ { 0x00003848, 0x00003fff },
+ { 0x0000384c, 0x00000001 },
+ { 0x00003868, 0x0ffc0000 },
+ { 0x0000386c, 0x0ffc0000 },
+ { 0x00003870, 0x0ffc0000 },
+ { 0x00003874, 0x00000000 },
+ { 0x00003800, 0x00000003 },
+};
+
+struct data_unit hdr10_pipe2_lut_a0[] = {
+ { 0x00004000, 0x00000000 },
+ { 0x00004004, 0x00000003 },
+ { 0x00004008, 0x00000007 },
+ { 0x0000400c, 0x0000000a },
+ { 0x00004010, 0x0000000e },
+ { 0x00004014, 0x00000011 },
+ { 0x00004018, 0x00000015 },
+ { 0x0000401c, 0x00000018 },
+ { 0x00004020, 0x0000001c },
+ { 0x00004024, 0x00000020 },
+ { 0x00004028, 0x00000023 },
+ { 0x0000402c, 0x00000027 },
+ { 0x00004030, 0x0000002a },
+ { 0x00004034, 0x0000002e },
+ { 0x00004038, 0x00000031 },
+ { 0x0000403c, 0x00000035 },
+ { 0x00004040, 0x00000038 },
+ { 0x00004044, 0x0000003c },
+ { 0x00004048, 0x00000040 },
+ { 0x0000404c, 0x00000043 },
+ { 0x00004050, 0x00000047 },
+ { 0x00004054, 0x0000004a },
+ { 0x00004058, 0x0000004e },
+ { 0x0000405c, 0x00000051 },
+ { 0x00004060, 0x00000055 },
+ { 0x00004064, 0x00000058 },
+ { 0x00004068, 0x0000005c },
+ { 0x0000406c, 0x00000060 },
+ { 0x00004070, 0x00000063 },
+ { 0x00004074, 0x00000067 },
+ { 0x00004078, 0x0000006a },
+ { 0x0000407c, 0x0000006e },
+ { 0x00004080, 0x00000071 },
+ { 0x00004084, 0x00000075 },
+ { 0x00004088, 0x00000078 },
+ { 0x0000408c, 0x0000007c },
+ { 0x00004090, 0x00000080 },
+ { 0x00004094, 0x00000083 },
+ { 0x00004098, 0x00000087 },
+ { 0x0000409c, 0x0000008a },
+ { 0x000040a0, 0x0000008e },
+ { 0x000040a4, 0x00000091 },
+ { 0x000040a8, 0x00000095 },
+ { 0x000040ac, 0x00000099 },
+ { 0x000040b0, 0x0000009c },
+ { 0x000040b4, 0x000000a0 },
+ { 0x000040b8, 0x000000a3 },
+ { 0x000040bc, 0x000000a7 },
+ { 0x000040c0, 0x000000aa },
+ { 0x000040c4, 0x000000ae },
+ { 0x000040c8, 0x000000b1 },
+ { 0x000040cc, 0x000000b5 },
+ { 0x000040d0, 0x000000b9 },
+ { 0x000040d4, 0x000000bc },
+ { 0x000040d8, 0x000000c0 },
+ { 0x000040dc, 0x000000c3 },
+ { 0x000040e0, 0x000000c7 },
+ { 0x000040e4, 0x000000ca },
+ { 0x000040e8, 0x000000ce },
+ { 0x000040ec, 0x000000d1 },
+ { 0x000040f0, 0x000000d5 },
+ { 0x000040f4, 0x000000d9 },
+ { 0x000040f8, 0x000000dc },
+ { 0x000040fc, 0x000000e0 },
+ { 0x00004100, 0x000000e3 },
+ { 0x00004104, 0x000000e7 },
+ { 0x00004108, 0x000000ea },
+ { 0x0000410c, 0x000000ee },
+ { 0x00004110, 0x000000f1 },
+ { 0x00004114, 0x000000f5 },
+ { 0x00004118, 0x000000f9 },
+ { 0x0000411c, 0x000000fc },
+ { 0x00004120, 0x00000100 },
+ { 0x00004124, 0x00000103 },
+ { 0x00004128, 0x00000107 },
+ { 0x0000412c, 0x0000010a },
+ { 0x00004130, 0x0000010e },
+ { 0x00004134, 0x00000112 },
+ { 0x00004138, 0x00000115 },
+ { 0x0000413c, 0x00000119 },
+ { 0x00004140, 0x0000011c },
+ { 0x00004144, 0x00000120 },
+ { 0x00004148, 0x00000123 },
+ { 0x0000414c, 0x00000126 },
+ { 0x00004150, 0x0000012a },
+ { 0x00004154, 0x0000012d },
+ { 0x00004158, 0x00000131 },
+ { 0x0000415c, 0x00000134 },
+ { 0x00004160, 0x00000138 },
+ { 0x00004164, 0x0000013c },
+ { 0x00004168, 0x0000013f },
+ { 0x0000416c, 0x00000143 },
+ { 0x00004170, 0x00000147 },
+ { 0x00004174, 0x0000014b },
+ { 0x00004178, 0x0000014e },
+ { 0x0000417c, 0x00000152 },
+ { 0x00004180, 0x00000156 },
+ { 0x00004184, 0x0000015a },
+ { 0x00004188, 0x0000015e },
+ { 0x0000418c, 0x00000162 },
+ { 0x00004190, 0x00000166 },
+ { 0x00004194, 0x0000016a },
+ { 0x00004198, 0x0000016e },
+ { 0x0000419c, 0x00000172 },
+ { 0x000041a0, 0x00000176 },
+ { 0x000041a4, 0x0000017a },
+ { 0x000041a8, 0x0000017e },
+ { 0x000041ac, 0x00000182 },
+ { 0x000041b0, 0x00000186 },
+ { 0x000041b4, 0x0000018a },
+ { 0x000041b8, 0x0000018f },
+ { 0x000041bc, 0x00000193 },
+ { 0x000041c0, 0x00000197 },
+ { 0x000041c4, 0x0000019b },
+ { 0x000041c8, 0x000001a0 },
+ { 0x000041cc, 0x000001a4 },
+ { 0x000041d0, 0x000001a8 },
+ { 0x000041d4, 0x000001ad },
+ { 0x000041d8, 0x000001b1 },
+ { 0x000041dc, 0x000001b5 },
+ { 0x000041e0, 0x000001ba },
+ { 0x000041e4, 0x000001be },
+ { 0x000041e8, 0x000001c3 },
+ { 0x000041ec, 0x000001c7 },
+ { 0x000041f0, 0x000001cc },
+ { 0x000041f4, 0x000001d0 },
+ { 0x000041f8, 0x000001d5 },
+ { 0x000041fc, 0x000001d9 },
+ { 0x00004200, 0x000001de },
+ { 0x00004204, 0x000001e3 },
+ { 0x00004208, 0x000001e7 },
+ { 0x0000420c, 0x000001ec },
+ { 0x00004210, 0x000001f1 },
+ { 0x00004214, 0x000001f6 },
+ { 0x00004218, 0x000001fa },
+ { 0x0000421c, 0x000001ff },
+ { 0x00004220, 0x00000204 },
+ { 0x00004224, 0x00000209 },
+ { 0x00004228, 0x0000020e },
+ { 0x0000422c, 0x00000213 },
+ { 0x00004230, 0x00000217 },
+ { 0x00004234, 0x0000021c },
+ { 0x00004238, 0x00000221 },
+ { 0x0000423c, 0x00000226 },
+ { 0x00004240, 0x0000022b },
+ { 0x00004244, 0x00000230 },
+ { 0x00004248, 0x00000236 },
+ { 0x0000424c, 0x0000023b },
+ { 0x00004250, 0x00000240 },
+ { 0x00004254, 0x00000245 },
+ { 0x00004258, 0x0000024a },
+ { 0x0000425c, 0x0000024f },
+ { 0x00004260, 0x00000255 },
+ { 0x00004264, 0x0000025a },
+ { 0x00004268, 0x0000025f },
+ { 0x0000426c, 0x00000264 },
+ { 0x00004270, 0x0000026a },
+ { 0x00004274, 0x0000026f },
+ { 0x00004278, 0x00000274 },
+ { 0x0000427c, 0x0000027a },
+ { 0x00004280, 0x0000027f },
+ { 0x00004284, 0x00000285 },
+ { 0x00004288, 0x0000028a },
+ { 0x0000428c, 0x00000290 },
+ { 0x00004290, 0x00000295 },
+ { 0x00004294, 0x0000029b },
+ { 0x00004298, 0x000002a0 },
+ { 0x0000429c, 0x000002a6 },
+ { 0x000042a0, 0x000002ac },
+ { 0x000042a4, 0x000002b1 },
+ { 0x000042a8, 0x000002b7 },
+ { 0x000042ac, 0x000002bd },
+ { 0x000042b0, 0x000002c2 },
+ { 0x000042b4, 0x000002c8 },
+ { 0x000042b8, 0x000002ce },
+ { 0x000042bc, 0x000002d4 },
+ { 0x000042c0, 0x000002da },
+ { 0x000042c4, 0x000002df },
+ { 0x000042c8, 0x000002e5 },
+ { 0x000042cc, 0x000002eb },
+ { 0x000042d0, 0x000002f1 },
+ { 0x000042d4, 0x000002f7 },
+ { 0x000042d8, 0x000002fd },
+ { 0x000042dc, 0x00000303 },
+ { 0x000042e0, 0x00000309 },
+ { 0x000042e4, 0x0000030f },
+ { 0x000042e8, 0x00000315 },
+ { 0x000042ec, 0x0000031c },
+ { 0x000042f0, 0x00000322 },
+ { 0x000042f4, 0x00000328 },
+ { 0x000042f8, 0x0000032e },
+ { 0x000042fc, 0x00000334 },
+ { 0x00004300, 0x0000033b },
+ { 0x00004304, 0x00000341 },
+ { 0x00004308, 0x00000347 },
+ { 0x0000430c, 0x0000034d },
+ { 0x00004310, 0x00000354 },
+ { 0x00004314, 0x0000035a },
+ { 0x00004318, 0x00000361 },
+ { 0x0000431c, 0x00000367 },
+ { 0x00004320, 0x0000036d },
+ { 0x00004324, 0x00000374 },
+ { 0x00004328, 0x0000037a },
+ { 0x0000432c, 0x00000381 },
+ { 0x00004330, 0x00000388 },
+ { 0x00004334, 0x0000038e },
+ { 0x00004338, 0x00000395 },
+ { 0x0000433c, 0x0000039b },
+ { 0x00004340, 0x000003a2 },
+ { 0x00004344, 0x000003a9 },
+ { 0x00004348, 0x000003b0 },
+ { 0x0000434c, 0x000003b6 },
+ { 0x00004350, 0x000003bd },
+ { 0x00004354, 0x000003c4 },
+ { 0x00004358, 0x000003cb },
+ { 0x0000435c, 0x000003d2 },
+ { 0x00004360, 0x000003d8 },
+ { 0x00004364, 0x000003df },
+ { 0x00004368, 0x000003e6 },
+ { 0x0000436c, 0x000003ed },
+ { 0x00004370, 0x000003f4 },
+ { 0x00004374, 0x000003fb },
+ { 0x00004378, 0x00000402 },
+ { 0x0000437c, 0x00000409 },
+ { 0x00004380, 0x00000411 },
+ { 0x00004384, 0x00000418 },
+ { 0x00004388, 0x0000041f },
+ { 0x0000438c, 0x00000426 },
+ { 0x00004390, 0x0000042d },
+ { 0x00004394, 0x00000434 },
+ { 0x00004398, 0x0000043c },
+ { 0x0000439c, 0x00000443 },
+ { 0x000043a0, 0x0000044a },
+ { 0x000043a4, 0x00000452 },
+ { 0x000043a8, 0x00000459 },
+ { 0x000043ac, 0x00000460 },
+ { 0x000043b0, 0x00000468 },
+ { 0x000043b4, 0x0000046f },
+ { 0x000043b8, 0x00000477 },
+ { 0x000043bc, 0x0000047e },
+ { 0x000043c0, 0x00000486 },
+ { 0x000043c4, 0x0000048d },
+ { 0x000043c8, 0x00000495 },
+ { 0x000043cc, 0x0000049c },
+ { 0x000043d0, 0x000004a4 },
+ { 0x000043d4, 0x000004ac },
+ { 0x000043d8, 0x000004b3 },
+ { 0x000043dc, 0x000004bb },
+ { 0x000043e0, 0x000004c3 },
+ { 0x000043e4, 0x000004cb },
+ { 0x000043e8, 0x000004d3 },
+ { 0x000043ec, 0x000004da },
+ { 0x000043f0, 0x000004e2 },
+ { 0x000043f4, 0x000004ea },
+ { 0x000043f8, 0x000004f2 },
+ { 0x000043fc, 0x000004fa },
+ { 0x00004400, 0x00000502 },
+ { 0x00004404, 0x0000050a },
+ { 0x00004408, 0x00000512 },
+ { 0x0000440c, 0x0000051a },
+ { 0x00004410, 0x00000522 },
+ { 0x00004414, 0x0000052a },
+ { 0x00004418, 0x00000532 },
+ { 0x0000441c, 0x0000053a },
+ { 0x00004420, 0x00000543 },
+ { 0x00004424, 0x0000054b },
+ { 0x00004428, 0x00000553 },
+ { 0x0000442c, 0x0000055b },
+ { 0x00004430, 0x00000564 },
+ { 0x00004434, 0x0000056c },
+ { 0x00004438, 0x00000574 },
+ { 0x0000443c, 0x0000057d },
+ { 0x00004440, 0x00000585 },
+ { 0x00004444, 0x0000058d },
+ { 0x00004448, 0x00000596 },
+ { 0x0000444c, 0x0000059e },
+ { 0x00004450, 0x000005a7 },
+ { 0x00004454, 0x000005af },
+ { 0x00004458, 0x000005b8 },
+ { 0x0000445c, 0x000005c1 },
+ { 0x00004460, 0x000005c9 },
+ { 0x00004464, 0x000005d2 },
+ { 0x00004468, 0x000005db },
+ { 0x0000446c, 0x000005e3 },
+ { 0x00004470, 0x000005ec },
+ { 0x00004474, 0x000005f5 },
+ { 0x00004478, 0x000005fe },
+ { 0x0000447c, 0x00000606 },
+ { 0x00004480, 0x0000060f },
+ { 0x00004484, 0x00000618 },
+ { 0x00004488, 0x00000621 },
+ { 0x0000448c, 0x0000062a },
+ { 0x00004490, 0x00000633 },
+ { 0x00004494, 0x0000063c },
+ { 0x00004498, 0x00000645 },
+ { 0x0000449c, 0x0000064e },
+ { 0x000044a0, 0x00000657 },
+ { 0x000044a4, 0x00000660 },
+ { 0x000044a8, 0x00000669 },
+ { 0x000044ac, 0x00000672 },
+ { 0x000044b0, 0x0000067b },
+ { 0x000044b4, 0x00000685 },
+ { 0x000044b8, 0x0000068e },
+ { 0x000044bc, 0x00000697 },
+ { 0x000044c0, 0x000006a0 },
+ { 0x000044c4, 0x000006aa },
+ { 0x000044c8, 0x000006b3 },
+ { 0x000044cc, 0x000006bd },
+ { 0x000044d0, 0x000006c6 },
+ { 0x000044d4, 0x000006cf },
+ { 0x000044d8, 0x000006d9 },
+ { 0x000044dc, 0x000006e2 },
+ { 0x000044e0, 0x000006ec },
+ { 0x000044e4, 0x000006f5 },
+ { 0x000044e8, 0x000006ff },
+ { 0x000044ec, 0x00000709 },
+ { 0x000044f0, 0x00000712 },
+ { 0x000044f4, 0x0000071c },
+ { 0x000044f8, 0x00000726 },
+ { 0x000044fc, 0x0000072f },
+ { 0x00004500, 0x00000739 },
+ { 0x00004504, 0x00000743 },
+ { 0x00004508, 0x0000074d },
+ { 0x0000450c, 0x00000756 },
+ { 0x00004510, 0x00000760 },
+ { 0x00004514, 0x0000076a },
+ { 0x00004518, 0x00000774 },
+ { 0x0000451c, 0x0000077e },
+ { 0x00004520, 0x00000788 },
+ { 0x00004524, 0x00000792 },
+ { 0x00004528, 0x0000079c },
+ { 0x0000452c, 0x000007a6 },
+ { 0x00004530, 0x000007b0 },
+ { 0x00004534, 0x000007ba },
+ { 0x00004538, 0x000007c4 },
+ { 0x0000453c, 0x000007cf },
+ { 0x00004540, 0x000007d9 },
+ { 0x00004544, 0x000007e3 },
+ { 0x00004548, 0x000007ed },
+ { 0x0000454c, 0x000007f7 },
+ { 0x00004550, 0x00000802 },
+ { 0x00004554, 0x0000080c },
+ { 0x00004558, 0x00000816 },
+ { 0x0000455c, 0x00000821 },
+ { 0x00004560, 0x0000082b },
+ { 0x00004564, 0x00000836 },
+ { 0x00004568, 0x00000840 },
+ { 0x0000456c, 0x0000084b },
+ { 0x00004570, 0x00000855 },
+ { 0x00004574, 0x00000860 },
+ { 0x00004578, 0x0000086a },
+ { 0x0000457c, 0x00000875 },
+ { 0x00004580, 0x00000880 },
+ { 0x00004584, 0x0000088a },
+ { 0x00004588, 0x00000895 },
+ { 0x0000458c, 0x000008a0 },
+ { 0x00004590, 0x000008ab },
+ { 0x00004594, 0x000008b5 },
+ { 0x00004598, 0x000008c0 },
+ { 0x0000459c, 0x000008cb },
+ { 0x000045a0, 0x000008d6 },
+ { 0x000045a4, 0x000008e1 },
+ { 0x000045a8, 0x000008ec },
+ { 0x000045ac, 0x000008f7 },
+ { 0x000045b0, 0x00000902 },
+ { 0x000045b4, 0x0000090d },
+ { 0x000045b8, 0x00000918 },
+ { 0x000045bc, 0x00000923 },
+ { 0x000045c0, 0x0000092e },
+ { 0x000045c4, 0x00000939 },
+ { 0x000045c8, 0x00000944 },
+ { 0x000045cc, 0x00000950 },
+ { 0x000045d0, 0x0000095b },
+ { 0x000045d4, 0x00000966 },
+ { 0x000045d8, 0x00000971 },
+ { 0x000045dc, 0x0000097d },
+ { 0x000045e0, 0x00000988 },
+ { 0x000045e4, 0x00000993 },
+ { 0x000045e8, 0x0000099f },
+ { 0x000045ec, 0x000009aa },
+ { 0x000045f0, 0x000009b6 },
+ { 0x000045f4, 0x000009c1 },
+ { 0x000045f8, 0x000009cd },
+ { 0x000045fc, 0x000009d8 },
+ { 0x00004600, 0x000009e4 },
+ { 0x00004604, 0x000009f0 },
+ { 0x00004608, 0x000009fb },
+ { 0x0000460c, 0x00000a07 },
+ { 0x00004610, 0x00000a13 },
+ { 0x00004614, 0x00000a1e },
+ { 0x00004618, 0x00000a2a },
+ { 0x0000461c, 0x00000a36 },
+ { 0x00004620, 0x00000a42 },
+ { 0x00004624, 0x00000a4e },
+ { 0x00004628, 0x00000a59 },
+ { 0x0000462c, 0x00000a65 },
+ { 0x00004630, 0x00000a71 },
+ { 0x00004634, 0x00000a7d },
+ { 0x00004638, 0x00000a89 },
+ { 0x0000463c, 0x00000a95 },
+ { 0x00004640, 0x00000aa1 },
+ { 0x00004644, 0x00000aad },
+ { 0x00004648, 0x00000ab9 },
+ { 0x0000464c, 0x00000ac6 },
+ { 0x00004650, 0x00000ad2 },
+ { 0x00004654, 0x00000ade },
+ { 0x00004658, 0x00000aea },
+ { 0x0000465c, 0x00000af6 },
+ { 0x00004660, 0x00000b03 },
+ { 0x00004664, 0x00000b0f },
+ { 0x00004668, 0x00000b1b },
+ { 0x0000466c, 0x00000b28 },
+ { 0x00004670, 0x00000b34 },
+ { 0x00004674, 0x00000b41 },
+ { 0x00004678, 0x00000b4d },
+ { 0x0000467c, 0x00000b5a },
+ { 0x00004680, 0x00000b66 },
+ { 0x00004684, 0x00000b73 },
+ { 0x00004688, 0x00000b7f },
+ { 0x0000468c, 0x00000b8c },
+ { 0x00004690, 0x00000b98 },
+ { 0x00004694, 0x00000ba5 },
+ { 0x00004698, 0x00000bb2 },
+ { 0x0000469c, 0x00000bbf },
+ { 0x000046a0, 0x00000bcb },
+ { 0x000046a4, 0x00000bd8 },
+ { 0x000046a8, 0x00000be5 },
+ { 0x000046ac, 0x00000bf2 },
+ { 0x000046b0, 0x00000bff },
+ { 0x000046b4, 0x00000c0c },
+ { 0x000046b8, 0x00000c19 },
+ { 0x000046bc, 0x00000c25 },
+ { 0x000046c0, 0x00000c32 },
+ { 0x000046c4, 0x00000c40 },
+ { 0x000046c8, 0x00000c4d },
+ { 0x000046cc, 0x00000c5a },
+ { 0x000046d0, 0x00000c67 },
+ { 0x000046d4, 0x00000c74 },
+ { 0x000046d8, 0x00000c81 },
+ { 0x000046dc, 0x00000c8e },
+ { 0x000046e0, 0x00000c9c },
+ { 0x000046e4, 0x00000ca9 },
+ { 0x000046e8, 0x00000cb6 },
+ { 0x000046ec, 0x00000cc3 },
+ { 0x000046f0, 0x00000cd1 },
+ { 0x000046f4, 0x00000cde },
+ { 0x000046f8, 0x00000cec },
+ { 0x000046fc, 0x00000cf9 },
+ { 0x00004700, 0x00000d07 },
+ { 0x00004704, 0x00000d14 },
+ { 0x00004708, 0x00000d22 },
+ { 0x0000470c, 0x00000d2f },
+ { 0x00004710, 0x00000d3d },
+ { 0x00004714, 0x00000d4a },
+ { 0x00004718, 0x00000d58 },
+ { 0x0000471c, 0x00000d66 },
+ { 0x00004720, 0x00000d73 },
+ { 0x00004724, 0x00000d81 },
+ { 0x00004728, 0x00000d8f },
+ { 0x0000472c, 0x00000d9d },
+ { 0x00004730, 0x00000dab },
+ { 0x00004734, 0x00000db8 },
+ { 0x00004738, 0x00000dc6 },
+ { 0x0000473c, 0x00000dd4 },
+ { 0x00004740, 0x00000de2 },
+ { 0x00004744, 0x00000df0 },
+ { 0x00004748, 0x00000dfe },
+ { 0x0000474c, 0x00000e0c },
+ { 0x00004750, 0x00000e1a },
+ { 0x00004754, 0x00000e29 },
+ { 0x00004758, 0x00000e37 },
+ { 0x0000475c, 0x00000e45 },
+ { 0x00004760, 0x00000e53 },
+ { 0x00004764, 0x00000e61 },
+ { 0x00004768, 0x00000e70 },
+ { 0x0000476c, 0x00000e7e },
+ { 0x00004770, 0x00000e8c },
+ { 0x00004774, 0x00000e9a },
+ { 0x00004778, 0x00000ea9 },
+ { 0x0000477c, 0x00000eb7 },
+ { 0x00004780, 0x00000ec6 },
+ { 0x00004784, 0x00000ed4 },
+ { 0x00004788, 0x00000ee3 },
+ { 0x0000478c, 0x00000ef1 },
+ { 0x00004790, 0x00000f00 },
+ { 0x00004794, 0x00000f0e },
+ { 0x00004798, 0x00000f1d },
+ { 0x0000479c, 0x00000f2c },
+ { 0x000047a0, 0x00000f3a },
+ { 0x000047a4, 0x00000f49 },
+ { 0x000047a8, 0x00000f58 },
+ { 0x000047ac, 0x00000f67 },
+ { 0x000047b0, 0x00000f75 },
+ { 0x000047b4, 0x00000f84 },
+ { 0x000047b8, 0x00000f93 },
+ { 0x000047bc, 0x00000fa2 },
+ { 0x000047c0, 0x00000fb1 },
+ { 0x000047c4, 0x00000fc0 },
+ { 0x000047c8, 0x00000fcf },
+ { 0x000047cc, 0x00000fde },
+ { 0x000047d0, 0x00000fed },
+ { 0x000047d4, 0x00000ffc },
+ { 0x000047d8, 0x0000100b },
+ { 0x000047dc, 0x0000101a },
+ { 0x000047e0, 0x0000102a },
+ { 0x000047e4, 0x00001039 },
+ { 0x000047e8, 0x00001048 },
+ { 0x000047ec, 0x00001057 },
+ { 0x000047f0, 0x00001067 },
+ { 0x000047f4, 0x00001076 },
+ { 0x000047f8, 0x00001085 },
+ { 0x000047fc, 0x00001095 },
+ { 0x00004800, 0x000010a4 },
+ { 0x00004804, 0x000010b4 },
+ { 0x00004808, 0x000010c3 },
+ { 0x0000480c, 0x000010d3 },
+ { 0x00004810, 0x000010e2 },
+ { 0x00004814, 0x000010f2 },
+ { 0x00004818, 0x00001101 },
+ { 0x0000481c, 0x00001111 },
+ { 0x00004820, 0x00001121 },
+ { 0x00004824, 0x00001130 },
+ { 0x00004828, 0x00001140 },
+ { 0x0000482c, 0x00001150 },
+ { 0x00004830, 0x00001160 },
+ { 0x00004834, 0x0000116f },
+ { 0x00004838, 0x0000117f },
+ { 0x0000483c, 0x0000118f },
+ { 0x00004840, 0x0000119f },
+ { 0x00004844, 0x000011af },
+ { 0x00004848, 0x000011bf },
+ { 0x0000484c, 0x000011cf },
+ { 0x00004850, 0x000011df },
+ { 0x00004854, 0x000011ef },
+ { 0x00004858, 0x000011ff },
+ { 0x0000485c, 0x0000120f },
+ { 0x00004860, 0x0000121f },
+ { 0x00004864, 0x00001230 },
+ { 0x00004868, 0x00001240 },
+ { 0x0000486c, 0x00001250 },
+ { 0x00004870, 0x00001260 },
+ { 0x00004874, 0x00001271 },
+ { 0x00004878, 0x00001281 },
+ { 0x0000487c, 0x00001291 },
+ { 0x00004880, 0x000012a2 },
+ { 0x00004884, 0x000012b2 },
+ { 0x00004888, 0x000012c3 },
+ { 0x0000488c, 0x000012d3 },
+ { 0x00004890, 0x000012e4 },
+ { 0x00004894, 0x000012f4 },
+ { 0x00004898, 0x00001305 },
+ { 0x0000489c, 0x00001316 },
+ { 0x000048a0, 0x00001326 },
+ { 0x000048a4, 0x00001337 },
+ { 0x000048a8, 0x00001348 },
+ { 0x000048ac, 0x00001359 },
+ { 0x000048b0, 0x00001369 },
+ { 0x000048b4, 0x0000137a },
+ { 0x000048b8, 0x0000138b },
+ { 0x000048bc, 0x0000139c },
+ { 0x000048c0, 0x000013ad },
+ { 0x000048c4, 0x000013be },
+ { 0x000048c8, 0x000013cf },
+ { 0x000048cc, 0x000013e0 },
+ { 0x000048d0, 0x000013f1 },
+ { 0x000048d4, 0x00001402 },
+ { 0x000048d8, 0x00001413 },
+ { 0x000048dc, 0x00001424 },
+ { 0x000048e0, 0x00001435 },
+ { 0x000048e4, 0x00001446 },
+ { 0x000048e8, 0x00001458 },
+ { 0x000048ec, 0x00001469 },
+ { 0x000048f0, 0x0000147a },
+ { 0x000048f4, 0x0000148b },
+ { 0x000048f8, 0x0000149d },
+ { 0x000048fc, 0x000014ae },
+ { 0x00004900, 0x000014c0 },
+ { 0x00004904, 0x000014d1 },
+ { 0x00004908, 0x000014e3 },
+ { 0x0000490c, 0x000014f4 },
+ { 0x00004910, 0x00001506 },
+ { 0x00004914, 0x00001517 },
+ { 0x00004918, 0x00001529 },
+ { 0x0000491c, 0x0000153a },
+ { 0x00004920, 0x0000154c },
+ { 0x00004924, 0x0000155e },
+ { 0x00004928, 0x0000156f },
+ { 0x0000492c, 0x00001581 },
+ { 0x00004930, 0x00001593 },
+ { 0x00004934, 0x000015a5 },
+ { 0x00004938, 0x000015b7 },
+ { 0x0000493c, 0x000015c9 },
+ { 0x00004940, 0x000015db },
+ { 0x00004944, 0x000015ec },
+ { 0x00004948, 0x000015fe },
+ { 0x0000494c, 0x00001610 },
+ { 0x00004950, 0x00001623 },
+ { 0x00004954, 0x00001635 },
+ { 0x00004958, 0x00001647 },
+ { 0x0000495c, 0x00001659 },
+ { 0x00004960, 0x0000166b },
+ { 0x00004964, 0x0000167d },
+ { 0x00004968, 0x0000168f },
+ { 0x0000496c, 0x000016a2 },
+ { 0x00004970, 0x000016b4 },
+ { 0x00004974, 0x000016c6 },
+ { 0x00004978, 0x000016d9 },
+ { 0x0000497c, 0x000016eb },
+ { 0x00004980, 0x000016fe },
+ { 0x00004984, 0x00001710 },
+ { 0x00004988, 0x00001722 },
+ { 0x0000498c, 0x00001735 },
+ { 0x00004990, 0x00001748 },
+ { 0x00004994, 0x0000175a },
+ { 0x00004998, 0x0000176d },
+ { 0x0000499c, 0x0000177f },
+ { 0x000049a0, 0x00001792 },
+ { 0x000049a4, 0x000017a5 },
+ { 0x000049a8, 0x000017b8 },
+ { 0x000049ac, 0x000017ca },
+ { 0x000049b0, 0x000017dd },
+ { 0x000049b4, 0x000017f0 },
+ { 0x000049b8, 0x00001803 },
+ { 0x000049bc, 0x00001816 },
+ { 0x000049c0, 0x00001829 },
+ { 0x000049c4, 0x0000183c },
+ { 0x000049c8, 0x0000184f },
+ { 0x000049cc, 0x00001862 },
+ { 0x000049d0, 0x00001875 },
+ { 0x000049d4, 0x00001888 },
+ { 0x000049d8, 0x0000189b },
+ { 0x000049dc, 0x000018ae },
+ { 0x000049e0, 0x000018c1 },
+ { 0x000049e4, 0x000018d5 },
+ { 0x000049e8, 0x000018e8 },
+ { 0x000049ec, 0x000018fb },
+ { 0x000049f0, 0x0000190e },
+ { 0x000049f4, 0x00001922 },
+ { 0x000049f8, 0x00001935 },
+ { 0x000049fc, 0x00001949 },
+ { 0x00004a00, 0x0000195c },
+ { 0x00004a04, 0x0000196f },
+ { 0x00004a08, 0x00001983 },
+ { 0x00004a0c, 0x00001996 },
+ { 0x00004a10, 0x000019aa },
+ { 0x00004a14, 0x000019be },
+ { 0x00004a18, 0x000019d1 },
+ { 0x00004a1c, 0x000019e5 },
+ { 0x00004a20, 0x000019f9 },
+ { 0x00004a24, 0x00001a0c },
+ { 0x00004a28, 0x00001a20 },
+ { 0x00004a2c, 0x00001a34 },
+ { 0x00004a30, 0x00001a48 },
+ { 0x00004a34, 0x00001a5c },
+ { 0x00004a38, 0x00001a70 },
+ { 0x00004a3c, 0x00001a84 },
+ { 0x00004a40, 0x00001a97 },
+ { 0x00004a44, 0x00001aab },
+ { 0x00004a48, 0x00001ac0 },
+ { 0x00004a4c, 0x00001ad4 },
+ { 0x00004a50, 0x00001ae8 },
+ { 0x00004a54, 0x00001afc },
+ { 0x00004a58, 0x00001b10 },
+ { 0x00004a5c, 0x00001b24 },
+ { 0x00004a60, 0x00001b38 },
+ { 0x00004a64, 0x00001b4d },
+ { 0x00004a68, 0x00001b61 },
+ { 0x00004a6c, 0x00001b75 },
+ { 0x00004a70, 0x00001b8a },
+ { 0x00004a74, 0x00001b9e },
+ { 0x00004a78, 0x00001bb2 },
+ { 0x00004a7c, 0x00001bc7 },
+ { 0x00004a80, 0x00001bdb },
+ { 0x00004a84, 0x00001bf0 },
+ { 0x00004a88, 0x00001c04 },
+ { 0x00004a8c, 0x00001c19 },
+ { 0x00004a90, 0x00001c2e },
+ { 0x00004a94, 0x00001c42 },
+ { 0x00004a98, 0x00001c57 },
+ { 0x00004a9c, 0x00001c6c },
+ { 0x00004aa0, 0x00001c80 },
+ { 0x00004aa4, 0x00001c95 },
+ { 0x00004aa8, 0x00001caa },
+ { 0x00004aac, 0x00001cbf },
+ { 0x00004ab0, 0x00001cd4 },
+ { 0x00004ab4, 0x00001ce8 },
+ { 0x00004ab8, 0x00001cfd },
+ { 0x00004abc, 0x00001d12 },
+ { 0x00004ac0, 0x00001d27 },
+ { 0x00004ac4, 0x00001d3c },
+ { 0x00004ac8, 0x00001d51 },
+ { 0x00004acc, 0x00001d67 },
+ { 0x00004ad0, 0x00001d7c },
+ { 0x00004ad4, 0x00001d91 },
+ { 0x00004ad8, 0x00001da6 },
+ { 0x00004adc, 0x00001dbb },
+ { 0x00004ae0, 0x00001dd1 },
+ { 0x00004ae4, 0x00001de6 },
+ { 0x00004ae8, 0x00001dfb },
+ { 0x00004aec, 0x00001e10 },
+ { 0x00004af0, 0x00001e26 },
+ { 0x00004af4, 0x00001e3b },
+ { 0x00004af8, 0x00001e51 },
+ { 0x00004afc, 0x00001e66 },
+ { 0x00004b00, 0x00001e7c },
+ { 0x00004b04, 0x00001e91 },
+ { 0x00004b08, 0x00001ea7 },
+ { 0x00004b0c, 0x00001ebd },
+ { 0x00004b10, 0x00001ed2 },
+ { 0x00004b14, 0x00001ee8 },
+ { 0x00004b18, 0x00001efe },
+ { 0x00004b1c, 0x00001f13 },
+ { 0x00004b20, 0x00001f29 },
+ { 0x00004b24, 0x00001f3f },
+ { 0x00004b28, 0x00001f55 },
+ { 0x00004b2c, 0x00001f6b },
+ { 0x00004b30, 0x00001f81 },
+ { 0x00004b34, 0x00001f96 },
+ { 0x00004b38, 0x00001fac },
+ { 0x00004b3c, 0x00001fc2 },
+ { 0x00004b40, 0x00001fd9 },
+ { 0x00004b44, 0x00001fef },
+ { 0x00004b48, 0x00002005 },
+ { 0x00004b4c, 0x0000201b },
+ { 0x00004b50, 0x00002031 },
+ { 0x00004b54, 0x00002047 },
+ { 0x00004b58, 0x0000205d },
+ { 0x00004b5c, 0x00002074 },
+ { 0x00004b60, 0x0000208a },
+ { 0x00004b64, 0x000020a0 },
+ { 0x00004b68, 0x000020b7 },
+ { 0x00004b6c, 0x000020cd },
+ { 0x00004b70, 0x000020e4 },
+ { 0x00004b74, 0x000020fa },
+ { 0x00004b78, 0x00002111 },
+ { 0x00004b7c, 0x00002127 },
+ { 0x00004b80, 0x0000213e },
+ { 0x00004b84, 0x00002154 },
+ { 0x00004b88, 0x0000216b },
+ { 0x00004b8c, 0x00002182 },
+ { 0x00004b90, 0x00002198 },
+ { 0x00004b94, 0x000021af },
+ { 0x00004b98, 0x000021c6 },
+ { 0x00004b9c, 0x000021dd },
+ { 0x00004ba0, 0x000021f3 },
+ { 0x00004ba4, 0x0000220a },
+ { 0x00004ba8, 0x00002221 },
+ { 0x00004bac, 0x00002238 },
+ { 0x00004bb0, 0x0000224f },
+ { 0x00004bb4, 0x00002266 },
+ { 0x00004bb8, 0x0000227d },
+ { 0x00004bbc, 0x00002294 },
+ { 0x00004bc0, 0x000022ab },
+ { 0x00004bc4, 0x000022c2 },
+ { 0x00004bc8, 0x000022da },
+ { 0x00004bcc, 0x000022f1 },
+ { 0x00004bd0, 0x00002308 },
+ { 0x00004bd4, 0x0000231f },
+ { 0x00004bd8, 0x00002337 },
+ { 0x00004bdc, 0x0000234e },
+ { 0x00004be0, 0x00002365 },
+ { 0x00004be4, 0x0000237d },
+ { 0x00004be8, 0x00002394 },
+ { 0x00004bec, 0x000023ac },
+ { 0x00004bf0, 0x000023c3 },
+ { 0x00004bf4, 0x000023db },
+ { 0x00004bf8, 0x000023f2 },
+ { 0x00004bfc, 0x0000240a },
+ { 0x00004c00, 0x00002421 },
+ { 0x00004c04, 0x00002439 },
+ { 0x00004c08, 0x00002451 },
+ { 0x00004c0c, 0x00002469 },
+ { 0x00004c10, 0x00002480 },
+ { 0x00004c14, 0x00002498 },
+ { 0x00004c18, 0x000024b0 },
+ { 0x00004c1c, 0x000024c8 },
+ { 0x00004c20, 0x000024e0 },
+ { 0x00004c24, 0x000024f8 },
+ { 0x00004c28, 0x00002510 },
+ { 0x00004c2c, 0x00002528 },
+ { 0x00004c30, 0x00002540 },
+ { 0x00004c34, 0x00002558 },
+ { 0x00004c38, 0x00002570 },
+ { 0x00004c3c, 0x00002588 },
+ { 0x00004c40, 0x000025a0 },
+ { 0x00004c44, 0x000025b8 },
+ { 0x00004c48, 0x000025d0 },
+ { 0x00004c4c, 0x000025e9 },
+ { 0x00004c50, 0x00002601 },
+ { 0x00004c54, 0x00002619 },
+ { 0x00004c58, 0x00002632 },
+ { 0x00004c5c, 0x0000264a },
+ { 0x00004c60, 0x00002663 },
+ { 0x00004c64, 0x0000267b },
+ { 0x00004c68, 0x00002693 },
+ { 0x00004c6c, 0x000026ac },
+ { 0x00004c70, 0x000026c5 },
+ { 0x00004c74, 0x000026dd },
+ { 0x00004c78, 0x000026f6 },
+ { 0x00004c7c, 0x0000270e },
+ { 0x00004c80, 0x00002727 },
+ { 0x00004c84, 0x00002740 },
+ { 0x00004c88, 0x00002759 },
+ { 0x00004c8c, 0x00002771 },
+ { 0x00004c90, 0x0000278a },
+ { 0x00004c94, 0x000027a3 },
+ { 0x00004c98, 0x000027bc },
+ { 0x00004c9c, 0x000027d5 },
+ { 0x00004ca0, 0x000027ee },
+ { 0x00004ca4, 0x00002807 },
+ { 0x00004ca8, 0x00002820 },
+ { 0x00004cac, 0x00002839 },
+ { 0x00004cb0, 0x00002852 },
+ { 0x00004cb4, 0x0000286b },
+ { 0x00004cb8, 0x00002884 },
+ { 0x00004cbc, 0x0000289e },
+ { 0x00004cc0, 0x000028b7 },
+ { 0x00004cc4, 0x000028d0 },
+ { 0x00004cc8, 0x000028e9 },
+ { 0x00004ccc, 0x00002903 },
+ { 0x00004cd0, 0x0000291c },
+ { 0x00004cd4, 0x00002936 },
+ { 0x00004cd8, 0x0000294f },
+ { 0x00004cdc, 0x00002968 },
+ { 0x00004ce0, 0x00002982 },
+ { 0x00004ce4, 0x0000299c },
+ { 0x00004ce8, 0x000029b5 },
+ { 0x00004cec, 0x000029cf },
+ { 0x00004cf0, 0x000029e8 },
+ { 0x00004cf4, 0x00002a02 },
+ { 0x00004cf8, 0x00002a1c },
+ { 0x00004cfc, 0x00002a35 },
+ { 0x00004d00, 0x00002a4f },
+ { 0x00004d04, 0x00002a69 },
+ { 0x00004d08, 0x00002a83 },
+ { 0x00004d0c, 0x00002a9d },
+ { 0x00004d10, 0x00002ab7 },
+ { 0x00004d14, 0x00002ad1 },
+ { 0x00004d18, 0x00002aeb },
+ { 0x00004d1c, 0x00002b05 },
+ { 0x00004d20, 0x00002b1f },
+ { 0x00004d24, 0x00002b39 },
+ { 0x00004d28, 0x00002b53 },
+ { 0x00004d2c, 0x00002b6d },
+ { 0x00004d30, 0x00002b87 },
+ { 0x00004d34, 0x00002ba1 },
+ { 0x00004d38, 0x00002bbc },
+ { 0x00004d3c, 0x00002bd6 },
+ { 0x00004d40, 0x00002bf0 },
+ { 0x00004d44, 0x00002c0b },
+ { 0x00004d48, 0x00002c25 },
+ { 0x00004d4c, 0x00002c3f },
+ { 0x00004d50, 0x00002c5a },
+ { 0x00004d54, 0x00002c74 },
+ { 0x00004d58, 0x00002c8f },
+ { 0x00004d5c, 0x00002ca9 },
+ { 0x00004d60, 0x00002cc4 },
+ { 0x00004d64, 0x00002cdf },
+ { 0x00004d68, 0x00002cf9 },
+ { 0x00004d6c, 0x00002d14 },
+ { 0x00004d70, 0x00002d2f },
+ { 0x00004d74, 0x00002d49 },
+ { 0x00004d78, 0x00002d64 },
+ { 0x00004d7c, 0x00002d7f },
+ { 0x00004d80, 0x00002d9a },
+ { 0x00004d84, 0x00002db5 },
+ { 0x00004d88, 0x00002dd0 },
+ { 0x00004d8c, 0x00002deb },
+ { 0x00004d90, 0x00002e06 },
+ { 0x00004d94, 0x00002e21 },
+ { 0x00004d98, 0x00002e3c },
+ { 0x00004d9c, 0x00002e57 },
+ { 0x00004da0, 0x00002e72 },
+ { 0x00004da4, 0x00002e8d },
+ { 0x00004da8, 0x00002ea8 },
+ { 0x00004dac, 0x00002ec4 },
+ { 0x00004db0, 0x00002edf },
+ { 0x00004db4, 0x00002efa },
+ { 0x00004db8, 0x00002f16 },
+ { 0x00004dbc, 0x00002f31 },
+ { 0x00004dc0, 0x00002f4c },
+ { 0x00004dc4, 0x00002f68 },
+ { 0x00004dc8, 0x00002f83 },
+ { 0x00004dcc, 0x00002f9f },
+ { 0x00004dd0, 0x00002fba },
+ { 0x00004dd4, 0x00002fd6 },
+ { 0x00004dd8, 0x00002ff1 },
+ { 0x00004ddc, 0x0000300d },
+ { 0x00004de0, 0x00003029 },
+ { 0x00004de4, 0x00003044 },
+ { 0x00004de8, 0x00003060 },
+ { 0x00004dec, 0x0000307c },
+ { 0x00004df0, 0x00003098 },
+ { 0x00004df4, 0x000030b4 },
+ { 0x00004df8, 0x000030d0 },
+ { 0x00004dfc, 0x000030eb },
+ { 0x00004e00, 0x00003107 },
+ { 0x00004e04, 0x00003123 },
+ { 0x00004e08, 0x0000313f },
+ { 0x00004e0c, 0x0000315b },
+ { 0x00004e10, 0x00003178 },
+ { 0x00004e14, 0x00003194 },
+ { 0x00004e18, 0x000031b0 },
+ { 0x00004e1c, 0x000031cc },
+ { 0x00004e20, 0x000031e8 },
+ { 0x00004e24, 0x00003205 },
+ { 0x00004e28, 0x00003221 },
+ { 0x00004e2c, 0x0000323d },
+ { 0x00004e30, 0x0000325a },
+ { 0x00004e34, 0x00003276 },
+ { 0x00004e38, 0x00003292 },
+ { 0x00004e3c, 0x000032af },
+ { 0x00004e40, 0x000032cb },
+ { 0x00004e44, 0x000032e8 },
+ { 0x00004e48, 0x00003304 },
+ { 0x00004e4c, 0x00003321 },
+ { 0x00004e50, 0x0000333e },
+ { 0x00004e54, 0x0000335a },
+ { 0x00004e58, 0x00003377 },
+ { 0x00004e5c, 0x00003394 },
+ { 0x00004e60, 0x000033b1 },
+ { 0x00004e64, 0x000033cd },
+ { 0x00004e68, 0x000033ea },
+ { 0x00004e6c, 0x00003407 },
+ { 0x00004e70, 0x00003424 },
+ { 0x00004e74, 0x00003441 },
+ { 0x00004e78, 0x0000345e },
+ { 0x00004e7c, 0x0000347b },
+ { 0x00004e80, 0x00003498 },
+ { 0x00004e84, 0x000034b5 },
+ { 0x00004e88, 0x000034d2 },
+ { 0x00004e8c, 0x000034ef },
+ { 0x00004e90, 0x0000350d },
+ { 0x00004e94, 0x0000352a },
+ { 0x00004e98, 0x00003547 },
+ { 0x00004e9c, 0x00003564 },
+ { 0x00004ea0, 0x00003582 },
+ { 0x00004ea4, 0x0000359f },
+ { 0x00004ea8, 0x000035bc },
+ { 0x00004eac, 0x000035da },
+ { 0x00004eb0, 0x000035f7 },
+ { 0x00004eb4, 0x00003615 },
+ { 0x00004eb8, 0x00003632 },
+ { 0x00004ebc, 0x00003650 },
+ { 0x00004ec0, 0x0000366e },
+ { 0x00004ec4, 0x0000368b },
+ { 0x00004ec8, 0x000036a9 },
+ { 0x00004ecc, 0x000036c7 },
+ { 0x00004ed0, 0x000036e4 },
+ { 0x00004ed4, 0x00003702 },
+ { 0x00004ed8, 0x00003720 },
+ { 0x00004edc, 0x0000373e },
+ { 0x00004ee0, 0x0000375c },
+ { 0x00004ee4, 0x0000377a },
+ { 0x00004ee8, 0x00003798 },
+ { 0x00004eec, 0x000037b6 },
+ { 0x00004ef0, 0x000037d4 },
+ { 0x00004ef4, 0x000037f2 },
+ { 0x00004ef8, 0x00003810 },
+ { 0x00004efc, 0x0000382e },
+ { 0x00004f00, 0x0000384c },
+ { 0x00004f04, 0x0000386a },
+ { 0x00004f08, 0x00003888 },
+ { 0x00004f0c, 0x000038a7 },
+ { 0x00004f10, 0x000038c5 },
+ { 0x00004f14, 0x000038e3 },
+ { 0x00004f18, 0x00003902 },
+ { 0x00004f1c, 0x00003920 },
+ { 0x00004f20, 0x0000393f },
+ { 0x00004f24, 0x0000395d },
+ { 0x00004f28, 0x0000397c },
+ { 0x00004f2c, 0x0000399a },
+ { 0x00004f30, 0x000039b9 },
+ { 0x00004f34, 0x000039d7 },
+ { 0x00004f38, 0x000039f6 },
+ { 0x00004f3c, 0x00003a15 },
+ { 0x00004f40, 0x00003a33 },
+ { 0x00004f44, 0x00003a52 },
+ { 0x00004f48, 0x00003a71 },
+ { 0x00004f4c, 0x00003a90 },
+ { 0x00004f50, 0x00003aaf },
+ { 0x00004f54, 0x00003acd },
+ { 0x00004f58, 0x00003aec },
+ { 0x00004f5c, 0x00003b0b },
+ { 0x00004f60, 0x00003b2a },
+ { 0x00004f64, 0x00003b49 },
+ { 0x00004f68, 0x00003b68 },
+ { 0x00004f6c, 0x00003b87 },
+ { 0x00004f70, 0x00003ba7 },
+ { 0x00004f74, 0x00003bc6 },
+ { 0x00004f78, 0x00003be5 },
+ { 0x00004f7c, 0x00003c04 },
+ { 0x00004f80, 0x00003c24 },
+ { 0x00004f84, 0x00003c43 },
+ { 0x00004f88, 0x00003c62 },
+ { 0x00004f8c, 0x00003c82 },
+ { 0x00004f90, 0x00003ca1 },
+ { 0x00004f94, 0x00003cc0 },
+ { 0x00004f98, 0x00003ce0 },
+ { 0x00004f9c, 0x00003cff },
+ { 0x00004fa0, 0x00003d1f },
+ { 0x00004fa4, 0x00003d3f },
+ { 0x00004fa8, 0x00003d5e },
+ { 0x00004fac, 0x00003d7e },
+ { 0x00004fb0, 0x00003d9e },
+ { 0x00004fb4, 0x00003dbd },
+ { 0x00004fb8, 0x00003ddd },
+ { 0x00004fbc, 0x00003dfd },
+ { 0x00004fc0, 0x00003e1d },
+ { 0x00004fc4, 0x00003e3d },
+ { 0x00004fc8, 0x00003e5d },
+ { 0x00004fcc, 0x00003e7c },
+ { 0x00004fd0, 0x00003e9c },
+ { 0x00004fd4, 0x00003ebc },
+ { 0x00004fd8, 0x00003edc },
+ { 0x00004fdc, 0x00003efd },
+ { 0x00004fe0, 0x00003f1d },
+ { 0x00004fe4, 0x00003f3d },
+ { 0x00004fe8, 0x00003f5d },
+ { 0x00004fec, 0x00003f7d },
+ { 0x00004ff0, 0x00003f9e },
+ { 0x00004ff4, 0x00003fbe },
+ { 0x00004ff8, 0x00003fde },
+ { 0x00004ffc, 0x00003fff },
+};
+
+struct data_unit hdr10_pipe2_lut_a1[] = {
+ { 0x00005000, 0x00000000 },
+ { 0x00005004, 0x00000003 },
+ { 0x00005008, 0x00000007 },
+ { 0x0000500c, 0x0000000a },
+ { 0x00005010, 0x0000000e },
+ { 0x00005014, 0x00000011 },
+ { 0x00005018, 0x00000015 },
+ { 0x0000501c, 0x00000018 },
+ { 0x00005020, 0x0000001c },
+ { 0x00005024, 0x00000020 },
+ { 0x00005028, 0x00000023 },
+ { 0x0000502c, 0x00000027 },
+ { 0x00005030, 0x0000002a },
+ { 0x00005034, 0x0000002e },
+ { 0x00005038, 0x00000031 },
+ { 0x0000503c, 0x00000035 },
+ { 0x00005040, 0x00000038 },
+ { 0x00005044, 0x0000003c },
+ { 0x00005048, 0x00000040 },
+ { 0x0000504c, 0x00000043 },
+ { 0x00005050, 0x00000047 },
+ { 0x00005054, 0x0000004a },
+ { 0x00005058, 0x0000004e },
+ { 0x0000505c, 0x00000051 },
+ { 0x00005060, 0x00000055 },
+ { 0x00005064, 0x00000058 },
+ { 0x00005068, 0x0000005c },
+ { 0x0000506c, 0x00000060 },
+ { 0x00005070, 0x00000063 },
+ { 0x00005074, 0x00000067 },
+ { 0x00005078, 0x0000006a },
+ { 0x0000507c, 0x0000006e },
+ { 0x00005080, 0x00000071 },
+ { 0x00005084, 0x00000075 },
+ { 0x00005088, 0x00000078 },
+ { 0x0000508c, 0x0000007c },
+ { 0x00005090, 0x00000080 },
+ { 0x00005094, 0x00000083 },
+ { 0x00005098, 0x00000087 },
+ { 0x0000509c, 0x0000008a },
+ { 0x000050a0, 0x0000008e },
+ { 0x000050a4, 0x00000091 },
+ { 0x000050a8, 0x00000095 },
+ { 0x000050ac, 0x00000099 },
+ { 0x000050b0, 0x0000009c },
+ { 0x000050b4, 0x000000a0 },
+ { 0x000050b8, 0x000000a3 },
+ { 0x000050bc, 0x000000a7 },
+ { 0x000050c0, 0x000000aa },
+ { 0x000050c4, 0x000000ae },
+ { 0x000050c8, 0x000000b1 },
+ { 0x000050cc, 0x000000b5 },
+ { 0x000050d0, 0x000000b9 },
+ { 0x000050d4, 0x000000bc },
+ { 0x000050d8, 0x000000c0 },
+ { 0x000050dc, 0x000000c3 },
+ { 0x000050e0, 0x000000c7 },
+ { 0x000050e4, 0x000000ca },
+ { 0x000050e8, 0x000000ce },
+ { 0x000050ec, 0x000000d1 },
+ { 0x000050f0, 0x000000d5 },
+ { 0x000050f4, 0x000000d9 },
+ { 0x000050f8, 0x000000dc },
+ { 0x000050fc, 0x000000e0 },
+ { 0x00005100, 0x000000e3 },
+ { 0x00005104, 0x000000e7 },
+ { 0x00005108, 0x000000ea },
+ { 0x0000510c, 0x000000ee },
+ { 0x00005110, 0x000000f1 },
+ { 0x00005114, 0x000000f5 },
+ { 0x00005118, 0x000000f9 },
+ { 0x0000511c, 0x000000fc },
+ { 0x00005120, 0x00000100 },
+ { 0x00005124, 0x00000103 },
+ { 0x00005128, 0x00000107 },
+ { 0x0000512c, 0x0000010a },
+ { 0x00005130, 0x0000010e },
+ { 0x00005134, 0x00000112 },
+ { 0x00005138, 0x00000115 },
+ { 0x0000513c, 0x00000119 },
+ { 0x00005140, 0x0000011c },
+ { 0x00005144, 0x00000120 },
+ { 0x00005148, 0x00000123 },
+ { 0x0000514c, 0x00000126 },
+ { 0x00005150, 0x0000012a },
+ { 0x00005154, 0x0000012d },
+ { 0x00005158, 0x00000131 },
+ { 0x0000515c, 0x00000134 },
+ { 0x00005160, 0x00000138 },
+ { 0x00005164, 0x0000013c },
+ { 0x00005168, 0x0000013f },
+ { 0x0000516c, 0x00000143 },
+ { 0x00005170, 0x00000147 },
+ { 0x00005174, 0x0000014b },
+ { 0x00005178, 0x0000014e },
+ { 0x0000517c, 0x00000152 },
+ { 0x00005180, 0x00000156 },
+ { 0x00005184, 0x0000015a },
+ { 0x00005188, 0x0000015e },
+ { 0x0000518c, 0x00000162 },
+ { 0x00005190, 0x00000166 },
+ { 0x00005194, 0x0000016a },
+ { 0x00005198, 0x0000016e },
+ { 0x0000519c, 0x00000172 },
+ { 0x000051a0, 0x00000176 },
+ { 0x000051a4, 0x0000017a },
+ { 0x000051a8, 0x0000017e },
+ { 0x000051ac, 0x00000182 },
+ { 0x000051b0, 0x00000186 },
+ { 0x000051b4, 0x0000018a },
+ { 0x000051b8, 0x0000018f },
+ { 0x000051bc, 0x00000193 },
+ { 0x000051c0, 0x00000197 },
+ { 0x000051c4, 0x0000019b },
+ { 0x000051c8, 0x000001a0 },
+ { 0x000051cc, 0x000001a4 },
+ { 0x000051d0, 0x000001a8 },
+ { 0x000051d4, 0x000001ad },
+ { 0x000051d8, 0x000001b1 },
+ { 0x000051dc, 0x000001b5 },
+ { 0x000051e0, 0x000001ba },
+ { 0x000051e4, 0x000001be },
+ { 0x000051e8, 0x000001c3 },
+ { 0x000051ec, 0x000001c7 },
+ { 0x000051f0, 0x000001cc },
+ { 0x000051f4, 0x000001d0 },
+ { 0x000051f8, 0x000001d5 },
+ { 0x000051fc, 0x000001d9 },
+ { 0x00005200, 0x000001de },
+ { 0x00005204, 0x000001e3 },
+ { 0x00005208, 0x000001e7 },
+ { 0x0000520c, 0x000001ec },
+ { 0x00005210, 0x000001f1 },
+ { 0x00005214, 0x000001f6 },
+ { 0x00005218, 0x000001fa },
+ { 0x0000521c, 0x000001ff },
+ { 0x00005220, 0x00000204 },
+ { 0x00005224, 0x00000209 },
+ { 0x00005228, 0x0000020e },
+ { 0x0000522c, 0x00000213 },
+ { 0x00005230, 0x00000217 },
+ { 0x00005234, 0x0000021c },
+ { 0x00005238, 0x00000221 },
+ { 0x0000523c, 0x00000226 },
+ { 0x00005240, 0x0000022b },
+ { 0x00005244, 0x00000230 },
+ { 0x00005248, 0x00000236 },
+ { 0x0000524c, 0x0000023b },
+ { 0x00005250, 0x00000240 },
+ { 0x00005254, 0x00000245 },
+ { 0x00005258, 0x0000024a },
+ { 0x0000525c, 0x0000024f },
+ { 0x00005260, 0x00000255 },
+ { 0x00005264, 0x0000025a },
+ { 0x00005268, 0x0000025f },
+ { 0x0000526c, 0x00000264 },
+ { 0x00005270, 0x0000026a },
+ { 0x00005274, 0x0000026f },
+ { 0x00005278, 0x00000274 },
+ { 0x0000527c, 0x0000027a },
+ { 0x00005280, 0x0000027f },
+ { 0x00005284, 0x00000285 },
+ { 0x00005288, 0x0000028a },
+ { 0x0000528c, 0x00000290 },
+ { 0x00005290, 0x00000295 },
+ { 0x00005294, 0x0000029b },
+ { 0x00005298, 0x000002a0 },
+ { 0x0000529c, 0x000002a6 },
+ { 0x000052a0, 0x000002ac },
+ { 0x000052a4, 0x000002b1 },
+ { 0x000052a8, 0x000002b7 },
+ { 0x000052ac, 0x000002bd },
+ { 0x000052b0, 0x000002c2 },
+ { 0x000052b4, 0x000002c8 },
+ { 0x000052b8, 0x000002ce },
+ { 0x000052bc, 0x000002d4 },
+ { 0x000052c0, 0x000002da },
+ { 0x000052c4, 0x000002df },
+ { 0x000052c8, 0x000002e5 },
+ { 0x000052cc, 0x000002eb },
+ { 0x000052d0, 0x000002f1 },
+ { 0x000052d4, 0x000002f7 },
+ { 0x000052d8, 0x000002fd },
+ { 0x000052dc, 0x00000303 },
+ { 0x000052e0, 0x00000309 },
+ { 0x000052e4, 0x0000030f },
+ { 0x000052e8, 0x00000315 },
+ { 0x000052ec, 0x0000031c },
+ { 0x000052f0, 0x00000322 },
+ { 0x000052f4, 0x00000328 },
+ { 0x000052f8, 0x0000032e },
+ { 0x000052fc, 0x00000334 },
+ { 0x00005300, 0x0000033b },
+ { 0x00005304, 0x00000341 },
+ { 0x00005308, 0x00000347 },
+ { 0x0000530c, 0x0000034d },
+ { 0x00005310, 0x00000354 },
+ { 0x00005314, 0x0000035a },
+ { 0x00005318, 0x00000361 },
+ { 0x0000531c, 0x00000367 },
+ { 0x00005320, 0x0000036d },
+ { 0x00005324, 0x00000374 },
+ { 0x00005328, 0x0000037a },
+ { 0x0000532c, 0x00000381 },
+ { 0x00005330, 0x00000388 },
+ { 0x00005334, 0x0000038e },
+ { 0x00005338, 0x00000395 },
+ { 0x0000533c, 0x0000039b },
+ { 0x00005340, 0x000003a2 },
+ { 0x00005344, 0x000003a9 },
+ { 0x00005348, 0x000003b0 },
+ { 0x0000534c, 0x000003b6 },
+ { 0x00005350, 0x000003bd },
+ { 0x00005354, 0x000003c4 },
+ { 0x00005358, 0x000003cb },
+ { 0x0000535c, 0x000003d2 },
+ { 0x00005360, 0x000003d8 },
+ { 0x00005364, 0x000003df },
+ { 0x00005368, 0x000003e6 },
+ { 0x0000536c, 0x000003ed },
+ { 0x00005370, 0x000003f4 },
+ { 0x00005374, 0x000003fb },
+ { 0x00005378, 0x00000402 },
+ { 0x0000537c, 0x00000409 },
+ { 0x00005380, 0x00000411 },
+ { 0x00005384, 0x00000418 },
+ { 0x00005388, 0x0000041f },
+ { 0x0000538c, 0x00000426 },
+ { 0x00005390, 0x0000042d },
+ { 0x00005394, 0x00000434 },
+ { 0x00005398, 0x0000043c },
+ { 0x0000539c, 0x00000443 },
+ { 0x000053a0, 0x0000044a },
+ { 0x000053a4, 0x00000452 },
+ { 0x000053a8, 0x00000459 },
+ { 0x000053ac, 0x00000460 },
+ { 0x000053b0, 0x00000468 },
+ { 0x000053b4, 0x0000046f },
+ { 0x000053b8, 0x00000477 },
+ { 0x000053bc, 0x0000047e },
+ { 0x000053c0, 0x00000486 },
+ { 0x000053c4, 0x0000048d },
+ { 0x000053c8, 0x00000495 },
+ { 0x000053cc, 0x0000049c },
+ { 0x000053d0, 0x000004a4 },
+ { 0x000053d4, 0x000004ac },
+ { 0x000053d8, 0x000004b3 },
+ { 0x000053dc, 0x000004bb },
+ { 0x000053e0, 0x000004c3 },
+ { 0x000053e4, 0x000004cb },
+ { 0x000053e8, 0x000004d3 },
+ { 0x000053ec, 0x000004da },
+ { 0x000053f0, 0x000004e2 },
+ { 0x000053f4, 0x000004ea },
+ { 0x000053f8, 0x000004f2 },
+ { 0x000053fc, 0x000004fa },
+ { 0x00005400, 0x00000502 },
+ { 0x00005404, 0x0000050a },
+ { 0x00005408, 0x00000512 },
+ { 0x0000540c, 0x0000051a },
+ { 0x00005410, 0x00000522 },
+ { 0x00005414, 0x0000052a },
+ { 0x00005418, 0x00000532 },
+ { 0x0000541c, 0x0000053a },
+ { 0x00005420, 0x00000543 },
+ { 0x00005424, 0x0000054b },
+ { 0x00005428, 0x00000553 },
+ { 0x0000542c, 0x0000055b },
+ { 0x00005430, 0x00000564 },
+ { 0x00005434, 0x0000056c },
+ { 0x00005438, 0x00000574 },
+ { 0x0000543c, 0x0000057d },
+ { 0x00005440, 0x00000585 },
+ { 0x00005444, 0x0000058d },
+ { 0x00005448, 0x00000596 },
+ { 0x0000544c, 0x0000059e },
+ { 0x00005450, 0x000005a7 },
+ { 0x00005454, 0x000005af },
+ { 0x00005458, 0x000005b8 },
+ { 0x0000545c, 0x000005c1 },
+ { 0x00005460, 0x000005c9 },
+ { 0x00005464, 0x000005d2 },
+ { 0x00005468, 0x000005db },
+ { 0x0000546c, 0x000005e3 },
+ { 0x00005470, 0x000005ec },
+ { 0x00005474, 0x000005f5 },
+ { 0x00005478, 0x000005fe },
+ { 0x0000547c, 0x00000606 },
+ { 0x00005480, 0x0000060f },
+ { 0x00005484, 0x00000618 },
+ { 0x00005488, 0x00000621 },
+ { 0x0000548c, 0x0000062a },
+ { 0x00005490, 0x00000633 },
+ { 0x00005494, 0x0000063c },
+ { 0x00005498, 0x00000645 },
+ { 0x0000549c, 0x0000064e },
+ { 0x000054a0, 0x00000657 },
+ { 0x000054a4, 0x00000660 },
+ { 0x000054a8, 0x00000669 },
+ { 0x000054ac, 0x00000672 },
+ { 0x000054b0, 0x0000067b },
+ { 0x000054b4, 0x00000685 },
+ { 0x000054b8, 0x0000068e },
+ { 0x000054bc, 0x00000697 },
+ { 0x000054c0, 0x000006a0 },
+ { 0x000054c4, 0x000006aa },
+ { 0x000054c8, 0x000006b3 },
+ { 0x000054cc, 0x000006bd },
+ { 0x000054d0, 0x000006c6 },
+ { 0x000054d4, 0x000006cf },
+ { 0x000054d8, 0x000006d9 },
+ { 0x000054dc, 0x000006e2 },
+ { 0x000054e0, 0x000006ec },
+ { 0x000054e4, 0x000006f5 },
+ { 0x000054e8, 0x000006ff },
+ { 0x000054ec, 0x00000709 },
+ { 0x000054f0, 0x00000712 },
+ { 0x000054f4, 0x0000071c },
+ { 0x000054f8, 0x00000726 },
+ { 0x000054fc, 0x0000072f },
+ { 0x00005500, 0x00000739 },
+ { 0x00005504, 0x00000743 },
+ { 0x00005508, 0x0000074d },
+ { 0x0000550c, 0x00000756 },
+ { 0x00005510, 0x00000760 },
+ { 0x00005514, 0x0000076a },
+ { 0x00005518, 0x00000774 },
+ { 0x0000551c, 0x0000077e },
+ { 0x00005520, 0x00000788 },
+ { 0x00005524, 0x00000792 },
+ { 0x00005528, 0x0000079c },
+ { 0x0000552c, 0x000007a6 },
+ { 0x00005530, 0x000007b0 },
+ { 0x00005534, 0x000007ba },
+ { 0x00005538, 0x000007c4 },
+ { 0x0000553c, 0x000007cf },
+ { 0x00005540, 0x000007d9 },
+ { 0x00005544, 0x000007e3 },
+ { 0x00005548, 0x000007ed },
+ { 0x0000554c, 0x000007f7 },
+ { 0x00005550, 0x00000802 },
+ { 0x00005554, 0x0000080c },
+ { 0x00005558, 0x00000816 },
+ { 0x0000555c, 0x00000821 },
+ { 0x00005560, 0x0000082b },
+ { 0x00005564, 0x00000836 },
+ { 0x00005568, 0x00000840 },
+ { 0x0000556c, 0x0000084b },
+ { 0x00005570, 0x00000855 },
+ { 0x00005574, 0x00000860 },
+ { 0x00005578, 0x0000086a },
+ { 0x0000557c, 0x00000875 },
+ { 0x00005580, 0x00000880 },
+ { 0x00005584, 0x0000088a },
+ { 0x00005588, 0x00000895 },
+ { 0x0000558c, 0x000008a0 },
+ { 0x00005590, 0x000008ab },
+ { 0x00005594, 0x000008b5 },
+ { 0x00005598, 0x000008c0 },
+ { 0x0000559c, 0x000008cb },
+ { 0x000055a0, 0x000008d6 },
+ { 0x000055a4, 0x000008e1 },
+ { 0x000055a8, 0x000008ec },
+ { 0x000055ac, 0x000008f7 },
+ { 0x000055b0, 0x00000902 },
+ { 0x000055b4, 0x0000090d },
+ { 0x000055b8, 0x00000918 },
+ { 0x000055bc, 0x00000923 },
+ { 0x000055c0, 0x0000092e },
+ { 0x000055c4, 0x00000939 },
+ { 0x000055c8, 0x00000944 },
+ { 0x000055cc, 0x00000950 },
+ { 0x000055d0, 0x0000095b },
+ { 0x000055d4, 0x00000966 },
+ { 0x000055d8, 0x00000971 },
+ { 0x000055dc, 0x0000097d },
+ { 0x000055e0, 0x00000988 },
+ { 0x000055e4, 0x00000993 },
+ { 0x000055e8, 0x0000099f },
+ { 0x000055ec, 0x000009aa },
+ { 0x000055f0, 0x000009b6 },
+ { 0x000055f4, 0x000009c1 },
+ { 0x000055f8, 0x000009cd },
+ { 0x000055fc, 0x000009d8 },
+ { 0x00005600, 0x000009e4 },
+ { 0x00005604, 0x000009f0 },
+ { 0x00005608, 0x000009fb },
+ { 0x0000560c, 0x00000a07 },
+ { 0x00005610, 0x00000a13 },
+ { 0x00005614, 0x00000a1e },
+ { 0x00005618, 0x00000a2a },
+ { 0x0000561c, 0x00000a36 },
+ { 0x00005620, 0x00000a42 },
+ { 0x00005624, 0x00000a4e },
+ { 0x00005628, 0x00000a59 },
+ { 0x0000562c, 0x00000a65 },
+ { 0x00005630, 0x00000a71 },
+ { 0x00005634, 0x00000a7d },
+ { 0x00005638, 0x00000a89 },
+ { 0x0000563c, 0x00000a95 },
+ { 0x00005640, 0x00000aa1 },
+ { 0x00005644, 0x00000aad },
+ { 0x00005648, 0x00000ab9 },
+ { 0x0000564c, 0x00000ac6 },
+ { 0x00005650, 0x00000ad2 },
+ { 0x00005654, 0x00000ade },
+ { 0x00005658, 0x00000aea },
+ { 0x0000565c, 0x00000af6 },
+ { 0x00005660, 0x00000b03 },
+ { 0x00005664, 0x00000b0f },
+ { 0x00005668, 0x00000b1b },
+ { 0x0000566c, 0x00000b28 },
+ { 0x00005670, 0x00000b34 },
+ { 0x00005674, 0x00000b41 },
+ { 0x00005678, 0x00000b4d },
+ { 0x0000567c, 0x00000b5a },
+ { 0x00005680, 0x00000b66 },
+ { 0x00005684, 0x00000b73 },
+ { 0x00005688, 0x00000b7f },
+ { 0x0000568c, 0x00000b8c },
+ { 0x00005690, 0x00000b98 },
+ { 0x00005694, 0x00000ba5 },
+ { 0x00005698, 0x00000bb2 },
+ { 0x0000569c, 0x00000bbf },
+ { 0x000056a0, 0x00000bcb },
+ { 0x000056a4, 0x00000bd8 },
+ { 0x000056a8, 0x00000be5 },
+ { 0x000056ac, 0x00000bf2 },
+ { 0x000056b0, 0x00000bff },
+ { 0x000056b4, 0x00000c0c },
+ { 0x000056b8, 0x00000c19 },
+ { 0x000056bc, 0x00000c25 },
+ { 0x000056c0, 0x00000c32 },
+ { 0x000056c4, 0x00000c40 },
+ { 0x000056c8, 0x00000c4d },
+ { 0x000056cc, 0x00000c5a },
+ { 0x000056d0, 0x00000c67 },
+ { 0x000056d4, 0x00000c74 },
+ { 0x000056d8, 0x00000c81 },
+ { 0x000056dc, 0x00000c8e },
+ { 0x000056e0, 0x00000c9c },
+ { 0x000056e4, 0x00000ca9 },
+ { 0x000056e8, 0x00000cb6 },
+ { 0x000056ec, 0x00000cc3 },
+ { 0x000056f0, 0x00000cd1 },
+ { 0x000056f4, 0x00000cde },
+ { 0x000056f8, 0x00000cec },
+ { 0x000056fc, 0x00000cf9 },
+ { 0x00005700, 0x00000d07 },
+ { 0x00005704, 0x00000d14 },
+ { 0x00005708, 0x00000d22 },
+ { 0x0000570c, 0x00000d2f },
+ { 0x00005710, 0x00000d3d },
+ { 0x00005714, 0x00000d4a },
+ { 0x00005718, 0x00000d58 },
+ { 0x0000571c, 0x00000d66 },
+ { 0x00005720, 0x00000d73 },
+ { 0x00005724, 0x00000d81 },
+ { 0x00005728, 0x00000d8f },
+ { 0x0000572c, 0x00000d9d },
+ { 0x00005730, 0x00000dab },
+ { 0x00005734, 0x00000db8 },
+ { 0x00005738, 0x00000dc6 },
+ { 0x0000573c, 0x00000dd4 },
+ { 0x00005740, 0x00000de2 },
+ { 0x00005744, 0x00000df0 },
+ { 0x00005748, 0x00000dfe },
+ { 0x0000574c, 0x00000e0c },
+ { 0x00005750, 0x00000e1a },
+ { 0x00005754, 0x00000e29 },
+ { 0x00005758, 0x00000e37 },
+ { 0x0000575c, 0x00000e45 },
+ { 0x00005760, 0x00000e53 },
+ { 0x00005764, 0x00000e61 },
+ { 0x00005768, 0x00000e70 },
+ { 0x0000576c, 0x00000e7e },
+ { 0x00005770, 0x00000e8c },
+ { 0x00005774, 0x00000e9a },
+ { 0x00005778, 0x00000ea9 },
+ { 0x0000577c, 0x00000eb7 },
+ { 0x00005780, 0x00000ec6 },
+ { 0x00005784, 0x00000ed4 },
+ { 0x00005788, 0x00000ee3 },
+ { 0x0000578c, 0x00000ef1 },
+ { 0x00005790, 0x00000f00 },
+ { 0x00005794, 0x00000f0e },
+ { 0x00005798, 0x00000f1d },
+ { 0x0000579c, 0x00000f2c },
+ { 0x000057a0, 0x00000f3a },
+ { 0x000057a4, 0x00000f49 },
+ { 0x000057a8, 0x00000f58 },
+ { 0x000057ac, 0x00000f67 },
+ { 0x000057b0, 0x00000f75 },
+ { 0x000057b4, 0x00000f84 },
+ { 0x000057b8, 0x00000f93 },
+ { 0x000057bc, 0x00000fa2 },
+ { 0x000057c0, 0x00000fb1 },
+ { 0x000057c4, 0x00000fc0 },
+ { 0x000057c8, 0x00000fcf },
+ { 0x000057cc, 0x00000fde },
+ { 0x000057d0, 0x00000fed },
+ { 0x000057d4, 0x00000ffc },
+ { 0x000057d8, 0x0000100b },
+ { 0x000057dc, 0x0000101a },
+ { 0x000057e0, 0x0000102a },
+ { 0x000057e4, 0x00001039 },
+ { 0x000057e8, 0x00001048 },
+ { 0x000057ec, 0x00001057 },
+ { 0x000057f0, 0x00001067 },
+ { 0x000057f4, 0x00001076 },
+ { 0x000057f8, 0x00001085 },
+ { 0x000057fc, 0x00001095 },
+ { 0x00005800, 0x000010a4 },
+ { 0x00005804, 0x000010b4 },
+ { 0x00005808, 0x000010c3 },
+ { 0x0000580c, 0x000010d3 },
+ { 0x00005810, 0x000010e2 },
+ { 0x00005814, 0x000010f2 },
+ { 0x00005818, 0x00001101 },
+ { 0x0000581c, 0x00001111 },
+ { 0x00005820, 0x00001121 },
+ { 0x00005824, 0x00001130 },
+ { 0x00005828, 0x00001140 },
+ { 0x0000582c, 0x00001150 },
+ { 0x00005830, 0x00001160 },
+ { 0x00005834, 0x0000116f },
+ { 0x00005838, 0x0000117f },
+ { 0x0000583c, 0x0000118f },
+ { 0x00005840, 0x0000119f },
+ { 0x00005844, 0x000011af },
+ { 0x00005848, 0x000011bf },
+ { 0x0000584c, 0x000011cf },
+ { 0x00005850, 0x000011df },
+ { 0x00005854, 0x000011ef },
+ { 0x00005858, 0x000011ff },
+ { 0x0000585c, 0x0000120f },
+ { 0x00005860, 0x0000121f },
+ { 0x00005864, 0x00001230 },
+ { 0x00005868, 0x00001240 },
+ { 0x0000586c, 0x00001250 },
+ { 0x00005870, 0x00001260 },
+ { 0x00005874, 0x00001271 },
+ { 0x00005878, 0x00001281 },
+ { 0x0000587c, 0x00001291 },
+ { 0x00005880, 0x000012a2 },
+ { 0x00005884, 0x000012b2 },
+ { 0x00005888, 0x000012c3 },
+ { 0x0000588c, 0x000012d3 },
+ { 0x00005890, 0x000012e4 },
+ { 0x00005894, 0x000012f4 },
+ { 0x00005898, 0x00001305 },
+ { 0x0000589c, 0x00001316 },
+ { 0x000058a0, 0x00001326 },
+ { 0x000058a4, 0x00001337 },
+ { 0x000058a8, 0x00001348 },
+ { 0x000058ac, 0x00001359 },
+ { 0x000058b0, 0x00001369 },
+ { 0x000058b4, 0x0000137a },
+ { 0x000058b8, 0x0000138b },
+ { 0x000058bc, 0x0000139c },
+ { 0x000058c0, 0x000013ad },
+ { 0x000058c4, 0x000013be },
+ { 0x000058c8, 0x000013cf },
+ { 0x000058cc, 0x000013e0 },
+ { 0x000058d0, 0x000013f1 },
+ { 0x000058d4, 0x00001402 },
+ { 0x000058d8, 0x00001413 },
+ { 0x000058dc, 0x00001424 },
+ { 0x000058e0, 0x00001435 },
+ { 0x000058e4, 0x00001446 },
+ { 0x000058e8, 0x00001458 },
+ { 0x000058ec, 0x00001469 },
+ { 0x000058f0, 0x0000147a },
+ { 0x000058f4, 0x0000148b },
+ { 0x000058f8, 0x0000149d },
+ { 0x000058fc, 0x000014ae },
+ { 0x00005900, 0x000014c0 },
+ { 0x00005904, 0x000014d1 },
+ { 0x00005908, 0x000014e3 },
+ { 0x0000590c, 0x000014f4 },
+ { 0x00005910, 0x00001506 },
+ { 0x00005914, 0x00001517 },
+ { 0x00005918, 0x00001529 },
+ { 0x0000591c, 0x0000153a },
+ { 0x00005920, 0x0000154c },
+ { 0x00005924, 0x0000155e },
+ { 0x00005928, 0x0000156f },
+ { 0x0000592c, 0x00001581 },
+ { 0x00005930, 0x00001593 },
+ { 0x00005934, 0x000015a5 },
+ { 0x00005938, 0x000015b7 },
+ { 0x0000593c, 0x000015c9 },
+ { 0x00005940, 0x000015db },
+ { 0x00005944, 0x000015ec },
+ { 0x00005948, 0x000015fe },
+ { 0x0000594c, 0x00001610 },
+ { 0x00005950, 0x00001623 },
+ { 0x00005954, 0x00001635 },
+ { 0x00005958, 0x00001647 },
+ { 0x0000595c, 0x00001659 },
+ { 0x00005960, 0x0000166b },
+ { 0x00005964, 0x0000167d },
+ { 0x00005968, 0x0000168f },
+ { 0x0000596c, 0x000016a2 },
+ { 0x00005970, 0x000016b4 },
+ { 0x00005974, 0x000016c6 },
+ { 0x00005978, 0x000016d9 },
+ { 0x0000597c, 0x000016eb },
+ { 0x00005980, 0x000016fe },
+ { 0x00005984, 0x00001710 },
+ { 0x00005988, 0x00001722 },
+ { 0x0000598c, 0x00001735 },
+ { 0x00005990, 0x00001748 },
+ { 0x00005994, 0x0000175a },
+ { 0x00005998, 0x0000176d },
+ { 0x0000599c, 0x0000177f },
+ { 0x000059a0, 0x00001792 },
+ { 0x000059a4, 0x000017a5 },
+ { 0x000059a8, 0x000017b8 },
+ { 0x000059ac, 0x000017ca },
+ { 0x000059b0, 0x000017dd },
+ { 0x000059b4, 0x000017f0 },
+ { 0x000059b8, 0x00001803 },
+ { 0x000059bc, 0x00001816 },
+ { 0x000059c0, 0x00001829 },
+ { 0x000059c4, 0x0000183c },
+ { 0x000059c8, 0x0000184f },
+ { 0x000059cc, 0x00001862 },
+ { 0x000059d0, 0x00001875 },
+ { 0x000059d4, 0x00001888 },
+ { 0x000059d8, 0x0000189b },
+ { 0x000059dc, 0x000018ae },
+ { 0x000059e0, 0x000018c1 },
+ { 0x000059e4, 0x000018d5 },
+ { 0x000059e8, 0x000018e8 },
+ { 0x000059ec, 0x000018fb },
+ { 0x000059f0, 0x0000190e },
+ { 0x000059f4, 0x00001922 },
+ { 0x000059f8, 0x00001935 },
+ { 0x000059fc, 0x00001949 },
+ { 0x00005a00, 0x0000195c },
+ { 0x00005a04, 0x0000196f },
+ { 0x00005a08, 0x00001983 },
+ { 0x00005a0c, 0x00001996 },
+ { 0x00005a10, 0x000019aa },
+ { 0x00005a14, 0x000019be },
+ { 0x00005a18, 0x000019d1 },
+ { 0x00005a1c, 0x000019e5 },
+ { 0x00005a20, 0x000019f9 },
+ { 0x00005a24, 0x00001a0c },
+ { 0x00005a28, 0x00001a20 },
+ { 0x00005a2c, 0x00001a34 },
+ { 0x00005a30, 0x00001a48 },
+ { 0x00005a34, 0x00001a5c },
+ { 0x00005a38, 0x00001a70 },
+ { 0x00005a3c, 0x00001a84 },
+ { 0x00005a40, 0x00001a97 },
+ { 0x00005a44, 0x00001aab },
+ { 0x00005a48, 0x00001ac0 },
+ { 0x00005a4c, 0x00001ad4 },
+ { 0x00005a50, 0x00001ae8 },
+ { 0x00005a54, 0x00001afc },
+ { 0x00005a58, 0x00001b10 },
+ { 0x00005a5c, 0x00001b24 },
+ { 0x00005a60, 0x00001b38 },
+ { 0x00005a64, 0x00001b4d },
+ { 0x00005a68, 0x00001b61 },
+ { 0x00005a6c, 0x00001b75 },
+ { 0x00005a70, 0x00001b8a },
+ { 0x00005a74, 0x00001b9e },
+ { 0x00005a78, 0x00001bb2 },
+ { 0x00005a7c, 0x00001bc7 },
+ { 0x00005a80, 0x00001bdb },
+ { 0x00005a84, 0x00001bf0 },
+ { 0x00005a88, 0x00001c04 },
+ { 0x00005a8c, 0x00001c19 },
+ { 0x00005a90, 0x00001c2e },
+ { 0x00005a94, 0x00001c42 },
+ { 0x00005a98, 0x00001c57 },
+ { 0x00005a9c, 0x00001c6c },
+ { 0x00005aa0, 0x00001c80 },
+ { 0x00005aa4, 0x00001c95 },
+ { 0x00005aa8, 0x00001caa },
+ { 0x00005aac, 0x00001cbf },
+ { 0x00005ab0, 0x00001cd4 },
+ { 0x00005ab4, 0x00001ce8 },
+ { 0x00005ab8, 0x00001cfd },
+ { 0x00005abc, 0x00001d12 },
+ { 0x00005ac0, 0x00001d27 },
+ { 0x00005ac4, 0x00001d3c },
+ { 0x00005ac8, 0x00001d51 },
+ { 0x00005acc, 0x00001d67 },
+ { 0x00005ad0, 0x00001d7c },
+ { 0x00005ad4, 0x00001d91 },
+ { 0x00005ad8, 0x00001da6 },
+ { 0x00005adc, 0x00001dbb },
+ { 0x00005ae0, 0x00001dd1 },
+ { 0x00005ae4, 0x00001de6 },
+ { 0x00005ae8, 0x00001dfb },
+ { 0x00005aec, 0x00001e10 },
+ { 0x00005af0, 0x00001e26 },
+ { 0x00005af4, 0x00001e3b },
+ { 0x00005af8, 0x00001e51 },
+ { 0x00005afc, 0x00001e66 },
+ { 0x00005b00, 0x00001e7c },
+ { 0x00005b04, 0x00001e91 },
+ { 0x00005b08, 0x00001ea7 },
+ { 0x00005b0c, 0x00001ebd },
+ { 0x00005b10, 0x00001ed2 },
+ { 0x00005b14, 0x00001ee8 },
+ { 0x00005b18, 0x00001efe },
+ { 0x00005b1c, 0x00001f13 },
+ { 0x00005b20, 0x00001f29 },
+ { 0x00005b24, 0x00001f3f },
+ { 0x00005b28, 0x00001f55 },
+ { 0x00005b2c, 0x00001f6b },
+ { 0x00005b30, 0x00001f81 },
+ { 0x00005b34, 0x00001f96 },
+ { 0x00005b38, 0x00001fac },
+ { 0x00005b3c, 0x00001fc2 },
+ { 0x00005b40, 0x00001fd9 },
+ { 0x00005b44, 0x00001fef },
+ { 0x00005b48, 0x00002005 },
+ { 0x00005b4c, 0x0000201b },
+ { 0x00005b50, 0x00002031 },
+ { 0x00005b54, 0x00002047 },
+ { 0x00005b58, 0x0000205d },
+ { 0x00005b5c, 0x00002074 },
+ { 0x00005b60, 0x0000208a },
+ { 0x00005b64, 0x000020a0 },
+ { 0x00005b68, 0x000020b7 },
+ { 0x00005b6c, 0x000020cd },
+ { 0x00005b70, 0x000020e4 },
+ { 0x00005b74, 0x000020fa },
+ { 0x00005b78, 0x00002111 },
+ { 0x00005b7c, 0x00002127 },
+ { 0x00005b80, 0x0000213e },
+ { 0x00005b84, 0x00002154 },
+ { 0x00005b88, 0x0000216b },
+ { 0x00005b8c, 0x00002182 },
+ { 0x00005b90, 0x00002198 },
+ { 0x00005b94, 0x000021af },
+ { 0x00005b98, 0x000021c6 },
+ { 0x00005b9c, 0x000021dd },
+ { 0x00005ba0, 0x000021f3 },
+ { 0x00005ba4, 0x0000220a },
+ { 0x00005ba8, 0x00002221 },
+ { 0x00005bac, 0x00002238 },
+ { 0x00005bb0, 0x0000224f },
+ { 0x00005bb4, 0x00002266 },
+ { 0x00005bb8, 0x0000227d },
+ { 0x00005bbc, 0x00002294 },
+ { 0x00005bc0, 0x000022ab },
+ { 0x00005bc4, 0x000022c2 },
+ { 0x00005bc8, 0x000022da },
+ { 0x00005bcc, 0x000022f1 },
+ { 0x00005bd0, 0x00002308 },
+ { 0x00005bd4, 0x0000231f },
+ { 0x00005bd8, 0x00002337 },
+ { 0x00005bdc, 0x0000234e },
+ { 0x00005be0, 0x00002365 },
+ { 0x00005be4, 0x0000237d },
+ { 0x00005be8, 0x00002394 },
+ { 0x00005bec, 0x000023ac },
+ { 0x00005bf0, 0x000023c3 },
+ { 0x00005bf4, 0x000023db },
+ { 0x00005bf8, 0x000023f2 },
+ { 0x00005bfc, 0x0000240a },
+ { 0x00005c00, 0x00002421 },
+ { 0x00005c04, 0x00002439 },
+ { 0x00005c08, 0x00002451 },
+ { 0x00005c0c, 0x00002469 },
+ { 0x00005c10, 0x00002480 },
+ { 0x00005c14, 0x00002498 },
+ { 0x00005c18, 0x000024b0 },
+ { 0x00005c1c, 0x000024c8 },
+ { 0x00005c20, 0x000024e0 },
+ { 0x00005c24, 0x000024f8 },
+ { 0x00005c28, 0x00002510 },
+ { 0x00005c2c, 0x00002528 },
+ { 0x00005c30, 0x00002540 },
+ { 0x00005c34, 0x00002558 },
+ { 0x00005c38, 0x00002570 },
+ { 0x00005c3c, 0x00002588 },
+ { 0x00005c40, 0x000025a0 },
+ { 0x00005c44, 0x000025b8 },
+ { 0x00005c48, 0x000025d0 },
+ { 0x00005c4c, 0x000025e9 },
+ { 0x00005c50, 0x00002601 },
+ { 0x00005c54, 0x00002619 },
+ { 0x00005c58, 0x00002632 },
+ { 0x00005c5c, 0x0000264a },
+ { 0x00005c60, 0x00002663 },
+ { 0x00005c64, 0x0000267b },
+ { 0x00005c68, 0x00002693 },
+ { 0x00005c6c, 0x000026ac },
+ { 0x00005c70, 0x000026c5 },
+ { 0x00005c74, 0x000026dd },
+ { 0x00005c78, 0x000026f6 },
+ { 0x00005c7c, 0x0000270e },
+ { 0x00005c80, 0x00002727 },
+ { 0x00005c84, 0x00002740 },
+ { 0x00005c88, 0x00002759 },
+ { 0x00005c8c, 0x00002771 },
+ { 0x00005c90, 0x0000278a },
+ { 0x00005c94, 0x000027a3 },
+ { 0x00005c98, 0x000027bc },
+ { 0x00005c9c, 0x000027d5 },
+ { 0x00005ca0, 0x000027ee },
+ { 0x00005ca4, 0x00002807 },
+ { 0x00005ca8, 0x00002820 },
+ { 0x00005cac, 0x00002839 },
+ { 0x00005cb0, 0x00002852 },
+ { 0x00005cb4, 0x0000286b },
+ { 0x00005cb8, 0x00002884 },
+ { 0x00005cbc, 0x0000289e },
+ { 0x00005cc0, 0x000028b7 },
+ { 0x00005cc4, 0x000028d0 },
+ { 0x00005cc8, 0x000028e9 },
+ { 0x00005ccc, 0x00002903 },
+ { 0x00005cd0, 0x0000291c },
+ { 0x00005cd4, 0x00002936 },
+ { 0x00005cd8, 0x0000294f },
+ { 0x00005cdc, 0x00002968 },
+ { 0x00005ce0, 0x00002982 },
+ { 0x00005ce4, 0x0000299c },
+ { 0x00005ce8, 0x000029b5 },
+ { 0x00005cec, 0x000029cf },
+ { 0x00005cf0, 0x000029e8 },
+ { 0x00005cf4, 0x00002a02 },
+ { 0x00005cf8, 0x00002a1c },
+ { 0x00005cfc, 0x00002a35 },
+ { 0x00005d00, 0x00002a4f },
+ { 0x00005d04, 0x00002a69 },
+ { 0x00005d08, 0x00002a83 },
+ { 0x00005d0c, 0x00002a9d },
+ { 0x00005d10, 0x00002ab7 },
+ { 0x00005d14, 0x00002ad1 },
+ { 0x00005d18, 0x00002aeb },
+ { 0x00005d1c, 0x00002b05 },
+ { 0x00005d20, 0x00002b1f },
+ { 0x00005d24, 0x00002b39 },
+ { 0x00005d28, 0x00002b53 },
+ { 0x00005d2c, 0x00002b6d },
+ { 0x00005d30, 0x00002b87 },
+ { 0x00005d34, 0x00002ba1 },
+ { 0x00005d38, 0x00002bbc },
+ { 0x00005d3c, 0x00002bd6 },
+ { 0x00005d40, 0x00002bf0 },
+ { 0x00005d44, 0x00002c0b },
+ { 0x00005d48, 0x00002c25 },
+ { 0x00005d4c, 0x00002c3f },
+ { 0x00005d50, 0x00002c5a },
+ { 0x00005d54, 0x00002c74 },
+ { 0x00005d58, 0x00002c8f },
+ { 0x00005d5c, 0x00002ca9 },
+ { 0x00005d60, 0x00002cc4 },
+ { 0x00005d64, 0x00002cdf },
+ { 0x00005d68, 0x00002cf9 },
+ { 0x00005d6c, 0x00002d14 },
+ { 0x00005d70, 0x00002d2f },
+ { 0x00005d74, 0x00002d49 },
+ { 0x00005d78, 0x00002d64 },
+ { 0x00005d7c, 0x00002d7f },
+ { 0x00005d80, 0x00002d9a },
+ { 0x00005d84, 0x00002db5 },
+ { 0x00005d88, 0x00002dd0 },
+ { 0x00005d8c, 0x00002deb },
+ { 0x00005d90, 0x00002e06 },
+ { 0x00005d94, 0x00002e21 },
+ { 0x00005d98, 0x00002e3c },
+ { 0x00005d9c, 0x00002e57 },
+ { 0x00005da0, 0x00002e72 },
+ { 0x00005da4, 0x00002e8d },
+ { 0x00005da8, 0x00002ea8 },
+ { 0x00005dac, 0x00002ec4 },
+ { 0x00005db0, 0x00002edf },
+ { 0x00005db4, 0x00002efa },
+ { 0x00005db8, 0x00002f16 },
+ { 0x00005dbc, 0x00002f31 },
+ { 0x00005dc0, 0x00002f4c },
+ { 0x00005dc4, 0x00002f68 },
+ { 0x00005dc8, 0x00002f83 },
+ { 0x00005dcc, 0x00002f9f },
+ { 0x00005dd0, 0x00002fba },
+ { 0x00005dd4, 0x00002fd6 },
+ { 0x00005dd8, 0x00002ff1 },
+ { 0x00005ddc, 0x0000300d },
+ { 0x00005de0, 0x00003029 },
+ { 0x00005de4, 0x00003044 },
+ { 0x00005de8, 0x00003060 },
+ { 0x00005dec, 0x0000307c },
+ { 0x00005df0, 0x00003098 },
+ { 0x00005df4, 0x000030b4 },
+ { 0x00005df8, 0x000030d0 },
+ { 0x00005dfc, 0x000030eb },
+ { 0x00005e00, 0x00003107 },
+ { 0x00005e04, 0x00003123 },
+ { 0x00005e08, 0x0000313f },
+ { 0x00005e0c, 0x0000315b },
+ { 0x00005e10, 0x00003178 },
+ { 0x00005e14, 0x00003194 },
+ { 0x00005e18, 0x000031b0 },
+ { 0x00005e1c, 0x000031cc },
+ { 0x00005e20, 0x000031e8 },
+ { 0x00005e24, 0x00003205 },
+ { 0x00005e28, 0x00003221 },
+ { 0x00005e2c, 0x0000323d },
+ { 0x00005e30, 0x0000325a },
+ { 0x00005e34, 0x00003276 },
+ { 0x00005e38, 0x00003292 },
+ { 0x00005e3c, 0x000032af },
+ { 0x00005e40, 0x000032cb },
+ { 0x00005e44, 0x000032e8 },
+ { 0x00005e48, 0x00003304 },
+ { 0x00005e4c, 0x00003321 },
+ { 0x00005e50, 0x0000333e },
+ { 0x00005e54, 0x0000335a },
+ { 0x00005e58, 0x00003377 },
+ { 0x00005e5c, 0x00003394 },
+ { 0x00005e60, 0x000033b1 },
+ { 0x00005e64, 0x000033cd },
+ { 0x00005e68, 0x000033ea },
+ { 0x00005e6c, 0x00003407 },
+ { 0x00005e70, 0x00003424 },
+ { 0x00005e74, 0x00003441 },
+ { 0x00005e78, 0x0000345e },
+ { 0x00005e7c, 0x0000347b },
+ { 0x00005e80, 0x00003498 },
+ { 0x00005e84, 0x000034b5 },
+ { 0x00005e88, 0x000034d2 },
+ { 0x00005e8c, 0x000034ef },
+ { 0x00005e90, 0x0000350d },
+ { 0x00005e94, 0x0000352a },
+ { 0x00005e98, 0x00003547 },
+ { 0x00005e9c, 0x00003564 },
+ { 0x00005ea0, 0x00003582 },
+ { 0x00005ea4, 0x0000359f },
+ { 0x00005ea8, 0x000035bc },
+ { 0x00005eac, 0x000035da },
+ { 0x00005eb0, 0x000035f7 },
+ { 0x00005eb4, 0x00003615 },
+ { 0x00005eb8, 0x00003632 },
+ { 0x00005ebc, 0x00003650 },
+ { 0x00005ec0, 0x0000366e },
+ { 0x00005ec4, 0x0000368b },
+ { 0x00005ec8, 0x000036a9 },
+ { 0x00005ecc, 0x000036c7 },
+ { 0x00005ed0, 0x000036e4 },
+ { 0x00005ed4, 0x00003702 },
+ { 0x00005ed8, 0x00003720 },
+ { 0x00005edc, 0x0000373e },
+ { 0x00005ee0, 0x0000375c },
+ { 0x00005ee4, 0x0000377a },
+ { 0x00005ee8, 0x00003798 },
+ { 0x00005eec, 0x000037b6 },
+ { 0x00005ef0, 0x000037d4 },
+ { 0x00005ef4, 0x000037f2 },
+ { 0x00005ef8, 0x00003810 },
+ { 0x00005efc, 0x0000382e },
+ { 0x00005f00, 0x0000384c },
+ { 0x00005f04, 0x0000386a },
+ { 0x00005f08, 0x00003888 },
+ { 0x00005f0c, 0x000038a7 },
+ { 0x00005f10, 0x000038c5 },
+ { 0x00005f14, 0x000038e3 },
+ { 0x00005f18, 0x00003902 },
+ { 0x00005f1c, 0x00003920 },
+ { 0x00005f20, 0x0000393f },
+ { 0x00005f24, 0x0000395d },
+ { 0x00005f28, 0x0000397c },
+ { 0x00005f2c, 0x0000399a },
+ { 0x00005f30, 0x000039b9 },
+ { 0x00005f34, 0x000039d7 },
+ { 0x00005f38, 0x000039f6 },
+ { 0x00005f3c, 0x00003a15 },
+ { 0x00005f40, 0x00003a33 },
+ { 0x00005f44, 0x00003a52 },
+ { 0x00005f48, 0x00003a71 },
+ { 0x00005f4c, 0x00003a90 },
+ { 0x00005f50, 0x00003aaf },
+ { 0x00005f54, 0x00003acd },
+ { 0x00005f58, 0x00003aec },
+ { 0x00005f5c, 0x00003b0b },
+ { 0x00005f60, 0x00003b2a },
+ { 0x00005f64, 0x00003b49 },
+ { 0x00005f68, 0x00003b68 },
+ { 0x00005f6c, 0x00003b87 },
+ { 0x00005f70, 0x00003ba7 },
+ { 0x00005f74, 0x00003bc6 },
+ { 0x00005f78, 0x00003be5 },
+ { 0x00005f7c, 0x00003c04 },
+ { 0x00005f80, 0x00003c24 },
+ { 0x00005f84, 0x00003c43 },
+ { 0x00005f88, 0x00003c62 },
+ { 0x00005f8c, 0x00003c82 },
+ { 0x00005f90, 0x00003ca1 },
+ { 0x00005f94, 0x00003cc0 },
+ { 0x00005f98, 0x00003ce0 },
+ { 0x00005f9c, 0x00003cff },
+ { 0x00005fa0, 0x00003d1f },
+ { 0x00005fa4, 0x00003d3f },
+ { 0x00005fa8, 0x00003d5e },
+ { 0x00005fac, 0x00003d7e },
+ { 0x00005fb0, 0x00003d9e },
+ { 0x00005fb4, 0x00003dbd },
+ { 0x00005fb8, 0x00003ddd },
+ { 0x00005fbc, 0x00003dfd },
+ { 0x00005fc0, 0x00003e1d },
+ { 0x00005fc4, 0x00003e3d },
+ { 0x00005fc8, 0x00003e5d },
+ { 0x00005fcc, 0x00003e7c },
+ { 0x00005fd0, 0x00003e9c },
+ { 0x00005fd4, 0x00003ebc },
+ { 0x00005fd8, 0x00003edc },
+ { 0x00005fdc, 0x00003efd },
+ { 0x00005fe0, 0x00003f1d },
+ { 0x00005fe4, 0x00003f3d },
+ { 0x00005fe8, 0x00003f5d },
+ { 0x00005fec, 0x00003f7d },
+ { 0x00005ff0, 0x00003f9e },
+ { 0x00005ff4, 0x00003fbe },
+ { 0x00005ff8, 0x00003fde },
+ { 0x00005ffc, 0x00003fff },
+};
+
+struct data_unit hdr10_pipe2_lut_a2[] = {
+ { 0x00006000, 0x00000000 },
+ { 0x00006004, 0x00000003 },
+ { 0x00006008, 0x00000007 },
+ { 0x0000600c, 0x0000000a },
+ { 0x00006010, 0x0000000e },
+ { 0x00006014, 0x00000011 },
+ { 0x00006018, 0x00000015 },
+ { 0x0000601c, 0x00000018 },
+ { 0x00006020, 0x0000001c },
+ { 0x00006024, 0x00000020 },
+ { 0x00006028, 0x00000023 },
+ { 0x0000602c, 0x00000027 },
+ { 0x00006030, 0x0000002a },
+ { 0x00006034, 0x0000002e },
+ { 0x00006038, 0x00000031 },
+ { 0x0000603c, 0x00000035 },
+ { 0x00006040, 0x00000038 },
+ { 0x00006044, 0x0000003c },
+ { 0x00006048, 0x00000040 },
+ { 0x0000604c, 0x00000043 },
+ { 0x00006050, 0x00000047 },
+ { 0x00006054, 0x0000004a },
+ { 0x00006058, 0x0000004e },
+ { 0x0000605c, 0x00000051 },
+ { 0x00006060, 0x00000055 },
+ { 0x00006064, 0x00000058 },
+ { 0x00006068, 0x0000005c },
+ { 0x0000606c, 0x00000060 },
+ { 0x00006070, 0x00000063 },
+ { 0x00006074, 0x00000067 },
+ { 0x00006078, 0x0000006a },
+ { 0x0000607c, 0x0000006e },
+ { 0x00006080, 0x00000071 },
+ { 0x00006084, 0x00000075 },
+ { 0x00006088, 0x00000078 },
+ { 0x0000608c, 0x0000007c },
+ { 0x00006090, 0x00000080 },
+ { 0x00006094, 0x00000083 },
+ { 0x00006098, 0x00000087 },
+ { 0x0000609c, 0x0000008a },
+ { 0x000060a0, 0x0000008e },
+ { 0x000060a4, 0x00000091 },
+ { 0x000060a8, 0x00000095 },
+ { 0x000060ac, 0x00000099 },
+ { 0x000060b0, 0x0000009c },
+ { 0x000060b4, 0x000000a0 },
+ { 0x000060b8, 0x000000a3 },
+ { 0x000060bc, 0x000000a7 },
+ { 0x000060c0, 0x000000aa },
+ { 0x000060c4, 0x000000ae },
+ { 0x000060c8, 0x000000b1 },
+ { 0x000060cc, 0x000000b5 },
+ { 0x000060d0, 0x000000b9 },
+ { 0x000060d4, 0x000000bc },
+ { 0x000060d8, 0x000000c0 },
+ { 0x000060dc, 0x000000c3 },
+ { 0x000060e0, 0x000000c7 },
+ { 0x000060e4, 0x000000ca },
+ { 0x000060e8, 0x000000ce },
+ { 0x000060ec, 0x000000d1 },
+ { 0x000060f0, 0x000000d5 },
+ { 0x000060f4, 0x000000d9 },
+ { 0x000060f8, 0x000000dc },
+ { 0x000060fc, 0x000000e0 },
+ { 0x00006100, 0x000000e3 },
+ { 0x00006104, 0x000000e7 },
+ { 0x00006108, 0x000000ea },
+ { 0x0000610c, 0x000000ee },
+ { 0x00006110, 0x000000f1 },
+ { 0x00006114, 0x000000f5 },
+ { 0x00006118, 0x000000f9 },
+ { 0x0000611c, 0x000000fc },
+ { 0x00006120, 0x00000100 },
+ { 0x00006124, 0x00000103 },
+ { 0x00006128, 0x00000107 },
+ { 0x0000612c, 0x0000010a },
+ { 0x00006130, 0x0000010e },
+ { 0x00006134, 0x00000112 },
+ { 0x00006138, 0x00000115 },
+ { 0x0000613c, 0x00000119 },
+ { 0x00006140, 0x0000011c },
+ { 0x00006144, 0x00000120 },
+ { 0x00006148, 0x00000123 },
+ { 0x0000614c, 0x00000126 },
+ { 0x00006150, 0x0000012a },
+ { 0x00006154, 0x0000012d },
+ { 0x00006158, 0x00000131 },
+ { 0x0000615c, 0x00000134 },
+ { 0x00006160, 0x00000138 },
+ { 0x00006164, 0x0000013c },
+ { 0x00006168, 0x0000013f },
+ { 0x0000616c, 0x00000143 },
+ { 0x00006170, 0x00000147 },
+ { 0x00006174, 0x0000014b },
+ { 0x00006178, 0x0000014e },
+ { 0x0000617c, 0x00000152 },
+ { 0x00006180, 0x00000156 },
+ { 0x00006184, 0x0000015a },
+ { 0x00006188, 0x0000015e },
+ { 0x0000618c, 0x00000162 },
+ { 0x00006190, 0x00000166 },
+ { 0x00006194, 0x0000016a },
+ { 0x00006198, 0x0000016e },
+ { 0x0000619c, 0x00000172 },
+ { 0x000061a0, 0x00000176 },
+ { 0x000061a4, 0x0000017a },
+ { 0x000061a8, 0x0000017e },
+ { 0x000061ac, 0x00000182 },
+ { 0x000061b0, 0x00000186 },
+ { 0x000061b4, 0x0000018a },
+ { 0x000061b8, 0x0000018f },
+ { 0x000061bc, 0x00000193 },
+ { 0x000061c0, 0x00000197 },
+ { 0x000061c4, 0x0000019b },
+ { 0x000061c8, 0x000001a0 },
+ { 0x000061cc, 0x000001a4 },
+ { 0x000061d0, 0x000001a8 },
+ { 0x000061d4, 0x000001ad },
+ { 0x000061d8, 0x000001b1 },
+ { 0x000061dc, 0x000001b5 },
+ { 0x000061e0, 0x000001ba },
+ { 0x000061e4, 0x000001be },
+ { 0x000061e8, 0x000001c3 },
+ { 0x000061ec, 0x000001c7 },
+ { 0x000061f0, 0x000001cc },
+ { 0x000061f4, 0x000001d0 },
+ { 0x000061f8, 0x000001d5 },
+ { 0x000061fc, 0x000001d9 },
+ { 0x00006200, 0x000001de },
+ { 0x00006204, 0x000001e3 },
+ { 0x00006208, 0x000001e7 },
+ { 0x0000620c, 0x000001ec },
+ { 0x00006210, 0x000001f1 },
+ { 0x00006214, 0x000001f6 },
+ { 0x00006218, 0x000001fa },
+ { 0x0000621c, 0x000001ff },
+ { 0x00006220, 0x00000204 },
+ { 0x00006224, 0x00000209 },
+ { 0x00006228, 0x0000020e },
+ { 0x0000622c, 0x00000213 },
+ { 0x00006230, 0x00000217 },
+ { 0x00006234, 0x0000021c },
+ { 0x00006238, 0x00000221 },
+ { 0x0000623c, 0x00000226 },
+ { 0x00006240, 0x0000022b },
+ { 0x00006244, 0x00000230 },
+ { 0x00006248, 0x00000236 },
+ { 0x0000624c, 0x0000023b },
+ { 0x00006250, 0x00000240 },
+ { 0x00006254, 0x00000245 },
+ { 0x00006258, 0x0000024a },
+ { 0x0000625c, 0x0000024f },
+ { 0x00006260, 0x00000255 },
+ { 0x00006264, 0x0000025a },
+ { 0x00006268, 0x0000025f },
+ { 0x0000626c, 0x00000264 },
+ { 0x00006270, 0x0000026a },
+ { 0x00006274, 0x0000026f },
+ { 0x00006278, 0x00000274 },
+ { 0x0000627c, 0x0000027a },
+ { 0x00006280, 0x0000027f },
+ { 0x00006284, 0x00000285 },
+ { 0x00006288, 0x0000028a },
+ { 0x0000628c, 0x00000290 },
+ { 0x00006290, 0x00000295 },
+ { 0x00006294, 0x0000029b },
+ { 0x00006298, 0x000002a0 },
+ { 0x0000629c, 0x000002a6 },
+ { 0x000062a0, 0x000002ac },
+ { 0x000062a4, 0x000002b1 },
+ { 0x000062a8, 0x000002b7 },
+ { 0x000062ac, 0x000002bd },
+ { 0x000062b0, 0x000002c2 },
+ { 0x000062b4, 0x000002c8 },
+ { 0x000062b8, 0x000002ce },
+ { 0x000062bc, 0x000002d4 },
+ { 0x000062c0, 0x000002da },
+ { 0x000062c4, 0x000002df },
+ { 0x000062c8, 0x000002e5 },
+ { 0x000062cc, 0x000002eb },
+ { 0x000062d0, 0x000002f1 },
+ { 0x000062d4, 0x000002f7 },
+ { 0x000062d8, 0x000002fd },
+ { 0x000062dc, 0x00000303 },
+ { 0x000062e0, 0x00000309 },
+ { 0x000062e4, 0x0000030f },
+ { 0x000062e8, 0x00000315 },
+ { 0x000062ec, 0x0000031c },
+ { 0x000062f0, 0x00000322 },
+ { 0x000062f4, 0x00000328 },
+ { 0x000062f8, 0x0000032e },
+ { 0x000062fc, 0x00000334 },
+ { 0x00006300, 0x0000033b },
+ { 0x00006304, 0x00000341 },
+ { 0x00006308, 0x00000347 },
+ { 0x0000630c, 0x0000034d },
+ { 0x00006310, 0x00000354 },
+ { 0x00006314, 0x0000035a },
+ { 0x00006318, 0x00000361 },
+ { 0x0000631c, 0x00000367 },
+ { 0x00006320, 0x0000036d },
+ { 0x00006324, 0x00000374 },
+ { 0x00006328, 0x0000037a },
+ { 0x0000632c, 0x00000381 },
+ { 0x00006330, 0x00000388 },
+ { 0x00006334, 0x0000038e },
+ { 0x00006338, 0x00000395 },
+ { 0x0000633c, 0x0000039b },
+ { 0x00006340, 0x000003a2 },
+ { 0x00006344, 0x000003a9 },
+ { 0x00006348, 0x000003b0 },
+ { 0x0000634c, 0x000003b6 },
+ { 0x00006350, 0x000003bd },
+ { 0x00006354, 0x000003c4 },
+ { 0x00006358, 0x000003cb },
+ { 0x0000635c, 0x000003d2 },
+ { 0x00006360, 0x000003d8 },
+ { 0x00006364, 0x000003df },
+ { 0x00006368, 0x000003e6 },
+ { 0x0000636c, 0x000003ed },
+ { 0x00006370, 0x000003f4 },
+ { 0x00006374, 0x000003fb },
+ { 0x00006378, 0x00000402 },
+ { 0x0000637c, 0x00000409 },
+ { 0x00006380, 0x00000411 },
+ { 0x00006384, 0x00000418 },
+ { 0x00006388, 0x0000041f },
+ { 0x0000638c, 0x00000426 },
+ { 0x00006390, 0x0000042d },
+ { 0x00006394, 0x00000434 },
+ { 0x00006398, 0x0000043c },
+ { 0x0000639c, 0x00000443 },
+ { 0x000063a0, 0x0000044a },
+ { 0x000063a4, 0x00000452 },
+ { 0x000063a8, 0x00000459 },
+ { 0x000063ac, 0x00000460 },
+ { 0x000063b0, 0x00000468 },
+ { 0x000063b4, 0x0000046f },
+ { 0x000063b8, 0x00000477 },
+ { 0x000063bc, 0x0000047e },
+ { 0x000063c0, 0x00000486 },
+ { 0x000063c4, 0x0000048d },
+ { 0x000063c8, 0x00000495 },
+ { 0x000063cc, 0x0000049c },
+ { 0x000063d0, 0x000004a4 },
+ { 0x000063d4, 0x000004ac },
+ { 0x000063d8, 0x000004b3 },
+ { 0x000063dc, 0x000004bb },
+ { 0x000063e0, 0x000004c3 },
+ { 0x000063e4, 0x000004cb },
+ { 0x000063e8, 0x000004d3 },
+ { 0x000063ec, 0x000004da },
+ { 0x000063f0, 0x000004e2 },
+ { 0x000063f4, 0x000004ea },
+ { 0x000063f8, 0x000004f2 },
+ { 0x000063fc, 0x000004fa },
+ { 0x00006400, 0x00000502 },
+ { 0x00006404, 0x0000050a },
+ { 0x00006408, 0x00000512 },
+ { 0x0000640c, 0x0000051a },
+ { 0x00006410, 0x00000522 },
+ { 0x00006414, 0x0000052a },
+ { 0x00006418, 0x00000532 },
+ { 0x0000641c, 0x0000053a },
+ { 0x00006420, 0x00000543 },
+ { 0x00006424, 0x0000054b },
+ { 0x00006428, 0x00000553 },
+ { 0x0000642c, 0x0000055b },
+ { 0x00006430, 0x00000564 },
+ { 0x00006434, 0x0000056c },
+ { 0x00006438, 0x00000574 },
+ { 0x0000643c, 0x0000057d },
+ { 0x00006440, 0x00000585 },
+ { 0x00006444, 0x0000058d },
+ { 0x00006448, 0x00000596 },
+ { 0x0000644c, 0x0000059e },
+ { 0x00006450, 0x000005a7 },
+ { 0x00006454, 0x000005af },
+ { 0x00006458, 0x000005b8 },
+ { 0x0000645c, 0x000005c1 },
+ { 0x00006460, 0x000005c9 },
+ { 0x00006464, 0x000005d2 },
+ { 0x00006468, 0x000005db },
+ { 0x0000646c, 0x000005e3 },
+ { 0x00006470, 0x000005ec },
+ { 0x00006474, 0x000005f5 },
+ { 0x00006478, 0x000005fe },
+ { 0x0000647c, 0x00000606 },
+ { 0x00006480, 0x0000060f },
+ { 0x00006484, 0x00000618 },
+ { 0x00006488, 0x00000621 },
+ { 0x0000648c, 0x0000062a },
+ { 0x00006490, 0x00000633 },
+ { 0x00006494, 0x0000063c },
+ { 0x00006498, 0x00000645 },
+ { 0x0000649c, 0x0000064e },
+ { 0x000064a0, 0x00000657 },
+ { 0x000064a4, 0x00000660 },
+ { 0x000064a8, 0x00000669 },
+ { 0x000064ac, 0x00000672 },
+ { 0x000064b0, 0x0000067b },
+ { 0x000064b4, 0x00000685 },
+ { 0x000064b8, 0x0000068e },
+ { 0x000064bc, 0x00000697 },
+ { 0x000064c0, 0x000006a0 },
+ { 0x000064c4, 0x000006aa },
+ { 0x000064c8, 0x000006b3 },
+ { 0x000064cc, 0x000006bd },
+ { 0x000064d0, 0x000006c6 },
+ { 0x000064d4, 0x000006cf },
+ { 0x000064d8, 0x000006d9 },
+ { 0x000064dc, 0x000006e2 },
+ { 0x000064e0, 0x000006ec },
+ { 0x000064e4, 0x000006f5 },
+ { 0x000064e8, 0x000006ff },
+ { 0x000064ec, 0x00000709 },
+ { 0x000064f0, 0x00000712 },
+ { 0x000064f4, 0x0000071c },
+ { 0x000064f8, 0x00000726 },
+ { 0x000064fc, 0x0000072f },
+ { 0x00006500, 0x00000739 },
+ { 0x00006504, 0x00000743 },
+ { 0x00006508, 0x0000074d },
+ { 0x0000650c, 0x00000756 },
+ { 0x00006510, 0x00000760 },
+ { 0x00006514, 0x0000076a },
+ { 0x00006518, 0x00000774 },
+ { 0x0000651c, 0x0000077e },
+ { 0x00006520, 0x00000788 },
+ { 0x00006524, 0x00000792 },
+ { 0x00006528, 0x0000079c },
+ { 0x0000652c, 0x000007a6 },
+ { 0x00006530, 0x000007b0 },
+ { 0x00006534, 0x000007ba },
+ { 0x00006538, 0x000007c4 },
+ { 0x0000653c, 0x000007cf },
+ { 0x00006540, 0x000007d9 },
+ { 0x00006544, 0x000007e3 },
+ { 0x00006548, 0x000007ed },
+ { 0x0000654c, 0x000007f7 },
+ { 0x00006550, 0x00000802 },
+ { 0x00006554, 0x0000080c },
+ { 0x00006558, 0x00000816 },
+ { 0x0000655c, 0x00000821 },
+ { 0x00006560, 0x0000082b },
+ { 0x00006564, 0x00000836 },
+ { 0x00006568, 0x00000840 },
+ { 0x0000656c, 0x0000084b },
+ { 0x00006570, 0x00000855 },
+ { 0x00006574, 0x00000860 },
+ { 0x00006578, 0x0000086a },
+ { 0x0000657c, 0x00000875 },
+ { 0x00006580, 0x00000880 },
+ { 0x00006584, 0x0000088a },
+ { 0x00006588, 0x00000895 },
+ { 0x0000658c, 0x000008a0 },
+ { 0x00006590, 0x000008ab },
+ { 0x00006594, 0x000008b5 },
+ { 0x00006598, 0x000008c0 },
+ { 0x0000659c, 0x000008cb },
+ { 0x000065a0, 0x000008d6 },
+ { 0x000065a4, 0x000008e1 },
+ { 0x000065a8, 0x000008ec },
+ { 0x000065ac, 0x000008f7 },
+ { 0x000065b0, 0x00000902 },
+ { 0x000065b4, 0x0000090d },
+ { 0x000065b8, 0x00000918 },
+ { 0x000065bc, 0x00000923 },
+ { 0x000065c0, 0x0000092e },
+ { 0x000065c4, 0x00000939 },
+ { 0x000065c8, 0x00000944 },
+ { 0x000065cc, 0x00000950 },
+ { 0x000065d0, 0x0000095b },
+ { 0x000065d4, 0x00000966 },
+ { 0x000065d8, 0x00000971 },
+ { 0x000065dc, 0x0000097d },
+ { 0x000065e0, 0x00000988 },
+ { 0x000065e4, 0x00000993 },
+ { 0x000065e8, 0x0000099f },
+ { 0x000065ec, 0x000009aa },
+ { 0x000065f0, 0x000009b6 },
+ { 0x000065f4, 0x000009c1 },
+ { 0x000065f8, 0x000009cd },
+ { 0x000065fc, 0x000009d8 },
+ { 0x00006600, 0x000009e4 },
+ { 0x00006604, 0x000009f0 },
+ { 0x00006608, 0x000009fb },
+ { 0x0000660c, 0x00000a07 },
+ { 0x00006610, 0x00000a13 },
+ { 0x00006614, 0x00000a1e },
+ { 0x00006618, 0x00000a2a },
+ { 0x0000661c, 0x00000a36 },
+ { 0x00006620, 0x00000a42 },
+ { 0x00006624, 0x00000a4e },
+ { 0x00006628, 0x00000a59 },
+ { 0x0000662c, 0x00000a65 },
+ { 0x00006630, 0x00000a71 },
+ { 0x00006634, 0x00000a7d },
+ { 0x00006638, 0x00000a89 },
+ { 0x0000663c, 0x00000a95 },
+ { 0x00006640, 0x00000aa1 },
+ { 0x00006644, 0x00000aad },
+ { 0x00006648, 0x00000ab9 },
+ { 0x0000664c, 0x00000ac6 },
+ { 0x00006650, 0x00000ad2 },
+ { 0x00006654, 0x00000ade },
+ { 0x00006658, 0x00000aea },
+ { 0x0000665c, 0x00000af6 },
+ { 0x00006660, 0x00000b03 },
+ { 0x00006664, 0x00000b0f },
+ { 0x00006668, 0x00000b1b },
+ { 0x0000666c, 0x00000b28 },
+ { 0x00006670, 0x00000b34 },
+ { 0x00006674, 0x00000b41 },
+ { 0x00006678, 0x00000b4d },
+ { 0x0000667c, 0x00000b5a },
+ { 0x00006680, 0x00000b66 },
+ { 0x00006684, 0x00000b73 },
+ { 0x00006688, 0x00000b7f },
+ { 0x0000668c, 0x00000b8c },
+ { 0x00006690, 0x00000b98 },
+ { 0x00006694, 0x00000ba5 },
+ { 0x00006698, 0x00000bb2 },
+ { 0x0000669c, 0x00000bbf },
+ { 0x000066a0, 0x00000bcb },
+ { 0x000066a4, 0x00000bd8 },
+ { 0x000066a8, 0x00000be5 },
+ { 0x000066ac, 0x00000bf2 },
+ { 0x000066b0, 0x00000bff },
+ { 0x000066b4, 0x00000c0c },
+ { 0x000066b8, 0x00000c19 },
+ { 0x000066bc, 0x00000c25 },
+ { 0x000066c0, 0x00000c32 },
+ { 0x000066c4, 0x00000c40 },
+ { 0x000066c8, 0x00000c4d },
+ { 0x000066cc, 0x00000c5a },
+ { 0x000066d0, 0x00000c67 },
+ { 0x000066d4, 0x00000c74 },
+ { 0x000066d8, 0x00000c81 },
+ { 0x000066dc, 0x00000c8e },
+ { 0x000066e0, 0x00000c9c },
+ { 0x000066e4, 0x00000ca9 },
+ { 0x000066e8, 0x00000cb6 },
+ { 0x000066ec, 0x00000cc3 },
+ { 0x000066f0, 0x00000cd1 },
+ { 0x000066f4, 0x00000cde },
+ { 0x000066f8, 0x00000cec },
+ { 0x000066fc, 0x00000cf9 },
+ { 0x00006700, 0x00000d07 },
+ { 0x00006704, 0x00000d14 },
+ { 0x00006708, 0x00000d22 },
+ { 0x0000670c, 0x00000d2f },
+ { 0x00006710, 0x00000d3d },
+ { 0x00006714, 0x00000d4a },
+ { 0x00006718, 0x00000d58 },
+ { 0x0000671c, 0x00000d66 },
+ { 0x00006720, 0x00000d73 },
+ { 0x00006724, 0x00000d81 },
+ { 0x00006728, 0x00000d8f },
+ { 0x0000672c, 0x00000d9d },
+ { 0x00006730, 0x00000dab },
+ { 0x00006734, 0x00000db8 },
+ { 0x00006738, 0x00000dc6 },
+ { 0x0000673c, 0x00000dd4 },
+ { 0x00006740, 0x00000de2 },
+ { 0x00006744, 0x00000df0 },
+ { 0x00006748, 0x00000dfe },
+ { 0x0000674c, 0x00000e0c },
+ { 0x00006750, 0x00000e1a },
+ { 0x00006754, 0x00000e29 },
+ { 0x00006758, 0x00000e37 },
+ { 0x0000675c, 0x00000e45 },
+ { 0x00006760, 0x00000e53 },
+ { 0x00006764, 0x00000e61 },
+ { 0x00006768, 0x00000e70 },
+ { 0x0000676c, 0x00000e7e },
+ { 0x00006770, 0x00000e8c },
+ { 0x00006774, 0x00000e9a },
+ { 0x00006778, 0x00000ea9 },
+ { 0x0000677c, 0x00000eb7 },
+ { 0x00006780, 0x00000ec6 },
+ { 0x00006784, 0x00000ed4 },
+ { 0x00006788, 0x00000ee3 },
+ { 0x0000678c, 0x00000ef1 },
+ { 0x00006790, 0x00000f00 },
+ { 0x00006794, 0x00000f0e },
+ { 0x00006798, 0x00000f1d },
+ { 0x0000679c, 0x00000f2c },
+ { 0x000067a0, 0x00000f3a },
+ { 0x000067a4, 0x00000f49 },
+ { 0x000067a8, 0x00000f58 },
+ { 0x000067ac, 0x00000f67 },
+ { 0x000067b0, 0x00000f75 },
+ { 0x000067b4, 0x00000f84 },
+ { 0x000067b8, 0x00000f93 },
+ { 0x000067bc, 0x00000fa2 },
+ { 0x000067c0, 0x00000fb1 },
+ { 0x000067c4, 0x00000fc0 },
+ { 0x000067c8, 0x00000fcf },
+ { 0x000067cc, 0x00000fde },
+ { 0x000067d0, 0x00000fed },
+ { 0x000067d4, 0x00000ffc },
+ { 0x000067d8, 0x0000100b },
+ { 0x000067dc, 0x0000101a },
+ { 0x000067e0, 0x0000102a },
+ { 0x000067e4, 0x00001039 },
+ { 0x000067e8, 0x00001048 },
+ { 0x000067ec, 0x00001057 },
+ { 0x000067f0, 0x00001067 },
+ { 0x000067f4, 0x00001076 },
+ { 0x000067f8, 0x00001085 },
+ { 0x000067fc, 0x00001095 },
+ { 0x00006800, 0x000010a4 },
+ { 0x00006804, 0x000010b4 },
+ { 0x00006808, 0x000010c3 },
+ { 0x0000680c, 0x000010d3 },
+ { 0x00006810, 0x000010e2 },
+ { 0x00006814, 0x000010f2 },
+ { 0x00006818, 0x00001101 },
+ { 0x0000681c, 0x00001111 },
+ { 0x00006820, 0x00001121 },
+ { 0x00006824, 0x00001130 },
+ { 0x00006828, 0x00001140 },
+ { 0x0000682c, 0x00001150 },
+ { 0x00006830, 0x00001160 },
+ { 0x00006834, 0x0000116f },
+ { 0x00006838, 0x0000117f },
+ { 0x0000683c, 0x0000118f },
+ { 0x00006840, 0x0000119f },
+ { 0x00006844, 0x000011af },
+ { 0x00006848, 0x000011bf },
+ { 0x0000684c, 0x000011cf },
+ { 0x00006850, 0x000011df },
+ { 0x00006854, 0x000011ef },
+ { 0x00006858, 0x000011ff },
+ { 0x0000685c, 0x0000120f },
+ { 0x00006860, 0x0000121f },
+ { 0x00006864, 0x00001230 },
+ { 0x00006868, 0x00001240 },
+ { 0x0000686c, 0x00001250 },
+ { 0x00006870, 0x00001260 },
+ { 0x00006874, 0x00001271 },
+ { 0x00006878, 0x00001281 },
+ { 0x0000687c, 0x00001291 },
+ { 0x00006880, 0x000012a2 },
+ { 0x00006884, 0x000012b2 },
+ { 0x00006888, 0x000012c3 },
+ { 0x0000688c, 0x000012d3 },
+ { 0x00006890, 0x000012e4 },
+ { 0x00006894, 0x000012f4 },
+ { 0x00006898, 0x00001305 },
+ { 0x0000689c, 0x00001316 },
+ { 0x000068a0, 0x00001326 },
+ { 0x000068a4, 0x00001337 },
+ { 0x000068a8, 0x00001348 },
+ { 0x000068ac, 0x00001359 },
+ { 0x000068b0, 0x00001369 },
+ { 0x000068b4, 0x0000137a },
+ { 0x000068b8, 0x0000138b },
+ { 0x000068bc, 0x0000139c },
+ { 0x000068c0, 0x000013ad },
+ { 0x000068c4, 0x000013be },
+ { 0x000068c8, 0x000013cf },
+ { 0x000068cc, 0x000013e0 },
+ { 0x000068d0, 0x000013f1 },
+ { 0x000068d4, 0x00001402 },
+ { 0x000068d8, 0x00001413 },
+ { 0x000068dc, 0x00001424 },
+ { 0x000068e0, 0x00001435 },
+ { 0x000068e4, 0x00001446 },
+ { 0x000068e8, 0x00001458 },
+ { 0x000068ec, 0x00001469 },
+ { 0x000068f0, 0x0000147a },
+ { 0x000068f4, 0x0000148b },
+ { 0x000068f8, 0x0000149d },
+ { 0x000068fc, 0x000014ae },
+ { 0x00006900, 0x000014c0 },
+ { 0x00006904, 0x000014d1 },
+ { 0x00006908, 0x000014e3 },
+ { 0x0000690c, 0x000014f4 },
+ { 0x00006910, 0x00001506 },
+ { 0x00006914, 0x00001517 },
+ { 0x00006918, 0x00001529 },
+ { 0x0000691c, 0x0000153a },
+ { 0x00006920, 0x0000154c },
+ { 0x00006924, 0x0000155e },
+ { 0x00006928, 0x0000156f },
+ { 0x0000692c, 0x00001581 },
+ { 0x00006930, 0x00001593 },
+ { 0x00006934, 0x000015a5 },
+ { 0x00006938, 0x000015b7 },
+ { 0x0000693c, 0x000015c9 },
+ { 0x00006940, 0x000015db },
+ { 0x00006944, 0x000015ec },
+ { 0x00006948, 0x000015fe },
+ { 0x0000694c, 0x00001610 },
+ { 0x00006950, 0x00001623 },
+ { 0x00006954, 0x00001635 },
+ { 0x00006958, 0x00001647 },
+ { 0x0000695c, 0x00001659 },
+ { 0x00006960, 0x0000166b },
+ { 0x00006964, 0x0000167d },
+ { 0x00006968, 0x0000168f },
+ { 0x0000696c, 0x000016a2 },
+ { 0x00006970, 0x000016b4 },
+ { 0x00006974, 0x000016c6 },
+ { 0x00006978, 0x000016d9 },
+ { 0x0000697c, 0x000016eb },
+ { 0x00006980, 0x000016fe },
+ { 0x00006984, 0x00001710 },
+ { 0x00006988, 0x00001722 },
+ { 0x0000698c, 0x00001735 },
+ { 0x00006990, 0x00001748 },
+ { 0x00006994, 0x0000175a },
+ { 0x00006998, 0x0000176d },
+ { 0x0000699c, 0x0000177f },
+ { 0x000069a0, 0x00001792 },
+ { 0x000069a4, 0x000017a5 },
+ { 0x000069a8, 0x000017b8 },
+ { 0x000069ac, 0x000017ca },
+ { 0x000069b0, 0x000017dd },
+ { 0x000069b4, 0x000017f0 },
+ { 0x000069b8, 0x00001803 },
+ { 0x000069bc, 0x00001816 },
+ { 0x000069c0, 0x00001829 },
+ { 0x000069c4, 0x0000183c },
+ { 0x000069c8, 0x0000184f },
+ { 0x000069cc, 0x00001862 },
+ { 0x000069d0, 0x00001875 },
+ { 0x000069d4, 0x00001888 },
+ { 0x000069d8, 0x0000189b },
+ { 0x000069dc, 0x000018ae },
+ { 0x000069e0, 0x000018c1 },
+ { 0x000069e4, 0x000018d5 },
+ { 0x000069e8, 0x000018e8 },
+ { 0x000069ec, 0x000018fb },
+ { 0x000069f0, 0x0000190e },
+ { 0x000069f4, 0x00001922 },
+ { 0x000069f8, 0x00001935 },
+ { 0x000069fc, 0x00001949 },
+ { 0x00006a00, 0x0000195c },
+ { 0x00006a04, 0x0000196f },
+ { 0x00006a08, 0x00001983 },
+ { 0x00006a0c, 0x00001996 },
+ { 0x00006a10, 0x000019aa },
+ { 0x00006a14, 0x000019be },
+ { 0x00006a18, 0x000019d1 },
+ { 0x00006a1c, 0x000019e5 },
+ { 0x00006a20, 0x000019f9 },
+ { 0x00006a24, 0x00001a0c },
+ { 0x00006a28, 0x00001a20 },
+ { 0x00006a2c, 0x00001a34 },
+ { 0x00006a30, 0x00001a48 },
+ { 0x00006a34, 0x00001a5c },
+ { 0x00006a38, 0x00001a70 },
+ { 0x00006a3c, 0x00001a84 },
+ { 0x00006a40, 0x00001a97 },
+ { 0x00006a44, 0x00001aab },
+ { 0x00006a48, 0x00001ac0 },
+ { 0x00006a4c, 0x00001ad4 },
+ { 0x00006a50, 0x00001ae8 },
+ { 0x00006a54, 0x00001afc },
+ { 0x00006a58, 0x00001b10 },
+ { 0x00006a5c, 0x00001b24 },
+ { 0x00006a60, 0x00001b38 },
+ { 0x00006a64, 0x00001b4d },
+ { 0x00006a68, 0x00001b61 },
+ { 0x00006a6c, 0x00001b75 },
+ { 0x00006a70, 0x00001b8a },
+ { 0x00006a74, 0x00001b9e },
+ { 0x00006a78, 0x00001bb2 },
+ { 0x00006a7c, 0x00001bc7 },
+ { 0x00006a80, 0x00001bdb },
+ { 0x00006a84, 0x00001bf0 },
+ { 0x00006a88, 0x00001c04 },
+ { 0x00006a8c, 0x00001c19 },
+ { 0x00006a90, 0x00001c2e },
+ { 0x00006a94, 0x00001c42 },
+ { 0x00006a98, 0x00001c57 },
+ { 0x00006a9c, 0x00001c6c },
+ { 0x00006aa0, 0x00001c80 },
+ { 0x00006aa4, 0x00001c95 },
+ { 0x00006aa8, 0x00001caa },
+ { 0x00006aac, 0x00001cbf },
+ { 0x00006ab0, 0x00001cd4 },
+ { 0x00006ab4, 0x00001ce8 },
+ { 0x00006ab8, 0x00001cfd },
+ { 0x00006abc, 0x00001d12 },
+ { 0x00006ac0, 0x00001d27 },
+ { 0x00006ac4, 0x00001d3c },
+ { 0x00006ac8, 0x00001d51 },
+ { 0x00006acc, 0x00001d67 },
+ { 0x00006ad0, 0x00001d7c },
+ { 0x00006ad4, 0x00001d91 },
+ { 0x00006ad8, 0x00001da6 },
+ { 0x00006adc, 0x00001dbb },
+ { 0x00006ae0, 0x00001dd1 },
+ { 0x00006ae4, 0x00001de6 },
+ { 0x00006ae8, 0x00001dfb },
+ { 0x00006aec, 0x00001e10 },
+ { 0x00006af0, 0x00001e26 },
+ { 0x00006af4, 0x00001e3b },
+ { 0x00006af8, 0x00001e51 },
+ { 0x00006afc, 0x00001e66 },
+ { 0x00006b00, 0x00001e7c },
+ { 0x00006b04, 0x00001e91 },
+ { 0x00006b08, 0x00001ea7 },
+ { 0x00006b0c, 0x00001ebd },
+ { 0x00006b10, 0x00001ed2 },
+ { 0x00006b14, 0x00001ee8 },
+ { 0x00006b18, 0x00001efe },
+ { 0x00006b1c, 0x00001f13 },
+ { 0x00006b20, 0x00001f29 },
+ { 0x00006b24, 0x00001f3f },
+ { 0x00006b28, 0x00001f55 },
+ { 0x00006b2c, 0x00001f6b },
+ { 0x00006b30, 0x00001f81 },
+ { 0x00006b34, 0x00001f96 },
+ { 0x00006b38, 0x00001fac },
+ { 0x00006b3c, 0x00001fc2 },
+ { 0x00006b40, 0x00001fd9 },
+ { 0x00006b44, 0x00001fef },
+ { 0x00006b48, 0x00002005 },
+ { 0x00006b4c, 0x0000201b },
+ { 0x00006b50, 0x00002031 },
+ { 0x00006b54, 0x00002047 },
+ { 0x00006b58, 0x0000205d },
+ { 0x00006b5c, 0x00002074 },
+ { 0x00006b60, 0x0000208a },
+ { 0x00006b64, 0x000020a0 },
+ { 0x00006b68, 0x000020b7 },
+ { 0x00006b6c, 0x000020cd },
+ { 0x00006b70, 0x000020e4 },
+ { 0x00006b74, 0x000020fa },
+ { 0x00006b78, 0x00002111 },
+ { 0x00006b7c, 0x00002127 },
+ { 0x00006b80, 0x0000213e },
+ { 0x00006b84, 0x00002154 },
+ { 0x00006b88, 0x0000216b },
+ { 0x00006b8c, 0x00002182 },
+ { 0x00006b90, 0x00002198 },
+ { 0x00006b94, 0x000021af },
+ { 0x00006b98, 0x000021c6 },
+ { 0x00006b9c, 0x000021dd },
+ { 0x00006ba0, 0x000021f3 },
+ { 0x00006ba4, 0x0000220a },
+ { 0x00006ba8, 0x00002221 },
+ { 0x00006bac, 0x00002238 },
+ { 0x00006bb0, 0x0000224f },
+ { 0x00006bb4, 0x00002266 },
+ { 0x00006bb8, 0x0000227d },
+ { 0x00006bbc, 0x00002294 },
+ { 0x00006bc0, 0x000022ab },
+ { 0x00006bc4, 0x000022c2 },
+ { 0x00006bc8, 0x000022da },
+ { 0x00006bcc, 0x000022f1 },
+ { 0x00006bd0, 0x00002308 },
+ { 0x00006bd4, 0x0000231f },
+ { 0x00006bd8, 0x00002337 },
+ { 0x00006bdc, 0x0000234e },
+ { 0x00006be0, 0x00002365 },
+ { 0x00006be4, 0x0000237d },
+ { 0x00006be8, 0x00002394 },
+ { 0x00006bec, 0x000023ac },
+ { 0x00006bf0, 0x000023c3 },
+ { 0x00006bf4, 0x000023db },
+ { 0x00006bf8, 0x000023f2 },
+ { 0x00006bfc, 0x0000240a },
+ { 0x00006c00, 0x00002421 },
+ { 0x00006c04, 0x00002439 },
+ { 0x00006c08, 0x00002451 },
+ { 0x00006c0c, 0x00002469 },
+ { 0x00006c10, 0x00002480 },
+ { 0x00006c14, 0x00002498 },
+ { 0x00006c18, 0x000024b0 },
+ { 0x00006c1c, 0x000024c8 },
+ { 0x00006c20, 0x000024e0 },
+ { 0x00006c24, 0x000024f8 },
+ { 0x00006c28, 0x00002510 },
+ { 0x00006c2c, 0x00002528 },
+ { 0x00006c30, 0x00002540 },
+ { 0x00006c34, 0x00002558 },
+ { 0x00006c38, 0x00002570 },
+ { 0x00006c3c, 0x00002588 },
+ { 0x00006c40, 0x000025a0 },
+ { 0x00006c44, 0x000025b8 },
+ { 0x00006c48, 0x000025d0 },
+ { 0x00006c4c, 0x000025e9 },
+ { 0x00006c50, 0x00002601 },
+ { 0x00006c54, 0x00002619 },
+ { 0x00006c58, 0x00002632 },
+ { 0x00006c5c, 0x0000264a },
+ { 0x00006c60, 0x00002663 },
+ { 0x00006c64, 0x0000267b },
+ { 0x00006c68, 0x00002693 },
+ { 0x00006c6c, 0x000026ac },
+ { 0x00006c70, 0x000026c5 },
+ { 0x00006c74, 0x000026dd },
+ { 0x00006c78, 0x000026f6 },
+ { 0x00006c7c, 0x0000270e },
+ { 0x00006c80, 0x00002727 },
+ { 0x00006c84, 0x00002740 },
+ { 0x00006c88, 0x00002759 },
+ { 0x00006c8c, 0x00002771 },
+ { 0x00006c90, 0x0000278a },
+ { 0x00006c94, 0x000027a3 },
+ { 0x00006c98, 0x000027bc },
+ { 0x00006c9c, 0x000027d5 },
+ { 0x00006ca0, 0x000027ee },
+ { 0x00006ca4, 0x00002807 },
+ { 0x00006ca8, 0x00002820 },
+ { 0x00006cac, 0x00002839 },
+ { 0x00006cb0, 0x00002852 },
+ { 0x00006cb4, 0x0000286b },
+ { 0x00006cb8, 0x00002884 },
+ { 0x00006cbc, 0x0000289e },
+ { 0x00006cc0, 0x000028b7 },
+ { 0x00006cc4, 0x000028d0 },
+ { 0x00006cc8, 0x000028e9 },
+ { 0x00006ccc, 0x00002903 },
+ { 0x00006cd0, 0x0000291c },
+ { 0x00006cd4, 0x00002936 },
+ { 0x00006cd8, 0x0000294f },
+ { 0x00006cdc, 0x00002968 },
+ { 0x00006ce0, 0x00002982 },
+ { 0x00006ce4, 0x0000299c },
+ { 0x00006ce8, 0x000029b5 },
+ { 0x00006cec, 0x000029cf },
+ { 0x00006cf0, 0x000029e8 },
+ { 0x00006cf4, 0x00002a02 },
+ { 0x00006cf8, 0x00002a1c },
+ { 0x00006cfc, 0x00002a35 },
+ { 0x00006d00, 0x00002a4f },
+ { 0x00006d04, 0x00002a69 },
+ { 0x00006d08, 0x00002a83 },
+ { 0x00006d0c, 0x00002a9d },
+ { 0x00006d10, 0x00002ab7 },
+ { 0x00006d14, 0x00002ad1 },
+ { 0x00006d18, 0x00002aeb },
+ { 0x00006d1c, 0x00002b05 },
+ { 0x00006d20, 0x00002b1f },
+ { 0x00006d24, 0x00002b39 },
+ { 0x00006d28, 0x00002b53 },
+ { 0x00006d2c, 0x00002b6d },
+ { 0x00006d30, 0x00002b87 },
+ { 0x00006d34, 0x00002ba1 },
+ { 0x00006d38, 0x00002bbc },
+ { 0x00006d3c, 0x00002bd6 },
+ { 0x00006d40, 0x00002bf0 },
+ { 0x00006d44, 0x00002c0b },
+ { 0x00006d48, 0x00002c25 },
+ { 0x00006d4c, 0x00002c3f },
+ { 0x00006d50, 0x00002c5a },
+ { 0x00006d54, 0x00002c74 },
+ { 0x00006d58, 0x00002c8f },
+ { 0x00006d5c, 0x00002ca9 },
+ { 0x00006d60, 0x00002cc4 },
+ { 0x00006d64, 0x00002cdf },
+ { 0x00006d68, 0x00002cf9 },
+ { 0x00006d6c, 0x00002d14 },
+ { 0x00006d70, 0x00002d2f },
+ { 0x00006d74, 0x00002d49 },
+ { 0x00006d78, 0x00002d64 },
+ { 0x00006d7c, 0x00002d7f },
+ { 0x00006d80, 0x00002d9a },
+ { 0x00006d84, 0x00002db5 },
+ { 0x00006d88, 0x00002dd0 },
+ { 0x00006d8c, 0x00002deb },
+ { 0x00006d90, 0x00002e06 },
+ { 0x00006d94, 0x00002e21 },
+ { 0x00006d98, 0x00002e3c },
+ { 0x00006d9c, 0x00002e57 },
+ { 0x00006da0, 0x00002e72 },
+ { 0x00006da4, 0x00002e8d },
+ { 0x00006da8, 0x00002ea8 },
+ { 0x00006dac, 0x00002ec4 },
+ { 0x00006db0, 0x00002edf },
+ { 0x00006db4, 0x00002efa },
+ { 0x00006db8, 0x00002f16 },
+ { 0x00006dbc, 0x00002f31 },
+ { 0x00006dc0, 0x00002f4c },
+ { 0x00006dc4, 0x00002f68 },
+ { 0x00006dc8, 0x00002f83 },
+ { 0x00006dcc, 0x00002f9f },
+ { 0x00006dd0, 0x00002fba },
+ { 0x00006dd4, 0x00002fd6 },
+ { 0x00006dd8, 0x00002ff1 },
+ { 0x00006ddc, 0x0000300d },
+ { 0x00006de0, 0x00003029 },
+ { 0x00006de4, 0x00003044 },
+ { 0x00006de8, 0x00003060 },
+ { 0x00006dec, 0x0000307c },
+ { 0x00006df0, 0x00003098 },
+ { 0x00006df4, 0x000030b4 },
+ { 0x00006df8, 0x000030d0 },
+ { 0x00006dfc, 0x000030eb },
+ { 0x00006e00, 0x00003107 },
+ { 0x00006e04, 0x00003123 },
+ { 0x00006e08, 0x0000313f },
+ { 0x00006e0c, 0x0000315b },
+ { 0x00006e10, 0x00003178 },
+ { 0x00006e14, 0x00003194 },
+ { 0x00006e18, 0x000031b0 },
+ { 0x00006e1c, 0x000031cc },
+ { 0x00006e20, 0x000031e8 },
+ { 0x00006e24, 0x00003205 },
+ { 0x00006e28, 0x00003221 },
+ { 0x00006e2c, 0x0000323d },
+ { 0x00006e30, 0x0000325a },
+ { 0x00006e34, 0x00003276 },
+ { 0x00006e38, 0x00003292 },
+ { 0x00006e3c, 0x000032af },
+ { 0x00006e40, 0x000032cb },
+ { 0x00006e44, 0x000032e8 },
+ { 0x00006e48, 0x00003304 },
+ { 0x00006e4c, 0x00003321 },
+ { 0x00006e50, 0x0000333e },
+ { 0x00006e54, 0x0000335a },
+ { 0x00006e58, 0x00003377 },
+ { 0x00006e5c, 0x00003394 },
+ { 0x00006e60, 0x000033b1 },
+ { 0x00006e64, 0x000033cd },
+ { 0x00006e68, 0x000033ea },
+ { 0x00006e6c, 0x00003407 },
+ { 0x00006e70, 0x00003424 },
+ { 0x00006e74, 0x00003441 },
+ { 0x00006e78, 0x0000345e },
+ { 0x00006e7c, 0x0000347b },
+ { 0x00006e80, 0x00003498 },
+ { 0x00006e84, 0x000034b5 },
+ { 0x00006e88, 0x000034d2 },
+ { 0x00006e8c, 0x000034ef },
+ { 0x00006e90, 0x0000350d },
+ { 0x00006e94, 0x0000352a },
+ { 0x00006e98, 0x00003547 },
+ { 0x00006e9c, 0x00003564 },
+ { 0x00006ea0, 0x00003582 },
+ { 0x00006ea4, 0x0000359f },
+ { 0x00006ea8, 0x000035bc },
+ { 0x00006eac, 0x000035da },
+ { 0x00006eb0, 0x000035f7 },
+ { 0x00006eb4, 0x00003615 },
+ { 0x00006eb8, 0x00003632 },
+ { 0x00006ebc, 0x00003650 },
+ { 0x00006ec0, 0x0000366e },
+ { 0x00006ec4, 0x0000368b },
+ { 0x00006ec8, 0x000036a9 },
+ { 0x00006ecc, 0x000036c7 },
+ { 0x00006ed0, 0x000036e4 },
+ { 0x00006ed4, 0x00003702 },
+ { 0x00006ed8, 0x00003720 },
+ { 0x00006edc, 0x0000373e },
+ { 0x00006ee0, 0x0000375c },
+ { 0x00006ee4, 0x0000377a },
+ { 0x00006ee8, 0x00003798 },
+ { 0x00006eec, 0x000037b6 },
+ { 0x00006ef0, 0x000037d4 },
+ { 0x00006ef4, 0x000037f2 },
+ { 0x00006ef8, 0x00003810 },
+ { 0x00006efc, 0x0000382e },
+ { 0x00006f00, 0x0000384c },
+ { 0x00006f04, 0x0000386a },
+ { 0x00006f08, 0x00003888 },
+ { 0x00006f0c, 0x000038a7 },
+ { 0x00006f10, 0x000038c5 },
+ { 0x00006f14, 0x000038e3 },
+ { 0x00006f18, 0x00003902 },
+ { 0x00006f1c, 0x00003920 },
+ { 0x00006f20, 0x0000393f },
+ { 0x00006f24, 0x0000395d },
+ { 0x00006f28, 0x0000397c },
+ { 0x00006f2c, 0x0000399a },
+ { 0x00006f30, 0x000039b9 },
+ { 0x00006f34, 0x000039d7 },
+ { 0x00006f38, 0x000039f6 },
+ { 0x00006f3c, 0x00003a15 },
+ { 0x00006f40, 0x00003a33 },
+ { 0x00006f44, 0x00003a52 },
+ { 0x00006f48, 0x00003a71 },
+ { 0x00006f4c, 0x00003a90 },
+ { 0x00006f50, 0x00003aaf },
+ { 0x00006f54, 0x00003acd },
+ { 0x00006f58, 0x00003aec },
+ { 0x00006f5c, 0x00003b0b },
+ { 0x00006f60, 0x00003b2a },
+ { 0x00006f64, 0x00003b49 },
+ { 0x00006f68, 0x00003b68 },
+ { 0x00006f6c, 0x00003b87 },
+ { 0x00006f70, 0x00003ba7 },
+ { 0x00006f74, 0x00003bc6 },
+ { 0x00006f78, 0x00003be5 },
+ { 0x00006f7c, 0x00003c04 },
+ { 0x00006f80, 0x00003c24 },
+ { 0x00006f84, 0x00003c43 },
+ { 0x00006f88, 0x00003c62 },
+ { 0x00006f8c, 0x00003c82 },
+ { 0x00006f90, 0x00003ca1 },
+ { 0x00006f94, 0x00003cc0 },
+ { 0x00006f98, 0x00003ce0 },
+ { 0x00006f9c, 0x00003cff },
+ { 0x00006fa0, 0x00003d1f },
+ { 0x00006fa4, 0x00003d3f },
+ { 0x00006fa8, 0x00003d5e },
+ { 0x00006fac, 0x00003d7e },
+ { 0x00006fb0, 0x00003d9e },
+ { 0x00006fb4, 0x00003dbd },
+ { 0x00006fb8, 0x00003ddd },
+ { 0x00006fbc, 0x00003dfd },
+ { 0x00006fc0, 0x00003e1d },
+ { 0x00006fc4, 0x00003e3d },
+ { 0x00006fc8, 0x00003e5d },
+ { 0x00006fcc, 0x00003e7c },
+ { 0x00006fd0, 0x00003e9c },
+ { 0x00006fd4, 0x00003ebc },
+ { 0x00006fd8, 0x00003edc },
+ { 0x00006fdc, 0x00003efd },
+ { 0x00006fe0, 0x00003f1d },
+ { 0x00006fe4, 0x00003f3d },
+ { 0x00006fe8, 0x00003f5d },
+ { 0x00006fec, 0x00003f7d },
+ { 0x00006ff0, 0x00003f9e },
+ { 0x00006ff4, 0x00003fbe },
+ { 0x00006ff8, 0x00003fde },
+ { 0x00006ffc, 0x00003fff },
+};
+
+struct data_unit hdr10_pipe2_csca[] = {
+ { 0x00007004, 0x0000255f },
+ { 0x0000700c, 0x00003989 },
+ { 0x00007010, 0x0000255f },
+ { 0x00007014, 0x0000f928 },
+ { 0x00007018, 0x0000eee6 },
+ { 0x0000701c, 0x0000255f },
+ { 0x00007020, 0x000043cc },
+ { 0x00007028, 0x000003c0 },
+ { 0x0000702c, 0x00000200 },
+ { 0x00007030, 0x00000200 },
+ { 0x00007038, 0x00000240 },
+ { 0x0000703c, 0x00000240 },
+ { 0x00007040, 0x0000036c },
+ { 0x00007044, 0x000001c0 },
+ { 0x00007048, 0x000001c0 },
+ { 0x0000704c, 0x0000000d },
+ { 0x00007068, 0x000003ff },
+ { 0x0000706c, 0x000003ff },
+ { 0x00007070, 0x000003ff },
+ { 0x00007080, 0x00000003 },
+ { 0x00007000, 0x00000003 },
+};
+
+struct data_unit hdr10_pipe2_cscb[] = {
+ { 0x00007804, 0x00007fe2 },
+ { 0x00007814, 0x00007fe2 },
+ { 0x00007824, 0x00007fe2 },
+ { 0x00007840, 0x00003fff },
+ { 0x00007844, 0x00003fff },
+ { 0x00007848, 0x00003fff },
+ { 0x0000784c, 0x00000001 },
+ { 0x00007868, 0x0ffc0000 },
+ { 0x0000786c, 0x0ffc0000 },
+ { 0x00007870, 0x0ffc0000 },
+ { 0x00007874, 0x00000000 },
+ { 0x00007800, 0x00000003 },
+};
+
+/* Linear to Non-Linear Conversion Tables */
+struct data_unit hdr10_opipe_a0[] = {
+ { 0x0000c000, 0x00003612 },
+ { 0x0000c004, 0x00003612 },
+ { 0x0000c008, 0x0000327c },
+ { 0x0000c00c, 0x00003840 },
+ { 0x0000c010, 0x00002fb2 },
+ { 0x0000c014, 0x00003475 },
+ { 0x0000c018, 0x00003728 },
+ { 0x0000c01c, 0x0000390e },
+ { 0x0000c020, 0x00002d7f },
+ { 0x0000c024, 0x00003134 },
+ { 0x0000c028, 0x00003397 },
+ { 0x0000c02c, 0x0000353d },
+ { 0x0000c030, 0x00003695 },
+ { 0x0000c034, 0x000037cb },
+ { 0x0000c038, 0x000038a2 },
+ { 0x0000c03c, 0x00003982 },
+ { 0x0000c040, 0x00002b71 },
+ { 0x0000c044, 0x00002ea4 },
+ { 0x0000c048, 0x00003079 },
+ { 0x0000c04c, 0x00003204 },
+ { 0x0000c050, 0x00003302 },
+ { 0x0000c054, 0x0000341c },
+ { 0x0000c058, 0x000034d5 },
+ { 0x0000c05c, 0x000035ad },
+ { 0x0000c060, 0x00003651 },
+ { 0x0000c064, 0x000036dc },
+ { 0x0000c068, 0x00003778 },
+ { 0x0000c06c, 0x00003811 },
+ { 0x0000c070, 0x00003870 },
+ { 0x0000c074, 0x000038d7 },
+ { 0x0000c078, 0x00003946 },
+ { 0x0000c07c, 0x000039bf },
+ { 0x0000c080, 0x00002955 },
+ { 0x0000c084, 0x00002c9c },
+ { 0x0000c088, 0x00002e31 },
+ { 0x0000c08c, 0x00002f25 },
+ { 0x0000c090, 0x00003026 },
+ { 0x0000c094, 0x000030d3 },
+ { 0x0000c098, 0x0000319b },
+ { 0x0000c09c, 0x0000323e },
+ { 0x0000c0a0, 0x000032bd },
+ { 0x0000c0a4, 0x0000334b },
+ { 0x0000c0a8, 0x000033e6 },
+ { 0x0000c0ac, 0x00003448 },
+ { 0x0000c0b0, 0x000034a4 },
+ { 0x0000c0b4, 0x00003508 },
+ { 0x0000c0b8, 0x00003574 },
+ { 0x0000c0bc, 0x000035e7 },
+ { 0x0000c0c0, 0x00003631 },
+ { 0x0000c0c4, 0x00003672 },
+ { 0x0000c0c8, 0x000036b8 },
+ { 0x0000c0cc, 0x00003702 },
+ { 0x0000c0d0, 0x0000374f },
+ { 0x0000c0d4, 0x000037a1 },
+ { 0x0000c0d8, 0x000037f7 },
+ { 0x0000c0dc, 0x00003828 },
+ { 0x0000c0e0, 0x00003857 },
+ { 0x0000c0e4, 0x00003889 },
+ { 0x0000c0e8, 0x000038bc },
+ { 0x0000c0ec, 0x000038f2 },
+ { 0x0000c0f0, 0x0000392a },
+ { 0x0000c0f4, 0x00003964 },
+ { 0x0000c0f8, 0x000039a0 },
+ { 0x0000c0fc, 0x000039de },
+ { 0x0000c100, 0x0000271c },
+ { 0x0000c104, 0x00002a8e },
+ { 0x0000c108, 0x00002c2a },
+ { 0x0000c10c, 0x00002d0e },
+ { 0x0000c110, 0x00002df1 },
+ { 0x0000c114, 0x00002e69 },
+ { 0x0000c118, 0x00002ee3 },
+ { 0x0000c11c, 0x00002f6a },
+ { 0x0000c120, 0x00002ffe },
+ { 0x0000c124, 0x0000304f },
+ { 0x0000c128, 0x000030a5 },
+ { 0x0000c12c, 0x00003102 },
+ { 0x0000c130, 0x00003166 },
+ { 0x0000c134, 0x000031d1 },
+ { 0x0000c138, 0x00003221 },
+ { 0x0000c13c, 0x0000325d },
+ { 0x0000c140, 0x0000329c },
+ { 0x0000c144, 0x000032df },
+ { 0x0000c148, 0x00003326 },
+ { 0x0000c14c, 0x00003370 },
+ { 0x0000c150, 0x000033be },
+ { 0x0000c154, 0x00003407 },
+ { 0x0000c158, 0x00003432 },
+ { 0x0000c15c, 0x0000345e },
+ { 0x0000c160, 0x0000348c },
+ { 0x0000c164, 0x000034bd },
+ { 0x0000c168, 0x000034ef },
+ { 0x0000c16c, 0x00003522 },
+ { 0x0000c170, 0x00003558 },
+ { 0x0000c174, 0x00003590 },
+ { 0x0000c178, 0x000035ca },
+ { 0x0000c17c, 0x00003602 },
+ { 0x0000c180, 0x00003621 },
+ { 0x0000c184, 0x00003641 },
+ { 0x0000c188, 0x00003662 },
+ { 0x0000c18c, 0x00003683 },
+ { 0x0000c190, 0x000036a6 },
+ { 0x0000c194, 0x000036ca },
+ { 0x0000c198, 0x000036ef },
+ { 0x0000c19c, 0x00003715 },
+ { 0x0000c1a0, 0x0000373b },
+ { 0x0000c1a4, 0x00003763 },
+ { 0x0000c1a8, 0x0000378c },
+ { 0x0000c1ac, 0x000037b6 },
+ { 0x0000c1b0, 0x000037e1 },
+ { 0x0000c1b4, 0x00003806 },
+ { 0x0000c1b8, 0x0000381d },
+ { 0x0000c1bc, 0x00003834 },
+ { 0x0000c1c0, 0x0000384b },
+ { 0x0000c1c4, 0x00003864 },
+ { 0x0000c1c8, 0x0000387c },
+ { 0x0000c1cc, 0x00003895 },
+ { 0x0000c1d0, 0x000038af },
+ { 0x0000c1d4, 0x000038c9 },
+ { 0x0000c1d8, 0x000038e4 },
+ { 0x0000c1dc, 0x00003900 },
+ { 0x0000c1e0, 0x0000391c },
+ { 0x0000c1e4, 0x00003938 },
+ { 0x0000c1e8, 0x00003955 },
+ { 0x0000c1ec, 0x00003973 },
+ { 0x0000c1f0, 0x00003991 },
+ { 0x0000c1f4, 0x000039af },
+ { 0x0000c1f8, 0x000039cf },
+ { 0x0000c1fc, 0x000039ee },
+ { 0x0000c200, 0x000024aa },
+ { 0x0000c204, 0x00002871 },
+ { 0x0000c208, 0x00002a1c },
+ { 0x0000c20c, 0x00002aff },
+ { 0x0000c210, 0x00002be3 },
+ { 0x0000c214, 0x00002c63 },
+ { 0x0000c218, 0x00002cd5 },
+ { 0x0000c21c, 0x00002d47 },
+ { 0x0000c220, 0x00002db8 },
+ { 0x0000c224, 0x00002e15 },
+ { 0x0000c228, 0x00002e4c },
+ { 0x0000c22c, 0x00002e86 },
+ { 0x0000c230, 0x00002ec4 },
+ { 0x0000c234, 0x00002f04 },
+ { 0x0000c238, 0x00002f47 },
+ { 0x0000c23c, 0x00002f8e },
+ { 0x0000c240, 0x00002fd8 },
+ { 0x0000c244, 0x00003012 },
+ { 0x0000c248, 0x0000303a },
+ { 0x0000c24c, 0x00003064 },
+ { 0x0000c250, 0x0000308f },
+ { 0x0000c254, 0x000030bc },
+ { 0x0000c258, 0x000030eb },
+ { 0x0000c25c, 0x0000311b },
+ { 0x0000c260, 0x0000314d },
+ { 0x0000c264, 0x00003180 },
+ { 0x0000c268, 0x000031b5 },
+ { 0x0000c26c, 0x000031ec },
+ { 0x0000c270, 0x00003212 },
+ { 0x0000c274, 0x0000322f },
+ { 0x0000c278, 0x0000324d },
+ { 0x0000c27c, 0x0000326c },
+ { 0x0000c280, 0x0000328c },
+ { 0x0000c284, 0x000032ad },
+ { 0x0000c288, 0x000032ce },
+ { 0x0000c28c, 0x000032f1 },
+ { 0x0000c290, 0x00003314 },
+ { 0x0000c294, 0x00003338 },
+ { 0x0000c298, 0x0000335d },
+ { 0x0000c29c, 0x00003383 },
+ { 0x0000c2a0, 0x000033aa },
+ { 0x0000c2a4, 0x000033d2 },
+ { 0x0000c2a8, 0x000033fb },
+ { 0x0000c2ac, 0x00003412 },
+ { 0x0000c2b0, 0x00003427 },
+ { 0x0000c2b4, 0x0000343d },
+ { 0x0000c2b8, 0x00003453 },
+ { 0x0000c2bc, 0x0000346a },
+ { 0x0000c2c0, 0x00003481 },
+ { 0x0000c2c4, 0x00003498 },
+ { 0x0000c2c8, 0x000034b0 },
+ { 0x0000c2cc, 0x000034c9 },
+ { 0x0000c2d0, 0x000034e2 },
+ { 0x0000c2d4, 0x000034fb },
+ { 0x0000c2d8, 0x00003515 },
+ { 0x0000c2dc, 0x00003530 },
+ { 0x0000c2e0, 0x0000354b },
+ { 0x0000c2e4, 0x00003566 },
+ { 0x0000c2e8, 0x00003582 },
+ { 0x0000c2ec, 0x0000359e },
+ { 0x0000c2f0, 0x000035bb },
+ { 0x0000c2f4, 0x000035d8 },
+ { 0x0000c2f8, 0x000035f6 },
+ { 0x0000c2fc, 0x0000360a },
+ { 0x0000c300, 0x00003619 },
+ { 0x0000c304, 0x00003629 },
+ { 0x0000c308, 0x00003639 },
+ { 0x0000c30c, 0x00003649 },
+ { 0x0000c310, 0x00003659 },
+ { 0x0000c314, 0x0000366a },
+ { 0x0000c318, 0x0000367b },
+ { 0x0000c31c, 0x0000368c },
+ { 0x0000c320, 0x0000369d },
+ { 0x0000c324, 0x000036af },
+ { 0x0000c328, 0x000036c1 },
+ { 0x0000c32c, 0x000036d3 },
+ { 0x0000c330, 0x000036e6 },
+ { 0x0000c334, 0x000036f8 },
+ { 0x0000c338, 0x0000370b },
+ { 0x0000c33c, 0x0000371e },
+ { 0x0000c340, 0x00003732 },
+ { 0x0000c344, 0x00003745 },
+ { 0x0000c348, 0x00003759 },
+ { 0x0000c34c, 0x0000376d },
+ { 0x0000c350, 0x00003782 },
+ { 0x0000c354, 0x00003797 },
+ { 0x0000c358, 0x000037ac },
+ { 0x0000c35c, 0x000037c1 },
+ { 0x0000c360, 0x000037d6 },
+ { 0x0000c364, 0x000037ec },
+ { 0x0000c368, 0x00003801 },
+ { 0x0000c36c, 0x0000380c },
+ { 0x0000c370, 0x00003817 },
+ { 0x0000c374, 0x00003823 },
+ { 0x0000c378, 0x0000382e },
+ { 0x0000c37c, 0x0000383a },
+ { 0x0000c380, 0x00003846 },
+ { 0x0000c384, 0x00003851 },
+ { 0x0000c388, 0x0000385e },
+ { 0x0000c38c, 0x0000386a },
+ { 0x0000c390, 0x00003876 },
+ { 0x0000c394, 0x00003883 },
+ { 0x0000c398, 0x0000388f },
+ { 0x0000c39c, 0x0000389c },
+ { 0x0000c3a0, 0x000038a9 },
+ { 0x0000c3a4, 0x000038b6 },
+ { 0x0000c3a8, 0x000038c3 },
+ { 0x0000c3ac, 0x000038d0 },
+ { 0x0000c3b0, 0x000038de },
+ { 0x0000c3b4, 0x000038eb },
+ { 0x0000c3b8, 0x000038f9 },
+ { 0x0000c3bc, 0x00003907 },
+ { 0x0000c3c0, 0x00003915 },
+ { 0x0000c3c4, 0x00003923 },
+ { 0x0000c3c8, 0x00003931 },
+ { 0x0000c3cc, 0x0000393f },
+ { 0x0000c3d0, 0x0000394e },
+ { 0x0000c3d4, 0x0000395c },
+ { 0x0000c3d8, 0x0000396b },
+ { 0x0000c3dc, 0x0000397a },
+ { 0x0000c3e0, 0x00003989 },
+ { 0x0000c3e4, 0x00003998 },
+ { 0x0000c3e8, 0x000039a8 },
+ { 0x0000c3ec, 0x000039b7 },
+ { 0x0000c3f0, 0x000039c7 },
+ { 0x0000c3f4, 0x000039d6 },
+ { 0x0000c3f8, 0x000039e6 },
+ { 0x0000c3fc, 0x000039f6 },
+ { 0x0000c400, 0x0000218e },
+ { 0x0000c404, 0x00002638 },
+ { 0x0000c408, 0x000027ff },
+ { 0x0000c40c, 0x000028e3 },
+ { 0x0000c410, 0x000029c7 },
+ { 0x0000c414, 0x00002a55 },
+ { 0x0000c418, 0x00002ac7 },
+ { 0x0000c41c, 0x00002b38 },
+ { 0x0000c420, 0x00002baa },
+ { 0x0000c424, 0x00002c0e },
+ { 0x0000c428, 0x00002c47 },
+ { 0x0000c42c, 0x00002c7f },
+ { 0x0000c430, 0x00002cb8 },
+ { 0x0000c434, 0x00002cf1 },
+ { 0x0000c438, 0x00002d2a },
+ { 0x0000c43c, 0x00002d63 },
+ { 0x0000c440, 0x00002d9c },
+ { 0x0000c444, 0x00002dd5 },
+ { 0x0000c448, 0x00002e07 },
+ { 0x0000c44c, 0x00002e23 },
+ { 0x0000c450, 0x00002e3f },
+ { 0x0000c454, 0x00002e5a },
+ { 0x0000c458, 0x00002e77 },
+ { 0x0000c45c, 0x00002e95 },
+ { 0x0000c460, 0x00002eb4 },
+ { 0x0000c464, 0x00002ed3 },
+ { 0x0000c468, 0x00002ef4 },
+ { 0x0000c46c, 0x00002f14 },
+ { 0x0000c470, 0x00002f36 },
+ { 0x0000c474, 0x00002f59 },
+ { 0x0000c478, 0x00002f7c },
+ { 0x0000c47c, 0x00002fa0 },
+ { 0x0000c480, 0x00002fc5 },
+ { 0x0000c484, 0x00002feb },
+ { 0x0000c488, 0x00003008 },
+ { 0x0000c48c, 0x0000301c },
+ { 0x0000c490, 0x00003030 },
+ { 0x0000c494, 0x00003044 },
+ { 0x0000c498, 0x00003059 },
+ { 0x0000c49c, 0x0000306e },
+ { 0x0000c4a0, 0x00003084 },
+ { 0x0000c4a4, 0x0000309a },
+ { 0x0000c4a8, 0x000030b1 },
+ { 0x0000c4ac, 0x000030c7 },
+ { 0x0000c4b0, 0x000030df },
+ { 0x0000c4b4, 0x000030f6 },
+ { 0x0000c4b8, 0x0000310f },
+ { 0x0000c4bc, 0x00003127 },
+ { 0x0000c4c0, 0x00003140 },
+ { 0x0000c4c4, 0x00003159 },
+ { 0x0000c4c8, 0x00003173 },
+ { 0x0000c4cc, 0x0000318d },
+ { 0x0000c4d0, 0x000031a8 },
+ { 0x0000c4d4, 0x000031c3 },
+ { 0x0000c4d8, 0x000031de },
+ { 0x0000c4dc, 0x000031fa },
+ { 0x0000c4e0, 0x0000320b },
+ { 0x0000c4e4, 0x00003219 },
+ { 0x0000c4e8, 0x00003228 },
+ { 0x0000c4ec, 0x00003237 },
+ { 0x0000c4f0, 0x00003246 },
+ { 0x0000c4f4, 0x00003255 },
+ { 0x0000c4f8, 0x00003265 },
+ { 0x0000c4fc, 0x00003274 },
+ { 0x0000c500, 0x00003284 },
+ { 0x0000c504, 0x00003294 },
+ { 0x0000c508, 0x000032a5 },
+ { 0x0000c50c, 0x000032b5 },
+ { 0x0000c510, 0x000032c6 },
+ { 0x0000c514, 0x000032d7 },
+ { 0x0000c518, 0x000032e8 },
+ { 0x0000c51c, 0x000032f9 },
+ { 0x0000c520, 0x0000330b },
+ { 0x0000c524, 0x0000331d },
+ { 0x0000c528, 0x0000332f },
+ { 0x0000c52c, 0x00003341 },
+ { 0x0000c530, 0x00003354 },
+ { 0x0000c534, 0x00003367 },
+ { 0x0000c538, 0x0000337a },
+ { 0x0000c53c, 0x0000338d },
+ { 0x0000c540, 0x000033a0 },
+ { 0x0000c544, 0x000033b4 },
+ { 0x0000c548, 0x000033c8 },
+ { 0x0000c54c, 0x000033dc },
+ { 0x0000c550, 0x000033f0 },
+ { 0x0000c554, 0x00003402 },
+ { 0x0000c558, 0x0000340d },
+ { 0x0000c55c, 0x00003417 },
+ { 0x0000c560, 0x00003422 },
+ { 0x0000c564, 0x0000342c },
+ { 0x0000c568, 0x00003437 },
+ { 0x0000c56c, 0x00003442 },
+ { 0x0000c570, 0x0000344d },
+ { 0x0000c574, 0x00003459 },
+ { 0x0000c578, 0x00003464 },
+ { 0x0000c57c, 0x0000346f },
+ { 0x0000c580, 0x0000347b },
+ { 0x0000c584, 0x00003487 },
+ { 0x0000c588, 0x00003492 },
+ { 0x0000c58c, 0x0000349e },
+ { 0x0000c590, 0x000034aa },
+ { 0x0000c594, 0x000034b6 },
+ { 0x0000c598, 0x000034c3 },
+ { 0x0000c59c, 0x000034cf },
+ { 0x0000c5a0, 0x000034dc },
+ { 0x0000c5a4, 0x000034e8 },
+ { 0x0000c5a8, 0x000034f5 },
+ { 0x0000c5ac, 0x00003502 },
+ { 0x0000c5b0, 0x0000350f },
+ { 0x0000c5b4, 0x0000351c },
+ { 0x0000c5b8, 0x00003529 },
+ { 0x0000c5bc, 0x00003536 },
+ { 0x0000c5c0, 0x00003544 },
+ { 0x0000c5c4, 0x00003551 },
+ { 0x0000c5c8, 0x0000355f },
+ { 0x0000c5cc, 0x0000356d },
+ { 0x0000c5d0, 0x0000357b },
+ { 0x0000c5d4, 0x00003589 },
+ { 0x0000c5d8, 0x00003597 },
+ { 0x0000c5dc, 0x000035a5 },
+ { 0x0000c5e0, 0x000035b4 },
+ { 0x0000c5e4, 0x000035c2 },
+ { 0x0000c5e8, 0x000035d1 },
+ { 0x0000c5ec, 0x000035e0 },
+ { 0x0000c5f0, 0x000035ef },
+ { 0x0000c5f4, 0x000035fe },
+ { 0x0000c5f8, 0x00003606 },
+ { 0x0000c5fc, 0x0000360e },
+ { 0x0000c600, 0x00003616 },
+ { 0x0000c604, 0x0000361d },
+ { 0x0000c608, 0x00003625 },
+ { 0x0000c60c, 0x0000362d },
+ { 0x0000c610, 0x00003635 },
+ { 0x0000c614, 0x0000363d },
+ { 0x0000c618, 0x00003645 },
+ { 0x0000c61c, 0x0000364d },
+ { 0x0000c620, 0x00003655 },
+ { 0x0000c624, 0x0000365e },
+ { 0x0000c628, 0x00003666 },
+ { 0x0000c62c, 0x0000366e },
+ { 0x0000c630, 0x00003677 },
+ { 0x0000c634, 0x0000367f },
+ { 0x0000c638, 0x00003688 },
+ { 0x0000c63c, 0x00003690 },
+ { 0x0000c640, 0x00003699 },
+ { 0x0000c644, 0x000036a2 },
+ { 0x0000c648, 0x000036ab },
+ { 0x0000c64c, 0x000036b4 },
+ { 0x0000c650, 0x000036bc },
+ { 0x0000c654, 0x000036c5 },
+ { 0x0000c658, 0x000036cf },
+ { 0x0000c65c, 0x000036d8 },
+ { 0x0000c660, 0x000036e1 },
+ { 0x0000c664, 0x000036ea },
+ { 0x0000c668, 0x000036f3 },
+ { 0x0000c66c, 0x000036fd },
+ { 0x0000c670, 0x00003706 },
+ { 0x0000c674, 0x00003710 },
+ { 0x0000c678, 0x00003719 },
+ { 0x0000c67c, 0x00003723 },
+ { 0x0000c680, 0x0000372d },
+ { 0x0000c684, 0x00003737 },
+ { 0x0000c688, 0x00003740 },
+ { 0x0000c68c, 0x0000374a },
+ { 0x0000c690, 0x00003754 },
+ { 0x0000c694, 0x0000375e },
+ { 0x0000c698, 0x00003768 },
+ { 0x0000c69c, 0x00003772 },
+ { 0x0000c6a0, 0x0000377d },
+ { 0x0000c6a4, 0x00003787 },
+ { 0x0000c6a8, 0x00003791 },
+ { 0x0000c6ac, 0x0000379c },
+ { 0x0000c6b0, 0x000037a6 },
+ { 0x0000c6b4, 0x000037b1 },
+ { 0x0000c6b8, 0x000037bb },
+ { 0x0000c6bc, 0x000037c6 },
+ { 0x0000c6c0, 0x000037d1 },
+ { 0x0000c6c4, 0x000037dc },
+ { 0x0000c6c8, 0x000037e7 },
+ { 0x0000c6cc, 0x000037f1 },
+ { 0x0000c6d0, 0x000037fc },
+ { 0x0000c6d4, 0x00003804 },
+ { 0x0000c6d8, 0x00003809 },
+ { 0x0000c6dc, 0x0000380f },
+ { 0x0000c6e0, 0x00003814 },
+ { 0x0000c6e4, 0x0000381a },
+ { 0x0000c6e8, 0x00003820 },
+ { 0x0000c6ec, 0x00003825 },
+ { 0x0000c6f0, 0x0000382b },
+ { 0x0000c6f4, 0x00003831 },
+ { 0x0000c6f8, 0x00003837 },
+ { 0x0000c6fc, 0x0000383d },
+ { 0x0000c700, 0x00003843 },
+ { 0x0000c704, 0x00003848 },
+ { 0x0000c708, 0x0000384e },
+ { 0x0000c70c, 0x00003854 },
+ { 0x0000c710, 0x0000385a },
+ { 0x0000c714, 0x00003861 },
+ { 0x0000c718, 0x00003867 },
+ { 0x0000c71c, 0x0000386d },
+ { 0x0000c720, 0x00003873 },
+ { 0x0000c724, 0x00003879 },
+ { 0x0000c728, 0x0000387f },
+ { 0x0000c72c, 0x00003886 },
+ { 0x0000c730, 0x0000388c },
+ { 0x0000c734, 0x00003892 },
+ { 0x0000c738, 0x00003899 },
+ { 0x0000c73c, 0x0000389f },
+ { 0x0000c740, 0x000038a5 },
+ { 0x0000c744, 0x000038ac },
+ { 0x0000c748, 0x000038b2 },
+ { 0x0000c74c, 0x000038b9 },
+ { 0x0000c750, 0x000038c0 },
+ { 0x0000c754, 0x000038c6 },
+ { 0x0000c758, 0x000038cd },
+ { 0x0000c75c, 0x000038d3 },
+ { 0x0000c760, 0x000038da },
+ { 0x0000c764, 0x000038e1 },
+ { 0x0000c768, 0x000038e8 },
+ { 0x0000c76c, 0x000038ee },
+ { 0x0000c770, 0x000038f5 },
+ { 0x0000c774, 0x000038fc },
+ { 0x0000c778, 0x00003903 },
+ { 0x0000c77c, 0x0000390a },
+ { 0x0000c780, 0x00003911 },
+ { 0x0000c784, 0x00003918 },
+ { 0x0000c788, 0x0000391f },
+ { 0x0000c78c, 0x00003926 },
+ { 0x0000c790, 0x0000392d },
+ { 0x0000c794, 0x00003934 },
+ { 0x0000c798, 0x0000393c },
+ { 0x0000c79c, 0x00003943 },
+ { 0x0000c7a0, 0x0000394a },
+ { 0x0000c7a4, 0x00003951 },
+ { 0x0000c7a8, 0x00003959 },
+ { 0x0000c7ac, 0x00003960 },
+ { 0x0000c7b0, 0x00003967 },
+ { 0x0000c7b4, 0x0000396f },
+ { 0x0000c7b8, 0x00003976 },
+ { 0x0000c7bc, 0x0000397e },
+ { 0x0000c7c0, 0x00003985 },
+ { 0x0000c7c4, 0x0000398d },
+ { 0x0000c7c8, 0x00003995 },
+ { 0x0000c7cc, 0x0000399c },
+ { 0x0000c7d0, 0x000039a4 },
+ { 0x0000c7d4, 0x000039ac },
+ { 0x0000c7d8, 0x000039b3 },
+ { 0x0000c7dc, 0x000039bb },
+ { 0x0000c7e0, 0x000039c3 },
+ { 0x0000c7e4, 0x000039cb },
+ { 0x0000c7e8, 0x000039d3 },
+ { 0x0000c7ec, 0x000039da },
+ { 0x0000c7f0, 0x000039e2 },
+ { 0x0000c7f4, 0x000039ea },
+ { 0x0000c7f8, 0x000039f2 },
+ { 0x0000c7fc, 0x000039fa },
+ { 0x0000c800, 0x00000000 },
+ { 0x0000c804, 0x0000238e },
+ { 0x0000c808, 0x0000258e },
+ { 0x0000c80c, 0x000026aa },
+ { 0x0000c810, 0x0000278e },
+ { 0x0000c814, 0x00002838 },
+ { 0x0000c818, 0x000028aa },
+ { 0x0000c81c, 0x0000291c },
+ { 0x0000c820, 0x0000298e },
+ { 0x0000c824, 0x000029ff },
+ { 0x0000c828, 0x00002a38 },
+ { 0x0000c82c, 0x00002a71 },
+ { 0x0000c830, 0x00002aaa },
+ { 0x0000c834, 0x00002ae3 },
+ { 0x0000c838, 0x00002b1c },
+ { 0x0000c83c, 0x00002b55 },
+ { 0x0000c840, 0x00002b8e },
+ { 0x0000c844, 0x00002bc7 },
+ { 0x0000c848, 0x00002bff },
+ { 0x0000c84c, 0x00002c1c },
+ { 0x0000c850, 0x00002c38 },
+ { 0x0000c854, 0x00002c55 },
+ { 0x0000c858, 0x00002c71 },
+ { 0x0000c85c, 0x00002c8e },
+ { 0x0000c860, 0x00002caa },
+ { 0x0000c864, 0x00002cc7 },
+ { 0x0000c868, 0x00002ce3 },
+ { 0x0000c86c, 0x00002cff },
+ { 0x0000c870, 0x00002d1c },
+ { 0x0000c874, 0x00002d38 },
+ { 0x0000c878, 0x00002d55 },
+ { 0x0000c87c, 0x00002d71 },
+ { 0x0000c880, 0x00002d8e },
+ { 0x0000c884, 0x00002daa },
+ { 0x0000c888, 0x00002dc7 },
+ { 0x0000c88c, 0x00002de3 },
+ { 0x0000c890, 0x00002dff },
+ { 0x0000c894, 0x00002e0e },
+ { 0x0000c898, 0x00002e1c },
+ { 0x0000c89c, 0x00002e2a },
+ { 0x0000c8a0, 0x00002e38 },
+ { 0x0000c8a4, 0x00002e47 },
+ { 0x0000c8a8, 0x00002e53 },
+ { 0x0000c8ac, 0x00002e61 },
+ { 0x0000c8b0, 0x00002e70 },
+ { 0x0000c8b4, 0x00002e7f },
+ { 0x0000c8b8, 0x00002e8e },
+ { 0x0000c8bc, 0x00002e9d },
+ { 0x0000c8c0, 0x00002eac },
+ { 0x0000c8c4, 0x00002ebc },
+ { 0x0000c8c8, 0x00002ecb },
+ { 0x0000c8cc, 0x00002edb },
+ { 0x0000c8d0, 0x00002eeb },
+ { 0x0000c8d4, 0x00002efc },
+ { 0x0000c8d8, 0x00002f0c },
+ { 0x0000c8dc, 0x00002f1d },
+ { 0x0000c8e0, 0x00002f2e },
+ { 0x0000c8e4, 0x00002f3f },
+ { 0x0000c8e8, 0x00002f50 },
+ { 0x0000c8ec, 0x00002f61 },
+ { 0x0000c8f0, 0x00002f73 },
+ { 0x0000c8f4, 0x00002f85 },
+ { 0x0000c8f8, 0x00002f97 },
+ { 0x0000c8fc, 0x00002fa9 },
+ { 0x0000c900, 0x00002fbc },
+ { 0x0000c904, 0x00002fce },
+ { 0x0000c908, 0x00002fe1 },
+ { 0x0000c90c, 0x00002ff4 },
+ { 0x0000c910, 0x00003003 },
+ { 0x0000c914, 0x0000300d },
+ { 0x0000c918, 0x00003017 },
+ { 0x0000c91c, 0x00003021 },
+ { 0x0000c920, 0x0000302b },
+ { 0x0000c924, 0x00003035 },
+ { 0x0000c928, 0x0000303f },
+ { 0x0000c92c, 0x0000304a },
+ { 0x0000c930, 0x00003054 },
+ { 0x0000c934, 0x0000305f },
+ { 0x0000c938, 0x00003069 },
+ { 0x0000c93c, 0x00003074 },
+ { 0x0000c940, 0x0000307f },
+ { 0x0000c944, 0x0000308a },
+ { 0x0000c948, 0x00003095 },
+ { 0x0000c94c, 0x000030a0 },
+ { 0x0000c950, 0x000030ab },
+ { 0x0000c954, 0x000030b6 },
+ { 0x0000c958, 0x000030c2 },
+ { 0x0000c95c, 0x000030cd },
+ { 0x0000c960, 0x000030d9 },
+ { 0x0000c964, 0x000030e5 },
+ { 0x0000c968, 0x000030f1 },
+ { 0x0000c96c, 0x000030fc },
+ { 0x0000c970, 0x00003109 },
+ { 0x0000c974, 0x00003115 },
+ { 0x0000c978, 0x00003121 },
+ { 0x0000c97c, 0x0000312d },
+ { 0x0000c980, 0x0000313a },
+ { 0x0000c984, 0x00003146 },
+ { 0x0000c988, 0x00003153 },
+ { 0x0000c98c, 0x00003160 },
+ { 0x0000c990, 0x0000316d },
+ { 0x0000c994, 0x0000317a },
+ { 0x0000c998, 0x00003187 },
+ { 0x0000c99c, 0x00003194 },
+ { 0x0000c9a0, 0x000031a1 },
+ { 0x0000c9a4, 0x000031af },
+ { 0x0000c9a8, 0x000031bc },
+ { 0x0000c9ac, 0x000031ca },
+ { 0x0000c9b0, 0x000031d8 },
+ { 0x0000c9b4, 0x000031e5 },
+ { 0x0000c9b8, 0x000031f3 },
+ { 0x0000c9bc, 0x00003200 },
+ { 0x0000c9c0, 0x00003208 },
+ { 0x0000c9c4, 0x0000320f },
+ { 0x0000c9c8, 0x00003216 },
+ { 0x0000c9cc, 0x0000321d },
+ { 0x0000c9d0, 0x00003224 },
+ { 0x0000c9d4, 0x0000322c },
+ { 0x0000c9d8, 0x00003233 },
+ { 0x0000c9dc, 0x0000323b },
+ { 0x0000c9e0, 0x00003242 },
+ { 0x0000c9e4, 0x0000324a },
+ { 0x0000c9e8, 0x00003251 },
+ { 0x0000c9ec, 0x00003259 },
+ { 0x0000c9f0, 0x00003261 },
+ { 0x0000c9f4, 0x00003268 },
+ { 0x0000c9f8, 0x00003270 },
+ { 0x0000c9fc, 0x00003278 },
+ { 0x0000ca00, 0x00003280 },
+ { 0x0000ca04, 0x00003288 },
+ { 0x0000ca08, 0x00003290 },
+ { 0x0000ca0c, 0x00003298 },
+ { 0x0000ca10, 0x000032a0 },
+ { 0x0000ca14, 0x000032a9 },
+ { 0x0000ca18, 0x000032b1 },
+ { 0x0000ca1c, 0x000032b9 },
+ { 0x0000ca20, 0x000032c2 },
+ { 0x0000ca24, 0x000032ca },
+ { 0x0000ca28, 0x000032d3 },
+ { 0x0000ca2c, 0x000032db },
+ { 0x0000ca30, 0x000032e4 },
+ { 0x0000ca34, 0x000032ec },
+ { 0x0000ca38, 0x000032f5 },
+ { 0x0000ca3c, 0x000032fe },
+ { 0x0000ca40, 0x00003307 },
+ { 0x0000ca44, 0x00003310 },
+ { 0x0000ca48, 0x00003318 },
+ { 0x0000ca4c, 0x00003321 },
+ { 0x0000ca50, 0x0000332a },
+ { 0x0000ca54, 0x00003334 },
+ { 0x0000ca58, 0x0000333d },
+ { 0x0000ca5c, 0x00003346 },
+ { 0x0000ca60, 0x0000334f },
+ { 0x0000ca64, 0x00003359 },
+ { 0x0000ca68, 0x00003362 },
+ { 0x0000ca6c, 0x0000336b },
+ { 0x0000ca70, 0x00003375 },
+ { 0x0000ca74, 0x0000337e },
+ { 0x0000ca78, 0x00003388 },
+ { 0x0000ca7c, 0x00003392 },
+ { 0x0000ca80, 0x0000339b },
+ { 0x0000ca84, 0x000033a5 },
+ { 0x0000ca88, 0x000033af },
+ { 0x0000ca8c, 0x000033b9 },
+ { 0x0000ca90, 0x000033c3 },
+ { 0x0000ca94, 0x000033cd },
+ { 0x0000ca98, 0x000033d7 },
+ { 0x0000ca9c, 0x000033e1 },
+ { 0x0000caa0, 0x000033eb },
+ { 0x0000caa4, 0x000033f5 },
+ { 0x0000caa8, 0x00003400 },
+ { 0x0000caac, 0x00003405 },
+ { 0x0000cab0, 0x0000340a },
+ { 0x0000cab4, 0x0000340f },
+ { 0x0000cab8, 0x00003414 },
+ { 0x0000cabc, 0x0000341a },
+ { 0x0000cac0, 0x0000341f },
+ { 0x0000cac4, 0x00003424 },
+ { 0x0000cac8, 0x0000342a },
+ { 0x0000cacc, 0x0000342f },
+ { 0x0000cad0, 0x00003435 },
+ { 0x0000cad4, 0x0000343a },
+ { 0x0000cad8, 0x00003440 },
+ { 0x0000cadc, 0x00003445 },
+ { 0x0000cae0, 0x0000344b },
+ { 0x0000cae4, 0x00003450 },
+ { 0x0000cae8, 0x00003456 },
+ { 0x0000caec, 0x0000345b },
+ { 0x0000caf0, 0x00003461 },
+ { 0x0000caf4, 0x00003467 },
+ { 0x0000caf8, 0x0000346d },
+ { 0x0000cafc, 0x00003472 },
+ { 0x0000cb00, 0x00003478 },
+ { 0x0000cb04, 0x0000347e },
+ { 0x0000cb08, 0x00003484 },
+ { 0x0000cb0c, 0x0000348a },
+ { 0x0000cb10, 0x0000348f },
+ { 0x0000cb14, 0x00003495 },
+ { 0x0000cb18, 0x0000349b },
+ { 0x0000cb1c, 0x000034a1 },
+ { 0x0000cb20, 0x000034a7 },
+ { 0x0000cb24, 0x000034ad },
+ { 0x0000cb28, 0x000034b3 },
+ { 0x0000cb2c, 0x000034ba },
+ { 0x0000cb30, 0x000034c0 },
+ { 0x0000cb34, 0x000034c6 },
+ { 0x0000cb38, 0x000034cc },
+ { 0x0000cb3c, 0x000034d2 },
+ { 0x0000cb40, 0x000034d8 },
+ { 0x0000cb44, 0x000034df },
+ { 0x0000cb48, 0x000034e5 },
+ { 0x0000cb4c, 0x000034eb },
+ { 0x0000cb50, 0x000034f2 },
+ { 0x0000cb54, 0x000034f8 },
+ { 0x0000cb58, 0x000034ff },
+ { 0x0000cb5c, 0x00003505 },
+ { 0x0000cb60, 0x0000350c },
+ { 0x0000cb64, 0x00003512 },
+ { 0x0000cb68, 0x00003519 },
+ { 0x0000cb6c, 0x0000351f },
+ { 0x0000cb70, 0x00003526 },
+ { 0x0000cb74, 0x0000352c },
+ { 0x0000cb78, 0x00003533 },
+ { 0x0000cb7c, 0x0000353a },
+ { 0x0000cb80, 0x00003540 },
+ { 0x0000cb84, 0x00003547 },
+ { 0x0000cb88, 0x0000354e },
+ { 0x0000cb8c, 0x00003555 },
+ { 0x0000cb90, 0x0000355c },
+ { 0x0000cb94, 0x00003563 },
+ { 0x0000cb98, 0x00003569 },
+ { 0x0000cb9c, 0x00003570 },
+ { 0x0000cba0, 0x00003577 },
+ { 0x0000cba4, 0x0000357e },
+ { 0x0000cba8, 0x00003585 },
+ { 0x0000cbac, 0x0000358c },
+ { 0x0000cbb0, 0x00003594 },
+ { 0x0000cbb4, 0x0000359b },
+ { 0x0000cbb8, 0x000035a2 },
+ { 0x0000cbbc, 0x000035a9 },
+ { 0x0000cbc0, 0x000035b0 },
+ { 0x0000cbc4, 0x000035b7 },
+ { 0x0000cbc8, 0x000035bf },
+ { 0x0000cbcc, 0x000035c6 },
+ { 0x0000cbd0, 0x000035cd },
+ { 0x0000cbd4, 0x000035d5 },
+ { 0x0000cbd8, 0x000035dc },
+ { 0x0000cbdc, 0x000035e4 },
+ { 0x0000cbe0, 0x000035eb },
+ { 0x0000cbe4, 0x000035f2 },
+ { 0x0000cbe8, 0x000035fa },
+ { 0x0000cbec, 0x00003600 },
+ { 0x0000cbf0, 0x00003604 },
+ { 0x0000cbf4, 0x00003608 },
+ { 0x0000cbf8, 0x0000360c },
+ { 0x0000cbfc, 0x00003610 },
+ { 0x0000cc00, 0x00003614 },
+ { 0x0000cc04, 0x00003617 },
+ { 0x0000cc08, 0x0000361b },
+ { 0x0000cc0c, 0x0000361f },
+ { 0x0000cc10, 0x00003623 },
+ { 0x0000cc14, 0x00003627 },
+ { 0x0000cc18, 0x0000362b },
+ { 0x0000cc1c, 0x0000362f },
+ { 0x0000cc20, 0x00003633 },
+ { 0x0000cc24, 0x00003637 },
+ { 0x0000cc28, 0x0000363b },
+ { 0x0000cc2c, 0x0000363f },
+ { 0x0000cc30, 0x00003643 },
+ { 0x0000cc34, 0x00003647 },
+ { 0x0000cc38, 0x0000364b },
+ { 0x0000cc3c, 0x0000364f },
+ { 0x0000cc40, 0x00003653 },
+ { 0x0000cc44, 0x00003657 },
+ { 0x0000cc48, 0x0000365b },
+ { 0x0000cc4c, 0x00003660 },
+ { 0x0000cc50, 0x00003664 },
+ { 0x0000cc54, 0x00003668 },
+ { 0x0000cc58, 0x0000366c },
+ { 0x0000cc5c, 0x00003670 },
+ { 0x0000cc60, 0x00003675 },
+ { 0x0000cc64, 0x00003679 },
+ { 0x0000cc68, 0x0000367d },
+ { 0x0000cc6c, 0x00003681 },
+ { 0x0000cc70, 0x00003686 },
+ { 0x0000cc74, 0x0000368a },
+ { 0x0000cc78, 0x0000368e },
+ { 0x0000cc7c, 0x00003693 },
+ { 0x0000cc80, 0x00003697 },
+ { 0x0000cc84, 0x0000369b },
+ { 0x0000cc88, 0x000036a0 },
+ { 0x0000cc8c, 0x000036a4 },
+ { 0x0000cc90, 0x000036a8 },
+ { 0x0000cc94, 0x000036ad },
+ { 0x0000cc98, 0x000036b1 },
+ { 0x0000cc9c, 0x000036b6 },
+ { 0x0000cca0, 0x000036ba },
+ { 0x0000cca4, 0x000036bf },
+ { 0x0000cca8, 0x000036c3 },
+ { 0x0000ccac, 0x000036c8 },
+ { 0x0000ccb0, 0x000036cc },
+ { 0x0000ccb4, 0x000036d1 },
+ { 0x0000ccb8, 0x000036d5 },
+ { 0x0000ccbc, 0x000036da },
+ { 0x0000ccc0, 0x000036df },
+ { 0x0000ccc4, 0x000036e3 },
+ { 0x0000ccc8, 0x000036e8 },
+ { 0x0000cccc, 0x000036ec },
+ { 0x0000ccd0, 0x000036f1 },
+ { 0x0000ccd4, 0x000036f6 },
+ { 0x0000ccd8, 0x000036fb },
+ { 0x0000ccdc, 0x000036ff },
+ { 0x0000cce0, 0x00003704 },
+ { 0x0000cce4, 0x00003709 },
+ { 0x0000cce8, 0x0000370d },
+ { 0x0000ccec, 0x00003712 },
+ { 0x0000ccf0, 0x00003717 },
+ { 0x0000ccf4, 0x0000371c },
+ { 0x0000ccf8, 0x00003721 },
+ { 0x0000ccfc, 0x00003725 },
+ { 0x0000cd00, 0x0000372a },
+ { 0x0000cd04, 0x0000372f },
+ { 0x0000cd08, 0x00003734 },
+ { 0x0000cd0c, 0x00003739 },
+ { 0x0000cd10, 0x0000373e },
+ { 0x0000cd14, 0x00003743 },
+ { 0x0000cd18, 0x00003748 },
+ { 0x0000cd1c, 0x0000374d },
+ { 0x0000cd20, 0x00003752 },
+ { 0x0000cd24, 0x00003757 },
+ { 0x0000cd28, 0x0000375c },
+ { 0x0000cd2c, 0x00003761 },
+ { 0x0000cd30, 0x00003766 },
+ { 0x0000cd34, 0x0000376b },
+ { 0x0000cd38, 0x00003770 },
+ { 0x0000cd3c, 0x00003775 },
+ { 0x0000cd40, 0x0000377a },
+ { 0x0000cd44, 0x0000377f },
+ { 0x0000cd48, 0x00003784 },
+ { 0x0000cd4c, 0x0000378a },
+ { 0x0000cd50, 0x0000378f },
+ { 0x0000cd54, 0x00003794 },
+ { 0x0000cd58, 0x00003799 },
+ { 0x0000cd5c, 0x0000379e },
+ { 0x0000cd60, 0x000037a4 },
+ { 0x0000cd64, 0x000037a9 },
+ { 0x0000cd68, 0x000037ae },
+ { 0x0000cd6c, 0x000037b3 },
+ { 0x0000cd70, 0x000037b9 },
+ { 0x0000cd74, 0x000037be },
+ { 0x0000cd78, 0x000037c3 },
+ { 0x0000cd7c, 0x000037c9 },
+ { 0x0000cd80, 0x000037ce },
+ { 0x0000cd84, 0x000037d4 },
+ { 0x0000cd88, 0x000037d9 },
+ { 0x0000cd8c, 0x000037de },
+ { 0x0000cd90, 0x000037e4 },
+ { 0x0000cd94, 0x000037e9 },
+ { 0x0000cd98, 0x000037ef },
+ { 0x0000cd9c, 0x000037f4 },
+ { 0x0000cda0, 0x000037fa },
+ { 0x0000cda4, 0x000037ff },
+ { 0x0000cda8, 0x00003802 },
+ { 0x0000cdac, 0x00003805 },
+ { 0x0000cdb0, 0x00003808 },
+ { 0x0000cdb4, 0x0000380a },
+ { 0x0000cdb8, 0x0000380d },
+ { 0x0000cdbc, 0x00003810 },
+ { 0x0000cdc0, 0x00003813 },
+ { 0x0000cdc4, 0x00003816 },
+ { 0x0000cdc8, 0x00003819 },
+ { 0x0000cdcc, 0x0000381b },
+ { 0x0000cdd0, 0x0000381e },
+ { 0x0000cdd4, 0x00003821 },
+ { 0x0000cdd8, 0x00003824 },
+ { 0x0000cddc, 0x00003827 },
+ { 0x0000cde0, 0x0000382a },
+ { 0x0000cde4, 0x0000382d },
+ { 0x0000cde8, 0x00003830 },
+ { 0x0000cdec, 0x00003832 },
+ { 0x0000cdf0, 0x00003835 },
+ { 0x0000cdf4, 0x00003838 },
+ { 0x0000cdf8, 0x0000383b },
+ { 0x0000cdfc, 0x0000383e },
+ { 0x0000ce00, 0x00003841 },
+ { 0x0000ce04, 0x00003844 },
+ { 0x0000ce08, 0x00003847 },
+ { 0x0000ce0c, 0x0000384a },
+ { 0x0000ce10, 0x0000384d },
+ { 0x0000ce14, 0x00003850 },
+ { 0x0000ce18, 0x00003853 },
+ { 0x0000ce1c, 0x00003856 },
+ { 0x0000ce20, 0x00003859 },
+ { 0x0000ce24, 0x0000385c },
+ { 0x0000ce28, 0x0000385f },
+ { 0x0000ce2c, 0x00003862 },
+ { 0x0000ce30, 0x00003865 },
+ { 0x0000ce34, 0x00003868 },
+ { 0x0000ce38, 0x0000386b },
+ { 0x0000ce3c, 0x0000386e },
+ { 0x0000ce40, 0x00003871 },
+ { 0x0000ce44, 0x00003874 },
+ { 0x0000ce48, 0x00003878 },
+ { 0x0000ce4c, 0x0000387b },
+ { 0x0000ce50, 0x0000387e },
+ { 0x0000ce54, 0x00003881 },
+ { 0x0000ce58, 0x00003884 },
+ { 0x0000ce5c, 0x00003887 },
+ { 0x0000ce60, 0x0000388a },
+ { 0x0000ce64, 0x0000388e },
+ { 0x0000ce68, 0x00003891 },
+ { 0x0000ce6c, 0x00003894 },
+ { 0x0000ce70, 0x00003897 },
+ { 0x0000ce74, 0x0000389a },
+ { 0x0000ce78, 0x0000389d },
+ { 0x0000ce7c, 0x000038a1 },
+ { 0x0000ce80, 0x000038a4 },
+ { 0x0000ce84, 0x000038a7 },
+ { 0x0000ce88, 0x000038aa },
+ { 0x0000ce8c, 0x000038ae },
+ { 0x0000ce90, 0x000038b1 },
+ { 0x0000ce94, 0x000038b4 },
+ { 0x0000ce98, 0x000038b7 },
+ { 0x0000ce9c, 0x000038bb },
+ { 0x0000cea0, 0x000038be },
+ { 0x0000cea4, 0x000038c1 },
+ { 0x0000cea8, 0x000038c4 },
+ { 0x0000ceac, 0x000038c8 },
+ { 0x0000ceb0, 0x000038cb },
+ { 0x0000ceb4, 0x000038ce },
+ { 0x0000ceb8, 0x000038d2 },
+ { 0x0000cebc, 0x000038d5 },
+ { 0x0000cec0, 0x000038d8 },
+ { 0x0000cec4, 0x000038dc },
+ { 0x0000cec8, 0x000038df },
+ { 0x0000cecc, 0x000038e3 },
+ { 0x0000ced0, 0x000038e6 },
+ { 0x0000ced4, 0x000038e9 },
+ { 0x0000ced8, 0x000038ed },
+ { 0x0000cedc, 0x000038f0 },
+ { 0x0000cee0, 0x000038f4 },
+ { 0x0000cee4, 0x000038f7 },
+ { 0x0000cee8, 0x000038fa },
+ { 0x0000ceec, 0x000038fe },
+ { 0x0000cef0, 0x00003901 },
+ { 0x0000cef4, 0x00003905 },
+ { 0x0000cef8, 0x00003908 },
+ { 0x0000cefc, 0x0000390c },
+ { 0x0000cf00, 0x0000390f },
+ { 0x0000cf04, 0x00003913 },
+ { 0x0000cf08, 0x00003916 },
+ { 0x0000cf0c, 0x0000391a },
+ { 0x0000cf10, 0x0000391d },
+ { 0x0000cf14, 0x00003921 },
+ { 0x0000cf18, 0x00003924 },
+ { 0x0000cf1c, 0x00003928 },
+ { 0x0000cf20, 0x0000392b },
+ { 0x0000cf24, 0x0000392f },
+ { 0x0000cf28, 0x00003933 },
+ { 0x0000cf2c, 0x00003936 },
+ { 0x0000cf30, 0x0000393a },
+ { 0x0000cf34, 0x0000393d },
+ { 0x0000cf38, 0x00003941 },
+ { 0x0000cf3c, 0x00003945 },
+ { 0x0000cf40, 0x00003948 },
+ { 0x0000cf44, 0x0000394c },
+ { 0x0000cf48, 0x00003950 },
+ { 0x0000cf4c, 0x00003953 },
+ { 0x0000cf50, 0x00003957 },
+ { 0x0000cf54, 0x0000395b },
+ { 0x0000cf58, 0x0000395e },
+ { 0x0000cf5c, 0x00003962 },
+ { 0x0000cf60, 0x00003966 },
+ { 0x0000cf64, 0x00003969 },
+ { 0x0000cf68, 0x0000396d },
+ { 0x0000cf6c, 0x00003971 },
+ { 0x0000cf70, 0x00003974 },
+ { 0x0000cf74, 0x00003978 },
+ { 0x0000cf78, 0x0000397c },
+ { 0x0000cf7c, 0x00003980 },
+ { 0x0000cf80, 0x00003983 },
+ { 0x0000cf84, 0x00003987 },
+ { 0x0000cf88, 0x0000398b },
+ { 0x0000cf8c, 0x0000398f },
+ { 0x0000cf90, 0x00003993 },
+ { 0x0000cf94, 0x00003996 },
+ { 0x0000cf98, 0x0000399a },
+ { 0x0000cf9c, 0x0000399e },
+ { 0x0000cfa0, 0x000039a2 },
+ { 0x0000cfa4, 0x000039a6 },
+ { 0x0000cfa8, 0x000039aa },
+ { 0x0000cfac, 0x000039ad },
+ { 0x0000cfb0, 0x000039b1 },
+ { 0x0000cfb4, 0x000039b5 },
+ { 0x0000cfb8, 0x000039b9 },
+ { 0x0000cfbc, 0x000039bd },
+ { 0x0000cfc0, 0x000039c1 },
+ { 0x0000cfc4, 0x000039c5 },
+ { 0x0000cfc8, 0x000039c9 },
+ { 0x0000cfcc, 0x000039cd },
+ { 0x0000cfd0, 0x000039d1 },
+ { 0x0000cfd4, 0x000039d5 },
+ { 0x0000cfd8, 0x000039d8 },
+ { 0x0000cfdc, 0x000039dc },
+ { 0x0000cfe0, 0x000039e0 },
+ { 0x0000cfe4, 0x000039e4 },
+ { 0x0000cfe8, 0x000039e8 },
+ { 0x0000cfec, 0x000039ec },
+ { 0x0000cff0, 0x000039f0 },
+ { 0x0000cff4, 0x000039f4 },
+ { 0x0000cff8, 0x000039f8 },
+ { 0x0000cffc, 0x000039fc },
+};
+
+struct data_unit hdr10_opipe_a1[] = {
+ { 0x0000d000, 0x00003612 },
+ { 0x0000d004, 0x00003612 },
+ { 0x0000d008, 0x0000327c },
+ { 0x0000d00c, 0x00003840 },
+ { 0x0000d010, 0x00002fb2 },
+ { 0x0000d014, 0x00003475 },
+ { 0x0000d018, 0x00003728 },
+ { 0x0000d01c, 0x0000390e },
+ { 0x0000d020, 0x00002d7f },
+ { 0x0000d024, 0x00003134 },
+ { 0x0000d028, 0x00003397 },
+ { 0x0000d02c, 0x0000353d },
+ { 0x0000d030, 0x00003695 },
+ { 0x0000d034, 0x000037cb },
+ { 0x0000d038, 0x000038a2 },
+ { 0x0000d03c, 0x00003982 },
+ { 0x0000d040, 0x00002b71 },
+ { 0x0000d044, 0x00002ea4 },
+ { 0x0000d048, 0x00003079 },
+ { 0x0000d04c, 0x00003204 },
+ { 0x0000d050, 0x00003302 },
+ { 0x0000d054, 0x0000341c },
+ { 0x0000d058, 0x000034d5 },
+ { 0x0000d05c, 0x000035ad },
+ { 0x0000d060, 0x00003651 },
+ { 0x0000d064, 0x000036dc },
+ { 0x0000d068, 0x00003778 },
+ { 0x0000d06c, 0x00003811 },
+ { 0x0000d070, 0x00003870 },
+ { 0x0000d074, 0x000038d7 },
+ { 0x0000d078, 0x00003946 },
+ { 0x0000d07c, 0x000039bf },
+ { 0x0000d080, 0x00002955 },
+ { 0x0000d084, 0x00002c9c },
+ { 0x0000d088, 0x00002e31 },
+ { 0x0000d08c, 0x00002f25 },
+ { 0x0000d090, 0x00003026 },
+ { 0x0000d094, 0x000030d3 },
+ { 0x0000d098, 0x0000319b },
+ { 0x0000d09c, 0x0000323e },
+ { 0x0000d0a0, 0x000032bd },
+ { 0x0000d0a4, 0x0000334b },
+ { 0x0000d0a8, 0x000033e6 },
+ { 0x0000d0ac, 0x00003448 },
+ { 0x0000d0b0, 0x000034a4 },
+ { 0x0000d0b4, 0x00003508 },
+ { 0x0000d0b8, 0x00003574 },
+ { 0x0000d0bc, 0x000035e7 },
+ { 0x0000d0c0, 0x00003631 },
+ { 0x0000d0c4, 0x00003672 },
+ { 0x0000d0c8, 0x000036b8 },
+ { 0x0000d0cc, 0x00003702 },
+ { 0x0000d0d0, 0x0000374f },
+ { 0x0000d0d4, 0x000037a1 },
+ { 0x0000d0d8, 0x000037f7 },
+ { 0x0000d0dc, 0x00003828 },
+ { 0x0000d0e0, 0x00003857 },
+ { 0x0000d0e4, 0x00003889 },
+ { 0x0000d0e8, 0x000038bc },
+ { 0x0000d0ec, 0x000038f2 },
+ { 0x0000d0f0, 0x0000392a },
+ { 0x0000d0f4, 0x00003964 },
+ { 0x0000d0f8, 0x000039a0 },
+ { 0x0000d0fc, 0x000039de },
+ { 0x0000d100, 0x0000271c },
+ { 0x0000d104, 0x00002a8e },
+ { 0x0000d108, 0x00002c2a },
+ { 0x0000d10c, 0x00002d0e },
+ { 0x0000d110, 0x00002df1 },
+ { 0x0000d114, 0x00002e69 },
+ { 0x0000d118, 0x00002ee3 },
+ { 0x0000d11c, 0x00002f6a },
+ { 0x0000d120, 0x00002ffe },
+ { 0x0000d124, 0x0000304f },
+ { 0x0000d128, 0x000030a5 },
+ { 0x0000d12c, 0x00003102 },
+ { 0x0000d130, 0x00003166 },
+ { 0x0000d134, 0x000031d1 },
+ { 0x0000d138, 0x00003221 },
+ { 0x0000d13c, 0x0000325d },
+ { 0x0000d140, 0x0000329c },
+ { 0x0000d144, 0x000032df },
+ { 0x0000d148, 0x00003326 },
+ { 0x0000d14c, 0x00003370 },
+ { 0x0000d150, 0x000033be },
+ { 0x0000d154, 0x00003407 },
+ { 0x0000d158, 0x00003432 },
+ { 0x0000d15c, 0x0000345e },
+ { 0x0000d160, 0x0000348c },
+ { 0x0000d164, 0x000034bd },
+ { 0x0000d168, 0x000034ef },
+ { 0x0000d16c, 0x00003522 },
+ { 0x0000d170, 0x00003558 },
+ { 0x0000d174, 0x00003590 },
+ { 0x0000d178, 0x000035ca },
+ { 0x0000d17c, 0x00003602 },
+ { 0x0000d180, 0x00003621 },
+ { 0x0000d184, 0x00003641 },
+ { 0x0000d188, 0x00003662 },
+ { 0x0000d18c, 0x00003683 },
+ { 0x0000d190, 0x000036a6 },
+ { 0x0000d194, 0x000036ca },
+ { 0x0000d198, 0x000036ef },
+ { 0x0000d19c, 0x00003715 },
+ { 0x0000d1a0, 0x0000373b },
+ { 0x0000d1a4, 0x00003763 },
+ { 0x0000d1a8, 0x0000378c },
+ { 0x0000d1ac, 0x000037b6 },
+ { 0x0000d1b0, 0x000037e1 },
+ { 0x0000d1b4, 0x00003806 },
+ { 0x0000d1b8, 0x0000381d },
+ { 0x0000d1bc, 0x00003834 },
+ { 0x0000d1c0, 0x0000384b },
+ { 0x0000d1c4, 0x00003864 },
+ { 0x0000d1c8, 0x0000387c },
+ { 0x0000d1cc, 0x00003895 },
+ { 0x0000d1d0, 0x000038af },
+ { 0x0000d1d4, 0x000038c9 },
+ { 0x0000d1d8, 0x000038e4 },
+ { 0x0000d1dc, 0x00003900 },
+ { 0x0000d1e0, 0x0000391c },
+ { 0x0000d1e4, 0x00003938 },
+ { 0x0000d1e8, 0x00003955 },
+ { 0x0000d1ec, 0x00003973 },
+ { 0x0000d1f0, 0x00003991 },
+ { 0x0000d1f4, 0x000039af },
+ { 0x0000d1f8, 0x000039cf },
+ { 0x0000d1fc, 0x000039ee },
+ { 0x0000d200, 0x000024aa },
+ { 0x0000d204, 0x00002871 },
+ { 0x0000d208, 0x00002a1c },
+ { 0x0000d20c, 0x00002aff },
+ { 0x0000d210, 0x00002be3 },
+ { 0x0000d214, 0x00002c63 },
+ { 0x0000d218, 0x00002cd5 },
+ { 0x0000d21c, 0x00002d47 },
+ { 0x0000d220, 0x00002db8 },
+ { 0x0000d224, 0x00002e15 },
+ { 0x0000d228, 0x00002e4c },
+ { 0x0000d22c, 0x00002e86 },
+ { 0x0000d230, 0x00002ec4 },
+ { 0x0000d234, 0x00002f04 },
+ { 0x0000d238, 0x00002f47 },
+ { 0x0000d23c, 0x00002f8e },
+ { 0x0000d240, 0x00002fd8 },
+ { 0x0000d244, 0x00003012 },
+ { 0x0000d248, 0x0000303a },
+ { 0x0000d24c, 0x00003064 },
+ { 0x0000d250, 0x0000308f },
+ { 0x0000d254, 0x000030bc },
+ { 0x0000d258, 0x000030eb },
+ { 0x0000d25c, 0x0000311b },
+ { 0x0000d260, 0x0000314d },
+ { 0x0000d264, 0x00003180 },
+ { 0x0000d268, 0x000031b5 },
+ { 0x0000d26c, 0x000031ec },
+ { 0x0000d270, 0x00003212 },
+ { 0x0000d274, 0x0000322f },
+ { 0x0000d278, 0x0000324d },
+ { 0x0000d27c, 0x0000326c },
+ { 0x0000d280, 0x0000328c },
+ { 0x0000d284, 0x000032ad },
+ { 0x0000d288, 0x000032ce },
+ { 0x0000d28c, 0x000032f1 },
+ { 0x0000d290, 0x00003314 },
+ { 0x0000d294, 0x00003338 },
+ { 0x0000d298, 0x0000335d },
+ { 0x0000d29c, 0x00003383 },
+ { 0x0000d2a0, 0x000033aa },
+ { 0x0000d2a4, 0x000033d2 },
+ { 0x0000d2a8, 0x000033fb },
+ { 0x0000d2ac, 0x00003412 },
+ { 0x0000d2b0, 0x00003427 },
+ { 0x0000d2b4, 0x0000343d },
+ { 0x0000d2b8, 0x00003453 },
+ { 0x0000d2bc, 0x0000346a },
+ { 0x0000d2c0, 0x00003481 },
+ { 0x0000d2c4, 0x00003498 },
+ { 0x0000d2c8, 0x000034b0 },
+ { 0x0000d2cc, 0x000034c9 },
+ { 0x0000d2d0, 0x000034e2 },
+ { 0x0000d2d4, 0x000034fb },
+ { 0x0000d2d8, 0x00003515 },
+ { 0x0000d2dc, 0x00003530 },
+ { 0x0000d2e0, 0x0000354b },
+ { 0x0000d2e4, 0x00003566 },
+ { 0x0000d2e8, 0x00003582 },
+ { 0x0000d2ec, 0x0000359e },
+ { 0x0000d2f0, 0x000035bb },
+ { 0x0000d2f4, 0x000035d8 },
+ { 0x0000d2f8, 0x000035f6 },
+ { 0x0000d2fc, 0x0000360a },
+ { 0x0000d300, 0x00003619 },
+ { 0x0000d304, 0x00003629 },
+ { 0x0000d308, 0x00003639 },
+ { 0x0000d30c, 0x00003649 },
+ { 0x0000d310, 0x00003659 },
+ { 0x0000d314, 0x0000366a },
+ { 0x0000d318, 0x0000367b },
+ { 0x0000d31c, 0x0000368c },
+ { 0x0000d320, 0x0000369d },
+ { 0x0000d324, 0x000036af },
+ { 0x0000d328, 0x000036c1 },
+ { 0x0000d32c, 0x000036d3 },
+ { 0x0000d330, 0x000036e6 },
+ { 0x0000d334, 0x000036f8 },
+ { 0x0000d338, 0x0000370b },
+ { 0x0000d33c, 0x0000371e },
+ { 0x0000d340, 0x00003732 },
+ { 0x0000d344, 0x00003745 },
+ { 0x0000d348, 0x00003759 },
+ { 0x0000d34c, 0x0000376d },
+ { 0x0000d350, 0x00003782 },
+ { 0x0000d354, 0x00003797 },
+ { 0x0000d358, 0x000037ac },
+ { 0x0000d35c, 0x000037c1 },
+ { 0x0000d360, 0x000037d6 },
+ { 0x0000d364, 0x000037ec },
+ { 0x0000d368, 0x00003801 },
+ { 0x0000d36c, 0x0000380c },
+ { 0x0000d370, 0x00003817 },
+ { 0x0000d374, 0x00003823 },
+ { 0x0000d378, 0x0000382e },
+ { 0x0000d37c, 0x0000383a },
+ { 0x0000d380, 0x00003846 },
+ { 0x0000d384, 0x00003851 },
+ { 0x0000d388, 0x0000385e },
+ { 0x0000d38c, 0x0000386a },
+ { 0x0000d390, 0x00003876 },
+ { 0x0000d394, 0x00003883 },
+ { 0x0000d398, 0x0000388f },
+ { 0x0000d39c, 0x0000389c },
+ { 0x0000d3a0, 0x000038a9 },
+ { 0x0000d3a4, 0x000038b6 },
+ { 0x0000d3a8, 0x000038c3 },
+ { 0x0000d3ac, 0x000038d0 },
+ { 0x0000d3b0, 0x000038de },
+ { 0x0000d3b4, 0x000038eb },
+ { 0x0000d3b8, 0x000038f9 },
+ { 0x0000d3bc, 0x00003907 },
+ { 0x0000d3c0, 0x00003915 },
+ { 0x0000d3c4, 0x00003923 },
+ { 0x0000d3c8, 0x00003931 },
+ { 0x0000d3cc, 0x0000393f },
+ { 0x0000d3d0, 0x0000394e },
+ { 0x0000d3d4, 0x0000395c },
+ { 0x0000d3d8, 0x0000396b },
+ { 0x0000d3dc, 0x0000397a },
+ { 0x0000d3e0, 0x00003989 },
+ { 0x0000d3e4, 0x00003998 },
+ { 0x0000d3e8, 0x000039a8 },
+ { 0x0000d3ec, 0x000039b7 },
+ { 0x0000d3f0, 0x000039c7 },
+ { 0x0000d3f4, 0x000039d6 },
+ { 0x0000d3f8, 0x000039e6 },
+ { 0x0000d3fc, 0x000039f6 },
+ { 0x0000d400, 0x0000218e },
+ { 0x0000d404, 0x00002638 },
+ { 0x0000d408, 0x000027ff },
+ { 0x0000d40c, 0x000028e3 },
+ { 0x0000d410, 0x000029c7 },
+ { 0x0000d414, 0x00002a55 },
+ { 0x0000d418, 0x00002ac7 },
+ { 0x0000d41c, 0x00002b38 },
+ { 0x0000d420, 0x00002baa },
+ { 0x0000d424, 0x00002c0e },
+ { 0x0000d428, 0x00002c47 },
+ { 0x0000d42c, 0x00002c7f },
+ { 0x0000d430, 0x00002cb8 },
+ { 0x0000d434, 0x00002cf1 },
+ { 0x0000d438, 0x00002d2a },
+ { 0x0000d43c, 0x00002d63 },
+ { 0x0000d440, 0x00002d9c },
+ { 0x0000d444, 0x00002dd5 },
+ { 0x0000d448, 0x00002e07 },
+ { 0x0000d44c, 0x00002e23 },
+ { 0x0000d450, 0x00002e3f },
+ { 0x0000d454, 0x00002e5a },
+ { 0x0000d458, 0x00002e77 },
+ { 0x0000d45c, 0x00002e95 },
+ { 0x0000d460, 0x00002eb4 },
+ { 0x0000d464, 0x00002ed3 },
+ { 0x0000d468, 0x00002ef4 },
+ { 0x0000d46c, 0x00002f14 },
+ { 0x0000d470, 0x00002f36 },
+ { 0x0000d474, 0x00002f59 },
+ { 0x0000d478, 0x00002f7c },
+ { 0x0000d47c, 0x00002fa0 },
+ { 0x0000d480, 0x00002fc5 },
+ { 0x0000d484, 0x00002feb },
+ { 0x0000d488, 0x00003008 },
+ { 0x0000d48c, 0x0000301c },
+ { 0x0000d490, 0x00003030 },
+ { 0x0000d494, 0x00003044 },
+ { 0x0000d498, 0x00003059 },
+ { 0x0000d49c, 0x0000306e },
+ { 0x0000d4a0, 0x00003084 },
+ { 0x0000d4a4, 0x0000309a },
+ { 0x0000d4a8, 0x000030b1 },
+ { 0x0000d4ac, 0x000030c7 },
+ { 0x0000d4b0, 0x000030df },
+ { 0x0000d4b4, 0x000030f6 },
+ { 0x0000d4b8, 0x0000310f },
+ { 0x0000d4bc, 0x00003127 },
+ { 0x0000d4c0, 0x00003140 },
+ { 0x0000d4c4, 0x00003159 },
+ { 0x0000d4c8, 0x00003173 },
+ { 0x0000d4cc, 0x0000318d },
+ { 0x0000d4d0, 0x000031a8 },
+ { 0x0000d4d4, 0x000031c3 },
+ { 0x0000d4d8, 0x000031de },
+ { 0x0000d4dc, 0x000031fa },
+ { 0x0000d4e0, 0x0000320b },
+ { 0x0000d4e4, 0x00003219 },
+ { 0x0000d4e8, 0x00003228 },
+ { 0x0000d4ec, 0x00003237 },
+ { 0x0000d4f0, 0x00003246 },
+ { 0x0000d4f4, 0x00003255 },
+ { 0x0000d4f8, 0x00003265 },
+ { 0x0000d4fc, 0x00003274 },
+ { 0x0000d500, 0x00003284 },
+ { 0x0000d504, 0x00003294 },
+ { 0x0000d508, 0x000032a5 },
+ { 0x0000d50c, 0x000032b5 },
+ { 0x0000d510, 0x000032c6 },
+ { 0x0000d514, 0x000032d7 },
+ { 0x0000d518, 0x000032e8 },
+ { 0x0000d51c, 0x000032f9 },
+ { 0x0000d520, 0x0000330b },
+ { 0x0000d524, 0x0000331d },
+ { 0x0000d528, 0x0000332f },
+ { 0x0000d52c, 0x00003341 },
+ { 0x0000d530, 0x00003354 },
+ { 0x0000d534, 0x00003367 },
+ { 0x0000d538, 0x0000337a },
+ { 0x0000d53c, 0x0000338d },
+ { 0x0000d540, 0x000033a0 },
+ { 0x0000d544, 0x000033b4 },
+ { 0x0000d548, 0x000033c8 },
+ { 0x0000d54c, 0x000033dc },
+ { 0x0000d550, 0x000033f0 },
+ { 0x0000d554, 0x00003402 },
+ { 0x0000d558, 0x0000340d },
+ { 0x0000d55c, 0x00003417 },
+ { 0x0000d560, 0x00003422 },
+ { 0x0000d564, 0x0000342c },
+ { 0x0000d568, 0x00003437 },
+ { 0x0000d56c, 0x00003442 },
+ { 0x0000d570, 0x0000344d },
+ { 0x0000d574, 0x00003459 },
+ { 0x0000d578, 0x00003464 },
+ { 0x0000d57c, 0x0000346f },
+ { 0x0000d580, 0x0000347b },
+ { 0x0000d584, 0x00003487 },
+ { 0x0000d588, 0x00003492 },
+ { 0x0000d58c, 0x0000349e },
+ { 0x0000d590, 0x000034aa },
+ { 0x0000d594, 0x000034b6 },
+ { 0x0000d598, 0x000034c3 },
+ { 0x0000d59c, 0x000034cf },
+ { 0x0000d5a0, 0x000034dc },
+ { 0x0000d5a4, 0x000034e8 },
+ { 0x0000d5a8, 0x000034f5 },
+ { 0x0000d5ac, 0x00003502 },
+ { 0x0000d5b0, 0x0000350f },
+ { 0x0000d5b4, 0x0000351c },
+ { 0x0000d5b8, 0x00003529 },
+ { 0x0000d5bc, 0x00003536 },
+ { 0x0000d5c0, 0x00003544 },
+ { 0x0000d5c4, 0x00003551 },
+ { 0x0000d5c8, 0x0000355f },
+ { 0x0000d5cc, 0x0000356d },
+ { 0x0000d5d0, 0x0000357b },
+ { 0x0000d5d4, 0x00003589 },
+ { 0x0000d5d8, 0x00003597 },
+ { 0x0000d5dc, 0x000035a5 },
+ { 0x0000d5e0, 0x000035b4 },
+ { 0x0000d5e4, 0x000035c2 },
+ { 0x0000d5e8, 0x000035d1 },
+ { 0x0000d5ec, 0x000035e0 },
+ { 0x0000d5f0, 0x000035ef },
+ { 0x0000d5f4, 0x000035fe },
+ { 0x0000d5f8, 0x00003606 },
+ { 0x0000d5fc, 0x0000360e },
+ { 0x0000d600, 0x00003616 },
+ { 0x0000d604, 0x0000361d },
+ { 0x0000d608, 0x00003625 },
+ { 0x0000d60c, 0x0000362d },
+ { 0x0000d610, 0x00003635 },
+ { 0x0000d614, 0x0000363d },
+ { 0x0000d618, 0x00003645 },
+ { 0x0000d61c, 0x0000364d },
+ { 0x0000d620, 0x00003655 },
+ { 0x0000d624, 0x0000365e },
+ { 0x0000d628, 0x00003666 },
+ { 0x0000d62c, 0x0000366e },
+ { 0x0000d630, 0x00003677 },
+ { 0x0000d634, 0x0000367f },
+ { 0x0000d638, 0x00003688 },
+ { 0x0000d63c, 0x00003690 },
+ { 0x0000d640, 0x00003699 },
+ { 0x0000d644, 0x000036a2 },
+ { 0x0000d648, 0x000036ab },
+ { 0x0000d64c, 0x000036b4 },
+ { 0x0000d650, 0x000036bc },
+ { 0x0000d654, 0x000036c5 },
+ { 0x0000d658, 0x000036cf },
+ { 0x0000d65c, 0x000036d8 },
+ { 0x0000d660, 0x000036e1 },
+ { 0x0000d664, 0x000036ea },
+ { 0x0000d668, 0x000036f3 },
+ { 0x0000d66c, 0x000036fd },
+ { 0x0000d670, 0x00003706 },
+ { 0x0000d674, 0x00003710 },
+ { 0x0000d678, 0x00003719 },
+ { 0x0000d67c, 0x00003723 },
+ { 0x0000d680, 0x0000372d },
+ { 0x0000d684, 0x00003737 },
+ { 0x0000d688, 0x00003740 },
+ { 0x0000d68c, 0x0000374a },
+ { 0x0000d690, 0x00003754 },
+ { 0x0000d694, 0x0000375e },
+ { 0x0000d698, 0x00003768 },
+ { 0x0000d69c, 0x00003772 },
+ { 0x0000d6a0, 0x0000377d },
+ { 0x0000d6a4, 0x00003787 },
+ { 0x0000d6a8, 0x00003791 },
+ { 0x0000d6ac, 0x0000379c },
+ { 0x0000d6b0, 0x000037a6 },
+ { 0x0000d6b4, 0x000037b1 },
+ { 0x0000d6b8, 0x000037bb },
+ { 0x0000d6bc, 0x000037c6 },
+ { 0x0000d6c0, 0x000037d1 },
+ { 0x0000d6c4, 0x000037dc },
+ { 0x0000d6c8, 0x000037e7 },
+ { 0x0000d6cc, 0x000037f1 },
+ { 0x0000d6d0, 0x000037fc },
+ { 0x0000d6d4, 0x00003804 },
+ { 0x0000d6d8, 0x00003809 },
+ { 0x0000d6dc, 0x0000380f },
+ { 0x0000d6e0, 0x00003814 },
+ { 0x0000d6e4, 0x0000381a },
+ { 0x0000d6e8, 0x00003820 },
+ { 0x0000d6ec, 0x00003825 },
+ { 0x0000d6f0, 0x0000382b },
+ { 0x0000d6f4, 0x00003831 },
+ { 0x0000d6f8, 0x00003837 },
+ { 0x0000d6fc, 0x0000383d },
+ { 0x0000d700, 0x00003843 },
+ { 0x0000d704, 0x00003848 },
+ { 0x0000d708, 0x0000384e },
+ { 0x0000d70c, 0x00003854 },
+ { 0x0000d710, 0x0000385a },
+ { 0x0000d714, 0x00003861 },
+ { 0x0000d718, 0x00003867 },
+ { 0x0000d71c, 0x0000386d },
+ { 0x0000d720, 0x00003873 },
+ { 0x0000d724, 0x00003879 },
+ { 0x0000d728, 0x0000387f },
+ { 0x0000d72c, 0x00003886 },
+ { 0x0000d730, 0x0000388c },
+ { 0x0000d734, 0x00003892 },
+ { 0x0000d738, 0x00003899 },
+ { 0x0000d73c, 0x0000389f },
+ { 0x0000d740, 0x000038a5 },
+ { 0x0000d744, 0x000038ac },
+ { 0x0000d748, 0x000038b2 },
+ { 0x0000d74c, 0x000038b9 },
+ { 0x0000d750, 0x000038c0 },
+ { 0x0000d754, 0x000038c6 },
+ { 0x0000d758, 0x000038cd },
+ { 0x0000d75c, 0x000038d3 },
+ { 0x0000d760, 0x000038da },
+ { 0x0000d764, 0x000038e1 },
+ { 0x0000d768, 0x000038e8 },
+ { 0x0000d76c, 0x000038ee },
+ { 0x0000d770, 0x000038f5 },
+ { 0x0000d774, 0x000038fc },
+ { 0x0000d778, 0x00003903 },
+ { 0x0000d77c, 0x0000390a },
+ { 0x0000d780, 0x00003911 },
+ { 0x0000d784, 0x00003918 },
+ { 0x0000d788, 0x0000391f },
+ { 0x0000d78c, 0x00003926 },
+ { 0x0000d790, 0x0000392d },
+ { 0x0000d794, 0x00003934 },
+ { 0x0000d798, 0x0000393c },
+ { 0x0000d79c, 0x00003943 },
+ { 0x0000d7a0, 0x0000394a },
+ { 0x0000d7a4, 0x00003951 },
+ { 0x0000d7a8, 0x00003959 },
+ { 0x0000d7ac, 0x00003960 },
+ { 0x0000d7b0, 0x00003967 },
+ { 0x0000d7b4, 0x0000396f },
+ { 0x0000d7b8, 0x00003976 },
+ { 0x0000d7bc, 0x0000397e },
+ { 0x0000d7c0, 0x00003985 },
+ { 0x0000d7c4, 0x0000398d },
+ { 0x0000d7c8, 0x00003995 },
+ { 0x0000d7cc, 0x0000399c },
+ { 0x0000d7d0, 0x000039a4 },
+ { 0x0000d7d4, 0x000039ac },
+ { 0x0000d7d8, 0x000039b3 },
+ { 0x0000d7dc, 0x000039bb },
+ { 0x0000d7e0, 0x000039c3 },
+ { 0x0000d7e4, 0x000039cb },
+ { 0x0000d7e8, 0x000039d3 },
+ { 0x0000d7ec, 0x000039da },
+ { 0x0000d7f0, 0x000039e2 },
+ { 0x0000d7f4, 0x000039ea },
+ { 0x0000d7f8, 0x000039f2 },
+ { 0x0000d7fc, 0x000039fa },
+ { 0x0000d800, 0x00000000 },
+ { 0x0000d804, 0x0000238e },
+ { 0x0000d808, 0x0000258e },
+ { 0x0000d80c, 0x000026aa },
+ { 0x0000d810, 0x0000278e },
+ { 0x0000d814, 0x00002838 },
+ { 0x0000d818, 0x000028aa },
+ { 0x0000d81c, 0x0000291c },
+ { 0x0000d820, 0x0000298e },
+ { 0x0000d824, 0x000029ff },
+ { 0x0000d828, 0x00002a38 },
+ { 0x0000d82c, 0x00002a71 },
+ { 0x0000d830, 0x00002aaa },
+ { 0x0000d834, 0x00002ae3 },
+ { 0x0000d838, 0x00002b1c },
+ { 0x0000d83c, 0x00002b55 },
+ { 0x0000d840, 0x00002b8e },
+ { 0x0000d844, 0x00002bc7 },
+ { 0x0000d848, 0x00002bff },
+ { 0x0000d84c, 0x00002c1c },
+ { 0x0000d850, 0x00002c38 },
+ { 0x0000d854, 0x00002c55 },
+ { 0x0000d858, 0x00002c71 },
+ { 0x0000d85c, 0x00002c8e },
+ { 0x0000d860, 0x00002caa },
+ { 0x0000d864, 0x00002cc7 },
+ { 0x0000d868, 0x00002ce3 },
+ { 0x0000d86c, 0x00002cff },
+ { 0x0000d870, 0x00002d1c },
+ { 0x0000d874, 0x00002d38 },
+ { 0x0000d878, 0x00002d55 },
+ { 0x0000d87c, 0x00002d71 },
+ { 0x0000d880, 0x00002d8e },
+ { 0x0000d884, 0x00002daa },
+ { 0x0000d888, 0x00002dc7 },
+ { 0x0000d88c, 0x00002de3 },
+ { 0x0000d890, 0x00002dff },
+ { 0x0000d894, 0x00002e0e },
+ { 0x0000d898, 0x00002e1c },
+ { 0x0000d89c, 0x00002e2a },
+ { 0x0000d8a0, 0x00002e38 },
+ { 0x0000d8a4, 0x00002e47 },
+ { 0x0000d8a8, 0x00002e53 },
+ { 0x0000d8ac, 0x00002e61 },
+ { 0x0000d8b0, 0x00002e70 },
+ { 0x0000d8b4, 0x00002e7f },
+ { 0x0000d8b8, 0x00002e8e },
+ { 0x0000d8bc, 0x00002e9d },
+ { 0x0000d8c0, 0x00002eac },
+ { 0x0000d8c4, 0x00002ebc },
+ { 0x0000d8c8, 0x00002ecb },
+ { 0x0000d8cc, 0x00002edb },
+ { 0x0000d8d0, 0x00002eeb },
+ { 0x0000d8d4, 0x00002efc },
+ { 0x0000d8d8, 0x00002f0c },
+ { 0x0000d8dc, 0x00002f1d },
+ { 0x0000d8e0, 0x00002f2e },
+ { 0x0000d8e4, 0x00002f3f },
+ { 0x0000d8e8, 0x00002f50 },
+ { 0x0000d8ec, 0x00002f61 },
+ { 0x0000d8f0, 0x00002f73 },
+ { 0x0000d8f4, 0x00002f85 },
+ { 0x0000d8f8, 0x00002f97 },
+ { 0x0000d8fc, 0x00002fa9 },
+ { 0x0000d900, 0x00002fbc },
+ { 0x0000d904, 0x00002fce },
+ { 0x0000d908, 0x00002fe1 },
+ { 0x0000d90c, 0x00002ff4 },
+ { 0x0000d910, 0x00003003 },
+ { 0x0000d914, 0x0000300d },
+ { 0x0000d918, 0x00003017 },
+ { 0x0000d91c, 0x00003021 },
+ { 0x0000d920, 0x0000302b },
+ { 0x0000d924, 0x00003035 },
+ { 0x0000d928, 0x0000303f },
+ { 0x0000d92c, 0x0000304a },
+ { 0x0000d930, 0x00003054 },
+ { 0x0000d934, 0x0000305f },
+ { 0x0000d938, 0x00003069 },
+ { 0x0000d93c, 0x00003074 },
+ { 0x0000d940, 0x0000307f },
+ { 0x0000d944, 0x0000308a },
+ { 0x0000d948, 0x00003095 },
+ { 0x0000d94c, 0x000030a0 },
+ { 0x0000d950, 0x000030ab },
+ { 0x0000d954, 0x000030b6 },
+ { 0x0000d958, 0x000030c2 },
+ { 0x0000d95c, 0x000030cd },
+ { 0x0000d960, 0x000030d9 },
+ { 0x0000d964, 0x000030e5 },
+ { 0x0000d968, 0x000030f1 },
+ { 0x0000d96c, 0x000030fc },
+ { 0x0000d970, 0x00003109 },
+ { 0x0000d974, 0x00003115 },
+ { 0x0000d978, 0x00003121 },
+ { 0x0000d97c, 0x0000312d },
+ { 0x0000d980, 0x0000313a },
+ { 0x0000d984, 0x00003146 },
+ { 0x0000d988, 0x00003153 },
+ { 0x0000d98c, 0x00003160 },
+ { 0x0000d990, 0x0000316d },
+ { 0x0000d994, 0x0000317a },
+ { 0x0000d998, 0x00003187 },
+ { 0x0000d99c, 0x00003194 },
+ { 0x0000d9a0, 0x000031a1 },
+ { 0x0000d9a4, 0x000031af },
+ { 0x0000d9a8, 0x000031bc },
+ { 0x0000d9ac, 0x000031ca },
+ { 0x0000d9b0, 0x000031d8 },
+ { 0x0000d9b4, 0x000031e5 },
+ { 0x0000d9b8, 0x000031f3 },
+ { 0x0000d9bc, 0x00003200 },
+ { 0x0000d9c0, 0x00003208 },
+ { 0x0000d9c4, 0x0000320f },
+ { 0x0000d9c8, 0x00003216 },
+ { 0x0000d9cc, 0x0000321d },
+ { 0x0000d9d0, 0x00003224 },
+ { 0x0000d9d4, 0x0000322c },
+ { 0x0000d9d8, 0x00003233 },
+ { 0x0000d9dc, 0x0000323b },
+ { 0x0000d9e0, 0x00003242 },
+ { 0x0000d9e4, 0x0000324a },
+ { 0x0000d9e8, 0x00003251 },
+ { 0x0000d9ec, 0x00003259 },
+ { 0x0000d9f0, 0x00003261 },
+ { 0x0000d9f4, 0x00003268 },
+ { 0x0000d9f8, 0x00003270 },
+ { 0x0000d9fc, 0x00003278 },
+ { 0x0000da00, 0x00003280 },
+ { 0x0000da04, 0x00003288 },
+ { 0x0000da08, 0x00003290 },
+ { 0x0000da0c, 0x00003298 },
+ { 0x0000da10, 0x000032a0 },
+ { 0x0000da14, 0x000032a9 },
+ { 0x0000da18, 0x000032b1 },
+ { 0x0000da1c, 0x000032b9 },
+ { 0x0000da20, 0x000032c2 },
+ { 0x0000da24, 0x000032ca },
+ { 0x0000da28, 0x000032d3 },
+ { 0x0000da2c, 0x000032db },
+ { 0x0000da30, 0x000032e4 },
+ { 0x0000da34, 0x000032ec },
+ { 0x0000da38, 0x000032f5 },
+ { 0x0000da3c, 0x000032fe },
+ { 0x0000da40, 0x00003307 },
+ { 0x0000da44, 0x00003310 },
+ { 0x0000da48, 0x00003318 },
+ { 0x0000da4c, 0x00003321 },
+ { 0x0000da50, 0x0000332a },
+ { 0x0000da54, 0x00003334 },
+ { 0x0000da58, 0x0000333d },
+ { 0x0000da5c, 0x00003346 },
+ { 0x0000da60, 0x0000334f },
+ { 0x0000da64, 0x00003359 },
+ { 0x0000da68, 0x00003362 },
+ { 0x0000da6c, 0x0000336b },
+ { 0x0000da70, 0x00003375 },
+ { 0x0000da74, 0x0000337e },
+ { 0x0000da78, 0x00003388 },
+ { 0x0000da7c, 0x00003392 },
+ { 0x0000da80, 0x0000339b },
+ { 0x0000da84, 0x000033a5 },
+ { 0x0000da88, 0x000033af },
+ { 0x0000da8c, 0x000033b9 },
+ { 0x0000da90, 0x000033c3 },
+ { 0x0000da94, 0x000033cd },
+ { 0x0000da98, 0x000033d7 },
+ { 0x0000da9c, 0x000033e1 },
+ { 0x0000daa0, 0x000033eb },
+ { 0x0000daa4, 0x000033f5 },
+ { 0x0000daa8, 0x00003400 },
+ { 0x0000daac, 0x00003405 },
+ { 0x0000dab0, 0x0000340a },
+ { 0x0000dab4, 0x0000340f },
+ { 0x0000dab8, 0x00003414 },
+ { 0x0000dabc, 0x0000341a },
+ { 0x0000dac0, 0x0000341f },
+ { 0x0000dac4, 0x00003424 },
+ { 0x0000dac8, 0x0000342a },
+ { 0x0000dacc, 0x0000342f },
+ { 0x0000dad0, 0x00003435 },
+ { 0x0000dad4, 0x0000343a },
+ { 0x0000dad8, 0x00003440 },
+ { 0x0000dadc, 0x00003445 },
+ { 0x0000dae0, 0x0000344b },
+ { 0x0000dae4, 0x00003450 },
+ { 0x0000dae8, 0x00003456 },
+ { 0x0000daec, 0x0000345b },
+ { 0x0000daf0, 0x00003461 },
+ { 0x0000daf4, 0x00003467 },
+ { 0x0000daf8, 0x0000346d },
+ { 0x0000dafc, 0x00003472 },
+ { 0x0000db00, 0x00003478 },
+ { 0x0000db04, 0x0000347e },
+ { 0x0000db08, 0x00003484 },
+ { 0x0000db0c, 0x0000348a },
+ { 0x0000db10, 0x0000348f },
+ { 0x0000db14, 0x00003495 },
+ { 0x0000db18, 0x0000349b },
+ { 0x0000db1c, 0x000034a1 },
+ { 0x0000db20, 0x000034a7 },
+ { 0x0000db24, 0x000034ad },
+ { 0x0000db28, 0x000034b3 },
+ { 0x0000db2c, 0x000034ba },
+ { 0x0000db30, 0x000034c0 },
+ { 0x0000db34, 0x000034c6 },
+ { 0x0000db38, 0x000034cc },
+ { 0x0000db3c, 0x000034d2 },
+ { 0x0000db40, 0x000034d8 },
+ { 0x0000db44, 0x000034df },
+ { 0x0000db48, 0x000034e5 },
+ { 0x0000db4c, 0x000034eb },
+ { 0x0000db50, 0x000034f2 },
+ { 0x0000db54, 0x000034f8 },
+ { 0x0000db58, 0x000034ff },
+ { 0x0000db5c, 0x00003505 },
+ { 0x0000db60, 0x0000350c },
+ { 0x0000db64, 0x00003512 },
+ { 0x0000db68, 0x00003519 },
+ { 0x0000db6c, 0x0000351f },
+ { 0x0000db70, 0x00003526 },
+ { 0x0000db74, 0x0000352c },
+ { 0x0000db78, 0x00003533 },
+ { 0x0000db7c, 0x0000353a },
+ { 0x0000db80, 0x00003540 },
+ { 0x0000db84, 0x00003547 },
+ { 0x0000db88, 0x0000354e },
+ { 0x0000db8c, 0x00003555 },
+ { 0x0000db90, 0x0000355c },
+ { 0x0000db94, 0x00003563 },
+ { 0x0000db98, 0x00003569 },
+ { 0x0000db9c, 0x00003570 },
+ { 0x0000dba0, 0x00003577 },
+ { 0x0000dba4, 0x0000357e },
+ { 0x0000dba8, 0x00003585 },
+ { 0x0000dbac, 0x0000358c },
+ { 0x0000dbb0, 0x00003594 },
+ { 0x0000dbb4, 0x0000359b },
+ { 0x0000dbb8, 0x000035a2 },
+ { 0x0000dbbc, 0x000035a9 },
+ { 0x0000dbc0, 0x000035b0 },
+ { 0x0000dbc4, 0x000035b7 },
+ { 0x0000dbc8, 0x000035bf },
+ { 0x0000dbcc, 0x000035c6 },
+ { 0x0000dbd0, 0x000035cd },
+ { 0x0000dbd4, 0x000035d5 },
+ { 0x0000dbd8, 0x000035dc },
+ { 0x0000dbdc, 0x000035e4 },
+ { 0x0000dbe0, 0x000035eb },
+ { 0x0000dbe4, 0x000035f2 },
+ { 0x0000dbe8, 0x000035fa },
+ { 0x0000dbec, 0x00003600 },
+ { 0x0000dbf0, 0x00003604 },
+ { 0x0000dbf4, 0x00003608 },
+ { 0x0000dbf8, 0x0000360c },
+ { 0x0000dbfc, 0x00003610 },
+ { 0x0000dc00, 0x00003614 },
+ { 0x0000dc04, 0x00003617 },
+ { 0x0000dc08, 0x0000361b },
+ { 0x0000dc0c, 0x0000361f },
+ { 0x0000dc10, 0x00003623 },
+ { 0x0000dc14, 0x00003627 },
+ { 0x0000dc18, 0x0000362b },
+ { 0x0000dc1c, 0x0000362f },
+ { 0x0000dc20, 0x00003633 },
+ { 0x0000dc24, 0x00003637 },
+ { 0x0000dc28, 0x0000363b },
+ { 0x0000dc2c, 0x0000363f },
+ { 0x0000dc30, 0x00003643 },
+ { 0x0000dc34, 0x00003647 },
+ { 0x0000dc38, 0x0000364b },
+ { 0x0000dc3c, 0x0000364f },
+ { 0x0000dc40, 0x00003653 },
+ { 0x0000dc44, 0x00003657 },
+ { 0x0000dc48, 0x0000365b },
+ { 0x0000dc4c, 0x00003660 },
+ { 0x0000dc50, 0x00003664 },
+ { 0x0000dc54, 0x00003668 },
+ { 0x0000dc58, 0x0000366c },
+ { 0x0000dc5c, 0x00003670 },
+ { 0x0000dc60, 0x00003675 },
+ { 0x0000dc64, 0x00003679 },
+ { 0x0000dc68, 0x0000367d },
+ { 0x0000dc6c, 0x00003681 },
+ { 0x0000dc70, 0x00003686 },
+ { 0x0000dc74, 0x0000368a },
+ { 0x0000dc78, 0x0000368e },
+ { 0x0000dc7c, 0x00003693 },
+ { 0x0000dc80, 0x00003697 },
+ { 0x0000dc84, 0x0000369b },
+ { 0x0000dc88, 0x000036a0 },
+ { 0x0000dc8c, 0x000036a4 },
+ { 0x0000dc90, 0x000036a8 },
+ { 0x0000dc94, 0x000036ad },
+ { 0x0000dc98, 0x000036b1 },
+ { 0x0000dc9c, 0x000036b6 },
+ { 0x0000dca0, 0x000036ba },
+ { 0x0000dca4, 0x000036bf },
+ { 0x0000dca8, 0x000036c3 },
+ { 0x0000dcac, 0x000036c8 },
+ { 0x0000dcb0, 0x000036cc },
+ { 0x0000dcb4, 0x000036d1 },
+ { 0x0000dcb8, 0x000036d5 },
+ { 0x0000dcbc, 0x000036da },
+ { 0x0000dcc0, 0x000036df },
+ { 0x0000dcc4, 0x000036e3 },
+ { 0x0000dcc8, 0x000036e8 },
+ { 0x0000dccc, 0x000036ec },
+ { 0x0000dcd0, 0x000036f1 },
+ { 0x0000dcd4, 0x000036f6 },
+ { 0x0000dcd8, 0x000036fb },
+ { 0x0000dcdc, 0x000036ff },
+ { 0x0000dce0, 0x00003704 },
+ { 0x0000dce4, 0x00003709 },
+ { 0x0000dce8, 0x0000370d },
+ { 0x0000dcec, 0x00003712 },
+ { 0x0000dcf0, 0x00003717 },
+ { 0x0000dcf4, 0x0000371c },
+ { 0x0000dcf8, 0x00003721 },
+ { 0x0000dcfc, 0x00003725 },
+ { 0x0000dd00, 0x0000372a },
+ { 0x0000dd04, 0x0000372f },
+ { 0x0000dd08, 0x00003734 },
+ { 0x0000dd0c, 0x00003739 },
+ { 0x0000dd10, 0x0000373e },
+ { 0x0000dd14, 0x00003743 },
+ { 0x0000dd18, 0x00003748 },
+ { 0x0000dd1c, 0x0000374d },
+ { 0x0000dd20, 0x00003752 },
+ { 0x0000dd24, 0x00003757 },
+ { 0x0000dd28, 0x0000375c },
+ { 0x0000dd2c, 0x00003761 },
+ { 0x0000dd30, 0x00003766 },
+ { 0x0000dd34, 0x0000376b },
+ { 0x0000dd38, 0x00003770 },
+ { 0x0000dd3c, 0x00003775 },
+ { 0x0000dd40, 0x0000377a },
+ { 0x0000dd44, 0x0000377f },
+ { 0x0000dd48, 0x00003784 },
+ { 0x0000dd4c, 0x0000378a },
+ { 0x0000dd50, 0x0000378f },
+ { 0x0000dd54, 0x00003794 },
+ { 0x0000dd58, 0x00003799 },
+ { 0x0000dd5c, 0x0000379e },
+ { 0x0000dd60, 0x000037a4 },
+ { 0x0000dd64, 0x000037a9 },
+ { 0x0000dd68, 0x000037ae },
+ { 0x0000dd6c, 0x000037b3 },
+ { 0x0000dd70, 0x000037b9 },
+ { 0x0000dd74, 0x000037be },
+ { 0x0000dd78, 0x000037c3 },
+ { 0x0000dd7c, 0x000037c9 },
+ { 0x0000dd80, 0x000037ce },
+ { 0x0000dd84, 0x000037d4 },
+ { 0x0000dd88, 0x000037d9 },
+ { 0x0000dd8c, 0x000037de },
+ { 0x0000dd90, 0x000037e4 },
+ { 0x0000dd94, 0x000037e9 },
+ { 0x0000dd98, 0x000037ef },
+ { 0x0000dd9c, 0x000037f4 },
+ { 0x0000dda0, 0x000037fa },
+ { 0x0000dda4, 0x000037ff },
+ { 0x0000dda8, 0x00003802 },
+ { 0x0000ddac, 0x00003805 },
+ { 0x0000ddb0, 0x00003808 },
+ { 0x0000ddb4, 0x0000380a },
+ { 0x0000ddb8, 0x0000380d },
+ { 0x0000ddbc, 0x00003810 },
+ { 0x0000ddc0, 0x00003813 },
+ { 0x0000ddc4, 0x00003816 },
+ { 0x0000ddc8, 0x00003819 },
+ { 0x0000ddcc, 0x0000381b },
+ { 0x0000ddd0, 0x0000381e },
+ { 0x0000ddd4, 0x00003821 },
+ { 0x0000ddd8, 0x00003824 },
+ { 0x0000dddc, 0x00003827 },
+ { 0x0000dde0, 0x0000382a },
+ { 0x0000dde4, 0x0000382d },
+ { 0x0000dde8, 0x00003830 },
+ { 0x0000ddec, 0x00003832 },
+ { 0x0000ddf0, 0x00003835 },
+ { 0x0000ddf4, 0x00003838 },
+ { 0x0000ddf8, 0x0000383b },
+ { 0x0000ddfc, 0x0000383e },
+ { 0x0000de00, 0x00003841 },
+ { 0x0000de04, 0x00003844 },
+ { 0x0000de08, 0x00003847 },
+ { 0x0000de0c, 0x0000384a },
+ { 0x0000de10, 0x0000384d },
+ { 0x0000de14, 0x00003850 },
+ { 0x0000de18, 0x00003853 },
+ { 0x0000de1c, 0x00003856 },
+ { 0x0000de20, 0x00003859 },
+ { 0x0000de24, 0x0000385c },
+ { 0x0000de28, 0x0000385f },
+ { 0x0000de2c, 0x00003862 },
+ { 0x0000de30, 0x00003865 },
+ { 0x0000de34, 0x00003868 },
+ { 0x0000de38, 0x0000386b },
+ { 0x0000de3c, 0x0000386e },
+ { 0x0000de40, 0x00003871 },
+ { 0x0000de44, 0x00003874 },
+ { 0x0000de48, 0x00003878 },
+ { 0x0000de4c, 0x0000387b },
+ { 0x0000de50, 0x0000387e },
+ { 0x0000de54, 0x00003881 },
+ { 0x0000de58, 0x00003884 },
+ { 0x0000de5c, 0x00003887 },
+ { 0x0000de60, 0x0000388a },
+ { 0x0000de64, 0x0000388e },
+ { 0x0000de68, 0x00003891 },
+ { 0x0000de6c, 0x00003894 },
+ { 0x0000de70, 0x00003897 },
+ { 0x0000de74, 0x0000389a },
+ { 0x0000de78, 0x0000389d },
+ { 0x0000de7c, 0x000038a1 },
+ { 0x0000de80, 0x000038a4 },
+ { 0x0000de84, 0x000038a7 },
+ { 0x0000de88, 0x000038aa },
+ { 0x0000de8c, 0x000038ae },
+ { 0x0000de90, 0x000038b1 },
+ { 0x0000de94, 0x000038b4 },
+ { 0x0000de98, 0x000038b7 },
+ { 0x0000de9c, 0x000038bb },
+ { 0x0000dea0, 0x000038be },
+ { 0x0000dea4, 0x000038c1 },
+ { 0x0000dea8, 0x000038c4 },
+ { 0x0000deac, 0x000038c8 },
+ { 0x0000deb0, 0x000038cb },
+ { 0x0000deb4, 0x000038ce },
+ { 0x0000deb8, 0x000038d2 },
+ { 0x0000debc, 0x000038d5 },
+ { 0x0000dec0, 0x000038d8 },
+ { 0x0000dec4, 0x000038dc },
+ { 0x0000dec8, 0x000038df },
+ { 0x0000decc, 0x000038e3 },
+ { 0x0000ded0, 0x000038e6 },
+ { 0x0000ded4, 0x000038e9 },
+ { 0x0000ded8, 0x000038ed },
+ { 0x0000dedc, 0x000038f0 },
+ { 0x0000dee0, 0x000038f4 },
+ { 0x0000dee4, 0x000038f7 },
+ { 0x0000dee8, 0x000038fa },
+ { 0x0000deec, 0x000038fe },
+ { 0x0000def0, 0x00003901 },
+ { 0x0000def4, 0x00003905 },
+ { 0x0000def8, 0x00003908 },
+ { 0x0000defc, 0x0000390c },
+ { 0x0000df00, 0x0000390f },
+ { 0x0000df04, 0x00003913 },
+ { 0x0000df08, 0x00003916 },
+ { 0x0000df0c, 0x0000391a },
+ { 0x0000df10, 0x0000391d },
+ { 0x0000df14, 0x00003921 },
+ { 0x0000df18, 0x00003924 },
+ { 0x0000df1c, 0x00003928 },
+ { 0x0000df20, 0x0000392b },
+ { 0x0000df24, 0x0000392f },
+ { 0x0000df28, 0x00003933 },
+ { 0x0000df2c, 0x00003936 },
+ { 0x0000df30, 0x0000393a },
+ { 0x0000df34, 0x0000393d },
+ { 0x0000df38, 0x00003941 },
+ { 0x0000df3c, 0x00003945 },
+ { 0x0000df40, 0x00003948 },
+ { 0x0000df44, 0x0000394c },
+ { 0x0000df48, 0x00003950 },
+ { 0x0000df4c, 0x00003953 },
+ { 0x0000df50, 0x00003957 },
+ { 0x0000df54, 0x0000395b },
+ { 0x0000df58, 0x0000395e },
+ { 0x0000df5c, 0x00003962 },
+ { 0x0000df60, 0x00003966 },
+ { 0x0000df64, 0x00003969 },
+ { 0x0000df68, 0x0000396d },
+ { 0x0000df6c, 0x00003971 },
+ { 0x0000df70, 0x00003974 },
+ { 0x0000df74, 0x00003978 },
+ { 0x0000df78, 0x0000397c },
+ { 0x0000df7c, 0x00003980 },
+ { 0x0000df80, 0x00003983 },
+ { 0x0000df84, 0x00003987 },
+ { 0x0000df88, 0x0000398b },
+ { 0x0000df8c, 0x0000398f },
+ { 0x0000df90, 0x00003993 },
+ { 0x0000df94, 0x00003996 },
+ { 0x0000df98, 0x0000399a },
+ { 0x0000df9c, 0x0000399e },
+ { 0x0000dfa0, 0x000039a2 },
+ { 0x0000dfa4, 0x000039a6 },
+ { 0x0000dfa8, 0x000039aa },
+ { 0x0000dfac, 0x000039ad },
+ { 0x0000dfb0, 0x000039b1 },
+ { 0x0000dfb4, 0x000039b5 },
+ { 0x0000dfb8, 0x000039b9 },
+ { 0x0000dfbc, 0x000039bd },
+ { 0x0000dfc0, 0x000039c1 },
+ { 0x0000dfc4, 0x000039c5 },
+ { 0x0000dfc8, 0x000039c9 },
+ { 0x0000dfcc, 0x000039cd },
+ { 0x0000dfd0, 0x000039d1 },
+ { 0x0000dfd4, 0x000039d5 },
+ { 0x0000dfd8, 0x000039d8 },
+ { 0x0000dfdc, 0x000039dc },
+ { 0x0000dfe0, 0x000039e0 },
+ { 0x0000dfe4, 0x000039e4 },
+ { 0x0000dfe8, 0x000039e8 },
+ { 0x0000dfec, 0x000039ec },
+ { 0x0000dff0, 0x000039f0 },
+ { 0x0000dff4, 0x000039f4 },
+ { 0x0000dff8, 0x000039f8 },
+ { 0x0000dffc, 0x000039fc },
+};
+
+struct data_unit hdr10_opipe_a2[] = {
+ { 0x0000e000, 0x00003612 },
+ { 0x0000e004, 0x00003612 },
+ { 0x0000e008, 0x0000327c },
+ { 0x0000e00c, 0x00003840 },
+ { 0x0000e010, 0x00002fb2 },
+ { 0x0000e014, 0x00003475 },
+ { 0x0000e018, 0x00003728 },
+ { 0x0000e01c, 0x0000390e },
+ { 0x0000e020, 0x00002d7f },
+ { 0x0000e024, 0x00003134 },
+ { 0x0000e028, 0x00003397 },
+ { 0x0000e02c, 0x0000353d },
+ { 0x0000e030, 0x00003695 },
+ { 0x0000e034, 0x000037cb },
+ { 0x0000e038, 0x000038a2 },
+ { 0x0000e03c, 0x00003982 },
+ { 0x0000e040, 0x00002b71 },
+ { 0x0000e044, 0x00002ea4 },
+ { 0x0000e048, 0x00003079 },
+ { 0x0000e04c, 0x00003204 },
+ { 0x0000e050, 0x00003302 },
+ { 0x0000e054, 0x0000341c },
+ { 0x0000e058, 0x000034d5 },
+ { 0x0000e05c, 0x000035ad },
+ { 0x0000e060, 0x00003651 },
+ { 0x0000e064, 0x000036dc },
+ { 0x0000e068, 0x00003778 },
+ { 0x0000e06c, 0x00003811 },
+ { 0x0000e070, 0x00003870 },
+ { 0x0000e074, 0x000038d7 },
+ { 0x0000e078, 0x00003946 },
+ { 0x0000e07c, 0x000039bf },
+ { 0x0000e080, 0x00002955 },
+ { 0x0000e084, 0x00002c9c },
+ { 0x0000e088, 0x00002e31 },
+ { 0x0000e08c, 0x00002f25 },
+ { 0x0000e090, 0x00003026 },
+ { 0x0000e094, 0x000030d3 },
+ { 0x0000e098, 0x0000319b },
+ { 0x0000e09c, 0x0000323e },
+ { 0x0000e0a0, 0x000032bd },
+ { 0x0000e0a4, 0x0000334b },
+ { 0x0000e0a8, 0x000033e6 },
+ { 0x0000e0ac, 0x00003448 },
+ { 0x0000e0b0, 0x000034a4 },
+ { 0x0000e0b4, 0x00003508 },
+ { 0x0000e0b8, 0x00003574 },
+ { 0x0000e0bc, 0x000035e7 },
+ { 0x0000e0c0, 0x00003631 },
+ { 0x0000e0c4, 0x00003672 },
+ { 0x0000e0c8, 0x000036b8 },
+ { 0x0000e0cc, 0x00003702 },
+ { 0x0000e0d0, 0x0000374f },
+ { 0x0000e0d4, 0x000037a1 },
+ { 0x0000e0d8, 0x000037f7 },
+ { 0x0000e0dc, 0x00003828 },
+ { 0x0000e0e0, 0x00003857 },
+ { 0x0000e0e4, 0x00003889 },
+ { 0x0000e0e8, 0x000038bc },
+ { 0x0000e0ec, 0x000038f2 },
+ { 0x0000e0f0, 0x0000392a },
+ { 0x0000e0f4, 0x00003964 },
+ { 0x0000e0f8, 0x000039a0 },
+ { 0x0000e0fc, 0x000039de },
+ { 0x0000e100, 0x0000271c },
+ { 0x0000e104, 0x00002a8e },
+ { 0x0000e108, 0x00002c2a },
+ { 0x0000e10c, 0x00002d0e },
+ { 0x0000e110, 0x00002df1 },
+ { 0x0000e114, 0x00002e69 },
+ { 0x0000e118, 0x00002ee3 },
+ { 0x0000e11c, 0x00002f6a },
+ { 0x0000e120, 0x00002ffe },
+ { 0x0000e124, 0x0000304f },
+ { 0x0000e128, 0x000030a5 },
+ { 0x0000e12c, 0x00003102 },
+ { 0x0000e130, 0x00003166 },
+ { 0x0000e134, 0x000031d1 },
+ { 0x0000e138, 0x00003221 },
+ { 0x0000e13c, 0x0000325d },
+ { 0x0000e140, 0x0000329c },
+ { 0x0000e144, 0x000032df },
+ { 0x0000e148, 0x00003326 },
+ { 0x0000e14c, 0x00003370 },
+ { 0x0000e150, 0x000033be },
+ { 0x0000e154, 0x00003407 },
+ { 0x0000e158, 0x00003432 },
+ { 0x0000e15c, 0x0000345e },
+ { 0x0000e160, 0x0000348c },
+ { 0x0000e164, 0x000034bd },
+ { 0x0000e168, 0x000034ef },
+ { 0x0000e16c, 0x00003522 },
+ { 0x0000e170, 0x00003558 },
+ { 0x0000e174, 0x00003590 },
+ { 0x0000e178, 0x000035ca },
+ { 0x0000e17c, 0x00003602 },
+ { 0x0000e180, 0x00003621 },
+ { 0x0000e184, 0x00003641 },
+ { 0x0000e188, 0x00003662 },
+ { 0x0000e18c, 0x00003683 },
+ { 0x0000e190, 0x000036a6 },
+ { 0x0000e194, 0x000036ca },
+ { 0x0000e198, 0x000036ef },
+ { 0x0000e19c, 0x00003715 },
+ { 0x0000e1a0, 0x0000373b },
+ { 0x0000e1a4, 0x00003763 },
+ { 0x0000e1a8, 0x0000378c },
+ { 0x0000e1ac, 0x000037b6 },
+ { 0x0000e1b0, 0x000037e1 },
+ { 0x0000e1b4, 0x00003806 },
+ { 0x0000e1b8, 0x0000381d },
+ { 0x0000e1bc, 0x00003834 },
+ { 0x0000e1c0, 0x0000384b },
+ { 0x0000e1c4, 0x00003864 },
+ { 0x0000e1c8, 0x0000387c },
+ { 0x0000e1cc, 0x00003895 },
+ { 0x0000e1d0, 0x000038af },
+ { 0x0000e1d4, 0x000038c9 },
+ { 0x0000e1d8, 0x000038e4 },
+ { 0x0000e1dc, 0x00003900 },
+ { 0x0000e1e0, 0x0000391c },
+ { 0x0000e1e4, 0x00003938 },
+ { 0x0000e1e8, 0x00003955 },
+ { 0x0000e1ec, 0x00003973 },
+ { 0x0000e1f0, 0x00003991 },
+ { 0x0000e1f4, 0x000039af },
+ { 0x0000e1f8, 0x000039cf },
+ { 0x0000e1fc, 0x000039ee },
+ { 0x0000e200, 0x000024aa },
+ { 0x0000e204, 0x00002871 },
+ { 0x0000e208, 0x00002a1c },
+ { 0x0000e20c, 0x00002aff },
+ { 0x0000e210, 0x00002be3 },
+ { 0x0000e214, 0x00002c63 },
+ { 0x0000e218, 0x00002cd5 },
+ { 0x0000e21c, 0x00002d47 },
+ { 0x0000e220, 0x00002db8 },
+ { 0x0000e224, 0x00002e15 },
+ { 0x0000e228, 0x00002e4c },
+ { 0x0000e22c, 0x00002e86 },
+ { 0x0000e230, 0x00002ec4 },
+ { 0x0000e234, 0x00002f04 },
+ { 0x0000e238, 0x00002f47 },
+ { 0x0000e23c, 0x00002f8e },
+ { 0x0000e240, 0x00002fd8 },
+ { 0x0000e244, 0x00003012 },
+ { 0x0000e248, 0x0000303a },
+ { 0x0000e24c, 0x00003064 },
+ { 0x0000e250, 0x0000308f },
+ { 0x0000e254, 0x000030bc },
+ { 0x0000e258, 0x000030eb },
+ { 0x0000e25c, 0x0000311b },
+ { 0x0000e260, 0x0000314d },
+ { 0x0000e264, 0x00003180 },
+ { 0x0000e268, 0x000031b5 },
+ { 0x0000e26c, 0x000031ec },
+ { 0x0000e270, 0x00003212 },
+ { 0x0000e274, 0x0000322f },
+ { 0x0000e278, 0x0000324d },
+ { 0x0000e27c, 0x0000326c },
+ { 0x0000e280, 0x0000328c },
+ { 0x0000e284, 0x000032ad },
+ { 0x0000e288, 0x000032ce },
+ { 0x0000e28c, 0x000032f1 },
+ { 0x0000e290, 0x00003314 },
+ { 0x0000e294, 0x00003338 },
+ { 0x0000e298, 0x0000335d },
+ { 0x0000e29c, 0x00003383 },
+ { 0x0000e2a0, 0x000033aa },
+ { 0x0000e2a4, 0x000033d2 },
+ { 0x0000e2a8, 0x000033fb },
+ { 0x0000e2ac, 0x00003412 },
+ { 0x0000e2b0, 0x00003427 },
+ { 0x0000e2b4, 0x0000343d },
+ { 0x0000e2b8, 0x00003453 },
+ { 0x0000e2bc, 0x0000346a },
+ { 0x0000e2c0, 0x00003481 },
+ { 0x0000e2c4, 0x00003498 },
+ { 0x0000e2c8, 0x000034b0 },
+ { 0x0000e2cc, 0x000034c9 },
+ { 0x0000e2d0, 0x000034e2 },
+ { 0x0000e2d4, 0x000034fb },
+ { 0x0000e2d8, 0x00003515 },
+ { 0x0000e2dc, 0x00003530 },
+ { 0x0000e2e0, 0x0000354b },
+ { 0x0000e2e4, 0x00003566 },
+ { 0x0000e2e8, 0x00003582 },
+ { 0x0000e2ec, 0x0000359e },
+ { 0x0000e2f0, 0x000035bb },
+ { 0x0000e2f4, 0x000035d8 },
+ { 0x0000e2f8, 0x000035f6 },
+ { 0x0000e2fc, 0x0000360a },
+ { 0x0000e300, 0x00003619 },
+ { 0x0000e304, 0x00003629 },
+ { 0x0000e308, 0x00003639 },
+ { 0x0000e30c, 0x00003649 },
+ { 0x0000e310, 0x00003659 },
+ { 0x0000e314, 0x0000366a },
+ { 0x0000e318, 0x0000367b },
+ { 0x0000e31c, 0x0000368c },
+ { 0x0000e320, 0x0000369d },
+ { 0x0000e324, 0x000036af },
+ { 0x0000e328, 0x000036c1 },
+ { 0x0000e32c, 0x000036d3 },
+ { 0x0000e330, 0x000036e6 },
+ { 0x0000e334, 0x000036f8 },
+ { 0x0000e338, 0x0000370b },
+ { 0x0000e33c, 0x0000371e },
+ { 0x0000e340, 0x00003732 },
+ { 0x0000e344, 0x00003745 },
+ { 0x0000e348, 0x00003759 },
+ { 0x0000e34c, 0x0000376d },
+ { 0x0000e350, 0x00003782 },
+ { 0x0000e354, 0x00003797 },
+ { 0x0000e358, 0x000037ac },
+ { 0x0000e35c, 0x000037c1 },
+ { 0x0000e360, 0x000037d6 },
+ { 0x0000e364, 0x000037ec },
+ { 0x0000e368, 0x00003801 },
+ { 0x0000e36c, 0x0000380c },
+ { 0x0000e370, 0x00003817 },
+ { 0x0000e374, 0x00003823 },
+ { 0x0000e378, 0x0000382e },
+ { 0x0000e37c, 0x0000383a },
+ { 0x0000e380, 0x00003846 },
+ { 0x0000e384, 0x00003851 },
+ { 0x0000e388, 0x0000385e },
+ { 0x0000e38c, 0x0000386a },
+ { 0x0000e390, 0x00003876 },
+ { 0x0000e394, 0x00003883 },
+ { 0x0000e398, 0x0000388f },
+ { 0x0000e39c, 0x0000389c },
+ { 0x0000e3a0, 0x000038a9 },
+ { 0x0000e3a4, 0x000038b6 },
+ { 0x0000e3a8, 0x000038c3 },
+ { 0x0000e3ac, 0x000038d0 },
+ { 0x0000e3b0, 0x000038de },
+ { 0x0000e3b4, 0x000038eb },
+ { 0x0000e3b8, 0x000038f9 },
+ { 0x0000e3bc, 0x00003907 },
+ { 0x0000e3c0, 0x00003915 },
+ { 0x0000e3c4, 0x00003923 },
+ { 0x0000e3c8, 0x00003931 },
+ { 0x0000e3cc, 0x0000393f },
+ { 0x0000e3d0, 0x0000394e },
+ { 0x0000e3d4, 0x0000395c },
+ { 0x0000e3d8, 0x0000396b },
+ { 0x0000e3dc, 0x0000397a },
+ { 0x0000e3e0, 0x00003989 },
+ { 0x0000e3e4, 0x00003998 },
+ { 0x0000e3e8, 0x000039a8 },
+ { 0x0000e3ec, 0x000039b7 },
+ { 0x0000e3f0, 0x000039c7 },
+ { 0x0000e3f4, 0x000039d6 },
+ { 0x0000e3f8, 0x000039e6 },
+ { 0x0000e3fc, 0x000039f6 },
+ { 0x0000e400, 0x0000218e },
+ { 0x0000e404, 0x00002638 },
+ { 0x0000e408, 0x000027ff },
+ { 0x0000e40c, 0x000028e3 },
+ { 0x0000e410, 0x000029c7 },
+ { 0x0000e414, 0x00002a55 },
+ { 0x0000e418, 0x00002ac7 },
+ { 0x0000e41c, 0x00002b38 },
+ { 0x0000e420, 0x00002baa },
+ { 0x0000e424, 0x00002c0e },
+ { 0x0000e428, 0x00002c47 },
+ { 0x0000e42c, 0x00002c7f },
+ { 0x0000e430, 0x00002cb8 },
+ { 0x0000e434, 0x00002cf1 },
+ { 0x0000e438, 0x00002d2a },
+ { 0x0000e43c, 0x00002d63 },
+ { 0x0000e440, 0x00002d9c },
+ { 0x0000e444, 0x00002dd5 },
+ { 0x0000e448, 0x00002e07 },
+ { 0x0000e44c, 0x00002e23 },
+ { 0x0000e450, 0x00002e3f },
+ { 0x0000e454, 0x00002e5a },
+ { 0x0000e458, 0x00002e77 },
+ { 0x0000e45c, 0x00002e95 },
+ { 0x0000e460, 0x00002eb4 },
+ { 0x0000e464, 0x00002ed3 },
+ { 0x0000e468, 0x00002ef4 },
+ { 0x0000e46c, 0x00002f14 },
+ { 0x0000e470, 0x00002f36 },
+ { 0x0000e474, 0x00002f59 },
+ { 0x0000e478, 0x00002f7c },
+ { 0x0000e47c, 0x00002fa0 },
+ { 0x0000e480, 0x00002fc5 },
+ { 0x0000e484, 0x00002feb },
+ { 0x0000e488, 0x00003008 },
+ { 0x0000e48c, 0x0000301c },
+ { 0x0000e490, 0x00003030 },
+ { 0x0000e494, 0x00003044 },
+ { 0x0000e498, 0x00003059 },
+ { 0x0000e49c, 0x0000306e },
+ { 0x0000e4a0, 0x00003084 },
+ { 0x0000e4a4, 0x0000309a },
+ { 0x0000e4a8, 0x000030b1 },
+ { 0x0000e4ac, 0x000030c7 },
+ { 0x0000e4b0, 0x000030df },
+ { 0x0000e4b4, 0x000030f6 },
+ { 0x0000e4b8, 0x0000310f },
+ { 0x0000e4bc, 0x00003127 },
+ { 0x0000e4c0, 0x00003140 },
+ { 0x0000e4c4, 0x00003159 },
+ { 0x0000e4c8, 0x00003173 },
+ { 0x0000e4cc, 0x0000318d },
+ { 0x0000e4d0, 0x000031a8 },
+ { 0x0000e4d4, 0x000031c3 },
+ { 0x0000e4d8, 0x000031de },
+ { 0x0000e4dc, 0x000031fa },
+ { 0x0000e4e0, 0x0000320b },
+ { 0x0000e4e4, 0x00003219 },
+ { 0x0000e4e8, 0x00003228 },
+ { 0x0000e4ec, 0x00003237 },
+ { 0x0000e4f0, 0x00003246 },
+ { 0x0000e4f4, 0x00003255 },
+ { 0x0000e4f8, 0x00003265 },
+ { 0x0000e4fc, 0x00003274 },
+ { 0x0000e500, 0x00003284 },
+ { 0x0000e504, 0x00003294 },
+ { 0x0000e508, 0x000032a5 },
+ { 0x0000e50c, 0x000032b5 },
+ { 0x0000e510, 0x000032c6 },
+ { 0x0000e514, 0x000032d7 },
+ { 0x0000e518, 0x000032e8 },
+ { 0x0000e51c, 0x000032f9 },
+ { 0x0000e520, 0x0000330b },
+ { 0x0000e524, 0x0000331d },
+ { 0x0000e528, 0x0000332f },
+ { 0x0000e52c, 0x00003341 },
+ { 0x0000e530, 0x00003354 },
+ { 0x0000e534, 0x00003367 },
+ { 0x0000e538, 0x0000337a },
+ { 0x0000e53c, 0x0000338d },
+ { 0x0000e540, 0x000033a0 },
+ { 0x0000e544, 0x000033b4 },
+ { 0x0000e548, 0x000033c8 },
+ { 0x0000e54c, 0x000033dc },
+ { 0x0000e550, 0x000033f0 },
+ { 0x0000e554, 0x00003402 },
+ { 0x0000e558, 0x0000340d },
+ { 0x0000e55c, 0x00003417 },
+ { 0x0000e560, 0x00003422 },
+ { 0x0000e564, 0x0000342c },
+ { 0x0000e568, 0x00003437 },
+ { 0x0000e56c, 0x00003442 },
+ { 0x0000e570, 0x0000344d },
+ { 0x0000e574, 0x00003459 },
+ { 0x0000e578, 0x00003464 },
+ { 0x0000e57c, 0x0000346f },
+ { 0x0000e580, 0x0000347b },
+ { 0x0000e584, 0x00003487 },
+ { 0x0000e588, 0x00003492 },
+ { 0x0000e58c, 0x0000349e },
+ { 0x0000e590, 0x000034aa },
+ { 0x0000e594, 0x000034b6 },
+ { 0x0000e598, 0x000034c3 },
+ { 0x0000e59c, 0x000034cf },
+ { 0x0000e5a0, 0x000034dc },
+ { 0x0000e5a4, 0x000034e8 },
+ { 0x0000e5a8, 0x000034f5 },
+ { 0x0000e5ac, 0x00003502 },
+ { 0x0000e5b0, 0x0000350f },
+ { 0x0000e5b4, 0x0000351c },
+ { 0x0000e5b8, 0x00003529 },
+ { 0x0000e5bc, 0x00003536 },
+ { 0x0000e5c0, 0x00003544 },
+ { 0x0000e5c4, 0x00003551 },
+ { 0x0000e5c8, 0x0000355f },
+ { 0x0000e5cc, 0x0000356d },
+ { 0x0000e5d0, 0x0000357b },
+ { 0x0000e5d4, 0x00003589 },
+ { 0x0000e5d8, 0x00003597 },
+ { 0x0000e5dc, 0x000035a5 },
+ { 0x0000e5e0, 0x000035b4 },
+ { 0x0000e5e4, 0x000035c2 },
+ { 0x0000e5e8, 0x000035d1 },
+ { 0x0000e5ec, 0x000035e0 },
+ { 0x0000e5f0, 0x000035ef },
+ { 0x0000e5f4, 0x000035fe },
+ { 0x0000e5f8, 0x00003606 },
+ { 0x0000e5fc, 0x0000360e },
+ { 0x0000e600, 0x00003616 },
+ { 0x0000e604, 0x0000361d },
+ { 0x0000e608, 0x00003625 },
+ { 0x0000e60c, 0x0000362d },
+ { 0x0000e610, 0x00003635 },
+ { 0x0000e614, 0x0000363d },
+ { 0x0000e618, 0x00003645 },
+ { 0x0000e61c, 0x0000364d },
+ { 0x0000e620, 0x00003655 },
+ { 0x0000e624, 0x0000365e },
+ { 0x0000e628, 0x00003666 },
+ { 0x0000e62c, 0x0000366e },
+ { 0x0000e630, 0x00003677 },
+ { 0x0000e634, 0x0000367f },
+ { 0x0000e638, 0x00003688 },
+ { 0x0000e63c, 0x00003690 },
+ { 0x0000e640, 0x00003699 },
+ { 0x0000e644, 0x000036a2 },
+ { 0x0000e648, 0x000036ab },
+ { 0x0000e64c, 0x000036b4 },
+ { 0x0000e650, 0x000036bc },
+ { 0x0000e654, 0x000036c5 },
+ { 0x0000e658, 0x000036cf },
+ { 0x0000e65c, 0x000036d8 },
+ { 0x0000e660, 0x000036e1 },
+ { 0x0000e664, 0x000036ea },
+ { 0x0000e668, 0x000036f3 },
+ { 0x0000e66c, 0x000036fd },
+ { 0x0000e670, 0x00003706 },
+ { 0x0000e674, 0x00003710 },
+ { 0x0000e678, 0x00003719 },
+ { 0x0000e67c, 0x00003723 },
+ { 0x0000e680, 0x0000372d },
+ { 0x0000e684, 0x00003737 },
+ { 0x0000e688, 0x00003740 },
+ { 0x0000e68c, 0x0000374a },
+ { 0x0000e690, 0x00003754 },
+ { 0x0000e694, 0x0000375e },
+ { 0x0000e698, 0x00003768 },
+ { 0x0000e69c, 0x00003772 },
+ { 0x0000e6a0, 0x0000377d },
+ { 0x0000e6a4, 0x00003787 },
+ { 0x0000e6a8, 0x00003791 },
+ { 0x0000e6ac, 0x0000379c },
+ { 0x0000e6b0, 0x000037a6 },
+ { 0x0000e6b4, 0x000037b1 },
+ { 0x0000e6b8, 0x000037bb },
+ { 0x0000e6bc, 0x000037c6 },
+ { 0x0000e6c0, 0x000037d1 },
+ { 0x0000e6c4, 0x000037dc },
+ { 0x0000e6c8, 0x000037e7 },
+ { 0x0000e6cc, 0x000037f1 },
+ { 0x0000e6d0, 0x000037fc },
+ { 0x0000e6d4, 0x00003804 },
+ { 0x0000e6d8, 0x00003809 },
+ { 0x0000e6dc, 0x0000380f },
+ { 0x0000e6e0, 0x00003814 },
+ { 0x0000e6e4, 0x0000381a },
+ { 0x0000e6e8, 0x00003820 },
+ { 0x0000e6ec, 0x00003825 },
+ { 0x0000e6f0, 0x0000382b },
+ { 0x0000e6f4, 0x00003831 },
+ { 0x0000e6f8, 0x00003837 },
+ { 0x0000e6fc, 0x0000383d },
+ { 0x0000e700, 0x00003843 },
+ { 0x0000e704, 0x00003848 },
+ { 0x0000e708, 0x0000384e },
+ { 0x0000e70c, 0x00003854 },
+ { 0x0000e710, 0x0000385a },
+ { 0x0000e714, 0x00003861 },
+ { 0x0000e718, 0x00003867 },
+ { 0x0000e71c, 0x0000386d },
+ { 0x0000e720, 0x00003873 },
+ { 0x0000e724, 0x00003879 },
+ { 0x0000e728, 0x0000387f },
+ { 0x0000e72c, 0x00003886 },
+ { 0x0000e730, 0x0000388c },
+ { 0x0000e734, 0x00003892 },
+ { 0x0000e738, 0x00003899 },
+ { 0x0000e73c, 0x0000389f },
+ { 0x0000e740, 0x000038a5 },
+ { 0x0000e744, 0x000038ac },
+ { 0x0000e748, 0x000038b2 },
+ { 0x0000e74c, 0x000038b9 },
+ { 0x0000e750, 0x000038c0 },
+ { 0x0000e754, 0x000038c6 },
+ { 0x0000e758, 0x000038cd },
+ { 0x0000e75c, 0x000038d3 },
+ { 0x0000e760, 0x000038da },
+ { 0x0000e764, 0x000038e1 },
+ { 0x0000e768, 0x000038e8 },
+ { 0x0000e76c, 0x000038ee },
+ { 0x0000e770, 0x000038f5 },
+ { 0x0000e774, 0x000038fc },
+ { 0x0000e778, 0x00003903 },
+ { 0x0000e77c, 0x0000390a },
+ { 0x0000e780, 0x00003911 },
+ { 0x0000e784, 0x00003918 },
+ { 0x0000e788, 0x0000391f },
+ { 0x0000e78c, 0x00003926 },
+ { 0x0000e790, 0x0000392d },
+ { 0x0000e794, 0x00003934 },
+ { 0x0000e798, 0x0000393c },
+ { 0x0000e79c, 0x00003943 },
+ { 0x0000e7a0, 0x0000394a },
+ { 0x0000e7a4, 0x00003951 },
+ { 0x0000e7a8, 0x00003959 },
+ { 0x0000e7ac, 0x00003960 },
+ { 0x0000e7b0, 0x00003967 },
+ { 0x0000e7b4, 0x0000396f },
+ { 0x0000e7b8, 0x00003976 },
+ { 0x0000e7bc, 0x0000397e },
+ { 0x0000e7c0, 0x00003985 },
+ { 0x0000e7c4, 0x0000398d },
+ { 0x0000e7c8, 0x00003995 },
+ { 0x0000e7cc, 0x0000399c },
+ { 0x0000e7d0, 0x000039a4 },
+ { 0x0000e7d4, 0x000039ac },
+ { 0x0000e7d8, 0x000039b3 },
+ { 0x0000e7dc, 0x000039bb },
+ { 0x0000e7e0, 0x000039c3 },
+ { 0x0000e7e4, 0x000039cb },
+ { 0x0000e7e8, 0x000039d3 },
+ { 0x0000e7ec, 0x000039da },
+ { 0x0000e7f0, 0x000039e2 },
+ { 0x0000e7f4, 0x000039ea },
+ { 0x0000e7f8, 0x000039f2 },
+ { 0x0000e7fc, 0x000039fa },
+ { 0x0000e800, 0x00000000 },
+ { 0x0000e804, 0x0000238e },
+ { 0x0000e808, 0x0000258e },
+ { 0x0000e80c, 0x000026aa },
+ { 0x0000e810, 0x0000278e },
+ { 0x0000e814, 0x00002838 },
+ { 0x0000e818, 0x000028aa },
+ { 0x0000e81c, 0x0000291c },
+ { 0x0000e820, 0x0000298e },
+ { 0x0000e824, 0x000029ff },
+ { 0x0000e828, 0x00002a38 },
+ { 0x0000e82c, 0x00002a71 },
+ { 0x0000e830, 0x00002aaa },
+ { 0x0000e834, 0x00002ae3 },
+ { 0x0000e838, 0x00002b1c },
+ { 0x0000e83c, 0x00002b55 },
+ { 0x0000e840, 0x00002b8e },
+ { 0x0000e844, 0x00002bc7 },
+ { 0x0000e848, 0x00002bff },
+ { 0x0000e84c, 0x00002c1c },
+ { 0x0000e850, 0x00002c38 },
+ { 0x0000e854, 0x00002c55 },
+ { 0x0000e858, 0x00002c71 },
+ { 0x0000e85c, 0x00002c8e },
+ { 0x0000e860, 0x00002caa },
+ { 0x0000e864, 0x00002cc7 },
+ { 0x0000e868, 0x00002ce3 },
+ { 0x0000e86c, 0x00002cff },
+ { 0x0000e870, 0x00002d1c },
+ { 0x0000e874, 0x00002d38 },
+ { 0x0000e878, 0x00002d55 },
+ { 0x0000e87c, 0x00002d71 },
+ { 0x0000e880, 0x00002d8e },
+ { 0x0000e884, 0x00002daa },
+ { 0x0000e888, 0x00002dc7 },
+ { 0x0000e88c, 0x00002de3 },
+ { 0x0000e890, 0x00002dff },
+ { 0x0000e894, 0x00002e0e },
+ { 0x0000e898, 0x00002e1c },
+ { 0x0000e89c, 0x00002e2a },
+ { 0x0000e8a0, 0x00002e38 },
+ { 0x0000e8a4, 0x00002e47 },
+ { 0x0000e8a8, 0x00002e53 },
+ { 0x0000e8ac, 0x00002e61 },
+ { 0x0000e8b0, 0x00002e70 },
+ { 0x0000e8b4, 0x00002e7f },
+ { 0x0000e8b8, 0x00002e8e },
+ { 0x0000e8bc, 0x00002e9d },
+ { 0x0000e8c0, 0x00002eac },
+ { 0x0000e8c4, 0x00002ebc },
+ { 0x0000e8c8, 0x00002ecb },
+ { 0x0000e8cc, 0x00002edb },
+ { 0x0000e8d0, 0x00002eeb },
+ { 0x0000e8d4, 0x00002efc },
+ { 0x0000e8d8, 0x00002f0c },
+ { 0x0000e8dc, 0x00002f1d },
+ { 0x0000e8e0, 0x00002f2e },
+ { 0x0000e8e4, 0x00002f3f },
+ { 0x0000e8e8, 0x00002f50 },
+ { 0x0000e8ec, 0x00002f61 },
+ { 0x0000e8f0, 0x00002f73 },
+ { 0x0000e8f4, 0x00002f85 },
+ { 0x0000e8f8, 0x00002f97 },
+ { 0x0000e8fc, 0x00002fa9 },
+ { 0x0000e900, 0x00002fbc },
+ { 0x0000e904, 0x00002fce },
+ { 0x0000e908, 0x00002fe1 },
+ { 0x0000e90c, 0x00002ff4 },
+ { 0x0000e910, 0x00003003 },
+ { 0x0000e914, 0x0000300d },
+ { 0x0000e918, 0x00003017 },
+ { 0x0000e91c, 0x00003021 },
+ { 0x0000e920, 0x0000302b },
+ { 0x0000e924, 0x00003035 },
+ { 0x0000e928, 0x0000303f },
+ { 0x0000e92c, 0x0000304a },
+ { 0x0000e930, 0x00003054 },
+ { 0x0000e934, 0x0000305f },
+ { 0x0000e938, 0x00003069 },
+ { 0x0000e93c, 0x00003074 },
+ { 0x0000e940, 0x0000307f },
+ { 0x0000e944, 0x0000308a },
+ { 0x0000e948, 0x00003095 },
+ { 0x0000e94c, 0x000030a0 },
+ { 0x0000e950, 0x000030ab },
+ { 0x0000e954, 0x000030b6 },
+ { 0x0000e958, 0x000030c2 },
+ { 0x0000e95c, 0x000030cd },
+ { 0x0000e960, 0x000030d9 },
+ { 0x0000e964, 0x000030e5 },
+ { 0x0000e968, 0x000030f1 },
+ { 0x0000e96c, 0x000030fc },
+ { 0x0000e970, 0x00003109 },
+ { 0x0000e974, 0x00003115 },
+ { 0x0000e978, 0x00003121 },
+ { 0x0000e97c, 0x0000312d },
+ { 0x0000e980, 0x0000313a },
+ { 0x0000e984, 0x00003146 },
+ { 0x0000e988, 0x00003153 },
+ { 0x0000e98c, 0x00003160 },
+ { 0x0000e990, 0x0000316d },
+ { 0x0000e994, 0x0000317a },
+ { 0x0000e998, 0x00003187 },
+ { 0x0000e99c, 0x00003194 },
+ { 0x0000e9a0, 0x000031a1 },
+ { 0x0000e9a4, 0x000031af },
+ { 0x0000e9a8, 0x000031bc },
+ { 0x0000e9ac, 0x000031ca },
+ { 0x0000e9b0, 0x000031d8 },
+ { 0x0000e9b4, 0x000031e5 },
+ { 0x0000e9b8, 0x000031f3 },
+ { 0x0000e9bc, 0x00003200 },
+ { 0x0000e9c0, 0x00003208 },
+ { 0x0000e9c4, 0x0000320f },
+ { 0x0000e9c8, 0x00003216 },
+ { 0x0000e9cc, 0x0000321d },
+ { 0x0000e9d0, 0x00003224 },
+ { 0x0000e9d4, 0x0000322c },
+ { 0x0000e9d8, 0x00003233 },
+ { 0x0000e9dc, 0x0000323b },
+ { 0x0000e9e0, 0x00003242 },
+ { 0x0000e9e4, 0x0000324a },
+ { 0x0000e9e8, 0x00003251 },
+ { 0x0000e9ec, 0x00003259 },
+ { 0x0000e9f0, 0x00003261 },
+ { 0x0000e9f4, 0x00003268 },
+ { 0x0000e9f8, 0x00003270 },
+ { 0x0000e9fc, 0x00003278 },
+ { 0x0000ea00, 0x00003280 },
+ { 0x0000ea04, 0x00003288 },
+ { 0x0000ea08, 0x00003290 },
+ { 0x0000ea0c, 0x00003298 },
+ { 0x0000ea10, 0x000032a0 },
+ { 0x0000ea14, 0x000032a9 },
+ { 0x0000ea18, 0x000032b1 },
+ { 0x0000ea1c, 0x000032b9 },
+ { 0x0000ea20, 0x000032c2 },
+ { 0x0000ea24, 0x000032ca },
+ { 0x0000ea28, 0x000032d3 },
+ { 0x0000ea2c, 0x000032db },
+ { 0x0000ea30, 0x000032e4 },
+ { 0x0000ea34, 0x000032ec },
+ { 0x0000ea38, 0x000032f5 },
+ { 0x0000ea3c, 0x000032fe },
+ { 0x0000ea40, 0x00003307 },
+ { 0x0000ea44, 0x00003310 },
+ { 0x0000ea48, 0x00003318 },
+ { 0x0000ea4c, 0x00003321 },
+ { 0x0000ea50, 0x0000332a },
+ { 0x0000ea54, 0x00003334 },
+ { 0x0000ea58, 0x0000333d },
+ { 0x0000ea5c, 0x00003346 },
+ { 0x0000ea60, 0x0000334f },
+ { 0x0000ea64, 0x00003359 },
+ { 0x0000ea68, 0x00003362 },
+ { 0x0000ea6c, 0x0000336b },
+ { 0x0000ea70, 0x00003375 },
+ { 0x0000ea74, 0x0000337e },
+ { 0x0000ea78, 0x00003388 },
+ { 0x0000ea7c, 0x00003392 },
+ { 0x0000ea80, 0x0000339b },
+ { 0x0000ea84, 0x000033a5 },
+ { 0x0000ea88, 0x000033af },
+ { 0x0000ea8c, 0x000033b9 },
+ { 0x0000ea90, 0x000033c3 },
+ { 0x0000ea94, 0x000033cd },
+ { 0x0000ea98, 0x000033d7 },
+ { 0x0000ea9c, 0x000033e1 },
+ { 0x0000eaa0, 0x000033eb },
+ { 0x0000eaa4, 0x000033f5 },
+ { 0x0000eaa8, 0x00003400 },
+ { 0x0000eaac, 0x00003405 },
+ { 0x0000eab0, 0x0000340a },
+ { 0x0000eab4, 0x0000340f },
+ { 0x0000eab8, 0x00003414 },
+ { 0x0000eabc, 0x0000341a },
+ { 0x0000eac0, 0x0000341f },
+ { 0x0000eac4, 0x00003424 },
+ { 0x0000eac8, 0x0000342a },
+ { 0x0000eacc, 0x0000342f },
+ { 0x0000ead0, 0x00003435 },
+ { 0x0000ead4, 0x0000343a },
+ { 0x0000ead8, 0x00003440 },
+ { 0x0000eadc, 0x00003445 },
+ { 0x0000eae0, 0x0000344b },
+ { 0x0000eae4, 0x00003450 },
+ { 0x0000eae8, 0x00003456 },
+ { 0x0000eaec, 0x0000345b },
+ { 0x0000eaf0, 0x00003461 },
+ { 0x0000eaf4, 0x00003467 },
+ { 0x0000eaf8, 0x0000346d },
+ { 0x0000eafc, 0x00003472 },
+ { 0x0000eb00, 0x00003478 },
+ { 0x0000eb04, 0x0000347e },
+ { 0x0000eb08, 0x00003484 },
+ { 0x0000eb0c, 0x0000348a },
+ { 0x0000eb10, 0x0000348f },
+ { 0x0000eb14, 0x00003495 },
+ { 0x0000eb18, 0x0000349b },
+ { 0x0000eb1c, 0x000034a1 },
+ { 0x0000eb20, 0x000034a7 },
+ { 0x0000eb24, 0x000034ad },
+ { 0x0000eb28, 0x000034b3 },
+ { 0x0000eb2c, 0x000034ba },
+ { 0x0000eb30, 0x000034c0 },
+ { 0x0000eb34, 0x000034c6 },
+ { 0x0000eb38, 0x000034cc },
+ { 0x0000eb3c, 0x000034d2 },
+ { 0x0000eb40, 0x000034d8 },
+ { 0x0000eb44, 0x000034df },
+ { 0x0000eb48, 0x000034e5 },
+ { 0x0000eb4c, 0x000034eb },
+ { 0x0000eb50, 0x000034f2 },
+ { 0x0000eb54, 0x000034f8 },
+ { 0x0000eb58, 0x000034ff },
+ { 0x0000eb5c, 0x00003505 },
+ { 0x0000eb60, 0x0000350c },
+ { 0x0000eb64, 0x00003512 },
+ { 0x0000eb68, 0x00003519 },
+ { 0x0000eb6c, 0x0000351f },
+ { 0x0000eb70, 0x00003526 },
+ { 0x0000eb74, 0x0000352c },
+ { 0x0000eb78, 0x00003533 },
+ { 0x0000eb7c, 0x0000353a },
+ { 0x0000eb80, 0x00003540 },
+ { 0x0000eb84, 0x00003547 },
+ { 0x0000eb88, 0x0000354e },
+ { 0x0000eb8c, 0x00003555 },
+ { 0x0000eb90, 0x0000355c },
+ { 0x0000eb94, 0x00003563 },
+ { 0x0000eb98, 0x00003569 },
+ { 0x0000eb9c, 0x00003570 },
+ { 0x0000eba0, 0x00003577 },
+ { 0x0000eba4, 0x0000357e },
+ { 0x0000eba8, 0x00003585 },
+ { 0x0000ebac, 0x0000358c },
+ { 0x0000ebb0, 0x00003594 },
+ { 0x0000ebb4, 0x0000359b },
+ { 0x0000ebb8, 0x000035a2 },
+ { 0x0000ebbc, 0x000035a9 },
+ { 0x0000ebc0, 0x000035b0 },
+ { 0x0000ebc4, 0x000035b7 },
+ { 0x0000ebc8, 0x000035bf },
+ { 0x0000ebcc, 0x000035c6 },
+ { 0x0000ebd0, 0x000035cd },
+ { 0x0000ebd4, 0x000035d5 },
+ { 0x0000ebd8, 0x000035dc },
+ { 0x0000ebdc, 0x000035e4 },
+ { 0x0000ebe0, 0x000035eb },
+ { 0x0000ebe4, 0x000035f2 },
+ { 0x0000ebe8, 0x000035fa },
+ { 0x0000ebec, 0x00003600 },
+ { 0x0000ebf0, 0x00003604 },
+ { 0x0000ebf4, 0x00003608 },
+ { 0x0000ebf8, 0x0000360c },
+ { 0x0000ebfc, 0x00003610 },
+ { 0x0000ec00, 0x00003614 },
+ { 0x0000ec04, 0x00003617 },
+ { 0x0000ec08, 0x0000361b },
+ { 0x0000ec0c, 0x0000361f },
+ { 0x0000ec10, 0x00003623 },
+ { 0x0000ec14, 0x00003627 },
+ { 0x0000ec18, 0x0000362b },
+ { 0x0000ec1c, 0x0000362f },
+ { 0x0000ec20, 0x00003633 },
+ { 0x0000ec24, 0x00003637 },
+ { 0x0000ec28, 0x0000363b },
+ { 0x0000ec2c, 0x0000363f },
+ { 0x0000ec30, 0x00003643 },
+ { 0x0000ec34, 0x00003647 },
+ { 0x0000ec38, 0x0000364b },
+ { 0x0000ec3c, 0x0000364f },
+ { 0x0000ec40, 0x00003653 },
+ { 0x0000ec44, 0x00003657 },
+ { 0x0000ec48, 0x0000365b },
+ { 0x0000ec4c, 0x00003660 },
+ { 0x0000ec50, 0x00003664 },
+ { 0x0000ec54, 0x00003668 },
+ { 0x0000ec58, 0x0000366c },
+ { 0x0000ec5c, 0x00003670 },
+ { 0x0000ec60, 0x00003675 },
+ { 0x0000ec64, 0x00003679 },
+ { 0x0000ec68, 0x0000367d },
+ { 0x0000ec6c, 0x00003681 },
+ { 0x0000ec70, 0x00003686 },
+ { 0x0000ec74, 0x0000368a },
+ { 0x0000ec78, 0x0000368e },
+ { 0x0000ec7c, 0x00003693 },
+ { 0x0000ec80, 0x00003697 },
+ { 0x0000ec84, 0x0000369b },
+ { 0x0000ec88, 0x000036a0 },
+ { 0x0000ec8c, 0x000036a4 },
+ { 0x0000ec90, 0x000036a8 },
+ { 0x0000ec94, 0x000036ad },
+ { 0x0000ec98, 0x000036b1 },
+ { 0x0000ec9c, 0x000036b6 },
+ { 0x0000eca0, 0x000036ba },
+ { 0x0000eca4, 0x000036bf },
+ { 0x0000eca8, 0x000036c3 },
+ { 0x0000ecac, 0x000036c8 },
+ { 0x0000ecb0, 0x000036cc },
+ { 0x0000ecb4, 0x000036d1 },
+ { 0x0000ecb8, 0x000036d5 },
+ { 0x0000ecbc, 0x000036da },
+ { 0x0000ecc0, 0x000036df },
+ { 0x0000ecc4, 0x000036e3 },
+ { 0x0000ecc8, 0x000036e8 },
+ { 0x0000eccc, 0x000036ec },
+ { 0x0000ecd0, 0x000036f1 },
+ { 0x0000ecd4, 0x000036f6 },
+ { 0x0000ecd8, 0x000036fb },
+ { 0x0000ecdc, 0x000036ff },
+ { 0x0000ece0, 0x00003704 },
+ { 0x0000ece4, 0x00003709 },
+ { 0x0000ece8, 0x0000370d },
+ { 0x0000ecec, 0x00003712 },
+ { 0x0000ecf0, 0x00003717 },
+ { 0x0000ecf4, 0x0000371c },
+ { 0x0000ecf8, 0x00003721 },
+ { 0x0000ecfc, 0x00003725 },
+ { 0x0000ed00, 0x0000372a },
+ { 0x0000ed04, 0x0000372f },
+ { 0x0000ed08, 0x00003734 },
+ { 0x0000ed0c, 0x00003739 },
+ { 0x0000ed10, 0x0000373e },
+ { 0x0000ed14, 0x00003743 },
+ { 0x0000ed18, 0x00003748 },
+ { 0x0000ed1c, 0x0000374d },
+ { 0x0000ed20, 0x00003752 },
+ { 0x0000ed24, 0x00003757 },
+ { 0x0000ed28, 0x0000375c },
+ { 0x0000ed2c, 0x00003761 },
+ { 0x0000ed30, 0x00003766 },
+ { 0x0000ed34, 0x0000376b },
+ { 0x0000ed38, 0x00003770 },
+ { 0x0000ed3c, 0x00003775 },
+ { 0x0000ed40, 0x0000377a },
+ { 0x0000ed44, 0x0000377f },
+ { 0x0000ed48, 0x00003784 },
+ { 0x0000ed4c, 0x0000378a },
+ { 0x0000ed50, 0x0000378f },
+ { 0x0000ed54, 0x00003794 },
+ { 0x0000ed58, 0x00003799 },
+ { 0x0000ed5c, 0x0000379e },
+ { 0x0000ed60, 0x000037a4 },
+ { 0x0000ed64, 0x000037a9 },
+ { 0x0000ed68, 0x000037ae },
+ { 0x0000ed6c, 0x000037b3 },
+ { 0x0000ed70, 0x000037b9 },
+ { 0x0000ed74, 0x000037be },
+ { 0x0000ed78, 0x000037c3 },
+ { 0x0000ed7c, 0x000037c9 },
+ { 0x0000ed80, 0x000037ce },
+ { 0x0000ed84, 0x000037d4 },
+ { 0x0000ed88, 0x000037d9 },
+ { 0x0000ed8c, 0x000037de },
+ { 0x0000ed90, 0x000037e4 },
+ { 0x0000ed94, 0x000037e9 },
+ { 0x0000ed98, 0x000037ef },
+ { 0x0000ed9c, 0x000037f4 },
+ { 0x0000eda0, 0x000037fa },
+ { 0x0000eda4, 0x000037ff },
+ { 0x0000eda8, 0x00003802 },
+ { 0x0000edac, 0x00003805 },
+ { 0x0000edb0, 0x00003808 },
+ { 0x0000edb4, 0x0000380a },
+ { 0x0000edb8, 0x0000380d },
+ { 0x0000edbc, 0x00003810 },
+ { 0x0000edc0, 0x00003813 },
+ { 0x0000edc4, 0x00003816 },
+ { 0x0000edc8, 0x00003819 },
+ { 0x0000edcc, 0x0000381b },
+ { 0x0000edd0, 0x0000381e },
+ { 0x0000edd4, 0x00003821 },
+ { 0x0000edd8, 0x00003824 },
+ { 0x0000eddc, 0x00003827 },
+ { 0x0000ede0, 0x0000382a },
+ { 0x0000ede4, 0x0000382d },
+ { 0x0000ede8, 0x00003830 },
+ { 0x0000edec, 0x00003832 },
+ { 0x0000edf0, 0x00003835 },
+ { 0x0000edf4, 0x00003838 },
+ { 0x0000edf8, 0x0000383b },
+ { 0x0000edfc, 0x0000383e },
+ { 0x0000ee00, 0x00003841 },
+ { 0x0000ee04, 0x00003844 },
+ { 0x0000ee08, 0x00003847 },
+ { 0x0000ee0c, 0x0000384a },
+ { 0x0000ee10, 0x0000384d },
+ { 0x0000ee14, 0x00003850 },
+ { 0x0000ee18, 0x00003853 },
+ { 0x0000ee1c, 0x00003856 },
+ { 0x0000ee20, 0x00003859 },
+ { 0x0000ee24, 0x0000385c },
+ { 0x0000ee28, 0x0000385f },
+ { 0x0000ee2c, 0x00003862 },
+ { 0x0000ee30, 0x00003865 },
+ { 0x0000ee34, 0x00003868 },
+ { 0x0000ee38, 0x0000386b },
+ { 0x0000ee3c, 0x0000386e },
+ { 0x0000ee40, 0x00003871 },
+ { 0x0000ee44, 0x00003874 },
+ { 0x0000ee48, 0x00003878 },
+ { 0x0000ee4c, 0x0000387b },
+ { 0x0000ee50, 0x0000387e },
+ { 0x0000ee54, 0x00003881 },
+ { 0x0000ee58, 0x00003884 },
+ { 0x0000ee5c, 0x00003887 },
+ { 0x0000ee60, 0x0000388a },
+ { 0x0000ee64, 0x0000388e },
+ { 0x0000ee68, 0x00003891 },
+ { 0x0000ee6c, 0x00003894 },
+ { 0x0000ee70, 0x00003897 },
+ { 0x0000ee74, 0x0000389a },
+ { 0x0000ee78, 0x0000389d },
+ { 0x0000ee7c, 0x000038a1 },
+ { 0x0000ee80, 0x000038a4 },
+ { 0x0000ee84, 0x000038a7 },
+ { 0x0000ee88, 0x000038aa },
+ { 0x0000ee8c, 0x000038ae },
+ { 0x0000ee90, 0x000038b1 },
+ { 0x0000ee94, 0x000038b4 },
+ { 0x0000ee98, 0x000038b7 },
+ { 0x0000ee9c, 0x000038bb },
+ { 0x0000eea0, 0x000038be },
+ { 0x0000eea4, 0x000038c1 },
+ { 0x0000eea8, 0x000038c4 },
+ { 0x0000eeac, 0x000038c8 },
+ { 0x0000eeb0, 0x000038cb },
+ { 0x0000eeb4, 0x000038ce },
+ { 0x0000eeb8, 0x000038d2 },
+ { 0x0000eebc, 0x000038d5 },
+ { 0x0000eec0, 0x000038d8 },
+ { 0x0000eec4, 0x000038dc },
+ { 0x0000eec8, 0x000038df },
+ { 0x0000eecc, 0x000038e3 },
+ { 0x0000eed0, 0x000038e6 },
+ { 0x0000eed4, 0x000038e9 },
+ { 0x0000eed8, 0x000038ed },
+ { 0x0000eedc, 0x000038f0 },
+ { 0x0000eee0, 0x000038f4 },
+ { 0x0000eee4, 0x000038f7 },
+ { 0x0000eee8, 0x000038fa },
+ { 0x0000eeec, 0x000038fe },
+ { 0x0000eef0, 0x00003901 },
+ { 0x0000eef4, 0x00003905 },
+ { 0x0000eef8, 0x00003908 },
+ { 0x0000eefc, 0x0000390c },
+ { 0x0000ef00, 0x0000390f },
+ { 0x0000ef04, 0x00003913 },
+ { 0x0000ef08, 0x00003916 },
+ { 0x0000ef0c, 0x0000391a },
+ { 0x0000ef10, 0x0000391d },
+ { 0x0000ef14, 0x00003921 },
+ { 0x0000ef18, 0x00003924 },
+ { 0x0000ef1c, 0x00003928 },
+ { 0x0000ef20, 0x0000392b },
+ { 0x0000ef24, 0x0000392f },
+ { 0x0000ef28, 0x00003933 },
+ { 0x0000ef2c, 0x00003936 },
+ { 0x0000ef30, 0x0000393a },
+ { 0x0000ef34, 0x0000393d },
+ { 0x0000ef38, 0x00003941 },
+ { 0x0000ef3c, 0x00003945 },
+ { 0x0000ef40, 0x00003948 },
+ { 0x0000ef44, 0x0000394c },
+ { 0x0000ef48, 0x00003950 },
+ { 0x0000ef4c, 0x00003953 },
+ { 0x0000ef50, 0x00003957 },
+ { 0x0000ef54, 0x0000395b },
+ { 0x0000ef58, 0x0000395e },
+ { 0x0000ef5c, 0x00003962 },
+ { 0x0000ef60, 0x00003966 },
+ { 0x0000ef64, 0x00003969 },
+ { 0x0000ef68, 0x0000396d },
+ { 0x0000ef6c, 0x00003971 },
+ { 0x0000ef70, 0x00003974 },
+ { 0x0000ef74, 0x00003978 },
+ { 0x0000ef78, 0x0000397c },
+ { 0x0000ef7c, 0x00003980 },
+ { 0x0000ef80, 0x00003983 },
+ { 0x0000ef84, 0x00003987 },
+ { 0x0000ef88, 0x0000398b },
+ { 0x0000ef8c, 0x0000398f },
+ { 0x0000ef90, 0x00003993 },
+ { 0x0000ef94, 0x00003996 },
+ { 0x0000ef98, 0x0000399a },
+ { 0x0000ef9c, 0x0000399e },
+ { 0x0000efa0, 0x000039a2 },
+ { 0x0000efa4, 0x000039a6 },
+ { 0x0000efa8, 0x000039aa },
+ { 0x0000efac, 0x000039ad },
+ { 0x0000efb0, 0x000039b1 },
+ { 0x0000efb4, 0x000039b5 },
+ { 0x0000efb8, 0x000039b9 },
+ { 0x0000efbc, 0x000039bd },
+ { 0x0000efc0, 0x000039c1 },
+ { 0x0000efc4, 0x000039c5 },
+ { 0x0000efc8, 0x000039c9 },
+ { 0x0000efcc, 0x000039cd },
+ { 0x0000efd0, 0x000039d1 },
+ { 0x0000efd4, 0x000039d5 },
+ { 0x0000efd8, 0x000039d8 },
+ { 0x0000efdc, 0x000039dc },
+ { 0x0000efe0, 0x000039e0 },
+ { 0x0000efe4, 0x000039e4 },
+ { 0x0000efe8, 0x000039e8 },
+ { 0x0000efec, 0x000039ec },
+ { 0x0000eff0, 0x000039f0 },
+ { 0x0000eff4, 0x000039f4 },
+ { 0x0000eff8, 0x000039f8 },
+ { 0x0000effc, 0x000039fc },
+};
+
+struct data_unit hdr10_opipe_csco[] = {
+ { 0x0000f074, 0x0000000c },
+ { 0x0000f000, 0x00000004 },
+};
diff --git a/drivers/video/fbdev/mxc/ldb.c b/drivers/video/fbdev/mxc/ldb.c
new file mode 100644
index 000000000000..1d6c9e08590c
--- /dev/null
+++ b/drivers/video/fbdev/mxc/ldb.c
@@ -0,0 +1,910 @@
+/*
+ * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+#include "mxc_dispdrv.h"
+
+#define DRIVER_NAME "ldb"
+
+#define LDB_BGREF_RMODE_INT (0x1 << 15)
+
+#define LDB_DI1_VS_POL_ACT_LOW (0x1 << 10)
+#define LDB_DI0_VS_POL_ACT_LOW (0x1 << 9)
+
+#define LDB_BIT_MAP_CH1_JEIDA (0x1 << 8)
+#define LDB_BIT_MAP_CH0_JEIDA (0x1 << 6)
+
+#define LDB_DATA_WIDTH_CH1_24 (0x1 << 7)
+#define LDB_DATA_WIDTH_CH0_24 (0x1 << 5)
+
+#define LDB_CH1_MODE_MASK (0x3 << 2)
+#define LDB_CH1_MODE_EN_TO_DI1 (0x3 << 2)
+#define LDB_CH1_MODE_EN_TO_DI0 (0x1 << 2)
+#define LDB_CH0_MODE_MASK (0x3 << 0)
+#define LDB_CH0_MODE_EN_TO_DI1 (0x3 << 0)
+#define LDB_CH0_MODE_EN_TO_DI0 (0x1 << 0)
+
+#define LDB_SPLIT_MODE_EN (0x1 << 4)
+
+#define INVALID_BUS_REG (~0UL)
+
+struct crtc_mux {
+ enum crtc crtc;
+ u32 val;
+};
+
+struct bus_mux {
+ int reg;
+ int shift;
+ int mask;
+ int crtc_mux_num;
+ const struct crtc_mux *crtcs;
+};
+
+struct ldb_info {
+ bool split_cap;
+ bool dual_cap;
+ bool ext_bgref_cap;
+ bool clk_fixup;
+ int ctrl_reg;
+ int bus_mux_num;
+ const struct bus_mux *buses;
+};
+
+struct ldb_data;
+
+struct ldb_chan {
+ struct ldb_data *ldb;
+ struct fb_info *fbi;
+ struct videomode vm;
+ enum crtc crtc;
+ int chno;
+ bool is_used;
+ bool online;
+};
+
+struct ldb_data {
+ struct regmap *regmap;
+ struct device *dev;
+ struct mxc_dispdrv_handle *mddh;
+ struct ldb_chan chan[2];
+ int bus_mux_num;
+ const struct bus_mux *buses;
+ int primary_chno;
+ int ctrl_reg;
+ u32 ctrl;
+ bool spl_mode;
+ bool dual_mode;
+ bool clk_fixup;
+ struct clk *di_clk[4];
+ struct clk *ldb_di_clk[2];
+ struct clk *div_3_5_clk[2];
+ struct clk *div_7_clk[2];
+ struct clk *div_sel_clk[2];
+};
+
+static const struct crtc_mux imx6q_lvds0_crtc_mux[] = {
+ {
+ .crtc = CRTC_IPU1_DI0,
+ .val = IMX6Q_GPR3_LVDS0_MUX_CTL_IPU1_DI0,
+ }, {
+ .crtc = CRTC_IPU1_DI1,
+ .val = IMX6Q_GPR3_LVDS0_MUX_CTL_IPU1_DI1,
+ }, {
+ .crtc = CRTC_IPU2_DI0,
+ .val = IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI0,
+ }, {
+ .crtc = CRTC_IPU2_DI1,
+ .val = IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI1,
+ }
+};
+
+static const struct crtc_mux imx6q_lvds1_crtc_mux[] = {
+ {
+ .crtc = CRTC_IPU1_DI0,
+ .val = IMX6Q_GPR3_LVDS1_MUX_CTL_IPU1_DI0,
+ }, {
+ .crtc = CRTC_IPU1_DI1,
+ .val = IMX6Q_GPR3_LVDS1_MUX_CTL_IPU1_DI1,
+ }, {
+ .crtc = CRTC_IPU2_DI0,
+ .val = IMX6Q_GPR3_LVDS1_MUX_CTL_IPU2_DI0,
+ }, {
+ .crtc = CRTC_IPU2_DI1,
+ .val = IMX6Q_GPR3_LVDS1_MUX_CTL_IPU2_DI1,
+ }
+};
+
+static const struct bus_mux imx6q_ldb_buses[] = {
+ {
+ .reg = IOMUXC_GPR3,
+ .shift = 6,
+ .mask = IMX6Q_GPR3_LVDS0_MUX_CTL_MASK,
+ .crtc_mux_num = ARRAY_SIZE(imx6q_lvds0_crtc_mux),
+ .crtcs = imx6q_lvds0_crtc_mux,
+ }, {
+ .reg = IOMUXC_GPR3,
+ .shift = 8,
+ .mask = IMX6Q_GPR3_LVDS1_MUX_CTL_MASK,
+ .crtc_mux_num = ARRAY_SIZE(imx6q_lvds1_crtc_mux),
+ .crtcs = imx6q_lvds1_crtc_mux,
+ }
+};
+
+static const struct ldb_info imx6q_ldb_info = {
+ .split_cap = true,
+ .dual_cap = true,
+ .ext_bgref_cap = false,
+ .clk_fixup = false,
+ .ctrl_reg = IOMUXC_GPR2,
+ .bus_mux_num = ARRAY_SIZE(imx6q_ldb_buses),
+ .buses = imx6q_ldb_buses,
+};
+
+static const struct ldb_info imx6qp_ldb_info = {
+ .split_cap = true,
+ .dual_cap = true,
+ .ext_bgref_cap = false,
+ .clk_fixup = true,
+ .ctrl_reg = IOMUXC_GPR2,
+ .bus_mux_num = ARRAY_SIZE(imx6q_ldb_buses),
+ .buses = imx6q_ldb_buses,
+};
+
+static const struct crtc_mux imx6dl_lvds0_crtc_mux[] = {
+ {
+ .crtc = CRTC_IPU1_DI0,
+ .val = IMX6DL_GPR3_LVDS0_MUX_CTL_IPU1_DI0,
+ }, {
+ .crtc = CRTC_IPU1_DI1,
+ .val = IMX6DL_GPR3_LVDS0_MUX_CTL_IPU1_DI1,
+ }, {
+ .crtc = CRTC_LCDIF1,
+ .val = IMX6DL_GPR3_LVDS0_MUX_CTL_LCDIF,
+ }
+};
+
+static const struct crtc_mux imx6dl_lvds1_crtc_mux[] = {
+ {
+ .crtc = CRTC_IPU1_DI0,
+ .val = IMX6DL_GPR3_LVDS1_MUX_CTL_IPU1_DI0,
+ }, {
+ .crtc = CRTC_IPU1_DI1,
+ .val = IMX6DL_GPR3_LVDS1_MUX_CTL_IPU1_DI1,
+ }, {
+ .crtc = CRTC_LCDIF1,
+ .val = IMX6DL_GPR3_LVDS1_MUX_CTL_LCDIF,
+ }
+};
+
+static const struct bus_mux imx6dl_ldb_buses[] = {
+ {
+ .reg = IOMUXC_GPR3,
+ .shift = 6,
+ .mask = IMX6DL_GPR3_LVDS0_MUX_CTL_MASK,
+ .crtc_mux_num = ARRAY_SIZE(imx6dl_lvds0_crtc_mux),
+ .crtcs = imx6dl_lvds0_crtc_mux,
+ }, {
+ .reg = IOMUXC_GPR3,
+ .shift = 8,
+ .mask = IMX6DL_GPR3_LVDS1_MUX_CTL_MASK,
+ .crtc_mux_num = ARRAY_SIZE(imx6dl_lvds1_crtc_mux),
+ .crtcs = imx6dl_lvds1_crtc_mux,
+ }
+};
+
+static const struct ldb_info imx6dl_ldb_info = {
+ .split_cap = true,
+ .dual_cap = true,
+ .ext_bgref_cap = false,
+ .clk_fixup = false,
+ .ctrl_reg = IOMUXC_GPR2,
+ .bus_mux_num = ARRAY_SIZE(imx6dl_ldb_buses),
+ .buses = imx6dl_ldb_buses,
+};
+
+static const struct crtc_mux imx6sx_lvds_crtc_mux[] = {
+ {
+ .crtc = CRTC_LCDIF1,
+ .val = IMX6SX_GPR5_DISP_MUX_LDB_CTRL_LCDIF1,
+ }, {
+ .crtc = CRTC_LCDIF2,
+ .val = IMX6SX_GPR5_DISP_MUX_LDB_CTRL_LCDIF2,
+ }
+};
+
+static const struct bus_mux imx6sx_ldb_buses[] = {
+ {
+ .reg = IOMUXC_GPR5,
+ .shift = 3,
+ .mask = IMX6SX_GPR5_DISP_MUX_LDB_CTRL_MASK,
+ .crtc_mux_num = ARRAY_SIZE(imx6sx_lvds_crtc_mux),
+ .crtcs = imx6sx_lvds_crtc_mux,
+ }
+};
+
+static const struct ldb_info imx6sx_ldb_info = {
+ .split_cap = false,
+ .dual_cap = false,
+ .ext_bgref_cap = false,
+ .clk_fixup = false,
+ .ctrl_reg = IOMUXC_GPR6,
+ .bus_mux_num = ARRAY_SIZE(imx6sx_ldb_buses),
+ .buses = imx6sx_ldb_buses,
+};
+
+static const struct crtc_mux imx53_lvds0_crtc_mux[] = {
+ { .crtc = CRTC_IPU1_DI0, },
+};
+
+static const struct crtc_mux imx53_lvds1_crtc_mux[] = {
+ { .crtc = CRTC_IPU1_DI1, }
+};
+
+static const struct bus_mux imx53_ldb_buses[] = {
+ {
+ .reg = INVALID_BUS_REG,
+ .crtc_mux_num = ARRAY_SIZE(imx53_lvds0_crtc_mux),
+ .crtcs = imx53_lvds0_crtc_mux,
+ }, {
+ .reg = INVALID_BUS_REG,
+ .crtc_mux_num = ARRAY_SIZE(imx53_lvds1_crtc_mux),
+ .crtcs = imx53_lvds1_crtc_mux,
+ }
+};
+
+static const struct ldb_info imx53_ldb_info = {
+ .split_cap = true,
+ .dual_cap = false,
+ .ext_bgref_cap = true,
+ .clk_fixup = false,
+ .ctrl_reg = IOMUXC_GPR2,
+ .bus_mux_num = ARRAY_SIZE(imx53_ldb_buses),
+ .buses = imx53_ldb_buses,
+};
+
+static const struct of_device_id ldb_dt_ids[] = {
+ { .compatible = "fsl,imx6qp-ldb", .data = &imx6qp_ldb_info, },
+ { .compatible = "fsl,imx6q-ldb", .data = &imx6q_ldb_info, },
+ { .compatible = "fsl,imx6dl-ldb", .data = &imx6dl_ldb_info, },
+ { .compatible = "fsl,imx6sx-ldb", .data = &imx6sx_ldb_info, },
+ { .compatible = "fsl,imx53-ldb", .data = &imx53_ldb_info, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ldb_dt_ids);
+
+static int ldb_init(struct mxc_dispdrv_handle *mddh,
+ struct mxc_dispdrv_setting *setting)
+{
+ struct ldb_data *ldb = mxc_dispdrv_getdata(mddh);
+ struct device *dev = ldb->dev;
+ struct fb_info *fbi = setting->fbi;
+ struct ldb_chan *chan;
+ struct fb_videomode fb_vm;
+ int chno;
+
+ chno = ldb->chan[ldb->primary_chno].is_used ?
+ !ldb->primary_chno : ldb->primary_chno;
+
+ chan = &ldb->chan[chno];
+
+ if (chan->is_used) {
+ dev_err(dev, "LVDS channel%d is already used\n", chno);
+ return -EBUSY;
+ }
+ if (!chan->online) {
+ dev_err(dev, "LVDS channel%d is not online\n", chno);
+ return -ENODEV;
+ }
+
+ chan->is_used = true;
+
+ chan->fbi = fbi;
+
+ fb_videomode_from_videomode(&chan->vm, &fb_vm);
+ fb_videomode_to_var(&fbi->var, &fb_vm);
+
+ setting->crtc = chan->crtc;
+
+ return 0;
+}
+
+static int get_di_clk_id(struct ldb_chan chan, int *id)
+{
+ struct ldb_data *ldb = chan.ldb;
+ int i = 0, chno = chan.chno, mask, shift;
+ enum crtc crtc;
+ u32 val;
+
+ /* no pre-muxing, such as mx53 */
+ if (ldb->buses[chno].reg == INVALID_BUS_REG) {
+ *id = chno;
+ return 0;
+ }
+
+ for (; i < ldb->buses[chno].crtc_mux_num; i++) {
+ crtc = ldb->buses[chno].crtcs[i].crtc;
+ val = ldb->buses[chno].crtcs[i].val;
+ mask = ldb->buses[chno].mask;
+ shift = ldb->buses[chno].shift;
+ if (chan.crtc == crtc) {
+ *id = (val & mask) >> shift;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int get_mux_val(struct bus_mux bus_mux, enum crtc crtc,
+ u32 *mux_val)
+{
+ int i = 0;
+
+ for (; i < bus_mux.crtc_mux_num; i++)
+ if (bus_mux.crtcs[i].crtc == crtc) {
+ *mux_val = bus_mux.crtcs[i].val;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int find_ldb_chno(struct ldb_data *ldb,
+ struct fb_info *fbi, int *chno)
+{
+ struct device *dev = ldb->dev;
+ int i = 0;
+
+ for (; i < 2; i++)
+ if (ldb->chan[i].fbi == fbi) {
+ *chno = ldb->chan[i].chno;
+ return 0;
+ }
+ dev_err(dev, "failed to find channel number\n");
+ return -EINVAL;
+}
+
+static void ldb_disable(struct mxc_dispdrv_handle *mddh,
+ struct fb_info *fbi);
+
+static int ldb_setup(struct mxc_dispdrv_handle *mddh,
+ struct fb_info *fbi)
+{
+ struct ldb_data *ldb = mxc_dispdrv_getdata(mddh);
+ struct ldb_chan chan;
+ struct device *dev = ldb->dev;
+ struct clk *ldb_di_parent, *ldb_di_sel, *ldb_di_sel_parent;
+ struct clk *other_ldb_di_sel = NULL;
+ struct bus_mux bus_mux;
+ int ret = 0, id = 0, chno, other_chno;
+ unsigned long serial_clk;
+ u32 mux_val;
+
+ ret = find_ldb_chno(ldb, fbi, &chno);
+ if (ret < 0)
+ return ret;
+
+ other_chno = chno ? 0 : 1;
+
+ chan = ldb->chan[chno];
+
+ bus_mux = ldb->buses[chno];
+
+ ret = get_di_clk_id(chan, &id);
+ if (ret < 0) {
+ dev_err(dev, "failed to get ch%d di clk id\n",
+ chan.chno);
+ return ret;
+ }
+
+ ret = get_mux_val(bus_mux, chan.crtc, &mux_val);
+ if (ret < 0) {
+ dev_err(dev, "failed to get ch%d mux val\n",
+ chan.chno);
+ return ret;
+ }
+
+
+ if (ldb->clk_fixup) {
+ /*
+ * ldb_di_sel_parent(plls) -> ldb_di_sel -> ldb_di[chno] ->
+ *
+ * -> div_3_5[chno] ->
+ * -> | |-> div_sel[chno] -> di[id]
+ * -> div_7[chno] ->
+ */
+ clk_set_parent(ldb->di_clk[id], ldb->div_sel_clk[chno]);
+ } else {
+ /*
+ * ldb_di_sel_parent(plls) -> ldb_di_sel ->
+ *
+ * -> div_3_5[chno] ->
+ * -> | |-> div_sel[chno] ->
+ * -> div_7[chno] ->
+ *
+ * -> ldb_di[chno] -> di[id]
+ */
+ clk_set_parent(ldb->di_clk[id], ldb->ldb_di_clk[chno]);
+ }
+ ldb_di_parent = ldb->spl_mode ? ldb->div_3_5_clk[chno] :
+ ldb->div_7_clk[chno];
+ clk_set_parent(ldb->div_sel_clk[chno], ldb_di_parent);
+ ldb_di_sel = clk_get_parent(ldb_di_parent);
+ ldb_di_sel_parent = clk_get_parent(ldb_di_sel);
+ serial_clk = ldb->spl_mode ? chan.vm.pixelclock * 7 / 2 :
+ chan.vm.pixelclock * 7;
+ clk_set_rate(ldb_di_sel_parent, serial_clk);
+
+ /*
+ * split mode or dual mode:
+ * clock tree for the other channel
+ */
+ if (ldb->spl_mode) {
+ clk_set_parent(ldb->div_sel_clk[other_chno],
+ ldb->div_3_5_clk[other_chno]);
+ other_ldb_di_sel =
+ clk_get_parent(ldb->div_3_5_clk[other_chno]);;
+ }
+
+ if (ldb->dual_mode) {
+ clk_set_parent(ldb->div_sel_clk[other_chno],
+ ldb->div_7_clk[other_chno]);
+ other_ldb_di_sel =
+ clk_get_parent(ldb->div_7_clk[other_chno]);;
+ }
+
+ if (ldb->spl_mode || ldb->dual_mode)
+ clk_set_parent(other_ldb_di_sel, ldb_di_sel_parent);
+
+ if (!(chan.fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)) {
+ if (ldb->spl_mode && bus_mux.reg == INVALID_BUS_REG)
+ /* no pre-muxing, such as mx53 */
+ ldb->ctrl |= (id == 0 ? LDB_DI0_VS_POL_ACT_LOW :
+ LDB_DI1_VS_POL_ACT_LOW);
+ else
+ ldb->ctrl |= (chno == 0 ? LDB_DI0_VS_POL_ACT_LOW :
+ LDB_DI1_VS_POL_ACT_LOW);
+ }
+
+ if (bus_mux.reg != INVALID_BUS_REG)
+ regmap_update_bits(ldb->regmap, bus_mux.reg,
+ bus_mux.mask, mux_val);
+
+ regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ctrl);
+
+ /* disable channel for correct sequence */
+ ldb_disable(mddh, fbi);
+
+ return ret;
+}
+
+static int ldb_enable(struct mxc_dispdrv_handle *mddh,
+ struct fb_info *fbi)
+{
+ struct ldb_data *ldb = mxc_dispdrv_getdata(mddh);
+ struct ldb_chan chan;
+ struct device *dev = ldb->dev;
+ struct bus_mux bus_mux;
+ int ret = 0, id = 0, chno, other_chno;
+
+ ret = find_ldb_chno(ldb, fbi, &chno);
+ if (ret < 0)
+ return ret;
+
+ chan = ldb->chan[chno];
+
+ bus_mux = ldb->buses[chno];
+
+ if (ldb->spl_mode || ldb->dual_mode) {
+ other_chno = chno ? 0 : 1;
+ clk_prepare_enable(ldb->ldb_di_clk[other_chno]);
+ }
+
+ if ((ldb->spl_mode || ldb->dual_mode) &&
+ bus_mux.reg == INVALID_BUS_REG) {
+ /* no pre-muxing, such as mx53 */
+ ret = get_di_clk_id(chan, &id);
+ if (ret < 0) {
+ dev_err(dev, "failed to get ch%d di clk id\n",
+ chan.chno);
+ return ret;
+ }
+
+ ldb->ctrl |= id ?
+ (LDB_CH0_MODE_EN_TO_DI1 | LDB_CH1_MODE_EN_TO_DI1) :
+ (LDB_CH0_MODE_EN_TO_DI0 | LDB_CH1_MODE_EN_TO_DI0);
+ } else {
+ if (ldb->spl_mode || ldb->dual_mode)
+ ldb->ctrl |= LDB_CH0_MODE_EN_TO_DI0 |
+ LDB_CH1_MODE_EN_TO_DI0;
+ else
+ ldb->ctrl |= chno ? LDB_CH1_MODE_EN_TO_DI1 :
+ LDB_CH0_MODE_EN_TO_DI0;
+ }
+
+ regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ctrl);
+ return 0;
+}
+
+static void ldb_disable(struct mxc_dispdrv_handle *mddh,
+ struct fb_info *fbi)
+{
+ struct ldb_data *ldb = mxc_dispdrv_getdata(mddh);
+ int ret, chno, other_chno;
+
+ ret = find_ldb_chno(ldb, fbi, &chno);
+ if (ret < 0)
+ return;
+
+ if (ldb->spl_mode || ldb->dual_mode) {
+ ldb->ctrl &= ~(LDB_CH1_MODE_MASK | LDB_CH0_MODE_MASK);
+ other_chno = chno ? 0 : 1;
+ clk_disable_unprepare(ldb->ldb_di_clk[other_chno]);
+ } else {
+ ldb->ctrl &= ~(chno ? LDB_CH1_MODE_MASK :
+ LDB_CH0_MODE_MASK);
+ }
+
+ regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ctrl);
+ return;
+}
+
+static struct mxc_dispdrv_driver ldb_drv = {
+ .name = DRIVER_NAME,
+ .init = ldb_init,
+ .setup = ldb_setup,
+ .enable = ldb_enable,
+ .disable = ldb_disable
+};
+
+enum {
+ LVDS_BIT_MAP_SPWG,
+ LVDS_BIT_MAP_JEIDA,
+};
+
+static const char *ldb_bit_mappings[] = {
+ [LVDS_BIT_MAP_SPWG] = "spwg",
+ [LVDS_BIT_MAP_JEIDA] = "jeida",
+};
+
+static int of_get_data_mapping(struct device_node *np)
+{
+ const char *bm;
+ int ret, i;
+
+ ret = of_property_read_string(np, "fsl,data-mapping", &bm);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(ldb_bit_mappings); i++)
+ if (!strcasecmp(bm, ldb_bit_mappings[i]))
+ return i;
+
+ return -EINVAL;
+}
+
+static const char *ldb_crtc_mappings[] = {
+ [CRTC_IPU_DI0] = "ipu-di0",
+ [CRTC_IPU_DI1] = "ipu-di1",
+ [CRTC_IPU1_DI0] = "ipu1-di0",
+ [CRTC_IPU1_DI1] = "ipu1-di1",
+ [CRTC_IPU2_DI0] = "ipu2-di0",
+ [CRTC_IPU2_DI1] = "ipu2-di1",
+ [CRTC_LCDIF] = "lcdif",
+ [CRTC_LCDIF1] = "lcdif1",
+ [CRTC_LCDIF2] = "lcdif2",
+};
+
+static enum crtc of_get_crtc_mapping(struct device_node *np)
+{
+ const char *cm;
+ enum crtc i;
+ int ret;
+
+ ret = of_property_read_string(np, "crtc", &cm);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(ldb_crtc_mappings); i++)
+ if (!strcasecmp(cm, ldb_crtc_mappings[i])) {
+ switch (i) {
+ case CRTC_IPU_DI0:
+ i = CRTC_IPU1_DI0;
+ break;
+ case CRTC_IPU_DI1:
+ i = CRTC_IPU1_DI1;
+ break;
+ case CRTC_LCDIF:
+ i = CRTC_LCDIF1;
+ break;
+ default:
+ break;
+ }
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int mux_count(struct ldb_data *ldb)
+{
+ int i, j, count = 0;
+ bool should_count[CRTC_MAX];
+ enum crtc crtc;
+
+ for (i = 0; i < CRTC_MAX; i++)
+ should_count[i] = true;
+
+ for (i = 0; i < ldb->bus_mux_num; i++) {
+ for (j = 0; j < ldb->buses[i].crtc_mux_num; j++) {
+ crtc = ldb->buses[i].crtcs[j].crtc;
+ if (should_count[crtc]) {
+ count++;
+ should_count[crtc] = false;
+ }
+ }
+ }
+
+ return count;
+}
+
+static bool is_valid_crtc(struct ldb_data *ldb, enum crtc crtc,
+ int chno)
+{
+ int i = 0;
+
+ if (chno > ldb->bus_mux_num - 1)
+ return false;
+
+ for (; i < ldb->buses[chno].crtc_mux_num; i++)
+ if (ldb->buses[chno].crtcs[i].crtc == crtc)
+ return true;
+
+ return false;
+}
+
+static int ldb_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *of_id =
+ of_match_device(ldb_dt_ids, dev);
+ const struct ldb_info *ldb_info =
+ (const struct ldb_info *)of_id->data;
+ struct device_node *np = dev->of_node, *child;
+ struct ldb_data *ldb;
+ bool ext_ref;
+ int i, data_width, mapping, child_count = 0;
+ char clkname[16];
+
+ ldb = devm_kzalloc(dev, sizeof(*ldb), GFP_KERNEL);
+ if (!ldb)
+ return -ENOMEM;
+
+ ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
+ if (IS_ERR(ldb->regmap)) {
+ dev_err(dev, "failed to get parent regmap\n");
+ return PTR_ERR(ldb->regmap);
+ }
+
+ ldb->dev = dev;
+ ldb->bus_mux_num = ldb_info->bus_mux_num;
+ ldb->buses = ldb_info->buses;
+ ldb->ctrl_reg = ldb_info->ctrl_reg;
+ ldb->clk_fixup = ldb_info->clk_fixup;
+ ldb->primary_chno = -1;
+
+ ext_ref = of_property_read_bool(np, "ext-ref");
+ if (!ext_ref && ldb_info->ext_bgref_cap)
+ ldb->ctrl |= LDB_BGREF_RMODE_INT;
+
+ ldb->spl_mode = of_property_read_bool(np, "split-mode");
+ if (ldb->spl_mode) {
+ if (ldb_info->split_cap) {
+ ldb->ctrl |= LDB_SPLIT_MODE_EN;
+ dev_info(dev, "split mode\n");
+ } else {
+ dev_err(dev, "cannot support split mode\n");
+ return -EINVAL;
+ }
+ }
+
+ ldb->dual_mode = of_property_read_bool(np, "dual-mode");
+ if (ldb->dual_mode) {
+ if (ldb_info->dual_cap) {
+ dev_info(dev, "dual mode\n");
+ } else {
+ dev_err(dev, "cannot support dual mode\n");
+ return -EINVAL;
+ }
+ }
+
+ if (ldb->dual_mode && ldb->spl_mode) {
+ dev_err(dev, "cannot support dual mode and split mode "
+ "simultaneously\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < mux_count(ldb); i++) {
+ sprintf(clkname, "di%d_sel", i);
+ ldb->di_clk[i] = devm_clk_get(dev, clkname);
+ if (IS_ERR(ldb->di_clk[i])) {
+ dev_err(dev, "failed to get clk %s\n", clkname);
+ return PTR_ERR(ldb->di_clk[i]);
+ }
+ }
+
+ for_each_child_of_node(np, child) {
+ struct ldb_chan *chan;
+ enum crtc crtc;
+ bool is_primary;
+ int ret;
+
+ ret = of_property_read_u32(child, "reg", &i);
+ if (ret || i < 0 || i > 1 || i >= ldb->bus_mux_num) {
+ dev_err(dev, "wrong LVDS channel number\n");
+ return -EINVAL;
+ }
+
+ if ((ldb->spl_mode || ldb->dual_mode) && i > 0) {
+ dev_warn(dev, "split mode or dual mode, ignoring "
+ "second output\n");
+ continue;
+ }
+
+ if (!of_device_is_available(child))
+ continue;
+
+ if (++child_count > ldb->bus_mux_num) {
+ dev_err(dev, "too many LVDS channels\n");
+ return -EINVAL;
+ }
+
+ chan = &ldb->chan[i];
+ chan->chno = i;
+ chan->ldb = ldb;
+ chan->online = true;
+
+ is_primary = of_property_read_bool(child, "primary");
+
+ if (ldb->bus_mux_num == 1 || (ldb->primary_chno == -1 &&
+ (is_primary || ldb->spl_mode || ldb->dual_mode)))
+ ldb->primary_chno = chan->chno;
+
+ ret = of_property_read_u32(child, "fsl,data-width",
+ &data_width);
+ if (ret || (data_width != 18 && data_width != 24)) {
+ dev_err(dev, "data width not specified or invalid\n");
+ return -EINVAL;
+ }
+
+ mapping = of_get_data_mapping(child);
+ switch (mapping) {
+ case LVDS_BIT_MAP_SPWG:
+ if (data_width == 24) {
+ if (i == 0 || ldb->spl_mode || ldb->dual_mode)
+ ldb->ctrl |= LDB_DATA_WIDTH_CH0_24;
+ if (i == 1 || ldb->spl_mode || ldb->dual_mode)
+ ldb->ctrl |= LDB_DATA_WIDTH_CH1_24;
+ }
+ break;
+ case LVDS_BIT_MAP_JEIDA:
+ if (data_width == 18) {
+ dev_err(dev, "JEIDA only support 24bit\n");
+ return -EINVAL;
+ }
+ if (i == 0 || ldb->spl_mode || ldb->dual_mode)
+ ldb->ctrl |= LDB_DATA_WIDTH_CH0_24 |
+ LDB_BIT_MAP_CH0_JEIDA;
+ if (i == 1 || ldb->spl_mode || ldb->dual_mode)
+ ldb->ctrl |= LDB_DATA_WIDTH_CH1_24 |
+ LDB_BIT_MAP_CH1_JEIDA;
+ break;
+ default:
+ dev_err(dev, "data mapping not specified or invalid\n");
+ return -EINVAL;
+ }
+
+ crtc = of_get_crtc_mapping(child);
+ if (is_valid_crtc(ldb, crtc, chan->chno)) {
+ ldb->chan[i].crtc = crtc;
+ } else {
+ dev_err(dev, "crtc not specified or invalid\n");
+ return -EINVAL;
+ }
+
+ ret = of_get_videomode(child, &chan->vm, 0);
+ if (ret)
+ return -EINVAL;
+
+ sprintf(clkname, "ldb_di%d", i);
+ ldb->ldb_di_clk[i] = devm_clk_get(dev, clkname);
+ if (IS_ERR(ldb->ldb_di_clk[i])) {
+ dev_err(dev, "failed to get clk %s\n", clkname);
+ return PTR_ERR(ldb->ldb_di_clk[i]);
+ }
+
+ sprintf(clkname, "ldb_di%d_div_3_5", i);
+ ldb->div_3_5_clk[i] = devm_clk_get(dev, clkname);
+ if (IS_ERR(ldb->div_3_5_clk[i])) {
+ dev_err(dev, "failed to get clk %s\n", clkname);
+ return PTR_ERR(ldb->div_3_5_clk[i]);
+ }
+
+ sprintf(clkname, "ldb_di%d_div_7", i);
+ ldb->div_7_clk[i] = devm_clk_get(dev, clkname);
+ if (IS_ERR(ldb->div_7_clk[i])) {
+ dev_err(dev, "failed to get clk %s\n", clkname);
+ return PTR_ERR(ldb->div_7_clk[i]);
+ }
+
+ sprintf(clkname, "ldb_di%d_div_sel", i);
+ ldb->div_sel_clk[i] = devm_clk_get(dev, clkname);
+ if (IS_ERR(ldb->div_sel_clk[i])) {
+ dev_err(dev, "failed to get clk %s\n", clkname);
+ return PTR_ERR(ldb->div_sel_clk[i]);
+ }
+ }
+
+ if (child_count == 0) {
+ dev_err(dev, "failed to find valid LVDS channel\n");
+ return -EINVAL;
+ }
+
+ if (ldb->primary_chno == -1) {
+ dev_err(dev, "failed to know primary channel\n");
+ return -EINVAL;
+ }
+
+ ldb->mddh = mxc_dispdrv_register(&ldb_drv);
+ mxc_dispdrv_setdata(ldb->mddh, ldb);
+ dev_set_drvdata(&pdev->dev, ldb);
+
+ return 0;
+}
+
+static int ldb_remove(struct platform_device *pdev)
+{
+ struct ldb_data *ldb = dev_get_drvdata(&pdev->dev);
+
+ mxc_dispdrv_puthandle(ldb->mddh);
+ mxc_dispdrv_unregister(ldb->mddh);
+ return 0;
+}
+
+static struct platform_driver ldb_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = ldb_dt_ids,
+ },
+ .probe = ldb_probe,
+ .remove = ldb_remove,
+};
+
+module_platform_driver(ldb_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("LDB driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/video/fbdev/mxc/mipi_dsi.c b/drivers/video/fbdev/mxc/mipi_dsi.c
new file mode 100644
index 000000000000..68a9bfa2aa9f
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mipi_dsi.c
@@ -0,0 +1,1039 @@
+/*
+ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/ipu.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/mipi_dsi.h>
+#include <linux/module.h>
+#include <linux/mxcfb.h>
+#include <linux/backlight.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <video/mipi_display.h>
+
+#include "mipi_dsi.h"
+
+#define DISPDRV_MIPI "mipi_dsi"
+#define ROUND_UP(x) ((x)+1)
+#define NS2PS_RATIO (1000)
+#define NUMBER_OF_CHUNKS (0x8)
+#define NULL_PKT_SIZE (0x8)
+#define PHY_BTA_MAXTIME (0xd00)
+#define PHY_LP2HS_MAXTIME (0x40)
+#define PHY_HS2LP_MAXTIME (0x40)
+#define PHY_STOP_WAIT_TIME (0x20)
+#define DSI_CLKMGR_CFG_CLK_DIV (0x107)
+#define DSI_GEN_PLD_DATA_BUF_ENTRY (0x10)
+#define MIPI_MUX_CTRL(v) (((v) & 0x3) << 4)
+#define MIPI_LCD_SLEEP_MODE_DELAY (120)
+#define MIPI_DSI_REG_RW_TIMEOUT (20)
+#define MIPI_DSI_PHY_TIMEOUT (10)
+
+static struct mipi_dsi_match_lcd mipi_dsi_lcd_db[] = {
+#ifdef CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL
+ {
+ "TRULY-WVGA",
+ {mipid_hx8369_get_lcd_videomode, mipid_hx8369_lcd_setup}
+ },
+#endif
+ {
+ "", {NULL, NULL}
+ }
+};
+
+struct _mipi_dsi_phy_pll_clk {
+ u32 max_phy_clk;
+ u32 config;
+};
+
+/* configure data for DPHY PLL 27M reference clk out */
+static const struct _mipi_dsi_phy_pll_clk mipi_dsi_phy_pll_clk_table[] = {
+ {1000, 0x74}, /* 950-1000MHz */
+ {950, 0x54}, /* 900-950Mhz */
+ {900, 0x34}, /* 850-900Mhz */
+ {850, 0x14}, /* 800-850MHz */
+ {800, 0x32}, /* 750-800MHz */
+ {750, 0x12}, /* 700-750Mhz */
+ {700, 0x30}, /* 650-700Mhz */
+ {650, 0x10}, /* 600-650MHz */
+ {600, 0x2e}, /* 550-600MHz */
+ {550, 0x0e}, /* 500-550Mhz */
+ {500, 0x2c}, /* 450-500Mhz */
+ {450, 0x0c}, /* 400-450MHz */
+ {400, 0x4a}, /* 360-400MHz */
+ {360, 0x2a}, /* 330-360Mhz */
+ {330, 0x48}, /* 300-330Mhz */
+ {300, 0x28}, /* 270-300MHz */
+ {270, 0x08}, /* 250-270MHz */
+ {250, 0x46}, /* 240-250Mhz */
+ {240, 0x26}, /* 210-240Mhz */
+ {210, 0x06}, /* 200-210MHz */
+ {200, 0x44}, /* 180-200MHz */
+ {180, 0x24}, /* 160-180MHz */
+ {160, 0x04}, /* 150-160MHz */
+};
+
+static int valid_mode(int pixel_fmt)
+{
+ return ((pixel_fmt == IPU_PIX_FMT_RGB24) ||
+ (pixel_fmt == IPU_PIX_FMT_BGR24) ||
+ (pixel_fmt == IPU_PIX_FMT_RGB666) ||
+ (pixel_fmt == IPU_PIX_FMT_RGB565) ||
+ (pixel_fmt == IPU_PIX_FMT_BGR666) ||
+ (pixel_fmt == IPU_PIX_FMT_RGB332));
+}
+
+static inline void mipi_dsi_read_register(struct mipi_dsi_info *mipi_dsi,
+ u32 reg, u32 *val)
+{
+ *val = ioread32(mipi_dsi->mmio_base + reg);
+ dev_dbg(&mipi_dsi->pdev->dev, "read_reg:0x%02x, val:0x%08x.\n",
+ reg, *val);
+}
+
+static inline void mipi_dsi_write_register(struct mipi_dsi_info *mipi_dsi,
+ u32 reg, u32 val)
+{
+ iowrite32(val, mipi_dsi->mmio_base + reg);
+ dev_dbg(&mipi_dsi->pdev->dev, "\t\twrite_reg:0x%02x, val:0x%08x.\n",
+ reg, val);
+}
+
+static int mipi_dsi_pkt_write(struct mipi_dsi_info *mipi_dsi,
+ u8 data_type, const u32 *buf, int len)
+{
+ u32 val;
+ u32 status = 0;
+ int write_len = len;
+ uint32_t timeout = 0;
+
+ if (len) {
+ /* generic long write command */
+ while (len / DSI_GEN_PLD_DATA_BUF_SIZE) {
+ mipi_dsi_write_register(mipi_dsi,
+ MIPI_DSI_GEN_PLD_DATA, *buf);
+ buf++;
+ len -= DSI_GEN_PLD_DATA_BUF_SIZE;
+ mipi_dsi_read_register(mipi_dsi,
+ MIPI_DSI_CMD_PKT_STATUS, &status);
+ while ((status & DSI_CMD_PKT_STATUS_GEN_PLD_W_FULL) ==
+ DSI_CMD_PKT_STATUS_GEN_PLD_W_FULL) {
+ msleep(1);
+ timeout++;
+ if (timeout == MIPI_DSI_REG_RW_TIMEOUT)
+ return -EIO;
+ mipi_dsi_read_register(mipi_dsi,
+ MIPI_DSI_CMD_PKT_STATUS, &status);
+ }
+ }
+ /* write the remainder bytes */
+ if (len > 0) {
+ while ((status & DSI_CMD_PKT_STATUS_GEN_PLD_W_FULL) ==
+ DSI_CMD_PKT_STATUS_GEN_PLD_W_FULL) {
+ msleep(1);
+ timeout++;
+ if (timeout == MIPI_DSI_REG_RW_TIMEOUT)
+ return -EIO;
+ mipi_dsi_read_register(mipi_dsi,
+ MIPI_DSI_CMD_PKT_STATUS, &status);
+ }
+ mipi_dsi_write_register(mipi_dsi,
+ MIPI_DSI_GEN_PLD_DATA, *buf);
+ }
+
+ val = data_type | ((write_len & DSI_GEN_HDR_DATA_MASK)
+ << DSI_GEN_HDR_DATA_SHIFT);
+ } else {
+ /* generic short write command */
+ val = data_type | ((*buf & DSI_GEN_HDR_DATA_MASK)
+ << DSI_GEN_HDR_DATA_SHIFT);
+ }
+
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS, &status);
+ while ((status & DSI_CMD_PKT_STATUS_GEN_CMD_FULL) ==
+ DSI_CMD_PKT_STATUS_GEN_CMD_FULL) {
+ msleep(1);
+ timeout++;
+ if (timeout == MIPI_DSI_REG_RW_TIMEOUT)
+ return -EIO;
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS,
+ &status);
+ }
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_GEN_HDR, val);
+
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS, &status);
+ while (!((status & DSI_CMD_PKT_STATUS_GEN_CMD_EMPTY) ==
+ DSI_CMD_PKT_STATUS_GEN_CMD_EMPTY) ||
+ !((status & DSI_CMD_PKT_STATUS_GEN_PLD_W_EMPTY) ==
+ DSI_CMD_PKT_STATUS_GEN_PLD_W_EMPTY)) {
+ msleep(1);
+ timeout++;
+ if (timeout == MIPI_DSI_REG_RW_TIMEOUT)
+ return -EIO;
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS,
+ &status);
+ }
+
+ return 0;
+}
+
+static int mipi_dsi_pkt_read(struct mipi_dsi_info *mipi_dsi,
+ u8 data_type, u32 *buf, int len)
+{
+ u32 val;
+ int read_len = 0;
+ uint32_t timeout = 0;
+
+ if (!len) {
+ mipi_dbg("%s, len = 0 invalid error!\n", __func__);
+ return -EINVAL;
+ }
+
+ val = data_type | ((*buf & DSI_GEN_HDR_DATA_MASK)
+ << DSI_GEN_HDR_DATA_SHIFT);
+ memset(buf, 0, len);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_GEN_HDR, val);
+
+ /* wait for cmd to sent out */
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS, &val);
+ while ((val & DSI_CMD_PKT_STATUS_GEN_RD_CMD_BUSY) !=
+ DSI_CMD_PKT_STATUS_GEN_RD_CMD_BUSY) {
+ msleep(1);
+ timeout++;
+ if (timeout == MIPI_DSI_REG_RW_TIMEOUT)
+ return -EIO;
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS,
+ &val);
+ }
+ /* wait for entire response stroed in FIFO */
+ while ((val & DSI_CMD_PKT_STATUS_GEN_RD_CMD_BUSY) ==
+ DSI_CMD_PKT_STATUS_GEN_RD_CMD_BUSY) {
+ msleep(1);
+ timeout++;
+ if (timeout == MIPI_DSI_REG_RW_TIMEOUT)
+ return -EIO;
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS,
+ &val);
+ }
+
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS, &val);
+ while (!(val & DSI_CMD_PKT_STATUS_GEN_PLD_R_EMPTY)) {
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_GEN_PLD_DATA, buf);
+ read_len += DSI_GEN_PLD_DATA_BUF_SIZE;
+ buf++;
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_PKT_STATUS,
+ &val);
+ if (read_len == (DSI_GEN_PLD_DATA_BUF_ENTRY *
+ DSI_GEN_PLD_DATA_BUF_SIZE))
+ break;
+ }
+
+ if ((len <= read_len) &&
+ ((len + DSI_GEN_PLD_DATA_BUF_SIZE) >= read_len))
+ return 0;
+ else {
+ dev_err(&mipi_dsi->pdev->dev,
+ "actually read_len:%d != len:%d.\n", read_len, len);
+ return -ERANGE;
+ }
+}
+
+static int mipi_dsi_dcs_cmd(struct mipi_dsi_info *mipi_dsi,
+ u8 cmd, const u32 *param, int num)
+{
+ int err = 0;
+ u32 buf[DSI_CMD_BUF_MAXSIZE];
+
+ switch (cmd) {
+ case MIPI_DCS_EXIT_SLEEP_MODE:
+ case MIPI_DCS_ENTER_SLEEP_MODE:
+ case MIPI_DCS_SET_DISPLAY_ON:
+ case MIPI_DCS_SET_DISPLAY_OFF:
+ buf[0] = cmd;
+ err = mipi_dsi_pkt_write(mipi_dsi,
+ MIPI_DSI_DCS_SHORT_WRITE, buf, 0);
+ break;
+
+ default:
+ dev_err(&mipi_dsi->pdev->dev,
+ "MIPI DSI DCS Command:0x%x Not supported!\n", cmd);
+ break;
+ }
+
+ return err;
+}
+
+static void mipi_dsi_dphy_init(struct mipi_dsi_info *mipi_dsi,
+ u32 cmd, u32 data)
+{
+ u32 val;
+ u32 timeout = 0;
+
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_IF_CTRL,
+ DSI_PHY_IF_CTRL_RESET);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PWR_UP, DSI_PWRUP_POWERUP);
+
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_TST_CTRL0, 0);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_TST_CTRL1,
+ (0x10000 | cmd));
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_TST_CTRL0, 2);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_TST_CTRL0, 0);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_TST_CTRL1, (0 | data));
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_TST_CTRL0, 2);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_TST_CTRL0, 0);
+ val = DSI_PHY_RSTZ_EN_CLK | DSI_PHY_RSTZ_DISABLE_RST |
+ DSI_PHY_RSTZ_DISABLE_SHUTDOWN;
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_RSTZ, val);
+
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_PHY_STATUS, &val);
+ while ((val & DSI_PHY_STATUS_LOCK) != DSI_PHY_STATUS_LOCK) {
+ msleep(1);
+ timeout++;
+ if (timeout == MIPI_DSI_PHY_TIMEOUT) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "Error: phy lock timeout!\n");
+ break;
+ }
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_PHY_STATUS, &val);
+ }
+ timeout = 0;
+ while ((val & DSI_PHY_STATUS_STOPSTATE_CLK_LANE) !=
+ DSI_PHY_STATUS_STOPSTATE_CLK_LANE) {
+ msleep(1);
+ timeout++;
+ if (timeout == MIPI_DSI_PHY_TIMEOUT) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "Error: phy lock lane timeout!\n");
+ break;
+ }
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_PHY_STATUS, &val);
+ }
+}
+
+static void mipi_dsi_enable_controller(struct mipi_dsi_info *mipi_dsi,
+ bool init)
+{
+ u32 val = 0;
+ u32 lane_byte_clk_period;
+ struct fb_videomode *mode = mipi_dsi->mode;
+ struct mipi_lcd_config *lcd_config = mipi_dsi->lcd_config;
+
+ if (init) {
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PWR_UP,
+ DSI_PWRUP_RESET);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_RSTZ,
+ DSI_PHY_RSTZ_RST);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_CLKMGR_CFG,
+ DSI_CLKMGR_CFG_CLK_DIV);
+
+ if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
+ val = DSI_DPI_CFG_VSYNC_ACT_LOW;
+ if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
+ val |= DSI_DPI_CFG_HSYNC_ACT_LOW;
+ if ((mode->sync & FB_SYNC_OE_LOW_ACT))
+ val |= DSI_DPI_CFG_DATAEN_ACT_LOW;
+ if (MIPI_RGB666_LOOSELY == lcd_config->dpi_fmt)
+ val |= DSI_DPI_CFG_EN18LOOSELY;
+ val |= (lcd_config->dpi_fmt & DSI_DPI_CFG_COLORCODE_MASK)
+ << DSI_DPI_CFG_COLORCODE_SHIFT;
+ val |= (lcd_config->virtual_ch & DSI_DPI_CFG_VID_MASK)
+ << DSI_DPI_CFG_VID_SHIFT;
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_DPI_CFG, val);
+
+ val = DSI_PCKHDL_CFG_EN_BTA |
+ DSI_PCKHDL_CFG_EN_ECC_RX |
+ DSI_PCKHDL_CFG_EN_CRC_RX;
+
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PCKHDL_CFG, val);
+
+ val = (mode->xres & DSI_VID_PKT_CFG_VID_PKT_SZ_MASK)
+ << DSI_VID_PKT_CFG_VID_PKT_SZ_SHIFT;
+ val |= (NUMBER_OF_CHUNKS & DSI_VID_PKT_CFG_NUM_CHUNKS_MASK)
+ << DSI_VID_PKT_CFG_NUM_CHUNKS_SHIFT;
+ val |= (NULL_PKT_SIZE & DSI_VID_PKT_CFG_NULL_PKT_SZ_MASK)
+ << DSI_VID_PKT_CFG_NULL_PKT_SZ_SHIFT;
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_VID_PKT_CFG, val);
+
+ /* enable LP mode when TX DCS cmd and enable DSI command mode */
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_CMD_MODE_CFG,
+ MIPI_DSI_CMD_MODE_CFG_EN_LOWPOWER);
+
+ /* mipi lane byte clk period in ns unit */
+ lane_byte_clk_period = NS2PS_RATIO /
+ (lcd_config->max_phy_clk / BITS_PER_BYTE);
+ val = ROUND_UP(mode->hsync_len * mode->pixclock /
+ NS2PS_RATIO / lane_byte_clk_period)
+ << DSI_TME_LINE_CFG_HSA_TIME_SHIFT;
+ val |= ROUND_UP(mode->left_margin * mode->pixclock /
+ NS2PS_RATIO / lane_byte_clk_period)
+ << DSI_TME_LINE_CFG_HBP_TIME_SHIFT;
+ val |= ROUND_UP((mode->left_margin + mode->right_margin +
+ mode->hsync_len + mode->xres) * mode->pixclock
+ / NS2PS_RATIO / lane_byte_clk_period)
+ << DSI_TME_LINE_CFG_HLINE_TIME_SHIFT;
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_TMR_LINE_CFG, val);
+
+ val = ((mode->vsync_len & DSI_VTIMING_CFG_VSA_LINES_MASK)
+ << DSI_VTIMING_CFG_VSA_LINES_SHIFT);
+ val |= ((mode->upper_margin & DSI_VTIMING_CFG_VBP_LINES_MASK)
+ << DSI_VTIMING_CFG_VBP_LINES_SHIFT);
+ val |= ((mode->lower_margin & DSI_VTIMING_CFG_VFP_LINES_MASK)
+ << DSI_VTIMING_CFG_VFP_LINES_SHIFT);
+ val |= ((mode->yres & DSI_VTIMING_CFG_V_ACT_LINES_MASK)
+ << DSI_VTIMING_CFG_V_ACT_LINES_SHIFT);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_VTIMING_CFG, val);
+
+ val = ((PHY_BTA_MAXTIME & DSI_PHY_TMR_CFG_BTA_TIME_MASK)
+ << DSI_PHY_TMR_CFG_BTA_TIME_SHIFT);
+ val |= ((PHY_LP2HS_MAXTIME & DSI_PHY_TMR_CFG_LP2HS_TIME_MASK)
+ << DSI_PHY_TMR_CFG_LP2HS_TIME_SHIFT);
+ val |= ((PHY_HS2LP_MAXTIME & DSI_PHY_TMR_CFG_HS2LP_TIME_MASK)
+ << DSI_PHY_TMR_CFG_HS2LP_TIME_SHIFT);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_TMR_CFG, val);
+
+ val = (((lcd_config->data_lane_num - 1) &
+ DSI_PHY_IF_CFG_N_LANES_MASK)
+ << DSI_PHY_IF_CFG_N_LANES_SHIFT);
+ val |= ((PHY_STOP_WAIT_TIME & DSI_PHY_IF_CFG_WAIT_TIME_MASK)
+ << DSI_PHY_IF_CFG_WAIT_TIME_SHIFT);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_IF_CFG, val);
+
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_ERROR_ST0, &val);
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_ERROR_ST1, &val);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_ERROR_MSK0, 0);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_ERROR_MSK1, 0);
+
+ mipi_dsi_dphy_init(mipi_dsi, DSI_PHY_CLK_INIT_COMMAND,
+ mipi_dsi->dphy_pll_config);
+ } else {
+ mipi_dsi_dphy_init(mipi_dsi, DSI_PHY_CLK_INIT_COMMAND,
+ mipi_dsi->dphy_pll_config);
+ }
+}
+
+static void mipi_dsi_disable_controller(struct mipi_dsi_info *mipi_dsi)
+{
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_IF_CTRL,
+ DSI_PHY_IF_CTRL_RESET);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PWR_UP, DSI_PWRUP_RESET);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_RSTZ, DSI_PHY_RSTZ_RST);
+}
+
+static irqreturn_t mipi_dsi_irq_handler(int irq, void *data)
+{
+ u32 mask0;
+ u32 mask1;
+ u32 status0;
+ u32 status1;
+ struct mipi_dsi_info *mipi_dsi;
+
+ mipi_dsi = (struct mipi_dsi_info *)data;
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_ERROR_ST0, &status0);
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_ERROR_ST1, &status1);
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_ERROR_MSK0, &mask0);
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_ERROR_MSK1, &mask1);
+
+ if ((status0 & (~mask0)) || (status1 & (~mask1))) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "mipi_dsi IRQ status0:0x%x, status1:0x%x!\n",
+ status0, status1);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static inline void mipi_dsi_set_mode(struct mipi_dsi_info *mipi_dsi,
+ bool cmd_mode)
+{
+ u32 val;
+
+ if (cmd_mode) {
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PWR_UP,
+ DSI_PWRUP_RESET);
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_MODE_CFG, &val);
+ val |= MIPI_DSI_CMD_MODE_CFG_EN_CMD_MODE;
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_CMD_MODE_CFG, val);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_VID_MODE_CFG, 0);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PWR_UP,
+ DSI_PWRUP_POWERUP);
+ } else {
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PWR_UP,
+ DSI_PWRUP_RESET);
+ /* Disable Command mode when tranfering video data */
+ mipi_dsi_read_register(mipi_dsi, MIPI_DSI_CMD_MODE_CFG, &val);
+ val &= ~MIPI_DSI_CMD_MODE_CFG_EN_CMD_MODE;
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_CMD_MODE_CFG, val);
+ val = DSI_VID_MODE_CFG_EN | DSI_VID_MODE_CFG_EN_BURSTMODE |
+ DSI_VID_MODE_CFG_EN_LP_MODE;
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_VID_MODE_CFG, val);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PWR_UP,
+ DSI_PWRUP_POWERUP);
+ mipi_dsi_write_register(mipi_dsi, MIPI_DSI_PHY_IF_CTRL,
+ DSI_PHY_IF_CTRL_TX_REQ_CLK_HS);
+ }
+}
+
+static int mipi_dsi_power_on(struct mxc_dispdrv_handle *disp)
+{
+ int err;
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+
+ if (!mipi_dsi->dsi_power_on) {
+ clk_prepare_enable(mipi_dsi->dphy_clk);
+ clk_prepare_enable(mipi_dsi->cfg_clk);
+ mipi_dsi_enable_controller(mipi_dsi, false);
+ mipi_dsi_set_mode(mipi_dsi, false);
+ /* host send pclk/hsync/vsync for two frames before sleep-out */
+ msleep((1000/mipi_dsi->mode->refresh + 1) << 1);
+ mipi_dsi_set_mode(mipi_dsi, true);
+ err = mipi_dsi_dcs_cmd(mipi_dsi, MIPI_DCS_EXIT_SLEEP_MODE,
+ NULL, 0);
+ if (err) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "MIPI DSI DCS Command sleep-in error!\n");
+ }
+ msleep(MIPI_LCD_SLEEP_MODE_DELAY);
+ mipi_dsi_set_mode(mipi_dsi, false);
+ mipi_dsi->dsi_power_on = 1;
+ }
+
+ return 0;
+}
+
+void mipi_dsi_power_off(struct mxc_dispdrv_handle *disp)
+{
+ int err;
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+
+ if (mipi_dsi->dsi_power_on) {
+ mipi_dsi_set_mode(mipi_dsi, true);
+ err = mipi_dsi_dcs_cmd(mipi_dsi, MIPI_DCS_ENTER_SLEEP_MODE,
+ NULL, 0);
+ if (err) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "MIPI DSI DCS Command display on error!\n");
+ }
+ /* To allow time for the supply voltages
+ * and clock circuits to stabilize.
+ */
+ msleep(5);
+ /* video stream timing on */
+ mipi_dsi_set_mode(mipi_dsi, false);
+ msleep(MIPI_LCD_SLEEP_MODE_DELAY);
+
+ mipi_dsi_set_mode(mipi_dsi, true);
+ mipi_dsi_disable_controller(mipi_dsi);
+ mipi_dsi->dsi_power_on = 0;
+ clk_disable_unprepare(mipi_dsi->dphy_clk);
+ clk_disable_unprepare(mipi_dsi->cfg_clk);
+ }
+}
+
+static int mipi_dsi_lcd_init(struct mipi_dsi_info *mipi_dsi,
+ struct mxc_dispdrv_setting *setting)
+{
+ int err;
+ int size;
+ int i;
+ struct fb_videomode *mipi_lcd_modedb;
+ struct fb_videomode mode;
+ struct device *dev = &mipi_dsi->pdev->dev;
+
+ for (i = 0; i < ARRAY_SIZE(mipi_dsi_lcd_db); i++) {
+ if (!strcmp(mipi_dsi->lcd_panel,
+ mipi_dsi_lcd_db[i].lcd_panel)) {
+ mipi_dsi->lcd_callback =
+ &mipi_dsi_lcd_db[i].lcd_callback;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(mipi_dsi_lcd_db)) {
+ dev_err(dev, "failed to find supported lcd panel.\n");
+ return -EINVAL;
+ }
+ /* get the videomode in the order: cmdline->platform data->driver */
+ mipi_dsi->lcd_callback->get_mipi_lcd_videomode(&mipi_lcd_modedb, &size,
+ &mipi_dsi->lcd_config);
+ err = fb_find_mode(&setting->fbi->var, setting->fbi,
+ setting->dft_mode_str,
+ mipi_lcd_modedb, size, NULL,
+ setting->default_bpp);
+ if (err != 1)
+ fb_videomode_to_var(&setting->fbi->var, mipi_lcd_modedb);
+
+ INIT_LIST_HEAD(&setting->fbi->modelist);
+ for (i = 0; i < size; i++) {
+ fb_var_to_videomode(&mode, &setting->fbi->var);
+ if (fb_mode_is_equal(&mode, mipi_lcd_modedb + i)) {
+ err = fb_add_videomode(mipi_lcd_modedb + i,
+ &setting->fbi->modelist);
+ /* Note: only support fb mode from driver */
+ mipi_dsi->mode = mipi_lcd_modedb + i;
+ break;
+ }
+ }
+ if ((err < 0) || (size == i)) {
+ dev_err(dev, "failed to add videomode.\n");
+ return err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mipi_dsi_phy_pll_clk_table); i++) {
+ if (mipi_dsi_phy_pll_clk_table[i].max_phy_clk <
+ mipi_dsi->lcd_config->max_phy_clk)
+ break;
+ }
+ if ((i == ARRAY_SIZE(mipi_dsi_phy_pll_clk_table)) ||
+ (mipi_dsi->lcd_config->max_phy_clk >
+ mipi_dsi_phy_pll_clk_table[0].max_phy_clk)) {
+ dev_err(dev, "failed to find data in"
+ "mipi_dsi_phy_pll_clk_table.\n");
+ return -EINVAL;
+ }
+ mipi_dsi->dphy_pll_config = mipi_dsi_phy_pll_clk_table[--i].config;
+ dev_dbg(dev, "dphy_pll_config:0x%x.\n", mipi_dsi->dphy_pll_config);
+
+ return 0;
+}
+
+static int mipi_dsi_enable(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
+{
+ int err;
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+
+ if (!mipi_dsi->lcd_inited) {
+ err = clk_prepare_enable(mipi_dsi->dphy_clk);
+ err |= clk_prepare_enable(mipi_dsi->cfg_clk);
+ if (err)
+ dev_err(&mipi_dsi->pdev->dev,
+ "clk enable error:%d!\n", err);
+ mipi_dsi_enable_controller(mipi_dsi, true);
+ err = mipi_dsi->lcd_callback->mipi_lcd_setup(
+ mipi_dsi);
+ if (err < 0) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "failed to init mipi lcd.");
+ clk_disable_unprepare(mipi_dsi->dphy_clk);
+ clk_disable_unprepare(mipi_dsi->cfg_clk);
+ return err;
+ }
+ mipi_dsi_set_mode(mipi_dsi, false);
+ mipi_dsi->dsi_power_on = 1;
+ mipi_dsi->lcd_inited = 1;
+ }
+ mipi_dsi_power_on(mipi_dsi->disp_mipi);
+
+ return 0;
+}
+
+static void mipi_dsi_disable(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
+{
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+
+ mipi_dsi_power_off(mipi_dsi->disp_mipi);
+}
+
+static int mipi_dsi_disp_init(struct mxc_dispdrv_handle *disp,
+ struct mxc_dispdrv_setting *setting)
+{
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+ struct device *dev = &mipi_dsi->pdev->dev;
+ int ret = 0;
+
+ if (!valid_mode(setting->if_fmt)) {
+ dev_warn(dev, "Input pixel format not valid"
+ "use default RGB24\n");
+ setting->if_fmt = IPU_PIX_FMT_RGB24;
+ }
+
+ ret = ipu_di_to_crtc(dev, mipi_dsi->dev_id,
+ mipi_dsi->disp_id, &setting->crtc);
+ if (ret < 0)
+ return ret;
+
+ ret = mipi_dsi_lcd_init(mipi_dsi, setting);
+ if (ret) {
+ dev_err(dev, "failed to init mipi dsi lcd\n");
+ return ret;
+ }
+
+ dev_dbg(dev, "MIPI DSI dispdrv inited!\n");
+ return ret;
+}
+
+static void mipi_dsi_disp_deinit(struct mxc_dispdrv_handle *disp)
+{
+ struct mipi_dsi_info *mipi_dsi;
+
+ mipi_dsi = mxc_dispdrv_getdata(disp);
+
+ mipi_dsi_power_off(mipi_dsi->disp_mipi);
+ if (mipi_dsi->bl)
+ backlight_device_unregister(mipi_dsi->bl);
+}
+
+static int mipi_dsi_setup(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
+{
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+ int xres_virtual = fbi->var.xres_virtual;
+ int yres_virtual = fbi->var.yres_virtual;
+ int xoffset = fbi->var.xoffset;
+ int yoffset = fbi->var.yoffset;
+ int pixclock = fbi->var.pixclock;
+
+ if (!mipi_dsi->mode)
+ return 0;
+
+ /* set the mode back to var in case userspace changes it */
+ fb_videomode_to_var(&fbi->var, mipi_dsi->mode);
+
+ /* restore some var entries cached */
+ fbi->var.xres_virtual = xres_virtual;
+ fbi->var.yres_virtual = yres_virtual;
+ fbi->var.xoffset = xoffset;
+ fbi->var.yoffset = yoffset;
+ fbi->var.pixclock = pixclock;
+ return 0;
+}
+
+static struct mxc_dispdrv_driver mipi_dsi_drv = {
+ .name = DISPDRV_MIPI,
+ .init = mipi_dsi_disp_init,
+ .deinit = mipi_dsi_disp_deinit,
+ .enable = mipi_dsi_enable,
+ .disable = mipi_dsi_disable,
+ .setup = mipi_dsi_setup,
+};
+
+static int device_reset(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ enum of_gpio_flags flags;
+ unsigned long gpio_flags;
+ unsigned int gpio;
+ bool initially_in_reset;
+ bool active_low;
+ s32 delay_us;
+ int ret;
+
+ gpio = of_get_named_gpio_flags(np, "reset-gpios", 0, &flags);
+ if (gpio == -EPROBE_DEFER) {
+ return gpio;
+ } else if (!gpio_is_valid(gpio)) {
+ dev_err(dev, "invalid reset gpio: %d\n", gpio);
+ return gpio;
+ }
+
+ active_low = flags & OF_GPIO_ACTIVE_LOW;
+
+ ret = of_property_read_u32(np, "reset-delay-us", &delay_us);
+ if (ret < 0 || delay_us < 0) {
+ dev_err(dev, "invalid reset delay\n");
+ return -EINVAL;
+ }
+
+ initially_in_reset = of_property_read_bool(np, "initially-in-reset");
+ if (active_low ^ initially_in_reset)
+ gpio_flags = GPIOF_OUT_INIT_HIGH;
+ else
+ gpio_flags = GPIOF_OUT_INIT_LOW;
+
+ ret = devm_gpio_request_one(dev, gpio, gpio_flags, NULL);
+ if (ret < 0) {
+ dev_err(dev, "failed to request gpio %d: %d\n", gpio, ret);
+ return ret;
+ }
+
+ gpio_set_value_cansleep(gpio, active_low ? 0 : 1);
+ udelay(delay_us);
+ gpio_set_value_cansleep(gpio, active_low ? 1 : 0);
+
+ return 0;
+}
+
+static int imx6q_mipi_dsi_get_mux(int dev_id, int disp_id)
+{
+ if (dev_id > 1 || disp_id > 1)
+ return -EINVAL;
+
+ return (dev_id << 5) | (disp_id << 4);
+}
+
+static struct mipi_dsi_bus_mux imx6q_mipi_dsi_mux[] = {
+ {
+ .reg = IOMUXC_GPR3,
+ .mask = IMX6Q_GPR3_MIPI_MUX_CTL_MASK,
+ .get_mux = imx6q_mipi_dsi_get_mux,
+ },
+};
+
+static int imx6dl_mipi_dsi_get_mux(int dev_id, int disp_id)
+{
+ if (dev_id > 1 || disp_id > 1)
+ return -EINVAL;
+
+ /* MIPI DSI source is LCDIF */
+ if (dev_id)
+ disp_id = 0;
+
+ return (dev_id << 5) | (disp_id << 4);
+}
+
+static struct mipi_dsi_bus_mux imx6dl_mipi_dsi_mux[] = {
+ {
+ .reg = IOMUXC_GPR3,
+ .mask = IMX6Q_GPR3_MIPI_MUX_CTL_MASK,
+ .get_mux = imx6dl_mipi_dsi_get_mux,
+ },
+};
+
+static const struct of_device_id imx_mipi_dsi_dt_ids[] = {
+ { .compatible = "fsl,imx6q-mipi-dsi", .data = imx6q_mipi_dsi_mux, },
+ { .compatible = "fsl,imx6dl-mipi-dsi", .data = imx6dl_mipi_dsi_mux, },
+ { }
+};
+MODULE_DEVICE_TABLE(of, imx_mipi_dsi_dt_ids);
+
+/**
+ * This function is called by the driver framework to initialize the MIPI DSI
+ * device.
+ *
+ * @param pdev The device structure for the MIPI DSI passed in by the
+ * driver framework.
+ *
+ * @return Returns 0 on success or negative error code on error
+ */
+static int mipi_dsi_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *of_id =
+ of_match_device(of_match_ptr(imx_mipi_dsi_dt_ids),
+ &pdev->dev);
+ struct mipi_dsi_info *mipi_dsi;
+ struct resource *res;
+ u32 dev_id, disp_id;
+ const char *lcd_panel;
+ int mux;
+ int ret = 0;
+
+ if (!np) {
+ dev_err(&pdev->dev, "failed to find device tree node\n");
+ return -ENODEV;
+ }
+
+ mipi_dsi = devm_kzalloc(&pdev->dev, sizeof(*mipi_dsi), GFP_KERNEL);
+ if (!mipi_dsi)
+ return -ENOMEM;
+
+ ret = of_property_read_string(np, "lcd_panel", &lcd_panel);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read of property lcd_panel\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "dev_id", &dev_id);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read of property dev_id\n");
+ return ret;
+ }
+ ret = of_property_read_u32(np, "disp_id", &disp_id);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read of property disp_id\n");
+ return ret;
+ }
+ mipi_dsi->dev_id = dev_id;
+ mipi_dsi->disp_id = disp_id;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get platform resource 0\n");
+ return -ENODEV;
+ }
+
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), pdev->name))
+ return -EBUSY;
+
+ mipi_dsi->mmio_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!mipi_dsi->mmio_base)
+ return -EBUSY;
+
+ mipi_dsi->irq = platform_get_irq(pdev, 0);
+ if (mipi_dsi->irq < 0) {
+ dev_err(&pdev->dev, "failed get device irq\n");
+ return -ENODEV;
+ }
+
+ ret = devm_request_irq(&pdev->dev, mipi_dsi->irq,
+ mipi_dsi_irq_handler,
+ 0, "mipi_dsi", mipi_dsi);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request irq\n");
+ return ret;
+ }
+
+ mipi_dsi->dphy_clk = devm_clk_get(&pdev->dev, "mipi_pllref_clk");
+ if (IS_ERR(mipi_dsi->dphy_clk)) {
+ dev_err(&pdev->dev, "failed to get dphy pll_ref_clk\n");
+ return PTR_ERR(mipi_dsi->dphy_clk);
+ }
+
+ mipi_dsi->cfg_clk = devm_clk_get(&pdev->dev, "mipi_cfg_clk");
+ if (IS_ERR(mipi_dsi->cfg_clk)) {
+ dev_err(&pdev->dev, "failed to get cfg_clk\n");
+ return PTR_ERR(mipi_dsi->cfg_clk);
+ }
+
+ mipi_dsi->disp_power_on = devm_regulator_get(&pdev->dev,
+ "disp-power-on");
+ if (!IS_ERR(mipi_dsi->disp_power_on)) {
+ ret = regulator_enable(mipi_dsi->disp_power_on);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable display "
+ "power regulator, err=%d\n", ret);
+ return ret;
+ }
+ } else {
+ mipi_dsi->disp_power_on = NULL;
+ }
+
+ ret = device_reset(&pdev->dev);
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "failed to reset: %d\n", ret);
+ goto dev_reset_fail;
+ }
+
+ if (of_id)
+ mipi_dsi->bus_mux = of_id->data;
+
+ mipi_dsi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
+ if (IS_ERR(mipi_dsi->regmap)) {
+ dev_err(&pdev->dev, "failed to get parent regmap\n");
+ ret = PTR_ERR(mipi_dsi->regmap);
+ goto get_parent_regmap_fail;
+ }
+
+ mux = mipi_dsi->bus_mux->get_mux(dev_id, disp_id);
+ if (mux >= 0)
+ regmap_update_bits(mipi_dsi->regmap, mipi_dsi->bus_mux->reg,
+ mipi_dsi->bus_mux->mask, (unsigned int)mux);
+ else
+ dev_warn(&pdev->dev, "invalid dev_id or disp_id muxing\n");
+
+ mipi_dsi->lcd_panel = kstrdup(lcd_panel, GFP_KERNEL);
+ if (!mipi_dsi->lcd_panel) {
+ dev_err(&pdev->dev, "failed to allocate lcd panel name\n");
+ ret = -ENOMEM;
+ goto kstrdup_fail;
+ }
+
+ mipi_dsi->pdev = pdev;
+ mipi_dsi->disp_mipi = mxc_dispdrv_register(&mipi_dsi_drv);
+ if (IS_ERR(mipi_dsi->disp_mipi)) {
+ dev_err(&pdev->dev, "mxc_dispdrv_register error\n");
+ ret = PTR_ERR(mipi_dsi->disp_mipi);
+ goto dispdrv_reg_fail;
+ }
+
+ mipi_dsi->mipi_dsi_pkt_read = mipi_dsi_pkt_read;
+ mipi_dsi->mipi_dsi_pkt_write = mipi_dsi_pkt_write;
+ mipi_dsi->mipi_dsi_dcs_cmd = mipi_dsi_dcs_cmd;
+
+ mxc_dispdrv_setdata(mipi_dsi->disp_mipi, mipi_dsi);
+ dev_set_drvdata(&pdev->dev, mipi_dsi);
+
+ dev_info(&pdev->dev, "i.MX MIPI DSI driver probed\n");
+ return ret;
+
+dispdrv_reg_fail:
+ kfree(mipi_dsi->lcd_panel);
+kstrdup_fail:
+get_parent_regmap_fail:
+dev_reset_fail:
+ if (mipi_dsi->disp_power_on)
+ regulator_disable(mipi_dsi->disp_power_on);
+ return ret;
+}
+
+static void mipi_dsi_shutdown(struct platform_device *pdev)
+{
+ struct mipi_dsi_info *mipi_dsi = dev_get_drvdata(&pdev->dev);
+
+ mipi_dsi_power_off(mipi_dsi->disp_mipi);
+}
+
+static int mipi_dsi_remove(struct platform_device *pdev)
+{
+ struct mipi_dsi_info *mipi_dsi = dev_get_drvdata(&pdev->dev);
+
+ mxc_dispdrv_puthandle(mipi_dsi->disp_mipi);
+ mxc_dispdrv_unregister(mipi_dsi->disp_mipi);
+
+ if (mipi_dsi->disp_power_on)
+ regulator_disable(mipi_dsi->disp_power_on);
+
+ kfree(mipi_dsi->lcd_panel);
+ dev_set_drvdata(&pdev->dev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver mipi_dsi_driver = {
+ .driver = {
+ .of_match_table = imx_mipi_dsi_dt_ids,
+ .name = "mxc_mipi_dsi",
+ },
+ .probe = mipi_dsi_probe,
+ .remove = mipi_dsi_remove,
+ .shutdown = mipi_dsi_shutdown,
+};
+
+static int __init mipi_dsi_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&mipi_dsi_driver);
+ if (err) {
+ pr_err("mipi_dsi_driver register failed\n");
+ return -ENODEV;
+ }
+ pr_debug("MIPI DSI driver module loaded: %s\n", mipi_dsi_driver.driver.name);
+ return 0;
+}
+
+static void __exit mipi_dsi_cleanup(void)
+{
+ platform_driver_unregister(&mipi_dsi_driver);
+}
+
+module_init(mipi_dsi_init);
+module_exit(mipi_dsi_cleanup);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX MIPI DSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/mxc/mipi_dsi.h b/drivers/video/fbdev/mxc/mipi_dsi.h
new file mode 100644
index 000000000000..62190248707c
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mipi_dsi.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2011-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2017 NXP.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __MIPI_DSI_H__
+#define __MIPI_DSI_H__
+
+#include <linux/regmap.h>
+#include "mxc_dispdrv.h"
+
+#ifdef DEBUG
+#define mipi_dbg(fmt, ...) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
+#else
+#define mipi_dbg(fmt, ...)
+#endif
+
+#define DSI_CMD_BUF_MAXSIZE (128)
+
+#define DSI_NON_BURST_WITH_SYNC_PULSE 0
+#define DSI_NON_BURST_WITH_SYNC_EVENT 1
+#define DSI_BURST_MODE 2
+
+#define DSI_HSA_PKT_OVERHEAD 10
+#define DSI_HFP_PKT_OVERHEAD 8
+#define DSI_HBP_PKT_OVERHEAD 14
+
+/* DPI interface pixel color coding map */
+enum mipi_dsi_dpi_fmt {
+ MIPI_RGB565_PACKED = 0,
+ MIPI_RGB565_LOOSELY,
+ MIPI_RGB565_CONFIG3,
+ MIPI_RGB666_PACKED,
+ MIPI_RGB666_LOOSELY,
+ MIPI_RGB888,
+};
+
+struct mipi_lcd_config {
+ u32 virtual_ch;
+ u32 data_lane_num;
+ /* device max DPHY clock in MHz unit */
+ u32 max_phy_clk;
+ enum mipi_dsi_dpi_fmt dpi_fmt;
+};
+
+struct mipi_dsi_info;
+struct mipi_dsi_lcd_callback {
+ /* callback for lcd panel operation */
+ void (*get_mipi_lcd_videomode)(struct fb_videomode **, int *,
+ struct mipi_lcd_config **);
+ int (*mipi_lcd_setup)(struct mipi_dsi_info *);
+
+};
+
+struct mipi_dsi_match_lcd {
+ char *lcd_panel;
+ struct mipi_dsi_lcd_callback lcd_callback;
+};
+
+struct mipi_dsi_bus_mux {
+ int reg;
+ int mask;
+ int (*get_mux) (int dev_id, int disp_id);
+};
+
+/* driver private data */
+struct mipi_dsi_info {
+ struct platform_device *pdev;
+ void __iomem *mmio_base;
+ void __iomem *phy_base;
+ struct regmap *regmap;
+ struct regmap *mux_sel;
+ const struct mipi_dsi_bus_mux *bus_mux;
+ int dsi_power_on;
+ int lcd_inited;
+ int encoder;
+ int traffic_mode;
+ u32 dphy_pll_config;
+ int dev_id;
+ int disp_id;
+ char *lcd_panel;
+ int irq;
+ uint32_t phy_ref_clkfreq;
+#ifdef CONFIG_FB_IMX64
+ struct clk *core_clk;
+ struct clk *phy_ref_clk;
+ struct clk *dbi_clk;
+ struct clk *rxesc_clk;
+ struct clk *txesc_clk;
+#else
+ struct clk *dphy_clk;
+ struct clk *cfg_clk;
+ struct clk *esc_clk;
+#endif
+ struct mxc_dispdrv_handle *disp_mipi;
+ int vmode_index;
+ struct fb_videomode *mode;
+ struct regulator *disp_power_on;
+ struct mipi_lcd_config *lcd_config;
+ /* board related power control */
+ struct backlight_device *bl;
+ /* callback for lcd panel operation */
+ struct mipi_dsi_lcd_callback *lcd_callback;
+
+ int (*mipi_dsi_pkt_read)(struct mipi_dsi_info *mipi,
+ u8 data_type, u32 *buf, int len);
+ int (*mipi_dsi_pkt_write)(struct mipi_dsi_info *mipi_dsi,
+ u8 data_type, const u32 *buf, int len);
+ int (*mipi_dsi_dcs_cmd)(struct mipi_dsi_info *mipi,
+ u8 cmd, const u32 *param, int num);
+};
+
+#ifdef CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL
+void mipid_hx8369_get_lcd_videomode(struct fb_videomode **mode, int *size,
+ struct mipi_lcd_config **data);
+int mipid_hx8369_lcd_setup(struct mipi_dsi_info *);
+#endif
+#ifdef CONFIG_FB_MXC_TRULY_PANEL_TFT3P5079E
+void mipid_otm8018b_get_lcd_videomode(struct fb_videomode **mode, int *size,
+ struct mipi_lcd_config **data);
+int mipid_otm8018b_lcd_setup(struct mipi_dsi_info *);
+#endif
+#ifdef CONFIG_FB_MXC_TRULY_PANEL_TFT3P5581E
+void mipid_hx8363_get_lcd_videomode(struct fb_videomode **mode, int *size,
+ struct mipi_lcd_config **data);
+int mipid_hx8363_lcd_setup(struct mipi_dsi_info *);
+#endif
+
+#ifndef CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL
+#error "Please configure MIPI LCD panel, we cannot find one!"
+#endif
+
+#endif
diff --git a/drivers/video/fbdev/mxc/mipi_dsi_northwest.c b/drivers/video/fbdev/mxc/mipi_dsi_northwest.c
new file mode 100644
index 000000000000..77b3cc3149a5
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mipi_dsi_northwest.c
@@ -0,0 +1,1543 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2017 NXP.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/bitops.h>
+#include <linux/gcd.h>
+#include <linux/mipi_dsi_northwest.h>
+#include <linux/module.h>
+#include <linux/mxcfb.h>
+#include <linux/pm_runtime.h>
+#include <linux/busfreq-imx.h>
+#include <linux/backlight.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_graph.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <video/mipi_display.h>
+#include <video/mxc_edid.h>
+#include <linux/mfd/syscon.h>
+
+#include "mipi_dsi.h"
+
+#define DISPDRV_MIPI "mipi_dsi_northwest"
+#define ROUND_UP(x) ((x)+1)
+#define NS2PS_RATIO (1000)
+#define MIPI_LCD_SLEEP_MODE_DELAY (120)
+#define MIPI_FIFO_TIMEOUT msecs_to_jiffies(250)
+#define PICOS_PER_SEC (1000000000ULL)
+#define PICOS2KHZ2(a, bpp) \
+ DIV_ROUND_CLOSEST_ULL(PICOS_PER_SEC * (bpp), (a))
+
+static struct mipi_dsi_match_lcd mipi_dsi_lcd_db[] = {
+#ifdef CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL
+ {
+ "TRULY-WVGA",
+ {mipid_hx8369_get_lcd_videomode, mipid_hx8369_lcd_setup}
+ },
+#endif
+#ifdef CONFIG_FB_MXC_TRULY_PANEL_TFT3P5079E
+ {
+ "TRULY-WVGA-TFT3P5079E",
+ {mipid_otm8018b_get_lcd_videomode, mipid_otm8018b_lcd_setup}
+ },
+#endif
+#ifdef CONFIG_FB_MXC_TRULY_PANEL_TFT3P5581E
+ {
+ "TRULY-WVGA-TFT3P5581E",
+ {mipid_hx8363_get_lcd_videomode, mipid_hx8363_lcd_setup}
+ },
+#endif
+ {
+ "", {NULL, NULL}
+ }
+};
+
+enum mipi_dsi_mode {
+ DSI_COMMAND_MODE,
+ DSI_VIDEO_MODE
+};
+
+#define DSI_LP_MODE 0
+#define DSI_HS_MODE 1
+
+enum mipi_dsi_payload {
+ DSI_PAYLOAD_CMD,
+ DSI_PAYLOAD_VIDEO,
+};
+
+struct pll_divider {
+ unsigned int cm; /* multiplier */
+ unsigned int cn; /* predivider */
+ unsigned int co; /* outdivider */
+};
+
+/**
+ * 'CM' value to 'CM' reigister config value map
+ * 'CM' = [16, 255];
+ */
+static unsigned int cm_map_table[240] = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 16 ~ 23 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 24 ~ 31 */
+
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 32 ~ 39 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 40 ~ 47 */
+
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 48 ~ 55 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 56 ~ 63 */
+
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 64 ~ 71 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 72 ~ 79 */
+
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 80 ~ 87 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 88 ~ 95 */
+
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 96 ~ 103 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 104 ~ 111 */
+
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 112 ~ 119 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 120 ~ 127 */
+
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 128 ~ 135 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 136 ~ 143 */
+
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 144 ~ 151 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 152 ~ 159 */
+
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 160 ~ 167 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 168 ~ 175 */
+
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 176 ~ 183 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 184 ~ 191 */
+
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 192 ~ 199 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 200 ~ 207 */
+
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 208 ~ 215 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 216 ~ 223 */
+
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 224 ~ 231 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 232 ~ 239 */
+
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 240 ~ 247 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f /* 248 ~ 255 */
+};
+
+/**
+ * map 'CN' value to 'CN' reigister config value
+ * 'CN' = [1, 32];
+ */
+static unsigned int cn_map_table[32] = {
+ 0x1f, 0x00, 0x10, 0x18, 0x1c, 0x0e, 0x07, 0x13, /* 1 ~ 8 */
+ 0x09, 0x04, 0x02, 0x11, 0x08, 0x14, 0x0a, 0x15, /* 9 ~ 16 */
+ 0x1a, 0x1d, 0x1e, 0x0f, 0x17, 0x1b, 0x0d, 0x16, /* 17 ~ 24 */
+ 0x0b, 0x05, 0x12, 0x19, 0x0c, 0x06, 0x03, 0x01 /* 25 ~ 32 */
+};
+
+/**
+ * map 'CO' value to 'CO' reigister config value
+ * 'CO' = { 1, 2, 4, 8 };
+ */
+static unsigned int co_map_table[4] = {
+ 0x0, 0x1, 0x2, 0x3
+};
+
+static DECLARE_COMPLETION(dsi_rx_done);
+static DECLARE_COMPLETION(dsi_tx_done);
+
+static void mipi_dsi_set_mode(struct mipi_dsi_info *mipi_dsi,
+ uint8_t mode);
+static int mipi_dsi_dcs_cmd(struct mipi_dsi_info *mipi_dsi,
+ u8 cmd, const u32 *param, int num);
+
+static int mipi_dsi_lcd_init(struct mipi_dsi_info *mipi_dsi,
+ struct mxc_dispdrv_setting *setting)
+{
+ u32 data_lane_num, max_data_rate;
+ int i, size, err = 0;
+ struct fb_videomode *mipi_lcd_modedb;
+ struct fb_videomode mode;
+ struct device *dev = &mipi_dsi->pdev->dev;
+
+ err = of_property_read_u32(dev->of_node,
+ "data-lanes-num", &data_lane_num);
+ if (err) {
+ dev_err(dev, "failed to get data lane num\n");
+ goto err0;
+ } else if (data_lane_num > 4) {
+ dev_err(dev, "invalid data lane number\n");
+ err = -EINVAL;
+ goto err0;
+ }
+
+ err = of_property_read_u32(dev->of_node,
+ "max-data-rate", &max_data_rate);
+ if (err) {
+ dev_err(dev, "failed to get max data rate\n");
+ goto err0;
+ }
+
+ if (mipi_dsi->encoder) {
+ mipi_dsi->lcd_config->virtual_ch = 0;
+ mipi_dsi->lcd_config->data_lane_num = data_lane_num;
+ mipi_dsi->lcd_config->max_phy_clk = max_data_rate;
+ mipi_dsi->lcd_config->dpi_fmt = MIPI_RGB888;
+ setting->fbi->var.bits_per_pixel = 32;
+
+ /* TODO Add bandwidth check */
+
+ if (setting->fbi->fbops->fb_check_var)
+ err = setting->fbi->fbops->fb_check_var(&setting->fbi->var,
+ setting->fbi);
+ if (err)
+ goto err0;
+
+ err = fb_add_videomode(mipi_dsi->mode,
+ &setting->fbi->modelist);
+ if (err)
+ goto err0;
+
+ fb_videomode_to_var(&setting->fbi->var, mipi_dsi->mode);
+ setting->fbi->mode = mipi_dsi->mode;
+err0:
+ return err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mipi_dsi_lcd_db); i++) {
+ if (!strcmp(mipi_dsi->lcd_panel,
+ mipi_dsi_lcd_db[i].lcd_panel)) {
+ mipi_dsi->lcd_callback =
+ &mipi_dsi_lcd_db[i].lcd_callback;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(mipi_dsi_lcd_db)) {
+ dev_err(dev, "failed to find supported lcd panel.\n");
+ return -EINVAL;
+ }
+
+ /* set default bpp to 32 if not set*/
+ if (!setting->default_bpp)
+ setting->default_bpp = 32;
+
+ mipi_dsi->lcd_callback->get_mipi_lcd_videomode(&mipi_lcd_modedb, &size,
+ &mipi_dsi->lcd_config);
+
+ err = fb_find_mode(&setting->fbi->var, setting->fbi,
+ setting->dft_mode_str,
+ mipi_lcd_modedb, size, NULL,
+ setting->default_bpp);
+ if (err != 1)
+ fb_videomode_to_var(&setting->fbi->var, mipi_lcd_modedb);
+
+ INIT_LIST_HEAD(&setting->fbi->modelist);
+ for (i = 0; i < size; i++) {
+ fb_var_to_videomode(&mode, &setting->fbi->var);
+ if (fb_mode_is_equal(&mode, mipi_lcd_modedb + i)) {
+ err = fb_add_videomode(mipi_lcd_modedb + i,
+ &setting->fbi->modelist);
+ mipi_dsi->mode = mipi_lcd_modedb + i;
+ break;
+ }
+ }
+
+ if ((err < 0) || (size == i)) {
+ dev_err(dev, "failed to add videomode.\n");
+ return err;
+ }
+
+ setting->fbi->mode = mipi_dsi->mode;
+
+ return 0;
+}
+
+static int mipi_dsi_disp_init(struct mxc_dispdrv_handle *disp,
+ struct mxc_dispdrv_setting *setting)
+{
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+ struct device *dev = &mipi_dsi->pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct reset_control *reset = NULL;
+ int ret = 0;
+
+ if (!mipi_dsi->encoder) {
+ reset = of_reset_control_get(np, NULL);
+ if (IS_ERR(reset))
+ return PTR_ERR(reset);
+ }
+
+ ret = mipi_dsi_lcd_init(mipi_dsi, setting);
+ if (ret) {
+ dev_err(dev, "failed to init mipi dsi lcd\n");
+ goto out;
+ }
+
+ dev_info(dev, "MIPI DSI dispdv inited\n");
+
+out:
+ if (!mipi_dsi->encoder)
+ reset_control_put(reset);
+
+ return ret;
+}
+
+static void mipi_dsi_disp_deinit(struct mxc_dispdrv_handle *disp)
+{
+ struct mipi_dsi_info *mipi_dsi;
+
+ mipi_dsi = mxc_dispdrv_getdata(disp);
+
+ if (mipi_dsi->bl)
+ backlight_device_unregister(mipi_dsi->bl);
+}
+
+static void mipi_dsi_set_mode(struct mipi_dsi_info *mipi_dsi,
+ uint8_t mode)
+{
+ uint32_t pkt_control;
+
+ pkt_control = readl(mipi_dsi->mmio_base + HOST_PKT_CONTROL);
+
+ switch (mode) {
+ case DSI_LP_MODE:
+ writel(0x1, mipi_dsi->mmio_base + HOST_CFG_NONCONTINUOUS_CLK);
+ break;
+ case DSI_HS_MODE:
+ writel(0x0, mipi_dsi->mmio_base + HOST_CFG_NONCONTINUOUS_CLK);
+ break;
+ default:
+ dev_err(&mipi_dsi->pdev->dev,
+ "invalid dsi mode\n");
+ return;
+ }
+
+ mdelay(1);
+}
+
+static uint32_t fmt_to_bpp(enum mipi_dsi_dpi_fmt dpi_fmt)
+{
+ switch (dpi_fmt) {
+ case MIPI_RGB888:
+ return 24;
+ case MIPI_RGB565_PACKED:
+ return 16;
+ default:
+ return 0;
+ }
+}
+
+/*
+static void dphy_calc_dividers(int *cm, int *cn, int *co)
+{
+}
+*/
+
+static int mipi_dsi_dphy_init(struct mipi_dsi_info *mipi_dsi)
+{
+ int i, best_div = -1;
+ int64_t delta;
+ uint64_t least_delta = ~0U;
+ uint32_t bpp, time_out = 100;
+ uint32_t lock;
+ uint32_t req_bit_clk;
+ uint64_t limit, div_result;
+ uint64_t denominator, numerator, divisor;
+ uint64_t norm_denom, norm_num, split_denom;
+ struct pll_divider div = { 0 };
+ struct fb_videomode *mode = mipi_dsi->mode;
+ struct mipi_lcd_config *lcd_config = mipi_dsi->lcd_config;
+
+#ifndef CONFIG_FB_IMX64
+ regmap_update_bits(mipi_dsi->regmap, SIM_SOPT1,
+ MIPI_ISO_DISABLE, MIPI_ISO_DISABLE);
+#endif
+
+ bpp = fmt_to_bpp(lcd_config->dpi_fmt);
+ req_bit_clk = PICOS2KHZ2(mode->pixclock, bpp) * 1000U;
+
+ switch (lcd_config->data_lane_num) {
+ case 1:
+ break;
+ case 2:
+ req_bit_clk = req_bit_clk >> 1;
+ break;
+ case 4:
+ req_bit_clk = req_bit_clk >> 2;
+ break;
+ default:
+ dev_err(&mipi_dsi->pdev->dev,
+ "requested data lane num is invalid\n");
+ return -EINVAL;
+ }
+
+ if (mipi_dsi->encoder) {
+ if (req_bit_clk > lcd_config->max_phy_clk)
+ return -EINVAL;
+ }
+
+ /* calc CM, CN and CO according to PHY PLL formula:
+ *
+ * 'PLL out bitclk = refclk * CM / (CN * CO);'
+ *
+ * Let:
+ * 'numerator = bitclk / divisor';
+ * 'denominator = refclk / divisor';
+ * Then:
+ * 'numerator / denominator = CM / (CN * CO)';
+ *
+ * CM is in [16, 255]
+ * CN is in [1, 32]
+ * CO is in { 1, 2, 4, 8 };
+ */
+ divisor = gcd(mipi_dsi->phy_ref_clkfreq, req_bit_clk);
+ WARN_ON(divisor == 1);
+
+ div_result = req_bit_clk;
+ do_div(div_result, divisor);
+ numerator = div_result;
+
+ div_result = mipi_dsi->phy_ref_clkfreq;
+ do_div(div_result, divisor);
+ denominator = div_result;
+
+ /* denominator & numerator out of range check */
+ if (DIV_ROUND_CLOSEST_ULL(numerator, denominator) > 255 ||
+ DIV_ROUND_CLOSEST_ULL(denominator, numerator) > 32 * 8)
+ return -EINVAL;
+
+ /* Normalization: reduce or increase
+ * numerator to [16, 255]
+ * denominator to [1, 32 * 8]
+ * Reduce normalization result is 'approximiate'
+ * Increase nomralization result is 'precise'
+ */
+ if (numerator > 255 || denominator > 32 * 8) {
+ /* approximate */
+ if (likely(numerator > denominator)) {
+ /* 'numerator > 255';
+ * 'limit' should meet below conditions:
+ * a. '(numerator / limit) >= 16'
+ * b. '(denominator / limit) >= 1'
+ */
+ limit = min(denominator,
+ DIV_ROUND_CLOSEST_ULL(numerator, 16));
+
+ /* Let:
+ * norm_num = numerator / i;
+ * norm_denom = denominator / i;
+ *
+ * So:
+ * delta = numerator * norm_denom -
+ * denominator * norm_num
+ */
+ for (i = 2; i <= limit; i++) {
+ norm_num = DIV_ROUND_CLOSEST_ULL(numerator, i);
+ if (norm_num > 255)
+ continue;
+
+ norm_denom = DIV_ROUND_CLOSEST_ULL(denominator, i);
+
+ /* 'norm_num <= 255' && 'norm_num > norm_denom'
+ * so, 'norm_denom < 256'
+ */
+ delta = numerator * norm_denom -
+ denominator * norm_num;
+ delta = abs(delta);
+ if (delta < least_delta) {
+ least_delta = delta;
+ best_div = i;
+ } else if (delta == least_delta) {
+ /* choose better one IF:
+ * 'norm_denom' derived from last 'best_div'
+ * needs later split, i.e, 'norm_denom > 32'.
+ */
+ if (DIV_ROUND_CLOSEST_ULL(denominator, best_div) > 32) {
+ least_delta = delta;
+ best_div = i;
+ }
+ }
+ }
+ } else {
+ /* 'denominator > 32 * 8';
+ * 'limit' should meet below conditions:
+ * a. '(numerator / limit >= 16'
+ * b. '(denominator / limit >= 1': obviously.
+ */
+ limit = DIV_ROUND_CLOSEST_ULL(numerator, 16);
+ if (!limit ||
+ DIV_ROUND_CLOSEST_ULL(denominator, limit) > 32 * 8)
+ return -EINVAL;
+
+ for (i = 2; i <= limit; i++) {
+ norm_denom = DIV_ROUND_CLOSEST_ULL(denominator, i);
+ if (norm_denom > 32 * 8)
+ continue;
+
+ norm_num = DIV_ROUND_CLOSEST_ULL(numerator, i);
+
+ /* 'norm_denom <= 256' && 'norm_num < norm_denom'
+ * so, 'norm_num <= 255'
+ */
+ delta = numerator * norm_denom -
+ denominator * norm_num;
+ delta = abs(delta);
+ if (delta < least_delta) {
+ least_delta = delta;
+ best_div = i;
+ } else if (delta == least_delta) {
+ if (DIV_ROUND_CLOSEST_ULL(denominator, best_div) > 32) {
+ least_delta = delta;
+ best_div = i;
+ }
+ }
+ }
+ }
+
+ numerator = DIV_ROUND_CLOSEST_ULL(numerator, best_div);
+ denominator = DIV_ROUND_CLOSEST_ULL(denominator, best_div);
+ } else if (numerator < 16) {
+ /* precise */
+
+ /* 'limit' should meet below conditions:
+ * a. 'denominator * limit <= 32 * 8'
+ * b. '16 <= numerator * limit <= 255'
+ * Choose 'limit' to be the least value
+ * which makes 'numerator * limit' to be
+ * in [16, 255].
+ */
+ limit = min(256 / (uint32_t)denominator,
+ 255 / (uint32_t)numerator);
+ if (limit == 1 || limit < DIV_ROUND_UP_ULL(16, numerator))
+ return -EINVAL;
+
+ /* choose the least available value for 'limit' */
+ limit = DIV_ROUND_UP_ULL(16, numerator);
+ numerator = numerator * limit;
+ denominator = denominator * limit;
+
+ WARN_ON(numerator < 16 || denominator > 32 * 8);
+ }
+
+ div.cm = cm_map_table[numerator - 16];
+
+ /* split 'denominator' to 'CN' and 'CO' */
+ if (denominator > 32) {
+ /* traverse four possible values of 'CO'
+ * there must be some value of 'CO' can be used
+ */
+ least_delta = ~0U;
+ for (i = 0; i < 4; i++) {
+ split_denom = DIV_ROUND_CLOSEST_ULL(denominator, 1 << i);
+ if (split_denom > 32)
+ continue;
+
+ /* calc deviation to choose the best one */
+ delta = denominator - split_denom * (1 << i);
+ delta = abs(delta);
+ if (delta < least_delta) {
+ least_delta = delta;
+ div.co = co_map_table[i];
+ div.cn = cn_map_table[split_denom - 1];
+ }
+ }
+ } else {
+ div.co = co_map_table[1 >> 1];
+ div.cn = cn_map_table[denominator - 1];
+ }
+
+ writel(div.cn, mipi_dsi->mmio_base + DPHY_CN);
+ writel(div.cm, mipi_dsi->mmio_base + DPHY_CM);
+ writel(div.co, mipi_dsi->mmio_base + DPHY_CO);
+
+ writel(0x25, mipi_dsi->mmio_base + DPHY_TST);
+ writel(0x0, mipi_dsi->mmio_base + DPHY_PD_PLL);
+
+ while(!(lock = readl(mipi_dsi->mmio_base + DPHY_LOCK))) {
+ udelay(10);
+ time_out--;
+ if (time_out == 0) {
+ dev_err(&mipi_dsi->pdev->dev, "cannot get the dphy lock = 0x%x\n", lock);
+ return -EINVAL;
+ }
+ }
+
+ dev_dbg(&mipi_dsi->pdev->dev, "%s: dphy lock = 0x%x\n", __func__, lock);
+
+ writel(0x0, mipi_dsi->mmio_base + DPHY_LOCK_BYP);
+ writel(0x1, mipi_dsi->mmio_base + DPHY_RTERM_SEL);
+ writel(0x0, mipi_dsi->mmio_base + DPHY_AUTO_PD_EN);
+ writel(0x1, mipi_dsi->mmio_base + DPHY_RXLPRP);
+ writel(0x1, mipi_dsi->mmio_base + DPHY_RXCDRP);
+ writel(0x0, mipi_dsi->mmio_base + DPHY_M_PRG_HS_PREPARE);
+ writel(0x0, mipi_dsi->mmio_base + DPHY_MC_PRG_HS_PREPARE);
+ writel(0x9, mipi_dsi->mmio_base + DPHY_M_PRG_HS_ZERO);
+ writel(0x20, mipi_dsi->mmio_base + DPHY_MC_PRG_HS_ZERO);
+ writel(0x5, mipi_dsi->mmio_base + DPHY_M_PRG_HS_TRAIL);
+ writel(0x5, mipi_dsi->mmio_base + DPHY_MC_PRG_HS_TRAIL);
+ writel(0x0, mipi_dsi->mmio_base + DPHY_PD_DPHY);
+
+#ifndef CONFIG_FB_IMX64
+ regmap_update_bits(mipi_dsi->regmap, SIM_SOPT1CFG,
+ DSI_PLL_EN, DSI_PLL_EN);
+#endif
+
+ return 0;
+}
+
+static int mipi_dsi_host_init(struct mipi_dsi_info *mipi_dsi)
+{
+ uint32_t lane_num;
+ struct mipi_lcd_config *lcd_config = mipi_dsi->lcd_config;
+
+ switch (lcd_config->data_lane_num) {
+ case 1:
+ lane_num = 0x0;
+ break;
+ case 2:
+ lane_num = 0x1;
+ break;
+ case 4:
+ lane_num = 0x3;
+ break;
+ default:
+ /* Invalid lane num */
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_FB_IMX64_DEBUG
+ printk("%s: data_lane_num = %d\n", __func__, lcd_config->data_lane_num);
+#endif
+
+ writel(lane_num, mipi_dsi->mmio_base + HOST_CFG_NUM_LANES);
+ writel(mipi_dsi->encoder ? 0x0 : 0x1,
+ mipi_dsi->mmio_base + HOST_CFG_NONCONTINUOUS_CLK);
+ writel(0x1, mipi_dsi->mmio_base + HOST_CFG_T_PRE);
+ writel(52, mipi_dsi->mmio_base + HOST_CFG_T_POST);
+ writel(13, mipi_dsi->mmio_base + HOST_CFG_TX_GAP);
+ writel(mipi_dsi->encoder ? 0x0 : 0x1,
+ mipi_dsi->mmio_base + HOST_CFG_AUTOINSERT_EOTP);
+ writel(0x0, mipi_dsi->mmio_base + HOST_CFG_EXTRA_CMDS_AFTER_EOTP);
+ writel(0x0, mipi_dsi->mmio_base + HOST_CFG_HTX_TO_COUNT);
+ writel(0x0, mipi_dsi->mmio_base + HOST_CFG_LRX_H_TO_COUNT);
+ writel(0x0, mipi_dsi->mmio_base + HOST_CFG_BTA_H_TO_COUNT);
+ writel(0x3A98, mipi_dsi->mmio_base + HOST_CFG_TWAKEUP);
+
+ return 0;
+}
+
+static int mipi_dsi_dpi_init(struct mipi_dsi_info *mipi_dsi)
+{
+ uint32_t bpp, color_coding, pixel_fmt;
+ uint32_t pixel_fifo_level, hfp_period, hbp_period, hsa_period;
+ struct fb_videomode *mode = mipi_dsi->mode;
+ struct mipi_lcd_config *lcd_config = mipi_dsi->lcd_config;
+
+ bpp = fmt_to_bpp(lcd_config->dpi_fmt);
+
+ writel(mode->xres, mipi_dsi->mmio_base + DPI_PIXEL_PAYLOAD_SIZE);
+
+ switch (mipi_dsi->traffic_mode) {
+ case DSI_NON_BURST_WITH_SYNC_PULSE:
+#ifdef CONFIG_FB_IMX64
+ pixel_fifo_level = 8;
+ hfp_period = mode->right_margin - DSI_HFP_PKT_OVERHEAD;
+ hbp_period = mode->left_margin - DSI_HBP_PKT_OVERHEAD;
+ hsa_period = mode->hsync_len - DSI_HSA_PKT_OVERHEAD;
+#else
+ pixel_fifo_level = mode->xres;
+ hfp_period = 0x10;
+ hbp_period = 0x60;
+ hsa_period = 0xf0;
+#endif
+ break;
+ case DSI_BURST_MODE:
+ pixel_fifo_level = mode->xres;
+#ifdef CONFIG_FB_IMX64
+ hfp_period = mode->right_margin;
+ hbp_period = mode->left_margin;
+ hsa_period = mode->hsync_len;
+#else
+ hfp_period = mode->right_margin * (bpp >> 3);
+ hbp_period = mode->left_margin * (bpp >> 3);
+ hsa_period = mode->hsync_len * (bpp >> 3);
+#endif
+ break;
+ default:
+ pr_debug("unsupport traffic mode: %d\n",
+ mipi_dsi->traffic_mode);
+ return -EINVAL;
+ }
+ writel(pixel_fifo_level, mipi_dsi->mmio_base + DPI_PIXEL_FIFO_SEND_LEVEL);
+
+ switch (bpp) {
+ case 24:
+ color_coding = 5;
+ pixel_fmt = 3;
+ break;
+ case 16:
+ case 18:
+ default:
+ break;
+ }
+ writel(color_coding, mipi_dsi->mmio_base + DPI_INTERFACE_COLOR_CODING);
+ writel(pixel_fmt, mipi_dsi->mmio_base + DPI_PIXEL_FORMAT);
+#ifdef CONFIG_FB_IMX64
+ writel(0x1, mipi_dsi->mmio_base + DPI_VSYNC_POLARITY);
+ writel(0x1, mipi_dsi->mmio_base + DPI_HSYNC_POLARITY);
+#else
+ writel(0x0, mipi_dsi->mmio_base + DPI_VSYNC_POLARITY);
+ writel(0x0, mipi_dsi->mmio_base + DPI_HSYNC_POLARITY);
+#endif
+ writel(mipi_dsi->traffic_mode,
+ mipi_dsi->mmio_base + DPI_VIDEO_MODE);
+
+ writel(hfp_period, mipi_dsi->mmio_base + DPI_HFP);
+ writel(hbp_period, mipi_dsi->mmio_base + DPI_HBP);
+ writel(hsa_period, mipi_dsi->mmio_base + DPI_HSA);
+
+ writel(0x0, mipi_dsi->mmio_base + DPI_ENABLE_MULT_PKTS);
+
+ writel(mode->upper_margin, mipi_dsi->mmio_base + DPI_VBP);
+ writel(mode->lower_margin, mipi_dsi->mmio_base + DPI_VFP);
+ writel(0x1, mipi_dsi->mmio_base + DPI_BLLP_MODE);
+ writel(0x0, mipi_dsi->mmio_base + DPI_USE_NULL_PKT_BLLP);
+
+ writel(mode->yres - 1, mipi_dsi->mmio_base + DPI_VACTIVE);
+
+ writel(0x0, mipi_dsi->mmio_base + DPI_VC);
+
+ return 0;
+}
+
+static void mipi_dsi_init_interrupt(struct mipi_dsi_info *mipi_dsi)
+{
+ uint32_t irqs_enable;
+
+ /* disable all the irqs */
+ writel(0xffffffff, mipi_dsi->mmio_base + HOST_IRQ_MASK);
+ writel(0x7, mipi_dsi->mmio_base + HOST_IRQ_MASK2);
+
+ irqs_enable = ~(HOST_IRQ_MASK_TX_PKT_DONE_MASK |
+ HOST_IRQ_MASK_RX_PKT_HDR_RCVD_MASK);
+
+ writel(irqs_enable, mipi_dsi->mmio_base + HOST_IRQ_MASK);
+}
+
+static int mipi_display_enter_sleep(struct mxc_dispdrv_handle *disp)
+{
+ int err;
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+
+ err = mipi_dsi_dcs_cmd(mipi_dsi, MIPI_DCS_SET_DISPLAY_OFF,
+ NULL, 0);
+ if (err)
+ return -EINVAL;
+ msleep(50);
+
+ err = mipi_dsi_dcs_cmd(mipi_dsi, MIPI_DCS_ENTER_SLEEP_MODE,
+ NULL, 0);
+ if (err) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "MIPI DSI DCS Command sleep in error!\n");
+ }
+ msleep(MIPI_LCD_SLEEP_MODE_DELAY);
+
+ return err;
+}
+
+static int mipi_display_exit_sleep(struct mxc_dispdrv_handle *disp)
+{
+ int err;
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+
+ err = mipi_dsi_dcs_cmd(mipi_dsi, MIPI_DCS_EXIT_SLEEP_MODE,
+ NULL, 0);
+ if (err) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "MIPI DSI DCS Command sleep-out error!\n");
+ return err;
+ }
+ msleep(MIPI_LCD_SLEEP_MODE_DELAY);
+
+ err = mipi_dsi_dcs_cmd(mipi_dsi, MIPI_DCS_SET_DISPLAY_ON,
+ NULL, 0);
+ msleep(20);
+
+ return err;
+}
+
+static void reset_dsi_domains(struct mipi_dsi_info *mipi_dsi, bool reset)
+{
+#ifdef CONFIG_FB_IMX64
+ /* pclk domain */
+ regmap_update_bits(mipi_dsi->regmap, SRC_MIPIPHY_RCR,
+ MIPI_DSI_PCLK_RESET_N, (reset ? 0 : MIPI_DSI_PCLK_RESET_N));
+ /* escape domain */
+ regmap_update_bits(mipi_dsi->regmap, SRC_MIPIPHY_RCR,
+ MIPI_DSI_ESC_RESET_N, (reset ? 0 : MIPI_DSI_ESC_RESET_N));
+ /* byte domain */
+ regmap_update_bits(mipi_dsi->regmap, SRC_MIPIPHY_RCR,
+ MIPI_DSI_RESET_BYTE_N, (reset ? 0 : MIPI_DSI_RESET_BYTE_N));
+ /* dpi domain */
+ regmap_update_bits(mipi_dsi->regmap, SRC_MIPIPHY_RCR,
+ MIPI_DSI_DPI_RESET_N, (reset ? 0 : MIPI_DSI_DPI_RESET_N));
+#else
+ /* escape domain */
+ regmap_update_bits(mipi_dsi->regmap, SIM_SOPT1CFG,
+ DSI_RST_ESC_N, (reset ? 0 : DSI_RST_ESC_N));
+ /* byte domain */
+ regmap_update_bits(mipi_dsi->regmap, SIM_SOPT1CFG,
+ DSI_RST_BYTE_N, (reset ? 0 : DSI_RST_BYTE_N));
+
+ /* dpi domain */
+ regmap_update_bits(mipi_dsi->regmap, SIM_SOPT1CFG,
+ DSI_RST_DPI_N, (reset ? 0 : DSI_RST_DPI_N));
+#endif
+}
+
+static int mipi_dsi_enable(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
+{
+ int ret;
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+
+#ifndef CONFIG_FB_IMX64
+ if (!mipi_dsi->dsi_power_on)
+ pm_runtime_get_sync(&mipi_dsi->pdev->dev);
+#endif
+
+ if (!mipi_dsi->lcd_inited) {
+#ifdef CONFIG_FB_IMX64
+ reset_dsi_domains(mipi_dsi, 0);
+#else
+ ret = clk_set_rate(mipi_dsi->esc_clk, 80000000);
+ if (ret) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "clk enable error: %d!\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(mipi_dsi->esc_clk);
+ if (ret) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "clk enable error: %d!\n", ret);
+ return -EINVAL;
+ }
+#endif
+
+ if ((ret = mipi_dsi_dphy_init(mipi_dsi)) < 0)
+ return ret;
+
+ if ((ret = mipi_dsi_host_init(mipi_dsi)) < 0)
+ return ret;
+
+ mipi_dsi_dpi_init(mipi_dsi);
+
+#ifndef CONFIG_FB_IMX64
+ reset_dsi_domains(mipi_dsi, 0);
+
+ /* display_en */
+ regmap_update_bits(mipi_dsi->regmap, SIM_SOPT1CFG,
+ DSI_SD, 0x0);
+ /* normal cm */
+ regmap_update_bits(mipi_dsi->regmap, SIM_SOPT1CFG,
+ DSI_CM, 0x0);
+#endif
+ msleep(20);
+
+ if (!mipi_dsi->encoder) {
+ ret = device_reset(&mipi_dsi->pdev->dev);
+ if (ret) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "failed to reset device: %d\n", ret);
+ return -EINVAL;
+ }
+ msleep(60);
+
+ mipi_dsi_init_interrupt(mipi_dsi);
+
+ ret = mipi_dsi->lcd_callback->mipi_lcd_setup(mipi_dsi);
+ if (ret < 0) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "failed to init mipi lcd.\n");
+ return ret;
+ }
+ mipi_dsi_set_mode(mipi_dsi, DSI_HS_MODE);
+ }
+
+ mipi_dsi->lcd_inited = 1;
+ } else {
+#ifndef CONFIG_FB_IMX64
+ ret = clk_prepare_enable(mipi_dsi->esc_clk);
+ if (ret) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "clk enable error: %d!\n", ret);
+ return -EINVAL;
+ }
+#endif
+
+ reset_dsi_domains(mipi_dsi, 0);
+
+ if (!mipi_dsi->encoder) {
+ ret = mipi_display_exit_sleep(mipi_dsi->disp_mipi);
+ if (ret) {
+ dev_err(&mipi_dsi->pdev->dev, "exit sleep failed\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void mipi_dsi_wr_tx_header(struct mipi_dsi_info *mipi_dsi,
+ u8 di, u8 data0, u8 data1, u8 mode, u8 need_bta)
+{
+ uint32_t pkt_control = 0;
+ uint16_t word_count = 0;
+
+ word_count = data0 | (data1 << 8);
+ pkt_control = HOST_PKT_CONTROL_WC(word_count) |
+ HOST_PKT_CONTROL_VC(0) |
+ HOST_PKT_CONTROL_DT(di) |
+ HOST_PKT_CONTROL_HS_SEL(mode) |
+ HOST_PKT_CONTROL_BTA_TX(need_bta);
+
+ dev_dbg(&mipi_dsi->pdev->dev, "pkt_control = %x\n", pkt_control);
+ writel(pkt_control, mipi_dsi->mmio_base + HOST_PKT_CONTROL);
+}
+
+static void mipi_dsi_wr_tx_data(struct mipi_dsi_info *mipi_dsi,
+ uint32_t tx_data)
+{
+ writel(tx_data, mipi_dsi->mmio_base + HOST_TX_PAYLOAD);
+}
+
+static void mipi_dsi_long_data_wr(struct mipi_dsi_info *mipi_dsi,
+ const uint8_t *data0, uint32_t data_size)
+{
+ uint32_t data_cnt = 0, payload = 0;
+
+ /* in case that data count is more than 4 */
+ for (data_cnt = 0; data_cnt < data_size; data_cnt += 4) {
+ /*
+ * after sending 4bytes per one time,
+ * send remainder data less then 4.
+ */
+ if ((data_size - data_cnt) < 4) {
+ if ((data_size - data_cnt) == 3) {
+ payload = data0[data_cnt] |
+ (data0[data_cnt + 1] << 8) |
+ (data0[data_cnt + 2] << 16);
+ dev_dbg(&mipi_dsi->pdev->dev, "count = 3 payload = %x, %x %x %x\n",
+ payload, data0[data_cnt], data0[data_cnt + 1], data0[data_cnt + 2]);
+ } else if ((data_size - data_cnt) == 2) {
+ payload = data0[data_cnt] |
+ (data0[data_cnt + 1] << 8);
+ dev_dbg(&mipi_dsi->pdev->dev, "count = 2 payload = %x, %x %x\n",
+ payload, data0[data_cnt], data0[data_cnt + 1]);
+ } else if ((data_size - data_cnt) == 1) {
+ payload = data0[data_cnt];
+ dev_dbg(&mipi_dsi->pdev->dev, "count = 1 payload = %x, %x\n",
+ payload, data0[data_cnt]);
+ }
+
+ mipi_dsi_wr_tx_data(mipi_dsi, payload);
+ } else {
+ payload = data0[data_cnt] |
+ (data0[data_cnt + 1] << 8) |
+ (data0[data_cnt + 2] << 16) |
+ (data0[data_cnt + 3] << 24);
+
+ dev_dbg(&mipi_dsi->pdev->dev,
+ "count = 4 payload = %x, %x %x %x %x\n",
+ payload, *(u8 *)(data0 + data_cnt),
+ data0[data_cnt + 1],
+ data0[data_cnt + 2],
+ data0[data_cnt + 3]);
+
+ mipi_dsi_wr_tx_data(mipi_dsi, payload);
+ }
+ }
+}
+
+static int mipi_dsi_pkt_write(struct mipi_dsi_info *mipi_dsi,
+ u8 data_type, const u32 *buf, int len)
+{
+ int ret = 0;
+ struct platform_device *pdev = mipi_dsi->pdev;
+ const uint8_t *data = (const uint8_t *)buf;
+
+ if (len == 0)
+ /* handle generic long write command */
+ mipi_dsi_wr_tx_header(mipi_dsi, data_type, data[0], data[1], DSI_LP_MODE, 0);
+ else {
+ reinit_completion(&dsi_tx_done);
+
+ /* handle generic long write command */
+ mipi_dsi_long_data_wr(mipi_dsi, data, len);
+ mipi_dsi_wr_tx_header(mipi_dsi, data_type, len & 0xff,
+ (len & 0xff00) >> 8, DSI_LP_MODE, 0);
+ }
+
+ /* send packet */
+ writel(0x1, mipi_dsi->mmio_base + HOST_SEND_PACKET);
+ ret = wait_for_completion_timeout(&dsi_tx_done, MIPI_FIFO_TIMEOUT);
+
+ if (!ret) {
+ dev_err(&pdev->dev, "wait tx done timeout!\n");
+ return -ETIMEDOUT;
+ }
+ mdelay(10);
+
+ return 0;
+}
+
+static uint32_t mipi_dsi_rd_rx_header(struct mipi_dsi_info *mipi_dsi)
+{
+ return readl(mipi_dsi->mmio_base + HOST_PKT_RX_PKT_HEADER);
+}
+
+static int mipi_dsi_pkt_read(struct mipi_dsi_info *mipi_dsi,
+ uint8_t data_type, uint32_t *buf, int len)
+{
+ int ret;
+ uint32_t rx_hdr;
+ struct platform_device *pdev = mipi_dsi->pdev;
+ const uint8_t *data = (const uint8_t *)buf;
+
+ if (len <= 4) {
+ reinit_completion(&dsi_rx_done);
+
+ mipi_dsi_wr_tx_header(mipi_dsi, data_type, data[0], data[1], DSI_LP_MODE, 1);
+ writel(0x1, mipi_dsi->mmio_base + HOST_SEND_PACKET);
+
+ ret = wait_for_completion_timeout(&dsi_rx_done, MIPI_FIFO_TIMEOUT);
+ if (!ret) {
+ dev_err(&pdev->dev, "wait rx done timeout!\n");
+ return -ETIMEDOUT;
+ }
+
+ rx_hdr = mipi_dsi_rd_rx_header(mipi_dsi);
+ dev_dbg(&pdev->dev, "rx: rx_hdr = 0x%x, data type = 0x%x, word_count = 0x%x\n",
+ rx_hdr, (rx_hdr >> 16) & 0x3f, rx_hdr & 0xffff);
+
+ buf[0] = rx_hdr & 0xff;
+ } else {
+ /* TODO: add support later */
+ }
+
+ return 0;
+}
+
+static int mipi_dsi_dcs_cmd(struct mipi_dsi_info *mipi_dsi,
+ u8 cmd, const u32 *param, int num)
+{
+ int err = 0;
+ u32 buf[DSI_CMD_BUF_MAXSIZE];
+
+ switch (cmd) {
+ case MIPI_DCS_EXIT_SLEEP_MODE:
+ case MIPI_DCS_ENTER_SLEEP_MODE:
+ case MIPI_DCS_SET_DISPLAY_ON:
+ case MIPI_DCS_SET_DISPLAY_OFF:
+ buf[0] = cmd;
+ buf[1] = 0x0;
+ err = mipi_dsi_pkt_write(mipi_dsi,
+ MIPI_DSI_DCS_SHORT_WRITE, buf, 0);
+ break;
+
+ default:
+ dev_err(&mipi_dsi->pdev->dev,
+ "MIPI DSI DCS Command:0x%x Not supported!\n", cmd);
+ break;
+ }
+
+ return err;
+}
+
+static void mipi_dsi_disable(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
+{
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+
+ if (!mipi_dsi->encoder)
+ mipi_display_enter_sleep(mipi_dsi->disp_mipi);
+
+#ifndef CONFIG_FB_IMX64
+ clk_disable_unprepare(mipi_dsi->esc_clk);
+#endif
+ reset_dsi_domains(mipi_dsi, 1);
+#ifdef CONFIG_FB_IMX64
+ regmap_update_bits(mipi_dsi->regmap, SRC_MIPIPHY_RCR,
+ MIPI_DSI_PCLK_RESET_N, 0x0);
+#else
+ regmap_update_bits(mipi_dsi->regmap, SIM_SOPT1CFG,
+ DSI_PLL_EN, 0x0);
+#endif
+}
+
+static int mipi_dsi_setup(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
+{
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+ int xres_virtual = fbi->var.xres_virtual;
+ int yres_virtual = fbi->var.yres_virtual;
+ int xoffset = fbi->var.xoffset;
+ int yoffset = fbi->var.yoffset;
+ int pixclock = fbi->var.pixclock;
+
+ if (!mipi_dsi->mode)
+ return 0;
+
+ /* set the mode back to var in case userspace changes it */
+ fb_videomode_to_var(&fbi->var, mipi_dsi->mode);
+
+ /* restore some var entries cached */
+ fbi->var.xres_virtual = xres_virtual;
+ fbi->var.yres_virtual = yres_virtual;
+ fbi->var.xoffset = xoffset;
+ fbi->var.yoffset = yoffset;
+ fbi->var.pixclock = pixclock;
+
+ return 0;
+}
+
+static struct mxc_dispdrv_driver mipi_dsi_drv = {
+ .name = DISPDRV_MIPI,
+ .init = mipi_dsi_disp_init,
+ .deinit = mipi_dsi_disp_deinit,
+ .enable = mipi_dsi_enable,
+ .disable = mipi_dsi_disable,
+ .setup = mipi_dsi_setup,
+};
+
+static irqreturn_t mipi_dsi_irq_handler(int irq, void *data)
+{
+ uint32_t irq_status;
+ struct mipi_dsi_info *mipi_dsi = data;
+ struct platform_device *pdev = mipi_dsi->pdev;
+
+ irq_status = readl(mipi_dsi->mmio_base + HOST_IRQ_STATUS);
+
+ dev_dbg(&pdev->dev, "irq_status = 0x%x\n", irq_status);
+
+ if (irq_status & HOST_IRQ_STATUS_TX_PKT_DONE) {
+ dev_dbg(&pdev->dev, "payload tx finished\n");
+ complete(&dsi_tx_done);
+ }
+
+ if (irq_status & HOST_IRQ_STATUS_RX_PKT_HDR_RCVD) {
+ dev_dbg(&pdev->dev, "rx data finished\n");
+ complete(&dsi_rx_done);
+ }
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_FB_IMX64
+static int dsi_clks_init(struct mipi_dsi_info *minfo)
+{
+ int ret = 0;
+ struct platform_device *pdev = minfo->pdev;
+ struct device_node *np = pdev->dev.of_node;
+
+ minfo->core_clk = devm_clk_get(&pdev->dev, "core");
+ BUG_ON(IS_ERR(minfo->core_clk));
+
+ minfo->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref");
+ BUG_ON(IS_ERR(minfo->phy_ref_clk));
+
+ minfo->rxesc_clk = devm_clk_get(&pdev->dev, "rxesc");
+ BUG_ON(IS_ERR(minfo->rxesc_clk));
+
+ minfo->txesc_clk = devm_clk_get(&pdev->dev, "txesc");
+ BUG_ON(IS_ERR(minfo->txesc_clk));
+
+ minfo->dbi_clk = devm_clk_get(&pdev->dev, "dbi");
+ BUG_ON(IS_ERR(minfo->dbi_clk));
+
+
+ ret = clk_set_rate(minfo->phy_ref_clk, minfo->phy_ref_clkfreq);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "set phy_ref clock rate failed\n");
+ goto out;
+ }
+
+ ret = clk_set_rate(minfo->rxesc_clk, 80000000);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "set rxesc clock rate failed\n");
+ goto out;
+ }
+
+ ret = clk_set_rate(minfo->txesc_clk, 20000000);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "set txesc clock rate failed\n");
+ goto out;
+ }
+
+ clk_prepare_enable(minfo->core_clk);
+ clk_prepare_enable(minfo->phy_ref_clk);
+ clk_prepare_enable(minfo->rxesc_clk);
+ clk_prepare_enable(minfo->txesc_clk);
+ /* TODO: dbi clk is not used yet */
+
+out:
+ return ret;
+}
+#endif
+
+/**
+ * This function is called by the driver framework to initialize the MIPI DSI
+ * device.
+ *
+ * @param pdev The device structure for the MIPI DSI passed in by the
+ * driver framework.
+ *
+ * @return Returns 0 on success or negative error code on error
+ */
+static int mipi_dsi_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct mipi_dsi_info *mipi_dsi;
+ struct device_node *endpoint = NULL, *remote;
+ struct resource *res;
+ const char *lcd_panel;
+ int ret = 0;
+ u32 vmode_index;
+ uint32_t phy_ref_clkfreq;
+
+ mipi_dsi = devm_kzalloc(&pdev->dev, sizeof(*mipi_dsi), GFP_KERNEL);
+ if (!mipi_dsi)
+ return -ENOMEM;
+ mipi_dsi->pdev = pdev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get platform mem resource\n");
+ return -ENOMEM;
+ }
+
+ mipi_dsi->mmio_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mipi_dsi->mmio_base))
+ return -ENODEV;
+
+ mipi_dsi->irq = platform_get_irq(pdev, 0);
+ if (mipi_dsi->irq < 0) {
+ dev_err(&pdev->dev, "failed to get device irq\n");
+ return -EINVAL;
+ }
+
+ ret = devm_request_irq(&pdev->dev, mipi_dsi->irq,
+ mipi_dsi_irq_handler,
+ 0, "mipi_dsi_northwest", mipi_dsi);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request mipi dsi irq\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "phy-ref-clkfreq",
+ &phy_ref_clkfreq);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to get phy reference clock rate\n");
+ return -EINVAL;
+ }
+
+ if (phy_ref_clkfreq < 24000000 || phy_ref_clkfreq > 200000000) {
+ dev_err(&pdev->dev, "invalid phy reference clock rate\n");
+ return -EINVAL;
+ }
+ mipi_dsi->phy_ref_clkfreq = phy_ref_clkfreq;
+
+#ifdef CONFIG_FB_IMX64
+ dsi_clks_init(mipi_dsi);
+
+ mipi_dsi->regmap = syscon_regmap_lookup_by_phandle(np, "reset");
+ if (IS_ERR(mipi_dsi->regmap)) {
+ dev_err(&pdev->dev, "failed to get reset regmap\n");
+ return -EINVAL;
+ }
+
+ mipi_dsi->mux_sel = syscon_regmap_lookup_by_phandle(np, "mux-sel");
+ if (IS_ERR(mipi_dsi->mux_sel)) {
+ dev_err(&pdev->dev, "failed to get mux_sel regmap\n");
+ return -EINVAL;
+ }
+
+ /* TODO: use lcdif for source */
+ regmap_update_bits(mipi_dsi->mux_sel, IOMUXC_GPR_GPR13,
+ GPR_MIPI_MUX_SEL, 0x0);
+
+#else
+ mipi_dsi->esc_clk = devm_clk_get(&pdev->dev, "mipi_dsi_clk");
+ if (IS_ERR(mipi_dsi->esc_clk)) {
+ dev_err(&pdev->dev, "failed to get esc clk\n");
+ return PTR_ERR(mipi_dsi->esc_clk);
+ }
+
+ mipi_dsi->regmap = syscon_regmap_lookup_by_phandle(np, "sim");
+ if (IS_ERR(mipi_dsi->regmap)) {
+ dev_err(&pdev->dev, "failed to get parent regmap\n");
+ return -EINVAL;
+ }
+#endif
+ /* check whether an encoder exists */
+ endpoint = of_graph_get_next_endpoint(np, NULL);
+ if (endpoint) {
+ remote = of_graph_get_remote_port_parent(endpoint);
+ if (!remote)
+ return -EINVAL;
+
+ ret = of_property_read_u32(remote, "video-mode", &vmode_index);
+ if ((ret < 0) || (vmode_index >= ARRAY_SIZE(mxc_cea_mode)))
+ return -EINVAL;
+ mipi_dsi->vmode_index = vmode_index;
+
+ mipi_dsi->mode = devm_kzalloc(&pdev->dev,
+ sizeof(struct fb_videomode),
+ GFP_KERNEL);
+ if (!mipi_dsi->mode)
+ return -ENOMEM;
+
+ memcpy(mipi_dsi->mode, &mxc_cea_mode[vmode_index],
+ sizeof(struct fb_videomode));
+
+ ret = of_property_read_u32(remote, "dsi-traffic-mode",
+ &mipi_dsi->traffic_mode);
+ if (ret < 0 || mipi_dsi->traffic_mode > 2) {
+ devm_kfree(&pdev->dev, mipi_dsi->mode);
+ return -EINVAL;
+ }
+
+ mipi_dsi->lcd_config = devm_kzalloc(&pdev->dev,
+ sizeof(struct mipi_lcd_config),
+ GFP_KERNEL);
+ if (!mipi_dsi->lcd_config) {
+ kfree(mipi_dsi->mode);
+ return -ENOMEM;
+ }
+
+ mipi_dsi->encoder = 1;
+ } else {
+ /* Default, using 'BURST-MODE' for mipi panel */
+ mipi_dsi->traffic_mode = 2;
+
+ ret = of_property_read_string(np, "lcd_panel", &lcd_panel);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read lcd_panel property\n");
+ return ret;
+ }
+
+ /* mipi VDDA is sw1 in PMIC which is always on */
+
+ mipi_dsi->lcd_panel = kstrdup(lcd_panel, GFP_KERNEL);
+ if (!mipi_dsi->lcd_panel) {
+ dev_err(&pdev->dev, "failed to allocate lcd panel\n");
+ ret = -ENOMEM;
+ }
+ }
+
+ mipi_dsi->disp_mipi = mxc_dispdrv_register(&mipi_dsi_drv);
+ if (IS_ERR(mipi_dsi->disp_mipi)) {
+ dev_err(&pdev->dev, "mxc_dispdrv_register error\n");
+ ret = PTR_ERR(mipi_dsi->disp_mipi);
+ goto dispdrv_reg_fail;
+ }
+
+ mipi_dsi->mipi_dsi_pkt_read = mipi_dsi_pkt_read;
+ mipi_dsi->mipi_dsi_pkt_write = mipi_dsi_pkt_write;
+ mipi_dsi->mipi_dsi_dcs_cmd = mipi_dsi_dcs_cmd;
+
+#ifndef CONFIG_FB_IMX64
+ pm_runtime_enable(&pdev->dev);
+#endif
+ mxc_dispdrv_setdata(mipi_dsi->disp_mipi, mipi_dsi);
+ dev_set_drvdata(&pdev->dev, mipi_dsi);
+
+ dev_info(&pdev->dev, "i.MX MIPI DSI driver probed\n");
+ return ret;
+
+dispdrv_reg_fail:
+ if (mipi_dsi->lcd_panel)
+ kfree(mipi_dsi->lcd_panel);
+ return ret;
+}
+
+static int mipi_dsi_remove(struct platform_device *pdev)
+{
+ struct mipi_dsi_info *mipi_dsi = dev_get_drvdata(&pdev->dev);
+
+ mxc_dispdrv_puthandle(mipi_dsi->disp_mipi);
+ mxc_dispdrv_unregister(mipi_dsi->disp_mipi);
+
+ kfree(mipi_dsi->lcd_panel);
+ dev_set_drvdata(&pdev->dev, NULL);
+
+ return 0;
+}
+
+static void mipi_dsi_shutdown(struct platform_device *pdev)
+{
+ struct mipi_dsi_info *mipi_dsi = dev_get_drvdata(&pdev->dev);
+
+ if (mipi_dsi->lcd_inited) {
+#ifndef CONFIG_FB_IMX64
+ clk_prepare_enable(mipi_dsi->esc_clk);
+#endif
+ if (!mipi_dsi->encoder)
+ mipi_display_enter_sleep(mipi_dsi->disp_mipi);
+
+ writel(0x1, mipi_dsi->mmio_base + DPHY_PD_PLL);
+ writel(0x1, mipi_dsi->mmio_base + DPHY_PD_DPHY);
+#ifndef CONFIG_FB_IMX64
+ clk_disable_unprepare(mipi_dsi->esc_clk);
+#endif
+ mipi_dsi->lcd_inited = 0;
+ }
+
+ reset_dsi_domains(mipi_dsi, 1);
+
+#ifdef CONFIG_FB_IMX64
+ regmap_update_bits(mipi_dsi->regmap, SRC_MIPIPHY_RCR,
+ MIPI_DSI_PCLK_RESET_N, 0x0);
+#else
+ regmap_update_bits(mipi_dsi->regmap, SIM_SOPT1CFG,
+ DSI_PLL_EN, 0x0);
+#endif
+}
+
+static const struct of_device_id imx_mipi_dsi_dt_ids[] = {
+ { .compatible = "fsl,imx7ulp-mipi-dsi", .data = NULL, },
+ { .compatible = "fsl,imx8mq-mipi-dsi", .data = NULL, },
+ { }
+};
+MODULE_DEVICE_TABLE(of, imx_mipi_dsi_dt_ids);
+
+static int mipi_dsi_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mipi_dsi_info *mipi_dsi = dev_get_drvdata(&pdev->dev);
+
+ mipi_dsi->dsi_power_on = 0;
+
+ return 0;
+}
+
+static int mipi_dsi_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mipi_dsi_info *mipi_dsi = dev_get_drvdata(&pdev->dev);
+
+ if (!mipi_dsi->dsi_power_on) {
+ request_bus_freq(BUS_FREQ_HIGH);
+ dev_dbg(dev, "mipi dsi busfreq high request.\n");
+
+ mipi_dsi->dsi_power_on = 1;
+ }
+
+ return 0;
+}
+
+static int mipi_dsi_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mipi_dsi_info *mipi_dsi = dev_get_drvdata(&pdev->dev);
+
+ if (unlikely(mipi_dsi->lcd_inited)) {
+#ifndef CONFIG_FB_IMX64
+ clk_prepare_enable(mipi_dsi->esc_clk);
+#endif
+
+ writel(0x1, mipi_dsi->mmio_base + DPHY_PD_PLL);
+ writel(0x1, mipi_dsi->mmio_base + DPHY_PD_DPHY);
+
+#ifndef CONFIG_FB_IMX64
+ clk_disable_unprepare(mipi_dsi->esc_clk);
+#endif
+ mipi_dsi->lcd_inited = 0;
+ }
+
+ pinctrl_pm_select_sleep_state(dev);
+
+ return 0;
+}
+
+static int mipi_dsi_resume(struct device *dev)
+{
+ pinctrl_pm_select_default_state(dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops mipi_dsi_pm_ops = {
+ .suspend = mipi_dsi_suspend,
+ .resume = mipi_dsi_resume,
+ .runtime_suspend = mipi_dsi_runtime_suspend,
+ .runtime_resume = mipi_dsi_runtime_resume,
+ .runtime_idle = NULL,
+};
+
+static struct platform_driver mipi_dsi_driver = {
+ .driver = {
+ .of_match_table = imx_mipi_dsi_dt_ids,
+ .name = "mipi_dsi_northwest",
+ .pm = &mipi_dsi_pm_ops,
+ },
+ .probe = mipi_dsi_probe,
+ .remove = mipi_dsi_remove,
+ .shutdown = mipi_dsi_shutdown,
+};
+
+static int __init mipi_dsi_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&mipi_dsi_driver);
+ if (err) {
+ pr_err("mipi_dsi_driver register failed\n");
+ return err;
+ }
+
+ pr_debug("MIPI DSI driver module loaded: %s\n", mipi_dsi_driver.driver.name);
+
+ return 0;
+}
+
+static void __exit mipi_dsi_exit(void)
+{
+ platform_driver_unregister(&mipi_dsi_driver);
+}
+
+module_init(mipi_dsi_init);
+module_exit(mipi_dsi_exit);
+
+MODULE_AUTHOR("NXP Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX MIPI DSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/mxc/mipi_dsi_samsung.c b/drivers/video/fbdev/mxc/mipi_dsi_samsung.c
new file mode 100644
index 000000000000..d6bcf2a3de9f
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mipi_dsi_samsung.c
@@ -0,0 +1,952 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2017 NXP.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/bitops.h>
+#include <linux/mipi_dsi_samsung.h>
+#include <linux/module.h>
+#include <linux/mxcfb.h>
+#include <linux/pm_runtime.h>
+#include <linux/busfreq-imx.h>
+#include <linux/backlight.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <video/mipi_display.h>
+#include <linux/mfd/syscon.h>
+
+#include "mipi_dsi.h"
+
+#define DISPDRV_MIPI "mipi_dsi_samsung"
+#define ROUND_UP(x) ((x)+1)
+#define NS2PS_RATIO (1000)
+#define MIPI_LCD_SLEEP_MODE_DELAY (120)
+#define MIPI_FIFO_TIMEOUT msecs_to_jiffies(250)
+
+static struct mipi_dsi_match_lcd mipi_dsi_lcd_db[] = {
+#ifdef CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL
+ {
+ "TRULY-WVGA",
+ {mipid_hx8369_get_lcd_videomode, mipid_hx8369_lcd_setup}
+ },
+#endif
+#ifdef CONFIG_FB_MXC_TRULY_PANEL_TFT3P5079E
+ {
+ "TRULY-WVGA-TFT3P5079E",
+ {mipid_otm8018b_get_lcd_videomode, mipid_otm8018b_lcd_setup}
+ },
+#endif
+#ifdef CONFIG_FB_MXC_TRULY_PANEL_TFT3P5581E
+ {
+ "TRULY-WVGA-TFT3P5581E",
+ {mipid_hx8363_get_lcd_videomode, mipid_hx8363_lcd_setup}
+ },
+#endif
+ {
+ "", {NULL, NULL}
+ }
+};
+
+enum mipi_dsi_mode {
+ DSI_COMMAND_MODE,
+ DSI_VIDEO_MODE
+};
+
+enum mipi_dsi_trans_mode {
+ DSI_LP_MODE,
+ DSI_HS_MODE
+};
+
+static struct regulator *mipi_phy_reg;
+static DECLARE_COMPLETION(dsi_rx_done);
+static DECLARE_COMPLETION(dsi_tx_done);
+
+static void mipi_dsi_dphy_power_down(void);
+static void mipi_dsi_set_mode(struct mipi_dsi_info *mipi_dsi,
+ enum mipi_dsi_trans_mode mode);
+
+static int mipi_dsi_lcd_init(struct mipi_dsi_info *mipi_dsi,
+ struct mxc_dispdrv_setting *setting)
+{
+ int i, size, err;
+ struct fb_videomode *mipi_lcd_modedb;
+ struct fb_videomode mode;
+ struct device *dev = &mipi_dsi->pdev->dev;
+
+ for (i = 0; i < ARRAY_SIZE(mipi_dsi_lcd_db); i++) {
+ if (!strcmp(mipi_dsi->lcd_panel,
+ mipi_dsi_lcd_db[i].lcd_panel)) {
+ mipi_dsi->lcd_callback =
+ &mipi_dsi_lcd_db[i].lcd_callback;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(mipi_dsi_lcd_db)) {
+ dev_err(dev, "failed to find supported lcd panel.\n");
+ return -EINVAL;
+ }
+
+ /* set default bpp to 32 if not set*/
+ if (!setting->default_bpp)
+ setting->default_bpp = 32;
+
+ mipi_dsi->lcd_callback->get_mipi_lcd_videomode(&mipi_lcd_modedb, &size,
+ &mipi_dsi->lcd_config);
+
+ err = fb_find_mode(&setting->fbi->var, setting->fbi,
+ setting->dft_mode_str,
+ mipi_lcd_modedb, size, NULL,
+ setting->default_bpp);
+ if (err != 1)
+ fb_videomode_to_var(&setting->fbi->var, mipi_lcd_modedb);
+
+ INIT_LIST_HEAD(&setting->fbi->modelist);
+ for (i = 0; i < size; i++) {
+ fb_var_to_videomode(&mode, &setting->fbi->var);
+ if (fb_mode_is_equal(&mode, mipi_lcd_modedb + i)) {
+ err = fb_add_videomode(mipi_lcd_modedb + i,
+ &setting->fbi->modelist);
+ mipi_dsi->mode = mipi_lcd_modedb + i;
+ break;
+ }
+ }
+
+ if ((err < 0) || (size == i)) {
+ dev_err(dev, "failed to add videomode.\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static void mipi_dsi_wr_tx_header(struct mipi_dsi_info *mipi_dsi,
+ u8 di, u8 data0, u8 data1)
+{
+ unsigned int reg;
+
+ reg = (data1 << 16) | (data0 << 8) | ((di & 0x3f) << 0);
+
+ writel(reg, mipi_dsi->mmio_base + MIPI_DSI_PKTHDR);
+}
+
+static void mipi_dsi_wr_tx_data(struct mipi_dsi_info *mipi_dsi,
+ unsigned int tx_data)
+{
+ writel(tx_data, mipi_dsi->mmio_base + MIPI_DSI_PAYLOAD);
+}
+
+static void mipi_dsi_long_data_wr(struct mipi_dsi_info *mipi_dsi,
+ const unsigned char *data0, unsigned int data_size)
+{
+ unsigned int data_cnt = 0, payload = 0;
+
+ /* in case that data count is more then 4 */
+ for (data_cnt = 0; data_cnt < data_size; data_cnt += 4) {
+ /*
+ * after sending 4bytes per one time,
+ * send remainder data less then 4.
+ */
+ if ((data_size - data_cnt) < 4) {
+ if ((data_size - data_cnt) == 3) {
+ payload = data0[data_cnt] |
+ data0[data_cnt + 1] << 8 |
+ data0[data_cnt + 2] << 16;
+ dev_dbg(&mipi_dsi->pdev->dev, "count = 3 payload = %x, %x %x %x\n",
+ payload, data0[data_cnt],
+ data0[data_cnt + 1],
+ data0[data_cnt + 2]);
+ } else if ((data_size - data_cnt) == 2) {
+ payload = data0[data_cnt] |
+ data0[data_cnt + 1] << 8;
+ dev_dbg(&mipi_dsi->pdev->dev,
+ "count = 2 payload = %x, %x %x\n", payload,
+ data0[data_cnt],
+ data0[data_cnt + 1]);
+ } else if ((data_size - data_cnt) == 1) {
+ payload = data0[data_cnt];
+ }
+
+ mipi_dsi_wr_tx_data(mipi_dsi, payload);
+ /* send 4bytes per one time. */
+ } else {
+ payload = data0[data_cnt] |
+ data0[data_cnt + 1] << 8 |
+ data0[data_cnt + 2] << 16 |
+ data0[data_cnt + 3] << 24;
+
+ dev_dbg(&mipi_dsi->pdev->dev,
+ "count = 4 payload = %x, %x %x %x %x\n",
+ payload, *(u8 *)(data0 + data_cnt),
+ data0[data_cnt + 1],
+ data0[data_cnt + 2],
+ data0[data_cnt + 3]);
+
+ mipi_dsi_wr_tx_data(mipi_dsi, payload);
+ }
+ }
+}
+
+static int mipi_dsi_pkt_write(struct mipi_dsi_info *mipi_dsi,
+ u8 data_type, const u32 *buf, int len)
+{
+ int ret = 0;
+ struct platform_device *pdev = mipi_dsi->pdev;
+ const unsigned char *data = (const unsigned char*)buf;
+
+ if (len == 0)
+ /* handle generic short write command */
+ mipi_dsi_wr_tx_header(mipi_dsi, data_type, data[0], data[1]);
+ else {
+ reinit_completion(&dsi_tx_done);
+
+ /* handle generic long write command */
+ mipi_dsi_long_data_wr(mipi_dsi, data, len);
+ mipi_dsi_wr_tx_header(mipi_dsi, data_type, len & 0xff, (len & 0xff00) >> 8);
+
+ ret = wait_for_completion_timeout(&dsi_tx_done, MIPI_FIFO_TIMEOUT);
+ if (!ret) {
+ dev_err(&pdev->dev, "wait tx done timeout!\n");
+ return -ETIMEDOUT;
+ }
+ }
+ mdelay(10);
+
+ return 0;
+}
+
+static void mipi_dsi_rd_tx_header(struct mipi_dsi_info *mipi_dsi,
+ u8 data_type, u8 data0)
+{
+ unsigned int reg = (data_type << 0) | (data0 << 8);
+
+ writel(reg, mipi_dsi->mmio_base + MIPI_DSI_PKTHDR);
+}
+
+static unsigned int mipi_dsi_rd_rx_fifo(struct mipi_dsi_info *mipi_dsi)
+{
+ return readl(mipi_dsi->mmio_base + MIPI_DSI_RXFIFO);
+}
+
+static int mipi_dsi_pkt_read(struct mipi_dsi_info *mipi_dsi,
+ u8 data_type, u32 *buf, int len)
+{
+ int ret;
+ struct platform_device *pdev = mipi_dsi->pdev;
+
+ if (len <= 4) {
+ reinit_completion(&dsi_rx_done);
+
+ mipi_dsi_rd_tx_header(mipi_dsi, data_type, buf[0]);
+
+ ret = wait_for_completion_timeout(&dsi_rx_done, MIPI_FIFO_TIMEOUT);
+ if (!ret) {
+ dev_err(&pdev->dev, "wait rx done timeout!\n");
+ return -ETIMEDOUT;
+ }
+
+ buf[0] = mipi_dsi_rd_rx_fifo(mipi_dsi);
+ buf[0] = buf[0] >> 8;
+ }
+ else {
+ /* TODO: add support later */
+ }
+
+ return 0;
+}
+
+int mipi_dsi_dcs_cmd(struct mipi_dsi_info *mipi_dsi,
+ u8 cmd, const u32 *param, int num)
+{
+ int err = 0;
+ u32 buf[DSI_CMD_BUF_MAXSIZE];
+
+ switch (cmd) {
+ case MIPI_DCS_EXIT_SLEEP_MODE:
+ case MIPI_DCS_ENTER_SLEEP_MODE:
+ case MIPI_DCS_SET_DISPLAY_ON:
+ case MIPI_DCS_SET_DISPLAY_OFF:
+ buf[0] = cmd;
+ err = mipi_dsi_pkt_write(mipi_dsi,
+ MIPI_DSI_DCS_SHORT_WRITE, buf, 0);
+ break;
+
+ default:
+ dev_err(&mipi_dsi->pdev->dev,
+ "MIPI DSI DCS Command:0x%x Not supported!\n", cmd);
+ break;
+ }
+
+ return err;
+}
+
+static void mipi_dsi_set_main_standby(struct mipi_dsi_info *mipi_dsi,
+ unsigned int enable)
+{
+ unsigned int reg;
+
+ reg = readl(mipi_dsi->mmio_base + MIPI_DSI_MDRESOL);
+
+ reg &= ~MIPI_DSI_MAIN_STANDBY(1);
+
+ if (enable)
+ reg |= MIPI_DSI_MAIN_STANDBY(1);
+
+ writel(reg, mipi_dsi->mmio_base + MIPI_DSI_MDRESOL);
+}
+
+static void mipi_dsi_power_off(struct mxc_dispdrv_handle *disp)
+{
+ int err;
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+
+ err = mipi_dsi_dcs_cmd(mipi_dsi, MIPI_DCS_ENTER_SLEEP_MODE,
+ NULL, 0);
+ if (err) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "MIPI DSI DCS Command display on error!\n");
+ }
+ msleep(MIPI_LCD_SLEEP_MODE_DELAY);
+
+ mipi_dsi_set_main_standby(mipi_dsi, 0);
+
+ clk_disable_unprepare(mipi_dsi->dphy_clk);
+ clk_disable_unprepare(mipi_dsi->cfg_clk);
+}
+
+static void mipi_dsi_dphy_power_on(struct platform_device *pdev)
+{
+ int ret;
+
+ regulator_set_voltage(mipi_phy_reg, 1000000, 1000000);
+
+ ret = regulator_enable(mipi_phy_reg);
+ if (ret){
+ dev_err(&pdev->dev, "failed to enable mipi phy regulatore\n");
+ BUG_ON(1);
+ }
+}
+
+static void mipi_dsi_dphy_power_down(void)
+{
+ regulator_disable(mipi_phy_reg);
+}
+
+static int mipi_dsi_lane_stop_state(struct mipi_dsi_info *mipi_dsi)
+{
+ unsigned int reg;
+
+ reg = readl(mipi_dsi->mmio_base + MIPI_DSI_STATUS);
+
+ if (((reg & MIPI_DSI_STOP_STATE_DAT(0x3)) == 0x3) &&
+ ((reg & MIPI_DSI_STOP_STATE_CLK(0x1)) ||
+ (reg & MIPI_DSI_TX_READY_HS_CLK(0x1))))
+ return 1;
+
+ return 0;
+}
+
+static void mipi_dsi_init_interrupt(struct mipi_dsi_info *mipi_dsi)
+{
+ unsigned int intsrc, intmsk;
+
+ intsrc = (INTSRC_SFR_PL_FIFO_EMPTY | INTSRC_RX_DATA_DONE);
+ writel(intsrc, mipi_dsi->mmio_base + MIPI_DSI_INTSRC);
+
+ intmsk = ~(INTMSK_SFR_PL_FIFO_EMPTY | INTMSK_RX_DATA_DONE);
+ writel(intmsk, mipi_dsi->mmio_base + MIPI_DSI_INTMSK);
+}
+
+static int mipi_dsi_master_init(struct mipi_dsi_info *mipi_dsi,
+ bool init)
+{
+ unsigned int time_out = 100;
+ unsigned int reg, byte_clk, esc_div;
+ struct fb_videomode *mode = mipi_dsi->mode;
+ struct device *dev = &mipi_dsi->pdev->dev;
+
+ /* configure DPHY PLL clock */
+ writel(MIPI_DSI_TX_REQUEST_HSCLK(0) |
+ MIPI_DSI_DPHY_SEL(0) |
+ MIPI_DSI_PLL_BYPASS(0) |
+ MIPI_DSI_BYTE_CLK_SRC(0),
+ mipi_dsi->mmio_base + MIPI_DSI_CLKCTRL);
+ if (!strcmp(mipi_dsi->lcd_panel, "TRULY-WVGA-TFT3P5581E"))
+ writel(MIPI_DSI_PLL_EN(1) | MIPI_DSI_PMS(0x3141),
+ mipi_dsi->mmio_base + MIPI_DSI_PLLCTRL);
+ else
+ writel(MIPI_DSI_PLL_EN(1) | MIPI_DSI_PMS(0x4190),
+ mipi_dsi->mmio_base + MIPI_DSI_PLLCTRL);
+
+ /* set PLLTMR: stable time */
+ writel(33024, mipi_dsi->mmio_base + MIPI_DSI_PLLTMR);
+ udelay(300);
+
+ /* configure byte clock */
+ reg = readl(mipi_dsi->mmio_base + MIPI_DSI_CLKCTRL);
+ reg |= MIPI_DSI_BYTE_CLK_EN(1);
+ byte_clk = 1500000000 / 8;
+ esc_div = DIV_ROUND_UP(byte_clk, 20 * 1000000);
+ reg |= (esc_div & 0xffff);
+ /* enable escape clock for clock lane and data lane0 and lane1 */
+ reg |= MIPI_DSI_LANE_ESC_CLK_EN(0x7);
+ reg |= MIPI_DSI_ESC_CLK_EN(1);
+ writel(reg, mipi_dsi->mmio_base + MIPI_DSI_CLKCTRL);
+
+ /* set main display resolution */
+ writel(MIPI_DSI_MAIN_HRESOL(mode->xres) |
+ MIPI_DSI_MAIN_VRESOL(mode->yres) |
+ MIPI_DSI_MAIN_STANDBY(0),
+ mipi_dsi->mmio_base + MIPI_DSI_MDRESOL);
+
+ /* set config register */
+ writel(MIPI_DSI_MFLUSH_VS(1) |
+ MIPI_DSI_SYNC_IN_FORM(0) |
+ MIPI_DSI_BURST_MODE(1) |
+ MIPI_DSI_VIDEO_MODE(1) |
+ MIPI_DSI_AUTO_MODE(0) |
+ MIPI_DSI_HSE_DISABLE_MODE(0) |
+ MIPI_DSI_HFP_DISABLE_MODE(0) |
+ MIPI_DSI_HBP_DISABLE_MODE(0) |
+ MIPI_DSI_HSA_DISABLE_MODE(0) |
+ MIPI_DSI_MAIN_VC(0) |
+ MIPI_DSI_SUB_VC(1) |
+ MIPI_DSI_MAIN_PIX_FORMAT(0x7) |
+ MIPI_DSI_SUB_PIX_FORMAT(0x7) |
+ MIPI_DSI_NUM_OF_DATALANE(0x1) |
+ MIPI_DSI_LANE_EN(0x7), /* enable data lane 0 and 1 */
+ mipi_dsi->mmio_base + MIPI_DSI_CONFIG);
+
+ /* set main display vporch */
+ writel(MIPI_DSI_CMDALLOW(0xf) |
+ MIPI_DSI_STABLE_VFP(mode->lower_margin) |
+ MIPI_DSI_MAIN_VBP(mode->upper_margin),
+ mipi_dsi->mmio_base + MIPI_DSI_MVPORCH);
+ /* set main display hporch */
+ writel(MIPI_DSI_MAIN_HFP(mode->right_margin) |
+ MIPI_DSI_MAIN_HBP(mode->left_margin),
+ mipi_dsi->mmio_base + MIPI_DSI_MHPORCH);
+ /* set main display sync */
+ writel(MIPI_DSI_MAIN_VSA(mode->vsync_len) |
+ MIPI_DSI_MAIN_HSA(mode->hsync_len),
+ mipi_dsi->mmio_base + MIPI_DSI_MSYNC);
+
+ /* configure d-phy timings */
+ if (!strcmp(mipi_dsi->lcd_panel, "TRULY-WVGA-TFT3P5581E")) {
+ writel(MIPI_DSI_M_TLPXCTL(2) | MIPI_DSI_M_THSEXITCTL(4),
+ mipi_dsi->mmio_base + MIPI_DSI_PHYTIMING);
+ writel(MIPI_DSI_M_TCLKPRPRCTL(5) |
+ MIPI_DSI_M_TCLKZEROCTL(14) |
+ MIPI_DSI_M_TCLKPOSTCTL(8) |
+ MIPI_DSI_M_TCLKTRAILCTL(3),
+ mipi_dsi->mmio_base + MIPI_DSI_PHYTIMING1);
+ writel(MIPI_DSI_M_THSPRPRCTL(3) |
+ MIPI_DSI_M_THSZEROCTL(3) |
+ MIPI_DSI_M_THSTRAILCTL(3),
+ mipi_dsi->mmio_base + MIPI_DSI_PHYTIMING2);
+ } else {
+ writel(MIPI_DSI_M_TLPXCTL(11) | MIPI_DSI_M_THSEXITCTL(18),
+ mipi_dsi->mmio_base + MIPI_DSI_PHYTIMING);
+ writel(MIPI_DSI_M_TCLKPRPRCTL(13) |
+ MIPI_DSI_M_TCLKZEROCTL(65) |
+ MIPI_DSI_M_TCLKPOSTCTL(17) |
+ MIPI_DSI_M_TCLKTRAILCTL(13),
+ mipi_dsi->mmio_base + MIPI_DSI_PHYTIMING1);
+ writel(MIPI_DSI_M_THSPRPRCTL(16) |
+ MIPI_DSI_M_THSZEROCTL(24) |
+ MIPI_DSI_M_THSTRAILCTL(16),
+ mipi_dsi->mmio_base + MIPI_DSI_PHYTIMING2);
+ }
+
+ writel(0xf000f, mipi_dsi->mmio_base + MIPI_DSI_TIMEOUT);
+
+ /* Init FIFO */
+ writel(0x0, mipi_dsi->mmio_base + MIPI_DSI_FIFOCTRL);
+ udelay(300);
+ writel(0x1f, mipi_dsi->mmio_base + MIPI_DSI_FIFOCTRL);
+
+ /* check clock and data lanes are in stop state
+ * which means dphy is in low power mode
+ */
+ while (!mipi_dsi_lane_stop_state(mipi_dsi)) {
+ time_out--;
+ if (time_out == 0) {
+ dev_err(dev, "MIPI DSI is not stop state.\n");
+ return -EINVAL;
+ }
+ }
+
+ /* transfer commands always in lp mode */
+ writel(MIPI_DSI_CMD_LPDT, mipi_dsi->mmio_base + MIPI_DSI_ESCMODE);
+
+ mipi_dsi_init_interrupt(mipi_dsi);
+
+ return 0;
+}
+
+static int mipi_dsi_disp_init(struct mxc_dispdrv_handle *disp,
+ struct mxc_dispdrv_setting *setting)
+{
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+ struct device *dev = &mipi_dsi->pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct reset_control *reset = NULL;
+ int ret = 0;
+
+ reset = of_reset_control_get(np, NULL);
+ if (IS_ERR(reset))
+ return PTR_ERR(reset);
+
+ ret = mipi_dsi_lcd_init(mipi_dsi, setting);
+ if (ret) {
+ dev_err(dev, "failed to init mipi dsi lcd\n");
+ goto out;
+ }
+
+ dev_info(dev, "MIPI DSI dispdrv inited!\n");
+
+out:
+ reset_control_put(reset);
+ return ret;
+}
+
+static void mipi_dsi_disp_deinit(struct mxc_dispdrv_handle *disp)
+{
+ struct mipi_dsi_info *mipi_dsi;
+
+ mipi_dsi = mxc_dispdrv_getdata(disp);
+
+ mipi_dsi_power_off(mipi_dsi->disp_mipi);
+ if (mipi_dsi->bl)
+ backlight_device_unregister(mipi_dsi->bl);
+}
+
+static void mipi_dsi_set_mode(struct mipi_dsi_info *mipi_dsi,
+ enum mipi_dsi_trans_mode mode)
+{
+ unsigned int dsi_clkctrl;
+
+ dsi_clkctrl = readl(mipi_dsi->mmio_base + MIPI_DSI_CLKCTRL);
+
+ switch (mode) {
+ case DSI_LP_MODE:
+ dsi_clkctrl &= ~MIPI_DSI_TX_REQUEST_HSCLK(1);
+ break;
+ case DSI_HS_MODE:
+ dsi_clkctrl |= MIPI_DSI_TX_REQUEST_HSCLK(1);
+ break;
+ default:
+ dev_err(&mipi_dsi->pdev->dev,
+ "invalid dsi mode\n");
+ return;
+ }
+
+ writel(dsi_clkctrl, mipi_dsi->mmio_base + MIPI_DSI_CLKCTRL);
+ mdelay(1);
+}
+
+static int mipi_dsi_enable(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
+{
+ int ret;
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+
+ if (fbi->state == FBINFO_STATE_SUSPENDED) {
+ if (mipi_dsi->disp_power_on) {
+ ret = regulator_enable(mipi_dsi->disp_power_on);
+ if (ret) {
+ dev_err(&mipi_dsi->pdev->dev, "failed to enable display "
+ "power regulator, err = %d\n", ret);
+ return ret;
+ }
+ }
+ }
+
+ if (!mipi_dsi->dsi_power_on)
+ pm_runtime_get_sync(&mipi_dsi->pdev->dev);
+
+ ret = clk_prepare_enable(mipi_dsi->dphy_clk);
+ ret |= clk_prepare_enable(mipi_dsi->cfg_clk);
+ if (ret) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "clk enable error:%d!\n", ret);
+ return -EINVAL;
+ }
+
+ if (!mipi_dsi->lcd_inited) {
+ ret = mipi_dsi_master_init(mipi_dsi, true);
+ if (ret)
+ return -EINVAL;
+
+ msleep(20);
+ ret = device_reset(&mipi_dsi->pdev->dev);
+ if (ret) {
+ dev_err(&mipi_dsi->pdev->dev, "failed to reset device: %d\n", ret);
+ return -EINVAL;
+ }
+ msleep(120);
+
+ /* the panel should be config under LP mode */
+ ret = mipi_dsi->lcd_callback->mipi_lcd_setup(mipi_dsi);
+ if (ret < 0) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "failed to init mipi lcd.\n");
+ return ret ;
+ }
+ mipi_dsi->lcd_inited = 1;
+
+ /* change to HS mode for panel display */
+ mipi_dsi_set_mode(mipi_dsi, DSI_HS_MODE);
+ } else {
+ ret = mipi_dsi_dcs_cmd(mipi_dsi, MIPI_DCS_EXIT_SLEEP_MODE,
+ NULL, 0);
+ if (ret) {
+ dev_err(&mipi_dsi->pdev->dev,
+ "MIPI DSI DCS Command sleep-in error!\n");
+ }
+ msleep(MIPI_LCD_SLEEP_MODE_DELAY);
+ }
+
+ mipi_dsi_set_main_standby(mipi_dsi, 1);
+
+ return 0;
+}
+
+static void mipi_dsi_disable(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
+{
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+
+ mipi_dsi_power_off(mipi_dsi->disp_mipi);
+
+ if (fbi->state == FBINFO_STATE_SUSPENDED) {
+ if (mipi_dsi->dsi_power_on) {
+ pm_runtime_put_noidle(&mipi_dsi->pdev->dev);
+ pm_runtime_put_sync_suspend(&mipi_dsi->pdev->dev);
+ pm_runtime_get_noresume(&mipi_dsi->pdev->dev);
+ }
+
+ if (mipi_dsi->disp_power_on)
+ regulator_disable(mipi_dsi->disp_power_on);
+
+ mipi_dsi->lcd_inited = 0;
+ }
+}
+
+static int mipi_dsi_setup(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
+{
+ struct mipi_dsi_info *mipi_dsi = mxc_dispdrv_getdata(disp);
+ int xres_virtual = fbi->var.xres_virtual;
+ int yres_virtual = fbi->var.yres_virtual;
+ int xoffset = fbi->var.xoffset;
+ int yoffset = fbi->var.yoffset;
+ int pixclock = fbi->var.pixclock;
+
+ if (!mipi_dsi->mode)
+ return 0;
+
+ /* set the mode back to var in case userspace changes it */
+ fb_videomode_to_var(&fbi->var, mipi_dsi->mode);
+
+ /* restore some var entries cached */
+ fbi->var.xres_virtual = xres_virtual;
+ fbi->var.yres_virtual = yres_virtual;
+ fbi->var.xoffset = xoffset;
+ fbi->var.yoffset = yoffset;
+ fbi->var.pixclock = pixclock;
+
+ return 0;
+}
+
+static struct mxc_dispdrv_driver mipi_dsi_drv = {
+ .name = DISPDRV_MIPI,
+ .init = mipi_dsi_disp_init,
+ .deinit = mipi_dsi_disp_deinit,
+ .enable = mipi_dsi_enable,
+ .disable = mipi_dsi_disable,
+ .setup = mipi_dsi_setup,
+};
+
+static const struct of_device_id imx_mipi_dsi_dt_ids[] = {
+ { .compatible = "fsl,imx7d-mipi-dsi", .data = NULL, },
+ { }
+};
+MODULE_DEVICE_TABLE(of, imx_mipi_dsi_dt_ids);
+
+static irqreturn_t mipi_dsi_irq_handler(int irq, void *data)
+{
+ unsigned int intsrc, intclr;
+ struct mipi_dsi_info *mipi_dsi = data;
+ struct platform_device *pdev = mipi_dsi->pdev;
+
+ intclr = 0;
+ intsrc = readl(mipi_dsi->mmio_base + MIPI_DSI_INTSRC);
+
+ dev_dbg(&pdev->dev, "intsrc = 0x%x\n", intsrc);
+
+ if (intsrc & INTSRC_SFR_PL_FIFO_EMPTY) {
+ dev_dbg(&pdev->dev, "playload tx finished\n");
+ intclr |= INTSRC_SFR_PL_FIFO_EMPTY;
+ complete(&dsi_tx_done);
+ }
+
+ if(intsrc & INTSRC_RX_DATA_DONE) {
+ dev_dbg(&pdev->dev, "rx data finished\n");
+ intclr |= INTSRC_RX_DATA_DONE;
+ complete(&dsi_rx_done);
+ }
+
+ /* clear the interrupts */
+ if (intclr)
+ writel(intclr, mipi_dsi->mmio_base + MIPI_DSI_INTSRC);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * This function is called by the driver framework to initialize the MIPI DSI
+ * device.
+ *
+ * @param pdev The device structure for the MIPI DSI passed in by the
+ * driver framework.
+ *
+ * @return Returns 0 on success or negative error code on error
+ */
+static int mipi_dsi_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct mipi_dsi_info *mipi_dsi;
+ struct resource *res;
+ const char *lcd_panel;
+ int ret = 0;
+
+ mipi_dsi = devm_kzalloc(&pdev->dev, sizeof(*mipi_dsi), GFP_KERNEL);
+ if (!mipi_dsi)
+ return -ENOMEM;
+ mipi_dsi->pdev = pdev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get platform resource mem\n");
+ return -ENODEV;
+ }
+
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), pdev->name))
+ return -EBUSY;
+
+ mipi_dsi->mmio_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!mipi_dsi->mmio_base)
+ return -ENOMEM;
+
+ mipi_dsi->irq = platform_get_irq(pdev, 0);
+ if (mipi_dsi->irq < 0) {
+ dev_err(&pdev->dev, "failed to get device irq\n");
+ return -EINVAL;
+ }
+
+ ret = devm_request_irq(&pdev->dev, mipi_dsi->irq,
+ mipi_dsi_irq_handler,
+ 0, "mipi_dsi_samsung", mipi_dsi);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request mipi dsi irq\n");
+ return ret;
+ }
+
+ mipi_dsi->dphy_clk = devm_clk_get(&pdev->dev, "mipi_pllref_clk");
+ if (IS_ERR(mipi_dsi->dphy_clk)) {
+ dev_err(&pdev->dev, "failed to get dphy pll_ref_clk\n");
+ return PTR_ERR(mipi_dsi->dphy_clk);
+ }
+
+ mipi_dsi->cfg_clk = devm_clk_get(&pdev->dev, "mipi_cfg_clk");
+ if (IS_ERR(mipi_dsi->cfg_clk)) {
+ dev_err(&pdev->dev, "failed to get cfg_clk\n");
+ return PTR_ERR(mipi_dsi->cfg_clk);
+ }
+
+ ret = of_property_read_string(np, "lcd_panel", &lcd_panel);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read lcd_panel property\n");
+ return ret;
+ }
+
+ mipi_phy_reg = devm_regulator_get(&pdev->dev, "mipi-phy");
+ if (IS_ERR(mipi_phy_reg)) {
+ dev_err(&pdev->dev, "mipi phy power supply not found\n");
+ return ret;
+ }
+
+ mipi_dsi->disp_power_on = devm_regulator_get(&pdev->dev,
+ "disp-power-on");
+ if (!IS_ERR(mipi_dsi->disp_power_on)) {
+ ret = regulator_enable(mipi_dsi->disp_power_on);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable display "
+ "power regulator, err = %d\n", ret);
+ return ret;
+ }
+ }
+
+ mipi_dsi->lcd_panel = kstrdup(lcd_panel, GFP_KERNEL);
+ if (!mipi_dsi->lcd_panel) {
+ dev_err(&pdev->dev, "failed to allocate lcd panel name\n");
+ ret = -ENOMEM;
+ goto kstrdup_fail;
+ }
+
+ mipi_dsi->disp_mipi = mxc_dispdrv_register(&mipi_dsi_drv);
+ if (IS_ERR(mipi_dsi->disp_mipi)) {
+ dev_err(&pdev->dev, "mxc_dispdrv_register error\n");
+ ret = PTR_ERR(mipi_dsi->disp_mipi);
+ goto dispdrv_reg_fail;
+ }
+
+ mipi_dsi->mipi_dsi_pkt_read = mipi_dsi_pkt_read;
+ mipi_dsi->mipi_dsi_pkt_write = mipi_dsi_pkt_write;
+ mipi_dsi->mipi_dsi_dcs_cmd = mipi_dsi_dcs_cmd;
+
+ pm_runtime_enable(&pdev->dev);
+
+ mxc_dispdrv_setdata(mipi_dsi->disp_mipi, mipi_dsi);
+ dev_set_drvdata(&pdev->dev, mipi_dsi);
+
+ dev_info(&pdev->dev, "i.MX MIPI DSI driver probed\n");
+ return ret;
+
+dispdrv_reg_fail:
+ kfree(mipi_dsi->lcd_panel);
+kstrdup_fail:
+ if (mipi_dsi->disp_power_on)
+ regulator_disable(mipi_dsi->disp_power_on);
+
+ return ret;
+}
+
+static void mipi_dsi_shutdown(struct platform_device *pdev)
+{
+ struct mipi_dsi_info *mipi_dsi = dev_get_drvdata(&pdev->dev);
+
+ mipi_dsi_power_off(mipi_dsi->disp_mipi);
+ mipi_dsi_dphy_power_down();
+}
+
+static int mipi_dsi_remove(struct platform_device *pdev)
+{
+ struct mipi_dsi_info *mipi_dsi = dev_get_drvdata(&pdev->dev);
+
+ mxc_dispdrv_puthandle(mipi_dsi->disp_mipi);
+ mxc_dispdrv_unregister(mipi_dsi->disp_mipi);
+
+ if (mipi_dsi->disp_power_on)
+ regulator_disable(mipi_dsi->disp_power_on);
+
+ kfree(mipi_dsi->lcd_panel);
+ dev_set_drvdata(&pdev->dev, NULL);
+
+ return 0;
+}
+
+static int mipi_dsi_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mipi_dsi_info *mipi_dsi = dev_get_drvdata(&pdev->dev);
+
+ if (mipi_dsi->dsi_power_on) {
+ release_bus_freq(BUS_FREQ_HIGH);
+ dev_dbg(dev, "mipi dsi busfreq high release.\n");
+
+ mipi_dsi_dphy_power_down();
+ mipi_dsi->dsi_power_on = 0;
+ }
+
+ return 0;
+}
+
+static int mipi_dsi_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mipi_dsi_info *mipi_dsi = dev_get_drvdata(&pdev->dev);
+
+ if (!mipi_dsi->dsi_power_on) {
+ request_bus_freq(BUS_FREQ_HIGH);
+ dev_dbg(dev, "mipi dsi busfreq high request.\n");
+
+ mipi_dsi_dphy_power_on(pdev);
+ mipi_dsi->dsi_power_on = 1;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops mipi_dsi_pm_ops = {
+ .runtime_suspend = mipi_dsi_runtime_suspend,
+ .runtime_resume = mipi_dsi_runtime_resume,
+ .runtime_idle = NULL,
+};
+
+static struct platform_driver mipi_dsi_driver = {
+ .driver = {
+ .of_match_table = imx_mipi_dsi_dt_ids,
+ .name = "mxc_mipi_dsi_samsung",
+ .pm = &mipi_dsi_pm_ops,
+ },
+ .probe = mipi_dsi_probe,
+ .remove = mipi_dsi_remove,
+ .shutdown = mipi_dsi_shutdown,
+};
+
+static int __init mipi_dsi_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&mipi_dsi_driver);
+ if (err) {
+ pr_err("mipi_dsi_driver register failed\n");
+ return err;
+ }
+
+ pr_debug("MIPI DSI driver module loaded: %s\n", mipi_dsi_driver.driver.name);
+
+ return 0;
+}
+
+static void __exit mipi_dsi_cleanup(void)
+{
+ platform_driver_unregister(&mipi_dsi_driver);
+}
+
+module_init(mipi_dsi_init);
+module_exit(mipi_dsi_cleanup);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX MIPI DSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/mxc/mxc_dcic.c b/drivers/video/fbdev/mxc/mxc_dcic.c
new file mode 100644
index 000000000000..cae872a05f7f
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mxc_dcic.c
@@ -0,0 +1,592 @@
+/*
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/clk.h>
+#include <linux/cdev.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioctl.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <linux/module.h>
+#include <linux/mxc_dcic.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <video/videomode.h>
+#include <video/of_videomode.h>
+
+#define DRIVER_NAME "mxc_dcic"
+
+#define DCIC_IPU1_DI0 "dcic-ipu1-di0"
+#define DCIC_IPU1_DI1 "dcic-ipu1-di1"
+#define DCIC_IPU2_DI0 "dcic-ipu2-di0"
+#define DCIC_IPU2_DI1 "dcic-ipu2-di1"
+#define DCIC_LCDIF "dcic-lcdif"
+#define DCIC_LCDIF1 "dcic-lcdif1"
+#define DCIC_LCDIF2 "dcic-lcdif2"
+#define DCIC_LVDS "dcic-lvds"
+#define DCIC_LVDS0 "dcic-lvds0"
+#define DCIC_LVDS1 "dcic-lvds1"
+#define DCIC_HDMI "dcic-hdmi"
+
+#define DCIC0_DEV_NAME "mxc_dcic0"
+#define DCIC1_DEV_NAME "mxc_dcic1"
+
+#define FB_SYNC_OE_LOW_ACT 0x80000000
+#define FB_SYNC_CLK_LAT_FALL 0x40000000
+
+static const struct dcic_mux imx6q_dcic0_mux[] = {
+ {
+ .dcic = DCIC_IPU1_DI0,
+ .val = IMX6Q_GPR10_DCIC1_MUX_CTL_IPU1_DI0,
+ }, {
+ .dcic = DCIC_LVDS0,
+ .val = IMX6Q_GPR10_DCIC1_MUX_CTL_LVDS0,
+ }, {
+ .dcic = DCIC_LVDS1,
+ .val = IMX6Q_GPR10_DCIC1_MUX_CTL_LVDS1,
+ }, {
+ .dcic = DCIC_HDMI,
+ .val = IMX6Q_GPR10_DCIC1_MUX_CTL_HDMI,
+ }
+};
+
+static const struct dcic_mux imx6q_dcic1_mux[] = {
+ {
+ .dcic = DCIC_IPU1_DI1,
+ .val = IMX6Q_GPR10_DCIC2_MUX_CTL_IPU1_DI1,
+ }, {
+ .dcic = DCIC_LVDS0,
+ .val = IMX6Q_GPR10_DCIC2_MUX_CTL_LVDS0,
+ }, {
+ .dcic = DCIC_LVDS1,
+ .val = IMX6Q_GPR10_DCIC2_MUX_CTL_LVDS1,
+ }, {
+ .dcic = DCIC_HDMI,
+ .val = IMX6Q_GPR10_DCIC2_MUX_CTL_MIPI,
+ }
+};
+
+static const struct bus_mux imx6q_dcic_buses[] = {
+ {
+ .name = DCIC0_DEV_NAME,
+ .reg = IOMUXC_GPR10,
+ .shift = 0,
+ .mask = IMX6Q_GPR10_DCIC1_MUX_CTL_MASK,
+ .dcic_mux_num = ARRAY_SIZE(imx6q_dcic0_mux),
+ .dcics = imx6q_dcic0_mux,
+ }, {
+ .name = DCIC1_DEV_NAME,
+ .reg = IOMUXC_GPR10,
+ .shift = 2,
+ .mask = IMX6Q_GPR10_DCIC2_MUX_CTL_MASK,
+ .dcic_mux_num = ARRAY_SIZE(imx6q_dcic1_mux),
+ .dcics = imx6q_dcic1_mux,
+ }
+};
+
+static const struct dcic_info imx6q_dcic_info = {
+ .bus_mux_num = ARRAY_SIZE(imx6q_dcic_buses),
+ .buses = imx6q_dcic_buses,
+};
+
+static const struct dcic_mux imx6sx_dcic0_mux[] = {
+ {
+ .dcic = DCIC_LCDIF1,
+ .val = IMX6SX_GPR5_DISP_MUX_DCIC1_LCDIF1,
+ }, {
+ .dcic = DCIC_LVDS,
+ .val = IMX6SX_GPR5_DISP_MUX_DCIC1_LVDS,
+ }
+};
+
+static const struct dcic_mux imx6sx_dcic1_mux[] = {
+ {
+ .dcic = DCIC_LCDIF2,
+ .val = IMX6SX_GPR5_DISP_MUX_DCIC2_LCDIF2,
+ }, {
+ .dcic = DCIC_LVDS,
+ .val = IMX6SX_GPR5_DISP_MUX_DCIC2_LVDS,
+ }
+};
+
+static const struct bus_mux imx6sx_dcic_buses[] = {
+ {
+ .name = DCIC0_DEV_NAME,
+ .reg = IOMUXC_GPR5,
+ .shift = 1,
+ .mask = IMX6SX_GPR5_DISP_MUX_DCIC1_MASK,
+ .dcic_mux_num = ARRAY_SIZE(imx6sx_dcic0_mux),
+ .dcics = imx6sx_dcic0_mux,
+ }, {
+ .name = DCIC1_DEV_NAME,
+ .reg = IOMUXC_GPR5,
+ .shift = 2,
+ .mask = IMX6SX_GPR5_DISP_MUX_DCIC2_MASK,
+ .dcic_mux_num = ARRAY_SIZE(imx6sx_dcic1_mux),
+ .dcics = imx6sx_dcic1_mux,
+ }
+};
+
+static const struct dcic_info imx6sx_dcic_info = {
+ .bus_mux_num = ARRAY_SIZE(imx6sx_dcic_buses),
+ .buses = imx6sx_dcic_buses,
+};
+
+static const struct of_device_id dcic_dt_ids[] = {
+ { .compatible = "fsl,imx6q-dcic", .data = &imx6q_dcic_info, },
+ { .compatible = "fsl,imx6sx-dcic", .data = &imx6sx_dcic_info, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, dcic_dt_ids);
+
+static int of_get_dcic_val(struct device_node *np, struct dcic_data *dcic)
+{
+ const char *mux;
+ int ret;
+ u32 i, dcic_id;
+
+ ret = of_property_read_string(np, "dcic_mux", &mux);
+ if (ret < 0) {
+ dev_err(dcic->dev, "Can not get dcic_mux\n");
+ return ret;
+ }
+ ret = of_property_read_u32(np, "dcic_id", &dcic_id);
+ if (ret < 0) {
+ dev_err(dcic->dev, "Can not get dcic_id\n");
+ return ret;
+ }
+
+ dcic->bus_n = dcic_id;
+
+ for (i = 0; i < dcic->buses[dcic_id].dcic_mux_num; i++)
+ if (!strcmp(mux, dcic->buses[dcic_id].dcics[i].dcic)) {
+ dcic->mux_n = i;
+ return dcic->buses[dcic_id].dcics[i].val;
+ }
+
+ return -EINVAL;
+}
+
+static void dcic_enable(struct dcic_data *dcic)
+{
+ u32 val;
+
+ val = readl(&dcic->regs->dcicc);
+ val |= DCICC_IC_ENABLE;
+ writel(val, &dcic->regs->dcicc);
+}
+
+void dcic_disable(struct dcic_data *dcic)
+{
+ u32 val;
+
+ val = readl(&dcic->regs->dcicc);
+ val &= ~DCICC_IC_MASK;
+ val |= DCICC_IC_DISABLE;
+ writel(val, &dcic->regs->dcicc);
+}
+
+static void roi_enable(struct dcic_data *dcic, struct roi_params *roi_param)
+{
+ u32 val;
+ u32 roi_n = roi_param->roi_n;
+
+ val = readl(&dcic->regs->ROI[roi_n].dcicrc);
+ val |= DCICRC_ROI_ENABLE;
+ if (roi_param->freeze)
+ val |= DCICRC_ROI_FROZEN;
+ writel(val, &dcic->regs->ROI[roi_n].dcicrc);
+}
+
+static void roi_disable(struct dcic_data *dcic, u32 roi_n)
+{
+ u32 val;
+
+ val = readl(&dcic->regs->ROI[roi_n].dcicrc);
+ val &= ~DCICRC_ROI_ENABLE;
+ writel(val, &dcic->regs->ROI[roi_n].dcicrc);
+}
+
+static bool roi_configure(struct dcic_data *dcic, struct roi_params *roi_param)
+{
+ struct roi_regs *roi_reg;
+ u32 val;
+
+ if (roi_param->roi_n < 0 || roi_param->roi_n >= 16) {
+ printk(KERN_ERR "Error, Wrong ROI number %d\n", roi_param->roi_n);
+ return false;
+ }
+
+ if (roi_param->end_x <= roi_param->start_x ||
+ roi_param->end_y <= roi_param->start_y) {
+ printk(KERN_ERR "Error, Wrong ROI\n");
+ return false;
+ }
+
+ roi_reg = (struct roi_regs *) &dcic->regs->ROI[roi_param->roi_n];
+
+ /* init roi block size */
+ val = roi_param->start_y << 16 | roi_param->start_x;
+ writel(val, &roi_reg->dcicrc);
+
+ val = roi_param->end_y << 16 | roi_param->end_x;
+ writel(val, &roi_reg->dcicrs);
+
+ writel(roi_param->ref_sig, &roi_reg->dcicrrs);
+
+ roi_enable(dcic, roi_param);
+ return true;
+}
+
+static void dcic_int_enable(struct dcic_data *dcic)
+{
+ u32 val;
+
+ /* Clean pending interrupt before enable int */
+ writel(DCICS_FI_STAT_PENDING, &dcic->regs->dcics);
+ writel(0xffffffff, &dcic->regs->dcics);
+
+ /* Enable function interrupt */
+ val = readl(&dcic->regs->dcicic);
+ val &= ~DCICIC_FUN_INT_MASK;
+ val |= DCICIC_FUN_INT_ENABLE;
+ writel(val, &dcic->regs->dcicic);
+}
+
+static void dcic_int_disable(struct dcic_data *dcic)
+{
+ u32 val;
+
+ /* Disable both function and error interrupt */
+ val = readl(&dcic->regs->dcicic);
+ val = DCICIC_ERROR_INT_DISABLE | DCICIC_FUN_INT_DISABLE;
+ writel(val, &dcic->regs->dcicic);
+}
+
+static irqreturn_t dcic_irq_handler(int irq, void *data)
+{
+ u32 i;
+
+ struct dcic_data *dcic = data;
+ u32 dcics = readl(&dcic->regs->dcics);
+
+ dcic->result = dcics & 0xffff;
+
+ dcic_int_disable(dcic);
+
+ /* clean dcic interrupt state */
+ writel(DCICS_FI_STAT_PENDING, &dcic->regs->dcics);
+ writel(dcics, &dcic->regs->dcics);
+
+ for (i = 0; i < 16; i++) {
+ printk(KERN_INFO "ROI=%d,crcRS=0x%x, crcCS=0x%x\n", i,
+ readl(&dcic->regs->ROI[i].dcicrrs),
+ readl(&dcic->regs->ROI[i].dcicrcs));
+ }
+ complete(&dcic->roi_crc_comp);
+
+ return 0;
+}
+
+static int dcic_configure(struct dcic_data *dcic, unsigned int sync)
+{
+ u32 val;
+ val = 0;
+
+ /* vsync, hsync, DE, clk_pol */
+ if (!(sync & FB_SYNC_HOR_HIGH_ACT))
+ val |= DCICC_HSYNC_POL_ACTIVE_LOW;
+ if (!(sync & FB_SYNC_VERT_HIGH_ACT))
+ val |= DCICC_VSYNC_POL_ACTIVE_LOW;
+ if (sync & FB_SYNC_OE_LOW_ACT)
+ val |= DCICC_DE_ACTIVE_LOW;
+ if (sync & FB_SYNC_CLK_LAT_FALL)
+ val |= DCICC_CLK_POL_INVERTED;
+
+ writel(val, &dcic->regs->dcicc);
+ return 0;
+}
+
+static int dcic_open(struct inode *inode, struct file *file)
+{
+ struct dcic_data *dcic;
+
+ dcic = container_of(inode->i_cdev, struct dcic_data, cdev);
+
+ mutex_lock(&dcic->lock);
+
+ clk_prepare_enable(dcic->disp_axi_clk);
+ clk_prepare_enable(dcic->dcic_clk);
+
+ file->private_data = dcic;
+ mutex_unlock(&dcic->lock);
+ return 0;
+}
+
+static int dcic_release(struct inode *inode, struct file *file)
+{
+ struct dcic_data *dcic = file->private_data;
+ u32 i;
+
+ mutex_lock(&dcic->lock);
+
+ for (i = 0; i < 16; i++)
+ roi_disable(dcic, i);
+
+ clk_disable_unprepare(dcic->dcic_clk);
+ clk_disable_unprepare(dcic->disp_axi_clk);
+
+ mutex_unlock(&dcic->lock);
+ return 0;
+}
+
+static int dcic_init(struct device_node *np, struct dcic_data *dcic)
+{
+ u32 val, bus;
+
+ val = of_get_dcic_val(np, dcic);
+ if (val < 0) {
+ printk(KERN_ERR "Error incorrect\n");
+ return -1;
+ }
+
+ bus = dcic->bus_n;
+
+ regmap_update_bits(dcic->regmap, dcic->buses[bus].reg ,
+ dcic->buses[bus].mask, val);
+
+ return 0;
+}
+
+static long dcic_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int __user *argp = (void __user *)arg;
+ struct dcic_data *dcic = file->private_data;
+ struct roi_params roi_param;
+ unsigned int sync;
+ int ret = 0;
+
+ switch (cmd) {
+ case DCIC_IOC_CONFIG_DCIC:
+ if (!copy_from_user(&sync, argp, sizeof(unsigned int)))
+ dcic_configure(dcic, sync);
+ break;
+ case DCIC_IOC_CONFIG_ROI:
+ if (copy_from_user(&roi_param, argp, sizeof(roi_param)))
+ return -EFAULT;
+ else
+ if (!roi_configure(dcic, &roi_param))
+ return -EINVAL;
+ break;
+ case DCIC_IOC_GET_RESULT:
+ init_completion(&dcic->roi_crc_comp);
+
+ dcic_enable(dcic);
+
+ dcic->result = 0;
+ msleep(25);
+
+ dcic_int_enable(dcic);
+
+ ret = wait_for_completion_interruptible_timeout(
+ &dcic->roi_crc_comp, 1 * HZ);
+ if (ret == 0) {
+ dev_err(dcic->dev,
+ "dcic wait for roi crc cal timeout\n");
+ ret = -ETIME;
+ } else if (ret > 0) {
+ if (copy_to_user(argp, &dcic->result, sizeof(dcic->result)))
+ return -EFAULT;
+ ret = 0;
+ }
+ dcic_disable(dcic);
+ break;
+ default:
+ printk(KERN_ERR "%s, Unsupport cmd %d\n", __func__, cmd);
+ break;
+ }
+ return ret;
+}
+
+
+static const struct file_operations mxc_dcic_fops = {
+ .owner = THIS_MODULE,
+ .open = dcic_open,
+ .release = dcic_release,
+ .unlocked_ioctl = dcic_ioctl,
+};
+
+static int dcic_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *of_id =
+ of_match_device(dcic_dt_ids, dev);
+ const struct dcic_info *dcic_info =
+ (const struct dcic_info *)of_id->data;
+ struct device_node *np = dev->of_node;
+ struct dcic_data *dcic;
+ struct resource *res;
+ const char *name;
+ dev_t devt;
+ int ret = 0;
+ int irq;
+
+ dcic = devm_kzalloc(&pdev->dev,
+ sizeof(struct dcic_data),
+ GFP_KERNEL);
+ if (!dcic) {
+ dev_err(&pdev->dev, "Cannot allocate device data\n");
+ ret = -ENOMEM;
+ goto ealloc;
+ }
+
+ platform_set_drvdata(pdev, dcic);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "No dcic base address found.\n");
+ ret = -ENODEV;
+ goto ealloc;
+ }
+
+ dcic->regs = (struct dcic_regs *) devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!dcic->regs) {
+ dev_err(&pdev->dev, "ioremap failed with dcic base\n");
+ ret = -ENOMEM;
+ goto ealloc;
+ }
+
+ dcic->dev = dev;
+ dcic->buses = dcic_info->buses;
+
+ dcic->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
+ if (IS_ERR(dcic->regmap)) {
+ dev_err(dev, "failed to get parent regmap\n");
+ ret = PTR_ERR(dcic->regmap);
+ goto ealloc;
+ }
+
+ /* clock */
+ dcic->disp_axi_clk = devm_clk_get(&pdev->dev, "disp-axi");
+ if (IS_ERR(dcic->disp_axi_clk)) {
+ dev_err(&pdev->dev, "get disp-axi clock failed\n");
+ ret = PTR_ERR(dcic->disp_axi_clk);
+ goto ealloc;
+ }
+
+ dcic->dcic_clk = devm_clk_get(&pdev->dev, "dcic");
+ if (IS_ERR(dcic->dcic_clk)) {
+ dev_err(&pdev->dev, "get dcic clk failed\n");
+ ret = PTR_ERR(dcic->dcic_clk);
+ goto ealloc;
+ }
+
+ mutex_init(&dcic->lock);
+ ret = dcic_init(np, dcic);
+ if (ret < 0) {
+ printk(KERN_ERR "Failed init dcic\n");
+ goto ealloc;
+ }
+
+ /* register device */
+ name = dcic->buses[dcic->bus_n].name;
+ dcic->major = register_chrdev(0, name, &mxc_dcic_fops);
+ if (dcic->major < 0) {
+ printk(KERN_ERR "DCIC: unable to get a major for dcic\n");
+ ret = -EBUSY;
+ goto ealloc;
+ }
+
+ dcic->class = class_create(THIS_MODULE, name);
+ if (IS_ERR(dcic->class)) {
+ ret = PTR_ERR(dcic->class);
+ goto err_out_chrdev;
+ }
+
+ /* create char device */
+ devt = MKDEV(dcic->major, 0);
+ dcic->devt = devt;
+
+ cdev_init(&dcic->cdev, &mxc_dcic_fops);
+ dcic->cdev.owner = THIS_MODULE;
+ ret = cdev_add(&dcic->cdev, devt, 1);
+ if (ret)
+ goto err_out_class;
+
+ device_create(dcic->class, NULL, devt,
+ NULL, name);
+
+ /* IRQ */
+ irq = platform_get_irq(pdev, 0);
+
+ ret = devm_request_irq(&pdev->dev, irq, dcic_irq_handler, 0,
+ dev_name(&pdev->dev), dcic);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq (%d) failed with error %d\n",
+ irq, ret);
+ goto err_out_cdev;
+ }
+
+ return 0;
+
+err_out_cdev:
+ cdev_del(&dcic->cdev);
+err_out_class:
+ device_destroy(dcic->class, devt);
+ class_destroy(dcic->class);
+err_out_chrdev:
+ unregister_chrdev(dcic->major, name);
+ealloc:
+ return ret;
+}
+
+static int dcic_remove(struct platform_device *pdev)
+{
+ struct dcic_data *dcic = platform_get_drvdata(pdev);
+ const char *name;
+
+ name = dcic->buses[dcic->bus_n].name;
+
+ device_destroy(dcic->class, dcic->devt);
+ cdev_del(&dcic->cdev);
+ class_destroy(dcic->class);
+ unregister_chrdev(dcic->major, name);
+ mutex_destroy(&dcic->lock);
+
+ return 0;
+}
+
+static struct platform_driver dcic_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = dcic_dt_ids,
+ },
+ .probe = dcic_probe,
+ .remove = dcic_remove,
+};
+
+module_platform_driver(dcic_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC DCIC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/video/fbdev/mxc/mxc_dispdrv.c b/drivers/video/fbdev/mxc/mxc_dispdrv.c
new file mode 100644
index 000000000000..77c0d50babea
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mxc_dispdrv.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file mxc_dispdrv.c
+ * @brief mxc display driver framework.
+ *
+ * A display device driver could call mxc_dispdrv_register(drv) in its dev_probe() function.
+ * Move all dev_probe() things into mxc_dispdrv_driver->init(), init() function should init
+ * and feedback setting;
+ * Move all dev_remove() things into mxc_dispdrv_driver->deinit();
+ * Move all dev_suspend() things into fb_notifier for SUSPEND, if there is;
+ * Move all dev_resume() things into fb_notifier for RESUME, if there is;
+ *
+ * mxc fb driver could call mxc_dispdrv_gethandle(name, setting) before a fb
+ * need be added, with fbi param passing by setting, after
+ * mxc_dispdrv_gethandle() return, FB driver should get the basic setting
+ * about fbi info and crtc.
+ *
+ * @ingroup Framebuffer
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include "mxc_dispdrv.h"
+
+static LIST_HEAD(dispdrv_list);
+static DEFINE_MUTEX(dispdrv_lock);
+
+struct mxc_dispdrv_entry {
+ /* Note: drv always the first element */
+ struct mxc_dispdrv_driver *drv;
+ bool active;
+ void *priv;
+ struct list_head list;
+};
+
+struct mxc_dispdrv_handle *mxc_dispdrv_register(struct mxc_dispdrv_driver *drv)
+{
+ struct mxc_dispdrv_entry *new;
+
+ mutex_lock(&dispdrv_lock);
+
+ new = kzalloc(sizeof(struct mxc_dispdrv_entry), GFP_KERNEL);
+ if (!new) {
+ mutex_unlock(&dispdrv_lock);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ new->drv = drv;
+ list_add_tail(&new->list, &dispdrv_list);
+
+ mutex_unlock(&dispdrv_lock);
+
+ return (struct mxc_dispdrv_handle *)new;
+}
+EXPORT_SYMBOL_GPL(mxc_dispdrv_register);
+
+int mxc_dispdrv_unregister(struct mxc_dispdrv_handle *handle)
+{
+ struct mxc_dispdrv_entry *entry = (struct mxc_dispdrv_entry *)handle;
+
+ if (entry) {
+ mutex_lock(&dispdrv_lock);
+ list_del(&entry->list);
+ mutex_unlock(&dispdrv_lock);
+ kfree(entry);
+ return 0;
+ } else
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(mxc_dispdrv_unregister);
+
+struct mxc_dispdrv_handle *mxc_dispdrv_gethandle(char *name,
+ struct mxc_dispdrv_setting *setting)
+{
+ int ret = -ENODEV, found = 0;
+ struct mxc_dispdrv_entry *entry;
+
+ mutex_lock(&dispdrv_lock);
+ list_for_each_entry(entry, &dispdrv_list, list) {
+ if (!strcmp(entry->drv->name, name) && (entry->drv->init)) {
+ ret = entry->drv->init((struct mxc_dispdrv_handle *)
+ entry, setting);
+ if (ret >= 0) {
+ entry->active = true;
+ found = 1;
+ break;
+ }
+ }
+ }
+ mutex_unlock(&dispdrv_lock);
+
+ return found ? (struct mxc_dispdrv_handle *)entry:ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(mxc_dispdrv_gethandle);
+
+void mxc_dispdrv_puthandle(struct mxc_dispdrv_handle *handle)
+{
+ struct mxc_dispdrv_entry *entry = (struct mxc_dispdrv_entry *)handle;
+
+ mutex_lock(&dispdrv_lock);
+ if (entry && entry->active && entry->drv->deinit) {
+ entry->drv->deinit(handle);
+ entry->active = false;
+ }
+ mutex_unlock(&dispdrv_lock);
+
+}
+EXPORT_SYMBOL_GPL(mxc_dispdrv_puthandle);
+
+int mxc_dispdrv_setdata(struct mxc_dispdrv_handle *handle, void *data)
+{
+ struct mxc_dispdrv_entry *entry = (struct mxc_dispdrv_entry *)handle;
+
+ if (entry) {
+ entry->priv = data;
+ return 0;
+ } else
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(mxc_dispdrv_setdata);
+
+void *mxc_dispdrv_getdata(struct mxc_dispdrv_handle *handle)
+{
+ struct mxc_dispdrv_entry *entry = (struct mxc_dispdrv_entry *)handle;
+
+ if (entry) {
+ return entry->priv;
+ } else
+ return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(mxc_dispdrv_getdata);
diff --git a/drivers/video/fbdev/mxc/mxc_dispdrv.h b/drivers/video/fbdev/mxc/mxc_dispdrv.h
new file mode 100644
index 000000000000..58d8a07d3380
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mxc_dispdrv.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __MXC_DISPDRV_H__
+#define __MXC_DISPDRV_H__
+#include <linux/fb.h>
+#include "crtc.h"
+
+struct mxc_dispdrv_handle {
+ struct mxc_dispdrv_driver *drv;
+};
+
+struct mxc_dispdrv_setting {
+ /*input-feedback parameter*/
+ struct fb_info *fbi;
+ int if_fmt;
+ int default_bpp;
+ char *dft_mode_str;
+
+ /* feedback parameter */
+ enum crtc crtc;
+};
+
+struct mxc_dispdrv_driver {
+ const char *name;
+ int (*init) (struct mxc_dispdrv_handle *, struct mxc_dispdrv_setting *);
+ void (*deinit) (struct mxc_dispdrv_handle *);
+ /* display driver enable function for extension */
+ int (*enable) (struct mxc_dispdrv_handle *, struct fb_info *);
+ /* display driver disable function, called at early part of fb_blank */
+ void (*disable) (struct mxc_dispdrv_handle *, struct fb_info *);
+ /* display driver setup function, called at early part of fb_set_par */
+ int (*setup) (struct mxc_dispdrv_handle *, struct fb_info *fbi);
+};
+
+struct mxc_dispdrv_handle *mxc_dispdrv_register(struct mxc_dispdrv_driver *drv);
+int mxc_dispdrv_unregister(struct mxc_dispdrv_handle *handle);
+struct mxc_dispdrv_handle *mxc_dispdrv_gethandle(char *name,
+ struct mxc_dispdrv_setting *setting);
+void mxc_dispdrv_puthandle(struct mxc_dispdrv_handle *handle);
+int mxc_dispdrv_setdata(struct mxc_dispdrv_handle *handle, void *data);
+void *mxc_dispdrv_getdata(struct mxc_dispdrv_handle *handle);
+#endif
diff --git a/drivers/video/fbdev/mxc/mxc_edid.c b/drivers/video/fbdev/mxc/mxc_edid.c
new file mode 100644
index 000000000000..02563d8781cc
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mxc_edid.c
@@ -0,0 +1,771 @@
+/*
+ * Copyright 2009-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @defgroup Framebuffer Framebuffer Driver for SDC and ADC.
+ */
+
+/*!
+ * @file mxc_edid.c
+ *
+ * @brief MXC EDID driver
+ *
+ * @ingroup Framebuffer
+ */
+
+/*!
+ * Include files
+ */
+#include <linux/i2c.h>
+#include <linux/fb.h>
+#include <video/mxc_edid.h>
+#include "../edid.h"
+
+#undef DEBUG /* define this for verbose EDID parsing output */
+#ifdef DEBUG
+#define DPRINTK(fmt, args...) printk(fmt, ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+const struct fb_videomode mxc_cea_mode[64] = {
+ /* #1: 640x480p@59.94/60Hz 4:3 */
+ [1] = {
+ NULL, 60, 640, 480, 39683, 48, 16, 33, 10, 96, 2, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #2: 720x480p@59.94/60Hz 4:3 */
+ [2] = {
+ NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #3: 720x480p@59.94/60Hz 16:9 */
+ [3] = {
+ NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #4: 1280x720p@59.94/60Hz 16:9 */
+ [4] = {
+ NULL, 60, 1280, 720, 13468, 220, 110, 20, 5, 40, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0
+ },
+ /* #5: 1920x1080i@59.94/60Hz 16:9 */
+ [5] = {
+ NULL, 60, 1920, 1080, 13763, 148, 88, 15, 2, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_INTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #6: 720(1440)x480iH@59.94/60Hz 4:3 */
+ [6] = {
+ NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0,
+ FB_VMODE_INTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #7: 720(1440)x480iH@59.94/60Hz 16:9 */
+ [7] = {
+ NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0,
+ FB_VMODE_INTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #8: 720(1440)x240pH@59.94/60Hz 4:3 */
+ [8] = {
+ NULL, 60, 1440, 240, 37108, 114, 38, 15, 4, 124, 3, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #9: 720(1440)x240pH@59.94/60Hz 16:9 */
+ [9] = {
+ NULL, 60, 1440, 240, 37108, 114, 38, 15, 4, 124, 3, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #14: 1440x480p@59.94/60Hz 4:3 */
+ [14] = {
+ NULL, 60, 1440, 480, 18500, 120, 32, 30, 9, 124, 6, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #15: 1440x480p@59.94/60Hz 16:9 */
+ [15] = {
+ NULL, 60, 1440, 480, 18500, 120, 32, 30, 9, 124, 6, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #16: 1920x1080p@60Hz 16:9 */
+ [16] = {
+ NULL, 60, 1920, 1080, 6734, 148, 88, 36, 4, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #17: 720x576pH@50Hz 4:3 */
+ [17] = {
+ NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #18: 720x576pH@50Hz 16:9 */
+ [18] = {
+ NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #19: 1280x720p@50Hz */
+ [19] = {
+ NULL, 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #20: 1920x1080i@50Hz */
+ [20] = {
+ NULL, 50, 1920, 1080, 13480, 148, 528, 15, 5, 528, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_INTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #23: 720(1440)x288pH@50Hz 4:3 */
+ [23] = {
+ NULL, 50, 1440, 288, 37037, 138, 24, 19, 2, 126, 3, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #24: 720(1440)x288pH@50Hz 16:9 */
+ [24] = {
+ NULL, 50, 1440, 288, 37037, 138, 24, 19, 2, 126, 3, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #29: 720(1440)x576pH@50Hz 4:3 */
+ [29] = {
+ NULL, 50, 1440, 576, 18518, 136, 24, 39, 5, 128, 5, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
+ },
+ /* #30: 720(1440)x576pH@50Hz 16:9 */
+ [30] = {
+ NULL, 50, 1440, 576, 18518, 136, 24, 39, 5, 128, 5, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #31: 1920x1080p@50Hz */
+ [31] = {
+ NULL, 50, 1920, 1080, 6734, 148, 528, 36, 4, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #32: 1920x1080p@23.98/24Hz */
+ [32] = {
+ NULL, 24, 1920, 1080, 13468, 148, 638, 36, 4, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #33: 1920x1080p@25Hz */
+ [33] = {
+ NULL, 25, 1920, 1080, 13468, 148, 528, 36, 4, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #34: 1920x1080p@30Hz */
+ [34] = {
+ NULL, 30, 1920, 1080, 13468, 148, 88, 36, 4, 44, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
+ },
+ /* #41: 1280x720p@100Hz 16:9 */
+ [41] = {
+ NULL, 100, 1280, 720, 6734, 220, 440, 20, 5, 40, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0
+ },
+ /* #47: 1280x720p@119.88/120Hz 16:9 */
+ [47] = {
+ NULL, 120, 1280, 720, 6734, 220, 110, 20, 5, 40, 5,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0
+ },
+};
+
+/*
+ * We have a special version of fb_mode_is_equal that ignores
+ * pixclock, since for many CEA modes, 2 frequencies are supported
+ * e.g. 640x480 @ 60Hz or 59.94Hz
+ */
+int mxc_edid_fb_mode_is_equal(bool use_aspect,
+ const struct fb_videomode *mode1,
+ const struct fb_videomode *mode2)
+{
+ u32 mask;
+
+ if (use_aspect)
+ mask = ~0;
+ else
+ mask = ~FB_VMODE_ASPECT_MASK;
+
+ return (mode1->xres == mode2->xres &&
+ mode1->yres == mode2->yres &&
+ mode1->hsync_len == mode2->hsync_len &&
+ mode1->vsync_len == mode2->vsync_len &&
+ mode1->left_margin == mode2->left_margin &&
+ mode1->right_margin == mode2->right_margin &&
+ mode1->upper_margin == mode2->upper_margin &&
+ mode1->lower_margin == mode2->lower_margin &&
+ mode1->sync == mode2->sync &&
+ /* refresh check, 59.94Hz and 60Hz have the same parameter
+ * in struct of mxc_cea_mode */
+ abs(mode1->refresh - mode2->refresh) <= 1 &&
+ (mode1->vmode & mask) == (mode2->vmode & mask));
+}
+
+static void get_detailed_timing(unsigned char *block,
+ struct fb_videomode *mode)
+{
+ mode->xres = H_ACTIVE;
+ mode->yres = V_ACTIVE;
+ mode->pixclock = PIXEL_CLOCK;
+ mode->pixclock /= 1000;
+ mode->pixclock = KHZ2PICOS(mode->pixclock);
+ mode->right_margin = H_SYNC_OFFSET;
+ mode->left_margin = (H_ACTIVE + H_BLANKING) -
+ (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
+ mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
+ V_SYNC_WIDTH;
+ mode->lower_margin = V_SYNC_OFFSET;
+ mode->hsync_len = H_SYNC_WIDTH;
+ mode->vsync_len = V_SYNC_WIDTH;
+ if (HSYNC_POSITIVE)
+ mode->sync |= FB_SYNC_HOR_HIGH_ACT;
+ if (VSYNC_POSITIVE)
+ mode->sync |= FB_SYNC_VERT_HIGH_ACT;
+ mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
+ (V_ACTIVE + V_BLANKING));
+ if (INTERLACED) {
+ mode->yres *= 2;
+ mode->upper_margin *= 2;
+ mode->lower_margin *= 2;
+ mode->vsync_len *= 2;
+ mode->vmode |= FB_VMODE_INTERLACED;
+ }
+ mode->flag = FB_MODE_IS_DETAILED;
+
+ if ((H_SIZE / 16) == (V_SIZE / 9))
+ mode->vmode |= FB_VMODE_ASPECT_16_9;
+ else if ((H_SIZE / 4) == (V_SIZE / 3))
+ mode->vmode |= FB_VMODE_ASPECT_4_3;
+ else if ((mode->xres / 16) == (mode->yres / 9))
+ mode->vmode |= FB_VMODE_ASPECT_16_9;
+ else if ((mode->xres / 4) == (mode->yres / 3))
+ mode->vmode |= FB_VMODE_ASPECT_4_3;
+
+ if (mode->vmode & FB_VMODE_ASPECT_16_9)
+ DPRINTK("Aspect ratio: 16:9\n");
+ if (mode->vmode & FB_VMODE_ASPECT_4_3)
+ DPRINTK("Aspect ratio: 4:3\n");
+ DPRINTK(" %d MHz ", PIXEL_CLOCK/1000000);
+ DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,
+ H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
+ DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,
+ V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
+ DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",
+ (VSYNC_POSITIVE) ? "+" : "-");
+}
+
+int mxc_edid_parse_ext_blk(unsigned char *edid,
+ struct mxc_edid_cfg *cfg,
+ struct fb_monspecs *specs)
+{
+ char detail_timing_desc_offset;
+ struct fb_videomode *mode, *m;
+ unsigned char index = 0x0;
+ unsigned char *block;
+ int i, num = 0, revision;
+
+ if (edid[index++] != 0x2) /* only support cea ext block now */
+ return 0;
+ revision = edid[index++];
+ DPRINTK("cea extent revision %d\n", revision);
+ mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);
+ if (mode == NULL)
+ return -1;
+
+ detail_timing_desc_offset = edid[index++];
+
+ if (revision >= 2) {
+ cfg->cea_underscan = (edid[index] >> 7) & 0x1;
+ cfg->cea_basicaudio = (edid[index] >> 6) & 0x1;
+ cfg->cea_ycbcr444 = (edid[index] >> 5) & 0x1;
+ cfg->cea_ycbcr422 = (edid[index] >> 4) & 0x1;
+
+ DPRINTK("CEA underscan %d\n", cfg->cea_underscan);
+ DPRINTK("CEA basicaudio %d\n", cfg->cea_basicaudio);
+ DPRINTK("CEA ycbcr444 %d\n", cfg->cea_ycbcr444);
+ DPRINTK("CEA ycbcr422 %d\n", cfg->cea_ycbcr422);
+ }
+
+ if (revision >= 3) {
+ /* short desc */
+ DPRINTK("CEA Short desc timmings\n");
+ index++;
+ while (index < detail_timing_desc_offset) {
+ unsigned char tagcode, blklen;
+
+ tagcode = (edid[index] >> 5) & 0x7;
+ blklen = (edid[index]) & 0x1f;
+
+ DPRINTK("Tagcode %x Len %d\n", tagcode, blklen);
+
+ switch (tagcode) {
+ case 0x2: /*Video data block*/
+ {
+ int cea_idx;
+ i = 0;
+ while (i < blklen) {
+ index++;
+ cea_idx = edid[index] & 0x7f;
+ if (cea_idx < ARRAY_SIZE(mxc_cea_mode) &&
+ (mxc_cea_mode[cea_idx].xres)) {
+ DPRINTK("Support CEA Format #%d\n", cea_idx);
+ mode[num] = mxc_cea_mode[cea_idx];
+ mode[num].flag |= FB_MODE_IS_STANDARD;
+ num++;
+ }
+ i++;
+ }
+ break;
+ }
+ case 0x3: /*Vendor specific data*/
+ {
+ unsigned char IEEE_reg_iden[3];
+ unsigned char deep_color;
+ unsigned char latency_present;
+ unsigned char I_latency_present;
+ unsigned char hdmi_video_present;
+ unsigned char hdmi_3d_present;
+ unsigned char hdmi_3d_multi_present;
+ unsigned char hdmi_vic_len;
+ unsigned char hdmi_3d_len;
+ unsigned char index_inc = 0;
+ unsigned char vsd_end;
+
+ vsd_end = index + blklen;
+
+ IEEE_reg_iden[0] = edid[index+1];
+ IEEE_reg_iden[1] = edid[index+2];
+ IEEE_reg_iden[2] = edid[index+3];
+ cfg->physical_address[0] = (edid[index+4] & 0xf0) >> 4;
+ cfg->physical_address[1] = (edid[index+4] & 0x0f);
+ cfg->physical_address[2] = (edid[index+5] & 0xf0) >> 4;
+ cfg->physical_address[3] = (edid[index+5] & 0x0f);
+
+ if ((IEEE_reg_iden[0] == 0x03) &&
+ (IEEE_reg_iden[1] == 0x0c) &&
+ (IEEE_reg_iden[2] == 0x00))
+ cfg->hdmi_cap = 1;
+
+ if (blklen > 5) {
+ deep_color = edid[index+6];
+ if (deep_color & 0x80)
+ cfg->vsd_support_ai = true;
+ if (deep_color & 0x40)
+ cfg->vsd_dc_48bit = true;
+ if (deep_color & 0x20)
+ cfg->vsd_dc_36bit = true;
+ if (deep_color & 0x10)
+ cfg->vsd_dc_30bit = true;
+ if (deep_color & 0x08)
+ cfg->vsd_dc_y444 = true;
+ if (deep_color & 0x01)
+ cfg->vsd_dvi_dual = true;
+ }
+
+ DPRINTK("VSD hdmi capability %d\n", cfg->hdmi_cap);
+ DPRINTK("VSD support ai %d\n", cfg->vsd_support_ai);
+ DPRINTK("VSD support deep color 48bit %d\n", cfg->vsd_dc_48bit);
+ DPRINTK("VSD support deep color 36bit %d\n", cfg->vsd_dc_36bit);
+ DPRINTK("VSD support deep color 30bit %d\n", cfg->vsd_dc_30bit);
+ DPRINTK("VSD support deep color y444 %d\n", cfg->vsd_dc_y444);
+ DPRINTK("VSD support dvi dual %d\n", cfg->vsd_dvi_dual);
+
+ if (blklen > 6)
+ cfg->vsd_max_tmdsclk_rate = edid[index+7] * 5;
+ DPRINTK("VSD MAX TMDS CLOCK RATE %d\n", cfg->vsd_max_tmdsclk_rate);
+
+ if (blklen > 7) {
+ latency_present = edid[index+8] >> 7;
+ I_latency_present = (edid[index+8] & 0x40) >> 6;
+ hdmi_video_present = (edid[index+8] & 0x20) >> 5;
+ cfg->vsd_cnc3 = (edid[index+8] & 0x8) >> 3;
+ cfg->vsd_cnc2 = (edid[index+8] & 0x4) >> 2;
+ cfg->vsd_cnc1 = (edid[index+8] & 0x2) >> 1;
+ cfg->vsd_cnc0 = edid[index+8] & 0x1;
+
+ DPRINTK("VSD cnc0 %d\n", cfg->vsd_cnc0);
+ DPRINTK("VSD cnc1 %d\n", cfg->vsd_cnc1);
+ DPRINTK("VSD cnc2 %d\n", cfg->vsd_cnc2);
+ DPRINTK("VSD cnc3 %d\n", cfg->vsd_cnc3);
+ DPRINTK("latency_present %d\n", latency_present);
+ DPRINTK("I_latency_present %d\n", I_latency_present);
+ DPRINTK("hdmi_video_present %d\n", hdmi_video_present);
+
+ } else {
+ index += blklen;
+ break;
+ }
+
+ index += 9;
+
+ /*latency present */
+ if (latency_present) {
+ cfg->vsd_video_latency = edid[index++];
+ cfg->vsd_audio_latency = edid[index++];
+
+ if (I_latency_present) {
+ cfg->vsd_I_video_latency = edid[index++];
+ cfg->vsd_I_audio_latency = edid[index++];
+ } else {
+ cfg->vsd_I_video_latency = cfg->vsd_video_latency;
+ cfg->vsd_I_audio_latency = cfg->vsd_audio_latency;
+ }
+
+ DPRINTK("VSD latency video_latency %d\n", cfg->vsd_video_latency);
+ DPRINTK("VSD latency audio_latency %d\n", cfg->vsd_audio_latency);
+ DPRINTK("VSD latency I_video_latency %d\n", cfg->vsd_I_video_latency);
+ DPRINTK("VSD latency I_audio_latency %d\n", cfg->vsd_I_audio_latency);
+ }
+
+ if (hdmi_video_present) {
+ hdmi_3d_present = edid[index] >> 7;
+ hdmi_3d_multi_present = (edid[index] & 0x60) >> 5;
+ index++;
+ hdmi_vic_len = (edid[index] & 0xe0) >> 5;
+ hdmi_3d_len = edid[index] & 0x1f;
+ index++;
+
+ DPRINTK("hdmi_3d_present %d\n", hdmi_3d_present);
+ DPRINTK("hdmi_3d_multi_present %d\n", hdmi_3d_multi_present);
+ DPRINTK("hdmi_vic_len %d\n", hdmi_vic_len);
+ DPRINTK("hdmi_3d_len %d\n", hdmi_3d_len);
+
+ if (hdmi_vic_len > 0) {
+ for (i = 0; i < hdmi_vic_len; i++) {
+ cfg->hdmi_vic[i] = edid[index++];
+ DPRINTK("HDMI_vic=%d\n", cfg->hdmi_vic[i]);
+ }
+ }
+
+ if (hdmi_3d_len > 0) {
+ if (hdmi_3d_present) {
+ if (hdmi_3d_multi_present == 0x1) {
+ cfg->hdmi_3d_struct_all = (edid[index] << 8) | edid[index+1];
+ index_inc = 2;
+ } else if (hdmi_3d_multi_present == 0x2) {
+ cfg->hdmi_3d_struct_all = (edid[index] << 8) | edid[index+1];
+ cfg->hdmi_3d_mask_all = (edid[index+2] << 8) | edid[index+3];
+ index_inc = 4;
+ } else
+ index_inc = 0;
+ }
+
+ DPRINTK("HDMI 3d struct all =0x%x\n", cfg->hdmi_3d_struct_all);
+ DPRINTK("HDMI 3d mask all =0x%x\n", cfg->hdmi_3d_mask_all);
+
+ /* Read 2D vic 3D_struct */
+ if ((hdmi_3d_len - index_inc) > 0) {
+ DPRINTK("Support 3D video format\n");
+ i = 0;
+ while ((hdmi_3d_len - index_inc) > 0) {
+
+ cfg->hdmi_3d_format[i].vic_order_2d = edid[index+index_inc] >> 4;
+ cfg->hdmi_3d_format[i].struct_3d = edid[index+index_inc] & 0x0f;
+ index_inc++;
+
+ if (cfg->hdmi_3d_format[i].struct_3d == 8) {
+ cfg->hdmi_3d_format[i].detail_3d = edid[index+index_inc] >> 4;
+ index_inc++;
+ } else if (cfg->hdmi_3d_format[i].struct_3d > 8) {
+ cfg->hdmi_3d_format[i].detail_3d = 0;
+ index_inc++;
+ }
+
+ DPRINTK("vic_order_2d=%d, 3d_struct=%d, 3d_detail=0x%x\n",
+ cfg->hdmi_3d_format[i].vic_order_2d,
+ cfg->hdmi_3d_format[i].struct_3d,
+ cfg->hdmi_3d_format[i].detail_3d);
+ i++;
+ }
+ }
+ index += index_inc;
+ }
+ }
+
+ index = vsd_end;
+
+ break;
+ }
+ case 0x1: /*Audio data block*/
+ {
+ u8 audio_format, max_ch, byte1, byte2, byte3;
+
+ i = 0;
+ cfg->max_channels = 0;
+ cfg->sample_rates = 0;
+ cfg->sample_sizes = 0;
+
+ while (i < blklen) {
+ byte1 = edid[index + 1];
+ byte2 = edid[index + 2];
+ byte3 = edid[index + 3];
+ index += 3;
+ i += 3;
+
+ audio_format = byte1 >> 3;
+ max_ch = (byte1 & 0x07) + 1;
+
+ DPRINTK("Audio Format Descriptor : %2d\n", audio_format);
+ DPRINTK("Max Number of Channels : %2d\n", max_ch);
+ DPRINTK("Sample Rates : %02x\n", byte2);
+
+ /* ALSA can't specify specific compressed
+ * formats, so only care about PCM for now. */
+ if (audio_format == AUDIO_CODING_TYPE_LPCM) {
+ if (max_ch > cfg->max_channels)
+ cfg->max_channels = max_ch;
+
+ cfg->sample_rates |= byte2;
+ cfg->sample_sizes |= byte3 & 0x7;
+ DPRINTK("Sample Sizes : %02x\n",
+ byte3 & 0x7);
+ }
+ }
+ break;
+ }
+ case 0x4: /*Speaker allocation block*/
+ {
+ i = 0;
+ while (i < blklen) {
+ cfg->speaker_alloc = edid[index + 1];
+ index += 3;
+ i += 3;
+ DPRINTK("Speaker Alloc : %02x\n", cfg->speaker_alloc);
+ }
+ break;
+ }
+ case 0x7: /*User extended block*/
+ default:
+ /* skip */
+ DPRINTK("Not handle block, tagcode = 0x%x\n", tagcode);
+ index += blklen;
+ break;
+ }
+
+ index++;
+ }
+ }
+
+ /* long desc */
+ DPRINTK("CEA long desc timmings\n");
+ index = detail_timing_desc_offset;
+ block = edid + index;
+ while (index < (EDID_LENGTH - DETAILED_TIMING_DESCRIPTION_SIZE)) {
+ if (!(block[0] == 0x00 && block[1] == 0x00)) {
+ get_detailed_timing(block, &mode[num]);
+ num++;
+ }
+ block += DETAILED_TIMING_DESCRIPTION_SIZE;
+ index += DETAILED_TIMING_DESCRIPTION_SIZE;
+ }
+
+ if (!num) {
+ kfree(mode);
+ return 0;
+ }
+
+ m = kmalloc((num + specs->modedb_len) *
+ sizeof(struct fb_videomode), GFP_KERNEL);
+ if (!m) {
+ kfree(mode);
+ return 0;
+ }
+
+ if (specs->modedb_len) {
+ memmove(m, specs->modedb,
+ specs->modedb_len * sizeof(struct fb_videomode));
+ kfree(specs->modedb);
+ }
+ memmove(m+specs->modedb_len, mode,
+ num * sizeof(struct fb_videomode));
+ kfree(mode);
+
+ specs->modedb_len += num;
+ specs->modedb = m;
+
+ return 0;
+}
+EXPORT_SYMBOL(mxc_edid_parse_ext_blk);
+
+static int mxc_edid_readblk(struct i2c_adapter *adp,
+ unsigned short addr, unsigned char *edid)
+{
+ int ret = 0, extblknum = 0;
+ unsigned char regaddr = 0x0;
+ struct i2c_msg msg[2] = {
+ {
+ .addr = addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &regaddr,
+ }, {
+ .addr = addr,
+ .flags = I2C_M_RD,
+ .len = EDID_LENGTH,
+ .buf = edid,
+ },
+ };
+
+ ret = i2c_transfer(adp, msg, ARRAY_SIZE(msg));
+ if (ret != ARRAY_SIZE(msg)) {
+ DPRINTK("unable to read EDID block\n");
+ return -EIO;
+ }
+
+ if (edid[1] == 0x00)
+ return -ENOENT;
+
+ extblknum = edid[0x7E];
+
+ if (extblknum) {
+ regaddr = 128;
+ msg[1].buf = edid + EDID_LENGTH;
+
+ ret = i2c_transfer(adp, msg, ARRAY_SIZE(msg));
+ if (ret != ARRAY_SIZE(msg)) {
+ DPRINTK("unable to read EDID ext block\n");
+ return -EIO;
+ }
+ }
+
+ return extblknum;
+}
+
+static int mxc_edid_readsegblk(struct i2c_adapter *adp, unsigned short addr,
+ unsigned char *edid, int seg_num)
+{
+ int ret = 0;
+ unsigned char segment = 0x1, regaddr = 0;
+ struct i2c_msg msg[3] = {
+ {
+ .addr = 0x30,
+ .flags = 0,
+ .len = 1,
+ .buf = &segment,
+ }, {
+ .addr = addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &regaddr,
+ }, {
+ .addr = addr,
+ .flags = I2C_M_RD,
+ .len = EDID_LENGTH,
+ .buf = edid,
+ },
+ };
+
+ ret = i2c_transfer(adp, msg, ARRAY_SIZE(msg));
+ if (ret != ARRAY_SIZE(msg)) {
+ DPRINTK("unable to read EDID block\n");
+ return -EIO;
+ }
+
+ if (seg_num == 2) {
+ regaddr = 128;
+ msg[2].buf = edid + EDID_LENGTH;
+
+ ret = i2c_transfer(adp, msg, ARRAY_SIZE(msg));
+ if (ret != ARRAY_SIZE(msg)) {
+ DPRINTK("unable to read EDID block\n");
+ return -EIO;
+ }
+ }
+
+ return ret;
+}
+
+int mxc_edid_var_to_vic(struct fb_var_screeninfo *var)
+{
+ int i;
+ struct fb_videomode m;
+
+ for (i = 0; i < ARRAY_SIZE(mxc_cea_mode); i++) {
+ fb_var_to_videomode(&m, var);
+ if (mxc_edid_fb_mode_is_equal(false, &m, &mxc_cea_mode[i]))
+ break;
+ }
+
+ if (i == ARRAY_SIZE(mxc_cea_mode))
+ return 0;
+
+ return i;
+}
+EXPORT_SYMBOL(mxc_edid_var_to_vic);
+
+int mxc_edid_mode_to_vic(const struct fb_videomode *mode)
+{
+ int i;
+ bool use_aspect = (mode->vmode & FB_VMODE_ASPECT_MASK);
+
+ for (i = 0; i < ARRAY_SIZE(mxc_cea_mode); i++) {
+ if (mxc_edid_fb_mode_is_equal(use_aspect, mode, &mxc_cea_mode[i]))
+ break;
+ }
+
+ if (i == ARRAY_SIZE(mxc_cea_mode))
+ return 0;
+
+ return i;
+}
+EXPORT_SYMBOL(mxc_edid_mode_to_vic);
+
+/* make sure edid has 512 bytes*/
+int mxc_edid_read(struct i2c_adapter *adp, unsigned short addr,
+ unsigned char *edid, struct mxc_edid_cfg *cfg, struct fb_info *fbi)
+{
+ int ret = 0, extblknum;
+ if (!adp || !edid || !cfg || !fbi)
+ return -EINVAL;
+
+ memset(edid, 0, EDID_LENGTH*4);
+ memset(cfg, 0, sizeof(struct mxc_edid_cfg));
+
+ extblknum = mxc_edid_readblk(adp, addr, edid);
+ if (extblknum < 0)
+ return extblknum;
+
+ /* edid first block parsing */
+ memset(&fbi->monspecs, 0, sizeof(fbi->monspecs));
+ fb_edid_to_monspecs(edid, &fbi->monspecs);
+
+ if (extblknum) {
+ int i;
+
+ /* FIXME: mxc_edid_readsegblk() won't read more than 2 blocks
+ * and the for-loop will read past the end of the buffer! :-( */
+ if (extblknum > 3) {
+ WARN_ON(true);
+ return -EINVAL;
+ }
+
+ /* need read segment block? */
+ if (extblknum > 1) {
+ ret = mxc_edid_readsegblk(adp, addr,
+ edid + EDID_LENGTH*2, extblknum - 1);
+ if (ret < 0)
+ return ret;
+ }
+
+ for (i = 1; i <= extblknum; i++)
+ /* edid ext block parsing */
+ mxc_edid_parse_ext_blk(edid + i*EDID_LENGTH,
+ cfg, &fbi->monspecs);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(mxc_edid_read);
+
diff --git a/drivers/video/fbdev/mxc/mxc_epdc_fb.c b/drivers/video/fbdev/mxc/mxc_epdc_fb.c
new file mode 100644
index 000000000000..0109b0371b76
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mxc_epdc_fb.c
@@ -0,0 +1,5601 @@
+/*
+ * Copyright (C) 2010-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; 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
+ *
+ */
+/*
+ * Based on STMP378X LCDIF
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+#include <linux/busfreq-imx.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/uaccess.h>
+#include <linux/cpufreq.h>
+#include <linux/firmware.h>
+#include <linux/kthread.h>
+#include <linux/dmaengine.h>
+#include <linux/pxp_dma.h>
+#include <linux/pm_runtime.h>
+#include <linux/mxcfb.h>
+#include <linux/mxcfb_epdc.h>
+#include <linux/gpio.h>
+#include <linux/regulator/driver.h>
+#include <linux/fsl_devices.h>
+#include <linux/bitops.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_data/dma-imx.h>
+#include <asm/cacheflush.h>
+
+#include "epdc_regs.h"
+
+/*
+ * Enable this define to have a default panel
+ * loaded during driver initialization
+ */
+/*#define DEFAULT_PANEL_HW_INIT*/
+
+#define NUM_SCREENS_MIN 2
+
+#define EPDC_V1_NUM_LUTS 16
+#define EPDC_V1_MAX_NUM_UPDATES 20
+#define EPDC_V2_NUM_LUTS 64
+#define EPDC_V2_MAX_NUM_UPDATES 64
+#define EPDC_MAX_NUM_BUFFERS 2
+#define INVALID_LUT (-1)
+#define DRY_RUN_NO_LUT 100
+
+/* Maximum update buffer image width due to v2.0 and v2.1 errata ERR005313. */
+#define EPDC_V2_MAX_UPDATE_WIDTH 2047
+#define EPDC_V2_ROTATION_ALIGNMENT 8
+
+#define DEFAULT_TEMP_INDEX 0
+#define DEFAULT_TEMP 20 /* room temp in deg Celsius */
+
+#define INIT_UPDATE_MARKER 0x12345678
+#define PAN_UPDATE_MARKER 0x12345679
+
+#define POWER_STATE_OFF 0
+#define POWER_STATE_ON 1
+
+#define MERGE_OK 0
+#define MERGE_FAIL 1
+#define MERGE_BLOCK 2
+
+static unsigned long default_bpp = 16;
+static DEFINE_MUTEX(hard_lock);
+
+struct update_marker_data {
+ struct list_head full_list;
+ struct list_head upd_list;
+ u32 update_marker;
+ struct completion update_completion;
+ int lut_num;
+ bool collision_test;
+ bool waiting;
+};
+
+struct update_desc_list {
+ struct list_head list;
+ struct mxcfb_update_data upd_data;/* Update parameters */
+ u32 epdc_offs; /* Added to buffer ptr to resolve alignment */
+ u32 epdc_stride; /* Depends on rotation & whether we skip PxP */
+ struct list_head upd_marker_list; /* List of markers for this update */
+ u32 update_order; /* Numeric ordering value for update */
+};
+
+/* This structure represents a list node containing both
+ * a memory region allocated as an output buffer for the PxP
+ * update processing task, and the update description (mode, region, etc.) */
+struct update_data_list {
+ struct list_head list;
+ dma_addr_t phys_addr; /* Pointer to phys address of processed Y buf */
+ void *virt_addr;
+ struct update_desc_list *update_desc;
+ int lut_num; /* Assigned before update is processed into working buffer */
+ u64 collision_mask; /* Set when update creates collision */
+ /* Mask of the LUTs the update collides with */
+};
+
+struct mxc_epdc_fb_data {
+ struct fb_info info;
+ struct fb_var_screeninfo epdc_fb_var; /* Internal copy of screeninfo
+ so we can sync changes to it */
+ u32 pseudo_palette[16];
+ char fw_str[24];
+ struct list_head list;
+ struct imx_epdc_fb_mode *cur_mode;
+ struct imx_epdc_fb_platform_data *pdata;
+ int blank;
+ u32 max_pix_size;
+ ssize_t map_size;
+ dma_addr_t phys_start;
+ u32 fb_offset;
+ int default_bpp;
+ int native_width;
+ int native_height;
+ int num_screens;
+ int epdc_irq;
+ struct device *dev;
+ int power_state;
+ int wait_for_powerdown;
+ struct completion powerdown_compl;
+ struct clk *epdc_clk_axi;
+ struct clk *epdc_clk_pix;
+ struct regulator *display_regulator;
+ struct regulator *vcom_regulator;
+ struct regulator *v3p3_regulator;
+ bool fw_default_load;
+ int rev;
+
+ /* FB elements related to EPDC updates */
+ int num_luts;
+ int max_num_updates;
+ bool in_init;
+ bool hw_ready;
+ bool hw_initializing;
+ bool waiting_for_idle;
+ u32 auto_mode;
+ u32 upd_scheme;
+ struct list_head upd_pending_list;
+ struct list_head upd_buf_queue;
+ struct list_head upd_buf_free_list;
+ struct list_head upd_buf_collision_list;
+ struct update_data_list *cur_update;
+ struct mutex queue_mutex;
+ int trt_entries;
+ int temp_index;
+ u8 *temp_range_bounds;
+ struct mxcfb_waveform_modes wv_modes;
+ bool wv_modes_update;
+ u32 *waveform_buffer_virt;
+ u32 waveform_buffer_phys;
+ u32 waveform_buffer_size;
+ u32 *working_buffer_virt;
+ u32 working_buffer_phys;
+ u32 working_buffer_size;
+ dma_addr_t *phys_addr_updbuf;
+ void **virt_addr_updbuf;
+ u32 upd_buffer_num;
+ u32 max_num_buffers;
+ dma_addr_t phys_addr_copybuf; /* Phys address of copied update data */
+ void *virt_addr_copybuf; /* Used for PxP SW workaround */
+ u32 order_cnt;
+ struct list_head full_marker_list;
+ u32 *lut_update_order; /* Array size = number of luts */
+ u64 epdc_colliding_luts;
+ u64 luts_complete_wb;
+ struct completion updates_done;
+ struct delayed_work epdc_done_work;
+ struct workqueue_struct *epdc_submit_workqueue;
+ struct work_struct epdc_submit_work;
+ struct workqueue_struct *epdc_intr_workqueue;
+ struct work_struct epdc_intr_work;
+ bool waiting_for_wb;
+ bool waiting_for_lut;
+ bool waiting_for_lut15;
+ struct completion update_res_free;
+ struct completion lut15_free;
+ struct completion eof_event;
+ int eof_sync_period;
+ struct mutex power_mutex;
+ bool powering_down;
+ bool updates_active;
+ int pwrdown_delay;
+ unsigned long tce_prevent;
+ bool restrict_width; /* work around rev >=2.0 width and
+ stride restriction */
+
+ /* FB elements related to PxP DMA */
+ struct completion pxp_tx_cmpl;
+ struct pxp_channel *pxp_chan;
+ struct pxp_config_data pxp_conf;
+ struct dma_async_tx_descriptor *txd;
+ dma_cookie_t cookie;
+ struct scatterlist sg[2];
+ struct mutex pxp_mutex; /* protects access to PxP */
+};
+
+struct waveform_data_header {
+ unsigned int wi0;
+ unsigned int wi1;
+ unsigned int wi2;
+ unsigned int wi3;
+ unsigned int wi4;
+ unsigned int wi5;
+ unsigned int wi6;
+ unsigned int xwia:24;
+ unsigned int cs1:8;
+ unsigned int wmta:24;
+ unsigned int fvsn:8;
+ unsigned int luts:8;
+ unsigned int mc:8;
+ unsigned int trc:8;
+ unsigned int reserved0_0:8;
+ unsigned int eb:8;
+ unsigned int sb:8;
+ unsigned int reserved0_1:8;
+ unsigned int reserved0_2:8;
+ unsigned int reserved0_3:8;
+ unsigned int reserved0_4:8;
+ unsigned int reserved0_5:8;
+ unsigned int cs2:8;
+};
+
+struct mxcfb_waveform_data_file {
+ struct waveform_data_header wdh;
+ u32 *data; /* Temperature Range Table + Waveform Data */
+};
+
+static struct fb_videomode e60_v110_mode = {
+ .name = "E60_V110",
+ .refresh = 50,
+ .xres = 800,
+ .yres = 600,
+ .pixclock = 18604700,
+ .left_margin = 8,
+ .right_margin = 178,
+ .upper_margin = 4,
+ .lower_margin = 10,
+ .hsync_len = 20,
+ .vsync_len = 4,
+ .sync = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .flag = 0,
+};
+
+static struct fb_videomode e60_v220_mode = {
+ .name = "E60_V220",
+ .refresh = 85,
+ .xres = 800,
+ .yres = 600,
+ .pixclock = 30000000,
+ .left_margin = 8,
+ .right_margin = 164,
+ .upper_margin = 4,
+ .lower_margin = 8,
+ .hsync_len = 4,
+ .vsync_len = 1,
+ .sync = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .flag = 0,
+};
+
+static struct fb_videomode e060scm_mode = {
+ .name = "E060SCM",
+ .refresh = 85,
+ .xres = 800,
+ .yres = 600,
+ .pixclock = 26666667,
+ .left_margin = 8,
+ .right_margin = 100,
+ .upper_margin = 4,
+ .lower_margin = 8,
+ .hsync_len = 4,
+ .vsync_len = 1,
+ .sync = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .flag = 0,
+};
+
+static struct fb_videomode e97_v110_mode = {
+ .name = "E97_V110",
+ .refresh = 50,
+ .xres = 1200,
+ .yres = 825,
+ .pixclock = 32000000,
+ .left_margin = 12,
+ .right_margin = 128,
+ .upper_margin = 4,
+ .lower_margin = 10,
+ .hsync_len = 20,
+ .vsync_len = 4,
+ .sync = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .flag = 0,
+};
+
+static struct imx_epdc_fb_mode panel_modes[] = {
+ {
+ &e60_v110_mode,
+ 4, /* vscan_holdoff */
+ 10, /* sdoed_width */
+ 20, /* sdoed_delay */
+ 10, /* sdoez_width */
+ 20, /* sdoez_delay */
+ 428, /* gdclk_hp_offs */
+ 20, /* gdsp_offs */
+ 0, /* gdoe_offs */
+ 1, /* gdclk_offs */
+ 1, /* num_ce */
+ },
+ {
+ &e60_v220_mode,
+ 4, /* vscan_holdoff */
+ 10, /* sdoed_width */
+ 20, /* sdoed_delay */
+ 10, /* sdoez_width */
+ 20, /* sdoez_delay */
+ 465, /* gdclk_hp_offs */
+ 20, /* gdsp_offs */
+ 0, /* gdoe_offs */
+ 9, /* gdclk_offs */
+ 1, /* num_ce */
+ },
+ {
+ &e060scm_mode,
+ 4, /* vscan_holdoff */
+ 10, /* sdoed_width */
+ 20, /* sdoed_delay */
+ 10, /* sdoez_width */
+ 20, /* sdoez_delay */
+ 419, /* gdclk_hp_offs */
+ 20, /* gdsp_offs */
+ 0, /* gdoe_offs */
+ 5, /* gdclk_offs */
+ 1, /* num_ce */
+ },
+ {
+ &e97_v110_mode,
+ 8, /* vscan_holdoff */
+ 10, /* sdoed_width */
+ 20, /* sdoed_delay */
+ 10, /* sdoez_width */
+ 20, /* sdoez_delay */
+ 632, /* gdclk_hp_offs */
+ 20, /* gdsp_offs */
+ 0, /* gdoe_offs */
+ 1, /* gdclk_offs */
+ 3, /* num_ce */
+ }
+};
+
+static struct imx_epdc_fb_platform_data epdc_data = {
+ .epdc_mode = panel_modes,
+ .num_modes = ARRAY_SIZE(panel_modes),
+};
+
+void __iomem *epdc_base;
+
+struct mxc_epdc_fb_data *g_fb_data;
+
+/* forward declaration */
+static int mxc_epdc_fb_get_temp_index(struct mxc_epdc_fb_data *fb_data,
+ int temp);
+static void mxc_epdc_fb_flush_updates(struct mxc_epdc_fb_data *fb_data);
+static int mxc_epdc_fb_blank(int blank, struct fb_info *info);
+static int mxc_epdc_fb_init_hw(struct fb_info *info);
+static int pxp_process_update(struct mxc_epdc_fb_data *fb_data,
+ u32 src_width, u32 src_height,
+ struct mxcfb_rect *update_region);
+static int pxp_complete_update(struct mxc_epdc_fb_data *fb_data, u32 *hist_stat);
+
+static void draw_mode0(struct mxc_epdc_fb_data *fb_data);
+static bool is_free_list_full(struct mxc_epdc_fb_data *fb_data);
+
+static void do_dithering_processing_Y1_v1_0(
+ unsigned char *update_region_virt_ptr,
+ dma_addr_t update_region_phys_ptr,
+ struct mxcfb_rect *update_region,
+ unsigned long update_region_stride,
+ int *err_dist);
+static void do_dithering_processing_Y4_v1_0(
+ unsigned char *update_region_virt_ptr,
+ dma_addr_t update_region_phys_ptr,
+ struct mxcfb_rect *update_region,
+ unsigned long update_region_stride,
+ int *err_dist);
+
+#ifdef DEBUG
+static void dump_pxp_config(struct mxc_epdc_fb_data *fb_data,
+ struct pxp_config_data *pxp_conf)
+{
+ dev_info(fb_data->dev, "S0 fmt 0x%x",
+ pxp_conf->s0_param.pixel_fmt);
+ dev_info(fb_data->dev, "S0 width 0x%x",
+ pxp_conf->s0_param.width);
+ dev_info(fb_data->dev, "S0 height 0x%x",
+ pxp_conf->s0_param.height);
+ dev_info(fb_data->dev, "S0 ckey 0x%x",
+ pxp_conf->s0_param.color_key);
+ dev_info(fb_data->dev, "S0 ckey en 0x%x",
+ pxp_conf->s0_param.color_key_enable);
+
+ dev_info(fb_data->dev, "OL0 combine en 0x%x",
+ pxp_conf->ol_param[0].combine_enable);
+ dev_info(fb_data->dev, "OL0 fmt 0x%x",
+ pxp_conf->ol_param[0].pixel_fmt);
+ dev_info(fb_data->dev, "OL0 width 0x%x",
+ pxp_conf->ol_param[0].width);
+ dev_info(fb_data->dev, "OL0 height 0x%x",
+ pxp_conf->ol_param[0].height);
+ dev_info(fb_data->dev, "OL0 ckey 0x%x",
+ pxp_conf->ol_param[0].color_key);
+ dev_info(fb_data->dev, "OL0 ckey en 0x%x",
+ pxp_conf->ol_param[0].color_key_enable);
+ dev_info(fb_data->dev, "OL0 alpha 0x%x",
+ pxp_conf->ol_param[0].global_alpha);
+ dev_info(fb_data->dev, "OL0 alpha en 0x%x",
+ pxp_conf->ol_param[0].global_alpha_enable);
+ dev_info(fb_data->dev, "OL0 local alpha en 0x%x",
+ pxp_conf->ol_param[0].local_alpha_enable);
+
+ dev_info(fb_data->dev, "Out fmt 0x%x",
+ pxp_conf->out_param.pixel_fmt);
+ dev_info(fb_data->dev, "Out width 0x%x",
+ pxp_conf->out_param.width);
+ dev_info(fb_data->dev, "Out height 0x%x",
+ pxp_conf->out_param.height);
+
+ dev_info(fb_data->dev,
+ "drect left 0x%x right 0x%x width 0x%x height 0x%x",
+ pxp_conf->proc_data.drect.left, pxp_conf->proc_data.drect.top,
+ pxp_conf->proc_data.drect.width,
+ pxp_conf->proc_data.drect.height);
+ dev_info(fb_data->dev,
+ "srect left 0x%x right 0x%x width 0x%x height 0x%x",
+ pxp_conf->proc_data.srect.left, pxp_conf->proc_data.srect.top,
+ pxp_conf->proc_data.srect.width,
+ pxp_conf->proc_data.srect.height);
+ dev_info(fb_data->dev, "Scaling en 0x%x", pxp_conf->proc_data.scaling);
+ dev_info(fb_data->dev, "HFlip en 0x%x", pxp_conf->proc_data.hflip);
+ dev_info(fb_data->dev, "VFlip en 0x%x", pxp_conf->proc_data.vflip);
+ dev_info(fb_data->dev, "Rotation 0x%x", pxp_conf->proc_data.rotate);
+ dev_info(fb_data->dev, "BG Color 0x%x", pxp_conf->proc_data.bgcolor);
+}
+
+static void dump_epdc_reg(void)
+{
+ printk(KERN_DEBUG "\n\n");
+ printk(KERN_DEBUG "EPDC_CTRL 0x%x\n", __raw_readl(EPDC_CTRL));
+ printk(KERN_DEBUG "EPDC_WVADDR 0x%x\n", __raw_readl(EPDC_WVADDR));
+ printk(KERN_DEBUG "EPDC_WB_ADDR 0x%x\n", __raw_readl(EPDC_WB_ADDR));
+ printk(KERN_DEBUG "EPDC_RES 0x%x\n", __raw_readl(EPDC_RES));
+ printk(KERN_DEBUG "EPDC_FORMAT 0x%x\n", __raw_readl(EPDC_FORMAT));
+ printk(KERN_DEBUG "EPDC_FIFOCTRL 0x%x\n", __raw_readl(EPDC_FIFOCTRL));
+ printk(KERN_DEBUG "EPDC_UPD_ADDR 0x%x\n", __raw_readl(EPDC_UPD_ADDR));
+ printk(KERN_DEBUG "EPDC_UPD_STRIDE 0x%x\n", __raw_readl(EPDC_UPD_STRIDE));
+ printk(KERN_DEBUG "EPDC_UPD_FIXED 0x%x\n", __raw_readl(EPDC_UPD_FIXED));
+ printk(KERN_DEBUG "EPDC_UPD_CORD 0x%x\n", __raw_readl(EPDC_UPD_CORD));
+ printk(KERN_DEBUG "EPDC_UPD_SIZE 0x%x\n", __raw_readl(EPDC_UPD_SIZE));
+ printk(KERN_DEBUG "EPDC_UPD_CTRL 0x%x\n", __raw_readl(EPDC_UPD_CTRL));
+ printk(KERN_DEBUG "EPDC_TEMP 0x%x\n", __raw_readl(EPDC_TEMP));
+ printk(KERN_DEBUG "EPDC_AUTOWV_LUT 0x%x\n", __raw_readl(EPDC_AUTOWV_LUT));
+ printk(KERN_DEBUG "EPDC_TCE_CTRL 0x%x\n", __raw_readl(EPDC_TCE_CTRL));
+ printk(KERN_DEBUG "EPDC_TCE_SDCFG 0x%x\n", __raw_readl(EPDC_TCE_SDCFG));
+ printk(KERN_DEBUG "EPDC_TCE_GDCFG 0x%x\n", __raw_readl(EPDC_TCE_GDCFG));
+ printk(KERN_DEBUG "EPDC_TCE_HSCAN1 0x%x\n", __raw_readl(EPDC_TCE_HSCAN1));
+ printk(KERN_DEBUG "EPDC_TCE_HSCAN2 0x%x\n", __raw_readl(EPDC_TCE_HSCAN2));
+ printk(KERN_DEBUG "EPDC_TCE_VSCAN 0x%x\n", __raw_readl(EPDC_TCE_VSCAN));
+ printk(KERN_DEBUG "EPDC_TCE_OE 0x%x\n", __raw_readl(EPDC_TCE_OE));
+ printk(KERN_DEBUG "EPDC_TCE_POLARITY 0x%x\n", __raw_readl(EPDC_TCE_POLARITY));
+ printk(KERN_DEBUG "EPDC_TCE_TIMING1 0x%x\n", __raw_readl(EPDC_TCE_TIMING1));
+ printk(KERN_DEBUG "EPDC_TCE_TIMING2 0x%x\n", __raw_readl(EPDC_TCE_TIMING2));
+ printk(KERN_DEBUG "EPDC_TCE_TIMING3 0x%x\n", __raw_readl(EPDC_TCE_TIMING3));
+ printk(KERN_DEBUG "EPDC_PIGEON_CTRL0 0x%x\n", __raw_readl(EPDC_PIGEON_CTRL0));
+ printk(KERN_DEBUG "EPDC_PIGEON_CTRL1 0x%x\n", __raw_readl(EPDC_PIGEON_CTRL1));
+ printk(KERN_DEBUG "EPDC_IRQ_MASK1 0x%x\n", __raw_readl(EPDC_IRQ_MASK1));
+ printk(KERN_DEBUG "EPDC_IRQ_MASK2 0x%x\n", __raw_readl(EPDC_IRQ_MASK2));
+ printk(KERN_DEBUG "EPDC_IRQ1 0x%x\n", __raw_readl(EPDC_IRQ1));
+ printk(KERN_DEBUG "EPDC_IRQ2 0x%x\n", __raw_readl(EPDC_IRQ2));
+ printk(KERN_DEBUG "EPDC_IRQ_MASK 0x%x\n", __raw_readl(EPDC_IRQ_MASK));
+ printk(KERN_DEBUG "EPDC_IRQ 0x%x\n", __raw_readl(EPDC_IRQ));
+ printk(KERN_DEBUG "EPDC_STATUS_LUTS 0x%x\n", __raw_readl(EPDC_STATUS_LUTS));
+ printk(KERN_DEBUG "EPDC_STATUS_LUTS2 0x%x\n", __raw_readl(EPDC_STATUS_LUTS2));
+ printk(KERN_DEBUG "EPDC_STATUS_NEXTLUT 0x%x\n", __raw_readl(EPDC_STATUS_NEXTLUT));
+ printk(KERN_DEBUG "EPDC_STATUS_COL1 0x%x\n", __raw_readl(EPDC_STATUS_COL));
+ printk(KERN_DEBUG "EPDC_STATUS_COL2 0x%x\n", __raw_readl(EPDC_STATUS_COL2));
+ printk(KERN_DEBUG "EPDC_STATUS 0x%x\n", __raw_readl(EPDC_STATUS));
+ printk(KERN_DEBUG "EPDC_UPD_COL_CORD 0x%x\n", __raw_readl(EPDC_UPD_COL_CORD));
+ printk(KERN_DEBUG "EPDC_UPD_COL_SIZE 0x%x\n", __raw_readl(EPDC_UPD_COL_SIZE));
+ printk(KERN_DEBUG "EPDC_DEBUG 0x%x\n", __raw_readl(EPDC_DEBUG));
+ printk(KERN_DEBUG "EPDC_DEBUG_LUT 0x%x\n", __raw_readl(EPDC_DEBUG_LUT));
+ printk(KERN_DEBUG "EPDC_HIST1_PARAM 0x%x\n", __raw_readl(EPDC_HIST1_PARAM));
+ printk(KERN_DEBUG "EPDC_HIST2_PARAM 0x%x\n", __raw_readl(EPDC_HIST2_PARAM));
+ printk(KERN_DEBUG "EPDC_HIST4_PARAM 0x%x\n", __raw_readl(EPDC_HIST4_PARAM));
+ printk(KERN_DEBUG "EPDC_HIST8_PARAM0 0x%x\n", __raw_readl(EPDC_HIST8_PARAM0));
+ printk(KERN_DEBUG "EPDC_HIST8_PARAM1 0x%x\n", __raw_readl(EPDC_HIST8_PARAM1));
+ printk(KERN_DEBUG "EPDC_HIST16_PARAM0 0x%x\n", __raw_readl(EPDC_HIST16_PARAM0));
+ printk(KERN_DEBUG "EPDC_HIST16_PARAM1 0x%x\n", __raw_readl(EPDC_HIST16_PARAM1));
+ printk(KERN_DEBUG "EPDC_HIST16_PARAM2 0x%x\n", __raw_readl(EPDC_HIST16_PARAM2));
+ printk(KERN_DEBUG "EPDC_HIST16_PARAM3 0x%x\n", __raw_readl(EPDC_HIST16_PARAM3));
+ printk(KERN_DEBUG "EPDC_GPIO 0x%x\n", __raw_readl(EPDC_GPIO));
+ printk(KERN_DEBUG "EPDC_VERSION 0x%x\n", __raw_readl(EPDC_VERSION));
+ printk(KERN_DEBUG "\n\n");
+}
+
+static void dump_update_data(struct device *dev,
+ struct update_data_list *upd_data_list)
+{
+ dev_info(dev,
+ "X = %d, Y = %d, Width = %d, Height = %d, WaveMode = %d, "
+ "LUT = %d, Coll Mask = 0x%llx, order = %d\n",
+ upd_data_list->update_desc->upd_data.update_region.left,
+ upd_data_list->update_desc->upd_data.update_region.top,
+ upd_data_list->update_desc->upd_data.update_region.width,
+ upd_data_list->update_desc->upd_data.update_region.height,
+ upd_data_list->update_desc->upd_data.waveform_mode,
+ upd_data_list->lut_num,
+ upd_data_list->collision_mask,
+ upd_data_list->update_desc->update_order);
+}
+
+static void dump_collision_list(struct mxc_epdc_fb_data *fb_data)
+{
+ struct update_data_list *plist;
+
+ dev_info(fb_data->dev, "Collision List:\n");
+ if (list_empty(&fb_data->upd_buf_collision_list))
+ dev_info(fb_data->dev, "Empty");
+ list_for_each_entry(plist, &fb_data->upd_buf_collision_list, list) {
+ dev_info(fb_data->dev, "Virt Addr = 0x%x, Phys Addr = 0x%x ",
+ (u32)plist->virt_addr, plist->phys_addr);
+ dump_update_data(fb_data->dev, plist);
+ }
+}
+
+static void dump_free_list(struct mxc_epdc_fb_data *fb_data)
+{
+ struct update_data_list *plist;
+
+ dev_info(fb_data->dev, "Free List:\n");
+ if (list_empty(&fb_data->upd_buf_free_list))
+ dev_info(fb_data->dev, "Empty");
+ list_for_each_entry(plist, &fb_data->upd_buf_free_list, list)
+ dev_info(fb_data->dev, "Virt Addr = 0x%x, Phys Addr = 0x%x ",
+ (u32)plist->virt_addr, plist->phys_addr);
+}
+
+static void dump_queue(struct mxc_epdc_fb_data *fb_data)
+{
+ struct update_data_list *plist;
+
+ dev_info(fb_data->dev, "Queue:\n");
+ if (list_empty(&fb_data->upd_buf_queue))
+ dev_info(fb_data->dev, "Empty");
+ list_for_each_entry(plist, &fb_data->upd_buf_queue, list) {
+ dev_info(fb_data->dev, "Virt Addr = 0x%x, Phys Addr = 0x%x ",
+ (u32)plist->virt_addr, plist->phys_addr);
+ dump_update_data(fb_data->dev, plist);
+ }
+}
+
+static void dump_desc_data(struct device *dev,
+ struct update_desc_list *upd_desc_list)
+{
+ dev_info(dev,
+ "X = %d, Y = %d, Width = %d, Height = %d, WaveMode = %d, "
+ "order = %d\n",
+ upd_desc_list->upd_data.update_region.left,
+ upd_desc_list->upd_data.update_region.top,
+ upd_desc_list->upd_data.update_region.width,
+ upd_desc_list->upd_data.update_region.height,
+ upd_desc_list->upd_data.waveform_mode,
+ upd_desc_list->update_order);
+}
+
+static void dump_pending_list(struct mxc_epdc_fb_data *fb_data)
+{
+ struct update_desc_list *plist;
+
+ dev_info(fb_data->dev, "Queue:\n");
+ if (list_empty(&fb_data->upd_pending_list))
+ dev_info(fb_data->dev, "Empty");
+ list_for_each_entry(plist, &fb_data->upd_pending_list, list)
+ dump_desc_data(fb_data->dev, plist);
+}
+
+static void dump_all_updates(struct mxc_epdc_fb_data *fb_data)
+{
+ dump_free_list(fb_data);
+ dump_queue(fb_data);
+ dump_collision_list(fb_data);
+ dev_info(fb_data->dev, "Current update being processed:\n");
+ if (fb_data->cur_update == NULL)
+ dev_info(fb_data->dev, "No current update\n");
+ else
+ dump_update_data(fb_data->dev, fb_data->cur_update);
+}
+#else
+static inline void dump_pxp_config(struct mxc_epdc_fb_data *fb_data,
+ struct pxp_config_data *pxp_conf) {}
+static inline void dump_epdc_reg(void) {}
+static inline void dump_update_data(struct device *dev,
+ struct update_data_list *upd_data_list) {}
+static inline void dump_collision_list(struct mxc_epdc_fb_data *fb_data) {}
+static inline void dump_free_list(struct mxc_epdc_fb_data *fb_data) {}
+static inline void dump_queue(struct mxc_epdc_fb_data *fb_data) {}
+static inline void dump_all_updates(struct mxc_epdc_fb_data *fb_data) {}
+
+#endif
+
+
+/********************************************************
+ * Start Low-Level EPDC Functions
+ ********************************************************/
+
+static inline void epdc_lut_complete_intr(int rev, u32 lut_num, bool enable)
+{
+ if (rev < 20) {
+ if (enable)
+ __raw_writel(1 << lut_num, EPDC_IRQ_MASK_SET);
+ else
+ __raw_writel(1 << lut_num, EPDC_IRQ_MASK_CLEAR);
+ } else {
+ if (enable) {
+ if (lut_num < 32)
+ __raw_writel(1 << lut_num, EPDC_IRQ_MASK1_SET);
+ else
+ __raw_writel(1 << (lut_num - 32),
+ EPDC_IRQ_MASK2_SET);
+ } else {
+ if (lut_num < 32)
+ __raw_writel(1 << lut_num,
+ EPDC_IRQ_MASK1_CLEAR);
+ else
+ __raw_writel(1 << (lut_num - 32),
+ EPDC_IRQ_MASK2_CLEAR);
+ }
+ }
+}
+
+static inline void epdc_working_buf_intr(bool enable)
+{
+ if (enable)
+ __raw_writel(EPDC_IRQ_WB_CMPLT_IRQ, EPDC_IRQ_MASK_SET);
+ else
+ __raw_writel(EPDC_IRQ_WB_CMPLT_IRQ, EPDC_IRQ_MASK_CLEAR);
+}
+
+static inline void epdc_clear_working_buf_irq(void)
+{
+ __raw_writel(EPDC_IRQ_WB_CMPLT_IRQ | EPDC_IRQ_LUT_COL_IRQ,
+ EPDC_IRQ_CLEAR);
+}
+
+static inline void epdc_eof_intr(bool enable)
+{
+ if (enable)
+ __raw_writel(EPDC_IRQ_FRAME_END_IRQ, EPDC_IRQ_MASK_SET);
+ else
+ __raw_writel(EPDC_IRQ_FRAME_END_IRQ, EPDC_IRQ_MASK_CLEAR);
+}
+
+static inline void epdc_clear_eof_irq(void)
+{
+ __raw_writel(EPDC_IRQ_FRAME_END_IRQ, EPDC_IRQ_CLEAR);
+}
+
+static inline bool epdc_signal_eof(void)
+{
+ return (__raw_readl(EPDC_IRQ_MASK) & __raw_readl(EPDC_IRQ)
+ & EPDC_IRQ_FRAME_END_IRQ) ? true : false;
+}
+
+static inline void epdc_set_temp(u32 temp)
+{
+ __raw_writel(temp, EPDC_TEMP);
+}
+
+static inline void epdc_set_screen_res(u32 width, u32 height)
+{
+ u32 val = (height << EPDC_RES_VERTICAL_OFFSET) | width;
+ __raw_writel(val, EPDC_RES);
+}
+
+static inline void epdc_set_update_addr(u32 addr)
+{
+ __raw_writel(addr, EPDC_UPD_ADDR);
+}
+
+static inline void epdc_set_update_coord(u32 x, u32 y)
+{
+ u32 val = (y << EPDC_UPD_CORD_YCORD_OFFSET) | x;
+ __raw_writel(val, EPDC_UPD_CORD);
+}
+
+static inline void epdc_set_update_dimensions(u32 width, u32 height)
+{
+ u32 val = (height << EPDC_UPD_SIZE_HEIGHT_OFFSET) | width;
+ __raw_writel(val, EPDC_UPD_SIZE);
+}
+
+static void epdc_set_update_waveform(struct mxcfb_waveform_modes *wv_modes)
+{
+ u32 val;
+
+ /* Configure the auto-waveform look-up table based on waveform modes */
+
+ /* Entry 1 = DU, 2 = GC4, 3 = GC8, etc. */
+ val = (wv_modes->mode_du << EPDC_AUTOWV_LUT_DATA_OFFSET) |
+ (0 << EPDC_AUTOWV_LUT_ADDR_OFFSET);
+ __raw_writel(val, EPDC_AUTOWV_LUT);
+ val = (wv_modes->mode_du << EPDC_AUTOWV_LUT_DATA_OFFSET) |
+ (1 << EPDC_AUTOWV_LUT_ADDR_OFFSET);
+ __raw_writel(val, EPDC_AUTOWV_LUT);
+ val = (wv_modes->mode_gc4 << EPDC_AUTOWV_LUT_DATA_OFFSET) |
+ (2 << EPDC_AUTOWV_LUT_ADDR_OFFSET);
+ __raw_writel(val, EPDC_AUTOWV_LUT);
+ val = (wv_modes->mode_gc8 << EPDC_AUTOWV_LUT_DATA_OFFSET) |
+ (3 << EPDC_AUTOWV_LUT_ADDR_OFFSET);
+ __raw_writel(val, EPDC_AUTOWV_LUT);
+ val = (wv_modes->mode_gc16 << EPDC_AUTOWV_LUT_DATA_OFFSET) |
+ (4 << EPDC_AUTOWV_LUT_ADDR_OFFSET);
+ __raw_writel(val, EPDC_AUTOWV_LUT);
+ val = (wv_modes->mode_gc32 << EPDC_AUTOWV_LUT_DATA_OFFSET) |
+ (5 << EPDC_AUTOWV_LUT_ADDR_OFFSET);
+ __raw_writel(val, EPDC_AUTOWV_LUT);
+}
+
+static void epdc_set_update_stride(u32 stride)
+{
+ __raw_writel(stride, EPDC_UPD_STRIDE);
+}
+
+static void epdc_submit_update(u32 lut_num, u32 waveform_mode, u32 update_mode,
+ bool use_dry_run, bool use_test_mode, u32 np_val)
+{
+ u32 reg_val = 0;
+
+ if (use_test_mode) {
+ reg_val |=
+ ((np_val << EPDC_UPD_FIXED_FIXNP_OFFSET) &
+ EPDC_UPD_FIXED_FIXNP_MASK) | EPDC_UPD_FIXED_FIXNP_EN;
+
+ __raw_writel(reg_val, EPDC_UPD_FIXED);
+
+ reg_val = EPDC_UPD_CTRL_USE_FIXED;
+ } else {
+ __raw_writel(reg_val, EPDC_UPD_FIXED);
+ }
+
+ if (waveform_mode == WAVEFORM_MODE_AUTO)
+ reg_val |= EPDC_UPD_CTRL_AUTOWV;
+ else
+ reg_val |= ((waveform_mode <<
+ EPDC_UPD_CTRL_WAVEFORM_MODE_OFFSET) &
+ EPDC_UPD_CTRL_WAVEFORM_MODE_MASK);
+
+ reg_val |= (use_dry_run ? EPDC_UPD_CTRL_DRY_RUN : 0) |
+ ((lut_num << EPDC_UPD_CTRL_LUT_SEL_OFFSET) &
+ EPDC_UPD_CTRL_LUT_SEL_MASK) |
+ update_mode;
+
+ __raw_writel(reg_val, EPDC_UPD_CTRL);
+}
+
+static inline bool epdc_is_lut_complete(int rev, u32 lut_num)
+{
+ u32 val;
+ bool is_compl;
+ if (rev < 20) {
+ val = __raw_readl(EPDC_IRQ);
+ is_compl = val & (1 << lut_num) ? true : false;
+ } else if (lut_num < 32) {
+ val = __raw_readl(EPDC_IRQ1);
+ is_compl = val & (1 << lut_num) ? true : false;
+ } else {
+ val = __raw_readl(EPDC_IRQ2);
+ is_compl = val & (1 << (lut_num - 32)) ? true : false;
+ }
+
+ return is_compl;
+}
+
+static inline void epdc_clear_lut_complete_irq(int rev, u32 lut_num)
+{
+ if (rev < 20)
+ __raw_writel(1 << lut_num, EPDC_IRQ_CLEAR);
+ else if (lut_num < 32)
+ __raw_writel(1 << lut_num, EPDC_IRQ1_CLEAR);
+ else
+ __raw_writel(1 << (lut_num - 32), EPDC_IRQ2_CLEAR);
+}
+
+static inline bool epdc_is_lut_active(u32 lut_num)
+{
+ u32 val;
+ bool is_active;
+
+ if (lut_num < 32) {
+ val = __raw_readl(EPDC_STATUS_LUTS);
+ is_active = val & (1 << lut_num) ? true : false;
+ } else {
+ val = __raw_readl(EPDC_STATUS_LUTS2);
+ is_active = val & (1 << (lut_num - 32)) ? true : false;
+ }
+
+ return is_active;
+}
+
+static inline bool epdc_any_luts_active(int rev)
+{
+ bool any_active;
+
+ if (rev < 20)
+ any_active = __raw_readl(EPDC_STATUS_LUTS) ? true : false;
+ else
+ any_active = (__raw_readl(EPDC_STATUS_LUTS) |
+ __raw_readl(EPDC_STATUS_LUTS2)) ? true : false;
+
+ return any_active;
+}
+
+static inline bool epdc_any_luts_available(void)
+{
+ bool luts_available =
+ (__raw_readl(EPDC_STATUS_NEXTLUT) &
+ EPDC_STATUS_NEXTLUT_NEXT_LUT_VALID) ? true : false;
+ return luts_available;
+}
+
+static inline int epdc_get_next_lut(void)
+{
+ u32 val =
+ __raw_readl(EPDC_STATUS_NEXTLUT) &
+ EPDC_STATUS_NEXTLUT_NEXT_LUT_MASK;
+ return val;
+}
+
+static int epdc_choose_next_lut(int rev, int *next_lut)
+{
+ u64 luts_status, unprocessed_luts, used_luts;
+ /* Available LUTs are reduced to 16 in 5-bit waveform mode */
+ bool format_p5n = ((__raw_readl(EPDC_FORMAT) &
+ EPDC_FORMAT_BUF_PIXEL_FORMAT_MASK) ==
+ EPDC_FORMAT_BUF_PIXEL_FORMAT_P5N);
+
+ luts_status = __raw_readl(EPDC_STATUS_LUTS);
+ if ((rev < 20) || format_p5n)
+ luts_status &= 0xFFFF;
+ else
+ luts_status |= ((u64)__raw_readl(EPDC_STATUS_LUTS2) << 32);
+
+ if (rev < 20) {
+ unprocessed_luts = __raw_readl(EPDC_IRQ) & 0xFFFF;
+ } else {
+ unprocessed_luts = __raw_readl(EPDC_IRQ1) |
+ ((u64)__raw_readl(EPDC_IRQ2) << 32);
+ if (format_p5n)
+ unprocessed_luts &= 0xFFFF;
+ }
+
+ /*
+ * Note on unprocessed_luts: There is a race condition
+ * where a LUT completes, but has not been processed by
+ * IRQ handler workqueue, and then a new update request
+ * attempts to use that LUT. We prevent that here by
+ * ensuring that the LUT we choose doesn't have its IRQ
+ * bit set (indicating it has completed but not yet been
+ * processed).
+ */
+ used_luts = luts_status | unprocessed_luts;
+
+ /*
+ * Selecting a LUT to minimize incidence of TCE Underrun Error
+ * --------------------------------------------------------
+ * We want to find the lowest order LUT that is of greater
+ * order than all other active LUTs. If highest order LUT
+ * is active, then we want to choose the lowest order
+ * available LUT.
+ *
+ * NOTE: For EPDC version 2.0 and later, TCE Underrun error
+ * bug is fixed, so it doesn't matter which LUT is used.
+ */
+
+ if ((rev < 20) || format_p5n) {
+ *next_lut = fls64(used_luts);
+ if (*next_lut > 15)
+ *next_lut = ffz(used_luts);
+ } else {
+ if ((u32)used_luts != ~0UL)
+ *next_lut = ffz((u32)used_luts);
+ else if ((u32)(used_luts >> 32) != ~0UL)
+ *next_lut = ffz((u32)(used_luts >> 32)) + 32;
+ else
+ *next_lut = INVALID_LUT;
+ }
+
+ if (used_luts & 0x8000)
+ return 1;
+ else
+ return 0;
+}
+
+static inline bool epdc_is_working_buffer_busy(void)
+{
+ u32 val = __raw_readl(EPDC_STATUS);
+ bool is_busy = (val & EPDC_STATUS_WB_BUSY) ? true : false;
+
+ return is_busy;
+}
+
+static inline bool epdc_is_working_buffer_complete(void)
+{
+ u32 val = __raw_readl(EPDC_IRQ);
+ bool is_compl = (val & EPDC_IRQ_WB_CMPLT_IRQ) ? true : false;
+
+ return is_compl;
+}
+
+static inline bool epdc_is_lut_cancelled(void)
+{
+ u32 val = __raw_readl(EPDC_STATUS);
+ bool is_void = (val & EPDC_STATUS_UPD_VOID) ? true : false;
+
+ return is_void;
+}
+
+static inline bool epdc_is_collision(void)
+{
+ u32 val = __raw_readl(EPDC_IRQ);
+ return (val & EPDC_IRQ_LUT_COL_IRQ) ? true : false;
+}
+
+static inline u64 epdc_get_colliding_luts(int rev)
+{
+ u32 val = __raw_readl(EPDC_STATUS_COL);
+ if (rev >= 20)
+ val |= (u64)__raw_readl(EPDC_STATUS_COL2) << 32;
+ return val;
+}
+
+static void epdc_set_horizontal_timing(u32 horiz_start, u32 horiz_end,
+ u32 hsync_width, u32 hsync_line_length)
+{
+ u32 reg_val =
+ ((hsync_width << EPDC_TCE_HSCAN1_LINE_SYNC_WIDTH_OFFSET) &
+ EPDC_TCE_HSCAN1_LINE_SYNC_WIDTH_MASK)
+ | ((hsync_line_length << EPDC_TCE_HSCAN1_LINE_SYNC_OFFSET) &
+ EPDC_TCE_HSCAN1_LINE_SYNC_MASK);
+ __raw_writel(reg_val, EPDC_TCE_HSCAN1);
+
+ reg_val =
+ ((horiz_start << EPDC_TCE_HSCAN2_LINE_BEGIN_OFFSET) &
+ EPDC_TCE_HSCAN2_LINE_BEGIN_MASK)
+ | ((horiz_end << EPDC_TCE_HSCAN2_LINE_END_OFFSET) &
+ EPDC_TCE_HSCAN2_LINE_END_MASK);
+ __raw_writel(reg_val, EPDC_TCE_HSCAN2);
+}
+
+static void epdc_set_vertical_timing(u32 vert_start, u32 vert_end,
+ u32 vsync_width)
+{
+ u32 reg_val =
+ ((vert_start << EPDC_TCE_VSCAN_FRAME_BEGIN_OFFSET) &
+ EPDC_TCE_VSCAN_FRAME_BEGIN_MASK)
+ | ((vert_end << EPDC_TCE_VSCAN_FRAME_END_OFFSET) &
+ EPDC_TCE_VSCAN_FRAME_END_MASK)
+ | ((vsync_width << EPDC_TCE_VSCAN_FRAME_SYNC_OFFSET) &
+ EPDC_TCE_VSCAN_FRAME_SYNC_MASK);
+ __raw_writel(reg_val, EPDC_TCE_VSCAN);
+}
+
+static void epdc_init_settings(struct mxc_epdc_fb_data *fb_data)
+{
+ struct imx_epdc_fb_mode *epdc_mode = fb_data->cur_mode;
+ struct fb_var_screeninfo *screeninfo = &fb_data->epdc_fb_var;
+ u32 reg_val;
+ int num_ce;
+ int i;
+
+ /* Enable clocks to access EPDC regs */
+ clk_prepare_enable(fb_data->epdc_clk_axi);
+ clk_prepare_enable(fb_data->epdc_clk_pix);
+
+ /* Reset */
+ __raw_writel(EPDC_CTRL_SFTRST, EPDC_CTRL_SET);
+ while (!(__raw_readl(EPDC_CTRL) & EPDC_CTRL_CLKGATE))
+ ;
+ __raw_writel(EPDC_CTRL_SFTRST, EPDC_CTRL_CLEAR);
+
+ /* Enable clock gating (clear to enable) */
+ __raw_writel(EPDC_CTRL_CLKGATE, EPDC_CTRL_CLEAR);
+ while (__raw_readl(EPDC_CTRL) & (EPDC_CTRL_SFTRST | EPDC_CTRL_CLKGATE))
+ ;
+
+ /* EPDC_CTRL */
+ reg_val = __raw_readl(EPDC_CTRL);
+ reg_val &= ~EPDC_CTRL_UPD_DATA_SWIZZLE_MASK;
+ reg_val |= EPDC_CTRL_UPD_DATA_SWIZZLE_NO_SWAP;
+ reg_val &= ~EPDC_CTRL_LUT_DATA_SWIZZLE_MASK;
+ reg_val |= EPDC_CTRL_LUT_DATA_SWIZZLE_NO_SWAP;
+ __raw_writel(reg_val, EPDC_CTRL_SET);
+
+ /* EPDC_FORMAT - 2bit TFT and 4bit Buf pixel format */
+ reg_val = EPDC_FORMAT_TFT_PIXEL_FORMAT_2BIT
+ | EPDC_FORMAT_BUF_PIXEL_FORMAT_P4N
+ | ((0x0 << EPDC_FORMAT_DEFAULT_TFT_PIXEL_OFFSET) &
+ EPDC_FORMAT_DEFAULT_TFT_PIXEL_MASK);
+ __raw_writel(reg_val, EPDC_FORMAT);
+
+ /* EPDC_FIFOCTRL (disabled) */
+ reg_val =
+ ((100 << EPDC_FIFOCTRL_FIFO_INIT_LEVEL_OFFSET) &
+ EPDC_FIFOCTRL_FIFO_INIT_LEVEL_MASK)
+ | ((200 << EPDC_FIFOCTRL_FIFO_H_LEVEL_OFFSET) &
+ EPDC_FIFOCTRL_FIFO_H_LEVEL_MASK)
+ | ((100 << EPDC_FIFOCTRL_FIFO_L_LEVEL_OFFSET) &
+ EPDC_FIFOCTRL_FIFO_L_LEVEL_MASK);
+ __raw_writel(reg_val, EPDC_FIFOCTRL);
+
+ /* EPDC_TEMP - Use default temp to get index */
+ epdc_set_temp(mxc_epdc_fb_get_temp_index(fb_data, DEFAULT_TEMP));
+
+ /* EPDC_RES */
+ epdc_set_screen_res(epdc_mode->vmode->xres, epdc_mode->vmode->yres);
+
+ /* EPDC_AUTOWV_LUT */
+ /* Initialize all auto-wavefrom look-up values to 2 - GC16 */
+ for (i = 0; i < 8; i++)
+ __raw_writel((2 << EPDC_AUTOWV_LUT_DATA_OFFSET) |
+ (i << EPDC_AUTOWV_LUT_ADDR_OFFSET), EPDC_AUTOWV_LUT);
+
+ /*
+ * EPDC_TCE_CTRL
+ * VSCAN_HOLDOFF = 4
+ * VCOM_MODE = MANUAL
+ * VCOM_VAL = 0
+ * DDR_MODE = DISABLED
+ * LVDS_MODE_CE = DISABLED
+ * LVDS_MODE = DISABLED
+ * DUAL_SCAN = DISABLED
+ * SDDO_WIDTH = 8bit
+ * PIXELS_PER_SDCLK = 4
+ */
+ reg_val =
+ ((epdc_mode->vscan_holdoff << EPDC_TCE_CTRL_VSCAN_HOLDOFF_OFFSET) &
+ EPDC_TCE_CTRL_VSCAN_HOLDOFF_MASK)
+ | EPDC_TCE_CTRL_PIXELS_PER_SDCLK_4;
+ __raw_writel(reg_val, EPDC_TCE_CTRL);
+
+ /* EPDC_TCE_HSCAN */
+ epdc_set_horizontal_timing(screeninfo->left_margin,
+ screeninfo->right_margin,
+ screeninfo->hsync_len,
+ screeninfo->hsync_len);
+
+ /* EPDC_TCE_VSCAN */
+ epdc_set_vertical_timing(screeninfo->upper_margin,
+ screeninfo->lower_margin,
+ screeninfo->vsync_len);
+
+ /* EPDC_TCE_OE */
+ reg_val =
+ ((epdc_mode->sdoed_width << EPDC_TCE_OE_SDOED_WIDTH_OFFSET) &
+ EPDC_TCE_OE_SDOED_WIDTH_MASK)
+ | ((epdc_mode->sdoed_delay << EPDC_TCE_OE_SDOED_DLY_OFFSET) &
+ EPDC_TCE_OE_SDOED_DLY_MASK)
+ | ((epdc_mode->sdoez_width << EPDC_TCE_OE_SDOEZ_WIDTH_OFFSET) &
+ EPDC_TCE_OE_SDOEZ_WIDTH_MASK)
+ | ((epdc_mode->sdoez_delay << EPDC_TCE_OE_SDOEZ_DLY_OFFSET) &
+ EPDC_TCE_OE_SDOEZ_DLY_MASK);
+ __raw_writel(reg_val, EPDC_TCE_OE);
+
+ /* EPDC_TCE_TIMING1 */
+ __raw_writel(0x0, EPDC_TCE_TIMING1);
+
+ /* EPDC_TCE_TIMING2 */
+ reg_val =
+ ((epdc_mode->gdclk_hp_offs << EPDC_TCE_TIMING2_GDCLK_HP_OFFSET) &
+ EPDC_TCE_TIMING2_GDCLK_HP_MASK)
+ | ((epdc_mode->gdsp_offs << EPDC_TCE_TIMING2_GDSP_OFFSET_OFFSET) &
+ EPDC_TCE_TIMING2_GDSP_OFFSET_MASK);
+ __raw_writel(reg_val, EPDC_TCE_TIMING2);
+
+ /* EPDC_TCE_TIMING3 */
+ reg_val =
+ ((epdc_mode->gdoe_offs << EPDC_TCE_TIMING3_GDOE_OFFSET_OFFSET) &
+ EPDC_TCE_TIMING3_GDOE_OFFSET_MASK)
+ | ((epdc_mode->gdclk_offs << EPDC_TCE_TIMING3_GDCLK_OFFSET_OFFSET) &
+ EPDC_TCE_TIMING3_GDCLK_OFFSET_MASK);
+ __raw_writel(reg_val, EPDC_TCE_TIMING3);
+
+ /*
+ * EPDC_TCE_SDCFG
+ * SDCLK_HOLD = 1
+ * SDSHR = 1
+ * NUM_CE = 1
+ * SDDO_REFORMAT = FLIP_PIXELS
+ * SDDO_INVERT = DISABLED
+ * PIXELS_PER_CE = display horizontal resolution
+ */
+ num_ce = epdc_mode->num_ce;
+ if (num_ce == 0)
+ num_ce = 1;
+ reg_val = EPDC_TCE_SDCFG_SDCLK_HOLD | EPDC_TCE_SDCFG_SDSHR
+ | ((num_ce << EPDC_TCE_SDCFG_NUM_CE_OFFSET) &
+ EPDC_TCE_SDCFG_NUM_CE_MASK)
+ | EPDC_TCE_SDCFG_SDDO_REFORMAT_FLIP_PIXELS
+ | ((epdc_mode->vmode->xres/num_ce << EPDC_TCE_SDCFG_PIXELS_PER_CE_OFFSET) &
+ EPDC_TCE_SDCFG_PIXELS_PER_CE_MASK);
+ __raw_writel(reg_val, EPDC_TCE_SDCFG);
+
+ /*
+ * EPDC_TCE_GDCFG
+ * GDRL = 1
+ * GDOE_MODE = 0;
+ * GDSP_MODE = 0;
+ */
+ reg_val = EPDC_TCE_SDCFG_GDRL;
+ __raw_writel(reg_val, EPDC_TCE_GDCFG);
+
+ /*
+ * EPDC_TCE_POLARITY
+ * SDCE_POL = ACTIVE LOW
+ * SDLE_POL = ACTIVE HIGH
+ * SDOE_POL = ACTIVE HIGH
+ * GDOE_POL = ACTIVE HIGH
+ * GDSP_POL = ACTIVE LOW
+ */
+ reg_val = EPDC_TCE_POLARITY_SDLE_POL_ACTIVE_HIGH
+ | EPDC_TCE_POLARITY_SDOE_POL_ACTIVE_HIGH
+ | EPDC_TCE_POLARITY_GDOE_POL_ACTIVE_HIGH;
+ __raw_writel(reg_val, EPDC_TCE_POLARITY);
+
+ /* EPDC_IRQ_MASK */
+ __raw_writel(EPDC_IRQ_TCE_UNDERRUN_IRQ, EPDC_IRQ_MASK);
+
+ /*
+ * EPDC_GPIO
+ * PWRCOM = ?
+ * PWRCTRL = ?
+ * BDR = ?
+ */
+ reg_val = ((0 << EPDC_GPIO_PWRCTRL_OFFSET) & EPDC_GPIO_PWRCTRL_MASK)
+ | ((0 << EPDC_GPIO_BDR_OFFSET) & EPDC_GPIO_BDR_MASK);
+ __raw_writel(reg_val, EPDC_GPIO);
+
+ __raw_writel(fb_data->waveform_buffer_phys, EPDC_WVADDR);
+ __raw_writel(fb_data->working_buffer_phys, EPDC_WB_ADDR);
+ __raw_writel(fb_data->working_buffer_phys, EPDC_WB_ADDR_TCE);
+
+ /* Disable clock */
+ clk_disable_unprepare(fb_data->epdc_clk_axi);
+ clk_disable_unprepare(fb_data->epdc_clk_pix);
+}
+
+static void epdc_powerup(struct mxc_epdc_fb_data *fb_data)
+{
+ int ret = 0;
+ mutex_lock(&fb_data->power_mutex);
+
+ /*
+ * If power down request is pending, clear
+ * powering_down to cancel the request.
+ */
+ if (fb_data->powering_down)
+ fb_data->powering_down = false;
+
+ if (fb_data->power_state == POWER_STATE_ON) {
+ mutex_unlock(&fb_data->power_mutex);
+ return;
+ }
+
+ dev_dbg(fb_data->dev, "EPDC Powerup\n");
+
+ fb_data->updates_active = true;
+
+ /* Enable the v3p3 regulator */
+ ret = regulator_enable(fb_data->v3p3_regulator);
+ if (IS_ERR((void *)ret)) {
+ dev_err(fb_data->dev, "Unable to enable V3P3 regulator."
+ "err = 0x%x\n", ret);
+ mutex_unlock(&fb_data->power_mutex);
+ return;
+ }
+
+ msleep(1);
+
+ pm_runtime_get_sync(fb_data->dev);
+
+ /* Enable clocks to EPDC */
+ clk_prepare_enable(fb_data->epdc_clk_axi);
+ clk_prepare_enable(fb_data->epdc_clk_pix);
+
+ __raw_writel(EPDC_CTRL_CLKGATE, EPDC_CTRL_CLEAR);
+
+ /* Enable power to the EPD panel */
+ ret = regulator_enable(fb_data->display_regulator);
+ if (IS_ERR((void *)ret)) {
+ dev_err(fb_data->dev, "Unable to enable DISPLAY regulator."
+ "err = 0x%x\n", ret);
+ mutex_unlock(&fb_data->power_mutex);
+ return;
+ }
+ ret = regulator_enable(fb_data->vcom_regulator);
+ if (IS_ERR((void *)ret)) {
+ dev_err(fb_data->dev, "Unable to enable VCOM regulator."
+ "err = 0x%x\n", ret);
+ mutex_unlock(&fb_data->power_mutex);
+ return;
+ }
+
+ fb_data->power_state = POWER_STATE_ON;
+
+ mutex_unlock(&fb_data->power_mutex);
+}
+
+static void epdc_powerdown(struct mxc_epdc_fb_data *fb_data)
+{
+ mutex_lock(&fb_data->power_mutex);
+
+ /* If powering_down has been cleared, a powerup
+ * request is pre-empting this powerdown request.
+ */
+ if (!fb_data->powering_down
+ || (fb_data->power_state == POWER_STATE_OFF)) {
+ mutex_unlock(&fb_data->power_mutex);
+ return;
+ }
+
+ dev_dbg(fb_data->dev, "EPDC Powerdown\n");
+
+ /* Disable power to the EPD panel */
+ regulator_disable(fb_data->vcom_regulator);
+ regulator_disable(fb_data->display_regulator);
+
+ /* Disable clocks to EPDC */
+ __raw_writel(EPDC_CTRL_CLKGATE, EPDC_CTRL_SET);
+ clk_disable_unprepare(fb_data->epdc_clk_pix);
+ clk_disable_unprepare(fb_data->epdc_clk_axi);
+
+ pm_runtime_put_sync_suspend(fb_data->dev);
+
+ /* turn off the V3p3 */
+ regulator_disable(fb_data->v3p3_regulator);
+
+ fb_data->power_state = POWER_STATE_OFF;
+ fb_data->powering_down = false;
+
+ if (fb_data->wait_for_powerdown) {
+ fb_data->wait_for_powerdown = false;
+ complete(&fb_data->powerdown_compl);
+ }
+
+ mutex_unlock(&fb_data->power_mutex);
+}
+
+static void epdc_init_sequence(struct mxc_epdc_fb_data *fb_data)
+{
+ /* Initialize EPDC, passing pointer to EPDC registers */
+ epdc_init_settings(fb_data);
+ fb_data->in_init = true;
+ epdc_powerup(fb_data);
+ draw_mode0(fb_data);
+ /* Force power down event */
+ fb_data->powering_down = true;
+ epdc_powerdown(fb_data);
+ fb_data->updates_active = false;
+}
+
+static int mxc_epdc_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ u32 len;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ if (offset < info->fix.smem_len) {
+ /* mapping framebuffer memory */
+ len = info->fix.smem_len - offset;
+ vma->vm_pgoff = (info->fix.smem_start + offset) >> PAGE_SHIFT;
+ } else
+ return -EINVAL;
+
+ len = PAGE_ALIGN(len);
+ if (vma->vm_end - vma->vm_start > len)
+ return -EINVAL;
+
+ /* make buffers bufferable */
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
+ dev_dbg(info->device, "mmap remap_pfn_range failed\n");
+ return -ENOBUFS;
+ }
+
+ return 0;
+}
+
+static inline u_int _chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+static int mxc_epdc_fb_setcolreg(u_int regno, u_int red, u_int green,
+ u_int blue, u_int transp, struct fb_info *info)
+{
+ unsigned int val;
+ int ret = 1;
+
+ /*
+ * If greyscale is true, then we convert the RGB value
+ * to greyscale no matter what visual we are using.
+ */
+ if (info->var.grayscale)
+ red = green = blue = (19595 * red + 38470 * green +
+ 7471 * blue) >> 16;
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ /*
+ * 16-bit True Colour. We encode the RGB value
+ * according to the RGB bitfield information.
+ */
+ if (regno < 16) {
+ u32 *pal = info->pseudo_palette;
+
+ val = _chan_to_field(red, &info->var.red);
+ val |= _chan_to_field(green, &info->var.green);
+ val |= _chan_to_field(blue, &info->var.blue);
+
+ pal[regno] = val;
+ ret = 0;
+ }
+ break;
+
+ case FB_VISUAL_STATIC_PSEUDOCOLOR:
+ case FB_VISUAL_PSEUDOCOLOR:
+ break;
+ }
+
+ return ret;
+}
+
+static int mxc_epdc_fb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
+{
+ int count, index, r;
+ u16 *red, *green, *blue, *transp;
+ u16 trans = 0xffff;
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+ int i;
+
+ dev_dbg(fb_data->dev, "setcmap\n");
+
+ if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) {
+ /* Only support an 8-bit, 256 entry lookup */
+ if (cmap->len != 256)
+ return 1;
+
+ mxc_epdc_fb_flush_updates(fb_data);
+
+ mutex_lock(&fb_data->pxp_mutex);
+ /*
+ * Store colormap in pxp_conf structure for later transmit
+ * to PxP during update process to convert gray pixels.
+ *
+ * Since red=blue=green for pseudocolor visuals, we can
+ * just use red values.
+ */
+ for (i = 0; i < 256; i++)
+ fb_data->pxp_conf.proc_data.lut_map[i] = cmap->red[i] & 0xFF;
+
+ fb_data->pxp_conf.proc_data.lut_map_updated = true;
+
+ mutex_unlock(&fb_data->pxp_mutex);
+ } else {
+ red = cmap->red;
+ green = cmap->green;
+ blue = cmap->blue;
+ transp = cmap->transp;
+ index = cmap->start;
+
+ for (count = 0; count < cmap->len; count++) {
+ if (transp)
+ trans = *transp++;
+ r = mxc_epdc_fb_setcolreg(index++, *red++, *green++, *blue++,
+ trans, info);
+ if (r != 0)
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+static void adjust_coordinates(u32 xres, u32 yres, u32 rotation,
+ struct mxcfb_rect *update_region, struct mxcfb_rect *adj_update_region)
+{
+ u32 temp;
+
+ /* If adj_update_region == NULL, pass result back in update_region */
+ /* If adj_update_region == valid, use it to pass back result */
+ if (adj_update_region)
+ switch (rotation) {
+ case FB_ROTATE_UR:
+ adj_update_region->top = update_region->top;
+ adj_update_region->left = update_region->left;
+ adj_update_region->width = update_region->width;
+ adj_update_region->height = update_region->height;
+ break;
+ case FB_ROTATE_CW:
+ adj_update_region->top = update_region->left;
+ adj_update_region->left = yres -
+ (update_region->top + update_region->height);
+ adj_update_region->width = update_region->height;
+ adj_update_region->height = update_region->width;
+ break;
+ case FB_ROTATE_UD:
+ adj_update_region->width = update_region->width;
+ adj_update_region->height = update_region->height;
+ adj_update_region->top = yres -
+ (update_region->top + update_region->height);
+ adj_update_region->left = xres -
+ (update_region->left + update_region->width);
+ break;
+ case FB_ROTATE_CCW:
+ adj_update_region->left = update_region->top;
+ adj_update_region->top = xres -
+ (update_region->left + update_region->width);
+ adj_update_region->width = update_region->height;
+ adj_update_region->height = update_region->width;
+ break;
+ }
+ else
+ switch (rotation) {
+ case FB_ROTATE_UR:
+ /* No adjustment needed */
+ break;
+ case FB_ROTATE_CW:
+ temp = update_region->top;
+ update_region->top = update_region->left;
+ update_region->left = yres -
+ (temp + update_region->height);
+ temp = update_region->width;
+ update_region->width = update_region->height;
+ update_region->height = temp;
+ break;
+ case FB_ROTATE_UD:
+ update_region->top = yres -
+ (update_region->top + update_region->height);
+ update_region->left = xres -
+ (update_region->left + update_region->width);
+ break;
+ case FB_ROTATE_CCW:
+ temp = update_region->left;
+ update_region->left = update_region->top;
+ update_region->top = xres -
+ (temp + update_region->width);
+ temp = update_region->width;
+ update_region->width = update_region->height;
+ update_region->height = temp;
+ break;
+ }
+}
+
+/*
+ * Set fixed framebuffer parameters based on variable settings.
+ *
+ * @param info framebuffer information pointer
+ */
+static int mxc_epdc_fb_set_fix(struct fb_info *info)
+{
+ struct fb_fix_screeninfo *fix = &info->fix;
+ struct fb_var_screeninfo *var = &info->var;
+
+ fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->accel = FB_ACCEL_NONE;
+ if (var->grayscale)
+ fix->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+ else
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ fix->xpanstep = 1;
+ fix->ypanstep = 1;
+
+ return 0;
+}
+
+/*
+ * This routine actually sets the video mode. It's in here where we
+ * the hardware state info->par and fix which can be affected by the
+ * change in par. For this driver it doesn't do much.
+ *
+ */
+static int mxc_epdc_fb_set_par(struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+ struct pxp_config_data *pxp_conf = &fb_data->pxp_conf;
+ struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+ struct fb_var_screeninfo *screeninfo = &fb_data->info.var;
+ struct imx_epdc_fb_mode *epdc_modes = fb_data->pdata->epdc_mode;
+ int i;
+ int ret;
+ __u32 xoffset_old, yoffset_old;
+
+ /*
+ * Can't change the FB parameters until current updates have completed.
+ * This function returns when all active updates are done.
+ */
+ mxc_epdc_fb_flush_updates(fb_data);
+
+ mutex_lock(&fb_data->queue_mutex);
+ /*
+ * Set all screeninfo except for xoffset/yoffset
+ * Subsequent call to pan_display will handle those.
+ */
+ xoffset_old = fb_data->epdc_fb_var.xoffset;
+ yoffset_old = fb_data->epdc_fb_var.yoffset;
+ fb_data->epdc_fb_var = *screeninfo;
+ fb_data->epdc_fb_var.xoffset = xoffset_old;
+ fb_data->epdc_fb_var.yoffset = yoffset_old;
+ mutex_unlock(&fb_data->queue_mutex);
+
+ mutex_lock(&fb_data->pxp_mutex);
+
+ /*
+ * Update PxP config data (used to process FB regions for updates)
+ * based on FB info and processing tasks required
+ */
+
+ /* Initialize non-channel-specific PxP parameters */
+ proc_data->drect.left = proc_data->srect.left = 0;
+ proc_data->drect.top = proc_data->srect.top = 0;
+ proc_data->drect.width = proc_data->srect.width = screeninfo->xres;
+ proc_data->drect.height = proc_data->srect.height = screeninfo->yres;
+ proc_data->scaling = 0;
+ proc_data->hflip = 0;
+ proc_data->vflip = 0;
+ proc_data->rotate = screeninfo->rotate;
+ proc_data->bgcolor = 0;
+ proc_data->overlay_state = 0;
+ proc_data->lut_transform = PXP_LUT_NONE;
+
+ /*
+ * configure S0 channel parameters
+ * Parameters should match FB format/width/height
+ */
+ if (screeninfo->grayscale)
+ pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_GREY;
+ else {
+ switch (screeninfo->bits_per_pixel) {
+ case 16:
+ pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_RGB565;
+ break;
+ case 24:
+ pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_RGB24;
+ break;
+ case 32:
+ pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_XRGB32;
+ break;
+ default:
+ pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_RGB565;
+ break;
+ }
+ }
+ pxp_conf->s0_param.width = screeninfo->xres_virtual;
+ pxp_conf->s0_param.height = screeninfo->yres;
+ pxp_conf->s0_param.color_key = -1;
+ pxp_conf->s0_param.color_key_enable = false;
+
+ /*
+ * Initialize Output channel parameters
+ * Output is Y-only greyscale
+ * Output width/height will vary based on update region size
+ */
+ pxp_conf->out_param.width = screeninfo->xres;
+ pxp_conf->out_param.height = screeninfo->yres;
+ pxp_conf->out_param.pixel_fmt = PXP_PIX_FMT_GREY;
+
+ mutex_unlock(&fb_data->pxp_mutex);
+
+ /*
+ * If HW not yet initialized, check to see if we are being sent
+ * an initialization request.
+ */
+ if (!fb_data->hw_ready) {
+ struct fb_videomode mode;
+ u32 xres_temp;
+
+ fb_var_to_videomode(&mode, screeninfo);
+
+ /* When comparing requested fb mode,
+ we need to use unrotated dimensions */
+ if ((screeninfo->rotate == FB_ROTATE_CW) ||
+ (screeninfo->rotate == FB_ROTATE_CCW)) {
+ xres_temp = mode.xres;
+ mode.xres = mode.yres;
+ mode.yres = xres_temp;
+ }
+
+ /*
+ * If requested video mode does not match current video
+ * mode, search for a matching panel.
+ */
+ if (fb_data->cur_mode &&
+ !fb_mode_is_equal(fb_data->cur_mode->vmode,
+ &mode)) {
+ bool found_match = false;
+
+ /* Match videomode against epdc modes */
+ for (i = 0; i < fb_data->pdata->num_modes; i++) {
+ if (!fb_mode_is_equal(epdc_modes[i].vmode,
+ &mode))
+ continue;
+ fb_data->cur_mode = &epdc_modes[i];
+ found_match = true;
+ break;
+ }
+
+ if (!found_match) {
+ dev_err(fb_data->dev,
+ "Failed to match requested "
+ "video mode\n");
+ return EINVAL;
+ }
+ }
+
+ /* Found a match - Grab timing params */
+ screeninfo->left_margin = mode.left_margin;
+ screeninfo->right_margin = mode.right_margin;
+ screeninfo->upper_margin = mode.upper_margin;
+ screeninfo->lower_margin = mode.lower_margin;
+ screeninfo->hsync_len = mode.hsync_len;
+ screeninfo->vsync_len = mode.vsync_len;
+
+ fb_data->hw_initializing = true;
+
+ /* Initialize EPDC settings and init panel */
+ ret =
+ mxc_epdc_fb_init_hw((struct fb_info *)fb_data);
+ if (ret) {
+ dev_err(fb_data->dev,
+ "Failed to load panel waveform data\n");
+ return ret;
+ }
+ }
+
+ /*
+ * EOF sync delay (in us) should be equal to the vscan holdoff time
+ * VSCAN_HOLDOFF time = (VSCAN_HOLDOFF value + 1) * Vertical lines
+ * Add 25us for additional margin
+ */
+ fb_data->eof_sync_period = (fb_data->cur_mode->vscan_holdoff + 1) *
+ 1000000/(fb_data->cur_mode->vmode->refresh *
+ (fb_data->cur_mode->vmode->upper_margin +
+ fb_data->cur_mode->vmode->yres +
+ fb_data->cur_mode->vmode->lower_margin +
+ fb_data->cur_mode->vmode->vsync_len)) + 25;
+
+ mxc_epdc_fb_set_fix(info);
+
+ return 0;
+}
+
+static int mxc_epdc_fb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+
+ if (!var->xres)
+ var->xres = 1;
+ if (!var->yres)
+ var->yres = 1;
+
+ if (var->xres_virtual < var->xoffset + var->xres)
+ var->xres_virtual = var->xoffset + var->xres;
+ if (var->yres_virtual < var->yoffset + var->yres)
+ var->yres_virtual = var->yoffset + var->yres;
+
+ if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
+ (var->bits_per_pixel != 16) && (var->bits_per_pixel != 8))
+ var->bits_per_pixel = default_bpp;
+
+ switch (var->bits_per_pixel) {
+ case 8:
+ if (var->grayscale != 0) {
+ /*
+ * For 8-bit grayscale, R, G, and B offset are equal.
+ *
+ */
+ var->red.length = 8;
+ var->red.offset = 0;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 0;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ } else {
+ var->red.length = 3;
+ var->red.offset = 5;
+ var->red.msb_right = 0;
+
+ var->green.length = 3;
+ var->green.offset = 2;
+ var->green.msb_right = 0;
+
+ var->blue.length = 2;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ }
+ break;
+ case 16:
+ var->red.length = 5;
+ var->red.offset = 11;
+ var->red.msb_right = 0;
+
+ var->green.length = 6;
+ var->green.offset = 5;
+ var->green.msb_right = 0;
+
+ var->blue.length = 5;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 24:
+ var->red.length = 8;
+ var->red.offset = 16;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 32:
+ var->red.length = 8;
+ var->red.offset = 16;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 8;
+ var->transp.offset = 24;
+ var->transp.msb_right = 0;
+ break;
+ }
+
+ switch (var->rotate) {
+ case FB_ROTATE_UR:
+ case FB_ROTATE_UD:
+ var->xres = fb_data->native_width;
+ var->yres = fb_data->native_height;
+ break;
+ case FB_ROTATE_CW:
+ case FB_ROTATE_CCW:
+ var->xres = fb_data->native_height;
+ var->yres = fb_data->native_width;
+ break;
+ default:
+ /* Invalid rotation value */
+ var->rotate = 0;
+ dev_dbg(fb_data->dev, "Invalid rotation request\n");
+ return -EINVAL;
+ }
+
+ var->xres_virtual = ALIGN(var->xres, 32);
+ var->yres_virtual = ALIGN(var->yres, 128) * fb_data->num_screens;
+
+ var->height = -1;
+ var->width = -1;
+
+ return 0;
+}
+
+void mxc_epdc_fb_set_waveform_modes(struct mxcfb_waveform_modes *modes,
+ struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+
+ mutex_lock(&fb_data->queue_mutex);
+
+ memcpy(&fb_data->wv_modes, modes, sizeof(struct mxcfb_waveform_modes));
+
+ /* Set flag to ensure that new waveform modes
+ * are programmed into EPDC before next update */
+ fb_data->wv_modes_update = true;
+
+ mutex_unlock(&fb_data->queue_mutex);
+}
+EXPORT_SYMBOL(mxc_epdc_fb_set_waveform_modes);
+
+static int mxc_epdc_fb_get_temp_index(struct mxc_epdc_fb_data *fb_data, int temp)
+{
+ int i;
+ int index = -1;
+
+ if (fb_data->trt_entries == 0) {
+ dev_err(fb_data->dev,
+ "No TRT exists...using default temp index\n");
+ return DEFAULT_TEMP_INDEX;
+ }
+
+ /* Search temperature ranges for a match */
+ for (i = 0; i < fb_data->trt_entries - 1; i++) {
+ if ((temp >= fb_data->temp_range_bounds[i])
+ && (temp < fb_data->temp_range_bounds[i+1])) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index < 0) {
+ dev_err(fb_data->dev,
+ "No TRT index match...using default temp index\n");
+ return DEFAULT_TEMP_INDEX;
+ }
+
+ dev_dbg(fb_data->dev, "Using temperature index %d\n", index);
+
+ return index;
+}
+
+int mxc_epdc_fb_set_temperature(int temperature, struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+
+ /* Store temp index. Used later when configuring updates. */
+ mutex_lock(&fb_data->queue_mutex);
+ fb_data->temp_index = mxc_epdc_fb_get_temp_index(fb_data, temperature);
+ mutex_unlock(&fb_data->queue_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(mxc_epdc_fb_set_temperature);
+
+int mxc_epdc_fb_set_auto_update(u32 auto_mode, struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+
+ dev_dbg(fb_data->dev, "Setting auto update mode to %d\n", auto_mode);
+
+ if ((auto_mode == AUTO_UPDATE_MODE_AUTOMATIC_MODE)
+ || (auto_mode == AUTO_UPDATE_MODE_REGION_MODE))
+ fb_data->auto_mode = auto_mode;
+ else {
+ dev_err(fb_data->dev, "Invalid auto update mode parameter.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(mxc_epdc_fb_set_auto_update);
+
+int mxc_epdc_fb_set_upd_scheme(u32 upd_scheme, struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+
+ dev_dbg(fb_data->dev, "Setting optimization level to %d\n", upd_scheme);
+
+ /*
+ * Can't change the scheme until current updates have completed.
+ * This function returns when all active updates are done.
+ */
+ mxc_epdc_fb_flush_updates(fb_data);
+
+ if ((upd_scheme == UPDATE_SCHEME_SNAPSHOT)
+ || (upd_scheme == UPDATE_SCHEME_QUEUE)
+ || (upd_scheme == UPDATE_SCHEME_QUEUE_AND_MERGE))
+ fb_data->upd_scheme = upd_scheme;
+ else {
+ dev_err(fb_data->dev, "Invalid update scheme specified.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(mxc_epdc_fb_set_upd_scheme);
+
+static void copy_before_process(struct mxc_epdc_fb_data *fb_data,
+ struct update_data_list *upd_data_list)
+{
+ struct mxcfb_update_data *upd_data =
+ &upd_data_list->update_desc->upd_data;
+ int i;
+ unsigned char *temp_buf_ptr = fb_data->virt_addr_copybuf;
+ unsigned char *src_ptr;
+ struct mxcfb_rect *src_upd_region;
+ int temp_buf_stride;
+ int src_stride;
+ int bpp = fb_data->epdc_fb_var.bits_per_pixel;
+ int left_offs, right_offs;
+ int x_trailing_bytes, y_trailing_bytes;
+ int alt_buf_offset;
+
+ /* Set source buf pointer based on input source, panning, etc. */
+ if (upd_data->flags & EPDC_FLAG_USE_ALT_BUFFER) {
+ src_upd_region = &upd_data->alt_buffer_data.alt_update_region;
+ src_stride =
+ upd_data->alt_buffer_data.width * bpp/8;
+ alt_buf_offset = upd_data->alt_buffer_data.phys_addr -
+ fb_data->info.fix.smem_start;
+ src_ptr = fb_data->info.screen_base + alt_buf_offset
+ + src_upd_region->top * src_stride;
+ } else {
+ src_upd_region = &upd_data->update_region;
+ src_stride = fb_data->epdc_fb_var.xres_virtual * bpp/8;
+ src_ptr = fb_data->info.screen_base + fb_data->fb_offset
+ + src_upd_region->top * src_stride;
+ }
+
+ temp_buf_stride = ALIGN(src_upd_region->width, 8) * bpp/8;
+ left_offs = src_upd_region->left * bpp/8;
+ right_offs = src_upd_region->width * bpp/8;
+ x_trailing_bytes = (ALIGN(src_upd_region->width, 8)
+ - src_upd_region->width) * bpp/8;
+
+ for (i = 0; i < src_upd_region->height; i++) {
+ /* Copy the full line */
+ memcpy(temp_buf_ptr, src_ptr + left_offs,
+ src_upd_region->width * bpp/8);
+
+ /* Clear any unwanted pixels at the end of each line */
+ if (src_upd_region->width & 0x7) {
+ memset(temp_buf_ptr + right_offs, 0x0,
+ x_trailing_bytes);
+ }
+
+ temp_buf_ptr += temp_buf_stride;
+ src_ptr += src_stride;
+ }
+
+ /* Clear any unwanted pixels at the bottom of the end of each line */
+ if (src_upd_region->height & 0x7) {
+ y_trailing_bytes = (ALIGN(src_upd_region->height, 8)
+ - src_upd_region->height) *
+ ALIGN(src_upd_region->width, 8) * bpp/8;
+ memset(temp_buf_ptr, 0x0, y_trailing_bytes);
+ }
+}
+
+static int epdc_process_update(struct update_data_list *upd_data_list,
+ struct mxc_epdc_fb_data *fb_data)
+{
+ struct mxcfb_rect *src_upd_region; /* Region of src buffer for update */
+ struct mxcfb_rect pxp_upd_region;
+ u32 src_width, src_height;
+ u32 offset_from_4, bytes_per_pixel;
+ u32 post_rotation_xcoord, post_rotation_ycoord, width_pxp_blocks;
+ u32 pxp_input_offs, pxp_output_offs, pxp_output_shift;
+ u32 hist_stat = 0;
+ int width_unaligned, height_unaligned;
+ bool input_unaligned = false;
+ bool line_overflow = false;
+ int pix_per_line_added;
+ bool use_temp_buf = false;
+ struct mxcfb_rect temp_buf_upd_region;
+ struct update_desc_list *upd_desc_list = upd_data_list->update_desc;
+
+ int ret;
+
+ /*
+ * Gotta do a whole bunch of buffer ptr manipulation to
+ * work around HW restrictions for PxP & EPDC
+ * Note: Applies to pre-2.0 versions of EPDC/PxP
+ */
+
+ /*
+ * Are we using FB or an alternate (overlay)
+ * buffer for source of update?
+ */
+ if (upd_desc_list->upd_data.flags & EPDC_FLAG_USE_ALT_BUFFER) {
+ src_width = upd_desc_list->upd_data.alt_buffer_data.width;
+ src_height = upd_desc_list->upd_data.alt_buffer_data.height;
+ src_upd_region = &upd_desc_list->upd_data.alt_buffer_data.alt_update_region;
+ } else {
+ src_width = fb_data->epdc_fb_var.xres_virtual;
+ src_height = fb_data->epdc_fb_var.yres;
+ src_upd_region = &upd_desc_list->upd_data.update_region;
+ }
+
+ bytes_per_pixel = fb_data->epdc_fb_var.bits_per_pixel/8;
+
+ /*
+ * SW workaround for PxP limitation (for pre-v2.0 HW)
+ *
+ * There are 3 cases where we cannot process the update data
+ * directly from the input buffer:
+ *
+ * 1) PxP must process 8x8 pixel blocks, and all pixels in each block
+ * are considered for auto-waveform mode selection. If the
+ * update region is not 8x8 aligned, additional unwanted pixels
+ * will be considered in auto-waveform mode selection.
+ *
+ * 2) PxP input must be 32-bit aligned, so any update
+ * address not 32-bit aligned must be shifted to meet the
+ * 32-bit alignment. The PxP will thus end up processing pixels
+ * outside of the update region to satisfy this alignment restriction,
+ * which can affect auto-waveform mode selection.
+ *
+ * 3) If input fails 32-bit alignment, and the resulting expansion
+ * of the processed region would add at least 8 pixels more per
+ * line than the original update line width, the EPDC would
+ * cause screen artifacts by incorrectly handling the 8+ pixels
+ * at the end of each line.
+ *
+ * Workaround is to copy from source buffer into a temporary
+ * buffer, which we pad with zeros to match the 8x8 alignment
+ * requirement. This temp buffer becomes the input to the PxP.
+ */
+ width_unaligned = src_upd_region->width & 0x7;
+ height_unaligned = src_upd_region->height & 0x7;
+
+ offset_from_4 = src_upd_region->left & 0x3;
+ input_unaligned = ((offset_from_4 * bytes_per_pixel % 4) != 0) ?
+ true : false;
+
+ pix_per_line_added = (offset_from_4 * bytes_per_pixel % 4)
+ / bytes_per_pixel;
+ if ((((fb_data->epdc_fb_var.rotate == FB_ROTATE_UR) ||
+ fb_data->epdc_fb_var.rotate == FB_ROTATE_UD)) &&
+ (ALIGN(src_upd_region->width, 8) <
+ ALIGN(src_upd_region->width + pix_per_line_added, 8)))
+ line_overflow = true;
+
+ /* Grab pxp_mutex here so that we protect access
+ * to copybuf in addition to the PxP structures */
+ mutex_lock(&fb_data->pxp_mutex);
+
+ if (((((width_unaligned || height_unaligned || input_unaligned) &&
+ (upd_desc_list->upd_data.waveform_mode == WAVEFORM_MODE_AUTO))
+ || line_overflow) && (fb_data->rev < 20)) ||
+ fb_data->restrict_width) {
+ dev_dbg(fb_data->dev, "Copying update before processing.\n");
+
+ /* Update to reflect what the new source buffer will be */
+ src_width = ALIGN(src_upd_region->width, 8);
+ src_height = ALIGN(src_upd_region->height, 8);
+
+ copy_before_process(fb_data, upd_data_list);
+
+ /*
+ * src_upd_region should now describe
+ * the new update buffer attributes.
+ */
+ temp_buf_upd_region.left = 0;
+ temp_buf_upd_region.top = 0;
+ temp_buf_upd_region.width = src_upd_region->width;
+ temp_buf_upd_region.height = src_upd_region->height;
+ src_upd_region = &temp_buf_upd_region;
+
+ use_temp_buf = true;
+ }
+
+ /*
+ * For pre-2.0 HW, input address must be 32-bit aligned
+ * Compute buffer offset to account for this PxP limitation
+ */
+ offset_from_4 = src_upd_region->left & 0x3;
+ input_unaligned = ((offset_from_4 * bytes_per_pixel % 4) != 0) ?
+ true : false;
+ if ((fb_data->rev < 20) && input_unaligned) {
+ /* Leave a gap between PxP input addr and update region pixels */
+ pxp_input_offs =
+ (src_upd_region->top * src_width + src_upd_region->left)
+ * bytes_per_pixel & 0xFFFFFFFC;
+ /* Update region left changes to reflect relative position to input ptr */
+ pxp_upd_region.left = (offset_from_4 * bytes_per_pixel % 4)
+ / bytes_per_pixel;
+ } else {
+ pxp_input_offs =
+ (src_upd_region->top * src_width + src_upd_region->left)
+ * bytes_per_pixel;
+ pxp_upd_region.left = 0;
+ }
+
+ pxp_upd_region.top = 0;
+
+ /*
+ * For version 2.0 and later of EPDC & PxP, if no rotation, we don't
+ * need to align width & height (rotation always requires 8-pixel
+ * width & height alignment, per PxP limitations)
+ */
+ if ((fb_data->epdc_fb_var.rotate == 0) && (fb_data->rev >= 20)) {
+ pxp_upd_region.width = src_upd_region->width;
+ pxp_upd_region.height = src_upd_region->height;
+ } else {
+ /* Update region dimensions to meet 8x8 pixel requirement */
+ pxp_upd_region.width = ALIGN(src_upd_region->width + pxp_upd_region.left, 8);
+ pxp_upd_region.height = ALIGN(src_upd_region->height, 8);
+ }
+
+ switch (fb_data->epdc_fb_var.rotate) {
+ case FB_ROTATE_UR:
+ default:
+ post_rotation_xcoord = pxp_upd_region.left;
+ post_rotation_ycoord = pxp_upd_region.top;
+ width_pxp_blocks = pxp_upd_region.width;
+ break;
+ case FB_ROTATE_CW:
+ width_pxp_blocks = pxp_upd_region.height;
+ post_rotation_xcoord = width_pxp_blocks - src_upd_region->height;
+ post_rotation_ycoord = pxp_upd_region.left;
+ break;
+ case FB_ROTATE_UD:
+ width_pxp_blocks = pxp_upd_region.width;
+ post_rotation_xcoord = width_pxp_blocks - src_upd_region->width - pxp_upd_region.left;
+ post_rotation_ycoord = pxp_upd_region.height - src_upd_region->height - pxp_upd_region.top;
+ break;
+ case FB_ROTATE_CCW:
+ width_pxp_blocks = pxp_upd_region.height;
+ post_rotation_xcoord = pxp_upd_region.top;
+ post_rotation_ycoord = pxp_upd_region.width - src_upd_region->width - pxp_upd_region.left;
+ break;
+ }
+
+ /* Update region start coord to force PxP to process full 8x8 regions */
+ pxp_upd_region.top &= ~0x7;
+ pxp_upd_region.left &= ~0x7;
+
+ if (fb_data->rev < 20) {
+ pxp_output_shift = ALIGN(post_rotation_xcoord, 8)
+ - post_rotation_xcoord;
+
+ pxp_output_offs = post_rotation_ycoord * width_pxp_blocks
+ + pxp_output_shift;
+
+ upd_desc_list->epdc_offs = ALIGN(pxp_output_offs, 8);
+ } else {
+ pxp_output_shift = 0;
+ pxp_output_offs = post_rotation_ycoord * width_pxp_blocks
+ + post_rotation_xcoord;
+
+ upd_desc_list->epdc_offs = pxp_output_offs;
+ }
+
+ upd_desc_list->epdc_stride = width_pxp_blocks;
+
+ /* Source address either comes from alternate buffer
+ provided in update data, or from the framebuffer. */
+ if (use_temp_buf)
+ sg_dma_address(&fb_data->sg[0]) =
+ fb_data->phys_addr_copybuf;
+ else if (upd_desc_list->upd_data.flags & EPDC_FLAG_USE_ALT_BUFFER)
+ sg_dma_address(&fb_data->sg[0]) =
+ upd_desc_list->upd_data.alt_buffer_data.phys_addr
+ + pxp_input_offs;
+ else {
+ sg_dma_address(&fb_data->sg[0]) =
+ fb_data->info.fix.smem_start + fb_data->fb_offset
+ + pxp_input_offs;
+ sg_set_page(&fb_data->sg[0],
+ virt_to_page(fb_data->info.screen_base),
+ fb_data->info.fix.smem_len,
+ offset_in_page(fb_data->info.screen_base));
+ }
+
+ /* Update sg[1] to point to output of PxP proc task */
+ sg_dma_address(&fb_data->sg[1]) = upd_data_list->phys_addr
+ + pxp_output_shift;
+ sg_set_page(&fb_data->sg[1], virt_to_page(upd_data_list->virt_addr),
+ fb_data->max_pix_size,
+ offset_in_page(upd_data_list->virt_addr));
+
+ /*
+ * Set PxP LUT transform type based on update flags.
+ */
+ fb_data->pxp_conf.proc_data.lut_transform = 0;
+ if (upd_desc_list->upd_data.flags & EPDC_FLAG_ENABLE_INVERSION)
+ fb_data->pxp_conf.proc_data.lut_transform |= PXP_LUT_INVERT;
+ if (upd_desc_list->upd_data.flags & EPDC_FLAG_FORCE_MONOCHROME)
+ fb_data->pxp_conf.proc_data.lut_transform |=
+ PXP_LUT_BLACK_WHITE;
+ if (upd_desc_list->upd_data.flags & EPDC_FLAG_USE_CMAP)
+ fb_data->pxp_conf.proc_data.lut_transform |=
+ PXP_LUT_USE_CMAP;
+
+ /*
+ * Toggle inversion processing if 8-bit
+ * inverted is the current pixel format.
+ */
+ if (fb_data->epdc_fb_var.grayscale == GRAYSCALE_8BIT_INVERTED)
+ fb_data->pxp_conf.proc_data.lut_transform ^= PXP_LUT_INVERT;
+
+ /* This is a blocking call, so upon return PxP tx should be done */
+ ret = pxp_process_update(fb_data, src_width, src_height,
+ &pxp_upd_region);
+ if (ret) {
+ dev_err(fb_data->dev, "Unable to submit PxP update task.\n");
+ mutex_unlock(&fb_data->pxp_mutex);
+ return ret;
+ }
+
+ /* If needed, enable EPDC HW while ePxP is processing */
+ if ((fb_data->power_state == POWER_STATE_OFF)
+ || fb_data->powering_down) {
+ epdc_powerup(fb_data);
+ }
+
+ /* This is a blocking call, so upon return PxP tx should be done */
+ ret = pxp_complete_update(fb_data, &hist_stat);
+ if (ret) {
+ dev_err(fb_data->dev, "Unable to complete PxP update task.\n");
+ mutex_unlock(&fb_data->pxp_mutex);
+ return ret;
+ }
+
+ mutex_unlock(&fb_data->pxp_mutex);
+
+ /* Update waveform mode from PxP histogram results */
+ if ((fb_data->rev <= 20) &&
+ (upd_desc_list->upd_data.waveform_mode == WAVEFORM_MODE_AUTO)) {
+ if (hist_stat & 0x1)
+ upd_desc_list->upd_data.waveform_mode =
+ fb_data->wv_modes.mode_du;
+ else if (hist_stat & 0x2)
+ upd_desc_list->upd_data.waveform_mode =
+ fb_data->wv_modes.mode_gc4;
+ else if (hist_stat & 0x4)
+ upd_desc_list->upd_data.waveform_mode =
+ fb_data->wv_modes.mode_gc8;
+ else if (hist_stat & 0x8)
+ upd_desc_list->upd_data.waveform_mode =
+ fb_data->wv_modes.mode_gc16;
+ else
+ upd_desc_list->upd_data.waveform_mode =
+ fb_data->wv_modes.mode_gc32;
+
+ dev_dbg(fb_data->dev, "hist_stat = 0x%x, new waveform = 0x%x\n",
+ hist_stat, upd_desc_list->upd_data.waveform_mode);
+ }
+
+ return 0;
+}
+
+static int epdc_submit_merge(struct update_desc_list *upd_desc_list,
+ struct update_desc_list *update_to_merge,
+ struct mxc_epdc_fb_data *fb_data)
+{
+ struct mxcfb_update_data *a, *b;
+ struct mxcfb_rect *arect, *brect;
+ struct mxcfb_rect combine;
+ bool use_flags = false;
+
+ a = &upd_desc_list->upd_data;
+ b = &update_to_merge->upd_data;
+ arect = &upd_desc_list->upd_data.update_region;
+ brect = &update_to_merge->upd_data.update_region;
+
+ /* Do not merge a dry-run collision test update */
+ if ((a->flags & EPDC_FLAG_TEST_COLLISION) ||
+ (b->flags & EPDC_FLAG_TEST_COLLISION))
+ return MERGE_BLOCK;
+
+ /*
+ * Updates with different flags must be executed sequentially.
+ * Halt the merge process to ensure this.
+ */
+ if (a->flags != b->flags) {
+ /*
+ * Special exception: if update regions are identical,
+ * we may be able to merge them.
+ */
+ if ((arect->left != brect->left) ||
+ (arect->top != brect->top) ||
+ (arect->width != brect->width) ||
+ (arect->height != brect->height))
+ return MERGE_BLOCK;
+
+ use_flags = true;
+ }
+
+ if (a->update_mode != b->update_mode)
+ a->update_mode = UPDATE_MODE_FULL;
+
+ if (a->waveform_mode != b->waveform_mode)
+ a->waveform_mode = WAVEFORM_MODE_AUTO;
+
+ if (arect->left > (brect->left + brect->width) ||
+ brect->left > (arect->left + arect->width) ||
+ arect->top > (brect->top + brect->height) ||
+ brect->top > (arect->top + arect->height))
+ return MERGE_FAIL;
+
+ combine.left = arect->left < brect->left ? arect->left : brect->left;
+ combine.top = arect->top < brect->top ? arect->top : brect->top;
+ combine.width = (arect->left + arect->width) >
+ (brect->left + brect->width) ?
+ (arect->left + arect->width - combine.left) :
+ (brect->left + brect->width - combine.left);
+ combine.height = (arect->top + arect->height) >
+ (brect->top + brect->height) ?
+ (arect->top + arect->height - combine.top) :
+ (brect->top + brect->height - combine.top);
+
+ /* Don't merge if combined width exceeds max width */
+ if (fb_data->restrict_width) {
+ u32 max_width = EPDC_V2_MAX_UPDATE_WIDTH;
+ u32 combined_width = combine.width;
+ if (fb_data->epdc_fb_var.rotate != FB_ROTATE_UR)
+ max_width -= EPDC_V2_ROTATION_ALIGNMENT;
+ if ((fb_data->epdc_fb_var.rotate == FB_ROTATE_CW) ||
+ (fb_data->epdc_fb_var.rotate == FB_ROTATE_CCW))
+ combined_width = combine.height;
+ if (combined_width > max_width)
+ return MERGE_FAIL;
+ }
+
+ *arect = combine;
+
+ /* Use flags of the later update */
+ if (use_flags)
+ a->flags = b->flags;
+
+ /* Merge markers */
+ list_splice_tail(&update_to_merge->upd_marker_list,
+ &upd_desc_list->upd_marker_list);
+
+ /* Merged update should take on the earliest order */
+ upd_desc_list->update_order =
+ (upd_desc_list->update_order > update_to_merge->update_order) ?
+ upd_desc_list->update_order : update_to_merge->update_order;
+
+ return MERGE_OK;
+}
+
+static void epdc_submit_work_func(struct work_struct *work)
+{
+ int temp_index;
+ struct update_data_list *next_update, *temp_update;
+ struct update_desc_list *next_desc, *temp_desc;
+ struct update_marker_data *next_marker, *temp_marker;
+ struct mxc_epdc_fb_data *fb_data =
+ container_of(work, struct mxc_epdc_fb_data, epdc_submit_work);
+ struct update_data_list *upd_data_list = NULL;
+ struct mxcfb_rect adj_update_region, *upd_region;
+ bool end_merge = false;
+ bool is_transform;
+ u32 update_addr;
+ int *err_dist;
+ int ret;
+
+ /* Protect access to buffer queues and to update HW */
+ mutex_lock(&fb_data->queue_mutex);
+
+ /*
+ * Are any of our collision updates able to go now?
+ * Go through all updates in the collision list and check to see
+ * if the collision mask has been fully cleared
+ */
+ list_for_each_entry_safe(next_update, temp_update,
+ &fb_data->upd_buf_collision_list, list) {
+
+ if (next_update->collision_mask != 0)
+ continue;
+
+ dev_dbg(fb_data->dev, "A collision update is ready to go!\n");
+
+ /* Force waveform mode to auto for resubmitted collisions */
+ next_update->update_desc->upd_data.waveform_mode =
+ WAVEFORM_MODE_AUTO;
+
+ /*
+ * We have a collision cleared, so select it for resubmission.
+ * If an update is already selected, attempt to merge.
+ */
+ if (!upd_data_list) {
+ upd_data_list = next_update;
+ list_del_init(&next_update->list);
+ if (fb_data->upd_scheme == UPDATE_SCHEME_QUEUE)
+ /* If not merging, we have our update */
+ break;
+ } else {
+ switch (epdc_submit_merge(upd_data_list->update_desc,
+ next_update->update_desc,
+ fb_data)) {
+ case MERGE_OK:
+ dev_dbg(fb_data->dev,
+ "Update merged [collision]\n");
+ list_del_init(&next_update->update_desc->list);
+ kfree(next_update->update_desc);
+ next_update->update_desc = NULL;
+ list_del_init(&next_update->list);
+ /* Add to free buffer list */
+ list_add_tail(&next_update->list,
+ &fb_data->upd_buf_free_list);
+ break;
+ case MERGE_FAIL:
+ dev_dbg(fb_data->dev,
+ "Update not merged [collision]\n");
+ break;
+ case MERGE_BLOCK:
+ dev_dbg(fb_data->dev,
+ "Merge blocked [collision]\n");
+ end_merge = true;
+ break;
+ }
+
+ if (end_merge) {
+ end_merge = false;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Skip pending update list only if we found a collision
+ * update and we are not merging
+ */
+ if (!((fb_data->upd_scheme == UPDATE_SCHEME_QUEUE) &&
+ upd_data_list)) {
+ /*
+ * If we didn't find a collision update ready to go, we
+ * need to get a free buffer and match it to a pending update.
+ */
+
+ /*
+ * Can't proceed if there are no free buffers (and we don't
+ * already have a collision update selected)
+ */
+ if (!upd_data_list &&
+ list_empty(&fb_data->upd_buf_free_list)) {
+ mutex_unlock(&fb_data->queue_mutex);
+ return;
+ }
+
+ list_for_each_entry_safe(next_desc, temp_desc,
+ &fb_data->upd_pending_list, list) {
+
+ dev_dbg(fb_data->dev, "Found a pending update!\n");
+
+ if (!upd_data_list) {
+ if (list_empty(&fb_data->upd_buf_free_list))
+ break;
+ upd_data_list =
+ list_entry(fb_data->upd_buf_free_list.next,
+ struct update_data_list, list);
+ list_del_init(&upd_data_list->list);
+ upd_data_list->update_desc = next_desc;
+ list_del_init(&next_desc->list);
+ if (fb_data->upd_scheme == UPDATE_SCHEME_QUEUE)
+ /* If not merging, we have an update */
+ break;
+ } else {
+ switch (epdc_submit_merge(upd_data_list->update_desc,
+ next_desc, fb_data)) {
+ case MERGE_OK:
+ dev_dbg(fb_data->dev,
+ "Update merged [queue]\n");
+ list_del_init(&next_desc->list);
+ kfree(next_desc);
+ break;
+ case MERGE_FAIL:
+ dev_dbg(fb_data->dev,
+ "Update not merged [queue]\n");
+ break;
+ case MERGE_BLOCK:
+ dev_dbg(fb_data->dev,
+ "Merge blocked [collision]\n");
+ end_merge = true;
+ break;
+ }
+
+ if (end_merge)
+ break;
+ }
+ }
+ }
+
+ /* Is update list empty? */
+ if (!upd_data_list) {
+ mutex_unlock(&fb_data->queue_mutex);
+ return;
+ }
+
+ /*
+ * If no processing required, skip update processing
+ * No processing means:
+ * - FB unrotated
+ * - FB pixel format = 8-bit grayscale
+ * - No look-up transformations (inversion, posterization, etc.)
+ *
+ * Note: A bug with EPDC stride prevents us from skipping
+ * PxP in versions 2.0 and earlier of EPDC.
+ */
+ is_transform = upd_data_list->update_desc->upd_data.flags &
+ (EPDC_FLAG_ENABLE_INVERSION | EPDC_FLAG_USE_DITHERING_Y1 |
+ EPDC_FLAG_USE_DITHERING_Y4 | EPDC_FLAG_FORCE_MONOCHROME |
+ EPDC_FLAG_USE_CMAP) ? true : false;
+
+ if ((fb_data->epdc_fb_var.rotate == FB_ROTATE_UR) &&
+ (fb_data->epdc_fb_var.grayscale == GRAYSCALE_8BIT) &&
+ !is_transform && (fb_data->rev > 20) &&
+ !fb_data->restrict_width) {
+
+ /* If needed, enable EPDC HW while ePxP is processing */
+ if ((fb_data->power_state == POWER_STATE_OFF)
+ || fb_data->powering_down)
+ epdc_powerup(fb_data);
+
+ /*
+ * Set update buffer pointer to the start of
+ * the update region in the frame buffer.
+ */
+ upd_region = &upd_data_list->update_desc->upd_data.update_region;
+ update_addr = fb_data->info.fix.smem_start +
+ ((upd_region->top * fb_data->info.var.xres_virtual) +
+ upd_region->left) * fb_data->info.var.bits_per_pixel/8;
+ upd_data_list->update_desc->epdc_stride =
+ fb_data->info.var.xres_virtual *
+ fb_data->info.var.bits_per_pixel/8;
+ } else {
+ /* Select from PxP output buffers */
+ upd_data_list->phys_addr =
+ fb_data->phys_addr_updbuf[fb_data->upd_buffer_num];
+ upd_data_list->virt_addr =
+ fb_data->virt_addr_updbuf[fb_data->upd_buffer_num];
+ fb_data->upd_buffer_num++;
+ if (fb_data->upd_buffer_num > fb_data->max_num_buffers-1)
+ fb_data->upd_buffer_num = 0;
+
+ /* Release buffer queues */
+ mutex_unlock(&fb_data->queue_mutex);
+
+ /* Perform PXP processing - EPDC power will also be enabled */
+ if (epdc_process_update(upd_data_list, fb_data)) {
+ dev_dbg(fb_data->dev, "PXP processing error.\n");
+ /* Protect access to buffer queues and to update HW */
+ mutex_lock(&fb_data->queue_mutex);
+ list_del_init(&upd_data_list->update_desc->list);
+ kfree(upd_data_list->update_desc);
+ upd_data_list->update_desc = NULL;
+ /* Add to free buffer list */
+ list_add_tail(&upd_data_list->list,
+ &fb_data->upd_buf_free_list);
+ /* Release buffer queues */
+ mutex_unlock(&fb_data->queue_mutex);
+ return;
+ }
+
+ /* Protect access to buffer queues and to update HW */
+ mutex_lock(&fb_data->queue_mutex);
+
+ update_addr = upd_data_list->phys_addr
+ + upd_data_list->update_desc->epdc_offs;
+ }
+
+ /* Get rotation-adjusted coordinates */
+ adjust_coordinates(fb_data->epdc_fb_var.xres,
+ fb_data->epdc_fb_var.yres, fb_data->epdc_fb_var.rotate,
+ &upd_data_list->update_desc->upd_data.update_region,
+ &adj_update_region);
+
+ /*
+ * Is the working buffer idle?
+ * If the working buffer is busy, we must wait for the resource
+ * to become free. The IST will signal this event.
+ */
+ if (fb_data->cur_update != NULL) {
+ dev_dbg(fb_data->dev, "working buf busy!\n");
+
+ /* Initialize event signalling an update resource is free */
+ init_completion(&fb_data->update_res_free);
+
+ fb_data->waiting_for_wb = true;
+
+ /* Leave spinlock while waiting for WB to complete */
+ mutex_unlock(&fb_data->queue_mutex);
+ wait_for_completion(&fb_data->update_res_free);
+ mutex_lock(&fb_data->queue_mutex);
+ }
+
+ /*
+ * Dithering Processing (Version 1.0 - for i.MX508 and i.MX6SL)
+ */
+ if (upd_data_list->update_desc->upd_data.flags &
+ EPDC_FLAG_USE_DITHERING_Y1) {
+
+ err_dist = kzalloc((fb_data->info.var.xres_virtual + 3) * 3
+ * sizeof(int), GFP_KERNEL);
+
+ /* Dithering Y8 -> Y1 */
+ do_dithering_processing_Y1_v1_0(
+ (uint8_t *)(upd_data_list->virt_addr +
+ upd_data_list->update_desc->epdc_offs),
+ upd_data_list->phys_addr +
+ upd_data_list->update_desc->epdc_offs,
+ &adj_update_region,
+ (fb_data->rev < 20) ?
+ ALIGN(adj_update_region.width, 8) :
+ adj_update_region.width,
+ err_dist);
+
+ kfree(err_dist);
+ } else if (upd_data_list->update_desc->upd_data.flags &
+ EPDC_FLAG_USE_DITHERING_Y4) {
+
+ err_dist = kzalloc((fb_data->info.var.xres_virtual + 3) * 3
+ * sizeof(int), GFP_KERNEL);
+
+ /* Dithering Y8 -> Y1 */
+ do_dithering_processing_Y4_v1_0(
+ (uint8_t *)(upd_data_list->virt_addr +
+ upd_data_list->update_desc->epdc_offs),
+ upd_data_list->phys_addr +
+ upd_data_list->update_desc->epdc_offs,
+ &adj_update_region,
+ (fb_data->rev < 20) ?
+ ALIGN(adj_update_region.width, 8) :
+ adj_update_region.width,
+ err_dist);
+
+ kfree(err_dist);
+ }
+
+ /*
+ * If there are no LUTs available,
+ * then we must wait for the resource to become free.
+ * The IST will signal this event.
+ */
+ if (!epdc_any_luts_available()) {
+ dev_dbg(fb_data->dev, "no luts available!\n");
+
+ /* Initialize event signalling an update resource is free */
+ init_completion(&fb_data->update_res_free);
+
+ fb_data->waiting_for_lut = true;
+
+ /* Leave spinlock while waiting for LUT to free up */
+ mutex_unlock(&fb_data->queue_mutex);
+ wait_for_completion(&fb_data->update_res_free);
+ mutex_lock(&fb_data->queue_mutex);
+ }
+
+ ret = epdc_choose_next_lut(fb_data->rev, &upd_data_list->lut_num);
+ /*
+ * If LUT15 is in use (for pre-EPDC v2.0 hardware):
+ * - Wait for LUT15 to complete is if TCE underrun prevent is enabled
+ * - If we go ahead with update, sync update submission with EOF
+ */
+ if (ret && fb_data->tce_prevent && (fb_data->rev < 20)) {
+ dev_dbg(fb_data->dev, "Waiting for LUT15\n");
+
+ /* Initialize event signalling that lut15 is free */
+ init_completion(&fb_data->lut15_free);
+
+ fb_data->waiting_for_lut15 = true;
+
+ /* Leave spinlock while waiting for LUT to free up */
+ mutex_unlock(&fb_data->queue_mutex);
+ wait_for_completion(&fb_data->lut15_free);
+ mutex_lock(&fb_data->queue_mutex);
+
+ epdc_choose_next_lut(fb_data->rev, &upd_data_list->lut_num);
+ } else if (ret && (fb_data->rev < 20)) {
+ /* Synchronize update submission time to reduce
+ chances of TCE underrun */
+ init_completion(&fb_data->eof_event);
+
+ epdc_eof_intr(true);
+
+ /* Leave spinlock while waiting for EOF event */
+ mutex_unlock(&fb_data->queue_mutex);
+ ret = wait_for_completion_timeout(&fb_data->eof_event,
+ msecs_to_jiffies(1000));
+ if (!ret) {
+ dev_err(fb_data->dev, "Missed EOF event!\n");
+ epdc_eof_intr(false);
+ }
+ udelay(fb_data->eof_sync_period);
+ mutex_lock(&fb_data->queue_mutex);
+
+ }
+
+ /* LUTs are available, so we get one here */
+ fb_data->cur_update = upd_data_list;
+
+ /* Reset mask for LUTS that have completed during WB processing */
+ fb_data->luts_complete_wb = 0;
+
+ /* If we are just testing for collision, we don't assign a LUT,
+ * so we don't need to update LUT-related resources. */
+ if (!(upd_data_list->update_desc->upd_data.flags
+ & EPDC_FLAG_TEST_COLLISION)) {
+ /* Associate LUT with update marker */
+ list_for_each_entry_safe(next_marker, temp_marker,
+ &upd_data_list->update_desc->upd_marker_list, upd_list)
+ next_marker->lut_num = fb_data->cur_update->lut_num;
+
+ /* Mark LUT with order */
+ fb_data->lut_update_order[upd_data_list->lut_num] =
+ upd_data_list->update_desc->update_order;
+
+ epdc_lut_complete_intr(fb_data->rev, upd_data_list->lut_num,
+ true);
+ }
+
+ /* Enable Collision and WB complete IRQs */
+ epdc_working_buf_intr(true);
+
+ /* Program EPDC update to process buffer */
+ if (upd_data_list->update_desc->upd_data.temp != TEMP_USE_AMBIENT) {
+ temp_index = mxc_epdc_fb_get_temp_index(fb_data,
+ upd_data_list->update_desc->upd_data.temp);
+ epdc_set_temp(temp_index);
+ } else
+ epdc_set_temp(fb_data->temp_index);
+ epdc_set_update_addr(update_addr);
+ epdc_set_update_coord(adj_update_region.left, adj_update_region.top);
+ epdc_set_update_dimensions(adj_update_region.width,
+ adj_update_region.height);
+ if (fb_data->rev > 20)
+ epdc_set_update_stride(upd_data_list->update_desc->epdc_stride);
+ if (fb_data->wv_modes_update &&
+ (upd_data_list->update_desc->upd_data.waveform_mode
+ == WAVEFORM_MODE_AUTO)) {
+ epdc_set_update_waveform(&fb_data->wv_modes);
+ fb_data->wv_modes_update = false;
+ }
+
+ epdc_submit_update(upd_data_list->lut_num,
+ upd_data_list->update_desc->upd_data.waveform_mode,
+ upd_data_list->update_desc->upd_data.update_mode,
+ (upd_data_list->update_desc->upd_data.flags
+ & EPDC_FLAG_TEST_COLLISION) ? true : false,
+ false, 0);
+
+ /* Release buffer queues */
+ mutex_unlock(&fb_data->queue_mutex);
+}
+
+static int mxc_epdc_fb_send_single_update(struct mxcfb_update_data *upd_data,
+ struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+ struct update_data_list *upd_data_list = NULL;
+ struct mxcfb_rect *screen_upd_region; /* Region on screen to update */
+ int temp_index;
+ int ret;
+ struct update_desc_list *upd_desc;
+ struct update_marker_data *marker_data, *next_marker, *temp_marker;
+
+ /* Has EPDC HW been initialized? */
+ if (!fb_data->hw_ready) {
+ /* Throw message if we are not mid-initialization */
+ if (!fb_data->hw_initializing)
+ dev_err(fb_data->dev, "Display HW not properly"
+ "initialized. Aborting update.\n");
+ return -EPERM;
+ }
+
+ /* Check validity of update params */
+ if ((upd_data->update_mode != UPDATE_MODE_PARTIAL) &&
+ (upd_data->update_mode != UPDATE_MODE_FULL)) {
+ dev_err(fb_data->dev,
+ "Update mode 0x%x is invalid. Aborting update.\n",
+ upd_data->update_mode);
+ return -EINVAL;
+ }
+ if ((upd_data->waveform_mode > 255) &&
+ (upd_data->waveform_mode != WAVEFORM_MODE_AUTO)) {
+ dev_err(fb_data->dev,
+ "Update waveform mode 0x%x is invalid."
+ " Aborting update.\n",
+ upd_data->waveform_mode);
+ return -EINVAL;
+ }
+
+ mutex_lock(&fb_data->queue_mutex);
+ if ((upd_data->update_region.left + upd_data->update_region.width > fb_data->epdc_fb_var.xres) ||
+ (upd_data->update_region.top + upd_data->update_region.height > fb_data->epdc_fb_var.yres)) {
+ mutex_unlock(&fb_data->queue_mutex);
+ dev_err(fb_data->dev,
+ "Update region is outside bounds of framebuffer."
+ "Aborting update.\n");
+ return -EINVAL;
+ }
+ mutex_unlock(&fb_data->queue_mutex);
+
+ if (upd_data->flags & EPDC_FLAG_USE_ALT_BUFFER) {
+ if ((upd_data->update_region.width !=
+ upd_data->alt_buffer_data.alt_update_region.width) ||
+ (upd_data->update_region.height !=
+ upd_data->alt_buffer_data.alt_update_region.height)) {
+ dev_err(fb_data->dev,
+ "Alternate update region dimensions must "
+ "match screen update region dimensions.\n");
+ return -EINVAL;
+ }
+ /* Validate physical address parameter */
+ if ((upd_data->alt_buffer_data.phys_addr <
+ fb_data->info.fix.smem_start) ||
+ (upd_data->alt_buffer_data.phys_addr >
+ fb_data->info.fix.smem_start + fb_data->map_size)) {
+ dev_err(fb_data->dev,
+ "Invalid physical address for alternate "
+ "buffer. Aborting update...\n");
+ return -EINVAL;
+ }
+ }
+
+ mutex_lock(&fb_data->queue_mutex);
+
+ /*
+ * If we are waiting to go into suspend, or the FB is blanked,
+ * we do not accept new updates
+ */
+ if ((fb_data->waiting_for_idle) ||
+ (fb_data->blank != FB_BLANK_UNBLANK)) {
+ dev_dbg(fb_data->dev, "EPDC not active."
+ "Update request abort.\n");
+ mutex_unlock(&fb_data->queue_mutex);
+ return -EPERM;
+ }
+
+ if (fb_data->upd_scheme == UPDATE_SCHEME_SNAPSHOT) {
+ int count = 0;
+ struct update_data_list *plist;
+
+ /*
+ * If next update is a FULL mode update, then we must
+ * ensure that all pending & active updates are complete
+ * before submitting the update. Otherwise, the FULL
+ * mode update may cause an endless collision loop with
+ * other updates. Block here until updates are flushed.
+ */
+ if (upd_data->update_mode == UPDATE_MODE_FULL) {
+ mutex_unlock(&fb_data->queue_mutex);
+ mxc_epdc_fb_flush_updates(fb_data);
+ mutex_lock(&fb_data->queue_mutex);
+ }
+
+ /* Count buffers in free buffer list */
+ list_for_each_entry(plist, &fb_data->upd_buf_free_list, list)
+ count++;
+
+ /* Use count to determine if we have enough
+ * free buffers to handle this update request */
+ if (count + fb_data->max_num_buffers
+ <= fb_data->max_num_updates) {
+ dev_err(fb_data->dev,
+ "No free intermediate buffers available.\n");
+ mutex_unlock(&fb_data->queue_mutex);
+ return -ENOMEM;
+ }
+
+ /* Grab first available buffer and delete from the free list */
+ upd_data_list =
+ list_entry(fb_data->upd_buf_free_list.next,
+ struct update_data_list, list);
+
+ list_del_init(&upd_data_list->list);
+ }
+
+ /*
+ * Create new update data structure, fill it with new update
+ * data and add it to the list of pending updates
+ */
+ upd_desc = kzalloc(sizeof(struct update_desc_list), GFP_KERNEL);
+ if (!upd_desc) {
+ dev_err(fb_data->dev,
+ "Insufficient system memory for update! Aborting.\n");
+ if (fb_data->upd_scheme == UPDATE_SCHEME_SNAPSHOT) {
+ list_add(&upd_data_list->list,
+ &fb_data->upd_buf_free_list);
+ }
+ mutex_unlock(&fb_data->queue_mutex);
+ return -EPERM;
+ }
+ /* Initialize per-update marker list */
+ INIT_LIST_HEAD(&upd_desc->upd_marker_list);
+ upd_desc->upd_data = *upd_data;
+ upd_desc->update_order = fb_data->order_cnt++;
+ list_add_tail(&upd_desc->list, &fb_data->upd_pending_list);
+
+ /* If marker specified, associate it with a completion */
+ if (upd_data->update_marker != 0) {
+ /* Allocate new update marker and set it up */
+ marker_data = kzalloc(sizeof(struct update_marker_data),
+ GFP_KERNEL);
+ if (!marker_data) {
+ dev_err(fb_data->dev, "No memory for marker!\n");
+ mutex_unlock(&fb_data->queue_mutex);
+ return -ENOMEM;
+ }
+ list_add_tail(&marker_data->upd_list,
+ &upd_desc->upd_marker_list);
+ marker_data->update_marker = upd_data->update_marker;
+ if (upd_desc->upd_data.flags & EPDC_FLAG_TEST_COLLISION)
+ marker_data->lut_num = DRY_RUN_NO_LUT;
+ else
+ marker_data->lut_num = INVALID_LUT;
+ init_completion(&marker_data->update_completion);
+ /* Add marker to master marker list */
+ list_add_tail(&marker_data->full_list,
+ &fb_data->full_marker_list);
+ }
+
+ if (fb_data->upd_scheme != UPDATE_SCHEME_SNAPSHOT) {
+ /* Queued update scheme processing */
+
+ mutex_unlock(&fb_data->queue_mutex);
+
+ /* Signal workqueue to handle new update */
+ queue_work(fb_data->epdc_submit_workqueue,
+ &fb_data->epdc_submit_work);
+
+ return 0;
+ }
+
+ /* Snapshot update scheme processing */
+
+ /* Set descriptor for current update, delete from pending list */
+ upd_data_list->update_desc = upd_desc;
+ list_del_init(&upd_desc->list);
+
+ mutex_unlock(&fb_data->queue_mutex);
+
+ /*
+ * Hold on to original screen update region, which we
+ * will ultimately use when telling EPDC where to update on panel
+ */
+ screen_upd_region = &upd_desc->upd_data.update_region;
+
+ /* Select from PxP output buffers */
+ upd_data_list->phys_addr =
+ fb_data->phys_addr_updbuf[fb_data->upd_buffer_num];
+ upd_data_list->virt_addr =
+ fb_data->virt_addr_updbuf[fb_data->upd_buffer_num];
+ fb_data->upd_buffer_num++;
+ if (fb_data->upd_buffer_num > fb_data->max_num_buffers-1)
+ fb_data->upd_buffer_num = 0;
+
+ ret = epdc_process_update(upd_data_list, fb_data);
+ if (ret) {
+ mutex_unlock(&fb_data->pxp_mutex);
+ return ret;
+ }
+
+ /* Pass selected waveform mode back to user */
+ upd_data->waveform_mode = upd_desc->upd_data.waveform_mode;
+
+ /* Get rotation-adjusted coordinates */
+ adjust_coordinates(fb_data->epdc_fb_var.xres,
+ fb_data->epdc_fb_var.yres, fb_data->epdc_fb_var.rotate,
+ &upd_desc->upd_data.update_region, NULL);
+
+ /* Grab lock for queue manipulation and update submission */
+ mutex_lock(&fb_data->queue_mutex);
+
+ /*
+ * Is the working buffer idle?
+ * If either the working buffer is busy, or there are no LUTs available,
+ * then we return and let the ISR handle the update later
+ */
+ if ((fb_data->cur_update != NULL) || !epdc_any_luts_available()) {
+ /* Add processed Y buffer to update list */
+ list_add_tail(&upd_data_list->list, &fb_data->upd_buf_queue);
+
+ /* Return and allow the update to be submitted by the ISR. */
+ mutex_unlock(&fb_data->queue_mutex);
+ return 0;
+ }
+
+ /* LUTs are available, so we get one here */
+ ret = epdc_choose_next_lut(fb_data->rev, &upd_data_list->lut_num);
+ if (ret && fb_data->tce_prevent && (fb_data->rev < 20)) {
+ dev_dbg(fb_data->dev, "Must wait for LUT15\n");
+ /* Add processed Y buffer to update list */
+ list_add_tail(&upd_data_list->list, &fb_data->upd_buf_queue);
+
+ /* Return and allow the update to be submitted by the ISR. */
+ mutex_unlock(&fb_data->queue_mutex);
+ return 0;
+ }
+
+ if (!(upd_data_list->update_desc->upd_data.flags
+ & EPDC_FLAG_TEST_COLLISION)) {
+
+ /* Save current update */
+ fb_data->cur_update = upd_data_list;
+
+ /* Reset mask for LUTS that have completed during WB processing */
+ fb_data->luts_complete_wb = 0;
+
+ /* Associate LUT with update marker */
+ list_for_each_entry_safe(next_marker, temp_marker,
+ &upd_data_list->update_desc->upd_marker_list, upd_list)
+ next_marker->lut_num = upd_data_list->lut_num;
+
+ /* Mark LUT as containing new update */
+ fb_data->lut_update_order[upd_data_list->lut_num] =
+ upd_desc->update_order;
+
+ epdc_lut_complete_intr(fb_data->rev, upd_data_list->lut_num,
+ true);
+ }
+
+ /* Clear status and Enable LUT complete and WB complete IRQs */
+ epdc_working_buf_intr(true);
+
+ /* Program EPDC update to process buffer */
+ epdc_set_update_addr(upd_data_list->phys_addr + upd_desc->epdc_offs);
+ epdc_set_update_coord(screen_upd_region->left, screen_upd_region->top);
+ epdc_set_update_dimensions(screen_upd_region->width,
+ screen_upd_region->height);
+ if (fb_data->rev > 20)
+ epdc_set_update_stride(upd_desc->epdc_stride);
+ if (upd_desc->upd_data.temp != TEMP_USE_AMBIENT) {
+ temp_index = mxc_epdc_fb_get_temp_index(fb_data,
+ upd_desc->upd_data.temp);
+ epdc_set_temp(temp_index);
+ } else
+ epdc_set_temp(fb_data->temp_index);
+ if (fb_data->wv_modes_update &&
+ (upd_desc->upd_data.waveform_mode == WAVEFORM_MODE_AUTO)) {
+ epdc_set_update_waveform(&fb_data->wv_modes);
+ fb_data->wv_modes_update = false;
+ }
+
+ epdc_submit_update(upd_data_list->lut_num,
+ upd_desc->upd_data.waveform_mode,
+ upd_desc->upd_data.update_mode,
+ (upd_desc->upd_data.flags
+ & EPDC_FLAG_TEST_COLLISION) ? true : false,
+ false, 0);
+
+ mutex_unlock(&fb_data->queue_mutex);
+ return 0;
+}
+
+int mxc_epdc_fb_send_update(struct mxcfb_update_data *upd_data,
+ struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+
+ if (!fb_data->restrict_width) {
+ /* No width restriction, send entire update region */
+ return mxc_epdc_fb_send_single_update(upd_data, info);
+ } else {
+ int ret;
+ __u32 width, left;
+ __u32 marker;
+ __u32 *region_width, *region_left;
+ u32 max_upd_width = EPDC_V2_MAX_UPDATE_WIDTH;
+
+ /* Further restrict max width due to pxp rotation
+ * alignment requirement
+ */
+ if (fb_data->epdc_fb_var.rotate != FB_ROTATE_UR)
+ max_upd_width -= EPDC_V2_ROTATION_ALIGNMENT;
+
+ /* Select split of width or height based on rotation */
+ if ((fb_data->epdc_fb_var.rotate == FB_ROTATE_UR) ||
+ (fb_data->epdc_fb_var.rotate == FB_ROTATE_UD)) {
+ region_width = &upd_data->update_region.width;
+ region_left = &upd_data->update_region.left;
+ } else {
+ region_width = &upd_data->update_region.height;
+ region_left = &upd_data->update_region.top;
+ }
+
+ if (*region_width <= max_upd_width)
+ return mxc_epdc_fb_send_single_update(upd_data, info);
+
+ width = *region_width;
+ left = *region_left;
+ marker = upd_data->update_marker;
+ upd_data->update_marker = 0;
+
+ do {
+ *region_width = max_upd_width;
+ *region_left = left;
+ ret = mxc_epdc_fb_send_single_update(upd_data, info);
+ if (ret)
+ return ret;
+ width -= max_upd_width;
+ left += max_upd_width;
+ } while (width > max_upd_width);
+
+ *region_width = width;
+ *region_left = left;
+ upd_data->update_marker = marker;
+ return mxc_epdc_fb_send_single_update(upd_data, info);
+ }
+}
+EXPORT_SYMBOL(mxc_epdc_fb_send_update);
+
+int mxc_epdc_fb_wait_update_complete(struct mxcfb_update_marker_data *marker_data,
+ struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+ struct update_marker_data *next_marker;
+ struct update_marker_data *temp;
+ bool marker_found = false;
+ int ret = 0;
+
+ /* 0 is an invalid update_marker value */
+ if (marker_data->update_marker == 0)
+ return -EINVAL;
+
+ /*
+ * Find completion associated with update_marker requested.
+ * Note: If update completed already, marker will have been
+ * cleared, it won't be found, and function will just return.
+ */
+
+ /* Grab queue lock to protect access to marker list */
+ mutex_lock(&fb_data->queue_mutex);
+
+ list_for_each_entry_safe(next_marker, temp,
+ &fb_data->full_marker_list, full_list) {
+ if (next_marker->update_marker == marker_data->update_marker) {
+ dev_dbg(fb_data->dev, "Waiting for marker %d\n",
+ marker_data->update_marker);
+ next_marker->waiting = true;
+ marker_found = true;
+ break;
+ }
+ }
+
+ mutex_unlock(&fb_data->queue_mutex);
+
+ /*
+ * If marker not found, it has either been signalled already
+ * or the update request failed. In either case, just return.
+ */
+ if (!marker_found)
+ return ret;
+
+ ret = wait_for_completion_timeout(&next_marker->update_completion,
+ msecs_to_jiffies(5000));
+ if (!ret) {
+ dev_err(fb_data->dev,
+ "Timed out waiting for update completion\n");
+ return -ETIMEDOUT;
+ }
+
+ marker_data->collision_test = next_marker->collision_test;
+
+ /* Free update marker object */
+ kfree(next_marker);
+
+ return ret;
+}
+EXPORT_SYMBOL(mxc_epdc_fb_wait_update_complete);
+
+int mxc_epdc_fb_set_pwrdown_delay(u32 pwrdown_delay,
+ struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+
+ fb_data->pwrdown_delay = pwrdown_delay;
+
+ return 0;
+}
+EXPORT_SYMBOL(mxc_epdc_fb_set_pwrdown_delay);
+
+int mxc_epdc_get_pwrdown_delay(struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+
+ return fb_data->pwrdown_delay;
+}
+EXPORT_SYMBOL(mxc_epdc_get_pwrdown_delay);
+
+static int mxc_epdc_fb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int ret = -EINVAL;
+
+ switch (cmd) {
+ case MXCFB_SET_WAVEFORM_MODES:
+ {
+ struct mxcfb_waveform_modes modes;
+ if (!copy_from_user(&modes, argp, sizeof(modes))) {
+ mxc_epdc_fb_set_waveform_modes(&modes, info);
+ ret = 0;
+ }
+ break;
+ }
+ case MXCFB_SET_TEMPERATURE:
+ {
+ int temperature;
+ if (!get_user(temperature, (int32_t __user *) arg))
+ ret = mxc_epdc_fb_set_temperature(temperature,
+ info);
+ break;
+ }
+ case MXCFB_SET_AUTO_UPDATE_MODE:
+ {
+ u32 auto_mode = 0;
+ if (!get_user(auto_mode, (__u32 __user *) arg))
+ ret = mxc_epdc_fb_set_auto_update(auto_mode,
+ info);
+ break;
+ }
+ case MXCFB_SET_UPDATE_SCHEME:
+ {
+ u32 upd_scheme = 0;
+ if (!get_user(upd_scheme, (__u32 __user *) arg))
+ ret = mxc_epdc_fb_set_upd_scheme(upd_scheme,
+ info);
+ break;
+ }
+ case MXCFB_SEND_UPDATE:
+ {
+ struct mxcfb_update_data upd_data;
+
+ if (mutex_lock_interruptible(&hard_lock) < 0)
+ return -ERESTARTSYS;
+
+ if (!copy_from_user(&upd_data, argp,
+ sizeof(upd_data))) {
+ ret = mxc_epdc_fb_send_update(&upd_data, info);
+ if (ret == 0 && copy_to_user(argp, &upd_data,
+ sizeof(upd_data)))
+ ret = -EFAULT;
+ } else {
+ ret = -EFAULT;
+ }
+
+ mutex_unlock(&hard_lock);
+
+ break;
+ }
+ case MXCFB_WAIT_FOR_UPDATE_COMPLETE:
+ {
+ struct mxcfb_update_marker_data upd_marker_data;
+ if (!copy_from_user(&upd_marker_data, argp,
+ sizeof(upd_marker_data))) {
+ ret = mxc_epdc_fb_wait_update_complete(
+ &upd_marker_data, info);
+ if (copy_to_user(argp, &upd_marker_data,
+ sizeof(upd_marker_data)))
+ ret = -EFAULT;
+ } else {
+ ret = -EFAULT;
+ }
+
+ break;
+ }
+
+ case MXCFB_SET_PWRDOWN_DELAY:
+ {
+ int delay = 0;
+ if (!get_user(delay, (__u32 __user *) arg))
+ ret =
+ mxc_epdc_fb_set_pwrdown_delay(delay, info);
+ break;
+ }
+
+ case MXCFB_GET_PWRDOWN_DELAY:
+ {
+ int pwrdown_delay = mxc_epdc_get_pwrdown_delay(info);
+ if (put_user(pwrdown_delay,
+ (int __user *)argp))
+ ret = -EFAULT;
+ ret = 0;
+ break;
+ }
+
+ case MXCFB_GET_WORK_BUFFER:
+ {
+ /* copy the epdc working buffer to the user space */
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+ flush_cache_all();
+ outer_flush_range(fb_data->working_buffer_phys,
+ fb_data->working_buffer_phys +
+ fb_data->working_buffer_size);
+ if (copy_to_user((void __user *)arg,
+ (const void *) fb_data->working_buffer_virt,
+ fb_data->working_buffer_size))
+ ret = -EFAULT;
+ else
+ ret = 0;
+ flush_cache_all();
+ outer_flush_range(fb_data->working_buffer_phys,
+ fb_data->working_buffer_phys +
+ fb_data->working_buffer_size);
+ break;
+ }
+
+ case MXCFB_DISABLE_EPDC_ACCESS:
+ {
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+ mxc_epdc_fb_flush_updates(fb_data);
+ /* disable handling any user update request */
+ mutex_lock(&hard_lock);
+ ret = 0;
+ break;
+ }
+
+ case MXCFB_ENABLE_EPDC_ACCESS:
+ {
+ /* enable user update handling again */
+ mutex_unlock(&hard_lock);
+ ret = 0;
+ break;
+ }
+
+ default:
+ break;
+ }
+ return ret;
+}
+
+static void mxc_epdc_fb_update_pages(struct mxc_epdc_fb_data *fb_data,
+ u16 y1, u16 y2)
+{
+ struct mxcfb_update_data update;
+
+ /* Do partial screen update, Update full horizontal lines */
+ update.update_region.left = 0;
+ update.update_region.width = fb_data->epdc_fb_var.xres;
+ update.update_region.top = y1;
+ update.update_region.height = y2 - y1;
+ update.waveform_mode = WAVEFORM_MODE_AUTO;
+ update.update_mode = UPDATE_MODE_FULL;
+ update.update_marker = 0;
+ update.temp = TEMP_USE_AMBIENT;
+ update.flags = 0;
+
+ mxc_epdc_fb_send_update(&update, &fb_data->info);
+}
+
+/* this is called back from the deferred io workqueue */
+static void mxc_epdc_fb_deferred_io(struct fb_info *info,
+ struct list_head *pagelist)
+{
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+ struct page *page;
+ unsigned long beg, end;
+ int y1, y2, miny, maxy;
+
+ if (fb_data->auto_mode != AUTO_UPDATE_MODE_AUTOMATIC_MODE)
+ return;
+
+ miny = INT_MAX;
+ maxy = 0;
+ list_for_each_entry(page, pagelist, lru) {
+ beg = page->index << PAGE_SHIFT;
+ end = beg + PAGE_SIZE - 1;
+ y1 = beg / info->fix.line_length;
+ y2 = end / info->fix.line_length;
+ if (y2 >= fb_data->epdc_fb_var.yres)
+ y2 = fb_data->epdc_fb_var.yres - 1;
+ if (miny > y1)
+ miny = y1;
+ if (maxy < y2)
+ maxy = y2;
+ }
+
+ mxc_epdc_fb_update_pages(fb_data, miny, maxy);
+}
+
+void mxc_epdc_fb_flush_updates(struct mxc_epdc_fb_data *fb_data)
+{
+ int ret;
+
+ if (fb_data->in_init)
+ return;
+
+ /* Grab queue lock to prevent any new updates from being submitted */
+ mutex_lock(&fb_data->queue_mutex);
+
+ /*
+ * 3 places to check for updates that are active or pending:
+ * 1) Updates in the pending list
+ * 2) Update buffers in use (e.g., PxP processing)
+ * 3) Active updates to panel - We can key off of EPDC
+ * power state to know if we have active updates.
+ */
+ if (!list_empty(&fb_data->upd_pending_list) ||
+ !is_free_list_full(fb_data) ||
+ (fb_data->updates_active == true)) {
+ /* Initialize event signalling updates are done */
+ init_completion(&fb_data->updates_done);
+ fb_data->waiting_for_idle = true;
+
+ mutex_unlock(&fb_data->queue_mutex);
+ /* Wait for any currently active updates to complete */
+ ret = wait_for_completion_timeout(&fb_data->updates_done,
+ msecs_to_jiffies(8000));
+ if (!ret)
+ dev_err(fb_data->dev,
+ "Flush updates timeout! ret = 0x%x\n", ret);
+
+ mutex_lock(&fb_data->queue_mutex);
+ fb_data->waiting_for_idle = false;
+ }
+
+ mutex_unlock(&fb_data->queue_mutex);
+}
+
+static int mxc_epdc_fb_blank(int blank, struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+ int ret;
+
+ dev_dbg(fb_data->dev, "blank = %d\n", blank);
+
+ if (fb_data->blank == blank)
+ return 0;
+
+ fb_data->blank = blank;
+
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ mxc_epdc_fb_flush_updates(fb_data);
+ /* Wait for powerdown */
+ mutex_lock(&fb_data->power_mutex);
+ if ((fb_data->power_state == POWER_STATE_ON) &&
+ (fb_data->pwrdown_delay == FB_POWERDOWN_DISABLE)) {
+
+ /* Powerdown disabled, so we disable EPDC manually */
+ int count = 0;
+ int sleep_ms = 10;
+
+ mutex_unlock(&fb_data->power_mutex);
+
+ /* If any active updates, wait for them to complete */
+ while (fb_data->updates_active) {
+ /* Timeout after 1 sec */
+ if ((count * sleep_ms) > 1000)
+ break;
+ msleep(sleep_ms);
+ count++;
+ }
+
+ fb_data->powering_down = true;
+ epdc_powerdown(fb_data);
+ } else if (fb_data->power_state != POWER_STATE_OFF) {
+ fb_data->wait_for_powerdown = true;
+ init_completion(&fb_data->powerdown_compl);
+ mutex_unlock(&fb_data->power_mutex);
+ ret = wait_for_completion_timeout(&fb_data->powerdown_compl,
+ msecs_to_jiffies(5000));
+ if (!ret) {
+ dev_err(fb_data->dev,
+ "No powerdown received!\n");
+ return -ETIMEDOUT;
+ }
+ } else
+ mutex_unlock(&fb_data->power_mutex);
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ mxc_epdc_fb_flush_updates(fb_data);
+ break;
+ }
+ return 0;
+}
+
+static int mxc_epdc_fb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+ u_int y_bottom;
+
+ dev_dbg(info->device, "%s: var->yoffset %d, info->var.yoffset %d\n",
+ __func__, var->yoffset, info->var.yoffset);
+ /* check if var is valid; also, xpan is not supported */
+ if (!var || (var->xoffset != info->var.xoffset) ||
+ (var->yoffset + var->yres > var->yres_virtual)) {
+ dev_dbg(info->device, "x panning not supported\n");
+ return -EINVAL;
+ }
+
+ if ((fb_data->epdc_fb_var.xoffset == var->xoffset) &&
+ (fb_data->epdc_fb_var.yoffset == var->yoffset))
+ return 0; /* No change, do nothing */
+
+ y_bottom = var->yoffset;
+
+ if (!(var->vmode & FB_VMODE_YWRAP))
+ y_bottom += var->yres;
+
+ if (y_bottom > info->var.yres_virtual)
+ return -EINVAL;
+
+ mutex_lock(&fb_data->queue_mutex);
+
+ fb_data->fb_offset = (var->yoffset * var->xres_virtual + var->xoffset)
+ * (var->bits_per_pixel) / 8;
+
+ fb_data->epdc_fb_var.xoffset = var->xoffset;
+ fb_data->epdc_fb_var.yoffset = var->yoffset;
+
+ if (var->vmode & FB_VMODE_YWRAP)
+ info->var.vmode |= FB_VMODE_YWRAP;
+ else
+ info->var.vmode &= ~FB_VMODE_YWRAP;
+
+ mutex_unlock(&fb_data->queue_mutex);
+
+ return 0;
+}
+
+static struct fb_ops mxc_epdc_fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = mxc_epdc_fb_check_var,
+ .fb_set_par = mxc_epdc_fb_set_par,
+ .fb_setcmap = mxc_epdc_fb_setcmap,
+ .fb_setcolreg = mxc_epdc_fb_setcolreg,
+ .fb_pan_display = mxc_epdc_fb_pan_display,
+ .fb_ioctl = mxc_epdc_fb_ioctl,
+ .fb_mmap = mxc_epdc_fb_mmap,
+ .fb_blank = mxc_epdc_fb_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static struct fb_deferred_io mxc_epdc_fb_defio = {
+ .delay = HZ,
+ .deferred_io = mxc_epdc_fb_deferred_io,
+};
+
+static void epdc_done_work_func(struct work_struct *work)
+{
+ struct mxc_epdc_fb_data *fb_data =
+ container_of(work, struct mxc_epdc_fb_data,
+ epdc_done_work.work);
+ epdc_powerdown(fb_data);
+}
+
+static bool is_free_list_full(struct mxc_epdc_fb_data *fb_data)
+{
+ int count = 0;
+ struct update_data_list *plist;
+
+ /* Count buffers in free buffer list */
+ list_for_each_entry(plist, &fb_data->upd_buf_free_list, list)
+ count++;
+
+ /* Check to see if all buffers are in this list */
+ if (count == fb_data->max_num_updates)
+ return true;
+ else
+ return false;
+}
+
+static irqreturn_t mxc_epdc_irq_handler(int irq, void *dev_id)
+{
+ struct mxc_epdc_fb_data *fb_data = dev_id;
+ u32 ints_fired, luts1_ints_fired, luts2_ints_fired;
+
+ /*
+ * If we just completed one-time panel init, bypass
+ * queue handling, clear interrupt and return
+ */
+ if (fb_data->in_init) {
+ if (epdc_is_working_buffer_complete()) {
+ epdc_working_buf_intr(false);
+ epdc_clear_working_buf_irq();
+ dev_dbg(fb_data->dev, "Cleared WB for init update\n");
+ }
+
+ if (epdc_is_lut_complete(fb_data->rev, 0)) {
+ epdc_lut_complete_intr(fb_data->rev, 0, false);
+ epdc_clear_lut_complete_irq(fb_data->rev, 0);
+ fb_data->in_init = false;
+ dev_dbg(fb_data->dev, "Cleared LUT complete for init update\n");
+ }
+
+ return IRQ_HANDLED;
+ }
+
+ ints_fired = __raw_readl(EPDC_IRQ_MASK) & __raw_readl(EPDC_IRQ);
+ if (fb_data->rev < 20) {
+ luts1_ints_fired = 0;
+ luts2_ints_fired = 0;
+ } else {
+ luts1_ints_fired = __raw_readl(EPDC_IRQ_MASK1) & __raw_readl(EPDC_IRQ1);
+ luts2_ints_fired = __raw_readl(EPDC_IRQ_MASK2) & __raw_readl(EPDC_IRQ2);
+ }
+
+ if (!(ints_fired || luts1_ints_fired || luts2_ints_fired))
+ return IRQ_HANDLED;
+
+ if (__raw_readl(EPDC_IRQ) & EPDC_IRQ_TCE_UNDERRUN_IRQ) {
+ dev_err(fb_data->dev,
+ "TCE underrun! Will continue to update panel\n");
+ /* Clear TCE underrun IRQ */
+ __raw_writel(EPDC_IRQ_TCE_UNDERRUN_IRQ, EPDC_IRQ_CLEAR);
+ }
+
+ /* Check if we are waiting on EOF to sync a new update submission */
+ if (epdc_signal_eof()) {
+ epdc_eof_intr(false);
+ epdc_clear_eof_irq();
+ complete(&fb_data->eof_event);
+ }
+
+ /*
+ * Workaround for EPDC v2.0/v2.1 errata: Must read collision status
+ * before clearing IRQ, or else collision status for bits 16:63
+ * will be automatically cleared. So we read it here, and there is
+ * no conflict with using it in epdc_intr_work_func since the
+ * working buffer processing flow is strictly sequential (i.e.,
+ * only one WB processing done at a time, so the data grabbed
+ * here should be up-to-date and accurate when the WB processing
+ * completes. Also, note that there is no impact to other versions
+ * of EPDC by reading LUT status here.
+ */
+ if (fb_data->cur_update != NULL)
+ fb_data->epdc_colliding_luts = epdc_get_colliding_luts(fb_data->rev);
+
+ /* Clear the interrupt mask for any interrupts signalled */
+ __raw_writel(ints_fired, EPDC_IRQ_MASK_CLEAR);
+ __raw_writel(luts1_ints_fired, EPDC_IRQ_MASK1_CLEAR);
+ __raw_writel(luts2_ints_fired, EPDC_IRQ_MASK2_CLEAR);
+
+ dev_dbg(fb_data->dev, "EPDC interrupts fired = 0x%x, "
+ "LUTS1 fired = 0x%x, LUTS2 fired = 0x%x\n",
+ ints_fired, luts1_ints_fired, luts2_ints_fired);
+
+ queue_work(fb_data->epdc_intr_workqueue,
+ &fb_data->epdc_intr_work);
+
+ return IRQ_HANDLED;
+}
+
+static void epdc_intr_work_func(struct work_struct *work)
+{
+ struct mxc_epdc_fb_data *fb_data =
+ container_of(work, struct mxc_epdc_fb_data, epdc_intr_work);
+ struct update_data_list *collision_update;
+ struct mxcfb_rect *next_upd_region;
+ struct update_marker_data *next_marker;
+ struct update_marker_data *temp;
+ int temp_index;
+ u64 temp_mask;
+ u32 lut;
+ bool ignore_collision = false;
+ int i;
+ bool wb_lut_done = false;
+ bool free_update = true;
+ int next_lut, epdc_next_lut_15;
+ u32 epdc_luts_active, epdc_wb_busy, epdc_luts_avail, epdc_lut_cancelled;
+ u32 epdc_collision;
+ u64 epdc_irq_stat;
+ bool epdc_waiting_on_wb;
+ u32 coll_coord, coll_size;
+ struct mxcfb_rect coll_region;
+
+ /* Protect access to buffer queues and to update HW */
+ mutex_lock(&fb_data->queue_mutex);
+
+ /* Capture EPDC status one time to limit exposure to race conditions */
+ epdc_luts_active = epdc_any_luts_active(fb_data->rev);
+ epdc_wb_busy = epdc_is_working_buffer_busy();
+ epdc_lut_cancelled = epdc_is_lut_cancelled();
+ epdc_luts_avail = epdc_any_luts_available();
+ epdc_collision = epdc_is_collision();
+ if (fb_data->rev < 20)
+ epdc_irq_stat = __raw_readl(EPDC_IRQ);
+ else
+ epdc_irq_stat = (u64)__raw_readl(EPDC_IRQ1) |
+ ((u64)__raw_readl(EPDC_IRQ2) << 32);
+ epdc_waiting_on_wb = (fb_data->cur_update != NULL) ? true : false;
+
+ /* Free any LUTs that have completed */
+ for (i = 0; i < fb_data->num_luts; i++) {
+ if ((epdc_irq_stat & (1ULL << i)) == 0)
+ continue;
+
+ dev_dbg(fb_data->dev, "LUT %d completed\n", i);
+
+ /* Disable IRQ for completed LUT */
+ epdc_lut_complete_intr(fb_data->rev, i, false);
+
+ /*
+ * Go through all updates in the collision list and
+ * unmask any updates that were colliding with
+ * the completed LUT.
+ */
+ list_for_each_entry(collision_update,
+ &fb_data->upd_buf_collision_list, list) {
+ collision_update->collision_mask =
+ collision_update->collision_mask & ~(1 << i);
+ }
+
+ epdc_clear_lut_complete_irq(fb_data->rev, i);
+
+ fb_data->luts_complete_wb |= 1ULL << i;
+
+ fb_data->lut_update_order[i] = 0;
+
+ /* Signal completion if submit workqueue needs a LUT */
+ if (fb_data->waiting_for_lut) {
+ complete(&fb_data->update_res_free);
+ fb_data->waiting_for_lut = false;
+ }
+
+ /* Signal completion if LUT15 free and is needed */
+ if (fb_data->waiting_for_lut15 && (i == 15)) {
+ complete(&fb_data->lut15_free);
+ fb_data->waiting_for_lut15 = false;
+ }
+
+ /* Detect race condition where WB and its LUT complete
+ (i.e. full update completes) in one swoop */
+ if (epdc_waiting_on_wb &&
+ (i == fb_data->cur_update->lut_num))
+ wb_lut_done = true;
+
+ /* Signal completion if anyone waiting on this LUT */
+ if (!wb_lut_done)
+ list_for_each_entry_safe(next_marker, temp,
+ &fb_data->full_marker_list,
+ full_list) {
+ if (next_marker->lut_num != i)
+ continue;
+
+ /* Found marker to signal - remove from list */
+ list_del_init(&next_marker->full_list);
+
+ /* Signal completion of update */
+ dev_dbg(fb_data->dev, "Signaling marker %d\n",
+ next_marker->update_marker);
+ if (next_marker->waiting)
+ complete(&next_marker->update_completion);
+ else
+ kfree(next_marker);
+ }
+ }
+
+ /* Check to see if all updates have completed */
+ if (list_empty(&fb_data->upd_pending_list) &&
+ is_free_list_full(fb_data) &&
+ !epdc_waiting_on_wb &&
+ !epdc_luts_active) {
+
+ fb_data->updates_active = false;
+
+ if (fb_data->pwrdown_delay != FB_POWERDOWN_DISABLE) {
+ /*
+ * Set variable to prevent overlapping
+ * enable/disable requests
+ */
+ fb_data->powering_down = true;
+
+ /* Schedule task to disable EPDC HW until next update */
+ schedule_delayed_work(&fb_data->epdc_done_work,
+ msecs_to_jiffies(fb_data->pwrdown_delay));
+
+ /* Reset counter to reduce chance of overflow */
+ fb_data->order_cnt = 0;
+ }
+
+ if (fb_data->waiting_for_idle)
+ complete(&fb_data->updates_done);
+ }
+
+ /* Is Working Buffer busy? */
+ if (epdc_wb_busy) {
+ /* Can't submit another update until WB is done */
+ mutex_unlock(&fb_data->queue_mutex);
+ return;
+ }
+
+ /*
+ * Were we waiting on working buffer?
+ * If so, update queues and check for collisions
+ */
+ if (epdc_waiting_on_wb) {
+ dev_dbg(fb_data->dev, "\nWorking buffer completed\n");
+
+ /* Signal completion if submit workqueue was waiting on WB */
+ if (fb_data->waiting_for_wb) {
+ complete(&fb_data->update_res_free);
+ fb_data->waiting_for_wb = false;
+ }
+
+ if (fb_data->cur_update->update_desc->upd_data.flags
+ & EPDC_FLAG_TEST_COLLISION) {
+ /* This was a dry run to test for collision */
+
+ /* Signal marker */
+ list_for_each_entry_safe(next_marker, temp,
+ &fb_data->full_marker_list,
+ full_list) {
+ if (next_marker->lut_num != DRY_RUN_NO_LUT)
+ continue;
+
+ if (epdc_collision)
+ next_marker->collision_test = true;
+ else
+ next_marker->collision_test = false;
+
+ dev_dbg(fb_data->dev,
+ "In IRQ, collision_test = %d\n",
+ next_marker->collision_test);
+
+ /* Found marker to signal - remove from list */
+ list_del_init(&next_marker->full_list);
+
+ /* Signal completion of update */
+ dev_dbg(fb_data->dev, "Signaling marker "
+ "for dry-run - %d\n",
+ next_marker->update_marker);
+ complete(&next_marker->update_completion);
+ }
+ } else if (epdc_lut_cancelled && !epdc_collision) {
+ /*
+ * Note: The update may be cancelled (void) if all
+ * pixels collided. In that case we handle it as a
+ * collision, not a cancel.
+ */
+
+ /* Clear LUT status (might be set if no AUTOWV used) */
+
+ /*
+ * Disable and clear IRQ for the LUT used.
+ * Even though LUT is cancelled in HW, the LUT
+ * complete bit may be set if AUTOWV not used.
+ */
+ epdc_lut_complete_intr(fb_data->rev,
+ fb_data->cur_update->lut_num, false);
+ epdc_clear_lut_complete_irq(fb_data->rev,
+ fb_data->cur_update->lut_num);
+
+ fb_data->lut_update_order[fb_data->cur_update->lut_num] = 0;
+
+ /* Signal completion if submit workqueue needs a LUT */
+ if (fb_data->waiting_for_lut) {
+ complete(&fb_data->update_res_free);
+ fb_data->waiting_for_lut = false;
+ }
+
+ list_for_each_entry_safe(next_marker, temp,
+ &fb_data->cur_update->update_desc->upd_marker_list,
+ upd_list) {
+
+ /* Del from per-update & full list */
+ list_del_init(&next_marker->upd_list);
+ list_del_init(&next_marker->full_list);
+
+ /* Signal completion of update */
+ dev_dbg(fb_data->dev,
+ "Signaling marker (cancelled) %d\n",
+ next_marker->update_marker);
+ if (next_marker->waiting)
+ complete(&next_marker->update_completion);
+ else
+ kfree(next_marker);
+ }
+ } else if (epdc_collision) {
+ /* Real update (no dry-run), collision occurred */
+
+ /* Check list of colliding LUTs, and add to our collision mask */
+ fb_data->cur_update->collision_mask =
+ fb_data->epdc_colliding_luts;
+
+ /* Clear collisions that completed since WB began */
+ fb_data->cur_update->collision_mask &=
+ ~fb_data->luts_complete_wb;
+
+ dev_dbg(fb_data->dev, "Collision mask = 0x%llx\n",
+ fb_data->epdc_colliding_luts);
+
+ /* For EPDC 2.0 and later, minimum collision bounds
+ are provided by HW. Recompute new bounds here. */
+ if ((fb_data->upd_scheme != UPDATE_SCHEME_SNAPSHOT)
+ && (fb_data->rev >= 20)) {
+ u32 xres, yres, rotate;
+ struct mxcfb_rect *cur_upd_rect =
+ &fb_data->cur_update->update_desc->upd_data.update_region;
+
+ /* Get collision region coords from EPDC */
+ coll_coord = __raw_readl(EPDC_UPD_COL_CORD);
+ coll_size = __raw_readl(EPDC_UPD_COL_SIZE);
+ coll_region.left =
+ (coll_coord & EPDC_UPD_COL_CORD_XCORD_MASK)
+ >> EPDC_UPD_COL_CORD_XCORD_OFFSET;
+ coll_region.top =
+ (coll_coord & EPDC_UPD_COL_CORD_YCORD_MASK)
+ >> EPDC_UPD_COL_CORD_YCORD_OFFSET;
+ coll_region.width =
+ (coll_size & EPDC_UPD_COL_SIZE_WIDTH_MASK)
+ >> EPDC_UPD_COL_SIZE_WIDTH_OFFSET;
+ coll_region.height =
+ (coll_size & EPDC_UPD_COL_SIZE_HEIGHT_MASK)
+ >> EPDC_UPD_COL_SIZE_HEIGHT_OFFSET;
+ dev_dbg(fb_data->dev, "Coll region: l = %d, "
+ "t = %d, w = %d, h = %d\n",
+ coll_region.left, coll_region.top,
+ coll_region.width, coll_region.height);
+
+ /* Convert coords back to orig orientation */
+ switch (fb_data->epdc_fb_var.rotate) {
+ case FB_ROTATE_CW:
+ xres = fb_data->epdc_fb_var.yres;
+ yres = fb_data->epdc_fb_var.xres;
+ rotate = FB_ROTATE_CCW;
+ break;
+ case FB_ROTATE_UD:
+ xres = fb_data->epdc_fb_var.xres;
+ yres = fb_data->epdc_fb_var.yres;
+ rotate = FB_ROTATE_UD;
+ break;
+ case FB_ROTATE_CCW:
+ xres = fb_data->epdc_fb_var.yres;
+ yres = fb_data->epdc_fb_var.xres;
+ rotate = FB_ROTATE_CW;
+ break;
+ default:
+ xres = fb_data->epdc_fb_var.xres;
+ yres = fb_data->epdc_fb_var.yres;
+ rotate = FB_ROTATE_UR;
+ break;
+ }
+ adjust_coordinates(xres, yres, rotate,
+ &coll_region, cur_upd_rect);
+
+ dev_dbg(fb_data->dev, "Adj coll region: l = %d, "
+ "t = %d, w = %d, h = %d\n",
+ cur_upd_rect->left, cur_upd_rect->top,
+ cur_upd_rect->width,
+ cur_upd_rect->height);
+ }
+
+ /*
+ * If we collide with newer updates, then
+ * we don't need to re-submit the update. The
+ * idea is that the newer updates should take
+ * precedence anyways, so we don't want to
+ * overwrite them.
+ */
+ for (temp_mask = fb_data->cur_update->collision_mask, lut = 0;
+ temp_mask != 0;
+ lut++, temp_mask = temp_mask >> 1) {
+ if (!(temp_mask & 0x1))
+ continue;
+
+ if (fb_data->lut_update_order[lut] >=
+ fb_data->cur_update->update_desc->update_order) {
+ dev_dbg(fb_data->dev,
+ "Ignoring collision with"
+ "newer update.\n");
+ ignore_collision = true;
+ break;
+ }
+ }
+
+ if (!ignore_collision) {
+ free_update = false;
+ /*
+ * If update has markers, clear the LUTs to
+ * avoid signalling that they have completed.
+ */
+ list_for_each_entry_safe(next_marker, temp,
+ &fb_data->cur_update->update_desc->upd_marker_list,
+ upd_list)
+ next_marker->lut_num = INVALID_LUT;
+
+ /* Move to collision list */
+ list_add_tail(&fb_data->cur_update->list,
+ &fb_data->upd_buf_collision_list);
+ }
+ }
+
+ /* Do we need to free the current update descriptor? */
+ if (free_update) {
+ /* Handle condition where WB & LUT are both complete */
+ if (wb_lut_done)
+ list_for_each_entry_safe(next_marker, temp,
+ &fb_data->cur_update->update_desc->upd_marker_list,
+ upd_list) {
+
+ /* Del from per-update & full list */
+ list_del_init(&next_marker->upd_list);
+ list_del_init(&next_marker->full_list);
+
+ /* Signal completion of update */
+ dev_dbg(fb_data->dev,
+ "Signaling marker (wb) %d\n",
+ next_marker->update_marker);
+ if (next_marker->waiting)
+ complete(&next_marker->update_completion);
+ else
+ kfree(next_marker);
+ }
+
+ /* Free marker list and update descriptor */
+ kfree(fb_data->cur_update->update_desc);
+
+ /* Add to free buffer list */
+ list_add_tail(&fb_data->cur_update->list,
+ &fb_data->upd_buf_free_list);
+
+ /* Check to see if all updates have completed */
+ if (list_empty(&fb_data->upd_pending_list) &&
+ is_free_list_full(fb_data) &&
+ !epdc_luts_active) {
+
+ fb_data->updates_active = false;
+
+ if (fb_data->pwrdown_delay !=
+ FB_POWERDOWN_DISABLE) {
+ /*
+ * Set variable to prevent overlapping
+ * enable/disable requests
+ */
+ fb_data->powering_down = true;
+
+ /* Schedule EPDC disable */
+ schedule_delayed_work(&fb_data->epdc_done_work,
+ msecs_to_jiffies(fb_data->pwrdown_delay));
+
+ /* Reset counter to reduce chance of overflow */
+ fb_data->order_cnt = 0;
+ }
+
+ if (fb_data->waiting_for_idle)
+ complete(&fb_data->updates_done);
+ }
+ }
+
+ /* Clear current update */
+ fb_data->cur_update = NULL;
+
+ /* Clear IRQ for working buffer */
+ epdc_working_buf_intr(false);
+ epdc_clear_working_buf_irq();
+ }
+
+ if (fb_data->upd_scheme != UPDATE_SCHEME_SNAPSHOT) {
+ /* Queued update scheme processing */
+
+ /* Schedule task to submit collision and pending update */
+ if (!fb_data->powering_down)
+ queue_work(fb_data->epdc_submit_workqueue,
+ &fb_data->epdc_submit_work);
+
+ /* Release buffer queues */
+ mutex_unlock(&fb_data->queue_mutex);
+
+ return;
+ }
+
+ /* Snapshot update scheme processing */
+
+ /* Check to see if any LUTs are free */
+ if (!epdc_luts_avail) {
+ dev_dbg(fb_data->dev, "No luts available.\n");
+ mutex_unlock(&fb_data->queue_mutex);
+ return;
+ }
+
+ epdc_next_lut_15 = epdc_choose_next_lut(fb_data->rev, &next_lut);
+ /* Check to see if there is a valid LUT to use */
+ if (epdc_next_lut_15 && fb_data->tce_prevent && (fb_data->rev < 20)) {
+ dev_dbg(fb_data->dev, "Must wait for LUT15\n");
+ mutex_unlock(&fb_data->queue_mutex);
+ return;
+ }
+
+ /*
+ * Are any of our collision updates able to go now?
+ * Go through all updates in the collision list and check to see
+ * if the collision mask has been fully cleared
+ */
+ list_for_each_entry(collision_update,
+ &fb_data->upd_buf_collision_list, list) {
+
+ if (collision_update->collision_mask != 0)
+ continue;
+
+ dev_dbg(fb_data->dev, "A collision update is ready to go!\n");
+ /*
+ * We have a collision cleared, so select it
+ * and we will retry the update
+ */
+ fb_data->cur_update = collision_update;
+ list_del_init(&fb_data->cur_update->list);
+ break;
+ }
+
+ /*
+ * If we didn't find a collision update ready to go,
+ * we try to grab one from the update queue
+ */
+ if (fb_data->cur_update == NULL) {
+ /* Is update list empty? */
+ if (list_empty(&fb_data->upd_buf_queue)) {
+ dev_dbg(fb_data->dev, "No pending updates.\n");
+
+ /* No updates pending, so we are done */
+ mutex_unlock(&fb_data->queue_mutex);
+ return;
+ } else {
+ dev_dbg(fb_data->dev, "Found a pending update!\n");
+
+ /* Process next item in update list */
+ fb_data->cur_update =
+ list_entry(fb_data->upd_buf_queue.next,
+ struct update_data_list, list);
+ list_del_init(&fb_data->cur_update->list);
+ }
+ }
+
+ /* Use LUT selected above */
+ fb_data->cur_update->lut_num = next_lut;
+
+ /* Associate LUT with update markers */
+ list_for_each_entry_safe(next_marker, temp,
+ &fb_data->cur_update->update_desc->upd_marker_list, upd_list)
+ next_marker->lut_num = fb_data->cur_update->lut_num;
+
+ /* Mark LUT as containing new update */
+ fb_data->lut_update_order[fb_data->cur_update->lut_num] =
+ fb_data->cur_update->update_desc->update_order;
+
+ /* Enable Collision and WB complete IRQs */
+ epdc_working_buf_intr(true);
+ epdc_lut_complete_intr(fb_data->rev, fb_data->cur_update->lut_num, true);
+
+ /* Program EPDC update to process buffer */
+ next_upd_region =
+ &fb_data->cur_update->update_desc->upd_data.update_region;
+ if (fb_data->cur_update->update_desc->upd_data.temp
+ != TEMP_USE_AMBIENT) {
+ temp_index = mxc_epdc_fb_get_temp_index(fb_data,
+ fb_data->cur_update->update_desc->upd_data.temp);
+ epdc_set_temp(temp_index);
+ } else
+ epdc_set_temp(fb_data->temp_index);
+ epdc_set_update_addr(fb_data->cur_update->phys_addr +
+ fb_data->cur_update->update_desc->epdc_offs);
+ epdc_set_update_coord(next_upd_region->left, next_upd_region->top);
+ epdc_set_update_dimensions(next_upd_region->width,
+ next_upd_region->height);
+ if (fb_data->rev > 20)
+ epdc_set_update_stride(fb_data->cur_update->update_desc->epdc_stride);
+ if (fb_data->wv_modes_update &&
+ (fb_data->cur_update->update_desc->upd_data.waveform_mode
+ == WAVEFORM_MODE_AUTO)) {
+ epdc_set_update_waveform(&fb_data->wv_modes);
+ fb_data->wv_modes_update = false;
+ }
+
+ epdc_submit_update(fb_data->cur_update->lut_num,
+ fb_data->cur_update->update_desc->upd_data.waveform_mode,
+ fb_data->cur_update->update_desc->upd_data.update_mode,
+ false, false, 0);
+
+ /* Release buffer queues */
+ mutex_unlock(&fb_data->queue_mutex);
+
+ return;
+}
+
+static void draw_mode0(struct mxc_epdc_fb_data *fb_data)
+{
+ u32 *upd_buf_ptr;
+ int i;
+ struct fb_var_screeninfo *screeninfo = &fb_data->epdc_fb_var;
+ u32 xres, yres;
+
+ upd_buf_ptr = (u32 *)fb_data->info.screen_base;
+
+ epdc_working_buf_intr(true);
+ epdc_lut_complete_intr(fb_data->rev, 0, true);
+
+ /* Use unrotated (native) width/height */
+ if ((screeninfo->rotate == FB_ROTATE_CW) ||
+ (screeninfo->rotate == FB_ROTATE_CCW)) {
+ xres = screeninfo->yres;
+ yres = screeninfo->xres;
+ } else {
+ xres = screeninfo->xres;
+ yres = screeninfo->yres;
+ }
+
+ /* Program EPDC update to process buffer */
+ epdc_set_update_addr(fb_data->phys_start);
+ epdc_set_update_coord(0, 0);
+ epdc_set_update_dimensions(xres, yres);
+ if (fb_data->rev > 20)
+ epdc_set_update_stride(0);
+ epdc_submit_update(0, fb_data->wv_modes.mode_init, UPDATE_MODE_FULL,
+ false, true, 0xFF);
+
+ dev_dbg(fb_data->dev, "Mode0 update - Waiting for LUT to complete...\n");
+
+ /* Will timeout after ~4-5 seconds */
+
+ for (i = 0; i < 40; i++) {
+ if (!epdc_is_lut_active(0)) {
+ dev_dbg(fb_data->dev, "Mode0 init complete\n");
+ return;
+ }
+ msleep(100);
+ }
+
+ dev_err(fb_data->dev, "Mode0 init failed!\n");
+
+ return;
+}
+
+
+static void mxc_epdc_fb_fw_handler(const struct firmware *fw,
+ void *context)
+{
+ struct mxc_epdc_fb_data *fb_data = context;
+ int ret;
+ struct mxcfb_waveform_data_file *wv_file;
+ int wv_data_offs;
+ int i;
+ struct mxcfb_update_data update;
+ struct mxcfb_update_marker_data upd_marker_data;
+ struct fb_var_screeninfo *screeninfo = &fb_data->epdc_fb_var;
+ u32 xres, yres;
+ struct clk *epdc_parent;
+ unsigned long rounded_parent_rate, epdc_pix_rate,
+ rounded_pix_clk, target_pix_clk;
+
+ if (fw == NULL) {
+ /* If default FW file load failed, we give up */
+ if (fb_data->fw_default_load)
+ return;
+
+ /* Try to load default waveform */
+ dev_dbg(fb_data->dev,
+ "Can't find firmware. Trying fallback fw\n");
+ fb_data->fw_default_load = true;
+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ "imx/epdc/epdc.fw", fb_data->dev, GFP_KERNEL, fb_data,
+ mxc_epdc_fb_fw_handler);
+ if (ret)
+ dev_err(fb_data->dev,
+ "Failed request_firmware_nowait err %d\n", ret);
+
+ return;
+ }
+
+ wv_file = (struct mxcfb_waveform_data_file *)fw->data;
+
+ /* Get size and allocate temperature range table */
+ fb_data->trt_entries = wv_file->wdh.trc + 1;
+ fb_data->temp_range_bounds = kzalloc(fb_data->trt_entries, GFP_KERNEL);
+
+ for (i = 0; i < fb_data->trt_entries; i++)
+ dev_dbg(fb_data->dev, "trt entry #%d = 0x%x\n", i, *((u8 *)&wv_file->data + i));
+
+ /* Copy TRT data */
+ memcpy(fb_data->temp_range_bounds, &wv_file->data, fb_data->trt_entries);
+
+ /* Set default temperature index using TRT and room temp */
+ fb_data->temp_index = mxc_epdc_fb_get_temp_index(fb_data, DEFAULT_TEMP);
+
+ /* Get offset and size for waveform data */
+ wv_data_offs = sizeof(wv_file->wdh) + fb_data->trt_entries + 1;
+ fb_data->waveform_buffer_size = fw->size - wv_data_offs;
+
+ /* Allocate memory for waveform data */
+ fb_data->waveform_buffer_virt = dma_alloc_coherent(fb_data->dev,
+ fb_data->waveform_buffer_size,
+ &fb_data->waveform_buffer_phys,
+ GFP_DMA | GFP_KERNEL);
+ if (fb_data->waveform_buffer_virt == NULL) {
+ dev_err(fb_data->dev, "Can't allocate mem for waveform!\n");
+ return;
+ }
+
+ memcpy(fb_data->waveform_buffer_virt, (u8 *)(fw->data) + wv_data_offs,
+ fb_data->waveform_buffer_size);
+
+ release_firmware(fw);
+
+ /* Enable clocks to access EPDC regs */
+ clk_prepare_enable(fb_data->epdc_clk_axi);
+
+ target_pix_clk = fb_data->cur_mode->vmode->pixclock;
+ /* Enable pix clk for EPDC */
+ rounded_pix_clk = clk_round_rate(fb_data->epdc_clk_pix, target_pix_clk);
+
+ if (((rounded_pix_clk >= target_pix_clk + target_pix_clk/100) ||
+ (rounded_pix_clk <= target_pix_clk - target_pix_clk/100))) {
+ /* Can't get close enough without changing parent clk */
+ epdc_parent = clk_get_parent(fb_data->epdc_clk_pix);
+ rounded_parent_rate = clk_round_rate(epdc_parent, target_pix_clk);
+
+ epdc_pix_rate = target_pix_clk;
+ while (epdc_pix_rate < rounded_parent_rate)
+ epdc_pix_rate *= 2;
+ clk_set_rate(epdc_parent, epdc_pix_rate);
+
+ rounded_pix_clk = clk_round_rate(fb_data->epdc_clk_pix, target_pix_clk);
+ if (((rounded_pix_clk >= target_pix_clk + target_pix_clk/100) ||
+ (rounded_pix_clk <= target_pix_clk - target_pix_clk/100)))
+ /* Still can't get a good clock, provide warning */
+ dev_err(fb_data->dev, "Unable to get an accurate EPDC pix clk"
+ "desired = %lu, actual = %lu\n", target_pix_clk,
+ rounded_pix_clk);
+ }
+
+ clk_set_rate(fb_data->epdc_clk_pix, rounded_pix_clk);
+ clk_prepare_enable(fb_data->epdc_clk_pix);
+
+ epdc_init_sequence(fb_data);
+
+ /* Disable clocks */
+ clk_disable_unprepare(fb_data->epdc_clk_axi);
+ clk_disable_unprepare(fb_data->epdc_clk_pix);
+
+ fb_data->hw_ready = true;
+ fb_data->hw_initializing = false;
+
+ /* Use unrotated (native) width/height */
+ if ((screeninfo->rotate == FB_ROTATE_CW) ||
+ (screeninfo->rotate == FB_ROTATE_CCW)) {
+ xres = screeninfo->yres;
+ yres = screeninfo->xres;
+ } else {
+ xres = screeninfo->xres;
+ yres = screeninfo->yres;
+ }
+
+ update.update_region.left = 0;
+ update.update_region.width = xres;
+ update.update_region.top = 0;
+ update.update_region.height = yres;
+ update.update_mode = UPDATE_MODE_FULL;
+ update.waveform_mode = WAVEFORM_MODE_AUTO;
+ update.update_marker = INIT_UPDATE_MARKER;
+ update.temp = TEMP_USE_AMBIENT;
+ update.flags = 0;
+
+ upd_marker_data.update_marker = update.update_marker;
+
+ mxc_epdc_fb_send_update(&update, &fb_data->info);
+
+ /* Block on initial update */
+ ret = mxc_epdc_fb_wait_update_complete(&upd_marker_data,
+ &fb_data->info);
+ if (ret < 0)
+ dev_err(fb_data->dev,
+ "Wait for initial update complete failed."
+ " Error = 0x%x", ret);
+}
+
+static int mxc_epdc_fb_init_hw(struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+ int ret;
+
+ /*
+ * Create fw search string based on ID string in selected videomode.
+ * Format is "imx/epdc_[panel string].fw"
+ */
+ if (fb_data->cur_mode) {
+ strcat(fb_data->fw_str, "imx/epdc/epdc_");
+ strcat(fb_data->fw_str, fb_data->cur_mode->vmode->name);
+ strcat(fb_data->fw_str, ".fw");
+ }
+
+ fb_data->fw_default_load = false;
+
+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ fb_data->fw_str, fb_data->dev, GFP_KERNEL,
+ fb_data, mxc_epdc_fb_fw_handler);
+ if (ret)
+ dev_dbg(fb_data->dev,
+ "Failed request_firmware_nowait err %d\n", ret);
+
+ return ret;
+}
+
+static ssize_t store_update(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mxcfb_update_data update;
+ struct fb_info *info = dev_get_drvdata(device);
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+
+ if (strncmp(buf, "direct", 6) == 0)
+ update.waveform_mode = fb_data->wv_modes.mode_du;
+ else if (strncmp(buf, "gc16", 4) == 0)
+ update.waveform_mode = fb_data->wv_modes.mode_gc16;
+ else if (strncmp(buf, "gc4", 3) == 0)
+ update.waveform_mode = fb_data->wv_modes.mode_gc4;
+
+ /* Now, request full screen update */
+ update.update_region.left = 0;
+ update.update_region.width = fb_data->epdc_fb_var.xres;
+ update.update_region.top = 0;
+ update.update_region.height = fb_data->epdc_fb_var.yres;
+ update.update_mode = UPDATE_MODE_FULL;
+ update.temp = TEMP_USE_AMBIENT;
+ update.update_marker = 0;
+ update.flags = 0;
+
+ mxc_epdc_fb_send_update(&update, info);
+
+ return count;
+}
+
+static struct device_attribute fb_attrs[] = {
+ __ATTR(update, S_IRUGO|S_IWUSR, NULL, store_update),
+};
+
+static const struct of_device_id imx_epdc_dt_ids[] = {
+ { .compatible = "fsl,imx6dl-epdc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_epdc_dt_ids);
+
+int mxc_epdc_fb_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct pinctrl *pinctrl;
+ struct mxc_epdc_fb_data *fb_data;
+ struct resource *res;
+ struct fb_info *info;
+ char *options, *opt;
+ char *panel_str = NULL;
+ char name[] = "mxcepdcfb";
+ struct fb_videomode *vmode;
+ int xres_virt, yres_virt, buf_size;
+ int xres_virt_rot, yres_virt_rot, pix_size_rot;
+ struct fb_var_screeninfo *var_info;
+ struct fb_fix_screeninfo *fix_info;
+ struct pxp_config_data *pxp_conf;
+ struct pxp_proc_data *proc_data;
+ struct scatterlist *sg;
+ struct update_data_list *upd_list;
+ struct update_data_list *plist, *temp_list;
+ int i;
+ unsigned long x_mem_size = 0;
+ u32 val;
+ int irq;
+
+ fb_data = (struct mxc_epdc_fb_data *)framebuffer_alloc(
+ sizeof(struct mxc_epdc_fb_data), &pdev->dev);
+ if (fb_data == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Get platform data and check validity */
+ fb_data->pdata = &epdc_data;
+ if ((fb_data->pdata == NULL) || (fb_data->pdata->num_modes < 1)
+ || (fb_data->pdata->epdc_mode == NULL)
+ || (fb_data->pdata->epdc_mode->vmode == NULL)) {
+ ret = -EINVAL;
+ goto out_fbdata;
+ }
+
+ if (fb_get_options(name, &options)) {
+ ret = -ENODEV;
+ goto out_fbdata;
+ }
+
+ fb_data->tce_prevent = 0;
+
+ if (options)
+ while ((opt = strsep(&options, ",")) != NULL) {
+ if (!*opt)
+ continue;
+
+ if (!strncmp(opt, "bpp=", 4))
+ fb_data->default_bpp =
+ simple_strtoul(opt + 4, NULL, 0);
+ else if (!strncmp(opt, "x_mem=", 6))
+ x_mem_size = memparse(opt + 6, NULL);
+ else if (!strncmp(opt, "tce_prevent", 11))
+ fb_data->tce_prevent = 1;
+ else
+ panel_str = opt;
+ }
+
+ fb_data->dev = &pdev->dev;
+
+ if (!fb_data->default_bpp)
+ fb_data->default_bpp = 16;
+
+ /* Set default (first defined mode) before searching for a match */
+ fb_data->cur_mode = &fb_data->pdata->epdc_mode[0];
+
+ if (panel_str)
+ for (i = 0; i < fb_data->pdata->num_modes; i++)
+ if (!strcmp(fb_data->pdata->epdc_mode[i].vmode->name,
+ panel_str)) {
+ fb_data->cur_mode =
+ &fb_data->pdata->epdc_mode[i];
+ break;
+ }
+
+ vmode = fb_data->cur_mode->vmode;
+
+ platform_set_drvdata(pdev, fb_data);
+ info = &fb_data->info;
+
+ /* Allocate color map for the FB */
+ ret = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (ret)
+ goto out_fbdata;
+
+ dev_dbg(&pdev->dev, "resolution %dx%d, bpp %d\n",
+ vmode->xres, vmode->yres, fb_data->default_bpp);
+
+ /*
+ * GPU alignment restrictions dictate framebuffer parameters:
+ * - 32-byte alignment for buffer width
+ * - 128-byte alignment for buffer height
+ * => 4K buffer alignment for buffer start
+ */
+ xres_virt = ALIGN(vmode->xres, 32);
+ yres_virt = ALIGN(vmode->yres, 128);
+ fb_data->max_pix_size = PAGE_ALIGN(xres_virt * yres_virt);
+
+ /*
+ * Have to check to see if aligned buffer size when rotated
+ * is bigger than when not rotated, and use the max
+ */
+ xres_virt_rot = ALIGN(vmode->yres, 32);
+ yres_virt_rot = ALIGN(vmode->xres, 128);
+ pix_size_rot = PAGE_ALIGN(xres_virt_rot * yres_virt_rot);
+ fb_data->max_pix_size = (fb_data->max_pix_size > pix_size_rot) ?
+ fb_data->max_pix_size : pix_size_rot;
+
+ buf_size = fb_data->max_pix_size * fb_data->default_bpp/8;
+
+ /* Compute the number of screens needed based on X memory requested */
+ if (x_mem_size > 0) {
+ fb_data->num_screens = DIV_ROUND_UP(x_mem_size, buf_size);
+ if (fb_data->num_screens < NUM_SCREENS_MIN)
+ fb_data->num_screens = NUM_SCREENS_MIN;
+ else if (buf_size * fb_data->num_screens > SZ_16M)
+ fb_data->num_screens = SZ_16M / buf_size;
+ } else
+ fb_data->num_screens = NUM_SCREENS_MIN;
+
+ fb_data->map_size = buf_size * fb_data->num_screens;
+ dev_dbg(&pdev->dev, "memory to allocate: %d\n", fb_data->map_size);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ ret = -ENODEV;
+ goto out_cmap;
+ }
+
+ epdc_base = devm_ioremap_resource(&pdev->dev, res);
+ if (epdc_base == NULL) {
+ ret = -ENOMEM;
+ goto out_cmap;
+ }
+
+ /* Allocate FB memory */
+ info->screen_base = dma_alloc_writecombine(&pdev->dev,
+ fb_data->map_size,
+ &fb_data->phys_start,
+ GFP_DMA | GFP_KERNEL);
+
+ if (info->screen_base == NULL) {
+ ret = -ENOMEM;
+ goto out_cmap;
+ }
+ dev_dbg(&pdev->dev, "allocated at %p:0x%x\n", info->screen_base,
+ fb_data->phys_start);
+
+ var_info = &info->var;
+ var_info->activate = FB_ACTIVATE_TEST;
+ var_info->bits_per_pixel = fb_data->default_bpp;
+ var_info->xres = vmode->xres;
+ var_info->yres = vmode->yres;
+ var_info->xres_virtual = xres_virt;
+ /* Additional screens allow for panning and buffer flipping */
+ var_info->yres_virtual = yres_virt * fb_data->num_screens;
+
+ var_info->pixclock = vmode->pixclock;
+ var_info->left_margin = vmode->left_margin;
+ var_info->right_margin = vmode->right_margin;
+ var_info->upper_margin = vmode->upper_margin;
+ var_info->lower_margin = vmode->lower_margin;
+ var_info->hsync_len = vmode->hsync_len;
+ var_info->vsync_len = vmode->vsync_len;
+ var_info->vmode = FB_VMODE_NONINTERLACED;
+
+ switch (fb_data->default_bpp) {
+ case 32:
+ case 24:
+ var_info->red.offset = 16;
+ var_info->red.length = 8;
+ var_info->green.offset = 8;
+ var_info->green.length = 8;
+ var_info->blue.offset = 0;
+ var_info->blue.length = 8;
+ break;
+
+ case 16:
+ var_info->red.offset = 11;
+ var_info->red.length = 5;
+ var_info->green.offset = 5;
+ var_info->green.length = 6;
+ var_info->blue.offset = 0;
+ var_info->blue.length = 5;
+ break;
+
+ case 8:
+ /*
+ * For 8-bit grayscale, R, G, and B offset are equal.
+ *
+ */
+ var_info->grayscale = GRAYSCALE_8BIT;
+
+ var_info->red.length = 8;
+ var_info->red.offset = 0;
+ var_info->red.msb_right = 0;
+ var_info->green.length = 8;
+ var_info->green.offset = 0;
+ var_info->green.msb_right = 0;
+ var_info->blue.length = 8;
+ var_info->blue.offset = 0;
+ var_info->blue.msb_right = 0;
+ break;
+
+ default:
+ dev_err(&pdev->dev, "unsupported bitwidth %d\n",
+ fb_data->default_bpp);
+ ret = -EINVAL;
+ goto out_dma_fb;
+ }
+
+ fix_info = &info->fix;
+
+ strcpy(fix_info->id, "mxc_epdc_fb");
+ fix_info->type = FB_TYPE_PACKED_PIXELS;
+ fix_info->visual = FB_VISUAL_TRUECOLOR;
+ fix_info->xpanstep = 0;
+ fix_info->ypanstep = 0;
+ fix_info->ywrapstep = 0;
+ fix_info->accel = FB_ACCEL_NONE;
+ fix_info->smem_start = fb_data->phys_start;
+ fix_info->smem_len = fb_data->map_size;
+ fix_info->ypanstep = 0;
+
+ fb_data->native_width = vmode->xres;
+ fb_data->native_height = vmode->yres;
+
+ info->fbops = &mxc_epdc_fb_ops;
+ info->var.activate = FB_ACTIVATE_NOW;
+ info->pseudo_palette = fb_data->pseudo_palette;
+ info->screen_size = info->fix.smem_len;
+ info->flags = FBINFO_FLAG_DEFAULT;
+
+ mxc_epdc_fb_set_fix(info);
+
+ fb_data->auto_mode = AUTO_UPDATE_MODE_REGION_MODE;
+ fb_data->upd_scheme = UPDATE_SCHEME_QUEUE_AND_MERGE;
+
+ /* Initialize our internal copy of the screeninfo */
+ fb_data->epdc_fb_var = *var_info;
+ fb_data->fb_offset = 0;
+ fb_data->eof_sync_period = 0;
+
+ fb_data->epdc_clk_axi = clk_get(fb_data->dev, "epdc_axi");
+ if (IS_ERR(fb_data->epdc_clk_axi)) {
+ dev_err(&pdev->dev, "Unable to get EPDC AXI clk."
+ "err = %d\n", (int)fb_data->epdc_clk_axi);
+ ret = -ENODEV;
+ goto out_dma_fb;
+ }
+ fb_data->epdc_clk_pix = clk_get(fb_data->dev, "epdc_pix");
+ if (IS_ERR(fb_data->epdc_clk_pix)) {
+ dev_err(&pdev->dev, "Unable to get EPDC pix clk."
+ "err = %d\n", (int)fb_data->epdc_clk_pix);
+ ret = -ENODEV;
+ goto out_dma_fb;
+ }
+
+ clk_prepare_enable(fb_data->epdc_clk_axi);
+ val = __raw_readl(EPDC_VERSION);
+ clk_disable_unprepare(fb_data->epdc_clk_axi);
+ fb_data->rev = ((val & EPDC_VERSION_MAJOR_MASK) >>
+ EPDC_VERSION_MAJOR_OFFSET) * 10
+ + ((val & EPDC_VERSION_MINOR_MASK) >>
+ EPDC_VERSION_MINOR_OFFSET);
+ dev_dbg(&pdev->dev, "EPDC version = %d\n", fb_data->rev);
+
+ if (fb_data->rev < 20) {
+ fb_data->num_luts = EPDC_V1_NUM_LUTS;
+ fb_data->max_num_updates = EPDC_V1_MAX_NUM_UPDATES;
+ } else {
+ fb_data->num_luts = EPDC_V2_NUM_LUTS;
+ fb_data->max_num_updates = EPDC_V2_MAX_NUM_UPDATES;
+ if (vmode->xres > EPDC_V2_MAX_UPDATE_WIDTH)
+ fb_data->restrict_width = true;
+ }
+ fb_data->max_num_buffers = EPDC_MAX_NUM_BUFFERS;
+
+ /*
+ * Initialize lists for pending updates,
+ * active update requests, update collisions,
+ * and freely available updates.
+ */
+ INIT_LIST_HEAD(&fb_data->upd_pending_list);
+ INIT_LIST_HEAD(&fb_data->upd_buf_queue);
+ INIT_LIST_HEAD(&fb_data->upd_buf_free_list);
+ INIT_LIST_HEAD(&fb_data->upd_buf_collision_list);
+
+ /* Allocate update buffers and add them to the list */
+ for (i = 0; i < fb_data->max_num_updates; i++) {
+ upd_list = kzalloc(sizeof(*upd_list), GFP_KERNEL);
+ if (upd_list == NULL) {
+ ret = -ENOMEM;
+ goto out_upd_lists;
+ }
+
+ /* Add newly allocated buffer to free list */
+ list_add(&upd_list->list, &fb_data->upd_buf_free_list);
+ }
+
+ fb_data->virt_addr_updbuf =
+ kzalloc(sizeof(void *) * fb_data->max_num_buffers, GFP_KERNEL);
+ fb_data->phys_addr_updbuf =
+ kzalloc(sizeof(dma_addr_t) * fb_data->max_num_buffers,
+ GFP_KERNEL);
+ for (i = 0; i < fb_data->max_num_buffers; i++) {
+ /*
+ * Allocate memory for PxP output buffer.
+ * Each update buffer is 1 byte per pixel, and can
+ * be as big as the full-screen frame buffer
+ */
+ fb_data->virt_addr_updbuf[i] =
+ kmalloc(fb_data->max_pix_size, GFP_KERNEL);
+ fb_data->phys_addr_updbuf[i] =
+ virt_to_phys(fb_data->virt_addr_updbuf[i]);
+ if (fb_data->virt_addr_updbuf[i] == NULL) {
+ ret = -ENOMEM;
+ goto out_upd_buffers;
+ }
+
+ dev_dbg(fb_data->info.device, "allocated %d bytes @ 0x%08X\n",
+ fb_data->max_pix_size, fb_data->phys_addr_updbuf[i]);
+ }
+
+ /* Counter indicating which update buffer should be used next. */
+ fb_data->upd_buffer_num = 0;
+
+ /*
+ * Allocate memory for PxP SW workaround buffer
+ * These buffers are used to hold copy of the update region,
+ * before sending it to PxP for processing.
+ */
+ fb_data->virt_addr_copybuf =
+ dma_alloc_coherent(fb_data->info.device, fb_data->max_pix_size*2,
+ &fb_data->phys_addr_copybuf,
+ GFP_DMA | GFP_KERNEL);
+ if (fb_data->virt_addr_copybuf == NULL) {
+ ret = -ENOMEM;
+ goto out_upd_buffers;
+ }
+
+ fb_data->working_buffer_size = vmode->yres * vmode->xres * 2;
+ /* Allocate memory for EPDC working buffer */
+ fb_data->working_buffer_virt =
+ dma_alloc_coherent(&pdev->dev, fb_data->working_buffer_size,
+ &fb_data->working_buffer_phys,
+ GFP_DMA | GFP_KERNEL);
+ if (fb_data->working_buffer_virt == NULL) {
+ dev_err(&pdev->dev, "Can't allocate mem for working buf!\n");
+ ret = -ENOMEM;
+ goto out_copybuffer;
+ }
+
+ /* Initialize EPDC pins */
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ dev_err(&pdev->dev, "can't get/select pinctrl\n");
+ ret = PTR_ERR(pinctrl);
+ goto out_copybuffer;
+ }
+
+ fb_data->in_init = false;
+
+ fb_data->hw_ready = false;
+ fb_data->hw_initializing = false;
+
+ /*
+ * Set default waveform mode values.
+ * Should be overwritten via ioctl.
+ */
+ fb_data->wv_modes.mode_init = 0;
+ fb_data->wv_modes.mode_du = 1;
+ fb_data->wv_modes.mode_gc4 = 3;
+ fb_data->wv_modes.mode_gc8 = 2;
+ fb_data->wv_modes.mode_gc16 = 2;
+ fb_data->wv_modes.mode_gc32 = 2;
+ fb_data->wv_modes_update = true;
+
+ /* Initialize marker list */
+ INIT_LIST_HEAD(&fb_data->full_marker_list);
+
+ /* Initialize all LUTs to inactive */
+ fb_data->lut_update_order =
+ kzalloc(fb_data->num_luts * sizeof(u32 *), GFP_KERNEL);
+ for (i = 0; i < fb_data->num_luts; i++)
+ fb_data->lut_update_order[i] = 0;
+
+ INIT_DELAYED_WORK(&fb_data->epdc_done_work, epdc_done_work_func);
+ fb_data->epdc_submit_workqueue = alloc_workqueue("EPDC Submit",
+ WQ_MEM_RECLAIM | WQ_HIGHPRI |
+ WQ_CPU_INTENSIVE | WQ_UNBOUND, 1);
+ INIT_WORK(&fb_data->epdc_submit_work, epdc_submit_work_func);
+ fb_data->epdc_intr_workqueue = alloc_workqueue("EPDC Interrupt",
+ WQ_MEM_RECLAIM | WQ_HIGHPRI |
+ WQ_CPU_INTENSIVE | WQ_UNBOUND, 1);
+ INIT_WORK(&fb_data->epdc_intr_work, epdc_intr_work_func);
+
+ /* Retrieve EPDC IRQ num */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "cannot get IRQ resource\n");
+ ret = -ENODEV;
+ goto out_dma_work_buf;
+ }
+ fb_data->epdc_irq = irq;
+
+ /* Register IRQ handler */
+ ret = devm_request_irq(&pdev->dev, fb_data->epdc_irq,
+ mxc_epdc_irq_handler, 0, "epdc", fb_data);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq (%d) failed with error %d\n",
+ fb_data->epdc_irq, ret);
+ ret = -ENODEV;
+ goto out_dma_work_buf;
+ }
+
+ info->fbdefio = &mxc_epdc_fb_defio;
+#ifdef CONFIG_FB_MXC_EINK_AUTO_UPDATE_MODE
+ fb_deferred_io_init(info);
+#endif
+
+ /* get pmic regulators */
+ fb_data->display_regulator = devm_regulator_get(&pdev->dev, "DISPLAY");
+ if (IS_ERR(fb_data->display_regulator)) {
+ dev_err(&pdev->dev, "Unable to get display PMIC regulator."
+ "err = 0x%x\n", (int)fb_data->display_regulator);
+ ret = -ENODEV;
+ goto out_dma_work_buf;
+ }
+ fb_data->vcom_regulator = devm_regulator_get(&pdev->dev, "VCOM");
+ if (IS_ERR(fb_data->vcom_regulator)) {
+ dev_err(&pdev->dev, "Unable to get VCOM regulator."
+ "err = 0x%x\n", (int)fb_data->vcom_regulator);
+ ret = -ENODEV;
+ goto out_dma_work_buf;
+ }
+ fb_data->v3p3_regulator = devm_regulator_get(&pdev->dev, "V3P3");
+ if (IS_ERR(fb_data->v3p3_regulator)) {
+ dev_err(&pdev->dev, "Unable to get V3P3 regulator."
+ "err = 0x%x\n", (int)fb_data->vcom_regulator);
+ ret = -ENODEV;
+ goto out_dma_work_buf;
+ }
+
+ if (device_create_file(info->dev, &fb_attrs[0]))
+ dev_err(&pdev->dev, "Unable to create file from fb_attrs\n");
+
+ fb_data->cur_update = NULL;
+
+ mutex_init(&fb_data->queue_mutex);
+ mutex_init(&fb_data->pxp_mutex);
+ mutex_init(&fb_data->power_mutex);
+
+ /*
+ * Fill out PxP config data structure based on FB info and
+ * processing tasks required
+ */
+ pxp_conf = &fb_data->pxp_conf;
+ proc_data = &pxp_conf->proc_data;
+
+ /* Initialize non-channel-specific PxP parameters */
+ proc_data->drect.left = proc_data->srect.left = 0;
+ proc_data->drect.top = proc_data->srect.top = 0;
+ proc_data->drect.width = proc_data->srect.width = fb_data->info.var.xres;
+ proc_data->drect.height = proc_data->srect.height = fb_data->info.var.yres;
+ proc_data->scaling = 0;
+ proc_data->hflip = 0;
+ proc_data->vflip = 0;
+ proc_data->rotate = 0;
+ proc_data->bgcolor = 0;
+ proc_data->overlay_state = 0;
+ proc_data->lut_transform = PXP_LUT_NONE;
+ proc_data->lut_map = NULL;
+
+ /*
+ * We initially configure PxP for RGB->YUV conversion,
+ * and only write out Y component of the result.
+ */
+
+ /*
+ * Initialize S0 channel parameters
+ * Parameters should match FB format/width/height
+ */
+ pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_RGB565;
+ pxp_conf->s0_param.width = fb_data->info.var.xres_virtual;
+ pxp_conf->s0_param.height = fb_data->info.var.yres;
+ pxp_conf->s0_param.color_key = -1;
+ pxp_conf->s0_param.color_key_enable = false;
+
+ /*
+ * Initialize OL0 channel parameters
+ * No overlay will be used for PxP operation
+ */
+ pxp_conf->ol_param[0].combine_enable = false;
+ pxp_conf->ol_param[0].width = 0;
+ pxp_conf->ol_param[0].height = 0;
+ pxp_conf->ol_param[0].pixel_fmt = PXP_PIX_FMT_RGB565;
+ pxp_conf->ol_param[0].color_key_enable = false;
+ pxp_conf->ol_param[0].color_key = -1;
+ pxp_conf->ol_param[0].global_alpha_enable = false;
+ pxp_conf->ol_param[0].global_alpha = 0;
+ pxp_conf->ol_param[0].local_alpha_enable = false;
+
+ /*
+ * Initialize Output channel parameters
+ * Output is Y-only greyscale
+ * Output width/height will vary based on update region size
+ */
+ pxp_conf->out_param.width = fb_data->info.var.xres;
+ pxp_conf->out_param.height = fb_data->info.var.yres;
+ pxp_conf->out_param.stride = pxp_conf->out_param.width;
+ pxp_conf->out_param.pixel_fmt = PXP_PIX_FMT_GREY;
+
+ /* Initialize color map for conversion of 8-bit gray pixels */
+ fb_data->pxp_conf.proc_data.lut_map = kmalloc(256, GFP_KERNEL);
+ if (fb_data->pxp_conf.proc_data.lut_map == NULL) {
+ dev_err(&pdev->dev, "Can't allocate mem for lut map!\n");
+ ret = -ENOMEM;
+ goto out_dma_work_buf;
+ }
+ for (i = 0; i < 256; i++)
+ fb_data->pxp_conf.proc_data.lut_map[i] = i;
+
+ fb_data->pxp_conf.proc_data.lut_map_updated = true;
+
+ /*
+ * Ensure this is set to NULL here...we will initialize pxp_chan
+ * later in our thread.
+ */
+ fb_data->pxp_chan = NULL;
+
+ /* Initialize Scatter-gather list containing 2 buffer addresses. */
+ sg = fb_data->sg;
+ sg_init_table(sg, 2);
+
+ /*
+ * For use in PxP transfers:
+ * sg[0] holds the FB buffer pointer
+ * sg[1] holds the Output buffer pointer (configured before TX request)
+ */
+ sg_dma_address(&sg[0]) = info->fix.smem_start;
+ sg_set_page(&sg[0], virt_to_page(info->screen_base),
+ info->fix.smem_len, offset_in_page(info->screen_base));
+
+ fb_data->order_cnt = 0;
+ fb_data->waiting_for_wb = false;
+ fb_data->waiting_for_lut = false;
+ fb_data->waiting_for_lut15 = false;
+ fb_data->waiting_for_idle = false;
+ fb_data->blank = FB_BLANK_UNBLANK;
+ fb_data->power_state = POWER_STATE_OFF;
+ fb_data->powering_down = false;
+ fb_data->wait_for_powerdown = false;
+ fb_data->updates_active = false;
+ fb_data->pwrdown_delay = 0;
+
+ /* Register FB */
+ ret = register_framebuffer(info);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "register_framebuffer failed with error %d\n", ret);
+ goto out_lutmap;
+ }
+
+ g_fb_data = fb_data;
+
+ pm_runtime_enable(fb_data->dev);
+
+#ifdef DEFAULT_PANEL_HW_INIT
+ ret = mxc_epdc_fb_init_hw((struct fb_info *)fb_data);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to initialize HW!\n");
+ }
+#endif
+
+ goto out;
+
+out_lutmap:
+ kfree(fb_data->pxp_conf.proc_data.lut_map);
+out_dma_work_buf:
+ dma_free_writecombine(&pdev->dev, fb_data->working_buffer_size,
+ fb_data->working_buffer_virt, fb_data->working_buffer_phys);
+out_copybuffer:
+ dma_free_writecombine(&pdev->dev, fb_data->max_pix_size*2,
+ fb_data->virt_addr_copybuf,
+ fb_data->phys_addr_copybuf);
+out_upd_buffers:
+ for (i = 0; i < fb_data->max_num_buffers; i++)
+ if (fb_data->virt_addr_updbuf[i] != NULL)
+ kfree(fb_data->virt_addr_updbuf[i]);
+ if (fb_data->virt_addr_updbuf != NULL)
+ kfree(fb_data->virt_addr_updbuf);
+ if (fb_data->phys_addr_updbuf != NULL)
+ kfree(fb_data->phys_addr_updbuf);
+out_upd_lists:
+ list_for_each_entry_safe(plist, temp_list, &fb_data->upd_buf_free_list,
+ list) {
+ list_del(&plist->list);
+ kfree(plist);
+ }
+out_dma_fb:
+ dma_free_writecombine(&pdev->dev, fb_data->map_size, info->screen_base,
+ fb_data->phys_start);
+
+out_cmap:
+ fb_dealloc_cmap(&info->cmap);
+out_fbdata:
+ kfree(fb_data);
+out:
+ return ret;
+}
+
+static int mxc_epdc_fb_remove(struct platform_device *pdev)
+{
+ struct update_data_list *plist, *temp_list;
+ struct mxc_epdc_fb_data *fb_data = platform_get_drvdata(pdev);
+ int i;
+
+ mxc_epdc_fb_blank(FB_BLANK_POWERDOWN, &fb_data->info);
+
+ flush_workqueue(fb_data->epdc_submit_workqueue);
+ destroy_workqueue(fb_data->epdc_submit_workqueue);
+
+ unregister_framebuffer(&fb_data->info);
+
+ for (i = 0; i < fb_data->max_num_buffers; i++)
+ if (fb_data->virt_addr_updbuf[i] != NULL)
+ kfree(fb_data->virt_addr_updbuf[i]);
+ if (fb_data->virt_addr_updbuf != NULL)
+ kfree(fb_data->virt_addr_updbuf);
+ if (fb_data->phys_addr_updbuf != NULL)
+ kfree(fb_data->phys_addr_updbuf);
+
+ dma_free_writecombine(&pdev->dev, fb_data->working_buffer_size,
+ fb_data->working_buffer_virt,
+ fb_data->working_buffer_phys);
+ if (fb_data->waveform_buffer_virt != NULL)
+ dma_free_writecombine(&pdev->dev, fb_data->waveform_buffer_size,
+ fb_data->waveform_buffer_virt,
+ fb_data->waveform_buffer_phys);
+ if (fb_data->virt_addr_copybuf != NULL)
+ dma_free_writecombine(&pdev->dev, fb_data->max_pix_size*2,
+ fb_data->virt_addr_copybuf,
+ fb_data->phys_addr_copybuf);
+ list_for_each_entry_safe(plist, temp_list, &fb_data->upd_buf_free_list,
+ list) {
+ list_del(&plist->list);
+ kfree(plist);
+ }
+#ifdef CONFIG_FB_MXC_EINK_AUTO_UPDATE_MODE
+ fb_deferred_io_cleanup(&fb_data->info);
+#endif
+
+ dma_free_writecombine(&pdev->dev, fb_data->map_size, fb_data->info.screen_base,
+ fb_data->phys_start);
+
+ /* Release PxP-related resources */
+ if (fb_data->pxp_chan != NULL)
+ dma_release_channel(&fb_data->pxp_chan->dma_chan);
+
+ fb_dealloc_cmap(&fb_data->info.cmap);
+
+ framebuffer_release(&fb_data->info);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mxc_epdc_fb_suspend(struct device *dev)
+{
+ struct mxc_epdc_fb_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ data->pwrdown_delay = FB_POWERDOWN_DISABLE;
+ ret = mxc_epdc_fb_blank(FB_BLANK_POWERDOWN, &data->info);
+ if (ret)
+ goto out;
+
+out:
+ return ret;
+}
+
+static int mxc_epdc_fb_resume(struct device *dev)
+{
+ struct mxc_epdc_fb_data *data = dev_get_drvdata(dev);
+
+ mxc_epdc_fb_blank(FB_BLANK_UNBLANK, &data->info);
+ epdc_init_settings(data);
+ data->updates_active = false;
+
+ return 0;
+}
+#else
+#define mxc_epdc_fb_suspend NULL
+#define mxc_epdc_fb_resume NULL
+#endif
+
+#ifdef CONFIG_PM
+static int mxc_epdc_fb_runtime_suspend(struct device *dev)
+{
+ release_bus_freq(BUS_FREQ_HIGH);
+ dev_dbg(dev, "epdc busfreq high release.\n");
+
+ return 0;
+}
+
+static int mxc_epdc_fb_runtime_resume(struct device *dev)
+{
+ request_bus_freq(BUS_FREQ_HIGH);
+ dev_dbg(dev, "epdc busfreq high request.\n");
+
+ return 0;
+}
+#else
+#define mxc_epdc_fb_runtime_suspend NULL
+#define mxc_epdc_fb_runtime_resume NULL
+#endif
+
+static const struct dev_pm_ops mxc_epdc_fb_pm_ops = {
+ SET_RUNTIME_PM_OPS(mxc_epdc_fb_runtime_suspend,
+ mxc_epdc_fb_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(mxc_epdc_fb_suspend, mxc_epdc_fb_resume)
+};
+
+static void mxc_epdc_fb_shutdown(struct platform_device *pdev)
+{
+ struct mxc_epdc_fb_data *fb_data = platform_get_drvdata(pdev);
+
+ /* Disable power to the EPD panel */
+ if (regulator_is_enabled(fb_data->vcom_regulator))
+ regulator_disable(fb_data->vcom_regulator);
+ if (regulator_is_enabled(fb_data->display_regulator))
+ regulator_disable(fb_data->display_regulator);
+
+ /* Disable clocks to EPDC */
+ clk_prepare_enable(fb_data->epdc_clk_axi);
+ clk_prepare_enable(fb_data->epdc_clk_pix);
+ __raw_writel(EPDC_CTRL_CLKGATE, EPDC_CTRL_SET);
+ clk_disable_unprepare(fb_data->epdc_clk_pix);
+ clk_disable_unprepare(fb_data->epdc_clk_axi);
+
+ /* turn off the V3p3 */
+ if (regulator_is_enabled(fb_data->v3p3_regulator))
+ regulator_disable(fb_data->v3p3_regulator);
+}
+
+static struct platform_driver mxc_epdc_fb_driver = {
+ .probe = mxc_epdc_fb_probe,
+ .remove = mxc_epdc_fb_remove,
+ .shutdown = mxc_epdc_fb_shutdown,
+ .driver = {
+ .name = "imx_epdc_fb",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(imx_epdc_dt_ids),
+ .pm = &mxc_epdc_fb_pm_ops,
+ },
+};
+
+/* Callback function triggered after PxP receives an EOF interrupt */
+static void pxp_dma_done(void *arg)
+{
+ struct pxp_tx_desc *tx_desc = to_tx_desc(arg);
+ struct dma_chan *chan = tx_desc->txd.chan;
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+ struct mxc_epdc_fb_data *fb_data = pxp_chan->client;
+
+ /* This call will signal wait_for_completion_timeout() in send_buffer_to_pxp */
+ complete(&fb_data->pxp_tx_cmpl);
+}
+
+static bool chan_filter(struct dma_chan *chan, void *arg)
+{
+ if (imx_dma_is_pxp(chan))
+ return true;
+ else
+ return false;
+}
+
+/* Function to request PXP DMA channel */
+static int pxp_chan_init(struct mxc_epdc_fb_data *fb_data)
+{
+ dma_cap_mask_t mask;
+ struct dma_chan *chan;
+
+ /*
+ * Request a free channel
+ */
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_PRIVATE, mask);
+ chan = dma_request_channel(mask, chan_filter, NULL);
+ if (!chan) {
+ dev_err(fb_data->dev, "Unsuccessfully received channel!!!!\n");
+ return -EBUSY;
+ }
+
+ fb_data->pxp_chan = to_pxp_channel(chan);
+ fb_data->pxp_chan->client = fb_data;
+
+ init_completion(&fb_data->pxp_tx_cmpl);
+
+ return 0;
+}
+
+/*
+ * Function to call PxP DMA driver and send our latest FB update region
+ * through the PxP and out to an intermediate buffer.
+ * Note: This is a blocking call, so upon return the PxP tx should be complete.
+ */
+static int pxp_process_update(struct mxc_epdc_fb_data *fb_data,
+ u32 src_width, u32 src_height,
+ struct mxcfb_rect *update_region)
+{
+ dma_cookie_t cookie;
+ struct scatterlist *sg = fb_data->sg;
+ struct dma_chan *dma_chan;
+ struct pxp_tx_desc *desc;
+ struct dma_async_tx_descriptor *txd;
+ struct pxp_config_data *pxp_conf = &fb_data->pxp_conf;
+ struct pxp_proc_data *proc_data = &fb_data->pxp_conf.proc_data;
+ int i, ret;
+ int length;
+
+ dev_dbg(fb_data->dev, "Starting PxP Send Buffer\n");
+
+ /* First, check to see that we have acquired a PxP Channel object */
+ if (fb_data->pxp_chan == NULL) {
+ /*
+ * PxP Channel has not yet been created and initialized,
+ * so let's go ahead and try
+ */
+ ret = pxp_chan_init(fb_data);
+ if (ret) {
+ /*
+ * PxP channel init failed, and we can't use the
+ * PxP until the PxP DMA driver has loaded, so we abort
+ */
+ dev_err(fb_data->dev, "PxP chan init failed\n");
+ return -ENODEV;
+ }
+ }
+
+ /*
+ * Init completion, so that we
+ * can be properly informed of the completion
+ * of the PxP task when it is done.
+ */
+ init_completion(&fb_data->pxp_tx_cmpl);
+
+ dma_chan = &fb_data->pxp_chan->dma_chan;
+
+ txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg, 2,
+ DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT,
+ NULL);
+ if (!txd) {
+ dev_err(fb_data->info.device,
+ "Error preparing a DMA transaction descriptor.\n");
+ return -EIO;
+ }
+
+ txd->callback_param = txd;
+ txd->callback = pxp_dma_done;
+
+ /*
+ * Configure PxP for processing of new update region
+ * The rest of our config params were set up in
+ * probe() and should not need to be changed.
+ */
+ pxp_conf->s0_param.width = src_width;
+ pxp_conf->s0_param.height = src_height;
+ proc_data->srect.top = update_region->top;
+ proc_data->srect.left = update_region->left;
+ proc_data->srect.width = update_region->width;
+ proc_data->srect.height = update_region->height;
+
+ /*
+ * Because only YUV/YCbCr image can be scaled, configure
+ * drect equivalent to srect, as such do not perform scaling.
+ */
+ proc_data->drect.top = 0;
+ proc_data->drect.left = 0;
+
+ /* PXP expects rotation in terms of degrees */
+ proc_data->rotate = fb_data->epdc_fb_var.rotate * 90;
+ if (proc_data->rotate > 270)
+ proc_data->rotate = 0;
+
+ /* Just as V4L2 PXP, we should pass the rotated values to PXP */
+ if ((proc_data->rotate == 90) || (proc_data->rotate == 270)) {
+ proc_data->drect.width = proc_data->srect.height;
+ proc_data->drect.height = proc_data->srect.width;
+ pxp_conf->out_param.width = update_region->height;
+ pxp_conf->out_param.height = update_region->width;
+ pxp_conf->out_param.stride = update_region->height;
+ } else {
+ proc_data->drect.width = proc_data->srect.width;
+ proc_data->drect.height = proc_data->srect.height;
+ pxp_conf->out_param.width = update_region->width;
+ pxp_conf->out_param.height = update_region->height;
+ pxp_conf->out_param.stride = update_region->width;
+ }
+
+ /* For EPDC v2.0, we need output to be 64-bit
+ * aligned since EPDC stride does not work. */
+ if (fb_data->rev <= 20)
+ pxp_conf->out_param.stride = ALIGN(pxp_conf->out_param.stride, 8);
+
+
+ desc = to_tx_desc(txd);
+ length = desc->len;
+ for (i = 0; i < length; i++) {
+ if (i == 0) {/* S0 */
+ memcpy(&desc->proc_data, proc_data, sizeof(struct pxp_proc_data));
+ pxp_conf->s0_param.paddr = sg_dma_address(&sg[0]);
+ memcpy(&desc->layer_param.s0_param, &pxp_conf->s0_param,
+ sizeof(struct pxp_layer_param));
+ } else if (i == 1) {
+ pxp_conf->out_param.paddr = sg_dma_address(&sg[1]);
+ memcpy(&desc->layer_param.out_param, &pxp_conf->out_param,
+ sizeof(struct pxp_layer_param));
+ }
+ /* TODO: OverLay */
+
+ desc = desc->next;
+ }
+
+ /* Submitting our TX starts the PxP processing task */
+ cookie = txd->tx_submit(txd);
+ if (cookie < 0) {
+ dev_err(fb_data->info.device, "Error sending FB through PxP\n");
+ return -EIO;
+ }
+
+ fb_data->txd = txd;
+
+ /* trigger ePxP */
+ dma_async_issue_pending(dma_chan);
+
+ return 0;
+}
+
+static int pxp_complete_update(struct mxc_epdc_fb_data *fb_data, u32 *hist_stat)
+{
+ int ret;
+ /*
+ * Wait for completion event, which will be set
+ * through our TX callback function.
+ */
+ ret = wait_for_completion_timeout(&fb_data->pxp_tx_cmpl, HZ / 10);
+ if (ret <= 0) {
+ dev_info(fb_data->info.device,
+ "PxP operation failed due to %s\n",
+ ret < 0 ? "user interrupt" : "timeout");
+ dma_release_channel(&fb_data->pxp_chan->dma_chan);
+ fb_data->pxp_chan = NULL;
+ return ret ? : -ETIMEDOUT;
+ }
+
+ if ((fb_data->pxp_conf.proc_data.lut_transform & EPDC_FLAG_USE_CMAP) &&
+ fb_data->pxp_conf.proc_data.lut_map_updated)
+ fb_data->pxp_conf.proc_data.lut_map_updated = false;
+
+ *hist_stat = to_tx_desc(fb_data->txd)->hist_status;
+ dma_release_channel(&fb_data->pxp_chan->dma_chan);
+ fb_data->pxp_chan = NULL;
+
+ dev_dbg(fb_data->dev, "TX completed\n");
+
+ return 0;
+}
+
+/*
+ * Different dithering algorithm can be used. We chose
+ * to implement Bill Atkinson's algorithm as an example
+ * Thanks Bill Atkinson for his dithering algorithm.
+ */
+
+/*
+ * Dithering algorithm implementation - Y8->Y1 version 1.0 for i.MX
+ */
+static void do_dithering_processing_Y1_v1_0(
+ unsigned char *update_region_virt_ptr,
+ dma_addr_t update_region_phys_ptr,
+ struct mxcfb_rect *update_region,
+ unsigned long update_region_stride,
+ int *err_dist)
+{
+
+ /* create a temp error distribution array */
+ int bwPix;
+ int y;
+ int col;
+ int *err_dist_l0, *err_dist_l1, *err_dist_l2, distrib_error;
+ int width_3 = update_region->width + 3;
+ char *y8buf;
+ int x_offset = 0;
+
+ /* prime a few elements the error distribution array */
+ for (y = 0; y < update_region->height; y++) {
+ /* Dithering the Y8 in sbuf to BW suitable for A2 waveform */
+ err_dist_l0 = err_dist + (width_3) * (y % 3);
+ err_dist_l1 = err_dist + (width_3) * ((y + 1) % 3);
+ err_dist_l2 = err_dist + (width_3) * ((y + 2) % 3);
+
+ y8buf = update_region_virt_ptr + x_offset;
+
+ /* scan the line and convert the Y8 to BW */
+ for (col = 1; col <= update_region->width; col++) {
+ bwPix = *(err_dist_l0 + col) + *y8buf;
+
+ if (bwPix >= 128) {
+ *y8buf++ = 0xff;
+ distrib_error = (bwPix - 255) >> 3;
+ } else {
+ *y8buf++ = 0;
+ distrib_error = bwPix >> 3;
+ }
+
+ /* modify the error distribution buffer */
+ *(err_dist_l0 + col + 2) += distrib_error;
+ *(err_dist_l1 + col + 1) += distrib_error;
+ *(err_dist_l0 + col + 1) += distrib_error;
+ *(err_dist_l1 + col - 1) += distrib_error;
+ *(err_dist_l1 + col) += distrib_error;
+ *(err_dist_l2 + col) = distrib_error;
+ }
+ x_offset += update_region_stride;
+ }
+
+ flush_cache_all();
+ outer_flush_range(update_region_phys_ptr, update_region_phys_ptr +
+ update_region->height * update_region->width);
+}
+
+/*
+ * Dithering algorithm implementation - Y8->Y4 version 1.0 for i.MX
+ */
+
+static void do_dithering_processing_Y4_v1_0(
+ unsigned char *update_region_virt_ptr,
+ dma_addr_t update_region_phys_ptr,
+ struct mxcfb_rect *update_region,
+ unsigned long update_region_stride,
+ int *err_dist)
+{
+
+ /* create a temp error distribution array */
+ int gcPix;
+ int y;
+ int col;
+ int *err_dist_l0, *err_dist_l1, *err_dist_l2, distrib_error;
+ int width_3 = update_region->width + 3;
+ char *y8buf;
+ int x_offset = 0;
+
+ /* prime a few elements the error distribution array */
+ for (y = 0; y < update_region->height; y++) {
+ /* Dithering the Y8 in sbuf to Y4 */
+ err_dist_l0 = err_dist + (width_3) * (y % 3);
+ err_dist_l1 = err_dist + (width_3) * ((y + 1) % 3);
+ err_dist_l2 = err_dist + (width_3) * ((y + 2) % 3);
+
+ y8buf = update_region_virt_ptr + x_offset;
+
+ /* scan the line and convert the Y8 to Y4 */
+ for (col = 1; col <= update_region->width; col++) {
+ gcPix = *(err_dist_l0 + col) + *y8buf;
+
+ if (gcPix > 255)
+ gcPix = 255;
+ else if (gcPix < 0)
+ gcPix = 0;
+
+ distrib_error = (*y8buf - (gcPix & 0xf0)) >> 3;
+
+ *y8buf++ = gcPix & 0xf0;
+
+ /* modify the error distribution buffer */
+ *(err_dist_l0 + col + 2) += distrib_error;
+ *(err_dist_l1 + col + 1) += distrib_error;
+ *(err_dist_l0 + col + 1) += distrib_error;
+ *(err_dist_l1 + col - 1) += distrib_error;
+ *(err_dist_l1 + col) += distrib_error;
+ *(err_dist_l2 + col) = distrib_error;
+ }
+ x_offset += update_region_stride;
+ }
+
+ flush_cache_all();
+ outer_flush_range(update_region_phys_ptr, update_region_phys_ptr +
+ update_region->height * update_region->width);
+}
+
+static int __init mxc_epdc_fb_init(void)
+{
+ return platform_driver_register(&mxc_epdc_fb_driver);
+}
+late_initcall(mxc_epdc_fb_init);
+
+static void __exit mxc_epdc_fb_exit(void)
+{
+ platform_driver_unregister(&mxc_epdc_fb_driver);
+}
+module_exit(mxc_epdc_fb_exit);
+
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC EPDC framebuffer driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("fb");
diff --git a/drivers/video/fbdev/mxc/mxc_epdc_v2_fb.c b/drivers/video/fbdev/mxc/mxc_epdc_v2_fb.c
new file mode 100644
index 000000000000..b908ad79689e
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mxc_epdc_v2_fb.c
@@ -0,0 +1,6833 @@
+/*
+ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * Copyright 2017 NXP
+ *
+ * This program is free software; 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
+ *
+ */
+/*
+ * Based on STMP378X LCDIF
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+#include <linux/busfreq-imx.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/uaccess.h>
+#include <linux/cpufreq.h>
+#include <linux/firmware.h>
+#include <linux/kthread.h>
+#include <linux/dmaengine.h>
+#include <linux/pxp_dma.h>
+#include <linux/pm_runtime.h>
+#include <linux/mxcfb.h>
+#include <linux/mxcfb_epdc.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/max17135.h>
+#include <linux/fsl_devices.h>
+#include <linux/bitops.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_data/dma-imx.h>
+#include <asm/cacheflush.h>
+
+#include "epdc_v2_regs.h"
+
+#define EPDC_STANDARD_MODE
+
+#define USE_PS_AS_OUTPUT
+
+/*
+ * Enable this define to have a default panel
+ * loaded during driver initialization
+ */
+/*#define DEFAULT_PANEL_HW_INIT*/
+
+#define SG_NUM 14 /* 2+4+4+4 */
+#define NUM_SCREENS_MIN 2
+
+#define EPDC_V1_NUM_LUTS 16
+#define EPDC_V1_MAX_NUM_UPDATES 20
+#define EPDC_V2_NUM_LUTS 64
+#define EPDC_V2_MAX_NUM_UPDATES 64
+#define EPDC_MAX_NUM_BUFFERS 2
+#define INVALID_LUT (-1)
+#define DRY_RUN_NO_LUT 100
+
+/* Maximum update buffer image width due to v2.0 and v2.1 errata ERR005313. */
+#define EPDC_V2_MAX_UPDATE_WIDTH 2047
+#define EPDC_V2_ROTATION_ALIGNMENT 8
+
+#define DEFAULT_TEMP_INDEX 0
+#define DEFAULT_TEMP 20 /* room temp in deg Celsius */
+
+#define INIT_UPDATE_MARKER 0x12345678
+#define PAN_UPDATE_MARKER 0x12345679
+
+#define POWER_STATE_OFF 0
+#define POWER_STATE_ON 1
+
+#define MERGE_OK 0
+#define MERGE_FAIL 1
+#define MERGE_BLOCK 2
+
+static u64 used_luts = 0x1; /* do not use LUT0 */
+static unsigned long default_bpp = 16;
+
+struct update_marker_data {
+ struct list_head full_list;
+ struct list_head upd_list;
+ u32 update_marker;
+ struct completion update_completion;
+ int lut_num;
+ bool collision_test;
+ bool waiting;
+};
+
+struct update_desc_list {
+ struct list_head list;
+ struct mxcfb_update_data upd_data;/* Update parameters */
+ u32 epdc_offs; /* Added to buffer ptr to resolve alignment */
+ u32 epdc_stride; /* Depends on rotation & whether we skip PxP */
+ struct list_head upd_marker_list; /* List of markers for this update */
+ u32 update_order; /* Numeric ordering value for update */
+};
+
+/* This structure represents a list node containing both
+ * a memory region allocated as an output buffer for the PxP
+ * update processing task, and the update description (mode, region, etc.) */
+struct update_data_list {
+ struct list_head list;
+ dma_addr_t phys_addr; /* Pointer to phys address of processed Y buf */
+ void *virt_addr;
+ struct update_desc_list *update_desc;
+ int lut_num; /* Assigned before update is processed into working buffer */
+ u64 collision_mask; /* Set when update creates collision */
+ /* Mask of the LUTs the update collides with */
+};
+
+struct mxc_epdc_fb_data {
+ struct fb_info info;
+ struct fb_var_screeninfo epdc_fb_var; /* Internal copy of screeninfo
+ so we can sync changes to it */
+ u32 pseudo_palette[16];
+ char fw_str[24];
+ struct list_head list;
+ struct imx_epdc_fb_mode *cur_mode;
+ struct imx_epdc_fb_platform_data *pdata;
+ int blank;
+ u32 max_pix_size;
+ ssize_t map_size;
+ dma_addr_t phys_start;
+ void *virt_start;
+ u32 fb_offset;
+ int default_bpp;
+ int native_width;
+ int native_height;
+ int num_screens;
+ int epdc_irq;
+ struct device *dev;
+ int power_state;
+ int wait_for_powerdown;
+ struct completion powerdown_compl;
+ struct clk *epdc_clk_axi;
+ struct clk *epdc_clk_pix;
+ struct regulator *display_regulator;
+ struct regulator *vcom_regulator;
+ struct regulator *v3p3_regulator;
+ bool fw_default_load;
+ int rev;
+
+ /* FB elements related to EPDC updates */
+ int num_luts;
+ int max_num_updates;
+ bool in_init;
+ bool hw_ready;
+ bool hw_initializing;
+ bool waiting_for_idle;
+ u32 auto_mode;
+ u32 upd_scheme;
+ struct list_head upd_pending_list;
+ struct list_head upd_buf_queue;
+ struct list_head upd_buf_free_list;
+ struct list_head upd_buf_collision_list;
+ struct update_data_list *cur_update;
+ struct mutex queue_mutex;
+ int trt_entries;
+ int temp_index;
+ u8 *temp_range_bounds;
+ struct mxcfb_waveform_modes wv_modes;
+ bool wv_modes_update;
+ bool waveform_is_advanced;
+ u32 *waveform_buffer_virt;
+ u32 waveform_buffer_phys;
+ u32 waveform_buffer_size;
+ u32 *working_buffer_virt;
+ u32 working_buffer_phys;
+ u32 working_buffer_size;
+ u32 *tmp_working_buffer_virt;
+ u32 tmp_working_buffer_phys;
+ dma_addr_t *phys_addr_updbuf;
+ void **virt_addr_updbuf;
+ u32 upd_buffer_num;
+ u32 max_num_buffers;
+ dma_addr_t phys_addr_copybuf; /* Phys address of copied update data */
+ void *virt_addr_copybuf; /* Used for PxP SW workaround */
+ dma_addr_t phys_addr_y4;
+ void *virt_addr_y4;
+ dma_addr_t phys_addr_y4c;
+ void *virt_addr_y4c;
+ dma_addr_t phys_addr_black;
+ void *virt_addr_black;
+ u32 order_cnt;
+ struct list_head full_marker_list;
+ u32 *lut_update_order; /* Array size = number of luts */
+ u64 epdc_colliding_luts;
+ u64 luts_complete_wb;
+ u64 luts_complete;
+ struct completion updates_done;
+ struct delayed_work epdc_done_work;
+ struct workqueue_struct *epdc_submit_workqueue;
+ struct work_struct epdc_submit_work;
+ struct workqueue_struct *epdc_intr_workqueue;
+ struct work_struct epdc_intr_work;
+ bool waiting_for_wb;
+ bool waiting_for_lut;
+ bool waiting_for_lut15;
+ struct completion update_res_free;
+ struct completion lut15_free;
+ struct completion eof_event;
+ int eof_sync_period;
+ struct mutex power_mutex;
+ bool powering_down;
+ bool updates_active;
+ int pwrdown_delay;
+ unsigned long tce_prevent;
+ bool restrict_width; /* work around rev >=2.0 width and
+ stride restriction */
+
+ /* FB elements related to PxP DMA */
+ struct completion pxp_tx_cmpl;
+ struct pxp_channel *pxp_chan;
+ struct pxp_config_data pxp_conf;
+ struct dma_async_tx_descriptor *txd;
+ dma_cookie_t cookie;
+ struct scatterlist sg[SG_NUM];
+ struct mutex pxp_mutex; /* protects access to PxP */
+
+ /* external mode or internal mode */
+ int epdc_wb_mode;
+ struct pxp_collision_info col_info;
+ u32 hist_status;
+
+ struct regmap *gpr;
+ u8 req_gpr;
+ u8 req_bit;
+};
+
+struct waveform_data_header {
+ unsigned int wi0;
+ unsigned int wi1;
+ unsigned int wi2;
+ unsigned int wi3;
+ unsigned int wi4;
+ unsigned int wi5;
+ unsigned int wi6;
+ unsigned int xwia:24;
+ unsigned int cs1:8;
+ unsigned int wmta:24;
+ unsigned int fvsn:8;
+ unsigned int luts:8;
+ unsigned int mc:8;
+ unsigned int trc:8;
+ unsigned int reserved0_0:8;
+ unsigned int eb:8;
+ unsigned int sb:8;
+ unsigned int reserved0_1:8;
+ unsigned int reserved0_2:8;
+ unsigned int reserved0_3:8;
+ unsigned int reserved0_4:8;
+ unsigned int reserved0_5:8;
+ unsigned int cs2:8;
+};
+
+struct mxcfb_waveform_data_file {
+ struct waveform_data_header wdh;
+ u32 *data; /* Temperature Range Table + Waveform Data */
+};
+
+#define WAVEFORM_HDR_LUT_ADVANCED_ALGO_MASK 0xc
+
+static struct fb_videomode ed060xh2c1mode = {
+ .name = "ED060XH2C1",
+ .refresh = 85,
+ .xres = 1024,
+ .yres = 758,
+ .pixclock = 40000000,
+ .left_margin = 12,
+ .right_margin = 76,
+ .upper_margin = 4,
+ .lower_margin = 5,
+ .hsync_len = 12,
+ .vsync_len = 2,
+ .sync = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .flag = 0,
+};
+
+static struct fb_videomode e60_v110_mode = {
+ .name = "E60_V110",
+ .refresh = 50,
+ .xres = 800,
+ .yres = 600,
+ .pixclock = 18604700,
+ .left_margin = 8,
+ .right_margin = 178,
+ .upper_margin = 4,
+ .lower_margin = 10,
+ .hsync_len = 20,
+ .vsync_len = 4,
+ .sync = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .flag = 0,
+};
+
+static struct fb_videomode e60_v220_mode = {
+ .name = "E60_V220",
+ .refresh = 85,
+ .xres = 800,
+ .yres = 600,
+ .pixclock = 30000000,
+ .left_margin = 8,
+ .right_margin = 164,
+ .upper_margin = 4,
+ .lower_margin = 8,
+ .hsync_len = 4,
+ .vsync_len = 1,
+ .sync = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .flag = 0,
+};
+
+static struct fb_videomode e060scm_mode = {
+ .name = "E060SCM",
+ .refresh = 85,
+ .xres = 800,
+ .yres = 600,
+ .pixclock = 26666667,
+ .left_margin = 8,
+ .right_margin = 100,
+ .upper_margin = 4,
+ .lower_margin = 8,
+ .hsync_len = 4,
+ .vsync_len = 1,
+ .sync = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .flag = 0,
+};
+
+static struct fb_videomode e97_v110_mode = {
+ .name = "E97_V110",
+ .refresh = 50,
+ .xres = 1200,
+ .yres = 825,
+ .pixclock = 32000000,
+ .left_margin = 12,
+ .right_margin = 128,
+ .upper_margin = 4,
+ .lower_margin = 10,
+ .hsync_len = 20,
+ .vsync_len = 4,
+ .sync = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .flag = 0,
+};
+
+static struct imx_epdc_fb_mode panel_modes[] = {
+ {
+ &ed060xh2c1mode, /* struct fb_videomode *mode */
+ 4, /* vscan_holdoff */
+ 10, /* sdoed_width */
+ 20, /* sdoed_delay */
+ 10, /* sdoez_width */
+ 20, /* sdoez_delay */
+ 524, /* GDCLK_HP */
+ 327, /* GDSP_OFF */
+ 0, /* GDOE_OFF */
+ 19, /* gdclk_offs */
+ 1, /* num_ce */
+ },
+ {
+ &e60_v110_mode,
+ 4, /* vscan_holdoff */
+ 10, /* sdoed_width */
+ 20, /* sdoed_delay */
+ 10, /* sdoez_width */
+ 20, /* sdoez_delay */
+ 428, /* gdclk_hp_offs */
+ 20, /* gdsp_offs */
+ 0, /* gdoe_offs */
+ 1, /* gdclk_offs */
+ 1, /* num_ce */
+ },
+ {
+ &e60_v220_mode,
+ 4, /* vscan_holdoff */
+ 10, /* sdoed_width */
+ 20, /* sdoed_delay */
+ 10, /* sdoez_width */
+ 20, /* sdoez_delay */
+ 465, /* gdclk_hp_offs */
+ 20, /* gdsp_offs */
+ 0, /* gdoe_offs */
+ 9, /* gdclk_offs */
+ 1, /* num_ce */
+ },
+ {
+ &e060scm_mode,
+ 4, /* vscan_holdoff */
+ 10, /* sdoed_width */
+ 20, /* sdoed_delay */
+ 10, /* sdoez_width */
+ 20, /* sdoez_delay */
+ 419, /* gdclk_hp_offs */
+ 263, /* gdsp_offs */
+ 0, /* gdoe_offs */
+ 5, /* gdclk_offs */
+ 1, /* num_ce */
+ },
+ {
+ &e97_v110_mode,
+ 8, /* vscan_holdoff */
+ 10, /* sdoed_width */
+ 20, /* sdoed_delay */
+ 10, /* sdoez_width */
+ 20, /* sdoez_delay */
+ 632, /* gdclk_hp_offs */
+ 20, /* gdsp_offs */
+ 0, /* gdoe_offs */
+ 1, /* gdclk_offs */
+ 3, /* num_ce */
+ }
+};
+
+static struct imx_epdc_fb_platform_data epdc_data = {
+ .epdc_mode = panel_modes,
+ .num_modes = ARRAY_SIZE(panel_modes),
+};
+
+void __iomem *epdc_v2_base;
+
+static struct mxc_epdc_fb_data *g_fb_data;
+
+/* forward declaration */
+static int mxc_epdc_fb_get_temp_index(struct mxc_epdc_fb_data *fb_data,
+ int temp);
+static void mxc_epdc_fb_flush_updates(struct mxc_epdc_fb_data *fb_data);
+static int mxc_epdc_fb_blank(int blank, struct fb_info *info);
+static int mxc_epdc_fb_init_hw(struct fb_info *info);
+static int pxp_legacy_process(struct mxc_epdc_fb_data *fb_data,
+ u32 src_width, u32 src_height,
+ struct mxcfb_rect *update_region);
+static int pxp_process_dithering(struct mxc_epdc_fb_data *fb_data,
+ struct mxcfb_rect *update_region);
+static int pxp_wfe_a_process(struct mxc_epdc_fb_data *fb_data,
+ struct mxcfb_rect *update_region,
+ struct update_data_list *upd_data_list);
+static int pxp_wfe_b_process_update(struct mxc_epdc_fb_data *fb_data,
+ struct mxcfb_rect *update_region);
+static int pxp_wfe_a_process_clear_workingbuffer(struct mxc_epdc_fb_data *fb_data,
+ u32 src_width, u32 src_height);
+static int pxp_complete_update(struct mxc_epdc_fb_data *fb_data, u32 *hist_stat);
+
+static void draw_mode0(struct mxc_epdc_fb_data *fb_data);
+static bool is_free_list_full(struct mxc_epdc_fb_data *fb_data);
+
+static void do_dithering_processing_Y1_v1_0(
+ unsigned char *update_region_virt_ptr,
+ dma_addr_t update_region_phys_ptr,
+ struct mxcfb_rect *update_region,
+ unsigned long update_region_stride,
+ int *err_dist);
+static void do_dithering_processing_Y4_v1_0(
+ unsigned char *update_region_virt_ptr,
+ dma_addr_t update_region_phys_ptr,
+ struct mxcfb_rect *update_region,
+ unsigned long update_region_stride,
+ int *err_dist);
+static inline void epdc_set_used_lut(u64 used_bit);
+static inline void epdc_reset_used_lut(void);
+static int pxp_clear_wb_work_func(struct mxc_epdc_fb_data *fb_data);
+static int epdc_working_buffer_update(struct mxc_epdc_fb_data *fb_data,
+ struct update_data_list *upd_data_list,
+ struct mxcfb_rect *update_region);
+extern void pxp_get_collision_info(struct pxp_collision_info *info);
+
+#ifdef DEBUG
+static void dump_pxp_config(struct mxc_epdc_fb_data *fb_data,
+ struct pxp_config_data *pxp_conf)
+{
+ dev_info(fb_data->dev, "S0 fmt 0x%x",
+ pxp_conf->s0_param.pixel_fmt);
+ dev_info(fb_data->dev, "S0 width 0x%x",
+ pxp_conf->s0_param.width);
+ dev_info(fb_data->dev, "S0 height 0x%x",
+ pxp_conf->s0_param.height);
+ dev_info(fb_data->dev, "S0 ckey 0x%x",
+ pxp_conf->s0_param.color_key);
+ dev_info(fb_data->dev, "S0 ckey en 0x%x",
+ pxp_conf->s0_param.color_key_enable);
+
+ dev_info(fb_data->dev, "OL0 combine en 0x%x",
+ pxp_conf->ol_param[0].combine_enable);
+ dev_info(fb_data->dev, "OL0 fmt 0x%x",
+ pxp_conf->ol_param[0].pixel_fmt);
+ dev_info(fb_data->dev, "OL0 width 0x%x",
+ pxp_conf->ol_param[0].width);
+ dev_info(fb_data->dev, "OL0 height 0x%x",
+ pxp_conf->ol_param[0].height);
+ dev_info(fb_data->dev, "OL0 ckey 0x%x",
+ pxp_conf->ol_param[0].color_key);
+ dev_info(fb_data->dev, "OL0 ckey en 0x%x",
+ pxp_conf->ol_param[0].color_key_enable);
+ dev_info(fb_data->dev, "OL0 alpha 0x%x",
+ pxp_conf->ol_param[0].global_alpha);
+ dev_info(fb_data->dev, "OL0 alpha en 0x%x",
+ pxp_conf->ol_param[0].global_alpha_enable);
+ dev_info(fb_data->dev, "OL0 local alpha en 0x%x",
+ pxp_conf->ol_param[0].local_alpha_enable);
+
+ dev_info(fb_data->dev, "Out fmt 0x%x",
+ pxp_conf->out_param.pixel_fmt);
+ dev_info(fb_data->dev, "Out width 0x%x",
+ pxp_conf->out_param.width);
+ dev_info(fb_data->dev, "Out height 0x%x",
+ pxp_conf->out_param.height);
+
+ dev_info(fb_data->dev,
+ "drect left 0x%x right 0x%x width 0x%x height 0x%x",
+ pxp_conf->proc_data.drect.left, pxp_conf->proc_data.drect.top,
+ pxp_conf->proc_data.drect.width,
+ pxp_conf->proc_data.drect.height);
+ dev_info(fb_data->dev,
+ "srect left 0x%x right 0x%x width 0x%x height 0x%x",
+ pxp_conf->proc_data.srect.left, pxp_conf->proc_data.srect.top,
+ pxp_conf->proc_data.srect.width,
+ pxp_conf->proc_data.srect.height);
+ dev_info(fb_data->dev, "Scaling en 0x%x", pxp_conf->proc_data.scaling);
+ dev_info(fb_data->dev, "HFlip en 0x%x", pxp_conf->proc_data.hflip);
+ dev_info(fb_data->dev, "VFlip en 0x%x", pxp_conf->proc_data.vflip);
+ dev_info(fb_data->dev, "Rotation 0x%x", pxp_conf->proc_data.rotate);
+ dev_info(fb_data->dev, "BG Color 0x%x", pxp_conf->proc_data.bgcolor);
+}
+
+static void dump_epdc_reg(void)
+{
+ printk(KERN_DEBUG "\n\n");
+ printk(KERN_DEBUG "EPDC_CTRL 0x%x\n", __raw_readl(EPDC_CTRL));
+ printk(KERN_DEBUG "EPDC_WVADDR 0x%x\n", __raw_readl(EPDC_WVADDR));
+ printk(KERN_DEBUG "EPDC_WB_ADDR 0x%x\n", __raw_readl(EPDC_WB_ADDR));
+ printk(KERN_DEBUG "EPDC_RES 0x%x\n", __raw_readl(EPDC_RES));
+ printk(KERN_DEBUG "EPDC_FORMAT 0x%x\n", __raw_readl(EPDC_FORMAT));
+ printk(KERN_DEBUG "EPDC_FIFOCTRL 0x%x\n", __raw_readl(EPDC_FIFOCTRL));
+ printk(KERN_DEBUG "EPDC_UPD_ADDR 0x%x\n", __raw_readl(EPDC_UPD_ADDR));
+ printk(KERN_DEBUG "EPDC_UPD_STRIDE 0x%x\n", __raw_readl(EPDC_UPD_STRIDE));
+ printk(KERN_DEBUG "EPDC_UPD_FIXED 0x%x\n", __raw_readl(EPDC_UPD_FIXED));
+ printk(KERN_DEBUG "EPDC_UPD_CORD 0x%x\n", __raw_readl(EPDC_UPD_CORD));
+ printk(KERN_DEBUG "EPDC_UPD_SIZE 0x%x\n", __raw_readl(EPDC_UPD_SIZE));
+ printk(KERN_DEBUG "EPDC_UPD_CTRL 0x%x\n", __raw_readl(EPDC_UPD_CTRL));
+ printk(KERN_DEBUG "EPDC_TEMP 0x%x\n", __raw_readl(EPDC_TEMP));
+ printk(KERN_DEBUG "EPDC_AUTOWV_LUT 0x%x\n", __raw_readl(EPDC_AUTOWV_LUT));
+ printk(KERN_DEBUG "EPDC_TCE_CTRL 0x%x\n", __raw_readl(EPDC_TCE_CTRL));
+ printk(KERN_DEBUG "EPDC_TCE_SDCFG 0x%x\n", __raw_readl(EPDC_TCE_SDCFG));
+ printk(KERN_DEBUG "EPDC_TCE_GDCFG 0x%x\n", __raw_readl(EPDC_TCE_GDCFG));
+ printk(KERN_DEBUG "EPDC_TCE_HSCAN1 0x%x\n", __raw_readl(EPDC_TCE_HSCAN1));
+ printk(KERN_DEBUG "EPDC_TCE_HSCAN2 0x%x\n", __raw_readl(EPDC_TCE_HSCAN2));
+ printk(KERN_DEBUG "EPDC_TCE_VSCAN 0x%x\n", __raw_readl(EPDC_TCE_VSCAN));
+ printk(KERN_DEBUG "EPDC_TCE_OE 0x%x\n", __raw_readl(EPDC_TCE_OE));
+ printk(KERN_DEBUG "EPDC_TCE_POLARITY 0x%x\n", __raw_readl(EPDC_TCE_POLARITY));
+ printk(KERN_DEBUG "EPDC_TCE_TIMING1 0x%x\n", __raw_readl(EPDC_TCE_TIMING1));
+ printk(KERN_DEBUG "EPDC_TCE_TIMING2 0x%x\n", __raw_readl(EPDC_TCE_TIMING2));
+ printk(KERN_DEBUG "EPDC_TCE_TIMING3 0x%x\n", __raw_readl(EPDC_TCE_TIMING3));
+ printk(KERN_DEBUG "EPDC_PIGEON_CTRL0 0x%x\n", __raw_readl(EPDC_PIGEON_CTRL0));
+ printk(KERN_DEBUG "EPDC_PIGEON_CTRL1 0x%x\n", __raw_readl(EPDC_PIGEON_CTRL1));
+ printk(KERN_DEBUG "EPDC_IRQ_MASK1 0x%x\n", __raw_readl(EPDC_IRQ_MASK1));
+ printk(KERN_DEBUG "EPDC_IRQ_MASK2 0x%x\n", __raw_readl(EPDC_IRQ_MASK2));
+ printk(KERN_DEBUG "EPDC_IRQ1 0x%x\n", __raw_readl(EPDC_IRQ1));
+ printk(KERN_DEBUG "EPDC_IRQ2 0x%x\n", __raw_readl(EPDC_IRQ2));
+ printk(KERN_DEBUG "EPDC_IRQ_MASK 0x%x\n", __raw_readl(EPDC_IRQ_MASK));
+ printk(KERN_DEBUG "EPDC_IRQ 0x%x\n", __raw_readl(EPDC_IRQ));
+ printk(KERN_DEBUG "EPDC_STATUS_LUTS 0x%x\n", __raw_readl(EPDC_STATUS_LUTS));
+ printk(KERN_DEBUG "EPDC_STATUS_LUTS2 0x%x\n", __raw_readl(EPDC_STATUS_LUTS2));
+ printk(KERN_DEBUG "EPDC_STATUS_NEXTLUT 0x%x\n", __raw_readl(EPDC_STATUS_NEXTLUT));
+ printk(KERN_DEBUG "EPDC_STATUS_COL1 0x%x\n", __raw_readl(EPDC_STATUS_COL));
+ printk(KERN_DEBUG "EPDC_STATUS_COL2 0x%x\n", __raw_readl(EPDC_STATUS_COL2));
+ printk(KERN_DEBUG "EPDC_STATUS 0x%x\n", __raw_readl(EPDC_STATUS));
+ printk(KERN_DEBUG "EPDC_UPD_COL_CORD 0x%x\n", __raw_readl(EPDC_UPD_COL_CORD));
+ printk(KERN_DEBUG "EPDC_UPD_COL_SIZE 0x%x\n", __raw_readl(EPDC_UPD_COL_SIZE));
+ printk(KERN_DEBUG "EPDC_DEBUG 0x%x\n", __raw_readl(EPDC_DEBUG));
+ printk(KERN_DEBUG "EPDC_DEBUG_LUT 0x%x\n", __raw_readl(EPDC_DEBUG_LUT));
+ printk(KERN_DEBUG "EPDC_HIST1_PARAM 0x%x\n", __raw_readl(EPDC_HIST1_PARAM));
+ printk(KERN_DEBUG "EPDC_HIST2_PARAM 0x%x\n", __raw_readl(EPDC_HIST2_PARAM));
+ printk(KERN_DEBUG "EPDC_HIST4_PARAM 0x%x\n", __raw_readl(EPDC_HIST4_PARAM));
+ printk(KERN_DEBUG "EPDC_HIST8_PARAM0 0x%x\n", __raw_readl(EPDC_HIST8_PARAM0));
+ printk(KERN_DEBUG "EPDC_HIST8_PARAM1 0x%x\n", __raw_readl(EPDC_HIST8_PARAM1));
+ printk(KERN_DEBUG "EPDC_HIST16_PARAM0 0x%x\n", __raw_readl(EPDC_HIST16_PARAM0));
+ printk(KERN_DEBUG "EPDC_HIST16_PARAM1 0x%x\n", __raw_readl(EPDC_HIST16_PARAM1));
+ printk(KERN_DEBUG "EPDC_HIST16_PARAM2 0x%x\n", __raw_readl(EPDC_HIST16_PARAM2));
+ printk(KERN_DEBUG "EPDC_HIST16_PARAM3 0x%x\n", __raw_readl(EPDC_HIST16_PARAM3));
+ printk(KERN_DEBUG "EPDC_GPIO 0x%x\n", __raw_readl(EPDC_GPIO));
+ printk(KERN_DEBUG "EPDC_VERSION 0x%x\n", __raw_readl(EPDC_VERSION));
+ printk(KERN_DEBUG "\n\n");
+}
+
+static void dump_update_data(struct device *dev,
+ struct update_data_list *upd_data_list)
+{
+ dev_info(dev,
+ "X = %d, Y = %d, Width = %d, Height = %d, WaveMode = %d, "
+ "LUT = %d, Coll Mask = 0x%llx, order = %d\n",
+ upd_data_list->update_desc->upd_data.update_region.left,
+ upd_data_list->update_desc->upd_data.update_region.top,
+ upd_data_list->update_desc->upd_data.update_region.width,
+ upd_data_list->update_desc->upd_data.update_region.height,
+ upd_data_list->update_desc->upd_data.waveform_mode,
+ upd_data_list->lut_num,
+ upd_data_list->collision_mask,
+ upd_data_list->update_desc->update_order);
+}
+
+static void dump_collision_list(struct mxc_epdc_fb_data *fb_data)
+{
+ struct update_data_list *plist;
+
+ dev_info(fb_data->dev, "Collision List:\n");
+ if (list_empty(&fb_data->upd_buf_collision_list))
+ dev_info(fb_data->dev, "Empty");
+ list_for_each_entry(plist, &fb_data->upd_buf_collision_list, list) {
+ dev_info(fb_data->dev, "Virt Addr = 0x%x, Phys Addr = 0x%x ",
+ (u32)plist->virt_addr, plist->phys_addr);
+ dump_update_data(fb_data->dev, plist);
+ }
+}
+
+static void dump_free_list(struct mxc_epdc_fb_data *fb_data)
+{
+ struct update_data_list *plist;
+
+ dev_info(fb_data->dev, "Free List:\n");
+ if (list_empty(&fb_data->upd_buf_free_list))
+ dev_info(fb_data->dev, "Empty");
+ list_for_each_entry(plist, &fb_data->upd_buf_free_list, list)
+ dev_info(fb_data->dev, "Virt Addr = 0x%x, Phys Addr = 0x%x ",
+ (u32)plist->virt_addr, plist->phys_addr);
+}
+
+static void dump_queue(struct mxc_epdc_fb_data *fb_data)
+{
+ struct update_data_list *plist;
+
+ dev_info(fb_data->dev, "Queue:\n");
+ if (list_empty(&fb_data->upd_buf_queue))
+ dev_info(fb_data->dev, "Empty");
+ list_for_each_entry(plist, &fb_data->upd_buf_queue, list) {
+ dev_info(fb_data->dev, "Virt Addr = 0x%x, Phys Addr = 0x%x ",
+ (u32)plist->virt_addr, plist->phys_addr);
+ dump_update_data(fb_data->dev, plist);
+ }
+}
+
+static void dump_desc_data(struct device *dev,
+ struct update_desc_list *upd_desc_list)
+{
+ dev_info(dev,
+ "X = %d, Y = %d, Width = %d, Height = %d, WaveMode = %d, "
+ "order = %d\n",
+ upd_desc_list->upd_data.update_region.left,
+ upd_desc_list->upd_data.update_region.top,
+ upd_desc_list->upd_data.update_region.width,
+ upd_desc_list->upd_data.update_region.height,
+ upd_desc_list->upd_data.waveform_mode,
+ upd_desc_list->update_order);
+}
+
+static void dump_pending_list(struct mxc_epdc_fb_data *fb_data)
+{
+ struct update_desc_list *plist;
+
+ dev_info(fb_data->dev, "Queue:\n");
+ if (list_empty(&fb_data->upd_pending_list))
+ dev_info(fb_data->dev, "Empty");
+ list_for_each_entry(plist, &fb_data->upd_pending_list, list)
+ dump_desc_data(fb_data->dev, plist);
+}
+
+static void dump_all_updates(struct mxc_epdc_fb_data *fb_data)
+{
+ dump_free_list(fb_data);
+ dump_queue(fb_data);
+ dump_collision_list(fb_data);
+ dev_info(fb_data->dev, "Current update being processed:\n");
+ if (fb_data->cur_update == NULL)
+ dev_info(fb_data->dev, "No current update\n");
+ else
+ dump_update_data(fb_data->dev, fb_data->cur_update);
+}
+
+static void dump_fw_header(struct device *dev,
+ struct mxcfb_waveform_data_file *fw)
+{
+ dev_dbg(dev, "Firmware Header:\n");
+ dev_dbg(dev, "wi0 0x%08x\n", fw->wdh.wi0);
+ dev_dbg(dev, "wi1 0x%08x\n", fw->wdh.wi1);
+ dev_dbg(dev, "wi2 0x%08x\n", fw->wdh.wi2);
+ dev_dbg(dev, "wi3 0x%08x\n", fw->wdh.wi3);
+ dev_dbg(dev, "wi4 0x%08x\n", fw->wdh.wi4);
+ dev_dbg(dev, "wi5 0x%08x\n", fw->wdh.wi5);
+ dev_dbg(dev, "wi6 0x%08x\n", fw->wdh.wi6);
+ dev_dbg(dev, "xwia:24 0x%06x\n", fw->wdh.xwia);
+ dev_dbg(dev, "cs1:8 0x%02x\n", fw->wdh.cs1);
+ dev_dbg(dev, "wmta:24 0x%06x\n", fw->wdh.wmta);
+ dev_dbg(dev, "fvsn:8 0x%02x\n", fw->wdh.fvsn);
+ dev_dbg(dev, "luts:8 0x%02x\n", fw->wdh.luts);
+ dev_dbg(dev, "mc:8 0x%02x\n", fw->wdh.mc);
+ dev_dbg(dev, "trc:8 0x%02x\n", fw->wdh.trc);
+ dev_dbg(dev, "reserved0_0 0x%02x\n", fw->wdh.reserved0_0);
+ dev_dbg(dev, "eb:8 0x%02x\n", fw->wdh.eb);
+ dev_dbg(dev, "sb:8 0x%02x\n", fw->wdh.sb);
+ dev_dbg(dev, "reserved0_1 0x%02x\n", fw->wdh.reserved0_1);
+ dev_dbg(dev, "reserved0_2 0x%02x\n", fw->wdh.reserved0_2);
+ dev_dbg(dev, "reserved0_3 0x%02x\n", fw->wdh.reserved0_3);
+ dev_dbg(dev, "reserved0_4 0x%02x\n", fw->wdh.reserved0_4);
+ dev_dbg(dev, "reserved0_5 0x%02x\n", fw->wdh.reserved0_5);
+ dev_dbg(dev, "cs2:8 0x%02x\n", fw->wdh.cs2);
+}
+
+#else
+static inline void dump_pxp_config(struct mxc_epdc_fb_data *fb_data,
+ struct pxp_config_data *pxp_conf) {}
+static inline void dump_epdc_reg(void) {}
+static inline void dump_update_data(struct device *dev,
+ struct update_data_list *upd_data_list) {}
+static inline void dump_collision_list(struct mxc_epdc_fb_data *fb_data) {}
+static inline void dump_free_list(struct mxc_epdc_fb_data *fb_data) {}
+static inline void dump_queue(struct mxc_epdc_fb_data *fb_data) {}
+static inline void dump_all_updates(struct mxc_epdc_fb_data *fb_data) {}
+static void dump_fw_header(struct device *dev,
+ struct mxcfb_waveform_data_file *fw) {}
+
+#endif
+
+
+/********************************************************
+ * Start Low-Level EPDC Functions
+ ********************************************************/
+
+static inline void epdc_lut_complete_intr(int rev, u32 lut_num, bool enable)
+{
+ if (rev < 20) {
+ if (enable)
+ __raw_writel(1 << lut_num, EPDC_IRQ_MASK_SET);
+ else
+ __raw_writel(1 << lut_num, EPDC_IRQ_MASK_CLEAR);
+ } else {
+ if (enable) {
+ if (lut_num < 32)
+ __raw_writel(1 << lut_num, EPDC_IRQ_MASK1_SET);
+ else
+ __raw_writel(1 << (lut_num - 32),
+ EPDC_IRQ_MASK2_SET);
+ } else {
+ if (lut_num < 32)
+ __raw_writel(1 << lut_num,
+ EPDC_IRQ_MASK1_CLEAR);
+ else
+ __raw_writel(1 << (lut_num - 32),
+ EPDC_IRQ_MASK2_CLEAR);
+ }
+ }
+}
+
+static inline void epdc_working_buf_intr(bool enable)
+{
+ if (enable)
+ __raw_writel(EPDC_IRQ_WB_CMPLT_IRQ, EPDC_IRQ_MASK_SET);
+ else
+ __raw_writel(EPDC_IRQ_WB_CMPLT_IRQ, EPDC_IRQ_MASK_CLEAR);
+}
+
+static inline void epdc_clear_working_buf_irq(void)
+{
+ __raw_writel(EPDC_IRQ_WB_CMPLT_IRQ | EPDC_IRQ_LUT_COL_IRQ,
+ EPDC_IRQ_CLEAR);
+}
+
+static inline void epdc_eof_intr(bool enable)
+{
+ if (enable)
+ __raw_writel(EPDC_IRQ_FRAME_END_IRQ, EPDC_IRQ_MASK_SET);
+ else
+ __raw_writel(EPDC_IRQ_FRAME_END_IRQ, EPDC_IRQ_MASK_CLEAR);
+}
+
+static inline void epdc_clear_eof_irq(void)
+{
+ __raw_writel(EPDC_IRQ_FRAME_END_IRQ, EPDC_IRQ_CLEAR);
+}
+
+static inline bool epdc_signal_eof(void)
+{
+ return (__raw_readl(EPDC_IRQ_MASK) & __raw_readl(EPDC_IRQ)
+ & EPDC_IRQ_FRAME_END_IRQ) ? true : false;
+}
+
+static inline void epdc_set_temp(u32 temp)
+{
+ int ret = 0;
+ /* used to store external panel temperature value */
+ unsigned int ext_temp, ext_temp_index = temp;
+
+ if (temp == DEFAULT_TEMP_INDEX) {
+ ret = max17135_reg_read(REG_MAX17135_EXT_TEMP, &ext_temp);
+ if (ret == 0) {
+ ext_temp = ext_temp >> 8;
+ dev_dbg(g_fb_data->dev, "the current external temperature is %d\n",
+ ext_temp);
+ ext_temp_index = mxc_epdc_fb_get_temp_index(g_fb_data, ext_temp);
+ }
+ }
+
+ __raw_writel(ext_temp_index, EPDC_TEMP);
+}
+
+static inline void epdc_set_screen_res(u32 width, u32 height)
+{
+ u32 val = (height << EPDC_RES_VERTICAL_OFFSET) | width;
+ __raw_writel(val, EPDC_RES);
+}
+
+static inline void epdc_set_update_addr(u32 addr)
+{
+#ifdef EPDC_STANDARD_MODE
+ __raw_writel(0, EPDC_UPD_ADDR);
+#else
+ __raw_writel(addr, EPDC_UPD_ADDR);
+#endif
+}
+
+static inline void epdc_set_update_coord(u32 x, u32 y)
+{
+ u32 val = (y << EPDC_UPD_CORD_YCORD_OFFSET) | x;
+ __raw_writel(val, EPDC_UPD_CORD);
+}
+
+static inline void epdc_set_update_dimensions(u32 width, u32 height)
+{
+ u32 val = (height << EPDC_UPD_SIZE_HEIGHT_OFFSET) | width;
+ __raw_writel(val, EPDC_UPD_SIZE);
+}
+
+static void epdc_set_update_waveform(struct mxcfb_waveform_modes *wv_modes)
+{
+ u32 val;
+
+#ifdef EPDC_STANDARD_MODE
+ return;
+#endif
+
+ /* Configure the auto-waveform look-up table based on waveform modes */
+
+ /* Entry 1 = DU, 2 = GC4, 3 = GC8, etc. */
+ val = (wv_modes->mode_du << EPDC_AUTOWV_LUT_DATA_OFFSET) |
+ (0 << EPDC_AUTOWV_LUT_ADDR_OFFSET);
+ __raw_writel(val, EPDC_AUTOWV_LUT);
+ val = (wv_modes->mode_du << EPDC_AUTOWV_LUT_DATA_OFFSET) |
+ (1 << EPDC_AUTOWV_LUT_ADDR_OFFSET);
+ __raw_writel(val, EPDC_AUTOWV_LUT);
+ val = (wv_modes->mode_gc4 << EPDC_AUTOWV_LUT_DATA_OFFSET) |
+ (2 << EPDC_AUTOWV_LUT_ADDR_OFFSET);
+ __raw_writel(val, EPDC_AUTOWV_LUT);
+ val = (wv_modes->mode_gc8 << EPDC_AUTOWV_LUT_DATA_OFFSET) |
+ (3 << EPDC_AUTOWV_LUT_ADDR_OFFSET);
+ __raw_writel(val, EPDC_AUTOWV_LUT);
+ val = (wv_modes->mode_gc16 << EPDC_AUTOWV_LUT_DATA_OFFSET) |
+ (4 << EPDC_AUTOWV_LUT_ADDR_OFFSET);
+ __raw_writel(val, EPDC_AUTOWV_LUT);
+ val = (wv_modes->mode_gc32 << EPDC_AUTOWV_LUT_DATA_OFFSET) |
+ (5 << EPDC_AUTOWV_LUT_ADDR_OFFSET);
+ __raw_writel(val, EPDC_AUTOWV_LUT);
+}
+
+static void epdc_set_update_stride(u32 stride)
+{
+#ifdef EPDC_STANDARD_MODE
+ __raw_writel(0, EPDC_UPD_STRIDE);
+#else
+ __raw_writel(stride, EPDC_UPD_STRIDE);
+#endif
+}
+
+static void epdc_submit_update(u32 lut_num, u32 waveform_mode, u32 update_mode,
+ bool use_dry_run, bool use_test_mode, u32 np_val)
+{
+ u32 reg_val = 0;
+
+ if (use_test_mode) {
+ reg_val |=
+ ((np_val << EPDC_UPD_FIXED_FIXNP_OFFSET) &
+ EPDC_UPD_FIXED_FIXNP_MASK) | EPDC_UPD_FIXED_FIXNP_EN;
+ reg_val |=
+ ((np_val << EPDC_UPD_FIXED_FIXCP_OFFSET) &
+ EPDC_UPD_FIXED_FIXCP_MASK) | EPDC_UPD_FIXED_FIXCP_EN;
+
+ __raw_writel(reg_val, EPDC_UPD_FIXED);
+
+ reg_val = EPDC_UPD_CTRL_USE_FIXED;
+ } else {
+ __raw_writel(reg_val, EPDC_UPD_FIXED);
+ }
+
+ if (waveform_mode == WAVEFORM_MODE_AUTO)
+ reg_val |= EPDC_UPD_CTRL_AUTOWV;
+ else
+ reg_val |= ((waveform_mode <<
+ EPDC_UPD_CTRL_WAVEFORM_MODE_OFFSET) &
+ EPDC_UPD_CTRL_WAVEFORM_MODE_MASK);
+
+ reg_val |= (use_dry_run ? EPDC_UPD_CTRL_DRY_RUN : 0) |
+ ((lut_num << EPDC_UPD_CTRL_LUT_SEL_OFFSET) &
+ EPDC_UPD_CTRL_LUT_SEL_MASK) |
+ update_mode;
+
+#ifdef EPDC_STANDARD_MODE
+ reg_val |= 0x80000000;
+
+ epdc_set_used_lut(lut_num);
+#endif
+ dump_epdc_reg();
+ __raw_writel(reg_val, EPDC_UPD_CTRL);
+}
+
+static inline bool epdc_is_lut_complete(int rev, u32 lut_num)
+{
+ u32 val;
+ bool is_compl;
+ if (rev < 20) {
+ val = __raw_readl(EPDC_IRQ);
+ is_compl = val & (1 << lut_num) ? true : false;
+ } else if (lut_num < 32) {
+ val = __raw_readl(EPDC_IRQ1);
+ is_compl = val & (1 << lut_num) ? true : false;
+ } else {
+ val = __raw_readl(EPDC_IRQ2);
+ is_compl = val & (1 << (lut_num - 32)) ? true : false;
+ }
+
+ return is_compl;
+}
+
+static inline void epdc_clear_lut_complete_irq(int rev, u32 lut_num)
+{
+ if (rev < 20)
+ __raw_writel(1 << lut_num, EPDC_IRQ_CLEAR);
+ else if (lut_num < 32)
+ __raw_writel(1 << lut_num, EPDC_IRQ1_CLEAR);
+ else
+ __raw_writel(1 << (lut_num - 32), EPDC_IRQ2_CLEAR);
+}
+
+static inline bool epdc_is_lut_active(u32 lut_num)
+{
+ u32 val;
+ bool is_active;
+
+ if (lut_num < 32) {
+ val = __raw_readl(EPDC_STATUS_LUTS);
+ is_active = val & (1 << lut_num) ? true : false;
+ } else {
+ val = __raw_readl(EPDC_STATUS_LUTS2);
+ is_active = val & (1 << (lut_num - 32)) ? true : false;
+ }
+
+ return is_active;
+}
+
+static inline bool epdc_any_luts_active(int rev)
+{
+ bool any_active;
+
+ if (rev < 20)
+ any_active = __raw_readl(EPDC_STATUS_LUTS) ? true : false;
+ else
+ any_active = (__raw_readl(EPDC_STATUS_LUTS) |
+ __raw_readl(EPDC_STATUS_LUTS2)) ? true : false;
+
+ return any_active;
+}
+
+static inline bool epdc_any_luts_real_available(void)
+{
+ if ((__raw_readl(EPDC_STATUS_LUTS) != 0xfffffffe) ||
+ (__raw_readl(EPDC_STATUS_LUTS2) != ~0UL))
+ return true;
+ else
+ return false;
+}
+
+static inline bool epdc_any_luts_available(void)
+{
+#ifdef EPDC_STANDARD_MODE
+ if (((u32)used_luts != ~0UL) || ((u32)(used_luts >> 32) != ~0UL))
+ return 1;
+ else
+ return 0;
+#else
+ bool luts_available =
+ (__raw_readl(EPDC_STATUS_NEXTLUT) &
+ EPDC_STATUS_NEXTLUT_NEXT_LUT_VALID) ? true : false;
+ return luts_available;
+#endif
+}
+
+static inline int epdc_get_next_lut(void)
+{
+ u32 val =
+ __raw_readl(EPDC_STATUS_NEXTLUT) &
+ EPDC_STATUS_NEXTLUT_NEXT_LUT_MASK;
+ return val;
+}
+
+static inline void epdc_set_used_lut(u64 used_bit)
+{
+ used_luts |= (u64)1 << used_bit;
+}
+
+static inline void epdc_reset_used_lut(void)
+{
+ used_luts = 0x1;
+}
+
+#ifdef EPDC_STANDARD_MODE
+/*
+ * in previous flow, when all LUTs are used, the LUT cleanup operation
+ * need to wait for all the LUT to finish, it will not happen util last LUT
+ * is done. while in new flow, the cleanup operation does not need to wait
+ * for all LUTs to finish, instead it can start when there's LUT's done.
+ * The saved time is multiple LUT operation time.
+ */
+static int epdc_choose_next_lut(struct mxc_epdc_fb_data *fb_data, int *next_lut)
+{
+ while (!epdc_any_luts_available()) {
+ u64 luts_complete = fb_data->luts_complete;
+ pxp_clear_wb_work_func(fb_data);
+ used_luts &= ~luts_complete;
+ fb_data->luts_complete &= ~luts_complete;
+ }
+
+ used_luts |= 0x1;
+
+ if ((u32)used_luts != ~0UL)
+ *next_lut = ffz((u32)used_luts);
+ else if ((u32)(used_luts >> 32) != ~0UL)
+ *next_lut = ffz((u32)(used_luts >> 32)) + 32;
+
+ return 0;
+}
+#else
+static int epdc_choose_next_lut(struct mxc_epdc_fb_data *fb_data, int *next_lut)
+{
+ u64 luts_status, unprocessed_luts, used_luts;
+ /* Available LUTs are reduced to 16 in 5-bit waveform mode */
+ bool format_p5n = ((__raw_readl(EPDC_FORMAT) &
+ EPDC_FORMAT_BUF_PIXEL_FORMAT_MASK) ==
+ EPDC_FORMAT_BUF_PIXEL_FORMAT_P5N);
+
+ luts_status = __raw_readl(EPDC_STATUS_LUTS);
+ if ((fb_data->rev < 20) || format_p5n)
+ luts_status &= 0xFFFF;
+ else
+ luts_status |= ((u64)__raw_readl(EPDC_STATUS_LUTS2) << 32);
+
+ if (fb_data->rev < 20) {
+ unprocessed_luts = __raw_readl(EPDC_IRQ) & 0xFFFF;
+ } else {
+ unprocessed_luts = __raw_readl(EPDC_IRQ1) |
+ ((u64)__raw_readl(EPDC_IRQ2) << 32);
+ if (format_p5n)
+ unprocessed_luts &= 0xFFFF;
+ }
+
+ /*
+ * Note on unprocessed_luts: There is a race condition
+ * where a LUT completes, but has not been processed by
+ * IRQ handler workqueue, and then a new update request
+ * attempts to use that LUT. We prevent that here by
+ * ensuring that the LUT we choose doesn't have its IRQ
+ * bit set (indicating it has completed but not yet been
+ * processed).
+ */
+ used_luts = luts_status | unprocessed_luts;
+
+ /*
+ * Selecting a LUT to minimize incidence of TCE Underrun Error
+ * --------------------------------------------------------
+ * We want to find the lowest order LUT that is of greater
+ * order than all other active LUTs. If highest order LUT
+ * is active, then we want to choose the lowest order
+ * available LUT.
+ *
+ * NOTE: For EPDC version 2.0 and later, TCE Underrun error
+ * bug is fixed, so it doesn't matter which LUT is used.
+ */
+
+ if ((fb_data->rev < 20) || format_p5n) {
+ *next_lut = fls64(used_luts);
+ if (*next_lut > 15)
+ *next_lut = ffz(used_luts);
+ } else {
+ if ((u32)used_luts != ~0UL)
+ *next_lut = ffz((u32)used_luts);
+ else if ((u32)(used_luts >> 32) != ~0UL)
+ *next_lut = ffz((u32)(used_luts >> 32)) + 32;
+ else
+ *next_lut = INVALID_LUT;
+ }
+
+ if (used_luts & 0x8000)
+ return 1;
+ else
+ return 0;
+}
+#endif
+
+static inline bool epdc_is_working_buffer_busy(void)
+{
+ u32 val = __raw_readl(EPDC_STATUS);
+ bool is_busy = (val & EPDC_STATUS_WB_BUSY) ? true : false;
+
+ return is_busy;
+}
+
+static inline bool epdc_is_working_buffer_complete(void)
+{
+ u32 val = __raw_readl(EPDC_IRQ);
+ bool is_compl = (val & EPDC_IRQ_WB_CMPLT_IRQ) ? true : false;
+
+ return is_compl;
+}
+
+static inline bool epdc_is_lut_cancelled(void)
+{
+ u32 val = __raw_readl(EPDC_STATUS);
+ bool is_void = (val & EPDC_STATUS_UPD_VOID) ? true : false;
+
+ return is_void;
+}
+
+static inline bool epdc_is_collision(void)
+{
+ u32 val = __raw_readl(EPDC_IRQ);
+ return (val & EPDC_IRQ_LUT_COL_IRQ) ? true : false;
+}
+
+static inline u64 epdc_get_colliding_luts(int rev)
+{
+ u32 val = __raw_readl(EPDC_STATUS_COL);
+ if (rev >= 20)
+ val |= (u64)__raw_readl(EPDC_STATUS_COL2) << 32;
+ return val;
+}
+
+static void epdc_set_horizontal_timing(u32 horiz_start, u32 horiz_end,
+ u32 hsync_width, u32 hsync_line_length)
+{
+ u32 reg_val =
+ ((hsync_width << EPDC_TCE_HSCAN1_LINE_SYNC_WIDTH_OFFSET) &
+ EPDC_TCE_HSCAN1_LINE_SYNC_WIDTH_MASK)
+ | ((hsync_line_length << EPDC_TCE_HSCAN1_LINE_SYNC_OFFSET) &
+ EPDC_TCE_HSCAN1_LINE_SYNC_MASK);
+ __raw_writel(reg_val, EPDC_TCE_HSCAN1);
+
+ reg_val =
+ ((horiz_start << EPDC_TCE_HSCAN2_LINE_BEGIN_OFFSET) &
+ EPDC_TCE_HSCAN2_LINE_BEGIN_MASK)
+ | ((horiz_end << EPDC_TCE_HSCAN2_LINE_END_OFFSET) &
+ EPDC_TCE_HSCAN2_LINE_END_MASK);
+ __raw_writel(reg_val, EPDC_TCE_HSCAN2);
+}
+
+static void epdc_set_vertical_timing(u32 vert_start, u32 vert_end,
+ u32 vsync_width)
+{
+ u32 reg_val =
+ ((vert_start << EPDC_TCE_VSCAN_FRAME_BEGIN_OFFSET) &
+ EPDC_TCE_VSCAN_FRAME_BEGIN_MASK)
+ | ((vert_end << EPDC_TCE_VSCAN_FRAME_END_OFFSET) &
+ EPDC_TCE_VSCAN_FRAME_END_MASK)
+ | ((vsync_width << EPDC_TCE_VSCAN_FRAME_SYNC_OFFSET) &
+ EPDC_TCE_VSCAN_FRAME_SYNC_MASK);
+ __raw_writel(reg_val, EPDC_TCE_VSCAN);
+}
+
+static void epdc_init_settings(struct mxc_epdc_fb_data *fb_data)
+{
+ struct imx_epdc_fb_mode *epdc_mode = fb_data->cur_mode;
+ struct fb_var_screeninfo *screeninfo = &fb_data->epdc_fb_var;
+ u32 reg_val;
+ int num_ce;
+#ifndef EPDC_STANDARD_MODE
+ int i;
+#endif
+ int j;
+ unsigned char *bb_p;
+
+ /* Enable clocks to access EPDC regs */
+ clk_prepare_enable(fb_data->epdc_clk_axi);
+ clk_prepare_enable(fb_data->epdc_clk_pix);
+
+ /* Reset */
+ __raw_writel(EPDC_CTRL_SFTRST, EPDC_CTRL_SET);
+ while (!(__raw_readl(EPDC_CTRL) & EPDC_CTRL_CLKGATE))
+ ;
+ __raw_writel(EPDC_CTRL_SFTRST, EPDC_CTRL_CLEAR);
+
+ /* Enable clock gating (clear to enable) */
+ __raw_writel(EPDC_CTRL_CLKGATE, EPDC_CTRL_CLEAR);
+ while (__raw_readl(EPDC_CTRL) & (EPDC_CTRL_SFTRST | EPDC_CTRL_CLKGATE))
+ ;
+
+ /* EPDC_CTRL */
+ reg_val = __raw_readl(EPDC_CTRL);
+ reg_val &= ~EPDC_CTRL_UPD_DATA_SWIZZLE_MASK;
+#ifdef EPDC_STANDARD_MODE
+ reg_val |= EPDC_CTRL_UPD_DATA_SWIZZLE_ALL_BYTES_SWAP;
+#else
+ reg_val |= EPDC_CTRL_UPD_DATA_SWIZZLE_NO_SWAP;
+#endif
+ reg_val &= ~EPDC_CTRL_LUT_DATA_SWIZZLE_MASK;
+ reg_val |= EPDC_CTRL_LUT_DATA_SWIZZLE_NO_SWAP;
+ __raw_writel(reg_val, EPDC_CTRL_SET);
+
+ /* EPDC_FORMAT - 2bit TFT and 4bit Buf pixel format */
+ reg_val = EPDC_FORMAT_TFT_PIXEL_FORMAT_2BIT
+#ifdef EPDC_STANDARD_MODE
+ | EPDC_FORMAT_WB_TYPE_WB_EXTERNAL16
+#endif
+ | EPDC_FORMAT_BUF_PIXEL_FORMAT_P4N
+ | ((0x0 << EPDC_FORMAT_DEFAULT_TFT_PIXEL_OFFSET) &
+ EPDC_FORMAT_DEFAULT_TFT_PIXEL_MASK);
+ __raw_writel(reg_val, EPDC_FORMAT);
+
+#ifdef EPDC_STANDARD_MODE
+ reg_val = 0;
+ if (fb_data->waveform_is_advanced) {
+ reg_val =
+ ((EPDC_WB_FIELD_USAGE_PTS << EPDC_WB_FIELD_USAGE_OFFSET) &
+ EPDC_WB_FIELD_USAGE_MASK)
+ | ((0x8 << EPDC_WB_FIELD_FROM_OFFSET) &
+ EPDC_WB_FIELD_FROM_MASK)
+ | ((0x8 << EPDC_WB_FIELD_TO_OFFSET) &
+ EPDC_WB_FIELD_TO_MASK)
+ | ((0x1 << EPDC_WB_FIELD_LEN_OFFSET) &
+ EPDC_WB_FIELD_LEN_MASK);
+ }
+ __raw_writel(reg_val, EPDC_WB_FIELD3);
+#endif
+
+ /* EPDC_FIFOCTRL (disabled) */
+ reg_val =
+ ((100 << EPDC_FIFOCTRL_FIFO_INIT_LEVEL_OFFSET) &
+ EPDC_FIFOCTRL_FIFO_INIT_LEVEL_MASK)
+ | ((200 << EPDC_FIFOCTRL_FIFO_H_LEVEL_OFFSET) &
+ EPDC_FIFOCTRL_FIFO_H_LEVEL_MASK)
+ | ((100 << EPDC_FIFOCTRL_FIFO_L_LEVEL_OFFSET) &
+ EPDC_FIFOCTRL_FIFO_L_LEVEL_MASK);
+ __raw_writel(reg_val, EPDC_FIFOCTRL);
+
+ /* EPDC_TEMP - Use default temp to get index */
+ epdc_set_temp(mxc_epdc_fb_get_temp_index(fb_data, DEFAULT_TEMP));
+
+ /* EPDC_RES */
+ epdc_set_screen_res(epdc_mode->vmode->xres, epdc_mode->vmode->yres);
+
+#ifndef EPDC_STANDARD_MODE
+ /* EPDC_AUTOWV_LUT */
+ /* Initialize all auto-wavefrom look-up values to 2 - GC16 */
+ for (i = 0; i < 8; i++)
+ __raw_writel((2 << EPDC_AUTOWV_LUT_DATA_OFFSET) |
+ (i << EPDC_AUTOWV_LUT_ADDR_OFFSET), EPDC_AUTOWV_LUT);
+#endif
+
+ /*
+ * EPDC_TCE_CTRL
+ * VSCAN_HOLDOFF = 4
+ * VCOM_MODE = MANUAL
+ * VCOM_VAL = 0
+ * DDR_MODE = DISABLED
+ * LVDS_MODE_CE = DISABLED
+ * LVDS_MODE = DISABLED
+ * DUAL_SCAN = DISABLED
+ * SDDO_WIDTH = 8bit
+ * PIXELS_PER_SDCLK = 4
+ */
+ reg_val =
+ ((epdc_mode->vscan_holdoff << EPDC_TCE_CTRL_VSCAN_HOLDOFF_OFFSET) &
+ EPDC_TCE_CTRL_VSCAN_HOLDOFF_MASK)
+ | EPDC_TCE_CTRL_PIXELS_PER_SDCLK_4;
+ __raw_writel(reg_val, EPDC_TCE_CTRL);
+
+ /* EPDC_TCE_HSCAN */
+ epdc_set_horizontal_timing(screeninfo->left_margin,
+ screeninfo->right_margin,
+ screeninfo->hsync_len,
+ screeninfo->hsync_len);
+
+ /* EPDC_TCE_VSCAN */
+ epdc_set_vertical_timing(screeninfo->upper_margin,
+ screeninfo->lower_margin,
+ screeninfo->vsync_len);
+
+ /* EPDC_TCE_OE */
+ reg_val =
+ ((epdc_mode->sdoed_width << EPDC_TCE_OE_SDOED_WIDTH_OFFSET) &
+ EPDC_TCE_OE_SDOED_WIDTH_MASK)
+ | ((epdc_mode->sdoed_delay << EPDC_TCE_OE_SDOED_DLY_OFFSET) &
+ EPDC_TCE_OE_SDOED_DLY_MASK)
+ | ((epdc_mode->sdoez_width << EPDC_TCE_OE_SDOEZ_WIDTH_OFFSET) &
+ EPDC_TCE_OE_SDOEZ_WIDTH_MASK)
+ | ((epdc_mode->sdoez_delay << EPDC_TCE_OE_SDOEZ_DLY_OFFSET) &
+ EPDC_TCE_OE_SDOEZ_DLY_MASK);
+ __raw_writel(reg_val, EPDC_TCE_OE);
+
+ /* EPDC_TCE_TIMING1 */
+ __raw_writel(0x0, EPDC_TCE_TIMING1);
+
+ /* EPDC_TCE_TIMING2 */
+ reg_val =
+ ((epdc_mode->gdclk_hp_offs << EPDC_TCE_TIMING2_GDCLK_HP_OFFSET) &
+ EPDC_TCE_TIMING2_GDCLK_HP_MASK)
+ | ((epdc_mode->gdsp_offs << EPDC_TCE_TIMING2_GDSP_OFFSET_OFFSET) &
+ EPDC_TCE_TIMING2_GDSP_OFFSET_MASK);
+ __raw_writel(reg_val, EPDC_TCE_TIMING2);
+
+ /* EPDC_TCE_TIMING3 */
+ reg_val =
+ ((epdc_mode->gdoe_offs << EPDC_TCE_TIMING3_GDOE_OFFSET_OFFSET) &
+ EPDC_TCE_TIMING3_GDOE_OFFSET_MASK)
+ | ((epdc_mode->gdclk_offs << EPDC_TCE_TIMING3_GDCLK_OFFSET_OFFSET) &
+ EPDC_TCE_TIMING3_GDCLK_OFFSET_MASK);
+ __raw_writel(reg_val, EPDC_TCE_TIMING3);
+
+ /*
+ * EPDC_TCE_SDCFG
+ * SDCLK_HOLD = 1
+ * SDSHR = 1
+ * NUM_CE = 1
+ * SDDO_REFORMAT = FLIP_PIXELS
+ * SDDO_INVERT = DISABLED
+ * PIXELS_PER_CE = display horizontal resolution
+ */
+ num_ce = epdc_mode->num_ce;
+ if (num_ce == 0)
+ num_ce = 1;
+ reg_val = EPDC_TCE_SDCFG_SDCLK_HOLD | EPDC_TCE_SDCFG_SDSHR
+ | ((num_ce << EPDC_TCE_SDCFG_NUM_CE_OFFSET) &
+ EPDC_TCE_SDCFG_NUM_CE_MASK)
+ | EPDC_TCE_SDCFG_SDDO_REFORMAT_FLIP_PIXELS
+ | ((epdc_mode->vmode->xres/num_ce << EPDC_TCE_SDCFG_PIXELS_PER_CE_OFFSET) &
+ EPDC_TCE_SDCFG_PIXELS_PER_CE_MASK);
+ __raw_writel(reg_val, EPDC_TCE_SDCFG);
+
+ /*
+ * EPDC_TCE_GDCFG
+ * GDRL = 1
+ * GDOE_MODE = 0;
+ * GDSP_MODE = 0;
+ */
+ reg_val = EPDC_TCE_SDCFG_GDRL;
+ __raw_writel(reg_val, EPDC_TCE_GDCFG);
+
+ /*
+ * EPDC_TCE_POLARITY
+ * SDCE_POL = ACTIVE LOW
+ * SDLE_POL = ACTIVE HIGH
+ * SDOE_POL = ACTIVE HIGH
+ * GDOE_POL = ACTIVE HIGH
+ * GDSP_POL = ACTIVE LOW
+ */
+ reg_val = EPDC_TCE_POLARITY_SDLE_POL_ACTIVE_HIGH
+ | EPDC_TCE_POLARITY_SDOE_POL_ACTIVE_HIGH
+ | EPDC_TCE_POLARITY_GDOE_POL_ACTIVE_HIGH;
+ __raw_writel(reg_val, EPDC_TCE_POLARITY);
+
+ /* EPDC_IRQ_MASK */
+ __raw_writel(EPDC_IRQ_TCE_UNDERRUN_IRQ, EPDC_IRQ_MASK);
+
+ /*
+ * EPDC_GPIO
+ * PWRCOM = ?
+ * PWRCTRL = ?
+ * BDR = ?
+ */
+ reg_val = ((0 << EPDC_GPIO_PWRCTRL_OFFSET) & EPDC_GPIO_PWRCTRL_MASK)
+ | ((0 << EPDC_GPIO_BDR_OFFSET) & EPDC_GPIO_BDR_MASK);
+ __raw_writel(reg_val, EPDC_GPIO);
+
+ __raw_writel(fb_data->waveform_buffer_phys, EPDC_WVADDR);
+ __raw_writel(fb_data->working_buffer_phys, EPDC_WB_ADDR);
+ __raw_writel(fb_data->working_buffer_phys, EPDC_WB_ADDR_TCE);
+
+ bb_p = (unsigned char *)fb_data->virt_addr_black;
+ for (j = 0; j < fb_data->cur_mode->vmode->xres * fb_data->cur_mode->vmode->yres; j++) {
+ *bb_p = 0x0;
+ bb_p++;
+ }
+
+ /* Disable clock */
+ clk_disable_unprepare(fb_data->epdc_clk_axi);
+ clk_disable_unprepare(fb_data->epdc_clk_pix);
+}
+
+static void epdc_powerup(struct mxc_epdc_fb_data *fb_data)
+{
+ int ret = 0;
+ mutex_lock(&fb_data->power_mutex);
+
+ /*
+ * If power down request is pending, clear
+ * powering_down to cancel the request.
+ */
+ if (fb_data->powering_down)
+ fb_data->powering_down = false;
+
+ if (fb_data->power_state == POWER_STATE_ON) {
+ mutex_unlock(&fb_data->power_mutex);
+ return;
+ }
+
+ dev_dbg(fb_data->dev, "EPDC Powerup\n");
+
+ fb_data->updates_active = true;
+
+ /* Enable the v3p3 regulator */
+ ret = regulator_enable(fb_data->v3p3_regulator);
+ if (IS_ERR((void *)ret)) {
+ dev_err(fb_data->dev, "Unable to enable V3P3 regulator."
+ "err = 0x%x\n", ret);
+ mutex_unlock(&fb_data->power_mutex);
+ return;
+ }
+
+ msleep(1);
+
+ pm_runtime_get_sync(fb_data->dev);
+
+ /* Enable clocks to EPDC */
+ clk_prepare_enable(fb_data->epdc_clk_axi);
+ clk_prepare_enable(fb_data->epdc_clk_pix);
+
+ __raw_writel(EPDC_CTRL_CLKGATE, EPDC_CTRL_CLEAR);
+
+ /* Enable power to the EPD panel */
+ ret = regulator_enable(fb_data->display_regulator);
+ if (IS_ERR((void *)ret)) {
+ dev_err(fb_data->dev, "Unable to enable DISPLAY regulator."
+ "err = 0x%x\n", ret);
+ mutex_unlock(&fb_data->power_mutex);
+ return;
+ }
+ ret = regulator_enable(fb_data->vcom_regulator);
+ if (IS_ERR((void *)ret)) {
+ dev_err(fb_data->dev, "Unable to enable VCOM regulator."
+ "err = 0x%x\n", ret);
+ mutex_unlock(&fb_data->power_mutex);
+ return;
+ }
+
+ fb_data->power_state = POWER_STATE_ON;
+
+ mutex_unlock(&fb_data->power_mutex);
+}
+
+static void epdc_powerdown(struct mxc_epdc_fb_data *fb_data)
+{
+ mutex_lock(&fb_data->power_mutex);
+
+ /* If powering_down has been cleared, a powerup
+ * request is pre-empting this powerdown request.
+ */
+ if (!fb_data->powering_down
+ || (fb_data->power_state == POWER_STATE_OFF)) {
+ mutex_unlock(&fb_data->power_mutex);
+ return;
+ }
+
+ dev_dbg(fb_data->dev, "EPDC Powerdown\n");
+
+ /* Disable power to the EPD panel */
+ regulator_disable(fb_data->vcom_regulator);
+ regulator_disable(fb_data->display_regulator);
+
+ /* Disable clocks to EPDC */
+ __raw_writel(EPDC_CTRL_CLKGATE, EPDC_CTRL_SET);
+ clk_disable_unprepare(fb_data->epdc_clk_pix);
+ clk_disable_unprepare(fb_data->epdc_clk_axi);
+
+ pm_runtime_put_sync_suspend(fb_data->dev);
+
+ /* turn off the V3p3 */
+ regulator_disable(fb_data->v3p3_regulator);
+
+ fb_data->power_state = POWER_STATE_OFF;
+ fb_data->powering_down = false;
+
+ if (fb_data->wait_for_powerdown) {
+ fb_data->wait_for_powerdown = false;
+ complete(&fb_data->powerdown_compl);
+ }
+
+ mutex_unlock(&fb_data->power_mutex);
+}
+
+static void epdc_init_sequence(struct mxc_epdc_fb_data *fb_data)
+{
+ /* Initialize EPDC, passing pointer to EPDC registers */
+ epdc_init_settings(fb_data);
+
+ fb_data->in_init = true;
+ epdc_powerup(fb_data);
+ draw_mode0(fb_data);
+ /* Force power down event */
+ fb_data->powering_down = true;
+ epdc_powerdown(fb_data);
+ fb_data->updates_active = false;
+}
+
+static int mxc_epdc_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ u32 len;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ if (offset < info->fix.smem_len) {
+ /* mapping framebuffer memory */
+ len = info->fix.smem_len - offset;
+ vma->vm_pgoff = (info->fix.smem_start + offset) >> PAGE_SHIFT;
+ } else
+ return -EINVAL;
+
+ len = PAGE_ALIGN(len);
+ if (vma->vm_end - vma->vm_start > len)
+ return -EINVAL;
+
+ /* make buffers bufferable */
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
+ dev_dbg(info->device, "mmap remap_pfn_range failed\n");
+ return -ENOBUFS;
+ }
+
+ return 0;
+}
+
+static inline u_int _chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+static int mxc_epdc_fb_setcolreg(u_int regno, u_int red, u_int green,
+ u_int blue, u_int transp, struct fb_info *info)
+{
+ unsigned int val;
+ int ret = 1;
+
+ /*
+ * If greyscale is true, then we convert the RGB value
+ * to greyscale no matter what visual we are using.
+ */
+ if (info->var.grayscale)
+ red = green = blue = (19595 * red + 38470 * green +
+ 7471 * blue) >> 16;
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ /*
+ * 16-bit True Colour. We encode the RGB value
+ * according to the RGB bitfield information.
+ */
+ if (regno < 16) {
+ u32 *pal = info->pseudo_palette;
+
+ val = _chan_to_field(red, &info->var.red);
+ val |= _chan_to_field(green, &info->var.green);
+ val |= _chan_to_field(blue, &info->var.blue);
+
+ pal[regno] = val;
+ ret = 0;
+ }
+ break;
+
+ case FB_VISUAL_STATIC_PSEUDOCOLOR:
+ case FB_VISUAL_PSEUDOCOLOR:
+ break;
+ }
+
+ return ret;
+}
+
+static int mxc_epdc_fb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
+{
+ int count, index, r;
+ u16 *red, *green, *blue, *transp;
+ u16 trans = 0xffff;
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+ int i;
+
+ dev_dbg(fb_data->dev, "setcmap\n");
+
+ if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) {
+ /* Only support an 8-bit, 256 entry lookup */
+ if (cmap->len != 256)
+ return 1;
+
+ mxc_epdc_fb_flush_updates(fb_data);
+
+ mutex_lock(&fb_data->pxp_mutex);
+ /*
+ * Store colormap in pxp_conf structure for later transmit
+ * to PxP during update process to convert gray pixels.
+ *
+ * Since red=blue=green for pseudocolor visuals, we can
+ * just use red values.
+ */
+ for (i = 0; i < 256; i++)
+ fb_data->pxp_conf.proc_data.lut_map[i] = cmap->red[i] & 0xFF;
+
+ fb_data->pxp_conf.proc_data.lut_map_updated = true;
+
+ mutex_unlock(&fb_data->pxp_mutex);
+ } else {
+ red = cmap->red;
+ green = cmap->green;
+ blue = cmap->blue;
+ transp = cmap->transp;
+ index = cmap->start;
+
+ for (count = 0; count < cmap->len; count++) {
+ if (transp)
+ trans = *transp++;
+ r = mxc_epdc_fb_setcolreg(index++, *red++, *green++, *blue++,
+ trans, info);
+ if (r != 0)
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+static void adjust_coordinates(u32 xres, u32 yres, u32 rotation,
+ struct mxcfb_rect *update_region, struct mxcfb_rect *adj_update_region)
+{
+ u32 temp;
+
+ /* If adj_update_region == NULL, pass result back in update_region */
+ /* If adj_update_region == valid, use it to pass back result */
+ if (adj_update_region)
+ switch (rotation) {
+ case FB_ROTATE_UR:
+ adj_update_region->top = update_region->top;
+ adj_update_region->left = update_region->left;
+ adj_update_region->width = update_region->width;
+ adj_update_region->height = update_region->height;
+ break;
+ case FB_ROTATE_CW:
+ adj_update_region->top = update_region->left;
+ adj_update_region->left = yres -
+ (update_region->top + update_region->height);
+ adj_update_region->width = update_region->height;
+ adj_update_region->height = update_region->width;
+ break;
+ case FB_ROTATE_UD:
+ adj_update_region->width = update_region->width;
+ adj_update_region->height = update_region->height;
+ adj_update_region->top = yres -
+ (update_region->top + update_region->height);
+ adj_update_region->left = xres -
+ (update_region->left + update_region->width);
+ break;
+ case FB_ROTATE_CCW:
+ adj_update_region->left = update_region->top;
+ adj_update_region->top = xres -
+ (update_region->left + update_region->width);
+ adj_update_region->width = update_region->height;
+ adj_update_region->height = update_region->width;
+ break;
+ }
+ else
+ switch (rotation) {
+ case FB_ROTATE_UR:
+ /* No adjustment needed */
+ break;
+ case FB_ROTATE_CW:
+ temp = update_region->top;
+ update_region->top = update_region->left;
+ update_region->left = yres -
+ (temp + update_region->height);
+ temp = update_region->width;
+ update_region->width = update_region->height;
+ update_region->height = temp;
+ break;
+ case FB_ROTATE_UD:
+ update_region->top = yres -
+ (update_region->top + update_region->height);
+ update_region->left = xres -
+ (update_region->left + update_region->width);
+ break;
+ case FB_ROTATE_CCW:
+ temp = update_region->left;
+ update_region->left = update_region->top;
+ update_region->top = xres -
+ (temp + update_region->width);
+ temp = update_region->width;
+ update_region->width = update_region->height;
+ update_region->height = temp;
+ break;
+ }
+}
+
+/*
+ * Set fixed framebuffer parameters based on variable settings.
+ *
+ * @param info framebuffer information pointer
+ */
+static int mxc_epdc_fb_set_fix(struct fb_info *info)
+{
+ struct fb_fix_screeninfo *fix = &info->fix;
+ struct fb_var_screeninfo *var = &info->var;
+
+ fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->accel = FB_ACCEL_NONE;
+ if (var->grayscale)
+ fix->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+ else
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ fix->xpanstep = 1;
+ fix->ypanstep = 1;
+
+ return 0;
+}
+
+/*
+ * This routine actually sets the video mode. It's in here where we
+ * the hardware state info->par and fix which can be affected by the
+ * change in par. For this driver it doesn't do much.
+ *
+ */
+static int mxc_epdc_fb_set_par(struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+ struct pxp_config_data *pxp_conf = &fb_data->pxp_conf;
+ struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+ struct fb_var_screeninfo *screeninfo = &fb_data->info.var;
+ struct imx_epdc_fb_mode *epdc_modes = fb_data->pdata->epdc_mode;
+ int i;
+ int ret;
+ __u32 xoffset_old, yoffset_old;
+
+ /*
+ * Can't change the FB parameters until current updates have completed.
+ * This function returns when all active updates are done.
+ */
+ mxc_epdc_fb_flush_updates(fb_data);
+
+ mutex_lock(&fb_data->queue_mutex);
+ /*
+ * Set all screeninfo except for xoffset/yoffset
+ * Subsequent call to pan_display will handle those.
+ */
+ xoffset_old = fb_data->epdc_fb_var.xoffset;
+ yoffset_old = fb_data->epdc_fb_var.yoffset;
+ fb_data->epdc_fb_var = *screeninfo;
+ fb_data->epdc_fb_var.xoffset = xoffset_old;
+ fb_data->epdc_fb_var.yoffset = yoffset_old;
+ mutex_unlock(&fb_data->queue_mutex);
+
+ mutex_lock(&fb_data->pxp_mutex);
+
+ /*
+ * Update PxP config data (used to process FB regions for updates)
+ * based on FB info and processing tasks required
+ */
+
+ /* Initialize non-channel-specific PxP parameters */
+ proc_data->drect.left = proc_data->srect.left = 0;
+ proc_data->drect.top = proc_data->srect.top = 0;
+ proc_data->drect.width = proc_data->srect.width = screeninfo->xres;
+ proc_data->drect.height = proc_data->srect.height = screeninfo->yres;
+ proc_data->scaling = 0;
+ proc_data->hflip = 0;
+ proc_data->vflip = 0;
+ proc_data->rotate = screeninfo->rotate;
+ proc_data->bgcolor = 0;
+ proc_data->overlay_state = 0;
+ proc_data->lut_transform = PXP_LUT_NONE;
+
+ /*
+ * configure S0 channel parameters
+ * Parameters should match FB format/width/height
+ */
+ if (screeninfo->grayscale)
+ pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_GREY;
+ else {
+ switch (screeninfo->bits_per_pixel) {
+ case 16:
+ pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_RGB565;
+ break;
+ case 24:
+ pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_RGB24;
+ break;
+ case 32:
+ pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_XRGB32;
+ break;
+ default:
+ pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_RGB565;
+ break;
+ }
+ }
+ pxp_conf->s0_param.width = screeninfo->xres_virtual;
+ pxp_conf->s0_param.stride = (screeninfo->bits_per_pixel * pxp_conf->s0_param.width) >> 3;
+ pxp_conf->s0_param.height = screeninfo->yres;
+ pxp_conf->s0_param.color_key = -1;
+ pxp_conf->s0_param.color_key_enable = false;
+
+ /*
+ * Initialize Output channel parameters
+ * Output is Y-only greyscale
+ * Output width/height will vary based on update region size
+ */
+ pxp_conf->out_param.width = screeninfo->xres;
+ pxp_conf->out_param.height = screeninfo->yres;
+ pxp_conf->out_param.pixel_fmt = PXP_PIX_FMT_GREY;
+
+ mutex_unlock(&fb_data->pxp_mutex);
+
+ /*
+ * If HW not yet initialized, check to see if we are being sent
+ * an initialization request.
+ */
+ if (!fb_data->hw_ready) {
+ struct fb_videomode mode;
+ u32 xres_temp;
+
+ fb_var_to_videomode(&mode, screeninfo);
+
+ /* When comparing requested fb mode,
+ we need to use unrotated dimensions */
+ if ((screeninfo->rotate == FB_ROTATE_CW) ||
+ (screeninfo->rotate == FB_ROTATE_CCW)) {
+ xres_temp = mode.xres;
+ mode.xres = mode.yres;
+ mode.yres = xres_temp;
+ }
+
+ /*
+ * If requested video mode does not match current video
+ * mode, search for a matching panel.
+ */
+ if (fb_data->cur_mode &&
+ !fb_mode_is_equal(fb_data->cur_mode->vmode,
+ &mode)) {
+ bool found_match = false;
+
+ /* Match videomode against epdc modes */
+ for (i = 0; i < fb_data->pdata->num_modes; i++) {
+ if (!fb_mode_is_equal(epdc_modes[i].vmode,
+ &mode))
+ continue;
+ fb_data->cur_mode = &epdc_modes[i];
+ found_match = true;
+ break;
+ }
+
+ if (!found_match) {
+ dev_err(fb_data->dev,
+ "Failed to match requested "
+ "video mode\n");
+ return EINVAL;
+ }
+ }
+
+ /* Found a match - Grab timing params */
+ screeninfo->left_margin = mode.left_margin;
+ screeninfo->right_margin = mode.right_margin;
+ screeninfo->upper_margin = mode.upper_margin;
+ screeninfo->lower_margin = mode.lower_margin;
+ screeninfo->hsync_len = mode.hsync_len;
+ screeninfo->vsync_len = mode.vsync_len;
+
+ fb_data->hw_initializing = true;
+
+ /* Initialize EPDC settings and init panel */
+ ret =
+ mxc_epdc_fb_init_hw((struct fb_info *)fb_data);
+ if (ret) {
+ dev_err(fb_data->dev,
+ "Failed to load panel waveform data\n");
+ return ret;
+ }
+ }
+
+ /*
+ * EOF sync delay (in us) should be equal to the vscan holdoff time
+ * VSCAN_HOLDOFF time = (VSCAN_HOLDOFF value + 1) * Vertical lines
+ * Add 25us for additional margin
+ */
+ fb_data->eof_sync_period = (fb_data->cur_mode->vscan_holdoff + 1) *
+ 1000000/(fb_data->cur_mode->vmode->refresh *
+ (fb_data->cur_mode->vmode->upper_margin +
+ fb_data->cur_mode->vmode->yres +
+ fb_data->cur_mode->vmode->lower_margin +
+ fb_data->cur_mode->vmode->vsync_len)) + 25;
+
+ mxc_epdc_fb_set_fix(info);
+
+ return 0;
+}
+
+static int mxc_epdc_fb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+
+ if (!var->xres)
+ var->xres = 1;
+ if (!var->yres)
+ var->yres = 1;
+
+ if (var->xres_virtual < var->xoffset + var->xres)
+ var->xres_virtual = var->xoffset + var->xres;
+ if (var->yres_virtual < var->yoffset + var->yres)
+ var->yres_virtual = var->yoffset + var->yres;
+
+ if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
+ (var->bits_per_pixel != 16) && (var->bits_per_pixel != 8))
+ var->bits_per_pixel = default_bpp;
+
+ switch (var->bits_per_pixel) {
+ case 8:
+ if (var->grayscale != 0) {
+ /*
+ * For 8-bit grayscale, R, G, and B offset are equal.
+ *
+ */
+ var->red.length = 8;
+ var->red.offset = 0;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 0;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ } else {
+ var->red.length = 3;
+ var->red.offset = 5;
+ var->red.msb_right = 0;
+
+ var->green.length = 3;
+ var->green.offset = 2;
+ var->green.msb_right = 0;
+
+ var->blue.length = 2;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ }
+ break;
+ case 16:
+ var->red.length = 5;
+ var->red.offset = 11;
+ var->red.msb_right = 0;
+
+ var->green.length = 6;
+ var->green.offset = 5;
+ var->green.msb_right = 0;
+
+ var->blue.length = 5;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 24:
+ var->red.length = 8;
+ var->red.offset = 16;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 32:
+ var->red.length = 8;
+ var->red.offset = 16;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 8;
+ var->transp.offset = 24;
+ var->transp.msb_right = 0;
+ break;
+ }
+
+ switch (var->rotate) {
+ case FB_ROTATE_UR:
+ case FB_ROTATE_UD:
+ var->xres = fb_data->native_width;
+ var->yres = fb_data->native_height;
+ break;
+ case FB_ROTATE_CW:
+ case FB_ROTATE_CCW:
+ var->xres = fb_data->native_height;
+ var->yres = fb_data->native_width;
+ break;
+ default:
+ /* Invalid rotation value */
+ var->rotate = 0;
+ dev_dbg(fb_data->dev, "Invalid rotation request\n");
+ return -EINVAL;
+ }
+
+ var->xres_virtual = ALIGN(var->xres, 32);
+ var->yres_virtual = ALIGN(var->yres, 128) * fb_data->num_screens;
+
+ var->height = -1;
+ var->width = -1;
+
+ return 0;
+}
+
+static void mxc_epdc_fb_set_waveform_modes(struct mxcfb_waveform_modes *modes,
+ struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+
+ mutex_lock(&fb_data->queue_mutex);
+
+ memcpy(&fb_data->wv_modes, modes, sizeof(struct mxcfb_waveform_modes));
+
+ /* Set flag to ensure that new waveform modes
+ * are programmed into EPDC before next update */
+ fb_data->wv_modes_update = true;
+
+ mutex_unlock(&fb_data->queue_mutex);
+}
+
+static int mxc_epdc_fb_get_temp_index(struct mxc_epdc_fb_data *fb_data, int temp)
+{
+ int i;
+ int index = -1;
+
+ if (fb_data->trt_entries == 0) {
+ dev_err(fb_data->dev,
+ "No TRT exists...using default temp index\n");
+ return DEFAULT_TEMP_INDEX;
+ }
+
+ /* Search temperature ranges for a match */
+ for (i = 0; i < fb_data->trt_entries - 1; i++) {
+ if ((temp >= fb_data->temp_range_bounds[i])
+ && (temp < fb_data->temp_range_bounds[i+1])) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index < 0) {
+ dev_err(fb_data->dev,
+ "No TRT index match...using default temp index\n");
+ return DEFAULT_TEMP_INDEX;
+ }
+
+ dev_dbg(fb_data->dev, "Using temperature index %d\n", index);
+
+ return index;
+}
+
+static int mxc_epdc_fb_set_temperature(int temperature, struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+
+ /* Store temp index. Used later when configuring updates. */
+ mutex_lock(&fb_data->queue_mutex);
+ fb_data->temp_index = mxc_epdc_fb_get_temp_index(fb_data, temperature);
+ mutex_unlock(&fb_data->queue_mutex);
+
+ return 0;
+}
+
+static int mxc_epdc_fb_set_auto_update(u32 auto_mode, struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+
+ dev_dbg(fb_data->dev, "Setting auto update mode to %d\n", auto_mode);
+
+ if ((auto_mode == AUTO_UPDATE_MODE_AUTOMATIC_MODE)
+ || (auto_mode == AUTO_UPDATE_MODE_REGION_MODE))
+ fb_data->auto_mode = auto_mode;
+ else {
+ dev_err(fb_data->dev, "Invalid auto update mode parameter.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mxc_epdc_fb_set_upd_scheme(u32 upd_scheme, struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+
+ dev_dbg(fb_data->dev, "Setting optimization level to %d\n", upd_scheme);
+
+ /*
+ * Can't change the scheme until current updates have completed.
+ * This function returns when all active updates are done.
+ */
+ mxc_epdc_fb_flush_updates(fb_data);
+
+ if ((upd_scheme == UPDATE_SCHEME_SNAPSHOT)
+ || (upd_scheme == UPDATE_SCHEME_QUEUE)
+ || (upd_scheme == UPDATE_SCHEME_QUEUE_AND_MERGE))
+ fb_data->upd_scheme = upd_scheme;
+ else {
+ dev_err(fb_data->dev, "Invalid update scheme specified.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void copy_before_process(struct mxc_epdc_fb_data *fb_data,
+ struct update_data_list *upd_data_list)
+{
+ struct mxcfb_update_data *upd_data =
+ &upd_data_list->update_desc->upd_data;
+ int i;
+ unsigned char *temp_buf_ptr = fb_data->virt_addr_copybuf;
+ unsigned char *src_ptr;
+ struct mxcfb_rect *src_upd_region;
+ int temp_buf_stride;
+ int src_stride;
+ int bpp = fb_data->epdc_fb_var.bits_per_pixel;
+ int left_offs, right_offs;
+ int x_trailing_bytes, y_trailing_bytes;
+ int alt_buf_offset;
+
+ /* Set source buf pointer based on input source, panning, etc. */
+ if (upd_data->flags & EPDC_FLAG_USE_ALT_BUFFER) {
+ src_upd_region = &upd_data->alt_buffer_data.alt_update_region;
+ src_stride =
+ upd_data->alt_buffer_data.width * bpp/8;
+ alt_buf_offset = upd_data->alt_buffer_data.phys_addr -
+ fb_data->info.fix.smem_start;
+ src_ptr = fb_data->info.screen_base + alt_buf_offset
+ + src_upd_region->top * src_stride;
+ } else {
+ src_upd_region = &upd_data->update_region;
+ src_stride = fb_data->epdc_fb_var.xres_virtual * bpp/8;
+ src_ptr = fb_data->info.screen_base + fb_data->fb_offset
+ + src_upd_region->top * src_stride;
+ }
+
+ temp_buf_stride = ALIGN(src_upd_region->width, 8) * bpp/8;
+ left_offs = src_upd_region->left * bpp/8;
+ right_offs = src_upd_region->width * bpp/8;
+ x_trailing_bytes = (ALIGN(src_upd_region->width, 8)
+ - src_upd_region->width) * bpp/8;
+
+ for (i = 0; i < src_upd_region->height; i++) {
+ /* Copy the full line */
+ memcpy(temp_buf_ptr, src_ptr + left_offs,
+ src_upd_region->width * bpp/8);
+
+ /* Clear any unwanted pixels at the end of each line */
+ if (src_upd_region->width & 0x7) {
+ memset(temp_buf_ptr + right_offs, 0x0,
+ x_trailing_bytes);
+ }
+
+ temp_buf_ptr += temp_buf_stride;
+ src_ptr += src_stride;
+ }
+
+ /* Clear any unwanted pixels at the bottom of the end of each line */
+ if (src_upd_region->height & 0x7) {
+ y_trailing_bytes = (ALIGN(src_upd_region->height, 8)
+ - src_upd_region->height) *
+ ALIGN(src_upd_region->width, 8) * bpp/8;
+ memset(temp_buf_ptr, 0x0, y_trailing_bytes);
+ }
+}
+
+/* Before every update to panel, we should call this
+ * function to update the working buffer first.
+ */
+static int epdc_working_buffer_update(struct mxc_epdc_fb_data *fb_data,
+ struct update_data_list *upd_data_list,
+ struct mxcfb_rect *update_region)
+{
+ struct pxp_proc_data *proc_data = &fb_data->pxp_conf.proc_data;
+ u32 wv_mode = upd_data_list->update_desc->upd_data.waveform_mode;
+ int ret = 0;
+ u32 hist_stat;
+ struct update_desc_list *upd_desc_list;
+
+ ret = pxp_wfe_a_process(fb_data, update_region, upd_data_list);
+ if (ret) {
+ dev_err(fb_data->dev, "Unable to submit PxP update task.\n");
+ mutex_unlock(&fb_data->pxp_mutex);
+ return ret;
+ }
+
+ /* If needed, enable EPDC HW while ePxP is processing */
+ if ((fb_data->power_state == POWER_STATE_OFF)
+ || fb_data->powering_down) {
+ epdc_powerup(fb_data);
+ }
+
+ /* This is a blocking call, so upon return PxP tx should be done */
+ ret = pxp_complete_update(fb_data, &fb_data->hist_status);
+ if (ret) {
+ dev_err(fb_data->dev, "Unable to complete PxP update task: main process\n");
+ return ret;
+ }
+
+ upd_desc_list = upd_data_list->update_desc;
+ if (fb_data->epdc_wb_mode &&
+ (upd_desc_list->upd_data.waveform_mode == WAVEFORM_MODE_AUTO)) {
+ hist_stat = fb_data->hist_status;
+
+ if (hist_stat & 0x1)
+ upd_desc_list->upd_data.waveform_mode =
+ fb_data->wv_modes.mode_du;
+ else if (hist_stat & 0x2)
+ upd_desc_list->upd_data.waveform_mode =
+ fb_data->wv_modes.mode_gc4;
+ else if (hist_stat & 0x4)
+ upd_desc_list->upd_data.waveform_mode =
+ fb_data->wv_modes.mode_gc8;
+ else if (hist_stat & 0x8)
+ upd_desc_list->upd_data.waveform_mode =
+ fb_data->wv_modes.mode_gc16;
+ else
+ upd_desc_list->upd_data.waveform_mode =
+ fb_data->wv_modes.mode_gc32;
+
+ dev_dbg(fb_data->dev, "hist_stat = 0x%x, new waveform = 0x%x\n",
+ hist_stat, upd_desc_list->upd_data.waveform_mode);
+ }
+
+ if (proc_data->detection_only == 1) {
+ dev_dbg(fb_data->dev, "collision detection only, no real update\n");
+ return 0;
+ }
+
+ if (fb_data->col_info.pixel_cnt) {
+ dev_dbg(fb_data->dev, "collision detected, can not do REAGl/-D\n");
+ return 0;
+ }
+
+ /* for REAGL/-D Processing */
+ if (wv_mode == WAVEFORM_MODE_GLR16
+ || wv_mode == WAVEFORM_MODE_GLD16) {
+ /* This is a blocking call, so upon return PxP tx should be done */
+ ret = pxp_wfe_b_process_update(fb_data, update_region);
+ if (ret) {
+ dev_err(fb_data->dev, "Unable to submit PxP update task.\n");
+ mutex_unlock(&fb_data->pxp_mutex);
+ return ret;
+ }
+
+ /* If needed, enable EPDC HW while ePxP is processing */
+ if ((fb_data->power_state == POWER_STATE_OFF)
+ || fb_data->powering_down) {
+ epdc_powerup(fb_data);
+ }
+
+ /* This is a blocking call, so upon return PxP tx should be done */
+ ret = pxp_complete_update(fb_data, &hist_stat);
+ if (ret) {
+ dev_err(fb_data->dev, "Unable to complete PxP update task: reagl/-d process\n");
+ mutex_unlock(&fb_data->pxp_mutex);
+ return ret;
+ }
+
+ }
+
+ return 0;
+}
+
+static int epdc_process_update(struct update_data_list *upd_data_list,
+ struct mxc_epdc_fb_data *fb_data)
+{
+ struct mxcfb_rect *src_upd_region; /* Region of src buffer for update */
+ struct mxcfb_rect pxp_upd_region;
+ u32 src_width, src_height;
+ u32 offset_from_4, bytes_per_pixel;
+ u32 post_rotation_xcoord, post_rotation_ycoord, width_pxp_blocks;
+ u32 pxp_input_offs, pxp_output_offs, pxp_output_shift;
+ u32 hist_stat = 0;
+ int width_unaligned, height_unaligned;
+ bool input_unaligned = false;
+ bool line_overflow = false;
+ int pix_per_line_added;
+ bool use_temp_buf = false;
+ struct mxcfb_rect temp_buf_upd_region;
+ struct update_desc_list *upd_desc_list = upd_data_list->update_desc;
+
+ int ret;
+
+ /*
+ * Gotta do a whole bunch of buffer ptr manipulation to
+ * work around HW restrictions for PxP & EPDC
+ * Note: Applies to pre-2.0 versions of EPDC/PxP
+ */
+
+ /*
+ * Are we using FB or an alternate (overlay)
+ * buffer for source of update?
+ */
+ if (upd_desc_list->upd_data.flags & EPDC_FLAG_USE_ALT_BUFFER) {
+ src_width = upd_desc_list->upd_data.alt_buffer_data.width;
+ src_height = upd_desc_list->upd_data.alt_buffer_data.height;
+ src_upd_region = &upd_desc_list->upd_data.alt_buffer_data.alt_update_region;
+ } else {
+ src_width = fb_data->epdc_fb_var.xres_virtual;
+ src_height = fb_data->epdc_fb_var.yres;
+ src_upd_region = &upd_desc_list->upd_data.update_region;
+ }
+
+ bytes_per_pixel = fb_data->epdc_fb_var.bits_per_pixel/8;
+
+ /*
+ * SW workaround for PxP limitation (for pre-v2.0 HW)
+ *
+ * There are 3 cases where we cannot process the update data
+ * directly from the input buffer:
+ *
+ * 1) PxP must process 8x8 pixel blocks, and all pixels in each block
+ * are considered for auto-waveform mode selection. If the
+ * update region is not 8x8 aligned, additional unwanted pixels
+ * will be considered in auto-waveform mode selection.
+ *
+ * 2) PxP input must be 32-bit aligned, so any update
+ * address not 32-bit aligned must be shifted to meet the
+ * 32-bit alignment. The PxP will thus end up processing pixels
+ * outside of the update region to satisfy this alignment restriction,
+ * which can affect auto-waveform mode selection.
+ *
+ * 3) If input fails 32-bit alignment, and the resulting expansion
+ * of the processed region would add at least 8 pixels more per
+ * line than the original update line width, the EPDC would
+ * cause screen artifacts by incorrectly handling the 8+ pixels
+ * at the end of each line.
+ *
+ * Workaround is to copy from source buffer into a temporary
+ * buffer, which we pad with zeros to match the 8x8 alignment
+ * requirement. This temp buffer becomes the input to the PxP.
+ */
+ width_unaligned = src_upd_region->width & 0x7;
+ height_unaligned = src_upd_region->height & 0x7;
+
+ offset_from_4 = src_upd_region->left & 0x3;
+ input_unaligned = ((offset_from_4 * bytes_per_pixel % 4) != 0) ?
+ true : false;
+
+ pix_per_line_added = (offset_from_4 * bytes_per_pixel % 4)
+ / bytes_per_pixel;
+ if ((((fb_data->epdc_fb_var.rotate == FB_ROTATE_UR) ||
+ fb_data->epdc_fb_var.rotate == FB_ROTATE_UD)) &&
+ (ALIGN(src_upd_region->width, 8) <
+ ALIGN(src_upd_region->width + pix_per_line_added, 8)))
+ line_overflow = true;
+
+ /* Grab pxp_mutex here so that we protect access
+ * to copybuf in addition to the PxP structures */
+ mutex_lock(&fb_data->pxp_mutex);
+
+ if (((((width_unaligned || height_unaligned || input_unaligned) &&
+ (upd_desc_list->upd_data.waveform_mode == WAVEFORM_MODE_AUTO))
+ || line_overflow) && (fb_data->rev < 20)) ||
+ fb_data->restrict_width) {
+ dev_dbg(fb_data->dev, "Copying update before processing.\n");
+
+ /* Update to reflect what the new source buffer will be */
+ src_width = ALIGN(src_upd_region->width, 8);
+ src_height = ALIGN(src_upd_region->height, 8);
+
+ copy_before_process(fb_data, upd_data_list);
+
+ /*
+ * src_upd_region should now describe
+ * the new update buffer attributes.
+ */
+ temp_buf_upd_region.left = 0;
+ temp_buf_upd_region.top = 0;
+ temp_buf_upd_region.width = src_upd_region->width;
+ temp_buf_upd_region.height = src_upd_region->height;
+ src_upd_region = &temp_buf_upd_region;
+
+ use_temp_buf = true;
+ }
+
+ /*
+ * For pre-2.0 HW, input address must be 32-bit aligned
+ * Compute buffer offset to account for this PxP limitation
+ */
+ offset_from_4 = src_upd_region->left & 0x3;
+ input_unaligned = ((offset_from_4 * bytes_per_pixel % 4) != 0) ?
+ true : false;
+ if ((fb_data->rev < 20) && input_unaligned) {
+ /* Leave a gap between PxP input addr and update region pixels */
+ pxp_input_offs =
+ (src_upd_region->top * src_width + src_upd_region->left)
+ * bytes_per_pixel & 0xFFFFFFFC;
+ /* Update region left changes to reflect relative position to input ptr */
+ pxp_upd_region.left = (offset_from_4 * bytes_per_pixel % 4)
+ / bytes_per_pixel;
+ } else {
+ pxp_input_offs =
+ (src_upd_region->top * src_width + src_upd_region->left)
+ * bytes_per_pixel;
+ pxp_upd_region.left = 0;
+ }
+
+ pxp_upd_region.top = 0;
+
+ /*
+ * For version 2.0 and later of EPDC & PxP, if no rotation, we don't
+ * need to align width & height (rotation always requires 8-pixel
+ * width & height alignment, per PxP limitations)
+ */
+ if ((fb_data->epdc_fb_var.rotate == 0) && (fb_data->rev >= 20)) {
+ pxp_upd_region.width = src_upd_region->width;
+ pxp_upd_region.height = src_upd_region->height;
+ } else {
+ /* Update region dimensions to meet 8x8 pixel requirement */
+ pxp_upd_region.width = ALIGN(src_upd_region->width + pxp_upd_region.left, 8);
+ pxp_upd_region.height = ALIGN(src_upd_region->height, 8);
+ }
+
+ switch (fb_data->epdc_fb_var.rotate) {
+ case FB_ROTATE_UR:
+ default:
+ post_rotation_xcoord = pxp_upd_region.left;
+ post_rotation_ycoord = pxp_upd_region.top;
+ width_pxp_blocks = pxp_upd_region.width;
+ break;
+ case FB_ROTATE_CW:
+ width_pxp_blocks = pxp_upd_region.height;
+ post_rotation_xcoord = width_pxp_blocks - src_upd_region->height;
+ post_rotation_ycoord = pxp_upd_region.left;
+ break;
+ case FB_ROTATE_UD:
+ width_pxp_blocks = pxp_upd_region.width;
+ post_rotation_xcoord = width_pxp_blocks - src_upd_region->width - pxp_upd_region.left;
+ post_rotation_ycoord = pxp_upd_region.height - src_upd_region->height - pxp_upd_region.top;
+ break;
+ case FB_ROTATE_CCW:
+ width_pxp_blocks = pxp_upd_region.height;
+ post_rotation_xcoord = pxp_upd_region.top;
+ post_rotation_ycoord = pxp_upd_region.width - src_upd_region->width - pxp_upd_region.left;
+ break;
+ }
+
+ /* Update region start coord to force PxP to process full 8x8 regions */
+ pxp_upd_region.top &= ~0x7;
+ pxp_upd_region.left &= ~0x7;
+
+ if (fb_data->rev < 20) {
+ pxp_output_shift = ALIGN(post_rotation_xcoord, 8)
+ - post_rotation_xcoord;
+
+ pxp_output_offs = post_rotation_ycoord * width_pxp_blocks
+ + pxp_output_shift;
+
+ upd_desc_list->epdc_offs = ALIGN(pxp_output_offs, 8);
+ } else {
+ pxp_output_shift = 0;
+ pxp_output_offs = post_rotation_ycoord * width_pxp_blocks
+ + post_rotation_xcoord;
+
+ upd_desc_list->epdc_offs = pxp_output_offs;
+ }
+
+ upd_desc_list->epdc_stride = width_pxp_blocks;
+
+ /* Source address either comes from alternate buffer
+ provided in update data, or from the framebuffer. */
+ if (use_temp_buf)
+ sg_dma_address(&fb_data->sg[0]) =
+ fb_data->phys_addr_copybuf;
+ else if (upd_desc_list->upd_data.flags & EPDC_FLAG_USE_ALT_BUFFER)
+ sg_dma_address(&fb_data->sg[0]) =
+ upd_desc_list->upd_data.alt_buffer_data.phys_addr
+ + pxp_input_offs;
+ else {
+ sg_dma_address(&fb_data->sg[0]) =
+ fb_data->info.fix.smem_start + fb_data->fb_offset
+ + pxp_input_offs;
+ sg_set_page(&fb_data->sg[0],
+ virt_to_page(fb_data->info.screen_base),
+ fb_data->info.fix.smem_len,
+ offset_in_page(fb_data->info.screen_base));
+ }
+
+ /* Update sg[1] to point to output of PxP proc task */
+ sg_dma_address(&fb_data->sg[1]) = upd_data_list->phys_addr
+ + pxp_output_shift;
+ sg_set_page(&fb_data->sg[1], virt_to_page(upd_data_list->virt_addr),
+ fb_data->max_pix_size,
+ offset_in_page(upd_data_list->virt_addr));
+
+ /*
+ * Set PxP LUT transform type based on update flags.
+ */
+ fb_data->pxp_conf.proc_data.lut_transform = 0;
+ if (upd_desc_list->upd_data.flags & EPDC_FLAG_ENABLE_INVERSION)
+ fb_data->pxp_conf.proc_data.lut_transform |= PXP_LUT_INVERT;
+ if (upd_desc_list->upd_data.flags & EPDC_FLAG_FORCE_MONOCHROME)
+ fb_data->pxp_conf.proc_data.lut_transform |=
+ PXP_LUT_BLACK_WHITE;
+ if (upd_desc_list->upd_data.flags & EPDC_FLAG_USE_CMAP)
+ fb_data->pxp_conf.proc_data.lut_transform |=
+ PXP_LUT_USE_CMAP;
+
+ /*
+ * Toggle inversion processing if 8-bit
+ * inverted is the current pixel format.
+ */
+ if (fb_data->epdc_fb_var.grayscale == GRAYSCALE_8BIT_INVERTED)
+ fb_data->pxp_conf.proc_data.lut_transform ^= PXP_LUT_INVERT;
+
+#ifdef USE_PS_AS_OUTPUT
+ /* This is a blocking call, so upon return PxP tx should be done */
+ ret = pxp_legacy_process(fb_data, src_width, src_height,
+ &pxp_upd_region);
+ if (ret) {
+ dev_err(fb_data->dev, "Unable to submit PxP update task.\n");
+ mutex_unlock(&fb_data->pxp_mutex);
+ return ret;
+ }
+
+ /* If needed, enable EPDC HW while ePxP is processing */
+ if ((fb_data->power_state == POWER_STATE_OFF)
+ || fb_data->powering_down) {
+ epdc_powerup(fb_data);
+ }
+
+ /* This is a blocking call, so upon return PxP tx should be done */
+ ret = pxp_complete_update(fb_data, &hist_stat);
+ if (ret) {
+ dev_err(fb_data->dev, "Unable to complete PxP update task: pre_prcoess.\n");
+ mutex_unlock(&fb_data->pxp_mutex);
+ return ret;
+ }
+#endif
+ pr_debug(" upd_data.dither_mode %d \n", upd_desc_list->upd_data.dither_mode);
+ fb_data->pxp_conf.proc_data.dither_mode = 0;
+
+ /* Dithering */
+ if ((EPDC_FLAG_USE_DITHERING_PASSTHROUGH < upd_desc_list->upd_data.dither_mode) &&
+ (upd_desc_list->upd_data.dither_mode < EPDC_FLAG_USE_DITHERING_MAX)) {
+
+ fb_data->pxp_conf.proc_data.dither_mode = upd_desc_list->upd_data.dither_mode;
+ fb_data->pxp_conf.proc_data.quant_bit = upd_desc_list->upd_data.quant_bit;
+
+ /* This is a blocking call, so upon return PxP tx should be done */
+ ret = pxp_process_dithering(fb_data, &pxp_upd_region);
+ if (ret) {
+ dev_err(fb_data->dev, "Unable to submit PxP update task.\n");
+ mutex_unlock(&fb_data->pxp_mutex);
+ return ret;
+ }
+
+ /* If needed, enable EPDC HW while ePxP is processing */
+ if ((fb_data->power_state == POWER_STATE_OFF)
+ || fb_data->powering_down) {
+ epdc_powerup(fb_data);
+ }
+
+ /* This is a blocking call, so upon return PxP tx should be done */
+ ret = pxp_complete_update(fb_data, &hist_stat);
+ if (ret) {
+ dev_err(fb_data->dev, "Unable to complete PxP update task: dithering process\n");
+ mutex_unlock(&fb_data->pxp_mutex);
+ return ret;
+ }
+
+ }
+
+ /* Regal D Processing */
+ fb_data->pxp_conf.proc_data.reagl_d_en =
+ (upd_desc_list->upd_data.waveform_mode == WAVEFORM_MODE_GLD16);
+
+ mutex_unlock(&fb_data->pxp_mutex);
+
+ /* Update waveform mode from PxP histogram results */
+ if ((fb_data->rev <= 20) &&
+ (upd_desc_list->upd_data.waveform_mode == WAVEFORM_MODE_AUTO)) {
+ if (hist_stat & 0x1)
+ upd_desc_list->upd_data.waveform_mode =
+ fb_data->wv_modes.mode_du;
+ else if (hist_stat & 0x2)
+ upd_desc_list->upd_data.waveform_mode =
+ fb_data->wv_modes.mode_gc4;
+ else if (hist_stat & 0x4)
+ upd_desc_list->upd_data.waveform_mode =
+ fb_data->wv_modes.mode_gc8;
+ else if (hist_stat & 0x8)
+ upd_desc_list->upd_data.waveform_mode =
+ fb_data->wv_modes.mode_gc16;
+ else
+ upd_desc_list->upd_data.waveform_mode =
+ fb_data->wv_modes.mode_gc32;
+
+ dev_dbg(fb_data->dev, "hist_stat = 0x%x, new waveform = 0x%x\n",
+ hist_stat, upd_desc_list->upd_data.waveform_mode);
+ }
+
+ return 0;
+}
+
+static int epdc_submit_merge(struct update_desc_list *upd_desc_list,
+ struct update_desc_list *update_to_merge,
+ struct mxc_epdc_fb_data *fb_data)
+{
+ struct mxcfb_update_data *a, *b;
+ struct mxcfb_rect *arect, *brect;
+ struct mxcfb_rect combine;
+ bool use_flags = false;
+
+ a = &upd_desc_list->upd_data;
+ b = &update_to_merge->upd_data;
+ arect = &upd_desc_list->upd_data.update_region;
+ brect = &update_to_merge->upd_data.update_region;
+
+ /* Do not merge a dry-run collision test update */
+ if ((a->flags & EPDC_FLAG_TEST_COLLISION) ||
+ (b->flags & EPDC_FLAG_TEST_COLLISION))
+ return MERGE_BLOCK;
+
+ /*
+ * Updates with different flags must be executed sequentially.
+ * Halt the merge process to ensure this.
+ */
+ if (a->flags != b->flags) {
+ /*
+ * Special exception: if update regions are identical,
+ * we may be able to merge them.
+ */
+ if ((arect->left != brect->left) ||
+ (arect->top != brect->top) ||
+ (arect->width != brect->width) ||
+ (arect->height != brect->height))
+ return MERGE_BLOCK;
+
+ use_flags = true;
+ }
+
+ if (a->update_mode != b->update_mode)
+ a->update_mode = UPDATE_MODE_FULL;
+
+ if (a->waveform_mode != b->waveform_mode)
+ a->waveform_mode = WAVEFORM_MODE_AUTO;
+
+ if (arect->left > (brect->left + brect->width) ||
+ brect->left > (arect->left + arect->width) ||
+ arect->top > (brect->top + brect->height) ||
+ brect->top > (arect->top + arect->height))
+ return MERGE_FAIL;
+
+ combine.left = arect->left < brect->left ? arect->left : brect->left;
+ combine.top = arect->top < brect->top ? arect->top : brect->top;
+ combine.width = (arect->left + arect->width) >
+ (brect->left + brect->width) ?
+ (arect->left + arect->width - combine.left) :
+ (brect->left + brect->width - combine.left);
+ combine.height = (arect->top + arect->height) >
+ (brect->top + brect->height) ?
+ (arect->top + arect->height - combine.top) :
+ (brect->top + brect->height - combine.top);
+
+ /* Don't merge if combined width exceeds max width */
+ if (fb_data->restrict_width) {
+ u32 max_width = EPDC_V2_MAX_UPDATE_WIDTH;
+ u32 combined_width = combine.width;
+ if (fb_data->epdc_fb_var.rotate != FB_ROTATE_UR)
+ max_width -= EPDC_V2_ROTATION_ALIGNMENT;
+ if ((fb_data->epdc_fb_var.rotate == FB_ROTATE_CW) ||
+ (fb_data->epdc_fb_var.rotate == FB_ROTATE_CCW))
+ combined_width = combine.height;
+ if (combined_width > max_width)
+ return MERGE_FAIL;
+ }
+
+ *arect = combine;
+
+ /* Use flags of the later update */
+ if (use_flags)
+ a->flags = b->flags;
+
+ /* Merge markers */
+ list_splice_tail(&update_to_merge->upd_marker_list,
+ &upd_desc_list->upd_marker_list);
+
+ /* Merged update should take on the earliest order */
+ upd_desc_list->update_order =
+ (upd_desc_list->update_order > update_to_merge->update_order) ?
+ upd_desc_list->update_order : update_to_merge->update_order;
+
+ return MERGE_OK;
+}
+
+static void epdc_submit_work_func(struct work_struct *work)
+{
+ int temp_index;
+ struct update_data_list *next_update, *temp_update;
+ struct update_desc_list *next_desc, *temp_desc;
+ struct update_marker_data *next_marker, *temp_marker;
+ struct mxc_epdc_fb_data *fb_data =
+ container_of(work, struct mxc_epdc_fb_data, epdc_submit_work);
+ struct pxp_config_data *pxp_conf = &fb_data->pxp_conf;
+ struct pxp_proc_data *proc_data = &pxp_conf->proc_data;
+ struct update_data_list *upd_data_list = NULL;
+ struct mxcfb_rect adj_update_region, *upd_region;
+ bool end_merge = false;
+ bool is_transform;
+ u32 update_addr;
+ int *err_dist;
+ int ret;
+
+ /* Protect access to buffer queues and to update HW */
+ mutex_lock(&fb_data->queue_mutex);
+
+ /*
+ * Are any of our collision updates able to go now?
+ * Go through all updates in the collision list and check to see
+ * if the collision mask has been fully cleared
+ */
+ list_for_each_entry_safe(next_update, temp_update,
+ &fb_data->upd_buf_collision_list, list) {
+
+ if (next_update->collision_mask != 0)
+ continue;
+
+ dev_dbg(fb_data->dev, "A collision update is ready to go!\n");
+
+ /* Force waveform mode to auto for resubmitted collisions */
+ next_update->update_desc->upd_data.waveform_mode =
+ WAVEFORM_MODE_AUTO;
+
+ /*
+ * We have a collision cleared, so select it for resubmission.
+ * If an update is already selected, attempt to merge.
+ */
+ if (!upd_data_list) {
+ upd_data_list = next_update;
+ list_del_init(&next_update->list);
+ if (fb_data->upd_scheme == UPDATE_SCHEME_QUEUE)
+ /* If not merging, we have our update */
+ break;
+ } else {
+ switch (epdc_submit_merge(upd_data_list->update_desc,
+ next_update->update_desc,
+ fb_data)) {
+ case MERGE_OK:
+ dev_dbg(fb_data->dev,
+ "Update merged [collision]\n");
+ list_del_init(&next_update->update_desc->list);
+ kfree(next_update->update_desc);
+ next_update->update_desc = NULL;
+ list_del_init(&next_update->list);
+ /* Add to free buffer list */
+ list_add_tail(&next_update->list,
+ &fb_data->upd_buf_free_list);
+ break;
+ case MERGE_FAIL:
+ dev_dbg(fb_data->dev,
+ "Update not merged [collision]\n");
+ break;
+ case MERGE_BLOCK:
+ dev_dbg(fb_data->dev,
+ "Merge blocked [collision]\n");
+ end_merge = true;
+ break;
+ }
+
+ if (end_merge) {
+ end_merge = false;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Skip pending update list only if we found a collision
+ * update and we are not merging
+ */
+ if (!((fb_data->upd_scheme == UPDATE_SCHEME_QUEUE) &&
+ upd_data_list)) {
+ /*
+ * If we didn't find a collision update ready to go, we
+ * need to get a free buffer and match it to a pending update.
+ */
+
+ /*
+ * Can't proceed if there are no free buffers (and we don't
+ * already have a collision update selected)
+ */
+ if (!upd_data_list &&
+ list_empty(&fb_data->upd_buf_free_list)) {
+ mutex_unlock(&fb_data->queue_mutex);
+ return;
+ }
+
+ list_for_each_entry_safe(next_desc, temp_desc,
+ &fb_data->upd_pending_list, list) {
+
+ dev_dbg(fb_data->dev, "Found a pending update!\n");
+
+ if (!upd_data_list) {
+ if (list_empty(&fb_data->upd_buf_free_list))
+ break;
+ upd_data_list =
+ list_entry(fb_data->upd_buf_free_list.next,
+ struct update_data_list, list);
+ list_del_init(&upd_data_list->list);
+ upd_data_list->update_desc = next_desc;
+ list_del_init(&next_desc->list);
+ if (fb_data->upd_scheme == UPDATE_SCHEME_QUEUE)
+ /* If not merging, we have an update */
+ break;
+ } else {
+ switch (epdc_submit_merge(upd_data_list->update_desc,
+ next_desc, fb_data)) {
+ case MERGE_OK:
+ dev_dbg(fb_data->dev,
+ "Update merged [queue]\n");
+ list_del_init(&next_desc->list);
+ kfree(next_desc);
+ break;
+ case MERGE_FAIL:
+ dev_dbg(fb_data->dev,
+ "Update not merged [queue]\n");
+ break;
+ case MERGE_BLOCK:
+ dev_dbg(fb_data->dev,
+ "Merge blocked [collision]\n");
+ end_merge = true;
+ break;
+ }
+
+ if (end_merge)
+ break;
+ }
+ }
+ }
+
+ /* Is update list empty? */
+ if (!upd_data_list) {
+ mutex_unlock(&fb_data->queue_mutex);
+ return;
+ }
+
+ /*
+ * If no processing required, skip update processing
+ * No processing means:
+ * - FB unrotated
+ * - FB pixel format = 8-bit grayscale
+ * - No look-up transformations (inversion, posterization, etc.)
+ * - No scaling/flip
+ */
+ is_transform = ((upd_data_list->update_desc->upd_data.flags &
+ (EPDC_FLAG_ENABLE_INVERSION | EPDC_FLAG_USE_DITHERING_Y1 |
+ EPDC_FLAG_USE_DITHERING_Y4 | EPDC_FLAG_FORCE_MONOCHROME |
+ EPDC_FLAG_USE_CMAP)) && (proc_data->scaling == 0) &&
+ (proc_data->hflip == 0) && (proc_data->vflip == 0)) ?
+ true : false;
+
+ /*XXX if we use external mode, we should first use pxp
+ * to update upd buffer data to working buffer first.
+ */
+ if ((fb_data->epdc_fb_var.rotate == FB_ROTATE_UR) &&
+ (fb_data->epdc_fb_var.grayscale == GRAYSCALE_8BIT) &&
+ !is_transform && (proc_data->dither_mode == 0) &&
+ !fb_data->restrict_width) {
+
+ /* If needed, enable EPDC HW while ePxP is processing */
+ if ((fb_data->power_state == POWER_STATE_OFF)
+ || fb_data->powering_down)
+ epdc_powerup(fb_data);
+
+ /*
+ * Set update buffer pointer to the start of
+ * the update region in the frame buffer.
+ */
+ upd_region = &upd_data_list->update_desc->upd_data.update_region;
+ update_addr = fb_data->info.fix.smem_start +
+ ((upd_region->top * fb_data->info.var.xres_virtual) +
+ upd_region->left) * fb_data->info.var.bits_per_pixel/8;
+ upd_data_list->update_desc->epdc_stride =
+ fb_data->info.var.xres_virtual *
+ fb_data->info.var.bits_per_pixel/8;
+ } else {
+ /* Select from PxP output buffers */
+ upd_data_list->phys_addr =
+ fb_data->phys_addr_updbuf[fb_data->upd_buffer_num];
+ upd_data_list->virt_addr =
+ fb_data->virt_addr_updbuf[fb_data->upd_buffer_num];
+ fb_data->upd_buffer_num++;
+ if (fb_data->upd_buffer_num > fb_data->max_num_buffers-1)
+ fb_data->upd_buffer_num = 0;
+
+ /* Release buffer queues */
+ mutex_unlock(&fb_data->queue_mutex);
+
+ /* Perform PXP processing - EPDC power will also be enabled */
+ if (epdc_process_update(upd_data_list, fb_data)) {
+ dev_dbg(fb_data->dev, "PXP processing error.\n");
+ /* Protect access to buffer queues and to update HW */
+ mutex_lock(&fb_data->queue_mutex);
+ list_del_init(&upd_data_list->update_desc->list);
+ kfree(upd_data_list->update_desc);
+ upd_data_list->update_desc = NULL;
+ /* Add to free buffer list */
+ list_add_tail(&upd_data_list->list,
+ &fb_data->upd_buf_free_list);
+ /* Release buffer queues */
+ mutex_unlock(&fb_data->queue_mutex);
+ return;
+ }
+
+ /* Protect access to buffer queues and to update HW */
+ mutex_lock(&fb_data->queue_mutex);
+
+ update_addr = upd_data_list->phys_addr
+ + upd_data_list->update_desc->epdc_offs;
+ }
+
+ /* Get rotation-adjusted coordinates */
+ adjust_coordinates(fb_data->epdc_fb_var.xres,
+ fb_data->epdc_fb_var.yres, fb_data->epdc_fb_var.rotate,
+ &upd_data_list->update_desc->upd_data.update_region,
+ &adj_update_region);
+
+ /*
+ * Is the working buffer idle?
+ * If the working buffer is busy, we must wait for the resource
+ * to become free. The IST will signal this event.
+ */
+ if (fb_data->cur_update != NULL) {
+ dev_dbg(fb_data->dev, "working buf busy!\n");
+
+ /* Initialize event signalling an update resource is free */
+ init_completion(&fb_data->update_res_free);
+
+ fb_data->waiting_for_wb = true;
+
+ /* Leave spinlock while waiting for WB to complete */
+ mutex_unlock(&fb_data->queue_mutex);
+ wait_for_completion(&fb_data->update_res_free);
+ mutex_lock(&fb_data->queue_mutex);
+ }
+
+ /*
+ * Dithering Processing (Version 1.0 - for i.MX508 and i.MX6SL)
+ */
+ if (upd_data_list->update_desc->upd_data.flags &
+ EPDC_FLAG_USE_DITHERING_Y1) {
+
+ err_dist = kzalloc((fb_data->info.var.xres_virtual + 3) * 3
+ * sizeof(int), GFP_KERNEL);
+
+ /* Dithering Y8 -> Y1 */
+ do_dithering_processing_Y1_v1_0(
+ (uint8_t *)(upd_data_list->virt_addr +
+ upd_data_list->update_desc->epdc_offs),
+ upd_data_list->phys_addr +
+ upd_data_list->update_desc->epdc_offs,
+ &adj_update_region,
+ (fb_data->rev < 20) ?
+ ALIGN(adj_update_region.width, 8) :
+ adj_update_region.width,
+ err_dist);
+
+ kfree(err_dist);
+ } else if (upd_data_list->update_desc->upd_data.flags &
+ EPDC_FLAG_USE_DITHERING_Y4) {
+
+ err_dist = kzalloc((fb_data->info.var.xres_virtual + 3) * 3
+ * sizeof(int), GFP_KERNEL);
+
+ /* Dithering Y8 -> Y1 */
+ do_dithering_processing_Y4_v1_0(
+ (uint8_t *)(upd_data_list->virt_addr +
+ upd_data_list->update_desc->epdc_offs),
+ upd_data_list->phys_addr +
+ upd_data_list->update_desc->epdc_offs,
+ &adj_update_region,
+ (fb_data->rev < 20) ?
+ ALIGN(adj_update_region.width, 8) :
+ adj_update_region.width,
+ err_dist);
+
+ kfree(err_dist);
+ }
+
+ /*
+ * If there are no LUTs available,
+ * then we must wait for the resource to become free.
+ * The IST will signal this event.
+ */
+ {
+ bool luts_available;
+
+ luts_available = fb_data->epdc_wb_mode ? epdc_any_luts_real_available() :
+ epdc_any_luts_available();
+ if (!luts_available) {
+ dev_dbg(fb_data->dev, "no luts available!\n");
+
+ /* Initialize event signalling an update resource is free */
+ init_completion(&fb_data->update_res_free);
+
+ fb_data->waiting_for_lut = true;
+
+ /* Leave spinlock while waiting for LUT to free up */
+ mutex_unlock(&fb_data->queue_mutex);
+ wait_for_completion(&fb_data->update_res_free);
+ mutex_lock(&fb_data->queue_mutex);
+ }
+ }
+
+ ret = epdc_choose_next_lut(fb_data, &upd_data_list->lut_num);
+ /*
+ * If LUT15 is in use (for pre-EPDC v2.0 hardware):
+ * - Wait for LUT15 to complete is if TCE underrun prevent is enabled
+ * - If we go ahead with update, sync update submission with EOF
+ */
+ if (ret && fb_data->tce_prevent && (fb_data->rev < 20)) {
+ dev_dbg(fb_data->dev, "Waiting for LUT15\n");
+
+ /* Initialize event signalling that lut15 is free */
+ init_completion(&fb_data->lut15_free);
+
+ fb_data->waiting_for_lut15 = true;
+
+ /* Leave spinlock while waiting for LUT to free up */
+ mutex_unlock(&fb_data->queue_mutex);
+ wait_for_completion(&fb_data->lut15_free);
+ mutex_lock(&fb_data->queue_mutex);
+
+ epdc_choose_next_lut(fb_data, &upd_data_list->lut_num);
+ } else if (ret && (fb_data->rev < 20)) {
+ /* Synchronize update submission time to reduce
+ chances of TCE underrun */
+ init_completion(&fb_data->eof_event);
+
+ epdc_eof_intr(true);
+
+ /* Leave spinlock while waiting for EOF event */
+ mutex_unlock(&fb_data->queue_mutex);
+ ret = wait_for_completion_timeout(&fb_data->eof_event,
+ msecs_to_jiffies(1000));
+ if (!ret) {
+ dev_err(fb_data->dev, "Missed EOF event!\n");
+ epdc_eof_intr(false);
+ }
+ udelay(fb_data->eof_sync_period);
+ mutex_lock(&fb_data->queue_mutex);
+
+ }
+
+ /* LUTs are available, so we get one here */
+ fb_data->cur_update = upd_data_list;
+
+ /* Reset mask for LUTS that have completed during WB processing */
+ fb_data->luts_complete_wb = 0;
+
+ /* If we are just testing for collision, we don't assign a LUT,
+ * so we don't need to update LUT-related resources. */
+ if (!(upd_data_list->update_desc->upd_data.flags
+ & EPDC_FLAG_TEST_COLLISION)) {
+ /* Associate LUT with update marker */
+ list_for_each_entry_safe(next_marker, temp_marker,
+ &upd_data_list->update_desc->upd_marker_list, upd_list)
+ next_marker->lut_num = fb_data->cur_update->lut_num;
+
+ /* Mark LUT with order */
+ fb_data->lut_update_order[upd_data_list->lut_num] =
+ upd_data_list->update_desc->update_order;
+
+ epdc_lut_complete_intr(fb_data->rev, upd_data_list->lut_num,
+ true);
+ }
+
+ /* Enable Collision and WB complete IRQs */
+ epdc_working_buf_intr(true);
+
+ /* add working buffer update here for external mode */
+ if (fb_data->epdc_wb_mode)
+ ret = epdc_working_buffer_update(fb_data, upd_data_list,
+ &adj_update_region);
+
+ /* Program EPDC update to process buffer */
+ if (upd_data_list->update_desc->upd_data.temp != TEMP_USE_AMBIENT) {
+ temp_index = mxc_epdc_fb_get_temp_index(fb_data,
+ upd_data_list->update_desc->upd_data.temp);
+ epdc_set_temp(temp_index);
+ } else
+ epdc_set_temp(fb_data->temp_index);
+
+ epdc_set_update_addr(update_addr);
+ epdc_set_update_coord(adj_update_region.left, adj_update_region.top);
+ epdc_set_update_dimensions(adj_update_region.width,
+ adj_update_region.height);
+ if (fb_data->rev > 20)
+ epdc_set_update_stride(upd_data_list->update_desc->epdc_stride);
+ if (fb_data->wv_modes_update &&
+ (upd_data_list->update_desc->upd_data.waveform_mode
+ == WAVEFORM_MODE_AUTO)) {
+ epdc_set_update_waveform(&fb_data->wv_modes);
+ fb_data->wv_modes_update = false;
+ }
+
+ epdc_submit_update(upd_data_list->lut_num,
+ upd_data_list->update_desc->upd_data.waveform_mode,
+ upd_data_list->update_desc->upd_data.update_mode,
+ (upd_data_list->update_desc->upd_data.flags
+ & EPDC_FLAG_TEST_COLLISION) ? true : false,
+ false, 0);
+
+ /* Release buffer queues */
+ mutex_unlock(&fb_data->queue_mutex);
+}
+
+static int mxc_epdc_fb_send_single_update(struct mxcfb_update_data *upd_data,
+ struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+ struct update_data_list *upd_data_list = NULL;
+ struct mxcfb_rect *screen_upd_region; /* Region on screen to update */
+ int temp_index;
+ int ret;
+ struct update_desc_list *upd_desc;
+ struct update_marker_data *marker_data, *next_marker, *temp_marker;
+
+ /* Has EPDC HW been initialized? */
+ if (!fb_data->hw_ready) {
+ /* Throw message if we are not mid-initialization */
+ if (!fb_data->hw_initializing)
+ dev_err(fb_data->dev, "Display HW not properly"
+ "initialized. Aborting update.\n");
+ return -EPERM;
+ }
+
+ /* Check validity of update params */
+ if ((upd_data->update_mode != UPDATE_MODE_PARTIAL) &&
+ (upd_data->update_mode != UPDATE_MODE_FULL)) {
+ dev_err(fb_data->dev,
+ "Update mode 0x%x is invalid. Aborting update.\n",
+ upd_data->update_mode);
+ return -EINVAL;
+ }
+ if ((upd_data->waveform_mode > 255) &&
+ (upd_data->waveform_mode != WAVEFORM_MODE_AUTO)) {
+ dev_err(fb_data->dev,
+ "Update waveform mode 0x%x is invalid."
+ " Aborting update.\n",
+ upd_data->waveform_mode);
+ return -EINVAL;
+ }
+ if ((upd_data->update_region.left >= fb_data->epdc_fb_var.xres) ||
+ (upd_data->update_region.top >= fb_data->epdc_fb_var.yres) ||
+ (upd_data->update_region.width > fb_data->epdc_fb_var.xres) ||
+ (upd_data->update_region.height > fb_data->epdc_fb_var.yres) ||
+ (upd_data->update_region.left + upd_data->update_region.width > fb_data->epdc_fb_var.xres) ||
+ (upd_data->update_region.top + upd_data->update_region.height > fb_data->epdc_fb_var.yres)) {
+ dev_err(fb_data->dev,
+ "Update region is outside bounds of framebuffer."
+ "Aborting update.\n");
+ return -EINVAL;
+ }
+ if (upd_data->flags & EPDC_FLAG_USE_ALT_BUFFER) {
+ if ((upd_data->update_region.width !=
+ upd_data->alt_buffer_data.alt_update_region.width) ||
+ (upd_data->update_region.height !=
+ upd_data->alt_buffer_data.alt_update_region.height)) {
+ dev_err(fb_data->dev,
+ "Alternate update region dimensions must "
+ "match screen update region dimensions.\n");
+ return -EINVAL;
+ }
+ /* Validate physical address parameter */
+ if ((upd_data->alt_buffer_data.phys_addr <
+ fb_data->info.fix.smem_start) ||
+ (upd_data->alt_buffer_data.phys_addr >
+ fb_data->info.fix.smem_start + fb_data->map_size)) {
+ dev_err(fb_data->dev,
+ "Invalid physical address for alternate "
+ "buffer. Aborting update...\n");
+ return -EINVAL;
+ }
+ }
+
+ mutex_lock(&fb_data->queue_mutex);
+
+ /*
+ * If we are waiting to go into suspend, or the FB is blanked,
+ * we do not accept new updates
+ */
+ if ((fb_data->waiting_for_idle) ||
+ (fb_data->blank != FB_BLANK_UNBLANK)) {
+ dev_dbg(fb_data->dev, "EPDC not active."
+ "Update request abort.\n");
+ mutex_unlock(&fb_data->queue_mutex);
+ return -EPERM;
+ }
+
+ if (fb_data->upd_scheme == UPDATE_SCHEME_SNAPSHOT) {
+ int count = 0;
+ struct update_data_list *plist;
+
+ /*
+ * If next update is a FULL mode update, then we must
+ * ensure that all pending & active updates are complete
+ * before submitting the update. Otherwise, the FULL
+ * mode update may cause an endless collision loop with
+ * other updates. Block here until updates are flushed.
+ */
+ if (upd_data->update_mode == UPDATE_MODE_FULL) {
+ mutex_unlock(&fb_data->queue_mutex);
+ mxc_epdc_fb_flush_updates(fb_data);
+ mutex_lock(&fb_data->queue_mutex);
+ }
+
+ /* Count buffers in free buffer list */
+ list_for_each_entry(plist, &fb_data->upd_buf_free_list, list)
+ count++;
+
+ /* Use count to determine if we have enough
+ * free buffers to handle this update request */
+ if (count + fb_data->max_num_buffers
+ <= fb_data->max_num_updates) {
+ dev_err(fb_data->dev,
+ "No free intermediate buffers available.\n");
+ mutex_unlock(&fb_data->queue_mutex);
+ return -ENOMEM;
+ }
+
+ /* Grab first available buffer and delete from the free list */
+ upd_data_list =
+ list_entry(fb_data->upd_buf_free_list.next,
+ struct update_data_list, list);
+
+ list_del_init(&upd_data_list->list);
+ }
+
+ /*
+ * Create new update data structure, fill it with new update
+ * data and add it to the list of pending updates
+ */
+ upd_desc = kzalloc(sizeof(struct update_desc_list), GFP_KERNEL);
+ if (!upd_desc) {
+ dev_err(fb_data->dev,
+ "Insufficient system memory for update! Aborting.\n");
+ if (fb_data->upd_scheme == UPDATE_SCHEME_SNAPSHOT) {
+ list_add(&upd_data_list->list,
+ &fb_data->upd_buf_free_list);
+ }
+ mutex_unlock(&fb_data->queue_mutex);
+ return -EPERM;
+ }
+ /* Initialize per-update marker list */
+ INIT_LIST_HEAD(&upd_desc->upd_marker_list);
+ upd_desc->upd_data = *upd_data;
+ upd_desc->update_order = fb_data->order_cnt++;
+ list_add_tail(&upd_desc->list, &fb_data->upd_pending_list);
+
+ /* If marker specified, associate it with a completion */
+ if (upd_data->update_marker != 0) {
+ /* Allocate new update marker and set it up */
+ marker_data = kzalloc(sizeof(struct update_marker_data),
+ GFP_KERNEL);
+ if (!marker_data) {
+ dev_err(fb_data->dev, "No memory for marker!\n");
+ mutex_unlock(&fb_data->queue_mutex);
+ return -ENOMEM;
+ }
+ list_add_tail(&marker_data->upd_list,
+ &upd_desc->upd_marker_list);
+ marker_data->update_marker = upd_data->update_marker;
+ if (upd_desc->upd_data.flags & EPDC_FLAG_TEST_COLLISION)
+ marker_data->lut_num = DRY_RUN_NO_LUT;
+ else
+ marker_data->lut_num = INVALID_LUT;
+ init_completion(&marker_data->update_completion);
+ /* Add marker to master marker list */
+ list_add_tail(&marker_data->full_list,
+ &fb_data->full_marker_list);
+ }
+
+ if (fb_data->upd_scheme != UPDATE_SCHEME_SNAPSHOT) {
+ /* Queued update scheme processing */
+
+ mutex_unlock(&fb_data->queue_mutex);
+
+ /* Signal workqueue to handle new update */
+ queue_work(fb_data->epdc_submit_workqueue,
+ &fb_data->epdc_submit_work);
+
+ return 0;
+ }
+
+ /* Snapshot update scheme processing */
+
+ /* Set descriptor for current update, delete from pending list */
+ upd_data_list->update_desc = upd_desc;
+ list_del_init(&upd_desc->list);
+
+ mutex_unlock(&fb_data->queue_mutex);
+
+ /*
+ * Hold on to original screen update region, which we
+ * will ultimately use when telling EPDC where to update on panel
+ */
+ screen_upd_region = &upd_desc->upd_data.update_region;
+
+ /* Select from PxP output buffers */
+ upd_data_list->phys_addr =
+ fb_data->phys_addr_updbuf[fb_data->upd_buffer_num];
+ upd_data_list->virt_addr =
+ fb_data->virt_addr_updbuf[fb_data->upd_buffer_num];
+ fb_data->upd_buffer_num++;
+ if (fb_data->upd_buffer_num > fb_data->max_num_buffers-1)
+ fb_data->upd_buffer_num = 0;
+
+ ret = epdc_process_update(upd_data_list, fb_data);
+ if (ret) {
+ mutex_unlock(&fb_data->pxp_mutex);
+ return ret;
+ }
+
+ /* Pass selected waveform mode back to user */
+ upd_data->waveform_mode = upd_desc->upd_data.waveform_mode;
+
+ /* Get rotation-adjusted coordinates */
+ adjust_coordinates(fb_data->epdc_fb_var.xres,
+ fb_data->epdc_fb_var.yres, fb_data->epdc_fb_var.rotate,
+ &upd_desc->upd_data.update_region, NULL);
+
+ /* Grab lock for queue manipulation and update submission */
+ mutex_lock(&fb_data->queue_mutex);
+
+ /*
+ * Is the working buffer idle?
+ * If either the working buffer is busy, or there are no LUTs available,
+ * then we return and let the ISR handle the update later
+ */
+ {
+ bool luts_available;
+
+ luts_available = fb_data->epdc_wb_mode ? epdc_any_luts_real_available() :
+ epdc_any_luts_available();
+ if ((fb_data->cur_update != NULL) || !luts_available) {
+ /* Add processed Y buffer to update list */
+ list_add_tail(&upd_data_list->list, &fb_data->upd_buf_queue);
+
+ /* Return and allow the update to be submitted by the ISR. */
+ mutex_unlock(&fb_data->queue_mutex);
+ return 0;
+ }
+ }
+
+ /* LUTs are available, so we get one here */
+ ret = epdc_choose_next_lut(fb_data, &upd_data_list->lut_num);
+ if (ret && fb_data->tce_prevent && (fb_data->rev < 20)) {
+ dev_dbg(fb_data->dev, "Must wait for LUT15\n");
+ /* Add processed Y buffer to update list */
+ list_add_tail(&upd_data_list->list, &fb_data->upd_buf_queue);
+
+ /* Return and allow the update to be submitted by the ISR. */
+ mutex_unlock(&fb_data->queue_mutex);
+ return 0;
+ }
+
+ if (!(upd_data_list->update_desc->upd_data.flags
+ & EPDC_FLAG_TEST_COLLISION)) {
+
+ /* Save current update */
+ fb_data->cur_update = upd_data_list;
+
+ /* Reset mask for LUTS that have completed during WB processing */
+ fb_data->luts_complete_wb = 0;
+
+ /* Associate LUT with update marker */
+ list_for_each_entry_safe(next_marker, temp_marker,
+ &upd_data_list->update_desc->upd_marker_list, upd_list)
+ next_marker->lut_num = upd_data_list->lut_num;
+
+ /* Mark LUT as containing new update */
+ fb_data->lut_update_order[upd_data_list->lut_num] =
+ upd_desc->update_order;
+
+ epdc_lut_complete_intr(fb_data->rev, upd_data_list->lut_num,
+ true);
+ }
+
+ /* Clear status and Enable LUT complete and WB complete IRQs */
+ epdc_working_buf_intr(true);
+
+ /* add working buffer update before display for external mode */
+ if (fb_data->epdc_wb_mode)
+ ret = epdc_working_buffer_update(fb_data, upd_data_list,
+ screen_upd_region);
+
+ /* Program EPDC update to process buffer */
+ epdc_set_update_addr(upd_data_list->phys_addr + upd_desc->epdc_offs);
+ epdc_set_update_coord(screen_upd_region->left, screen_upd_region->top);
+ epdc_set_update_dimensions(screen_upd_region->width,
+ screen_upd_region->height);
+ if (fb_data->rev > 20)
+ epdc_set_update_stride(upd_desc->epdc_stride);
+ if (upd_desc->upd_data.temp != TEMP_USE_AMBIENT) {
+ temp_index = mxc_epdc_fb_get_temp_index(fb_data,
+ upd_desc->upd_data.temp);
+ epdc_set_temp(temp_index);
+ } else
+ epdc_set_temp(fb_data->temp_index);
+ if (fb_data->wv_modes_update &&
+ (upd_desc->upd_data.waveform_mode == WAVEFORM_MODE_AUTO)) {
+ epdc_set_update_waveform(&fb_data->wv_modes);
+ fb_data->wv_modes_update = false;
+ }
+
+ epdc_submit_update(upd_data_list->lut_num,
+ upd_desc->upd_data.waveform_mode,
+ upd_desc->upd_data.update_mode,
+ (upd_desc->upd_data.flags
+ & EPDC_FLAG_TEST_COLLISION) ? true : false,
+ false, 0);
+
+ mutex_unlock(&fb_data->queue_mutex);
+ return 0;
+}
+
+static int mxc_epdc_fb_send_update(struct mxcfb_update_data *upd_data,
+ struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+
+ if (!fb_data->restrict_width) {
+ /* No width restriction, send entire update region */
+ return mxc_epdc_fb_send_single_update(upd_data, info);
+ } else {
+ int ret;
+ __u32 width, left;
+ __u32 marker;
+ __u32 *region_width, *region_left;
+ u32 max_upd_width = EPDC_V2_MAX_UPDATE_WIDTH;
+
+ /* Further restrict max width due to pxp rotation
+ * alignment requirement
+ */
+ if (fb_data->epdc_fb_var.rotate != FB_ROTATE_UR)
+ max_upd_width -= EPDC_V2_ROTATION_ALIGNMENT;
+
+ /* Select split of width or height based on rotation */
+ if ((fb_data->epdc_fb_var.rotate == FB_ROTATE_UR) ||
+ (fb_data->epdc_fb_var.rotate == FB_ROTATE_UD)) {
+ region_width = &upd_data->update_region.width;
+ region_left = &upd_data->update_region.left;
+ } else {
+ region_width = &upd_data->update_region.height;
+ region_left = &upd_data->update_region.top;
+ }
+
+ if (*region_width <= max_upd_width)
+ return mxc_epdc_fb_send_single_update(upd_data, info);
+
+ width = *region_width;
+ left = *region_left;
+ marker = upd_data->update_marker;
+ upd_data->update_marker = 0;
+
+ do {
+ *region_width = max_upd_width;
+ *region_left = left;
+ ret = mxc_epdc_fb_send_single_update(upd_data, info);
+ if (ret)
+ return ret;
+ width -= max_upd_width;
+ left += max_upd_width;
+ } while (width > max_upd_width);
+
+ *region_width = width;
+ *region_left = left;
+ upd_data->update_marker = marker;
+ return mxc_epdc_fb_send_single_update(upd_data, info);
+ }
+}
+
+static int mxc_epdc_fb_wait_update_complete(struct mxcfb_update_marker_data *marker_data,
+ struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+ struct update_marker_data *next_marker;
+ struct update_marker_data *temp;
+ bool marker_found = false;
+ int ret = 0;
+
+ /* 0 is an invalid update_marker value */
+ if (marker_data->update_marker == 0)
+ return -EINVAL;
+
+ /*
+ * Find completion associated with update_marker requested.
+ * Note: If update completed already, marker will have been
+ * cleared, it won't be found, and function will just return.
+ */
+
+ /* Grab queue lock to protect access to marker list */
+ mutex_lock(&fb_data->queue_mutex);
+
+ list_for_each_entry_safe(next_marker, temp,
+ &fb_data->full_marker_list, full_list) {
+ if (next_marker->update_marker == marker_data->update_marker) {
+ dev_dbg(fb_data->dev, "Waiting for marker %d\n",
+ marker_data->update_marker);
+ next_marker->waiting = true;
+ marker_found = true;
+ break;
+ }
+ }
+
+ mutex_unlock(&fb_data->queue_mutex);
+
+ /*
+ * If marker not found, it has either been signalled already
+ * or the update request failed. In either case, just return.
+ */
+ if (!marker_found)
+ return ret;
+
+ ret = wait_for_completion_timeout(&next_marker->update_completion,
+ msecs_to_jiffies(5000));
+ if (!ret) {
+ dev_err(fb_data->dev,
+ "Timed out waiting for update completion\n");
+ return -ETIMEDOUT;
+ }
+
+ marker_data->collision_test = next_marker->collision_test;
+
+ /* Free update marker object */
+ kfree(next_marker);
+
+ return ret;
+}
+
+static int mxc_epdc_fb_set_pwrdown_delay(u32 pwrdown_delay,
+ struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+
+ fb_data->pwrdown_delay = pwrdown_delay;
+
+ return 0;
+}
+
+static int mxc_epdc_get_pwrdown_delay(struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+
+ return fb_data->pwrdown_delay;
+}
+
+static int mxc_epdc_fb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int ret = -EINVAL;
+
+ switch (cmd) {
+ case MXCFB_SET_WAVEFORM_MODES:
+ {
+ struct mxcfb_waveform_modes modes;
+ if (!copy_from_user(&modes, argp, sizeof(modes))) {
+ mxc_epdc_fb_set_waveform_modes(&modes, info);
+ ret = 0;
+ }
+ break;
+ }
+ case MXCFB_SET_TEMPERATURE:
+ {
+ int temperature;
+ if (!get_user(temperature, (int32_t __user *) arg))
+ ret = mxc_epdc_fb_set_temperature(temperature,
+ info);
+ break;
+ }
+ case MXCFB_SET_AUTO_UPDATE_MODE:
+ {
+ u32 auto_mode = 0;
+ if (!get_user(auto_mode, (__u32 __user *) arg))
+ ret = mxc_epdc_fb_set_auto_update(auto_mode,
+ info);
+ break;
+ }
+ case MXCFB_SET_UPDATE_SCHEME:
+ {
+ u32 upd_scheme = 0;
+ if (!get_user(upd_scheme, (__u32 __user *) arg))
+ ret = mxc_epdc_fb_set_upd_scheme(upd_scheme,
+ info);
+ break;
+ }
+ case MXCFB_SEND_UPDATE:
+ {
+ struct mxcfb_update_data upd_data;
+ if (!copy_from_user(&upd_data, argp,
+ sizeof(upd_data))) {
+ ret = mxc_epdc_fb_send_update(&upd_data, info);
+ if (ret == 0 && copy_to_user(argp, &upd_data,
+ sizeof(upd_data)))
+ ret = -EFAULT;
+ } else {
+ ret = -EFAULT;
+ }
+
+ break;
+ }
+ case MXCFB_WAIT_FOR_UPDATE_COMPLETE:
+ {
+ struct mxcfb_update_marker_data upd_marker_data;
+ if (!copy_from_user(&upd_marker_data, argp,
+ sizeof(upd_marker_data))) {
+ ret = mxc_epdc_fb_wait_update_complete(
+ &upd_marker_data, info);
+ if (copy_to_user(argp, &upd_marker_data,
+ sizeof(upd_marker_data)))
+ ret = -EFAULT;
+ } else {
+ ret = -EFAULT;
+ }
+
+ break;
+ }
+
+ case MXCFB_SET_PWRDOWN_DELAY:
+ {
+ int delay = 0;
+ if (!get_user(delay, (__u32 __user *) arg))
+ ret =
+ mxc_epdc_fb_set_pwrdown_delay(delay, info);
+ break;
+ }
+
+ case MXCFB_GET_PWRDOWN_DELAY:
+ {
+ int pwrdown_delay = mxc_epdc_get_pwrdown_delay(info);
+ if (put_user(pwrdown_delay,
+ (int __user *)argp))
+ ret = -EFAULT;
+ ret = 0;
+ break;
+ }
+
+ case MXCFB_GET_WORK_BUFFER:
+ {
+ /* copy the epdc working buffer to the user space */
+ struct mxc_epdc_fb_data *fb_data = info ?
+ (struct mxc_epdc_fb_data *)info:g_fb_data;
+ flush_cache_all();
+ outer_flush_range(fb_data->working_buffer_phys,
+ fb_data->working_buffer_phys +
+ fb_data->working_buffer_size);
+ if (copy_to_user((void __user *)arg,
+ (const void *) fb_data->working_buffer_virt,
+ fb_data->working_buffer_size))
+ ret = -EFAULT;
+ else
+ ret = 0;
+ flush_cache_all();
+ outer_flush_range(fb_data->working_buffer_phys,
+ fb_data->working_buffer_phys +
+ fb_data->working_buffer_size);
+ break;
+ }
+
+ default:
+ break;
+ }
+ return ret;
+}
+
+static void mxc_epdc_fb_update_pages(struct mxc_epdc_fb_data *fb_data,
+ u16 y1, u16 y2)
+{
+ struct mxcfb_update_data update;
+
+ /* Do partial screen update, Update full horizontal lines */
+ update.update_region.left = 0;
+ update.update_region.width = fb_data->epdc_fb_var.xres;
+ update.update_region.top = y1;
+ update.update_region.height = y2 - y1;
+ update.waveform_mode = WAVEFORM_MODE_AUTO;
+ update.update_mode = UPDATE_MODE_FULL;
+ update.update_marker = 0;
+ update.temp = TEMP_USE_AMBIENT;
+ update.flags = 0;
+
+ mxc_epdc_fb_send_update(&update, &fb_data->info);
+}
+
+/* this is called back from the deferred io workqueue */
+static void mxc_epdc_fb_deferred_io(struct fb_info *info,
+ struct list_head *pagelist)
+{
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+ struct page *page;
+ unsigned long beg, end;
+ int y1, y2, miny, maxy;
+
+ if (fb_data->auto_mode != AUTO_UPDATE_MODE_AUTOMATIC_MODE)
+ return;
+
+ miny = INT_MAX;
+ maxy = 0;
+ list_for_each_entry(page, pagelist, lru) {
+ beg = page->index << PAGE_SHIFT;
+ end = beg + PAGE_SIZE - 1;
+ y1 = beg / info->fix.line_length;
+ y2 = end / info->fix.line_length;
+ if (y2 >= fb_data->epdc_fb_var.yres)
+ y2 = fb_data->epdc_fb_var.yres - 1;
+ if (miny > y1)
+ miny = y1;
+ if (maxy < y2)
+ maxy = y2;
+ }
+
+ mxc_epdc_fb_update_pages(fb_data, miny, maxy);
+}
+
+void mxc_epdc_fb_flush_updates(struct mxc_epdc_fb_data *fb_data)
+{
+ int ret;
+
+ if (fb_data->in_init)
+ return;
+
+ /* Grab queue lock to prevent any new updates from being submitted */
+ mutex_lock(&fb_data->queue_mutex);
+
+ /*
+ * 3 places to check for updates that are active or pending:
+ * 1) Updates in the pending list
+ * 2) Update buffers in use (e.g., PxP processing)
+ * 3) Active updates to panel - We can key off of EPDC
+ * power state to know if we have active updates.
+ */
+ if (!list_empty(&fb_data->upd_pending_list) ||
+ !is_free_list_full(fb_data) ||
+ (fb_data->updates_active == true)) {
+ /* Initialize event signalling updates are done */
+ init_completion(&fb_data->updates_done);
+ fb_data->waiting_for_idle = true;
+
+ mutex_unlock(&fb_data->queue_mutex);
+ /* Wait for any currently active updates to complete */
+ ret = wait_for_completion_timeout(&fb_data->updates_done,
+ msecs_to_jiffies(8000));
+ if (!ret)
+ dev_err(fb_data->dev,
+ "Flush updates timeout! ret = 0x%x\n", ret);
+
+ mutex_lock(&fb_data->queue_mutex);
+ fb_data->waiting_for_idle = false;
+ }
+
+ mutex_unlock(&fb_data->queue_mutex);
+}
+
+static int mxc_epdc_fb_blank(int blank, struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+ int ret;
+
+ dev_dbg(fb_data->dev, "blank = %d\n", blank);
+
+ if (fb_data->blank == blank)
+ return 0;
+
+ fb_data->blank = blank;
+
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ mxc_epdc_fb_flush_updates(fb_data);
+ /* Wait for powerdown */
+ mutex_lock(&fb_data->power_mutex);
+ if ((fb_data->power_state == POWER_STATE_ON) &&
+ (fb_data->pwrdown_delay == FB_POWERDOWN_DISABLE)) {
+
+ /* Powerdown disabled, so we disable EPDC manually */
+ int count = 0;
+ int sleep_ms = 10;
+
+ mutex_unlock(&fb_data->power_mutex);
+
+ /* If any active updates, wait for them to complete */
+ while (fb_data->updates_active) {
+ /* Timeout after 1 sec */
+ if ((count * sleep_ms) > 1000)
+ break;
+ msleep(sleep_ms);
+ count++;
+ }
+
+ fb_data->powering_down = true;
+ epdc_powerdown(fb_data);
+ } else if (fb_data->power_state != POWER_STATE_OFF) {
+ fb_data->wait_for_powerdown = true;
+ init_completion(&fb_data->powerdown_compl);
+ mutex_unlock(&fb_data->power_mutex);
+ ret = wait_for_completion_timeout(&fb_data->powerdown_compl,
+ msecs_to_jiffies(5000));
+ if (!ret) {
+ dev_err(fb_data->dev,
+ "No powerdown received!\n");
+ return -ETIMEDOUT;
+ }
+ } else
+ mutex_unlock(&fb_data->power_mutex);
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ mxc_epdc_fb_flush_updates(fb_data);
+ break;
+ }
+ return 0;
+}
+
+static int mxc_epdc_fb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+ u_int y_bottom;
+
+ dev_dbg(info->device, "%s: var->yoffset %d, info->var.yoffset %d\n",
+ __func__, var->yoffset, info->var.yoffset);
+ /* check if var is valid; also, xpan is not supported */
+ if (!var || (var->xoffset != info->var.xoffset) ||
+ (var->yoffset + var->yres > var->yres_virtual)) {
+ dev_dbg(info->device, "x panning not supported\n");
+ return -EINVAL;
+ }
+
+ if ((fb_data->epdc_fb_var.xoffset == var->xoffset) &&
+ (fb_data->epdc_fb_var.yoffset == var->yoffset))
+ return 0; /* No change, do nothing */
+
+ y_bottom = var->yoffset;
+
+ if (!(var->vmode & FB_VMODE_YWRAP))
+ y_bottom += var->yres;
+
+ if (y_bottom > info->var.yres_virtual)
+ return -EINVAL;
+
+ mutex_lock(&fb_data->queue_mutex);
+
+ fb_data->fb_offset = (var->yoffset * var->xres_virtual + var->xoffset)
+ * (var->bits_per_pixel) / 8;
+
+ fb_data->epdc_fb_var.xoffset = var->xoffset;
+ fb_data->epdc_fb_var.yoffset = var->yoffset;
+
+ if (var->vmode & FB_VMODE_YWRAP)
+ info->var.vmode |= FB_VMODE_YWRAP;
+ else
+ info->var.vmode &= ~FB_VMODE_YWRAP;
+
+ mutex_unlock(&fb_data->queue_mutex);
+
+ return 0;
+}
+
+static struct fb_ops mxc_epdc_fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = mxc_epdc_fb_check_var,
+ .fb_set_par = mxc_epdc_fb_set_par,
+ .fb_setcmap = mxc_epdc_fb_setcmap,
+ .fb_setcolreg = mxc_epdc_fb_setcolreg,
+ .fb_pan_display = mxc_epdc_fb_pan_display,
+ .fb_ioctl = mxc_epdc_fb_ioctl,
+ .fb_mmap = mxc_epdc_fb_mmap,
+ .fb_blank = mxc_epdc_fb_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static struct fb_deferred_io mxc_epdc_fb_defio = {
+ .delay = HZ,
+ .deferred_io = mxc_epdc_fb_deferred_io,
+};
+
+static void epdc_done_work_func(struct work_struct *work)
+{
+ struct mxc_epdc_fb_data *fb_data =
+ container_of(work, struct mxc_epdc_fb_data,
+ epdc_done_work.work);
+ epdc_powerdown(fb_data);
+}
+
+static bool is_free_list_full(struct mxc_epdc_fb_data *fb_data)
+{
+ int count = 0;
+ struct update_data_list *plist;
+
+ /* Count buffers in free buffer list */
+ list_for_each_entry(plist, &fb_data->upd_buf_free_list, list)
+ count++;
+
+ /* Check to see if all buffers are in this list */
+ if (count == fb_data->max_num_updates)
+ return true;
+ else
+ return false;
+}
+
+static irqreturn_t mxc_epdc_irq_handler(int irq, void *dev_id)
+{
+ struct mxc_epdc_fb_data *fb_data = dev_id;
+ u32 ints_fired, luts1_ints_fired, luts2_ints_fired;
+
+ /*
+ * If we just completed one-time panel init, bypass
+ * queue handling, clear interrupt and return
+ */
+ if (fb_data->in_init) {
+ if (epdc_is_working_buffer_complete()) {
+ epdc_working_buf_intr(false);
+ epdc_clear_working_buf_irq();
+ dev_dbg(fb_data->dev, "Cleared WB for init update\n");
+ }
+
+ if (epdc_is_lut_complete(fb_data->rev, 0)) {
+ epdc_lut_complete_intr(fb_data->rev, 0, false);
+ epdc_clear_lut_complete_irq(fb_data->rev, 0);
+ fb_data->in_init = false;
+ dev_dbg(fb_data->dev, "Cleared LUT complete for init update\n");
+ }
+
+ return IRQ_HANDLED;
+ }
+
+ ints_fired = __raw_readl(EPDC_IRQ_MASK) & __raw_readl(EPDC_IRQ);
+ if (fb_data->rev < 20) {
+ luts1_ints_fired = 0;
+ luts2_ints_fired = 0;
+ } else {
+ luts1_ints_fired = __raw_readl(EPDC_IRQ_MASK1) & __raw_readl(EPDC_IRQ1);
+ luts2_ints_fired = __raw_readl(EPDC_IRQ_MASK2) & __raw_readl(EPDC_IRQ2);
+ }
+
+ if (!(ints_fired || luts1_ints_fired || luts2_ints_fired))
+ return IRQ_HANDLED;
+
+ if (__raw_readl(EPDC_IRQ) & EPDC_IRQ_TCE_UNDERRUN_IRQ) {
+ dev_err(fb_data->dev,
+ "TCE underrun! Will continue to update panel\n");
+ /* Clear TCE underrun IRQ */
+ __raw_writel(EPDC_IRQ_TCE_UNDERRUN_IRQ, EPDC_IRQ_CLEAR);
+ }
+
+ /* Check if we are waiting on EOF to sync a new update submission */
+ if (epdc_signal_eof()) {
+ epdc_eof_intr(false);
+ epdc_clear_eof_irq();
+ complete(&fb_data->eof_event);
+ }
+
+ /*
+ * Workaround for EPDC v2.0/v2.1 errata: Must read collision status
+ * before clearing IRQ, or else collision status for bits 16:63
+ * will be automatically cleared. So we read it here, and there is
+ * no conflict with using it in epdc_intr_work_func since the
+ * working buffer processing flow is strictly sequential (i.e.,
+ * only one WB processing done at a time, so the data grabbed
+ * here should be up-to-date and accurate when the WB processing
+ * completes. Also, note that there is no impact to other versions
+ * of EPDC by reading LUT status here.
+ */
+ if (fb_data->cur_update != NULL)
+ fb_data->epdc_colliding_luts = epdc_get_colliding_luts(fb_data->rev);
+
+ /* Clear the interrupt mask for any interrupts signalled */
+ __raw_writel(ints_fired, EPDC_IRQ_MASK_CLEAR);
+ __raw_writel(luts1_ints_fired, EPDC_IRQ_MASK1_CLEAR);
+ __raw_writel(luts2_ints_fired, EPDC_IRQ_MASK2_CLEAR);
+
+ dev_dbg(fb_data->dev, "EPDC interrupts fired = 0x%x, "
+ "LUTS1 fired = 0x%x, LUTS2 fired = 0x%x\n",
+ ints_fired, luts1_ints_fired, luts2_ints_fired);
+
+ queue_work(fb_data->epdc_intr_workqueue,
+ &fb_data->epdc_intr_work);
+
+ return IRQ_HANDLED;
+}
+
+static void epdc_intr_work_func(struct work_struct *work)
+{
+ struct mxc_epdc_fb_data *fb_data =
+ container_of(work, struct mxc_epdc_fb_data, epdc_intr_work);
+ struct update_data_list *collision_update;
+ struct mxcfb_rect *next_upd_region;
+ struct update_marker_data *next_marker;
+ struct update_marker_data *temp;
+ int temp_index;
+ u64 temp_mask;
+ u32 lut;
+ bool ignore_collision = false;
+ int i;
+ bool wb_lut_done = false;
+ bool free_update = true;
+ int next_lut, epdc_next_lut_15;
+ u32 epdc_luts_active, epdc_wb_busy, epdc_luts_avail, epdc_lut_cancelled;
+ u32 epdc_collision;
+ u64 epdc_irq_stat;
+ bool epdc_waiting_on_wb;
+ u32 coll_coord, coll_size;
+ struct mxcfb_rect coll_region;
+
+ /* Protect access to buffer queues and to update HW */
+ mutex_lock(&fb_data->queue_mutex);
+
+ /* Capture EPDC status one time to limit exposure to race conditions */
+ epdc_luts_active = epdc_any_luts_active(fb_data->rev);
+ epdc_wb_busy = epdc_is_working_buffer_busy();
+
+ /*XXX unsupport update cancelled in external mode temporarily */
+ if (fb_data->epdc_wb_mode)
+ epdc_lut_cancelled = 0;
+ else
+ epdc_lut_cancelled = epdc_is_lut_cancelled();
+
+ if (fb_data->epdc_wb_mode)
+ epdc_luts_avail = epdc_any_luts_real_available();
+ else
+ epdc_luts_avail = epdc_any_luts_available();
+
+ if (fb_data->epdc_wb_mode)
+ epdc_collision = fb_data->col_info.pixel_cnt ? 1 : 0;
+ else
+ epdc_collision = epdc_is_collision();
+
+ if (fb_data->rev < 20)
+ epdc_irq_stat = __raw_readl(EPDC_IRQ);
+ else
+ epdc_irq_stat = (u64)__raw_readl(EPDC_IRQ1) |
+ ((u64)__raw_readl(EPDC_IRQ2) << 32);
+ epdc_waiting_on_wb = (fb_data->cur_update != NULL) ? true : false;
+
+ /* Free any LUTs that have completed */
+ for (i = 0; i < fb_data->num_luts; i++) {
+ if ((epdc_irq_stat & (1ULL << i)) == 0)
+ continue;
+
+ dev_dbg(fb_data->dev, "LUT %d completed\n", i);
+
+ /* Disable IRQ for completed LUT */
+ epdc_lut_complete_intr(fb_data->rev, i, false);
+
+ /*
+ * Go through all updates in the collision list and
+ * unmask any updates that were colliding with
+ * the completed LUT.
+ */
+ list_for_each_entry(collision_update,
+ &fb_data->upd_buf_collision_list, list) {
+ collision_update->collision_mask =
+ collision_update->collision_mask & ~(1ULL << i);
+ }
+
+ epdc_clear_lut_complete_irq(fb_data->rev, i);
+
+ fb_data->luts_complete_wb |= 1ULL << i;
+ if (i != 0)
+ fb_data->luts_complete |= 1ULL << i;
+
+ fb_data->lut_update_order[i] = 0;
+
+ /* Signal completion if submit workqueue needs a LUT */
+ if (fb_data->waiting_for_lut) {
+ complete(&fb_data->update_res_free);
+ fb_data->waiting_for_lut = false;
+ }
+
+ /* Signal completion if LUT15 free and is needed */
+ if (fb_data->waiting_for_lut15 && (i == 15)) {
+ complete(&fb_data->lut15_free);
+ fb_data->waiting_for_lut15 = false;
+ }
+
+ /* Detect race condition where WB and its LUT complete
+ (i.e. full update completes) in one swoop */
+ if (epdc_waiting_on_wb &&
+ (i == fb_data->cur_update->lut_num))
+ wb_lut_done = true;
+
+ /* Signal completion if anyone waiting on this LUT */
+ if (!wb_lut_done)
+ list_for_each_entry_safe(next_marker, temp,
+ &fb_data->full_marker_list,
+ full_list) {
+ if (next_marker->lut_num != i)
+ continue;
+
+ /* Found marker to signal - remove from list */
+ list_del_init(&next_marker->full_list);
+
+ /* Signal completion of update */
+ dev_dbg(fb_data->dev, "Signaling marker %d\n",
+ next_marker->update_marker);
+ if (next_marker->waiting)
+ complete(&next_marker->update_completion);
+ else
+ kfree(next_marker);
+ }
+ }
+
+ /* Check to see if all updates have completed */
+ if (list_empty(&fb_data->upd_pending_list) &&
+ is_free_list_full(fb_data) &&
+ !epdc_waiting_on_wb &&
+ !epdc_luts_active) {
+
+ fb_data->updates_active = false;
+
+ if (fb_data->pwrdown_delay != FB_POWERDOWN_DISABLE) {
+ /*
+ * Set variable to prevent overlapping
+ * enable/disable requests
+ */
+ fb_data->powering_down = true;
+
+ /* Schedule task to disable EPDC HW until next update */
+ schedule_delayed_work(&fb_data->epdc_done_work,
+ msecs_to_jiffies(fb_data->pwrdown_delay));
+
+ /* Reset counter to reduce chance of overflow */
+ fb_data->order_cnt = 0;
+ }
+
+ if (fb_data->waiting_for_idle)
+ complete(&fb_data->updates_done);
+ }
+
+ /* Is Working Buffer busy? */
+ if (epdc_wb_busy) {
+ /* Can't submit another update until WB is done */
+ mutex_unlock(&fb_data->queue_mutex);
+ return;
+ }
+
+ /*
+ * Were we waiting on working buffer?
+ * If so, update queues and check for collisions
+ */
+ if (epdc_waiting_on_wb) {
+ dev_dbg(fb_data->dev, "\nWorking buffer completed\n");
+
+ /* Signal completion if submit workqueue was waiting on WB */
+ if (fb_data->waiting_for_wb) {
+ complete(&fb_data->update_res_free);
+ fb_data->waiting_for_wb = false;
+ }
+
+ if (fb_data->cur_update->update_desc->upd_data.flags
+ & EPDC_FLAG_TEST_COLLISION) {
+ /* This was a dry run to test for collision */
+
+ /* Signal marker */
+ list_for_each_entry_safe(next_marker, temp,
+ &fb_data->full_marker_list,
+ full_list) {
+ if (next_marker->lut_num != DRY_RUN_NO_LUT)
+ continue;
+
+ if (epdc_collision)
+ next_marker->collision_test = true;
+ else
+ next_marker->collision_test = false;
+
+ dev_dbg(fb_data->dev,
+ "In IRQ, collision_test = %d\n",
+ next_marker->collision_test);
+
+ /* Found marker to signal - remove from list */
+ list_del_init(&next_marker->full_list);
+
+ /* Signal completion of update */
+ dev_dbg(fb_data->dev, "Signaling marker "
+ "for dry-run - %d\n",
+ next_marker->update_marker);
+ complete(&next_marker->update_completion);
+ }
+ memset(&fb_data->col_info, 0x0, sizeof(struct pxp_collision_info));
+ } else if (epdc_lut_cancelled && !epdc_collision) {
+ /*
+ * Note: The update may be cancelled (void) if all
+ * pixels collided. In that case we handle it as a
+ * collision, not a cancel.
+ */
+
+ /* Clear LUT status (might be set if no AUTOWV used) */
+
+ /*
+ * Disable and clear IRQ for the LUT used.
+ * Even though LUT is cancelled in HW, the LUT
+ * complete bit may be set if AUTOWV not used.
+ */
+ epdc_lut_complete_intr(fb_data->rev,
+ fb_data->cur_update->lut_num, false);
+ epdc_clear_lut_complete_irq(fb_data->rev,
+ fb_data->cur_update->lut_num);
+
+ fb_data->lut_update_order[fb_data->cur_update->lut_num] = 0;
+
+ /* Signal completion if submit workqueue needs a LUT */
+ if (fb_data->waiting_for_lut) {
+ complete(&fb_data->update_res_free);
+ fb_data->waiting_for_lut = false;
+ }
+
+ list_for_each_entry_safe(next_marker, temp,
+ &fb_data->cur_update->update_desc->upd_marker_list,
+ upd_list) {
+
+ /* Del from per-update & full list */
+ list_del_init(&next_marker->upd_list);
+ list_del_init(&next_marker->full_list);
+
+ /* Signal completion of update */
+ dev_dbg(fb_data->dev,
+ "Signaling marker (cancelled) %d\n",
+ next_marker->update_marker);
+ if (next_marker->waiting)
+ complete(&next_marker->update_completion);
+ else
+ kfree(next_marker);
+ }
+ } else if (epdc_collision) {
+ /* Real update (no dry-run), collision occurred */
+
+ /* Check list of colliding LUTs, and add to our collision mask */
+ if (fb_data->epdc_wb_mode)
+ fb_data->epdc_colliding_luts = (u64)fb_data->col_info.victim_luts[0] |
+ (((u64)fb_data->col_info.victim_luts[1]) << 32);
+
+ fb_data->cur_update->collision_mask =
+ fb_data->epdc_colliding_luts;
+
+ /* Clear collisions that completed since WB began */
+ fb_data->cur_update->collision_mask &=
+ ~fb_data->luts_complete_wb;
+
+ dev_dbg(fb_data->dev, "Collision mask = 0x%llx\n",
+ fb_data->epdc_colliding_luts);
+
+ /* For EPDC 2.0 and later, minimum collision bounds
+ are provided by HW. Recompute new bounds here. */
+ if ((fb_data->upd_scheme != UPDATE_SCHEME_SNAPSHOT)
+ && (fb_data->rev >= 20)) {
+ u32 xres, yres, rotate;
+ struct mxcfb_rect adj_update_region;
+ struct mxcfb_rect *cur_upd_rect =
+ &fb_data->cur_update->update_desc->upd_data.update_region;
+
+ if (fb_data->epdc_wb_mode) {
+ adjust_coordinates(fb_data->epdc_fb_var.xres,
+ fb_data->epdc_fb_var.yres, fb_data->epdc_fb_var.rotate,
+ cur_upd_rect, &adj_update_region);
+
+ coll_region.left = fb_data->col_info.rect_min_x + adj_update_region.left;
+ coll_region.top = fb_data->col_info.rect_min_y + adj_update_region.top;
+ coll_region.width = fb_data->col_info.rect_max_x - fb_data->col_info.rect_min_x + 1;
+ coll_region.height = fb_data->col_info.rect_max_y - fb_data->col_info.rect_min_y + 1;
+ memset(&fb_data->col_info, 0x0, sizeof(struct pxp_collision_info));
+ } else {
+ /* Get collision region coords from EPDC */
+ coll_coord = __raw_readl(EPDC_UPD_COL_CORD);
+ coll_size = __raw_readl(EPDC_UPD_COL_SIZE);
+ coll_region.left =
+ (coll_coord & EPDC_UPD_COL_CORD_XCORD_MASK)
+ >> EPDC_UPD_COL_CORD_XCORD_OFFSET;
+ coll_region.top =
+ (coll_coord & EPDC_UPD_COL_CORD_YCORD_MASK)
+ >> EPDC_UPD_COL_CORD_YCORD_OFFSET;
+ coll_region.width =
+ (coll_size & EPDC_UPD_COL_SIZE_WIDTH_MASK)
+ >> EPDC_UPD_COL_SIZE_WIDTH_OFFSET;
+ coll_region.height =
+ (coll_size & EPDC_UPD_COL_SIZE_HEIGHT_MASK)
+ >> EPDC_UPD_COL_SIZE_HEIGHT_OFFSET;
+ }
+ dev_dbg(fb_data->dev, "Coll region: l = %d, "
+ "t = %d, w = %d, h = %d\n",
+ coll_region.left, coll_region.top,
+ coll_region.width, coll_region.height);
+
+ /* Convert coords back to orig orientation */
+ switch (fb_data->epdc_fb_var.rotate) {
+ case FB_ROTATE_CW:
+ xres = fb_data->epdc_fb_var.yres;
+ yres = fb_data->epdc_fb_var.xres;
+ rotate = FB_ROTATE_CCW;
+ break;
+ case FB_ROTATE_UD:
+ xres = fb_data->epdc_fb_var.xres;
+ yres = fb_data->epdc_fb_var.yres;
+ rotate = FB_ROTATE_UD;
+ break;
+ case FB_ROTATE_CCW:
+ xres = fb_data->epdc_fb_var.yres;
+ yres = fb_data->epdc_fb_var.xres;
+ rotate = FB_ROTATE_CW;
+ break;
+ default:
+ xres = fb_data->epdc_fb_var.xres;
+ yres = fb_data->epdc_fb_var.yres;
+ rotate = FB_ROTATE_UR;
+ break;
+ }
+ adjust_coordinates(xres, yres, rotate,
+ &coll_region, cur_upd_rect);
+
+ dev_dbg(fb_data->dev, "Adj coll region: l = %d, "
+ "t = %d, w = %d, h = %d\n",
+ cur_upd_rect->left, cur_upd_rect->top,
+ cur_upd_rect->width,
+ cur_upd_rect->height);
+ }
+
+ /*
+ * If we collide with newer updates, then
+ * we don't need to re-submit the update. The
+ * idea is that the newer updates should take
+ * precedence anyways, so we don't want to
+ * overwrite them.
+ */
+ for (temp_mask = fb_data->cur_update->collision_mask, lut = 0;
+ temp_mask != 0;
+ lut++, temp_mask = temp_mask >> 1) {
+ if (!(temp_mask & 0x1))
+ continue;
+
+ if (fb_data->lut_update_order[lut] >=
+ fb_data->cur_update->update_desc->update_order) {
+ dev_dbg(fb_data->dev,
+ "Ignoring collision with"
+ "newer update.\n");
+ ignore_collision = true;
+ break;
+ }
+ }
+
+ if (!ignore_collision) {
+ free_update = false;
+ /*
+ * If update has markers, clear the LUTs to
+ * avoid signalling that they have completed.
+ */
+ list_for_each_entry_safe(next_marker, temp,
+ &fb_data->cur_update->update_desc->upd_marker_list,
+ upd_list)
+ next_marker->lut_num = INVALID_LUT;
+
+ /* Move to collision list */
+ list_add_tail(&fb_data->cur_update->list,
+ &fb_data->upd_buf_collision_list);
+ }
+ }
+
+ /* Do we need to free the current update descriptor? */
+ if (free_update) {
+ /* Handle condition where WB & LUT are both complete */
+ if (wb_lut_done)
+ list_for_each_entry_safe(next_marker, temp,
+ &fb_data->cur_update->update_desc->upd_marker_list,
+ upd_list) {
+
+ /* Del from per-update & full list */
+ list_del_init(&next_marker->upd_list);
+ list_del_init(&next_marker->full_list);
+
+ /* Signal completion of update */
+ dev_dbg(fb_data->dev,
+ "Signaling marker (wb) %d\n",
+ next_marker->update_marker);
+ if (next_marker->waiting)
+ complete(&next_marker->update_completion);
+ else
+ kfree(next_marker);
+ }
+
+ /* Free marker list and update descriptor */
+ kfree(fb_data->cur_update->update_desc);
+
+ /* Add to free buffer list */
+ list_add_tail(&fb_data->cur_update->list,
+ &fb_data->upd_buf_free_list);
+
+ /* Check to see if all updates have completed */
+ if (list_empty(&fb_data->upd_pending_list) &&
+ is_free_list_full(fb_data) &&
+ !epdc_luts_active) {
+
+ fb_data->updates_active = false;
+
+ if (fb_data->pwrdown_delay !=
+ FB_POWERDOWN_DISABLE) {
+ /*
+ * Set variable to prevent overlapping
+ * enable/disable requests
+ */
+ fb_data->powering_down = true;
+
+ /* Schedule EPDC disable */
+ schedule_delayed_work(&fb_data->epdc_done_work,
+ msecs_to_jiffies(fb_data->pwrdown_delay));
+
+ /* Reset counter to reduce chance of overflow */
+ fb_data->order_cnt = 0;
+ }
+
+ if (fb_data->waiting_for_idle)
+ complete(&fb_data->updates_done);
+ }
+ }
+
+ /* Clear current update */
+ fb_data->cur_update = NULL;
+
+ /* Clear IRQ for working buffer */
+ epdc_working_buf_intr(false);
+ epdc_clear_working_buf_irq();
+ }
+
+ if (fb_data->upd_scheme != UPDATE_SCHEME_SNAPSHOT) {
+ /* Queued update scheme processing */
+
+ /* Schedule task to submit collision and pending update */
+ if (!fb_data->powering_down)
+ queue_work(fb_data->epdc_submit_workqueue,
+ &fb_data->epdc_submit_work);
+
+ /* Release buffer queues */
+ mutex_unlock(&fb_data->queue_mutex);
+
+ return;
+ }
+
+ /* Snapshot update scheme processing */
+
+ /* Check to see if any LUTs are free */
+ if (!epdc_luts_avail) {
+ dev_dbg(fb_data->dev, "No luts available.\n");
+ mutex_unlock(&fb_data->queue_mutex);
+ return;
+ }
+
+ epdc_next_lut_15 = epdc_choose_next_lut(fb_data, &next_lut);
+ /* Check to see if there is a valid LUT to use */
+ if (epdc_next_lut_15 && fb_data->tce_prevent && (fb_data->rev < 20)) {
+ dev_dbg(fb_data->dev, "Must wait for LUT15\n");
+ mutex_unlock(&fb_data->queue_mutex);
+ return;
+ }
+
+ /*
+ * Are any of our collision updates able to go now?
+ * Go through all updates in the collision list and check to see
+ * if the collision mask has been fully cleared
+ */
+ list_for_each_entry(collision_update,
+ &fb_data->upd_buf_collision_list, list) {
+
+ if (collision_update->collision_mask != 0)
+ continue;
+
+ dev_dbg(fb_data->dev, "A collision update is ready to go!\n");
+ /*
+ * We have a collision cleared, so select it
+ * and we will retry the update
+ */
+ fb_data->cur_update = collision_update;
+ list_del_init(&fb_data->cur_update->list);
+ break;
+ }
+
+ /*
+ * If we didn't find a collision update ready to go,
+ * we try to grab one from the update queue
+ */
+ if (fb_data->cur_update == NULL) {
+ /* Is update list empty? */
+ if (list_empty(&fb_data->upd_buf_queue)) {
+ dev_dbg(fb_data->dev, "No pending updates.\n");
+
+ /* No updates pending, so we are done */
+ mutex_unlock(&fb_data->queue_mutex);
+ return;
+ } else {
+ dev_dbg(fb_data->dev, "Found a pending update!\n");
+
+ /* Process next item in update list */
+ fb_data->cur_update =
+ list_entry(fb_data->upd_buf_queue.next,
+ struct update_data_list, list);
+ list_del_init(&fb_data->cur_update->list);
+ }
+ }
+
+ /* Use LUT selected above */
+ fb_data->cur_update->lut_num = next_lut;
+
+ /* Associate LUT with update markers */
+ list_for_each_entry_safe(next_marker, temp,
+ &fb_data->cur_update->update_desc->upd_marker_list, upd_list)
+ next_marker->lut_num = fb_data->cur_update->lut_num;
+
+ /* Mark LUT as containing new update */
+ fb_data->lut_update_order[fb_data->cur_update->lut_num] =
+ fb_data->cur_update->update_desc->update_order;
+
+ /* Enable Collision and WB complete IRQs */
+ epdc_working_buf_intr(true);
+ epdc_lut_complete_intr(fb_data->rev, fb_data->cur_update->lut_num, true);
+
+ /* Program EPDC update to process buffer */
+ next_upd_region =
+ &fb_data->cur_update->update_desc->upd_data.update_region;
+
+ /* add working buffer update here for external mode */
+ if (fb_data->epdc_wb_mode)
+ epdc_working_buffer_update(fb_data, fb_data->cur_update,
+ next_upd_region);
+
+ if (fb_data->cur_update->update_desc->upd_data.temp
+ != TEMP_USE_AMBIENT) {
+ temp_index = mxc_epdc_fb_get_temp_index(fb_data,
+ fb_data->cur_update->update_desc->upd_data.temp);
+ epdc_set_temp(temp_index);
+ } else
+ epdc_set_temp(fb_data->temp_index);
+ epdc_set_update_addr(fb_data->cur_update->phys_addr +
+ fb_data->cur_update->update_desc->epdc_offs);
+ epdc_set_update_coord(next_upd_region->left, next_upd_region->top);
+ epdc_set_update_dimensions(next_upd_region->width,
+ next_upd_region->height);
+ if (fb_data->rev > 20)
+ epdc_set_update_stride(fb_data->cur_update->update_desc->epdc_stride);
+ if (fb_data->wv_modes_update &&
+ (fb_data->cur_update->update_desc->upd_data.waveform_mode
+ == WAVEFORM_MODE_AUTO)) {
+ epdc_set_update_waveform(&fb_data->wv_modes);
+ fb_data->wv_modes_update = false;
+ }
+
+ epdc_submit_update(fb_data->cur_update->lut_num,
+ fb_data->cur_update->update_desc->upd_data.waveform_mode,
+ fb_data->cur_update->update_desc->upd_data.update_mode,
+ false, false, 0);
+
+ /* Release buffer queues */
+ mutex_unlock(&fb_data->queue_mutex);
+
+ return;
+}
+
+static void draw_mode0(struct mxc_epdc_fb_data *fb_data)
+{
+ u32 *upd_buf_ptr;
+ int i;
+ struct fb_var_screeninfo *screeninfo = &fb_data->epdc_fb_var;
+ u32 xres, yres;
+
+ upd_buf_ptr = (u32 *)fb_data->info.screen_base;
+
+ epdc_working_buf_intr(true);
+ epdc_lut_complete_intr(fb_data->rev, 0, true);
+
+ /* Use unrotated (native) width/height */
+ if ((screeninfo->rotate == FB_ROTATE_CW) ||
+ (screeninfo->rotate == FB_ROTATE_CCW)) {
+ xres = screeninfo->yres;
+ yres = screeninfo->xres;
+ } else {
+ xres = screeninfo->xres;
+ yres = screeninfo->yres;
+ }
+
+ /* Program EPDC update to process buffer */
+ epdc_set_update_addr(fb_data->phys_start);
+ epdc_set_update_coord(0, 0);
+ epdc_set_update_dimensions(xres, yres);
+ if (fb_data->rev > 20)
+ epdc_set_update_stride(0);
+ epdc_submit_update(0, fb_data->wv_modes.mode_init, UPDATE_MODE_FULL,
+ false, true, 0xFF);
+
+ dev_dbg(fb_data->dev, "Mode0 update - Waiting for LUT to complete...\n");
+
+ /* Will timeout after ~4-5 seconds */
+
+ for (i = 0; i < 40; i++) {
+ if (!epdc_is_lut_active(0)) {
+ dev_dbg(fb_data->dev, "Mode0 init complete\n");
+ return;
+ }
+ msleep(100);
+ }
+
+ dev_err(fb_data->dev, "Mode0 init failed!\n");
+
+ return;
+}
+
+
+static void mxc_epdc_fb_fw_handler(const struct firmware *fw,
+ void *context)
+{
+ struct mxc_epdc_fb_data *fb_data = context;
+ int ret;
+ struct mxcfb_waveform_data_file *wv_file;
+ int wv_data_offs;
+ int i;
+ struct mxcfb_update_data update;
+ struct mxcfb_update_marker_data upd_marker_data;
+ struct fb_var_screeninfo *screeninfo = &fb_data->epdc_fb_var;
+ u32 xres, yres;
+ struct clk *epdc_parent;
+ unsigned long rounded_parent_rate, epdc_pix_rate,
+ rounded_pix_clk, target_pix_clk;
+
+ if (fw == NULL) {
+ /* If default FW file load failed, we give up */
+ if (fb_data->fw_default_load)
+ return;
+
+ /* Try to load default waveform */
+ dev_dbg(fb_data->dev,
+ "Can't find firmware. Trying fallback fw\n");
+ fb_data->fw_default_load = true;
+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ "imx/epdc/epdc.fw", fb_data->dev, GFP_KERNEL, fb_data,
+ mxc_epdc_fb_fw_handler);
+ if (ret)
+ dev_err(fb_data->dev,
+ "Failed request_firmware_nowait err %d\n", ret);
+
+ return;
+ }
+
+ wv_file = (struct mxcfb_waveform_data_file *)fw->data;
+
+ dump_fw_header(fb_data->dev, wv_file);
+
+ /* Get size and allocate temperature range table */
+ fb_data->trt_entries = wv_file->wdh.trc + 1;
+ fb_data->temp_range_bounds = kzalloc(fb_data->trt_entries, GFP_KERNEL);
+
+ for (i = 0; i < fb_data->trt_entries; i++)
+ dev_dbg(fb_data->dev, "trt entry #%d = 0x%x\n", i, *((u8 *)&wv_file->data + i));
+
+ /* Copy TRT data */
+ memcpy(fb_data->temp_range_bounds, &wv_file->data, fb_data->trt_entries);
+
+ /* Set default temperature index using TRT and room temp */
+ fb_data->temp_index = mxc_epdc_fb_get_temp_index(fb_data, DEFAULT_TEMP);
+
+ /* Get offset and size for waveform data */
+ wv_data_offs = sizeof(wv_file->wdh) + fb_data->trt_entries + 1;
+ fb_data->waveform_buffer_size = fw->size - wv_data_offs;
+
+ /* Allocate memory for waveform data */
+ fb_data->waveform_buffer_virt = dma_alloc_coherent(fb_data->dev,
+ fb_data->waveform_buffer_size,
+ &fb_data->waveform_buffer_phys,
+ GFP_DMA | GFP_KERNEL);
+ if (fb_data->waveform_buffer_virt == NULL) {
+ dev_err(fb_data->dev, "Can't allocate mem for waveform!\n");
+ return;
+ }
+
+ memcpy(fb_data->waveform_buffer_virt, (u8 *)(fw->data) + wv_data_offs,
+ fb_data->waveform_buffer_size);
+
+ /* Check for advanced algorithms */
+ if ((wv_file->wdh.luts & WAVEFORM_HDR_LUT_ADVANCED_ALGO_MASK) != 0) {
+ dev_dbg(fb_data->dev,
+ "Waveform file supports advanced algorithms\n");
+ fb_data->waveform_is_advanced = true;
+ } else {
+ dev_dbg(fb_data->dev,
+ "Waveform file does not support advanced algorithms\n");
+ fb_data->waveform_is_advanced = false;
+ }
+
+ release_firmware(fw);
+
+ /* Enable clocks to access EPDC regs */
+ clk_prepare_enable(fb_data->epdc_clk_axi);
+
+ target_pix_clk = fb_data->cur_mode->vmode->pixclock;
+
+ rounded_pix_clk = clk_round_rate(fb_data->epdc_clk_pix, target_pix_clk);
+
+ if (((rounded_pix_clk >= target_pix_clk + target_pix_clk/100) ||
+ (rounded_pix_clk <= target_pix_clk - target_pix_clk/100))) {
+ /* Can't get close enough without changing parent clk */
+ epdc_parent = clk_get_parent(fb_data->epdc_clk_pix);
+ rounded_parent_rate = clk_round_rate(epdc_parent, target_pix_clk);
+
+ epdc_pix_rate = target_pix_clk;
+ while (epdc_pix_rate < rounded_parent_rate)
+ epdc_pix_rate *= 2;
+ clk_set_rate(epdc_parent, epdc_pix_rate);
+
+ rounded_pix_clk = clk_round_rate(fb_data->epdc_clk_pix, target_pix_clk);
+ if (((rounded_pix_clk >= target_pix_clk + target_pix_clk/100) ||
+ (rounded_pix_clk <= target_pix_clk - target_pix_clk/100)))
+ /* Still can't get a good clock, provide warning */
+ dev_err(fb_data->dev, "Unable to get an accurate EPDC pix clk"
+ "desired = %lu, actual = %lu\n", target_pix_clk,
+ rounded_pix_clk);
+ }
+
+ clk_set_rate(fb_data->epdc_clk_pix, rounded_pix_clk);
+
+ /* Enable pix clk for EPDC */
+ clk_prepare_enable(fb_data->epdc_clk_pix);
+
+ epdc_init_sequence(fb_data);
+
+ /* Disable clocks */
+ clk_disable_unprepare(fb_data->epdc_clk_axi);
+ clk_disable_unprepare(fb_data->epdc_clk_pix);
+
+ fb_data->hw_ready = true;
+ fb_data->hw_initializing = false;
+
+ /* Use unrotated (native) width/height */
+ if ((screeninfo->rotate == FB_ROTATE_CW) ||
+ (screeninfo->rotate == FB_ROTATE_CCW)) {
+ xres = screeninfo->yres;
+ yres = screeninfo->xres;
+ } else {
+ xres = screeninfo->xres;
+ yres = screeninfo->yres;
+ }
+
+ update.update_region.left = 0;
+ update.update_region.width = xres;
+ update.update_region.top = 0;
+ update.update_region.height = yres;
+ update.update_mode = UPDATE_MODE_FULL;
+ update.waveform_mode = WAVEFORM_MODE_AUTO;
+ update.update_marker = INIT_UPDATE_MARKER;
+ update.temp = TEMP_USE_AMBIENT;
+ update.flags = 0;
+ update.dither_mode = 0;
+
+ upd_marker_data.update_marker = update.update_marker;
+
+ mxc_epdc_fb_send_update(&update, &fb_data->info);
+
+ /* Block on initial update */
+ ret = mxc_epdc_fb_wait_update_complete(&upd_marker_data,
+ &fb_data->info);
+ if (ret < 0)
+ dev_err(fb_data->dev,
+ "Wait for initial update complete failed."
+ " Error = 0x%x", ret);
+}
+
+static int mxc_epdc_fb_init_hw(struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+ int ret;
+
+ /*
+ * Create fw search string based on ID string in selected videomode.
+ * Format is "imx/epdc/epdc_[panel string].fw"
+ */
+ if (fb_data->cur_mode) {
+ strcat(fb_data->fw_str, "imx/epdc/epdc_");
+ strcat(fb_data->fw_str, fb_data->cur_mode->vmode->name);
+ strcat(fb_data->fw_str, ".fw");
+ }
+
+ fb_data->fw_default_load = false;
+
+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ fb_data->fw_str, fb_data->dev, GFP_KERNEL,
+ fb_data, mxc_epdc_fb_fw_handler);
+ if (ret)
+ dev_dbg(fb_data->dev,
+ "Failed request_firmware_nowait err %d\n", ret);
+
+ return ret;
+}
+
+static ssize_t store_update(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mxcfb_update_data update;
+ struct fb_info *info = dev_get_drvdata(device);
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+
+ if (strncmp(buf, "direct", 6) == 0)
+ update.waveform_mode = fb_data->wv_modes.mode_du;
+ else if (strncmp(buf, "gc16", 4) == 0)
+ update.waveform_mode = fb_data->wv_modes.mode_gc16;
+ else if (strncmp(buf, "gc4", 3) == 0)
+ update.waveform_mode = fb_data->wv_modes.mode_gc4;
+
+ /* Now, request full screen update */
+ update.update_region.left = 0;
+ update.update_region.width = fb_data->epdc_fb_var.xres;
+ update.update_region.top = 0;
+ update.update_region.height = fb_data->epdc_fb_var.yres;
+ update.update_mode = UPDATE_MODE_FULL;
+ update.temp = TEMP_USE_AMBIENT;
+ update.update_marker = 0;
+ update.flags = 0;
+
+ mxc_epdc_fb_send_update(&update, info);
+
+ return count;
+}
+
+static struct device_attribute fb_attrs[] = {
+ __ATTR(update, S_IRUGO|S_IWUSR, NULL, store_update),
+};
+
+static const struct of_device_id imx_epdc_dt_ids[] = {
+ { .compatible = "fsl,imx7d-epdc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_epdc_dt_ids);
+
+static int mxc_epdc_fb_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct pinctrl *pinctrl;
+ struct mxc_epdc_fb_data *fb_data;
+ struct resource *res;
+ struct fb_info *info;
+ char *options, *opt;
+ char *panel_str = NULL;
+ char name[] = "mxcepdcfb";
+ struct fb_videomode *vmode;
+ int xres_virt, yres_virt, buf_size;
+ int xres_virt_rot, yres_virt_rot, pix_size_rot;
+ struct fb_var_screeninfo *var_info;
+ struct fb_fix_screeninfo *fix_info;
+ struct pxp_config_data *pxp_conf;
+ struct pxp_proc_data *proc_data;
+ struct scatterlist *sg;
+ struct update_data_list *upd_list;
+ struct update_data_list *plist, *temp_list;
+ int i;
+ unsigned long x_mem_size = 0;
+ u32 val;
+ int irq;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *node;
+ phandle phandle;
+ u32 out_val[3];
+ int enable_gpio;
+ enum of_gpio_flags flag;
+ unsigned short *wk_p;
+
+ if (!np)
+ return -EINVAL;
+
+ fb_data = (struct mxc_epdc_fb_data *)framebuffer_alloc(
+ sizeof(struct mxc_epdc_fb_data), &pdev->dev);
+ if (fb_data == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = of_property_read_u32_array(np, "epdc-ram", out_val, 3);
+ if (ret) {
+ dev_dbg(&pdev->dev, "no epdc-ram property found\n");
+ } else {
+ phandle = *out_val;
+
+ node = of_find_node_by_phandle(phandle);
+ if (!node) {
+ dev_dbg(&pdev->dev, "not find gpr node by phandle\n");
+ ret = PTR_ERR(node);
+ goto out_fbdata;
+ }
+ fb_data->gpr = syscon_node_to_regmap(node);
+ if (IS_ERR(fb_data->gpr)) {
+ dev_err(&pdev->dev, "failed to get gpr regmap\n");
+ ret = PTR_ERR(fb_data->gpr);
+ goto out_fbdata;
+ }
+ of_node_put(node);
+ fb_data->req_gpr = out_val[1];
+ fb_data->req_bit = out_val[2];
+
+ regmap_update_bits(fb_data->gpr, fb_data->req_gpr,
+ 1 << fb_data->req_bit, 0);
+ }
+
+ if (of_find_property(np, "en-gpios", NULL)) {
+ enable_gpio = of_get_named_gpio_flags(np, "en-gpios", 0, &flag);
+ if (enable_gpio == -EPROBE_DEFER) {
+ dev_info(&pdev->dev, "GPIO requested is not"
+ "here yet, deferring the probe\n");
+ return -EPROBE_DEFER;
+ }
+ if (!gpio_is_valid(enable_gpio)) {
+ dev_warn(&pdev->dev, "No dt property: en-gpios\n");
+ } else {
+
+ ret = devm_gpio_request_one(&pdev->dev,
+ enable_gpio,
+ (flag & OF_GPIO_ACTIVE_LOW)
+ ? GPIOF_OUT_INIT_LOW :
+ GPIOF_OUT_INIT_HIGH,
+ "en_pins");
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request gpio"
+ " %d: %d\n", enable_gpio, ret);
+ return -EINVAL;
+ }
+ }
+ }
+
+ /* Get platform data and check validity */
+ fb_data->pdata = &epdc_data;
+ if ((fb_data->pdata == NULL) || (fb_data->pdata->num_modes < 1)
+ || (fb_data->pdata->epdc_mode == NULL)
+ || (fb_data->pdata->epdc_mode->vmode == NULL)) {
+ ret = -EINVAL;
+ goto out_fbdata;
+ }
+
+ if (fb_get_options(name, &options)) {
+ ret = -ENODEV;
+ goto out_fbdata;
+ }
+
+ fb_data->epdc_wb_mode = 1;
+ fb_data->tce_prevent = 0;
+
+ if (options)
+ while ((opt = strsep(&options, ",")) != NULL) {
+ if (!*opt)
+ continue;
+
+ if (!strncmp(opt, "bpp=", 4))
+ fb_data->default_bpp =
+ simple_strtoul(opt + 4, NULL, 0);
+ else if (!strncmp(opt, "x_mem=", 6))
+ x_mem_size = memparse(opt + 6, NULL);
+ else if (!strncmp(opt, "tce_prevent", 11))
+ fb_data->tce_prevent = 1;
+ else
+ panel_str = opt;
+ }
+
+ fb_data->dev = &pdev->dev;
+
+ if (!fb_data->default_bpp)
+ fb_data->default_bpp = 16;
+
+ /* Set default (first defined mode) before searching for a match */
+ fb_data->cur_mode = &fb_data->pdata->epdc_mode[0];
+
+ if (panel_str)
+ for (i = 0; i < fb_data->pdata->num_modes; i++)
+ if (!strcmp(fb_data->pdata->epdc_mode[i].vmode->name,
+ panel_str)) {
+ fb_data->cur_mode =
+ &fb_data->pdata->epdc_mode[i];
+ break;
+ }
+
+ vmode = fb_data->cur_mode->vmode;
+
+ platform_set_drvdata(pdev, fb_data);
+ info = &fb_data->info;
+
+ /* Allocate color map for the FB */
+ ret = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (ret)
+ goto out_fbdata;
+
+ dev_dbg(&pdev->dev, "resolution %dx%d, bpp %d\n",
+ vmode->xres, vmode->yres, fb_data->default_bpp);
+
+ /*
+ * GPU alignment restrictions dictate framebuffer parameters:
+ * - 32-byte alignment for buffer width
+ * - 128-byte alignment for buffer height
+ * => 4K buffer alignment for buffer start
+ */
+ xres_virt = ALIGN(vmode->xres, 32);
+ yres_virt = ALIGN(vmode->yres, 128);
+ fb_data->max_pix_size = PAGE_ALIGN(xres_virt * yres_virt);
+
+ /*
+ * Have to check to see if aligned buffer size when rotated
+ * is bigger than when not rotated, and use the max
+ */
+ xres_virt_rot = ALIGN(vmode->yres, 32);
+ yres_virt_rot = ALIGN(vmode->xres, 128);
+ pix_size_rot = PAGE_ALIGN(xres_virt_rot * yres_virt_rot);
+ fb_data->max_pix_size = (fb_data->max_pix_size > pix_size_rot) ?
+ fb_data->max_pix_size : pix_size_rot;
+
+ buf_size = fb_data->max_pix_size * fb_data->default_bpp/8;
+
+ /* Compute the number of screens needed based on X memory requested */
+ if (x_mem_size > 0) {
+ fb_data->num_screens = DIV_ROUND_UP(x_mem_size, buf_size);
+ if (fb_data->num_screens < NUM_SCREENS_MIN)
+ fb_data->num_screens = NUM_SCREENS_MIN;
+ else if (buf_size * fb_data->num_screens > SZ_16M)
+ fb_data->num_screens = SZ_16M / buf_size;
+ } else
+ fb_data->num_screens = NUM_SCREENS_MIN;
+
+ fb_data->map_size = buf_size * fb_data->num_screens;
+ dev_dbg(&pdev->dev, "memory to allocate: %d\n", fb_data->map_size);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ ret = -ENODEV;
+ goto out_cmap;
+ }
+
+ epdc_v2_base = devm_ioremap_resource(&pdev->dev, res);
+ if (epdc_v2_base == NULL) {
+ ret = -ENOMEM;
+ goto out_cmap;
+ }
+
+ /* Allocate FB memory */
+ info->screen_base = dma_alloc_writecombine(&pdev->dev,
+ fb_data->map_size,
+ &fb_data->phys_start,
+ GFP_DMA | GFP_KERNEL);
+
+ if (info->screen_base == NULL) {
+ ret = -ENOMEM;
+ goto out_cmap;
+ }
+ dev_dbg(&pdev->dev, "allocated at %p:0x%x\n", info->screen_base,
+ fb_data->phys_start);
+
+ var_info = &info->var;
+ var_info->activate = FB_ACTIVATE_TEST;
+ var_info->bits_per_pixel = fb_data->default_bpp;
+ var_info->xres = vmode->xres;
+ var_info->yres = vmode->yres;
+ var_info->xres_virtual = xres_virt;
+ /* Additional screens allow for panning and buffer flipping */
+ var_info->yres_virtual = yres_virt * fb_data->num_screens;
+
+ var_info->pixclock = vmode->pixclock;
+ var_info->left_margin = vmode->left_margin;
+ var_info->right_margin = vmode->right_margin;
+ var_info->upper_margin = vmode->upper_margin;
+ var_info->lower_margin = vmode->lower_margin;
+ var_info->hsync_len = vmode->hsync_len;
+ var_info->vsync_len = vmode->vsync_len;
+ var_info->vmode = FB_VMODE_NONINTERLACED;
+
+ switch (fb_data->default_bpp) {
+ case 32:
+ case 24:
+ var_info->red.offset = 16;
+ var_info->red.length = 8;
+ var_info->green.offset = 8;
+ var_info->green.length = 8;
+ var_info->blue.offset = 0;
+ var_info->blue.length = 8;
+ break;
+
+ case 16:
+ var_info->red.offset = 11;
+ var_info->red.length = 5;
+ var_info->green.offset = 5;
+ var_info->green.length = 6;
+ var_info->blue.offset = 0;
+ var_info->blue.length = 5;
+ break;
+
+ case 8:
+ /*
+ * For 8-bit grayscale, R, G, and B offset are equal.
+ *
+ */
+ var_info->grayscale = GRAYSCALE_8BIT;
+
+ var_info->red.length = 8;
+ var_info->red.offset = 0;
+ var_info->red.msb_right = 0;
+ var_info->green.length = 8;
+ var_info->green.offset = 0;
+ var_info->green.msb_right = 0;
+ var_info->blue.length = 8;
+ var_info->blue.offset = 0;
+ var_info->blue.msb_right = 0;
+ break;
+
+ default:
+ dev_err(&pdev->dev, "unsupported bitwidth %d\n",
+ fb_data->default_bpp);
+ ret = -EINVAL;
+ goto out_dma_fb;
+ }
+
+ fix_info = &info->fix;
+
+ strcpy(fix_info->id, "mxc_epdc_fb");
+ fix_info->type = FB_TYPE_PACKED_PIXELS;
+ fix_info->visual = FB_VISUAL_TRUECOLOR;
+ fix_info->xpanstep = 0;
+ fix_info->ypanstep = 0;
+ fix_info->ywrapstep = 0;
+ fix_info->accel = FB_ACCEL_NONE;
+ fix_info->smem_start = fb_data->phys_start;
+ fix_info->smem_len = fb_data->map_size;
+ fix_info->ypanstep = 0;
+
+ fb_data->native_width = vmode->xres;
+ fb_data->native_height = vmode->yres;
+
+ info->fbops = &mxc_epdc_fb_ops;
+ info->var.activate = FB_ACTIVATE_NOW;
+ info->pseudo_palette = fb_data->pseudo_palette;
+ info->screen_size = info->fix.smem_len;
+ info->flags = FBINFO_FLAG_DEFAULT;
+
+ mxc_epdc_fb_set_fix(info);
+
+ fb_data->auto_mode = AUTO_UPDATE_MODE_REGION_MODE;
+ fb_data->upd_scheme = UPDATE_SCHEME_QUEUE_AND_MERGE;
+
+ /* Initialize our internal copy of the screeninfo */
+ fb_data->epdc_fb_var = *var_info;
+ fb_data->fb_offset = 0;
+ fb_data->eof_sync_period = 0;
+
+ fb_data->epdc_clk_axi = clk_get(fb_data->dev, "epdc_axi");
+ if (IS_ERR(fb_data->epdc_clk_axi)) {
+ dev_err(&pdev->dev, "Unable to get EPDC AXI clk."
+ "err = %d\n", (int)fb_data->epdc_clk_axi);
+ ret = -ENODEV;
+ goto out_dma_fb;
+ }
+ fb_data->epdc_clk_pix = clk_get(fb_data->dev, "epdc_pix");
+ if (IS_ERR(fb_data->epdc_clk_pix)) {
+ dev_err(&pdev->dev, "Unable to get EPDC pix clk."
+ "err = %d\n", (int)fb_data->epdc_clk_pix);
+ ret = -ENODEV;
+ goto out_dma_fb;
+ }
+
+ clk_prepare_enable(fb_data->epdc_clk_axi);
+ clk_prepare_enable(fb_data->epdc_clk_pix);
+ val = __raw_readl(EPDC_VERSION);
+ clk_disable_unprepare(fb_data->epdc_clk_pix);
+ clk_disable_unprepare(fb_data->epdc_clk_axi);
+ fb_data->rev = ((val & EPDC_VERSION_MAJOR_MASK) >>
+ EPDC_VERSION_MAJOR_OFFSET) * 10
+ + ((val & EPDC_VERSION_MINOR_MASK) >>
+ EPDC_VERSION_MINOR_OFFSET);
+ dev_dbg(&pdev->dev, "EPDC version = %d\n", fb_data->rev);
+
+ if (fb_data->rev < 20) {
+ fb_data->num_luts = EPDC_V1_NUM_LUTS;
+ fb_data->max_num_updates = EPDC_V1_MAX_NUM_UPDATES;
+ } else {
+ fb_data->num_luts = EPDC_V2_NUM_LUTS;
+ fb_data->max_num_updates = EPDC_V2_MAX_NUM_UPDATES;
+ if (vmode->xres > EPDC_V2_MAX_UPDATE_WIDTH)
+ fb_data->restrict_width = true;
+ }
+ fb_data->max_num_buffers = EPDC_MAX_NUM_BUFFERS;
+
+ /*
+ * Initialize lists for pending updates,
+ * active update requests, update collisions,
+ * and freely available updates.
+ */
+ INIT_LIST_HEAD(&fb_data->upd_pending_list);
+ INIT_LIST_HEAD(&fb_data->upd_buf_queue);
+ INIT_LIST_HEAD(&fb_data->upd_buf_free_list);
+ INIT_LIST_HEAD(&fb_data->upd_buf_collision_list);
+
+ /* Allocate update buffers and add them to the list */
+ for (i = 0; i < fb_data->max_num_updates; i++) {
+ upd_list = kzalloc(sizeof(*upd_list), GFP_KERNEL);
+ if (upd_list == NULL) {
+ ret = -ENOMEM;
+ goto out_upd_lists;
+ }
+
+ /* Add newly allocated buffer to free list */
+ list_add(&upd_list->list, &fb_data->upd_buf_free_list);
+ }
+
+ fb_data->virt_addr_updbuf =
+ kzalloc(sizeof(void *) * fb_data->max_num_buffers, GFP_KERNEL);
+ fb_data->phys_addr_updbuf =
+ kzalloc(sizeof(dma_addr_t) * fb_data->max_num_buffers,
+ GFP_KERNEL);
+ for (i = 0; i < fb_data->max_num_buffers; i++) {
+ /*
+ * Allocate memory for PxP output buffer.
+ * Each update buffer is 1 byte per pixel, and can
+ * be as big as the full-screen frame buffer
+ */
+ fb_data->virt_addr_updbuf[i] =
+ kmalloc(fb_data->max_pix_size, GFP_KERNEL);
+ fb_data->phys_addr_updbuf[i] =
+ virt_to_phys(fb_data->virt_addr_updbuf[i]);
+ if (fb_data->virt_addr_updbuf[i] == NULL) {
+ ret = -ENOMEM;
+ goto out_upd_buffers;
+ }
+
+ dev_dbg(fb_data->info.device, "allocated %d bytes @ 0x%08X\n",
+ fb_data->max_pix_size, fb_data->phys_addr_updbuf[i]);
+ }
+
+ /* Counter indicating which update buffer should be used next. */
+ fb_data->upd_buffer_num = 0;
+
+ /*
+ * Allocate memory for PxP SW workaround buffer
+ * These buffers are used to hold copy of the update region,
+ * before sending it to PxP for processing.
+ */
+ fb_data->virt_addr_copybuf =
+ dma_alloc_coherent(fb_data->info.device, fb_data->max_pix_size*2,
+ &fb_data->phys_addr_copybuf,
+ GFP_DMA | GFP_KERNEL);
+ if (fb_data->virt_addr_copybuf == NULL) {
+ ret = -ENOMEM;
+ goto out_upd_buffers;
+ }
+
+ fb_data->virt_addr_y4 =
+ dma_alloc_coherent(fb_data->info.device, fb_data->max_pix_size*2,
+ &fb_data->phys_addr_y4,
+ GFP_DMA | GFP_KERNEL);
+ if (fb_data->virt_addr_y4 == NULL) {
+ ret = -ENOMEM;
+ goto out_upd_buffers;
+ }
+
+ fb_data->virt_addr_y4c =
+ dma_alloc_coherent(fb_data->info.device, fb_data->max_pix_size*2,
+ &fb_data->phys_addr_y4c,
+ GFP_DMA | GFP_KERNEL);
+ if (fb_data->virt_addr_y4c == NULL) {
+ ret = -ENOMEM;
+ goto out_upd_buffers;
+ }
+
+ fb_data->virt_addr_black =
+ dma_alloc_coherent(fb_data->info.device, fb_data->max_pix_size*2,
+ &fb_data->phys_addr_black,
+ GFP_DMA | GFP_KERNEL);
+ if (fb_data->virt_addr_black == NULL) {
+ ret = -ENOMEM;
+ goto out_upd_buffers;
+ }
+
+ fb_data->working_buffer_size = vmode->yres * vmode->xres * 2;
+
+ /* Allocate memory for EPDC working buffer */
+ fb_data->working_buffer_virt =
+ dma_alloc_coherent(&pdev->dev, fb_data->working_buffer_size,
+ &fb_data->working_buffer_phys,
+ GFP_DMA | GFP_KERNEL);
+ if (fb_data->working_buffer_virt == NULL) {
+ dev_err(&pdev->dev, "Can't allocate mem for working buf!\n");
+ ret = -ENOMEM;
+ goto out_copybuffer;
+ }
+
+ /* initialize the working buffer */
+ wk_p = (unsigned short *)fb_data->working_buffer_virt;
+ for (i = 0; i < fb_data->cur_mode->vmode->xres *
+ fb_data->cur_mode->vmode->yres; i++) {
+ *wk_p = 0x00F0;
+ wk_p++;
+ }
+
+ fb_data->tmp_working_buffer_virt =
+ dma_alloc_coherent(&pdev->dev, fb_data->working_buffer_size,
+ &fb_data->tmp_working_buffer_phys,
+ GFP_DMA | GFP_KERNEL);
+ if (fb_data->tmp_working_buffer_virt == NULL) {
+ dev_err(&pdev->dev, "Can't allocate mem for tmp working buf!\n");
+ ret = -ENOMEM;
+ goto out_copybuffer;
+ }
+
+ /* Initialize EPDC pins */
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ dev_err(&pdev->dev, "can't get/select pinctrl\n");
+ ret = PTR_ERR(pinctrl);
+ goto out_copybuffer;
+ }
+
+ fb_data->in_init = false;
+
+ fb_data->hw_ready = false;
+ fb_data->hw_initializing = false;
+
+ /*
+ * Set default waveform mode values.
+ * Should be overwritten via ioctl.
+ */
+ fb_data->wv_modes.mode_init = 0;
+ fb_data->wv_modes.mode_du = 1;
+ fb_data->wv_modes.mode_gc4 = 3;
+ fb_data->wv_modes.mode_gc8 = 2;
+ fb_data->wv_modes.mode_gc16 = 2;
+ fb_data->wv_modes.mode_gc32 = 2;
+ fb_data->wv_modes_update = true;
+
+ /* Initialize marker list */
+ INIT_LIST_HEAD(&fb_data->full_marker_list);
+
+ /* Initialize all LUTs to inactive */
+ fb_data->lut_update_order =
+ kzalloc(fb_data->num_luts * sizeof(u32 *), GFP_KERNEL);
+ for (i = 0; i < fb_data->num_luts; i++)
+ fb_data->lut_update_order[i] = 0;
+
+ INIT_DELAYED_WORK(&fb_data->epdc_done_work, epdc_done_work_func);
+ fb_data->epdc_submit_workqueue = alloc_workqueue("EPDC Submit",
+ WQ_MEM_RECLAIM | WQ_HIGHPRI |
+ WQ_CPU_INTENSIVE | WQ_UNBOUND, 1);
+ INIT_WORK(&fb_data->epdc_submit_work, epdc_submit_work_func);
+ fb_data->epdc_intr_workqueue = alloc_workqueue("EPDC Interrupt",
+ WQ_MEM_RECLAIM | WQ_HIGHPRI |
+ WQ_CPU_INTENSIVE | WQ_UNBOUND, 1);
+ INIT_WORK(&fb_data->epdc_intr_work, epdc_intr_work_func);
+
+ /* Retrieve EPDC IRQ num */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "cannot get IRQ resource\n");
+ ret = -ENODEV;
+ goto out_dma_work_buf;
+ }
+ fb_data->epdc_irq = irq;
+
+ /* Register IRQ handler */
+ ret = devm_request_irq(&pdev->dev, fb_data->epdc_irq,
+ mxc_epdc_irq_handler, 0, "epdc", fb_data);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq (%d) failed with error %d\n",
+ fb_data->epdc_irq, ret);
+ ret = -ENODEV;
+ goto out_dma_work_buf;
+ }
+
+ info->fbdefio = &mxc_epdc_fb_defio;
+#ifdef CONFIG_FB_MXC_EINK_AUTO_UPDATE_MODE
+ fb_deferred_io_init(info);
+#endif
+
+ /* get pmic regulators */
+ fb_data->display_regulator = devm_regulator_get(&pdev->dev, "DISPLAY");
+ if (IS_ERR(fb_data->display_regulator)) {
+ dev_err(&pdev->dev, "Unable to get display PMIC regulator."
+ "err = 0x%x\n", (int)fb_data->display_regulator);
+ ret = -ENODEV;
+ goto out_dma_work_buf;
+ }
+ fb_data->vcom_regulator = devm_regulator_get(&pdev->dev, "VCOM");
+ if (IS_ERR(fb_data->vcom_regulator)) {
+ dev_err(&pdev->dev, "Unable to get VCOM regulator."
+ "err = 0x%x\n", (int)fb_data->vcom_regulator);
+ ret = -ENODEV;
+ goto out_dma_work_buf;
+ }
+ fb_data->v3p3_regulator = devm_regulator_get(&pdev->dev, "V3P3");
+ if (IS_ERR(fb_data->v3p3_regulator)) {
+ dev_err(&pdev->dev, "Unable to get V3P3 regulator."
+ "err = 0x%x\n", (int)fb_data->vcom_regulator);
+ ret = -ENODEV;
+ goto out_dma_work_buf;
+ }
+
+ if (device_create_file(info->dev, &fb_attrs[0]))
+ dev_err(&pdev->dev, "Unable to create file from fb_attrs\n");
+
+ fb_data->cur_update = NULL;
+
+ mutex_init(&fb_data->queue_mutex);
+ mutex_init(&fb_data->pxp_mutex);
+ mutex_init(&fb_data->power_mutex);
+
+ /*
+ * Fill out PxP config data structure based on FB info and
+ * processing tasks required
+ */
+ pxp_conf = &fb_data->pxp_conf;
+ proc_data = &pxp_conf->proc_data;
+
+ /* Initialize non-channel-specific PxP parameters */
+ proc_data->drect.left = proc_data->srect.left = 0;
+ proc_data->drect.top = proc_data->srect.top = 0;
+ proc_data->drect.width = proc_data->srect.width = fb_data->info.var.xres;
+ proc_data->drect.height = proc_data->srect.height = fb_data->info.var.yres;
+ proc_data->scaling = 0;
+ proc_data->hflip = 0;
+ proc_data->vflip = 0;
+ proc_data->rotate = 0;
+ proc_data->bgcolor = 0;
+ proc_data->overlay_state = 0;
+ proc_data->lut_transform = PXP_LUT_NONE;
+ proc_data->lut_map = NULL;
+
+ /*
+ * We initially configure PxP for RGB->YUV conversion,
+ * and only write out Y component of the result.
+ */
+
+ /*
+ * Initialize S0 channel parameters
+ * Parameters should match FB format/width/height
+ */
+ pxp_conf->s0_param.pixel_fmt = PXP_PIX_FMT_RGB565;
+ pxp_conf->s0_param.width = fb_data->info.var.xres_virtual;
+ pxp_conf->s0_param.stride = (var_info->bits_per_pixel * pxp_conf->s0_param.width) >> 3;
+ pxp_conf->s0_param.height = fb_data->info.var.yres;
+ pxp_conf->s0_param.color_key = -1;
+ pxp_conf->s0_param.color_key_enable = false;
+
+ /*
+ * Initialize OL0 channel parameters
+ * No overlay will be used for PxP operation
+ */
+ pxp_conf->ol_param[0].combine_enable = false;
+ pxp_conf->ol_param[0].width = 0;
+ pxp_conf->ol_param[0].height = 0;
+ pxp_conf->ol_param[0].pixel_fmt = PXP_PIX_FMT_RGB565;
+ pxp_conf->ol_param[0].color_key_enable = false;
+ pxp_conf->ol_param[0].color_key = -1;
+ pxp_conf->ol_param[0].global_alpha_enable = false;
+ pxp_conf->ol_param[0].global_alpha = 0;
+ pxp_conf->ol_param[0].local_alpha_enable = false;
+
+ /*
+ * Initialize Output channel parameters
+ * Output is Y-only greyscale
+ * Output width/height will vary based on update region size
+ */
+ pxp_conf->out_param.width = fb_data->info.var.xres;
+ pxp_conf->out_param.height = fb_data->info.var.yres;
+ pxp_conf->out_param.stride = pxp_conf->out_param.width;
+ pxp_conf->out_param.pixel_fmt = PXP_PIX_FMT_GREY;
+
+ /* Initialize color map for conversion of 8-bit gray pixels */
+ fb_data->pxp_conf.proc_data.lut_map = kmalloc(256, GFP_KERNEL);
+ if (fb_data->pxp_conf.proc_data.lut_map == NULL) {
+ dev_err(&pdev->dev, "Can't allocate mem for lut map!\n");
+ ret = -ENOMEM;
+ goto out_dma_work_buf;
+ }
+ for (i = 0; i < 256; i++)
+ fb_data->pxp_conf.proc_data.lut_map[i] = i;
+
+ fb_data->pxp_conf.proc_data.lut_map_updated = true;
+
+ /*
+ * Ensure this is set to NULL here...we will initialize pxp_chan
+ * later in our thread.
+ */
+ fb_data->pxp_chan = NULL;
+
+ /* Initialize Scatter-gather list containing 2 buffer addresses. */
+ sg = fb_data->sg;
+ sg_init_table(sg, SG_NUM);
+
+ /*
+ * For use in PxP transfers:
+ * sg[0] holds the FB buffer pointer
+ * sg[1] holds the Output buffer pointer (configured before TX request)
+ */
+ sg_dma_address(&sg[0]) = info->fix.smem_start;
+ sg_set_page(&sg[0], virt_to_page(info->screen_base),
+ info->fix.smem_len, offset_in_page(info->screen_base));
+
+ fb_data->order_cnt = 0;
+ fb_data->waiting_for_wb = false;
+ fb_data->waiting_for_lut = false;
+ fb_data->waiting_for_lut15 = false;
+ fb_data->waiting_for_idle = false;
+ fb_data->blank = FB_BLANK_UNBLANK;
+ fb_data->power_state = POWER_STATE_OFF;
+ fb_data->powering_down = false;
+ fb_data->wait_for_powerdown = false;
+ fb_data->updates_active = false;
+ fb_data->pwrdown_delay = 0;
+
+ /* Register FB */
+ ret = register_framebuffer(info);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "register_framebuffer failed with error %d\n", ret);
+ goto out_lutmap;
+ }
+
+ g_fb_data = fb_data;
+
+ pm_runtime_enable(fb_data->dev);
+
+#ifdef DEFAULT_PANEL_HW_INIT
+ ret = mxc_epdc_fb_init_hw((struct fb_info *)fb_data);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to initialize HW!\n");
+ }
+#endif
+
+ goto out;
+
+out_lutmap:
+ kfree(fb_data->pxp_conf.proc_data.lut_map);
+out_dma_work_buf:
+ dma_free_writecombine(&pdev->dev, fb_data->working_buffer_size,
+ fb_data->working_buffer_virt, fb_data->working_buffer_phys);
+out_copybuffer:
+ dma_free_writecombine(&pdev->dev, fb_data->max_pix_size*2,
+ fb_data->virt_addr_copybuf,
+ fb_data->phys_addr_copybuf);
+out_upd_buffers:
+ for (i = 0; i < fb_data->max_num_buffers; i++)
+ if (fb_data->virt_addr_updbuf[i] != NULL)
+ kfree(fb_data->virt_addr_updbuf[i]);
+ if (fb_data->virt_addr_updbuf != NULL)
+ kfree(fb_data->virt_addr_updbuf);
+ if (fb_data->phys_addr_updbuf != NULL)
+ kfree(fb_data->phys_addr_updbuf);
+out_upd_lists:
+ list_for_each_entry_safe(plist, temp_list, &fb_data->upd_buf_free_list,
+ list) {
+ list_del(&plist->list);
+ kfree(plist);
+ }
+out_dma_fb:
+ dma_free_writecombine(&pdev->dev, fb_data->map_size, info->screen_base,
+ fb_data->phys_start);
+
+out_cmap:
+ fb_dealloc_cmap(&info->cmap);
+out_fbdata:
+ kfree(fb_data);
+out:
+ return ret;
+}
+
+static int mxc_epdc_fb_remove(struct platform_device *pdev)
+{
+ struct update_data_list *plist, *temp_list;
+ struct mxc_epdc_fb_data *fb_data = platform_get_drvdata(pdev);
+ int i;
+
+ mxc_epdc_fb_blank(FB_BLANK_POWERDOWN, &fb_data->info);
+
+ flush_workqueue(fb_data->epdc_submit_workqueue);
+ destroy_workqueue(fb_data->epdc_submit_workqueue);
+
+ unregister_framebuffer(&fb_data->info);
+
+ for (i = 0; i < fb_data->max_num_buffers; i++)
+ if (fb_data->virt_addr_updbuf[i] != NULL)
+ kfree(fb_data->virt_addr_updbuf[i]);
+ if (fb_data->virt_addr_updbuf != NULL)
+ kfree(fb_data->virt_addr_updbuf);
+ if (fb_data->phys_addr_updbuf != NULL)
+ kfree(fb_data->phys_addr_updbuf);
+
+ dma_free_writecombine(&pdev->dev, fb_data->working_buffer_size,
+ fb_data->working_buffer_virt,
+ fb_data->working_buffer_phys);
+ if (fb_data->waveform_buffer_virt != NULL)
+ dma_free_writecombine(&pdev->dev, fb_data->waveform_buffer_size,
+ fb_data->waveform_buffer_virt,
+ fb_data->waveform_buffer_phys);
+ if (fb_data->virt_addr_copybuf != NULL)
+ dma_free_writecombine(&pdev->dev, fb_data->max_pix_size*2,
+ fb_data->virt_addr_copybuf,
+ fb_data->phys_addr_copybuf);
+ list_for_each_entry_safe(plist, temp_list, &fb_data->upd_buf_free_list,
+ list) {
+ list_del(&plist->list);
+ kfree(plist);
+ }
+#ifdef CONFIG_FB_MXC_EINK_AUTO_UPDATE_MODE
+ fb_deferred_io_cleanup(&fb_data->info);
+#endif
+
+ dma_free_writecombine(&pdev->dev, fb_data->map_size, fb_data->info.screen_base,
+ fb_data->phys_start);
+
+ /* Release PxP-related resources */
+ if (fb_data->pxp_chan != NULL)
+ dma_release_channel(&fb_data->pxp_chan->dma_chan);
+
+ fb_dealloc_cmap(&fb_data->info.cmap);
+
+ framebuffer_release(&fb_data->info);
+ if (!IS_ERR_OR_NULL(fb_data->gpr))
+ regmap_update_bits(fb_data->gpr, fb_data->req_gpr,
+ 1 << fb_data->req_bit, 1 << fb_data->req_bit);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mxc_epdc_fb_suspend(struct device *dev)
+{
+ struct mxc_epdc_fb_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ data->pwrdown_delay = FB_POWERDOWN_DISABLE;
+ ret = mxc_epdc_fb_blank(FB_BLANK_POWERDOWN, &data->info);
+
+ if (ret)
+ goto out;
+
+out:
+ pinctrl_pm_select_sleep_state(dev);
+
+ return ret;
+}
+
+static int mxc_epdc_fb_resume(struct device *dev)
+{
+ struct mxc_epdc_fb_data *data = dev_get_drvdata(dev);
+
+ pinctrl_pm_select_default_state(dev);
+
+ mxc_epdc_fb_blank(FB_BLANK_UNBLANK, &data->info);
+ epdc_init_settings(data);
+ data->updates_active = false;
+
+ return 0;
+}
+#else
+#define mxc_epdc_fb_suspend NULL
+#define mxc_epdc_fb_resume NULL
+#endif
+
+#ifdef CONFIG_PM
+static int mxc_epdc_fb_runtime_suspend(struct device *dev)
+{
+ release_bus_freq(BUS_FREQ_HIGH);
+ dev_dbg(dev, "epdc busfreq high release.\n");
+
+ return 0;
+}
+
+static int mxc_epdc_fb_runtime_resume(struct device *dev)
+{
+ request_bus_freq(BUS_FREQ_HIGH);
+ dev_dbg(dev, "epdc busfreq high request.\n");
+
+ return 0;
+}
+#else
+#define mxc_epdc_fb_runtime_suspend NULL
+#define mxc_epdc_fb_runtime_resume NULL
+#endif
+
+static const struct dev_pm_ops mxc_epdc_fb_pm_ops = {
+ SET_RUNTIME_PM_OPS(mxc_epdc_fb_runtime_suspend,
+ mxc_epdc_fb_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(mxc_epdc_fb_suspend, mxc_epdc_fb_resume)
+};
+
+static void mxc_epdc_fb_shutdown(struct platform_device *pdev)
+{
+ struct mxc_epdc_fb_data *fb_data = platform_get_drvdata(pdev);
+
+ /* Disable power to the EPD panel */
+ if (regulator_is_enabled(fb_data->vcom_regulator))
+ regulator_disable(fb_data->vcom_regulator);
+ if (regulator_is_enabled(fb_data->display_regulator))
+ regulator_disable(fb_data->display_regulator);
+
+ /* Disable clocks to EPDC */
+ clk_prepare_enable(fb_data->epdc_clk_axi);
+ clk_prepare_enable(fb_data->epdc_clk_pix);
+ __raw_writel(EPDC_CTRL_CLKGATE, EPDC_CTRL_SET);
+ clk_disable_unprepare(fb_data->epdc_clk_pix);
+ clk_disable_unprepare(fb_data->epdc_clk_axi);
+
+ /* turn off the V3p3 */
+ if (regulator_is_enabled(fb_data->v3p3_regulator))
+ regulator_disable(fb_data->v3p3_regulator);
+}
+
+static struct platform_driver mxc_epdc_fb_driver = {
+ .probe = mxc_epdc_fb_probe,
+ .remove = mxc_epdc_fb_remove,
+ .shutdown = mxc_epdc_fb_shutdown,
+ .driver = {
+ .name = "imx_epdc_v2_fb",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(imx_epdc_dt_ids),
+ .pm = &mxc_epdc_fb_pm_ops,
+ },
+};
+
+/* Callback function triggered after PxP receives an EOF interrupt */
+static void pxp_dma_done(void *arg)
+{
+ struct pxp_tx_desc *tx_desc = to_tx_desc(arg);
+ struct dma_chan *chan = tx_desc->txd.chan;
+ struct pxp_channel *pxp_chan = to_pxp_channel(chan);
+ struct mxc_epdc_fb_data *fb_data = pxp_chan->client;
+
+ /*
+ * if epd works in external mode, we should queue epdc_intr_workqueue
+ * after a wfe_a process finishes.
+ */
+ if (fb_data->epdc_wb_mode && (tx_desc->proc_data.engine_enable & PXP_ENABLE_WFE_A)) {
+ pxp_get_collision_info(&fb_data->col_info);
+ queue_work(fb_data->epdc_intr_workqueue,
+ &fb_data->epdc_intr_work);
+ }
+
+ /* This call will signal wait_for_completion_timeout() in send_buffer_to_pxp */
+ complete(&fb_data->pxp_tx_cmpl);
+}
+
+static bool chan_filter(struct dma_chan *chan, void *arg)
+{
+ if (imx_dma_is_pxp(chan))
+ return true;
+ else
+ return false;
+}
+
+/* Function to request PXP DMA channel */
+static int pxp_chan_init(struct mxc_epdc_fb_data *fb_data)
+{
+ dma_cap_mask_t mask;
+ struct dma_chan *chan;
+
+ /*
+ * Request a free channel
+ */
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_PRIVATE, mask);
+ chan = dma_request_channel(mask, chan_filter, NULL);
+ if (!chan) {
+ dev_err(fb_data->dev, "Unsuccessfully received channel!!!!\n");
+ return -EBUSY;
+ }
+
+ fb_data->pxp_chan = to_pxp_channel(chan);
+ fb_data->pxp_chan->client = fb_data;
+
+ init_completion(&fb_data->pxp_tx_cmpl);
+
+ return 0;
+}
+
+static int pxp_wfe_a_process_clear_workingbuffer(struct mxc_epdc_fb_data *fb_data,
+ u32 panel_width, u32 panel_height)
+{
+ dma_cookie_t cookie;
+ struct scatterlist *sg = fb_data->sg;
+ struct dma_chan *dma_chan;
+ struct pxp_tx_desc *desc;
+ struct dma_async_tx_descriptor *txd;
+ struct pxp_config_data *pxp_conf = &fb_data->pxp_conf;
+ struct pxp_proc_data *proc_data = &fb_data->pxp_conf.proc_data;
+ int i, j = 0, ret;
+ int length;
+
+ dev_dbg(fb_data->dev, "Starting PxP WFE_A process for clearing WB.\n");
+
+ /* First, check to see that we have acquired a PxP Channel object */
+ if (fb_data->pxp_chan == NULL) {
+ /*
+ * PxP Channel has not yet been created and initialized,
+ * so let's go ahead and try
+ */
+ ret = pxp_chan_init(fb_data);
+ if (ret) {
+ /*
+ * PxP channel init failed, and we can't use the
+ * PxP until the PxP DMA driver has loaded, so we abort
+ */
+ dev_err(fb_data->dev, "PxP chan init failed\n");
+ return -ENODEV;
+ }
+ }
+
+ /*
+ * Init completion, so that we
+ * can be properly informed of the completion
+ * of the PxP task when it is done.
+ */
+ init_completion(&fb_data->pxp_tx_cmpl);
+
+ dma_chan = &fb_data->pxp_chan->dma_chan;
+
+ txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg, 2 + 4,
+ DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT,
+ NULL);
+ if (!txd) {
+ dev_err(fb_data->info.device,
+ "Error preparing a DMA transaction descriptor.\n");
+ return -EIO;
+ }
+
+ txd->callback_param = txd;
+ txd->callback = pxp_dma_done;
+
+ proc_data->working_mode = PXP_MODE_STANDARD;
+ proc_data->engine_enable = PXP_ENABLE_WFE_A;
+ proc_data->lut = 0;
+ proc_data->detection_only = 0;
+ proc_data->reagl_en = 0;
+ proc_data->partial_update = 0;
+ proc_data->alpha_en = 1;
+ proc_data->lut_sels = fb_data->luts_complete;
+ proc_data->lut_cleanup = 1;
+
+ pxp_conf->wfe_a_fetch_param[0].stride = panel_width;
+ pxp_conf->wfe_a_fetch_param[0].width = panel_width;
+ pxp_conf->wfe_a_fetch_param[0].height = panel_height;
+ pxp_conf->wfe_a_fetch_param[0].paddr = fb_data->phys_addr_black;
+ pxp_conf->wfe_a_fetch_param[1].stride = panel_width;
+ pxp_conf->wfe_a_fetch_param[1].width = panel_width;
+ pxp_conf->wfe_a_fetch_param[1].height = panel_height;
+ pxp_conf->wfe_a_fetch_param[1].paddr = fb_data->working_buffer_phys;
+ pxp_conf->wfe_a_fetch_param[0].left = 0;
+ pxp_conf->wfe_a_fetch_param[0].top = 0;
+ pxp_conf->wfe_a_fetch_param[1].left = 0;
+ pxp_conf->wfe_a_fetch_param[1].top = 0;
+
+ pxp_conf->wfe_a_store_param[0].stride = panel_width;
+ pxp_conf->wfe_a_store_param[0].width = panel_width;
+ pxp_conf->wfe_a_store_param[0].height = panel_height;
+ pxp_conf->wfe_a_store_param[0].paddr = fb_data->phys_addr_y4c;
+ pxp_conf->wfe_a_store_param[1].stride = panel_width;
+ pxp_conf->wfe_a_store_param[1].width = panel_width;
+ pxp_conf->wfe_a_store_param[1].height = panel_height;
+ pxp_conf->wfe_a_store_param[1].paddr = fb_data->working_buffer_phys;
+ pxp_conf->wfe_a_store_param[0].left = 0;
+ pxp_conf->wfe_a_store_param[0].top = 0;
+ pxp_conf->wfe_a_store_param[1].left = 0;
+ pxp_conf->wfe_a_store_param[1].top = 0;
+
+ desc = to_tx_desc(txd);
+ length = desc->len;
+
+ memcpy(&desc->proc_data, proc_data, sizeof(struct pxp_proc_data));
+ for (i = 0; i < length; i++) {
+ if (i == 0 || i == 1) {/* wfe_a won't use s0 or output at all */
+ desc = desc->next;
+
+ } else if ((pxp_conf->proc_data.engine_enable & PXP_ENABLE_WFE_A) && (j < 4)) {
+ for (j = 0; j < 4; j++) {
+ if (j == 0) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->wfe_a_fetch_param[0],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_WFE_A_FETCH0;
+ } else if (j == 1) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->wfe_a_fetch_param[1],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_WFE_A_FETCH1;
+ } else if (j == 2) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->wfe_a_store_param[0],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_WFE_A_STORE0;
+ } else if (j == 3) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->wfe_a_store_param[1],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_WFE_A_STORE1;
+ }
+
+ desc = desc->next;
+ }
+
+ i += 4;
+ }
+ }
+
+ /* Submitting our TX starts the PxP processing task */
+ cookie = txd->tx_submit(txd);
+ if (cookie < 0) {
+ dev_err(fb_data->info.device, "Error sending FB through PxP\n");
+ return -EIO;
+ }
+
+ fb_data->txd = txd;
+
+ /* trigger ePxP */
+ dma_async_issue_pending(dma_chan);
+
+ return 0;
+}
+
+static int pxp_clear_wb_work_func(struct mxc_epdc_fb_data *fb_data)
+{
+ unsigned int hist_stat;
+ int ret;
+
+ dev_dbg(fb_data->dev, "PxP WFE to clear working buffer.\n");
+
+ mutex_lock(&fb_data->pxp_mutex);
+ ret = pxp_wfe_a_process_clear_workingbuffer(fb_data, fb_data->cur_mode->vmode->xres, fb_data->cur_mode->vmode->yres);
+ if (ret) {
+ dev_err(fb_data->dev, "Unable to submit PxP update task.\n");
+ mutex_unlock(&fb_data->pxp_mutex);
+ return ret;
+ }
+ mutex_unlock(&fb_data->pxp_mutex);
+
+ /* If needed, enable EPDC HW while ePxP is processing */
+ if ((fb_data->power_state == POWER_STATE_OFF)
+ || fb_data->powering_down) {
+ epdc_powerup(fb_data);
+ }
+
+ /* This is a blocking call, so upon return PxP tx should be done */
+ ret = pxp_complete_update(fb_data, &hist_stat);
+ if (ret) {
+ dev_err(fb_data->dev, "Unable to complete PxP update task: clear wb process\n");
+ mutex_unlock(&fb_data->pxp_mutex);
+ return ret;
+ }
+
+ return 0;
+}
+
+
+/* PS_AS_OUT */
+static int pxp_legacy_process(struct mxc_epdc_fb_data *fb_data,
+ u32 src_width, u32 src_height,
+ struct mxcfb_rect *update_region)
+{
+ dma_cookie_t cookie;
+ struct scatterlist *sg = fb_data->sg;
+ struct dma_chan *dma_chan;
+ struct pxp_tx_desc *desc;
+ struct dma_async_tx_descriptor *txd;
+ struct pxp_config_data *pxp_conf = &fb_data->pxp_conf;
+ struct pxp_proc_data *proc_data = &fb_data->pxp_conf.proc_data;
+ struct fb_var_screeninfo *screeninfo = &fb_data->info.var;
+ int i, ret;
+ int length;
+
+ dev_dbg(fb_data->dev, "Starting PxP legacy process.\n");
+
+ /* First, check to see that we have acquired a PxP Channel object */
+ if (fb_data->pxp_chan == NULL) {
+ /*
+ * PxP Channel has not yet been created and initialized,
+ * so let's go ahead and try
+ */
+ ret = pxp_chan_init(fb_data);
+ if (ret) {
+ /*
+ * PxP channel init failed, and we can't use the
+ * PxP until the PxP DMA driver has loaded, so we abort
+ */
+ dev_err(fb_data->dev, "PxP chan init failed\n");
+ return -ENODEV;
+ }
+ }
+
+ /*
+ * Init completion, so that we
+ * can be properly informed of the completion
+ * of the PxP task when it is done.
+ */
+ init_completion(&fb_data->pxp_tx_cmpl);
+
+ dma_chan = &fb_data->pxp_chan->dma_chan;
+
+ txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg, 2,
+ DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT,
+ NULL);
+ if (!txd) {
+ dev_err(fb_data->info.device,
+ "Error preparing a DMA transaction descriptor.\n");
+ return -EIO;
+ }
+
+ txd->callback_param = txd;
+ txd->callback = pxp_dma_done;
+
+ proc_data->working_mode = PXP_MODE_LEGACY;
+ proc_data->engine_enable = PXP_ENABLE_PS_AS_OUT;
+
+ /*
+ * Configure PxP for processing of new update region
+ * The rest of our config params were set up in
+ * probe() and should not need to be changed.
+ */
+ pxp_conf->s0_param.width = src_width;
+ pxp_conf->s0_param.stride = (screeninfo->bits_per_pixel * src_width) >> 3;
+ pxp_conf->s0_param.height = src_height;
+ proc_data->srect.top = update_region->top;
+ proc_data->srect.left = update_region->left;
+ proc_data->srect.width = update_region->width;
+ proc_data->srect.height = update_region->height;
+ proc_data->lut_cleanup = 0;
+
+ /*
+ * Because only YUV/YCbCr image can be scaled, configure
+ * drect equivalent to srect, as such do not perform scaling.
+ */
+ proc_data->drect.top = 0;
+ proc_data->drect.left = 0;
+
+ /* PXP expects rotation in terms of degrees */
+ proc_data->rotate = fb_data->epdc_fb_var.rotate * 90;
+ if (proc_data->rotate > 270)
+ proc_data->rotate = 0;
+
+ /* we should pass the rotated values to PXP */
+ if ((proc_data->rotate == 90) || (proc_data->rotate == 270)) {
+ proc_data->drect.width = proc_data->srect.height;
+ proc_data->drect.height = proc_data->srect.width;
+ pxp_conf->out_param.width = update_region->height;
+ pxp_conf->out_param.height = update_region->width;
+ pxp_conf->out_param.stride = update_region->height;
+ } else {
+ proc_data->drect.width = proc_data->srect.width;
+ proc_data->drect.height = proc_data->srect.height;
+ pxp_conf->out_param.width = update_region->width;
+ pxp_conf->out_param.height = update_region->height;
+ pxp_conf->out_param.stride = update_region->width;
+ }
+
+ /* For EPDC v2.0, we need output to be 64-bit
+ * aligned since EPDC stride does not work. */
+ if (fb_data->rev <= 20)
+ pxp_conf->out_param.stride = ALIGN(pxp_conf->out_param.stride, 8);
+
+ desc = to_tx_desc(txd);
+ length = desc->len;
+
+ for (i = 0; i < length; i++) {
+ if (i == 0) {/* S0 */
+ memcpy(&desc->proc_data, proc_data, sizeof(struct pxp_proc_data));
+ pxp_conf->s0_param.paddr = sg_dma_address(&sg[0]);
+ memcpy(&desc->layer_param.s0_param, &pxp_conf->s0_param,
+ sizeof(struct pxp_layer_param));
+ desc = desc->next;
+
+ } else if (i == 1) {
+ pxp_conf->out_param.paddr = sg_dma_address(&sg[1]);
+ memcpy(&desc->layer_param.out_param, &pxp_conf->out_param,
+ sizeof(struct pxp_layer_param));
+ desc = desc->next;
+ }
+ }
+
+ /* Submitting our TX starts the PxP processing task */
+ cookie = txd->tx_submit(txd);
+ if (cookie < 0) {
+ dev_err(fb_data->info.device, "Error sending FB through PxP\n");
+ return -EIO;
+ }
+
+ fb_data->txd = txd;
+
+ /* trigger ePxP */
+ dma_async_issue_pending(dma_chan);
+
+ return 0;
+}
+
+static int pxp_process_dithering(struct mxc_epdc_fb_data *fb_data,
+ struct mxcfb_rect *update_region)
+{
+ dma_cookie_t cookie;
+ struct scatterlist *sg = fb_data->sg;
+ struct dma_chan *dma_chan;
+ struct pxp_tx_desc *desc;
+ struct dma_async_tx_descriptor *txd;
+ struct pxp_config_data *pxp_conf = &fb_data->pxp_conf;
+ struct pxp_proc_data *proc_data = &fb_data->pxp_conf.proc_data;
+ int i, j = 0, ret;
+ int length;
+
+ dev_dbg(fb_data->dev, "Starting PxP Dithering process.\n");
+
+ /* First, check to see that we have acquired a PxP Channel object */
+ if (fb_data->pxp_chan == NULL) {
+ /*
+ * PxP Channel has not yet been created and initialized,
+ * so let's go ahead and try
+ */
+ ret = pxp_chan_init(fb_data);
+ if (ret) {
+ /*
+ * PxP channel init failed, and we can't use the
+ * PxP until the PxP DMA driver has loaded, so we abort
+ */
+ dev_err(fb_data->dev, "PxP chan init failed\n");
+ return -ENODEV;
+ }
+ }
+
+ /*
+ * Init completion, so that we
+ * can be properly informed of the completion
+ * of the PxP task when it is done.
+ */
+ init_completion(&fb_data->pxp_tx_cmpl);
+
+ dma_chan = &fb_data->pxp_chan->dma_chan;
+
+ txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg, 2 + 4,
+ DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT,
+ NULL);
+ if (!txd) {
+ dev_err(fb_data->info.device,
+ "Error preparing a DMA transaction descriptor.\n");
+ return -EIO;
+ }
+
+ txd->callback_param = txd;
+ txd->callback = pxp_dma_done;
+
+ proc_data->working_mode = PXP_MODE_STANDARD;
+ proc_data->engine_enable = PXP_ENABLE_DITHER;
+
+ pxp_conf->dither_fetch_param[0].stride = update_region->width;
+ pxp_conf->dither_fetch_param[0].width = update_region->width;
+ pxp_conf->dither_fetch_param[0].height = update_region->height;
+#ifdef USE_PS_AS_OUTPUT
+ pxp_conf->dither_fetch_param[0].paddr = sg_dma_address(&sg[1]);
+#else
+ pxp_conf->dither_fetch_param[0].paddr = sg_dma_address(&sg[0]);
+#endif
+ pxp_conf->dither_fetch_param[1].stride = update_region->width;
+ pxp_conf->dither_fetch_param[1].width = update_region->width;
+ pxp_conf->dither_fetch_param[1].height = update_region->height;
+ pxp_conf->dither_fetch_param[1].paddr = pxp_conf->dither_fetch_param[0].paddr;
+
+ pxp_conf->dither_store_param[0].stride = update_region->width;
+ pxp_conf->dither_store_param[0].width = update_region->width;
+ pxp_conf->dither_store_param[0].height = update_region->height;
+ pxp_conf->dither_store_param[0].paddr = fb_data->phys_addr_y4;
+ pxp_conf->dither_store_param[1].stride = update_region->width;
+ pxp_conf->dither_store_param[1].width = update_region->width;
+ pxp_conf->dither_store_param[1].height = update_region->height;
+ pxp_conf->dither_store_param[1].paddr = pxp_conf->dither_store_param[0].paddr;
+
+ desc = to_tx_desc(txd);
+ length = desc->len;
+
+ for (i = 0; i < length; i++) {
+ if (i == 0) {/* S0 */
+ memcpy(&desc->proc_data, proc_data, sizeof(struct pxp_proc_data));
+ pxp_conf->s0_param.paddr = sg_dma_address(&sg[0]);
+ memcpy(&desc->layer_param.s0_param, &pxp_conf->s0_param,
+ sizeof(struct pxp_layer_param));
+ desc = desc->next;
+ } else if (i == 1) {
+ pxp_conf->out_param.paddr = sg_dma_address(&sg[1]);
+ memcpy(&desc->layer_param.out_param, &pxp_conf->out_param,
+ sizeof(struct pxp_layer_param));
+ desc = desc->next;
+ } else if ((pxp_conf->proc_data.engine_enable & PXP_ENABLE_DITHER) && (j < 4)) {
+ for (j = 0; j < 4; j++) {
+ if (j == 0) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->dither_fetch_param[0],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_DITHER_FETCH0;
+ } else if (j == 1) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->dither_fetch_param[1],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_DITHER_FETCH1;
+ } else if (j == 2) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->dither_store_param[0],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_DITHER_STORE0;
+ } else if (j == 3) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->dither_store_param[1],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_DITHER_STORE1;
+ }
+
+ desc = desc->next;
+ }
+
+ i += 4;
+ }
+ }
+
+ /* Submitting our TX starts the PxP processing task */
+ cookie = txd->tx_submit(txd);
+ if (cookie < 0) {
+ dev_err(fb_data->info.device, "Error sending FB through PxP\n");
+ return -EIO;
+ }
+
+ fb_data->txd = txd;
+
+ /* trigger ePxP */
+ dma_async_issue_pending(dma_chan);
+
+ return 0;
+}
+
+/*
+ * Function to call PxP DMA driver and send our latest FB update region
+ * through the PxP and out to an intermediate buffer.
+ * Note: This is a blocking call, so upon return the PxP tx should be complete.
+ */
+static int pxp_wfe_a_process(struct mxc_epdc_fb_data *fb_data,
+ struct mxcfb_rect *update_region,
+ struct update_data_list *upd_data_list)
+{
+ dma_cookie_t cookie;
+ struct scatterlist *sg = fb_data->sg;
+ struct dma_chan *dma_chan;
+ struct pxp_tx_desc *desc;
+ struct dma_async_tx_descriptor *txd;
+ struct pxp_config_data *pxp_conf = &fb_data->pxp_conf;
+ struct pxp_proc_data *proc_data = &fb_data->pxp_conf.proc_data;
+ u32 wv_mode = upd_data_list->update_desc->upd_data.waveform_mode;
+ int i, j = 0, ret;
+ int length;
+ bool is_transform;
+
+ dev_dbg(fb_data->dev, "Starting PxP WFE_A process.\n");
+
+ /* First, check to see that we have acquired a PxP Channel object */
+ if (fb_data->pxp_chan == NULL) {
+ /*
+ * PxP Channel has not yet been created and initialized,
+ * so let's go ahead and try
+ */
+ ret = pxp_chan_init(fb_data);
+ if (ret) {
+ /*
+ * PxP channel init failed, and we can't use the
+ * PxP until the PxP DMA driver has loaded, so we abort
+ */
+ dev_err(fb_data->dev, "PxP chan init failed\n");
+ return -ENODEV;
+ }
+ }
+
+ /*
+ * Init completion, so that we
+ * can be properly informed of the completion
+ * of the PxP task when it is done.
+ */
+ init_completion(&fb_data->pxp_tx_cmpl);
+
+ dma_chan = &fb_data->pxp_chan->dma_chan;
+
+ txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg, 2 + 4,
+ DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT,
+ NULL);
+ if (!txd) {
+ dev_err(fb_data->info.device,
+ "Error preparing a DMA transaction descriptor.\n");
+ return -EIO;
+ }
+
+ txd->callback_param = txd;
+ txd->callback = pxp_dma_done;
+
+ proc_data->working_mode = PXP_MODE_STANDARD;
+ proc_data->engine_enable = PXP_ENABLE_WFE_A;
+ proc_data->lut = upd_data_list->lut_num;
+ proc_data->alpha_en = 0;
+ proc_data->lut_sels = fb_data->luts_complete;
+ proc_data->lut_status_1 = __raw_readl(EPDC_STATUS_LUTS);
+ proc_data->lut_status_2 = __raw_readl(EPDC_STATUS_LUTS2);
+ proc_data->lut_cleanup = 0;
+
+ if (upd_data_list->update_desc->upd_data.flags & EPDC_FLAG_TEST_COLLISION) {
+ proc_data->detection_only = 1;
+ dev_dbg(fb_data->info.device,
+ "collision test_only send to pxp\n");
+ } else
+ proc_data->detection_only = 0;
+
+ if (wv_mode == WAVEFORM_MODE_GLR16
+ || wv_mode == WAVEFORM_MODE_GLD16)
+ proc_data->reagl_en = 1;
+
+ if (upd_data_list->update_desc->upd_data.update_mode == UPDATE_MODE_PARTIAL)
+ proc_data->partial_update = 1;
+ else
+ proc_data->partial_update = 0;
+
+ /* fetch0 is upd buffer */
+ pxp_conf->wfe_a_fetch_param[0].stride = upd_data_list->update_desc->epdc_stride;
+ pxp_conf->wfe_a_fetch_param[0].width = update_region->width;
+ pxp_conf->wfe_a_fetch_param[0].height = update_region->height;
+ /* upd buffer left and top should be always 0 */
+ pxp_conf->wfe_a_fetch_param[0].left = 0;
+ pxp_conf->wfe_a_fetch_param[0].top = 0;
+ if (proc_data->dither_mode) {
+ pxp_conf->wfe_a_fetch_param[0].paddr = fb_data->phys_addr_y4;
+ } else {
+ is_transform = ((upd_data_list->update_desc->upd_data.flags &
+ (EPDC_FLAG_ENABLE_INVERSION | EPDC_FLAG_USE_DITHERING_Y1 |
+ EPDC_FLAG_USE_DITHERING_Y4 | EPDC_FLAG_FORCE_MONOCHROME |
+ EPDC_FLAG_USE_CMAP)) && (proc_data->scaling == 0) &&
+ (proc_data->hflip == 0) && (proc_data->vflip == 0)) ?
+ true : false;
+
+ if ((fb_data->epdc_fb_var.rotate == FB_ROTATE_UR) &&
+ (fb_data->epdc_fb_var.grayscale == GRAYSCALE_8BIT) &&
+ !is_transform && (proc_data->dither_mode == 0) &&
+ !(upd_data_list->update_desc->upd_data.flags &
+ EPDC_FLAG_USE_ALT_BUFFER) &&
+ !fb_data->restrict_width) {
+ sg_dma_address(&sg[0]) = fb_data->info.fix.smem_start;
+ sg_set_page(&sg[0],
+ virt_to_page(fb_data->info.screen_base),
+ fb_data->info.fix.smem_len,
+ offset_in_page(fb_data->info.screen_base));
+ pxp_conf->wfe_a_fetch_param[0].paddr =
+ sg_dma_address(&sg[0]);
+
+ pxp_conf->wfe_a_fetch_param[0].left = update_region->left;
+ pxp_conf->wfe_a_fetch_param[0].top = update_region->top;
+ } else
+ pxp_conf->wfe_a_fetch_param[0].paddr =
+ upd_data_list->phys_addr + upd_data_list->update_desc->epdc_offs;
+ }
+
+ /* fetch1 is working buffer */
+ pxp_conf->wfe_a_fetch_param[1].stride = fb_data->cur_mode->vmode->xres;
+ pxp_conf->wfe_a_fetch_param[1].width = update_region->width;
+ pxp_conf->wfe_a_fetch_param[1].height = update_region->height;
+ pxp_conf->wfe_a_fetch_param[1].paddr = fb_data->working_buffer_phys;
+ pxp_conf->wfe_a_fetch_param[1].left = update_region->left;
+ pxp_conf->wfe_a_fetch_param[1].top = update_region->top;
+
+ /* store0 is y4c buffer */
+ pxp_conf->wfe_a_store_param[0].stride = fb_data->cur_mode->vmode->xres;
+ pxp_conf->wfe_a_store_param[0].width = update_region->width;
+ pxp_conf->wfe_a_store_param[0].height = update_region->height;
+ pxp_conf->wfe_a_store_param[0].paddr = fb_data->phys_addr_y4c;
+
+ /* store1 is (temp) working buffer */
+ pxp_conf->wfe_a_store_param[1].stride = fb_data->cur_mode->vmode->xres;
+ pxp_conf->wfe_a_store_param[1].width = update_region->width;
+ pxp_conf->wfe_a_store_param[1].height = update_region->height;
+ if (wv_mode == WAVEFORM_MODE_GLR16
+ || wv_mode == WAVEFORM_MODE_GLD16)
+ pxp_conf->wfe_a_store_param[1].paddr = fb_data->tmp_working_buffer_phys;
+ else
+ pxp_conf->wfe_a_store_param[1].paddr = fb_data->working_buffer_phys;
+ pxp_conf->wfe_a_store_param[1].left = update_region->left;
+ pxp_conf->wfe_a_store_param[1].top = update_region->top;
+
+ desc = to_tx_desc(txd);
+ length = desc->len;
+
+ memcpy(&desc->proc_data, proc_data, sizeof(struct pxp_proc_data));
+ for (i = 0; i < length; i++) {
+ if (i == 0 || i == 1) {/* wfe_a won't use s0 or output at all */
+ desc = desc->next;
+ } else if ((pxp_conf->proc_data.engine_enable & PXP_ENABLE_WFE_A) && (j < 4)) {
+ for (j = 0; j < 4; j++) {
+ if (j == 0) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->wfe_a_fetch_param[0],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_WFE_A_FETCH0;
+ } else if (j == 1) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->wfe_a_fetch_param[1],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_WFE_A_FETCH1;
+ } else if (j == 2) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->wfe_a_store_param[0],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_WFE_A_STORE0;
+ } else if (j == 3) {
+ memcpy(&desc->layer_param.processing_param,
+ &pxp_conf->wfe_a_store_param[1],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.flag = PXP_BUF_FLAG_WFE_A_STORE1;
+ }
+
+ desc = desc->next;
+ }
+
+ i += 4;
+ }
+ }
+
+ /* Submitting our TX starts the PxP processing task */
+ cookie = txd->tx_submit(txd);
+ if (cookie < 0) {
+ dev_err(fb_data->info.device, "Error sending FB through PxP\n");
+ return -EIO;
+ }
+
+ fb_data->txd = txd;
+
+ /* trigger ePxP */
+ dma_async_issue_pending(dma_chan);
+
+ return 0;
+}
+
+/* For REAGL/-D processing */
+static int pxp_wfe_b_process_update(struct mxc_epdc_fb_data *fb_data,
+ struct mxcfb_rect *update_region)
+{
+ dma_cookie_t cookie;
+ struct scatterlist *sg = fb_data->sg;
+ struct dma_chan *dma_chan;
+ struct pxp_tx_desc *desc;
+ struct dma_async_tx_descriptor *txd;
+ struct pxp_config_data *pxp_conf = &fb_data->pxp_conf;
+ struct pxp_proc_data *proc_data = &fb_data->pxp_conf.proc_data;
+ int i, j = 0, ret;
+ int length;
+
+ dev_dbg(fb_data->dev, "Starting PxP WFE_B process.\n");
+
+ /* First, check to see that we have acquired a PxP Channel object */
+ if (fb_data->pxp_chan == NULL) {
+ /*
+ * PxP Channel has not yet been created and initialized,
+ * so let's go ahead and try
+ */
+ ret = pxp_chan_init(fb_data);
+ if (ret) {
+ /*
+ * PxP channel init failed, and we can't use the
+ * PxP until the PxP DMA driver has loaded, so we abort
+ */
+ dev_err(fb_data->dev, "PxP chan init failed\n");
+ return -ENODEV;
+ }
+ }
+
+ /*
+ * Init completion, so that we
+ * can be properly informed of the completion
+ * of the PxP task when it is done.
+ */
+ init_completion(&fb_data->pxp_tx_cmpl);
+
+ dma_chan = &fb_data->pxp_chan->dma_chan;
+
+ txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg, 2 + 4,
+ DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT,
+ NULL);
+ if (!txd) {
+ dev_err(fb_data->info.device,
+ "Error preparing a DMA transaction descriptor.\n");
+ return -EIO;
+ }
+
+ txd->callback_param = txd;
+ txd->callback = pxp_dma_done;
+
+ proc_data->working_mode = PXP_MODE_STANDARD;
+ proc_data->engine_enable = PXP_ENABLE_WFE_B;
+ proc_data->lut_update = false;
+ proc_data->lut_cleanup = 0;
+
+ pxp_conf->wfe_b_fetch_param[0].stride = fb_data->cur_mode->vmode->xres;
+ pxp_conf->wfe_b_fetch_param[0].width = fb_data->cur_mode->vmode->xres;
+ pxp_conf->wfe_b_fetch_param[0].height = fb_data->cur_mode->vmode->yres;
+ pxp_conf->wfe_b_fetch_param[0].paddr = fb_data->phys_addr_black;
+ pxp_conf->wfe_b_fetch_param[1].stride = fb_data->cur_mode->vmode->xres;
+ pxp_conf->wfe_b_fetch_param[1].width = update_region->width;
+ pxp_conf->wfe_b_fetch_param[1].height = update_region->height;
+ pxp_conf->wfe_b_fetch_param[1].top = update_region->top;
+ pxp_conf->wfe_b_fetch_param[1].left = update_region->left;
+ pxp_conf->wfe_b_fetch_param[1].paddr = fb_data->tmp_working_buffer_phys;
+
+ pxp_conf->wfe_b_store_param[0].stride = fb_data->cur_mode->vmode->xres;
+ pxp_conf->wfe_b_store_param[0].width = update_region->width;
+ pxp_conf->wfe_b_store_param[0].height = update_region->height;
+ pxp_conf->wfe_b_store_param[0].top = update_region->top;
+ pxp_conf->wfe_b_store_param[0].left = update_region->left;
+ pxp_conf->wfe_b_store_param[0].paddr = fb_data->working_buffer_phys;
+ pxp_conf->wfe_b_store_param[1].stride = fb_data->cur_mode->vmode->xres;
+ pxp_conf->wfe_b_store_param[1].width = update_region->width;
+ pxp_conf->wfe_b_store_param[1].height = update_region->height;
+ pxp_conf->wfe_b_store_param[1].paddr = 0;
+
+ desc = to_tx_desc(txd);
+ length = desc->len;
+
+ for (i = 0; i < length; i++) {
+ if (i == 0) { /* S0 */
+ memcpy(&desc->proc_data, proc_data,
+ sizeof(struct pxp_proc_data));
+ pxp_conf->s0_param.paddr = sg_dma_address(&sg[0]);
+ memcpy(&desc->layer_param.s0_param, &pxp_conf->s0_param,
+ sizeof(struct pxp_layer_param));
+ desc = desc->next;
+ } else if (i == 1) {
+ pxp_conf->out_param.paddr = sg_dma_address(&sg[1]);
+ memcpy(&desc->layer_param.out_param,
+ &pxp_conf->out_param,
+ sizeof(struct pxp_layer_param));
+ desc = desc->next;
+ } else
+ if ((pxp_conf->proc_data.engine_enable & PXP_ENABLE_WFE_B)
+ && (j < 4)) {
+ for (j = 0; j < 4; j++) {
+ if (j == 0) {
+ memcpy(&desc->layer_param.
+ processing_param,
+ &pxp_conf->wfe_b_fetch_param[0],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.
+ flag = PXP_BUF_FLAG_WFE_B_FETCH0;
+ } else if (j == 1) {
+ memcpy(&desc->layer_param.
+ processing_param,
+ &pxp_conf->wfe_b_fetch_param[1],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.
+ flag = PXP_BUF_FLAG_WFE_B_FETCH1;
+ } else if (j == 2) {
+ memcpy(&desc->layer_param.
+ processing_param,
+ &pxp_conf->wfe_b_store_param[0],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.
+ flag = PXP_BUF_FLAG_WFE_B_STORE0;
+ } else if (j == 3) {
+ memcpy(&desc->layer_param.
+ processing_param,
+ &pxp_conf->wfe_b_store_param[1],
+ sizeof(struct pxp_layer_param));
+ desc->layer_param.processing_param.
+ flag = PXP_BUF_FLAG_WFE_B_STORE1;
+ }
+
+ desc = desc->next;
+ }
+
+ i += 4;
+ }
+ }
+
+ /* Submitting our TX starts the PxP processing task */
+ cookie = txd->tx_submit(txd);
+ if (cookie < 0) {
+ dev_err(fb_data->info.device, "Error sending FB through PxP\n");
+ return -EIO;
+ }
+
+ fb_data->txd = txd;
+
+ /* trigger ePxP */
+ dma_async_issue_pending(dma_chan);
+
+ return 0;
+}
+
+static int pxp_complete_update(struct mxc_epdc_fb_data *fb_data, u32 *hist_stat)
+{
+ int ret;
+ /*
+ * Wait for completion event, which will be set
+ * through our TX callback function.
+ */
+ ret = wait_for_completion_timeout(&fb_data->pxp_tx_cmpl, HZ * 2);
+ if (ret <= 0) {
+ dev_info(fb_data->info.device,
+ "PxP operation failed due to %s\n",
+ ret < 0 ? "user interrupt" : "timeout");
+ dma_release_channel(&fb_data->pxp_chan->dma_chan);
+ fb_data->pxp_chan = NULL;
+ return ret ? : -ETIMEDOUT;
+ }
+
+ if ((fb_data->pxp_conf.proc_data.lut_transform & EPDC_FLAG_USE_CMAP) &&
+ fb_data->pxp_conf.proc_data.lut_map_updated)
+ fb_data->pxp_conf.proc_data.lut_map_updated = false;
+
+ *hist_stat = to_tx_desc(fb_data->txd)->hist_status;
+ dma_release_channel(&fb_data->pxp_chan->dma_chan);
+ fb_data->pxp_chan = NULL;
+
+ dev_dbg(fb_data->dev, "TX completed\n");
+
+ return 0;
+}
+
+/*
+ * Different dithering algorithm can be used. We chose
+ * to implement Bill Atkinson's algorithm as an example
+ * Thanks Bill Atkinson for his dithering algorithm.
+ */
+
+/*
+ * Dithering algorithm implementation - Y8->Y1 version 1.0 for i.MX
+ */
+static void do_dithering_processing_Y1_v1_0(
+ unsigned char *update_region_virt_ptr,
+ dma_addr_t update_region_phys_ptr,
+ struct mxcfb_rect *update_region,
+ unsigned long update_region_stride,
+ int *err_dist)
+{
+
+ /* create a temp error distribution array */
+ int bwPix;
+ int y;
+ int col;
+ int *err_dist_l0, *err_dist_l1, *err_dist_l2, distrib_error;
+ int width_3 = update_region->width + 3;
+ char *y8buf;
+ int x_offset = 0;
+
+ /* prime a few elements the error distribution array */
+ for (y = 0; y < update_region->height; y++) {
+ /* Dithering the Y8 in sbuf to BW suitable for A2 waveform */
+ err_dist_l0 = err_dist + (width_3) * (y % 3);
+ err_dist_l1 = err_dist + (width_3) * ((y + 1) % 3);
+ err_dist_l2 = err_dist + (width_3) * ((y + 2) % 3);
+
+ y8buf = update_region_virt_ptr + x_offset;
+
+ /* scan the line and convert the Y8 to BW */
+ for (col = 1; col <= update_region->width; col++) {
+ bwPix = *(err_dist_l0 + col) + *y8buf;
+
+ if (bwPix >= 128) {
+ *y8buf++ = 0xff;
+ distrib_error = (bwPix - 255) >> 3;
+ } else {
+ *y8buf++ = 0;
+ distrib_error = bwPix >> 3;
+ }
+
+ /* modify the error distribution buffer */
+ *(err_dist_l0 + col + 2) += distrib_error;
+ *(err_dist_l1 + col + 1) += distrib_error;
+ *(err_dist_l0 + col + 1) += distrib_error;
+ *(err_dist_l1 + col - 1) += distrib_error;
+ *(err_dist_l1 + col) += distrib_error;
+ *(err_dist_l2 + col) = distrib_error;
+ }
+ x_offset += update_region_stride;
+ }
+
+ flush_cache_all();
+ outer_flush_range(update_region_phys_ptr, update_region_phys_ptr +
+ update_region->height * update_region->width);
+}
+
+/*
+ * Dithering algorithm implementation - Y8->Y4 version 1.0 for i.MX
+ */
+
+static void do_dithering_processing_Y4_v1_0(
+ unsigned char *update_region_virt_ptr,
+ dma_addr_t update_region_phys_ptr,
+ struct mxcfb_rect *update_region,
+ unsigned long update_region_stride,
+ int *err_dist)
+{
+
+ /* create a temp error distribution array */
+ int gcPix;
+ int y;
+ int col;
+ int *err_dist_l0, *err_dist_l1, *err_dist_l2, distrib_error;
+ int width_3 = update_region->width + 3;
+ char *y8buf;
+ int x_offset = 0;
+
+ /* prime a few elements the error distribution array */
+ for (y = 0; y < update_region->height; y++) {
+ /* Dithering the Y8 in sbuf to Y4 */
+ err_dist_l0 = err_dist + (width_3) * (y % 3);
+ err_dist_l1 = err_dist + (width_3) * ((y + 1) % 3);
+ err_dist_l2 = err_dist + (width_3) * ((y + 2) % 3);
+
+ y8buf = update_region_virt_ptr + x_offset;
+
+ /* scan the line and convert the Y8 to Y4 */
+ for (col = 1; col <= update_region->width; col++) {
+ gcPix = *(err_dist_l0 + col) + *y8buf;
+
+ if (gcPix > 255)
+ gcPix = 255;
+ else if (gcPix < 0)
+ gcPix = 0;
+
+ distrib_error = (*y8buf - (gcPix & 0xf0)) >> 3;
+
+ *y8buf++ = gcPix & 0xf0;
+
+ /* modify the error distribution buffer */
+ *(err_dist_l0 + col + 2) += distrib_error;
+ *(err_dist_l1 + col + 1) += distrib_error;
+ *(err_dist_l0 + col + 1) += distrib_error;
+ *(err_dist_l1 + col - 1) += distrib_error;
+ *(err_dist_l1 + col) += distrib_error;
+ *(err_dist_l2 + col) = distrib_error;
+ }
+ x_offset += update_region_stride;
+ }
+
+ flush_cache_all();
+ outer_flush_range(update_region_phys_ptr, update_region_phys_ptr +
+ update_region->height * update_region->width);
+}
+
+static int __init mxc_epdc_fb_init(void)
+{
+ return platform_driver_register(&mxc_epdc_fb_driver);
+}
+late_initcall(mxc_epdc_fb_init);
+
+static void __exit mxc_epdc_fb_exit(void)
+{
+ platform_driver_unregister(&mxc_epdc_fb_driver);
+}
+module_exit(mxc_epdc_fb_exit);
+
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC EPDC V2 framebuffer driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("fb");
diff --git a/drivers/video/fbdev/mxc/mxc_hdmi.c b/drivers/video/fbdev/mxc/mxc_hdmi.c
new file mode 100644
index 000000000000..9e844805c0d2
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mxc_hdmi.c
@@ -0,0 +1,2980 @@
+/*
+ * Copyright (C) 2011-2016 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+/*
+ * SH-Mobile High-Definition Multimedia Interface (HDMI) driver
+ * for SLISHDMI13T and SLIPHDMIT IP cores
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/uaccess.h>
+#include <linux/cpufreq.h>
+#include <linux/firmware.h>
+#include <linux/kthread.h>
+#include <linux/regulator/driver.h>
+#include <linux/fsl_devices.h>
+#include <linux/ipu.h>
+#include <linux/regmap.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/of_device.h>
+
+#include <linux/console.h>
+#include <linux/types.h>
+
+#include "../edid.h"
+#include <video/mxc_edid.h>
+#include <video/mxc_hdmi.h>
+#include "mxc_dispdrv.h"
+
+#include <linux/mfd/mxc-hdmi-core.h>
+
+#define DISPDRV_HDMI "hdmi"
+#define HDMI_EDID_LEN 512
+
+/* status codes for reading edid */
+#define HDMI_EDID_SUCCESS 0
+#define HDMI_EDID_FAIL -1
+#define HDMI_EDID_SAME -2
+#define HDMI_EDID_NO_MODES -3
+
+#define NUM_CEA_VIDEO_MODES 64
+#define DEFAULT_VIDEO_MODE 16 /* 1080P */
+
+#define RGB 0
+#define YCBCR444 1
+#define YCBCR422_16BITS 2
+#define YCBCR422_8BITS 3
+#define XVYCC444 4
+
+/*
+ * We follow a flowchart which is in the "Synopsys DesignWare Courses
+ * HDMI Transmitter Controller User Guide, 1.30a", section 3.1
+ * (dwc_hdmi_tx_user.pdf)
+ *
+ * Below are notes that say "HDMI Initialization Step X"
+ * These correspond to the flowchart.
+ */
+
+/*
+ * We are required to configure VGA mode before reading edid
+ * in HDMI Initialization Step B
+ */
+static const struct fb_videomode vga_mode = {
+ /* 640x480 @ 60 Hz, 31.5 kHz hsync */
+ NULL, 60, 640, 480, 39721, 48, 16, 33, 10, 96, 2, 0,
+ FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, FB_MODE_IS_VESA,
+};
+
+enum hdmi_datamap {
+ RGB444_8B = 0x01,
+ RGB444_10B = 0x03,
+ RGB444_12B = 0x05,
+ RGB444_16B = 0x07,
+ YCbCr444_8B = 0x09,
+ YCbCr444_10B = 0x0B,
+ YCbCr444_12B = 0x0D,
+ YCbCr444_16B = 0x0F,
+ YCbCr422_8B = 0x16,
+ YCbCr422_10B = 0x14,
+ YCbCr422_12B = 0x12,
+};
+
+enum hdmi_colorimetry {
+ eITU601,
+ eITU709,
+};
+
+struct hdmi_vmode {
+ bool mDVI;
+ bool mHSyncPolarity;
+ bool mVSyncPolarity;
+ bool mInterlaced;
+ bool mDataEnablePolarity;
+
+ unsigned int mPixelClock;
+ unsigned int mPixelRepetitionInput;
+ unsigned int mPixelRepetitionOutput;
+};
+
+struct hdmi_data_info {
+ unsigned int enc_in_format;
+ unsigned int enc_out_format;
+ unsigned int enc_color_depth;
+ unsigned int colorimetry;
+ unsigned int pix_repet_factor;
+ unsigned int hdcp_enable;
+ unsigned int rgb_out_enable;
+ struct hdmi_vmode video_mode;
+};
+
+struct hdmi_phy_reg_config {
+ /* HDMI PHY register config for pass HCT */
+ u16 reg_vlev;
+ u16 reg_cksymtx;
+};
+
+struct mxc_hdmi {
+ struct platform_device *pdev;
+ struct platform_device *core_pdev;
+ struct mxc_dispdrv_handle *disp_mxc_hdmi;
+ struct fb_info *fbi;
+ struct clk *hdmi_isfr_clk;
+ struct clk *hdmi_iahb_clk;
+ struct clk *mipi_core_clk;
+ struct delayed_work hotplug_work;
+ struct delayed_work hdcp_hdp_work;
+
+ struct notifier_block nb;
+
+ struct hdmi_data_info hdmi_data;
+ int vic;
+ struct mxc_edid_cfg edid_cfg;
+ u8 edid[HDMI_EDID_LEN];
+ bool fb_reg;
+ bool cable_plugin;
+ u8 blank;
+ bool dft_mode_set;
+ char *dft_mode_str;
+ int default_bpp;
+ u8 latest_intr_stat;
+ bool irq_enabled;
+ spinlock_t irq_lock;
+ bool phy_enabled;
+ struct fb_videomode default_mode;
+ struct fb_videomode previous_non_vga_mode;
+ bool requesting_vga_for_initialization;
+
+ int *gpr_base;
+ int *gpr_hdmi_base;
+ int *gpr_sdma_base;
+ int cpu_type;
+ int cpu_version;
+ struct hdmi_phy_reg_config phy_config;
+
+ struct pinctrl *pinctrl;
+};
+
+static int hdmi_major;
+static struct class *hdmi_class;
+
+struct i2c_client *hdmi_i2c;
+struct mxc_hdmi *g_hdmi;
+
+static bool hdmi_inited;
+static bool hdcp_init;
+static struct regulator *hdmi_regulator;
+
+extern const struct fb_videomode mxc_cea_mode[64];
+extern void mxc_hdmi_cec_handle(u16 cec_stat);
+
+static void mxc_hdmi_setup(struct mxc_hdmi *hdmi, unsigned long event);
+static void hdmi_enable_overflow_interrupts(void);
+static void hdmi_disable_overflow_interrupts(void);
+
+static struct platform_device_id imx_hdmi_devtype[] = {
+ {
+ .name = "hdmi-imx6DL",
+ .driver_data = IMX6DL_HDMI,
+ }, {
+ .name = "hdmi-imx6Q",
+ .driver_data = IMX6Q_HDMI,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype);
+
+static const struct of_device_id imx_hdmi_dt_ids[] = {
+ { .compatible = "fsl,imx6dl-hdmi-video", .data = &imx_hdmi_devtype[IMX6DL_HDMI], },
+ { .compatible = "fsl,imx6q-hdmi-video", .data = &imx_hdmi_devtype[IMX6Q_HDMI], },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
+
+static inline int cpu_is_imx6dl(struct mxc_hdmi *hdmi)
+{
+ return hdmi->cpu_type == IMX6DL_HDMI;
+}
+#ifdef DEBUG
+static void dump_fb_videomode(const struct fb_videomode *m)
+{
+ pr_debug("fb_videomode = %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ m->refresh, m->xres, m->yres, m->pixclock, m->left_margin,
+ m->right_margin, m->upper_margin, m->lower_margin,
+ m->hsync_len, m->vsync_len, m->sync, m->vmode, m->flag);
+}
+#else
+static void dump_fb_videomode(const struct fb_videomode *m)
+{}
+#endif
+
+static ssize_t mxc_hdmi_show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxc_hdmi *hdmi = dev_get_drvdata(dev);
+
+ strcpy(buf, hdmi->fbi->fix.id);
+ sprintf(buf+strlen(buf), "\n");
+
+ return strlen(buf);
+}
+
+static DEVICE_ATTR(fb_name, S_IRUGO, mxc_hdmi_show_name, NULL);
+
+static ssize_t mxc_hdmi_show_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxc_hdmi *hdmi = dev_get_drvdata(dev);
+
+ if (hdmi->cable_plugin == false)
+ strcpy(buf, "plugout\n");
+ else
+ strcpy(buf, "plugin\n");
+
+ return strlen(buf);
+}
+
+static DEVICE_ATTR(cable_state, S_IRUGO, mxc_hdmi_show_state, NULL);
+
+static ssize_t mxc_hdmi_show_edid(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxc_hdmi *hdmi = dev_get_drvdata(dev);
+ int i, j, len = 0;
+
+ for (j = 0; j < HDMI_EDID_LEN/16; j++) {
+ for (i = 0; i < 16; i++)
+ len += sprintf(buf+len, "0x%02X ",
+ hdmi->edid[j*16 + i]);
+ len += sprintf(buf+len, "\n");
+ }
+
+ return len;
+}
+
+static DEVICE_ATTR(edid, S_IRUGO, mxc_hdmi_show_edid, NULL);
+
+static ssize_t mxc_hdmi_show_rgb_out_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxc_hdmi *hdmi = dev_get_drvdata(dev);
+
+ if (hdmi->hdmi_data.rgb_out_enable == true)
+ strcpy(buf, "RGB out\n");
+ else
+ strcpy(buf, "YCbCr out\n");
+
+ return strlen(buf);
+}
+
+static ssize_t mxc_hdmi_store_rgb_out_enable(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mxc_hdmi *hdmi = dev_get_drvdata(dev);
+ unsigned long value;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &value);
+ if (ret)
+ return ret;
+
+ hdmi->hdmi_data.rgb_out_enable = value;
+
+ /* Reconfig HDMI for output color space change */
+ mxc_hdmi_setup(hdmi, 0);
+
+ return count;
+}
+
+static DEVICE_ATTR(rgb_out_enable, S_IRUGO | S_IWUSR,
+ mxc_hdmi_show_rgb_out_enable,
+ mxc_hdmi_store_rgb_out_enable);
+
+static ssize_t mxc_hdmi_show_hdcp_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mxc_hdmi *hdmi = dev_get_drvdata(dev);
+
+ if (hdmi->hdmi_data.hdcp_enable == false)
+ strcpy(buf, "hdcp disable\n");
+ else
+ strcpy(buf, "hdcp enable\n");
+
+ return strlen(buf);
+
+}
+
+static ssize_t mxc_hdmi_store_hdcp_enable(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct mxc_hdmi *hdmi = dev_get_drvdata(dev);
+ char event_string[32];
+ char *envp[] = { event_string, NULL };
+ unsigned long value;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &value);
+ if (ret)
+ return ret;
+
+ hdmi->hdmi_data.hdcp_enable = value;
+
+ /* Reconfig HDMI for HDCP */
+ mxc_hdmi_setup(hdmi, 0);
+
+ if (hdmi->hdmi_data.hdcp_enable == false) {
+ sprintf(event_string, "EVENT=hdcpdisable");
+ kobject_uevent_env(&hdmi->pdev->dev.kobj, KOBJ_CHANGE, envp);
+ } else {
+ sprintf(event_string, "EVENT=hdcpenable");
+ kobject_uevent_env(&hdmi->pdev->dev.kobj, KOBJ_CHANGE, envp);
+ }
+
+ return count;
+
+}
+
+static DEVICE_ATTR(hdcp_enable, S_IRUGO | S_IWUSR,
+ mxc_hdmi_show_hdcp_enable, mxc_hdmi_store_hdcp_enable);
+
+/*!
+ * this submodule is responsible for the video data synchronization.
+ * for example, for RGB 4:4:4 input, the data map is defined as
+ * pin{47~40} <==> R[7:0]
+ * pin{31~24} <==> G[7:0]
+ * pin{15~8} <==> B[7:0]
+ */
+static void hdmi_video_sample(struct mxc_hdmi *hdmi)
+{
+ int color_format = 0;
+ u8 val;
+
+ if (hdmi->hdmi_data.enc_in_format == RGB) {
+ if (hdmi->hdmi_data.enc_color_depth == 8)
+ color_format = 0x01;
+ else if (hdmi->hdmi_data.enc_color_depth == 10)
+ color_format = 0x03;
+ else if (hdmi->hdmi_data.enc_color_depth == 12)
+ color_format = 0x05;
+ else if (hdmi->hdmi_data.enc_color_depth == 16)
+ color_format = 0x07;
+ else
+ return;
+ } else if (hdmi->hdmi_data.enc_in_format == YCBCR444) {
+ if (hdmi->hdmi_data.enc_color_depth == 8)
+ color_format = 0x09;
+ else if (hdmi->hdmi_data.enc_color_depth == 10)
+ color_format = 0x0B;
+ else if (hdmi->hdmi_data.enc_color_depth == 12)
+ color_format = 0x0D;
+ else if (hdmi->hdmi_data.enc_color_depth == 16)
+ color_format = 0x0F;
+ else
+ return;
+ } else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) {
+ if (hdmi->hdmi_data.enc_color_depth == 8)
+ color_format = 0x16;
+ else if (hdmi->hdmi_data.enc_color_depth == 10)
+ color_format = 0x14;
+ else if (hdmi->hdmi_data.enc_color_depth == 12)
+ color_format = 0x12;
+ else
+ return;
+ }
+
+ val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
+ ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
+ HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
+ hdmi_writeb(val, HDMI_TX_INVID0);
+
+ /* Enable TX stuffing: When DE is inactive, fix the output data to 0 */
+ val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
+ HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
+ HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
+ hdmi_writeb(val, HDMI_TX_INSTUFFING);
+ hdmi_writeb(0x0, HDMI_TX_GYDATA0);
+ hdmi_writeb(0x0, HDMI_TX_GYDATA1);
+ hdmi_writeb(0x0, HDMI_TX_RCRDATA0);
+ hdmi_writeb(0x0, HDMI_TX_RCRDATA1);
+ hdmi_writeb(0x0, HDMI_TX_BCBDATA0);
+ hdmi_writeb(0x0, HDMI_TX_BCBDATA1);
+}
+
+static int isColorSpaceConversion(struct mxc_hdmi *hdmi)
+{
+ return (hdmi->hdmi_data.enc_in_format !=
+ hdmi->hdmi_data.enc_out_format);
+}
+
+static int isColorSpaceDecimation(struct mxc_hdmi *hdmi)
+{
+ return ((hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS) &&
+ (hdmi->hdmi_data.enc_in_format == RGB ||
+ hdmi->hdmi_data.enc_in_format == YCBCR444));
+}
+
+static int isColorSpaceInterpolation(struct mxc_hdmi *hdmi)
+{
+ return ((hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) &&
+ (hdmi->hdmi_data.enc_out_format == RGB
+ || hdmi->hdmi_data.enc_out_format == YCBCR444));
+}
+
+/*!
+ * update the color space conversion coefficients.
+ */
+static void update_csc_coeffs(struct mxc_hdmi *hdmi)
+{
+ unsigned short csc_coeff[3][4];
+ unsigned int csc_scale = 1;
+ u8 val;
+ bool coeff_selected = false;
+
+ if (isColorSpaceConversion(hdmi)) { /* csc needed */
+ if (hdmi->hdmi_data.enc_out_format == RGB) {
+ if (hdmi->hdmi_data.colorimetry == eITU601) {
+ csc_coeff[0][0] = 0x2000;
+ csc_coeff[0][1] = 0x6926;
+ csc_coeff[0][2] = 0x74fd;
+ csc_coeff[0][3] = 0x010e;
+
+ csc_coeff[1][0] = 0x2000;
+ csc_coeff[1][1] = 0x2cdd;
+ csc_coeff[1][2] = 0x0000;
+ csc_coeff[1][3] = 0x7e9a;
+
+ csc_coeff[2][0] = 0x2000;
+ csc_coeff[2][1] = 0x0000;
+ csc_coeff[2][2] = 0x38b4;
+ csc_coeff[2][3] = 0x7e3b;
+
+ csc_scale = 1;
+ coeff_selected = true;
+ } else if (hdmi->hdmi_data.colorimetry == eITU709) {
+ csc_coeff[0][0] = 0x2000;
+ csc_coeff[0][1] = 0x7106;
+ csc_coeff[0][2] = 0x7a02;
+ csc_coeff[0][3] = 0x00a7;
+
+ csc_coeff[1][0] = 0x2000;
+ csc_coeff[1][1] = 0x3264;
+ csc_coeff[1][2] = 0x0000;
+ csc_coeff[1][3] = 0x7e6d;
+
+ csc_coeff[2][0] = 0x2000;
+ csc_coeff[2][1] = 0x0000;
+ csc_coeff[2][2] = 0x3b61;
+ csc_coeff[2][3] = 0x7e25;
+
+ csc_scale = 1;
+ coeff_selected = true;
+ }
+ } else if (hdmi->hdmi_data.enc_in_format == RGB) {
+ if (hdmi->hdmi_data.colorimetry == eITU601) {
+ csc_coeff[0][0] = 0x2591;
+ csc_coeff[0][1] = 0x1322;
+ csc_coeff[0][2] = 0x074b;
+ csc_coeff[0][3] = 0x0000;
+
+ csc_coeff[1][0] = 0x6535;
+ csc_coeff[1][1] = 0x2000;
+ csc_coeff[1][2] = 0x7acc;
+ csc_coeff[1][3] = 0x0200;
+
+ csc_coeff[2][0] = 0x6acd;
+ csc_coeff[2][1] = 0x7534;
+ csc_coeff[2][2] = 0x2000;
+ csc_coeff[2][3] = 0x0200;
+
+ csc_scale = 0;
+ coeff_selected = true;
+ } else if (hdmi->hdmi_data.colorimetry == eITU709) {
+ csc_coeff[0][0] = 0x2dc5;
+ csc_coeff[0][1] = 0x0d9b;
+ csc_coeff[0][2] = 0x049e;
+ csc_coeff[0][3] = 0x0000;
+
+ csc_coeff[1][0] = 0x62f0;
+ csc_coeff[1][1] = 0x2000;
+ csc_coeff[1][2] = 0x7d11;
+ csc_coeff[1][3] = 0x0200;
+
+ csc_coeff[2][0] = 0x6756;
+ csc_coeff[2][1] = 0x78ab;
+ csc_coeff[2][2] = 0x2000;
+ csc_coeff[2][3] = 0x0200;
+
+ csc_scale = 0;
+ coeff_selected = true;
+ }
+ }
+ }
+
+ if (!coeff_selected) {
+ csc_coeff[0][0] = 0x2000;
+ csc_coeff[0][1] = 0x0000;
+ csc_coeff[0][2] = 0x0000;
+ csc_coeff[0][3] = 0x0000;
+
+ csc_coeff[1][0] = 0x0000;
+ csc_coeff[1][1] = 0x2000;
+ csc_coeff[1][2] = 0x0000;
+ csc_coeff[1][3] = 0x0000;
+
+ csc_coeff[2][0] = 0x0000;
+ csc_coeff[2][1] = 0x0000;
+ csc_coeff[2][2] = 0x2000;
+ csc_coeff[2][3] = 0x0000;
+
+ csc_scale = 1;
+ }
+
+ /* Update CSC parameters in HDMI CSC registers */
+ hdmi_writeb((unsigned char)(csc_coeff[0][0] & 0xFF),
+ HDMI_CSC_COEF_A1_LSB);
+ hdmi_writeb((unsigned char)(csc_coeff[0][0] >> 8),
+ HDMI_CSC_COEF_A1_MSB);
+ hdmi_writeb((unsigned char)(csc_coeff[0][1] & 0xFF),
+ HDMI_CSC_COEF_A2_LSB);
+ hdmi_writeb((unsigned char)(csc_coeff[0][1] >> 8),
+ HDMI_CSC_COEF_A2_MSB);
+ hdmi_writeb((unsigned char)(csc_coeff[0][2] & 0xFF),
+ HDMI_CSC_COEF_A3_LSB);
+ hdmi_writeb((unsigned char)(csc_coeff[0][2] >> 8),
+ HDMI_CSC_COEF_A3_MSB);
+ hdmi_writeb((unsigned char)(csc_coeff[0][3] & 0xFF),
+ HDMI_CSC_COEF_A4_LSB);
+ hdmi_writeb((unsigned char)(csc_coeff[0][3] >> 8),
+ HDMI_CSC_COEF_A4_MSB);
+
+ hdmi_writeb((unsigned char)(csc_coeff[1][0] & 0xFF),
+ HDMI_CSC_COEF_B1_LSB);
+ hdmi_writeb((unsigned char)(csc_coeff[1][0] >> 8),
+ HDMI_CSC_COEF_B1_MSB);
+ hdmi_writeb((unsigned char)(csc_coeff[1][1] & 0xFF),
+ HDMI_CSC_COEF_B2_LSB);
+ hdmi_writeb((unsigned char)(csc_coeff[1][1] >> 8),
+ HDMI_CSC_COEF_B2_MSB);
+ hdmi_writeb((unsigned char)(csc_coeff[1][2] & 0xFF),
+ HDMI_CSC_COEF_B3_LSB);
+ hdmi_writeb((unsigned char)(csc_coeff[1][2] >> 8),
+ HDMI_CSC_COEF_B3_MSB);
+ hdmi_writeb((unsigned char)(csc_coeff[1][3] & 0xFF),
+ HDMI_CSC_COEF_B4_LSB);
+ hdmi_writeb((unsigned char)(csc_coeff[1][3] >> 8),
+ HDMI_CSC_COEF_B4_MSB);
+
+ hdmi_writeb((unsigned char)(csc_coeff[2][0] & 0xFF),
+ HDMI_CSC_COEF_C1_LSB);
+ hdmi_writeb((unsigned char)(csc_coeff[2][0] >> 8),
+ HDMI_CSC_COEF_C1_MSB);
+ hdmi_writeb((unsigned char)(csc_coeff[2][1] & 0xFF),
+ HDMI_CSC_COEF_C2_LSB);
+ hdmi_writeb((unsigned char)(csc_coeff[2][1] >> 8),
+ HDMI_CSC_COEF_C2_MSB);
+ hdmi_writeb((unsigned char)(csc_coeff[2][2] & 0xFF),
+ HDMI_CSC_COEF_C3_LSB);
+ hdmi_writeb((unsigned char)(csc_coeff[2][2] >> 8),
+ HDMI_CSC_COEF_C3_MSB);
+ hdmi_writeb((unsigned char)(csc_coeff[2][3] & 0xFF),
+ HDMI_CSC_COEF_C4_LSB);
+ hdmi_writeb((unsigned char)(csc_coeff[2][3] >> 8),
+ HDMI_CSC_COEF_C4_MSB);
+
+ val = hdmi_readb(HDMI_CSC_SCALE);
+ val &= ~HDMI_CSC_SCALE_CSCSCALE_MASK;
+ val |= csc_scale & HDMI_CSC_SCALE_CSCSCALE_MASK;
+ hdmi_writeb(val, HDMI_CSC_SCALE);
+}
+
+static void hdmi_video_csc(struct mxc_hdmi *hdmi)
+{
+ int color_depth = 0;
+ int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
+ int decimation = 0;
+ u8 val;
+
+ /* YCC422 interpolation to 444 mode */
+ if (isColorSpaceInterpolation(hdmi))
+ interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1;
+ else if (isColorSpaceDecimation(hdmi))
+ decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3;
+
+ if (hdmi->hdmi_data.enc_color_depth == 8)
+ color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
+ else if (hdmi->hdmi_data.enc_color_depth == 10)
+ color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP;
+ else if (hdmi->hdmi_data.enc_color_depth == 12)
+ color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP;
+ else if (hdmi->hdmi_data.enc_color_depth == 16)
+ color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP;
+ else
+ return;
+
+ /*configure the CSC registers */
+ hdmi_writeb(interpolation | decimation, HDMI_CSC_CFG);
+ val = hdmi_readb(HDMI_CSC_SCALE);
+ val &= ~HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK;
+ val |= color_depth;
+ hdmi_writeb(val, HDMI_CSC_SCALE);
+
+ update_csc_coeffs(hdmi);
+}
+
+/*!
+ * HDMI video packetizer is used to packetize the data.
+ * for example, if input is YCC422 mode or repeater is used,
+ * data should be repacked this module can be bypassed.
+ */
+static void hdmi_video_packetize(struct mxc_hdmi *hdmi)
+{
+ unsigned int color_depth = 0;
+ unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
+ unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
+ struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
+ u8 val;
+
+ if (hdmi_data->enc_out_format == RGB
+ || hdmi_data->enc_out_format == YCBCR444) {
+ if (hdmi_data->enc_color_depth == 0)
+ output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
+ else if (hdmi_data->enc_color_depth == 8) {
+ color_depth = 4;
+ output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
+ } else if (hdmi_data->enc_color_depth == 10)
+ color_depth = 5;
+ else if (hdmi_data->enc_color_depth == 12)
+ color_depth = 6;
+ else if (hdmi_data->enc_color_depth == 16)
+ color_depth = 7;
+ else
+ return;
+ } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
+ if (hdmi_data->enc_color_depth == 0 ||
+ hdmi_data->enc_color_depth == 8)
+ remap_size = HDMI_VP_REMAP_YCC422_16bit;
+ else if (hdmi_data->enc_color_depth == 10)
+ remap_size = HDMI_VP_REMAP_YCC422_20bit;
+ else if (hdmi_data->enc_color_depth == 12)
+ remap_size = HDMI_VP_REMAP_YCC422_24bit;
+ else
+ return;
+ output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
+ } else
+ return;
+
+ /* HDMI not support deep color,
+ * because IPU MAX support color depth is 24bit */
+ color_depth = 0;
+
+ /* set the packetizer registers */
+ val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
+ HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
+ ((hdmi_data->pix_repet_factor <<
+ HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
+ HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
+ hdmi_writeb(val, HDMI_VP_PR_CD);
+
+ val = hdmi_readb(HDMI_VP_STUFF);
+ val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK;
+ val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE;
+ hdmi_writeb(val, HDMI_VP_STUFF);
+
+ /* Data from pixel repeater block */
+ if (hdmi_data->pix_repet_factor > 1) {
+ val = hdmi_readb(HDMI_VP_CONF);
+ val &= ~(HDMI_VP_CONF_PR_EN_MASK |
+ HDMI_VP_CONF_BYPASS_SELECT_MASK);
+ val |= HDMI_VP_CONF_PR_EN_ENABLE |
+ HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
+ hdmi_writeb(val, HDMI_VP_CONF);
+ } else { /* data from packetizer block */
+ val = hdmi_readb(HDMI_VP_CONF);
+ val &= ~(HDMI_VP_CONF_PR_EN_MASK |
+ HDMI_VP_CONF_BYPASS_SELECT_MASK);
+ val |= HDMI_VP_CONF_PR_EN_DISABLE |
+ HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
+ hdmi_writeb(val, HDMI_VP_CONF);
+ }
+
+ val = hdmi_readb(HDMI_VP_STUFF);
+ val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK;
+ val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET;
+ hdmi_writeb(val, HDMI_VP_STUFF);
+
+ hdmi_writeb(remap_size, HDMI_VP_REMAP);
+
+ if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
+ val = hdmi_readb(HDMI_VP_CONF);
+ val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
+ HDMI_VP_CONF_PP_EN_ENMASK |
+ HDMI_VP_CONF_YCC422_EN_MASK);
+ val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
+ HDMI_VP_CONF_PP_EN_ENABLE |
+ HDMI_VP_CONF_YCC422_EN_DISABLE;
+ hdmi_writeb(val, HDMI_VP_CONF);
+ } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
+ val = hdmi_readb(HDMI_VP_CONF);
+ val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
+ HDMI_VP_CONF_PP_EN_ENMASK |
+ HDMI_VP_CONF_YCC422_EN_MASK);
+ val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
+ HDMI_VP_CONF_PP_EN_DISABLE |
+ HDMI_VP_CONF_YCC422_EN_ENABLE;
+ hdmi_writeb(val, HDMI_VP_CONF);
+ } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
+ val = hdmi_readb(HDMI_VP_CONF);
+ val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
+ HDMI_VP_CONF_PP_EN_ENMASK |
+ HDMI_VP_CONF_YCC422_EN_MASK);
+ val |= HDMI_VP_CONF_BYPASS_EN_ENABLE |
+ HDMI_VP_CONF_PP_EN_DISABLE |
+ HDMI_VP_CONF_YCC422_EN_DISABLE;
+ hdmi_writeb(val, HDMI_VP_CONF);
+ } else {
+ return;
+ }
+
+ val = hdmi_readb(HDMI_VP_STUFF);
+ val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK |
+ HDMI_VP_STUFF_YCC422_STUFFING_MASK);
+ val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
+ HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE;
+ hdmi_writeb(val, HDMI_VP_STUFF);
+
+ val = hdmi_readb(HDMI_VP_CONF);
+ val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK;
+ val |= output_select;
+ hdmi_writeb(val, HDMI_VP_CONF);
+}
+
+#if 0
+/* Force a fixed color screen */
+static void hdmi_video_force_output(struct mxc_hdmi *hdmi, unsigned char force)
+{
+ u8 val;
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ if (force) {
+ hdmi_writeb(0x00, HDMI_FC_DBGTMDS2); /* R */
+ hdmi_writeb(0x00, HDMI_FC_DBGTMDS1); /* G */
+ hdmi_writeb(0xFF, HDMI_FC_DBGTMDS0); /* B */
+ val = hdmi_readb(HDMI_FC_DBGFORCE);
+ val |= HDMI_FC_DBGFORCE_FORCEVIDEO;
+ hdmi_writeb(val, HDMI_FC_DBGFORCE);
+ } else {
+ val = hdmi_readb(HDMI_FC_DBGFORCE);
+ val &= ~HDMI_FC_DBGFORCE_FORCEVIDEO;
+ hdmi_writeb(val, HDMI_FC_DBGFORCE);
+ hdmi_writeb(0x00, HDMI_FC_DBGTMDS2); /* R */
+ hdmi_writeb(0x00, HDMI_FC_DBGTMDS1); /* G */
+ hdmi_writeb(0x00, HDMI_FC_DBGTMDS0); /* B */
+ }
+}
+#endif
+
+static inline void hdmi_phy_test_clear(struct mxc_hdmi *hdmi,
+ unsigned char bit)
+{
+ u8 val = hdmi_readb(HDMI_PHY_TST0);
+ val &= ~HDMI_PHY_TST0_TSTCLR_MASK;
+ val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) &
+ HDMI_PHY_TST0_TSTCLR_MASK;
+ hdmi_writeb(val, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_enable(struct mxc_hdmi *hdmi,
+ unsigned char bit)
+{
+ u8 val = hdmi_readb(HDMI_PHY_TST0);
+ val &= ~HDMI_PHY_TST0_TSTEN_MASK;
+ val |= (bit << HDMI_PHY_TST0_TSTEN_OFFSET) &
+ HDMI_PHY_TST0_TSTEN_MASK;
+ hdmi_writeb(val, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_clock(struct mxc_hdmi *hdmi,
+ unsigned char bit)
+{
+ u8 val = hdmi_readb(HDMI_PHY_TST0);
+ val &= ~HDMI_PHY_TST0_TSTCLK_MASK;
+ val |= (bit << HDMI_PHY_TST0_TSTCLK_OFFSET) &
+ HDMI_PHY_TST0_TSTCLK_MASK;
+ hdmi_writeb(val, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_din(struct mxc_hdmi *hdmi,
+ unsigned char bit)
+{
+ hdmi_writeb(bit, HDMI_PHY_TST1);
+}
+
+static inline void hdmi_phy_test_dout(struct mxc_hdmi *hdmi,
+ unsigned char bit)
+{
+ hdmi_writeb(bit, HDMI_PHY_TST2);
+}
+
+static bool hdmi_phy_wait_i2c_done(struct mxc_hdmi *hdmi, int msec)
+{
+ unsigned char val = 0;
+ val = hdmi_readb(HDMI_IH_I2CMPHY_STAT0) & 0x3;
+ while (val == 0) {
+ udelay(1000);
+ if (msec-- == 0)
+ return false;
+ val = hdmi_readb(HDMI_IH_I2CMPHY_STAT0) & 0x3;
+ }
+ return true;
+}
+
+static void hdmi_phy_i2c_write(struct mxc_hdmi *hdmi, unsigned short data,
+ unsigned char addr)
+{
+ hdmi_writeb(0xFF, HDMI_IH_I2CMPHY_STAT0);
+ hdmi_writeb(addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
+ hdmi_writeb((unsigned char)(data >> 8),
+ HDMI_PHY_I2CM_DATAO_1_ADDR);
+ hdmi_writeb((unsigned char)(data >> 0),
+ HDMI_PHY_I2CM_DATAO_0_ADDR);
+ hdmi_writeb(HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
+ HDMI_PHY_I2CM_OPERATION_ADDR);
+ hdmi_phy_wait_i2c_done(hdmi, 1000);
+}
+
+#if 0
+static unsigned short hdmi_phy_i2c_read(struct mxc_hdmi *hdmi,
+ unsigned char addr)
+{
+ unsigned short data;
+ unsigned char msb = 0, lsb = 0;
+ hdmi_writeb(0xFF, HDMI_IH_I2CMPHY_STAT0);
+ hdmi_writeb(addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
+ hdmi_writeb(HDMI_PHY_I2CM_OPERATION_ADDR_READ,
+ HDMI_PHY_I2CM_OPERATION_ADDR);
+ hdmi_phy_wait_i2c_done(hdmi, 1000);
+ msb = hdmi_readb(HDMI_PHY_I2CM_DATAI_1_ADDR);
+ lsb = hdmi_readb(HDMI_PHY_I2CM_DATAI_0_ADDR);
+ data = (msb << 8) | lsb;
+ return data;
+}
+
+static int hdmi_phy_i2c_write_verify(struct mxc_hdmi *hdmi, unsigned short data,
+ unsigned char addr)
+{
+ unsigned short val = 0;
+ hdmi_phy_i2c_write(hdmi, data, addr);
+ val = hdmi_phy_i2c_read(hdmi, addr);
+ return (val == data);
+}
+#endif
+
+static bool hdmi_edid_wait_i2c_done(struct mxc_hdmi *hdmi, int msec)
+{
+ unsigned char val = 0;
+ val = hdmi_readb(HDMI_IH_I2CM_STAT0) & 0x2;
+ while (val == 0) {
+
+ udelay(1000);
+ if (msec-- == 0) {
+ dev_dbg(&hdmi->pdev->dev,
+ "HDMI EDID i2c operation time out!!\n");
+ return false;
+ }
+ val = hdmi_readb(HDMI_IH_I2CM_STAT0) & 0x2;
+ }
+ return true;
+}
+
+static u8 hdmi_edid_i2c_read(struct mxc_hdmi *hdmi,
+ u8 addr, u8 blockno)
+{
+ u8 spointer = blockno / 2;
+ u8 edidaddress = ((blockno % 2) * 0x80) + addr;
+ u8 data;
+
+ hdmi_writeb(0xFF, HDMI_IH_I2CM_STAT0);
+ hdmi_writeb(edidaddress, HDMI_I2CM_ADDRESS);
+ hdmi_writeb(spointer, HDMI_I2CM_SEGADDR);
+ if (spointer == 0)
+ hdmi_writeb(HDMI_I2CM_OPERATION_READ,
+ HDMI_I2CM_OPERATION);
+ else
+ hdmi_writeb(HDMI_I2CM_OPERATION_READ_EXT,
+ HDMI_I2CM_OPERATION);
+
+ hdmi_edid_wait_i2c_done(hdmi, 30);
+ data = hdmi_readb(HDMI_I2CM_DATAI);
+ hdmi_writeb(0xFF, HDMI_IH_I2CM_STAT0);
+ return data;
+}
+
+
+/* "Power-down enable (active low)"
+ * That mean that power up == 1! */
+static void mxc_hdmi_phy_enable_power(u8 enable)
+{
+ hdmi_mask_writeb(enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_PDZ_OFFSET,
+ HDMI_PHY_CONF0_PDZ_MASK);
+}
+
+static void mxc_hdmi_phy_enable_tmds(u8 enable)
+{
+ hdmi_mask_writeb(enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_ENTMDS_OFFSET,
+ HDMI_PHY_CONF0_ENTMDS_MASK);
+}
+
+static void mxc_hdmi_phy_gen2_pddq(u8 enable)
+{
+ hdmi_mask_writeb(enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
+ HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
+}
+
+static void mxc_hdmi_phy_gen2_txpwron(u8 enable)
+{
+ hdmi_mask_writeb(enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
+ HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
+}
+
+#if 0
+static void mxc_hdmi_phy_gen2_enhpdrxsense(u8 enable)
+{
+ hdmi_mask_writeb(enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_OFFSET,
+ HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_MASK);
+}
+#endif
+
+static void mxc_hdmi_phy_sel_data_en_pol(u8 enable)
+{
+ hdmi_mask_writeb(enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_SELDATAENPOL_OFFSET,
+ HDMI_PHY_CONF0_SELDATAENPOL_MASK);
+}
+
+static void mxc_hdmi_phy_sel_interface_control(u8 enable)
+{
+ hdmi_mask_writeb(enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_SELDIPIF_OFFSET,
+ HDMI_PHY_CONF0_SELDIPIF_MASK);
+}
+
+static int hdmi_phy_configure(struct mxc_hdmi *hdmi, unsigned char pRep,
+ unsigned char cRes, int cscOn)
+{
+ u8 val;
+ u8 msec;
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ /* color resolution 0 is 8 bit colour depth */
+ if (cRes == 0)
+ cRes = 8;
+
+ if (pRep != 0)
+ return false;
+ else if (cRes != 8 && cRes != 12)
+ return false;
+
+ /* Enable csc path */
+ if (cscOn)
+ val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH;
+ else
+ val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS;
+
+ hdmi_writeb(val, HDMI_MC_FLOWCTRL);
+
+ /* gen2 tx power off */
+ mxc_hdmi_phy_gen2_txpwron(0);
+
+ /* gen2 pddq */
+ mxc_hdmi_phy_gen2_pddq(1);
+
+ /* PHY reset */
+ hdmi_writeb(HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
+ hdmi_writeb(HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
+
+ hdmi_writeb(HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
+
+ hdmi_phy_test_clear(hdmi, 1);
+ hdmi_writeb(HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
+ HDMI_PHY_I2CM_SLAVE_ADDR);
+ hdmi_phy_test_clear(hdmi, 0);
+
+ if (hdmi->hdmi_data.video_mode.mPixelClock < 0) {
+ dev_dbg(&hdmi->pdev->dev, "Pixel clock (%d) must be positive\n",
+ hdmi->hdmi_data.video_mode.mPixelClock);
+ return false;
+ }
+
+ if (hdmi->hdmi_data.video_mode.mPixelClock <= 45250000) {
+ switch (cRes) {
+ case 8:
+ /* PLL/MPLL Cfg */
+ hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); /* GMPCTRL */
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x21e1, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x41e2, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
+ break;
+ default:
+ return false;
+ }
+ } else if (hdmi->hdmi_data.video_mode.mPixelClock <= 92500000) {
+ switch (cRes) {
+ case 8:
+ hdmi_phy_i2c_write(hdmi, 0x0140, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x2141, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x4142, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+ default:
+ return false;
+ }
+ } else if (hdmi->hdmi_data.video_mode.mPixelClock <= 148500000) {
+ switch (cRes) {
+ case 8:
+ hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x20a1, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x40a2, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+ default:
+ return false;
+ }
+ } else {
+ switch (cRes) {
+ case 8:
+ hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x2001, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x4002, 0x06);
+ hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
+ default:
+ return false;
+ }
+ }
+
+ if (hdmi->hdmi_data.video_mode.mPixelClock <= 54000000) {
+ switch (cRes) {
+ case 8:
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); /* CURRCTRL */
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+ break;
+ default:
+ return false;
+ }
+ } else if (hdmi->hdmi_data.video_mode.mPixelClock <= 58400000) {
+ switch (cRes) {
+ case 8:
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+ break;
+ default:
+ return false;
+ }
+ } else if (hdmi->hdmi_data.video_mode.mPixelClock <= 72000000) {
+ switch (cRes) {
+ case 8:
+ hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ break;
+ default:
+ return false;
+ }
+ } else if (hdmi->hdmi_data.video_mode.mPixelClock <= 74250000) {
+ switch (cRes) {
+ case 8:
+ hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ break;
+ default:
+ return false;
+ }
+ } else if (hdmi->hdmi_data.video_mode.mPixelClock <= 118800000) {
+ switch (cRes) {
+ case 8:
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+ break;
+ default:
+ return false;
+ }
+ } else if (hdmi->hdmi_data.video_mode.mPixelClock <= 216000000) {
+ switch (cRes) {
+ case 8:
+ hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+ break;
+ case 10:
+ hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
+ break;
+ case 12:
+ hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+ break;
+ default:
+ return false;
+ }
+ } else {
+ dev_err(&hdmi->pdev->dev,
+ "Pixel clock %d - unsupported by HDMI\n",
+ hdmi->hdmi_data.video_mode.mPixelClock);
+ return false;
+ }
+
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+ /* RESISTANCE TERM 133Ohm Cfg */
+ hdmi_phy_i2c_write(hdmi, 0x0005, 0x19); /* TXTERM */
+ /* PREEMP Cgf 0.00 */
+ hdmi_phy_i2c_write(hdmi, 0x800d, 0x09); /* CKSYMTXCTRL */
+ /* TX/CK LVL 10 */
+ hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */
+
+ /* Board specific setting for PHY register 0x09, 0x0e to pass HCT */
+ if (hdmi->phy_config.reg_cksymtx != 0)
+ hdmi_phy_i2c_write(hdmi, hdmi->phy_config.reg_cksymtx, 0x09);
+
+ if (hdmi->phy_config.reg_vlev != 0)
+ hdmi_phy_i2c_write(hdmi, hdmi->phy_config.reg_vlev, 0x0E);
+
+ /* REMOVE CLK TERM */
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
+
+ if (hdmi->hdmi_data.video_mode.mPixelClock > 148500000) {
+ hdmi_phy_i2c_write(hdmi, 0x800b, 0x09);
+ hdmi_phy_i2c_write(hdmi, 0x0129, 0x0E);
+ }
+
+ mxc_hdmi_phy_enable_power(1);
+
+ /* toggle TMDS enable */
+ mxc_hdmi_phy_enable_tmds(0);
+ mxc_hdmi_phy_enable_tmds(1);
+
+ /* gen2 tx power on */
+ mxc_hdmi_phy_gen2_txpwron(1);
+ mxc_hdmi_phy_gen2_pddq(0);
+
+ /*Wait for PHY PLL lock */
+ msec = 4;
+ val = hdmi_readb(HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
+ while (val == 0) {
+ udelay(1000);
+ if (msec-- == 0) {
+ dev_dbg(&hdmi->pdev->dev, "PHY PLL not locked\n");
+ return false;
+ }
+ val = hdmi_readb(HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
+ }
+
+ return true;
+}
+
+static void mxc_hdmi_phy_init(struct mxc_hdmi *hdmi)
+{
+ int i;
+ bool cscon = false;
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ /* Never do phy init if pixel clock is gated.
+ * Otherwise HDMI PHY will get messed up and generate an overflow
+ * interrupt that can't be cleared or detected by accessing the
+ * status register. */
+ if (!hdmi->fb_reg || !hdmi->cable_plugin
+ || (hdmi->blank != FB_BLANK_UNBLANK))
+ return;
+
+ if (!hdmi->hdmi_data.video_mode.mDVI)
+ hdmi_enable_overflow_interrupts();
+
+ /*check csc whether needed activated in HDMI mode */
+ cscon = (isColorSpaceConversion(hdmi) &&
+ !hdmi->hdmi_data.video_mode.mDVI);
+
+ /* HDMI Phy spec says to do the phy initialization sequence twice */
+ for (i = 0 ; i < 2 ; i++) {
+ mxc_hdmi_phy_sel_data_en_pol(1);
+ mxc_hdmi_phy_sel_interface_control(0);
+ mxc_hdmi_phy_enable_tmds(0);
+ mxc_hdmi_phy_enable_power(0);
+
+ /* Enable CSC */
+ hdmi_phy_configure(hdmi, 0, 8, cscon);
+ }
+
+ hdmi->phy_enabled = true;
+}
+
+static void hdmi_config_AVI(struct mxc_hdmi *hdmi)
+{
+ u8 val;
+ u8 pix_fmt;
+ u8 under_scan;
+ u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry;
+ struct fb_videomode mode;
+ const struct fb_videomode *edid_mode;
+ bool aspect_16_9;
+
+ dev_dbg(&hdmi->pdev->dev, "set up AVI frame\n");
+
+ fb_var_to_videomode(&mode, &hdmi->fbi->var);
+ /* Use mode from list extracted from EDID to get aspect ratio */
+ if (!list_empty(&hdmi->fbi->modelist)) {
+ edid_mode = fb_find_nearest_mode(&mode, &hdmi->fbi->modelist);
+ if (edid_mode->vmode & FB_VMODE_ASPECT_16_9)
+ aspect_16_9 = true;
+ else
+ aspect_16_9 = false;
+ } else
+ aspect_16_9 = false;
+
+ /********************************************
+ * AVI Data Byte 1
+ ********************************************/
+ if (hdmi->hdmi_data.enc_out_format == YCBCR444)
+ pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR444;
+ else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS)
+ pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR422;
+ else
+ pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_RGB;
+
+ if (hdmi->edid_cfg.cea_underscan)
+ under_scan = HDMI_FC_AVICONF0_SCAN_INFO_UNDERSCAN;
+ else
+ under_scan = HDMI_FC_AVICONF0_SCAN_INFO_NODATA;
+
+ /*
+ * Active format identification data is present in the AVI InfoFrame.
+ * Under scan info, no bar data
+ */
+ val = pix_fmt | under_scan |
+ HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT |
+ HDMI_FC_AVICONF0_BAR_DATA_NO_DATA;
+
+ hdmi_writeb(val, HDMI_FC_AVICONF0);
+
+ /********************************************
+ * AVI Data Byte 2
+ ********************************************/
+
+ /* Set the Aspect Ratio */
+ if (aspect_16_9) {
+ act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9;
+ coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9;
+ } else {
+ act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3;
+ coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3;
+ }
+
+ /* Set up colorimetry */
+ if (hdmi->hdmi_data.enc_out_format == XVYCC444) {
+ colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO;
+ if (hdmi->hdmi_data.colorimetry == eITU601)
+ ext_colorimetry =
+ HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+ else /* hdmi->hdmi_data.colorimetry == eITU709 */
+ ext_colorimetry =
+ HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709;
+ } else if (hdmi->hdmi_data.enc_out_format != RGB) {
+ if (hdmi->hdmi_data.colorimetry == eITU601)
+ colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_SMPTE;
+ else /* hdmi->hdmi_data.colorimetry == eITU709 */
+ colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_ITUR;
+ ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+ } else { /* Carries no data */
+ colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA;
+ ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+ }
+
+ val = colorimetry | coded_ratio | act_ratio;
+ hdmi_writeb(val, HDMI_FC_AVICONF1);
+
+ /********************************************
+ * AVI Data Byte 3
+ ********************************************/
+
+ val = HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA | ext_colorimetry |
+ HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT |
+ HDMI_FC_AVICONF2_SCALING_NONE;
+ hdmi_writeb(val, HDMI_FC_AVICONF2);
+
+ /********************************************
+ * AVI Data Byte 4
+ ********************************************/
+ hdmi_writeb(hdmi->vic, HDMI_FC_AVIVID);
+
+ /********************************************
+ * AVI Data Byte 5
+ ********************************************/
+
+ /* Set up input and output pixel repetition */
+ val = (((hdmi->hdmi_data.video_mode.mPixelRepetitionInput + 1) <<
+ HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET) &
+ HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK) |
+ ((hdmi->hdmi_data.video_mode.mPixelRepetitionOutput <<
+ HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET) &
+ HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK);
+ hdmi_writeb(val, HDMI_FC_PRCONF);
+
+ /* IT Content and quantization range = don't care */
+ val = HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS |
+ HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED;
+ hdmi_writeb(val, HDMI_FC_AVICONF3);
+
+ /********************************************
+ * AVI Data Bytes 6-13
+ ********************************************/
+ hdmi_writeb(0, HDMI_FC_AVIETB0);
+ hdmi_writeb(0, HDMI_FC_AVIETB1);
+ hdmi_writeb(0, HDMI_FC_AVISBB0);
+ hdmi_writeb(0, HDMI_FC_AVISBB1);
+ hdmi_writeb(0, HDMI_FC_AVIELB0);
+ hdmi_writeb(0, HDMI_FC_AVIELB1);
+ hdmi_writeb(0, HDMI_FC_AVISRB0);
+ hdmi_writeb(0, HDMI_FC_AVISRB1);
+}
+
+/*!
+ * this submodule is responsible for the video/audio data composition.
+ */
+static void hdmi_av_composer(struct mxc_hdmi *hdmi)
+{
+ u8 inv_val;
+ struct fb_info *fbi = hdmi->fbi;
+ struct fb_videomode fb_mode;
+ struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
+ int hblank, vblank;
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ fb_var_to_videomode(&fb_mode, &fbi->var);
+
+ vmode->mHSyncPolarity = ((fb_mode.sync & FB_SYNC_HOR_HIGH_ACT) != 0);
+ vmode->mVSyncPolarity = ((fb_mode.sync & FB_SYNC_VERT_HIGH_ACT) != 0);
+ vmode->mInterlaced = ((fb_mode.vmode & FB_VMODE_INTERLACED) != 0);
+ vmode->mPixelClock = (fb_mode.xres + fb_mode.left_margin +
+ fb_mode.right_margin + fb_mode.hsync_len) * (fb_mode.yres +
+ fb_mode.upper_margin + fb_mode.lower_margin +
+ fb_mode.vsync_len) * fb_mode.refresh;
+
+ dev_dbg(&hdmi->pdev->dev, "final pixclk = %d\n", vmode->mPixelClock);
+
+ /* Set up HDMI_FC_INVIDCONF */
+ inv_val = (hdmi->hdmi_data.hdcp_enable ?
+ HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
+ HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
+
+ inv_val |= (vmode->mVSyncPolarity ?
+ HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
+ HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
+
+ inv_val |= (vmode->mHSyncPolarity ?
+ HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
+ HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
+
+ inv_val |= (vmode->mDataEnablePolarity ?
+ HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
+ HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);
+
+ if (hdmi->vic == 39)
+ inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH;
+ else
+ inv_val |= (vmode->mInterlaced ?
+ HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH :
+ HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW);
+
+ inv_val |= (vmode->mInterlaced ?
+ HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
+ HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE);
+
+ inv_val |= (vmode->mDVI ?
+ HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE :
+ HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE);
+
+ hdmi_writeb(inv_val, HDMI_FC_INVIDCONF);
+
+ /* Set up horizontal active pixel region width */
+ hdmi_writeb(fb_mode.xres >> 8, HDMI_FC_INHACTV1);
+ hdmi_writeb(fb_mode.xres, HDMI_FC_INHACTV0);
+
+ /* Set up vertical blanking pixel region width */
+ hdmi_writeb(fb_mode.yres >> 8, HDMI_FC_INVACTV1);
+ hdmi_writeb(fb_mode.yres, HDMI_FC_INVACTV0);
+
+ /* Set up horizontal blanking pixel region width */
+ hblank = fb_mode.left_margin + fb_mode.right_margin +
+ fb_mode.hsync_len;
+ hdmi_writeb(hblank >> 8, HDMI_FC_INHBLANK1);
+ hdmi_writeb(hblank, HDMI_FC_INHBLANK0);
+
+ /* Set up vertical blanking pixel region width */
+ vblank = fb_mode.upper_margin + fb_mode.lower_margin +
+ fb_mode.vsync_len;
+ hdmi_writeb(vblank, HDMI_FC_INVBLANK);
+
+ /* Set up HSYNC active edge delay width (in pixel clks) */
+ hdmi_writeb(fb_mode.right_margin >> 8, HDMI_FC_HSYNCINDELAY1);
+ hdmi_writeb(fb_mode.right_margin, HDMI_FC_HSYNCINDELAY0);
+
+ /* Set up VSYNC active edge delay (in pixel clks) */
+ hdmi_writeb(fb_mode.lower_margin, HDMI_FC_VSYNCINDELAY);
+
+ /* Set up HSYNC active pulse width (in pixel clks) */
+ hdmi_writeb(fb_mode.hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
+ hdmi_writeb(fb_mode.hsync_len, HDMI_FC_HSYNCINWIDTH0);
+
+ /* Set up VSYNC active edge delay (in pixel clks) */
+ hdmi_writeb(fb_mode.vsync_len, HDMI_FC_VSYNCINWIDTH);
+
+ dev_dbg(&hdmi->pdev->dev, "%s exit\n", __func__);
+}
+
+static int mxc_edid_read_internal(struct mxc_hdmi *hdmi, unsigned char *edid,
+ struct mxc_edid_cfg *cfg, struct fb_info *fbi)
+{
+ int extblknum;
+ int i, j, ret;
+ unsigned char *ediddata = edid;
+ unsigned char tmpedid[EDID_LENGTH];
+
+ dev_info(&hdmi->pdev->dev, "%s\n", __func__);
+
+ if (!edid || !cfg || !fbi)
+ return -EINVAL;
+
+ /* init HDMI I2CM for read edid*/
+ hdmi_writeb(0x0, HDMI_I2CM_DIV);
+ hdmi_writeb(0x00, HDMI_I2CM_SS_SCL_HCNT_1_ADDR);
+ hdmi_writeb(0x79, HDMI_I2CM_SS_SCL_HCNT_0_ADDR);
+ hdmi_writeb(0x00, HDMI_I2CM_SS_SCL_LCNT_1_ADDR);
+ hdmi_writeb(0x91, HDMI_I2CM_SS_SCL_LCNT_0_ADDR);
+
+ hdmi_writeb(0x00, HDMI_I2CM_FS_SCL_HCNT_1_ADDR);
+ hdmi_writeb(0x0F, HDMI_I2CM_FS_SCL_HCNT_0_ADDR);
+ hdmi_writeb(0x00, HDMI_I2CM_FS_SCL_LCNT_1_ADDR);
+ hdmi_writeb(0x21, HDMI_I2CM_FS_SCL_LCNT_0_ADDR);
+
+ hdmi_writeb(0x50, HDMI_I2CM_SLAVE);
+ hdmi_writeb(0x30, HDMI_I2CM_SEGADDR);
+
+ /* Umask edid interrupt */
+ hdmi_writeb(HDMI_I2CM_INT_DONE_POL,
+ HDMI_I2CM_INT);
+
+ hdmi_writeb(HDMI_I2CM_CTLINT_NAC_POL |
+ HDMI_I2CM_CTLINT_ARBITRATION_POL,
+ HDMI_I2CM_CTLINT);
+
+ /* reset edid data zero */
+ memset(edid, 0, EDID_LENGTH*4);
+ memset(cfg, 0, sizeof(struct mxc_edid_cfg));
+
+ /* Check first three byte of EDID head */
+ if (!(hdmi_edid_i2c_read(hdmi, 0, 0) == 0x00) ||
+ !(hdmi_edid_i2c_read(hdmi, 1, 0) == 0xFF) ||
+ !(hdmi_edid_i2c_read(hdmi, 2, 0) == 0xFF)) {
+ dev_info(&hdmi->pdev->dev, "EDID head check failed!");
+ return -ENOENT;
+ }
+
+ for (i = 0; i < 128; i++) {
+ *ediddata = hdmi_edid_i2c_read(hdmi, i, 0);
+ ediddata++;
+ }
+
+ extblknum = edid[0x7E];
+ if (extblknum == 255)
+ extblknum = 0;
+
+ if (extblknum) {
+ ediddata = edid + EDID_LENGTH;
+ for (i = 0; i < 128; i++) {
+ *ediddata = hdmi_edid_i2c_read(hdmi, i, 1);
+ ediddata++;
+ }
+ }
+
+ /* edid first block parsing */
+ memset(&fbi->monspecs, 0, sizeof(fbi->monspecs));
+ fb_edid_to_monspecs(edid, &fbi->monspecs);
+
+ if (extblknum) {
+ ret = mxc_edid_parse_ext_blk(edid + EDID_LENGTH,
+ cfg, &fbi->monspecs);
+ if (ret < 0)
+ return -ENOENT;
+ }
+
+ /* need read segment block? */
+ if (extblknum > 1) {
+ for (j = 2; j <= extblknum; j++) {
+ for (i = 0; i < 128; i++)
+ tmpedid[i] = hdmi_edid_i2c_read(hdmi, i, j);
+
+ /* edid ext block parsing */
+ ret = mxc_edid_parse_ext_blk(tmpedid,
+ cfg, &fbi->monspecs);
+ if (ret < 0)
+ return -ENOENT;
+ }
+ }
+
+ return 0;
+}
+
+static int mxc_hdmi_read_edid(struct mxc_hdmi *hdmi)
+{
+ int ret;
+ u8 edid_old[HDMI_EDID_LEN];
+ u8 clkdis;
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ /* save old edid */
+ memcpy(edid_old, hdmi->edid, HDMI_EDID_LEN);
+
+ /* Read EDID via HDMI DDC when HDCP Enable */
+ if (!hdcp_init)
+ ret = mxc_edid_read(hdmi_i2c->adapter, hdmi_i2c->addr,
+ hdmi->edid, &hdmi->edid_cfg, hdmi->fbi);
+ else {
+
+ /* Disable HDCP clk */
+ if (hdmi->hdmi_data.hdcp_enable) {
+ clkdis = hdmi_readb(HDMI_MC_CLKDIS);
+ clkdis |= HDMI_MC_CLKDIS_HDCPCLK_DISABLE;
+ hdmi_writeb(clkdis, HDMI_MC_CLKDIS);
+ }
+
+ ret = mxc_edid_read_internal(hdmi, hdmi->edid,
+ &hdmi->edid_cfg, hdmi->fbi);
+
+ /* Enable HDCP clk */
+ if (hdmi->hdmi_data.hdcp_enable) {
+ clkdis = hdmi_readb(HDMI_MC_CLKDIS);
+ clkdis &= ~HDMI_MC_CLKDIS_HDCPCLK_DISABLE;
+ hdmi_writeb(clkdis, HDMI_MC_CLKDIS);
+ }
+
+ }
+ if (ret < 0) {
+ dev_dbg(&hdmi->pdev->dev, "read failed\n");
+ return HDMI_EDID_FAIL;
+ }
+
+ /* Save edid cfg for audio driver */
+ hdmi_set_edid_cfg(&hdmi->edid_cfg);
+
+ if (!memcmp(edid_old, hdmi->edid, HDMI_EDID_LEN)) {
+ dev_info(&hdmi->pdev->dev, "same edid\n");
+ return HDMI_EDID_SAME;
+ }
+
+ if (hdmi->fbi->monspecs.modedb_len == 0) {
+ dev_info(&hdmi->pdev->dev, "No modes read from edid\n");
+ return HDMI_EDID_NO_MODES;
+ }
+
+ return HDMI_EDID_SUCCESS;
+}
+
+static void mxc_hdmi_phy_disable(struct mxc_hdmi *hdmi)
+{
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ if (!hdmi->phy_enabled)
+ return;
+
+ hdmi_disable_overflow_interrupts();
+
+ /* Setting PHY to reset status */
+ hdmi_writeb(HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
+
+ /* Power down PHY */
+ mxc_hdmi_phy_enable_tmds(0);
+ mxc_hdmi_phy_enable_power(0);
+ mxc_hdmi_phy_gen2_txpwron(0);
+ mxc_hdmi_phy_gen2_pddq(1);
+
+ hdmi->phy_enabled = false;
+ dev_dbg(&hdmi->pdev->dev, "%s - exit\n", __func__);
+}
+
+/* HDMI Initialization Step B.4 */
+static void mxc_hdmi_enable_video_path(struct mxc_hdmi *hdmi)
+{
+ u8 clkdis;
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ /* control period minimum duration */
+ hdmi_writeb(12, HDMI_FC_CTRLDUR);
+ hdmi_writeb(32, HDMI_FC_EXCTRLDUR);
+ hdmi_writeb(1, HDMI_FC_EXCTRLSPAC);
+
+ /* Set to fill TMDS data channels */
+ hdmi_writeb(0x0B, HDMI_FC_CH0PREAM);
+ hdmi_writeb(0x16, HDMI_FC_CH1PREAM);
+ hdmi_writeb(0x21, HDMI_FC_CH2PREAM);
+
+ clkdis = hdmi_readb(HDMI_MC_CLKDIS);
+ /* Enable pixel clock and tmds data path */
+ clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
+ hdmi_writeb(clkdis, HDMI_MC_CLKDIS);
+
+ clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
+ hdmi_writeb(clkdis, HDMI_MC_CLKDIS);
+
+ /* Enable csc path */
+ if (isColorSpaceConversion(hdmi)) {
+ clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
+ hdmi_writeb(clkdis, HDMI_MC_CLKDIS);
+ }
+}
+
+static void hdmi_enable_audio_clk(struct mxc_hdmi *hdmi)
+{
+ u8 clkdis;
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ clkdis = hdmi_readb(HDMI_MC_CLKDIS);
+ clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
+ hdmi_writeb(clkdis, HDMI_MC_CLKDIS);
+}
+
+/* Workaround to clear the overflow condition */
+static void mxc_hdmi_clear_overflow(struct mxc_hdmi *hdmi)
+{
+ int count;
+ u8 val;
+
+ /* TMDS software reset */
+ hdmi_writeb((u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
+
+ val = hdmi_readb(HDMI_FC_INVIDCONF);
+
+ if (cpu_is_imx6dl(hdmi)) {
+ hdmi_writeb(val, HDMI_FC_INVIDCONF);
+ return;
+ }
+
+ for (count = 0 ; count < 5 ; count++)
+ hdmi_writeb(val, HDMI_FC_INVIDCONF);
+}
+
+static void hdmi_enable_overflow_interrupts(void)
+{
+ pr_debug("%s\n", __func__);
+ hdmi_writeb(0, HDMI_FC_MASK2);
+ hdmi_writeb(0, HDMI_IH_MUTE_FC_STAT2);
+}
+
+static void hdmi_disable_overflow_interrupts(void)
+{
+ pr_debug("%s\n", __func__);
+ hdmi_writeb(HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
+ HDMI_IH_MUTE_FC_STAT2);
+ hdmi_writeb(0xff, HDMI_FC_MASK2);
+}
+
+static void mxc_hdmi_notify_fb(struct mxc_hdmi *hdmi)
+{
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ /* Don't notify if we aren't registered yet */
+ WARN_ON(!hdmi->fb_reg);
+
+ /* disable the phy before ipu changes mode */
+ mxc_hdmi_phy_disable(hdmi);
+
+ /*
+ * Note that fb_set_var will block. During this time,
+ * FB_EVENT_MODE_CHANGE callback will happen.
+ * So by the end of this function, mxc_hdmi_setup()
+ * will be done.
+ */
+ hdmi->fbi->var.activate |= FB_ACTIVATE_FORCE;
+ console_lock();
+ hdmi->fbi->flags |= FBINFO_MISC_USEREVENT;
+ fb_set_var(hdmi->fbi, &hdmi->fbi->var);
+ hdmi->fbi->flags &= ~FBINFO_MISC_USEREVENT;
+ console_unlock();
+
+ dev_dbg(&hdmi->pdev->dev, "%s exit\n", __func__);
+}
+
+static void mxc_hdmi_edid_rebuild_modelist(struct mxc_hdmi *hdmi)
+{
+ int i;
+ struct fb_videomode *mode;
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ console_lock();
+
+ fb_destroy_modelist(&hdmi->fbi->modelist);
+ fb_add_videomode(&vga_mode, &hdmi->fbi->modelist);
+
+ for (i = 0; i < hdmi->fbi->monspecs.modedb_len; i++) {
+ /*
+ * We might check here if mode is supported by HDMI.
+ * We do not currently support interlaced modes.
+ * And add CEA modes in the modelist.
+ */
+ mode = &hdmi->fbi->monspecs.modedb[i];
+
+ if (!(mode->vmode & FB_VMODE_INTERLACED) &&
+ (mxc_edid_mode_to_vic(mode) != 0)) {
+
+ dev_dbg(&hdmi->pdev->dev, "Added mode %d:", i);
+ dev_dbg(&hdmi->pdev->dev,
+ "xres = %d, yres = %d, freq = %d, vmode = %d, flag = %d\n",
+ hdmi->fbi->monspecs.modedb[i].xres,
+ hdmi->fbi->monspecs.modedb[i].yres,
+ hdmi->fbi->monspecs.modedb[i].refresh,
+ hdmi->fbi->monspecs.modedb[i].vmode,
+ hdmi->fbi->monspecs.modedb[i].flag);
+
+ fb_add_videomode(mode, &hdmi->fbi->modelist);
+ }
+ }
+
+ fb_new_modelist(hdmi->fbi);
+
+ console_unlock();
+}
+
+static void mxc_hdmi_default_edid_cfg(struct mxc_hdmi *hdmi)
+{
+ /* Default setting HDMI working in HDMI mode */
+ hdmi->edid_cfg.hdmi_cap = true;
+}
+
+static void mxc_hdmi_default_modelist(struct mxc_hdmi *hdmi)
+{
+ struct fb_modelist *modelist;
+ struct fb_videomode *m;
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ /* If no EDID data read, set up default modelist; since we don't know
+ * the supported modes of the current sink, we will use only one mode in
+ * this modelist:
+ * the default_mode set up at init (usually got from cmdline)
+ */
+ dev_info(&hdmi->pdev->dev, "create default modelist\n");
+
+ /* If the current modelist is already default, don't re-create it*/
+ if (list_is_singular(&hdmi->fbi->modelist)) {
+ modelist = list_entry((&hdmi->fbi->modelist)->next,
+ struct fb_modelist, list);
+ m = &modelist->mode;
+ if (fb_mode_is_equal(m, &hdmi->default_mode)) {
+ dev_info(&hdmi->pdev->dev,
+ "Modelist is already default, no need to re-create!\n");
+ return;
+ }
+
+ }
+
+ console_lock();
+ fb_destroy_modelist(&hdmi->fbi->modelist);
+ fb_add_videomode(&hdmi->default_mode, &hdmi->fbi->modelist);
+ fb_new_modelist(hdmi->fbi);
+ console_unlock();
+}
+
+static void mxc_hdmi_set_mode_to_vga_dvi(struct mxc_hdmi *hdmi)
+{
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ hdmi_disable_overflow_interrupts();
+
+ fb_videomode_to_var(&hdmi->fbi->var, &vga_mode);
+
+ hdmi->requesting_vga_for_initialization = true;
+ mxc_hdmi_notify_fb(hdmi);
+ hdmi->requesting_vga_for_initialization = false;
+}
+
+static void mxc_hdmi_set_mode(struct mxc_hdmi *hdmi)
+{
+ const struct fb_videomode *mode;
+ struct fb_videomode m;
+ struct fb_var_screeninfo var;
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ /* Set the default mode only once. */
+ if (!hdmi->dft_mode_set) {
+ fb_videomode_to_var(&var, &hdmi->default_mode);
+ hdmi->dft_mode_set = true;
+ } else
+ fb_videomode_to_var(&var, &hdmi->previous_non_vga_mode);
+
+ fb_var_to_videomode(&m, &var);
+ dump_fb_videomode(&m);
+
+ mode = fb_find_nearest_mode(&m, &hdmi->fbi->modelist);
+ if (!mode) {
+ pr_err("%s: could not find mode in modelist\n", __func__);
+ return;
+ }
+
+ /* If both video mode and work mode same as previous,
+ * init HDMI again */
+ if (fb_mode_is_equal(&hdmi->previous_non_vga_mode, mode) &&
+ (hdmi->edid_cfg.hdmi_cap != hdmi->hdmi_data.video_mode.mDVI)) {
+ dev_dbg(&hdmi->pdev->dev,
+ "%s: Video mode same as previous\n", __func__);
+ /* update fbi mode in case modelist is updated */
+ hdmi->fbi->mode = (struct fb_videomode *)mode;
+ fb_videomode_to_var(&hdmi->fbi->var, mode);
+ /* update hdmi setting in case EDID data updated */
+ mxc_hdmi_setup(hdmi, 0);
+ } else {
+ dev_dbg(&hdmi->pdev->dev, "%s: New video mode\n", __func__);
+ mxc_hdmi_set_mode_to_vga_dvi(hdmi);
+ fb_videomode_to_var(&hdmi->fbi->var, mode);
+ dump_fb_videomode((struct fb_videomode *)mode);
+ mxc_hdmi_notify_fb(hdmi);
+ }
+
+}
+
+static void mxc_hdmi_cable_connected(struct mxc_hdmi *hdmi)
+{
+ int edid_status;
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ hdmi->cable_plugin = true;
+
+ /* HDMI Initialization Step C */
+ edid_status = mxc_hdmi_read_edid(hdmi);
+
+ /* Read EDID again if first EDID read failed */
+ if (edid_status == HDMI_EDID_NO_MODES ||
+ edid_status == HDMI_EDID_FAIL) {
+ int retry_status;
+ dev_info(&hdmi->pdev->dev, "Read EDID again\n");
+ msleep(200);
+ retry_status = mxc_hdmi_read_edid(hdmi);
+ /* If we get NO_MODES on the 1st and SAME on the 2nd attempt we
+ * want NO_MODES as final result. */
+ if (retry_status != HDMI_EDID_SAME)
+ edid_status = retry_status;
+ }
+
+ /* HDMI Initialization Steps D, E, F */
+ switch (edid_status) {
+ case HDMI_EDID_SUCCESS:
+ mxc_hdmi_edid_rebuild_modelist(hdmi);
+ break;
+
+ /* Nothing to do if EDID same */
+ case HDMI_EDID_SAME:
+ break;
+
+ case HDMI_EDID_FAIL:
+ mxc_hdmi_default_edid_cfg(hdmi);
+ /* No break here */
+ case HDMI_EDID_NO_MODES:
+ default:
+ mxc_hdmi_default_modelist(hdmi);
+ break;
+ }
+
+ /* Setting video mode */
+ mxc_hdmi_set_mode(hdmi);
+
+ dev_dbg(&hdmi->pdev->dev, "%s exit\n", __func__);
+}
+
+static int mxc_hdmi_power_on(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
+{
+ struct mxc_hdmi *hdmi = mxc_dispdrv_getdata(disp);
+ mxc_hdmi_phy_init(hdmi);
+ return 0;
+}
+
+static void mxc_hdmi_power_off(struct mxc_dispdrv_handle *disp,
+ struct fb_info *fbi)
+{
+ struct mxc_hdmi *hdmi = mxc_dispdrv_getdata(disp);
+ mxc_hdmi_phy_disable(hdmi);
+}
+
+static void mxc_hdmi_cable_disconnected(struct mxc_hdmi *hdmi)
+{
+ u8 clkdis;
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+ /* Disable All HDMI clock and bypass cec */
+ clkdis = hdmi_readb(HDMI_MC_CLKDIS);
+ clkdis |= 0x5f;
+ hdmi_writeb(clkdis, HDMI_MC_CLKDIS);
+
+ mxc_hdmi_phy_disable(hdmi);
+
+ hdmi_disable_overflow_interrupts();
+
+ hdmi->cable_plugin = false;
+}
+
+static void hotplug_worker(struct work_struct *work)
+{
+ struct delayed_work *delay_work = to_delayed_work(work);
+ struct mxc_hdmi *hdmi =
+ container_of(delay_work, struct mxc_hdmi, hotplug_work);
+ u32 phy_int_stat, phy_int_pol, phy_int_mask;
+ u8 val;
+ unsigned long flags;
+ char event_string[32];
+ char *envp[] = { event_string, NULL };
+
+ phy_int_stat = hdmi->latest_intr_stat;
+ phy_int_pol = hdmi_readb(HDMI_PHY_POL0);
+
+ dev_dbg(&hdmi->pdev->dev, "phy_int_stat=0x%x, phy_int_pol=0x%x\n",
+ phy_int_stat, phy_int_pol);
+
+ /* check cable status */
+ if (phy_int_stat & HDMI_IH_PHY_STAT0_HPD) {
+ /* cable connection changes */
+ if (phy_int_pol & HDMI_PHY_HPD) {
+ /* Plugin event */
+ dev_dbg(&hdmi->pdev->dev, "EVENT=plugin\n");
+ mxc_hdmi_cable_connected(hdmi);
+
+ /* Make HPD intr active low to capture unplug event */
+ val = hdmi_readb(HDMI_PHY_POL0);
+ val &= ~HDMI_PHY_HPD;
+ hdmi_writeb(val, HDMI_PHY_POL0);
+
+ hdmi_set_cable_state(1);
+
+ sprintf(event_string, "EVENT=plugin");
+ kobject_uevent_env(&hdmi->pdev->dev.kobj, KOBJ_CHANGE, envp);
+#ifdef CONFIG_MXC_HDMI_CEC
+ mxc_hdmi_cec_handle(0x80);
+#endif
+ } else if (!(phy_int_pol & HDMI_PHY_HPD)) {
+ /* Plugout event */
+ dev_dbg(&hdmi->pdev->dev, "EVENT=plugout\n");
+ hdmi_set_cable_state(0);
+ mxc_hdmi_abort_stream();
+ mxc_hdmi_cable_disconnected(hdmi);
+
+ /* Make HPD intr active high to capture plugin event */
+ val = hdmi_readb(HDMI_PHY_POL0);
+ val |= HDMI_PHY_HPD;
+ hdmi_writeb(val, HDMI_PHY_POL0);
+
+ sprintf(event_string, "EVENT=plugout");
+ kobject_uevent_env(&hdmi->pdev->dev.kobj, KOBJ_CHANGE, envp);
+#ifdef CONFIG_MXC_HDMI_CEC
+ mxc_hdmi_cec_handle(0x100);
+#endif
+
+ } else
+ dev_dbg(&hdmi->pdev->dev, "EVENT=none?\n");
+ }
+
+ /* Lock here to ensure full powerdown sequence
+ * completed before next interrupt processed */
+ spin_lock_irqsave(&hdmi->irq_lock, flags);
+
+ /* Re-enable HPD interrupts */
+ phy_int_mask = hdmi_readb(HDMI_PHY_MASK0);
+ phy_int_mask &= ~HDMI_PHY_HPD;
+ hdmi_writeb(phy_int_mask, HDMI_PHY_MASK0);
+
+ /* Unmute interrupts */
+ hdmi_writeb(~HDMI_IH_MUTE_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
+
+ if (hdmi_readb(HDMI_IH_FC_STAT2) & HDMI_IH_FC_STAT2_OVERFLOW_MASK)
+ mxc_hdmi_clear_overflow(hdmi);
+
+ spin_unlock_irqrestore(&hdmi->irq_lock, flags);
+}
+
+static void hdcp_hdp_worker(struct work_struct *work)
+{
+ struct delayed_work *delay_work = to_delayed_work(work);
+ struct mxc_hdmi *hdmi =
+ container_of(delay_work, struct mxc_hdmi, hdcp_hdp_work);
+ char event_string[32];
+ char *envp[] = { event_string, NULL };
+
+ /* HDCP interrupt */
+ sprintf(event_string, "EVENT=hdcpint");
+ kobject_uevent_env(&hdmi->pdev->dev.kobj, KOBJ_CHANGE, envp);
+
+ /* Unmute interrupts in HDCP application*/
+}
+
+static irqreturn_t mxc_hdmi_hotplug(int irq, void *data)
+{
+ struct mxc_hdmi *hdmi = data;
+ u8 val, intr_stat;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hdmi->irq_lock, flags);
+
+ /* Check and clean packet overflow interrupt.*/
+ if (hdmi_readb(HDMI_IH_FC_STAT2) &
+ HDMI_IH_FC_STAT2_OVERFLOW_MASK) {
+ mxc_hdmi_clear_overflow(hdmi);
+
+ dev_dbg(&hdmi->pdev->dev, "Overflow interrupt received\n");
+ /* clear irq status */
+ hdmi_writeb(HDMI_IH_FC_STAT2_OVERFLOW_MASK,
+ HDMI_IH_FC_STAT2);
+ }
+
+ /*
+ * We could not disable the irq. Probably the audio driver
+ * has enabled it. Masking off the HDMI interrupts using
+ * HDMI registers.
+ */
+ /* Capture status - used in hotplug_worker ISR */
+ intr_stat = hdmi_readb(HDMI_IH_PHY_STAT0);
+
+ if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
+
+ dev_dbg(&hdmi->pdev->dev, "Hotplug interrupt received\n");
+ hdmi->latest_intr_stat = intr_stat;
+
+ /* Mute interrupts until handled */
+
+ val = hdmi_readb(HDMI_IH_MUTE_PHY_STAT0);
+ val |= HDMI_IH_MUTE_PHY_STAT0_HPD;
+ hdmi_writeb(val, HDMI_IH_MUTE_PHY_STAT0);
+
+ val = hdmi_readb(HDMI_PHY_MASK0);
+ val |= HDMI_PHY_HPD;
+ hdmi_writeb(val, HDMI_PHY_MASK0);
+
+ /* Clear Hotplug interrupts */
+ hdmi_writeb(HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
+
+ schedule_delayed_work(&(hdmi->hotplug_work), msecs_to_jiffies(20));
+ }
+
+ /* Check HDCP interrupt state */
+ if (hdmi->hdmi_data.hdcp_enable) {
+ val = hdmi_readb(HDMI_A_APIINTSTAT);
+ if (val != 0) {
+ /* Mute interrupts until interrupt handled */
+ val = 0xFF;
+ hdmi_writeb(val, HDMI_A_APIINTMSK);
+ schedule_delayed_work(&(hdmi->hdcp_hdp_work), msecs_to_jiffies(50));
+ }
+ }
+
+ spin_unlock_irqrestore(&hdmi->irq_lock, flags);
+ return IRQ_HANDLED;
+}
+
+static void mxc_hdmi_setup(struct mxc_hdmi *hdmi, unsigned long event)
+{
+ struct fb_videomode m;
+ const struct fb_videomode *edid_mode;
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ fb_var_to_videomode(&m, &hdmi->fbi->var);
+ dump_fb_videomode(&m);
+
+ dev_dbg(&hdmi->pdev->dev, "%s - video mode changed\n", __func__);
+
+ hdmi->vic = 0;
+ if (!hdmi->requesting_vga_for_initialization) {
+ /* Save mode if this isn't the result of requesting
+ * vga default. */
+ memcpy(&hdmi->previous_non_vga_mode, &m,
+ sizeof(struct fb_videomode));
+ if (!list_empty(&hdmi->fbi->modelist)) {
+ edid_mode = fb_find_nearest_mode(&m, &hdmi->fbi->modelist);
+ pr_debug("edid mode ");
+ dump_fb_videomode((struct fb_videomode *)edid_mode);
+ /* update fbi mode */
+ hdmi->fbi->mode = (struct fb_videomode *)edid_mode;
+ hdmi->vic = mxc_edid_mode_to_vic(edid_mode);
+ }
+ }
+
+ hdmi_disable_overflow_interrupts();
+
+ dev_dbg(&hdmi->pdev->dev, "CEA mode used vic=%d\n", hdmi->vic);
+ if (hdmi->edid_cfg.hdmi_cap)
+ hdmi->hdmi_data.video_mode.mDVI = false;
+ else {
+ dev_dbg(&hdmi->pdev->dev, "CEA mode vic=%d work in DVI\n", hdmi->vic);
+ hdmi->hdmi_data.video_mode.mDVI = true;
+ }
+
+ if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
+ (hdmi->vic == 21) || (hdmi->vic == 22) ||
+ (hdmi->vic == 2) || (hdmi->vic == 3) ||
+ (hdmi->vic == 17) || (hdmi->vic == 18))
+ hdmi->hdmi_data.colorimetry = eITU601;
+ else
+ hdmi->hdmi_data.colorimetry = eITU709;
+
+ if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
+ (hdmi->vic == 12) || (hdmi->vic == 13) ||
+ (hdmi->vic == 14) || (hdmi->vic == 15) ||
+ (hdmi->vic == 25) || (hdmi->vic == 26) ||
+ (hdmi->vic == 27) || (hdmi->vic == 28) ||
+ (hdmi->vic == 29) || (hdmi->vic == 30) ||
+ (hdmi->vic == 35) || (hdmi->vic == 36) ||
+ (hdmi->vic == 37) || (hdmi->vic == 38))
+ hdmi->hdmi_data.video_mode.mPixelRepetitionOutput = 1;
+ else
+ hdmi->hdmi_data.video_mode.mPixelRepetitionOutput = 0;
+
+ hdmi->hdmi_data.video_mode.mPixelRepetitionInput = 0;
+
+ /* TODO: Get input format from IPU (via FB driver iface) */
+ hdmi->hdmi_data.enc_in_format = RGB;
+
+ hdmi->hdmi_data.enc_out_format = RGB;
+
+ /* YCbCr only enabled in HDMI mode */
+ if (!hdmi->hdmi_data.video_mode.mDVI &&
+ !hdmi->hdmi_data.rgb_out_enable) {
+ if (hdmi->edid_cfg.cea_ycbcr444)
+ hdmi->hdmi_data.enc_out_format = YCBCR444;
+ else if (hdmi->edid_cfg.cea_ycbcr422)
+ hdmi->hdmi_data.enc_out_format = YCBCR422_8BITS;
+ }
+
+ /* IPU not support depth color output */
+ hdmi->hdmi_data.enc_color_depth = 8;
+ hdmi->hdmi_data.pix_repet_factor = 0;
+ hdmi->hdmi_data.video_mode.mDataEnablePolarity = true;
+
+ /* HDMI Initialization Step B.1 */
+ hdmi_av_composer(hdmi);
+
+ /* HDMI Initializateion Step B.2 */
+ mxc_hdmi_phy_init(hdmi);
+
+ /* HDMI Initialization Step B.3 */
+ mxc_hdmi_enable_video_path(hdmi);
+
+ /* not for DVI mode */
+ if (hdmi->hdmi_data.video_mode.mDVI)
+ dev_dbg(&hdmi->pdev->dev, "%s DVI mode\n", __func__);
+ else {
+ dev_dbg(&hdmi->pdev->dev, "%s CEA mode\n", __func__);
+
+ /* HDMI Initialization Step E - Configure audio */
+ hdmi_clk_regenerator_update_pixel_clock(hdmi->fbi->var.pixclock);
+ hdmi_enable_audio_clk(hdmi);
+
+ /* HDMI Initialization Step F - Configure AVI InfoFrame */
+ hdmi_config_AVI(hdmi);
+ }
+
+ hdmi_video_packetize(hdmi);
+ hdmi_video_csc(hdmi);
+ hdmi_video_sample(hdmi);
+
+ mxc_hdmi_clear_overflow(hdmi);
+
+ dev_dbg(&hdmi->pdev->dev, "%s exit\n\n", __func__);
+
+}
+
+/* Wait until we are registered to enable interrupts */
+static void mxc_hdmi_fb_registered(struct mxc_hdmi *hdmi)
+{
+ unsigned long flags;
+
+ if (hdmi->fb_reg)
+ return;
+
+ spin_lock_irqsave(&hdmi->irq_lock, flags);
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ hdmi_writeb(HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
+ HDMI_PHY_I2CM_INT_ADDR);
+
+ hdmi_writeb(HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
+ HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
+ HDMI_PHY_I2CM_CTLINT_ADDR);
+
+ /* enable cable hot plug irq */
+ hdmi_writeb((u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0);
+
+ /* Clear Hotplug interrupts */
+ hdmi_writeb(HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
+
+ /* Unmute interrupts */
+ hdmi_writeb(~HDMI_IH_MUTE_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
+
+ hdmi->fb_reg = true;
+
+ spin_unlock_irqrestore(&hdmi->irq_lock, flags);
+
+}
+
+static int mxc_hdmi_fb_event(struct notifier_block *nb,
+ unsigned long val, void *v)
+{
+ struct fb_event *event = v;
+ struct mxc_hdmi *hdmi = container_of(nb, struct mxc_hdmi, nb);
+
+ if (strcmp(event->info->fix.id, hdmi->fbi->fix.id))
+ return 0;
+
+ switch (val) {
+ case FB_EVENT_FB_REGISTERED:
+ dev_dbg(&hdmi->pdev->dev, "event=FB_EVENT_FB_REGISTERED\n");
+ mxc_hdmi_fb_registered(hdmi);
+ hdmi_set_registered(1);
+ break;
+
+ case FB_EVENT_FB_UNREGISTERED:
+ dev_dbg(&hdmi->pdev->dev, "event=FB_EVENT_FB_UNREGISTERED\n");
+ hdmi->fb_reg = false;
+ hdmi_set_registered(0);
+ break;
+
+ case FB_EVENT_MODE_CHANGE:
+ dev_dbg(&hdmi->pdev->dev, "event=FB_EVENT_MODE_CHANGE\n");
+ if (hdmi->fb_reg)
+ mxc_hdmi_setup(hdmi, val);
+ break;
+
+ case FB_EVENT_BLANK:
+ if ((*((int *)event->data) == FB_BLANK_UNBLANK) &&
+ (*((int *)event->data) != hdmi->blank)) {
+ dev_dbg(&hdmi->pdev->dev,
+ "event=FB_EVENT_BLANK - UNBLANK\n");
+
+ hdmi->blank = *((int *)event->data);
+
+ if (hdmi->fb_reg && hdmi->cable_plugin)
+ mxc_hdmi_setup(hdmi, val);
+ hdmi_set_blank_state(1);
+
+ } else if (*((int *)event->data) != hdmi->blank) {
+ dev_dbg(&hdmi->pdev->dev,
+ "event=FB_EVENT_BLANK - BLANK\n");
+ hdmi_set_blank_state(0);
+ mxc_hdmi_abort_stream();
+
+ mxc_hdmi_phy_disable(hdmi);
+
+ hdmi->blank = *((int *)event->data);
+ } else
+ dev_dbg(&hdmi->pdev->dev,
+ "FB BLANK state no changed!\n");
+
+ break;
+
+ case FB_EVENT_SUSPEND:
+ dev_dbg(&hdmi->pdev->dev,
+ "event=FB_EVENT_SUSPEND\n");
+
+ if (hdmi->blank == FB_BLANK_UNBLANK) {
+ mxc_hdmi_phy_disable(hdmi);
+ clk_disable(hdmi->hdmi_iahb_clk);
+ clk_disable(hdmi->hdmi_isfr_clk);
+ clk_disable(hdmi->mipi_core_clk);
+ }
+ break;
+
+ case FB_EVENT_RESUME:
+ dev_dbg(&hdmi->pdev->dev,
+ "event=FB_EVENT_RESUME\n");
+
+ if (hdmi->blank == FB_BLANK_UNBLANK) {
+ clk_enable(hdmi->mipi_core_clk);
+ clk_enable(hdmi->hdmi_iahb_clk);
+ clk_enable(hdmi->hdmi_isfr_clk);
+ mxc_hdmi_phy_init(hdmi);
+ }
+ break;
+
+ }
+ return 0;
+}
+
+static void hdmi_init_route(struct mxc_hdmi *hdmi)
+{
+ uint32_t hdmi_mux_setting, reg;
+ int ipu_id, disp_id;
+
+ ipu_id = mxc_hdmi_ipu_id;
+ disp_id = mxc_hdmi_disp_id;
+
+ if ((ipu_id > 1) || (ipu_id < 0)) {
+ pr_err("Invalid IPU select for HDMI: %d. Set to 0\n", ipu_id);
+ ipu_id = 0;
+ }
+
+ if ((disp_id > 1) || (disp_id < 0)) {
+ pr_err("Invalid DI select for HDMI: %d. Set to 0\n", disp_id);
+ disp_id = 0;
+ }
+
+ reg = readl(hdmi->gpr_hdmi_base);
+
+ /* Configure the connection between IPU1/2 and HDMI */
+ hdmi_mux_setting = 2*ipu_id + disp_id;
+
+ /* GPR3, bits 2-3 = HDMI_MUX_CTL */
+ reg &= ~0xd;
+ reg |= hdmi_mux_setting << 2;
+
+ writel(reg, hdmi->gpr_hdmi_base);
+
+ /* Set HDMI event as SDMA event2 for HDMI audio */
+ reg = readl(hdmi->gpr_sdma_base);
+ reg |= 0x1;
+ writel(reg, hdmi->gpr_sdma_base);
+}
+
+static void hdmi_hdcp_get_property(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+
+ /* Check hdcp enable by dts.*/
+ hdcp_init = of_property_read_bool(np, "fsl,hdcp");
+ if (hdcp_init)
+ dev_dbg(&pdev->dev, "hdcp enable\n");
+ else
+ dev_dbg(&pdev->dev, "hdcp disable\n");
+}
+
+static void hdmi_get_of_property(struct mxc_hdmi *hdmi)
+{
+ struct platform_device *pdev = hdmi->pdev;
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *of_id =
+ of_match_device(imx_hdmi_dt_ids, &pdev->dev);
+ int ret;
+ u32 phy_reg_vlev = 0, phy_reg_cksymtx = 0;
+
+ if (of_id) {
+ pdev->id_entry = of_id->data;
+ hdmi->cpu_type = pdev->id_entry->driver_data;
+ }
+
+ /* HDMI PHY register vlev and cksymtx preperty is optional.
+ * It is for specific board to pass HCT electrical part.
+ * Default value will been setting in HDMI PHY config function
+ * if it is not define in device tree.
+ */
+ ret = of_property_read_u32(np, "fsl,phy_reg_vlev", &phy_reg_vlev);
+ if (ret)
+ dev_dbg(&pdev->dev, "No board specific HDMI PHY vlev\n");
+
+ ret = of_property_read_u32(np, "fsl,phy_reg_cksymtx", &phy_reg_cksymtx);
+ if (ret)
+ dev_dbg(&pdev->dev, "No board specific HDMI PHY cksymtx\n");
+
+ /* Specific phy config */
+ hdmi->phy_config.reg_cksymtx = phy_reg_cksymtx;
+ hdmi->phy_config.reg_vlev = phy_reg_vlev;
+
+}
+
+/* HDMI Initialization Step A */
+static int mxc_hdmi_disp_init(struct mxc_dispdrv_handle *disp,
+ struct mxc_dispdrv_setting *setting)
+{
+ int ret = 0;
+ u32 i;
+ const struct fb_videomode *mode;
+ struct fb_videomode m;
+ struct mxc_hdmi *hdmi = mxc_dispdrv_getdata(disp);
+ int irq = platform_get_irq(hdmi->pdev, 0);
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ /* Check hdmi disp init once */
+ if (hdmi_inited) {
+ dev_err(&hdmi->pdev->dev,
+ "Error only one HDMI output support now!\n");
+ return -1;
+ }
+
+ hdmi_get_of_property(hdmi);
+
+ if (irq < 0)
+ return -ENODEV;
+
+ /* Setting HDMI default to blank state */
+ hdmi->blank = FB_BLANK_POWERDOWN;
+
+ ret = ipu_di_to_crtc(&hdmi->pdev->dev, mxc_hdmi_ipu_id,
+ mxc_hdmi_disp_id, &setting->crtc);
+ if (ret < 0)
+ return ret;
+
+ setting->if_fmt = IPU_PIX_FMT_RGB24;
+
+ hdmi->dft_mode_str = setting->dft_mode_str;
+ hdmi->default_bpp = setting->default_bpp;
+ dev_dbg(&hdmi->pdev->dev, "%s - default mode %s bpp=%d\n",
+ __func__, hdmi->dft_mode_str, hdmi->default_bpp);
+
+ hdmi->fbi = setting->fbi;
+
+ hdmi_init_route(hdmi);
+
+ hdmi->mipi_core_clk = clk_get(&hdmi->pdev->dev, "mipi_core");
+ if (IS_ERR(hdmi->mipi_core_clk)) {
+ ret = PTR_ERR(hdmi->mipi_core_clk);
+ dev_err(&hdmi->pdev->dev,
+ "Unable to get mipi core clk: %d\n", ret);
+ goto egetclk;
+ }
+
+ ret = clk_prepare_enable(hdmi->mipi_core_clk);
+ if (ret < 0) {
+ dev_err(&hdmi->pdev->dev,
+ "Cannot enable mipi core clock: %d\n", ret);
+ goto erate;
+ }
+
+ hdmi->hdmi_isfr_clk = clk_get(&hdmi->pdev->dev, "hdmi_isfr");
+ if (IS_ERR(hdmi->hdmi_isfr_clk)) {
+ ret = PTR_ERR(hdmi->hdmi_isfr_clk);
+ dev_err(&hdmi->pdev->dev,
+ "Unable to get HDMI clk: %d\n", ret);
+ goto egetclk1;
+ }
+
+ ret = clk_prepare_enable(hdmi->hdmi_isfr_clk);
+ if (ret < 0) {
+ dev_err(&hdmi->pdev->dev,
+ "Cannot enable HDMI isfr clock: %d\n", ret);
+ goto erate1;
+ }
+
+ hdmi->hdmi_iahb_clk = clk_get(&hdmi->pdev->dev, "hdmi_iahb");
+ if (IS_ERR(hdmi->hdmi_iahb_clk)) {
+ ret = PTR_ERR(hdmi->hdmi_iahb_clk);
+ dev_err(&hdmi->pdev->dev,
+ "Unable to get HDMI clk: %d\n", ret);
+ goto egetclk2;
+ }
+
+ ret = clk_prepare_enable(hdmi->hdmi_iahb_clk);
+ if (ret < 0) {
+ dev_err(&hdmi->pdev->dev,
+ "Cannot enable HDMI iahb clock: %d\n", ret);
+ goto erate2;
+ }
+
+ dev_dbg(&hdmi->pdev->dev, "Enabled HDMI clocks\n");
+
+ /* Init DDC pins for HDCP */
+ if (hdcp_init) {
+ hdmi->pinctrl = devm_pinctrl_get_select_default(&hdmi->pdev->dev);
+ if (IS_ERR(hdmi->pinctrl)) {
+ dev_err(&hdmi->pdev->dev, "can't get/select DDC pinctrl\n");
+ goto erate2;
+ }
+ }
+
+ /* Product and revision IDs */
+ dev_info(&hdmi->pdev->dev,
+ "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
+ hdmi_readb(HDMI_DESIGN_ID),
+ hdmi_readb(HDMI_REVISION_ID),
+ hdmi_readb(HDMI_PRODUCT_ID0),
+ hdmi_readb(HDMI_PRODUCT_ID1));
+
+ /* To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator
+ * N and cts values before enabling phy */
+ hdmi_init_clk_regenerator();
+
+ INIT_LIST_HEAD(&hdmi->fbi->modelist);
+
+ spin_lock_init(&hdmi->irq_lock);
+
+ /* Set the default mode and modelist when disp init. */
+ fb_find_mode(&hdmi->fbi->var, hdmi->fbi,
+ hdmi->dft_mode_str, NULL, 0, NULL,
+ hdmi->default_bpp);
+
+ console_lock();
+
+ fb_destroy_modelist(&hdmi->fbi->modelist);
+
+ /*Add all no interlaced CEA mode to default modelist */
+ for (i = 0; i < ARRAY_SIZE(mxc_cea_mode); i++) {
+ mode = &mxc_cea_mode[i];
+ if (!(mode->vmode & FB_VMODE_INTERLACED) && (mode->xres != 0))
+ fb_add_videomode(mode, &hdmi->fbi->modelist);
+ }
+
+ console_unlock();
+
+ /* Find a nearest mode in default modelist */
+ fb_var_to_videomode(&m, &hdmi->fbi->var);
+
+ hdmi->dft_mode_set = false;
+ mode = fb_find_nearest_mode(&m, &hdmi->fbi->modelist);
+ if (!mode) {
+ pr_err("%s: could not find mode in modelist\n", __func__);
+ return -1;
+ }
+ dump_fb_videomode(mode);
+ /* Save default video mode */
+ memcpy(&hdmi->default_mode, mode, sizeof(struct fb_videomode));
+
+ fb_videomode_to_var(&hdmi->fbi->var, mode);
+
+ /* update fbi mode */
+ hdmi->fbi->mode = (struct fb_videomode *)mode;
+
+ /* Default setting HDMI working in HDMI mode*/
+ hdmi->edid_cfg.hdmi_cap = true;
+
+ INIT_DELAYED_WORK(&hdmi->hotplug_work, hotplug_worker);
+ INIT_DELAYED_WORK(&hdmi->hdcp_hdp_work, hdcp_hdp_worker);
+
+ /* Configure registers related to HDMI interrupt
+ * generation before registering IRQ. */
+ hdmi_writeb(HDMI_PHY_HPD, HDMI_PHY_POL0);
+
+ /* Clear Hotplug interrupts */
+ hdmi_writeb(HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
+
+ hdmi->nb.notifier_call = mxc_hdmi_fb_event;
+ ret = fb_register_client(&hdmi->nb);
+ if (ret < 0)
+ goto efbclient;
+
+ memset(&hdmi->hdmi_data, 0, sizeof(struct hdmi_data_info));
+
+ /* Default HDMI working in RGB mode */
+ hdmi->hdmi_data.rgb_out_enable = true;
+
+ ret = devm_request_irq(&hdmi->pdev->dev, irq, mxc_hdmi_hotplug, IRQF_SHARED,
+ dev_name(&hdmi->pdev->dev), hdmi);
+ if (ret < 0) {
+ dev_err(&hdmi->pdev->dev,
+ "Unable to request irq: %d\n", ret);
+ goto ereqirq;
+ }
+
+ ret = device_create_file(&hdmi->pdev->dev, &dev_attr_fb_name);
+ if (ret < 0)
+ dev_warn(&hdmi->pdev->dev,
+ "cound not create sys node for fb name\n");
+ ret = device_create_file(&hdmi->pdev->dev, &dev_attr_cable_state);
+ if (ret < 0)
+ dev_warn(&hdmi->pdev->dev,
+ "cound not create sys node for cable state\n");
+ ret = device_create_file(&hdmi->pdev->dev, &dev_attr_edid);
+ if (ret < 0)
+ dev_warn(&hdmi->pdev->dev,
+ "cound not create sys node for edid\n");
+
+ ret = device_create_file(&hdmi->pdev->dev, &dev_attr_rgb_out_enable);
+ if (ret < 0)
+ dev_warn(&hdmi->pdev->dev,
+ "cound not create sys node for rgb out enable\n");
+
+ ret = device_create_file(&hdmi->pdev->dev, &dev_attr_hdcp_enable);
+ if (ret < 0)
+ dev_warn(&hdmi->pdev->dev,
+ "cound not create sys node for hdcp enable\n");
+
+ dev_dbg(&hdmi->pdev->dev, "%s exit\n", __func__);
+
+ hdmi_inited = true;
+
+ return ret;
+
+efbclient:
+ free_irq(irq, hdmi);
+ereqirq:
+ clk_disable_unprepare(hdmi->hdmi_iahb_clk);
+erate2:
+ clk_put(hdmi->hdmi_iahb_clk);
+egetclk2:
+ clk_disable_unprepare(hdmi->hdmi_isfr_clk);
+erate1:
+ clk_put(hdmi->hdmi_isfr_clk);
+egetclk1:
+ clk_disable_unprepare(hdmi->mipi_core_clk);
+erate:
+ clk_put(hdmi->mipi_core_clk);
+egetclk:
+ dev_dbg(&hdmi->pdev->dev, "%s error exit\n", __func__);
+
+ return ret;
+}
+
+static void mxc_hdmi_disp_deinit(struct mxc_dispdrv_handle *disp)
+{
+ struct mxc_hdmi *hdmi = mxc_dispdrv_getdata(disp);
+
+ dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);
+
+ fb_unregister_client(&hdmi->nb);
+
+ clk_disable_unprepare(hdmi->hdmi_isfr_clk);
+ clk_put(hdmi->hdmi_isfr_clk);
+ clk_disable_unprepare(hdmi->hdmi_iahb_clk);
+ clk_put(hdmi->hdmi_iahb_clk);
+ clk_disable_unprepare(hdmi->mipi_core_clk);
+ clk_put(hdmi->mipi_core_clk);
+
+ platform_device_unregister(hdmi->pdev);
+
+ hdmi_inited = false;
+}
+
+static struct mxc_dispdrv_driver mxc_hdmi_drv = {
+ .name = DISPDRV_HDMI,
+ .init = mxc_hdmi_disp_init,
+ .deinit = mxc_hdmi_disp_deinit,
+ .enable = mxc_hdmi_power_on,
+ .disable = mxc_hdmi_power_off,
+};
+
+
+static int mxc_hdmi_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static long mxc_hdmi_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int __user *argp = (void __user *)arg;
+ int ret = 0;
+
+ switch (cmd) {
+ case HDMI_IOC_GET_RESOURCE:
+ ret = copy_to_user(argp, &g_hdmi->hdmi_data,
+ sizeof(g_hdmi->hdmi_data)) ? -EFAULT : 0;
+ break;
+ case HDMI_IOC_GET_CPU_TYPE:
+ ret = put_user(g_hdmi->cpu_type, argp);
+ break;
+ default:
+ pr_debug("Unsupport cmd %d\n", cmd);
+ break;
+ }
+
+ return ret;
+}
+
+static int mxc_hdmi_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static const struct file_operations mxc_hdmi_fops = {
+ .owner = THIS_MODULE,
+ .open = mxc_hdmi_open,
+ .release = mxc_hdmi_release,
+ .unlocked_ioctl = mxc_hdmi_ioctl,
+};
+
+
+static int mxc_hdmi_probe(struct platform_device *pdev)
+{
+ struct mxc_hdmi *hdmi;
+ struct device *temp_class;
+ struct resource *res;
+ int ret = 0;
+
+ /* Check I2C driver is loaded and available
+ * check hdcp function is enable by dts */
+ hdmi_hdcp_get_property(pdev);
+ if (!hdmi_i2c && !hdcp_init)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOENT;
+
+ hdmi = devm_kzalloc(&pdev->dev,
+ sizeof(struct mxc_hdmi),
+ GFP_KERNEL);
+ if (!hdmi) {
+ dev_err(&pdev->dev, "Cannot allocate device data\n");
+ ret = -ENOMEM;
+ goto ealloc;
+ }
+ g_hdmi = hdmi;
+
+ hdmi_major = register_chrdev(hdmi_major, "mxc_hdmi", &mxc_hdmi_fops);
+ if (hdmi_major < 0) {
+ printk(KERN_ERR "HDMI: unable to get a major for HDMI\n");
+ ret = -EBUSY;
+ goto ealloc;
+ }
+
+ hdmi_class = class_create(THIS_MODULE, "mxc_hdmi");
+ if (IS_ERR(hdmi_class)) {
+ ret = PTR_ERR(hdmi_class);
+ goto err_out_chrdev;
+ }
+
+ temp_class = device_create(hdmi_class, NULL, MKDEV(hdmi_major, 0),
+ NULL, "mxc_hdmi");
+ if (IS_ERR(temp_class)) {
+ ret = PTR_ERR(temp_class);
+ goto err_out_class;
+ }
+
+ hdmi->pdev = pdev;
+
+ hdmi->core_pdev = platform_device_alloc("mxc_hdmi_core", -1);
+ if (!hdmi->core_pdev) {
+ pr_err("%s failed platform_device_alloc for hdmi core\n",
+ __func__);
+ ret = -ENOMEM;
+ goto ecore;
+ }
+
+ hdmi->gpr_base = ioremap(res->start, resource_size(res));
+ if (!hdmi->gpr_base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto eiomap;
+ }
+
+ hdmi->gpr_hdmi_base = hdmi->gpr_base + 3;
+ hdmi->gpr_sdma_base = hdmi->gpr_base;
+
+ hdmi_inited = false;
+
+ hdmi->disp_mxc_hdmi = mxc_dispdrv_register(&mxc_hdmi_drv);
+ if (IS_ERR(hdmi->disp_mxc_hdmi)) {
+ dev_err(&pdev->dev, "Failed to register dispdrv - 0x%x\n",
+ (int)hdmi->disp_mxc_hdmi);
+ ret = (int)hdmi->disp_mxc_hdmi;
+ goto edispdrv;
+ }
+ mxc_dispdrv_setdata(hdmi->disp_mxc_hdmi, hdmi);
+
+ platform_set_drvdata(pdev, hdmi);
+
+ hdmi_regulator = devm_regulator_get(&pdev->dev, "HDMI");
+ if (!IS_ERR(hdmi_regulator)) {
+ ret = regulator_enable(hdmi_regulator);
+ if (ret) {
+ dev_err(&pdev->dev, "enable 5v hdmi regulator failed\n");
+ goto edispdrv;
+ }
+ } else {
+ hdmi_regulator = NULL;
+ dev_warn(&pdev->dev, "No hdmi 5v supply\n");
+ }
+
+ return 0;
+edispdrv:
+ iounmap(hdmi->gpr_base);
+eiomap:
+ platform_device_put(hdmi->core_pdev);
+ecore:
+ kfree(hdmi);
+err_out_class:
+ device_destroy(hdmi_class, MKDEV(hdmi_major, 0));
+ class_destroy(hdmi_class);
+err_out_chrdev:
+ unregister_chrdev(hdmi_major, "mxc_hdmi");
+ealloc:
+ return ret;
+}
+
+static int mxc_hdmi_remove(struct platform_device *pdev)
+{
+ struct mxc_hdmi *hdmi = platform_get_drvdata(pdev);
+ int irq = platform_get_irq(pdev, 0);
+
+ fb_unregister_client(&hdmi->nb);
+
+ mxc_dispdrv_puthandle(hdmi->disp_mxc_hdmi);
+ mxc_dispdrv_unregister(hdmi->disp_mxc_hdmi);
+ iounmap(hdmi->gpr_base);
+ /* No new work will be scheduled, wait for running ISR */
+ free_irq(irq, hdmi);
+ kfree(hdmi);
+
+ if (hdmi_regulator)
+ regulator_disable(hdmi_regulator);
+
+ g_hdmi = NULL;
+
+ return 0;
+}
+
+static struct platform_driver mxc_hdmi_driver = {
+ .probe = mxc_hdmi_probe,
+ .remove = mxc_hdmi_remove,
+ .driver = {
+ .name = "mxc_hdmi",
+ .of_match_table = imx_hdmi_dt_ids,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init mxc_hdmi_init(void)
+{
+ return platform_driver_register(&mxc_hdmi_driver);
+}
+module_init(mxc_hdmi_init);
+
+static void __exit mxc_hdmi_exit(void)
+{
+ if (hdmi_major > 0) {
+ device_destroy(hdmi_class, MKDEV(hdmi_major, 0));
+ class_destroy(hdmi_class);
+ unregister_chrdev(hdmi_major, "mxc_hdmi");
+ hdmi_major = 0;
+ }
+
+ platform_driver_unregister(&mxc_hdmi_driver);
+}
+module_exit(mxc_hdmi_exit);
+
+static int mxc_hdmi_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
+ return -ENODEV;
+
+ hdmi_i2c = client;
+
+ return 0;
+}
+
+static int mxc_hdmi_i2c_remove(struct i2c_client *client)
+{
+ hdmi_i2c = NULL;
+ return 0;
+}
+
+static const struct of_device_id imx_hdmi_i2c_match[] = {
+ { .compatible = "fsl,imx6-hdmi-i2c", },
+ { /* sentinel */ }
+};
+
+static const struct i2c_device_id mxc_hdmi_i2c_id[] = {
+ { "mxc_hdmi_i2c", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, mxc_hdmi_i2c_id);
+
+static struct i2c_driver mxc_hdmi_i2c_driver = {
+ .driver = {
+ .name = "mxc_hdmi_i2c",
+ .of_match_table = imx_hdmi_i2c_match,
+ },
+ .probe = mxc_hdmi_i2c_probe,
+ .remove = mxc_hdmi_i2c_remove,
+ .id_table = mxc_hdmi_i2c_id,
+};
+
+static int __init mxc_hdmi_i2c_init(void)
+{
+ return i2c_add_driver(&mxc_hdmi_i2c_driver);
+}
+
+static void __exit mxc_hdmi_i2c_exit(void)
+{
+ i2c_del_driver(&mxc_hdmi_i2c_driver);
+}
+
+module_init(mxc_hdmi_i2c_init);
+module_exit(mxc_hdmi_i2c_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
diff --git a/drivers/video/fbdev/mxc/mxc_ipuv3_fb.c b/drivers/video/fbdev/mxc/mxc_ipuv3_fb.c
new file mode 100644
index 000000000000..c6001b6a73d2
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mxc_ipuv3_fb.c
@@ -0,0 +1,3673 @@
+/*
+ * Copyright 2004-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @defgroup Framebuffer Framebuffer Driver for SDC and ADC.
+ */
+
+/*!
+ * @file mxcfb.c
+ *
+ * @brief MXC Frame buffer driver for SDC
+ *
+ * @ingroup Framebuffer
+ */
+
+/*!
+ * Include files
+ */
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/fsl_devices.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/ipu.h>
+#include <linux/ipu-v3.h>
+#include <linux/ipu-v3-pre.h>
+#include <linux/ipu-v3-prg.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mxcfb.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/time.h>
+#include <linux/uaccess.h>
+
+#include "mxc_dispdrv.h"
+
+/*
+ * Driver name
+ */
+#define MXCFB_NAME "mxc_sdc_fb"
+
+/* Display port number */
+#define MXCFB_PORT_NUM 2
+/*!
+ * Structure containing the MXC specific framebuffer information.
+ */
+struct mxcfb_info {
+ int default_bpp;
+ int cur_blank;
+ int next_blank;
+ ipu_channel_t ipu_ch;
+ int ipu_id;
+ int ipu_di;
+ int pre_num;
+ u32 ipu_di_pix_fmt;
+ bool ipu_int_clk;
+ bool overlay;
+ bool alpha_chan_en;
+ bool late_init;
+ bool first_set_par;
+ bool resolve;
+ bool prefetch;
+ bool on_the_fly;
+ uint32_t final_pfmt;
+ unsigned long gpu_sec_buf_off;
+ unsigned long base;
+ uint32_t x_crop;
+ uint32_t y_crop;
+ unsigned int sec_buf_off;
+ unsigned int trd_buf_off;
+ dma_addr_t store_addr;
+ dma_addr_t alpha_phy_addr0;
+ dma_addr_t alpha_phy_addr1;
+ void *alpha_virt_addr0;
+ void *alpha_virt_addr1;
+ uint32_t alpha_mem_len;
+ uint32_t ipu_ch_irq;
+ uint32_t ipu_ch_nf_irq;
+ uint32_t ipu_alp_ch_irq;
+ uint32_t cur_ipu_buf;
+ uint32_t cur_ipu_alpha_buf;
+
+ u32 pseudo_palette[16];
+
+ bool mode_found;
+ struct completion flip_complete;
+ struct completion alpha_flip_complete;
+ struct completion vsync_complete;
+ struct completion otf_complete; /* on the fly */
+
+ void *ipu;
+ struct fb_info *ovfbi;
+
+ struct mxc_dispdrv_handle *dispdrv;
+
+ struct fb_var_screeninfo cur_var;
+ uint32_t cur_ipu_pfmt;
+ uint32_t cur_fb_pfmt;
+ bool cur_prefetch;
+ spinlock_t spin_lock; /* for PRE small yres cases */
+ struct ipu_pre_context *pre_config;
+};
+
+struct mxcfb_pfmt {
+ u32 fb_pix_fmt;
+ int bpp;
+ struct fb_bitfield red;
+ struct fb_bitfield green;
+ struct fb_bitfield blue;
+ struct fb_bitfield transp;
+};
+
+struct mxcfb_tile_block {
+ u32 fb_pix_fmt;
+ int bw; /* in pixel */
+ int bh; /* in pixel */
+};
+
+#define NA (~0x0UL)
+static const struct mxcfb_pfmt mxcfb_pfmts[] = {
+ /* pixel bpp red green blue transp */
+ {IPU_PIX_FMT_RGB565, 16, {11, 5, 0}, { 5, 6, 0}, { 0, 5, 0}, { 0, 0, 0} },
+ {IPU_PIX_FMT_BGRA4444, 16, { 8, 4, 0}, { 4, 4, 0}, { 0, 4, 0}, { 12, 4, 0} },
+ {IPU_PIX_FMT_BGRA5551, 16, {10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0} },
+ {IPU_PIX_FMT_RGB24, 24, { 0, 8, 0}, { 8, 8, 0}, {16, 8, 0}, { 0, 0, 0} },
+ {IPU_PIX_FMT_BGR24, 24, {16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 0, 0, 0} },
+ {IPU_PIX_FMT_RGB32, 32, { 0, 8, 0}, { 8, 8, 0}, {16, 8, 0}, {24, 8, 0} },
+ {IPU_PIX_FMT_BGR32, 32, {16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, {24, 8, 0} },
+ {IPU_PIX_FMT_ABGR32, 32, {24, 8, 0}, {16, 8, 0}, { 8, 8, 0}, { 0, 8, 0} },
+ /* pixel bpp red green blue transp */
+ {IPU_PIX_FMT_YUV420P2, 12, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_YUV420P, 12, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_YVU420P, 12, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_NV12, 12, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {PRE_PIX_FMT_NV21, 12, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_NV16, 16, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {PRE_PIX_FMT_NV61, 16, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_YUV422P, 16, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_YVU422P, 16, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_UYVY, 16, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_YUYV, 16, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_YUV444, 24, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_YUV444P, 24, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_AYUV, 32, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ /* pixel bpp red green blue transp */
+ {IPU_PIX_FMT_GPU32_SB_ST, 32, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_GPU32_SB_SRT, 32, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_GPU32_ST, 32, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_GPU32_SRT, 32, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_GPU16_SB_ST, 16, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_GPU16_SB_SRT, 16, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_GPU16_ST, 16, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+ {IPU_PIX_FMT_GPU16_SRT, 16, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA}, {NA, NA, NA} },
+};
+
+/* Tile fb alignment */
+static const struct mxcfb_tile_block tas[] = {
+ {IPU_PIX_FMT_GPU32_SB_ST, 16, 8},
+ {IPU_PIX_FMT_GPU32_SB_SRT, 64, 128},
+ {IPU_PIX_FMT_GPU32_ST, 16, 4},
+ {IPU_PIX_FMT_GPU32_SRT, 64, 64},
+ {IPU_PIX_FMT_GPU16_SB_ST, 16, 8},
+ {IPU_PIX_FMT_GPU16_SB_SRT, 64, 128},
+ {IPU_PIX_FMT_GPU16_ST, 16, 4},
+ {IPU_PIX_FMT_GPU16_SRT, 64, 64},
+};
+
+/* The block can be resolved */
+static const struct mxcfb_tile_block trs[] = {
+ /* pixel w h */
+ {IPU_PIX_FMT_GPU32_SB_ST, 16, 4},
+ {IPU_PIX_FMT_GPU32_SB_SRT, 16, 4},
+ {IPU_PIX_FMT_GPU32_ST, 16, 4},
+ {IPU_PIX_FMT_GPU32_SRT, 16, 4},
+ {IPU_PIX_FMT_GPU16_SB_ST, 16, 4},
+ {IPU_PIX_FMT_GPU16_SB_SRT, 16, 4},
+ {IPU_PIX_FMT_GPU16_ST, 16, 4},
+ {IPU_PIX_FMT_GPU16_SRT, 16, 4},
+};
+
+struct mxcfb_alloc_list {
+ struct list_head list;
+ dma_addr_t phy_addr;
+ void *cpu_addr;
+ u32 size;
+};
+
+enum {
+ BOTH_ON,
+ SRC_ON,
+ TGT_ON,
+ BOTH_OFF
+};
+
+static bool g_dp_in_use[2];
+LIST_HEAD(fb_alloc_list);
+
+/* Return default standard(RGB) pixel format */
+static uint32_t bpp_to_pixfmt(int bpp)
+{
+ uint32_t pixfmt = 0;
+
+ switch (bpp) {
+ case 24:
+ pixfmt = IPU_PIX_FMT_BGR24;
+ break;
+ case 32:
+ pixfmt = IPU_PIX_FMT_BGR32;
+ break;
+ case 16:
+ pixfmt = IPU_PIX_FMT_RGB565;
+ break;
+ }
+ return pixfmt;
+}
+
+static inline int bitfield_is_equal(struct fb_bitfield f1,
+ struct fb_bitfield f2)
+{
+ return !memcmp(&f1, &f2, sizeof(f1));
+}
+
+static int pixfmt_to_var(uint32_t pixfmt, struct fb_var_screeninfo *var)
+{
+ int i, ret = -1;
+
+ for (i = 0; i < ARRAY_SIZE(mxcfb_pfmts); i++) {
+ if (pixfmt == mxcfb_pfmts[i].fb_pix_fmt) {
+ var->red = mxcfb_pfmts[i].red;
+ var->green = mxcfb_pfmts[i].green;
+ var->blue = mxcfb_pfmts[i].blue;
+ var->transp = mxcfb_pfmts[i].transp;
+ var->bits_per_pixel = mxcfb_pfmts[i].bpp;
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int bpp_to_var(int bpp, struct fb_var_screeninfo *var)
+{
+ uint32_t pixfmt = 0;
+
+ if (var->nonstd)
+ return -1;
+
+ pixfmt = bpp_to_pixfmt(bpp);
+ if (pixfmt)
+ return pixfmt_to_var(pixfmt, var);
+ else
+ return -1;
+}
+
+static int check_var_pixfmt(struct fb_var_screeninfo *var)
+{
+ int i, ret = -1;
+
+ if (var->nonstd) {
+ for (i = 0; i < ARRAY_SIZE(mxcfb_pfmts); i++) {
+ if (mxcfb_pfmts[i].fb_pix_fmt == var->nonstd) {
+ var->bits_per_pixel = mxcfb_pfmts[i].bpp;
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mxcfb_pfmts); i++) {
+ if (bitfield_is_equal(var->red, mxcfb_pfmts[i].red) &&
+ bitfield_is_equal(var->green, mxcfb_pfmts[i].green) &&
+ bitfield_is_equal(var->blue, mxcfb_pfmts[i].blue) &&
+ bitfield_is_equal(var->transp, mxcfb_pfmts[i].transp) &&
+ var->bits_per_pixel == mxcfb_pfmts[i].bpp) {
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+static uint32_t fb_to_store_pixfmt(uint32_t fb_pixfmt)
+{
+ switch (fb_pixfmt) {
+ case IPU_PIX_FMT_RGB32:
+ case IPU_PIX_FMT_BGR32:
+ case IPU_PIX_FMT_ABGR32:
+ case IPU_PIX_FMT_RGB24:
+ case IPU_PIX_FMT_BGR24:
+ case IPU_PIX_FMT_RGB565:
+ case IPU_PIX_FMT_BGRA4444:
+ case IPU_PIX_FMT_BGRA5551:
+ case IPU_PIX_FMT_UYVY:
+ case IPU_PIX_FMT_YUYV:
+ case IPU_PIX_FMT_YUV444:
+ case IPU_PIX_FMT_AYUV:
+ return fb_pixfmt;
+ case IPU_PIX_FMT_YUV422P:
+ case IPU_PIX_FMT_YVU422P:
+ case IPU_PIX_FMT_YUV420P2:
+ case IPU_PIX_FMT_YVU420P:
+ case IPU_PIX_FMT_NV12:
+ case PRE_PIX_FMT_NV21:
+ case IPU_PIX_FMT_NV16:
+ case PRE_PIX_FMT_NV61:
+ case IPU_PIX_FMT_YUV420P:
+ return IPU_PIX_FMT_UYVY;
+ case IPU_PIX_FMT_YUV444P:
+ return IPU_PIX_FMT_AYUV;
+ default:
+ return 0;
+ }
+}
+
+static uint32_t fbi_to_pixfmt(struct fb_info *fbi, bool original_fb)
+{
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
+ int i;
+ uint32_t pixfmt = 0;
+
+ if (fbi->var.nonstd) {
+ if (mxc_fbi->prefetch && !original_fb) {
+ if (ipu_pixel_format_is_gpu_tile(fbi->var.nonstd))
+ goto next;
+
+ return fb_to_store_pixfmt(fbi->var.nonstd);
+ } else {
+ return fbi->var.nonstd;
+ }
+ }
+
+next:
+ for (i = 0; i < ARRAY_SIZE(mxcfb_pfmts); i++) {
+ if (bitfield_is_equal(fbi->var.red, mxcfb_pfmts[i].red) &&
+ bitfield_is_equal(fbi->var.green, mxcfb_pfmts[i].green) &&
+ bitfield_is_equal(fbi->var.blue, mxcfb_pfmts[i].blue) &&
+ bitfield_is_equal(fbi->var.transp, mxcfb_pfmts[i].transp)) {
+ pixfmt = mxcfb_pfmts[i].fb_pix_fmt;
+ break;
+ }
+ }
+
+ if (pixfmt == 0)
+ dev_err(fbi->device, "cannot get pixel format\n");
+
+ return pixfmt;
+}
+
+static void fmt_to_tile_alignment(uint32_t fmt, int *bw, int *bh)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tas); i++) {
+ if (tas[i].fb_pix_fmt == fmt) {
+ *bw = tas[i].bw;
+ *bh = tas[i].bh;
+ }
+ }
+
+ BUG_ON(!(*bw) || !(*bh));
+}
+
+static void fmt_to_tile_block(uint32_t fmt, int *bw, int *bh)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(trs); i++) {
+ if (trs[i].fb_pix_fmt == fmt) {
+ *bw = trs[i].bw;
+ *bh = trs[i].bh;
+ }
+ }
+
+ BUG_ON(!(*bw) || !(*bh));
+}
+
+static struct fb_info *found_registered_fb(ipu_channel_t ipu_ch, int ipu_id)
+{
+ int i;
+ struct mxcfb_info *mxc_fbi;
+ struct fb_info *fbi = NULL;
+
+ for (i = 0; i < num_registered_fb; i++) {
+ mxc_fbi =
+ ((struct mxcfb_info *)(registered_fb[i]->par));
+
+ if ((mxc_fbi->ipu_ch == ipu_ch) &&
+ (mxc_fbi->ipu_id == ipu_id)) {
+ fbi = registered_fb[i];
+ break;
+ }
+ }
+ return fbi;
+}
+
+static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id);
+static irqreturn_t mxcfb_nf_irq_handler(int irq, void *dev_id);
+static int mxcfb_blank(int blank, struct fb_info *info);
+static int mxcfb_map_video_memory(struct fb_info *fbi);
+static int mxcfb_unmap_video_memory(struct fb_info *fbi);
+static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd,
+ unsigned long arg);
+
+/*
+ * Set fixed framebuffer parameters based on variable settings.
+ *
+ * @param info framebuffer information pointer
+ */
+static int mxcfb_set_fix(struct fb_info *info)
+{
+ struct fb_fix_screeninfo *fix = &info->fix;
+ struct fb_var_screeninfo *var = &info->var;
+
+ fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->accel = FB_ACCEL_NONE;
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ fix->xpanstep = 1;
+ fix->ywrapstep = 1;
+ fix->ypanstep = 1;
+
+ return 0;
+}
+
+static int _setup_disp_channel1(struct fb_info *fbi)
+{
+ ipu_channel_params_t params;
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
+
+ memset(&params, 0, sizeof(params));
+
+ if (mxc_fbi->ipu_ch == MEM_DC_SYNC) {
+ params.mem_dc_sync.di = mxc_fbi->ipu_di;
+ if (fbi->var.vmode & FB_VMODE_INTERLACED)
+ params.mem_dc_sync.interlaced = true;
+ params.mem_dc_sync.out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
+ params.mem_dc_sync.in_pixel_fmt = mxc_fbi->on_the_fly ?
+ mxc_fbi->final_pfmt :
+ fbi_to_pixfmt(fbi, false);
+ } else {
+ params.mem_dp_bg_sync.di = mxc_fbi->ipu_di;
+ if (fbi->var.vmode & FB_VMODE_INTERLACED)
+ params.mem_dp_bg_sync.interlaced = true;
+ params.mem_dp_bg_sync.out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
+ params.mem_dp_bg_sync.in_pixel_fmt = mxc_fbi->on_the_fly ?
+ mxc_fbi->final_pfmt :
+ fbi_to_pixfmt(fbi, false);
+ if (mxc_fbi->alpha_chan_en)
+ params.mem_dp_bg_sync.alpha_chan_en = true;
+ }
+ if (ipu_init_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch, &params) < 0) {
+ dev_err(fbi->device, "init ipu channel fail\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int _setup_disp_channel2(struct fb_info *fbi)
+{
+ int retval = 0;
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
+ int fb_stride, ipu_stride, bw = 0, bh = 0;
+ unsigned long base, ipu_base;
+ unsigned int fr_xoff, fr_yoff, fr_w, fr_h;
+ unsigned int prg_width;
+ struct ipu_pre_context pre;
+ bool post_pre_disable = false;
+
+ switch (fbi_to_pixfmt(fbi, true)) {
+ case IPU_PIX_FMT_YUV420P2:
+ case IPU_PIX_FMT_YVU420P:
+ case IPU_PIX_FMT_NV12:
+ case PRE_PIX_FMT_NV21:
+ case IPU_PIX_FMT_NV16:
+ case PRE_PIX_FMT_NV61:
+ case IPU_PIX_FMT_YUV422P:
+ case IPU_PIX_FMT_YVU422P:
+ case IPU_PIX_FMT_YUV420P:
+ case IPU_PIX_FMT_YUV444P:
+ fb_stride = fbi->var.xres_virtual;
+ break;
+ default:
+ fb_stride = fbi->fix.line_length;
+ }
+
+ base = fbi->fix.smem_start;
+ fr_xoff = fbi->var.xoffset;
+ fr_w = fbi->var.xres_virtual;
+ if (!(fbi->var.vmode & FB_VMODE_YWRAP)) {
+ dev_dbg(fbi->device, "Y wrap disabled\n");
+ fr_yoff = fbi->var.yoffset % fbi->var.yres;
+ fr_h = fbi->var.yres;
+ base += fbi->fix.line_length * fbi->var.yres *
+ (fbi->var.yoffset / fbi->var.yres);
+ if (ipu_pixel_format_is_split_gpu_tile(fbi->var.nonstd))
+ base += (mxc_fbi->gpu_sec_buf_off -
+ fbi->fix.line_length * fbi->var.yres / 2) *
+ (fbi->var.yoffset / fbi->var.yres);
+ } else {
+ dev_dbg(fbi->device, "Y wrap enabled\n");
+ fr_yoff = fbi->var.yoffset;
+ fr_h = fbi->var.yres_virtual;
+ }
+
+ /* pixel block alignment for resolving cases */
+ if (mxc_fbi->resolve) {
+ fmt_to_tile_block(fbi->var.nonstd, &bw, &bh);
+ } else {
+ base += fr_yoff * fb_stride + fr_xoff *
+ bytes_per_pixel(fbi_to_pixfmt(fbi, true));
+ }
+
+ if (!mxc_fbi->on_the_fly)
+ mxc_fbi->cur_ipu_buf = 2;
+ init_completion(&mxc_fbi->flip_complete);
+ /*
+ * We don't need to wait for vsync at the first time
+ * we do pan display after fb is initialized, as IPU will
+ * switch to the newly selected buffer automatically,
+ * so we call complete() for both mxc_fbi->flip_complete
+ * and mxc_fbi->alpha_flip_complete.
+ */
+ if (!mxc_fbi->prefetch ||
+ (mxc_fbi->prefetch && !ipu_pre_yres_is_small(fbi->var.yres)))
+ complete(&mxc_fbi->flip_complete);
+ if (mxc_fbi->alpha_chan_en) {
+ mxc_fbi->cur_ipu_alpha_buf = 1;
+ init_completion(&mxc_fbi->alpha_flip_complete);
+ complete(&mxc_fbi->alpha_flip_complete);
+ }
+
+ if (mxc_fbi->prefetch) {
+ struct ipu_prg_config prg;
+ struct fb_var_screeninfo from_var, to_var;
+
+ if (mxc_fbi->pre_num < 0) {
+ mxc_fbi->pre_num = ipu_pre_alloc(mxc_fbi->ipu_id,
+ mxc_fbi->ipu_ch);
+ if (mxc_fbi->pre_num < 0) {
+ dev_dbg(fbi->device, "failed to alloc PRE\n");
+ mxc_fbi->prefetch = mxc_fbi->cur_prefetch;
+ mxc_fbi->resolve = false;
+ if (!mxc_fbi->on_the_fly)
+ mxc_fbi->cur_blank = FB_BLANK_POWERDOWN;
+ return mxc_fbi->pre_num;
+ }
+ }
+ pre.repeat = true;
+ pre.vflip = fbi->var.rotate ? true : false;
+ pre.handshake_en = true;
+ pre.hsk_abort_en = true;
+ pre.hsk_line_num = 0;
+ pre.sdw_update = true;
+ pre.cur_buf = base;
+ pre.next_buf = pre.cur_buf;
+ if (fbi->var.vmode & FB_VMODE_INTERLACED) {
+ pre.interlaced = 2;
+ if (mxc_fbi->resolve) {
+ pre.field_inverse = fbi->var.rotate;
+ pre.interlace_offset = 0;
+ } else {
+ pre.field_inverse = 0;
+ if (fbi->var.rotate) {
+ pre.interlace_offset = ~(fbi->var.xres_virtual *
+ bytes_per_pixel(fbi_to_pixfmt(fbi, true))) + 1;
+ pre.cur_buf += fbi->var.xres_virtual * bytes_per_pixel(fbi_to_pixfmt(fbi, true));
+ pre.next_buf = pre.cur_buf;
+ } else {
+ pre.interlace_offset = fbi->var.xres_virtual *
+ bytes_per_pixel(fbi_to_pixfmt(fbi, true));
+ }
+ }
+ } else {
+ pre.interlaced = 0;
+ pre.interlace_offset = 0;
+ }
+ pre.prefetch_mode = mxc_fbi->resolve ? 1 : 0;
+ pre.tile_fmt = mxc_fbi->resolve ? fbi->var.nonstd : 0;
+ pre.read_burst = mxc_fbi->resolve ? 0x4 : 0x3;
+ if (fbi_to_pixfmt(fbi, true) == IPU_PIX_FMT_RGB24 ||
+ fbi_to_pixfmt(fbi, true) == IPU_PIX_FMT_BGR24 ||
+ fbi_to_pixfmt(fbi, true) == IPU_PIX_FMT_YUV444) {
+ if ((fbi->var.xres * 3) % 8 == 0 &&
+ (fbi->var.xres_virtual * 3) % 8 == 0)
+ pre.prefetch_input_bpp = 64;
+ else if ((fbi->var.xres * 3) % 4 == 0 &&
+ (fbi->var.xres_virtual * 3) % 4 == 0)
+ pre.prefetch_input_bpp = 32;
+ else if ((fbi->var.xres * 3) % 2 == 0 &&
+ (fbi->var.xres_virtual * 3) % 2 == 0)
+ pre.prefetch_input_bpp = 16;
+ else
+ pre.prefetch_input_bpp = 8;
+ } else {
+ pre.prefetch_input_bpp =
+ 8 * bytes_per_pixel(fbi_to_pixfmt(fbi, true));
+ }
+ pre.prefetch_input_pixel_fmt = mxc_fbi->resolve ?
+ 0x1 : (fbi->var.nonstd ? fbi->var.nonstd : 0);
+ pre.shift_bypass = (mxc_fbi->on_the_fly &&
+ mxc_fbi->final_pfmt != fbi_to_pixfmt(fbi, false)) ?
+ false : true;
+ pixfmt_to_var(fbi_to_pixfmt(fbi, false), &from_var);
+ pixfmt_to_var(mxc_fbi->final_pfmt, &to_var);
+ if (mxc_fbi->on_the_fly &&
+ (format_to_colorspace(fbi_to_pixfmt(fbi, true)) == RGB) &&
+ (bytes_per_pixel(fbi_to_pixfmt(fbi, true)) == 4)) {
+ pre.prefetch_shift_offset = (from_var.red.offset << to_var.red.offset) |
+ (from_var.green.offset << to_var.green.offset) |
+ (from_var.blue.offset << to_var.blue.offset) |
+ (from_var.transp.offset << to_var.transp.offset);
+ pre.prefetch_shift_width = (to_var.red.length << (to_var.red.offset/2)) |
+ (to_var.green.length << (to_var.green.offset/2)) |
+ (to_var.blue.length << (to_var.blue.offset/2)) |
+ (to_var.transp.length << (to_var.transp.offset/2));
+ } else {
+ pre.prefetch_shift_offset = 0;
+ pre.prefetch_shift_width = 0;
+ }
+ pre.tpr_coor_offset_en = mxc_fbi->resolve ? true : false;
+ pre.prefetch_output_size.left = mxc_fbi->resolve ? (fr_xoff & ~(bw - 1)) : 0;
+ pre.prefetch_output_size.top = mxc_fbi->resolve ? (fr_yoff & ~(bh - 1)) : 0;
+ if (fbi_to_pixfmt(fbi, true) == IPU_PIX_FMT_RGB24 ||
+ fbi_to_pixfmt(fbi, true) == IPU_PIX_FMT_BGR24 ||
+ fbi_to_pixfmt(fbi, true) == IPU_PIX_FMT_YUV444) {
+ pre.prefetch_output_size.width = (fbi->var.xres * 3) /
+ (pre.prefetch_input_bpp / 8);
+ pre.store_output_bpp = pre.prefetch_input_bpp;
+ } else {
+ pre.prefetch_output_size.width = fbi->var.xres;
+ pre.store_output_bpp = 8 *
+ bytes_per_pixel(fbi_to_pixfmt(fbi, false));
+ }
+ pre.prefetch_output_size.height = fbi->var.yres;
+ pre.prefetch_input_active_width = pre.prefetch_output_size.width;
+ if (fbi_to_pixfmt(fbi, true) == IPU_PIX_FMT_RGB24 ||
+ fbi_to_pixfmt(fbi, true) == IPU_PIX_FMT_BGR24 ||
+ fbi_to_pixfmt(fbi, true) == IPU_PIX_FMT_YUV444)
+ pre.prefetch_input_width = (fbi->var.xres_virtual * 3) /
+ (pre.prefetch_input_bpp / 8);
+ else
+ pre.prefetch_input_width = fbi->var.xres_virtual;
+ pre.prefetch_input_height = fbi->var.yres;
+ prg_width = pre.prefetch_output_size.width;
+ if (!(pre.prefetch_input_active_width % 32))
+ pre.block_size = 0;
+ else if (!(pre.prefetch_input_active_width % 16))
+ pre.block_size = 1;
+ else
+ pre.block_size = 0;
+ if (mxc_fbi->resolve) {
+ int bs = pre.block_size ? 16 : 32;
+ pre.prefetch_input_active_width += fr_xoff % bw;
+ if (((fr_xoff % bw) + pre.prefetch_input_active_width) % bs)
+ pre.prefetch_input_active_width =
+ ALIGN(pre.prefetch_input_active_width, bs);
+ pre.prefetch_output_size.width =
+ pre.prefetch_input_active_width;
+ prg_width = pre.prefetch_output_size.width;
+ pre.prefetch_input_height += fr_yoff % bh;
+ if (((fr_yoff % bh) + fbi->var.yres) % 4) {
+ pre.prefetch_input_height =
+ (fbi->var.vmode & FB_VMODE_INTERLACED) ?
+ ALIGN(pre.prefetch_input_height, 8) :
+ ALIGN(pre.prefetch_input_height, 4);
+ } else {
+ if (fbi->var.vmode & FB_VMODE_INTERLACED)
+ pre.prefetch_input_height =
+ ALIGN(pre.prefetch_input_height, 8);
+ }
+ pre.prefetch_output_size.height = pre.prefetch_input_height;
+ }
+
+ /* store output pitch 8-byte aligned */
+ while ((pre.store_output_bpp * prg_width) % 64)
+ prg_width++;
+
+ pre.store_pitch = (pre.store_output_bpp * prg_width) / 8;
+
+ pre.store_en = true;
+ pre.write_burst = 0x3;
+ ipu_get_channel_offset(fbi_to_pixfmt(fbi, true),
+ fbi->var.xres,
+ fr_h,
+ fr_w,
+ 0, 0,
+ fr_yoff,
+ fr_xoff,
+ &pre.sec_buf_off,
+ &pre.trd_buf_off);
+ if (mxc_fbi->resolve)
+ pre.sec_buf_off = mxc_fbi->gpu_sec_buf_off;
+
+ ipu_pre_config(mxc_fbi->pre_num, &pre);
+ ipu_stride = pre.store_pitch;
+ ipu_base = pre.store_addr;
+ mxc_fbi->store_addr = ipu_base;
+
+ if (mxc_fbi->cur_prefetch && mxc_fbi->on_the_fly) {
+ /*
+ * Make sure any pending interrupt is handled so that
+ * the buffer panned can start to be scanned out.
+ */
+ if (!ipu_pre_yres_is_small(fbi->var.yres)) {
+ mxcfb_ioctl(fbi, MXCFB_WAIT_FOR_VSYNC,
+ (unsigned long)fbi->par);
+ mxcfb_ioctl(fbi, MXCFB_WAIT_FOR_VSYNC,
+ (unsigned long)fbi->par);
+ }
+
+ mxc_fbi->pre_config = &pre;
+
+ /*
+ * Write the PRE control register in the flip interrupt
+ * handler in this on-the-fly case to workaround the
+ * SoC design bug recorded by errata ERR009624.
+ */
+ init_completion(&mxc_fbi->otf_complete);
+ ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
+ ipu_enable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
+ retval = wait_for_completion_timeout(
+ &mxc_fbi->otf_complete, HZ/2);
+ if (retval == 0) {
+ dev_err(fbi->device, "timeout when waiting "
+ "for on the fly config irq\n");
+ return -ETIMEDOUT;
+ } else {
+ retval = 0;
+ }
+ } else {
+ retval = ipu_pre_set_ctrl(mxc_fbi->pre_num, &pre);
+ if (retval < 0)
+ return retval;
+ }
+
+ if (!mxc_fbi->on_the_fly || !mxc_fbi->cur_prefetch) {
+ prg.id = mxc_fbi->ipu_id;
+ prg.pre_num = mxc_fbi->pre_num;
+ prg.ipu_ch = mxc_fbi->ipu_ch;
+ prg.so = (fbi->var.vmode & FB_VMODE_INTERLACED) ?
+ PRG_SO_INTERLACE : PRG_SO_PROGRESSIVE;
+ prg.vflip = fbi->var.rotate ? true : false;
+ prg.block_mode = mxc_fbi->resolve ? PRG_BLOCK_MODE : PRG_SCAN_MODE;
+ prg.stride = (fbi->var.vmode & FB_VMODE_INTERLACED) ?
+ ipu_stride * 2 : ipu_stride;
+ prg.ilo = (fbi->var.vmode & FB_VMODE_INTERLACED) ?
+ ipu_stride : 0;
+ prg.height = mxc_fbi->resolve ?
+ pre.prefetch_output_size.height : fbi->var.yres;
+ prg.ipu_height = fbi->var.yres;
+ prg.crop_line = mxc_fbi->resolve ?
+ ((fbi->var.vmode & FB_VMODE_INTERLACED) ? (fr_yoff % bh) / 2 : fr_yoff % bh) : 0;
+ prg.baddr = pre.store_addr;
+ prg.offset = mxc_fbi->resolve ? (prg.crop_line * prg.stride +
+ (fr_xoff % bw) *
+ bytes_per_pixel(fbi_to_pixfmt(fbi, false))) : 0;
+ ipu_base += prg.offset;
+ if (ipu_base % 8) {
+ dev_err(fbi->device,
+ "IPU base address is not 8byte aligned\n");
+ return -EINVAL;
+ }
+ mxc_fbi->store_addr = ipu_base;
+
+ if (!mxc_fbi->on_the_fly) {
+ retval = ipu_init_channel_buffer(mxc_fbi->ipu,
+ mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
+ fbi_to_pixfmt(fbi, false),
+ fbi->var.xres, fbi->var.yres,
+ ipu_stride,
+ fbi->var.rotate,
+ ipu_base,
+ ipu_base,
+ fbi->var.accel_flags &
+ FB_ACCEL_DOUBLE_FLAG ? 0 : ipu_base,
+ 0, 0);
+ if (retval) {
+ dev_err(fbi->device,
+ "ipu_init_channel_buffer error %d\n", retval);
+ return retval;
+ }
+ }
+
+ retval = ipu_prg_config(&prg);
+ if (retval < 0) {
+ dev_err(fbi->device,
+ "failed to configure PRG %d\n", retval);
+ return retval;
+ }
+
+ retval = ipu_pre_enable(mxc_fbi->pre_num);
+ if (retval < 0) {
+ ipu_prg_disable(mxc_fbi->ipu_id, mxc_fbi->pre_num);
+ dev_err(fbi->device,
+ "failed to enable PRE %d\n", retval);
+ return retval;
+ }
+
+ retval = ipu_prg_wait_buf_ready(mxc_fbi->ipu_id,
+ mxc_fbi->pre_num,
+ pre.hsk_line_num,
+ pre.prefetch_output_size.height);
+ if (retval < 0) {
+ ipu_prg_disable(mxc_fbi->ipu_id, mxc_fbi->pre_num);
+ ipu_pre_disable(mxc_fbi->pre_num);
+ ipu_pre_free(&mxc_fbi->pre_num);
+ dev_err(fbi->device, "failed to wait PRG ready %d\n", retval);
+ return retval;
+ }
+ }
+ } else {
+ ipu_stride = fb_stride;
+ ipu_base = base;
+ if (mxc_fbi->on_the_fly)
+ post_pre_disable = true;
+ }
+
+ if (mxc_fbi->on_the_fly && ((mxc_fbi->cur_prefetch && !mxc_fbi->prefetch) ||
+ (!mxc_fbi->cur_prefetch && mxc_fbi->prefetch))) {
+ int htotal = fbi->var.xres + fbi->var.right_margin +
+ fbi->var.hsync_len + fbi->var.left_margin;
+ int vtotal = fbi->var.yres + fbi->var.lower_margin +
+ fbi->var.vsync_len + fbi->var.upper_margin;
+ int timeout = ((htotal * vtotal) / PICOS2KHZ(fbi->var.pixclock)) * 2 ;
+ int cur_buf = 0;
+
+ BUG_ON(timeout <= 0);
+
+ ++mxc_fbi->cur_ipu_buf;
+ mxc_fbi->cur_ipu_buf %= 3;
+ if (ipu_update_channel_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch,
+ IPU_INPUT_BUFFER,
+ mxc_fbi->cur_ipu_buf,
+ ipu_base) == 0) {
+ if (!mxc_fbi->prefetch)
+ ipu_update_channel_offset(mxc_fbi->ipu,
+ mxc_fbi->ipu_ch,
+ IPU_INPUT_BUFFER,
+ fbi_to_pixfmt(fbi, true),
+ fr_w,
+ fr_h,
+ fr_w,
+ 0, 0,
+ fr_yoff,
+ fr_xoff);
+ ipu_select_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch,
+ IPU_INPUT_BUFFER, mxc_fbi->cur_ipu_buf);
+ for (; timeout > 0; timeout--) {
+ cur_buf = ipu_get_cur_buffer_idx(mxc_fbi->ipu,
+ mxc_fbi->ipu_ch,
+ IPU_INPUT_BUFFER);
+ if (cur_buf == mxc_fbi->cur_ipu_buf)
+ break;
+
+ udelay(1000);
+ }
+ if (!timeout)
+ dev_err(fbi->device, "Timeout for switch to buf %d "
+ "to address=0x%08lX, current buf %d, "
+ "buf0 ready %d, buf1 ready %d, buf2 ready "
+ "%d\n", mxc_fbi->cur_ipu_buf, ipu_base,
+ ipu_get_cur_buffer_idx(mxc_fbi->ipu,
+ mxc_fbi->ipu_ch,
+ IPU_INPUT_BUFFER),
+ ipu_check_buffer_ready(mxc_fbi->ipu,
+ mxc_fbi->ipu_ch,
+ IPU_INPUT_BUFFER, 0),
+ ipu_check_buffer_ready(mxc_fbi->ipu,
+ mxc_fbi->ipu_ch,
+ IPU_INPUT_BUFFER, 1),
+ ipu_check_buffer_ready(mxc_fbi->ipu,
+ mxc_fbi->ipu_ch,
+ IPU_INPUT_BUFFER, 2));
+ }
+ } else if (!mxc_fbi->on_the_fly && !mxc_fbi->prefetch) {
+ retval = ipu_init_channel_buffer(mxc_fbi->ipu,
+ mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
+ mxc_fbi->on_the_fly ? mxc_fbi->final_pfmt :
+ fbi_to_pixfmt(fbi, false),
+ fbi->var.xres, fbi->var.yres,
+ ipu_stride,
+ fbi->var.rotate,
+ ipu_base,
+ ipu_base,
+ fbi->var.accel_flags &
+ FB_ACCEL_DOUBLE_FLAG ? 0 : ipu_base,
+ 0, 0);
+ if (retval) {
+ dev_err(fbi->device,
+ "ipu_init_channel_buffer error %d\n", retval);
+ return retval;
+ }
+ /* update u/v offset */
+ if (!mxc_fbi->prefetch)
+ ipu_update_channel_offset(mxc_fbi->ipu, mxc_fbi->ipu_ch,
+ IPU_INPUT_BUFFER,
+ fbi_to_pixfmt(fbi, true),
+ fr_w,
+ fr_h,
+ fr_w,
+ 0, 0,
+ fr_yoff,
+ fr_xoff);
+ }
+
+ if (post_pre_disable) {
+ ipu_prg_disable(mxc_fbi->ipu_id, mxc_fbi->pre_num);
+ ipu_pre_disable(mxc_fbi->pre_num);
+ ipu_pre_free(&mxc_fbi->pre_num);
+ }
+
+ if (mxc_fbi->alpha_chan_en) {
+ retval = ipu_init_channel_buffer(mxc_fbi->ipu,
+ mxc_fbi->ipu_ch,
+ IPU_ALPHA_IN_BUFFER,
+ IPU_PIX_FMT_GENERIC,
+ fbi->var.xres, fbi->var.yres,
+ fbi->var.xres,
+ fbi->var.rotate,
+ mxc_fbi->alpha_phy_addr1,
+ mxc_fbi->alpha_phy_addr0,
+ 0,
+ 0, 0);
+ if (retval) {
+ dev_err(fbi->device,
+ "ipu_init_channel_buffer error %d\n", retval);
+ return retval;
+ }
+ }
+
+ return retval;
+}
+
+static bool mxcfb_need_to_set_par(struct fb_info *fbi)
+{
+ struct mxcfb_info *mxc_fbi = fbi->par;
+
+ if ((fbi->var.activate & FB_ACTIVATE_FORCE) &&
+ (fbi->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
+ return true;
+
+ /*
+ * Ignore xoffset and yoffset update,
+ * because pan display handles this case.
+ */
+ mxc_fbi->cur_var.xoffset = fbi->var.xoffset;
+ mxc_fbi->cur_var.yoffset = fbi->var.yoffset;
+
+ return !!memcmp(&mxc_fbi->cur_var, &fbi->var,
+ sizeof(struct fb_var_screeninfo));
+}
+
+static bool mxcfb_can_set_par_on_the_fly(struct fb_info *fbi,
+ uint32_t *final_pfmt)
+{
+ struct mxcfb_info *mxc_fbi = fbi->par;
+ struct fb_var_screeninfo cur_var = mxc_fbi->cur_var;
+ uint32_t cur_pfmt = mxc_fbi->cur_ipu_pfmt;
+ uint32_t new_pfmt = fbi_to_pixfmt(fbi, false);
+ uint32_t new_fb_pfmt = fbi_to_pixfmt(fbi, true);
+ int cur_bpp, new_bpp, cur_bw, cur_bh, new_bw, new_bh;
+ unsigned int mem_len;
+ ipu_color_space_t cur_space, new_space;
+
+ cur_space = format_to_colorspace(cur_pfmt);
+ new_space = format_to_colorspace(new_pfmt);
+
+ cur_bpp = bytes_per_pixel(cur_pfmt);
+ new_bpp = bytes_per_pixel(new_pfmt);
+
+ if (mxc_fbi->first_set_par || mxc_fbi->cur_blank != FB_BLANK_UNBLANK)
+ return false;
+
+ if (!mxc_fbi->prefetch && !mxc_fbi->cur_prefetch)
+ return false;
+
+ if (!mxc_fbi->prefetch && cur_pfmt != new_pfmt)
+ return false;
+
+ if (cur_space == RGB && (cur_bpp == 2 || cur_bpp == 3) &&
+ cur_pfmt != new_pfmt)
+ return false;
+
+ if (!(mxc_fbi->cur_prefetch && mxc_fbi->prefetch) &&
+ ((cur_var.xres_virtual != fbi->var.xres_virtual) ||
+ (cur_var.xres != cur_var.xres_virtual) ||
+ (fbi->var.xres != fbi->var.xres_virtual)))
+ return false;
+
+ if (cur_space != new_space ||
+ (new_space == RGB && cur_bpp != new_bpp))
+ return false;
+
+ if (new_space == YCbCr)
+ return false;
+
+ mem_len = fbi->var.yres_virtual * fbi->fix.line_length;
+ if (mxc_fbi->resolve && mxc_fbi->gpu_sec_buf_off) {
+ if (fbi->var.vmode & FB_VMODE_YWRAP)
+ mem_len = mxc_fbi->gpu_sec_buf_off + mem_len / 2;
+ else
+ mem_len = mxc_fbi->gpu_sec_buf_off *
+ (fbi->var.yres_virtual / fbi->var.yres) + mem_len / 2;
+ }
+ if (mem_len > fbi->fix.smem_len)
+ return false;
+
+ if (mxc_fbi->resolve && ipu_pixel_format_is_gpu_tile(mxc_fbi->cur_fb_pfmt)) {
+ fmt_to_tile_block(mxc_fbi->cur_fb_pfmt, &cur_bw, &cur_bh);
+ fmt_to_tile_block(new_fb_pfmt, &new_bw, &new_bh);
+
+ if (cur_bw != new_bw || cur_bh != new_bh ||
+ cur_var.xoffset % cur_bw != fbi->var.xoffset % new_bw ||
+ cur_var.yoffset % cur_bh != fbi->var.yoffset % new_bh)
+ return false;
+ } else if (mxc_fbi->resolve && mxc_fbi->cur_prefetch) {
+ fmt_to_tile_block(new_fb_pfmt, &new_bw, &new_bh);
+ if (fbi->var.xoffset % new_bw || fbi->var.yoffset % new_bh ||
+ fbi->var.xres % 16 || fbi->var.yres %
+ (fbi->var.vmode & FB_VMODE_INTERLACED ? 8 : 4))
+ return false;
+ } else if (mxc_fbi->prefetch && ipu_pixel_format_is_gpu_tile(mxc_fbi->cur_fb_pfmt)) {
+ fmt_to_tile_block(mxc_fbi->cur_fb_pfmt, &cur_bw, &cur_bh);
+ if (cur_var.xoffset % cur_bw || cur_var.yoffset % cur_bh ||
+ cur_var.xres % 16 || cur_var.yres %
+ (cur_var.vmode & FB_VMODE_INTERLACED ? 8 : 4))
+ return false;
+ }
+
+ cur_var.xres_virtual = fbi->var.xres_virtual;
+ cur_var.yres_virtual = fbi->var.yres_virtual;
+ cur_var.xoffset = fbi->var.xoffset;
+ cur_var.yoffset = fbi->var.yoffset;
+ cur_var.red = fbi->var.red;
+ cur_var.green = fbi->var.green;
+ cur_var.blue = fbi->var.blue;
+ cur_var.transp = fbi->var.transp;
+ cur_var.nonstd = fbi->var.nonstd;
+ if (memcmp(&cur_var, &fbi->var,
+ sizeof(struct fb_var_screeninfo)))
+ return false;
+
+ *final_pfmt = cur_pfmt;
+
+ return true;
+}
+
+static void mxcfb_check_resolve(struct fb_info *fbi)
+{
+ struct mxcfb_info *mxc_fbi = fbi->par;
+
+ switch (fbi->var.nonstd) {
+ case IPU_PIX_FMT_GPU32_ST:
+ case IPU_PIX_FMT_GPU32_SRT:
+ case IPU_PIX_FMT_GPU16_ST:
+ case IPU_PIX_FMT_GPU16_SRT:
+ mxc_fbi->gpu_sec_buf_off = 0;
+ case IPU_PIX_FMT_GPU32_SB_ST:
+ case IPU_PIX_FMT_GPU32_SB_SRT:
+ case IPU_PIX_FMT_GPU16_SB_ST:
+ case IPU_PIX_FMT_GPU16_SB_SRT:
+ mxc_fbi->prefetch = true;
+ mxc_fbi->resolve = true;
+ break;
+ default:
+ mxc_fbi->resolve = false;
+ }
+}
+
+static void mxcfb_check_yuv(struct fb_info *fbi)
+{
+ struct mxcfb_info *mxc_fbi = fbi->par;
+
+ if (fbi->var.vmode & FB_VMODE_INTERLACED) {
+ if (ipu_pixel_format_is_multiplanar_yuv(fbi_to_pixfmt(fbi, true)))
+ mxc_fbi->prefetch = false;
+ } else {
+ if (fbi->var.nonstd == PRE_PIX_FMT_NV21 ||
+ fbi->var.nonstd == PRE_PIX_FMT_NV61)
+ mxc_fbi->prefetch = true;
+ }
+}
+
+/*
+ * Set framebuffer parameters and change the operating mode.
+ *
+ * @param info framebuffer information pointer
+ */
+static int mxcfb_set_par(struct fb_info *fbi)
+{
+ int retval = 0;
+ u32 mem_len, alpha_mem_len;
+ ipu_di_signal_cfg_t sig_cfg;
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
+ uint32_t final_pfmt = 0;
+ int16_t ov_pos_x = 0, ov_pos_y = 0;
+ int ov_pos_ret = 0;
+ struct mxcfb_info *mxc_fbi_fg = NULL;
+ bool ovfbi_enable = false, on_the_fly;
+
+ if (ipu_ch_param_bad_alpha_pos(fbi_to_pixfmt(fbi, true)) &&
+ mxc_fbi->alpha_chan_en) {
+ dev_err(fbi->device, "Bad pixel format for "
+ "graphics plane fb\n");
+ return -EINVAL;
+ }
+
+ if (mxc_fbi->ovfbi)
+ mxc_fbi_fg = (struct mxcfb_info *)mxc_fbi->ovfbi->par;
+
+ if (mxc_fbi->ovfbi && mxc_fbi_fg)
+ if (mxc_fbi_fg->next_blank == FB_BLANK_UNBLANK)
+ ovfbi_enable = true;
+
+ if (!mxcfb_need_to_set_par(fbi))
+ return 0;
+
+ dev_dbg(fbi->device, "Reconfiguring framebuffer\n");
+
+ if (fbi->var.xres == 0 || fbi->var.yres == 0)
+ return 0;
+
+ mxcfb_set_fix(fbi);
+
+ mxcfb_check_resolve(fbi);
+
+ mxcfb_check_yuv(fbi);
+
+ on_the_fly = mxcfb_can_set_par_on_the_fly(fbi, &final_pfmt);
+ mxc_fbi->on_the_fly = on_the_fly;
+ mxc_fbi->final_pfmt = final_pfmt;
+
+ if (on_the_fly)
+ dev_dbg(fbi->device, "Reconfiguring framebuffer on the fly\n");
+
+ if (ovfbi_enable) {
+ ov_pos_ret = ipu_disp_get_window_pos(
+ mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch,
+ &ov_pos_x, &ov_pos_y);
+ if (ov_pos_ret < 0)
+ dev_err(fbi->device, "Get overlay pos failed, dispdrv:%s.\n",
+ mxc_fbi->dispdrv->drv->name);
+
+ if (!on_the_fly) {
+ ipu_clear_irq(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch_irq);
+ ipu_disable_irq(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch_irq);
+ ipu_clear_irq(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch_nf_irq);
+ ipu_disable_irq(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch_nf_irq);
+ ipu_disable_channel(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch, true);
+ ipu_uninit_channel(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch);
+ if (mxc_fbi_fg->cur_prefetch) {
+ ipu_prg_disable(mxc_fbi_fg->ipu_id, mxc_fbi_fg->pre_num);
+ ipu_pre_disable(mxc_fbi_fg->pre_num);
+ ipu_pre_free(&mxc_fbi_fg->pre_num);
+ }
+ }
+ }
+
+ if (!on_the_fly) {
+ ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
+ ipu_disable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
+ ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_nf_irq);
+ ipu_disable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_nf_irq);
+ ipu_disable_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch, true);
+ ipu_uninit_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch);
+ if (mxc_fbi->cur_prefetch) {
+ ipu_prg_disable(mxc_fbi->ipu_id, mxc_fbi->pre_num);
+ ipu_pre_disable(mxc_fbi->pre_num);
+ ipu_pre_free(&mxc_fbi->pre_num);
+ }
+ }
+
+ /*
+ * Disable IPU hsp clock if it is enabled for an
+ * additional time in ipu common driver.
+ */
+ if (mxc_fbi->first_set_par && mxc_fbi->late_init)
+ ipu_disable_hsp_clk(mxc_fbi->ipu);
+
+ mem_len = fbi->var.yres_virtual * fbi->fix.line_length;
+ if (mxc_fbi->resolve && mxc_fbi->gpu_sec_buf_off) {
+ if (fbi->var.vmode & FB_VMODE_YWRAP)
+ mem_len = mxc_fbi->gpu_sec_buf_off + mem_len / 2;
+ else
+ mem_len = mxc_fbi->gpu_sec_buf_off *
+ (fbi->var.yres_virtual / fbi->var.yres) + mem_len / 2;
+ }
+ if (!fbi->fix.smem_start || (mem_len > fbi->fix.smem_len)) {
+ if (fbi->fix.smem_start)
+ mxcfb_unmap_video_memory(fbi);
+
+ if (mxcfb_map_video_memory(fbi) < 0)
+ return -ENOMEM;
+ }
+
+ if (mxc_fbi->first_set_par) {
+ /*
+ * Clear the screen in case uboot fb pixel format is not
+ * the same to kernel fb pixel format.
+ */
+ if (mxc_fbi->late_init)
+ memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
+
+ mxc_fbi->first_set_par = false;
+ }
+
+ if (mxc_fbi->alpha_chan_en) {
+ alpha_mem_len = fbi->var.xres * fbi->var.yres;
+ if ((!mxc_fbi->alpha_phy_addr0 && !mxc_fbi->alpha_phy_addr1) ||
+ (alpha_mem_len > mxc_fbi->alpha_mem_len)) {
+ if (mxc_fbi->alpha_phy_addr0)
+ dma_free_coherent(fbi->device,
+ mxc_fbi->alpha_mem_len,
+ mxc_fbi->alpha_virt_addr0,
+ mxc_fbi->alpha_phy_addr0);
+ if (mxc_fbi->alpha_phy_addr1)
+ dma_free_coherent(fbi->device,
+ mxc_fbi->alpha_mem_len,
+ mxc_fbi->alpha_virt_addr1,
+ mxc_fbi->alpha_phy_addr1);
+
+ mxc_fbi->alpha_virt_addr0 =
+ dma_alloc_coherent(fbi->device,
+ alpha_mem_len,
+ &mxc_fbi->alpha_phy_addr0,
+ GFP_DMA | GFP_KERNEL);
+
+ mxc_fbi->alpha_virt_addr1 =
+ dma_alloc_coherent(fbi->device,
+ alpha_mem_len,
+ &mxc_fbi->alpha_phy_addr1,
+ GFP_DMA | GFP_KERNEL);
+ if (mxc_fbi->alpha_virt_addr0 == NULL ||
+ mxc_fbi->alpha_virt_addr1 == NULL) {
+ dev_err(fbi->device, "mxcfb: dma alloc for"
+ " alpha buffer failed.\n");
+ if (mxc_fbi->alpha_virt_addr0)
+ dma_free_coherent(fbi->device,
+ mxc_fbi->alpha_mem_len,
+ mxc_fbi->alpha_virt_addr0,
+ mxc_fbi->alpha_phy_addr0);
+ if (mxc_fbi->alpha_virt_addr1)
+ dma_free_coherent(fbi->device,
+ mxc_fbi->alpha_mem_len,
+ mxc_fbi->alpha_virt_addr1,
+ mxc_fbi->alpha_phy_addr1);
+ return -ENOMEM;
+ }
+ mxc_fbi->alpha_mem_len = alpha_mem_len;
+ }
+ }
+
+ if (mxc_fbi->next_blank != FB_BLANK_UNBLANK)
+ return retval;
+
+ if (!on_the_fly && mxc_fbi->dispdrv && mxc_fbi->dispdrv->drv->setup) {
+ retval = mxc_fbi->dispdrv->drv->setup(mxc_fbi->dispdrv, fbi);
+ if (retval < 0) {
+ dev_err(fbi->device, "setup error, dispdrv:%s.\n",
+ mxc_fbi->dispdrv->drv->name);
+ return -EINVAL;
+ }
+ }
+
+ if (!on_the_fly) {
+ _setup_disp_channel1(fbi);
+ if (ovfbi_enable)
+ _setup_disp_channel1(mxc_fbi->ovfbi);
+ }
+
+ if (!mxc_fbi->overlay && !on_the_fly) {
+ uint32_t out_pixel_fmt;
+
+ memset(&sig_cfg, 0, sizeof(sig_cfg));
+ if (fbi->var.vmode & FB_VMODE_INTERLACED)
+ sig_cfg.interlaced = true;
+ out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
+ if (fbi->var.vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
+ sig_cfg.odd_field_first = true;
+ if (mxc_fbi->ipu_int_clk)
+ sig_cfg.int_clk = true;
+ if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ sig_cfg.Hsync_pol = true;
+ if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ sig_cfg.Vsync_pol = true;
+ if (!(fbi->var.sync & FB_SYNC_CLK_LAT_FALL))
+ sig_cfg.clk_pol = true;
+ if (fbi->var.sync & FB_SYNC_DATA_INVERT)
+ sig_cfg.data_pol = true;
+ if (!(fbi->var.sync & FB_SYNC_OE_LOW_ACT))
+ sig_cfg.enable_pol = true;
+ if (fbi->var.sync & FB_SYNC_CLK_IDLE_EN)
+ sig_cfg.clkidle_en = true;
+
+ dev_dbg(fbi->device, "pixclock = %ul Hz\n",
+ (u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL));
+
+ if (ipu_init_sync_panel(mxc_fbi->ipu, mxc_fbi->ipu_di,
+ (PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
+ fbi->var.xres, fbi->var.yres,
+ out_pixel_fmt,
+ fbi->var.left_margin,
+ fbi->var.hsync_len,
+ fbi->var.right_margin,
+ fbi->var.upper_margin,
+ fbi->var.vsync_len,
+ fbi->var.lower_margin,
+ 0, sig_cfg) != 0) {
+ dev_err(fbi->device,
+ "mxcfb: Error initializing panel.\n");
+ return -EINVAL;
+ }
+
+ fbi->mode =
+ (struct fb_videomode *)fb_match_mode(&fbi->var,
+ &fbi->modelist);
+
+ ipu_disp_set_window_pos(mxc_fbi->ipu, mxc_fbi->ipu_ch, 0, 0);
+ }
+
+ retval = _setup_disp_channel2(fbi);
+ if (retval) {
+ if (!on_the_fly)
+ ipu_uninit_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch);
+ return retval;
+ }
+
+ if (ovfbi_enable && !on_the_fly) {
+ if (ov_pos_ret >= 0)
+ ipu_disp_set_window_pos(
+ mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch,
+ ov_pos_x, ov_pos_y);
+ retval = _setup_disp_channel2(mxc_fbi->ovfbi);
+ if (retval) {
+ ipu_uninit_channel(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch);
+ ipu_uninit_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch);
+ return retval;
+ }
+ }
+
+ if (!on_the_fly) {
+ ipu_enable_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch);
+ if (ovfbi_enable)
+ ipu_enable_channel(mxc_fbi_fg->ipu, mxc_fbi_fg->ipu_ch);
+ }
+
+ if (!on_the_fly && mxc_fbi->dispdrv && mxc_fbi->dispdrv->drv->enable) {
+ retval = mxc_fbi->dispdrv->drv->enable(mxc_fbi->dispdrv, fbi);
+ if (retval < 0) {
+ dev_err(fbi->device, "enable error, dispdrv:%s.\n",
+ mxc_fbi->dispdrv->drv->name);
+ return -EINVAL;
+ }
+ }
+
+ mxc_fbi->cur_var = fbi->var;
+ mxc_fbi->cur_ipu_pfmt = on_the_fly ? mxc_fbi->final_pfmt :
+ fbi_to_pixfmt(fbi, false);
+ mxc_fbi->cur_fb_pfmt = fbi_to_pixfmt(fbi, true);
+ mxc_fbi->cur_prefetch = mxc_fbi->prefetch;
+
+ return retval;
+}
+
+static int _swap_channels(struct fb_info *fbi_from,
+ struct fb_info *fbi_to, bool both_on)
+{
+ int retval, tmp;
+ ipu_channel_t old_ch;
+ struct fb_info *ovfbi;
+ struct mxcfb_info *mxc_fbi_from = (struct mxcfb_info *)fbi_from->par;
+ struct mxcfb_info *mxc_fbi_to = (struct mxcfb_info *)fbi_to->par;
+
+ if (both_on) {
+ ipu_disable_channel(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch, true);
+ ipu_uninit_channel(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch);
+ }
+
+ /* switch the mxc fbi parameters */
+ old_ch = mxc_fbi_from->ipu_ch;
+ mxc_fbi_from->ipu_ch = mxc_fbi_to->ipu_ch;
+ mxc_fbi_to->ipu_ch = old_ch;
+ tmp = mxc_fbi_from->ipu_ch_irq;
+ mxc_fbi_from->ipu_ch_irq = mxc_fbi_to->ipu_ch_irq;
+ mxc_fbi_to->ipu_ch_irq = tmp;
+ tmp = mxc_fbi_from->ipu_ch_nf_irq;
+ mxc_fbi_from->ipu_ch_nf_irq = mxc_fbi_to->ipu_ch_nf_irq;
+ mxc_fbi_to->ipu_ch_nf_irq = tmp;
+ ovfbi = mxc_fbi_from->ovfbi;
+ mxc_fbi_from->ovfbi = mxc_fbi_to->ovfbi;
+ mxc_fbi_to->ovfbi = ovfbi;
+
+ _setup_disp_channel1(fbi_from);
+ retval = _setup_disp_channel2(fbi_from);
+ if (retval)
+ return retval;
+
+ /* switch between dp and dc, disable old idmac, enable new idmac */
+ retval = ipu_swap_channel(mxc_fbi_from->ipu, old_ch, mxc_fbi_from->ipu_ch);
+ ipu_uninit_channel(mxc_fbi_from->ipu, old_ch);
+
+ if (both_on) {
+ _setup_disp_channel1(fbi_to);
+ retval = _setup_disp_channel2(fbi_to);
+ if (retval)
+ return retval;
+ ipu_enable_channel(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch);
+ }
+
+ return retval;
+}
+
+static int swap_channels(struct fb_info *fbi_from)
+{
+ int i;
+ int swap_mode;
+ ipu_channel_t ch_to;
+ struct mxcfb_info *mxc_fbi_from = (struct mxcfb_info *)fbi_from->par;
+ struct fb_info *fbi_to = NULL;
+ struct mxcfb_info *mxc_fbi_to;
+
+ /* what's the target channel? */
+ if (mxc_fbi_from->ipu_ch == MEM_BG_SYNC)
+ ch_to = MEM_DC_SYNC;
+ else
+ ch_to = MEM_BG_SYNC;
+
+ fbi_to = found_registered_fb(ch_to, mxc_fbi_from->ipu_id);
+ if (!fbi_to)
+ return -1;
+ mxc_fbi_to = (struct mxcfb_info *)fbi_to->par;
+
+ ipu_clear_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_irq);
+ ipu_clear_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_irq);
+ ipu_free_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_irq, fbi_from);
+ ipu_free_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_irq, fbi_to);
+ ipu_clear_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_nf_irq);
+ ipu_clear_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_nf_irq);
+ ipu_free_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_nf_irq, fbi_from);
+ ipu_free_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_nf_irq, fbi_to);
+
+ if (mxc_fbi_from->cur_blank == FB_BLANK_UNBLANK) {
+ if (mxc_fbi_to->cur_blank == FB_BLANK_UNBLANK)
+ swap_mode = BOTH_ON;
+ else
+ swap_mode = SRC_ON;
+ } else {
+ if (mxc_fbi_to->cur_blank == FB_BLANK_UNBLANK)
+ swap_mode = TGT_ON;
+ else
+ swap_mode = BOTH_OFF;
+ }
+
+ switch (swap_mode) {
+ case BOTH_ON:
+ /* disable target->switch src->enable target */
+ _swap_channels(fbi_from, fbi_to, true);
+ break;
+ case SRC_ON:
+ /* just switch src */
+ _swap_channels(fbi_from, fbi_to, false);
+ break;
+ case TGT_ON:
+ /* just switch target */
+ _swap_channels(fbi_to, fbi_from, false);
+ break;
+ case BOTH_OFF:
+ /* switch directly, no more need to do */
+ mxc_fbi_to->ipu_ch = mxc_fbi_from->ipu_ch;
+ mxc_fbi_from->ipu_ch = ch_to;
+ i = mxc_fbi_from->ipu_ch_irq;
+ mxc_fbi_from->ipu_ch_irq = mxc_fbi_to->ipu_ch_irq;
+ mxc_fbi_to->ipu_ch_irq = i;
+ i = mxc_fbi_from->ipu_ch_nf_irq;
+ mxc_fbi_from->ipu_ch_nf_irq = mxc_fbi_to->ipu_ch_nf_irq;
+ mxc_fbi_to->ipu_ch_nf_irq = i;
+ break;
+ default:
+ break;
+ }
+
+ if (ipu_request_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_irq,
+ mxcfb_irq_handler, IPU_IRQF_ONESHOT,
+ MXCFB_NAME, fbi_from) != 0) {
+ dev_err(fbi_from->device, "Error registering irq %d\n",
+ mxc_fbi_from->ipu_ch_irq);
+ return -EBUSY;
+ }
+ ipu_disable_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_irq);
+ if (ipu_request_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_irq,
+ mxcfb_irq_handler, IPU_IRQF_ONESHOT,
+ MXCFB_NAME, fbi_to) != 0) {
+ dev_err(fbi_to->device, "Error registering irq %d\n",
+ mxc_fbi_to->ipu_ch_irq);
+ return -EBUSY;
+ }
+ ipu_disable_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_irq);
+ if (ipu_request_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_nf_irq,
+ mxcfb_nf_irq_handler, IPU_IRQF_ONESHOT,
+ MXCFB_NAME, fbi_from) != 0) {
+ dev_err(fbi_from->device, "Error registering irq %d\n",
+ mxc_fbi_from->ipu_ch_nf_irq);
+ return -EBUSY;
+ }
+ ipu_disable_irq(mxc_fbi_from->ipu, mxc_fbi_from->ipu_ch_nf_irq);
+ if (ipu_request_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_nf_irq,
+ mxcfb_nf_irq_handler, IPU_IRQF_ONESHOT,
+ MXCFB_NAME, fbi_to) != 0) {
+ dev_err(fbi_to->device, "Error registering irq %d\n",
+ mxc_fbi_to->ipu_ch_nf_irq);
+ return -EBUSY;
+ }
+ ipu_disable_irq(mxc_fbi_to->ipu, mxc_fbi_to->ipu_ch_nf_irq);
+
+ return 0;
+}
+
+/*
+ * Check framebuffer variable parameters and adjust to valid values.
+ *
+ * @param var framebuffer variable parameters
+ *
+ * @param info framebuffer information pointer
+ */
+static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ u32 vtotal;
+ u32 htotal;
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par;
+ struct fb_info tmp_fbi;
+ unsigned int fr_xoff, fr_yoff, fr_w, fr_h, line_length;
+ unsigned long base = 0;
+ int ret, bw = 0, bh = 0;
+ bool triple_buffer = false;
+
+ if (var->xres == 0 || var->yres == 0)
+ return 0;
+
+ /* fg should not bigger than bg */
+ if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {
+ struct fb_info *fbi_tmp;
+ int bg_xres = 0, bg_yres = 0;
+ int16_t pos_x, pos_y;
+
+ bg_xres = var->xres;
+ bg_yres = var->yres;
+
+ fbi_tmp = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
+ if (!fbi_tmp) {
+ dev_err(info->device,
+ "cannot find background fb for overlay fb\n");
+ return -EINVAL;
+ }
+
+ bg_xres = fbi_tmp->var.xres;
+ bg_yres = fbi_tmp->var.yres;
+
+ ipu_disp_get_window_pos(mxc_fbi->ipu, mxc_fbi->ipu_ch, &pos_x, &pos_y);
+
+ if ((var->xres + pos_x) > bg_xres)
+ var->xres = bg_xres - pos_x;
+ if ((var->yres + pos_y) > bg_yres)
+ var->yres = bg_yres - pos_y;
+
+ if (fbi_tmp->var.vmode & FB_VMODE_INTERLACED)
+ var->vmode |= FB_VMODE_INTERLACED;
+ else
+ var->vmode &= ~FB_VMODE_INTERLACED;
+
+ var->pixclock = fbi_tmp->var.pixclock;
+ var->right_margin = fbi_tmp->var.right_margin;
+ var->hsync_len = fbi_tmp->var.hsync_len;
+ var->left_margin = fbi_tmp->var.left_margin +
+ fbi_tmp->var.xres - var->xres;
+ var->upper_margin = fbi_tmp->var.upper_margin;
+ var->vsync_len = fbi_tmp->var.vsync_len;
+ var->lower_margin = fbi_tmp->var.lower_margin +
+ fbi_tmp->var.yres - var->yres;
+ }
+
+ if (var->rotate > IPU_ROTATE_VERT_FLIP)
+ var->rotate = IPU_ROTATE_NONE;
+
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+
+ if (var->yres_virtual < var->yres) {
+ var->yres_virtual = var->yres * 3;
+ triple_buffer = true;
+ }
+
+ if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
+ (var->bits_per_pixel != 16) && (var->bits_per_pixel != 12) &&
+ (var->bits_per_pixel != 8))
+ var->bits_per_pixel = 16;
+
+ if (check_var_pixfmt(var)) {
+ /* Fall back to default */
+ ret = bpp_to_var(var->bits_per_pixel, var);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (ipu_pixel_format_is_gpu_tile(var->nonstd)) {
+ fmt_to_tile_alignment(var->nonstd, &bw, &bh);
+ var->xres_virtual = ALIGN(var->xres_virtual, bw);
+ if (triple_buffer)
+ var->yres_virtual = 3 * ALIGN(var->yres, bh);
+ else
+ var->yres_virtual = ALIGN(var->yres_virtual, bh);
+ }
+
+ line_length = var->xres_virtual * var->bits_per_pixel / 8;
+ fr_xoff = var->xoffset;
+ fr_w = var->xres_virtual;
+ if (!(var->vmode & FB_VMODE_YWRAP)) {
+ fr_yoff = var->yoffset % var->yres;
+ fr_h = var->yres;
+ base = line_length * var->yres *
+ (var->yoffset / var->yres);
+ if (ipu_pixel_format_is_split_gpu_tile(var->nonstd))
+ base += (mxc_fbi->gpu_sec_buf_off -
+ line_length * var->yres / 2) *
+ (var->yoffset / var->yres);
+ } else {
+ fr_yoff = var->yoffset;
+ fr_h = var->yres_virtual;
+ }
+
+ tmp_fbi.device = info->device;
+ tmp_fbi.var = *var;
+ tmp_fbi.par = mxc_fbi;
+ if (ipu_pixel_format_is_gpu_tile(var->nonstd)) {
+ unsigned int crop_line, prg_width = var->xres, offset;
+ int ipu_stride, prg_stride, bs;
+ bool tmp_prefetch = mxc_fbi->prefetch;
+
+ if (!(var->xres % 32))
+ bs = 32;
+ else if (!(var->xres % 16))
+ bs = 16;
+ else
+ bs = 32;
+
+ prg_width += fr_xoff % bw;
+ if (((fr_xoff % bw) + prg_width) % bs)
+ prg_width = ALIGN(prg_width, bs);
+
+ mxc_fbi->prefetch = true;
+ ipu_stride = prg_width *
+ bytes_per_pixel(fbi_to_pixfmt(&tmp_fbi, false));
+
+ if (var->vmode & FB_VMODE_INTERLACED) {
+ if ((fr_yoff % bh) % 2) {
+ dev_err(info->device,
+ "wrong crop value in interlaced mode\n");
+ return -EINVAL;
+ }
+ crop_line = (fr_yoff % bh) / 2;
+ prg_stride = ipu_stride * 2;
+ } else {
+ crop_line = fr_yoff % bh;
+ prg_stride = ipu_stride;
+ }
+
+ offset = crop_line * prg_stride +
+ (fr_xoff % bw) *
+ bytes_per_pixel(fbi_to_pixfmt(&tmp_fbi, false));
+ mxc_fbi->prefetch = tmp_prefetch;
+ if (offset % 8) {
+ dev_err(info->device,
+ "IPU base address is not 8byte aligned\n");
+ return -EINVAL;
+ }
+ } else {
+ unsigned int uoff = 0, voff = 0;
+ int fb_stride;
+
+ switch (fbi_to_pixfmt(&tmp_fbi, true)) {
+ case IPU_PIX_FMT_YUV420P2:
+ case IPU_PIX_FMT_YVU420P:
+ case IPU_PIX_FMT_NV12:
+ case PRE_PIX_FMT_NV21:
+ case IPU_PIX_FMT_NV16:
+ case PRE_PIX_FMT_NV61:
+ case IPU_PIX_FMT_YUV422P:
+ case IPU_PIX_FMT_YVU422P:
+ case IPU_PIX_FMT_YUV420P:
+ case IPU_PIX_FMT_YUV444P:
+ fb_stride = var->xres_virtual;
+ break;
+ default:
+ fb_stride = line_length;
+ }
+ base += fr_yoff * fb_stride +
+ fr_xoff * var->bits_per_pixel / 8;
+
+ ipu_get_channel_offset(fbi_to_pixfmt(&tmp_fbi, true),
+ var->xres,
+ fr_h,
+ fr_w,
+ 0, 0,
+ fr_yoff,
+ fr_xoff,
+ &uoff,
+ &voff);
+ if (base % 8 || uoff % 8 || voff % 8) {
+ dev_err(info->device,
+ "IPU base address is not 8byte aligned\n");
+ return -EINVAL;
+ }
+ }
+
+ if (var->pixclock < 1000) {
+ htotal = var->xres + var->right_margin + var->hsync_len +
+ var->left_margin;
+ vtotal = var->yres + var->lower_margin + var->vsync_len +
+ var->upper_margin;
+ var->pixclock = (vtotal * htotal * 6UL) / 100UL;
+ var->pixclock = KHZ2PICOS(var->pixclock);
+ dev_dbg(info->device,
+ "pixclock set for 60Hz refresh = %u ps\n",
+ var->pixclock);
+ }
+
+ var->height = -1;
+ var->width = -1;
+ var->grayscale = 0;
+
+ return 0;
+}
+
+static inline u_int _chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+static int mxcfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int trans, struct fb_info *fbi)
+{
+ unsigned int val;
+ int ret = 1;
+
+ /*
+ * If greyscale is true, then we convert the RGB value
+ * to greyscale no matter what visual we are using.
+ */
+ if (fbi->var.grayscale)
+ red = green = blue = (19595 * red + 38470 * green +
+ 7471 * blue) >> 16;
+ switch (fbi->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ /*
+ * 16-bit True Colour. We encode the RGB value
+ * according to the RGB bitfield information.
+ */
+ if (regno < 16) {
+ u32 *pal = fbi->pseudo_palette;
+
+ val = _chan_to_field(red, &fbi->var.red);
+ val |= _chan_to_field(green, &fbi->var.green);
+ val |= _chan_to_field(blue, &fbi->var.blue);
+
+ pal[regno] = val;
+ ret = 0;
+ }
+ break;
+
+ case FB_VISUAL_STATIC_PSEUDOCOLOR:
+ case FB_VISUAL_PSEUDOCOLOR:
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Function to handle custom ioctls for MXC framebuffer.
+ *
+ * @param inode inode struct
+ *
+ * @param file file struct
+ *
+ * @param cmd Ioctl command to handle
+ *
+ * @param arg User pointer to command arguments
+ *
+ * @param fbi framebuffer information pointer
+ */
+static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ int __user *argp = (void __user *)arg;
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
+
+ switch (cmd) {
+ case MXCFB_SET_GBL_ALPHA:
+ {
+ struct mxcfb_gbl_alpha ga;
+
+ if (copy_from_user(&ga, (void *)arg, sizeof(ga))) {
+ retval = -EFAULT;
+ break;
+ }
+
+ if (ipu_disp_set_global_alpha(mxc_fbi->ipu,
+ mxc_fbi->ipu_ch,
+ (bool)ga.enable,
+ ga.alpha)) {
+ retval = -EINVAL;
+ break;
+ }
+
+ if (ga.enable)
+ mxc_fbi->alpha_chan_en = false;
+
+ if (ga.enable)
+ dev_dbg(fbi->device,
+ "Set global alpha of %s to %d\n",
+ fbi->fix.id, ga.alpha);
+ break;
+ }
+ case MXCFB_SET_LOC_ALPHA:
+ {
+ struct mxcfb_loc_alpha la;
+ bool bad_pixfmt =
+ ipu_ch_param_bad_alpha_pos(fbi_to_pixfmt(fbi, true));
+
+ if (copy_from_user(&la, (void *)arg, sizeof(la))) {
+ retval = -EFAULT;
+ break;
+ }
+
+ if (la.enable && !la.alpha_in_pixel) {
+ struct fb_info *fbi_tmp;
+ ipu_channel_t ipu_ch;
+
+ if (bad_pixfmt) {
+ dev_err(fbi->device, "Bad pixel format "
+ "for graphics plane fb\n");
+ retval = -EINVAL;
+ break;
+ }
+
+ mxc_fbi->alpha_chan_en = true;
+
+ if (mxc_fbi->ipu_ch == MEM_FG_SYNC)
+ ipu_ch = MEM_BG_SYNC;
+ else if (mxc_fbi->ipu_ch == MEM_BG_SYNC)
+ ipu_ch = MEM_FG_SYNC;
+ else {
+ retval = -EINVAL;
+ break;
+ }
+
+ fbi_tmp = found_registered_fb(ipu_ch, mxc_fbi->ipu_id);
+ if (fbi_tmp)
+ ((struct mxcfb_info *)(fbi_tmp->par))->alpha_chan_en = false;
+ } else
+ mxc_fbi->alpha_chan_en = false;
+
+ if (ipu_disp_set_global_alpha(mxc_fbi->ipu,
+ mxc_fbi->ipu_ch,
+ !(bool)la.enable, 0)) {
+ retval = -EINVAL;
+ break;
+ }
+
+ fbi->var.activate = (fbi->var.activate & ~FB_ACTIVATE_MASK) |
+ FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
+ mxcfb_set_par(fbi);
+
+ la.alpha_phy_addr0 = mxc_fbi->alpha_phy_addr0;
+ la.alpha_phy_addr1 = mxc_fbi->alpha_phy_addr1;
+ if (copy_to_user((void *)arg, &la, sizeof(la))) {
+ retval = -EFAULT;
+ break;
+ }
+
+ if (la.enable)
+ dev_dbg(fbi->device,
+ "Enable DP local alpha for %s\n",
+ fbi->fix.id);
+ break;
+ }
+ case MXCFB_SET_LOC_ALP_BUF:
+ {
+ unsigned long base;
+ uint32_t ipu_alp_ch_irq;
+
+ if (!(((mxc_fbi->ipu_ch == MEM_FG_SYNC) ||
+ (mxc_fbi->ipu_ch == MEM_BG_SYNC)) &&
+ (mxc_fbi->alpha_chan_en))) {
+ dev_err(fbi->device,
+ "Should use background or overlay "
+ "framebuffer to set the alpha buffer "
+ "number\n");
+ return -EINVAL;
+ }
+
+ if (get_user(base, argp))
+ return -EFAULT;
+
+ if (base != mxc_fbi->alpha_phy_addr0 &&
+ base != mxc_fbi->alpha_phy_addr1) {
+ dev_err(fbi->device,
+ "Wrong alpha buffer physical address "
+ "%lu\n", base);
+ return -EINVAL;
+ }
+
+ if (mxc_fbi->ipu_ch == MEM_FG_SYNC)
+ ipu_alp_ch_irq = IPU_IRQ_FG_ALPHA_SYNC_EOF;
+ else
+ ipu_alp_ch_irq = IPU_IRQ_BG_ALPHA_SYNC_EOF;
+
+ retval = wait_for_completion_timeout(
+ &mxc_fbi->alpha_flip_complete, HZ/2);
+ if (retval == 0) {
+ dev_err(fbi->device, "timeout when waiting for alpha flip irq\n");
+ retval = -ETIMEDOUT;
+ break;
+ }
+
+ mxc_fbi->cur_ipu_alpha_buf =
+ !mxc_fbi->cur_ipu_alpha_buf;
+ if (ipu_update_channel_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch,
+ IPU_ALPHA_IN_BUFFER,
+ mxc_fbi->
+ cur_ipu_alpha_buf,
+ base) == 0) {
+ ipu_select_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch,
+ IPU_ALPHA_IN_BUFFER,
+ mxc_fbi->cur_ipu_alpha_buf);
+ ipu_clear_irq(mxc_fbi->ipu, ipu_alp_ch_irq);
+ ipu_enable_irq(mxc_fbi->ipu, ipu_alp_ch_irq);
+ } else {
+ dev_err(fbi->device,
+ "Error updating %s SDC alpha buf %d "
+ "to address=0x%08lX\n",
+ fbi->fix.id,
+ mxc_fbi->cur_ipu_alpha_buf, base);
+ }
+ break;
+ }
+ case MXCFB_SET_CLR_KEY:
+ {
+ struct mxcfb_color_key key;
+ if (copy_from_user(&key, (void *)arg, sizeof(key))) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = ipu_disp_set_color_key(mxc_fbi->ipu, mxc_fbi->ipu_ch,
+ key.enable,
+ key.color_key);
+ dev_dbg(fbi->device, "Set color key to 0x%08X\n",
+ key.color_key);
+ break;
+ }
+ case MXCFB_SET_GAMMA:
+ {
+ struct mxcfb_gamma gamma;
+ if (copy_from_user(&gamma, (void *)arg, sizeof(gamma))) {
+ retval = -EFAULT;
+ break;
+ }
+ retval = ipu_disp_set_gamma_correction(mxc_fbi->ipu,
+ mxc_fbi->ipu_ch,
+ gamma.enable,
+ gamma.constk,
+ gamma.slopek);
+ break;
+ }
+ case MXCFB_SET_GPU_SPLIT_FMT:
+ {
+ struct mxcfb_gpu_split_fmt fmt;
+
+ if (copy_from_user(&fmt, (void *)arg, sizeof(fmt))) {
+ retval = -EFAULT;
+ break;
+ }
+
+ if (fmt.var.nonstd != IPU_PIX_FMT_GPU32_SB_ST &&
+ fmt.var.nonstd != IPU_PIX_FMT_GPU32_SB_SRT &&
+ fmt.var.nonstd != IPU_PIX_FMT_GPU16_SB_ST &&
+ fmt.var.nonstd != IPU_PIX_FMT_GPU16_SB_SRT) {
+ retval = -EINVAL;
+ break;
+ }
+
+ mxc_fbi->gpu_sec_buf_off = fmt.offset;
+ fmt.var.activate = (fbi->var.activate & ~FB_ACTIVATE_MASK) |
+ FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
+ console_lock();
+ fbi->flags |= FBINFO_MISC_USEREVENT;
+ retval = fb_set_var(fbi, &fmt.var);
+ fbi->flags &= ~FBINFO_MISC_USEREVENT;
+ console_unlock();
+ break;
+ }
+ case MXCFB_SET_PREFETCH:
+ {
+ int enable;
+
+ if (copy_from_user(&enable, (void *)arg, sizeof(enable))) {
+ retval = -EFAULT;
+ break;
+ }
+
+ if (!enable) {
+ if (ipu_pixel_format_is_gpu_tile(fbi_to_pixfmt(fbi, true))) {
+ dev_err(fbi->device, "Cannot disable prefetch in "
+ "resolving mode\n");
+ retval = -EINVAL;
+ break;
+ }
+ if (ipu_pixel_format_is_pre_yuv(fbi_to_pixfmt(fbi, true))) {
+ dev_err(fbi->device, "Cannot disable prefetch when "
+ "PRE gets NV61 or NV21\n");
+ retval = -EINVAL;
+ break;
+ }
+ } else {
+ if ((fbi->var.vmode & FB_VMODE_INTERLACED) &&
+ ipu_pixel_format_is_multiplanar_yuv(fbi_to_pixfmt(fbi, true))) {
+ dev_err(fbi->device, "Cannot enable prefetch when "
+ "PRE gets multiplanar YUV frames\n");
+ retval = -EINVAL;
+ break;
+ }
+ }
+
+ retval = mxcfb_check_var(&fbi->var, fbi);
+ if (retval)
+ break;
+
+ mxc_fbi->prefetch = !!enable;
+
+ if (mxc_fbi->cur_prefetch == mxc_fbi->prefetch)
+ break;
+
+ fbi->var.activate = (fbi->var.activate & ~FB_ACTIVATE_MASK) |
+ FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
+ retval = mxcfb_set_par(fbi);
+ break;
+ }
+ case MXCFB_GET_PREFETCH:
+ {
+ struct mxcfb_info *mxc_fbi =
+ (struct mxcfb_info *)fbi->par;
+
+ if (put_user(mxc_fbi->cur_prefetch, argp))
+ return -EFAULT;
+ break;
+ }
+ case MXCFB_WAIT_FOR_VSYNC:
+ {
+ if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {
+ /* BG should poweron */
+ struct mxcfb_info *bg_mxcfbi = NULL;
+ struct fb_info *fbi_tmp;
+
+ fbi_tmp = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
+ if (fbi_tmp)
+ bg_mxcfbi = ((struct mxcfb_info *)(fbi_tmp->par));
+
+ if (!bg_mxcfbi) {
+ retval = -EINVAL;
+ break;
+ }
+ if (bg_mxcfbi->cur_blank != FB_BLANK_UNBLANK) {
+ retval = -EINVAL;
+ break;
+ }
+ }
+ if (mxc_fbi->cur_blank != FB_BLANK_UNBLANK) {
+ retval = -EINVAL;
+ break;
+ }
+
+ init_completion(&mxc_fbi->vsync_complete);
+ ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_nf_irq);
+ ipu_enable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_nf_irq);
+ retval = wait_for_completion_interruptible_timeout(
+ &mxc_fbi->vsync_complete, 1 * HZ);
+ if (retval == 0) {
+ dev_err(fbi->device,
+ "MXCFB_WAIT_FOR_VSYNC: timeout %d\n",
+ retval);
+ retval = -ETIME;
+ } else if (retval > 0) {
+ retval = 0;
+ }
+ break;
+ }
+ case FBIO_ALLOC:
+ {
+ int size;
+ struct mxcfb_alloc_list *mem;
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (mem == NULL)
+ return -ENOMEM;
+
+ if (get_user(size, argp)) {
+ kfree(mem);
+ return -EFAULT;
+ }
+
+ mem->size = PAGE_ALIGN(size);
+
+ mem->cpu_addr = dma_alloc_coherent(fbi->device, size,
+ &mem->phy_addr,
+ GFP_KERNEL);
+ if (mem->cpu_addr == NULL) {
+ kfree(mem);
+ return -ENOMEM;
+ }
+
+ list_add(&mem->list, &fb_alloc_list);
+
+ if (put_user(mem->phy_addr, argp)) {
+ list_del(&mem->list);
+ dma_free_coherent(fbi->device,
+ mem->size,
+ mem->cpu_addr,
+ mem->phy_addr);
+ kfree(mem);
+ return -EFAULT;
+ }
+
+ dev_dbg(fbi->device, "allocated %d bytes @ 0x%08X\n",
+ mem->size, mem->phy_addr);
+
+ break;
+ }
+ case FBIO_FREE:
+ {
+ unsigned long offset;
+ struct mxcfb_alloc_list *mem;
+
+ if (get_user(offset, argp))
+ return -EFAULT;
+
+ retval = -EINVAL;
+ list_for_each_entry(mem, &fb_alloc_list, list) {
+ if (mem->phy_addr == offset) {
+ list_del(&mem->list);
+ dma_free_coherent(fbi->device,
+ mem->size,
+ mem->cpu_addr,
+ mem->phy_addr);
+ kfree(mem);
+ retval = 0;
+ break;
+ }
+ }
+
+ break;
+ }
+ case MXCFB_SET_OVERLAY_POS:
+ {
+ struct mxcfb_pos pos;
+ struct fb_info *bg_fbi = NULL;
+ struct mxcfb_info *bg_mxcfbi = NULL;
+
+ if (mxc_fbi->ipu_ch != MEM_FG_SYNC) {
+ dev_err(fbi->device, "Should use the overlay "
+ "framebuffer to set the position of "
+ "the overlay window\n");
+ retval = -EINVAL;
+ break;
+ }
+
+ if (copy_from_user(&pos, (void *)arg, sizeof(pos))) {
+ retval = -EFAULT;
+ break;
+ }
+
+ bg_fbi = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
+ if (bg_fbi)
+ bg_mxcfbi = ((struct mxcfb_info *)(bg_fbi->par));
+
+ if (bg_fbi == NULL) {
+ dev_err(fbi->device, "Cannot find the "
+ "background framebuffer\n");
+ retval = -ENOENT;
+ break;
+ }
+
+ /* if fb is unblank, check if the pos fit the display */
+ if (mxc_fbi->cur_blank == FB_BLANK_UNBLANK) {
+ if (fbi->var.xres + pos.x > bg_fbi->var.xres) {
+ if (bg_fbi->var.xres < fbi->var.xres)
+ pos.x = 0;
+ else
+ pos.x = bg_fbi->var.xres - fbi->var.xres;
+ }
+ if (fbi->var.yres + pos.y > bg_fbi->var.yres) {
+ if (bg_fbi->var.yres < fbi->var.yres)
+ pos.y = 0;
+ else
+ pos.y = bg_fbi->var.yres - fbi->var.yres;
+ }
+ }
+
+ retval = ipu_disp_set_window_pos(mxc_fbi->ipu, mxc_fbi->ipu_ch,
+ pos.x, pos.y);
+
+ if (copy_to_user((void *)arg, &pos, sizeof(pos))) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case MXCFB_GET_FB_IPU_CHAN:
+ {
+ struct mxcfb_info *mxc_fbi =
+ (struct mxcfb_info *)fbi->par;
+
+ if (put_user(mxc_fbi->ipu_ch, argp))
+ return -EFAULT;
+ break;
+ }
+ case MXCFB_GET_DIFMT:
+ {
+ struct mxcfb_info *mxc_fbi =
+ (struct mxcfb_info *)fbi->par;
+
+ if (put_user(mxc_fbi->ipu_di_pix_fmt, argp))
+ return -EFAULT;
+ break;
+ }
+ case MXCFB_GET_FB_IPU_DI:
+ {
+ struct mxcfb_info *mxc_fbi =
+ (struct mxcfb_info *)fbi->par;
+
+ if (put_user(mxc_fbi->ipu_di, argp))
+ return -EFAULT;
+ break;
+ }
+ case MXCFB_GET_FB_BLANK:
+ {
+ struct mxcfb_info *mxc_fbi =
+ (struct mxcfb_info *)fbi->par;
+
+ if (put_user(mxc_fbi->cur_blank, argp))
+ return -EFAULT;
+ break;
+ }
+ case MXCFB_SET_DIFMT:
+ {
+ struct mxcfb_info *mxc_fbi =
+ (struct mxcfb_info *)fbi->par;
+
+ if (get_user(mxc_fbi->ipu_di_pix_fmt, argp))
+ return -EFAULT;
+
+ break;
+ }
+ case MXCFB_CSC_UPDATE:
+ {
+ struct mxcfb_csc_matrix csc;
+
+ if (copy_from_user(&csc, (void *) arg, sizeof(csc)))
+ return -EFAULT;
+
+ if ((mxc_fbi->ipu_ch != MEM_FG_SYNC) &&
+ (mxc_fbi->ipu_ch != MEM_BG_SYNC) &&
+ (mxc_fbi->ipu_ch != MEM_BG_ASYNC0))
+ return -EFAULT;
+ ipu_set_csc_coefficients(mxc_fbi->ipu, mxc_fbi->ipu_ch,
+ csc.param);
+ break;
+ }
+ default:
+ retval = -EINVAL;
+ }
+ return retval;
+}
+
+/*
+ * mxcfb_blank():
+ * Blank the display.
+ */
+static int mxcfb_blank(int blank, struct fb_info *info)
+{
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par;
+ int ret = 0;
+
+ dev_dbg(info->device, "blank = %d\n", blank);
+
+ if (blank)
+ blank = FB_BLANK_POWERDOWN;
+
+ if (mxc_fbi->cur_blank == blank)
+ return 0;
+
+ mxc_fbi->next_blank = blank;
+
+ if (blank == FB_BLANK_UNBLANK) {
+ info->var.activate = (info->var.activate & ~FB_ACTIVATE_MASK) |
+ FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
+ ret = fb_set_var(info, &info->var);
+ } else {
+ if (mxc_fbi->dispdrv && mxc_fbi->dispdrv->drv->disable)
+ mxc_fbi->dispdrv->drv->disable(mxc_fbi->dispdrv, info);
+ ipu_disable_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch, true);
+ if (mxc_fbi->ipu_di >= 0)
+ ipu_uninit_sync_panel(mxc_fbi->ipu, mxc_fbi->ipu_di);
+ ipu_uninit_channel(mxc_fbi->ipu, mxc_fbi->ipu_ch);
+ if (mxc_fbi->cur_prefetch) {
+ ipu_prg_disable(mxc_fbi->ipu_id, mxc_fbi->pre_num);
+ ipu_pre_disable(mxc_fbi->pre_num);
+ ipu_pre_free(&mxc_fbi->pre_num);
+ }
+ }
+ if (!ret)
+ mxc_fbi->cur_blank = blank;
+ return ret;
+}
+
+/*
+ * Pan or Wrap the Display
+ *
+ * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+ *
+ * @param var Variable screen buffer information
+ * @param info Framebuffer information pointer
+ */
+static int
+mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par,
+ *mxc_graphic_fbi = NULL;
+ u_int y_bottom;
+ unsigned int fr_xoff, fr_yoff, fr_w, fr_h;
+ unsigned long base, ipu_base = 0, active_alpha_phy_addr = 0;
+ bool loc_alpha_en = false;
+ int fb_stride;
+ int bw = 0, bh = 0;
+ int i;
+ int ret;
+
+ /* no pan display during fb blank */
+ if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {
+ struct mxcfb_info *bg_mxcfbi = NULL;
+ struct fb_info *fbi_tmp;
+
+ fbi_tmp = found_registered_fb(MEM_BG_SYNC, mxc_fbi->ipu_id);
+ if (fbi_tmp)
+ bg_mxcfbi = ((struct mxcfb_info *)(fbi_tmp->par));
+ if (!bg_mxcfbi)
+ return -EINVAL;
+ if (bg_mxcfbi->cur_blank != FB_BLANK_UNBLANK)
+ return -EINVAL;
+ }
+ if (mxc_fbi->cur_blank != FB_BLANK_UNBLANK)
+ return -EINVAL;
+
+ if (mxc_fbi->resolve) {
+ fmt_to_tile_block(info->var.nonstd, &bw, &bh);
+
+ if (mxc_fbi->cur_var.xoffset % bw != var->xoffset % bw ||
+ mxc_fbi->cur_var.yoffset % bh != var->yoffset % bh) {
+ dev_err(info->device, "do not support panning "
+ "with tile crop settings changed\n");
+ return -EINVAL;
+ }
+ }
+
+ y_bottom = var->yoffset;
+
+ if (y_bottom > info->var.yres_virtual)
+ return -EINVAL;
+
+ switch (fbi_to_pixfmt(info, true)) {
+ case IPU_PIX_FMT_YUV420P2:
+ case IPU_PIX_FMT_YVU420P:
+ case IPU_PIX_FMT_NV12:
+ case PRE_PIX_FMT_NV21:
+ case IPU_PIX_FMT_NV16:
+ case PRE_PIX_FMT_NV61:
+ case IPU_PIX_FMT_YUV422P:
+ case IPU_PIX_FMT_YVU422P:
+ case IPU_PIX_FMT_YUV420P:
+ case IPU_PIX_FMT_YUV444P:
+ fb_stride = info->var.xres_virtual;
+ break;
+ default:
+ fb_stride = info->fix.line_length;
+ }
+
+ base = info->fix.smem_start;
+ fr_xoff = var->xoffset;
+ fr_w = info->var.xres_virtual;
+ if (!(var->vmode & FB_VMODE_YWRAP)) {
+ dev_dbg(info->device, "Y wrap disabled\n");
+ fr_yoff = var->yoffset % info->var.yres;
+ fr_h = info->var.yres;
+ base += info->fix.line_length * info->var.yres *
+ (var->yoffset / info->var.yres);
+ if (ipu_pixel_format_is_split_gpu_tile(var->nonstd))
+ base += (mxc_fbi->gpu_sec_buf_off -
+ info->fix.line_length * info->var.yres / 2) *
+ (var->yoffset / info->var.yres);
+ } else {
+ dev_dbg(info->device, "Y wrap enabled\n");
+ fr_yoff = var->yoffset;
+ fr_h = info->var.yres_virtual;
+ }
+ if (!mxc_fbi->resolve) {
+ base += fr_yoff * fb_stride + fr_xoff *
+ bytes_per_pixel(fbi_to_pixfmt(info, true));
+
+ if (mxc_fbi->cur_prefetch && (info->var.vmode & FB_VMODE_INTERLACED))
+ base += info->var.rotate ?
+ fr_w * bytes_per_pixel(fbi_to_pixfmt(info, true)) : 0;
+ }
+
+ if (mxc_fbi->cur_prefetch) {
+ unsigned long lock_flags = 0;
+
+ if (ipu_pre_yres_is_small(info->var.yres))
+ /*
+ * Update the PRE buffer address in the flip interrupt
+ * handler in this case to workaround the SoC design
+ * bug recorded by errata ERR009624.
+ */
+ spin_lock_irqsave(&mxc_fbi->spin_lock, lock_flags);
+
+ if (mxc_fbi->resolve) {
+ mxc_fbi->x_crop = fr_xoff & ~(bw - 1);
+ mxc_fbi->y_crop = fr_yoff & ~(bh - 1);
+ } else {
+ mxc_fbi->x_crop = 0;
+ mxc_fbi->y_crop = 0;
+ }
+
+ ipu_get_channel_offset(fbi_to_pixfmt(info, true),
+ info->var.xres,
+ fr_h,
+ fr_w,
+ 0, 0,
+ fr_yoff,
+ fr_xoff,
+ &mxc_fbi->sec_buf_off,
+ &mxc_fbi->trd_buf_off);
+ if (mxc_fbi->resolve)
+ mxc_fbi->sec_buf_off = mxc_fbi->gpu_sec_buf_off;
+
+ if (ipu_pre_yres_is_small(info->var.yres)) {
+ mxc_fbi->base = base;
+ spin_unlock_irqrestore(&mxc_fbi->spin_lock, lock_flags);
+ }
+ } else {
+ ipu_base = base;
+ }
+
+ /* Check if DP local alpha is enabled and find the graphic fb */
+ if (mxc_fbi->ipu_ch == MEM_BG_SYNC || mxc_fbi->ipu_ch == MEM_FG_SYNC) {
+ for (i = 0; i < num_registered_fb; i++) {
+ char bg_id[] = "DISP3 BG";
+ char fg_id[] = "DISP3 FG";
+ char *idstr = registered_fb[i]->fix.id;
+ bg_id[4] += mxc_fbi->ipu_id;
+ fg_id[4] += mxc_fbi->ipu_id;
+ if ((strcmp(idstr, bg_id) == 0 ||
+ strcmp(idstr, fg_id) == 0) &&
+ ((struct mxcfb_info *)
+ (registered_fb[i]->par))->alpha_chan_en) {
+ loc_alpha_en = true;
+ mxc_graphic_fbi = (struct mxcfb_info *)
+ (registered_fb[i]->par);
+ active_alpha_phy_addr =
+ mxc_fbi->cur_ipu_alpha_buf ?
+ mxc_graphic_fbi->alpha_phy_addr1 :
+ mxc_graphic_fbi->alpha_phy_addr0;
+ dev_dbg(info->device, "Updating SDC alpha "
+ "buf %d address=0x%08lX\n",
+ !mxc_fbi->cur_ipu_alpha_buf,
+ active_alpha_phy_addr);
+ break;
+ }
+ }
+ }
+
+ if (!mxc_fbi->cur_prefetch ||
+ (mxc_fbi->cur_prefetch && !ipu_pre_yres_is_small(info->var.yres))) {
+ ret = wait_for_completion_timeout(&mxc_fbi->flip_complete,
+ HZ/2);
+ if (ret == 0) {
+ dev_err(info->device, "timeout when waiting for flip "
+ "irq\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ if (!mxc_fbi->cur_prefetch) {
+ ++mxc_fbi->cur_ipu_buf;
+ mxc_fbi->cur_ipu_buf %= 3;
+ dev_dbg(info->device, "Updating SDC %s buf %d address=0x%08lX\n",
+ info->fix.id, mxc_fbi->cur_ipu_buf, base);
+ }
+ mxc_fbi->cur_ipu_alpha_buf = !mxc_fbi->cur_ipu_alpha_buf;
+
+ if (mxc_fbi->cur_prefetch)
+ goto next;
+
+ if (ipu_update_channel_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
+ mxc_fbi->cur_ipu_buf, ipu_base) == 0) {
+next:
+ /* Update the DP local alpha buffer only for graphic plane */
+ if (loc_alpha_en && mxc_graphic_fbi == mxc_fbi &&
+ ipu_update_channel_buffer(mxc_graphic_fbi->ipu, mxc_graphic_fbi->ipu_ch,
+ IPU_ALPHA_IN_BUFFER,
+ mxc_fbi->cur_ipu_alpha_buf,
+ active_alpha_phy_addr) == 0) {
+ ipu_select_buffer(mxc_graphic_fbi->ipu, mxc_graphic_fbi->ipu_ch,
+ IPU_ALPHA_IN_BUFFER,
+ mxc_fbi->cur_ipu_alpha_buf);
+ }
+
+ /* update u/v offset */
+ if (!mxc_fbi->cur_prefetch) {
+ ipu_update_channel_offset(mxc_fbi->ipu, mxc_fbi->ipu_ch,
+ IPU_INPUT_BUFFER,
+ fbi_to_pixfmt(info, true),
+ fr_w,
+ fr_h,
+ fr_w,
+ 0, 0,
+ fr_yoff,
+ fr_xoff);
+
+ ipu_select_buffer(mxc_fbi->ipu, mxc_fbi->ipu_ch,
+ IPU_INPUT_BUFFER, mxc_fbi->cur_ipu_buf);
+ } else if (!ipu_pre_yres_is_small(info->var.yres)) {
+ ipu_pre_set_fb_buffer(mxc_fbi->pre_num,
+ mxc_fbi->resolve,
+ base, info->var.yres,
+ mxc_fbi->x_crop,
+ mxc_fbi->y_crop,
+ mxc_fbi->sec_buf_off,
+ mxc_fbi->trd_buf_off);
+ }
+ ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
+ ipu_enable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
+ } else {
+ dev_err(info->device,
+ "Error updating SDC buf %d to address=0x%08lX, "
+ "current buf %d, buf0 ready %d, buf1 ready %d, "
+ "buf2 ready %d\n", mxc_fbi->cur_ipu_buf, base,
+ ipu_get_cur_buffer_idx(mxc_fbi->ipu, mxc_fbi->ipu_ch,
+ IPU_INPUT_BUFFER),
+ ipu_check_buffer_ready(mxc_fbi->ipu, mxc_fbi->ipu_ch,
+ IPU_INPUT_BUFFER, 0),
+ ipu_check_buffer_ready(mxc_fbi->ipu, mxc_fbi->ipu_ch,
+ IPU_INPUT_BUFFER, 1),
+ ipu_check_buffer_ready(mxc_fbi->ipu, mxc_fbi->ipu_ch,
+ IPU_INPUT_BUFFER, 2));
+ if (!mxc_fbi->cur_prefetch) {
+ ++mxc_fbi->cur_ipu_buf;
+ mxc_fbi->cur_ipu_buf %= 3;
+ ++mxc_fbi->cur_ipu_buf;
+ mxc_fbi->cur_ipu_buf %= 3;
+ }
+ mxc_fbi->cur_ipu_alpha_buf = !mxc_fbi->cur_ipu_alpha_buf;
+ ipu_clear_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
+ ipu_enable_irq(mxc_fbi->ipu, mxc_fbi->ipu_ch_irq);
+ return -EBUSY;
+ }
+
+ if (mxc_fbi->cur_prefetch && ipu_pre_yres_is_small(info->var.yres)) {
+ ret = wait_for_completion_timeout(&mxc_fbi->flip_complete,
+ HZ/2);
+ if (ret == 0) {
+ dev_err(info->device, "timeout when waiting for flip "
+ "irq\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ dev_dbg(info->device, "Update complete\n");
+
+ info->var.yoffset = var->yoffset;
+ mxc_fbi->cur_var.xoffset = var->xoffset;
+ mxc_fbi->cur_var.yoffset = var->yoffset;
+
+ return 0;
+}
+
+/*
+ * Function to handle custom mmap for MXC framebuffer.
+ *
+ * @param fbi framebuffer information pointer
+ *
+ * @param vma Pointer to vm_area_struct
+ */
+static int mxcfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
+{
+ bool found = false;
+ u32 len;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ struct mxcfb_alloc_list *mem;
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
+
+ if (offset < fbi->fix.smem_len) {
+ /* mapping framebuffer memory */
+ len = fbi->fix.smem_len - offset;
+ vma->vm_pgoff = (fbi->fix.smem_start + offset) >> PAGE_SHIFT;
+ } else if ((vma->vm_pgoff ==
+ (mxc_fbi->alpha_phy_addr0 >> PAGE_SHIFT)) ||
+ (vma->vm_pgoff ==
+ (mxc_fbi->alpha_phy_addr1 >> PAGE_SHIFT))) {
+ len = mxc_fbi->alpha_mem_len;
+ } else {
+ list_for_each_entry(mem, &fb_alloc_list, list) {
+ if (offset == mem->phy_addr) {
+ found = true;
+ len = mem->size;
+ break;
+ }
+ }
+ if (!found)
+ return -EINVAL;
+ }
+
+ len = PAGE_ALIGN(len);
+ if (vma->vm_end - vma->vm_start > len)
+ return -EINVAL;
+
+ /* make buffers bufferable */
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ vma->vm_flags |= VM_IO;
+
+ if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
+ dev_dbg(fbi->device, "mmap remap_pfn_range failed\n");
+ return -ENOBUFS;
+ }
+
+ return 0;
+}
+
+/*!
+ * This structure contains the pointers to the control functions that are
+ * invoked by the core framebuffer driver to perform operations like
+ * blitting, rectangle filling, copy regions and cursor definition.
+ */
+static struct fb_ops mxcfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_set_par = mxcfb_set_par,
+ .fb_check_var = mxcfb_check_var,
+ .fb_setcolreg = mxcfb_setcolreg,
+ .fb_pan_display = mxcfb_pan_display,
+ .fb_ioctl = mxcfb_ioctl,
+ .fb_mmap = mxcfb_mmap,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_blank = mxcfb_blank,
+};
+
+static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id)
+{
+ struct fb_info *fbi = dev_id;
+ struct mxcfb_info *mxc_fbi = fbi->par;
+
+ if (mxc_fbi->pre_config) {
+ ipu_pre_set_ctrl(mxc_fbi->pre_num, mxc_fbi->pre_config);
+ mxc_fbi->pre_config = NULL;
+ complete(&mxc_fbi->otf_complete);
+ return IRQ_HANDLED;
+ }
+
+ if (mxc_fbi->cur_prefetch && ipu_pre_yres_is_small(fbi->var.yres)) {
+ spin_lock(&mxc_fbi->spin_lock);
+ ipu_pre_set_fb_buffer(mxc_fbi->pre_num,
+ mxc_fbi->resolve,
+ mxc_fbi->base, fbi->var.yres,
+ mxc_fbi->x_crop, mxc_fbi->y_crop,
+ mxc_fbi->sec_buf_off,
+ mxc_fbi->trd_buf_off);
+ spin_unlock(&mxc_fbi->spin_lock);
+ }
+
+ complete(&mxc_fbi->flip_complete);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mxcfb_nf_irq_handler(int irq, void *dev_id)
+{
+ struct fb_info *fbi = dev_id;
+ struct mxcfb_info *mxc_fbi = fbi->par;
+
+ complete(&mxc_fbi->vsync_complete);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mxcfb_alpha_irq_handler(int irq, void *dev_id)
+{
+ struct fb_info *fbi = dev_id;
+ struct mxcfb_info *mxc_fbi = fbi->par;
+
+ complete(&mxc_fbi->alpha_flip_complete);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Suspends the framebuffer and blanks the screen. Power management support
+ */
+static int mxcfb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct fb_info *fbi = platform_get_drvdata(pdev);
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
+ int saved_blank;
+#ifdef CONFIG_FB_MXC_LOW_PWR_DISPLAY
+ void *fbmem;
+#endif
+
+ if (mxc_fbi->ovfbi) {
+ struct mxcfb_info *mxc_fbi_fg =
+ (struct mxcfb_info *)mxc_fbi->ovfbi->par;
+
+ console_lock();
+ fb_set_suspend(mxc_fbi->ovfbi, 1);
+ saved_blank = mxc_fbi_fg->cur_blank;
+ mxcfb_blank(FB_BLANK_POWERDOWN, mxc_fbi->ovfbi);
+ mxc_fbi_fg->next_blank = saved_blank;
+ console_unlock();
+ }
+
+ console_lock();
+ fb_set_suspend(fbi, 1);
+ saved_blank = mxc_fbi->cur_blank;
+ mxcfb_blank(FB_BLANK_POWERDOWN, fbi);
+ mxc_fbi->next_blank = saved_blank;
+ console_unlock();
+
+ return 0;
+}
+
+/*
+ * Resumes the framebuffer and unblanks the screen. Power management support
+ */
+static int mxcfb_resume(struct platform_device *pdev)
+{
+ struct fb_info *fbi = platform_get_drvdata(pdev);
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
+
+ console_lock();
+ mxcfb_blank(mxc_fbi->next_blank, fbi);
+ fb_set_suspend(fbi, 0);
+ console_unlock();
+
+ if (mxc_fbi->ovfbi) {
+ struct mxcfb_info *mxc_fbi_fg =
+ (struct mxcfb_info *)mxc_fbi->ovfbi->par;
+ console_lock();
+ mxcfb_blank(mxc_fbi_fg->next_blank, mxc_fbi->ovfbi);
+ fb_set_suspend(mxc_fbi->ovfbi, 0);
+ console_unlock();
+ }
+
+ return 0;
+}
+
+/*
+ * Main framebuffer functions
+ */
+
+/*!
+ * Allocates the DRAM memory for the frame buffer. This buffer is remapped
+ * into a non-cached, non-buffered, memory region to allow palette and pixel
+ * writes to occur without flushing the cache. Once this area is remapped,
+ * all virtual memory access to the video memory should occur at the new region.
+ *
+ * @param fbi framebuffer information pointer
+ *
+ * @return Error code indicating success or failure
+ */
+static int mxcfb_map_video_memory(struct fb_info *fbi)
+{
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
+
+ if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length)
+ fbi->fix.smem_len = fbi->var.yres_virtual *
+ fbi->fix.line_length;
+
+ if (mxc_fbi->resolve && mxc_fbi->gpu_sec_buf_off) {
+ if (fbi->var.vmode & FB_VMODE_YWRAP)
+ fbi->fix.smem_len = mxc_fbi->gpu_sec_buf_off +
+ fbi->fix.smem_len / 2;
+ else
+ fbi->fix.smem_len = mxc_fbi->gpu_sec_buf_off *
+ (fbi->var.yres_virtual / fbi->var.yres) +
+ fbi->fix.smem_len / 2;
+ }
+
+ fbi->screen_base = dma_alloc_writecombine(fbi->device,
+ fbi->fix.smem_len,
+ (dma_addr_t *)&fbi->fix.smem_start,
+ GFP_DMA | GFP_KERNEL);
+ if (fbi->screen_base == 0) {
+ dev_err(fbi->device, "Unable to allocate framebuffer memory\n");
+ fbi->fix.smem_len = 0;
+ fbi->fix.smem_start = 0;
+ return -EBUSY;
+ }
+
+ dev_dbg(fbi->device, "allocated fb @ paddr=0x%08X, size=%d.\n",
+ (uint32_t) fbi->fix.smem_start, fbi->fix.smem_len);
+
+ fbi->screen_size = fbi->fix.smem_len;
+
+ /* Clear the screen */
+ memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
+
+ return 0;
+}
+
+/*!
+ * De-allocates the DRAM memory for the frame buffer.
+ *
+ * @param fbi framebuffer information pointer
+ *
+ * @return Error code indicating success or failure
+ */
+static int mxcfb_unmap_video_memory(struct fb_info *fbi)
+{
+ dma_free_writecombine(fbi->device, fbi->fix.smem_len,
+ fbi->screen_base, fbi->fix.smem_start);
+ fbi->screen_base = 0;
+ fbi->fix.smem_start = 0;
+ fbi->fix.smem_len = 0;
+ return 0;
+}
+
+/*!
+ * Initializes the framebuffer information pointer. After allocating
+ * sufficient memory for the framebuffer structure, the fields are
+ * filled with custom information passed in from the configurable
+ * structures. This includes information such as bits per pixel,
+ * color maps, screen width/height and RGBA offsets.
+ *
+ * @return Framebuffer structure initialized with our information
+ */
+static struct fb_info *mxcfb_init_fbinfo(struct device *dev, struct fb_ops *ops)
+{
+ struct fb_info *fbi;
+ struct mxcfb_info *mxcfbi;
+ struct ipuv3_fb_platform_data *plat_data = dev->platform_data;
+
+ /*
+ * Allocate sufficient memory for the fb structure
+ */
+ fbi = framebuffer_alloc(sizeof(struct mxcfb_info), dev);
+ if (!fbi)
+ return NULL;
+
+ mxcfbi = (struct mxcfb_info *)fbi->par;
+
+ fbi->var.activate = FB_ACTIVATE_NOW;
+
+ bpp_to_var(plat_data->default_bpp, &fbi->var);
+
+ fbi->fbops = ops;
+ fbi->flags = FBINFO_FLAG_DEFAULT;
+ fbi->pseudo_palette = mxcfbi->pseudo_palette;
+
+ /*
+ * Allocate colormap
+ */
+ fb_alloc_cmap(&fbi->cmap, 16, 0);
+
+ return fbi;
+}
+
+static ssize_t show_disp_chan(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct mxcfb_info *mxcfbi = (struct mxcfb_info *)info->par;
+
+ if (mxcfbi->ipu_ch == MEM_BG_SYNC)
+ return sprintf(buf, "2-layer-fb-bg\n");
+ else if (mxcfbi->ipu_ch == MEM_FG_SYNC)
+ return sprintf(buf, "2-layer-fb-fg\n");
+ else if (mxcfbi->ipu_ch == MEM_DC_SYNC)
+ return sprintf(buf, "1-layer-fb\n");
+ else
+ return sprintf(buf, "err: no display chan\n");
+}
+
+static ssize_t swap_disp_chan(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct mxcfb_info *mxcfbi = (struct mxcfb_info *)info->par;
+ struct mxcfb_info *fg_mxcfbi = NULL;
+
+ console_lock();
+ /* swap only happen between DP-BG and DC, while DP-FG disable */
+ if (((mxcfbi->ipu_ch == MEM_BG_SYNC) &&
+ (strstr(buf, "1-layer-fb") != NULL)) ||
+ ((mxcfbi->ipu_ch == MEM_DC_SYNC) &&
+ (strstr(buf, "2-layer-fb-bg") != NULL))) {
+ struct fb_info *fbi_fg;
+
+ fbi_fg = found_registered_fb(MEM_FG_SYNC, mxcfbi->ipu_id);
+ if (fbi_fg)
+ fg_mxcfbi = (struct mxcfb_info *)fbi_fg->par;
+
+ if (!fg_mxcfbi ||
+ fg_mxcfbi->cur_blank == FB_BLANK_UNBLANK) {
+ dev_err(dev,
+ "Can not switch while fb2(fb-fg) is on.\n");
+ console_unlock();
+ return count;
+ }
+
+ if (swap_channels(info) < 0)
+ dev_err(dev, "Swap display channel failed.\n");
+ }
+
+ console_unlock();
+ return count;
+}
+static DEVICE_ATTR(fsl_disp_property, S_IWUSR | S_IRUGO,
+ show_disp_chan, swap_disp_chan);
+
+static ssize_t show_disp_dev(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct mxcfb_info *mxcfbi = (struct mxcfb_info *)info->par;
+
+ if (mxcfbi->ipu_ch == MEM_FG_SYNC)
+ return sprintf(buf, "overlay\n");
+ else
+ return sprintf(buf, "%s\n", mxcfbi->dispdrv->drv->name);
+}
+static DEVICE_ATTR(fsl_disp_dev_property, S_IRUGO, show_disp_dev, NULL);
+
+static int mxcfb_get_crtc(struct device *dev, struct mxcfb_info *mxcfbi,
+ enum crtc crtc)
+{
+ int i = 0;
+
+ for (; i < ARRAY_SIZE(ipu_di_crtc_maps); i++)
+ if (ipu_di_crtc_maps[i].crtc == crtc) {
+ mxcfbi->ipu_id = ipu_di_crtc_maps[i].ipu_id;
+ mxcfbi->ipu_di = ipu_di_crtc_maps[i].ipu_di;
+ return 0;
+ }
+
+ dev_err(dev, "failed to get valid crtc\n");
+ return -EINVAL;
+}
+
+static int mxcfb_dispdrv_init(struct platform_device *pdev,
+ struct fb_info *fbi)
+{
+ struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
+ struct mxcfb_info *mxcfbi = (struct mxcfb_info *)fbi->par;
+ struct mxc_dispdrv_setting setting;
+ char disp_dev[32], *default_dev = "lcd";
+ int ret = 0;
+
+ setting.if_fmt = plat_data->interface_pix_fmt;
+ setting.dft_mode_str = plat_data->mode_str;
+ setting.default_bpp = plat_data->default_bpp;
+ if (!setting.default_bpp)
+ setting.default_bpp = 16;
+ setting.fbi = fbi;
+ if (!strlen(plat_data->disp_dev)) {
+ memcpy(disp_dev, default_dev, strlen(default_dev));
+ disp_dev[strlen(default_dev)] = '\0';
+ } else {
+ memcpy(disp_dev, plat_data->disp_dev,
+ strlen(plat_data->disp_dev));
+ disp_dev[strlen(plat_data->disp_dev)] = '\0';
+ }
+
+ mxcfbi->dispdrv = mxc_dispdrv_gethandle(disp_dev, &setting);
+ if (IS_ERR(mxcfbi->dispdrv)) {
+ ret = PTR_ERR(mxcfbi->dispdrv);
+ dev_err(&pdev->dev, "NO mxc display driver found!\n");
+ return ret;
+ } else {
+ /* fix-up */
+ mxcfbi->ipu_di_pix_fmt = setting.if_fmt;
+ mxcfbi->default_bpp = setting.default_bpp;
+
+ ret = mxcfb_get_crtc(&pdev->dev, mxcfbi, setting.crtc);
+ if (ret)
+ return ret;
+
+ dev_dbg(&pdev->dev, "di_pixfmt:0x%x, bpp:0x%x, di:%d, ipu:%d\n",
+ setting.if_fmt, setting.default_bpp,
+ mxcfbi->ipu_di, mxcfbi->ipu_id);
+ }
+
+ dev_info(&pdev->dev, "registered mxc display driver %s\n", disp_dev);
+
+ return ret;
+}
+
+/*
+ * Parse user specified options (`video=trident:')
+ * example:
+ * video=mxcfb0:dev=lcd,800x480M-16@55,if=RGB565,bpp=16,noaccel
+ * video=mxcfb0:dev=lcd,800x480M-16@55,if=RGB565,fbpix=RGB565
+ */
+static int mxcfb_option_setup(struct platform_device *pdev, struct fb_info *fbi)
+{
+ struct ipuv3_fb_platform_data *pdata = pdev->dev.platform_data;
+ char *options, *opt, *fb_mode_str = NULL;
+ char name[] = "mxcfb0";
+ uint32_t fb_pix_fmt = 0;
+
+ name[5] += pdev->id;
+ if (fb_get_options(name, &options)) {
+ dev_err(&pdev->dev, "Can't get fb option for %s!\n", name);
+ return -ENODEV;
+ }
+
+ if (!options || !*options)
+ return 0;
+
+ while ((opt = strsep(&options, ",")) != NULL) {
+ if (!*opt)
+ continue;
+
+ if (!strncmp(opt, "dev=", 4)) {
+ memcpy(pdata->disp_dev, opt + 4, strlen(opt) - 4);
+ pdata->disp_dev[strlen(opt) - 4] = '\0';
+ } else if (!strncmp(opt, "if=", 3)) {
+ if (!strncmp(opt+3, "RGB24", 5))
+ pdata->interface_pix_fmt = IPU_PIX_FMT_RGB24;
+ else if (!strncmp(opt+3, "BGR24", 5))
+ pdata->interface_pix_fmt = IPU_PIX_FMT_BGR24;
+ else if (!strncmp(opt+3, "GBR24", 5))
+ pdata->interface_pix_fmt = IPU_PIX_FMT_GBR24;
+ else if (!strncmp(opt+3, "RGB565", 6))
+ pdata->interface_pix_fmt = IPU_PIX_FMT_RGB565;
+ else if (!strncmp(opt+3, "RGB666", 6))
+ pdata->interface_pix_fmt = IPU_PIX_FMT_RGB666;
+ else if (!strncmp(opt+3, "YUV444", 6))
+ pdata->interface_pix_fmt = IPU_PIX_FMT_YUV444;
+ else if (!strncmp(opt+3, "LVDS666", 7))
+ pdata->interface_pix_fmt = IPU_PIX_FMT_LVDS666;
+ else if (!strncmp(opt+3, "YUYV16", 6))
+ pdata->interface_pix_fmt = IPU_PIX_FMT_YUYV;
+ else if (!strncmp(opt+3, "UYVY16", 6))
+ pdata->interface_pix_fmt = IPU_PIX_FMT_UYVY;
+ else if (!strncmp(opt+3, "YVYU16", 6))
+ pdata->interface_pix_fmt = IPU_PIX_FMT_YVYU;
+ else if (!strncmp(opt+3, "VYUY16", 6))
+ pdata->interface_pix_fmt = IPU_PIX_FMT_VYUY;
+ } else if (!strncmp(opt, "fbpix=", 6)) {
+ if (!strncmp(opt+6, "RGB24", 5))
+ fb_pix_fmt = IPU_PIX_FMT_RGB24;
+ else if (!strncmp(opt+6, "BGR24", 5))
+ fb_pix_fmt = IPU_PIX_FMT_BGR24;
+ else if (!strncmp(opt+6, "RGB32", 5))
+ fb_pix_fmt = IPU_PIX_FMT_RGB32;
+ else if (!strncmp(opt+6, "BGR32", 5))
+ fb_pix_fmt = IPU_PIX_FMT_BGR32;
+ else if (!strncmp(opt+6, "ABGR32", 6))
+ fb_pix_fmt = IPU_PIX_FMT_ABGR32;
+ else if (!strncmp(opt+6, "RGB565", 6))
+ fb_pix_fmt = IPU_PIX_FMT_RGB565;
+ else if (!strncmp(opt+6, "BGRA4444", 8))
+ fb_pix_fmt = IPU_PIX_FMT_BGRA4444;
+ else if (!strncmp(opt+6, "BGRA5551", 8))
+ fb_pix_fmt = IPU_PIX_FMT_BGRA5551;
+
+ if (fb_pix_fmt) {
+ pixfmt_to_var(fb_pix_fmt, &fbi->var);
+ pdata->default_bpp =
+ fbi->var.bits_per_pixel;
+ }
+ } else if (!strncmp(opt, "int_clk", 7)) {
+ pdata->int_clk = true;
+ continue;
+ } else if (!strncmp(opt, "bpp=", 4)) {
+ /* bpp setting cannot overwirte fbpix setting */
+ if (fb_pix_fmt)
+ continue;
+
+ pdata->default_bpp =
+ simple_strtoul(opt + 4, NULL, 0);
+
+ fb_pix_fmt = bpp_to_pixfmt(pdata->default_bpp);
+ if (fb_pix_fmt)
+ pixfmt_to_var(fb_pix_fmt, &fbi->var);
+ } else
+ fb_mode_str = opt;
+ }
+
+ if (fb_mode_str)
+ pdata->mode_str = fb_mode_str;
+
+ return 0;
+}
+
+static int mxcfb_register(struct fb_info *fbi)
+{
+ struct mxcfb_info *mxcfbi = (struct mxcfb_info *)fbi->par;
+ struct fb_videomode m;
+ int ret = 0;
+ char bg0_id[] = "DISP3 BG";
+ char bg1_id[] = "DISP3 BG - DI1";
+ char fg_id[] = "DISP3 FG";
+
+ if (mxcfbi->ipu_di == 0) {
+ bg0_id[4] += mxcfbi->ipu_id;
+ strcpy(fbi->fix.id, bg0_id);
+ } else if (mxcfbi->ipu_di == 1) {
+ bg1_id[4] += mxcfbi->ipu_id;
+ strcpy(fbi->fix.id, bg1_id);
+ } else { /* Overlay */
+ fg_id[4] += mxcfbi->ipu_id;
+ strcpy(fbi->fix.id, fg_id);
+ }
+
+ mxcfb_check_var(&fbi->var, fbi);
+
+ mxcfb_set_fix(fbi);
+
+ /* Added first mode to fbi modelist. */
+ if (!fbi->modelist.next || !fbi->modelist.prev)
+ INIT_LIST_HEAD(&fbi->modelist);
+ fb_var_to_videomode(&m, &fbi->var);
+ fb_add_videomode(&m, &fbi->modelist);
+
+ if (ipu_request_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq,
+ mxcfb_irq_handler, IPU_IRQF_ONESHOT, MXCFB_NAME, fbi) != 0) {
+ dev_err(fbi->device, "Error registering EOF irq handler.\n");
+ ret = -EBUSY;
+ goto err0;
+ }
+ ipu_disable_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq);
+ if (ipu_request_irq(mxcfbi->ipu, mxcfbi->ipu_ch_nf_irq,
+ mxcfb_nf_irq_handler, IPU_IRQF_ONESHOT, MXCFB_NAME, fbi) != 0) {
+ dev_err(fbi->device, "Error registering NFACK irq handler.\n");
+ ret = -EBUSY;
+ goto err1;
+ }
+ ipu_disable_irq(mxcfbi->ipu, mxcfbi->ipu_ch_nf_irq);
+
+ if (mxcfbi->ipu_alp_ch_irq != -1)
+ if (ipu_request_irq(mxcfbi->ipu, mxcfbi->ipu_alp_ch_irq,
+ mxcfb_alpha_irq_handler, IPU_IRQF_ONESHOT,
+ MXCFB_NAME, fbi) != 0) {
+ dev_err(fbi->device, "Error registering alpha irq "
+ "handler.\n");
+ ret = -EBUSY;
+ goto err2;
+ }
+
+ if (!mxcfbi->late_init) {
+ fbi->var.activate |= FB_ACTIVATE_FORCE;
+ console_lock();
+ fbi->flags |= FBINFO_MISC_USEREVENT;
+ ret = fb_set_var(fbi, &fbi->var);
+ fbi->flags &= ~FBINFO_MISC_USEREVENT;
+ console_unlock();
+ if (ret < 0) {
+ dev_err(fbi->device, "Error fb_set_var ret:%d\n", ret);
+ goto err3;
+ }
+
+ if (mxcfbi->next_blank == FB_BLANK_UNBLANK) {
+ console_lock();
+ ret = fb_blank(fbi, FB_BLANK_UNBLANK);
+ console_unlock();
+ if (ret < 0) {
+ dev_err(fbi->device,
+ "Error fb_blank ret:%d\n", ret);
+ goto err4;
+ }
+ }
+ } else {
+ /*
+ * Setup the channel again though bootloader
+ * has done this, then set_par() can stop the
+ * channel neatly and re-initialize it .
+ */
+ if (mxcfbi->next_blank == FB_BLANK_UNBLANK) {
+ console_lock();
+ _setup_disp_channel1(fbi);
+ ipu_enable_channel(mxcfbi->ipu, mxcfbi->ipu_ch);
+ console_unlock();
+ }
+ }
+
+
+ ret = register_framebuffer(fbi);
+ if (ret < 0)
+ goto err5;
+
+ return ret;
+err5:
+ if (mxcfbi->next_blank == FB_BLANK_UNBLANK) {
+ console_lock();
+ if (!mxcfbi->late_init)
+ fb_blank(fbi, FB_BLANK_POWERDOWN);
+ else {
+ ipu_disable_channel(mxcfbi->ipu, mxcfbi->ipu_ch,
+ true);
+ ipu_uninit_channel(mxcfbi->ipu, mxcfbi->ipu_ch);
+ }
+ console_unlock();
+ }
+err4:
+err3:
+ if (mxcfbi->ipu_alp_ch_irq != -1)
+ ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_alp_ch_irq, fbi);
+err2:
+ ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_ch_nf_irq, fbi);
+err1:
+ ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq, fbi);
+err0:
+ return ret;
+}
+
+static void mxcfb_unregister(struct fb_info *fbi)
+{
+ struct mxcfb_info *mxcfbi = (struct mxcfb_info *)fbi->par;
+
+ if (mxcfbi->ipu_alp_ch_irq != -1)
+ ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_alp_ch_irq, fbi);
+ if (mxcfbi->ipu_ch_irq)
+ ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq, fbi);
+ if (mxcfbi->ipu_ch_nf_irq)
+ ipu_free_irq(mxcfbi->ipu, mxcfbi->ipu_ch_nf_irq, fbi);
+
+ unregister_framebuffer(fbi);
+}
+
+static int mxcfb_setup_overlay(struct platform_device *pdev,
+ struct fb_info *fbi_bg, struct resource *res)
+{
+ struct fb_info *ovfbi;
+ struct mxcfb_info *mxcfbi_bg = (struct mxcfb_info *)fbi_bg->par;
+ struct mxcfb_info *mxcfbi_fg;
+ int ret = 0;
+
+ ovfbi = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ops);
+ if (!ovfbi) {
+ ret = -ENOMEM;
+ goto init_ovfbinfo_failed;
+ }
+ mxcfbi_fg = (struct mxcfb_info *)ovfbi->par;
+
+ mxcfbi_fg->ipu = ipu_get_soc(mxcfbi_bg->ipu_id);
+ if (IS_ERR(mxcfbi_fg->ipu)) {
+ ret = -ENODEV;
+ goto get_ipu_failed;
+ }
+ mxcfbi_fg->ipu_id = mxcfbi_bg->ipu_id;
+ mxcfbi_fg->ipu_ch_irq = IPU_IRQ_FG_SYNC_EOF;
+ mxcfbi_fg->ipu_ch_nf_irq = IPU_IRQ_FG_SYNC_NFACK;
+ mxcfbi_fg->ipu_alp_ch_irq = IPU_IRQ_FG_ALPHA_SYNC_EOF;
+ mxcfbi_fg->ipu_ch = MEM_FG_SYNC;
+ mxcfbi_fg->ipu_di = -1;
+ mxcfbi_fg->ipu_di_pix_fmt = mxcfbi_bg->ipu_di_pix_fmt;
+ mxcfbi_fg->overlay = true;
+ mxcfbi_fg->cur_blank = mxcfbi_fg->next_blank = FB_BLANK_POWERDOWN;
+ mxcfbi_fg->prefetch = false;
+ mxcfbi_fg->resolve = false;
+ mxcfbi_fg->pre_num = -1;
+
+ /* Need dummy values until real panel is configured */
+ ovfbi->var.xres = 240;
+ ovfbi->var.yres = 320;
+
+ if (res && res->start && res->end) {
+ ovfbi->fix.smem_len = res->end - res->start + 1;
+ ovfbi->fix.smem_start = res->start;
+ ovfbi->screen_base = ioremap(
+ ovfbi->fix.smem_start,
+ ovfbi->fix.smem_len);
+ }
+
+ ret = mxcfb_register(ovfbi);
+ if (ret < 0)
+ goto register_ov_failed;
+
+ mxcfbi_bg->ovfbi = ovfbi;
+
+ return ret;
+
+register_ov_failed:
+get_ipu_failed:
+ fb_dealloc_cmap(&ovfbi->cmap);
+ framebuffer_release(ovfbi);
+init_ovfbinfo_failed:
+ return ret;
+}
+
+static void mxcfb_unsetup_overlay(struct fb_info *fbi_bg)
+{
+ struct mxcfb_info *mxcfbi_bg = (struct mxcfb_info *)fbi_bg->par;
+ struct fb_info *ovfbi = mxcfbi_bg->ovfbi;
+
+ mxcfb_unregister(ovfbi);
+
+ if (&ovfbi->cmap)
+ fb_dealloc_cmap(&ovfbi->cmap);
+ framebuffer_release(ovfbi);
+}
+
+static bool ipu_usage[2][2];
+static int ipu_test_set_usage(int ipu, int di)
+{
+ if (ipu_usage[ipu][di])
+ return -EBUSY;
+ else
+ ipu_usage[ipu][di] = true;
+ return 0;
+}
+
+static void ipu_clear_usage(int ipu, int di)
+{
+ ipu_usage[ipu][di] = false;
+}
+
+static int mxcfb_get_of_property(struct platform_device *pdev,
+ struct ipuv3_fb_platform_data *plat_data)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const char *disp_dev;
+ const char *mode_str = NULL;
+ const char *pixfmt;
+ int err;
+ int len;
+ u32 bpp, int_clk;
+ u32 late_init;
+
+ err = of_property_read_string(np, "disp_dev", &disp_dev);
+ if (err < 0) {
+ dev_dbg(&pdev->dev, "get of property disp_dev fail\n");
+ return err;
+ }
+ err = of_property_read_string(np, "mode_str", &mode_str);
+ if (err < 0)
+ dev_dbg(&pdev->dev, "get of property mode_str fail\n");
+ err = of_property_read_string(np, "interface_pix_fmt", &pixfmt);
+ if (err) {
+ dev_dbg(&pdev->dev, "get of property pix fmt fail\n");
+ return err;
+ }
+ err = of_property_read_u32(np, "default_bpp", &bpp);
+ if (err) {
+ dev_dbg(&pdev->dev, "get of property bpp fail\n");
+ return err;
+ }
+ err = of_property_read_u32(np, "int_clk", &int_clk);
+ if (err) {
+ dev_dbg(&pdev->dev, "get of property int_clk fail\n");
+ return err;
+ }
+ err = of_property_read_u32(np, "late_init", &late_init);
+ if (err) {
+ dev_dbg(&pdev->dev, "get of property late_init fail\n");
+ return err;
+ }
+
+ plat_data->prefetch = of_property_read_bool(np, "prefetch");
+
+ if (!strncmp(pixfmt, "RGB24", 5))
+ plat_data->interface_pix_fmt = IPU_PIX_FMT_RGB24;
+ else if (!strncmp(pixfmt, "BGR24", 5))
+ plat_data->interface_pix_fmt = IPU_PIX_FMT_BGR24;
+ else if (!strncmp(pixfmt, "GBR24", 5))
+ plat_data->interface_pix_fmt = IPU_PIX_FMT_GBR24;
+ else if (!strncmp(pixfmt, "RGB565", 6))
+ plat_data->interface_pix_fmt = IPU_PIX_FMT_RGB565;
+ else if (!strncmp(pixfmt, "RGB666", 6))
+ plat_data->interface_pix_fmt = IPU_PIX_FMT_RGB666;
+ else if (!strncmp(pixfmt, "YUV444", 6))
+ plat_data->interface_pix_fmt = IPU_PIX_FMT_YUV444;
+ else if (!strncmp(pixfmt, "LVDS666", 7))
+ plat_data->interface_pix_fmt = IPU_PIX_FMT_LVDS666;
+ else if (!strncmp(pixfmt, "YUYV16", 6))
+ plat_data->interface_pix_fmt = IPU_PIX_FMT_YUYV;
+ else if (!strncmp(pixfmt, "UYVY16", 6))
+ plat_data->interface_pix_fmt = IPU_PIX_FMT_UYVY;
+ else if (!strncmp(pixfmt, "YVYU16", 6))
+ plat_data->interface_pix_fmt = IPU_PIX_FMT_YVYU;
+ else if (!strncmp(pixfmt, "VYUY16", 6))
+ plat_data->interface_pix_fmt = IPU_PIX_FMT_VYUY;
+ else {
+ dev_err(&pdev->dev, "err interface_pix_fmt!\n");
+ return -ENOENT;
+ }
+
+ len = min(sizeof(plat_data->disp_dev) - 1, strlen(disp_dev));
+ memcpy(plat_data->disp_dev, disp_dev, len);
+ plat_data->disp_dev[len] = '\0';
+ plat_data->mode_str = (char *)mode_str;
+ plat_data->default_bpp = bpp;
+ plat_data->int_clk = (bool)int_clk;
+ plat_data->late_init = (bool)late_init;
+ return err;
+}
+
+/*!
+ * Probe routine for the framebuffer driver. It is called during the
+ * driver binding process. The following functions are performed in
+ * this routine: Framebuffer initialization, Memory allocation and
+ * mapping, Framebuffer registration, IPU initialization.
+ *
+ * @return Appropriate error code to the kernel common code
+ */
+static int mxcfb_probe(struct platform_device *pdev)
+{
+ struct ipuv3_fb_platform_data *plat_data;
+ struct fb_info *fbi;
+ struct mxcfb_info *mxcfbi;
+ struct resource *res;
+ int ret = 0;
+
+ dev_dbg(&pdev->dev, "%s enter\n", __func__);
+ pdev->id = of_alias_get_id(pdev->dev.of_node, "mxcfb");
+ if (pdev->id < 0) {
+ dev_err(&pdev->dev, "can not get alias id\n");
+ return pdev->id;
+ }
+
+ plat_data = devm_kzalloc(&pdev->dev, sizeof(struct
+ ipuv3_fb_platform_data), GFP_KERNEL);
+ if (!plat_data)
+ return -ENOMEM;
+ pdev->dev.platform_data = plat_data;
+
+ ret = mxcfb_get_of_property(pdev, plat_data);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "get mxcfb of property fail\n");
+ return ret;
+ }
+
+ /* Initialize FB structures */
+ fbi = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ops);
+ if (!fbi) {
+ ret = -ENOMEM;
+ goto init_fbinfo_failed;
+ }
+
+ ret = mxcfb_option_setup(pdev, fbi);
+ if (ret)
+ goto get_fb_option_failed;
+
+ mxcfbi = (struct mxcfb_info *)fbi->par;
+ mxcfbi->ipu_int_clk = plat_data->int_clk;
+ mxcfbi->late_init = plat_data->late_init;
+ mxcfbi->first_set_par = true;
+ mxcfbi->prefetch = plat_data->prefetch;
+ mxcfbi->pre_num = -1;
+ spin_lock_init(&mxcfbi->spin_lock);
+
+ ret = mxcfb_dispdrv_init(pdev, fbi);
+ if (ret < 0)
+ goto init_dispdrv_failed;
+
+ ret = ipu_test_set_usage(mxcfbi->ipu_id, mxcfbi->ipu_di);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "ipu%d-di%d already in use\n",
+ mxcfbi->ipu_id, mxcfbi->ipu_di);
+ goto ipu_in_busy;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res && res->start && res->end) {
+ fbi->fix.smem_len = res->end - res->start + 1;
+ fbi->fix.smem_start = res->start;
+ fbi->screen_base = ioremap(fbi->fix.smem_start, fbi->fix.smem_len);
+ /* Do not clear the fb content drawn in bootloader. */
+ if (!mxcfbi->late_init)
+ memset(fbi->screen_base, 0, fbi->fix.smem_len);
+ }
+
+ mxcfbi->ipu = ipu_get_soc(mxcfbi->ipu_id);
+ if (IS_ERR(mxcfbi->ipu)) {
+ ret = -ENODEV;
+ goto get_ipu_failed;
+ }
+
+ /* first user uses DP with alpha feature */
+ if (!g_dp_in_use[mxcfbi->ipu_id]) {
+ mxcfbi->ipu_ch_irq = IPU_IRQ_BG_SYNC_EOF;
+ mxcfbi->ipu_ch_nf_irq = IPU_IRQ_BG_SYNC_NFACK;
+ mxcfbi->ipu_alp_ch_irq = IPU_IRQ_BG_ALPHA_SYNC_EOF;
+ mxcfbi->ipu_ch = MEM_BG_SYNC;
+ /* Unblank the primary fb only by default */
+ if (pdev->id == 0)
+ mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_UNBLANK;
+ else
+ mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_POWERDOWN;
+
+ ret = mxcfb_register(fbi);
+ if (ret < 0)
+ goto mxcfb_register_failed;
+
+ ipu_disp_set_global_alpha(mxcfbi->ipu, mxcfbi->ipu_ch,
+ true, 0x80);
+ ipu_disp_set_color_key(mxcfbi->ipu, mxcfbi->ipu_ch, false, 0);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ ret = mxcfb_setup_overlay(pdev, fbi, res);
+
+ if (ret < 0) {
+ mxcfb_unregister(fbi);
+ goto mxcfb_setupoverlay_failed;
+ }
+
+ g_dp_in_use[mxcfbi->ipu_id] = true;
+
+ ret = device_create_file(mxcfbi->ovfbi->dev,
+ &dev_attr_fsl_disp_property);
+ if (ret)
+ dev_err(mxcfbi->ovfbi->dev, "Error %d on creating "
+ "file for disp property\n",
+ ret);
+
+ ret = device_create_file(mxcfbi->ovfbi->dev,
+ &dev_attr_fsl_disp_dev_property);
+ if (ret)
+ dev_err(mxcfbi->ovfbi->dev, "Error %d on creating "
+ "file for disp device "
+ "propety\n", ret);
+ } else {
+ mxcfbi->ipu_ch_irq = IPU_IRQ_DC_SYNC_EOF;
+ mxcfbi->ipu_ch_nf_irq = IPU_IRQ_DC_SYNC_NFACK;
+ mxcfbi->ipu_alp_ch_irq = -1;
+ mxcfbi->ipu_ch = MEM_DC_SYNC;
+ mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_POWERDOWN;
+
+ ret = mxcfb_register(fbi);
+ if (ret < 0)
+ goto mxcfb_register_failed;
+ }
+
+ platform_set_drvdata(pdev, fbi);
+
+ ret = device_create_file(fbi->dev, &dev_attr_fsl_disp_property);
+ if (ret)
+ dev_err(&pdev->dev, "Error %d on creating file for disp "
+ "property\n", ret);
+
+ ret = device_create_file(fbi->dev, &dev_attr_fsl_disp_dev_property);
+ if (ret)
+ dev_err(&pdev->dev, "Error %d on creating file for disp "
+ " device propety\n", ret);
+
+ return 0;
+
+mxcfb_setupoverlay_failed:
+mxcfb_register_failed:
+get_ipu_failed:
+ ipu_clear_usage(mxcfbi->ipu_id, mxcfbi->ipu_di);
+ipu_in_busy:
+init_dispdrv_failed:
+ fb_dealloc_cmap(&fbi->cmap);
+ framebuffer_release(fbi);
+get_fb_option_failed:
+init_fbinfo_failed:
+ return ret;
+}
+
+static int mxcfb_remove(struct platform_device *pdev)
+{
+ struct fb_info *fbi = platform_get_drvdata(pdev);
+ struct mxcfb_info *mxc_fbi = fbi->par;
+
+ device_remove_file(fbi->dev, &dev_attr_fsl_disp_dev_property);
+ device_remove_file(fbi->dev, &dev_attr_fsl_disp_property);
+ mxcfb_blank(FB_BLANK_POWERDOWN, fbi);
+ mxcfb_unregister(fbi);
+ mxcfb_unmap_video_memory(fbi);
+
+ if (mxc_fbi->ovfbi) {
+ device_remove_file(mxc_fbi->ovfbi->dev,
+ &dev_attr_fsl_disp_dev_property);
+ device_remove_file(mxc_fbi->ovfbi->dev,
+ &dev_attr_fsl_disp_property);
+ mxcfb_blank(FB_BLANK_POWERDOWN, mxc_fbi->ovfbi);
+ mxcfb_unsetup_overlay(fbi);
+ mxcfb_unmap_video_memory(mxc_fbi->ovfbi);
+ }
+
+ ipu_clear_usage(mxc_fbi->ipu_id, mxc_fbi->ipu_di);
+ if (&fbi->cmap)
+ fb_dealloc_cmap(&fbi->cmap);
+ framebuffer_release(fbi);
+ return 0;
+}
+
+static const struct of_device_id imx_mxcfb_dt_ids[] = {
+ { .compatible = "fsl,mxc_sdc_fb"},
+ { /* sentinel */ }
+};
+
+/*!
+ * This structure contains pointers to the power management callback functions.
+ */
+static struct platform_driver mxcfb_driver = {
+ .driver = {
+ .name = MXCFB_NAME,
+ .of_match_table = imx_mxcfb_dt_ids,
+ },
+ .probe = mxcfb_probe,
+ .remove = mxcfb_remove,
+ .suspend = mxcfb_suspend,
+ .resume = mxcfb_resume,
+};
+
+/*!
+ * Main entry function for the framebuffer. The function registers the power
+ * management callback functions with the kernel and also registers the MXCFB
+ * callback functions with the core Linux framebuffer driver \b fbmem.c
+ *
+ * @return Error code indicating success or failure
+ */
+int __init mxcfb_init(void)
+{
+ return platform_driver_register(&mxcfb_driver);
+}
+
+void mxcfb_exit(void)
+{
+ platform_driver_unregister(&mxcfb_driver);
+}
+
+module_init(mxcfb_init);
+module_exit(mxcfb_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC framebuffer driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("fb");
diff --git a/drivers/video/fbdev/mxc/mxc_lcdif.c b/drivers/video/fbdev/mxc/mxc_lcdif.c
new file mode 100644
index 000000000000..59d429c82017
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mxc_lcdif.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/ipu.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mxcfb.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+
+#include "mxc_dispdrv.h"
+
+struct mxc_lcd_platform_data {
+ u32 default_ifmt;
+ u32 ipu_id;
+ u32 disp_id;
+};
+
+struct mxc_lcdif_data {
+ struct platform_device *pdev;
+ struct mxc_dispdrv_handle *disp_lcdif;
+};
+
+#define DISPDRV_LCD "lcd"
+
+static struct fb_videomode lcdif_modedb[] = {
+ {
+ /* 800x480 @ 57 Hz , pixel clk @ 27MHz */
+ "CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10,
+ FB_SYNC_CLK_LAT_FALL,
+ FB_VMODE_NONINTERLACED,
+ 0,},
+ {
+ /* 800x480 @ 60 Hz , pixel clk @ 32MHz */
+ "SEIKO-WVGA", 60, 800, 480, 29850, 89, 164, 23, 10, 10, 10,
+ FB_SYNC_CLK_LAT_FALL,
+ FB_VMODE_NONINTERLACED,
+ 0,},
+};
+static int lcdif_modedb_sz = ARRAY_SIZE(lcdif_modedb);
+
+static int lcdif_init(struct mxc_dispdrv_handle *disp,
+ struct mxc_dispdrv_setting *setting)
+{
+ int ret, i;
+ struct mxc_lcdif_data *lcdif = mxc_dispdrv_getdata(disp);
+ struct device *dev = &lcdif->pdev->dev;
+ struct mxc_lcd_platform_data *plat_data = dev->platform_data;
+ struct fb_videomode *modedb = lcdif_modedb;
+ int modedb_sz = lcdif_modedb_sz;
+
+ /* use platform defined ipu/di */
+ ret = ipu_di_to_crtc(dev, plat_data->ipu_id,
+ plat_data->disp_id, &setting->crtc);
+ if (ret < 0)
+ return ret;
+
+ ret = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str,
+ modedb, modedb_sz, NULL, setting->default_bpp);
+ if (!ret) {
+ fb_videomode_to_var(&setting->fbi->var, &modedb[0]);
+ setting->if_fmt = plat_data->default_ifmt;
+ }
+
+ INIT_LIST_HEAD(&setting->fbi->modelist);
+ for (i = 0; i < modedb_sz; i++) {
+ struct fb_videomode m;
+ fb_var_to_videomode(&m, &setting->fbi->var);
+ if (fb_mode_is_equal(&m, &modedb[i])) {
+ fb_add_videomode(&modedb[i],
+ &setting->fbi->modelist);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+void lcdif_deinit(struct mxc_dispdrv_handle *disp)
+{
+ /*TODO*/
+}
+
+static struct mxc_dispdrv_driver lcdif_drv = {
+ .name = DISPDRV_LCD,
+ .init = lcdif_init,
+ .deinit = lcdif_deinit,
+};
+
+static int lcd_get_of_property(struct platform_device *pdev,
+ struct mxc_lcd_platform_data *plat_data)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int err;
+ u32 ipu_id, disp_id;
+ const char *default_ifmt;
+
+ err = of_property_read_string(np, "default_ifmt", &default_ifmt);
+ if (err) {
+ dev_dbg(&pdev->dev, "get of property default_ifmt fail\n");
+ return err;
+ }
+ err = of_property_read_u32(np, "ipu_id", &ipu_id);
+ if (err) {
+ dev_dbg(&pdev->dev, "get of property ipu_id fail\n");
+ return err;
+ }
+ err = of_property_read_u32(np, "disp_id", &disp_id);
+ if (err) {
+ dev_dbg(&pdev->dev, "get of property disp_id fail\n");
+ return err;
+ }
+
+ plat_data->ipu_id = ipu_id;
+ plat_data->disp_id = disp_id;
+ if (!strncmp(default_ifmt, "RGB24", 5))
+ plat_data->default_ifmt = IPU_PIX_FMT_RGB24;
+ else if (!strncmp(default_ifmt, "BGR24", 5))
+ plat_data->default_ifmt = IPU_PIX_FMT_BGR24;
+ else if (!strncmp(default_ifmt, "GBR24", 5))
+ plat_data->default_ifmt = IPU_PIX_FMT_GBR24;
+ else if (!strncmp(default_ifmt, "RGB565", 6))
+ plat_data->default_ifmt = IPU_PIX_FMT_RGB565;
+ else if (!strncmp(default_ifmt, "RGB666", 6))
+ plat_data->default_ifmt = IPU_PIX_FMT_RGB666;
+ else if (!strncmp(default_ifmt, "YUV444", 6))
+ plat_data->default_ifmt = IPU_PIX_FMT_YUV444;
+ else if (!strncmp(default_ifmt, "LVDS666", 7))
+ plat_data->default_ifmt = IPU_PIX_FMT_LVDS666;
+ else if (!strncmp(default_ifmt, "YUYV16", 6))
+ plat_data->default_ifmt = IPU_PIX_FMT_YUYV;
+ else if (!strncmp(default_ifmt, "UYVY16", 6))
+ plat_data->default_ifmt = IPU_PIX_FMT_UYVY;
+ else if (!strncmp(default_ifmt, "YVYU16", 6))
+ plat_data->default_ifmt = IPU_PIX_FMT_YVYU;
+ else if (!strncmp(default_ifmt, "VYUY16", 6))
+ plat_data->default_ifmt = IPU_PIX_FMT_VYUY;
+ else {
+ dev_err(&pdev->dev, "err default_ifmt!\n");
+ return -ENOENT;
+ }
+
+ return err;
+}
+
+static int mxc_lcdif_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct pinctrl *pinctrl;
+ struct mxc_lcdif_data *lcdif;
+ struct mxc_lcd_platform_data *plat_data;
+
+ dev_dbg(&pdev->dev, "%s enter\n", __func__);
+ lcdif = devm_kzalloc(&pdev->dev, sizeof(struct mxc_lcdif_data),
+ GFP_KERNEL);
+ if (!lcdif)
+ return -ENOMEM;
+ plat_data = devm_kzalloc(&pdev->dev,
+ sizeof(struct mxc_lcd_platform_data),
+ GFP_KERNEL);
+ if (!plat_data)
+ return -ENOMEM;
+ pdev->dev.platform_data = plat_data;
+
+ ret = lcd_get_of_property(pdev, plat_data);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "get lcd of property fail\n");
+ return ret;
+ }
+
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ dev_err(&pdev->dev, "can't get/select pinctrl\n");
+ return PTR_ERR(pinctrl);
+ }
+
+ lcdif->pdev = pdev;
+ lcdif->disp_lcdif = mxc_dispdrv_register(&lcdif_drv);
+ mxc_dispdrv_setdata(lcdif->disp_lcdif, lcdif);
+
+ dev_set_drvdata(&pdev->dev, lcdif);
+ dev_dbg(&pdev->dev, "%s exit\n", __func__);
+
+ return ret;
+}
+
+static int mxc_lcdif_remove(struct platform_device *pdev)
+{
+ struct mxc_lcdif_data *lcdif = dev_get_drvdata(&pdev->dev);
+
+ mxc_dispdrv_puthandle(lcdif->disp_lcdif);
+ mxc_dispdrv_unregister(lcdif->disp_lcdif);
+ kfree(lcdif);
+ return 0;
+}
+
+static const struct of_device_id imx_lcd_dt_ids[] = {
+ { .compatible = "fsl,lcd"},
+ { /* sentinel */ }
+};
+static struct platform_driver mxc_lcdif_driver = {
+ .driver = {
+ .name = "mxc_lcdif",
+ .of_match_table = imx_lcd_dt_ids,
+ },
+ .probe = mxc_lcdif_probe,
+ .remove = mxc_lcdif_remove,
+};
+
+static int __init mxc_lcdif_init(void)
+{
+ return platform_driver_register(&mxc_lcdif_driver);
+}
+
+static void __exit mxc_lcdif_exit(void)
+{
+ platform_driver_unregister(&mxc_lcdif_driver);
+}
+
+module_init(mxc_lcdif_init);
+module_exit(mxc_lcdif_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX ipuv3 LCD extern port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/mxc/mxcfb_hx8363_wvga.c b/drivers/video/fbdev/mxc/mxcfb_hx8363_wvga.c
new file mode 100644
index 000000000000..155e8491d765
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mxcfb_hx8363_wvga.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/spinlock.h>
+#include <linux/mipi_dsi.h>
+#include <linux/mxcfb.h>
+#include <linux/backlight.h>
+#include <video/mipi_display.h>
+
+#include "mipi_dsi.h"
+
+#define HX8363_TWO_DATA_LANE (0x2)
+#define HX8363_MAX_DPHY_CLK (800)
+#define HX8363_CMD_GETHXID (0xF4)
+#define HX8363_CMD_GETHXID_LEN (0x4)
+#define HX8363_ID (0x84)
+#define HX8363_ID_MASK (0xFF)
+
+
+#define CHECK_RETCODE(ret) \
+do { \
+ if (ret < 0) { \
+ dev_err(&mipi_dsi->pdev->dev, \
+ "%s ERR: ret:%d, line:%d.\n", \
+ __func__, ret, __LINE__); \
+ return ret; \
+ } \
+} while (0)
+
+static void parse_variadic(int n, u8 *buf, ...)
+{
+ int i = 0;
+ va_list args;
+
+ if (unlikely(!n)) return;
+
+ va_start(args, buf);
+
+ for (i = 0; i < n; i++)
+ buf[i + 1] = (u8)va_arg(args, int);
+
+ va_end(args);
+}
+
+#define TC358763_DCS_write_1A_nP(n, addr, ...) { \
+ int err; \
+ \
+ buf[0] = addr; \
+ parse_variadic(n, buf, ##__VA_ARGS__); \
+ \
+ if (n >= 2) \
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, \
+ MIPI_DSI_DCS_LONG_WRITE, (u32*)buf, n + 1); \
+ else if (n == 1) \
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, \
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, (u32*)buf, 0); \
+ else if (n == 0) \
+ { \
+ buf[1] = 0; \
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, \
+ MIPI_DSI_DCS_SHORT_WRITE, (u32*)buf, 0); \
+ } \
+ CHECK_RETCODE(err); \
+}
+
+#define TC358763_DCS_write_1A_0P(addr) \
+ TC358763_DCS_write_1A_nP(0, addr)
+
+#define TC358763_DCS_write_1A_1P(addr, ...) \
+ TC358763_DCS_write_1A_nP(1, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_2P(addr, ...) \
+ TC358763_DCS_write_1A_nP(2, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_3P(addr, ...) \
+ TC358763_DCS_write_1A_nP(3, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_5P(addr, ...) \
+ TC358763_DCS_write_1A_nP(5, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_6P(addr, ...) \
+ TC358763_DCS_write_1A_nP(6, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_7P(addr, ...) \
+ TC358763_DCS_write_1A_nP(7, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_12P(addr, ...) \
+ TC358763_DCS_write_1A_nP(12, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_13P(addr, ...) \
+ TC358763_DCS_write_1A_nP(13, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_14P(addr, ...) \
+ TC358763_DCS_write_1A_nP(14, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_19P(addr, ...) \
+ TC358763_DCS_write_1A_nP(19, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_34P(addr, ...) \
+ TC358763_DCS_write_1A_nP(34, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_127P(addr, ...) \
+ TC358763_DCS_write_1A_nP(127, addr, __VA_ARGS__)
+
+static int hx8363bl_brightness;
+
+#define ACTIVE_HIGH_NAME "TRUULY-WVGA-SYNC-HIGH"
+#define ACTIVE_LOW_NAME "TRUULY-WVGA-SYNC-LOW"
+
+static struct fb_videomode truly_lcd_modedb[] = {
+ {
+ ACTIVE_HIGH_NAME, 50, 480, 854, 41042,
+ 40, 60,
+ 3, 3,
+ 8, 4,
+ 0x0,
+ FB_VMODE_NONINTERLACED,
+ 0,
+ }, {
+ ACTIVE_LOW_NAME, 50, 480, 854, 41042,
+ 40, 60,
+ 3, 3,
+ 8, 4,
+ FB_SYNC_OE_LOW_ACT,
+ FB_VMODE_NONINTERLACED,
+ 0,
+ },
+};
+
+static struct mipi_lcd_config lcd_config = {
+ .virtual_ch = 0x0,
+ .data_lane_num = HX8363_TWO_DATA_LANE,
+ .max_phy_clk = HX8363_MAX_DPHY_CLK,
+ .dpi_fmt = MIPI_RGB888,
+};
+
+void mipid_hx8363_get_lcd_videomode(struct fb_videomode **mode, int *size,
+ struct mipi_lcd_config **data)
+{
+ *mode = &truly_lcd_modedb[0];
+ *size = ARRAY_SIZE(truly_lcd_modedb);
+ *data = &lcd_config;
+}
+
+int mipid_hx8363_lcd_setup(struct mipi_dsi_info *mipi_dsi)
+{
+ u8 buf[DSI_CMD_BUF_MAXSIZE];
+
+ dev_dbg(&mipi_dsi->pdev->dev, "MIPI DSI LCD HX8363 setup.\n");
+
+ TC358763_DCS_write_1A_3P(0xB9,0xFF,0x83,0x63);/* SET password */
+
+ TC358763_DCS_write_1A_19P(0xB1,0x01,0x00,0x44,0x08,0x01,0x10,0x10,0x36,
+ 0x3E,0x1A,0x1A,0x40,0x12,0x00,0xE6,0xE6,0xE6,0xE6,0xE6);/* Set Power */
+ TC358763_DCS_write_1A_2P(0xB2,0x08,0x03);/* Set DISP */
+ TC358763_DCS_write_1A_7P(0xB4,0x02,0x18,0x9C,0x08,0x18,0x04,0x6C);
+ TC358763_DCS_write_1A_1P(0xB6,0x00);/* Set VCOM */
+ TC358763_DCS_write_1A_1P(0xCC,0x0B);/* Set Panel */
+ TC358763_DCS_write_1A_34P(0xE0,0x0E,0x15,0x19,0x30,0x31,0x3F,0x27,0x3C,0x88,0x8F,0xD1,0xD5,0xD7,0x16,0x16,
+ 0x0C,0x1E,0x0E,0x15,0x19,0x30,0x31,0x3F,0x27,0x3C,0x88,0x8F,
+ 0xD1,0xD5,0xD7,0x16,0x16,0x0C,0x1E);
+ mdelay(5);
+
+ TC358763_DCS_write_1A_1P(0x3A,0x77);/* 24bit */
+ TC358763_DCS_write_1A_14P(0xBA,0x11,0x00,0x56,0xC6,0x10,0x89,0xFF,0x0F,0x32,0x6E,0x04,0x07,0x9A,0x92);
+ TC358763_DCS_write_1A_0P(0x21);
+
+ TC358763_DCS_write_1A_0P(0x11);
+ msleep(10);
+
+ TC358763_DCS_write_1A_0P(0x29);
+ msleep(120);
+
+ return 0;
+}
+
+static int mipid_bl_update_status(struct backlight_device *bl)
+{
+ return 0;
+}
+
+static int mipid_bl_get_brightness(struct backlight_device *bl)
+{
+ return hx8363bl_brightness;
+}
+
+static int mipi_bl_check_fb(struct backlight_device *bl, struct fb_info *fbi)
+{
+ return 0;
+}
+
+static const struct backlight_ops mipid_lcd_bl_ops = {
+ .update_status = mipid_bl_update_status,
+ .get_brightness = mipid_bl_get_brightness,
+ .check_fb = mipi_bl_check_fb,
+};
diff --git a/drivers/video/fbdev/mxc/mxcfb_hx8369_wvga.c b/drivers/video/fbdev/mxc/mxcfb_hx8369_wvga.c
new file mode 100644
index 000000000000..581eccad0dcd
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mxcfb_hx8369_wvga.c
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/spinlock.h>
+#include <linux/mipi_dsi.h>
+#include <linux/mxcfb.h>
+#include <linux/backlight.h>
+#include <video/mipi_display.h>
+
+#include "mipi_dsi.h"
+
+#define MIPI_DSI_MAX_RET_PACK_SIZE (0x4)
+
+#define HX8369BL_MAX_BRIGHT (255)
+#define HX8369BL_DEF_BRIGHT (255)
+
+#define HX8369_MAX_DPHY_CLK (800)
+#define HX8369_ONE_DATA_LANE (0x1)
+#define HX8369_TWO_DATA_LANE (0x2)
+
+#define HX8369_CMD_SETEXTC (0xB9)
+#define HX8369_CMD_SETEXTC_LEN (0x4)
+#define HX8369_CMD_SETEXTC_PARAM_1 (0x6983ff)
+
+#define HX8369_CMD_GETHXID (0xF4)
+#define HX8369_CMD_GETHXID_LEN (0x4)
+#define HX8369_ID (0x69)
+#define HX8369_ID_MASK (0xFF)
+
+#define HX8369_CMD_SETDISP (0xB2)
+#define HX8369_CMD_SETDISP_LEN (16)
+#define HX8369_CMD_SETDISP_1_HALT (0x00)
+#define HX8369_CMD_SETDISP_2_RES_MODE (0x23)
+#define HX8369_CMD_SETDISP_3_BP (0x03)
+#define HX8369_CMD_SETDISP_4_FP (0x03)
+#define HX8369_CMD_SETDISP_5_SAP (0x70)
+#define HX8369_CMD_SETDISP_6_GENON (0x00)
+#define HX8369_CMD_SETDISP_7_GENOFF (0xff)
+#define HX8369_CMD_SETDISP_8_RTN (0x00)
+#define HX8369_CMD_SETDISP_9_TEI (0x00)
+#define HX8369_CMD_SETDISP_10_TEP_UP (0x00)
+#define HX8369_CMD_SETDISP_11_TEP_LOW (0x00)
+#define HX8369_CMD_SETDISP_12_BP_PE (0x03)
+#define HX8369_CMD_SETDISP_13_FP_PE (0x03)
+#define HX8369_CMD_SETDISP_14_RTN_PE (0x00)
+#define HX8369_CMD_SETDISP_15_GON (0x01)
+
+#define HX8369_CMD_SETCYC (0xB4)
+#define HX8369_CMD_SETCYC_LEN (6)
+#define HX8369_CMD_SETCYC_PARAM_1 (0x5f1d00)
+#define HX8369_CMD_SETCYC_PARAM_2 (0x060e)
+
+#define HX8369_CMD_SETGIP (0xD5)
+#define HX8369_CMD_SETGIP_LEN (27)
+#define HX8369_CMD_SETGIP_PARAM_1 (0x030400)
+#define HX8369_CMD_SETGIP_PARAM_2 (0x1c050100)
+#define HX8369_CMD_SETGIP_PARAM_3 (0x00030170)
+#define HX8369_CMD_SETGIP_PARAM_4 (0x51064000)
+#define HX8369_CMD_SETGIP_PARAM_5 (0x41000007)
+#define HX8369_CMD_SETGIP_PARAM_6 (0x07075006)
+#define HX8369_CMD_SETGIP_PARAM_7 (0x040f)
+
+#define HX8369_CMD_SETPOWER (0xB1)
+#define HX8369_CMD_SETPOWER_LEN (20)
+#define HX8369_CMD_SETPOWER_PARAM_1 (0x340001)
+#define HX8369_CMD_SETPOWER_PARAM_2 (0x0f0f0006)
+#define HX8369_CMD_SETPOWER_PARAM_3 (0x3f3f322a)
+#define HX8369_CMD_SETPOWER_PARAM_4 (0xe6013a07)
+#define HX8369_CMD_SETPOWER_PARAM_5 (0xe6e6e6e6)
+
+#define HX8369_CMD_SETVCOM (0xB6)
+#define HX8369_CMD_SETVCOM_LEN (3)
+#define HX8369_CMD_SETVCOM_PARAM_1 (0x5656)
+
+#define HX8369_CMD_SETPANEL (0xCC)
+#define HX8369_CMD_SETPANEL_PARAM_1 (0x02)
+
+#define HX8369_CMD_SETGAMMA (0xE0)
+#define HX8369_CMD_SETGAMMA_LEN (35)
+#define HX8369_CMD_SETGAMMA_PARAM_1 (0x221d00)
+#define HX8369_CMD_SETGAMMA_PARAM_2 (0x2e3f3d38)
+#define HX8369_CMD_SETGAMMA_PARAM_3 (0x0f0d064a)
+#define HX8369_CMD_SETGAMMA_PARAM_4 (0x16131513)
+#define HX8369_CMD_SETGAMMA_PARAM_5 (0x1d001910)
+#define HX8369_CMD_SETGAMMA_PARAM_6 (0x3f3d3822)
+#define HX8369_CMD_SETGAMMA_PARAM_7 (0x0d064a2e)
+#define HX8369_CMD_SETGAMMA_PARAM_8 (0x1315130f)
+#define HX8369_CMD_SETGAMMA_PARAM_9 (0x191016)
+
+#define HX8369_CMD_SETMIPI (0xBA)
+#define HX8369_CMD_SETMIPI_LEN (14)
+#define HX8369_CMD_SETMIPI_PARAM_1 (0xc6a000)
+#define HX8369_CMD_SETMIPI_PARAM_2 (0x10000a00)
+#define HX8369_CMD_SETMIPI_ONELANE (0x10 << 24)
+#define HX8369_CMD_SETMIPI_TWOLANE (0x11 << 24)
+#define HX8369_CMD_SETMIPI_PARAM_3 (0x00026f30)
+#define HX8369_CMD_SETMIPI_PARAM_4 (0x4018)
+
+#define HX8369_CMD_SETPIXEL_FMT (0x3A)
+#define HX8369_CMD_SETPIXEL_FMT_24BPP (0x77)
+#define HX8369_CMD_SETPIXEL_FMT_18BPP (0x66)
+#define HX8369_CMD_SETPIXEL_FMT_16BPP (0x55)
+
+#define HX8369_CMD_SETCLUMN_ADDR (0x2A)
+#define HX8369_CMD_SETCLUMN_ADDR_LEN (5)
+#define HX8369_CMD_SETCLUMN_ADDR_PARAM_1 (0xdf0000)
+#define HX8369_CMD_SETCLUMN_ADDR_PARAM_2 (0x01)
+
+#define HX8369_CMD_SETPAGE_ADDR (0x2B)
+#define HX8369_CMD_SETPAGE_ADDR_LEN (5)
+#define HX8369_CMD_SETPAGE_ADDR_PARAM_1 (0x1f0000)
+#define HX8369_CMD_SETPAGE_ADDR_PARAM_2 (0x03)
+
+#define HX8369_CMD_WRT_DISP_BRIGHT (0x51)
+#define HX8369_CMD_WRT_DISP_BRIGHT_PARAM_1 (0xFF)
+
+#define HX8369_CMD_WRT_CABC_MIN_BRIGHT (0x5E)
+#define HX8369_CMD_WRT_CABC_MIN_BRIGHT_PARAM_1 (0x20)
+
+#define HX8369_CMD_WRT_CABC_CTRL (0x55)
+#define HX8369_CMD_WRT_CABC_CTRL_PARAM_1 (0x1)
+
+#define HX8369_CMD_WRT_CTRL_DISP (0x53)
+#define HX8369_CMD_WRT_CTRL_DISP_PARAM_1 (0x24)
+
+#define CHECK_RETCODE(ret) \
+do { \
+ if (ret < 0) { \
+ dev_err(&mipi_dsi->pdev->dev, \
+ "%s ERR: ret:%d, line:%d.\n", \
+ __func__, ret, __LINE__); \
+ return ret; \
+ } \
+} while (0)
+
+static int hx8369bl_brightness;
+static int mipid_init_backlight(struct mipi_dsi_info *mipi_dsi);
+
+static struct fb_videomode truly_lcd_modedb[] = {
+ {
+ "TRULY-WVGA", 64, 480, 800, 37880,
+ 8, 8,
+ 6, 6,
+ 8, 6,
+ FB_SYNC_OE_LOW_ACT,
+ FB_VMODE_NONINTERLACED,
+ 0,
+ },
+};
+
+static struct mipi_lcd_config lcd_config = {
+ .virtual_ch = 0x0,
+ .data_lane_num = HX8369_TWO_DATA_LANE,
+ .max_phy_clk = HX8369_MAX_DPHY_CLK,
+ .dpi_fmt = MIPI_RGB888,
+};
+void mipid_hx8369_get_lcd_videomode(struct fb_videomode **mode, int *size,
+ struct mipi_lcd_config **data)
+{
+ *mode = &truly_lcd_modedb[0];
+ *size = ARRAY_SIZE(truly_lcd_modedb);
+ *data = &lcd_config;
+}
+
+int mipid_hx8369_lcd_setup(struct mipi_dsi_info *mipi_dsi)
+{
+ u32 buf[DSI_CMD_BUF_MAXSIZE];
+ int err;
+
+ dev_dbg(&mipi_dsi->pdev->dev, "MIPI DSI LCD setup.\n");
+ buf[0] = HX8369_CMD_SETEXTC | (HX8369_CMD_SETEXTC_PARAM_1 << 8);
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_LONG_WRITE,
+ buf, HX8369_CMD_SETEXTC_LEN);
+ CHECK_RETCODE(err);
+ buf[0] = MIPI_DSI_MAX_RET_PACK_SIZE;
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi,
+ MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
+ buf, 0);
+ CHECK_RETCODE(err);
+ buf[0] = HX8369_CMD_GETHXID;
+ err = mipi_dsi->mipi_dsi_pkt_read(mipi_dsi,
+ MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM,
+ buf, HX8369_CMD_GETHXID_LEN);
+ if (!err && ((buf[0] & HX8369_ID_MASK) == HX8369_ID)) {
+ dev_info(&mipi_dsi->pdev->dev,
+ "MIPI DSI LCD ID:0x%x.\n", buf[0]);
+ } else {
+ dev_err(&mipi_dsi->pdev->dev,
+ "mipi_dsi_pkt_read err:%d, data:0x%x.\n",
+ err, buf[0]);
+ dev_info(&mipi_dsi->pdev->dev,
+ "MIPI DSI LCD not detected!\n");
+ return err;
+ }
+
+ /* set LCD resolution as 480RGBx800, DPI interface,
+ * display operation mode: RGB data bypass GRAM mode.
+ */
+ buf[0] = HX8369_CMD_SETDISP | (HX8369_CMD_SETDISP_1_HALT << 8) |
+ (HX8369_CMD_SETDISP_2_RES_MODE << 16) |
+ (HX8369_CMD_SETDISP_3_BP << 24);
+ buf[1] = HX8369_CMD_SETDISP_4_FP | (HX8369_CMD_SETDISP_5_SAP << 8) |
+ (HX8369_CMD_SETDISP_6_GENON << 16) |
+ (HX8369_CMD_SETDISP_7_GENOFF << 24);
+ buf[2] = HX8369_CMD_SETDISP_8_RTN | (HX8369_CMD_SETDISP_9_TEI << 8) |
+ (HX8369_CMD_SETDISP_10_TEP_UP << 16) |
+ (HX8369_CMD_SETDISP_11_TEP_LOW << 24);
+ buf[3] = HX8369_CMD_SETDISP_12_BP_PE |
+ (HX8369_CMD_SETDISP_13_FP_PE << 8) |
+ (HX8369_CMD_SETDISP_14_RTN_PE << 16) |
+ (HX8369_CMD_SETDISP_15_GON << 24);
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_LONG_WRITE,
+ buf, HX8369_CMD_SETDISP_LEN);
+ CHECK_RETCODE(err);
+
+ /* Set display waveform cycle */
+ buf[0] = HX8369_CMD_SETCYC | (HX8369_CMD_SETCYC_PARAM_1 << 8);
+ buf[1] = HX8369_CMD_SETCYC_PARAM_2;
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_LONG_WRITE,
+ buf, HX8369_CMD_SETCYC_LEN);
+ CHECK_RETCODE(err);
+
+ /* Set GIP timing output control */
+ buf[0] = HX8369_CMD_SETGIP | (HX8369_CMD_SETGIP_PARAM_1 << 8);
+ buf[1] = HX8369_CMD_SETGIP_PARAM_2;
+ buf[2] = HX8369_CMD_SETGIP_PARAM_3;
+ buf[3] = HX8369_CMD_SETGIP_PARAM_4;
+ buf[4] = HX8369_CMD_SETGIP_PARAM_5;
+ buf[5] = HX8369_CMD_SETGIP_PARAM_6;
+ buf[6] = HX8369_CMD_SETGIP_PARAM_7;
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_LONG_WRITE, buf,
+ HX8369_CMD_SETGIP_LEN);
+ CHECK_RETCODE(err);
+
+ /* Set power: standby, DC etc. */
+ buf[0] = HX8369_CMD_SETPOWER | (HX8369_CMD_SETPOWER_PARAM_1 << 8);
+ buf[1] = HX8369_CMD_SETPOWER_PARAM_2;
+ buf[2] = HX8369_CMD_SETPOWER_PARAM_3;
+ buf[3] = HX8369_CMD_SETPOWER_PARAM_4;
+ buf[4] = HX8369_CMD_SETPOWER_PARAM_5;
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_LONG_WRITE, buf,
+ HX8369_CMD_SETPOWER_LEN);
+ CHECK_RETCODE(err);
+
+ /* Set VCOM voltage. */
+ buf[0] = HX8369_CMD_SETVCOM | (HX8369_CMD_SETVCOM_PARAM_1 << 8);
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_LONG_WRITE, buf,
+ HX8369_CMD_SETVCOM_LEN);
+ CHECK_RETCODE(err);
+
+ /* Set Panel: BGR/RGB or Inversion. */
+ buf[0] = HX8369_CMD_SETPANEL | (HX8369_CMD_SETPANEL_PARAM_1 << 8);
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi,
+ MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM, buf, 0);
+ CHECK_RETCODE(err);
+
+ /* Set gamma curve related setting */
+ buf[0] = HX8369_CMD_SETGAMMA | (HX8369_CMD_SETGAMMA_PARAM_1 << 8);
+ buf[1] = HX8369_CMD_SETGAMMA_PARAM_2;
+ buf[2] = HX8369_CMD_SETGAMMA_PARAM_3;
+ buf[3] = HX8369_CMD_SETGAMMA_PARAM_4;
+ buf[4] = HX8369_CMD_SETGAMMA_PARAM_5;
+ buf[5] = HX8369_CMD_SETGAMMA_PARAM_6;
+ buf[6] = HX8369_CMD_SETGAMMA_PARAM_7;
+ buf[7] = HX8369_CMD_SETGAMMA_PARAM_8;
+ buf[8] = HX8369_CMD_SETGAMMA_PARAM_9;
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_LONG_WRITE, buf,
+ HX8369_CMD_SETGAMMA_LEN);
+ CHECK_RETCODE(err);
+
+ /* Set MIPI: DPHYCMD & DSICMD, data lane number */
+ buf[0] = HX8369_CMD_SETMIPI | (HX8369_CMD_SETMIPI_PARAM_1 << 8);
+ buf[1] = HX8369_CMD_SETMIPI_PARAM_2;
+ buf[2] = HX8369_CMD_SETMIPI_PARAM_3;
+ if (lcd_config.data_lane_num == HX8369_ONE_DATA_LANE)
+ buf[2] |= HX8369_CMD_SETMIPI_ONELANE;
+ else
+ buf[2] |= HX8369_CMD_SETMIPI_TWOLANE;
+ buf[3] = HX8369_CMD_SETMIPI_PARAM_4;
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_LONG_WRITE, buf,
+ HX8369_CMD_SETMIPI_LEN);
+ CHECK_RETCODE(err);
+
+ /* Set pixel format:24bpp */
+ buf[0] = HX8369_CMD_SETPIXEL_FMT;
+ switch (lcd_config.dpi_fmt) {
+ case MIPI_RGB565_PACKED:
+ case MIPI_RGB565_LOOSELY:
+ case MIPI_RGB565_CONFIG3:
+ buf[0] |= (HX8369_CMD_SETPIXEL_FMT_16BPP << 8);
+ break;
+
+ case MIPI_RGB666_LOOSELY:
+ case MIPI_RGB666_PACKED:
+ buf[0] |= (HX8369_CMD_SETPIXEL_FMT_18BPP << 8);
+ break;
+
+ case MIPI_RGB888:
+ buf[0] |= (HX8369_CMD_SETPIXEL_FMT_24BPP << 8);
+ break;
+
+ default:
+ buf[0] |= (HX8369_CMD_SETPIXEL_FMT_24BPP << 8);
+ break;
+ }
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM,
+ buf, 0);
+ CHECK_RETCODE(err);
+
+ /* Set column address: 0~479 */
+ buf[0] = HX8369_CMD_SETCLUMN_ADDR |
+ (HX8369_CMD_SETCLUMN_ADDR_PARAM_1 << 8);
+ buf[1] = HX8369_CMD_SETCLUMN_ADDR_PARAM_2;
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_LONG_WRITE,
+ buf, HX8369_CMD_SETCLUMN_ADDR_LEN);
+ CHECK_RETCODE(err);
+
+ /* Set page address: 0~799 */
+ buf[0] = HX8369_CMD_SETPAGE_ADDR |
+ (HX8369_CMD_SETPAGE_ADDR_PARAM_1 << 8);
+ buf[1] = HX8369_CMD_SETPAGE_ADDR_PARAM_2;
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_LONG_WRITE,
+ buf, HX8369_CMD_SETPAGE_ADDR_LEN);
+ CHECK_RETCODE(err);
+
+ /* Set display brightness related */
+ buf[0] = HX8369_CMD_WRT_DISP_BRIGHT |
+ (HX8369_CMD_WRT_DISP_BRIGHT_PARAM_1 << 8);
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM,
+ buf, 0);
+ CHECK_RETCODE(err);
+
+ buf[0] = HX8369_CMD_WRT_CABC_CTRL |
+ (HX8369_CMD_WRT_CABC_CTRL_PARAM_1 << 8);
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM,
+ buf, 0);
+ CHECK_RETCODE(err);
+
+ buf[0] = HX8369_CMD_WRT_CTRL_DISP |
+ (HX8369_CMD_WRT_CTRL_DISP_PARAM_1 << 8);
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM,
+ buf, 0);
+ CHECK_RETCODE(err);
+
+ /* exit sleep mode and set display on */
+ buf[0] = MIPI_DCS_EXIT_SLEEP_MODE;
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM,
+ buf, 0);
+ CHECK_RETCODE(err);
+ /* To allow time for the supply voltages
+ * and clock circuits to stabilize.
+ */
+ msleep(5);
+ buf[0] = MIPI_DCS_SET_DISPLAY_ON;
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM,
+ buf, 0);
+ CHECK_RETCODE(err);
+
+ err = mipid_init_backlight(mipi_dsi);
+ return err;
+}
+
+static int mipid_bl_update_status(struct backlight_device *bl)
+{
+ int err;
+ u32 buf;
+ int brightness = bl->props.brightness;
+ struct mipi_dsi_info *mipi_dsi = bl_get_data(bl);
+
+ if (bl->props.power != FB_BLANK_UNBLANK ||
+ bl->props.fb_blank != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ buf = HX8369_CMD_WRT_DISP_BRIGHT |
+ ((brightness & HX8369BL_MAX_BRIGHT) << 8);
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM,
+ &buf, 0);
+ CHECK_RETCODE(err);
+
+ hx8369bl_brightness = brightness & HX8369BL_MAX_BRIGHT;
+
+ dev_dbg(&bl->dev, "mipid backlight bringtness:%d.\n", brightness);
+ return 0;
+}
+
+static int mipid_bl_get_brightness(struct backlight_device *bl)
+{
+ return hx8369bl_brightness;
+}
+
+static int mipi_bl_check_fb(struct backlight_device *bl, struct fb_info *fbi)
+{
+ return 0;
+}
+
+static const struct backlight_ops mipid_lcd_bl_ops = {
+ .update_status = mipid_bl_update_status,
+ .get_brightness = mipid_bl_get_brightness,
+ .check_fb = mipi_bl_check_fb,
+};
+
+static int mipid_init_backlight(struct mipi_dsi_info *mipi_dsi)
+{
+ struct backlight_properties props;
+ struct backlight_device *bl;
+
+ if (mipi_dsi->bl) {
+ pr_debug("mipid backlight already init!\n");
+ return 0;
+ }
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.max_brightness = HX8369BL_MAX_BRIGHT;
+ props.type = BACKLIGHT_RAW;
+ bl = backlight_device_register("mipid-bl", &mipi_dsi->pdev->dev,
+ mipi_dsi, &mipid_lcd_bl_ops, &props);
+ if (IS_ERR(bl)) {
+ pr_err("error %ld on backlight register\n", PTR_ERR(bl));
+ return PTR_ERR(bl);
+ }
+ mipi_dsi->bl = bl;
+ bl->props.power = FB_BLANK_UNBLANK;
+ bl->props.fb_blank = FB_BLANK_UNBLANK;
+ bl->props.brightness = HX8369BL_DEF_BRIGHT;
+
+ mipid_bl_update_status(bl);
+ return 0;
+}
diff --git a/drivers/video/fbdev/mxc/mxcfb_otm8018b_wvga.c b/drivers/video/fbdev/mxc/mxcfb_otm8018b_wvga.c
new file mode 100644
index 000000000000..fa7db02f37f6
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mxcfb_otm8018b_wvga.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/spinlock.h>
+#include <linux/mipi_dsi.h>
+#include <linux/mxcfb.h>
+#include <linux/backlight.h>
+#include <video/mipi_display.h>
+
+#include "mipi_dsi.h"
+
+#define OTM8018B_TWO_DATA_LANE (0x2)
+#define OTM8018B_MAX_DPHY_CLK (800)
+
+#define CHECK_RETCODE(ret) \
+do { \
+ if (ret < 0) { \
+ dev_err(&mipi_dsi->pdev->dev, \
+ "%s ERR: ret:%d, line:%d.\n", \
+ __func__, ret, __LINE__); \
+ return ret; \
+ } \
+} while (0)
+
+static void parse_variadic(int n, u8 *buf, ...)
+{
+ int i = 0;
+ va_list args;
+
+ if (unlikely(!n)) return;
+
+ va_start(args, buf);
+
+ for (i = 0; i < n; i++)
+ buf[i + 1] = (u8)va_arg(args, int);
+
+ va_end(args);
+}
+
+#define TC358763_DCS_write_1A_nP(n, addr, ...) { \
+ int err; \
+ \
+ buf[0] = addr; \
+ parse_variadic(n, buf, ##__VA_ARGS__); \
+ \
+ err = mipi_dsi->mipi_dsi_pkt_write(mipi_dsi, \
+ MIPI_DSI_GENERIC_LONG_WRITE, (u32*)buf, n + 1); \
+ CHECK_RETCODE(err); \
+}
+
+#define TC358763_DCS_write_1A_0P(addr) \
+ TC358763_DCS_write_1A_nP(0, addr)
+
+#define TC358763_DCS_write_1A_1P(addr, ...) \
+ TC358763_DCS_write_1A_nP(1, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_2P(addr, ...) \
+ TC358763_DCS_write_1A_nP(2, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_3P(addr, ...) \
+ TC358763_DCS_write_1A_nP(3, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_5P(addr, ...) \
+ TC358763_DCS_write_1A_nP(5, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_6P(addr, ...) \
+ TC358763_DCS_write_1A_nP(6, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_12P(addr, ...) \
+ TC358763_DCS_write_1A_nP(12, addr, __VA_ARGS__)
+
+#define TC358763_DCS_write_1A_14P(addr, ...) \
+ TC358763_DCS_write_1A_nP(14, addr, __VA_ARGS__)
+
+static int otm8018bbl_brightness;
+
+static struct fb_videomode truly_lcd_modedb[] = {
+ {
+ "TRULY-WVGA", 64, 480, 800, 37880,
+ 8, 8,
+ 6, 6,
+ 8, 6,
+ FB_SYNC_OE_LOW_ACT,
+ FB_VMODE_NONINTERLACED,
+ 0,
+ },
+};
+
+static struct mipi_lcd_config lcd_config = {
+ .virtual_ch = 0x0,
+ .data_lane_num = OTM8018B_TWO_DATA_LANE,
+ .max_phy_clk = OTM8018B_MAX_DPHY_CLK,
+ .dpi_fmt = MIPI_RGB888,
+};
+
+void mipid_otm8018b_get_lcd_videomode(struct fb_videomode **mode, int *size,
+ struct mipi_lcd_config **data)
+{
+ *mode = &truly_lcd_modedb[0];
+ *size = ARRAY_SIZE(truly_lcd_modedb);
+ *data = &lcd_config;
+}
+
+int mipid_otm8018b_lcd_setup(struct mipi_dsi_info *mipi_dsi)
+{
+ u8 buf[DSI_CMD_BUF_MAXSIZE];
+
+ dev_dbg(&mipi_dsi->pdev->dev, "MIPI DSI LCD setup.\n");
+
+ TC358763_DCS_write_1A_3P(0xFF,0x80,0x09,0x01);
+ TC358763_DCS_write_1A_1P(0x00,0x80);
+ TC358763_DCS_write_1A_2P(0xFF,0x80,0x09);
+
+ TC358763_DCS_write_1A_1P(0x00,0x03);
+ TC358763_DCS_write_1A_1P(0xff,0x01);
+
+ TC358763_DCS_write_1A_1P(0x00,0xb4);
+ TC358763_DCS_write_1A_1P(0xc0,0x10);
+
+ TC358763_DCS_write_1A_1P(0x00,0x82);
+ TC358763_DCS_write_1A_1P(0xC5,0xa3);
+
+ TC358763_DCS_write_1A_1P(0x00,0x90);
+ TC358763_DCS_write_1A_2P(0xC5,0x96,0x76);
+
+ TC358763_DCS_write_1A_1P(0x00,0x00);
+ TC358763_DCS_write_1A_2P(0xD8,0x75,0x73);
+
+ TC358763_DCS_write_1A_1P(0x00,0x00);
+ TC358763_DCS_write_1A_1P(0xD9,0x5e);
+
+ TC358763_DCS_write_1A_1P(0x00,0x81);
+ TC358763_DCS_write_1A_1P(0xC1,0x66);
+
+ TC358763_DCS_write_1A_1P(0x00,0xA1);
+ TC358763_DCS_write_1A_1P(0xC1,0x08);
+
+ TC358763_DCS_write_1A_1P(0x00,0x89);
+ TC358763_DCS_write_1A_1P(0xC4,0x08);
+
+ TC358763_DCS_write_1A_1P(0x00,0xA2);
+ TC358763_DCS_write_1A_3P(0xC0,0x1B,0x00,0x02);
+
+ TC358763_DCS_write_1A_1P(0x00,0x81);
+ TC358763_DCS_write_1A_1P(0xC4,0x83);
+
+ TC358763_DCS_write_1A_1P(0x00,0x92);
+ TC358763_DCS_write_1A_1P(0xC5,0x01);
+
+ TC358763_DCS_write_1A_1P(0x00,0xb1);
+ TC358763_DCS_write_1A_1P(0xC5,0xa9);
+
+ TC358763_DCS_write_1A_1P(0x00,0x90);
+ TC358763_DCS_write_1A_6P(0xC0,0x00,0x44,0x00,0x00,0x00,0x03);
+
+ TC358763_DCS_write_1A_1P(0x00,0xA6);
+ TC358763_DCS_write_1A_3P(0xC1,0x00,0x00,0x00);
+
+ TC358763_DCS_write_1A_1P(0x00,0x80);
+ TC358763_DCS_write_1A_12P(0xCE,0x87,0x03,0x00,0x85,0x03,0x00,
+ 0x86,0x03,0x00,0x84,0x03,0x00);
+
+ TC358763_DCS_write_1A_1P(0x00,0xA0);
+ TC358763_DCS_write_1A_14P(0xCE,0x38,0x03,0x03,0x58,0x00,0x00,
+ 0x00,0x38,0x02,0x03,0x59,0x00,0x00,0x00);
+
+ TC358763_DCS_write_1A_1P(0x00,0xB0);
+ TC358763_DCS_write_1A_14P(0xCE,0x38,0x01,0x03,0x5a,0x00,0x00,
+ 0x00,0x38,0x00,0x03,0x5b,0x00,0x00,0x00);
+
+ TC358763_DCS_write_1A_1P(0x00,0xC0);
+ TC358763_DCS_write_1A_14P(0xCE,0x30,0x00,0x03,0x5c,0x00,0x00,
+ 0x00,0x30,0x01,0x03,0x5d,0x00,0x00,0x00);
+
+ TC358763_DCS_write_1A_1P(0x00,0xD0);
+ TC358763_DCS_write_1A_14P(0xCE,0x30,0x02,0x03,0x5e,0x00,0x00,
+ 0x00,0x30,0x03,0x03,0x5f,0x00,0x00,0x00);
+
+ TC358763_DCS_write_1A_1P(0x00,0xC7);
+ TC358763_DCS_write_1A_1P(0xCF,0x00);
+
+ TC358763_DCS_write_1A_1P(0x00,0xC9);
+ TC358763_DCS_write_1A_1P(0xCF,0x00);
+
+ TC358763_DCS_write_1A_1P(0x00,0xC4);
+ TC358763_DCS_write_1A_6P(0xCB,0x04,0x04,0x04,0x04,0x04,0x04);
+
+ TC358763_DCS_write_1A_1P(0x00,0xd9);
+ TC358763_DCS_write_1A_6P(0xCB,0x04,0x04,0x04,0x04,0x04,0x04);
+
+ TC358763_DCS_write_1A_1P(0x00,0x84);
+ TC358763_DCS_write_1A_6P(0xCc,0x0c,0x0a,0x10,0x0e,0x03,0x04);
+
+ TC358763_DCS_write_1A_1P(0x00,0x9e);
+ TC358763_DCS_write_1A_1P(0xCc,0x0b);
+
+ TC358763_DCS_write_1A_1P(0x00,0xA0);
+ TC358763_DCS_write_1A_5P(0xCC,0x09,0x0f,0x0d,0x01,0x02);
+
+ TC358763_DCS_write_1A_1P(0x00,0xb4);
+ TC358763_DCS_write_1A_5P(0xCC,0x0d,0x09,0x0b,0x02,0x01);
+
+ TC358763_DCS_write_1A_1P(0x00,0xce);
+ TC358763_DCS_write_1A_1P(0xCc,0x0e);
+
+ TC358763_DCS_write_1A_1P(0x00,0xD0);
+ TC358763_DCS_write_1A_5P(0xCC,0x10,0x0a,0x0c,0x04,0x03);
+
+ TC358763_DCS_write_1A_1P(0x00,0x00);
+ TC358763_DCS_write_1A_1P(0x3a,0x77);
+
+ TC358763_DCS_write_1A_0P(0x11);
+
+ msleep(200);
+
+ TC358763_DCS_write_1A_0P(0x29);
+
+ TC358763_DCS_write_1A_0P(0x2C);
+
+ return 0;
+}
+
+static int mipid_bl_update_status(struct backlight_device *bl)
+{
+ return 0;
+}
+
+static int mipid_bl_get_brightness(struct backlight_device *bl)
+{
+ return otm8018bbl_brightness;
+}
+
+static int mipi_bl_check_fb(struct backlight_device *bl, struct fb_info *fbi)
+{
+ return 0;
+}
+
+static const struct backlight_ops mipid_lcd_bl_ops = {
+ .update_status = mipid_bl_update_status,
+ .get_brightness = mipid_bl_get_brightness,
+ .check_fb = mipi_bl_check_fb,
+};
diff --git a/drivers/video/fbdev/mxc/mxsfb_sii902x.c b/drivers/video/fbdev/mxc/mxsfb_sii902x.c
new file mode 100644
index 000000000000..b9ab7db822ed
--- /dev/null
+++ b/drivers/video/fbdev/mxc/mxsfb_sii902x.c
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) 2010-2015 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @defgroup Framebuffer Framebuffer Driver for Sii902x.
+ */
+
+/*!
+ * @file mxsfb_sii902x.c
+ *
+ * @brief Frame buffer driver for SII902x
+ *
+ * @ingroup Framebuffer
+ */
+
+/*!
+ * Include files
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/i2c.h>
+#include <linux/fsl_devices.h>
+#include <linux/interrupt.h>
+#include <linux/reset.h>
+#include <asm/mach-types.h>
+#include <video/mxc_edid.h>
+
+#define SII_EDID_LEN 512
+#define DRV_NAME "sii902x"
+
+struct sii902x_data {
+ struct i2c_client *client;
+ struct delayed_work det_work;
+ struct fb_info *fbi;
+ struct mxc_edid_cfg edid_cfg;
+ u8 cable_plugin;
+ u8 edid[SII_EDID_LEN];
+ bool dft_mode_set;
+ const char *mode_str;
+ int bits_per_pixel;
+} sii902x;
+
+static void sii902x_poweron(void);
+static void sii902x_poweroff(void);
+
+static int sii902x_in_init_state;
+
+#ifdef DEBUG
+static void dump_fb_videomode(struct fb_videomode *m)
+{
+ pr_debug("fb_videomode = %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ m->refresh, m->xres, m->yres, m->pixclock, m->left_margin,
+ m->right_margin, m->upper_margin, m->lower_margin,
+ m->hsync_len, m->vsync_len, m->sync, m->vmode, m->flag);
+}
+#else
+static void dump_fb_videomode(struct fb_videomode *m)
+{}
+#endif
+
+static __attribute__ ((unused)) void dump_regs(u8 reg, int len)
+{
+ u8 buf[50];
+ int i;
+
+ i2c_smbus_read_i2c_block_data(sii902x.client, reg, len, buf);
+ for (i = 0; i < len; i++)
+ dev_dbg(&sii902x.client->dev, "reg[0x%02X]: 0x%02X\n",
+ i+reg, buf[i]);
+}
+
+static ssize_t sii902x_show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ strcpy(buf, sii902x.fbi->fix.id);
+ sprintf(buf+strlen(buf), "\n");
+
+ return strlen(buf);
+}
+
+static DEVICE_ATTR(fb_name, S_IRUGO, sii902x_show_name, NULL);
+
+static ssize_t sii902x_show_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (sii902x.cable_plugin == 0)
+ strcpy(buf, "plugout\n");
+ else
+ strcpy(buf, "plugin\n");
+
+ return strlen(buf);
+}
+
+static DEVICE_ATTR(cable_state, S_IRUGO, sii902x_show_state, NULL);
+
+static ssize_t sii902x_show_edid(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i, j, len = 0;
+
+ for (j = 0; j < SII_EDID_LEN/16; j++) {
+ for (i = 0; i < 16; i++)
+ len += sprintf(buf+len, "0x%02X ",
+ sii902x.edid[j*16 + i]);
+ len += sprintf(buf+len, "\n");
+ }
+
+ return len;
+}
+
+static DEVICE_ATTR(edid, S_IRUGO, sii902x_show_edid, NULL);
+
+static void sii902x_setup(struct fb_info *fbi)
+{
+ u16 data[4];
+ u32 refresh;
+ u8 *tmp;
+ int i;
+
+ dev_dbg(&sii902x.client->dev, "Sii902x: setup..\n");
+
+ /* Power up */
+ i2c_smbus_write_byte_data(sii902x.client, 0x1E, 0x00);
+
+ /* set TPI video mode */
+ data[0] = PICOS2KHZ(fbi->var.pixclock) / 10;
+ data[2] = fbi->var.hsync_len + fbi->var.left_margin +
+ fbi->var.xres + fbi->var.right_margin;
+ data[3] = fbi->var.vsync_len + fbi->var.upper_margin +
+ fbi->var.yres + fbi->var.lower_margin;
+ refresh = data[2] * data[3];
+ refresh = (PICOS2KHZ(fbi->var.pixclock) * 1000) / refresh;
+ data[1] = refresh * 100;
+ tmp = (u8 *)data;
+ for (i = 0; i < 8; i++)
+ i2c_smbus_write_byte_data(sii902x.client, i, tmp[i]);
+
+ /* input bus/pixel: full pixel wide (24bit), rising edge */
+ i2c_smbus_write_byte_data(sii902x.client, 0x08, 0x70);
+ /* Set input format to RGB */
+ i2c_smbus_write_byte_data(sii902x.client, 0x09, 0x00);
+ /* set output format to RGB */
+ i2c_smbus_write_byte_data(sii902x.client, 0x0A, 0x00);
+}
+
+static void sii902x_audio_setup(void)
+{
+ /* audio setup */
+ i2c_smbus_write_byte_data(sii902x.client, 0x25, 0x00);
+ i2c_smbus_write_byte_data(sii902x.client, 0x26, 0x40);
+ i2c_smbus_write_byte_data(sii902x.client, 0x27, 0x00);
+}
+
+#ifdef CONFIG_FB_MODE_HELPERS
+static int sii902x_read_edid(struct fb_info *fbi)
+{
+ int old, dat, ret, cnt = 100;
+ unsigned short addr = 0x50;
+
+ dev_dbg(&sii902x.client->dev, "%s\n", __func__);
+
+ old = i2c_smbus_read_byte_data(sii902x.client, 0x1A);
+
+ i2c_smbus_write_byte_data(sii902x.client, 0x1A, old | 0x4);
+ do {
+ cnt--;
+ msleep(10);
+ dat = i2c_smbus_read_byte_data(sii902x.client, 0x1A);
+ } while ((!(dat & 0x2)) && cnt);
+
+ if (!cnt) {
+ ret = -1;
+ goto done;
+ }
+
+ i2c_smbus_write_byte_data(sii902x.client, 0x1A, old | 0x06);
+
+ /* edid reading */
+ ret = mxc_edid_read(sii902x.client->adapter, addr,
+ sii902x.edid, &sii902x.edid_cfg, fbi);
+
+ cnt = 100;
+ do {
+ cnt--;
+ i2c_smbus_write_byte_data(sii902x.client, 0x1A, old & ~0x6);
+ msleep(10);
+ dat = i2c_smbus_read_byte_data(sii902x.client, 0x1A);
+ } while ((dat & 0x6) && cnt);
+
+ if (!cnt)
+ ret = -1;
+
+done:
+
+ i2c_smbus_write_byte_data(sii902x.client, 0x1A, old);
+ return ret;
+}
+#else
+static int sii902x_read_edid(struct fb_info *fbi)
+{
+ return -1;
+}
+#endif
+
+static void sii902x_cable_connected(void)
+{
+ int i;
+ const struct fb_videomode *mode;
+ struct fb_videomode m;
+
+ if (sii902x_read_edid(sii902x.fbi) < 0)
+ dev_err(&sii902x.client->dev,
+ "Sii902x: read edid fail\n");
+ else {
+ if (sii902x.fbi->monspecs.modedb_len > 0) {
+
+ fb_destroy_modelist(&sii902x.fbi->modelist);
+
+ for (i = 0; i < sii902x.fbi->monspecs.modedb_len; i++) {
+
+ mode = &sii902x.fbi->monspecs.modedb[i];
+
+ if (!(mode->vmode & FB_VMODE_INTERLACED)) {
+ dev_dbg(&sii902x.client->dev, "Added mode %d:", i);
+ dev_dbg(&sii902x.client->dev,
+ "xres = %d, yres = %d, freq = %d, vmode = %d, flag = %d\n",
+ mode->xres, mode->yres, mode->refresh,
+ mode->vmode, mode->flag);
+
+ fb_add_videomode(mode, &sii902x.fbi->modelist);
+ }
+ }
+
+ /* Set the default mode only once. */
+ if (!sii902x.dft_mode_set &&
+ sii902x.mode_str && sii902x.bits_per_pixel) {
+
+ dev_dbg(&sii902x.client->dev, "%s: setting to default=%s bpp=%d\n",
+ __func__, sii902x.mode_str, sii902x.bits_per_pixel);
+
+ fb_find_mode(&sii902x.fbi->var, sii902x.fbi,
+ sii902x.mode_str, NULL, 0, NULL,
+ sii902x.bits_per_pixel);
+
+ sii902x.dft_mode_set = true;
+ }
+
+ fb_var_to_videomode(&m, &sii902x.fbi->var);
+ dump_fb_videomode(&m);
+
+ mode = fb_find_nearest_mode(&m,
+ &sii902x.fbi->modelist);
+
+ /* update fbi mode */
+ sii902x.fbi->mode = (struct fb_videomode *)mode;
+
+ fb_videomode_to_var(&sii902x.fbi->var, mode);
+
+ sii902x.fbi->var.activate |= FB_ACTIVATE_FORCE;
+ console_lock();
+ sii902x.fbi->flags |= FBINFO_MISC_USEREVENT;
+ fb_set_var(sii902x.fbi, &sii902x.fbi->var);
+ sii902x.fbi->flags &= ~FBINFO_MISC_USEREVENT;
+ console_unlock();
+ }
+ /* Power on sii902x */
+ sii902x_poweron();
+ }
+}
+
+static void det_worker(struct work_struct *work)
+{
+ int dat;
+ char event_string[16];
+ char *envp[] = { event_string, NULL };
+
+ dev_dbg(&sii902x.client->dev, "%s\n", __func__);
+
+ dat = i2c_smbus_read_byte_data(sii902x.client, 0x3D);
+
+ /* cable connection state */
+ if (dat & 0x4) {
+ sii902x.cable_plugin = 1;
+ dev_dbg(&sii902x.client->dev, "EVENT=plugin\n");
+ sprintf(event_string, "EVENT=plugin");
+ sii902x_cable_connected();
+ } else {
+ sii902x.cable_plugin = 0;
+ dev_dbg(&sii902x.client->dev, "EVENT=plugout\n");
+ sprintf(event_string, "EVENT=plugout");
+ /* Power off sii902x */
+ sii902x_poweroff();
+ }
+ kobject_uevent_env(&sii902x.client->dev.kobj, KOBJ_CHANGE, envp);
+
+ i2c_smbus_write_byte_data(sii902x.client, 0x3D, dat);
+
+ dev_dbg(&sii902x.client->dev, "exit %s\n", __func__);
+
+}
+
+static irqreturn_t sii902x_detect_handler(int irq, void *data)
+{
+ if (sii902x.fbi)
+ schedule_delayed_work(&(sii902x.det_work), msecs_to_jiffies(50));
+
+ return IRQ_HANDLED;
+}
+
+static int sii902x_fb_event(struct notifier_block *nb, unsigned long val, void *v)
+{
+ struct fb_event *event = v;
+ struct fb_info *fbi = event->info;
+
+ dev_dbg(&sii902x.client->dev, "%s event=0x%lx\n", __func__, val);
+
+ if (sii902x_in_init_state) {
+ if (val == FB_EVENT_FB_REGISTERED && !sii902x.fbi)
+ sii902x.fbi = fbi;
+
+ return 0;
+ }
+
+ switch (val) {
+ case FB_EVENT_FB_REGISTERED:
+ if (sii902x.fbi == NULL)
+ sii902x.fbi = fbi;
+ /* Manually trigger a plugin/plugout interrupter to check cable state */
+ schedule_delayed_work(&(sii902x.det_work), msecs_to_jiffies(50));
+
+ fb_show_logo(fbi, 0);
+
+ break;
+ case FB_EVENT_MODE_CHANGE:
+ sii902x_setup(fbi);
+ break;
+ case FB_EVENT_BLANK:
+ if (*((int *)event->data) == FB_BLANK_UNBLANK) {
+ dev_dbg(&sii902x.client->dev, "FB_BLANK_UNBLANK\n");
+ sii902x_poweron();
+ } else {
+ dev_dbg(&sii902x.client->dev, "FB_BLANK_BLANK\n");
+ sii902x_poweroff();
+ }
+ break;
+ }
+ return 0;
+}
+
+static struct notifier_block nb = {
+ .notifier_call = sii902x_fb_event,
+};
+
+static int mxsfb_get_of_property(void)
+{
+ struct device_node *np = sii902x.client->dev.of_node;
+ const char *mode_str;
+ int bits_per_pixel, ret;
+
+ ret = of_property_read_string(np, "mode_str", &mode_str);
+ if (ret < 0) {
+ dev_warn(&sii902x.client->dev, "get of property mode_str fail\n");
+ return ret;
+ }
+ ret = of_property_read_u32(np, "bits-per-pixel", &bits_per_pixel);
+ if (ret) {
+ dev_warn(&sii902x.client->dev, "get of property bpp fail\n");
+ return ret;
+ }
+
+ sii902x.mode_str = mode_str;
+ sii902x.bits_per_pixel = bits_per_pixel;
+
+ return ret;
+}
+
+static int sii902x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int i, dat, ret;
+ struct fb_info edid_fbi;
+ struct fb_info *init_fbi = sii902x.fbi;
+
+ memset(&sii902x, 0, sizeof(sii902x));
+
+ sii902x.client = client;
+
+ dev_dbg(&sii902x.client->dev, "%s\n", __func__);;
+
+ /* Reset sii902x */
+ ret = device_reset(&sii902x.client->dev);
+ if (ret)
+ dev_warn(&sii902x.client->dev, "No reset pin found\n");
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+ /* Set 902x in hardware TPI mode on and jump out of D3 state */
+ if (i2c_smbus_write_byte_data(sii902x.client, 0xc7, 0x00) < 0) {
+ dev_err(&sii902x.client->dev,
+ "Sii902x: cound not find device\n");
+ return -ENODEV;
+ }
+
+ /* read device ID */
+ for (i = 10; i > 0; i--) {
+ dat = i2c_smbus_read_byte_data(sii902x.client, 0x1B);
+ dev_dbg(&sii902x.client->dev, "Sii902x: read id = 0x%02X", dat);
+ if (dat == 0xb0) {
+ dat = i2c_smbus_read_byte_data(sii902x.client, 0x1C);
+ dev_dbg(&sii902x.client->dev, "-0x%02X", dat);
+ dat = i2c_smbus_read_byte_data(sii902x.client, 0x1D);
+ dev_dbg(&sii902x.client->dev, "-0x%02X", dat);
+ dat = i2c_smbus_read_byte_data(sii902x.client, 0x30);
+ dev_dbg(&sii902x.client->dev, "-0x%02X\n", dat);
+ break;
+ }
+ }
+ if (i == 0) {
+ dev_err(&sii902x.client->dev,
+ "Sii902x: cound not find device\n");
+ return -ENODEV;
+ }
+
+ /* enable hmdi audio */
+ sii902x_audio_setup();
+
+ /* try to read edid, only if cable is plugged in */
+ dat = i2c_smbus_read_byte_data(sii902x.client, 0x3D);
+ if (dat & 0x04) {
+ ret = sii902x_read_edid(&edid_fbi);
+ if (ret < 0)
+ dev_warn(&sii902x.client->dev, "Can not read edid\n");
+ }
+
+ if (sii902x.client->irq) {
+ ret = request_irq(sii902x.client->irq, sii902x_detect_handler,
+ IRQF_TRIGGER_FALLING,
+ "SII902x_det", &sii902x);
+ if (ret < 0)
+ dev_warn(&sii902x.client->dev,
+ "Sii902x: cound not request det irq %d\n",
+ sii902x.client->irq);
+ else {
+ /*enable cable hot plug irq*/
+ i2c_smbus_write_byte_data(sii902x.client, 0x3c, 0x01);
+ INIT_DELAYED_WORK(&(sii902x.det_work), det_worker);
+ }
+ ret = device_create_file(&sii902x.client->dev, &dev_attr_fb_name);
+ if (ret < 0)
+ dev_warn(&sii902x.client->dev,
+ "Sii902x: cound not create sys node for fb name\n");
+ ret = device_create_file(&sii902x.client->dev, &dev_attr_cable_state);
+ if (ret < 0)
+ dev_warn(&sii902x.client->dev,
+ "Sii902x: cound not create sys node for cable state\n");
+ ret = device_create_file(&sii902x.client->dev, &dev_attr_edid);
+ if (ret < 0)
+ dev_warn(&sii902x.client->dev,
+ "Sii902x: cound not create sys node for edid\n");
+
+ }
+
+ mxsfb_get_of_property();
+
+ if (init_fbi) {
+ sii902x.fbi = init_fbi;
+
+ /* Manually trigger a plugin/plugout interrupter to check cable state */
+ schedule_delayed_work(&(sii902x.det_work), msecs_to_jiffies(50));
+ }
+
+ sii902x_in_init_state = 0;
+
+ return 0;
+}
+
+static int sii902x_remove(struct i2c_client *client)
+{
+ fb_unregister_client(&nb);
+ sii902x_poweroff();
+
+ return 0;
+}
+
+static void sii902x_poweron(void)
+{
+ /* Turn on DVI or HDMI */
+ if (sii902x.edid_cfg.hdmi_cap)
+ i2c_smbus_write_byte_data(sii902x.client, 0x1A, 0x01);
+ else
+ i2c_smbus_write_byte_data(sii902x.client, 0x1A, 0x00);
+ return;
+}
+
+static void sii902x_poweroff(void)
+{
+ /* disable tmds before changing resolution */
+ if (sii902x.edid_cfg.hdmi_cap)
+ i2c_smbus_write_byte_data(sii902x.client, 0x1A, 0x11);
+ else
+ i2c_smbus_write_byte_data(sii902x.client, 0x1A, 0x10);
+
+ return;
+}
+
+static int __init sii902x_init(void)
+{
+ sii902x_in_init_state = 1;
+
+ return fb_register_client(&nb);
+}
+fs_initcall_sync(sii902x_init);
+
+static const struct i2c_device_id sii902x_id[] = {
+ { DRV_NAME, 0},
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, sii902x_id);
+
+static const struct of_device_id sii902x_dt_ids[] = {
+ { .compatible = "SiI,sii902x", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sii902x_dt_ids);
+
+static struct i2c_driver sii902x_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = sii902x_dt_ids,
+ },
+ .probe = sii902x_probe,
+ .remove = sii902x_remove,
+ .id_table = sii902x_id,
+};
+
+module_i2c_driver(sii902x_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("SII902x DVI/HDMI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/mxsfb.c b/drivers/video/fbdev/mxsfb.c
index 7846f0e8bbbb..5659ec2d18c4 100644
--- a/drivers/video/fbdev/mxsfb.c
+++ b/drivers/video/fbdev/mxsfb.c
@@ -4,7 +4,8 @@
* This code is based on:
* Author: Vitaly Wool <vital@embeddedalley.com>
*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2017 NXP
+ * Copyright 2008-2015 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
@@ -39,18 +40,30 @@
* the required value in the imx_fb_videomode structure.
*/
+#include <linux/busfreq-imx.h>
+#include <linux/console.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/pm_qos.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/fb.h>
+#include <linux/mxcfb.h>
#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
#include <video/of_display_timing.h>
-#include <video/of_videomode.h>
#include <video/videomode.h>
+#include <linux/uaccess.h>
+
+#include "mxc/mxc_dispdrv.h"
#define REG_SET 4
#define REG_CLR 8
@@ -79,6 +92,9 @@
#define LCDC_V3_DATA 0x1b0
#define LCDC_V4_DEBUG0 0x1d0
#define LCDC_V3_DEBUG0 0x1f0
+#define LCDC_AS_CTRL 0x210
+#define LCDC_AS_BUF 0x220
+#define LCDC_AS_NEXT_BUF 0x230
#define CTRL_SFTRST (1 << 31)
#define CTRL_CLKGATE (1 << 30)
@@ -96,9 +112,30 @@
#define CTRL_DF24 (1 << 1)
#define CTRL_RUN (1 << 0)
-#define CTRL1_FIFO_CLEAR (1 << 21)
-#define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16)
-#define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf)
+#define CTRL1_RECOVERY_ON_UNDERFLOW (1 << 24)
+#define CTRL1_FIFO_CLEAR (1 << 21)
+#define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16)
+#define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf)
+#define CTRL1_OVERFLOW_IRQ_EN (1 << 15)
+#define CTRL1_UNDERFLOW_IRQ_EN (1 << 14)
+#define CTRL1_CUR_FRAME_DONE_IRQ_EN (1 << 13)
+#define CTRL1_VSYNC_EDGE_IRQ_EN (1 << 12)
+#define CTRL1_OVERFLOW_IRQ (1 << 11)
+#define CTRL1_UNDERFLOW_IRQ (1 << 10)
+#define CTRL1_CUR_FRAME_DONE_IRQ (1 << 9)
+#define CTRL1_VSYNC_EDGE_IRQ (1 << 8)
+#define CTRL1_IRQ_ENABLE_MASK (CTRL1_OVERFLOW_IRQ_EN | \
+ CTRL1_UNDERFLOW_IRQ_EN | \
+ CTRL1_CUR_FRAME_DONE_IRQ_EN | \
+ CTRL1_VSYNC_EDGE_IRQ_EN)
+#define CTRL1_IRQ_ENABLE_SHIFT 12
+#define CTRL1_IRQ_STATUS_MASK (CTRL1_OVERFLOW_IRQ | \
+ CTRL1_UNDERFLOW_IRQ | \
+ CTRL1_CUR_FRAME_DONE_IRQ | \
+ CTRL1_VSYNC_EDGE_IRQ)
+#define CTRL1_IRQ_STATUS_SHIFT 8
+
+#define CTRL2_OUTSTANDING_REQS__REQ_16 (4 << 21)
#define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16)
#define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff)
@@ -149,12 +186,13 @@
#define STMLCDIF_18BIT 2 /** pixel data bus to the display is of 18 bit width */
#define STMLCDIF_24BIT 3 /** pixel data bus to the display is of 24 bit width */
-#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT (1 << 6)
-#define MXSFB_SYNC_DOTCLK_FALLING_ACT (1 << 7) /* negtive edge sampling */
+#define FB_SYNC_OE_LOW_ACT 0x80000000
+#define FB_SYNC_CLK_LAT_FALL 0x40000000
enum mxsfb_devtype {
MXSFB_V3,
MXSFB_V4,
+ MXSFB_V5,
};
/* CPU dependent register offsets */
@@ -166,26 +204,79 @@ struct mxsfb_devdata {
unsigned hs_wdth_mask;
unsigned hs_wdth_shift;
unsigned ipversion;
+ u32 flags;
+};
+
+struct mxsfb_layer;
+
+struct mxsfb_layer_ops {
+ void (*enable)(struct mxsfb_layer *ofb);
+ void (*disable)(struct mxsfb_layer *ofb);
+ void (*setup)(struct mxsfb_layer *ofb);
+};
+
+struct mxsfb_layer {
+ struct fb_info *ol_fb;
+ int id;
+ int registered;
+ atomic_t usage;
+ int blank_state;
+ uint32_t global_alpha;
+
+ struct mxsfb_layer_ops *ops;
+
+ struct device *dev;
+ void __iomem *video_mem;
+ unsigned long video_mem_phys;
+ size_t video_mem_size;
+
+ struct mxsfb_info *fbi;
};
+#define NAME_LEN 32
+
struct mxsfb_info {
- struct fb_info fb_info;
+ struct fb_info *fb_info;
struct platform_device *pdev;
- struct clk *clk;
+ struct clk *clk_pix;
struct clk *clk_axi;
struct clk *clk_disp_axi;
+ bool clk_pix_enabled;
+ bool clk_axi_enabled;
+ bool clk_disp_axi_enabled;
void __iomem *base; /* registers */
+ u32 sync; /* record display timing polarities */
unsigned allocated_size;
int enabled;
unsigned ld_intf_width;
unsigned dotclk_delay;
const struct mxsfb_devdata *devdata;
- u32 sync;
struct regulator *reg_lcd;
+ bool wait4vsync;
+ struct completion vsync_complete;
+ struct completion flip_complete;
+ int cur_blank;
+ int restore_blank;
+ char disp_dev[NAME_LEN];
+ struct mxc_dispdrv_handle *dispdrv;
+ int id;
+ struct fb_var_screeninfo var;
+ struct pm_qos_request pm_qos_req;
+
+ char disp_videomode[NAME_LEN];
+
+#ifdef CONFIG_FB_MXC_OVERLAY
+ struct mxsfb_layer overlay;
+#endif
};
#define mxsfb_is_v3(host) (host->devdata->ipversion == 3)
#define mxsfb_is_v4(host) (host->devdata->ipversion == 4)
+#define mxsfb_is_v5(host) (host->devdata->ipversion == 5)
+
+#define MXSFB_FLAG_NULL 0x0
+#define MXSFB_FLAG_BUSFREQ 0x1
+#define MXSFB_FLAG_PMQOS 0x2
static const struct mxsfb_devdata mxsfb_devdata[] = {
[MXSFB_V3] = {
@@ -196,6 +287,7 @@ static const struct mxsfb_devdata mxsfb_devdata[] = {
.hs_wdth_mask = 0xff,
.hs_wdth_shift = 24,
.ipversion = 3,
+ .flags = MXSFB_FLAG_NULL,
},
[MXSFB_V4] = {
.transfer_count = LCDC_V4_TRANSFER_COUNT,
@@ -205,10 +297,77 @@ static const struct mxsfb_devdata mxsfb_devdata[] = {
.hs_wdth_mask = 0x3fff,
.hs_wdth_shift = 18,
.ipversion = 4,
+ .flags = MXSFB_FLAG_BUSFREQ,
+ },
+ [MXSFB_V5] = {
+ .transfer_count = LCDC_V4_TRANSFER_COUNT,
+ .cur_buf = LCDC_V4_CUR_BUF,
+ .next_buf = LCDC_V4_NEXT_BUF,
+ .debug0 = LCDC_V4_DEBUG0,
+ .hs_wdth_mask = 0x3fff,
+ .hs_wdth_shift = 18,
+ .ipversion = 4,
+ .flags = MXSFB_FLAG_PMQOS,
},
};
-#define to_imxfb_host(x) (container_of(x, struct mxsfb_info, fb_info))
+static int mxsfb_map_videomem(struct fb_info *info);
+static int mxsfb_unmap_videomem(struct fb_info *info);
+static int mxsfb_set_par(struct fb_info *fb_info);
+
+/* enable lcdif pix clock */
+static inline void clk_enable_pix(struct mxsfb_info *host)
+{
+ if (!host->clk_pix_enabled && (host->clk_pix != NULL)) {
+ clk_prepare_enable(host->clk_pix);
+ host->clk_pix_enabled = true;
+ }
+}
+
+/* disable lcdif pix clock */
+static inline void clk_disable_pix(struct mxsfb_info *host)
+{
+ if (host->clk_pix_enabled && (host->clk_pix != NULL)) {
+ clk_disable_unprepare(host->clk_pix);
+ host->clk_pix_enabled = false;
+ }
+}
+
+/* enable lcdif axi clock */
+static inline void clk_enable_axi(struct mxsfb_info *host)
+{
+ if (!host->clk_axi_enabled && (host->clk_axi != NULL)) {
+ clk_prepare_enable(host->clk_axi);
+ host->clk_axi_enabled = true;
+ }
+}
+
+/* disable lcdif axi clock */
+static inline void clk_disable_axi(struct mxsfb_info *host)
+{
+ if (host->clk_axi_enabled && (host->clk_axi != NULL)) {
+ clk_disable_unprepare(host->clk_axi);
+ host->clk_axi_enabled = false;
+ }
+}
+
+/* enable DISP axi clock */
+static inline void clk_enable_disp_axi(struct mxsfb_info *host)
+{
+ if (!host->clk_disp_axi_enabled && (host->clk_disp_axi != NULL)) {
+ clk_prepare_enable(host->clk_disp_axi);
+ host->clk_disp_axi_enabled = true;
+ }
+}
+
+/* disable DISP axi clock */
+static inline void clk_disable_disp_axi(struct mxsfb_info *host)
+{
+ if (host->clk_disp_axi_enabled && (host->clk_disp_axi != NULL)) {
+ clk_disable_unprepare(host->clk_disp_axi);
+ host->clk_disp_axi_enabled = false;
+ }
+}
/* mask and shift depends on architecture */
static inline u32 set_hsync_pulse_width(struct mxsfb_info *host, unsigned val)
@@ -241,6 +400,105 @@ static const struct fb_bitfield def_rgb565[] = {
}
};
+#ifdef CONFIG_FB_MXC_OVERLAY
+static u32 saved_as_ctrl;
+static u32 saved_as_next_buf;
+
+static const struct fb_bitfield def_argb555[] = {
+ [RED] = {
+ .offset = 10,
+ .length = 5,
+ },
+ [GREEN] = {
+ .offset = 5,
+ .length = 5,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 5,
+ },
+ [TRANSP] = {
+ .offset = 15,
+ .length = 0,
+ }
+};
+
+static const struct fb_bitfield def_rgb555[] = {
+ [RED] = {
+ .offset = 10,
+ .length = 5,
+ },
+ [GREEN] = {
+ .offset = 5,
+ .length = 5,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 5,
+ },
+ [TRANSP] = {
+ .offset = 0,
+ .length = 0,
+ }
+};
+
+static const struct fb_bitfield def_argb444[] = {
+ [RED] = {
+ .offset = 8,
+ .length = 4,
+ },
+ [GREEN] = {
+ .offset = 4,
+ .length = 4,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 4,
+ },
+ [TRANSP] = {
+ .offset = 12,
+ .length = 4,
+ }
+};
+
+static const struct fb_bitfield def_rgb444[] = {
+ [RED] = {
+ .offset = 8,
+ .length = 4,
+ },
+ [GREEN] = {
+ .offset = 4,
+ .length = 4,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 4,
+ },
+ [TRANSP] = {
+ .offset = 0,
+ .length = 0,
+ }
+};
+#endif
+
+static const struct fb_bitfield def_rgb666[] = {
+ [RED] = {
+ .offset = 16,
+ .length = 6,
+ },
+ [GREEN] = {
+ .offset = 8,
+ .length = 6,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 6,
+ },
+ [TRANSP] = { /* no support for transparency */
+ .length = 0,
+ }
+};
+
static const struct fb_bitfield def_rgb888[] = {
[RED] = {
.offset = 16,
@@ -259,6 +517,38 @@ static const struct fb_bitfield def_rgb888[] = {
}
};
+static const struct fb_bitfield def_argb32[] = {
+ [RED] = {
+ .offset = 16,
+ .length = 8,
+ },
+ [GREEN] = {
+ .offset = 8,
+ .length = 8,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 8,
+ },
+ [TRANSP] = {
+ .offset = 24,
+ .length = 8,
+ }
+};
+
+#define bitfield_is_equal(f1, f2) (!memcmp(&(f1), &(f2), sizeof(f1)))
+
+static inline bool pixfmt_is_equal(struct fb_var_screeninfo *var,
+ const struct fb_bitfield *f)
+{
+ if (bitfield_is_equal(var->red, f[RED]) &&
+ bitfield_is_equal(var->green, f[GREEN]) &&
+ bitfield_is_equal(var->blue, f[BLUE]))
+ return true;
+
+ return false;
+}
+
static inline unsigned chan_to_field(unsigned chan, struct fb_bitfield *bf)
{
chan &= 0xffff;
@@ -266,10 +556,46 @@ static inline unsigned chan_to_field(unsigned chan, struct fb_bitfield *bf)
return chan << bf->offset;
}
+static irqreturn_t mxsfb_irq_handler(int irq, void *dev_id)
+{
+ struct mxsfb_info *host = dev_id;
+ u32 ctrl1, enable, status, acked_status;
+
+ ctrl1 = readl(host->base + LCDC_CTRL1);
+ enable = (ctrl1 & CTRL1_IRQ_ENABLE_MASK) >> CTRL1_IRQ_ENABLE_SHIFT;
+ status = (ctrl1 & CTRL1_IRQ_STATUS_MASK) >> CTRL1_IRQ_STATUS_SHIFT;
+ acked_status = (enable & status) << CTRL1_IRQ_STATUS_SHIFT;
+
+ if ((acked_status & CTRL1_VSYNC_EDGE_IRQ) && host->wait4vsync) {
+ writel(CTRL1_VSYNC_EDGE_IRQ,
+ host->base + LCDC_CTRL1 + REG_CLR);
+ writel(CTRL1_VSYNC_EDGE_IRQ_EN,
+ host->base + LCDC_CTRL1 + REG_CLR);
+ host->wait4vsync = 0;
+ complete(&host->vsync_complete);
+ }
+
+ if (acked_status & CTRL1_CUR_FRAME_DONE_IRQ) {
+ writel(CTRL1_CUR_FRAME_DONE_IRQ,
+ host->base + LCDC_CTRL1 + REG_CLR);
+ writel(CTRL1_CUR_FRAME_DONE_IRQ_EN,
+ host->base + LCDC_CTRL1 + REG_CLR);
+ complete(&host->flip_complete);
+ }
+
+ if (acked_status & CTRL1_UNDERFLOW_IRQ)
+ writel(CTRL1_UNDERFLOW_IRQ, host->base + LCDC_CTRL1 + REG_CLR);
+
+ if (acked_status & CTRL1_OVERFLOW_IRQ)
+ writel(CTRL1_OVERFLOW_IRQ, host->base + LCDC_CTRL1 + REG_CLR);
+
+ return IRQ_HANDLED;
+}
+
static int mxsfb_check_var(struct fb_var_screeninfo *var,
struct fb_info *fb_info)
{
- struct mxsfb_info *host = to_imxfb_host(fb_info);
+ struct mxsfb_info *host = fb_info->par;
const struct fb_bitfield *rgb = NULL;
if (var->xres < MIN_XRES)
@@ -277,9 +603,18 @@ static int mxsfb_check_var(struct fb_var_screeninfo *var,
if (var->yres < MIN_YRES)
var->yres = MIN_YRES;
- var->xres_virtual = var->xres;
+ if (var->xres_virtual > var->xres) {
+ dev_dbg(fb_info->device, "stride not supported\n");
+ return -EINVAL;
+ }
- var->yres_virtual = var->yres;
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+
+ if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 16))
+ var->bits_per_pixel = 32;
switch (var->bits_per_pixel) {
case 16:
@@ -290,17 +625,35 @@ static int mxsfb_check_var(struct fb_var_screeninfo *var,
switch (host->ld_intf_width) {
case STMLCDIF_8BIT:
pr_debug("Unsupported LCD bus width mapping\n");
- break;
+ return -EINVAL;
case STMLCDIF_16BIT:
+ /* 24 bit to 18 bit mapping */
+ rgb = def_rgb666;
+ break;
case STMLCDIF_18BIT:
+ if (pixfmt_is_equal(var, def_rgb666))
+ /* 24 bit to 18 bit mapping */
+ rgb = def_rgb666;
+ else
+ rgb = def_rgb888;
+ break;
case STMLCDIF_24BIT:
/* real 24 bit */
rgb = def_rgb888;
break;
+ default:
+ /*
+ * 32-bit output is possible through I/O muxing, if this
+ * option is available on chip. Currently not
+ * implemented.
+ */
+ pr_debug("Currently unsupported output colour depth: %u\n",
+ host->ld_intf_width);
+ return -EINVAL;
}
break;
default:
- pr_err("Unsupported colour depth: %u\n", var->bits_per_pixel);
+ pr_debug("Unsupported colour depth: %u\n", var->bits_per_pixel);
return -EINVAL;
}
@@ -316,26 +669,27 @@ static int mxsfb_check_var(struct fb_var_screeninfo *var,
return 0;
}
-static inline void mxsfb_enable_axi_clk(struct mxsfb_info *host)
-{
- if (host->clk_axi)
- clk_prepare_enable(host->clk_axi);
-}
-
-static inline void mxsfb_disable_axi_clk(struct mxsfb_info *host)
-{
- if (host->clk_axi)
- clk_disable_unprepare(host->clk_axi);
-}
-
static void mxsfb_enable_controller(struct fb_info *fb_info)
{
- struct mxsfb_info *host = to_imxfb_host(fb_info);
+ struct mxsfb_info *host = fb_info->par;
u32 reg;
int ret;
+#ifdef CONFIG_FB_IMX64_DEBUG
+ static int pix_enable;
+#endif
dev_dbg(&host->pdev->dev, "%s\n", __func__);
+ if (host->dispdrv && host->dispdrv->drv->setup) {
+ ret = host->dispdrv->drv->setup(host->dispdrv, fb_info);
+ if (ret < 0) {
+ dev_err(&host->pdev->dev, "failed to setup"
+ "dispdrv:%s\n", host->dispdrv->drv->name);
+ return;
+ }
+ host->sync = fb_info->var.sync;
+ }
+
if (host->reg_lcd) {
ret = regulator_enable(host->reg_lcd);
if (ret) {
@@ -345,12 +699,44 @@ static void mxsfb_enable_controller(struct fb_info *fb_info)
}
}
- if (host->clk_disp_axi)
- clk_prepare_enable(host->clk_disp_axi);
- clk_prepare_enable(host->clk);
- clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U);
+ if (host->dispdrv && host->dispdrv->drv->enable) {
+ ret = host->dispdrv->drv->enable(host->dispdrv, fb_info);
+ if (ret < 0)
+ dev_err(&host->pdev->dev, "failed to enable "
+ "dispdrv:%s\n", host->dispdrv->drv->name);
+ }
+
+#ifdef CONFIG_FB_IMX64_DEBUG
+ if (unlikely(!pix_enable)) {
+ /* the pixel clock should be disabled before
+ * trying to set its clock rate successfully.
+ */
+#else
+ clk_disable_pix(host);
+#endif
+ ret = clk_set_rate(host->clk_pix,
+ PICOS2KHZ(fb_info->var.pixclock) * 1000U);
+ if (ret) {
+ dev_err(&host->pdev->dev,
+ "lcd pixel rate set failed: %d\n", ret);
+
+ if (host->reg_lcd) {
+ ret = regulator_disable(host->reg_lcd);
+ if (ret)
+ dev_err(&host->pdev->dev,
+ "lcd regulator disable failed: %d\n",
+ ret);
+ }
+ return;
+ }
+ clk_enable_pix(host);
+#ifdef CONFIG_FB_IMX64_DEBUG
+ pix_enable++;
+ }
+#endif
- mxsfb_enable_axi_clk(host);
+ writel(CTRL2_OUTSTANDING_REQS__REQ_16,
+ host->base + LCDC_V4_CTRL2 + REG_SET);
/* if it was disabled, re-enable the mode again */
writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_SET);
@@ -360,20 +746,30 @@ static void mxsfb_enable_controller(struct fb_info *fb_info)
reg |= VDCTRL4_SYNC_SIGNALS_ON;
writel(reg, host->base + LCDC_VDCTRL4);
+ writel(CTRL_MASTER, host->base + LCDC_CTRL + REG_SET);
writel(CTRL_RUN, host->base + LCDC_CTRL + REG_SET);
+ /* Recovery on underflow */
+ writel(CTRL1_RECOVERY_ON_UNDERFLOW, host->base + LCDC_CTRL1 + REG_SET);
+
host->enabled = 1;
+
}
static void mxsfb_disable_controller(struct fb_info *fb_info)
{
- struct mxsfb_info *host = to_imxfb_host(fb_info);
+ struct mxsfb_info *host = fb_info->par;
unsigned loop;
u32 reg;
int ret;
dev_dbg(&host->pdev->dev, "%s\n", __func__);
+ writel(CTRL_RUN, host->base + LCDC_CTRL + REG_CLR);
+
+ if (host->dispdrv && host->dispdrv->drv->disable)
+ host->dispdrv->drv->disable(host->dispdrv, fb_info);
+
/*
* Even if we disable the controller here, it will still continue
* until its FIFOs are running out of data
@@ -388,15 +784,11 @@ static void mxsfb_disable_controller(struct fb_info *fb_info)
loop--;
}
+ writel(CTRL_MASTER, host->base + LCDC_CTRL + REG_CLR);
+
reg = readl(host->base + LCDC_VDCTRL4);
writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4);
- mxsfb_disable_axi_clk(host);
-
- clk_disable_unprepare(host->clk);
- if (host->clk_disp_axi)
- clk_disable_unprepare(host->clk_disp_axi);
-
host->enabled = 0;
if (host->reg_lcd) {
@@ -407,20 +799,67 @@ static void mxsfb_disable_controller(struct fb_info *fb_info)
}
}
+/**
+ This function compare the fb parameter see whether it was different
+ parameter for hardware, if it was different parameter, the hardware
+ will reinitialize. All will compared except x/y offset.
+ */
+static bool mxsfb_par_equal(struct fb_info *fbi, struct mxsfb_info *host)
+{
+ /* Here we set the xoffset, yoffset to zero, and compare two
+ * var see have different or not. */
+ struct fb_var_screeninfo oldvar = host->var;
+ struct fb_var_screeninfo newvar = fbi->var;
+
+ if ((fbi->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW &&
+ fbi->var.activate & FB_ACTIVATE_FORCE)
+ return false;
+
+ oldvar.xoffset = newvar.xoffset = 0;
+ oldvar.yoffset = newvar.yoffset = 0;
+
+ return memcmp(&oldvar, &newvar, sizeof(struct fb_var_screeninfo)) == 0;
+}
+
static int mxsfb_set_par(struct fb_info *fb_info)
{
- struct mxsfb_info *host = to_imxfb_host(fb_info);
+ struct mxsfb_info *host = fb_info->par;
u32 ctrl, vdctrl0, vdctrl4;
int line_size, fb_size;
int reenable = 0;
+ static u32 equal_bypass = 0;
+#ifdef CONFIG_FB_IMX64_DEBUG
+ static int time;
+
+ if (time == 1)
+ return 0;
+ time++;
+#endif
+
+ if (likely(equal_bypass > 1)) {
+ /* If parameter no change, don't reconfigure. */
+ if (mxsfb_par_equal(fb_info, host))
+ return 0;
+ } else
+ equal_bypass++;
+
+ dev_dbg(&host->pdev->dev, "%s\n", __func__);
+
+ /* If fb is in blank mode, it is
+ * unnecessary to really set par here.
+ * It can be delayed when unblank fb
+ */
+ if (host->cur_blank != FB_BLANK_UNBLANK)
+ return 0;
line_size = fb_info->var.xres * (fb_info->var.bits_per_pixel >> 3);
+ fb_info->fix.line_length = line_size;
fb_size = fb_info->var.yres_virtual * line_size;
- if (fb_size > fb_info->fix.smem_len)
+ if (fb_size > fb_info->fix.smem_len) {
+ dev_err(&host->pdev->dev, "exceeds the fb buffer size limit!\n");
return -ENOMEM;
-
- fb_info->fix.line_length = line_size;
+ }
/*
* It seems, you can't re-program the controller if it is still running.
@@ -432,8 +871,6 @@ static int mxsfb_set_par(struct fb_info *fb_info)
mxsfb_disable_controller(fb_info);
}
- mxsfb_enable_axi_clk(host);
-
/* clear the FIFOs */
writel(CTRL1_FIFO_CLEAR, host->base + LCDC_CTRL1 + REG_SET);
@@ -451,12 +888,22 @@ static int mxsfb_set_par(struct fb_info *fb_info)
ctrl |= CTRL_SET_WORD_LENGTH(3);
switch (host->ld_intf_width) {
case STMLCDIF_8BIT:
- mxsfb_disable_axi_clk(host);
- dev_err(&host->pdev->dev,
+ dev_dbg(&host->pdev->dev,
"Unsupported LCD bus width mapping\n");
return -EINVAL;
case STMLCDIF_16BIT:
+ /* 24 bit to 18 bit mapping */
+ ctrl |= CTRL_DF24; /* ignore the upper 2 bits in
+ * each colour component
+ */
+ break;
case STMLCDIF_18BIT:
+ if (pixfmt_is_equal(&fb_info->var, def_rgb666))
+ /* 24 bit to 18 bit mapping */
+ ctrl |= CTRL_DF24; /* ignore the upper 2 bits in
+ * each colour component
+ */
+ break;
case STMLCDIF_24BIT:
/* real 24 bit */
break;
@@ -465,8 +912,7 @@ static int mxsfb_set_par(struct fb_info *fb_info)
writel(CTRL1_SET_BYTE_PACKAGING(0x7), host->base + LCDC_CTRL1);
break;
default:
- mxsfb_disable_axi_clk(host);
- dev_err(&host->pdev->dev, "Unhandled color depth of %u\n",
+ dev_dbg(&host->pdev->dev, "Unhandled color depth of %u\n",
fb_info->var.bits_per_pixel);
return -EINVAL;
}
@@ -481,13 +927,16 @@ static int mxsfb_set_par(struct fb_info *fb_info)
VDCTRL0_VSYNC_PERIOD_UNIT |
VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
VDCTRL0_SET_VSYNC_PULSE_WIDTH(fb_info->var.vsync_len);
- if (fb_info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ /* use the saved sync to avoid wrong sync information */
+ if (host->sync & FB_SYNC_HOR_HIGH_ACT)
vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
- if (fb_info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ if (host->sync & FB_SYNC_VERT_HIGH_ACT)
vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
- if (host->sync & MXSFB_SYNC_DATA_ENABLE_HIGH_ACT)
+#ifndef CONFIG_FB_IMX64_DEBUG
+ if (!(host->sync & FB_SYNC_OE_LOW_ACT))
vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
- if (host->sync & MXSFB_SYNC_DOTCLK_FALLING_ACT)
+#endif
+ if (host->sync & FB_SYNC_CLK_LAT_FALL)
vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
writel(vdctrl0, host->base + LCDC_VDCTRL0);
@@ -519,11 +968,15 @@ static int mxsfb_set_par(struct fb_info *fb_info)
fb_info->fix.line_length * fb_info->var.yoffset,
host->base + host->devdata->next_buf);
- mxsfb_disable_axi_clk(host);
-
if (reenable)
mxsfb_enable_controller(fb_info);
+ /* Clear activate as not Reconfiguring framebuffer again */
+ if ((fb_info->var.activate & FB_ACTIVATE_FORCE) &&
+ (fb_info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
+ fb_info->var.activate = FB_ACTIVATE_NOW;
+
+ host->var = fb_info->var;
return 0;
}
@@ -567,22 +1020,90 @@ static int mxsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
return ret;
}
+static int mxsfb_wait_for_vsync(struct fb_info *fb_info)
+{
+ struct mxsfb_info *host = fb_info->par;
+ int ret = 0;
+
+ if (host->cur_blank != FB_BLANK_UNBLANK) {
+ dev_err(fb_info->device, "can't wait for VSYNC when fb "
+ "is blank\n");
+ return -EINVAL;
+ }
+
+ init_completion(&host->vsync_complete);
+
+ host->wait4vsync = 1;
+ writel(CTRL1_VSYNC_EDGE_IRQ_EN,
+ host->base + LCDC_CTRL1 + REG_SET);
+ ret = wait_for_completion_interruptible_timeout(
+ &host->vsync_complete, 1 * HZ);
+ if (ret == 0) {
+ dev_err(fb_info->device,
+ "mxs wait for vsync timeout\n");
+ host->wait4vsync = 0;
+ ret = -ETIME;
+ } else if (ret > 0) {
+ ret = 0;
+ }
+ return ret;
+}
+
+static int mxsfb_ioctl(struct fb_info *fb_info, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = -EINVAL;
+
+ switch (cmd) {
+ case MXCFB_WAIT_FOR_VSYNC:
+ ret = mxsfb_wait_for_vsync(fb_info);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
static int mxsfb_blank(int blank, struct fb_info *fb_info)
{
- struct mxsfb_info *host = to_imxfb_host(fb_info);
+ struct mxsfb_info *host = fb_info->par;
+
+#ifdef CONFIG_FB_IMX64_DEBUG
+ return 0;
+#endif
+
+ host->cur_blank = blank;
switch (blank) {
case FB_BLANK_POWERDOWN:
case FB_BLANK_VSYNC_SUSPEND:
case FB_BLANK_HSYNC_SUSPEND:
case FB_BLANK_NORMAL:
- if (host->enabled)
+ if (host->enabled) {
mxsfb_disable_controller(fb_info);
+ pm_runtime_put_sync_suspend(&host->pdev->dev);
+ }
+
+ clk_disable_disp_axi(host);
+ clk_disable_axi(host);
+ clk_disable_pix(host);
break;
case FB_BLANK_UNBLANK:
- if (!host->enabled)
+ fb_info->var.activate = (fb_info->var.activate & ~FB_ACTIVATE_MASK) |
+ FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
+
+ clk_enable_pix(host);
+ clk_enable_axi(host);
+ clk_enable_disp_axi(host);
+
+ if (!host->enabled) {
+ pm_runtime_get_sync(&host->pdev->dev);
+
+ writel(0, host->base + LCDC_CTRL);
+ mxsfb_set_par(host->fb_info);
mxsfb_enable_controller(fb_info);
+ }
break;
}
return 0;
@@ -591,21 +1112,71 @@ static int mxsfb_blank(int blank, struct fb_info *fb_info)
static int mxsfb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *fb_info)
{
- struct mxsfb_info *host = to_imxfb_host(fb_info);
+ int ret = 0;
+ struct mxsfb_info *host = fb_info->par;
unsigned offset;
- if (var->xoffset != 0)
+ if (host->cur_blank != FB_BLANK_UNBLANK) {
+ dev_dbg(fb_info->device, "can't do pan display when fb "
+ "is blank\n");
return -EINVAL;
+ }
- offset = fb_info->fix.line_length * var->yoffset;
+ if (var->xoffset > 0) {
+ dev_dbg(fb_info->device, "x panning not supported\n");
+ return -EINVAL;
+ }
- mxsfb_enable_axi_clk(host);
+ if ((var->yoffset + var->yres > var->yres_virtual)) {
+ dev_err(fb_info->device, "y panning exceeds\n");
+ return -EINVAL;
+ }
+
+ init_completion(&host->flip_complete);
+
+ offset = fb_info->fix.line_length * var->yoffset;
/* update on next VSYNC */
writel(fb_info->fix.smem_start + offset,
host->base + host->devdata->next_buf);
- mxsfb_disable_axi_clk(host);
+ writel(CTRL1_CUR_FRAME_DONE_IRQ_EN,
+ host->base + LCDC_CTRL1 + REG_SET);
+
+ ret = wait_for_completion_timeout(&host->flip_complete, HZ / 2);
+ if (!ret) {
+ dev_err(fb_info->device,
+ "mxs wait for pan flip timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int mxsfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ u32 len;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ if (offset < info->fix.smem_len) {
+ /* mapping framebuffer memory */
+ len = info->fix.smem_len - offset;
+ vma->vm_pgoff = (info->fix.smem_start + offset) >> PAGE_SHIFT;
+ } else
+ return -EINVAL;
+
+ len = PAGE_ALIGN(len);
+ if (vma->vm_end - vma->vm_start > len)
+ return -EINVAL;
+
+ /* make buffers bufferable */
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
+ dev_dbg(info->device, "mmap remap_pfn_range failed\n");
+ return -ENOBUFS;
+ }
return 0;
}
@@ -615,31 +1186,43 @@ static struct fb_ops mxsfb_ops = {
.fb_check_var = mxsfb_check_var,
.fb_set_par = mxsfb_set_par,
.fb_setcolreg = mxsfb_setcolreg,
+ .fb_ioctl = mxsfb_ioctl,
.fb_blank = mxsfb_blank,
.fb_pan_display = mxsfb_pan_display,
+ .fb_mmap = mxsfb_mmap,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
-static int mxsfb_restore_mode(struct mxsfb_info *host,
- struct fb_videomode *vmode)
+static int mxsfb_restore_mode(struct mxsfb_info *host)
{
- struct fb_info *fb_info = &host->fb_info;
+ struct fb_info *fb_info = host->fb_info;
unsigned line_count;
unsigned period;
unsigned long pa, fbsize;
- int bits_per_pixel, ofs, ret = 0;
+ int bits_per_pixel, ofs;
u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl;
+ struct fb_videomode vmode;
- mxsfb_enable_axi_clk(host);
+ clk_enable_axi(host);
+ clk_enable_disp_axi(host);
+
+#ifndef CONFIG_FB_IMX64_DEBUG
+ /* Enable pixel clock earlier since in 7D
+ * the lcdif registers should be accessed
+ * when the pixel clock is enabled, otherwise
+ * the bus will be hang.
+ */
+ clk_enable_pix(host);
+#endif
/* Only restore the mode when the controller is running */
ctrl = readl(host->base + LCDC_CTRL);
- if (!(ctrl & CTRL_RUN)) {
- ret = -EINVAL;
- goto err;
- }
+ if (!(ctrl & CTRL_RUN))
+ return -EINVAL;
+
+ memset(&vmode, 0, sizeof(vmode));
vdctrl0 = readl(host->base + LCDC_VDCTRL0);
vdctrl2 = readl(host->base + LCDC_VDCTRL2);
@@ -648,8 +1231,8 @@ static int mxsfb_restore_mode(struct mxsfb_info *host,
transfer_count = readl(host->base + host->devdata->transfer_count);
- vmode->xres = TRANSFER_COUNT_GET_HCOUNT(transfer_count);
- vmode->yres = TRANSFER_COUNT_GET_VCOUNT(transfer_count);
+ vmode.xres = TRANSFER_COUNT_GET_HCOUNT(transfer_count);
+ vmode.yres = TRANSFER_COUNT_GET_VCOUNT(transfer_count);
switch (CTRL_GET_WORD_LENGTH(ctrl)) {
case 0:
@@ -660,53 +1243,49 @@ static int mxsfb_restore_mode(struct mxsfb_info *host,
break;
case 1:
default:
- ret = -EINVAL;
- goto err;
+ return -EINVAL;
}
fb_info->var.bits_per_pixel = bits_per_pixel;
- vmode->pixclock = KHZ2PICOS(clk_get_rate(host->clk) / 1000U);
- vmode->hsync_len = get_hsync_pulse_width(host, vdctrl2);
- vmode->left_margin = GET_HOR_WAIT_CNT(vdctrl3) - vmode->hsync_len;
- vmode->right_margin = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2) -
- vmode->hsync_len - vmode->left_margin - vmode->xres;
- vmode->vsync_len = VDCTRL0_GET_VSYNC_PULSE_WIDTH(vdctrl0);
+ vmode.pixclock = KHZ2PICOS(clk_get_rate(host->clk_pix) / 1000U);
+ vmode.hsync_len = get_hsync_pulse_width(host, vdctrl2);
+ vmode.left_margin = GET_HOR_WAIT_CNT(vdctrl3) - vmode.hsync_len;
+ vmode.right_margin = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2) - vmode.hsync_len -
+ vmode.left_margin - vmode.xres;
+ vmode.vsync_len = VDCTRL0_GET_VSYNC_PULSE_WIDTH(vdctrl0);
period = readl(host->base + LCDC_VDCTRL1);
- vmode->upper_margin = GET_VERT_WAIT_CNT(vdctrl3) - vmode->vsync_len;
- vmode->lower_margin = period - vmode->vsync_len -
- vmode->upper_margin - vmode->yres;
+ vmode.upper_margin = GET_VERT_WAIT_CNT(vdctrl3) - vmode.vsync_len;
+ vmode.lower_margin = period - vmode.vsync_len - vmode.upper_margin - vmode.yres;
- vmode->vmode = FB_VMODE_NONINTERLACED;
+ vmode.vmode = FB_VMODE_NONINTERLACED;
- vmode->sync = 0;
+ vmode.sync = 0;
if (vdctrl0 & VDCTRL0_HSYNC_ACT_HIGH)
- vmode->sync |= FB_SYNC_HOR_HIGH_ACT;
+ vmode.sync |= FB_SYNC_HOR_HIGH_ACT;
if (vdctrl0 & VDCTRL0_VSYNC_ACT_HIGH)
- vmode->sync |= FB_SYNC_VERT_HIGH_ACT;
+ vmode.sync |= FB_SYNC_VERT_HIGH_ACT;
pr_debug("Reconstructed video mode:\n");
pr_debug("%dx%d, hsync: %u left: %u, right: %u, vsync: %u, upper: %u, lower: %u\n",
- vmode->xres, vmode->yres, vmode->hsync_len, vmode->left_margin,
- vmode->right_margin, vmode->vsync_len, vmode->upper_margin,
- vmode->lower_margin);
- pr_debug("pixclk: %ldkHz\n", PICOS2KHZ(vmode->pixclock));
+ vmode.xres, vmode.yres,
+ vmode.hsync_len, vmode.left_margin, vmode.right_margin,
+ vmode.vsync_len, vmode.upper_margin, vmode.lower_margin);
+ pr_debug("pixclk: %ldkHz\n", PICOS2KHZ(vmode.pixclock));
+
+ fb_add_videomode(&vmode, &fb_info->modelist);
host->ld_intf_width = CTRL_GET_BUS_WIDTH(ctrl);
host->dotclk_delay = VDCTRL4_GET_DOTCLK_DLY(vdctrl4);
- fb_info->fix.line_length = vmode->xres * (bits_per_pixel >> 3);
+ fb_info->fix.line_length = vmode.xres * (bits_per_pixel >> 3);
pa = readl(host->base + host->devdata->cur_buf);
- fbsize = fb_info->fix.line_length * vmode->yres;
- if (pa < fb_info->fix.smem_start) {
- ret = -EINVAL;
- goto err;
- }
- if (pa + fbsize > fb_info->fix.smem_start + fb_info->fix.smem_len) {
- ret = -EINVAL;
- goto err;
- }
+ fbsize = fb_info->fix.line_length * vmode.yres;
+ if (pa < fb_info->fix.smem_start)
+ return -EINVAL;
+ if (pa + fbsize > fb_info->fix.smem_start + fb_info->fix.smem_len)
+ return -EINVAL;
ofs = pa - fb_info->fix.smem_start;
if (ofs) {
memmove(fb_info->screen_base, fb_info->screen_base + ofs, fbsize);
@@ -715,28 +1294,28 @@ static int mxsfb_restore_mode(struct mxsfb_info *host,
line_count = fb_info->fix.smem_len / fb_info->fix.line_length;
fb_info->fix.ypanstep = 1;
+ fb_info->fix.ywrapstep = 1;
- clk_prepare_enable(host->clk);
host->enabled = 1;
-err:
- if (ret)
- mxsfb_disable_axi_clk(host);
-
- return ret;
+ return 0;
}
-static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host,
- struct fb_videomode *vmode)
+static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host)
{
- struct fb_info *fb_info = &host->fb_info;
+ struct fb_info *fb_info = host->fb_info;
struct fb_var_screeninfo *var = &fb_info->var;
struct device *dev = &host->pdev->dev;
struct device_node *np = host->pdev->dev.of_node;
struct device_node *display_np;
- struct videomode vm;
+ struct device_node *timings_np;
+ struct display_timings *timings = NULL;
+ const char *disp_dev, *disp_videomode;
u32 width;
- int ret;
+ int i;
+ int ret = 0;
+
+ host->id = of_alias_get_id(np, "lcdif");
display_np = of_parse_phandle(np, "display", 0);
if (!display_np) {
@@ -776,77 +1355,216 @@ static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host,
goto put_display_node;
}
- ret = of_get_videomode(display_np, &vm, OF_USE_NATIVE_MODE);
- if (ret) {
- dev_err(dev, "failed to get videomode from DT\n");
+ ret = of_property_read_string(np, "disp-dev", &disp_dev);
+ if (!ret) {
+ memcpy(host->disp_dev, disp_dev, strlen(disp_dev));
+
+ if (!of_property_read_string(np, "disp-videomode",
+ &disp_videomode)) {
+ memcpy(host->disp_videomode, disp_videomode,
+ strlen(disp_videomode));
+ }
+
+ /* Timing is from encoder driver */
+ goto put_display_node;
+ }
+
+ timings = of_get_display_timings(display_np);
+ if (!timings) {
+ dev_err(dev, "failed to get display timings\n");
+ ret = -ENOENT;
goto put_display_node;
}
- ret = fb_videomode_from_videomode(&vm, vmode);
- if (ret < 0)
+ timings_np = of_find_node_by_name(display_np,
+ "display-timings");
+ if (!timings_np) {
+ dev_err(dev, "failed to find display-timings node\n");
+ ret = -ENOENT;
goto put_display_node;
+ }
- if (vm.flags & DISPLAY_FLAGS_DE_HIGH)
- host->sync |= MXSFB_SYNC_DATA_ENABLE_HIGH_ACT;
- if (vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
- host->sync |= MXSFB_SYNC_DOTCLK_FALLING_ACT;
+ for (i = 0; i < of_get_child_count(timings_np); i++) {
+ struct videomode vm;
+ struct fb_videomode fb_vm;
+
+ ret = videomode_from_timings(timings, &vm, i);
+ if (ret < 0)
+ goto put_timings_node;
+ ret = fb_videomode_from_videomode(&vm, &fb_vm);
+ if (ret < 0)
+ goto put_timings_node;
+
+ if (!(vm.flags & DISPLAY_FLAGS_DE_HIGH))
+ fb_vm.sync |= FB_SYNC_OE_LOW_ACT;
+ if (vm.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
+ fb_vm.sync |= FB_SYNC_CLK_LAT_FALL;
+ fb_add_videomode(&fb_vm, &fb_info->modelist);
+ }
+put_timings_node:
+ of_node_put(timings_np);
put_display_node:
+ if (timings)
+ kfree(timings);
of_node_put(display_np);
return ret;
}
-static int mxsfb_init_fbinfo(struct mxsfb_info *host,
- struct fb_videomode *vmode)
+static int mxsfb_init_fbinfo(struct mxsfb_info *host)
{
int ret;
- struct device *dev = &host->pdev->dev;
- struct fb_info *fb_info = &host->fb_info;
+ struct fb_info *fb_info = host->fb_info;
struct fb_var_screeninfo *var = &fb_info->var;
- dma_addr_t fb_phys;
- void *fb_virt;
- unsigned fb_size;
+ struct fb_modelist *modelist;
fb_info->fbops = &mxsfb_ops;
fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST;
- strlcpy(fb_info->fix.id, "mxs", sizeof(fb_info->fix.id));
fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
fb_info->fix.ypanstep = 1;
+ fb_info->fix.ywrapstep = 1;
fb_info->fix.visual = FB_VISUAL_TRUECOLOR,
fb_info->fix.accel = FB_ACCEL_NONE;
- ret = mxsfb_init_fbinfo_dt(host, vmode);
+ ret = mxsfb_init_fbinfo_dt(host);
if (ret)
return ret;
+ if (host->id < 0)
+ sprintf(fb_info->fix.id, "mxs-lcdif");
+ else
+ sprintf(fb_info->fix.id, "mxs-lcdif%d", host->id);
+
+ if (!list_empty(&fb_info->modelist)) {
+ /* first video mode in the modelist as default video mode */
+ modelist = list_first_entry(&fb_info->modelist,
+ struct fb_modelist, list);
+ fb_videomode_to_var(var, &modelist->mode);
+ }
+ /* save the sync value getting from dtb */
+ host->sync = fb_info->var.sync;
+
var->nonstd = 0;
var->activate = FB_ACTIVATE_NOW;
var->accel_flags = 0;
var->vmode = FB_VMODE_NONINTERLACED;
+ /* init the color fields */
+ mxsfb_check_var(var, fb_info);
+
+ fb_info->fix.line_length =
+ fb_info->var.xres * (fb_info->var.bits_per_pixel >> 3);
+ fb_info->fix.smem_len = SZ_32M;
+
/* Memory allocation for framebuffer */
- fb_size = SZ_2M;
- fb_virt = dma_alloc_wc(dev, PAGE_ALIGN(fb_size), &fb_phys, GFP_KERNEL);
- if (!fb_virt)
+ if (mxsfb_map_videomem(fb_info) < 0)
return -ENOMEM;
- fb_info->fix.smem_start = fb_phys;
- fb_info->screen_base = fb_virt;
- fb_info->screen_size = fb_info->fix.smem_len = fb_size;
+ if (mxsfb_restore_mode(host))
+ memset((char *)fb_info->screen_base, 0, fb_info->fix.smem_len);
- if (mxsfb_restore_mode(host, vmode))
- memset(fb_virt, 0, fb_size);
+ return 0;
+}
+
+static int mxsfb_dispdrv_init(struct platform_device *pdev,
+ struct fb_info *fbi)
+{
+ struct mxsfb_info *host = fbi->par;
+ struct mxc_dispdrv_setting setting;
+ struct device *dev = &pdev->dev;
+ char disp_dev[32];
+
+ if (!strlen(host->disp_dev))
+ return 0;
+
+ memset(&setting, 0x0, sizeof(setting));
+ setting.fbi = fbi;
+ memcpy(disp_dev, host->disp_dev, strlen(host->disp_dev));
+ disp_dev[strlen(host->disp_dev)] = '\0';
+
+ /* Use videomode name from dtb, if any given */
+ if (host->disp_videomode) {
+ setting.dft_mode_str = kmalloc(NAME_LEN, GFP_KERNEL);
+ if (setting.dft_mode_str) {
+ memset(setting.dft_mode_str, 0x0, NAME_LEN);
+ memcpy(setting.dft_mode_str, host->disp_videomode,
+ strlen(host->disp_videomode));
+ }
+ }
+
+ host->dispdrv = mxc_dispdrv_gethandle(disp_dev, &setting);
+
+ kfree(setting.dft_mode_str);
+
+ if (IS_ERR(host->dispdrv))
+ return -EPROBE_DEFER;
+ else
+ dev_info(dev, "registered mxc display driver %s\n",
+ disp_dev);
return 0;
}
static void mxsfb_free_videomem(struct mxsfb_info *host)
{
- struct device *dev = &host->pdev->dev;
- struct fb_info *fb_info = &host->fb_info;
+ struct fb_info *fb_info = host->fb_info;
- dma_free_wc(dev, fb_info->screen_size, fb_info->screen_base,
- fb_info->fix.smem_start);
+ mxsfb_unmap_videomem(fb_info);
+}
+
+/*!
+ * Allocates the DRAM memory for the frame buffer. This buffer is remapped
+ * into a non-cached, non-buffered, memory region to allow palette and pixel
+ * writes to occur without flushing the cache. Once this area is remapped,
+ * all virtual memory access to the video memory should occur at the new region.
+ *
+ * @param fbi framebuffer information pointer
+ *
+ * @return Error code indicating success or failure
+ */
+static int mxsfb_map_videomem(struct fb_info *fbi)
+{
+ if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length)
+ fbi->fix.smem_len = fbi->var.yres_virtual *
+ fbi->fix.line_length;
+
+ fbi->screen_base = dma_alloc_writecombine(fbi->device,
+ fbi->fix.smem_len,
+ (dma_addr_t *)&fbi->fix.smem_start,
+ GFP_DMA | GFP_KERNEL);
+ if (fbi->screen_base == 0) {
+ dev_err(fbi->device, "Unable to allocate framebuffer memory\n");
+ fbi->fix.smem_len = 0;
+ fbi->fix.smem_start = 0;
+ return -EBUSY;
+ }
+
+ dev_dbg(fbi->device, "allocated fb @ paddr=0x%08X, size=%d.\n",
+ (uint32_t) fbi->fix.smem_start, fbi->fix.smem_len);
+
+ fbi->screen_size = fbi->fix.smem_len;
+
+ /* Clear the screen */
+ memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
+
+ return 0;
+}
+
+/*!
+ * De-allocates the DRAM memory for the frame buffer.
+ *
+ * @param fbi framebuffer information pointer
+ *
+ * @return Error code indicating success or failure
+ */
+static int mxsfb_unmap_videomem(struct fb_info *fbi)
+{
+ dma_free_writecombine(fbi->device, fbi->fix.smem_len,
+ fbi->screen_base, fbi->fix.smem_start);
+ fbi->screen_base = 0;
+ fbi->fix.smem_start = 0;
+ fbi->fix.smem_len = 0;
+ return 0;
}
static const struct platform_device_id mxsfb_devtype[] = {
@@ -857,6 +1575,9 @@ static const struct platform_device_id mxsfb_devtype[] = {
.name = "imx28-fb",
.driver_data = MXSFB_V4,
}, {
+ .name = "imx7ulp-fb",
+ .driver_data = MXSFB_V5,
+ }, {
/* sentinel */
}
};
@@ -865,10 +1586,602 @@ MODULE_DEVICE_TABLE(platform, mxsfb_devtype);
static const struct of_device_id mxsfb_dt_ids[] = {
{ .compatible = "fsl,imx23-lcdif", .data = &mxsfb_devtype[0], },
{ .compatible = "fsl,imx28-lcdif", .data = &mxsfb_devtype[1], },
+ { .compatible = "fsl,imx7ulp-lcdif", .data = &mxsfb_devtype[2], },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mxsfb_dt_ids);
+#ifdef CONFIG_FB_MXC_OVERLAY
+static int overlay_fmt_support(uint32_t fmt)
+{
+ switch (fmt) {
+ case V4L2_PIX_FMT_ARGB32:
+ case V4L2_PIX_FMT_XRGB32:
+ return 32;
+ case V4L2_PIX_FMT_ARGB555:
+ case V4L2_PIX_FMT_ARGB444:
+ case V4L2_PIX_FMT_XRGB555:
+ case V4L2_PIX_FMT_RGB444:
+ case V4L2_PIX_FMT_RGB565:
+ return 16;
+ default:
+ return -EINVAL;
+ }
+}
+
+/* alpha mode */
+#define ALPHA_CTRL_EMBEDDED 0x0
+#define ALPHA_CTRL_OVERRIDE 0x1
+#define ALPHA_CTRL_MULTIPLY 0x2
+#define ALPHA_CTRL_ROPS 0x3
+
+static void overlayfb_enable(struct mxsfb_layer *ofb)
+{
+ struct mxsfb_info *fbi = ofb->fbi;
+
+ if (!lock_fb_info(fbi->fb_info))
+ return;
+
+ if (fbi->cur_blank == FB_BLANK_UNBLANK) {
+ mxsfb_disable_controller(fbi->fb_info);
+ writel(CTRL1_FIFO_CLEAR, fbi->base + LCDC_CTRL1 + REG_SET);
+ }
+
+ writel(0x1, fbi->base + LCDC_AS_CTRL + REG_SET);
+
+ if (fbi->cur_blank == FB_BLANK_UNBLANK) {
+ writel(CTRL1_FIFO_CLEAR, fbi->base + LCDC_CTRL1 + REG_CLR);
+ mxsfb_enable_controller(fbi->fb_info);
+ }
+ unlock_fb_info(fbi->fb_info);
+}
+
+static void overlayfb_disable(struct mxsfb_layer *ofb)
+{
+ struct mxsfb_info *fbi = ofb->fbi;
+
+ writel(0x1, fbi->base + LCDC_AS_CTRL + REG_CLR);
+}
+
+static void overlayfb_setup(struct mxsfb_layer *ofb)
+{
+ uint32_t as_next_buf, as_ctrl = 0;
+ uint8_t format, alpha_ctrl, global_alpha_en = 0;
+ struct mxsfb_info *fbi = ofb->fbi;
+ struct fb_var_screeninfo *var = &ofb->ol_fb->var;
+
+ /* set fb1 framebuffer address */
+ as_next_buf = ofb->video_mem_phys;
+ writel(as_next_buf, fbi->base + LCDC_AS_NEXT_BUF);
+
+ /* clear the LCDC_AS_CTRL */
+ writel(0x0, fbi->base + LCDC_AS_CTRL);
+
+ switch (var->grayscale) {
+ case 0: /* color */
+ switch (var->bits_per_pixel) {
+ case 16: /* RGB565 */
+ format = 0xE;
+ global_alpha_en = 1;
+ break;
+ case 32: /* ARGB8888 */
+ format = 0x0;
+ global_alpha_en = 1;
+ break;
+ default:
+ return;
+ }
+ break;
+ case 1: /* grayscale */
+ return;
+ default:
+ switch (var->grayscale) {
+ case V4L2_PIX_FMT_ARGB32:
+ format = 0x0;
+ break;
+ case V4L2_PIX_FMT_XRGB32:
+ format = 0x4;
+ global_alpha_en = 1;
+ break;
+ case V4L2_PIX_FMT_ARGB555:
+ format = 0x8;
+ break;
+ case V4L2_PIX_FMT_ARGB444:
+ format = 0x9;
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ format = 0xC;
+ global_alpha_en = 1;
+ break;
+ case V4L2_PIX_FMT_RGB444:
+ format = 0xD;
+ global_alpha_en = 1;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ format = 0xE;
+ global_alpha_en = 1;
+ break;
+ default:
+ return;
+ }
+ break;
+ }
+ as_ctrl |= ((format & 0xf) << 4);
+
+ alpha_ctrl = global_alpha_en ? ALPHA_CTRL_OVERRIDE :
+ ALPHA_CTRL_EMBEDDED;
+ as_ctrl |= ((alpha_ctrl & 0x3) << 1);
+ if (global_alpha_en)
+ as_ctrl |= ((ofb->global_alpha & 0xff) << 8);
+
+ writel(as_ctrl, fbi->base + LCDC_AS_CTRL);
+}
+
+static struct mxsfb_layer_ops ofb_ops = {
+ .enable = overlayfb_enable,
+ .disable = overlayfb_disable,
+ .setup = overlayfb_setup,
+};
+
+static int overlayfb_open(struct fb_info *info, int user)
+{
+ struct mxsfb_layer *ofb = (struct mxsfb_layer*)info->par;
+ struct mxsfb_info *fbi = ofb->fbi;
+
+ if (atomic_inc_return(&ofb->usage) == 1) {
+ ofb->ol_fb->var.xres = fbi->fb_info->var.xres;
+ ofb->ol_fb->var.yres = fbi->fb_info->var.yres;
+ ofb->ol_fb->var.xres_virtual = fbi->fb_info->var.xres_virtual;
+ ofb->ol_fb->var.yres_virtual = fbi->fb_info->var.yres;
+ ofb->ol_fb->var.bits_per_pixel = fbi->fb_info->var.bits_per_pixel;
+ ofb->ol_fb->var.vmode = FB_VMODE_NONINTERLACED;
+ }
+
+ return 0;
+}
+
+static int overlayfb_release(struct fb_info *info, int user)
+{
+ struct mxsfb_layer *ofb = (struct mxsfb_layer*)info->par;
+
+ BUG_ON(!atomic_read(&ofb->usage));
+
+ if (atomic_dec_return(&ofb->usage) == 0) {
+ if (ofb->blank_state == FB_BLANK_UNBLANK)
+ ofb->ops->disable(ofb);
+
+ ofb->blank_state = -1;
+ }
+
+ return 0;
+}
+
+static void fill_fmt_bitfields(struct fb_var_screeninfo *var,
+ const struct fb_bitfield *color)
+{
+ var->red = color[RED];
+ var->green = color[GREEN];
+ var->blue = color[BLUE];
+ var->transp = color[TRANSP];
+}
+
+static int overlayfb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ int bpp;
+ struct mxsfb_layer *ofb = (struct mxsfb_layer*)info->par;
+ struct mxsfb_info *fbi = ofb->fbi;
+ const struct fb_bitfield *rgb = NULL;
+
+ /* lcdif doesn't support different bpp of AS and PS */
+ if (var->bits_per_pixel != fbi->fb_info->var.bits_per_pixel)
+ return -EINVAL;
+
+ /* overlay width & should be equal to fb0 */
+ if ((var->xres != fbi->fb_info->var.xres) ||
+ (var->yres != fbi->fb_info->var.yres))
+ return -EINVAL;
+
+ if ((var->xres > 2048) || (var->yres > 2048))
+ return -EINVAL;
+
+ if (var->xres_virtual > var->xres)
+ return -EINVAL;
+
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+
+ switch (var->grayscale) {
+ case 0: /* color */
+ switch (var->bits_per_pixel) {
+ case 16:/* RGB565 */
+ rgb = def_rgb565;
+ break;
+ case 32:/* ARGB8888 */
+ rgb = def_argb32;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case 1: /* grayscale */
+ return -EINVAL;
+ default: /* fourcc */
+ if ((bpp = overlay_fmt_support(var->grayscale)) < 0) {
+ dev_err(info->dev, "unsupport pixel format for overlay\n");
+ return -EINVAL;
+ }
+
+ var->bits_per_pixel = bpp;
+ if (var->bits_per_pixel < 16)
+ return -EINVAL;
+
+ switch (var->grayscale) {
+ case V4L2_PIX_FMT_ARGB32:
+ rgb = def_argb32;
+ break;
+ case V4L2_PIX_FMT_XRGB32:
+ rgb = def_rgb888;
+ break;
+ case V4L2_PIX_FMT_ARGB555:
+ rgb = def_argb555;
+ break;
+ case V4L2_PIX_FMT_ARGB444:
+ rgb = def_argb444;
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ rgb = def_rgb555;
+ break;
+ case V4L2_PIX_FMT_RGB444:
+ rgb = def_rgb444;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ rgb = def_rgb565;
+ break;
+ default:
+ /*
+ * This should never be reached since the verification
+ * is done in overlay_fmt_support(), but handle this in
+ * case there will be a sync error between formats
+ * supported in fmt_support and this function.
+ */
+ return -EINVAL;
+ }
+ break;
+ }
+
+ if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
+ info->fix.smem_len)
+ return -EINVAL;
+
+ fill_fmt_bitfields(var, rgb);
+
+ return 0;
+}
+
+static int overlayfb_set_par(struct fb_info *info)
+{
+ int size, bpp;
+ struct mxsfb_layer *ofb = (struct mxsfb_layer*)info->par;
+ struct mxsfb_info *fbi = ofb->fbi;
+ struct fb_var_screeninfo *var = &ofb->ol_fb->var;
+
+ bpp = var->bits_per_pixel;
+ ofb->ol_fb->fix.line_length = var->xres_virtual * bpp / 8;
+
+ size = PAGE_ALIGN(ofb->ol_fb->fix.line_length * var->yres_virtual);
+ if (ofb->video_mem_size < size)
+ return -EINVAL;
+
+ if (!lock_fb_info(fbi->fb_info))
+ return -EINVAL;
+
+ if (fbi->cur_blank != FB_BLANK_UNBLANK) {
+ clk_enable_pix(fbi);
+ clk_enable_axi(fbi);
+ clk_enable_disp_axi(fbi);
+ }
+ unlock_fb_info(fbi->fb_info);
+
+ if (ofb->blank_state == FB_BLANK_UNBLANK)
+ ofb->ops->disable(ofb);
+
+ ofb->ops->setup(ofb);
+
+ if (ofb->blank_state == FB_BLANK_UNBLANK)
+ ofb->ops->enable(ofb);
+
+ if (!lock_fb_info(fbi->fb_info))
+ return -EINVAL;
+
+ if (fbi->cur_blank != FB_BLANK_UNBLANK) {
+ clk_disable_disp_axi(fbi);
+ clk_disable_axi(fbi);
+ clk_disable_pix(fbi);
+ }
+ unlock_fb_info(fbi->fb_info);
+
+ if ((var->activate & FB_ACTIVATE_FORCE) &&
+ (var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
+ var->activate = FB_ACTIVATE_NOW;
+
+ return 0;
+}
+
+static int overlayfb_blank(int blank, struct fb_info *info)
+{
+ struct mxsfb_layer *ofb = (struct mxsfb_layer*)info->par;
+ struct mxsfb_info *fbi = ofb->fbi;
+
+ if (ofb->blank_state == blank)
+ return 0;
+
+ if (!lock_fb_info(fbi->fb_info))
+ return -EINVAL;
+
+ if (fbi->cur_blank != FB_BLANK_UNBLANK) {
+ clk_enable_pix(fbi);
+ clk_enable_axi(fbi);
+ clk_enable_disp_axi(fbi);
+ }
+ unlock_fb_info(fbi->fb_info);
+
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ ofb->ops->disable(ofb);
+ break;
+ case FB_BLANK_UNBLANK:
+ ofb->ops->enable(ofb);
+ break;
+ }
+
+ if (!lock_fb_info(fbi->fb_info))
+ return -EINVAL;
+
+ if (fbi->cur_blank != FB_BLANK_UNBLANK) {
+ clk_disable_disp_axi(fbi);
+ clk_disable_axi(fbi);
+ clk_disable_pix(fbi);
+ }
+ unlock_fb_info(fbi->fb_info);
+
+ ofb->blank_state = blank;
+
+ return 0;
+}
+
+static int overlayfb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ int ret = 0;
+ unsigned int bytes_offset;
+ struct mxsfb_layer *ofb = (struct mxsfb_layer *)info->par;
+ struct mxsfb_info *fbi = ofb->fbi;
+
+ init_completion(&fbi->flip_complete);
+
+ if (!lock_fb_info(fbi->fb_info))
+ return -EINVAL;
+
+ if (fbi->cur_blank != FB_BLANK_UNBLANK) {
+ unlock_fb_info(fbi->fb_info);
+ return -EINVAL;
+ }
+
+ unlock_fb_info(fbi->fb_info);
+
+ bytes_offset = info->fix.line_length * var->yoffset;
+ writel(info->fix.smem_start + bytes_offset,
+ fbi->base + LCDC_AS_NEXT_BUF);
+
+ /* update on next VSYNC */
+ writel(CTRL1_CUR_FRAME_DONE_IRQ_EN,
+ fbi->base + LCDC_CTRL1 + REG_SET);
+
+ ret = wait_for_completion_timeout(&fbi->flip_complete, HZ / 2);
+ if (!ret) {
+ dev_err(info->device,
+ "overlay wait for pane flip timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static struct fb_ops overlay_fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = overlayfb_open,
+ .fb_release = overlayfb_release,
+ .fb_check_var = overlayfb_check_var,
+ .fb_set_par = overlayfb_set_par,
+ .fb_blank = overlayfb_blank,
+ .fb_pan_display = overlayfb_pan_display,
+ .fb_mmap = mxsfb_mmap,
+};
+
+static void init_mxsfb_overlay(struct mxsfb_info *fbi,
+ struct mxsfb_layer *ofb)
+{
+ dev_dbg(&fbi->pdev->dev, "AS overlay init\n");
+
+ ofb->ol_fb->fix.type = FB_TYPE_PACKED_PIXELS;
+ ofb->ol_fb->fix.xpanstep = 0;
+ ofb->ol_fb->fix.ypanstep = 1;
+ ofb->ol_fb->fix.ywrapstep = 1;
+ ofb->ol_fb->fix.visual = FB_VISUAL_TRUECOLOR;
+ ofb->ol_fb->fix.accel = FB_ACCEL_NONE;
+
+ ofb->ol_fb->var.activate = FB_ACTIVATE_NXTOPEN;
+ ofb->ol_fb->var.xres = fbi->fb_info->var.xres;
+ ofb->ol_fb->var.yres = fbi->fb_info->var.yres;
+ ofb->ol_fb->var.xres_virtual = fbi->fb_info->var.xres_virtual;
+ ofb->ol_fb->var.yres_virtual = fbi->fb_info->var.yres;
+ ofb->ol_fb->var.bits_per_pixel = fbi->fb_info->var.bits_per_pixel;
+ ofb->ol_fb->var.vmode = FB_VMODE_NONINTERLACED;
+ ofb->ol_fb->var.nonstd = 0;
+
+ /* Copy timings of primary fb */
+ ofb->ol_fb->var.pixclock = fbi->fb_info->var.pixclock;
+ ofb->ol_fb->var.left_margin = fbi->fb_info->var.left_margin;
+ ofb->ol_fb->var.right_margin = fbi->fb_info->var.right_margin;
+ ofb->ol_fb->var.upper_margin = fbi->fb_info->var.upper_margin;
+ ofb->ol_fb->var.lower_margin = fbi->fb_info->var.lower_margin;
+ ofb->ol_fb->var.hsync_len = fbi->fb_info->var.hsync_len;
+ ofb->ol_fb->var.vsync_len = fbi->fb_info->var.vsync_len;
+
+ ofb->ol_fb->fbops = &overlay_fb_ops;
+ ofb->ol_fb->node = -1;
+ ofb->ol_fb->par = ofb;
+ INIT_LIST_HEAD(&ofb->ol_fb->modelist);
+
+ ofb->id = 0;
+ ofb->ops = &ofb_ops;
+ atomic_set(&ofb->usage, 0);
+ ofb->blank_state = -1;
+ ofb->global_alpha = 255;
+ ofb->fbi = fbi;
+
+ sprintf(ofb->ol_fb->fix.id, "FG");
+}
+
+static int mxsfb_overlay_map_video_memory(struct mxsfb_info *fbi,
+ struct mxsfb_layer *ofb)
+{
+ struct fb_info *fb = fbi->fb_info;
+ BUG_ON(!fb->fix.smem_len);
+
+ ofb->video_mem_size = fb->fix.smem_len;
+ ofb->video_mem = dma_alloc_writecombine(ofb->dev,
+ ofb->video_mem_size,
+ (dma_addr_t *)&ofb->video_mem_phys,
+ GFP_DMA | GFP_KERNEL);
+
+ if (ofb->video_mem == NULL) {
+ dev_err(ofb->dev, "Unable to allocate overlay fb memory\n");
+ return -ENOMEM;
+ }
+
+ /* clear overlay fb memory buffer */
+ memset(ofb->video_mem, 0x0, ofb->video_mem_size);
+
+ ofb->ol_fb->fix.smem_start = ofb->video_mem_phys;
+ ofb->ol_fb->fix.smem_len = ofb->video_mem_size;
+ ofb->ol_fb->screen_base = ofb->video_mem;
+
+ return 0;
+}
+
+static void mxsfb_overlay_init(struct mxsfb_info *fbi)
+{
+ int ret;
+ struct mxsfb_layer *ofb = &fbi->overlay;
+ struct fb_videomode ofb_vm;
+
+ ofb->dev = &fbi->pdev->dev;
+ ofb->ol_fb = framebuffer_alloc(0, ofb->dev);
+ if (!ofb->ol_fb) {
+ dev_err(ofb->dev, "Faild to allocate overlay fbinfo\n");
+ return;
+ }
+
+ init_mxsfb_overlay(fbi, ofb);
+
+ /* add videomode to overlay fb */
+ fb_var_to_videomode(&ofb_vm, &fbi->fb_info->var);
+ ret = fb_add_videomode(&ofb_vm, &ofb->ol_fb->modelist);
+ if (ret) {
+ dev_err(ofb->dev, "add vm to ofb failed\n");
+ goto fb_release;
+ }
+
+ ret = register_framebuffer(ofb->ol_fb);
+ if (ret) {
+ dev_err(ofb->dev, "failed to register overlay\n");
+ goto fb_release;
+ }
+
+ ret = mxsfb_overlay_map_video_memory(fbi, ofb);
+ if (ret) {
+ dev_err(ofb->dev, "failed to map video mem for overlay\n");
+ goto fb_unregister;
+ }
+
+ /* setup the initial params for overlay fb */
+ overlayfb_check_var(&ofb->ol_fb->var, ofb->ol_fb);
+ overlayfb_set_par(ofb->ol_fb);
+
+ ofb->registered = 1;
+
+ return;
+
+fb_unregister:
+ unregister_framebuffer(ofb->ol_fb);
+fb_release:
+ framebuffer_release(ofb->ol_fb);
+}
+
+static void mxsfb_overlay_exit(struct mxsfb_info *fbi)
+{
+ struct mxsfb_layer *ofb = &fbi->overlay;
+
+ if (ofb->registered) {
+ if (ofb->video_mem)
+ dma_free_writecombine(ofb->dev, ofb->video_mem_size,
+ ofb->video_mem, ofb->video_mem_phys);
+
+ unregister_framebuffer(ofb->ol_fb);
+ framebuffer_release(ofb->ol_fb);
+ }
+}
+
+static void mxsfb_overlay_resume(struct mxsfb_info *fbi)
+{
+ if (fbi->cur_blank != FB_BLANK_UNBLANK) {
+ clk_enable_pix(fbi);
+ clk_enable_axi(fbi);
+ clk_enable_disp_axi(fbi);
+ }
+
+ writel(saved_as_ctrl, fbi->base + LCDC_AS_CTRL);
+ writel(saved_as_next_buf, fbi->base + LCDC_AS_NEXT_BUF);
+
+ if (fbi->cur_blank != FB_BLANK_UNBLANK) {
+ clk_disable_disp_axi(fbi);
+ clk_disable_axi(fbi);
+ clk_disable_pix(fbi);
+ }
+
+}
+
+static void mxsfb_overlay_suspend(struct mxsfb_info *fbi)
+{
+ if (fbi->cur_blank != FB_BLANK_UNBLANK) {
+ clk_enable_pix(fbi);
+ clk_enable_axi(fbi);
+ clk_enable_disp_axi(fbi);
+ }
+
+ saved_as_ctrl = readl(fbi->base + LCDC_AS_CTRL);
+ saved_as_next_buf = readl(fbi->base + LCDC_AS_NEXT_BUF);
+
+ if (fbi->cur_blank != FB_BLANK_UNBLANK) {
+ clk_disable_disp_axi(fbi);
+ clk_disable_axi(fbi);
+ clk_disable_pix(fbi);
+ }
+}
+#else
+static void mxsfb_overlay_init(struct mxsfb_info *fbi) {}
+static void mxsfb_overlay_exit(struct mxsfb_info *fbi) {}
+static void mxsfb_overlay_resume(struct mxsfb_info *fbi) {}
+static void mxsfb_overlay_suspend(struct mxsfb_info *fbi) {}
+#endif
+
static int mxsfb_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
@@ -876,28 +2189,58 @@ static int mxsfb_probe(struct platform_device *pdev)
struct resource *res;
struct mxsfb_info *host;
struct fb_info *fb_info;
- struct fb_videomode *mode;
- int ret;
+ struct pinctrl *pinctrl;
+ int irq = platform_get_irq(pdev, 0);
+ int gpio, ret;
if (of_id)
pdev->id_entry = of_id->data;
- fb_info = framebuffer_alloc(sizeof(struct mxsfb_info), &pdev->dev);
- if (!fb_info) {
- dev_err(&pdev->dev, "Failed to allocate fbdev\n");
+ gpio = of_get_named_gpio(pdev->dev.of_node, "enable-gpio", 0);
+ if (gpio == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ if (gpio_is_valid(gpio)) {
+ ret = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_OUT_INIT_LOW, "lcd_pwr_en");
+ if (ret) {
+ dev_err(&pdev->dev, "faild to request gpio %d, ret = %d\n", gpio, ret);
+ return ret;
+ }
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Cannot get memory IO resource\n");
+ return -ENODEV;
+ }
+
+ host = devm_kzalloc(&pdev->dev, sizeof(struct mxsfb_info), GFP_KERNEL);
+ if (!host) {
+ dev_err(&pdev->dev, "Failed to allocate IO resource\n");
return -ENOMEM;
}
- mode = devm_kzalloc(&pdev->dev, sizeof(struct fb_videomode),
- GFP_KERNEL);
- if (mode == NULL)
+ fb_info = framebuffer_alloc(0, &pdev->dev);
+ if (!fb_info) {
+ dev_err(&pdev->dev, "Failed to allocate fbdev\n");
+ devm_kfree(&pdev->dev, host);
return -ENOMEM;
+ }
+ host->fb_info = fb_info;
+ fb_info->par = host;
- host = to_imxfb_host(fb_info);
+ ret = devm_request_irq(&pdev->dev, irq, mxsfb_irq_handler, 0,
+ dev_name(&pdev->dev), host);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq (%d) failed with error %d\n",
+ irq, ret);
+ ret = -ENODEV;
+ goto fb_release;
+ }
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->base)) {
+ dev_err(&pdev->dev, "ioremap failed\n");
ret = PTR_ERR(host->base);
goto fb_release;
}
@@ -907,19 +2250,28 @@ static int mxsfb_probe(struct platform_device *pdev)
host->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];
- host->clk = devm_clk_get(&host->pdev->dev, NULL);
- if (IS_ERR(host->clk)) {
- ret = PTR_ERR(host->clk);
+ host->clk_pix = devm_clk_get(&host->pdev->dev, "pix");
+ if (IS_ERR(host->clk_pix)) {
+ host->clk_pix = NULL;
+ ret = PTR_ERR(host->clk_pix);
goto fb_release;
}
host->clk_axi = devm_clk_get(&host->pdev->dev, "axi");
- if (IS_ERR(host->clk_axi))
+ if (IS_ERR(host->clk_axi)) {
host->clk_axi = NULL;
+ ret = PTR_ERR(host->clk_axi);
+ dev_err(&pdev->dev, "Failed to get axi clock: %d\n", ret);
+ goto fb_release;
+ }
host->clk_disp_axi = devm_clk_get(&host->pdev->dev, "disp_axi");
- if (IS_ERR(host->clk_disp_axi))
+ if (IS_ERR(host->clk_disp_axi)) {
host->clk_disp_axi = NULL;
+ ret = PTR_ERR(host->clk_disp_axi);
+ dev_err(&pdev->dev, "Failed to get disp_axi clock: %d\n", ret);
+ goto fb_release;
+ }
host->reg_lcd = devm_regulator_get(&pdev->dev, "lcd");
if (IS_ERR(host->reg_lcd))
@@ -929,79 +2281,205 @@ static int mxsfb_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!fb_info->pseudo_palette) {
ret = -ENOMEM;
+ dev_err(&pdev->dev, "Failed to allocate pseudo_palette memory\n");
goto fb_release;
}
- ret = mxsfb_init_fbinfo(host, mode);
- if (ret != 0)
- goto fb_release;
-
- fb_videomode_to_var(&fb_info->var, mode);
+ INIT_LIST_HEAD(&fb_info->modelist);
- /* init the color fields */
- mxsfb_check_var(&fb_info->var, fb_info);
+ pm_runtime_enable(&host->pdev->dev);
- platform_set_drvdata(pdev, fb_info);
+ ret = mxsfb_init_fbinfo(host);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Failed to initialize fbinfo: %d\n", ret);
+ goto fb_pm_runtime_disable;
+ }
- ret = register_framebuffer(fb_info);
+ ret = mxsfb_dispdrv_init(pdev, fb_info);
if (ret != 0) {
- dev_err(&pdev->dev,"Failed to register framebuffer\n");
- goto fb_destroy;
+ if (ret == -EPROBE_DEFER)
+ dev_info(&pdev->dev,
+ "Defer fb probe due to dispdrv not ready\n");
+ goto fb_free_videomem;
+ }
+
+ if (!host->dispdrv) {
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto fb_pm_runtime_disable;
+ }
}
if (!host->enabled) {
- mxsfb_enable_axi_clk(host);
writel(0, host->base + LCDC_CTRL);
- mxsfb_disable_axi_clk(host);
mxsfb_set_par(fb_info);
mxsfb_enable_controller(fb_info);
+ pm_runtime_get_sync(&host->pdev->dev);
+ }
+
+ ret = register_framebuffer(fb_info);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "Failed to register framebuffer\n");
+ goto fb_destroy;
+ }
+
+ mxsfb_overlay_init(host);
+
+#ifndef CONFIG_FB_IMX64_DEBUG
+ console_lock();
+ ret = fb_blank(fb_info, FB_BLANK_UNBLANK);
+ console_unlock();
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to unblank framebuffer\n");
+ goto fb_unregister;
}
+#endif
dev_info(&pdev->dev, "initialized\n");
return 0;
+#ifndef CONFIG_FB_IMX64_DEBUG
+fb_unregister:
+ unregister_framebuffer(fb_info);
+#endif
fb_destroy:
- if (host->enabled)
- clk_disable_unprepare(host->clk);
+ fb_destroy_modelist(&fb_info->modelist);
+fb_free_videomem:
+ mxsfb_free_videomem(host);
+fb_pm_runtime_disable:
+ clk_disable_pix(host);
+ clk_disable_axi(host);
+ clk_disable_disp_axi(host);
+
+ pm_runtime_disable(&host->pdev->dev);
+ devm_kfree(&pdev->dev, fb_info->pseudo_palette);
fb_release:
framebuffer_release(fb_info);
+ devm_kfree(&pdev->dev, host);
return ret;
}
static int mxsfb_remove(struct platform_device *pdev)
{
- struct fb_info *fb_info = platform_get_drvdata(pdev);
- struct mxsfb_info *host = to_imxfb_host(fb_info);
+ struct mxsfb_info *host = platform_get_drvdata(pdev);
+ struct fb_info *fb_info = host->fb_info;
if (host->enabled)
mxsfb_disable_controller(fb_info);
+ if (host->devdata->flags & MXSFB_FLAG_PMQOS)
+ pm_qos_remove_request(&host->pm_qos_req);
+
+ pm_runtime_disable(&host->pdev->dev);
+ mxsfb_overlay_exit(host);
unregister_framebuffer(fb_info);
mxsfb_free_videomem(host);
+ platform_set_drvdata(pdev, NULL);
+
+ devm_kfree(&pdev->dev, fb_info->pseudo_palette);
framebuffer_release(fb_info);
+ devm_kfree(&pdev->dev, host);
return 0;
}
static void mxsfb_shutdown(struct platform_device *pdev)
{
- struct fb_info *fb_info = platform_get_drvdata(pdev);
- struct mxsfb_info *host = to_imxfb_host(fb_info);
-
- mxsfb_enable_axi_clk(host);
+ struct mxsfb_info *host = platform_get_drvdata(pdev);
/*
* Force stop the LCD controller as keeping it running during reboot
* might interfere with the BootROM's boot mode pads sampling.
*/
- writel(CTRL_RUN, host->base + LCDC_CTRL + REG_CLR);
+ if (host->cur_blank == FB_BLANK_UNBLANK) {
+ writel(CTRL_RUN, host->base + LCDC_CTRL + REG_CLR);
+ writel(CTRL_MASTER, host->base + LCDC_CTRL + REG_CLR);
+ }
+}
+
+#ifdef CONFIG_PM
+static int mxsfb_runtime_suspend(struct device *dev)
+{
+ struct mxsfb_info *host = dev_get_drvdata(dev);
- mxsfb_disable_axi_clk(host);
+ if (host->devdata->flags & MXSFB_FLAG_BUSFREQ)
+ release_bus_freq(BUS_FREQ_HIGH);
+
+ if (host->devdata->flags & MXSFB_FLAG_PMQOS)
+ pm_qos_remove_request(&host->pm_qos_req);
+
+ dev_dbg(dev, "mxsfb busfreq high release.\n");
+
+ return 0;
}
+static int mxsfb_runtime_resume(struct device *dev)
+{
+ struct mxsfb_info *host = dev_get_drvdata(dev);
+
+ if (host->devdata->flags & MXSFB_FLAG_BUSFREQ)
+ request_bus_freq(BUS_FREQ_HIGH);
+
+ if (host->devdata->flags & MXSFB_FLAG_PMQOS)
+ pm_qos_add_request(&host->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY, 0);
+
+ dev_dbg(dev, "mxsfb busfreq high request.\n");
+
+ return 0;
+}
+
+static int mxsfb_suspend(struct device *pdev)
+{
+ struct mxsfb_info *host = dev_get_drvdata(pdev);
+ struct fb_info *fb_info = host->fb_info;
+ int saved_blank;
+
+ console_lock();
+ mxsfb_overlay_suspend(host);
+ fb_set_suspend(fb_info, 1);
+ saved_blank = host->cur_blank;
+ mxsfb_blank(FB_BLANK_POWERDOWN, fb_info);
+ host->restore_blank = saved_blank;
+ console_unlock();
+
+ pinctrl_pm_select_sleep_state(pdev);
+
+ return 0;
+}
+
+static int mxsfb_resume(struct device *pdev)
+{
+ struct mxsfb_info *host = dev_get_drvdata(pdev);
+ struct fb_info *fb_info = host->fb_info;
+
+ pinctrl_pm_select_default_state(pdev);
+
+ console_lock();
+ mxsfb_blank(host->restore_blank, fb_info);
+ fb_set_suspend(fb_info, 0);
+ mxsfb_overlay_resume(host);
+ console_unlock();
+
+ return 0;
+}
+#else
+#define mxsfb_runtime_suspend NULL
+#define mxsfb_runtime_resume NULL
+
+#define mxsfb_suspend NULL
+#define mxsfb_resume NULL
+#endif
+
+static const struct dev_pm_ops mxsfb_pm_ops = {
+ SET_RUNTIME_PM_OPS(mxsfb_runtime_suspend, mxsfb_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(mxsfb_suspend, mxsfb_resume)
+};
+
static struct platform_driver mxsfb_driver = {
.probe = mxsfb_probe,
.remove = mxsfb_remove,
@@ -1010,6 +2488,7 @@ static struct platform_driver mxsfb_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = mxsfb_dt_ids,
+ .pm = &mxsfb_pm_ops,
},
};
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index b73520aaf697..28b1e325536f 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -393,6 +393,103 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
}
EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
+/**
+ * hdmi_drm_infoframe_init() - initialize an HDMI Dynaminc Range and
+ * mastering infoframe
+ * @frame: HDMI DRM infoframe
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame)
+{
+ memset(frame, 0, sizeof(*frame));
+
+ frame->type = HDMI_INFOFRAME_TYPE_DRM;
+ frame->version = 1;
+
+ return 0;
+}
+EXPORT_SYMBOL(hdmi_drm_infoframe_init);
+
+/**
+ * hdmi_drm_infoframe_pack() - write HDMI DRM infoframe to binary buffer
+ * @frame: HDMI DRM infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Packs the information contained in the @frame structure into a binary
+ * representation that can be written into the corresponding controller
+ * registers. Also computes the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_drm_infoframe_pack(struct hdmi_drm_infoframe *frame, void *buffer,
+ size_t size)
+{
+ u8 *ptr = buffer;
+ size_t length;
+
+ length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
+
+ if (size < length)
+ return -ENOSPC;
+
+ memset(buffer, 0, size);
+
+ ptr[0] = frame->type;
+ ptr[1] = frame->version;
+ ptr[2] = frame->length;
+ ptr[3] = 0; /* checksum */
+
+ /* start infoframe payload */
+ ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+ ptr[0] = frame->eotf;
+ ptr[1] = frame->metadata_type;
+
+ ptr[2] = frame->display_primaries_x[0] & 0xff;
+ ptr[3] = frame->display_primaries_x[0] >> 8;
+
+ ptr[4] = frame->display_primaries_x[1] & 0xff;
+ ptr[5] = frame->display_primaries_x[1] >> 8;
+
+ ptr[6] = frame->display_primaries_x[2] & 0xff;
+ ptr[7] = frame->display_primaries_x[2] >> 8;
+
+ ptr[9] = frame->display_primaries_y[0] & 0xff;
+ ptr[10] = frame->display_primaries_y[0] >> 8;
+
+ ptr[11] = frame->display_primaries_y[1] & 0xff;
+ ptr[12] = frame->display_primaries_y[1] >> 8;
+
+ ptr[13] = frame->display_primaries_y[2] & 0xff;
+ ptr[14] = frame->display_primaries_y[2] >> 8;
+
+ ptr[15] = frame->white_point_x & 0xff;
+ ptr[16] = frame->white_point_x >> 8;
+
+ ptr[17] = frame->white_point_y & 0xff;
+ ptr[18] = frame->white_point_y >> 8;
+
+ ptr[19] = frame->max_mastering_display_luminance & 0xff;
+ ptr[20] = frame->max_mastering_display_luminance >> 8;
+
+ ptr[21] = frame->min_mastering_display_luminance & 0xff;
+ ptr[22] = frame->min_mastering_display_luminance >> 8;
+
+ ptr[23] = frame->max_cll & 0xff;
+ ptr[24] = frame->max_cll >> 8;
+
+ ptr[25] = frame->max_fall & 0xff;
+ ptr[26] = frame->max_fall >> 8;
+
+ hdmi_infoframe_set_checksum(buffer, length);
+
+ return length;
+}
+
/*
* hdmi_vendor_any_infoframe_pack() - write a vendor infoframe to binary buffer
*/
@@ -430,6 +527,9 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
case HDMI_INFOFRAME_TYPE_AVI:
length = hdmi_avi_infoframe_pack(&frame->avi, buffer, size);
break;
+ case HDMI_INFOFRAME_TYPE_DRM:
+ length = hdmi_drm_infoframe_pack(&frame->drm, buffer, size);
+ break;
case HDMI_INFOFRAME_TYPE_SPD:
length = hdmi_spd_infoframe_pack(&frame->spd, buffer, size);
break;
@@ -462,6 +562,8 @@ static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
return "Source Product Description (SPD)";
case HDMI_INFOFRAME_TYPE_AUDIO:
return "Audio";
+ case HDMI_INFOFRAME_TYPE_DRM:
+ return "Dynamic Range and Mastering";
}
return "Reserved";
}
@@ -538,6 +640,10 @@ hdmi_picture_aspect_get_name(enum hdmi_picture_aspect picture_aspect)
return "4:3";
case HDMI_PICTURE_ASPECT_16_9:
return "16:9";
+ case HDMI_PICTURE_ASPECT_64_27:
+ return "64:27";
+ case HDMI_PICTURE_ASPECT_256_135:
+ return "256:135";
case HDMI_PICTURE_ASPECT_RESERVED:
return "Reserved";
}
@@ -904,6 +1010,39 @@ static void hdmi_audio_infoframe_log(const char *level,
frame->downmix_inhibit ? "Yes" : "No");
}
+/**
+ * hdmi_drm_infoframe_log() - log info of HDMI DRM infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI DRM infoframe
+ */
+static void hdmi_drm_infoframe_log(const char *level,
+ struct device *dev,
+ struct hdmi_drm_infoframe *frame)
+{
+ int i;
+
+ hdmi_infoframe_log_header(level, dev,
+ (struct hdmi_any_infoframe *)frame);
+ hdmi_log("length: %d\n", frame->length);
+ hdmi_log("eotf: %d\n", frame->eotf);
+ for (i = 0; i <= 2; i++) {
+ hdmi_log("x[%d]: %d\n", i, frame->display_primaries_x[i]);
+ hdmi_log("y[%d]: %d\n", i, frame->display_primaries_y[i]);
+ }
+
+ hdmi_log("white point x: %d\n", frame->white_point_x);
+ hdmi_log("white point y: %d\n", frame->white_point_y);
+
+ hdmi_log("max_mastering_display_luminance: %d\n",
+ frame->max_mastering_display_luminance);
+ hdmi_log("min_mastering_display_luminance: %d\n",
+ frame->min_mastering_display_luminance);
+
+ hdmi_log("max_cll: %d\n", frame->max_cll);
+ hdmi_log("max_fall: %d\n", frame->max_fall);
+}
+
static const char *
hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)
{
@@ -992,6 +1131,9 @@ void hdmi_infoframe_log(const char *level,
case HDMI_INFOFRAME_TYPE_VENDOR:
hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
break;
+ case HDMI_INFOFRAME_TYPE_DRM:
+ hdmi_drm_infoframe_log(level, dev, &frame->drm);
+ break;
}
}
EXPORT_SYMBOL(hdmi_infoframe_log);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 8f8909a668d7..523e6a73664e 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -540,7 +540,7 @@ config MAX77620_WATCHDOG
config IMX2_WDT
tristate "IMX2+ Watchdog"
- depends on ARCH_MXC || ARCH_LAYERSCAPE
+ depends on ARCH_MXC || ARCH_LAYERSCAPE || ARCH_MXC_ARM64
select REGMAP_MMIO
select WATCHDOG_CORE
help
@@ -552,6 +552,30 @@ config IMX2_WDT
To compile this driver as a module, choose M here: the
module will be called imx2_wdt.
+config IMX7ULP_WDT
+ tristate "IMX7ULP Watchdog"
+ depends on ARCH_MXC
+ select WATCHDOG_CORE
+ help
+ This is the driver for the hardware watchdog
+ on the Freescale IMX7ULP and later processors.
+ If you have one of these processors and wish to have
+ watchdog support enabled, say Y, otherwise say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imx7ulp_wdt.
+
+config IMX8_WDT
+ tristate "IMX8 Watchdog"
+ depends on OF
+ select WATCHDOG_CORE
+ help
+ This is the driver for the watchdog on i.mx8QM/QXP
+ and later processors, this virtual watch dog call
+ the interfaces which provided by SCFW.
+ If you have one of these processors and wish to have
+ watchdog support enabled, say Y, otherwise say N.
+
config UX500_WATCHDOG
tristate "ST-Ericsson Ux500 watchdog"
depends on MFD_DB8500_PRCMU
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index caa9f4aa492a..3d2a0f8277e5 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -64,6 +64,8 @@ obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
obj-$(CONFIG_TS4800_WATCHDOG) += ts4800_wdt.o
obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
+obj-$(CONFIG_IMX7ULP_WDT) += imx7ulp_wdt.o
+obj-$(CONFIG_IMX8_WDT) += imx8_wdt.o
obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o
obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index 518dfa1047cb..fd28b660f475 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -2,7 +2,8 @@
* Watchdog driver for IMX2 and later processors
*
* Copyright (C) 2010 Wolfram Sang, Pengutronix e.K. <w.sang@pengutronix.de>
- * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP.
*
* some parts adapted by similar drivers from Darius Augulis and Vladimir
* Zapolskiy, additional improvements by Wim Van Sebroeck.
@@ -92,6 +93,26 @@ static const struct watchdog_info imx2_wdt_pretimeout_info = {
WDIOF_PRETIMEOUT,
};
+static int imx2_wdt_ping(struct watchdog_device *wdog)
+{
+ struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
+
+ regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ1);
+ regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ2);
+ return 0;
+}
+
+
+static inline bool imx2_wdt_is_running(struct imx2_wdt_device *wdev)
+{
+ u32 val;
+
+ regmap_read(wdev->regmap, IMX2_WDT_WCR, &val);
+
+ return val & IMX2_WDT_WCR_WDE;
+}
+
+
static int imx2_wdt_restart(struct watchdog_device *wdog, unsigned long action,
void *data)
{
@@ -106,6 +127,10 @@ static int imx2_wdt_restart(struct watchdog_device *wdog, unsigned long action,
/* Assert SRS signal */
regmap_write(wdev->regmap, IMX2_WDT_WCR, wcr_enable);
+
+ if (imx2_wdt_is_running(wdev))
+ imx2_wdt_ping(wdog);
+
/*
* Due to imx6q errata ERR004346 (WDOG: WDOG SRS bit requires to be
* written twice), we add another two writes to ensure there must be at
@@ -117,7 +142,9 @@ static int imx2_wdt_restart(struct watchdog_device *wdog, unsigned long action,
regmap_write(wdev->regmap, IMX2_WDT_WCR, wcr_enable);
/* wait for reset to assert... */
- mdelay(500);
+ mdelay(100);
+ dev_err(wdog->parent, "failed to assert %s reset, trying with timeout\n",
+ wdev->ext_reset ? "external" : "internal");
return 0;
}
@@ -151,24 +178,6 @@ static inline void imx2_wdt_setup(struct watchdog_device *wdog)
regmap_write(wdev->regmap, IMX2_WDT_WCR, val);
}
-static inline bool imx2_wdt_is_running(struct imx2_wdt_device *wdev)
-{
- u32 val;
-
- regmap_read(wdev->regmap, IMX2_WDT_WCR, &val);
-
- return val & IMX2_WDT_WCR_WDE;
-}
-
-static int imx2_wdt_ping(struct watchdog_device *wdog)
-{
- struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
-
- regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ1);
- regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ2);
- return 0;
-}
-
static void __imx2_wdt_set_timeout(struct watchdog_device *wdog,
unsigned int new_timeout)
{
diff --git a/drivers/watchdog/imx7ulp_wdt.c b/drivers/watchdog/imx7ulp_wdt.c
new file mode 100644
index 000000000000..b54268849ce6
--- /dev/null
+++ b/drivers/watchdog/imx7ulp_wdt.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/watchdog.h>
+
+#define WDOG_CS 0x0
+#define WDOG_CS_CMD32EN (1 << 13)
+#define WDOG_CS_ULK (1 << 11)
+#define WDOG_CS_RCS (1 << 10)
+#define WDOG_CS_EN (1 << 7)
+#define WDOG_CS_UPDATE (1 << 5)
+
+#define WDOG_CNT 0x4
+#define WDOG_TOVAL 0x8
+
+#define REFRESH_SEQ0 0xA602
+#define REFRESH_SEQ1 0xB480
+#define REFRESH ((REFRESH_SEQ1 << 16) | (REFRESH_SEQ0))
+
+#define UNLOCK_SEQ0 0xC520
+#define UNLOCK_SEQ1 0xD928
+#define UNLOCK ((UNLOCK_SEQ1 << 16) | (UNLOCK_SEQ0))
+
+struct imx7ulp_wdt {
+ void __iomem *base;
+ int rate;
+ struct watchdog_device wdd;
+ struct notifier_block restart_handler;
+};
+
+static inline void imx7ulp_wdt_enable(void __iomem *base, bool enable)
+{
+ u32 val = readl(base + WDOG_CS);
+
+ local_irq_disable();
+
+ writel(UNLOCK, base + WDOG_CNT);
+ if (enable)
+ writel(val | WDOG_CS_EN, base + WDOG_CS);
+ else
+ writel(val & ~WDOG_CS_EN, base + WDOG_CS);
+
+ local_irq_enable();
+}
+
+static inline bool imx7ulp_wdt_is_enabled(void __iomem *base)
+{
+ u32 val = readl(base + WDOG_CS);
+
+ return val & WDOG_CS_EN;
+}
+
+static int imx7ulp_wdt_ping(struct watchdog_device *wdog)
+{
+ /* refresh the wdt counter to keepalive */
+ struct imx7ulp_wdt *wdt = watchdog_get_drvdata(wdog);
+ local_irq_disable();
+ writel(REFRESH, wdt->base + WDOG_CNT);
+ local_irq_enable();
+ return 0;
+}
+
+static int imx7ulp_wdt_start(struct watchdog_device *wdog)
+{
+ struct imx7ulp_wdt *wdt = watchdog_get_drvdata(wdog);
+ imx7ulp_wdt_enable(wdt->base, true);
+
+ return 0;
+}
+
+static int imx7ulp_wdt_stop(struct watchdog_device *wdog)
+{
+ struct imx7ulp_wdt *wdt = watchdog_get_drvdata(wdog);
+ imx7ulp_wdt_enable(wdt->base, false);
+
+ return 0;
+}
+
+static int imx7ulp_wdt_set_timeout(struct watchdog_device *wdog, unsigned int timeout)
+{
+ struct imx7ulp_wdt *wdt = watchdog_get_drvdata(wdog);
+ u32 val = wdt->rate * timeout;
+
+ local_irq_disable();
+
+ writel(UNLOCK, wdt->base + WDOG_CNT);
+ writel(val, wdt->base + WDOG_TOVAL);
+
+ local_irq_enable();
+
+ wdog->timeout = timeout;
+
+ imx7ulp_wdt_ping(wdog);
+
+ return 0;
+}
+
+static const struct watchdog_ops imx7ulp_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = imx7ulp_wdt_start,
+ .stop = imx7ulp_wdt_stop,
+ .ping = imx7ulp_wdt_ping,
+ .set_timeout = imx7ulp_wdt_set_timeout,
+};
+
+static const struct watchdog_info imx7ulp_wdt_info = {
+ .identity = "i.MX7ULP watchdog timer",
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING
+ | WDIOF_MAGICCLOSE,
+};
+
+static int imx7ulp_wdt_restart_handler(struct notifier_block *this,
+ unsigned long action, void *data)
+{
+ struct imx7ulp_wdt *wdt = container_of(this, struct imx7ulp_wdt, restart_handler);
+
+ local_irq_disable();
+
+ imx7ulp_wdt_enable(wdt->base, true);
+ imx7ulp_wdt_set_timeout(&wdt->wdd, 1);
+
+ local_irq_enable();
+
+ /* wait for wdog to fire */
+ while(true)
+ ;
+
+ return NOTIFY_DONE;
+}
+
+static inline void imx7ulp_wdt_init(void __iomem *base, unsigned int timeout)
+{
+ u32 val;
+
+ local_irq_disable();
+
+ /* unlock the wdog for reconfiguration */
+ writel_relaxed(UNLOCK_SEQ0, base + WDOG_CNT);
+ writel_relaxed(UNLOCK_SEQ1, base + WDOG_CNT);
+
+ /*set an initial timeout value in TOVAL */
+ writel(timeout, base + WDOG_TOVAL);
+ /* enable 32bit command sequence and reconfigure */
+ val = (1 << 13) | (1 << 8) | (1 << 5);
+ writel(val, base + WDOG_CS);
+
+ local_irq_enable();
+}
+
+static int imx7ulp_wdt_probe(struct platform_device *pdev)
+{
+ struct imx7ulp_wdt *wdt;
+ struct resource *res;
+ int err;
+ u32 timeout;
+
+ wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+ if (!wdt)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, wdt);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ wdt->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(wdt->base))
+ return PTR_ERR(wdt->base);
+
+ /* use the 1KHz LPO as the counter clock */
+ wdt->rate = 1000;
+
+ /* init the wdd */
+ wdt->wdd.info = &imx7ulp_wdt_info;
+ wdt->wdd.ops = &imx7ulp_wdt_ops;
+ wdt->wdd.min_timeout = 1;
+ wdt->wdd.max_timeout = 60;
+ wdt->wdd.parent = &pdev->dev;
+ watchdog_set_drvdata(&wdt->wdd, wdt);
+ /*
+ * set the timeout_parm to 0 to get the timeout
+ * from 'timeout-sec' property in dtb.
+ */
+ err = watchdog_init_timeout(&wdt->wdd, 0, &pdev->dev);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to init the wdog timeout\n");
+ return err;
+ }
+
+ timeout = wdt->wdd.timeout * wdt->rate;
+ /* reconfigure the watchdog timer.*/
+ imx7ulp_wdt_init(wdt->base, timeout);
+
+ err = watchdog_register_device(&wdt->wdd);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to register watchdog device\n");
+ return err;
+ }
+
+ wdt->restart_handler.notifier_call = imx7ulp_wdt_restart_handler;
+ wdt->restart_handler.priority = 128;
+ err = register_restart_handler(&wdt->restart_handler);
+ if (err) {
+ dev_err(&pdev->dev, "cannot register restart handler\n");
+ watchdog_unregister_device(&wdt->wdd);
+ return err;
+ }
+
+ return 0;
+}
+
+static int imx7ulp_wdt_remove(struct platform_device *pdev)
+{
+ struct imx7ulp_wdt *wdt = platform_get_drvdata(pdev);
+
+ imx7ulp_wdt_stop(&wdt->wdd);
+
+ watchdog_unregister_device(&wdt->wdd);
+
+ return 0;
+}
+
+static void imx7ulp_wdt_shutdown(struct platform_device *pdev)
+{
+ struct imx7ulp_wdt *wdt = platform_get_drvdata(pdev);
+
+ if (watchdog_active(&wdt->wdd))
+ imx7ulp_wdt_stop(&wdt->wdd);
+}
+
+#ifdef CONFIG_PM_SLEEP
+/* Disable watchdog before suspend */
+static int imx7ulp_wdt_suspend(struct device *dev)
+{
+ struct imx7ulp_wdt *wdt = dev_get_drvdata(dev);
+
+ imx7ulp_wdt_enable(wdt->base, false);
+
+ return 0;
+}
+
+static int imx7ulp_wdt_resume(struct device *dev)
+{
+ struct imx7ulp_wdt *wdt = dev_get_drvdata(dev);
+ u32 timeout = wdt->wdd.timeout * wdt->rate;
+
+ if (imx7ulp_wdt_is_enabled(wdt->base))
+ imx7ulp_wdt_init(wdt->base, timeout);
+
+ if (watchdog_active(&wdt->wdd))
+ imx7ulp_wdt_enable(wdt->base, true);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(imx7ulp_wdt_pm_ops, imx7ulp_wdt_suspend,
+ imx7ulp_wdt_resume);
+
+static const struct of_device_id imx7ulp_wdt_dt_ids[] = {
+ { .compatible = "fsl,imx7ulp-wdt", },
+ { /*sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx7ulp_wdt_dt_ids);
+
+static struct platform_driver imx7ulp_wdt_driver = {
+ .probe = imx7ulp_wdt_probe,
+ .remove = imx7ulp_wdt_remove,
+ .shutdown = imx7ulp_wdt_shutdown,
+ .driver = {
+ .name = "imx7ulp-wdt",
+ .pm = &imx7ulp_wdt_pm_ops,
+ .of_match_table = imx7ulp_wdt_dt_ids,
+ },
+};
+
+module_platform_driver(imx7ulp_wdt_driver);
+
+MODULE_AUTHOR("Bai Ping <ping.bai@nxp.com>");
+MODULE_DESCRIPTION("Freescale i.MX7ULP watchdog driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/watchdog/imx8_wdt.c b/drivers/watchdog/imx8_wdt.c
new file mode 100644
index 000000000000..955f1295d591
--- /dev/null
+++ b/drivers/watchdog/imx8_wdt.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2017 NXP.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/watchdog.h>
+#include <soc/imx/fsl_sip.h>
+#include <soc/imx8/sc/sci.h>
+#include <soc/imx8/sc/svc/irq/api.h>
+
+#define DEFAULT_TIMEOUT 60
+/*
+ * Software timer tick implemented in scfw side, support 10ms to 0xffffffff ms
+ * in theory, but for normal case, 1s~128s is enough, you can change this max
+ * value in case it's not enough.
+ */
+#define MAX_TIMEOUT 128
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0000);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static unsigned int timeout = DEFAULT_TIMEOUT;
+module_param(timeout, uint, 0000);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default="
+ __MODULE_STRING(DEFAULT_TIMEOUT) ")");
+
+static struct watchdog_device imx8_wdd;
+
+static int imx8_wdt_notify(struct notifier_block *nb,
+ unsigned long event, void *group)
+{
+ /* ignore other irqs */
+ if (!(event & SC_IRQ_WDOG &&
+ (*(sc_irq_group_t *)group == SC_IRQ_GROUP_WDOG)))
+ return 0;
+
+ watchdog_notify_pretimeout(&imx8_wdd);
+
+ return 0;
+}
+
+static int imx8_wdt_ping(struct watchdog_device *wdog)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(FSL_SIP_SRTC, FSL_SIP_SRTC_PING_WDOG, 0, 0, 0, 0, 0, 0,
+ &res);
+
+ return res.a0;
+}
+
+static int imx8_wdt_start(struct watchdog_device *wdog)
+{
+ struct arm_smccc_res res;
+
+ /* no block */
+ arm_smccc_smc(FSL_SIP_SRTC, FSL_SIP_SRTC_START_WDOG, 0, 0, 0, 0, 0, 0,
+ &res);
+ if (res.a0)
+ return res.a0;
+ /* TODO: change to SC_TIMER_WDOG_ACTION_PARTITION after SCFW support */
+ arm_smccc_smc(FSL_SIP_SRTC, FSL_SIP_SRTC_SET_WDOG_ACT,
+ SC_TIMER_WDOG_ACTION_BOARD, 0, 0, 0, 0, 0, &res);
+ return res.a0;
+}
+
+static int imx8_wdt_stop(struct watchdog_device *wdog)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(FSL_SIP_SRTC, FSL_SIP_SRTC_STOP_WDOG, 0, 0, 0, 0, 0, 0,
+ &res);
+
+ return res.a0;
+}
+
+static int imx8_wdt_set_timeout(struct watchdog_device *wdog,
+ unsigned int timeout)
+{
+ struct arm_smccc_res res;
+
+ wdog->timeout = timeout;
+
+ arm_smccc_smc(FSL_SIP_SRTC, FSL_SIP_SRTC_SET_TIMEOUT_WDOG,
+ timeout * 1000, 0, 0, 0, 0, 0, &res);
+
+ return res.a0;
+}
+
+static int imx8_wdt_set_pretimeout(struct watchdog_device *wdog,
+ unsigned int new_pretimeout)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(FSL_SIP_SRTC, FSL_SIP_SRTC_SET_PRETIME_WDOG,
+ new_pretimeout * 1000, 0, 0, 0, 0, 0,
+ &res);
+
+ return res.a0;
+}
+
+static const struct watchdog_ops imx8_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = imx8_wdt_start,
+ .stop = imx8_wdt_stop,
+ .ping = imx8_wdt_ping,
+ .set_timeout = imx8_wdt_set_timeout,
+ .set_pretimeout = imx8_wdt_set_pretimeout,
+};
+
+static const struct watchdog_info imx8_wdt_info = {
+ .identity = "i.MX8 watchdog timer",
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE | WDIOF_PRETIMEOUT,
+};
+
+static struct notifier_block imx8_wdt_notifier = {
+ .notifier_call = imx8_wdt_notify,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int imx8_wdt_suspend(struct device *dev)
+{
+ if (test_bit(WDOG_ACTIVE, &imx8_wdd.status))
+ imx8_wdt_stop(&imx8_wdd);
+
+ return 0;
+}
+
+static int imx8_wdt_resume(struct device *dev)
+{
+ if (test_bit(WDOG_ACTIVE, &imx8_wdd.status))
+ imx8_wdt_start(&imx8_wdd);
+
+ return 0;
+}
+
+static const struct dev_pm_ops imx8_wdt_pm_ops = {
+ .suspend = imx8_wdt_suspend,
+ .resume = imx8_wdt_resume,
+};
+
+#define IMX8_WDT_PM_OPS (&imx8_wdt_pm_ops)
+
+#else
+
+#define IMX8_WDT_PM_OPS NULL
+
+#endif
+
+static int imx8_wdt_probe(struct platform_device *pdev)
+{
+ struct watchdog_device *wdt = &imx8_wdd;
+ int err;
+
+ platform_set_drvdata(pdev, wdt);
+ /* init the wdd */
+ wdt->info = &imx8_wdt_info;
+ wdt->ops = &imx8_wdt_ops;
+ wdt->min_timeout = 1;
+ wdt->max_timeout = MAX_TIMEOUT;
+ wdt->parent = &pdev->dev;
+ watchdog_set_drvdata(wdt, NULL);
+
+ err = watchdog_init_timeout(wdt, DEFAULT_TIMEOUT, &pdev->dev);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to init the wdog timeout:%d\n",
+ err);
+ return err;
+ }
+
+ err = watchdog_register_device(wdt);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to register watchdog device\n");
+ return err;
+ }
+
+ return register_scu_notifier(&imx8_wdt_notifier);
+}
+
+static int imx8_wdt_remove(struct platform_device *pdev)
+{
+ struct watchdog_device *wdt = platform_get_drvdata(pdev);
+
+ imx8_wdt_stop(wdt);
+
+ watchdog_unregister_device(wdt);
+
+ return 0;
+}
+
+static void imx8_wdt_shutdown(struct platform_device *pdev)
+{
+ struct watchdog_device *wdt = platform_get_drvdata(pdev);
+
+ if (watchdog_active(wdt))
+ imx8_wdt_stop(wdt);
+}
+
+static const struct of_device_id imx8_wdt_dt_ids[] = {
+ { .compatible = "fsl,imx8-wdt", },
+ { /*sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx8_wdt_dt_ids);
+
+static struct platform_driver imx8_wdt_driver = {
+ .probe = imx8_wdt_probe,
+ .remove = imx8_wdt_remove,
+ .shutdown = imx8_wdt_shutdown,
+ .driver = {
+ .name = "imx8-wdt",
+ .of_match_table = imx8_wdt_dt_ids,
+ .pm = IMX8_WDT_PM_OPS,
+ },
+};
+
+module_platform_driver(imx8_wdt_driver);
+
+MODULE_AUTHOR("Robin Gong <yibin.gong@nxp.com>");
+MODULE_DESCRIPTION("NXP i.MX8 watchdog driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index 2fe7353ab720..5b4ca99e75b9 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -699,3 +699,31 @@ xen_swiotlb_dma_mmap(struct device *dev, struct vm_area_struct *vma,
return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size);
}
EXPORT_SYMBOL_GPL(xen_swiotlb_dma_mmap);
+
+/*
+ * This function should be called with the pages from the current domain only,
+ * passing pages mapped from other domains would lead to memory corruption.
+ */
+int
+xen_swiotlb_get_sgtable(struct device *dev, struct sg_table *sgt,
+ void *cpu_addr, dma_addr_t handle, size_t size,
+ unsigned long attrs)
+{
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+ if (__generic_dma_ops(dev)->get_sgtable) {
+#if 0
+ /*
+ * This check verifies that the page belongs to the current domain and
+ * is not one mapped from another domain.
+ * This check is for debug only, and should not go to production build
+ */
+ unsigned long bfn = PHYS_PFN(dma_to_phys(dev, handle));
+ BUG_ON (!page_is_ram(bfn));
+#endif
+ return __generic_dma_ops(dev)->get_sgtable(dev, sgt, cpu_addr,
+ handle, size, attrs);
+ }
+#endif
+ return dma_common_get_sgtable(dev, sgt, cpu_addr, handle, size);
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_get_sgtable);